1 /*
2 * Copyright (c) 2023-2024 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 "local_sign_key.h"
17
18 #include <cstring>
19 #include <cstdio>
20 #include <climits>
21 #include <securec.h>
22 #include <string>
23
24 #include "byte_buffer.h"
25 #include "cert_utils.h"
26 #include "errcode.h"
27 #include "iservice_registry.h"
28 #include "log.h"
29 #include "system_ability_definition.h"
30
31 namespace OHOS {
32 namespace Security {
33 namespace CodeSign {
34 static const std::string ALIAS_NAME = "LOCAL_SIGN_KEY";
35 static const struct HksBlob LOCAL_SIGN_KEY_ALIAS = { ALIAS_NAME.size(), (uint8_t *)ALIAS_NAME.c_str()};
36 static const uint32_t SIGNATURE_COMMON_SIZE = 512;
37
38 static const std::string SUPPORTED_SIGN_ALGORITHM = "ECDSA256";
39 static constexpr uint32_t MAX_SIGN_SIZE = 65535;
40
41 static const struct HksParam ECC_KEY_PRARAM[] = {
42 { .tag = HKS_TAG_KEY_STORAGE_FLAG, .uint32Param = HKS_STORAGE_PERSISTENT },
43 { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_ECC },
44 { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_ECC_KEY_SIZE_256 },
45 { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_SIGN | HKS_KEY_PURPOSE_VERIFY },
46 { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_SHA256 },
47 { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }
48 };
49
50 static const struct HksParam ECC_SIGN_PRARAM[] = {
51 { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_ECC },
52 { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_ECC_KEY_SIZE_256 },
53 { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_SIGN },
54 { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_SHA256 },
55 { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }
56 };
57
58 static const struct HksParam ECC_EXIST_PRARAM[] = {
59 { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }
60 };
61
GetInstance()62 LocalSignKey &LocalSignKey::GetInstance()
63 {
64 static LocalSignKey singleLocalSignKey;
65 return singleLocalSignKey;
66 }
67
LocalSignKey()68 LocalSignKey::LocalSignKey()
69 {
70 }
71
~LocalSignKey()72 LocalSignKey::~LocalSignKey()
73 {
74 if (cert_ != nullptr) {
75 delete cert_;
76 cert_ = nullptr;
77 }
78 if (certChain_ != nullptr) {
79 FreeCertChain(&certChain_, certChain_->certsCount);
80 certChain_ = nullptr;
81 }
82 }
83
SetChallenge(const ByteBuffer & challenge)84 void LocalSignKey::SetChallenge(const ByteBuffer &challenge)
85 {
86 std::lock_guard<std::mutex> lock(lock_);
87 if (challenge_) {
88 challenge_.reset(nullptr);
89 }
90 uint32_t len = challenge.GetSize();
91 challenge_ = std::make_unique<ByteBuffer>(len);
92 if (challenge_ == nullptr) {
93 return;
94 }
95 if (memcpy_s(challenge_->GetBuffer(), len, challenge.GetBuffer(), len) != EOK) {
96 LOG_ERROR("set challenge failed.");
97 }
98 }
Connect()99 sptr<AppExecFwk::IBundleMgr> LocalSignKey::Connect()
100 {
101 sptr<ISystemAbilityManager> systemAbilityManager =
102 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
103 if (systemAbilityManager == nullptr) {
104 LOG_ERROR("failed to get system ability manager");
105 return nullptr;
106 }
107 sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
108 if (remoteObject == nullptr) {
109 LOG_ERROR("get remoteObject failed");
110 return nullptr;
111 }
112 return iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
113 }
114
UpdateKey()115 bool LocalSignKey::UpdateKey()
116 {
117 HUKSParamSet paramSet;
118 bool bRet = paramSet.Init(ECC_EXIST_PRARAM, sizeof(ECC_EXIST_PRARAM) / sizeof(HksParam));
119 if (!bRet) {
120 return false;
121 }
122 int32_t ret = HksKeyExist(&LOCAL_SIGN_KEY_ALIAS, paramSet.GetParamSet());
123 if (ret == HKS_ERROR_NOT_EXIST) {
124 LOG_INFO("The key does not exist, update the key, ret is %{public}d!", ret);
125 sptr<AppExecFwk::IBundleMgr> bundleMgr = Connect();
126 if (bundleMgr == nullptr) {
127 LOG_ERROR("Get bundleMgr failed");
128 return false;
129 }
130 int32_t result = bundleMgr->ResetAllAOT();
131 if (result != ERR_OK) {
132 LOG_ERROR("bundleMgr reset aot fail.");
133 return false;
134 }
135 if (!GenerateKey()) {
136 LOG_ERROR("GenerateKey fail.");
137 return false;
138 }
139 } else if (ret != HKS_SUCCESS) {
140 LOG_ERROR("HksKeyExist fail, ret is %{public}d!", ret);
141 return false;
142 }
143 return true;
144 }
145
InitKey()146 bool LocalSignKey::InitKey()
147 {
148 if (!UpdateKey()) {
149 return false;
150 }
151 certChain_ = QueryCertChain();
152 if (certChain_ == nullptr) {
153 return false;
154 }
155 return true;
156 }
157
GetSignCert()158 const ByteBuffer *LocalSignKey::GetSignCert()
159 {
160 if (cert_ != nullptr) {
161 return cert_;
162 }
163 const HksCertChain *certChain = GetCertChain();
164 if (certChain == nullptr) {
165 return nullptr;
166 }
167 cert_ = new (std::nothrow) ByteBuffer();
168 if (cert_ == nullptr) {
169 LOG_ERROR("Alloc memory for cert blob failed.");
170 return nullptr;
171 }
172 // get cert chain with 4 certs. the first is sign cert
173 if (!cert_->CopyFrom(certChain->certs[0].data, certChain->certs[0].size)) {
174 delete cert_;
175 cert_ = nullptr;
176 }
177 return cert_;
178 }
179
GetCertChain()180 const HksCertChain *LocalSignKey::GetCertChain()
181 {
182 if (certChain_ != nullptr) {
183 return certChain_;
184 }
185 certChain_ = QueryCertChain();
186 if (certChain_ == nullptr) {
187 LOG_ERROR("QueryCertChain failed.");
188 return nullptr;
189 }
190 return certChain_;
191 }
192
QueryCertChain()193 HksCertChain *LocalSignKey::QueryCertChain()
194 {
195 // init attest param
196 HUKSParamSet paramSet;
197 if (!GetAttestParamSet(paramSet)) {
198 return nullptr;
199 }
200
201 HksCertChain *certChain = nullptr;
202 // alloc memory for cert chain
203 if (!ConstructDataToCertChain(&certChain)) {
204 return nullptr;
205 }
206
207 // get cert chain by huks attest
208 int32_t ret = HksAttestKey(&LOCAL_SIGN_KEY_ALIAS, paramSet.GetParamSet(), certChain);
209 if (ret != HKS_SUCCESS) {
210 FreeCertChain(&certChain, certChain->certsCount);
211 LOG_ERROR("HksAttestKey fail, ret is %{public}d!", ret);
212 return nullptr;
213 }
214 return certChain;
215 }
216
GetFormattedCertChain(ByteBuffer & buffer)217 int32_t LocalSignKey::GetFormattedCertChain(ByteBuffer &buffer)
218 {
219 if (GetCertChain() == nullptr) {
220 return CS_ERR_HUKS_OBTAIN_CERT;
221 }
222 if (!FormattedCertChain(certChain_, buffer)) {
223 return CS_ERR_MEMORY;
224 }
225 return CS_SUCCESS;
226 }
227
GetKeyParamSet(HUKSParamSet & paramSet)228 bool LocalSignKey::GetKeyParamSet(HUKSParamSet ¶mSet)
229 {
230 if (algorithm_.compare(SUPPORTED_SIGN_ALGORITHM) == 0) {
231 return paramSet.Init(ECC_KEY_PRARAM, sizeof(ECC_KEY_PRARAM) / sizeof(HksParam));
232 }
233 return false;
234 }
235
GetAttestParamSet(HUKSParamSet & paramSet)236 bool LocalSignKey::GetAttestParamSet(HUKSParamSet ¶mSet)
237 {
238 std::lock_guard<std::mutex> lock(lock_);
239 // init challenge data by secure random function
240 if (challenge_ == nullptr) {
241 challenge_ = GetRandomChallenge();
242 if (challenge_ == nullptr) {
243 return false;
244 }
245 }
246
247 LOG_INFO("challenge in attest param.");
248 struct HksBlob challengeBlob = {
249 .size = challenge_->GetSize(),
250 .data = challenge_->GetBuffer()
251 };
252 struct HksParam attestationParams[] = {
253 { .tag = HKS_TAG_ATTESTATION_CHALLENGE, .blob = challengeBlob },
254 { .tag = HKS_TAG_ATTESTATION_ID_ALIAS, .blob = LOCAL_SIGN_KEY_ALIAS },
255 { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }
256 };
257 return paramSet.Init(attestationParams, sizeof(attestationParams) / sizeof(HksParam));
258 }
259
GenerateKey()260 bool LocalSignKey::GenerateKey()
261 {
262 HUKSParamSet paramSet;
263 if (!GetKeyParamSet(paramSet)) {
264 return false;
265 }
266 int32_t ret = HksGenerateKey(&LOCAL_SIGN_KEY_ALIAS, paramSet.GetParamSet(), nullptr);
267 if (ret != HKS_SUCCESS) {
268 LOG_ERROR("HksGenerateKey failed, ret is %{public}d!", ret);
269 return false;
270 }
271 return true;
272 }
273
GetSignParamSet(HUKSParamSet & paramSet)274 bool LocalSignKey::GetSignParamSet(HUKSParamSet ¶mSet)
275 {
276 if (algorithm_.compare(SUPPORTED_SIGN_ALGORITHM) == 0) {
277 return paramSet.Init(ECC_SIGN_PRARAM, sizeof(ECC_SIGN_PRARAM) / sizeof(HksParam));
278 }
279 return false;
280 }
281
Sign(const ByteBuffer & data,ByteBuffer & signature)282 bool LocalSignKey::Sign(const ByteBuffer &data, ByteBuffer &signature)
283 {
284 if (data.GetSize() > MAX_SIGN_SIZE) {
285 LOG_ERROR("Data to sign is too long");
286 return false;
287 }
288 struct HksBlob inData = {
289 .size = data.GetSize(),
290 .data = data.GetBuffer()
291 };
292
293 uint8_t tmpOut[SIGNATURE_COMMON_SIZE] = {0};
294 struct HksBlob outData = {
295 .size = SIGNATURE_COMMON_SIZE,
296 .data = tmpOut
297 };
298 if (!SignByHUKS(&inData, &outData)) {
299 return false;
300 }
301 if (!signature.CopyFrom(outData.data, outData.size)) {
302 return false;
303 }
304 return true;
305 }
306
SignByHUKS(const struct HksBlob * inData,struct HksBlob * outData)307 bool LocalSignKey::SignByHUKS(const struct HksBlob *inData, struct HksBlob *outData)
308 {
309 if (!UpdateKey()) {
310 return false;
311 }
312 HUKSParamSet paramSet;
313 if (!GetSignParamSet(paramSet)) {
314 return false;
315 }
316 // first stage: init, set key alias
317 uint8_t tmpHandle[sizeof(uint64_t)] = {0};
318 struct HksBlob handle = { sizeof(uint64_t), tmpHandle };
319 int32_t ret = HksInit(&LOCAL_SIGN_KEY_ALIAS, paramSet.GetParamSet(), &handle, nullptr);
320 if (ret != HKS_SUCCESS) {
321 LOG_ERROR("HksInit failed");
322 return false;
323 }
324 // second stage: update, send input data to HUKS
325 struct HksBlob tmpOutData = {
326 .size = MAX_SIGN_SIZE,
327 .data = nullptr
328 };
329 tmpOutData.data = static_cast<uint8_t *>(malloc(tmpOutData.size));
330 if (tmpOutData.data == nullptr) {
331 LOG_ERROR("Alloc memory for blob failed.");
332 return false;
333 }
334 ret = HksUpdate(&handle, paramSet.GetParamSet(), inData, &tmpOutData);
335 if (ret != HKS_SUCCESS) {
336 LOG_ERROR("HksUpdate Failed.");
337 free(tmpOutData.data);
338 return false;
339 }
340 // third stage: finish, get signature from HUKS
341 tmpOutData.size = 0;
342 ret = HksFinish(&handle, paramSet.GetParamSet(), &tmpOutData, outData);
343 free(tmpOutData.data);
344 if (ret != HKS_SUCCESS) {
345 LOG_ERROR("HksFinish Failed.");
346 return false;
347 }
348 return true;
349 }
350 }
351 }
352 }
353