• 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     char credStr[DSLM_CRED_STR_LEN_MAX] = {0};
212     if (memcpy_s(credStr, DSLM_CRED_STR_LEN_MAX, credBuff->credVal, credBuff->credLen + 1) != EOK) {
213         return ERR_MEMORY_ERR;
214     }
215 
216     int32_t ret = VerifyDslmCredential(credStr, credInfo, NULL);
217     if (ret != SUCCESS) {
218         SECURITY_LOG_ERROR("VerifyDslmCredential failed");
219         return ret;
220     }
221 
222     ret = CheckCredInfo(device, credInfo, CRED_MAX_LEVEL_TYPE_SMALL);
223     if (ret != SUCCESS) {
224         SECURITY_LOG_ERROR("CheckCredInfo failed");
225         return ret;
226     }
227 
228     return SUCCESS;
229 }
230 
VerifyStandardDslmCred(const DeviceIdentify * device,uint64_t challenge,const DslmCredBuff * credBuff,DslmCredInfo * credInfo)231 static int32_t VerifyStandardDslmCred(const DeviceIdentify *device, uint64_t challenge, const DslmCredBuff *credBuff,
232     DslmCredInfo *credInfo)
233 {
234     struct DslmInfoInCertChain resultInfo;
235     int32_t ret = InitDslmInfoInCertChain(&resultInfo);
236     if (ret != SUCCESS) {
237         SECURITY_LOG_ERROR("InitDslmInfoInCertChain failed");
238         return ret;
239     }
240 
241     do {
242         // 1. Verify the certificate chain, get data in the certificate chain(nonce + UDID + cred).
243         ret = ValidateCertChainAdapter(credBuff->credVal, credBuff->credLen, &resultInfo);
244         if (ret != SUCCESS) {
245             SECURITY_LOG_ERROR("ValidateCertChainAdapter failed");
246             break;
247         }
248 
249         // 2. Parses the NONCE into CHALLENGE and PK_INFO_LIST, verifies them separately.
250         ret = VerifyNonceOfCertChain(resultInfo.nonceStr, device, challenge);
251         if (ret != SUCCESS) {
252             SECURITY_LOG_ERROR("verifyNonceOfCertChain failed");
253             break;
254         }
255 
256         // 3. The cred content is "<header>.<payload>.<signature>.<attestation>", parse and verify it.
257         ret = VerifyDslmCredential(resultInfo.credStr, credInfo, NULL);
258         if (ret != SUCCESS) {
259             SECURITY_LOG_ERROR("VerifyDslmCredential failed");
260             break;
261         }
262         ret = CheckCredInfo(device, credInfo, CRED_MAX_LEVEL_TYPE_STANDARD);
263         if (ret != SUCCESS) {
264             SECURITY_LOG_ERROR("CheckCredInfo failed");
265             break;
266         }
267     } while (0);
268 
269     DestroyDslmInfoInCertChain(&resultInfo);
270     if (ret == SUCCESS) {
271         SECURITY_LOG_INFO("success, cred level = %{public}d", credInfo->credLevel);
272     }
273     return ret;
274 }
275 
VerifyOhosDslmCred(const DeviceIdentify * device,uint64_t challenge,const DslmCredBuff * credBuff,DslmCredInfo * credInfo)276 int32_t VerifyOhosDslmCred(const DeviceIdentify *device, uint64_t challenge, const DslmCredBuff *credBuff,
277     DslmCredInfo *credInfo)
278 {
279     if (device == NULL || credBuff == NULL || credInfo == NULL) {
280         return ERR_INVALID_PARA;
281     }
282 
283     SECURITY_LOG_INFO("start");
284     credInfo->credType = credBuff->type;
285     switch (credBuff->type) {
286         case CRED_TYPE_STANDARD:
287             return VerifyStandardDslmCred(device, challenge, credBuff, credInfo);
288         case CRED_TYPE_SMALL:
289         case CRED_TYPE_MINI:
290             return VerifyLiteDslmCred(device, credBuff, credInfo);
291         default:
292             SECURITY_LOG_ERROR("invalid cred type");
293             break;
294     }
295     return ERR_INVALID_PARA;
296 }