how to install CA certificate programmatically on Android without user interaction

xiaoxiao2021-02-28  76

转自: https://stackoverflow.com/questions/11657172/how-to-install-ca-certificate-programmatically-on-android-without-user-interacti 15 down vote favorite 13

I'm trying to install certificates without prompting the user. I know this is not good practice, but that's what PM wants.

Using KeyChain.createInstallIntent(), I can get Android to launch the certificate installation dialog by calling startActivity. However, when I pass the intent to sendBroadcast, nothing happens. Maybe the platform doesn't support this for security reasons?

String CERT_FILE = Environment.getExternalStorageDirectory() + "/test/IAT.crt"; Intent intent = KeyChain.createInstallIntent(); try { FileInputStream certIs = new FileInputStream(CERT_FILE); byte [] cert = new byte[(int)certFile.length()]; certIs.read(cert); X509Certificate x509 = X509Certificate.getInstance(cert); intent.putExtra(KeyChain.EXTRA_CERTIFICATE, x509.getEncoded()); intent.putExtra(KeyChain.EXTRA_NAME, "IAT Cert"); EapActivity.this.startActivityForResult(intent, 0); // this works but shows UI EapActivity.this.sendBroadcast(intent); // this doesn't install cert } catch (IOException e) { android  android-intent  x509certificate  android-wifi share improve this question edited Mar 3 '16 at 10:14 OneWorld 10.7k 15 58 110 asked  Jul 25 '12 at 19:30 Pedro 208 1 2 6     There's no receiver listening for that Intent - just an activity in the system, and for good reasons - allowing any malicious random app to install root CA's silently would be a omghuge security hole. –  Jens  Jul 25 '12 at 19:55 add a comment

5 Answers

active oldest votes up vote 10 down vote

You can only install certificates silently if you have system privileges. Showing up a confirmation dialog is intentional, since trusting certificates can have serious consequences -- Android could happily open phishing sites without a warning, etc. That said, the dialog in ICS/JB is pretty bad -- it doesn't tell you what certificate you are installing and who issued it, just that it's a CA certificate, which is kind of obvious.

So, either use the public KeyChain API and use startActivity() to get the confirmation dialog, or pre-provision devices before handling them to users.

Update: In Android 4.4, DevicePolicyManager has a hidden API (installCaCert) that allows you to install certificates silently. You need the MANAGE_CA_CERTIFICATES permission, which is signature|system, so still not doable for user-installed apps.

share improve this answer edited May 5 '14 at 18:12 answered  Jul 26 '12 at 3:11 Nikolay Elenkov 44.4k 6 70 74     It also forces you to protect your device either with a numeric PIN code or with an unlock pattern for the lockscreen, which is kind of annoying but understandable in terms of user security. I guess they want to be sure that the one installing the certificate will also be the owner of the device. –  Sebastiano  Feb 12 '13 at 15:49 1   Something like that, however if there is no password/PIN to begin with, you can set it to whatever you want. The password/PIN is then used to derive a master key to encrypt private keys with. Certificates get encrypted with it too, which is not strictly necessary. –  Nikolay Elenkov  Feb 12 '13 at 17:09 1   installCaCert has become visible in SDK 21 and apparently available to device administrators. –  Rupert Rawnsley  Oct 19 '15 at 9:33    @RupertRawnsley AFAIK, it only works if your device admin is also the device owner ('super admin') –  Nikolay Elenkov  Oct 21 '15 at 3:20   Device owner is a new one on me. System access via NFC - what could possibly go wrong? ;-) –  Rupert Rawnsley  Oct 21 '15 at 8:02 add a comment up vote 7 down vote

Using KeyChain.createInstallIntent(), I can get Android to launch the certificate installation dialog by calling startActivity. However, when I pass the intent to sendBroadcast, nothing happens.

Few if any Intent objects that you would pass to startActivity() would work with sendBroadcast(). They are independent channels of the quasi-message bus that is the Intentsystem.

share improve this answer edited Mar 3 '16 at 10:14 OneWorld 10.7k 15 58 110 answered  Jul 25 '12 at 20:01 CommonsWare 656k 105 1588 1636     And, by any chance, do someone know how to detect the Certificate installation intent ? (after the user input on the cert password & name ? ) I have found no freaking way to check that my CA security cert is correctly installed. Even before the user have typed the password to extract the certificate, when I request the KeyStore, the certificate is present so I can't know wheter or not the user have completed the installation. –  Alex  Nov 3 '16 at 17:29 add a comment up vote 3 down vote

For non-system app developers - the simple answer is it can not be done without user interaction.

For System App developers, I found the following solution, NB you must run the app with the system user id and sign the app with the system key or the service will reject your attempts to install the certificate.

Step 1 - Create interface

Create a new package in your project: android.security, then copy IKeyChainService.aidl into this package.

Step 2 - Bind to service and install certificate

The Activity gives an example of how to install a CA certificate:

public class KeyChainTest extends Activity { private final Object mServiceLock = new Object(); private IKeyChainService mService; private boolean mIsBoundService =false; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mServiceLock) { mService = IKeyChainService.Stub.asInterface(service); mServiceLock.notifyAll(); try { byte[] result = YOUR_CA_CERT_AS_BYTE_ARRAY //The next line actually installs the certificate mService.installCaCertificate(result); } catch (Exception e) { //EXception handling goes here } } } @Override public void onServiceDisconnected(ComponentName name) { synchronized (mServiceLock) { mService = null; } } }; private void bindService() { mIsBoundService = bindService(new Intent(IKeyChainService.class.getName()), mServiceConnection, Context.BIND_AUTO_CREATE); } private void unbindServices() { if (mIsBoundService) { unbindService(mServiceConnection); mIsBoundService = false; } } @Override public void onDestroy () { unbindServices(); } @Override protected void onStart() { super.onStart(); // Bind to KeyChainService bindService(); } }

I hope this helps someone - it took me a long time to work it out :)

share improve this answer edited Jul 8 '13 at 2:22 answered  Jul 8 '13 at 2:16 Chris Noldus 1,487 2 12 20     This is not possible until our application shares the UID. final String actualPackage = getPackageManager().getNameForUid(getCallingUid()); if (!expectedPackage.equals(actualPackage)) { throw new IllegalStateException(actualPackage); } validates the caller. Can you explain how did you managed without sharing UID? –  Pankaj Kumar  May 7 '14 at 10:03   @Pankaj - We use the sysytem uid in the sharedUserId property of the Android Manifest for our system apps, perhaps this is why I did not need to do it programatically as you have. –  Chris Noldus  Jan 24 '15 at 10:58 add a comment up vote 1 down vote

Only a system user application can silently install a CA certificate. On Lollipop though, Google introduced silent certificate management API through DevicePolicyManager, but you would either have to be Android-for-Work profile owner or device owner.

share improve this answer answered  Aug 21 '15 at 21:45 Konjengbam 61 2   add a comment up vote 1 down vote

If you have root privilege, you could copy the certs file to /data/misc/user/0/cacerts-added/

share improve this answer answered  Mar 26 at 14:30 ospider 302 3 10   add a comment

Your Answer

转载请注明原文地址: https://www.6miu.com/read-39505.html

最新回复(0)