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 "iso_auth_client_task.h"
17 #include "account_module_defines.h"
18 #include "clib_error.h"
19 #include "common_defs.h"
20 #include "device_auth.h"
21 #include "device_auth_defines.h"
22 #include "hc_log.h"
23 #include "hc_types.h"
24 #include "iso_auth_task_common.h"
25 #include "iso_protocol_common.h"
26 #include "protocol_common.h"
27 
28 enum {
29     TASK_STATUS_ISO_MAIN_BEGIN = 0,
30     TASK_STATUS_ISO_MAIN_STEP_ONE = 1,
31     TASK_STATUS_ISO_MAIN_STEP_TWO = 2,
32     TASK_STATUS_ISO_MAIN_END = 3,
33 };
34 
GetIsoAuthClientType(void)35 static AccountTaskType GetIsoAuthClientType(void)
36 {
37     return TASK_TYPE_ISO_AUTH_CLIENT;
38 }
39 
AddBeginDataToJson(const IsoAuthParams * params,CJson * sendToPeer)40 static int32_t AddBeginDataToJson(const IsoAuthParams *params, CJson *sendToPeer)
41 {
42     CJson *data = CreateJson();
43     if (data == NULL) {
44         LOGE("Create data json failed.");
45         return HC_ERR_JSON_CREATE;
46     }
47 
48     if (AddByteToJson(data, FIELD_SALT,
49         params->isoBaseParams.randSelf.val, params->isoBaseParams.randSelf.length) != CLIB_SUCCESS) {
50         LOGE("Add saltSelf to json failed.");
51         goto CLEAN_UP;
52     }
53     if (AddByteToJson(data, FIELD_PAYLOAD,
54         params->isoBaseParams.authIdSelf.val, params->isoBaseParams.authIdSelf.length) != CLIB_SUCCESS) {
55         LOGE("Add payloadSelf to json failed.");
56         goto CLEAN_UP;
57     }
58     if (AddByteToJson(data, FIELD_SEED, params->seed, sizeof(params->seed)) != CLIB_SUCCESS) {
59         LOGE("Add seed to json failed.");
60         goto CLEAN_UP;
61     }
62     if (AddObjToJson(sendToPeer, FIELD_DATA, data) != CLIB_SUCCESS) {
63         LOGE("Add data json obj to json failed.");
64         goto CLEAN_UP;
65     }
66 
67     FreeJson(data);
68     return HC_SUCCESS;
69 CLEAN_UP:
70     FreeJson(data);
71     return HC_ERR_JSON_ADD;
72 }
73 
PackIsoAuthClientBeginMsg(const IsoAuthParams * params,CJson * out)74 static int32_t PackIsoAuthClientBeginMsg(const IsoAuthParams *params, CJson *out)
75 {
76     CJson *sendToPeer = CreateJson();
77     if (sendToPeer == NULL) {
78         LOGE("Create sendToPeer json failed.");
79         return HC_ERR_JSON_CREATE;
80     }
81 
82     if (AddIntToJson(sendToPeer, FIELD_AUTH_FORM, params->authForm) != CLIB_SUCCESS) {
83         LOGE("Add authForm to json failed.");
84         goto CLEAN_UP;
85     }
86     if (AddIntToJson(sendToPeer, FIELD_STEP, CMD_ISO_AUTH_MAIN_ONE) != CLIB_SUCCESS) {
87         LOGE("Add step code to json failed.");
88         goto CLEAN_UP;
89     }
90     if (AddIntToJson(sendToPeer, FIELD_CREDENTIAL_TYPE, params->credentialType) != CLIB_SUCCESS) {
91         LOGE("Add credentialType to json failed.");
92         goto CLEAN_UP;
93     }
94     if (AddStringToJson(sendToPeer, FIELD_USER_ID, params->userIdSelf) != CLIB_SUCCESS) {
95         LOGE("Add userIdSelf to json failed.");
96         goto CLEAN_UP;
97     }
98     if (AddByteToJson(sendToPeer, FIELD_DEV_ID, params->devIdSelf.val, params->devIdSelf.length) != CLIB_SUCCESS) {
99         LOGE("Add devIdSelf to json failed.");
100         goto CLEAN_UP;
101     }
102     if (AddStringToJson(sendToPeer, FIELD_DEVICE_ID, params->deviceIdSelf) != CLIB_SUCCESS) {
103         LOGE("Add deviceIdSelf to json failed.");
104         goto CLEAN_UP;
105     }
106 
107     if (AddBeginDataToJson(params, sendToPeer) != HC_SUCCESS) {
108         LOGE("AddBeginDataToJson failed.");
109         goto CLEAN_UP;
110     }
111 
112     if (AddObjToJson(out, FIELD_SEND_TO_PEER, sendToPeer) != CLIB_SUCCESS) {
113         LOGE("Add sendToPeer to json failed.");
114         goto CLEAN_UP;
115     }
116     FreeJson(sendToPeer);
117     return HC_SUCCESS;
118 CLEAN_UP:
119     FreeJson(sendToPeer);
120     return HC_ERR_JSON_ADD;
121 }
122 
AccountAuthGenSeed(IsoAuthParams * params)123 static int32_t AccountAuthGenSeed(IsoAuthParams *params)
124 {
125     Uint8Buff seedBuff = { params->seed, sizeof(params->seed) };
126     int32_t res = params->isoBaseParams.loader->generateRandom(&seedBuff);
127     if (res != HC_SUCCESS) {
128         LOGE("GenerateRandom for seed failed, res: %d.", res);
129     }
130     return res;
131 }
132 
IsoAuthClientBegin(TaskBase * task,const CJson * in,CJson * out,int32_t * status)133 static int32_t IsoAuthClientBegin(TaskBase *task, const CJson *in, CJson *out, int32_t *status)
134 {
135     (void)in;
136     if (task->taskStatus != TASK_STATUS_ISO_MAIN_BEGIN) {
137         LOGD("The message is repeated, ignore it, taskStatus: %d.", task->taskStatus);
138         *status = IGNORE_MSG;
139         return HC_SUCCESS;
140     }
141 
142     IsoAuthClientTask *innerTask = (IsoAuthClientTask *)task;
143     int32_t ret = IsoClientGenRandom(&innerTask->params.isoBaseParams);
144     if (ret != HC_SUCCESS) {
145         LOGE("IsoClientGenRandom failed, res: %d.", ret);
146         return ret;
147     }
148     ret = AccountAuthGenSeed(&innerTask->params);
149     if (ret != HC_SUCCESS) {
150         LOGE("AccountAuthGenSeed failed, res: %d.", ret);
151         return ret;
152     }
153 
154     // Send params to server.
155     ret = PackIsoAuthClientBeginMsg(&innerTask->params, out);
156     if (ret != HC_SUCCESS) {
157         LOGE("PackIsoAuthClientBeginMsg failed, ret: %d.", ret);
158         return ret;
159     }
160 
161     innerTask->taskBase.taskStatus = TASK_STATUS_ISO_MAIN_STEP_ONE;
162     *status = CONTINUE;
163     return HC_SUCCESS;
164 }
165 
ParseIsoAuthServerGetTokenMsg(IsoAuthParams * params,const CJson * in,Uint8Buff * peerToken)166 static int32_t ParseIsoAuthServerGetTokenMsg(IsoAuthParams *params, const CJson *in, Uint8Buff *peerToken)
167 {
168     const char *userIdPeer = GetStringFromJson(in, FIELD_USER_ID);
169     if (userIdPeer == NULL) {
170         LOGE("Failed to get userIdPeer from input data for client in sym auth.");
171         return HC_ERR_JSON_GET;
172     }
173     if (strcpy_s(params->userIdPeer, DEV_AUTH_USER_ID_SIZE, userIdPeer) != EOK) {
174         LOGE("Copy for userIdPeer failed for client in sym auth.");
175         return HC_ERR_MEMORY_COPY;
176     }
177     if (GetByteFromJson(in, FIELD_SALT, params->isoBaseParams.randPeer.val,
178         params->isoBaseParams.randPeer.length) != CLIB_SUCCESS) {
179         LOGE("Get saltPeer from json failed for client.");
180         return HC_ERR_JSON_GET;
181     }
182     if (GetByteFromJson(in, FIELD_TOKEN, peerToken->val, peerToken->length) != CLIB_SUCCESS) {
183         LOGE("Get peerToken from json failed for client.");
184         return HC_ERR_JSON_GET;
185     }
186     int32_t res = ExtractAndVerifyPayload(params, in);
187     if (res != HC_SUCCESS) {
188         LOGE("ExtractAndVerifyPayload failed for client, res: %d.", res);
189     }
190     return res;
191 }
192 
PackIsoAuthClientGetTokenMsg(const IsoAuthParams * params,CJson * out)193 static int32_t PackIsoAuthClientGetTokenMsg(const IsoAuthParams *params, CJson *out)
194 {
195     CJson *sendToPeer = CreateJson();
196     if (sendToPeer == NULL) {
197         LOGE("Create sendToPeer json failed.");
198         return HC_ERR_JSON_CREATE;
199     }
200     CJson *data = CreateJson();
201     if (data == NULL) {
202         LOGE("Create data json failed.");
203         FreeJson(sendToPeer);
204         return HC_ERR_JSON_CREATE;
205     }
206 
207     if (AddIntToJson(sendToPeer, FIELD_AUTH_FORM, params->authForm) != CLIB_SUCCESS) {
208         LOGE("Add authForm to json failed.");
209         goto CLEAN_UP;
210     }
211     if (AddIntToJson(sendToPeer, FIELD_STEP, CMD_ISO_AUTH_MAIN_TWO) != CLIB_SUCCESS) {
212         LOGE("Add step code to json failed.");
213         goto CLEAN_UP;
214     }
215     if (AddByteToJson(data, FIELD_TOKEN, params->hmacToken, sizeof(params->hmacToken)) != CLIB_SUCCESS) {
216         LOGE("Add hmacToken to json failed.");
217         goto CLEAN_UP;
218     }
219     if (AddObjToJson(sendToPeer, FIELD_DATA, data) != CLIB_SUCCESS) {
220         LOGE("Add data json obj to json failed.");
221         goto CLEAN_UP;
222     }
223     if (AddObjToJson(out, FIELD_SEND_TO_PEER, sendToPeer) != CLIB_SUCCESS) {
224         LOGE("Add sendToPeer to json failed.");
225         goto CLEAN_UP;
226     }
227     FreeJson(sendToPeer);
228     FreeJson(data);
229     return HC_SUCCESS;
230 CLEAN_UP:
231     FreeJson(sendToPeer);
232     FreeJson(data);
233     return HC_ERR_JSON_ADD;
234 }
235 
IsoAuthClientGetToken(TaskBase * task,const CJson * in,CJson * out,int32_t * status)236 static int32_t IsoAuthClientGetToken(TaskBase *task, const CJson *in, CJson *out, int32_t *status)
237 {
238     IsoAuthClientTask *innerTask = (IsoAuthClientTask *)task;
239     if (innerTask->taskBase.taskStatus < TASK_STATUS_ISO_MAIN_STEP_ONE) {
240         LOGE("Message code is not match with task status, taskStatus: %d", innerTask->taskBase.taskStatus);
241         return HC_ERR_BAD_MESSAGE;
242     }
243     if (innerTask->taskBase.taskStatus > TASK_STATUS_ISO_MAIN_STEP_ONE) {
244         LOGI("The message is repeated, ignore it, taskStatus: %d.", innerTask->taskBase.taskStatus);
245         *status = IGNORE_MSG;
246         return HC_SUCCESS;
247     }
248 
249     // Receive params from server.
250     uint8_t peerToken[HMAC_TOKEN_SIZE] = { 0 };
251     Uint8Buff peerTokenBuf = { peerToken, HMAC_TOKEN_SIZE };
252     int32_t res = ParseIsoAuthServerGetTokenMsg(&innerTask->params, in, &peerTokenBuf);
253     if (res != HC_SUCCESS) {
254         LOGE("ParseIsoAuthServerGetTokenMsg failed, res: %d.", res);
255         return res;
256     }
257 
258     // Get psk and process hmacToken.
259     res = AccountAuthGeneratePsk(&innerTask->params);
260     if (res != HC_SUCCESS) {
261         LOGE("AccountAuthGeneratePsk failed, res: %d.", res);
262         return res;
263     }
264     Uint8Buff selfTokenBuf = { innerTask->params.hmacToken, HMAC_TOKEN_SIZE };
265     res = IsoClientCheckAndGenToken(&(innerTask->params.isoBaseParams), &peerTokenBuf, &selfTokenBuf);
266     if (res != HC_SUCCESS) {
267         LOGE("IsoClientCheckAndGenToken failed, res: %d.", res);
268         return res;
269     }
270 
271     // Send params to server.
272     res = PackIsoAuthClientGetTokenMsg(&innerTask->params, out);
273     if (res != HC_SUCCESS) {
274         LOGE("PackIsoAuthClientGetTokenMsg failed, res: %d.", res);
275         return res;
276     }
277 
278     innerTask->taskBase.taskStatus = TASK_STATUS_ISO_MAIN_STEP_TWO;
279     *status = CONTINUE;
280     return HC_SUCCESS;
281 }
282 
IsoAuthClientGetSessionKey(TaskBase * task,const CJson * in,CJson * out,int32_t * status)283 static int32_t IsoAuthClientGetSessionKey(TaskBase *task, const CJson *in, CJson *out, int32_t *status)
284 {
285     IsoAuthClientTask *innerTask = (IsoAuthClientTask *)task;
286     if (innerTask->taskBase.taskStatus < TASK_STATUS_ISO_MAIN_STEP_TWO) {
287         LOGE("Message code is not match with task status, taskStatus: %d", innerTask->taskBase.taskStatus);
288         return HC_ERR_BAD_MESSAGE;
289     }
290     if (innerTask->taskBase.taskStatus > TASK_STATUS_ISO_MAIN_STEP_TWO) {
291         LOGI("The message is repeated, ignore it, taskStatus: %d", innerTask->taskBase.taskStatus);
292         *status = IGNORE_MSG;
293         return HC_SUCCESS;
294     }
295 
296     // Receive params from server.
297     uint8_t authResultHmac[AUTH_RESULT_MAC_SIZE] = { 0 };
298     if (GetByteFromJson(in, FIELD_AUTH_RESULT_MAC, authResultHmac, sizeof(authResultHmac)) != CLIB_SUCCESS) {
299         LOGE("Get authResultHmac from json failed.");
300         return HC_ERR_JSON_GET;
301     }
302 
303     // Generate and verify the HMAC, then generate session key.
304     int32_t res = IsoClientGenSessionKey(&(innerTask->params.isoBaseParams), 0, authResultHmac, sizeof(authResultHmac));
305     if (res != HC_SUCCESS) {
306         LOGE("IsoClientGenSessionKey failed, res: %d.", res);
307         return res;
308     }
309 
310     res = AuthIsoSendFinalToOut(&innerTask->params, out);
311     if (res != HC_SUCCESS) {
312         LOGE("AuthIsoSendFinalToOut failed, res: %d.", res);
313         return res;
314     }
315 
316     innerTask->taskBase.taskStatus = TASK_STATUS_ISO_MAIN_END;
317     *status = FINISH;
318     return HC_SUCCESS;
319 }
320 
ProcessClientTask(TaskBase * task,const CJson * in,CJson * out,int32_t * status)321 static int32_t ProcessClientTask(TaskBase *task, const CJson *in, CJson *out, int32_t *status)
322 {
323     int32_t res;
324     if (task->taskStatus == TASK_STATUS_ISO_MAIN_BEGIN) {
325         res = IsoAuthClientBegin(task, in, out, status);
326         if (res != HC_SUCCESS) {
327             LOGE("IsoAuthClientBegin failed, res: %d.", res);
328         }
329         return res;
330     }
331 
332     int32_t authStep;
333     if (GetIntFromJson(in, FIELD_STEP, &authStep) != CLIB_SUCCESS) {
334         LOGE("Get message code from json failed.");
335         return HC_ERR_JSON_GET;
336     }
337     switch (authStep) {
338         case RET_ISO_AUTH_FOLLOWER_ONE:
339             res = IsoAuthClientGetToken(task, in, out, status);
340             break;
341         case RET_ISO_AUTH_FOLLOWER_TWO:
342             res = IsoAuthClientGetSessionKey(task, in, out, status);
343             break;
344         default:
345             res = HC_ERR_BAD_MESSAGE;
346     }
347     if (res != HC_SUCCESS) {
348         LOGE("Process iso auth client failed, step: %d, res: %d.", authStep, res);
349     }
350     return res;
351 }
352 
DestroyAuthClientAuthTask(TaskBase * task)353 static void DestroyAuthClientAuthTask(TaskBase *task)
354 {
355     if (task == NULL) {
356         return;
357     }
358     IsoAuthClientTask *innerTask = (IsoAuthClientTask *)task;
359     DestroyIsoAuthParams(&(innerTask->params));
360     HcFree(innerTask);
361 }
362 
CreateIsoAuthClientTask(const CJson * in,CJson * out,const AccountVersionInfo * verInfo)363 TaskBase *CreateIsoAuthClientTask(const CJson *in, CJson *out, const AccountVersionInfo *verInfo)
364 {
365     if ((in == NULL) || (out == NULL) || (verInfo == NULL)) {
366         LOGE("Params is null for client sym auth.");
367         return NULL;
368     }
369     IsoAuthClientTask *task = (IsoAuthClientTask *)HcMalloc(sizeof(IsoAuthClientTask), 0);
370     if (task == NULL) {
371         LOGE("Malloc for IsoAuthClientTask failed.");
372         return NULL;
373     }
374     task->taskBase.getTaskType = GetIsoAuthClientType;
375     task->taskBase.process = ProcessClientTask;
376     task->taskBase.destroyTask = DestroyAuthClientAuthTask;
377 
378     int32_t res = InitIsoAuthParams(in, &(task->params), verInfo);
379     if (res != HC_SUCCESS) {
380         LOGE("InitIsoAuthParams failed, res: %d.", res);
381         DestroyAuthClientAuthTask((TaskBase *)task);
382         return NULL;
383     }
384 
385     task->taskBase.taskStatus = TASK_STATUS_ISO_MAIN_BEGIN;
386     return (TaskBase *)task;
387 }
388