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: %" LOG_PUB "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: %" LOG_PUB "d, curState: %" LOG_PUB "d, nextState: %" LOG_PUB "d", eventType,
183 cmd->curState, STATE_MACHINE[i].nextState);
184 cmd->curState = STATE_MACHINE[i].nextState;
185 *returnState = (cmd->curState == cmd->finishState) ? CMD_STATE_FINISH : CMD_STATE_CONTINUE;
186 return HC_SUCCESS;
187 }
188 }
189 LOGI("Unsupported event type. Ignore process. [Event]: %" LOG_PUB "d, [CurState]: %" LOG_PUB "d",
190 eventType, cmd->curState);
191 return HC_SUCCESS;
192 }
193
StartMkAgreeCmd(BaseCmd * cmd,CJson ** out)194 static int32_t StartMkAgreeCmd(BaseCmd *cmd, CJson **out)
195 {
196 if ((cmd == NULL) || (out == NULL)) {
197 LOGE("Invalid params!");
198 return HC_ERR_INVALID_PARAMS;
199 }
200 if (cmd->curState != cmd->beginState) {
201 LOGE("Invalid state!");
202 return HC_ERR_UNSUPPORTED_OPCODE;
203 }
204 CmdState state;
205 return SwitchState(cmd, NULL, out, &state);
206 }
207
ProcessMkAgreeCmd(BaseCmd * cmd,const CJson * in,CJson ** out,CmdState * returnState)208 static int32_t ProcessMkAgreeCmd(BaseCmd *cmd, const CJson *in, CJson **out, CmdState *returnState)
209 {
210 if ((cmd == NULL) || (in == NULL) || (out == NULL) || (returnState == NULL)) {
211 LOGE("Invalid params.");
212 return HC_ERR_INVALID_PARAMS;
213 }
214 if ((cmd->curState == cmd->finishState) || (cmd->curState == cmd->failState)) {
215 LOGE("Invalid state!");
216 return HC_ERR_UNSUPPORTED_OPCODE;
217 }
218 return SwitchState(cmd, in, out, returnState);
219 }
220
DestroyMkAgreeCmd(BaseCmd * cmd)221 static void DestroyMkAgreeCmd(BaseCmd *cmd)
222 {
223 if (cmd == NULL) {
224 LOGE("cmd is null.");
225 return;
226 }
227 MkAgreeCmd *impl = (MkAgreeCmd *)cmd;
228 if (impl->task != NULL) {
229 impl->task->destroy(impl->task);
230 }
231 HcFree(impl);
232 }
233
InitMkAgreeTask(MkAgreeCmd * cmd,const MkAgreeParams * params,bool isClient)234 static int32_t InitMkAgreeTask(MkAgreeCmd *cmd, const MkAgreeParams *params, bool isClient)
235 {
236 CJson *json = CreateJson();
237 if (json == NULL) {
238 LOGE("Failed to create json param!");
239 return HC_ERR_JSON_CREATE;
240 }
241 if (AddBoolToJson(json, FIELD_IS_CLIENT, isClient) != HC_SUCCESS) {
242 LOGE("Failed to add isClient!");
243 FreeJson(json);
244 return HC_ERR_JSON_ADD;
245 }
246 if (AddIntToJson(json, FIELD_OS_ACCOUNT_ID, params->osAccountId) != HC_SUCCESS) {
247 LOGE("Failed to add osAccountId!");
248 FreeJson(json);
249 return HC_ERR_JSON_ADD;
250 }
251 if (AddStringToJson(json, FIELD_REAL_INFO, params->peerInfo) != HC_SUCCESS) {
252 LOGE("Failed to add peerInfo!");
253 FreeJson(json);
254 return HC_ERR_JSON_ADD;
255 }
256 if (AddStringToJson(json, FIELD_INDEX_KEY, params->pdidIndex) != HC_SUCCESS) {
257 LOGE("Failed to add pdidIndex!");
258 FreeJson(json);
259 return HC_ERR_JSON_ADD;
260 }
261 int32_t res = CreateMkAgreeTask(TASK_TYPE_PAKE, json, &cmd->task);
262 FreeJson(json);
263 if (res != HC_SUCCESS) {
264 LOGE("Failed to create mk agree task!");
265 }
266 return res;
267 }
268
InitMkAgreeCmd(MkAgreeCmd * cmd,const MkAgreeParams * params,bool isClient,int32_t strategy)269 static int32_t InitMkAgreeCmd(MkAgreeCmd *cmd, const MkAgreeParams *params,
270 bool isClient, int32_t strategy)
271 {
272 int32_t res = InitMkAgreeTask(cmd, params, isClient);
273 if (res != HC_SUCCESS) {
274 LOGE("Failed to init mk agree task!");
275 return res;
276 }
277 cmd->base.type = MK_AGREE_CMD_TYPE;
278 cmd->base.strategy = strategy;
279 cmd->base.isCaller = isClient;
280 cmd->base.beginState = isClient ? CLIENT_INIT_STATE : SERVER_WAIT_REQUEST_STATE;
281 cmd->base.finishState = FINISH_STATE;
282 cmd->base.failState = FAIL_STATE;
283 cmd->base.curState = cmd->base.beginState;
284 cmd->base.start = StartMkAgreeCmd;
285 cmd->base.process = ProcessMkAgreeCmd;
286 cmd->base.destroy = DestroyMkAgreeCmd;
287 return HC_SUCCESS;
288 }
289
CreateMkAgreeCmd(const void * baseParams,bool isClient,int32_t strategy)290 BaseCmd *CreateMkAgreeCmd(const void *baseParams, bool isClient, int32_t strategy)
291 {
292 if (baseParams == NULL) {
293 LOGE("Invalid input params!");
294 return NULL;
295 }
296 MkAgreeCmd *cmd = (MkAgreeCmd *)HcMalloc(sizeof(MkAgreeCmd), 0);
297 if (cmd == NULL) {
298 LOGE("Failed to allocate memory for cmd!");
299 return NULL;
300 }
301 const MkAgreeParams *params = (const MkAgreeParams *)baseParams;
302 int32_t res = InitMkAgreeCmd(cmd, params, isClient, strategy);
303 if (res != HC_SUCCESS) {
304 HcFree(cmd);
305 return NULL;
306 }
307 return (BaseCmd *)cmd;
308 }