我是一名 Android 开发者,必须使用
KeyChain
而不是 KeyStore
。我们代码的 KeyStore 变体有效。我需要添加KeyChain
等价物。
这行得通
final char[] PASSWORD = "***SOMEPASSWORD****".toCharArray();
TrustManager[] trustManager;
SSLSocketFactory sslSocketFactory;
KeyStore keyStore;
InputStream inputStream = context.getResources().getAssets().open("xxxx-xxxxx-xxxxx-xxxx.pfx");
keyStore = KeyStore.getInstance("PKCS12");
KeyStore.LoadStoreParameter
keyStore.load(inputStream,PASSWORD);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance (TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager))
{
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
trustManager = trustManagers;
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
keyManagerFactory.init(keyStore,PASSWORD);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(),null,null);
sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(15000, TimeUnit.MILLISECONDS).readTimeout(0, TimeUnit.MILLISECONDS)
.writeTimeout(15000, TimeUnit.MILLISECONDS).cookieJar(new ReactCookieJarContainer());
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManager[0]);
OkHttpClient okHttpClient = builder.build();
问题是这一行
InputStream inputStream = context.getResources().getAssets().open("xxxx-xxxxx-xxxxx-xxxx.pfx");
我们不允许使用资产文件夹(出于本次对话范围之外的原因)但我们被允许将相同的文件放在KeyChain
所以我做了,我可以使用以下方法检索它。 X509Certificate[] chain = KeyChain.getCertificateChain(context, "xxxx-xxxxx-xxxxx-xxxx");
自从
X509Certificate[] chain = KeyChain.getCertificateChain(context, "xxxx-xxxxx-xxxxx-xxxx"); //this gets the correct X509Certificate
通过
KeyChain
获取证书我的直觉是用这个换掉它:
X509TrustManager customTm = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
try {
return X509Certificate[] chain = KeyChain.getCertificateChain(context, "xxxx-xxxxx-xxxxx-xxxx");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeyChainException e) {
e.printStackTrace();
}
return null;
}
};
TrustManager[] trustManager = new TrustManager[] { customTm };
sslContext.init(null, trustManager, null);
但它不起作用,所以我的问题是:我如何使用我从
KeyChain
获得的X509Certificate作为我进入KeyStore
的资产的替代品?
我想通了,代码需要变得稍微不同,但是我找不到任何地方都没有记录:我不得不面对滚动键盘来完成它
所以。 OP 示例是我使用资产文件夹中的 pfx 文件。
为了不在构建环境中使用资产文件(又名
KeyStore
),以便在运行时直接从android操作系统的一部分加载证书并在代码中获取它(又名KeyChain
)(即为了加载您可以在设备下方屏幕中看到的证书)....
这是它在 android 中的位置的插图,但不是我的屏幕截图
...使用此代码
final char[] PASSWORD = "***SOMEPASSWORD****".toCharArray();
TrustManager[] trustManager;
SSLSocketFactory sslSocketFactory;
KeyStore keyStore;
X509Certificate[] keychain;
PrivateKey privateKey;
keychain = KeyChain.getCertificateChain(context, "xkeyx-xaliasxx");
privateKey = KeyChain.getPrivateKey(context, "xkeyx-xaliasxx");
keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null, null);
keyStore.setKeyEntry("xkeyx-xaliasxx", privateKey, PASSWORD, keychain);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance (TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager))
{
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
trustManager = trustManagers;
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
keyManagerFactory.init(keyStore,PASSWORD);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(),null,null);
sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(15000, TimeUnit.MILLISECONDS).readTimeout(0, TimeUnit.MILLISECONDS)
.writeTimeout(15000, TimeUnit.MILLISECONDS).cookieJar(new ReactCookieJarContainer());
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManager[0]);
OkHttpClient okHttpClient = builder.build();
注意这仅在应用程序中的用户确认证书后才有效:因此此代码需要至少运行一次
KeyChain.choosePrivateKeyAlias(RN.getReactActivity(), (KeyChainAliasCallback) alias -> {
Log.d("cert", String.format("User has selected client certificate alias: %s should be xkeyx-xaliasxx", alias));
X509Certificate[] truechain;
try {
truechain = KeyChain.getCertificateChain(Context, alias);
if (truechain != null) {
Log.d("cert", "truechain count" + truechain.length);
}
else{
Log.d("cert", "truechain count is null");
}
} catch (InterruptedException e) {
Log.e("cert", "InterruptedException", e);
} catch (KeyChainException e) {
Log.e("cert", "KeyChainException", e);
}
}, null, null, null, -1, null);