1 /*
2  * Copyright (C) 2022-2024 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 "user_sign_centre.h"
17 
18 #include "securec.h"
19 
20 #include "adaptor_algorithm.h"
21 #include "adaptor_log.h"
22 #include "adaptor_time.h"
23 #include "token_key.h"
24 
25 #define TOKEN_VALIDITY_PERIOD (10 * 60 * 1000)
26 
27 #define AES_GCM_TOKEN_AAD "OH_authToken"
28 #define AES_GCM_TOKEN_AAD_SIZE 12
29 
30 #ifdef IAM_TEST_ENABLE
31 #define IAM_STATIC
32 #else
33 #define IAM_STATIC static
34 #endif
35 
IsTimeValid(const UserAuthTokenHal * userAuthToken)36 IAM_STATIC bool IsTimeValid(const UserAuthTokenHal *userAuthToken)
37 {
38     uint64_t currentTime = GetSystemTime();
39     if (currentTime < userAuthToken->tokenDataPlain.time) {
40         return false;
41     }
42     if (currentTime - userAuthToken->tokenDataPlain.time > TOKEN_VALIDITY_PERIOD) {
43         return false;
44     }
45     return true;
46 }
47 
UserAuthTokenHmac(UserAuthTokenHal * userAuthToken,HksAuthTokenKey * tokenKey)48 IAM_STATIC ResultCode UserAuthTokenHmac(UserAuthTokenHal *userAuthToken, HksAuthTokenKey *tokenKey)
49 {
50     Buffer *sign = NULL;
51 
52     const Buffer data = GetTmpBuffer((uint8_t *)userAuthToken, AUTH_TOKEN_DATA_LEN, AUTH_TOKEN_DATA_LEN);
53     const Buffer key = GetTmpBuffer(tokenKey->macKey, sizeof(tokenKey->macKey), sizeof(tokenKey->macKey));
54     ResultCode ret = HmacSha256(&key, &data, &sign);
55     if (ret != RESULT_SUCCESS) {
56         LOG_ERROR("HmacSha256 failed");
57         goto EXIT;
58     }
59     if (!CheckBufferWithSize(sign, SHA256_DIGEST_SIZE)) {
60         LOG_ERROR("CheckBufferWithSize failed");
61         ret = RESULT_GENERAL_ERROR;
62         goto EXIT;
63     }
64     if (memcpy_s(userAuthToken->sign, SHA256_DIGEST_SIZE, sign->buf, sign->contentSize) != EOK) {
65         LOG_ERROR("sign copy failed");
66         ret = RESULT_BAD_COPY;
67         goto EXIT;
68     }
69 
70 EXIT:
71     DestoryBuffer(sign);
72     return ret;
73 }
74 
DeinitAesGcmParam(AesGcmParam * aesGcmParam)75 IAM_STATIC void DeinitAesGcmParam(AesGcmParam *aesGcmParam)
76 {
77     DestoryBuffer(aesGcmParam->aad);
78     DestoryBuffer(aesGcmParam->iv);
79     DestoryBuffer(aesGcmParam->key);
80     (void)memset_s(aesGcmParam, sizeof(AesGcmParam), 0, sizeof(AesGcmParam));
81 }
82 
DecryptTokenCipher(const UserAuthTokenHal * userAuthToken,UserAuthTokenPlain * tokenPlain,HksAuthTokenKey * tokenKey)83 IAM_STATIC ResultCode DecryptTokenCipher(const UserAuthTokenHal *userAuthToken, UserAuthTokenPlain *tokenPlain,
84     HksAuthTokenKey *tokenKey)
85 {
86     AesGcmParam aesGcmParam = {
87         .key = CreateBufferByData(tokenKey->cipherKey, sizeof(tokenKey->cipherKey)),
88         .iv = CreateBufferByData(userAuthToken->iv, sizeof(userAuthToken->iv)),
89         .aad = CreateBufferByData((uint8_t *)AES_GCM_TOKEN_AAD, AES_GCM_TOKEN_AAD_SIZE),
90     };
91     Buffer *plaintext = NULL;
92     int ret = RESULT_GENERAL_ERROR;
93     if (!IsBufferValid(aesGcmParam.key) || !IsBufferValid(aesGcmParam.iv) || !IsBufferValid(aesGcmParam.aad)) {
94         LOG_ERROR("get buffer failed");
95         goto EXIT;
96     }
97     const Buffer tag = GetTmpBuffer((uint8_t *)userAuthToken->tag, sizeof(userAuthToken->tag),
98         sizeof(userAuthToken->tag));
99     const Buffer ciphertext = GetTmpBuffer((uint8_t *)userAuthToken->tokenDataCipher,
100         sizeof(userAuthToken->tokenDataCipher), sizeof(userAuthToken->tokenDataCipher));
101     ret = AesGcmDecrypt(&ciphertext, &aesGcmParam, &tag, &plaintext);
102     if (ret != RESULT_SUCCESS) {
103         LOG_ERROR("AesGcmDecrypt failed");
104         goto EXIT;
105     }
106     if (!CheckBufferWithSize(plaintext, sizeof(tokenPlain->tokenDataToEncrypt))) {
107         LOG_ERROR("CheckBufferWithSize failed");
108         ret = RESULT_GENERAL_ERROR;
109         goto EXIT;
110     }
111     if (memcpy_s(&(tokenPlain->tokenDataToEncrypt), sizeof(tokenPlain->tokenDataToEncrypt),
112         plaintext->buf, plaintext->contentSize) != EOK) {
113         LOG_ERROR("copy TokenDataToEncrypt failed");
114         ret = RESULT_GENERAL_ERROR;
115         goto EXIT;
116     }
117 
118 EXIT:
119     DestoryBuffer(plaintext);
120     DeinitAesGcmParam(&aesGcmParam);
121     return ret;
122 }
123 
CheckUserAuthTokenHmac(const UserAuthTokenHal * userAuthToken,HksAuthTokenKey * tokenKey)124 IAM_STATIC ResultCode CheckUserAuthTokenHmac(const UserAuthTokenHal *userAuthToken, HksAuthTokenKey *tokenKey)
125 {
126     Buffer *rightSign = NULL;
127     const Buffer data = GetTmpBuffer((uint8_t *)userAuthToken, AUTH_TOKEN_DATA_LEN, AUTH_TOKEN_DATA_LEN);
128     const Buffer key = GetTmpBuffer(tokenKey->macKey, sizeof(tokenKey->macKey), sizeof(tokenKey->macKey));
129     ResultCode ret = HmacSha256(&key, &data, &rightSign);
130     if (ret != RESULT_SUCCESS) {
131         LOG_ERROR("HmacSha256 failed");
132         goto EXIT;
133     }
134     const Buffer sign = GetTmpBuffer((uint8_t *)userAuthToken->sign, SHA256_DIGEST_SIZE, SHA256_DIGEST_SIZE);
135     if (!CompareBuffer(rightSign, &sign)) {
136         LOG_ERROR("sign compare failed");
137         ret = RESULT_BAD_SIGN;
138     }
139 
140 EXIT:
141     DestoryBuffer(rightSign);
142     return ret;
143 }
144 
UserAuthTokenVerify(UserAuthTokenHal * userAuthToken,UserAuthTokenPlain * tokenPlain)145 ResultCode UserAuthTokenVerify(UserAuthTokenHal *userAuthToken, UserAuthTokenPlain *tokenPlain)
146 {
147     if (userAuthToken == NULL || tokenPlain == NULL) {
148         LOG_ERROR("userAuthToken is null");
149         return RESULT_BAD_PARAM;
150     }
151     if (!IsTimeValid(userAuthToken)) {
152         LOG_ERROR("token timeout");
153         return RESULT_TOKEN_TIMEOUT;
154     }
155     HksAuthTokenKey tokenKey = {};
156     ResultCode ret = GetTokenKey(&tokenKey);
157     if (ret != RESULT_SUCCESS) {
158         LOG_ERROR("GetTokenKey fail");
159         (void)memset_s(&tokenKey, sizeof(HksAuthTokenKey), 0, sizeof(HksAuthTokenKey));
160         return ret;
161     }
162     ret = CheckUserAuthTokenHmac(userAuthToken, &tokenKey);
163     if (ret != RESULT_SUCCESS) {
164         LOG_ERROR("UserAuthTokenVerify fail");
165         (void)memset_s(&tokenKey, sizeof(HksAuthTokenKey), 0, sizeof(HksAuthTokenKey));
166         return ret;
167     }
168     tokenPlain->tokenDataPlain = userAuthToken->tokenDataPlain;
169     ret = DecryptTokenCipher(userAuthToken, tokenPlain, &tokenKey);
170     if (ret != RESULT_SUCCESS) {
171         LOG_ERROR("DecryptTokenCipher fail");
172     }
173     (void)memset_s(&tokenKey, sizeof(HksAuthTokenKey), 0, sizeof(HksAuthTokenKey));
174     return ret;
175 }
176 
InitAesGcmParam(AesGcmParam * aesGcmParam,const HksAuthTokenKey * tokenKey)177 IAM_STATIC ResultCode InitAesGcmParam(AesGcmParam *aesGcmParam, const HksAuthTokenKey *tokenKey)
178 {
179     int32_t ret = RESULT_GENERAL_ERROR;
180     aesGcmParam->key = CreateBufferByData(tokenKey->cipherKey, sizeof(tokenKey->cipherKey));
181     aesGcmParam->iv = CreateBufferBySize(AES_GCM_IV_SIZE);
182     aesGcmParam->aad = CreateBufferByData((uint8_t *)AES_GCM_TOKEN_AAD, AES_GCM_TOKEN_AAD_SIZE);
183     if (!IsBufferValid(aesGcmParam->key) || !IsBufferValid(aesGcmParam->iv) || !IsBufferValid(aesGcmParam->aad)) {
184         LOG_ERROR("get secure uid failed");
185         goto EXIT;
186     }
187     ret = SecureRandom(aesGcmParam->iv->buf, aesGcmParam->iv->maxSize);
188     if (ret != RESULT_SUCCESS) {
189         LOG_ERROR("SecureRandom failed");
190         goto EXIT;
191     }
192     aesGcmParam->iv->contentSize = aesGcmParam->iv->maxSize;
193     return ret;
194 EXIT:
195     DeinitAesGcmParam(aesGcmParam);
196     return ret;
197 }
198 
CopyTokenCipherParam(const Buffer * ciphertext,const Buffer * tag,const Buffer * iv,UserAuthTokenHal * authToken)199 IAM_STATIC ResultCode CopyTokenCipherParam(const Buffer *ciphertext, const Buffer *tag, const Buffer *iv,
200     UserAuthTokenHal *authToken)
201 {
202     if (!CheckBufferWithSize(ciphertext, sizeof(authToken->tokenDataCipher))) {
203         LOG_ERROR("bad ciphertext size");
204         return RESULT_GENERAL_ERROR;
205     }
206     if (memcpy_s(authToken->tokenDataCipher, sizeof(authToken->tokenDataCipher),
207         ciphertext->buf, ciphertext->contentSize) != EOK) {
208         LOG_ERROR("copy ciphertext failed");
209         return RESULT_GENERAL_ERROR;
210     }
211     if (!CheckBufferWithSize(tag, sizeof(authToken->tag))) {
212         LOG_ERROR("bad tag size");
213         return RESULT_GENERAL_ERROR;
214     }
215     if (memcpy_s(authToken->tag, sizeof(authToken->tag), tag->buf, tag->contentSize) != EOK) {
216         LOG_ERROR("copy tag failed");
217         return RESULT_GENERAL_ERROR;
218     }
219     if (!CheckBufferWithSize(iv, sizeof(authToken->iv))) {
220         LOG_ERROR("bad iv size");
221         return RESULT_GENERAL_ERROR;
222     }
223     if (memcpy_s(authToken->iv, sizeof(authToken->iv), iv->buf, iv->contentSize) != EOK) {
224         LOG_ERROR("copy iv failed");
225         return RESULT_GENERAL_ERROR;
226     }
227     return RESULT_SUCCESS;
228 }
229 
GetTokenDataCipherResult(const TokenDataToEncrypt * data,UserAuthTokenHal * authToken,const HksAuthTokenKey * tokenKey)230 IAM_STATIC ResultCode GetTokenDataCipherResult(const TokenDataToEncrypt *data, UserAuthTokenHal *authToken,
231     const HksAuthTokenKey *tokenKey)
232 {
233     AesGcmParam aesGcmParam = {0};
234     Buffer *ciphertext = NULL;
235     Buffer *tag = NULL;
236     ResultCode ret = InitAesGcmParam(&aesGcmParam, tokenKey);
237     if (ret != RESULT_SUCCESS) {
238         LOG_ERROR("InitAesGcmParam failed");
239         goto EXIT;
240     }
241     const Buffer plaintext = GetTmpBuffer((uint8_t *)data, sizeof(TokenDataToEncrypt), sizeof(TokenDataToEncrypt));
242     ret = AesGcmEncrypt(&plaintext, &aesGcmParam, &ciphertext, &tag);
243     if (ret != RESULT_SUCCESS) {
244         LOG_ERROR("AesGcmEncrypt failed");
245         goto EXIT;
246     }
247     ret = CopyTokenCipherParam(ciphertext, tag, aesGcmParam.iv, authToken);
248     if (ret != RESULT_SUCCESS) {
249         LOG_ERROR("CopyTokenCipherParam failed");
250         goto EXIT;
251     }
252 
253 EXIT:
254     DestoryBuffer(tag);
255     DestoryBuffer(ciphertext);
256     DeinitAesGcmParam(&aesGcmParam);
257     return ret;
258 }
259 
UserAuthTokenSign(UserAuthTokenPlain * tokenPlain,UserAuthTokenHal * authToken)260 ResultCode UserAuthTokenSign(UserAuthTokenPlain *tokenPlain, UserAuthTokenHal *authToken)
261 {
262     if (tokenPlain == NULL || authToken == NULL) {
263         LOG_ERROR("bad param");
264         return RESULT_BAD_PARAM;
265     }
266 
267     (void)memset_s(authToken, sizeof(UserAuthTokenHal), 0, sizeof(UserAuthTokenHal));
268     HksAuthTokenKey tokenKey = {};
269     ResultCode ret = GetTokenKey(&tokenKey);
270     if (ret != RESULT_SUCCESS) {
271         LOG_ERROR("GetTokenKey fail");
272         goto FAIL;
273     }
274 
275     authToken->version = TOKEN_VERSION;
276     authToken->tokenDataPlain = tokenPlain->tokenDataPlain;
277     authToken->tokenDataPlain.time = GetSystemTime();
278     LOG_INFO("signed token type %{public}u", authToken->tokenDataPlain.tokenType);
279 
280     ret = GetTokenDataCipherResult(&(tokenPlain->tokenDataToEncrypt), authToken, &tokenKey);
281     if (ret != RESULT_SUCCESS) {
282         LOG_ERROR("GetTokenDataCipherResult failed");
283         goto FAIL;
284     }
285 
286     ret = UserAuthTokenHmac(authToken, &tokenKey);
287     if (ret != RESULT_SUCCESS) {
288         LOG_ERROR("UserAuthTokenHmac fail");
289         goto FAIL;
290     }
291     (void)memset_s(&tokenKey, sizeof(HksAuthTokenKey), 0, sizeof(HksAuthTokenKey));
292     return RESULT_SUCCESS;
293 
294 FAIL:
295     (void)memset_s(&tokenKey, sizeof(HksAuthTokenKey), 0, sizeof(HksAuthTokenKey));
296     (void)memset_s(authToken, sizeof(UserAuthTokenHal), 0, sizeof(UserAuthTokenHal));
297     return ret;
298 }
299 
ReuseUnlockTokenSign(UserAuthTokenHal * reuseToken)300 ResultCode ReuseUnlockTokenSign(UserAuthTokenHal *reuseToken)
301 {
302     if (reuseToken == NULL) {
303         LOG_ERROR("reuseToken is null");
304         return RESULT_BAD_PARAM;
305     }
306     HksAuthTokenKey tokenKey = {};
307     ResultCode ret = GetTokenKey(&tokenKey);
308     if (ret != RESULT_SUCCESS) {
309         LOG_ERROR("GetTokenKey fail");
310         goto FAIL;
311     }
312     ret = UserAuthTokenHmac(reuseToken, &tokenKey);
313     if (ret != RESULT_SUCCESS) {
314         LOG_ERROR("ReuseUnlockTokenSign fail");
315         goto FAIL;
316     }
317     (void)memset_s(&tokenKey, sizeof(HksAuthTokenKey), 0, sizeof(HksAuthTokenKey));
318     return RESULT_SUCCESS;
319 
320 FAIL:
321     (void)memset_s(&tokenKey, sizeof(HksAuthTokenKey), 0, sizeof(HksAuthTokenKey));
322     (void)memset_s(reuseToken, sizeof(UserAuthTokenHal), 0, sizeof(UserAuthTokenHal));
323     return ret;
324 }