Fidati di tutti i certificati che utilizzano HttpClient su HTTPS

Recentemente ha pubblicato una domanda riguardante HttpClient su Https (che si trova qui ). Ho fatto qualche progresso, ma ho incontrato nuovi problemi. Come per il mio ultimo problema, non riesco a trovare un esempio che funzioni per me. Fondamentalmente, voglio che il mio client accetti qualsiasi certificato (perché sto sempre puntando solo a un server) ma continuo a ricevere javax.net.ssl.SSLException: Not trusted server certificate exception.

Quindi questo è quello che ho:

 public void connect() throws A_WHOLE_BUNCH_OF_EXCEPTIONS { HttpPost post = new HttpPost(new URI(PROD_URL)); post.setEntity(new StringEntity(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); } 

Ed ecco l’errore che sto ottenendo:

 W/System.err( 901): javax.net.ssl.SSLException: Not trusted server certificate 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 

Nota: non implementarlo nel codice di produzione che utilizzerai su una rete di cui non ti fidi del tutto. Soprattutto tutto ciò che riguarda la rete pubblica.

La tua domanda è proprio quello che voglio sapere. Dopo aver fatto alcune ricerche, la conclusione è la seguente.

In modo HttpClient, dovresti creare una class personalizzata da org.apache.http.conn.ssl.SSLSocketFactory, non da quella org.apache.http.conn.ssl.SSLSocketFactory stessa. Alcuni indizi possono essere trovati in questo post La gestione SSL personalizzata ha smesso di funzionare su Android 2.2 FroYo .

Un esempio è come …

 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, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[] { tm }, null); } @Override public Socket createSocket(Socket socket, String 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(); } } 

e utilizzare questa class durante la creazione dell’istanza di 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(); } } 

A proposito, il link sottostante è per qualcuno che sta cercando la soluzione HttpURLConnection. Connessione Https Android

Ho testato i due tipi di soluzioni di cui sopra su froyo e funzionano tutti come un incantesimo nei miei casi. Infine, l’uso di HttpURLConnection potrebbe affrontare i problemi di reindirizzamento, ma questo va oltre l’argomento.

Nota: prima di decidere di fidarsi di tutti i certificati, probabilmente dovresti conoscere bene il sito e non essere dannoso per l’utente finale.

In effetti, il rischio che prendi dovrebbe essere considerato attentamente, compreso l’effetto del sito simulato dell’hacker menzionato nei seguenti commenti che ho profondamente apprezzato. In alcune situazioni, anche se potrebbe essere difficile prendersi cura di tutti i certificati, è meglio conoscere gli svantaggi impliciti per fidarsi di tutti loro.

Fondamentalmente hai quattro potenziali soluzioni per correggere un’eccezione “Non attendibile” su Android utilizzando httpclient:

  1. Fidati di tutti i certificati. Non farlo, a meno che tu non sappia davvero cosa stai facendo.
  2. Creare un SSLSocketFactory personalizzato che si fidi solo del certificato. Questo funziona finché sai esattamente a quali server ti connetteresti, ma non appena avrai bisogno di connetterti a un nuovo server con un certificato SSL diverso, dovrai aggiornare la tua app.
  3. Crea un file di archivio di chiavi che contenga la “lista principale” di certificati di Android, quindi aggiungi il tuo. Se uno di questi certificati scade lungo la strada, sei responsabile dell’aggiornamento nella tua app. Non riesco a pensare a una ragione per farlo.
  4. Creare un SSLSocketFactory personalizzato che utilizza il certificato KeyStore incorporato, ma ricade su un KeyStore alternativo per tutto ciò che non riesce a verificare con il valore predefinito.

Questa risposta utilizza la soluzione n. 4, che mi sembra la più robusta.

La soluzione consiste nell’utilizzare un SSLSocketFactory che può accettare più KeyStor, consentendo di fornire il proprio KeyStore con i propri certificati. Ciò consente di caricare certificati di livello superiore aggiuntivi come Thawte che potrebbero mancare su alcuni dispositivi Android. Ti consente anche di caricare anche i tuoi certificati autofirmati. Utilizzerà innanzitutto i certificati predefiniti dei dispositivi predefiniti e ricadrà sui certificati aggiuntivi solo se necessario.

Per prima cosa, dovrai determinare quale certificato ti manca nel tuo KeyStore. Esegui il seguente comando:

 openssl s_client -connect www.yourserver.com:443 

E vedrai output come il seguente:

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

Come puoi vedere, il nostro certificato di origine è di Thawte. Vai al sito Web del tuo provider e trova il certificato corrispondente. Per noi, era qui , e puoi vedere che quello di cui avevamo bisogno era l’unico Copyright 2006.

Se si sta utilizzando un certificato autofirmato, non è necessario eseguire il passaggio precedente poiché si dispone già del certificato di firma.

Quindi, creare un file di archivio di chiavi contenente il certificato di firma mancante. Crazybob ha dettagli su come farlo su Android , ma l’idea è di fare quanto segue:

Se non lo hai già, scarica la libreria del fornitore bouncy castle da: http://www.bouncycastle.org/latest_releases.html . Questo andrà sul tuo classpath di seguito.

Esegui un comando per estrarre il certificato dal server e creare un file pem. In questo caso, mycert.pem.

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

Quindi eseguire i seguenti comandi per creare il keystore.

 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 

Si noterà che lo script precedente inserisce il risultato in res/raw/mystore.bks . Ora hai un file che carichi nella tua app per Android che fornisce i certificati mancanti.

Per fare ciò, registrare SSLSocketFactory per lo schema 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); 

Per creare il tuo 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 strings.xml/mystore_password ks.load(in, context.getString( R.string.mystore_password ).toCharArray()); } finally { in.close(); } return new AdditionalKeyStoresSSLSocketFactory(ks); } catch( Exception e ) { throw new RuntimeException(e); } } 

Infine, il codice AdditionalKeyStoresSSLSocketFactory, che accetta il nuovo KeyStore e controlla se il KeyStore incorporato non riesce a convalidare un certificato SSL:

 /** * Allows you to trust certificates 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, String 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, String 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, String 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()]); } } } 

Aggiungi questo codice prima di HttpsURLConnection e sarà fatto. Capito.

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

Spero che questo ti aiuta.

Questa è una ctriggers idea. Affidarsi a qualsiasi certificato è (molto) leggermente migliore rispetto all’utilizzo di nessun SSL. Quando dici “Voglio che il mio cliente accetti qualsiasi certificato (perché sto sempre puntando solo a un server)” supponi che questo significhi che in qualche modo puntare a “un server” sia sicuro, che non è su una rete pubblica.

Sei completamente aperto a un attacco man-in-the-middle affidandoti a qualsiasi certificato. Chiunque può eseguire il proxy della connessione stabilendo una connessione SSL separata con te e con il server finale. Il MITM ha quindi accesso all’intera richiesta e risposta. A meno che tu non abbia davvero bisogno di SSL in primo luogo (il tuo messaggio non ha nulla di sensibile e non esegue l’autenticazione) non dovresti fidarti ciecamente di tutti i certificati.

Dovresti considerare di aggiungere il certificato pubblico a un jks usando keytool e usarlo per build il tuo factory socket, come questo:

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

Questo ha un avvertimento a cui prestare attenzione. Il certificato scadrà alla fine e il codice smetterà di funzionare in quel momento. Puoi facilmente determinare quando accadrà guardando il certificato.

È ansible disabilitare il controllo SSL HttpURLConnection a scopo di test in questo modo dall’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 di HttpComponents è stata modificata. Funziona con il codice qui sotto.

 public static HttpClient getTestHttpClient() { try { SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){ @Override public boolean isTrusted(X509Certificate[] chain, String 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(); } } 

Il codice di cui sopra in https://stackoverflow.com/a/6378872/1553004 è corretto, tranne che DEVE anche chiamare il verificatore del nome host:

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

Mi sono registrato allo stackoverflow espressamente per aggiungere questa correzione. Ascolta il mio avvertimento!

Sto aggiungendo una risposta per coloro che usano httpclient-4.5 e probabilmente anche per 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, String 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); } } } 

Affidarmi a tutti i certificati non era una vera alternativa per me, così ho fatto quanto segue per ottenere HttpsURLConnection per fidarsi di un nuovo certificato (vedi anche http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store- on.html ).

  1. Ottieni il certificato; Ho ottenuto questo risultato esportando il certificato in Firefox (fai clic sull’icona del lucchetto, ottieni i dettagli del certificato, fai clic su Esporta), quindi utilizzi il portacolo per esportare un truststore (BKS).

  2. Caricare il Truststore da /res/raw/geotrust_cert.bks con il seguente codice:

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

Ecco una versione molto semplice che utilizza il codice httpclient 4.1.2. Questo può quindi essere modificato in qualsiasi algoritmo di fiducia che ritieni opportuno.

 public static HttpClient getTestHttpClient() { try { SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){ @Override public boolean isTrusted(X509Certificate[] chain, String 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(); } } 

Mi è sembrata la risposta di “emmby” (risposta 16 giugno 11 alle 21:29), elemento n. 4: “Creare un SSLSocketFactory personalizzato che utilizza il certificato incorporato KeyStore, ma ricade su un KeyStore alternativo per tutto ciò che non riesce per verificare con l’impostazione predefinita. ”

Questa è un’implementazione semplificata. Carica il keystore di sistema e unisci con il keystore dell’applicazione.

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

A simple mode to convert from JKS to 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 certificates 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(String requestTokenEndpointUrl, String accessTokenEndpointUrl, String authorizationWebsiteUrl) { super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl); //this.httpClient = new DefaultHttpClient();//Version implemented and that throws the famous "javax.net.ssl.SSLException: Not trusted server certificate" if the certificate is not signed with a CA this.httpClient = MySSLSocketFactory.getNewHttpClient();//This will work with all certificates (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-certificates-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, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[] { tm }, null); } @Override public Socket createSocket(Socket socket, String 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(); } } 

}

Spero che questo aiuti qualcuno.

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

 /** * Disables the SSL certificate 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, String arg1) throws CertificateException { // Not implemented } @Override public void checkServerTrusted(X509Certificate[] arg0, String 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` 

con

  `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 certificate checks.

use this class

 public class WCFs { // https://192.168.30.8/myservice.svc?wsdl private static final String NAMESPACE = "http://tempuri.org/"; private static final String URL = "192.168.30.8"; private static final String SERVICE = "/myservice.svc?wsdl"; private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/"; public static Thread myMethod(Runnable rp) { String 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 String 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(String 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, String algorithm, String 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, String 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, String string) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, String string) 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, String string) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, String string) 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, String string) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, String string) 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.