• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &paramSet)
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 &paramSet)
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 &paramSet)
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