我们的应用程序使用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显示网站证书无效(红色和交叉)。应用程序捕获异常:"未找到证书路径的信任锚"
所以我将两个键添加到asset文件夹并使用快速静态类来使用这些键:
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);
这是固定的东西,但Universal Image Loader也断了,所以我写了一些代码来修复它(自定义图像下载器类):
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证书(即启动某些设置意图或其他内容)?
答案 0 :(得分:0)
我编写了简单的lib ssl-utils-android来加载来自以下资产的特定证书:
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
您可以在my blog post上了解更多相关信息。
编辑: 将您自己的http客户端实例加载到Universal Image Loader,如:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
...
.imageDownloader(new HttpClientImageDownloader(context, yourHttpClient))
...
.build();
ImageLoader.getInstance().init(config);
我从未使用过UIL。希望它能奏效。