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 "inputer_data_impl.h"
17 
18 #include <cstddef>
19 #include <regex>
20 #include <vector>
21 
22 #include <openssl/sha.h>
23 
24 #include "securec.h"
25 
26 #include "iam_logger.h"
27 #include "iam_ptr.h"
28 #include "scrypt.h"
29 #include "settings_data_manager.h"
30 #ifdef CUSTOMIZATION_ENTERPRISE_DEVICE_MANAGEMENT_ENABLE
31 #include "security_manager_proxy.h"
32 #endif
33 
34 #define LOG_TAG "PIN_AUTH_SDK"
35 
36 namespace OHOS {
37 namespace UserIam {
38 namespace PinAuth {
39 namespace {
40 constexpr uint32_t PIN_LEN_FOUR = 4;
41 constexpr uint32_t PIN_LEN_SIX = 6;
42 constexpr uint32_t PIN_LEN_NINE = 9;
43 constexpr uint32_t SPECIFY_PIN_COMPLEXITY = 10002;
44 }
45 
InputerDataImpl(const InputerGetDataParam &param)46 InputerDataImpl::InputerDataImpl(const InputerGetDataParam &param)
47     : mode_(param.mode), algoVersion_(param.algoVersion), algoParameter_(param.algoParameter),
48       inputerSetData_(param.inputerSetData), complexityReg_(param.complexityReg), userId_(param.userId),
49       authIntent_(param.authIntent)
50 {
51 }
52 
GetRecoveryKeyData( const std::vector<uint8_t> &dataIn, std::vector<uint8_t> &dataOut, int32_t &errorCode)53 void InputerDataImpl::GetRecoveryKeyData(
54     const std::vector<uint8_t> &dataIn, std::vector<uint8_t> &dataOut, int32_t &errorCode)
55 {
56     if (algoVersion_ == RECOVERY_KEY_ALGO_VERSION_V0) {
57         if (GetSha256(dataIn, dataOut)) {
58             IAM_LOGI("recovery key data sha256 succeed");
59             errorCode = UserAuth::SUCCESS;
60             return;
61         }
62     }
63     IAM_LOGE("recovery key data sha256 failed");
64 }
65 
GetPinData( int32_t authSubType, const std::vector<uint8_t> &dataIn, std::vector<uint8_t> &dataOut, int32_t &errorCode)66 void InputerDataImpl::GetPinData(
67     int32_t authSubType, const std::vector<uint8_t> &dataIn, std::vector<uint8_t> &dataOut, int32_t &errorCode)
68 {
69     IAM_LOGI("start authSubType: %{public}d", authSubType);
70     errorCode = CheckPinComplexity(authSubType, dataIn);
71     if (errorCode != UserAuth::SUCCESS && mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) {
72         IAM_LOGE("CheckPinComplexity enroll failed");
73         return;
74     }
75     if (mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL && authSubType == UserAuth::PIN_PATTERN) {
76         IAM_LOGE("GetPinData Enroll Unsupport Type Pattern");
77         return;
78     }
79     auto scryptPointer = Common::MakeUnique<Scrypt>(algoParameter_);
80     if (scryptPointer == nullptr) {
81         IAM_LOGE("scryptPointer is nullptr");
82         return;
83     }
84     if (authSubType == UserAuth::PIN_PATTERN) {
85         std::vector<uint8_t> patternDataIn(dataIn);
86         for (uint8_t &data : patternDataIn) {
87             data += 1;
88         }
89         scryptPointer->GetScrypt(patternDataIn, algoVersion_).swap(dataOut);
90         (void)memset_s(patternDataIn.data(), patternDataIn.size(), 0, patternDataIn.size());
91     } else {
92         scryptPointer->GetScrypt(dataIn, algoVersion_).swap(dataOut);
93     }
94     if (dataOut.empty()) {
95         IAM_LOGE("get scrypt fail");
96         return;
97     }
98     if ((algoVersion_ > PIN_ALGO_VERSION_V1) && (mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) &&
99         (!GetSha256(dataIn, dataOut))) {
100         IAM_LOGE("get sha256 fail");
101         if (!dataOut.empty()) {
102             (void)memset_s(dataOut.data(), dataOut.size(), 0, dataOut.size());
103         }
104         dataOut.clear();
105     }
106 }
107 
OnSetData(int32_t authSubType, std::vector<uint8_t> data)108 void InputerDataImpl::OnSetData(int32_t authSubType, std::vector<uint8_t> data)
109 {
110     IAM_LOGI("start userId:%{public}d, data size:%{public}zu, algo version:%{public}u, complexityReg size:%{public}zu",
111         userId_, data.size(), algoVersion_, complexityReg_.size());
112     std::vector<uint8_t> setData;
113     int32_t errorCode = UserAuth::GENERAL_ERROR;
114     if (mode_ == GET_DATA_MODE_ALL_IN_ONE_RECOVERY_KEY_AUTH) {
115         GetRecoveryKeyData(data, setData, errorCode);
116     } else {
117         GetPinData(authSubType, data, setData, errorCode);
118     }
119     OnSetDataInner(authSubType, setData, errorCode);
120     if (!data.empty()) {
121         (void)memset_s(data.data(), data.size(), 0, data.size());
122     }
123     if (!setData.empty()) {
124         (void)memset_s(setData.data(), setData.size(), 0, setData.size());
125     }
126 }
127 
GetSha256(const std::vector<uint8_t> &data, std::vector<uint8_t> &out)128 bool InputerDataImpl::GetSha256(const std::vector<uint8_t> &data, std::vector<uint8_t> &out)
129 {
130     uint8_t sha256Result[SHA256_DIGEST_LENGTH] = {};
131     if (SHA256(data.data(), data.size(), sha256Result) != sha256Result) {
132         IAM_LOGE("get sha256 fail");
133         (void)memset_s(sha256Result, SHA256_DIGEST_LENGTH, 0, SHA256_DIGEST_LENGTH);
134         return false;
135     }
136     out.insert(out.end(), sha256Result, sha256Result + SHA256_DIGEST_LENGTH);
137     (void)memset_s(sha256Result, SHA256_DIGEST_LENGTH, 0, SHA256_DIGEST_LENGTH);
138     return true;
139 }
140 
OnSetDataInner(int32_t authSubType, std::vector<uint8_t> &setData, int32_t errorCode)141 void InputerDataImpl::OnSetDataInner(int32_t authSubType, std::vector<uint8_t> &setData, int32_t errorCode)
142 {
143     if (inputerSetData_ == nullptr) {
144         IAM_LOGE("inputerSetData is nullptr");
145         return;
146     }
147     inputerSetData_->OnSetData(authSubType, setData, errorCode);
148 }
149 
CheckPinSizeBySubType(int32_t authSubType, size_t size)150 bool InputerDataImpl::CheckPinSizeBySubType(int32_t authSubType, size_t size)
151 {
152     if (mode_ != GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) {
153         return true;
154     }
155     if (size < PIN_LEN_FOUR) {
156         return false;
157     }
158     switch (authSubType) {
159         case UserAuth::PIN_FOUR:
160             return (size == PIN_LEN_FOUR);
161         case UserAuth::PIN_PATTERN:
162             return (size >= PIN_LEN_FOUR && size <= PIN_LEN_NINE);
163         default:
164             return (size >= PIN_LEN_SIX);
165     }
166 }
167 
CheckPinComplexity(int32_t authSubType, const std::vector<uint8_t> &data)168 int32_t InputerDataImpl::CheckPinComplexity(int32_t authSubType, const std::vector<uint8_t> &data)
169 {
170     if (data.empty()) {
171         IAM_LOGE("get empty data");
172         return UserAuth::COMPLEXITY_CHECK_FAILED;
173     }
174     if (!CheckPinSizeBySubType(authSubType, data.size())) {
175         IAM_LOGE("check data size failed");
176         return UserAuth::COMPLEXITY_CHECK_FAILED;
177     }
178     std::vector<uint8_t> input = data;
179     input.emplace_back('\0');
180     if (!CheckEdmPinComplexity(authSubType, input)) {
181         IAM_LOGE("CheckEdmPinComplexity failed");
182         (void)memset_s(input.data(), input.size(), 0, input.size());
183         return UserAuth::COMPLEXITY_CHECK_FAILED;
184     }
185     if (!CheckSpecialPinComplexity(input, authSubType)) {
186         IAM_LOGE("CheckSpecialPinComplexity failed");
187         (void)memset_s(input.data(), input.size(), 0, input.size());
188         return UserAuth::COMPLEXITY_CHECK_FAILED;
189     }
190     (void)memset_s(input.data(), input.size(), 0, input.size());
191     return UserAuth::SUCCESS;
192 }
193 
CheckSpecialPinComplexity(std::vector<uint8_t> &input, int32_t authSubType)194 bool InputerDataImpl::CheckSpecialPinComplexity(std::vector<uint8_t> &input, int32_t authSubType)
195 {
196     IAM_LOGI("start");
197     if (mode_ != GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL &&
198         !(mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_AUTH && authIntent_ == SPECIFY_PIN_COMPLEXITY)) {
199         return true;
200     }
201     if (complexityReg_.empty()) {
202         IAM_LOGI("complexityReg is empty");
203         return true;
204     }
205     const std::string key = "payment_security_level";
206     int32_t isCheckPinComplexity = 0;
207     if (!SettingsDataManager::GetIntValue(userId_, key, isCheckPinComplexity)) {
208         IAM_LOGI("no exist isCheckPinComplexity");
209         return true;
210     }
211     if (isCheckPinComplexity == 0) {
212         IAM_LOGI("no need check special pin complexity");
213         return true;
214     }
215     if (authSubType == UserAuth::PIN_FOUR || authSubType == UserAuth::PIN_PATTERN) {
216         IAM_LOGE("authSubType is PIN_FOUR or PIN_PATTERN");
217         return false;
218     }
219     if (input.size() <= PIN_LEN_SIX) {
220         IAM_LOGE("check data size failed");
221     }
222     return CheckPinComplexityByReg(input, complexityReg_);
223 }
224 
CheckEdmPinComplexity(int32_t authSubType, std::vector<uint8_t> &input)225 bool InputerDataImpl::CheckEdmPinComplexity(int32_t authSubType, std::vector<uint8_t> &input)
226 {
227     IAM_LOGI("start");
228     if (mode_ != GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) {
229         return true;
230     }
231 #ifdef CUSTOMIZATION_ENTERPRISE_DEVICE_MANAGEMENT_ENABLE
232     EDM::PasswordPolicy policy;
233     int32_t ret = EDM::SecurityManagerProxy::GetSecurityManagerProxy()->GetPasswordPolicy(policy);
234     if (ret != ERR_OK || policy.complexityReg.empty()) {
235         IAM_LOGE("GetPasswordPolicy failed, check other policy");
236         return true;
237     }
238     if (authSubType != UserAuth::PIN_MIXED) {
239         IAM_LOGE("GetPasswordPolicy success, authSubType can only be PIN_MIXED");
240         return false;
241     }
242     return CheckPinComplexityByReg(input, policy.complexityReg);
243 #else
244     IAM_LOGI("This device not support edm");
245 #endif
246     return true;
247 }
248 
CheckPinComplexityByReg(std::vector<uint8_t> &input, const std::string &complexityReg)249 bool InputerDataImpl::CheckPinComplexityByReg(std::vector<uint8_t> &input, const std::string &complexityReg)
250 {
251     try {
252         std::regex regex(complexityReg);
253         bool checkRet = std::regex_match(reinterpret_cast<char*>(input.data()), regex);
254         if (!checkRet) {
255             IAM_LOGE("PIN_MIXED does not pass complexity check");
256             return false;
257         }
258     } catch (const std::regex_error &e) {
259         IAM_LOGE("create regex failed");
260         return false;
261     }
262     return true;
263 }
264 } // namespace PinAuth
265 } // namespace UserIam
266 } // namespace OHOS
267