2012-01-10 25 views
12

Ogni volta che viene eseguito questo codice, viene visualizzato un errore "Nessun certificato peer".SSL Android - Nessun certificato peer

Il certificato SSL è valido, acquistato da Namecheap (PositiveSSL). Ha prima CA crt e si apre bene nel browser Android.

HTTP server: nginx

Codice:

public void postData() { 

// Add your data 
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); 

nameValuePairs.add(new BasicNameValuePair("string", "myfirststring")); 

try { 

    HttpPost post = new HttpPost(new URI("https://example.com/submit")); 
    post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 

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

    // Execute HTTP Post Request 
    @SuppressWarnings("unused") 
    HttpResponse result = client.execute(post); 

} catch (ClientProtocolException e) { 
    // TODO Auto-generated catch block 
    Log.e(TAG,e.getMessage()); 
    Log.e(TAG,e.toString()); 
    e.printStackTrace(); 
} catch (IOException e) { 
    // TODO Auto-generated catch block 
    Log.e(TAG,e.getMessage()); 
    Log.e(TAG,e.toString()); 
    e.printStackTrace(); 
} catch (URISyntaxException e) { 
     // TODO Auto-generated catch block 
    Log.e(TAG,e.getMessage()); 
    Log.e(TAG,e.toString()); 
    e.printStackTrace(); 
    } catch (KeyStoreException e) { 
     // TODO Auto-generated catch block 
     Log.e(TAG,e.getMessage()); 
     Log.e(TAG,e.toString()); 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     // TODO Auto-generated catch block 
     Log.e(TAG,e.getMessage()); 
     Log.e(TAG,e.toString()); 
     e.printStackTrace(); 
    } catch (CertificateException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
     Log.e(TAG,e.toString()); 
     Log.e(TAG,e.getMessage()); 
    } catch (KeyManagementException e) { 
     // TODO Auto-generated catch block 
     Log.e(TAG,e.getMessage()); 
     Log.e(TAG,e.toString()); 
     e.printStackTrace(); 
    } catch (UnrecoverableKeyException e) { 
     // TODO Auto-generated catch block 
     Log.e(TAG,e.getMessage()); 
     Log.e(TAG,e.toString()); 
     e.printStackTrace(); 
    } 
} 

Adb Logcat:

01-10 15:44:34.872: E/myfirstapp(572): No peer certificate 
01-10 15:44:34.872: E/myfirstapp(572): javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 
01-10 15:44:34.883: W/System.err(572): javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 
01-10 15:44:34.883: W/System.err(572): at org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:137) 
01-10 15:44:34.883: W/System.err(572): at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93) 
01-10 15:44:34.908: W/System.err(572): at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381) 
01-10 15:44:34.908: W/System.err(572): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:165) 
01-10 15:44:34.908: W/System.err(572): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
01-10 15:44:34.914: W/System.err(572): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
01-10 15:44:34.914: W/System.err(572): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360) 
01-10 15:44:34.914: W/System.err(572): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
01-10 15:44:34.914: W/System.err(572): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
01-10 15:44:34.914: W/System.err(572): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 
01-10 15:44:34.933: W/System.err(572): at com.giggsey.myfirstapp.myfirstappIntent.postData(myfirstappIntent.java:126) 
01-10 15:44:34.933: W/System.err(572): at com.giggsey.myfirstapp.myfirstappIntent.onReceive(myfirstappIntent.java:77) 
01-10 15:44:34.933: W/System.err(572): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2118) 
01-10 15:44:34.945: W/System.err(572): at android.app.ActivityThread.access$1500(ActivityThread.java:122) 
01-10 15:44:34.945: W/System.err(572): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
01-10 15:44:34.952: W/System.err(572): at android.os.Handler.dispatchMessage(Handler.java:99) 
01-10 15:44:34.952: W/System.err(572): at android.os.Looper.loop(Looper.java:137) 
01-10 15:44:34.962: W/System.err(572): at android.app.ActivityThread.main(ActivityThread.java:4340) 
01-10 15:44:34.962: W/System.err(572): at java.lang.reflect.Method.invokeNative(Native Method) 
01-10 15:44:34.962: W/System.err(572): at java.lang.reflect.Method.invoke(Method.java:511) 
01-10 15:44:34.972: W/System.err(572): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
01-10 15:44:34.972: W/System.err(572): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
01-10 15:44:34.981: W/System.err(572): at dalvik.system.NativeStart.main(Native Method) 
+1

Dal momento che il certificato è valido, si può provare senza il proprio SchemeRegistry, basandosi solo su Android predefinito? – kenota

+2

Utilizzare questa pagina per testare il certificato. Sono abbastanza sicuro che ti mancano alcuni certificati intermedi. https://www.digicert.com/help/index.htm Questo dovrebbe farti sapere se si tratta di un problema relativo al server. Quale penso che sia – blindstuff

+0

@blindstuff Tutti i tick da quella pagina. – giggsey

risposta

20

Anche se questa domanda ha una risposta accettata ho pensato che valga la pena di rispondere da quando ho ottenuto lo stesso errore su un dispositivo Android più vecchio in esecuzione 2.3.3:

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 

Dopo aver letto diverse domande correlate diverse su SO I è giunto alla conclusione che questo può accadere per due (forse più?) motivi:

  • impropria installazione di un certificato intermedio
  • ordinamento non corretto della catena di certificati

Nel mio caso si trattava di un ordine errato di certificati. Ad esempio sto postando l'ordine cert da this question con la risposta perspicace da parte dell'utente bdc. È possibile ottenere l'ordine del certificato facendo seguito da un terminale:

openssl s_client -connect eu.battle.net:443 

(ovviamente sostituendo eu.battle.net con il proprio server). Nel caso di eu.battle.net a quel tempo l'ordine era:

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

Mentre avrebbe dovuto essere:

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

La regola è che l'emittente di cert "n" nella catena dovrebbe corrispondere al soggetto di cert "n + 1".

Una volta trovato il problema, è stato banale cambiare l'ordine del cert sul server e le cose hanno iniziato immediatamente a funzionare sul dispositivo Android 2.3.3. Immagino sia positivo che le vecchie versioni di Android siano un po 'fastidiose per quanto riguarda l'ordine dei certificati, ma è stato anche un incubo visto che le nuove versioni di Android riordinano automaticamente i certificati. Diavolo, anche un vecchio iPhone 3GS funzionava con certs fuori uso.

+0

Grazie per questa risposta. Ho avuto il problema di ordinare i certificati e mi stava facendo impazzire - a quanto pare alcune versioni di Android accettano i certificati nell'ordine sbagliato, e altri no. –

+0

Idem per me, i certificati rapidssl erano indietro, tutti i browser funzionavano ma la mia app non funzionava. Quando ho riordinato i certificati, tutto ha funzionato. Grazie mille! – mvsjes2

+0

Venerato. Ho provato molti diversi metodi di keytool e bouncycastle, ma alla fine Android 2.3 non mi piaceva non avere il cert intermedio nella catena ssl del mio server. Né Android Jellybean, Firefox, IE o Chrome si sono lamentati, ma solo Android 2.3 DefaultHTTPClient. Dopo aver aggiunto gd_intermediate.crt, la mia app GB ha funzionato su SSL. Vedi qui per i dettagli: http: //informationideas.com/news/2011/11/29/android-making-https-requests-with-ssl-from-godaddy-no-peer-certificate-error/ – wufoo

2

Se non è un problema di server, che nella maggior parte dei casi che ho visto questo problema è legato a mancare intermedia certs o cattiva una installazione dei certificati.

provare a utilizzare il Registro schema come questo:

SchemeRegistry schReg = new SchemeRegistry(); 
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 
schReg.register(new Scheme("https",SSLSocketFactory.getSocketFactory(), 443)); 
SingleClientConnManager conMgr = new SingleClientConnManager(params,post.getParams()); 
+3

Ho usato 'mClient = new DefaultHttpClient(); mClient.getConnectionManager(). getSchemeRegistry(). register (new Scheme ("SSLSocketFactory", SSLSocketFactory.getSocketFactory(), 443)); e ha funzionato. Grazie! – shkschneider

+0

@shkschneider, sei il mio eroe! – sha256

+2

@shkschneider ... ho anche provato questa linea con il mio HttpClient ma mi ha dato lo stesso errore "No Peer Certificate" ... sto inviando parametri JSON con richiesta https ... Per favore aiutami – Noman

-1

Perché certificato è valido, non si dovrebbe usare personalizzato SchemeRegistry, si dovrebbe solo fare affidamento su di default Android meccanismo di convalida dei certificati.

+2

Potresti per favore approfondire Questo? Non riesco a capire come utilizzare questo meccanismo predefinito. –

+3

Puoi approfondire questo argomento per coloro che non sanno come codificare per questo meccanismo predefinito? – JPM

+0

Perfetto. Grazie. SO ha un limite di char per la risposta non accetto perfetto. #sad –

3

Questo white paper può riepilogare tutto ciò che è necessario sapere per far funzionare il protocollo SSL su Android. Sulla base della mia recente esperienza, l'approccio migliore è ottenere un certificato SSL che piaccia ad Android.

+1

"l'approccio migliore è ottenere un certificato SSL che piaccia ad Android." Sfortunatamente, l'unica volta utile è quando si ha il lusso di controllare il lato server. È raro.Quel libro bianco è sicuramente utile comunque. –

0

Attualmente sto provando a diagnosticare questo in questo momento, e sembra che una cosa che potrebbe causare questo problema è che il server non funziona o la connessione scade.

0

Rimuovere tutto il personale del Registro di sistema e l'errore "Nessun errore di certificazione peer" è stato risolto.

ie.

ho rimuovere questo codice dal mio

SchemeRegistry schReg = new SchemeRegistry(); 
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 
schReg.register(new Scheme("https",SSLSocketFactory.getSocketFactory(), 443)); 
SingleClientConnManager conMgr = new SingleClientConnManager(params,post.getParams()); 

Può essere che si può provare a rimuovere quelli dalla vostra.

0

Ho provato a risolvere questo problema dal codice Android aggiungendo una regola "accetta tutto il certificato". Ma tutto lo sforzo da parte di Android era inutile. Infine, facendo un CNAME nella registrazione del registro che assicurava che tutte le richieste andassero allo stesso indirizzo IP risolto il problema

1

Controlla l'ora del tuo sistema. Se l'ora non è quella attuale potrebbe causare questo errore.

+1

Questo può essere un commento. –

0

Assicurarsi di utilizzare HttpsURLConnection anziché HttpURLConnection.

Problemi correlati