1*4724848cSchristos /*
2*4724848cSchristos * Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved.
3*4724848cSchristos *
4*4724848cSchristos * Licensed under the OpenSSL license (the "License"). You may not use
5*4724848cSchristos * this file except in compliance with the License. You can obtain a copy
6*4724848cSchristos * in the file LICENSE in the source distribution or at
7*4724848cSchristos * https://www.openssl.org/source/license.html
8*4724848cSchristos */
9*4724848cSchristos
10*4724848cSchristos #include <stdio.h>
11*4724848cSchristos #include <stdlib.h>
12*4724848cSchristos #include <string.h>
13*4724848cSchristos #include "testutil.h"
14*4724848cSchristos #include <openssl/opensslconf.h>
15*4724848cSchristos
16*4724848cSchristos #if (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
17*4724848cSchristos defined(__x86_64) || defined(__x86_64__) || \
18*4724848cSchristos defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ)
19*4724848cSchristos
20*4724848cSchristos size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len);
21*4724848cSchristos size_t OPENSSL_ia32_rdseed_bytes(unsigned char *buf, size_t len);
22*4724848cSchristos
23*4724848cSchristos void OPENSSL_cpuid_setup(void);
24*4724848cSchristos
25*4724848cSchristos extern unsigned int OPENSSL_ia32cap_P[4];
26*4724848cSchristos
sanity_check_bytes(size_t (* rng)(unsigned char *,size_t),int rounds,int min_failures,int max_retries,int max_zero_words)27*4724848cSchristos static int sanity_check_bytes(size_t (*rng)(unsigned char *, size_t),
28*4724848cSchristos int rounds, int min_failures, int max_retries, int max_zero_words)
29*4724848cSchristos {
30*4724848cSchristos int testresult = 0;
31*4724848cSchristos unsigned char prior[31] = {0}, buf[31] = {0}, check[7];
32*4724848cSchristos int failures = 0, zero_words = 0;
33*4724848cSchristos
34*4724848cSchristos int i;
35*4724848cSchristos for (i = 0; i < rounds; i++) {
36*4724848cSchristos size_t generated = 0;
37*4724848cSchristos
38*4724848cSchristos int retry;
39*4724848cSchristos for (retry = 0; retry < max_retries; retry++) {
40*4724848cSchristos generated = rng(buf, sizeof(buf));
41*4724848cSchristos if (generated == sizeof(buf))
42*4724848cSchristos break;
43*4724848cSchristos failures++;
44*4724848cSchristos }
45*4724848cSchristos
46*4724848cSchristos /*-
47*4724848cSchristos * Verify that we don't have too many unexpected runs of zeroes,
48*4724848cSchristos * implying that we might be accidentally using the 32-bit RDRAND
49*4724848cSchristos * instead of the 64-bit one on 64-bit systems.
50*4724848cSchristos */
51*4724848cSchristos size_t j;
52*4724848cSchristos for (j = 0; j < sizeof(buf) - 1; j++) {
53*4724848cSchristos if (buf[j] == 0 && buf[j+1] == 0) {
54*4724848cSchristos zero_words++;
55*4724848cSchristos }
56*4724848cSchristos }
57*4724848cSchristos
58*4724848cSchristos if (!TEST_int_eq(generated, sizeof(buf)))
59*4724848cSchristos goto end;
60*4724848cSchristos if (!TEST_false(!memcmp(prior, buf, sizeof(buf))))
61*4724848cSchristos goto end;
62*4724848cSchristos
63*4724848cSchristos /* Verify that the last 7 bytes of buf aren't all the same value */
64*4724848cSchristos unsigned char *tail = &buf[sizeof(buf) - sizeof(check)];
65*4724848cSchristos memset(check, tail[0], 7);
66*4724848cSchristos if (!TEST_false(!memcmp(check, tail, sizeof(check))))
67*4724848cSchristos goto end;
68*4724848cSchristos
69*4724848cSchristos /* Save the result and make sure it's different next time */
70*4724848cSchristos memcpy(prior, buf, sizeof(buf));
71*4724848cSchristos }
72*4724848cSchristos
73*4724848cSchristos if (!TEST_int_le(zero_words, max_zero_words))
74*4724848cSchristos goto end;
75*4724848cSchristos
76*4724848cSchristos if (!TEST_int_ge(failures, min_failures))
77*4724848cSchristos goto end;
78*4724848cSchristos
79*4724848cSchristos testresult = 1;
80*4724848cSchristos end:
81*4724848cSchristos return testresult;
82*4724848cSchristos }
83*4724848cSchristos
sanity_check_rdrand_bytes(void)84*4724848cSchristos static int sanity_check_rdrand_bytes(void)
85*4724848cSchristos {
86*4724848cSchristos return sanity_check_bytes(OPENSSL_ia32_rdrand_bytes, 1000, 0, 10, 10);
87*4724848cSchristos }
88*4724848cSchristos
sanity_check_rdseed_bytes(void)89*4724848cSchristos static int sanity_check_rdseed_bytes(void)
90*4724848cSchristos {
91*4724848cSchristos /*-
92*4724848cSchristos * RDSEED may take many retries to succeed; note that this is effectively
93*4724848cSchristos * multiplied by the 8x retry loop in asm, and failure probabilities are
94*4724848cSchristos * increased by the fact that we need either 4 or 8 samples depending on
95*4724848cSchristos * the platform.
96*4724848cSchristos */
97*4724848cSchristos return sanity_check_bytes(OPENSSL_ia32_rdseed_bytes, 1000, 1, 10000, 10);
98*4724848cSchristos }
99*4724848cSchristos
setup_tests(void)100*4724848cSchristos int setup_tests(void)
101*4724848cSchristos {
102*4724848cSchristos OPENSSL_cpuid_setup();
103*4724848cSchristos
104*4724848cSchristos int have_rdseed = (OPENSSL_ia32cap_P[2] & (1 << 18)) != 0;
105*4724848cSchristos int have_rdrand = (OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0;
106*4724848cSchristos
107*4724848cSchristos if (have_rdrand) {
108*4724848cSchristos ADD_TEST(sanity_check_rdrand_bytes);
109*4724848cSchristos }
110*4724848cSchristos
111*4724848cSchristos if (have_rdseed) {
112*4724848cSchristos ADD_TEST(sanity_check_rdseed_bytes);
113*4724848cSchristos }
114*4724848cSchristos
115*4724848cSchristos return 1;
116*4724848cSchristos }
117*4724848cSchristos
118*4724848cSchristos
119*4724848cSchristos #else
120*4724848cSchristos
setup_tests(void)121*4724848cSchristos int setup_tests(void)
122*4724848cSchristos {
123*4724848cSchristos return 1;
124*4724848cSchristos }
125*4724848cSchristos
126*4724848cSchristos #endif
127