[英]how to install CA certificate programmatically on Android without user interaction
I'm trying to install certificates without prompting the user.我试图在不提示用户的情况下安装证书。 I know this is not good practice, but that's what PM wants.我知道这不是好的做法,但这正是 PM 想要的。
Using KeyChain.createInstallIntent()
, I can get Android to launch the certificate installation dialog by calling startActivity
.使用KeyChain.createInstallIntent()
,我可以让 Android 通过调用startActivity
来启动证书安装对话框。 However, when I pass the intent to sendBroadcast
, nothing happens.但是,当我将意图传递给sendBroadcast
时,什么也没有发生。 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) {
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.显示一个确认对话框是有意的,因为信任证书会产生严重的后果——Android 可以在没有警告的情况下愉快地打开钓鱼网站,等等。也就是说,ICS/JB 中的对话框非常糟糕——它没有告诉你什么您正在安装的证书以及颁发者,只是它是一个 CA 证书,这很明显。
So, either use the public KeyChain
API and use startActivity()
to get the confirmation dialog, or pre-provision devices before handling them to users.因此,要么使用公共KeyChain
API 并使用startActivity()
获取确认对话框,要么在将设备处理给用户之前预先配置设备。
Update: In Android 4.4, DevicePolicyManager
has a hidden API ( installCaCert
) that allows you to install certificates silently.更新:在 Android 4.4 中, DevicePolicyManager
有一个隐藏的 API ( installCaCert
),允许您静默安装证书。 You need the MANAGE_CA_CERTIFICATES
permission, which is signature|system
, so still not doable for user-installed apps.您需要MANAGE_CA_CERTIFICATES
权限,即signature|system
,因此对于用户安装的应用程序仍然不可行。
Using KeyChain.createInstallIntent() , I can get Android to launch the certificate installation dialog by calling startActivity.使用KeyChain.createInstallIntent() ,我可以让 Android 通过调用 startActivity 来启动证书安装对话框。 However, when I pass the intent to sendBroadcast, nothing happens.但是,当我将意图传递给 sendBroadcast 时,什么也没有发生。
Few if any Intent
objects that you would pass to startActivity()
would work with sendBroadcast()
.您将传递给startActivity()
的Intent
对象很少能与sendBroadcast()
一起使用。 They are independent channels of the quasi-message bus that is the Intent
system.它们是作为Intent
系统的准消息总线的独立通道。
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.对于系统应用程序开发人员,我找到了以下解决方案,注意您必须使用系统用户 ID 运行应用程序并使用系统密钥签署应用程序,否则服务将拒绝您安装证书的尝试。
Step 1 - Create interface第 1 步-创建界面
Create a new package in your project: android.security , then copy IKeyChainService.aidl into this package.在您的项目中创建一个新包: android.security ,然后将IKeyChainService.aidl复制到该包中。
Step 2 - Bind to service and install certificate第 2 步-绑定到服务并安装证书
The Activity gives an example of how to install a CA certificate:该活动给出了如何安装 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();
}
}
I hope this helps someone - it took me a long time to work it out:)我希望这对某人有帮助——我花了很长时间才弄明白:)
This thread is a bit dated already, nevertheless since I stumbled upon the same issue and couldn't find any "out of the box" solution for Android O or later, I thought I'd share what I came up with and which worked well for me when trying to install Certificates (CA and others) to the Android Trusted credentials "User" store:这个线程已经有点过时了,但是由于我偶然发现了同样的问题并且找不到任何适用于 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);
Note that if you want to silently install a certificate this way, your app needs to be a system app, ie it needs to have请注意,如果您想以这种方式静默安装证书,您的应用程序需要是系统应用程序,即它需要有
android:sharedUserId="android.uid.system"
declared in it's manifest.在清单中声明。
Cheers!干杯!
If you have root privilege, you could copy the certs file to /data/misc/user/0/cacerts-added/
如果您有 root 权限,您可以将证书文件复制到/data/misc/user/0/cacerts-added/
Based on the @ospider 's answer, i managed to succesfully install the cert like this way:根据@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
I got the name of the copied file ( 807e3b02.0
) by installing manually the cert i wanted to automate and seeing how Android saved it (whith adb shell ls -l /data/misc/user/0/cacerts-added/
)我通过手动安装我想要自动化的证书并查看 Android 如何保存它(使用adb shell ls -l /data/misc/user/0/cacerts-added/
)获得了复制文件的名称( 807e3b02.0
)
Hope this help.希望这有帮助。
Regards.问候。
Only a system user application can silently install a CA certificate.只有系统用户应用程序可以静默安装 CA 证书。 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.尽管在 Lollipop 上,Google 通过 DevicePolicyManager 引入了静默证书管理 API,但您必须是 Android-for-Work 配置文件所有者或设备所有者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.