iPXE
entropy.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 /** @file
28  *
29  * Entropy source
30  *
31  * This algorithm is designed to comply with ANS X9.82 Part 4 (April
32  * 2011 Draft) Section 13.3. This standard is unfortunately not
33  * freely available.
34  */
35 
36 #include <stdint.h>
37 #include <assert.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <ipxe/crypto.h>
41 #include <ipxe/hash_df.h>
42 #include <ipxe/entropy.h>
43 
44 /* Disambiguate the various error causes */
45 #define EPIPE_REPETITION_COUNT_TEST \
46  __einfo_error ( EINFO_EPIPE_REPETITION_COUNT_TEST )
47 #define EINFO_EPIPE_REPETITION_COUNT_TEST \
48  __einfo_uniqify ( EINFO_EPIPE, 0x01, "Repetition count test failed" )
49 #define EPIPE_ADAPTIVE_PROPORTION_TEST \
50  __einfo_error ( EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST )
51 #define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \
52  __einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
53 
54 /**
55  * Initialise repetition count test
56  *
57  * @v source Entropy source
58  */
59 static void repetition_count_test_init ( struct entropy_source *source ) {
61  &source->repetition_count_test;
62 
63  /* Sanity checks */
64  assert ( test->repetition_count == 0 );
65  assert ( test->cutoff > 0 );
66 }
67 
68 /**
69  * Perform repetition count test
70  *
71  * @v source Entropy source
72  * @v sample Noise sample
73  * @ret rc Return status code
74  *
75  * This is the Repetition Count Test defined in ANS X9.82 Part 2
76  * (October 2011 Draft) Section 8.5.2.1.2.
77  */
78 static int repetition_count_test ( struct entropy_source *source,
79  noise_sample_t sample ) {
81  &source->repetition_count_test;
82 
83  /* A = the most recently seen sample value
84  * B = the number of times that value A has been seen in a row
85  * C = the cutoff value above which the repetition test should fail
86  */
87 
88  /* 1. For each new sample processed:
89  *
90  * (Note that the test for "repetition_count > 0" ensures that
91  * the initial value of most_recent_sample is treated as being
92  * undefined.)
93  */
94  if ( ( sample == test->most_recent_sample ) &&
95  ( test->repetition_count > 0 ) ) {
96 
97  /* a) If the new sample = A, then B is incremented by one. */
98  test->repetition_count++;
99 
100  /* i. If B >= C, then an error condition is raised
101  * due to a failure of the test
102  */
103  if ( test->repetition_count >= test->cutoff ) {
104  DBGC ( source, "ENTROPY %s excessively repeated "
105  "value %d (%d/%d)\n", source->name, sample,
106  test->repetition_count, test->cutoff );
108  }
109 
110  } else {
111 
112  /* b) Else:
113  * i. A = new sample
114  */
115  test->most_recent_sample = sample;
116 
117  /* ii. B = 1 */
118  test->repetition_count = 1;
119  }
120 
121  return 0;
122 }
123 
124 /**
125  * Initialise adaptive proportion test
126  *
127  * @v source Entropy source
128  */
129 static void adaptive_proportion_test_init ( struct entropy_source *source ) {
131  &source->adaptive_proportion_test;
132 
133  /* Sanity checks */
134  assert ( test->sample_count == 0 );
135  assert ( test->repetition_count == 0 );
136  assert ( test->cutoff > 0 );
137 
138  /* Ensure that a new test run starts immediately */
139  test->sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
140 }
141 
142 /**
143  * Perform adaptive proportion test
144  *
145  * @v source Entropy source
146  * @v sample Noise sample
147  * @ret rc Return status code
148  *
149  * This is the Adaptive Proportion Test for the Most Common Value
150  * defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.
151  */
152 static int adaptive_proportion_test ( struct entropy_source *source,
153  noise_sample_t sample ) {
155  &source->adaptive_proportion_test;
156 
157  /* A = the sample value currently being counted
158  * S = the number of samples examined in this run of the test so far
159  * N = the total number of samples that must be observed in
160  * one run of the test, also known as the "window size" of
161  * the test
162  * B = the current number of times that S (sic) has been seen
163  * in the W (sic) samples examined so far
164  * C = the cutoff value above which the repetition test should fail
165  * W = the probability of a false positive: 2^-30
166  */
167 
168  /* 1. The entropy source draws the current sample from the
169  * noise source.
170  *
171  * (Nothing to do; we already have the current sample.)
172  */
173 
174  /* 2. If S = N, then a new run of the test begins: */
175  if ( test->sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
176 
177  /* a. A = the current sample */
178  test->current_counted_sample = sample;
179 
180  /* b. S = 0 */
181  test->sample_count = 0;
182 
183  /* c. B = 0 */
184  test->repetition_count = 0;
185 
186  } else {
187 
188  /* Else: (the test is already running)
189  * a. S = S + 1
190  */
191  test->sample_count++;
192 
193  /* b. If A = the current sample, then: */
194  if ( sample == test->current_counted_sample ) {
195 
196  /* i. B = B + 1 */
197  test->repetition_count++;
198 
199  /* ii. If S (sic) > C then raise an error
200  * condition, because the test has
201  * detected a failure
202  */
203  if ( test->repetition_count > test->cutoff ) {
204  DBGC ( source, "ENTROPY %s excessively "
205  "repeated value %d (%d/%d)\n",
206  source->name, sample,
207  test->repetition_count, test->cutoff );
209  }
210  }
211  }
212 
213  return 0;
214 }
215 
216 /**
217  * Get entropy sample
218  *
219  * @v source Entropy source
220  * @ret entropy Entropy sample
221  * @ret rc Return status code
222  *
223  * This is the GetEntropy function defined in ANS X9.82 Part 2
224  * (October 2011 Draft) Section 6.5.1.
225  */
226 static int get_entropy ( struct entropy_source *source,
227  entropy_sample_t *entropy ) {
228  noise_sample_t noise;
229  int rc;
230 
231  /* Any failure is permanent */
232  if ( ( rc = source->rc ) != 0 )
233  goto err_broken;
234 
235  /* Get noise sample */
236  if ( ( rc = get_noise ( source, &noise ) ) != 0 )
237  goto err_get_noise;
238 
239  /* Perform Repetition Count Test and Adaptive Proportion Test
240  * as mandated by ANS X9.82 Part 2 (October 2011 Draft)
241  * Section 8.5.2.1.1.
242  */
243  if ( ( rc = repetition_count_test ( source, noise ) ) != 0 )
244  goto err_repetition_count_test;
245  if ( ( rc = adaptive_proportion_test ( source, noise ) ) != 0 )
246  goto err_adaptive_proportion_test;
247 
248  /* We do not use any optional conditioning component */
249  *entropy = noise;
250 
251  return 0;
252 
253  err_adaptive_proportion_test:
254  err_repetition_count_test:
255  err_get_noise:
256  source->rc = rc;
257  err_broken:
258  return rc;
259 }
260 
261 /**
262  * Initialise startup test
263  *
264  * @v source Entropy source
265  */
266 static void startup_test_init ( struct entropy_source *source ) {
267  struct entropy_startup_test *test = &source->startup_test;
268 
269  /* Sanity check */
270  assert ( test->tested == 0 );
271  assert ( test->count > 0 );
272 }
273 
274 /**
275  * Perform startup test
276  *
277  * @v source Entropy source
278  * @ret rc Return status code
279  */
280 static int startup_test ( struct entropy_source *source ) {
281  struct entropy_startup_test *test = &source->startup_test;
282  entropy_sample_t sample;
283  int rc;
284 
285  /* Perform mandatory number of startup tests */
286  for ( ; test->tested < test->count ; test->tested++ ) {
287  if ( ( rc = get_entropy ( source, &sample ) ) != 0 ) {
288  DBGC ( source, "ENTROPY %s failed: %s\n",
289  source->name, strerror ( rc ) );
290  return rc;
291  }
292  }
293 
294  return 0;
295 }
296 
297 /**
298  * Enable entropy gathering
299  *
300  * @v source Entropy source
301  * @ret rc Return status code
302  */
303 int entropy_enable ( struct entropy_source *source ) {
304  int rc;
305 
306  /* Refuse to enable a previously failed source */
307  if ( ( rc = source->rc ) != 0 )
308  return rc;
309 
310  /* Enable entropy source */
311  if ( ( rc = source->enable() ) != 0 ) {
312  DBGC ( source, "ENTROPY %s could not enable: %s\n",
313  source->name, strerror ( rc ) );
314  source->rc = rc;
315  return rc;
316  }
317 
318  /* Sanity check */
319  assert ( source->min_entropy_per_sample > 0 );
320 
321  /* Initialise test state if this source has not previously been used */
322  if ( source->startup_test.tested == 0 ) {
323  repetition_count_test_init ( source );
325  startup_test_init ( source );
326  }
327 
328  DBGC ( source, "ENTROPY %s enabled\n", source->name );
329  return 0;
330 }
331 
332 /**
333  * Enable and test entropy source
334  *
335  * @v source Entropy source
336  * @ret rc Return status code
337  */
338 static int entropy_enable_and_test ( struct entropy_source *source ) {
339  int rc;
340 
341  /* Enable source */
342  if ( ( rc = entropy_enable ( source ) ) != 0 )
343  goto err_enable;
344 
345  /* Test source */
346  if ( ( rc = startup_test ( source ) ) != 0 )
347  goto err_test;
348 
349  DBGC ( source, "ENTROPY %s passed %d startup tests\n",
350  source->name, source->startup_test.count );
351  return 0;
352 
353  err_test:
354  entropy_disable ( source );
355  err_enable:
356  assert ( source->rc == rc );
357  return rc;
358 }
359 
360 /**
361  * Enable first working entropy source
362  *
363  * @v source Entropy source to fill in
364  * @ret rc Return status code
365  */
366 static int entropy_enable_working ( struct entropy_source **source ) {
367  int rc;
368 
369  /* Find the first working source */
370  rc = -ENOENT;
372  if ( ( rc = entropy_enable_and_test ( *source ) ) == 0 )
373  return 0;
374  }
375 
376  DBGC ( *source, "ENTROPY has no working sources: %s\n",
377  strerror ( rc ) );
378  return rc;
379 }
380 
381 /**
382  * Disable entropy gathering
383  *
384  * @v source Entropy source
385  */
386 void entropy_disable ( struct entropy_source *source ) {
387 
388  /* Disable entropy gathering, if applicable */
389  if ( source->disable )
390  source->disable();
391 
392  DBGC ( source, "ENTROPY %s disabled\n", source->name );
393 }
394 
395 /**
396  * Create next nonce value
397  *
398  * @ret nonce Nonce
399  *
400  * This is the MakeNextNonce function defined in ANS X9.82 Part 4
401  * (April 2011 Draft) Section 13.3.4.2.
402  */
403 static uint32_t make_next_nonce ( void ) {
404  static uint32_t nonce;
405 
406  /* The simplest implementation of a nonce uses a large counter */
407  nonce++;
408 
409  return nonce;
410 }
411 
412 /**
413  * Obtain entropy input temporary buffer
414  *
415  * @v min_entropy Min-entropy required
416  * @v tmp Temporary buffer
417  * @v tmp_len Length of temporary buffer
418  * @ret rc Return status code
419  *
420  * This is (part of) the implementation of the Get_entropy_input
421  * function (using an entropy source as the source of entropy input
422  * and condensing each entropy source output after each GetEntropy
423  * call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section
424  * 13.3.4.2.
425  */
427  size_t tmp_len ) {
428  struct entropy_source *source;
429  struct {
430  uint32_t nonce;
431  entropy_sample_t sample;
432  } __attribute__ (( packed )) data;;
433  uint8_t df_buf[tmp_len];
434  min_entropy_t entropy_total;
435  unsigned int num_samples;
436  unsigned int i;
437  int rc;
438 
439  /* Enable entropy gathering */
440  if ( ( rc = entropy_enable_working ( &source ) ) != 0 )
441  goto err_enable_working;
442 
443  /* Sanity checks */
444  assert ( source->startup_test.count > 0 );
445  assert ( source->startup_test.tested >= source->startup_test.count );
446 
447  /* 3. entropy_total = 0 */
448  entropy_total = MIN_ENTROPY ( 0 );
449 
450  /* 4. tmp = a fixed n-bit value, such as 0^n */
451  memset ( tmp, 0, tmp_len );
452 
453  /* 5. While ( entropy_total < min_entropy ) */
454  for ( num_samples = 0 ; entropy_total < min_entropy ; num_samples++ ) {
455  /* 5.1. ( status, entropy_bitstring, assessed_entropy )
456  * = GetEntropy()
457  * 5.2. If status indicates an error, return ( status, Null )
458  */
459  if ( ( rc = get_entropy ( source, &data.sample ) ) != 0 )
460  goto err_get_entropy;
461 
462  /* 5.3. nonce = MakeNextNonce() */
463  data.nonce = make_next_nonce();
464 
465  /* 5.4. tmp = tmp XOR
466  * df ( ( nonce || entropy_bitstring ), n )
467  */
468  hash_df ( &entropy_hash_df_algorithm, &data, sizeof ( data ),
469  df_buf, sizeof ( df_buf ) );
470  for ( i = 0 ; i < tmp_len ; i++ )
471  tmp[i] ^= df_buf[i];
472 
473  /* 5.5. entropy_total = entropy_total + assessed_entropy */
474  entropy_total += source->min_entropy_per_sample;
475  }
476 
477  /* Disable entropy gathering */
478  entropy_disable ( source );
479 
480  DBGC ( source, "ENTROPY %s gathered %d bits in %d samples\n",
481  source->name, ( min_entropy / MIN_ENTROPY_SCALE ), num_samples );
482  return 0;
483 
484  err_get_entropy:
485  entropy_disable ( source );
486  assert ( source->rc == rc );
487  err_enable_working:
488  return rc;
489 }
490 
491 /* Drag in objects via entropy_enable */
493 
494 /* Drag in entropy configuration */
495 REQUIRE_OBJECT ( config_entropy );
#define __attribute__(x)
Definition: compiler.h:10
int rc
Failure status (if any)
Definition: entropy.h:144
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned int tested
Number of startup tests performed.
Definition: entropy.h:107
FILE_SECBOOT(PERMITTED)
Error codes.
#define MIN_ENTROPY_SCALE
Fixed-point scale for min-entropy amounts.
Definition: entropy.h:35
void(* disable)(void)
Disable entropy gathering.
Definition: entropy.h:156
static int repetition_count_test(struct entropy_source *source, noise_sample_t sample)
Perform repetition count test.
Definition: entropy.c:78
int(* enable)(void)
Enable entropy gathering.
Definition: entropy.h:151
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:515
Cryptographic API.
min_entropy_t min_entropy_per_sample
min-entropy per sample
Definition: entropy.h:132
static void adaptive_proportion_test_init(struct entropy_source *source)
Initialise adaptive proportion test.
Definition: entropy.c:129
Hash-based derivation function (Hash_df)
#define EPIPE_ADAPTIVE_PROPORTION_TEST
Definition: entropy.c:49
#define ENTROPY_SOURCES
Entropy source table.
Definition: entropy.h:170
An entropy source.
Definition: entropy.h:117
int get_entropy_input_tmp(min_entropy_t min_entropy, uint8_t *tmp, size_t tmp_len)
Obtain entropy input temporary buffer.
Definition: entropy.c:426
static int startup_test(struct entropy_source *source)
Perform startup test.
Definition: entropy.c:280
static int adaptive_proportion_test(struct entropy_source *source, noise_sample_t sample)
Perform adaptive proportion test.
Definition: entropy.c:152
const char * name
Name.
Definition: entropy.h:119
static uint32_t make_next_nonce(void)
Create next nonce value.
Definition: entropy.c:403
unsigned long tmp
Definition: linux_pci.h:65
#define EPIPE_REPETITION_COUNT_TEST
Definition: entropy.c:45
Repetition count test state.
Definition: entropy.h:52
struct entropy_repetition_count_test repetition_count_test
Repetition count test state.
Definition: entropy.h:134
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
struct entropy_startup_test startup_test
Startup test state.
Definition: entropy.h:138
static void startup_test_init(struct entropy_source *source)
Initialise startup test.
Definition: entropy.c:266
static void repetition_count_test_init(struct entropy_source *source)
Initialise repetition count test.
Definition: entropy.c:59
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
REQUIRING_SYMBOL(entropy_enable)
void hash_df(struct digest_algorithm *hash, const void *input, size_t input_len, void *output, size_t output_len)
Distribute entropy throughout a buffer.
Definition: hash_df.c:85
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
REQUIRE_OBJECT(config_entropy)
static int get_noise(struct entropy_source *source, noise_sample_t *noise)
Get noise sample.
Definition: entropy.h:209
unsigned char uint8_t
Definition: stdint.h:10
static int entropy_enable_working(struct entropy_source **source)
Enable first working entropy source.
Definition: entropy.c:366
static int get_entropy(struct entropy_source *source, entropy_sample_t *entropy)
Get entropy sample.
Definition: entropy.c:226
int entropy_enable(struct entropy_source *source)
Enable entropy gathering.
Definition: entropy.c:303
#define ADAPTIVE_PROPORTION_WINDOW_SIZE
Window size for the adaptive proportion test.
Definition: entropy.h:354
unsigned int uint32_t
Definition: stdint.h:12
u8 nonce[32]
Nonce value.
Definition: wpa.h:52
#define MIN_ENTROPY(bits)
Construct a min-entropy fixed-point value.
Definition: entropy.h:43
unsigned int min_entropy_t
An amount of min-entropy.
Definition: entropy.h:32
uint8_t entropy_sample_t
An entropy sample.
Definition: entropy.h:25
Startup test state.
Definition: entropy.h:105
struct entropy_adaptive_proportion_test adaptive_proportion_test
Adaptive proportion test state.
Definition: entropy.h:136
unsigned int count
Number of startup tests required for one full cycle.
Definition: entropy.h:113
uint8_t data[48]
Additional event data.
Definition: ena.h:22
uint8_t noise_sample_t
A noise sample.
Definition: entropy.h:22
#define entropy_hash_df_algorithm
Use SHA-256 as the underlying hash algorithm for Hash_df.
Definition: entropy.h:193
void entropy_disable(struct entropy_source *source)
Disable entropy gathering.
Definition: entropy.c:386
String functions.
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
Entropy source.
static int entropy_enable_and_test(struct entropy_source *source)
Enable and test entropy source.
Definition: entropy.c:338
static int test
Definition: epic100.c:73
Adaptive proportion test state.
Definition: entropy.h:76
void * memset(void *dest, int character, size_t len) __nonnull