1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #if defined(HITLS_CRYPTO_ENTROPY) && defined(HITLS_CRYPTO_ENTROPY_SYS)
18
19 #include <stdint.h>
20 #include "securec.h"
21 #include "crypt_errno.h"
22 #include "bsl_list_internal.h"
23 #include "bsl_err_internal.h"
24 #include "es_noise_source.h"
25
26 #define ES_NS_MAX_SIZE 16
27 #define ES_MIN_ENTROPY_MAX 8
28 /* Noise source non-blocking reading. Set the maximum reading time to 10s. */
29 #define ES_MAX_TIMEOUT_MAX 10
30
31 static int32_t NsRead(ES_NoiseSource *ns, uint8_t *buf, uint32_t bufLen);
32 /*
33 * GM/T 0105-2021 Section 5.5
34 * The Power-Up Health Test requires a continuous health test of at least 1024 consecutive samples.
35 */
36 #define ENTROPY_START_UP_TEST_SIZE 1024
ES_NoiseSourceStartupTest(ES_NoiseSource * ns)37 int32_t ES_NoiseSourceStartupTest(ES_NoiseSource *ns)
38 {
39 uint8_t buf[ENTROPY_START_UP_TEST_SIZE] = {0};
40 return NsRead(ns, buf, ENTROPY_START_UP_TEST_SIZE);
41 }
42
ES_NsCreate(const char * name,bool autoTest,uint32_t minEntropy,const CRYPT_EAL_NsMethod * method,const CRYPT_EAL_NsTestPara * para)43 static ES_NoiseSource *ES_NsCreate(const char *name, bool autoTest, uint32_t minEntropy,
44 const CRYPT_EAL_NsMethod *method, const CRYPT_EAL_NsTestPara *para)
45 {
46 ES_NoiseSource *ctx = BSL_SAL_Malloc(sizeof(ES_NoiseSource));
47 if (ctx == NULL) {
48 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
49 return NULL;
50 }
51 (void)memset_s(ctx, sizeof(ES_NoiseSource), 0, sizeof(ES_NoiseSource));
52 uint32_t len = strlen(name) + 1;
53 ctx->name = BSL_SAL_Malloc(len);
54 if (ctx->name == NULL) {
55 BSL_SAL_FREE(ctx);
56 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
57 return NULL;
58 }
59 (void)strncpy_s(ctx->name, len, name, len - 1);
60 // Initializing
61 ctx->autoTest = autoTest;
62 ctx->para = method->para;
63 ctx->init = method->init;
64 ctx->read = method->read;
65 ctx->deinit = method->deinit;
66 ctx->minEntropy = minEntropy;
67 ctx->state.rctCutoff = para->rctCutoff;
68 ctx->state.aptCutOff = para->aptCutoff;
69 ctx->state.aptWindowSize = para->aptWinSize;
70 return ctx;
71 }
72
ES_NsFree(ES_NoiseSource * ns)73 static void ES_NsFree(ES_NoiseSource *ns)
74 {
75 if (ns->usrdata != NULL && ns->deinit != NULL) {
76 ns->deinit(ns->usrdata);
77 }
78 BSL_SAL_FREE(ns->name);
79 BSL_SAL_Free(ns);
80 return;
81 }
82
ES_NsListCreat(void)83 BslList *ES_NsListCreat(void)
84 {
85 BslList *ns = BSL_LIST_New(sizeof(BslListNode));
86 if (ns == NULL) {
87 BSL_ERR_PUSH_ERROR(BSL_LIST_MALLOC_FAIL);
88 return NULL;
89 }
90 ES_NoiseSource *jitterCtx = ES_CpuJitterGetCtx();
91 if (jitterCtx == NULL) {
92 goto ERR;
93 }
94 int32_t ret = BSL_LIST_AddElement(ns, jitterCtx, BSL_LIST_POS_AFTER);
95 if (ret != CRYPT_SUCCESS) {
96 ES_NsFree(jitterCtx);
97 goto ERR;
98 }
99 ES_NoiseSource *stampCtx = ES_TimeStampGetCtx();
100 if (stampCtx == NULL) {
101 goto ERR;
102 }
103 ret = BSL_LIST_AddElement(ns, stampCtx, BSL_LIST_POS_AFTER);
104 if (ret != CRYPT_SUCCESS) {
105 ES_NsFree(stampCtx);
106 goto ERR;
107 }
108 return ns;
109 ERR:
110 BSL_LIST_FREE(ns, (BSL_LIST_PFUNC_FREE)ES_NsFree);
111 return NULL;
112 }
113
ES_NsListInit(BslList * nsList,bool enableTest)114 int32_t ES_NsListInit(BslList *nsList, bool enableTest)
115 {
116 if (BSL_LIST_COUNT(nsList) == 0) {
117 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_NO_NS);
118 return CRYPT_ENTROPY_ES_NO_NS;
119 }
120 bool nsUsed = false;
121 ES_NoiseSource *ns = NULL;
122 for (ns = BSL_LIST_GET_FIRST(nsList); ns != NULL; ns = BSL_LIST_GET_NEXT(nsList)) {
123 /*
124 * If the health check is automatically performed when the noise source is generated, no additional health
125 * check is required. Otherwise, determine whether to perform the health check based on the configuration.
126 */
127 ns->enableTest = (ns->autoTest) ? false : enableTest;
128 if (ns->init != NULL) {
129 ns->usrdata = ns->init(ns->para);
130 if (ns->usrdata == NULL) {
131 ns->isEnable = false;
132 continue;
133 }
134 }
135 ns->isInit = true;
136 if (enableTest) {
137 int32_t ret = ES_NoiseSourceStartupTest(ns);
138 if (ret != CRYPT_SUCCESS) {
139 ns->isEnable = false;
140 BSL_ERR_PUSH_ERROR(ret);
141 continue;
142 }
143 }
144 ns->isEnable = true;
145 nsUsed = true;
146 }
147 if (!nsUsed) {
148 ES_NsListDeinit(nsList);
149 return CRYPT_ENTROPY_ES_NO_NS;
150 }
151 return CRYPT_SUCCESS;
152 }
153
ES_NsListDeinit(BslList * nsList)154 void ES_NsListDeinit(BslList *nsList)
155 {
156 if (BSL_LIST_COUNT(nsList) == 0) {
157 return;
158 }
159 ES_NoiseSource *ns = NULL;
160 for (ns = BSL_LIST_GET_FIRST(nsList); ns != NULL; ns = BSL_LIST_GET_NEXT(nsList)) {
161 ns->isInit = false;
162 ns->isEnable = false;
163 if (ns->deinit != NULL) {
164 ns->deinit(ns->usrdata);
165 ns->usrdata = NULL;
166 }
167 }
168 return;
169 }
170
ES_NsListFree(BslList * nsList)171 void ES_NsListFree(BslList *nsList)
172 {
173 BSL_LIST_FREE(nsList, (BSL_LIST_PFUNC_FREE)ES_NsFree);
174 }
175
ES_NsComp(const ES_NoiseSource * ns,const char * name)176 static int32_t ES_NsComp(const ES_NoiseSource *ns, const char *name)
177 {
178 return strcmp(ns->name, name);
179 }
180
ES_NsAdd(BslList * nsList,const char * name,bool autoTest,uint32_t minEntropy,const CRYPT_EAL_NsMethod * method,const CRYPT_EAL_NsTestPara * para)181 int32_t ES_NsAdd(BslList *nsList, const char *name, bool autoTest, uint32_t minEntropy,
182 const CRYPT_EAL_NsMethod *method, const CRYPT_EAL_NsTestPara *para)
183 {
184 if (name == NULL || minEntropy > ES_MIN_ENTROPY_MAX) {
185 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
186 return CRYPT_NULL_INPUT;
187 }
188 if (method->read == NULL || (method->init == NULL && method->deinit != NULL) ||
189 (method->init != NULL && method->deinit == NULL)) {
190 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
191 return CRYPT_NULL_INPUT;
192 }
193 if (BSL_LIST_COUNT(nsList) >= ES_NS_MAX_SIZE) {
194 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_NS_FULL);
195 return CRYPT_ENTROPY_ES_NS_FULL;
196 }
197 if (BSL_LIST_SearchEx(nsList, name, (BSL_LIST_PFUNC_CMP)ES_NsComp) != NULL) {
198 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_DUP_NS);
199 return CRYPT_ENTROPY_ES_DUP_NS;
200 }
201 ES_NoiseSource *ns = ES_NsCreate(name, autoTest, minEntropy, method, para);
202 if (ns == NULL) {
203 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_CREATE_ERROR);
204 return CRYPT_ENTROPY_ES_CREATE_ERROR;
205 }
206 int32_t ret = BSL_LIST_AddElement(nsList, ns, BSL_LIST_POS_AFTER);
207 if (ret != CRYPT_SUCCESS) {
208 ES_NsFree(ns);
209 }
210 return ret;
211 }
212
ES_NsRemove(BslList * nsList,const char * name)213 int32_t ES_NsRemove(BslList *nsList, const char *name)
214 {
215 BslListNode *tmpNode = NULL;
216 for (BslListNode *node = BSL_LIST_FirstNode(nsList); node != NULL;) {
217 tmpNode = node;
218 ES_NoiseSource *ns = BSL_LIST_GetData(tmpNode);
219 if (ns == NULL) {
220 continue;
221 }
222 if (strcmp(ns->name, name) == 0) {
223 BSL_LIST_DeleteNode(nsList, (const BslListNode *)tmpNode, (BSL_LIST_PFUNC_FREE)ES_NsFree);
224 return CRYPT_SUCCESS;
225 }
226 node = BSL_LIST_GetNextNode(nsList, tmpNode);
227 }
228 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_NS_NOT_FOUND);
229 return CRYPT_ENTROPY_ES_NS_NOT_FOUND;
230 }
231
NsRead(ES_NoiseSource * ns,uint8_t * buf,uint32_t bufLen)232 static int32_t NsRead(ES_NoiseSource *ns, uint8_t *buf, uint32_t bufLen)
233 {
234 int32_t ret = ns->read(ns->usrdata, ES_MAX_TIMEOUT_MAX, buf, bufLen);
235 if (ret != CRYPT_SUCCESS) {
236 BSL_ERR_PUSH_ERROR(ret);
237 return ret;
238 }
239 if (!ns->enableTest) {
240 return CRYPT_SUCCESS;
241 }
242 for (uint32_t iter = 0; iter < bufLen; iter++) {
243 ret = ES_HealthTestRct(&(ns->state), buf[iter]);
244 if (ret != CRYPT_SUCCESS) {
245 return ret;
246 }
247 ret = ES_HealthTestApt(&(ns->state), buf[iter]);
248 if (ret != CRYPT_SUCCESS) {
249 return ret;
250 }
251 }
252 return ret;
253 }
254
ES_NsRead(ES_NoiseSource * ns,uint8_t * buf,uint32_t bufLen)255 int32_t ES_NsRead(ES_NoiseSource *ns, uint8_t *buf, uint32_t bufLen)
256 {
257 if (ns->isInit != true || ns->isEnable != true) {
258 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_NS_NOT_AVA);
259 return CRYPT_ENTROPY_ES_NS_NOT_AVA;
260 }
261
262 return NsRead(ns, buf, bufLen);
263 }
264
ES_NsListGetMinEntropy(BslList * nsList)265 uint32_t ES_NsListGetMinEntropy(BslList *nsList)
266 {
267 if (BSL_LIST_COUNT(nsList) == 0) {
268 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_NO_NS);
269 return 0;
270 }
271 uint32_t minEntropy = 8;
272 ES_NoiseSource *ns = NULL;
273 for (ns = BSL_LIST_GET_FIRST(nsList); ns != NULL; ns = BSL_LIST_GET_NEXT(nsList)) {
274 minEntropy = (ns->minEntropy < minEntropy) ? ns->minEntropy : minEntropy;
275 }
276 return minEntropy;
277 }
278 #endif