Java – a request to automatically or the user to select the appropriate client certificate

I am developing a hybrid Cordova application that may connect to different servers Some of them do require customer certificates

Install the corresponding root certificate and client certificate on the Android phone

On the Chrome browser, I get the following dialog box to select the corresponding client certificate for the web connection

Use Cordova plug-in Cordova client cert authentication to pop up the same HTTP (s) request dialog box in WebView

My question is how to implement automatic certificate selection for HTTP (s) requests on the native Android platform without explicitly declaring the corresponding client certificate Or is the user selected certificate implemented on chrome similar?

This is the current implementation, which will throw a handshake exception:

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
}

Solution

You can use the certificate previously installed in the Android Keychain (system keystore) to extend x509extendedkeymanager to configure the sslcontext used by urlconnection

The certificate is referenced by the alias you need To prompt the user for a selection using a dialog box similar to chrome:

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

This is the code to configure SSL connection using custom keymanager It uses the default trustmanager and hostnameverifier If the server uses self signed certificates that do not exist in the Android default truststore, you need to configure them (it is not recommended to trust all certificates)

//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();

Finally, you will have a complete implementation of the custom x509 extended keymanager extracted from here and here, which is responsible for selecting client certificates I have extracted the required code

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();
        }
    }
}

I didn't test it Report any errors!

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>