1 /* Retrieval of cryptographically random bytes from the operating system.
2 *
3 * Written by Zack Weinberg <zackw at panix.com> in 2017.
4 *
5 * No copyright is claimed, and the software is hereby placed in the public
6 * domain. In case this attempt to disclaim copyright and place the software
7 * in the public domain is deemed null and void, then the software is
8 * Copyright (c) 2017 Zack Weinberg and it is hereby released to the
9 * general public under the following terms:
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted.
13 *
14 * There's ABSOLUTELY NO WARRANTY, express or implied.
15 */
16
17 #include "crypt-port.h"
18
19 #include <errno.h>
20 #include <stdlib.h>
21
22 #ifdef HAVE_FCNTL_H
23 #include <fcntl.h>
24 #endif
25 #ifdef HAVE_SYS_RANDOM_H
26 #include <sys/random.h>
27 #endif
28 #ifdef HAVE_SYS_SYSCALL_H
29 #include <sys/syscall.h>
30 #endif
31 #ifdef HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34
35 /* If we have O_CLOEXEC, we use it, but if we don't, we don't worry
36 about it. */
37 #ifndef O_CLOEXEC
38 #define O_CLOEXEC 0
39 #endif
40
41 /* There is no universally portable way to access a system CSPRNG.
42 If the C library provides any of the following functions, we try them,
43 in order of preference: arc4random_buf, getentropy, getrandom.
44 If none of those are available or they don't work, we attempt to
45 make direct system calls for getentropy and getrandom. If *that*
46 doesn't work, we try opening and reading /dev/urandom.
47
48 This function returns true if the exact number of requested bytes
49 was successfully read, false otherwise; if it returns false, errno
50 has been set. It may block. It cannot be used to read more than
51 256 bytes at a time (this is a limitation inherited from
52 getentropy() and enforced regardless of the actual back-end in use).
53
54 If we fall all the way back to /dev/urandom, we open and close it on
55 each call. */
56
57 bool
58 get_random_bytes(void *buf, size_t buflen)
59 {
60 if (buflen == 0)
61 return true;
62
63 /* Some, but not all, of the primitives below are limited to
64 producing no more than 256 bytes of random data. Impose this
65 constraint on our callers regardless of which primitive is
66 actually used. */
67 if (buflen > 256)
68 {
69 errno = EIO;
70 return false;
71 }
72
73 /* To eliminate the possibility of one of the primitives below failing
74 with EFAULT, force a crash now if the buffer is unwritable. */
75 explicit_bzero (buf, buflen);
76
77 #ifdef HAVE_ARC4RANDOM_BUF
78 /* arc4random_buf, if it exists, can never fail. */
79 arc4random_buf (buf, buflen);
80 return true;
81
82 #else /* no arc4random_buf */
83
84 #ifdef HAVE_GETENTROPY
85 /* getentropy may exist but lack kernel support. */
86 static bool getentropy_doesnt_work;
87 if (!getentropy_doesnt_work)
88 {
89 if (!getentropy (buf, buflen))
90 return true;
91 getentropy_doesnt_work = true;
92 }
93 #endif
94
95 #ifdef HAVE_GETRANDOM
96 /* Likewise getrandom. */
97 static bool getrandom_doesnt_work;
98 if (!getrandom_doesnt_work)
99 {
100 if ((size_t)getrandom (buf, buflen, 0) == buflen)
101 return true;
102 getrandom_doesnt_work = true;
103 }
104 #endif
105
106 /* If we can make arbitrary syscalls, try getentropy and getrandom
107 again that way. */
108 #ifdef HAVE_SYSCALL
109 #ifdef SYS_getentropy
110 static bool sys_getentropy_doesnt_work;
111 if (!sys_getentropy_doesnt_work)
112 {
113 if (!syscall (SYS_getentropy, buf, buflen))
114 return true;
115 sys_getentropy_doesnt_work = true;
116 }
117 #endif
118
119 #ifdef SYS_getrandom
120 static bool sys_getrandom_doesnt_work;
121 if (!sys_getrandom_doesnt_work)
122 {
123 if ((size_t)syscall (SYS_getrandom, buf, buflen, 0) == buflen)
124 return true;
125 sys_getrandom_doesnt_work = true;
126 }
127 #endif
128 #endif
129
130 #if defined HAVE_SYS_STAT_H && defined HAVE_FCNTL_H && defined HAVE_UNISTD_H
131 /* Try reading from /dev/urandom. */
132 static bool dev_urandom_doesnt_work;
133 if (!dev_urandom_doesnt_work)
134 {
135 int fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC);
136 if (fd == -1)
137 dev_urandom_doesnt_work = true;
138 else
139 {
140 ssize_t nread = read (fd, buf, buflen);
141 if (nread < 0 || (size_t)nread < buflen)
142 dev_urandom_doesnt_work = true;
143
144 close(fd);
145 return !dev_urandom_doesnt_work;
146 }
147 }
148 #endif
149 #endif /* no arc4random_buf */
150
151 /* if we get here, we're just completely hosed */
152 errno = ENOSYS;
153 return false;
154 }