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 #ifdef HITLS_CRYPTO_ENTROPY
18
19 #include <stdint.h>
20 #include "securec.h"
21 #include "bsl_err_internal.h"
22 #include "crypt_errno.h"
23 #include "entropy_seed_pool.h"
24
25 #define SEEDPOOL_ES_MAX_SIZE 16
26 #define SEEDPOOL_ES_INIT_MINENTROPY 9
27 #define SEEDPOOL_ES_FULL_MINENTROPY 8
28 #define SEEDPOOL_ES_SYS_MINENTROPY 7
29
ENTROPY_SeedPoolNew(bool isCreateNullPool)30 ENTROPY_SeedPool *ENTROPY_SeedPoolNew(bool isCreateNullPool)
31 {
32 ENTROPY_SeedPool *poolCtx = BSL_SAL_Malloc(sizeof(ENTROPY_SeedPool));
33 if (poolCtx == NULL) {
34 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
35 return NULL;
36 }
37 (void)memset_s(poolCtx, sizeof(ENTROPY_SeedPool), 0, sizeof(ENTROPY_SeedPool));
38 poolCtx->esList = BSL_LIST_New(sizeof(ENTROPY_Source));
39 if (poolCtx->esList == NULL) {
40 BSL_SAL_Free(poolCtx);
41 BSL_ERR_PUSH_ERROR(BSL_LIST_MALLOC_FAIL);
42 return NULL;
43 }
44 poolCtx->minEntropy = SEEDPOOL_ES_INIT_MINENTROPY;
45 if (isCreateNullPool) {
46 return poolCtx;
47 }
48 CRYPT_EAL_EsPara para = {false, SEEDPOOL_ES_SYS_MINENTROPY, NULL, ENTROPY_SysEntropyGet};
49 int32_t ret = ENTROPY_SeedPoolAddEs(poolCtx, ¶);
50 if (ret != CRYPT_SUCCESS) {
51 ENTROPY_SeedPoolFree(poolCtx);
52 BSL_ERR_PUSH_ERROR(ret);
53 return NULL;
54 }
55 CRYPT_EAL_EsPara hwPara = {true, SEEDPOOL_ES_FULL_MINENTROPY, NULL, ENTROPY_HWEntropyGet};
56 ret = ENTROPY_SeedPoolAddEs(poolCtx, &hwPara);
57 if (ret != CRYPT_SUCCESS) {
58 ENTROPY_SeedPoolFree(poolCtx);
59 BSL_ERR_PUSH_ERROR(ret);
60 return NULL;
61 }
62 return poolCtx;
63 }
64
SeedPoolEsNew(const CRYPT_EAL_EsPara * para)65 static ENTROPY_Source *SeedPoolEsNew(const CRYPT_EAL_EsPara *para)
66 {
67 ENTROPY_Source *es = BSL_SAL_Malloc(sizeof(ENTROPY_Source));
68 if (es == NULL) {
69 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
70 return NULL;
71 }
72 es->isPhysical = para->isPhysical;
73 es->minEntropy = para->minEntropy;
74 es->ctx = para->entropyCtx;
75 es->entropyGet = (EntropyGet)(para->entropyGet);
76 return es;
77 }
78
ENTROPY_SeedPoolAddEs(ENTROPY_SeedPool * pool,const CRYPT_EAL_EsPara * para)79 int32_t ENTROPY_SeedPoolAddEs(ENTROPY_SeedPool *pool, const CRYPT_EAL_EsPara *para)
80 {
81 if (pool == NULL) {
82 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
83 return CRYPT_NULL_INPUT;
84 }
85
86 if (BSL_LIST_COUNT(pool->esList) >= SEEDPOOL_ES_MAX_SIZE) {
87 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_ES_LIST_FULL);
88 return CRYPT_SEED_POOL_ES_LIST_FULL;
89 }
90 ENTROPY_Source *es = SeedPoolEsNew(para);
91 if (es == NULL) {
92 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NEW_ERROR);
93 return CRYPT_SEED_POOL_NEW_ERROR;
94 }
95 /*
96 * The header insertion method is used to add an entropy source to ensure that the entropy source added by the
97 * invoker is used first when the entropy data is obtained.
98 */
99 int32_t ret = BSL_LIST_AddElement(pool->esList, es, BSL_LIST_POS_BEFORE);
100 if (ret != CRYPT_SUCCESS) {
101 BSL_SAL_Free(es);
102 BSL_ERR_PUSH_ERROR(ret);
103 return ret;
104 }
105 pool->minEntropy = (pool->minEntropy < para->minEntropy) ? pool->minEntropy : para->minEntropy;
106 pool->isContainFes = pool->isContainFes || (para->minEntropy == SEEDPOOL_ES_FULL_MINENTROPY);
107 pool->isContainPes = pool->isContainPes || para->isPhysical;
108 return CRYPT_SUCCESS;
109 }
110
ENTROPY_SeedPoolFree(ENTROPY_SeedPool * pool)111 void ENTROPY_SeedPoolFree(ENTROPY_SeedPool *pool)
112 {
113 if (pool == NULL) {
114 return;
115 }
116
117 if (pool->esList != NULL) {
118 BSL_LIST_FREE(pool->esList, BSL_SAL_Free);
119 }
120 BSL_SAL_Free(pool);
121 return;
122 }
123
GetMinLen(uint32_t needEntropy,uint32_t currEntropy,uint32_t minEntropy,uint32_t bufLen)124 static uint32_t GetMinLen(uint32_t needEntropy, uint32_t currEntropy, uint32_t minEntropy, uint32_t bufLen)
125 {
126 if (needEntropy == 0) {
127 return bufLen;
128 }
129 uint32_t len =
130 (uint32_t)(((uint64_t)(needEntropy - currEntropy) + (uint64_t)minEntropy - 1) / (uint64_t)minEntropy);
131 return bufLen >= len ? len : bufLen;
132 }
133
134
ENTROPY_SeedPoolCollect(ENTROPY_SeedPool * pool,bool isNpesUsed,uint32_t needEntropy,uint8_t * data,uint32_t * len)135 uint32_t ENTROPY_SeedPoolCollect(ENTROPY_SeedPool *pool, bool isNpesUsed, uint32_t needEntropy, uint8_t *data,
136 uint32_t *len)
137 {
138 if (data == NULL || len == NULL) {
139 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
140 return 0;
141 }
142 if (!ENTROPY_SeedPoolCheckState(pool, isNpesUsed)) {
143 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_STATE_ERROR);
144 return 0;
145 }
146 uint32_t bufLen = *len;
147 uint8_t *buf = data;
148 uint32_t curEntropy = 0;
149 for (ENTROPY_Source *es = BSL_LIST_GET_FIRST(pool->esList); es != NULL; es = BSL_LIST_GET_NEXT(pool->esList)) {
150 if (!isNpesUsed && !es->isPhysical) {
151 continue;
152 }
153 uint32_t tmpLen = GetMinLen(needEntropy, curEntropy, es->minEntropy, bufLen);
154 uint32_t readLen = es->entropyGet(es->ctx, buf, tmpLen);
155 if (readLen > 0) {
156 bufLen -= readLen;
157 buf += readLen;
158 curEntropy += es->minEntropy * readLen;
159 }
160 bool flag = (needEntropy == 0) ? (bufLen == 0) : (curEntropy >= needEntropy);
161 if (flag) {
162 break;
163 }
164 }
165 *len = buf - data;
166 return curEntropy;
167 }
168
ENTROPY_SeedPoolCheckState(ENTROPY_SeedPool * seedPool,bool isNpesUsed)169 bool ENTROPY_SeedPoolCheckState(ENTROPY_SeedPool *seedPool, bool isNpesUsed)
170 {
171 if (seedPool == NULL) {
172 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
173 return false;
174 }
175 if (BSL_LIST_COUNT(seedPool->esList) == 0) {
176 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NO_ENTROPY_SOURCE);
177 return false;
178 }
179 if (!isNpesUsed && !seedPool->isContainPes) {
180 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NO_ENTROPY_SOURCE);
181 return false;
182 }
183 return true;
184 }
185
ENTROPY_SeedPoolGetMinEntropy(ENTROPY_SeedPool * seedPool)186 uint32_t ENTROPY_SeedPoolGetMinEntropy(ENTROPY_SeedPool *seedPool)
187 {
188 if (seedPool == NULL) {
189 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
190 return 0;
191 }
192 return seedPool->minEntropy;
193 }
194 #endif