android4.4 授信安装,只能安装指定证书的应用
如果打开设置–>安全–>验证应用 后,系统在安装apk时默认会检查系统中是否存在符合条件的广播接受者,然后发送apk信息。这个广播接受者可以完成验证安装。
我们的思路是在系统中新建一个ContentResolver 用于存储系统中支持的应用证书信息。apk安装的时候会查询并校验apk。确定是否同意安装。
packageManagerService–>handleStartCopy函数检查符合条件的Receiver,并发送信息,而我们会增加verification.putExtra(“pkg_path”,mPackageURI.getPath());主要用于接受端解析apk,获取证书信息并校验。
Receiver端:
AndroidManifest.xml如下:
<receiver android:name=".verificationApp">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>
<data android:mimeType="application/vnd.android.package-archive"/>
</intent-filter>
</receiver>
在verificationApp 中:
如果同意安装调用:
mPm = context.getPackageManager();
mPm.verifyPendingInstall(id, PackageManager.VERIFICATION_ALLOW);
不同意安装:
mPm.verifyPendingInstall(id, PackageManager.VERIFICATION_REJECT);
授信安装的思路大致如此,除了上面的这些,剩下的就只有添加证书的应用程序,已经存储证书的provider了。
证书存储:
package com.provider.pkgShaProvider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created by haozhenghui on 16/8/25.
*/
public class pkgShaProvider extends ContentProvider {
private String DB_name="pkgSha1.db3";
private String my_table="allowApp";
final String TAG="pkgSha1Provider";
private final String cerPath="/system/planCer/";
private List<cerCls> cerList=new ArrayList<cerCls>();
SQLiteDatabase pkgDb;
@Override
public boolean onCreate() {
cerList=ReadSystemCerFile();
pkgDb=this.getContext().openOrCreateDatabase(DB_name, Context.MODE_PRIVATE, null);
pkgDb.execSQL("create table if not exists "+my_table+"(_id INTEGER PRIMARY KEY AUTOINCREMENT, sha1 TEXT NOT NULL,owner TEXT," +
"announcer TEXT," +
"SerialNum TEXT," +
"MD5 TEXT," +
"SHA256 TEXT," +
"AlgorithmName TEXT," +
"versionNum TEXT," +
"system TEXT" +
")");
for (int i=0;i<cerList.size();i++){
cerCls cer=cerList.get(i);
if (!lineIsExist(pkgDb,my_table,"sha1",cer.SHA1)){
insertLine(pkgDb,my_table,cer);
}
}
return true;
}
public void insertLine(SQLiteDatabase pkgDb,String my_table,cerCls cer){
ContentValues values=new ContentValues();
values.put("sha1",cer.SHA1);
values.put("owner",cer.owner);
values.put("announcer",cer.announcer);
values.put("SerialNum",cer.SerialNum);
values.put("MD5",cer.MD5);
values.put("SHA256",cer.SHA256);
values.put("AlgorithmName",cer.AlgorithmName);
values.put("versionNum",cer.versionNum);
values.put("system",cer.system);
pkgDb.insert(my_table,null,values);
}
public boolean lineIsExist(SQLiteDatabase pkgdb,String tab_name,String srcName,String distName){
Cursor cursor=pkgdb.query(tab_name, null, null, null, null, null,null);
cursor.moveToFirst();
for(int i=0; i<cursor.getCount(); i++){
int index = cursor.getColumnIndexOrThrow(srcName);
String src = cursor.getString(index);
if (src.equals(distName)){
return true;
}
cursor.moveToNext();
}
return false;
}
public List<cerCls> ReadSystemCerFile(){
List<cerCls> myCerList=new ArrayList<cerCls>();
File file=new File(cerPath);
File[] subFile = file.listFiles();
for (int i=0;i<subFile.length;i++){
if(subFile[i].isFile()){
try {
cerCls cer=ReadX509CerFile(subFile[i]);
cer.system="true";
myCerList.add(cer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return myCerList;
}
public cerCls ReadX509CerFile(File file) throws Exception{
cerCls cerC=new cerCls();
try {
InputStream inStream = new FileInputStream(file);
// 创建X509工厂类
CertificateFactory cf = CertificateFactory.getInstance("X.509");
//CertificateFactory cf = CertificateFactory.getInstance("X509");
// 创建证书对象
X509Certificate oCert = (X509Certificate) cf
.generateCertificate(inStream);
inStream.close();
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd");
String info = null;
// 获得证书版本
info = String.valueOf(oCert.getVersion());
cerC.versionNum=info;
// 获得证书序列号
info = oCert.getSerialNumber().toString(16);
cerC.SerialNum=info;
// 获得证书有效期
Date beforedate = oCert.getNotBefore();
info = dateformat.format(beforedate);
// System.out.println("证书生效日期:" + info);
Date afterdate = oCert.getNotAfter();
info = dateformat.format(afterdate);
// System.out.println("证书失效日期:" + info);
// 获得证书主体信息
info = oCert.getSubjectDN().getName();
cerC.owner=info;
// 获得证书颁发者信息
info = oCert.getIssuerDN().getName();
cerC.announcer=info;
// 获得证书签名算法名称
info = oCert.getSigAlgName();
cerC.AlgorithmName=info;
// PublicKey pk = oCert.getPublicKey();
// System.out.println("pk:"+pk.toString());
MessageDigest md= MessageDigest.getInstance("SHA1");
byte[] publicKey=md.digest(oCert.getEncoded());
String hexString=byte2HexFormatted(publicKey);
// System.out.println(hexString);
cerC.SHA1=hexString;
} catch (Exception e) {
System.out.println("解析证书出错!");
e.printStackTrace();
}
return cerC;
}
public String byte2HexFormatted(byte[] arr){
StringBuilder str=new StringBuilder(arr.length * 2);
for (int i=0;i<arr.length;i++){
String h=Integer.toHexString(arr[i]);
int l=h.length();
if (l==1){
h="0"+h;
}
if (l>2){
h=h.substring(l-2, l);
}
str.append(h.toUpperCase());
if (i<arr.length-1){
str.append(':');
}
}
return str.toString();
}
@Override
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
Cursor c = pkgDb.query(my_table, null, null, null, null, null,null);
return c;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
pkgDb.insert(my_table,null,contentValues);
return null;
}
@Override
public int delete(Uri uri, String s, String[] strings) {
pkgDb.delete(my_table,s,strings);
return 0;
}
@Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0;
}
}
读取本地证书:
package com.android.settings.verifyapp;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created by haozhenghui on 16-8-30.
*/
public class ReadCerFile {
private final String TAG="ReadCerFile";
public List<cerCls> ReadUserCerFile(String path) {
List<cerCls> myCerList = new ArrayList<cerCls>();
File file = new File(path);
File[] subFile = file.listFiles();
for (int i = 0; i < subFile.length; i++) {
if (subFile[i].isFile()) {
try {
cerCls cer = ReadX509CerFile(subFile[i]);
cer.system = "false";
myCerList.add(cer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return myCerList;
}
public cerCls readX509CerFileFromUser(String path){
Log.d(TAG,"path:"+path);
File file=new File(path);
if (file.isFile()){
try {
cerCls cer=ReadX509CerFile(file);
cer.system="false";
return cer;
} catch (Exception e) {
e.printStackTrace();
}
}
Log.e(TAG,"not file");
return null;
}
public cerCls ReadX509CerFile(File file) throws Exception {
cerCls cerC = new cerCls();
try {
InputStream inStream = new FileInputStream(file);
// 创建X509工厂类
CertificateFactory cf = CertificateFactory.getInstance("X.509");
//CertificateFactory cf = CertificateFactory.getInstance("X509");
// 创建证书对象
X509Certificate oCert = (X509Certificate) cf
.generateCertificate(inStream);
inStream.close();
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd");
String info = null;
// 获得证书版本
info = String.valueOf(oCert.getVersion());
cerC.versionNum = info;
// 获得证书序列号
info = oCert.getSerialNumber().toString(16);
cerC.SerialNum = info;
// 获得证书有效期
Date beforedate = oCert.getNotBefore();
info = dateformat.format(beforedate);
// System.out.println("证书生效日期:" + info);
Date afterdate = oCert.getNotAfter();
info = dateformat.format(afterdate);
// System.out.println("证书失效日期:" + info);
// 获得证书主体信息
info = oCert.getSubjectDN().getName();
cerC.owner = info;
// 获得证书颁发者信息
info = oCert.getIssuerDN().getName();
cerC.announcer = info;
// 获得证书签名算法名称
info = oCert.getSigAlgName();
cerC.AlgorithmName = info;
// PublicKey pk = oCert.getPublicKey();
// System.out.println("pk:"+pk.toString());
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] publicKey = md.digest(oCert.getEncoded());
String hexString = byte2HexFormatted(publicKey);
// System.out.println(hexString);
cerC.SHA1 = hexString;
} catch (Exception e) {
System.out.println("解析证书出错!");
e.printStackTrace();
}
return cerC;
}
public String byte2HexFormatted(byte[] arr) {
StringBuilder str = new StringBuilder(arr.length * 2);
for (int i = 0; i < arr.length; i++) {
String h = Integer.toHexString(arr[i]);
int l = h.length();
if (l == 1) {
h = "0" + h;
}
if (l > 2) {
h = h.substring(l - 2, l);
}
str.append(h.toUpperCase());
if (i < arr.length - 1) {
str.append(':');
}
}
return str.toString();
}
}