通过 https 发送 POST 请求时出现 SSLHandshakeException
SSLHandshakeException when sending POST request via https
我试图向远程安全服务器发送 POST 请求( https 调用)。
首先,我使用 OkHTTP 库进行调用,因为该库可以在以前的应用程序中进行 http 调用,但是使用 https 它不再起作用,请参阅我之前的 post:
我决定尝试使用 HttpURLConnection 进行调用,如下所述:https://developer.android.com/reference/java/net/HttpURLConnection.html
我使用的代码仅适用于某些设备。
它可以在配备 SIM 卡和 wifi 的 android 6.0 上的 Wiko 上使用,但不能在 Android 4.2.2 上的三星上使用,只能通过 link 上网无线网络
这是我遇到的问题logcat:
02-23 12:29:59.893 11026-11951 W/System.err: javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.923 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:382)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:231)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:281)
02-23 12:29:59.923 11026-11951 W/System.err: at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:109)
02-23 12:29:59.923 11026-11951 W/System.err: at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:82)
02-23 12:29:59.923 11026-11951 W/System.err: at android.os.AsyncTask.call(AsyncTask.java:287)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:234)
02-23 12:29:59.923 11026-11951 W/System.err: at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:230)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
02-23 12:29:59.933 11026-11951 W/System.err: at java.lang.Thread.run(Thread.java:856)
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: java.security.cert.CertificateException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:296)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:197)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:598)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:379)
02-23 12:29:59.933 11026-11951 W/System.err: ... 16 more
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.943 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1475)
02-23 12:29:59.943 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:305)
02-23 12:29:59.943 11026-11951 W/System.err: at com.sec.android.security.pkix.SecCertPathValidatorSpi.engineValidate(SecCertPathValidatorSpi.java:99)
02-23 12:29:59.953 11026-11951 W/System.err: at java.security.cert.CertPathValidator.validate(CertPathValidator.java:190)
02-23 12:29:59.953 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:283)
02-23 12:29:59.953 11026-11951 W/System.err: ... 20 more
02-23 12:29:59.953 11026-11951 W/System.err: Caused by: java.security.SignatureException: Signature was not verified
02-23 12:29:59.953 11026-11951 W/System.err: at org.apache.harmony.security.provider.cert.X509CertImpl.verify(X509CertImpl.java:384)
02-23 12:29:59.953 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities.verifyX509Certificate(CertPathValidatorUtilities.java:1428)
02-23 12:29:59.953 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1470)
02-23 12:29:59.953 11026-11951 W/System.err: ... 24 more
以及附加到此日志的代码:
class NetworkAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
Authentification authentification = new Authentification();
authentification.setApplicationToken(applicationtoken);
Gson gson = new Gson();
//String json = gson.toJson(authentification);
String json = "";
Log.d(TAG, json);
JSONObject auth = new JSONObject();
try {
auth.put("application_token",mytoken);
} catch (JSONException e) {
e.printStackTrace();
}
String url = myurl;
try {
URL object = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) object.openConnection();
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Lenght", String.valueOf(json.getBytes("UTF-8").length));
con.setRequestMethod("POST");
con.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
OutputStreamWriter wr = null;
wr = new OutputStreamWriter(con.getOutputStream());
wr.write(auth.toString());
wr.flush();
StringBuilder sb = new StringBuilder();
int HttpResult = 0;
HttpResult = con.getResponseCode();
if (HttpResult == HttpURLConnection.HTTP_OK) {
BufferedReader br = new BufferedReader(
new InputStreamReader(con.getInputStream(), "utf-8"));
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
Log.d(TAG, "First log");
Log.d(TAG, "" + sb.toString());
} else {
Log.d(TAG, "response code : " + HttpResult);
Log.d(TAG, "Http not ok");
Log.d(TAG, con.getResponseMessage());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
我不明白为什么我的第一台设备可以验证签名而另一台不能。
我尝试按照此处的说明同步日期和时间:Could not validate certificate signature?
这里有对我的问题的可能解释,但我不明白 https://groups.google.com/forum/#!topic/android-security-discuss/C_cm3k9SdaM
有人遇到同样的问题并解决了吗?
UPDT :
Alex 和 Anton 提出的两种方法都不适用于我的设备。
使用 Google 播放服务表示提供程序是最新的。使用此处描述的方法启用 TLS 1.1 和 1.2 时,我仍然没有得到签名验证:https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
UPDT 2:
按照此 link,服务器应使用 TLS 1.1:https://www.ssllabs.com
Android 旧设备上的 4.2.2 根本不支持服务器上使用的新 TLS 版本。您需要允许在您的服务器上至少使用 TLS 1.1,客户端无需执行任何操作。
UPD: TLS 1.2 支持在 Android <5 上默认未启用,但您可以使用自定义 SSLSocketFactory
启用它的使用,包括以下内容方法:
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
参考link:https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
正如 Anton Malyshev 所说,Android 4.2.2 不支持 TLS v1.2,事实上在 Android 5.0 以下的设备上,即使某些设备支持它,您也会运行 已弃用证书的问题。
如果设备有播放服务,您可以尝试安装 google ssl 提供程序。
您可以阅读更多关于
https://developer.android.com/training/articles/security-gms-provider.html
我能够使用带有 Retrofit2 的 OkHttp 来实现这一点。它是用 Kotlin 编写的。
您可以在您的启动器中启动您的应用程序时添加它 activity:
try {
SSLContext.getInstance("TLSv1.2")
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
try {
ProviderInstaller.installIfNeeded(context)
} catch (e: Exception) {
e.printStackTrace()
}
同时将此添加到您的 OkHttp Builder 中:
fun provideSecureClient(): OkHttpClient {
try {
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as KeyStore?)
val trustManagers = trustManagerFactory.trustManagers
if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
throw IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers))
}
val trustManager = trustManagers[0] as X509TrustManager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
val sslSocketFactory = sslContext.socketFactory
return OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
private void updateAndroidSecurityProvider() {
try {
ProviderInstaller.installIfNeeded(this);
} catch (Exception e) {
e.getMessage();
}
}
在调用任何 HTTP 之前调用上述方法。
和
在 gradle 中添加了以下库:
compile 'com.google.android.gms:play-services-auth:11.8.0'
我试图向远程安全服务器发送 POST 请求( https 调用)。 首先,我使用 OkHTTP 库进行调用,因为该库可以在以前的应用程序中进行 http 调用,但是使用 https 它不再起作用,请参阅我之前的 post:
我决定尝试使用 HttpURLConnection 进行调用,如下所述:https://developer.android.com/reference/java/net/HttpURLConnection.html 我使用的代码仅适用于某些设备。
它可以在配备 SIM 卡和 wifi 的 android 6.0 上的 Wiko 上使用,但不能在 Android 4.2.2 上的三星上使用,只能通过 link 上网无线网络
这是我遇到的问题logcat:
02-23 12:29:59.893 11026-11951 W/System.err: javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.923 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:382)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:231)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:281)
02-23 12:29:59.923 11026-11951 W/System.err: at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:109)
02-23 12:29:59.923 11026-11951 W/System.err: at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:82)
02-23 12:29:59.923 11026-11951 W/System.err: at android.os.AsyncTask.call(AsyncTask.java:287)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:234)
02-23 12:29:59.923 11026-11951 W/System.err: at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:230)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
02-23 12:29:59.933 11026-11951 W/System.err: at java.lang.Thread.run(Thread.java:856)
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: java.security.cert.CertificateException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:296)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:197)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:598)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:379)
02-23 12:29:59.933 11026-11951 W/System.err: ... 16 more
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.943 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1475)
02-23 12:29:59.943 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:305)
02-23 12:29:59.943 11026-11951 W/System.err: at com.sec.android.security.pkix.SecCertPathValidatorSpi.engineValidate(SecCertPathValidatorSpi.java:99)
02-23 12:29:59.953 11026-11951 W/System.err: at java.security.cert.CertPathValidator.validate(CertPathValidator.java:190)
02-23 12:29:59.953 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:283)
02-23 12:29:59.953 11026-11951 W/System.err: ... 20 more
02-23 12:29:59.953 11026-11951 W/System.err: Caused by: java.security.SignatureException: Signature was not verified
02-23 12:29:59.953 11026-11951 W/System.err: at org.apache.harmony.security.provider.cert.X509CertImpl.verify(X509CertImpl.java:384)
02-23 12:29:59.953 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities.verifyX509Certificate(CertPathValidatorUtilities.java:1428)
02-23 12:29:59.953 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1470)
02-23 12:29:59.953 11026-11951 W/System.err: ... 24 more
以及附加到此日志的代码:
class NetworkAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
Authentification authentification = new Authentification();
authentification.setApplicationToken(applicationtoken);
Gson gson = new Gson();
//String json = gson.toJson(authentification);
String json = "";
Log.d(TAG, json);
JSONObject auth = new JSONObject();
try {
auth.put("application_token",mytoken);
} catch (JSONException e) {
e.printStackTrace();
}
String url = myurl;
try {
URL object = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) object.openConnection();
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Lenght", String.valueOf(json.getBytes("UTF-8").length));
con.setRequestMethod("POST");
con.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
OutputStreamWriter wr = null;
wr = new OutputStreamWriter(con.getOutputStream());
wr.write(auth.toString());
wr.flush();
StringBuilder sb = new StringBuilder();
int HttpResult = 0;
HttpResult = con.getResponseCode();
if (HttpResult == HttpURLConnection.HTTP_OK) {
BufferedReader br = new BufferedReader(
new InputStreamReader(con.getInputStream(), "utf-8"));
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
Log.d(TAG, "First log");
Log.d(TAG, "" + sb.toString());
} else {
Log.d(TAG, "response code : " + HttpResult);
Log.d(TAG, "Http not ok");
Log.d(TAG, con.getResponseMessage());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
我不明白为什么我的第一台设备可以验证签名而另一台不能。 我尝试按照此处的说明同步日期和时间:Could not validate certificate signature?
这里有对我的问题的可能解释,但我不明白 https://groups.google.com/forum/#!topic/android-security-discuss/C_cm3k9SdaM
有人遇到同样的问题并解决了吗?
UPDT : Alex 和 Anton 提出的两种方法都不适用于我的设备。 使用 Google 播放服务表示提供程序是最新的。使用此处描述的方法启用 TLS 1.1 和 1.2 时,我仍然没有得到签名验证:https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
UPDT 2:
按照此 link,服务器应使用 TLS 1.1:https://www.ssllabs.com
Android 旧设备上的 4.2.2 根本不支持服务器上使用的新 TLS 版本。您需要允许在您的服务器上至少使用 TLS 1.1,客户端无需执行任何操作。
UPD: TLS 1.2 支持在 Android <5 上默认未启用,但您可以使用自定义 SSLSocketFactory
启用它的使用,包括以下内容方法:
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
参考link:https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
正如 Anton Malyshev 所说,Android 4.2.2 不支持 TLS v1.2,事实上在 Android 5.0 以下的设备上,即使某些设备支持它,您也会运行 已弃用证书的问题。
如果设备有播放服务,您可以尝试安装 google ssl 提供程序。
您可以阅读更多关于 https://developer.android.com/training/articles/security-gms-provider.html
我能够使用带有 Retrofit2 的 OkHttp 来实现这一点。它是用 Kotlin 编写的。
您可以在您的启动器中启动您的应用程序时添加它 activity:
try {
SSLContext.getInstance("TLSv1.2")
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
try {
ProviderInstaller.installIfNeeded(context)
} catch (e: Exception) {
e.printStackTrace()
}
同时将此添加到您的 OkHttp Builder 中:
fun provideSecureClient(): OkHttpClient {
try {
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as KeyStore?)
val trustManagers = trustManagerFactory.trustManagers
if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
throw IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers))
}
val trustManager = trustManagers[0] as X509TrustManager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
val sslSocketFactory = sslContext.socketFactory
return OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
private void updateAndroidSecurityProvider() {
try {
ProviderInstaller.installIfNeeded(this);
} catch (Exception e) {
e.getMessage();
}
}
在调用任何 HTTP 之前调用上述方法。
和
在 gradle 中添加了以下库:
compile 'com.google.android.gms:play-services-auth:11.8.0'