This commit is contained in:
2024-09-27 19:16:49 +08:00
commit 49d0cea04d
10000 changed files with 1616312 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cert_utils.h"
#include <cstring>
#include <string>
#include "log.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
static const uint32_t CERT_DATA_SIZE = 8192;
static const uint32_t CERT_COUNT = 4;
bool ConstructDataToCertChain(struct HksCertChain **certChain)
{
*certChain = static_cast<struct HksCertChain *>(malloc(sizeof(struct HksCertChain)));
if (*certChain == nullptr) {
LOG_ERROR(LABEL, "malloc fail");
return false;
}
(*certChain)->certsCount = CERT_COUNT;
(*certChain)->certs = static_cast<struct HksBlob *>(malloc(sizeof(struct HksBlob) *
((*certChain)->certsCount)));
if ((*certChain)->certs == nullptr) {
free(*certChain);
*certChain = nullptr;
return false;
}
for (uint32_t i = 0; i < (*certChain)->certsCount; i++) {
(*certChain)->certs[i].size = CERT_DATA_SIZE;
(*certChain)->certs[i].data = static_cast<uint8_t *>(malloc((*certChain)->certs[i].size));
if ((*certChain)->certs[i].data == nullptr) {
LOG_ERROR(LABEL, "malloc fail");
FreeCertChain(certChain, i);
return false;
}
}
return true;
}
void FreeCertChain(struct HksCertChain **certChain, const uint32_t pos)
{
if (*certChain == nullptr) {
return;
}
if ((*certChain)->certs == nullptr) {
free(*certChain);
*certChain = nullptr;
return;
}
for (uint32_t j = 0; j < pos; j++) {
if ((*certChain)->certs[j].data != nullptr) {
free((*certChain)->certs[j].data);
(*certChain)->certs[j].data = nullptr;
}
}
free((*certChain)->certs);
(*certChain)->certs = nullptr;
free(*certChain);
*certChain = nullptr;
}
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "file_helper.h"
#include <climits>
#include <cstdlib>
#include <unistd.h>
#include "directory_ex.h"
#include "log.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
bool CheckFilePathValid(const std::string &path, const std::string &baseRealPath)
{
std::string realPath;
if (!OHOS::PathToRealPath(path, realPath)) {
LOG_INFO(LABEL, "Get real path failed, path = %{public}s", path.c_str());
return false;
}
return (realPath.size() > baseRealPath.size()) &&
(baseRealPath.compare(realPath.substr(0, baseRealPath.size())) == 0);
}
}
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fsverity_utils_helper.h"
#include <common_defs.h>
#include <fcntl.h>
#include <fsverity_uapi.h>
#include <sys/types.h>
#include <unistd.h>
#include "errcode.h"
#include "file_helper.h"
#include "log.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
static constexpr int MAX_DIGEST_SIZE = 64; // size of sha512
static constexpr int FSVERITY_HASH_PAGE_SIZE = 4096;
static const char *FSVERITY_DIGEST_MAGIC = "FSVerity";
static constexpr uint32_t FSVERITY_DIGEST_MAGIC_LENGTH = 8;
FsverityUtilsHelper &FsverityUtilsHelper::GetInstance()
{
static FsverityUtilsHelper singleFsverityUtilsHelper;
return singleFsverityUtilsHelper;
}
FsverityUtilsHelper::FsverityUtilsHelper()
{
Init();
}
FsverityUtilsHelper::~FsverityUtilsHelper() {}
void FsverityUtilsHelper::Init()
{
libfsverity_set_error_callback(ErrorMsgLogCallback);
}
void FsverityUtilsHelper::ErrorMsgLogCallback(const char *msg)
{
LOG_ERROR(LABEL, "fsverity_utils error = %{public}s", msg);
}
bool FsverityUtilsHelper::FormatDigest(libfsverity_digest *digest, uint8_t *buffer)
{
struct fsverity_formatted_digest *ret = reinterpret_cast<struct fsverity_formatted_digest *>(buffer);
if (memcpy_s(ret->magic, FSVERITY_DIGEST_MAGIC_LENGTH, FSVERITY_DIGEST_MAGIC,
FSVERITY_DIGEST_MAGIC_LENGTH) != EOK) {
return false;
}
ret->digest_algorithm = cpu_to_le16(digest->digest_algorithm);
ret->digest_size = cpu_to_le16(digest->digest_size);
if (memcpy_s(ret->digest, MAX_DIGEST_SIZE, digest->digest, digest->digest_size) != EOK) {
return false;
}
return true;
}
bool FsverityUtilsHelper::ComputeDigest(const char *path, struct libfsverity_digest **digest)
{
struct libfsverity_merkle_tree_params tree_params = {
.version = 1,
.hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
.block_size = FSVERITY_HASH_PAGE_SIZE
};
FileReader reader;
if (!reader.Open(path)) {
return false;
}
if (!reader.GetFileSize(&tree_params.file_size)) {
return false;
}
// compute digest by fsverity-utils and use callback to read data in file
if (libfsverity_compute_digest(&reader, FileReader::ReadFileCallback, &tree_params, digest)) {
LOG_ERROR(LABEL, "Compute digest failed.");
return false;
}
return true;
}
bool FsverityUtilsHelper::GenerateFormattedDigest(const char *path, ByteBuffer &digestBuffer)
{
LOG_INFO(LABEL, "GenerateFormattedDigest called.");
struct libfsverity_digest *digest = nullptr;
if (!ComputeDigest(path, &digest)) {
return false;
}
uint32_t digestLen = sizeof(struct fsverity_formatted_digest) + digest->digest_size;
if (!digestBuffer.Resize(digestLen)) {
free(digest);
return false;
}
bool ret = FormatDigest(digest, digestBuffer.GetBuffer());
free(digest);
return ret;
}
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "openssl_utils.h"
#include "openssl/err.h"
#include "log.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
constexpr int OPENSSL_ERR_MESSAGE_MAX_LEN = 1024;
void ErrLogWithOpenSSLMsg(const char *msg)
{
LOG_ERROR(LABEL, "%{public}s", msg);
GetOpensslErrorMessage();
}
void GetOpensslErrorMessage()
{
unsigned long retOpenssl;
char errOpenssl[OPENSSL_ERR_MESSAGE_MAX_LEN];
while ((retOpenssl = ERR_get_error()) != 0) {
// error string is written no more than OPENSSL_ERR_MESSAGE_MAX_LEN in errOpenssl
ERR_error_string_n(retOpenssl, errOpenssl, OPENSSL_ERR_MESSAGE_MAX_LEN);
LOG_ERROR(LABEL, "openssl err: %{public}lu, message: %{public}s", retOpenssl, errOpenssl);
}
}
X509 *LoadCertFromBuffer(const uint8_t *buffer, const uint32_t size)
{
BIO *mem = BIO_new_mem_buf(buffer, size);
if (mem == nullptr) {
LOG_ERROR(LABEL, "Fail to create bio for cert.");
return nullptr;
}
X509 *cert = d2i_X509_bio(mem, nullptr);
if (cert == nullptr) {
ErrLogWithOpenSSLMsg("Certificate is invalid.");
}
BIO_free(mem);
return cert;
}
STACK_OF(X509) *MakeStackOfCerts(const std::vector<ByteBuffer> &certChain)
{
STACK_OF(X509)* certs = sk_X509_new_null();
if (certs == nullptr) {
return nullptr;
}
for (const ByteBuffer &cert: certChain) {
X509 *tmp = LoadCertFromBuffer(cert.GetBuffer(), cert.GetSize());
if ((tmp == nullptr) || (!sk_X509_push(certs, tmp))) {
// including each cert in certs and stack of certs
sk_X509_pop_free(certs, X509_free);
certs = nullptr;
break;
}
}
return certs;
}
}
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pkcs7_data.h"
#include <string>
#include "log.h"
#include "openssl/asn1.h"
#include "openssl_utils.h"
#include "securec.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
PKCS7Data::PKCS7Data(const EVP_MD *md, X509 *cert)
: cert_(cert), md_(md)
{
}
PKCS7Data::~PKCS7Data()
{
cert_ = nullptr;
md_ = nullptr;
if (p7_ != nullptr) {
// signerinfo would be freed with p7
PKCS7_free(p7_);
p7_ = nullptr;
}
}
bool PKCS7Data::InitPKCS7Data(const std::vector<ByteBuffer> &certChain)
{
int flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR | PKCS7_PARTIAL;
STACK_OF(X509) *certs = nullptr;
if (certChain.empty()) {
flags = flags | PKCS7_NOCERTS;
} else {
certs = MakeStackOfCerts(certChain);
}
p7_ = PKCS7_sign(nullptr, nullptr, certs, nullptr, flags);
if (p7_ == nullptr) {
sk_X509_pop_free(certs, X509_free);
return false;
}
return true;
}
bool PKCS7Data::GetPKCS7Data(ByteBuffer &pkcs7Data)
{
BIO *bio = BIO_new(BIO_s_mem());
bool ret = false;
do {
if (bio == nullptr) {
break;
}
if (!i2d_PKCS7_bio(bio, p7_)) {
ErrLogWithOpenSSLMsg("Encode pkcs7 data failed.");
break;
}
uint8_t *tmp = nullptr;
long tmpSize = BIO_get_mem_data(bio, &tmp);
if ((tmpSize < 0) || (tmpSize > UINT32_MAX)) {
break;
}
if (!pkcs7Data.CopyFrom(tmp, static_cast<uint32_t>(tmpSize))) {
break;
}
ret = true;
} while (0);
BIO_free(bio);
return ret;
}
bool PKCS7Data::AddSignerInfo(PKCS7_SIGNER_INFO *p7i)
{
if (!PKCS7_add_signer(p7_, p7i)) {
PKCS7_SIGNER_INFO_free(p7i);
LOG_ERROR(LABEL, "Add signer to pkcs7 failed");
return false;
}
return true;
}
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pkcs7_generator.h"
#include "errcode.h"
#include "log.h"
#include "openssl/asn1.h"
#include "openssl/evp.h"
#include "openssl/pem.h"
#include "openssl/x509.h"
#include "openssl_utils.h"
#include "pkcs7_data.h"
#include "securec.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
int32_t PKCS7Generator::GenerateSignature(SignKey &key, const char *hashAlg,
const ByteBuffer &contentData, ByteBuffer &out)
{
LOG_INFO(LABEL, "GenerateSignature called.");
int32_t ret = CS_ERR_OPENSSL_PKCS7;
X509 *cert = nullptr;
do {
const ByteBuffer *certBuffer = key.GetSignCert();
if (certBuffer == nullptr) {
ret = CS_ERR_HUKS_OBTAIN_CERT;
break;
}
cert = LoadCertFromBuffer(certBuffer->GetBuffer(), certBuffer->GetSize());
if (cert == nullptr) {
ret = CS_ERR_OPENSSL_LOAD_CERT;
break;
}
const EVP_MD *md = EVP_get_digestbyname(hashAlg);
if (md == nullptr) {
break;
}
PKCS7Data pkcs7(md, cert);
if (!pkcs7.InitPKCS7Data(key.GetCarriedCerts())) {
break;
}
SignerInfo signerInfo;
if (!signerInfo.InitSignerInfo(cert, md, contentData)) {
break;
}
if (!pkcs7.AddSignerInfo(signerInfo.GetSignerInfo())) {
break;
}
ret = SignData(key, signerInfo);
if (ret != CS_SUCCESS) {
break;
}
if (!pkcs7.GetPKCS7Data(out)) {
ret = CS_ERR_OPENSSL_PKCS7;
break;
}
ret = CS_SUCCESS;
} while (0);
X509_free(cert);
if (ret != CS_SUCCESS) {
LOG_ERROR(LABEL, "Generate signature failed, ret = %{public}d", ret);
}
return ret;
}
int32_t PKCS7Generator::SignData(SignKey &key, SignerInfo &signerInfo)
{
uint32_t dataSize = 0;
uint8_t *data = signerInfo.GetDataToSign(dataSize);
if (data == nullptr) {
return CS_ERR_OPENSSL_PKCS7;
}
ByteBuffer unsignedData;
if (!unsignedData.CopyFrom(data, dataSize)) {
return CS_ERR_MEMORY;
}
ByteBuffer rawSignature;
if (!key.Sign(unsignedData, rawSignature)) {
return CS_ERR_HUKS_SIGN;
}
if (!signerInfo.AddSignatureInSignerInfo(rawSignature)) {
return CS_ERR_OPENSSL_PKCS7;
}
return CS_SUCCESS;
}
}
}
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "signer_info.h"
#include "log.h"
#include "openssl/asn1.h"
#include "openssl/pem.h"
#include "openssl_utils.h"
#include "securec.h"
namespace OHOS {
namespace Security {
namespace CodeSign {
static constexpr int INVALID_SIGN_ALGORITHM_NID = -1;
static constexpr int MAX_SIGNATURE_SIZE = 1024; // 1024: max signature length
bool SignerInfo::InitSignerInfo(X509 *cert, const EVP_MD *md,
const ByteBuffer &contentData, bool carrySigningTime)
{
if ((cert == nullptr) || (md == nullptr)) {
return false;
}
md_ = md;
carrySigningTime_ = carrySigningTime;
p7info_ = PKCS7_SIGNER_INFO_new();
if (p7info_ == nullptr) {
ErrLogWithOpenSSLMsg("Create pkcs7 signer info failed");
return false;
}
bool ret = false;
do {
// set default information, pkcs7 signer info version is 1
if (!ASN1_INTEGER_set(p7info_->version, 1)) {
break;
}
// add sign cert info
if (!X509_NAME_set(&p7info_->issuer_and_serial->issuer,
X509_get_issuer_name(cert))) {
break;
}
ASN1_INTEGER_free(p7info_->issuer_and_serial->serial);
if (!(p7info_->issuer_and_serial->serial =
ASN1_INTEGER_dup(X509_get_serialNumber(cert)))) {
break;
}
// add digest and signature algorithm
if (!X509_ALGOR_set0(p7info_->digest_alg, OBJ_nid2obj(EVP_MD_type(md)),
V_ASN1_NULL, nullptr)) {
break;
}
int signatureNid = GetSignAlgorithmID(cert);
if (signatureNid < 0) {
break;
}
if (!X509_ALGOR_set0(p7info_->digest_enc_alg, OBJ_nid2obj(signatureNid),
V_ASN1_NULL, nullptr)) {
break;
}
if (!AddAttrsToSignerInfo(contentData)) {
ErrLogWithOpenSSLMsg("Add attributes to signer info failed");
break;
}
ret = true;
} while (0);
if (!ret) {
PKCS7_SIGNER_INFO_free(p7info_);
ErrLogWithOpenSSLMsg("Init pkcs7 signer info failed");
}
return ret;
}
bool SignerInfo::AddAttrsToSignerInfo(const ByteBuffer &contentData)
{
if (!carrySigningTime_) {
unsignedData_ = std::make_unique<ByteBuffer>();
if (!unsignedData_->CopyFrom(contentData.GetBuffer(), contentData.GetSize())) {
unsignedData_.reset(nullptr);
return false;
}
return true;
}
if (!PKCS7_add_attrib_content_type(p7info_, nullptr)) {
return false;
}
if (!PKCS7_add0_attrib_signing_time(p7info_, nullptr)) {
return false;
}
ByteBuffer digest;
if (!ComputeDigest(contentData, digest)) {
return false;
}
if (!PKCS7_add1_attrib_digest(p7info_, digest.GetBuffer(), digest.GetSize())) {
return false;
}
return true;
}
uint8_t *SignerInfo::GetDataToSign(uint32_t &len)
{
if (p7info_ == nullptr) {
return nullptr;
}
uint8_t *data = nullptr;
if (carrySigningTime_) {
int itemLen = ASN1_item_i2d(reinterpret_cast<ASN1_VALUE *>(p7info_->auth_attr), &data,
ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
if (itemLen < 0) {
return nullptr;
}
len = itemLen;
} else {
if (unsignedData_ == nullptr) {
return nullptr;
}
data = unsignedData_->GetBuffer();
len = unsignedData_->GetSize();
}
return data;
}
bool SignerInfo::AddSignatureInSignerInfo(const ByteBuffer &signature)
{
if (p7info_ == nullptr) {
return false;
}
uint32_t signatureSize = signature.GetSize();
// tmp will be free when freeing p7info_
if (signatureSize == 0 || signatureSize > MAX_SIGNATURE_SIZE) {
return false;
}
uint8_t *tmp = static_cast<uint8_t *>(malloc(signatureSize));
if (tmp == nullptr) {
return false;
}
(void)memcpy_s(tmp, signatureSize, signature.GetBuffer(), signatureSize);
ASN1_STRING_set0(p7info_->enc_digest, tmp, signatureSize);
return true;
}
bool SignerInfo::ComputeDigest(const ByteBuffer &data, ByteBuffer &digest)
{
uint8_t mdBuffer[EVP_MAX_MD_SIZE];
uint32_t mdLen = 0;
EVP_MD_CTX *mCtx = EVP_MD_CTX_new();
bool ret = false;
do {
if (mCtx == nullptr) {
break;
}
if (!EVP_DigestInit_ex(mCtx, md_, nullptr)) {
break;
}
if (!EVP_DigestUpdate(mCtx, data.GetBuffer(), data.GetSize())) {
break;
}
if (!EVP_DigestFinal_ex(mCtx, mdBuffer, &mdLen)) {
break;
}
ret = true;
} while (0);
if (!ret) {
ErrLogWithOpenSSLMsg("Compute digest failed.");
} else if (!digest.CopyFrom(mdBuffer, mdLen)) {
ret = false;
}
EVP_MD_CTX_free(mCtx);
return ret;
}
int SignerInfo::GetSignAlgorithmID(const X509 *cert)
{
X509_PUBKEY *xpkey = X509_get_X509_PUBKEY(cert);
ASN1_OBJECT *koid = nullptr;
if (!X509_PUBKEY_get0_param(&koid, nullptr, nullptr, nullptr, xpkey)) {
return INVALID_SIGN_ALGORITHM_NID;
}
int signatureNid = OBJ_obj2nid(koid);
if (signatureNid == NID_rsaEncryption) {
return signatureNid;
}
OBJ_find_sigid_by_algs(&signatureNid, EVP_MD_type(md_), signatureNid);
return signatureNid;
}
PKCS7_SIGNER_INFO *SignerInfo::GetSignerInfo()
{
return p7info_;
}
}
}
}