如何在Android上以编程方式安装CA证书而无需用户交互

Ped*_*dro 18 android x509certificate android-intent android-wifi

我正在尝试安装证书而不提示用户.我知道这不是好习惯,但这就是PM想要的.

使用KeyChain.createInstallIntent(),我可以通过调用让Android启动证书安装对话框startActivity.但是,当我通过意图时sendBroadcast,没有任何反应.出于安全考虑,平台可能不支持此功能吗?

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) {
Run Code Online (Sandbox Code Playgroud)

Nik*_*kov 11

如果您具有系统权限,则只能以静默方式安装证书.出现确认对话是有意的,因为信任证书可能会产生严重后果 - Android可以在没有警告的情况下高兴地打开网络钓鱼站点等等.也就是说,ICS/JB中的对话非常糟糕 - 它没有告诉你什么你正在安装的证书和发布它的证书,只是它是一个CA证书,这很明显.

因此,要么使用公共KeyChainAPI并使用它startActivity()来获取确认对话框,要么在将设备处理给用户之前预先设置它们.

更新:在Android 4.4中,DevicePolicyManager有一个隐藏的API(installCaCert),允许您以静默方式安装证书.您需要该MANAGE_CA_CERTIFICATES权限,这signature|system对于用户安装的应用程序仍然不可行.

  • `installCaCert`已在[SDK 21](http://developer.android.com/reference/android/app/admin/DevicePolicyManager.html)中显示,并且显然可供设备管理员使用. (3认同)

Com*_*are 8

使用KeyChain.createInstallIntent(),我可以通过调用startActivity让Android启动证书安装对话框.但是,当我将意图传递给sendBroadcast时,没有任何反应.

几乎没有Intent你传递给它的对象startActivity()可以使用sendBroadcast().它们是作为Intent系统的准消息总线的独立通道.


Chr*_*dus 5

对于非系统应用程序开发人员-简单的答案是没有用户交互就无法完成。

对于系统应用程序开发人员,我找到了以下解决方案,请注意,您必须使用系统用户ID运行该应用程序,并使用系统密钥对应用程序进行签名,否则该服务将拒绝您尝试安装证书的尝试。

第1步 - 创建界面

在您的项目中创建一个新包:android.security,然后将IKeyChainService.aidl复制到该包中。

第2步 - 绑定到服务并安装证书

该活动提供了有关如何安装CA证书的示例:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望这对某人有帮助-我花了很长时间来解决:)