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 "linked_list.h"
27 #include "idm_database.h"
28
29 #define SESSION_VALIDITY_PERIOD (10 * 60 * 1000)
30 #define MAX_CHALLENGE_GENERATION_TIMES 5
31
32 #ifdef IAM_TEST_ENABLE
33 #define IAM_STATIC
34 #else
35 #define IAM_STATIC static
36 #endif
37
38 // User IDM session information.
39 struct SessionInfo {
40 int32_t userId;
41 uint32_t authType;
42 uint64_t time;
43 uint64_t validAuthTokenTime;
44 uint8_t challenge[CHALLENGE_LEN];
45 uint64_t scheduleId;
46 bool isUpdate;
47 bool isScheduleValid;
48 } *g_session;
49
50 IAM_STATIC Buffer *g_cacheRootSecret = NULL;
51
DestroyCacheRootSecret(void)52 IAM_STATIC void DestroyCacheRootSecret(void)
53 {
54 DestoryBuffer(g_cacheRootSecret);
55 g_cacheRootSecret = NULL;
56 }
57
IsSessionExist(void)58 IAM_STATIC bool IsSessionExist(void)
59 {
60 if (g_session == NULL) {
61 LOG_INFO("the session does not exist");
62 return false;
63 }
64 return true;
65 }
66
GenerateChallenge(uint8_t * challenge,uint32_t challengeLen)67 IAM_STATIC ResultCode GenerateChallenge(uint8_t *challenge, uint32_t challengeLen)
68 {
69 for (uint32_t i = 0; i < MAX_CHALLENGE_GENERATION_TIMES; ++i) {
70 if (SecureRandom(challenge, challengeLen) != RESULT_SUCCESS) {
71 LOG_ERROR("get challenge failed");
72 return RESULT_GENERAL_ERROR;
73 }
74 for (uint32_t j = 0; j < challengeLen; j++) {
75 if (challenge[j] != 0) {
76 return RESULT_SUCCESS;
77 }
78 }
79 LOG_INFO("challenge is invalid, get again.");
80 }
81 LOG_ERROR("a rare failture");
82 return RESULT_GENERAL_ERROR;
83 }
84
OpenEditSession(int32_t userId,uint8_t * challenge,uint32_t challengeLen)85 ResultCode OpenEditSession(int32_t userId, uint8_t *challenge, uint32_t challengeLen)
86 {
87 if (challenge == NULL || challengeLen != CHALLENGE_LEN) {
88 LOG_ERROR("challenge is null");
89 return RESULT_BAD_PARAM;
90 }
91 (void)memset_s(challenge, CHALLENGE_LEN, 0, CHALLENGE_LEN);
92 if (IsSessionExist()) {
93 (void)CloseEditSession();
94 }
95 g_session = Malloc(sizeof(struct SessionInfo));
96 if (g_session == NULL) {
97 LOG_ERROR("g_session malloc failed");
98 return RESULT_NO_MEMORY;
99 }
100 if (memset_s(g_session, sizeof(struct SessionInfo), 0, sizeof(struct SessionInfo)) != EOK) {
101 LOG_ERROR("g_session set failed");
102 Free(g_session);
103 g_session = NULL;
104 return RESULT_GENERAL_ERROR;
105 }
106 g_session->userId = userId;
107 ResultCode ret = GenerateChallenge(g_session->challenge, CHALLENGE_LEN);
108 if (ret != RESULT_SUCCESS) {
109 LOG_ERROR("failed to generate challenge");
110 Free(g_session);
111 g_session = NULL;
112 return ret;
113 }
114 g_session->time = GetSystemTime();
115 g_session->validAuthTokenTime = g_session->time;
116
117 if (memcpy_s(challenge, CHALLENGE_LEN, g_session->challenge, CHALLENGE_LEN) != EOK) {
118 LOG_ERROR("failed to copy challenge");
119 Free(g_session);
120 g_session = NULL;
121 return RESULT_BAD_COPY;
122 }
123 g_session->isScheduleValid = false;
124 return RESULT_SUCCESS;
125 }
126
RefreshValidTokenTime(void)127 void RefreshValidTokenTime(void)
128 {
129 if (!IsSessionExist()) {
130 LOG_ERROR("session is invalid");
131 return;
132 }
133 g_session->validAuthTokenTime = GetSystemTime();
134 }
135
IsValidTokenTime(uint64_t tokenTime)136 bool IsValidTokenTime(uint64_t tokenTime)
137 {
138 if (!IsSessionExist()) {
139 LOG_ERROR("session is invalid");
140 return false;
141 }
142 return tokenTime >= g_session->validAuthTokenTime;
143 }
144
CloseEditSession(void)145 ResultCode CloseEditSession(void)
146 {
147 if (!IsSessionExist()) {
148 return RESULT_GENERAL_ERROR;
149 }
150 DestroyCacheRootSecret();
151 ClearCachePin(g_session->userId);
152 Free(g_session);
153 g_session = NULL;
154 return RESULT_SUCCESS;
155 }
156
GetUserId(int32_t * userId)157 ResultCode GetUserId(int32_t *userId)
158 {
159 if (userId == NULL || !IsSessionExist()) {
160 LOG_ERROR("param is invalid");
161 return RESULT_BAD_PARAM;
162 }
163 *userId = g_session->userId;
164 return RESULT_SUCCESS;
165 }
166
CheckChallenge(uint8_t * challenge,uint32_t challengeLen)167 ResultCode CheckChallenge(uint8_t *challenge, uint32_t challengeLen)
168 {
169 if (challenge == NULL || challengeLen != CHALLENGE_LEN) {
170 LOG_ERROR("param is invalid");
171 return RESULT_BAD_PARAM;
172 }
173 if (!IsSessionExist()) {
174 LOG_ERROR("param is invalid");
175 return RESULT_NEED_INIT;
176 }
177 if (memcmp(challenge, g_session->challenge, CHALLENGE_LEN) != EOK) {
178 LOG_ERROR("failed to compare challenge");
179 return RESULT_BAD_MATCH;
180 }
181 return RESULT_SUCCESS;
182 }
183
AssociateCoauthSchedule(uint64_t scheduleId,uint32_t authType,bool isUpdate)184 ResultCode AssociateCoauthSchedule(uint64_t scheduleId, uint32_t authType, bool isUpdate)
185 {
186 if (!IsSessionExist()) {
187 return RESULT_NEED_INIT;
188 }
189 g_session->scheduleId = scheduleId;
190 g_session->authType = authType;
191 g_session->isUpdate = isUpdate;
192 g_session->isScheduleValid = true;
193 return RESULT_SUCCESS;
194 }
195
BreakOffCoauthSchedule(void)196 void BreakOffCoauthSchedule(void)
197 {
198 if (!IsSessionExist()) {
199 return;
200 }
201 if (g_session->isScheduleValid) {
202 RemoveCoAuthSchedule(g_session->scheduleId);
203 }
204 g_session->isScheduleValid = false;
205 }
206
GetEnrollScheduleInfo(uint64_t * scheduleId,uint32_t * authType)207 ResultCode GetEnrollScheduleInfo(uint64_t *scheduleId, uint32_t *authType)
208 {
209 if (scheduleId == NULL || authType == NULL) {
210 LOG_ERROR("param is null");
211 return RESULT_BAD_PARAM;
212 }
213 if (!IsSessionExist() || g_session->isScheduleValid == false) {
214 return RESULT_NEED_INIT;
215 }
216 *scheduleId = g_session->scheduleId;
217 *authType = g_session->authType;
218 return RESULT_SUCCESS;
219 }
220
CheckSessionTimeout(void)221 ResultCode CheckSessionTimeout(void)
222 {
223 if (!IsSessionExist()) {
224 return RESULT_NEED_INIT;
225 }
226 uint64_t currentTime = GetSystemTime();
227 if (currentTime < g_session->time) {
228 LOG_ERROR("bad time, currentTime: %{public}" PRIu64 ", sessionTime: %{public}" PRIu64,
229 currentTime, g_session->time);
230 return RESULT_GENERAL_ERROR;
231 }
232 if (currentTime - g_session->time > SESSION_VALIDITY_PERIOD) {
233 LOG_ERROR("timeout, currentTime: %{public}" PRIu64 ", sessionTime: %{public}" PRIu64,
234 currentTime, g_session->time);
235 DestroyCacheRootSecret();
236 ClearCachePin(g_session->userId);
237 return RESULT_TIMEOUT;
238 }
239 return RESULT_SUCCESS;
240 }
241
GetIsUpdate(bool * isUpdate)242 ResultCode GetIsUpdate(bool *isUpdate)
243 {
244 if (isUpdate == NULL) {
245 LOG_ERROR("param is invalid");
246 return RESULT_BAD_PARAM;
247 }
248 if (!IsSessionExist() || g_session->isScheduleValid == false) {
249 LOG_ERROR("session need init");
250 return RESULT_NEED_INIT;
251 }
252 *isUpdate = g_session->isUpdate;
253 return RESULT_SUCCESS;
254 }
255
CheckSessionValid(int32_t userId)256 ResultCode CheckSessionValid(int32_t userId)
257 {
258 ResultCode ret = CheckSessionTimeout();
259 if (ret != RESULT_SUCCESS) {
260 return ret;
261 }
262 if (g_session->userId != userId) {
263 return RESULT_GENERAL_ERROR;
264 }
265 return RESULT_SUCCESS;
266 }
267
CacheRootSecret(int32_t userId,Buffer * rootSecret)268 void CacheRootSecret(int32_t userId, Buffer *rootSecret)
269 {
270 /* The presence of a session is the pin change phase */
271 if (CheckSessionTimeout() != RESULT_SUCCESS) {
272 return;
273 }
274 if (g_session->userId != userId) {
275 LOG_ERROR("CacheRootSecret check user id fail");
276 return;
277 }
278 if (!CheckBufferWithSize(rootSecret, ROOT_SECRET_LEN)) {
279 LOG_ERROR("check root secret fail");
280 return;
281 }
282 DestroyCacheRootSecret();
283 g_cacheRootSecret = CopyBuffer(rootSecret);
284 if (g_cacheRootSecret == NULL) {
285 LOG_ERROR("copy cache root secret fail");
286 }
287 }
288
GetCacheRootSecret(int32_t userId)289 Buffer *GetCacheRootSecret(int32_t userId)
290 {
291 if (CheckSessionTimeout() != RESULT_SUCCESS) {
292 return NULL;
293 }
294 if (g_session->userId != userId) {
295 LOG_ERROR("GetCacheRootSecret check user id fail");
296 return NULL;
297 }
298 if (g_cacheRootSecret == NULL) {
299 LOG_ERROR("no cache root secret");
300 return NULL;
301 }
302 return CopyBuffer(g_cacheRootSecret);
303 }
304
GetChallenge(uint8_t * challenge,uint32_t challengeLen)305 ResultCode GetChallenge(uint8_t *challenge, uint32_t challengeLen)
306 {
307 if ((challenge == NULL) || (challengeLen != CHALLENGE_LEN)) {
308 LOG_ERROR("challenge is invalid");
309 return RESULT_BAD_PARAM;
310 }
311
312 ResultCode ret = CheckSessionTimeout();
313 if (ret != RESULT_SUCCESS) {
314 LOG_ERROR("session does not exist");
315 return ret;
316 }
317 if (memcpy_s(challenge, challengeLen, g_session->challenge, CHALLENGE_LEN) != EOK) {
318 LOG_ERROR("copy challenge failed");
319 return RESULT_GENERAL_ERROR;
320 }
321
322 return RESULT_SUCCESS;
323 }
324
IsValidUserType(int32_t userType)325 ResultCode IsValidUserType(int32_t userType)
326 {
327 if (userType != MAIN_USER && userType != SUB_USER && userType != PRIVATE_USER) {
328 LOG_ERROR("userType is invalid");
329 return RESULT_BAD_PARAM;
330 }
331 LOG_INFO("userType is valid");
332 return RESULT_SUCCESS;
333 }