加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 自动或用户选择适当的客户端证书的请求

发布时间:2020-12-15 00:54:12 所属栏目:Java 来源:网络整理
导读:我正在开发一个可能连接到不同服务器的混合cordova应用程序.其中一些确实需要客户证书. 在Android手机上安装相应的根证书客户端证书. 在Chrome浏览器上,我得到以下对话框,为Web连接选择相应的客户端证书. 使用cordova插件cordova-client-cert-authentication
我正在开发一个可能连接到不同服务器的混合cordova应用程序.其中一些确实需要客户证书.

在Android手机上安装相应的根证书客户端证书.

在Chrome浏览器上,我得到以下对话框,为Web连接选择相应的客户端证书.

使用cordova插件cordova-client-cert-authentication,在WebView中弹出相同的Http(s)请求对话框.

我的问题是如何在原生Android平台上实现Http(s)请求的自动证书选择,而无需明确声明相应的客户端证书.或者在Chrome上实现的用户选择证书是否类似?

这是当前的实现,它会抛出握手异常:

try {
    URL url = new URL( versionUrl );
    HttpsURLConnection urlConnection = ( HttpsURLConnection ) url.openConnection();

    urlConnection.setConnectTimeout( 10000 );

    InputStream in = urlConnection.getInputStream();
}
catch(Exception e)
{
    //javax.net.ssl.SSLHandshakeException: Handshake failed
}

解决方法

您可以使用先前安装在Android KeyChain(系统密钥库)中的证书,扩展X509ExtendedKeyManager以配置URLConnection使用的SSLContext

证书由您需要的别名引用.要使用类似于chrome的对话框提示用户进行选择:

KeyChain.choosePrivateKeyAlias(this,this,// Callback
            new String[] {"RSA","DSA"},// Any key types.
            null,// Any issuers.
            null,// Any host
            -1,// Any port
            DEFAULT_ALIAS);

这是使用自定义KeyManager配置SSL连接的代码.它使用默认的TrustManager和HostnameVerifier.如果服务器使用Android默认信任库中不存在的自签名证书,则需要配置它们(不建议信任所有证书)

//Configure trustManager if needed
TrustManager[] trustManagers = null;

//Configure keyManager to select the private key and the certificate chain from KeyChain
KeyManager keyManager = KeyChainKeyManager.fromAlias(
            context,mClientCertAlias);

//Configure SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] {keyManager},trustManagers,null);


//Perform the connection
URL url = new URL( versionUrl );
HttpsURLConnection urlConnection = ( HttpsURLConnection ) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
//urlConnection.setHostnameVerifier(hostnameVerifier);  //Configure hostnameVerifier if needed
urlConnection.setConnectTimeout( 10000 );
InputStream in = urlConnection.getInputStream();

最后,您将拥有从here和here中提取的自定义X509ExtendedKeyManager的完整实现,该实现负责选择客户端证书.我已经提取了所需的代码.

public static class KeyChainKeyManager extends X509ExtendedKeyManager {
    private final String mClientAlias;
    private final X509Certificate[] mCertificateChain;
    private final PrivateKey mPrivateKey;

        /**
         * Builds an instance of a KeyChainKeyManager using the given certificate alias.
         * If for any reason retrieval of the credentials from the system {@link android.security.KeyChain} fails,* a {@code null} value will be returned.
         */
        public static KeyChainKeyManager fromAlias(Context context,String alias)
                throws CertificateException {
            X509Certificate[] certificateChain;
            try {
                certificateChain = KeyChain.getCertificateChain(context,alias);
            } catch (KeyChainException e) {
                throw new CertificateException(e);
            } catch (InterruptedException e) {
                throw new CertificateException(e);
            }

            PrivateKey privateKey;
            try {
                privateKey = KeyChain.getPrivateKey(context,alias);
            } catch (KeyChainException e) {
                throw new CertificateException(e);
            } catch (InterruptedException e) {
                throw new CertificateException(e);
            }

            if (certificateChain == null || privateKey == null) {
                throw new CertificateException("Can't access certificate from keystore");
            }

            return new KeyChainKeyManager(alias,certificateChain,privateKey);
        }

        private KeyChainKeyManager(
                String clientAlias,X509Certificate[] certificateChain,PrivateKey privateKey) {
            mClientAlias = clientAlias;
            mCertificateChain = certificateChain;
            mPrivateKey = privateKey;
        }


        @Override
        public String chooseClientAlias(String[] keyTypes,Principal[] issuers,Socket socket) {
            return mClientAlias;
        }

        @Override
        public X509Certificate[] getCertificateChain(String alias) {
            return mCertificateChain;
        }

        @Override
        public PrivateKey getPrivateKey(String alias) {
            return mPrivateKey;
        }

         @Override
        public final String chooseServerAlias( String keyType,Socket socket) {
            // not a client SSLSocket callback
            throw new UnsupportedOperationException();
        }

        @Override
        public final String[] getClientAliases(String keyType,Principal[] issuers) {
            // not a client SSLSocket callback
            throw new UnsupportedOperationException();
        }

        @Override
        public final String[] getServerAliases(String keyType,Principal[] issuers) {
            // not a client SSLSocket callback
            throw new UnsupportedOperationException();
        }
    }
}

我没有测试它.报告任何错误!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读