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. 39struct 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 50IAM_STATIC Buffer *g_cacheRootSecret = NULL; 51 52IAM_STATIC void DestroyCacheRootSecret(void) 53{ 54 DestoryBuffer(g_cacheRootSecret); 55 g_cacheRootSecret = NULL; 56} 57 58IAM_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 67IAM_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 85ResultCode 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 127void RefreshValidTokenTime(void) 128{ 129 if (!IsSessionExist()) { 130 LOG_ERROR("session is invalid"); 131 return; 132 } 133 g_session->validAuthTokenTime = GetSystemTime(); 134} 135 136bool 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 145ResultCode 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 157ResultCode 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 167ResultCode 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 184ResultCode 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 196void 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 207ResultCode 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 221ResultCode 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 242ResultCode 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 256ResultCode 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 268void 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 289Buffer *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 305ResultCode 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 325ResultCode 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}