1 /*
2  * Copyright (C) 2023 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 "mk_agree.h"
17 
18 #include "common_defs.h"
19 #include "device_auth.h"
20 #include "device_auth_defines.h"
21 #include "hc_log.h"
22 #include "mk_agree_task.h"
23 
24 #define FIELD_EVENT "event"
25 #define FIELD_ERR_CODE "errCode"
26 
27 typedef enum {
28     START_EVENT = 0,
29     START_MK_AGREE_REQUEST_EVENT,
30     SEND_MK_AGREE_RESPONSE_EVENT,
31     FAIL_EVENT,
32     UNKNOWN_EVENT
33 } EventEnum;
34 
35 typedef enum {
36     CLIENT_INIT_STATE = 0,
37     SERVER_WAIT_REQUEST_STATE,
38     CLIENT_WAIT_RESPONSE_STATE,
39     FINISH_STATE,
40     FAIL_STATE
41 } StateEnum;
42 
43 typedef struct {
44     BaseCmd base;
45     MkAgreeTaskBase *task;
46 } MkAgreeCmd;
47 
48 typedef struct {
49     int32_t curState;
50     int32_t eventType;
51     int32_t (*stateProcessFunc)(BaseCmd *, const CJson *, CJson **);
52     void (*exceptionHandleFunc)(int32_t, CJson **);
53     int32_t nextState;
54 } CmdStateNode;
55 
ProcessMkAgreeError(int32_t errorCode,CJson ** out)56 static void ProcessMkAgreeError(int32_t errorCode, CJson **out)
57 {
58     (void)errorCode;
59     (void)out;
60 }
61 
InformPeerError(int32_t errorCode,CJson ** out)62 static void InformPeerError(int32_t errorCode, CJson **out)
63 {
64     CJson *json = CreateJson();
65     if (json == NULL) {
66         LOGE("Failed to create json!");
67         return;
68     }
69     if (AddIntToJson(json, FIELD_EVENT, FAIL_EVENT) != HC_SUCCESS) {
70         LOGE("Failed to add event!");
71         FreeJson(json);
72         return;
73     }
74     if (AddIntToJson(json, FIELD_ERR_CODE, errorCode) != HC_SUCCESS) {
75         LOGE("Failed to add error code!");
76         FreeJson(json);
77         return;
78     }
79     *out = json;
80     return;
81 }
82 
ThrowException(BaseCmd * cmd,const CJson * in,CJson ** out)83 static int32_t ThrowException(BaseCmd *cmd, const CJson *in, CJson **out)
84 {
85     LOGI("throw exception.");
86     (void)cmd;
87     (void)in;
88     (void)out;
89     return HC_ERR_UNSUPPORTED_OPCODE;
90 }
91 
AddEventByState(const BaseCmd * cmd,CJson * sendData)92 static int32_t AddEventByState(const BaseCmd *cmd, CJson *sendData)
93 {
94     if (cmd->curState == CLIENT_INIT_STATE) {
95         return AddIntToJson(sendData, FIELD_EVENT, START_MK_AGREE_REQUEST_EVENT);
96     } else if (cmd->curState == SERVER_WAIT_REQUEST_STATE) {
97         return AddIntToJson(sendData, FIELD_EVENT, SEND_MK_AGREE_RESPONSE_EVENT);
98     } else {
99         LOGE("Invalid state!");
100         return HC_ERR_INVALID_PARAMS;
101     }
102 }
103 
ProcessMkAgreeTask(BaseCmd * cmd,const CJson * in,CJson ** out)104 static int32_t ProcessMkAgreeTask(BaseCmd *cmd, const CJson *in, CJson **out)
105 {
106     LOGI("process mk agree task, current state is: %d", cmd->curState);
107     CJson *sendData = CreateJson();
108     if (sendData == NULL) {
109         LOGE("Failed to create sendData!");
110         return HC_ERR_JSON_CREATE;
111     }
112     MkAgreeCmd *impl = (MkAgreeCmd *)cmd;
113     int32_t res = impl->task->process(impl->task, in, sendData);
114     if (res != HC_SUCCESS) {
115         LOGE("Failed to process mk agree task!");
116         FreeJson(sendData);
117         return res;
118     }
119     if (cmd->curState == CLIENT_WAIT_RESPONSE_STATE) {
120         FreeJson(sendData);
121         return HC_SUCCESS;
122     }
123     CJson *sendToPeer = GetObjFromJson(sendData, FIELD_SEND_TO_PEER);
124     if (sendToPeer == NULL) {
125         LOGE("sendToPeer is null!");
126         FreeJson(sendData);
127         return HC_ERR_JSON_GET;
128     }
129     *out = DuplicateJson(sendToPeer);
130     FreeJson(sendData);
131     if (*out == NULL) {
132         LOGE("Failed to duplicate send data!");
133         return HC_ERR_JSON_FAIL;
134     }
135     res = AddEventByState(cmd, *out);
136     if (res != HC_SUCCESS) {
137         LOGE("Failed to add event!");
138         FreeJson(*out);
139         *out = NULL;
140         return res;
141     }
142     return HC_SUCCESS;
143 }
144 
145 static const CmdStateNode STATE_MACHINE[] = {
146     { CLIENT_INIT_STATE, START_EVENT, ProcessMkAgreeTask, InformPeerError, CLIENT_WAIT_RESPONSE_STATE },
147     { SERVER_WAIT_REQUEST_STATE, START_MK_AGREE_REQUEST_EVENT, ProcessMkAgreeTask, InformPeerError, FINISH_STATE },
148     { SERVER_WAIT_REQUEST_STATE, FAIL_EVENT, ThrowException, ProcessMkAgreeError, FAIL_STATE },
149     { CLIENT_WAIT_RESPONSE_STATE, SEND_MK_AGREE_RESPONSE_EVENT, ProcessMkAgreeTask, ProcessMkAgreeError, FINISH_STATE },
150     { CLIENT_WAIT_RESPONSE_STATE, FAIL_EVENT, ThrowException, ProcessMkAgreeError, FAIL_STATE },
151 };
152 
DecodeEvent(const CJson * in)153 static int32_t DecodeEvent(const CJson *in)
154 {
155     if (in == NULL) {
156         LOGI("start event.");
157         return START_EVENT;
158     }
159     int32_t event;
160     if (GetIntFromJson(in, FIELD_EVENT, &event) != HC_SUCCESS) {
161         LOGE("Failed to get event from received msg!");
162         return UNKNOWN_EVENT;
163     }
164     if (event < START_EVENT || event > UNKNOWN_EVENT) {
165         LOGE("Invalid event!");
166         return UNKNOWN_EVENT;
167     }
168     return event;
169 }
170 
SwitchState(BaseCmd * cmd,const CJson * in,CJson ** out,CmdState * returnState)171 static int32_t SwitchState(BaseCmd *cmd, const CJson *in, CJson **out, CmdState *returnState)
172 {
173     int32_t eventType = DecodeEvent(in);
174     for (uint32_t i = 0; i < sizeof(STATE_MACHINE) / sizeof(STATE_MACHINE[0]); i++) {
175         if ((STATE_MACHINE[i].curState == cmd->curState) && (STATE_MACHINE[i].eventType == eventType)) {
176             int32_t res = STATE_MACHINE[i].stateProcessFunc(cmd, in, out);
177             if (res != HC_SUCCESS) {
178                 STATE_MACHINE[i].exceptionHandleFunc(res, out);
179                 cmd->curState = cmd->failState;
180                 return res;
181             }
182             LOGI("event: %d, curState: %d, nextState: %d", eventType, cmd->curState, STATE_MACHINE[i].nextState);
183             cmd->curState = STATE_MACHINE[i].nextState;
184             *returnState = (cmd->curState == cmd->finishState) ? CMD_STATE_FINISH : CMD_STATE_CONTINUE;
185             return HC_SUCCESS;
186         }
187     }
188     LOGI("Unsupported event type. Ignore process. [Event]: %d, [CurState]: %d", eventType, cmd->curState);
189     return HC_SUCCESS;
190 }
191 
StartMkAgreeCmd(BaseCmd * cmd,CJson ** out)192 static int32_t StartMkAgreeCmd(BaseCmd *cmd, CJson **out)
193 {
194     if ((cmd == NULL) || (out == NULL)) {
195         LOGE("Invalid params!");
196         return HC_ERR_INVALID_PARAMS;
197     }
198     if (cmd->curState != cmd->beginState) {
199         LOGE("Invalid state!");
200         return HC_ERR_UNSUPPORTED_OPCODE;
201     }
202     CmdState state;
203     return SwitchState(cmd, NULL, out, &state);
204 }
205 
ProcessMkAgreeCmd(BaseCmd * cmd,const CJson * in,CJson ** out,CmdState * returnState)206 static int32_t ProcessMkAgreeCmd(BaseCmd *cmd, const CJson *in, CJson **out, CmdState *returnState)
207 {
208     if ((cmd == NULL) || (in == NULL) || (out == NULL) || (returnState == NULL)) {
209         LOGE("Invalid params.");
210         return HC_ERR_INVALID_PARAMS;
211     }
212     if ((cmd->curState == cmd->finishState) || (cmd->curState == cmd->failState)) {
213         LOGE("Invalid state!");
214         return HC_ERR_UNSUPPORTED_OPCODE;
215     }
216     return SwitchState(cmd, in, out, returnState);
217 }
218 
DestroyMkAgreeCmd(BaseCmd * cmd)219 static void DestroyMkAgreeCmd(BaseCmd *cmd)
220 {
221     if (cmd == NULL) {
222         LOGE("cmd is null.");
223         return;
224     }
225     MkAgreeCmd *impl = (MkAgreeCmd *)cmd;
226     if (impl->task != NULL) {
227         impl->task->destroy(impl->task);
228     }
229     HcFree(impl);
230 }
231 
InitMkAgreeTask(MkAgreeCmd * cmd,const MkAgreeParams * params,bool isClient)232 static int32_t InitMkAgreeTask(MkAgreeCmd *cmd, const MkAgreeParams *params, bool isClient)
233 {
234     CJson *json = CreateJson();
235     if (json == NULL) {
236         LOGE("Failed to create json param!");
237         return HC_ERR_JSON_CREATE;
238     }
239     if (AddBoolToJson(json, FIELD_IS_CLIENT, isClient) != HC_SUCCESS) {
240         LOGE("Failed to add isClient!");
241         FreeJson(json);
242         return HC_ERR_JSON_ADD;
243     }
244     if (AddIntToJson(json, FIELD_OS_ACCOUNT_ID, params->osAccountId) != HC_SUCCESS) {
245         LOGE("Failed to add osAccountId!");
246         FreeJson(json);
247         return HC_ERR_JSON_ADD;
248     }
249     if (AddStringToJson(json, FIELD_REAL_INFO, params->peerInfo) != HC_SUCCESS) {
250         LOGE("Failed to add peerInfo!");
251         FreeJson(json);
252         return HC_ERR_JSON_ADD;
253     }
254     if (AddStringToJson(json, FIELD_INDEX_KEY, params->pdidIndex) != HC_SUCCESS) {
255         LOGE("Failed to add pdidIndex!");
256         FreeJson(json);
257         return HC_ERR_JSON_ADD;
258     }
259     int32_t res = CreateMkAgreeTask(TASK_TYPE_PAKE, json, &cmd->task);
260     FreeJson(json);
261     if (res != HC_SUCCESS) {
262         LOGE("Failed to create mk agree task!");
263     }
264     return res;
265 }
266 
InitMkAgreeCmd(MkAgreeCmd * cmd,const MkAgreeParams * params,bool isClient,int32_t strategy)267 static int32_t InitMkAgreeCmd(MkAgreeCmd *cmd, const MkAgreeParams *params,
268     bool isClient, int32_t strategy)
269 {
270     int32_t res = InitMkAgreeTask(cmd, params, isClient);
271     if (res != HC_SUCCESS) {
272         LOGE("Failed to init mk agree task!");
273         return res;
274     }
275     cmd->base.type = MK_AGREE_CMD_TYPE;
276     cmd->base.strategy = strategy;
277     cmd->base.isCaller = isClient;
278     cmd->base.beginState = isClient ? CLIENT_INIT_STATE : SERVER_WAIT_REQUEST_STATE;
279     cmd->base.finishState = FINISH_STATE;
280     cmd->base.failState = FAIL_STATE;
281     cmd->base.curState = cmd->base.beginState;
282     cmd->base.start = StartMkAgreeCmd;
283     cmd->base.process = ProcessMkAgreeCmd;
284     cmd->base.destroy = DestroyMkAgreeCmd;
285     return HC_SUCCESS;
286 }
287 
CreateMkAgreeCmd(const void * baseParams,bool isClient,int32_t strategy)288 BaseCmd *CreateMkAgreeCmd(const void *baseParams, bool isClient, int32_t strategy)
289 {
290     if (baseParams == NULL) {
291         LOGE("Invalid input params!");
292         return NULL;
293     }
294     MkAgreeCmd *cmd = (MkAgreeCmd *)HcMalloc(sizeof(MkAgreeCmd), 0);
295     if (cmd == NULL) {
296         LOGE("Failed to allocate memory for cmd!");
297         return NULL;
298     }
299     const MkAgreeParams *params = (const MkAgreeParams *)baseParams;
300     int32_t res = InitMkAgreeCmd(cmd, params, isClient, strategy);
301     if (res != HC_SUCCESS) {
302         HcFree(cmd);
303         return NULL;
304     }
305     return (BaseCmd *)cmd;
306 }