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 }