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 #include "hks_sa_interface.h"
23 
24 #include <errors.h>
25 #include <ipc_types.h>
26 #include <memory>
27 #include <mutex>
28 #include <securec.h>
29 
30 #include "hks_dcm_callback_handler.h"
31 #include "hks_log.h"
32 #include "huks_service_ipc_interface_code.h"
33 
34 namespace OHOS {
35 namespace Security {
36 namespace Hks {
37 
SendAsyncReply(uint32_t errCode,std::unique_ptr<uint8_t[]> & certChain,uint32_t sz)38 void HksStub::SendAsyncReply(uint32_t errCode, std::unique_ptr<uint8_t[]> &certChain, uint32_t sz)
39 {
40     std::unique_lock<std::mutex> lck(mMutex);
41     mErrCode = errCode;
42     mAsyncReply = std::move(certChain);
43     mSize = sz;
44     mCv.notify_all();
45 }
46 
ProcessAttestKeyAsyncReply(MessageParcel & data)47 int HksStub::ProcessAttestKeyAsyncReply(MessageParcel& data)
48 {
49     std::unique_ptr<uint8_t[]> certChain{};
50     uint32_t errCode = data.ReadUint32();
51     if (errCode != DCM_SUCCESS) {
52         HKS_LOG_E("ipc client read errCode %" LOG_PUBLIC "u", errCode);
53         SendAsyncReply(errCode, certChain, 0);
54         return ERR_INVALID_DATA;
55     }
56     uint32_t certChainLen = 0;
57     int err = ERR_INVALID_DATA;
58     do {
59         uint32_t sz = data.ReadUint32();
60         if (sz == 0 || sz > MAX_OUT_BLOB_SIZE) {
61             HKS_LOG_E("invalid sz %" LOG_PUBLIC "u", sz);
62             break;
63         }
64         const uint8_t *ptr = data.ReadBuffer(sz);
65         if (ptr == nullptr) {
66             HKS_LOG_E("ReadBuffer %" LOG_PUBLIC "u size ptr is nullptr", sz);
67             break;
68         }
69         std::unique_ptr<uint8_t[]> receivedPtr(new (std::nothrow) uint8_t[sz]());
70         if (receivedPtr == nullptr) {
71             HKS_LOG_E("new receivedPtr failed");
72             err = ERR_NO_MEMORY;
73             break;
74         }
75         errno_t err = memcpy_s(receivedPtr.get(), sz, ptr, sz);
76         if (err != EOK) {
77             HKS_LOG_E("memcpy_s receivedPtr failed");
78             break;
79         }
80         err = ERR_OK;
81         certChain = std::move(receivedPtr);
82         certChainLen = sz;
83     } while (false);
84     SendAsyncReply(errCode, certChain, certChainLen);
85     return err;
86 }
87 
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)88 int HksStub::OnRemoteRequest(uint32_t code,
89     MessageParcel& data, MessageParcel& reply, MessageOption& option)
90 {
91     if (data.ReadInterfaceToken() != GetDescriptor()) {
92         HKS_LOG_E("failed to check interface token! code %" LOG_PUBLIC "d", code);
93         return ERR_INVALID_DATA;
94     }
95     int result = ERR_NONE;
96 
97     switch (code) {
98         case HKS_MSG_ATTEST_KEY_ASYNC_REPLY:
99             result = ProcessAttestKeyAsyncReply(data);
100             break;
101         default:
102             HKS_LOG_E("unknown remote request code %" LOG_PUBLIC "u", code);
103             result = ERR_TRANSACTION_FAILED;
104             break;
105     }
106 
107     return result;
108 }
109 
WaitForAsyncReply(int timeout)110 std::tuple<uint32_t, std::unique_ptr<uint8_t[]>, uint32_t> HksStub::WaitForAsyncReply(int timeout)
111 {
112     std::unique_lock<std::mutex> lck(mMutex);
113     mAsyncReply = nullptr;
114     mSize = 0;
115     mErrCode = DCM_SUCCESS;
116     HKS_LOG_I("begin wait for async reply");
117     mCv.wait_for(lck, std::chrono::seconds(timeout));
118     return {mErrCode, std::move(mAsyncReply), mSize};
119 }
120 
121 BrokerDelegator<HksProxy> HksProxy::delegator_;
HksProxy(const sptr<IRemoteObject> & impl)122 HksProxy::HksProxy(const sptr<IRemoteObject> &impl)
123     : IRemoteProxy<IHksService>(impl)
124 {
125 }
126 
SendAsyncReply(uint32_t errCode,std::unique_ptr<uint8_t[]> & certChain,uint32_t sz)127 void HksProxy::SendAsyncReply(uint32_t errCode, std::unique_ptr<uint8_t[]> &certChain, uint32_t sz)
128 {
129     if (Remote() == nullptr) {
130         HKS_LOG_E("Remote() is nullptr! Would not SendRequest!");
131         return;
132     }
133     MessageParcel data, reply;
134     MessageOption option = MessageOption::TF_ASYNC;
135     bool writeResult = data.WriteInterfaceToken(GetDescriptor());
136     if (!writeResult) {
137         HKS_LOG_E("WriteInterfaceToken errCode %" LOG_PUBLIC "u failed %" LOG_PUBLIC "d", errCode, writeResult);
138         return;
139     }
140     writeResult = data.WriteUint32(errCode);
141     if (!writeResult) {
142         HKS_LOG_E("WriteUint32 errCode %" LOG_PUBLIC "u failed %" LOG_PUBLIC "d", errCode, writeResult);
143         return;
144     }
145     if (errCode != DCM_SUCCESS) {
146         HKS_LOG_E("dcm callback fail errCode %" LOG_PUBLIC "u", errCode);
147         int res = Remote()->SendRequest(HKS_MSG_ATTEST_KEY_ASYNC_REPLY, data, reply, option);
148         if (res != ERR_OK) {
149             HKS_LOG_E("send fail reply errCode failed %" LOG_PUBLIC "d", res);
150         }
151         return;
152     }
153     writeResult = data.WriteUint32(sz);
154     if (!writeResult) {
155         HKS_LOG_E("WriteUint32 sz %" LOG_PUBLIC "u failed %" LOG_PUBLIC "d", sz, writeResult);
156         return;
157     }
158     if (sz == 0 || certChain == nullptr) {
159         HKS_LOG_E("dcm reply success but empty certChain %" LOG_PUBLIC "u", sz);
160         int res = Remote()->SendRequest(HKS_MSG_ATTEST_KEY_ASYNC_REPLY, data, reply, option);
161         if (res != ERR_OK) {
162             HKS_LOG_E("Remote()->SendRequest HKS_MSG_ATTEST_KEY_ASYNC_REPLY failed %" LOG_PUBLIC "d", res);
163         }
164         return;
165     }
166     writeResult = data.WriteBuffer(certChain.get(), sz);
167     if (!writeResult) {
168         HKS_LOG_E("WriteBuffer size %" LOG_PUBLIC "u failed %" LOG_PUBLIC "d", sz, writeResult);
169         return;
170     }
171     int res = Remote()->SendRequest(HKS_MSG_ATTEST_KEY_ASYNC_REPLY, data, reply, option);
172     if (res != ERR_OK) {
173         HKS_LOG_E("Remote()->SendRequest HKS_MSG_ATTEST_KEY_ASYNC_REPLY failed %" LOG_PUBLIC "d", res);
174     }
175 }
176 
177 } // namespace Hks
178 } // namespace Security
179 } // namespace OHOS
180