我试图从自签名证书切换到众所周知的CA(通过“让我们加密”)。下面的原始代码可以很好地从Android应用连接到服务器,方法是先传递JSON,例如{“ name”:“ xxx”},而服务器回显相应的数据。
try {
URL url = new URL(intent.getStringExtra(URL));
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(buildSslSocketFactory());
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setChunkedStreamingMode(0);
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json");
conn.connect();
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
Log.d(TAG,data +"sending to " + actStr(action) );
writer.write(data);
writer.close();
int respC = conn.getResponseCode();
if (respC < 200 || respC >= 400 ) { // OK is 200-399
Log.e(TAG, "sending to " + actStr(action) + ", got response code " + respC + "=" + conn.getResponseMessage());
conn.disconnect();
return;
}
reader = new BufferedReader( new InputStreamReader( conn.getInputStream()));
makeStr = new StringBuilder();
data = "";
while ((data = reader.readLine()) != null) {
makeStr.append(data);
Log.d(TAG, "read"+data);
}
conn.disconnect();
} catch (Exception e) {
Log.d(TAG, "Failed sending to " + actStr(action) + ", cause: " + e.getCause() + " message: " + e.getMessage());
} finally {
if (reader != null) {
try {
makeStr.append("");
reader.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
它与标准SslSocketFactory一起提供:
private static SSLSocketFactory buildSslSocketFactory() {
// Add support for self-signed (local) SSL certificates
// Based on http://developer.android.com/training/articles/security-ssl.html#UnknownCa
try {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream is = App.getAppResources().getAssets().open(ManageActivity.certificate);
InputStream caInput = new BufferedInputStream(is);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
//System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
Log.d(TAG,"ca=" +((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
因此,要切换到具有受信任证书的站点,我将上面的代码保持不变,但是更改了证书,这是根据nKn在这里的答案将中间证书+站点证书组合而成的证书:{{3} }(我实际上已经尝试了根证书,中间证书和站点证书之间的所有组合,并分别对单个证书进行了测试。但是它们都不起作用)。与其他人的问题不同,我没有任何错误,可以证明我拥有不受信任的证书或某物。
似乎从服务器站点收到了一个发布请求(我从错误日志中收到了一条消息),但是输入内容没有任何内容,因此应用程序也没有从服务器获得任何响应。但是,与自签名证书设置相比,来自服务器站点的代码完全相同,而且当我使用curl从终端传递相同的JSON时,它会响应我想要的内容,因此我怀疑是否是证书问题。
有人知道如何解决吗,或者我实际上不必包括证书或其他东西吗?
答案 0 :(得分:0)
所以我发现问题出在最后。 可能是
conn.setChunkedStreamingMode(0);
不允许将任何数据传递到服务器(尽管我不知道为什么在以前使用自签名证书时它可以工作...)
在这种情况下,也不需要SslSocketFactory。