diff options
author | william <william@25tandclement.com> | 2014-04-19 10:55:01 -0700 |
---|---|---|
committer | william <william@25tandclement.com> | 2014-04-19 10:55:01 -0700 |
commit | c5351ea4c69ad43dbad6179760307d98eeddbb4f (patch) | |
tree | 10f1495673a742c6853ddf5a1b2656cf1dc92883 /src | |
parent | 657892416234797396bc0f3a6cf03614083009fc (diff) | |
download | luaossl-c5351ea4c69ad43dbad6179760307d98eeddbb4f.tar.gz luaossl-c5351ea4c69ad43dbad6179760307d98eeddbb4f.tar.bz2 luaossl-c5351ea4c69ad43dbad6179760307d98eeddbb4f.zip |
add rand.stir, which polls system entropy in the most robust way possible, because OpenSSL only knows how to use /dev/urandom
Diffstat (limited to 'src')
-rw-r--r-- | src/openssl.c | 227 |
1 files changed, 207 insertions, 20 deletions
diff --git a/src/openssl.c b/src/openssl.c index 432c683..967665f 100644 --- a/src/openssl.c +++ b/src/openssl.c | |||
@@ -26,23 +26,32 @@ | |||
26 | #ifndef LUAOSSL_H | 26 | #ifndef LUAOSSL_H |
27 | #define LUAOSSL_H | 27 | #define LUAOSSL_H |
28 | 28 | ||
29 | #include <limits.h> /* INT_MAX INT_MIN */ | 29 | #include <limits.h> /* INT_MAX INT_MIN */ |
30 | #include <string.h> /* memset(3) */ | 30 | #include <string.h> /* memset(3) strerror_r(3) */ |
31 | #include <strings.h> /* strcasecmp(3) */ | 31 | #include <strings.h> /* strcasecmp(3) */ |
32 | #include <math.h> /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ | 32 | #include <math.h> /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ |
33 | #include <time.h> /* struct tm time_t strptime(3) */ | 33 | #include <time.h> /* struct tm time_t strptime(3) */ |
34 | #include <ctype.h> /* tolower(3) */ | 34 | #include <ctype.h> /* tolower(3) */ |
35 | #include <errno.h> /* errno */ | ||
35 | 36 | ||
36 | #include <sys/types.h> | 37 | #include <sys/types.h> /* ssize_t pid_t */ |
37 | #include <sys/stat.h> /* struct stat stat(2) */ | 38 | #include <sys/sysctl.h> /* CTL_KERN KERN_RANDOM RANDOM_UUID KERN_URND KERN_ARND sysctl(2) */ |
38 | #include <sys/socket.h> /* AF_INET AF_INET6 */ | 39 | #include <sys/time.h> /* struct timeval gettimeofday(2) */ |
40 | #include <sys/stat.h> /* struct stat stat(2) */ | ||
41 | #include <sys/socket.h> /* AF_INET AF_INET6 */ | ||
42 | #include <sys/resource.h> /* RUSAGE_SELF struct rusage getrusage(2) */ | ||
43 | #include <sys/utsname.h> /* struct utsname uname(3) */ | ||
39 | 44 | ||
40 | #include <netinet/in.h> /* struct in_addr struct in6_addr */ | 45 | #include <fcntl.h> /* O_RDONLY O_CLOEXEC open(2) */ |
41 | #include <arpa/inet.h> /* inet_pton(3) */ | ||
42 | 46 | ||
43 | #include <pthread.h> /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */ | 47 | #include <unistd.h> /* close(2) getpid(2) */ |
44 | 48 | ||
45 | #include <dlfcn.h> /* dladdr(3) dlopen(3) */ | 49 | #include <netinet/in.h> /* struct in_addr struct in6_addr */ |
50 | #include <arpa/inet.h> /* inet_pton(3) */ | ||
51 | |||
52 | #include <pthread.h> /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */ | ||
53 | |||
54 | #include <dlfcn.h> /* dladdr(3) dlopen(3) */ | ||
46 | 55 | ||
47 | #include <openssl/err.h> | 56 | #include <openssl/err.h> |
48 | #include <openssl/bn.h> | 57 | #include <openssl/bn.h> |
@@ -107,6 +116,56 @@ | |||
107 | #define HAI SAY("hai") | 116 | #define HAI SAY("hai") |
108 | 117 | ||
109 | 118 | ||
119 | #define xitoa_putc(c) do { if (p < lim) dst[p] = (c); p++; } while (0) | ||
120 | |||
121 | static const char *xitoa(char *dst, size_t lim, long i) { | ||
122 | size_t p = 0; | ||
123 | unsigned long d = 1000000000UL, n = 0, r; | ||
124 | |||
125 | if (i < 0) { | ||
126 | xitoa_putc('-'); | ||
127 | i *= -1; | ||
128 | } | ||
129 | |||
130 | if ((i = MIN(2147483647L, i))) { | ||
131 | do { | ||
132 | if ((r = i / d) || n) { | ||
133 | i -= r * d; | ||
134 | n++; | ||
135 | xitoa_putc('0' + r); | ||
136 | } | ||
137 | } while (d /= 10); | ||
138 | } else { | ||
139 | xitoa_putc('0'); | ||
140 | } | ||
141 | |||
142 | if (lim) | ||
143 | dst[MIN(p, lim - 1)] = '\0'; | ||
144 | |||
145 | return dst; | ||
146 | } /* xitoa() */ | ||
147 | |||
148 | |||
149 | #define xstrerror(error) xstrerror_r((error), (char[256]){ 0 }, 256) | ||
150 | |||
151 | static const char *xstrerror_r(int error, char *dst, size_t lim) { | ||
152 | static const char unknown[] = "Unknown error: "; | ||
153 | size_t n; | ||
154 | |||
155 | if (0 == strerror_r(error, dst, lim) && *dst != '\0') | ||
156 | return dst; | ||
157 | |||
158 | /* | ||
159 | * glibc snprintf can fail on memory pressure, so format our number | ||
160 | * manually. | ||
161 | */ | ||
162 | n = MIN(sizeof unknown - 1, lim); | ||
163 | memcpy(dst, unknown, n); | ||
164 | |||
165 | return xitoa(&dst[n], lim - n, error); | ||
166 | } /* xstrerror_r() */ | ||
167 | |||
168 | |||
110 | static void *prepudata(lua_State *L, size_t size, const char *tname, int (*gc)(lua_State *)) { | 169 | static void *prepudata(lua_State *L, size_t size, const char *tname, int (*gc)(lua_State *)) { |
111 | void *p = memset(lua_newuserdata(L, size), 0, size); | 170 | void *p = memset(lua_newuserdata(L, size), 0, size); |
112 | 171 | ||
@@ -3017,7 +3076,7 @@ static int xs_add(lua_State *L) { | |||
3017 | int ok; | 3076 | int ok; |
3018 | 3077 | ||
3019 | if (0 != stat(path, &st)) | 3078 | if (0 != stat(path, &st)) |
3020 | return luaL_error(L, "%s: %s", path, strerror(errno)); | 3079 | return luaL_error(L, "%s: %s", path, xstrerror(errno)); |
3021 | 3080 | ||
3022 | if (S_ISDIR(st.st_mode)) | 3081 | if (S_ISDIR(st.st_mode)) |
3023 | ok = X509_STORE_load_locations(store, NULL, path); | 3082 | ok = X509_STORE_load_locations(store, NULL, path); |
@@ -3919,6 +3978,137 @@ int luaopen__openssl_cipher(lua_State *L) { | |||
3919 | * | 3978 | * |
3920 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 3979 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
3921 | 3980 | ||
3981 | #ifndef HAVE_RANDOM_UUID | ||
3982 | #define HAVE_RANDOM_UUID (defined __linux) /* RANDOM_UUID is an enum, not macro */ | ||
3983 | #endif | ||
3984 | |||
3985 | #ifndef HAVE_KERN_URND | ||
3986 | #define HAVE_KERN_URND (defined KERN_URND) | ||
3987 | #endif | ||
3988 | |||
3989 | #ifndef HAVE_KERN_ARND | ||
3990 | #define HAVE_KERN_ARND (defined KERN_ARND) | ||
3991 | #endif | ||
3992 | |||
3993 | static int stir(unsigned rqstd) { | ||
3994 | unsigned count = 0; | ||
3995 | int error; | ||
3996 | unsigned char data[256]; | ||
3997 | #if HAVE_RANDOM_UUID || HAVE_KERN_URND || HAVE_KERN_ARND | ||
3998 | #if HAVE_RANDOM_UUID | ||
3999 | int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID }; | ||
4000 | #elif HAVE_KERN_URND | ||
4001 | int mib[] = { CTL_KERN, KERN_URND }; | ||
4002 | #else | ||
4003 | int mib[] = { CTL_KERN, KERN_ARND }; | ||
4004 | #endif | ||
4005 | |||
4006 | while (count < rqstd) { | ||
4007 | size_t n = MIN(rqstd - count, sizeof data); | ||
4008 | |||
4009 | if (0 != sysctl(mib, countof(mib), data, &n, (void *)0, 0)) | ||
4010 | break; | ||
4011 | |||
4012 | RAND_add(data, n, n); | ||
4013 | |||
4014 | count += n; | ||
4015 | } | ||
4016 | #endif | ||
4017 | |||
4018 | if (count < rqstd) { | ||
4019 | #if defined O_CLOEXEC | ||
4020 | int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); | ||
4021 | #else | ||
4022 | int fd = open("/dev/urandom", O_RDONLY); | ||
4023 | #endif | ||
4024 | |||
4025 | if (fd == -1) | ||
4026 | goto syserr; | ||
4027 | |||
4028 | while (count < rqstd) { | ||
4029 | ssize_t n = read(fd, data, MIN(rqstd - count, sizeof data)); | ||
4030 | |||
4031 | switch (n) { | ||
4032 | case 0: | ||
4033 | errno = EIO; | ||
4034 | |||
4035 | /* FALL THROUGH */ | ||
4036 | case -1: | ||
4037 | if (errno == EINTR) | ||
4038 | continue; | ||
4039 | |||
4040 | error = errno; | ||
4041 | |||
4042 | close(fd); | ||
4043 | |||
4044 | goto error; | ||
4045 | default: | ||
4046 | RAND_add(data, n, n); | ||
4047 | |||
4048 | count += n; | ||
4049 | } | ||
4050 | } | ||
4051 | |||
4052 | close(fd); | ||
4053 | } | ||
4054 | |||
4055 | return 0; | ||
4056 | syserr: | ||
4057 | error = errno; | ||
4058 | error:; | ||
4059 | struct { | ||
4060 | struct timeval tv; | ||
4061 | pid_t pid; | ||
4062 | struct rusage ru; | ||
4063 | struct utsname un; | ||
4064 | int (*fn)(); | ||
4065 | } junk; | ||
4066 | |||
4067 | gettimeofday(&junk.tv, NULL); | ||
4068 | junk.pid = getpid(); | ||
4069 | getrusage(RUSAGE_SELF, &junk.ru); | ||
4070 | uname(&junk.un); | ||
4071 | junk.fn = &stir; | ||
4072 | |||
4073 | RAND_add(&junk, sizeof junk, 0.1); | ||
4074 | |||
4075 | return error; | ||
4076 | } /* stir() */ | ||
4077 | |||
4078 | |||
4079 | static int rand_stir(lua_State *L) { | ||
4080 | int error = stir(luaL_optunsigned(L, 1, 16)); | ||
4081 | |||
4082 | if (error) { | ||
4083 | lua_pushboolean(L, 0); | ||
4084 | lua_pushstring(L, xstrerror(error)); | ||
4085 | lua_pushinteger(L, error); | ||
4086 | |||
4087 | return 3; | ||
4088 | } else { | ||
4089 | lua_pushboolean(L, 1); | ||
4090 | |||
4091 | return 1; | ||
4092 | } | ||
4093 | } /* rand_stir() */ | ||
4094 | |||
4095 | |||
4096 | static int rand_add(lua_State *L) { | ||
4097 | const void *buf; | ||
4098 | size_t len; | ||
4099 | lua_Number entropy; | ||
4100 | |||
4101 | buf = luaL_checklstring(L, 1, &len); | ||
4102 | entropy = luaL_optnumber(L, 2, len); | ||
4103 | |||
4104 | RAND_add(buf, len, entropy); | ||
4105 | |||
4106 | lua_pushboolean(L, 1); | ||
4107 | |||
4108 | return 1; | ||
4109 | } /* rand_add() */ | ||
4110 | |||
4111 | |||
3922 | static int rand_bytes(lua_State *L) { | 4112 | static int rand_bytes(lua_State *L) { |
3923 | int size = luaL_checkint(L, 1); | 4113 | int size = luaL_checkint(L, 1); |
3924 | luaL_Buffer B; | 4114 | luaL_Buffer B; |
@@ -4060,6 +4250,8 @@ static int rand_uniform(lua_State *L) { | |||
4060 | 4250 | ||
4061 | 4251 | ||
4062 | static const luaL_Reg rand_globals[] = { | 4252 | static const luaL_Reg rand_globals[] = { |
4253 | { "stir", &rand_stir }, | ||
4254 | { "add", &rand_add }, | ||
4063 | { "bytes", &rand_bytes }, | 4255 | { "bytes", &rand_bytes }, |
4064 | { "ready", &rand_ready }, | 4256 | { "ready", &rand_ready }, |
4065 | { "uniform", &rand_uniform }, | 4257 | { "uniform", &rand_uniform }, |
@@ -4194,12 +4386,7 @@ static void initall(lua_State *L) { | |||
4194 | if (error == -1) { | 4386 | if (error == -1) { |
4195 | luaL_error(L, "openssl.init: %s", dlerror()); | 4387 | luaL_error(L, "openssl.init: %s", dlerror()); |
4196 | } else { | 4388 | } else { |
4197 | char why[256]; | 4389 | luaL_error(L, "openssl.init: %s", xstrerror(error)); |
4198 | |||
4199 | if (0 != strerror_r(error, why, sizeof why) || *why == '\0') | ||
4200 | luaL_error(L, "openssl.init: Unknown error: %d", error); | ||
4201 | |||
4202 | luaL_error(L, "openssl.init: %s", why); | ||
4203 | } | 4390 | } |
4204 | } | 4391 | } |
4205 | 4392 | ||