I seguenti passaggi principali sono necessari per ottenere una connessione protetta dalle autorità di certificazione che non sono considerate affidabili dalla piattaforma Android.
Come richiesto da molti utenti, ho rispecchiato le parti più importanti del mio articolo di blog qui:
- Prendi tutti i certificati richiesti (root e qualsiasi CA intermedia)
- Crea un keystore con keytool e BouncyCastle provider e importa i certificati
- Carica il keystore nella tua app Android e usalo per le connessioni protette (ti consiglio di usare Apache HttpClient invece dello standard
java.net.ssl.HttpsURLConnection
(più facile da capire, più performante)
Prendi le certs
È necessario ottenere tutti i certificati che creano una catena dal certificato endpoint fino alla CA principale. Ciò significa che tutti i certificati CA intermedi (se presenti) e anche il certificato CA radice. Non è necessario ottenere il certificato endpoint.
Crea il keystore
Scarica il provider BouncyCastle e memorizzalo in una posizione nota. Assicurati anche di poter invocare il comando keytool (solitamente situato nella cartella bin dell'installazione di JRE).
Ora importa le certs ottenute (non importare il certificato endpoint) in un keystore formattato BouncyCastle.
Non l'ho provato, ma penso che l'ordine di importazione dei certificati sia importante. Ciò significa, importare prima il certificato CA intermedio più basso e poi fino al certificato CA principale.
Con il comando seguente un nuovo keystore (se non già presente) con la password verrà creato mysecret e verrà importato il certificato CA intermedio. Ho anche definito il provider BouncyCastle, dove può essere trovato sul mio file system e sul formato del keystore. Eseguire questo comando per ciascun certificato nella catena.
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Verifica se i certificati sono stati importati correttamente nel keystore:
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Dovrebbe produrre l'intera catena:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
Ora puoi copiare il keystore come risorsa non elaborata nella tua app Android sotto res/raw/
Usa il keystore nella tua app
Prima di tutto dobbiamo creare un Apache HttpClient personalizzato che utilizza il nostro keystore per le connessioni HTTPS:
import org.apache.http.*
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
Abbiamo creato il nostro HttpClient personalizzato, ora possiamo usarlo per connessioni sicure. Ad esempio, quando effettuiamo una chiamata GET a una risorsa REST:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
Questo è tutto ;)