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