2013-10-17 28 views
9

Ho un'applicazione Android che si sta connettendo a un servizio Web SSL che ospitiamo. Il server Web è apache e ha una propria CA che abbiamo creato e un certificato SSL autofirmato.Richiesta HTTP SSL HTTP con certificato autofirmato e CA

Ho importato il certificato CA sul tablet Android nella sezione Certificati attendibili dell'utente in Sicurezza.

Ho testato l'accesso al server web e posso confermare che il certificato di servizio web mostra come valido (screenshot qui sotto)

Valid certificate

Ecco il certificato nelle impostazioni di sicurezza:

Trusted certificate

Ora quando provo ad accedere al servizio web nella mia applicazione ottengo l'eccezione "Nessun certificato peer" attivata.

Questa è l'implementazione SSL semplificata:

public class MainActivity extends Activity { 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    // allows network on main thread (temp hack) 
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 
    StrictMode.setThreadPolicy(policy); 

    SchemeRegistry schemeRegistry = new SchemeRegistry(); 
    //schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); 
    schemeRegistry.register(new Scheme("https", newSSLSocketFactory(), 443)); 


    HttpParams params = new BasicHttpParams(); 

    SingleClientConnManager mgr = new SingleClientConnManager(params, schemeRegistry); 

    HttpClient client = new DefaultHttpClient(mgr, params); 

    HttpPost httpRequest = new HttpPost("https://our-web-service.com"); 

    try { 
     client.execute(httpRequest); 
    } catch (Exception e) { 
     e.printStackTrace(); // 
    } 
} 

/* 
* Standard SSL CA Store Setup // 
*/ 
private SSLSocketFactory newSSLSocketFactory() { 

    KeyStore trusted; 

    try { 
     trusted = KeyStore.getInstance("AndroidCAStore"); 
     trusted.load(null, null); 
     Enumeration<String> aliases = trusted.aliases(); 

     while (aliases.hasMoreElements()) { 
      String alias = aliases.nextElement(); 
      X509Certificate cert = (X509Certificate) trusted.getCertificate(alias); 
      Log.d("", "Alias="+alias); 
      Log.d("", "Subject DN: " + cert.getSubjectDN().getName()); 
      Log.d("", "Issuer DN: " + cert.getIssuerDN().getName()); 
     }  

     SSLSocketFactory sf = new SSLSocketFactory(trusted); 
     sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); 

     return sf; 

    } catch (Exception e) { 
     // TODO Auto-generated catch block 
     throw new AssertionError(e); 
    } 
} 

} 

Il ciclo while appena sputa fuori i certificati e posso vedere il mio CA nei registri. Ma ottengo ancora l'eccezione "No Peer Certificate".

10-17 18: 29: 01,234: I/System.out (4006): Nessun certificato pari

Devo caricare manualmente il mio certificato CA in qualche modo in questa implementazione?

+0

Hai provato manualmente il caricamento del certificato CA in questa implementazione? – BON

+0

Puoi ottenere un certificato SSL gratuito e affidabile per il tuo dominio da http://www.startssl.com/ (li sto utilizzando per alcune app), quindi non devi occuparti di aggiungere la CA in ogni dispositivo che vuole usare la tua app. –

risposta

4

risolto utilizzando: HttpsURLConnection

URLConnection conn = null; 
URL url = new URL(strURL); 
conn = url.openConnection(); 
HttpsURLConnection httpsConn = (HttpsURLConnection) conn; 

Questo sembra funzionare bene con i certificati CA installato dall'utente.

2

È possibile compiuto l'operazione utilizzando anche DefaultHttpClient, anche se here is suggested a:

Preferisco HttpURLConnection per il nuovo codice

Prestare attenzione anche in importazione o l'aggiunta di certificato alla propria applicazione in quanto si può avere problemi nell'aggiornamento del certificato quando scadrà.

Ecco come ottenere un DefaultHttpClient fidarsi di un certificato autofirmato:

* This method returns the appropriate HttpClient. 
* @param isTLS Whether Transport Layer Security is required. 
* @param trustStoreInputStream The InputStream generated from the BKS keystore. 
* @param trustStorePsw The password related to the keystore. 
* @return The DefaultHttpClient object used to invoke execute(request) method. 
private DefaultHttpClient getHttpClient(boolean isTLS, InputStream trustStoreInputStream, String trustStorePsw) 
    throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, UnrecoverableKeyException { 
    DefaultHttpClient client = null;   
    SchemeRegistry schemeRegistry = new SchemeRegistry(); 
    Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 8080); 
    schemeRegistry.register(http); 
    if(isTLS) { 
     KeyStore trustKeyStore = null; 
     char[] trustStorePswCharArray = null; 
     if(trustStorePsw!=null) { 
      trustStorePswCharArray = trustStorePsw.toCharArray(); 
     } 
     trustKeyStore = KeyStore.getInstance("BKS"); 
     trustKeyStore.load(trustStoreInputStream, trustStorePswCharArray); 
     SSLSocketFactory sslSocketFactory = null; 
     sslSocketFactory = new SSLSocketFactory(trustKeyStore); 
     Scheme https = new Scheme("https", sslSocketFactory, 8443); 
     schemeRegistry.register(https); 
    }     
    HttpParams httpParams = new BasicHttpParams(); 
    HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT); 
    HttpConnectionParams.setSoTimeout(httpParams, SOCKET_TIMEOUT);   
    ClientConnectionManager clientConnectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);   
    client = new DefaultHttpClient(clientConnectionManager, httpParams);   
    return client; 
} 

ed ecco come ottenere un HttpsURLConnection:

* This method set the certificate for the HttpsURLConnection 
* @param url The url to contact. 
* @param certificateInputStream The InputStream generated from the .crt certificate. 
* @param certAlias The alias for the certificate. 
* @return The returned HttpsURLConnection 
private HttpsURLConnection getHttpsURLConnection(URL url, InputStream certificateInputStream, String certAlias) 
    throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException { 
    HttpsURLConnection connection = null; 
    CertificateFactory certFactory = null; 
    Certificate cert = null; 
    KeyStore keyStore = null; 
    TrustManagerFactory tmFactory = null; 
    SSLContext sslContext = null; 
    // Load certificates from an InputStream 
    certFactory = CertificateFactory.getInstance("X.509"); 
    cert = certFactory.generateCertificate(certificateInputStream); 
    certificateInputStream.close(); 
    // Create a KeyStore containing the trusted certificates 
    keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
    keyStore.load(null, null); 
    keyStore.setCertificateEntry(certAlias, cert); 
    // Create a TrustManager that trusts the certificates in our KeyStore 
    tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    tmFactory.init(keyStore); 
    // Create an SSLContext that uses our TrustManager 
    sslContext = SSLContext.getInstance("TLS"); 
    sslContext.init(null, tmFactory.getTrustManagers(), null); 
    connection = (HttpsURLConnection)url.openConnection(); 
    connection.setSSLSocketFactory(sslContext.getSocketFactory()); 
    return connection; 
}