我正在尝试安装证书而不提示用户。我知道这不是好习惯,但这就是PM想要的。
使用KeyChain.createInstallIntent()
,我可以通过调用startActivity
让Android启动证书安装对话框。但是,当我将意图传递给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) {
答案 0 :(得分:11)
如果您具有系统权限,则只能以静默方式安装证书。出现确认对话是有意的,因为信任证书可能会产生严重后果 - Android可以在没有警告的情况下高兴地打开网络钓鱼站点等等。也就是说,ICS / JB中的对话非常糟糕 - 它没有告诉你什么你正在安装的证书和发布它的证书,只是它是一个CA证书,这很明显。
因此,要么使用公共KeyChain
API并使用startActivity()
来获取确认对话框,要么在将设备处理给用户之前预先配置设备。
更新:在Android 4.4中,DevicePolicyManager
有一个隐藏的API(installCaCert
),允许您以静默方式安装证书。您需要MANAGE_CA_CERTIFICATES
权限,即signature|system
,因此对用户安装的应用仍然不可行。
答案 1 :(得分:8)
使用KeyChain.createInstallIntent(),我可以通过调用startActivity让Android启动证书安装对话框。但是,当我将意图传递给sendBroadcast时,没有任何反应。
如果您传递给Intent
的任何startActivity()
个对象与sendBroadcast()
一起使用,则很少。它们是准消息总线的独立通道,即Intent
系统。
答案 2 :(得分:4)
对于非系统应用程序开发人员 - 简单的答案是没有用户交互就无法完成。
对于System App开发人员,我找到了以下解决方案,NB您必须使用系统用户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();
}
}
我希望这对某人有所帮助 - 我花了很长时间才解决这个问题:)
答案 3 :(得分:2)
如果您具有root权限,则可以将certs文件复制到/data/misc/user/0/cacerts-added/
答案 4 :(得分:2)
该线程已经过时,因为我偶然发现了同一问题,并且找不到适用于Android O或更高版本的任何“开箱即用”的解决方案,所以我想分享一下我的想法,并且在尝试将证书(CA和其他证书)安装到Android Trusted凭据“用户”商店时,对我来说效果很好:
// 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"
在清单中声明。
干杯!
答案 5 :(得分:1)
只有系统用户应用程序才能以静默方式安装CA证书。但是在Lollipop上,Google通过DevicePolicyManager引入了静默证书管理API,但您必须是Android-for-Work配置文件所有者或设备所有者。
答案 6 :(得分:0)
根据@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
我通过手动安装我想要自动化的证书并查看Android如何保存它来获得复制文件(807e3b02.0
)的名称(adb shell ls -l /data/misc/user/0/cacerts-added/
)
希望得到这个帮助。
问候。