1 /*
2 * Copyright (c) 2023-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 #ifdef HKS_CONFIG_FILE
17 #include HKS_CONFIG_FILE
18 #else
19 #include "hks_config.h"
20 #endif
21
22 #ifndef HKS_UNTRUSTED_RUNNING_ENV
23
24 #include "hks_dcm_callback_handler.h"
25
26 #include <cinttypes>
27 #include <cstdint>
28 #include <dlfcn.h>
29 #include <map>
30 #include <mutex>
31 #include <new>
32 #include <refbase.h>
33 #include <securec.h>
34
35 #include "hks_log.h"
36 #include "hks_report.h"
37 #include "hks_sa_interface.h"
38 #include "hks_template.h"
39 #include "hks_type.h"
40 #include "iremote_broker.h"
41 #include "iremote_object.h"
42
43 #define DCM_SDK_SO "libdevice_cert_mgr_sdk.z.so"
44
45 namespace OHOS {
46 namespace Security {
47 namespace Hks {
48
49 class ThreadSafeMap {
50 public:
GetMutex()51 std::mutex &GetMutex()
52 {
53 return mContainerLock;
54 }
SetNewInstanceWithoutLock(sptr<IHksService> index,uint64_t value)55 int32_t SetNewInstanceWithoutLock(sptr<IHksService> index, uint64_t value)
56 {
57 typename std::map<sptr<IHksService>, uint64_t>::iterator position = mValues.find(index);
58 if (position != mValues.end()) {
59 HKS_LOG_E("SetNewInstance: current value exist requestId = %" LOG_PUBLIC PRIu64, position->second);
60 return HKS_ERROR_ALREADY_EXISTS;
61 }
62 mValues[index] = value;
63 return HKS_SUCCESS;
64 }
GetProxyWithoutLock(uint64_t value)65 sptr<IHksService> GetProxyWithoutLock(uint64_t value)
66 {
67 auto position = findInMapByValue(value);
68 if (position == mValues.end()) {
69 HKS_LOG_E("GetProxyWithoutLock: current value not exist, requestId %" LOG_PUBLIC PRIu64, value);
70 return nullptr;
71 }
72 return position->first;
73 }
RemoveWithoutLock(uint64_t value)74 void RemoveWithoutLock(uint64_t value)
75 {
76 auto position = findInMapByValue(value);
77 if (position == mValues.end()) {
78 HKS_LOG_E("RemoveWithoutLock: current value not exist, requestId %" LOG_PUBLIC PRIu64, value);
79 return;
80 }
81 mValues.erase(position);
82 }
83 private:
84 std::mutex mContainerLock{};
85 std::map<sptr<IHksService>, uint64_t> mValues{};
findInMapByValue(uint64_t value)86 std::map<sptr<IHksService>, uint64_t>::iterator findInMapByValue(uint64_t value)
87 {
88 return std::find_if(
89 mValues.begin(), mValues.end(), [value](const std::pair<sptr<IHksService>, uint64_t> &element) {
90 return element.second == value;
91 });
92 }
93 };
94
CopyBlobToBuffer(const struct DcmBlob * blob,struct HksBlob * buf)95 int32_t CopyBlobToBuffer(const struct DcmBlob *blob, struct HksBlob *buf)
96 {
97 if (buf->size < sizeof(blob->size) + ALIGN_SIZE(blob->size)) {
98 HKS_LOG_E("buf size smaller than blob size");
99 return HKS_ERROR_BUFFER_TOO_SMALL;
100 }
101 if (memcpy_s(buf->data, buf->size, &blob->size, sizeof(blob->size)) != EOK) {
102 HKS_LOG_E("copy buf fail");
103 return HKS_ERROR_BUFFER_TOO_SMALL;
104 }
105 buf->data += sizeof(blob->size);
106 buf->size -= sizeof(blob->size);
107 if (memcpy_s(buf->data, buf->size, blob->data, blob->size) != EOK) {
108 HKS_LOG_E("copy buf fail");
109 return HKS_ERROR_BUFFER_TOO_SMALL;
110 }
111 buf->data += ALIGN_SIZE(blob->size);
112 buf->size -= ALIGN_SIZE(blob->size);
113 return HKS_SUCCESS;
114 }
115
PackAttestChain(struct DcmCertChain * certChain,struct HksBlob * certChainPacked)116 int32_t PackAttestChain(struct DcmCertChain *certChain, struct HksBlob *certChainPacked)
117 {
118 if (certChain == nullptr || certChain->certs == nullptr) {
119 HKS_LOG_E("certChain buffer from caller is null.");
120 return HKS_ERROR_NULL_POINTER;
121 }
122 if (certChain->certsCount == 0 || certChain->certsCount > HKS_CERT_COUNT) {
123 HKS_LOG_E("certs count %" LOG_PUBLIC "u is not correct", certChain->certsCount);
124 return HKS_ERROR_BUFFER_TOO_SMALL;
125 }
126 for (uint32_t i = 0; i < certChain->certsCount; ++i) {
127 if (certChain->certs[i].data == nullptr || certChain->certs[i].size == 0 ||
128 certChain->certs[i].size > HKS_CERT_APP_SIZE) {
129 HKS_LOG_E("cert %" LOG_PUBLIC "u is null or cert size %" LOG_PUBLIC "u invalid ",
130 i, certChain->certs[i].size);
131 return HKS_ERROR_INVALID_ARGUMENT;
132 }
133 }
134
135 struct HksBlob tmp = *certChainPacked;
136 if (tmp.size <= sizeof(uint32_t)) {
137 HKS_LOG_E("certChainPacked size too small");
138 return HKS_ERROR_BUFFER_TOO_SMALL;
139 }
140 *((uint32_t *)tmp.data) = certChain->certsCount;
141 tmp.data += sizeof(uint32_t);
142 tmp.size -= sizeof(uint32_t);
143 int32_t ret = 0;
144
145 for (uint32_t i = 0; i < certChain->certsCount; ++i) {
146 if (certChain->certs[i].data == nullptr) {
147 HKS_LOG_E("single cert %" LOG_PUBLIC "u from huks is null.", i);
148 ret = HKS_ERROR_NULL_POINTER;
149 break;
150 }
151 ret = CopyBlobToBuffer(&certChain->certs[i], &tmp);
152 HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "copy cert fail")
153 }
154 if (ret != HKS_SUCCESS) {
155 return ret;
156 }
157 certChainPacked->size = tmp.data - certChainPacked->data;
158 return HKS_SUCCESS;
159 }
160
161 ThreadSafeMap g_instancesList{};
162 void *g_certMgrSdkHandle{};
163 AttestFunction g_attestFunction{};
164
165 }}} // OHOS::Security::Hks
166
167 using OHOS::Security::Hks::g_instancesList;
168 using OHOS::Security::Hks::g_certMgrSdkHandle;
169 using OHOS::Security::Hks::g_attestFunction;
170 using OHOS::Security::Hks::IHksService;
171 using OHOS::Security::Hks::PackAttestChain;
172 using OHOS::sptr;
173
HksDcmCallback(DcmAnonymousResponse * response)174 void HksDcmCallback(DcmAnonymousResponse *response)
175 {
176 if (response == nullptr) {
177 HKS_LOG_E("dcm callback got null response");
178 HksReport(__func__, nullptr, nullptr, HUKS_ERR_CODE_EXTERNAL_ERROR);
179 return;
180 }
181 if (response->errCode != DCM_SUCCESS) {
182 HksReport(__func__, nullptr, nullptr, response->errCode);
183 }
184 HKS_LOG_I("dcm callback requestId %" LOG_PUBLIC PRIu64, response->requestId);
185 std::lock_guard<std::mutex> lockGuard(g_instancesList.GetMutex());
186 sptr<IHksService> hksProxy = g_instancesList.GetProxyWithoutLock(response->requestId);
187 if (hksProxy == nullptr) {
188 HKS_LOG_E("GetProxyWithoutLock failed *requestId %" LOG_PUBLIC PRIu64, response->requestId);
189 return;
190 }
191 std::unique_ptr<uint8_t[]> replyData = nullptr;
192 uint32_t replySize = 0;
193 do {
194 HKS_IF_NOT_SUCC_LOGE_BREAK(response->errCode, "HksDcmCallback failed %" LOG_PUBLIC "d", response->errCode)
195 uint32_t packedSize = HKS_CERT_ROOT_SIZE + HKS_CERT_CA_SIZE + HKS_CERT_DEVICE_SIZE + HKS_CERT_APP_SIZE;
196 std::unique_ptr<uint8_t[]> packedCertChain(new (std::nothrow) uint8_t[packedSize]());
197 HKS_IF_NULL_LOGE_BREAK(packedCertChain, "new cert chain buffer failed")
198 HksBlob packedBlob { .size = packedSize, .data = packedCertChain.get() };
199 int ret = PackAttestChain(response->certChain, &packedBlob);
200 HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "PackAttestChain failed %" LOG_PUBLIC "d", ret)
201 replyData = std::move(packedCertChain);
202 replySize = packedBlob.size;
203 } while (false);
204 hksProxy->SendAsyncReply(response->errCode, replyData, replySize);
205 g_instancesList.RemoveWithoutLock(response->requestId);
206 }
207
HksDcmCallbackHandlerSetRequestIdWithoutLock(const uint8_t * remoteObject,uint64_t requestId)208 int32_t HksDcmCallbackHandlerSetRequestIdWithoutLock(const uint8_t *remoteObject, uint64_t requestId)
209 {
210 auto hksProxy = OHOS::iface_cast<IHksService>(
211 reinterpret_cast<OHOS::IRemoteObject *>(const_cast<uint8_t *>(remoteObject)));
212 if (hksProxy == nullptr) {
213 HKS_LOG_E("iface_cast IHksService failed");
214 return HKS_ERROR_NULL_POINTER;
215 }
216 int ret = g_instancesList.SetNewInstanceWithoutLock(hksProxy, requestId);
217 if (ret != HKS_SUCCESS) {
218 HKS_LOG_E("g_instancesList.SetNewInstance failed %" LOG_PUBLIC "d", ret);
219 }
220 return ret;
221 }
222
HksDcmCallbackHandlerGetMapMutex(void)223 std::mutex &HksDcmCallbackHandlerGetMapMutex(void)
224 {
225 return g_instancesList.GetMutex();
226 }
227
HksOpenDcmFunction(void)228 AttestFunction HksOpenDcmFunction(void)
229 {
230 if (g_attestFunction != nullptr) {
231 return g_attestFunction;
232 }
233
234 g_certMgrSdkHandle = dlopen(DCM_SDK_SO, RTLD_NOW);
235 if (g_certMgrSdkHandle == nullptr) {
236 HKS_LOG_E("dlopen " DCM_SDK_SO " failed! %" LOG_PUBLIC "s", dlerror());
237 return nullptr;
238 }
239 g_attestFunction = reinterpret_cast<AttestFunction>(dlsym(g_certMgrSdkHandle, "DcmAnonymousAttestKey"));
240 if (g_attestFunction == nullptr) {
241 HKS_LOG_E("dlsym failed %" LOG_PUBLIC "s", dlerror());
242 HksCloseDcmFunction();
243 return nullptr;
244 }
245 return g_attestFunction;
246 }
247
HksCloseDcmFunction(void)248 void HksCloseDcmFunction(void)
249 {
250 if (g_certMgrSdkHandle == nullptr) {
251 g_attestFunction = nullptr;
252 return;
253 }
254 int ret = dlclose(g_certMgrSdkHandle);
255 if (ret != 0) {
256 HKS_LOG_E("dlclose g_certMgrSdkHandle failed %" LOG_PUBLIC "d %" LOG_PUBLIC "s", ret, dlerror());
257 }
258 g_certMgrSdkHandle = nullptr;
259 g_attestFunction = nullptr;
260 }
261
262 #endif // HKS_UNTRUSTED_RUNNING_ENV
263