• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "dslm_ohos_verify.h"
17 
18 #include <stdbool.h>
19 #include <string.h>
20 
21 #include "securec.h"
22 
23 #include "dslm_credential_utils.h"
24 #include "external_interface_adapter.h"
25 #include "utils_hexstring.h"
26 #include "utils_json.h"
27 #include "utils_log.h"
28 #include "utils_mem.h"
29 
30 #define UDID_STRING_LENGTH 65
31 
32 #define CRED_MAX_LEVEL_TYPE_SMALL 2
33 #define CRED_MAX_LEVEL_TYPE_STANDARD 5
34 
35 #define CRED_VALUE_TYPE_DEBUG "debug"
36 #define CRED_VALUE_TYPE_RELEASE "release"
37 
38 #define DSLM_CRED_STR_LEN_MAX 4096
39 
40 struct NonceOfCertChain {
41     uint64_t challenge;
42     uint8_t *pbkInfoList;
43     uint32_t pbkInfoListLen;
44 };
45 
CheckCredInfo(const struct DeviceIdentify * device,DslmCredInfo * info,uint32_t maxLevel)46 static int32_t CheckCredInfo(const struct DeviceIdentify *device, DslmCredInfo *info, uint32_t maxLevel)
47 {
48     SECURITY_LOG_DEBUG("start");
49     if (info->credLevel > maxLevel) {
50         SECURITY_LOG_ERROR("cred level = %{public}d check error", info->credLevel);
51         info->credLevel = 0;
52         return ERR_CHECK_CRED_INFO;
53     }
54     if (strlen(info->udid) == 0) {
55         SECURITY_LOG_DEBUG("current cred has no udid, skip CheckCredInfo");
56         return SUCCESS;
57     }
58     if (strncmp(info->releaseType, CRED_VALUE_TYPE_DEBUG, strlen(CRED_VALUE_TYPE_DEBUG)) == 0) {
59         if (memcmp((char *)device->identity, info->udid, strlen(info->udid)) == 0) {
60             return SUCCESS;
61         }
62         return ERR_CHECK_CRED_INFO;
63     }
64     SECURITY_LOG_DEBUG("success");
65     return SUCCESS;
66 }
67 
ParseNonceOfCertChain(const char * jsonBuffer,struct NonceOfCertChain * nonce)68 static int32_t ParseNonceOfCertChain(const char *jsonBuffer, struct NonceOfCertChain *nonce)
69 {
70     DslmJsonHandle json = DslmCreateJson(jsonBuffer);
71     if (json == NULL) {
72         return ERR_INVALID_PARA;
73     }
74 
75     // 1. Get challenge.
76     const char *challengeStr = DslmGetJsonFieldString(json, "challenge");
77     if (challengeStr == NULL) {
78         DslmDestroyJson(json);
79         return ERR_PARSE_NONCE;
80     }
81     int32_t ret =
82         DslmHexStringToByte(challengeStr, strlen(challengeStr), (uint8_t *)&nonce->challenge, sizeof(nonce->challenge));
83     if (ret != SUCCESS) {
84         DslmDestroyJson(json);
85         return ERR_PARSE_NONCE;
86     }
87 
88     // 2. Get PublicKey Info.
89     const char *pkInfoListStr = DslmGetJsonFieldString(json, "pkInfoList");
90     if (pkInfoListStr == NULL) {
91         DslmDestroyJson(json);
92         return ERR_PARSE_NONCE;
93     }
94     nonce->pbkInfoList = (uint8_t *)MALLOC(strlen(pkInfoListStr) + 1);
95     if (nonce->pbkInfoList == NULL) {
96         DslmDestroyJson(json);
97         return ERR_NO_MEMORY;
98     }
99 
100     ret = strcpy_s((char *)nonce->pbkInfoList, strlen(pkInfoListStr) + 1, pkInfoListStr);
101     if (ret != EOK) {
102         FREE(nonce->pbkInfoList);
103         nonce->pbkInfoList = NULL;
104         DslmDestroyJson(json);
105         return ERR_MEMORY_ERR;
106     }
107     DslmDestroyJson(json);
108     return SUCCESS;
109 }
110 
FreeNonceOfCertChain(struct NonceOfCertChain * nonce)111 static void FreeNonceOfCertChain(struct NonceOfCertChain *nonce)
112 {
113     if (nonce == NULL) {
114         return;
115     }
116     if (nonce->pbkInfoList != NULL) {
117         FREE(nonce->pbkInfoList);
118         nonce->pbkInfoList = NULL;
119     }
120     (void)memset_s(nonce, sizeof(struct NonceOfCertChain), 0, sizeof(struct NonceOfCertChain));
121 }
122 
FindCommonPkInfo(const char * bufferA,const char * bufferB)123 static int32_t FindCommonPkInfo(const char *bufferA, const char *bufferB)
124 {
125     if (bufferA == NULL || bufferB == NULL) {
126         return ERR_INVALID_PARA;
127     }
128     DslmJsonHandle jsonA = DslmCreateJson(bufferA);
129     if (jsonA == NULL) {
130         return ERR_INVALID_PARA;
131     }
132     DslmJsonHandle jsonB = DslmCreateJson(bufferB);
133     if (jsonB == NULL) {
134         DslmDestroyJson(jsonA);
135         return ERR_INVALID_PARA;
136     }
137     uint32_t sizeA = (uint32_t)DslmGetJsonFieldJsonArraySize(jsonA);
138     uint32_t sizeB = (uint32_t)DslmGetJsonFieldJsonArraySize(jsonB);
139 
140     for (uint32_t i = 0; i < sizeA; i++) {
141         for (uint32_t j = 0; j < sizeB; j++) {
142             if (DslmCompareJsonData(DslmGetJsonFieldJsonArray(jsonA, i), DslmGetJsonFieldJsonArray(jsonB, j), true)) {
143                 DslmDestroyJson(jsonA);
144                 DslmDestroyJson(jsonB);
145                 return SUCCESS;
146             }
147         }
148     }
149     DslmDestroyJson(jsonA);
150     DslmDestroyJson(jsonB);
151     return ERR_NOEXIST_COMMON_PK_INFO;
152 }
153 
CheckNonceOfCertChain(const struct NonceOfCertChain * nonce,uint64_t challenge,const char * pbkInfoList)154 static int32_t CheckNonceOfCertChain(const struct NonceOfCertChain *nonce, uint64_t challenge, const char *pbkInfoList)
155 {
156     if (challenge != nonce->challenge) {
157         SECURITY_LOG_ERROR("compare nonce challenge failed");
158         return ERR_CHALLENGE_ERR;
159     }
160 
161     int32_t ret = FindCommonPkInfo((char *)pbkInfoList, (char *)nonce->pbkInfoList);
162     if (ret != SUCCESS) {
163         SECURITY_LOG_ERROR("compare nonce public key info failed");
164         return SUCCESS;
165     }
166     return SUCCESS;
167 }
168 
VerifyNonceOfCertChain(const char * jsonStr,const struct DeviceIdentify * device,uint64_t challenge)169 static int32_t VerifyNonceOfCertChain(const char *jsonStr, const struct DeviceIdentify *device, uint64_t challenge)
170 {
171     char *pkInfoListStr = NULL;
172     struct NonceOfCertChain nonce;
173     (void)memset_s(&nonce, sizeof(struct NonceOfCertChain), 0, sizeof(struct NonceOfCertChain));
174 
175     char udidStr[UDID_STRING_LENGTH] = {0};
176     if (memcpy_s(udidStr, UDID_STRING_LENGTH, device->identity, device->length) != EOK) {
177         return ERR_MEMORY_ERR;
178     }
179 
180     int32_t ret = ERR_DEFAULT;
181     do {
182         ret = ParseNonceOfCertChain(jsonStr, &nonce);
183         if (ret != SUCCESS) {
184             SECURITY_LOG_ERROR("ParseNonceOfCertChain failed");
185             break;
186         }
187 
188         ret = GetPkInfoListStr(false, udidStr, &pkInfoListStr);
189         if (ret != SUCCESS) {
190             SECURITY_LOG_ERROR("GetPkInfoListStr failed");
191             break;
192         }
193 
194         ret = CheckNonceOfCertChain(&nonce, challenge, pkInfoListStr);
195         if (ret != SUCCESS) {
196             SECURITY_LOG_ERROR("CheckNonceOfCertChain failed");
197             break;
198         }
199         SECURITY_LOG_DEBUG("success");
200     } while (0);
201 
202     FreeNonceOfCertChain(&nonce);
203     if (pkInfoListStr != NULL) {
204         FREE(pkInfoListStr);
205     }
206     return ret;
207 }
208 
VerifyLiteDslmCred(const DeviceIdentify * device,const DslmCredBuff * credBuff,DslmCredInfo * credInfo)209 static int32_t VerifyLiteDslmCred(const DeviceIdentify *device, const DslmCredBuff *credBuff, DslmCredInfo *credInfo)
210 {
211     if (credBuff->credLen > UINT16_MAX) {
212         return ERR_MEMORY_ERR;
213     }
214 
215     char credStr[DSLM_CRED_STR_LEN_MAX] = {0};
216     if (memcpy_s(credStr, DSLM_CRED_STR_LEN_MAX, credBuff->credVal, credBuff->credLen + 1) != EOK) {
217         return ERR_MEMORY_ERR;
218     }
219 
220     int32_t ret = VerifyDslmCredential(credStr, credInfo, NULL);
221     if (ret != SUCCESS) {
222         SECURITY_LOG_ERROR("VerifyDslmCredential failed");
223         return ret;
224     }
225 
226     ret = CheckCredInfo(device, credInfo, CRED_MAX_LEVEL_TYPE_SMALL);
227     if (ret != SUCCESS) {
228         SECURITY_LOG_ERROR("CheckCredInfo failed");
229         return ret;
230     }
231 
232     return SUCCESS;
233 }
234 
VerifyStandardDslmCred(const DeviceIdentify * device,uint64_t challenge,const DslmCredBuff * credBuff,DslmCredInfo * credInfo)235 static int32_t VerifyStandardDslmCred(const DeviceIdentify *device, uint64_t challenge, const DslmCredBuff *credBuff,
236     DslmCredInfo *credInfo)
237 {
238     struct DslmInfoInCertChain resultInfo;
239     int32_t ret = InitDslmInfoInCertChain(&resultInfo);
240     if (ret != SUCCESS) {
241         SECURITY_LOG_ERROR("InitDslmInfoInCertChain failed");
242         return ret;
243     }
244 
245     do {
246         // 1. Verify the certificate chain, get data in the certificate chain(nonce + UDID + cred).
247         ret = ValidateCertChainAdapter(credBuff->credVal, credBuff->credLen, &resultInfo);
248         if (ret != SUCCESS) {
249             SECURITY_LOG_ERROR("ValidateCertChainAdapter failed");
250             break;
251         }
252 
253         // 2. Parses the NONCE into CHALLENGE and PK_INFO_LIST, verifies them separately.
254         ret = VerifyNonceOfCertChain(resultInfo.nonceStr, device, challenge);
255         if (ret != SUCCESS) {
256             SECURITY_LOG_ERROR("verifyNonceOfCertChain failed");
257             break;
258         }
259 
260         // 3. The cred content is "<header>.<payload>.<signature>.<attestation>", parse and verify it.
261         ret = VerifyDslmCredential(resultInfo.credStr, credInfo, NULL);
262         if (ret != SUCCESS) {
263             SECURITY_LOG_ERROR("VerifyDslmCredential failed");
264             break;
265         }
266         ret = CheckCredInfo(device, credInfo, CRED_MAX_LEVEL_TYPE_STANDARD);
267         if (ret != SUCCESS) {
268             SECURITY_LOG_ERROR("CheckCredInfo failed");
269             break;
270         }
271     } while (0);
272 
273     DestroyDslmInfoInCertChain(&resultInfo);
274     if (ret == SUCCESS) {
275         SECURITY_LOG_INFO("success, cred level = %{public}d", credInfo->credLevel);
276     }
277     return ret;
278 }
279 
VerifyOhosDslmCred(const DeviceIdentify * device,uint64_t challenge,const DslmCredBuff * credBuff,DslmCredInfo * credInfo)280 int32_t VerifyOhosDslmCred(const DeviceIdentify *device, uint64_t challenge, const DslmCredBuff *credBuff,
281     DslmCredInfo *credInfo)
282 {
283     if (device == NULL || credBuff == NULL || credInfo == NULL) {
284         return ERR_INVALID_PARA;
285     }
286 
287     SECURITY_LOG_INFO("start");
288     credInfo->credType = credBuff->type;
289     switch (credBuff->type) {
290         case CRED_TYPE_STANDARD:
291             return VerifyStandardDslmCred(device, challenge, credBuff, credInfo);
292         case CRED_TYPE_SMALL:
293         case CRED_TYPE_MINI:
294             return VerifyLiteDslmCred(device, credBuff, credInfo);
295         default:
296             SECURITY_LOG_ERROR("invalid cred type");
297             break;
298     }
299     return ERR_INVALID_PARA;
300 }