Erreur «Pas de certificat par les pairs» dans Android 2.3, mais PAS dans 4

Obtenir le "javax.net.ssl.SSLPeerUnverifiedException: No peer certificate error" dans un émulateur exécutant Android 2.3, mais PAS dans 4. En 4, il fonctionne parfaitement. J'essaie de me connecter à un serveur en direct via https. Il utilise un certificat Thawte valide, fonctionne bien dans tous les navigateurs et Android 3 et 4.

Si quelqu'un a un code d'aide, VEUILLEZ et merci. De plus, si quelqu'un a des suggestions sur une solution de rechange sécurisée, je l'apprécierais. J'apprends toujours, et j'ai été sur ce problème pendant une semaine. Il doit se terminer, afin que je puisse continuer à travailler et à apprendre. Urgh.

  • Android obtenez le chemin d'image à partir d'un dessin comme chaîne
  • Fonction d'enregistrement de test Espresso dans Android Studio 2.2
  • Aucune ressource trouvée qui correspond au prénom 'android: Theme.Material.Light.DarkActionBar'
  • Comment utiliser Gradle pour générer des fichiers de projets Eclipse et Intellij pour des projets Android
  • Comment définir la taille d'un ProgressBar d'Android de manière programmée?
  • Méthode d'activité d'appel du récepteur de diffusion
  • Voici le code HttpCLient, courtoisie Antoine Hauck ( http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/ ):

      import java.io.InputStream; import java.security.KeyStore; import java.security.cert.CertificateException; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import javax.security.cert.X509Certificate; 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.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; import android.content.Context; 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.my_cert); try { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore trusted.load(in, "my_pass".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); } } } 

    Et voici le code qui l'instancie:

     DefaultHttpClient client = new MyHttpClient(getApplicationContext()); HttpPost post = new HttpPost(server_login_url); List <NameValuePair> parameters = new ArrayList <NameValuePair>(); parameters.add(new BasicNameValuePair("username", user)); parameters.add(new BasicNameValuePair("password", pass)); try { post.setEntity(new UrlEncodedFormEntity(parameters, HTTP.UTF_8)); } catch (UnsupportedEncodingException e2) { // TODO Auto-generated catch block Log.d(DEBUG_TAG, "in UnsupportedEncodingException - " + e2.getMessage()); e2.printStackTrace(); } // Execute the GET call and obtain the response HttpResponse getResponse = null; try { getResponse = client.execute(post); } catch (ClientProtocolException e) { // TODO Auto-generated catch block // Toast.makeText(getBaseContext(),message,Toast.LENGTH_LONG).show(); Log.d(DEBUG_TAG, "in ClientProtocolException - " + e.getMessage()); } catch (IOException e) { // TODO Auto-generated catch block // Toast.makeText(getBaseContext(),message,Toast.LENGTH_LONG).show(); Log.d(DEBUG_TAG, "in client.execute IOException - " + e.getMessage()); e.printStackTrace(); } 

    L'erreur est détectée dans le bloc IOException. Voici la pile:

     javax.net.ssl.SSLPeerUnverifiedException: No peer certificate org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:258) org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93) org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381) org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164) org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359) org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) org.ffb.tools.SplashActivity$LoginTask.makeConnection(SplashActivity.java:506) org.ffb.tools.SplashActivity$LoginTask.doLogin(SplashActivity.java:451) org.ffb.tools.SplashActivity$LoginTask.doInBackground(SplashActivity.java:439) org.ffb.tools.SplashActivity$LoginTask.doInBackground(SplashActivity.java:1) android.os.AsyncTask$2.call(AsyncTask.java:185) java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306) java.util.concurrent.FutureTask.run(FutureTask.java:138) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) java.lang.Thread.run(Thread.java:1019) 

    Voici la chaîne (à partir de la commande openssl):

    La chaîne semble bien, je pense.

      i:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA 1 s:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV 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 

  • Emplacement: autorisations GPS / réseau: souhaité si disponible
  • Android: comment détecter si un périphérique est WiFi ou WiFi + Cellulaire
  • Police personnalisée sur Android
  • Comment obtenir la résolution de l'écran dans Android Honeycomb?
  • Comment afficher Spinner With Label (Static Text)?
  • Accessibilité d'Android pour modifier le texte avec un indice
  • 5 Solutions collect form web for “Erreur «Pas de certificat par les pairs» dans Android 2.3, mais PAS dans 4”

    Ce fil a été vraiment utile lorsque j'ai débogué un problème similaire.

    Résumé Android 2.3 Liste de contrôle HTTPS / SSL:

    • Si votre CA est dans la liste 2,3 2.3 de CA approuvée d' Android – et Thawte est – il n'est pas nécessaire d'inclure le certificat dans l'application.
    • Android 2.3 ne prend pas en charge l' indication de nom de serveur, donc si votre serveur s'appuie sur le protocole SSL, Android pourrait ne pas recevoir les certificats que vous attendez.
    • Avez-vous une chaîne de certificats sur le serveur installée, et est-elle ordonnée correctement? La plupart des navigateurs utilisent des chaînes de certificats hors service, mais Android 2.3 ne le fait pas. La réponse de bdc dans le fil que j'ai mentionné ci-dessus décrit comment vérifier la validité de votre certificat SSL et la chaîne avec "openssl s_client -connect yourserver.com:443".
    • Lorsque vous déterminez cet ancien périphérique 2.3 que vous avez dans votre tiroir inférieur, assurez-vous que la date et l'heure sont réglées correctement après avoir été imputable pendant trop longtemps.

    J'avais exactement le même problème que vous. Tout fonctionnait bien avec android> 3.X mais quand j'ai essayé avec certains (mais pas tous!) 2.3.X appareils J'ai eu cette fameuse exception "No peer certificate error".

    J'ai creusé beaucoup dans stackoverflow et d'autres blogs, mais je n'ai trouvé rien qui fonctionnait sur ces dispositifs «rogue» (dans mon cas: utilisation correcte de truststore, sans sni, correction de la chaîne cert sur le serveur, etc.) .

    Il semble que Apache HttpClient d'Android ne fonctionnait pas correctement sur certains périphériques 2.3.X. L'exception "sans certificats pairs" se produisait trop tôt pour atteindre même un code de vérificateur de nom d'hôte personnalisé, donc une solution comme celle-là ne fonctionnait pas pour moi.

    Voici mon code:

     KeyStore trustStore = KeyStore.getInstance("BKS"); InputStream is = this.getAssets().open("discretio.bks"); trustStore.load(is, "discretio".toCharArray()); is.close(); SSLSocketFactory sockfacto = new SSLSocketFactory(trustStore); sockfacto.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", sockfacto, 443)); SingleClientConnManager mgr = new SingleClientConnManager(httpParameters, schemeRegistry); HttpClient client = new DefaultHttpClient(mgr, httpParameters); HttpGet request = new HttpGet(url); HttpResponse response = client.execute(request); 

    J'ai donc réécrit tout en utilisant javax.net.ssl.HttpsURLConnection et maintenant il fonctionne sur tous les appareils que j'ai testés (de 2.3.3 à 4.X).

    Voici mon nouveau code:

     KeyStore trustStore = KeyStore.getInstance("BKS"); InputStream is = this.getAssets().open("discretio.bks"); trustStore.load(is, "discretio".toCharArray()); is.close(); TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init(trustStore); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null); URL request = new URL(url); HttpsURLConnection urlConnection = (HttpsURLConnection) request.openConnection(); //ensure that we are using a StrictHostnameVerifier urlConnection.setHostnameVerifier(new StrictHostnameVerifier()); urlConnection.setSSLSocketFactory(context.getSocketFactory()); urlConnection.setConnectTimeout(15000); InputStream in = urlConnection.getInputStream(); //I don't want to change my function's return type (laziness) so I'm building an HttpResponse BasicHttpEntity res = new BasicHttpEntity(); res.setContent(in); HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, urlConnection.getResponseCode(), ""); resp.setEntity(res); 

    La validation de la chaîne de certificats et du nom d'hôte fonctionne (je les ai testés). Si quelqu'un veut regarder mieux le changement, voici un diff

    Les commentaires sont les bienvenus, j'espère qu'il aidera certaines personnes.

    Une autre source de ce message peut être un paramètre de date / heure non valide, par exemple lorsque vous utilisez un périphérique qui est passé quelques mois sans pouvoir. Tout à fait trivial, mais il peut être difficile à repérer.

    Quels sont les certificats que vous chargez de R.raw.my_cert ? Cette erreur parle soit d'avoir un serveur mal configuré – n'installant pas les CA intermédiaires primaires et secondaires de Thawte – ou vous ne chargez pas et ne faites pas confiance à la chaîne de certificat correcte.

    La vérification de certificat (ou plus précisément – la construction de chaînes) logique dans (au moins) Android 2.3 est défectueuse.

    Voilà ce que j'ai observé:

    • Si le serveur TLS dans sa chaîne de certificats fournit uniquement le certificat du serveur (non auto-signé ou auto-signé), vous pouvez mettre le certificat du serveur dans le magasin de clés et la vérification réussira.

    • Si le serveur TLS dans sa chaîne de certificats fournit également un certificat de CA intermédiaire, alors, dans le magasin de clés, vous devez mettre uniquement le certificat de l'autorité de certification et assurez-vous que le magasin de clés NE contient PAS de certificats de CA du serveur et de l'intermédiaire (sinon la vérification échouera de manière aléatoire).

    • Si le serveur TLS dans sa chaîne de certificats fournit des certificats de CA intermédiaires et racines dans le bon ordre, il vous suffit de vous assurer que le certificat de l'autorité de certification est dans le magasin de clés (peu importe si les certificats CA du serveur et intermédiaires sont présents).

    Donc, la manière «correcte / fiable» de savoir comment gérer cela est d'inclure dans les magasins clés uniquement les certificats de CA de racine et de responsabiliser la configuration du serveur pour «Aucun certificat de pair» – dans le cas où la chaîne de certificats du serveur ne fournit pas de certificats d'AC intermédiaires ou les certificats sont en mauvais ordre . Vous pouvez tester le serveur en utilisant https://www.ssllabs.com/ssltest/ .

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.