|
@@ -1803,6 +1803,110 @@ test_crypto_siphash(void *arg)
|
|
;
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* We want the likelihood that the random buffer exhibits any regular pattern
|
|
|
|
+ * to be far less than the memory bit error rate in the int return value.
|
|
|
|
+ * Using 2048 bits provides a failure rate of 1/(3 * 10^616), and we call
|
|
|
|
+ * 3 functions, leading to an overall error rate of 1/10^616.
|
|
|
|
+ * This is comparable with the 1/10^603 failure rate of test_crypto_rng_range.
|
|
|
|
+ */
|
|
|
|
+#define FAILURE_MODE_BUFFER_SIZE (2048/8)
|
|
|
|
+
|
|
|
|
+/** Check crypto_rand for a failure mode where it does nothing to the buffer,
|
|
|
|
+ * or it sets the buffer to all zeroes. Return 0 when the check passes,
|
|
|
|
+ * or -1 when it fails. */
|
|
|
|
+static int
|
|
|
|
+crypto_rand_check_failure_mode_zero(void)
|
|
|
|
+{
|
|
|
|
+ char buf[FAILURE_MODE_BUFFER_SIZE];
|
|
|
|
+
|
|
|
|
+ memset(buf, 0, FAILURE_MODE_BUFFER_SIZE);
|
|
|
|
+ crypto_rand(buf, FAILURE_MODE_BUFFER_SIZE);
|
|
|
|
+
|
|
|
|
+ for (size_t i = 0; i < FAILURE_MODE_BUFFER_SIZE; i++) {
|
|
|
|
+ if (buf[i] != 0) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return -1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/** Check crypto_rand for a failure mode where every int64_t in the buffer is
|
|
|
|
+ * the same. Return 0 when the check passes, or -1 when it fails. */
|
|
|
|
+static int
|
|
|
|
+crypto_rand_check_failure_mode_identical(void)
|
|
|
|
+{
|
|
|
|
+ /* just in case the buffer size isn't a multiple of sizeof(int64_t) */
|
|
|
|
+#define FAILURE_MODE_BUFFER_SIZE_I64 \
|
|
|
|
+ (FAILURE_MODE_BUFFER_SIZE/SIZEOF_INT64_T)
|
|
|
|
+#define FAILURE_MODE_BUFFER_SIZE_I64_BYTES \
|
|
|
|
+ (FAILURE_MODE_BUFFER_SIZE_I64*SIZEOF_INT64_T)
|
|
|
|
+
|
|
|
|
+#if FAILURE_MODE_BUFFER_SIZE_I64 < 2
|
|
|
|
+#error FAILURE_MODE_BUFFER_SIZE needs to be at least 2*SIZEOF_INT64_T
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ int64_t buf[FAILURE_MODE_BUFFER_SIZE_I64];
|
|
|
|
+
|
|
|
|
+ memset(buf, 0, FAILURE_MODE_BUFFER_SIZE_I64_BYTES);
|
|
|
|
+ crypto_rand((char *)buf, FAILURE_MODE_BUFFER_SIZE_I64_BYTES);
|
|
|
|
+
|
|
|
|
+ for (size_t i = 1; i < FAILURE_MODE_BUFFER_SIZE_I64; i++) {
|
|
|
|
+ if (buf[i] != buf[i-1]) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return -1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/** Check crypto_rand for a failure mode where it increments the "random"
|
|
|
|
+ * value by 1 for every byte in the buffer. (This is OpenSSL's PREDICT mode.)
|
|
|
|
+ * Return 0 when the check passes, or -1 when it fails. */
|
|
|
|
+static int
|
|
|
|
+crypto_rand_check_failure_mode_predict(void)
|
|
|
|
+{
|
|
|
|
+ unsigned char buf[FAILURE_MODE_BUFFER_SIZE];
|
|
|
|
+
|
|
|
|
+ memset(buf, 0, FAILURE_MODE_BUFFER_SIZE);
|
|
|
|
+ crypto_rand((char *)buf, FAILURE_MODE_BUFFER_SIZE);
|
|
|
|
+
|
|
|
|
+ for (size_t i = 1; i < FAILURE_MODE_BUFFER_SIZE; i++) {
|
|
|
|
+ /* check if the last byte was incremented by 1, including integer
|
|
|
|
+ * wrapping */
|
|
|
|
+ if (buf[i] - buf[i-1] != 1 && buf[i-1] - buf[i] != 255) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return -1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#undef FAILURE_MODE_BUFFER_SIZE
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+test_crypto_failure_modes(void *arg)
|
|
|
|
+{
|
|
|
|
+ int rv = 0;
|
|
|
|
+ (void)arg;
|
|
|
|
+
|
|
|
|
+ rv = crypto_early_init();
|
|
|
|
+ tt_assert(rv == 0);
|
|
|
|
+
|
|
|
|
+ /* Check random works */
|
|
|
|
+ rv = crypto_rand_check_failure_mode_zero();
|
|
|
|
+ tt_assert(rv == 0);
|
|
|
|
+
|
|
|
|
+ rv = crypto_rand_check_failure_mode_identical();
|
|
|
|
+ tt_assert(rv == 0);
|
|
|
|
+
|
|
|
|
+ rv = crypto_rand_check_failure_mode_predict();
|
|
|
|
+ tt_assert(rv == 0);
|
|
|
|
+
|
|
|
|
+ done:
|
|
|
|
+ ;
|
|
|
|
+}
|
|
|
|
+
|
|
#define CRYPTO_LEGACY(name) \
|
|
#define CRYPTO_LEGACY(name) \
|
|
{ #name, test_crypto_ ## name , 0, NULL, NULL }
|
|
{ #name, test_crypto_ ## name , 0, NULL, NULL }
|
|
|
|
|
|
@@ -1841,6 +1945,7 @@ struct testcase_t crypto_tests[] = {
|
|
{ "ed25519_fuzz_donna", test_crypto_ed25519_fuzz_donna, TT_FORK, NULL,
|
|
{ "ed25519_fuzz_donna", test_crypto_ed25519_fuzz_donna, TT_FORK, NULL,
|
|
NULL },
|
|
NULL },
|
|
{ "siphash", test_crypto_siphash, 0, NULL, NULL },
|
|
{ "siphash", test_crypto_siphash, 0, NULL, NULL },
|
|
|
|
+ { "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL },
|
|
END_OF_TESTCASES
|
|
END_OF_TESTCASES
|
|
};
|
|
};
|
|
|
|
|