• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/cpu.h>
22 #include <openssl/span.h>
23 
24 #include "../fipsmodule/rand/fork_detect.h"
25 #include "../fipsmodule/rand/internal.h"
26 #include "../test/abi_test.h"
27 #include "../test/test_util.h"
28 
29 #if defined(OPENSSL_THREADS)
30 #include <array>
31 #include <thread>
32 #include <vector>
33 #endif
34 
35 #if !defined(OPENSSL_WINDOWS)
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
40 #endif
41 
42 
43 // These tests are, strictly speaking, flaky, but we use large enough buffers
44 // that the probability of failing when we should pass is negligible.
45 
TEST(RandTest,NotObviouslyBroken)46 TEST(RandTest, NotObviouslyBroken) {
47   static const uint8_t kZeros[256] = {0};
48 
49   uint8_t buf1[256], buf2[256];
50   RAND_bytes(buf1, sizeof(buf1));
51   RAND_bytes(buf2, sizeof(buf2));
52 
53   EXPECT_NE(Bytes(buf1), Bytes(buf2));
54   EXPECT_NE(Bytes(buf1), Bytes(kZeros));
55   EXPECT_NE(Bytes(buf2), Bytes(kZeros));
56 }
57 
58 #if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_IOS) && \
59     !defined(OPENSSL_FUCHSIA) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
ForkAndRand(bssl::Span<uint8_t> out)60 static bool ForkAndRand(bssl::Span<uint8_t> out) {
61   int pipefds[2];
62   if (pipe(pipefds) < 0) {
63     perror("pipe");
64     return false;
65   }
66 
67   // This is a multi-threaded process, but GTest does not run tests concurrently
68   // and there currently are no threads, so this should be safe.
69   pid_t child = fork();
70   if (child < 0) {
71     perror("fork");
72     close(pipefds[0]);
73     close(pipefds[1]);
74     return false;
75   }
76 
77   if (child == 0) {
78     // This is the child. Generate entropy and write it to the parent.
79     close(pipefds[0]);
80     RAND_bytes(out.data(), out.size());
81     while (!out.empty()) {
82       ssize_t ret = write(pipefds[1], out.data(), out.size());
83       if (ret < 0) {
84         if (errno == EINTR) {
85           continue;
86         }
87         perror("write");
88         _exit(1);
89       }
90       out = out.subspan(static_cast<size_t>(ret));
91     }
92     _exit(0);
93   }
94 
95   // This is the parent. Read the entropy from the child.
96   close(pipefds[1]);
97   while (!out.empty()) {
98     ssize_t ret = read(pipefds[0], out.data(), out.size());
99     if (ret <= 0) {
100       if (ret == 0) {
101         fprintf(stderr, "Unexpected EOF from child.\n");
102       } else {
103         if (errno == EINTR) {
104           continue;
105         }
106         perror("read");
107       }
108       close(pipefds[0]);
109       return false;
110     }
111     out = out.subspan(static_cast<size_t>(ret));
112   }
113   close(pipefds[0]);
114 
115   // Wait for the child to exit.
116   int status;
117   if (waitpid(child, &status, 0) < 0) {
118     perror("waitpid");
119     return false;
120   }
121   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
122     fprintf(stderr, "Child did not exit cleanly.\n");
123     return false;
124   }
125 
126   return true;
127 }
128 
TEST(RandTest,Fork)129 TEST(RandTest, Fork) {
130   static const uint8_t kZeros[16] = {0};
131 
132   // Draw a little entropy to initialize any internal PRNG buffering.
133   uint8_t byte;
134   RAND_bytes(&byte, 1);
135 
136   // Draw entropy in two child processes and the parent process. This test
137   // intentionally uses smaller buffers than the others, to minimize the chance
138   // of sneaking by with a large enough buffer that we've since reseeded from
139   // the OS.
140   uint8_t buf1[16], buf2[16], buf3[16];
141   ASSERT_TRUE(ForkAndRand(buf1));
142   ASSERT_TRUE(ForkAndRand(buf2));
143   RAND_bytes(buf3, sizeof(buf3));
144 
145   // All should be different.
146   EXPECT_NE(Bytes(buf1), Bytes(buf2));
147   EXPECT_NE(Bytes(buf2), Bytes(buf3));
148   EXPECT_NE(Bytes(buf1), Bytes(buf3));
149   EXPECT_NE(Bytes(buf1), Bytes(kZeros));
150   EXPECT_NE(Bytes(buf2), Bytes(kZeros));
151   EXPECT_NE(Bytes(buf3), Bytes(kZeros));
152 }
153 #endif  // !OPENSSL_WINDOWS && !OPENSSL_IOS &&
154         // !OPENSSL_FUCHSIA && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE
155 
156 #if defined(OPENSSL_THREADS)
RunConcurrentRands(size_t num_threads)157 static void RunConcurrentRands(size_t num_threads) {
158   static const uint8_t kZeros[256] = {0};
159 
160   std::vector<std::array<uint8_t, 256>> bufs(num_threads);
161   std::vector<std::thread> threads(num_threads);
162 
163   for (size_t i = 0; i < num_threads; i++) {
164     threads[i] =
165         std::thread([i, &bufs] { RAND_bytes(bufs[i].data(), bufs[i].size()); });
166   }
167   for (size_t i = 0; i < num_threads; i++) {
168     threads[i].join();
169   }
170 
171   for (size_t i = 0; i < num_threads; i++) {
172     EXPECT_NE(Bytes(bufs[i]), Bytes(kZeros));
173     for (size_t j = i + 1; j < num_threads; j++) {
174       EXPECT_NE(Bytes(bufs[i]), Bytes(bufs[j]));
175     }
176   }
177 }
178 
179 // Test that threads may concurrently draw entropy without tripping TSan.
TEST(RandTest,Threads)180 TEST(RandTest, Threads) {
181   constexpr size_t kFewerThreads = 10;
182   constexpr size_t kMoreThreads = 20;
183 
184   // Draw entropy in parallel.
185   RunConcurrentRands(kFewerThreads);
186   // Draw entropy in parallel with higher concurrency than the previous maximum.
187   RunConcurrentRands(kMoreThreads);
188   // Draw entropy in parallel with lower concurrency than the previous maximum.
189   RunConcurrentRands(kFewerThreads);
190 }
191 #endif  // OPENSSL_THREADS
192 
193 #if defined(OPENSSL_X86_64) && defined(SUPPORTS_ABI_TEST)
TEST(RandTest,RdrandABI)194 TEST(RandTest, RdrandABI) {
195   if (!have_rdrand()) {
196     fprintf(stderr, "rdrand not supported. Skipping.\n");
197     return;
198   }
199 
200   uint8_t buf[32];
201   CHECK_ABI_SEH(CRYPTO_rdrand, buf);
202   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, nullptr, 0);
203   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 8);
204   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 16);
205   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 24);
206   CHECK_ABI_SEH(CRYPTO_rdrand_multiple8_buf, buf, 32);
207 }
208 #endif  // OPENSSL_X86_64 && SUPPORTS_ABI_TEST
209