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