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
26namespace OHOS {
27namespace SignatureTools {
28
29const uint32_t VerifyCertOpensslUtils::MIN_CERT_CHAIN_LEN_NEED_VERIFY_CRL = 2;
30const int32_t VerifyCertOpensslUtils::OPENSSL_READ_CRL_MAX_TIME = 1048576; // 1024 * 1024
31const int32_t VerifyCertOpensslUtils::OPENSSL_READ_CRL_LEN_EACH_TIME = 1024;
32const int32_t VerifyCertOpensslUtils::BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA = 4;
33const int32_t VerifyCertOpensslUtils::BASE64_ENCODE_PACKET_LEN = 3;
34
35void 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
49void VerifyCertOpensslUtils::ClearCertVisitSign(CertSign& certVisitSign)
50{
51    for (auto& certPair : certVisitSign) {
52        certPair.second = false;
53    }
54}
55
56bool 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
88X509* 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
110bool 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
125bool 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
146bool VerifyCertOpensslUtils::CheckAsn1TimeIsValid(const ASN1_TIME* asn1Time)
147{
148    if (asn1Time == nullptr || asn1Time->data == nullptr) {
149        return false;
150    }
151    return true;
152}
153
154bool 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
163bool 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
189bool 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
214X509_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
233bool 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
241bool 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
253bool 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
265std::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
282void 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