From c191551c53211db38976183b821f2df12a0f3b7c Mon Sep 17 00:00:00 2001 From: william Date: Mon, 9 Mar 2015 10:15:49 -0700 Subject: early external data API work --- src/openssl.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 3 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index c1b5436..4e0b898 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -87,6 +87,10 @@ #define HAVE_SSL_CTX_SET_ALPN_PROTOS (OPENSSL_VERSION_NUMBER >= 0x1000200fL) #endif +#ifndef HAVE_SSL_CTX_SET_ALPN_SELECT_CB +#define HAVE_SSL_CTX_SET_ALPN_SELECT_CB HAVE_SSL_CTX_SET_ALPN_PROTOS +#endif + #ifndef HAVE_SSL_SET_ALPN_PROTOS #define HAVE_SSL_SET_ALPN_PROTOS HAVE_SSL_CTX_SET_ALPN_PROTOS #endif @@ -99,6 +103,25 @@ #define STRERROR_R_CHAR_P (defined __GLIBC__ && (_GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600))) #endif +#ifndef LIST_HEAD +#define LIST_HEAD(name, type) struct name { struct type *lh_first; } +#define LIST_ENTRY(type) struct { struct type *le_next, **le_prev; } +#define LIST_INIT(head) do { LIST_FIRST((head)) = NULL; } while (0) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) +#define LIST_INSERT_HEAD(head, elm, field) do { + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) +#endif + #define BIGNUM_CLASS "BIGNUM*" #define PKEY_CLASS "EVP_PKEY*" #define X509_NAME_CLASS "X509_NAME*" @@ -581,6 +604,173 @@ static void *compat_EVP_PKEY_get0(EVP_PKEY *key) { #endif +struct ex_state { + lua_State *mainthread; + LIST_HEAD(, ex_data) data; +}; /* struct ex_state */ + +struct ex_data { + struct ex_state *state; + int refs; + int arg[4]; + LIST_ENTRY(ex_data) le; +}; /* struct ex_data */ + +enum { + EX_SSL_CTX_ALPN_SELECT_CB, +}; + +static struct ex_type { + int class_index; + int index; + void *(*get_ex_data)(); + int (*set_ex_data)(); +} ex_type[] = { + [EX_SSL_CTX_ALPN_SELECT_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, +}; + +static int ex_data_dup(CRYPTO_EX_DATA *to NOTUSED, CRYPTO_EX_DATA *from NOTUSED, void *from_d, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { + struct ex_data **data = from_d; + + if (*data) + (*data)->refs++; + + return 1; +} /* ex_data_dup() */ + +static void ex_data_free(void *parent NOTUSED, void *_data, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { + struct ex_data *data = _data; + + if (!data || --data->refs > 0) + return; + + if (data->state) + LIST_REMOVE(data, le); + + free(data); +} /* ex_data_free() */ + +static int ex_initonce(void) { + struct ex_type *type; + + for (type = ex_type; type < endof(ex_type); type++) { + if (-1 == (type->index = CRYPTO_get_ex_new_index(type->class_index, 0, NULL, NULL, &ex_data_dup, &ex_data_free))) + return -1; + }; + + return 0; +} /* ex_initonce() */ + +static int ex__gc(lua_State *L) { + struct ex_state *state = lua_touserdata(L, 1); + struct ex_data *data; + + if (!state) + return 0; + + /* invalidate back references to Lua state */ + for (data = LIST_FIRST(&state->data); data; data = LIST_NEXT(data, le)) { + data->state = NULL; + } + + return 0; +} /* ex__gc() */ + +static void ex_init(lua_State *L) { + struct ex_state *state; + struct lua_State *thr; + + state = prepudata(L, sizeof *state, NULL, &ex__gc); + LIST_INIT(&state->data); + +#if defined LUA_RIDX_MAINTHREAD + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); + state->mainthread = lua_tothread(L, -1); + lua_pop(L, 1); +#else + lua_pushvalue(L, -1); + thr = lua_newthread(L); + lua_settable(L, LUA_REGISTRYINDEX); + state->mainthread = thr; +#endif + + lua_pushcfunction(L, &ex__gc); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + + lua_pop(L, 1); +} /* ex_init() */ + +static struct ex_state *ex_get(lua_State *L) { + struct ex_state *state; + + lua_pushcfunction(L, &ex__gc); + lua_gettable(L, LUA_REGISTRYINDEX); + + luaL_checktype(L, -1, LUA_TUSERDATA); + state = lua_touserdata(L, -1); + lua_pop(L, 1); + + return state; +} /* ex_get() */ + +static int ex_data_get(lua_State **L, int _type, void *obj) { + struct ex_type *type = &ex_type[_type]; + struct ex_data *data; + int i; + + if (!(data = type->get_ex_data(obj, type->index))) + return 0; + if (!data->state) + return 0; + + if (!*L) + *L = data->state->mainthread; + + for (i = 0; i < (int)countof(data->arg); i++) { + lua_rawgeti(*L, LUA_REGISTRYINDEX, data->arg[i]); + } + + return i; +} /* ex_data_get() */ + +static int ex_data_set(lua_State *L, int _type, void *obj, int n) { + struct ex_type *type = &ex_type[_type]; + struct ex_state *state; + struct ex_data *data; + int i, j; + + if ((data = type->get_ex_data(obj, type->index)) && data->state) { + for (i = 0; i < (int)countof(data->arg); i++) { + luaL_unref(L, LUA_REGISTRYINDEX, data->arg[i]); + data->arg[i] = LUA_NOREF; + } + } else { + state = ex_get(L); + + if (!(data = malloc(sizeof *data))) + return errno; + + if (!type->set_ex_data(obj, type->index, data)) + return -1; + + data->state = state; + data->refs = 1; + for (i = 0; i < (int)countof(data->arg); i++) + data->arg[i] = LUA_NOREF; + LIST_INSERT_HEAD(&state->data, data, le); + } + + for (i = n, j = 0; i > 0 && j < (int)countof(data->arg); i--, j++) { + lua_pushvalue(L, -i); + data->arg[j] = luaL_ref(L, LUA_REGISTRYINDEX); + } + + lua_pop(L, n); + + return 0; +} /* ex_data_set() */ + static void initall(lua_State *L); @@ -4609,6 +4799,32 @@ static int sx_setAlpnProtos(lua_State *L) { } /* sx_setAlpnProtos() */ #endif +#if HAVE_SSL_CTX_SET_ALPN_SELECT_CB +static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { + lua_State *L = NULL; + int n; + + n = ex_data_get(&L, EX_SSL_CTX_ALPN_SELECT_CB, ssl); + + return 0; +} /* sx_setAlpnSelect_cb() */ + +static int sx_setAlpnSelect(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + struct ex_data *data; + int error; + + luaL_checktype(L, 2, LUA_TFUNCTION); + error = ex_data_set(L, EX_SSL_CTX_ALPN_SELECT_CB, ctx, 1); + + SSL_CTX_set_alpn_select_cb(ctx, &sx_setAlpnSelect_cb, NULL); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setAlpnSelect() */ +#endif + static int sx__gc(lua_State *L) { SSL_CTX **ud = luaL_checkudata(L, 1, SSL_CTX_CLASS); @@ -5803,7 +6019,7 @@ int luaopen__openssl_des(lua_State *L) { * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE_DLADDR -#define HAVE_DLADDR (!defined _AIX) +#define HAVE_DLADDR (!defined _AIX) /* TODO: https://root.cern.ch/drupal/content/aix-and-dladdr */ #endif static struct { @@ -5847,8 +6063,8 @@ static unsigned long mt_gettid(void) { return _lwp_self(); #else /* - * pthread_t is an integer on Solaris and Linux, and a unique pointer - * on OpenBSD. + * pthread_t is an integer on Solaris and Linux, an unsigned integer + * on AIX, and a unique pointer on OpenBSD. */ return (unsigned long)pthread_self(); #endif @@ -5940,10 +6156,20 @@ static void initall(lua_State *L) { * already been configured. */ OPENSSL_config(NULL); + + if ((error = ex_initonce())) { + if (error == -1) { + throwssl(L, "openssl.init"); + } else { + luaL_error(L, "openssl.init: %s", xstrerror(error)); + } + } } pthread_mutex_unlock(&mutex); + ex_init(L); + addclass(L, BIGNUM_CLASS, bn_methods, bn_metatable); addclass(L, PKEY_CLASS, pk_methods, pk_metatable); addclass(L, X509_NAME_CLASS, xn_methods, xn_metatable); -- cgit v1.2.3-59-g8ed1b From 55da052192e151ee055e62a378d6ebdbdcbe5087 Mon Sep 17 00:00:00 2001 From: william Date: Thu, 9 Apr 2015 20:53:43 -0700 Subject: refactor and fixup some interfaces, and begin to flesh out ALPN selection callback --- src/openssl.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 148 insertions(+), 39 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 4e0b898..3465922 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -424,6 +424,24 @@ static void checkprotos(luaL_Buffer *B, lua_State *L, int index) { } } /* checkprotos() */ +static void pushprotos(lua_State *L, const unsigned char *p, size_t n) { + const unsigned char *pe = &p[n]; + int i = 0; + + lua_newtable(L); + + while (p < pe) { + n = *p++; + + if ((size_t)(pe - p) < n) + luaL_error(L, "corrupt ALPN protocol list (%zu > %zu)", n, (size_t)(pe - p)); + + lua_pushlstring(L, (const void *)p, n); + lua_rawseti(L, -2, ++i); + p += n; + } +} /* pushprotos() */ + static _Bool getfield(lua_State *L, int index, const char *k) { lua_getfield(L, index, k); @@ -604,15 +622,44 @@ static void *compat_EVP_PKEY_get0(EVP_PKEY *key) { #endif +typedef int auxref_t; +typedef int auxtype_t; + +static void auxL_unref(lua_State *L, auxref_t *ref) { + luaL_unref(L, LUA_REGISTRYINDEX, *ref); + *ref = LUA_NOREF; +} /* auxL_unref() */ + +static void auxL_ref(lua_State *L, int index, auxref_t *ref) { + auxL_unref(L, ref); + lua_pushvalue(L, index); + *ref = luaL_ref(L, LUA_REGISTRYINDEX); +} /* auxL_ref() */ + +static auxtype_t auxL_getref(lua_State *L, auxref_t ref) { + if (ref == LUA_NOREF || ref == LUA_REFNIL) { + lua_pushnil(L); + } else { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + } + + return lua_type(L, -1); +} /* auxL_getref() */ + + struct ex_state { - lua_State *mainthread; + lua_State *L; LIST_HEAD(, ex_data) data; }; /* struct ex_state */ +#ifndef EX_DATA_MAXARGS +#define EX_DATA_MAXARGS 4 +#endif + struct ex_data { struct ex_state *state; int refs; - int arg[4]; + auxref_t arg[EX_DATA_MAXARGS]; LIST_ENTRY(ex_data) le; }; /* struct ex_data */ @@ -621,40 +668,47 @@ enum { }; static struct ex_type { - int class_index; - int index; + int class_index; /* OpenSSL object type identifier */ + int index; /* OpenSSL-allocated external data identifier */ void *(*get_ex_data)(); int (*set_ex_data)(); } ex_type[] = { [EX_SSL_CTX_ALPN_SELECT_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, }; -static int ex_data_dup(CRYPTO_EX_DATA *to NOTUSED, CRYPTO_EX_DATA *from NOTUSED, void *from_d, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { +static int ex_ondup(CRYPTO_EX_DATA *to NOTUSED, CRYPTO_EX_DATA *from NOTUSED, void *from_d, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { struct ex_data **data = from_d; if (*data) (*data)->refs++; return 1; -} /* ex_data_dup() */ +} /* ex_ondup() */ -static void ex_data_free(void *parent NOTUSED, void *_data, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { +static void ex_onfree(void *parent NOTUSED, void *_data, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { struct ex_data *data = _data; if (!data || --data->refs > 0) return; - if (data->state) + if (data->state) { + int i; + + for (i = 0; i < (int)countof(data->arg); i++) { + auxL_unref(data->state->L, &data->arg[i]); + } + LIST_REMOVE(data, le); + } free(data); -} /* ex_data_free() */ +} /* ex_onfree() */ static int ex_initonce(void) { struct ex_type *type; for (type = ex_type; type < endof(ex_type); type++) { - if (-1 == (type->index = CRYPTO_get_ex_new_index(type->class_index, 0, NULL, NULL, &ex_data_dup, &ex_data_free))) + if (-1 == (type->index = CRYPTO_get_ex_new_index(type->class_index, 0, NULL, NULL, &ex_ondup, &ex_onfree))) return -1; }; @@ -676,22 +730,27 @@ static int ex__gc(lua_State *L) { return 0; } /* ex__gc() */ -static void ex_init(lua_State *L) { +static void ex_newstate(lua_State *L) { struct ex_state *state; struct lua_State *thr; state = prepudata(L, sizeof *state, NULL, &ex__gc); LIST_INIT(&state->data); + /* + * XXX: Don't reuse mainthread because if an error occurs in a + * callback Lua might longjmp across the OpenSSL call stack. + * Instead, we'll install our own panic handlers. + */ #if defined LUA_RIDX_MAINTHREAD lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); - state->mainthread = lua_tothread(L, -1); + state->L = lua_tothread(L, -1); lua_pop(L, 1); #else lua_pushvalue(L, -1); thr = lua_newthread(L); lua_settable(L, LUA_REGISTRYINDEX); - state->mainthread = thr; + state->L = thr; #endif lua_pushcfunction(L, &ex__gc); @@ -699,9 +758,9 @@ static void ex_init(lua_State *L) { lua_settable(L, LUA_REGISTRYINDEX); lua_pop(L, 1); -} /* ex_init() */ +} /* ex_newstate() */ -static struct ex_state *ex_get(lua_State *L) { +static struct ex_state *ex_getstate(lua_State *L) { struct ex_state *state; lua_pushcfunction(L, &ex__gc); @@ -712,12 +771,12 @@ static struct ex_state *ex_get(lua_State *L) { lua_pop(L, 1); return state; -} /* ex_get() */ +} /* ex_getstate() */ -static int ex_data_get(lua_State **L, int _type, void *obj) { +static size_t ex_getdata(lua_State **L, int _type, void *obj) { struct ex_type *type = &ex_type[_type]; struct ex_data *data; - int i; + size_t i; if (!(data = type->get_ex_data(obj, type->index))) return 0; @@ -725,28 +784,31 @@ static int ex_data_get(lua_State **L, int _type, void *obj) { return 0; if (!*L) - *L = data->state->mainthread; + *L = data->state->L; + + if (!lua_checkstack(*L, countof(data->arg))) + return 0; - for (i = 0; i < (int)countof(data->arg); i++) { + for (i = 0; i < countof(data->arg) && data->arg[i] != LUA_NOREF; i++) { lua_rawgeti(*L, LUA_REGISTRYINDEX, data->arg[i]); } return i; -} /* ex_data_get() */ +} /* ex_getdata() */ -static int ex_data_set(lua_State *L, int _type, void *obj, int n) { +/* returns 0 on success, otherwise error (>0 == errno, -1 == OpenSSL error) */ +static int ex_setdata(lua_State *L, int _type, void *obj, size_t n) { struct ex_type *type = &ex_type[_type]; struct ex_state *state; struct ex_data *data; - int i, j; + size_t i, j; if ((data = type->get_ex_data(obj, type->index)) && data->state) { - for (i = 0; i < (int)countof(data->arg); i++) { - luaL_unref(L, LUA_REGISTRYINDEX, data->arg[i]); - data->arg[i] = LUA_NOREF; + for (i = 0; i < countof(data->arg); i++) { + auxL_unref(L, &data->arg[i]); } } else { - state = ex_get(L); + state = ex_getstate(L); if (!(data = malloc(sizeof *data))) return errno; @@ -756,20 +818,19 @@ static int ex_data_set(lua_State *L, int _type, void *obj, int n) { data->state = state; data->refs = 1; - for (i = 0; i < (int)countof(data->arg); i++) + for (i = 0; i < countof(data->arg); i++) data->arg[i] = LUA_NOREF; LIST_INSERT_HEAD(&state->data, data, le); } - for (i = n, j = 0; i > 0 && j < (int)countof(data->arg); i--, j++) { - lua_pushvalue(L, -i); - data->arg[j] = luaL_ref(L, LUA_REGISTRYINDEX); + for (i = n, j = 0; i > 0 && j < countof(data->arg); i--, j++) { + auxL_ref(L, -(int)i, &data->arg[j]); } lua_pop(L, n); return 0; -} /* ex_data_set() */ +} /* ex_setdata() */ static void initall(lua_State *L); @@ -4800,13 +4861,44 @@ static int sx_setAlpnProtos(lua_State *L) { #endif #if HAVE_SSL_CTX_SET_ALPN_SELECT_CB -static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { +static SSL *ssl_push(lua_State *, SSL *); + +static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *_ctx) { + SSL_CTX *ctx = _ctx; lua_State *L = NULL; - int n; + size_t n; + int top, status; - n = ex_data_get(&L, EX_SSL_CTX_ALPN_SELECT_CB, ssl); + if (0 == (n = ex_getdata(&L, EX_SSL_CTX_ALPN_SELECT_CB, ctx))) + return SSL_TLSEXT_ERR_ALERT_FATAL; - return 0; + top = lua_gettop(L) - n; + + /* TODO: Install temporary panic handler to catch OOM errors */ + + /* pass the SSL object as first argument */ + ssl_push(L, ssl); + pushprotos(L, in, inlen); + + /* TODO: lua_rotate ssl and protocols table into position. */ + + if (LUA_OK != (status = lua_pcall(L, 2 + (n - 1), 1, 0))) + goto fatal; + + /* TODO: check return value */ + (void)out; (void)outlen; + + lua_settop(L, top); + + return SSL_TLSEXT_ERR_OK; +fatal: + lua_settop(L, top); + + return SSL_TLSEXT_ERR_ALERT_FATAL; +noack: + lua_settop(L, top); + + return SSL_TLSEXT_ERR_NOACK; } /* sx_setAlpnSelect_cb() */ static int sx_setAlpnSelect(lua_State *L) { @@ -4815,9 +4907,17 @@ static int sx_setAlpnSelect(lua_State *L) { int error; luaL_checktype(L, 2, LUA_TFUNCTION); - error = ex_data_set(L, EX_SSL_CTX_ALPN_SELECT_CB, ctx, 1); + if ((error = ex_setdata(L, EX_SSL_CTX_ALPN_SELECT_CB, ctx, 1))) { + if (error > 0) { + return luaL_error(L, "unable to set ALPN protocol selection callback: %s", xstrerror(error)); + } else if (!ERR_peek_error()) { + return luaL_error(L, "unable to set ALPN protocol selection callback: Unknown internal error"); + } else { + return throwssl(L, "ssl.context:setAlpnSelect"); + } + } - SSL_CTX_set_alpn_select_cb(ctx, &sx_setAlpnSelect_cb, NULL); + SSL_CTX_set_alpn_select_cb(ctx, &sx_setAlpnSelect_cb, ctx); lua_pushboolean(L, 1); @@ -4936,6 +5036,15 @@ int luaopen__openssl_ssl_context(lua_State *L) { * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +static SSL *ssl_push(lua_State *L, SSL *ssl) { + SSL **ud = prepsimple(L, SSL_CLASS); + + CRYPTO_add(&(ssl)->references, 1, CRYPTO_LOCK_SSL); + *ud = ssl; + + return *ud; +} /* ssl_push() */ + static int ssl_new(lua_State *L) { lua_pushnil(L); @@ -6168,7 +6277,7 @@ static void initall(lua_State *L) { pthread_mutex_unlock(&mutex); - ex_init(L); + ex_newstate(L); addclass(L, BIGNUM_CLASS, bn_methods, bn_metatable); addclass(L, PKEY_CLASS, pk_methods, pk_metatable); -- cgit v1.2.3-59-g8ed1b From 8dbe7e424adcfcf0bec4c8573b874d733c5b2a66 Mon Sep 17 00:00:00 2001 From: william Date: Thu, 16 Apr 2015 21:00:58 -0700 Subject: add fix for issue #17 --- src/openssl.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 7 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 3465922..163ba7f 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -33,7 +33,9 @@ #include /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ #include /* struct tm time_t strptime(3) time(2) */ #include /* tolower(3) */ +#include /* sig_atomic_t */ #include /* ENOMEM errno */ +#include /* assert */ #include /* ssize_t pid_t */ #if !defined __sun && !defined _AIX @@ -44,16 +46,11 @@ #include /* AF_INET AF_INET6 */ #include /* RUSAGE_SELF struct rusage getrusage(2) */ #include /* struct utsname uname(3) */ - #include /* O_RDONLY O_CLOEXEC open(2) */ - #include /* close(2) getpid(2) */ - #include /* struct in_addr struct in6_addr */ #include /* inet_pton(3) */ - #include /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */ - #include /* dladdr(3) dlopen(3) */ #if __APPLE__ @@ -576,6 +573,22 @@ static void lib_setintegers(lua_State *L, const integer_Reg *l) { } /* lib_setintegers() */ +#define COMPAT_X509_STORE_FREE_BUG 0x01 + +static struct { + int flags; + + int SSL_CTX_ex_index; + void (*X509_STORE_free)(X509_STORE *); + + struct { + X509_STORE *store; + } tmp; +} compat = { + .flags = 0, + .SSL_CTX_ex_index = -1, + .X509_STORE_free = &X509_STORE_free, +}; #if !HAVE_EVP_PKEY_base_id #define EVP_PKEY_base_id(key) compat_EVP_PKEY_base_id((key)) @@ -621,6 +634,126 @@ static void *compat_EVP_PKEY_get0(EVP_PKEY *key) { } /* compat_EVP_PKEY_get0() */ #endif +/* X509_STORE_free in OpenSSL versions < 1.0.2 doesn't obey reference count */ +#define X509_STORE_free(store) \ + (compat.X509_STORE_free)((store)) + +static void compat_X509_STORE_free(X509_STORE *store) { + int i; + + i = CRYPTO_add(&store->references, -1, CRYPTO_LOCK_X509_STORE); + + if (i > 0) + return; + + (X509_STORE_free)(store); +} /* compat_X509_STORE_free() */ + +#if !HAVE_SSL_CTX_set1_cert_store +#define SSL_CTX_set1_cert_store(ctx, store) \ + compat_SSL_CTX_set1_cert_store((ctx), (store)) + +static void compat_SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store) { + int n; + + /* + * This isn't thead-safe, but using X509_STORE or SSL_CTX objects + * from different threads isn't safe generally. + */ + if (ctx->cert_store) { + X509_STORE_free(ctx->cert_store); + ctx->cert_store = NULL; + } + + n = store->references; + + SSL_CTX_set_cert_store(ctx, store); + + if (n == store->references) + CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); +} /* compat_SSL_CTX_set1_cert_store() */ +#endif + +static void compat_SSL_CTX_onfree(void *_ctx, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { + SSL_CTX *ctx = _ctx; + + if (ctx->cert_store) { + X509_STORE_free(ctx->cert_store); + ctx->cert_store = NULL; + } +} /* compat_SSL_CTX_onfree() */ + +/* helper routine to determine if X509_STORE_free obeys reference count */ +static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { + /* unfortunately there's no way to remove a handler */ + if (store != compat.tmp.store) + return; + + /* signal that we were freed by nulling our reference */ + compat.tmp.store = NULL; +} /* compat_init_X509_STORE_onfree() */ + +static int compat_init(void) { + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + static volatile sig_atomic_t done; + int error; + + if ((error = pthread_mutex_lock(&mutex))) + return error; + + if (!done) { + /* + * Test if X509_STORE_free obeys reference counts. + */ + if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, 0, NULL, NULL, NULL, &compat_init_X509_STORE_onfree)) + goto sslerr; + + if (!(compat.tmp.store = X509_STORE_new())) + goto sslerr; + + CRYPTO_add(&compat.tmp.store->references, 1, CRYPTO_LOCK_X509_STORE); + X509_STORE_free(compat.tmp.store); + + if (compat.tmp.store) { + X509_STORE_free(compat.tmp.store); + assert(compat.tmp.store == NULL); + compat.tmp.store = NULL; + } else { + /* + * If X509_STORE_free does NOT obey reference + * counts, then make sure that our fixed version is + * called on SSL_CTX destruction. Note that this + * won't fix code which doesn't properly obey the + * reference counts when setting the cert_store + * member. + */ + if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, 0, NULL, NULL, NULL, &compat_SSL_CTX_onfree)) + goto sslerr; + + compat.flags |= COMPAT_X509_STORE_FREE_BUG; + } + + done = 1; + } +epilog: + if (compat.tmp.store) { + X509_STORE_free(compat.tmp.store); + compat.tmp.store = NULL; + } + + pthread_mutex_unlock(&mutex); + + return 0; +sslerr: + error = -1; + + goto epilog; +syserr: + error = errno; + + goto epilog; +} /* compat_init() */ + typedef int auxref_t; typedef int auxtype_t; @@ -4699,8 +4832,7 @@ static int sx_setStore(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509_STORE *store = checksimple(L, 2, X509_STORE_CLASS); - SSL_CTX_set_cert_store(ctx, store); - CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); + SSL_CTX_set1_cert_store(ctx, store); lua_pushboolean(L, 1); @@ -6251,6 +6383,15 @@ static void initall(lua_State *L) { } } + /* TODO: Move down to after SSL_load_error_strings */ + if ((error = compat_init())) { + if (error == -1) { + throwssl(L, "openssl.init"); + } else { + luaL_error(L, "openssl.init: %s", xstrerror(error)); + } + } + pthread_mutex_lock(&mutex); if (!initssl) { -- cgit v1.2.3-59-g8ed1b From b5c0bb622f55b6e52a1ae1a5ec5a4ded0cded96b Mon Sep 17 00:00:00 2001 From: william Date: Thu, 16 Apr 2015 21:03:57 -0700 Subject: don't care about the SSL_CTX class index --- src/openssl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 163ba7f..90db798 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -578,7 +578,6 @@ static void lib_setintegers(lua_State *L, const integer_Reg *l) { static struct { int flags; - int SSL_CTX_ex_index; void (*X509_STORE_free)(X509_STORE *); struct { @@ -586,7 +585,6 @@ static struct { } tmp; } compat = { .flags = 0, - .SSL_CTX_ex_index = -1, .X509_STORE_free = &X509_STORE_free, }; -- cgit v1.2.3-59-g8ed1b From c6a00deb359b38ec72aeeba3b07a22fdda209dbc Mon Sep 17 00:00:00 2001 From: william Date: Fri, 17 Apr 2015 16:08:24 -0700 Subject: pin the module in memory when installing external app data callbacks, as these can be never be uninstalled --- src/openssl.c | 358 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 234 insertions(+), 124 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 90db798..0894fcf 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -23,9 +23,6 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ -#ifndef LUAOSSL_H -#define LUAOSSL_H - #include /* INT_MAX INT_MIN UCHAR_MAX */ #include /* uintptr_t */ #include /* memset(3) strerror_r(3) */ @@ -33,8 +30,7 @@ #include /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ #include /* struct tm time_t strptime(3) time(2) */ #include /* tolower(3) */ -#include /* sig_atomic_t */ -#include /* ENOMEM errno */ +#include /* ENOMEM ENOTSUP errno */ #include /* assert */ #include /* ssize_t pid_t */ @@ -80,6 +76,10 @@ #include "compat52.h" #endif +#ifndef HAVE_DLADDR +#define HAVE_DLADDR (!defined _AIX) /* TODO: https://root.cern.ch/drupal/content/aix-and-dladdr */ +#endif + #ifndef HAVE_SSL_CTX_SET_ALPN_PROTOS #define HAVE_SSL_CTX_SET_ALPN_PROTOS (OPENSSL_VERSION_NUMBER >= 0x1000200fL) #endif @@ -573,6 +573,83 @@ static void lib_setintegers(lua_State *L, const integer_Reg *l) { } /* lib_setintegers() */ +/* + * Auxiliary Lua API routines + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +typedef int auxref_t; +typedef int auxtype_t; + +static void auxL_unref(lua_State *L, auxref_t *ref) { + luaL_unref(L, LUA_REGISTRYINDEX, *ref); + *ref = LUA_NOREF; +} /* auxL_unref() */ + +static void auxL_ref(lua_State *L, int index, auxref_t *ref) { + auxL_unref(L, ref); + lua_pushvalue(L, index); + *ref = luaL_ref(L, LUA_REGISTRYINDEX); +} /* auxL_ref() */ + +static auxtype_t auxL_getref(lua_State *L, auxref_t ref) { + if (ref == LUA_NOREF || ref == LUA_REFNIL) { + lua_pushnil(L); + } else { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + } + + return lua_type(L, -1); +} /* auxL_getref() */ + + +/* + * dl - dynamically loaded module management + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Prevent loader from unlinking us if we've registered a callback with + * OpenSSL by taking another reference to ourselves. + */ +static int dl_anchor(void) { +#if HAVE_DLADDR + extern int luaopen__openssl(lua_State *); + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + static void *anchor; + Dl_info info; + int error = 0; + + if ((error = pthread_mutex_lock(&mutex))) + return error; + + if (anchor) + goto epilog; + + if (!dladdr((void *)&luaopen__openssl, &info)) + goto dlerr; + + if (!(anchor = dlopen(info.dli_fname, RTLD_NOW|RTLD_LOCAL))) + goto dlerr; +epilog: + (void)pthread_mutex_unlock(&mutex); + + return error; +dlerr: + error = -2; + + goto epilog; +#else + return 0;//ENOTSUP; +#endif +} /* dl_anchor() */ + + +/* + * compat - OpenSSL API compatibility and bug workarounds + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #define COMPAT_X509_STORE_FREE_BUG 0x01 static struct { @@ -632,7 +709,9 @@ static void *compat_EVP_PKEY_get0(EVP_PKEY *key) { } /* compat_EVP_PKEY_get0() */ #endif -/* X509_STORE_free in OpenSSL versions < 1.0.2 doesn't obey reference count */ +/* + * X509_STORE_free in OpenSSL versions < 1.0.2 doesn't obey reference count + */ #define X509_STORE_free(store) \ (compat.X509_STORE_free)((store)) @@ -672,14 +751,14 @@ static void compat_SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store) { } /* compat_SSL_CTX_set1_cert_store() */ #endif -static void compat_SSL_CTX_onfree(void *_ctx, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { +static void compat_init_SSL_CTX_onfree(void *_ctx, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { SSL_CTX *ctx = _ctx; if (ctx->cert_store) { X509_STORE_free(ctx->cert_store); ctx->cert_store = NULL; } -} /* compat_SSL_CTX_onfree() */ +} /* compat_init_SSL_CTX_onfree() */ /* helper routine to determine if X509_STORE_free obeys reference count */ static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { @@ -693,90 +772,89 @@ static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPT static int compat_init(void) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - static volatile sig_atomic_t done; - int error; + static int store_index = -1, ssl_ctx_index = -1, done; + X509_STORE *store; + int error = 0; if ((error = pthread_mutex_lock(&mutex))) return error; - if (!done) { - /* - * Test if X509_STORE_free obeys reference counts. - */ - if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, 0, NULL, NULL, NULL, &compat_init_X509_STORE_onfree)) - goto sslerr; + if (done) + goto epilog; - if (!(compat.tmp.store = X509_STORE_new())) - goto sslerr; + /* + * We need to unconditionally install at least one external + * application data callback. Because these can never be + * uninstalled, we can never be unloaded. + */ + if ((error = dl_anchor())) + goto epilog; - CRYPTO_add(&compat.tmp.store->references, 1, CRYPTO_LOCK_X509_STORE); - X509_STORE_free(compat.tmp.store); + /* + * Test if X509_STORE_free obeys reference counts by installing an + * onfree callback. + */ + if (store_index == -1 + && -1 == (store_index = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, 0, NULL, NULL, NULL, &compat_init_X509_STORE_onfree))) + goto sslerr; - if (compat.tmp.store) { - X509_STORE_free(compat.tmp.store); - assert(compat.tmp.store == NULL); - compat.tmp.store = NULL; - } else { - /* - * If X509_STORE_free does NOT obey reference - * counts, then make sure that our fixed version is - * called on SSL_CTX destruction. Note that this - * won't fix code which doesn't properly obey the - * reference counts when setting the cert_store - * member. - */ - if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, 0, NULL, NULL, NULL, &compat_SSL_CTX_onfree)) - goto sslerr; - - compat.flags |= COMPAT_X509_STORE_FREE_BUG; - } + if (!(compat.tmp.store = X509_STORE_new())) + goto sslerr; + + CRYPTO_add(&compat.tmp.store->references, 1, CRYPTO_LOCK_X509_STORE); + X509_STORE_free(compat.tmp.store); - done = 1; + if (compat.tmp.store) { + /* + * Because our onfree callback didn't execute, we assume + * X509_STORE_free obeys reference counts. Alternatively, + * our callback might not have executed for some other + * reason. We assert the truth of our assumption by checking + * again after calling X509_STORE_free once more. + */ + X509_STORE_free(compat.tmp.store); + assert(compat.tmp.store == NULL); + compat.tmp.store = NULL; /* in case assertions disabled */ + } else { + /* + * Because our onfree callback was invoked, X509_STORE_free + * appears not to obey reference counts. Ensure that our + * fixed version is called on SSL_CTX destruction. + * + * NB: We depend on the coincidental order of operations in + * SSL_CTX_free that user data destruction occurs before + * free'ing the cert_store member. Ruby's OpenSSL bindings + * also depend on this order as we both use the onfree + * callback to clear the member. + */ + if (ssl_ctx_index == -1 + && -1 == (ssl_ctx_index = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, 0, NULL, NULL, NULL, &compat_init_SSL_CTX_onfree))) + goto sslerr; + + compat.flags |= COMPAT_X509_STORE_FREE_BUG; } + + done = 1; epilog: if (compat.tmp.store) { X509_STORE_free(compat.tmp.store); compat.tmp.store = NULL; } - pthread_mutex_unlock(&mutex); + (void)pthread_mutex_unlock(&mutex); - return 0; + return error; sslerr: error = -1; - goto epilog; -syserr: - error = errno; - goto epilog; } /* compat_init() */ -typedef int auxref_t; -typedef int auxtype_t; - -static void auxL_unref(lua_State *L, auxref_t *ref) { - luaL_unref(L, LUA_REGISTRYINDEX, *ref); - *ref = LUA_NOREF; -} /* auxL_unref() */ - -static void auxL_ref(lua_State *L, int index, auxref_t *ref) { - auxL_unref(L, ref); - lua_pushvalue(L, index); - *ref = luaL_ref(L, LUA_REGISTRYINDEX); -} /* auxL_ref() */ - -static auxtype_t auxL_getref(lua_State *L, auxref_t ref) { - if (ref == LUA_NOREF || ref == LUA_REFNIL) { - lua_pushnil(L); - } else { - lua_rawgeti(L, LUA_REGISTRYINDEX, ref); - } - - return lua_type(L, -1); -} /* auxL_getref() */ - +/* + * External Application Data Hooks + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct ex_state { lua_State *L; @@ -835,16 +913,43 @@ static void ex_onfree(void *parent NOTUSED, void *_data, CRYPTO_EX_DATA *ad NOTU free(data); } /* ex_onfree() */ -static int ex_initonce(void) { +static int ex_init(void) { + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + static int done; struct ex_type *type; + int error = 0; + + if ((error = pthread_mutex_lock(&mutex))) + return error; + + if (done) + goto epilog; + + /* + * Our callbacks can never be uninstalled, so ensure we're never + * unloaded. + */ + if ((error = dl_anchor())) + goto epilog; for (type = ex_type; type < endof(ex_type); type++) { + if (type->index != -1) + continue; + if (-1 == (type->index = CRYPTO_get_ex_new_index(type->class_index, 0, NULL, NULL, &ex_ondup, &ex_onfree))) - return -1; + goto sslerr; }; - return 0; -} /* ex_initonce() */ + done = 1; +epilog: + (void)pthread_mutex_unlock(&mutex); + + return error; +sslerr: + error = -1; + + goto epilog; +} /* ex_init() */ static int ex__gc(lua_State *L) { struct ex_state *state = lua_touserdata(L, 1); @@ -966,6 +1071,25 @@ static int ex_setdata(lua_State *L, int _type, void *obj, size_t n) { static void initall(lua_State *L); +/* + * compat - Lua OpenSSL + * + * Bindings to our internal feature detection, compatability, and workaround + * code. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int luaopen__openssl_compat(lua_State *L) { + initall(L); + + lua_newtable(L); + lua_pushboolean(L, !!(compat.flags & COMPAT_X509_STORE_FREE_BUG)); + lua_setfield(L, -2, "X509_STORE_FREE_BUG"); + + return 1; +} /* luaopen__openssl_compat() */ + + /* * OPENSSL - openssl * @@ -6257,18 +6381,11 @@ int luaopen__openssl_des(lua_State *L) { * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HAVE_DLADDR -#define HAVE_DLADDR (!defined _AIX) /* TODO: https://root.cern.ch/drupal/content/aix-and-dladdr */ -#endif - static struct { pthread_mutex_t *lock; int nlock; - - void *dlref; } mt_state; - static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUSED) { if (mode & CRYPTO_LOCK) pthread_mutex_lock(&mt_state.lock[type]); @@ -6276,7 +6393,6 @@ static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUS pthread_mutex_unlock(&mt_state.lock[type]); } /* mt_lock() */ - /* * Sources include Google and especially the Wine Project. See get_unix_tid * at http://source.winehq.org/git/wine.git/?a=blob;f=dlls/ntdll/server.c. @@ -6309,12 +6425,16 @@ static unsigned long mt_gettid(void) { #endif } /* mt_gettid() */ - static int mt_init(void) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - int bound = 0, error = 0; + static int done, bound; + int error = 0; - pthread_mutex_lock(&mutex); + if ((error = pthread_mutex_lock(&mutex))) + return error; + + if (done) + goto epilog; if (!CRYPTO_get_locking_callback()) { if (!mt_state.lock) { @@ -6324,11 +6444,20 @@ static int mt_init(void) { if (!(mt_state.lock = malloc(mt_state.nlock * sizeof *mt_state.lock))) { error = errno; - goto leave; + goto epilog; } for (i = 0; i < mt_state.nlock; i++) { - pthread_mutex_init(&mt_state.lock[i], NULL); + if ((error = pthread_mutex_init(&mt_state.lock[i], NULL))) { + while (i > 0) { + pthread_mutex_destroy(&mt_state.lock[--i]); + } + + free(mt_state.lock); + mt_state.lock = NULL; + + goto epilog; + } } } @@ -6341,27 +6470,11 @@ static int mt_init(void) { bound = 1; } - /* - * Prevent loader from unlinking us if we've registered a callback - * with OpenSSL by taking another reference to ourselves. - */ -#if HAVE_DLADDR - if (bound && !mt_state.dlref) { - Dl_info info; - - if (!dladdr((void *)&luaopen__openssl_rand, &info)) { - error = -1; - goto leave; - } + if (bound && (error = dl_anchor())) + goto epilog; - if (!(mt_state.dlref = dlopen(info.dli_fname, RTLD_NOW|RTLD_LOCAL))) { - error = -1; - goto leave; - } - } -#endif - -leave: + done = 1; +epilog: pthread_mutex_unlock(&mutex); return error; @@ -6381,15 +6494,6 @@ static void initall(lua_State *L) { } } - /* TODO: Move down to after SSL_load_error_strings */ - if ((error = compat_init())) { - if (error == -1) { - throwssl(L, "openssl.init"); - } else { - luaL_error(L, "openssl.init: %s", xstrerror(error)); - } - } - pthread_mutex_lock(&mutex); if (!initssl) { @@ -6404,17 +6508,25 @@ static void initall(lua_State *L) { * already been configured. */ OPENSSL_config(NULL); + } - if ((error = ex_initonce())) { - if (error == -1) { - throwssl(L, "openssl.init"); - } else { - luaL_error(L, "openssl.init: %s", xstrerror(error)); - } + pthread_mutex_unlock(&mutex); + + if ((error = compat_init())) { + if (error == -1) { + throwssl(L, "openssl.init"); + } else { + luaL_error(L, "openssl.init: %s", xstrerror(error)); } } - pthread_mutex_unlock(&mutex); + if ((error = ex_init())) { + if (error == -1) { + throwssl(L, "openssl.init"); + } else { + luaL_error(L, "openssl.init: %s", xstrerror(error)); + } + } ex_newstate(L); @@ -6436,5 +6548,3 @@ static void initall(lua_State *L) { addclass(L, CIPHER_CLASS, cipher_methods, cipher_metatable); } /* initall() */ - -#endif /* LUAOSSL_H */ -- cgit v1.2.3-59-g8ed1b From 25715fc735e2a87e52a1929a96c88bea4c8dc9cf Mon Sep 17 00:00:00 2001 From: william Date: Fri, 17 Apr 2015 16:43:36 -0700 Subject: unify OpenSSL, DYLD, and system errno error handling, and begin to regularize auxiliary routines under the aux prefix --- src/openssl.c | 556 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 277 insertions(+), 279 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 0894fcf..03cc3f7 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -196,35 +196,6 @@ static const char *xitoa(char *dst, size_t lim, long i) { } /* xitoa() */ -#define xstrerror(error) xstrerror_r((error), (char[256]){ 0 }, 256) - -static const char *xstrerror_r(int error, char *dst, size_t lim) { - static const char unknown[] = "Unknown error: "; - size_t n; - -#if STRERROR_R_CHAR_P - char *rv = strerror_r(error, dst, lim); - - if (rv != NULL) - return dst; -#else - int rv = strerror_r(error, dst, lim); - - if (0 == rv) - return dst; -#endif - - /* - * glibc snprintf can fail on memory pressure, so format our number - * manually. - */ - n = MIN(sizeof unknown - 1, lim); - memcpy(dst, unknown, n); - - return xitoa(&dst[n], lim - n, error); -} /* xstrerror_r() */ - - static void *prepudata(lua_State *L, size_t size, const char *tname, int (*gc)(lua_State *)) { void *p = memset(lua_newuserdata(L, size), 0, size); @@ -278,40 +249,6 @@ static void *testsimple(lua_State *L, int index, const char *tname) { } /* testsimple() */ -static const char *pusherror(lua_State *L, const char *fun) { - unsigned long code; - const char *path, *file; - int line; - char txt[256]; - - if (!ERR_peek_error()) - return lua_pushstring(L, "oops: no OpenSSL errors set"); - - code = ERR_get_error_line(&path, &line); - - if ((file = strrchr(path, '/'))) - ++file; - else - file = path; - - ERR_clear_error(); - - ERR_error_string_n(code, txt, sizeof txt); - - if (fun) - return lua_pushfstring(L, "%s: %s:%d:%s", fun, file, line, txt); - else - return lua_pushfstring(L, "%s:%d:%s", file, line, txt); -} /* pusherror() */ - - -static int throwssl(lua_State *L, const char *fun) { - pusherror(L, fun); - - return lua_error(L); -} /* throwssl() */ - - static int interpose(lua_State *L, const char *mt) { luaL_getmetatable(L, mt); @@ -509,6 +446,69 @@ static const char *pushnid(lua_State *L, int nid) { } /* pushnid() */ +/* + * Auxiliary C routines + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define aux_strerror(error) aux_strerror_r((error), (char[256]){ 0 }, 256) + +static const char *aux_strerror_r(int error, char *dst, size_t lim) { + static const char unknown[] = "Unknown error: "; + size_t n; + +#if STRERROR_R_CHAR_P + char *rv = strerror_r(error, dst, lim); + + if (rv != NULL) + return dst; +#else + int rv = strerror_r(error, dst, lim); + + if (0 == rv) + return dst; +#endif + + /* + * glibc snprintf can fail on memory pressure, so format our number + * manually. + */ + n = MIN(sizeof unknown - 1, lim); + memcpy(dst, unknown, n); + + return xitoa(&dst[n], lim - n, error); +} /* aux_strerror_r() */ + + +/* + * Auxiliary Lua API routines + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +typedef int auxref_t; +typedef int auxtype_t; + +static void auxL_unref(lua_State *L, auxref_t *ref) { + luaL_unref(L, LUA_REGISTRYINDEX, *ref); + *ref = LUA_NOREF; +} /* auxL_unref() */ + +static void auxL_ref(lua_State *L, int index, auxref_t *ref) { + auxL_unref(L, ref); + lua_pushvalue(L, index); + *ref = luaL_ref(L, LUA_REGISTRYINDEX); +} /* auxL_ref() */ + +static auxtype_t auxL_getref(lua_State *L, auxref_t ref) { + if (ref == LUA_NOREF || ref == LUA_REFNIL) { + lua_pushnil(L); + } else { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + } + + return lua_type(L, -1); +} /* auxL_getref() */ + /* * Lua 5.3 distinguishes integers and numbers, and by default uses 64-bit * integers. The following routines try to preserve this distinction and @@ -518,14 +518,13 @@ static const char *pushnid(lua_State *L, int nid) { * sizeof lua_Integer <= sizeof long long. Which is a safe bet where OpenSSL * is typically used. */ -#define lib_Integer long long -#define lib_Unsigned unsigned long long +#define auxL_Integer long long +#define auxL_Unsigned unsigned long long #define lua_IntegerMax ((1ULL << (sizeof (lua_Integer) * 8 - 1)) - 1) #define lua_IntegerMin (-lua_IntegerMax - 1) - -static void lib_pushinteger(lua_State *L, lib_Integer i) { +static void auxL_pushinteger(lua_State *L, auxL_Integer i) { /* * TODO: Check value explicitly, but will need to silence compiler * diagnostics about useless comparisons. @@ -536,71 +535,85 @@ static void lib_pushinteger(lua_State *L, lib_Integer i) { /* TODO: Check overflow. */ lua_pushnumber(L, i); } -} /* lib_pushinteger() */ - +} /* auxL_pushinteger() */ -NOTUSED static void lib_pushunsigned(lua_State *L, lib_Unsigned i) { +NOTUSED static void auxL_pushunsigned(lua_State *L, auxL_Unsigned i) { if (i <= lua_IntegerMax) { lua_pushinteger(L, i); - } else if (i == (lib_Unsigned)(lua_Number)i) { + } else if (i == (auxL_Unsigned)(lua_Number)i) { lua_pushnumber(L, i); } else { luaL_error(L, "unsigned integer value not representable as lua_Integer or lua_Number"); } -} /* lib_pushunsigned() */ - +} /* auxL_pushunsigned() */ -static lib_Integer lib_checkinteger(lua_State *L, int index) { - if (sizeof (lua_Integer) >= sizeof (lib_Integer)) { +static auxL_Integer auxL_checkinteger(lua_State *L, int index) { + if (sizeof (lua_Integer) >= sizeof (auxL_Integer)) { return luaL_checkinteger(L, index); } else { /* TODO: Check overflow. */ - return (lib_Integer)luaL_checknumber(L, index); + return (auxL_Integer)luaL_checknumber(L, index); } -} /* lib_checkinteger() */ - +} /* auxL_checkinteger() */ typedef struct { const char *name; - lib_Integer value; -} integer_Reg; + auxL_Integer value; +} auxL_IntegerReg; -static void lib_setintegers(lua_State *L, const integer_Reg *l) { +static void auxL_setintegers(lua_State *L, const auxL_IntegerReg *l) { for (; l->name; l++) { - lib_pushinteger(L, l->value); + auxL_pushinteger(L, l->value); lua_setfield(L, -2, l->name); } -} /* lib_setintegers() */ +} /* auxL_setintegers() */ +#define auxL_EDYLD -2 +#define auxL_EOPENSSL -1 -/* - * Auxiliary Lua API routines - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +static const char *auxL_pusherror(lua_State *L, int error, const char *fun) { + if (error == auxL_EOPENSSL) { + unsigned long code; + const char *path, *file; + int line; + char txt[256]; -typedef int auxref_t; -typedef int auxtype_t; + if (!ERR_peek_error()) + return lua_pushstring(L, "oops: no OpenSSL errors set"); -static void auxL_unref(lua_State *L, auxref_t *ref) { - luaL_unref(L, LUA_REGISTRYINDEX, *ref); - *ref = LUA_NOREF; -} /* auxL_unref() */ + code = ERR_get_error_line(&path, &line); -static void auxL_ref(lua_State *L, int index, auxref_t *ref) { - auxL_unref(L, ref); - lua_pushvalue(L, index); - *ref = luaL_ref(L, LUA_REGISTRYINDEX); -} /* auxL_ref() */ + if ((file = strrchr(path, '/'))) { + ++file; + } else { + file = path; + } -static auxtype_t auxL_getref(lua_State *L, auxref_t ref) { - if (ref == LUA_NOREF || ref == LUA_REFNIL) { - lua_pushnil(L); + ERR_clear_error(); + + ERR_error_string_n(code, txt, sizeof txt); + + if (fun) { + return lua_pushfstring(L, "%s: %s:%d:%s", fun, file, line, txt); + } else { + return lua_pushfstring(L, "%s:%d:%s", file, line, txt); + } + } else if (error == auxL_EDYLD) { + const char *const fmt = (fun)? "%s: %s" : "%.0s%s"; + + return lua_pushfstring(L, fmt, (fun)? fun : "", dlerror()); } else { - lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + const char *const fmt = (fun)? "%s: %s" : "%.0s%s"; + + return lua_pushfstring(L, fmt, (fun)? fun : "", aux_strerror(error)); } +} /* auxL_pusherror() */ - return lua_type(L, -1); -} /* auxL_getref() */ +static int auxL_error(lua_State *L, int error, const char *fun) { + auxL_pusherror(L, error, fun); + + return lua_error(L); +} /* auxL_error() */ /* @@ -636,7 +649,7 @@ epilog: return error; dlerr: - error = -2; + error = auxL_EDYLD; goto epilog; #else @@ -845,7 +858,7 @@ epilog: return error; sslerr: - error = -1; + error = auxL_EOPENSSL; goto epilog; } /* compat_init() */ @@ -946,7 +959,7 @@ epilog: return error; sslerr: - error = -1; + error = auxL_EOPENSSL; goto epilog; } /* ex_init() */ @@ -1249,7 +1262,7 @@ int luaopen__openssl(lua_State *L) { } } - lib_pushinteger(L, OPENSSL_VERSION_NUMBER); + auxL_pushinteger(L, OPENSSL_VERSION_NUMBER); lua_setfield(L, -2, "VERSION_NUMBER"); lua_pushstring(L, OPENSSL_VERSION_TEXT); @@ -1274,7 +1287,7 @@ static BIGNUM *bn_push(lua_State *L) { BIGNUM **ud = prepsimple(L, BIGNUM_CLASS); if (!(*ud = BN_new())) - throwssl(L, "bignum.new"); + auxL_error(L, auxL_EOPENSSL, "bignum.new"); return *ud; } /* bn_push() */ @@ -1392,7 +1405,7 @@ static BIGNUM *(checkbig)(lua_State *L, int index, _Bool *lvalue) { bn = prepsimple(L, BIGNUM_CLASS); if (!BN_dec2bn(bn, dec)) - throwssl(L, "bignum"); + auxL_error(L, auxL_EOPENSSL, "bignum"); lua_replace(L, index); @@ -1403,7 +1416,7 @@ static BIGNUM *(checkbig)(lua_State *L, int index, _Bool *lvalue) { bn = prepsimple(L, BIGNUM_CLASS); if (!f2bn(bn, lua_tonumber(L, index))) - throwssl(L, "bignum"); + auxL_error(L, auxL_EOPENSSL, "bignum"); lua_replace(L, index); @@ -1461,7 +1474,7 @@ static BN_CTX *getctx(lua_State *L) { ctx = prepsimple(L, NULL, &ctx__gc); if (!(*ctx = BN_CTX_new())) - throwssl(L, "bignum"); + auxL_error(L, auxL_EOPENSSL, "bignum"); lua_pushcfunction(L, &ctx__gc); lua_pushvalue(L, -2); @@ -1481,7 +1494,7 @@ static int bn__add(lua_State *L) { bn_prepops(L, &r, &a, &b, 1); if (!BN_add(r, a, b)) - return throwssl(L, "bignum:__add"); + return auxL_error(L, auxL_EOPENSSL, "bignum:__add"); return 1; } /* bn__add() */ @@ -1493,7 +1506,7 @@ static int bn__sub(lua_State *L) { bn_prepops(L, &r, &a, &b, 0); if (!BN_sub(r, a, b)) - return throwssl(L, "bignum:__sub"); + return auxL_error(L, auxL_EOPENSSL, "bignum:__sub"); return 1; } /* bn__sub() */ @@ -1505,7 +1518,7 @@ static int bn__mul(lua_State *L) { bn_prepops(L, &r, &a, &b, 1); if (!BN_mul(r, a, b, getctx(L))) - return throwssl(L, "bignum:__mul"); + return auxL_error(L, auxL_EOPENSSL, "bignum:__mul"); return 1; } /* bn__mul() */ @@ -1518,7 +1531,7 @@ static int bn__div(lua_State *L) { bn_prepops(L, &r, &a, &b, 0); if (!BN_div(r, NULL, a, b, getctx(L))) - return throwssl(L, "bignum:__div"); + return auxL_error(L, auxL_EOPENSSL, "bignum:__div"); return 1; } /* bn__div() */ @@ -1531,7 +1544,7 @@ static int bn__mod(lua_State *L) { bn_prepops(L, &r, &a, &b, 0); if (!BN_mod(r, a, b, getctx(L))) - return throwssl(L, "bignum:__mod"); + return auxL_error(L, auxL_EOPENSSL, "bignum:__mod"); return 1; } /* bn__mod() */ @@ -1544,7 +1557,7 @@ static int bn__pow(lua_State *L) { bn_prepops(L, &r, &a, &b, 0); if (!BN_exp(r, a, b, getctx(L))) - return throwssl(L, "bignum:__pow"); + return auxL_error(L, auxL_EOPENSSL, "bignum:__pow"); return 1; } /* bn__pow() */ @@ -1608,7 +1621,7 @@ static int bn__tostring(lua_State *L) { char *txt; if (!(txt = BN_bn2dec(bn))) - return throwssl(L, "bignum:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "bignum:__tostring"); lua_pushstring(L, txt); @@ -1680,7 +1693,7 @@ static BIO *getbio(lua_State *L) { bio = prepsimple(L, NULL, &bio__gc); if (!(*bio = BIO_new(BIO_s_mem()))) - throwssl(L, "BIO_new"); + auxL_error(L, auxL_EOPENSSL, "BIO_new"); lua_pushcfunction(L, &bio__gc); lua_pushvalue(L, -2); @@ -1753,14 +1766,14 @@ static int pk_new(lua_State *L) { creat: if (!(*ud = EVP_PKEY_new())) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); switch (EVP_PKEY_type(type)) { case EVP_PKEY_RSA: { RSA *rsa; if (!(rsa = RSA_generate_key(bits, exp, 0, 0))) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); EVP_PKEY_set1_RSA(*ud, rsa); @@ -1772,11 +1785,11 @@ creat: DSA *dsa; if (!(dsa = DSA_generate_parameters(bits, 0, 0, 0, 0, 0, 0))) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!DSA_generate_key(dsa)) { DSA_free(dsa); - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EVP_PKEY_set1_DSA(*ud, dsa); @@ -1789,11 +1802,11 @@ creat: DH *dh; if (!(dh = DH_generate_parameters(bits, exp, 0, 0))) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!DH_generate_key(dh)) { DH_free(dh); - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EVP_PKEY_set1_DH(*ud, dh); @@ -1808,7 +1821,7 @@ creat: EC_KEY *key; if (!(grp = EC_GROUP_new_by_curve_name(curve))) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_NAMED_CURVE); @@ -1817,7 +1830,7 @@ creat: if (!(key = EC_KEY_new())) { EC_GROUP_free(grp); - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EC_KEY_set_group(key, grp); @@ -1826,7 +1839,7 @@ creat: if (!EC_KEY_generate_key(key)) { EC_KEY_free(key); - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EVP_PKEY_set1_EC_KEY(*ud, key); @@ -1862,7 +1875,7 @@ creat: data = luaL_checklstring(L, 1, &len); if (!(bio = BIO_new_mem_buf((void *)data, len))) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (type == X509_PEM || type == X509_ANY) { if (!prvtonly && !pub) { @@ -1936,7 +1949,7 @@ done: if (!*ud) { if (goterr) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); /* we should never get here */ return luaL_error(L, "failed to load key for some unexpected reason"); @@ -1978,7 +1991,7 @@ static int pk_setPublicKey(lua_State *L) { type = optencoding(L, 3, "*", X509_ANY|X509_PEM|X509_DER); if (!(bio = BIO_new_mem_buf((void *)data, len))) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (type == X509_ANY || type == X509_PEM) { ok = !!PEM_read_bio_PUBKEY(bio, key, 0, ""); @@ -1991,7 +2004,7 @@ static int pk_setPublicKey(lua_State *L) { BIO_free(bio); if (!ok) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); lua_pushboolean(L, 1); @@ -2010,7 +2023,7 @@ static int pk_setPrivateKey(lua_State *L) { type = optencoding(L, 3, "*", X509_ANY|X509_PEM|X509_DER); if (!(bio = BIO_new_mem_buf((void *)data, len))) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (type == X509_ANY || type == X509_PEM) { ok = !!PEM_read_bio_PrivateKey(bio, key, 0, ""); @@ -2023,7 +2036,7 @@ static int pk_setPrivateKey(lua_State *L) { BIO_free(bio); if (!ok) - return throwssl(L, "pkey.new"); + return auxL_error(L, auxL_EOPENSSL, "pkey.new"); lua_pushboolean(L, 1); @@ -2044,7 +2057,7 @@ static int pk_sign(lua_State *L) { n = LUAL_BUFFERSIZE; if (!EVP_SignFinal(md, (void *)luaL_prepbuffer(&B), &n, key)) - return throwssl(L, "pkey:sign"); + return auxL_error(L, auxL_EOPENSSL, "pkey:sign"); luaL_addsize(&B, n); luaL_pushresult(&B); @@ -2070,7 +2083,7 @@ static int pk_verify(lua_State *L) { break; default: - return throwssl(L, "pkey:verify"); + return auxL_error(L, auxL_EOPENSSL, "pkey:verify"); } return 1; @@ -2102,7 +2115,7 @@ static int pk_toPEM(lua_State *L) { switch (checkoption(L, i, NULL, opts)) { case 0: case 1: /* public, PublicKey */ if (!PEM_write_bio_PUBKEY(bio, key)) - return throwssl(L, "pkey:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); len = BIO_get_mem_data(bio, &pem); lua_pushlstring(L, pem, len); @@ -2111,7 +2124,7 @@ static int pk_toPEM(lua_State *L) { break; case 2: case 3: /* private, PrivateKey */ if (!PEM_write_bio_PrivateKey(bio, key, 0, 0, 0, 0, 0)) - return throwssl(L, "pkey:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); len = BIO_get_mem_data(bio, &pem); lua_pushlstring(L, pem, len); @@ -2131,7 +2144,7 @@ static int pk_toPEM(lua_State *L) { DSA_free(dsa); if (!ok) - return throwssl(L, "pkey:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } @@ -2143,7 +2156,7 @@ static int pk_toPEM(lua_State *L) { DH_free(dh); if (!ok) - return throwssl(L, "pkey:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } @@ -2157,7 +2170,7 @@ static int pk_toPEM(lua_State *L) { EC_KEY_free(ec); if (!ok) - return throwssl(L, "pkey:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } @@ -2194,11 +2207,11 @@ static int pk__tostring(lua_State *L) { switch (type) { case X509_PEM: if (!PEM_write_bio_PUBKEY(bio, key)) - return throwssl(L, "pkey:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; case X509_DER: if (!i2d_PUBKEY_bio(bio, key)) - return throwssl(L, "pkey:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } /* switch() */ @@ -2271,7 +2284,7 @@ static X509_NAME *xn_dup(lua_State *L, X509_NAME *name) { X509_NAME **ud = prepsimple(L, X509_NAME_CLASS); if (!(*ud = X509_NAME_dup(name))) - throwssl(L, "x509.name.dup"); + auxL_error(L, auxL_EOPENSSL, "x509.name.dup"); return *ud; } /* xn_dup() */ @@ -2281,7 +2294,7 @@ static int xn_new(lua_State *L) { X509_NAME **ud = prepsimple(L, X509_NAME_CLASS); if (!(*ud = X509_NAME_new())) - return throwssl(L, "x509.name.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.name.new"); return 1; } /* xn_new() */ @@ -2308,7 +2321,7 @@ static int xn_add(lua_State *L) { ASN1_OBJECT_free(obj); if (!ok) - return throwssl(L, "x509.name:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.name:add"); lua_pushvalue(L, 1); @@ -2337,7 +2350,7 @@ static int xn_all(lua_State *L) { nid = OBJ_obj2nid(obj); if (0 > (len = OBJ_obj2txt(txt, sizeof txt, obj, 1))) - return throwssl(L, "x509.name:all"); + return auxL_error(L, auxL_EOPENSSL, "x509.name:all"); lua_pushlstring(L, txt, len); @@ -2391,7 +2404,7 @@ static int xn__next(lua_State *L) { lua_pushstring(L, id); } else { if (0 > (len = OBJ_obj2txt(txt, sizeof txt, obj, 1))) - return throwssl(L, "x509.name:__pairs"); + return auxL_error(L, auxL_EOPENSSL, "x509.name:__pairs"); lua_pushlstring(L, txt, len); } @@ -2481,7 +2494,7 @@ static GENERAL_NAMES *gn_dup(lua_State *L, GENERAL_NAMES *gens) { GENERAL_NAMES **ud = prepsimple(L, X509_GENS_CLASS); if (!(*ud = sk_GENERAL_NAME_dup(gens))) - throwssl(L, "x509.altname.dup"); + auxL_error(L, auxL_EOPENSSL, "x509.altname.dup"); return *ud; } /* gn_dup() */ @@ -2491,7 +2504,7 @@ static int gn_new(lua_State *L) { GENERAL_NAMES **ud = prepsimple(L, X509_GENS_CLASS); if (!(*ud = sk_GENERAL_NAME_new_null())) - return throwssl(L, "x509.altname.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.altname.new"); return 1; } /* gn_new() */ @@ -2591,7 +2604,7 @@ text: error: GENERAL_NAME_free(gen); - return throwssl(L, "x509.altname:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.altname:add"); } /* gn_add() */ @@ -2778,7 +2791,7 @@ error: if (conf) NCONF_free(conf); - return throwssl(L, "x509.extension.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.extension.new"); } /* xe_new() */ @@ -2844,7 +2857,7 @@ static int xc_new(lua_State *L) { int ok = 0; if (!(tmp = BIO_new_mem_buf((char *)data, len))) - return throwssl(L, "x509.cert.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert.new"); if (type == X509_PEM || type == X509_ANY) { ok = !!(*ud = PEM_read_bio_X509(tmp, NULL, 0, "")); /* no password */ @@ -2857,10 +2870,10 @@ static int xc_new(lua_State *L) { BIO_free(tmp); if (!ok) - return throwssl(L, "x509.cert.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert.new"); } else { if (!(*ud = X509_new())) - return throwssl(L, "x509.cert.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert.new"); X509_gmtime_adj(X509_get_notBefore(*ud), 0); X509_gmtime_adj(X509_get_notAfter(*ud), 0); @@ -2904,7 +2917,7 @@ static int xc_getSerial(lua_State *L) { if ((i = X509_get_serialNumber(crt))) { if (!ASN1_INTEGER_to_BN(i, serial)) - return throwssl(L, "x509.cert:getSerial"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:getSerial"); } return 1; @@ -2929,7 +2942,7 @@ static int xc_setSerial(lua_State *L) { error: ASN1_INTEGER_free(serial); - return throwssl(L, "x509.cert:setSerial"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setSerial"); } /* xc_setSerial() */ @@ -2953,7 +2966,7 @@ static int xc_digest(lua_State *L) { BIGNUM *bn = bn_push(L); if (!BN_bin2bn(md, len, bn)) - return throwssl(L, "x509.cert:digest"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:digest"); break; } @@ -3172,11 +3185,11 @@ static int xc_setLifetime(lua_State *L) { ut = lua_tonumber(L, 2); if (!ASN1_TIME_set(X509_get_notBefore(crt), ut)) - return throwssl(L, "x509.cert:setLifetime"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #if 0 } else if ((dt = luaL_optstring(L, 2, 0))) { if (!ASN1_TIME_set_string(X509_get_notBefore(crt), dt)) - return throwssl(L, "x509.cert:setLifetime"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #endif } @@ -3184,11 +3197,11 @@ static int xc_setLifetime(lua_State *L) { ut = lua_tonumber(L, 3); if (!ASN1_TIME_set(X509_get_notAfter(crt), ut)) - return throwssl(L, "x509.cert:setLifetime"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #if 0 } else if ((dt = luaL_optstring(L, 3, 0))) { if (!ASN1_TIME_set_string(X509_get_notAfter(crt), dt)) - return throwssl(L, "x509.cert:setLifetime"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #endif } @@ -3216,7 +3229,7 @@ static int xc_setIssuer(lua_State *L) { X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_set_issuer_name(crt, name)) - return throwssl(L, "x509.cert:setIssuer"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setIssuer"); lua_pushboolean(L, 1); @@ -3242,7 +3255,7 @@ static int xc_setSubject(lua_State *L) { X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_set_subject_name(crt, name)) - return throwssl(L, "x509.cert:setSubject"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setSubject"); lua_pushboolean(L, 1); @@ -3290,7 +3303,7 @@ static int xc_setIssuerAlt(lua_State *L) { GENERAL_NAMES *gens = checksimple(L, 2, X509_GENS_CLASS); if (!X509_add1_ext_i2d(crt, NID_issuer_alt_name, gens, 0, X509V3_ADD_REPLACE)) - return throwssl(L, "x509.altname:setIssuerAlt"); + return auxL_error(L, auxL_EOPENSSL, "x509.altname:setIssuerAlt"); lua_pushboolean(L, 1); @@ -3316,7 +3329,7 @@ static int xc_setSubjectAlt(lua_State *L) { GENERAL_NAMES *gens = checksimple(L, 2, X509_GENS_CLASS); if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, X509V3_ADD_REPLACE)) - return throwssl(L, "x509.altname:setSubjectAlt"); + return auxL_error(L, auxL_EOPENSSL, "x509.altname:setSubjectAlt"); lua_pushboolean(L, 1); @@ -3492,7 +3505,7 @@ static int xc_setBasicConstraint(lua_State *L) { error: BASIC_CONSTRAINTS_free(bs); - return throwssl(L, "x509.cert:setBasicConstraint"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setBasicConstraint"); } /* xc_setBasicConstraint() */ @@ -3522,7 +3535,7 @@ static int xc_addExtension(lua_State *L) { X509_EXTENSION *ext = checksimple(L, 2, X509_EXT_CLASS); if (!X509_add_ext(crt, ext, -1)) - return throwssl(L, "x509.cert:addExtension"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:addExtension"); lua_pushboolean(L, 1); @@ -3572,7 +3585,7 @@ static int xc_getPublicKey(lua_State *L) { EVP_PKEY **key = prepsimple(L, PKEY_CLASS); if (!(*key = X509_get_pubkey(crt))) - return throwssl(L, "x509.cert:getPublicKey"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:getPublicKey"); return 1; } /* xc_getPublicKey() */ @@ -3583,7 +3596,7 @@ static int xc_setPublicKey(lua_State *L) { EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_set_pubkey(crt, key)) - return throwssl(L, "x509.cert:setPublicKey"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:setPublicKey"); lua_pushboolean(L, 1); @@ -3615,7 +3628,7 @@ static int xc_sign(lua_State *L) { EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_sign(crt, key, xc_signature(L, 3, key))) - return throwssl(L, "x509.cert:sign"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:sign"); lua_pushboolean(L, 1); @@ -3673,7 +3686,7 @@ static int xc_text(lua_State *L) { } if (!X509_print_ex(bio, crt, 0, flags)) - return throwssl(L, "x509.cert:text"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:text"); len = BIO_get_mem_data(bio, &data); @@ -3693,11 +3706,11 @@ static int xc__tostring(lua_State *L) { switch (type) { case X509_PEM: if (!PEM_write_bio_X509(bio, crt)) - return throwssl(L, "x509.cert:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:__tostring"); break; case X509_DER: if (!i2d_X509_bio(bio, crt)) - return throwssl(L, "x509.cert:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:__tostring"); break; } /* switch() */ @@ -3796,14 +3809,14 @@ static int xr_new(lua_State *L) { if ((crt = testsimple(L, 1, X509_CERT_CLASS))) { if (!(*ud = X509_to_X509_REQ(crt, 0, 0))) - return throwssl(L, "x509.csr.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); } else if ((data = luaL_optlstring(L, 1, NULL, &len))) { int type = optencoding(L, 2, "*", X509_ANY|X509_PEM|X509_DER); BIO *tmp; int ok = 0; if (!(tmp = BIO_new_mem_buf((char *)data, len))) - return throwssl(L, "x509.csr.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); if (type == X509_PEM || type == X509_ANY) { ok = !!(*ud = PEM_read_bio_X509_REQ(tmp, NULL, 0, "")); /* no password */ @@ -3816,10 +3829,10 @@ static int xr_new(lua_State *L) { BIO_free(tmp); if (!ok) - return throwssl(L, "x509.csr.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); } else { if (!(*ud = X509_REQ_new())) - return throwssl(L, "x509.csr.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); } return 1; @@ -3871,7 +3884,7 @@ static int xr_setSubject(lua_State *L) { X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_REQ_set_subject_name(csr, name)) - return throwssl(L, "x509.csr:setSubject"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr:setSubject"); lua_pushboolean(L, 1); @@ -3884,7 +3897,7 @@ static int xr_getPublicKey(lua_State *L) { EVP_PKEY **key = prepsimple(L, PKEY_CLASS); if (!(*key = X509_REQ_get_pubkey(csr))) - return throwssl(L, "x509.cert:getPublicKey"); + return auxL_error(L, auxL_EOPENSSL, "x509.cert:getPublicKey"); return 1; } /* xr_getPublicKey() */ @@ -3895,7 +3908,7 @@ static int xr_setPublicKey(lua_State *L) { EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_REQ_set_pubkey(csr, key)) - return throwssl(L, "x509.csr:setPublicKey"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr:setPublicKey"); lua_pushboolean(L, 1); @@ -3908,7 +3921,7 @@ static int xr_sign(lua_State *L) { EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_REQ_sign(csr, key, xc_signature(L, 3, key))) - return throwssl(L, "x509.csr:sign"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr:sign"); lua_pushboolean(L, 1); @@ -3926,11 +3939,11 @@ static int xr__tostring(lua_State *L) { switch (type) { case X509_PEM: if (!PEM_write_bio_X509_REQ(bio, csr)) - return throwssl(L, "x509.csr:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr:__tostring"); break; case X509_DER: if (!i2d_X509_REQ_bio(bio, csr)) - return throwssl(L, "x509.csr:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "x509.csr:__tostring"); break; } /* switch() */ @@ -4007,7 +4020,7 @@ static int xx_new(lua_State *L) { int ok = 0; if (!(tmp = BIO_new_mem_buf((char *)data, len))) - return throwssl(L, "x509.crl.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); if (type == X509_PEM || type == X509_ANY) { ok = !!(*ud = PEM_read_bio_X509_CRL(tmp, NULL, 0, "")); /* no password */ @@ -4020,10 +4033,10 @@ static int xx_new(lua_State *L) { BIO_free(tmp); if (!ok) - return throwssl(L, "x509.crl.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); } else { if (!(*ud = X509_CRL_new())) - return throwssl(L, "x509.crl.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); X509_gmtime_adj(X509_CRL_get_lastUpdate(*ud), 0); } @@ -4083,7 +4096,7 @@ static int xx_setLastUpdate(lua_State *L) { /* lastUpdate always present */ if (!ASN1_TIME_set(X509_CRL_get_lastUpdate(crl), updated)) - return throwssl(L, "x509.crl:setLastUpdate"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:setLastUpdate"); lua_pushboolean(L, 1); @@ -4136,7 +4149,7 @@ error: if (time) ASN1_TIME_free(time); - return throwssl(L, "x509.crl:setNextUpdate"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:setNextUpdate"); } /* xx_setNextUpdate() */ @@ -4158,7 +4171,7 @@ static int xx_setIssuer(lua_State *L) { X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_CRL_set_issuer_name(crl, name)) - return throwssl(L, "x509.crl:setIssuer"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:setIssuer"); lua_pushboolean(L, 1); @@ -4212,7 +4225,7 @@ error: if (rev) X509_REVOKED_free(rev); - return throwssl(L, "x509.crl:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:add"); } /* xx_add() */ @@ -4221,7 +4234,7 @@ static int xx_sign(lua_State *L) { EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_CRL_sign(crl, key, xc_signature(L, 3, key))) - return throwssl(L, "x509.crl:sign"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:sign"); lua_pushboolean(L, 1); @@ -4237,7 +4250,7 @@ static int xx_text(lua_State *L) { long len; if (!X509_CRL_print(bio, crl)) - return throwssl(L, "x509.crl:text"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:text"); len = BIO_get_mem_data(bio, &data); @@ -4257,11 +4270,11 @@ static int xx__tostring(lua_State *L) { switch (type) { case X509_PEM: if (!PEM_write_bio_X509_CRL(bio, crl)) - return throwssl(L, "x509.crl:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:__tostring"); break; case X509_DER: if (!i2d_X509_CRL_bio(bio, crl)) - return throwssl(L, "x509.crl:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "x509.crl:__tostring"); break; } /* switch() */ @@ -4365,7 +4378,7 @@ static void xl_dup(lua_State *L, STACK_OF(X509) *src, _Bool copy) { return; error: - throwssl(L, "sk_X509_dup"); + auxL_error(L, auxL_EOPENSSL, "sk_X509_dup"); } /* xl_dup() */ @@ -4373,7 +4386,7 @@ static int xl_new(lua_State *L) { STACK_OF(X509) **chain = prepsimple(L, X509_CHAIN_CLASS); if (!(*chain = sk_X509_new_null())) - return throwssl(L, "x509.chain.new"); + return auxL_error(L, auxL_EOPENSSL, "x509.chain.new"); return 1; } /* xl_new() */ @@ -4390,11 +4403,11 @@ static int xl_add(lua_State *L) { X509 *dup; if (!(dup = X509_dup(crt))) - return throwssl(L, "x509.chain:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.chain:add"); if (!sk_X509_push(chain, dup)) { X509_free(dup); - return throwssl(L, "x509.chain:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.chain:add"); } lua_pushvalue(L, 1); @@ -4421,7 +4434,7 @@ static int xl__next(lua_State *L) { ret = prepsimple(L, X509_CERT_CLASS); if (!(*ret = X509_dup(crt))) - return throwssl(L, "x509.chain:__next"); + return auxL_error(L, auxL_EOPENSSL, "x509.chain:__next"); break; } @@ -4489,7 +4502,7 @@ static int xs_new(lua_State *L) { X509_STORE **ud = prepsimple(L, X509_STORE_CLASS); if (!(*ud = X509_STORE_new())) - return throwssl(L, "x509.store"); + return auxL_error(L, auxL_EOPENSSL, "x509.store"); return 1; } /* xs_new() */ @@ -4510,11 +4523,11 @@ static int xs_add(lua_State *L) { X509 *dup; if (!(dup = X509_dup(crt))) - return throwssl(L, "x509.store:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); if (!X509_STORE_add_cert(store, dup)) { X509_free(dup); - return throwssl(L, "x509.store:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); } } else { const char *path = luaL_checkstring(L, i); @@ -4522,7 +4535,7 @@ static int xs_add(lua_State *L) { int ok; if (0 != stat(path, &st)) - return luaL_error(L, "%s: %s", path, xstrerror(errno)); + return luaL_error(L, "%s: %s", path, aux_strerror(errno)); if (S_ISDIR(st.st_mode)) ok = X509_STORE_load_locations(store, NULL, path); @@ -4530,7 +4543,7 @@ static int xs_add(lua_State *L) { ok = X509_STORE_load_locations(store, path, NULL); if (!ok) - return throwssl(L, "x509.store:add"); + return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); } } @@ -4556,7 +4569,7 @@ static int xs_verify(lua_State *L) { int i, n; if (!(chain = sk_X509_dup(checksimple(L, 3, X509_CHAIN_CLASS)))) - return throwssl(L, "x509.store:verify"); + return auxL_error(L, auxL_EOPENSSL, "x509.store:verify"); n = sk_X509_num(chain); @@ -4569,7 +4582,7 @@ static int xs_verify(lua_State *L) { if (!X509_STORE_CTX_init(&ctx, store, crt, chain)) { sk_X509_pop_free(chain, X509_free); - return throwssl(L, "x509.store:verify"); + return auxL_error(L, auxL_EOPENSSL, "x509.store:verify"); } ERR_clear_error(); @@ -4583,7 +4596,7 @@ static int xs_verify(lua_State *L) { X509_STORE_CTX_cleanup(&ctx); if (!*proof) - return throwssl(L, "x509.store:verify"); + return auxL_error(L, auxL_EOPENSSL, "x509.store:verify"); lua_pushboolean(L, 1); lua_pushvalue(L, -2); @@ -4601,7 +4614,7 @@ static int xs_verify(lua_State *L) { default: X509_STORE_CTX_cleanup(&ctx); - return throwssl(L, "x509.store:verify"); + return auxL_error(L, auxL_EOPENSSL, "x509.store:verify"); } } /* xs_verify() */ @@ -4659,7 +4672,7 @@ static int stx_new(lua_State *L) { STACK_OF(X509) *chain; if (!(*ud = X509_STORE_CTX_new())) - return throwssl(L, "x509.store.context"); + return auxL_error(L, auxL_EOPENSSL, "x509.store.context"); return 1; } /* stx_new() */ @@ -4771,7 +4784,7 @@ error: if (no_kcert) luaL_argerror(L, 1, lua_pushfstring(L, "certificate matching the key not found")); - return throwssl(L, "pkcs12.new"); + return auxL_error(L, auxL_EOPENSSL, "pkcs12.new"); } /* p12_new() */ @@ -4787,7 +4800,7 @@ static int p12__tostring(lua_State *L) { long len; if (!i2d_PKCS12_bio(bio, p12)) - return throwssl(L, "pkcs12:__tostring"); + return auxL_error(L, auxL_EOPENSSL, "pkcs12:__tostring"); len = BIO_get_mem_data(bio, &data); @@ -4908,7 +4921,7 @@ static int sx_new(lua_State *L) { ud = prepsimple(L, SSL_CTX_CLASS); if (!(*ud = SSL_CTX_new(method()))) - return throwssl(L, "ssl.context.new"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context.new"); SSL_CTX_set_options(*ud, options); @@ -4923,9 +4936,9 @@ static int sx_interpose(lua_State *L) { static int sx_setOptions(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - lib_Integer options = lib_checkinteger(L, 2); + auxL_Integer options = auxL_checkinteger(L, 2); - lib_pushinteger(L, SSL_CTX_set_options(ctx, options)); + auxL_pushinteger(L, SSL_CTX_set_options(ctx, options)); return 1; } /* sx_setOptions() */ @@ -4934,7 +4947,7 @@ static int sx_setOptions(lua_State *L) { static int sx_getOptions(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - lib_pushinteger(L, SSL_CTX_get_options(ctx)); + auxL_pushinteger(L, SSL_CTX_get_options(ctx)); return 1; } /* sx_getOptions() */ @@ -4942,9 +4955,9 @@ static int sx_getOptions(lua_State *L) { static int sx_clearOptions(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - lib_Integer options = lib_checkinteger(L, 2); + auxL_Integer options = auxL_checkinteger(L, 2); - lib_pushinteger(L, SSL_CTX_clear_options(ctx, options)); + auxL_pushinteger(L, SSL_CTX_clear_options(ctx, options)); return 1; } /* sx_clearOptions() */ @@ -4998,7 +5011,7 @@ static int sx_setCertificate(lua_State *L) { X509_free(crt); if (!ok) - return throwssl(L, "ssl.context:setCertificate"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCertificate"); lua_pushboolean(L, 1); @@ -5020,7 +5033,7 @@ static int sx_setPrivateKey(lua_State *L) { * private key is actually defined in the object. */ if (!SSL_CTX_use_PrivateKey(ctx, key)) - return throwssl(L, "ssl.context:setPrivateKey"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setPrivateKey"); lua_pushboolean(L, 1); @@ -5033,7 +5046,7 @@ static int sx_setCipherList(lua_State *L) { const char *ciphers = luaL_checkstring(L, 2); if (!SSL_CTX_set_cipher_list(ctx, ciphers)) - return throwssl(L, "ssl.context:setCipherList"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCipherList"); lua_pushboolean(L, 1); @@ -5054,26 +5067,26 @@ static int sx_setEphemeralKey(lua_State *L) { switch (EVP_PKEY_base_id(key)) { case EVP_PKEY_RSA: if (!(tmp = EVP_PKEY_get0(key))) - return throwssl(L, "ssl.context:setEphemeralKey"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); if (!SSL_CTX_set_tmp_rsa(ctx, tmp)) - return throwssl(L, "ssl.context:setEphemeralKey"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); break; case EVP_PKEY_DH: if (!(tmp = EVP_PKEY_get0(key))) - return throwssl(L, "ssl.context:setEphemeralKey"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); if (!SSL_CTX_set_tmp_dh(ctx, tmp)) - return throwssl(L, "ssl.context:setEphemeralKey"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); break; case EVP_PKEY_EC: if (!(tmp = EVP_PKEY_get0(key))) - return throwssl(L, "ssl.context:setEphemeralKey"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); if (!SSL_CTX_set_tmp_ecdh(ctx, tmp)) - return throwssl(L, "ssl.context:setEphemeralKey"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); break; default: @@ -5102,9 +5115,9 @@ static int sx_setAlpnProtos(lua_State *L) { ERR_clear_error(); if (0 != SSL_CTX_set_alpn_protos(ctx, (const unsigned char*)tmp, len)) { if (!ERR_peek_error()) { - return luaL_error(L, "unable to set ALPN protocols: %s", xstrerror(ENOMEM)); + return luaL_error(L, "unable to set ALPN protocols: %s", aux_strerror(ENOMEM)); } else { - return throwssl(L, "ssl.context:setAlpnProtos"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setAlpnProtos"); } } @@ -5163,11 +5176,11 @@ static int sx_setAlpnSelect(lua_State *L) { luaL_checktype(L, 2, LUA_TFUNCTION); if ((error = ex_setdata(L, EX_SSL_CTX_ALPN_SELECT_CB, ctx, 1))) { if (error > 0) { - return luaL_error(L, "unable to set ALPN protocol selection callback: %s", xstrerror(error)); + return luaL_error(L, "unable to set ALPN protocol selection callback: %s", aux_strerror(error)); } else if (!ERR_peek_error()) { return luaL_error(L, "unable to set ALPN protocol selection callback: Unknown internal error"); } else { - return throwssl(L, "ssl.context:setAlpnSelect"); + return auxL_error(L, auxL_EOPENSSL, "ssl.context:setAlpnSelect"); } } @@ -5220,7 +5233,7 @@ static const luaL_Reg sx_globals[] = { { NULL, NULL }, }; -static const integer_Reg sx_verify[] = { +static const auxL_IntegerReg sx_verify[] = { { "VERIFY_NONE", SSL_VERIFY_NONE }, { "VERIFY_PEER", SSL_VERIFY_PEER }, { "VERIFY_FAIL_IF_NO_PEER_CERT", SSL_VERIFY_FAIL_IF_NO_PEER_CERT }, @@ -5228,7 +5241,7 @@ static const integer_Reg sx_verify[] = { { NULL, 0 }, }; -static const integer_Reg sx_option[] = { +static const auxL_IntegerReg sx_option[] = { { "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG }, { "OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG }, { "OP_LEGACY_SERVER_CONNECT", SSL_OP_LEGACY_SERVER_CONNECT }, @@ -5278,8 +5291,8 @@ int luaopen__openssl_ssl_context(lua_State *L) { initall(L); luaL_newlib(L, sx_globals); - lib_setintegers(L, sx_verify); - lib_setintegers(L, sx_option); + auxL_setintegers(L, sx_verify); + auxL_setintegers(L, sx_option); return 1; } /* luaopen__openssl_ssl_context() */ @@ -5313,9 +5326,9 @@ static int ssl_interpose(lua_State *L) { static int ssl_setOptions(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CTX_CLASS); - lib_Integer options = lib_checkinteger(L, 2); + auxL_Integer options = auxL_checkinteger(L, 2); - lib_pushinteger(L, SSL_set_options(ssl, options)); + auxL_pushinteger(L, SSL_set_options(ssl, options)); return 1; } /* ssl_setOptions() */ @@ -5324,7 +5337,7 @@ static int ssl_setOptions(lua_State *L) { static int ssl_getOptions(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CTX_CLASS); - lib_pushinteger(L, SSL_get_options(ssl)); + auxL_pushinteger(L, SSL_get_options(ssl)); return 1; } /* ssl_getOptions() */ @@ -5332,9 +5345,9 @@ static int ssl_getOptions(lua_State *L) { static int ssl_clearOptions(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CTX_CLASS); - lib_Integer options = lib_checkinteger(L, 2); + auxL_Integer options = auxL_checkinteger(L, 2); - lib_pushinteger(L, SSL_clear_options(ssl, options)); + auxL_pushinteger(L, SSL_clear_options(ssl, options)); return 1; } /* ssl_clearOptions() */ @@ -5408,7 +5421,7 @@ static int ssl_setHostName(lua_State *L) { const char *host = luaL_checkstring(L, 2); if (!SSL_set_tlsext_host_name(ssl, host)) - return throwssl(L, "ssl:setHostName"); + return auxL_error(L, auxL_EOPENSSL, "ssl:setHostName"); lua_pushboolean(L, 1); @@ -5498,9 +5511,9 @@ static int ssl_setAlpnProtos(lua_State *L) { ERR_clear_error(); if (0 != SSL_set_alpn_protos(ssl, (const unsigned char*)tmp, len)) { if (!ERR_peek_error()) { - return luaL_error(L, "unable to set ALPN protocols: %s", xstrerror(ENOMEM)); + return luaL_error(L, "unable to set ALPN protocols: %s", aux_strerror(ENOMEM)); } else { - return throwssl(L, "ssl:setAlpnProtos"); + return auxL_error(L, auxL_EOPENSSL, "ssl:setAlpnProtos"); } } @@ -5554,7 +5567,7 @@ static const luaL_Reg ssl_globals[] = { { NULL, NULL }, }; -static const integer_Reg ssl_version[] = { +static const auxL_IntegerReg ssl_version[] = { { "SSL2_VERSION", SSL2_VERSION }, { "SSL3_VERSION", SSL3_VERSION }, { "TLS1_VERSION", TLS1_VERSION }, @@ -5572,9 +5585,9 @@ int luaopen__openssl_ssl(lua_State *L) { initall(L); luaL_newlib(L, ssl_globals); - lib_setintegers(L, ssl_version); - lib_setintegers(L, sx_verify); - lib_setintegers(L, sx_option); + auxL_setintegers(L, ssl_version); + auxL_setintegers(L, sx_verify); + auxL_setintegers(L, sx_option); return 1; } /* luaopen__openssl_ssl() */ @@ -5605,7 +5618,7 @@ static int md_new(lua_State *L) { EVP_MD_CTX_init(ctx); if (!EVP_DigestInit_ex(ctx, type, NULL)) - return throwssl(L, "digest.new"); + return auxL_error(L, auxL_EOPENSSL, "digest.new"); return 1; } /* md_new() */ @@ -5626,7 +5639,7 @@ static void md_update_(lua_State *L, EVP_MD_CTX *ctx, int from, int to) { p = luaL_checklstring(L, i, &n); if (!EVP_DigestUpdate(ctx, p, n)) - throwssl(L, "digest:update"); + auxL_error(L, auxL_EOPENSSL, "digest:update"); } } /* md_update_() */ @@ -5651,7 +5664,7 @@ static int md_final(lua_State *L) { md_update_(L, ctx, 2, lua_gettop(L)); if (!EVP_DigestFinal_ex(ctx, md, &len)) - return throwssl(L, "digest:final"); + return auxL_error(L, auxL_EOPENSSL, "digest:final"); lua_pushlstring(L, (char *)md, len); @@ -5822,7 +5835,7 @@ static int cipher_new(lua_State *L) { EVP_CIPHER_CTX_init(ctx); if (!EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, -1)) - return throwssl(L, "cipher.new"); + return auxL_error(L, auxL_EOPENSSL, "cipher.new"); return 1; } /* cipher_new() */ @@ -5860,7 +5873,7 @@ static int cipher_init(lua_State *L, _Bool encrypt) { return 1; sslerr: - return throwssl(L, (encrypt)? "cipher:encrypt" : "cipher:decrypt"); + return auxL_error(L, auxL_EOPENSSL, (encrypt)? "cipher:encrypt" : "cipher:decrypt"); } /* cipher_init() */ @@ -5919,7 +5932,7 @@ static int cipher_update(lua_State *L) { return 1; sslerr: lua_pushnil(L); - pusherror(L, NULL); + auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } /* cipher_update() */ @@ -5950,7 +5963,7 @@ static int cipher_final(lua_State *L) { return 1; sslerr: lua_pushnil(L); - pusherror(L, NULL); + auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } /* cipher_final() */ @@ -6137,7 +6150,7 @@ static int rand_stir(lua_State *L) { if (error) { lua_pushboolean(L, 0); - lua_pushstring(L, xstrerror(error)); + lua_pushstring(L, aux_strerror(error)); lua_pushinteger(L, error); return 3; @@ -6178,7 +6191,7 @@ static int rand_bytes(lua_State *L) { n = MIN((size - count), LUAL_BUFFERSIZE); if (!RAND_bytes((void *)luaL_prepbuffer(&B), n)) - return throwssl(L, "rand.bytes"); + return auxL_error(L, auxL_EOPENSSL, "rand.bytes"); luaL_addsize(&B, n); count += n; @@ -6201,7 +6214,7 @@ static unsigned long long rand_llu(lua_State *L) { unsigned long long llu; if (!RAND_bytes((void *)&llu, sizeof llu)) - throwssl(L, "rand.uniform"); + auxL_error(L, auxL_EOPENSSL, "rand.uniform"); return llu; } /* rand_llu() */ @@ -6486,13 +6499,8 @@ static void initall(lua_State *L) { static int initssl; int error; - if ((error = mt_init())) { - if (error == -1) { - luaL_error(L, "openssl.init: %s", dlerror()); - } else { - luaL_error(L, "openssl.init: %s", xstrerror(error)); - } - } + if ((error = mt_init())) + auxL_error(L, error, "openssl.init"); pthread_mutex_lock(&mutex); @@ -6512,21 +6520,11 @@ static void initall(lua_State *L) { pthread_mutex_unlock(&mutex); - if ((error = compat_init())) { - if (error == -1) { - throwssl(L, "openssl.init"); - } else { - luaL_error(L, "openssl.init: %s", xstrerror(error)); - } - } + if ((error = compat_init())) + auxL_error(L, error, "openssl.init"); - if ((error = ex_init())) { - if (error == -1) { - throwssl(L, "openssl.init"); - } else { - luaL_error(L, "openssl.init: %s", xstrerror(error)); - } - } + if ((error = ex_init())) + auxL_error(L, error, "openssl.init"); ex_newstate(L); -- cgit v1.2.3-59-g8ed1b From 551ef0b4d84767eaf0c9a88b7a297f19052218e1 Mon Sep 17 00:00:00 2001 From: william Date: Fri, 17 Apr 2015 16:54:40 -0700 Subject: forgot to install our X509_STORE_free replacement --- src/openssl.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 03cc3f7..5872197 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -1,7 +1,7 @@ /* ========================================================================== * openssl.c - Lua OpenSSL * -------------------------------------------------------------------------- - * Copyright (c) 2012-2014 William Ahern + * Copyright (c) 2012-2015 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -831,8 +831,14 @@ static int compat_init(void) { } else { /* * Because our onfree callback was invoked, X509_STORE_free - * appears not to obey reference counts. Ensure that our - * fixed version is called on SSL_CTX destruction. + * appears not to obey reference counts. Use our fixed + * version in our own code. + */ + compat.X509_STORE_free = &compat_X509_STORE_free; + + /* + * Ensure that our fixed version is called on SSL_CTX + * destruction. * * NB: We depend on the coincidental order of operations in * SSL_CTX_free that user data destruction occurs before -- cgit v1.2.3-59-g8ed1b From 23eafb649ad3e5a8fec499986ecafc453901548a Mon Sep 17 00:00:00 2001 From: william Date: Fri, 17 Apr 2015 19:09:28 -0700 Subject: finish setAlpnSelect --- src/openssl.c | 74 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 5872197..77cec55 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -30,7 +30,7 @@ #include /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ #include /* struct tm time_t strptime(3) time(2) */ #include /* tolower(3) */ -#include /* ENOMEM ENOTSUP errno */ +#include /* ENOMEM ENOTSUP EOVERFLOW errno */ #include /* assert */ #include /* ssize_t pid_t */ @@ -881,7 +881,7 @@ struct ex_state { }; /* struct ex_state */ #ifndef EX_DATA_MAXARGS -#define EX_DATA_MAXARGS 4 +#define EX_DATA_MAXARGS 8 #endif struct ex_data { @@ -1058,6 +1058,9 @@ static int ex_setdata(lua_State *L, int _type, void *obj, size_t n) { struct ex_data *data; size_t i, j; + if (n > countof(data->arg)) + return EOVERFLOW; + if ((data = type->get_ex_data(obj, type->index)) && data->state) { for (i = 0; i < countof(data->arg); i++) { auxL_unref(L, &data->arg[i]); @@ -1069,7 +1072,7 @@ static int ex_setdata(lua_State *L, int _type, void *obj, size_t n) { return errno; if (!type->set_ex_data(obj, type->index, data)) - return -1; + return auxL_EOPENSSL; data->state = state; data->refs = 1; @@ -5139,37 +5142,64 @@ static SSL *ssl_push(lua_State *, SSL *); static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *_ctx) { SSL_CTX *ctx = _ctx; lua_State *L = NULL; - size_t n; - int top, status; + size_t n, protolen, tmpsiz; + int otop, status; + const void *proto; + void *tmpbuf; - if (0 == (n = ex_getdata(&L, EX_SSL_CTX_ALPN_SELECT_CB, ctx))) + *out = NULL; + *outlen = 0; + + /* always expect function (1st) and return string buffer (Nth) */ + if ((n = ex_getdata(&L, EX_SSL_CTX_ALPN_SELECT_CB, ctx)) < 2) return SSL_TLSEXT_ERR_ALERT_FATAL; - top = lua_gettop(L) - n; + otop = lua_gettop(L) - n; /* TODO: Install temporary panic handler to catch OOM errors */ - /* pass the SSL object as first argument */ + /* pass SSL object as 1st argument */ ssl_push(L, ssl); + lua_insert(L, otop + 3); + + /* pass table of protocol names as 2nd argument */ pushprotos(L, in, inlen); + lua_insert(L, otop + 4); + + if (LUA_OK != (status = lua_pcall(L, 2 + (n - 2), 1, 0))) + goto fatal; + + /* did we get a string result? */ + if (!(proto = lua_tolstring(L, -1, &protolen))) + goto noack; + + /* will it fit in our return buffer? */ + if (!(tmpbuf = lua_touserdata(L, otop + 1))) + goto fatal; - /* TODO: lua_rotate ssl and protocols table into position. */ + tmpsiz = lua_rawlen(L, otop + 1); - if (LUA_OK != (status = lua_pcall(L, 2 + (n - 1), 1, 0))) + if (protolen > tmpsiz) goto fatal; - /* TODO: check return value */ - (void)out; (void)outlen; + memcpy(tmpbuf, proto, protolen); + + /* + * NB: Our return buffer is anchored using the luaL_ref API, so even + * once we pop the stack it will remain valid. + */ + *out = tmpbuf; + *outlen = protolen; - lua_settop(L, top); + lua_settop(L, otop); return SSL_TLSEXT_ERR_OK; fatal: - lua_settop(L, top); + lua_settop(L, otop); return SSL_TLSEXT_ERR_ALERT_FATAL; noack: - lua_settop(L, top); + lua_settop(L, otop); return SSL_TLSEXT_ERR_NOACK; } /* sx_setAlpnSelect_cb() */ @@ -5180,13 +5210,18 @@ static int sx_setAlpnSelect(lua_State *L) { int error; luaL_checktype(L, 2, LUA_TFUNCTION); - if ((error = ex_setdata(L, EX_SSL_CTX_ALPN_SELECT_CB, ctx, 1))) { + + /* allocate space to store the selected protocol in our callback */ + lua_newuserdata(L, UCHAR_MAX); + lua_insert(L, 2); + + if ((error = ex_setdata(L, EX_SSL_CTX_ALPN_SELECT_CB, ctx, lua_gettop(L) - 1))) { if (error > 0) { return luaL_error(L, "unable to set ALPN protocol selection callback: %s", aux_strerror(error)); - } else if (!ERR_peek_error()) { + } else if (error == auxL_EOPENSSL && !ERR_peek_error()) { return luaL_error(L, "unable to set ALPN protocol selection callback: Unknown internal error"); } else { - return auxL_error(L, auxL_EOPENSSL, "ssl.context:setAlpnSelect"); + return auxL_error(L, error, "ssl.context:setAlpnSelect"); } } @@ -5224,6 +5259,9 @@ static const luaL_Reg sx_methods[] = { { "setEphemeralKey", &sx_setEphemeralKey }, #if HAVE_SSL_CTX_SET_ALPN_PROTOS { "setAlpnProtos", &sx_setAlpnProtos }, +#endif +#if HAVE_SSL_CTX_SET_ALPN_SELECT_CB + { "setAlpnSelect", &sx_setAlpnSelect }, #endif { NULL, NULL }, }; -- cgit v1.2.3-59-g8ed1b From 3a1ed42149c48c2dfdca86e0c730c1fa91f11324 Mon Sep 17 00:00:00 2001 From: william Date: Mon, 20 Apr 2015 13:19:02 -0700 Subject: add missing line continuation to LIST_INSERT_HEAD macro, and fix stale code comment --- src/openssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 77cec55..5331501 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -111,7 +111,7 @@ LIST_NEXT((elm), field)->field.le_prev = (elm)->field.le_prev; \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \ } while (0) -#define LIST_INSERT_HEAD(head, elm, field) do { +#define LIST_INSERT_HEAD(head, elm, field) do { \ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ LIST_FIRST((head)) = (elm); \ @@ -5150,7 +5150,7 @@ static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned cha *out = NULL; *outlen = 0; - /* always expect function (1st) and return string buffer (Nth) */ + /* expect at least two values: return buffer and closure */ if ((n = ex_getdata(&L, EX_SSL_CTX_ALPN_SELECT_CB, ctx)) < 2) return SSL_TLSEXT_ERR_ALERT_FATAL; -- cgit v1.2.3-59-g8ed1b