2013-10-17 16 views
9

Ich habe eine Android-Anwendung, die Verbindung zu einem SSL-Webdienst, den wir hosten. Der Webserver ist Apache und verfügt über eine eigene CA, die wir erstellt haben, und ein selbstsigniertes SSL-Zertifikat.Android SSL HTTP-Anfrage mit selbst signierten Cert und CA

Ich habe unser CA-Zertifikat auf das Android-Tablet im Abschnitt "Benutzer-vertrauenswürdige Zertifikate" in Sicherheit importiert.

ich Zugriff auf den Web-Server getestet und kann bestätigen, dass das Web-Service-Zertifikat als gültig zeigt (Abbildung unten)

Valid certificate

Hier wird das Zertifikat in den Sicherheitseinstellungen ist:

Trusted certificate

Wenn ich versuche, auf den Webservice in meiner Anwendung zuzugreifen, bekomme ich die Ausnahme "Kein Peer-Zertifikat" ausgelöst.

Dies ist die SSL-Implementierung vereinfacht:

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

} 

Die while-Schleife spuckt nur die Zertifikate aus, und ich kann meine eigenen CA in den Protokollen sehen. Aber ich bekomme immer noch die Ausnahme "Kein Peer-Zertifikat".

10-17 18: 29: 01,234: I/System.out (4006): Kein Peer-Zertifikat

Muss ich manuell irgendwie mein CA-Zertifikat laden in dieser Implementierung?

+0

Haben Sie Ihr CA-Zertifikat in dieser Implementierung manuell Laden versucht? – BON

+0

Sie können ein kostenloses und vertrauenswürdiges SSL-Zertifikat für Ihre Domain von http://www.startssl.com/ beziehen (ich verwende sie für einige Apps), so dass Sie sich nicht darum kümmern müssen, Ihre CA auf jedem Gerät hinzuzufügen Das möchte deine App verwenden. –

Antwort

4

unter Verwendung Gelöst: HttpsURLConnection

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

Dies scheint mit Benutzer installiert CA-Zertifikate zu funktionieren.

2

können Sie erreicht die Aufgabe auch DefaultHttpClient verwenden, obwohl here is suggested zu:

HttpURLConnection Bevorzugen für neuen Code

Achten Sie auch auf den Import oder das Hinzufügen Zertifikat für Ihre Anwendung, da Sie haben Probleme beim Aktualisieren des Zertifikats, wenn es abläuft.

Hier wie ein DefaultHttpClient Vertrauen auf ein selbst signiertes Zertifikat erhalten:

* 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; 
} 

und hier wie ein HttpsURLConnection zu bekommen:

* 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; 
}