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