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