Android 应用程序中的 2 向 SSL 不工作
2-way SSL in Android App not working
我正在尝试创建一个 Android 应用程序,它使用 2-way SSL 与 NodeJS 应用程序进行通信。我有 2 个版本的代码来发出请求,但两个版本都不起作用。如果我 运行 使用纯 Java,那么第一个版本的代码可以工作,但是当我尝试将其放入我的 Android 应用程序时,服务器无法识别客户端证书:
版本 1:
System.setProperty("javax.net.ssl.keyStore", "jks-keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass1");
System.setProperty("javax.net.ssl.trustStore", "jkstruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "pass2");
// specify url
String url = "https://example.com/startup";
System.out.println("Startup URL is " + url);
// This block of code keeps self-signed certificates from causing errors.
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
}
);
// initiate the request
try
{
URL hp = new URL(url);
HttpsURLConnection hpCon = (HttpsURLConnection)hp.openConnection();
boolean isProxy = hpCon.usingProxy();
InputStream obj = (InputStream) hpCon.getInputStream();
// print out JSON response
System.out.println(convertStreamToString(obj));
}
catch (Exception ex)
{
ex.printStackTrace();
}
错误 1:
03-17 12:25:18.616: W/System.err(331): javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
版本 2:
// load truststore certificate
InputStream clientTruststoreIs = getResources().openRawResource(R.raw.tsserver);
KeyStore trustStore = null;
trustStore = KeyStore.getInstance("BKS");
trustStore.load(clientTruststoreIs, "pass1".toCharArray());
System.out.println("Loaded server certificates: " + trustStore.size());
// initialize trust manager factory with the read truststore
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
// setup client certificate
// load client certificate
InputStream keyStoreStream = getResources().openRawResource(R.raw.tsclient);
KeyStore keyStore = null;
keyStore = KeyStore.getInstance("BKS");
keyStore.load(keyStoreStream, "pass2".toCharArray());
System.out.println("Loaded client certificates: " + keyStore.size());
// initialize key manager factory with the read client certificate
KeyManagerFactory keyManagerFactory = null;
keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "pass2".toCharArray());
// initialize SSLSocketFactory to use the certificates
SSLSocketFactory socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS, keyStore, "pass2", trustStore, null, null);
// Set basic data
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUseExpectContinue(params, true);
HttpProtocolParams.setUserAgent(params, "Android app/1.0.0");
// Make pool
ConnPerRoute connPerRoute = new ConnPerRouteBean(12);
ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
ConnManagerParams.setMaxTotalConnections(params, 20);
// Set timeout
HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
HttpConnectionParams.setSoTimeout(params, 20 * 1000);
HttpConnectionParams.setSocketBufferSize(params, 8192);
// Some client params
HttpClientParams.setRedirecting(params, false);
// Register http/s schemas!
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", socketFactory, 443));
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params);
try {
String res = executeHttpGet(sClient, "https://example.com/startup");
System.out.println("------- SSL RESULT IS = " + res);
} catch (Exception e) {
System.out.println("---- ex " + e.getMessage());
e.printStackTrace();
}
错误 2:服务器没有看到客户端证书
这两个代码示例都会导致服务器看不到客户端证书。任何想法为什么这不起作用?谢谢。
如果我们仔细阅读 documentaion 我们可以发现:
自签名证书抛出类似于您遇到的错误。对于服务器而言,自签名证书被信任以无任何错误地通过并不重要,在任何一种情况下都会抛出 SSLHandshakeException。
要将其传递给 assemble 一组受信任的 CA 证书,并将它们添加到您的信任库中。然后从该 CA 发出的所有证书都将受到信任,这将忽略直接将它们添加到 da truststore 文件中的需要。
现在如何将 CA 可信证书添加到信任库:
设置您自己的 CA here
然后:
给定 CA 证书,cacert.pem,格式为 PEM ,您可以通过输入以下命令将证书添加到 JKS 信任库(或创建新的信任库):
keytool -import -file cacert.pem -alias CAAlias -keystore truststore.ts -storepass StorePass
其中 CAAlias 是一个方便的标记,使您能够使用 keytool 实用程序访问此特定的 CA 证书。文件 truststore.ts 是一个包含 CA 证书 的密钥库文件——如果该文件不存在,keytool 实用程序会创建一个. StorePass 密码提供对密钥库文件的访问,truststore.t
看看这个document。
我正在尝试创建一个 Android 应用程序,它使用 2-way SSL 与 NodeJS 应用程序进行通信。我有 2 个版本的代码来发出请求,但两个版本都不起作用。如果我 运行 使用纯 Java,那么第一个版本的代码可以工作,但是当我尝试将其放入我的 Android 应用程序时,服务器无法识别客户端证书:
版本 1:
System.setProperty("javax.net.ssl.keyStore", "jks-keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pass1");
System.setProperty("javax.net.ssl.trustStore", "jkstruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "pass2");
// specify url
String url = "https://example.com/startup";
System.out.println("Startup URL is " + url);
// This block of code keeps self-signed certificates from causing errors.
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
}
);
// initiate the request
try
{
URL hp = new URL(url);
HttpsURLConnection hpCon = (HttpsURLConnection)hp.openConnection();
boolean isProxy = hpCon.usingProxy();
InputStream obj = (InputStream) hpCon.getInputStream();
// print out JSON response
System.out.println(convertStreamToString(obj));
}
catch (Exception ex)
{
ex.printStackTrace();
}
错误 1:
03-17 12:25:18.616: W/System.err(331): javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
版本 2:
// load truststore certificate
InputStream clientTruststoreIs = getResources().openRawResource(R.raw.tsserver);
KeyStore trustStore = null;
trustStore = KeyStore.getInstance("BKS");
trustStore.load(clientTruststoreIs, "pass1".toCharArray());
System.out.println("Loaded server certificates: " + trustStore.size());
// initialize trust manager factory with the read truststore
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
// setup client certificate
// load client certificate
InputStream keyStoreStream = getResources().openRawResource(R.raw.tsclient);
KeyStore keyStore = null;
keyStore = KeyStore.getInstance("BKS");
keyStore.load(keyStoreStream, "pass2".toCharArray());
System.out.println("Loaded client certificates: " + keyStore.size());
// initialize key manager factory with the read client certificate
KeyManagerFactory keyManagerFactory = null;
keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "pass2".toCharArray());
// initialize SSLSocketFactory to use the certificates
SSLSocketFactory socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS, keyStore, "pass2", trustStore, null, null);
// Set basic data
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUseExpectContinue(params, true);
HttpProtocolParams.setUserAgent(params, "Android app/1.0.0");
// Make pool
ConnPerRoute connPerRoute = new ConnPerRouteBean(12);
ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
ConnManagerParams.setMaxTotalConnections(params, 20);
// Set timeout
HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
HttpConnectionParams.setSoTimeout(params, 20 * 1000);
HttpConnectionParams.setSocketBufferSize(params, 8192);
// Some client params
HttpClientParams.setRedirecting(params, false);
// Register http/s schemas!
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", socketFactory, 443));
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params);
try {
String res = executeHttpGet(sClient, "https://example.com/startup");
System.out.println("------- SSL RESULT IS = " + res);
} catch (Exception e) {
System.out.println("---- ex " + e.getMessage());
e.printStackTrace();
}
错误 2:服务器没有看到客户端证书
这两个代码示例都会导致服务器看不到客户端证书。任何想法为什么这不起作用?谢谢。
如果我们仔细阅读 documentaion 我们可以发现:
自签名证书抛出类似于您遇到的错误。对于服务器而言,自签名证书被信任以无任何错误地通过并不重要,在任何一种情况下都会抛出 SSLHandshakeException。
要将其传递给 assemble 一组受信任的 CA 证书,并将它们添加到您的信任库中。然后从该 CA 发出的所有证书都将受到信任,这将忽略直接将它们添加到 da truststore 文件中的需要。
现在如何将 CA 可信证书添加到信任库:
设置您自己的 CA here
然后:
给定 CA 证书,cacert.pem,格式为 PEM ,您可以通过输入以下命令将证书添加到 JKS 信任库(或创建新的信任库):
keytool -import -file cacert.pem -alias CAAlias -keystore truststore.ts -storepass StorePass
其中 CAAlias 是一个方便的标记,使您能够使用 keytool 实用程序访问此特定的 CA 证书。文件 truststore.ts 是一个包含 CA 证书 的密钥库文件——如果该文件不存在,keytool 实用程序会创建一个. StorePass 密码提供对密钥库文件的访问,truststore.t
看看这个document。