1 /*
2 * Copyright (c) 2021-2022 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 #include "hks_request.h"
17
18 #include <iservice_registry.h>
19 #include <message_option.h>
20 #include <securec.h>
21
22 #include "hks_base_check.h" // for HksAttestIsAnonymous
23 #include "hks_log.h"
24 #include "hks_param.h"
25 #include "hks_sa_interface.h"
26 #include "hks_template.h"
27 #include "hks_type.h"
28 #include "huks_service_ipc_interface_code.h"
29
30 using namespace OHOS;
31
32 namespace {
33 constexpr int SA_ID_KEYSTORE_SERVICE = 3510;
34 const std::u16string SA_KEYSTORE_SERVICE_DESCRIPTOR = u"ohos.security.hks.service";
35 }
36
GetHksProxy()37 static sptr<IRemoteObject> GetHksProxy()
38 {
39 auto registry = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
40 HKS_IF_NULL_LOGE_RETURN(registry, nullptr, "GetHksProxy registry is null")
41
42 sptr<IRemoteObject> hksProxy = registry->GetSystemAbility(SA_ID_KEYSTORE_SERVICE);
43 HKS_IF_NULL_LOGE_RETURN(hksProxy, nullptr,
44 "GetHksProxy GetSystemAbility %" LOG_PUBLIC "d is null", SA_ID_KEYSTORE_SERVICE)
45
46 return hksProxy;
47 }
48
HksReadRequestReply(MessageParcel & reply,struct HksBlob * outBlob)49 static int32_t HksReadRequestReply(MessageParcel &reply, struct HksBlob *outBlob)
50 {
51 int32_t ret = reply.ReadInt32();
52
53 uint32_t outLen = reply.ReadUint32();
54 if (ret == HKS_SUCCESS && outLen == 0) {
55 if (outBlob != nullptr) {
56 outBlob->size = 0;
57 }
58 }
59 if (outLen != 0) {
60 HKS_IF_NOT_SUCC_RETURN(CheckBlob(outBlob), ret == HKS_SUCCESS ? HKS_ERROR_INVALID_ARGUMENT : ret)
61 const uint8_t *outData = reply.ReadBuffer(outLen);
62 HKS_IF_NULL_RETURN(outData, ret == HKS_SUCCESS ? HKS_ERROR_IPC_MSG_FAIL : ret)
63
64 if (ret == HKS_SUCCESS) {
65 if (outBlob->size < outLen) {
66 HKS_LOG_E("outBlob size[%" LOG_PUBLIC "u] smaller than outLen[%" LOG_PUBLIC "u]",
67 outBlob->size, outLen);
68 return (ret == HKS_SUCCESS) ? HKS_ERROR_BUFFER_TOO_SMALL : ret;
69 }
70 HKS_IF_NOT_EOK_LOGE_RETURN(memcpy_s(outBlob->data, outBlob->size, outData, outLen),
71 ret == HKS_SUCCESS ? HKS_ERROR_INSUFFICIENT_MEMORY : ret, "copy outBlob data failed!")
72 outBlob->size = outLen;
73 }
74 }
75 #ifdef L2_STANDARD
76 uint32_t errMsgLen = 0;
77 if (reply.ReadUint32(errMsgLen) && errMsgLen != 0 && errMsgLen < MAX_ERROR_MESSAGE_LEN) {
78 HKS_LOG_I("reply get errMsgLen = %u", errMsgLen);
79 const uint8_t *errMsg = reply.ReadUnpadBuffer(errMsgLen);
80 HKS_IF_NULL_LOGE_RETURN(errMsg, ret, "[ipc error] read errorMsg")
81 HksAppendThreadErrMsg(errMsg, errMsgLen);
82 }
83 PrintErrorMsg();
84 #endif
85
86 return ret;
87 }
88
HksSendAnonAttestRequestAndWaitAsyncReply(MessageParcel & data,const struct HksParamSet * paramSet,sptr<IRemoteObject> hksProxy,sptr<Security::Hks::HksStub> hksCallback,struct HksBlob * outBlob)89 static int32_t HksSendAnonAttestRequestAndWaitAsyncReply(MessageParcel &data, const struct HksParamSet *paramSet,
90 sptr<IRemoteObject> hksProxy, sptr<Security::Hks::HksStub> hksCallback, struct HksBlob *outBlob)
91 {
92 HKS_IF_NOT_SUCC_LOGE_RETURN(CheckBlob(outBlob), HKS_ERROR_INVALID_ARGUMENT, "invalid outBlob");
93 MessageParcel reply{};
94 // We send the request in sync mode, and we send a stub instance in the request.
95 // We wait for the instance callback later.
96 MessageOption option = MessageOption::TF_SYNC;
97 int error = hksProxy->SendRequest(HKS_MSG_ATTEST_KEY_ASYNC_REPLY, data, reply, option);
98 HKS_IF_NOT_SUCC_LOGE_RETURN(error, HKS_ERROR_IPC_MSG_FAIL, "hksProxy->SendRequest failed %" LOG_PUBLIC "d", error);
99
100 int ret = HksReadRequestReply(reply, outBlob);
101 HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret,
102 "HksSendAnonAttestRequestAndWaitAsyncReply HksReadRequestReply failed %" LOG_PUBLIC "d", ret)
103
104 #ifndef HKS_UNTRUSTED_RUNNING_ENV
105 int timeout = 10; // seconds
106 auto [errCode, packedCerts, packedSize] = hksCallback->WaitForAsyncReply(timeout);
107 if (errCode != HKS_SUCCESS || packedCerts == nullptr || packedSize == 0) {
108 HKS_LOG_E("errCode %" LOG_PUBLIC "u fail or packedCerts empty or size %" LOG_PUBLIC "u 0", errCode, packedSize);
109 return HUKS_ERR_CODE_EXTERNAL_ERROR;
110 }
111
112 if (outBlob->size < packedSize) {
113 HKS_LOG_E("out blob empty or too small %" LOG_PUBLIC "u %" LOG_PUBLIC "u", outBlob->size, packedSize);
114 return HKS_ERROR_INVALID_ARGUMENT;
115 }
116
117 HKS_IF_NOT_EOK_LOGE_RETURN(memcpy_s(outBlob->data, outBlob->size, packedCerts.get(), packedSize),
118 HKS_ERROR_INVALID_ARGUMENT, "memcpy_s failed destMax %" LOG_PUBLIC "u count %" LOG_PUBLIC "u",
119 outBlob->size, packedSize)
120 outBlob->size = packedSize;
121 return HKS_SUCCESS;
122 #else
123 (void)(paramSet);
124 (void)(hksCallback);
125 return ret;
126 #endif
127 }
128
HksSendRequest(enum HksIpcInterfaceCode type,const struct HksBlob * inBlob,struct HksBlob * outBlob,const struct HksParamSet * paramSet)129 int32_t HksSendRequest(enum HksIpcInterfaceCode type, const struct HksBlob *inBlob,
130 struct HksBlob *outBlob, const struct HksParamSet *paramSet)
131 {
132 #ifdef L2_STANDARD
133 HksClearThreadErrorMsg();
134 #endif
135 enum HksSendType sendType = HKS_SEND_TYPE_SYNC;
136 struct HksParam *sendTypeParam = nullptr;
137 int32_t ret = HksGetParam(paramSet, HKS_TAG_IS_ASYNCHRONIZED, &sendTypeParam);
138 if (ret == HKS_SUCCESS) {
139 sendType = static_cast<enum HksSendType>(sendTypeParam->uint32Param);
140 }
141
142 MessageParcel data;
143 MessageParcel reply;
144 MessageOption option;
145 if (sendType == HKS_SEND_TYPE_SYNC) {
146 option = MessageOption::TF_SYNC;
147 } else {
148 option = MessageOption::TF_ASYNC;
149 }
150 HKS_IF_NOT_TRUE_RETURN(data.WriteInterfaceToken(SA_KEYSTORE_SERVICE_DESCRIPTOR), HKS_ERROR_BAD_STATE);
151
152 if (outBlob == nullptr) {
153 HKS_IF_NOT_TRUE_RETURN(data.WriteUint32(0), HKS_ERROR_BAD_STATE);
154 } else {
155 HKS_IF_NOT_TRUE_RETURN(data.WriteUint32(outBlob->size), HKS_ERROR_BAD_STATE);
156 }
157 HKS_IF_NOT_TRUE_RETURN(data.WriteUint32(inBlob->size), HKS_ERROR_BAD_STATE);
158 HKS_IF_NOT_TRUE_RETURN(data.WriteBuffer(inBlob->data, static_cast<size_t>(inBlob->size)), HKS_ERROR_BAD_STATE);
159
160 sptr<IRemoteObject> hksProxy = GetHksProxy();
161 HKS_IF_NULL_LOGE_RETURN(hksProxy, HKS_ERROR_BAD_STATE, "GetHksProxy registry is null")
162
163 if (type == HKS_MSG_ATTEST_KEY_ASYNC_REPLY) {
164 sptr<Security::Hks::HksStub> hksCallback = new (std::nothrow) Security::Hks::HksStub();
165 HKS_IF_NULL_LOGE_RETURN(hksCallback, HKS_ERROR_INSUFFICIENT_MEMORY, "new HksStub failed")
166 // We write a HksStub instance if type == HKS_MSG_ATTEST_KEY_ASYNC_REPLY,
167 // then we can read it in the server side if type == HKS_MSG_ATTEST_KEY_ASYNC_REPLY.
168 bool result = data.WriteRemoteObject(hksCallback);
169 HKS_IF_NOT_TRUE_LOGE_RETURN(result, HKS_ERROR_IPC_MSG_FAIL,
170 "WriteRemoteObject hksCallback failed %" LOG_PUBLIC "d", result)
171 return HksSendAnonAttestRequestAndWaitAsyncReply(data, paramSet, hksProxy, hksCallback, outBlob);
172 // If the mode is non-anonymous attest, we write a HksStub instance here, then go back and process as normal.
173 }
174
175 int error = hksProxy->SendRequest(type, data, reply, option);
176 HKS_IF_TRUE_LOGE_RETURN(error != 0, HKS_ERROR_IPC_MSG_FAIL, "hksProxy->SendRequest failed %" LOG_PUBLIC "d", error)
177
178 return HksReadRequestReply(reply, outBlob);
179 }
180