• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2020, 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/ctrdrbg.h>
16 
17 #include "../fipsmodule/rand/internal.h"
18 #include "../internal.h"
19 
20 #if defined(BORINGSSL_FIPS)
21 
22 #define ENTROPY_READ_LEN \
23   (/* last_block size */ 16 + CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD)
24 
25 #if defined(OPENSSL_ANDROID)
26 
27 #include <errno.h>
28 #include <stdatomic.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <sys/un.h>
32 #include <unistd.h>
33 
34 // socket_history_t enumerates whether the entropy daemon should be contacted
35 // for a given entropy request. Values other than socket_not_yet_attempted are
36 // sticky so if the first attempt to read from the daemon fails it's assumed
37 // that the daemon is not present and no more attempts will be made. If the
38 // first attempt is successful then attempts will be made forever more.
39 enum socket_history_t {
40   // initial value, no connections to the entropy daemon have been made yet.
41   socket_not_yet_attempted = 0,
42   // reading from the entropy daemon was successful
43   socket_success,
44   // reading from the entropy daemon failed.
45   socket_failed,
46 };
47 
48 static _Atomic enum socket_history_t g_socket_history =
49     socket_not_yet_attempted;
50 
51 // DAEMON_RESPONSE_LEN is the number of bytes that the entropy daemon replies
52 // with.
53 #define DAEMON_RESPONSE_LEN 496
54 
55 static_assert(ENTROPY_READ_LEN == DAEMON_RESPONSE_LEN,
56               "entropy daemon response length mismatch");
57 
get_seed_from_daemon(uint8_t * out_entropy,size_t out_entropy_len)58 static int get_seed_from_daemon(uint8_t *out_entropy, size_t out_entropy_len) {
59   // |RAND_need_entropy| should never call this function for more than
60   // |DAEMON_RESPONSE_LEN| bytes.
61   if (out_entropy_len > DAEMON_RESPONSE_LEN) {
62     abort();
63   }
64 
65   const enum socket_history_t socket_history = atomic_load(&g_socket_history);
66   if (socket_history == socket_failed) {
67     return 0;
68   }
69 
70   int ret = 0;
71   const int sock = socket(AF_UNIX, SOCK_STREAM, 0);
72   if (sock < 0) {
73     goto out;
74   }
75 
76   struct sockaddr_un sun;
77   memset(&sun, 0, sizeof(sun));
78   sun.sun_family = AF_UNIX;
79   static const char kSocketPath[] = "/dev/socket/prng_seeder";
80   static_assert(sizeof(kSocketPath) <= UNIX_PATH_MAX,
81                       "kSocketPath too long");
82   OPENSSL_memcpy(sun.sun_path, kSocketPath, sizeof(kSocketPath));
83 
84   if (connect(sock, (struct sockaddr *)&sun, sizeof(sun))) {
85     goto out;
86   }
87 
88   uint8_t buffer[DAEMON_RESPONSE_LEN];
89   size_t done = 0;
90   while (done < sizeof(buffer)) {
91     ssize_t n;
92     do {
93       n = read(sock, buffer + done, sizeof(buffer) - done);
94     } while (n == -1 && errno == EINTR);
95 
96     if (n < 1) {
97       goto out;
98     }
99     done += n;
100   }
101 
102   if (done != DAEMON_RESPONSE_LEN) {
103     // The daemon should always write |DAEMON_RESPONSE_LEN| bytes on every
104     // connection.
105     goto out;
106   }
107 
108   assert(out_entropy_len <= DAEMON_RESPONSE_LEN);
109   OPENSSL_memcpy(out_entropy, buffer, out_entropy_len);
110   ret = 1;
111 
112 out:
113   if (socket_history == socket_not_yet_attempted) {
114     enum socket_history_t expected = socket_history;
115     // If another thread has already updated |g_socket_history| then we defer
116     // to their value.
117     atomic_compare_exchange_strong(&g_socket_history, &expected,
118                                    (ret == 0) ? socket_failed : socket_success);
119   }
120 
121   close(sock);
122   return ret;
123 }
124 
125 #else
126 
get_seed_from_daemon(uint8_t * out_entropy,size_t out_entropy_len)127 static int get_seed_from_daemon(uint8_t *out_entropy, size_t out_entropy_len) {
128   return 0;
129 }
130 
131 #endif  // OPENSSL_ANDROID
132 
133 // RAND_need_entropy is called by the FIPS module when it has blocked because of
134 // a lack of entropy. This signal is used as an indication to feed it more.
RAND_need_entropy(size_t bytes_needed)135 void RAND_need_entropy(size_t bytes_needed) {
136   uint8_t buf[ENTROPY_READ_LEN];
137   size_t todo = sizeof(buf);
138   if (todo > bytes_needed) {
139     todo = bytes_needed;
140   }
141 
142   int want_additional_input;
143   if (get_seed_from_daemon(buf, todo)) {
144     want_additional_input = 1;
145   } else {
146     CRYPTO_get_seed_entropy(buf, todo, &want_additional_input);
147   }
148 
149   if (boringssl_fips_break_test("CRNG")) {
150     // This breaks the "continuous random number generator test" defined in FIPS
151     // 140-2, section 4.9.2, and implemented in |rand_get_seed|.
152     OPENSSL_memset(buf, 0, todo);
153   }
154 
155   RAND_load_entropy(buf, todo, want_additional_input);
156 }
157 
158 #endif  // FIPS
159