概念

为了确保应用的完整性和来源可靠,OpenHarmony需要对应用进行签名和验签。

       应用开发阶段:开发者完成开发并生成安装包后,需要开发者对安装包进行签名,以证明安装包发布到设备的过程中没有被篡改。OpenHarmony的应用完整性校验模块提供了签名工具、签名证书生成规范,以及签名所需的公钥证书等完整的机制,支撑开发者对应用安装包签名。为了方便开源社区开发者,版本中预置了公钥证书和对应的私钥,为开源社区提供离线签名和校验能力;在OpenHarmony商用版本中应替换此公钥证书和对应的私钥。

       应用安装阶段:OpenHarmony用户程序框架子系统负责应用的安装。在接收到应用安装包之后,应用程序框架子系统需要解析安装包的签名数据,然后使用应用完整性校验模块的API对签名进行验证,只有校验成功之后才允许安装此应用. 应用完整性校验模块在校验安装包签名数据时,会使用系统预置的公钥证书进行验签。

 

流程

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

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

图1 经过签名的Hap包结构

 

zh-cn_image_0000001217526184

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

整包验签

整包签名数据块是一个PKCS7格式的签名块(signed data),验签过程包括PKSC7签名验证、哈希比较、证书链验证以及证书链与设备预置根证书的匹配校验。

授权文件验签

授权文件数据块是一个PKCS7格式的签名块(signed data),其中PKCS7签名块的内容信息(contentinfo)是授权文件的内容。验签过程包括:PKCS7签名验证、哈希比较、证书链验证以及签发授权文件证书的合法性校验。

授权文件内容校验

验签模块将对授权文件内容进行合法性检查。如果授权文件是调试类型,则会比对本机UDID是否在授权文件授权调试的UDID列表中,如果本机UDID在授权文件授权调试的UDID列表中,则会进一步比较授权文件中的调试证书和整包签名使用的证书是否相同,如果相同,则验证通过。

 

代码分析

接口:int HapVerify(const std::string& filePath, HapVerifyResult& hapVerifyResult)

参数1:文件路径

参数2:hap包的验证结果

 

函数调用关系

HapVerify->HapVerifyV2::Verify->Verify(hapFile, hapVerifyV1Result)

 

代码路径:base/security/appverify/interfaces/innerkits/appverify/src/interfaces/hap_verify.cpp

函数一、

int32_t HapVerify(const std::string& filePath, HapVerifyResult& hapVerifyResult)

{

    if (!g_isInit && !HapVerifyInit()) {  //这段代码负责初始化一个系统中的几个关键信任和安全组件。它首先尝试初始化两个核心组件(根证书管理和受信任源管理)

        return VERIFY_SOURCE_INIT_FAIL;

    }

    HapVerifyV2 hapVerifyV2;

    return hapVerifyV2.Verify(filePath, hapVerifyResult);  //包认证函数

}

 

 代码路径:base/security/appverify/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp

函数二、

int32_t HapVerifyV2::Verify(const std::string& filePath, HapVerifyResult& hapVerifyV1Result)

{

    HAPVERIFY_LOG_DEBUG("Start Verify");

    std::string standardFilePath;

    if (!CheckFilePath(filePath, standardFilePath)) {  //调用CheckFilePath函数检查输入的文件路径是否有效,并将有效的标准文件路径存储在standardFilePath中

        return FILE_PATH_INVALID;

    }

    RandomAccessFile hapFile;

    if (!hapFile.Init(standardFilePath)) {   //调用hapFile的Init方法尝试打开standardFilePath指定的文件

        HAPVERIFY_LOG_ERROR("open standard file failed");

        return OPEN_FILE_ERROR;

    }

    int32_t resultCode = Verify(hapFile, hapVerifyV1Result);  //这行代码调用了当前类的另一个Verify成员函数,将hapFile和hapVerifyV1Result作为参数传递

    return resultCode;

}

代码路径:base/security/appverify/interfaces/innerkits/appverify/src/verify/hap_verify_v2.cpp


函数三、

int32_t HapVerifyV2::Verify(RandomAccessFile& hapFile, HapVerifyResult& hapVerifyV1Result)

{

    SignatureInfo hapSignInfo;   //声明了一个SignatureInfo类型的变量hapSignInfo,用于存储从HAP文件中提取的签名信息

    if (!HapSigningBlockUtils::FindHapSignature(hapFile, hapSignInfo)) {     //函数尝试从hapFile中提取签名信息

        return SIGNATURE_NOT_FOUND;

    }

   //接下来的几行代码使用hapSignInfo中的信息来设置hapVerifyV1Result的各个属性,包括版本、PKCS#7签名块、PKCS#7配置文件块和可选块

    hapVerifyV1Result.SetVersion(hapSignInfo.version);

    hapVerifyV1Result.SetPkcs7SignBlock(hapSignInfo.hapSignatureBlock);

    hapVerifyV1Result.SetPkcs7ProfileBlock(hapSignInfo.hapSignatureBlock);

    hapVerifyV1Result.SetOptionalBlocks(hapSignInfo.optionBlocks);

    Pkcs7Context pkcs7Context;  //声明了一个Pkcs7Context类型的变量pkcs7Context,用于存储PKCS#7验证的上下文信息块。

    if (!VerifyAppPkcs7(pkcs7Context, hapSignInfo.hapSignatureBlock)) {  //调用VerifyAppPkcs7函数验证PKCS#7签名块

        return VERIFY_APP_PKCS7_FAIL;

    }

    int32_t profileIndex = 0;

    if (!HapSigningBlockUtils::GetOptionalBlockIndex(hapSignInfo.optionBlocks, PROFILE_BLOB, profileIndex)) { //找到配置文件块在可选块中的索引

        return NO_PROFILE_BLOCK_FAIL;

    }

    bool profileNeedWriteCrl = false;

    if (!VerifyAppSourceAndParseProfile(pkcs7Context, hapSignInfo.optionBlocks[profileIndex].optionalBlockValue,

        hapVerifyV1Result, profileNeedWriteCrl)) {   //验证应用程序来源并解析配置文件块

        HAPVERIFY_LOG_ERROR("APP source is not trusted");

        return APP_SOURCE_NOT_TRUSTED;

    }

    if (!GetDigestAndAlgorithm(pkcs7Context)) {    //从pkcs7Context中获取摘要和算法信息

        HAPVERIFY_LOG_ERROR("Get digest failed");

        return GET_DIGEST_FAIL;

    }

    std::vector<std::string> publicKeys;

    if (!HapVerifyOpensslUtils::GetPublickeys(pkcs7Context.certChains[0], publicKeys)) {  //从证书链中获取公钥列表

        HAPVERIFY_LOG_ERROR("Get publicKeys failed");

        return GET_PUBLICKEY_FAIL;

    }

    hapVerifyV1Result.SetPublicKey(publicKeys);  //公钥列表设置到hapVerifyV1Result中

    std::vector<std::string> certSignatures;

    if (!HapVerifyOpensslUtils::GetSignatures(pkcs7Context.certChains[0], certSignatures)) {  //从证书链中获取签名列表

        HAPVERIFY_LOG_ERROR("Get sianatures failed");

        return GET_SIGNATURE_FAIL;

    }

    hapVerifyV1Result.SetSignature(certSignatures); //签名列表设置到hapVerifyV1Result中

    if (!HapSigningBlockUtils::VerifyHapIntegrity(pkcs7Context, hapFile, hapSignInfo)) { //验证HAP文件的完整性

        HAPVERIFY_LOG_ERROR("Verify Integrity failed");

        return VERIFY_INTEGRITY_FAIL;

    }

    WriteCrlIfNeed(pkcs7Context, profileNeedWriteCrl); //根据profileNeedWriteCrl的值,调用WriteCrlIfNeed函数决定是否写入证书撤销列表(CRL)

    return VERIFY_SUCCESS;

}

 

 

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐