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