1/*
2 * Copyright (c) 2024-2024 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 "signature_tools_log.h"
17#include "signature_tools_errno.h"
18#include "verify_hap_openssl_utils.h"
19#include "signer.h"
20#include "securec.h"
21#include "constant.h"
22#include "pkcs7_data.h"
23
24namespace OHOS {
25namespace SignatureTools {
26
27static constexpr int BUFFER_SIZE = 4096;
28
29static int PKCS7AddAttribute(PKCS7* p7, const std::vector<PKCS7Attr>& attrs)
30{
31    STACK_OF(PKCS7_SIGNER_INFO)* signerInfos = PKCS7_get_signer_info(p7);
32    if (signerInfos == NULL || sk_PKCS7_SIGNER_INFO_num(signerInfos) != 1) {
33        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
34                            "signer info count not equal 1,pkcs7 add customize attribute failed");
35        return INVALIDPARAM_ERROR;
36    }
37    PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(signerInfos, 0);
38    for (PKCS7Attr attr : attrs) {
39        if (PKCS7_add_signed_attribute(signerInfo, attr.nid, attr.atrtype, attr.value) != 1) {
40            if (attr.atrtype == V_ASN1_UTF8STRING)
41                ASN1_STRING_free(reinterpret_cast<ASN1_STRING*>(attr.value));
42            PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
43                                "pkcs7 add customize attribute failed");
44            return RET_FAILED;
45        }
46    }
47    return RET_OK;
48}
49
50static int I2dPkcs7Str(PKCS7* p7, std::string& ret)
51{
52    /* raw data exported in pkcs7 */
53    unsigned char* out = NULL;
54    int outSize = 0;
55    /* Deserialize to obtain the p7b byte stream */
56    outSize = i2d_PKCS7(p7, &out);
57    if (out == NULL || outSize <= 0) {
58        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
59                            "pkcs7 is invalid");
60        return INVALIDPARAM_ERROR;
61    }
62    ret.clear();
63    ret.resize(outSize);
64    std::copy(out, out + outSize, &ret[0]);
65    OPENSSL_free(out);
66    return RET_OK;
67}
68
69static int SetSignerInfoSignAlgor(PKCS7_SIGNER_INFO* info)
70{
71    int signNid = 0;
72    int hashNid = 0;
73    X509_ALGOR* dig;
74    X509_ALGOR* sig;
75    PKCS7_SIGNER_INFO_get0_algs(info, NULL, &dig, &sig);
76    if (dig == NULL || dig->algorithm == NULL ||
77        (hashNid = OBJ_obj2nid(dig->algorithm)) == NID_undef ||
78        !OBJ_find_sigid_by_algs(&signNid, hashNid, NID_X9_62_id_ecPublicKey) ||
79        X509_ALGOR_set0(sig, OBJ_nid2obj(signNid), V_ASN1_UNDEF, 0) != 1) {
80        return 0;
81    }
82    return 1;
83}
84
85static int VerifySignature(PKCS7* pkcs7, BIO* p7bio)
86{
87    /* signature information */
88    STACK_OF(PKCS7_SIGNER_INFO)* skSignerInfo = NULL;
89    /* signature count */
90    int signerCount = 0;
91    /* verify signature value */
92    skSignerInfo = PKCS7_get_signer_info(pkcs7);
93    signerCount = sk_PKCS7_SIGNER_INFO_num(skSignerInfo);
94    for (int i = 0; i < signerCount; i++) {
95        PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(skSignerInfo, i);
96        X509* sigCert = PKCS7_cert_from_signer_info(pkcs7, signerInfo);
97        if (PKCS7_signatureVerify(p7bio, pkcs7, signerInfo, sigCert) != 1) {
98            PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "signature value verify failed");
99            return VERIFY_ERROR;
100        }
101    }
102    return RET_OK;
103}
104
105PKCS7Data::PKCS7Data(int flags) : m_p7(nullptr), m_flags(flags)
106{
107}
108
109PKCS7Data::~PKCS7Data()
110{
111    PKCS7_free(m_p7);
112    m_p7 = NULL;
113}
114
115int PKCS7Data::Sign(const std::string& content, const std::shared_ptr<Signer>& signer,
116                    const std::string& sigAlg, std::string& ret, std::vector<PKCS7Attr> attrs)
117{
118    int result = RET_OK;
119    if ((result = InitPkcs7(content, signer, sigAlg, attrs)) < 0) {
120        goto err;
121    }
122
123    /* serialization */
124    if ((result = I2dPkcs7Str(m_p7, ret)) < 0) {
125        goto err;
126    }
127    /* release resources */
128err:
129    if (result < 0) {
130        SIGNATURE_TOOLS_LOGE("sign failed");
131    }
132    return result;
133}
134
135int PKCS7Data::Parse(const std::string& p7bBytes)
136{
137    const unsigned char* data = reinterpret_cast<const unsigned char*>(&p7bBytes[0]);
138    return Parse(&data, static_cast<long>(p7bBytes.size()));
139}
140int PKCS7Data::Parse(const std::vector<int8_t>& p7bBytes)
141{
142    const unsigned char* data = reinterpret_cast<const unsigned char*>(&p7bBytes[0]);
143    return Parse(&data, static_cast<long>(p7bBytes.size()));
144}
145int PKCS7Data::Parse(const unsigned char** in, long len)
146{
147    /* If p7 has been initialized, it will be released */
148    if (m_p7) {
149        PKCS7_free(m_p7);
150        m_p7 = NULL;
151    }
152    /* Deserialize */
153    m_p7 = d2i_PKCS7(NULL, in, len);
154    if (m_p7 == NULL) {
155        PrintErrorNumberMsg("PARSE_ERROR", PARSE_ERROR, "invalid p7b data, parse failed");
156        return PARSE_ERROR;
157    }
158    return RET_OK;
159}
160
161int PKCS7Data::Verify(const std::string& content) const
162{
163    if (VerifySign(content) < 0) {
164        PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "signature verify failed");
165        return VERIFY_ERROR;
166    }
167    if (VerifyCertChain() < 0) {
168        PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "cert Chain verify failed");
169        PrintCertChainSub(m_p7->d.sign->cert);
170        return VERIFY_ERROR;
171    }
172    return RET_OK;
173}
174
175int PKCS7Data::GetContent(std::string& originalRawData) const
176{
177    BIO* oriBio = PKCS7_dataDecode(m_p7, NULL, NULL, NULL);
178    if (oriBio == NULL) {
179        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "pkcs7 get content data failed!");
180        return INVALIDPARAM_ERROR;
181    }
182    char buf[BUFFER_SIZE]{0};
183    size_t readBytes = 0;
184    while (BIO_read_ex(oriBio, buf, sizeof(buf), &readBytes) == 1) {
185        originalRawData.append(buf, readBytes);
186    }
187    BIO_free_all(oriBio);
188    return RET_OK;
189}
190
191static void PKCS7AddCrls(PKCS7* p7, STACK_OF(X509_CRL)* crls)
192{
193    for (int i = 0; i < sk_X509_CRL_num(crls); i++) {
194        PKCS7_add_crl(p7, sk_X509_CRL_value(crls, i));
195    }
196}
197
198int PKCS7Data::InitPkcs7(const std::string& content, const std::shared_ptr<Signer>& signer,
199                         const std::string& sigAlg, std::vector<PKCS7Attr> attrs)
200{
201    STACK_OF(X509)* certs = NULL;
202    /* hash algorithm */
203    const EVP_MD* md = NULL;
204    /* entity certificate */
205    X509* cert = NULL;
206    int result = RET_OK;
207    if (signer == NULL) {
208        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "signer is NULL , sign failed");
209        result = INVALIDPARAM_ERROR;
210        goto err;
211    }
212    m_signer = signer;
213    m_sigAlg = sigAlg;
214    certs = signer->GetCertificates();
215    if (SortX509Stack(certs) < 0) {
216        result = RET_FAILED;
217        goto err;
218    }
219    if (sigAlg == SIGN_ALG_SHA384) {
220        md = EVP_sha384();
221    } else if (sigAlg == SIGN_ALG_SHA256) {
222        md = EVP_sha256();
223    } else {
224        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
225                            sigAlg + "is invalid sigAlg, please use SHA256withECDSA/SHA384withECDSA, sign failed");
226        result = INVALIDPARAM_ERROR;
227        goto err;
228    }
229    /* Extract the entity certificate from the certificate chain */
230    cert = sk_X509_delete(certs, 0);
231    m_p7 = Pkcs7Sign(cert, certs, md, content, m_flags, attrs);
232    if (m_p7 == NULL) {
233        PrintErrorNumberMsg("INVALIDPARAM_ERROR", SIGN_ERROR, "p7 is NULL, pkcs7 sign failed");
234        result = SIGN_ERROR;
235        goto err;
236    }
237    PKCS7AddCrls(m_p7, signer->GetCrls());
238
239err:
240    sk_X509_pop_free(certs, X509_free);
241    X509_free(cert);
242    return result;
243}
244
245void PKCS7Data::PrintCertChainSub(const STACK_OF(X509)* certs)
246{
247    if (certs == NULL)
248        return;
249    SIGNATURE_TOOLS_LOGI("certChainSubject:");
250    int certNum = sk_X509_num(certs);
251    SIGNATURE_TOOLS_LOGI("certNum%s", std::to_string(certNum).c_str());
252    for (int i = 0; i < certNum; i++) {
253        SIGNATURE_TOOLS_LOGI("certificate %s", std::to_string(i).c_str());
254        std::string sub;
255        VerifyCertOpensslUtils::GetSubjectFromX509(sk_X509_value(certs, i), sub);
256        SIGNATURE_TOOLS_LOGI("%s", sub.c_str());
257    }
258}
259
260std::string PKCS7Data::GetASN1Time(const ASN1_TIME* tm)
261{
262    if (tm == NULL) {
263        return "";
264    }
265    /* Convert the ASN1_TIME structure to a standard tm structure. */
266    struct tm time;
267    ASN1_TIME_to_tm(tm, &time);
268    /* Convert to local time(considering the time zone) */
269    time_t t = mktime(&time);
270    if (t < 0) {
271        return "";
272    }
273    struct tm* localTime = localtime(&t);
274    if (localTime == nullptr) {
275        return "";
276    }
277    /* Print local time */
278    char buf[128] = {0};
279    if (sprintf_s(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d",
280                  localTime->tm_year + YEAR1900, localTime->tm_mon + 1, localTime->tm_mday,
281                  localTime->tm_hour, localTime->tm_min, localTime->tm_sec) == -1) {
282        return "";
283    }
284    return std::string(buf, strlen(buf));
285}
286
287bool PKCS7Data::X509NameCompare(const X509* cert, const X509* issuerCert)
288{
289    if (cert == nullptr || issuerCert == nullptr) {
290        PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR,
291                            "input cert is NULL");
292        return false;
293    }
294    X509_NAME* aName = X509_get_issuer_name(cert);
295    X509_NAME* bName = X509_get_subject_name(issuerCert);
296    if (X509_NAME_cmp(aName, bName) != 0) {
297        PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR,
298                            "cert issuer name is not equal to its issuer\'s  name");
299        return false;
300    }
301    return true;
302}
303
304int PKCS7Data::CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime,
305                                          const ASN1_TIME* notBefore, const ASN1_TIME* notAfter)
306{
307    if (notBefore == nullptr || notBefore->data == nullptr || notAfter == nullptr || notAfter->data == nullptr) {
308        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
309                            "invalid period, check signtime failed please use valid period to to check signtime");
310        return INVALIDPARAM_ERROR;
311    }
312    if (signTime == nullptr || signTime->value.asn1_string == nullptr ||
313        signTime->value.asn1_string->data == nullptr) {
314        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "signtime is NULL");
315        return INVALIDPARAM_ERROR;
316    }
317    ASN1_TIME* tm = ASN1_TIME_new();
318    ASN1_TIME_set_string(tm, (reinterpret_cast<const char*>(signTime->value.asn1_string->data)));
319    if (ASN1_TIME_compare(notBefore, signTime->value.asn1_string) > 0 ||
320        ASN1_TIME_compare(notAfter, signTime->value.asn1_string) < 0) {
321        SIGNATURE_TOOLS_LOGE("sign time invalid, signTime: %s, notBefore: %s, "
322                             "notAfter: %s", GetASN1Time(tm).c_str(),
323                             GetASN1Time(notBefore).c_str(), GetASN1Time(notAfter).c_str());
324        ASN1_TIME_free(tm);
325        return RET_FAILED;
326    }
327    ASN1_TIME_free(tm);
328    return RET_OK;
329}
330
331static X509* FindSubCertThenEraseItFromSets(X509* cert, std::unordered_set<X509*>& x509Sets)
332{
333    X509* ret = NULL;
334    for (X509* c : x509Sets) {
335        X509_NAME* name1 = X509_get_subject_name(cert);
336        X509_NAME* name2 = X509_get_issuer_name(c);
337        if (X509_NAME_cmp(name1, name2) == 0) {
338            x509Sets.erase(c);
339            ret = c;
340            break;
341        }
342    }
343    return ret;
344}
345
346int PKCS7Data::SortX509Stack(STACK_OF(X509)* certs)
347{
348    std::unordered_set<X509*> x509Sets;
349    std::list<X509*>certChain;
350    X509* tmp = NULL;
351    int result = RET_FAILED;
352
353    if (sk_X509_num(certs) < MIN_CERTS_NUM) {
354        PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "cert of certchain count less than two!");
355        goto err;
356    }
357    for (int i = 0; i < sk_X509_num(certs); i++) {
358        x509Sets.insert(sk_X509_value(certs, i));
359    }
360    if (sk_X509_num(certs) != static_cast<int>(x509Sets.size())) {
361        PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "sort x509 certchain failed!");
362        goto err;
363    }
364    for (X509* cert : x509Sets) {
365        if (X509_name_cmp(X509_get_subject_name(cert), X509_get_issuer_name(cert)) == 0) {
366            tmp = cert;
367            x509Sets.erase(cert);
368            break;
369        }
370    }
371    if (tmp == NULL) {
372        PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR,
373                            "can't find root cert from certchain ,sort x509 certchain failed!");
374        goto err;
375    }
376    certChain.push_front(tmp);
377    while ((tmp = FindSubCertThenEraseItFromSets(tmp, x509Sets))) {
378        certChain.push_front(tmp);
379    }
380    if (x509Sets.size() != 0) {
381        PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR,
382                            "certchain contain invalid cert, sort x509 certchain failed!");
383        goto err;
384    }
385    while (sk_X509_num(certs)) {
386        sk_X509_pop(certs);
387    }
388    for (X509* cert : certChain) {
389        sk_X509_push(certs, cert);
390    }
391    result = RET_OK;
392err:
393    return result;
394}
395
396int PKCS7Data::VerifySign(const std::string& content)const
397{
398    BIO* inBio = NULL;
399    if ((m_flags & PKCS7_DETACHED)) {
400        inBio = BIO_new_mem_buf(reinterpret_cast<const void*>(content.c_str()),
401                                static_cast<int>(content.size()));
402        if (inBio == NULL) {
403            PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR,
404                                "new mem buf error!,pkcs7 verify signature failed");
405            return VERIFY_ERROR;
406        }
407    }
408    if (PKCS7_verify(m_p7, NULL, NULL, inBio, NULL, m_flags) != 1) {
409        PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "pkcs7 verify signature failed");
410        BIO_free(inBio);
411        return VERIFY_ERROR;
412    }
413    BIO_free(inBio);
414    return RET_OK;
415}
416
417int PKCS7Data::VerifyCertChain()const
418{
419    /* Validate the certificate chain */
420    STACK_OF(PKCS7_SIGNER_INFO)* skSignerInfo = PKCS7_get_signer_info(m_p7);
421    int signerCount = sk_PKCS7_SIGNER_INFO_num(skSignerInfo);
422    int c = signerCount;
423    STACK_OF(X509)* certs = NULL;
424    int result = RET_FAILED;
425    /* Original certificate chain */
426    STACK_OF(X509)* certChain = m_p7->d.sign->cert;
427    /* Copy of the certificate chain, with the entity certificate removed later */
428    certs = sk_X509_dup(certChain);
429    if (SortX509Stack(certs) < 0) {
430        SIGNATURE_TOOLS_LOGE("sort x509 stack failed, verify certchain failed");
431        goto err;
432    }
433    /* Retrieve the certificate chain without the entity certificate */
434    while (c--) {
435        sk_X509_delete(certs, 0);
436    }
437    for (int i = 0; i < signerCount; i++) {
438        PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(skSignerInfo, i);
439        if ((result = VerifySignerInfoCertchain(m_p7, signerInfo, certs, certChain)) < 0) {
440            SIGNATURE_TOOLS_LOGE("verify certchain failed");
441            goto err;
442        }
443    }
444    result = RET_OK;
445err:
446    sk_X509_free(certs);
447    return result;
448}
449
450int PKCS7Data::CheckSginerInfoSignTimeInCertChainValidPeriod(PKCS7_SIGNER_INFO* signerInfo,
451                                                             STACK_OF(X509)* certs) const
452{
453    if (signerInfo == NULL || certs == NULL) {
454        PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "input is NULL, check signtime invalid");
455        return INVALIDPARAM_ERROR;
456    }
457    ASN1_TYPE* signTime = PKCS7_get_signed_attribute(signerInfo, NID_pkcs9_signingTime);
458    for (int i = 0; i < sk_X509_num(certs); i++) {
459        X509* cert = sk_X509_value(certs, i);
460        const ASN1_TIME* notBefore = X509_get0_notBefore(cert);
461        const ASN1_TIME* notAfter = X509_get0_notAfter(cert);
462        if (CheckSignTimeInValidPeriod(signTime, notBefore, notAfter) < 0) {
463            SIGNATURE_TOOLS_LOGE("pkcs7 sign time check failed");
464            return INVALIDPARAM_ERROR;
465        }
466    }
467    return RET_OK;
468}
469
470int PKCS7Data::VerifySignerInfoCertchain(PKCS7* pkcs7, PKCS7_SIGNER_INFO* signerInfo,
471                                         STACK_OF(X509)* certs, STACK_OF(X509)* certChain)const
472{
473    X509* sigCert = PKCS7_cert_from_signer_info(pkcs7, signerInfo);
474    int j = 0;
475    /* Trace back through the subject information and validate the signature value of each certificate */
476    if (!X509NameCompare(sigCert, sk_X509_value(certs, 0))) {
477        SIGNATURE_TOOLS_LOGE("entity name compare not equal, verify failed");
478        return VERIFY_ERROR;
479    }
480    /* verify entity certificate signature value */
481    if (!VerifyCertOpensslUtils::CertVerify(sigCert, sk_X509_value(certs, 0))) {
482        SIGNATURE_TOOLS_LOGE("entity cert signature verify failed");
483        return VERIFY_ERROR;
484    }
485    for (; j + 1 < sk_X509_num(certs); j++) {
486        if (!X509NameCompare(sk_X509_value(certs, j), sk_X509_value(certs, j + 1))) {
487            SIGNATURE_TOOLS_LOGE("sub cert name compare not equal, verify failed");
488            return VERIFY_ERROR;
489        }
490        /* Verify the signature value of the intermediate certificate */
491        if (!VerifyCertOpensslUtils::CertVerify(sk_X509_value(certs, j), sk_X509_value(certs, j + 1))) {
492            SIGNATURE_TOOLS_LOGE("sub cert signature verify failed");
493            return VERIFY_ERROR;
494        }
495    }
496    if (!X509NameCompare(sk_X509_value(certs, j), sk_X509_value(certs, j))) {
497        SIGNATURE_TOOLS_LOGE("root cert name compare not equal, verify failed");
498        return VERIFY_ERROR;
499    }
500    /* Verify the signature value of the root certificate */
501    if (!VerifyCertOpensslUtils::CertVerify(sk_X509_value(certs, j), sk_X509_value(certs, j))) {
502        SIGNATURE_TOOLS_LOGE("root cert signature verify failed");
503        return VERIFY_ERROR;
504    }
505    /* Verify that the signature time in the signature information is within the validity period of
506    the certificate chain (entity certificate will be verified in PKCS7_verify) */
507    if (CheckSginerInfoSignTimeInCertChainValidPeriod(signerInfo, certChain) < 0) {
508        SIGNATURE_TOOLS_LOGE("sign time is invalid,verify failed");
509        return VERIFY_ERROR;
510    }
511    return RET_OK;
512}
513
514int PKCS7Data::Pkcs7SignAttr(PKCS7_SIGNER_INFO* info)
515{
516    unsigned char* attrBuf = NULL;
517    int attrLen;
518
519    std::string data;
520    std::string signature;
521    unsigned char* sigRet = NULL;
522    int sigLen = 0;
523
524    attrLen = ASN1_item_i2d((ASN1_VALUE*)info->auth_attr, &attrBuf,
525                            ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
526    if (!attrBuf) {
527        OPENSSL_free(attrBuf);
528        return 0;
529    }
530
531    data.assign(reinterpret_cast<const char*>(attrBuf), attrLen);
532    signature = m_signer->GetSignature(data, m_sigAlg);
533    if (signature.empty()) {
534        OPENSSL_free(attrBuf);
535        return 0;
536    }
537    sigLen = signature.size();
538    sigRet = reinterpret_cast<unsigned char*>(OPENSSL_malloc(sigLen));
539    if (sigRet == NULL) {
540        OPENSSL_free(attrBuf);
541        return 0;
542    }
543    std::copy(&signature[0], &signature[0] + signature.size(), sigRet);
544    ASN1_STRING_set0(info->enc_digest, sigRet, sigLen);
545    OPENSSL_free(attrBuf);
546    return 1;
547}
548
549static ASN1_OCTET_STRING* PKCS7GetASN1Content(PKCS7* pkcs7)
550{
551    if (PKCS7_type_is_data(pkcs7)) {
552        return pkcs7->d.data;
553    }
554    return NULL;
555}
556
557int PKCS7Data::Pkcs7AddTimeDigestAndSignAttr(PKCS7_SIGNER_INFO* info, EVP_MD_CTX* hashCtx)
558{
559    unsigned char hashData[EVP_MAX_MD_SIZE];
560    unsigned int hashLen;
561
562    /* add signing time */
563    if (!PKCS7_get_signed_attribute(info, NID_pkcs9_signingTime)) {
564        if (!PKCS7_add0_attrib_signing_time(info, NULL)) {
565            return 0;
566        }
567    }
568
569    /* add digest */
570    if (!EVP_DigestFinal_ex(hashCtx, hashData, &hashLen)) {
571        return 0;
572    }
573    if (!PKCS7_add1_attrib_digest(info, hashData, hashLen)) {
574        return 0;
575    }
576
577    /* sign the attributes */
578    if (!Pkcs7SignAttr(info)) {
579        return 0;
580    }
581
582    return 1;
583}
584
585static BIO* PKCS7SearchDigest(EVP_MD_CTX** pHash, BIO* io, int numberID)
586{
587    while ((io = BIO_find_type(io, BIO_TYPE_MD))) {
588        BIO_get_md_ctx(io, pHash);
589        if (*pHash == NULL) {
590            return NULL;
591        }
592        if (EVP_MD_CTX_type(*pHash) == numberID) {
593            return io;
594        }
595        io = BIO_next(io);
596    }
597    return NULL;
598}
599
600static int PKCS7DataFinalCheck(PKCS7* pkcs7, BIO* bio,
601                               STACK_OF(PKCS7_SIGNER_INFO)** psk, ASN1_OCTET_STRING** pos)
602{
603    int id = 0;
604
605    if (pkcs7 == NULL || pkcs7->d.ptr == NULL) {
606        return 0;
607    }
608
609    id = OBJ_obj2nid(pkcs7->type);
610    pkcs7->state = PKCS7_S_HEADER;
611
612    if (id == NID_pkcs7_signed) {
613        *psk = pkcs7->d.sign->signer_info;
614        *pos = PKCS7GetASN1Content(pkcs7->d.sign->contents);
615        if (PKCS7_type_is_data(pkcs7->d.sign->contents) && pkcs7->detached) {
616            ASN1_OCTET_STRING_free(*pos);
617            *pos = NULL;
618            pkcs7->d.sign->contents->d.data = NULL;
619        }
620        return 1;
621    }
622    return 0;
623}
624
625int PKCS7Data::Pkcs7DataFinalSignAttr(STACK_OF(PKCS7_SIGNER_INFO)* infoStack, BIO* bio)
626{
627    EVP_MD_CTX* hashCtx = NULL;
628    STACK_OF(X509_ATTRIBUTE)* attrStack = NULL;
629    BIO* ioTmp = NULL;
630    int result = 0;
631    EVP_MD_CTX* ctxTmp = EVP_MD_CTX_new();
632    if (ctxTmp == NULL) {
633        return 0;
634    }
635
636    if (infoStack == NULL) {
637        goto err;
638    }
639    for (int i = 0; i < sk_PKCS7_SIGNER_INFO_num(infoStack); i++) {
640        PKCS7_SIGNER_INFO* info = sk_PKCS7_SIGNER_INFO_value(infoStack, i);
641
642        int numberID = OBJ_obj2nid(info->digest_alg->algorithm);
643
644        ioTmp = bio;
645
646        ioTmp = PKCS7SearchDigest(&hashCtx, ioTmp, numberID);
647
648        if (ioTmp == NULL || !EVP_MD_CTX_copy_ex(ctxTmp, hashCtx)) {
649            goto err;
650        }
651
652        attrStack = info->auth_attr;
653
654        if (sk_X509_ATTRIBUTE_num(attrStack) > 0) {
655            if (!Pkcs7AddTimeDigestAndSignAttr(info, ctxTmp)) {
656                goto err;
657            }
658        } else {
659            goto err;
660        }
661    }
662    result = 1;
663err:
664    EVP_MD_CTX_free(ctxTmp);
665    return result;
666}
667
668static int PKCS7DataFinalSetContent(PKCS7* pkcs7, ASN1_OCTET_STRING* asn1Str, BIO* io)
669{
670    BIO* ioTmp = NULL;
671    if (!PKCS7_is_detached(pkcs7)) {
672        if (asn1Str == NULL) {
673            return 0;
674        }
675        if (!(asn1Str->flags & ASN1_STRING_FLAG_NDEF)) {
676            char* contentData;
677            long contentLen;
678            ioTmp = BIO_find_type(io, BIO_TYPE_MEM);
679            if (ioTmp == NULL) {
680                return 0;
681            }
682            contentLen = BIO_get_mem_data(ioTmp, &contentData);
683
684            BIO_set_flags(ioTmp, BIO_FLAGS_MEM_RDONLY);
685            BIO_set_mem_eof_return(ioTmp, 0);
686            ASN1_STRING_set0(asn1Str, (unsigned char*)contentData, contentLen);
687        }
688    }
689    return 1;
690}
691int PKCS7Data::Pkcs7DataFinal(PKCS7* pkcs7, BIO* io)
692{
693    STACK_OF(PKCS7_SIGNER_INFO)* infoStack = NULL;
694    ASN1_OCTET_STRING* os = NULL;
695
696    if (!PKCS7DataFinalCheck(pkcs7, io, &infoStack, &os) ||
697        !Pkcs7DataFinalSignAttr(infoStack, io) ||
698        !PKCS7DataFinalSetContent(pkcs7, os, io)) {
699        return 0;
700    }
701    return 1;
702}
703
704int PKCS7Data::Pkcs7Final(PKCS7* pkcs7, const std::string& content, int flags)
705{
706    BIO* p7bio;
707    int result = 0;
708
709    if ((p7bio = PKCS7_dataInit(pkcs7, NULL)) == NULL) {
710        return 0;
711    }
712
713    if (BIO_write(p7bio, content.c_str(), static_cast<int>(content.size())) <= 0) {
714        SIGNATURE_TOOLS_LOGE("add json data to pkcs7 failed");
715        goto err;
716    }
717
718    (void)BIO_flush(p7bio);
719
720    if (!Pkcs7DataFinal(pkcs7, p7bio)) {
721        goto err;
722    }
723    /* Verify the signature value */
724    if (VerifySignature(pkcs7, p7bio) < 0) {
725        goto err;
726    }
727    result = 1;
728
729err:
730    BIO_free_all(p7bio);
731    return result;
732}
733
734static int Pkcs7SetSignerInfo(PKCS7_SIGNER_INFO* info, X509* cert, const EVP_MD* hash)
735{
736    if (!ASN1_INTEGER_set(info->version, 1) ||
737        !X509_NAME_set(&info->issuer_and_serial->issuer, X509_get_issuer_name(cert))) {
738        return 0;
739    }
740
741    ASN1_INTEGER_free(info->issuer_and_serial->serial);
742    if (!(info->issuer_and_serial->serial =
743          ASN1_INTEGER_dup(X509_get_serialNumber(cert)))) {
744        return 0;
745    }
746
747    X509_ALGOR_set0(info->digest_alg, OBJ_nid2obj(EVP_MD_type(hash)),
748                    V_ASN1_NULL, NULL);
749
750    if (!SetSignerInfoSignAlgor(info)) {
751        return 0;
752    }
753    return 1;
754}
755
756static PKCS7_SIGNER_INFO* Pkcs7AddSignature(PKCS7* pkcs7, X509* cert, const EVP_MD* hash)
757{
758    PKCS7_SIGNER_INFO* info = NULL;
759
760    if (!(info = PKCS7_SIGNER_INFO_new()) ||
761        !Pkcs7SetSignerInfo(info, cert, hash) ||
762        !PKCS7_add_signer(pkcs7, info)) {
763        goto err;
764    }
765    return info;
766err:
767    PKCS7_SIGNER_INFO_free(info);
768    return NULL;
769}
770
771
772static PKCS7_SIGNER_INFO* Pkcs7AddSignerInfo(PKCS7* pkcs7, X509* entityCert, const EVP_MD* hash, int flags)
773{
774    PKCS7_SIGNER_INFO* info = NULL;
775    if ((info = Pkcs7AddSignature(pkcs7, entityCert, hash)) == NULL) {
776        return NULL;
777    }
778    if (!PKCS7_add_certificate(pkcs7, entityCert)) {
779        return NULL;
780    }
781    if (!PKCS7_add_attrib_content_type(info, NULL)) {
782        return NULL;
783    }
784    return info;
785}
786
787PKCS7* PKCS7Data::Pkcs7Sign(X509* entityCert, STACK_OF(X509)* certs, const EVP_MD* hash,
788                            const std::string& content, int flags, const std::vector<PKCS7Attr>& attrs)
789{
790    PKCS7* pkcs7;
791
792    if (!(pkcs7 = PKCS7_new()) ||
793        !PKCS7_set_type(pkcs7, NID_pkcs7_signed) ||
794        !PKCS7_content_new(pkcs7, NID_pkcs7_data) ||
795        !Pkcs7AddSignerInfo(pkcs7, entityCert, hash, flags) ||
796        (PKCS7AddAttribute(pkcs7, attrs) < 0)) {
797        PKCS7_free(pkcs7);
798        return NULL;
799    }
800
801    if (!(flags & PKCS7_NOCERTS)) {
802        for (int i = 0; i < sk_X509_num(certs); i++) {
803            if (!PKCS7_add_certificate(pkcs7, sk_X509_value(certs, i))) {
804                PKCS7_free(pkcs7);
805                return NULL;
806            }
807        }
808    }
809
810    if (flags & PKCS7_DETACHED) {
811        PKCS7_set_detached(pkcs7, 1);
812    }
813
814    if (Pkcs7Final(pkcs7, content, flags)) {
815        return pkcs7;
816    }
817    PKCS7_free(pkcs7);
818    return NULL;
819}
820} // namespace SignatureTools
821} // namespace OHOS