]> git.saurik.com Git - apple/xnu.git/blame - osfmk/prng/entropy.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / prng / entropy.c
CommitLineData
1c79356b 1/*
f427ee49 2 * Copyright (c) 2019 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5ba3f43e 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
5ba3f43e 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
5ba3f43e 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
5ba3f43e 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b 28
2a1bd2d3
A
29#include <libkern/crypto/sha2.h>
30#include <libkern/crypto/crypto_internal.h>
31#include <os/atomic_private.h>
32#include <kern/assert.h>
33#include <kern/percpu.h>
f427ee49 34#include <kern/zalloc.h>
2a1bd2d3
A
35#include <kern/lock_group.h>
36#include <kern/locks.h>
37#include <kern/misc_protos.h>
f427ee49
A
38#include <pexpert/pexpert.h>
39#include <prng/entropy.h>
f427ee49 40#include <machine/machine_routines.h>
2a1bd2d3
A
41#include <libkern/section_keywords.h>
42#include <sys/cdefs.h>
cb323159 43
2a1bd2d3
A
44// The number of samples we can hold in an entropy buffer.
45#define ENTROPY_MAX_SAMPLE_COUNT (2048)
cb323159 46
2a1bd2d3
A
47// The state for a per-CPU entropy buffer.
48typedef struct entropy_cpu_data {
49 // A buffer to hold entropy samples.
50 entropy_sample_t samples[ENTROPY_MAX_SAMPLE_COUNT];
51
52 // A count of samples resident in the buffer. It also functions as
53 // an index to the buffer. All entries at indices less than the
54 // sample count are considered valid for consumption by the
55 // reader. The reader resets this to zero after consuming the
56 // available entropy.
57 uint32_t _Atomic sample_count;
58} entropy_cpu_data_t;
59
60// This structure holds the state for an instance of a FIPS continuous
61// health test. In practice, we do not expect these tests to fail.
62typedef struct entropy_health_test {
63 // The initial sample observed in this test instance. Tests look
64 // for some repetition of the sample, either consecutively or
65 // within a window.
66 entropy_sample_t init_observation;
67
68 // The count of times the initial observation has recurred within
69 // the span of the current test.
70 uint64_t observation_count;
71
72 // The statistics are only relevant for telemetry and parameter
73 // tuning. They do not drive any actual logic in the module.
74 entropy_health_stats_t *stats;
75} entropy_health_test_t;
76
77typedef enum health_test_result {
78 health_test_failure,
79 health_test_success
80} health_test_result_t;
81
82// Along with various counters and the buffer itself, this includes
83// the state for two FIPS continuous health tests.
84typedef struct entropy_data {
85 // State for a SHA256 computation. This is used to accumulate
86 // entropy samples from across all CPUs. It is finalized when
87 // entropy is provided to the consumer of this module.
88 SHA256_CTX sha256_ctx;
89
90 // Since the corecrypto kext is not loaded when this module is
91 // initialized, we cannot initialize the SHA256 state at that
92 // time. Instead, we initialize it lazily during entropy
93 // consumption. This flag tracks whether initialization is
94 // complete.
95 bool sha256_ctx_init;
96
97 // A total count of entropy samples that have passed through this
98 // structure. It is incremented as new samples are accumulated
99 // from the various per-CPU structures. The "current" count of
100 // samples is the difference between this field and the "read"
101 // sample count below (which see).
102 uint64_t total_sample_count;
103
104 // Initially zero, this flag is reset to the current sample count
105 // if and when we fail a health test. We consider the startup
106 // health tests to be complete when the difference between the
107 // total sample count and this field is at least 1024. In other
108 // words, we must accumulate 1024 good samples to demonstrate
109 // viability. We refuse to provide any entropy before that
110 // threshold is reached.
111 uint64_t startup_sample_count;
112
113 // The count of samples from the last time we provided entropy to
114 // the kernel RNG. We use this to compute how many new samples we
115 // have to contribute. This value is also reset to the current
116 // sample count in case of health test failure.
117 uint64_t read_sample_count;
118
119 // The lock group for this structure; see below.
120 lck_grp_t lock_group;
121
122 // This structure accumulates entropy samples from across all CPUs
123 // for a single point of consumption protected by a mutex.
124 lck_mtx_t mutex;
125
126 // State for the Repetition Count Test.
127 entropy_health_test_t repetition_count_test;
128
129 // State for the Adaptive Proportion Test.
130 entropy_health_test_t adaptive_proportion_test;
131} entropy_data_t;
132
133static entropy_cpu_data_t PERCPU_DATA(entropy_cpu_data);
134
135int entropy_health_startup_done;
136entropy_health_stats_t entropy_health_rct_stats;
137entropy_health_stats_t entropy_health_apt_stats;
138
139static entropy_data_t entropy_data = {
140 .repetition_count_test = {
141 .init_observation = -1,
142 .stats = &entropy_health_rct_stats,
143 },
144 .adaptive_proportion_test = {
145 .init_observation = -1,
146 .stats = &entropy_health_apt_stats,
147 },
f427ee49 148};
1c79356b 149
2a1bd2d3
A
150__security_const_late entropy_sample_t *entropy_analysis_buffer;
151__security_const_late uint32_t entropy_analysis_buffer_size;
152static __security_const_late uint32_t entropy_analysis_max_sample_count;
153static uint32_t entropy_analysis_sample_count;
154
155__startup_func
156static void
157entropy_analysis_init(uint32_t sample_count)
158{
159 entropy_analysis_max_sample_count = sample_count;
160 entropy_analysis_buffer_size = sample_count * sizeof(entropy_sample_t);
161 entropy_analysis_buffer = zalloc_permanent(entropy_analysis_buffer_size, ZALIGN(entropy_sample_t));
2a1bd2d3
A
162}
163
164__startup_func
165void
166entropy_init(void)
167{
168 lck_grp_init(&entropy_data.lock_group, "entropy-data", LCK_GRP_ATTR_NULL);
169 lck_mtx_init(&entropy_data.mutex, &entropy_data.lock_group, LCK_ATTR_NULL);
170
171 // The below path is used only for testing. This boot arg is used
172 // to collect raw entropy samples for offline analysis. The "ebsz"
173 // name is supported only until dependent tools can be updated to
174 // use the more descriptive "entropy-analysis-sample-count".
175 uint32_t sample_count = 0;
176 if (__improbable(PE_parse_boot_argn("entropy-analysis-sample-count", &sample_count, sizeof(sample_count)))) {
177 entropy_analysis_init(sample_count);
178 } else if (__improbable(PE_parse_boot_argn("ebsz", &sample_count, sizeof(sample_count)))) {
179 entropy_analysis_init(sample_count);
180 }
181}
182
0a7de745 183void
2a1bd2d3
A
184entropy_collect(void)
185{
186 // This function is called from within the interrupt handler, so
187 // we do not need to disable interrupts.
188
189 entropy_cpu_data_t *e = PERCPU_GET(entropy_cpu_data);
190
191 uint32_t sample_count = os_atomic_load(&e->sample_count, relaxed);
192
193 assert(sample_count <= ENTROPY_MAX_SAMPLE_COUNT);
194
195 // If the buffer is full, we return early without collecting
196 // entropy.
197 if (sample_count == ENTROPY_MAX_SAMPLE_COUNT) {
198 return;
199 }
200
201 e->samples[sample_count] = (entropy_sample_t)ml_get_timebase_entropy();
202
203 // If the consumer has reset the sample count on us, the only
204 // consequence is a dropped sample. We effectively abort the
205 // entropy collection in this case.
206 (void)os_atomic_cmpxchg(&e->sample_count, sample_count, sample_count + 1, release);
207}
208
209// For information on the following tests, see NIST SP 800-90B 4
210// Health Tests. These tests are intended to detect catastrophic
211// degradations in entropy. As noted in that document:
212//
213// > Health tests are expected to raise an alarm in three cases:
214// > 1. When there is a significant decrease in the entropy of the
215// > outputs,
216// > 2. When noise source failures occur, or
217// > 3. When hardware fails, and implementations do not work
218// > correctly.
219//
220// Each entropy accumulator declines to release entropy until the
221// startup tests required by NIST are complete. In the event that a
222// health test does fail, all entropy accumulators are reset and
223// decline to release further entropy until their startup tests can be
224// repeated.
225
226static health_test_result_t
227add_observation(entropy_health_test_t *t, uint64_t bound)
228{
229 t->observation_count += 1;
230 t->stats->max_observation_count = MAX(t->stats->max_observation_count, (uint32_t)t->observation_count);
231 if (__improbable(t->observation_count >= bound)) {
232 t->stats->failure_count += 1;
233 return health_test_failure;
234 }
235
236 return health_test_success;
237}
238
239static void
240reset_test(entropy_health_test_t *t, entropy_sample_t observation)
241{
242 t->stats->reset_count += 1;
243 t->init_observation = observation;
244 t->observation_count = 1;
245 t->stats->max_observation_count = MAX(t->stats->max_observation_count, (uint32_t)t->observation_count);
246}
247
248// 4.4.1 Repetition Count Test
249//
250// Like the name implies, this test counts consecutive occurrences of
251// the same value.
252//
253// We compute the bound C as:
254//
255// A = 2^-128
256// H = 1
257// C = 1 + ceil(-log(A, 2) / H) = 129
258//
259// With A the acceptable chance of false positive and H a conservative
260// estimate for the entropy (in bits) of each sample.
261
262#define REPETITION_COUNT_BOUND (129)
263
264static health_test_result_t
265repetition_count_test(entropy_sample_t observation)
266{
267 entropy_health_test_t *t = &entropy_data.repetition_count_test;
268
269 if (t->init_observation == observation) {
270 return add_observation(t, REPETITION_COUNT_BOUND);
271 } else {
272 reset_test(t, observation);
273 }
274
275 return health_test_success;
276}
277
278// 4.4.2 Adaptive Proportion Test
279//
280// This test counts occurrences of a value within a window of samples.
281//
282// We use a non-binary alphabet, giving us a window size of 512. (In
283// particular, we consider the least-significant byte of each time
284// sample.)
285//
286// Assuming one bit of entropy, we can compute the binomial cumulative
287// distribution function over 512 trials in SageMath as:
288//
289// k = var('k')
290// f(x) = sum(binomial(512, k), k, x, 512) / 2^512
291//
292// We compute the bound C as the minimal x for which:
293//
294// f(x) < 2^-128
295//
296// Is true.
297//
298// Empirically, we have C = 400.
299
300#define ADAPTIVE_PROPORTION_BOUND (400)
301#define ADAPTIVE_PROPORTION_WINDOW (512)
302
303// This mask definition requires the window be a power of two.
304static_assert(__builtin_popcount(ADAPTIVE_PROPORTION_WINDOW) == 1);
305#define ADAPTIVE_PROPORTION_INDEX_MASK (ADAPTIVE_PROPORTION_WINDOW - 1)
306
307static health_test_result_t
308adaptive_proportion_test(entropy_sample_t observation, uint32_t offset)
309{
310 entropy_health_test_t *t = &entropy_data.adaptive_proportion_test;
311
312 // We work in windows of size ADAPTIVE_PROPORTION_WINDOW, so we
313 // can compute our index by taking the entropy buffer's overall
314 // sample count plus the offset of this observation modulo the
315 // window size.
316 uint32_t index = (entropy_data.total_sample_count + offset) & ADAPTIVE_PROPORTION_INDEX_MASK;
317
318 if (index == 0) {
319 reset_test(t, observation);
320 } else if (t->init_observation == observation) {
321 return add_observation(t, ADAPTIVE_PROPORTION_BOUND);
322 }
323
324 return health_test_success;
325}
326
327static health_test_result_t
328entropy_health_test(uint32_t sample_count, entropy_sample_t *samples)
329{
330 health_test_result_t result = health_test_success;
331
332 for (uint32_t i = 0; i < sample_count; i += 1) {
333 // We only consider the low bits of each sample, since that is
334 // where we expect the entropy to be concentrated.
335 entropy_sample_t observation = samples[i] & 0xff;
336
337 if (__improbable(repetition_count_test(observation) == health_test_failure)) {
338 result = health_test_failure;
339 }
340
341 if (__improbable(adaptive_proportion_test(observation, i) == health_test_failure)) {
342 result = health_test_failure;
343 }
344 }
345
346 return result;
347}
348
349static void
350entropy_analysis_store(uint32_t sample_count, entropy_sample_t *samples)
351{
352 lck_mtx_assert(&entropy_data.mutex, LCK_MTX_ASSERT_OWNED);
353
354 sample_count = MIN(sample_count, (entropy_analysis_max_sample_count - entropy_analysis_sample_count));
355 if (sample_count == 0) {
356 return;
357 }
358
359 size_t size = sample_count * sizeof(samples[0]);
360 memcpy(&entropy_analysis_buffer[entropy_analysis_sample_count], samples, size);
361 entropy_analysis_sample_count += sample_count;
362}
363
364int32_t
365entropy_provide(size_t *entropy_size, void *entropy, __unused void *arg)
1c79356b 366{
2a1bd2d3
A
367#if (DEVELOPMENT || DEBUG)
368 if (*entropy_size < SHA256_DIGEST_LENGTH) {
369 panic("[entropy_provide] recipient entropy buffer is too small\n");
370 }
371#endif
372
373 int32_t sample_count = 0;
374 *entropy_size = 0;
375
376 // The first call to this function comes while the corecrypto kext
377 // is being loaded. We require SHA256 to accumulate entropy
378 // samples.
379 if (__improbable(!g_crypto_funcs)) {
380 return sample_count;
381 }
382
383 // There is only one consumer (the kernel PRNG), but they could
384 // try to consume entropy from different threads. We simply fail
385 // if a consumption is already in progress.
386 if (!lck_mtx_try_lock(&entropy_data.mutex)) {
387 return sample_count;
388 }
389
390 // This only happens on the first call to this function. We cannot
391 // perform this initialization in entropy_init because the
392 // corecrypto kext is not loaded yet.
393 if (__improbable(!entropy_data.sha256_ctx_init)) {
394 SHA256_Init(&entropy_data.sha256_ctx);
395 entropy_data.sha256_ctx_init = true;
396 }
397
398 health_test_result_t health_test_result = health_test_success;
399
400 // We accumulate entropy from all CPUs.
401 percpu_foreach(e, entropy_cpu_data) {
402 // On each CPU, the sample count functions as an index into
403 // the entropy buffer. All samples before that index are valid
404 // for consumption.
405 uint32_t cpu_sample_count = os_atomic_load(&e->sample_count, acquire);
406
407 assert(cpu_sample_count <= ENTROPY_MAX_SAMPLE_COUNT);
1c79356b 408
2a1bd2d3
A
409 // The health test depends in part on the current state of
410 // the entropy data, so we test the new sample before
411 // accumulating it.
412 if (__improbable(entropy_health_test(cpu_sample_count, e->samples) == health_test_failure)) {
413 health_test_result = health_test_failure;
f427ee49 414 }
cb323159 415
2a1bd2d3
A
416 // We accumulate the samples regardless of whether the test
417 // failed. It cannot hurt.
418 entropy_data.total_sample_count += cpu_sample_count;
419 SHA256_Update(&entropy_data.sha256_ctx, e->samples, cpu_sample_count * sizeof(e->samples[0]));
cb323159 420
2a1bd2d3
A
421 // This code path is only used for testing. Its use is governed by
422 // a boot arg; see its initialization above.
423 if (__improbable(entropy_analysis_buffer)) {
424 entropy_analysis_store(cpu_sample_count, e->samples);
425 }
426
427 // "Drain" the per-CPU buffer by resetting its sample count.
428 os_atomic_store(&e->sample_count, 0, relaxed);
429 }
cb323159 430
2a1bd2d3
A
431 // We expect this never to happen.
432 //
433 // But if it does happen, we need to return negative to signal the
434 // consumer (i.e. the kernel PRNG) that there has been a failure.
435 if (__improbable(health_test_result == health_test_failure)) {
436 entropy_health_startup_done = 0;
437 entropy_data.startup_sample_count = entropy_data.total_sample_count;
438 entropy_data.read_sample_count = entropy_data.total_sample_count;
439 sample_count = -1;
440 goto out;
f427ee49 441 }
2a1bd2d3
A
442
443 // FIPS requires we pass our startup health tests before providing
444 // any entropy. This condition is only true during startup and in
445 // case of reset due to test failure.
446 if (__improbable((entropy_data.total_sample_count - entropy_data.startup_sample_count) < 1024)) {
447 goto out;
448 }
449
450 entropy_health_startup_done = 1;
451
452 // The count of new samples from the consumer's perspective.
453 int32_t n = (int32_t)(entropy_data.total_sample_count - entropy_data.read_sample_count);
454
455 // For performance reasons, we require a small threshold of
456 // samples to have built up before we provide any to the PRNG.
457 if (n < 32) {
458 goto out;
459 }
460
461 SHA256_Final(entropy, &entropy_data.sha256_ctx);
462 SHA256_Init(&entropy_data.sha256_ctx);
463 entropy_data.read_sample_count = entropy_data.total_sample_count;
464
465 sample_count = n;
466 *entropy_size = SHA256_DIGEST_LENGTH;
467
468out:
469 lck_mtx_unlock(&entropy_data.mutex);
470
471 return sample_count;
1c79356b 472}