1 /*
2  * Copyright (c) 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 
16 #include "huks_attest_verifier.h"
17 
18 #include <openssl/asn1.h>
19 #include <openssl/obj_mac.h>
20 #include <openssl/objects.h>
21 #include <openssl/ossl_typ.h>
22 #include <openssl/pem.h>
23 #include <openssl/safestack.h>
24 #include <openssl/x509.h>
25 #include <openssl/x509v3.h>
26 #include <openssl/x509_vfy.h>
27 #include <string>
28 #include <vector>
29 
30 #include "byte_buffer.h"
31 #include "cert_utils.h"
32 #include "log.h"
33 #include "openssl_utils.h"
34 
35 namespace OHOS {
36 namespace Security {
37 namespace CodeSign {
38 static const std::string ATTEST_ROOT_CA_PATH = "/system/etc/security/trusted_attest_root_ca.cer";
39 static const std::vector<std::string> ATTESTTATION_EXTENSION = {
40     "1.3.6.1.4.1.2011.2.376.1.3",
41     "AttestationInfo",
42     "Attestation Information"
43 };
44 
45 static const std::vector<std::string> SA_INFO_EXTENSION = {
46     "1.3.6.1.4.1.2011.2.376.2.1.3.1",
47     "SA INFO",
48     "SystemAbiliy Information"
49 };
50 
51 static const std::vector<std::string> CHALLENGE_EXTENSION = {
52     "1.3.6.1.4.1.2011.2.376.2.1.4",
53     "Challenge",
54     "Challenge"
55 };
56 
57 static const std::string LOCAL_CODE_SIGN_SA_NAME = "local_code_sign";
58 
59 static constexpr uint32_t MIN_VECTOR_SIZE = 3;
60 static bool g_verifierInited = false;
61 static int g_saNid = 0;
62 static int g_challengeNid = 0;
63 static int g_attestationNid = 0;
64 #ifdef VERIFY_KEY_ATTEST_CERTCHAIN
65 static constexpr uint32_t COMMON_NAME_BUF_SIZE = 256;
66 #endif
67 
GetNidFromDefination(const std::vector<std::string> & defVector)68 static inline int GetNidFromDefination(const std::vector<std::string> &defVector)
69 {
70     if (defVector.size() < MIN_VECTOR_SIZE) {
71         return NID_undef;
72     }
73     return CreateNIDFromOID(defVector[0], defVector[1], defVector[defVector.size() - 1]);
74 }
75 
InitVerifier()76 static void InitVerifier()
77 {
78     if (g_verifierInited) {
79         return;
80     }
81     g_saNid = GetNidFromDefination(SA_INFO_EXTENSION);
82     g_challengeNid = GetNidFromDefination(CHALLENGE_EXTENSION);
83     g_attestationNid = GetNidFromDefination(ATTESTTATION_EXTENSION);
84     LOG_DEBUG("g_saNid = %{public}d, g_challengeNid = %{public}d, g_attestationNid = %{public}d",
85         g_saNid, g_challengeNid, g_attestationNid);
86     g_verifierInited = true;
87 }
88 
AddCAToStore(X509_STORE * store)89 static bool AddCAToStore(X509_STORE *store)
90 {
91     FILE *fp = fopen(ATTEST_ROOT_CA_PATH.c_str(), "r");
92     if (fp == nullptr) {
93         LOG_ERROR("Open file failed.");
94         return false;
95     }
96 
97     X509 *caCert = nullptr;
98     do {
99         caCert = PEM_read_X509(fp, nullptr, nullptr, nullptr);
100         if (caCert == nullptr) {
101             break;
102         }
103         if (X509_STORE_add_cert(store, caCert) <= 0) {
104             LOG_ERROR("add cert to X509 store failed");
105             GetOpensslErrorMessage();
106         }
107         LOG_INFO("Add root CA successfully");
108     } while (caCert != nullptr);
109     (void) fclose(fp);
110     return true;
111 }
112 
VerifyIssurCert(X509 * cert,STACK_OF (X509)* chain)113 static bool VerifyIssurCert(X509 *cert, STACK_OF(X509) *chain)
114 {
115     X509_STORE *store = X509_STORE_new();
116     if (store == nullptr) {
117         return false;
118     }
119 
120     bool ret = false;
121     X509_STORE_CTX *storeCtx = nullptr;
122 
123     do {
124         if (!AddCAToStore(store)) {
125             break;
126         }
127         storeCtx = X509_STORE_CTX_new();
128         if (storeCtx == nullptr) {
129             break;
130         }
131 
132         if (!X509_STORE_CTX_init(storeCtx, store, cert, chain)) {
133             LOG_ERROR("init X509_STORE_CTX failed.");
134             break;
135         }
136         X509_STORE_CTX_set_purpose(storeCtx, X509_PURPOSE_ANY);
137         // because user can set date of device, validation skip time check for fool-proofing
138         X509_STORE_CTX_set_flags(storeCtx, X509_V_FLAG_NO_CHECK_TIME);
139         int index = X509_verify_cert(storeCtx);
140         if (index <= 0) {
141             index = X509_STORE_CTX_get_error(storeCtx);
142             LOG_ERROR("Verify cert failed, msg = %{public}s", X509_verify_cert_error_string(index));
143             break;
144         }
145         ret = true;
146     } while (0);
147     if (!ret) {
148         GetOpensslErrorMessage();
149     }
150     X509_STORE_CTX_free(storeCtx);
151     X509_STORE_free(store);
152     return ret;
153 }
154 
VerifySigningCert(X509 * signCert,X509 * issuerCert)155 static bool VerifySigningCert(X509 *signCert, X509 *issuerCert)
156 {
157     EVP_PKEY *key = X509_get0_pubkey(issuerCert);
158     if (key == nullptr) {
159         LOG_ERROR("get pub key failed.");
160         return false;
161     }
162     if (X509_verify(signCert, key) <= 0) {
163         LOG_ERROR("verify signing cert failed.");
164         GetOpensslErrorMessage();
165         return false;
166     }
167     return true;
168 }
169 
CompareTargetValue(int nid,uint8_t * data,int size,const ByteBuffer & challenge)170 static bool CompareTargetValue(int nid, uint8_t *data, int size, const ByteBuffer &challenge)
171 {
172     if (nid == g_saNid) {
173         std::string str(reinterpret_cast<char *>(data), size);
174         LOG_INFO("compare with proc = %{private}s", str.c_str());
175         return str.find(LOCAL_CODE_SIGN_SA_NAME) != std::string::npos;
176     } else if (nid == g_challengeNid) {
177         LOG_INFO("compare with challenge");
178         return (static_cast<uint32_t>(size) == challenge.GetSize())
179                     && (memcmp(data, challenge.GetBuffer(), size) == 0);
180     }
181     return true;
182 }
183 
ParseASN1Sequence(uint8_t * data,int size,const ByteBuffer & challenge)184 static bool ParseASN1Sequence(uint8_t *data, int size, const ByteBuffer &challenge)
185 {
186     STACK_OF(ASN1_TYPE) *types = d2i_ASN1_SEQUENCE_ANY(
187         nullptr, const_cast<const uint8_t **>(&data), size);
188     if (types == nullptr) {
189         return false;
190     }
191 
192     int num = sk_ASN1_TYPE_num(types);
193     int curNid = -1;
194     bool ret = true;
195     for (int i = 0; i < num; i++) {
196         ASN1_TYPE *type = sk_ASN1_TYPE_value(types, i);
197         if (type->type == V_ASN1_SEQUENCE) {
198             ret = ParseASN1Sequence(type->value.sequence->data, type->value.sequence->length,
199                 challenge);
200         } else if (type->type == V_ASN1_OBJECT) {
201             ASN1_OBJECT *obj = type->value.object;
202             curNid = OBJ_obj2nid(obj);
203         } else if (type->type == V_ASN1_OCTET_STRING) {
204             ASN1_OCTET_STRING *value = type->value.octet_string;
205             ret = CompareTargetValue(curNid, value->data, value->length, challenge);
206         }
207         if (!ret) {
208             LOG_ERROR("Value is unexpected");
209             break;
210         }
211     }
212     return ret;
213 }
214 
VerifyExtension(X509 * cert,const ByteBuffer & challenge)215 static bool VerifyExtension(X509 *cert, const ByteBuffer &challenge)
216 {
217     if (challenge.GetBuffer() == nullptr) {
218         return false;
219     }
220 
221     const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert);
222     int num;
223 
224     if ((num = sk_X509_EXTENSION_num(exts)) <= 0) {
225         LOG_ERROR("Get extension failed.");
226         return false;
227     }
228 
229     InitVerifier();
230     for (int i = 0; i < num; i++) {
231         X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
232         ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
233         if (obj == nullptr) {
234             LOG_ERROR("Get ans1 object faild");
235             continue;
236         }
237         int curNid = OBJ_obj2nid(obj);
238         if (g_attestationNid == curNid) {
239             const ASN1_OCTET_STRING *extData = X509_EXTENSION_get_data(ext);
240             if (!ParseASN1Sequence(extData->data, extData->length, challenge)) {
241                 LOG_INFO("extension verify failed.");
242                 return false;
243             }
244         }
245     }
246     return true;
247 }
248 
249 #ifdef CODE_SIGNATURE_DEBUGGABLE
ShowCertInfo(const std::vector<ByteBuffer> & certChainBuffer,const ByteBuffer & issuerBuffer,const ByteBuffer & certBuffer)250 static void ShowCertInfo(const std::vector<ByteBuffer> &certChainBuffer,
251     const ByteBuffer &issuerBuffer, const ByteBuffer &certBuffer)
252 {
253     std::string pem;
254     LOG_INFO("Dump cert chain");
255     for (auto cert: certChainBuffer) {
256         if (ConvertCertToPEMString(cert, pem)) {
257             LOG_INFO("%{private}s", pem.c_str());
258         }
259     }
260     LOG_INFO("Dump issuer cert");
261     if (ConvertCertToPEMString(issuerBuffer, pem)) {
262         LOG_INFO("%{private}s", pem.c_str());
263     }
264     LOG_INFO("Dump signing cert");
265     if (ConvertCertToPEMString(certBuffer, pem)) {
266         LOG_INFO("%{private}s", pem.c_str());
267     }
268 }
269 #endif
270 
VerifyCertAndExtension(X509 * signCert,X509 * issuerCert,const ByteBuffer & challenge)271 bool VerifyCertAndExtension(X509 *signCert, X509 *issuerCert, const ByteBuffer &challenge)
272 {
273     if (!VerifySigningCert(signCert, issuerCert)) {
274         return false;
275     }
276     LOG_DEBUG("Verify sign cert pass");
277 
278     if (!VerifyExtension(signCert, challenge)) {
279         LOG_ERROR("Verify extension failed.");
280         return false;
281     }
282     LOG_INFO("Verify success");
283     return true;
284 }
285 
VerifyIntermediateCASubject(const std::vector<ByteBuffer> & certChainBuffer)286 static bool VerifyIntermediateCASubject(const std::vector<ByteBuffer> &certChainBuffer)
287 {
288 #ifndef VERIFY_KEY_ATTEST_CERTCHAIN
289     LOG_INFO("Skip intermediate CA subject verification.");
290     return true;
291 #else
292     if (certChainBuffer.empty()) {
293         LOG_ERROR("The vector is empty");
294         return false;
295     }
296 
297     auto certBuffer = certChainBuffer.back();
298     X509 *cert = LoadCertFromBuffer(certBuffer.GetBuffer(), certBuffer.GetSize());
299     if (cert == nullptr) {
300         LOG_ERROR("Load intermediate CA cert failed.");
301         return false;
302     }
303 
304     bool ret = false;
305     do {
306         X509_NAME *subjectName = X509_get_subject_name(cert);
307         if (subjectName == nullptr) {
308             LOG_ERROR("Get subject name failed.");
309             break;
310         }
311 
312         char commonNameBuf[COMMON_NAME_BUF_SIZE] = {0};
313         int len = X509_NAME_get_text_by_NID(subjectName, NID_commonName, commonNameBuf, COMMON_NAME_BUF_SIZE);
314         if (len <= 0) {
315             LOG_ERROR("Get common name failed.");
316             break;
317         }
318 
319         if (!strstr(commonNameBuf, "Huawei CBG Mobile Equipment CA") &&
320             !strstr(commonNameBuf, "Huawei CBG Equipment S2 CA") &&
321             !strstr(commonNameBuf, "Huawei CBG Equipment S3 CA")) {
322             LOG_ERROR("Intermediate CA common name not matched, common name:%{private}s", commonNameBuf);
323             break;
324         }
325 
326         ret = true;
327     } while (0);
328 
329     X509_free(cert);
330     return ret;
331 #endif
332 }
333 
GetVerifiedCert(const ByteBuffer & buffer,const ByteBuffer & challenge,ByteBuffer & certBuffer)334 bool GetVerifiedCert(const ByteBuffer &buffer, const ByteBuffer &challenge, ByteBuffer &certBuffer)
335 {
336     std::vector<ByteBuffer> certChainBuffer;
337     ByteBuffer issuerBuffer;
338     if (!GetCertChainFormBuffer(buffer, certBuffer, issuerBuffer, certChainBuffer)) {
339         return false;
340     }
341     X509 *issuerCert = LoadCertFromBuffer(issuerBuffer.GetBuffer(), issuerBuffer.GetSize());
342     if (issuerCert == nullptr) {
343         LOG_ERROR("Load issuerCert cert failed.");
344         return false;
345     }
346     bool ret = false;
347     X509 *signCert = nullptr;
348     STACK_OF(X509 *) certChain = nullptr;
349     do {
350         certChain = MakeStackOfCerts(certChainBuffer);
351         if (certChain == nullptr) {
352             LOG_ERROR("Load cert chain failed.");
353             break;
354         }
355         if (!VerifyIntermediateCASubject(certChainBuffer)) {
356             LOG_ERROR("Failed to verify the Intermediate CA subject.");
357             break;
358         }
359         if (!VerifyIssurCert(issuerCert, certChain)) {
360             LOG_ERROR("Verify issuer cert not pass.");
361             break;
362         }
363         LOG_DEBUG("Verify issuer cert pass");
364         signCert = LoadCertFromBuffer(certBuffer.GetBuffer(), certBuffer.GetSize());
365         if (signCert == nullptr) {
366             LOG_ERROR("Load signing cert failed.");
367             break;
368         }
369         if (!VerifyCertAndExtension(signCert, issuerCert, challenge)) {
370             break;
371         }
372         ret = true;
373     } while (0);
374     X509_free(signCert);
375     X509_free(issuerCert);
376     sk_X509_pop_free(certChain, X509_free);
377 #ifdef CODE_SIGNATURE_DEBUGGABLE
378     if (!ret) {
379         ShowCertInfo(certChainBuffer, issuerBuffer, certBuffer);
380     }
381 #endif
382     LOG_INFO("verify finished, ret = %{public}d.", ret);
383     return ret;
384 }
385 }
386 }
387 }
388