android - verified - retrofit ssl pinning
httpclient ssl certificate en android (3)
Tengo algunos problemas con SSL utilizando httpclient en Android. Estoy intentando acceder al certificado autofirmado en detalles. Deseo que mi aplicación confíe en todos los certificados (usaré SSL solo para el cifrado de datos). Primero intenté usar esta guía http://hc.apache.org/httpclient-3.x/sslguide.html en el escritorio funciona bien, pero en android todavía tengo javax.net.ssl.SSLException: Certificado de servidor no confiable. Después de buscar en google, encontré otros ejemplos de cómo habilitar ssl.
http://groups.google.com/group/android-developers/browse_thread/thread/62d856cdcfa9f16e - Trabajando cuando uso URLConnection pero con HttpClient todavía tengo la excepción.
http://www.discursive.com/books/cjcook/reference/http-webdav-sect-self-signed.html - en el escritorio, el uso de jar de apache funciona, pero el uso de android incluido en las clases de SDK no puede hacer que funcione .
http://mail-archives.apache.org/mod_mbox/hc-httpclient-users/200808.mbox/%3C1218824624.6561.14.camel@ubuntu%3E - también obtienes la misma excepción
Entonces, ¿cómo puedo confiar en todos los certificados en Android usando HttpClient?
Si observa el código de DefaultHttpClient, se ve así:
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(
new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager connManager = null;
HttpParams params = getParams();
...
}
Observe la asignación del esquema https a org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory ().
Puede crear una implementación personalizada para la interfaz org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory
( http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/protocol/SecureProtocolSocketFactory. html ) donde puede crear java.net.SSLSocket
con un TrustManager
personalizado que acepte todo el certificado.
Es posible que desee consultar JSSE para obtener más detalles en http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSefGuide.html
La idea clave es utilizar un SSLSocketFactory personalizado que implemente LayeredSocketFactory. El socket personalizado no necesita HostNameVerifier.
private static final class TrustAllSSLSocketFactory implements
LayeredSocketFactory {
private static final TrustAllSSLSocketFactory DEFAULT_FACTORY = new TrustAllSSLSocketFactory();
public static TrustAllSSLSocketFactory getSocketFactory() {
return DEFAULT_FACTORY;
}
private SSLContext sslcontext;
private javax.net.ssl.SSLSocketFactory socketfactory;
private TrustAllSSLSocketFactory() {
super();
TrustManager[] tm = new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// do nothing
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// do nothing
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
} };
try {
this.sslcontext = SSLContext.getInstance(SSLSocketFactory.TLS);
this.sslcontext.init(null, tm, new SecureRandom());
this.socketfactory = this.sslcontext.getSocketFactory();
} catch ( NoSuchAlgorithmException e ) {
Log.e(LOG_TAG,
"Failed to instantiate TrustAllSSLSocketFactory!", e);
} catch ( KeyManagementException e ) {
Log.e(LOG_TAG,
"Failed to instantiate TrustAllSSLSocketFactory!", e);
}
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
socket, host, port, autoClose);
return sslSocket;
}
@Override
public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException {
if ( host == null ) {
throw new IllegalArgumentException(
"Target host may not be null.");
}
if ( params == null ) {
throw new IllegalArgumentException(
"Parameters may not be null.");
}
SSLSocket sslsock = (SSLSocket) ( ( sock != null ) ? sock
: createSocket() );
if ( ( localAddress != null ) || ( localPort > 0 ) ) {
// we need to bind explicitly
if ( localPort < 0 ) {
localPort = 0; // indicates "any"
}
InetSocketAddress isa = new InetSocketAddress(localAddress,
localPort);
sslsock.bind(isa);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
InetSocketAddress remoteAddress;
remoteAddress = new InetSocketAddress(host, port);
sslsock.connect(remoteAddress, connTimeout);
sslsock.setSoTimeout(soTimeout);
return sslsock;
}
@Override
public Socket createSocket() throws IOException {
// the cast makes sure that the factory is working as expected
return (SSLSocket) this.socketfactory.createSocket();
}
@Override
public boolean isSecure(Socket sock) throws IllegalArgumentException {
return true;
}
}
Luego puede continuar utilizando el SSLSocketFactory personalizado en el registro del esquema admitido.
private static final BasicHttpParams sHttpParams = new BasicHttpParams();
private static final SchemeRegistry sSupportedSchemes = new SchemeRegistry();
static {
sHttpParams.setParameter("http.socket.timeout", READ_TIMEOUT);
sHttpParams.setParameter("http.connection.timeout", CONNECT_TIMEOUT);
sSupportedSchemes.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
sSupportedSchemes.register(new Scheme("https",
TrustAllSSLSocketFactory.getSocketFactory(), 443));
}
En lugar de aceptar todos los certificados, recomiendo esta solución: Confiar en todos los certificados utilizando HttpClient a través de HTTPS