gpt4 book ai didi

java - 如何在 Android 4.X 中以编程方式导入全局 CA 证书?

转载 作者:太空狗 更新时间:2023-10-29 14:48:10 25 4
gpt4 key购买 nike

我们的应用程序使用 http/https 连接其 REST 服务器。在我们切换到 https 之前,一切正常。 最低 SDK 版本 = 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 将站点证书显示为无效(红色和交叉)。应用程序捕获异常:“找不到证书路径的信任 anchor ”

所以我将这两个键都添加到 Assets 文件夹中,并制作了快速静态类来使用这些键:

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 证书(即启动一些设置 Intent 或其他东西)?

最佳答案

我写了简单的库 ssl-utils-android从这样的 Assets 加载特定证书:

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。希望它能奏效。

关于java - 如何在 Android 4.X 中以编程方式导入全局 CA 证书?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37657469/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com