mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-10-30 07:56:50 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5412db1370 |
@ -1,12 +0,0 @@
|
||||
#ifndef _BITS_ENTROPY_H
|
||||
#define _BITS_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific entropy API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_ENTROPY_H */
|
||||
@ -1,12 +0,0 @@
|
||||
#ifndef _BITS_ENTROPY_H
|
||||
#define _BITS_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* LoongArch64-specific entropy API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_ENTROPY_H */
|
||||
@ -32,12 +32,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <errno.h>
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/entropy.h>
|
||||
#include <ipxe/drbg.h>
|
||||
|
||||
struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED );
|
||||
|
||||
/** Number of times to retry RDRAND instruction */
|
||||
#define RDRAND_RETRY_COUNT 16
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour CPUID_FEATURES_INTEL_ECX_RDRAND
|
||||
#define colour &rdrand_entropy
|
||||
|
||||
/**
|
||||
* Enable entropy gathering
|
||||
@ -54,18 +57,17 @@ static int rdrand_entropy_enable ( void ) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Data returned by RDRAND is theoretically full entropy, up
|
||||
* to a security strength of 128 bits, so assume that each
|
||||
* sample contains exactly 8 bits of entropy.
|
||||
*/
|
||||
if ( DRBG_SECURITY_STRENGTH > 128 )
|
||||
return -ENOTSUP;
|
||||
entropy_init ( &rdrand_entropy, MIN_ENTROPY ( 8.0 ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable entropy gathering
|
||||
*
|
||||
*/
|
||||
static void rdrand_entropy_disable ( void ) {
|
||||
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
/**
|
||||
* Get noise sample
|
||||
*
|
||||
@ -93,7 +95,9 @@ static int rdrand_get_noise ( noise_sample_t *noise ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PROVIDE_ENTROPY_INLINE ( rdrand, min_entropy_per_sample );
|
||||
PROVIDE_ENTROPY ( rdrand, entropy_enable, rdrand_entropy_enable );
|
||||
PROVIDE_ENTROPY ( rdrand, entropy_disable, rdrand_entropy_disable );
|
||||
PROVIDE_ENTROPY ( rdrand, get_noise, rdrand_get_noise );
|
||||
/** Hardware random number generator entropy source */
|
||||
struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED ) = {
|
||||
.name = "rdrand",
|
||||
.enable = rdrand_entropy_enable,
|
||||
.get_noise = rdrand_get_noise,
|
||||
};
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
#ifndef _BITS_ENTROPY_H
|
||||
#define _BITS_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86-specific entropy API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/rtc_entropy.h>
|
||||
#include <ipxe/rdrand.h>
|
||||
|
||||
#endif /* _BITS_ENTROPY_H */
|
||||
@ -1,37 +0,0 @@
|
||||
#ifndef _IPXE_RDRAND_H
|
||||
#define _IPXE_RDRAND_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Hardware random number generator
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/drbg.h>
|
||||
|
||||
#ifdef ENTROPY_RDRAND
|
||||
#define ENTROPY_PREFIX_rdrand
|
||||
#else
|
||||
#define ENTROPY_PREFIX_rdrand __rdrand_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* min-entropy per sample
|
||||
*
|
||||
* @ret min_entropy min-entropy of each sample
|
||||
*/
|
||||
static inline __always_inline min_entropy_t
|
||||
ENTROPY_INLINE ( rdrand, min_entropy_per_sample ) ( void ) {
|
||||
|
||||
/* Data returned by RDRAND is theoretically full entropy, up
|
||||
* to a security strength of 128 bits.
|
||||
*/
|
||||
if ( DRBG_SECURITY_STRENGTH > 128 )
|
||||
return 0;
|
||||
return MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_RDRAND_H */
|
||||
@ -1,62 +0,0 @@
|
||||
#ifndef _IPXE_RTC_ENTROPY_H
|
||||
#define _IPXE_RTC_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RTC-based entropy source
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ENTROPY_RTC
|
||||
#define ENTROPY_PREFIX_rtc
|
||||
#else
|
||||
#define ENTROPY_PREFIX_rtc __rtc_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* min-entropy per sample
|
||||
*
|
||||
* @ret min_entropy min-entropy of each sample
|
||||
*/
|
||||
static inline __always_inline min_entropy_t
|
||||
ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
|
||||
|
||||
/* The min-entropy has been measured on several platforms
|
||||
* using the entropy_sample test code. Modelling the samples
|
||||
* as independent, and using a confidence level of 99.99%, the
|
||||
* measurements were as follows:
|
||||
*
|
||||
* qemu-kvm : 7.38 bits
|
||||
* VMware : 7.46 bits
|
||||
* Physical hardware : 2.67 bits
|
||||
*
|
||||
* We choose the lowest of these (2.67 bits) and apply a 50%
|
||||
* safety margin to allow for some potential non-independence
|
||||
* of samples.
|
||||
*/
|
||||
return MIN_ENTROPY ( 1.3 );
|
||||
}
|
||||
|
||||
extern uint8_t rtc_sample ( void );
|
||||
|
||||
/**
|
||||
* Get noise sample
|
||||
*
|
||||
* @ret noise Noise sample
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static inline __always_inline int
|
||||
ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
|
||||
|
||||
/* Get sample */
|
||||
*noise = rtc_sample();
|
||||
|
||||
/* Always successful */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_RTC_ENTROPY_H */
|
||||
@ -39,6 +39,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/entropy.h>
|
||||
|
||||
struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL );
|
||||
|
||||
/** Maximum time to wait for an RTC interrupt, in milliseconds */
|
||||
#define RTC_MAX_WAIT_MS 100
|
||||
|
||||
@ -203,6 +205,21 @@ static int rtc_entropy_enable ( void ) {
|
||||
if ( ( rc = rtc_entropy_check() ) != 0 )
|
||||
goto err_check;
|
||||
|
||||
/* The min-entropy has been measured on several platforms
|
||||
* using the entropy_sample test code. Modelling the samples
|
||||
* as independent, and using a confidence level of 99.99%, the
|
||||
* measurements were as follows:
|
||||
*
|
||||
* qemu-kvm : 7.38 bits
|
||||
* VMware : 7.46 bits
|
||||
* Physical hardware : 2.67 bits
|
||||
*
|
||||
* We choose the lowest of these (2.67 bits) and apply a 50%
|
||||
* safety margin to allow for some potential non-independence
|
||||
* of samples.
|
||||
*/
|
||||
entropy_init ( &rtc_entropy, MIN_ENTROPY ( 1.3 ) );
|
||||
|
||||
return 0;
|
||||
|
||||
err_check:
|
||||
@ -226,11 +243,12 @@ static void rtc_entropy_disable ( void ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure a single RTC tick
|
||||
* Get noise sample
|
||||
*
|
||||
* @ret delta Length of RTC tick (in TSC units)
|
||||
* @ret noise Noise sample
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
uint8_t rtc_sample ( void ) {
|
||||
static int rtc_get_noise ( noise_sample_t *noise ) {
|
||||
uint32_t before;
|
||||
uint32_t after;
|
||||
uint32_t temp;
|
||||
@ -265,10 +283,14 @@ uint8_t rtc_sample ( void ) {
|
||||
: "=a" ( after ), "=d" ( before ), "=Q" ( temp )
|
||||
: "2" ( 0 ) );
|
||||
|
||||
return ( after - before );
|
||||
*noise = ( after - before );
|
||||
return 0;
|
||||
}
|
||||
|
||||
PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
|
||||
PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
|
||||
PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
|
||||
PROVIDE_ENTROPY_INLINE ( rtc, get_noise );
|
||||
/** RTC entropy source */
|
||||
struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL ) = {
|
||||
.name = "rtc",
|
||||
.enable = rtc_entropy_enable,
|
||||
.disable = rtc_entropy_disable,
|
||||
.get_noise = rtc_get_noise,
|
||||
};
|
||||
|
||||
@ -50,46 +50,61 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \
|
||||
__einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
|
||||
|
||||
/** Current entropy source */
|
||||
static struct entropy_source *entropy_source;
|
||||
|
||||
/**
|
||||
* Calculate cutoff value for the repetition count test
|
||||
* Enable entropy gathering
|
||||
*
|
||||
* @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.
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned int
|
||||
repetition_count_cutoff ( void ) {
|
||||
double max_repetitions;
|
||||
unsigned int cutoff;
|
||||
int entropy_enable ( void ) {
|
||||
int rc;
|
||||
|
||||
/* 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() ) );
|
||||
/* Enable selected source, if applicable */
|
||||
if ( entropy_source ) {
|
||||
|
||||
/* 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 );
|
||||
/* Enable entropy source */
|
||||
if ( ( rc = entropy_source->enable() ) != 0 ) {
|
||||
DBGC ( &entropy_source, "ENTROPY could not enable "
|
||||
"source %s: %s\n", entropy_source->name,
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 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 );
|
||||
/* Sanity checks */
|
||||
assert ( entropy_source->min_entropy_per_sample > 0 );
|
||||
assert ( entropy_source->repetition_count_cutoff > 0 );
|
||||
assert ( entropy_source->adaptive_proportion_cutoff > 0 );
|
||||
assert ( entropy_source->startup_test_count > 0 );
|
||||
|
||||
return cutoff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find the first working source */
|
||||
rc = -ENOENT;
|
||||
for_each_table_entry ( entropy_source, ENTROPY_SOURCES ) {
|
||||
if ( ( rc = entropy_enable() ) == 0 ) {
|
||||
DBGC ( &entropy_source, "ENTROPY using source %s\n",
|
||||
entropy_source->name );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable entropy gathering
|
||||
*
|
||||
*/
|
||||
void entropy_disable ( void ) {
|
||||
|
||||
/* Sanity check */
|
||||
assert ( entropy_source != NULL );
|
||||
|
||||
/* Disable entropy gathering, if applicable */
|
||||
if ( entropy_source->disable )
|
||||
entropy_source->disable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,6 +119,8 @@ repetition_count_cutoff ( void ) {
|
||||
static int repetition_count_test ( noise_sample_t sample ) {
|
||||
static noise_sample_t most_recent_sample;
|
||||
static unsigned int repetition_count = 0;
|
||||
unsigned int repetition_count_cutoff =
|
||||
entropy_source->repetition_count_cutoff;
|
||||
|
||||
/* A = the most recently seen sample value
|
||||
* B = the number of times that value A has been seen in a row
|
||||
@ -124,7 +141,7 @@ static int repetition_count_test ( noise_sample_t sample ) {
|
||||
/* i. If B >= C, then an error condition is raised
|
||||
* due to a failure of the test
|
||||
*/
|
||||
if ( repetition_count >= repetition_count_cutoff() )
|
||||
if ( repetition_count >= repetition_count_cutoff )
|
||||
return -EPIPE_REPETITION_COUNT_TEST;
|
||||
|
||||
} else {
|
||||
@ -141,117 +158,6 @@ static int repetition_count_test ( noise_sample_t sample ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
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
|
||||
*
|
||||
* @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
|
||||
adaptive_proportion_cutoff ( void ) {
|
||||
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 = adaptive_proportion_cutoff_lookup ( n, h );
|
||||
|
||||
/* Fail unless cutoff value is a build-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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform adaptive proportion test
|
||||
*
|
||||
@ -265,6 +171,8 @@ static int adaptive_proportion_test ( noise_sample_t sample ) {
|
||||
static noise_sample_t current_counted_sample;
|
||||
static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
|
||||
static unsigned int repetition_count;
|
||||
unsigned int adaptive_proportion_cutoff =
|
||||
entropy_source->adaptive_proportion_cutoff;
|
||||
|
||||
/* A = the sample value currently being counted
|
||||
* B = the number of samples examined in this run of the test so far
|
||||
@ -312,7 +220,7 @@ static int adaptive_proportion_test ( noise_sample_t sample ) {
|
||||
* condition, because the test has
|
||||
* detected a failure
|
||||
*/
|
||||
if ( repetition_count > adaptive_proportion_cutoff() )
|
||||
if ( repetition_count > adaptive_proportion_cutoff )
|
||||
return -EPIPE_ADAPTIVE_PROPORTION_TEST;
|
||||
|
||||
}
|
||||
@ -321,6 +229,23 @@ static int adaptive_proportion_test ( noise_sample_t sample ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
|
||||
/* Sanity check */
|
||||
assert ( entropy_source != NULL );
|
||||
|
||||
return entropy_source->get_noise ( noise );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entropy sample
|
||||
*
|
||||
@ -334,6 +259,9 @@ static int get_entropy ( entropy_sample_t *entropy ) {
|
||||
static int rc = 0;
|
||||
noise_sample_t noise;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( entropy_source != NULL );
|
||||
|
||||
/* Any failure is permanent */
|
||||
if ( rc != 0 )
|
||||
return rc;
|
||||
@ -357,31 +285,6 @@ static int get_entropy ( entropy_sample_t *entropy ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate number of samples required for startup tests
|
||||
*
|
||||
* @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
|
||||
startup_test_count ( void ) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create next nonce value
|
||||
*
|
||||
@ -402,7 +305,7 @@ static uint32_t make_next_nonce ( void ) {
|
||||
/**
|
||||
* Obtain entropy input temporary buffer
|
||||
*
|
||||
* @v num_samples Number of entropy samples
|
||||
* @v min_entropy Min-entropy required
|
||||
* @v tmp Temporary buffer
|
||||
* @v tmp_len Length of temporary buffer
|
||||
* @ret rc Return status code
|
||||
@ -412,11 +315,8 @@ static uint32_t make_next_nonce ( void ) {
|
||||
* and condensing 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.
|
||||
*/
|
||||
int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
|
||||
int get_entropy_input_tmp ( min_entropy_t min_entropy, uint8_t *tmp,
|
||||
size_t tmp_len ) {
|
||||
static unsigned int startup_tested = 0;
|
||||
struct {
|
||||
@ -424,6 +324,7 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
|
||||
entropy_sample_t sample;
|
||||
} __attribute__ (( packed )) data;;
|
||||
uint8_t df_buf[tmp_len];
|
||||
min_entropy_t entropy_total;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
@ -432,22 +333,20 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
|
||||
return rc;
|
||||
|
||||
/* Perform mandatory startup tests, if not yet performed */
|
||||
for ( ; startup_tested < startup_test_count() ; startup_tested++ ) {
|
||||
for ( ; startup_tested < entropy_source->startup_test_count ;
|
||||
startup_tested++ ) {
|
||||
if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
|
||||
goto err_get_entropy;
|
||||
}
|
||||
|
||||
/* 3. entropy_total = 0
|
||||
*
|
||||
* (Nothing to do; the number of entropy samples required has
|
||||
* already been precalculated.)
|
||||
*/
|
||||
/* 3. entropy_total = 0 */
|
||||
entropy_total = MIN_ENTROPY ( 0 );
|
||||
|
||||
/* 4. tmp = a fixed n-bit value, such as 0^n */
|
||||
memset ( tmp, 0, tmp_len );
|
||||
|
||||
/* 5. While ( entropy_total < min_entropy ) */
|
||||
while ( num_samples-- ) {
|
||||
while ( entropy_total < min_entropy ) {
|
||||
/* 5.1. ( status, entropy_bitstring, assessed_entropy )
|
||||
* = GetEntropy()
|
||||
* 5.2. If status indicates an error, return ( status, Null )
|
||||
@ -466,11 +365,8 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
|
||||
for ( i = 0 ; i < tmp_len ; i++ )
|
||||
tmp[i] ^= df_buf[i];
|
||||
|
||||
/* 5.5. entropy_total = entropy_total + assessed_entropy
|
||||
*
|
||||
* (Nothing to do; the number of entropy samples
|
||||
* required has already been precalculated.)
|
||||
*/
|
||||
/* 5.5. entropy_total = entropy_total + assessed_entropy */
|
||||
entropy_total += entropy_source->min_entropy_per_sample;
|
||||
}
|
||||
|
||||
/* Disable entropy gathering */
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Nonexistent entropy source
|
||||
*
|
||||
*
|
||||
* This source provides no entropy and must NOT be used in a
|
||||
* security-sensitive environment.
|
||||
*/
|
||||
|
||||
#include <ipxe/entropy.h>
|
||||
|
||||
PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample );
|
||||
PROVIDE_ENTROPY_INLINE ( null, entropy_enable );
|
||||
PROVIDE_ENTROPY_INLINE ( null, entropy_disable );
|
||||
PROVIDE_ENTROPY_INLINE ( null, get_noise );
|
||||
@ -1,35 +0,0 @@
|
||||
#ifndef _IPXE_EFI_ENTROPY_H
|
||||
#define _IPXE_EFI_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI entropy source
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ENTROPY_EFI
|
||||
#define ENTROPY_PREFIX_efi
|
||||
#else
|
||||
#define ENTROPY_PREFIX_efi __efi_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* min-entropy per sample
|
||||
*
|
||||
* @ret min_entropy min-entropy of each sample
|
||||
*/
|
||||
static inline __always_inline min_entropy_t
|
||||
ENTROPY_INLINE ( efi, min_entropy_per_sample ) ( void ) {
|
||||
|
||||
/* We use essentially the same mechanism as for the BIOS
|
||||
* RTC-based entropy source, and so assume the same
|
||||
* min-entropy per sample.
|
||||
*/
|
||||
return MIN_ENTROPY ( 1.3 );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_EFI_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
|
||||
/** Declare an entropy source */
|
||||
#define __entropy_source( order ) __table_entry ( ENTROPY_SOURCES, order )
|
||||
|
||||
/** @defgroup entropy_source_order Entropy source order
|
||||
*
|
||||
* @ret rc Return status code
|
||||
* @{
|
||||
*/
|
||||
int entropy_enable ( void );
|
||||
|
||||
/**
|
||||
* Disable entropy gathering
|
||||
*
|
||||
*/
|
||||
void entropy_disable ( void );
|
||||
#define ENTROPY_PREFERRED 01 /**< Preferred entropy source */
|
||||
#define ENTROPY_NORMAL 02 /**< Normal entropy source */
|
||||
#define ENTROPY_FALLBACK 03 /**< Fallback entropy source */
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* 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,9 @@ 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 to avoid unnecessarily linking in
|
||||
* hash_df(), since the 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 +163,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 +202,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 +228,229 @@ 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 ( 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 */
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
#ifndef _IPXE_LINUX_ENTROPY_H
|
||||
#define _IPXE_LINUX_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* /dev/random-based entropy source
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef ENTROPY_LINUX
|
||||
#define ENTROPY_PREFIX_linux
|
||||
#else
|
||||
#define ENTROPY_PREFIX_linux __linux_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* min-entropy per sample
|
||||
*
|
||||
* @ret min_entropy min-entropy of each sample
|
||||
*/
|
||||
static inline __always_inline min_entropy_t
|
||||
ENTROPY_INLINE ( linux, min_entropy_per_sample ) ( void ) {
|
||||
|
||||
/* linux_get_noise() reads a single byte from /dev/random,
|
||||
* which is supposed to block until a sufficient amount of
|
||||
* entropy is available. We therefore assume that each sample
|
||||
* contains exactly 8 bits of entropy.
|
||||
*/
|
||||
return MIN_ENTROPY ( 8.0 );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_LINUX_ENTROPY_H */
|
||||
@ -1,52 +0,0 @@
|
||||
#ifndef _IPXE_NULL_ENTROPY_H
|
||||
#define _IPXE_NULL_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Nonexistent entropy source
|
||||
*
|
||||
* This source provides no entropy and must NOT be used in a
|
||||
* security-sensitive environment.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ENTROPY_NULL
|
||||
#define ENTROPY_PREFIX_null
|
||||
#else
|
||||
#define ENTROPY_PREFIX_null __null_
|
||||
#endif
|
||||
|
||||
static inline __always_inline int
|
||||
ENTROPY_INLINE ( null, entropy_enable ) ( void ) {
|
||||
/* Do nothing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline __always_inline void
|
||||
ENTROPY_INLINE ( null, entropy_disable ) ( void ) {
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
static inline __always_inline min_entropy_t
|
||||
ENTROPY_INLINE ( null, min_entropy_per_sample ) ( void ) {
|
||||
/* Actual amount of min-entropy is zero. To avoid
|
||||
* division-by-zero errors and to allow compilation of
|
||||
* entropy-consuming code, pretend to have 1 bit of entropy in
|
||||
* each sample.
|
||||
*/
|
||||
return MIN_ENTROPY ( 1.0 );
|
||||
}
|
||||
|
||||
static inline __always_inline int
|
||||
ENTROPY_INLINE ( null, get_noise ) ( noise_sample_t *noise ) {
|
||||
|
||||
/* All sample values are constant */
|
||||
*noise = 0x01;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_NULL_ENTROPY_H */
|
||||
@ -36,6 +36,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
*/
|
||||
|
||||
struct entropy_source efi_entropy __entropy_source ( ENTROPY_NORMAL );
|
||||
|
||||
/** Random number generator protocol */
|
||||
static EFI_RNG_PROTOCOL *efirng;
|
||||
EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng );
|
||||
@ -91,6 +93,12 @@ static int efi_entropy_enable ( void ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* We use essentially the same mechanism as for the BIOS
|
||||
* RTC-based entropy source, and so assume the same
|
||||
* min-entropy per sample.
|
||||
*/
|
||||
entropy_init ( &efi_entropy, MIN_ENTROPY ( 1.3 ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -235,7 +243,10 @@ static int efi_get_noise ( noise_sample_t *noise ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PROVIDE_ENTROPY_INLINE ( efi, min_entropy_per_sample );
|
||||
PROVIDE_ENTROPY ( efi, entropy_enable, efi_entropy_enable );
|
||||
PROVIDE_ENTROPY ( efi, entropy_disable, efi_entropy_disable );
|
||||
PROVIDE_ENTROPY ( efi, get_noise, efi_get_noise );
|
||||
/** EFI entropy source */
|
||||
struct entropy_source efi_entropy __entropy_source ( ENTROPY_NORMAL ) = {
|
||||
.name = "efi",
|
||||
.enable = efi_entropy_enable,
|
||||
.disable = efi_entropy_disable,
|
||||
.get_noise = efi_get_noise,
|
||||
};
|
||||
|
||||
@ -34,6 +34,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/linux_api.h>
|
||||
#include <ipxe/entropy.h>
|
||||
|
||||
struct entropy_source linux_entropy __entropy_source ( ENTROPY_NORMAL );
|
||||
|
||||
/** Entropy source filename */
|
||||
static const char entropy_filename[] = "/dev/random";
|
||||
|
||||
@ -55,6 +57,13 @@ static int linux_entropy_enable ( void ) {
|
||||
return entropy_fd;
|
||||
}
|
||||
|
||||
/* linux_get_noise() reads a single byte from /dev/random,
|
||||
* which is supposed to block until a sufficient amount of
|
||||
* entropy is available. We therefore assume that each sample
|
||||
* contains exactly 8 bits of entropy.
|
||||
*/
|
||||
entropy_init ( &linux_entropy, MIN_ENTROPY ( 8.0 ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -95,7 +104,10 @@ static int linux_get_noise ( noise_sample_t *noise ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PROVIDE_ENTROPY_INLINE ( linux, min_entropy_per_sample );
|
||||
PROVIDE_ENTROPY ( linux, entropy_enable, linux_entropy_enable );
|
||||
PROVIDE_ENTROPY ( linux, entropy_disable, linux_entropy_disable );
|
||||
PROVIDE_ENTROPY ( linux, get_noise, linux_get_noise );
|
||||
/** Linux entropy source */
|
||||
struct entropy_source linux_entropy __entropy_source ( ENTROPY_NORMAL ) = {
|
||||
.name = "linux",
|
||||
.enable = linux_entropy_enable,
|
||||
.disable = linux_entropy_disable,
|
||||
.get_noise = linux_get_noise,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user