• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         HKS_IF_TRUE_LOGE_RETURN(position != mValues.end(), HKS_ERROR_ALREADY_EXISTS,
59             "SetNewInstance: current value exist requestId = %" LOG_PUBLIC PRIu64, position->second)
60         mValues[index] = value;
61         return HKS_SUCCESS;
62     }
GetProxyWithoutLock(uint64_t value)63     sptr<IHksService> GetProxyWithoutLock(uint64_t value)
64     {
65         auto position = findInMapByValue(value);
66         HKS_IF_TRUE_LOGE_RETURN(position == mValues.end(), nullptr,
67             "GetProxyWithoutLock: current value not exist, requestId %" LOG_PUBLIC PRIu64, value)
68         return position->first;
69     }
RemoveWithoutLock(uint64_t value)70     void RemoveWithoutLock(uint64_t value)
71     {
72         auto position = findInMapByValue(value);
73         HKS_IF_TRUE_LOGE_RETURN_VOID(position == mValues.end(),
74             "RemoveWithoutLock: current value not exist, requestId %" LOG_PUBLIC PRIu64, value)
75         mValues.erase(position);
76     }
77 private:
78     std::mutex mContainerLock{};
79     std::map<sptr<IHksService>, uint64_t> mValues{};
findInMapByValue(uint64_t value)80     std::map<sptr<IHksService>, uint64_t>::iterator findInMapByValue(uint64_t value)
81     {
82         return std::find_if(
83             mValues.begin(), mValues.end(), [value](const std::pair<sptr<IHksService>, uint64_t> &element) {
84             return element.second == value;
85         });
86     }
87 };
88 
CopyBlobToBuffer(const struct DcmBlob * blob,struct HksBlob * buf)89 int32_t CopyBlobToBuffer(const struct DcmBlob *blob, struct HksBlob *buf)
90 {
91     HKS_IF_TRUE_LOGE_RETURN(buf->size < sizeof(blob->size) + ALIGN_SIZE(blob->size), HKS_ERROR_BUFFER_TOO_SMALL,
92         "buf size smaller than blob size")
93     HKS_IF_NOT_EOK_LOGE_RETURN(memcpy_s(buf->data, buf->size, &blob->size, sizeof(blob->size)),
94         HKS_ERROR_BUFFER_TOO_SMALL, "copy buf fail")
95     buf->data += sizeof(blob->size);
96     buf->size -= sizeof(blob->size);
97     HKS_IF_NOT_EOK_LOGE_RETURN(memcpy_s(buf->data, buf->size, blob->data, blob->size),
98         HKS_ERROR_BUFFER_TOO_SMALL, "copy buf fail")
99     buf->data += ALIGN_SIZE(blob->size);
100     buf->size -= ALIGN_SIZE(blob->size);
101     return HKS_SUCCESS;
102 }
103 
PackAttestChain(struct DcmCertChain * certChain,struct HksBlob * certChainPacked)104 int32_t PackAttestChain(struct DcmCertChain *certChain, struct HksBlob *certChainPacked)
105 {
106     HKS_IF_TRUE_LOGE_RETURN(certChain == nullptr || certChain->certs == nullptr, HKS_ERROR_NULL_POINTER,
107         "certChain buffer from caller is null.")
108     HKS_IF_TRUE_LOGE_RETURN(certChain->certsCount == 0 || certChain->certsCount > HKS_CERT_COUNT,
109         HKS_ERROR_BUFFER_TOO_SMALL, "certs count %" LOG_PUBLIC "u is not correct", certChain->certsCount)
110     for (uint32_t i = 0; i < certChain->certsCount; ++i) {
111         HKS_IF_TRUE_LOGE_RETURN(certChain->certs[i].data == nullptr || certChain->certs[i].size == 0 ||
112             certChain->certs[i].size > HKS_CERT_APP_SIZE, HKS_ERROR_INVALID_ARGUMENT,
113             "cert %" LOG_PUBLIC "u is null or cert size %" LOG_PUBLIC "u invalid ", i, certChain->certs[i].size)
114     }
115 
116     struct HksBlob tmp = *certChainPacked;
117     HKS_IF_TRUE_LOGE_RETURN(tmp.size <= sizeof(uint32_t), HKS_ERROR_BUFFER_TOO_SMALL,
118         "certChainPacked size too small")
119     *((uint32_t *)tmp.data) = certChain->certsCount;
120     tmp.data += sizeof(uint32_t);
121     tmp.size -= sizeof(uint32_t);
122     int32_t ret = 0;
123 
124     for (uint32_t i = 0; i < certChain->certsCount; ++i) {
125         if (certChain->certs[i].data == nullptr) {
126             HKS_LOG_E("single cert %" LOG_PUBLIC "u from huks is null.", i);
127             ret = HKS_ERROR_NULL_POINTER;
128             break;
129         }
130         ret = CopyBlobToBuffer(&certChain->certs[i], &tmp);
131         HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "copy cert fail")
132     }
133     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "PackAttestChain fail")
134     certChainPacked->size = tmp.data - certChainPacked->data;
135     return HKS_SUCCESS;
136 }
137 
138 ThreadSafeMap g_instancesList{};
139 void *g_certMgrSdkHandle{};
140 AttestFunction g_attestFunction{};
141 
142 }}} // OHOS::Security::Hks
143 
144 using OHOS::Security::Hks::g_instancesList;
145 using OHOS::Security::Hks::g_certMgrSdkHandle;
146 using OHOS::Security::Hks::g_attestFunction;
147 using OHOS::Security::Hks::IHksService;
148 using OHOS::Security::Hks::PackAttestChain;
149 using OHOS::sptr;
150 
HksDcmCallback(DcmAnonymousResponse * response)151 void HksDcmCallback(DcmAnonymousResponse *response)
152 {
153     if (response == nullptr) {
154         HKS_LOG_E("dcm callback got null response");
155         HksReport(__func__, nullptr, nullptr, HUKS_ERR_CODE_EXTERNAL_ERROR);
156         return;
157     }
158     if (response->errCode != DCM_SUCCESS) {
159         HksReport(__func__, nullptr, nullptr, response->errCode);
160     }
161     HKS_LOG_I("dcm callback requestId %" LOG_PUBLIC PRIu64, response->requestId);
162     std::lock_guard<std::mutex> lockGuard(g_instancesList.GetMutex());
163     sptr<IHksService> hksProxy = g_instancesList.GetProxyWithoutLock(response->requestId);
164     HKS_IF_NULL_LOGE_RETURN_VOID(hksProxy, "GetProxyWithoutLock failed *requestId %" LOG_PUBLIC PRIu64,
165         response->requestId)
166     std::unique_ptr<uint8_t[]> replyData = nullptr;
167     uint32_t replySize = 0;
168     do {
169         HKS_IF_NOT_SUCC_LOGE_BREAK(response->errCode, "HksDcmCallback failed %" LOG_PUBLIC "d", response->errCode)
170         uint32_t packedSize = HKS_CERT_ROOT_SIZE + HKS_CERT_CA_SIZE + HKS_CERT_DEVICE_SIZE + HKS_CERT_APP_SIZE;
171         std::unique_ptr<uint8_t[]> packedCertChain(new (std::nothrow) uint8_t[packedSize]());
172         HKS_IF_NULL_LOGE_BREAK(packedCertChain, "new cert chain buffer failed")
173         HksBlob packedBlob { .size = packedSize, .data = packedCertChain.get() };
174         int ret = PackAttestChain(response->certChain, &packedBlob);
175         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "PackAttestChain failed %" LOG_PUBLIC "d", ret)
176         replyData = std::move(packedCertChain);
177         replySize = packedBlob.size;
178     } while (false);
179     hksProxy->SendAsyncReply(response->errCode, replyData, replySize);
180     g_instancesList.RemoveWithoutLock(response->requestId);
181 }
182 
HksDcmCallbackHandlerSetRequestIdWithoutLock(const uint8_t * remoteObject,uint64_t requestId)183 int32_t HksDcmCallbackHandlerSetRequestIdWithoutLock(const uint8_t *remoteObject, uint64_t requestId)
184 {
185     auto hksProxy = OHOS::iface_cast<IHksService>(
186         reinterpret_cast<OHOS::IRemoteObject *>(const_cast<uint8_t *>(remoteObject)));
187     HKS_IF_NULL_LOGE_RETURN(hksProxy, HKS_ERROR_NULL_POINTER, "iface_cast IHksService failed")
188     int ret = g_instancesList.SetNewInstanceWithoutLock(hksProxy, requestId);
189     HKS_IF_NOT_SUCC_LOGE(ret, "g_instancesList.SetNewInstance failed %" LOG_PUBLIC "d", ret)
190     return ret;
191 }
192 
HksDcmCallbackHandlerGetMapMutex(void)193 std::mutex &HksDcmCallbackHandlerGetMapMutex(void)
194 {
195     return g_instancesList.GetMutex();
196 }
197 
HksOpenDcmFunction(void)198 AttestFunction HksOpenDcmFunction(void)
199 {
200     HKS_IF_TRUE_RETURN(g_attestFunction != nullptr, g_attestFunction)
201 
202     g_certMgrSdkHandle = dlopen(DCM_SDK_SO, RTLD_NOW);
203     HKS_IF_NULL_LOGE_RETURN(g_certMgrSdkHandle, nullptr, "dlopen " DCM_SDK_SO " failed! %" LOG_PUBLIC "s", dlerror())
204     g_attestFunction = reinterpret_cast<AttestFunction>(dlsym(g_certMgrSdkHandle, "DcmAnonymousAttestKey"));
205     if (g_attestFunction == nullptr) {
206         HKS_LOG_E("dlsym failed %" LOG_PUBLIC "s", dlerror());
207         HksCloseDcmFunction();
208         return nullptr;
209     }
210     return g_attestFunction;
211 }
212 
HksCloseDcmFunction(void)213 void HksCloseDcmFunction(void)
214 {
215     if (g_certMgrSdkHandle == nullptr) {
216         g_attestFunction = nullptr;
217         return;
218     }
219     int ret = dlclose(g_certMgrSdkHandle);
220     HKS_IF_TRUE_LOGE(ret != 0, "dlclose g_certMgrSdkHandle failed %" LOG_PUBLIC "d %" LOG_PUBLIC "s", ret, dlerror())
221     g_certMgrSdkHandle = nullptr;
222     g_attestFunction = nullptr;
223 }
224 
225 #endif // HKS_UNTRUSTED_RUNNING_ENV
226