1# Fingerprint Authentication 2 3## Overview 4 5### Function 6 7Fingerprint authentication is indispensable in identity authentication scenarios, such as device unlocking, payment, and app logins. The fingerprint authentication (Fingerprint_auth) module provides fingerprint authentication for a device after a user enrolls a fingerprint. The figure below shows the fingerprint authentication architecture. 8 9The Fingerprint_auth driver is developed based on the Hardware Driver Foundation (HDF). It shields hardware differences and provides stable fingerprint authentication capabilities for the upper-layer user authentication (User_auth) framework and Fingerprint_auth service. It provides APIs for obtaining the fingerprint authentication executor list, executor information, and template information by template ID, comparing fingerprint template information of the executor and that of User_auth, enrolling or deleting fingerprints, and performing fingerprint authentication. 10 11**Figure 1** Fingerprint authentication architecture 12 13![image](figures/fingerprint_auth_architecture.png "Fingerprint authentication architecture") 14 15### Basic Concepts 16 17The identity authentication consists of the User_auth framework and basic authentication services. It supports basic functions such as setting and deleting user credentials and performing authentication. The system supports user identity authentication and data collection, processing, storage, and comparison. 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- Authentication credential 47 48 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. 49 50- Data verification by the executor 51 52 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. 53 54- HAPs 55 56 OpenHarmony Ability Packages (HAPs) represent the upper-layer applications of the Fingerprint_auth driver in this document. 57 58- IDL interface 59 60 An Interface Definition Language (IDL) is a language that lets a program or object written in one language communicate with another program written in an unknown language. An IDL compiler generates client stub files and server framework files. In this document, the IDL interface implements communication between the Fingerprint_auth service and the driver. 61 62- IPC 63 64 Inter-Process Communication (IPC) is a mechanism that allows processes to communicate with each other. 65 66### Working Principles 67 68The fingerprint_auth driver provides stable basic fingerprint authentication capabilities for the upper-layer User_auth framework and Fingerprint_auth service to ensure successful fingerprint authentication on devices. 69 70The figure below shows the interaction between the Fingerprint_auth service and the Fingerprint_auth driver. 71 72The Fingerprint_auth service obtains the executor information by using **GetExecutorInfo()** and registers the executor with the User_auth framework. The Fingerprint_auth service exchanges information with the Fingerprint_auth driver for authentication, identification, and query through the executor APIs. 73You can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use. 74 75**Figure 2** Interaction between the Fingerprint_auth service and Fingerprint_auth driver 76 77![image](figures/fingerprint_auth_service_and_driver_interaction.png "Fingerprint_auth service and driver interaction") 78 79### Constraints 80 81A Trusted Execution Environment (TEE) must be available on the device to store encrypted fingerprint feature information. 82 83## Development Guidelines 84 85### When to Use 86 87The fingerprint_auth driver provides stable basic fingerprint authentication capabilities for the upper-layer User_auth framework and Fingerprint_auth service to ensure successful fingerprint authentication on devices. To implement the preceding functions, you need to develop the Fingerprint_auth driver based on the HDF, and then implement the APIs for obtaining the executor list and functional APIs such as authentication and query. 88 89### Available APIs 90 91**Table 1** Available APIs 92 93| API | Description | 94| ------------------------------------------------------------ | ------------------------------------------------------------ | 95| GetExecutorList(std::vector<sptr<IExecutor>>& executorList) | Obtains the executor list. | 96| GetExecutorInfo(ExecutorInfo& info) | Obtains the executor information, including the executor type, executor role, authentication type, security level, and executor public key.| 97| GetTemplateInfo(uint64_t templateId, TemplateInfo& info) | Obtains information about the template based on the specified ID. | 98| OnRegisterFinish(const std::vector<uint64_t>& templateIdList,<br> const std::vector<uint8_t>& frameworkPublicKey, const std::vector<uint8_t>& extraInfo) | Obtains the public key and template ID list from User_auth after the executor is registered successfully.| 99| Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br> const sptr<IExecutorCallback>& callbackObj) | Enrolls a fingerprint template. | 100| Authenticate(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList,<br> const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj) | Authenticates a fingerprint template. | 101| Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br> const sptr<IExecutorCallback>& callbackObj) | Identifies a fingerprint template. | 102| Delete(const std::vector<uint64_t>& templateIdList) | Deletes a fingerprint template. | 103| Cancel(uint64_t scheduleId) | Cancels a fingerprint enrolling, authentication, or identification operation based on the **scheduleId**. | 104| SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,<br> const sptr<IExecutorCallback>& callbackObj) | Sends commands to the Fingerprint_auth driver. | 105 106**Table 2** Callbacks 107 108| API | Description | 109| ------------------------------------------------------------ | ------------------------ | 110| IExecutorCallback::OnResult(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the operation result. | 111| IExecutorCallback::OnTip(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the interaction information about the operation process.| 112 113### How to Develop 114 115The following uses the Hi3516D V300 development board as an example to demonstrate how to develop the Fingerprint_auth driver. <br/>The directory structure is as follows: 116 117```undefined 118// drivers/peripheral/fingerprint_auth 119├── BUILD.gn # Build script 120├── bundle.json # Module description file 121└── hdi_service # Fingerprint_auth driver implementation 122 ├── BUILD.gn # Build script 123 ├── include # Header files 124 └── src 125 ├── executor_impl.cpp # Implementation of authentication and enrollment APIs 126 ├── fingerprint_auth_interface_driver.cpp # Fingerprint_auth driver entry 127 └── fingerprint_auth_interface_service.cpp # Implementation of the API for obtaining the executor list 128``` 129 130The development procedure is as follows: 131 1321. Develop the Fingerprint_auth driver based on the HDF using the **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions. For details about the code, see [fingerprint_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/fingerprint_auth/hdi_service/src/fingerprint_auth_interface_driver.cpp).<br>The sample code is as follows: 133 134 ```c++ 135 // Create an IRemoteObject object by using the custom HdfFingerprintAuthInterfaceHost object, which consists of the IoService object and HDI service. 136 struct HdfFingerprintAuthInterfaceHost { 137 struct IDeviceIoService ioService; 138 OHOS::sptr<OHOS::IRemoteObject> stub; 139 }; 140 141 // Enable the IPC service to call the response API. 142 static int32_t FingerprintAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, 143 struct HdfSBuf *reply) 144 { 145 IAM_LOGI("start"); 146 auto *hdfFingerprintAuthInterfaceHost = CONTAINER_OF(client->device->service, 147 struct HdfFingerprintAuthInterfaceHost, ioService); 148 149 OHOS::MessageParcel *dataParcel = nullptr; 150 OHOS::MessageParcel *replyParcel = nullptr; 151 OHOS::MessageOption option; 152 153 if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { 154 IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__); 155 return HDF_ERR_INVALID_PARAM; 156 } 157 if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { 158 IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__); 159 return HDF_ERR_INVALID_PARAM; 160 } 161 162 return hdfFingerprintAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); 163 } 164 165 // Initialize the HdfFingerprintAuthInterfaceDriver object. 166 int HdfFingerprintAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject) 167 { 168 IAM_LOGI("start"); 169 if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_USERAUTH)) { 170 IAM_LOGE("set fingerprint auth hdf class failed"); 171 return HDF_FAILURE; 172 } 173 return HDF_SUCCESS; 174 } 175 176 // Bind the service provided by the Fingerprint_auth driver to the HDF. 177 int HdfFingerprintAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject) 178 { 179 IAM_LOGI("start"); 180 auto *hdfFingerprintAuthInterfaceHost = new (std::nothrow) HdfFingerprintAuthInterfaceHost; 181 if (hdfFingerprintAuthInterfaceHost == nullptr) { 182 IAM_LOGE("%{public}s: failed to create HdfFaceAuthInterfaceHost object", __func__); 183 return HDF_FAILURE; 184 } 185 186 hdfFingerprintAuthInterfaceHost->ioService.Dispatch = FingerprintAuthInterfaceDriverDispatch; 187 hdfFingerprintAuthInterfaceHost->ioService.Open = NULL; 188 hdfFingerprintAuthInterfaceHost->ioService.Release = NULL; 189 190 auto serviceImpl = IFingerprintAuthInterface::Get(true); 191 if (serviceImpl == nullptr) { 192 IAM_LOGE("%{public}s: failed to implement service", __func__); 193 return HDF_FAILURE; 194 } 195 196 hdfFingerprintAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 197 IFaceAuthInterface::GetDescriptor()); 198 if (hdfFingerprintAuthInterfaceHost->stub == nullptr) { 199 IAM_LOGE("%{public}s: Failed to get stub object", __func__); 200 return HDF_FAILURE; 201 } 202 203 deviceObject->service = &hdfFingerprintAuthInterfaceHost->ioService; 204 IAM_LOGI("success"); 205 return HDF_SUCCESS; 206 } 207 208 // Release the resources used by the Fingerprint_auth driver. 209 void HdfFingerprintAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) 210 { 211 IAM_LOGI("start"); 212 auto *hdfFingerprintAuthInterfaceHost = CONTAINER_OF(deviceObject->service, 213 struct HdfFaceAuthInterfaceHost, ioService); 214 delete hdfFaceAuthInterfaceHost; 215 IAM_LOGI("success"); 216 } 217 218 // Register the Fingerprint_auth driver entry data structure object. 219 struct HdfDriverEntry g_fingerprintAuthInterfaceDriverEntry = { 220 .moduleVersion = 1, 221 .moduleName = "fingerprint_auth_interface_service", 222 .Bind = HdfFingerprintAuthInterfaceDriverBind, 223 .Init = HdfFingerprintAuthInterfaceDriverInit, 224 .Release = HdfFingerprintAuthInterfaceDriverRelease, 225 }; 226 227 // 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. 228 HDF_INIT(g_fingerprintAuthInterfaceDriverEntry); 229 ``` 230 2312. Implement the API for obtaining the executor list. For details about the code, see [fingerprint_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/fingerprint_auth/hdi_service/src/fingerprint_auth_interface_service.cpp).<br>The sample code is as follows: 232 233 ```c++ 234 // Executor implementation class 235 class ExecutorImpl : public IExecutor { 236 public: 237 ExecutorImpl(struct ExecutorInfo executorInfo); 238 virtual ~ExecutorImpl() {} 239 240 private: 241 struct ExecutorInfo executorInfo_; // Executor information 242 }; 243 244 static constexpr uint16_t SENSOR_ID = 123; // Executor sensor ID 245 static constexpr uint32_t EXECUTOR_TYPE = 123; // Executor type 246 static constexpr size_t PUBLIC_KEY_LEN = 32; //32-byte public key of the executor 247 248 // Create an HDI service object. 249 extern "C" IFaceAuthInterface *FingerprintAuthInterfaceImplGetInstance(void) 250 { 251 auto fingerprintAuthInterfaceService = new (std::nothrow) FingerprintAuthInterfaceService(); 252 if (fingerprintAuthInterfaceService == nullptr) { 253 IAM_LOGE("faceAuthInterfaceService is nullptr"); 254 return nullptr; 255 } 256 return fingerprintAuthInterfaceService; 257 } 258 259 // Obtain the executor list and create an executor. 260 int32_t GetExecutorList(std::vector<sptr<IExecutor>>& executorList) 261 { 262 IAM_LOGI("interface mock start"); 263 executorList.clear(); 264 struct ExecutorInfo executorInfoExample = { 265 .sensorId = SENSOR_ID, 266 .executorType = EXECUTOR_TYPE, 267 .executorRole = ExecutorRole::ALL_IN_ONE, 268 .authType = AuthType::FINGERPRINT, 269 .esl = ExecutorSecureLevel::ESL0, // Executor security level, which ranges from ESL0 to ESL3 (highest). 270 .publicKey = std::vector<uint8_t>(PUBLIC_KEY_LEN, 0), // 32-byte public key, using the Ed25519 algorithm. 271 .extraInfo = {}, 272 }; 273 auto executor = new (std::nothrow) ExecutorImpl(executorInfoExample); 274 if (executor == nullptr) { 275 IAM_LOGE("executor is nullptr"); 276 return HDF_FAILURE; 277 } 278 executorList.push_back(sptr<IExecutor>(executor)); 279 IAM_LOGI("interface mock success"); 280 return HDF_SUCCESS; 281 } 282 ``` 283 2843. Implement each function of the executor. For details about the code, see [executor_impl.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/fingerprint_auth/hdi_service/src/executor_impl.cpp).<br>The sample code is as follows: 285 286 ```c++ 287 // Obtain the executor information. 288 int32_t GetExecutorInfo(ExecutorInfo& info) 289 { 290 IAM_LOGI("interface mock start"); 291 info = executorInfo_; 292 IAM_LOGI("Executor information got successfully"); 293 return HDF_SUCCESS; 294 } 295 296 // Obtain template information based on templateId. 297 int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo& info) 298 { 299 IAM_LOGI("interface mock start"); 300 static_cast<void>(templateId); 301 info = {0}; 302 IAM_LOGI("Template information got successfully"); 303 return HDF_SUCCESS; 304 } 305 306 // After the executor is successfully registered, obtain the public key and template ID list from User_auth and save the public key. The executor compares its template ID list with the template ID list obtained and updates its template ID list. 307 int32_t OnRegisterFinish(const std::vector<uint64_t>& templateIdList, 308 const std::vector<uint8_t>& frameworkPublicKey, const std::vector<uint8_t>& extraInfo) 309 { 310 IAM_LOGI("interface mock start"); 311 static_cast<void>(templateIdList); 312 static_cast<void>(extraInfo); 313 static_cast<void>(frameworkPublicKey); 314 IAM_LOGI("registration finished"); 315 return HDF_SUCCESS; 316 } 317 318 // Enroll fingerprints. 319 int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo, 320 const sptr<IExecutorCallback>& callbackObj) 321 { 322 IAM_LOGI("interface mock start"); 323 static_cast<void>(scheduleId); 324 static_cast<void>(extraInfo); 325 IAM_LOGI("enroll, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT); 326 int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {}); 327 if (ret != ResultCode::SUCCESS) { 328 IAM_LOGE("callback result is %{public}d", ret); 329 return HDF_FAILURE; 330 } 331 return HDF_SUCCESS; 332 } 333 334 // Authenticate fingerprints. 335 int32_t Authenticate(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList, 336 const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj) 337 { 338 IAM_LOGI("interface mock start"); 339 static_cast<void>(scheduleId); 340 static_cast<void>(templateIdList); 341 static_cast<void>(extraInfo); 342 IAM_LOGI("authenticate, result is %{public}d", ResultCode::NOT_ENROLLED); 343 int32_t ret = callbackObj->OnResult(ResultCode::NOT_ENROLLED, {}); 344 if (ret != ResultCode::SUCCESS) { 345 IAM_LOGE("callback result is %{public}d", ret); 346 return HDF_FAILURE; 347 } 348 return HDF_SUCCESS; 349 } 350 351 // Identify fingerprints. 352 int32_t Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo, 353 const sptr<IExecutorCallback>& callbackObj) 354 { 355 IAM_LOGI("interface mock start"); 356 static_cast<void>(scheduleId); 357 static_cast<void>(extraInfo); 358 IAM_LOGI("identify, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT); 359 int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {}); 360 if (ret != ResultCode::SUCCESS) { 361 IAM_LOGE("callback result is %{public}d", ret); 362 return HDF_FAILURE; 363 } 364 return HDF_SUCCESS; 365 } 366 367 // Delete a fingerprint template. 368 int32_t Delete(const std::vector<uint64_t>& templateIdList) 369 { 370 IAM_LOGI("interface mock start"); 371 static_cast<void>(templateIdList); 372 IAM_LOGI("delete success"); 373 return HDF_SUCCESS; 374 } 375 376 // Cancel the operation based on the specified scheduleId. 377 int32_t Cancel(uint64_t scheduleId) 378 { 379 IAM_LOGI("interface mock start"); 380 static_cast<void>(scheduleId); 381 IAM_LOGI("cancel success"); 382 return HDF_SUCCESS; 383 } 384 385 // Send template locking or unlocking command from the Fingerprint_auth service to the Fingerprint_auth driver. 386 int32_t SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo, 387 const sptr<IExecutorCallback>& callbackObj) 388 { 389 IAM_LOGI("interface mock start"); 390 static_cast<void>(extraInfo); 391 int32_t ret; 392 switch (commandId) { 393 case LOCK_TEMPLATE: 394 IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS); 395 ret = callbackObj->OnResult(ResultCode::SUCCESS, {}); 396 if (ret != ResultCode::SUCCESS) { 397 IAM_LOGE("callback result is %{public}d", ret); 398 return HDF_FAILURE; 399 } 400 break; 401 case UNLOCK_TEMPLATE: 402 IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS); 403 ret = callbackObj->OnResult(ResultCode::SUCCESS, {}); 404 if (ret != ResultCode::SUCCESS) { 405 IAM_LOGE("callback result is %{public}d", ret); 406 return HDF_FAILURE; 407 } 408 break; 409 default: 410 IAM_LOGD("not support CommandId : %{public}d", commandId); 411 ret = callbackObj->OnResult(ResultCode::GENERAL_ERROR, {}); 412 if (ret != ResultCode::SUCCESS) { 413 IAM_LOGE("callback result is %{public}d", ret); 414 return HDF_FAILURE; 415 } 416 } 417 return HDF_SUCCESS; 418 } 419 ``` 420 4214. Modify **serviceName2Config** in the **fingerprint_auth_service.cpp** file if you need to add a driver or modify driver information. 422 423 ```c++ 424 // base/user_iam/fingerprint_auth/services/src/fingerprint_auth_service.cpp 425 void FingerprintAuthService::StartDriverManager() 426 { 427 IAM_LOGI("start"); 428 // Service name and ID of the driver to add or modify. The driver service name and ID must be globally unique. 429 const std::map<std::string, UserAuth::ServiceConfig> serviceName2Config = { 430 {"fingerprint_auth_interface_service", {2, std::make_shared<FingerprintAuthDriverHdi>()}}, 431 }; 432 UserIAM::UserAuth::IDriverManager::GetInstance().Start(serviceName2Config); 433 } 434 ``` 435 436### Verification 437 438Use the [User Authentication APIs](../../application-dev/reference/apis/js-apis-useriam-userauth.md) to develop a JavaScript application and verify the application on the Hi3516D V300 development board. The JavaScript application invokes the Fingerprint_auth driver via the Fingerprint_auth service. 439 440The sample code is as follows: 441 442```js 443// API version 8 444import userIAM_userAuth from '@ohos.userIAM.userAuth'; 445let auth = new userIAM_userAuth.UserAuth(); 446 447export default { 448 getVersion() { 449 console.info("start to get version"); 450 let version = this.auth.getVersion(); 451 console.info("auth version = " + version); 452 }, 453 454 startAuth() { 455 console.info("start auth"); 456 // auth is an API that can be called. You can set the authentication type to FINGERPRINT to check whether the driver is successfully registered with the framework and whether the authentication APIs are implemented as expected. result holds the authentication result. 457 this.auth.auth(null, userIAM_userAuth.UserAuthType.FINGERPRINT, userIAM_userAuth.AuthTrustLevel.ATL1, { 458 onResult: (result, extraInfo) => { 459 try { 460 console.info("auth onResult result = " + result); 461 console.info("auth onResult extraInfo = " + JSON.stringify(extraInfo)); 462 if (result == userIAM_userAuth.ResultCode.SUCCESS) { 463 // Add the logic to be executed when the authentication is successful. 464 } else { 465 // Add the logic to be executed when the authentication fails. 466 } 467 } catch (e) { 468 console.info("auth onResult error = " + e); 469 } 470 }, 471 472 onAcquireInfo: (module, acquire, extraInfo) => { 473 try { 474 console.info("auth onAcquireInfo module = " + module); 475 console.info("auth onAcquireInfo acquire = " + acquire); 476 console.info("auth onAcquireInfo extraInfo = " + JSON.stringify(extraInfo)); 477 } catch (e) { 478 console.info("auth onAcquireInfo error = " + e); 479 } 480 } 481 }); 482 } 483} 484``` 485