/* * 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_; } } } }