1 Star 0 Fork 5K

fish / docs

forked from OpenHarmony / docs 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
应用验签开发指导.md 12.89 KB
一键复制 编辑 原始数据 按行查看 历史
NEEN 提交于 2021-04-08 16:33 . fixed bugs

应用验签开发指导

场景介绍

当需要验证调试应用、发布应用,OpenHarmony自签名应用的完整性是否被破坏时,可以调用验签组件的接口进行验证。如有需要还可通过验签接口获取部分描述文件信息,如appid。对于调试应用,还可通过验签接口验证应用和设备的UDID是否匹配,确保应用安装在了正确的设备上。

验签流程

未经签名的Hap包的压缩方式是ZIP格式,简单分为文件块,中心目录(Central directory)块,中心目录结尾(EOCD,End of central directory record)块。

经过签名的Hap包,在文件块,和中心目录块之间,插入了签名块。签名块由文件签名数据块(data sign block)、描述文件签名数据块(profile sign block)和签名头(sign head)组成,如下图所示。

图 1 经过签名的Hap包结构

整个验签流程,主要分为三部分:整包验签、描述文件签名块验签,以及描述文件内容校验。

整包验签

用设备的预置根证书,通过证书链来证明叶子证书本身是可信的,然后用叶子证书的公钥解密出的摘要证明整包是未篡改的。

具体操作步骤如下:

  1. 对文件签名数据块中的证书链进行校验,确定其叶子证书是可信的。
  2. 用叶子证书中的公钥对文件签名块进行验签,证明其未被篡改。
  3. 计算并合并文件块,中心目录块和中心目录结尾块的摘要。然后将计算结果,再与签名块中的描述文件签名块的摘要合并,将最终合并的摘要与文件签名块中包含的摘要对比,如果两者相等,则整包验签通过。

描述文件签名块验签

首先判断文件签名的签发单位,如果是应用市场签发的发布应用,则无需对描述文件进行验签,直接信任,否则要对其验签。先取出整个描述文件签名块,然后验证证书链,最后用叶子证书对描述文件数据块验签,证明其未被篡改。

描述文件内容校验

取出描述文件,并对其内容进行合法性检查。其中若hap包为调试应用,则会比对本机UDID与描述文件中包含的UDID列表,如果本机UDID在描述文件的UDID列表中包含,则验证通过。比较描述文件中包含的证书(如果是应用市场发布应用或OpenHarmony自签名则无需比较),和整包校验时使用的叶子证书,如果相同,认为整个验签流程完成。

接口说明

验签组件当前提供innerkits接口,仅供系统应用调用,相关接口及功能描述如下:

表 1 验签组件API接口功能介绍

接口名

描述

int APPVERI_AppVerify(const char *filePath, VerifyResult *verifyRst)

主入口函数,输入文件路径,进行验签,并将从描述文件中获取的数据通过verifyRst返回给调用者

int APPVERI_SetDebugMode(bool mode)

设置测试模式,设置mode为true,则支持基于测试根密钥的证书链校验,设置mode为false,则关闭基于测试根密钥的证书链校验。

注:当前没有基于现有测试根密钥的证书,开发者可根据自身需要,替换测试根密钥并进行相关验证。

void APPVERI_FreeVerifyRst(VerifyResult *verifyRst)

释放verifyRst中申请的内存

开发步骤(场景一)

验签指导

对应用市场发布应用、基于应用市场调试证书签发的调试应用、OpenHarmony自签名应用的校验。

  1. 定义出参结构体变量VerifyResult;

    VerifyResult verifyResult = {0};
  2. 以文件路径及VerifyResult为入参,调用APPVERI_AppVerify进行文件校验;

    int32_t ret = APPVERI_AppVerify(hapFilepath.c_str(), &verifyResult);
  3. 判断返回结果,如果校验通过的话,获取VerifyResult中的数据,进行业务处理;

    signatureInfo.appId = verifyResult.profile.appid;
    signatureInfo.provisionBundleName = verifyResult.profile.bundleInfo.bundleName;
  4. 调用APPVERI_FreeVerifyRst,释放VerifyResult中申请的内存。

    APPVERI_FreeVerifyRst(&verifyResult);

生成OpenHarmony自签名应用

如果是OpenHarmony自签名应用的校验,开发者可通过以下方式生成OpenHarmony自签名应用。

  1. 材料备齐。

    生成自签名应用需要的材料有:签名工具、系统应用hap包、系统应用profile文件(*.p7b)、签名证书(*.cer)、签名公私钥对(*.jks)。

  2. 将所有材料放在同一个目录下,打开shell。

  3. 根据应用、描述文件的实际名称修改指令,并在shell中输入,完成签名。

    java -jar hapsigntoolv2.jar sign -mode localjks -privatekey "OpenHarmony Software Signature" -inputFile camera.hap -outputFile signed_camera.hap -signAlg SHA256withECDSA -keystore OpenHarmony.jks -keystorepasswd 123456 -keyaliaspasswd 123456 -profile camera_release.p7b -certpath OpenHarmony.cer -profileSigned 1

    关键字段说明:

    -jar:签名工具,hapsigntool

    -mode:本地签名标记位,固定为localjks

    -privatekey:密钥对别名,签名公私钥对的别名为OpenHarmony Software Signature

    -inputFile:待签名应用,通过编译产生

    -outputFile:签名后应用,最终输出

    -signAlg:签名算法,当前固定为SHA256withECDSA

    -keystore:公私钥对,使用签名公私钥对,位于开源库security_services_app_verify仓中OpenHarmonyCer目录下,OpenHarmony.jks。默认密码为123456 ,用户可采用工具(例如keytool)更改默认密码

    -keystorepasswd:公私钥对密码,默认签名公私钥对密码为123456

    -keyaliaspasswd:公私钥对别名密码,默认签名公私钥对别名密码为123456

    -profile:描述文件,应用的描述文件位于对应源代码目录中

    -certpath:使用签名证书,位于开源库security_services_app_verify仓中OpenHarmonyCer目录下,OpenHarmony.cer

    -profileSigned:签名块中是否包含描述文件(profile)。固定为1(包含)

开发示例

以应用管理框架组件在应用安装时进行验签的实际调用为例:

uint8_t HapSignVerify::VerifySignature(const std::string &hapFilepath, SignatureInfo &signatureInfo)
{
	bool mode = ManagerService::GetInstance().IsDebugMode();
	HILOG_INFO(HILOG_MODULE_APP, "current mode is %d!", mode);
        // 定义结果结构体
	VerifyResult verifyResult = {0};
        // 输入待验签文件路径进行验签
	int32_t ret = APPVERI_AppVerify(hapFilepath.c_str(), &verifyResult); 
	uint8_t errorCode = SwitchErrorCode(ret);
	if (errorCode != ERR_OK) {
		return errorCode;
	}
        // 从结果结构体中获取appid
	signatureInfo.appId = verifyResult.profile.appid; 
        // 从结果结构体中获取描述文件中书写的应用名
	signatureInfo.provisionBundleName = verifyResult.profile.bundleInfo.bundleName; 
	int32_t restricNum = verifyResult.profile.permission.restricNum;
	for (int32_t i = 0; i < restricNum; i++) {
		signatureInfo.restrictedPermissions.emplace_back((verifyResult.profile.permission.restricPermission)[i]);
	}
        // 释放结果结构体中申请的内存
	APPVERI_FreeVerifyRst(&verifyResult); 
	return ERR_OK;
}

开发步骤(场景二)

验签指导

对采用基于测试根密钥证书签名的应用的校验。

  1. 调用APPVERI_SetDebugMode(true)开启测试模式;

    	ManagerService::SetDebugMode(true);
    ...
    uint8_t ManagerService::SetDebugMode(bool enable)
    {
    	int32_t ret = APPVERI_SetDebugMode(enable);
    	if (ret < 0) {
    		HILOG_ERROR(HILOG_MODULE_APP, "set signature debug mode failed");
    		return ERR_APPEXECFWK_SET_DEBUG_MODE_ERROR;
    	}
    	isDebugMode_ = enable;
    	HILOG_INFO(HILOG_MODULE_APP, "current sign debug mode is %d", isDebugMode_);
    	return ERR_OK;
    }
  2. 同场景一中步骤一至四,定义结构体,校验、释放结构体;

  3. 调用APPVERI_SetDebugMode(false)关闭测试模式。

            ManagerService::SetDebugMode(false);

开发示例

完整开发示例如下(在场景一代码示例的基础上进行补充):

uint8_t ManagerService::SetDebugMode(bool enable)
{
	int32_t ret = APPVERI_SetDebugMode(enable);
	if (ret < 0) {
		HILOG_ERROR(HILOG_MODULE_APP, "set signature debug mode failed");
		return ERR_APPEXECFWK_SET_DEBUG_MODE_ERROR;
	}
	isDebugMode_ = enable;
	HILOG_INFO(HILOG_MODULE_APP, "current sign debug mode is %d", isDebugMode_);
	return ERR_OK;
}
uint8_t HapSignVerify::VerifySignature(const std::string &hapFilepath, SignatureInfo &signatureInfo)
{
        // 开启支持测试服务器签名应用验证
        ManagerService::SetDebugMode(true); 
	bool mode = ManagerService::GetInstance().IsDebugMode();
	HILOG_INFO(HILOG_MODULE_APP, "current mode is %d!", mode);
        // 定义结果结构体
	VerifyResult verifyResult = {0}; 
        // 输入待验签文件路径进行验签
	int32_t ret = APPVERI_AppVerify(hapFilepath.c_str(), &verifyResult); 
	uint8_t errorCode = SwitchErrorCode(ret);
	if (errorCode != ERR_OK) {
		return errorCode;
	}
        // 从结果结构体中获取appid
	signatureInfo.appId = verifyResult.profile.appid; 
        // 从结果结构体中获取描述文件中书写的应用名
	signatureInfo.provisionBundleName = verifyResult.profile.bundleInfo.bundleName; 
	int32_t restricNum = verifyResult.profile.permission.restricNum;
	for (int32_t i = 0; i < restricNum; i++) {
		signatureInfo.restrictedPermissions.emplace_back((verifyResult.profile.permission.restricPermission)[i]);
	}
        // 释放结果结构体中申请的内存
        APPVERI_FreeVerifyRst(&verifyResult); 
        // 关闭支持测试服务器签名应用验证
        ManagerService::SetDebugMode(false); 
	return ERR_OK;
}

调测验证

  1. 选取一个在OpenHarmony上能够正常安装的应用A。
  2. 根据开发指导开发。
  3. 对应用A,采用自开发程序进行验签,验签通过,能获取到appid。即为开发成功。
1
https://gitee.com/fish_neil/docs.git
git@gitee.com:fish_neil/docs.git
fish_neil
docs
docs
master

搜索帮助