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 | ||
