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 "idm_session.h"
17
18 #include <inttypes.h>
19 #include "securec.h"
20
21 #include "adaptor_algorithm.h"
22 #include "adaptor_log.h"
23 #include "adaptor_memory.h"
24 #include "adaptor_time.h"
25 #include "coauth.h"
26 #include "buffer.h"
27 #include "linked_list.h"
28 #include "idm_database.h"
29
30 #define SESSION_VALIDITY_PERIOD (10 * 60 * 1000)
31 #define MAX_CHALLENGE_GENERATION_TIMES 5
32
33 #ifdef IAM_TEST_ENABLE
34 #define IAM_STATIC
35 #else
36 #define IAM_STATIC static
37 #endif
38
39 // User IDM session information.
40 struct SessionInfo {
41 int32_t userId;
42 uint32_t authType;
43 uint64_t time;
44 uint64_t validAuthTokenTime;
45 uint8_t challenge[CHALLENGE_LEN];
46 uint64_t scheduleId;
47 ScheduleType scheduleType;
48 bool isScheduleValid;
49 PinChangeScence pinChangeScence;
50 Buffer *oldRootSecret;
51 Buffer *curRootSecret;
52 Buffer *newRootSecret;
53 } *g_session;
54
IsSessionExist(void)55 IAM_STATIC bool IsSessionExist(void)
56 {
57 if (g_session == NULL) {
58 LOG_INFO("the session does not exist");
59 return false;
60 }
61 return true;
62 }
63
GenerateChallenge(uint8_t * challenge,uint32_t challengeLen)64 IAM_STATIC ResultCode GenerateChallenge(uint8_t *challenge, uint32_t challengeLen)
65 {
66 for (uint32_t i = 0; i < MAX_CHALLENGE_GENERATION_TIMES; ++i) {
67 if (SecureRandom(challenge, challengeLen) != RESULT_SUCCESS) {
68 LOG_ERROR("get challenge failed");
69 return RESULT_GENERAL_ERROR;
70 }
71 for (uint32_t j = 0; j < challengeLen; j++) {
72 if (challenge[j] != 0) {
73 return RESULT_SUCCESS;
74 }
75 }
76 LOG_INFO("challenge is invalid, get again.");
77 }
78 LOG_ERROR("a rare failture");
79 return RESULT_GENERAL_ERROR;
80 }
81
OpenEditSession(int32_t userId,uint8_t * challenge,uint32_t challengeLen)82 ResultCode OpenEditSession(int32_t userId, uint8_t *challenge, uint32_t challengeLen)
83 {
84 if (challenge == NULL || challengeLen != CHALLENGE_LEN) {
85 LOG_ERROR("challenge is null");
86 return RESULT_BAD_PARAM;
87 }
88 (void)memset_s(challenge, CHALLENGE_LEN, 0, CHALLENGE_LEN);
89 if (IsSessionExist()) {
90 (void)CloseEditSession();
91 }
92 g_session = Malloc(sizeof(struct SessionInfo));
93 if (g_session == NULL) {
94 LOG_ERROR("g_session malloc failed");
95 return RESULT_NO_MEMORY;
96 }
97 if (memset_s(g_session, sizeof(struct SessionInfo), 0, sizeof(struct SessionInfo)) != EOK) {
98 LOG_ERROR("g_session set failed");
99 Free(g_session);
100 g_session = NULL;
101 return RESULT_GENERAL_ERROR;
102 }
103 g_session->userId = userId;
104 ResultCode ret = GenerateChallenge(g_session->challenge, CHALLENGE_LEN);
105 if (ret != RESULT_SUCCESS) {
106 LOG_ERROR("failed to generate challenge");
107 Free(g_session);
108 g_session = NULL;
109 return ret;
110 }
111 g_session->time = GetSystemTime();
112 g_session->validAuthTokenTime = g_session->time;
113
114 if (memcpy_s(challenge, CHALLENGE_LEN, g_session->challenge, CHALLENGE_LEN) != EOK) {
115 LOG_ERROR("failed to copy challenge");
116 Free(g_session);
117 g_session = NULL;
118 return RESULT_BAD_COPY;
119 }
120 g_session->isScheduleValid = false;
121 return RESULT_SUCCESS;
122 }
123
RefreshValidTokenTime(void)124 void RefreshValidTokenTime(void)
125 {
126 if (!IsSessionExist()) {
127 LOG_ERROR("session is invalid");
128 return;
129 }
130 g_session->validAuthTokenTime = GetSystemTime();
131 }
132
IsValidTokenTime(uint64_t tokenTime)133 bool IsValidTokenTime(uint64_t tokenTime)
134 {
135 if (!IsSessionExist()) {
136 LOG_ERROR("session is invalid");
137 return false;
138 }
139 return tokenTime >= g_session->validAuthTokenTime;
140 }
141
CloseEditSession(void)142 ResultCode CloseEditSession(void)
143 {
144 if (!IsSessionExist()) {
145 return RESULT_GENERAL_ERROR;
146 }
147 ClearCachePin(g_session->userId);
148 DestoryBuffer(g_session->oldRootSecret);
149 DestoryBuffer(g_session->curRootSecret);
150 DestoryBuffer(g_session->newRootSecret);
151 Free(g_session);
152 g_session = NULL;
153 return RESULT_SUCCESS;
154 }
155
GetUserId(int32_t * userId)156 ResultCode GetUserId(int32_t *userId)
157 {
158 if (userId == NULL || !IsSessionExist()) {
159 LOG_ERROR("param is invalid");
160 return RESULT_BAD_PARAM;
161 }
162 *userId = g_session->userId;
163 return RESULT_SUCCESS;
164 }
165
CheckChallenge(const uint8_t * challenge,uint32_t challengeLen)166 ResultCode CheckChallenge(const uint8_t *challenge, uint32_t challengeLen)
167 {
168 if (challenge == NULL || challengeLen != CHALLENGE_LEN) {
169 LOG_ERROR("param is invalid");
170 return RESULT_BAD_PARAM;
171 }
172 if (!IsSessionExist()) {
173 LOG_ERROR("param is invalid");
174 return RESULT_NEED_INIT;
175 }
176 if (memcmp(challenge, g_session->challenge, CHALLENGE_LEN) != EOK) {
177 LOG_ERROR("failed to compare challenge");
178 return RESULT_BAD_MATCH;
179 }
180 return RESULT_SUCCESS;
181 }
182
AssociateCoauthSchedule(uint64_t scheduleId,uint32_t authType,ScheduleType scheduleType)183 ResultCode AssociateCoauthSchedule(uint64_t scheduleId, uint32_t authType, ScheduleType scheduleType)
184 {
185 LOG_INFO("start");
186 if (!IsSessionExist()) {
187 LOG_ERROR("session is not exist");
188 return RESULT_NEED_INIT;
189 }
190 g_session->scheduleId = scheduleId;
191 g_session->authType = authType;
192 g_session->scheduleType = scheduleType;
193 g_session->isScheduleValid = true;
194 return RESULT_SUCCESS;
195 }
196
BreakOffCoauthSchedule(void)197 void BreakOffCoauthSchedule(void)
198 {
199 if (!IsSessionExist()) {
200 return;
201 }
202 if (g_session->isScheduleValid) {
203 RemoveCoAuthSchedule(g_session->scheduleId);
204 }
205 g_session->isScheduleValid = false;
206 }
207
GetEnrollScheduleInfo(uint64_t * scheduleId,uint32_t * authType)208 ResultCode GetEnrollScheduleInfo(uint64_t *scheduleId, uint32_t *authType)
209 {
210 if (scheduleId == NULL || authType == NULL) {
211 LOG_ERROR("param is null");
212 return RESULT_BAD_PARAM;
213 }
214 if (!IsSessionExist() || g_session->isScheduleValid == false) {
215 return RESULT_NEED_INIT;
216 }
217 *scheduleId = g_session->scheduleId;
218 *authType = g_session->authType;
219 return RESULT_SUCCESS;
220 }
221
CheckSessionTimeout(void)222 ResultCode CheckSessionTimeout(void)
223 {
224 if (!IsSessionExist()) {
225 return RESULT_NEED_INIT;
226 }
227 uint64_t currentTime = GetSystemTime();
228 if (currentTime < g_session->time) {
229 LOG_ERROR("bad time, currentTime: %{public}" PRIu64 ", sessionTime: %{public}" PRIu64,
230 currentTime, g_session->time);
231 return RESULT_GENERAL_ERROR;
232 }
233 if (currentTime - g_session->time > SESSION_VALIDITY_PERIOD) {
234 LOG_ERROR("timeout, currentTime: %{public}" PRIu64 ", sessionTime: %{public}" PRIu64,
235 currentTime, g_session->time);
236 DestoryBuffer(g_session->oldRootSecret);
237 ClearCachePin(g_session->userId);
238 return RESULT_TIMEOUT;
239 }
240 return RESULT_SUCCESS;
241 }
242
GetScheduleType(ScheduleType * scheduleType)243 ResultCode GetScheduleType(ScheduleType *scheduleType)
244 {
245 if (scheduleType == NULL) {
246 LOG_ERROR("param is invalid");
247 return RESULT_BAD_PARAM;
248 }
249 if (!IsSessionExist() || g_session->isScheduleValid == false) {
250 LOG_ERROR("session need init");
251 return RESULT_NEED_INIT;
252 }
253 *scheduleType = g_session->scheduleType;
254 return RESULT_SUCCESS;
255 }
256
CheckSessionValid(int32_t userId)257 ResultCode CheckSessionValid(int32_t userId)
258 {
259 ResultCode ret = CheckSessionTimeout();
260 if (ret != RESULT_SUCCESS) {
261 return ret;
262 }
263 if (g_session->userId != userId) {
264 return RESULT_GENERAL_ERROR;
265 }
266 return RESULT_SUCCESS;
267 }
268
GetChallenge(uint8_t * challenge,uint32_t challengeLen)269 ResultCode GetChallenge(uint8_t *challenge, uint32_t challengeLen)
270 {
271 if ((challenge == NULL) || (challengeLen != CHALLENGE_LEN)) {
272 LOG_ERROR("challenge is invalid");
273 return RESULT_BAD_PARAM;
274 }
275
276 ResultCode ret = CheckSessionTimeout();
277 if (ret != RESULT_SUCCESS) {
278 LOG_ERROR("session does not exist");
279 return ret;
280 }
281 if (memcpy_s(challenge, challengeLen, g_session->challenge, CHALLENGE_LEN) != EOK) {
282 LOG_ERROR("copy challenge failed");
283 return RESULT_GENERAL_ERROR;
284 }
285
286 return RESULT_SUCCESS;
287 }
288
IsValidUserType(int32_t userType)289 ResultCode IsValidUserType(int32_t userType)
290 {
291 if (userType != MAIN_USER && userType != SUB_USER && userType != PRIVATE_USER) {
292 LOG_ERROR("userType is invalid");
293 return RESULT_BAD_PARAM;
294 }
295 LOG_INFO("userType is valid");
296 return RESULT_SUCCESS;
297 }
298
SetPinChangeScence(int32_t userId,uint32_t authIntent)299 void SetPinChangeScence(int32_t userId, uint32_t authIntent)
300 {
301 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
302 LOG_ERROR("session is invalid, userId: %{public}d", userId);
303 return;
304 }
305 if (authIntent == ABANDONED_PIN_AUTH) {
306 g_session->pinChangeScence = PIN_RESET_SCENCE;
307 } else {
308 g_session->pinChangeScence = PIN_UPDATE_SCENCE;
309 }
310 LOG_INFO("pinChangeScence: %{public}d", g_session->pinChangeScence);
311 return;
312 }
313
GetPinChangeScence(int32_t userId)314 PinChangeScence GetPinChangeScence(int32_t userId)
315 {
316 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
317 LOG_ERROR("session is invalid, userId: %{public}d", userId);
318 return 0;
319 }
320 LOG_INFO("pinChangeScence: %{public}d", g_session->pinChangeScence);
321 return g_session->pinChangeScence;
322 }
323
SetOldRootSecret(int32_t userId,Buffer * rootSecret)324 void SetOldRootSecret(int32_t userId, Buffer *rootSecret)
325 {
326 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
327 LOG_ERROR("session is invalid, userId: %{public}d", userId);
328 return;
329 }
330
331 if (!CheckBufferWithSize(rootSecret, ROOT_SECRET_LEN)) {
332 LOG_ERROR("rootSecret is invalid, userId: %{public}d", userId);
333 return;
334 }
335
336 DestoryBuffer(g_session->oldRootSecret);
337 g_session->oldRootSecret = CreateBufferByData(rootSecret->buf, rootSecret->contentSize);
338 if (g_session->oldRootSecret == NULL) {
339 LOG_ERROR("CreateBufferByData fail, userId: %{public}d", userId);
340 return;
341 }
342
343 return;
344 }
345
GetOldRootSecret(int32_t userId)346 Buffer *GetOldRootSecret(int32_t userId)
347 {
348 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
349 LOG_ERROR("session is invalid, userId: %{public}d", userId);
350 return NULL;
351 }
352 return g_session->oldRootSecret;
353 }
354
SetCurRootSecret(int32_t userId,Buffer * rootSecret)355 void SetCurRootSecret(int32_t userId, Buffer *rootSecret)
356 {
357 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
358 LOG_ERROR("session is invalid, userId: %{public}d", userId);
359 return;
360 }
361
362 if (!CheckBufferWithSize(rootSecret, ROOT_SECRET_LEN)) {
363 LOG_ERROR("rootSecret is invalid, userId: %{public}d", userId);
364 return;
365 }
366
367 DestoryBuffer(g_session->curRootSecret);
368 g_session->curRootSecret = CreateBufferByData(rootSecret->buf, rootSecret->contentSize);
369 if (g_session->curRootSecret == NULL) {
370 LOG_ERROR("CreateBufferByData fail, userId: %{public}d", userId);
371 return;
372 }
373
374 return;
375 }
376
GetCurRootSecret(int32_t userId)377 Buffer *GetCurRootSecret(int32_t userId)
378 {
379 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
380 LOG_ERROR("session is invalid, userId: %{public}d", userId);
381 return NULL;
382 }
383 return g_session->curRootSecret;
384 }
385
SetNewRootSecret(int32_t userId,Buffer * rootSecret)386 ResultCode SetNewRootSecret(int32_t userId, Buffer *rootSecret)
387 {
388 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
389 LOG_ERROR("session is invalid, userId: %{public}d", userId);
390 return RESULT_GENERAL_ERROR;
391 }
392
393 if (!CheckBufferWithSize(rootSecret, ROOT_SECRET_LEN)) {
394 LOG_ERROR("rootSecret is invalid, userId: %{public}d", userId);
395 return RESULT_GENERAL_ERROR;
396 }
397
398 DestoryBuffer(g_session->newRootSecret);
399 g_session->newRootSecret = CreateBufferByData(rootSecret->buf, rootSecret->contentSize);
400 if (g_session->newRootSecret == NULL) {
401 LOG_ERROR("CreateBufferByData fail, userId: %{public}d", userId);
402 return RESULT_NO_MEMORY;
403 }
404
405 return RESULT_SUCCESS;
406 }
407
GetNewRootSecret(int32_t userId)408 Buffer *GetNewRootSecret(int32_t userId)
409 {
410 if (CheckSessionValid(userId) != RESULT_SUCCESS) {
411 LOG_ERROR("session is invalid, userId: %{public}d", userId);
412 return NULL;
413 }
414 return g_session->newRootSecret;
415 }