1 /*
2 * Copyright (c) 2024-2024 Huawei Device Co., Ltd.verify_cert_openssl_utils.h
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_cert_openssl_utils.h"
16 #include <cinttypes>
17 #include <cmath>
18 #include <fstream>
19
20 #include "openssl/pem.h"
21 #include "openssl/sha.h"
22 #include "signature_tools_log.h"
23 #include "securec.h"
24 #include "verify_hap_openssl_utils.h"
25
26 namespace OHOS {
27 namespace SignatureTools {
28
29 const uint32_t VerifyCertOpensslUtils::MIN_CERT_CHAIN_LEN_NEED_VERIFY_CRL = 2;
30 const int32_t VerifyCertOpensslUtils::OPENSSL_READ_CRL_MAX_TIME = 1048576; // 1024 * 1024
31 const int32_t VerifyCertOpensslUtils::OPENSSL_READ_CRL_LEN_EACH_TIME = 1024;
32 const int32_t VerifyCertOpensslUtils::BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA = 4;
33 const int32_t VerifyCertOpensslUtils::BASE64_ENCODE_PACKET_LEN = 3;
34
35 void VerifyCertOpensslUtils::GenerateCertSignFromCertStack(STACK_OF(X509)* stackCerts, CertSign& certVisitSign)
36 {
37 if (stackCerts == nullptr) {
38 return;
39 }
40 for (int32_t i = 0; i < sk_X509_num(stackCerts); i++) {
41 X509* x509Cert = sk_X509_value(stackCerts, i);
42 if (x509Cert == nullptr) {
43 continue;
44 }
45 certVisitSign[x509Cert] = false;
46 }
47 }
48
ClearCertVisitSign(CertSign& certVisitSign)49 void VerifyCertOpensslUtils::ClearCertVisitSign(CertSign& certVisitSign)
50 {
51 for (auto& certPair : certVisitSign) {
52 certPair.second = false;
53 }
54 }
55
GetCertsChain(CertChain& certsChain, CertSign& certVisitSign)56 bool VerifyCertOpensslUtils::GetCertsChain(CertChain& certsChain, CertSign& certVisitSign)
57 {
58 if (certsChain.empty() || certVisitSign.empty()) {
59 SIGNATURE_TOOLS_LOGE("input is invalid");
60 return false;
61 }
62 X509* issuerCert;
63 X509* cert = certsChain[0];
64 while ((issuerCert = FindCertOfIssuer(cert, certVisitSign)) != nullptr) {
65 certsChain.push_back(X509_dup(issuerCert));
66 certVisitSign[issuerCert] = true;
67 cert = issuerCert;
68 }
69 if (CertVerify(cert, cert) == false) {
70 SIGNATURE_TOOLS_LOGE("CertVerify is invalid");
71 return false;
72 }
73 {
74 X509_NAME* aName = X509_get_issuer_name(cert);
75 X509_NAME* bName = X509_get_subject_name(cert);
76 if (aName == NULL || bName == NULL) {
77 SIGNATURE_TOOLS_LOGE("NULL X509_NAME");
78 return false;
79 }
80 if (X509_NAME_cmp(aName, bName) != 0) {
81 SIGNATURE_TOOLS_LOGE("compare error!");
82 return false;
83 }
84 return true;
85 }
86 }
87
FindCertOfIssuer(X509* cert, CertSign& certVisitSign)88 X509* VerifyCertOpensslUtils::FindCertOfIssuer(X509* cert, CertSign& certVisitSign)
89 {
90 if (cert == nullptr) {
91 SIGNATURE_TOOLS_LOGE("input is invalid");
92 return nullptr;
93 }
94 X509_NAME* signCertIssuerName = X509_get_issuer_name(cert);
95 for (auto certPair : certVisitSign) {
96 if (certPair.second) {
97 continue;
98 }
99 X509* issuerCert = certPair.first;
100 X509_NAME* issuerCertSubjectName = X509_get_subject_name(issuerCert);
101 /* verify sign and issuer */
102 if (X509NameCompare(issuerCertSubjectName, signCertIssuerName) &&
103 CertVerify(cert, issuerCert)) {
104 return issuerCert;
105 }
106 }
107 return nullptr;
108 }
109
CertVerify(X509* cert, const X509* issuerCert)110 bool VerifyCertOpensslUtils::CertVerify(X509* cert, const X509* issuerCert)
111 {
112 if (cert == nullptr) {
113 SIGNATURE_TOOLS_LOGE("input is invalid");
114 return false;
115 }
116 EVP_PKEY* caPublicKey = X509_get0_pubkey(issuerCert);
117 if (caPublicKey == nullptr) {
118 VerifyHapOpensslUtils::GetOpensslErrorMessage();
119 SIGNATURE_TOOLS_LOGE("get pubkey from caCert failed");
120 return false;
121 }
122 return X509_verify(cert, caPublicKey) > 0;
123 }
124
VerifyCertChainPeriodOfValidity(CertChain& certsChain, const ASN1_TYPE* signTime)125 bool VerifyCertOpensslUtils::VerifyCertChainPeriodOfValidity(CertChain& certsChain,
126 const ASN1_TYPE* signTime)
127 {
128 if (certsChain.empty()) {
129 return false;
130 }
131 for (uint32_t i = 0; i < certsChain.size() - 1; i++) {
132 if (certsChain[i] == nullptr) {
133 SIGNATURE_TOOLS_LOGE("%dst cert is nullptr", i);
134 return false;
135 }
136 const ASN1_TIME* notBefore = X509_get0_notBefore(certsChain[i]);
137 const ASN1_TIME* notAfter = X509_get0_notAfter(certsChain[i]);
138 if (!CheckSignTimeInValidPeriod(signTime, notBefore, notAfter)) {
139 SIGNATURE_TOOLS_LOGE("%dst cert is not in period of validity", i);
140 return false;
141 }
142 }
143 return true;
144 }
145
CheckAsn1TimeIsValid(const ASN1_TIME* asn1Time)146 bool VerifyCertOpensslUtils::CheckAsn1TimeIsValid(const ASN1_TIME* asn1Time)
147 {
148 if (asn1Time == nullptr || asn1Time->data == nullptr) {
149 return false;
150 }
151 return true;
152 }
153
CheckAsn1TypeIsValid(const ASN1_TYPE* asn1Type)154 bool VerifyCertOpensslUtils::CheckAsn1TypeIsValid(const ASN1_TYPE* asn1Type)
155 {
156 if (asn1Type == nullptr || asn1Type->value.asn1_string == nullptr ||
157 asn1Type->value.asn1_string->data == nullptr) {
158 return false;
159 }
160 return true;
161 }
162
CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime, const ASN1_TIME* notBefore, const ASN1_TIME* notAfter)163 bool VerifyCertOpensslUtils::CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime,
164 const ASN1_TIME* notBefore,
165 const ASN1_TIME* notAfter)
166 {
167 if (!CheckAsn1TimeIsValid(notBefore) || !CheckAsn1TimeIsValid(notAfter)) {
168 SIGNATURE_TOOLS_LOGE("no valid period");
169 return false;
170 }
171 if (!CheckAsn1TypeIsValid(signTime)) {
172 SIGNATURE_TOOLS_LOGE("signTime is invalid");
173 return false;
174 }
175 if (ASN1_TIME_compare(notBefore, signTime->value.asn1_string) > 0 ||
176 ASN1_TIME_compare(notAfter, signTime->value.asn1_string) < 0) {
177 SIGNATURE_TOOLS_LOGE("Out of valid period, signTime: %s, "
178 "notBefore:%s, notAfter : %s",
179 signTime->value.asn1_string->data, notBefore->data, notAfter->data);
180 return false;
181 }
182 SIGNATURE_TOOLS_LOGD("signTime type: %d, data: %s, "
183 "notBefore:%s, notAfter : %s",
184 signTime->type, signTime->value.asn1_string->data,
185 notBefore->data, notAfter->data);
186 return true;
187 }
188
VerifyCrl(CertChain& certsChain, STACK_OF(X509_CRL)* crls, Pkcs7Context& pkcs7Context)189 bool VerifyCertOpensslUtils::VerifyCrl(CertChain& certsChain, STACK_OF(X509_CRL)* crls,
190 Pkcs7Context& pkcs7Context)
191 {
192 if (certsChain.empty()) {
193 SIGNATURE_TOOLS_LOGE("cert chain is null");
194 return false;
195 }
196 /* get signed cert's issuer and then it will be used to find local crl */
197 if (!GetIssuerFromX509(certsChain[0], pkcs7Context.certIssuer)) {
198 SIGNATURE_TOOLS_LOGE("get issuer of signed cert failed");
199 return false;
200 }
201 X509_CRL* targetCrl = GetCrlBySignedCertIssuer(crls, certsChain[0]);
202 /* crl is optional */
203 if (targetCrl != nullptr && certsChain.size() >= MIN_CERT_CHAIN_LEN_NEED_VERIFY_CRL) {
204 /* if it include crl, it must be verified by ca cert */
205 if (X509_CRL_verify(targetCrl, X509_get0_pubkey(certsChain[1])) <= 0) {
206 VerifyHapOpensslUtils::GetOpensslErrorMessage();
207 SIGNATURE_TOOLS_LOGE("verify crlInPackage failed");
208 return false;
209 }
210 }
211 return true;
212 }
213
214 X509_CRL* VerifyCertOpensslUtils::GetCrlBySignedCertIssuer(STACK_OF(X509_CRL)* crls, const X509* cert)
215 {
216 if (crls == nullptr || cert == nullptr) {
217 return nullptr;
218 }
219 X509_NAME* certIssuerName = X509_get_issuer_name(cert);
220 for (int32_t i = 0; i < sk_X509_CRL_num(crls); i++) {
221 X509_CRL* x509Crl = sk_X509_CRL_value(crls, i);
222 if (x509Crl == nullptr) {
223 continue;
224 }
225 X509_NAME* crlIssuer = X509_CRL_get_issuer(x509Crl);
226 if (X509NameCompare(crlIssuer, certIssuerName)) {
227 return x509Crl;
228 }
229 }
230 return nullptr;
231 }
232
X509NameCompare(const X509_NAME* a, const X509_NAME* b)233 bool VerifyCertOpensslUtils::X509NameCompare(const X509_NAME* a, const X509_NAME* b)
234 {
235 if (a == nullptr || b == nullptr) {
236 return false;
237 }
238 return X509_NAME_cmp(a, b) == 0;
239 }
240
GetSubjectFromX509(const X509* cert, std::string& subject)241 bool VerifyCertOpensslUtils::GetSubjectFromX509(const X509* cert, std::string& subject)
242 {
243 if (cert == nullptr) {
244 SIGNATURE_TOOLS_LOGE("cert is nullptr");
245 return false;
246 }
247 X509_NAME* name = X509_get_subject_name(cert);
248 subject = GetDnToString(name);
249 SIGNATURE_TOOLS_LOGD("subject = %s", subject.c_str());
250 return true;
251 }
252
GetIssuerFromX509(const X509* cert, std::string& issuer)253 bool VerifyCertOpensslUtils::GetIssuerFromX509(const X509* cert, std::string& issuer)
254 {
255 if (cert == nullptr) {
256 SIGNATURE_TOOLS_LOGE("cert is nullptr");
257 return false;
258 }
259 X509_NAME* name = X509_get_issuer_name(cert);
260 issuer = GetDnToString(name);
261 SIGNATURE_TOOLS_LOGD("cert issuer = %s", issuer.c_str());
262 return true;
263 }
264
GetDnToString(X509_NAME* x509Name)265 std::string VerifyCertOpensslUtils::GetDnToString(X509_NAME* x509Name)
266 {
267 if (x509Name == nullptr) {
268 return "";
269 }
270 std::string countryNameString;
271 GetTextFromX509Name(x509Name, NID_countryName, countryNameString);
272 std::string organizationName;
273 GetTextFromX509Name(x509Name, NID_organizationName, organizationName);
274 std::string organizationalUnitName;
275 GetTextFromX509Name(x509Name, NID_organizationalUnitName, organizationalUnitName);
276 std::string commonName;
277 GetTextFromX509Name(x509Name, NID_commonName, commonName);
278 return "C=" + countryNameString + ", O=" + organizationName + ", OU=" + organizationalUnitName +
279 ", CN=" + commonName;
280 }
281
GetTextFromX509Name(X509_NAME* name, int32_t nId, std::string& text)282 void VerifyCertOpensslUtils::GetTextFromX509Name(X509_NAME* name, int32_t nId, std::string& text)
283 {
284 int32_t textLen = X509_NAME_get_text_by_NID(name, nId, nullptr, 0);
285 if (textLen <= 0) {
286 return;
287 }
288 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(textLen + 1);
289 if (X509_NAME_get_text_by_NID(name, nId, buffer.get(), textLen + 1) != textLen) {
290 return;
291 }
292 text = std::string(buffer.get());
293 }
294 } // namespace SignatureTools
295 } // namespace OHOS