客户端证书的Android okhttp3错误

时间:2019-12-20 09:29:51

标签: android https okhttp client-certificates

我对使用okhttp3库进行https请求的android本机应用程序有问题。我必须使用客户端证书进行身份验证。问题是,当我调用build的{​​{1}}函数时,它会抛出HandshakeCertificates.Builder以获取某些 string 的长度(我不知道它是什么字符串)。我发现,只有在构建之前调用NullPointerException时才会发生。

我能够调试heldCertificate,其中使用别名,密钥,密码和链参数调用KeyStore.setKeyEntry。它们都不是null,我认为它们具有正确的值(但我不是证书的专家,因此可能缺少某些内容)。我无权访问BcKeyStoreSpi.engineSetKeyEntry的代码。

我正在将Android 9 Enterprise与Samsung Galaxy Tab A SM-T515上的工作资料一起使用。

依赖项(仅适用于okhttp):

  • 实现(“ com.squareup.okhttp3:okhttp:4.1.0”)
  • implementation(“ com.squareup.okhttp3:okhttp-tls:4.1.0”)

有人可以帮我吗?谢谢

代码

BcKeyStoreSpi.engineSetKeyEntry

Stacktrace

PrivateKey privateKey = KeyChain.getPrivateKey(context, certAlias);
            X509Certificate[] certChain = KeyChain.getCertificateChain(context, certAlias);
            X509Certificate mdmCert = certChain[0];

            HandshakeCertificates.Builder builder = new HandshakeCertificates.Builder();
            builder.addPlatformTrustedCertificates();

            for (X509Certificate cert : certChain) {
                builder.addTrustedCertificate(cert);
            }

            builder.heldCertificate(        //if this is commented then everything is ok
                    new HeldCertificate(
                            new KeyPair(
                                    mdmCert.getPublicKey(),
                                    privateKey
                            ),
                            mdmCert
                    ),
                    certChain
            );

            HandshakeCertificates clientCertificates = builder.build(); //this throws exception

1 个答案:

答案 0 :(得分:0)

您无法提取密钥来填充另一个密钥库。相反,您应该使用类似于本文的自定义密钥库。

https://medium.com/@_kbremner/android-and-client-authentication-fd416af19a04

        KeyChain.choosePrivateKeyAlias(this,
                { alias -> storeAlias(alias) },
                arrayOf("RSA", "DSA"),  // List of acceptable key types. null for any
                null,  // issuer, null for any
                null,  // host name of server requesting the cert, null if unavailable
                443,  // port of server requesting the cert, -1 if unavailable
                null) // alias to preselect, null if unavailable

关键代码为

val pk = KeyChain.getPrivateKey(applicationContext, alias)!!
val chain = KeyChain.getCertificateChain(applicationContext, alias)!!


                val km = object : X509KeyManager {
                    override fun getClientAliases(keyType: String?, issuers: Array<Principal>): Array<String> {
                        return arrayOf(alias)
                    }

                    override fun chooseClientAlias(keyType: Array<out String>?, issuers: Array<out Principal>?, socket: Socket?): String {
                        return alias
                    }

                    override fun getServerAliases(keyType: String?, issuers: Array<Principal>): Array<String> {
                        return arrayOf()
                    }

                    override fun chooseServerAlias(keyType: String?, issuers: Array<Principal>, socket: Socket): String {
                        return ""
                    }

                    override fun getCertificateChain(alias: String?): Array<X509Certificate> {
                        return chain
                    }

                    override fun getPrivateKey(alias: String?): PrivateKey {
                        return pk
                    }
                }

                val sslContext = SSLContext.getInstance("TLS")
                sslContext.init(arrayOf(km), trustManagers, null)

                val client: OkHttpClient = OkHttpClient.Builder()
                        .sslSocketFactory(sslContext.socketFactory, trustManagers[0] as X509TrustManager)
                        .build()