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 &paramSet)
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 &paramSet)
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 &paramSet)
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