Je l'ai cherché partout sur internet et bien que certaines personnes prétendent avoir trouvé la solution, soit il ne fonctionne pas ou n'est pas un exemple de code pour le sauvegarder.
Personne ne sait comment accepter une auto-signé cert en Java sur Android?
Un exemple de code, ce serait parfait.
Réponses
Trop de publicités?J'ai cette fonctionnalité dans exchangeIt, qui se connecte à Microsoft exchange via WebDav. Voici un code pour créer un client http qui va se connecter à l'auto-signé cert via SSL:
SchemeRegistry schemeRegistry = new SchemeRegistry();
// http scheme
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// https scheme
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
Le EasySSLSocketFactory est ici, et le EasyX509TrustManager est ici.
Le code pour exchangeIt est open source, et hébergé sur googlecode ici, si vous avez des questions. Je ne suis pas en train de le plus, mais le code devrait fonctionner.
A noter que depuis Android 2.2 le processus a changé un peu, afin de vérifier ce faire le code du travail ci-dessus.
Voici une autre façon, sans aucune des classes supplémentaires:
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
private void trustEveryone() {
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){
public boolean verify(String hostname, SSLSession session) {
return true;
}});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new X509TrustManager(){
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}}}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
context.getSocketFactory());
} catch (Exception e) { // should never happen
e.printStackTrace();
}
}
Bon Matin tout le monde
J'ai fait face à cette question hier, lors de la migration de notre société API RESTful HTTPS, mais à l'aide de SSL auto-signé certs.
J'ai cherché partout, mais tous les "corriger", a marqué les réponses que j'ai trouvé consiste à désactiver la validation de certificat, clairement écrasant tous les sens du protocole SSL.
Je suis finalement arrivé à une solution.
-
Créer Des Locaux De Stockage Des Clés
Pour permettre à votre application de valider vos certificats auto-signés, vous devez fournir une coutume keystore avec les certificats d'une manière qui Android peuvent faire confiance à votre point de terminaison.
Le format de ces personnalisées des fichiers de clés est "BKS" de BouncyCastle, si vous avez besoin de la version 1.46 de BouncyCastleProvider que vous pouvez télécharger Ici
Vous avez également besoin de votre certificat auto-signé, je vais considérer que je ts nommé
self_cert.pem
Maintenant la commande pour la création de votre fichier de clés est
$ keytool -import -v -trustcacerts -alias 0 \ -file *PATH_TO_SELF_CERT.PEM* \ -keystore *PATH_TO_KEYSTORE* \ -storetype BKS \ -provider org.bouncycastle.jce.provider.BouncyCastleProvider \ -providerpath *PATH_TO_bcprov-jdk15on-146.jar* \ -storepass *STOREPASS*
PATH_TO_KEYSTORE
de points à un fichier où votre fichier de clés sera créé, il ne DOIT PAS EXISTERPATH_TO_bcprov-jdk15on-146.jar.JAR
est le chemin d'accès pour le téléchargement .jar bibliothèque.STOREPASS
est votre nouvellement créé de mot de passe du fichier de clés. -
Inclure fichier de clés sur votre Application
Copiez le nouveau fichier de stockage des clés d'
PATH_TO_KEYSTORE
deres/raw/certs.bks
(certs.bks est juste le nom du fichier, vous pouvez utiliser n'importe quel nom que vous voulez)Créer une clé en
res/values/strings.xml
avec<resources> ... <string name="store_pass">*STOREPASS*</string> ... </resources>
-
Créer un cette classe qui hérite
DefaultHttpClient
import android.content.Context; import android.util.Log; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.HttpParams; import java.io.IOException; import java.io.InputStream; import java.security.*; public class MyHttpClient extends DefaultHttpClient { private static Context appContext = null; private static HttpParams params = null; private static SchemeRegistry schmReg = null; private static Scheme httpsScheme = null; private static Scheme httpScheme = null; private static String TAG = "MyHttpClient"; public MyHttpClient(Context myContext) { appContext = myContext; if (httpScheme == null || httpsScheme == null) { httpScheme = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80); httpsScheme = new Scheme("https", mySSLSocketFactory(), 443); } getConnectionManager().getSchemeRegistry().register(httpScheme); getConnectionManager().getSchemeRegistry().register(httpsScheme); } private SSLSocketFactory mySSLSocketFactory() { SSLSocketFactory ret = null; try { final KeyStore ks = KeyStore.getInstance("BKS"); final InputStream inputStream = appContext.getResources().openRawResource(R.raw.certs); ks.load(inputStream, appContext.getString(R.string.store_pass).toCharArray()); inputStream.close(); ret = new SSLSocketFactory(ks); } catch (UnrecoverableKeyException ex) { Log.d(TAG, ex.getMessage()); } catch (KeyStoreException ex) { Log.d(TAG, ex.getMessage()); } catch (KeyManagementException ex) { Log.d(TAG, ex.getMessage()); } catch (NoSuchAlgorithmException ex) { Log.d(TAG, ex.getMessage()); } catch (IOException ex) { Log.d(TAG, ex.getMessage()); } catch (Exception ex) { Log.d(TAG, ex.getMessage()); } finally { return ret; } } }
Maintenant, il suffit d'utiliser une instance de MyHttpClient
comme vous le feriez avec DefaultHttpClient
pour faire de votre https requêtes, et il va utiliser et de valider correctement vos certificats SSL auto-signés.
HttpResponse httpResponse;
HttpPost httpQuery = new HttpPost("https://yourserver.com");
... set up your query ...
MyHttpClient myClient = new MyHttpClient(myContext);
try{
httpResponse = myClient.(peticionHttp);
// Check for 200 OK code
if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
... do whatever you want with your response ...
}
}catch (Exception ex){
Log.d("httpError", ex.getMessage());
}
Cheers!
À moins que j'ai raté quelque chose, les autres réponses sur cette page sont DANGEREUX, et sont fonctionnellement équivalents à pas à l'aide de SSL à tous. Si vous faites confiance à des certificats auto-signés, sans procéder à d'autres vérifications pour s'assurer que les certificats sont ceux qui vous attendent, alors n'importe qui peut créer un certificat auto-signé et peut se faire passer pour votre serveur. À ce stade, vous n'avez aucune sécurité réelle.
La seule façon légitime de le faire (sans écrire une pleine SSL pile) est à ajouter une ancre de confiance pour être dignes de confiance lors de la vérification du certificat du processus. Les deux impliquent de coder en dur la confiance d'ancrage certificat dans votre application et de l'ajouter à ce que ancres de confiance que le système d'exploitation (ou d'autre, vous ne serez pas en mesure de se connecter à votre site si vous obtenez un vrai certificat).
Je suis conscient de deux façons de le faire:
Créer un magasin de confiance tel que décrit à http://www.ibm.com/developerworks/java/library/j-customssl/#8
-
Créer une sous-classe personnalisée de X509TrustManager et remplacer le getAcceptedIssuers méthode retourne un tableau qui contient votre certificat:
public X509Certificate[] getAcceptedIssuers() { X509Certificate[] trustedAnchors = super.getAcceptedIssuers(); /* Create a new array with room for an additional trusted certificate. */ X509Certificate[] myTrustedAnchors = new X509Certificate[trustedAnchors.length + 1]; System.arraycopy(trustedAnchors, 0, myTrustedAnchors, 0, trustedAnchors.length); /* Load your certificate. Thanks to http://stackoverflow.com/questions/11857417/x509trustmanager-override-without-allowing-all-certs for this bit. */ InputStream inStream = new FileInputStream("fileName-of-cert"); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream); inStream.close(); /* Add your anchor cert as the last item in the array. */ myTrustedAnchors[trustedAnchors.length] = cert; return myTrustedAnchors; }
Notez que ce code est entièrement testées et peuvent même ne pas compiler, mais devrait au moins vous orienter dans la bonne direction.
Brian Yarger réponse fonctionne sous Android 2.2 ainsi, si vous modifiez le plus grand createSocket surcharge de la méthode comme suit. Il m'a fallu un certain temps pour obtenir l'auto-signé Ssl de travail.
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
}