1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "pkcs7_signed_data.h"
17#include <openssl/asn1.h>
18#include <openssl/bio.h>
19#include <openssl/pkcs7.h>
20#include <openssl/rsa.h>
21#include <openssl/sha.h>
22#include <openssl/x509.h>
23#include "cert_verify.h"
24#include "dump.h"
25#include "openssl_util.h"
26#include "pkg_utils.h"
27
28namespace Hpackage {
29namespace {
30constexpr size_t g_digestAlgoLength[][2] = {
31    {NID_sha256, SHA256_DIGEST_LENGTH},
32};
33
34size_t GetDigestLength(const size_t digestNid)
35{
36    for (size_t i = 0; i < sizeof(g_digestAlgoLength) / sizeof(g_digestAlgoLength[0]); i++) {
37        if (digestNid == g_digestAlgoLength[i][0]) {
38            return g_digestAlgoLength[i][1];
39        }
40    }
41    return 0;
42}
43}
44
45Pkcs7SignedData::~Pkcs7SignedData()
46{
47    if (pkcs7_ != nullptr) {
48        PKCS7_free(pkcs7_);
49        pkcs7_ = nullptr;
50    }
51}
52
53int32_t Pkcs7SignedData::GetHashFromSignBlock(const uint8_t *srcData, const size_t dataLen,
54    std::vector<uint8_t> &hash)
55{
56    int32_t ret = ParsePkcs7Data(srcData, dataLen);
57    if (ret != 0) {
58        PKG_LOGE("parse pkcs7 data fail");
59        UPDATER_LAST_WORD(ret);
60        return ret;
61    }
62
63    ret = Verify();
64    if (ret != 0) {
65        PKG_LOGE("verify pkcs7 data fail");
66        UPDATER_LAST_WORD(ret);
67        return ret;
68    }
69    hash.assign(digest_.begin(), digest_.end());
70
71    return 0;
72}
73
74int32_t Pkcs7SignedData::ParsePkcs7Data(const uint8_t *srcData, const size_t dataLen)
75{
76    if (srcData == nullptr || dataLen == 0) {
77        UPDATER_LAST_WORD(-1);
78        return -1;
79    }
80    if (Init(srcData, dataLen) != 0) {
81        PKG_LOGE("init pkcs7 data fail");
82        UPDATER_LAST_WORD(-1);
83        return -1;
84    }
85
86    return DoParse();
87}
88
89int32_t Pkcs7SignedData::Verify() const
90{
91    std::vector<uint8_t> digestForEVP;
92    for (unsigned int i = 0; i < signatureInfo.overall.length; i++) {
93        digestForEVP.push_back(static_cast<uint8_t>(signatureInfo.overall.buffer[i]));
94    }
95    if (Verify(digestForEVP, {}, true) == 0) {
96        return 0;
97    }
98    return Verify(digest_, {}, true);
99}
100
101int32_t Pkcs7SignedData::Verify(const std::vector<uint8_t> &hash, const std::vector<uint8_t> &sig,
102    bool sigInSignerInfo) const
103{
104    if (hash.empty()) {
105        return -1;
106    }
107    int32_t ret = -1;
108    for (auto &signerInfo : signerInfos_) {
109        ret = Pkcs7SignleSignerVerify(signerInfo, hash, sigInSignerInfo ? signerInfo.digestEncryptData : sig);
110        if (ret == 0) {
111            PKG_LOGI("p7sourceData check success");
112            break;
113        }
114        PKG_LOGI("p7sourceData continue");
115    }
116
117    return ret;
118}
119
120int32_t Pkcs7SignedData::Init(const uint8_t *sourceData, const uint32_t sourceDataLen)
121{
122    Updater::UPDATER_INIT_RECORD;
123    BIO *p7Bio = BIO_new(BIO_s_mem());
124    if (p7Bio == nullptr) {
125        PKG_LOGE("BIO_new error!");
126        UPDATER_LAST_WORD(-1);
127        return -1;
128    }
129    if (static_cast<uint32_t>(BIO_write(p7Bio, sourceData, sourceDataLen)) != sourceDataLen) {
130        PKG_LOGE("BIO_write error!");
131        UPDATER_LAST_WORD(-1);
132        BIO_free(p7Bio);
133        return -1;
134    }
135
136    if (pkcs7_ != nullptr) {
137        PKCS7_free(pkcs7_);
138        pkcs7_ = nullptr;
139    }
140    pkcs7_ = d2i_PKCS7_bio(p7Bio, nullptr);
141    if (pkcs7_ == nullptr) {
142        PKG_LOGE("d2i_PKCS7_bio failed!");
143        BIO_free(p7Bio);
144        UPDATER_LAST_WORD(-1);
145        return -1;
146    }
147
148    int32_t type = OBJ_obj2nid(pkcs7_->type);
149    if (type != NID_pkcs7_signed) {
150        PKG_LOGE("Invalid pkcs7 data type %d", type);
151        BIO_free(p7Bio);
152        UPDATER_LAST_WORD(-1);
153        return -1;
154    }
155
156    BIO_free(p7Bio);
157    if (CertVerify::GetInstance().Init() != 0) {
158        PKG_LOGE("init cert verify fail");
159        UPDATER_LAST_WORD(-1);
160        return -1;
161    }
162    return 0;
163}
164
165/*
166 * tools.ietf.org/html/rfc2315#section-9.1
167 * SignedData ::= SEQUENCE(0x30) {
168 *     INTEGER(0x02)            version Version,
169 *     SET(0x31)                digestAlgorithms DigestAlgorithmIdentifiers,
170 *     SEQUENCE(0x30)           contentInfo ContentInfo,
171 *     CONTET_SPECIFIC[0](0xA0) certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
172 *     CONTET_SPECIFIC[1](0xA1) crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
173 *     SET(0x31)                signerInfos SignerInfos }
174 */
175int32_t Pkcs7SignedData::DoParse()
176{
177    std::vector<uint8_t> contentInfo;
178    int32_t ret = ParseContentInfo(contentInfo);
179    if (ret != 0) {
180        PKG_LOGE("parse pkcs7 contentInfo fail");
181        UPDATER_LAST_WORD(-1);
182        return -1;
183    }
184
185    if (GetInstance().GetDigest(contentInfo, signatureInfo, digest_) != 0) {
186        ret = GetDigestFromContentInfo(contentInfo);
187        if (ret != 0) {
188            PKG_LOGE("invalid pkcs7 contentInfo fail");
189            UPDATER_LAST_WORD(-1);
190            return -1;
191        }
192    }
193
194    return SignerInfosParse();
195}
196
197/*
198 * tools.ietf.org/html/rfc2315#section-7
199 * ContentInfo ::= SEQUENCE(0x30) {
200 *     OBJECT_IDENTIFIER(0x06)  contentType ContentType,
201 *     CONTET_SPECIFIC[0](0xA0) content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
202 *
203 * tools.ietf.org/html/rfc2315#section-8
204 *     Data ::= OCTET STRING
205 */
206int32_t Pkcs7SignedData::ParseContentInfo(std::vector<uint8_t> &digestBlock) const
207{
208    Updater::UPDATER_INIT_RECORD;
209    PKCS7_SIGNED *signData = pkcs7_->d.sign;
210    if (signData == nullptr) {
211        PKG_LOGE("invalid pkcs7 signed data!");
212        UPDATER_LAST_WORD(-1);
213        return -1;
214    }
215
216    PKCS7 *contentInfo = signData->contents;
217    if (contentInfo == nullptr) {
218        PKG_LOGE("pkcs7 content is nullptr!");
219        UPDATER_LAST_WORD(-1);
220        return -1;
221    }
222    if (OBJ_obj2nid(contentInfo->type) != NID_pkcs7_data) {
223        PKG_LOGE("invalid pkcs7 signed data type");
224        UPDATER_LAST_WORD(-1);
225        return -1;
226    }
227
228    if (GetASN1OctetStringData(contentInfo->d.data, digestBlock) != 0) {
229        PKG_LOGE("get pkcs7 contentInfo fail");
230        UPDATER_LAST_WORD(-1);
231        return -1;
232    }
233
234    return 0;
235}
236
237int32_t Pkcs7SignedData::GetDigestFromContentInfo(std::vector<uint8_t> &digestBlock)
238{
239    Updater::UPDATER_INIT_RECORD;
240    if (digestBlock.size() <= sizeof(uint32_t)) {
241        PKG_LOGE("invalid digest block info.");
242        UPDATER_LAST_WORD(-1);
243        return -1;
244    }
245
246    size_t offset = 0;
247    size_t algoId = static_cast<size_t>(ReadLE16(digestBlock.data() + offset));
248    offset += static_cast<size_t>(sizeof(uint16_t));
249    size_t digestLen = static_cast<size_t>(ReadLE16(digestBlock.data() + offset));
250    offset += static_cast<size_t>(sizeof(uint16_t));
251    if ((GetDigestLength(algoId) != digestLen) || ((digestLen + offset) != digestBlock.size())) {
252        PKG_LOGE("invalid digestLen[%zu] and digestBlock len[%zu]", digestLen, digestBlock.size());
253        UPDATER_LAST_WORD(-1);
254        return -1;
255    }
256    digest_.assign(digestBlock.begin() + offset, digestBlock.end());
257    return 0;
258}
259
260Pkcs7SignedData &Pkcs7SignedData::GetInstance()
261{
262    static Pkcs7SignedData checkPackagesInfo;
263    return checkPackagesInfo;
264}
265
266extern "C" __attribute__((constructor)) void RegisterVerifyHelper(void)
267{
268    Pkcs7SignedData::GetInstance().RegisterVerifyHelper(std::make_unique<Pkcs7VerifyHelper>());
269}
270
271void Pkcs7SignedData::RegisterVerifyHelper(std::unique_ptr<VerifyHelper> ptr)
272{
273    helper_ = std::move(ptr);
274}
275
276Pkcs7VerifyHelper::~Pkcs7VerifyHelper()
277{
278    return;
279}
280
281int32_t Pkcs7VerifyHelper::GetDigestFromSubBlocks(std::vector<uint8_t> &digestBlock,
282    HwSigningSigntureInfo &signatureInfo, std::vector<uint8_t> &digest)
283{
284    PKG_LOGE("Pkcs7VerifyHelper in");
285    return -1;
286}
287
288int32_t Pkcs7SignedData::GetDigest(std::vector<uint8_t> &digestBlock,
289    HwSigningSigntureInfo &signatureInfo, std::vector<uint8_t> &digest)
290{
291    if (helper_ == nullptr) {
292        PKG_LOGE("helper_ null error");
293        return -1;
294    }
295    return helper_->GetDigestFromSubBlocks(digestBlock, signatureInfo, digest);
296}
297
298/*
299 * tools.ietf.org/html/rfc2315#section-9.2
300 * SignerInfo ::= SEQUENCE(0x30) {
301 *     INTEGER(0x02)             version Version,
302 *     SEQUENCE(0x30)            issuerAndSerialNumber IssuerAndSerialNumber,
303 *     SEQUENCE(0x30)            digestAlgorithm DigestAlgorithmIdentifier,
304 *     CONTET_SPECIFIC[0](0xA0)  authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
305 *     SEQUENCE(0x30)            digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
306 *     OCTET_STRING(0x30)        encryptedDigest EncryptedDigest,
307 *     CONTET_SPECIFIC[1](0xA1)  unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL }
308 */
309int32_t Pkcs7SignedData::ReadSig(const uint8_t *sourceData, const uint32_t sourceDataLen,
310    std::vector<std::vector<uint8_t>> &sigs)
311{
312    if (sourceData == nullptr || sourceDataLen == 0) {
313        UPDATER_LAST_WORD(PKCS7_INVALID_PARAM_ERR);
314        return PKCS7_INVALID_PARAM_ERR;
315    }
316    if (Init(sourceData, sourceDataLen) != 0) {
317        PKG_LOGE("init pkcs7 data fail");
318        UPDATER_LAST_WORD(PKCS7_INIT_ERR);
319        return PKCS7_INIT_ERR;
320    }
321    STACK_OF(PKCS7_SIGNER_INFO) *p7SignerInfos = PKCS7_get_signer_info(pkcs7_);
322    if (p7SignerInfos == nullptr) {
323        PKG_LOGE("get pkcs7 signers failed!");
324        UPDATER_LAST_WORD(PKCS7_INVALID_VALUE_ERR);
325        return PKCS7_INVALID_VALUE_ERR;
326    }
327    int signerInfoNum = sk_PKCS7_SIGNER_INFO_num(p7SignerInfos);
328    if (signerInfoNum <= 0) {
329        PKG_LOGE("invalid signers info num %d!", signerInfoNum);
330        UPDATER_LAST_WORD(PKCS7_INVALID_VALUE_ERR);
331        return PKCS7_INVALID_VALUE_ERR;
332    }
333    for (int i = 0; i < signerInfoNum; i++) {
334        PKCS7_SIGNER_INFO *p7SiTmp = sk_PKCS7_SIGNER_INFO_value(p7SignerInfos, i);
335        Pkcs7SignerInfo signer;
336        int32_t ret = SignerInfoParse(p7SiTmp, signer);
337        if (ret != 0) {
338            PKG_LOGE("SignerInfo Parse failed!");
339            continue;
340        }
341        sigs.push_back(signer.digestEncryptData);
342    }
343    if (sigs.size() == 0) {
344        PKG_LOGE("no valid sigs!");
345        UPDATER_LAST_WORD(PKCS7_HAS_NO_VALID_SIG_ERR);
346        return PKCS7_HAS_NO_VALID_SIG_ERR;
347    }
348    return PKCS7_SUCCESS;
349}
350
351int32_t Pkcs7SignedData::SignerInfosParse()
352{
353    Updater::UPDATER_INIT_RECORD;
354    STACK_OF(PKCS7_SIGNER_INFO) *p7SignerInfos = PKCS7_get_signer_info(pkcs7_);
355    if (p7SignerInfos == nullptr) {
356        PKG_LOGE("get pkcs7 signers info failed!");
357        UPDATER_LAST_WORD(-1);
358        return -1;
359    }
360
361    int signerInfoNum = sk_PKCS7_SIGNER_INFO_num(p7SignerInfos);
362    if (signerInfoNum <= 0) {
363        PKG_LOGE("invalid signers info num %d!", signerInfoNum);
364        UPDATER_LAST_WORD(-1);
365        return -1;
366    }
367
368    for (int i = 0; i < signerInfoNum; i++) {
369        PKCS7_SIGNER_INFO *p7SiTmp = sk_PKCS7_SIGNER_INFO_value(p7SignerInfos, i);
370        Pkcs7SignerInfo signer;
371        int32_t ret = SignerInfoParse(p7SiTmp, signer);
372        if (ret != 0) {
373            PKG_LOGE("SignerInfoParse failed!");
374            continue;
375        }
376        signerInfos_.push_back(std::move(signer));
377    }
378
379    return 0;
380}
381
382int32_t Pkcs7SignedData::SignerInfoParse(PKCS7_SIGNER_INFO *p7SignerInfo, Pkcs7SignerInfo &signerInfo)
383{
384    if (p7SignerInfo == nullptr) {
385        return -1;
386    }
387    PKCS7_ISSUER_AND_SERIAL *p7IssuerAndSerial = p7SignerInfo->issuer_and_serial;
388    if (p7IssuerAndSerial == nullptr) {
389        PKG_LOGE("signer cert info is nullptr!");
390        UPDATER_LAST_WORD(-1);
391        return -1;
392    }
393    signerInfo.issuerName = p7IssuerAndSerial->issuer;
394    signerInfo.serialNumber = p7IssuerAndSerial->serial;
395
396    int32_t ret = GetX509AlgorithmNid(p7SignerInfo->digest_alg, signerInfo.digestNid);
397    if (ret != 0) {
398        PKG_LOGE("Parse signer info digest_alg failed!");
399        return ret;
400    }
401    ret = GetX509AlgorithmNid(p7SignerInfo->digest_enc_alg, signerInfo.digestEncryptNid);
402    if (ret != 0) {
403        PKG_LOGE("Parse signer info digest_enc_alg failed!");
404        return ret;
405    }
406
407    ret = GetASN1OctetStringData(p7SignerInfo->enc_digest, signerInfo.digestEncryptData);
408    if (ret != 0) {
409        PKG_LOGE("parse signer info enc_digest failed!");
410        return ret;
411    }
412
413    return 0;
414}
415
416int32_t Pkcs7SignedData::Pkcs7SignleSignerVerify(const Pkcs7SignerInfo &signerInfo, const std::vector<uint8_t> &hash,
417    const std::vector<uint8_t> &sig) const
418{
419    if (pkcs7_ == nullptr) {
420        UPDATER_LAST_WORD(-1);
421        return -1;
422    }
423    STACK_OF(X509) *certStack = pkcs7_->d.sign->cert;
424    if (certStack == nullptr) {
425        PKG_LOGE("certStack is empty!");
426        UPDATER_LAST_WORD(-1);
427        return -1;
428    }
429
430    X509 *cert = X509_find_by_issuer_and_serial(certStack, signerInfo.issuerName, signerInfo.serialNumber);
431    if (cert == nullptr) {
432        PKG_LOGE("cert is empty");
433        UPDATER_LAST_WORD(-1);
434        return -1;
435    }
436
437    if (CertVerify::GetInstance().CheckCertChain(certStack, cert) != 0) {
438        PKG_LOGE("public cert check fail");
439        UPDATER_LAST_WORD(-1);
440        return -1;
441    }
442
443    return VerifyDigest(cert, signerInfo, hash, sig);
444}
445
446int32_t Pkcs7SignedData::VerifyDigest(X509 *cert, const Pkcs7SignerInfo &signer, const std::vector<uint8_t> &hash,
447    const std::vector<uint8_t> &sig) const
448{
449    Updater::UPDATER_INIT_RECORD;
450    if (cert == nullptr) {
451        UPDATER_LAST_WORD(-1);
452        return -1;
453    }
454
455    EVP_PKEY *pubKey = X509_get_pubkey(cert);
456    if (pubKey == nullptr) {
457        PKG_LOGE("get pubkey from cert fail");
458        UPDATER_LAST_WORD(-1);
459        return -1;
460    }
461
462    auto ret = VerifyDigestByPubKey(pubKey, signer.digestNid, hash, sig);
463    EVP_PKEY_free(pubKey);
464    return ret;
465}
466} // namespace Hpackage
467