1 /*
2  * Copyright (C) 2023 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 <cinttypes>
17 #include <cstring>
18 #include <unistd.h>
19 #include <gtest/gtest.h>
20 #include "device_auth.h"
21 #include "device_auth_defines.h"
22 #include "json_utils.h"
23 #include "securec.h"
24 #include "nativetoken_kit.h"
25 #include "token_setproc.h"
26 #include "hc_dev_info.h"
27 
28 using namespace std;
29 using namespace testing::ext;
30 
31 namespace {
32 #define PROC_NAME_DEVICE_MANAGER "device_manager"
33 #define TEST_REQ_ID 123
34 #define TEST_OS_ACCOUNT_ID 100
35 #define TEST_APP_ID "TestAppId"
36 #define TEST_APP_ID2 "TestAppId2"
37 #define TEST_UDID "TestUdid"
38 #define TEST_UDID_CLIENT "5420459D93FE773F9945FD64277FBA2CAB8FB996DDC1D0B97676FBB1242B3930"
39 #define TEST_UDID_SERVER "52E2706717D5C39D736E134CC1E3BE1BAA2AA52DB7C76A37C749558BD2E6492C"
40 #define TEST_PIN_CODE "123456"
41 
42 static const char* AUTH_WITH_PIN_PARAMS = "{\"osAccountId\":100,\"acquireType\":0,\"pinCode\":\"123456\"}";
43 static const char* AUTH_DIRECT_PARAMS =
44     "{\"osAccountId\":100,\"acquireType\":0,\"serviceType\":\"service.type.import\",\"peerConnDeviceId\":"
45     "\"52E2706717D5C39D736E134CC1E3BE1BAA2AA52DB7C76A37C749558BD2E6492C\"}";
46 #define FIELD_PUBLIC_KEY "publicKey"
47 #define FIELD_PIN_CODE "pinCode"
48 #define SERVICE_TYPE_IMPORT "service.type.import"
49 #define DEFAULT_SERVICE_TYPE "service.type.default"
50 
51 enum AsyncStatus {
52     ASYNC_STATUS_WAITING = 0,
53     ASYNC_STATUS_TRANSMIT = 1,
54     ASYNC_STATUS_FINISH = 2,
55     ASYNC_STATUS_ERROR = 3
56 };
57 
58 static AsyncStatus volatile g_asyncStatus;
59 static uint32_t g_transmitDataMaxLen = 2048;
60 static uint8_t g_transmitData[2048] = { 0 };
61 static uint32_t g_transmitDataLen = 0;
62 
NativeTokenSet(const char * procName)63 static void NativeTokenSet(const char *procName)
64 {
65     const char *acls[] = {"ACCESS_IDS"};
66     const char *perms[] = {
67         "ohos.permission.PLACE_CALL",
68         "ohos.permission.ACCESS_IDS"
69     };
70     uint64_t tokenId;
71     NativeTokenInfoParams infoInstance = {
72         .dcapsNum = 0,
73         .permsNum = 2,
74         .aclsNum = 1,
75         .dcaps = NULL,
76         .perms = perms,
77         .acls = acls,
78         .processName = procName,
79         .aplStr = "system_core",
80     };
81     tokenId = GetAccessTokenId(&infoInstance);
82     SetSelfTokenID(tokenId);
83 }
84 
OnTransmit(int64_t requestId,const uint8_t * data,uint32_t dataLen)85 static bool OnTransmit(int64_t requestId, const uint8_t *data, uint32_t dataLen)
86 {
87     if (memcpy_s(g_transmitData, g_transmitDataMaxLen, data, dataLen) != EOK) {
88         return false;
89     }
90     g_transmitDataLen = dataLen;
91     g_asyncStatus = ASYNC_STATUS_TRANSMIT;
92     return true;
93 }
94 
OnSessionKeyReturned(int64_t requestId,const uint8_t * sessionKey,uint32_t sessionKeyLen)95 static void OnSessionKeyReturned(int64_t requestId, const uint8_t *sessionKey, uint32_t sessionKeyLen)
96 {
97     (void)requestId;
98     (void)sessionKey;
99     (void)sessionKeyLen;
100     return;
101 }
102 
OnFinish(int64_t requestId,int operationCode,const char * authReturn)103 static void OnFinish(int64_t requestId, int operationCode, const char *authReturn)
104 {
105     g_asyncStatus = ASYNC_STATUS_FINISH;
106 }
107 
OnError(int64_t requestId,int operationCode,int errorCode,const char * errorReturn)108 static void OnError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn)
109 {
110     g_asyncStatus = ASYNC_STATUS_ERROR;
111 }
112 
OnAuthRequestDirectTmp(int64_t requestId,int operationCode,const char * reqParam)113 static char *OnAuthRequestDirectTmp(int64_t requestId, int operationCode, const char *reqParam)
114 {
115     CJson *json = CreateJson();
116     AddIntToJson(json, FIELD_CONFIRMATION, REQUEST_ACCEPTED);
117     AddStringToJson(json, FIELD_PIN_CODE, TEST_PIN_CODE);
118     AddStringToJson(json, FIELD_PEER_CONN_DEVICE_ID, TEST_UDID_CLIENT);
119     char *returnDataStr = PackJsonToString(json);
120     FreeJson(json);
121     return returnDataStr;
122 }
123 
OnAuthRequestDirect(int64_t requestId,int operationCode,const char * reqParam)124 static char *OnAuthRequestDirect(int64_t requestId, int operationCode, const char *reqParam)
125 {
126     CJson *json = CreateJson();
127     AddIntToJson(json, FIELD_CONFIRMATION, REQUEST_ACCEPTED);
128     AddStringToJson(json, FIELD_PEER_CONN_DEVICE_ID, TEST_UDID_CLIENT);
129     AddStringToJson(json, FIELD_SERVICE_TYPE, SERVICE_TYPE_IMPORT);
130     char *returnDataStr = PackJsonToString(json);
131     FreeJson(json);
132     return returnDataStr;
133 }
134 
135 static DeviceAuthCallback g_daTmpCallback = {
136     .onTransmit = OnTransmit,
137     .onSessionKeyReturned = OnSessionKeyReturned,
138     .onFinish = OnFinish,
139     .onError = OnError,
140     .onRequest = OnAuthRequestDirectTmp
141 };
142 
143 static DeviceAuthCallback g_daLTCallback = {
144     .onTransmit = OnTransmit,
145     .onSessionKeyReturned = OnSessionKeyReturned,
146     .onFinish = OnFinish,
147     .onError = OnError,
148     .onRequest = OnAuthRequestDirect
149 };
150 
CreateCredentialParamsJson(int32_t osAccountId,const char * deviceId,int32_t flag,const char * serviceType,CJson * out)151 static void CreateCredentialParamsJson(
152     int32_t osAccountId, const char *deviceId, int32_t flag,
153     const char *serviceType, CJson *out)
154 {
155     AddIntToJson(out, FIELD_OS_ACCOUNT_ID, osAccountId);
156     AddStringToJson(out, FIELD_DEVICE_ID, deviceId);
157     AddStringToJson(out, FIELD_SERVICE_TYPE, serviceType);
158     AddIntToJson(out, FIELD_ACQURIED_TYPE, P2P_BIND);
159 
160     if (flag >= 0) {
161         AddIntToJson(out, FIELD_CRED_OP_FLAG, flag);
162     }
163     return;
164 }
165 
GetSelfUdid(char ** selfUdid)166 static int32_t GetSelfUdid(char **selfUdid)
167 {
168     printf("%s called.\n", __FUNCTION__);
169     char udid[INPUT_UDID_LEN] = { 0 };
170     int32_t res = HcGetUdid((uint8_t *)udid, INPUT_UDID_LEN);
171     if (res != HC_SUCCESS) {
172         printf("Failed to get self udid! res: %d", res);
173         return res;
174     }
175 
176     printf("self udid: %s\n", udid);
177     *selfUdid = strdup(udid);
178     return HC_SUCCESS;
179 }
180 
CreateServerKeyPair()181 static int32_t CreateServerKeyPair()
182 {
183     char *selfUdid = nullptr;
184     int32_t res = GetSelfUdid(&selfUdid);
185     if (res != HC_SUCCESS) {
186         return res;
187     }
188     CJson *json = CreateJson();
189     if (json == nullptr) {
190         printf("Failed to create json!\n");
191         free(selfUdid);
192         return HC_ERR_JSON_CREATE;
193     }
194     CreateCredentialParamsJson(TEST_OS_ACCOUNT_ID, selfUdid, RETURN_FLAG_PUBLIC_KEY,
195         DEFAULT_SERVICE_TYPE, json);
196     char *requestParams = PackJsonToString(json);
197     FreeJson(json);
198     free(selfUdid);
199     if (requestParams == nullptr) {
200         printf("Failed to pack json to string!\n");
201         return HC_ERR_PACKAGE_JSON_TO_STRING_FAIL;
202     }
203     char *returnData = nullptr;
204 
205     printf("ProcessCredentialDemo: operationCode=%d\n", CRED_OP_CREATE);
206     res = ProcessCredential(CRED_OP_CREATE, requestParams, &returnData);
207     FreeJsonString(requestParams);
208     if (returnData) {
209         printf("returnData: %s\n", returnData);
210         CJson *in = CreateJsonFromString(returnData);
211         if (in == nullptr) {
212             printf("CreateJsonFromString returnData failed !\n");
213         } else {
214             if (GetIntFromJson(in, FIELD_CRED_OP_RESULT, &res) != HC_SUCCESS) {
215                 printf("GetIntFromJson  result failed !\n");
216                 FreeJson(in);
217                 return HC_ERR_INVALID_PARAMS;
218             }
219             printf("get  result from returnData: %d\n", res);
220             return res;
221         }
222     }
223 
224     printf("returnData is null !\n");
225 
226     return res;
227 }
228 
DeleteServerKeyPair()229 static int32_t DeleteServerKeyPair()
230 {
231     char *selfUdid = nullptr;
232     int32_t res = GetSelfUdid(&selfUdid);
233     if (res != HC_SUCCESS) {
234         return res;
235     }
236     CJson *json = CreateJson();
237     if (json == nullptr) {
238         printf("Failed to create json!\n");
239         free(selfUdid);
240         return HC_ERR_ALLOC_MEMORY;
241     }
242     CreateCredentialParamsJson(TEST_OS_ACCOUNT_ID, selfUdid, 1, DEFAULT_SERVICE_TYPE, json);
243     char *requestParams = PackJsonToString(json);
244     FreeJson(json);
245     free(selfUdid);
246     if (requestParams == nullptr) {
247         printf("Failed to pack json to string!\n");
248         return HC_ERR_PACKAGE_JSON_TO_STRING_FAIL;
249     }
250     char *returnData = nullptr;
251 
252     printf("ProcessCredentialDemo: operationCode=%d\n", CRED_OP_DELETE);
253     res = ProcessCredential(CRED_OP_DELETE, requestParams, &returnData);
254     FreeJsonString(requestParams);
255     if (returnData) {
256         printf("returnData: %s\n", returnData);
257         CJson *in = CreateJsonFromString(returnData);
258         if (in == nullptr) {
259             printf("CreateJsonFromString returnData failed !\n");
260         } else {
261             if (GetIntFromJson(in, FIELD_CRED_OP_RESULT, &res) != HC_SUCCESS) {
262                 printf("GetIntFromJson  result failed !\n");
263                 FreeJson(in);
264                 return HC_ERR_INVALID_PARAMS;
265             }
266             printf("get  result from returnData: %d\n", res);
267             return res;
268         }
269     }
270 
271     printf("returnData is null !\n");
272 
273     return res;
274 }
275 
ProcessCredentialDemo(int operationCode,const char * serviceType)276 static int32_t ProcessCredentialDemo(int operationCode, const char *serviceType)
277 {
278     int32_t flag = -1;
279     if (operationCode == CRED_OP_CREATE || operationCode == CRED_OP_QUERY) {
280         flag = 1;
281     }
282     CJson *json = CreateJson();
283     if (json == NULL) {
284         return HC_ERR_ALLOC_MEMORY;
285     }
286     CreateCredentialParamsJson(TEST_OS_ACCOUNT_ID, TEST_UDID, flag, serviceType, json);
287     char *requestParams = PackJsonToString(json);
288     FreeJson(json);
289     char *returnData = nullptr;
290 
291     printf("ProcessCredentialDemo: operationCode=%d\n", operationCode);
292     int32_t res = ProcessCredential(operationCode, requestParams, &returnData);
293     FreeJsonString(requestParams);
294     if (returnData) {
295         printf("returnData: %s\n", returnData);
296         CJson *in = CreateJsonFromString(returnData);
297         if (in == nullptr) {
298             printf("CreateJsonFromString returnData failed !\n");
299         } else {
300             if (GetIntFromJson(in, FIELD_CRED_OP_RESULT, &res) != HC_SUCCESS) {
301                 printf("GetIntFromJson  result failed !\n");
302                 FreeJson(in);
303                 return HC_ERR_INVALID_PARAMS;
304             }
305             printf("get  result from returnData: %d\n", res);
306             return res;
307         }
308     }
309 
310     printf("returnData is null !\n");
311 
312     return res;
313 }
314 
ProcessCredentialDemoImport(const char * importServiceType)315 static int32_t ProcessCredentialDemoImport(const char *importServiceType)
316 {
317     CJson *json = CreateJson();
318     if (json == NULL) {
319         return HC_ERR_ALLOC_MEMORY;
320     }
321     CreateCredentialParamsJson(TEST_OS_ACCOUNT_ID, TEST_UDID, -1, importServiceType, json);
322     AddStringToJson(json, FIELD_PUBLIC_KEY,
323         "CA32A9DFACB944B1F6292C9AE10783F6376A987A9CE30C13300BC866917DFF2E");
324     char *requestParams = PackJsonToString(json);
325     FreeJson(json);
326     char *returnData = nullptr;
327 
328     printf("ProcessCredentialDemoImport\n");
329     int32_t res = ProcessCredential(CRED_OP_IMPORT, requestParams, &returnData);
330     FreeJsonString(requestParams);
331     if (returnData) {
332         CJson *in = CreateJsonFromString(returnData);
333         if (in == nullptr) {
334             printf("CreateJsonFromString returnData failed !\n");
335         } else {
336             if (GetIntFromJson(in, FIELD_CRED_OP_RESULT, &res) != HC_SUCCESS) {
337                 printf("GetIntFromJson  result failed !\n");
338                 FreeJson(in);
339                 return HC_ERR_INVALID_PARAMS;
340             }
341             printf("get  result from returnData: %d\n", res);
342             return res;
343         }
344     }
345 
346     printf("returnData is null !\n");
347 
348     return res;
349 }
350 
351 class DaAuthDeviceTest : public testing::Test {
352 public:
353     static void SetUpTestCase();
354     static void TearDownTestCase();
355     void SetUp();
356     void TearDown();
357 };
358 
SetUpTestCase()359 void DaAuthDeviceTest::SetUpTestCase() {}
360 
TearDownTestCase()361 void DaAuthDeviceTest::TearDownTestCase() {}
362 
SetUp()363 void DaAuthDeviceTest::SetUp()
364 {
365     NativeTokenSet(PROC_NAME_DEVICE_MANAGER);
366     int32_t ret = InitDeviceAuthService();
367     ASSERT_EQ(ret, HC_SUCCESS);
368 }
369 
TearDown()370 void DaAuthDeviceTest::TearDown()
371 {
372     DestroyDeviceAuthService();
373 }
374 
375 HWTEST_F(DaAuthDeviceTest, DaAuthDeviceTest001, TestSize.Level0)
376 {
377     int32_t res = StartAuthDevice(TEST_REQ_ID, AUTH_WITH_PIN_PARAMS, &g_daTmpCallback);
378     ASSERT_EQ(res, HC_SUCCESS);
379     res = CancelAuthRequest(TEST_REQ_ID, AUTH_WITH_PIN_PARAMS);
380     ASSERT_EQ(res, HC_SUCCESS);
381 }
382 
383 HWTEST_F(DaAuthDeviceTest, DaAuthDeviceTest002, TestSize.Level0)
384 {
385     int32_t res = StartAuthDevice(TEST_REQ_ID, AUTH_DIRECT_PARAMS, &g_daLTCallback);
386     ASSERT_EQ(res, HC_SUCCESS);
387     res = CancelAuthRequest(TEST_REQ_ID, AUTH_DIRECT_PARAMS);
388     ASSERT_EQ(res, HC_SUCCESS);
389 }
390 
391 HWTEST_F(DaAuthDeviceTest, DaAuthDeviceTest003, TestSize.Level0)
392 {
393     int32_t res = ProcessCredentialDemo(CRED_OP_DELETE, DEFAULT_SERVICE_TYPE);
394     ASSERT_EQ(res, HC_SUCCESS);
395     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
396     ASSERT_NE(res, HC_SUCCESS);
397     res = ProcessCredentialDemo(CRED_OP_CREATE, DEFAULT_SERVICE_TYPE);
398     ASSERT_EQ(res, HC_SUCCESS);
399     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
400     ASSERT_EQ(res, HC_SUCCESS);
401     res = ProcessCredentialDemo(CRED_OP_DELETE, DEFAULT_SERVICE_TYPE);
402     ASSERT_EQ(res, HC_SUCCESS);
403     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
404     ASSERT_NE(res, HC_SUCCESS);
405 }
406 
407 HWTEST_F(DaAuthDeviceTest, DaAuthDeviceTest004, TestSize.Level0)
408 {
409     int32_t res = ProcessCredentialDemo(CRED_OP_CREATE, DEFAULT_SERVICE_TYPE);
410     ASSERT_EQ(res, HC_SUCCESS);
411     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
412     ASSERT_EQ(res, HC_SUCCESS);
413     res = ProcessCredentialDemo(CRED_OP_DELETE, DEFAULT_SERVICE_TYPE);
414     ASSERT_EQ(res, HC_SUCCESS);
415     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
416     ASSERT_NE(res, HC_SUCCESS);
417 }
418 
419 HWTEST_F(DaAuthDeviceTest, DaAuthDeviceTest005, TestSize.Level0)
420 {
421     int32_t res = CreateServerKeyPair();
422     ASSERT_EQ(res, HC_SUCCESS);
423     res = ProcessCredentialDemoImport(SERVICE_TYPE_IMPORT);
424     ASSERT_EQ(res, HC_SUCCESS);
425     res = ProcessCredentialDemo(CRED_OP_QUERY, SERVICE_TYPE_IMPORT);
426     ASSERT_EQ(res, HC_SUCCESS);
427     res = ProcessCredentialDemo(CRED_OP_DELETE, SERVICE_TYPE_IMPORT);
428     ASSERT_EQ(res, HC_SUCCESS);
429     res = ProcessCredentialDemo(CRED_OP_QUERY, SERVICE_TYPE_IMPORT);
430     ASSERT_NE(res, HC_SUCCESS);
431     res = DeleteServerKeyPair();
432     ASSERT_EQ(res, HC_SUCCESS);
433 }
434 
435 HWTEST_F(DaAuthDeviceTest, DaAuthDeviceTest006, TestSize.Level0)
436 {
437     int32_t res = CreateServerKeyPair();
438     ASSERT_EQ(res, HC_SUCCESS);
439     res = ProcessCredentialDemoImport(SERVICE_TYPE_IMPORT);
440     ASSERT_EQ(res, HC_SUCCESS);
441     res = ProcessCredentialDemoImport(SERVICE_TYPE_IMPORT);
442     ASSERT_EQ(res, HC_SUCCESS);
443     res = ProcessCredentialDemo(CRED_OP_QUERY, SERVICE_TYPE_IMPORT);
444     ASSERT_EQ(res, HC_SUCCESS);
445     res = ProcessCredentialDemo(CRED_OP_DELETE, SERVICE_TYPE_IMPORT);
446     ASSERT_EQ(res, HC_SUCCESS);
447     res = ProcessCredentialDemo(CRED_OP_QUERY, SERVICE_TYPE_IMPORT);
448     ASSERT_NE(res, HC_SUCCESS);
449     res = DeleteServerKeyPair();
450     ASSERT_EQ(res, HC_SUCCESS);
451 }
452 
453 HWTEST_F(DaAuthDeviceTest, DaAuthDeviceTest007, TestSize.Level0)
454 {
455     int32_t res = ProcessCredentialDemo(CRED_OP_CREATE, DEFAULT_SERVICE_TYPE);
456     ASSERT_EQ(res, HC_SUCCESS);
457     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
458     ASSERT_EQ(res, HC_SUCCESS);
459     res = ProcessCredentialDemo(CRED_OP_CREATE, DEFAULT_SERVICE_TYPE);
460     ASSERT_NE(res, HC_SUCCESS);
461     res = ProcessCredentialDemo(CRED_OP_DELETE, DEFAULT_SERVICE_TYPE);
462     ASSERT_EQ(res, HC_SUCCESS);
463     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
464     ASSERT_NE(res, HC_SUCCESS);
465 }
466 
467 class ApiAccessBlockTest : public testing::Test {
468 public:
469     static void SetUpTestCase();
470     static void TearDownTestCase();
471     void SetUp();
472     void TearDown();
473 };
474 
SetUpTestCase()475 void ApiAccessBlockTest::SetUpTestCase() {}
476 
TearDownTestCase()477 void ApiAccessBlockTest::TearDownTestCase() {}
478 
SetUp()479 void ApiAccessBlockTest::SetUp()
480 {
481     NativeTokenSet(TEST_APP_ID2);
482     int32_t ret = InitDeviceAuthService();
483     ASSERT_EQ(ret, HC_SUCCESS);
484 }
485 
TearDown()486 void ApiAccessBlockTest::TearDown()
487 {
488     DestroyDeviceAuthService();
489 }
490 
491 HWTEST_F(ApiAccessBlockTest, ApiAccessBlockTest001, TestSize.Level0)
492 {
493     int32_t res = ProcessCredentialDemo(CRED_OP_CREATE, DEFAULT_SERVICE_TYPE);
494     ASSERT_NE(res, HC_SUCCESS);
495 }
496 
497 class ApiAccessPassTest : public testing::Test {
498 public:
499     static void SetUpTestCase();
500     static void TearDownTestCase();
501     void SetUp();
502     void TearDown();
503 };
504 
SetUpTestCase()505 void ApiAccessPassTest::SetUpTestCase() {}
506 
TearDownTestCase()507 void ApiAccessPassTest::TearDownTestCase() {}
508 
SetUp()509 void ApiAccessPassTest::SetUp()
510 {
511     NativeTokenSet(PROC_NAME_DEVICE_MANAGER);
512     int32_t ret = InitDeviceAuthService();
513     ASSERT_EQ(ret, HC_SUCCESS);
514 }
515 
TearDown()516 void ApiAccessPassTest::TearDown()
517 {
518     DestroyDeviceAuthService();
519 }
520 
521 HWTEST_F(ApiAccessPassTest, ApiAccessPassTest001, TestSize.Level0)
522 {
523     int32_t res = ProcessCredentialDemo(CRED_OP_CREATE, DEFAULT_SERVICE_TYPE);
524     ASSERT_EQ(res, HC_SUCCESS);
525     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
526     ASSERT_EQ(res, HC_SUCCESS);
527     res = ProcessCredentialDemo(CRED_OP_DELETE, DEFAULT_SERVICE_TYPE);
528     ASSERT_EQ(res, HC_SUCCESS);
529     res = ProcessCredentialDemo(CRED_OP_QUERY, DEFAULT_SERVICE_TYPE);
530     ASSERT_NE(res, HC_SUCCESS);
531 }
532 
533 }
534