Faire confiance à tous les certificates utilisant HttpClient sur HTTPS

Récemment publié une question concernant le HttpClient sur HttpClient ( trouvé ici ). J’ai fait des progrès, mais j’ai rencontré de nouveaux problèmes. Comme pour mon dernier problème, je n’arrive pas à trouver un exemple où que ce soit qui fonctionne pour moi. Fondamentalement, je souhaite que mon client accepte tous les certificates (car je ne pointe jamais vers un seul serveur), mais je continue à recevoir une javax.net.ssl.SSLException: Not trusted server certificatee exception.

Donc c’est ce que j’ai:

 public void connect() throws A_WHOLE_BUNCH_OF_EXCEPTIONS { HttpPost post = new HttpPost(new URI(PROD_URL)); post.setEntity(new SsortingngEntity(BODY)); KeyStore trusted = KeyStore.getInstance("BKS"); trusted.load(null, "".toCharArray()); SSLSocketFactory sslf = new SSLSocketFactory(trusted); sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme ("https", sslf, 443)); SingleClientConnManager cm = new SingleClientConnManager(post.getParams(), schemeRegistry); HttpClient client = new DefaultHttpClient(cm, post.getParams()); HttpResponse result = client.execute(post); } 

Et voici l’erreur que j’ai:

 W/System.err( 901): javax.net.ssl.SSLException: Not trusted server certificatee W/System.err( 901): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360) W/System.err( 901): at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92) W/System.err( 901): at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321) W/System.err( 901): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129) W/System.err( 901): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) W/System.err( 901): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) W/System.err( 901): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) W/System.err( 901): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) W/System.err( 901): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) W/System.err( 901): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) W/System.err( 901): at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:129) W/System.err( 901): at me.harrisonlee.test.ssl.MainActivity.access$0(MainActivity.java:77) W/System.err( 901): at me.harrisonlee.test.ssl.MainActivity$2.run(MainActivity.java:49) W/System.err( 901): Caused by: java.security.cert.CertificateException: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty W/System.err( 901): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:157) W/System.err( 901): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355) W/System.err( 901): ... 12 more W/System.err( 901): Caused by: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty W/System.err( 901): at java.security.cert.PKIXParameters.checkTrustAnchors(PKIXParameters.java:645) W/System.err( 901): at java.security.cert.PKIXParameters.(PKIXParameters.java:89) W/System.err( 901): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.(TrustManagerImpl.java:89) W/System.err( 901): at org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:134) W/System.err( 901): at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:226)W/System.err( 901): at org.apache.http.conn.ssl.SSLSocketFactory.createTrustManagers(SSLSocketFactory.java:263) W/System.err( 901): at org.apache.http.conn.ssl.SSLSocketFactory.(SSLSocketFactory.java:190) W/System.err( 901): at org.apache.http.conn.ssl.SSLSocketFactory.(SSLSocketFactory.java:216) W/System.err( 901): at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:107) W/System.err( 901): ... 2 more 

    Remarque: N’implémentez pas cela dans le code de production que vous allez utiliser sur un réseau auquel vous ne faites pas entièrement confiance. Surtout tout ce qui passe par internet.

    Votre question est juste ce que je veux savoir. Après quelques recherches, la conclusion est la suivante.

    De la manière HttpClient, vous devez créer une classe personnalisée à partir de org.apache.http.conn.ssl.SSLSocketFactory, pas de celle org.apache.http.conn.ssl.SSLSocketFactory elle-même. Quelques indices peuvent être trouvés dans cet article La gestion de SSL personnalisée a cessé de fonctionner sur Android 2.2 FroYo .

    Un exemple est comme …

     import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.conn.ssl.SSLSocketFactory; public class MySSLSocketFactory extends SSLSocketFactory { SSLContext sslContext = SSLContext.getInstance("TLS"); public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[] { tm }, null); } @Override public Socket createSocket(Socket socket, Ssortingng host, int port, boolean autoClose) throws IOException, UnknownHostException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } } 

    et utilisez cette classe lors de la création d’une instance de HttpClient.

     public HttpClient getNewHttpClient() { try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); MySSLSocketFactory sf = new MySSLSocketFactory(trustStore); sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); return new DefaultHttpClient(ccm, params); } catch (Exception e) { return new DefaultHttpClient(); } } 

    BTW, le lien ci-dessous est pour quelqu’un qui cherche la solution HttpURLConnection. Connexion Https Android

    J’ai testé les deux types de solutions ci-dessus sur froyo, et elles fonctionnent toutes comme un charme dans mes cas. Enfin, l’utilisation de HttpURLConnection peut faire face aux problèmes de redirection, mais cela n’est pas le sujet.

    Remarque: avant de décider de faire confiance à tous les certificates, vous devez probablement connaître le site correctement et ne pas en nuire à l’utilisateur final.

    En effet, le risque que vous prenez doit être considéré avec soin, y compris l’effet du site de simulation de pirate informatique mentionné dans les commentaires suivants que j’ai profondément apprécié. Dans certaines situations, bien qu’il puisse être difficile de prendre en charge tous les certificates, vous devez connaître les inconvénients implicites à leur faire confiance.

    Vous avez essentiellement quatre solutions possibles pour corriger une exception “non approuvée” sur Android en utilisant httpclient:

    1. Faites confiance à tous les certificates. Ne faites pas cela, à moins que vous ne sachiez vraiment ce que vous faites.
    2. Créez un SSLSocketFactory personnalisé qui ne fait confiance qu’à votre certificate. Cela fonctionne tant que vous connaissez exactement les serveurs auxquels vous allez vous connecter, mais dès que vous devez vous connecter à un nouveau serveur avec un certificate SSL différent, vous devez mettre à jour votre application.
    3. Créez un fichier de clés contenant la “liste principale” de certificates d’Android, puis ajoutez les vôtres. Si l’un de ces certificates arrive à expiration, vous devez le mettre à jour dans votre application. Je ne peux pas penser à une raison de le faire.
    4. Créez un SSLSocketFactory personnalisé utilisant le certificate intégré KeyStore, mais retombe sur un autre KeyStore pour tout ce qui ne parvient pas à vérifier avec le défaut.

    Cette réponse utilise la solution n ° 4, qui me semble la plus robuste.

    La solution consiste à utiliser un SSLSocketFactory pouvant accepter plusieurs magasins KeyStore, vous permettant ainsi de fournir votre propre KeyStore avec vos propres certificates. Cela vous permet de charger des certificates de niveau supérieur supplémentaires, tels que Thawte, qui peuvent être manquants sur certains appareils Android. Il vous permet également de charger vos propres certificates auto-signés. Il utilisera d’abord les certificates de périphérique par défaut intégrés et utilisera vos certificates supplémentaires uniquement si nécessaire.

    Tout d’abord, vous voudrez déterminer quel certificate vous manque dans votre KeyStore. Exécutez la commande suivante:

     openssl s_client -connect www.yourserver.com:443 

    Et vous verrez la sortie comme suit:

     Certificate chain 0 s:/O=www.yourserver.com/OU=Go to https://www.thawte.com/repository/index.html/OU=Thawte SSL123 certificatee/OU=Domain Validated/CN=www.yourserver.com 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 

    Comme vous pouvez le voir, notre certificate racine provient de Thawte. Accédez au site Web de votre fournisseur et trouvez le certificate correspondant. Pour nous, c’était ici , et vous pouvez voir que celui dont nous avions besoin était celui de Copyright 2006.

    Si vous utilisez un certificate auto-signé, vous n’avez pas besoin de faire l’étape précédente car vous avez déjà votre certificate de signature.

    Ensuite, créez un fichier de clés contenant le certificate de signature manquant. Crazybob a des détails sur comment faire cela sur Android , mais l’idée est de faire ce qui suit:

    Si vous ne l’avez pas déjà, téléchargez la bibliothèque du fournisseur de château gonflable à l’ adresse suivante : http://www.bouncycastle.org/latest_releases.html . Cela ira sur votre classpath ci-dessous.

    Exécutez une commande pour extraire le certificate du serveur et créer un fichier pem. Dans ce cas, mycert.pem.

     echo | openssl s_client -connect ${MY_SERVER}:443 2>&1 | \ sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem 

    Exécutez ensuite les commandes suivantes pour créer le fichier de clés.

     export CLASSPATH=/path/to/bouncycastle/bcprov-jdk15on-155.jar CERTSTORE=res/raw/mystore.bks if [ -a $CERTSTORE ]; then rm $CERTSTORE || exit 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file <(openssl x509 -in mycert.pem) \ -keystore $CERTSTORE \ -storetype BKS \ -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ -providerpath /path/to/bouncycastle/bcprov-jdk15on-155.jar \ -storepass some-password 

    Vous remarquerez que le script ci-dessus place le résultat dans res/raw/mystore.bks . Vous avez maintenant un fichier que vous allez charger dans votre application Android et qui fournit le ou les certificates manquants.

    Pour ce faire, enregistrez votre SSLSocketFactory pour le schéma SSL:

     final SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", createAdditionalCertsSSLSocketFactory(), 443)); // and then however you create your connection manager, I use ThreadSafeClientConnManager final HttpParams params = new BasicHttpParams(); ... final ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params,schemeRegistry); 

    Pour créer votre SSLSocketFactory:

     protected org.apache.http.conn.ssl.SSLSocketFactory createAdditionalCertsSSLSocketFactory() { try { final KeyStore ks = KeyStore.getInstance("BKS"); // the bks file we generated above final InputStream in = context.getResources().openRawResource( R.raw.mystore); try { // don't forget to put the password used above in ssortingngs.xml/mystore_password ks.load(in, context.getSsortingng( R.ssortingng.mystore_password ).toCharArray()); } finally { in.close(); } return new AdditionalKeyStoresSSLSocketFactory(ks); } catch( Exception e ) { throw new RuntimeException(e); } } 

    Et enfin, le code AdditionalKeyStoresSSLSocketFactory, qui accepte votre nouveau KeyStore et vérifie si le KeyStore intégré ne parvient pas à valider un certificate SSL:

     /** * Allows you to trust certificatees from additional KeyStores in addition to * the default KeyStore */ public class AdditionalKeyStoresSSLSocketFactory extends SSLSocketFactory { protected SSLContext sslContext = SSLContext.getInstance("TLS"); public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(null, null, null, null, null, null); sslContext.init(null, new TrustManager[]{new AdditionalKeyStoresTrustManager(keyStore)}, null); } @Override public Socket createSocket(Socket socket, Ssortingng host, int port, boolean autoClose) throws IOException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } /** * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager */ public static class AdditionalKeyStoresTrustManager implements X509TrustManager { protected ArrayList x509TrustManagers = new ArrayList(); protected AdditionalKeyStoresTrustManager(KeyStore... additionalkeyStores) { final ArrayList factories = new ArrayList(); try { // The default Trustmanager with default keystore final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); original.init((KeyStore) null); factories.add(original); for( KeyStore keyStore : additionalkeyStores ) { final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); additionalCerts.init(keyStore); factories.add(additionalCerts); } } catch (Exception e) { throw new RuntimeException(e); } /* * Iterate over the returned trustmanagers, and hold on * to any that are X509TrustManagers */ for (TrustManagerFactory tmf : factories) for( TrustManager tm : tmf.getTrustManagers() ) if (tm instanceof X509TrustManager) x509TrustManagers.add( (X509TrustManager)tm ); if( x509TrustManagers.size()==0 ) throw new RuntimeException("Couldn't find any X509TrustManagers"); } /* * Delegate to the default trust manager. */ public void checkClientTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { final X509TrustManager defaultX509TrustManager = x509TrustManagers.get(0); defaultX509TrustManager.checkClientTrusted(chain, authType); } /* * Loop over the trustmanagers until we find one that accepts our server */ public void checkServerTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { for( X509TrustManager tm : x509TrustManagers ) { try { tm.checkServerTrusted(chain,authType); return; } catch( CertificateException e ) { // ignore } } throw new CertificateException(); } public X509Certificate[] getAcceptedIssuers() { final ArrayList list = new ArrayList(); for( X509TrustManager tm : x509TrustManagers ) list.addAll(Arrays.asList(tm.getAcceptedIssuers())); return list.toArray(new X509Certificate[list.size()]); } } } 

    Ajoutez ce code avant le HttpsURLConnection et ce sera fait. Je l’ai.

     private void trustEveryone() { try { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ public boolean verify(Ssortingng hostname, SSLSession session) { return true; }}); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new X509TrustManager[]{new X509TrustManager(){ public void checkClientTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException {} public void checkServerTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }}}, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory( context.getSocketFactory()); } catch (Exception e) { // should never happen e.printStackTrace(); } } 

    J’espère que ceci vous aide.

    C’est une mauvaise idée. Faire confiance à n’importe quel certificate est seulement (très) légèrement meilleur que de ne pas utiliser de SSL du tout. Lorsque vous dites “Je veux que mon client accepte tout certificate (parce que je ne pointe que vers un seul serveur)”, vous supposez que cela signifie que le fait de pointer sur “un serveur” est sûr, et non sur un réseau public.

    Vous êtes complètement ouvert à une attaque de type “man-in-the-middle” en faisant confiance à tout certificate. N’importe qui peut envoyer votre connexion par proxy en établissant une connexion SSL séparée avec vous et avec le serveur final. Le MITM a alors access à toute votre demande et à votre réponse. À moins que vous n’ayez pas vraiment besoin de SSL (votre message n’a rien de sensible et ne fait pas d’authentification), vous ne devriez pas faire confiance à tous les certificates.

    Vous devriez envisager d’append le cert public à un jks en utilisant keytool, et en l’utilisant pour créer votre fabrique de socket, comme ceci:

      KeyStore ks = KeyStore.getInstance("JKS"); // get user password and file input stream char[] password = ("mykspassword")).toCharArray(); ClassLoader cl = this.getClass().getClassLoader(); InputStream stream = cl.getResourceAsStream("myjks.jks"); ks.load(stream, password); stream.close(); SSLContext sc = SSLContext.getInstance("TLS"); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); kmf.init(ks, password); tmf.init(ks); sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null); return sc.getSocketFactory(); 

    Cela a une réserve à surveiller. Le certificate expirera éventuellement et le code cessera de fonctionner à ce moment. Vous pouvez facilement déterminer quand cela se produira en consultant le certificate.

    Vous pouvez désactiver la vérification SSL HttpURLConnection à des fins de test de cette manière depuis l’API 8:

      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); if (conn instanceof HttpsURLConnection) { HttpsURLConnection httpsConn = (HttpsURLConnection) conn; httpsConn.setSSLSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null)); httpsConn.setHostnameVerifier(new AllowAllHostnameVerifier()); } 

    L’API de HttpComponents a été modifiée. Cela fonctionne avec le code ci-dessous.

     public static HttpClient getTestHttpClient() { try { SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){ @Override public boolean isTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { return true; } }, new AllowAllHostnameVerifier()); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("https",8444, sf)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry); return new DefaultHttpClient(ccm); } catch (Exception e) { e.printStackTrace(); return new DefaultHttpClient(); } } 

    Le code ci-dessus dans https://stackoverflow.com/a/6378872/1553004 est correct, sauf qu’il DOIT également appeler le vérificateur de nom d’hôte:

      @Override public Socket createSocket(Socket socket, Ssortingng host, int port, boolean autoClose) throws IOException { SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); getHostnameVerifier().verify(host, sslSocket); return sslSocket; } 

    Je me suis inscrit à stackoverflow expressément pour append ce correctif. Suivez mon avertissement!

    J’ajoute une réponse pour ceux qui utilisent httpclient-4.5, et fonctionne probablement aussi pour 4.4.

     import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.HttpResponseException; import org.apache.http.client.fluent.ContentResponseHandler; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; public class HttpClientUtils{ public static HttpClient getHttpClientWithoutSslValidation_UsingHttpClient_4_5_2() { try { SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { return true; } }); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier()); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); return httpclient; } catch (Exception e) { throw new RuntimeException(e); } } } 

    Faire confiance à tous les certificates n’était pas une véritable alternative pour moi, alors j’ai fait ce qui suit pour que HttpsURLConnection fasse confiance à un nouveau certificate (voir aussi http://nelenkov.blogspot.jp/2011/12/using-custom-certificatee-trust-store- on.html ).

    1. Obtenez le certificate Je l’ai fait en exportant le certificate dans Firefox (cliquez sur la petite icône de locking, obtenez les détails du certificate, cliquez sur exporter), puis utilisez portecle pour exporter un fichier de clés certifiées (BKS).

    2. Chargez le fichier de clés certifiées dans /res/raw/geotrust_cert.bks avec le code suivant:

        final KeyStore trustStore = KeyStore.getInstance("BKS"); final InputStream in = context.getResources().openRawResource( R.raw.geotrust_cert); trustStore.load(in, null); final TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); final SSLContext sslCtx = SSLContext.getInstance("TLS"); sslCtx.init(null, tmf.getTrustManagers(), new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslCtx .getSocketFactory()); 

    Voici une version très simple utilisant le code 4.1.2 httpclient. Cela peut ensuite être modifié en n’importe quel algorithme de confiance que vous voyez approprié.

     public static HttpClient getTestHttpClient() { try { SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){ @Override public boolean isTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { return true; } }); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("https", 443, sf)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry); return new DefaultHttpClient(ccm); } catch (Exception e) { return new DefaultHttpClient(); } } 

    Je suis la réponse de “emmby” (réponse le 16 juin 11 à 21:29), élément n ° 4: “Créer un SSLSocketFactory personnalisé qui utilise le certificate intégré KeyStore, mais retombe sur un autre KeyStore pour tout ce qui échoue vérifier avec la valeur par défaut. ”

    Ceci est une implémentation simplifiée. Chargez le fichier de clés du système et fusionnez-le avec le fichier de clés de l’application.

     public HttpClient getNewHttpClient() { try { InputStream in = null; // Load default system keystore KeyStore trusted = KeyStore.getInstance(KeyStore.getDefaultType()); try { in = new BufferedInputStream(new FileInputStream(System.getProperty("javax.net.ssl.trustStore"))); // Normally: "/system/etc/security/cacerts.bks" trusted.load(in, null); // no password is "changeit" } finally { if (in != null) { in.close(); in = null; } } // Load application keystore & merge with system try { KeyStore appTrusted = KeyStore.getInstance("BKS"); in = context.getResources().openRawResource(R.raw.mykeystore); appTrusted.load(in, null); // no password is "changeit" for (Enumeration e = appTrusted.aliases(); e.hasMoreElements();) { final Ssortingng alias = e.nextElement(); final KeyStore.Entry entry = appTrusted.getEntry(alias, null); trusted.setEntry(System.currentTimeMillis() + ":" + alias, entry, null); } } finally { if (in != null) { in.close(); in = null; } } HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); SSLSocketFactory sf = new SSLSocketFactory(trusted); sf.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); return new DefaultHttpClient(ccm, params); } catch (Exception e) { return new DefaultHttpClient(); } } 

    Un mode simple pour convertir de JKS à BKS:

     keytool -importkeystore -destkeystore cacerts.bks -deststoretype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk16-141.jar -deststorepass changeit -srcstorepass changeit -srckeystore $JAVA_HOME/jre/lib/security/cacerts -srcstoretype JKS -noprompt 

    *Note: In Android 4.0 (ICS) the Trust Store has changed, more info: http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html

    For those who would like to allow all certificatees to work (for testing purposes) over OAuth, follow these steps:

    1) Download the source code of the Android OAuth API here: https://github.com/kaeppler/signpost

    2) Find the file “CommonsHttpOAuthProvider” class

    3) Change it as below:

     public class CommonsHttpOAuthProvider extends AbstractOAuthProvider { private static final long serialVersionUID = 1L; private transient HttpClient httpClient; public CommonsHttpOAuthProvider(Ssortingng requestTokenEndpointUrl, Ssortingng accessTokenEndpointUrl, Ssortingng authorizationWebsiteUrl) { super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl); //this.httpClient = new DefaultHttpClient();//Version implemented and that throws the famous "javax.net.ssl.SSLException: Not trusted server certificatee" if the certificatee is not signed with a CA this.httpClient = MySSLSocketFactory.getNewHttpClient();//This will work with all certificatees (for testing purposes only) } 

    The “MySSLSocketFactory” above is based on the accepted answer. To make it even easier, here goes the complete class:

     package com.netcomps.oauth_example; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; 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.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP; //http://stackoverflow.com/questions/2642777/trusting-all-certificatees-using-httpclient-over-https public class MySSLSocketFactory extends SSLSocketFactory { SSLContext sslContext = SSLContext.getInstance("TLS"); public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, Ssortingng authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[] { tm }, null); } @Override public Socket createSocket(Socket socket, Ssortingng host, int port, boolean autoClose) throws IOException, UnknownHostException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } public static HttpClient getNewHttpClient() { try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); SSLSocketFactory sf = new MySSLSocketFactory(trustStore); sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); return new DefaultHttpClient(ccm, params); } catch (Exception e) { return new DefaultHttpClient(); } } 

    }

    J’espère que cela aide quelqu’un.

    I used this and It works for me on all OS.

     /** * Disables the SSL certificatee checking for new instances of {@link HttpsURLConnection} This has been created to * aid testing on a local box, not for use on production. */ private static void disableSSLCertificateChecking() { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] arg0, Ssortingng arg1) throws CertificateException { // Not implemented } @Override public void checkServerTrusted(X509Certificate[] arg0, Ssortingng arg1) throws CertificateException { // Not implemented } } }; try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } 

    Any body still struggling with StartCom SSL Certificates on Android 2.1 visit https://www.startssl.com/certs/ and download the ca.pem, now in the answer provided by @emmby replace

     `export CLASSPATH=bcprov-jdk16-145.jar CERTSTORE=res/raw/mystore.bks if [ -a $CERTSTORE ]; then rm $CERTSTORE || exit 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file <(openssl x509 -in mycert.pem) \ -keystore $CERTSTORE \ -storetype BKS \ -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ -providerpath /usr/share/java/bcprov.jar \ -storepass some-password` 

    avec

      `export CLASSPATH=bcprov-jdk16-145.jar CERTSTORE=res/raw/mystore.bks if [ -a $CERTSTORE ]; then rm $CERTSTORE || exit 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file <(openssl x509 -in ca.pem) \ -keystore $CERTSTORE \ -storetype BKS \ -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ -providerpath /usr/share/java/bcprov.jar \ -storepass some-password` 

    Should work out of the box. I was struggling it for over a day even after a perfect answer by @emmby .. Hope this helps someone...

    Just adding -Dtrust_all_cert=true to VM arguments should do. This argument tells java to ignore certificatee checks.

    utiliser cette classe

     public class WCFs { // https://192.168.30.8/myservice.svc?wsdl private static final Ssortingng NAMESPACE = "http://tempuri.org/"; private static final Ssortingng URL = "192.168.30.8"; private static final Ssortingng SERVICE = "/myservice.svc?wsdl"; private static Ssortingng SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/"; public static Thread myMethod(Runnable rp) { Ssortingng METHOD_NAME = "myMethod"; SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); request.addProperty("Message", "Https WCF Running..."); return _call(rp,METHOD_NAME, request); } protected static HandlerThread _call(final RunProcess rp,final Ssortingng METHOD_NAME, SoapObject soapReq) { final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); int TimeOut = 5*1000; envelope.dotNet = true; envelope.bodyOut = soapReq; envelope.setOutputSoapObject(soapReq); final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut); try { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake { @Override public boolean verify(Ssortingng hostname, SSLSession session) { return true; } }); KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password"); ((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL")); } catch(Exception e){} HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber()) { @Override public void run() { Handler h = new Handler(Looper.getMainLooper()); Object response = null; for(int i=0; i<4; i++) { response = send(envelope, httpTransport_net , METHOD_NAME, null); try {if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){} if(response != null) break; ThreadHelper.threadSleep(250); } if(response != null) { if(rp != null) { rp.setArguments(response.toString()); h.post(rp); } } else { if(Thread.currentThread().isInterrupted()) return; if(rp != null) { rp.setExceptionState(true); h.post(rp); } } ThreadHelper.stopThread(this); } }; thread.start(); return thread; } private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List headerList) { try { if(headerList != null) androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList); else androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope); Object res = envelope.getResponse(); if(res instanceof SoapPrimitive) return (SoapPrimitive) envelope.getResponse(); else if(res instanceof SoapObject) return ((SoapObject) envelope.getResponse()); } catch(Exception e) {} return null; } public static KeyStore getFromRaw(@RawRes int id, Ssortingng algorithm, Ssortingng filePassword) { try { InputStream inputStream = ResourceMaster.openRaw(id); KeyStore keystore = KeyStore.getInstance(algorithm); keystore.load(inputStream, filePassword.toCharArray()); inputStream.close(); return keystore; } catch(Exception e) {} return null; } public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, Ssortingng SSLAlgorithm) { try { TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustKey); SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS" context.init(null, tmf.getTrustManagers(), null); return context.getSocketFactory(); } catch(Exception e){} return null; } 

    }

    work with all https

     httpClient = new DefaultHttpClient(); SSLContext ctx = SSLContext.getInstance("TLS"); X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, Ssortingng ssortingng) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, Ssortingng ssortingng) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; ctx.init(null, new TrustManager[]{tm}, null); SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, ssf)); 

    There a many answers above but I wasn’t able to get any of them working correctly (with my limited time), so for anyone else in the same situation you can try the code below which worked perfectly for my java testing purposes:

      public static HttpClient wrapClient(HttpClient base) { try { SSLContext ctx = SSLContext.getInstance("TLS"); X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, Ssortingng ssortingng) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, Ssortingng ssortingng) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; ctx.init(null, new TrustManager[]{tm}, null); SSLSocketFactory ssf = new SSLSocketFactory(ctx); ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ClientConnectionManager ccm = base.getConnectionManager(); SchemeRegistry sr = ccm.getSchemeRegistry(); sr.register(new Scheme("https", ssf, 443)); return new DefaultHttpClient(ccm, base.getParams()); } catch (Exception ex) { return null; } } 

    and call like:

     DefaultHttpClient baseClient = new DefaultHttpClient(); HttpClient httpClient = wrapClient(baseClient ); 

    Reference: http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-problem-using-apache-httpclient/

    Simply use this –

     public DefaultHttpClient wrapClient(HttpClient base) { try { SSLContext ctx = SSLContext.getInstance("TLS"); X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, Ssortingng ssortingng) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, Ssortingng ssortingng) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; ctx.init(null, new TrustManager[]{tm}, null); SSLSocketFactory ssf = new SSLSocketFactory(ctx); ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ClientConnectionManager ccm = base.getConnectionManager(); SchemeRegistry sr = ccm.getSchemeRegistry(); sr.register(new Scheme("https", ssf, 443)); return new DefaultHttpClient(ccm, base.getParams()); } catch (Exception ex) { return null; } } 

    Daniel’s answer was good except I had to change this code…

      SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); 

    to this code…

      ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); SchemeRegistry registry = ccm.getShemeRegistry() registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); 

    to get it to work.