diff options
Diffstat (limited to 'src/include/ipxe/entropy.h')
-rw-r--r-- | src/include/ipxe/entropy.h | 414 |
1 files changed, 313 insertions, 101 deletions
diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index d2e3ce501..108c37669 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -12,40 +12,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <string.h> #include <assert.h> -#include <ipxe/api.h> #include <ipxe/hash_df.h> #include <ipxe/sha256.h> +#include <ipxe/tables.h> #include <config/entropy.h> -/** - * Calculate static inline entropy API function name - * - * @v _prefix Subsystem prefix - * @v _api_func API function - * @ret _subsys_func Subsystem API function - */ -#define ENTROPY_INLINE( _subsys, _api_func ) \ - SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func ) - -/** - * Provide a entropy API implementation - * - * @v _prefix Subsystem prefix - * @v _api_func API function - * @v _func Implementing function - */ -#define PROVIDE_ENTROPY( _subsys, _api_func, _func ) \ - PROVIDE_SINGLE_API ( ENTROPY_PREFIX_ ## _subsys, _api_func, _func ) - -/** - * Provide a static inline entropy API implementation - * - * @v _prefix Subsystem prefix - * @v _api_func API function - */ -#define PROVIDE_ENTROPY_INLINE( _subsys, _api_func ) \ - PROVIDE_SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func ) - /** A noise sample */ typedef uint8_t noise_sample_t; @@ -71,56 +42,93 @@ typedef unsigned int min_entropy_t; #define MIN_ENTROPY( bits ) \ ( ( min_entropy_t ) ( (bits) * MIN_ENTROPY_SCALE ) ) -/* Include all architecture-independent entropy API headers */ -#include <ipxe/null_entropy.h> -#include <ipxe/efi/efi_entropy.h> -#include <ipxe/linux/linux_entropy.h> +/** An entropy source */ +struct entropy_source { + /** Name */ + const char *name; + /** + * min-entropy per sample + * + * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in + * NIST SP 800-90 Appendix C.3 as + * + * H_min = -log2 ( p_max ) + * + * where p_max is the probability of the most likely sample value. + * + * Filled in by entropy_init(). + */ + min_entropy_t min_entropy_per_sample; + /** + * Repetition count test cutoff value + * + * This is the cutoff value for the Repetition Count Test + * defined in ANS X9.82 Part 2 (October 2011 Draft) Section + * 8.5.2.1.2. + * + * Filled in by entropy_init(). + */ + unsigned int repetition_count_cutoff; + /** + * Adaptive proportion test cutoff value + * + * This is the cutoff value for the Adaptive Proportion Test + * defined in ANS X9.82 Part 2 (October 2011 Draft) Section + * 8.5.2.1.3.1.2. + * + * Filled in by entropy_init(). + */ + unsigned int adaptive_proportion_cutoff; + /** + * Startup test count + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 + * requires that at least one full cycle of the continuous + * tests must be performed at start-up. + */ + unsigned int startup_test_count; + /** + * Enable entropy gathering + * + * @ret rc Return status code + */ + int ( * enable ) ( void ); + /** + * Disable entropy gathering + * + */ + void ( * disable ) ( void ); + /** + * Get noise sample + * + * @ret noise Noise sample + * @ret rc Return status code + * + * This is the GetNoise function defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 6.5.2. + */ + int ( * get_noise ) ( noise_sample_t *noise ); +}; -/* Include all architecture-dependent entropy API headers */ -#include <bits/entropy.h> +/** Entropy source table */ +#define ENTROPY_SOURCES __table ( struct entropy_source, "entropy_sources" ) -/** - * Enable entropy gathering - * - * @ret rc Return status code - */ -int entropy_enable ( void ); +/** Declare an entropy source */ +#define __entropy_source( order ) __table_entry ( ENTROPY_SOURCES, order ) -/** - * Disable entropy gathering +/** @defgroup entropy_source_order Entropy source order * + * @{ */ -void entropy_disable ( void ); -/** - * min-entropy per sample - * - * @ret min_entropy min-entropy of each sample - * - * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in - * NIST SP 800-90 Appendix C.3 as - * - * H_min = -log2 ( p_max ) - * - * where p_max is the probability of the most likely sample value. - * - * This must be a compile-time constant. - */ -min_entropy_t min_entropy_per_sample ( void ); +#define ENTROPY_PREFERRED 01 /**< Preferred entropy source */ +#define ENTROPY_NORMAL 02 /**< Normal entropy source */ +#define ENTROPY_FALLBACK 03 /**< Fallback entropy source */ -/** - * Get noise sample - * - * @ret noise Noise sample - * @ret rc Return status code - * - * This is the GetNoise function defined in ANS X9.82 Part 2 - * (October 2011 Draft) Section 6.5.2. - */ -int get_noise ( noise_sample_t *noise ); +/** @} */ -extern int get_entropy_input_tmp ( unsigned int num_samples, - uint8_t *tmp, size_t tmp_len ); +extern int get_entropy_input_tmp ( min_entropy_t min_entropy, uint8_t *tmp, + size_t tmp_len ); /** Use SHA-256 as the underlying hash algorithm for Hash_df * @@ -145,8 +153,8 @@ extern int get_entropy_input_tmp ( unsigned int num_samples, * each entropy source output after each GetEntropy call) as defined * in ANS X9.82 Part 4 (April 2011 Draft) Section 13.3.4.2. * - * To minimise code size, the number of samples required is calculated - * at compilation time. + * This function is inlined since the entropy amount and length inputs + * are always compile-time constants. */ static inline __attribute__ (( always_inline )) int get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, @@ -154,41 +162,16 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, size_t tmp_len = ( ( ( min_entropy_bits * 2 ) + 7 ) / 8 ); uint8_t tmp_buf[ tmp_len ]; uint8_t *tmp = ( ( tmp_len > max_len ) ? tmp_buf : data ); - double min_samples; - unsigned int num_samples; unsigned int n; int rc; - /* Sanity checks */ - linker_assert ( ( min_entropy_per_sample() <= - MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ), - min_entropy_per_sample_is_impossibly_high ); + /* Sanity check */ linker_assert ( ( min_entropy_bits <= ( 8 * max_len ) ), entropy_buffer_too_small ); /* Round up minimum entropy to an integral number of bytes */ min_entropy_bits = ( ( min_entropy_bits + 7 ) & ~7 ); - /* Calculate number of samples required to contain sufficient entropy */ - min_samples = ( MIN_ENTROPY ( min_entropy_bits ) / - min_entropy_per_sample() ); - - /* Round up to a whole number of samples. We don't have the - * ceil() function available, so do the rounding by hand. - */ - num_samples = min_samples; - if ( num_samples < min_samples ) - num_samples++; - linker_assert ( ( num_samples >= min_samples ), rounding_error ); - - /* Floating-point operations are not allowed in iPXE since we - * never set up a suitable environment. Abort the build - * unless the calculated number of samples is a compile-time - * constant. - */ - linker_assert ( __builtin_constant_p ( num_samples ), - num_samples_not_constant ); - /* (Unnumbered). The output length of the hash function shall * meet or exceed the security strength indicated by the * min_entropy parameter. @@ -218,8 +201,10 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, linker_assert ( __builtin_constant_p ( tmp_len ), tmp_len_not_constant ); linker_assert ( ( n == ( 8 * tmp_len ) ), tmp_len_mismatch ); - if ( ( rc = get_entropy_input_tmp ( num_samples, tmp, tmp_len ) ) != 0 ) + if ( ( rc = get_entropy_input_tmp ( MIN_ENTROPY ( min_entropy_bits ), + tmp, tmp_len ) ) != 0 ) { return rc; + } /* 6. If ( n < min_length ), then tmp = tmp || 0^(min_length-n) * 7. If ( n > max_length ), then tmp = df ( tmp, max_length ) @@ -242,4 +227,231 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, } } +/** + * Calculate cutoff value for the repetition count test + * + * @v min_entropy_per_sample Min-entropy per sample + * @ret cutoff Cutoff value + * + * This is the cutoff value for the Repetition Count Test defined in + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_repetition_count_cutoff ( min_entropy_t min_entropy_per_sample ) { + double max_repetitions; + unsigned int cutoff; + + /* The cutoff formula for the repetition test is: + * + * C = ( 1 + ( -log2(W) / H_min ) ) + * + * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October + * 2011 Draft) Section 8.5.2.1.3.1). + */ + max_repetitions = ( 1 + ( MIN_ENTROPY ( 30 ) / + min_entropy_per_sample ) ); + + /* Round up to a whole number of repetitions. We don't have + * the ceil() function available, so do the rounding by hand. + */ + cutoff = max_repetitions; + if ( cutoff < max_repetitions ) + cutoff++; + linker_assert ( ( cutoff >= max_repetitions ), rounding_error ); + + /* Floating-point operations are not allowed in iPXE since we + * never set up a suitable environment. Abort the build + * unless the calculated number of repetitions is a + * compile-time constant. + */ + linker_assert ( __builtin_constant_p ( cutoff ), + repetition_count_cutoff_not_constant ); + + return cutoff; +} + +/** + * Window size for the adaptive proportion test + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows + * five possible window sizes: 16, 64, 256, 4096 and 65536. + * + * We expect to generate relatively few (<256) entropy samples during + * a typical iPXE run; the use of a large window size would mean that + * the test would never complete a single cycle. We use a window size + * of 64, which is the smallest window size that permits values of + * H_min down to one bit per sample. + */ +#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64 + +/** + * Combine adaptive proportion test window size and min-entropy + * + * @v n N (window size) + * @v h H (min-entropy) + * @ret n_h (N,H) combined value + */ +#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) ) + +/** + * Define a row of the adaptive proportion cutoff table + * + * @v h H (min-entropy) + * @v c16 Cutoff for N=16 + * @v c64 Cutoff for N=64 + * @v c256 Cutoff for N=256 + * @v c4096 Cutoff for N=4096 + * @v c65536 Cutoff for N=65536 + */ +#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \ + case APC_N_H ( 16, h ) : return c16; \ + case APC_N_H ( 64, h ) : return c64; \ + case APC_N_H ( 256, h ) : return c256; \ + case APC_N_H ( 4096, h ) : return c4096; \ + case APC_N_H ( 65536, h ) : return c65536; + +/** Value used to represent "N/A" in adaptive proportion cutoff table */ +#define APC_NA 0 + +/** + * Look up value in adaptive proportion test cutoff table + * + * @v n N (window size) + * @v h H (min-entropy) + * @ret cutoff Cutoff + * + * This is the table of cutoff values defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 8.5.2.1.3.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) { + switch ( APC_N_H ( n, h ) ) { + APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 ); + APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 ); + APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 ); + APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 ); + APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 ); + APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 ); + APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 ); + APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 ); + APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 ); + APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 ); + APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 ); + APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 ); + APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 ); + APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 ); + APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 ); + APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 ); + APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 ); + APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 ); + APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 ); + APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 ); + default: + return APC_NA; + } +} + +/** + * Calculate cutoff value for the adaptive proportion test + * + * @v min_entropy_per_sample Min-entropy per sample + * @ret cutoff Cutoff value + * + * This is the cutoff value for the Adaptive Proportion Test defined + * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_adaptive_proportion_cutoff ( min_entropy_t min_entropy_per_sample ) { + unsigned int h; + unsigned int n; + unsigned int cutoff; + + /* Look up cutoff value in cutoff table */ + n = ADAPTIVE_PROPORTION_WINDOW_SIZE; + h = ( min_entropy_per_sample / MIN_ENTROPY_SCALE ); + cutoff = entropy_adaptive_proportion_cutoff_lookup ( n, h ); + + /* Fail unless cutoff value is a compile-time constant */ + linker_assert ( __builtin_constant_p ( cutoff ), + adaptive_proportion_cutoff_not_constant ); + + /* Fail if cutoff value is N/A */ + linker_assert ( ( cutoff != APC_NA ), + adaptive_proportion_cutoff_not_applicable ); + + return cutoff; +} + +/** + * Calculate number of samples required for startup tests + * + * @v repetition_count_cutoff Repetition count test cutoff value + * @v adaptive_proportion_cutoff Adaptive proportion test cutoff value + * @ret num_samples Number of samples required + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires + * that at least one full cycle of the continuous tests must be + * performed at start-up. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_startup_test_count ( unsigned int repetition_count_cutoff, + unsigned int adaptive_proportion_cutoff ) { + unsigned int num_samples; + + /* At least max(N,C) samples shall be generated by the noise + * source for start-up testing. + */ + num_samples = repetition_count_cutoff; + if ( num_samples < adaptive_proportion_cutoff ) + num_samples = adaptive_proportion_cutoff; + linker_assert ( __builtin_constant_p ( num_samples ), + startup_test_count_not_constant ); + + return num_samples; +} + +/** + * Initialise entropy source + * + * @v source Entropy source + * @v min_entropy_per_sample Min-entropy per sample + * + * The cutoff value calculations for the repetition count test and the + * adaptive proportion test are provided as static inline functions + * since the results will always be compile-time constants. + */ +static inline __attribute__ (( always_inline )) void +entropy_init ( struct entropy_source *source, + min_entropy_t min_entropy_per_sample ) { + unsigned int repetition_count_cutoff; + unsigned int adaptive_proportion_cutoff; + unsigned int startup_test_count; + + /* Sanity check */ + linker_assert ( min_entropy_per_sample > MIN_ENTROPY ( 0 ), + min_entropy_per_sample_is_zero ); + linker_assert ( ( min_entropy_per_sample <= + MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ), + min_entropy_per_sample_is_impossibly_high ); + + /* Calculate test cutoff values */ + repetition_count_cutoff = + entropy_repetition_count_cutoff ( min_entropy_per_sample ); + adaptive_proportion_cutoff = + entropy_adaptive_proportion_cutoff ( min_entropy_per_sample ); + startup_test_count = + entropy_startup_test_count ( repetition_count_cutoff, + adaptive_proportion_cutoff ); + + /* Record min-entropy per sample and test cutoff values */ + source->min_entropy_per_sample = min_entropy_per_sample; + source->repetition_count_cutoff = repetition_count_cutoff; + source->adaptive_proportion_cutoff = adaptive_proportion_cutoff; + source->startup_test_count = startup_test_count; +} + +extern int entropy_enable ( void ); +extern void entropy_disable ( void ); +extern int get_noise ( noise_sample_t *noise ); + #endif /* _IPXE_ENTROPY_H */ |