提交 #1
This commit is contained in:
80
base/security/code_signature/utils/src/cert_utils.cpp
Normal file
80
base/security/code_signature/utils/src/cert_utils.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
base/security/code_signature/utils/src/file_helper.cpp
Normal file
40
base/security/code_signature/utils/src/file_helper.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
base/security/code_signature/utils/src/fsverity_utils_helper.cpp
Normal file
112
base/security/code_signature/utils/src/fsverity_utils_helper.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
base/security/code_signature/utils/src/openssl_utils.cpp
Normal file
76
base/security/code_signature/utils/src/openssl_utils.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
base/security/code_signature/utils/src/pkcs7_data.cpp
Normal file
98
base/security/code_signature/utils/src/pkcs7_data.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
base/security/code_signature/utils/src/pkcs7_generator.cpp
Normal file
102
base/security/code_signature/utils/src/pkcs7_generator.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
206
base/security/code_signature/utils/src/signer_info.cpp
Normal file
206
base/security/code_signature/utils/src/signer_info.cpp
Normal 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_;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user