在 OKHttpClient sslSocketFactory 中使用来自 KeyChain 的 X509Certificate

问题描述 投票:0回答:1

我是一名 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
的资产的替代品?

java android x509certificate keychain
1个回答
0
投票

我想通了,代码需要变得稍微不同,但是我找不到任何地方都没有记录:我不得不面对滚动键盘来完成它

所以。 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);
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.