As etapas principais a seguir são necessárias para obter uma conexão segura das autoridades de certificação que não são consideradas confiáveis pela plataforma Android.
Conforme solicitado por muitos usuários, espelhei as partes mais importantes do artigo do meu blog aqui:
- Pegue todos os certificados necessários (raiz e quaisquer CAs intermediárias)
- Crie um keystore com keytool e o provedor BouncyCastle e importe os certificados
- Carregue o keystore no seu aplicativo Android e use-o para as conexões seguras (eu recomendo usar o Apache HttpClient em vez do padrão
java.net.ssl.HttpsURLConnection
(mais fácil de entender, mais eficiente)
Pegue os certs
É necessário obter todos os certificados que constroem uma cadeia a partir do certificado do terminal até a CA raiz. Isso significa que qualquer certificado CA intermediário (se presente) e também o certificado CA raiz. Você não precisa obter o certificado do terminal.
Crie o keystore
Faça o download do provedor BouncyCastle e armazene-o em um local conhecido. Verifique também se você pode chamar o comando keytool (geralmente localizado na pasta bin da instalação do JRE).
Agora importe os certificados obtidos (não importe o certificado do terminal) para um keystore no formato BouncyCastle.
Não testei, mas acho importante a ordem de importação dos certificados. Isso significa, importe primeiro o certificado CA intermediário mais baixo e depois o certificado CA raiz.
Com o comando a seguir, um novo keystore (se ainda não estiver presente) com a senha mysecret será criado e o certificado CA intermediário será importado. Também defini o provedor BouncyCastle, onde ele pode ser encontrado no meu sistema de arquivos e no formato keystore. Execute este comando para cada certificado na cadeia.
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
Verifique se os certificados foram importados corretamente no 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
Deve gerar toda a cadeia:
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
Agora você pode copiar o keystore como um recurso bruto no seu aplicativo Android em res/raw/
Use o keystore no seu aplicativo
Primeiro, precisamos criar um Apache HttpClient personalizado que use nosso keystore para conexões 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);
}
}
}
Criamos nosso HttpClient personalizado, agora podemos usá-lo para conexões seguras. Por exemplo, quando fazemos uma chamada GET para um recurso 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();
É isso aí ;)