修复 javax.net.ssl.SSLPeerUnverifiedException:没有对等证书
Fixing javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
我正在开发一个 android 应用程序,它必须使用自签名证书 (SSL/TLS1.2) 通过 https 与服务器通信。我也在用 Volley.
我正在学习 this 教程。保存 .crt 文件,在 keytool -importcert -v -trustcacerts -file "cert.crt" -alias IntermediateCA -keystore "key.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-146.jar" -storetype BKS -storepass blabla
的原始目录中创建 key.bks
等等。
当我向服务器发送数据时,Response.ErrorListener() 收到无对等证书错误。
尝试使用 Postman 发送我的 json(当然,必须添加证书)- 工作正常。
在我的 android 设备上手动安装证书 - 工作正常
我怎样才能让它发挥作用?
我为这个问题奋斗了很多。
看来我要发送到的服务器有一个虚拟主机(托管在 GAE 上)。在 Android 5.0 上这个问题已经解决了,但是在 Android 5.0 以下你必须添加 SNI 支持自己。
下面是对这个问题的解释http://blog.dev001.net/post/67082904181/android-using-sni-and-tlsv1-2-with-apache.
因此,为了使我的代码正常工作,我必须更改教程中的 SslSocketFactory class。它发挥了魔力。
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.params.HttpParams;
import android.annotation.TargetApi;
import android.net.SSLCertificateSocketFactory;
import android.os.Build;
class SslSocketFactory extends SSLSocketFactory {
InputStream mkeyStore;
String mkeyStorePassword;
public SslSocketFactory(InputStream keyStore, String keyStorePassword) throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException{
super(null);
mkeyStore=keyStore;
mkeyStorePassword=keyStorePassword;
}
@Override
public Socket connectSocket(Socket s, String host, int port, InetAddress localAddress, int localPort, HttpParams params) throws IOException {
return null;
}
@Override
public Socket createSocket() throws IOException {
return null;
}
@Override
public boolean isSecure(Socket s) throws IllegalArgumentException {
if (s instanceof SSLSocket) {
return ((SSLSocket) s).isConnected();
}
return false;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
SSLSocket sslSocket = null;
if (autoClose) {
socket.close();
}
SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0, null);
try {
sslSocketFactory.setTrustManagers(new TrustManager[] { new SsX509TrustManager( mkeyStore, mkeyStorePassword) });
} catch (GeneralSecurityException e1) {
e1.printStackTrace();
}
sslSocket = (SSLSocket) sslSocketFactory.createSocket(InetAddress.getByName(host), port);
sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
sslSocketFactory.setHostname(sslSocket, host);
} else {
try {
java.lang.reflect.Method setHostnameMethod = sslSocket.getClass().getMethod("setHostname", String.class);
setHostnameMethod.invoke(sslSocket, host);
} catch (Exception e) {
}
}
return sslSocket;
}
}
我正在开发一个 android 应用程序,它必须使用自签名证书 (SSL/TLS1.2) 通过 https 与服务器通信。我也在用 Volley.
我正在学习 this 教程。保存 .crt 文件,在 keytool -importcert -v -trustcacerts -file "cert.crt" -alias IntermediateCA -keystore "key.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-146.jar" -storetype BKS -storepass blabla
的原始目录中创建 key.bks
等等。
当我向服务器发送数据时,Response.ErrorListener() 收到无对等证书错误。
尝试使用 Postman 发送我的 json(当然,必须添加证书)- 工作正常。
在我的 android 设备上手动安装证书 - 工作正常
我怎样才能让它发挥作用?
我为这个问题奋斗了很多。 看来我要发送到的服务器有一个虚拟主机(托管在 GAE 上)。在 Android 5.0 上这个问题已经解决了,但是在 Android 5.0 以下你必须添加 SNI 支持自己。 下面是对这个问题的解释http://blog.dev001.net/post/67082904181/android-using-sni-and-tlsv1-2-with-apache.
因此,为了使我的代码正常工作,我必须更改教程中的 SslSocketFactory class。它发挥了魔力。
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.params.HttpParams;
import android.annotation.TargetApi;
import android.net.SSLCertificateSocketFactory;
import android.os.Build;
class SslSocketFactory extends SSLSocketFactory {
InputStream mkeyStore;
String mkeyStorePassword;
public SslSocketFactory(InputStream keyStore, String keyStorePassword) throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException{
super(null);
mkeyStore=keyStore;
mkeyStorePassword=keyStorePassword;
}
@Override
public Socket connectSocket(Socket s, String host, int port, InetAddress localAddress, int localPort, HttpParams params) throws IOException {
return null;
}
@Override
public Socket createSocket() throws IOException {
return null;
}
@Override
public boolean isSecure(Socket s) throws IllegalArgumentException {
if (s instanceof SSLSocket) {
return ((SSLSocket) s).isConnected();
}
return false;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
SSLSocket sslSocket = null;
if (autoClose) {
socket.close();
}
SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0, null);
try {
sslSocketFactory.setTrustManagers(new TrustManager[] { new SsX509TrustManager( mkeyStore, mkeyStorePassword) });
} catch (GeneralSecurityException e1) {
e1.printStackTrace();
}
sslSocket = (SSLSocket) sslSocketFactory.createSocket(InetAddress.getByName(host), port);
sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
sslSocketFactory.setHostname(sslSocket, host);
} else {
try {
java.lang.reflect.Method setHostnameMethod = sslSocket.getClass().getMethod("setHostname", String.class);
setHostnameMethod.invoke(sslSocket, host);
} catch (Exception e) {
}
}
return sslSocket;
}
}