1# PIN Authentication 2 3## Overview 4 5### Function 6 7Personal Identification Number (PIN) authentication provides user authentication capabilities in identity authentication scenarios, such as device unlocking, payment, and app logins. After a user registers a PIN, the PIN authentication (Pin_auth) module unlocks the device only when the correct PIN is entered. The figure below shows the architecture of PIN authentication. 8 9The Pin_auth driver is developed based on the Hardware Driver Foundation (HDF). The Pin_auth driver model shields hardware differences and provides stable PIN authentication capabilities for the user User_auth framework (User_auth) and PIN authentication system ability (SA). The PIN authentication capabilities include obtaining the PIN authentication executor list, executor information, and anti-brute force information of the specified template, comparing the template ID list of the executor and that of User_auth, enrolling or deleting PINs, and performing PIN authentication. 10 11**Figure 1** PIN authentication architecture 12 13![image](figures/pin_auth_architecture.png "PIN authentication architecture") 14 15### Basic Concepts 16The identity authentication consists of User_auth and basic authentication services (including PIN authentication and facial recognition). It supports basic functions such as setting and deleting user credentials and performing authentication. 17 18- Executor 19 20 The executor collects, processes, stores, and compares data for authentication. Each authentication service provides the executor capabilities, which are scheduled by User_auth to implement basic capabilities. 21 22- Executor security level 23 24 Security level required for the execution environment of an executor. 25 26- Executor role 27 28 - Executor: independently completes the entire process of credential registration and identity authentication. The executor can collect, process, store, and compare data to complete the authentication. 29 30 - Collector: only collects data during user authentication. It needs to work with the authenticator to complete user authentication. 31 32 - Authenticator: only processes data, obtains the stored credential template, and compares it with the authentication information generated. 33 34- Executor type 35 36 The authentication algorithm varies depending on the authentication mode and device used. Different executor types are defined based on the supported algorithm type or the device in use. 37 38- User_auth public key & executor public key 39 40 To ensure user data security and authentication result accuracy, measures must be taken to protect the integrity of the key information exchanged between User_auth and basic authentication services. Public keys must be exchanged when the executor provided by a basic authentication service interworks with User_auth. 41 42 - The executor uses the User_auth public key to verify scheduling instructions. 43 44 - User_auth uses the executor public key to verify the authentication result accuracy and the integrity of the information exchanged with the executor. 45 46 47- PIN authentication credential template 48 49 Authentication credentials are generated and stored by the authentication service when users set authentication credentials. Each template has an ID to index a set of template information files. The template information needs to be compared with the authentication data generated during authentication to complete identity authentication. 50 51- Data verification by the executor 52 53 User_auth manages the mappings between user identities and credential IDs in a unified manner. When connecting to User_auth, the executor obtains the template ID list from User_auth and updates its template ID list based on the template ID list obtained. 54 55### Working Principles 56 57The Pin_auth driver provides basic PIN authentication capabilities for the upper-layer User_auth and Pin_auth service to ensure successful PIN authentication. You can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use. 58 59**Figure 2** Pin_auth service and Pin_auth driver APIs 60 61![image](figures/pin_auth_service_and_driver_interaction.png "interaction between the pin_auth service and driver") 62 63### Constraints 64PIN authentication must be implemented in a Trusted Execution Environment (TEE), and the confidential information, such as PINs and credentials, must be stored in a TEE. 65## Development Guidelines 66 67### When to Use 68The Pin_auth driver provides basic PIN authentication capabilities for the User_auth and Pin_auth service to ensure successful PIN authentication. 69 70### Available APIs 71 72**Table 1** Available APIs 73 74| API | Description | 75| ------------------------------------------------------------ | ------------------------------------------------------------ | 76| GetExecutorList(std::vector<sptr<IExecutor>>& executorList) | Obtains the executor list. | 77| GetExecutorInfo(ExecutorInfo& info) | Obtains information about an executor. | 78| GetTemplateInfo(uint64_t templateId, TemplateInfo& info) | Obtains information about a template. | 79| OnRegisterFinish(const std::vector<uint64_t>& templateIdList,<br>const std::vector<uint8_t>& frameworkPublicKey,<br>const std::vector<uint8_t>& extraInfo) | Obtains the public key and template ID list from User_auth after the executor is registered successfully.| 80| OnSetData(uint64_t scheduleId, uint64_t authSubType, <br>const std::vector<uint8_t> &data) | Called to return the subtype and anonymized data of PIN authentication. | 81| Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br>const sptr<IExecutorCallback>& callbackObj) | Enrolls a PIN. | 82| Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj) | Starts PIN authentication. | 83| Delete(uint64_t templateId) | Deletes a PIN template. | 84| Cancel(uint64_t scheduleId) | Cancels an operation. | 85| SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,<br>const sptr<IExecutorCallback>& callbackObj) | Reserved. | 86 87**Table 2** Callbacks 88 89| API | Description | 90| ------------------------------------------------------------ | -------------------- | 91| IExecutorCallback::OnResult(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the operation result.| 92| IExecutorCallback::OnGetData(uint64_t scheduleId, const std::vector<uint8_t>& salt,<br> uint64_t authSubType)| Called to return the PIN information obtained. | 93 94### How to Develop 95 96The following uses the RK3568 platform as an example to demonstrate how to develop the Pin_auth driver. 97 98The directory structure is as follows: 99 100```text 101// drivers/peripheral/pin_auth 102├── BUILD.gn # Build script 103├── bundle.json # Module description file 104├── test # Test cases 105└── hdi_service # Pin_auth driver implementation 106 ├── BUILD.gn # Build script 107 ├── adaptor # Implementation of related algorithms 108 ├── common # Implementation of common interfaces 109 ├── database # Database implementation 110 ├── main # Entry for implementing PIN-related functions 111 └── service # Entry for implementing the Pin_auth driver 112 ├── inc # Header files 113 └── src 114 ├── executor_impl.cpp # Implementation of authentication and enrollment APIs 115 ├── pin_auth_interface_driver.cpp # Pin_auth driver entry 116 └── pin_auth_interface_service.cpp # Implementation of the APIs for obtaining the executor list 117``` 118 119The development procedure is as follows: 120 1211. Develop the Pin_auth driver based on the HDF. The **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions are used. For details about the code, see [pin_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/pin_auth/hdi_service/service/src/pin_auth_interface_driver.cpp). 122 123 ```c++ 124 // Create the PinAuthInterfaceService object by using the custom HdfPinAuthInterfaceHost object, which consists of the IoService object and HDI service. 125 struct HdfPinAuthInterfaceHost { 126 struct IDeviceIoService ioService; 127 OHOS::sptr<OHOS::IRemoteObject> stub; 128 }; 129 130 // Enable the IPC service to call the response API. 131 static int32_t PinAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) 132 { 133 IAM_LOGI("start"); 134 auto *hdfPinAuthInterfaceHost = CONTAINER_OF(client->device->service, 135 struct HdfPinAuthInterfaceHost, ioService); 136 137 OHOS::MessageParcel *dataParcel = nullptr; 138 OHOS::MessageParcel *replyParcel = nullptr; 139 OHOS::MessageOption option; 140 141 if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { 142 IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__); 143 return HDF_ERR_INVALID_PARAM; 144 } 145 if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { 146 IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__); 147 return HDF_ERR_INVALID_PARAM; 148 } 149 150 return hdfPinAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); 151 } 152 153 // Initialize the HdfPinAuthInterfaceDriver object. 154 static int HdfPinAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject) 155 { 156 IAM_LOGI("start"); 157 std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi = 158 OHOS::UserIAM::Common::MakeShared<OHOS::UserIAM::PinAuth::PinAuth>(); 159 constexpr uint32_t SUCCESS = 0; 160 if (pinHdi == nullptr || pinHdi->Init() != SUCCESS) { 161 IAM_LOGE("PIN HAL initialization failed"); 162 return HDF_FAILURE; 163 } 164 return HDF_SUCCESS; 165 } 166 167 // Bind the service provided by the Pin_auth driver to the HDF. 168 static int HdfPinAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject) 169 { 170 IAM_LOGI("start"); 171 auto *hdfPinAuthInterfaceHost = new (std::nothrow) HdfPinAuthInterfaceHost; 172 if (hdfPinAuthInterfaceHost == nullptr) { 173 IAM_LOGE("%{public}s: Failed to create HdfPinAuthInterfaceHost object", __func__); 174 return HDF_FAILURE; 175 } 176 177 hdfPinAuthInterfaceHost->ioService.Dispatch = PinAuthInterfaceDriverDispatch; 178 hdfPinAuthInterfaceHost->ioService.Open = NULL; 179 hdfPinAuthInterfaceHost->ioService.Release = NULL; 180 181 auto serviceImpl = IPinAuthInterface::Get(true); 182 if (serviceImpl == nullptr) { 183 IAM_LOGE("%{public}s: Failed to implement the service", __func__); 184 return HDF_FAILURE; 185 } 186 187 hdfPinAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 188 IPinAuthInterface::GetDescriptor()); 189 if (hdfPinAuthInterfaceHost->stub == nullptr) { 190 IAM_LOGE("%{public}s: Failed to get stub object", __func__); 191 return HDF_FAILURE; 192 } 193 194 deviceObject->service = &hdfPinAuthInterfaceHost->ioService; 195 IAM_LOGI("success"); 196 return HDF_SUCCESS; 197 } 198 199 // Release resources of the Pin_auth driver. 200 static void HdfPinAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) 201 { 202 IAM_LOGI("start"); 203 auto *hdfPinAuthInterfaceHost = CONTAINER_OF(deviceObject->service, 204 struct HdfPinAuthInterfaceHost, ioService); 205 delete hdfPinAuthInterfaceHost; 206 IAM_LOGI("success"); 207 } 208 209 static struct HdfDriverEntry g_pinAuthInterfaceDriverEntry = { 210 .moduleVersion = 1, 211 .moduleName = "pinauth_interface_service", 212 .Bind = HdfPinAuthInterfaceDriverBind, 213 .Init = HdfPinAuthInterfaceDriverInit, 214 .Release = HdfPinAuthInterfaceDriverRelease, 215 }; 216 217 // Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind() function and then the Init() function. If the Init() function fails to be called, the HDF will call Release() to release driver resources and exit the driver model. 218 HDF_INIT(g_pinauthinterfaceDriverEntry); 219 ``` 220 221 222 2231. Obtain the executor list. For details about the code, see [pin_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/pin_auth/hdi_service/service/src/pin_auth_interface_service.cpp). 224 225 ```c++ 226 // Executor implementation class 227 class ExecutorImpl : public IExecutor, public NoCopyable { 228 public: 229 explicit ExecutorImpl(std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi); 230 virtual ~ExecutorImpl() {} 231 int32_t GetExecutorInfo(ExecutorInfo &info) override; 232 int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo &info) override; 233 int32_t OnRegisterFinish(const std::vector<uint64_t> &templateIdList, 234 const std::vector<uint8_t> &frameworkPublicKey, const std::vector<uint8_t> &extraInfo) override; 235 int32_t OnSetData(uint64_t scheduleId, uint64_t authSubType, const std::vector<uint8_t> &data) override; 236 int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t> &extraInfo, 237 const sptr<IExecutorCallback> &callbackObj) override; 238 int32_t Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t> &extraInfo, 239 const sptr<IExecutorCallback> &callbackObj) override; 240 int32_t Delete(uint64_t templateId) override; 241 int32_t Cancel(uint64_t scheduleId) override; 242 int32_t SendCommand(int32_t commandId, const std::vector<uint8_t> &extraInfo, 243 const sptr<IExecutorCallback> &callbackObj) override; 244 245 private: 246 class ScheduleMap { 247 public: 248 uint32_t AddScheduleInfo(const uint64_t scheduleId, const uint32_t commandId, 249 const sptr<IExecutorCallback> callback, const uint64_t templateId, const std::vector<uint8_t> salt); 250 uint32_t GetScheduleInfo(const uint64_t scheduleId, uint32_t &commandId, sptr<IExecutorCallback> &callback, 251 uint64_t &templateId, std::vector<uint8_t> &salt); 252 uint32_t DeleteScheduleId(const uint64_t scheduleId); 253 254 private: 255 struct ScheduleInfo { 256 uint32_t commandId; 257 sptr<IExecutorCallback> callback; 258 uint64_t templateId; 259 std::vector<uint8_t> salt; 260 }; 261 262 std::mutex mutex_; 263 std::map<uint64_t, struct ScheduleInfo> scheduleInfo_; 264 }; 265 266 private: 267 uint32_t NewSalt(std::vector<uint8_t> &salt); 268 void CallError(const sptr<IExecutorCallback> &callbackObj, const uint32_t errorCode); 269 std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi_; 270 ScheduleMap scheduleMap_; 271 }; 272 273 // Obtain the executor list and create an executor (example only). 274 int32_t PinAuthInterfaceService::GetExecutorList(std::vector<sptr<IExecutor>> &executorList) 275 { 276 IAM_LOGI("start"); 277 std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi = 278 OHOS::UserIAM::Common::MakeShared<OHOS::UserIAM::PinAuth::PinAuth>(); 279 if (pinHdi == nullptr) { 280 IAM_LOGE("Failed to generate pinHdi"); 281 return HDF_FAILURE; 282 } 283 sptr<IExecutor> executor = new (std::nothrow) ExecutorImpl(pinHdi); 284 if (executor == nullptr) { 285 IAM_LOGE("Failed to generate executor"); 286 return HDF_FAILURE; 287 } 288 executorList.push_back(executor); 289 IAM_LOGI("end"); 290 return HDF_SUCCESS; 291 } 292 ``` 293 294 295 2961. Implement each function of the executor. For details about the code, see [executor_impl.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/pin_auth/hdi_service/service/src/executor_impl.cpp). 297 298 ```c++ 299 // Obtain executor information (example only). 300 int32_t ExecutorImpl::GetExecutorInfo(ExecutorInfo &info) 301 { 302 IAM_LOGI("start"); 303 constexpr unsigned short SENSOR_ID = 1; 304 info.sensorId = SENSOR_ID; 305 info.executorType = EXECUTOR_TYPE; 306 info.executorRole = ExecutorRole::ALL_IN_ONE; 307 info.authType = AuthType::PIN; 308 if (pinHdi_ == nullptr) { 309 IAM_LOGE("pinHdi_ is nullptr"); 310 return HDF_FAILURE; 311 } 312 uint32_t eslRet = 0; 313 int32_t result = pinHdi_->GetExecutorInfo(info.publicKey, eslRet); 314 if (result != SUCCESS) { 315 IAM_LOGE("Failed to get ExecutorInfo, error code : %{public}d", result); 316 return result; 317 } 318 info.esl = static_cast<ExecutorSecureLevel>(eslRet); 319 320 return HDF_SUCCESS; 321 } 322 323 // Obtain template information based on templateId. 324 int32_t ExecutorImpl::GetTemplateInfo(uint64_t templateId, TemplateInfo &info) 325 { 326 IAM_LOGI("start"); 327 if (pinHdi_ == nullptr) { 328 IAM_LOGE("pinHdi_ is nullptr"); 329 return HDF_FAILURE; 330 } 331 OHOS::UserIAM::PinAuth::PinCredentialInfo infoRet = {}; 332 int32_t result = pinHdi_->QueryPinInfo(templateId, infoRet); 333 if (result != SUCCESS) { 334 IAM_LOGE("Failed to get TemplateInfo, error code : %{public}d", result); 335 return result; 336 } 337 /* subType is stored in extraInfo. */ 338 info.extraInfo.resize(infoRet.subType); 339 if (memcpy_s(&(info.extraInfo[0]), sizeof(infoRet.subType), &(infoRet.subType), sizeof(infoRet.subType)) != EOK) { 340 IAM_LOGE("Failed to copy subType to extraInfo."); 341 return HDF_FAILURE; 342 } 343 344 info.executorType = EXECUTOR_TYPE; 345 info.remainAttempts = infoRet.remainTimes; 346 info.lockoutDuration = infoRet.freezingTime; 347 348 return HDF_SUCCESS; 349 } 350 351 // After the executor is successfully registered, obtain the public key and template ID list from User_auth and save the public key obtained. The executor compares its template ID list with the template ID list obtained and updates its template ID list. 352 int32_t ExecutorImpl::OnRegisterFinish(const std::vector<uint64_t> &templateIdList, 353 const std::vector<uint8_t> &frameworkPublicKey, const std::vector<uint8_t> &extraInfo) 354 { 355 IAM_LOGI("start"); 356 static_cast<void>(frameworkPublicKey); 357 static_cast<void>(extraInfo); 358 if (pinHdi_ == nullptr) { 359 IAM_LOGE("pinHdi_ is nullptr"); 360 return HDF_FAILURE; 361 } 362 int32_t result = pinHdi_->VerifyTemplateData(templateIdList); 363 if (result != SUCCESS) { 364 IAM_LOGE("Failed to verify templateData"); 365 return result; 366 } 367 368 return HDF_SUCCESS; 369 } 370 371 // Enroll the PIN. 372 int32_t ExecutorImpl::Enroll(uint64_t scheduleId, const std::vector<uint8_t> &extraInfo, 373 const sptr<IExecutorCallback> &callbackObj) 374 { 375 IAM_LOGI("start"); 376 if (callbackObj == nullptr) { 377 IAM_LOGE("callbackObj is nullptr"); 378 return HDF_FAILURE; 379 } 380 static_cast<void>(extraInfo); 381 std::vector<uint8_t> salt; 382 if (NewSalt(salt) != HDF_SUCCESS) { 383 IAM_LOGE("new salt failed"); 384 CallError(callbackObj, HDF_FAILURE); 385 return HDF_FAILURE; 386 } 387 int32_t result = scheduleMap_.AddScheduleInfo(scheduleId, ENROLL_PIN, callbackObj, 0, salt); 388 if (result != HDF_SUCCESS) { 389 IAM_LOGE("Failed to add scheduleInfo, error code : %{public}d", result); 390 CallError(callbackObj, HDF_FAILURE); 391 return result; 392 } 393 result = callbackObj->OnGetData(scheduleId, salt, 0); 394 if (result != SUCCESS) { 395 IAM_LOGE("Failed to enroll PIN , error code : %{public}d", result); 396 // If the enrollment fails, delete scheduleId of scheduleMap. 397 if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) { 398 IAM_LOGI("Failed to delete scheduleId"); 399 } 400 return result; 401 } 402 403 return HDF_SUCCESS; 404 } 405 406 // Implement the callback for returning data. 407 int32_t ExecutorImpl::OnSetData(uint64_t scheduleId, uint64_t authSubType, const std::vector<uint8_t> &data) 408 { 409 IAM_LOGI("start"); 410 if (pinHdi_ == nullptr) { 411 IAM_LOGE("pinHdi_ is nullptr"); 412 return HDF_FAILURE; 413 } 414 std::vector<uint8_t> resultTlv; 415 int32_t result = SUCCESS; 416 constexpr uint32_t INVALID_ID = 2; 417 uint32_t commandId = INVALID_ID; 418 sptr<IExecutorCallback> callback = nullptr; 419 uint64_t templateId = 0; 420 std::vector<uint8_t> salt(0, 0); 421 if (scheduleMap_.GetScheduleInfo(scheduleId, commandId, callback, templateId, salt) != HDF_SUCCESS) { 422 IAM_LOGE("Failed to get ScheduleInfo, error code : %{public}d", result); 423 return HDF_FAILURE; 424 } 425 switch (commandId) { 426 case ENROLL_PIN: 427 result = pinHdi_->EnrollPin(scheduleId, authSubType, salt, data, resultTlv); 428 if (result != SUCCESS) { 429 IAM_LOGE("Failed to enroll PIN, error code : %{public}d", result); 430 } 431 break; 432 case AUTH_PIN: 433 result = pinHdi_->AuthPin(scheduleId, templateId, data, resultTlv); 434 if (result != SUCCESS) { 435 IAM_LOGE("Failed to authenticate PIN, error code : %{public}d", result); 436 } 437 break; 438 default: 439 IAM_LOGE("Error commandId"); 440 } 441 442 if (callback->OnResult(result, resultTlv) != SUCCESS) { 443 IAM_LOGE("callbackObj Pin failed"); 444 } 445 // Delete scheduleId from scheduleMap when the enrollment and authentication are successful. 446 if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) { 447 IAM_LOGI("Failed to delete scheduleId"); 448 } 449 450 return HDF_SUCCESS; 451 } 452 // Perform PIN authentication. 453 int32_t ExecutorImpl::Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t> &extraInfo, 454 const sptr<IExecutorCallback> &callbackObj) 455 { 456 IAM_LOGI("start"); 457 if (callbackObj == nullptr) { 458 IAM_LOGE("callbackObj is nullptr"); 459 return HDF_FAILURE; 460 } 461 if (pinHdi_ == nullptr) { 462 IAM_LOGE("pinHdi_ is nullptr"); 463 CallError(callbackObj, HDF_FAILURE); 464 return HDF_FAILURE; 465 } 466 static_cast<void>(extraInfo); 467 std::vector<uint8_t> salt; 468 int32_t result = pinHdi_->GetSalt(templateId, salt); 469 if (result != SUCCESS) { 470 IAM_LOGE("Failed to get salt, error code : %{public}d", result); 471 CallError(callbackObj, HDF_FAILURE); 472 return result; 473 } 474 result = scheduleMap_.AddScheduleInfo(scheduleId, AUTH_PIN, callbackObj, templateId, salt); 475 if (result != HDF_SUCCESS) { 476 IAM_LOGE("Failed to add scheduleInfo, error code : %{public}d", result); 477 CallError(callbackObj, HDF_FAILURE); 478 return result; 479 } 480 result = callbackObj->OnGetData(scheduleId, salt, 0); 481 if (result != SUCCESS) { 482 IAM_LOGE("Failed to authenticate PIN, error code : %{public}d", result); 483 // If the authentication fails, delete scheduleId of scheduleMap. 484 if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) { 485 IAM_LOGI("Failed to delete scheduleId"); 486 } 487 return result; 488 } 489 490 return HDF_SUCCESS; 491 } 492 493 // Delete the PIN template. 494 int32_t ExecutorImpl::Delete(uint64_t templateId) 495 { 496 IAM_LOGI("start"); 497 if (pinHdi_ == nullptr) { 498 IAM_LOGE("pinHdi_ is nullptr"); 499 return HDF_FAILURE; 500 } 501 int32_t result = pinHdi_->DeleteTemplate(templateId); 502 if (result != SUCCESS) { 503 IAM_LOGE("Failed to verify templateData, error code : %{public}d", result); 504 return result; 505 } 506 507 return HDF_SUCCESS; 508 } 509 510 // Cancel the operation based on the specified scheduleId. 511 int32_t ExecutorImpl::Cancel(uint64_t scheduleId) 512 { 513 IAM_LOGI("start"); 514 if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) { 515 IAM_LOGE("scheduleId is not found"); 516 return HDF_FAILURE; 517 } 518 return HDF_SUCCESS; 519 } 520 521 // API reserved. 522 int32_t ExecutorImpl::SendCommand(int32_t commandId, const std::vector<uint8_t> &extraInfo, 523 const sptr<IExecutorCallback> &callbackObj) 524 { 525 IAM_LOGI("Extension interface, temporarily useless"); 526 static_cast<void>(commandId); 527 static_cast<void>(extraInfo); 528 static_cast<void>(callbackObj); 529 return HDF_SUCCESS; 530 } 531 ``` 532 533 534### Verification 535Verify whether PIN authentication can be successfully performed on the RK3568 platform as follows: 536 5371. Set a PIN. 538 539 Touch **Settings** > **Biometrics & passwords** > **Password**, and enter your password. 540 5412. Verify PIN authentication. 542 543 1) Press the power button to lock the screen. 544 545 2) Press the power button again, and enter an incorrect password for five consecutive times. The device will be locked for 60 seconds. 546 547 3) Enter the correct password. The screen is unlocked. 548 5493. Disable PIN authentication. 550 551 1) Touch **Settings** > **Biometrics & passwords** > **Password**. 552 553 2) Touch **Disable lock screen password** and **Disable**. 554 5554. Change the PIN. 556 557 1) Touch **Settings** > **Biometrics & passwords** > **Password**. 558 559 2) Touch **Change screen lock password** and set the new password. 560