/work/mbedtls-3.6.6/library/psa_crypto_random.c
Line | Count | Source |
1 | | /* |
2 | | * PSA crypto random generator. |
3 | | */ |
4 | | /* |
5 | | * Copyright The Mbed TLS Contributors |
6 | | * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
7 | | */ |
8 | | |
9 | | #include "common.h" |
10 | | |
11 | | #if defined(MBEDTLS_PSA_CRYPTO_C) && !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) |
12 | | |
13 | | #include "psa_crypto_core.h" |
14 | | #include "psa_crypto_random.h" |
15 | | #include "psa_crypto_random_impl.h" |
16 | | #include "threading_internal.h" |
17 | | |
18 | | #if defined(MBEDTLS_PSA_INJECT_ENTROPY) |
19 | | #include "entropy_poll.h" |
20 | | #endif |
21 | | |
22 | | #if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) |
23 | | /* For getpid(), for fork protection */ |
24 | | #include <unistd.h> |
25 | | #if defined(MBEDTLS_HAVE_TIME) |
26 | | #include <mbedtls/platform_time.h> |
27 | | #else |
28 | | /* For gettimeofday(), for fork protection without actual entropy */ |
29 | | #include <sys/time.h> |
30 | | #endif |
31 | | #endif |
32 | | |
33 | | void psa_random_internal_init(mbedtls_psa_random_context_t *rng) |
34 | 0 | { |
35 | | /* Set default configuration if |
36 | | * mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */ |
37 | 0 | if (rng->entropy_init == NULL) { |
38 | 0 | rng->entropy_init = mbedtls_entropy_init; |
39 | 0 | } |
40 | 0 | if (rng->entropy_free == NULL) { |
41 | 0 | rng->entropy_free = mbedtls_entropy_free; |
42 | 0 | } |
43 | |
|
44 | 0 | rng->entropy_init(&rng->entropy); |
45 | | #if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \ |
46 | | defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) |
47 | | /* The PSA entropy injection feature depends on using NV seed as an entropy |
48 | | * source. Add NV seed as an entropy source for PSA entropy injection. */ |
49 | | mbedtls_entropy_add_source(&rng->entropy, |
50 | | mbedtls_nv_seed_poll, NULL, |
51 | | MBEDTLS_ENTROPY_BLOCK_SIZE, |
52 | | MBEDTLS_ENTROPY_SOURCE_STRONG); |
53 | | #endif |
54 | |
|
55 | 0 | mbedtls_psa_drbg_init(&rng->drbg); |
56 | 0 | } |
57 | | |
58 | | void psa_random_internal_free(mbedtls_psa_random_context_t *rng) |
59 | 0 | { |
60 | 0 | mbedtls_psa_drbg_free(&rng->drbg); |
61 | 0 | rng->entropy_free(&rng->entropy); |
62 | 0 | } |
63 | | psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng) |
64 | 0 | { |
65 | 0 | const unsigned char drbg_seed[] = "PSA"; |
66 | 0 | int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy, |
67 | 0 | drbg_seed, sizeof(drbg_seed) - 1); |
68 | 0 | #if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) |
69 | 0 | rng->pid = getpid(); |
70 | 0 | #endif |
71 | 0 | return mbedtls_to_psa_error(ret); |
72 | 0 | } |
73 | | |
74 | | #if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) |
75 | | static psa_status_t psa_random_internal_reseed_child( |
76 | | mbedtls_psa_random_context_t *rng, |
77 | | intmax_t pid) |
78 | 0 | { |
79 | | /* Reseeding from actual entropy gives the child a unique RNG state |
80 | | * which the parent process cannot predict, and wipes the |
81 | | * parent's RNG state from the child. |
82 | | * |
83 | | * However, in some library configurations, there is no actual |
84 | | * entropy source, only a nonvolatile seed (MBEDTLS_ENTROPY_NV_SEED |
85 | | * enabled and no actual entropy source enabled). In such a |
86 | | * configuration, the reseed operation is deterministic and |
87 | | * always injects the same content, so with the DRBG reseed |
88 | | * process alone, for example, two child processes forked in |
89 | | * close sequence would end up with the same RNG state. |
90 | | |
91 | | * To avoid this, we use a personalization string that has a high |
92 | | * likelihood of being unique. This way, the child has a unique state. |
93 | | * The parent can predict the child's RNG state until the next time |
94 | | * it reseeds or generates some random output, but that's |
95 | | * unavoidable in the absence of actual entropy. |
96 | | */ |
97 | 0 | struct { |
98 | | /* Using the PID mostly guarantees that each child gets a |
99 | | * unique state. */ |
100 | | /* Use intmax_t, not pid_t, because some Unix-like platforms |
101 | | * don't define pid_t, or more likely nowadays they define |
102 | | * pid_t but only with certain platform macros which might not |
103 | | * be the exact ones we use. In practice, this only costs |
104 | | * a couple of instructions to pass and compare two words |
105 | | * rather than one. |
106 | | */ |
107 | 0 | intmax_t pid; |
108 | | /* In case an old child had died and its PID is reused for |
109 | | * a new child of the same process, also include the time. */ |
110 | 0 | #if defined(MBEDTLS_HAVE_TIME) |
111 | 0 | mbedtls_ms_time_t now; |
112 | | #else |
113 | | struct timeval now; |
114 | | #endif |
115 | 0 | } perso; |
116 | 0 | memset(&perso, 0, sizeof(perso)); |
117 | 0 | perso.pid = pid; |
118 | 0 | #if defined(MBEDTLS_HAVE_TIME) |
119 | 0 | perso.now = mbedtls_ms_time(); |
120 | | #else |
121 | | /* We don't have mbedtls_ms_time(), but the platform has getpid(). |
122 | | * Use gettimeofday(), which is a classic Unix function. Modern POSIX |
123 | | * has stopped requiring gettimeofday() (in favor of clock_gettime()), |
124 | | * but this is fallback code for restricted configurations, so it's |
125 | | * more likely to be used on embedded platforms that only have a subset |
126 | | * of Unix APIs and are more likely to have the classic gettimeofday(). */ |
127 | | if (gettimeofday(&perso.now, NULL) == -1) { |
128 | | return PSA_ERROR_INSUFFICIENT_ENTROPY; |
129 | | } |
130 | | #endif |
131 | 0 | int ret = mbedtls_psa_drbg_reseed(&rng->drbg, |
132 | 0 | (unsigned char *) &perso, sizeof(perso)); |
133 | 0 | return mbedtls_to_psa_error(ret); |
134 | 0 | } |
135 | | #endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */ |
136 | | |
137 | | psa_status_t psa_random_internal_generate( |
138 | | mbedtls_psa_random_context_t *rng, |
139 | | uint8_t *output, size_t output_size) |
140 | 0 | { |
141 | 0 | #if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) |
142 | 0 | intmax_t pid = getpid(); |
143 | 0 | if (pid != rng->pid) { |
144 | | /* This is a (grand...)child of the original process, but |
145 | | * we inherited the RNG state from our parent. We must reseed! */ |
146 | | #if defined(MBEDTLS_THREADING_C) |
147 | | mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex); |
148 | | #endif /* defined(MBEDTLS_THREADING_C) */ |
149 | 0 | psa_status_t status = psa_random_internal_reseed_child(rng, pid); |
150 | 0 | if (status == PSA_SUCCESS) { |
151 | 0 | rng->pid = pid; |
152 | 0 | } |
153 | | #if defined(MBEDTLS_THREADING_C) |
154 | | mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); |
155 | | #endif /* defined(MBEDTLS_THREADING_C) */ |
156 | 0 | if (status != PSA_SUCCESS) { |
157 | 0 | return status; |
158 | 0 | } |
159 | 0 | } |
160 | 0 | #endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */ |
161 | | |
162 | 0 | while (output_size > 0) { |
163 | 0 | size_t request_size = |
164 | 0 | (output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ? |
165 | 0 | MBEDTLS_PSA_RANDOM_MAX_REQUEST : |
166 | 0 | output_size); |
167 | 0 | #if defined(MBEDTLS_CTR_DRBG_C) |
168 | 0 | int ret = mbedtls_ctr_drbg_random(&rng->drbg, output, request_size); |
169 | | #elif defined(MBEDTLS_HMAC_DRBG_C) |
170 | | int ret = mbedtls_hmac_drbg_random(&rng->drbg, output, request_size); |
171 | | #endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */ |
172 | 0 | if (ret != 0) { |
173 | 0 | return mbedtls_to_psa_error(ret); |
174 | 0 | } |
175 | 0 | output_size -= request_size; |
176 | 0 | output += request_size; |
177 | 0 | } |
178 | 0 | return PSA_SUCCESS; |
179 | 0 | } |
180 | | |
181 | | #endif /* MBEDTLS_PSA_CRYPTO_C && !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ |