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