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 #include <string>
16 #include <unordered_map>
17 #include "securec.h"
18 #include "js_async_work.h"
19 #include "devattest_errno.h"
20 #include "devattest_interface.h"
21 #include "devattest_log.h"
22 #include "native_device_attest.h"
23 using namespace std;
24 
25 namespace OHOS {
26 namespace ACELite {
27 static const std::unordered_map<uint32_t, std::string> g_errorStringMap = {
28     {DEVATTEST_ERR_JS_IS_NOT_SYSTEM_APP,
29         "This api is system api, Please use the system application to call this api"},
30     {DEVATTEST_ERR_JS_PARAMETER_ERROR, "Input paramters wrong"},
31     {DEVATTEST_ERR_JS_SYSTEM_SERVICE_EXCEPTION, "System service exception, please try again or reboot your device"},
32 };
33 
GetErrorMessage(uint32_t errorCode)34 string GetErrorMessage(uint32_t errorCode)
35 {
36     auto iter = g_errorStringMap.find(errorCode);
37     if (iter != g_errorStringMap.end()) {
38         return iter->second;
39     } else {
40         return "Unknown error, please reboot your device and try again";
41     }
42 }
43 
GetJsiErrorMessage(int32_t errorCode)44 static JSIValue GetJsiErrorMessage(int32_t errorCode)
45 {
46     JSIValue error = JSI::CreateObject();
47     if (error == nullptr) {
48         return nullptr;
49     }
50     if (errorCode == DEVATTEST_FAIL) {
51         errorCode = DEVATTEST_ERR_JS_SYSTEM_SERVICE_EXCEPTION;
52     }
53     JSI::SetStringProperty(error, "message", GetErrorMessage(errorCode).c_str());
54     JSI::SetNumberProperty(error, "code", errorCode);
55     return error;
56 }
57 
58 
FailCallBack(const JSIValue thisVal, const JSIValue args, int32_t ret)59 void FailCallBack(const JSIValue thisVal, const JSIValue args, int32_t ret)
60 {
61     if (JSI::ValueIsUndefined(args)) {
62         return;
63     }
64     JSIValue error = GetJsiErrorMessage(ret);
65     JSIValue data = JSI::CreateUndefined();
66     JSIValue argv[ARGC_TWO] = {error, data};
67     JSI::CallFunction(args, thisVal, argv, ARGC_TWO);
68     JSI::ReleaseValueList(error, data, ARGS_END);
69 }
70 
SuccessCallBack(const JSIValue thisVal, const JSIValue args, JSIValue jsiValue)71 void SuccessCallBack(const JSIValue thisVal, const JSIValue args, JSIValue jsiValue)
72 {
73     if (JSI::ValueIsUndefined(args)) {
74         return;
75     }
76     JSIValue error = JSI::CreateUndefined();
77     JSIValue argv[ARGC_TWO] = {error, jsiValue};
78     JSI::CallFunction(args, thisVal, argv, ARGC_TWO);
79     JSI::ReleaseValueList(error, ARGS_END);
80 }
81 
IsValidParam(const JSIValue* args, uint8_t argsNum)82 bool IsValidParam(const JSIValue* args, uint8_t argsNum)
83 {
84     if ((argsNum == 1) && !JSI::ValueIsUndefined(args[0])) {
85         return true;
86     }
87     return false;
88 }
89 
ExecuteAsyncWork(const JSIValue thisVal, const JSIValue* args, uint8_t argsNum, AsyncWorkHandler ExecuteFunc)90 JSIValue ExecuteAsyncWork(const JSIValue thisVal, const JSIValue* args,
91     uint8_t argsNum, AsyncWorkHandler ExecuteFunc)
92 {
93     JSIValue undefValue = JSI::CreateUndefined();
94     if (args == NULL) {
95         return GetJsiErrorMessage(DEVATTEST_ERR_JS_PARAMETER_ERROR);
96     }
97     if (!IsValidParam(args, argsNum)) {
98         FailCallBack(thisVal, *args, DEVATTEST_ERR_JS_PARAMETER_ERROR);
99         return undefValue;
100     }
101     FuncParams* params = new(std::nothrow) FuncParams();
102     if (params == nullptr) {
103         FailCallBack(thisVal, *args, DEVATTEST_ERR_JS_SYSTEM_SERVICE_EXCEPTION);
104         return undefValue;
105     }
106     params->thisVal = JSI::AcquireValue(thisVal);
107     params->args = JSI::AcquireValue(args[0]);
108     JsAsyncWork::DispatchAsyncWork(ExecuteFunc, reinterpret_cast<void *>(params));
109     return undefValue;
110 }
111 
SetJsResult(JSIValue *result, AttestResultInfo *attestResultInfo)112 int32_t SetJsResult(JSIValue *result, AttestResultInfo *attestResultInfo)
113 {
114     JSI::SetNumberProperty(*result, "authResult", attestResultInfo->authResult);
115     JSI::SetNumberProperty(*result, "softwareResult", attestResultInfo->softwareResult);
116 
117     JSIValue array = JSI::CreateNull();
118     size_t size = sizeof(attestResultInfo->softwareResultDetail) / sizeof(int32_t);
119     if (size > 0) {
120         bool isArray = false;
121         array = JSI::CreateArray(size);
122         isArray = JSI::ValueIsArray(array);
123         if (!isArray) {
124             HILOGE("JSI_create_array fail");
125             return DEVATTEST_FAIL;
126         }
127         JSIValue element = JSI::CreateNull();
128         for (size_t i = 0; i != size; ++i) {
129             element = JSI::CreateNumber(attestResultInfo->softwareResultDetail[i]);
130             JSI::SetPropertyByIndex(array, i, element);
131             JSI::ReleaseValue(element);
132         }
133     }
134     JSI::SetNamedProperty(*result, "softwareResultDetail", array);
135 
136     JSI::SetStringProperty(*result, "ticket", attestResultInfo->ticket);
137     return DEVATTEST_SUCCESS;
138 }
139 
GetAttestResultInfo(JSIValue *result)140 int32_t GetAttestResultInfo(JSIValue *result)
141 {
142     AttestResultInfo attestResultInfo = { 0 };
143     attestResultInfo.ticket = NULL;
144     int32_t ret = GetAttestStatus(&attestResultInfo);
145     if (ret != DEVATTEST_SUCCESS) {
146         HILOGE("[GetAttestResultInfo] Failed to GetAttestStatus");
147         return ret;
148     }
149 
150     if (attestResultInfo.ticket == NULL) {
151         return ret;
152     }
153 
154     ret = SetJsResult(result, &attestResultInfo);
155     free(attestResultInfo.ticket);
156     attestResultInfo.ticket = NULL;
157     return ret;
158 }
159 
ExecuteGetAttestResult(void* data)160 void ExecuteGetAttestResult(void* data)
161 {
162     FuncParams* params = reinterpret_cast<FuncParams *>(data);
163     if (params == nullptr) {
164         return;
165     }
166     JSIValue args = params->args;
167     JSIValue thisVal = params->thisVal;
168     JSIValue result = JSI::CreateObject();
169     int32_t ret = GetAttestResultInfo(&result);
170     if (ret != DEVATTEST_SUCCESS) {
171         FailCallBack(thisVal, args, ret);
172     } else {
173         SuccessCallBack(thisVal, args, result);
174     }
175     JSI::ReleaseValueList(args, thisVal, result, ARGS_END);
176     delete params;
177     params = nullptr;
178     return;
179 }
180 
GetAttestResultInfoSync(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)181 JSIValue NativeDeviceAttest::GetAttestResultInfoSync(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
182 {
183     HILOGI("[GetAttestResultInfoSync] In.");
184     AttestResultInfo attestResultInfo = { 0 };
185     attestResultInfo.ticket = NULL;
186 
187     int32_t ret = GetAttestStatus(&attestResultInfo);
188     if (ret != DEVATTEST_SUCCESS) {
189         HILOGE("[GetAttestResultInfoSync] Failed to GetAttestStatus");
190         return GetJsiErrorMessage(ret);
191     }
192 
193     if (attestResultInfo.ticket == NULL) {
194         return GetJsiErrorMessage(DEVATTEST_ERR_JS_SYSTEM_SERVICE_EXCEPTION);
195     }
196 
197     JSIValue result = JSI::CreateObject();
198     ret = SetJsResult(&result, &attestResultInfo);
199     if (ret != DEVATTEST_SUCCESS) {
200         JSI::ReleaseValueList(result, ARGS_END);
201         return GetJsiErrorMessage(DEVATTEST_ERR_JS_SYSTEM_SERVICE_EXCEPTION);
202     }
203 
204     free(attestResultInfo.ticket);
205     attestResultInfo.ticket = NULL;
206 
207     return result;
208 }
209 
GetAttestResultInfoAsync(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)210 JSIValue NativeDeviceAttest::GetAttestResultInfoAsync(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
211 {
212     HILOGI("[GetAttestResultInfoAsync] In.");
213     return ExecuteAsyncWork(thisVal, args, argsNum, ExecuteGetAttestResult);
214 }
215 
216 
InitDeviceAttestModule(JSIValue exports)217 void InitDeviceAttestModule(JSIValue exports)
218 {
219     JSI::SetModuleAPI(exports, "getAttestStatus", NativeDeviceAttest::GetAttestResultInfoAsync);
220     JSI::SetModuleAPI(exports, "getAttestStatusSync", NativeDeviceAttest::GetAttestResultInfoSync);
221 }
222 } // namespace ACELite
223 } // namespace OHOS