最近遇到几个WAPI证书安装的问题,看了几天WAPI的相关代码,这里总结一下。

user证书是以"-----BEGIN CERTIFICATE-----“和”-----BEGIN EC PRIVATE KEY-----“开头,ca证书只有”-----BEGIN CERTIFICATE-----",没有"-----BEGIN EC PRIVATE KEY-----"

private static final String CERT_BEGIN = "-----BEGIN CERTIFICATE-----";
private static final String CERT_END = "-----END CERTIFICATE-----";
private static final String PRIKEY_BEGIN = "-----BEGIN EC PRIVATE KEY-----";
private static final String PRIKEY_END = "-----END EC PRIVATE KEY-----";indexCertBegin = certContent.indexOf(CERT_BEGIN);
indexCertEnd = certContent.indexOf(CERT_END);
indexPriKeyBegin = certContent.indexOf(PRIKEY_BEGIN);
indexPriKeyEnd = certContent.indexOf(PRIKEY_END);if(indexCertBegin >= 0 && indexCertEnd > 0)
{if(indexPriKeyBegin > 0 && indexPriKeyEnd > 0){Log.d(TAG, "user cert file");return 1;}else if(indexPriKeyBegin <= 0 && indexPriKeyEnd <= 0){Log.d(TAG, "ca cert file");return 2;}else{Log.d(TAG, "other cert file 1");return 0;}
}

Android中WAPI证书管理虽然在设置中,但是他是一个单独的app,在packages/apps/WapiCertManage下面。

一、点击WAPI证书管理,会进入这个activity。然后点击右上角加载证书。
packages/apps/WapiCertManage/src/com/wapi/wapicertmanage/WapiCertManageActivity.java

public boolean onOptionsItemSelected(MenuItem item) {// TODO Auto-generated method stubsuper.onOptionsItemSelected(item);switch (item.getItemId()){case MENU_ID_ADD_CERT:onAddWapiCertItem("");return true;default:return false;}
}

二、这里可以看到,点击按钮以后会先去从SD卡中find证书。如果onFindWapiCertFromSDRoot找到了证书,则弹出安装证书的Dialog。

public boolean onAddWapiCertItem(String userCertName)
{if(onFindWapiCertFromSDRoot()){onShowAddWapiCertDialog(userCertName);return true;}else{return false;}
}

三、接下来看怎么查找WAPI证书,先判断有没有SD卡,注意这里的SD卡是内置SD卡,安装WAPI证书必须把证书放在内置SD卡,不支持手动选择目录。Environment.getExternalStorageDirectory()就是获取内置SD卡。
如果在/sdcard/下发现cer证书或者p12证书,则返回true,否则弹出没有可用的证书。

private boolean onFindWapiCertFromSDRoot() {if (! Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){Log.e(TAG, "No SD card found.");Toast.makeText(WapiCertManageActivity.this, R.string.text_not_access_to_SD, Toast.LENGTH_LONG).show();return false;}File sdRoot = Environment.getExternalStorageDirectory();if(sdRoot == null){Log.e(TAG, "sd root file is null.");return false;}try{boolean bFind = false;File[] fileList = sdRoot.listFiles();int length = fileList.length;for (int i = 0; i < length; i++){if (WapiCertUtil.isTheSuffix(fileList[i].getAbsoluteFile().toString(), ".cer")){if (!fileList[i].isDirectory() &&(WapiCertUtil.getCertificateType(fileList[i]) == 1)){Log.d(TAG, "Find wapi user cert");bFind = true;break;}}else if(WapiCertUtil.isTheSuffix(fileList[i].getAbsoluteFile().toString(), ".p12")){Log.v(TAG, "find a p12 cert ");bFind = true;break;}else{continue;
y            }}if(bFind){return true;}else{Toast.makeText(this, R.string.text_not_find_valid_cert_in_SD, Toast.LENGTH_LONG).show();return false;}}catch (Exception e){e.printStackTrace();return false;}
}

四、由第二步可知,第三步找到证书以后会弹出安装证书的Dialog

private void onShowAddWapiCertDialog(String userCertName)
{WapiCertManageDlg dialog = new WapiCertManageDlg(this, this, userCertName);dialog.setWapiCertStore(mWapiCertStore);dialog.setMode(WapiCertManageDlg.MODE_ADD_CERT);dialog.setTitle(R.string.add_cert_dlg_title_name);mAddCertDlg = dialog;dialog.show();
}

五、我们看WapiCertManageDlg的代码
packages/apps/WapiCertManage/src/com/wapi/wapicertmanage/WapiCertManageDlg.java

onCreate->onLayout->setLayout->onReferenceViews->setUserCertSpinnerAdapter
protected void onCreate(Bundle savedInstanceState)
{onLayout();super.onCreate(savedInstanceState);
}

setUserCertSpinnerAdapter就是遍历SD卡并将其中的user证书、ca证书和p12证书分别放到一个list中。最后再设置一下选择器。

private void setUserCertSpinnerAdapter()
{Context context = getContext();File certificateList [];int i = 0;mUserCertArray.clear();mIssuerCertArray.clear();//File certificatePath = WapiCertUtil.getSdCardCertificateFile(null);File certificatePath = Environment.getExternalStorageDirectory();try{if (certificatePath != null){certificateList = certificatePath.listFiles();for (i = 0; i < certificateList.length; i++){//Log.v(TAG, "certificateList[i].getAbsoluteFile().toString():"+certificateList[i].getAbsoluteFile().toString());if (WapiCertUtil.isTheSuffix(certificateList[i].getAbsoluteFile().toString(), ".cer")){Log.v(TAG, "certificateList[" + i + "]: " +certificateList[i].getAbsoluteFile().toString());if (!certificateList[i].isDirectory() &&//isUserCertificate(certificateList[i]))(WapiCertUtil.getCertificateType(certificateList[i]) == 1)){Log.d(TAG, "add user cert");mUserCertArray.add(certificateList[i].getName());}else if(!certificateList[i].isDirectory() &&//isUserCertificate(certificateList[i]))(WapiCertUtil.getCertificateType(certificateList[i]) == 2)){Log.d(TAG, "add ca cert");mIssuerCertArray.add(certificateList[i].getName());}}else if(WapiCertUtil.isTheSuffix(certificateList[i].getAbsoluteFile().toString(), ".p12")){Log.v(TAG, "find a p12 cert ");//if(certificateList[i].length<2048){mUserCertArray.add(certificateList[i].getName());}}else{//Log.v(TAG, "not rhgit  cert");continue;}}}ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context,android.R.layout.simple_spinner_item,(String [])mUserCertArray.toArray(new String[0]));adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);mUserCertSpinner.setAdapter(adapter);if(! TextUtils.isEmpty(mUserCertName)){Log.d(TAG, "init, mUserCertName is not empty, set selection");setSelection(mUserCertSpinner, mUserCertName);}}catch (Exception e){setMessage(e.toString());}
}

六、用户选择要安装的证书,然后点击安装

public void onClick(DialogInterface dialog, int which)
{Log.v(TAG, "onClick which " + which);if (which == mInstallCertButtonPos){if(handleInstallCert()){mWapiCertListenner.notifyInstallCert(mUserCertName, mUserCertPath, mCaCertpath, mUserCert, mPriKey, mCaCert);}else{mWapiCertListenner.notifyReopenDlg(mUserCertName);}}else if (which == mCancelButtonPos){handleCancle();}
}

看一下如果处理安装证书。
如果是p12证书,会去解析证书。如果是ca证书,则会直接读取证书内容。目的都是为了获得证书的user cert和私钥。拿到信息以后会去匹配信息matchWapiCert。

private boolean handleInstallCert(){Log.d(TAG, "Handle install user cert: " + mUserCertName);if (null == mUserCertName || TextUtils.isEmpty(mUserCertName)) {Toast.makeText(getContext(), R.string.text_not_find_valid_user_cert_in_SD,Toast.LENGTH_LONG).show();return false;}mUserCertPath = SDCARD_ROOT_PATH + "/" + mUserCertName;Log.d(TAG, "user cert path: " + mUserCertPath);if(mbP12Cert){mP12Pwd = mP12EditText.getText().toString();if((mP12Pwd == null) || TextUtils.isEmpty(mP12Pwd)) {Toast.makeText(getContext(), R.string.text_p12_password_empty,Toast.LENGTH_LONG).show();return false;}File userCertFile = new File(mUserCertPath);byte[] userCertData = WapiCertUtil.readFile(userCertFile);UserCertParam userCertParam = mWapiCertStore.parseP12Cert(userCertData, mP12Pwd);if(userCertParam.cert.length == 0 || userCertParam.prikey.length == 0) {Toast.makeText(getContext(), R.string.text_p12_password_error, Toast.LENGTH_LONG).show();return false;}String strTemp = new String(userCertParam.cert);mUserCert = WapiCertUtil.addCertHeader(strTemp);mPriKey = userCertParam.prikey;}else{File userCertFile = new File(mUserCertPath);byte[] userCertData = WapiCertUtil.readFile(userCertFile);String strTemp = new String(userCertData);mUserCert = WapiCertUtil.getCertElement(strTemp);mPriKey = WapiCertUtil.getPriKeyElement(strTemp);}Log.d(TAG, "user cert: " + (new String(mUserCert)));Log.d(TAG, "private key: " + (new String(mPriKey)));return matchWapiCert(mUserCert, mPriKey);}

七、匹配证书
这里也是遍历之前查到的所以CA证书,看哪个与选的user证书匹配。

private boolean matchWapiCert(byte[] userCert, byte[] priKey) {int index = 0;int caCertCount = 0;caCertCount = mIssuerCertArray.size();Log.d(TAG, "ca cert count: " + caCertCount);for( index = 0; index < caCertCount; index ++) {String caCertName = mIssuerCertArray.get(index);String caCertPath = SDCARD_ROOT_PATH + "/" + caCertName;Log.d(TAG, "ca cert path: " + caCertPath);File caCertFile = new File(caCertPath);byte[] caCertData = WapiCertUtil.readFile(caCertFile);//String strTemp = new String(caCertData);//mCaCert = WapiCertUtil.getCertElement(strTemp);if(mWapiCertStore.checkUserCaCert(userCert, priKey, caCertData)) {mCaCertpath = caCertPath;mCaCert = caCertData;return true;}}Toast.makeText(getContext(), R.string.text_not_match_valid_ca_cert_in_SD, Toast.LENGTH_LONG).show();return false;
}

八、
packages/apps/WapiCertStore/src/com/wapi/wapicertstore/WapiCertStore.java

public boolean checkUserCaCert(byte[] userCert, byte[] priKey, byte[] caCert) {if(checkUserCaCertNative(userCert, priKey, caCert) == 0) {return true;}else {return false;}
}

真正的实现在这里
external/wpa_supplicant_8/wpa_supplicant/wapi/libwapi_cert/wapi_cert_jni.c

jint
Java_com_wapi_wapicertstore_WapiCertStore_checkUserCaCertNative ( JNIEnv* env ,jobject clazz , jbyteArray userCert , jbyteArray priKey ,jbyteArray caCert )
{(void) (clazz);unsigned char *byteUserCert = (unsigned char *) (*env)->GetByteArrayElements ( env ,userCert , 0 );int userCertLen = (*env)->GetArrayLength ( env , userCert );unsigned char *bytePriKey = (unsigned char *) (*env)->GetByteArrayElements ( env , priKey ,0 );int priKeyLen = (*env)->GetArrayLength ( env , priKey );unsigned char *byteCaCert = (unsigned char *) (*env)->GetByteArrayElements ( env , caCert ,0 );int caCertLen = (*env)->GetArrayLength ( env , caCert );int ret = Check_Asue_Asu_Cert ( byteUserCert , userCertLen , bytePriKey ,priKeyLen , byteCaCert , caCertLen );if ( ret != 0 ) {ALOGD("in '%s':'%d' Get UsrCert Or Prikey error\n" , __func__ ,__LINE__ );return -1;}return 0;
}

external/wpa_supplicant_8/wpa_supplicant/wapi/libwapi_cert/wapi_cert.c

int
Check_Asue_Asu_Cert ( const unsigned char *user_cert , int user_cert_len ,const unsigned char *pri_key , int pri_key_len ,const unsigned char *as_cert , int as_cert_len )
{unsigned short unpackcert_len = user_cert_len;unsigned short prikey_outlen = pri_key_len;int asu_outlen = as_cert_len;unsigned char *unpack_cert = malloc ( unpackcert_len );unsigned char *prikey_out = malloc ( prikey_outlen );unsigned char *asucert_out = malloc ( asu_outlen );int ret;ret = Unpack_AsueCert ( user_cert , user_cert_len , unpack_cert ,&unpackcert_len );if ( ret != 0 ){goto error;}ret = Unpack_AsuePrikey ( pri_key , pri_key_len , prikey_out ,&prikey_outlen );if ( ret != 0 ){goto error;}ret = Unpack_AsuCert ( as_cert , as_cert_len , asucert_out , &asu_outlen );if ( ret != 0 ){goto error;}if ( IWN_Check_UserCert_by_CACert ( unpack_cert , unpackcert_len ,asucert_out , asu_outlen , ECC_P192 ) != 1 ){goto error;}if ( IWN_Match_Pub_Pri_key ( unpack_cert , unpackcert_len , prikey_out ,prikey_outlen , ECC_P192 ) != 1 ){goto error;}free ( asucert_out );free ( prikey_out );free ( unpack_cert );return 0;error:free ( asucert_out );free ( prikey_out );free ( unpack_cert );return -1;
}

再后面就是通过加密算法验证user证书和ca证书了,如果匹配成功则安装证书,安装成功。

Android11 WAPI证书安装流程相关推荐

  1. Android 证书安装流程分析

    一.证书在源码中的路径 5.1系统证书(命名是 openssl x509 -subject_hash_old -in filename) libcore/luni/src/main/files/cac ...

  2. 【Android 安装包优化】APK 打包流程 ( 文件结构 | 打包流程 | 安装流程 | 安卓虚拟机 )

    文章目录 一.APK 文件结构 二.APK 打包流程 三.APK 安装流程 四.安卓虚拟机 一.APK 文件结构 Android 应用的安装包时 以 " .apk " 为后缀的 A ...

  3. https证书申请流程和简介

    HTTPS证书是什么 HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安 ...

  4. Android 安装apk流程,Android PMS(二)-Apk安装流程

    原创内容,转载请注明出处,多谢配合. 一.APK组成 在APK的安装流程,在此之前先简单了解下APK组成: 目录/文件 描述 assert 存放的原生资源文件,通过AssetManager类访问. l ...

  5. Android中APK安装流程解析

    前言:大家都知道,手机关机以后,就是一个冰冷的砖头,只能用来做防身的利器,但是开机后,点击桌面上的任何一个图片,都能开启一个APP,这说明在开机过程中,系统把已经安装好的APP加载到内存中,这到底是怎 ...

  6. Tencent SSL 数字证书安装部署

    目录 前言 一.SSL 证书购买 二.配置监听器 三.Nginx SSL 配置 FAQ 前言 之前写了一篇关于 SSL 证书的文章<Nginx 自签证书实现80转443>,不过这是自签证书 ...

  7. 【Linux】宝塔面板 SSL 证书安装部署

    宝塔面板 SSL 证书安装部署 前言 证书下载 宝塔配置SSL 注意事项 前言 前期有讲过Tomcat和Nginx分别部署SSL证书,但也有好多小伙伴们私信我说,帮忙出一期宝塔面板部署SSL证书的教程 ...

  8. mitmproxy环境搭建与证书安装

    mitmproxy还有两个关联组件,一个是mitmdump,它是mitmproxy的命令行接口,利用它可以对接Python脚本,实现监听后的处理:另一个是mitmweb,它是一个Web程序,通过它以清 ...

  9. iOS 制作推送证书的流程 超详细!!!!!

    制作推送证书的流程: 首先我们要有生成一个Certificate Signing Request(也就是CSR)的请求文件.(在应用程序里的使用工具中找到钥匙串访问). 登录开发者账号: (1)如果没 ...

  10. ssl证书如何安装?常见的四类ssl证书安装方法介绍

    网站运营过程中我们不仅会使用到很多的技术,也需要取得相应的认证,在各类型的认证证书当中,ssl证书可以说是最为关键的一种.ssl证书作为确保服务器与用户之间信息传输稳定性和安全性的一种协议证书,ssl ...

最新文章

  1. 599元的智能视频音箱发布,百度准备补贴几个亿?
  2. 如何设计一个通用的权限管理系统
  3. Django 权限管理-后台根据用户权限动态生成菜单
  4. Redis 内存压缩实战
  5. 【看这里】网易云信 IM 红包上线啦!最快3小时集成红包功能
  6. 服务器不安装Excel,实现导出Excel功能
  7. IOS开发(104)之程序执行状态更改
  8. 这个转录组比对工具很快,十几分钟一个样品
  9. (转)基于Metronic的Bootstrap开发框架经验总结(5)--Bootstrap文件上传插件File Input的使用...
  10. mysql error report,ECSHOP网店系统提示MYSQL SERVER ERROR REPORT的解决方法
  11. cmd杀死MySQL进程命令
  12. xxxxxxxxxccccxcc
  13. cat和EOF的组合妙用
  14. android7.1.2 xposed,安卓7.1 xposed框架
  15. python高级用法使用手册(收藏)
  16. 详细解读TPH-YOLOv5 | 让目标检测任务中的小目标无处遁形
  17. linux时间同步到win7,mac与win7时间不同步怎么办_mac与win7时间不准如何解决
  18. 好用的工作邮箱有哪些?工作邮箱如何登录
  19. 电路板级的EMC设计 (1)概述
  20. 大学生怎么入门Android,从一个大学生的角度打开K30PRO,以及对手机圈子的一些看法...

热门文章

  1. 深度学习caffe教程
  2. Ubuntu16.04安装caffe教程(同时安装tensorflow与Pytorch)
  3. 阿里矢量库图标在线链接的使用方法,引入,改变大小与颜色
  4. 安卓系统刷机怎么刷机_手机怎么刷机
  5. 浅谈工业4.0时代,深信服adesk桌面云如何助力智能工厂.
  6. 李宏毅深度学习HW2 收入预测 (logistic regression)
  7. Axure rp8.1.0.3381激活码(亲测可用)
  8. ZLMediaKit+wvp-GB28181-pro,搭建28181协议视频平台
  9. 地理探测器 GD包下载及应用(R语言,基于Rstudio)
  10. Linux内核编程的特点