From d4aa420319bff15a6f84f679c6374dda7cf1b0f2 Mon Sep 17 00:00:00 2001 From: William Ahern Date: Mon, 9 Dec 2013 20:56:25 -0800 Subject: move newly split files into src/ directory --- GNUmakefile | 214 --- Makefile | 7 - compat52.h | 152 -- openssl.bignum.lua | 3 - openssl.c | 3929 ------------------------------------------ openssl.cipher.lua | 3 - openssl.digest.lua | 3 - openssl.hmac.lua | 3 - openssl.pubkey.lua | 4 - openssl.rand.lua | 3 - openssl.ssl.context.lua | 3 - openssl.ssl.lua | 3 - openssl.x509.altname.lua | 13 - openssl.x509.chain.lua | 3 - openssl.x509.lua | 3 - openssl.x509.name.lua | 13 - openssl.x509.store.lua | 3 - src/GNUmakefile | 214 +++ src/Makefile | 7 + src/compat52.h | 152 ++ src/openssl.bignum.lua | 3 + src/openssl.c | 3929 ++++++++++++++++++++++++++++++++++++++++++ src/openssl.cipher.lua | 3 + src/openssl.digest.lua | 3 + src/openssl.hmac.lua | 3 + src/openssl.pubkey.lua | 4 + src/openssl.rand.lua | 3 + src/openssl.ssl.context.lua | 3 + src/openssl.ssl.lua | 3 + src/openssl.x509.altname.lua | 13 + src/openssl.x509.chain.lua | 3 + src/openssl.x509.lua | 3 + src/openssl.x509.name.lua | 13 + src/openssl.x509.store.lua | 3 + 34 files changed, 4362 insertions(+), 4362 deletions(-) delete mode 100644 GNUmakefile delete mode 100644 Makefile delete mode 100644 compat52.h delete mode 100644 openssl.bignum.lua delete mode 100644 openssl.c delete mode 100644 openssl.cipher.lua delete mode 100644 openssl.digest.lua delete mode 100644 openssl.hmac.lua delete mode 100644 openssl.pubkey.lua delete mode 100644 openssl.rand.lua delete mode 100644 openssl.ssl.context.lua delete mode 100644 openssl.ssl.lua delete mode 100644 openssl.x509.altname.lua delete mode 100644 openssl.x509.chain.lua delete mode 100644 openssl.x509.lua delete mode 100644 openssl.x509.name.lua delete mode 100644 openssl.x509.store.lua create mode 100644 src/GNUmakefile create mode 100644 src/Makefile create mode 100644 src/compat52.h create mode 100644 src/openssl.bignum.lua create mode 100644 src/openssl.c create mode 100644 src/openssl.cipher.lua create mode 100644 src/openssl.digest.lua create mode 100644 src/openssl.hmac.lua create mode 100644 src/openssl.pubkey.lua create mode 100644 src/openssl.rand.lua create mode 100644 src/openssl.ssl.context.lua create mode 100644 src/openssl.ssl.lua create mode 100644 src/openssl.x509.altname.lua create mode 100644 src/openssl.x509.chain.lua create mode 100644 src/openssl.x509.lua create mode 100644 src/openssl.x509.name.lua create mode 100644 src/openssl.x509.store.lua diff --git a/GNUmakefile b/GNUmakefile deleted file mode 100644 index fcf79a6..0000000 --- a/GNUmakefile +++ /dev/null @@ -1,214 +0,0 @@ -# non-recursive prologue -sp := $(sp).x -dirstack_$(sp) := $(d) -d := $(abspath $(lastword $(MAKEFILE_LIST))/..) - -ifeq ($(origin GUARD_$(d)), undefined) -GUARD_$(d) := 1 - - -# -# E N V I R O N M E N T C O N F I G U R A T I O N -# -include $(d)/../GNUmakefile - - -# -# C O M P I L A T I O N F L A G S -# -OS_$(d) = $(shell $(d)/../mk/vendor.os) -CC_$(d) = $(shell $(d)/../mk/vendor.cc) -LUAPATH_$(d) = $(shell env CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" $(" - -help: $(d)/help - - -endif # include guard - -# non-recursive epilogue -d := $(dirstack_$(sp)) -sp := $(basename $(sp)) diff --git a/Makefile b/Makefile deleted file mode 100644 index d0f0d47..0000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -.POSIX: - -all: - +gmake -f GNUmakefile all - -.DEFAULT: - +gmake -f GNUmakefile $< diff --git a/compat52.h b/compat52.h deleted file mode 100644 index 96ec9b2..0000000 --- a/compat52.h +++ /dev/null @@ -1,152 +0,0 @@ -/* ========================================================================== - * compat52.h - Routines for Lua 5.2 compatibility - * -------------------------------------------------------------------------- - * Copyright (c) 2012 William Ahern - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * ========================================================================== - */ -#if LUA_VERSION_NUM < 502 - -#define LUA_OK 0 - - -static void luaL_setmetatable(lua_State *L, const char *tname) { - luaL_getmetatable(L, tname); - lua_setmetatable(L, -2); -} /* luaL_setmetatable() */ - - -static int lua_absindex(lua_State *L, int idx) { - return (idx > 0 || idx <= LUA_REGISTRYINDEX)? idx : lua_gettop(L) + idx + 1; -} /* lua_absindex() */ - - -static void *luaL_testudata(lua_State *L, int arg, const char *tname) { - void *p = lua_touserdata(L, arg); - int eq; - - if (!p || !lua_getmetatable(L, arg)) - return 0; - - luaL_getmetatable(L, tname); - eq = lua_rawequal(L, -2, -1); - lua_pop(L, 2); - - return (eq)? p : 0; -} /* luaL_testudate() */ - - -static void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { - int i, t = lua_absindex(L, -1 - nup); - - for (; l->name; l++) { - for (i = 0; i < nup; i++) - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); - lua_setfield(L, t, l->name); - } - - lua_pop(L, nup); -} /* luaL_setfuncs() */ - - -#define luaL_newlibtable(L, l) \ - lua_createtable(L, 0, (sizeof (l) / sizeof *(l)) - 1) - -#define luaL_newlib(L, l) \ - (luaL_newlibtable((L), (l)), luaL_setfuncs((L), (l), 0)) - - -static void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) { - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); - lua_call(L, 1, 1); - - lua_getglobal(L, "package"); - lua_getfield(L, -1, "loaded"); - lua_pushvalue(L, -3); - lua_setfield(L, -2, modname); - - lua_pop(L, 2); - - if (glb) { - lua_pushvalue(L, -1); - lua_setglobal(L, modname); - } -} /* luaL_requiref() */ - - -#define lua_resume(L, from, nargs) lua_resume((L), (nargs)) - - -static void lua_rawgetp(lua_State *L, int index, const void *p) { - index = lua_absindex(L, index); - lua_pushlightuserdata(L, (void *)p); - lua_rawget(L, index); -} /* lua_rawgetp() */ - -static void lua_rawsetp(lua_State *L, int index, const void *p) { - index = lua_absindex(L, index); - lua_pushlightuserdata(L, (void *)p); - lua_pushvalue(L, -2); - lua_rawset(L, index); - lua_pop(L, 1); -} /* lua_rawsetp() */ - - -#ifndef LUA_UNSIGNED -#define LUA_UNSIGNED unsigned -#endif - -typedef LUA_UNSIGNED lua_Unsigned; - - -static void lua_pushunsigned(lua_State *L, lua_Unsigned n) { - lua_pushnumber(L, (lua_Number)n); -} /* lua_pushunsigned() */ - -static lua_Unsigned luaL_checkunsigned(lua_State *L, int arg) { - return (lua_Unsigned)luaL_checknumber(L, arg); -} /* luaL_checkunsigned() */ - - -static lua_Unsigned luaL_optunsigned(lua_State *L, int arg, lua_Unsigned def) { - return (lua_Unsigned)luaL_optnumber(L, arg, (lua_Number)def); -} /* luaL_optunsigned() */ - - -#ifndef LUA_FILEHANDLE /* Not defined by earlier LuaJIT releases */ -#define LUA_FILEHANDLE "FILE*" -#endif - -/* - * Lua 5.1 userdata is a simple FILE *, while LuaJIT is a struct with the - * first member a FILE *, similar to Lua 5.2. - */ -typedef struct luaL_Stream { - FILE *f; -} luaL_Stream; - - -#define lua_rawlen(...) lua_objlen(__VA_ARGS__) - - -#endif /* LUA_VERSION_NUM < 502 */ diff --git a/openssl.bignum.lua b/openssl.bignum.lua deleted file mode 100644 index 3090a68..0000000 --- a/openssl.bignum.lua +++ /dev/null @@ -1,3 +0,0 @@ -local bignum = require"_openssl.bignum" - -return bignum diff --git a/openssl.c b/openssl.c deleted file mode 100644 index c8af43d..0000000 --- a/openssl.c +++ /dev/null @@ -1,3929 +0,0 @@ -/* ========================================================================== - * openssl.c - Lua OpenSSL - * -------------------------------------------------------------------------- - * Copyright (c) 2012 William Ahern - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * ========================================================================== - */ -#ifndef L_OPENSSL_H -#define L_OPENSSH_H - -#include /* INT_MAX INT_MIN */ -#include /* memset(3) */ -#include /* strcasecmp(3) */ -#include /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ -#include /* struct tm time_t strptime(3) */ - -#include -#include /* struct stat stat(2) */ -#include /* AF_INET AF_INET6 */ - -#include /* struct in_addr struct in6_addr */ -#include /* inet_pton(3) */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if LUA_VERSION_NUM < 502 -#include "compat52.h" -#endif - -#define BIGNUM_CLASS "BIGNUM*" -#define PUBKEY_CLASS "EVP_PKEY*" -#define X509_NAME_CLASS "X509_NAME*" -#define X509_GENS_CLASS "GENERAL_NAMES*" -#define X509_CERT_CLASS "X509*" -#define X509_CHAIN_CLASS "STACK_OF(X509)*" -#define X509_CSR_CLASS "X509_REQ*" -#define X509_STORE_CLASS "X509_STORE*" -#define X509_STCTX_CLASS "X509_STORE_CTX*" -#define SSL_CTX_CLASS "SSL_CTX*" -#define SSL_CLASS "SSL*" -#define DIGEST_CLASS "EVP_MD_CTX" /* not a pointer */ -#define HMAC_CLASS "HMAC_CTX" /* not a pointer */ -#define CIPHER_CLASS "EVP_CIPHER_CTX" /* not a pointer */ - - -#define countof(a) (sizeof (a) / sizeof *(a)) -#define endof(a) (&(a)[countof(a)]) - -#define CLAMP(i, min, max) (((i) < (min))? (min) : ((i) > (max))? (max) : (i)) - -#undef MIN -#define MIN(a, b) (((a) < (b))? (a) : (b)) - -#define stricmp(a, b) strcasecmp((a), (b)) -#define strieq(a, b) (!stricmp((a), (b))) - -#define SAY_(file, func, line, fmt, ...) \ - fprintf(stderr, "%s:%d: " fmt "%s", __func__, __LINE__, __VA_ARGS__) - -#define SAY(...) SAY_(__FILE__, __func__, __LINE__, __VA_ARGS__, "\n") - -#define HAI SAY("hai") - - -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); - - if (tname) { - luaL_setmetatable(L, tname); - } else { - lua_newtable(L); - lua_pushcfunction(L, gc); - lua_setfield(L, -2, "__gc"); - lua_setmetatable(L, -2); - } - - return p; -} /* prepudata() */ - - -static void *prepsimple(lua_State *L, const char *tname, int (*gc)(lua_State *)) { - void **p = prepudata(L, sizeof (void *), tname, gc); - return p; -} /* prepsimple() */ - -#define prepsimple_(a, b, c, ...) prepsimple((a), (b), (c)) -#define prepsimple(...) prepsimple_(__VA_ARGS__, 0) - - -static void *checksimple(lua_State *L, int index, const char *tname) { - void **p; - - if (tname) { - p = luaL_checkudata(L, index, tname); - } else { - luaL_checktype(L, index, LUA_TUSERDATA); - p = lua_touserdata(L, index); - } - - return *p; -} /* checksimple() */ - - -static void *testsimple(lua_State *L, int index, const char *tname) { - void **p; - - if (tname) { - p = luaL_testudata(L, index, tname); - } else { - luaL_checktype(L, index, LUA_TUSERDATA); - p = lua_touserdata(L, index); - } - - return (p)? *p : (void *)0; -} /* testsimple() */ - - -static const char *pusherror(lua_State *L, const char *fun) { - unsigned long code; - const char *path, *file; - int line; - char txt[256]; - - 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); - - if (!strncmp("__", luaL_checkstring(L, 1), 2)) - lua_pushvalue(L, -1); - else - lua_getfield(L, -1, "__index"); - - lua_pushvalue(L, -4); /* push method name */ - lua_gettable(L, -2); /* push old method */ - - lua_pushvalue(L, -5); /* push method name */ - lua_pushvalue(L, -5); /* push new method */ - lua_settable(L, -4); /* replace old method */ - - return 1; /* return old method */ -} /* interpose() */ - - -static void addclass(lua_State *L, const char *name, const luaL_Reg *methods, const luaL_Reg *metamethods) { - if (luaL_newmetatable(L, name)) { - luaL_setfuncs(L, metamethods, 0); - lua_newtable(L); - luaL_setfuncs(L, methods, 0); - lua_setfield(L, -2, "__index"); - lua_pop(L, 1); - } -} /* addclass() */ - - -static int checkoption(struct lua_State *L, int index, const char *def, const char *opts[]) { - const char *opt = (def)? luaL_optstring(L, index, def) : luaL_checkstring(L, index); - int i; - - for (i = 0; opts[i]; i++) { - if (strieq(opts[i], opt)) - return i; - } - - return luaL_argerror(L, index, lua_pushfstring(L, "invalid option %s", opt)); -} /* checkoption() */ - - -static _Bool getfield(lua_State *L, int index, const char *k) { - lua_getfield(L, index, k); - - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - - return 0; - } else { - return 1; - } -} /* getfield() */ - - -static _Bool loadfield(lua_State *L, int index, const char *k, int type, void *p) { - if (!getfield(L, index, k)) - return 0; - - switch (type) { - case LUA_TSTRING: - *(const char **)p = luaL_checkstring(L, -1); - break; - case LUA_TNUMBER: - *(lua_Number *)p = luaL_checknumber(L, -1); - break; - default: - luaL_error(L, "loadfield(type=%d): invalid type", type); - break; - } /* switch() */ - - lua_pop(L, 1); /* table keeps reference */ - - return 1; -} /* loadfield() */ - - -static const char *pushnid(lua_State *L, int nid) { - const char *txt; - ASN1_OBJECT *obj; - char buf[256]; - int len; - - if ((txt = OBJ_nid2sn(nid)) || (txt = OBJ_nid2ln(nid))) { - lua_pushstring(L, txt); - } else { - if (!(obj = OBJ_nid2obj(nid))) - luaL_error(L, "%d: unknown ASN.1 NID", nid); - - if (-1 == (len = OBJ_obj2txt(buf, sizeof buf, obj, 1))) - luaL_error(L, "%d: invalid ASN.1 NID", nid); - - lua_pushlstring(L, buf, len); - } - - return lua_tostring(L, -1); -} /* pushnid() */ - - -static void initall(lua_State *L); - - -/* - * BIGNUM - openssl.bignum - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static BIGNUM *bn_push(lua_State *L) { - BIGNUM **ud = prepsimple(L, BIGNUM_CLASS); - - if (!(*ud = BN_new())) - throwssl(L, "bignum.new"); - - return *ud; -} /* bn_push() */ - - -#define checkbig_(a, b, c, ...) checkbig((a), (b), (c)) -#define checkbig(...) checkbig_(__VA_ARGS__, &(_Bool){ 0 }) - -static BIGNUM *(checkbig)(lua_State *, int, _Bool *); - -static int bn_new(lua_State *L) { - int i, n; - - if ((n = lua_gettop(L)) > 0) { - for (i = 1; i <= n; i++) - checkbig(L, i); - - return n; - } else { - bn_push(L); - - return 1; - } -} /* bn_new() */ - - -static int bn_interpose(lua_State *L) { - return interpose(L, BIGNUM_CLASS); -} /* bn_interpose() */ - - -/* return integral part */ -static inline double intof(double f) { - return (isfinite(f))? floor(fabs(f)) : 0.0; -} /* intof() */ - - -/* convert integral to BN_ULONG. returns success or failure. */ -static _Bool int2ul(BN_ULONG *ul, double f) { - int exp; - - frexp(f, &exp); - - if (exp > (int)sizeof *ul * 8) - return 0; - - *ul = (BN_ULONG)f; - - return 1; -} /* int2ul() */ - - -/* convert integral BIGNUM. returns success or failure. */ -static _Bool int2bn(BIGNUM **bn, double q) { - unsigned char nib[32], bin[32], *p; - size_t i, n; - double r; - - p = nib; - - while (q >= 1.0 && p < endof(nib)) { - r = fmod(q, 256.0); - *p++ = r; - q = round((q - r) / 256.0); - } - - n = p - nib; - - for (i = 0; i < n; i++) { - bin[i] = *--p; - } - - if (!(*bn = BN_bin2bn(bin, n, *bn))) - return 0; - - return 1; -} /* int2bn() */ - - -/* convert double to BIGNUM. returns success or failure. */ -static _Bool f2bn(BIGNUM **bn, double f) { - double i = intof(f); - BN_ULONG lu; - - if (int2ul(&lu, i)) { - if (!*bn && !(*bn = BN_new())) - return 0; - - if (!BN_set_word(*bn, lu)) - return 0; - } else if (!int2bn(bn, i)) - return 0; - - BN_set_negative(*bn, signbit(f)); - - return 1; -} /* f2bn() */ - - -static BIGNUM *(checkbig)(lua_State *L, int index, _Bool *lvalue) { - BIGNUM **bn; - const char *dec; - size_t len; - - index = lua_absindex(L, index); - - switch (lua_type(L, index)) { - case LUA_TSTRING: - *lvalue = 0; - - dec = lua_tolstring(L, index, &len); - - luaL_argcheck(L, len > 0 && *dec, index, "invalid big number string"); - - bn = prepsimple(L, BIGNUM_CLASS); - - if (!BN_dec2bn(bn, dec)) - throwssl(L, "bignum"); - - lua_replace(L, index); - - return *bn; - case LUA_TNUMBER: - *lvalue = 0; - - bn = prepsimple(L, BIGNUM_CLASS); - - if (!f2bn(bn, lua_tonumber(L, index))) - throwssl(L, "bignum"); - - lua_replace(L, index); - - return *bn; - default: - *lvalue = 1; - - return checksimple(L, index, BIGNUM_CLASS); - } /* switch() */ -} /* checkbig() */ - - -static void bn_prepops(lua_State *L, BIGNUM **r, BIGNUM **a, BIGNUM **b, _Bool commute) { - _Bool lvalue = 1; - - lua_settop(L, 2); /* a, b */ - - *a = checkbig(L, 1, &lvalue); - - if (!lvalue && commute) - lua_pushvalue(L, 1); - - *b = checkbig(L, 2, &lvalue); - - if (!lvalue && commute && lua_gettop(L) < 3) - lua_pushvalue(L, 2); - - if (lua_gettop(L) < 3) - bn_push(L); - - *r = *(BIGNUM **)lua_touserdata(L, 3); -} /* bn_prepops() */ - - -static int ctx__gc(lua_State *L) { - BN_CTX **ctx = lua_touserdata(L, 1); - - BN_CTX_free(*ctx); - *ctx = NULL; - - return 0; -} /* ctx__gc() */ - -static BN_CTX *getctx(lua_State *L) { - BN_CTX **ctx; - - lua_pushcfunction(L, &ctx__gc); - lua_gettable(L, LUA_REGISTRYINDEX); - - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - - ctx = prepsimple(L, NULL, &ctx__gc); - - if (!(*ctx = BN_CTX_new())) - throwssl(L, "bignum"); - - lua_pushcfunction(L, &ctx__gc); - lua_pushvalue(L, -2); - lua_settable(L, LUA_REGISTRYINDEX); - } - - ctx = lua_touserdata(L, -1); - lua_pop(L, 1); - - return *ctx; -} /* getctx() */ - - -static int bn__add(lua_State *L) { - BIGNUM *r, *a, *b; - - bn_prepops(L, &r, &a, &b, 1); - - if (!BN_add(r, a, b)) - return throwssl(L, "bignum:__add"); - - return 1; -} /* bn__add() */ - - -static int bn__sub(lua_State *L) { - BIGNUM *r, *a, *b; - - bn_prepops(L, &r, &a, &b, 0); - - if (!BN_sub(r, a, b)) - return throwssl(L, "bignum:__sub"); - - return 1; -} /* bn__sub() */ - - -static int bn__mul(lua_State *L) { - BIGNUM *r, *a, *b; - - bn_prepops(L, &r, &a, &b, 1); - - if (!BN_mul(r, a, b, getctx(L))) - return throwssl(L, "bignum:__mul"); - - return 1; -} /* bn__mul() */ - - -static int bn__div(lua_State *L) { - BIGNUM *r, *a, *b; - BN_CTX *ctx; - - bn_prepops(L, &r, &a, &b, 0); - - if (!BN_div(r, NULL, a, b, getctx(L))) - return throwssl(L, "bignum:__div"); - - return 1; -} /* bn__div() */ - - -static int bn__mod(lua_State *L) { - BIGNUM *r, *a, *b; - BN_CTX *ctx; - - bn_prepops(L, &r, &a, &b, 0); - - if (!BN_mod(r, a, b, getctx(L))) - return throwssl(L, "bignum:__mod"); - - return 1; -} /* bn__mod() */ - - -static int bn__pow(lua_State *L) { - BIGNUM *r, *a, *b; - BN_CTX *ctx; - - bn_prepops(L, &r, &a, &b, 0); - - if (!BN_exp(r, a, b, getctx(L))) - return throwssl(L, "bignum:__pow"); - - return 1; -} /* bn__pow() */ - - -static int bn__unm(lua_State *L) { - BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); - - BN_set_negative(a, !BN_is_negative(a)); - - return 1; -} /* bn__unm() */ - - -static int bn__eq(lua_State *L) { - BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); - BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); - - lua_pushboolean(L, 0 == BN_cmp(a, b)); - - return 1; -} /* bn__eq() */ - - -static int bn__lt(lua_State *L) { - BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); - BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); - int cmp = BN_cmp(a, b); - - lua_pushboolean(L, cmp == -1); - - return 1; -} /* bn__lt() */ - - -static int bn__le(lua_State *L) { - BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); - BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); - int cmp = BN_cmp(a, b); - - lua_pushboolean(L, cmp <= 0); - - return 1; -} /* bn__le() */ - - -static int bn__gc(lua_State *L) { - BIGNUM **ud = luaL_checkudata(L, 1, BIGNUM_CLASS); - - BN_free(*ud); - *ud = NULL; - - return 0; -} /* bn__gc() */ - - -static int bn__tostring(lua_State *L) { - BIGNUM *bn = checksimple(L, 1, BIGNUM_CLASS); - char *txt; - - if (!(txt = BN_bn2dec(bn))) - throwssl(L, "bignum:__tostring"); - - lua_pushstring(L, txt); - - return 1; -} /* bn__tostring() */ - - -static const luaL_Reg bn_methods[] = { - { NULL, NULL }, -}; - -static const luaL_Reg bn_metatable[] = { - { "__add", &bn__add }, - { "__sub", &bn__sub }, - { "__mul", &bn__mul }, - { "__div", &bn__div }, - { "__mod", &bn__mod }, - { "__pow", &bn__pow }, - { "__unm", &bn__unm }, - { "__eq", &bn__eq }, - { "__lt", &bn__lt }, - { "__le", &bn__le }, - { "__gc", &bn__gc }, - { "__tostring", &bn__tostring }, - { NULL, NULL }, -}; - - -static const luaL_Reg bn_globals[] = { - { "new", &bn_new }, - { "interpose", &bn_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_bignum(lua_State *L) { - initall(L); - - luaL_newlib(L, bn_globals); - - return 1; -} /* luaopen__openssl_bignum() */ - - -/* - * EVP_PKEY - openssl.pubkey - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static int bio__gc(lua_State *L) { - BIO **bio = lua_touserdata(L, 1); - - BIO_free(*bio); - *bio = NULL; - - return 0; -} /* bio__gc() */ - -static BIO *getbio(lua_State *L) { - BIO **bio; - - lua_pushcfunction(L, &bio__gc); - lua_gettable(L, LUA_REGISTRYINDEX); - - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - - bio = prepsimple(L, NULL, &bio__gc); - - if (!(*bio = BIO_new(BIO_s_mem()))) - throwssl(L, "BIO_new"); - - lua_pushcfunction(L, &bio__gc); - lua_pushvalue(L, -2); - lua_settable(L, LUA_REGISTRYINDEX); - } - - bio = lua_touserdata(L, -1); - lua_pop(L, 1); - - BIO_reset(*bio); - - return *bio; -} /* getbio() */ - - -static int pk_new(lua_State *L) { - EVP_PKEY **ud; - - lua_settop(L, 1); - - ud = prepsimple(L, PUBKEY_CLASS); - - if (lua_istable(L, 1)) { - int type = EVP_PKEY_RSA; - unsigned bits = 1024; - unsigned exp = 65537; - int curve = NID_X9_62_prime192v1; - const char *id; - lua_Number n; - - if (!lua_istable(L, 1)) - goto creat; - - if (loadfield(L, 1, "type", LUA_TSTRING, &id)) { - static const struct { int nid; const char *sn; } types[] = { - { EVP_PKEY_RSA, "RSA" }, - { EVP_PKEY_DSA, "DSA" }, - { EVP_PKEY_DH, "DH" }, - { EVP_PKEY_EC, "EC" }, - }; - unsigned i; - - type = OBJ_sn2nid(id); - - if (NID_undef == (type = EVP_PKEY_type(OBJ_sn2nid(id)))) { - for (i = 0; i < countof(types); i++) { - if (strieq(id, types[i].sn)) { - type = types[i].nid; - break; - } - } - } - - luaL_argcheck(L, type != NID_undef, 1, lua_pushfstring(L, "%s: invalid key type", id)); - } - - if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { - luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); - bits = (unsigned)n; - } - - if (loadfield(L, 1, "exp", LUA_TNUMBER, &n)) { - luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `exp' invalid", n)); - exp = (unsigned)n; - } - - if (loadfield(L, 1, "curve", LUA_TSTRING, &id)) { - curve = OBJ_sn2nid(id); - luaL_argcheck(L, curve != NID_undef, 1, lua_pushfstring(L, "%s: invalid curve", id)); - } - -creat: - if (!(*ud = EVP_PKEY_new())) - return throwssl(L, "pubkey.new"); - - switch (EVP_PKEY_type(type)) { - case EVP_PKEY_RSA: { - RSA *rsa; - - if (!(rsa = RSA_generate_key(bits, exp, 0, 0))) - return throwssl(L, "pubkey.new"); - - EVP_PKEY_set1_RSA(*ud, rsa); - - RSA_free(rsa); - - break; - } - case EVP_PKEY_DSA: { - DSA *dsa; - - if (!(dsa = DSA_generate_parameters(bits, 0, 0, 0, 0, 0, 0))) - return throwssl(L, "pubkey.new"); - - if (!DSA_generate_key(dsa)) { - DSA_free(dsa); - return throwssl(L, "pubkey.new"); - } - - EVP_PKEY_set1_DSA(*ud, dsa); - - DSA_free(dsa); - - break; - } - case EVP_PKEY_DH: { - DH *dh; - - if (!(dh = DH_generate_parameters(bits, exp, 0, 0))) - return throwssl(L, "pubkey.new"); - - if (!DH_generate_key(dh)) { - DH_free(dh); - return throwssl(L, "pubkey.new"); - } - - EVP_PKEY_set1_DH(*ud, dh); - - DH_free(dh); - - break; - } -#ifndef OPENSSL_NO_EC - case EVP_PKEY_EC: { - EC_GROUP *grp; - EC_KEY *key; - - if (!(grp = EC_GROUP_new_by_curve_name(curve))) - return throwssl(L, "pubkey.new"); - - EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_NAMED_CURVE); - - /* compressed points patented */ - EC_GROUP_set_point_conversion_form(grp, POINT_CONVERSION_UNCOMPRESSED); - - if (!(key = EC_KEY_new())) { - EC_GROUP_free(grp); - return throwssl(L, "pubkey.new"); - } - - EC_KEY_set_group(key, grp); - - EC_GROUP_free(grp); - - if (!EC_KEY_generate_key(key)) { - EC_KEY_free(key); - return throwssl(L, "pubkey.new"); - } - - EVP_PKEY_set1_EC_KEY(*ud, key); - - EC_KEY_free(key); - - break; - } -#endif - default: - return luaL_error(L, "%d: unknown EVP base type (%d)", EVP_PKEY_type(type), type); - } /* switch() */ - } else { - const char *pem; - size_t len; - BIO *bio; - int ok; - - if (!(*ud = EVP_PKEY_new())) - return throwssl(L, "pubkey.new"); - - switch (lua_type(L, 1)) { - case LUA_TSTRING: - pem = luaL_checklstring(L, 1, &len); - - if (!(bio = BIO_new_mem_buf((void *)pem, len))) - return throwssl(L, "pubkey.new"); - - if (strstr(pem, "PUBLIC KEY")) { - ok = !!PEM_read_bio_PUBKEY(bio, ud, 0, 0); - } else { - ok = !!PEM_read_bio_PrivateKey(bio, ud, 0, 0); - } - - BIO_free(bio); - - if (!ok) - return throwssl(L, "pubkey.new"); - - break; - default: - return luaL_error(L, "%s: unknown key initializer", lua_typename(L, lua_type(L, 1))); - } /* switch() */ - } - - return 1; -} /* pk_new() */ - - -static int pk_interpose(lua_State *L) { - return interpose(L, X509_NAME_CLASS); -} /* pk_interpose() */ - - -static int pk_type(lua_State *L) { - EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); - int nid = key->type; - - pushnid(L, nid); - - return 1; -} /* pk_type() */ - - -static int pk_setPublicKey(lua_State *L) { - EVP_PKEY **key = luaL_checkudata(L, 1, PUBKEY_CLASS); - const char *pem; - size_t len; - BIO *bio; - int ok; - - lua_settop(L, 2); - - pem = luaL_checklstring(L, 2, &len); - - if (!(bio = BIO_new_mem_buf((void *)pem, len))) - return throwssl(L, "pubkey.new"); - - ok = !!PEM_read_bio_PUBKEY(bio, key, 0, 0); - - BIO_free(bio); - - if (!ok) - return throwssl(L, "pubkey.new"); - - lua_pushboolean(L, 1); - - return 1; -} /* pk_setPublicKey() */ - - -static int pk_setPrivateKey(lua_State *L) { - EVP_PKEY **key = luaL_checkudata(L, 1, PUBKEY_CLASS); - const char *pem; - size_t len; - BIO *bio; - int ok; - - lua_settop(L, 2); - - pem = luaL_checklstring(L, 2, &len); - - if (!(bio = BIO_new_mem_buf((void *)pem, len))) - return throwssl(L, "pubkey.new"); - - ok = !!PEM_read_bio_PrivateKey(bio, key, 0, 0); - - BIO_free(bio); - - if (!ok) - return throwssl(L, "pubkey.new"); - - lua_pushboolean(L, 1); - - return 1; -} /* pk_setPrivateKEY() */ - - -static int pk_sign(lua_State *L) { - EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); - EVP_MD_CTX *md = luaL_checkudata(L, 2, DIGEST_CLASS); - luaL_Buffer B; - unsigned n; - - if (LUAL_BUFFERSIZE < EVP_PKEY_size(key)) - return luaL_error(L, "pubkey:sign: LUAL_BUFFERSIZE(%u) < EVP_PKEY_size(%u)", (unsigned)LUAL_BUFFERSIZE, (unsigned)EVP_PKEY_size(key)); - - luaL_buffinit(L, &B); - n = LUAL_BUFFERSIZE; - - if (!EVP_SignFinal(md, (void *)luaL_prepbuffer(&B), &n, key)) - return throwssl(L, "pubkey:sign"); - - luaL_addsize(&B, n); - luaL_pushresult(&B); - - return 1; -} /* pk_sign() */ - - -static int pk_verify(lua_State *L) { - EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); - size_t len; - const void *sig = luaL_checklstring(L, 2, &len); - EVP_MD_CTX *md = luaL_checkudata(L, 3, DIGEST_CLASS); - - switch (EVP_VerifyFinal(md, sig, len, key)) { - case 0: /* WRONG */ - ERR_clear_error(); - lua_pushboolean(L, 0); - - break; - case 1: /* OK */ - lua_pushboolean(L, 1); - - break; - default: - return throwssl(L, "pubkey:verify"); - } - - return 1; -} /* pk_verify() */ - - -static int pk_toPEM(lua_State *L) { - EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); - int top, i, ok; - BIO *bio; - char *pem; - long len; - - if (1 == (top = lua_gettop(L))) { - lua_pushstring(L, "publickey"); - ++top; - } - - bio = getbio(L); - - for (i = 2; i <= top; i++) { - static const char *opts[] = { - "public", "PublicKey", - "private", "PrivateKey", -// "params", "Parameters", - NULL, - }; - - switch (checkoption(L, i, NULL, opts)) { - case 0: case 1: /* public, PublicKey */ - if (!PEM_write_bio_PUBKEY(bio, key)) - return throwssl(L, "pubkey:__tostring"); - - len = BIO_get_mem_data(bio, &pem); - lua_pushlstring(L, pem, len); - - BIO_reset(bio); - break; - case 2: case 3: /* private, PrivateKey */ - if (!PEM_write_bio_PrivateKey(bio, key, 0, 0, 0, 0, 0)) - throwssl(L, "pubkey:__tostring"); - - len = BIO_get_mem_data(bio, &pem); - lua_pushlstring(L, pem, len); - - break; -#if 0 - case 4: case 5: /* params, Parameters */ - /* EVP_PKEY_base_id not in OS X */ - switch (EVP_PKEY_type(key->type)) { - case EVP_PKEY_RSA: - break; - case EVP_PKEY_DSA: { - DSA *dsa = EVP_PKEY_get1_DSA(key); - - ok = !!PEM_write_bio_DSAparams(bio, dsa); - - DSA_free(dsa); - - if (!ok) - return throwssl(L, "pubkey:__tostring"); - - break; - } - case EVP_PKEY_DH: { - DH *dh = EVP_PKEY_get1_DH(key); - - ok = !!PEM_write_bio_DHparams(bio, dh); - - DH_free(dh); - - if (!ok) - return throwssl(L, "pubkey:__tostring"); - - break; - } -#ifndef OPENSSL_NO_EC - case EVP_PKEY_EC: { - EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); - const EC_GROUP *grp = EC_KEY_get0_group(ec); - - ok = !!PEM_write_bio_ECPKParameters(bio, grp); - - EC_KEY_free(ec); - - if (!ok) - return throwssl(L, "pubkey:__tostring"); - - break; - } -#endif - default: - return luaL_error(L, "%d: unknown EVP base type", EVP_PKEY_type(key->type)); - } - - lua_pushlstring(L, pem, len); - - BIO_reset(bio); - - break; -#endif - default: - lua_pushnil(L); - - break; - } /* switch() */ - } /* for() */ - - return lua_gettop(L) - top; -} /* pk_toPEM() */ - - -static int pk__tostring(lua_State *L) { - EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); - BIO *bio = getbio(L); - char *pem; - long len; - int ok; - - if (!PEM_write_bio_PUBKEY(bio, key)) - return throwssl(L, "pubkey:__tostring"); - - len = BIO_get_mem_data(bio, &pem); - lua_pushlstring(L, pem, len); - - return 1; -} /* pk__tostring() */ - - -static int pk__gc(lua_State *L) { - EVP_PKEY **ud = luaL_checkudata(L, 1, PUBKEY_CLASS); - - EVP_PKEY_free(*ud); - *ud = NULL; - - return 0; -} /* pk__gc() */ - - -static const luaL_Reg pk_methods[] = { - { "type", &pk_type }, - { "setPublicKey", &pk_setPublicKey }, - { "setPrivateKey", &pk_setPrivateKey }, - { "sign", &pk_sign }, - { "verify", &pk_verify }, - { "toPEM", &pk_toPEM }, - { NULL, NULL }, -}; - -static const luaL_Reg pk_metatable[] = { - { "__tostring", &pk__tostring }, - { "__gc", &pk__gc }, - { NULL, NULL }, -}; - - -static const luaL_Reg pk_globals[] = { - { "new", &pk_new }, - { "interpose", &pk_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_pubkey(lua_State *L) { - initall(L); - - luaL_newlib(L, pk_globals); - - return 1; -} /* luaopen__openssl_pubkey() */ - - -/* - * X509_NAME - openssl.x509.name - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -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"); - - return *ud; -} /* xn_dup() */ - - -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 1; -} /* xn_new() */ - - -static int xn_interpose(lua_State *L) { - return interpose(L, X509_NAME_CLASS); -} /* xn_interpose() */ - - -static int xn_add(lua_State *L) { - X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); - const char *nid = luaL_checkstring(L, 2); - size_t len; - const char *txt = luaL_checklstring(L, 3, &len); - ASN1_OBJECT *obj; - int ok; - - if (!(obj = OBJ_txt2obj(nid, 0))) - return luaL_error(L, "x509.name:add: %s: invalid NID", nid); - - ok = !!X509_NAME_add_entry_by_OBJ(name, obj, MBSTRING_ASC, (unsigned char *)txt, len, -1, 0); - - ASN1_OBJECT_free(obj); - - if (!ok) - return throwssl(L, "x509.name:add"); - - lua_pushboolean(L, 1); - - return 1; -} /* xn_add() */ - - -static int xn_all(lua_State *L) { - X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); - int count = X509_NAME_entry_count(name); - X509_NAME_ENTRY *entry; - ASN1_OBJECT *obj; - const char *id; - char txt[256]; - int i, nid, len; - - lua_newtable(L); - - for (i = 0; i < count; i++) { - if (!(entry = X509_NAME_get_entry(name, i))) - continue; - - lua_newtable(L); - - obj = X509_NAME_ENTRY_get_object(entry); - nid = OBJ_obj2nid(obj); - - if (0 > (len = OBJ_obj2txt(txt, sizeof txt, obj, 1))) - return throwssl(L, "x509.name:all"); - - lua_pushlstring(L, txt, len); - - if (nid != NID_undef && ((id = OBJ_nid2ln(nid)) || (id = OBJ_nid2sn(nid)))) - lua_pushstring(L, id); - else - lua_pushvalue(L, -1); - - if (nid != NID_undef && (id = OBJ_nid2sn(nid))) - lua_pushstring(L, id); - else - lua_pushvalue(L, -1); - - lua_setfield(L, -4, "sn"); - lua_setfield(L, -3, "ln"); - lua_setfield(L, -2, "id"); - - len = ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)); - lua_pushlstring(L, (char *)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), len); - - lua_setfield(L, -2, "blob"); - - lua_rawseti(L, -2, i + 1); - } - - return 1; -} /* xn_all() */ - - -static int xn__next(lua_State *L) { - X509_NAME *name = checksimple(L, lua_upvalueindex(1), X509_NAME_CLASS); - X509_NAME_ENTRY *entry; - ASN1_OBJECT *obj; - const char *id; - char txt[256]; - int i, n, nid, len; - - lua_settop(L, 0); - - i = lua_tointeger(L, lua_upvalueindex(2)); - n = X509_NAME_entry_count(name); - - while (i < n) { - if (!(entry = X509_NAME_get_entry(name, i++))) - continue; - - obj = X509_NAME_ENTRY_get_object(entry); - nid = OBJ_obj2nid(obj); - - if (nid != NID_undef && ((id = OBJ_nid2sn(nid)) || (id = OBJ_nid2ln(nid)))) { - lua_pushstring(L, id); - } else { - if (0 > (len = OBJ_obj2txt(txt, sizeof txt, obj, 1))) - return throwssl(L, "x509.name:__pairs"); - - lua_pushlstring(L, txt, len); - } - - len = ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)); - lua_pushlstring(L, (char *)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), len); - - break; - } - - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(2)); - - return lua_gettop(L); -} /* xn__next() */ - -static int xn__pairs(lua_State *L) { - lua_settop(L, 1); - lua_pushinteger(L, 0); - - lua_pushcclosure(L, &xn__next, 2); - - return 1; -} /* xn__pairs() */ - - -static int xn__gc(lua_State *L) { - X509_NAME **ud = luaL_checkudata(L, 1, X509_NAME_CLASS); - - X509_NAME_free(*ud); - *ud = NULL; - - return 0; -} /* xn__gc() */ - - -static int xn__tostring(lua_State *L) { - X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); - char txt[1024] = { 0 }; - - /* FIXME: oneline is deprecated */ - X509_NAME_oneline(name, txt, sizeof txt); - - lua_pushstring(L, txt); - - return 1; -} /* xn__tostring() */ - - -static const luaL_Reg xn_methods[] = { - { "add", &xn_add }, - { "all", &xn_all }, - { NULL, NULL }, -}; - -static const luaL_Reg xn_metatable[] = { - { "__pairs", &xn__pairs }, - { "__gc", &xn__gc }, - { "__tostring", &xn__tostring }, - { NULL, NULL }, -}; - - -static const luaL_Reg xn_globals[] = { - { "new", &xn_new }, - { "interpose", &xn_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_x509_name(lua_State *L) { - initall(L); - - luaL_newlib(L, xn_globals); - - return 1; -} /* luaopen__openssl_x509_name() */ - - -/* - * GENERAL_NAMES - openssl.x509.altname - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -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"); - - return *ud; -} /* gn_dup() */ - - -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 1; -} /* gn_new() */ - - -static int gn_interpose(lua_State *L) { - return interpose(L, X509_GENS_CLASS); -} /* gn_interpose() */ - - -static int gn_setCritical(lua_State *L) { - GENERAL_NAMES *gens = checksimple(L, 1, X509_GENS_CLASS); - - return 0; -} /* gn_setCritical() */ - - -static int gn_checktype(lua_State *L, int index) { - static const struct { int type; const char *name; } table[] = { - { GEN_EMAIL, "RFC822Name" }, - { GEN_EMAIL, "RFC822" }, - { GEN_EMAIL, "email" }, - { GEN_URI, "UniformResourceIdentifier" }, - { GEN_URI, "URI" }, - { GEN_DNS, "DNSName" }, - { GEN_DNS, "DNS" }, - { GEN_IPADD, "IPAddress" }, - { GEN_IPADD, "IP" }, - }; - const char *type = luaL_checkstring(L, index); - unsigned i; - - for (i = 0; i < countof(table); i++) { - if (strieq(table[i].name, type)) - return table[i].type; - } - - return luaL_error(L, "%s: invalid type", type), 0; -} /* gn_checktype() */ - - -static int gn_add(lua_State *L) { - GENERAL_NAMES *gens = checksimple(L, 1, X509_GENS_CLASS); - int type = gn_checktype(L, 2); - size_t len; - const char *txt = luaL_checklstring(L, 3, &len); - GENERAL_NAME *gen = NULL; - union { struct in6_addr in6; struct in_addr in; } ip; - - if (type == GEN_IPADD) { - if (strchr(txt, ':')) { - if (1 != inet_pton(AF_INET6, txt, &ip.in6)) - return luaL_error(L, "%s: invalid address", txt); - - txt = (char *)ip.in6.s6_addr; - len = 16; - } else { - if (1 != inet_pton(AF_INET, txt, &ip.in)) - return luaL_error(L, "%s: invalid address", txt); - - txt = (char *)&ip.in.s_addr; - len = 4; - } - } - - if (!(gen = GENERAL_NAME_new())) - goto error; - - gen->type = type; - - if (!(gen->d.ia5 = M_ASN1_IA5STRING_new())) - goto error; - - if (!ASN1_STRING_set(gen->d.ia5, (unsigned char *)txt, len)) - goto error; - - sk_GENERAL_NAME_push(gens, gen); - - lua_pushboolean(L, 1); - - return 1; -error: - GENERAL_NAME_free(gen); - - return throwssl(L, "x509.altname:add"); -} /* gn_add() */ - - -static int gn__next(lua_State *L) { - GENERAL_NAMES *gens = checksimple(L, lua_upvalueindex(1), X509_GENS_CLASS); - int i = lua_tointeger(L, lua_upvalueindex(2)); - int n = sk_GENERAL_NAME_num(gens); - - lua_settop(L, 0); - - while (i < n) { - GENERAL_NAME *name; - const char *tag, *txt; - size_t len; - union { struct in_addr in; struct in6_addr in6; } ip; - char buf[INET6_ADDRSTRLEN + 1]; - int af; - - if (!(name = sk_GENERAL_NAME_value(gens, i++))) - continue; - - switch (name->type) { - case GEN_EMAIL: - tag = "email"; - txt = (char *)M_ASN1_STRING_data(name->d.rfc822Name); - len = M_ASN1_STRING_length(name->d.rfc822Name); - - break; - case GEN_URI: - tag = "URI"; - txt = (char *)M_ASN1_STRING_data(name->d.uniformResourceIdentifier); - len = M_ASN1_STRING_length(name->d.uniformResourceIdentifier); - - break; - case GEN_DNS: - tag = "DNS"; - txt = (char *)M_ASN1_STRING_data(name->d.dNSName); - len = M_ASN1_STRING_length(name->d.dNSName); - - break; - case GEN_IPADD: - tag = "IP"; - txt = (char *)M_ASN1_STRING_data(name->d.iPAddress); - len = M_ASN1_STRING_length(name->d.iPAddress); - - switch (len) { - case 16: - memcpy(ip.in6.s6_addr, txt, 16); - af = AF_INET6; - - break; - case 4: - memcpy(&ip.in.s_addr, txt, 4); - af = AF_INET; - - break; - default: - continue; - } - - if (!(txt = inet_ntop(af, &ip, buf, sizeof buf))) - continue; - - len = strlen(txt); - - break; - default: - continue; - } - - lua_pushstring(L, tag); - lua_pushlstring(L, txt, len); - - break; - } - - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(2)); - - return lua_gettop(L); -} /* gn__next() */ - -static int gn__pairs(lua_State *L) { - lua_settop(L, 1); - lua_pushinteger(L, 0); - lua_pushcclosure(L, &gn__next, 2); - - return 1; -} /* gn__pairs() */ - - -static int gn__gc(lua_State *L) { - GENERAL_NAMES **ud = luaL_checkudata(L, 1, X509_GENS_CLASS); - - sk_GENERAL_NAME_pop_free(*ud, GENERAL_NAME_free); - *ud = NULL; - - return 0; -} /* gn__gc() */ - - -static const luaL_Reg gn_methods[] = { - { "add", &gn_add }, - { NULL, NULL }, -}; - -static const luaL_Reg gn_metatable[] = { - { "__pairs", &gn__pairs }, - { "__gc", &gn__gc }, - { NULL, NULL }, -}; - - -static const luaL_Reg gn_globals[] = { - { "new", &gn_new }, - { "interpose", &gn_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_x509_altname(lua_State *L) { - initall(L); - - luaL_newlib(L, gn_globals); - - return 1; -} /* luaopen__openssl_x509_altname() */ - - -/* - * X509 - openssl.x509.cert - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static int xc_new(lua_State *L) { - const char *pem; - size_t len; - X509 **ud; - - lua_settop(L, 1); - - ud = prepsimple(L, X509_CERT_CLASS); - - if ((pem = luaL_optlstring(L, 1, NULL, &len))) { - BIO *tmp; - int ok; - - if (!(tmp = BIO_new_mem_buf((char *)pem, len))) - return throwssl(L, "x509.cert.new"); - - ok = !!PEM_read_bio_X509(tmp, ud, 0, ""); /* no password */ - - BIO_free(tmp); - - if (!ok) - return throwssl(L, "x509.cert.new"); - } else { - if (!(*ud = X509_new())) - return throwssl(L, "x509.cert.new"); - - X509_gmtime_adj(X509_get_notBefore(*ud), 0); - X509_gmtime_adj(X509_get_notAfter(*ud), 0); - } - - return 1; -} /* xc_new() */ - - -static int xc_interpose(lua_State *L) { - return interpose(L, X509_CERT_CLASS); -} /* xc_interpose() */ - - -static int xc_getVersion(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - - lua_pushinteger(L, X509_get_version(crt) + 1); - - return 1; -} /* xc_getVersion() */ - - -static int xc_setVersion(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - int version = luaL_checkint(L, 2); - - if (!X509_set_version(crt, version - 1)) - return luaL_error(L, "x509.cert:setVersion: %d: invalid version", version); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setVersion() */ - - -static int xc_getSerial(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - BIGNUM *serial = bn_push(L); - ASN1_INTEGER *i; - - if ((i = X509_get_serialNumber(crt))) { - if (!ASN1_INTEGER_to_BN(i, serial)) - return throwssl(L, "x509.cert:getSerial"); - } - - return 1; -} /* xc_getSerial() */ - - -static int xc_setSerial(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - ASN1_INTEGER *serial; - - if (!(serial = BN_to_ASN1_INTEGER(checkbig(L, 2), NULL))) - goto error; - - if (!X509_set_serialNumber(crt, serial)) - goto error; - - ASN1_INTEGER_free(serial); - - lua_pushboolean(L, 1); - - return 1; -error: - ASN1_INTEGER_free(serial); - - return throwssl(L, "x509.cert:setSerial"); -} /* xc_setSerial() */ - - -static int xc_digest(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - const char *type = luaL_optstring(L, 2, "sha1"); - int format = luaL_checkoption(L, 3, "x", (const char *[]){ "s", "x", "n", NULL }); - const EVP_MD *ctx; - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned len; - - lua_settop(L, 3); /* self, type, hex */ - - if (!(ctx = EVP_get_digestbyname(type))) - return luaL_error(L, "x509.cert:digest: %s: invalid digest type", type); - - X509_digest(crt, ctx, md, &len); - - switch (format) { - case 2: { - BIGNUM *bn = bn_push(L); - - if (!BN_bin2bn(md, len, bn)) - return throwssl(L, "x509.cert:digest"); - - break; - } - case 1: { - static const unsigned char x[16] = "0123456789abcdef"; - luaL_Buffer B; - unsigned i; - -#if LUA_VERSION_NUM < 502 - luaL_buffinit(L, &B); -#else - luaL_buffinitsize(L, &B, 2 * len); -#endif - - for (i = 0; i < len; i++) { - luaL_addchar(&B, x[0x0f & (md[i] >> 4)]); - luaL_addchar(&B, x[0x0f & (md[i] >> 0)]); - } - - luaL_pushresult(&B); - - break; - } - default: - lua_pushlstring(L, (const char *)md, len); - - break; - } /* switch() */ - - return 1; -} /* xc_digest() */ - - -static _Bool isleap(int year) { - if (year >= 0) - return !(year % 4) && ((year % 100) || !(year % 400)); - else - return isleap(-(year + 1)); -} /* isleap() */ - - -static int yday(int year, int mon, int mday) { - static const int past[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - int yday = past[CLAMP(mon, 0, 11)] + CLAMP(mday, 1, 31) - 1; - - return yday + (mon > 1 && isleap(year)); -} /* yday() */ - - -static int tm_yday(const struct tm *tm) { - return (tm->tm_yday)? tm->tm_yday : yday(1900 + tm->tm_year, tm->tm_mon, tm->tm_mday); -} /* tm_yday() */ - - -static int leaps(int year) { - if (year >= 0) - return (year / 400) + (year / 4) - (year / 100); - else - return -(leaps(-(year + 1)) + 1); -} /* leaps() */ - - -static double tm2unix(const struct tm *tm, int gmtoff) { - int year = tm->tm_year + 1900; - double ts; - - ts = 86400.0 * 365.0 * (year - 1970); - ts += 86400.0 * (leaps(year - 1) - leaps(1969)); - ts += 86400 * tm_yday(tm); - ts += 3600 * tm->tm_hour; - ts += 60 * tm->tm_min; - ts += CLAMP(tm->tm_sec, 0, 59); - ts += (year < 1970)? gmtoff : -gmtoff; - - return ts; -} /* tm2unix() */ - - -static _Bool scan(int *i, char **cp, int n, int signok) { - int sign = 1; - - *i = 0; - - if (signok) { - if (**cp == '-') { - sign = -1; - ++*cp; - } else if (**cp == '+') { - ++*cp; - } - } - - while (n-- > 0) { - if (**cp < '0' || **cp > '9') - return 0; - - *i *= 10; - *i += *(*cp)++ - '0'; - } - - *i *= sign; - - return 1; -} /* scan() */ - - -static double timeutc(ASN1_TIME *time) { - char buf[32] = "", *cp; - struct tm tm = { 0 }; - int gmtoff = 0, year, i; - double ts; - - if (!ASN1_TIME_check(time)) - return 0; - - cp = strncpy(buf, (const char *)ASN1_STRING_data((ASN1_STRING *)time), sizeof buf - 1); - - if (ASN1_STRING_type(time) == V_ASN1_GENERALIZEDTIME) { - if (!scan(&year, &cp, 4, 1)) - goto badfmt; - } else { - if (!scan(&year, &cp, 2, 0)) - goto badfmt; - year += (year < 50)? 2000 : 1999; - } - - tm.tm_year = year - 1900; - - if (!scan(&i, &cp, 2, 0)) - goto badfmt; - - tm.tm_mon = CLAMP(i, 1, 12) - 1; - - if (!scan(&i, &cp, 2, 0)) - goto badfmt; - - tm.tm_mday = CLAMP(i, 1, 31); - - tm.tm_yday = yday(year, tm.tm_mon, tm.tm_mday); - - if (!scan(&i, &cp, 2, 0)) - goto badfmt; - - tm.tm_hour = CLAMP(i, 0, 23); - - if (!scan(&i, &cp, 2, 0)) - goto badfmt; - - tm.tm_min = CLAMP(i, 0, 59); - - if (*cp >= '0' && *cp <= '9') { - if (!scan(&i, &cp, 2, 0)) - goto badfmt; - - tm.tm_sec = CLAMP(i, 0, 59); - } - - if (*cp == '+' || *cp == '-') { - int sign = (*cp++ == '-')? -1 : 1; - int hh, mm; - - if (!scan(&hh, &cp, 2, 0) || !scan(&mm, &cp, 2, 0)) - goto badfmt; - - gmtoff = (CLAMP(hh, 0, 23) * 3600) - + (CLAMP(mm, 0, 59) * 60); - - gmtoff *= sign; - } - - return tm2unix(&tm, gmtoff); -badfmt: - return INFINITY; -} /* timeutc() */ - - -static int xc_getLifetime(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - double begin = INFINITY, end = INFINITY; - ASN1_TIME *time; - - if ((time = X509_get_notBefore(crt))) - begin = timeutc(time); - - if ((time = X509_get_notAfter(crt))) - end = timeutc(time); - - if (isfinite(begin)) - lua_pushnumber(L, begin); - else - lua_pushnil(L); - - if (isfinite(end)) - lua_pushnumber(L, end); - else - lua_pushnil(L); - - if (isfinite(begin) && isfinite(end) && begin <= end) - lua_pushnumber(L, fabs(end - begin)); - else - lua_pushnumber(L, 0.0); - - return 3; -} /* xc_getLifetime() */ - - -static int xc_setLifetime(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - ASN1_TIME *time; - double ut; - const char *dt; - - lua_settop(L, 3); - - if (lua_isnumber(L, 2)) { - ut = lua_tonumber(L, 2); - - if (!ASN1_TIME_set(X509_get_notBefore(crt), ut)) - return throwssl(L, "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"); -#endif - } - - if (lua_isnumber(L, 3)) { - ut = lua_tonumber(L, 3); - - if (!ASN1_TIME_set(X509_get_notAfter(crt), ut)) - return throwssl(L, "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"); -#endif - } - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setLifetime() */ - - -static int xc_getIssuer(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - X509_NAME *name; - - if (!(name = X509_get_issuer_name(crt))) - return 0; - - xn_dup(L, name); - - return 1; -} /* xc_getIssuer() */ - - -static int xc_setIssuer(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); - - if (!X509_set_issuer_name(crt, name)) - return throwssl(L, "x509.cert:setIssuer"); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setIssuer() */ - - -static int xc_getSubject(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - X509_NAME *name; - - if (!(name = X509_get_subject_name(crt))) - return 0; - - xn_dup(L, name); - - return 1; -} /* xc_getSubject() */ - - -static int xc_setSubject(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); - - if (!X509_set_subject_name(crt, name)) - return throwssl(L, "x509.cert:setSubject"); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setSubject() */ - - -static void xc_setCritical(X509 *crt, int nid, _Bool yes) { - X509_EXTENSION *ext; - int loc; - - if ((loc = X509_get_ext_by_NID(crt, nid, -1)) >= 0 - && (ext = X509_get_ext(crt, loc))) - X509_EXTENSION_set_critical(ext, yes); -} /* xc_setCritical() */ - - -static _Bool xc_getCritical(X509 *crt, int nid) { - X509_EXTENSION *ext; - int loc; - - if ((loc = X509_get_ext_by_NID(crt, nid, -1)) >= 0 - && (ext = X509_get_ext(crt, loc))) - return X509_EXTENSION_get_critical(ext); - else - return 0; -} /* xc_getCritical() */ - - -static int xc_getIssuerAlt(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - GENERAL_NAMES *gens; - - if (!(gens = X509_get_ext_d2i(crt, NID_issuer_alt_name, 0, 0))) - return 0; - - gn_dup(L, gens); - - return 1; -} /* xc_getIssuerAlt() */ - - -static int xc_setIssuerAlt(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - 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"); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setIssuerAlt() */ - - -static int xc_getSubjectAlt(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - GENERAL_NAMES *gens; - - if (!(gens = X509_get_ext_d2i(crt, NID_subject_alt_name, 0, 0))) - return 0; - - gn_dup(L, gens); - - return 1; -} /* xc_getSubjectAlt() */ - - -static int xc_setSubjectAlt(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - 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"); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setSubjectAlt() */ - - -static int xc_getIssuerAltCritical(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - - lua_pushboolean(L, xc_getCritical(crt, NID_issuer_alt_name)); - - return 1; -} /* xc_getIssuerAltCritical() */ - - -static int xc_setIssuerAltCritical(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - - luaL_checkany(L, 2); - xc_setCritical(crt, NID_issuer_alt_name, lua_toboolean(L, 2)); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setIssuerAltCritical() */ - - -static int xc_getSubjectAltCritical(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - - lua_pushboolean(L, xc_getCritical(crt, NID_subject_alt_name)); - - return 1; -} /* xc_getSubjectAltCritical() */ - - -static int xc_setSubjectAltCritical(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - - luaL_checkany(L, 2); - xc_setCritical(crt, NID_subject_alt_name, lua_toboolean(L, 2)); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setSubjectAltCritical() */ - - -static int xc_getBasicConstraint(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - BASIC_CONSTRAINTS *bs; - int CA, pathLen; - - if (!(bs = X509_get_ext_d2i(crt, NID_basic_constraints, 0, 0))) { - /* FIXME: detect error or just non-existent */ - - if (lua_gettop(L) > 1) - return 0; - - lua_newtable(L); - - return 1; - } - - CA = bs->ca; - pathLen = ASN1_INTEGER_get(bs->pathlen); - - BASIC_CONSTRAINTS_free(bs); - - if (lua_gettop(L) > 1) { - int n = 0, i, top; - - for (i = 2, top = lua_gettop(L); i <= top; i++) { - switch (checkoption(L, i, 0, (const char *[]){ "CA", "pathLen", "pathLenConstraint", NULL })) { - case 0: - lua_pushboolean(L, CA); - n++; - break; - case 1: - /* FALL THROUGH */ - case 2: - lua_pushinteger(L, pathLen); - n++; - break; - } - } - - return n; - } else { - lua_newtable(L); - - lua_pushboolean(L, CA); - lua_setfield(L, -2, "CA"); - - lua_pushinteger(L, pathLen); - lua_setfield(L, -2, "pathLen"); - - return 1; - } -} /* xc_getBasicConstraint() */ - - -static int xc_setBasicConstraint(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - BASIC_CONSTRAINTS *bs = 0; - int CA = -1, pathLen = -1; - int critical = 0; - - luaL_checkany(L, 2); - - if (lua_istable(L, 2)) { - lua_getfield(L, 2, "CA"); - if (!lua_isnil(L, -1)) - CA = lua_toboolean(L, -1); - lua_pop(L, 1); - - lua_getfield(L, 2, "pathLen"); - pathLen = luaL_optint(L, -1, pathLen); - lua_pop(L, 1); - - lua_getfield(L, 2, "pathLenConstraint"); - pathLen = luaL_optint(L, -1, pathLen); - lua_pop(L, 1); - - if (!(bs = BASIC_CONSTRAINTS_new())) - goto error; - } else { - lua_settop(L, 3); - - switch (checkoption(L, 2, 0, (const char *[]){ "CA", "pathLen", "pathLenConstraint", NULL })) { - case 0: - luaL_checktype(L, 3, LUA_TBOOLEAN); - CA = lua_toboolean(L, 3); - - break; - case 1: - /* FALL THROUGH */ - case 2: - pathLen = luaL_checkint(L, 3); - - break; - } - - if (!(bs = X509_get_ext_d2i(crt, NID_basic_constraints, &critical, 0))) { - /* FIXME: detect whether error or just non-existent */ - if (!(bs = BASIC_CONSTRAINTS_new())) - goto error; - } - } - - if (CA != -1) - bs->ca = CA; - - if (pathLen >= 0) { - ASN1_INTEGER_free(bs->pathlen); - - if (!(bs->pathlen = M_ASN1_INTEGER_new())) - goto error; - - if (!ASN1_INTEGER_set(bs->pathlen, pathLen)) - goto error; - } - - if (!X509_add1_ext_i2d(crt, NID_basic_constraints, bs, critical, X509V3_ADD_REPLACE)) - goto error; - - BASIC_CONSTRAINTS_free(bs); - - lua_pushboolean(L, 1); - - return 1; -error: - BASIC_CONSTRAINTS_free(bs); - - return throwssl(L, "x509.cert:setBasicConstraint"); -} /* xc_setBasicConstraint() */ - - -static int xc_getBasicConstraintsCritical(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - - lua_pushboolean(L, xc_getCritical(crt, NID_basic_constraints)); - - return 1; -} /* xc_getBasicConstraintsCritical() */ - - -static int xc_setBasicConstraintsCritical(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - - luaL_checkany(L, 2); - xc_setCritical(crt, NID_basic_constraints, lua_toboolean(L, 2)); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setBasicConstraintsCritical() */ - - -static int xc_isIssuedBy(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - X509 *issuer = checksimple(L, 2, X509_CERT_CLASS); - EVP_PKEY *key; - int ok, why = 0; - - ERR_clear_error(); - - if (X509_V_OK != (why = X509_check_issued(issuer, crt))) - goto done; - - if (!(key = X509_get_pubkey(issuer))) { - why = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; - goto done; - } - - ok = (1 == X509_verify(crt, key)); - - EVP_PKEY_free(key); - - if (!ok) - why = X509_V_ERR_CERT_SIGNATURE_FAILURE; - -done: - if (why != X509_V_OK) { - lua_pushboolean(L, 0); - lua_pushstring(L, X509_verify_cert_error_string(why)); - - return 2; - } else { - lua_pushboolean(L, 1); - - return 1; - } -} /* xc_isIssuedBy() */ - - -static int xc_getPublicKey(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - EVP_PKEY **key = prepsimple(L, PUBKEY_CLASS); - - if (!(*key = X509_get_pubkey(crt))) - return throwssl(L, "x509.cert:getPublicKey"); - - return 1; -} /* xc_getPublicKey() */ - - -static int xc_setPublicKey(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); - - if (!X509_set_pubkey(crt, key)) - return throwssl(L, "x509.cert:setPublicKey"); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_setPublicKey() */ - - -static const EVP_MD *xc_signature(lua_State *L, int index, EVP_PKEY *key) { - const char *id; - const EVP_MD *md; - - if ((id = luaL_optstring(L, index, NULL))) - return ((md = EVP_get_digestbyname(id)))? md : EVP_md_null(); - - switch (EVP_PKEY_type(key->type)) { - case EVP_PKEY_RSA: - return EVP_sha1(); - case EVP_PKEY_DSA: - return EVP_dss1(); - case EVP_PKEY_EC: - return EVP_ecdsa(); - default: - return EVP_md_null(); - } -} /* xc_signature() */ - -static int xc_sign(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); - - if (!X509_sign(crt, key, xc_signature(L, 3, key))) - return throwssl(L, "x509.cert:sign"); - - lua_pushboolean(L, 1); - - return 1; -} /* xc_sign() */ - - -static int xc__tostring(lua_State *L) { - X509 *crt = checksimple(L, 1, X509_CERT_CLASS); - int fmt = checkoption(L, 2, "pem", (const char *[]){ "pem", NULL }); - BIO *bio = getbio(L); - char *pem; - long len; - - if (!PEM_write_bio_X509(bio, crt)) - return throwssl(L, "x509.cert:__tostring"); - - len = BIO_get_mem_data(bio, &pem); - - lua_pushlstring(L, pem, len); - - return 1; -} /* xc__tostring() */ - - -static int xc__gc(lua_State *L) { - X509 **ud = luaL_checkudata(L, 1, X509_CERT_CLASS); - - X509_free(*ud); - *ud = NULL; - - return 0; -} /* xc__gc() */ - - -static const luaL_Reg xc_methods[] = { - { "getVersion", &xc_getVersion }, - { "setVersion", &xc_setVersion }, - { "getSerial", &xc_getSerial }, - { "setSerial", &xc_setSerial }, - { "digest", &xc_digest }, - { "getLifetime", &xc_getLifetime }, - { "setLifetime", &xc_setLifetime }, - { "getIssuer", &xc_getIssuer }, - { "setIssuer", &xc_setIssuer }, - { "getSubject", &xc_getSubject }, - { "setSubject", &xc_setSubject }, - { "getIssuerAlt", &xc_getIssuerAlt }, - { "setIssuerAlt", &xc_setIssuerAlt }, - { "getSubjectAlt", &xc_getSubjectAlt }, - { "setSubjectAlt", &xc_setSubjectAlt }, - { "getIssuerAltCritical", &xc_getIssuerAltCritical }, - { "setIssuerAltCritical", &xc_setIssuerAltCritical }, - { "getSubjectAltCritical", &xc_getSubjectAltCritical }, - { "setSubjectAltCritical", &xc_setSubjectAltCritical }, - { "getBasicConstraints", &xc_getBasicConstraint }, - { "getBasicConstraint", &xc_getBasicConstraint }, - { "setBasicConstraints", &xc_setBasicConstraint }, - { "setBasicConstraint", &xc_setBasicConstraint }, - { "getBasicConstraintsCritical", &xc_getBasicConstraintsCritical }, - { "setBasicConstraintsCritical", &xc_setBasicConstraintsCritical }, - { "isIssuedBy", &xc_isIssuedBy }, - { "getPublicKey", &xc_getPublicKey }, - { "setPublicKey", &xc_setPublicKey }, - { "sign", &xc_sign }, - { NULL, NULL }, -}; - -static const luaL_Reg xc_metatable[] = { - { "__tostring", &xc__tostring }, - { "__gc", &xc__gc }, - { NULL, NULL }, -}; - - -static const luaL_Reg xc_globals[] = { - { "new", &xc_new }, - { "interpose", &xc_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_x509_cert(lua_State *L) { - initall(L); - - luaL_newlib(L, xc_globals); - - return 1; -} /* luaopen__openssl_x509_cert() */ - - -/* - * X509_REQ - openssl.x509.csr - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static int xr_new(lua_State *L) { - const char *pem; - size_t len; - X509_REQ **ud; - X509 *crt; - - lua_settop(L, 1); - - ud = prepsimple(L, X509_CSR_CLASS); - - if ((crt = testsimple(L, 1, X509_CERT_CLASS))) { - if (!(*ud = X509_to_X509_REQ(crt, 0, 0))) - return throwssl(L, "x509.csr.new"); - } else if ((pem = luaL_optlstring(L, 1, NULL, &len))) { - BIO *tmp; - int ok; - - if (!(tmp = BIO_new_mem_buf((char *)pem, len))) - return throwssl(L, "x509.csr.new"); - - ok = !!PEM_read_bio_X509_REQ(tmp, ud, 0, ""); /* no password */ - - BIO_free(tmp); - - if (!ok) - return throwssl(L, "x509.csr.new"); - } else { - if (!(*ud = X509_REQ_new())) - return throwssl(L, "x509.csr.new"); - } - - return 1; -} /* xr_new() */ - - -static int xr_interpose(lua_State *L) { - return interpose(L, X509_CSR_CLASS); -} /* xr_interpose() */ - - -static int xr_getVersion(lua_State *L) { - X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); - - lua_pushinteger(L, X509_REQ_get_version(csr) + 1); - - return 1; -} /* xr_getVersion() */ - - -static int xr_setVersion(lua_State *L) { - X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); - int version = luaL_checkint(L, 2); - - if (!X509_REQ_set_version(csr, version - 1)) - return luaL_error(L, "x509.csr:setVersion: %d: invalid version", version); - - lua_pushboolean(L, 1); - - return 1; -} /* xr_setVersion() */ - - -static int xr_getSubject(lua_State *L) { - X509_REQ *crt = checksimple(L, 1, X509_CSR_CLASS); - X509_NAME *name; - - if (!(name = X509_REQ_get_subject_name(crt))) - return 0; - - xn_dup(L, name); - - return 1; -} /* xr_getSubject() */ - - -static int xr_setSubject(lua_State *L) { - X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); - X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); - - if (!X509_REQ_set_subject_name(csr, name)) - return throwssl(L, "x509.csr:setSubject"); - - lua_pushboolean(L, 1); - - return 1; -} /* xr_setSubject() */ - - -static int xr_getPublicKey(lua_State *L) { - X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); - EVP_PKEY **key = prepsimple(L, PUBKEY_CLASS); - - if (!(*key = X509_REQ_get_pubkey(csr))) - return throwssl(L, "x509.cert:getPublicKey"); - - return 1; -} /* xr_getPublicKey() */ - - -static int xr_setPublicKey(lua_State *L) { - X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); - EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); - - if (!X509_REQ_set_pubkey(csr, key)) - return throwssl(L, "x509.csr:setPublicKey"); - - lua_pushboolean(L, 1); - - return 1; -} /* xr_setPublicKey() */ - - -static int xr_sign(lua_State *L) { - X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); - EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); - - if (!X509_REQ_sign(csr, key, xc_signature(L, 3, key))) - return throwssl(L, "x509.csr:sign"); - - lua_pushboolean(L, 1); - - return 1; -} /* xr_sign() */ - - -static int xr__tostring(lua_State *L) { - X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); - int fmt = checkoption(L, 2, "pem", (const char *[]){ "pem", NULL }); - BIO *bio = getbio(L); - char *pem; - long len; - - if (!PEM_write_bio_X509_REQ(bio, csr)) - return throwssl(L, "x509.csr:__tostring"); - - len = BIO_get_mem_data(bio, &pem); - - lua_pushlstring(L, pem, len); - - return 1; -} /* xr__tostring() */ - - -static int xr__gc(lua_State *L) { - X509_REQ **ud = luaL_checkudata(L, 1, X509_CSR_CLASS); - - X509_REQ_free(*ud); - *ud = NULL; - - return 0; -} /* xr__gc() */ - -static const luaL_Reg xr_methods[] = { - { "getVersion", &xr_getVersion }, - { "setVersion", &xr_setVersion }, - { "getSubject", &xr_getSubject }, - { "setSubject", &xr_setSubject }, - { "getPublicKey", &xr_getPublicKey }, - { "setPublicKey", &xr_setPublicKey }, - { "sign", &xr_sign }, - { NULL, NULL }, -}; - -static const luaL_Reg xr_metatable[] = { - { "__tostring", &xr__tostring }, - { "__gc", &xr__gc }, - { NULL, NULL }, -}; - - -static const luaL_Reg xr_globals[] = { - { "new", &xr_new }, - { "interpose", &xr_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_x509_csr(lua_State *L) { - initall(L); - - luaL_newlib(L, xr_globals); - - return 1; -} /* luaopen__openssl_x509_csr() */ - - -/* - * STACK_OF(X509) - openssl.x509.chain - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static void xl_dup(lua_State *L, STACK_OF(X509) *src, _Bool copy) { - STACK_OF(X509) **dst = prepsimple(L, X509_CHAIN_CLASS); - X509 *crt; - int i, n; - - if (copy) { - if (!(*dst = sk_X509_new_null())) - goto error; - - n = sk_X509_num(src); - - for (i = 0; i < n; i++) { - if (!(crt = sk_X509_value(src, i))) - continue; - - if (!(crt = X509_dup(crt))) - goto error; - - if (!sk_X509_push(*dst, crt)) { - X509_free(crt); - goto error; - } - } - } else { - if (!(*dst = sk_X509_dup(src))) - goto error; - - n = sk_X509_num(*dst); - - for (i = 0; i < n; i++) { - if (!(crt = sk_X509_value(*dst, i))) - continue; - CRYPTO_add(&crt->references, 1, CRYPTO_LOCK_X509); - } - } - - return; -error: - throwssl(L, "sk_X509_dup"); -} /* xl_dup() */ - - -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 1; -} /* xl_new() */ - - -static int xl_interpose(lua_State *L) { - return interpose(L, X509_CHAIN_CLASS); -} /* xl_interpose() */ - - -static int xl_add(lua_State *L) { - STACK_OF(X509) *chain = checksimple(L, 1, X509_CHAIN_CLASS); - X509 *crt = checksimple(L, 2, X509_CERT_CLASS); - X509 *dup; - - if (!(dup = X509_dup(crt))) - return throwssl(L, "x509.chain:add"); - - if (!sk_X509_push(chain, dup)) { - X509_free(dup); - return throwssl(L, "x509.chain:add"); - } - - lua_pushboolean(L, 1); - - return 1; -} /* xl_add() */ - - -static int xl__next(lua_State *L) { - STACK_OF(X509) *chain = checksimple(L, lua_upvalueindex(1), X509_CHAIN_CLASS); - int i = lua_tointeger(L, lua_upvalueindex(2)); - int n = sk_X509_num(chain); - - lua_settop(L, 0); - - while (i < n) { - X509 *crt, **ret; - - if (!(crt = sk_X509_value(chain, i++))) - continue; - - lua_pushinteger(L, i); - - ret = prepsimple(L, X509_CERT_CLASS); - - if (!(*ret = X509_dup(crt))) - return throwssl(L, "x509.chain:__next"); - - break; - } - - lua_pushinteger(L, i); - lua_replace(L, lua_upvalueindex(2)); - - return lua_gettop(L); -} /* xl__next() */ - -static int xl__pairs(lua_State *L) { - lua_settop(L, 1); - lua_pushinteger(L, 0); - lua_pushcclosure(L, &xl__next, 2); - - return 1; -} /* xl__pairs() */ - - -static int xl__gc(lua_State *L) { - STACK_OF(X509) **chain = luaL_checkudata(L, 1, X509_CHAIN_CLASS); - - sk_X509_pop_free(*chain, X509_free); - *chain = NULL; - - return 0; -} /* xl__gc() */ - - -static const luaL_Reg xl_methods[] = { - { "add", &xl_add }, - { NULL, NULL }, -}; - -static const luaL_Reg xl_metatable[] = { - { "__pairs", &xl__pairs }, - { "__ipairs", &xl__pairs }, - { "__gc", &xl__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg xl_globals[] = { - { "new", &xl_new }, - { "interpose", &xl_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_x509_chain(lua_State *L) { - initall(L); - - luaL_newlib(L, xl_globals); - - return 1; -} /* luaopen__openssl_x509_chain() */ - - -/* - * X509_STORE - openssl.x509.store - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -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 1; -} /* xs_new() */ - - -static int xs_interpose(lua_State *L) { - return interpose(L, X509_STORE_CLASS); -} /* xs_interpose() */ - - -static int xs_add(lua_State *L) { - X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); - int i, top = lua_gettop(L); - - for (i = 2; i <= top; i++) { - if (lua_isuserdata(L, i)) { - X509 *crt = checksimple(L, i, X509_CERT_CLASS); - X509 *dup; - - if (!(dup = X509_dup(crt))) - return throwssl(L, "x509.store:add"); - - if (!X509_STORE_add_cert(store, dup)) { - X509_free(dup); - return throwssl(L, "x509.store:add"); - } - } else { - const char *path = luaL_checkstring(L, i); - struct stat st; - int ok; - - if (0 != stat(path, &st)) - return luaL_error(L, "%s: %s", path, strerror(errno)); - - if (S_ISDIR(st.st_mode)) - ok = X509_STORE_load_locations(store, NULL, path); - else - ok = X509_STORE_load_locations(store, path, NULL); - - if (!ok) - return throwssl(L, "x509.store:add"); - } - } - - lua_pushboolean(L, 1); - - return 1; -} /* xs_add() */ - - -static int xs_verify(lua_State *L) { - X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); - X509 *crt = checksimple(L, 2, X509_CERT_CLASS); - STACK_OF(X509) *chain = NULL, **proof; - X509_STORE_CTX ctx; - int ok, why; - - /* pre-allocate space for a successful return */ - lua_settop(L, 3); - proof = prepsimple(L, X509_CHAIN_CLASS); - - if (!lua_isnoneornil(L, 3)) { - X509 *elm; - int i, n; - - if (!(chain = sk_X509_dup(checksimple(L, 3, X509_CHAIN_CLASS)))) - return throwssl(L, "x509.store:verify"); - - n = sk_X509_num(chain); - - for (i = 0; i < n; i++) { - if (!(elm = sk_X509_value(chain, i))) - continue; - CRYPTO_add(&elm->references, 1, CRYPTO_LOCK_X509); - } - } - - if (!X509_STORE_CTX_init(&ctx, store, crt, chain)) { - sk_X509_pop_free(chain, X509_free); - return throwssl(L, "x509.store:verify"); - } - - ERR_clear_error(); - - ok = X509_verify_cert(&ctx); - - switch (ok) { - case 1: /* verified */ - *proof = X509_STORE_CTX_get1_chain(&ctx); - - X509_STORE_CTX_cleanup(&ctx); - - if (!*proof) - return throwssl(L, "x509.store:verify"); - - lua_pushboolean(L, 1); - lua_pushvalue(L, -2); - - return 2; - case 0: /* not verified */ - why = X509_STORE_CTX_get_error(&ctx); - - X509_STORE_CTX_cleanup(&ctx); - - lua_pushboolean(L, 0); - lua_pushstring(L, X509_verify_cert_error_string(why)); - - return 2; - default: - X509_STORE_CTX_cleanup(&ctx); - - return throwssl(L, "x509.store:verify"); - } -} /* xs_verify() */ - - -static int xs__gc(lua_State *L) { - X509_STORE **ud = luaL_checkudata(L, 1, X509_STORE_CLASS); - - X509_STORE_free(*ud); - *ud = NULL; - - return 0; -} /* xs__gc() */ - - -static const luaL_Reg xs_methods[] = { - { "add", &xs_add }, - { "verify", &xs_verify }, - { NULL, NULL }, -}; - -static const luaL_Reg xs_metatable[] = { - { "__gc", &xs__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg xs_globals[] = { - { "new", &xs_new }, - { "interpose", &xs_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_x509_store(lua_State *L) { - initall(L); - - luaL_newlib(L, xs_globals); - - return 1; -} /* luaopen__openssl_x509_store() */ - - -/* - * X509_STORE_CTX - openssl.x509.store.context - * - * This object is intended to be a temporary container in OpenSSL, so the - * memory management is quite clumsy. In particular, it doesn't take - * ownership of the X509_STORE object, which means the reference must be - * held externally for the life of the X509_STORE_CTX object. - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#if 0 -static int stx_new(lua_State *L) { - X509_STORE_CTX **ud = prepsimple(L, X509_STCTX_CLASS); - STACK_OF(X509) *chain; - - if (!(*ud = X509_STORE_CTX_new())) - return throwssl(L, "x509.store.context"); - - return 1; -} /* stx_new() */ - - -static int stx_interpose(lua_State *L) { - return interpose(L, X509_STCTX_CLASS); -} /* stx_interpose() */ - - -static int stx_add(lua_State *L) { - X509_STORE_CTX *ctx = checksimple(L, 1, X509_STCTX_CLASS); - - return 0; -} /* stx_add() */ - - -static int stx__gc(lua_State *L) { - X509_STORE **ud = luaL_checkudata(L, 1, X509_STORE_CLASS); - - X509_STORE_free(*ud); - *ud = NULL; - - return 0; -} /* stx__gc() */ - - -static const luaL_Reg stx_methods[] = { - { "add", &stx_add }, - { NULL, NULL }, -}; - -static const luaL_Reg stx_metatable[] = { - { "__gc", &stx__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg stx_globals[] = { - { "new", &stx_new }, - { "interpose", &stx_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_x509_store_context(lua_State *L) { - initall(L); - - luaL_newlib(L, stx_globals); - - return 1; -} /* luaopen__openssl_x509_store_context() */ -#endif - - -/* - * SSL_CTX - openssl.ssl.context - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static int sx_new(lua_State *L) { - static const char *opts[] = { - "SSLv2", "SSLv3", "SSLv23", "SSL", "TLSv1", "TLS", NULL - }; - /* later versions of SSL declare a const qualifier on the return type */ - __typeof__(&TLSv1_client_method) method = &TLSv1_client_method; - _Bool srv; - SSL_CTX **ud; - - lua_settop(L, 2); - srv = lua_toboolean(L, 2); - - switch (checkoption(L, 1, "TLS", opts)) { -#ifndef OPENSSL_NO_SSL2 - case 0: /* SSLv2 */ - method = (srv)? &SSLv2_server_method : &SSLv2_client_method; - break; -#endif - case 1: /* SSLv3 */ - method = (srv)? &SSLv3_server_method : &SSLv3_client_method; - break; - case 2: /* SSLv23 */ - /* FALL THROUGH */ - case 3: /* SSL */ - method = (srv)? &SSLv23_server_method : &SSLv23_client_method; - break; - case 4: /* TLSv1 */ - /* FALL THROUGH */ - case 5: /* TLS */ - method = (srv)? &TLSv1_server_method : &TLSv1_client_method; - break; - } - - ud = prepsimple(L, SSL_CTX_CLASS); - - if (!(*ud = SSL_CTX_new(method()))) - return throwssl(L, "ssl.context.new"); - - return 1; -} /* sx_new() */ - - -static int sx_interpose(lua_State *L) { - return interpose(L, SSL_CTX_CLASS); -} /* sx_interpose() */ - - -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); - - lua_pushboolean(L, 1); - - return 1; -} /* sx_setStore() */ - - -static int sx_setVerify(lua_State *L) { - SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - int mode = luaL_optint(L, 2, -1); - int depth = luaL_optint(L, 3, -1); - - if (mode != -1) - SSL_CTX_set_verify(ctx, mode, 0); - - if (depth != -1) - SSL_CTX_set_verify_depth(ctx, depth); - - lua_pushboolean(L, 1); - - return 1; -} /* sx_setVerify() */ - - -static int sx_getVerify(lua_State *L) { - SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - - lua_pushinteger(L, SSL_CTX_get_verify_mode(ctx)); - lua_pushinteger(L, SSL_CTX_get_verify_depth(ctx)); - - return 2; -} /* sx_getVerify() */ - - -static int sx_setCertificate(lua_State *L) { - SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - X509 *crt = X509_dup(checksimple(L, 2, X509_CERT_CLASS)); - int ok; - - ok = SSL_CTX_use_certificate(ctx, crt); - X509_free(crt); - - if (!ok) - return throwssl(L, "ssl.context:setCertificate"); - - lua_pushboolean(L, 1); - - return 1; -} /* sx_setCertificate() */ - - -static int sx_setPrivateKey(lua_State *L) { - SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); - - /* - * NOTE: No easy way to dup the key, but a shared reference should - * be okay as keys are less mutable than certificates. - */ - if (!SSL_CTX_use_PrivateKey(ctx, key)) - return throwssl(L, "ssl.context:setPrivateKey"); - - lua_pushboolean(L, 1); - - return 1; -} /* sx_setPrivateKey() */ - - -static int sx_setCipherList(lua_State *L) { - SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); - const char *ciphers = luaL_checkstring(L, 2); - - if (!SSL_CTX_set_cipher_list(ctx, ciphers)) - return throwssl(L, "ssl.context:setCipherList"); - - lua_pushboolean(L, 1); - - return 1; -} /* sx_setCipherList() */ - - -static int sx__gc(lua_State *L) { - SSL_CTX **ud = luaL_checkudata(L, 1, SSL_CTX_CLASS); - - SSL_CTX_free(*ud); - *ud = NULL; - - return 0; -} /* sx__gc() */ - - -static const luaL_Reg sx_methods[] = { - { "setStore", &sx_setStore }, - { "setVerify", &sx_setVerify }, - { "getVerify", &sx_getVerify }, - { "setCertificate", &sx_setCertificate }, - { "setPrivateKey", &sx_setPrivateKey }, - { "setCipherList", &sx_setCipherList }, - { NULL, NULL }, -}; - -static const luaL_Reg sx_metatable[] = { - { "__gc", &sx__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg sx_globals[] = { - { "new", &sx_new }, - { "interpose", &sx_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_ssl_context(lua_State *L) { - initall(L); - - luaL_newlib(L, sx_globals); - - lua_pushinteger(L, SSL_VERIFY_NONE); - lua_setfield(L, -2, "VERIFY_NONE"); - - lua_pushinteger(L, SSL_VERIFY_PEER); - lua_setfield(L, -2, "VERIFY_PEER"); - - lua_pushinteger(L, SSL_VERIFY_FAIL_IF_NO_PEER_CERT); - lua_setfield(L, -2, "VERIFY_FAIL_IF_NO_PEER_CERT"); - - lua_pushinteger(L, SSL_VERIFY_CLIENT_ONCE); - lua_setfield(L, -2, "VERIFY_CLIENT_ONCE"); - - return 1; -} /* luaopen__openssl_ssl_context() */ - - -/* - * SSL - openssl.ssl - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static int ssl_new(lua_State *L) { - lua_pushnil(L); - - return 1; -} /* ssl_new() */ - - -static int ssl_interpose(lua_State *L) { - return interpose(L, SSL_CLASS); -} /* ssl_interpose() */ - - -static int ssl_getPeerCertificate(lua_State *L) { - SSL *ssl = checksimple(L, 1, SSL_CLASS); - X509 **x509 = prepsimple(L, X509_CERT_CLASS); - - if (!(*x509 = SSL_get_peer_certificate(ssl))) - return 0; - - return 1; -} /* ssl_getPeerCertificate() */ - - -static int ssl_getPeerChain(lua_State *L) { - SSL *ssl = checksimple(L, 1, SSL_CLASS); - STACK_OF(X509) *chain; - - if (!(chain = SSL_get_peer_cert_chain(ssl))) - return 0; - - xl_dup(L, chain, 0); - - return 1; -} /* ssl_getPeerChain() */ - - -static int ssl_getCipherInfo(lua_State *L) { - SSL *ssl = checksimple(L, 1, SSL_CLASS); - const SSL_CIPHER *cipher; - char descr[256]; - - if (!(cipher = SSL_get_current_cipher(ssl))) - return 0; - - lua_newtable(L); - - lua_pushstring(L, SSL_CIPHER_get_name(cipher)); - lua_setfield(L, -2, "name"); - - lua_pushinteger(L, SSL_CIPHER_get_bits(cipher, 0)); - lua_setfield(L, -2, "bits"); - - lua_pushstring(L, SSL_CIPHER_get_version(cipher)); - lua_setfield(L, -2, "version"); - - lua_pushstring(L, SSL_CIPHER_description(cipher, descr, sizeof descr)); - lua_setfield(L, -2, "description"); - - return 1; -} /* ssl_getCipherInfo() */ - - -static int ssl__gc(lua_State *L) { - SSL **ud = luaL_checkudata(L, 1, SSL_CLASS); - - SSL_free(*ud); - *ud = NULL; - - return 0; -} /* ssl__gc() */ - - -static const luaL_Reg ssl_methods[] = { - { "getPeerCertificate", &ssl_getPeerCertificate }, - { "getPeerChain", &ssl_getPeerChain }, - { "getCipherInfo", &ssl_getCipherInfo }, - { NULL, NULL }, -}; - -static const luaL_Reg ssl_metatable[] = { - { "__gc", &ssl__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg ssl_globals[] = { - { "new", &ssl_new }, - { "interpose", &ssl_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_ssl(lua_State *L) { - initall(L); - - luaL_newlib(L, ssl_globals); - - return 1; -} /* luaopen__openssl_ssl() */ - - -/* - * Digest - openssl.digest - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static const EVP_MD *md_optdigest(lua_State *L, int index) { - const char *name = luaL_optstring(L, index, "sha1"); - const EVP_MD *type; - - if (!(type = EVP_get_digestbyname(name))) - luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid digest type", name)); - - return type; -} /* md_optdigest() */ - - -static int md_new(lua_State *L) { - const EVP_MD *type = md_optdigest(L, 1); - EVP_MD_CTX *ctx; - - ctx = prepudata(L, sizeof *ctx, DIGEST_CLASS, NULL); - - EVP_MD_CTX_init(ctx); - - if (!EVP_DigestInit_ex(ctx, type, NULL)) - return throwssl(L, "digest.new"); - - return 1; -} /* md_new() */ - - -static int md_interpose(lua_State *L) { - return interpose(L, DIGEST_CLASS); -} /* md_interpose() */ - - -static void md_update_(lua_State *L, EVP_MD_CTX *ctx, int from, int to) { - int i; - - for (i = from; i <= to; i++) { - const void *p; - size_t n; - - p = luaL_checklstring(L, i, &n); - - if (!EVP_DigestUpdate(ctx, p, n)) - throwssl(L, "digest:update"); - } -} /* md_update_() */ - - -static int md_update(lua_State *L) { - EVP_MD_CTX *ctx = luaL_checkudata(L, 1, DIGEST_CLASS); - int i, top = lua_gettop(L); - - md_update_(L, ctx, 2, lua_gettop(L)); - - lua_pushboolean(L, 1); - - return 1; -} /* md_update() */ - - -static int md_final(lua_State *L) { - EVP_MD_CTX *ctx = luaL_checkudata(L, 1, DIGEST_CLASS); - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned len; - - md_update_(L, ctx, 2, lua_gettop(L)); - - if (!EVP_DigestFinal_ex(ctx, md, &len)) - return throwssl(L, "digest:final"); - - lua_pushlstring(L, (char *)md, len); - - return 1; -} /* md_final() */ - - -static int md__gc(lua_State *L) { - EVP_MD_CTX *ctx = luaL_checkudata(L, 1, DIGEST_CLASS); - - EVP_MD_CTX_cleanup(ctx); - - return 0; -} /* md__gc() */ - - -static const luaL_Reg md_methods[] = { - { "update", &md_update }, - { "final", &md_final }, - { NULL, NULL }, -}; - -static const luaL_Reg md_metatable[] = { - { "__gc", &md__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg md_globals[] = { - { "new", &md_new }, - { "interpose", &md_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_digest(lua_State *L) { - initall(L); - - luaL_newlib(L, md_globals); - - return 1; -} /* luaopen__openssl_digest() */ - - -/* - * HMAC - openssl.hmac - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static int hmac_new(lua_State *L) { - const void *key; - size_t len; - const EVP_MD *type; - HMAC_CTX *ctx; - - key = luaL_checklstring(L, 1, &len); - type = md_optdigest(L, 2); - - ctx = prepudata(L, sizeof *ctx, HMAC_CLASS, NULL); - - HMAC_Init_ex(ctx, key, len, type, NULL); - - return 1; -} /* hmac_new() */ - - -static int hmac_interpose(lua_State *L) { - return interpose(L, HMAC_CLASS); -} /* hmac_interpose() */ - - -static void hmac_update_(lua_State *L, HMAC_CTX *ctx, int from, int to) { - int i; - - for (i = from; i <= to; i++) { - const void *p; - size_t n; - - p = luaL_checklstring(L, i, &n); - - HMAC_Update(ctx, p, n); - } -} /* hmac_update_() */ - - -static int hmac_update(lua_State *L) { - HMAC_CTX *ctx = luaL_checkudata(L, 1, HMAC_CLASS); - - hmac_update_(L, ctx, 2, lua_gettop(L)); - - lua_pushboolean(L, 1); - - return 1; -} /* hmac_update() */ - - -static int hmac_final(lua_State *L) { - HMAC_CTX *ctx = luaL_checkudata(L, 1, HMAC_CLASS); - unsigned char hmac[EVP_MAX_MD_SIZE]; - unsigned len; - - hmac_update_(L, ctx, 2, lua_gettop(L)); - - HMAC_Final(ctx, hmac, &len); - - lua_pushlstring(L, (char *)hmac, len); - - return 1; -} /* hmac_final() */ - - -static int hmac__gc(lua_State *L) { - HMAC_CTX *ctx = luaL_checkudata(L, 1, HMAC_CLASS); - - HMAC_CTX_cleanup(ctx); - - return 0; -} /* hmac__gc() */ - - -static const luaL_Reg hmac_methods[] = { - { "update", &hmac_update }, - { "final", &hmac_final }, - { NULL, NULL }, -}; - -static const luaL_Reg hmac_metatable[] = { - { "__gc", &hmac__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg hmac_globals[] = { - { "new", &hmac_new }, - { "interpose", &hmac_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_hmac(lua_State *L) { - initall(L); - - luaL_newlib(L, hmac_globals); - - return 1; -} /* luaopen__openssl_hmac() */ - - -/* - * Cipher - openssl.cipher - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static const EVP_CIPHER *cipher_checktype(lua_State *L, int index) { - const char *name = luaL_checkstring(L, index); - const EVP_CIPHER *type; - - if (!(type = EVP_get_cipherbyname(name))) - luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid cipher type", name)); - - return type; -} /* cipher_checktype() */ - - -static int cipher_new(lua_State *L) { - const EVP_CIPHER *type; - EVP_CIPHER_CTX *ctx; - - type = cipher_checktype(L, 1); - - ctx = prepudata(L, sizeof *ctx, CIPHER_CLASS, NULL); - EVP_CIPHER_CTX_init(ctx); - - if (!EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, -1)) - return throwssl(L, "cipher.new"); - - return 1; -} /* cipher_new() */ - - -static int cipher_interpose(lua_State *L) { - return interpose(L, HMAC_CLASS); -} /* cipher_interpose() */ - - -static int cipher_init(lua_State *L, _Bool encrypt) { - EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); - const void *key, *iv; - size_t n, m; - - key = luaL_checklstring(L, 2, &n); - m = (size_t)EVP_CIPHER_CTX_key_length(ctx); - luaL_argcheck(L, n == m, 2, lua_pushfstring(L, "%d: invalid key length (should be %d)", (int)n, (int)m)); - - iv = luaL_optlstring(L, 3, NULL, &n); - m = (size_t)EVP_CIPHER_CTX_iv_length(ctx); - luaL_argcheck(L, n == m, 3, lua_pushfstring(L, "%d: invalid IV length (should be %d)", (int)n, (int)m)); - - if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, encrypt)) - goto sslerr; - - if (!lua_isnoneornil(L, 4)) { - luaL_checktype(L, 4, LUA_TBOOLEAN); - - if (!EVP_CIPHER_CTX_set_padding(ctx, lua_toboolean(L, 4))) - goto sslerr; - } - - lua_settop(L, 1); - - return 1; -sslerr: - return throwssl(L, (encrypt)? "cipher:encrypt" : "cipher:decrypt"); -} /* cipher_init() */ - - -static int cipher_encrypt(lua_State *L) { - return cipher_init(L, 1); -} /* cipher_encrypt() */ - - -static int cipher_decrypt(lua_State *L) { - return cipher_init(L, 0); -} /* cipher_decrypt() */ - - -static _Bool cipher_update_(lua_State *L, EVP_CIPHER_CTX *ctx, luaL_Buffer *B, int from, int to) { - const unsigned char *p, *pe; - size_t block, step, n; - int i; - - block = EVP_CIPHER_CTX_block_size(ctx); - - if (LUAL_BUFFERSIZE < block * 2) - luaL_error(L, "cipher:update: LUAL_BUFFERSIZE(%d) < 2 * EVP_CIPHER_CTX_block_size(%d)", (int)LUAL_BUFFERSIZE, (int)block); - - step = LUAL_BUFFERSIZE - block; - - for (i = from; i <= to; i++) { - p = (const unsigned char *)luaL_checklstring(L, i, &n); - pe = p + n; - - while (p < pe) { - int in = (int)MIN((size_t)(pe - p), step), out; - - if (!EVP_CipherUpdate(ctx, (void *)luaL_prepbuffer(B), &out, p, in)) - return 0; - - p += in; - luaL_addsize(B, out); - } - } - - return 1; -} /* cipher_update_() */ - - -static int cipher_update(lua_State *L) { - EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); - luaL_Buffer B; - - luaL_buffinit(L, &B); - - if (!cipher_update_(L, ctx, &B, 2, lua_gettop(L))) - goto sslerr; - - luaL_pushresult(&B); - - return 1; -sslerr: - lua_pushnil(L); - pusherror(L, NULL); - - return 2; -} /* cipher_update() */ - - -static int cipher_final(lua_State *L) { - EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); - luaL_Buffer B; - size_t block; - int out; - - luaL_buffinit(L, &B); - - if (!cipher_update_(L, ctx, &B, 2, lua_gettop(L))) - goto sslerr; - - block = EVP_CIPHER_CTX_block_size(ctx); - - if (LUAL_BUFFERSIZE < block) - return luaL_error(L, "cipher:update: LUAL_BUFFERSIZE(%d) < EVP_CIPHER_CTX_block_size(%d)", (int)LUAL_BUFFERSIZE, (int)block); - - if (!EVP_CipherFinal(ctx, (void *)luaL_prepbuffer(&B), &out)) - goto sslerr; - - luaL_addsize(&B, out); - luaL_pushresult(&B); - - return 1; -sslerr: - lua_pushnil(L); - pusherror(L, NULL); - - return 2; -} /* cipher_final() */ - - -static int cipher__gc(lua_State *L) { - EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); - - EVP_CIPHER_CTX_cleanup(ctx); - - return 0; -} /* cipher__gc() */ - - -static const luaL_Reg cipher_methods[] = { - { "encrypt", &cipher_encrypt }, - { "decrypt", &cipher_decrypt }, - { "update", &cipher_update }, - { "final", &cipher_final }, - { NULL, NULL }, -}; - -static const luaL_Reg cipher_metatable[] = { - { "__gc", &cipher__gc }, - { NULL, NULL }, -}; - -static const luaL_Reg cipher_globals[] = { - { "new", &cipher_new }, - { "interpose", &cipher_interpose }, - { NULL, NULL }, -}; - -int luaopen__openssl_cipher(lua_State *L) { - initall(L); - - luaL_newlib(L, cipher_globals); - - return 1; -} /* luaopen__openssl_cipher() */ - - -/* - * Rand - openssl.rand - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static int rand_bytes(lua_State *L) { - int size = luaL_checkint(L, 1); - luaL_Buffer B; - int count = 0, n; - - luaL_buffinit(L, &B); - - while (count < size) { - n = MIN((size - count), LUAL_BUFFERSIZE); - - if (!RAND_bytes((void *)luaL_prepbuffer(&B), n)) - return throwssl(L, "rand.bytes"); - - luaL_addsize(&B, n); - count += n; - } - - luaL_pushresult(&B); - - return 1; -} /* rand_bytes() */ - - -static int rand_ready(lua_State *L) { - lua_pushboolean(L, RAND_status() == 1); - - return 1; -} /* rand_ready() */ - - -static unsigned long long rand_llu(lua_State *L) { - unsigned long long llu; - - if (!RAND_bytes((void *)&llu, sizeof llu)) - throwssl(L, "rand.uniform"); - - return llu; -} /* rand_llu() */ - -/* - * The following algorithm for rand_uniform() is taken from OpenBSD's - * arc4random_uniform, written by Otto Moerbeek, with subsequent - * simplification by Jorden Verwer. Otto's source code comment reads - * - * Uniformity is achieved by generating new random numbers until the one - * returned is outside the range [0, 2**32 % upper_bound). This guarantees - * the selected random number will be inside [2**32 % upper_bound, 2**32) - * which maps back to [0, upper_bound) after reduction modulo upper_bound. - * - * -- - * A more bit-efficient approach by the eminent statistician Herman Rubin - * can be found in this sci.crypt Usenet post. - * - * From: hrubin@odds.stat.purdue.edu (Herman Rubin) - * Newsgroups: sci.crypt - * Subject: Re: Generating a random number between 0 and N-1 - * Date: 14 Nov 2002 11:20:37 -0500 - * Organization: Purdue University Statistics Department - * Lines: 40 - * Message-ID: - * References: <3DCD8D75.40408@nospam.com> - * NNTP-Posting-Host: odds.stat.purdue.edu - * X-Trace: mozo.cc.purdue.edu 1037290837 9316 128.210.141.13 (14 Nov 2002 16:20:37 GMT) - * X-Complaints-To: ne...@news.purdue.edu - * NNTP-Posting-Date: Thu, 14 Nov 2002 16:20:37 +0000 (UTC) - * Xref: archiver1.google.com sci.crypt:78935 - * - * In article <3DCD8D7...@nospam.com>, - * Michael Amling wrote: - * >Carlos Moreno wrote: - * - * I have already posted on this, but a repeat might be - * in order. - * - * If one can trust random bits, the most bitwise efficient - * manner to get a single random integer between 0 and N-1 - * can be obtained as follows; the code can be made more - * computationally efficient. I believe it is easier to - * understand with gotos. I am assuming N>1. - * - * i = 0; j = 1; - * - * loop: j=2*j; i=2*i+RANBIT; - * if (j < N) goto loop; - * if (i >= N) { - * i = i - N; - * j = j - N; - * goto loop:} - * else return (i); - * - * The algorithm works because at each stage i is uniform - * between 0 and j-1. - * - * Another possibility is to generate k bits, where 2^k >= N. - * If 2^k = c*N + remainder, generate the appropriate value - * if a k-bit random number is less than c*N. - * - * For N = 17 (numbers just larger than powers of 2 are "bad"), - * the amount of information is about 4.09 bits, the best - * algorithm to generate one random number takes about 5.765 - * bits, taking k = 5 uses 9.412 bits, taking k = 6 or 7 uses - * 7.529 bits. These are averages, but the tails are not bad. - * - * (https://groups.google.com/forum/message/raw?msg=sci.crypt/DMslf6tSrD8/rv9rk6oP3r4J) - */ -static int rand_uniform(lua_State *L) { - if (lua_isnoneornil(L, 1)) { - unsigned long long r = rand_llu(L); - - lua_pushnumber(L, r); - - return 1; - } else { - unsigned long long N = luaL_checknumber(L, 1); - unsigned long long r, m; - - luaL_argcheck(L, N > 1, 1, lua_pushfstring(L, "[0, %d): interval is empty", (int)N)); - - m = -N % N; - - do { - r = rand_llu(L); - } while (r < m); - - lua_pushnumber(L, (r % N)); - - return 1; - } -} /* rand_uniform() */ - - -static const luaL_Reg rand_globals[] = { - { "bytes", &rand_bytes }, - { "ready", &rand_ready }, - { "uniform", &rand_uniform }, - { NULL, NULL }, -}; - -int luaopen__openssl_rand(lua_State *L) { - initall(L); - - luaL_newlib(L, rand_globals); - - return 1; -} /* luaopen__openssl_rand() */ - - -static void initall(lua_State *L) { - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); - - addclass(L, BIGNUM_CLASS, bn_methods, bn_metatable); - addclass(L, PUBKEY_CLASS, pk_methods, pk_metatable); - addclass(L, X509_NAME_CLASS, xn_methods, xn_metatable); - addclass(L, X509_GENS_CLASS, gn_methods, gn_metatable); - addclass(L, X509_CERT_CLASS, xc_methods, xc_metatable); - addclass(L, X509_CSR_CLASS, xr_methods, xr_metatable); - addclass(L, X509_CHAIN_CLASS, xl_methods, xl_metatable); - addclass(L, X509_STORE_CLASS, xs_methods, xs_metatable); - addclass(L, SSL_CTX_CLASS, sx_methods, sx_metatable); - addclass(L, SSL_CLASS, ssl_methods, ssl_metatable); - addclass(L, DIGEST_CLASS, md_methods, md_metatable); - addclass(L, HMAC_CLASS, hmac_methods, hmac_metatable); - addclass(L, CIPHER_CLASS, cipher_methods, cipher_metatable); -} /* initall() */ - - -#endif /* L_OPENSSL_H */ diff --git a/openssl.cipher.lua b/openssl.cipher.lua deleted file mode 100644 index 876cd1b..0000000 --- a/openssl.cipher.lua +++ /dev/null @@ -1,3 +0,0 @@ -local ctx = require"_openssl.cipher" - -return ctx diff --git a/openssl.digest.lua b/openssl.digest.lua deleted file mode 100644 index 87cc958..0000000 --- a/openssl.digest.lua +++ /dev/null @@ -1,3 +0,0 @@ -local ctx = require"_openssl.digest" - -return ctx diff --git a/openssl.hmac.lua b/openssl.hmac.lua deleted file mode 100644 index e622d1d..0000000 --- a/openssl.hmac.lua +++ /dev/null @@ -1,3 +0,0 @@ -local ctx = require"_openssl.hmac" - -return ctx diff --git a/openssl.pubkey.lua b/openssl.pubkey.lua deleted file mode 100644 index 6dc5614..0000000 --- a/openssl.pubkey.lua +++ /dev/null @@ -1,4 +0,0 @@ -local pubkey = require"_openssl.pubkey" - -return pubkey - diff --git a/openssl.rand.lua b/openssl.rand.lua deleted file mode 100644 index 70e9d3f..0000000 --- a/openssl.rand.lua +++ /dev/null @@ -1,3 +0,0 @@ -local ctx = require"_openssl.rand" - -return ctx diff --git a/openssl.ssl.context.lua b/openssl.ssl.context.lua deleted file mode 100644 index 44a9163..0000000 --- a/openssl.ssl.context.lua +++ /dev/null @@ -1,3 +0,0 @@ -local ctx = require"_openssl.ssl.context" - -return ctx diff --git a/openssl.ssl.lua b/openssl.ssl.lua deleted file mode 100644 index 3c348f6..0000000 --- a/openssl.ssl.lua +++ /dev/null @@ -1,3 +0,0 @@ -local ctx = require"_openssl.ssl" - -return ctx diff --git a/openssl.x509.altname.lua b/openssl.x509.altname.lua deleted file mode 100644 index 66f16e7..0000000 --- a/openssl.x509.altname.lua +++ /dev/null @@ -1,13 +0,0 @@ -local altname = require"_openssl.x509.altname" - -altname.interpose("__tostring", function (self) - local t = { } - - for k, v in pairs(self) do - t[#t + 1] = k .. ":" .. v - end - - return table.concat(t, ", ") -end) - -return altname diff --git a/openssl.x509.chain.lua b/openssl.x509.chain.lua deleted file mode 100644 index e89dec8..0000000 --- a/openssl.x509.chain.lua +++ /dev/null @@ -1,3 +0,0 @@ -local chain = require"_openssl.x509.chain" - -return chain diff --git a/openssl.x509.lua b/openssl.x509.lua deleted file mode 100644 index 278baf5..0000000 --- a/openssl.x509.lua +++ /dev/null @@ -1,3 +0,0 @@ -local x509 = require"_openssl.x509.cert" - -return x509 diff --git a/openssl.x509.name.lua b/openssl.x509.name.lua deleted file mode 100644 index a531502..0000000 --- a/openssl.x509.name.lua +++ /dev/null @@ -1,13 +0,0 @@ -local name = require"_openssl.x509.name" - -name.interpose("__tostring", function (self) - local t = { } - - for k, v in pairs(self) do - t[#t + 1] = k .. "=" .. v - end - - return table.concat(t, ", ") -end) - -return name diff --git a/openssl.x509.store.lua b/openssl.x509.store.lua deleted file mode 100644 index a717870..0000000 --- a/openssl.x509.store.lua +++ /dev/null @@ -1,3 +0,0 @@ -local store = require"_openssl.x509.store" - -return store diff --git a/src/GNUmakefile b/src/GNUmakefile new file mode 100644 index 0000000..fcf79a6 --- /dev/null +++ b/src/GNUmakefile @@ -0,0 +1,214 @@ +# non-recursive prologue +sp := $(sp).x +dirstack_$(sp) := $(d) +d := $(abspath $(lastword $(MAKEFILE_LIST))/..) + +ifeq ($(origin GUARD_$(d)), undefined) +GUARD_$(d) := 1 + + +# +# E N V I R O N M E N T C O N F I G U R A T I O N +# +include $(d)/../GNUmakefile + + +# +# C O M P I L A T I O N F L A G S +# +OS_$(d) = $(shell $(d)/../mk/vendor.os) +CC_$(d) = $(shell $(d)/../mk/vendor.cc) +LUAPATH_$(d) = $(shell env CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" $(" + +help: $(d)/help + + +endif # include guard + +# non-recursive epilogue +d := $(dirstack_$(sp)) +sp := $(basename $(sp)) diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..d0f0d47 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,7 @@ +.POSIX: + +all: + +gmake -f GNUmakefile all + +.DEFAULT: + +gmake -f GNUmakefile $< diff --git a/src/compat52.h b/src/compat52.h new file mode 100644 index 0000000..96ec9b2 --- /dev/null +++ b/src/compat52.h @@ -0,0 +1,152 @@ +/* ========================================================================== + * compat52.h - Routines for Lua 5.2 compatibility + * -------------------------------------------------------------------------- + * Copyright (c) 2012 William Ahern + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * ========================================================================== + */ +#if LUA_VERSION_NUM < 502 + +#define LUA_OK 0 + + +static void luaL_setmetatable(lua_State *L, const char *tname) { + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} /* luaL_setmetatable() */ + + +static int lua_absindex(lua_State *L, int idx) { + return (idx > 0 || idx <= LUA_REGISTRYINDEX)? idx : lua_gettop(L) + idx + 1; +} /* lua_absindex() */ + + +static void *luaL_testudata(lua_State *L, int arg, const char *tname) { + void *p = lua_touserdata(L, arg); + int eq; + + if (!p || !lua_getmetatable(L, arg)) + return 0; + + luaL_getmetatable(L, tname); + eq = lua_rawequal(L, -2, -1); + lua_pop(L, 2); + + return (eq)? p : 0; +} /* luaL_testudate() */ + + +static void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { + int i, t = lua_absindex(L, -1 - nup); + + for (; l->name; l++) { + for (i = 0; i < nup; i++) + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); + lua_setfield(L, t, l->name); + } + + lua_pop(L, nup); +} /* luaL_setfuncs() */ + + +#define luaL_newlibtable(L, l) \ + lua_createtable(L, 0, (sizeof (l) / sizeof *(l)) - 1) + +#define luaL_newlib(L, l) \ + (luaL_newlibtable((L), (l)), luaL_setfuncs((L), (l), 0)) + + +static void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) { + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); + lua_call(L, 1, 1); + + lua_getglobal(L, "package"); + lua_getfield(L, -1, "loaded"); + lua_pushvalue(L, -3); + lua_setfield(L, -2, modname); + + lua_pop(L, 2); + + if (glb) { + lua_pushvalue(L, -1); + lua_setglobal(L, modname); + } +} /* luaL_requiref() */ + + +#define lua_resume(L, from, nargs) lua_resume((L), (nargs)) + + +static void lua_rawgetp(lua_State *L, int index, const void *p) { + index = lua_absindex(L, index); + lua_pushlightuserdata(L, (void *)p); + lua_rawget(L, index); +} /* lua_rawgetp() */ + +static void lua_rawsetp(lua_State *L, int index, const void *p) { + index = lua_absindex(L, index); + lua_pushlightuserdata(L, (void *)p); + lua_pushvalue(L, -2); + lua_rawset(L, index); + lua_pop(L, 1); +} /* lua_rawsetp() */ + + +#ifndef LUA_UNSIGNED +#define LUA_UNSIGNED unsigned +#endif + +typedef LUA_UNSIGNED lua_Unsigned; + + +static void lua_pushunsigned(lua_State *L, lua_Unsigned n) { + lua_pushnumber(L, (lua_Number)n); +} /* lua_pushunsigned() */ + +static lua_Unsigned luaL_checkunsigned(lua_State *L, int arg) { + return (lua_Unsigned)luaL_checknumber(L, arg); +} /* luaL_checkunsigned() */ + + +static lua_Unsigned luaL_optunsigned(lua_State *L, int arg, lua_Unsigned def) { + return (lua_Unsigned)luaL_optnumber(L, arg, (lua_Number)def); +} /* luaL_optunsigned() */ + + +#ifndef LUA_FILEHANDLE /* Not defined by earlier LuaJIT releases */ +#define LUA_FILEHANDLE "FILE*" +#endif + +/* + * Lua 5.1 userdata is a simple FILE *, while LuaJIT is a struct with the + * first member a FILE *, similar to Lua 5.2. + */ +typedef struct luaL_Stream { + FILE *f; +} luaL_Stream; + + +#define lua_rawlen(...) lua_objlen(__VA_ARGS__) + + +#endif /* LUA_VERSION_NUM < 502 */ diff --git a/src/openssl.bignum.lua b/src/openssl.bignum.lua new file mode 100644 index 0000000..3090a68 --- /dev/null +++ b/src/openssl.bignum.lua @@ -0,0 +1,3 @@ +local bignum = require"_openssl.bignum" + +return bignum diff --git a/src/openssl.c b/src/openssl.c new file mode 100644 index 0000000..c8af43d --- /dev/null +++ b/src/openssl.c @@ -0,0 +1,3929 @@ +/* ========================================================================== + * openssl.c - Lua OpenSSL + * -------------------------------------------------------------------------- + * Copyright (c) 2012 William Ahern + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * ========================================================================== + */ +#ifndef L_OPENSSL_H +#define L_OPENSSH_H + +#include /* INT_MAX INT_MIN */ +#include /* memset(3) */ +#include /* strcasecmp(3) */ +#include /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ +#include /* struct tm time_t strptime(3) */ + +#include +#include /* struct stat stat(2) */ +#include /* AF_INET AF_INET6 */ + +#include /* struct in_addr struct in6_addr */ +#include /* inet_pton(3) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if LUA_VERSION_NUM < 502 +#include "compat52.h" +#endif + +#define BIGNUM_CLASS "BIGNUM*" +#define PUBKEY_CLASS "EVP_PKEY*" +#define X509_NAME_CLASS "X509_NAME*" +#define X509_GENS_CLASS "GENERAL_NAMES*" +#define X509_CERT_CLASS "X509*" +#define X509_CHAIN_CLASS "STACK_OF(X509)*" +#define X509_CSR_CLASS "X509_REQ*" +#define X509_STORE_CLASS "X509_STORE*" +#define X509_STCTX_CLASS "X509_STORE_CTX*" +#define SSL_CTX_CLASS "SSL_CTX*" +#define SSL_CLASS "SSL*" +#define DIGEST_CLASS "EVP_MD_CTX" /* not a pointer */ +#define HMAC_CLASS "HMAC_CTX" /* not a pointer */ +#define CIPHER_CLASS "EVP_CIPHER_CTX" /* not a pointer */ + + +#define countof(a) (sizeof (a) / sizeof *(a)) +#define endof(a) (&(a)[countof(a)]) + +#define CLAMP(i, min, max) (((i) < (min))? (min) : ((i) > (max))? (max) : (i)) + +#undef MIN +#define MIN(a, b) (((a) < (b))? (a) : (b)) + +#define stricmp(a, b) strcasecmp((a), (b)) +#define strieq(a, b) (!stricmp((a), (b))) + +#define SAY_(file, func, line, fmt, ...) \ + fprintf(stderr, "%s:%d: " fmt "%s", __func__, __LINE__, __VA_ARGS__) + +#define SAY(...) SAY_(__FILE__, __func__, __LINE__, __VA_ARGS__, "\n") + +#define HAI SAY("hai") + + +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); + + if (tname) { + luaL_setmetatable(L, tname); + } else { + lua_newtable(L); + lua_pushcfunction(L, gc); + lua_setfield(L, -2, "__gc"); + lua_setmetatable(L, -2); + } + + return p; +} /* prepudata() */ + + +static void *prepsimple(lua_State *L, const char *tname, int (*gc)(lua_State *)) { + void **p = prepudata(L, sizeof (void *), tname, gc); + return p; +} /* prepsimple() */ + +#define prepsimple_(a, b, c, ...) prepsimple((a), (b), (c)) +#define prepsimple(...) prepsimple_(__VA_ARGS__, 0) + + +static void *checksimple(lua_State *L, int index, const char *tname) { + void **p; + + if (tname) { + p = luaL_checkudata(L, index, tname); + } else { + luaL_checktype(L, index, LUA_TUSERDATA); + p = lua_touserdata(L, index); + } + + return *p; +} /* checksimple() */ + + +static void *testsimple(lua_State *L, int index, const char *tname) { + void **p; + + if (tname) { + p = luaL_testudata(L, index, tname); + } else { + luaL_checktype(L, index, LUA_TUSERDATA); + p = lua_touserdata(L, index); + } + + return (p)? *p : (void *)0; +} /* testsimple() */ + + +static const char *pusherror(lua_State *L, const char *fun) { + unsigned long code; + const char *path, *file; + int line; + char txt[256]; + + 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); + + if (!strncmp("__", luaL_checkstring(L, 1), 2)) + lua_pushvalue(L, -1); + else + lua_getfield(L, -1, "__index"); + + lua_pushvalue(L, -4); /* push method name */ + lua_gettable(L, -2); /* push old method */ + + lua_pushvalue(L, -5); /* push method name */ + lua_pushvalue(L, -5); /* push new method */ + lua_settable(L, -4); /* replace old method */ + + return 1; /* return old method */ +} /* interpose() */ + + +static void addclass(lua_State *L, const char *name, const luaL_Reg *methods, const luaL_Reg *metamethods) { + if (luaL_newmetatable(L, name)) { + luaL_setfuncs(L, metamethods, 0); + lua_newtable(L); + luaL_setfuncs(L, methods, 0); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + } +} /* addclass() */ + + +static int checkoption(struct lua_State *L, int index, const char *def, const char *opts[]) { + const char *opt = (def)? luaL_optstring(L, index, def) : luaL_checkstring(L, index); + int i; + + for (i = 0; opts[i]; i++) { + if (strieq(opts[i], opt)) + return i; + } + + return luaL_argerror(L, index, lua_pushfstring(L, "invalid option %s", opt)); +} /* checkoption() */ + + +static _Bool getfield(lua_State *L, int index, const char *k) { + lua_getfield(L, index, k); + + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + + return 0; + } else { + return 1; + } +} /* getfield() */ + + +static _Bool loadfield(lua_State *L, int index, const char *k, int type, void *p) { + if (!getfield(L, index, k)) + return 0; + + switch (type) { + case LUA_TSTRING: + *(const char **)p = luaL_checkstring(L, -1); + break; + case LUA_TNUMBER: + *(lua_Number *)p = luaL_checknumber(L, -1); + break; + default: + luaL_error(L, "loadfield(type=%d): invalid type", type); + break; + } /* switch() */ + + lua_pop(L, 1); /* table keeps reference */ + + return 1; +} /* loadfield() */ + + +static const char *pushnid(lua_State *L, int nid) { + const char *txt; + ASN1_OBJECT *obj; + char buf[256]; + int len; + + if ((txt = OBJ_nid2sn(nid)) || (txt = OBJ_nid2ln(nid))) { + lua_pushstring(L, txt); + } else { + if (!(obj = OBJ_nid2obj(nid))) + luaL_error(L, "%d: unknown ASN.1 NID", nid); + + if (-1 == (len = OBJ_obj2txt(buf, sizeof buf, obj, 1))) + luaL_error(L, "%d: invalid ASN.1 NID", nid); + + lua_pushlstring(L, buf, len); + } + + return lua_tostring(L, -1); +} /* pushnid() */ + + +static void initall(lua_State *L); + + +/* + * BIGNUM - openssl.bignum + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static BIGNUM *bn_push(lua_State *L) { + BIGNUM **ud = prepsimple(L, BIGNUM_CLASS); + + if (!(*ud = BN_new())) + throwssl(L, "bignum.new"); + + return *ud; +} /* bn_push() */ + + +#define checkbig_(a, b, c, ...) checkbig((a), (b), (c)) +#define checkbig(...) checkbig_(__VA_ARGS__, &(_Bool){ 0 }) + +static BIGNUM *(checkbig)(lua_State *, int, _Bool *); + +static int bn_new(lua_State *L) { + int i, n; + + if ((n = lua_gettop(L)) > 0) { + for (i = 1; i <= n; i++) + checkbig(L, i); + + return n; + } else { + bn_push(L); + + return 1; + } +} /* bn_new() */ + + +static int bn_interpose(lua_State *L) { + return interpose(L, BIGNUM_CLASS); +} /* bn_interpose() */ + + +/* return integral part */ +static inline double intof(double f) { + return (isfinite(f))? floor(fabs(f)) : 0.0; +} /* intof() */ + + +/* convert integral to BN_ULONG. returns success or failure. */ +static _Bool int2ul(BN_ULONG *ul, double f) { + int exp; + + frexp(f, &exp); + + if (exp > (int)sizeof *ul * 8) + return 0; + + *ul = (BN_ULONG)f; + + return 1; +} /* int2ul() */ + + +/* convert integral BIGNUM. returns success or failure. */ +static _Bool int2bn(BIGNUM **bn, double q) { + unsigned char nib[32], bin[32], *p; + size_t i, n; + double r; + + p = nib; + + while (q >= 1.0 && p < endof(nib)) { + r = fmod(q, 256.0); + *p++ = r; + q = round((q - r) / 256.0); + } + + n = p - nib; + + for (i = 0; i < n; i++) { + bin[i] = *--p; + } + + if (!(*bn = BN_bin2bn(bin, n, *bn))) + return 0; + + return 1; +} /* int2bn() */ + + +/* convert double to BIGNUM. returns success or failure. */ +static _Bool f2bn(BIGNUM **bn, double f) { + double i = intof(f); + BN_ULONG lu; + + if (int2ul(&lu, i)) { + if (!*bn && !(*bn = BN_new())) + return 0; + + if (!BN_set_word(*bn, lu)) + return 0; + } else if (!int2bn(bn, i)) + return 0; + + BN_set_negative(*bn, signbit(f)); + + return 1; +} /* f2bn() */ + + +static BIGNUM *(checkbig)(lua_State *L, int index, _Bool *lvalue) { + BIGNUM **bn; + const char *dec; + size_t len; + + index = lua_absindex(L, index); + + switch (lua_type(L, index)) { + case LUA_TSTRING: + *lvalue = 0; + + dec = lua_tolstring(L, index, &len); + + luaL_argcheck(L, len > 0 && *dec, index, "invalid big number string"); + + bn = prepsimple(L, BIGNUM_CLASS); + + if (!BN_dec2bn(bn, dec)) + throwssl(L, "bignum"); + + lua_replace(L, index); + + return *bn; + case LUA_TNUMBER: + *lvalue = 0; + + bn = prepsimple(L, BIGNUM_CLASS); + + if (!f2bn(bn, lua_tonumber(L, index))) + throwssl(L, "bignum"); + + lua_replace(L, index); + + return *bn; + default: + *lvalue = 1; + + return checksimple(L, index, BIGNUM_CLASS); + } /* switch() */ +} /* checkbig() */ + + +static void bn_prepops(lua_State *L, BIGNUM **r, BIGNUM **a, BIGNUM **b, _Bool commute) { + _Bool lvalue = 1; + + lua_settop(L, 2); /* a, b */ + + *a = checkbig(L, 1, &lvalue); + + if (!lvalue && commute) + lua_pushvalue(L, 1); + + *b = checkbig(L, 2, &lvalue); + + if (!lvalue && commute && lua_gettop(L) < 3) + lua_pushvalue(L, 2); + + if (lua_gettop(L) < 3) + bn_push(L); + + *r = *(BIGNUM **)lua_touserdata(L, 3); +} /* bn_prepops() */ + + +static int ctx__gc(lua_State *L) { + BN_CTX **ctx = lua_touserdata(L, 1); + + BN_CTX_free(*ctx); + *ctx = NULL; + + return 0; +} /* ctx__gc() */ + +static BN_CTX *getctx(lua_State *L) { + BN_CTX **ctx; + + lua_pushcfunction(L, &ctx__gc); + lua_gettable(L, LUA_REGISTRYINDEX); + + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + + ctx = prepsimple(L, NULL, &ctx__gc); + + if (!(*ctx = BN_CTX_new())) + throwssl(L, "bignum"); + + lua_pushcfunction(L, &ctx__gc); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + + ctx = lua_touserdata(L, -1); + lua_pop(L, 1); + + return *ctx; +} /* getctx() */ + + +static int bn__add(lua_State *L) { + BIGNUM *r, *a, *b; + + bn_prepops(L, &r, &a, &b, 1); + + if (!BN_add(r, a, b)) + return throwssl(L, "bignum:__add"); + + return 1; +} /* bn__add() */ + + +static int bn__sub(lua_State *L) { + BIGNUM *r, *a, *b; + + bn_prepops(L, &r, &a, &b, 0); + + if (!BN_sub(r, a, b)) + return throwssl(L, "bignum:__sub"); + + return 1; +} /* bn__sub() */ + + +static int bn__mul(lua_State *L) { + BIGNUM *r, *a, *b; + + bn_prepops(L, &r, &a, &b, 1); + + if (!BN_mul(r, a, b, getctx(L))) + return throwssl(L, "bignum:__mul"); + + return 1; +} /* bn__mul() */ + + +static int bn__div(lua_State *L) { + BIGNUM *r, *a, *b; + BN_CTX *ctx; + + bn_prepops(L, &r, &a, &b, 0); + + if (!BN_div(r, NULL, a, b, getctx(L))) + return throwssl(L, "bignum:__div"); + + return 1; +} /* bn__div() */ + + +static int bn__mod(lua_State *L) { + BIGNUM *r, *a, *b; + BN_CTX *ctx; + + bn_prepops(L, &r, &a, &b, 0); + + if (!BN_mod(r, a, b, getctx(L))) + return throwssl(L, "bignum:__mod"); + + return 1; +} /* bn__mod() */ + + +static int bn__pow(lua_State *L) { + BIGNUM *r, *a, *b; + BN_CTX *ctx; + + bn_prepops(L, &r, &a, &b, 0); + + if (!BN_exp(r, a, b, getctx(L))) + return throwssl(L, "bignum:__pow"); + + return 1; +} /* bn__pow() */ + + +static int bn__unm(lua_State *L) { + BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); + + BN_set_negative(a, !BN_is_negative(a)); + + return 1; +} /* bn__unm() */ + + +static int bn__eq(lua_State *L) { + BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); + BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); + + lua_pushboolean(L, 0 == BN_cmp(a, b)); + + return 1; +} /* bn__eq() */ + + +static int bn__lt(lua_State *L) { + BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); + BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); + int cmp = BN_cmp(a, b); + + lua_pushboolean(L, cmp == -1); + + return 1; +} /* bn__lt() */ + + +static int bn__le(lua_State *L) { + BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); + BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); + int cmp = BN_cmp(a, b); + + lua_pushboolean(L, cmp <= 0); + + return 1; +} /* bn__le() */ + + +static int bn__gc(lua_State *L) { + BIGNUM **ud = luaL_checkudata(L, 1, BIGNUM_CLASS); + + BN_free(*ud); + *ud = NULL; + + return 0; +} /* bn__gc() */ + + +static int bn__tostring(lua_State *L) { + BIGNUM *bn = checksimple(L, 1, BIGNUM_CLASS); + char *txt; + + if (!(txt = BN_bn2dec(bn))) + throwssl(L, "bignum:__tostring"); + + lua_pushstring(L, txt); + + return 1; +} /* bn__tostring() */ + + +static const luaL_Reg bn_methods[] = { + { NULL, NULL }, +}; + +static const luaL_Reg bn_metatable[] = { + { "__add", &bn__add }, + { "__sub", &bn__sub }, + { "__mul", &bn__mul }, + { "__div", &bn__div }, + { "__mod", &bn__mod }, + { "__pow", &bn__pow }, + { "__unm", &bn__unm }, + { "__eq", &bn__eq }, + { "__lt", &bn__lt }, + { "__le", &bn__le }, + { "__gc", &bn__gc }, + { "__tostring", &bn__tostring }, + { NULL, NULL }, +}; + + +static const luaL_Reg bn_globals[] = { + { "new", &bn_new }, + { "interpose", &bn_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_bignum(lua_State *L) { + initall(L); + + luaL_newlib(L, bn_globals); + + return 1; +} /* luaopen__openssl_bignum() */ + + +/* + * EVP_PKEY - openssl.pubkey + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int bio__gc(lua_State *L) { + BIO **bio = lua_touserdata(L, 1); + + BIO_free(*bio); + *bio = NULL; + + return 0; +} /* bio__gc() */ + +static BIO *getbio(lua_State *L) { + BIO **bio; + + lua_pushcfunction(L, &bio__gc); + lua_gettable(L, LUA_REGISTRYINDEX); + + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + + bio = prepsimple(L, NULL, &bio__gc); + + if (!(*bio = BIO_new(BIO_s_mem()))) + throwssl(L, "BIO_new"); + + lua_pushcfunction(L, &bio__gc); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + + bio = lua_touserdata(L, -1); + lua_pop(L, 1); + + BIO_reset(*bio); + + return *bio; +} /* getbio() */ + + +static int pk_new(lua_State *L) { + EVP_PKEY **ud; + + lua_settop(L, 1); + + ud = prepsimple(L, PUBKEY_CLASS); + + if (lua_istable(L, 1)) { + int type = EVP_PKEY_RSA; + unsigned bits = 1024; + unsigned exp = 65537; + int curve = NID_X9_62_prime192v1; + const char *id; + lua_Number n; + + if (!lua_istable(L, 1)) + goto creat; + + if (loadfield(L, 1, "type", LUA_TSTRING, &id)) { + static const struct { int nid; const char *sn; } types[] = { + { EVP_PKEY_RSA, "RSA" }, + { EVP_PKEY_DSA, "DSA" }, + { EVP_PKEY_DH, "DH" }, + { EVP_PKEY_EC, "EC" }, + }; + unsigned i; + + type = OBJ_sn2nid(id); + + if (NID_undef == (type = EVP_PKEY_type(OBJ_sn2nid(id)))) { + for (i = 0; i < countof(types); i++) { + if (strieq(id, types[i].sn)) { + type = types[i].nid; + break; + } + } + } + + luaL_argcheck(L, type != NID_undef, 1, lua_pushfstring(L, "%s: invalid key type", id)); + } + + if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { + luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); + bits = (unsigned)n; + } + + if (loadfield(L, 1, "exp", LUA_TNUMBER, &n)) { + luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `exp' invalid", n)); + exp = (unsigned)n; + } + + if (loadfield(L, 1, "curve", LUA_TSTRING, &id)) { + curve = OBJ_sn2nid(id); + luaL_argcheck(L, curve != NID_undef, 1, lua_pushfstring(L, "%s: invalid curve", id)); + } + +creat: + if (!(*ud = EVP_PKEY_new())) + return throwssl(L, "pubkey.new"); + + switch (EVP_PKEY_type(type)) { + case EVP_PKEY_RSA: { + RSA *rsa; + + if (!(rsa = RSA_generate_key(bits, exp, 0, 0))) + return throwssl(L, "pubkey.new"); + + EVP_PKEY_set1_RSA(*ud, rsa); + + RSA_free(rsa); + + break; + } + case EVP_PKEY_DSA: { + DSA *dsa; + + if (!(dsa = DSA_generate_parameters(bits, 0, 0, 0, 0, 0, 0))) + return throwssl(L, "pubkey.new"); + + if (!DSA_generate_key(dsa)) { + DSA_free(dsa); + return throwssl(L, "pubkey.new"); + } + + EVP_PKEY_set1_DSA(*ud, dsa); + + DSA_free(dsa); + + break; + } + case EVP_PKEY_DH: { + DH *dh; + + if (!(dh = DH_generate_parameters(bits, exp, 0, 0))) + return throwssl(L, "pubkey.new"); + + if (!DH_generate_key(dh)) { + DH_free(dh); + return throwssl(L, "pubkey.new"); + } + + EVP_PKEY_set1_DH(*ud, dh); + + DH_free(dh); + + break; + } +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: { + EC_GROUP *grp; + EC_KEY *key; + + if (!(grp = EC_GROUP_new_by_curve_name(curve))) + return throwssl(L, "pubkey.new"); + + EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_NAMED_CURVE); + + /* compressed points patented */ + EC_GROUP_set_point_conversion_form(grp, POINT_CONVERSION_UNCOMPRESSED); + + if (!(key = EC_KEY_new())) { + EC_GROUP_free(grp); + return throwssl(L, "pubkey.new"); + } + + EC_KEY_set_group(key, grp); + + EC_GROUP_free(grp); + + if (!EC_KEY_generate_key(key)) { + EC_KEY_free(key); + return throwssl(L, "pubkey.new"); + } + + EVP_PKEY_set1_EC_KEY(*ud, key); + + EC_KEY_free(key); + + break; + } +#endif + default: + return luaL_error(L, "%d: unknown EVP base type (%d)", EVP_PKEY_type(type), type); + } /* switch() */ + } else { + const char *pem; + size_t len; + BIO *bio; + int ok; + + if (!(*ud = EVP_PKEY_new())) + return throwssl(L, "pubkey.new"); + + switch (lua_type(L, 1)) { + case LUA_TSTRING: + pem = luaL_checklstring(L, 1, &len); + + if (!(bio = BIO_new_mem_buf((void *)pem, len))) + return throwssl(L, "pubkey.new"); + + if (strstr(pem, "PUBLIC KEY")) { + ok = !!PEM_read_bio_PUBKEY(bio, ud, 0, 0); + } else { + ok = !!PEM_read_bio_PrivateKey(bio, ud, 0, 0); + } + + BIO_free(bio); + + if (!ok) + return throwssl(L, "pubkey.new"); + + break; + default: + return luaL_error(L, "%s: unknown key initializer", lua_typename(L, lua_type(L, 1))); + } /* switch() */ + } + + return 1; +} /* pk_new() */ + + +static int pk_interpose(lua_State *L) { + return interpose(L, X509_NAME_CLASS); +} /* pk_interpose() */ + + +static int pk_type(lua_State *L) { + EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); + int nid = key->type; + + pushnid(L, nid); + + return 1; +} /* pk_type() */ + + +static int pk_setPublicKey(lua_State *L) { + EVP_PKEY **key = luaL_checkudata(L, 1, PUBKEY_CLASS); + const char *pem; + size_t len; + BIO *bio; + int ok; + + lua_settop(L, 2); + + pem = luaL_checklstring(L, 2, &len); + + if (!(bio = BIO_new_mem_buf((void *)pem, len))) + return throwssl(L, "pubkey.new"); + + ok = !!PEM_read_bio_PUBKEY(bio, key, 0, 0); + + BIO_free(bio); + + if (!ok) + return throwssl(L, "pubkey.new"); + + lua_pushboolean(L, 1); + + return 1; +} /* pk_setPublicKey() */ + + +static int pk_setPrivateKey(lua_State *L) { + EVP_PKEY **key = luaL_checkudata(L, 1, PUBKEY_CLASS); + const char *pem; + size_t len; + BIO *bio; + int ok; + + lua_settop(L, 2); + + pem = luaL_checklstring(L, 2, &len); + + if (!(bio = BIO_new_mem_buf((void *)pem, len))) + return throwssl(L, "pubkey.new"); + + ok = !!PEM_read_bio_PrivateKey(bio, key, 0, 0); + + BIO_free(bio); + + if (!ok) + return throwssl(L, "pubkey.new"); + + lua_pushboolean(L, 1); + + return 1; +} /* pk_setPrivateKEY() */ + + +static int pk_sign(lua_State *L) { + EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); + EVP_MD_CTX *md = luaL_checkudata(L, 2, DIGEST_CLASS); + luaL_Buffer B; + unsigned n; + + if (LUAL_BUFFERSIZE < EVP_PKEY_size(key)) + return luaL_error(L, "pubkey:sign: LUAL_BUFFERSIZE(%u) < EVP_PKEY_size(%u)", (unsigned)LUAL_BUFFERSIZE, (unsigned)EVP_PKEY_size(key)); + + luaL_buffinit(L, &B); + n = LUAL_BUFFERSIZE; + + if (!EVP_SignFinal(md, (void *)luaL_prepbuffer(&B), &n, key)) + return throwssl(L, "pubkey:sign"); + + luaL_addsize(&B, n); + luaL_pushresult(&B); + + return 1; +} /* pk_sign() */ + + +static int pk_verify(lua_State *L) { + EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); + size_t len; + const void *sig = luaL_checklstring(L, 2, &len); + EVP_MD_CTX *md = luaL_checkudata(L, 3, DIGEST_CLASS); + + switch (EVP_VerifyFinal(md, sig, len, key)) { + case 0: /* WRONG */ + ERR_clear_error(); + lua_pushboolean(L, 0); + + break; + case 1: /* OK */ + lua_pushboolean(L, 1); + + break; + default: + return throwssl(L, "pubkey:verify"); + } + + return 1; +} /* pk_verify() */ + + +static int pk_toPEM(lua_State *L) { + EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); + int top, i, ok; + BIO *bio; + char *pem; + long len; + + if (1 == (top = lua_gettop(L))) { + lua_pushstring(L, "publickey"); + ++top; + } + + bio = getbio(L); + + for (i = 2; i <= top; i++) { + static const char *opts[] = { + "public", "PublicKey", + "private", "PrivateKey", +// "params", "Parameters", + NULL, + }; + + switch (checkoption(L, i, NULL, opts)) { + case 0: case 1: /* public, PublicKey */ + if (!PEM_write_bio_PUBKEY(bio, key)) + return throwssl(L, "pubkey:__tostring"); + + len = BIO_get_mem_data(bio, &pem); + lua_pushlstring(L, pem, len); + + BIO_reset(bio); + break; + case 2: case 3: /* private, PrivateKey */ + if (!PEM_write_bio_PrivateKey(bio, key, 0, 0, 0, 0, 0)) + throwssl(L, "pubkey:__tostring"); + + len = BIO_get_mem_data(bio, &pem); + lua_pushlstring(L, pem, len); + + break; +#if 0 + case 4: case 5: /* params, Parameters */ + /* EVP_PKEY_base_id not in OS X */ + switch (EVP_PKEY_type(key->type)) { + case EVP_PKEY_RSA: + break; + case EVP_PKEY_DSA: { + DSA *dsa = EVP_PKEY_get1_DSA(key); + + ok = !!PEM_write_bio_DSAparams(bio, dsa); + + DSA_free(dsa); + + if (!ok) + return throwssl(L, "pubkey:__tostring"); + + break; + } + case EVP_PKEY_DH: { + DH *dh = EVP_PKEY_get1_DH(key); + + ok = !!PEM_write_bio_DHparams(bio, dh); + + DH_free(dh); + + if (!ok) + return throwssl(L, "pubkey:__tostring"); + + break; + } +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: { + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); + const EC_GROUP *grp = EC_KEY_get0_group(ec); + + ok = !!PEM_write_bio_ECPKParameters(bio, grp); + + EC_KEY_free(ec); + + if (!ok) + return throwssl(L, "pubkey:__tostring"); + + break; + } +#endif + default: + return luaL_error(L, "%d: unknown EVP base type", EVP_PKEY_type(key->type)); + } + + lua_pushlstring(L, pem, len); + + BIO_reset(bio); + + break; +#endif + default: + lua_pushnil(L); + + break; + } /* switch() */ + } /* for() */ + + return lua_gettop(L) - top; +} /* pk_toPEM() */ + + +static int pk__tostring(lua_State *L) { + EVP_PKEY *key = checksimple(L, 1, PUBKEY_CLASS); + BIO *bio = getbio(L); + char *pem; + long len; + int ok; + + if (!PEM_write_bio_PUBKEY(bio, key)) + return throwssl(L, "pubkey:__tostring"); + + len = BIO_get_mem_data(bio, &pem); + lua_pushlstring(L, pem, len); + + return 1; +} /* pk__tostring() */ + + +static int pk__gc(lua_State *L) { + EVP_PKEY **ud = luaL_checkudata(L, 1, PUBKEY_CLASS); + + EVP_PKEY_free(*ud); + *ud = NULL; + + return 0; +} /* pk__gc() */ + + +static const luaL_Reg pk_methods[] = { + { "type", &pk_type }, + { "setPublicKey", &pk_setPublicKey }, + { "setPrivateKey", &pk_setPrivateKey }, + { "sign", &pk_sign }, + { "verify", &pk_verify }, + { "toPEM", &pk_toPEM }, + { NULL, NULL }, +}; + +static const luaL_Reg pk_metatable[] = { + { "__tostring", &pk__tostring }, + { "__gc", &pk__gc }, + { NULL, NULL }, +}; + + +static const luaL_Reg pk_globals[] = { + { "new", &pk_new }, + { "interpose", &pk_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_pubkey(lua_State *L) { + initall(L); + + luaL_newlib(L, pk_globals); + + return 1; +} /* luaopen__openssl_pubkey() */ + + +/* + * X509_NAME - openssl.x509.name + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +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"); + + return *ud; +} /* xn_dup() */ + + +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 1; +} /* xn_new() */ + + +static int xn_interpose(lua_State *L) { + return interpose(L, X509_NAME_CLASS); +} /* xn_interpose() */ + + +static int xn_add(lua_State *L) { + X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); + const char *nid = luaL_checkstring(L, 2); + size_t len; + const char *txt = luaL_checklstring(L, 3, &len); + ASN1_OBJECT *obj; + int ok; + + if (!(obj = OBJ_txt2obj(nid, 0))) + return luaL_error(L, "x509.name:add: %s: invalid NID", nid); + + ok = !!X509_NAME_add_entry_by_OBJ(name, obj, MBSTRING_ASC, (unsigned char *)txt, len, -1, 0); + + ASN1_OBJECT_free(obj); + + if (!ok) + return throwssl(L, "x509.name:add"); + + lua_pushboolean(L, 1); + + return 1; +} /* xn_add() */ + + +static int xn_all(lua_State *L) { + X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); + int count = X509_NAME_entry_count(name); + X509_NAME_ENTRY *entry; + ASN1_OBJECT *obj; + const char *id; + char txt[256]; + int i, nid, len; + + lua_newtable(L); + + for (i = 0; i < count; i++) { + if (!(entry = X509_NAME_get_entry(name, i))) + continue; + + lua_newtable(L); + + obj = X509_NAME_ENTRY_get_object(entry); + nid = OBJ_obj2nid(obj); + + if (0 > (len = OBJ_obj2txt(txt, sizeof txt, obj, 1))) + return throwssl(L, "x509.name:all"); + + lua_pushlstring(L, txt, len); + + if (nid != NID_undef && ((id = OBJ_nid2ln(nid)) || (id = OBJ_nid2sn(nid)))) + lua_pushstring(L, id); + else + lua_pushvalue(L, -1); + + if (nid != NID_undef && (id = OBJ_nid2sn(nid))) + lua_pushstring(L, id); + else + lua_pushvalue(L, -1); + + lua_setfield(L, -4, "sn"); + lua_setfield(L, -3, "ln"); + lua_setfield(L, -2, "id"); + + len = ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)); + lua_pushlstring(L, (char *)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), len); + + lua_setfield(L, -2, "blob"); + + lua_rawseti(L, -2, i + 1); + } + + return 1; +} /* xn_all() */ + + +static int xn__next(lua_State *L) { + X509_NAME *name = checksimple(L, lua_upvalueindex(1), X509_NAME_CLASS); + X509_NAME_ENTRY *entry; + ASN1_OBJECT *obj; + const char *id; + char txt[256]; + int i, n, nid, len; + + lua_settop(L, 0); + + i = lua_tointeger(L, lua_upvalueindex(2)); + n = X509_NAME_entry_count(name); + + while (i < n) { + if (!(entry = X509_NAME_get_entry(name, i++))) + continue; + + obj = X509_NAME_ENTRY_get_object(entry); + nid = OBJ_obj2nid(obj); + + if (nid != NID_undef && ((id = OBJ_nid2sn(nid)) || (id = OBJ_nid2ln(nid)))) { + lua_pushstring(L, id); + } else { + if (0 > (len = OBJ_obj2txt(txt, sizeof txt, obj, 1))) + return throwssl(L, "x509.name:__pairs"); + + lua_pushlstring(L, txt, len); + } + + len = ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)); + lua_pushlstring(L, (char *)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), len); + + break; + } + + lua_pushinteger(L, i); + lua_replace(L, lua_upvalueindex(2)); + + return lua_gettop(L); +} /* xn__next() */ + +static int xn__pairs(lua_State *L) { + lua_settop(L, 1); + lua_pushinteger(L, 0); + + lua_pushcclosure(L, &xn__next, 2); + + return 1; +} /* xn__pairs() */ + + +static int xn__gc(lua_State *L) { + X509_NAME **ud = luaL_checkudata(L, 1, X509_NAME_CLASS); + + X509_NAME_free(*ud); + *ud = NULL; + + return 0; +} /* xn__gc() */ + + +static int xn__tostring(lua_State *L) { + X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); + char txt[1024] = { 0 }; + + /* FIXME: oneline is deprecated */ + X509_NAME_oneline(name, txt, sizeof txt); + + lua_pushstring(L, txt); + + return 1; +} /* xn__tostring() */ + + +static const luaL_Reg xn_methods[] = { + { "add", &xn_add }, + { "all", &xn_all }, + { NULL, NULL }, +}; + +static const luaL_Reg xn_metatable[] = { + { "__pairs", &xn__pairs }, + { "__gc", &xn__gc }, + { "__tostring", &xn__tostring }, + { NULL, NULL }, +}; + + +static const luaL_Reg xn_globals[] = { + { "new", &xn_new }, + { "interpose", &xn_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_x509_name(lua_State *L) { + initall(L); + + luaL_newlib(L, xn_globals); + + return 1; +} /* luaopen__openssl_x509_name() */ + + +/* + * GENERAL_NAMES - openssl.x509.altname + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +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"); + + return *ud; +} /* gn_dup() */ + + +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 1; +} /* gn_new() */ + + +static int gn_interpose(lua_State *L) { + return interpose(L, X509_GENS_CLASS); +} /* gn_interpose() */ + + +static int gn_setCritical(lua_State *L) { + GENERAL_NAMES *gens = checksimple(L, 1, X509_GENS_CLASS); + + return 0; +} /* gn_setCritical() */ + + +static int gn_checktype(lua_State *L, int index) { + static const struct { int type; const char *name; } table[] = { + { GEN_EMAIL, "RFC822Name" }, + { GEN_EMAIL, "RFC822" }, + { GEN_EMAIL, "email" }, + { GEN_URI, "UniformResourceIdentifier" }, + { GEN_URI, "URI" }, + { GEN_DNS, "DNSName" }, + { GEN_DNS, "DNS" }, + { GEN_IPADD, "IPAddress" }, + { GEN_IPADD, "IP" }, + }; + const char *type = luaL_checkstring(L, index); + unsigned i; + + for (i = 0; i < countof(table); i++) { + if (strieq(table[i].name, type)) + return table[i].type; + } + + return luaL_error(L, "%s: invalid type", type), 0; +} /* gn_checktype() */ + + +static int gn_add(lua_State *L) { + GENERAL_NAMES *gens = checksimple(L, 1, X509_GENS_CLASS); + int type = gn_checktype(L, 2); + size_t len; + const char *txt = luaL_checklstring(L, 3, &len); + GENERAL_NAME *gen = NULL; + union { struct in6_addr in6; struct in_addr in; } ip; + + if (type == GEN_IPADD) { + if (strchr(txt, ':')) { + if (1 != inet_pton(AF_INET6, txt, &ip.in6)) + return luaL_error(L, "%s: invalid address", txt); + + txt = (char *)ip.in6.s6_addr; + len = 16; + } else { + if (1 != inet_pton(AF_INET, txt, &ip.in)) + return luaL_error(L, "%s: invalid address", txt); + + txt = (char *)&ip.in.s_addr; + len = 4; + } + } + + if (!(gen = GENERAL_NAME_new())) + goto error; + + gen->type = type; + + if (!(gen->d.ia5 = M_ASN1_IA5STRING_new())) + goto error; + + if (!ASN1_STRING_set(gen->d.ia5, (unsigned char *)txt, len)) + goto error; + + sk_GENERAL_NAME_push(gens, gen); + + lua_pushboolean(L, 1); + + return 1; +error: + GENERAL_NAME_free(gen); + + return throwssl(L, "x509.altname:add"); +} /* gn_add() */ + + +static int gn__next(lua_State *L) { + GENERAL_NAMES *gens = checksimple(L, lua_upvalueindex(1), X509_GENS_CLASS); + int i = lua_tointeger(L, lua_upvalueindex(2)); + int n = sk_GENERAL_NAME_num(gens); + + lua_settop(L, 0); + + while (i < n) { + GENERAL_NAME *name; + const char *tag, *txt; + size_t len; + union { struct in_addr in; struct in6_addr in6; } ip; + char buf[INET6_ADDRSTRLEN + 1]; + int af; + + if (!(name = sk_GENERAL_NAME_value(gens, i++))) + continue; + + switch (name->type) { + case GEN_EMAIL: + tag = "email"; + txt = (char *)M_ASN1_STRING_data(name->d.rfc822Name); + len = M_ASN1_STRING_length(name->d.rfc822Name); + + break; + case GEN_URI: + tag = "URI"; + txt = (char *)M_ASN1_STRING_data(name->d.uniformResourceIdentifier); + len = M_ASN1_STRING_length(name->d.uniformResourceIdentifier); + + break; + case GEN_DNS: + tag = "DNS"; + txt = (char *)M_ASN1_STRING_data(name->d.dNSName); + len = M_ASN1_STRING_length(name->d.dNSName); + + break; + case GEN_IPADD: + tag = "IP"; + txt = (char *)M_ASN1_STRING_data(name->d.iPAddress); + len = M_ASN1_STRING_length(name->d.iPAddress); + + switch (len) { + case 16: + memcpy(ip.in6.s6_addr, txt, 16); + af = AF_INET6; + + break; + case 4: + memcpy(&ip.in.s_addr, txt, 4); + af = AF_INET; + + break; + default: + continue; + } + + if (!(txt = inet_ntop(af, &ip, buf, sizeof buf))) + continue; + + len = strlen(txt); + + break; + default: + continue; + } + + lua_pushstring(L, tag); + lua_pushlstring(L, txt, len); + + break; + } + + lua_pushinteger(L, i); + lua_replace(L, lua_upvalueindex(2)); + + return lua_gettop(L); +} /* gn__next() */ + +static int gn__pairs(lua_State *L) { + lua_settop(L, 1); + lua_pushinteger(L, 0); + lua_pushcclosure(L, &gn__next, 2); + + return 1; +} /* gn__pairs() */ + + +static int gn__gc(lua_State *L) { + GENERAL_NAMES **ud = luaL_checkudata(L, 1, X509_GENS_CLASS); + + sk_GENERAL_NAME_pop_free(*ud, GENERAL_NAME_free); + *ud = NULL; + + return 0; +} /* gn__gc() */ + + +static const luaL_Reg gn_methods[] = { + { "add", &gn_add }, + { NULL, NULL }, +}; + +static const luaL_Reg gn_metatable[] = { + { "__pairs", &gn__pairs }, + { "__gc", &gn__gc }, + { NULL, NULL }, +}; + + +static const luaL_Reg gn_globals[] = { + { "new", &gn_new }, + { "interpose", &gn_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_x509_altname(lua_State *L) { + initall(L); + + luaL_newlib(L, gn_globals); + + return 1; +} /* luaopen__openssl_x509_altname() */ + + +/* + * X509 - openssl.x509.cert + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int xc_new(lua_State *L) { + const char *pem; + size_t len; + X509 **ud; + + lua_settop(L, 1); + + ud = prepsimple(L, X509_CERT_CLASS); + + if ((pem = luaL_optlstring(L, 1, NULL, &len))) { + BIO *tmp; + int ok; + + if (!(tmp = BIO_new_mem_buf((char *)pem, len))) + return throwssl(L, "x509.cert.new"); + + ok = !!PEM_read_bio_X509(tmp, ud, 0, ""); /* no password */ + + BIO_free(tmp); + + if (!ok) + return throwssl(L, "x509.cert.new"); + } else { + if (!(*ud = X509_new())) + return throwssl(L, "x509.cert.new"); + + X509_gmtime_adj(X509_get_notBefore(*ud), 0); + X509_gmtime_adj(X509_get_notAfter(*ud), 0); + } + + return 1; +} /* xc_new() */ + + +static int xc_interpose(lua_State *L) { + return interpose(L, X509_CERT_CLASS); +} /* xc_interpose() */ + + +static int xc_getVersion(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + + lua_pushinteger(L, X509_get_version(crt) + 1); + + return 1; +} /* xc_getVersion() */ + + +static int xc_setVersion(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + int version = luaL_checkint(L, 2); + + if (!X509_set_version(crt, version - 1)) + return luaL_error(L, "x509.cert:setVersion: %d: invalid version", version); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setVersion() */ + + +static int xc_getSerial(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + BIGNUM *serial = bn_push(L); + ASN1_INTEGER *i; + + if ((i = X509_get_serialNumber(crt))) { + if (!ASN1_INTEGER_to_BN(i, serial)) + return throwssl(L, "x509.cert:getSerial"); + } + + return 1; +} /* xc_getSerial() */ + + +static int xc_setSerial(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + ASN1_INTEGER *serial; + + if (!(serial = BN_to_ASN1_INTEGER(checkbig(L, 2), NULL))) + goto error; + + if (!X509_set_serialNumber(crt, serial)) + goto error; + + ASN1_INTEGER_free(serial); + + lua_pushboolean(L, 1); + + return 1; +error: + ASN1_INTEGER_free(serial); + + return throwssl(L, "x509.cert:setSerial"); +} /* xc_setSerial() */ + + +static int xc_digest(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + const char *type = luaL_optstring(L, 2, "sha1"); + int format = luaL_checkoption(L, 3, "x", (const char *[]){ "s", "x", "n", NULL }); + const EVP_MD *ctx; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned len; + + lua_settop(L, 3); /* self, type, hex */ + + if (!(ctx = EVP_get_digestbyname(type))) + return luaL_error(L, "x509.cert:digest: %s: invalid digest type", type); + + X509_digest(crt, ctx, md, &len); + + switch (format) { + case 2: { + BIGNUM *bn = bn_push(L); + + if (!BN_bin2bn(md, len, bn)) + return throwssl(L, "x509.cert:digest"); + + break; + } + case 1: { + static const unsigned char x[16] = "0123456789abcdef"; + luaL_Buffer B; + unsigned i; + +#if LUA_VERSION_NUM < 502 + luaL_buffinit(L, &B); +#else + luaL_buffinitsize(L, &B, 2 * len); +#endif + + for (i = 0; i < len; i++) { + luaL_addchar(&B, x[0x0f & (md[i] >> 4)]); + luaL_addchar(&B, x[0x0f & (md[i] >> 0)]); + } + + luaL_pushresult(&B); + + break; + } + default: + lua_pushlstring(L, (const char *)md, len); + + break; + } /* switch() */ + + return 1; +} /* xc_digest() */ + + +static _Bool isleap(int year) { + if (year >= 0) + return !(year % 4) && ((year % 100) || !(year % 400)); + else + return isleap(-(year + 1)); +} /* isleap() */ + + +static int yday(int year, int mon, int mday) { + static const int past[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int yday = past[CLAMP(mon, 0, 11)] + CLAMP(mday, 1, 31) - 1; + + return yday + (mon > 1 && isleap(year)); +} /* yday() */ + + +static int tm_yday(const struct tm *tm) { + return (tm->tm_yday)? tm->tm_yday : yday(1900 + tm->tm_year, tm->tm_mon, tm->tm_mday); +} /* tm_yday() */ + + +static int leaps(int year) { + if (year >= 0) + return (year / 400) + (year / 4) - (year / 100); + else + return -(leaps(-(year + 1)) + 1); +} /* leaps() */ + + +static double tm2unix(const struct tm *tm, int gmtoff) { + int year = tm->tm_year + 1900; + double ts; + + ts = 86400.0 * 365.0 * (year - 1970); + ts += 86400.0 * (leaps(year - 1) - leaps(1969)); + ts += 86400 * tm_yday(tm); + ts += 3600 * tm->tm_hour; + ts += 60 * tm->tm_min; + ts += CLAMP(tm->tm_sec, 0, 59); + ts += (year < 1970)? gmtoff : -gmtoff; + + return ts; +} /* tm2unix() */ + + +static _Bool scan(int *i, char **cp, int n, int signok) { + int sign = 1; + + *i = 0; + + if (signok) { + if (**cp == '-') { + sign = -1; + ++*cp; + } else if (**cp == '+') { + ++*cp; + } + } + + while (n-- > 0) { + if (**cp < '0' || **cp > '9') + return 0; + + *i *= 10; + *i += *(*cp)++ - '0'; + } + + *i *= sign; + + return 1; +} /* scan() */ + + +static double timeutc(ASN1_TIME *time) { + char buf[32] = "", *cp; + struct tm tm = { 0 }; + int gmtoff = 0, year, i; + double ts; + + if (!ASN1_TIME_check(time)) + return 0; + + cp = strncpy(buf, (const char *)ASN1_STRING_data((ASN1_STRING *)time), sizeof buf - 1); + + if (ASN1_STRING_type(time) == V_ASN1_GENERALIZEDTIME) { + if (!scan(&year, &cp, 4, 1)) + goto badfmt; + } else { + if (!scan(&year, &cp, 2, 0)) + goto badfmt; + year += (year < 50)? 2000 : 1999; + } + + tm.tm_year = year - 1900; + + if (!scan(&i, &cp, 2, 0)) + goto badfmt; + + tm.tm_mon = CLAMP(i, 1, 12) - 1; + + if (!scan(&i, &cp, 2, 0)) + goto badfmt; + + tm.tm_mday = CLAMP(i, 1, 31); + + tm.tm_yday = yday(year, tm.tm_mon, tm.tm_mday); + + if (!scan(&i, &cp, 2, 0)) + goto badfmt; + + tm.tm_hour = CLAMP(i, 0, 23); + + if (!scan(&i, &cp, 2, 0)) + goto badfmt; + + tm.tm_min = CLAMP(i, 0, 59); + + if (*cp >= '0' && *cp <= '9') { + if (!scan(&i, &cp, 2, 0)) + goto badfmt; + + tm.tm_sec = CLAMP(i, 0, 59); + } + + if (*cp == '+' || *cp == '-') { + int sign = (*cp++ == '-')? -1 : 1; + int hh, mm; + + if (!scan(&hh, &cp, 2, 0) || !scan(&mm, &cp, 2, 0)) + goto badfmt; + + gmtoff = (CLAMP(hh, 0, 23) * 3600) + + (CLAMP(mm, 0, 59) * 60); + + gmtoff *= sign; + } + + return tm2unix(&tm, gmtoff); +badfmt: + return INFINITY; +} /* timeutc() */ + + +static int xc_getLifetime(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + double begin = INFINITY, end = INFINITY; + ASN1_TIME *time; + + if ((time = X509_get_notBefore(crt))) + begin = timeutc(time); + + if ((time = X509_get_notAfter(crt))) + end = timeutc(time); + + if (isfinite(begin)) + lua_pushnumber(L, begin); + else + lua_pushnil(L); + + if (isfinite(end)) + lua_pushnumber(L, end); + else + lua_pushnil(L); + + if (isfinite(begin) && isfinite(end) && begin <= end) + lua_pushnumber(L, fabs(end - begin)); + else + lua_pushnumber(L, 0.0); + + return 3; +} /* xc_getLifetime() */ + + +static int xc_setLifetime(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + ASN1_TIME *time; + double ut; + const char *dt; + + lua_settop(L, 3); + + if (lua_isnumber(L, 2)) { + ut = lua_tonumber(L, 2); + + if (!ASN1_TIME_set(X509_get_notBefore(crt), ut)) + return throwssl(L, "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"); +#endif + } + + if (lua_isnumber(L, 3)) { + ut = lua_tonumber(L, 3); + + if (!ASN1_TIME_set(X509_get_notAfter(crt), ut)) + return throwssl(L, "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"); +#endif + } + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setLifetime() */ + + +static int xc_getIssuer(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + X509_NAME *name; + + if (!(name = X509_get_issuer_name(crt))) + return 0; + + xn_dup(L, name); + + return 1; +} /* xc_getIssuer() */ + + +static int xc_setIssuer(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); + + if (!X509_set_issuer_name(crt, name)) + return throwssl(L, "x509.cert:setIssuer"); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setIssuer() */ + + +static int xc_getSubject(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + X509_NAME *name; + + if (!(name = X509_get_subject_name(crt))) + return 0; + + xn_dup(L, name); + + return 1; +} /* xc_getSubject() */ + + +static int xc_setSubject(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); + + if (!X509_set_subject_name(crt, name)) + return throwssl(L, "x509.cert:setSubject"); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setSubject() */ + + +static void xc_setCritical(X509 *crt, int nid, _Bool yes) { + X509_EXTENSION *ext; + int loc; + + if ((loc = X509_get_ext_by_NID(crt, nid, -1)) >= 0 + && (ext = X509_get_ext(crt, loc))) + X509_EXTENSION_set_critical(ext, yes); +} /* xc_setCritical() */ + + +static _Bool xc_getCritical(X509 *crt, int nid) { + X509_EXTENSION *ext; + int loc; + + if ((loc = X509_get_ext_by_NID(crt, nid, -1)) >= 0 + && (ext = X509_get_ext(crt, loc))) + return X509_EXTENSION_get_critical(ext); + else + return 0; +} /* xc_getCritical() */ + + +static int xc_getIssuerAlt(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + GENERAL_NAMES *gens; + + if (!(gens = X509_get_ext_d2i(crt, NID_issuer_alt_name, 0, 0))) + return 0; + + gn_dup(L, gens); + + return 1; +} /* xc_getIssuerAlt() */ + + +static int xc_setIssuerAlt(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + 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"); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setIssuerAlt() */ + + +static int xc_getSubjectAlt(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + GENERAL_NAMES *gens; + + if (!(gens = X509_get_ext_d2i(crt, NID_subject_alt_name, 0, 0))) + return 0; + + gn_dup(L, gens); + + return 1; +} /* xc_getSubjectAlt() */ + + +static int xc_setSubjectAlt(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + 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"); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setSubjectAlt() */ + + +static int xc_getIssuerAltCritical(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + + lua_pushboolean(L, xc_getCritical(crt, NID_issuer_alt_name)); + + return 1; +} /* xc_getIssuerAltCritical() */ + + +static int xc_setIssuerAltCritical(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + + luaL_checkany(L, 2); + xc_setCritical(crt, NID_issuer_alt_name, lua_toboolean(L, 2)); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setIssuerAltCritical() */ + + +static int xc_getSubjectAltCritical(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + + lua_pushboolean(L, xc_getCritical(crt, NID_subject_alt_name)); + + return 1; +} /* xc_getSubjectAltCritical() */ + + +static int xc_setSubjectAltCritical(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + + luaL_checkany(L, 2); + xc_setCritical(crt, NID_subject_alt_name, lua_toboolean(L, 2)); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setSubjectAltCritical() */ + + +static int xc_getBasicConstraint(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + BASIC_CONSTRAINTS *bs; + int CA, pathLen; + + if (!(bs = X509_get_ext_d2i(crt, NID_basic_constraints, 0, 0))) { + /* FIXME: detect error or just non-existent */ + + if (lua_gettop(L) > 1) + return 0; + + lua_newtable(L); + + return 1; + } + + CA = bs->ca; + pathLen = ASN1_INTEGER_get(bs->pathlen); + + BASIC_CONSTRAINTS_free(bs); + + if (lua_gettop(L) > 1) { + int n = 0, i, top; + + for (i = 2, top = lua_gettop(L); i <= top; i++) { + switch (checkoption(L, i, 0, (const char *[]){ "CA", "pathLen", "pathLenConstraint", NULL })) { + case 0: + lua_pushboolean(L, CA); + n++; + break; + case 1: + /* FALL THROUGH */ + case 2: + lua_pushinteger(L, pathLen); + n++; + break; + } + } + + return n; + } else { + lua_newtable(L); + + lua_pushboolean(L, CA); + lua_setfield(L, -2, "CA"); + + lua_pushinteger(L, pathLen); + lua_setfield(L, -2, "pathLen"); + + return 1; + } +} /* xc_getBasicConstraint() */ + + +static int xc_setBasicConstraint(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + BASIC_CONSTRAINTS *bs = 0; + int CA = -1, pathLen = -1; + int critical = 0; + + luaL_checkany(L, 2); + + if (lua_istable(L, 2)) { + lua_getfield(L, 2, "CA"); + if (!lua_isnil(L, -1)) + CA = lua_toboolean(L, -1); + lua_pop(L, 1); + + lua_getfield(L, 2, "pathLen"); + pathLen = luaL_optint(L, -1, pathLen); + lua_pop(L, 1); + + lua_getfield(L, 2, "pathLenConstraint"); + pathLen = luaL_optint(L, -1, pathLen); + lua_pop(L, 1); + + if (!(bs = BASIC_CONSTRAINTS_new())) + goto error; + } else { + lua_settop(L, 3); + + switch (checkoption(L, 2, 0, (const char *[]){ "CA", "pathLen", "pathLenConstraint", NULL })) { + case 0: + luaL_checktype(L, 3, LUA_TBOOLEAN); + CA = lua_toboolean(L, 3); + + break; + case 1: + /* FALL THROUGH */ + case 2: + pathLen = luaL_checkint(L, 3); + + break; + } + + if (!(bs = X509_get_ext_d2i(crt, NID_basic_constraints, &critical, 0))) { + /* FIXME: detect whether error or just non-existent */ + if (!(bs = BASIC_CONSTRAINTS_new())) + goto error; + } + } + + if (CA != -1) + bs->ca = CA; + + if (pathLen >= 0) { + ASN1_INTEGER_free(bs->pathlen); + + if (!(bs->pathlen = M_ASN1_INTEGER_new())) + goto error; + + if (!ASN1_INTEGER_set(bs->pathlen, pathLen)) + goto error; + } + + if (!X509_add1_ext_i2d(crt, NID_basic_constraints, bs, critical, X509V3_ADD_REPLACE)) + goto error; + + BASIC_CONSTRAINTS_free(bs); + + lua_pushboolean(L, 1); + + return 1; +error: + BASIC_CONSTRAINTS_free(bs); + + return throwssl(L, "x509.cert:setBasicConstraint"); +} /* xc_setBasicConstraint() */ + + +static int xc_getBasicConstraintsCritical(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + + lua_pushboolean(L, xc_getCritical(crt, NID_basic_constraints)); + + return 1; +} /* xc_getBasicConstraintsCritical() */ + + +static int xc_setBasicConstraintsCritical(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + + luaL_checkany(L, 2); + xc_setCritical(crt, NID_basic_constraints, lua_toboolean(L, 2)); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setBasicConstraintsCritical() */ + + +static int xc_isIssuedBy(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + X509 *issuer = checksimple(L, 2, X509_CERT_CLASS); + EVP_PKEY *key; + int ok, why = 0; + + ERR_clear_error(); + + if (X509_V_OK != (why = X509_check_issued(issuer, crt))) + goto done; + + if (!(key = X509_get_pubkey(issuer))) { + why = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; + goto done; + } + + ok = (1 == X509_verify(crt, key)); + + EVP_PKEY_free(key); + + if (!ok) + why = X509_V_ERR_CERT_SIGNATURE_FAILURE; + +done: + if (why != X509_V_OK) { + lua_pushboolean(L, 0); + lua_pushstring(L, X509_verify_cert_error_string(why)); + + return 2; + } else { + lua_pushboolean(L, 1); + + return 1; + } +} /* xc_isIssuedBy() */ + + +static int xc_getPublicKey(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + EVP_PKEY **key = prepsimple(L, PUBKEY_CLASS); + + if (!(*key = X509_get_pubkey(crt))) + return throwssl(L, "x509.cert:getPublicKey"); + + return 1; +} /* xc_getPublicKey() */ + + +static int xc_setPublicKey(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); + + if (!X509_set_pubkey(crt, key)) + return throwssl(L, "x509.cert:setPublicKey"); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_setPublicKey() */ + + +static const EVP_MD *xc_signature(lua_State *L, int index, EVP_PKEY *key) { + const char *id; + const EVP_MD *md; + + if ((id = luaL_optstring(L, index, NULL))) + return ((md = EVP_get_digestbyname(id)))? md : EVP_md_null(); + + switch (EVP_PKEY_type(key->type)) { + case EVP_PKEY_RSA: + return EVP_sha1(); + case EVP_PKEY_DSA: + return EVP_dss1(); + case EVP_PKEY_EC: + return EVP_ecdsa(); + default: + return EVP_md_null(); + } +} /* xc_signature() */ + +static int xc_sign(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); + + if (!X509_sign(crt, key, xc_signature(L, 3, key))) + return throwssl(L, "x509.cert:sign"); + + lua_pushboolean(L, 1); + + return 1; +} /* xc_sign() */ + + +static int xc__tostring(lua_State *L) { + X509 *crt = checksimple(L, 1, X509_CERT_CLASS); + int fmt = checkoption(L, 2, "pem", (const char *[]){ "pem", NULL }); + BIO *bio = getbio(L); + char *pem; + long len; + + if (!PEM_write_bio_X509(bio, crt)) + return throwssl(L, "x509.cert:__tostring"); + + len = BIO_get_mem_data(bio, &pem); + + lua_pushlstring(L, pem, len); + + return 1; +} /* xc__tostring() */ + + +static int xc__gc(lua_State *L) { + X509 **ud = luaL_checkudata(L, 1, X509_CERT_CLASS); + + X509_free(*ud); + *ud = NULL; + + return 0; +} /* xc__gc() */ + + +static const luaL_Reg xc_methods[] = { + { "getVersion", &xc_getVersion }, + { "setVersion", &xc_setVersion }, + { "getSerial", &xc_getSerial }, + { "setSerial", &xc_setSerial }, + { "digest", &xc_digest }, + { "getLifetime", &xc_getLifetime }, + { "setLifetime", &xc_setLifetime }, + { "getIssuer", &xc_getIssuer }, + { "setIssuer", &xc_setIssuer }, + { "getSubject", &xc_getSubject }, + { "setSubject", &xc_setSubject }, + { "getIssuerAlt", &xc_getIssuerAlt }, + { "setIssuerAlt", &xc_setIssuerAlt }, + { "getSubjectAlt", &xc_getSubjectAlt }, + { "setSubjectAlt", &xc_setSubjectAlt }, + { "getIssuerAltCritical", &xc_getIssuerAltCritical }, + { "setIssuerAltCritical", &xc_setIssuerAltCritical }, + { "getSubjectAltCritical", &xc_getSubjectAltCritical }, + { "setSubjectAltCritical", &xc_setSubjectAltCritical }, + { "getBasicConstraints", &xc_getBasicConstraint }, + { "getBasicConstraint", &xc_getBasicConstraint }, + { "setBasicConstraints", &xc_setBasicConstraint }, + { "setBasicConstraint", &xc_setBasicConstraint }, + { "getBasicConstraintsCritical", &xc_getBasicConstraintsCritical }, + { "setBasicConstraintsCritical", &xc_setBasicConstraintsCritical }, + { "isIssuedBy", &xc_isIssuedBy }, + { "getPublicKey", &xc_getPublicKey }, + { "setPublicKey", &xc_setPublicKey }, + { "sign", &xc_sign }, + { NULL, NULL }, +}; + +static const luaL_Reg xc_metatable[] = { + { "__tostring", &xc__tostring }, + { "__gc", &xc__gc }, + { NULL, NULL }, +}; + + +static const luaL_Reg xc_globals[] = { + { "new", &xc_new }, + { "interpose", &xc_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_x509_cert(lua_State *L) { + initall(L); + + luaL_newlib(L, xc_globals); + + return 1; +} /* luaopen__openssl_x509_cert() */ + + +/* + * X509_REQ - openssl.x509.csr + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int xr_new(lua_State *L) { + const char *pem; + size_t len; + X509_REQ **ud; + X509 *crt; + + lua_settop(L, 1); + + ud = prepsimple(L, X509_CSR_CLASS); + + if ((crt = testsimple(L, 1, X509_CERT_CLASS))) { + if (!(*ud = X509_to_X509_REQ(crt, 0, 0))) + return throwssl(L, "x509.csr.new"); + } else if ((pem = luaL_optlstring(L, 1, NULL, &len))) { + BIO *tmp; + int ok; + + if (!(tmp = BIO_new_mem_buf((char *)pem, len))) + return throwssl(L, "x509.csr.new"); + + ok = !!PEM_read_bio_X509_REQ(tmp, ud, 0, ""); /* no password */ + + BIO_free(tmp); + + if (!ok) + return throwssl(L, "x509.csr.new"); + } else { + if (!(*ud = X509_REQ_new())) + return throwssl(L, "x509.csr.new"); + } + + return 1; +} /* xr_new() */ + + +static int xr_interpose(lua_State *L) { + return interpose(L, X509_CSR_CLASS); +} /* xr_interpose() */ + + +static int xr_getVersion(lua_State *L) { + X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); + + lua_pushinteger(L, X509_REQ_get_version(csr) + 1); + + return 1; +} /* xr_getVersion() */ + + +static int xr_setVersion(lua_State *L) { + X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); + int version = luaL_checkint(L, 2); + + if (!X509_REQ_set_version(csr, version - 1)) + return luaL_error(L, "x509.csr:setVersion: %d: invalid version", version); + + lua_pushboolean(L, 1); + + return 1; +} /* xr_setVersion() */ + + +static int xr_getSubject(lua_State *L) { + X509_REQ *crt = checksimple(L, 1, X509_CSR_CLASS); + X509_NAME *name; + + if (!(name = X509_REQ_get_subject_name(crt))) + return 0; + + xn_dup(L, name); + + return 1; +} /* xr_getSubject() */ + + +static int xr_setSubject(lua_State *L) { + X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); + X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); + + if (!X509_REQ_set_subject_name(csr, name)) + return throwssl(L, "x509.csr:setSubject"); + + lua_pushboolean(L, 1); + + return 1; +} /* xr_setSubject() */ + + +static int xr_getPublicKey(lua_State *L) { + X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); + EVP_PKEY **key = prepsimple(L, PUBKEY_CLASS); + + if (!(*key = X509_REQ_get_pubkey(csr))) + return throwssl(L, "x509.cert:getPublicKey"); + + return 1; +} /* xr_getPublicKey() */ + + +static int xr_setPublicKey(lua_State *L) { + X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); + EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); + + if (!X509_REQ_set_pubkey(csr, key)) + return throwssl(L, "x509.csr:setPublicKey"); + + lua_pushboolean(L, 1); + + return 1; +} /* xr_setPublicKey() */ + + +static int xr_sign(lua_State *L) { + X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); + EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); + + if (!X509_REQ_sign(csr, key, xc_signature(L, 3, key))) + return throwssl(L, "x509.csr:sign"); + + lua_pushboolean(L, 1); + + return 1; +} /* xr_sign() */ + + +static int xr__tostring(lua_State *L) { + X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); + int fmt = checkoption(L, 2, "pem", (const char *[]){ "pem", NULL }); + BIO *bio = getbio(L); + char *pem; + long len; + + if (!PEM_write_bio_X509_REQ(bio, csr)) + return throwssl(L, "x509.csr:__tostring"); + + len = BIO_get_mem_data(bio, &pem); + + lua_pushlstring(L, pem, len); + + return 1; +} /* xr__tostring() */ + + +static int xr__gc(lua_State *L) { + X509_REQ **ud = luaL_checkudata(L, 1, X509_CSR_CLASS); + + X509_REQ_free(*ud); + *ud = NULL; + + return 0; +} /* xr__gc() */ + +static const luaL_Reg xr_methods[] = { + { "getVersion", &xr_getVersion }, + { "setVersion", &xr_setVersion }, + { "getSubject", &xr_getSubject }, + { "setSubject", &xr_setSubject }, + { "getPublicKey", &xr_getPublicKey }, + { "setPublicKey", &xr_setPublicKey }, + { "sign", &xr_sign }, + { NULL, NULL }, +}; + +static const luaL_Reg xr_metatable[] = { + { "__tostring", &xr__tostring }, + { "__gc", &xr__gc }, + { NULL, NULL }, +}; + + +static const luaL_Reg xr_globals[] = { + { "new", &xr_new }, + { "interpose", &xr_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_x509_csr(lua_State *L) { + initall(L); + + luaL_newlib(L, xr_globals); + + return 1; +} /* luaopen__openssl_x509_csr() */ + + +/* + * STACK_OF(X509) - openssl.x509.chain + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static void xl_dup(lua_State *L, STACK_OF(X509) *src, _Bool copy) { + STACK_OF(X509) **dst = prepsimple(L, X509_CHAIN_CLASS); + X509 *crt; + int i, n; + + if (copy) { + if (!(*dst = sk_X509_new_null())) + goto error; + + n = sk_X509_num(src); + + for (i = 0; i < n; i++) { + if (!(crt = sk_X509_value(src, i))) + continue; + + if (!(crt = X509_dup(crt))) + goto error; + + if (!sk_X509_push(*dst, crt)) { + X509_free(crt); + goto error; + } + } + } else { + if (!(*dst = sk_X509_dup(src))) + goto error; + + n = sk_X509_num(*dst); + + for (i = 0; i < n; i++) { + if (!(crt = sk_X509_value(*dst, i))) + continue; + CRYPTO_add(&crt->references, 1, CRYPTO_LOCK_X509); + } + } + + return; +error: + throwssl(L, "sk_X509_dup"); +} /* xl_dup() */ + + +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 1; +} /* xl_new() */ + + +static int xl_interpose(lua_State *L) { + return interpose(L, X509_CHAIN_CLASS); +} /* xl_interpose() */ + + +static int xl_add(lua_State *L) { + STACK_OF(X509) *chain = checksimple(L, 1, X509_CHAIN_CLASS); + X509 *crt = checksimple(L, 2, X509_CERT_CLASS); + X509 *dup; + + if (!(dup = X509_dup(crt))) + return throwssl(L, "x509.chain:add"); + + if (!sk_X509_push(chain, dup)) { + X509_free(dup); + return throwssl(L, "x509.chain:add"); + } + + lua_pushboolean(L, 1); + + return 1; +} /* xl_add() */ + + +static int xl__next(lua_State *L) { + STACK_OF(X509) *chain = checksimple(L, lua_upvalueindex(1), X509_CHAIN_CLASS); + int i = lua_tointeger(L, lua_upvalueindex(2)); + int n = sk_X509_num(chain); + + lua_settop(L, 0); + + while (i < n) { + X509 *crt, **ret; + + if (!(crt = sk_X509_value(chain, i++))) + continue; + + lua_pushinteger(L, i); + + ret = prepsimple(L, X509_CERT_CLASS); + + if (!(*ret = X509_dup(crt))) + return throwssl(L, "x509.chain:__next"); + + break; + } + + lua_pushinteger(L, i); + lua_replace(L, lua_upvalueindex(2)); + + return lua_gettop(L); +} /* xl__next() */ + +static int xl__pairs(lua_State *L) { + lua_settop(L, 1); + lua_pushinteger(L, 0); + lua_pushcclosure(L, &xl__next, 2); + + return 1; +} /* xl__pairs() */ + + +static int xl__gc(lua_State *L) { + STACK_OF(X509) **chain = luaL_checkudata(L, 1, X509_CHAIN_CLASS); + + sk_X509_pop_free(*chain, X509_free); + *chain = NULL; + + return 0; +} /* xl__gc() */ + + +static const luaL_Reg xl_methods[] = { + { "add", &xl_add }, + { NULL, NULL }, +}; + +static const luaL_Reg xl_metatable[] = { + { "__pairs", &xl__pairs }, + { "__ipairs", &xl__pairs }, + { "__gc", &xl__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg xl_globals[] = { + { "new", &xl_new }, + { "interpose", &xl_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_x509_chain(lua_State *L) { + initall(L); + + luaL_newlib(L, xl_globals); + + return 1; +} /* luaopen__openssl_x509_chain() */ + + +/* + * X509_STORE - openssl.x509.store + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +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 1; +} /* xs_new() */ + + +static int xs_interpose(lua_State *L) { + return interpose(L, X509_STORE_CLASS); +} /* xs_interpose() */ + + +static int xs_add(lua_State *L) { + X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); + int i, top = lua_gettop(L); + + for (i = 2; i <= top; i++) { + if (lua_isuserdata(L, i)) { + X509 *crt = checksimple(L, i, X509_CERT_CLASS); + X509 *dup; + + if (!(dup = X509_dup(crt))) + return throwssl(L, "x509.store:add"); + + if (!X509_STORE_add_cert(store, dup)) { + X509_free(dup); + return throwssl(L, "x509.store:add"); + } + } else { + const char *path = luaL_checkstring(L, i); + struct stat st; + int ok; + + if (0 != stat(path, &st)) + return luaL_error(L, "%s: %s", path, strerror(errno)); + + if (S_ISDIR(st.st_mode)) + ok = X509_STORE_load_locations(store, NULL, path); + else + ok = X509_STORE_load_locations(store, path, NULL); + + if (!ok) + return throwssl(L, "x509.store:add"); + } + } + + lua_pushboolean(L, 1); + + return 1; +} /* xs_add() */ + + +static int xs_verify(lua_State *L) { + X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); + X509 *crt = checksimple(L, 2, X509_CERT_CLASS); + STACK_OF(X509) *chain = NULL, **proof; + X509_STORE_CTX ctx; + int ok, why; + + /* pre-allocate space for a successful return */ + lua_settop(L, 3); + proof = prepsimple(L, X509_CHAIN_CLASS); + + if (!lua_isnoneornil(L, 3)) { + X509 *elm; + int i, n; + + if (!(chain = sk_X509_dup(checksimple(L, 3, X509_CHAIN_CLASS)))) + return throwssl(L, "x509.store:verify"); + + n = sk_X509_num(chain); + + for (i = 0; i < n; i++) { + if (!(elm = sk_X509_value(chain, i))) + continue; + CRYPTO_add(&elm->references, 1, CRYPTO_LOCK_X509); + } + } + + if (!X509_STORE_CTX_init(&ctx, store, crt, chain)) { + sk_X509_pop_free(chain, X509_free); + return throwssl(L, "x509.store:verify"); + } + + ERR_clear_error(); + + ok = X509_verify_cert(&ctx); + + switch (ok) { + case 1: /* verified */ + *proof = X509_STORE_CTX_get1_chain(&ctx); + + X509_STORE_CTX_cleanup(&ctx); + + if (!*proof) + return throwssl(L, "x509.store:verify"); + + lua_pushboolean(L, 1); + lua_pushvalue(L, -2); + + return 2; + case 0: /* not verified */ + why = X509_STORE_CTX_get_error(&ctx); + + X509_STORE_CTX_cleanup(&ctx); + + lua_pushboolean(L, 0); + lua_pushstring(L, X509_verify_cert_error_string(why)); + + return 2; + default: + X509_STORE_CTX_cleanup(&ctx); + + return throwssl(L, "x509.store:verify"); + } +} /* xs_verify() */ + + +static int xs__gc(lua_State *L) { + X509_STORE **ud = luaL_checkudata(L, 1, X509_STORE_CLASS); + + X509_STORE_free(*ud); + *ud = NULL; + + return 0; +} /* xs__gc() */ + + +static const luaL_Reg xs_methods[] = { + { "add", &xs_add }, + { "verify", &xs_verify }, + { NULL, NULL }, +}; + +static const luaL_Reg xs_metatable[] = { + { "__gc", &xs__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg xs_globals[] = { + { "new", &xs_new }, + { "interpose", &xs_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_x509_store(lua_State *L) { + initall(L); + + luaL_newlib(L, xs_globals); + + return 1; +} /* luaopen__openssl_x509_store() */ + + +/* + * X509_STORE_CTX - openssl.x509.store.context + * + * This object is intended to be a temporary container in OpenSSL, so the + * memory management is quite clumsy. In particular, it doesn't take + * ownership of the X509_STORE object, which means the reference must be + * held externally for the life of the X509_STORE_CTX object. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#if 0 +static int stx_new(lua_State *L) { + X509_STORE_CTX **ud = prepsimple(L, X509_STCTX_CLASS); + STACK_OF(X509) *chain; + + if (!(*ud = X509_STORE_CTX_new())) + return throwssl(L, "x509.store.context"); + + return 1; +} /* stx_new() */ + + +static int stx_interpose(lua_State *L) { + return interpose(L, X509_STCTX_CLASS); +} /* stx_interpose() */ + + +static int stx_add(lua_State *L) { + X509_STORE_CTX *ctx = checksimple(L, 1, X509_STCTX_CLASS); + + return 0; +} /* stx_add() */ + + +static int stx__gc(lua_State *L) { + X509_STORE **ud = luaL_checkudata(L, 1, X509_STORE_CLASS); + + X509_STORE_free(*ud); + *ud = NULL; + + return 0; +} /* stx__gc() */ + + +static const luaL_Reg stx_methods[] = { + { "add", &stx_add }, + { NULL, NULL }, +}; + +static const luaL_Reg stx_metatable[] = { + { "__gc", &stx__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg stx_globals[] = { + { "new", &stx_new }, + { "interpose", &stx_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_x509_store_context(lua_State *L) { + initall(L); + + luaL_newlib(L, stx_globals); + + return 1; +} /* luaopen__openssl_x509_store_context() */ +#endif + + +/* + * SSL_CTX - openssl.ssl.context + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int sx_new(lua_State *L) { + static const char *opts[] = { + "SSLv2", "SSLv3", "SSLv23", "SSL", "TLSv1", "TLS", NULL + }; + /* later versions of SSL declare a const qualifier on the return type */ + __typeof__(&TLSv1_client_method) method = &TLSv1_client_method; + _Bool srv; + SSL_CTX **ud; + + lua_settop(L, 2); + srv = lua_toboolean(L, 2); + + switch (checkoption(L, 1, "TLS", opts)) { +#ifndef OPENSSL_NO_SSL2 + case 0: /* SSLv2 */ + method = (srv)? &SSLv2_server_method : &SSLv2_client_method; + break; +#endif + case 1: /* SSLv3 */ + method = (srv)? &SSLv3_server_method : &SSLv3_client_method; + break; + case 2: /* SSLv23 */ + /* FALL THROUGH */ + case 3: /* SSL */ + method = (srv)? &SSLv23_server_method : &SSLv23_client_method; + break; + case 4: /* TLSv1 */ + /* FALL THROUGH */ + case 5: /* TLS */ + method = (srv)? &TLSv1_server_method : &TLSv1_client_method; + break; + } + + ud = prepsimple(L, SSL_CTX_CLASS); + + if (!(*ud = SSL_CTX_new(method()))) + return throwssl(L, "ssl.context.new"); + + return 1; +} /* sx_new() */ + + +static int sx_interpose(lua_State *L) { + return interpose(L, SSL_CTX_CLASS); +} /* sx_interpose() */ + + +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); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setStore() */ + + +static int sx_setVerify(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + int mode = luaL_optint(L, 2, -1); + int depth = luaL_optint(L, 3, -1); + + if (mode != -1) + SSL_CTX_set_verify(ctx, mode, 0); + + if (depth != -1) + SSL_CTX_set_verify_depth(ctx, depth); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setVerify() */ + + +static int sx_getVerify(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + + lua_pushinteger(L, SSL_CTX_get_verify_mode(ctx)); + lua_pushinteger(L, SSL_CTX_get_verify_depth(ctx)); + + return 2; +} /* sx_getVerify() */ + + +static int sx_setCertificate(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + X509 *crt = X509_dup(checksimple(L, 2, X509_CERT_CLASS)); + int ok; + + ok = SSL_CTX_use_certificate(ctx, crt); + X509_free(crt); + + if (!ok) + return throwssl(L, "ssl.context:setCertificate"); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setCertificate() */ + + +static int sx_setPrivateKey(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + EVP_PKEY *key = checksimple(L, 2, PUBKEY_CLASS); + + /* + * NOTE: No easy way to dup the key, but a shared reference should + * be okay as keys are less mutable than certificates. + */ + if (!SSL_CTX_use_PrivateKey(ctx, key)) + return throwssl(L, "ssl.context:setPrivateKey"); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setPrivateKey() */ + + +static int sx_setCipherList(lua_State *L) { + SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); + const char *ciphers = luaL_checkstring(L, 2); + + if (!SSL_CTX_set_cipher_list(ctx, ciphers)) + return throwssl(L, "ssl.context:setCipherList"); + + lua_pushboolean(L, 1); + + return 1; +} /* sx_setCipherList() */ + + +static int sx__gc(lua_State *L) { + SSL_CTX **ud = luaL_checkudata(L, 1, SSL_CTX_CLASS); + + SSL_CTX_free(*ud); + *ud = NULL; + + return 0; +} /* sx__gc() */ + + +static const luaL_Reg sx_methods[] = { + { "setStore", &sx_setStore }, + { "setVerify", &sx_setVerify }, + { "getVerify", &sx_getVerify }, + { "setCertificate", &sx_setCertificate }, + { "setPrivateKey", &sx_setPrivateKey }, + { "setCipherList", &sx_setCipherList }, + { NULL, NULL }, +}; + +static const luaL_Reg sx_metatable[] = { + { "__gc", &sx__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg sx_globals[] = { + { "new", &sx_new }, + { "interpose", &sx_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_ssl_context(lua_State *L) { + initall(L); + + luaL_newlib(L, sx_globals); + + lua_pushinteger(L, SSL_VERIFY_NONE); + lua_setfield(L, -2, "VERIFY_NONE"); + + lua_pushinteger(L, SSL_VERIFY_PEER); + lua_setfield(L, -2, "VERIFY_PEER"); + + lua_pushinteger(L, SSL_VERIFY_FAIL_IF_NO_PEER_CERT); + lua_setfield(L, -2, "VERIFY_FAIL_IF_NO_PEER_CERT"); + + lua_pushinteger(L, SSL_VERIFY_CLIENT_ONCE); + lua_setfield(L, -2, "VERIFY_CLIENT_ONCE"); + + return 1; +} /* luaopen__openssl_ssl_context() */ + + +/* + * SSL - openssl.ssl + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int ssl_new(lua_State *L) { + lua_pushnil(L); + + return 1; +} /* ssl_new() */ + + +static int ssl_interpose(lua_State *L) { + return interpose(L, SSL_CLASS); +} /* ssl_interpose() */ + + +static int ssl_getPeerCertificate(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + X509 **x509 = prepsimple(L, X509_CERT_CLASS); + + if (!(*x509 = SSL_get_peer_certificate(ssl))) + return 0; + + return 1; +} /* ssl_getPeerCertificate() */ + + +static int ssl_getPeerChain(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + STACK_OF(X509) *chain; + + if (!(chain = SSL_get_peer_cert_chain(ssl))) + return 0; + + xl_dup(L, chain, 0); + + return 1; +} /* ssl_getPeerChain() */ + + +static int ssl_getCipherInfo(lua_State *L) { + SSL *ssl = checksimple(L, 1, SSL_CLASS); + const SSL_CIPHER *cipher; + char descr[256]; + + if (!(cipher = SSL_get_current_cipher(ssl))) + return 0; + + lua_newtable(L); + + lua_pushstring(L, SSL_CIPHER_get_name(cipher)); + lua_setfield(L, -2, "name"); + + lua_pushinteger(L, SSL_CIPHER_get_bits(cipher, 0)); + lua_setfield(L, -2, "bits"); + + lua_pushstring(L, SSL_CIPHER_get_version(cipher)); + lua_setfield(L, -2, "version"); + + lua_pushstring(L, SSL_CIPHER_description(cipher, descr, sizeof descr)); + lua_setfield(L, -2, "description"); + + return 1; +} /* ssl_getCipherInfo() */ + + +static int ssl__gc(lua_State *L) { + SSL **ud = luaL_checkudata(L, 1, SSL_CLASS); + + SSL_free(*ud); + *ud = NULL; + + return 0; +} /* ssl__gc() */ + + +static const luaL_Reg ssl_methods[] = { + { "getPeerCertificate", &ssl_getPeerCertificate }, + { "getPeerChain", &ssl_getPeerChain }, + { "getCipherInfo", &ssl_getCipherInfo }, + { NULL, NULL }, +}; + +static const luaL_Reg ssl_metatable[] = { + { "__gc", &ssl__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg ssl_globals[] = { + { "new", &ssl_new }, + { "interpose", &ssl_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_ssl(lua_State *L) { + initall(L); + + luaL_newlib(L, ssl_globals); + + return 1; +} /* luaopen__openssl_ssl() */ + + +/* + * Digest - openssl.digest + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static const EVP_MD *md_optdigest(lua_State *L, int index) { + const char *name = luaL_optstring(L, index, "sha1"); + const EVP_MD *type; + + if (!(type = EVP_get_digestbyname(name))) + luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid digest type", name)); + + return type; +} /* md_optdigest() */ + + +static int md_new(lua_State *L) { + const EVP_MD *type = md_optdigest(L, 1); + EVP_MD_CTX *ctx; + + ctx = prepudata(L, sizeof *ctx, DIGEST_CLASS, NULL); + + EVP_MD_CTX_init(ctx); + + if (!EVP_DigestInit_ex(ctx, type, NULL)) + return throwssl(L, "digest.new"); + + return 1; +} /* md_new() */ + + +static int md_interpose(lua_State *L) { + return interpose(L, DIGEST_CLASS); +} /* md_interpose() */ + + +static void md_update_(lua_State *L, EVP_MD_CTX *ctx, int from, int to) { + int i; + + for (i = from; i <= to; i++) { + const void *p; + size_t n; + + p = luaL_checklstring(L, i, &n); + + if (!EVP_DigestUpdate(ctx, p, n)) + throwssl(L, "digest:update"); + } +} /* md_update_() */ + + +static int md_update(lua_State *L) { + EVP_MD_CTX *ctx = luaL_checkudata(L, 1, DIGEST_CLASS); + int i, top = lua_gettop(L); + + md_update_(L, ctx, 2, lua_gettop(L)); + + lua_pushboolean(L, 1); + + return 1; +} /* md_update() */ + + +static int md_final(lua_State *L) { + EVP_MD_CTX *ctx = luaL_checkudata(L, 1, DIGEST_CLASS); + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned len; + + md_update_(L, ctx, 2, lua_gettop(L)); + + if (!EVP_DigestFinal_ex(ctx, md, &len)) + return throwssl(L, "digest:final"); + + lua_pushlstring(L, (char *)md, len); + + return 1; +} /* md_final() */ + + +static int md__gc(lua_State *L) { + EVP_MD_CTX *ctx = luaL_checkudata(L, 1, DIGEST_CLASS); + + EVP_MD_CTX_cleanup(ctx); + + return 0; +} /* md__gc() */ + + +static const luaL_Reg md_methods[] = { + { "update", &md_update }, + { "final", &md_final }, + { NULL, NULL }, +}; + +static const luaL_Reg md_metatable[] = { + { "__gc", &md__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg md_globals[] = { + { "new", &md_new }, + { "interpose", &md_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_digest(lua_State *L) { + initall(L); + + luaL_newlib(L, md_globals); + + return 1; +} /* luaopen__openssl_digest() */ + + +/* + * HMAC - openssl.hmac + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int hmac_new(lua_State *L) { + const void *key; + size_t len; + const EVP_MD *type; + HMAC_CTX *ctx; + + key = luaL_checklstring(L, 1, &len); + type = md_optdigest(L, 2); + + ctx = prepudata(L, sizeof *ctx, HMAC_CLASS, NULL); + + HMAC_Init_ex(ctx, key, len, type, NULL); + + return 1; +} /* hmac_new() */ + + +static int hmac_interpose(lua_State *L) { + return interpose(L, HMAC_CLASS); +} /* hmac_interpose() */ + + +static void hmac_update_(lua_State *L, HMAC_CTX *ctx, int from, int to) { + int i; + + for (i = from; i <= to; i++) { + const void *p; + size_t n; + + p = luaL_checklstring(L, i, &n); + + HMAC_Update(ctx, p, n); + } +} /* hmac_update_() */ + + +static int hmac_update(lua_State *L) { + HMAC_CTX *ctx = luaL_checkudata(L, 1, HMAC_CLASS); + + hmac_update_(L, ctx, 2, lua_gettop(L)); + + lua_pushboolean(L, 1); + + return 1; +} /* hmac_update() */ + + +static int hmac_final(lua_State *L) { + HMAC_CTX *ctx = luaL_checkudata(L, 1, HMAC_CLASS); + unsigned char hmac[EVP_MAX_MD_SIZE]; + unsigned len; + + hmac_update_(L, ctx, 2, lua_gettop(L)); + + HMAC_Final(ctx, hmac, &len); + + lua_pushlstring(L, (char *)hmac, len); + + return 1; +} /* hmac_final() */ + + +static int hmac__gc(lua_State *L) { + HMAC_CTX *ctx = luaL_checkudata(L, 1, HMAC_CLASS); + + HMAC_CTX_cleanup(ctx); + + return 0; +} /* hmac__gc() */ + + +static const luaL_Reg hmac_methods[] = { + { "update", &hmac_update }, + { "final", &hmac_final }, + { NULL, NULL }, +}; + +static const luaL_Reg hmac_metatable[] = { + { "__gc", &hmac__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg hmac_globals[] = { + { "new", &hmac_new }, + { "interpose", &hmac_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_hmac(lua_State *L) { + initall(L); + + luaL_newlib(L, hmac_globals); + + return 1; +} /* luaopen__openssl_hmac() */ + + +/* + * Cipher - openssl.cipher + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static const EVP_CIPHER *cipher_checktype(lua_State *L, int index) { + const char *name = luaL_checkstring(L, index); + const EVP_CIPHER *type; + + if (!(type = EVP_get_cipherbyname(name))) + luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid cipher type", name)); + + return type; +} /* cipher_checktype() */ + + +static int cipher_new(lua_State *L) { + const EVP_CIPHER *type; + EVP_CIPHER_CTX *ctx; + + type = cipher_checktype(L, 1); + + ctx = prepudata(L, sizeof *ctx, CIPHER_CLASS, NULL); + EVP_CIPHER_CTX_init(ctx); + + if (!EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, -1)) + return throwssl(L, "cipher.new"); + + return 1; +} /* cipher_new() */ + + +static int cipher_interpose(lua_State *L) { + return interpose(L, HMAC_CLASS); +} /* cipher_interpose() */ + + +static int cipher_init(lua_State *L, _Bool encrypt) { + EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); + const void *key, *iv; + size_t n, m; + + key = luaL_checklstring(L, 2, &n); + m = (size_t)EVP_CIPHER_CTX_key_length(ctx); + luaL_argcheck(L, n == m, 2, lua_pushfstring(L, "%d: invalid key length (should be %d)", (int)n, (int)m)); + + iv = luaL_optlstring(L, 3, NULL, &n); + m = (size_t)EVP_CIPHER_CTX_iv_length(ctx); + luaL_argcheck(L, n == m, 3, lua_pushfstring(L, "%d: invalid IV length (should be %d)", (int)n, (int)m)); + + if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, encrypt)) + goto sslerr; + + if (!lua_isnoneornil(L, 4)) { + luaL_checktype(L, 4, LUA_TBOOLEAN); + + if (!EVP_CIPHER_CTX_set_padding(ctx, lua_toboolean(L, 4))) + goto sslerr; + } + + lua_settop(L, 1); + + return 1; +sslerr: + return throwssl(L, (encrypt)? "cipher:encrypt" : "cipher:decrypt"); +} /* cipher_init() */ + + +static int cipher_encrypt(lua_State *L) { + return cipher_init(L, 1); +} /* cipher_encrypt() */ + + +static int cipher_decrypt(lua_State *L) { + return cipher_init(L, 0); +} /* cipher_decrypt() */ + + +static _Bool cipher_update_(lua_State *L, EVP_CIPHER_CTX *ctx, luaL_Buffer *B, int from, int to) { + const unsigned char *p, *pe; + size_t block, step, n; + int i; + + block = EVP_CIPHER_CTX_block_size(ctx); + + if (LUAL_BUFFERSIZE < block * 2) + luaL_error(L, "cipher:update: LUAL_BUFFERSIZE(%d) < 2 * EVP_CIPHER_CTX_block_size(%d)", (int)LUAL_BUFFERSIZE, (int)block); + + step = LUAL_BUFFERSIZE - block; + + for (i = from; i <= to; i++) { + p = (const unsigned char *)luaL_checklstring(L, i, &n); + pe = p + n; + + while (p < pe) { + int in = (int)MIN((size_t)(pe - p), step), out; + + if (!EVP_CipherUpdate(ctx, (void *)luaL_prepbuffer(B), &out, p, in)) + return 0; + + p += in; + luaL_addsize(B, out); + } + } + + return 1; +} /* cipher_update_() */ + + +static int cipher_update(lua_State *L) { + EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); + luaL_Buffer B; + + luaL_buffinit(L, &B); + + if (!cipher_update_(L, ctx, &B, 2, lua_gettop(L))) + goto sslerr; + + luaL_pushresult(&B); + + return 1; +sslerr: + lua_pushnil(L); + pusherror(L, NULL); + + return 2; +} /* cipher_update() */ + + +static int cipher_final(lua_State *L) { + EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); + luaL_Buffer B; + size_t block; + int out; + + luaL_buffinit(L, &B); + + if (!cipher_update_(L, ctx, &B, 2, lua_gettop(L))) + goto sslerr; + + block = EVP_CIPHER_CTX_block_size(ctx); + + if (LUAL_BUFFERSIZE < block) + return luaL_error(L, "cipher:update: LUAL_BUFFERSIZE(%d) < EVP_CIPHER_CTX_block_size(%d)", (int)LUAL_BUFFERSIZE, (int)block); + + if (!EVP_CipherFinal(ctx, (void *)luaL_prepbuffer(&B), &out)) + goto sslerr; + + luaL_addsize(&B, out); + luaL_pushresult(&B); + + return 1; +sslerr: + lua_pushnil(L); + pusherror(L, NULL); + + return 2; +} /* cipher_final() */ + + +static int cipher__gc(lua_State *L) { + EVP_CIPHER_CTX *ctx = luaL_checkudata(L, 1, CIPHER_CLASS); + + EVP_CIPHER_CTX_cleanup(ctx); + + return 0; +} /* cipher__gc() */ + + +static const luaL_Reg cipher_methods[] = { + { "encrypt", &cipher_encrypt }, + { "decrypt", &cipher_decrypt }, + { "update", &cipher_update }, + { "final", &cipher_final }, + { NULL, NULL }, +}; + +static const luaL_Reg cipher_metatable[] = { + { "__gc", &cipher__gc }, + { NULL, NULL }, +}; + +static const luaL_Reg cipher_globals[] = { + { "new", &cipher_new }, + { "interpose", &cipher_interpose }, + { NULL, NULL }, +}; + +int luaopen__openssl_cipher(lua_State *L) { + initall(L); + + luaL_newlib(L, cipher_globals); + + return 1; +} /* luaopen__openssl_cipher() */ + + +/* + * Rand - openssl.rand + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static int rand_bytes(lua_State *L) { + int size = luaL_checkint(L, 1); + luaL_Buffer B; + int count = 0, n; + + luaL_buffinit(L, &B); + + while (count < size) { + n = MIN((size - count), LUAL_BUFFERSIZE); + + if (!RAND_bytes((void *)luaL_prepbuffer(&B), n)) + return throwssl(L, "rand.bytes"); + + luaL_addsize(&B, n); + count += n; + } + + luaL_pushresult(&B); + + return 1; +} /* rand_bytes() */ + + +static int rand_ready(lua_State *L) { + lua_pushboolean(L, RAND_status() == 1); + + return 1; +} /* rand_ready() */ + + +static unsigned long long rand_llu(lua_State *L) { + unsigned long long llu; + + if (!RAND_bytes((void *)&llu, sizeof llu)) + throwssl(L, "rand.uniform"); + + return llu; +} /* rand_llu() */ + +/* + * The following algorithm for rand_uniform() is taken from OpenBSD's + * arc4random_uniform, written by Otto Moerbeek, with subsequent + * simplification by Jorden Verwer. Otto's source code comment reads + * + * Uniformity is achieved by generating new random numbers until the one + * returned is outside the range [0, 2**32 % upper_bound). This guarantees + * the selected random number will be inside [2**32 % upper_bound, 2**32) + * which maps back to [0, upper_bound) after reduction modulo upper_bound. + * + * -- + * A more bit-efficient approach by the eminent statistician Herman Rubin + * can be found in this sci.crypt Usenet post. + * + * From: hrubin@odds.stat.purdue.edu (Herman Rubin) + * Newsgroups: sci.crypt + * Subject: Re: Generating a random number between 0 and N-1 + * Date: 14 Nov 2002 11:20:37 -0500 + * Organization: Purdue University Statistics Department + * Lines: 40 + * Message-ID: + * References: <3DCD8D75.40408@nospam.com> + * NNTP-Posting-Host: odds.stat.purdue.edu + * X-Trace: mozo.cc.purdue.edu 1037290837 9316 128.210.141.13 (14 Nov 2002 16:20:37 GMT) + * X-Complaints-To: ne...@news.purdue.edu + * NNTP-Posting-Date: Thu, 14 Nov 2002 16:20:37 +0000 (UTC) + * Xref: archiver1.google.com sci.crypt:78935 + * + * In article <3DCD8D7...@nospam.com>, + * Michael Amling wrote: + * >Carlos Moreno wrote: + * + * I have already posted on this, but a repeat might be + * in order. + * + * If one can trust random bits, the most bitwise efficient + * manner to get a single random integer between 0 and N-1 + * can be obtained as follows; the code can be made more + * computationally efficient. I believe it is easier to + * understand with gotos. I am assuming N>1. + * + * i = 0; j = 1; + * + * loop: j=2*j; i=2*i+RANBIT; + * if (j < N) goto loop; + * if (i >= N) { + * i = i - N; + * j = j - N; + * goto loop:} + * else return (i); + * + * The algorithm works because at each stage i is uniform + * between 0 and j-1. + * + * Another possibility is to generate k bits, where 2^k >= N. + * If 2^k = c*N + remainder, generate the appropriate value + * if a k-bit random number is less than c*N. + * + * For N = 17 (numbers just larger than powers of 2 are "bad"), + * the amount of information is about 4.09 bits, the best + * algorithm to generate one random number takes about 5.765 + * bits, taking k = 5 uses 9.412 bits, taking k = 6 or 7 uses + * 7.529 bits. These are averages, but the tails are not bad. + * + * (https://groups.google.com/forum/message/raw?msg=sci.crypt/DMslf6tSrD8/rv9rk6oP3r4J) + */ +static int rand_uniform(lua_State *L) { + if (lua_isnoneornil(L, 1)) { + unsigned long long r = rand_llu(L); + + lua_pushnumber(L, r); + + return 1; + } else { + unsigned long long N = luaL_checknumber(L, 1); + unsigned long long r, m; + + luaL_argcheck(L, N > 1, 1, lua_pushfstring(L, "[0, %d): interval is empty", (int)N)); + + m = -N % N; + + do { + r = rand_llu(L); + } while (r < m); + + lua_pushnumber(L, (r % N)); + + return 1; + } +} /* rand_uniform() */ + + +static const luaL_Reg rand_globals[] = { + { "bytes", &rand_bytes }, + { "ready", &rand_ready }, + { "uniform", &rand_uniform }, + { NULL, NULL }, +}; + +int luaopen__openssl_rand(lua_State *L) { + initall(L); + + luaL_newlib(L, rand_globals); + + return 1; +} /* luaopen__openssl_rand() */ + + +static void initall(lua_State *L) { + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + + addclass(L, BIGNUM_CLASS, bn_methods, bn_metatable); + addclass(L, PUBKEY_CLASS, pk_methods, pk_metatable); + addclass(L, X509_NAME_CLASS, xn_methods, xn_metatable); + addclass(L, X509_GENS_CLASS, gn_methods, gn_metatable); + addclass(L, X509_CERT_CLASS, xc_methods, xc_metatable); + addclass(L, X509_CSR_CLASS, xr_methods, xr_metatable); + addclass(L, X509_CHAIN_CLASS, xl_methods, xl_metatable); + addclass(L, X509_STORE_CLASS, xs_methods, xs_metatable); + addclass(L, SSL_CTX_CLASS, sx_methods, sx_metatable); + addclass(L, SSL_CLASS, ssl_methods, ssl_metatable); + addclass(L, DIGEST_CLASS, md_methods, md_metatable); + addclass(L, HMAC_CLASS, hmac_methods, hmac_metatable); + addclass(L, CIPHER_CLASS, cipher_methods, cipher_metatable); +} /* initall() */ + + +#endif /* L_OPENSSL_H */ diff --git a/src/openssl.cipher.lua b/src/openssl.cipher.lua new file mode 100644 index 0000000..876cd1b --- /dev/null +++ b/src/openssl.cipher.lua @@ -0,0 +1,3 @@ +local ctx = require"_openssl.cipher" + +return ctx diff --git a/src/openssl.digest.lua b/src/openssl.digest.lua new file mode 100644 index 0000000..87cc958 --- /dev/null +++ b/src/openssl.digest.lua @@ -0,0 +1,3 @@ +local ctx = require"_openssl.digest" + +return ctx diff --git a/src/openssl.hmac.lua b/src/openssl.hmac.lua new file mode 100644 index 0000000..e622d1d --- /dev/null +++ b/src/openssl.hmac.lua @@ -0,0 +1,3 @@ +local ctx = require"_openssl.hmac" + +return ctx diff --git a/src/openssl.pubkey.lua b/src/openssl.pubkey.lua new file mode 100644 index 0000000..6dc5614 --- /dev/null +++ b/src/openssl.pubkey.lua @@ -0,0 +1,4 @@ +local pubkey = require"_openssl.pubkey" + +return pubkey + diff --git a/src/openssl.rand.lua b/src/openssl.rand.lua new file mode 100644 index 0000000..70e9d3f --- /dev/null +++ b/src/openssl.rand.lua @@ -0,0 +1,3 @@ +local ctx = require"_openssl.rand" + +return ctx diff --git a/src/openssl.ssl.context.lua b/src/openssl.ssl.context.lua new file mode 100644 index 0000000..44a9163 --- /dev/null +++ b/src/openssl.ssl.context.lua @@ -0,0 +1,3 @@ +local ctx = require"_openssl.ssl.context" + +return ctx diff --git a/src/openssl.ssl.lua b/src/openssl.ssl.lua new file mode 100644 index 0000000..3c348f6 --- /dev/null +++ b/src/openssl.ssl.lua @@ -0,0 +1,3 @@ +local ctx = require"_openssl.ssl" + +return ctx diff --git a/src/openssl.x509.altname.lua b/src/openssl.x509.altname.lua new file mode 100644 index 0000000..66f16e7 --- /dev/null +++ b/src/openssl.x509.altname.lua @@ -0,0 +1,13 @@ +local altname = require"_openssl.x509.altname" + +altname.interpose("__tostring", function (self) + local t = { } + + for k, v in pairs(self) do + t[#t + 1] = k .. ":" .. v + end + + return table.concat(t, ", ") +end) + +return altname diff --git a/src/openssl.x509.chain.lua b/src/openssl.x509.chain.lua new file mode 100644 index 0000000..e89dec8 --- /dev/null +++ b/src/openssl.x509.chain.lua @@ -0,0 +1,3 @@ +local chain = require"_openssl.x509.chain" + +return chain diff --git a/src/openssl.x509.lua b/src/openssl.x509.lua new file mode 100644 index 0000000..278baf5 --- /dev/null +++ b/src/openssl.x509.lua @@ -0,0 +1,3 @@ +local x509 = require"_openssl.x509.cert" + +return x509 diff --git a/src/openssl.x509.name.lua b/src/openssl.x509.name.lua new file mode 100644 index 0000000..a531502 --- /dev/null +++ b/src/openssl.x509.name.lua @@ -0,0 +1,13 @@ +local name = require"_openssl.x509.name" + +name.interpose("__tostring", function (self) + local t = { } + + for k, v in pairs(self) do + t[#t + 1] = k .. "=" .. v + end + + return table.concat(t, ", ") +end) + +return name diff --git a/src/openssl.x509.store.lua b/src/openssl.x509.store.lua new file mode 100644 index 0000000..a717870 --- /dev/null +++ b/src/openssl.x509.store.lua @@ -0,0 +1,3 @@ +local store = require"_openssl.x509.store" + +return store -- cgit v1.2.3-59-g8ed1b