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 
29 namespace OHOS {
30 namespace SignatureTools {
31 using Pkcs7SignerInfoStack = STACK_OF(PKCS7_SIGNER_INFO);
32 using X509AttributeStack = STACK_OF(X509_ATTRIBUTE);
33 const int32_t VerifyHapOpensslUtils::OPENSSL_PKCS7_VERIFY_SUCCESS = 1;
34 const 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 */
40 const int32_t VerifyHapOpensslUtils::OPENSSL_READ_DATA_MAX_TIME = 2097152;
41 const int32_t VerifyHapOpensslUtils::OPENSSL_READ_DATA_LEN_EACH_TIME = 1024;
42 /* Signature algorithm OID for extended PKCS7 */
43 const std::string VerifyHapOpensslUtils::PKCS7_EXT_SHAWITHRSA_PSS = PKCS7_EXT_SIGNATURE_OID;
44 const int32_t VerifyHapOpensslUtils::MAX_OID_LENGTH = 128;
45 
ParsePkcs7Package(const unsigned char packageData[], uint32_t packageLen, Pkcs7Context& pkcs7Context)46 bool 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 
GetCertChains(PKCS7* p7, Pkcs7Context& pkcs7Context)66 bool 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 
VerifyCertChain(CertChain& certsChain, PKCS7* p7, PKCS7_SIGNER_INFO* signInfo, Pkcs7Context& pkcs7Context, CertSign& certVisitSign)111 bool 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 
CheckPkcs7SignedDataIsValid(const PKCS7* p7)128 bool 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 
GetCrlStack(PKCS7* p7, STACK_OF(X509_CRL)* x509Crl)136 bool 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 
VerifyPkcs7(Pkcs7Context& pkcs7Context)145 bool 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 
VerifyPkcs7SignedData(Pkcs7Context& pkcs7Context)158 bool 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 
198 bool 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 
GetContentInfo(const PKCS7* p7ContentInfo, ByteBuffer& content)223 bool 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 
GetOpensslErrorMessage()246 void 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