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