1/*
2 * Copyright (c) 2023-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 "pkcs7_data.h"
17
18#include <string>
19#include <openssl/asn1.h>
20#include <securec.h>
21
22#include "log.h"
23#include "openssl_utils.h"
24
25
26namespace OHOS {
27namespace Security {
28namespace CodeSign {
29PKCS7Data::PKCS7Data(const EVP_MD *md, X509 *cert)
30    : cert_(cert), md_(md)
31{
32}
33
34PKCS7Data::~PKCS7Data()
35{
36    cert_ = nullptr;
37    md_ = nullptr;
38    if (p7_ != nullptr) {
39        // signerinfo would be freed with p7
40        PKCS7_free(p7_);
41        p7_ = nullptr;
42    }
43}
44
45bool PKCS7Data::InitPKCS7Data(const std::vector<ByteBuffer> &certChain)
46{
47    uint32_t flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR | PKCS7_PARTIAL;
48    STACK_OF(X509) *certs = nullptr;
49    if (certChain.empty()) {
50        flags = flags | PKCS7_NOCERTS;
51    } else {
52        certs = MakeStackOfCerts(certChain);
53    }
54    p7_ = PKCS7_sign(nullptr, nullptr, certs, nullptr, static_cast<int>(flags));
55    if (p7_ == nullptr) {
56        sk_X509_pop_free(certs, X509_free);
57        return false;
58    }
59    return true;
60}
61
62bool PKCS7Data::GetPKCS7Data(ByteBuffer &pkcs7Data)
63{
64    BIO *bio = BIO_new(BIO_s_mem());
65    bool ret = false;
66    do {
67        if (bio == nullptr) {
68            break;
69        }
70        if (!i2d_PKCS7_bio(bio, p7_)) {
71            ERR_LOG_WITH_OPEN_SSL_MSG("Encode pkcs7 data failed.");
72            break;
73        }
74        uint8_t *tmp = nullptr;
75        long tmpSize = BIO_get_mem_data(bio, &tmp);
76        if ((tmpSize < 0) || (tmpSize > UINT32_MAX)) {
77            break;
78        }
79        if (!pkcs7Data.CopyFrom(tmp, static_cast<uint32_t>(tmpSize))) {
80            break;
81        }
82        ret = true;
83    } while (0);
84    BIO_free(bio);
85    return ret;
86}
87
88bool PKCS7Data::AddSignerInfo(PKCS7_SIGNER_INFO *p7i)
89{
90    if (!PKCS7_add_signer(p7_, p7i)) {
91        PKCS7_SIGNER_INFO_free(p7i);
92        LOG_ERROR("Add signer to pkcs7 failed");
93        return false;
94    }
95    return true;
96}
97}
98}
99}