Les étapes principales suivantes sont nécessaires pour établir une connexion sécurisée à partir des autorités de certification qui ne sont pas considérées comme approuvées par la plate-forme Android.
Comme demandé par de nombreux utilisateurs, j'ai reproduit les parties les plus importantes de mon article de blog ici:
- Récupérez tous les certificats requis (racine et toute autorité de certification intermédiaire)
- Créez un keystore avec keytool et le fournisseur BouncyCastle et importez les certificats
- Chargez le keystore dans votre application Android et utilisez-le pour les connexions sécurisées (je recommande d'utiliser Apache HttpClient au lieu du standard
java.net.ssl.HttpsURLConnection
(plus facile à comprendre, plus performant)
Prenez les certificats
Vous devez obtenir tous les certificats qui créent une chaîne à partir du certificat de point de terminaison jusqu'à la racine CA. Cela signifie, tous les certificats de l'autorité de certification intermédiaire (le cas échéant) ainsi que le certificat de l'autorité de certification racine. Vous n'avez pas besoin d'obtenir le certificat de point de terminaison.
Créer le keystore
Téléchargez le fournisseur BouncyCastle et stockez-le dans un emplacement connu. Assurez-vous également que vous pouvez appeler la commande keytool (généralement située sous le dossier bin de votre installation JRE).
Importez maintenant les certificats obtenus (n'importez pas le certificat de point de terminaison) dans un magasin de clés au format BouncyCastle.
Je ne l'ai pas testé, mais je pense que l'ordre d'importation des certificats est important. Cela signifie que vous importez d'abord le certificat de l'autorité de certification intermédiaire le plus bas, puis jusqu'au certificat de l'autorité de certification racine.
Avec la commande suivante, un nouveau keystore (s'il n'est pas déjà présent) avec le mot de passe mysecret sera créé et le certificat de CA intermédiaire sera importé. J'ai également défini le fournisseur BouncyCastle, où il peut être trouvé sur mon système de fichiers et le format de keystore. Exécutez cette commande pour chaque certificat de la chaîne.
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
Vérifiez si les certificats ont été correctement importés dans le fichier de clés:
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
Devrait afficher toute la chaîne:
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
Vous pouvez maintenant copier le keystore en tant que ressource brute dans votre application Android sous res/raw/
Utilisez le keystore dans votre application
Tout d'abord, nous devons créer un Apache HttpClient personnalisé qui utilise notre keystore pour les connexions 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);
}
}
}
Nous avons créé notre HttpClient personnalisé, maintenant nous pouvons l'utiliser pour des connexions sécurisées. Par exemple, lorsque nous faisons un appel GET à une ressource 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();
C'est tout ;)