1 /*
2 * Copyright (c) 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 #include "local_sign_key.h"
17
18 #include <cstring>
19 #include <cstdio>
20 #include <climits>
21 #include <openssl/rand.h>
22 #include <string>
23
24 #include "byte_buffer.h"
25 #include "cert_utils.h"
26 #include "errcode.h"
27 #include "log.h"
28 #include "securec.h"
29
30 namespace OHOS {
31 namespace Security {
32 namespace CodeSign {
33 static const std::string ALIAS_NAME = "LOCAL_SIGN_KEY";
34 static const struct HksBlob LOCAL_SIGN_KEY_ALIAS = { ALIAS_NAME.size(), (uint8_t *)ALIAS_NAME.c_str()};
35 static const uint32_t CHALLENGE_LEN = 32;
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 = 128;
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 };
48
49 static const struct HksParam ECC_SIGN_PRARAM[] = {
50 { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_ECC },
51 { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_ECC_KEY_SIZE_256 },
52 { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_SIGN },
53 { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_SHA256 }
54 };
55
GetInstance()56 LocalSignKey &LocalSignKey::GetInstance()
57 {
58 static LocalSignKey singleLocalSignKey;
59 return singleLocalSignKey;
60 }
61
LocalSignKey()62 LocalSignKey::LocalSignKey()
63 {
64 }
65
~LocalSignKey()66 LocalSignKey::~LocalSignKey()
67 {
68 if (cert_ != nullptr) {
69 delete cert_;
70 cert_ = nullptr;
71 }
72 if (certChain_ != nullptr) {
73 FreeCertChain(&certChain_, certChain_->certsCount);
74 certChain_ = nullptr;
75 }
76 }
77
InitKey()78 bool LocalSignKey::InitKey()
79 {
80 int32_t ret = HksKeyExist(&LOCAL_SIGN_KEY_ALIAS, nullptr);
81 if (ret == HKS_ERROR_NOT_EXIST) {
82 if (!GenerateKey()) {
83 return false;
84 }
85 } else if (ret != HKS_SUCCESS) {
86 LOG_ERROR(LABEL, "HksKeyExist fail, ret is %{public}d!", ret);
87 return false;
88 }
89 return true;
90 }
91
GetSignCert()92 const ByteBuffer *LocalSignKey::GetSignCert()
93 {
94 if (cert_ != nullptr) {
95 return cert_;
96 }
97 const HksCertChain *certChain = GetCertChain();
98 if (certChain == nullptr) {
99 return nullptr;
100 }
101 cert_ = new (std::nothrow) ByteBuffer();
102 if (cert_ == nullptr) {
103 LOG_ERROR(LABEL, "Alloc memory for cert blob failed.");
104 return nullptr;
105 }
106 // get cert chain with 4 certs. the first is sign cert
107 if (!cert_->CopyFrom(certChain->certs[0].data, certChain->certs[0].size)) {
108 delete cert_;
109 cert_ = nullptr;
110 }
111 return cert_;
112 }
113
GetCertChain()114 const HksCertChain *LocalSignKey::GetCertChain()
115 {
116 if (certChain_ != nullptr) {
117 return certChain_;
118 }
119 certChain_ = QueryCertChain();
120 if (certChain_ == nullptr) {
121 LOG_ERROR(LABEL, "QueryCertChain failed.");
122 return nullptr;
123 }
124 return certChain_;
125 }
QueryCertChain()126 HksCertChain *LocalSignKey::QueryCertChain()
127 {
128 // init attest param
129 HUKSParamSet paramSet;
130 if (!GetAttestParamSet(paramSet)) {
131 return nullptr;
132 }
133
134 HksCertChain *certChain = nullptr;
135 // alloc memory for cert chain
136 if (!ConstructDataToCertChain(&certChain)) {
137 return nullptr;
138 }
139
140 // get cert chain by huks attest
141 int32_t ret = HksAttestKey(&LOCAL_SIGN_KEY_ALIAS, paramSet.GetParamSet(), certChain);
142 if (ret != HKS_SUCCESS) {
143 LOG_ERROR(LABEL, "HksAttestKey fail, ret is %{public}d!", ret);
144 return nullptr;
145 }
146 return certChain;
147 }
148
GetKeyParamSet(HUKSParamSet & paramSet)149 bool LocalSignKey::GetKeyParamSet(HUKSParamSet ¶mSet)
150 {
151 if (algorithm_.compare(SUPPORTED_SIGN_ALGORITHM) == 0) {
152 return paramSet.Init(ECC_KEY_PRARAM, sizeof(ECC_KEY_PRARAM) / sizeof(HksParam));
153 }
154 return false;
155 }
156
GetAttestParamSet(HUKSParamSet & paramSet)157 bool LocalSignKey::GetAttestParamSet(HUKSParamSet ¶mSet)
158 {
159 // init challenge data by secure random function
160 if (challenge_ == nullptr) {
161 challenge_ = std::make_unique<uint8_t[]>(CHALLENGE_LEN);
162 if (challenge_ == nullptr) {
163 return false;
164 }
165 RAND_bytes(challenge_.get(), CHALLENGE_LEN);
166 }
167 struct HksBlob challengeBlob = {
168 .size = CHALLENGE_LEN,
169 .data = challenge_.get()
170 };
171 struct HksParam attestationParams[] = {
172 { .tag = HKS_TAG_ATTESTATION_CHALLENGE, .blob = challengeBlob },
173 { .tag = HKS_TAG_ATTESTATION_ID_ALIAS, .blob = LOCAL_SIGN_KEY_ALIAS },
174 };
175 return paramSet.Init(attestationParams, sizeof(attestationParams) / sizeof(HksParam));
176 }
177
GenerateKey()178 bool LocalSignKey::GenerateKey()
179 {
180 HUKSParamSet paramSet;
181 if (!GetKeyParamSet(paramSet)) {
182 return false;
183 }
184 int32_t ret = HksGenerateKey(&LOCAL_SIGN_KEY_ALIAS, paramSet.GetParamSet(), nullptr);
185 if (ret != HKS_SUCCESS) {
186 LOG_ERROR(LABEL, "HksGenerateKey failed, ret is %{public}d!", ret);
187 return false;
188 }
189 return true;
190 }
191
GetSignParamSet(HUKSParamSet & paramSet)192 bool LocalSignKey::GetSignParamSet(HUKSParamSet ¶mSet)
193 {
194 if (algorithm_.compare(SUPPORTED_SIGN_ALGORITHM) == 0) {
195 return paramSet.Init(ECC_SIGN_PRARAM, sizeof(ECC_SIGN_PRARAM) / sizeof(HksParam));
196 }
197 return false;
198 }
199
Sign(const ByteBuffer & data,ByteBuffer & signature)200 bool LocalSignKey::Sign(const ByteBuffer &data, ByteBuffer &signature)
201 {
202 if (data.GetSize() > MAX_SIGN_SIZE) {
203 LOG_ERROR(LABEL, "Data to sign is too long");
204 return false;
205 }
206 struct HksBlob inData = {
207 .size = data.GetSize(),
208 .data = data.GetBuffer()
209 };
210
211 uint8_t tmpOut[SIGNATURE_COMMON_SIZE] = {0};
212 struct HksBlob outData = {
213 .size = SIGNATURE_COMMON_SIZE,
214 .data = tmpOut
215 };
216 if (!SignByHUKS(&inData, &outData)) {
217 return false;
218 }
219 if (!signature.CopyFrom(outData.data, outData.size)) {
220 return false;
221 }
222 return true;
223 }
224
SignByHUKS(const struct HksBlob * inData,struct HksBlob * outData)225 bool LocalSignKey::SignByHUKS(const struct HksBlob *inData, struct HksBlob *outData)
226 {
227 HUKSParamSet paramSet;
228 if (!GetSignParamSet(paramSet)) {
229 return false;
230 }
231
232 // first stage: init, set key alias
233 uint8_t tmpHandle[sizeof(uint64_t)] = {0};
234 struct HksBlob handle = { sizeof(uint64_t), tmpHandle };
235 int32_t ret = HksInit(&LOCAL_SIGN_KEY_ALIAS, paramSet.GetParamSet(), &handle, nullptr);
236 if (ret != HKS_SUCCESS) {
237 LOG_ERROR(LABEL, "HksInit failed");
238 return false;
239 }
240
241 // second stage: update, send input data to HUKS
242 struct HksBlob tmpOutData = {
243 .size = MAX_SIGN_SIZE,
244 .data = nullptr
245 };
246 tmpOutData.data = static_cast<uint8_t *>(malloc(tmpOutData.size));
247 if (tmpOutData.data == nullptr) {
248 LOG_ERROR(LABEL, "Alloc memory for blob failed.");
249 return false;
250 }
251 ret = HksUpdate(&handle, paramSet.GetParamSet(), inData, &tmpOutData);
252 if (ret != HKS_SUCCESS) {
253 LOG_ERROR(LABEL, "HksUpdate Failed.");
254 free(tmpOutData.data);
255 return CS_ERR_PARAM_INVALID;
256 }
257
258 // third stage: finish, get signature from HUKS
259 tmpOutData.size = 0;
260 ret = HksFinish(&handle, paramSet.GetParamSet(), &tmpOutData, outData);
261 free(tmpOutData.data);
262 if (ret != HKS_SUCCESS) {
263 LOG_ERROR(LABEL, "HksFinish Failed.");
264 return false;
265 }
266 return true;
267 }
268 }
269 }
270 }
271