xref: /aosp_15_r20/external/boringssl/src/crypto/rand_extra/rand_test.cc (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1 /* Copyright (c) 2018, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/rand.h>
16 
17 #include <stdio.h>
18 
19 #include <gtest/gtest.h>
20 
21 #include <openssl/span.h>
22 
23 #include "../fipsmodule/rand/fork_detect.h"
24 #include "../fipsmodule/rand/internal.h"
25 #include "../test/abi_test.h"
26 #include "../test/test_util.h"
27 
28 #if defined(OPENSSL_THREADS)
29 #include <array>
30 #include <thread>
31 #include <vector>
32 #endif
33 
34 #if !defined(OPENSSL_WINDOWS)
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <unistd.h>
39 #endif
40 
41 
42 // These tests are, strictly speaking, flaky, but we use large enough buffers
43 // that the probability of failing when we should pass is negligible.
44 
TEST(RandTest,NotObviouslyBroken)45 TEST(RandTest, NotObviouslyBroken) {
46   static const uint8_t kZeros[256] = {0};
47 
48   uint8_t buf1[256], buf2[256];
49   RAND_bytes(buf1, sizeof(buf1));
50   RAND_bytes(buf2, sizeof(buf2));
51 
52   EXPECT_NE(Bytes(buf1), Bytes(buf2));
53   EXPECT_NE(Bytes(buf1), Bytes(kZeros));
54   EXPECT_NE(Bytes(buf2), Bytes(kZeros));
55 }
56 
57 #if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_IOS) && \
58     !defined(OPENSSL_FUCHSIA) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
ForkAndRand(bssl::Span<uint8_t> out,bool fork_unsafe_buffering)59 static bool ForkAndRand(bssl::Span<uint8_t> out, bool fork_unsafe_buffering) {
60   int pipefds[2];
61   if (pipe(pipefds) < 0) {
62     perror("pipe");
63     return false;
64   }
65 
66   // This is a multi-threaded process, but GTest does not run tests concurrently
67   // and there currently are no threads, so this should be safe.
68   pid_t child = fork();
69   if (child < 0) {
70     perror("fork");
71     close(pipefds[0]);
72     close(pipefds[1]);
73     return false;
74   }
75 
76   if (child == 0) {
77     // This is the child. Generate entropy and write it to the parent.
78     close(pipefds[0]);
79     if (fork_unsafe_buffering) {
80       RAND_enable_fork_unsafe_buffering(-1);
81     }
82     RAND_bytes(out.data(), out.size());
83     while (!out.empty()) {
84       ssize_t ret = write(pipefds[1], out.data(), out.size());
85       if (ret < 0) {
86         if (errno == EINTR) {
87           continue;
88         }
89         perror("write");
90         _exit(1);
91       }
92       out = out.subspan(static_cast<size_t>(ret));
93     }
94     _exit(0);
95   }
96 
97   // This is the parent. Read the entropy from the child.
98   close(pipefds[1]);
99   while (!out.empty()) {
100     ssize_t ret = read(pipefds[0], out.data(), out.size());
101     if (ret <= 0) {
102       if (ret == 0) {
103         fprintf(stderr, "Unexpected EOF from child.\n");
104       } else {
105         if (errno == EINTR) {
106           continue;
107         }
108         perror("read");
109       }
110       close(pipefds[0]);
111       return false;
112     }
113     out = out.subspan(static_cast<size_t>(ret));
114   }
115   close(pipefds[0]);
116 
117   // Wait for the child to exit.
118   int status;
119   if (waitpid(child, &status, 0) < 0) {
120     perror("waitpid");
121     return false;
122   }
123   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
124     fprintf(stderr, "Child did not exit cleanly.\n");
125     return false;
126   }
127 
128   return true;
129 }
130 
TEST(RandTest,Fork)131 TEST(RandTest, Fork) {
132   static const uint8_t kZeros[16] = {0};
133 
134   // Draw a little entropy to initialize any internal PRNG buffering.
135   uint8_t byte;
136   RAND_bytes(&byte, 1);
137 
138   // Draw entropy in two child processes and the parent process. This test
139   // intentionally uses smaller buffers than the others, to minimize the chance
140   // of sneaking by with a large enough buffer that we've since reseeded from
141   // the OS.
142   //
143   // All child processes should have different PRNGs, including the ones that
144   // disavow fork-safety. Although they are produced by fork, they themselves do
145   // not fork after that call.
146   uint8_t bufs[5][16];
147   ASSERT_TRUE(ForkAndRand(bufs[0], /*fork_unsafe_buffering=*/false));
148   ASSERT_TRUE(ForkAndRand(bufs[1], /*fork_unsafe_buffering=*/false));
149   ASSERT_TRUE(ForkAndRand(bufs[2], /*fork_unsafe_buffering=*/true));
150   ASSERT_TRUE(ForkAndRand(bufs[3], /*fork_unsafe_buffering=*/true));
151   RAND_bytes(bufs[4], sizeof(bufs[4]));
152 
153   // All should be different and non-zero.
154   for (const auto &buf : bufs) {
155     EXPECT_NE(Bytes(buf), Bytes(kZeros));
156   }
157   for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(bufs); i++) {
158     for (size_t j = 0; j < i; j++) {
159       EXPECT_NE(Bytes(bufs[i]), Bytes(bufs[j]))
160           << "buffers " << i << " and " << j << " matched";
161     }
162   }
163 }
164 #endif  // !OPENSSL_WINDOWS && !OPENSSL_IOS &&
165         // !OPENSSL_FUCHSIA && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE
166 
167 #if defined(OPENSSL_THREADS)
RunConcurrentRands(size_t num_threads)168 static void RunConcurrentRands(size_t num_threads) {
169   static const uint8_t kZeros[256] = {0};
170 
171   std::vector<std::array<uint8_t, 256>> bufs(num_threads);
172   std::vector<std::thread> threads(num_threads);
173 
174   for (size_t i = 0; i < num_threads; i++) {
175     threads[i] =
176         std::thread([i, &bufs] { RAND_bytes(bufs[i].data(), bufs[i].size()); });
177   }
178   for (size_t i = 0; i < num_threads; i++) {
179     threads[i].join();
180   }
181 
182   for (size_t i = 0; i < num_threads; i++) {
183     EXPECT_NE(Bytes(bufs[i]), Bytes(kZeros));
184     for (size_t j = i + 1; j < num_threads; j++) {
185       EXPECT_NE(Bytes(bufs[i]), Bytes(bufs[j]));
186     }
187   }
188 }
189 
190 // Test that threads may concurrently draw entropy without tripping TSan.
TEST(RandTest,Threads)191 TEST(RandTest, Threads) {
192   constexpr size_t kFewerThreads = 10;
193   constexpr size_t kMoreThreads = 20;
194 
195   // Draw entropy in parallel.
196   RunConcurrentRands(kFewerThreads);
197   // Draw entropy in parallel with higher concurrency than the previous maximum.
198   RunConcurrentRands(kMoreThreads);
199   // Draw entropy in parallel with lower concurrency than the previous maximum.
200   RunConcurrentRands(kFewerThreads);
201 }
202 #endif  // OPENSSL_THREADS
203 
204 #if defined(OPENSSL_X86_64) && defined(SUPPORTS_ABI_TEST)
TEST(RandTest,RdrandABI)205 TEST(RandTest, RdrandABI) {
206   if (!have_rdrand()) {
207     fprintf(stderr, "rdrand not supported. Skipping.\n");
208     return;
209   }
210 
211   uint8_t buf[32];
212   CHECK_ABI_SEH(CRYPTO_rdrand, buf);
213   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, nullptr, 0);
214   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 8);
215   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 16);
216   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 24);
217   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 32);
218 }
219 #endif  // OPENSSL_X86_64 && SUPPORTS_ABI_TEST
220