0

I installed a X509 certificate into andorid keychain using following code:

        Intent installIntent = KeyChain.createInstallIntent();
        installIntent.putExtra(KeyChain.EXTRA_NAME, "My certificate");
        installIntent.putExtra(KeyChain.EXTRA_CERTIFICATE, certificate.getEncoded());
        startActivityForResult(installIntent, 2);

I get an toast mentioning "My Certificate is installed". Now when I am trying to fetch it back using following code:

 try {
        KeyStore ks = KeyStore.getInstance("AndroidCAStore");
        if (ks != null) {
            ks.load(null, null);
            Enumeration aliases = ks.aliases();
            List<String> alliasesNames = Collections.list(aliases);
            for (String name : alliasesNames) {
                if (ks.getCertificate(name) instanceof X509Certificate) {
                    X509Certificate certificate = (X509Certificate) ks.getCertificate(name);
                    if (certificate.getIssuerDN().getName().contains("My Certificate")) {
                        Log.d("CERTEXIST", "**********User Cert " + certificate.getIssuerDN().getName());
                    }
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (java.security.cert.CertificateException e) {
        e.printStackTrace();
    }

I am not able to find that installed x509 in this. Also I could see the installed x509 cert in User certificate in security settings of the device.

Also when I prompt user to choose a cert for server communication using:

        KeyChain.choosePrivateKeyAlias(loginActivity, this,
            new String[]{}, null, null, -1, null);
    }

The prompt doesn't show my certificate. I am new to this certificates and key chain in Android.

I would like to know how to retrive the saved x509 cert and prompt that to user to select that certificate.

Any help is appreciated.

Kannan_SJD
  • 1,022
  • 2
  • 13
  • 32

1 Answers1

1

KeyChain.choosePrivateKeyAlias launches an antivity to prompt user to select the alias for a private key, but you have installed a certificate, not a private key, so your certificate will not be there.

KeyChain.createInstallIntent() can be used to install X509 certificates or PKCS#12 files, containing both private key and certificates. If you need to install a private key+certificate for authentication you need to provide a p12 file.

byte pkcs12Data[] = ...
installIntent.putExtra(KeyChain._PKCS12, pkcs12Data);
pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • Thanks for you response @pedrofb. I understood the same. I have a PKCS12 file (pfx) and while installing that through KeyChain._PKCS12 in intent; it ask user for a password. In my case user is not aware of the password. We generate it through code. So load that PCKS12 file to keystore and extracted its certificate chain and installed the 509 cert from that cert chain. – Kannan_SJD Mar 28 '18 at 05:43
  • What should I do if I should not ask user to enter the password for my .pfx file install.? I have password generated through code. Can I populate that password in the prompt atleast (may be by passing password through intent)? or is there a way to remove password from that pfx file. – Kannan_SJD Mar 28 '18 at 05:44
  • Or should I convert that pfx file to any other format which still serves the purpose like pem without password and allow user to install that? I am totally confused and cannot choose what needs to be done? Please help! – Kannan_SJD Mar 28 '18 at 05:53
  • The user will have to enter the password. This is by design, to prevent a malicious agent from installing private keys without the user's knowledge and that may cause for example a man-in-the-middle attack. KeyChain only accepts pkcs12 format for private keys, and p12 files require a password (to encrypt the content). You can try an empty password "", and let user to tap directly the OK button, but I do not know it this will work. See https://stackoverflow.com/questions/27497723/export-a-pkcs12-file-without-an-export-password – pedrofb Mar 28 '18 at 06:02
  • Thanks for the reply. Sorry to trouble you again. But this particular PKCS 12 file is being downloaded from a server which generates this file with a password. So after downloading this file; I should try to decrypt that with the known password and create another pkcs12 file with an empty password"". I have been searching for the same but couldn't find a way to do it programatically. If you could guide me to that; that will be really helpful. – Kannan_SJD Mar 28 '18 at 06:12
  • Also is there a way I could pass the password to the password prompt? User should still click submit but password will be prepopulated. I cannot find an extra in the createinstallintent for the same. – Kannan_SJD Mar 28 '18 at 06:13
  • You can not provide a password to createInstallIntent. It is a System prompt. Extracting keys from a p12 and creating another is possible and simple (just `load` it and `store` with the new password) , but I suggest you first try the empty password before coding it – pedrofb Mar 28 '18 at 06:33
  • Thanks. Sure, Let me try with a sample file and I will update here – Kannan_SJD Mar 28 '18 at 06:54
  • Hi @pedrofb I am able to install an empty password certificate with user just clicking the submit button. I did it programatically too.. Now once the certificate is installed and I use choosePrivateKeyAlias to choose a certificate. does it actually means that cA certificate will be added to all subsequent HTTP requests. I use Volley Library and until now we create a sslContext with the certificate and add that to volley requests. Do I still need to do the same by retriving the certificate back from key chain? – Kannan_SJD Mar 29 '18 at 05:27
  • 1
    _does i_t actually means that cA certificate will be added to all subsequent HTTP requests_, No, you need to configure the SSL context to use the `KeyChain` as keystore. You can not provide the key directly to the `SSLContext` because KeyChain keys are non extractable, so you will need a X509TrustManager adapter (may be Volley supports it directly) – pedrofb Apr 01 '18 at 18:53
  • Thanks for your help @pedorfb. If I still has to add this manually then I couldn't understand the reason of prompting the user to choose a certificate.. What is android trying to achieve with that action? – Kannan_SJD Apr 03 '18 at 05:33
  • The user can have multiple certificates and is asked to choose one. If you know the alias you do not have to ask, so it would only be necessary the first time. – pedrofb Apr 03 '18 at 05:58
  • Ok thanks. Now I should send the CA certificate back to server with a SSLContext class. All I could get back with that alias is the private key and certificate chain. How do I recreate the certificate with these values? Should I concate them together as strings and load to a keystore. I am sorry to bother you but I couldn't find any helpful reference with keychain API out there. – Kannan_SJD Apr 03 '18 at 06:27
  • You need the private key and the certification chain to be authenticated during the SSL connection. See https://stackoverflow.com/a/45035052/6371459 – pedrofb Apr 03 '18 at 07:30
  • Thanks for the reference. I have been looking for this..! Thanks for all your help @pedorfb – Kannan_SJD Apr 03 '18 at 09:37