Ich verwende Retrofit, um auf meine REST - API zuzugreifen. Wenn ich jedoch meine API hinter ssl stelle und mit http://myhost/myapi
darauf zugreife, erhalte ich folgende Fehlermeldung:
Muss ich jetzt etwas mehr tun, da sich meine API hinter SSL befindet?
So schließe ich mich an:
private final String API = "https://myhost/myapi";
private final RestAdapter REST_ADAPTER = new RestAdapter.Builder()
.setServer(API)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
01-10 09:49:55.621 2076-2100/com.myapp.mobile D/Retrofit﹕ javax.net.ssl.SSLHandshakeException: Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:401)
at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.Java:209)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.Java:478)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.Java:433)
at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.Java:290)
at libcore.net.http.HttpEngine.sendRequest(HttpEngine.Java:240)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.Java:282)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.Java:497)
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.Java:134)
at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.Java:90)
at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.Java:48)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.Java:287)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.Java:222)
at $Proxy12.signin(Native Method)
at com.myapp.loginactivity$3.doInBackground(LoginActivity.Java:143)
at com.myapp.loginactivity$3.doInBackground(LoginActivity.Java:136)
at Android.os.AsyncTask$2.call(AsyncTask.Java:287)
at Java.util.concurrent.FutureTask.run(FutureTask.Java:234)
at Android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.Java:230)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1080)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:573)
at Java.lang.Thread.run(Thread.Java:841)
Caused by: Java.security.cert.CertificateException: Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.Apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.Java:282)
at org.Apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.Java:202)
at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.Java:595)
at org.Apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:398)
at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.Java:209)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.Java:478)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.Java:433)
at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.Java:290)
at libcore.net.http.HttpEngine.sendRequest(HttpEngine.Java:240)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.Java:282)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.Java:497)
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.Java:134)
at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.Java:90)
at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.Java:48)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.Java:287)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.Java:222)
at $Proxy12.signin(Native Method)
at com.myapp.LoginActivity$3.doInBackground(LoginActivity.Java:143)
at com.myapp.LoginActivity$3.doInBackground(LoginActivity.Java:136)
at Android.os.AsyncTask$2.call(AsyncTask.Java:287)
at Java.util.concurrent.FutureTask.run(FutureTask.Java:234)
at Android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.Java:230)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1080)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:573)
at Java.lang.Thread.run(Thread.Java:841)
Der Grund dafür ist, dass die JVM/Dalvik den CA-Zertifikaten im System oder den Benutzerzertifikatspeichern nicht vertrauen.
Um dies mit Retrofit zu beheben: Wenn Sie okhttp verwenden, ist es bei einem anderen Client sehr ähnlich.
Sie müssen tun:
EIN). Erstellen Sie einen Zertifizierungsspeicher, der den öffentlichen Schlüssel der Zertifizierungsstelle enthält. Dazu müssen Sie das nächste Skript für * nix starten. Sie benötigen die OpenSL-Installation auf Ihrem Rechner und können von https://www.bouncycastle.org/ the jar bcprov-jdk16-1.46.jar herunterladen. Laden Sie diese Version nicht .__ herunter. Andernfalls ist die Version 1.5x nicht mit Android 4.0.4 kompatibel.
#!/bin/bash
if [ -z $1 ]; then
echo "Usage: cert2Android<CA cert PEM file>"
exit 1
fi
CACERT=$1
BCJAR=bcprov-jdk16-1.46.jar
TRUSTSTORE=mytruststore.bks
ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in $CACERT`
if [ -f $TRUSTSTORE ]; then
rm $TRUSTSTORE || exit 1
fi
echo "Adding certificate to $TRUSTSTORE..."
keytool -import -v -trustcacerts -alias $ALIAS \
-file $CACERT \
-keystore $TRUSTSTORE -storetype BKS \
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
-providerpath $BCJAR \
-storepass secret
echo ""
echo "Added '$CACERT' with alias '$ALIAS' to $TRUSTSTORE..."
B). Kopieren Sie die Datei truststore mytruststore.bks in res/raw Ihres Projekts
C). Festlegen von SSLContext der Verbindung:
.............
okHttpClient = new OkHttpClient();
try {
KeyStore ksTrust = KeyStore.getInstance("BKS");
InputStream instream = context.getResources().openRawResource(R.raw.mytruststore);
ksTrust.load(instream, "secret".toCharArray());
// TrustManager decides which certificate authorities to use.
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ksTrust);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) {
e.printStackTrace();
}
.................
Hallo dasselbe Problem, das ich gelöst habe, du kannst es versuchen
// SET SSL
public static OkClient setSSLFactoryForClient(OkHttpClient client) {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
client.setSslSocketFactory(sslSocketFactory);
client.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
return new OkClient(client);
}
Es gibt vier Möglichkeiten, die ich kenne:
Ich gehe davon aus, dass Sie nicht dafür bezahlen wollen. Daher denke ich, dass die eleganteste Lösung die erste ist.
http://blog.crazybob.org/2010/02/Android-trusting-ssl-certificates.html
Das SSL ist nicht richtig konfiguriert. Diese trustAnchor-Fehler bedeuten normalerweise, dass der Trust Store nicht gefunden werden kann. Überprüfen Sie Ihre Konfiguration und vergewissern Sie sich, dass Sie tatsächlich auf den Trust Store zeigen und dass dieser vorhanden ist.
Stellen Sie sicher, dass Sie eine -Djavax.net.ssl.trustStore
-Systemeigenschaft festgelegt haben, und überprüfen Sie, ob der Pfad tatsächlich zum Trust Store führt.
Sie können SSL-Debugging auch aktivieren, indem Sie diese Systemeigenschaft -Djavax.net.debug=all
festlegen. In der Debug-Ausgabe wird festgestellt, dass der Trust Store nicht gefunden werden kann.
Dies kann aus verschiedenen Gründen geschehen, darunter:
bitte überprüfen Sie diesen Link zur Lösung: https://developer.Android.com/training/articles/security-ssl.html#CommonProblems
Ich benutze diese Klasse und habe kein Problem.
public class WCFs
{
// https://192.168.30.8/myservice.svc?wsdl
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "192.168.30.8";
private static final String SERVICE = "/myservice.svc?wsdl";
private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";
public static Thread myMethod(Runnable rp)
{
String METHOD_NAME = "myMethod";
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("Message", "Https WCF Running...");
return _call(rp,METHOD_NAME, request);
}
protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
{
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
int TimeOut = 5*1000;
envelope.dotNet = true;
envelope.bodyOut = soapReq;
envelope.setOutputSoapObject(soapReq);
final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);
try
{
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
{
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
});
KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));
}
catch(Exception e){}
HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
{
@Override
public void run()
{
Handler h = new Handler(Looper.getMainLooper());
Object response = null;
for(int i=0; i<4; i++)
{
response = send(envelope, httpTransport_net , METHOD_NAME, null);
try
{if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}
if(response != null)
break;
ThreadHelper.threadSleep(250);
}
if(response != null)
{
if(rp != null)
{
rp.setArguments(response.toString());
h.post(rp);
}
}
else
{
if(Thread.currentThread().isInterrupted())
return;
if(rp != null)
{
rp.setExceptionState(true);
h.post(rp);
}
}
ThreadHelper.stopThread(this);
}
};
thread.start();
return thread;
}
private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
{
try
{
if(headerList != null)
androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
else
androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);
Object res = envelope.getResponse();
if(res instanceof SoapPrimitive)
return (SoapPrimitive) envelope.getResponse();
else if(res instanceof SoapObject)
return ((SoapObject) envelope.getResponse());
}
catch(Exception e)
{}
return null;
}
public static KeyStore getFromRaw(@RawRes int id, String algorithm, String filePassword)
{
try
{
InputStream inputStream = ResourceMaster.openRaw(id);
KeyStore keystore = KeyStore.getInstance(algorithm);
keystore.load(inputStream, filePassword.toCharArray());
inputStream.close();
return keystore;
}
catch(Exception e)
{}
return null;
}
public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
{
try
{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustKey);
SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
catch(Exception e){}
return null;
}
}