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#include "verify_hap_openssl_utils.h"
16#include "signature_tools_log.h"
17#include "openssl/asn1.h"
18#include "openssl/bio.h"
19#include "openssl/crypto.h"
20#include "openssl/err.h"
21#include "openssl/obj_mac.h"
22#include "openssl/objects.h"
23#include "openssl/rsa.h"
24#include "openssl/x509.h"
25#include "openssl/pem.h"
26#include "constant.h"
27#include "signature_info.h"
28
29namespace OHOS {
30namespace SignatureTools {
31using Pkcs7SignerInfoStack = STACK_OF(PKCS7_SIGNER_INFO);
32using X509AttributeStack = STACK_OF(X509_ATTRIBUTE);
33const int32_t VerifyHapOpensslUtils::OPENSSL_PKCS7_VERIFY_SUCCESS = 1;
34const int32_t VerifyHapOpensslUtils::OPENSSL_ERR_MESSAGE_MAX_LEN = 1024;
35/*
36* OPENSSL_READ_DATA_MAX_TIME * OPENSSL_READ_DATA_LEN_EACH_TIME < 2GBytes.
37* make the maximum size of data that can be read each time be 1 KBytes,
38* so the maximum times of read data is 1024 * 1024 * 2 = 2097152;
39*/
40const int32_t VerifyHapOpensslUtils::OPENSSL_READ_DATA_MAX_TIME = 2097152;
41const int32_t VerifyHapOpensslUtils::OPENSSL_READ_DATA_LEN_EACH_TIME = 1024;
42/* Signature algorithm OID for extended PKCS7 */
43const std::string VerifyHapOpensslUtils::PKCS7_EXT_SHAWITHRSA_PSS = PKCS7_EXT_SIGNATURE_OID;
44const int32_t VerifyHapOpensslUtils::MAX_OID_LENGTH = 128;
45
46bool VerifyHapOpensslUtils::ParsePkcs7Package(const unsigned char packageData[],
47                                              uint32_t packageLen, Pkcs7Context& pkcs7Context)
48{
49    if (packageData == nullptr || packageLen == 0) {
50        SIGNATURE_TOOLS_LOGE("invalid input");
51        return false;
52    }
53    pkcs7Context.p7 = d2i_PKCS7(nullptr, &packageData, packageLen);
54    if (!CheckPkcs7SignedDataIsValid(pkcs7Context.p7)) {
55        GetOpensslErrorMessage();
56        SIGNATURE_TOOLS_LOGE("p7 is invalid");
57        return false;
58    }
59    if (!GetContentInfo(pkcs7Context.p7->d.sign->contents, pkcs7Context.content)) {
60        SIGNATURE_TOOLS_LOGE("Get content from pkcs7 failed");
61        return false;
62    }
63    return true;
64}
65
66bool VerifyHapOpensslUtils::GetCertChains(PKCS7* p7, Pkcs7Context& pkcs7Context)
67{
68    if (!CheckPkcs7SignedDataIsValid(p7)) {
69        SIGNATURE_TOOLS_LOGE("p7 is invalid");
70        return false;
71    }
72    CertSign certVisitSign;
73    VerifyCertOpensslUtils::GenerateCertSignFromCertStack(p7->d.sign->cert, certVisitSign);
74    Pkcs7SignerInfoStack* signerInfoStack = PKCS7_get_signer_info(p7);
75    if (signerInfoStack == nullptr) {
76        SIGNATURE_TOOLS_LOGE("get signerInfoStack error");
77        GetOpensslErrorMessage();
78        return false;
79    }
80    int32_t signCount = sk_PKCS7_SIGNER_INFO_num(signerInfoStack);
81    if (signCount <= 0) {
82        SIGNATURE_TOOLS_LOGE("can not find signinfo");
83        return false;
84    }
85    for (int32_t i = 0; i < signCount; i++) {
86        /* get ith signInfo */
87        PKCS7_SIGNER_INFO* signInfo = sk_PKCS7_SIGNER_INFO_value(signerInfoStack, i);
88        if (signInfo == nullptr) {
89            SIGNATURE_TOOLS_LOGE("signInfo %dst is nullptr", i);
90            return false;
91        }
92        /* GET X509 certificate */
93        X509* cert = PKCS7_cert_from_signer_info(p7, signInfo);
94        if (cert == nullptr) {
95            SIGNATURE_TOOLS_LOGE("get cert for %dst signInfo failed", i);
96            return false;
97        }
98        CertChain certChain;
99        pkcs7Context.certChain.push_back(certChain);
100        pkcs7Context.certChain[i].push_back(X509_dup(cert));
101        VerifyCertOpensslUtils::ClearCertVisitSign(certVisitSign);
102        certVisitSign[cert] = true;
103        if (!VerifyCertChain(pkcs7Context.certChain[i], p7, signInfo, pkcs7Context, certVisitSign)) {
104            SIGNATURE_TOOLS_LOGE("verify %dst certchain failed", i);
105            return false;
106        }
107    }
108    return true;
109}
110
111bool VerifyHapOpensslUtils::VerifyCertChain(CertChain& certsChain, PKCS7* p7,
112                                            PKCS7_SIGNER_INFO* signInfo,
113                                            Pkcs7Context& pkcs7Context,
114                                            CertSign& certVisitSign)
115{
116    if (!VerifyCertOpensslUtils::GetCertsChain(certsChain, certVisitSign)) {
117        SIGNATURE_TOOLS_LOGE("get cert chain for signInfo failed");
118        return false;
119    }
120    ASN1_TYPE* signTime = PKCS7_get_signed_attribute(signInfo, NID_pkcs9_signingTime);
121    if (!VerifyCertOpensslUtils::VerifyCertChainPeriodOfValidity(certsChain, signTime)) {
122        SIGNATURE_TOOLS_LOGE("VerifyCertChainPeriodOfValidity for signInfo failed");
123        return false;
124    }
125    return true;
126}
127
128bool VerifyHapOpensslUtils::CheckPkcs7SignedDataIsValid(const PKCS7* p7)
129{
130    if (p7 == nullptr || !PKCS7_type_is_signed(p7) || p7->d.sign == nullptr) {
131        return false;
132    }
133    return true;
134}
135
136bool VerifyHapOpensslUtils::GetCrlStack(PKCS7* p7, STACK_OF(X509_CRL)* x509Crl)
137{
138    if (!CheckPkcs7SignedDataIsValid(p7)) {
139        return false;
140    }
141    x509Crl = p7->d.sign->crl;
142    return true;
143}
144
145bool VerifyHapOpensslUtils::VerifyPkcs7(Pkcs7Context& pkcs7Context)
146{
147    if (!CheckPkcs7SignedDataIsValid(pkcs7Context.p7)) {
148        SIGNATURE_TOOLS_LOGE("p7 type is invalid signed_data_pkcs7");
149        return false;
150    }
151    if (!VerifyPkcs7SignedData(pkcs7Context)) {
152        SIGNATURE_TOOLS_LOGE("verify p7 error");
153        return false;
154    }
155    return true;
156}
157
158bool VerifyHapOpensslUtils::VerifyPkcs7SignedData(Pkcs7Context& pkcs7Context)
159{
160    /* get signed data which was used to be signed */
161    BIO* p7Bio = PKCS7_dataDecode(pkcs7Context.p7, nullptr, nullptr, nullptr);
162    if (p7Bio == nullptr) {
163        SIGNATURE_TOOLS_LOGE("get p7bio error");
164        GetOpensslErrorMessage();
165        return false;
166    }
167    char buf[OPENSSL_READ_DATA_LEN_EACH_TIME] = { 0 };
168    int32_t readLen = BIO_read(p7Bio, buf, sizeof(buf));
169    int32_t readTime = 0;
170    while ((readLen > 0) && (++readTime < OPENSSL_READ_DATA_MAX_TIME)) {
171        readLen = BIO_read(p7Bio, buf, sizeof(buf));
172    }
173    Pkcs7SignerInfoStack* signerInfoStack = PKCS7_get_signer_info(pkcs7Context.p7);
174    if (signerInfoStack == nullptr) {
175        SIGNATURE_TOOLS_LOGE("get signerInfoStack error");
176        BIO_free_all(p7Bio);
177        GetOpensslErrorMessage();
178        return false;
179    }
180    /* get the num of signInfo */
181    int32_t signCount = sk_PKCS7_SIGNER_INFO_num(signerInfoStack);
182    if (signCount <= 0) {
183        SIGNATURE_TOOLS_LOGE("can not find signinfo");
184        BIO_free_all(p7Bio);
185        return false;
186    }
187    for (int32_t i = 0; i < signCount; i++) {
188        if (!VerifySignInfo(signerInfoStack, p7Bio, i, pkcs7Context)) {
189            SIGNATURE_TOOLS_LOGE("Verify %dst signInfo failed", i);
190            BIO_free_all(p7Bio);
191            return false;
192        }
193    }
194    BIO_free_all(p7Bio);
195    return true;
196}
197
198bool VerifyHapOpensslUtils::VerifySignInfo(STACK_OF(PKCS7_SIGNER_INFO)* signerInfoStack,
199                                           BIO* p7Bio, int32_t signInfoNum, Pkcs7Context& pkcs7Context)
200{
201    if (signerInfoStack == nullptr || p7Bio == nullptr) {
202        SIGNATURE_TOOLS_LOGE("invalid input");
203        return false;
204    }
205    /* get signInfo */
206    PKCS7_SIGNER_INFO* signInfo = sk_PKCS7_SIGNER_INFO_value(signerInfoStack, signInfoNum);
207    if (signInfo == nullptr) {
208        SIGNATURE_TOOLS_LOGE("signInfo %dst is nullptr", signInfoNum);
209        return false;
210    }
211    /* GET X509 certificate */
212    X509* cert = pkcs7Context.certChain[signInfoNum][0];
213
214    if (PKCS7_signatureVerify(p7Bio, pkcs7Context.p7, signInfo, cert) <= 0) {
215        SIGNATURE_TOOLS_LOGE("PKCS7_signatureVerify %dst signInfo failed", signInfoNum);
216        GetOpensslErrorMessage();
217        return false;
218    }
219
220    return true;
221}
222
223bool VerifyHapOpensslUtils::GetContentInfo(const PKCS7* p7ContentInfo, ByteBuffer& content)
224{
225    if ((p7ContentInfo == nullptr) || !PKCS7_type_is_data(p7ContentInfo)) {
226        SIGNATURE_TOOLS_LOGE("p7ContentInfo is invalid");
227        return false;
228    }
229    ASN1_OCTET_STRING* strContentInfo = p7ContentInfo->d.data;
230    if (strContentInfo == nullptr) {
231        SIGNATURE_TOOLS_LOGE("strContentInfo is invalid");
232        return false;
233    }
234    int32_t strContentInfoLen = strContentInfo->length;
235    unsigned char* strContentInfoData = strContentInfo->data;
236    if (strContentInfoData == nullptr || strContentInfoLen <= 0) {
237        SIGNATURE_TOOLS_LOGE("ASN1_OCTET_STRING is invalid");
238        return false;
239    }
240    content.SetCapacity(strContentInfoLen);
241    content.PutData(0, reinterpret_cast<char*>(strContentInfoData), strContentInfoLen);
242    SIGNATURE_TOOLS_LOGD("strContentInfoLen: %d", strContentInfoLen);
243    return true;
244}
245
246void VerifyHapOpensslUtils::GetOpensslErrorMessage()
247{
248    unsigned long retOpenssl;
249    char errOpenssl[OPENSSL_ERR_MESSAGE_MAX_LEN];
250    while ((retOpenssl = ERR_get_error()) != 0) {
251        ERR_error_string(retOpenssl, errOpenssl);
252        SIGNATURE_TOOLS_LOGE("openssl err: %lu, message: %s", retOpenssl, errOpenssl);
253    }
254}
255} // namespace SignatureTools
256} // namespace OHOS