25

我正在尝试在不提示用户的情况下安装证书。我知道这不是好的做法,但这就是 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) {
4

7 回答 7

14

如果您具有系统权限,则只能静默安装证书。显示确认对话框是故意的,因为信任证书可能会产生严重后果——Android 可以愉快地打开网络钓鱼站点而不会发出警告等。也就是说,ICS/JB 中的对话框非常糟糕——它不会告诉你什么您正在安装的证书以及谁颁发的证书,只是它是 CA 证书,这很明显。

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

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

于 2012-07-26T03:11:45.190 回答
9

使用KeyChain.createInstallIntent(),我可以通过调用 startActivity 让 Android 启动证书安装对话框。但是,当我将意图传递给 sendBroadcast 时,什么也没有发生。

Intent您将传递给的对象很少startActivity()会与sendBroadcast(). 它们是作为系统的准消息总线的独立通道Intent

于 2012-07-25T20:01:45.967 回答
7

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

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

第 1 步-创建接口

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

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

Activity 给出了如何安装 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();
    }
}

我希望这对某人有所帮助-我花了很长时间才解决这个问题:)

于 2013-07-08T02:16:54.913 回答
2

根据@ospider的回答,我设法以这种方式成功安装了证书:

adb shell mkdir -p /data/misc/user/0/cacerts-added
adb push certificate.cer /data/misc/user/0/cacerts-added/807e3b02.0

# Maybe these two lines are not strictly necessary...
adb shell chmod 644 /data/misc/user/0/cacerts-added/807e3b02.0
adb shell chown system:system /data/misc/user/0/cacerts-added/807e3b02.0

807e3b02.0通过手动安装我想要自动化的证书并查看Android如何保存它(whith adb shell ls -l /data/misc/user/0/cacerts-added/)获得了复制文件的名称()


希望这有帮助。

问候。

于 2018-02-02T14:54:30.657 回答
2

如果您有 root 权限,您可以将 certs 文件复制到/data/misc/user/0/cacerts-added/

于 2017-03-26T14:30:40.630 回答
2

这个线程已经有点过时了,但是因为我偶然发现了同样的问题并且找不到任何适用于 Android O 或更高版本的“开箱即用”解决方案,我想我会分享我想出的并且效果很好的解决方案对我来说,在尝试将证书(CA 和其他证书)安装到 Android 受信任的凭据“用户”存储时:

// Supply context, e.g. from "Context context = getApplicationContext();"
// String fileName points to the file holding the certificate to be installed. pem/der/pfx tested.
RandomAccessFile file = new RandomAccessFile(fileName, "r");
byte[] certificateBytes = new byte[(int)file.length()];
file.read(certificateBytes);

Class<?> keyChainConnectionClass = Objects.requireNonNull(context.getClassLoader()).loadClass("android.security.KeyChain$KeyChainConnection");
Class<?> iKeyChainServiceClass  = Objects.requireNonNull(context.getClassLoader()).loadClass("android.security.IKeyChainService");

Method keyChainBindMethod = KeyChain.class.getMethod("bind", Context.class);
Method keyChainConnectionGetServiceMethod = keyChainConnectionClass.getMethod("getService");
Object keyChainConnectionObject = keyChainBindMethod.invoke(null, context);
Object iKeyChainServiceObject = keyChainConnectionGetServiceMethod.invoke(keyChainConnectionObject);

Method installCaCertificate = iKeyChainServiceClass.getDeclaredMethod("installCaCertificate", byte[].class);
installCaCertificate.invoke(iKeyChainServiceObject, certificateBytes);

请注意,如果您想以这种方式静默安装证书,您的应用程序需要是系统应用程序,即它需要具有

android:sharedUserId="android.uid.system"

在它的清单中声明。

干杯!

于 2020-07-22T13:04:01.953 回答
1

只有系统用户应用程序可以静默安装 CA 证书。不过,在 Lollipop 上,Google 通过 DevicePolicyManager 引入了静默证书管理 API,但您必须是 Android-for-Work 配置文件所有者或设备所有者。

于 2015-08-21T21:45:20.173 回答