【发布时间】:2016-10-06 01:31:40
【问题描述】:
我们的应用程序使用 http/https 连接其 REST 服务器。在我们切换到 https 之前,一切正常。 Min SDK version = 14。 IOS版本运行没有任何问题。
这是openssl s_client -connect test_server.ru:443 的输出:
Certificate chain
0 s:/CN=test_server.ru
i:/C=US/O=thawte, Inc./OU=Domain Validated SSL/CN=thawte DV SSL CA - G2
1 s:/C=US/O=thawte, Inc./OU=Domain Validated SSL/CN=thawte DV SSL CA - G2
i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
2 s:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
Android 4-5 Chrome 将站点证书显示为无效(红色和交叉)。应用程序捕获异常:“未找到证书路径的信任锚”
所以我将两个键都添加到资产文件夹并制作了快速静态类来使用这些键:
public class CustomTrustCA {
private static SSLContext mSSLContext = null;
public static SSLSocketFactory getInstance() {
if (mSSLContext == null && Init() == null) return null;
return mSSLContext.getSocketFactory();
}
public static SSLContext Init() {
Certificate ca = null;
Certificate ca2 = null;
InputStream caInput = null;
InputStream caInput2 = null;
KeyStore keyStore = null;
TrustManagerFactory tmf = null;
mSSLContext = null;
//noinspection TryFinallyCanBeTryWithResources
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
caInput = Application.AppContext.getAssets().open("thawte.cer");
ca = cf.generateCertificate(caInput);
caInput2 = Application.AppContext.getAssets().open("thawte2.cer");
ca2 = cf.generateCertificate(caInput2);
} catch (Exception e) {
Logger.Exception(e);
} finally {
try {
if (caInput != null) caInput.close();
if (caInput2 != null) caInput2.close();
} catch (Exception ignored) {}
}
if (ca == null) return null;
if (ca2 == null) return null;
try {
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
keyStore.setCertificateEntry("ca2", ca2);
} catch (Exception e) {
Logger.Exception(e);
}
try {
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
} catch (Exception e) {
Logger.Exception(e);
}
if (tmf == null) return null;
try {
// Create an SSLContext that uses our TrustManager
mSSLContext = SSLContext.getInstance("TLS");
mSSLContext.init(null, tmf.getTrustManagers(), null);
} catch (Exception e) {
Logger.Exception(e);
}
return mSSLContext;
}
}
然后我将它添加到低级 http 代码中:
HttpsURLConnection urlConnection = (HttpsURLConnection) full_url.openConnection();
SSLSocketFactory instance = CustomTrustCA.getInstance();
if (instance != null) urlConnection.setSSLSocketFactory(instance);
这解决了问题,但通用图像加载器也坏了,所以我写了一些代码来修复它(自定义图像下载器类):
public class SecureImageDownloader extends BaseImageDownloader {
public static final String TAG = SecureImageDownloader.class.getName();
public SecureImageDownloader(Context context, int connectTimeout, int readTimeout) {
super(context, connectTimeout, readTimeout);
}
@Override
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
URL url = null;
try {
url = new URL(imageUri);
} catch (MalformedURLException e) {
Logger.Exception(e);
}
HttpURLConnection http = null;
if (url == null) return null;
if (Scheme.ofUri(imageUri) == Scheme.HTTPS) {
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setSSLSocketFactory(CustomTrustCA.getInstance());
http = https;
http.connect();
} else {
http = (HttpURLConnection) url.openConnection();
}
http.setConnectTimeout(connectTimeout);
http.setReadTimeout(readTimeout);
return new FlushedInputStream(new BufferedInputStream(http.getInputStream()));
}
}
好的。主要代码现在可以工作了。 UIL 也可以...但是...
最后我发现附件的 DownloadManager 和 Intent.ACTION_VIEW 也停止工作(应用程序将它们传递 https url!),但不知道如何修复它们。这是我的代码:
if (isNotEmpty(documentUri)) {
DownloadManager.Request downloadReq = new DownloadManager.Request(Uri.parse(documentUri));
downloadReq.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, attachment.Name());
downloadReq.allowScanningByMediaScanner();
downloadReq.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
DownloadManager dm = (DownloadManager) Application.AppContext.getSystemService(Context.DOWNLOAD_SERVICE);
dm.enqueue(downloadReq);
}
有没有办法使用代码添加系统范围的 CA 证书(即启动一些设置意图或其他东西)?
【问题讨论】:
标签: java android ssl certificate ssl-certificate