1094332d3Sopenharmony_ci/*
2094332d3Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3094332d3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4094332d3Sopenharmony_ci * you may not use this file except in compliance with the License.
5094332d3Sopenharmony_ci * You may obtain a copy of the License at
6094332d3Sopenharmony_ci *
7094332d3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8094332d3Sopenharmony_ci *
9094332d3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10094332d3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11094332d3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12094332d3Sopenharmony_ci * See the License for the specific language governing permissions and
13094332d3Sopenharmony_ci * limitations under the License.
14094332d3Sopenharmony_ci */
15094332d3Sopenharmony_ci
16094332d3Sopenharmony_ci#include "idm_session.h"
17094332d3Sopenharmony_ci
18094332d3Sopenharmony_ci#include <inttypes.h>
19094332d3Sopenharmony_ci#include "securec.h"
20094332d3Sopenharmony_ci
21094332d3Sopenharmony_ci#include "adaptor_algorithm.h"
22094332d3Sopenharmony_ci#include "adaptor_log.h"
23094332d3Sopenharmony_ci#include "adaptor_memory.h"
24094332d3Sopenharmony_ci#include "adaptor_time.h"
25094332d3Sopenharmony_ci#include "coauth.h"
26094332d3Sopenharmony_ci#include "linked_list.h"
27094332d3Sopenharmony_ci#include "idm_database.h"
28094332d3Sopenharmony_ci
29094332d3Sopenharmony_ci#define SESSION_VALIDITY_PERIOD (10 * 60 * 1000)
30094332d3Sopenharmony_ci#define MAX_CHALLENGE_GENERATION_TIMES 5
31094332d3Sopenharmony_ci
32094332d3Sopenharmony_ci#ifdef IAM_TEST_ENABLE
33094332d3Sopenharmony_ci#define IAM_STATIC
34094332d3Sopenharmony_ci#else
35094332d3Sopenharmony_ci#define IAM_STATIC static
36094332d3Sopenharmony_ci#endif
37094332d3Sopenharmony_ci
38094332d3Sopenharmony_ci// User IDM session information.
39094332d3Sopenharmony_cistruct SessionInfo {
40094332d3Sopenharmony_ci    int32_t userId;
41094332d3Sopenharmony_ci    uint32_t authType;
42094332d3Sopenharmony_ci    uint64_t time;
43094332d3Sopenharmony_ci    uint64_t validAuthTokenTime;
44094332d3Sopenharmony_ci    uint8_t challenge[CHALLENGE_LEN];
45094332d3Sopenharmony_ci    uint64_t scheduleId;
46094332d3Sopenharmony_ci    bool isUpdate;
47094332d3Sopenharmony_ci    bool isScheduleValid;
48094332d3Sopenharmony_ci} *g_session;
49094332d3Sopenharmony_ci
50094332d3Sopenharmony_ciIAM_STATIC Buffer *g_cacheRootSecret = NULL;
51094332d3Sopenharmony_ci
52094332d3Sopenharmony_ciIAM_STATIC void DestroyCacheRootSecret(void)
53094332d3Sopenharmony_ci{
54094332d3Sopenharmony_ci    DestoryBuffer(g_cacheRootSecret);
55094332d3Sopenharmony_ci    g_cacheRootSecret = NULL;
56094332d3Sopenharmony_ci}
57094332d3Sopenharmony_ci
58094332d3Sopenharmony_ciIAM_STATIC bool IsSessionExist(void)
59094332d3Sopenharmony_ci{
60094332d3Sopenharmony_ci    if (g_session == NULL) {
61094332d3Sopenharmony_ci        LOG_INFO("the session does not exist");
62094332d3Sopenharmony_ci        return false;
63094332d3Sopenharmony_ci    }
64094332d3Sopenharmony_ci    return true;
65094332d3Sopenharmony_ci}
66094332d3Sopenharmony_ci
67094332d3Sopenharmony_ciIAM_STATIC ResultCode GenerateChallenge(uint8_t *challenge, uint32_t challengeLen)
68094332d3Sopenharmony_ci{
69094332d3Sopenharmony_ci    for (uint32_t i = 0; i < MAX_CHALLENGE_GENERATION_TIMES; ++i) {
70094332d3Sopenharmony_ci        if (SecureRandom(challenge, challengeLen) != RESULT_SUCCESS) {
71094332d3Sopenharmony_ci            LOG_ERROR("get challenge failed");
72094332d3Sopenharmony_ci            return RESULT_GENERAL_ERROR;
73094332d3Sopenharmony_ci        }
74094332d3Sopenharmony_ci        for (uint32_t j = 0; j < challengeLen; j++) {
75094332d3Sopenharmony_ci            if (challenge[j] != 0) {
76094332d3Sopenharmony_ci                return RESULT_SUCCESS;
77094332d3Sopenharmony_ci            }
78094332d3Sopenharmony_ci        }
79094332d3Sopenharmony_ci        LOG_INFO("challenge is invalid, get again.");
80094332d3Sopenharmony_ci    }
81094332d3Sopenharmony_ci    LOG_ERROR("a rare failture");
82094332d3Sopenharmony_ci    return RESULT_GENERAL_ERROR;
83094332d3Sopenharmony_ci}
84094332d3Sopenharmony_ci
85094332d3Sopenharmony_ciResultCode OpenEditSession(int32_t userId, uint8_t *challenge, uint32_t challengeLen)
86094332d3Sopenharmony_ci{
87094332d3Sopenharmony_ci    if (challenge == NULL || challengeLen != CHALLENGE_LEN) {
88094332d3Sopenharmony_ci        LOG_ERROR("challenge is null");
89094332d3Sopenharmony_ci        return RESULT_BAD_PARAM;
90094332d3Sopenharmony_ci    }
91094332d3Sopenharmony_ci    (void)memset_s(challenge, CHALLENGE_LEN, 0, CHALLENGE_LEN);
92094332d3Sopenharmony_ci    if (IsSessionExist()) {
93094332d3Sopenharmony_ci        (void)CloseEditSession();
94094332d3Sopenharmony_ci    }
95094332d3Sopenharmony_ci    g_session = Malloc(sizeof(struct SessionInfo));
96094332d3Sopenharmony_ci    if (g_session == NULL) {
97094332d3Sopenharmony_ci        LOG_ERROR("g_session malloc failed");
98094332d3Sopenharmony_ci        return RESULT_NO_MEMORY;
99094332d3Sopenharmony_ci    }
100094332d3Sopenharmony_ci    if (memset_s(g_session, sizeof(struct SessionInfo), 0, sizeof(struct SessionInfo)) != EOK) {
101094332d3Sopenharmony_ci        LOG_ERROR("g_session set failed");
102094332d3Sopenharmony_ci        Free(g_session);
103094332d3Sopenharmony_ci        g_session = NULL;
104094332d3Sopenharmony_ci        return RESULT_GENERAL_ERROR;
105094332d3Sopenharmony_ci    }
106094332d3Sopenharmony_ci    g_session->userId = userId;
107094332d3Sopenharmony_ci    ResultCode ret = GenerateChallenge(g_session->challenge, CHALLENGE_LEN);
108094332d3Sopenharmony_ci    if (ret != RESULT_SUCCESS) {
109094332d3Sopenharmony_ci        LOG_ERROR("failed to generate challenge");
110094332d3Sopenharmony_ci        Free(g_session);
111094332d3Sopenharmony_ci        g_session = NULL;
112094332d3Sopenharmony_ci        return ret;
113094332d3Sopenharmony_ci    }
114094332d3Sopenharmony_ci    g_session->time = GetSystemTime();
115094332d3Sopenharmony_ci    g_session->validAuthTokenTime = g_session->time;
116094332d3Sopenharmony_ci
117094332d3Sopenharmony_ci    if (memcpy_s(challenge, CHALLENGE_LEN, g_session->challenge, CHALLENGE_LEN) != EOK) {
118094332d3Sopenharmony_ci        LOG_ERROR("failed to copy challenge");
119094332d3Sopenharmony_ci        Free(g_session);
120094332d3Sopenharmony_ci        g_session = NULL;
121094332d3Sopenharmony_ci        return RESULT_BAD_COPY;
122094332d3Sopenharmony_ci    }
123094332d3Sopenharmony_ci    g_session->isScheduleValid = false;
124094332d3Sopenharmony_ci    return RESULT_SUCCESS;
125094332d3Sopenharmony_ci}
126094332d3Sopenharmony_ci
127094332d3Sopenharmony_civoid RefreshValidTokenTime(void)
128094332d3Sopenharmony_ci{
129094332d3Sopenharmony_ci    if (!IsSessionExist()) {
130094332d3Sopenharmony_ci        LOG_ERROR("session is invalid");
131094332d3Sopenharmony_ci        return;
132094332d3Sopenharmony_ci    }
133094332d3Sopenharmony_ci    g_session->validAuthTokenTime = GetSystemTime();
134094332d3Sopenharmony_ci}
135094332d3Sopenharmony_ci
136094332d3Sopenharmony_cibool IsValidTokenTime(uint64_t tokenTime)
137094332d3Sopenharmony_ci{
138094332d3Sopenharmony_ci    if (!IsSessionExist()) {
139094332d3Sopenharmony_ci        LOG_ERROR("session is invalid");
140094332d3Sopenharmony_ci        return false;
141094332d3Sopenharmony_ci    }
142094332d3Sopenharmony_ci    return tokenTime >= g_session->validAuthTokenTime;
143094332d3Sopenharmony_ci}
144094332d3Sopenharmony_ci
145094332d3Sopenharmony_ciResultCode CloseEditSession(void)
146094332d3Sopenharmony_ci{
147094332d3Sopenharmony_ci    if (!IsSessionExist()) {
148094332d3Sopenharmony_ci        return RESULT_GENERAL_ERROR;
149094332d3Sopenharmony_ci    }
150094332d3Sopenharmony_ci    DestroyCacheRootSecret();
151094332d3Sopenharmony_ci    ClearCachePin(g_session->userId);
152094332d3Sopenharmony_ci    Free(g_session);
153094332d3Sopenharmony_ci    g_session = NULL;
154094332d3Sopenharmony_ci    return RESULT_SUCCESS;
155094332d3Sopenharmony_ci}
156094332d3Sopenharmony_ci
157094332d3Sopenharmony_ciResultCode GetUserId(int32_t *userId)
158094332d3Sopenharmony_ci{
159094332d3Sopenharmony_ci    if (userId == NULL || !IsSessionExist()) {
160094332d3Sopenharmony_ci        LOG_ERROR("param is invalid");
161094332d3Sopenharmony_ci        return RESULT_BAD_PARAM;
162094332d3Sopenharmony_ci    }
163094332d3Sopenharmony_ci    *userId = g_session->userId;
164094332d3Sopenharmony_ci    return RESULT_SUCCESS;
165094332d3Sopenharmony_ci}
166094332d3Sopenharmony_ci
167094332d3Sopenharmony_ciResultCode CheckChallenge(uint8_t *challenge, uint32_t challengeLen)
168094332d3Sopenharmony_ci{
169094332d3Sopenharmony_ci    if (challenge == NULL || challengeLen != CHALLENGE_LEN) {
170094332d3Sopenharmony_ci        LOG_ERROR("param is invalid");
171094332d3Sopenharmony_ci        return RESULT_BAD_PARAM;
172094332d3Sopenharmony_ci    }
173094332d3Sopenharmony_ci    if (!IsSessionExist()) {
174094332d3Sopenharmony_ci        LOG_ERROR("param is invalid");
175094332d3Sopenharmony_ci        return RESULT_NEED_INIT;
176094332d3Sopenharmony_ci    }
177094332d3Sopenharmony_ci    if (memcmp(challenge, g_session->challenge, CHALLENGE_LEN) != EOK) {
178094332d3Sopenharmony_ci        LOG_ERROR("failed to compare challenge");
179094332d3Sopenharmony_ci        return RESULT_BAD_MATCH;
180094332d3Sopenharmony_ci    }
181094332d3Sopenharmony_ci    return RESULT_SUCCESS;
182094332d3Sopenharmony_ci}
183094332d3Sopenharmony_ci
184094332d3Sopenharmony_ciResultCode AssociateCoauthSchedule(uint64_t scheduleId, uint32_t authType, bool isUpdate)
185094332d3Sopenharmony_ci{
186094332d3Sopenharmony_ci    if (!IsSessionExist()) {
187094332d3Sopenharmony_ci        return RESULT_NEED_INIT;
188094332d3Sopenharmony_ci    }
189094332d3Sopenharmony_ci    g_session->scheduleId = scheduleId;
190094332d3Sopenharmony_ci    g_session->authType = authType;
191094332d3Sopenharmony_ci    g_session->isUpdate = isUpdate;
192094332d3Sopenharmony_ci    g_session->isScheduleValid = true;
193094332d3Sopenharmony_ci    return RESULT_SUCCESS;
194094332d3Sopenharmony_ci}
195094332d3Sopenharmony_ci
196094332d3Sopenharmony_civoid BreakOffCoauthSchedule(void)
197094332d3Sopenharmony_ci{
198094332d3Sopenharmony_ci    if (!IsSessionExist()) {
199094332d3Sopenharmony_ci        return;
200094332d3Sopenharmony_ci    }
201094332d3Sopenharmony_ci    if (g_session->isScheduleValid) {
202094332d3Sopenharmony_ci        RemoveCoAuthSchedule(g_session->scheduleId);
203094332d3Sopenharmony_ci    }
204094332d3Sopenharmony_ci    g_session->isScheduleValid = false;
205094332d3Sopenharmony_ci}
206094332d3Sopenharmony_ci
207094332d3Sopenharmony_ciResultCode GetEnrollScheduleInfo(uint64_t *scheduleId, uint32_t *authType)
208094332d3Sopenharmony_ci{
209094332d3Sopenharmony_ci    if (scheduleId == NULL || authType == NULL) {
210094332d3Sopenharmony_ci        LOG_ERROR("param is null");
211094332d3Sopenharmony_ci        return RESULT_BAD_PARAM;
212094332d3Sopenharmony_ci    }
213094332d3Sopenharmony_ci    if (!IsSessionExist() || g_session->isScheduleValid == false) {
214094332d3Sopenharmony_ci        return RESULT_NEED_INIT;
215094332d3Sopenharmony_ci    }
216094332d3Sopenharmony_ci    *scheduleId = g_session->scheduleId;
217094332d3Sopenharmony_ci    *authType = g_session->authType;
218094332d3Sopenharmony_ci    return RESULT_SUCCESS;
219094332d3Sopenharmony_ci}
220094332d3Sopenharmony_ci
221094332d3Sopenharmony_ciResultCode CheckSessionTimeout(void)
222094332d3Sopenharmony_ci{
223094332d3Sopenharmony_ci    if (!IsSessionExist()) {
224094332d3Sopenharmony_ci        return RESULT_NEED_INIT;
225094332d3Sopenharmony_ci    }
226094332d3Sopenharmony_ci    uint64_t currentTime = GetSystemTime();
227094332d3Sopenharmony_ci    if (currentTime < g_session->time) {
228094332d3Sopenharmony_ci        LOG_ERROR("bad time, currentTime: %{public}" PRIu64 ", sessionTime: %{public}" PRIu64,
229094332d3Sopenharmony_ci            currentTime, g_session->time);
230094332d3Sopenharmony_ci        return RESULT_GENERAL_ERROR;
231094332d3Sopenharmony_ci    }
232094332d3Sopenharmony_ci    if (currentTime - g_session->time > SESSION_VALIDITY_PERIOD) {
233094332d3Sopenharmony_ci        LOG_ERROR("timeout, currentTime: %{public}" PRIu64 ", sessionTime: %{public}" PRIu64,
234094332d3Sopenharmony_ci            currentTime, g_session->time);
235094332d3Sopenharmony_ci        DestroyCacheRootSecret();
236094332d3Sopenharmony_ci        ClearCachePin(g_session->userId);
237094332d3Sopenharmony_ci        return RESULT_TIMEOUT;
238094332d3Sopenharmony_ci    }
239094332d3Sopenharmony_ci    return RESULT_SUCCESS;
240094332d3Sopenharmony_ci}
241094332d3Sopenharmony_ci
242094332d3Sopenharmony_ciResultCode GetIsUpdate(bool *isUpdate)
243094332d3Sopenharmony_ci{
244094332d3Sopenharmony_ci    if (isUpdate == NULL) {
245094332d3Sopenharmony_ci        LOG_ERROR("param is invalid");
246094332d3Sopenharmony_ci        return RESULT_BAD_PARAM;
247094332d3Sopenharmony_ci    }
248094332d3Sopenharmony_ci    if (!IsSessionExist() || g_session->isScheduleValid == false) {
249094332d3Sopenharmony_ci        LOG_ERROR("session need init");
250094332d3Sopenharmony_ci        return RESULT_NEED_INIT;
251094332d3Sopenharmony_ci    }
252094332d3Sopenharmony_ci    *isUpdate = g_session->isUpdate;
253094332d3Sopenharmony_ci    return RESULT_SUCCESS;
254094332d3Sopenharmony_ci}
255094332d3Sopenharmony_ci
256094332d3Sopenharmony_ciResultCode CheckSessionValid(int32_t userId)
257094332d3Sopenharmony_ci{
258094332d3Sopenharmony_ci    ResultCode ret = CheckSessionTimeout();
259094332d3Sopenharmony_ci    if (ret != RESULT_SUCCESS) {
260094332d3Sopenharmony_ci        return ret;
261094332d3Sopenharmony_ci    }
262094332d3Sopenharmony_ci    if (g_session->userId != userId) {
263094332d3Sopenharmony_ci        return RESULT_GENERAL_ERROR;
264094332d3Sopenharmony_ci    }
265094332d3Sopenharmony_ci    return RESULT_SUCCESS;
266094332d3Sopenharmony_ci}
267094332d3Sopenharmony_ci
268094332d3Sopenharmony_civoid CacheRootSecret(int32_t userId, Buffer *rootSecret)
269094332d3Sopenharmony_ci{
270094332d3Sopenharmony_ci    /* The presence of a session is the pin change phase */
271094332d3Sopenharmony_ci    if (CheckSessionTimeout() != RESULT_SUCCESS) {
272094332d3Sopenharmony_ci        return;
273094332d3Sopenharmony_ci    }
274094332d3Sopenharmony_ci    if (g_session->userId != userId) {
275094332d3Sopenharmony_ci        LOG_ERROR("CacheRootSecret check user id fail");
276094332d3Sopenharmony_ci        return;
277094332d3Sopenharmony_ci    }
278094332d3Sopenharmony_ci    if (!CheckBufferWithSize(rootSecret, ROOT_SECRET_LEN)) {
279094332d3Sopenharmony_ci        LOG_ERROR("check root secret fail");
280094332d3Sopenharmony_ci        return;
281094332d3Sopenharmony_ci    }
282094332d3Sopenharmony_ci    DestroyCacheRootSecret();
283094332d3Sopenharmony_ci    g_cacheRootSecret = CopyBuffer(rootSecret);
284094332d3Sopenharmony_ci    if (g_cacheRootSecret == NULL) {
285094332d3Sopenharmony_ci        LOG_ERROR("copy cache root secret fail");
286094332d3Sopenharmony_ci    }
287094332d3Sopenharmony_ci}
288094332d3Sopenharmony_ci
289094332d3Sopenharmony_ciBuffer *GetCacheRootSecret(int32_t userId)
290094332d3Sopenharmony_ci{
291094332d3Sopenharmony_ci    if (CheckSessionTimeout() != RESULT_SUCCESS) {
292094332d3Sopenharmony_ci        return NULL;
293094332d3Sopenharmony_ci    }
294094332d3Sopenharmony_ci    if (g_session->userId != userId) {
295094332d3Sopenharmony_ci        LOG_ERROR("GetCacheRootSecret check user id fail");
296094332d3Sopenharmony_ci        return NULL;
297094332d3Sopenharmony_ci    }
298094332d3Sopenharmony_ci    if (g_cacheRootSecret == NULL) {
299094332d3Sopenharmony_ci        LOG_ERROR("no cache root secret");
300094332d3Sopenharmony_ci        return NULL;
301094332d3Sopenharmony_ci    }
302094332d3Sopenharmony_ci    return CopyBuffer(g_cacheRootSecret);
303094332d3Sopenharmony_ci}
304094332d3Sopenharmony_ci
305094332d3Sopenharmony_ciResultCode GetChallenge(uint8_t *challenge, uint32_t challengeLen)
306094332d3Sopenharmony_ci{
307094332d3Sopenharmony_ci    if ((challenge == NULL) || (challengeLen != CHALLENGE_LEN)) {
308094332d3Sopenharmony_ci        LOG_ERROR("challenge is invalid");
309094332d3Sopenharmony_ci        return RESULT_BAD_PARAM;
310094332d3Sopenharmony_ci    }
311094332d3Sopenharmony_ci
312094332d3Sopenharmony_ci    ResultCode ret = CheckSessionTimeout();
313094332d3Sopenharmony_ci    if (ret != RESULT_SUCCESS) {
314094332d3Sopenharmony_ci        LOG_ERROR("session does not exist");
315094332d3Sopenharmony_ci        return ret;
316094332d3Sopenharmony_ci    }
317094332d3Sopenharmony_ci    if (memcpy_s(challenge, challengeLen, g_session->challenge, CHALLENGE_LEN) != EOK) {
318094332d3Sopenharmony_ci        LOG_ERROR("copy challenge failed");
319094332d3Sopenharmony_ci        return RESULT_GENERAL_ERROR;
320094332d3Sopenharmony_ci    }
321094332d3Sopenharmony_ci
322094332d3Sopenharmony_ci    return RESULT_SUCCESS;
323094332d3Sopenharmony_ci}
324094332d3Sopenharmony_ci
325094332d3Sopenharmony_ciResultCode IsValidUserType(int32_t userType)
326094332d3Sopenharmony_ci{
327094332d3Sopenharmony_ci    if (userType != MAIN_USER && userType != SUB_USER && userType != PRIVATE_USER) {
328094332d3Sopenharmony_ci        LOG_ERROR("userType is invalid");
329094332d3Sopenharmony_ci        return RESULT_BAD_PARAM;
330094332d3Sopenharmony_ci    }
331094332d3Sopenharmony_ci    LOG_INFO("userType is valid");
332094332d3Sopenharmony_ci    return RESULT_SUCCESS;
333094332d3Sopenharmony_ci}