• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# User_auth
2
3## 概述
4
5### 功能简介
6
7用户认证功能是端侧设备不可或缺的一部分,可应用于设备解锁、支付、应用登录等身份认证场景。用户认证(User_auth)框架统一管理用户身份与认证凭据模板的映射关系,通过调度各认证基础服务(包含口令认证、人脸识别等)实现的执行器完成用户认证凭据注册、凭据删除、身份认证及相关信息查询。用户认证的整体架构如图1。
8
9基于HDF(Hardware Driver Foundation)驱动框架开发的User_auth驱动,能够屏蔽硬件器件差异,为上层应用(设置、锁屏等)和账号管理SA(System Ability)提供稳定的用户身份认证能力,支持用户凭据管理、认证信息录入、认证方案生成以及认证执行器信息管理能力。
10
11**图1** 用户认证功能整体框架
12
13![image](figures/用户认证功能整体框架图.png "用户认证功能整体框架图")
14
15### 基本概念
16用户认证框架与各个基础认证服务(包含口令认证、人脸识别等)组成的身份认证系统,支持用户认证凭据设置、删除、认证等基础功能。
17
18- 认证凭据信息
19
20  用户设置口令、录入人脸时,会生成认证凭据模板,凭据信息由用户身份信息与凭据模板信息组成,用于在认证用户时找到匹配指定用户的凭据模板。
21
22- 认证凭据模板
23
24  认证凭据模板在用户设置认证凭据时由认证服务产生并存储。每个模板有一个ID,用于索引模板信息文件。在认证时,读取模板信息并和当次认证过程中产生的认证数据做对比,完成身份认证。
25
26- 执行器
27
28  执行器是能够提供数据采集、处理、存储及比对能力的模块,各基础认证服务提供执行器能力,被身份认证框架调度完成各项基础功能。
29
30- 执行器角色
31
32  - ​    全功能执行器:执行器可独立处理凭据注册和身份认证请求,即可提供用户认证数据采集、处理、储存及比对能力。
33
34  - ​    采集器:执行器提供用户认证时的数据采集能力,需要和认证器配合完成用户认证。
35
36  - ​    认证器:认证器提供用户认证时的数据处理能力,读取存储凭据模板信息并完成比对。
37
38- 执行器类型
39
40  同一种身份认证类型的不同认证方式、设备器件差异都会产生认证算法差异,执行器根据这些差异定义不同的执行器类型。
41
42- 执行器安全等级
43
44  执行器提供能力时所在运行环境达到的安全级别。
45
46- 用户认证框架公钥 & 执行器公钥
47
48  用户身份认证处理需要保证用户数据安全以及认证结果的准确性,用户认证框架与基础认证服务间的关键交互信息需要做数据完整性保护,各基础认证服务将提供的执行器能力对接到用户认证框架时,需要交换各自的公钥,其中:
49
50    - 执行器通过用户认证框架公钥校验调度指令的准确性,如锁定一个人脸模板,这种情况导致无法使用人脸功能,属于敏感操作,需要确保指令准确,才可处理。
51
52    - 执行器公钥可被用户认证框架用于校验认证结果的准确性,同时用于执行器交互认证时的校验交互信息的完整性。
53
54
55- 认证结果可信等级
56
57  不同认证方式及认证过程运行环境的安全级别差异,使得生成的认证结果的可信级别不同。
58
59- 认证方案
60
61  用户发起认证请求所使用的认证方式、认证结果可信等级、执行器信息和凭据信息等相关信息。
62
63- 调度信息
64
65  包括执行器信息及执行器处理请求需要的凭据模板信息,用于用户认证框架调度执行器完成基础功能。
66
67- System Ability
68
69  系统能力,由系统服务管理服务(System Ability Manager)加载,向OpenHarmony系统提供系统基础能力的基础服务。
70
71- Kit
72
73  OpenHarmony系统向第三方应用提供的基础应用编程接口。
74
75- Inner API
76
77  OpenHarmony系统向系统应用提供的应用编程接口。
78
79- IDL接口
80
81  接口定义语言(Interface Definition Language),通过IDL编译器编译后,能够生成与编程语言相关的文件:客户端桩文件,服务器框架文件。本文主要是通过IDL接口生成的客户端和服务端来实现User_auth服务和驱动的通信,详细使用方法可参考[IDL简介](https://gitee.com/openharmony/ability_idl_tool/blob/master/README.md)82
83- IPC通信
84
85  IPC(Inter Process Communication),进程间通信是指两个进程的数据之间产生交互,详细原理可参考[IPC通信简介](https://gitee.com/openharmony/communication_ipc/blob/master/README_zh.md)86
87- HDI
88
89  HDI(Hardware Device Interface),硬件设备接口,位于基础系统服务层和设备驱动层之间,是提供给硬件系统服务开发者使用的、统一的硬件设备功能抽象接口,其目的是为系统服务屏蔽底层硬件设备差异,具体可参考[HDI规范](../../design/hdi-design-specifications.md)。
90
91### 运作机制
92
93User_auth驱动主要工作是屏蔽不同安全器件和安全环境的差异,通过统一的认证能力注册、录入、认证接口,向User_auth服务提供认证执行器管理、认证凭据管理和认证方案生成管理等能力。
94开发者可基于HDF框架对不同芯片进行各自驱动的开发及HDI层接口的调用。
95
96**图2** User_auth服务和User_auth驱动交互
97
98![image](figures/用户认证服务和userauth驱动接口.png "用户认证服务和userauth驱动接口")
99
100### 约束与限制
101
102User_auth驱动的实现需要在可信执行环境中实现,保证用户凭据信息的安全存储及用户身份认证结果的可信可靠。
103
104## 开发指导
105
106### 场景介绍
107
108User_auth驱动的主要工作是为User_auth服务提供稳定的用户凭据管理、认证会话管理以及执行器信息管理能力,保证设备上口令认证和生物识别功能可以正常运行。
109
110### 接口说明
111
112注:以下接口列举的为IDL接口描述生成的对应C++语言函数接口,接口声明见idl文件(/drivers/interface/user_auth)。
113在本文中,执行器注册、凭据录入、凭据删除、用户认证和用户识别相关的HDI接口如表1所示。
114
115**表1** 接口功能介绍
116
117| 接口名称       | 功能介绍     |
118| --------------------------- | --------------------------- |
119| Init()           | 初始化缓存信息。                        |
120| AddExecutor(const ExecutorRegisterInfo& info, uint64_t& index, std::vector\<uint8_t>& publicKey,<br/>        std::vector\<uint64_t>& templateIds) | 添加认证执行器,获得此认证能力。           |
121| DeleteExecutor(uint64_t index)            | 根据索引值index删除认证执行器。       |
122| OpenSession(int32_t userId, std::vector\<uint8_t>& challenge) | 开启认证凭据管理Session。      |
123| CloseSession(int32_t userId)        | 关闭认证凭据管理Session。            |
124| BeginEnrollment(int32_t userId, const std::vector\<uint8_t>& authToken, const EnrollParam& param,<br/>        ScheduleInfo& info) | 发起用户的认证凭据的录入,当录入类型为PIN码且当前用户已录入PIN码的情况下会更新PIN码(V1_0版本)。 |
125| UpdateEnrollmentResult(int32_t userId, const std::vector\<uint8_t>& scheduleResult, uint64_t& credentialId,<br/>        CredentialInfo& oldInfo) | 更新录入结果,完成此次录入。   |
126| CancelEnrollment(int32_t userId)     | 取消此次录入。          |
127| DeleteCredential(int32_t userId, uint64_t credentialId, const std::vector\<uint8_t>& authToken,<br/>        CredentialInfo& info) | 根据credentialId删除凭据信息。                               |
128| DeleteUser(int32_t userId, const std::vector\<uint8_t>& authToken,<br/>        std::vector\<CredentialInfo>& deletedInfos) | 删除PIN码即在用户认证框架中删除用户。                        |
129| EnforceDeleteUser(int32_t userId, std::vector\<CredentialInfo>& deletedInfos) | 强制删除用户,当系统内此用户被删除时强制调用。               |
130| GetCredential(int32_t userId, AuthType authType, std::vector\<CredentialInfo>& infos) | 查询用户某种认证类型下的凭据信息。             |
131| GetSecureInfo(int32_t userId, uint64_t& secureUid, std::vector\<EnrolledInfo>& infos) | 查询用户的安全用户Id和每种认证类型的录入标记Id。             |
132| BeginAuthentication(uint64_t contextId, const AuthSolution& param,<br/>        std::vector\<ScheduleInfo>& scheduleInfos) | 发起认证,生成认证方案和调度信息(V1_0版本)。                           |
133| UpdateAuthenticationResult(uint64_t contextId, const std::vector\<uint8_t>& scheduleResult,<br/>        AuthResultInfo& info) | 更新认证结果,进行此次认证方案结果的评估。                   |
134| CancelAuthentication(uint64_t contextId)      | 取消此次认证。             |
135| BeginIdentification(uint64_t contextId, AuthType authType, const std::vector\<int8_t>& challenge,<br/>        uint32_t executorId, ScheduleInfo& scheduleInfo) | 发起识别,生成识别方案和调度信息(V1_0版本)。                           |
136| UpdateIdentificationResult(uint64_t contextId, const std::vector\<uint8_t>& scheduleResult,<br/>        IdentifyResultInfo& info) | 更新识别结果,进行此次识别方案结果的评估。                   |
137| CancelIdentification(uint64_t contextId)             | 取消此次识别。              |
138| GetAuthTrustLevel(int32_t userId, AuthType authType, uint32_t& authTrustLevel) | 获取此用户当前认证类型的认证可信等级。     |
139| GetValidSolution(int32_t userId, const std::vector\<AuthType>& authTypes, uint32_t authTrustLevel,<br/>        std::vector\<AuthType>& validTypes) | 筛选此用户当前认证可信等级下可用的认证方式。                   |
140| BeginEnrollmentV1_1(int32_t userId, const std::vector\<uint8_t>& authToken, const EnrollParam& param, ScheduleInfoV1_1& info) | 发起用户的认证凭据的录入,当录入类型为PIN码且当前用户已录入PIN码的情况下会更新PIN码(V1_1版本)。 |
141| BeginAuthenticationV1_1(uint64_t contextId, const AuthSolution& param,  std::vector\<ScheduleInfoV1_1>& scheduleInfos) | 发起认证,生成认证方案和调度信息(V1_1版本)。                           |
142| BeginIdentificationV1_1(uint64_t contextId, AuthType authType,
143 const std::vector\<uint8_t>& challenge, uint32_t executorSensorHint, ScheduleInfoV1_1& scheduleInfo)| 发起识别,生成识别方案和调度信息(V1_1版本)。                           |
144
145### 开发步骤
146
147以Hi3516DV300平台为例,我们提供了User_auth驱动DEMO实例,以下是目录结构及各部分功能简介。
148
149```undefined
150// drivers/peripheral/user_auth
151├── BUILD.gn     # 编译脚本
152├── bundle.json  # 组件描述文件
153└── hdi_service  # User_auth驱动实现
154    ├── BUILD.gn   # 编译脚本
155    ├── module     # 功能实现
156    └── service
157        ├── user_auth_interface_driver.cpp   # User_auth驱动入口
158        └── user_auth_interface_service.cpp  # 获取执行器列表接口实现
159```
160
161下面结合DEMO实例介绍驱动开发的具体步骤。
162
1631. 基于HDF驱动框架,按照驱动Driver Entry程序,完成User_auth驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现,详细代码参见[user_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_driver.cpp)文件。
164
165   ```c++
166   // 通过自定义的HdfUserAuthInterfaceHost对象包含IoService对象和真正的HDI Service实现IRemoteObject对象
167   struct HdfUserAuthInterfaceHost {
168       struct IDeviceIoService ioService;
169       OHOS::sptr<OHOS::IRemoteObject> stub;
170   };
171
172   // 服务接口调用响应接口
173   static int32_t UserAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
174       struct HdfSBuf *reply)
175   {
176       auto *hdfUserAuthInterfaceHost = CONTAINER_OF(client->device->service, struct HdfUserAuthInterfaceHost, ioService);
177
178       OHOS::MessageParcel *dataParcel = nullptr;
179       OHOS::MessageParcel *replyParcel = nullptr;
180       OHOS::MessageOption option;
181
182       if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
183           HDF_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__);
184           return HDF_ERR_INVALID_PARAM;
185       }
186       if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
187           HDF_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__);
188           return HDF_ERR_INVALID_PARAM;
189       }
190
191       return hdfUserAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
192   }
193
194   // 初始化接口
195   int HdfUserAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
196   {
197       HDF_LOGI("HdfUserAuthInterfaceDriverInit enter");
198       OHOS::UserIAM::Common::Init();
199       return HDF_SUCCESS;
200   }
201
202   // User_auth驱动对外提供的服务绑定到HDF框架
203   int HdfUserAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
204   {
205       HDF_LOGI("HdfUserAuthInterfaceDriverBind enter");
206
207       auto *hdfUserAuthInterfaceHost = new (std::nothrow) HdfUserAuthInterfaceHost;
208       if (hdfUserAuthInterfaceHost == nullptr) {
209           HDF_LOGE("%{public}s: failed to create HdfUserAuthInterfaceHost object", __func__);
210           return HDF_FAILURE;
211       }
212
213       hdfUserAuthInterfaceHost->ioService.Dispatch = UserAuthInterfaceDriverDispatch;
214       hdfUserAuthInterfaceHost->ioService.Open = NULL;
215       hdfUserAuthInterfaceHost->ioService.Release = NULL;
216
217       auto serviceImpl = IUserAuthInterface::Get(true);
218       if (serviceImpl == nullptr) {
219           HDF_LOGE("%{public}s: failed to implement service", __func__);
220           return HDF_FAILURE;
221       }
222
223       hdfUserAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
224           IUserAuthInterface::GetDescriptor());
225       if (hdfUserAuthInterfaceHost->stub == nullptr) {
226           HDF_LOGE("%{public}s: failed to get stub object", __func__);
227           return HDF_FAILURE;
228       }
229
230       deviceObject->service = &hdfUserAuthInterfaceHost->ioService;
231       return HDF_SUCCESS;
232   }
233
234   // 释放User_auth驱动中的资源
235   void HdfUserAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject){
236       HDF_LOGI("HdfUserAuthInterfaceDriverRelease enter");
237       auto *hdfUserAuthInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfUserAuthInterfaceHost, ioService);
238       delete hdfUserAuthInterfaceHost;
239   }
240
241   // 注册User_auth驱动入口数据结构体对象
242   struct HdfDriverEntry g_userAuthInterfaceDriverEntry = {
243       .moduleVersion = 1,
244       .moduleName = "user_auth_device_driver",
245       .Bind = HdfUserAuthInterfaceDriverBind,
246       .Init = HdfUserAuthInterfaceDriverInit,
247       .Release = HdfUserAuthInterfaceDriverRelease,
248   };
249
250   // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出
251   #ifndef __cplusplus
252   extern "C" {
253   #endif
254   HDF_INIT(g_userAuthInterfaceDriverEntry);
255   #ifndef __cplusplus
256   }
257   #endif
258   ```
259
2602. 执行器注册接口举例实现,详细代码参见[user_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_service.cpp)文件。
261
262   ```c++
263   // 添加执行器
264   int32_t UserAuthInterfaceService::AddExecutor(const ExecutorRegisterInfo& info, uint64_t& index,
265       std::vector<uint8_t>& publicKey, std::vector<uint64_t>& templateIds)
266   {
267       GlobalLock();
268       ExecutorInfoHal executorInfoHal;
269       CopyExecutorInfo(info, executorInfoHal);
270       int32_t ret = RegisterExecutor(&executorInfoHal, &index);
271       GlobalUnLock();
272       return ret;
273   }
274
275   // 删除执行器
276   int32_t UserAuthInterfaceService::DeleteExecutor(uint64_t index)
277   {
278       return UnRegisterExecutor(index);
279   }
280   ```
281
2823. 录入接口举例实现,详细代码参见[user_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_service.cpp)文件。
283
284   ```c++
285   // 开启认证凭据管理会话
286   int32_t UserAuthInterfaceService::OpenSession(int32_t userId, std::vector<uint8_t>& challenge)
287   {
288       GlobalLock();
289       uint64_t challengeU64 = 0;
290       int32_t ret = OpenEditSession(userId, &challengeU64);
291       challenge.resize(sizeof(uint64_t));
292       if (memcpy_s(&challenge[0], challenge.size(), &challengeU64, sizeof(uint64_t)) != EOK) {
293           IAM_LOGE("failed to copy challengeU64");
294           return RESULT_BAD_COPY;
295       }
296       GlobalUnLock();
297       return ret;
298   }
299
300   // 关闭认证凭据管理会话
301   int32_t UserAuthInterfaceService::CloseSession(int32_t userId)
302   {
303       GlobalLock();
304       int32_t ret = CloseEditSession();
305       GlobalUnLock();
306       return ret;
307   }
308
309   // 发起录入,生成录入调度信息(V1_1版本)
310   int32_t UserAuthInterfaceService::BeginEnrollmentV1_1(int32_t userId, const std::vector<uint8_t>& authToken,
311       const EnrollParam& param, ScheduleInfoV1_1& info)
312   {
313       IAM_LOGI("start");
314       GlobalLock();
315       if (authToken.size() != sizeof(UserAuthTokenHal) && param.authType != PIN) {
316           IAM_LOGE("authToken len is invalid");
317           GlobalUnLock();
318           return RESULT_BAD_PARAM;
319       }
320       PermissionCheckParam checkParam;
321       if (authToken.size() == sizeof(UserAuthTokenHal) &&
322           memcpy_s(checkParam.token, AUTH_TOKEN_LEN, &authToken[0], authToken.size()) != EOK) {
323           GlobalUnLock();
324           return RESULT_BAD_COPY;
325       }
326       checkParam.authType = param.authType;
327       checkParam.userId = userId;
328       checkParam.authSubType = (uint64_t)param.executorType;
329       CoAuthSchedule scheduleInfo;
330       int32_t ret = CheckEnrollPermission(checkParam, &scheduleInfo.scheduleId);
331       if (ret != RESULT_SUCCESS) {
332           IAM_LOGE("Failed to check permission");
333           GlobalUnLock();
334           return ret;
335       }
336       ret = GetCoAuthSchedule(&scheduleInfo);
337       if (ret != RESULT_SUCCESS) {
338           IAM_LOGE("Failed to get schedule info");
339           GlobalUnLock();
340           return ret;
341       }
342       if (!CopyScheduleInfo(&scheduleInfo, &info)) {
343           IAM_LOGE("Failed to copy schedule info");
344           ret = RESULT_BAD_COPY;
345       }
346       GlobalUnLock();
347       return ret;
348   }
349
350   // 发起录入,生成录入调度信息(V1_0版本),通过调用 V1_1 版本相应接口实现功能
351   int32_t UserAuthInterfaceService::BeginEnrollment(int32_t userId, const std::vector<uint8_t> &authToken,
352       const EnrollParam &param, ScheduleInfo &info)
353   {
354       IAM_LOGI("start");
355       ScheduleInfoV1_1 infoV1_1;
356       int32_t ret = BeginEnrollmentV1_1(userId, authToken, param, infoV1_1);
357       CopyScheduleInfoV1_1ToV1_0(infoV1_1, info);
358       return ret;
359   }
360
361   // 取消录入接口实现
362   int32_t UserAuthInterfaceService::CancelEnrollment(int32_t userId)
363   {
364       IAM_LOGI("start");
365       BreakOffCoauthSchedule(userId);
366       return RESULT_SUCCESS;
367   }
368
369   // 录入凭据信息存储接口实现
370   int32_t UserAuthInterfaceService::UpdateEnrollmentResult(int32_t userId, const std::vector<uint8_t>& scheduleResult,
371       uint64_t& credentialId, CredentialInfo& oldInfo)
372   {
373       IAM_LOGI("start");
374       GlobalLock();
375       if (scheduleResult.size() == 0) {
376           IAM_LOGE("enrollToken is invalid");
377           GlobalUnLock();
378           return RESULT_BAD_PARAM;
379       }
380       Buffer *scheduleResultBuffer = CreateBufferByData(&scheduleResult[0], scheduleResult.size());
381       if (scheduleResultBuffer == nullptr) {
382           IAM_LOGE("scheduleTokenBuffer is null");
383           GlobalUnLock();
384           return RESULT_NO_MEMORY;
385       }
386       bool isUpdate;
387       int32_t ret = GetIsUpdate(&isUpdate);
388       if (ret != RESULT_SUCCESS) {
389           IAM_LOGE("Failed to get isUpdate");
390           return ret;
391       }
392       if (isUpdate) {
393           CredentialInfoHal oldCredentialHal;
394           ret = UpdateCredentialFunc(scheduleResultBuffer, &credentialId, &oldCredentialHal);
395           oldInfo.authType = static_cast<AuthType>(oldCredentialHal.authType);
396           oldInfo.credentialId = oldCredentialHal.credentialId;
397           oldInfo.templateId = oldCredentialHal.templateId;
398           oldInfo.executorType = static_cast<uint32_t>(oldCredentialHal.authSubType);
399           oldInfo.executorId = 0;
400           oldInfo.index = 0;
401       } else {
402           ret = AddCredentialFunc(scheduleResultBuffer, &credentialId);
403       }
404       DestoryBuffer(scheduleResultBuffer);
405       GlobalUnLock();
406       return ret;
407   }
408   ```
409
4104. 认证接口举例实现,详细代码参见[user_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/user_auth/hdi_service/service/user_auth_interface_service.cpp)文件。
411
412   ```c++
413   // 创建HDI服务对象
414   extern "C" IUserAuthInterface *UserAuthInterfaceImplGetInstance(void)
415   {
416       auto userAuthInterfaceService = new (std::nothrow) UserAuthInterfaceService();
417       if (userAuthInterfaceService == nullptr) {
418           IAM_LOGE("userAuthInterfaceService is nullptr");
419           return nullptr;
420       }
421       return userAuthInterfaceService;
422   }
423
424   // 发起认证,生成认证方案和调度信息
425   int32_t UserAuthInterfaceService::BeginAuthenticationV1_1(uint64_t contextId, const AuthSolution& param,
426       std::vector<ScheduleInfoV1_1>& infos)
427   {
428       IAM_LOGI("start");
429       if (param.challenge.size() != sizeof(uint64_t)) {
430           IAM_LOGE("Failed to copy challenge");
431           return RESULT_BAD_PARAM;
432       }
433       GlobalLock();
434       CoAuthSchedule *schedulesGet = nullptr;
435       uint32_t scheduleIdNum = 0;
436       AuthSolutionHal solutionIn;
437       solutionIn.contextId = contextId;
438       solutionIn.userId = param.userId;
439       solutionIn.authType = static_cast<uint32_t>(param.authType);
440       solutionIn.authTrustLevel = param.authTrustLevel;
441       if (memcpy_s(&solutionIn.challenge, sizeof(uint64_t), &param.challenge[0],
442           param.challenge.size()) != EOK) {
443           IAM_LOGE("Failed to copy challenge");
444           GlobalUnLock();
445           return RESULT_BAD_COPY;
446       }
447       int32_t ret = GenerateSolutionFunc(solutionIn, &schedulesGet, &scheduleIdNum);
448       if (ret != RESULT_SUCCESS) {
449           IAM_LOGE("Failed to generate solution");
450           GlobalUnLock();
451           return ret;
452       }
453       for (uint32_t i = 0; i < scheduleIdNum; i++) {
454           ScheduleInfoV1_1 temp;
455           if (!CopyScheduleInfo(schedulesGet + i, &temp)) {
456               infos.clear();
457               ret = RESULT_GENERAL_ERROR;
458               break;
459           }
460           infos.push_back(temp);
461       }
462       free(schedulesGet);
463       GlobalUnLock();
464       return ret;
465   }
466
467   // 发起认证,生成认证方案和调度信息(V1_0版本),通过调用 V1_1 版本相应接口实现功能
468   int32_t UserAuthInterfaceService::BeginAuthentication(uint64_t contextId, const AuthSolution &param,
469       std::vector<ScheduleInfo> &infos)
470   {
471       IAM_LOGI("start");
472       std::vector<ScheduleInfoV1_1> infosV1_1;
473       int32_t ret = BeginAuthenticationV1_1(contextId, param, infosV1_1);
474       CopyScheduleInfosV1_1ToV1_0(infosV1_1, infos);
475       return ret;
476   }
477
478   // 更新认证结果,进行此次认证方案结果的评估
479   int32_t UserAuthInterfaceService::UpdateAuthenticationResult(uint64_t contextId,
480       const std::vector<uint8_t>& scheduleResult, AuthResultInfo& info)
481   {
482       IAM_LOGI("start");
483       GlobalLock();
484       if (scheduleResult.size() == 0) {
485           IAM_LOGE("param is invalid");
486           info.result = RESULT_BAD_PARAM;
487           GlobalUnLock();
488           return RESULT_BAD_PARAM;
489       }
490       Buffer *scheduleResultBuffer = CreateBufferByData(&scheduleResult[0], scheduleResult.size());
491       if (scheduleResultBuffer == nullptr) {
492           IAM_LOGE("scheduleTokenBuffer is null");
493           info.result = RESULT_GENERAL_ERROR;
494           GlobalUnLock();
495           return RESULT_NO_MEMORY;
496       }
497       UserAuthTokenHal authTokenHal;
498       info.result = RequestAuthResultFunc(contextId, scheduleResultBuffer, &authTokenHal);
499       if (info.result != RESULT_SUCCESS) {
500           IAM_LOGE("Failed to execute func");
501           DestoryBuffer(scheduleResultBuffer);
502           GlobalUnLock();
503           return info.result;
504       }
505       info.token.resize(sizeof(UserAuthTokenHal));
506       if (memcpy_s(&info.token[0], info.token.size(), &authTokenHal, sizeof(authTokenHal)) != EOK) {
507           IAM_LOGE("Failed to copy authToken");
508           DestoryBuffer(scheduleResultBuffer);
509           GlobalUnLock();
510           return RESULT_BAD_COPY;
511       }
512       DestoryBuffer(scheduleResultBuffer);
513       GlobalUnLock();
514       return RESULT_SUCCESS;
515   }
516
517   // 取消认证
518   int32_t UserAuthInterfaceService::CancelAuthentication(uint64_t contextId)
519   {
520       IAM_LOGI("start");
521       GlobalLock();
522       uint32_t scheduleIdNum = 0;
523       int32_t ret = CancelContextFunc(contextId, nullptr, &scheduleIdNum);
524       if (ret != RESULT_SUCCESS) {
525           IAM_LOGE("Failed to execute func");
526           GlobalUnLock();
527           return ret;
528       }
529       GlobalUnLock();
530       return RESULT_SUCCESS;
531   }
532   ```
533
534### 调测验证
535
536驱动开发完成后,通过[用户认证API接口](../../application-dev/reference/apis/js-apis-useriam-userauth.md)开发JS应用,基于Hi3516DV300平台验证。认证和取消功能验证的JS测试代码如下:
537
538    ```js
539    // API version 9
540    import userIAM_userAuth from '@ohos.userIAM.userAuth';
541
542    let challenge = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
543    let authType = userIAM_userAuth.UserAuthType.FACE;
544    let authTrustLevel = userIAM_userAuth.AuthTrustLevel.ATL1;
545
546    // 获取认证对象
547    let auth;
548    try {
549        auth = userIAM_userAuth.getAuthInstance(challenge, authType, authTrustLevel);
550        console.log("get auth instance success");
551    } catch (error) {
552        console.log("get auth instance failed" + error);
553    }
554
555    // 订阅认证结果
556    try {
557        auth.on("result", {
558            callback: (result: userIAM_userAuth.AuthResultInfo) => {
559                console.log("authV9 result " + result.result);
560                console.log("authV9 token " + result.token);
561                console.log("authV9 remainAttempts " + result.remainAttempts);
562                console.log("authV9 lockoutDuration " + result.lockoutDuration);
563            }
564        });
565        console.log("subscribe authentication event success");
566    } catch (error) {
567        console.log("subscribe authentication event failed " + error);
568    }
569
570    // 开始认证
571    try {
572        auth.start();
573        console.info("authV9 start auth success");
574    } catch (error) {
575        console.info("authV9 start auth failed, error = " + error);
576    }
577
578    // 取消认证
579    try {
580        auth.cancel();
581        console.info("cancel auth success");
582    } catch (error) {
583        console.info("cancel auth failed, error = " + error);
584    }
585
586    // 取消订阅认证结果
587    try {
588        auth.off("result");
589        console.info("cancel subscribe authentication event success");
590    } catch (error) {
591        console.info("cancel subscribe authentication event failed, error = " + error);
592    }
593    ```
594