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