diff --git a/package/luvi/0003-Bump-bundled-lua-openssl-to-version-0.7.4.patch b/package/luvi/0003-Bump-bundled-lua-openssl-to-version-0.7.4.patch
new file mode 100644
index 0000000000..339b3f759a
--- /dev/null
+++ b/package/luvi/0003-Bump-bundled-lua-openssl-to-version-0.7.4.patch
@@ -0,0 +1,31718 @@
+Bump bundled lua-openssl to version 0.7.4 for compatibility with OpenSSL 1.1.x.
+
+Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
+
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/appveyor.yml luvi-src-v2.7.6/deps/lua-openssl/appveyor.yml
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/appveyor.yml	2019-02-13 11:31:40.277302045 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/appveyor.yml	2019-02-13 11:53:24.105128513 +0100
+@@ -9,7 +9,7 @@ install:
+ - git submodule update --recursive
+ - '"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86'
+ - cd C:\
+-- ps: Start-FileDownload 'https://github.com/zhaozg/openssl-win32/blob/1.0.2/misc/luv.dll?raw=true' 'C:\luv.dll'
++#- ps: Start-FileDownload 'https://github.com/zhaozg/openssl-win32/blob/1.0.2/misc/luv.dll?raw=true' -FileName 'C:\luv.dll'
+ #- git clone https://github.com/zhaozg/openssl-win32.git C:\openssl-win32
+ - git clone http://luajit.org/git/luajit-2.0.git C:\luajit-2.0
+ build_script:
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/auxiliar.c luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/auxiliar.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/auxiliar.c	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/auxiliar.c	2019-02-13 11:53:29.051738872 +0100
+@@ -7,6 +7,10 @@
+ 
+ #include "auxiliar.h"
+ 
++#if LUA_VERSION_NUM<503
++#include "c-api/compat-5.3.h"
++#endif
++
+ /*=========================================================================*\
+ * Exported functions
+ \*=========================================================================*/
+@@ -143,7 +147,7 @@ void *auxiliar_getgroupudata(lua_State *
+ * otherwise
+ \*-------------------------------------------------------------------------*/
+ void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
+-    return luaL_checkudata(L, objidx, classname);
++    return luaL_testudata(L, objidx, classname);
+ }
+ 
+ /*-------------------------------------------------------------------------*\
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/readme.md luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/readme.md
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/readme.md	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/readme.md	2019-02-13 11:53:29.051738872 +0100
+@@ -0,0 +1,65 @@
++# lua-auxiliar
++
++## Introduce
++
++The origin auxiliar is part of [luasocket](https://github.com/diegonehab/luasocket), it's a general purpose class implemention lib for userdata with metatable.
++
++```
++/*=========================================================================*\
++* Auxiliar routines for class hierarchy manipulation
++* LuaSocket toolkit (but completely independent of other LuaSocket modules)
++*
++* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
++* group is a name associated with a class. A class can belong to any number
++* of groups. This module provides the functionality to:
++*
++*   - create new classes
++*   - add classes to groups
++*   - set the class of objects
++*   - check if an object belongs to a given class or group
++*   - get the userdata associated to objects
++*   - print objects in a pretty way
++*
++* LuaSocket class names follow the convention <module>{<class>}. Modules
++* can define any number of classes and groups. The module tcp.c, for
++* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
++* the groups tcp{client,server} and tcp{any}. Module functions can then
++* perform type-checking on their arguments by either class or group.
++*
++* LuaSocket metatables define the __index metamethod as being a table. This
++* table has one field for each method supported by the class, and a field
++* "class" with the class name.
++*
++* The mapping from class name to the corresponding metatable and the
++* reverse mapping are done using lauxlib.
++\*=========================================================================*/
++```
++
++## Update
++
++I do minimual change, and add a few APIs for [lui](https://github.com/zhaozg/lui) and [lua-openssl](https://github.com/zhaozg/lua-openssl).
++TODO more
++
++## License
++```text
++LuaSocket 3.0 license
++Copyright © 2004-2018 Diego Nehab
++
++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.
++```
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/subsidiar.c luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/subsidiar.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/subsidiar.c	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/subsidiar.c	2019-02-13 11:53:29.051738872 +0100
+@@ -0,0 +1,22 @@
++#include "auxiliar.h"
++#include "subsidiar.h"
++
++int auxiliar_enumerate(lua_State *L, int tidx, const LuaL_Enumeration *lenums)
++{
++  int n = tidx < 0 ? tidx-2 : tidx;
++  const LuaL_Enumeration *e = lenums;
++  while( e->name!=NULL ) 
++  {
++    lua_pushstring(L, e->name);
++    lua_pushinteger(L, e->val);
++    lua_rawset(L, n);
++    e++;
++  }
++  return 1;
++}
++
++int auxiliar_checkoption(lua_State*L, int objidx, const char* def, const char* const slist[], const int ival[])
++{
++  int at = luaL_checkoption(L, objidx, def, slist);
++  return ival[at];
++}
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/subsidiar.h luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/subsidiar.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/auxiliar/subsidiar.h	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/auxiliar/subsidiar.h	2019-02-13 11:53:29.051738872 +0100
+@@ -0,0 +1,51 @@
++#ifndef SUBSIDIAR_H
++#define SUBSIDIAR_H
++
++#include "lua.h"
++#include "lauxlib.h"
++
++/* subsidiary part for auxiliar libirary */
++
++#define AUXILIAR_SET(L, tidx, lvar, cval, ltype)    \
++  do {                                              \
++  int n = tidx < 0 ? tidx-1 : tidx;                 \
++  lua_push##ltype(L, (cval));                       \
++  lua_setfield(L, n, lvar);                         \
++  } while(0)
++
++#define AUXLIAR_GET(L, tidx, lvar, cvar, ltype)     \
++  do {                                              \
++  lua_getfield(L, tidx, lvar);                      \
++  cvar = lua_to##ltype(L, -1);                      \
++  lua_pop(L, 1);                                    \
++  } while(0)
++
++#define AUXILIAR_SETLSTR(L, tidx, lvar, cval, len)  \
++  do {                                              \
++  int n = tidx < 0 ? tidx-1 : tidx;                 \
++  lua_pushlstring(L, (const char*)(cval),len);      \
++  lua_setfield(L, n, lvar);                         \
++  } while(0)
++
++#define AUXILIAR_GETLSTR(L, tidx, lvar, cvar, len)  \
++  do {                                              \
++  lua_getfield(L, tidx, lvar);                      \
++  cvar = lua_tolstring(L, -1, &len);                \
++  lua_setfield(L, n, lvar);                         \
++  } while(0)
++
++typedef struct
++{
++  const char* name;
++  int val;
++} LuaL_Enumeration;
++
++int auxiliar_enumerate(lua_State *L, int tidx, const LuaL_Enumeration *lenum);
++int auxiliar_checkoption(lua_State*L, 
++                         int objidx,
++                         const char *def, 
++                         const char *const slist[],
++                         const int ival[]);
++
++#endif
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.c luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.c	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.c	2019-02-13 11:53:29.078405237 +0100
+@@ -3,6 +3,7 @@
+ #include <string.h>
+ #include <ctype.h>
+ #include <errno.h>
++#include <stdio.h>
+ #include "compat-5.3.h"
+ 
+ /* don't compile it again if it already is included via compat53.h */
+@@ -14,6 +15,75 @@
+ /* definitions for Lua 5.1 only */
+ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
+ 
++#ifndef COMPAT53_FOPEN_NO_LOCK
++#  if defined(_MSC_VER)
++#    define COMPAT53_FOPEN_NO_LOCK 1
++#  else /* otherwise */
++#    define COMPAT53_FOPEN_NO_LOCK 0
++#  endif /* VC++ only so far */
++#endif /* No-lock fopen_s usage if possible */
++
++#if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK
++#  include <share.h>
++#endif /* VC++ _fsopen for share-allowed file read */
++
++#ifndef COMPAT53_HAVE_STRERROR_R
++#  if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || \
++      (!defined (__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6))
++#    define COMPAT53_HAVE_STRERROR_R 1
++#  else /* none of the defines matched: define to 0 */
++#    define COMPAT53_HAVE_STRERROR_R 0
++#  endif /* have strerror_r of some form */
++#endif /* strerror_r */
++
++#ifndef COMPAT53_HAVE_STRERROR_S
++#  if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \
++      defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__)
++#    define COMPAT53_HAVE_STRERROR_S 1
++#  else /* not VC++ or C11 */
++#    define COMPAT53_HAVE_STRERROR_S 0
++#  endif /* strerror_s from VC++ or C11 */
++#endif /* strerror_s */
++
++#ifndef COMPAT53_LUA_FILE_BUFFER_SIZE
++#  define COMPAT53_LUA_FILE_BUFFER_SIZE 4096
++#endif /* Lua File Buffer Size */
++
++
++static char* compat53_strerror (int en, char* buff, size_t sz) {
++#if COMPAT53_HAVE_STRERROR_R
++  /* use strerror_r here, because it's available on these specific platforms */
++  if (sz > 0) {
++    buff[0] = '\0';
++    /* we don't care whether the GNU version or the XSI version is used: */
++    if (strerror_r(en, buff, sz)) {
++      /* Yes, we really DO want to ignore the return value!
++       * GCC makes that extra hard, not even a (void) cast will do. */
++    }
++    if (buff[0] == '\0') {
++      /* Buffer is unchanged, so we probably have called GNU strerror_r which
++       * returned a static constant string. Chances are that strerror will
++       * return the same static constant string and therefore be thread-safe. */
++      return strerror(en);
++    }
++  }
++  return buff; /* sz is 0 *or* strerror_r wrote into the buffer */
++#elif COMPAT53_HAVE_STRERROR_S
++  /* for MSVC and other C11 implementations, use strerror_s since it's
++   * provided by default by the libraries */
++  strerror_s(buff, sz, en);
++  return buff;
++#else
++  /* fallback, but strerror is not guaranteed to be threadsafe due to modifying
++   * errno itself and some impls not locking a static buffer for it ... but most
++   * known systems have threadsafe errno: this might only change if the locale
++   * is changed out from under someone while this function is being called */
++  (void)buff;
++  (void)sz;
++  return strerror(en);
++#endif
++}
++
+ 
+ COMPAT53_API int lua_absindex (lua_State *L, int i) {
+   if (i < 0 && i > LUA_REGISTRYINDEX)
+@@ -100,15 +170,17 @@ COMPAT53_API void lua_copy (lua_State *L
+ 
+ COMPAT53_API void lua_len (lua_State *L, int i) {
+   switch (lua_type(L, i)) {
+-    case LUA_TSTRING: /* fall through */
++    case LUA_TSTRING:
++      lua_pushnumber(L, (lua_Number)lua_objlen(L, i));
++      break;
+     case LUA_TTABLE:
+       if (!luaL_callmeta(L, i, "__len"))
+-        lua_pushnumber(L, (int)lua_objlen(L, i));
++        lua_pushnumber(L, (lua_Number)lua_objlen(L, i));
+       break;
+     case LUA_TUSERDATA:
+       if (luaL_callmeta(L, i, "__len"))
+         break;
+-      /* maybe fall through */
++      /* FALLTHROUGH */
+     default:
+       luaL_error(L, "attempt to get length of a %s value",
+                  lua_typename(L, lua_type(L, i)));
+@@ -132,15 +204,6 @@ COMPAT53_API void lua_rawsetp (lua_State
+ }
+ 
+ 
+-COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) {
+-  lua_Integer n = lua_tointeger(L, i);
+-  if (isnum != NULL) {
+-    *isnum = (n != 0 || lua_isnumber(L, i));
+-}
+-  return n;
+-}
+-
+-
+ COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) {
+   lua_Number n = lua_tonumber(L, i);
+   if (isnum != NULL) {
+@@ -183,14 +246,15 @@ COMPAT53_API int luaL_getsubtable (lua_S
+ }
+ 
+ 
+-COMPAT53_API int luaL_len (lua_State *L, int i) {
+-  int res = 0, isnum = 0;
++COMPAT53_API lua_Integer luaL_len (lua_State *L, int i) {
++  lua_Integer res = 0;
++  int isnum = 0;
+   luaL_checkstack(L, 1, "not enough stack slots");
+   lua_len(L, i);
+-  res = (int)lua_tointegerx(L, -1, &isnum);
++  res = lua_tointegerx(L, -1, &isnum);
+   lua_pop(L, 1);
+   if (!isnum)
+-    luaL_error(L, "object length is not a number");
++    luaL_error(L, "object length is not an integer");
+   return res;
+ }
+ 
+@@ -233,34 +297,6 @@ COMPAT53_API void *luaL_testudata (lua_S
+ }
+ 
+ 
+-COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
+-  if (!luaL_callmeta(L, idx, "__tostring")) {
+-    int t = lua_type(L, idx);
+-    switch (t) {
+-      case LUA_TNIL:
+-        lua_pushliteral(L, "nil");
+-        break;
+-      case LUA_TSTRING:
+-      case LUA_TNUMBER:
+-        lua_pushvalue(L, idx);
+-        break;
+-      case LUA_TBOOLEAN:
+-        if (lua_toboolean(L, idx))
+-          lua_pushliteral(L, "true");
+-        else
+-          lua_pushliteral(L, "false");
+-        break;
+-      default:
+-        lua_pushfstring(L, "%s: %p", lua_typename(L, t),
+-                                     lua_topointer(L, idx));
+-        break;
+-    }
+-  }
+-  return lua_tolstring(L, -1, len);
+-}
+-
+-
+-#if !defined(COMPAT53_IS_LUAJIT)
+ static int compat53_countlevels (lua_State *L) {
+   lua_Debug ar;
+   int li = 1, le = 1;
+@@ -361,26 +397,221 @@ COMPAT53_API void luaL_traceback (lua_St
+ 
+ 
+ COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
++  const char *serr = NULL;
+   int en = errno;  /* calls to Lua API may change this value */
++  char buf[512] = { 0 };
+   if (stat) {
+     lua_pushboolean(L, 1);
+     return 1;
+   }
+   else {
+     lua_pushnil(L);
++    serr = compat53_strerror(en, buf, sizeof(buf));
+     if (fname)
+-      lua_pushfstring(L, "%s: %s", fname, strerror(en));
++      lua_pushfstring(L, "%s: %s", fname, serr);
+     else
+-      lua_pushstring(L, strerror(en));
++      lua_pushstring(L, serr);
+     lua_pushnumber(L, (lua_Number)en);
+     return 3;
+   }
+ }
+ 
+ 
++static int compat53_checkmode (lua_State *L, const char *mode, const char *modename, int err) {
++  if (mode && strchr(mode, modename[0]) == NULL) {
++    lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode);
++    return err;
++  }
++  return LUA_OK;
++}
++
++
++typedef struct {
++  lua_Reader reader;
++  void *ud;
++  int has_peeked_data;
++  const char *peeked_data;
++  size_t peeked_data_size;
++} compat53_reader_data;
++
++
++static const char *compat53_reader (lua_State *L, void *ud, size_t *size) {
++  compat53_reader_data *data = (compat53_reader_data *)ud;
++  if (data->has_peeked_data) {
++    data->has_peeked_data = 0;
++    *size = data->peeked_data_size;
++    return data->peeked_data;
++  } else
++    return data->reader(L, data->ud, size);
++}
++
++
++COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *source, const char *mode) {
++  int status = LUA_OK;
++  compat53_reader_data compat53_data = { reader, data, 1, 0, 0 };
++  compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size));
++  if (compat53_data.peeked_data && compat53_data.peeked_data_size &&
++      compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */
++      status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX);
++  else
++      status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX);
++  if (status != LUA_OK)
++    return status;
++  /* we need to call the original 5.1 version of lua_load! */
++#undef lua_load
++  return lua_load(L, compat53_reader, &compat53_data, source);
++#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53)
++}
++
++
++typedef struct {
++  int n;  /* number of pre-read characters */
++  FILE *f;  /* file being read */
++  char buff[COMPAT53_LUA_FILE_BUFFER_SIZE];  /* area for reading file */
++} compat53_LoadF;
++
++
++static const char *compat53_getF (lua_State *L, void *ud, size_t *size) {
++  compat53_LoadF *lf = (compat53_LoadF *)ud;
++  (void)L;  /* not used */
++  if (lf->n > 0) {  /* are there pre-read characters to be read? */
++    *size = lf->n;  /* return them (chars already in buffer) */
++    lf->n = 0;  /* no more pre-read characters */
++  }
++  else {  /* read a block from file */
++    /* 'fread' can return > 0 *and* set the EOF flag. If next call to
++       'compat53_getF' called 'fread', it might still wait for user input.
++       The next check avoids this problem. */
++    if (feof(lf->f)) return NULL;
++    *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);  /* read block */
++  }
++  return lf->buff;
++}
++
++
++static int compat53_errfile (lua_State *L, const char *what, int fnameindex) {
++  char buf[512] = {0};
++  const char *serr = compat53_strerror(errno, buf, sizeof(buf));
++  const char *filename = lua_tostring(L, fnameindex) + 1;
++  lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
++  lua_remove(L, fnameindex);
++  return LUA_ERRFILE;
++}
++
++
++static int compat53_skipBOM (compat53_LoadF *lf) {
++  const char *p = "\xEF\xBB\xBF";  /* UTF-8 BOM mark */
++  int c;
++  lf->n = 0;
++  do {
++    c = getc(lf->f);
++    if (c == EOF || c != *(const unsigned char *)p++) return c;
++    lf->buff[lf->n++] = (char)c;  /* to be read by the parser */
++  } while (*p != '\0');
++  lf->n = 0;  /* prefix matched; discard it */
++  return getc(lf->f);  /* return next character */
++}
++
++
++/*
++** reads the first character of file 'f' and skips an optional BOM mark
++** in its beginning plus its first line if it starts with '#'. Returns
++** true if it skipped the first line.  In any case, '*cp' has the
++** first "valid" character of the file (after the optional BOM and
++** a first-line comment).
++*/
++static int compat53_skipcomment (compat53_LoadF *lf, int *cp) {
++  int c = *cp = compat53_skipBOM(lf);
++  if (c == '#') {  /* first line is a comment (Unix exec. file)? */
++    do {  /* skip first line */
++      c = getc(lf->f);
++    } while (c != EOF && c != '\n');
++    *cp = getc(lf->f);  /* skip end-of-line, if present */
++    return 1;  /* there was a comment */
++  }
++  else return 0;  /* no comment */
++}
++
++
++COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) {
++  compat53_LoadF lf;
++  int status, readstatus;
++  int c;
++  int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */
++  if (filename == NULL) {
++    lua_pushliteral(L, "=stdin");
++    lf.f = stdin;
++  }
++  else {
++    lua_pushfstring(L, "@%s", filename);
++#if defined(_MSC_VER)
++    /* This code is here to stop a deprecation error that stops builds
++     * if a certain macro is defined. While normally not caring would
++     * be best, some header-only libraries and builds can't afford to
++     * dictate this to the user. A quick check shows that fopen_s this
++     * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET,
++     * possibly even before that so we don't need to do any version
++     * number checks, since this has been there since forever.  */
++
++    /* TO USER: if you want the behavior of typical fopen_s/fopen,
++     * which does lock the file on VC++, define the macro used below to 0 */
++#if COMPAT53_FOPEN_NO_LOCK
++    lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */
++    if (lf.f == NULL)
++      return compat53_errfile(L, "open", fnameindex);
++#else /* use default locking version */
++    if (fopen_s(&lf.f, filename, "r") != 0)
++      return compat53_errfile(L, "open", fnameindex);
++#endif /* Locking vs. No-locking fopen variants */
++#else
++    lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */
++    if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex);
++#endif
++  }
++  if (compat53_skipcomment(&lf, &c))  /* read initial portion */
++    lf.buff[lf.n++] = '\n';  /* add line to correct line numbers */
++  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
++#if defined(_MSC_VER)
++    if (freopen_s(&lf.f, filename, "rb", lf.f) != 0)
++      return compat53_errfile(L, "reopen", fnameindex);
++#else
++    lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
++    if (lf.f == NULL) return compat53_errfile(L, "reopen", fnameindex);
++#endif
++    compat53_skipcomment(&lf, &c);  /* re-read initial portion */
++  }
++  if (c != EOF)
++    lf.buff[lf.n++] = (char)c;  /* 'c' is the first character of the stream */
++  status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode);
++  readstatus = ferror(lf.f);
++  if (filename) fclose(lf.f);  /* close file (even in case of errors) */
++  if (readstatus) {
++    lua_settop(L, fnameindex);  /* ignore results from 'lua_load' */
++    return compat53_errfile(L, "read", fnameindex);
++  }
++  lua_remove(L, fnameindex);
++  return status;
++}
++
++
++COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode) {
++  int status = LUA_OK;
++  if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) {
++    status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX);
++  }
++  else {
++    status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX);
++  }
++  if (status != LUA_OK)
++    return status;
++  return luaL_loadbuffer(L, buff, sz, name);
++}
++
++
+ #if !defined(l_inspectstat) && \
+     (defined(unix) || defined(__unix) || defined(__unix__) || \
+-     defined(__TOS_AIX__) || defined(_SYSTYPE_BSD))
++     defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \
++     (defined(__APPLE__) && defined(__MACH__)))
+ /* some form of unix; check feature macros in unistd.h for details */
+ #  include <unistd.h>
+ /* check posix version; the relevant include files and macros probably
+@@ -414,7 +645,6 @@ COMPAT53_API int luaL_execresult (lua_St
+     return 3;
+   }
+ }
+-#endif /* not COMPAT53_IS_LUAJIT */
+ 
+ 
+ COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) {
+@@ -501,6 +731,22 @@ COMPAT53_API int lua_isinteger (lua_Stat
+ }
+ 
+ 
++COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) {
++  int ok = 0;
++  lua_Number n = lua_tonumberx(L, i, &ok);
++  if (ok) {
++    if (n == (lua_Integer)n) {
++      if (isnum)
++        *isnum = 1;
++      return (lua_Integer)n;
++    }
++  }
++  if (isnum)
++    *isnum = 0;
++  return 0;
++}
++
++
+ static void compat53_reverse (lua_State *L, int a, int b) {
+   for (; a < b; ++a, --b) {
+     lua_pushvalue(L, a);
+@@ -537,7 +783,7 @@ COMPAT53_API void lua_seti (lua_State *L
+ 
+ 
+ #if !defined(lua_str2number)
+-#  define lua_str2number(s, p)  strtod(s, p)
++#  define lua_str2number(s, p)  strtod((s), (p))
+ #endif
+ 
+ COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) {
+@@ -555,6 +801,40 @@ COMPAT53_API size_t lua_stringtonumber (
+ }
+ 
+ 
++COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
++  if (!luaL_callmeta(L, idx, "__tostring")) {
++    int t = lua_type(L, idx), tt = 0;
++    char const* name = NULL;
++    switch (t) {
++      case LUA_TNIL:
++        lua_pushliteral(L, "nil");
++        break;
++      case LUA_TSTRING:
++      case LUA_TNUMBER:
++        lua_pushvalue(L, idx);
++        break;
++      case LUA_TBOOLEAN:
++        if (lua_toboolean(L, idx))
++          lua_pushliteral(L, "true");
++        else
++          lua_pushliteral(L, "false");
++        break;
++      default:
++        tt = luaL_getmetafield(L, idx, "__name");
++        name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t);
++        lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx));
++        if (tt != LUA_TNIL)
++          lua_replace(L, -2);
++        break;
++    }
++  } else {
++    if (!lua_isstring(L, -1))
++      luaL_error(L, "'__tostring' must return a string");
++  }
++  return lua_tolstring(L, -1, len);
++}
++
++
+ COMPAT53_API void luaL_requiref (lua_State *L, const char *modname,
+                                  lua_CFunction openf, int glb) {
+   luaL_checkstack(L, 3, "not enough stack slots available");
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.h luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.h	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/c-api/compat-5.3.h	2019-02-13 11:53:29.078405237 +0100
+@@ -4,16 +4,18 @@
+ #include <stddef.h>
+ #include <limits.h>
+ #include <string.h>
+-#if defined( __cplusplus ) && !defined( COMPAT53_LUA_CPP )
++#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)
+ extern "C" {
+ #endif
+ #include <lua.h>
+ #include <lauxlib.h>
+-#if defined( __cplusplus ) && !defined( COMPAT53_LUA_CPP )
++#include <lualib.h>
++#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP)
+ }
+ #endif
+ 
+ 
++#undef COMPAT53_INCLUDE_SOURCE
+ #if defined(COMPAT53_PREFIX)
+ /* - change the symbol names of functions to avoid linker conflicts
+  * - compat-5.3.c needs to be compiled (and linked) separately
+@@ -21,13 +23,11 @@ extern "C" {
+ #  if !defined(COMPAT53_API)
+ #    define COMPAT53_API extern
+ #  endif
+-#  undef COMPAT53_INCLUDE_SOURCE
+ #else /* COMPAT53_PREFIX */
+ /* - make all functions static and include the source.
+- * - don't mess with the symbol names of functions
+  * - compat-5.3.c doesn't need to be compiled (and linked) separately
+  */
+-#  define COMPAT53_PREFIX lua
++#  define COMPAT53_PREFIX compat53
+ #  undef COMPAT53_API
+ #  if defined(__GNUC__) || defined(__clang__)
+ #    define COMPAT53_API __attribute__((__unused__)) static
+@@ -51,29 +51,54 @@ extern "C" {
+  * lua_upvaluejoin
+  * lua_version
+  * lua_yieldk
+- * luaL_loadbufferx
+- * luaL_loadfilex
+  */
+ 
+-/* PUC-Rio Lua uses lconfig_h as include guard for luaconf.h,
+- * LuaJIT uses luaconf_h. If you use PUC-Rio's include files
+- * but LuaJIT's library, you will need to define the macro
+- * COMPAT53_IS_LUAJIT yourself! */
+-#if !defined(COMPAT53_IS_LUAJIT) && defined(luaconf_h)
+-#  define COMPAT53_IS_LUAJIT
+-#endif
+-
+-#define LUA_OK 0
+-#define LUA_OPADD 0
+-#define LUA_OPSUB 1
+-#define LUA_OPMUL 2
+-#define LUA_OPDIV 3
+-#define LUA_OPMOD 4
+-#define LUA_OPPOW 5
+-#define LUA_OPUNM 6
+-#define LUA_OPEQ 0
+-#define LUA_OPLT 1
+-#define LUA_OPLE 2
++#ifndef LUA_OK
++#  define LUA_OK 0
++#endif
++#ifndef LUA_OPADD
++#  define LUA_OPADD 0
++#endif
++#ifndef LUA_OPSUB
++#  define LUA_OPSUB 1
++#endif
++#ifndef LUA_OPMUL
++#  define LUA_OPMUL 2
++#endif
++#ifndef LUA_OPDIV
++#  define LUA_OPDIV 3
++#endif
++#ifndef LUA_OPMOD
++#  define LUA_OPMOD 4
++#endif
++#ifndef LUA_OPPOW
++#  define LUA_OPPOW 5
++#endif
++#ifndef LUA_OPUNM
++#  define LUA_OPUNM 6
++#endif
++#ifndef LUA_OPEQ
++#  define LUA_OPEQ 0
++#endif
++#ifndef LUA_OPLT
++#  define LUA_OPLT 1
++#endif
++#ifndef LUA_OPLE
++#  define LUA_OPLE 2
++#endif
++
++/* LuaJIT/Lua 5.1 does not have the updated
++ * error codes for thread status/function returns (but some patched versions do)
++ * define it only if it's not found
++ */
++#if !defined(LUA_ERRGCMM)
++/* Use + 2 because in some versions of Lua (Lua 5.1)
++ * LUA_ERRFILE is defined as (LUA_ERRERR+1)
++ * so we need to avoid it (LuaJIT might have something at this
++ * integer value too)
++ */
++#  define LUA_ERRGCMM (LUA_ERRERR + 2)
++#endif /* LUA_ERRGCMM define */
+ 
+ typedef size_t lua_Unsigned;
+ 
+@@ -86,6 +111,14 @@ typedef struct luaL_Buffer_53 {
+ } luaL_Buffer_53;
+ #define luaL_Buffer luaL_Buffer_53
+ 
++/* In PUC-Rio 5.1, userdata is a simple FILE*
++ * In LuaJIT, it's a struct where the first member is a FILE*
++ * We can't support the `closef` member
++ */
++typedef struct luaL_Stream {
++  FILE *f;
++} luaL_Stream;
++
+ #define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex)
+ COMPAT53_API int lua_absindex (lua_State *L, int i);
+ 
+@@ -99,20 +132,30 @@ COMPAT53_API int lua_compare (lua_State
+ COMPAT53_API void lua_copy (lua_State *L, int from, int to);
+ 
+ #define lua_getuservalue(L, i) \
+-  (lua_getfenv(L, i), lua_type(L, -1))
++  (lua_getfenv((L), (i)), lua_type((L), -1))
+ #define lua_setuservalue(L, i) \
+-  (luaL_checktype(L, -1, LUA_TTABLE), lua_setfenv(L, i))
++  (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i)))
+ 
+ #define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len)
+ COMPAT53_API void lua_len (lua_State *L, int i);
+ 
+-#define luaL_newlibtable(L, l) \
+-  (lua_createtable(L, 0, sizeof(l)/sizeof(*(l))-1))
+-#define luaL_newlib(L, l) \
+-  (luaL_newlibtable(L, l), luaL_register(L, NULL, l))
++#define lua_pushstring(L, s) \
++  (lua_pushstring((L), (s)), lua_tostring((L), -1))
++
++#define lua_pushlstring(L, s, len) \
++  ((((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))), lua_tostring((L), -1))
++
++#ifndef luaL_newlibtable
++#  define luaL_newlibtable(L, l) \
++  (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1))
++#endif
++#ifndef luaL_newlib
++#  define luaL_newlib(L, l) \
++  (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l)))
++#endif
+ 
+ #define lua_pushglobaltable(L) \
+-  lua_pushvalue(L, LUA_GLOBALSINDEX)
++  lua_pushvalue((L), LUA_GLOBALSINDEX)
+ 
+ #define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp)
+ COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p);
+@@ -120,10 +163,9 @@ COMPAT53_API int lua_rawgetp (lua_State
+ #define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp)
+ COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p);
+ 
+-#define lua_rawlen(L, i) lua_objlen(L, i)
++#define lua_rawlen(L, i) lua_objlen((L), (i))
+ 
+-#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx)
+-COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum);
++#define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL)
+ 
+ #define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx)
+ COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum);
+@@ -131,6 +173,15 @@ COMPAT53_API lua_Number lua_tonumberx (l
+ #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion)
+ COMPAT53_API void luaL_checkversion (lua_State *L);
+ 
++#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53)
++COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode);
++
++#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex)
++COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode);
++
++#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx)
++COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
++
+ #define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53)
+ COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg);
+ 
+@@ -138,7 +189,7 @@ COMPAT53_API void luaL_checkstack (lua_S
+ COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name);
+ 
+ #define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len)
+-COMPAT53_API int luaL_len (lua_State *L, int i);
++COMPAT53_API lua_Integer luaL_len (lua_State *L, int i);
+ 
+ #define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs)
+ COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
+@@ -149,10 +200,6 @@ COMPAT53_API void luaL_setmetatable (lua
+ #define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata)
+ COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname);
+ 
+-#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring)
+-COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
+-
+-#if !defined(COMPAT53_IS_LUAJIT)
+ #define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback)
+ COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level);
+ 
+@@ -161,12 +208,14 @@ COMPAT53_API int luaL_fileresult (lua_St
+ 
+ #define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult)
+ COMPAT53_API int luaL_execresult (lua_State *L, int stat);
+-#endif /* COMPAT53_IS_LUAJIT */
+ 
+ #define lua_callk(L, na, nr, ctx, cont) \
+-  ((void)(ctx), (void)(cont), lua_call(L, na, nr))
++  ((void)(ctx), (void)(cont), lua_call((L), (na), (nr)))
+ #define lua_pcallk(L, na, nr, err, ctx, cont) \
+-  ((void)(ctx), (void)(cont), lua_pcall(L, na, nr, err))
++  ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err)))
++
++#define lua_resume(L, from, nargs) \
++  ((void)(from), lua_resume((L), (nargs)))
+ 
+ #define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53)
+ COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B);
+@@ -185,15 +234,15 @@ COMPAT53_API void luaL_pushresult (luaL_
+ 
+ #undef luaL_buffinitsize
+ #define luaL_buffinitsize(L, B, s) \
+-  (luaL_buffinit(L, B), luaL_prepbuffsize(B, s))
++  (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s)))
+ 
+ #undef luaL_prepbuffer
+ #define luaL_prepbuffer(B) \
+-  luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
++  luaL_prepbuffsize((B), LUAL_BUFFERSIZE)
+ 
+ #undef luaL_addchar
+ #define luaL_addchar(B, c) \
+-  ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize(B, 1)), \
++  ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \
+    ((B)->ptr[(B)->nelems++] = (c)))
+ 
+ #undef luaL_addsize
+@@ -202,23 +251,23 @@ COMPAT53_API void luaL_pushresult (luaL_
+ 
+ #undef luaL_addstring
+ #define luaL_addstring(B, s) \
+-  luaL_addlstring(B, s, strlen(s))
++  luaL_addlstring((B), (s), strlen((s)))
+ 
+ #undef luaL_pushresultsize
+ #define luaL_pushresultsize(B, s) \
+-  (luaL_addsize(B, s), luaL_pushresult(B))
++  (luaL_addsize((B), (s)), luaL_pushresult((B)))
+ 
+ #if defined(LUA_COMPAT_APIINTCASTS)
+ #define lua_pushunsigned(L, n) \
+-  lua_pushinteger(L, (lua_Integer)(n))
++  lua_pushinteger((L), (lua_Integer)(n))
+ #define lua_tounsignedx(L, i, is) \
+-  ((lua_Unsigned)lua_tointegerx(L, i, is))
++  ((lua_Unsigned)lua_tointegerx((L), (i), (is)))
+ #define lua_tounsigned(L, i) \
+-  lua_tounsignedx(L, i, NULL)
++  lua_tounsignedx((L), (i), NULL)
+ #define luaL_checkunsigned(L, a) \
+-  ((lua_Unsigned)luaL_checkinteger(L, a))
++  ((lua_Unsigned)luaL_checkinteger((L), (a)))
+ #define luaL_optunsigned(L, a, d) \
+-  ((lua_Unsigned)luaL_optinteger(L, a, (lua_Integer)(d)))
++  ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d)))
+ #endif
+ 
+ #endif /* Lua 5.1 only */
+@@ -233,13 +282,13 @@ typedef int lua_KContext;
+ typedef int (*lua_KFunction)(lua_State *L, int status, lua_KContext ctx);
+ 
+ #define lua_dump(L, w, d, s) \
+-  ((void)(s), lua_dump(L, w, d))
++  ((void)(s), lua_dump((L), (w), (d)))
+ 
+ #define lua_getfield(L, i, k) \
+-  (lua_getfield(L, i, k), lua_type(L, -1))
++  (lua_getfield((L), (i), (k)), lua_type((L), -1))
+ 
+ #define lua_gettable(L, i) \
+-  (lua_gettable(L, i), lua_type(L, -1))
++  (lua_gettable((L), (i)), lua_type((L), -1))
+ 
+ #define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti)
+ COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i);
+@@ -247,14 +296,17 @@ COMPAT53_API int lua_geti (lua_State *L,
+ #define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger)
+ COMPAT53_API int lua_isinteger (lua_State *L, int index);
+ 
++#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53)
++COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum);
++
+ #define lua_numbertointeger(n, p) \
+   ((*(p) = (lua_Integer)(n)), 1)
+ 
+ #define lua_rawget(L, i) \
+-  (lua_rawget(L, i), lua_type(L, -1))
++  (lua_rawget((L), (i)), lua_type((L), -1))
+ 
+ #define lua_rawgeti(L, i, n) \
+-  (lua_rawgeti(L, i, n), lua_type(L, -1))
++  (lua_rawgeti((L), (i), (n)), lua_type((L), -1))
+ 
+ #define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate)
+ COMPAT53_API void lua_rotate (lua_State *L, int idx, int n);
+@@ -265,11 +317,14 @@ COMPAT53_API void lua_seti (lua_State *L
+ #define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber)
+ COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s);
+ 
++#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring)
++COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
++
+ #define luaL_getmetafield(L, o, e) \
+-  (luaL_getmetafield(L, o, e) ? lua_type(L, -1) : LUA_TNIL)
++  (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL)
+ 
+ #define luaL_newmetatable(L, tn) \
+-  (luaL_newmetatable(L, tn) ? (lua_pushstring(L, tn), lua_setfield(L, -2, "__name"), 1) : 0)
++  (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0)
+ 
+ #define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53)
+ COMPAT53_API void luaL_requiref (lua_State *L, const char *modname,
+@@ -290,13 +345,16 @@ COMPAT53_API void luaL_requiref (lua_Sta
+  */
+ 
+ #define lua_getglobal(L, n) \
+-  (lua_getglobal(L, n), lua_type(L, -1))
++  (lua_getglobal((L), (n)), lua_type((L), -1))
+ 
+ #define lua_getuservalue(L, i) \
+-  (lua_getuservalue(L, i), lua_type(L, -1))
++  (lua_getuservalue((L), (i)), lua_type((L), -1))
++
++#define lua_pushlstring(L, s, len) \
++  (((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len)))
+ 
+ #define lua_rawgetp(L, i, p) \
+-  (lua_rawgetp(L, i, p), lua_type(L, -1))
++  (lua_rawgetp((L), (i), (p)), lua_type((L), -1))
+ 
+ #define LUA_KFUNCTION(_name) \
+   static int (_name)(lua_State *L, int status, lua_KContext ctx); \
+@@ -308,30 +366,30 @@ COMPAT53_API void luaL_requiref (lua_Sta
+   static int (_name)(lua_State *L, int status, lua_KContext ctx)
+ 
+ #define lua_pcallk(L, na, nr, err, ctx, cont) \
+-  lua_pcallk(L, na, nr, err, ctx, cont ## _52)
++  lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52)
+ 
+ #define lua_callk(L, na, nr, ctx, cont) \
+-  lua_callk(L, na, nr, ctx, cont ## _52)
++  lua_callk((L), (na), (nr), (ctx), cont ## _52)
+ 
+ #define lua_yieldk(L, nr, ctx, cont) \
+-  lua_yieldk(L, nr, ctx, cont ## _52)
++  lua_yieldk((L), (nr), (ctx), cont ## _52)
+ 
+ #ifdef lua_call
+ #  undef lua_call
+ #  define lua_call(L, na, nr) \
+-  (lua_callk)(L, na, nr, 0, NULL)
++  (lua_callk)((L), (na), (nr), 0, NULL)
+ #endif
+ 
+ #ifdef lua_pcall
+ #  undef lua_pcall
+ #  define lua_pcall(L, na, nr, err) \
+-  (lua_pcallk)(L, na, nr, err, 0, NULL)
++  (lua_pcallk)((L), (na), (nr), (err), 0, NULL)
+ #endif
+ 
+ #ifdef lua_yield
+ #  undef lua_yield
+ #  define lua_yield(L, nr) \
+-  (lua_yieldk)(L, nr, 0, NULL)
++  (lua_yieldk)((L), (nr), 0, NULL)
+ #endif
+ 
+ #endif /* Lua 5.2 only */
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/compat53/init.lua luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/compat53/init.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/compat53/init.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/compat53/init.lua	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,373 @@
++local lua_version = _VERSION:sub(-3)
++
++
++if lua_version < "5.3" then
++
++   local _G, pairs, require, select, type =
++         _G, pairs, require, select, type
++   local debug, io = debug, io
++   local unpack = lua_version == "5.1" and unpack or table.unpack
++
++   local M = require("compat53.module")
++
++   -- select the most powerful getmetatable function available
++   local gmt = type(debug) == "table" and debug.getmetatable or
++               getmetatable or function() return false end
++   -- metatable for file objects from Lua's standard io library
++   local file_meta = gmt(io.stdout)
++
++
++   -- make '*' optional for file:read and file:lines
++   if type(file_meta) == "table" and type(file_meta.__index) == "table" then
++
++      local function addasterisk(fmt)
++         if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then
++            return "*"..fmt
++         else
++            return fmt
++         end
++      end
++
++      local file_lines = file_meta.__index.lines
++      file_meta.__index.lines = function(self, ...)
++         local n = select('#', ...)
++         for i = 1, n do
++            local a = select(i, ...)
++            local b = addasterisk(a)
++            -- as an optimization we only allocate a table for the
++            -- modified format arguments when we have a '*' somewhere
++            if a ~= b then
++               local args = { ... }
++               args[i] = b
++               for j = i+1, n do
++                  args[j] = addasterisk(args[j])
++               end
++               return file_lines(self, unpack(args, 1, n))
++            end
++         end
++         return file_lines(self, ...)
++      end
++
++      local file_read = file_meta.__index.read
++      file_meta.__index.read = function(self, ...)
++         local n = select('#', ...)
++         for i = 1, n do
++            local a = select(i, ...)
++            local b = addasterisk(a)
++            -- as an optimization we only allocate a table for the
++            -- modified format arguments when we have a '*' somewhere
++            if a ~= b then
++               local args = { ... }
++               args[i] = b
++               for j = i+1, n do
++                  args[j] = addasterisk(args[j])
++               end
++               return file_read(self, unpack(args, 1, n))
++            end
++         end
++         return file_read(self, ...)
++      end
++
++   end -- got a valid metatable for file objects
++
++
++   -- changes for Lua 5.1 only
++   if lua_version == "5.1" then
++
++      -- cache globals
++      local error, pcall, rawset, setmetatable, tostring, xpcall =
++            error, pcall, rawset, setmetatable, tostring, xpcall
++      local coroutine, package, string = coroutine, package, string
++      local coroutine_resume = coroutine.resume
++      local coroutine_running = coroutine.running
++      local coroutine_status = coroutine.status
++      local coroutine_yield = coroutine.yield
++      local io_type = io.type
++
++
++      -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
++      local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
++      local is_luajit52 = is_luajit and
++        #setmetatable({}, { __len = function() return 1 end }) == 1
++
++
++      -- make package.searchers available as an alias for package.loaders
++      local p_index = { searchers = package.loaders }
++      setmetatable(package, {
++         __index = p_index,
++         __newindex = function(p, k, v)
++            if k == "searchers" then
++               rawset(p, "loaders", v)
++               p_index.searchers = v
++            else
++               rawset(p, k, v)
++            end
++         end
++      })
++
++
++      if type(file_meta) == "table" and type(file_meta.__index) == "table" then
++         if not is_luajit then
++            local function helper(_, var_1, ...)
++               if var_1 == nil then
++                  if (...) ~= nil then
++                     error((...), 2)
++                  end
++               end
++               return var_1, ...
++            end
++
++            local function lines_iterator(st)
++               return helper(st, st.f:read(unpack(st, 1, st.n)))
++            end
++
++            local file_write = file_meta.__index.write
++            file_meta.__index.write = function(self, ...)
++               local res, msg, errno = file_write(self, ...)
++               if res then
++                  return self
++               else
++                  return nil, msg, errno
++               end
++            end
++
++            file_meta.__index.lines = function(self, ...)
++               if io_type(self) == "closed file" then
++                  error("attempt to use a closed file", 2)
++               end
++               local st = { f=self, n=select('#', ...), ... }
++               for i = 1, st.n do
++                  local t = type(st[i])
++                  if t == "string" then
++                     local fmt = st[i]:match("^*?([aln])")
++                     if not fmt then
++                        error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
++                     end
++                     st[i] = "*"..fmt
++                  elseif t ~= "number" then
++                     error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
++                  end
++               end
++               return lines_iterator, st
++            end
++         end -- not luajit
++      end -- file_meta valid
++
++
++      -- the (x)pcall implementations start a new coroutine internally
++      -- to allow yielding even in Lua 5.1. to allow for accurate
++      -- stack traces we keep track of the nested coroutine activations
++      -- in the weak tables below:
++      local weak_meta = { __mode = "kv" }
++      -- maps the internal pcall coroutines to the user coroutine that
++      -- *should* be running if pcall didn't use coroutines internally
++      local pcall_mainOf = setmetatable({}, weak_meta)
++      -- table that maps each running coroutine started by pcall to
++      -- the coroutine that resumed it (user coroutine *or* pcall
++      -- coroutine!)
++      local pcall_previous = setmetatable({}, weak_meta)
++      -- reverse of `pcall_mainOf`. maps a user coroutine to the
++      -- currently active pcall coroutine started within it
++      local pcall_callOf = setmetatable({}, weak_meta)
++      -- similar to `pcall_mainOf` but is used only while executing
++      -- the error handler of xpcall (thus no nesting is necessary!)
++      local xpcall_running = setmetatable({}, weak_meta)
++
++      -- handle debug functions
++      if type(debug) == "table" then
++         local debug_getinfo = debug.getinfo
++         local debug_traceback = debug.traceback
++
++         if not is_luajit then
++            local function calculate_trace_level(co, level)
++               if level ~= nil then
++                  for out = 1, 1/0 do
++                     local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "")
++                     if info == nil then
++                        local max = out-1
++                        if level <= max then
++                           return level
++                        end
++                        return nil, level-max
++                     end
++                  end
++               end
++               return 1
++            end
++
++            local stack_pattern = "\nstack traceback:"
++            local stack_replace = ""
++            function debug.traceback(co, msg, level)
++               local lvl
++               local nilmsg
++               if type(co) ~= "thread" then
++                  co, msg, level = coroutine_running(), co, msg
++               end
++               if msg == nil then
++                  msg = ""
++                  nilmsg = true
++               elseif type(msg) ~= "string" then
++                  return msg
++               end
++               if co == nil then
++                  msg = debug_traceback(msg, level or 1)
++               else
++                  local xpco = xpcall_running[co]
++                  if xpco ~= nil then
++                     lvl, level = calculate_trace_level(xpco, level)
++                     if lvl then
++                        msg = debug_traceback(xpco, msg, lvl)
++                     else
++                        msg = msg..stack_pattern
++                     end
++                     lvl, level = calculate_trace_level(co, level)
++                     if lvl then
++                        local trace = debug_traceback(co, "", lvl)
++                        msg = msg..trace:gsub(stack_pattern, stack_replace)
++                     end
++                  else
++                     co = pcall_callOf[co] or co
++                     lvl, level = calculate_trace_level(co, level)
++                     if lvl then
++                        msg = debug_traceback(co, msg, lvl)
++                     else
++                        msg = msg..stack_pattern
++                     end
++                  end
++                  co = pcall_previous[co]
++                  while co ~= nil do
++                     lvl, level = calculate_trace_level(co, level)
++                     if lvl then
++                        local trace = debug_traceback(co, "", lvl)
++                        msg = msg..trace:gsub(stack_pattern, stack_replace)
++                     end
++                     co = pcall_previous[co]
++                  end
++               end
++               if nilmsg then
++                  msg = msg:gsub("^\n", "")
++               end
++               msg = msg:gsub("\n\t%(tail call%): %?", "\000")
++               msg = msg:gsub("\n\t%.%.%.\n", "\001\n")
++               msg = msg:gsub("\n\t%.%.%.$", "\001")
++               msg = msg:gsub("(%z+)\001(%z+)", function(some, other)
++                  return "\n\t(..."..#some+#other.."+ tail call(s)...)"
++               end)
++               msg = msg:gsub("\001(%z+)", function(zeros)
++                  return "\n\t(..."..#zeros.."+ tail call(s)...)"
++               end)
++               msg = msg:gsub("(%z+)\001", function(zeros)
++                  return "\n\t(..."..#zeros.."+ tail call(s)...)"
++               end)
++               msg = msg:gsub("%z+", function(zeros)
++                  return "\n\t(..."..#zeros.." tail call(s)...)"
++               end)
++               msg = msg:gsub("\001", function()
++                  return "\n\t..."
++               end)
++               return msg
++            end
++         end -- is not luajit
++      end -- debug table available
++
++
++      if not is_luajit52 then
++         local coroutine_running52 = M.coroutine.running
++         function M.coroutine.running()
++            local co, ismain = coroutine_running52()
++            if ismain then
++               return co, true
++            else
++               return pcall_mainOf[co] or co, false
++            end
++         end
++      end
++
++      if not is_luajit then
++         local function pcall_results(current, call, success, ...)
++            if coroutine_status(call) == "suspended" then
++               return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...)))
++            end
++            if pcall_previous then
++               pcall_previous[call] = nil
++               local main = pcall_mainOf[call]
++               if main == current then current = nil end
++               pcall_callOf[main] = current
++            end
++            pcall_mainOf[call] = nil
++            return success, ...
++         end
++
++         local function pcall_exec(current, call, ...)
++            local main = pcall_mainOf[current] or current
++            pcall_mainOf[call] = main
++            if pcall_previous then
++               pcall_previous[call] = current
++               pcall_callOf[main] = call
++            end
++            return pcall_results(current, call, coroutine_resume(call, ...))
++         end
++
++         local coroutine_create52 = M.coroutine.create
++
++         local function pcall_coroutine(func)
++            if type(func) ~= "function" then
++               local callable = func
++               func = function (...) return callable(...) end
++            end
++            return coroutine_create52(func)
++         end
++
++         function M.pcall(func, ...)
++            local current = coroutine_running()
++            if not current then return pcall(func, ...) end
++            return pcall_exec(current, pcall_coroutine(func), ...)
++         end
++
++         local function xpcall_catch(current, call, msgh, success, ...)
++            if not success then
++               xpcall_running[current] = call
++               local ok, result = pcall(msgh, ...)
++               xpcall_running[current] = nil
++               if not ok then
++                  return false, "error in error handling ("..tostring(result)..")"
++               end
++               return false, result
++            end
++            return true, ...
++         end
++
++         function M.xpcall(f, msgh, ...)
++            local current = coroutine_running()
++            if not current then
++               local args, n = { ... }, select('#', ...)
++               return xpcall(function() return f(unpack(args, 1, n)) end, msgh)
++            end
++            local call = pcall_coroutine(f)
++            return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...))
++         end
++      end -- not luajit
++
++   end -- lua 5.1
++
++
++   -- handle exporting to global scope
++   local function extend_table(from, to)
++      if from ~= to then
++         for k,v in pairs(from) do
++            if type(v) == "table" and
++               type(to[k]) == "table" and
++               v ~= to[k] then
++               extend_table(v, to[k])
++            else
++               to[k] = v
++            end
++         end
++      end
++   end
++
++   extend_table(M, _G)
++
++end -- lua < 5.3
++
++-- vi: set expandtab softtabstop=3 shiftwidth=3 :
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/compat53/module.lua luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/compat53/module.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/compat53/module.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/compat53/module.lua	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,827 @@
++local _G, _VERSION = _G, _VERSION
++local lua_version = _VERSION:sub(-3)
++
++
++local M = _G
++
++if lua_version < "5.3" then
++
++   -- cache globals in upvalues
++   local error, ipairs, pairs, pcall, require, select, setmetatable, type =
++         error, ipairs, pairs, pcall, require, select, setmetatable, type
++   local debug, io, math, package, string, table =
++         debug, io, math, package, string, table
++   local io_lines = io.lines
++   local io_read = io.read
++   local unpack = lua_version == "5.1" and unpack or table.unpack
++
++   -- create module table
++   M = {}
++   local M_meta = {
++      __index = _G,
++      -- __newindex is set at the end
++   }
++   setmetatable(M, M_meta)
++
++   -- create subtables
++   M.io = setmetatable({}, { __index = io })
++   M.math = setmetatable({}, { __index = math })
++   M.string = setmetatable({}, { __index = string })
++   M.table = setmetatable({}, { __index = table })
++   M.utf8 = {}
++
++
++   -- select the most powerful getmetatable function available
++   local gmt = type(debug) == "table" and debug.getmetatable or
++               getmetatable or function() return false end
++
++   -- type checking functions
++   local checkinteger -- forward declararation
++
++   local function argcheck(cond, i, f, extra)
++      if not cond then
++         error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0)
++      end
++   end
++
++
++   -- load utf8 library
++   local utf8_ok, utf8lib = pcall(require, "compat53.utf8")
++   if utf8_ok then
++      if lua_version == "5.1" then
++         utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*"
++      end
++      for k,v in pairs(utf8lib) do
++         M.utf8[k] = v
++      end
++      package.loaded["utf8"] = M.utf8
++   end
++
++
++   -- load table library
++   local table_ok, tablib = pcall(require, "compat53.table")
++   if table_ok then
++      for k,v in pairs(tablib) do
++         M.table[k] = v
++      end
++   end
++
++
++   -- load string packing functions
++   local str_ok, strlib = pcall(require, "compat53.string")
++   if str_ok then
++      for k,v in pairs(strlib) do
++         M.string[k] = v
++      end
++   end
++
++
++   -- try Roberto's struct module for string packing/unpacking if
++   -- compat53.string is unavailable
++   if not str_ok then
++      local struct_ok, struct = pcall(require, "struct")
++      if struct_ok then
++         M.string.pack = struct.pack
++         M.string.packsize = struct.size
++         M.string.unpack = struct.unpack
++      end
++   end
++
++
++   -- update math library
++   do
++      local maxint, minint = 1
++
++      while maxint+1 > maxint and 2*maxint > maxint do
++         maxint = maxint * 2
++      end
++      if 2*maxint <= maxint then
++         maxint = 2*maxint-1
++         minint = -maxint-1
++      else
++         maxint = maxint
++         minint = -maxint
++      end
++      M.math.maxinteger = maxint
++      M.math.mininteger = minint
++
++      function M.math.tointeger(n)
++         if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then
++            return n
++         end
++         return nil
++      end
++
++      function M.math.type(n)
++         if type(n) == "number" then
++            if n <= maxint and n >= minint and n % 1 == 0 then
++               return "integer"
++            else
++               return "float"
++            end
++         else
++            return nil
++         end
++      end
++
++      function checkinteger(x, i, f)
++         local t = type(x)
++         if t ~= "number" then
++            error("bad argument #"..i.." to '"..f..
++                  "' (number expected, got "..t..")", 0)
++         elseif x > maxint or x < minint or x % 1 ~= 0 then
++            error("bad argument #"..i.." to '"..f..
++                  "' (number has no integer representation)", 0)
++         else
++            return x
++         end
++      end
++
++      function M.math.ult(m, n)
++         m = checkinteger(m, "1", "math.ult")
++         n = checkinteger(n, "2", "math.ult")
++         if m >= 0 and n < 0 then
++            return true
++         elseif m < 0 and n >= 0 then
++            return false
++         else
++            return m < n
++         end
++      end
++   end
++
++
++   -- assert should allow non-string error objects
++   function M.assert(cond, ...)
++      if cond then
++         return cond, ...
++      elseif select('#', ...) > 0 then
++         error((...), 0)
++      else
++         error("assertion failed!", 0)
++      end
++   end
++
++
++   -- ipairs should respect __index metamethod
++   do
++      local function ipairs_iterator(st, var)
++         var = var + 1
++         local val = st[var]
++         if val ~= nil then
++            return var, st[var]
++         end
++      end
++      function M.ipairs(t)
++         if gmt(t) ~= nil then -- t has metatable
++            return ipairs_iterator, t, 0
++         else
++            return ipairs(t)
++         end
++      end
++   end
++
++
++   -- make '*' optional for io.read and io.lines
++   do
++      local function addasterisk(fmt)
++         if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then
++            return "*"..fmt
++         else
++            return fmt
++         end
++      end
++
++      function M.io.read(...)
++         local n = select('#', ...)
++         for i = 1, n do
++            local a = select(i, ...)
++            local b = addasterisk(a)
++            -- as an optimization we only allocate a table for the
++            -- modified format arguments when we have a '*' somewhere.
++            if a ~= b then
++               local args = { ... }
++               args[i] = b
++               for j = i+1, n do
++                  args[j] = addasterisk(args[j])
++               end
++               return io_read(unpack(args, 1, n))
++            end
++         end
++         return io_read(...)
++      end
++
++      -- PUC-Rio Lua 5.1 uses a different implementation for io.lines!
++      function M.io.lines(...)
++         local n = select('#', ...)
++         for i = 2, n do
++            local a = select(i, ...)
++            local b = addasterisk(a)
++            -- as an optimization we only allocate a table for the
++            -- modified format arguments when we have a '*' somewhere.
++            if a ~= b then
++               local args = { ... }
++               args[i] = b
++               for j = i+1, n do
++                  args[j] = addasterisk(args[j])
++               end
++               return io_lines(unpack(args, 1, n))
++            end
++         end
++         return io_lines(...)
++      end
++   end
++
++
++   -- update table library (if C module not available)
++   if not table_ok then
++      local table_concat = table.concat
++      local table_insert = table.insert
++      local table_remove = table.remove
++      local table_sort = table.sort
++
++      function M.table.concat(list, sep, i, j)
++         local mt = gmt(list)
++         if type(mt) == "table" and type(mt.__len) == "function" then
++            local src = list
++            list, i, j  = {}, i or 1, j or mt.__len(src)
++            for k = i, j do
++               list[k] = src[k]
++            end
++         end
++         return table_concat(list, sep, i, j)
++      end
++
++      function M.table.insert(list, ...)
++         local mt = gmt(list)
++         local has_mt = type(mt) == "table"
++         local has_len = has_mt and type(mt.__len) == "function"
++         if has_mt and (has_len or mt.__index or mt.__newindex) then
++            local e = (has_len and mt.__len(list) or #list)+1
++            local nargs, pos, value = select('#', ...), ...
++            if nargs == 1 then
++               pos, value = e, pos
++            elseif nargs == 2 then
++               pos = checkinteger(pos, "2", "table.insert")
++               argcheck(1 <= pos and pos <= e, "2", "table.insert",
++                        "position out of bounds" )
++            else
++               error("wrong number of arguments to 'insert'", 0)
++            end
++            for i = e-1, pos, -1 do
++               list[i+1] = list[i]
++            end
++            list[pos] = value
++         else
++            return table_insert(list, ...)
++         end
++      end
++
++      function M.table.move(a1, f, e, t, a2)
++         a2 = a2 or a1
++         f = checkinteger(f, "2", "table.move")
++         argcheck(f > 0, "2", "table.move",
++                  "initial position must be positive")
++         e = checkinteger(e, "3", "table.move")
++         t = checkinteger(t, "4", "table.move")
++         if e >= f then
++            local m, n, d = 0, e-f, 1
++            if t > f then m, n, d = n, m, -1 end
++            for i = m, n, d do
++               a2[t+i] = a1[f+i]
++            end
++         end
++         return a2
++      end
++
++      function M.table.remove(list, pos)
++         local mt = gmt(list)
++         local has_mt = type(mt) == "table"
++         local has_len = has_mt and type(mt.__len) == "function"
++         if has_mt and (has_len or mt.__index or mt.__newindex) then
++            local e = (has_len and mt.__len(list) or #list)
++            pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e
++            if pos ~= e then
++               argcheck(1 <= pos and pos <= e+1, "2", "table.remove",
++                        "position out of bounds" )
++            end
++            local result = list[pos]
++            while pos < e do
++               list[pos] = list[pos+1]
++               pos = pos + 1
++            end
++            list[pos] = nil
++            return result
++         else
++            return table_remove(list, pos)
++         end
++      end
++
++      do
++         local function pivot(list, cmp, a, b)
++            local m = b - a
++            if m > 2 then
++               local c = a + (m-m%2)/2
++               local x, y, z = list[a], list[b], list[c]
++               if not cmp(x, y) then
++                  x, y, a, b = y, x, b, a
++               end
++               if not cmp(y, z) then
++                  y, b = z, c
++               end
++               if not cmp(x, y) then
++                  y, b = x, a
++               end
++               return b, y
++            else
++               return b, list[b]
++            end
++         end
++
++         local function lt_cmp(a, b)
++            return a < b
++         end
++
++         local function qsort(list, cmp, b, e)
++            if b < e then
++               local i, j, k, val = b, e, pivot(list, cmp, b, e)
++               while i < j do
++                  while i < j and cmp(list[i], val) do
++                     i = i + 1
++                  end
++                  while i < j and not cmp(list[j], val) do
++                     j = j - 1
++                  end
++                  if i < j then
++                     list[i], list[j] = list[j], list[i]
++                     if i == k then k = j end -- update pivot position
++                     i, j = i+1, j-1
++                  end
++               end
++               if i ~= k and not cmp(list[i], val) then
++                  list[i], list[k] = val, list[i]
++                  k = i -- update pivot position
++               end
++               qsort(list, cmp, b, i == k and i-1 or i)
++               return qsort(list, cmp, i+1, e)
++            end
++         end
++
++         function M.table.sort(list, cmp)
++            local mt = gmt(list)
++            local has_mt = type(mt) == "table"
++            local has_len = has_mt and type(mt.__len) == "function"
++            if has_len then
++               cmp = cmp or lt_cmp
++               local len = mt.__len(list)
++               return qsort(list, cmp, 1, len)
++            else
++               return table_sort(list, cmp)
++            end
++         end
++      end
++
++      local function unpack_helper(list, i, j, ...)
++         if j < i then
++            return ...
++         else
++            return unpack_helper(list, i, j-1, list[j], ...)
++         end
++      end
++      function M.table.unpack(list, i, j)
++         local mt = gmt(list)
++         local has_mt = type(mt) == "table"
++         local has_len = has_mt and type(mt.__len) == "function"
++         if has_mt and (has_len or mt.__index) then
++            i, j = i or 1, j or (has_len and mt.__len(list)) or #list
++            return unpack_helper(list, i, j)
++         else
++            return unpack(list, i, j)
++         end
++      end
++   end -- update table library
++
++
++   -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2
++   if lua_version == "5.1" then
++      -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
++      local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
++      local is_luajit52 = is_luajit and
++        #setmetatable({}, { __len = function() return 1 end }) == 1
++
++      -- cache globals in upvalues
++      local load, loadfile, loadstring, setfenv, xpcall =
++            load, loadfile, loadstring, setfenv, xpcall
++      local coroutine, os = coroutine, os
++      local coroutine_create = coroutine.create
++      local coroutine_resume = coroutine.resume
++      local coroutine_running = coroutine.running
++      local coroutine_status = coroutine.status
++      local coroutine_yield = coroutine.yield
++      local io_input = io.input
++      local io_open = io.open
++      local io_output = io.output
++      local io_write = io.write
++      local math_log = math.log
++      local os_execute = os.execute
++      local string_find = string.find
++      local string_format = string.format
++      local string_gmatch = string.gmatch
++      local string_gsub = string.gsub
++      local string_match = string.match
++      local string_rep = string.rep
++      local table_concat = table.concat
++
++      -- create subtables
++      M.coroutine = setmetatable({}, { __index = coroutine })
++      M.os = setmetatable({}, { __index = os })
++      M.package = setmetatable({}, { __index = package })
++
++      -- handle debug functions
++      if type(debug) == "table" then
++         local debug_setfenv = debug.setfenv
++         local debug_getfenv = debug.getfenv
++         local debug_setmetatable = debug.setmetatable
++
++         M.debug = setmetatable({}, { __index = debug })
++
++         if not is_luajit52 then
++            function M.debug.setuservalue(obj, value)
++               if type(obj) ~= "userdata" then
++                  error("bad argument #1 to 'setuservalue' (userdata expected, got "..
++                        type(obj)..")", 2)
++               end
++               if value == nil then value = _G end
++               if type(value) ~= "table" then
++                  error("bad argument #2 to 'setuservalue' (table expected, got "..
++                        type(value)..")", 2)
++               end
++               return debug_setfenv(obj, value)
++            end
++
++            function M.debug.getuservalue(obj)
++               if type(obj) ~= "userdata" then
++                  return nil
++               else
++                  local v = debug_getfenv(obj)
++                  if v == _G or v == package then
++                     return nil
++                  end
++                  return v
++               end
++            end
++
++            function M.debug.setmetatable(value, tab)
++               debug_setmetatable(value, tab)
++               return value
++            end
++         end -- not luajit with compat52 enabled
++      end -- debug table available
++
++
++      if not is_luajit52 then
++         function M.pairs(t)
++            local mt = gmt(t)
++            if type(mt) == "table" and type(mt.__pairs) == "function" then
++               return mt.__pairs(t)
++            else
++               return pairs(t)
++            end
++         end
++      end
++
++
++      if not is_luajit then
++         local function check_mode(mode, prefix)
++            local has = { text = false, binary = false }
++            for i = 1,#mode do
++               local c = mode:sub(i, i)
++               if c == "t" then has.text = true end
++               if c == "b" then has.binary = true end
++            end
++            local t = prefix:sub(1, 1) == "\27" and "binary" or "text"
++            if not has[t] then
++               return "attempt to load a "..t.." chunk (mode is '"..mode.."')"
++            end
++         end
++
++         function M.load(ld, source, mode, env)
++            mode = mode or "bt"
++            local chunk, msg
++            if type( ld ) == "string" then
++               if mode ~= "bt" then
++                  local merr = check_mode(mode, ld)
++                  if merr then return nil, merr end
++               end
++               chunk, msg = loadstring(ld, source)
++            else
++               local ld_type = type(ld)
++               if ld_type ~= "function" then
++                  error("bad argument #1 to 'load' (function expected, got "..
++                        ld_type..")", 2)
++               end
++               if mode ~= "bt" then
++                  local checked, merr = false, nil
++                  local function checked_ld()
++                     if checked then
++                        return ld()
++                     else
++                        checked = true
++                        local v = ld()
++                        merr = check_mode(mode, v or "")
++                        if merr then return nil end
++                        return v
++                     end
++                  end
++                  chunk, msg = load(checked_ld, source)
++                  if merr then return nil, merr end
++               else
++                  chunk, msg = load(ld, source)
++               end
++            end
++            if not chunk then
++               return chunk, msg
++            end
++            if env ~= nil then
++               setfenv(chunk, env)
++            end
++            return chunk
++         end
++
++         M.loadstring = M.load
++
++         function M.loadfile(file, mode, env)
++            mode = mode or "bt"
++            if mode ~= "bt" then
++               local f = io_open(file, "rb")
++               if f then
++                  local prefix = f:read(1)
++                  f:close()
++                  if prefix then
++                     local merr = check_mode(mode, prefix)
++                     if merr then return nil, merr end
++                  end
++               end
++            end
++            local chunk, msg = loadfile(file)
++            if not chunk then
++               return chunk, msg
++            end
++            if env ~= nil then
++               setfenv(chunk, env)
++            end
++            return chunk
++         end
++      end -- not luajit
++
++
++      if not is_luajit52 then
++         function M.rawlen(v)
++            local t = type(v)
++            if t ~= "string" and t ~= "table" then
++               error("bad argument #1 to 'rawlen' (table or string expected)", 2)
++            end
++            return #v
++         end
++      end
++
++
++      if not is_luajit then
++         function M.xpcall(f, msgh, ...)
++            local args, n = { ... }, select('#', ...)
++            return xpcall(function() return f(unpack(args, 1, n)) end, msgh)
++         end
++      end
++
++
++      if not is_luajit52 then
++         function M.os.execute(cmd)
++            local code = os_execute(cmd)
++            -- Lua 5.1 does not report exit by signal.
++            if code == 0 then
++               return true, "exit", code
++            else
++               if package.config:sub(1, 1) == '/' then
++                  code = code/256 -- only correct on Linux!
++               end
++               return nil, "exit", code
++            end
++         end
++      end
++
++
++      if not table_ok and not is_luajit52 then
++         M.table.pack = function(...)
++            return { n = select('#', ...), ... }
++         end
++      end
++
++
++      local main_coroutine = coroutine_create(function() end)
++
++      function M.coroutine.create(func)
++         local success, result = pcall(coroutine_create, func)
++         if not success then
++            if type(func) ~= "function" then
++               error("bad argument #1 (function expected)", 0)
++             end
++            result = coroutine_create(function(...) return func(...) end)
++         end
++         return result
++      end
++
++      if not is_luajit52 then
++         function M.coroutine.running()
++            local co = coroutine_running()
++            if co then
++               return co, false
++            else
++               return main_coroutine, true
++            end
++         end
++      end
++
++      function M.coroutine.yield(...)
++         local co, flag = coroutine_running()
++         if co and not flag then
++            return coroutine_yield(...)
++         else
++            error("attempt to yield from outside a coroutine", 0)
++         end
++      end
++
++      if not is_luajit then
++         function M.coroutine.resume(co, ...)
++            if co == main_coroutine then
++               return false, "cannot resume non-suspended coroutine"
++            else
++               return coroutine_resume(co, ...)
++            end
++         end
++
++         function M.coroutine.status(co)
++            local notmain = coroutine_running()
++            if co == main_coroutine then
++               return notmain and "normal" or "running"
++            else
++               return coroutine_status(co)
++            end
++         end
++      end -- not luajit
++
++
++      if not is_luajit then
++         M.math.log = function(x, base)
++            if base ~= nil then
++               return math_log(x)/math_log(base)
++            else
++               return math_log(x)
++            end
++         end
++      end
++
++
++      if not is_luajit then
++         function M.package.searchpath(name, path, sep, rep)
++            sep = (sep or "."):gsub("(%p)", "%%%1")
++            rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1")
++            local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1")
++            local msg = {}
++            for subpath in path:gmatch("[^;]+") do
++               local fpath = subpath:gsub("%?", pname)
++               local f = io_open(fpath, "r")
++               if f then
++                  f:close()
++                  return fpath
++               end
++               msg[#msg+1] = "\n\tno file '" .. fpath .. "'"
++            end
++            return nil, table_concat(msg)
++         end
++      end
++
++
++      local function fix_pattern(pattern)
++         return (string_gsub(pattern, "%z", "%%z"))
++      end
++
++      function M.string.find(s, pattern, ...)
++         return string_find(s, fix_pattern(pattern), ...)
++      end
++
++      function M.string.gmatch(s, pattern)
++         return string_gmatch(s, fix_pattern(pattern))
++      end
++
++      function M.string.gsub(s, pattern, ...)
++         return string_gsub(s, fix_pattern(pattern), ...)
++      end
++
++      function M.string.match(s, pattern, ...)
++         return string_match(s, fix_pattern(pattern), ...)
++      end
++
++      if not is_luajit then
++         function M.string.rep(s, n, sep)
++            if sep ~= nil and sep ~= "" and n >= 2 then
++               return s .. string_rep(sep..s, n-1)
++            else
++               return string_rep(s, n)
++            end
++         end
++      end
++
++      if not is_luajit then
++         do
++            local addqt = {
++               ["\n"] = "\\\n",
++               ["\\"] = "\\\\",
++               ["\""] = "\\\""
++            }
++
++            local function addquoted(c, d)
++               return (addqt[c] or string_format(d~="" and "\\%03d" or "\\%d", c:byte()))..d
++            end
++
++            function M.string.format(fmt, ...)
++               local args, n = { ... }, select('#', ...)
++               local i = 0
++               local function adjust_fmt(lead, mods, kind)
++                  if #lead % 2 == 0 then
++                     i = i + 1
++                     if kind == "s" then
++                        args[i] = _G.tostring(args[i])
++                     elseif kind == "q" then
++                        args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"'
++                        return lead.."%"..mods.."s"
++                     end
++                  end
++               end
++               fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt)
++               return string_format(fmt, unpack(args, 1, n))
++            end
++         end
++      end
++
++
++      function M.io.write(...)
++         local res, msg, errno = io_write(...)
++         if res then
++            return io_output()
++         else
++            return nil, msg, errno
++         end
++      end
++
++      if not is_luajit then
++         local function helper(st, var_1, ...)
++            if var_1 == nil then
++               if st.doclose then st.f:close() end
++               if (...) ~= nil then
++                  error((...), 2)
++               end
++            end
++            return var_1, ...
++         end
++
++         local function lines_iterator(st)
++            return helper(st, st.f:read(unpack(st, 1, st.n)))
++         end
++
++         function M.io.lines(fname, ...)
++            local doclose, file, msg
++            if fname ~= nil then
++               doclose, file, msg = true, io_open(fname, "r")
++               if not file then error(msg, 2) end
++            else
++               doclose, file = false, io_input()
++            end
++            local st = { f=file, doclose=doclose, n=select('#', ...), ... }
++            for i = 1, st.n do
++               local t = type(st[i])
++               if t == "string" then
++                  local fmt = st[i]:match("^%*?([aln])")
++                  if not fmt then
++                     error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
++                  end
++                  st[i] = "*"..fmt
++               elseif t ~= "number" then
++                  error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
++               end
++            end
++            return lines_iterator, st
++         end
++      end -- not luajit
++
++   end -- lua 5.1
++
++   -- further write should be forwarded to _G
++   M_meta.__newindex = _G
++
++end -- lua < 5.3
++
++
++-- return module table
++return M
++
++-- vi: set expandtab softtabstop=3 shiftwidth=3 :
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/LICENSE luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/LICENSE
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/LICENSE	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/LICENSE	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,20 @@
++The MIT License (MIT)
++
++Copyright (c) 2015 Kepler Project.
++
++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.
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/lprefix.h luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/lprefix.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/lprefix.h	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/lprefix.h	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,175 @@
++/*
++** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $
++** Definitions for Lua code that must come before any other header file
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lprefix_h
++#define lprefix_h
++
++
++/*
++** Allows POSIX/XSI stuff
++*/
++#if !defined(LUA_USE_C89)	/* { */
++
++#if !defined(_XOPEN_SOURCE)
++#define _XOPEN_SOURCE           600
++#elif _XOPEN_SOURCE == 0
++#undef _XOPEN_SOURCE  /* use -D_XOPEN_SOURCE=0 to undefine it */
++#endif
++
++/*
++** Allows manipulation of large files in gcc and some other compilers
++*/
++#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS)
++#define _LARGEFILE_SOURCE       1
++#define _FILE_OFFSET_BITS       64
++#endif
++
++#endif				/* } */
++
++
++/*
++** Windows stuff
++*/
++#if defined(_WIN32) 	/* { */
++
++#if !defined(_CRT_SECURE_NO_WARNINGS)
++#define _CRT_SECURE_NO_WARNINGS  /* avoid warnings about ISO C functions */
++#endif
++
++#endif			/* } */
++
++
++/* COMPAT53 adaptation */
++#include "c-api/compat-5.3.h"
++
++#undef LUAMOD_API
++#define LUAMOD_API extern
++
++
++#ifdef lutf8lib_c
++#  define luaopen_utf8 luaopen_compat53_utf8
++/* we don't support the %U format string of lua_pushfstring!
++ * code below adapted from the Lua 5.3 sources:
++ */
++static const char *compat53_utf8_escape (lua_State* L, long x) {
++  if (x < 0x80) { /* ASCII */
++    char c = (char)x;
++    lua_pushlstring(L, &c, 1);
++  } else {
++    char buff[8] = { 0 };
++    unsigned int mfb = 0x3f;
++    int n = 1;
++    do {
++      buff[8 - (n++)] = (char)(0x80|(x & 0x3f));
++      x >>= 6;
++      mfb >>= 1;
++    } while (x > mfb);
++    buff[8-n] = (char)((~mfb << 1) | x);
++    lua_pushlstring(L, buff+8-n, n);
++  }
++  return lua_tostring(L, -1);
++}
++#  define lua_pushfstring(L, fmt, l) \
++  compat53_utf8_escape(L, l)
++#endif
++
++
++#ifdef ltablib_c
++#  define luaopen_table luaopen_compat53_table
++#  ifndef LUA_MAXINTEGER
++/* conservative estimate: */
++#    define LUA_MAXINTEGER INT_MAX
++#  endif
++#endif /* ltablib_c */
++
++
++#ifdef lstrlib_c
++#include <locale.h>
++#include <lualib.h>
++/* move the string library open function out of the way (we only take
++ * the string packing functions)!
++ */
++#  define luaopen_string luaopen_string_XXX
++/* used in string.format implementation, which we don't use: */
++#  ifndef LUA_INTEGER_FRMLEN
++#    define LUA_INTEGER_FRMLEN ""
++#    define LUA_NUMBER_FRMLEN ""
++#  endif
++#  ifndef LUA_MININTEGER
++#    define LUA_MININTEGER 0
++#  endif
++#  ifndef LUA_INTEGER_FMT
++#    define LUA_INTEGER_FMT "%d"
++#  endif
++#  ifndef LUAI_UACINT
++#    define LUAI_UACINT lua_Integer
++#  endif
++/* different Lua 5.3 versions have conflicting variants of this macro
++ * in luaconf.h, there's a fallback implementation in lstrlib.c, and
++ * the macro isn't used for string (un)packing anyway!
++ * */
++#  undef lua_number2strx
++#  if LUA_VERSION_NUM < 503
++/* lstrlib assumes that lua_Integer and lua_Unsigned have the same
++ * size, so we use the unsigned equivalent of ptrdiff_t! */
++#    define lua_Unsigned size_t
++#  endif
++#  ifndef l_mathlim
++#    ifdef LUA_NUMBER_DOUBLE
++#      define l_mathlim(n) (DBL_##n)
++#    else
++#      define l_mathlim(n) (FLT_##n)
++#    endif
++#  endif
++#  ifndef l_mathop
++#    ifdef LUA_NUMBER_DOUBLE
++#      define l_mathop(op) op
++#    else
++#      define l_mathop(op) op##f
++#    endif
++#  endif
++#  ifndef lua_getlocaledecpoint
++#    define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
++#  endif
++#  ifndef l_sprintf
++#    if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
++#      define l_sprintf(s,sz,f,i) (snprintf(s, sz, f, i))
++#    else
++#      define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s, f, i))
++#    endif
++#  endif
++
++static int str_pack (lua_State *L);
++static int str_packsize (lua_State *L);
++static int str_unpack (lua_State *L);
++LUAMOD_API int luaopen_compat53_string (lua_State *L) {
++  luaL_Reg const funcs[] = {
++    { "pack", str_pack },
++    { "packsize", str_packsize },
++    { "unpack", str_unpack },
++    { NULL, NULL }
++  };
++  luaL_newlib(L, funcs);
++  return 1;
++}
++/* fake CLANG feature detection on other compilers */
++#  ifndef __has_attribute
++#    define __has_attribute(x) 0
++#  endif
++/* make luaopen_string(_XXX) static, so it (and all other referenced
++ * string functions) won't be included in the resulting dll
++ * (hopefully).
++ */
++#  undef LUAMOD_API
++#  if defined(__GNUC__) || __has_attribute(__unused__)
++#    define LUAMOD_API __attribute__((__unused__)) static
++#  else
++#    define LUAMOD_API static
++#  endif
++#endif /* lstrlib.c */
++
++#endif
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/lstrlib.c luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/lstrlib.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/lstrlib.c	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/lstrlib.c	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,1584 @@
++/*
++** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $
++** Standard library for string operations and pattern-matching
++** See Copyright Notice in lua.h
++*/
++
++#define lstrlib_c
++#define LUA_LIB
++
++#include "lprefix.h"
++
++
++#include <ctype.h>
++#include <float.h>
++#include <limits.h>
++#include <locale.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include "lua.h"
++
++#include "lauxlib.h"
++#include "lualib.h"
++
++
++/*
++** maximum number of captures that a pattern can do during
++** pattern-matching. This limit is arbitrary, but must fit in
++** an unsigned char.
++*/
++#if !defined(LUA_MAXCAPTURES)
++#define LUA_MAXCAPTURES		32
++#endif
++
++
++/* macro to 'unsign' a character */
++#define uchar(c)	((unsigned char)(c))
++
++
++/*
++** Some sizes are better limited to fit in 'int', but must also fit in
++** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
++*/
++#define MAX_SIZET	((size_t)(~(size_t)0))
++
++#define MAXSIZE  \
++	(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
++
++
++
++
++static int str_len (lua_State *L) {
++  size_t l;
++  luaL_checklstring(L, 1, &l);
++  lua_pushinteger(L, (lua_Integer)l);
++  return 1;
++}
++
++
++/* translate a relative string position: negative means back from end */
++static lua_Integer posrelat (lua_Integer pos, size_t len) {
++  if (pos >= 0) return pos;
++  else if (0u - (size_t)pos > len) return 0;
++  else return (lua_Integer)len + pos + 1;
++}
++
++
++static int str_sub (lua_State *L) {
++  size_t l;
++  const char *s = luaL_checklstring(L, 1, &l);
++  lua_Integer start = posrelat(luaL_checkinteger(L, 2), l);
++  lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l);
++  if (start < 1) start = 1;
++  if (end > (lua_Integer)l) end = l;
++  if (start <= end)
++    lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);
++  else lua_pushliteral(L, "");
++  return 1;
++}
++
++
++static int str_reverse (lua_State *L) {
++  size_t l, i;
++  luaL_Buffer b;
++  const char *s = luaL_checklstring(L, 1, &l);
++  char *p = luaL_buffinitsize(L, &b, l);
++  for (i = 0; i < l; i++)
++    p[i] = s[l - i - 1];
++  luaL_pushresultsize(&b, l);
++  return 1;
++}
++
++
++static int str_lower (lua_State *L) {
++  size_t l;
++  size_t i;
++  luaL_Buffer b;
++  const char *s = luaL_checklstring(L, 1, &l);
++  char *p = luaL_buffinitsize(L, &b, l);
++  for (i=0; i<l; i++)
++    p[i] = tolower(uchar(s[i]));
++  luaL_pushresultsize(&b, l);
++  return 1;
++}
++
++
++static int str_upper (lua_State *L) {
++  size_t l;
++  size_t i;
++  luaL_Buffer b;
++  const char *s = luaL_checklstring(L, 1, &l);
++  char *p = luaL_buffinitsize(L, &b, l);
++  for (i=0; i<l; i++)
++    p[i] = toupper(uchar(s[i]));
++  luaL_pushresultsize(&b, l);
++  return 1;
++}
++
++
++static int str_rep (lua_State *L) {
++  size_t l, lsep;
++  const char *s = luaL_checklstring(L, 1, &l);
++  lua_Integer n = luaL_checkinteger(L, 2);
++  const char *sep = luaL_optlstring(L, 3, "", &lsep);
++  if (n <= 0) lua_pushliteral(L, "");
++  else if (l + lsep < l || l + lsep > MAXSIZE / n)  /* may overflow? */
++    return luaL_error(L, "resulting string too large");
++  else {
++    size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
++    luaL_Buffer b;
++    char *p = luaL_buffinitsize(L, &b, totallen);
++    while (n-- > 1) {  /* first n-1 copies (followed by separator) */
++      memcpy(p, s, l * sizeof(char)); p += l;
++      if (lsep > 0) {  /* empty 'memcpy' is not that cheap */
++        memcpy(p, sep, lsep * sizeof(char));
++        p += lsep;
++      }
++    }
++    memcpy(p, s, l * sizeof(char));  /* last copy (not followed by separator) */
++    luaL_pushresultsize(&b, totallen);
++  }
++  return 1;
++}
++
++
++static int str_byte (lua_State *L) {
++  size_t l;
++  const char *s = luaL_checklstring(L, 1, &l);
++  lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l);
++  lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l);
++  int n, i;
++  if (posi < 1) posi = 1;
++  if (pose > (lua_Integer)l) pose = l;
++  if (posi > pose) return 0;  /* empty interval; return no values */
++  if (pose - posi >= INT_MAX)  /* arithmetic overflow? */
++    return luaL_error(L, "string slice too long");
++  n = (int)(pose -  posi) + 1;
++  luaL_checkstack(L, n, "string slice too long");
++  for (i=0; i<n; i++)
++    lua_pushinteger(L, uchar(s[posi+i-1]));
++  return n;
++}
++
++
++static int str_char (lua_State *L) {
++  int n = lua_gettop(L);  /* number of arguments */
++  int i;
++  luaL_Buffer b;
++  char *p = luaL_buffinitsize(L, &b, n);
++  for (i=1; i<=n; i++) {
++    lua_Integer c = luaL_checkinteger(L, i);
++    luaL_argcheck(L, uchar(c) == c, i, "value out of range");
++    p[i - 1] = uchar(c);
++  }
++  luaL_pushresultsize(&b, n);
++  return 1;
++}
++
++
++static int writer (lua_State *L, const void *b, size_t size, void *B) {
++  (void)L;
++  luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
++  return 0;
++}
++
++
++static int str_dump (lua_State *L) {
++  luaL_Buffer b;
++  int strip = lua_toboolean(L, 2);
++  luaL_checktype(L, 1, LUA_TFUNCTION);
++  lua_settop(L, 1);
++  luaL_buffinit(L,&b);
++  if (lua_dump(L, writer, &b, strip) != 0)
++    return luaL_error(L, "unable to dump given function");
++  luaL_pushresult(&b);
++  return 1;
++}
++
++
++
++/*
++** {======================================================
++** PATTERN MATCHING
++** =======================================================
++*/
++
++
++#define CAP_UNFINISHED	(-1)
++#define CAP_POSITION	(-2)
++
++
++typedef struct MatchState {
++  const char *src_init;  /* init of source string */
++  const char *src_end;  /* end ('\0') of source string */
++  const char *p_end;  /* end ('\0') of pattern */
++  lua_State *L;
++  int matchdepth;  /* control for recursive depth (to avoid C stack overflow) */
++  unsigned char level;  /* total number of captures (finished or unfinished) */
++  struct {
++    const char *init;
++    ptrdiff_t len;
++  } capture[LUA_MAXCAPTURES];
++} MatchState;
++
++
++/* recursive function */
++static const char *match (MatchState *ms, const char *s, const char *p);
++
++
++/* maximum recursion depth for 'match' */
++#if !defined(MAXCCALLS)
++#define MAXCCALLS	200
++#endif
++
++
++#define L_ESC		'%'
++#define SPECIALS	"^$*+?.([%-"
++
++
++static int check_capture (MatchState *ms, int l) {
++  l -= '1';
++  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
++    return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
++  return l;
++}
++
++
++static int capture_to_close (MatchState *ms) {
++  int level = ms->level;
++  for (level--; level>=0; level--)
++    if (ms->capture[level].len == CAP_UNFINISHED) return level;
++  return luaL_error(ms->L, "invalid pattern capture");
++}
++
++
++static const char *classend (MatchState *ms, const char *p) {
++  switch (*p++) {
++    case L_ESC: {
++      if (p == ms->p_end)
++        luaL_error(ms->L, "malformed pattern (ends with '%%')");
++      return p+1;
++    }
++    case '[': {
++      if (*p == '^') p++;
++      do {  /* look for a ']' */
++        if (p == ms->p_end)
++          luaL_error(ms->L, "malformed pattern (missing ']')");
++        if (*(p++) == L_ESC && p < ms->p_end)
++          p++;  /* skip escapes (e.g. '%]') */
++      } while (*p != ']');
++      return p+1;
++    }
++    default: {
++      return p;
++    }
++  }
++}
++
++
++static int match_class (int c, int cl) {
++  int res;
++  switch (tolower(cl)) {
++    case 'a' : res = isalpha(c); break;
++    case 'c' : res = iscntrl(c); break;
++    case 'd' : res = isdigit(c); break;
++    case 'g' : res = isgraph(c); break;
++    case 'l' : res = islower(c); break;
++    case 'p' : res = ispunct(c); break;
++    case 's' : res = isspace(c); break;
++    case 'u' : res = isupper(c); break;
++    case 'w' : res = isalnum(c); break;
++    case 'x' : res = isxdigit(c); break;
++    case 'z' : res = (c == 0); break;  /* deprecated option */
++    default: return (cl == c);
++  }
++  return (islower(cl) ? res : !res);
++}
++
++
++static int matchbracketclass (int c, const char *p, const char *ec) {
++  int sig = 1;
++  if (*(p+1) == '^') {
++    sig = 0;
++    p++;  /* skip the '^' */
++  }
++  while (++p < ec) {
++    if (*p == L_ESC) {
++      p++;
++      if (match_class(c, uchar(*p)))
++        return sig;
++    }
++    else if ((*(p+1) == '-') && (p+2 < ec)) {
++      p+=2;
++      if (uchar(*(p-2)) <= c && c <= uchar(*p))
++        return sig;
++    }
++    else if (uchar(*p) == c) return sig;
++  }
++  return !sig;
++}
++
++
++static int singlematch (MatchState *ms, const char *s, const char *p,
++                        const char *ep) {
++  if (s >= ms->src_end)
++    return 0;
++  else {
++    int c = uchar(*s);
++    switch (*p) {
++      case '.': return 1;  /* matches any char */
++      case L_ESC: return match_class(c, uchar(*(p+1)));
++      case '[': return matchbracketclass(c, p, ep-1);
++      default:  return (uchar(*p) == c);
++    }
++  }
++}
++
++
++static const char *matchbalance (MatchState *ms, const char *s,
++                                   const char *p) {
++  if (p >= ms->p_end - 1)
++    luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
++  if (*s != *p) return NULL;
++  else {
++    int b = *p;
++    int e = *(p+1);
++    int cont = 1;
++    while (++s < ms->src_end) {
++      if (*s == e) {
++        if (--cont == 0) return s+1;
++      }
++      else if (*s == b) cont++;
++    }
++  }
++  return NULL;  /* string ends out of balance */
++}
++
++
++static const char *max_expand (MatchState *ms, const char *s,
++                                 const char *p, const char *ep) {
++  ptrdiff_t i = 0;  /* counts maximum expand for item */
++  while (singlematch(ms, s + i, p, ep))
++    i++;
++  /* keeps trying to match with the maximum repetitions */
++  while (i>=0) {
++    const char *res = match(ms, (s+i), ep+1);
++    if (res) return res;
++    i--;  /* else didn't match; reduce 1 repetition to try again */
++  }
++  return NULL;
++}
++
++
++static const char *min_expand (MatchState *ms, const char *s,
++                                 const char *p, const char *ep) {
++  for (;;) {
++    const char *res = match(ms, s, ep+1);
++    if (res != NULL)
++      return res;
++    else if (singlematch(ms, s, p, ep))
++      s++;  /* try with one more repetition */
++    else return NULL;
++  }
++}
++
++
++static const char *start_capture (MatchState *ms, const char *s,
++                                    const char *p, int what) {
++  const char *res;
++  int level = ms->level;
++  if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
++  ms->capture[level].init = s;
++  ms->capture[level].len = what;
++  ms->level = level+1;
++  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
++    ms->level--;  /* undo capture */
++  return res;
++}
++
++
++static const char *end_capture (MatchState *ms, const char *s,
++                                  const char *p) {
++  int l = capture_to_close(ms);
++  const char *res;
++  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
++  if ((res = match(ms, s, p)) == NULL)  /* match failed? */
++    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
++  return res;
++}
++
++
++static const char *match_capture (MatchState *ms, const char *s, int l) {
++  size_t len;
++  l = check_capture(ms, l);
++  len = ms->capture[l].len;
++  if ((size_t)(ms->src_end-s) >= len &&
++      memcmp(ms->capture[l].init, s, len) == 0)
++    return s+len;
++  else return NULL;
++}
++
++
++static const char *match (MatchState *ms, const char *s, const char *p) {
++  if (ms->matchdepth-- == 0)
++    luaL_error(ms->L, "pattern too complex");
++  init: /* using goto's to optimize tail recursion */
++  if (p != ms->p_end) {  /* end of pattern? */
++    switch (*p) {
++      case '(': {  /* start capture */
++        if (*(p + 1) == ')')  /* position capture? */
++          s = start_capture(ms, s, p + 2, CAP_POSITION);
++        else
++          s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
++        break;
++      }
++      case ')': {  /* end capture */
++        s = end_capture(ms, s, p + 1);
++        break;
++      }
++      case '$': {
++        if ((p + 1) != ms->p_end)  /* is the '$' the last char in pattern? */
++          goto dflt;  /* no; go to default */
++        s = (s == ms->src_end) ? s : NULL;  /* check end of string */
++        break;
++      }
++      case L_ESC: {  /* escaped sequences not in the format class[*+?-]? */
++        switch (*(p + 1)) {
++          case 'b': {  /* balanced string? */
++            s = matchbalance(ms, s, p + 2);
++            if (s != NULL) {
++              p += 4; goto init;  /* return match(ms, s, p + 4); */
++            }  /* else fail (s == NULL) */
++            break;
++          }
++          case 'f': {  /* frontier? */
++            const char *ep; char previous;
++            p += 2;
++            if (*p != '[')
++              luaL_error(ms->L, "missing '[' after '%%f' in pattern");
++            ep = classend(ms, p);  /* points to what is next */
++            previous = (s == ms->src_init) ? '\0' : *(s - 1);
++            if (!matchbracketclass(uchar(previous), p, ep - 1) &&
++               matchbracketclass(uchar(*s), p, ep - 1)) {
++              p = ep; goto init;  /* return match(ms, s, ep); */
++            }
++            s = NULL;  /* match failed */
++            break;
++          }
++          case '0': case '1': case '2': case '3':
++          case '4': case '5': case '6': case '7':
++          case '8': case '9': {  /* capture results (%0-%9)? */
++            s = match_capture(ms, s, uchar(*(p + 1)));
++            if (s != NULL) {
++              p += 2; goto init;  /* return match(ms, s, p + 2) */
++            }
++            break;
++          }
++          default: goto dflt;
++        }
++        break;
++      }
++      default: dflt: {  /* pattern class plus optional suffix */
++        const char *ep = classend(ms, p);  /* points to optional suffix */
++        /* does not match at least once? */
++        if (!singlematch(ms, s, p, ep)) {
++          if (*ep == '*' || *ep == '?' || *ep == '-') {  /* accept empty? */
++            p = ep + 1; goto init;  /* return match(ms, s, ep + 1); */
++          }
++          else  /* '+' or no suffix */
++            s = NULL;  /* fail */
++        }
++        else {  /* matched once */
++          switch (*ep) {  /* handle optional suffix */
++            case '?': {  /* optional */
++              const char *res;
++              if ((res = match(ms, s + 1, ep + 1)) != NULL)
++                s = res;
++              else {
++                p = ep + 1; goto init;  /* else return match(ms, s, ep + 1); */
++              }
++              break;
++            }
++            case '+':  /* 1 or more repetitions */
++              s++;  /* 1 match already done */
++              /* FALLTHROUGH */
++            case '*':  /* 0 or more repetitions */
++              s = max_expand(ms, s, p, ep);
++              break;
++            case '-':  /* 0 or more repetitions (minimum) */
++              s = min_expand(ms, s, p, ep);
++              break;
++            default:  /* no suffix */
++              s++; p = ep; goto init;  /* return match(ms, s + 1, ep); */
++          }
++        }
++        break;
++      }
++    }
++  }
++  ms->matchdepth++;
++  return s;
++}
++
++
++
++static const char *lmemfind (const char *s1, size_t l1,
++                               const char *s2, size_t l2) {
++  if (l2 == 0) return s1;  /* empty strings are everywhere */
++  else if (l2 > l1) return NULL;  /* avoids a negative 'l1' */
++  else {
++    const char *init;  /* to search for a '*s2' inside 's1' */
++    l2--;  /* 1st char will be checked by 'memchr' */
++    l1 = l1-l2;  /* 's2' cannot be found after that */
++    while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
++      init++;   /* 1st char is already checked */
++      if (memcmp(init, s2+1, l2) == 0)
++        return init-1;
++      else {  /* correct 'l1' and 's1' to try again */
++        l1 -= init-s1;
++        s1 = init;
++      }
++    }
++    return NULL;  /* not found */
++  }
++}
++
++
++static void push_onecapture (MatchState *ms, int i, const char *s,
++                                                    const char *e) {
++  if (i >= ms->level) {
++    if (i == 0)  /* ms->level == 0, too */
++      lua_pushlstring(ms->L, s, e - s);  /* add whole match */
++    else
++      luaL_error(ms->L, "invalid capture index %%%d", i + 1);
++  }
++  else {
++    ptrdiff_t l = ms->capture[i].len;
++    if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
++    if (l == CAP_POSITION)
++      lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
++    else
++      lua_pushlstring(ms->L, ms->capture[i].init, l);
++  }
++}
++
++
++static int push_captures (MatchState *ms, const char *s, const char *e) {
++  int i;
++  int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
++  luaL_checkstack(ms->L, nlevels, "too many captures");
++  for (i = 0; i < nlevels; i++)
++    push_onecapture(ms, i, s, e);
++  return nlevels;  /* number of strings pushed */
++}
++
++
++/* check whether pattern has no special characters */
++static int nospecials (const char *p, size_t l) {
++  size_t upto = 0;
++  do {
++    if (strpbrk(p + upto, SPECIALS))
++      return 0;  /* pattern has a special character */
++    upto += strlen(p + upto) + 1;  /* may have more after \0 */
++  } while (upto <= l);
++  return 1;  /* no special chars found */
++}
++
++
++static void prepstate (MatchState *ms, lua_State *L,
++                       const char *s, size_t ls, const char *p, size_t lp) {
++  ms->L = L;
++  ms->matchdepth = MAXCCALLS;
++  ms->src_init = s;
++  ms->src_end = s + ls;
++  ms->p_end = p + lp;
++}
++
++
++static void reprepstate (MatchState *ms) {
++  ms->level = 0;
++  lua_assert(ms->matchdepth == MAXCCALLS);
++}
++
++
++static int str_find_aux (lua_State *L, int find) {
++  size_t ls, lp;
++  const char *s = luaL_checklstring(L, 1, &ls);
++  const char *p = luaL_checklstring(L, 2, &lp);
++  lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls);
++  if (init < 1) init = 1;
++  else if (init > (lua_Integer)ls + 1) {  /* start after string's end? */
++    lua_pushnil(L);  /* cannot find anything */
++    return 1;
++  }
++  /* explicit request or no special characters? */
++  if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {
++    /* do a plain search */
++    const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
++    if (s2) {
++      lua_pushinteger(L, (s2 - s) + 1);
++      lua_pushinteger(L, (s2 - s) + lp);
++      return 2;
++    }
++  }
++  else {
++    MatchState ms;
++    const char *s1 = s + init - 1;
++    int anchor = (*p == '^');
++    if (anchor) {
++      p++; lp--;  /* skip anchor character */
++    }
++    prepstate(&ms, L, s, ls, p, lp);
++    do {
++      const char *res;
++      reprepstate(&ms);
++      if ((res=match(&ms, s1, p)) != NULL) {
++        if (find) {
++          lua_pushinteger(L, (s1 - s) + 1);  /* start */
++          lua_pushinteger(L, res - s);   /* end */
++          return push_captures(&ms, NULL, 0) + 2;
++        }
++        else
++          return push_captures(&ms, s1, res);
++      }
++    } while (s1++ < ms.src_end && !anchor);
++  }
++  lua_pushnil(L);  /* not found */
++  return 1;
++}
++
++
++static int str_find (lua_State *L) {
++  return str_find_aux(L, 1);
++}
++
++
++static int str_match (lua_State *L) {
++  return str_find_aux(L, 0);
++}
++
++
++/* state for 'gmatch' */
++typedef struct GMatchState {
++  const char *src;  /* current position */
++  const char *p;  /* pattern */
++  const char *lastmatch;  /* end of last match */
++  MatchState ms;  /* match state */
++} GMatchState;
++
++
++static int gmatch_aux (lua_State *L) {
++  GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
++  const char *src;
++  gm->ms.L = L;
++  for (src = gm->src; src <= gm->ms.src_end; src++) {
++    const char *e;
++    reprepstate(&gm->ms);
++    if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
++      gm->src = gm->lastmatch = e;
++      return push_captures(&gm->ms, src, e);
++    }
++  }
++  return 0;  /* not found */
++}
++
++
++static int gmatch (lua_State *L) {
++  size_t ls, lp;
++  const char *s = luaL_checklstring(L, 1, &ls);
++  const char *p = luaL_checklstring(L, 2, &lp);
++  GMatchState *gm;
++  lua_settop(L, 2);  /* keep them on closure to avoid being collected */
++  gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
++  prepstate(&gm->ms, L, s, ls, p, lp);
++  gm->src = s; gm->p = p; gm->lastmatch = NULL;
++  lua_pushcclosure(L, gmatch_aux, 3);
++  return 1;
++}
++
++
++static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
++                                                   const char *e) {
++  size_t l, i;
++  lua_State *L = ms->L;
++  const char *news = lua_tolstring(L, 3, &l);
++  for (i = 0; i < l; i++) {
++    if (news[i] != L_ESC)
++      luaL_addchar(b, news[i]);
++    else {
++      i++;  /* skip ESC */
++      if (!isdigit(uchar(news[i]))) {
++        if (news[i] != L_ESC)
++          luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
++        luaL_addchar(b, news[i]);
++      }
++      else if (news[i] == '0')
++          luaL_addlstring(b, s, e - s);
++      else {
++        push_onecapture(ms, news[i] - '1', s, e);
++        luaL_tolstring(L, -1, NULL);  /* if number, convert it to string */
++        lua_remove(L, -2);  /* remove original value */
++        luaL_addvalue(b);  /* add capture to accumulated result */
++      }
++    }
++  }
++}
++
++
++static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
++                                       const char *e, int tr) {
++  lua_State *L = ms->L;
++  switch (tr) {
++    case LUA_TFUNCTION: {
++      int n;
++      lua_pushvalue(L, 3);
++      n = push_captures(ms, s, e);
++      lua_call(L, n, 1);
++      break;
++    }
++    case LUA_TTABLE: {
++      push_onecapture(ms, 0, s, e);
++      lua_gettable(L, 3);
++      break;
++    }
++    default: {  /* LUA_TNUMBER or LUA_TSTRING */
++      add_s(ms, b, s, e);
++      return;
++    }
++  }
++  if (!lua_toboolean(L, -1)) {  /* nil or false? */
++    lua_pop(L, 1);
++    lua_pushlstring(L, s, e - s);  /* keep original text */
++  }
++  else if (!lua_isstring(L, -1))
++    luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
++  luaL_addvalue(b);  /* add result to accumulator */
++}
++
++
++static int str_gsub (lua_State *L) {
++  size_t srcl, lp;
++  const char *src = luaL_checklstring(L, 1, &srcl);  /* subject */
++  const char *p = luaL_checklstring(L, 2, &lp);  /* pattern */
++  const char *lastmatch = NULL;  /* end of last match */
++  int tr = lua_type(L, 3);  /* replacement type */
++  lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);  /* max replacements */
++  int anchor = (*p == '^');
++  lua_Integer n = 0;  /* replacement count */
++  MatchState ms;
++  luaL_Buffer b;
++  luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
++                   tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
++                      "string/function/table expected");
++  luaL_buffinit(L, &b);
++  if (anchor) {
++    p++; lp--;  /* skip anchor character */
++  }
++  prepstate(&ms, L, src, srcl, p, lp);
++  while (n < max_s) {
++    const char *e;
++    reprepstate(&ms);  /* (re)prepare state for new match */
++    if ((e = match(&ms, src, p)) != NULL && e != lastmatch) {  /* match? */
++      n++;
++      add_value(&ms, &b, src, e, tr);  /* add replacement to buffer */
++      src = lastmatch = e;
++    }
++    else if (src < ms.src_end)  /* otherwise, skip one character */
++      luaL_addchar(&b, *src++);
++    else break;  /* end of subject */
++    if (anchor) break;
++  }
++  luaL_addlstring(&b, src, ms.src_end-src);
++  luaL_pushresult(&b);
++  lua_pushinteger(L, n);  /* number of substitutions */
++  return 2;
++}
++
++/* }====================================================== */
++
++
++
++/*
++** {======================================================
++** STRING FORMAT
++** =======================================================
++*/
++
++#if !defined(lua_number2strx)	/* { */
++
++/*
++** Hexadecimal floating-point formatter
++*/
++
++#include <math.h>
++
++#define SIZELENMOD	(sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
++
++
++/*
++** Number of bits that goes into the first digit. It can be any value
++** between 1 and 4; the following definition tries to align the number
++** to nibble boundaries by making what is left after that first digit a
++** multiple of 4.
++*/
++#define L_NBFD		((l_mathlim(MANT_DIG) - 1)%4 + 1)
++
++
++/*
++** Add integer part of 'x' to buffer and return new 'x'
++*/
++static lua_Number adddigit (char *buff, int n, lua_Number x) {
++  lua_Number dd = l_mathop(floor)(x);  /* get integer part from 'x' */
++  int d = (int)dd;
++  buff[n] = (d < 10 ? d + '0' : d - 10 + 'a');  /* add to buffer */
++  return x - dd;  /* return what is left */
++}
++
++
++static int num2straux (char *buff, int sz, lua_Number x) {
++  /* if 'inf' or 'NaN', format it like '%g' */
++  if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
++    return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
++  else if (x == 0) {  /* can be -0... */
++    /* create "0" or "-0" followed by exponent */
++    return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x);
++  }
++  else {
++    int e;
++    lua_Number m = l_mathop(frexp)(x, &e);  /* 'x' fraction and exponent */
++    int n = 0;  /* character count */
++    if (m < 0) {  /* is number negative? */
++      buff[n++] = '-';  /* add signal */
++      m = -m;  /* make it positive */
++    }
++    buff[n++] = '0'; buff[n++] = 'x';  /* add "0x" */
++    m = adddigit(buff, n++, m * (1 << L_NBFD));  /* add first digit */
++    e -= L_NBFD;  /* this digit goes before the radix point */
++    if (m > 0) {  /* more digits? */
++      buff[n++] = lua_getlocaledecpoint();  /* add radix point */
++      do {  /* add as many digits as needed */
++        m = adddigit(buff, n++, m * 16);
++      } while (m > 0);
++    }
++    n += l_sprintf(buff + n, sz - n, "p%+d", e);  /* add exponent */
++    lua_assert(n < sz);
++    return n;
++  }
++}
++
++
++static int lua_number2strx (lua_State *L, char *buff, int sz,
++                            const char *fmt, lua_Number x) {
++  int n = num2straux(buff, sz, x);
++  if (fmt[SIZELENMOD] == 'A') {
++    int i;
++    for (i = 0; i < n; i++)
++      buff[i] = toupper(uchar(buff[i]));
++  }
++  else if (fmt[SIZELENMOD] != 'a')
++    luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
++  return n;
++}
++
++#endif				/* } */
++
++
++/*
++** Maximum size of each formatted item. This maximum size is produced
++** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
++** and '\0') + number of decimal digits to represent maxfloat (which
++** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
++** expenses", such as locale-dependent stuff)
++*/
++#define MAX_ITEM        (120 + l_mathlim(MAX_10_EXP))
++
++
++/* valid flags in a format specification */
++#define FLAGS	"-+ #0"
++
++/*
++** maximum size of each format specification (such as "%-099.99d")
++*/
++#define MAX_FORMAT	32
++
++
++static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
++  luaL_addchar(b, '"');
++  while (len--) {
++    if (*s == '"' || *s == '\\' || *s == '\n') {
++      luaL_addchar(b, '\\');
++      luaL_addchar(b, *s);
++    }
++    else if (iscntrl(uchar(*s))) {
++      char buff[10];
++      if (!isdigit(uchar(*(s+1))))
++        l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
++      else
++        l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
++      luaL_addstring(b, buff);
++    }
++    else
++      luaL_addchar(b, *s);
++    s++;
++  }
++  luaL_addchar(b, '"');
++}
++
++
++/*
++** Ensures the 'buff' string uses a dot as the radix character.
++*/
++static void checkdp (char *buff, int nb) {
++  if (memchr(buff, '.', nb) == NULL) {  /* no dot? */
++    char point = lua_getlocaledecpoint();  /* try locale point */
++    char *ppoint = (char *)memchr(buff, point, nb);
++    if (ppoint) *ppoint = '.';  /* change it to a dot */
++  }
++}
++
++
++static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
++  switch (lua_type(L, arg)) {
++    case LUA_TSTRING: {
++      size_t len;
++      const char *s = lua_tolstring(L, arg, &len);
++      addquoted(b, s, len);
++      break;
++    }
++    case LUA_TNUMBER: {
++      char *buff = luaL_prepbuffsize(b, MAX_ITEM);
++      int nb;
++      if (!lua_isinteger(L, arg)) {  /* float? */
++        lua_Number n = lua_tonumber(L, arg);  /* write as hexa ('%a') */
++        nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
++        checkdp(buff, nb);  /* ensure it uses a dot */
++      }
++      else {  /* integers */
++        lua_Integer n = lua_tointeger(L, arg);
++        const char *format = (n == LUA_MININTEGER)  /* corner case? */
++                           ? "0x%" LUA_INTEGER_FRMLEN "x"  /* use hexa */
++                           : LUA_INTEGER_FMT;  /* else use default format */
++        nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
++      }
++      luaL_addsize(b, nb);
++      break;
++    }
++    case LUA_TNIL: case LUA_TBOOLEAN: {
++      luaL_tolstring(L, arg, NULL);
++      luaL_addvalue(b);
++      break;
++    }
++    default: {
++      luaL_argerror(L, arg, "value has no literal form");
++    }
++  }
++}
++
++
++static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
++  const char *p = strfrmt;
++  while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
++  if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))
++    luaL_error(L, "invalid format (repeated flags)");
++  if (isdigit(uchar(*p))) p++;  /* skip width */
++  if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
++  if (*p == '.') {
++    p++;
++    if (isdigit(uchar(*p))) p++;  /* skip precision */
++    if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
++  }
++  if (isdigit(uchar(*p)))
++    luaL_error(L, "invalid format (width or precision too long)");
++  *(form++) = '%';
++  memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
++  form += (p - strfrmt) + 1;
++  *form = '\0';
++  return p;
++}
++
++
++/*
++** add length modifier into formats
++*/
++static void addlenmod (char *form, const char *lenmod) {
++  size_t l = strlen(form);
++  size_t lm = strlen(lenmod);
++  char spec = form[l - 1];
++  strcpy(form + l - 1, lenmod);
++  form[l + lm - 1] = spec;
++  form[l + lm] = '\0';
++}
++
++
++static int str_format (lua_State *L) {
++  int top = lua_gettop(L);
++  int arg = 1;
++  size_t sfl;
++  const char *strfrmt = luaL_checklstring(L, arg, &sfl);
++  const char *strfrmt_end = strfrmt+sfl;
++  luaL_Buffer b;
++  luaL_buffinit(L, &b);
++  while (strfrmt < strfrmt_end) {
++    if (*strfrmt != L_ESC)
++      luaL_addchar(&b, *strfrmt++);
++    else if (*++strfrmt == L_ESC)
++      luaL_addchar(&b, *strfrmt++);  /* %% */
++    else { /* format item */
++      char form[MAX_FORMAT];  /* to store the format ('%...') */
++      char *buff = luaL_prepbuffsize(&b, MAX_ITEM);  /* to put formatted item */
++      int nb = 0;  /* number of bytes in added item */
++      if (++arg > top)
++        luaL_argerror(L, arg, "no value");
++      strfrmt = scanformat(L, strfrmt, form);
++      switch (*strfrmt++) {
++        case 'c': {
++          nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
++          break;
++        }
++        case 'd': case 'i':
++        case 'o': case 'u': case 'x': case 'X': {
++          lua_Integer n = luaL_checkinteger(L, arg);
++          addlenmod(form, LUA_INTEGER_FRMLEN);
++          nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
++          break;
++        }
++        case 'a': case 'A':
++          addlenmod(form, LUA_NUMBER_FRMLEN);
++          nb = lua_number2strx(L, buff, MAX_ITEM, form,
++                                  luaL_checknumber(L, arg));
++          break;
++        case 'e': case 'E': case 'f':
++        case 'g': case 'G': {
++          lua_Number n = luaL_checknumber(L, arg);
++          addlenmod(form, LUA_NUMBER_FRMLEN);
++          nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
++          break;
++        }
++        case 'q': {
++          addliteral(L, &b, arg);
++          break;
++        }
++        case 's': {
++          size_t l;
++          const char *s = luaL_tolstring(L, arg, &l);
++          if (form[2] == '\0')  /* no modifiers? */
++            luaL_addvalue(&b);  /* keep entire string */
++          else {
++            luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
++            if (!strchr(form, '.') && l >= 100) {
++              /* no precision and string is too long to be formatted */
++              luaL_addvalue(&b);  /* keep entire string */
++            }
++            else {  /* format the string into 'buff' */
++              nb = l_sprintf(buff, MAX_ITEM, form, s);
++              lua_pop(L, 1);  /* remove result from 'luaL_tolstring' */
++            }
++          }
++          break;
++        }
++        default: {  /* also treat cases 'pnLlh' */
++          return luaL_error(L, "invalid option '%%%c' to 'format'",
++                               *(strfrmt - 1));
++        }
++      }
++      lua_assert(nb < MAX_ITEM);
++      luaL_addsize(&b, nb);
++    }
++  }
++  luaL_pushresult(&b);
++  return 1;
++}
++
++/* }====================================================== */
++
++
++/*
++** {======================================================
++** PACK/UNPACK
++** =======================================================
++*/
++
++
++/* value used for padding */
++#if !defined(LUAL_PACKPADBYTE)
++#define LUAL_PACKPADBYTE		0x00
++#endif
++
++/* maximum size for the binary representation of an integer */
++#define MAXINTSIZE	16
++
++/* number of bits in a character */
++#define NB	CHAR_BIT
++
++/* mask for one character (NB 1's) */
++#define MC	((1 << NB) - 1)
++
++/* size of a lua_Integer */
++#define SZINT	((int)sizeof(lua_Integer))
++
++
++/* dummy union to get native endianness */
++static const union {
++  int dummy;
++  char little;  /* true iff machine is little endian */
++} nativeendian = {1};
++
++
++/* dummy structure to get native alignment requirements */
++struct cD {
++  char c;
++  union { double d; void *p; lua_Integer i; lua_Number n; } u;
++};
++
++#define MAXALIGN	(offsetof(struct cD, u))
++
++
++/*
++** Union for serializing floats
++*/
++typedef union Ftypes {
++  float f;
++  double d;
++  lua_Number n;
++  char buff[5 * sizeof(lua_Number)];  /* enough for any float type */
++} Ftypes;
++
++
++/*
++** information to pack/unpack stuff
++*/
++typedef struct Header {
++  lua_State *L;
++  int islittle;
++  int maxalign;
++} Header;
++
++
++/*
++** options for pack/unpack
++*/
++typedef enum KOption {
++  Kint,		/* signed integers */
++  Kuint,	/* unsigned integers */
++  Kfloat,	/* floating-point numbers */
++  Kchar,	/* fixed-length strings */
++  Kstring,	/* strings with prefixed length */
++  Kzstr,	/* zero-terminated strings */
++  Kpadding,	/* padding */
++  Kpaddalign,	/* padding for alignment */
++  Knop		/* no-op (configuration or spaces) */
++} KOption;
++
++
++/*
++** Read an integer numeral from string 'fmt' or return 'df' if
++** there is no numeral
++*/
++static int digit (int c) { return '0' <= c && c <= '9'; }
++
++static int getnum (const char **fmt, int df) {
++  if (!digit(**fmt))  /* no number? */
++    return df;  /* return default value */
++  else {
++    int a = 0;
++    do {
++      a = a*10 + (*((*fmt)++) - '0');
++    } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
++    return a;
++  }
++}
++
++
++/*
++** Read an integer numeral and raises an error if it is larger
++** than the maximum size for integers.
++*/
++static int getnumlimit (Header *h, const char **fmt, int df) {
++  int sz = getnum(fmt, df);
++  if (sz > MAXINTSIZE || sz <= 0)
++    luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
++                     sz, MAXINTSIZE);
++  return sz;
++}
++
++
++/*
++** Initialize Header
++*/
++static void initheader (lua_State *L, Header *h) {
++  h->L = L;
++  h->islittle = nativeendian.little;
++  h->maxalign = 1;
++}
++
++
++/*
++** Read and classify next option. 'size' is filled with option's size.
++*/
++static KOption getoption (Header *h, const char **fmt, int *size) {
++  int opt = *((*fmt)++);
++  *size = 0;  /* default */
++  switch (opt) {
++    case 'b': *size = sizeof(char); return Kint;
++    case 'B': *size = sizeof(char); return Kuint;
++    case 'h': *size = sizeof(short); return Kint;
++    case 'H': *size = sizeof(short); return Kuint;
++    case 'l': *size = sizeof(long); return Kint;
++    case 'L': *size = sizeof(long); return Kuint;
++    case 'j': *size = sizeof(lua_Integer); return Kint;
++    case 'J': *size = sizeof(lua_Integer); return Kuint;
++    case 'T': *size = sizeof(size_t); return Kuint;
++    case 'f': *size = sizeof(float); return Kfloat;
++    case 'd': *size = sizeof(double); return Kfloat;
++    case 'n': *size = sizeof(lua_Number); return Kfloat;
++    case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
++    case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
++    case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
++    case 'c':
++      *size = getnum(fmt, -1);
++      if (*size == -1)
++        luaL_error(h->L, "missing size for format option 'c'");
++      return Kchar;
++    case 'z': return Kzstr;
++    case 'x': *size = 1; return Kpadding;
++    case 'X': return Kpaddalign;
++    case ' ': break;
++    case '<': h->islittle = 1; break;
++    case '>': h->islittle = 0; break;
++    case '=': h->islittle = nativeendian.little; break;
++    case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
++    default: luaL_error(h->L, "invalid format option '%c'", opt);
++  }
++  return Knop;
++}
++
++
++/*
++** Read, classify, and fill other details about the next option.
++** 'psize' is filled with option's size, 'notoalign' with its
++** alignment requirements.
++** Local variable 'size' gets the size to be aligned. (Kpadal option
++** always gets its full alignment, other options are limited by
++** the maximum alignment ('maxalign'). Kchar option needs no alignment
++** despite its size.
++*/
++static KOption getdetails (Header *h, size_t totalsize,
++                           const char **fmt, int *psize, int *ntoalign) {
++  KOption opt = getoption(h, fmt, psize);
++  int align = *psize;  /* usually, alignment follows size */
++  if (opt == Kpaddalign) {  /* 'X' gets alignment from following option */
++    if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
++      luaL_argerror(h->L, 1, "invalid next option for option 'X'");
++  }
++  if (align <= 1 || opt == Kchar)  /* need no alignment? */
++    *ntoalign = 0;
++  else {
++    if (align > h->maxalign)  /* enforce maximum alignment */
++      align = h->maxalign;
++    if ((align & (align - 1)) != 0)  /* is 'align' not a power of 2? */
++      luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
++    *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
++  }
++  return opt;
++}
++
++
++/*
++** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
++** The final 'if' handles the case when 'size' is larger than
++** the size of a Lua integer, correcting the extra sign-extension
++** bytes if necessary (by default they would be zeros).
++*/
++static void packint (luaL_Buffer *b, lua_Unsigned n,
++                     int islittle, int size, int neg) {
++  char *buff = luaL_prepbuffsize(b, size);
++  int i;
++  buff[islittle ? 0 : size - 1] = (char)(n & MC);  /* first byte */
++  for (i = 1; i < size; i++) {
++    n >>= NB;
++    buff[islittle ? i : size - 1 - i] = (char)(n & MC);
++  }
++  if (neg && size > SZINT) {  /* negative number need sign extension? */
++    for (i = SZINT; i < size; i++)  /* correct extra bytes */
++      buff[islittle ? i : size - 1 - i] = (char)MC;
++  }
++  luaL_addsize(b, size);  /* add result to buffer */
++}
++
++
++/*
++** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
++** given 'islittle' is different from native endianness.
++*/
++static void copywithendian (volatile char *dest, volatile const char *src,
++                            int size, int islittle) {
++  if (islittle == nativeendian.little) {
++    while (size-- != 0)
++      *(dest++) = *(src++);
++  }
++  else {
++    dest += size - 1;
++    while (size-- != 0)
++      *(dest--) = *(src++);
++  }
++}
++
++
++static int str_pack (lua_State *L) {
++  luaL_Buffer b;
++  Header h;
++  const char *fmt = luaL_checkstring(L, 1);  /* format string */
++  int arg = 1;  /* current argument to pack */
++  size_t totalsize = 0;  /* accumulate total size of result */
++  initheader(L, &h);
++  lua_pushnil(L);  /* mark to separate arguments from string buffer */
++  luaL_buffinit(L, &b);
++  while (*fmt != '\0') {
++    int size, ntoalign;
++    KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
++    totalsize += ntoalign + size;
++    while (ntoalign-- > 0)
++     luaL_addchar(&b, LUAL_PACKPADBYTE);  /* fill alignment */
++    arg++;
++    switch (opt) {
++      case Kint: {  /* signed integers */
++        lua_Integer n = luaL_checkinteger(L, arg);
++        if (size < SZINT) {  /* need overflow check? */
++          lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
++          luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
++        }
++        packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
++        break;
++      }
++      case Kuint: {  /* unsigned integers */
++        lua_Integer n = luaL_checkinteger(L, arg);
++        if (size < SZINT)  /* need overflow check? */
++          luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
++                           arg, "unsigned overflow");
++        packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
++        break;
++      }
++      case Kfloat: {  /* floating-point options */
++        volatile Ftypes u;
++        char *buff = luaL_prepbuffsize(&b, size);
++        lua_Number n = luaL_checknumber(L, arg);  /* get argument */
++        if (size == sizeof(u.f)) u.f = (float)n;  /* copy it into 'u' */
++        else if (size == sizeof(u.d)) u.d = (double)n;
++        else u.n = n;
++        /* move 'u' to final result, correcting endianness if needed */
++        copywithendian(buff, u.buff, size, h.islittle);
++        luaL_addsize(&b, size);
++        break;
++      }
++      case Kchar: {  /* fixed-size string */
++        size_t len;
++        const char *s = luaL_checklstring(L, arg, &len);
++        luaL_argcheck(L, len <= (size_t)size, arg,
++                         "string longer than given size");
++        luaL_addlstring(&b, s, len);  /* add string */
++        while (len++ < (size_t)size)  /* pad extra space */
++          luaL_addchar(&b, LUAL_PACKPADBYTE);
++        break;
++      }
++      case Kstring: {  /* strings with length count */
++        size_t len;
++        const char *s = luaL_checklstring(L, arg, &len);
++        luaL_argcheck(L, size >= (int)sizeof(size_t) ||
++                         len < ((size_t)1 << (size * NB)),
++                         arg, "string length does not fit in given size");
++        packint(&b, (lua_Unsigned)len, h.islittle, size, 0);  /* pack length */
++        luaL_addlstring(&b, s, len);
++        totalsize += len;
++        break;
++      }
++      case Kzstr: {  /* zero-terminated string */
++        size_t len;
++        const char *s = luaL_checklstring(L, arg, &len);
++        luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
++        luaL_addlstring(&b, s, len);
++        luaL_addchar(&b, '\0');  /* add zero at the end */
++        totalsize += len + 1;
++        break;
++      }
++      case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE);  /* FALLTHROUGH */
++      case Kpaddalign: case Knop:
++        arg--;  /* undo increment */
++        break;
++    }
++  }
++  luaL_pushresult(&b);
++  return 1;
++}
++
++
++static int str_packsize (lua_State *L) {
++  Header h;
++  const char *fmt = luaL_checkstring(L, 1);  /* format string */
++  size_t totalsize = 0;  /* accumulate total size of result */
++  initheader(L, &h);
++  while (*fmt != '\0') {
++    int size, ntoalign;
++    KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
++    size += ntoalign;  /* total space used by option */
++    luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
++                     "format result too large");
++    totalsize += size;
++    switch (opt) {
++      case Kstring:  /* strings with length count */
++      case Kzstr:    /* zero-terminated string */
++        luaL_argerror(L, 1, "variable-length format");
++        /* call never return, but to avoid warnings: *//* FALLTHROUGH */
++      default:  break;
++    }
++  }
++  lua_pushinteger(L, (lua_Integer)totalsize);
++  return 1;
++}
++
++
++/*
++** Unpack an integer with 'size' bytes and 'islittle' endianness.
++** If size is smaller than the size of a Lua integer and integer
++** is signed, must do sign extension (propagating the sign to the
++** higher bits); if size is larger than the size of a Lua integer,
++** it must check the unread bytes to see whether they do not cause an
++** overflow.
++*/
++static lua_Integer unpackint (lua_State *L, const char *str,
++                              int islittle, int size, int issigned) {
++  lua_Unsigned res = 0;
++  int i;
++  int limit = (size  <= SZINT) ? size : SZINT;
++  for (i = limit - 1; i >= 0; i--) {
++    res <<= NB;
++    res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i];
++  }
++  if (size < SZINT) {  /* real size smaller than lua_Integer? */
++    if (issigned) {  /* needs sign extension? */
++      lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);
++      res = ((res ^ mask) - mask);  /* do sign extension */
++    }
++  }
++  else if (size > SZINT) {  /* must check unread bytes */
++    int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
++    for (i = limit; i < size; i++) {
++      if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
++        luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
++    }
++  }
++  return (lua_Integer)res;
++}
++
++
++static int str_unpack (lua_State *L) {
++  Header h;
++  const char *fmt = luaL_checkstring(L, 1);
++  size_t ld;
++  const char *data = luaL_checklstring(L, 2, &ld);
++  size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1;
++  int n = 0;  /* number of results */
++  luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
++  initheader(L, &h);
++  while (*fmt != '\0') {
++    int size, ntoalign;
++    KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
++    if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)
++      luaL_argerror(L, 2, "data string too short");
++    pos += ntoalign;  /* skip alignment */
++    /* stack space for item + next position */
++    luaL_checkstack(L, 2, "too many results");
++    n++;
++    switch (opt) {
++      case Kint:
++      case Kuint: {
++        lua_Integer res = unpackint(L, data + pos, h.islittle, size,
++                                       (opt == Kint));
++        lua_pushinteger(L, res);
++        break;
++      }
++      case Kfloat: {
++        volatile Ftypes u;
++        lua_Number num;
++        copywithendian(u.buff, data + pos, size, h.islittle);
++        if (size == sizeof(u.f)) num = (lua_Number)u.f;
++        else if (size == sizeof(u.d)) num = (lua_Number)u.d;
++        else num = u.n;
++        lua_pushnumber(L, num);
++        break;
++      }
++      case Kchar: {
++        lua_pushlstring(L, data + pos, size);
++        break;
++      }
++      case Kstring: {
++        size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
++        luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short");
++        lua_pushlstring(L, data + pos + size, len);
++        pos += len;  /* skip string */
++        break;
++      }
++      case Kzstr: {
++        size_t len = (int)strlen(data + pos);
++        lua_pushlstring(L, data + pos, len);
++        pos += len + 1;  /* skip string plus final '\0' */
++        break;
++      }
++      case Kpaddalign: case Kpadding: case Knop:
++        n--;  /* undo increment */
++        break;
++    }
++    pos += size;
++  }
++  lua_pushinteger(L, pos + 1);  /* next position */
++  return n + 1;
++}
++
++/* }====================================================== */
++
++
++static const luaL_Reg strlib[] = {
++  {"byte", str_byte},
++  {"char", str_char},
++  {"dump", str_dump},
++  {"find", str_find},
++  {"format", str_format},
++  {"gmatch", gmatch},
++  {"gsub", str_gsub},
++  {"len", str_len},
++  {"lower", str_lower},
++  {"match", str_match},
++  {"rep", str_rep},
++  {"reverse", str_reverse},
++  {"sub", str_sub},
++  {"upper", str_upper},
++  {"pack", str_pack},
++  {"packsize", str_packsize},
++  {"unpack", str_unpack},
++  {NULL, NULL}
++};
++
++
++static void createmetatable (lua_State *L) {
++  lua_createtable(L, 0, 1);  /* table to be metatable for strings */
++  lua_pushliteral(L, "");  /* dummy string */
++  lua_pushvalue(L, -2);  /* copy table */
++  lua_setmetatable(L, -2);  /* set table as metatable for strings */
++  lua_pop(L, 1);  /* pop dummy string */
++  lua_pushvalue(L, -2);  /* get string library */
++  lua_setfield(L, -2, "__index");  /* metatable.__index = string */
++  lua_pop(L, 1);  /* pop metatable */
++}
++
++
++/*
++** Open string library
++*/
++LUAMOD_API int luaopen_string (lua_State *L) {
++  luaL_newlib(L, strlib);
++  createmetatable(L);
++  return 1;
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/ltablib.c luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/ltablib.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/ltablib.c	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/ltablib.c	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,450 @@
++/*
++** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
++** Library for Table Manipulation
++** See Copyright Notice in lua.h
++*/
++
++#define ltablib_c
++#define LUA_LIB
++
++#include "lprefix.h"
++
++
++#include <limits.h>
++#include <stddef.h>
++#include <string.h>
++
++#include "lua.h"
++
++#include "lauxlib.h"
++#include "lualib.h"
++
++
++/*
++** Operations that an object must define to mimic a table
++** (some functions only need some of them)
++*/
++#define TAB_R	1			/* read */
++#define TAB_W	2			/* write */
++#define TAB_L	4			/* length */
++#define TAB_RW	(TAB_R | TAB_W)		/* read/write */
++
++
++#define aux_getn(L,n,w)	(checktab(L, n, (w) | TAB_L), luaL_len(L, n))
++
++
++static int checkfield (lua_State *L, const char *key, int n) {
++  lua_pushstring(L, key);
++  return (lua_rawget(L, -n) != LUA_TNIL);
++}
++
++
++/*
++** Check that 'arg' either is a table or can behave like one (that is,
++** has a metatable with the required metamethods)
++*/
++static void checktab (lua_State *L, int arg, int what) {
++  if (lua_type(L, arg) != LUA_TTABLE) {  /* is it not a table? */
++    int n = 1;  /* number of elements to pop */
++    if (lua_getmetatable(L, arg) &&  /* must have metatable */
++        (!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
++        (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
++        (!(what & TAB_L) || checkfield(L, "__len", ++n))) {
++      lua_pop(L, n);  /* pop metatable and tested metamethods */
++    }
++    else
++      luaL_checktype(L, arg, LUA_TTABLE);  /* force an error */
++  }
++}
++
++
++#if defined(LUA_COMPAT_MAXN)
++static int maxn (lua_State *L) {
++  lua_Number max = 0;
++  luaL_checktype(L, 1, LUA_TTABLE);
++  lua_pushnil(L);  /* first key */
++  while (lua_next(L, 1)) {
++    lua_pop(L, 1);  /* remove value */
++    if (lua_type(L, -1) == LUA_TNUMBER) {
++      lua_Number v = lua_tonumber(L, -1);
++      if (v > max) max = v;
++    }
++  }
++  lua_pushnumber(L, max);
++  return 1;
++}
++#endif
++
++
++static int tinsert (lua_State *L) {
++  lua_Integer e = aux_getn(L, 1, TAB_RW) + 1;  /* first empty element */
++  lua_Integer pos;  /* where to insert new element */
++  switch (lua_gettop(L)) {
++    case 2: {  /* called with only 2 arguments */
++      pos = e;  /* insert new element at the end */
++      break;
++    }
++    case 3: {
++      lua_Integer i;
++      pos = luaL_checkinteger(L, 2);  /* 2nd argument is the position */
++      luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
++      for (i = e; i > pos; i--) {  /* move up elements */
++        lua_geti(L, 1, i - 1);
++        lua_seti(L, 1, i);  /* t[i] = t[i - 1] */
++      }
++      break;
++    }
++    default: {
++      return luaL_error(L, "wrong number of arguments to 'insert'");
++    }
++  }
++  lua_seti(L, 1, pos);  /* t[pos] = v */
++  return 0;
++}
++
++
++static int tremove (lua_State *L) {
++  lua_Integer size = aux_getn(L, 1, TAB_RW);
++  lua_Integer pos = luaL_optinteger(L, 2, size);
++  if (pos != size)  /* validate 'pos' if given */
++    luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
++  lua_geti(L, 1, pos);  /* result = t[pos] */
++  for ( ; pos < size; pos++) {
++    lua_geti(L, 1, pos + 1);
++    lua_seti(L, 1, pos);  /* t[pos] = t[pos + 1] */
++  }
++  lua_pushnil(L);
++  lua_seti(L, 1, pos);  /* t[pos] = nil */
++  return 1;
++}
++
++
++/*
++** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
++** possible, copy in increasing order, which is better for rehashing.
++** "possible" means destination after original range, or smaller
++** than origin, or copying to another table.
++*/
++static int tmove (lua_State *L) {
++  lua_Integer f = luaL_checkinteger(L, 2);
++  lua_Integer e = luaL_checkinteger(L, 3);
++  lua_Integer t = luaL_checkinteger(L, 4);
++  int tt = !lua_isnoneornil(L, 5) ? 5 : 1;  /* destination table */
++  checktab(L, 1, TAB_R);
++  checktab(L, tt, TAB_W);
++  if (e >= f) {  /* otherwise, nothing to move */
++    lua_Integer n, i;
++    luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
++                  "too many elements to move");
++    n = e - f + 1;  /* number of elements to move */
++    luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
++                  "destination wrap around");
++    if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
++      for (i = 0; i < n; i++) {
++        lua_geti(L, 1, f + i);
++        lua_seti(L, tt, t + i);
++      }
++    }
++    else {
++      for (i = n - 1; i >= 0; i--) {
++        lua_geti(L, 1, f + i);
++        lua_seti(L, tt, t + i);
++      }
++    }
++  }
++  lua_pushvalue(L, tt);  /* return destination table */
++  return 1;
++}
++
++
++static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
++  lua_geti(L, 1, i);
++  if (!lua_isstring(L, -1))
++    luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
++                  luaL_typename(L, -1), i);
++  luaL_addvalue(b);
++}
++
++
++static int tconcat (lua_State *L) {
++  luaL_Buffer b;
++  lua_Integer last = aux_getn(L, 1, TAB_R);
++  size_t lsep;
++  const char *sep = luaL_optlstring(L, 2, "", &lsep);
++  lua_Integer i = luaL_optinteger(L, 3, 1);
++  last = luaL_optinteger(L, 4, last);
++  luaL_buffinit(L, &b);
++  for (; i < last; i++) {
++    addfield(L, &b, i);
++    luaL_addlstring(&b, sep, lsep);
++  }
++  if (i == last)  /* add last value (if interval was not empty) */
++    addfield(L, &b, i);
++  luaL_pushresult(&b);
++  return 1;
++}
++
++
++/*
++** {======================================================
++** Pack/unpack
++** =======================================================
++*/
++
++static int pack (lua_State *L) {
++  int i;
++  int n = lua_gettop(L);  /* number of elements to pack */
++  lua_createtable(L, n, 1);  /* create result table */
++  lua_insert(L, 1);  /* put it at index 1 */
++  for (i = n; i >= 1; i--)  /* assign elements */
++    lua_seti(L, 1, i);
++  lua_pushinteger(L, n);
++  lua_setfield(L, 1, "n");  /* t.n = number of elements */
++  return 1;  /* return table */
++}
++
++
++static int unpack (lua_State *L) {
++  lua_Unsigned n;
++  lua_Integer i = luaL_optinteger(L, 2, 1);
++  lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
++  if (i > e) return 0;  /* empty range */
++  n = (lua_Unsigned)e - i;  /* number of elements minus 1 (avoid overflows) */
++  if (n >= (unsigned int)INT_MAX  || !lua_checkstack(L, (int)(++n)))
++    return luaL_error(L, "too many results to unpack");
++  for (; i < e; i++) {  /* push arg[i..e - 1] (to avoid overflows) */
++    lua_geti(L, 1, i);
++  }
++  lua_geti(L, 1, e);  /* push last element */
++  return (int)n;
++}
++
++/* }====================================================== */
++
++
++
++/*
++** {======================================================
++** Quicksort
++** (based on 'Algorithms in MODULA-3', Robert Sedgewick;
++**  Addison-Wesley, 1993.)
++** =======================================================
++*/
++
++
++/* type for array indices */
++typedef unsigned int IdxT;
++
++
++/*
++** Produce a "random" 'unsigned int' to randomize pivot choice. This
++** macro is used only when 'sort' detects a big imbalance in the result
++** of a partition. (If you don't want/need this "randomness", ~0 is a
++** good choice.)
++*/
++#if !defined(l_randomizePivot)		/* { */
++
++#include <time.h>
++
++/* size of 'e' measured in number of 'unsigned int's */
++#define sof(e)		(sizeof(e) / sizeof(unsigned int))
++
++/*
++** Use 'time' and 'clock' as sources of "randomness". Because we don't
++** know the types 'clock_t' and 'time_t', we cannot cast them to
++** anything without risking overflows. A safe way to use their values
++** is to copy them to an array of a known type and use the array values.
++*/
++static unsigned int l_randomizePivot (void) {
++  clock_t c = clock();
++  time_t t = time(NULL);
++  unsigned int buff[sof(c) + sof(t)];
++  unsigned int i, rnd = 0;
++  memcpy(buff, &c, sof(c) * sizeof(unsigned int));
++  memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
++  for (i = 0; i < sof(buff); i++)
++    rnd += buff[i];
++  return rnd;
++}
++
++#endif					/* } */
++
++
++/* arrays larger than 'RANLIMIT' may use randomized pivots */
++#define RANLIMIT	100u
++
++
++static void set2 (lua_State *L, IdxT i, IdxT j) {
++  lua_seti(L, 1, i);
++  lua_seti(L, 1, j);
++}
++
++
++/*
++** Return true iff value at stack index 'a' is less than the value at
++** index 'b' (according to the order of the sort).
++*/
++static int sort_comp (lua_State *L, int a, int b) {
++  if (lua_isnil(L, 2))  /* no function? */
++    return lua_compare(L, a, b, LUA_OPLT);  /* a < b */
++  else {  /* function */
++    int res;
++    lua_pushvalue(L, 2);    /* push function */
++    lua_pushvalue(L, a-1);  /* -1 to compensate function */
++    lua_pushvalue(L, b-2);  /* -2 to compensate function and 'a' */
++    lua_call(L, 2, 1);      /* call function */
++    res = lua_toboolean(L, -1);  /* get result */
++    lua_pop(L, 1);          /* pop result */
++    return res;
++  }
++}
++
++
++/*
++** Does the partition: Pivot P is at the top of the stack.
++** precondition: a[lo] <= P == a[up-1] <= a[up],
++** so it only needs to do the partition from lo + 1 to up - 2.
++** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
++** returns 'i'.
++*/
++static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
++  IdxT i = lo;  /* will be incremented before first use */
++  IdxT j = up - 1;  /* will be decremented before first use */
++  /* loop invariant: a[lo .. i] <= P <= a[j .. up] */
++  for (;;) {
++    /* next loop: repeat ++i while a[i] < P */
++    while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
++      if (i == up - 1)  /* a[i] < P  but a[up - 1] == P  ?? */
++        luaL_error(L, "invalid order function for sorting");
++      lua_pop(L, 1);  /* remove a[i] */
++    }
++    /* after the loop, a[i] >= P and a[lo .. i - 1] < P */
++    /* next loop: repeat --j while P < a[j] */
++    while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
++      if (j < i)  /* j < i  but  a[j] > P ?? */
++        luaL_error(L, "invalid order function for sorting");
++      lua_pop(L, 1);  /* remove a[j] */
++    }
++    /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
++    if (j < i) {  /* no elements out of place? */
++      /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */
++      lua_pop(L, 1);  /* pop a[j] */
++      /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */
++      set2(L, up - 1, i);
++      return i;
++    }
++    /* otherwise, swap a[i] - a[j] to restore invariant and repeat */
++    set2(L, i, j);
++  }
++}
++
++
++/*
++** Choose an element in the middle (2nd-3th quarters) of [lo,up]
++** "randomized" by 'rnd'
++*/
++static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
++  IdxT r4 = (up - lo) / 4;  /* range/4 */
++  IdxT p = rnd % (r4 * 2) + (lo + r4);
++  lua_assert(lo + r4 <= p && p <= up - r4);
++  return p;
++}
++
++
++/*
++** QuickSort algorithm (recursive function)
++*/
++static void auxsort (lua_State *L, IdxT lo, IdxT up,
++                                   unsigned int rnd) {
++  while (lo < up) {  /* loop for tail recursion */
++    IdxT p;  /* Pivot index */
++    IdxT n;  /* to be used later */
++    /* sort elements 'lo', 'p', and 'up' */
++    lua_geti(L, 1, lo);
++    lua_geti(L, 1, up);
++    if (sort_comp(L, -1, -2))  /* a[up] < a[lo]? */
++      set2(L, lo, up);  /* swap a[lo] - a[up] */
++    else
++      lua_pop(L, 2);  /* remove both values */
++    if (up - lo == 1)  /* only 2 elements? */
++      return;  /* already sorted */
++    if (up - lo < RANLIMIT || rnd == 0)  /* small interval or no randomize? */
++      p = (lo + up)/2;  /* middle element is a good pivot */
++    else  /* for larger intervals, it is worth a random pivot */
++      p = choosePivot(lo, up, rnd);
++    lua_geti(L, 1, p);
++    lua_geti(L, 1, lo);
++    if (sort_comp(L, -2, -1))  /* a[p] < a[lo]? */
++      set2(L, p, lo);  /* swap a[p] - a[lo] */
++    else {
++      lua_pop(L, 1);  /* remove a[lo] */
++      lua_geti(L, 1, up);
++      if (sort_comp(L, -1, -2))  /* a[up] < a[p]? */
++        set2(L, p, up);  /* swap a[up] - a[p] */
++      else
++        lua_pop(L, 2);
++    }
++    if (up - lo == 2)  /* only 3 elements? */
++      return;  /* already sorted */
++    lua_geti(L, 1, p);  /* get middle element (Pivot) */
++    lua_pushvalue(L, -1);  /* push Pivot */
++    lua_geti(L, 1, up - 1);  /* push a[up - 1] */
++    set2(L, p, up - 1);  /* swap Pivot (a[p]) with a[up - 1] */
++    p = partition(L, lo, up);
++    /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
++    if (p - lo < up - p) {  /* lower interval is smaller? */
++      auxsort(L, lo, p - 1, rnd);  /* call recursively for lower interval */
++      n = p - lo;  /* size of smaller interval */
++      lo = p + 1;  /* tail call for [p + 1 .. up] (upper interval) */
++    }
++    else {
++      auxsort(L, p + 1, up, rnd);  /* call recursively for upper interval */
++      n = up - p;  /* size of smaller interval */
++      up = p - 1;  /* tail call for [lo .. p - 1]  (lower interval) */
++    }
++    if ((up - lo) / 128 > n) /* partition too imbalanced? */
++      rnd = l_randomizePivot();  /* try a new randomization */
++  }  /* tail call auxsort(L, lo, up, rnd) */
++}
++
++
++static int sort (lua_State *L) {
++  lua_Integer n = aux_getn(L, 1, TAB_RW);
++  if (n > 1) {  /* non-trivial interval? */
++    luaL_argcheck(L, n < INT_MAX, 1, "array too big");
++    if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */
++      luaL_checktype(L, 2, LUA_TFUNCTION);  /* must be a function */
++    lua_settop(L, 2);  /* make sure there are two arguments */
++    auxsort(L, 1, (IdxT)n, 0);
++  }
++  return 0;
++}
++
++/* }====================================================== */
++
++
++static const luaL_Reg tab_funcs[] = {
++  {"concat", tconcat},
++#if defined(LUA_COMPAT_MAXN)
++  {"maxn", maxn},
++#endif
++  {"insert", tinsert},
++  {"pack", pack},
++  {"unpack", unpack},
++  {"remove", tremove},
++  {"move", tmove},
++  {"sort", sort},
++  {NULL, NULL}
++};
++
++
++LUAMOD_API int luaopen_table (lua_State *L) {
++  luaL_newlib(L, tab_funcs);
++#if defined(LUA_COMPAT_UNPACK)
++  /* _G.unpack = table.unpack */
++  lua_getfield(L, -1, "unpack");
++  lua_setglobal(L, "unpack");
++#endif
++  return 1;
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/lutf8lib.c luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/lutf8lib.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/lutf8lib.c	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/lutf8lib.c	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,256 @@
++/*
++** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $
++** Standard library for UTF-8 manipulation
++** See Copyright Notice in lua.h
++*/
++
++#define lutf8lib_c
++#define LUA_LIB
++
++#include "lprefix.h"
++
++
++#include <assert.h>
++#include <limits.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include "lua.h"
++
++#include "lauxlib.h"
++#include "lualib.h"
++
++#define MAXUNICODE	0x10FFFF
++
++#define iscont(p)	((*(p) & 0xC0) == 0x80)
++
++
++/* from strlib */
++/* translate a relative string position: negative means back from end */
++static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
++  if (pos >= 0) return pos;
++  else if (0u - (size_t)pos > len) return 0;
++  else return (lua_Integer)len + pos + 1;
++}
++
++
++/*
++** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
++*/
++static const char *utf8_decode (const char *o, int *val) {
++  static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
++  const unsigned char *s = (const unsigned char *)o;
++  unsigned int c = s[0];
++  unsigned int res = 0;  /* final result */
++  if (c < 0x80)  /* ascii? */
++    res = c;
++  else {
++    int count = 0;  /* to count number of continuation bytes */
++    while (c & 0x40) {  /* still have continuation bytes? */
++      int cc = s[++count];  /* read next byte */
++      if ((cc & 0xC0) != 0x80)  /* not a continuation byte? */
++        return NULL;  /* invalid byte sequence */
++      res = (res << 6) | (cc & 0x3F);  /* add lower 6 bits from cont. byte */
++      c <<= 1;  /* to test next bit */
++    }
++    res |= ((c & 0x7F) << (count * 5));  /* add first byte */
++    if (count > 3 || res > MAXUNICODE || res <= limits[count])
++      return NULL;  /* invalid byte sequence */
++    s += count;  /* skip continuation bytes read */
++  }
++  if (val) *val = res;
++  return (const char *)s + 1;  /* +1 to include first byte */
++}
++
++
++/*
++** utf8len(s [, i [, j]]) --> number of characters that start in the
++** range [i,j], or nil + current position if 's' is not well formed in
++** that interval
++*/
++static int utflen (lua_State *L) {
++  int n = 0;
++  size_t len;
++  const char *s = luaL_checklstring(L, 1, &len);
++  lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
++  lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len);
++  luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2,
++                   "initial position out of string");
++  luaL_argcheck(L, --posj < (lua_Integer)len, 3,
++                   "final position out of string");
++  while (posi <= posj) {
++    const char *s1 = utf8_decode(s + posi, NULL);
++    if (s1 == NULL) {  /* conversion error? */
++      lua_pushnil(L);  /* return nil ... */
++      lua_pushinteger(L, posi + 1);  /* ... and current position */
++      return 2;
++    }
++    posi = s1 - s;
++    n++;
++  }
++  lua_pushinteger(L, n);
++  return 1;
++}
++
++
++/*
++** codepoint(s, [i, [j]])  -> returns codepoints for all characters
++** that start in the range [i,j]
++*/
++static int codepoint (lua_State *L) {
++  size_t len;
++  const char *s = luaL_checklstring(L, 1, &len);
++  lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
++  lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len);
++  int n;
++  const char *se;
++  luaL_argcheck(L, posi >= 1, 2, "out of range");
++  luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
++  if (posi > pose) return 0;  /* empty interval; return no values */
++  if (pose - posi >= INT_MAX)  /* (lua_Integer -> int) overflow? */
++    return luaL_error(L, "string slice too long");
++  n = (int)(pose -  posi) + 1;
++  luaL_checkstack(L, n, "string slice too long");
++  n = 0;
++  se = s + pose;
++  for (s += posi - 1; s < se;) {
++    int code;
++    s = utf8_decode(s, &code);
++    if (s == NULL)
++      return luaL_error(L, "invalid UTF-8 code");
++    lua_pushinteger(L, code);
++    n++;
++  }
++  return n;
++}
++
++
++static void pushutfchar (lua_State *L, int arg) {
++  lua_Integer code = luaL_checkinteger(L, arg);
++  luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range");
++  lua_pushfstring(L, "%U", (long)code);
++}
++
++
++/*
++** utfchar(n1, n2, ...)  -> char(n1)..char(n2)...
++*/
++static int utfchar (lua_State *L) {
++  int n = lua_gettop(L);  /* number of arguments */
++  if (n == 1)  /* optimize common case of single char */
++    pushutfchar(L, 1);
++  else {
++    int i;
++    luaL_Buffer b;
++    luaL_buffinit(L, &b);
++    for (i = 1; i <= n; i++) {
++      pushutfchar(L, i);
++      luaL_addvalue(&b);
++    }
++    luaL_pushresult(&b);
++  }
++  return 1;
++}
++
++
++/*
++** offset(s, n, [i])  -> index where n-th character counting from
++**   position 'i' starts; 0 means character at 'i'.
++*/
++static int byteoffset (lua_State *L) {
++  size_t len;
++  const char *s = luaL_checklstring(L, 1, &len);
++  lua_Integer n  = luaL_checkinteger(L, 2);
++  lua_Integer posi = (n >= 0) ? 1 : len + 1;
++  posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
++  luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
++                   "position out of range");
++  if (n == 0) {
++    /* find beginning of current byte sequence */
++    while (posi > 0 && iscont(s + posi)) posi--;
++  }
++  else {
++    if (iscont(s + posi))
++      luaL_error(L, "initial position is a continuation byte");
++    if (n < 0) {
++       while (n < 0 && posi > 0) {  /* move back */
++         do {  /* find beginning of previous character */
++           posi--;
++         } while (posi > 0 && iscont(s + posi));
++         n++;
++       }
++     }
++     else {
++       n--;  /* do not move for 1st character */
++       while (n > 0 && posi < (lua_Integer)len) {
++         do {  /* find beginning of next character */
++           posi++;
++         } while (iscont(s + posi));  /* (cannot pass final '\0') */
++         n--;
++       }
++     }
++  }
++  if (n == 0)  /* did it find given character? */
++    lua_pushinteger(L, posi + 1);
++  else  /* no such character */
++    lua_pushnil(L);
++  return 1;
++}
++
++
++static int iter_aux (lua_State *L) {
++  size_t len;
++  const char *s = luaL_checklstring(L, 1, &len);
++  lua_Integer n = lua_tointeger(L, 2) - 1;
++  if (n < 0)  /* first iteration? */
++    n = 0;  /* start from here */
++  else if (n < (lua_Integer)len) {
++    n++;  /* skip current byte */
++    while (iscont(s + n)) n++;  /* and its continuations */
++  }
++  if (n >= (lua_Integer)len)
++    return 0;  /* no more codepoints */
++  else {
++    int code;
++    const char *next = utf8_decode(s + n, &code);
++    if (next == NULL || iscont(next))
++      return luaL_error(L, "invalid UTF-8 code");
++    lua_pushinteger(L, n + 1);
++    lua_pushinteger(L, code);
++    return 2;
++  }
++}
++
++
++static int iter_codes (lua_State *L) {
++  luaL_checkstring(L, 1);
++  lua_pushcfunction(L, iter_aux);
++  lua_pushvalue(L, 1);
++  lua_pushinteger(L, 0);
++  return 3;
++}
++
++
++/* pattern to match a single UTF-8 character */
++#define UTF8PATT	"[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
++
++
++static const luaL_Reg funcs[] = {
++  {"offset", byteoffset},
++  {"codepoint", codepoint},
++  {"char", utfchar},
++  {"len", utflen},
++  {"codes", iter_codes},
++  /* placeholders */
++  {"charpattern", NULL},
++  {NULL, NULL}
++};
++
++
++LUAMOD_API int luaopen_utf8 (lua_State *L) {
++  luaL_newlib(L, funcs);
++  lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
++  lua_setfield(L, -2, "charpattern");
++  return 1;
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/README.md luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/README.md
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/README.md	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/README.md	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,239 @@
++[![Build Status](https://travis-ci.org/keplerproject/lua-compat-5.3.svg?branch=master)](https://travis-ci.org/keplerproject/lua-compat-5.3)
++
++# lua-compat-5.3
++
++Lua-5.3-style APIs for Lua 5.2 and 5.1.
++
++## What is it
++
++This is a small module that aims to make it easier to write code
++in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua
++5.3. This does *not* make Lua 5.2 (or even Lua 5.1) entirely
++compatible with Lua 5.3, but it brings the API closer to that of Lua
++5.3.
++
++It includes:
++
++* _For writing Lua_: The Lua module `compat53`, which can be require'd
++  from Lua scripts and run in Lua 5.1, 5.2, and 5.3, including a
++  backport of the `utf8` module, the 5.3 `table` module, and the
++  string packing functions straight from the Lua 5.3 sources.
++* _For writing C_: A C header and file which can be linked to your
++  Lua module written in C, providing some functions from the C API
++  of Lua 5.3 that do not exist in Lua 5.2 or 5.1, making it easier to
++  write C code that compiles with all three versions of liblua.
++
++## How to use it
++
++### Lua module
++
++```lua
++require("compat53")
++```
++
++`compat53` makes changes to your global environment and does not return
++a meaningful return value, so the usual idiom of storing the return of
++`require` in a local variable makes no sense.
++
++When run under Lua 5.3, this module does nothing.
++
++When run under Lua 5.2 or 5.1, it replaces some of your standard
++functions and adds new ones to bring your environment closer to that
++of Lua 5.3. It also tries to load the backported `utf8`, `table`, and
++string packing modules automatically. If unsuccessful, pure Lua
++versions of the new `table` functions are used as a fallback, and
++[Roberto's struct library][1] is tried for string packing.
++
++#### Lua submodules
++
++```lua
++local _ENV = require("compat53.module")
++if setfenv then setfenv(1, _ENV) end
++```
++
++The `compat53.module` module does not modify the global environment,
++and so it is safe to use in modules without affecting other Lua files.
++It is supposed to be set as the current environment (see above), i.e.
++cherry picking individual functions from this module is expressly
++*not* supported!). Not all features are available when using this
++module (e.g. yieldable (x)pcall support, string/file methods, etc.),
++so it is recommended to use plain `require("compat53")` whenever
++possible.
++
++### C code
++
++There are two ways of adding the C API compatibility functions/macros to
++your project:
++* If `COMPAT53_PREFIX` is *not* `#define`d, `compat-5.3.h` `#include`s
++  `compat-5.3.c`, and all functions are made `static`. You don't have to
++  compile/link/add `compat-5.3.c` yourself. This is useful for one-file
++  projects.
++* If `COMPAT53_PREFIX` is `#define`d, all exported functions are renamed
++  behind the scenes using this prefix to avoid linker conflicts with other
++  code using this package. This doesn't change the way you call the
++  compatibility functions in your code. You have to compile and link
++  `compat-5.3.c` to your project yourself. You can change the way the
++  functions are exported using the `COMPAT53_API` macro (e.g. if you need
++  some `__declspec` magic). While it is technically possible to use
++  the "lua" prefix (and it looks better in the debugger), this is
++  discouraged because LuaJIT has started to implement its own Lua 5.2+
++  C API functions, and with the "lua" prefix you'd violate the
++  one-definition rule with recent LuaJIT versions.
++
++## What's implemented
++
++### Lua
++
++* the `utf8` module backported from the Lua 5.3 sources
++* `string.pack`, `string.packsize`, and `string.unpack` from the Lua
++  5.3 sources or from the `struct` module. (`struct` is not 100%
++  compatible to Lua 5.3's string packing!) (See [here][4])
++* `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`,
++  and `math.ult` (see [here][5])
++* `assert` accepts non-string error messages
++* `ipairs` respects `__index` metamethod
++* `table.move`
++* `table` library respects metamethods
++
++For Lua 5.1 additionally:
++* `load` and `loadfile` accept `mode` and `env` parameters
++* `table.pack` and `table.unpack`
++* string patterns may contain embedded zeros (but see [here][6])
++* `string.rep` accepts `sep` argument
++* `string.format` calls `tostring` on arguments for `%s`
++* `math.log` accepts base argument
++* `xpcall` takes additional arguments
++* `pcall` and `xpcall` can execute functions that yield (see
++  [here][22] for a possible problem with `coroutine.running`)
++* `pairs` respects `__pairs` metamethod (see [here][7])
++* `rawlen` (but `#` still doesn't respect `__len` for tables)
++* `package.searchers` as alias for `package.loaders`
++* `package.searchpath` (see [here][8])
++* `coroutine` functions dealing with the main coroutine (see
++  [here][22] for a possible problem with `coroutine.running`)
++* `coroutine.create` accepts functions written in C
++* return code of `os.execute` (see [here][9])
++* `io.write` and `file:write` return file handle
++* `io.lines` and `file:lines` accept format arguments (like `io.read`)
++  (see [here][10] and [here][11])
++* `debug.setmetatable` returns object
++* `debug.getuservalue` (see [here][12])
++* `debug.setuservalue` (see [here][13])
++
++### C
++
++* `lua_KContext` (see [here][14])
++* `lua_KFunction` (see [here][14])
++* `lua_dump` (extra `strip` parameter, ignored, see [here][15])
++* `lua_getfield` (return value)
++* `lua_geti` and `lua_seti`
++* `lua_getglobal` (return value)
++* `lua_getmetafield` (return value)
++* `lua_gettable` (return value)
++* `lua_getuservalue` (limited compatibility, see [here][16])
++* `lua_setuservalue` (limited compatibility, see [here][17])
++* `lua_isinteger`
++* `lua_numbertointeger`
++* `lua_callk` and `lua_pcallk` (limited compatibility, see [here][14])
++* `lua_resume`
++* `lua_rawget` and `lua_rawgeti` (return values)
++* `lua_rawgetp` and `lua_rawsetp`
++* `luaL_requiref` (now checks `package.loaded` first)
++* `lua_rotate`
++* `lua_stringtonumber` (see [here][18])
++
++For Lua 5.1 additionally:
++* `LUA_OK`
++* `LUA_ERRGCMM`
++* `LUA_OP*` macros for `lua_arith` and `lua_compare`
++* `LUA_FILEHANDLE`
++* `lua_Unsigned`
++* `luaL_Stream` (limited compatibility, see [here][19])
++* `lua_absindex`
++* `lua_arith` (see [here][20])
++* `lua_compare`
++* `lua_len`, `lua_rawlen`, and `luaL_len`
++* `lua_load` (mode argument)
++* `lua_pushstring`, `lua_pushlstring` (return value)
++* `lua_copy`
++* `lua_pushglobaltable`
++* `luaL_testudata`
++* `luaL_setfuncs`, `luaL_newlibtable`, and `luaL_newlib`
++* `luaL_setmetatable`
++* `luaL_getsubtable`
++* `luaL_traceback`
++* `luaL_execresult`
++* `luaL_fileresult`
++* `luaL_loadbufferx`
++* `luaL_loadfilex`
++* `luaL_checkversion` (with empty body, only to avoid compile errors,
++  see [here][21])
++* `luaL_tolstring`
++* `luaL_buffinitsize`, `luaL_prepbuffsize`, and `luaL_pushresultsize`
++  (see [here][22])
++* `lua_pushunsigned`, `lua_tounsignedx`, `lua_tounsigned`,
++  `luaL_checkunsigned`, `luaL_optunsigned`, if
++  `LUA_COMPAT_APIINTCASTS` is defined.
++
++## What's not implemented
++
++* bit operators
++* integer division operator
++* utf8 escape sequences
++* 64 bit integers
++* `coroutine.isyieldable`
++* Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See
++  [`lua-compat-5.2`][2] for a detailed list.
++* the following C API functions/macros:
++  * `lua_isyieldable`
++  * `lua_getextraspace`
++  * `lua_arith` (new operators missing)
++  * `lua_push(v)fstring` (new formats missing)
++  * `lua_upvalueid` (5.1)
++  * `lua_upvaluejoin` (5.1)
++  * `lua_version` (5.1)
++  * `lua_yieldk` (5.1)
++
++## See also
++
++* For Lua-5.2-style APIs under Lua 5.1, see [lua-compat-5.2][2],
++  which also is the basis for most of the code in this project.
++* For Lua-5.1-style APIs under Lua 5.0, see [Compat-5.1][3]
++
++## Credits
++
++This package contains code written by:
++
++* [The Lua Team](http://www.lua.org)
++* Philipp Janda ([@siffiejoe](http://github.com/siffiejoe))
++* Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola))
++* Hisham Muhammad ([@hishamhm](http://github.com/hishamhm))
++* Renato Maia ([@renatomaia](http://github.com/renatomaia))
++* [@ThePhD](http://github.com/ThePhD)
++* [@Daurnimator](http://github.com/Daurnimator)
++
++
++  [1]: http://www.inf.puc-rio.br/~roberto/struct/
++  [2]: http://github.com/keplerproject/lua-compat-5.2/
++  [3]: http://keplerproject.org/compat/
++  [4]: https://github.com/keplerproject/lua-compat-5.3/wiki/string_packing
++  [5]: https://github.com/keplerproject/lua-compat-5.3/wiki/math.type
++  [6]: https://github.com/keplerproject/lua-compat-5.3/wiki/pattern_matching
++  [7]: https://github.com/keplerproject/lua-compat-5.3/wiki/pairs
++  [8]: https://github.com/keplerproject/lua-compat-5.3/wiki/package.searchpath
++  [9]: https://github.com/keplerproject/lua-compat-5.3/wiki/os.execute
++  [10]: https://github.com/keplerproject/lua-compat-5.3/wiki/io.lines
++  [11]: https://github.com/keplerproject/lua-compat-5.3/wiki/file.lines
++  [12]: https://github.com/keplerproject/lua-compat-5.3/wiki/debug.getuservalue
++  [13]: https://github.com/keplerproject/lua-compat-5.3/wiki/debug.setuservalue
++  [14]: https://github.com/keplerproject/lua-compat-5.3/wiki/yieldable_c_functions
++  [15]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_dump
++  [16]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_getuservalue
++  [17]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_setuservalue
++  [18]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_stringtonumber
++  [19]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Stream
++  [20]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_arith
++  [21]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_checkversion
++  [22]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Buffer
++  [23]: https://github.com/keplerproject/lua-compat-5.3/wiki/coroutine.running
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.1-1.rockspec luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.1-1.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.1-1.rockspec	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.1-1.rockspec	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,31 @@
++package = "compat53"
++version = "0.1-1"
++source = {
++   url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.1.zip",
++   dir = "lua-compat-5.3-0.1",
++}
++description = {
++   summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
++   detailed = [[
++      This is a small module that aims to make it easier to write Lua
++      code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
++      It does *not* make Lua 5.2 (or even 5.1) entirely compatible
++      with Lua 5.3, but it brings the API closer to that of Lua 5.3.
++   ]],
++   homepage = "https://github.com/keplerproject/lua-compat-5.3",
++   license = "MIT"
++}
++dependencies = {
++   "lua >= 5.1, < 5.4",
++   --"struct" -- make Roberto's struct module optional
++}
++build = {
++   type = "builtin",
++   modules = {
++      ["compat53"] = "compat53.lua",
++      ["compat53.utf8"] = "lutf8lib.c",
++      ["compat53.table"] = "ltablib.c",
++      ["compat53.string"] = "lstrlib.c",
++   }
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.2-1.rockspec luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.2-1.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.2-1.rockspec	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.2-1.rockspec	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,32 @@
++package = "compat53"
++version = "0.2-1"
++source = {
++   url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.2.zip",
++   dir = "lua-compat-5.3-0.2",
++}
++description = {
++   summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
++   detailed = [[
++      This is a small module that aims to make it easier to write Lua
++      code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
++      It does *not* make Lua 5.2 (or even 5.1) entirely compatible
++      with Lua 5.3, but it brings the API closer to that of Lua 5.3.
++   ]],
++   homepage = "https://github.com/keplerproject/lua-compat-5.3",
++   license = "MIT"
++}
++dependencies = {
++   "lua >= 5.1, < 5.4",
++   --"struct" -- make Roberto's struct module optional
++}
++build = {
++   type = "builtin",
++   modules = {
++      ["compat53.init"] = "compat53/init.lua",
++      ["compat53.module"] = "compat53/module.lua",
++      ["compat53.utf8"] = "lutf8lib.c",
++      ["compat53.table"] = "ltablib.c",
++      ["compat53.string"] = "lstrlib.c",
++   }
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.3-1.rockspec luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.3-1.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.3-1.rockspec	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.3-1.rockspec	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,32 @@
++package = "compat53"
++version = "0.3-1"
++source = {
++   url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.3.zip",
++   dir = "lua-compat-5.3-0.3",
++}
++description = {
++   summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
++   detailed = [[
++      This is a small module that aims to make it easier to write Lua
++      code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
++      It does *not* make Lua 5.2 (or even 5.1) entirely compatible
++      with Lua 5.3, but it brings the API closer to that of Lua 5.3.
++   ]],
++   homepage = "https://github.com/keplerproject/lua-compat-5.3",
++   license = "MIT"
++}
++dependencies = {
++   "lua >= 5.1, < 5.4",
++   --"struct" -- make Roberto's struct module optional
++}
++build = {
++   type = "builtin",
++   modules = {
++      ["compat53.init"] = "compat53/init.lua",
++      ["compat53.module"] = "compat53/module.lua",
++      ["compat53.utf8"] = "lutf8lib.c",
++      ["compat53.table"] = "ltablib.c",
++      ["compat53.string"] = "lstrlib.c",
++   }
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.4-1.rockspec luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.4-1.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.4-1.rockspec	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.4-1.rockspec	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,32 @@
++package = "compat53"
++version = "0.4-1"
++source = {
++   url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.4.zip",
++   dir = "lua-compat-5.3-0.4",
++}
++description = {
++   summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
++   detailed = [[
++      This is a small module that aims to make it easier to write Lua
++      code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
++      It does *not* make Lua 5.2 (or even 5.1) entirely compatible
++      with Lua 5.3, but it brings the API closer to that of Lua 5.3.
++   ]],
++   homepage = "https://github.com/keplerproject/lua-compat-5.3",
++   license = "MIT"
++}
++dependencies = {
++   "lua >= 5.1, < 5.4",
++   --"struct" -- make Roberto's struct module optional
++}
++build = {
++   type = "builtin",
++   modules = {
++      ["compat53.init"] = "compat53/init.lua",
++      ["compat53.module"] = "compat53/module.lua",
++      ["compat53.utf8"] = "lutf8lib.c",
++      ["compat53.table"] = "ltablib.c",
++      ["compat53.string"] = "lstrlib.c",
++   }
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.5-1.rockspec luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.5-1.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.5-1.rockspec	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-0.5-1.rockspec	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,32 @@
++package = "compat53"
++version = "0.5-1"
++source = {
++   url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.5.zip",
++   dir = "lua-compat-5.3-0.5",
++}
++description = {
++   summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
++   detailed = [[
++      This is a small module that aims to make it easier to write Lua
++      code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
++      It does *not* make Lua 5.2 (or even 5.1) entirely compatible
++      with Lua 5.3, but it brings the API closer to that of Lua 5.3.
++   ]],
++   homepage = "https://github.com/keplerproject/lua-compat-5.3",
++   license = "MIT"
++}
++dependencies = {
++   "lua >= 5.1, < 5.4",
++   --"struct" -- make Roberto's struct module optional
++}
++build = {
++   type = "builtin",
++   modules = {
++      ["compat53.init"] = "compat53/init.lua",
++      ["compat53.module"] = "compat53/module.lua",
++      ["compat53.utf8"] = "lutf8lib.c",
++      ["compat53.table"] = "ltablib.c",
++      ["compat53.string"] = "lstrlib.c",
++   }
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-scm-0.rockspec luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-scm-0.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-scm-0.rockspec	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/rockspecs/compat53-scm-0.rockspec	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,32 @@
++package = "compat53"
++version = "scm-0"
++source = {
++   url = "https://github.com/keplerproject/lua-compat-5.3/archive/master.zip",
++   dir = "lua-compat-5.3-master",
++}
++description = {
++   summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
++   detailed = [[
++      This is a small module that aims to make it easier to write Lua
++      code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
++      It does *not* make Lua 5.2 (or even 5.1) entirely compatible
++      with Lua 5.3, but it brings the API closer to that of Lua 5.3.
++   ]],
++   homepage = "https://github.com/keplerproject/lua-compat-5.3",
++   license = "MIT"
++}
++dependencies = {
++   "lua >= 5.1, < 5.4",
++   --"struct" -- make Roberto's struct module optional
++}
++build = {
++   type = "builtin",
++   modules = {
++      ["compat53.init"] = "compat53/init.lua",
++      ["compat53.module"] = "compat53/module.lua",
++      ["compat53.utf8"] = "lutf8lib.c",
++      ["compat53.table"] = "ltablib.c",
++      ["compat53.string"] = "lstrlib.c",
++   }
++}
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/tests/test.lua luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/tests/test.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/tests/test.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/tests/test.lua	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,819 @@
++#!/usr/bin/env lua
++
++local F, tproxy, writefile, noprint, ___
++do
++  local type, unpack = type, table.unpack or unpack
++  local assert, io = assert, io
++  function F(...)
++    local args, n = { ... }, select('#', ...)
++    for i = 1, n do
++      local t = type(args[i])
++      if t ~= "string" and t ~= "number" and t ~= "boolean" then
++        args[i] = t
++      end
++    end
++    return unpack(args, 1, n)
++  end
++  function tproxy(t)
++    return setmetatable({}, {
++      __index = t,
++      __newindex = t,
++      __len = function() return #t end,
++    }), t
++  end
++  function writefile(name, contents, bin)
++    local f = assert(io.open(name, bin and "wb" or "w"))
++    f:write(contents)
++    f:close()
++  end
++  function noprint() end
++  local sep = ("="):rep(70)
++  function ___()
++    print(sep)
++  end
++end
++
++local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2")
++if jit then V = "jit" end
++
++local mode = "global"
++if arg[1] == "module" then
++  mode = "module"
++end
++local self = arg[0]
++
++package.path = "../?.lua;../?/init.lua"
++package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll"
++if mode == "module" then
++  print("testing Lua API using `compat53.module` ...")
++  _ENV = require("compat53.module")
++  if setfenv then setfenv(1, _ENV) end
++else
++  print("testing Lua API using `compat53` ...")
++  require("compat53")
++end
++
++
++___''
++do
++  print("assert", F(pcall(assert, false)))
++  print("assert", F(pcall(assert, false, nil)))
++  print("assert", F(pcall(assert, false, "error msg")))
++  print("assert", F(pcall(assert, nil, {})))
++  print("assert", F(pcall(assert, 1, 2, 3)))
++end
++
++
++___''
++do
++  local t = setmetatable({}, { __index = { 1, false, "three" } })
++  for i,v in ipairs(t) do
++    print("ipairs", i, v)
++  end
++end
++
++
++___''
++do
++  local p, t = tproxy{ "a", "b", "c" }
++  print("table.concat", table.concat(p))
++  print("table.concat", table.concat(p, ",", 2))
++  print("table.concat", table.concat(p, ".", 1, 2))
++  print("table.concat", table.concat(t))
++  print("table.concat", table.concat(t, ",", 2))
++  print("table.concat", table.concat(t, ".", 1, 2))
++end
++
++
++___''
++do
++  local p, t = tproxy{ "a", "b", "c" }
++  table.insert(p, "d")
++  print("table.insert", next(p), t[4])
++  table.insert(p, 1, "z")
++  print("table.insert", next(p),  t[1], t[2])
++  table.insert(p, 2, "y")
++  print("table.insert", next(p), t[1], t[2], p[3])
++  t = { "a", "b", "c" }
++  table.insert(t, "d")
++  print("table.insert", t[1], t[2], t[3], t[4])
++  table.insert(t, 1, "z")
++  print("table.insert", t[1], t[2], t[3], t[4], t[5])
++  table.insert(t, 2, "y")
++  print("table.insert", t[1], t[2], t[3], t[4], t[5])
++end
++
++
++___''
++do
++  local ps, s = tproxy{ "a", "b", "c", "d" }
++  local pd, d = tproxy{ "A", "B", "C", "D" }
++  table.move(ps, 1, 4, 1, pd)
++  print("table.move", next(pd), d[1], d[2], d[3], d[4])
++  pd, d = tproxy{ "A", "B", "C", "D" }
++  table.move(ps, 2, 4, 1, pd)
++  print("table.move", next(pd), d[1], d[2], d[3], d[4])
++  pd, d = tproxy{ "A", "B", "C", "D" }
++  table.move(ps, 2, 3, 4, pd)
++  print("table.move", next(pd), d[1], d[2], d[3], d[4], d[5])
++  table.move(ps, 2, 4, 1)
++  print("table.move", next(ps), s[1], s[2], s[3], s[4])
++  ps, s = tproxy{ "a", "b", "c", "d" }
++  table.move(ps, 2, 3, 4)
++  print("table.move", next(ps), s[1], s[2], s[3], s[4], s[5])
++  s = { "a", "b", "c", "d" }
++  d = { "A", "B", "C", "D" }
++  table.move(s, 1, 4, 1, d)
++  print("table.move", d[1], d[2], d[3], d[4])
++  d = { "A", "B", "C", "D" }
++  table.move(s, 2, 4, 1, d)
++  print("table.move", d[1], d[2], d[3], d[4])
++  d = { "A", "B", "C", "D" }
++  table.move(s, 2, 3, 4, d)
++  print("table.move", d[1], d[2], d[3], d[4], d[5])
++  table.move(s, 2, 4, 1)
++  print("table.move", s[1], s[2], s[3], s[4])
++  s = { "a", "b", "c", "d" }
++  table.move(s, 2, 3, 4)
++  print("table.move", s[1], s[2], s[3], s[4], s[5])
++end
++
++
++___''
++do
++  local p, t = tproxy{ "a", "b", "c", "d", "e" }
++  print("table.remove", table.remove(p))
++  print("table.remove", next(p), t[1], t[2], t[3], t[4], t[5])
++  print("table.remove", table.remove(p, 1))
++  print("table.remove", next(p), t[1], t[2], t[3], t[4])
++  print("table.remove", table.remove(p, 2))
++  print("table.remove", next(p), t[1], t[2], t[3])
++  print("table.remove", table.remove(p, 3))
++  print("table.remove", next(p), t[1], t[2], t[3])
++  p, t = tproxy{}
++  print("table.remove", table.remove(p))
++  print("table.remove", next(p), next(t))
++  t = { "a", "b", "c", "d", "e" }
++  print("table.remove", table.remove(t))
++  print("table.remove", t[1], t[2], t[3], t[4], t[5])
++  print("table.remove", table.remove(t, 1))
++  print("table.remove", t[1], t[2], t[3], t[4])
++  print("table.remove", table.remove(t, 2))
++  print("table.remove", t[1], t[2], t[3])
++  print("table.remove", table.remove(t, 3))
++  print("table.remove", t[1], t[2], t[3])
++  t = {}
++  print("table.remove", table.remove(t))
++  print("table.remove", next(t))
++end
++
++___''
++do
++  local p, t = tproxy{ 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 }
++  table.sort(p)
++  print("table.sort", next(p))
++  for i,v in ipairs(t) do
++    print("table.sort", i, v)
++  end
++  table.sort(p)
++  print("table.sort", next(p))
++  for i,v in ipairs(t) do
++    print("table.sort", i, v)
++  end
++  p, t = tproxy{ 9, 8, 7, 6, 5, 4, 3, 2, 1 }
++  table.sort(p)
++  print("table.sort", next(p))
++  for i,v in ipairs(t) do
++    print("table.sort", i, v)
++  end
++  table.sort(p, function(a, b) return a > b end)
++  print("table.sort", next(p))
++  for i,v in ipairs(t) do
++    print("table.sort", i, v)
++  end
++  p, t = tproxy{ 1, 1, 1, 1, 1 }
++  print("table.sort", next(p))
++  for i,v in ipairs(t) do
++    print("table.sort", i, v)
++  end
++  t = { 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 }
++  table.sort(t)
++  for i,v in ipairs(t) do
++    print("table.sort", i, v)
++  end
++  table.sort(t, function(a, b) return a > b end)
++  for i,v in ipairs(t) do
++    print("table.sort", i, v)
++  end
++end
++
++
++___''
++do
++  local p, t = tproxy{ "a", "b", "c" }
++  print("table.unpack", table.unpack(p))
++  print("table.unpack", table.unpack(p, 2))
++  print("table.unpack", table.unpack(p, 1, 2))
++  print("table.unpack", table.unpack(t))
++  print("table.unpack", table.unpack(t, 2))
++  print("table.unpack", table.unpack(t, 1, 2))
++end
++
++
++___''
++print("math.maxinteger", math.maxinteger+1 > math.maxinteger)
++print("math.mininteger", math.mininteger-1 < math.mininteger)
++
++
++___''
++print("math.tointeger", math.tointeger(0))
++print("math.tointeger", math.tointeger(math.pi))
++print("math.tointeger", math.tointeger("hello"))
++print("math.tointeger", math.tointeger(math.maxinteger+2.0))
++print("math.tointeger", math.tointeger(math.mininteger*2.0))
++
++
++___''
++print("math.type", math.type(0))
++print("math.type", math.type(math.pi))
++print("math.type", math.type("hello"))
++
++
++___''
++print("math.ult", math.ult(1, 2), math.ult(2, 1))
++print("math.ult", math.ult(-1, 2), math.ult(2, -1))
++print("math.ult", math.ult(-1, -2), math.ult(-2, -1))
++print("math.ult", pcall(math.ult, "x", 2))
++print("math.ult", pcall(math.ult, 1, 2.1))
++___''
++
++
++if utf8.len then
++  local unpack = table.unpack or unpack
++  local function utf8rt(s)
++    local t = { utf8.codepoint(s, 1, #s) }
++    local ps, cs = {}, {}
++    for p,c in utf8.codes(s) do
++      ps[#ps+1], cs[#cs+1] = p, c
++    end
++    print("utf8.codes", unpack(ps))
++    print("utf8.codes", unpack(cs))
++    print("utf8.codepoint", unpack(t))
++    print("utf8.len", utf8.len(s), #t, #s)
++    print("utf8.char", utf8.char(unpack(t)))
++  end
++  utf8rt("äöüßÄÖÜ")
++  utf8rt("abcdefg")
++  ___''
++  local s = "äöüßÄÖÜ"
++  print("utf8.offset", utf8.offset(s, 1, 1))
++  print("utf8.offset", utf8.offset(s, 2, 1))
++  print("utf8.offset", utf8.offset(s, 3, 1))
++  print("utf8.offset", pcall(utf8.offset, s, 3, 2))
++  print("utf8.offset", utf8.offset(s, 3, 3))
++  print("utf8.offset", utf8.offset(s, -1, 7))
++  print("utf8.offset", utf8.offset(s, -2, 7))
++  print("utf8.offset", utf8.offset(s, -3, 7))
++  print("utf8.offset", utf8.offset(s, -1))
++  ___''
++else
++  print("XXX: utf8 module not available")
++end
++
++
++if string.pack then
++  local format = "bBhHlLjJdc3z"
++  local s = string.pack(format, -128, 255, -32768, 65535, -2147483648, 4294967295, -32768, 65536, 1.25, "abc", "defgh")
++  print("string.unpack", string.unpack(format, s))
++  ___''
++else
++  print("XXX: string packing not available")
++end
++
++
++print("testing Lua API for Lua 5.1 ...")
++
++___''
++print("debug.getuservalue()", F(debug.getuservalue(false)))
++print("debug.setuservalue()", pcall(function()
++  debug.setuservalue(false, {})
++end))
++print("debug.setmetatable()", F(debug.setmetatable({}, {})))
++
++
++___''
++do
++   local t = setmetatable({}, {
++      __pairs = function() return pairs({ a = "a" }) end,
++   })
++   for k,v in pairs(t) do
++      print("pairs()", k, v)
++   end
++end
++
++
++___''
++do
++   local code = "print('hello world')\n"
++   local badcode = "print('blub\n"
++   print("load()", pcall(function() load(true) end))
++   print("load()", F(load(badcode)))
++   print("load()", F(load(code)))
++   print("load()", F(load(code, "[L]")))
++   print("load()", F(load(code, "[L]", "b")))
++   print("load()", F(load(code, "[L]", "t")))
++   print("load()", F(load(code, "[L]", "bt")))
++   local f = load(code, "[L]", "bt", {})
++   print("load()", pcall(f))
++   f = load(code, "[L]", "bt", { print = noprint })
++   print("load()", pcall(f))
++   local bytecode = string.dump(f)
++   print("load()", F(load(bytecode)))
++   print("load()", F(load(bytecode, "[L]")))
++   print("load()", F(load(bytecode, "[L]", "b")))
++   print("load()", F(load(bytecode, "[L]", "t")))
++   print("load()", F(load(bytecode, "[L]", "bt")))
++   f = load(bytecode, "[L]", "bt", {})
++   print("load()", pcall(f))
++   f = load(bytecode, "[L]", "bt", { print = noprint })
++   print("load()", pcall(f))
++   local function make_loader(code)
++      local mid = math.floor( #code/2 )
++      local array = { code:sub(1, mid), code:sub(mid+1) }
++      local i = 0
++      return function()
++         i = i + 1
++         return array[i]
++      end
++   end
++   print("load()", F(load(make_loader(badcode))))
++   print("load()", F(load(make_loader(code))))
++   print("load()", F(load(make_loader(code), "[L]")))
++   print("load()", F(load(make_loader(code), "[L]", "b")))
++   print("load()", F(load(make_loader(code), "[L]", "t")))
++   print("load()", F(load(make_loader(code), "[L]", "bt")))
++   f = load(make_loader(code), "[L]", "bt", {})
++   print("load()", pcall(f))
++   f = load(make_loader(code), "[L]", "bt", { print = noprint })
++   print("load()", pcall(f))
++   print("load()", F(load(make_loader(bytecode))))
++   print("load()", F(load(make_loader(bytecode), "[L]")))
++   print("load()", F(load(make_loader(bytecode), "[L]", "b")))
++   print("load()", F(load(make_loader(bytecode), "[L]", "t")))
++   print("load()", F(load(make_loader(bytecode), "[L]", "bt")))
++   f = load(make_loader(bytecode), "[L]", "bt", {})
++   print("load()", pcall(f))
++   f = load(make_loader(bytecode), "[L]", "bt", { print = noprint })
++   print("load()", pcall(f))
++   writefile("good.lua", code)
++   writefile("bad.lua", badcode)
++   writefile("good.luac", bytecode, true)
++   print("loadfile()", F(loadfile("bad.lua")))
++   print("loadfile()", F(loadfile("good.lua")))
++   print("loadfile()", F(loadfile("good.lua", "b")))
++   print("loadfile()", F(loadfile("good.lua", "t")))
++   print("loadfile()", F(loadfile("good.lua", "bt")))
++   f = loadfile("good.lua", "bt", {})
++   print("loadfile()", pcall(f))
++   f = loadfile("good.lua", "bt", { print = noprint })
++   print("loadfile()", pcall(f))
++   print("loadfile()", F(loadfile("good.luac")))
++   print("loadfile()", F(loadfile("good.luac", "b")))
++   print("loadfile()", F(loadfile("good.luac", "t")))
++   print("loadfile()", F(loadfile("good.luac", "bt")))
++   f = loadfile("good.luac", "bt", {})
++   print("loadfile()", pcall(f))
++   f = loadfile("good.luac", "bt", { print = noprint })
++   print("loadfile()", pcall(f))
++   os.remove("good.lua")
++   os.remove("bad.lua")
++   os.remove("good.luac")
++end
++
++
++___''
++do
++   local function func(throw)
++      if throw then
++         error("argh")
++      else
++         return 1, 2, 3
++      end
++   end
++   local function tb(err) return "|"..err.."|" end
++   print("xpcall()", xpcall(func, debug.traceback, false))
++   print("xpcall()", xpcall(func, debug.traceback, true))
++   print("xpcall()", xpcall(func, tb, true))
++   if mode ~= "module" then
++     local function func2(cb)
++       print("xpcall()", xpcall(cb, debug.traceback, "str"))
++     end
++     local function func3(cb)
++       print("pcall()", pcall(cb, "str"))
++     end
++     local function cb(arg)
++        coroutine.yield(2)
++        return arg
++     end
++     local c = coroutine.wrap(func2)
++     print("xpcall()", c(cb))
++     print("xpcall()", c())
++     local c = coroutine.wrap(func3)
++     print("pcall()", c(cb))
++     print("pcall()", c())
++   end
++end
++
++
++___''
++do
++   local t = setmetatable({ 1 }, { __len = function() return 5 end })
++   print("rawlen()", rawlen(t), rawlen("123"))
++end
++
++
++___''
++print("os.execute()", os.execute("exit 1"))
++io.flush()
++print("os.execute()", os.execute("echo 'hello world!'"))
++io.flush()
++print("os.execute()", os.execute("no_such_file"))
++
++
++___''
++do
++   local t = table.pack("a", nil, "b", nil)
++   print("table.(un)pack()", t.n, table.unpack(t, 1, t.n))
++end
++
++
++___''
++do
++   print("coroutine.running()", F(coroutine.wrap(function()
++      return coroutine.running()
++   end)()))
++   print("coroutine.running()", F(coroutine.running()))
++   local main_co, co1, co2 = coroutine.running()
++   -- coroutine.yield
++   if mode ~= "module" then
++     print("coroutine.yield()", pcall(function()
++        coroutine.yield(1, 2, 3)
++     end))
++   end
++   print("coroutine.yield()", coroutine.wrap(function()
++      coroutine.yield(1, 2, 3)
++   end)())
++   print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3))
++   co1 = coroutine.create(function(a, b, c)
++      print("coroutine.resume()", a, b, c)
++      return a, b, c
++   end)
++   print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3))
++   co1 = coroutine.create(function()
++      print("coroutine.status()", "[co1] main is", coroutine.status(main_co))
++      print("coroutine.status()", "[co1] co2 is", coroutine.status(co2))
++   end)
++   co2 = coroutine.create(function()
++      print("coroutine.status()", "[co2] main is", coroutine.status(main_co))
++      print("coroutine.status()", "[co2] co2 is", coroutine.status(co2))
++      coroutine.yield()
++      coroutine.resume(co1)
++   end)
++   print("coroutine.status()", coroutine.status(main_co))
++   print("coroutine.status()", coroutine.status(co2))
++   coroutine.resume(co2)
++   print("coroutine.status()", F(coroutine.status(co2)))
++   coroutine.resume(co2)
++   print("coroutine.status()", F(coroutine.status(co2)))
++end
++
++
++___''
++print("math.log()", math.log(1000))
++print("math.log()", math.log(1000, 10))
++
++
++___''
++do
++   local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()"
++   print(prefix, package.searchpath("no.such.module", path))
++   print(prefix, package.searchpath("no.such.module", ""))
++   print(prefix, package.searchpath("compat53", path))
++   print(prefix, package.searchpath("no:such:module", path, ":", "|"))
++end
++
++
++___''
++if mode ~= "module" then
++   local function mod_func() return {} end
++   local function my_searcher(name)
++      if name == "my.module" then
++         print("package.searchers", "my.module found")
++         return mod_func
++      end
++   end
++   local function my_searcher2(name)
++      if name == "my.module" then
++         print("package.searchers", "my.module found 2")
++         return mod_func
++      end
++   end
++   table.insert(package.searchers, my_searcher)
++   require("my.module")
++   package.loaded["my.module"] = nil
++   local new_s = { my_searcher2 }
++   for i,f in ipairs(package.searchers) do
++      new_s[i+1] = f
++   end
++   package.searchers = new_s
++   require("my.module")
++end
++
++
++___''
++do
++   print("string.find()", string.find("abc\0abc\0abc", "[^a\0]+"))
++   print("string.find()", string.find("abc\0abc\0abc", "%w+\0", 5))
++   for x in string.gmatch("abc\0def\0ghi", "[^\0]+") do
++      print("string.gmatch()", x)
++   end
++   for x in string.gmatch("abc\0def\0ghi", "%w*\0") do
++      print("string.gmatch()", #x)
++   end
++   print("string.gsub()", string.gsub("abc\0def\0ghi", "[\0]", "X"))
++   print("string.gsub()", string.gsub("abc\0def\0ghi", "%w*\0", "X"))
++   print("string.gsub()", string.gsub("abc\0def\0ghi", "%A", "X"))
++   print("string.match()", string.match("abc\0abc\0abc", "([^\0a]+)"))
++   print("string.match()", #string.match("abc\0abc\0abc", ".*\0"))
++   print("string.rep()", string.rep("a", 0))
++   print("string.rep()", string.rep("b", 1))
++   print("string.rep()", string.rep("c", 4))
++   print("string.rep()", string.rep("a", 0, "|"))
++   print("string.rep()", string.rep("b", 1, "|"))
++   print("string.rep()", string.rep("c", 4, "|"))
++   local _tostring = tostring
++   function tostring(v)
++      if type(v) == "number" then
++         return "(".._tostring(v)..")"
++      else
++         return _tostring(v)
++      end
++   end
++   print("string.format()", string.format("%q", "\"\\\0000\0010\002\r\n0\t0\""))
++   print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {}))
++   print("string.format()", string.format("%-3f %%%s %%s", 3.1, true))
++   print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil))
++   print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout))
++   print("string.format()", pcall(function()
++      print("string.format()", string.format("%d %%s", {}))
++   end))
++   tostring = _tostring
++end
++
++
++___''
++do
++   print("io.write()", io.type(io.write("hello world\n")))
++   local f = assert(io.tmpfile())
++   print("file:write()", io.type(f:write("hello world\n")))
++   f:close()
++end
++
++
++___''
++do
++   writefile("data.txt", "123 18.8 hello world\ni'm here\n")
++   io.input("data.txt")
++   print("io.read()", io.read("*n", "*number", "*l", "*a"))
++   io.input("data.txt")
++   print("io.read()", io.read("n", "number", "l", "a"))
++   io.input(io.stdin)
++   if mode ~= "module" then
++     local f = assert(io.open("data.txt", "r"))
++     print("file:read()", f:read("*n", "*number", "*l", "*a"))
++     f:close()
++     f = assert(io.open("data.txt", "r"))
++     print("file:read()", f:read("n", "number", "l", "a"))
++     f:close()
++   end
++   os.remove("data.txt")
++end
++
++
++___''
++do
++   writefile("data.txt", "123 18.8 hello world\ni'm here\n")
++   for a,b in io.lines(self, 2, "*l") do
++      print("io.lines()", a, b)
++      break
++   end
++   for l in io.lines(self) do
++      print("io.lines()", l)
++      break
++   end
++   for n1,n2,rest in io.lines("data.txt", "*n", "n", "*a") do
++      print("io.lines()", n1, n2, rest)
++   end
++   for l in io.lines("data.txt") do
++      print("io.lines()", l)
++   end
++   print("io.lines()", pcall(function()
++      for l in io.lines("data.txt", "*x") do print(l) end
++   end))
++   print("io.lines()", pcall(function()
++      for l in io.lines("no_such_file.txt") do print(l) end
++   end))
++   if mode ~= "module" then
++     local f = assert(io.open(self, "r"))
++     for a,b in f:lines(2, "*l") do
++        print("file:lines()", a, b)
++        break
++     end
++     f:close()
++     f = assert(io.open("data.txt", "r"))
++     for n1,n2,rest in f:lines("*n", "n", "*a") do
++        print("file:lines()", n1, n2, rest)
++     end
++     f:close()
++     f = assert(io.open("data.txt", "r"))
++     for l in f:lines() do
++        print("file:lines()", l)
++     end
++     f:close()
++     print("file:lines()", pcall(function()
++        for l in f:lines() do print(l) end
++     end))
++     print("file:lines()", pcall(function()
++        local f = assert(io.open("data.txt", "r"))
++        for l in f:lines("*l", "*x") do print(l) end
++        f:close()
++     end))
++   end
++   os.remove("data.txt")
++end
++___''
++
++
++print("testing C API ...")
++local mod = require("testmod")
++___''
++print("isinteger", mod.isinteger(1))
++print("isinteger", mod.isinteger(0))
++print("isinteger", mod.isinteger(1234567))
++print("isinteger", mod.isinteger(12.3))
++print("isinteger", mod.isinteger(math.huge))
++print("isinteger", mod.isinteger(math.sqrt(-1)))
++
++
++___''
++print("rotate", mod.rotate(1, 1, 2, 3, 4, 5, 6))
++print("rotate", mod.rotate(-1, 1, 2, 3, 4, 5, 6))
++print("rotate", mod.rotate(4, 1, 2, 3, 4, 5, 6))
++print("rotate", mod.rotate(-4, 1, 2, 3, 4, 5, 6))
++
++
++___''
++print("strtonum", mod.strtonum("+123"))
++print("strtonum", mod.strtonum(" 123 "))
++print("strtonum", mod.strtonum("-1.23"))
++print("strtonum", mod.strtonum(" 123 abc"))
++print("strtonum", mod.strtonum("jkl"))
++
++
++___''
++local a, b, c = mod.requiref()
++print("requiref", type(a), type(b), type(c),
++      a.boolean, b.boolean, c.boolean,
++      type(requiref1), type(requiref2), type(requiref3))
++
++___''
++local proxy, backend = {}, {}
++setmetatable(proxy, { __index = backend, __newindex = backend })
++print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
++print("geti/seti", mod.getseti(proxy, 1))
++print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
++print("geti/seti", mod.getseti(proxy, 1))
++print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
++
++-- tests for Lua 5.1
++___''
++print("tonumber", mod.tonumber(12))
++print("tonumber", mod.tonumber("12"))
++print("tonumber", mod.tonumber("0"))
++print("tonumber", mod.tonumber(false))
++print("tonumber", mod.tonumber("error"))
++
++___''
++print("tointeger", mod.tointeger(12))
++print("tointeger", mod.tointeger(-12))
++print("tointeger", mod.tointeger(12.1))
++print("tointeger", mod.tointeger(12.9))
++print("tointeger", mod.tointeger(-12.1))
++print("tointeger", mod.tointeger(-12.9))
++print("tointeger", mod.tointeger("12"))
++print("tointeger", mod.tointeger("0"))
++print("tointeger", mod.tointeger(math.pi))
++print("tointeger", mod.tointeger(false))
++print("tointeger", mod.tointeger("error"))
++
++___''
++print("len", mod.len("123"))
++print("len", mod.len({ 1, 2, 3}))
++print("len", pcall(mod.len, true))
++local ud, meta = mod.newproxy()
++meta.__len = function() return 5 end
++print("len", mod.len(ud))
++meta.__len = function() return true end
++print("len", pcall(mod.len, ud))
++
++___''
++print("copy", mod.copy(true, "string", {}, 1))
++
++___''
++print("rawgetp/rawsetp", mod.rawxetp())
++print("rawgetp/rawsetp", mod.rawxetp("I'm back"))
++
++___''
++print("globals", F(mod.globals()), mod.globals() == _G)
++
++___''
++local t = {}
++print("getsubtable", F(mod.subtable(t)))
++local x, msg = mod.subtable(t)
++print("getsubtable", F(x, msg, x == t.xxx))
++
++___''
++print("udata", F(mod.udata()))
++print("udata", mod.udata("nosuchtype"))
++
++___''
++print("uservalue", F(mod.uservalue()))
++
++___''
++print("upvalues", mod.getupvalues())
++
++___''
++print("absindex", mod.absindex("hi", true))
++
++___''
++print("arith", mod.arith(2, 1))
++print("arith", mod.arith(3, 5))
++
++___''
++print("compare", mod.compare(1, 1))
++print("compare", mod.compare(2, 1))
++print("compare", mod.compare(1, 2))
++
++___''
++print("tolstring", mod.tolstring("string"))
++local t = setmetatable({}, {
++  __tostring = function(v) return "mytable" end
++})
++print("tolstring", mod.tolstring(t))
++local t = setmetatable({}, {
++  __tostring = function(v) return nil end
++})
++print("tolstring", pcall(mod.tolstring, t))
++local ud, meta = mod.newproxy()
++meta.__name = "XXX"
++print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy"))
++
++___''
++print("pushstring", mod.pushstring())
++
++___''
++print("Buffer", mod.buffer())
++
++___''
++print("execresult", mod.exec("exit 0"))
++print("execresult", mod.exec("exit 1"))
++print("execresult", mod.exec("exit 25"))
++
++___''
++do
++  local bin = string.dump(function() end)
++  local modes = { "t", "b", "bt" }
++  local codes = {
++    "", "return true", bin, "invalidsource", "\27invalidbinary"
++  }
++  for _,m in ipairs(modes) do
++    for i,c in ipairs(codes) do
++      print("loadbufferx", m, i, F(mod.loadstring(c, m)))
++    end
++  end
++
++  ___''
++  local bom = "\239\187\191"
++  local shebang = "#!/usr/bin/env lua\n"
++  codes[#codes+1] = bom .. shebang .. "return true"
++  codes[#codes+1] = bom .. shebang .. bin
++  codes[#codes+1] = bom .. shebang .. "invalidsource"
++  codes[#codes+1] = bom .. shebang .. "\027invalidbinary"
++  for _,m in ipairs(modes) do
++    for i,c in ipairs(codes) do
++      print("loadfilex", m, i, F(mod.loadfile(c, m)))
++    end
++  end
++end
++___''
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/tests/testmod.c luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/tests/testmod.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/tests/testmod.c	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/tests/testmod.c	2019-02-13 11:53:29.078405237 +0100
+@@ -0,0 +1,352 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include "compat-5.3.h"
++
++
++static int test_isinteger (lua_State *L) {
++  lua_pushboolean(L, lua_isinteger(L, 1));
++  return 1;
++}
++
++
++static int test_rotate (lua_State *L) {
++  int r = (int)luaL_checkinteger(L, 1);
++  int n = lua_gettop(L)-1;
++  luaL_argcheck(L, (r < 0 ? -r : r) <= n, 1, "not enough arguments");
++  lua_rotate(L, 2, r);
++  return n;
++}
++
++
++static int test_str2num (lua_State *L) {
++  const char *s = luaL_checkstring(L, 1);
++  size_t len = lua_stringtonumber(L, s);
++  if (len == 0)
++    lua_pushnumber(L, 0);
++  lua_pushinteger(L, (lua_Integer)len);
++  return 2;
++}
++
++
++static int my_mod (lua_State *L ) {
++  lua_newtable(L);
++  lua_pushboolean(L, 1);
++  lua_setfield(L, -2, "boolean");
++  return 1;
++}
++
++static int test_requiref (lua_State *L) {
++  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
++  lua_newtable(L);
++  lua_pushboolean(L, 0);
++  lua_setfield(L, -2, "boolean");
++  lua_setfield(L, -2, "requiref3");
++  lua_pop(L, 1);
++  luaL_requiref(L, "requiref1", my_mod, 0);
++  luaL_requiref(L, "requiref2", my_mod, 1);
++  luaL_requiref(L, "requiref3", my_mod, 1);
++  return 3;
++}
++
++static int test_getseti (lua_State *L) {
++  lua_Integer k = luaL_checkinteger(L, 2);
++  lua_Integer n = 0;
++  if (lua_geti(L, 1, k) == LUA_TNUMBER) {
++    n = lua_tointeger(L, -1);
++  } else {
++    lua_pop(L, 1);
++    lua_pushinteger(L, n);
++  }
++  lua_pushinteger(L, n+1);
++  lua_seti(L, 1, k);
++  return 1;
++}
++
++
++/* additional tests for Lua5.1 */
++#define NUP 3
++
++static int test_newproxy (lua_State *L) {
++  lua_settop(L, 0);
++  lua_newuserdata(L, 0);
++  lua_newtable(L);
++  lua_pushvalue(L, -1);
++  lua_pushboolean(L, 1);
++  lua_setfield(L, -2, "__gc");
++  lua_setmetatable(L, -3);
++  return 2;
++}
++
++static int test_absindex (lua_State *L) {
++  int i = 1;
++  for (i = 1; i <= NUP; ++i)
++    lua_pushvalue(L, lua_absindex(L, lua_upvalueindex(i)));
++  lua_pushvalue(L, lua_absindex(L, LUA_REGISTRYINDEX));
++  lua_pushstring(L, lua_typename(L, lua_type(L, lua_absindex(L, -1))));
++  lua_replace(L, lua_absindex(L, -2));
++  lua_pushvalue(L, lua_absindex(L, -2));
++  lua_pushvalue(L, lua_absindex(L, -4));
++  lua_pushvalue(L, lua_absindex(L, -6));
++  i += 3;
++  lua_pushvalue(L, lua_absindex(L, 1));
++  lua_pushvalue(L, lua_absindex(L, 2));
++  lua_pushvalue(L, lua_absindex(L, 3));
++  i += 3;
++  return i;
++}
++
++static int test_arith (lua_State *L) {
++  lua_settop(L, 2);
++  lua_pushvalue(L, 1);
++  lua_pushvalue(L, 2);
++  lua_arith(L, LUA_OPADD);
++  lua_pushvalue(L, 1);
++  lua_pushvalue(L, 2);
++  lua_arith(L, LUA_OPSUB);
++  lua_pushvalue(L, 1);
++  lua_pushvalue(L, 2);
++  lua_arith(L, LUA_OPMUL);
++  lua_pushvalue(L, 1);
++  lua_pushvalue(L, 2);
++  lua_arith(L, LUA_OPDIV);
++  lua_pushvalue(L, 1);
++  lua_pushvalue(L, 2);
++  lua_arith(L, LUA_OPMOD);
++  lua_pushvalue(L, 1);
++  lua_pushvalue(L, 2);
++  lua_arith(L, LUA_OPPOW);
++  lua_pushvalue(L, 1);
++  lua_arith(L, LUA_OPUNM);
++  return lua_gettop(L)-2;
++}
++
++static int test_compare (lua_State *L) {
++  luaL_checknumber(L, 1);
++  luaL_checknumber(L, 2);
++  lua_settop(L, 2);
++  lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPEQ));
++  lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLT));
++  lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLE));
++  return 3;
++}
++
++static int test_globals (lua_State *L) {
++  lua_pushglobaltable(L);
++  return 1;
++}
++
++static int test_tonumber (lua_State *L) {
++  int isnum = 0;
++  lua_Number n = lua_tonumberx(L, 1, &isnum);
++  if (!isnum)
++    lua_pushnil(L);
++  else
++    lua_pushnumber(L, n);
++  return 1;
++}
++
++static int test_tointeger (lua_State *L) {
++  int isnum = 0;
++  lua_Integer n = lua_tointegerx(L, 1, &isnum);
++  if (!isnum)
++    lua_pushnil(L);
++  else
++    lua_pushinteger(L, n);
++  lua_pushinteger(L, lua_tointeger(L, 1));
++  return 2;
++}
++
++static int test_len (lua_State *L) {
++  luaL_checkany(L, 1);
++  lua_len(L, 1);
++  lua_pushinteger(L, luaL_len(L, 1));
++  return 2;
++}
++
++static int test_copy (lua_State *L) {
++  int args = lua_gettop(L);
++  if (args >= 2) {
++    int i = 0;
++    for (i = args-1; i > 0; --i)
++      lua_copy(L, args, i);
++  }
++  return args;
++}
++
++/* need an address */
++static char const dummy = 0;
++
++static int test_rawxetp (lua_State *L) {
++  if (lua_gettop(L) > 0)
++    lua_pushvalue(L, 1);
++  else
++    lua_pushliteral(L, "hello again");
++  lua_rawsetp(L, LUA_REGISTRYINDEX, &dummy);
++  lua_settop(L, 0);
++  lua_rawgetp(L, LUA_REGISTRYINDEX, &dummy);
++  return 1;
++}
++
++static int test_udata (lua_State *L) {
++  const char *tname = luaL_optstring(L, 1, "utype1");
++  void *u1 = lua_newuserdata(L, 1);
++  int u1pos = lua_gettop(L);
++  void *u2 = lua_newuserdata(L, 1);
++  int u2pos = lua_gettop(L);
++  luaL_newmetatable(L, "utype1");
++  luaL_newmetatable(L, "utype2");
++  lua_pop(L, 2);
++  luaL_setmetatable(L, "utype2");
++  lua_pushvalue(L, u1pos);
++  luaL_setmetatable(L, "utype1");
++  lua_pop(L, 1);
++  (void)u1;
++  (void)u2;
++  lua_pushlightuserdata(L, luaL_testudata(L, u1pos, tname));
++  lua_pushlightuserdata(L, luaL_testudata(L, u2pos, tname));
++  luaL_getmetatable(L, "utype1");
++  lua_getfield(L, -1, "__name");
++  lua_replace(L, -2);
++  return 3;
++}
++
++static int test_subtable (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++  lua_settop(L, 1);
++  if (luaL_getsubtable(L, 1, "xxx")) {
++    lua_pushliteral(L, "oldtable");
++  } else {
++    lua_pushliteral(L, "newtable");
++  }
++  return 2;
++}
++
++static int test_uservalue (lua_State *L) {
++  void *udata = lua_newuserdata(L, 1);
++  int ui = lua_gettop(L);
++  lua_newtable(L);
++  lua_setuservalue(L, ui);
++  lua_pushinteger(L, lua_getuservalue(L, ui));
++  (void)udata;
++  return 2;
++}
++
++static int test_upvalues (lua_State *L) {
++  int i = 1;
++  for (i = 1; i <= NUP; ++i)
++    lua_pushvalue(L, lua_upvalueindex(i));
++  return NUP;
++}
++
++static int test_tolstring (lua_State *L) {
++  size_t len = 0;
++  luaL_tolstring(L, 1, &len);
++  lua_pushinteger(L, (int)len);
++  return 2;
++}
++
++static int test_pushstring (lua_State *L) {
++  lua_pushstring(L, lua_pushliteral(L, "abc"));
++  lua_pushstring(L, lua_pushlstring(L, "abc", 2));
++  lua_pushstring(L, lua_pushlstring(L, NULL, 0));
++  lua_pushstring(L, lua_pushstring(L, "abc"));
++  lua_pushboolean(L, NULL == lua_pushstring(L, NULL));
++  return 10;
++}
++
++static int test_buffer (lua_State *L) {
++  luaL_Buffer b;
++  char *p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE+1);
++  p[0] = 'a';
++  p[1] = 'b';
++  luaL_addsize(&b, 2);
++  luaL_addstring(&b, "c");
++  lua_pushliteral(L, "d");
++  luaL_addvalue(&b);
++  luaL_addchar(&b, 'e');
++  luaL_pushresult(&b);
++  return 1;
++}
++
++static int test_exec (lua_State *L) {
++  const char *cmd = luaL_checkstring(L, 1);
++  return luaL_execresult(L, system(cmd));
++}
++
++static int test_loadstring (lua_State *L) {
++  size_t len = 0;
++  char const* s = luaL_checklstring(L, 1, &len);
++  char const* mode = luaL_optstring(L, 2, "bt");
++  lua_pushinteger(L, luaL_loadbufferx(L, s, len, s, mode));
++  return 2;
++}
++
++static int test_loadfile (lua_State *L) {
++  char filename[L_tmpnam+1] = { 0 };
++  size_t len = 0;
++  char const* s = luaL_checklstring(L, 1, &len);
++  char const* mode = luaL_optstring(L, 2, "bt");
++  if (tmpnam(filename)) {
++    FILE* f = fopen(filename, "wb");
++    if (f) {
++      fwrite(s, 1, len, f);
++      fclose(f);
++      lua_pushinteger(L, luaL_loadfilex(L, filename, mode));
++      remove(filename);
++      return 2;
++    } else
++      remove(filename);
++  }
++  return 0;
++}
++
++
++static const luaL_Reg funcs[] = {
++  { "isinteger", test_isinteger },
++  { "rotate", test_rotate },
++  { "strtonum", test_str2num },
++  { "requiref", test_requiref },
++  { "getseti", test_getseti },
++  { "newproxy", test_newproxy },
++  { "arith", test_arith },
++  { "compare", test_compare },
++  { "tonumber", test_tonumber },
++  { "tointeger", test_tointeger },
++  { "len", test_len },
++  { "copy", test_copy },
++  { "rawxetp", test_rawxetp },
++  { "subtable", test_subtable },
++  { "udata", test_udata },
++  { "uservalue", test_uservalue },
++  { "globals", test_globals },
++  { "tolstring", test_tolstring },
++  { "pushstring", test_pushstring },
++  { "buffer", test_buffer },
++  { "exec", test_exec },
++  { "loadstring", test_loadstring },
++  { "loadfile", test_loadfile },
++  { NULL, NULL }
++};
++
++static const luaL_Reg more_funcs[] = {
++  { "getupvalues", test_upvalues },
++  { "absindex", test_absindex },
++  { NULL, NULL }
++};
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++int luaopen_testmod (lua_State *L) {
++  int i = 1;
++  luaL_newlib(L, funcs);
++  for (i = 1; i <= NUP; ++i)
++    lua_pushnumber(L, i);
++  luaL_setfuncs(L, more_funcs, NUP);
++  return 1;
++}
++#ifdef __cplusplus
++}
++#endif
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/.travis.yml luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/.travis.yml
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/deps/lua-compat/.travis.yml	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/deps/lua-compat/.travis.yml	2019-02-13 11:53:29.075071941 +0100
+@@ -0,0 +1,47 @@
++language: c
++compiler: gcc
++
++sudo: false
++
++env:
++  - LUA="lua=5.1"
++  - LUA="lua=5.1" EXTERNAL=true
++  - LUA="lua=5.1" COMPILER="g++"
++  - LUA="lua=5.1" EXTERNAL=true COMPILER="g++"
++  - LUA="luajit=@v2.1 --compat=none"
++  - LUA="luajit=@v2.1 --compat=none" EXTERNAL=true
++  - LUA="luajit=@v2.1 --compat=all"
++  - LUA="luajit=@v2.1 --compat=all" EXTERNAL=true
++  - LUA="lua=5.2"
++  - LUA="lua=5.2" EXTERNAL=true
++  - LUA="lua=5.2" COMPILER="g++"
++  - LUA="lua=5.2" EXTERNAL=true COMPILER="g++"
++
++branches:
++  only:
++    - master
++
++git:
++  depth: 3
++
++notifications:
++  email: false
++
++before_install:
++  - pip install --user hererocks
++  - hererocks old --$LUA
++  - test -e old/bin/lua || (cd old/bin && ln -s luajit* lua)
++  - hererocks new --lua=5.3
++
++install:
++  - export CC="${COMPILER:-gcc}" DEF="" SRC="" CFLAGS="-Wall -Wextra -Ic-api -O2 -fPIC"
++  - if [ "x${EXTERNAL:-}" = xtrue ]; then DEF="-DCOMPAT53_PREFIX=compat53" SRC="c-api/compat-5.3.c"; fi
++  - ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/testmod.so tests/testmod.c ${SRC}
++  - ${CC} ${CFLAGS} -Inew/include ${DEF} -shared -o new/testmod.so tests/testmod.c ${SRC}
++  - gcc ${CFLAGS} -Iold/include ${DEF} -shared -o old/compat53.so ltablib.c lutf8lib.c lstrlib.c ${SRC}
++
++script:
++  - (cd old && bin/lua ../tests/test.lua) > old.txt
++  - (cd new && bin/lua ../tests/test.lua) > new.txt
++  - diff old.txt new.txt || true
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/asn1.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/asn1.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/asn1.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/asn1.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,209 +0,0 @@
+----
+--- Provide asn1_object, asn1_string, asn1_object as lua object.
+--- Sometime when you want to custome x509, you maybe need to use this.
+---
+--- @module asn1
+--- @usage
+---  asn1 = require('openssl').asn1
+---
+-
+-do  -- define module function
+-
+---- Create asn1_object object
+---
+--- @tparam string name_or_oid  short name,long name or oid string
+--- @tparam[opt] boolean no_name  true for only oid string, default is false
+--- @treturn asn1_object mapping to ASN1_OBJECT in openssl
+---
+--- @see asn1_object
+-function new_object() end
+-
+---- Create asn1_object object
+---
+--- @tparam integer nid ident to asn1_object
+--- @treturn asn1_object mapping to ASN1_OBJECT in openssl
+---
+--- @see asn1_object
+-function new_object() end
+-
+---- Create asn1_object object
+---
+--- @tparam table options have sn, ln, oid keys to create asn1_object
+--- @treturn asn1_object mapping to ASN1_OBJECT in openssl
+---
+--- @see asn1_object
+-function new_object() end
+-
+---- Create asn1_string object
+---
+--- <br/><p> asn1_string object support types:   "integer", "enumerated", "bit", "octet", "utf8",
+--- "numeric", "printable", "t61", "teletex", "videotex", "ia5", "graphics", "iso64",
+--- "visible", "general", "unversal", "bmp", "utctime" </p>
+---
+--- @tparam string data to create new asn1_string
+--- @tparam[opt] string type asn1 string type, defult with 'utf8'
+--- @see asn1_string
+-function new_string() end
+-
+---- get nid for txt, which can be short name, long name, or numerical oid
+---
+--- @tparam string txt which get to nid
+--- @treturn integer nid or nil on fail
+-function txt2nid() end
+-
+---- make tag, class number to string
+---
+--- @tparam number clsortag which to string
+--- @tparam string range only accept 'class' or 'tag'
+-function tostring() end
+-
+---- parse der encoded string
+--- @tparam string der string
+--- @tparam[opt=1] number start offset to parse
+--- @tparam[opt=-i] number stop offset to parse
+---  this like string.sub()
+--- @treturn[1] number tag
+--- @treturn[1] number class
+--- @treturn[1] number parsed data start offset
+--- @treturn[1] number parsed data stop offset
+--- @treturn[1] boolean true for constructed data
+--- @treturn[2] nil for fail
+--- @treturn[2] string error msg
+--- @treturn[2] number inner error code
+-function get_object() end
+-
+---- do der encode and return encoded string partly head or full
+--- @tparam number tag
+--- @tparam number class
+--- @tparam[opt=nil] number|string length or date to encode, defualt will make
+--- indefinite length constructed
+--- @tparam[opt=nil] boolean constructed or not
+--- @treturn string der encoded string or head when not give data
+-function put_object() end
+-
+-end
+-
+-do  -- define class
+-
+---- openssl.asn1_object object
+--- @type asn1_object
+---
+-do  -- defint asn1_object
+-
+---- get nid of asn1_object.
+---
+--- @treturn integer nid of asn1_object
+---
+-function nid() end
+-
+---- get name of asn1_object.
+---
+--- @treturn string short name of asn1_object
+--- @treturn string long name of asn1_object
+---
+-function name() end
+-
+---- get short name of asn1_object.
+---
+--- @treturn string short name of asn1_object
+---
+-function sn() end
+-
+---- get long name of asn1_object.
+---
+--- @treturn string long name of asn1_object
+---
+-function ln() end
+-
+---- get text of asn1_object.
+---
+--- @tparam[opt] boolean no_name true for only oid or name, default with false
+--- @treturn string long or short name, even oid of asn1_object
+---
+-function txt() end
+-
+---- compare two asn1_objects, if equals return true
+---
+--- @tparam asn1_object another to compre
+--- @treturn boolean true if equals
+---
+-function __eq(another) end
+-
+---- make a clone of asn1_object
+---
+--- @treturn asn1_object clone for self
+-function dup() end
+-
+---- get data of asn1_object
+---
+--- @treturn string asn1_object data
+-function data() end
+-
+-end
+-
+-
+---- openssl.asn1_string object
+--- @type asn1_string
+-
+-do
+-
+---- get type of asn1_string
+---
+--- @treturn string type of asn1_string
+--- @see new_string
+-function type() end
+-
+---- get data of asn1_string
+---
+--- @treturn string raw data of asn1_string
+-function data() end
+-
+---- set data of asn1_string
+---
+--- @tparam string data set to asn1_string
+--- @treturn boolean success if value set true, or follow by errmsg
+--- @treturn string fail error message
+-function data() end
+-
+---- get data as utf8 encode string
+---
+--- @treturn string utf8 encoded string
+-function toutf8() end
+-
+---- get data as printable encode string
+---
+--- @treturn string printable encoded string
+-function print() end
+-
+---- duplicate a new asn1_string
+---
+--- @treturn asn1_string clone for self
+-function dup() end
+-
+---- get length two asn1_string
+---
+--- @treturn integer length of asn1_string
+--- @usage
+---  local astr = asn1.new_string('ABCD')
+---  print('length:',#astr)
+---  print('length:',astr:length())
+---  assert(#astr==astr:length,"must equals")
+-function length() end
+-
+---- compare two asn1_string, if equals return true
+---
+--- @tparam asn1_string another to compre
+--- @treturn boolean true if equals
+--- @usage
+---  local obj = astr:dup()
+---  assert(obj==astr, "must equals")
+-function __eq(another) end
+-
+---- convert asn1_string to lua string
+---
+--- @treturn string result format match with type:data
+-function __tostring() end
+-
+-end
+-
+-end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/bio.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/bio.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/bio.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/bio.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,147 +0,0 @@
+-------------
+--- Provide bio module.
+--- bio object mapping to BIO in openssl
+--- openssl.bio is a help object, it is useful, but rarely use.
+--- @module bio
+--- @usage
+---  bio = require'openssl'.bio
+-
+-do --define module function
+-
+---- make string as bio object
+--- same with bio.mem, implication by metatable '__call'
+--- @tparam[opt=nil] string data
+--- @treturn bio
+-function openssl.bio() end
+-
+---- make string as bio object
+--- @tparam[opt=nil] string data, it will be memory buffer data
+--- @treturn bio it can be input or output object
+-function mem() end
+-
+---- make tcp bio from socket fd
+--- @tparam number fd
+--- @tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
+--- @treturn bio
+-function socket() end
+-
+---- make dgram bio from socket fd
+--- @tparam number fd
+--- @tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
+--- @treturn bio
+-function dgram() end
+-
+---- make socket or file bio with fd
+--- @tparam number fd
+--- @tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
+--- @treturn bio
+-function fd() end
+-
+---- make file object with file name or path
+--- @tparam string file
+--- @tparam[opt='r'] string mode
+--- @treturn bio
+-function file() end
+-
+---- make tcp client socket
+--- @tparam string host_addr addrees like 'host:port'
+--- @tparam[opt=true] boolean connect default connect immediately
+--- @treturn bio
+-function connect() end
+-
+---- make tcp listen socket 
+--- @tparam string host_port address like 'host:port'
+--- @treturn bio 
+-function accept() end
+-
+---- Create base64 or buffer bio, which can append to an io BIO object
+--- @tparam string mode support 'base64' or 'buffer'
+--- @treturn bio
+-function filter() end
+-
+---- Create digest bio, which can append to an io BIO object
+--- @tparam string mode must be 'digest'
+--- @tparam evp_md|string md_alg
+--- @treturn bio
+-function filter() end
+-
+---- Create ssl bio
+--- @tparam string mode must be 'ssl'
+--- @tparam ssl s
+--- @tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
+--- @treturn bio
+-function filter() end
+-
+---- create cipher filter bio object
+--- @tparam string mode must be 'cipher'
+--- @tparam string key
+--- @tparam string iv
+--- @tparam[opt=true] boolean encrypt
+--- @treturn bio
+-function filter() end
+-
+-end  -- define module
+-
+-
+-do  -- define class
+-
+---- openssl.bio object
+--- @type bio
+---
+-
+-do  -- define bio
+-
+---- setup ready and accept client connect
+--- @tparam[opt=false] boolean setup true for setup accept bio, false or none will accept client connect
+--- @treturn[1] boolean result only when setup is true
+--- @treturn[2] bio accpeted bio object
+-function accept() end 
+-
+---- read data from bio object
+--- @tparam number len
+--- @treturn string string length may be less than param len
+-function read() end
+-
+---- get line from bio object
+--- @tparam[opt=256] number max line len
+--- @treturn string string length may be less than param len
+-function gets() end
+-
+---- write data to bio object
+--- @tparam string data
+--- @treturn number length success write
+-function write() end
+-
+---- put line to bio object
+--- @tparam string data
+--- @treturn number length success write
+-function puts() end
+-
+---- get mem data, only support mem bio object
+--- @treturn string
+-function get_mem() end
+-
+---- push bio append to chain of bio, if want to free a chain use free_all()
+--- @tparam bio append
+--- @treturn bio 
+-function push() end
+-
+---- remove bio from chain
+--- @tparam bio toremove
+-function pop() end
+-
+---- free a chain
+-function free_all() end
+-
+---- close bio
+-function close() end
+-
+---- get type of bio
+--- @treturn string
+-function type() end
+-
+--- reset bio
+--- @TODO string
+-function reset() end
+-
+-end --define class
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/cipher.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/cipher.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/cipher.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/cipher.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,229 +0,0 @@
+---- 
+--- Provide cipher function in lua.
+---
+--- @module cipher
+--- @usage
+---  cipher = require('openssl').cipher
+---
+-
+-do  -- define module function
+-
+---- list all support cipher algs
+---
+--- @tparam[opt] boolean alias include alias names for cipher alg, default true
+--- @treturn[table] all cipher methods
+---
+-function list() end
+-
+-
+---- get evp_cipher object
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @treturn evp_cipher cipher object mapping EVP_MD in openssl
+---
+--- @see evp_cipher
+-function get() end
+-
+---- get evp_cipher_ctx object for encrypt or decrypt
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam boolean encrypt true for encrypt,false for decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn evp_cipher_ctx cipher object mapping EVP_CIPHER_CTX in openssl
+---
+--- @see evp_cipher_ctx
+-function new() end
+-
+---- get evp_cipher_ctx object for encrypt
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn evp_cipher_ctx cipher object mapping EVP_CIPHER_CTX in openssl
+---
+--- @see evp_cipher_ctx
+-function encrypt_new() end
+-
+---- get evp_cipher_ctx object for decrypt
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn evp_cipher_ctx cipher object mapping EVP_CIPHER_CTX in openssl
+---
+--- @see evp_cipher_ctx
+-function decrypt_new() end
+-
+---- quick encrypt or decrypt
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam boolean encrypt true for encrypt,false for decrypt
+--- @tparam string input data to encrypt or decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn string result
+-function cipher() end
+-
+---- quick encrypt or decrypt,alias to cipher
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam boolean encrypt true for encrypt,false for decrypt
+--- @tparam string input data to encrypt or decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn string result
+-function openssl.cipher() end
+-
+---- quick encrypt
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam string input data to encrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn string result encrypt data
+-function encrypt() end
+-
+---- quick decrypt
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam string input data to decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn string result decrypt data
+-function decrypt() end
+- 
+-end
+-
+-do  -- define class
+-
+---- openssl.evp_cipher object
+--- @type evp_cipher
+---
+-do  -- define evp_cipher
+-
+-
+---- get infomation of evp_cipher object
+---
+--- @treturn table info keys include name,block_size,key_length,iv_length,flags,mode
+-function info() end
+-
+---- derive key
+---
+--- @tparam string data derive data
+--- @tparam string[opt] string salt salt will get strong security
+--- @tparam ev_digest|string md digest method used to diver key, default with 'sha1'
+--- @treturn string key
+--- @treturn string iv
+-function BytesToKey() end
+-
+---- do encrypt or decrypt
+---
+--- @tparam boolean encrypt true for encrypt,false for decrypt
+--- @tparam string input data to encrypt or decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn string result
+-function cipher() end
+-
+---- do encrypt
+---
+--- @tparam string input data to encrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn string result
+-function encrypt() end
+-
+---- do decrypt
+---
+--- @tparam string input data to decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn string result
+-function decrypt() end
+-
+---- get evp_cipher_ctx to encrypt or decrypt 
+---
+--- @tparam boolean encrypt true for encrypt,false for decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn evp_cipher_ctx evp_cipher_ctx object
+---
+--- @see evp_cipher_ctx
+-function new() end
+-
+---- get evp_cipher_ctx to encrypt 
+---
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn evp_cipher_ctx evp_cipher_ctx object
+---
+--- @see evp_cipher_ctx
+-function encrypt_new() end
+-
+---- get evp_cipher_ctx to decrypt 
+---
+--- @tparam boolean encrypt true for encrypt,false for decrypt
+--- @tparam string key secret key
+--- @tparam[opt] string iv
+--- @tparam[opt] boolean pad true for padding default
+--- @tparam[opt] engine engine custom crypto engine
+--- @treturn evp_cipher_ctx evp_cipher_ctx object
+---
+--- @see evp_cipher_ctx
+-function decrypt_new() end
+-
+-end
+-
+-do  -- define evp_cipher_ctx
+-
+---- openssl.evp_cipher_ctx object
+--- @type evp_cipher_ctx
+---
+- 
+---- get infomation of evp_cipher_ctx object
+---
+--- @treturn table info keys include block_size,key_length,iv_length,flags,mode,nid,type, evp_cipher
+-function info() end
+-  
+---- feed data to do cipher
+---
+--- @tparam string msg data
+--- @treturn string result parture result
+-function update() end
+-
+---- get result of cipher
+---
+--- @treturn string result last result
+-function final() end
+-
+-end
+-
+-end
+-
+-
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/cms.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/cms.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/cms.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/cms.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,142 +0,0 @@
+---- Provide cms function in lua.
+--- cms are based on apps/cms.c from the OpenSSL dist, so for more information, see the documentation for OpenSSL.
+--- cms api need flags, not support "detached", "nodetached", "text", "nointern", "noverify", "nochain", "nocerts",
+--- "noattr", "binary", "nosigs"
+---
+--- Decrypts the S/MIME message in the BIO object and output the results to BIO object. 
+--- recipcert is a CERT for one of the recipients. recipkey specifies the private key matching recipcert.
+--- Headers is an array of headers to prepend to the message, they will not be included in the encoded section.
+---
+--- @module cms
+--- @usage
+---  cms = require('openssl').cms
+---
+-
+-do  -- define module function
+-
+---- create cms object
+--- @treturn cms
+-function create() end
+-
+---- read cms object
+--- @tparam bio input
+--- @tparam[opt=0] number flags
+--- @treturn cms
+-function create() end
+-
+---- create digest cms object
+--- @tparam bio input
+--- @tparam evp_digest|string md_alg
+--- @tparam[opt=0] number flags
+--- @treturn cms
+-function create() end
+-
+---- encrypt with recipt certs
+--- @tparam stack_of_x509 recipt certs
+--- @tparam bio input
+--- @tparam string|evp_cipher cipher_alg
+--- @tparam[opt=0] number flags
+--- @tparam[opt=nil] table options, may have key,keyid, password field which must be string type 
+--- @treturn cms
+-function encrypt() end
+-
+---- decrypt cms message
+--- @tparam cms message
+--- @tparam evp_pkey pkey
+--- @tparam x509 recipt
+--- @tparam bio dcount output object
+--- @tparam bio out output object
+--- @tparam[opt=0] number flags
+--- @tparam[opt=nil] table options may have key, keyid, password field, which must be string type
+--- @treturn boolean
+-function decrypt() end
+-
+---- make signed cms object
+--- @tparam x509 signer cert
+--- @tparam evp_pkey pkey
+--- @tparam stack_of_x509 certs include in the CMS
+--- @tparam bio input_data
+--- @tparam[opt=0] number flags 
+--- @treturn cms object
+-function sign() end
+-
+---- verfiy signed cms object
+--- @tparam cms signed
+--- @tparam string verify_mode, must be 'verify'
+--- @tparam stack_of_x509 others 
+--- @tparam x509_store castore
+--- @tparam bio message
+--- @tparam bio out
+--- @tparam[opt=0] number flags
+--- @treturn boolean result
+-function verify() end
+-
+---- verify digest cms object
+--- @tparam cms digested
+--- @tparam string verify_mode, must be 'digest'
+--- @tparam bio input message
+--- @tparam bio out content
+--- @tparam[opt=0] number flags
+--- @treturn boolean result
+-function verify() end
+-
+---- verify receipt cms object
+--- @tparam cms cms
+--- @tparam string verify_mode must be 'receipt'
+--- @tparam cms source
+--- @tparam stack_of_x509 certs
+--- @tparam x509_store store
+--- @tparam[opt=0] number flags
+--- @treturn boolean result
+-function verify() end
+-
+---- read cms object from input bio or string
+--- @tparam bio|string input 
+--- @tparam[opt='auto'] string format, support 'auto','smime','der','pem'
+---  auto will only try 'der' or 'pem'
+--- @tparam[opt=nil] bio content, only used when format is 'smime'
+--- @treturn cms
+-function read() end
+-
+---- write cms object to bio object
+--- @tparam cms cms
+--- @tparam bio out
+--- @tparam bio in 
+--- @tparam[opt=0] number flags 
+--- @tparam[opt='smime'] string format
+--- @treturn boolean 
+-function write() end
+-
+---- create compress cms object
+--- @tparam bio input 
+--- @tparam string alg, zlib or rle 
+--- @tparam[opt=0] number flags
+--- @treturn cms
+-function compress() end
+-
+---- uncompress cms object
+--- @tparam cms cms
+--- @tparam bio input 
+--- @tparam bio out 
+--- @tparam[opt=0] number flags
+--- @treturn boolean
+-function uncompress() end
+-
+---- create enryptdata cms
+--- @tparam bio input 
+--- @tparam cipher|string cipher_alg
+--- @tparam strig key 
+--- @tparam[opt=0] number flags
+--- @treturn cms object
+-function EncryptedData_encrypt() end
+-
+---- decrypt encryptdata cms
+--- @tparam cms encrypted
+--- @tparam string key
+--- @tparam bio out 
+--- @tparam[opt=0] number flags
+--- @treturn boolean result 
+-function EncryptedData_decrypt() end
+-
+-end
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/config.ld luvi-src-v2.7.6/deps/lua-openssl/ldoc/config.ld
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/config.ld	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/config.ld	1970-01-01 01:00:00.000000000 +0100
+@@ -1,33 +0,0 @@
+-project='lua-openssl'
+-title='lua-openssl Docmentation'
+-description='Openssl binding for Lua'
+-format='discount'
+-backtick_references=false
+-file={
+-	'openssl.lua',
+-	'asn1.lua',
+-	'bio.lua',
+-	'cipher.lua',
+-	'digest.lua',
+-	'hmac.lua',
+-	'pkey.lua',
+-	'x509.lua',
+-	'x509_name.lua',
+-	'x509_extension.lua',
+-	'x509_attr.lua',
+-	'x509_req.lua',
+-	'x509_crl.lua',
+-	'x509_store.lua',
+-	'pkcs7.lua',
+-	'cms.lua',
+-	'pkcs12.lua',
+-	'timestamp.lua',
+-	'ssl.lua',
+-	'sk.lua'
+-}
+-dir='doc'
+-readme='README.md'
+-style='!pale'
+-kind_names={topic='Manual',script='Programs'}
+-examples = {
+-}
+\ No newline at end of file
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/digest.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/digest.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/digest.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/digest.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,156 +0,0 @@
+---- 
+--- Provide digest function in lua.
+---
+--- @module digest
+--- @usage
+---  digest = require('openssl').digest
+---
+-
+-do  -- define module function
+-
+---- list all support digest algs
+---
+--- @tparam[opt] boolean alias include alias names for digest alg, default true
+--- @treturn[table] all methods
+---
+-function list() end
+-
+---- get evp_digest object
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @treturn evp_digest digest object mapping EVP_MD in openssl
+---
+--- @see evp_digest
+-function get() end
+-
+---- get evp_digest_ctx object
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @treturn evp_digest_ctx digest object mapping EVP_MD_CTX in openssl
+---
+--- @see evp_digest_ctx
+-function new() end
+-
+---- quick method to generate digest result
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam string msg to compute digest 
+--- @tparam[opt] boolean raw binary result return if set true, or hex encoded string default
+--- @treturn string digest result value
+-function digest() end
+- 
+---- create digest object for sign
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam[opt=nil] engine object
+--- @treturn evp_digest_ctx
+-function signInit() end
+-
+---- create digest object for verify
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam[opt=nil] engine object
+--- @treturn evp_digest_ctx
+-function verifyInit() end
+-
+-end
+-
+-do  -- define class
+-
+---- openssl.evp_digest object
+--- @type evp_digest
+---
+-do  -- define evp_digest
+-
+---- create new evp_digest_ctx
+---
+--- @tparam[opt] engine, nothing will use default engine
+--- @treturn evp_digest_ctx ctx
+--- @see evp_digest_ctx
+-function new() end
+-
+---- get infomation of evp_digest object
+---
+--- @treturn table info keys include nid,name size,block_size,pkey_type,flags
+-function info() end
+-
+---- compute msg digest result
+---
+--- @tparam string msg data to digest
+--- @tparam[opt] engine, eng
+--- @treturn string result a binary hash value for msg
+-function digest() end
+-
+---- create digest object for sign
+---
+--- @tparam[opt=nil] engine object
+--- @treturn evp_digest_ctx
+-function signInit() end
+-
+---- create digest object for verify
+---
+--- @tparam[opt=nil] engine object
+--- @treturn evp_digest_ctx
+-function verifyInit() end
+-
+-end
+-
+-do  -- define evp_digest_ctx
+-
+---- openssl.evp_digest_ctx object
+--- @type evp_digest_ctx
+---
+- 
+---- get infomation of evp_digest_ctx object
+---
+--- @treturn table info keys include size,block_size,digest
+-function info() end
+-
+---- feed data to do digest
+---
+--- @tparam string msg data
+--- @treturn boolean result true for success
+-function update() end
+-
+---- get result of digest
+---
+--- @tparam[opt] string last last part of data
+--- @tparam[opt] boolean raw binary or hex encoded result, default true for binary result
+--- @treturn string val hash result 
+-function final() end
+-
+-
+---- reset evp_diget_ctx to reuse
+---
+-function reset() end
+-
+---- feed data for sign to get signature
+---
+--- @tparam string data to be signed
+--- @treturn boolean result
+-function signUpdate() end
+-
+---- feed data for verify with signature
+---
+--- @tparam string data to be verified
+--- @treturn boolean result
+-function verifyUpdate() end
+-
+---- get result of sign
+---
+--- @tparam evp_pkey private key to do sign
+--- @treturn string singed result
+-function signFinal() end
+-
+---- get verify result
+---
+--- @tparam string signature
+--- @treturn boolean result, true for verify pass
+-function verifyFinal() end
+-
+-end
+-
+-end
+-
+-
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/hmac.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/hmac.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/hmac.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/hmac.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,77 +0,0 @@
+---- 
+--- Provide hmac function in lua.
+---
+--- @module hmac
+--- @usage
+---  hamc = require('openssl').hmac
+---
+-
+-do  -- define module function
+-
+---- compute hmac one step, in module openssl
+---
+--- @tparam evp_digest|string|nid digest digest alg identity
+--- @tparam string key
+--- @tparam[opt] engine engine, nothing with default engine
+--- @treturn string result binary string
+---
+-function openssl.hmac() end
+-
+---- compute hmac one step, in module openssl.hamc
+---
+--- @tparam evp_digest|string|nid digest digest alg identity
+--- @tparam string key
+--- @tparam boolean raw, return binary or hex encoded string, true false binary or hex
+--- @tparam[opt] engine engine, nothing with default engine
+--- @treturn string result binary or hex string
+-function hmac() end
+-
+---- alias for hmac
+---
+--- @tparam evp_digest|string|nid digest digest alg identity
+--- @tparam string key
+--- @tparam boolean raw, return binary or hex encoded string, true false binary or hex
+--- @tparam[opt] engine engine, nothing with default engine
+--- @treturn string result binary or hex string
+-function digest() end
+-
+---- get hamc_ctx object
+---
+--- @tparam string|integer|asn1_object alg name, nid or object identity
+--- @tparam string key secret key
+--- @tparam[opt] engine engine, nothing with default engine
+--- @treturn hamc_ctx hmac object mapping HMAC_CTX in openssl
+---
+--- @see hmac_ctx
+-function new() end
+- 
+-end
+-
+-do  -- define class
+-
+---- openssl.hmac_ctx object
+--- @type hmac_ctx
+---
+-
+-do  -- define hmac_ctx
+-
+---- feed data to do digest
+---
+--- @tparam string msg data
+-function update() end
+-
+---- get result of hmac
+---
+--- @tparam[opt] string last last part of data
+--- @tparam[opt] boolean raw binary or hex encoded result, default true for binary result
+--- @treturn string val hash result 
+-function final() end
+-
+-
+---- reset hmac_ctx to reuse
+---
+-function reset() end
+-
+-end
+-
+-end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/openssl.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/openssl.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/openssl.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/openssl.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,76 +0,0 @@
+----
+--- Provide openssl base function in lua.
+---
+--- @module openssl
+--- @usage
+---  openssl = require('openssl')
+---
+-
+-do  -- define module function
+-
+--- Most lua-openssl function or methods return nil or false when error or
+--- failed, followed by string type error _reason_ and number type error _code_,
+--- _code_ can pass to openssl.error() to get more error information.
+-
+---- hex encode or decode string
+--- @tparam string str
+--- @tparam[opt=true] boolean encode true to encoed, false to decode
+--- @treturn string
+-function hex() end
+-
+---- base64 encode or decode
+--- @tparam string|bio input
+--- @tparam[opt=true] boolean encode true to encoed, false to decode
+--- @tparam[opt=true] boolean NO_NL true with newline, false without newline
+--- @treturn string
+-function base64() end
+-
+---- get method names
+--- @tparam string type support 'cipher','digests','pkeys','comps'
+--- @treturn table as array
+-function list() end
+-
+---- get last or given error infomation
+--- @tparam[opt] number error, default use ERR_get_error() return value
+--- @tparam[opt=false] boolean clear the current thread's error queue.
+--- @treturn number errcode
+--- @treturn string reason
+--- @treturn string library name
+--- @treturn string function name
+--- @treturn boolean is this is fatal error
+-function error() end
+-
+---- get random bytes
+--- @tparam number length
+--- @tparam[opt=false] boolean strong true to generate strong randome bytes
+--- @treturn string
+-function random() end
+-
+---- get random generator state
+--- @tparam boolean result true for sucess
+-function rand_status() end
+-
+---- load rand seed from file
+--- @tparam[opt=nil] string file path to laod seed, default opensl management
+--- @treturn boolean result
+-function rand_load() end
+-
+---- save rand seed to file
+--- @tparam[opt=nil] string file path to save seed, default openssl management
+--- @treturn bool result
+-function rand_write() end
+-
+---- cleanup random genrator
+-function rand_cleanup() end
+-
+---- get openssl engine object
+--- @tparam string engine_id
+--- @treturn engine
+-function engine() end
+-
+--- get lua-openssl version
+--- @tparam[opt] boolean format result will be number when set true, or string
+--- @treturn lua-openssl version, lua version, openssl version
+-function version() end
+-
+-end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/pkcs12.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/pkcs12.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/pkcs12.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/pkcs12.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,28 +0,0 @@
+---- 
+--- Provide pkcs12 function in lua.
+---
+--- @module pkcs12
+--- @usage
+---  pkcs12 = require('openssl').pkcs12
+---
+-
+-do  -- define module function
+-
+---- parse pkcs12 data as lua table
+---
+--- @tparam string|bio input pkcs12 content
+--- @tparam string password for pkcs12
+--- @treturn table result contain 'cert', 'pkey', 'extracerts' keys
+-function read() end
+-
+---- create and export pkcs12 data
+--- @tparam x509 cert
+--- @tparam evp_pkey pkey
+--- @tparam string password
+--- @tparam[opt] string friendlyname
+--- @tparam[opt] table|stak_of_x509 extracerts
+--- @treturn string data
+-function export() end
+-
+-end
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/pkcs7.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/pkcs7.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/pkcs7.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/pkcs7.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,91 +0,0 @@
+----
+--- Provide pkcs7 function in lua.
+---
+--- @module pkcs7
+--- @usage
+---  pkcs7 = require('openssl').pkcs7
+---
+-
+-do  -- define module function
+-
+---- read pkcs7
+--- read string or bio object, which include pkcs7 content
+--- @tparam bio|string input
+--- @tparam[opt='auto'] format allow 'auto','der','pem','smime'
+---  auto will only try 'der' or 'pem'
+--- @tparam string password for pkcs12
+--- @treturn pkcs7 object or nil
+--- @treturn string content exist only smime format
+-function read() end
+-
+---- sign message with signcert and signpkey to create pkcs7 object
+--- @tparam string|bio msg
+--- @tparam x509 sigcert
+--- @tparam evp_pkey signkey
+--- @tparam[opt] stack_of_x509 cacerts
+--- @tparam[opt=0] number flags
+--- @treturn pkcs7 object
+-function sign() end
+-
+---- verify pkcs7 object, and return msg content, follow by singers
+--- @tparam pkcs7 in
+--- @tparam[opt] stack_of_x509 signercerts
+--- @tparam[opt] x509_store cacerts
+--- @tparam[opt] string|bio msg
+--- @tparam[opt=0] number flags
+--- @treturn[1] string content
+--- @treturn[1] boolean result
+-function verify() end
+-
+---- encrypt message with recipcerts certificates return encrypted pkcs7 object
+--- @tparam string|bio msg
+--- @tparam stack_of_x509 recipcerts
+--- @tparam[opt='rc4'] string|evp_cipher cipher
+--- @tparam[opt] number flags
+-function encrypt() end
+-
+---- decrypt encrypted pkcs7 message
+--- @tparam pkcs7 input
+--- @tparam x509 recipcert
+--- @tparam evp_pkey recipkey
+--- @treturn string decrypt message
+-function decrypt() end
+-
+-end
+-
+-
+-do  -- define class
+-
+---- openssl.pkcs7 object
+--- @type pkcs7
+---
+-
+-do  -- define pkcs7
+-
+---- export pkcs7 as string
+--- @tparam[opt=true] boolean pem default export as pem format, false export as der string
+--- @treturn string
+-function export() end
+-
+---- export pkcs7 as a string
+--- @treturn table  a table has pkcs7 infomation, include type,and other things relate to types
+-function parse() end
+-
+---- verify pkcs7 object, and return msg content, follow by singers
+--- @tparam[opt] stack_of_x509 signercerts
+--- @tparam[opt] x509_store cacerts
+--- @tparam[opt] string|bio msg
+--- @tparam[opt=0] number flags
+--- @treturn string content
+--- @treturn stack_of_x509 signers
+-function verify() end
+-
+---- decrypt encrypted pkcs7 message
+--- @tparam x509 recipcert
+--- @tparam evp_pkey recipkey
+--- @treturn string decrypt message
+-function decrypt() end
+-
+-end
+-
+-end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/pkey.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/pkey.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/pkey.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/pkey.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,201 +0,0 @@
+-------------
+--- Provide Public/Private key module.
+--- @module pkey
+--- @usage
+---  pkey = require'openssl'.pkey
+-
+-do --define module function
+-
+---- generate a new ec keypair
+--- @tparam string alg, alg must be 'ec'
+--- @tparam string|number curvename this can be integer as curvename NID
+--- @tparam[opt] integer flags when alg is ec need this.
+--- @treturn evp_pkey object with mapping to EVP_PKEY in openssl
+-function new() end
+-
+---- generate a new keypair
+--- @tparam[opt='rsa'] string alg, accept 'rsa','dsa','dh'
+--- @tparam[opt=1024|512] integer bits, rsa with 1024,dh with 512
+--- @tparam[opt]  when alg is rsa give e value default is 0x10001
+--- @treturn evp_pkey object with mapping to EVP_PKEY in openssl
+-function new() end
+-
+---- create a new keypair by factors of keypair or get public key only
+--- @tparam table factors to create private/public key, key alg only accept accept 'rsa','dsa','dh','ec' and must exist</br>
+---  when arg is rsa, table may with key n,e,d,p,q,dmp1,dmq1,iqmp, both are binary string or openssl.bn<br>
+---  when arg is dsa, table may with key p,q,g,priv_key,pub_key, both are binary string or openssl.bn<br>
+---  when arg is dh, table may with key p,g,priv_key,pub_key, both are binary string or openssl.bn<br>
+---  when arg is ec, table may with D,X,Y,Z,both are binary string or openssl.bn<br>
+--- @treturn evp_pkey object with mapping to EVP_PKEY in openssl
+--- @usage
+---  --create rsa public key
+---    pubkey = new({alg='rsa',n=...,e=...}
+---  --create new rsa
+---    rsa = new({alg='rsa',n=...,q=...,e=...,...}
+-function new() end
+-
+---- get public key from private key object
+--- @tparam evp_pkey priv_key
+--- @treturn evp_pkey pub_key
+--- @see evp_pkey
+-function get_public() end
+-
+---- read public/private key from data
+--- @tparam string|openssl.bio input string data or bio object
+--- @tparam[opt=false] boolean priv prikey set true when input is private key
+--- @tparam[opt='auto'] format format or encoding of input, support 'auto','pem','der'
+--- @tparam[opt] string passhprase when input is private key, or key types 'ec','rsa','dsa','dh'
+--- @treturn evp_pkey public key
+--- @see evp_pkey
+-function read() end
+-
+---- sign message with private key
+--- @tparam evp_pkey key key used to sign message
+--- @tparam string data data be signed
+--- @tparam[opt='SHA1'] string|env_digest md_alg default use sha-1
+--- @treturn string signed message
+-function sign() end
+-
+---- verify signed message with public key
+--- @tparam evp_pkey key key used to verify message
+--- @tparam string data data be signed
+--- @tparam string signature signed result
+--- @tparam[opt='SHA1'] string|env_digest md_alg default use sha-1
+--- @tparam boolean true for pass verify
+-function verify() end
+-
+---- encrypt message with public key
+--- encrypt length of message must not longer than key size, if shorter will do padding,currently supports 6 padding modes.
+--- They are: pkcs1, sslv23, no, oaep, x931, pss.
+--- @tparam evp_pkey key key used to encrypted message
+--- @tparam string data data to be encrypted
+--- @tparam string[opt='pkcs1'] string padding padding mode
+--- @treturn string encrypted message
+-function encrypt() end
+-
+---- decrypt message with private key
+--- pair with encrypt
+--- @tparam evp_pkey key key used to decrypted message
+--- @tparam string data data to be decrypted
+--- @tparam string[opt='pkcs1'] string padding padding mode
+--- @treturn[1] string result
+--- @treturn[2] nil
+-function decrypt() end
+-
+---- seal  and encrypt  message with one public key
+--- data be encrypt with secret key, secret key be encrypt with public key
+--- encrypts data using pubkeys in table, so that only owners of the respective private keys and ekeys can decrypt and read the data.
+--- @tparam table pubkeys public keys to encrypt secret key
+--- @tparam string data data to be encrypted
+--- @tparam[opt='RC4'] cipher|string alg
+--- @treturn string data encrypted
+--- @treturn table ekey secret key encrypted by public key
+--- @treturn stringiv
+-function seal() end
+-
+---- seal and encrypt message with one public key
+--- data be encrypt with secret key, secret key be encrypt with public key
+--- @tparam evp_pkey pubkey public keys to encrypt secret key
+--- @tparam string data data to be encrypted
+--- @tparam[opt='RC4'] cipher|string alg
+--- @treturn string data encrypted
+--- @treturn string skey secret key encrypted by public key
+--- @treturn string iv
+-function seal() end
+-
+---- open and ecrypted seal data with private key
+--- @tparam evp_pkey pkey private key used to open encrypted secret key
+--- @tparam string ekey encrypted secret key
+--- @tparam string string iv
+--- @tparam[opt='RC4'] evp_cipher|string md_alg
+--- @treturn string data decrypted message or nil on failure
+-function open() end
+-
+-end  -- define module
+-
+-
+-do  -- define class
+-
+---- openssl.evp_pkey object
+--- @type evp_pkey
+---
+-
+-do  -- define evp_pkey
+-
+---- export evp_pkey as pem string
+--- @tparam[opt=true] boolean pem default export as pem format, false export as der string
+--- @tparam[opt=false] boolean raw_key true for export low layer key just rsa,dsa,ec, and public key only support RSA
+--- @tparam[opt] string passphrase if given, export key will encrypt with des-cbc-ede,
+---    only need when export private key
+--- @treturn string
+-function export() end
+-
+---- export evp_pkey as der string
+--- @tparam boolean pem set false to export as der string
+--- @tparam[opt=false] boolean raw_key true for export low layer key just rsa,dsa,ec, and public key only support RSA
+--- @tparam[opt] string passphrase if given, export key will encrypt with des-cbc-ede,
+---    only need when export private key
+--- @treturn string
+-function export() end
+-
+---- get key details as table
+--- @treturn table infos with key bits,pkey,type, pkey may be rsa,dh,dsa, show as table with factor hex encoded bignum
+-function parse() end
+-
+---- return key is private or public
+--- @treturn boolean ture is private or public key
+-function is_private() end
+-
+---- compute dh key, check whether then supplied key is a private key
+--- by checking then prime factors whether set
+--- @tparam string remote_public_key
+--- @treturn string
+--- @todo: more check
+-function compute_key() end
+-
+---- sign message with private key
+--- @tparam string data data be signed
+--- @tparam[opt='SHA1'] string|env_digest md_alg default use sha-1
+--- @treturn string signed message
+-function sign() end
+-
+---- verify signed message with public key
+--- @tparam string data data be signed
+--- @tparam string signature signed result
+--- @tparam[opt='SHA1'] string|env_digest md_alg default use sha-1
+--- @treturn boolean true for pass verify
+-function verify() end
+-
+---- encrypt message with public key
+--- encrypt length of message must not longer than key size, if shorter will do padding,currently supports 6 padding modes.
+--- They are: pkcs1, sslv23, no, oaep, x931, pss.
+--- @tparam string data data to be encrypted
+--- @tparam string[opt='pkcs1'] string padding padding mode
+--- @treturn string encrypted message
+-function encrypt() end
+-
+---- decrypt message with private key
+--- pair with encrypt
+--- @tparam string data data to be decrypted
+--- @tparam string[opt='pkcs1'] string padding padding mode
+--- @treturn[1] string result
+--- @treturn[2] nil
+-function decrypt() end
+-
+---- seal and encrypt message with one public key
+--- data be encrypt with secret key, secret key be encrypt with public key
+--- @tparam string data data to be encrypted
+--- @tparam[opt='RC4'] cipher|string alg
+--- @treturn string data encrypted
+--- @treturn string skey secret key encrypted by public key
+--- @treturn string iv
+-function seal() end
+-
+---- open and ecrypted seal data with private key
+--- @tparam string ekey encrypted secret key
+--- @tparam string string iv
+--- @tparam[opt='RC4'] evp_cipher|string md_alg
+--- @treturn string data decrypted message or nil on failure
+-function open() end
+-
+-end --define class
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/sk.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/sk.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/sk.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/sk.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,74 +0,0 @@
+---- 
+--- Provide hmac function in lua.
+-
+---
+--- @module hmac
+--- @usage
+---  hamc = require('openssl').hmac
+---
+-
+-do  -- define module function
+-
+---- read stack_of_x509 from string data or bio input
+--- @tparam string|bio input 
+--- @treturn stack_of_x509
+--- @see stack_of_object
+-function openssl.sk_x509_read() end
+-
+---- contrust stack_of_x509 from table
+--- @tparam table certs x509 object certs
+--- @treturn stack_of_x509
+--- @see stack_of_object
+-function openssl.sk_x509_new() end
+-
+-end
+-
+-do  -- define class
+-
+---- openssl.stack_of_object object
+--- stack_of_x509_extension, stack_of_x509, stack_of_x509_attribute object has same interface.
+--- stack_of_x509 is an important object in lua-openssl, it can be used as a certchain, trusted CA files or unstrust certs.
+--- object not support x509, x509_extension or x509_attribute
+--- @type stack_of_object
+---
+-
+-do  -- define stack_of_object
+-
+---- push an object into stack
+--- @tparam object obj
+--- @treturn stack_of_object self
+-function push() end
+-
+---- pop an object from stack
+--- @treturn object
+-function pop() end
+-
+---- set object at given location
+--- @tparam integer location
+--- @tparam object object
+--- @treturn stack_of_object self
+-function set() end
+-
+---- get object at given location
+--- @tparam integer location
+--- @treturn object obj
+-function get() end
+-
+---- insert object at given location
+--- @tparam object obj
+--- @tparam integer location
+--- @treturn stack_of_x509 self
+-function insert() end
+-
+---- delete object at geiven location
+--- @tparam integer location
+--- @treturn object deleted object
+-function delete() end
+-
+---- convert stack_of_object to table
+--- @@treturn table contain object index start from 1
+-function totable() end
+-
+-end
+-
+-end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/ssl.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/ssl.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/ssl.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/ssl.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,408 +0,0 @@
+----
+--- Provide ssl function in lua.
+---
+--- @module ssl
+--- @usage
+---  hamc = require('openssl').ssl
+---
+-
+-do  -- define module function
+-
+---- create ssl_ctx object, which mapping to SSL_CTX in openssl.
+--- @tparam string protocol support 'SSLv3', 'SSLv23', 'SSLv2', 'TSLv1', 'TSLv1_1','TSLv1_2','DTLSv1', and can be follow by '_server' or '_client'
+--- @tparam[opt] string support_ciphers, if not given, default of openssl will be used
+--- @treturn ssl_ctx
+-function ctx_new() end
+-
+---- get alert_string for ssl state
+--- @tparam number alert
+--- @tparam[opt=false] boolean long
+--- @treturn string alert type
+--- @treturn string desc string, if long set true will return long info
+-function alert_string() end
+-
+-end
+-
+-do  -- define class
+-
+---- openssl.ssl_ctx object
+--- @type ssl_ctx
+---
+-
+-do  -- define ssl_ctx
+-
+---- tell ssl_ctx use private key and certificate, and check private key
+--- @tparam evp_pkey pkey
+--- @tparam x509 cert
+--- @treturn boolean result return true for ok, or nil followed by errmsg and errval
+-function use() end
+-
+---- add client ca cert and option extra chain cert
+--- @tparam x509 clientca
+--- @tparam[opt] table extra_chain_cert_array
+--- @treturn boolean result
+-function add() end
+-
+---- set temp callback
+--- @tparam string keytype, 'dh','ecdh',or 'rsa'
+--- @tparam function tmp_cb
+--- @param[opt] vararg
+-function set_tmp() end
+-
+---- set tmp key content pem format
+--- @tparam string keytype, 'dh','ecdh',or 'rsa'
+--- @tparam string key_pem
+-function set_tmp() end
+-
+---- set ecdh with given curvename as tmp key
+--- @tparam string keytype, must be 'ecdh'
+--- @tparam string curvename
+-function set_tmp() emd
+-
+---- clean given mode
+--- mode support 'enable_partial_write','accept_moving_write_buffer','auto_retry','no_auto_chain','release_buffers'
+--- @tparam boolean clear must be true
+--- @tparam string mode
+--- @param[opt] ...
+--- @treturn string
+--- @treturn ...
+--- @usage
+---  modes = { ssl_ctx:mode('enable_partial_write','accept_moving_write_buffer','auto_retry') },
+---
+---   for  i, v in ipairs(modes)
+---     print(v)
+---  end
+---  --output 'enable_partial_write','accept_moving_write_buffer','auto_retry'
+-function mode() end
+-
+---- get options
+--- @treturn table string list of current options
+-function options() end
+-
+---- set options
+--- @tparam string option, support "microsoft_sess_id_bug", "netscape_challenge_bug", "netscape_reuse_cipher_change_bug",
+--- "sslref2_reuse_cert_type_bug", "microsoft_big_sslv3_buffer", "msie_sslv3_rsa_padding","ssleay_080_client_dh_bug",
+--- "tls_d5_bug","tls_block_padding_bug","dont_insert_empty_fragments","all", please to see ssl_options.h
+--- @treturn table string list of current options after set new option
+-function options() end
+-
+---- clear options
+--- @tparam boolean clear set true to clear options
+--- @tparam string option, support "microsoft_sess_id_bug", "netscape_challenge_bug", "netscape_reuse_cipher_change_bug",
+--- "sslref2_reuse_cert_type_bug", "microsoft_big_sslv3_buffer", "msie_sslv3_rsa_padding","ssleay_080_client_dh_bug",
+--- "tls_d5_bug","tls_block_padding_bug","dont_insert_empty_fragments","all",  please to see ssl_options.h
+--- @treturn table string list of current options after clear some option
+-function options() end
+-
+---- get timeout
+--- @return number
+-function timeout() end
+-
+---- set timeout
+--- @tparam number timeout
+--- @treturn number previous timeout
+-function timeout() end
+-
+---- get quit_shutdown is set or not
+--- Normally when a SSL connection is finished, the parties must send out
+--- "close notify" alert messages using ***SSL:shutdown"*** for a clean shutdown.
+--- @treturn boolean result
+-function quiet_shutdown() end
+-
+---- set quiet_shutdown
+--- @tparam boolean quiet
+--- When setting the "quiet shutdown" flag to 1, ***SSL:shutdown*** will set the internal flags
+--- to SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN. ***SSL:shutdown*** then behaves like
+--- ***SSL:set_shutdown*** called with SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN.
+--- The session is thus considered to be shutdown, but no "close notify" alert
+--- is sent to the peer. This behaviour violates the TLS standard.
+--- The default is normal shutdown behaviour as described by the TLS standard.
+--- @treturn boolean result
+-function quiet_shutdown() end
+-
+---- set verify locations with cafile and capath
+--- ssl_ctx:verify_locations specifies the locations for *ctx*, at
+--- which CA certificates for verification purposes are located. The certificates
+--- available via *CAfile* and *CApath* are trusted.
+--- @tparam string cafile
+--- @tparam string capath
+--- @treturn boolean result
+-function verify_locations() end
+-
+---- get certificate verification store of ssl_ctx
+---@treturn x509_store store
+-function cert_store() end
+-
+---- set or replaces then certificate verification store of ssl_ctx
+--- @tparam x509_store store
+---@treturn x509_store store
+-function cert_store() end
+-
+---- get verify depth when cert chain veirition
+--- @treturn number depth
+-function verify_depth() end
+-
+---- set verify depth when cert chain veirition
+--- @tparam number depth
+--- @treturn number depth
+-function verify_depth() end
+-
+---- get verify_mode, return number mode and all string modes list
+--- @treturn number mode_code
+--- @return ...
+- --  none: not verify client cert
+- --  peer: verify client cert
+- --  fail: if client not have cert, will failure
+- --  once: verify client only once.
+--- @usage
+---  mode = {ctx:verify_mode()}
+---  print('integer mode',mode[1])
+---  for i=2, #mode then
+---    print('string mode:'..mode[i])
+---  end
+-function verify_mode() end
+-
+---- set ssl verify mode and callback
+--- @tparam number mode, mode set to ctx, must be ssl.none or ssl.peer, and ssl.peer support combine with ssl.fail or ssl.once
+--- @tparam[opt=nil] function ssl verify callback in lua function, not give will use default openssl callback, when mode is 'none', will be ignore this
+--- verify_cb must be boolean function(verifyarg) prototype, return true to continue or false to end ssl handshake
+--- verifyarg has field 'error', 'error_string','error_depth','current_cert', and 'preverify_ok'
+--- @treturn boolean result
+-function verify_mode() end
+-
+---- set certificate verify callback function
+--- @tparam[opt] function cert_verify_cb with boolean function(verifyargs) prototype, if nil or none will use openssl default callback
+--- verifyargs has field 'error', 'error_string','error_depth','current_cert'
+-function set_cert_verify() end
+-
+---- set certificate verify options
+--- @tparam table verify_cb_flag support field always_continue with boolean value and verify_depth with number value.
+-function set_cert_verify() end
+-
+---- get current session cache mode
+--- @ table modes as array, mode is 'no_auto_clear','server','client','both','off'
+-function session_cache_mode()
+-
+---- set session cache mode,and return old mode
+--- @param mode string support 'no_auto_clear','server','client','both','off',
+--- 'no_auto_clear' can be combine with others, so accept one or two param.
+-function session_cache_mode(...)
+-
+---- create bio object
+--- @tparam string host_addr format like 'host:port'
+--- @tparam[opt=false] boolean server, true listen at host_addr,false connect to host_addr
+--- @tparam[opt=true] boolean autoretry ssl operation autoretry mode
+--- @treturn bio bio object
+-function bio() end
+-
+---- create ssl object
+--- @tparam bio bio
+--- @tparam[opt=false] boolean server, true will make ssl server
+--- @treturn ssl
+-function ssl() end
+-
+---- create ssl object
+--- @tparam bio input
+--- @tparam bio ouput
+--- @tparam[opt=false] boolean server, true will make ssl server
+--- @treturn ssl
+-function ssl() end
+-
+-end
+-
+-do  --define ssl object
+-
+---- openssl.ssl object
+---  All SSL object IO operation methods(connect, accept, handshake, read,
+---  peek or write) return nil or false when fail or error.
+---  When nil returned, it followed by 'ssl' or 'syscall', means SSL layer or
+---  system layer error. When false returned, it followed by number 0,
+---  'want_read','want_write','want_x509_lookup','want_connect','want_accept'.
+---  Numnber 0 means SSL connection closed, others means you should do some
+---  SSL operation.
+--- @type ssl
+-
+---- get value according to what, arg can be list, arg must be in below list
+--- @tparam string arg
+---  certificate:  return SSL certificates
+---  fd: return file or network connect fd
+---  rfd:
+---  wfd:
+---  client_CA_list
+---  read_ahead: -> boolean
+---  shared_ciphers: string
+---  cipher_list -> string
+---  verify_mode: number
+---  verify_depth
+---  state_string
+---  state_string_long
+---  rstate_string
+---  rstate_string_long
+---  iversion
+---  version
+---  default_timeout,
+---  certificates
+---  verify_result
+---  state
+---  state_string
+--- @return according to arg
+-function get() end
+-
+---- set value according to what, arg can be list, arg must be in below list
+--- @tparam string arg
+---  certificate:  return SSL certificates
+---  fd: return file or network connect fd
+---  rfd:
+---  wfd:
+---  client_CA:
+---  read_ahead
+---  cipher_list
+---  verify_depth
+---  purpose:
+---  trust:
+---  verify_result
+---  state
+--- @param value val type accroding to arg
+--- @return value
+-function set() end
+-
+---- tell ssl use private key and certificate, and check private key
+--- @tparam evp_pkey pkey
+--- @tparam[opt] x509 cert
+--- @treturn boolean result return true for ok, or nil followed by errmsg and errval
+-function use() end
+-
+---- get peer certificate and certificate chains
+--- @treturn x509 certificate
+--- @treturn sk_of_x509 chains of peer
+-function peer() end
+-
+---- get socket fd of ssl
+--- @treturn number fd
+-function getfd() end
+-
+---- get current cipher info
+--- @treturn table include name,version,id,bits,algbits and description
+-function current_cipher() end
+-
+---- get current compression name
+--- @treturn string
+-function current_compression() end
+-
+---- get peer certificate verify result
+--- @treturn boolean true for success
+--- @treturn table all certificate in chains verify result
+---  preverify_ok as boolean verify result
+---  error as number error code
+---  error_string as string error message
+---  error_depth as number verify depth
+---  current_cert as x509 certificate to verified
+-function getpeerverification() end
+-
+---- get ssl session
+--- @treturn ssl_session session object
+-function session() end
+-
+---- set ssl session
+--- @tparam string|ssl_session sesion
+---  reuse session would speed up ssl handshake
+--- @treturn boolean result
+-function session() end
+-
+---- duplicate ssl object
+--- @treturn ssl
+-function dup() end
+-
+---- get ssl_ctx associate with current ssl
+--- @treturn ssl_ctx
+-function ctx() end
+-
+---- set ssl_ctx associate to current ssl
+--- @tparam ssl_ctx ctx
+--- @treturn ssl_ctx orgine ssl_ctx object
+-function ctx() end
+-
+---- reset ssl object to allow another connection
+--- @treturn boolean result true for success
+-function clear() end
+-
+---- get want to do
+--- @treturn string 'nothing', 'reading', 'writing', 'x509_lookup'
+--- @treturn number state want
+-function want() end
+-
+---- get number of bytes available inside SSL fro immediate read
+--- treturn number
+-function pending() end
+-
+---- do ssl server accept
+--- @treturn boolean true for success
+--- @treturn string fail reason
+-function accept() end
+-
+---- do ssl client connect
+--- @treturn boolean true for success
+--- @treturn string fail reasion
+-function connect() end
+-
+---- do ssl read
+--- @tparam[opt=4096] number length to read
+--- @treturn string data, nil or false for fail
+--- @treturn string fail reason
+-function read() end
+-
+---- do ssl peak, data can be read again
+--- @tparam[opt=4096] number length to read
+--- @treturn string data, nil or false for fail
+--- @treturn string fail reason
+-function peek() end
+-
+---- do ssl write
+--- @tparam string data
+--- @treturn number count of bytes write successfully
+--- @treturn string fail reason
+-function write() end
+-
+---- do ssl renegotiate
+--- @treturn boolean true for success
+--- @treturn string fail reasion
+-function renegotiate() end
+-
+---- do ssl handshake, support both server and client side
+--- @treturn boolean true for success
+--- @treturn string fail reasion
+-function handshake() end
+-
+---- shutdown SSL connection
+-function shutdown() end
+-
+---- shutdown ssl connect with special mode, disable read or write,
+--- enable or disable quite shutdown
+--- @tparam string mode support 'read','write', 'quite', 'noquite'
+-function shutdown() end
+-
+---- shutdown ssl connection with quite or noquite mode
+--- @tparam boolean mode
+--- @treturn[1] boolean if mode is true, return true or false for quite
+--- @treturn[2] string if mode is false, return 'read' or 'write' for shutdown direction
+-function shutdown() end
+-
+---- do ssl renegotiate_pending
+--- @treturn boolean true for success
+--- @treturn string fail reasion
+-function renegotiate_pending() end
+-
+---- do ssl renegotiate_pending
+--- @treturn boolean true for success
+--- @treturn string fail reasion
+-function renegotiate_pending() end
+-
+---- make ssl to client mode
+-function set_connect_state() end
+-
+---- make ssl to server mode
+-function set_accept_state() end
+-
+-end
+-
+-end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/timestamp.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/timestamp.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/timestamp.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/timestamp.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,334 +0,0 @@
+----
+--- Provide timestamp module.
+--- create and manage x509 certificate sign request
+--- @module ts
+--- @usage
+---  ts = require'openssl'.ts
+---
+-
+-do --define module function
+-
+---- create a new ts_req object.
+--- @tparam[opt=1] integer version
+--- @treturn ts_req timestamp sign request object
+--- @see ts_req
+-function req_new () end
+-
+---- read ts_req object from string or bio data
+--- @tparam string|bio input
+--- @treturn ts_req timestamp sign request object
+--- @see ts_req
+-function req_read() end
+-
+---- read ts_resp object from string or bio input
+--- @tparam string|bio input
+--- @treturn ts_resp object
+-function resp_read() end
+-
+---- create ts_resp_ctx object
+--- @tparam[opt] x509 signer timestamp certificate
+--- @tparam[opt] evp_pkey pkey private key to sign ts_req
+--- @tparam[opt] asn1_object|string|nid identity for default policy object
+--- @treturn ts_resp_ctx object
+-
+-function resp_ctx_new() end
+-
+---- create ts_verify_ctx object
+--- @tparam[opt=nil] string|ts_req reqdata
+--- @treturn ts_verify_ctx object
+-function verify_ctx_new() end
+-
+-end  -- define module
+-
+-do  -- define class
+-
+--------------------------------------------------------------------------------------------
+---- openssl.ts_req object
+--- @type ts_req
+-
+-do  -- define ts_req
+-
+---- export ts_req to string
+--- @treturn string
+-function export () end
+-
+---- get info as table 
+--- @treturn table
+-function info() end
+-
+---- create ts_verify_ctx from ts_req object
+--- @treturn ts_verify_ctx object
+-function to_verify_ctx() end
+-
+---- make a clone of ts_req object
+--- @treturn ts_req
+-function dup() end
+-
+---- get version
+--- @treturn integer
+-function version() end
+-
+---- set version
+--- @tparam integer version
+--- @treturn boolean result
+-function version() end
+-
+---- get cert_req
+--- @treturn boolean true for set or not
+-function cert_req() end
+-
+---- set cert_req
+--- @tparam boolean cert_req 
+--- @treturn boolean result
+-function cert_req() end
+-
+---- get nonce
+--- @treturn bn openssl.bn object
+-function nonce() end
+-
+---- set nonce
+--- @tparam string|bn nonce
+--- @treturn boolean result
+-function nonce() end
+-
+---- get policy_id
+--- @treturn asn1_object
+-function policy_id() end
+-
+---- set policy_id
+--- @tparam asn1_object|number id  identity for asn1_object
+--- @treturn boolean result
+-function policy_id() end
+-
+---- get msg_imprint
+--- @treturn string octet octet string
+--- @treturn table with algorithm and paramater
+-function msg_imprint() end
+-
+---- set msg_imprint
+--- @tparam string data digest value of message 
+--- @tparam[opt='sha'] string|evp_md md_alg
+--- @treturn boolean result
+-function msg_imprint() end
+-
+-end --define class
+-
+-
+---- openssl.ts_resp object
+--- @type ts_resp
+-
+-do  -- define ts_resp
+-
+---- export ts_resp to string
+--- @treturn string
+-function export () end
+-
+---- duplicate ts_resp object
+--- @treturn ts_resp object
+-function dup () end
+-
+---- get info as table
+--- @treturn table 
+-function info() end
+-
+---- get info as table
+--- @treturn table 
+-function tst_info() end
+-
+-end
+-
+---- openssl.ts_verify_ctx object
+--- @type ts_verify_ctx
+-do
+---- verify ts_resp object, pkcs7 token or ts_resp data
+--- @tparam ts_resp|pkcs7|string data
+--- @treturn boolean result
+-function verify() end
+-
+---- get x509_store cacerts
+--- @treturn stack_of_x509
+-function store() end
+-
+---- set x509_store cacerts
+--- @tparam x509_store cacerts
+--- @treturn boolean result
+-function store() end
+-
+---- get flags 
+--- @treturn integer flags
+-function flags() end
+-
+---- set flags
+--- @tparam integer flags
+--- @treturn boolean result
+-function flags() end
+-
+---- get untrust certs
+--- @treturn stack_of_x509 untrust
+-function certs() end
+-
+---- set untrust certs
+--- @tparam stack_of_x509 untrust
+--- @treturn boolean result
+-function certs() end
+-
+---- get data
+--- @treturn bio data object
+-function data() end
+-
+---- set data
+--- @tparam bio data object
+--- @treturn boolean result
+-function data() end
+-
+---- get imprint
+--- @treturn string imprint
+-function imprint() end
+-
+---- set imprint
+--- @tparam string imprint
+--- @treturn boolean result
+-function imprint() end
+-
+-end
+-
+---- openssl.ts_resp_ctx object
+--- @type ts_resp_ctx
+-
+-do
+-
+---- get signer cert and pkey
+--- @treturn x509 cert object or nil
+--- @treturn evp_pkey pkey object or nil
+-function signer() end
+-
+---- set signer cert and pkey
+--- @tparam x509 cert signer cert
+--- @tparam evp_pkey pkey signer pkey
+--- @treturn boolean result
+-function signer() end
+-
+---- get additional certs 
+--- @treturn stack_of_x509 certs object or nil
+-function certs() end
+-
+---- set additional certs 
+--- @tparam stack_of_x509 certs
+--- @treturn boolean result
+-function certs() end
+-
+---- get flags
+--- @treturn integer flags
+-function flags() end
+-
+---- set flags
+--- @tparam integer flags
+--- @treturn boolean result
+-function flags() end
+-
+---- get policies
+--- @treturn stack_of_asn1_object 
+-function policies() end
+-
+---- set policies
+--- @tparam asn1_object|integer|string|stack_of_asn1_object|table policies
+--- @treturn boolean result
+-function policies() end
+-
+---- get accuracy
+--- @treturn integer seconds
+--- @treturn integer millis
+--- @treturn integer micros
+-function accuracy() end
+-
+---- set accuracy
+--- @tparam integer seconds
+--- @tparam integer millis
+--- @tparam integer micros
+--- @treturn boolean result
+-function accuracy() end
+-
+---- get clock_precision_digits
+--- @treturn integer clock_precision_digits
+-function clock_precision_digits() end
+-
+---- set clock_precision_digits
+--- @tparam integer clock_precision_digits
+--- @treturn boolean result
+-function clock_precision_digits() end
+-
+---- set status info
+--- @tparam integer status
+--- @tparam string text
+--- @treturn boolean result
+-function set_status_info() end
+-
+---- set status info cond
+--- @tparam integer status
+--- @tparam string text
+--- @treturn boolean result
+-function set_status_info_cond() end
+-
+---- add failure info 
+--- @tparam integer failure
+--- @treturn result
+-function add_failure_info() end
+-
+---- get all digest method 
+--- @treturn table contains all support digest method
+-function md() end
+-
+---- set support digest method
+--- @tparam table mds support digest method
+--- @treturn boolean result
+-function md() end
+-
+---- add digest
+--- @tparam string|evp_digest md_alg
+--- @treturn boolean result
+-function md() end
+-
+---- get tst_info as table
+--- @treturn table tst_info
+-function tst_info() end
+-
+---- get ts_req object
+--- @treturn rs_req
+-function request() end
+-
+---- set serial generate callback function
+--- @tparam function serial_cb serial_cb with proto funciont(ts_resp_ctx, arg) return openssl.bn end
+--- @usage
+---  function serial_cb(tsa,arg)
+---    local bn = ...
+---    return bn
+---  end
+---  local arg = {}
+---- ts_resp_ctx:set_serial_cb(serial_cb, arg)
+-function set_serial_cb() end
+-
+---- set time callback function
+--- @tparam function time_cb serial_cb with proto funciont(ts_resp_ctx, arg) return sec, usec end
+--- @usage
+---  function time_cb(tsa,arg)
+---    local time = os.time()
+---    local utime = nil
+---    return time,utime
+---  end
+---  local arg = {}
+---- ts_resp_ctx:set_time_cb(time_cb, arg)
+-function set_serial_cb() end
+-
+---- create response for ts_req
+--- @tparam string|bio|ts_req data support string,bio ts_req content or ts_req object
+--- @treturn ts_resp result
+-function create_response() end
+-
+---- sign ts_req and get ts_resp, alias of create_response
+--- @tparam string|bio|ts_req data support string,bio ts_req content or ts_req object
+--- @treturn ts_resp result
+-function sign() end
+-
+-end
+-
+-end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_attr.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_attr.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_attr.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_attr.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,121 +0,0 @@
+---- 
+--- Provide x509_attribute as lua object.
+--- Sometime when you make CSR,TS or X509, you maybe need to use this.
+---
+--- @module x509.attr
+--- @usage
+---  attr = require('openssl').x509.attr
+---
+-
+-do  -- define module function
+-
+---- Create x509_attribute object
+---
+--- @tparam table attribute with object, type and value
+--- @treturn[1] x509_attribute mapping to X509_ATTRIBUTE in openssl
+---
+--- @see x509_attribute_param_table
+-function new_attribute() end
+-
+---- Create stack_of_x509_attribute object, which mapping to STACK_OF(X509_ATTRIBUTE)
+---
+--- @tparam table node_array, each node is a x509_attribute node
+--- @treturn sk_x509_attribute mapping to STACK_OF(X509_ATTRIBUTE) in openssl
+---
+--- @see new_attribute, sk
+-function new_sk_attribute() end
+-
+-end
+-
+-do -- define module table
+-
+---- x509_attribute contrust param table.
+---
+--- @table x509_attribute_param_table
+--- @tfield string|integer|asn1_object object, identify a asn1_object
+--- @tfield string|integer type, same with type in asn1.new_string
+--- @tfield string|asn1_object value, value of attribute
+---
+--- @usage
+--- xattr = x509.attr.new_attribute {
+---   object = asn1_object,
+---   type = Nid_or_String,
+---   value = string or asn1_string value
+--- }
+--- 
+-function new_attribute() end
+-
+---- x509_attribute infomation table
+---
+--- @table x509_attribute_info_table
+--- @tfield asn1_object|object object of asn1_object
+--- @tfield boolean single  true for single value
+--- @tfield table value  if single, value is asn1_type or array have asn1_type node table  
+-
+---- asn1_type object as table
+---
+--- @table asn1_type_table
+--- @tfield string value, value data
+--- @tfield string type, type of value
+--- @tfield string format, value is 'der', only exist when type is not in 'bit','bmp','octet'
+--- 
+-end
+-
+-do  -- define class
+-
+---- openssl.x509_attribute object
+--- @type x509_attribute
+---
+-do  -- defint x509_attribute
+-
+---- get infomation table of x509_attribute.
+---
+--- @treturn[1] table info,  x509_attribute infomation as table
+--- @see x509_attribute_info_table
+-function info() end
+-
+---- clone then asn1_attribute
+---
+--- @treturn x509_attribute attr clone of x509_attribute
+-function dup() end
+-
+---- get type of x509_attribute.
+---
+--- @tparam[opt] integer location which location to get type, default is 0
+--- @treturn[1] table asn1_type, asn1_type as table info
+--- @treturn[2] nil nil, fail return nothing
+---
+--- @see asn1_type_table
+-function type() end
+-
+---- get asn1_object of x509_attribute.
+---
+--- @treturn[1] asn1_object object of x509_attribute
+-function object() end
+-
+---- set asn1_object for x509_attribute.
+---
+--- @tparam asn1_object obj
+--- @treturn[1] boolean true for success
+--- @treturn[2] nil nil when occure error
+--- @treturn[2] string errmsg error message
+-function object() end
+-
+---- get type of x509_attribute
+---
+--- @tparam integer idx location want to get type
+--- @tparam string attrtype attribute type
+--- @treturn asn1_string
+-function data() end
+-
+---- set type of x509_attribute
+---
+--- @tparam string attrtype attribute type
+--- @tparam string data set to asn1_attr
+--- @string data to set
+-function data() end
+-
+-end
+-
+-end
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_crl.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_crl.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_crl.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_crl.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,157 +0,0 @@
+----
+--- Provide x509_crl as lua object.
+--- create and manage x509 certificate sign request
+--- @module x509.crl
+--- @usage
+---  crl = require'openssl'.x509.crl
+---
+-
+-do --define module function
+-
+---- create or generate a new x509_crl object.
+--- Note if not give evp_pkey, will create a new x509_crl object,if give will generate a signed x509_crl object.
+--- @tparam[opt] table revoked_list 
+--- @tparam[opt] x509 cacert ca cert to sign x509_crl
+--- @tparam[opt] evp_pkey capkey private key to sign x509_crl
+--- @tparam[opt] string|evp_md md_alg
+--- @tparam[opt=7*24*3600] number period to generate new crl
+--- @treturn x509_crl object
+--- @see x509_crl
+-function new() end
+-
+---- read x509_crl from string or bio input
+--- @tparam bio|string input input data
+--- @tparam[opt='auto'] string format support 'auto','pem','der'
+--- @treturn x509_crl certificate sign request object
+--- @see x509_crl
+-function read() end
+-
+---- list all support reason info
+--- @treturn table contain support reason node like {lname=...,sname=...,bitnum=...}
+-function reason() end
+-
+-end  -- define module
+-
+-do  -- define class
+-
+---- openssl.x509_crl object
+--- @type x509_crl
+---
+-
+-do  -- define x509_crl
+-
+---- export x509_crl to string
+--- @tparam[opt='pem'] string format
+--- @tparam[opt='true'] boolean noext not export extension
+--- @treturn string
+-function export () end
+-
+---- sign x509_crl
+--- @tparam evp_pkey pkey private key to sign x509
+--- @tparam x509|x509_name cacert or cacert x509_name
+--- @tparam[opt='sha1WithRSAEncryption'] string|md_digest md_alg
+--- @treturn boolean result true for check pass
+-function sign() end
+-
+---- get digest of x509_crl
+--- @tparam[opt='SHA1'] evp_md|string md_alg default use sha1
+--- @treturn string digest result
+-function digest() end
+-
+---- compare with other x509_crl object
+--- @tparam x509_crl other
+--- @treturn boolean result true for equals or false
+--- @usage
+---  x:cmp(y) == (x==y)
+-function cmp() end
+-
+---- make a delta x509_crl object
+--- @tparam x509_crl newer
+--- @tparam evp_pkey pkey
+--- @tparam[opt='sha1'] evp_md|string md_alg
+--- @tparam[opt=0] integer flags
+--- @treturn x509_crl delta result x509_crl object 
+-function diff() end
+-
+---- check x509_crl with evp_pkey
+--- @tparam evp_pkey pkey
+--- @tparam[opt=0] integer flags 
+--- @treturn boolean result true for pass
+-function check() end
+-
+---- parse x509_crl object as table
+--- @tparam[opt=true] shortname default will use short object name
+--- @treturn table result
+-function parse() end
+-
+---- get count of revoked entry
+--- @treturn number count
+--- @usage
+---  assert(#crl==crl:count())
+-function count() end
+-
+---- get revoekd entry
+--- @tparam number index
+--- @treturn table revoekd 
+-function get() end
+-
+---- set version key
+--- @tparam integer version
+--- @treturn boolean result
+-function version() end
+-
+---- get issuer x509_name object
+--- @treturn x509_name
+-function issuer() end
+-
+---- set issuer x509_name object
+--- @tparam x509_name|x509 issuer
+--- @treturn boolean result
+-function issuer() end
+-
+---- get lastUpdate time
+--- @treturn string lastUpdate
+-function lastUpdate() end
+-
+---- set lastUpdate time
+--- @tparam number lastUpdate
+--- @treturn boolean result
+-function lastUpdate() end
+-
+---- get nextUpdate time
+--- @treturn string nextUpdate
+-function nextUpdate() end
+-
+---- set nextUpdate time
+--- @tparam number nextUpdate
+--- @treturn boolean result
+-function nextUpdate() end
+-
+---- get updateTime time
+--- @treturn string lastUpdate
+--- @treturn string nextUpdate
+-function updateTime() end
+-
+---- set updateTime time
+--- @tparam[opt=os.time()] lastUpdate, default use current time
+--- @tparam number periord periord how long time(seconds)
+--- @treturn boolean result
+-function updateTime() end
+-
+---- get extensions of x509_crl
+--- @treturn stack_of_x509_extension extensions
+-function extensions() end
+-
+---- set extensions to x509_crl object
+--- @tparam stack_of_x509_extension extensions add to x509_crl
+--- @treturn boolean result
+-function extensions() end
+-
+---- add revoked entry to x509_crl object
+--- @tparam string|number|bn serial
+--- @tparam number revokedtime
+--- @tparam[opt=0] number|string reason
+--- @treturn boolean result true for add success
+-function add() end
+-
+-end --define class
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_extension.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_extension.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_extension.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_extension.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,142 +0,0 @@
+---- 
+--- Provide x509_extension as lua object.
+--- Sometime when you make CSR,TS or X509, you maybe need to use this.
+---
+--- @module x509.extension
+--- @usage
+---  extension = require('openssl').x509.extension
+---
+-
+-do  -- define module function
+-
+---- Create x509_extension object
+---
+--- @tparam table extension with object, value and critical
+--- @treturn x509_extension mapping to X509_EXTENSION in openssl
+---
+--- @see x509_extension_param_table
+-function new_extension() end
+-
+---- read der encoded x509_extension
+--- @tparam string data der encoded
+--- @treturn x509_extension mappling to X509_EXTENSION in openssl
+-function read_extension() end
+-
+---- Create stack_of_x509_extension object, which mapping to STACK_OF(X509_EXTENSION)
+---
+--- @tparam table node_array, each node is a x509_extension node
+--- @treturn[1] sk_x509_extension mapping to STACK_OF(X509_EXTENSION) in openssl
+---
+--- @see new_extension, sk
+-function new_sk_extension() end
+-
+---- get all x509 certificate supported extensions
+--- @treturn table contain all support extension nid
+--- @treturn table contain all support extension info as table node {lname=..., sname=..., nid=...}
+-function support() end
+-
+---- ask x509_extension object support or not 
+--- @tparam x509_extension extension 
+--- @tparam boolean true for supported, false or not 
+-function support() end
+-
+---- ask nid or name support or not 
+--- @tparam number|string nid_or_name for extension 
+--- @tparam boolean true for supported, false or not 
+-function support() end
+-
+-end
+-
+-do -- define module table
+-
+---- x509_extension contrust param table.
+---
+--- @table x509_extension_param_table
+--- @tfield boolean critical true set critical
+--- @tfield asn1_string value of x509_extension
+--- @tfield string|asn1_object object, object of extension
+---
+--- @usage
+--- xattr = x509.attr.new_extension {
+---   object = asn1_object,
+---   critical = false,
+---   value = string or asn1_string value
+--- }
+-function new_extension() end
+-
+---- x509_extension infomation table
+--- other field is number type, and value table is alter name.(I not understand clearly)
+--- @table x509_extension_info_table
+--- @tfield asn1_object|object object of x509_extension
+--- @tfield boolean|critical true for critical value
+--- @tfield string|value as octet string
+-
+-
+-end
+-
+-do  -- define class
+-
+---- openssl.x509_extension object
+--- @type x509_extension
+---
+-do  -- defint x509_extension
+-
+---- get infomation table of x509_extension.
+---
+--- @tparam[opt] boolean|utf8 true for utf8 default 
+--- @treturn[1] table info,  x509_extension infomation as table
+--- @see x509_extension_info_table
+-function info() end
+-
+---- clone then x509_extension
+---
+--- @treturn x509_extension attr clone of x509_extension
+-function dup() end
+-
+---- get critical of x509_extension.
+---
+--- @treturn boolean true if extension set critical or false
+-function critical() end
+-
+---- set critical of x509_extension.
+---
+--- @tparam boolean critical set to self
+--- @treturn[1] boolean set critical success return true
+--- @treturn[2] nil nil, fail return nothing
+--- @treturn[2] string errmsg reason of fail
+-function critical() end
+-
+---- get asn1_object of x509_extension.
+---
+--- @treturn[1] asn1_object object of x509_extension
+-function object() end
+-
+---- set asn1_object for x509_extension.
+---
+--- @tparam asn1_object obj
+--- @treturn[1] boolean true for success
+--- @treturn[2] nil nil when occure error
+--- @treturn[2] string errmsg error message
+-function object() end
+-
+---- get data of x509_extension
+---
+--- @treturn asn1_string
+-function data() end
+-
+---- set type of x509_extension
+---
+--- @tparam asn1_string data set to self
+--- @treturn[1] boolean true for success
+--- @treturn[2] nil nil when occure error
+--- @treturn[2] string errmsg error message
+-function data() end
+-
+---- export x509_extenion to der encoded string
+--- @treturn string 
+-function export() end
+-
+-end
+-
+-end
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,187 +0,0 @@
+----
+--- Provide x509 module.
+--- create and manage x509 certificate
+--- @module x509
+--- @usage
+---  x509 = require'openssl'.x509
+---
+-
+-do --define module function
+-
+---- create or generate a new x509 object.
+--- @tparam[opt] openssl.bn serial serial number
+--- @tparam[opt] x509_req csr,copy x509_name, pubkey and extension to new object
+--- @tparam[opt] x509_name subject subject name set to x509_req
+--- @tparam[opt] stack_of_x509_extension extensions add to x509
+--- @tparam[opt] stack_of_x509_attribute attributes add to x509
+--- @treturn x509 certificate object
+-function new() end
+-
+---- read x509 from string or bio input
+--- @tparam bio|string input input data
+--- @tparam[opt='auto'] string format support 'auto','pem','der'
+--- @treturn x509 certificate object
+-function read() end
+-
+---- return all supported purpose as table
+--- @treturn table
+-function purpose() end
+-
+---- get special purpose info as table
+--- @tparam number|string purpose id or short name
+--- @treturn table
+-function purpose() end
+-
+---- get support certtypes
+--- @tparam[opt='standard'] string type support 'standard','netscape','extend'
+--- @treturn table if type is 'standard' or 'netscape', contains node with {lname=...,sname=...,bitname=...},
+---                if type is 'extend', contains node with {lname=...,sname=...,nid=...}
+-function certtypes() end
+-
+---- get certificate verify result string message
+--- @tparam number verify_result
+--- @treturn string result message
+-function verify_cert_error_string() end
+-
+-end --define module
+-
+-do  -- define class
+-
+---- openssl.x509 object
+--- @type x509
+---
+-
+-do  -- define x509
+-
+---- export x509_req to string
+--- @tparam[opt='pem'] string format, 'der' or 'pem' default
+--- @tparam[opt='true'] boolean noext not export extension
+--- @treturn string
+-function export() end
+-
+---- parse x509 object as table
+--- @tparam[opt=true] shortname default will use short object name
+--- @treturn table result which all x509 information
+-function parse() end
+-
+---- sign x509
+--- @tparam evp_pkey pkey private key to sign x509
+--- @tparam x509|x509_name cacert or cacert x509_name
+--- @tparam[opt='sha1WithRSAEncryption'] string|md_digest md_alg
+--- @treturn boolean result true for check pass
+-function sign() end
+-
+---- check x509 with evp_pkey
+--- @tparam evp_pkey pkey private key witch match with x509 pubkey
+--- @treturn boolean result true for check pass
+-function check() end
+-
+---- check x509 with ca certchian and option purpose
+--- purpose can be one of: ssl_client, ssl_server, ns_ssl_server, smime_sign, smime_encrypt, crl_sign, any, ocsp_helper, timestamp_sign
+--- @tparam x509_store cacerts 
+--- @tparam x509_store untrusted certs  containing a bunch of certs that are not trusted but may be useful in validating the certificate.
+--- @tparam[opt] string purpose to check supported
+--- @treturn boolean result true for check pass
+--- @treturn integer verify result
+--- @see verify_cert_error_string
+-function check() end
+-
+---- get digest of x509 object
+--- @tparam[opt='sha1'] evp_digest|string md_alg, default use 'sha1'
+--- @treturn string digest result
+-function digest() end
+-
+---- get public key of x509
+--- @treturn evp_pkey public key
+-function pubkey() end
+-
+---- set public key of x509
+--- @tparam evp_pkey pubkey public key set to x509
+--- @treturn boolean result, true for success
+-function pubkey() end
+-
+---- get extensions of x509 object
+--- @tparam[opt=false] boolean asobject, true for return as stack_of_x509_extension or as table
+--- @treturn[1] stack_of_x509_extension object when param set true
+--- @treturn[2] table contain all x509_extension when param set false or nothing
+-function extensions() end
+-
+---- set extension of x509 object
+--- @tparam stack_of_x509_extension extensions
+--- @treturn boolean result true for success
+-function extensions() end
+-
+---- get issuer name of x509
+--- @tparam[opt=false] boolean asobject, true for return as x509_name object, or as table
+--- @treturn[1] x509_name issuer
+--- @treturn[1] table issuer name as table
+-function issuer() end
+-
+---- set issuer name of x509
+--- @tparam x509_name name
+--- @treturn boolean result true for success
+-function issuer() end
+-
+---- get subject name of x509
+--- @tparam[opt=false] boolean asobject, true for return as x509_name object, or as table
+--- @treturn[1] x509_name subject name
+--- @treturn[1] table subject name as table
+-function subject() end
+-
+---- set subject name of x509
+--- @tparam x509_name subject
+--- @treturn boolean result true for success
+-function subject() end
+-
+---- get serial number of x509
+--- @tparam[opt=true] boolean asobject
+--- @treturn[1] bn object
+--- @treturn[2] string result
+-function serial() end
+-
+---- set serial number of x509
+--- @tparam string|number|bn serail
+--- @treturn boolean result true for success
+-function serial() end
+-
+---- get version number of x509
+--- @treturn number version of x509
+-function version() end
+-
+---- set version number of x509
+--- @tparam number version
+--- @treturn boolean result true for result
+-function version() end
+-
+---- get notbefore valid time of x509
+--- @treturn string notbefore time string
+-function notbefore() end
+-
+---- set notbefore valid time of x509
+--- @tparam string|number notbefore
+-function notbefore() end
+-
+---- get notafter valid time of x509
+--- @treturn string notafter time string
+-function notafter() end
+-
+---- set notafter valid time of x509
+--- @tparam string|number notafter
+-function notafter() end
+-
+---- check x509 valid
+--- @tparam[opt] number time, default will use now time
+--- @treturn boolean result true for valid, or for invalid
+--- @treturn string notbefore
+--- @treturn string notafter
+-function validat()
+-
+---- set valid time, notbefore and notafter
+--- @tparam number notbefore
+--- @tparam number notafter
+--- @treturn boolean result, true for success
+-function validat() end
+-
+-end --define x509
+-
+-end --define class
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_name.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_name.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_name.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_name.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,144 +0,0 @@
+---- 
+--- Provide x509_name as lua object.
+--- Sometime when you make CSR,TS or X509, you maybe need to use this.
+---
+--- @module x509.name
+--- @usage
+---  name = require('openssl').x509.name
+---
+-
+-
+-do  -- define module function
+-
+---- Create x509_name object
+---
+--- @tparam table array include name node
+--- @tparam[opt] boolean utf8 encode will be use default
+--- @treturn x509_name mapping to X509_EXTENSION in openssl
+--- @usage
+---  name = require'openssl'.x509.name
+---  subject = name.new{
+---    {C='CN'},
+---    {O='kkhub.com'},
+---    {CN='zhaozg'}
+---  }
+---
+-
+-function new() end
+-
+---- Create x509_name from der string
+---
+--- @tparam string content DER encoded string
+--- @treturn x509_name mapping to X509_NAME in openssl
+---
+-function d2i() end
+-
+-end
+-
+-do -- define module table
+---
+---- x509_name infomation table
+--- other field is number type, and value table is alter name.(I not understand clearly)
+--- @table x509_extension_info_table
+--- @tfield asn1_object|object object of x509_name
+--- @tfield boolean|critical true for critical value
+--- @tfield string|value as octet string
+-
+-
+-end
+-
+-do  -- define class
+-
+---- openssl.x509_name object
+--- @type x509_name
+---
+-do  -- define x509_name
+-
+---- as oneline of x509_name.
+---
+--- @treturn string line, name as oneline text 
+-function oneline() end
+-
+---- get hash code of x509_name
+---
+--- @treturn integer hash hash code of x509_name
+-function hash() end
+-
+---- get digest of x509_name
+---
+--- @tparam string|nid|openssl.evp_md md method of digest
+--- @treturn string digest digest value by given alg of x509_name
+-function digest() end
+-
+---- print x509_name to bio object
+---
+--- @tparam openssl.bio out output bio object
+--- @tparam[opt] integer indent for output
+--- @tparam[opt] integer flags for output
+--- @treturn boolean result, follow by error message
+-function print() end
+-
+---- return x509_name as table
+---
+--- @tparam boolean utf8 true for utf8 encoded string, default
+--- @treturn table names
+--- @see new
+-function info() end
+-
+---- compare two x509_name
+---
+--- @tparam x509_name another to compare with 
+--- @treturn boolean result true for equal or false
+--- @usage
+---
+---  name1 = name.new({...})
+---  name2 = name1:dup()
+---  assert(name1:cmp(name2)==(name1==name2))
+---
+-function cmp() end
+-
+---- get DER encoded string of x509_name.
+---
+--- @treturn string der
+-function i2d() end
+-
+---- get count in x509_name.
+---
+--- @treturn integer count of x509_name
+-function entry_count() end
+-
+---- get text by given asn1_object or nid
+---
+--- @tparam string|integer|asn1_object identid for asn1_object
+--- @tparam[opt=-1] number lastpos retrieve the next index after lastpos
+--- @treturn string
+--- @treturn lastpos
+-function get_text() end
+-
+---- get x509 name entry by index
+--- @tparam integer index start from 0, and less than xn:entry_count()
+--- @tparam[opt=true] boolean utf8
+--- @treturn x509 name entry table
+-function get_entry() end
+-
+---- add name entry 
+---
+--- @tparam string|integer|asn1_object identid for asn1_object
+--- @tparam string data to add
+--- @tparam[opt] boolean utf8 true for use utf8 default
+--- @treturn boolean result true for success or follow by error message
+-function add_entry() end
+-
+---- get index by give asn1_object or nid
+---
+--- @tparam integer location which name entry to delete
+--- @treturn[1] asn1_object object that delete name entry
+--- @treturn[1] asn1_string value that delete name entry
+--- @treturn[2] nil delete nothing 
+-function delete_entry() end
+-
+-
+-end
+-
+-end
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_req.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_req.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_req.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_req.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,119 +0,0 @@
+----
+--- Provide x509_req as lua object.
+--- create and manage x509 certificate sign request
+--- @module x509.req
+--- @usage
+---  req = require'openssl'.x509.req
+---
+-
+-do --define module function
+-
+---- create or generate a new x509_req object.
+--- Note if not give evp_pkey, will create a new x509_req object,or will generate a signed x509_req object.
+--- @tparam[opt] x509_name subject subject name set to x509_req
+--- @tparam[opt] stack_of_x509_extension extensions add to x509_req
+--- @tparam[opt] stack_of_x509_attribute attributes add to x509_req
+--- @tparam[opt] evp_pkey pkey private key sign the x509_req, and set as public key
+--- @tparam[opt='sha1WithRSAEncryption'] evp_digest|string md_alg,  only used when pkey exist, and should fellow pkey
+--- @treturn x509_req certificate sign request object
+--- @see x509_req
+-function new () end
+-
+---- read x509_req from string or bio input
+--- @tparam bio|string input input data
+--- @tparam[opt='auto'] string format support 'auto','pem','der'
+--- @treturn x509_req certificate sign request object
+-function read() end
+-
+-end  -- define module
+-
+-do  -- define class
+-
+---- openssl.x509_req object
+--- @type x509_req
+---
+-
+-do  -- define x509_req
+-
+---- export x509_req to string
+--- @tparam[opt='pem'] string format
+--- @tparam[opt='true'] boolean noext not export extension
+--- @treturn string
+-function export () end
+-
+---- get public key
+--- @treturn evp_pkey public key
+-function public() end
+-
+---- set public key
+--- @tparam evp_pkey pubkey public key set to x509_req
+--- @treturn boolean result
+-function public() end
+-
+---- get version key
+--- @treturn integer
+-function version() end
+-
+---- set version key
+--- @tparam integer version
+--- @treturn boolean result
+-function version() end
+-
+---- get subject x509_name object
+--- @treturn x509_name
+-function subject() end
+-
+---- set subject x509_name object
+--- @tparam x509_name subject
+--- @treturn boolean result
+-function subject() end
+-
+---- remove attribute object from location
+--- @tparam integer location
+--- @tparam nil nil, nil not none
+--- @treturn x509_attribute attribute removed
+-function attribute() end
+-
+---- get attribute object from location
+--- @tparam integer location
+--- @treturn x509_attribute attribute
+-function attribute() end
+-
+---- add attribute to x509_req object
+--- @tparam x509_attribute attribute attribute to add
+--- @treturn boolean result
+-function attribute() end
+-
+---- get total attribute count in x509_req object
+--- @treturn integer
+-function attr_count() end
+-
+---- convert x509_req to x509 object
+--- @treturn x509 object not signed
+--- @fixme memleaks
+-function to_x509()
+-
+---- clone x509_req object
+--- @treturn x509_req object
+-function dup()
+-
+---- check x509_req with evp_pkey
+--- @tparam evp_pkey pkey
+--- @treturn boolean result true for check pass
+-function check() end
+-
+---- verify x509_req signature
+--- @treturn boolean result true for verify pass
+-function verify() end
+-
+---- get digest of x509_req
+--- @tparam[opt='SHA1'] evp_md|string md_alg default use sha1
+--- @treturn string digest result
+-function digest() end
+-
+---- parse x509_req object as table
+--- @tparam[opt=true] shortname default will use short object name
+--- @treturn table result
+-function parse() end
+-
+-end --define class
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_store.lua luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_store.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/ldoc/x509_store.lua	2019-02-13 11:31:40.280635356 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/ldoc/x509_store.lua	1970-01-01 01:00:00.000000000 +0100
+@@ -1,69 +0,0 @@
+----
+--- Provide x509_store as lua object.
+--- create and manage x509 store object
+--- @module x509.store
+--- @usage
+---  store = require'openssl'.x509.store
+---
+-
+-do --define module function
+-
+---- create or generate a new x509_store object.
+--- @tparam table certs array of x509 objects, all x509 object will add to store, certs can be empty but not nil
+--- @tparam[opt] table crls array of x509_crl objects, all crl object will add to store
+--- @treturn x509_store object
+--- @see x509_store
+-function new() end
+-
+-end  -- define module
+-
+-do  -- define class
+-
+---- openssl.x509_store object
+--- @type x509_store
+---
+-
+-do  -- define x509_store
+-
+-function export () end
+-
+---- set verify depth of certificate chains
+--- @tparam number depth
+--- @treturn boolean result 
+-function depth() end
+-
+---- set verify flags of certificate chains
+--- @tparam number flags
+--- @treturn boolean result 
+-function flags() end
+-
+---- set as trust x509 store
+--- @tparam boolean trust
+--- @treturn boolean result 
+-function trust() end
+-
+---- set prupose of x509 store
+--- @tparam integer purpose
+--- @treturn boolean result
+-function purpose() end
+-
+---- load certificate from file or dir,not given any paramater will load from defaults path
+--- @tparam[opt] string filepath
+--- @tparam[opt] string dirpath
+--- @treturn boolean result
+-function load() end
+-
+---- add x509 certificate or crl to store
+--- paramater support x509 object,x509_crl object or array contains x509,x509_crl object
+--- @treturn boolean result
+-function add(...) end
+-
+---- add lookup path for store
+--- @tparam string path file or dir path to add
+--- @tparam[opt='file'] mode only 'file' or 'dir'
+--- @tparam[opt='default'] format only 'pem', 'der' or 'default'
+--- @treturn boolean result
+-function add_lookup() end
+-
+-end --define class
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/lib/luv/ssl.lua luvi-src-v2.7.6/deps/lua-openssl/lib/luv/ssl.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/lib/luv/ssl.lua	2019-02-13 11:31:40.277302045 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/lib/luv/ssl.lua	2019-02-13 11:53:24.105128513 +0100
+@@ -1,240 +1,246 @@
+-local uv = require('luv')
+-local openssl=require'openssl'
+-local ssl,bio,x509,pkey,csr = openssl.ssl,openssl.bio,openssl.x509,openssl.pkey,openssl.csr
++local uv = require 'luv'
++local openssl = require 'openssl'
++local ssl, bio, x509, pkey, csr = openssl.ssl, openssl.bio, openssl.x509, openssl.pkey, openssl.csr
+ 
+-local bit = require'bit'
++local bit = require 'bit'
+ local print = print
+--- support 
++-- support
+ local M = {}
+ 
+-local function load(path)
+-    local f = io.open(path,'rb')
+-    if f then
+-        local c = f:read('*a')
+-        f:close()
+-        return c
+-    end
++local function load (path)
++  local f = io.open(path, 'rb')
++  if f then
++    local c = f:read '*a'
++    f:close()
++    return c
++  end
+ end
+ 
+-function M.new_ctx(params)
+-    params = params or {}
+-    local protocol = params.protocol or  'SSLv3_client'
+-    local ctx = ssl.ctx_new(protocol, params.ciphers)
+-
+-	local xkey,xcert = nil,nil
+-
+-    if (params.certificate) then
+-        xcert = assert(x509.read(load(params.certificate)))
+-    end
+-
+-	if params.key then
+-		if (type(params.password)=='nil') then
+-			xkey = assert(pkey.read(load(params.key),true,'pem'))
+-		elseif (type(params.password)=='string')  then
+-			xkey = assert(pkey.read(load(params.key),true,'pem',params.password))
+-		elseif (type(params.password)=='function') then
+-			local p = assert(params.password())
+-			xkey = assert(pkey.read(load(params.key),true,'pem',p))
+-		end
+-		assert(ctx:use(xkey, xcert))
+-	end
+-
+-    if(params.cafile or params.capath) then
+-        ctx:verify_locations(params.cafile,params.capath)
+-    end
+-
+-    local unpack = unpack or table.unpack   
+-    if(params.verify) then
+-        ctx:verify_mode(params.verify)
+-    end
+-    if params.options and #params.options>0 then
+-        local args = {}
+-        for i=1,#params.options do
+-            table.insert(arg,params.options[i])
+-        end
+-        ctx:options(ssl.none)
+-    end
+-    
+-    if params.verifyext then
+-        ctx:set_cert_verify(params.verifyext)
+-    end
+-    if params.dhparam then
+-        ctx:set_tmp('dh',params.dhparam)
+-    end
+-    if params.curve then
+-        ctx:set_tmp('ecdh',params.curve)
+-    end
+-	return ctx
++function M.new_ctx (params)
++  params = params or {}
++  local protocol = params.protocol or 'SSLv3_client'
++  local ctx = ssl.ctx_new(protocol, params.ciphers)
++
++  local xkey, xcert = nil, nil
++
++  if params.certificate then
++    local ctx = assert(load(params.certificate))
++    xcert = assert(x509.read(ctx))
++  end
++
++  if params.key then
++    if type(params.password) == 'nil' then
++      xkey = assert(pkey.read(load(params.key), true, 'pem'))
++    elseif type(params.password) == 'string' then
++      xkey = assert(pkey.read(load(params.key), true, 'pem', params.password))
++    elseif type(params.password) == 'function' then
++      local p = assert(params.password())
++      xkey = assert(pkey.read(load(params.key), true, 'pem', p))
++    end
++    assert(ctx:use(xkey, xcert))
++  end
++
++  if params.cafile or params.capath then
++    ctx:verify_locations(params.cafile, params.capath)
++  end
++
++  local unpack = unpack or table.unpack
++  if params.verify then
++    ctx:verify_mode(params.verify)
++  end
++  if params.options and #params.options > 0 then
++    local args = {}
++    for i = 1, #params.options do
++      table.insert(arg, params.options[i])
++    end
++    ctx:options(ssl.none)
++  end
++
++  if params.verifyext then
++    ctx:set_cert_verify(params.verifyext)
++  end
++  if params.dhparam then
++    ctx:set_tmp('dh', params.dhparam)
++  end
++  if params.curve then
++    ctx:set_tmp('ecdh', params.curve)
++  end
++  return ctx
+ end
+ 
+ local S = {}
+ S.__index = {
++  handshake = function (self, connected_cb)
++    if not self.connecting then
++      uv.read_start(self.socket, function (err, chunk)
++          if err then
++            print('ERR', err)
++            self:onerror(err)
++          end
++          if chunk then
++            self.inp:write(chunk)
++            self:handshake(connected_cb)
++          else
++            self:close()
++          end
++        end)
++
++      self.connecting = true
++    end
++    if not self.connected then
++      local ret, err = self.ssl:handshake()
++      if ret == nil then
++        if self.onerror then
++          self:onerror()
++        elseif self.onclose then
++          self:onclose()
++        else
++          self:close()
++        end
++      else
++        local i, o = self.out:pending()
++        if i > 0 then
++          --client handshake
++          uv.write(self.socket, self.out:read(), function ()
++              self:handshake(connected_cb)
++            end)
++          return
++        end
++        if ret == false then
++          return
++        end
+ 
+-    handshake = function(self, connected_cb)
+-		if not self.connecting then
+-            uv.read_start(self.socket, function(err,chunk)
+-                if(err) then 
+-                    print('ERR',err)
+-                    self:onerror(err)
+-                end
+-                if chunk then
+-                    self.inp:write(chunk)
+-                    self:handshake(connected_cb)
+-                else
+-                    self:close()
++        self.connected = true
++        uv.read_stop(self.socket)
++        uv.read_start(self.socket, function (err, chunk)
++            if err then
++              print('ERR', err)
++              self:onerror()
++            end
++            if chunk then
++              local ret, err = self.inp:write(chunk)
++              if ret == nil then
++                if self.onerror then
++                  self.onerror(self)
++                elseif self.onend then
++                  self.onend(self)
+                 end
+-			end)
++                return
++              end
+ 
+-            self.connecting = true
+-		end
+-        if not self.connected then
+-            local ret,err = self.ssl:handshake()
+-            if ret==nil then
+-                if (self.onerror) then
+-                    self:onerror()
+-                elseif (self.onclose) then
+-                    self:onclose()
+-                else
+-                    self:close()
++              while self.connected and self.inp:pending()>0 do
++                if o > 0 then
++                  assert(false, 'never here')
+                 end
+-            else
+-                local i, o = self.out:pending()
+-                if i > 0 then  --�ͻ�������ʹ��
+-                    uv.write(self.socket, self.out:read(), function()
+-                        self:handshake(connected_cb)
+-                    end)
+-                    return
++                local ret, msg = self.ssl:read()
++                if ret then
++                  self:ondata(ret)
+                 end
+-                if (ret==false) then return end
+-                
+-                self.connected = true
+-                uv.read_stop(self.socket)
+-                uv.read_start(self.socket, function(err,chunk)
+-                    if(err) then 
+-                        print('ERR',err)
+-                        self:onerror()
+-                    end
+-                    if chunk then
+-                        local ret,err = self.inp:write(chunk)
+-                        if ret==nil then
+-                            if self.onerror then
+-                                self.onerror(self)
+-                            elseif self.onend then
+-                                self.onend(self)
+-                            end
+-                            return
+-                        end
+-                        
+-                        local i,o = self.inp:pending()
+-                        while i>0 do
+-                            if o > 0 then
+-                                assert(false,'never here')
+-                            end
+-                            local ret, msg = self.ssl:read()
+-                            if ret then
+-                                self:ondata(ret)
+-                            end
+-                            i,o = self.inp:pending()
+-                        end
+-                    else
+-                        self:close()
+-                    end
+-                end)
+-                connected_cb(self)
+-            end
+-
+-            return self.connected
+-        end
+-	end,
+-    shutdown = function(self,callback)
+-        if not self.shutdown then
+-            self.ssl:shutdown()
+-            self.socket:shutdown()
+-            if callback then
+-                callback(self)
+-            end
+-            self.shutdown = true
+-        end
+-    end,
+-    close = function(self)
+-        if self.connected then
+-            if self.onclose then
+-                self.onclose(self)
+-            end
+-            self:shutdown()
+-            if self.ssl then
+-                self.ssl:shutdown()
+-            end
+-            self.ssl = nil
+-            if self.inp then self.inp:close() end
+-            if self.out then self.out:close() end
+-
+-            self.out,self.inp = nil,nil
+-            uv.close(self.socket)
+-            self.connected = nil
+-            self.socket = nil
+-        end
+-    end,
+-    write = function(self,data,cb)
+-        if not self.ssl then
+-            return
+-        end
+-        local ret,err = self.ssl:write(data)
+-        if ret==nil then
+-            if self.onerror then
+-                self.onerror(self)
+-            elseif self.onend then
+-                self.onend(self)
++              end
++            else
++              self:close()
+             end
+-            return
+-        end
+-        local i,o = self.out:pending()
+-        if i>0 then
+-            uv.write(self.socket,self.out:read(),cb)
+-        end
+-        if o > 0 then
+-            assert(false,'never here')
+-        end
++          end)
++        connected_cb(self)
++      end
++
++      return self.connected
++    end
++  end,
++  shutdown = function (self, callback)
++    if not self.shutdown then
++      self.ssl:shutdown()
++      self.socket:shutdown()
++      if callback then
++        callback(self)
++      end
++      self.shutdown = true
++    end
++  end,
++  close = function (self)
++    if self.connected then
++      if self.onclose then
++        self.onclose(self)
++      end
++      self:shutdown()
++      if self.ssl then
++        self.ssl:shutdown()
++      end
++      self.ssl = nil
++      if self.inp then
++        self.inp:close()
++      end
++      if self.out then
++        self.out:close()
++      end
++
++      self.out, self.inp = nil, nil
++      uv.close(self.socket)
++      self.connected = nil
++      self.socket = nil
++    end
++  end,
++  write = function (self, data, cb)
++    if not self.ssl then
++      return
++    end
++    local ret, err = self.ssl:write(data)
++    if ret == nil then
++      if self.onerror then
++        self.onerror(self)
++      elseif self.onend then
++        self.onend(self)
++      end
++      return
++    end
++    local i, o = self.out:pending()
++    if i > 0 then
++      uv.write(self.socket, self.out:read(), cb)
+     end
++    if o > 0 then
++      assert(false, 'never here')
++    end
++  end,
++
+ }
+ 
+-function M.new_ssl(ctx,socket,server)
+-    local s = {}
+-    s.inp,s.out  =  bio.mem(8192),bio.mem(8192)
+-    s.socket    =  socket
+-    s.mode = server and server or false
+-    s.ssl = ctx:ssl(s.inp,s.out,s.mode)
+-	uv.tcp_nodelay(socket,true)
+-    
+-    setmetatable(s,S)
+-    return s
++function M.new_ssl (ctx, socket, server)
++  local s = {}
++  s.inp, s.out = bio.mem(8192), bio.mem(8192)
++  s.socket = socket
++  s.mode = server and server or false
++  s.ssl = ctx:ssl(s.inp, s.out, s.mode)
++  uv.tcp_nodelay(socket, true)
++
++  setmetatable(s, S)
++  return s
+ end
+ 
+-function M.connect(host,port,ctx,connected_cb)
+-    if type(ctx)=='table' then
+-        ctx = ssl.new_ctx(ctx)
+-    end
+-    local socket = uv.new_tcp()
+-    local scli = M.new_ssl(ctx, socket) 
+-    
+-    uv.tcp_connect(socket, host, port, function(self, err)
+-        if err then 
+-            print('ERROR',err)
+-        else
+-            print('SCLI',scli)
+-            scli:handshake(function(self)
+-                if connected_cb then
+-                    connected_cb(self)
+-                end
+-            end)
+-        end
++function M.connect (host, port, ctx, connected_cb)
++  if type(ctx) == 'table' then
++    ctx = ssl.new_ctx(ctx)
++  end
++  local socket = uv.new_tcp()
++  local scli = M.new_ssl(ctx, socket)
++
++  uv.tcp_connect(socket, host, port, function (self, err)
++      if err then
++        print('ERROR', err)
++      else
++        print('SCLI', scli)
++        scli:handshake(function (self)
++            if connected_cb then
++              connected_cb(self)
++            end
++          end)
++      end
+     end)
+ 
+-    return scli   
++  return scli
+ end
+ 
+-function M.error()
+-    return openssl.error(true)
++function M.error ()
++  return openssl.error(true)
+ end
+ 
+ return M
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/Makefile luvi-src-v2.7.6/deps/lua-openssl/Makefile
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/Makefile	2019-02-13 11:31:40.273968734 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/Makefile	2019-02-13 11:53:24.105128513 +0100
+@@ -1,85 +1,121 @@
+-T=openssl
+-
+-PREFIX		?=/usr/local
+-LIB_OPTION	?= -shared 
+-
+-#Lua auto detect
+-LUA_VERSION ?= $(shell pkg-config luajit --print-provides)
+-ifeq ($(LUA_VERSION),)                         ############ Not use luajit
+-LUAV		?= $(shell lua -e "_,_,v=string.find(_VERSION,'Lua (.+)');print(v)")
+-LUA_CFLAGS	?= -I$(PREFIX)/include/lua$(LUAV)
+-LUA_LIBS	?= -L$(PREFIX)/lib 
+-LUA_LIBDIR	?= $(PREFIX)/lib/lua/$(LUAV)
+-else
+-LUAV		?= $(shell lua -e "_,_,v=string.find(_VERSION,'Lua (.+)');print(v)")
+-LUA_CFLAGS	?= $(shell pkg-config luajit --cflags)
+-LUA_LIBS	?= $(shell pkg-config luajit --libs)
+-LUA_LIBDIR	?= $(PREFIX)/lib/lua/$(LUAV)
+-endif
+-
+-#OS auto detect
+-SYS := $(shell gcc -dumpmachine)
+-
+-ifneq (, $(findstring linux, $(SYS)))
+-# Do linux things
+-LDFLAGS		    = -fPIC -lrt -ldl
+-OPENSSL_LIBS	?= $(shell pkg-config openssl --libs) 
+-OPENSSL_CFLAGS	?= $(shell pkg-config openssl --cflags)
+-CFLAGS		    = -fPIC $(OPENSSL_CFLAGS) $(LUA_CFLAGS)
+-endif
+-ifneq (, $(findstring apple, $(SYS)))
+-# Do darwin things
+-LDFLAGS		    = -fPIC -lrt -ldl
+-OPENSSL_LIBS	?= $(shell pkg-config openssl --libs) 
+-OPENSSL_CFLAGS	?= $(shell pkg-config openssl --cflags)
+-CFLAGS		    = -fPIC $(OPENSSL_CFLAGS) $(LUA_CFLAGS)
+-endif
+-ifneq (, $(findstring mingw, $(SYS)))
+-# Do mingw things
+-V			= $(shell lua -e "v=string.gsub('$(LUAV)','%.','');print(v)")
+-LDFLAGS		= -mwindows -lcrypt32 -lssl -lcrypto -lws2_32 $(PREFIX)/bin/lua$(V).dll 
+-LUA_CFLAGS	= -DLUA_LIB -DLUA_BUILD_AS_DLL -I$(PREFIX)/include/
+-CFLAGS		= $(OPENSSL_CFLAGS) $(LUA_CFLAGS)
+-endif
+-ifneq (, $(findstring cygwin, $(SYS)))
+-# Do cygwin things
+-OPENSSL_LIBS	?= $(shell pkg-config openssl --libs) 
+-OPENSSL_CFLAGS  ?= $(shell pkg-config openssl --cflags)
+-CFLAGS		= -fPIC $(OPENSSL_CFLAGS) $(LUA_CFLAGS)
+-endif
+-#custome config
+-ifeq (.config, $(wildcard .config))
+-include .config
+-endif
+-
+-LIBNAME= $T.so.$V
+-
+-#LIB_OPTION= -bundle -undefined dynamic_lookup #for MacOS X
+-
+-# Compilation directives
+-WARN_MOST	= -Wall -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings -pedantic
+-WARN		= -Wall -Wno-unused-value
+-WARN_MIN	= 
+-CFLAGS		+= $(WARN_MIN) -DPTHREADS 
+-CC= gcc -g $(CFLAGS) -Ideps
+-
+-
+-OBJS=src/asn1.o src/auxiliar.o src/bio.o src/cipher.o src/cms.o src/compat.o src/crl.o src/csr.o src/dh.o src/digest.o src/dsa.o \
+-src/ec.o src/engine.o src/hmac.o src/lbn.o src/lhash.o src/misc.o src/ocsp.o src/openssl.o src/ots.o src/pkcs12.o src/pkcs7.o    \
+-src/pkey.o src/rsa.o src/ssl.o src/th-lock.o src/util.o src/x509.o src/xattrs.o src/xexts.o src/xname.o src/xstore.o src/xalgor.o src/callback.o 
+-
+-.c.o:
+-	$(CC) -c -o $@ $?
+-
+-all: $T.so
+-	echo $(SYS)
+-
+-$T.so: $(OBJS)
+-	MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; $(CC) $(CFLAGS) $(LIB_OPTION) -o $T.so $(OBJS) $(OPENSSL_LIBS) $(LUA_LIBS) $(LDFLAGS)
+-
+-install: all
+-	mkdir -p $(LUA_LIBDIR)
+-	cp $T.so $(LUA_LIBDIR)
+-
+-clean:
+-	rm -f $T.so $(OBJS) 
++T=openssl
++
++PREFIX		?=/usr/local
++CC		:= $(CROSS)$(CC)
++AR		:= $(CROSS)$(AR)
++LD		:= $(CROSS)$(LD)
++
++#OS auto detect
++ifneq (,$(TARGET_SYS))
++  SYS		:= $(TARGET_SYS)
++else
++  SYS		:= $(shell gcc -dumpmachine)
++endif
++
++#Lua auto detect
++LUA_VERSION	:= $(shell pkg-config luajit --print-provides)
++ifeq ($(LUA_VERSION),)
++  # Not found luajit package, try lua
++  LUA_VERSION	:= $(shell pkg-config lua --print-provides)
++  ifeq ($(LUA_VERSION),)
++    # Not found lua package, try from prefix
++    LUA_VERSION := $(shell lua -e "_,_,v=string.find(_VERSION,'Lua (.+)');print(v)")
++    LUA_CFLAGS	?= -I$(PREFIX)/include/lua$(LUA_VERSION)
++    LUA_LIBS	?= -L$(PREFIX)/lib -llua
++    LUA_LIBDIR	?= $(PREFIX)/lib/lua/$(LUA_VERSION)
++  else
++    # Found lua package
++    LUA_VERSION	:= $(shell lua -e "_,_,v=string.find(_VERSION,'Lua (.+)');print(v)")
++    LUA_CFLAGS	?= $(shell pkg-config lua --cflags)
++    LUA_LIBS	?= $(shell pkg-config lua --libs)
++    LUA_LIBDIR	?= $(PREFIX)/lib/lua/$(LUA_VERSION)
++  endif
++else
++  # Found luajit package
++  LUA_VERSION	:= $(shell luajit -e "_,_,v=string.find(_VERSION,'Lua (.+)');print(v)")
++  LUA_CFLAGS	?= $(shell pkg-config luajit --cflags)
++  LUA_LIBS	?= $(shell pkg-config luajit --libs)
++  LUA_LIBDIR	?= $(PREFIX)/lib/lua/$(LUA_VERSION)
++endif
++
++#OpenSSL auto detect
++OPENSSL_CFLAGS	?= $(shell pkg-config openssl --cflags)
++OPENSSL_LIBS	?= $(shell pkg-config openssl --static --libs)
++
++ifneq (, $(findstring linux, $(SYS)))
++  # Do linux things
++  CFLAGS	 = -fpic
++  LDFLAGS	 = -Wl,--no-undefined -fpic -lrt -ldl -lm
++endif
++
++ifneq (, $(findstring apple, $(SYS)))
++  # Do darwin things
++  CFLAGS	 = -fPIC
++  LDFLAGS	 = -fPIC -undefined dynamic_lookup -ldl
++  #MACOSX_DEPLOYMENT_TARGET="10.3"
++  CC		:= MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} $(CC)
++endif
++
++ifneq (, $(findstring mingw, $(SYS)))
++  # Do mingw things
++  CFLAGS	 = -DLUA_LIB -DLUA_BUILD_AS_DLL -DWIN32_LEAN_AND_MEAN
++endif
++
++ifneq (, $(findstring cygwin, $(SYS)))
++  # Do cygwin things
++  CFLAGS	 = -fPIC
++endif
++
++ifneq (, $(findstring iOS, $(SYS)))
++  # Do iOS things
++  CFLAGS	 = -fPIC
++  LDFLAGS	 = -fPIC -ldl
++endif
++
++#custom config
++ifeq (.config, $(wildcard .config))
++  include .config
++endif
++
++LIBNAME= $T.so.$V
++
++CFLAGS		+= $(OPENSSL_CFLAGS) $(LUA_CFLAGS) $(TARGET_FLAGS)
++LDFLAGS		+= -shared $(OPENSSL_LIBS) $(LUA_LIBS)
++# Compilation directives
++WARN_MIN	 = -Wall -Wno-unused-value
++WARN		 = -Wall
++WARN_MOST	 = $(WARN) -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings -pedantic
++CFLAGS		+= -g $(WARN_MIN) -DPTHREADS -Ideps -Ideps/lua-compat -Ideps/auxiliar
++
++
++OBJS=src/asn1.o deps/auxiliar/auxiliar.o src/bio.o src/cipher.o src/cms.o src/compat.o src/crl.o src/csr.o src/dh.o src/digest.o src/dsa.o \
++src/ec.o src/engine.o src/hmac.o src/lbn.o src/lhash.o src/misc.o src/ocsp.o src/openssl.o src/ots.o src/pkcs12.o src/pkcs7.o    \
++src/pkey.o src/rsa.o src/ssl.o src/th-lock.o src/util.o src/x509.o src/xattrs.o src/xexts.o src/xname.o src/xstore.o \
++src/xalgor.o src/callback.o src/srp.o deps/auxiliar/subsidiar.o
++
++.c.o:
++	$(CC) $(CFLAGS) -c -o $@ $?
++
++all: $T.so
++	@echo "Target system: "$(SYS)
++
++$T.so: lib$T.a
++	$(CC) -o $@ src/openssl.o -L. -l$T $(LDFLAGS)
++
++lib$T.a: $(OBJS)
++	$(AR) rcs $@ $?
++
++install: all
++	mkdir -p $(LUA_LIBDIR)
++	cp $T.so $(LUA_LIBDIR)
++
++info:
++	@echo "Target system: "$(SYS)
++	@echo "CC:" $(CC)
++	@echo "AR:" $(AR)
++	@echo "PREFIX:" $(PREFIX)
++
++clean:
++	rm -f $T.so lib$T.a $(OBJS)
++
++# vim: ts=8 sw=8 noet
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/Makefile.win luvi-src-v2.7.6/deps/lua-openssl/Makefile.win
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/Makefile.win	2019-02-13 11:31:40.277302045 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/Makefile.win	2019-02-13 11:53:24.105128513 +0100
+@@ -1,25 +1,31 @@
+-T= openssl
+-
+-include config.win
+-
+-OBJS=src\asn1.obj src\auxiliar.obj src\bio.obj src\cipher.obj src\cms.obj src\compat.obj src\crl.obj src\csr.obj src\dh.obj src\digest.obj src\dsa.obj \
+-src\ec.obj src\engine.obj src\hmac.obj src\lbn.obj src\lhash.obj src\misc.obj src\ocsp.obj src\openssl.obj src\ots.obj src\pkcs12.obj src\pkcs7.obj    \
+-src\pkey.obj src\rsa.obj src\ssl.obj src\th-lock.obj src\util.obj src\x509.obj src\xattrs.obj src\xexts.obj src\xname.obj src\xstore.obj src\xalgor.obj src\callback.obj
+-
+-
+-lib: src\$T.dll
+-
+-.c.obj:
+-	$(CC) /nologo /c /DLUA_BUILD_AS_DLL /DLUA_LIB /Fo$@ $(CFLAGS) $<
+-
+-src\$T.dll: $(OBJS)
+-	link /DLL /out:src\$T.dll $(OBJS) "$(LUA_LIB)" "$(OPENSSL_LIB)" ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib 
+-	IF EXIST src\$T.dll.manifest mt -manifest src\$T.dll.manifest -outputresource:src\$T.dll;2
+-
+-install: src\$T.dll
+-	IF NOT EXIST "$(LUA_LIBDIR)" mkdir "$(LUA_LIBDIR)"
+-	copy src\$T.dll "$(LUA_LIBDIR)"
+-
+-clean:
+-	del src\$T.dll $(OBJS) src\$T.lib src\$T.exp
+-	IF EXIST src\$T.dll.manifest del src\$T.dll.manifest
+\ No newline at end of file
++T= openssl
++
++include config.win
++
++OBJS= \
++deps\auxiliar\auxiliar.obj src\asn1.obj src\bio.obj src\cipher.obj src\cms.obj \
++src\compat.obj src\crl.obj src\csr.obj src\dh.obj src\digest.obj src\dsa.obj   \
++src\ec.obj src\engine.obj src\hmac.obj src\lbn.obj src\lhash.obj src\misc.obj  \
++src\ocsp.obj src\openssl.obj src\ots.obj src\pkcs12.obj src\pkcs7.obj          \
++src\pkey.obj src\rsa.obj src\ssl.obj src\th-lock.obj src\util.obj src\x509.obj \
++src\xattrs.obj src\xexts.obj src\xname.obj src\xstore.obj src\xalgor.obj       \
++src\callback.obj src\srp.obj deps\auxiliar\subsidiar.obj
++
++
++lib: src\$T.dll
++
++.c.obj:
++	$(CC) /nologo /c /I"deps/lua-compat" /I"deps/auxiliar" /DLUA_BUILD_AS_DLL /DLUA_LIB /Fo$@ $(CFLAGS) $<
++
++src\$T.dll: $(OBJS)
++	link /DLL /out:src\$T.dll $(OBJS) "$(LUA_LIB)" "$(OPENSSL_LIB)" \
++		ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib 
++	IF EXIST src\$T.dll.manifest mt -manifest src\$T.dll.manifest -outputresource:src\$T.dll;2
++
++install: src\$T.dll
++	IF NOT EXIST "$(LUA_LIBDIR)" mkdir "$(LUA_LIBDIR)"
++	copy src\$T.dll "$(LUA_LIBDIR)"
++
++clean:
++	del src\$T.dll $(OBJS) src\$T.lib src\$T.exp
++	IF EXIST src\$T.dll.manifest del src\$T.dll.manifest
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/openssl-scm-6.rockspec luvi-src-v2.7.6/deps/lua-openssl/openssl-scm-6.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/openssl-scm-6.rockspec	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/openssl-scm-6.rockspec	2019-02-13 11:53:24.105128513 +0100
+@@ -0,0 +1,80 @@
++package = "openssl"
++version = "scm-6"
++
++source = {
++  url = "gitrec://github.com/zhaozg/lua-openssl",
++  tag = "0.7.4"
++}
++
++description = {
++  summary    = "Openssl binding for Lua",
++  homepage   = "https://github.com/zhaozg/lua-openssl",
++  license    = "MIT",
++  maintainer = "George Zhao",
++  detailed   = [[
++  ]],
++}
++
++dependencies = {
++  "luarocks-fetch-gitrec",
++  "lua >= 5.1, < 5.4"
++}
++
++external_dependencies = {
++  OPENSSL = {
++    header = "openssl/evp.h"
++  }
++}
++
++build = {
++  type = "builtin",
++
++  modules = {
++    openssl = {
++      sources = {
++        "deps/auxiliar/auxiliar.c","src/asn1.c","src/bio.c","src/callback.c",
++        "src/cipher.c","src/cms.c","src/compat.c","src/crl.c",
++        "src/csr.c","src/dh.c","src/digest.c","src/dsa.c",
++        "src/ec.c","src/engine.c","src/hmac.c","src/lbn.c",
++        "src/lhash.c","src/misc.c","src/ocsp.c","src/openssl.c",
++        "src/ots.c","src/pkcs7.c","src/pkcs12.c","src/pkey.c",
++        "src/rsa.c","src/ssl.c","src/th-lock.c","src/util.c",
++        "src/x509.c","src/xattrs.c","src/xexts.c","src/xname.c",
++        "src/xalgor.c","src/xstore.c", "src/srp.c",
++        "deps/auxiliar/subsidiar.c"
++      },
++      incdirs = {"$(OPENSSL_DIR)/include", "deps/auxiliar", "deps/lua-compat"},
++      defines = {"PTHREADS"},
++      libraries = {"ssl", "crypto"},
++    }
++  },
++
++  platforms = {
++    windows = {
++      modules = {
++        openssl = {
++          libraries = {"libeay32", "ssleay32", "ws2_32", "kernel32", "user32", "gdi32", "advapi32"},
++          defines = {"LUA_BUILD_AS_DLL", "LUA_LIB", "WIN32_LEAN_AND_MEAN"},
++          incdirs = {"$(OPENSSL_DIR)/include"},
++          libdirs = {"$(OPENSSL_DIR)/lib"},
++        }
++      }
++    },
++    linux = {
++      modules = {
++        openssl = {
++          incdirs = {"$(OPENSSL_DIR)/include"},
++          libdirs = {"$(OPENSSL_DIR)/lib"},
++        }
++      }
++    },
++    macosx = {
++      modules = {
++        openssl = {
++          incdirs = {"$(OPENSSL_DIR)/include"},
++          libdirs = {"$(OPENSSL_DIR)/lib"},
++        }
++      }
++    }
++  },
++}
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/README.md luvi-src-v2.7.6/deps/lua-openssl/README.md
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/README.md	2019-02-13 11:31:40.273968734 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/README.md	2019-02-13 11:53:24.105128513 +0100
+@@ -3,12 +3,12 @@ lua-openssl toolkit - A free, MIT-licens
+ [![Build Status](https://travis-ci.org/zhaozg/lua-openssl.svg)](https://travis-ci.org/zhaozg/lua-openssl)
+ [![Build status](https://ci.appveyor.com/api/projects/status/f8xchhlj035yqq88/branch/master?svg=true)](https://ci.appveyor.com/project/zhaozg/lua-openssl/branch/master)
+ 
+-#Index
++# Index
+ 
+ 1. [Introduction](#introduction)
+ 2. [Documentation](#documentation)
+-2. [Howto](#a---howto)
+-3. [Examples](#b--example-usage) 
++2. [Howto](#howto)
++3. [Examples](#example-usage) 
+ 
+ # Introduction
+ 
+@@ -16,17 +16,17 @@ I needed a full OpenSSL binding for Lua,
+ I found the PHP openssl binding is a good implementation, and it inspired me.
+ So I decided to write this OpenSSL toolkit for Lua.
+ 
+-The goal is to fully support the listed items.Below you can find the development progress of lua-openssl. 
++The goal is to fully support the listed items. Below you can find the development progress of lua-openssl: 
+ 
+ * Symmetrical encrypt/decrypt. (Finished)
+ * Message digest. (Finished)
+ * Asymmetrical encrypt/decrypt/sign/verify/seal/open. (Finished)
+ * X509 certificate. (Finished)
+-* PKCS7/CMS. (Developing)
++* PKCS7/CMS. (Finished)
+ * SSL/TLS. (Finished)
+ 
+-Most of the lua-openssl functions require a key or certificate as argument; to make things easy to use OpenSSL,
+-This rule allow you to specify certificates or keys in the following ways:
++Most of the lua-openssl functions require a key or certificate as argument; to make things easy to use OpenSSL.
++This rule allows you to specify certificates or keys in the following ways:
+ 
+ 1. As an openssl.x509 object returned from openssl.x509.read
+ 2. As an openssl.evp_pkey object return from openssl.pkey.read or openssl.pkey.new
+@@ -47,7 +47,7 @@ digest() equals with digest.digest(), sa
+ 
+ ## documentation
+ 
+-Document please see [here](http://zhaozg.github.io/lua-openssl/)
++Document please see [here](http://zhaozg.github.io/lua-openssl/index.html)
+ 
+ ## compat with others
+ 
+@@ -101,26 +101,26 @@ below.
+ 
+ bn library:
+ ```
+- __add(x,y)		compare(x,y)		pow(x,y) 
+- __div(x,y)		div(x,y)			powmod(x,y,m) 
+- __eq(x,y)		divmod(x,y)			random(bits) 
+- __lt(x,y)		gcd(x,y)			rmod(x,y) 
+- __mod(x,y)		invmod(x)			sqr(x) 
+- __mul(x,y)		isneg(x)			sqrmod(x) 
+- __pow(x,y)		isodd(x)			sqrtmod(x) 
+- __sub(x,y)		isone(x)			sub(x,y) 
+- __tostring(x)	isprime(x,[checks])	submod(x,y,m) 
+- __unm(x)		iszero(x)			text(t) 
+- abs(x)			mod(x,y)			tohex(x) 
+- add(x,y)		mul(x,y)			tonumber(x) 
+- addmod(x,y,m)	mulmod(x,y,m)		tostring(x) 
+- aprime(bits)	neg(x)				totext(x) 
+- bits(x)		number(x)			version 
++ __add(x,y)        compare(x,y)          pow(x,y) 
++ __div(x,y)        div(x,y)              powmod(x,y,m) 
++ __eq(x,y)         divmod(x,y)           random(bits) 
++ __lt(x,y)         gcd(x,y)              rmod(x,y) 
++ __mod(x,y)        invmod(x)             sqr(x) 
++ __mul(x,y)        isneg(x)              sqrmod(x) 
++ __pow(x,y)        isodd(x)              sqrtmod(x) 
++ __sub(x,y)        isone(x)              sub(x,y) 
++ __tostring(x)     isprime(x,[checks])   submod(x,y,m) 
++ __unm(x)          iszero(x)             text(t) 
++ abs(x)            mod(x,y)              tohex(x) 
++ add(x,y)          mul(x,y)              tonumber(x) 
++ addmod(x,y,m)     mulmod(x,y,m)         tostring(x) 
++ aprime(bits)      neg(x)                totext(x) 
++ bits(x)           number(x)             version 
+ ```
+ 
+ ## Version
+ 
+-This lua-openssl toolkit works with Lua 5.1 or 5.2, and OpenSSL (0.9.8 or above 1.0.0). 
++This lua-openssl toolkit works with Lua 5.1/5.2 or LuaJIT 2.0/2.1, and OpenSSL (0.9.8 or above 1.0.0). 
+ It is recommended to use the most up-to-date OpenSSL version because of the recent security fixes.
+ 
+ If you want to get the lua-openssl and OpenSSL versions from a Lua script, here is how:
+@@ -129,15 +129,20 @@ If you want to get the lua-openssl and O
+ openssl = require "openssl"
+ lua_openssl_version, lua_version, openssl_version = openssl.version()
+ ```
++## Style
++
++Source code of lua-openssl tidy with [astyle](http://astyle.sourceforge.net/) `--style=allman --indent=spaces=2` 
+ 
+ ## Bugs
+ 
+-Lua-Openssl is heavily updated, if you find bug, please report to [here](https://github.com/zhaozg/lua-openssl/issues/)
++Lua-Openssl is heavily updated, if you find a bug, please report to [here](https://github.com/zhaozg/lua-openssl/issues/)
+ 
+-#A.   Howto
++# Howto
+ 
+ ### Howto 1: Build on Linux/Unix System.
+ 
++    git clone --recurse https://github.com/zhaozg/lua-openssl.git lua-openssl
++    cd lua-openssl
+ 	make
+ 	make install
+ 	make clean
+@@ -147,6 +152,8 @@ Lua-Openssl is heavily updated, if you f
+ Before building, please change the setting in the config.win file.
+ Works with Lua5.1 (should support Lua5.2 by updating the config.win file).
+ 
++    git clone --recurse https://github.com/zhaozg/lua-openssl.git lua-openssl
++    cd lua-openssl
+ 	nmake -f makefile.win
+ 	nmake -f makefile.win install
+ 	nmake -f makefile.win clean
+@@ -154,6 +161,8 @@ Works with Lua5.1 (should support Lua5.2
+ 
+ ### Howto 3: Build on Windows with mingw.
+ 
++    git clone --recurse https://github.com/zhaozg/lua-openssl.git lua-openssl
++    cd lua-openssl
+ 	make
+ 	make install
+ 	make clean
+@@ -170,17 +179,17 @@ _code_ can pass to openssl.error() to ge
+ 
+   All SSL object IO operation methods return nil or false when fail or error.
+ When nil returned, it followed by 'ssl' or 'syscall', means SSL layer or 
+-system layer error. When false returned, it followed by number 0, 'want_read',
+-'want_write','want_x509_lookup','want_connect','want_accept'. Numnber 0 means
+-SSL connection closed, others means you should do some SSL operation.
++system layer error. When false returned, it is followed by number 0, 'want_read',
++'want_write','want_x509_lookup','want_connect','want_accept'. Number 0 means
++SSL connection closed, other numbers means you should do some SSL operation.
+ 
+-  Please remeber that when lua-openssl function or methods failed without 
+-error code, you can get last error by openssl.error(), and repeat call 
++  Please remember that when lua-openssl function or methods fail without an 
++error code, you can get the last error by openssl.error(), and repeat call 
+ openssl.error() will walk through error stacks of current threads. 
+ openssl.error(true) will also clear error stacks after get last error code,
+ this is very useful to free memory when lua-openssl repeat calls or run long times.
+ 
+-#B.  Example usage
++# Example usage
+ 
+ ### Example 1: short encrypt/decrypt
+ 
+@@ -206,7 +215,20 @@ bb = mdc:final()
+ assert(openssl.hex(aa,true)==bb)
+ ```
+ 
+-### Example 3:  Iterate a openssl.stack_of_x509(sk_x509) object
++### Example 3: Quick HMAC hash
++
++```lua
++local hmac = require "openssl".hmac
++
++alg = 'sha256'
++key = '0123456789'
++msg = 'example message'
++
++hmac.hmac(alg, msg, key, true) -- binary/"raw" output
++hmac.hmac(alg, msg, key, false) -- hex output
++```
++
++### Example 4:  Iterate a openssl.stack_of_x509(sk_x509) object
+ 
+ ```lua
+ n = #sk
+@@ -215,7 +237,7 @@ for i=1, n do
+ end
+ ```
+ 
+-### Example 4: read and parse certificate
++### Example 5: read and parse certificate
+ 
+ ```lua
+ local openssl = require('openssl')
+@@ -243,10 +265,10 @@ end
+ test_x509()
+ ```
+ 
+-###Example 5: bio network handle(TCP)
++### Example 5: bio network handle(TCP)
+ 
+  * server
+- 
++
+ ```lua
+ local openssl = require'openssl'
+ local bio = openssl.bio
+@@ -270,6 +292,7 @@ end
+ ```
+ 
+  * client
++
+ ```lua
+ local openssl = require'openssl'
+ local bio = openssl.bio
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/rockspecs/openssl-scm-0.rockspec luvi-src-v2.7.6/deps/lua-openssl/rockspecs/openssl-scm-0.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/rockspecs/openssl-scm-0.rockspec	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/rockspecs/openssl-scm-0.rockspec	1970-01-01 01:00:00.000000000 +0100
+@@ -1,40 +0,0 @@
+-package = "openssl"
+-version = "scm-0"
+-
+-source = {
+-  url = "https://github.com/zhaozg/lua-openssl/archive/master.zip",
+-  dir = "lua-openssl-master",
+-}
+-
+-description = {
+-  summary    = "Openssl binding for Lua",
+-  homepage   = "https://github.com/zhaozg/lua-openssl",
+-  license    = "MIT/X11",
+-  maintainer = "George Zhao",
+-  detailed   = [[
+-  ]],
+-}
+-
+-dependencies = {
+-  "lua >= 5.1, < 5.3"
+-}
+-
+-external_dependencies = {
+-}
+-
+-build = {
+-  type = "builtin",
+-
+-  platforms = {
+-    windows = {
+-      type = "command",
+-      build_command = [[nmake -f makefile.win]],
+-      install_command = [[nmake -f makefile.win install]]
+-    },
+-    unix = {
+-      type = "command",
+-      build_command = [[make]],
+-      install_command = [[make install]]
+-	}
+-  }
+-}
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/rockspecs/openssl-scm-1.rockspec luvi-src-v2.7.6/deps/lua-openssl/rockspecs/openssl-scm-1.rockspec
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/rockspecs/openssl-scm-1.rockspec	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/rockspecs/openssl-scm-1.rockspec	1970-01-01 01:00:00.000000000 +0100
+@@ -1,61 +0,0 @@
+-package = "openssl"
+-version = "scm-1"
+-
+-source = {
+-  url = "https://github.com/zhaozg/lua-openssl/archive/master.zip",
+-  dir = "lua-openssl-master",
+-}
+-
+-description = {
+-  summary    = "Openssl binding for Lua",
+-  homepage   = "https://github.com/zhaozg/lua-openssl",
+-  license    = "MIT/X11",
+-  maintainer = "George Zhao",
+-  detailed   = [[
+-  ]],
+-}
+-
+-dependencies = {
+-  "lua >= 5.1, < 5.4"
+-}
+-
+-external_dependencies = {
+-  OPENSSL = {
+-    header = "openssl/evp.h"
+-  }
+-}
+-
+-build = {
+-  type = "builtin",
+-
+-  modules = {
+-    openssl = {
+-      sources = {
+-        "src/asn1.c","src/auxiliar.c","src/bio.c","src/callback.c",
+-        "src/cipher.c","src/cms.c","src/compat.c","src/crl.c",
+-        "src/csr.c","src/dh.c","src/digest.c","src/dsa.c",
+-        "src/ec.c","src/engine.c","src/hmac.c","src/lbn.c",
+-        "src/lhash.c","src/misc.c","src/ocsp.c","src/openssl.c",
+-        "src/ots.c","src/pkcs7.c","src/pkcs12.c","src/pkey.c",
+-        "src/rsa.c","src/ssl.c","src/th-lock.c","src/util.c",
+-        "src/x509.c","src/xattrs.c","src/xexts.c","src/xname.c",
+-        "src/xalgor.c","src/xstore.c",
+-      },
+-      incdirs = {"$(OPENSSL_INCDIR)", "deps"},
+-      libdirs = {"$(OPENSSL_LIBDIR)"},
+-      defines = {"PTHREADS"},
+-      libraries = {"ssl", "crypto"},
+-    }
+-  },
+-
+-  platforms = {
+-    windows = {
+-      modules = {
+-        openssl = {
+-          libraries = {"libeay32", "ssleay32", "ws2_32", "kernel32", "user32", "gdi32", "advapi32"},
+-          defines = {"LUA_BUILD_AS_DLL", "LUA_LIB", "WIN32_LEAN_AND_MEAN"},
+-        }
+-      }
+-    }
+-  },
+-}
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/samples/srp.lua luvi-src-v2.7.6/deps/lua-openssl/samples/srp.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/samples/srp.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/samples/srp.lua	2019-02-13 11:53:24.275126573 +0100
+@@ -0,0 +1,43 @@
++local openssl = require'openssl'
++local srp = assert(openssl.srp)
++
++--both
++local GN = srp.get_default_gN('1024');
++
++local function test(username, clipass, srvpass)
++  assert(username)
++  assert(clipass)
++  srvpass = srvpass or clipass
++  --server
++  local salt, v = GN:create_verifier(username,srvpass)
++  print('salt:', salt:tohex())
++  print('verifier:',v:tohex())
++
++  local Bpub, Brnd = GN:calc_b(v)
++  print("Bpnb:",Bpub:tohex())
++  print("Brnd:",Brnd:tohex())
++
++  --client
++  local Apub, Arnd = GN:calc_a()
++  print("Apnb:",Apub:tohex())
++  print("Arnd:",Arnd:tohex())
++
++  --both
++  local u = GN:calc_u(Apub, Bpub)
++  print("u:",u:tohex())
++
++  --client
++  local x = GN.calc_x(salt, username, clipass)
++  local Kclient = GN:calc_client_key(Bpub,x, Arnd, u)
++
++  --server
++  local Kserver = GN:calc_server_key(Apub, v, u, Brnd)
++
++  return Kclient==Kserver
++end
++
++local cnt = 1
++for i=1,cnt do
++assert(test('zhaozg','password','password'))
++assert(not test('zhaozg','password','password1'))
++end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/asn1.c luvi-src-v2.7.6/deps/lua-openssl/src/asn1.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/asn1.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/asn1.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,9 +1,13 @@
+-/*=========================================================================*\
+-* asn1.c
+-* asn1 routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++openssl.asn1 module for lua-openssl binding.
++Provide asn1\_object, asn1\_string, asn1\_object as lua object.
++Sometime when you want to custome x509, you maybe need to use this.
++
++@module asn1
++@usage
++  asn1 = require('openssl').asn1
++*/
++
+ #include "openssl.h"
+ #include "private.h"
+ #include <openssl/asn1.h>
+@@ -15,7 +19,7 @@
+ #define timezone _timezone
+ #endif
+ 
+-static LuaL_Enum asn1_const[] =
++static LuaL_Enumeration asn1_const[] =
+ {
+   /* 0 */
+   {"UNIVERSAL",         V_ASN1_UNIVERSAL},
+@@ -75,10 +79,14 @@ static LuaL_Enum asn1_const[] =
+ #define TAG_IDX_OFFSET  11
+ #define TAG_IDX_LENGTH  31
+ 
+-
++/***
++create asn1_type object
++@function new_type
++*/
+ static int openssl_asn1type_new(lua_State*L)
+ {
+   ASN1_TYPE* at = ASN1_TYPE_new();
++  ASN1_STRING *s = NULL;
+   int ret = 1;
+   if (lua_isboolean(L, 1))
+   {
+@@ -99,9 +107,8 @@ static int openssl_asn1type_new(lua_Stat
+     const char* octet = luaL_checklstring(L, 1, &size);
+     ret = ASN1_TYPE_set_octetstring(at, (unsigned char*)octet, size);
+   }
+-  else if (auxiliar_isgroup(L, "openssl.asn1group", 1))
++  else if ((s = GET_GROUP(1, ASN1_STRING, "openssl.asn1group")) != NULL)
+   {
+-    ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+     ret = ASN1_TYPE_set1(at, ASN1_STRING_type(s), s);
+   }
+   else
+@@ -115,6 +122,436 @@ static int openssl_asn1type_new(lua_Stat
+   return 1;
+ }
+ 
++/***
++parse der encoded string
++@function get_object
++@tparam string der string
++@tparam[opt=1] number start offset to parse
++@tparam[opt=-i] number stop offset to parse
++ this like string.sub()
++@treturn[1] number tag
++@treturn[1] number class
++@treturn[1] number parsed data start offset
++@treturn[1] number parsed data stop offset
++@treturn[1] boolean true for constructed data
++@treturn[2] nil for fail
++@treturn[2] string error msg
++@treturn[2] number inner error code
++*/
++static int openssl_get_object(lua_State*L)
++{
++  size_t l = 0;
++  const char* asn1s = luaL_checklstring(L, 1, &l);
++  size_t off = posrelat(luaL_optinteger(L, 2, 1), l);
++  size_t length = posrelat(luaL_optinteger(L, 3, l), l);
++
++  const unsigned char *p = (const unsigned char *)asn1s + off - 1;
++  long len = 0;
++  int tag = 0;
++  int class = 0;
++  int ret;
++
++  p = (const unsigned char *)asn1s + off - 1;
++  ret = ASN1_get_object(&p, &len, &tag, &class, length - off + 1);
++  if (ret & 0x80)
++  {
++    lua_pushnil(L);
++    lua_pushstring(L, "arg 1 with error encoding");
++    lua_pushinteger(L, ret);
++    return 3;
++  }
++  lua_pushinteger(L, tag);
++  lua_pushinteger(L, class);
++  lua_pushinteger(L, p - (const unsigned char *)asn1s + 1);
++  lua_pushinteger(L, p + len - (const unsigned char *)asn1s);
++
++  lua_pushboolean(L, ret & V_ASN1_CONSTRUCTED);
++  return 5;
++}
++
++/***
++do der encode and return encoded string partly head or full
++@function put_object
++@tparam number tag
++@tparam number class
++@tparam[opt=nil] number|string length or date to encode, defualt will make
++indefinite length constructed
++@tparam[opt=nil] boolean constructed or not
++@treturn string der encoded string or head when not give data
++*/
++static int openssl_put_object(lua_State*L)
++{
++  int tag = luaL_checkint(L, 1);
++  int cls = luaL_checkint(L, 2);
++  int length = 0;
++  int constructed;
++  unsigned char *p1, *p2;
++  const char* dat = NULL;
++  luaL_Buffer B;
++
++  luaL_argcheck(L,
++                lua_isnoneornil(L, 3) || lua_type(L, 3) == LUA_TNUMBER || lua_isstring(L, 3), 3,
++                "if exist only accept string or number");
++  luaL_argcheck(L, lua_isnoneornil(L, 4) || lua_isboolean(L, 4), 4,
++                "if exist must be boolean type");
++
++  if (lua_isnoneornil(L, 3))
++  {
++    /* constructed == 2 for indefinite length constructed */
++    constructed = 2;
++    length = 0;
++  }
++  else
++  {
++    if (lua_type(L, 3) == LUA_TNUMBER)
++    {
++      length = lua_tointeger(L, 3);
++    }
++    else if (lua_isstring(L, 3))
++    {
++      size_t l;
++      dat = lua_tolstring(L, 3, &l);
++      length = (int)l;
++    }
++
++    constructed = lua_isnoneornil(L, 4) ? 0 : lua_toboolean(L, 4);
++  }
++  luaL_buffinit(L, &B);
++  p1 = (unsigned char *)luaL_prepbuffer(&B);
++  p2 = p1;
++
++  ASN1_put_object(&p2, constructed, length, tag, cls);
++  luaL_addsize(&B, p2 - p1);
++  if (dat)
++  {
++    luaL_addlstring(&B, dat, length);
++  }
++  luaL_pushresult(&B);
++  return 1;
++};
++
++/***
++make tag, class number to string
++
++@function tostring
++@tparam number clsortag which to string
++@tparam string range only accept 'class' or 'tag'
++*/
++static int openssl_asn1_tostring(lua_State*L)
++{
++  int val = luaL_checkint(L, 1);
++  const char* range = luaL_optstring(L, 2, NULL);
++  int i;
++
++  if (range == NULL)
++  {
++    for (i = 0; i < sizeof(asn1_const) / sizeof(LuaL_Enumeration) - 1; i++)
++    {
++      if (asn1_const[i].val == val)
++      {
++        lua_pushstring(L, asn1_const[i + CLS_IDX_OFFSET].name);
++        return 1;
++      }
++    }
++  }
++  else if (strcmp("tag", range) == 0)
++  {
++    for (i = 0; i < TAG_IDX_LENGTH; i++)
++    {
++      if (asn1_const[i + TAG_IDX_OFFSET].val == val)
++      {
++        lua_pushstring(L, asn1_const[i + TAG_IDX_OFFSET].name);
++        return 1;
++      }
++    }
++  }
++  else if (strcmp("class", range) == 0)
++  {
++    for (i = 0; i < CLS_IDX_LENGTH; i++)
++    {
++      if (asn1_const[i + CLS_IDX_OFFSET].val == val)
++      {
++        lua_pushstring(L, asn1_const[i + CLS_IDX_OFFSET].name);
++        return 1;
++      }
++    }
++  }
++
++  return 0;
++}
++
++/***
++Create asn1_string object
++
++<br/><p> asn1_string object support types:   "integer", "enumerated", "bit", "octet", "utf8",
++"numeric", "printable", "t61", "teletex", "videotex", "ia5", "graphics", "iso64",
++"visible", "general", "unversal", "bmp", "utctime" </p>
++
++@function new_string
++@tparam string data to create new asn1_string
++@tparam[opt] string type asn1 string type, defult with 'utf8'
++@treturn asn1_string
++@see asn1_string
++*/
++static int openssl_asn1string_new(lua_State* L)
++{
++  size_t size = 0;
++  const char* data = luaL_checklstring(L, 1, &size);
++  int type = luaL_checkint(L, 2);
++  ASN1_STRING *s = ASN1_STRING_type_new(type);
++  ASN1_STRING_set(s, data, size);
++  PUSH_OBJECT(s, "openssl.asn1_string");
++  return 1;
++}
++
++/***
++Create asn1_integer object
++
++@function new_integer
++@tparam number|bn integer to create new asn1_integer
++@treturn asn1_integer
++@see asn1_integer
++*/
++static int openssl_asn1int_new(lua_State* L)
++{
++  ASN1_INTEGER *ai = ASN1_INTEGER_new();
++  if (lua_isinteger(L, 1))
++  {
++    long v = luaL_checklong(L, 1);
++    ASN1_INTEGER_set(ai, v);
++  }
++  else if (!lua_isnone(L, 1))
++  {
++    BIGNUM *bn = BN_get(L, 1);
++    ai = BN_to_ASN1_INTEGER(bn, ai);
++    BN_free(bn);
++  }
++  PUSH_OBJECT(ai, "openssl.asn1_integer");
++  return 1;
++}
++
++/***
++Create asn1_time object
++@function new_generalizedtime
++@tparam none|number|string time
++@treturn asn1_time
++*/
++static int openssl_asn1generalizedtime_new(lua_State* L)
++{
++  ASN1_GENERALIZEDTIME* a = NULL;
++  int ret = 1;
++  luaL_argcheck(L,
++                1,
++                lua_isnone(L, 1) || lua_isnumber(L, 1) || lua_isstring(L, 1),
++                "must be number, string or none"
++               );
++  a = ASN1_GENERALIZEDTIME_new();
++  if (lua_isnumber(L, 1))
++    ASN1_GENERALIZEDTIME_set(a, luaL_checkinteger(L, 1));
++  else if (lua_isstring(L, 1))
++    ret = ASN1_GENERALIZEDTIME_set_string(a, lua_tostring(L, 1));
++
++  if (ret == 1)
++    PUSH_OBJECT(a, "openssl.asn1_time");
++  else
++    return openssl_pushresult(L, ret);
++  return 1;
++}
++
++/***
++Create asn1_time object
++@function new_utctime
++@tparam none|number|string time
++@treturn asn1_time
++*/
++static int openssl_asn1utctime_new(lua_State* L)
++{
++  ASN1_UTCTIME* a = NULL;
++  int ret = 1;
++  luaL_argcheck(L,
++                1,
++                lua_isnone(L, 1) || lua_isnumber(L, 1) || lua_isstring(L, 1),
++                "must be number, string or none"
++               );
++  a = ASN1_UTCTIME_new();
++  if (lua_isnumber(L, 1))
++  {
++    time_t t = luaL_checkinteger(L, 1);
++    ASN1_TIME_set(a, t);
++  }
++  else if (lua_isstring(L, 1))
++    ret = ASN1_TIME_set_string(a, lua_tostring(L, 1));
++
++  if (ret == 1)
++    PUSH_OBJECT(a, "openssl.asn1_time");
++  else
++    return openssl_pushresult(L, ret);
++  return 1;
++}
++
++/***
++get nid for txt, which can be short name, long name, or numerical oid
++
++@function txt2nid
++@tparam string txt which get to nid
++@treturn integer nid or nil on fail
++*/
++static int openssl_txt2nid(lua_State*L)
++{
++  const char* txt = luaL_checkstring(L, 1);
++  int nid = OBJ_txt2nid(txt);
++  if (nid != NID_undef)
++  {
++    lua_pushinteger(L, nid);
++  }
++  else
++    lua_pushnil(L);
++
++  return 1;
++}
++
++/***
++Create asn1_object object
++
++@function new_object
++@tparam string name_or_oid  short name,long name or oid string
++@tparam[opt] boolean no_name  true for only oid string, default is false
++@treturn asn1_object mapping to ASN1_OBJECT in openssl
++@see asn1_object
++*/
++
++/***
++Create asn1_object object
++
++@function new_object
++@tparam integer nid ident to asn1_object
++@treturn asn1_object mapping to ASN1_OBJECT in openssl
++@see asn1_object
++*/
++
++/***
++Create asn1_object object
++
++@function new_object
++@tparam table options have sn, ln, oid keys to create asn1_object
++@treturn asn1_object mapping to ASN1_OBJECT in openssl
++@see asn1_object
++*/
++static int openssl_asn1object_new(lua_State* L)
++{
++  if (lua_type(L, 1) == LUA_TNUMBER)
++  {
++    int nid = luaL_checkint(L, 1);
++    ASN1_OBJECT* obj = OBJ_nid2obj(nid);
++    if (obj)
++      PUSH_OBJECT(obj, "openssl.asn1_object");
++    else
++      lua_pushnil(L);
++  }
++  else if (lua_isstring(L, 1))
++  {
++    const char* txt = luaL_checkstring(L, 1);
++    int no_name = lua_isnone(L, 2) ? 0 : lua_toboolean(L, 2);
++
++    ASN1_OBJECT* obj = OBJ_txt2obj(txt, no_name);
++    if (obj)
++      PUSH_OBJECT(obj, "openssl.asn1_object");
++    else
++      lua_pushnil(L);
++  }
++  else if (lua_istable(L, 1))
++  {
++    const char *oid, *sn, *ln;
++    ASN1_OBJECT* obj;
++    int nid;
++
++    lua_getfield(L, 1, "oid");
++    luaL_argcheck(L, lua_isstring(L, -1), 1, "not have oid field or is not string");
++    oid = luaL_checkstring(L, -1);
++    lua_pop(L, 1);
++
++    lua_getfield(L, 1, "sn");
++    luaL_argcheck(L, lua_isstring(L, -1), 1, "not have sn field or is not string");
++    sn = luaL_checkstring(L, -1);
++    lua_pop(L, 1);
++
++    lua_getfield(L, 1, "ln");
++    luaL_argcheck(L, lua_isstring(L, -1), 1, "not have ln field or is not string");
++    ln = luaL_checkstring(L, -1);
++    lua_pop(L, 1);
++
++    if (OBJ_txt2nid(oid) != NID_undef)
++    {
++      luaL_argerror(L, 1, "oid already exist");
++    }
++
++    if (OBJ_sn2nid(sn) != NID_undef)
++    {
++      luaL_argerror(L, 1, "sn already exist");
++    }
++
++    if (OBJ_ln2nid(ln) != NID_undef)
++    {
++      luaL_argerror(L, 1, "ln already exist");
++    }
++
++    nid = OBJ_create(oid, sn, ln);
++    if (nid != NID_undef)
++    {
++      obj = OBJ_nid2obj(nid);
++      PUSH_OBJECT(obj, "openssl.asn1_object");
++    }
++    else
++      luaL_argerror(L, 1, "create object fail");
++  }
++  else
++    luaL_argerror(L, 1, "need accept paramater");
++
++  return 1;
++}
++
++/***
++convert der encoded asn1type string to object
++@function asn1type_di2
++@tparam string der
++@treturn asn1type object for success, and nil for fail
++*/
++static int openssl_asn1type_d2i(lua_State*L)
++{
++  size_t size;
++  const unsigned char* data = (const unsigned char*)luaL_checklstring(L, 1, &size);
++  ASN1_TYPE* at = d2i_ASN1_TYPE(NULL, &data, size);
++  if (at)
++  {
++    PUSH_OBJECT(at, "openssl.asn1_type");
++  }
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++static luaL_Reg R[] =
++{
++  {"new_object", openssl_asn1object_new},
++
++  {"new_integer", openssl_asn1int_new},
++  {"new_string", openssl_asn1string_new},
++  {"new_utctime", openssl_asn1utctime_new},
++  {"new_generalizedtime", openssl_asn1generalizedtime_new},
++
++  {"new_type", openssl_asn1type_new},
++  {"d2i_asn1type", openssl_asn1type_d2i},
++
++  {"get_object", openssl_get_object},
++  {"put_object", openssl_put_object},
++
++  {"tostring", openssl_asn1_tostring},
++  {"txt2nid",   openssl_txt2nid},
++
++  {NULL, NULL}
++};
++
++
+ static int openssl_asn1type_type(lua_State*L)
+ {
+   ASN1_TYPE* at = CHECK_OBJECT(1, ASN1_TYPE, "openssl.asn1_type");
+@@ -289,20 +726,6 @@ int openssl_push_asn1type(lua_State* L,
+   return 1;
+ }
+ 
+-static int openssl_asn1type_d2i(lua_State*L)
+-{
+-  size_t size;
+-  const unsigned char* data = (const unsigned char*)luaL_checklstring(L, 1, &size);
+-  ASN1_TYPE* at = d2i_ASN1_TYPE(NULL, &data, size);
+-  if (at)
+-  {
+-    PUSH_OBJECT(at, "openssl.asn1_type");
+-  }
+-  else
+-    lua_pushnil(L);
+-  return 1;
+-}
+-
+ static luaL_Reg asn1type_funcs[] =
+ {
+   {"type",      openssl_asn1type_type},
+@@ -320,23 +743,44 @@ static luaL_Reg asn1type_funcs[] =
+   {NULL,        NULL}
+ };
+ 
+-
+-/*** asn1_object routines ***/
++/***
++openssl.asn1_object object
++@type asn1_object
++*/
++/***
++get nid of asn1_object.
++
++@function nid
++@treturn integer nid of asn1_object
++*/
+ static int openssl_asn1object_nid(lua_State* L)
+ {
+   ASN1_OBJECT* o = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+-  lua_pushinteger(L, o->nid);
++  lua_pushinteger(L, OBJ_obj2nid(o));
+   return 1;
+ }
+ 
++/***
++get name of asn1_object.
++
++@function name
++@treturn string short name and followed by long name of asn1_object
++*/
+ static int openssl_asn1object_name(lua_State* L)
+ {
+   ASN1_OBJECT* o = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+-  lua_pushstring(L, o->sn);
+-  lua_pushstring(L, o->ln);
++  int nid = OBJ_obj2nid(o);
++  lua_pushstring(L, OBJ_nid2sn(nid));
++  lua_pushstring(L, OBJ_nid2ln(nid));
+   return 2;
+ }
+ 
++/***
++get long name of asn1_object.
++
++@function ln
++@treturn string long name of asn1_object
++*/
+ static int openssl_asn1object_ln(lua_State* L)
+ {
+   ASN1_OBJECT* o = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+@@ -348,6 +792,11 @@ static int openssl_asn1object_ln(lua_Sta
+   return 1;
+ }
+ 
++/***
++get short name of asn1_object.
++@function sn
++@treturn string short name of asn1_object
++*/
+ static int openssl_asn1object_sn(lua_State* L)
+ {
+   ASN1_OBJECT* o = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+@@ -359,6 +808,13 @@ static int openssl_asn1object_sn(lua_Sta
+   return 1;
+ }
+ 
++/***
++get text of asn1_object.
++
++@function txt
++@tparam[opt] boolean no_name true for only oid or name, default with false
++@treturn string long or short name, even oid of asn1_object
++*/
+ static int openssl_asn1object_txt(lua_State* L)
+ {
+   ASN1_OBJECT* o = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+@@ -372,6 +828,13 @@ static int openssl_asn1object_txt(lua_St
+   return 1;
+ }
+ 
++/***
++compare two asn1_objects, if equals return true
++
++@function equals
++@tparam asn1_object another to compre
++@treturn boolean true if equals
++*/
+ static int openssl_asn1object_equals(lua_State* L)
+ {
+   ASN1_OBJECT* o = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+@@ -381,6 +844,12 @@ static int openssl_asn1object_equals(lua
+   return 1;
+ }
+ 
++/***
++get data of asn1_object
++
++@function data
++@treturn string asn1_object data
++*/
+ static int openssl_asn1object_data(lua_State* L)
+ {
+   ASN1_OBJECT* s = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+@@ -401,6 +870,12 @@ static int openssl_asn1object_free(lua_S
+   return 0;
+ }
+ 
++/***
++make a clone of asn1_object
++
++@function dup
++@treturn asn1_object clone for self
++*/
+ static int openssl_asn1object_dup(lua_State* L)
+ {
+   ASN1_OBJECT* o = CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object");
+@@ -419,6 +894,7 @@ static luaL_Reg asn1obj_funcs[] =
+   {"txt",         openssl_asn1object_txt},
+   {"dup",         openssl_asn1object_dup},
+   {"data",        openssl_asn1object_data},
++  {"equals",      openssl_asn1object_equals},
+ 
+   {"__eq",        openssl_asn1object_equals},
+   {"__gc",        openssl_asn1object_free},
+@@ -427,123 +903,10 @@ static luaL_Reg asn1obj_funcs[] =
+   {NULL,    NULL}
+ };
+ 
+-
+-static int openssl_asn1object_new(lua_State* L)
+-{
+-  if (lua_type(L, 1) == LUA_TNUMBER)
+-  {
+-    int nid = luaL_checkint(L, 1);
+-    ASN1_OBJECT* obj = OBJ_nid2obj(nid);
+-    if (obj)
+-      PUSH_OBJECT(obj, "openssl.asn1_object");
+-    else
+-      lua_pushnil(L);
+-  }
+-  else if (lua_isstring(L, 1))
+-  {
+-    const char* txt = luaL_checkstring(L, 1);
+-    int no_name = lua_isnone(L, 2) ? 0 : lua_toboolean(L, 2);
+-
+-    ASN1_OBJECT* obj = OBJ_txt2obj(txt, no_name);
+-    if (obj)
+-      PUSH_OBJECT(obj, "openssl.asn1_object");
+-    else
+-      lua_pushnil(L);
+-  }
+-  else if (lua_istable(L, 1))
+-  {
+-    const char *oid, *sn, *ln;
+-    ASN1_OBJECT* obj;
+-    int nid;
+-
+-    lua_getfield(L, 1, "oid");
+-    luaL_argcheck(L, lua_isstring(L, -1), 1, "not have oid field or is not string");
+-    oid = luaL_checkstring(L, -1);
+-    lua_pop(L, 1);
+-
+-    lua_getfield(L, 1, "sn");
+-    luaL_argcheck(L, lua_isstring(L, -1), 1, "not have sn field or is not string");
+-    sn = luaL_checkstring(L, -1);
+-    lua_pop(L, 1);
+-
+-    lua_getfield(L, 1, "ln");
+-    luaL_argcheck(L, lua_isstring(L, -1), 1, "not have ln field or is not string");
+-    ln = luaL_checkstring(L, -1);
+-    lua_pop(L, 1);
+-
+-    if (OBJ_txt2nid(oid) != NID_undef)
+-    {
+-      luaL_argerror(L, 1, "oid already exist");
+-    }
+-
+-    if (OBJ_sn2nid(sn) != NID_undef)
+-    {
+-      luaL_argerror(L, 1, "sn already exist");
+-    }
+-
+-    if (OBJ_ln2nid(ln) != NID_undef)
+-    {
+-      luaL_argerror(L, 1, "ln already exist");
+-    }
+-
+-    nid = OBJ_create(oid, sn, ln);
+-    if (nid != NID_undef)
+-    {
+-      obj = OBJ_nid2obj(nid);
+-      PUSH_OBJECT(obj, "openssl.asn1_object");
+-    }
+-    else
+-      luaL_argerror(L, 1, "create object fail");
+-  }
+-  else
+-    luaL_argerror(L, 1, "need accept paramater");
+-
+-  return 1;
+-}
+-
+-static int openssl_txt2nid(lua_State*L)
+-{
+-  const char* txt = luaL_checkstring(L, 1);
+-  int nid = OBJ_txt2nid(txt);
+-  if (nid != NID_undef)
+-  {
+-    lua_pushinteger(L, nid);
+-  }
+-  else
+-    lua_pushnil(L);
+-
+-  return 1;
+-}
+-
+-static int openssl_asn1string_new(lua_State* L)
+-{
+-  size_t size = 0;
+-  const char* data = luaL_checklstring(L, 1, &size);
+-  int type = luaL_checkint(L, 2);
+-  ASN1_STRING *s = ASN1_STRING_type_new(type);
+-  ASN1_STRING_set(s, data, size);
+-  PUSH_OBJECT(s, "openssl.asn1_string");
+-  return 1;
+-}
+-
+-static int openssl_asn1int_new(lua_State* L)
+-{
+-  ASN1_INTEGER *ai = ASN1_INTEGER_new();
+-  if (lua_isinteger(L, 1))
+-  {
+-    long v = luaL_checklong(L, 1);
+-    ASN1_INTEGER_set(ai, v);
+-  }
+-  else if (!lua_isnone(L, 1))
+-  {
+-    BIGNUM *bn = BN_get(L, 1);
+-    ai = BN_to_ASN1_INTEGER(bn, ai);
+-    BN_free(bn);
+-  }
+-  PUSH_OBJECT(ai, "openssl.asn1_integer");
+-  return 1;
+-}
+-
++/***
++openssl.asn1_integer object
++@type asn1_integer
++*/
+ static int openssl_asn1int_bn(lua_State *L)
+ {
+   ASN1_INTEGER *ai = CHECK_OBJECT(1, ASN1_INTEGER, "openssl.asn1_integer");
+@@ -562,6 +925,14 @@ static int openssl_asn1int_bn(lua_State
+   }
+ }
+ 
++/***
++openssl.asn1_string object
++@type asn1_string
++*/
++
++/***
++@function set
++*/
+ static int openssl_asn1group_set(lua_State *L)
+ {
+   ASN1_STRING *s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -637,6 +1008,9 @@ static time_t ASN1_TIME_get(ASN1_TIME* t
+   return mktime(&t) + off;
+ }
+ 
++/***
++@function get
++*/
+ static int openssl_asn1group_get(lua_State *L)
+ {
+   ASN1_STRING *s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -664,6 +1038,9 @@ static int openssl_asn1group_get(lua_Sta
+   return 0;
+ }
+ 
++/***
++@function i2d
++*/
+ static int openssl_asn1group_i2d(lua_State *L)
+ {
+   ASN1_STRING *s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -716,6 +1093,9 @@ static int openssl_asn1group_i2d(lua_Sta
+   return 0;
+ }
+ 
++/***
++@function d2i
++*/
+ static int openssl_asn1group_d2i(lua_State *L)
+ {
+   ASN1_STRING *s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -732,7 +1112,6 @@ static int openssl_asn1group_d2i(lua_Sta
+     else
+       lua_pushvalue(L, 1);
+     return 1;
+-    break;
+   }
+   case V_ASN1_UTCTIME:
+   {
+@@ -763,6 +1142,13 @@ static int openssl_asn1group_d2i(lua_Sta
+   return 0;
+ }
+ 
++/***
++get type of asn1_string
++
++@function type
++@treturn string type of asn1_string
++@see new_string
++*/
+ static int openssl_asn1group_type(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -780,6 +1166,17 @@ static int openssl_asn1group_type(lua_St
+   return 1;
+ }
+ 
++/***
++get length two asn1_string
++
++@function length
++@treturn integer length of asn1_string
++@usage
++  local astr = asn1.new_string('ABCD')
++  print('length:',#astr)
++  print('length:',astr:length())
++  assert(#astr==astr:length,"must equals")
++*/
+ static int openssl_asn1group_length(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -787,6 +1184,21 @@ static int openssl_asn1group_length(lua_
+   return 1;
+ }
+ 
++/***
++get data of asn1_string
++
++@function data
++@treturn string raw data of asn1_string
++*/
++
++/***
++set data of asn1_string
++
++@function data
++@tparam string data set to asn1_string
++@treturn boolean success if value set true, or follow by errmsg
++@treturn string fail error message
++*/
+ static int openssl_asn1group_data(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -802,6 +1214,16 @@ static int openssl_asn1group_data(lua_St
+   return 1;
+ }
+ 
++/***
++compare two asn1_string, if equals return true
++
++@function equals
++@tparam asn1_string another to compre
++@treturn boolean true if equals
++@usage
++  local obj = astr:dup()
++  assert(obj==astr, "must equals")
++*/
+ static int openssl_asn1group_eq(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -835,6 +1257,12 @@ static int openssl_asn1group_free(lua_St
+   return 0;
+ }
+ 
++/***
++convert asn1_string to lua string
++
++@function __tostring
++@treturn string result format match with type:data
++*/
+ static int openssl_asn1group_tostring(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -862,6 +1290,12 @@ static int openssl_asn1group_tostring(lu
+   return 0;
+ }
+ 
++/***
++get data as printable encode string
++
++@function toprint
++@treturn string printable encoded string
++*/
+ static int openssl_asn1group_toprint(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -893,6 +1327,12 @@ static int openssl_asn1group_toprint(lua
+   return 1;
+ }
+ 
++/***
++get data as utf8 encode string
++
++@function toutf8
++@treturn string utf8 encoded string
++*/
+ static int openssl_asn1group_toutf8(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -906,6 +1346,12 @@ static int openssl_asn1group_toutf8(lua_
+   return 1;
+ }
+ 
++/***
++duplicate a new asn1_string
++
++@function dup
++@treturn asn1_string clone for self
++*/
+ static int openssl_asn1group_dup(lua_State* L)
+ {
+   ASN1_STRING* s = CHECK_GROUP(1, ASN1_STRING, "openssl.asn1group");
+@@ -913,53 +1359,6 @@ static int openssl_asn1group_dup(lua_Sta
+   return 1;
+ }
+ 
+-static int openssl_asn1generalizedtime_new(lua_State* L)
+-{
+-  ASN1_GENERALIZEDTIME* a = NULL;
+-  int ret = 1;
+-  luaL_argcheck(L,
+-                1,
+-                lua_isnone(L, 1) || lua_isnumber(L, 1) || lua_isstring(L, 1),
+-                "must be number, string or none"
+-               );
+-  a = ASN1_GENERALIZEDTIME_new();
+-  if (lua_isnumber(L, 1))
+-    ASN1_GENERALIZEDTIME_set(a, luaL_checkinteger(L, 1));
+-  else if (lua_isstring(L, 1))
+-    ret = ASN1_GENERALIZEDTIME_set_string(a, lua_tostring(L, 1));
+-
+-  if (ret == 1)
+-    PUSH_OBJECT(a, "openssl.asn1_time");
+-  else
+-    return openssl_pushresult(L, ret);
+-  return 1;
+-}
+-
+-static int openssl_asn1utctime_new(lua_State* L)
+-{
+-  ASN1_UTCTIME* a = NULL;
+-  int ret = 1;
+-  luaL_argcheck(L,
+-                1,
+-                lua_isnone(L, 1) || lua_isnumber(L, 1) || lua_isstring(L, 1),
+-                "must be number, string or none"
+-               );
+-  a = ASN1_UTCTIME_new();
+-  if (lua_isnumber(L, 1))
+-  {
+-    time_t t = luaL_checkinteger(L, 1);
+-    ASN1_TIME_set(a, t);
+-  }
+-  else if (lua_isstring(L, 1))
+-    ret = ASN1_TIME_set_string(a, lua_tostring(L, 1));
+-
+-  if (ret == 1)
+-    PUSH_OBJECT(a, "openssl.asn1_time");
+-  else
+-    return openssl_pushresult(L, ret);
+-  return 1;
+-}
+-
+ static int openssl_asn1time_check(lua_State* L)
+ {
+   ASN1_TIME *a = CHECK_OBJECT(1, ASN1_TIME, "openssl.asn1_time");
+@@ -992,7 +1391,7 @@ static luaL_Reg asn1str_funcs[] =
+   {"tostring",  openssl_asn1group_tostring},
+ 
+   {"__len",     openssl_asn1group_length},
+-  {"__tostring", auxiliar_tostring},
++  {"__tostring",auxiliar_tostring},
+ 
+   {"__eq",      openssl_asn1group_eq},
+   {"__gc",      openssl_asn1group_free},
+@@ -1012,157 +1411,8 @@ static luaL_Reg asn1str_funcs[] =
+   {NULL, NULL}
+ };
+ 
+-static int openssl_get_object(lua_State*L)
+-{
+-  size_t l = 0;
+-  const char* asn1s = luaL_checklstring(L, 1, &l);
+-  size_t off = posrelat(luaL_optinteger(L, 2, 1), l);
+-  size_t length = posrelat(luaL_optinteger(L, 3, l), l);
+-
+-  const unsigned char *p = (const unsigned char *)asn1s + off - 1;
+-  long len = 0;
+-  int tag = 0;
+-  int class = 0;
+-  int ret;
+-
+-  p = (const unsigned char *)asn1s + off - 1;
+-  ret = ASN1_get_object(&p, &len, &tag, &class, length - off + 1);
+-  if (ret & 0x80)
+-  {
+-    lua_pushnil(L);
+-    lua_pushstring(L, "arg 1 with error encoding");
+-    lua_pushinteger(L, ret);
+-    return 3;
+-  }
+-  lua_pushinteger(L, tag);
+-  lua_pushinteger(L, class);
+-  lua_pushinteger(L, p - (const unsigned char *)asn1s + 1);
+-  lua_pushinteger(L, p + len - (const unsigned char *)asn1s);
+-
+-  lua_pushboolean(L, ret & V_ASN1_CONSTRUCTED);
+-  return 5;
+-}
+-
+-static int openssl_put_object(lua_State*L)
+-{
+-  int tag = luaL_checkint(L, 1);
+-  int cls = luaL_checkint(L, 2);
+-  int length = 0;
+-  int constructed;
+-  unsigned char *p1, *p2;
+-  const char* dat = NULL;
+-  luaL_Buffer B;
+-
+-  luaL_argcheck(L,
+-                lua_isnoneornil(L, 3) || lua_type(L, 3) == LUA_TNUMBER || lua_isstring(L, 3), 3,
+-                "if exist only accept string or number");
+-  luaL_argcheck(L, lua_isnoneornil(L, 4) || lua_isboolean(L, 4), 4,
+-                "if exist must be boolean type");
+-
+-  if (lua_isnoneornil(L, 3))
+-  {
+-    /* constructed == 2 for indefinite length constructed */
+-    constructed = 2;
+-    length = 0;
+-  }
+-  else
+-  {
+-    if (lua_type(L, 3) == LUA_TNUMBER)
+-    {
+-      length = lua_tointeger(L, 3);
+-    }
+-    else if (lua_isstring(L, 3))
+-    {
+-      size_t l;
+-      dat = lua_tolstring(L, 3, &l);
+-      length = (int)l;
+-    }
+-
+-    constructed = lua_isnoneornil(L, 4) ? 0 : lua_toboolean(L, 4);
+-  }
+-  luaL_buffinit(L, &B);
+-  p1 = (unsigned char *)luaL_prepbuffer(&B);
+-  p2 = p1;
+-
+-  ASN1_put_object(&p2, constructed, length, tag, cls);
+-  luaL_addsize(&B, p2 - p1);
+-  if (dat)
+-  {
+-    luaL_addlstring(&B, dat, length);
+-  }
+-  luaL_pushresult(&B);
+-  return 1;
+-};
+-
+-static int openssl_asn1_tostring(lua_State*L)
+-{
+-  int val = luaL_checkint(L, 1);
+-  const char* range = luaL_optstring(L, 2, NULL);
+-  int i;
+-
+-  if (range == NULL)
+-  {
+-    for (i = 0; i < sizeof(asn1_const) / sizeof(LuaL_Enum) - 1; i++)
+-    {
+-      if (asn1_const[i].val == val)
+-      {
+-        lua_pushstring(L, asn1_const[i + CLS_IDX_OFFSET].name);
+-        return 1;
+-      }
+-    }
+-  }
+-  else if (strcmp("tag", range) == 0)
+-  {
+-    for (i = 0; i < TAG_IDX_LENGTH; i++)
+-    {
+-      if (asn1_const[i + TAG_IDX_OFFSET].val == val)
+-      {
+-        lua_pushstring(L, asn1_const[i + TAG_IDX_OFFSET].name);
+-        return 1;
+-      }
+-    }
+-  }
+-  else if (strcmp("class", range) == 0)
+-  {
+-    for (i = 0; i < CLS_IDX_LENGTH; i++)
+-    {
+-      if (asn1_const[i + CLS_IDX_OFFSET].val == val)
+-      {
+-        lua_pushstring(L, asn1_const[i + CLS_IDX_OFFSET].name);
+-        return 1;
+-      }
+-    }
+-  }
+-
+-  return 0;
+-}
+-
+-static luaL_Reg R[] =
+-{
+-  {"new_object", openssl_asn1object_new},
+-
+-  {"new_integer", openssl_asn1int_new},
+-  {"new_string", openssl_asn1string_new},
+-  {"new_utctime", openssl_asn1utctime_new},
+-  {"new_generalizedtime", openssl_asn1generalizedtime_new},
+-
+-  {"new_type", openssl_asn1type_new},
+-  {"d2i_asn1type", openssl_asn1type_d2i},
+-
+-  {"get_object", openssl_get_object},
+-  {"put_object", openssl_put_object},
+-
+-  {"tostring", openssl_asn1_tostring},
+-
+-  {"txt2nid",   openssl_txt2nid},
+-
+-
+-  {NULL, NULL}
+-};
+-
+ int luaopen_asn1(lua_State *L)
+ {
+-  int i;
+   tzset();
+   auxiliar_newclass(L, "openssl.asn1_object", asn1obj_funcs);
+   auxiliar_newclass(L, "openssl.asn1_type", asn1type_funcs);
+@@ -1182,12 +1432,7 @@ int luaopen_asn1(lua_State *L)
+   lua_pushliteral(L, MYVERSION);
+   lua_settable(L, -3);
+ 
+-  for (i = 0; i < sizeof(asn1_const) / sizeof(LuaL_Enum) - 1; i++)
+-  {
+-    LuaL_Enum e = asn1_const[i];
+-    lua_pushinteger(L, e.val);
+-    lua_setfield(L, -2, e.name);
+-  }
++  auxiliar_enumerate(L, -1, asn1_const);
+ 
+   return 1;
+ }
+@@ -1212,7 +1457,7 @@ int openssl_get_nid(lua_State*L, int idx
+   else if (lua_isuserdata(L, idx))
+   {
+     ASN1_OBJECT* obj = CHECK_OBJECT(idx, ASN1_OBJECT, "openssl.asn1_object");
+-    return obj->nid;
++    return  OBJ_obj2nid(obj);
+   }
+   else
+   {
+@@ -1229,9 +1474,18 @@ int openssl_push_asn1object(lua_State* L
+   return 1;
+ }
+ 
+-int openssl_push_asn1(lua_State* L, ASN1_STRING* string, int type)
++int openssl_push_asn1(lua_State* L, const ASN1_STRING* string, int type)
+ {
+-  if (type == V_ASN1_UNDEF)
++  if (string == NULL)
++  {
++    lua_pushnil(L);
++    return 1;
++  }
++  if ((string->type & V_ASN1_GENERALIZEDTIME) == V_ASN1_GENERALIZEDTIME && type == V_ASN1_UTCTIME)
++    type = V_ASN1_GENERALIZEDTIME;
++  else if ((string->type & V_ASN1_UTCTIME) == V_ASN1_UTCTIME && type == V_ASN1_GENERALIZEDTIME)
++    type = V_ASN1_UTCTIME;
++  else if (type == V_ASN1_UNDEF)
+     type = string->type;
+   if ((string->type & type) != type)
+   {
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/auxiliar.c luvi-src-v2.7.6/deps/lua-openssl/src/auxiliar.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/auxiliar.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/auxiliar.c	1970-01-01 01:00:00.000000000 +0100
+@@ -1,41 +0,0 @@
+-#include "../deps/auxiliar/auxiliar.c"
+-
+-#if LUA_VERSION_NUM==501
+-#define lua_rawlen lua_strlen
+-#define luaL_typeerror luaL_typerror
+-#endif
+-/*=========================================================================*\
+-* Exported functions
+-\*=========================================================================*/
+-
+-int auxiliar_isclass(lua_State *L, const char *classname, int objidx)
+-{
+-  void *p = lua_touserdata(L, objidx);
+-  if (p != NULL)    /* value is a userdata? */
+-  {
+-    if (lua_getmetatable(L, objidx))    /* does it have a metatable? */
+-    {
+-      lua_getfield(L, LUA_REGISTRYINDEX, classname);  /* get correct metatable */
+-      if (lua_rawequal(L, -1, -2))    /* does it have the correct mt? */
+-      {
+-        lua_pop(L, 2);  /* remove both metatables */
+-        return 1;
+-      }
+-      else
+-        lua_pop(L, 2);
+-    }
+-  }
+-  return 0;
+-}
+-
+-int auxiliar_isgroup(lua_State *L, const char *groupname, int objidx)
+-{
+-  void *data = auxiliar_getgroupudata(L, groupname, objidx);
+-  return data != NULL;
+-}
+-
+-int auxiliar_checkoption(lua_State*L, int objidx, const char* def, const char* const slist[], const int ival[])
+-{
+-  int at = luaL_checkoption(L, objidx, def, slist);
+-  return ival[at];
+-}
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/auxiliar.h luvi-src-v2.7.6/deps/lua-openssl/src/auxiliar.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/auxiliar.h	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/auxiliar.h	1970-01-01 01:00:00.000000000 +0100
+@@ -1,37 +0,0 @@
+-#ifndef AUXILIAR_H_EXT
+-#define AUXILIAR_H_EXT
+-#include "../deps/auxiliar/auxiliar.h"
+-
+-#define AUXILIAR_SET(L,tidx, lvar, cval, ltype) \
+-  do {                  \
+-  int n = tidx < 0 ? tidx-1 : tidx;   \
+-  lua_push##ltype(L, (cval));       \
+-  lua_setfield(L, n, lvar);       \
+-  } while(0)
+-
+-#define AUXILIAR_SETLSTR(L,tidx, lvar, cval,len)  \
+-  do {                  \
+-  int n = tidx < 0 ? tidx-1 : tidx;   \
+-  lua_pushlstring(L, (const char*)(cval),len);        \
+-  lua_setfield(L, n, lvar);       \
+-  } while(0)
+-
+-#define AUXLIAR_GET(L,tidx, lvar, cvar, ltype)  \
+-  do {                  \
+-  lua_getfield(L, tidx, lvar);      \
+-  cvar = lua_to##ltype(L, -1);      \
+-  lua_pop(L, 1);              \
+-  } while(0)
+-
+-typedef struct
+-{
+-  const char* name;
+-  int val;
+-} LuaL_Enum;
+-
+-int auxiliar_isclass(lua_State *L, const char *classname, int objidx);
+-int auxiliar_isgroup(lua_State *L, const char *groupname, int objidx);
+-
+-int auxiliar_checkoption(lua_State*L, int objidx, const char* def, const char* const slist[], const int ival[]);
+-
+-#endif /* AUXILIAR_H_EXT */
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/bio.c luvi-src-v2.7.6/deps/lua-openssl/src/bio.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/bio.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/bio.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,10 +1,11 @@
+-/*=========================================================================*\
+-* bio.c
+-* bio object for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
+-
++/***
++bio object for lua-openssl binding,  mapping to BIO in openssl
++openssl.bio is a help object, it is useful, but rarely use.
++
++@module bio
++@usage
++  bio = require'openssl'.bio
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #include <openssl/ssl.h>
+@@ -53,7 +54,6 @@ luaL_error(L, "error opening the file(%s
+ PUSH_OBJECT(bio,"openssl.bio");
+ return 1;
+ }
+-
+ */
+ 
+ static const char* close_flags[] =
+@@ -63,6 +63,13 @@ static const char* close_flags[] =
+   NULL
+ };
+ 
++/***
++make string as bio object
++
++@function mem
++@tparam[opt=nil] string data, it will be memory buffer data
++@treturn bio it can be input or output object
++*/
+ static LUA_FUNCTION(openssl_bio_new_mem)
+ {
+   size_t l = 0;
+@@ -78,11 +85,19 @@ static LUA_FUNCTION(openssl_bio_new_mem)
+     BIO_write(bio, d, l);
+   }
+ 
+-  BIO_set_close(bio, BIO_CLOSE);
++  (void)BIO_set_close(bio, BIO_CLOSE);
+   PUSH_OBJECT(bio, "openssl.bio");
+   return 1;
+ }
+ 
++/***
++make tcp bio from socket fd
++
++@function socket
++@tparam number fd
++@tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
++@treturn bio
++*/
+ static LUA_FUNCTION(openssl_bio_new_socket)
+ {
+   int s = luaL_checkint(L, 1);
+@@ -93,6 +108,14 @@ static LUA_FUNCTION(openssl_bio_new_sock
+   return 1;
+ }
+ 
++/***
++make dgram bio from socket fd
++
++@function dgram
++@tparam number fd
++@tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
++@treturn bio
++*/
+ static LUA_FUNCTION(openssl_bio_new_dgram)
+ {
+   int s = luaL_checkint(L, 1);
+@@ -102,6 +125,13 @@ static LUA_FUNCTION(openssl_bio_new_dgra
+   return 1;
+ }
+ 
++/***
++make socket or file bio with fd
++@function fd
++@tparam number fd
++@tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
++@treturn bio
++*/
+ static LUA_FUNCTION(openssl_bio_new_fd)
+ {
+   int fd = luaL_checkint(L, 1);
+@@ -112,6 +142,13 @@ static LUA_FUNCTION(openssl_bio_new_fd)
+   return 1;
+ }
+ 
++/***
++make file object with file name or path
++@function file
++@tparam string file
++@tparam[opt='r'] string mode
++@treturn bio
++*/
+ static LUA_FUNCTION(openssl_bio_new_file)
+ {
+   const char* f = luaL_checkstring(L, 1);
+@@ -123,6 +160,12 @@ static LUA_FUNCTION(openssl_bio_new_file
+   return 1;
+ }
+ 
++/***
++make tcp listen socket
++@function accept
++@tparam string host_port address like 'host:port'
++@treturn bio
++*/
+ static LUA_FUNCTION(openssl_bio_new_accept)
+ {
+   const char* port = lua_tostring(L, 1);
+@@ -132,6 +175,13 @@ static LUA_FUNCTION(openssl_bio_new_acce
+   return 1;
+ }
+ 
++/***
++make tcp client socket
++@function connect
++@tparam string host_addr addrees like 'host:port'
++@tparam[opt=true] boolean connect default connect immediately
++@treturn bio
++*/
+ static int openssl_bio_new_connect(lua_State *L)
+ {
+   const char *host = luaL_checkstring(L, 1);
+@@ -167,7 +217,7 @@ static int openssl_bio_new_connect(lua_S
+       openssl_newvalue(L, bio);
+ 
+       lua_pushboolean(L, 1);
+-      openssl_setvalue(L, bio, "free_all");
++      openssl_valueset(L, bio, "free_all");
+       return 1;
+     }
+     else
+@@ -183,6 +233,36 @@ static int openssl_bio_new_connect(lua_S
+   return 0;
+ }
+ 
++/***
++Create base64 or buffer bio, which can append to an io BIO object
++@function filter
++@tparam string mode support 'base64' or 'buffer'
++@treturn bio
++*/
++/***
++Create digest bio, which can append to an io BIO object
++@function filter
++@tparam string mode must be 'digest'
++@tparam evp_md|string md_alg
++@treturn bio
++*/
++/***
++Create ssl bio
++@function filter
++@tparam string mode must be 'ssl'
++@tparam ssl s
++@tparam[opt='noclose'] flag support 'close' or 'noclose' when close or gc
++@treturn bio
++*/
++/***
++create cipher filter bio object
++@function filter
++@tparam string mode must be 'cipher'
++@tparam string key
++@tparam string iv
++@tparam[opt=true] boolean encrypt
++@treturn bio
++*/
+ static LUA_FUNCTION(openssl_bio_new_filter)
+ {
+   /* 0         1        2      3      4    5 */
+@@ -213,7 +293,7 @@ static LUA_FUNCTION(openssl_bio_new_filt
+   break;
+   case 3:
+   {
+-    const EVP_MD* md = get_digest(L, 2);
++    const EVP_MD* md = get_digest(L, 2, NULL);
+     bio = BIO_new(BIO_f_md());
+     ret = BIO_set_md(bio, md);
+   }
+@@ -236,7 +316,7 @@ static LUA_FUNCTION(openssl_bio_new_filt
+       openssl_newvalue(L, bio);
+ 
+       lua_pushboolean(L, 1);
+-      openssl_setvalue(L, bio, "free_all");
++      openssl_valueset(L, bio, "free_all");
+     }
+     return 1;
+   }
+@@ -249,6 +329,17 @@ static LUA_FUNCTION(openssl_bio_new_filt
+ }
+ 
+ /* bio object method */
++/***
++openssl.bio object
++@type bio
++*/
++
++/***
++read data from bio object
++@function read
++@tparam number len
++@treturn string string length may be less than param len
++*/
+ static LUA_FUNCTION(openssl_bio_read)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -280,6 +371,12 @@ static LUA_FUNCTION(openssl_bio_read)
+   return ret;
+ }
+ 
++/***
++get line from bio object
++@function gets
++@tparam[opt=256] number max line len
++@treturn string string length may be less than param len
++*/
+ static LUA_FUNCTION(openssl_bio_gets)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -310,7 +407,12 @@ static LUA_FUNCTION(openssl_bio_gets)
+   return ret;
+ }
+ 
+-
++/***
++write data to bio object
++@function write
++@tparam string data
++@treturn number length success write
++*/
+ static LUA_FUNCTION(openssl_bio_write)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -339,6 +441,12 @@ static LUA_FUNCTION(openssl_bio_write)
+   return ret;
+ }
+ 
++/***
++put line to bio object
++@function puts
++@tparam string data
++@treturn number length success write
++*/
+ static LUA_FUNCTION(openssl_bio_puts)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -365,6 +473,11 @@ static LUA_FUNCTION(openssl_bio_puts)
+   return ret;
+ }
+ 
++/***
++flush buffer of bio object
++@function flush
++@treturn boolean true for success, others for fail
++*/
+ static LUA_FUNCTION(openssl_bio_flush)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -382,7 +495,7 @@ static LUA_FUNCTION(openssl_bio_free)
+     all = lua_toboolean(L, 2);
+   else
+   {
+-    openssl_getvalue(L, bio, "free_all");
++    openssl_valueget(L, bio, "free_all");
+     all = lua_toboolean(L, -1);
+     lua_pop(L, 1);
+   }
+@@ -396,6 +509,11 @@ static LUA_FUNCTION(openssl_bio_free)
+   return 0;
+ }
+ 
++/***
++get type of bio
++@function type
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_bio_type)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -403,6 +521,12 @@ static LUA_FUNCTION(openssl_bio_type)
+   return 1;
+ }
+ 
++/***
++set nonblock for bio object
++@function nbio
++@tparam boolean nonblock
++@treturn boolean result, true for success, others for fail
++*/
+ static LUA_FUNCTION(openssl_bio_nbio)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -428,16 +552,24 @@ static LUA_FUNCTION(openssl_bio_retry)
+   return 1;
+ }
+ 
+-
+-
++/***
++reset bio
++@function reset
++*/
+ static LUA_FUNCTION(openssl_bio_reset)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+-  BIO_reset(bio);
++  (void)BIO_reset(bio);
+   return 0;
+ }
+ 
+ /* filter bio object */
++/***
++push bio append to chain of bio, if want to free a chain use free_all()
++@function push
++@tparam bio append
++@treturn bio
++*/
+ static LUA_FUNCTION(openssl_bio_push)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -450,23 +582,33 @@ static LUA_FUNCTION(openssl_bio_push)
+   return 1;
+ }
+ 
++/***
++remove bio from chain
++@function pop
++@tparam bio toremove
++*/
+ static LUA_FUNCTION(openssl_bio_pop)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+   BIO* end = BIO_pop(bio);
+-  if (end)
++  if (end == NULL)
+   {
+     lua_pushnil(L);
+   }
+   else
+   {
+-    CRYPTO_add(&end->references, 1, CRYPTO_LOCK_BIO);
++    BIO_up_ref(end);
+     PUSH_OBJECT(end, "openssl.bio");
+   }
+   return 1;
+ }
+ 
+ /* mem */
++/***
++get mem data, only support mem bio object
++@function get_mem
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_bio_get_mem)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -482,7 +624,13 @@ static LUA_FUNCTION(openssl_bio_get_mem)
+ }
+ 
+ /* network socket */
+-
++/***
++setup ready and accept client connect
++@function accept
++@tparam[opt=false] boolean setup true for setup accept bio, false or none will accept client connect
++@treturn[1] boolean result only when setup is true
++@treturn[2] bio accpeted bio object
++*/
+ static LUA_FUNCTION(openssl_bio_accept)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -498,7 +646,7 @@ static LUA_FUNCTION(openssl_bio_accept)
+       openssl_newvalue(L, nb);
+ 
+       lua_pushboolean(L, 1);
+-      openssl_setvalue(L, nb, "free_all");
++      openssl_valueset(L, nb, "free_all");
+       return 1;
+     }
+     else
+@@ -510,6 +658,10 @@ static LUA_FUNCTION(openssl_bio_accept)
+   return 0;
+ }
+ 
++/***
++shutdown SSL or TCP connection
++@function shutdown
++*/
+ static LUA_FUNCTION(openssl_bio_shutdown)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -520,14 +672,18 @@ static LUA_FUNCTION(openssl_bio_shutdown
+   }
+   else if (BIO_method_type(bio) & (BIO_TYPE_SOCKET | BIO_TYPE_FD))
+   {
+-    BIO_shutdown_wr(bio);;
++    (void)BIO_shutdown_wr(bio);;
+   }
+   else
+     luaL_error(L, "don't know how to shutdown");
+   return 0;
+ }
+ 
+-
++/***
++get ssl object assosited with bio object
++@function get_ssl
++@treturn ssl
++*/
+ static LUA_FUNCTION(openssl_bio_get_ssl)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -543,6 +699,11 @@ static LUA_FUNCTION(openssl_bio_get_ssl)
+   return 0;
+ }
+ 
++/***
++do TCP or SSL connect
++@function connect
++@treturn booolean result true for success and others for fail
++*/
+ static LUA_FUNCTION(openssl_bio_connect)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -550,6 +711,11 @@ static LUA_FUNCTION(openssl_bio_connect)
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++do handshake of TCP or SSL connection
++@function handshake
++@treturn boolean result true for success, and others for fail
++*/
+ static LUA_FUNCTION(openssl_bio_handshake)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -557,6 +723,17 @@ static LUA_FUNCTION(openssl_bio_handshak
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get fd of bio object
++@function fd
++@treturn number
++*/
++/***
++set fd of bio object
++@function fd
++@tparam number fd
++@treturn number fd
++*/
+ static LUA_FUNCTION(openssl_bio_fd)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -584,71 +761,68 @@ void BIO_info_callback(BIO *bio, int cmd
+   BIO *b;
+   char buf[256];
+   char *p;
+-  long r = 1;
+   size_t p_maxlen;
+   (void) argl;
+   (void) argp;
+-  if (BIO_CB_RETURN & cmd)
+-    r = ret;
+ 
+-  BIO_snprintf(buf, sizeof buf, "BIO[%08lX]:", (unsigned long)bio);
++  snprintf(buf, sizeof buf, "BIO[%p]:", bio);
+   p = &(buf[14]);
+   p_maxlen = sizeof buf - 14;
+   switch (cmd)
+   {
+   case BIO_CB_FREE:
+-    BIO_snprintf(p, p_maxlen, "Free - %s\n", bio->method->name);
++    snprintf(p, p_maxlen, "Free - %s\n", BIO_method_name(bio));
+     break;
+   case BIO_CB_READ:
+-    if (bio->method->type & BIO_TYPE_DESCRIPTOR)
+-      BIO_snprintf(p, p_maxlen, "read(%d,%lu) - %s fd=%d\n",
+-                   bio->num, (unsigned long)argi,
+-                   bio->method->name, bio->num);
++    if (BIO_method_type(bio) & BIO_TYPE_DESCRIPTOR)
++      snprintf(p, p_maxlen, "read(%lu,%lu) - %s fd=%lu\n",
++               BIO_number_read(bio), (unsigned long)argi,
++               BIO_method_name(bio), BIO_number_read(bio));
+     else
+-      BIO_snprintf(p, p_maxlen, "read(%d,%lu) - %s\n",
+-                   bio->num, (unsigned long)argi,
+-                   bio->method->name);
++      snprintf(p, p_maxlen, "read(%lu,%lu) - %s\n",
++               BIO_number_read(bio), (unsigned long)argi,
++               BIO_method_name(bio));
+     break;
+   case BIO_CB_WRITE:
+-    if (bio->method->type & BIO_TYPE_DESCRIPTOR)
+-      BIO_snprintf(p, p_maxlen, "write(%d,%lu) - %s fd=%d\n",
+-                   bio->num, (unsigned long)argi,
+-                   bio->method->name, bio->num);
++    if (BIO_method_type(bio) & BIO_TYPE_DESCRIPTOR)
++      snprintf(p, p_maxlen, "write(%lu,%lu) - %s fd=%lu\n",
++               BIO_number_written(bio), (unsigned long)argi,
++               BIO_method_name(bio), BIO_number_written(bio));
+     else
+-      BIO_snprintf(p, p_maxlen, "write(%d,%lu) - %s\n",
+-                   bio->num, (unsigned long)argi,
+-                   bio->method->name);
++      snprintf(p, p_maxlen, "write(%lu,%lu) - %s\n",
++               BIO_number_written(bio), (unsigned long)argi,
++               BIO_method_name(bio));
+     break;
+   case BIO_CB_PUTS:
+-    BIO_snprintf(p, p_maxlen, "puts() - %s\n", bio->method->name);
++    snprintf(p, p_maxlen, "puts() - %s\n", BIO_method_name(bio));
+     break;
+   case BIO_CB_GETS:
+-    BIO_snprintf(p, p_maxlen, "gets(%lu) - %s\n", (unsigned long)argi, bio->method->name);
++    snprintf(p, p_maxlen, "gets(%lu) - %s\n", (unsigned long)argi, BIO_method_name(bio));
+     break;
+   case BIO_CB_CTRL:
+-    BIO_snprintf(p, p_maxlen, "ctrl(%lu) - %s\n", (unsigned long)argi, bio->method->name);
++    snprintf(p, p_maxlen, "ctrl(%lu) - %s\n", (unsigned long)argi, BIO_method_name(bio));
+     break;
+   case BIO_CB_RETURN|BIO_CB_READ:
+-    BIO_snprintf(p, p_maxlen, "read return %ld\n", ret);
++    snprintf(p, p_maxlen, "read return %ld\n", ret);
+     break;
+   case BIO_CB_RETURN|BIO_CB_WRITE:
+-    BIO_snprintf(p, p_maxlen, "write return %ld\n", ret);
++    snprintf(p, p_maxlen, "write return %ld\n", ret);
+     break;
+   case BIO_CB_RETURN|BIO_CB_GETS:
+-    BIO_snprintf(p, p_maxlen, "gets return %ld\n", ret);
++    snprintf(p, p_maxlen, "gets return %ld\n", ret);
+     break;
+   case BIO_CB_RETURN|BIO_CB_PUTS:
+-    BIO_snprintf(p, p_maxlen, "puts return %ld\n", ret);
++    snprintf(p, p_maxlen, "puts return %ld\n", ret);
+     break;
+   case BIO_CB_RETURN|BIO_CB_CTRL:
+-    BIO_snprintf(p, p_maxlen, "ctrl return %ld\n", ret);
++    snprintf(p, p_maxlen, "ctrl return %ld\n", ret);
+     break;
+   default:
+-    BIO_snprintf(p, p_maxlen, "bio callback - unknown type (%d)\n", cmd);
++    snprintf(p, p_maxlen, "bio callback - unknown type (%d)\n", cmd);
+     break;
+   }
+ 
+-  b = (BIO *)bio->cb_arg;
++  b = (BIO *)BIO_get_callback_arg(bio);
+   if (b != NULL)
+     BIO_write(b, buf, strlen(buf));
+ #if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)
+@@ -657,6 +831,12 @@ void BIO_info_callback(BIO *bio, int cmd
+ #endif
+ }
+ 
++/***
++set callback function of bio information
++@function set_callback
++@tparam function callback
++@treturn boolean result true for success, and others for fail
++*/
+ static LUA_FUNCTION(openssl_bio_set_callback)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -668,6 +848,11 @@ static LUA_FUNCTION(openssl_bio_set_call
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++return pending length of bytes to read and write
++@function pending
++@treturn number pending of read, followed by pending of write
++*/
+ static LUA_FUNCTION(openssl_bio_pending)
+ {
+   BIO* bio = CHECK_OBJECT(1, BIO, "openssl.bio");
+@@ -679,6 +864,16 @@ static LUA_FUNCTION(openssl_bio_pending)
+   return 2;
+ }
+ 
++/***
++free a chain
++@function free_all
++*/
++
++/***
++close bio
++@function close
++*/
++
+ static luaL_Reg bio_funs[] =
+ {
+   /* generate operation */
+@@ -746,4 +941,3 @@ int luaopen_bio(lua_State *L)
+ 
+   return 1;
+ }
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/callback.c luvi-src-v2.7.6/deps/lua-openssl/src/callback.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/callback.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/callback.c	2019-02-13 11:53:24.275126573 +0100
+@@ -13,17 +13,17 @@ static int verify_cb(int preverify_ok, X
+ {
+   int err = X509_STORE_CTX_get_error(xctx);
+   int depth = X509_STORE_CTX_get_error_depth(xctx);
+-  X509 *current = xctx->current_cert;
++  X509 *current = X509_STORE_CTX_get_current_cert(xctx);
+ 
+   if (L)
+   {
+     /* get verify_cert state */
+-    openssl_getvalue(L, ssl, "verify_cert");
++    openssl_valueget(L, ssl, "verify_cert");
+     if (lua_isnil(L, -1))
+     {
+       lua_newtable(L);
+-      openssl_setvalue(L, ssl, "verify_cert");
+-      openssl_getvalue(L, ssl, "verify_cert");
++      openssl_valueset(L, ssl, "verify_cert");
++      openssl_valueget(L, ssl, "verify_cert");
+     }
+ 
+     /* create current verify state table */
+@@ -42,11 +42,11 @@ static int verify_cb(int preverify_ok, X
+     if (current)
+     {
+       PUSH_OBJECT(current, "openssl.x509");
+-      CRYPTO_add(&current->references, 1, CRYPTO_LOCK_X509);
++      X509_up_ref(current);
+       lua_setfield(L, -2, "current_cert");
+     }
+ 
+-    openssl_getvalue(L, ctx, preverify_ok == -1 ? "cert_verify_cb" : "verify_cb");
++    openssl_valueget(L, ctx, preverify_ok == -1 ? "cert_verify_cb" : "verify_cb");
+     if (lua_isfunction(L, -1))
+     {
+       /* this is set by  SSL_CTX_set_verify */
+@@ -62,7 +62,7 @@ static int verify_cb(int preverify_ok, X
+     else
+     {
+       int always_continue, verify_depth;
+-      openssl_getvalue(L, ctx, "verify_cb_flags");
++      openssl_valueget(L, ctx, "verify_cb_flags");
+       /*
+       int verify_depth;
+       int always_continue;
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/cipher.c luvi-src-v2.7.6/deps/lua-openssl/src/cipher.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/cipher.c	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/cipher.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,10 +1,10 @@
+-/*=========================================================================*\
+-* cipher.c
+-* cipher module for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++cipher module for lua-openssl binding
+ 
++@module cipher
++@usage
++  cipher = require('openssl').cipher
++*/
+ #include "openssl.h"
+ #include "private.h"
+ 
+@@ -12,6 +12,13 @@
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
++/***
++list all support cipher algs
++
++@function list
++@tparam[opt] boolean alias include alias names for cipher alg, default true
++@treturn[table] all cipher methods
++*/
+ static LUA_FUNCTION(openssl_cipher_list)
+ {
+   int alias = lua_isnoneornil(L, 1) ? 1 : lua_toboolean(L, 1);
+@@ -20,6 +27,15 @@ static LUA_FUNCTION(openssl_cipher_list)
+   return 1;
+ }
+ 
++/***
++get evp_cipher object
++
++@function get
++@tparam string|integer|asn1_object alg name, nid or object identity
++@treturn evp_cipher cipher object mapping EVP_MD in openssl
++
++@see evp_cipher
++*/
+ static LUA_FUNCTION(openssl_cipher_get)
+ {
+   if (!lua_isuserdata(L, 1))
+@@ -33,12 +49,24 @@ static LUA_FUNCTION(openssl_cipher_get)
+   }
+   else
+   {
+-    luaL_argcheck(L, auxiliar_isclass(L, "openssl.evp_cipher", 1), 1, "only accept openssl.evp_cipher object");
++    luaL_argcheck(L, auxiliar_getclassudata(L, "openssl.evp_cipher", 1), 1, "only accept openssl.evp_cipher object");
+     lua_pushvalue(L, 1);
+   }
+   return 1;
+ }
+ 
++/***
++quick encrypt
++
++@function encrypt
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam string input data to encrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn string result encrypt data
++*/
+ static LUA_FUNCTION(openssl_evp_encrypt)
+ {
+   const EVP_CIPHER* cipher = NULL;
+@@ -116,6 +144,18 @@ static LUA_FUNCTION(openssl_evp_encrypt)
+   return 0;
+ }
+ 
++/***
++quick decrypt
++
++@function decrypt
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam string input data to decrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn string result decrypt data
++*/
+ static LUA_FUNCTION(openssl_evp_decrypt)
+ {
+   const EVP_CIPHER* cipher;
+@@ -193,6 +233,19 @@ static LUA_FUNCTION(openssl_evp_decrypt)
+   return 0;
+ }
+ 
++/***
++quick encrypt or decrypt
++
++@function cipher
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam boolean encrypt true for encrypt,false for decrypt
++@tparam string input data to encrypt or decrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn string result
++*/
+ static LUA_FUNCTION(openssl_evp_cipher)
+ {
+   const EVP_CIPHER* cipher = NULL;
+@@ -285,6 +338,21 @@ typedef enum
+   DO_DECRYPT = 1
+ } CIPHER_MODE;
+ 
++/***
++get evp_cipher_ctx object for encrypt or decrypt
++
++@function new
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam boolean encrypt true for encrypt,false for decrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn evp_cipher_ctx cipher object mapping EVP_CIPHER_CTX in openssl
++
++@see evp_cipher_ctx
++*/
++
+ static LUA_FUNCTION(openssl_cipher_new)
+ {
+   const EVP_CIPHER* cipher = get_cipher(L, 1, NULL);
+@@ -328,6 +396,20 @@ static LUA_FUNCTION(openssl_cipher_new)
+   return 1;
+ }
+ 
++/***
++get evp_cipher_ctx object for encrypt
++
++@function encrypt_new
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn evp_cipher_ctx cipher object mapping EVP_CIPHER_CTX in openssl
++
++@see evp_cipher_ctx
++*/
++
+ static LUA_FUNCTION(openssl_cipher_encrypt_new)
+ {
+   const EVP_CIPHER* cipher  = get_cipher(L, 1, NULL);
+@@ -370,6 +452,20 @@ static LUA_FUNCTION(openssl_cipher_encry
+   return 1;
+ }
+ 
++/***
++get evp_cipher_ctx object for decrypt
++
++@function decrypt_new
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn evp_cipher_ctx cipher object mapping EVP_CIPHER_CTX in openssl
++
++@see evp_cipher_ctx
++*/
++
+ static LUA_FUNCTION(openssl_cipher_decrypt_new)
+ {
+   const EVP_CIPHER* cipher = get_cipher(L, 1, NULL);
+@@ -424,7 +520,16 @@ static LUA_FUNCTION(openssl_cipher_decry
+   return 0;
+ }
+ 
+-/* evp_cipher method */
++/***
++openssl.evp_cipher object
++@type evp_cipher
++*/
++/***
++get infomation of evp_cipher object
++
++@function info
++@treturn table info keys include name,block_size,key_length,iv_length,flags,mode
++*/
+ static LUA_FUNCTION(openssl_cipher_info)
+ {
+   EVP_CIPHER *cipher = CHECK_OBJECT(1, EVP_CIPHER, "openssl.evp_cipher");
+@@ -438,14 +543,23 @@ static LUA_FUNCTION(openssl_cipher_info)
+   return 1;
+ }
+ 
++/***
++derive key
+ 
++@function BytesToKey
++@tparam string data derive data
++@tparam string[opt] string salt salt will get strong security
++@tparam ev_digest|string md digest method used to diver key, default with 'sha1'
++@treturn string key
++@treturn string iv
++*/
+ static LUA_FUNCTION(openssl_evp_BytesToKey)
+ {
+   EVP_CIPHER* c = CHECK_OBJECT(1, EVP_CIPHER, "openssl.evp_cipher");
+   size_t lsalt, lk;
+   const char* k = luaL_checklstring(L, 2, &lk);
+   const char* salt = luaL_optlstring(L, 3, NULL, &lsalt);
+-  const EVP_MD* m = lua_isnoneornil(L, 4) ? EVP_get_digestbyname("sha1") : get_digest(L, 4);
++  const EVP_MD* m = get_digest(L, 4, "sha256");
+   char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
+   int ret;
+   if (salt != NULL && lsalt < PKCS5_SALT_LEN)
+@@ -457,15 +571,102 @@ static LUA_FUNCTION(openssl_evp_BytesToK
+   ret = EVP_BytesToKey(c, m, (unsigned char*)salt, (unsigned char*)k, lk, 1, (unsigned char*)key, (unsigned char*)iv);
+   if (ret > 1)
+   {
+-    lua_pushlstring(L, key, c->key_len);
+-    lua_pushlstring(L, iv, c->iv_len);
++    lua_pushlstring(L, key, EVP_CIPHER_key_length(c));
++    lua_pushlstring(L, iv, EVP_CIPHER_iv_length(c));
+     return 2;
+   }
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get evp_cipher_ctx to encrypt or decrypt
++
++@function new
++@tparam boolean encrypt true for encrypt,false for decrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn evp_cipher_ctx evp_cipher_ctx object
++
++@see evp_cipher_ctx
++*/
++
++/***
++get evp_cipher_ctx to encrypt
++
++@function encrypt_new
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn evp_cipher_ctx evp_cipher_ctx object
++
++@see evp_cipher_ctx
++*/
++
++/***
++get evp_cipher_ctx to decrypt
++
++@function decrypt_new
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn evp_cipher_ctx evp_cipher_ctx object
++
++@see evp_cipher_ctx
++*/
++
++/***
++do encrypt or decrypt
++
++@function cipher
++@tparam boolean encrypt true for encrypt,false for decrypt
++@tparam string input data to encrypt or decrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn string result
++*/
++
++/***
++do encrypt
++
++@function encrypt
++@tparam string input data to encrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn string result
++*/
++
++/***
++do decrypt
++
++@function decrypt
++@tparam string input data to decrypt
++@tparam string key secret key
++@tparam[opt] string iv
++@tparam[opt] boolean pad true for padding default
++@tparam[opt] engine engine custom crypto engine
++@treturn string result
++*/
+ 
+ /* evp_cipher_ctx method */
++/***
++openssl.evp_cipher_ctx object
++@type evp_cipher_ctx
++*/
++/***
++feed data to do cipher
++
++@function update
++@tparam string msg data
++@treturn string result parture result
++*/
+ static LUA_FUNCTION(openssl_evp_cipher_update)
+ {
+   EVP_CIPHER_CTX* c = CHECK_OBJECT(1, EVP_CIPHER_CTX, "openssl.evp_cipher_ctx");
+@@ -498,6 +699,12 @@ static LUA_FUNCTION(openssl_evp_cipher_u
+   return (ret == 1 ? ret : openssl_pushresult(L, ret));
+ }
+ 
++/***
++get result of cipher
++
++@function final
++@treturn string result last result
++*/
+ static LUA_FUNCTION(openssl_evp_cipher_final)
+ {
+   EVP_CIPHER_CTX* c = CHECK_OBJECT(1, EVP_CIPHER_CTX, "openssl.evp_cipher_ctx");
+@@ -527,6 +734,12 @@ static LUA_FUNCTION(openssl_evp_cipher_f
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get infomation of evp_cipher_ctx object
++
++@function info
++@treturn table info keys include block_size,key_length,iv_length,flags,mode,nid,type, evp_cipher
++*/
+ static LUA_FUNCTION(openssl_cipher_ctx_info)
+ {
+   EVP_CIPHER_CTX *ctx = CHECK_OBJECT(1, EVP_CIPHER_CTX, "openssl.evp_cipher_ctx");
+@@ -546,10 +759,13 @@ static LUA_FUNCTION(openssl_cipher_ctx_i
+ static LUA_FUNCTION(openssl_cipher_ctx_free)
+ {
+   EVP_CIPHER_CTX *ctx = CHECK_OBJECT(1, EVP_CIPHER_CTX, "openssl.evp_cipher_ctx");
++  if(!ctx)
++    return 0;
+   lua_pushnil(L);
+   lua_rawsetp(L, LUA_REGISTRYINDEX, ctx);
+   EVP_CIPHER_CTX_cleanup(ctx);
+   EVP_CIPHER_CTX_free(ctx);
++  FREE_OBJECT(1);
+   return 0;
+ }
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/cms.c luvi-src-v2.7.6/deps/lua-openssl/src/cms.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/cms.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/cms.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,10 +1,32 @@
+-/*=========================================================================*\
+-* hamc.c
+-* hamc module for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++cms module for lua-openssl binding
+ 
++The Cryptographic Message Syntax (CMS) is the IETF's standard for
++cryptographically protected messages. It can be used to digitally sign, digest,
++authenticate or encrypt any form of digital data. CMS is based on the syntax of
++PKCS#7, which in turn is based on the Privacy-Enhanced Mail standard. The
++newest version of CMS is specified in RFC 5652.
++
++The architecture of CMS is built around certificate-based key management, such
++as the profile defined by the PKIX working group. CMS is used as the key
++cryptographic component of many other cryptographic standards, such as S/MIME,
++PKCS #12 and the RFC 3161 Digital timestamping protocol.
++
++OpenSSL is open source software that can encrypt, decrypt, sign and verify,
++compress and uncompress CMS documents.
++
++
++CMS are based on apps/cms.c from the OpenSSL dist, so for more information,
++you better see the documentation for OpenSSL.
++cms api need flags, not support "detached", "nodetached", "text", "nointern",
++"noverify", "nochain", "nocerts", "noattr", "binary", "nosigs"
++
++OpenSSL not give full document about CMS api, so some function will be dangers.
++
++@module cms
++@usage
++  cms = require('openssl').cms
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #if OPENSSL_VERSION_NUMBER > 0x00909000L && !defined (LIBRESSL_VERSION_NUMBER)
+@@ -14,35 +36,47 @@
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
+-static LuaL_Enum cms_flags[] =
++static LuaL_Enumeration cms_flags[] =
+ {
+-  {"text",    0x1},
+-  {"nocerts",   0x2},
+-  {"no_content_verify", 0x04},
+-  {"no_attr_verify",    0x8},
+-  {"nosigs",        (CMS_NO_CONTENT_VERIFY | CMS_NO_ATTR_VERIFY)},
+-  {"nointern",    0x10},
++  {"text",                  0x1},
++  {"nocerts",               0x2},
++  {"no_content_verify",     0x04},
++  {"no_attr_verify",        0x8},
++  {"nosigs",                (CMS_NO_CONTENT_VERIFY | CMS_NO_ATTR_VERIFY)},
++  {"nointern",              0x10},
+   {"no_signer_cert_verify", 0x20},
+-  {"noverify",    0x20},
+-  {"detached",    0x40},
+-  {"binary",      0x80},
+-  {"noattr",      0x100},
+-  {"nosmimecap",    0x200},
+-  {"nooldmimetype", 0x400},
+-  {"crlfeol",     0x800},
+-  {"stream",      0x1000},
+-  {"nocrl",     0x2000},
+-  {"partial",     0x4000},
+-  {"reuse_digest",  0x8000},
+-  {"use_keyid",   0x10000},
+-  {"debug_decrypt", 0x20000},
+-  {NULL,        -1}
++  {"noverify",              0x20},
++  {"detached",              0x40},
++  {"binary",                0x80},
++  {"noattr",                0x100},
++  {"nosmimecap",            0x200},
++  {"nooldmimetype",         0x400},
++  {"crlfeol",               0x800},
++  {"stream",                0x1000},
++  {"nocrl",                 0x2000},
++  {"partial",               0x4000},
++  {"reuse_digest",          0x8000},
++  {"use_keyid",             0x10000},
++  {"debug_decrypt",         0x20000},
++  {NULL,                    -1}
+ };
+ 
++/***
++read cms object from input bio or string
++
++@function read
++@tparam bio|string input
++@tparam[opt='auto'] string format, support 'auto','smime','der','pem'
++  auto will only try 'der' or 'pem'
++@tparam[opt=nil] bio content, only used when format is 'smime'
++@treturn cms
++*/
+ static int openssl_cms_read(lua_State *L)
+ {
+   BIO* in = load_bio_object(L, 1);
+   int fmt = luaL_checkoption(L, 2, "auto", format);
++  BIO* data = NULL;
++
+   CMS_ContentInfo *cms = NULL;
+   if (fmt == FORMAT_AUTO)
+   {
+@@ -60,27 +94,38 @@ static int openssl_cms_read(lua_State *L
+   }
+   else if (fmt == FORMAT_SMIME)
+   {
+-    BIO *indata = load_bio_object(L, 3);
+-    cms = SMIME_read_CMS(in, &indata);
++    cms = SMIME_read_CMS(in, &data);
+   }
+ 
+   if (cms)
+   {
+     PUSH_OBJECT(cms, "openssl.cms");
+-    return 1;
++    if(data!=NULL)
++      PUSH_OBJECT(data, "openssl.bn");
++    return data!=NULL? 2 : 1;
+   }
+   return openssl_pushresult(L, 0);
+ }
+ 
++/***
++write cms object to bio object
+ 
++@function export
++@tparam cms cms
++@tparam[opt] bio data
++@tparam[opt=0] number flags
++@tparam[opt='smime'] string format
++@treturn string
++@return nil, and followed by error message
++*/
+ static int openssl_cms_write(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+-  BIO *out = load_bio_object(L, 2);
+-  BIO *in = load_bio_object(L, 3);
+-  int flags = luaL_optint(L, 4, 0);
+-  int fmt = luaL_checkoption(L, 5, "smime", format);
++  BIO *in = lua_isnoneornil(L, 2) ? NULL : load_bio_object(L, 2);
++  int flags = luaL_optint(L, 3, 0);
++  int fmt = luaL_checkoption(L, 4, "smime", format);
+   int ret = 0;
++  BIO *out = BIO_new(BIO_s_mem());
+ 
+   if (fmt == FORMAT_SMIME)
+     ret = SMIME_write_CMS(out, cms, in, flags);
+@@ -89,13 +134,45 @@ static int openssl_cms_write(lua_State *
+   else if (fmt == FORMAT_DER)
+   {
+     ret = i2d_CMS_bio_stream(out, cms, in, flags);
+-    //i2d_CMS_bio
+   }
+   else
+     luaL_argerror(L, 5, "only accept smime, pem or der");
++  if (ret==1)
++  {
++    BUF_MEM *mem;
++    BIO_get_mem_ptr(out, &mem);
++    lua_pushlstring(L, mem->data, mem->length);
++  }
++  if(in!=NULL)
++    BIO_free(in);
++  if(out!=NULL)
++    BIO_free(out);
++  if(ret==1)
++    return 1;
+   return openssl_pushresult(L, ret);
+ }
+-
++/***
++create empty cms object
++@function create
++@treturn cms
++*/
++
++/***
++create cms object from string or bio object
++@function create
++@tparam bio input
++@tparam[opt=0] number flags
++@treturn cms
++*/
++
++/***
++create digest cms object
++@function create
++@tparam bio input
++@tparam evp_digest|string md_alg
++@tparam[opt=0] number flags
++@treturn cms
++*/
+ static int openssl_cms_create(lua_State*L)
+ {
+   CMS_ContentInfo *cms = NULL;
+@@ -109,7 +186,7 @@ static int openssl_cms_create(lua_State*
+     BIO* in = load_bio_object(L, 1);
+     if (lua_isuserdata(L, 2))
+     {
+-      const EVP_MD* md = get_digest(L, 2);
++      const EVP_MD* md = get_digest(L, 2, NULL);
+       int flags = luaL_optint(L, 3, 0);
+       cms = CMS_digest_create(in, md, flags);
+     }
+@@ -124,7 +201,14 @@ static int openssl_cms_create(lua_State*
+   return 1;
+ }
+ 
+-
++/***
++create compress cms object
++@function compress
++@tparam bio input
++@tparam string alg, zlib or rle
++@tparam[opt=0] number flags
++@treturn cms
++*/
+ static int openssl_cms_compress(lua_State *L)
+ {
+   BIO* in = load_bio_object(L, 1);
+@@ -150,6 +234,15 @@ static int openssl_cms_compress(lua_Stat
+   return openssl_pushresult(L, 0);
+ }
+ 
++/***
++uncompress cms object
++@function uncompress
++@tparam cms cms
++@tparam bio input
++@tparam bio out
++@tparam[opt=0] number flags
++@treturn boolean
++*/
+ static int openssl_cms_uncompress(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+@@ -161,15 +254,26 @@ static int openssl_cms_uncompress(lua_St
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++make signed cms object
++
++@function sign
++@tparam x509 signer cert
++@tparam evp_pkey pkey
++@tparam bio input_data
++@tparam[opt] stack_of_x509 certs include in the CMS
++@tparam[opt=0] number flags
++@treturn cms object
++*/
+ static int openssl_cms_sign(lua_State *L)
+ {
+   X509* signcert = CHECK_OBJECT(1, X509, "openssl.x509");
+   EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-  STACK_OF(X509)* certs = openssl_sk_x509_fromtable(L, 3);
+-  BIO* data = load_bio_object(L, 4);
++  BIO* data = load_bio_object(L, 3);
++  STACK_OF(X509)* certs = openssl_sk_x509_fromtable(L, 4);
+   unsigned int flags = luaL_optint(L, 5, 0);
+   CMS_ContentInfo *cms;
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 2, "must be private key");
++
+   cms = CMS_sign(signcert, pkey, certs, data, flags);
+   if (cms)
+   {
+@@ -179,59 +283,62 @@ static int openssl_cms_sign(lua_State *L
+   return openssl_pushresult(L, 0);
+ }
+ 
++
++/***
++verfiy signed cms object
++@function verify
++@tparam cms signed
++@tparam stack_of_x509 signers
++@tparam[opt] x509_store store trust certificates store
++@tparam[opt] bio message
++@tparam[opt=0] number flags
++@treturn string content
++@return nil, and followed by error message
++*/
+ static int openssl_cms_verify(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+-  static const char* verify_mode[] =
+-  {
+-    "verify",  /* 0 */
+-    "digest",  /* 1 */
+-    "receipt",   /* 2 */
+-    NULL
+-  };
+-  int mode = luaL_checkoption(L, 2, NULL, verify_mode);
+-  if (mode == 1)
+-  {
+-    BIO* in = load_bio_object(L, 3);
+-    BIO* out = load_bio_object(L, 4);
+-    unsigned int flags = luaL_optint(L, 5, 0);
+-
+-    int ret = CMS_digest_verify(cms, in, out, flags);
+-    return openssl_pushresult(L, ret);
+-  }
+-  if (mode == 2)
+-  {
+-    CMS_ContentInfo *src = CHECK_OBJECT(3, CMS_ContentInfo, "openssl.cms");
+-    STACK_OF(X509) *other = openssl_sk_x509_fromtable(L, 4);
+-    X509_STORE* store = CHECK_OBJECT(5, X509_STORE, "openssl.x509_store");
+-    unsigned int flags = luaL_optint(L, 6, 0);
+-    int ret = CMS_verify_receipt(cms, src, other, store, flags);
+-    return openssl_pushresult(L, ret);
+-  }
+-  if (mode == 0)
+-  {
+-    STACK_OF(X509) *other = openssl_sk_x509_fromtable(L, 3);
+-    X509_STORE* store = CHECK_OBJECT(4, X509_STORE, "openssl.x509_store");
+-    BIO* in = load_bio_object(L, 5);
+-    BIO* out = load_bio_object(L, 6);
+-    unsigned int flags = luaL_optint(L, 7, 0);
+-    int ret = CMS_verify(cms, other, store, in, out, flags);
+-    return openssl_pushresult(L, ret);
+-  }
+-
+-  return 0;
+-}
+-
+-
++  STACK_OF(X509)* signers = openssl_sk_x509_fromtable(L, 2);
++  X509_STORE* trust = CHECK_OBJECT(3, X509_STORE, "openssl.x509_store");
++  BIO* in = lua_isnoneornil(L, 4) ? NULL : load_bio_object(L, 4);
++  unsigned int flags = luaL_optint(L, 5, 0);
++  BIO* out = BIO_new(BIO_s_mem());
++  int ret = CMS_verify(cms, signers, trust, in, out, flags);
++  if (ret==1)
++  {
++    BUF_MEM *mem;
++    BIO_get_mem_ptr(out, &mem);
++    lua_pushlstring(L, mem->data, mem->length);
++  }
++  if (in!=NULL)
++    BIO_free(in);
++  if (out!=NULL)
++    BIO_free(out);
++  if (ret !=1)
++    ret = openssl_pushresult(L, ret);
++  return ret;
++}
++
++/***
++create enryptdata cms
++@function EncryptedData_encrypt
++@tparam bio|string input
++@tparam strig key
++@tparam[opt='des-ede3-cbc'] string|evp_cipher cipher_alg
++@tparam[opt=0] number flags
++@treturn cms object
++@return nil, followed by error message
++*/
+ static int openssl_cms_EncryptedData_encrypt(lua_State*L)
+ {
+   BIO* in = load_bio_object(L, 1);
+-  const EVP_CIPHER* ciphers = get_cipher(L, 2, NULL);
+   size_t klen;
+-  const char* key = luaL_checklstring(L, 3, &klen);
++  const char* key = luaL_checklstring(L, 2, &klen);
++  const EVP_CIPHER* ciphers = get_cipher(L, 3, "des-ede3-cbc");
+   unsigned int flags = luaL_optint(L, 4, 0);
+ 
+   CMS_ContentInfo *cms = CMS_EncryptedData_encrypt(in, ciphers, (const unsigned char*) key, klen, flags);
++  BIO_free(in);
+   if (cms)
+   {
+     PUSH_OBJECT(cms, "openssl.cms");
+@@ -240,18 +347,92 @@ static int openssl_cms_EncryptedData_enc
+   return openssl_pushresult(L, 0);
+ }
+ 
++/***
++decrypt encryptdata cms
++@function EncryptedData_decrypt
++@tparam cms encrypted
++@tparam string key
++@tparam[opt] bio dcont
++@tparam[opt=0] number flags
++@treturn boolean result
++*/
+ static int openssl_cms_EncryptedData_decrypt(lua_State*L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+   size_t klen;
+   const char* key = luaL_checklstring(L, 2, &klen);
+-  BIO* dcont = load_bio_object(L, 3);
+-  BIO* out = load_bio_object(L, 4);
+-  unsigned int flags = luaL_optint(L, 5, 0);
++  BIO* dcont = lua_isnoneornil(L, 3) ? NULL : load_bio_object(L, 3);
++  unsigned int flags = luaL_optint(L, 4, 0);
++  BIO *out = BIO_new(BIO_s_mem());
+ 
+   int ret = CMS_EncryptedData_decrypt(cms, (const unsigned char*)key, klen, dcont, out, flags);
++  if(ret==1)
++  {
++    BUF_MEM *mem;
++    BIO_get_mem_ptr(out, &mem);
++    lua_pushlstring(L, mem->data, mem->length);
++  }
++  if(dcont!=NULL)
++    BIO_free(dcont);
++  BIO_free(out);
++  if(ret!=1)
++    ret = openssl_pushresult(L, ret);
++  return ret;
++}
++
++/***
++create digest cms
++@function digest_create
++@tparam bio|string input
++@tparam[opt='sha256'] string|evp_md digest_alg
++@tparam[opt=0] number flags
++@treturn cms object
++@return nil, followed by error message
++*/
++static int openssl_cms_digest_create(lua_State*L)
++{
++  BIO* in = load_bio_object(L, 1);
++  const EVP_MD* md = get_digest(L, 2, "sha256");
++  unsigned int flags = luaL_optint(L, 3, 0);
+ 
+-  return openssl_pushresult(L, ret);
++  CMS_ContentInfo *cms = CMS_digest_create(in, md, flags);
++  BIO_free(in);
++  if (cms)
++  {
++    PUSH_OBJECT(cms, "openssl.cms");
++    return 1;
++  }
++  return openssl_pushresult(L, 0);
++}
++
++/***
++verify digest cms
++@function digest_verify
++@tparam cms digested
++@tparam[opt] string|bio dcont
++@tparam[opt=0] number flags
++@treturn boolean result
++*/
++static int openssl_cms_digest_verify(lua_State*L)
++{
++  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
++  BIO *dcont = lua_isnoneornil(L, 2) ? NULL : load_bio_object(L, 2);
++  unsigned int flags = luaL_optint(L, 3, 0);
++  BIO *out = BIO_new(BIO_s_mem());
++
++  int ret = CMS_digest_verify(cms, dcont, out, flags);
++  if(ret==1)
++  {
++    BUF_MEM *mem;
++    BIO_get_mem_ptr(out, &mem);
++    lua_pushlstring(L, mem->data, mem->length);
++  }
++  if(dcont!=NULL)
++    BIO_free(dcont);
++  BIO_free(out);
++  if(ret!=1)
++    ret = openssl_pushresult(L, ret);
++  return ret;
+ }
+ 
+ static char *memdup(const char *src, size_t buffer_length)
+@@ -284,19 +465,31 @@ static char *memdup(const char *src, siz
+   return buffer;
+ }
+ 
++/***
++encrypt with recipt certs
++@function encrypt
++@tparam stack_of_x509 recipt certs
++@tparam bio|string input
++@tparam[opt='des-ede3-cbc'] string|evp_cipher cipher_alg
++@tparam[opt=0] number flags
++@tparam[opt=nil] table options, support key, keyid, password fields,
++  and values must be string type
++@treturn cms
++*/
+ static int openssl_cms_encrypt(lua_State *L)
+ {
+   STACK_OF(X509)* encerts = openssl_sk_x509_fromtable(L, 1);
+   BIO* in = load_bio_object(L, 2);
+-  const EVP_CIPHER* ciphers = get_cipher(L, 3, NULL);
++  const EVP_CIPHER* ciphers = get_cipher(L, 3, "des-ede3-cbc");
+   unsigned int flags = luaL_optint(L, 4, 0);
+-  int ret = 0;
+   CMS_ContentInfo *cms = CMS_encrypt(encerts, in, ciphers, flags);
+-  CMS_RecipientInfo *recipient;
++  int ret = 1;
+   if (cms)
+   {
+     if (lua_istable(L, 5))
+     {
++      CMS_RecipientInfo *recipient;
++
+       lua_getfield(L, 5, "key");
+       lua_getfield(L, 5, "keyid");
+       if (lua_isstring(L, -1) && lua_isstring(L, -2))
+@@ -358,19 +551,32 @@ static int openssl_cms_encrypt(lua_State
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++decrypt cms message
++@function decrypt
++@tparam cms message
++@tparam evp_pkey pkey
++@tparam x509 recipt
++@tparam[opt] bio dcount output object
++@tparam[opt=0] number flags
++@tparam[opt=nil] table options may have key, keyid, password field,
++  and values must be string type
++@treturn string decrypted message
++@return nil, and followed by error message
++*/
+ static int openssl_cms_decrypt(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+   EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+   X509* x509 = CHECK_OBJECT(3, X509, "openssl.x509");
+-  BIO* dcont = load_bio_object(L, 4);
+-  BIO* out = load_bio_object(L, 5);
+-  unsigned int flags = luaL_optint(L, 6, 0);
++  BIO* dcont = lua_isnoneornil(L, 4) ? NULL : load_bio_object(L, 4);
++  unsigned int flags = luaL_optint(L, 5, 0);
+   int ret = 1;
++  BIO* out = BIO_new(BIO_s_mem());
+ 
+-  if (lua_istable(L, 7))
++  if (lua_istable(L, 6))
+   {
+-    lua_getfield(L, 7, "password");
++    lua_getfield(L, 6, "password");
+     if (lua_isstring(L, -1))
+     {
+       unsigned char*passwd = (unsigned char*)lua_tostring(L, -1);
+@@ -383,8 +589,8 @@ static int openssl_cms_decrypt(lua_State
+     lua_pop(L, 1);
+     if (ret)
+     {
+-      lua_getfield(L, 7, "key");
+-      lua_getfield(L, 7, "keyid");
++      lua_getfield(L, 6, "key");
++      lua_getfield(L, 6, "keyid");
+       if (lua_isstring(L, -1) && lua_isstring(L, -2))
+       {
+         size_t keylen, keyidlen;
+@@ -394,30 +600,32 @@ static int openssl_cms_decrypt(lua_State
+       }
+       else if (!lua_isnil(L, -1) || !lua_isnil(L, -2))
+       {
+-        luaL_argerror(L, 7, "key and keyid field must be string");
++        luaL_argerror(L, 6, "key and keyid field must be string");
+       }
+       lua_pop(L, 2);
+     }
+   }
+ 
+   if (ret)
+-  {
+     ret = CMS_decrypt_set1_pkey(cms, pkey, x509);
+-  }
+ 
+   if (ret == 1)
+     ret = CMS_decrypt(cms, NULL, NULL, dcont, out, flags);
+-  return openssl_pushresult(L, ret);
+-}
+ 
++  if (ret == 1)
++  {
++    BUF_MEM *mem;
++    BIO_get_mem_ptr(out, &mem);
++    lua_pushlstring(L, mem->data, mem->length);
++  }
+ 
+-/************************************************************************/
+-static int openssl_cms_type(lua_State *L)
+-{
+-  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+-  const ASN1_OBJECT *obj = CMS_get0_type(cms);
+-  PUSH_OBJECT(obj, "openssl.object");
++  if (dcont!=NULL)
++    BIO_free(dcont);
++  if (out!=NULL)
++    BIO_free(out);
+ 
++  if (ret!=1)
++    return openssl_pushresult(L, ret);
+   return 1;
+ }
+ 
+@@ -430,24 +638,103 @@ static int openssl_cms_bio_new(lua_State
+   return 1;
+ }
+ 
++static const luaL_Reg R[] =
++{
++  {"read",                  openssl_cms_read},
++  {"write",                 openssl_cms_write},
++
++  {"bio_new",               openssl_cms_bio_new},
++  {"create",                openssl_cms_create},
++
++  {"sign",                  openssl_cms_sign},
++  {"verify",                openssl_cms_verify},
++  {"encrypt",               openssl_cms_encrypt},
++  {"decrypt",               openssl_cms_decrypt},
++
++  {"digest_create",         openssl_cms_digest_create},
++  {"digest_verify",         openssl_cms_digest_verify},
++  {"EncryptedData_encrypt", openssl_cms_EncryptedData_encrypt},
++  {"EncryptedData_decrypt", openssl_cms_EncryptedData_decrypt},
++  {"compress",              openssl_cms_compress},
++  {"uncompress",            openssl_cms_uncompress},
++
++  {NULL,  NULL}
++};
++
++/*****************************************************************************/
++/***
++openssl.cms object
++@type cms
++@warning some api undocumented, dangers!!!
++*/
++
++/***
++get type of cms object
++@function cms
++@treturn asn1_object type of cms
++*/
++static int openssl_cms_type(lua_State *L)
++{
++  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
++  const ASN1_OBJECT *obj = CMS_get0_type(cms);
++  PUSH_OBJECT(obj, "openssl.asn1_object");
++
++  return 1;
++}
++
++/***
++do dataInit
++@function datainit
++@tparam[opt] bio|string data
++@treturn bio cmsbio
++@return nil for fail
++@warning inner use
++*/
+ static int openssl_cms_datainit(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+-  BIO* icont = load_bio_object(L, 2);
+-  icont = CMS_dataInit(cms, icont);
+-  PUSH_OBJECT(icont, "openssl.bio");
++  BIO* icont = lua_isnoneornil(L, 2) ? NULL : load_bio_object(L, 2);
++  BIO* cbio = CMS_dataInit(cms, icont);
++  if(cbio!=NULL)
++    PUSH_OBJECT(icont, "openssl.bio");
++  else
++    lua_pushnil(L);
++  BIO_free(icont);
+   return 1;
+ }
+ 
++/***
++do dataFinal
++@function datafnal
++@tparam bio cmsbio bio returned by datainit
++@treturn boolean true for success, other value will followed by error message
++@warning inner use
++*/
+ static int openssl_cms_datafinal(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+   BIO* bio = load_bio_object(L, 2);
+   int ret = CMS_dataFinal(cms, bio);
+   lua_pushboolean(L, ret);
++  BIO_free(bio);
+   return 1;
+ }
+ 
++/***
++get detached state
++@function detached
++@treturn boolean true for detached
++@tparam bio cmsbio bio returned by datainit
++@treturn boolean true for success, others value will followed by error message
++@warning inner use
++*/
++/***
++set detached state
++@function detached
++@tparam boolean detach
++@treturn boolean for success, others value will followed by error message
++@warning inner use
++*/
+ static int openssl_cms_detached(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+@@ -455,29 +742,37 @@ static int openssl_cms_detached(lua_Stat
+   if (lua_isnone(L, 2))
+   {
+     ret = CMS_is_detached(cms);
++    lua_pushboolean(L, ret);
++    return 1;
+   }
+   else
+   {
+     int detached = auxiliar_checkboolean(L, 2);
+     ret = CMS_set_detached(cms, detached);
+   }
+-  lua_pushboolean(L, ret);
+   return 1;
+ }
+ 
++/***
++get content of cms object
++@function content
++@treturn string content, if have no content will return nil
++@warning inner use
++*/
+ static int openssl_cms_content(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+   ASN1_OCTET_STRING** content = CMS_get0_content(cms);
+   if (content && *content)
+   {
+-
+-    lua_pushnil(L);
+-    return 1;
++    ASN1_OCTET_STRING* s = *content;
++    lua_pushlstring(L, (const char*)ASN1_STRING_data(s), ASN1_STRING_length(s));
+   }
+-  lua_pushnil(L);
++  else
++    lua_pushnil(L);
+   return 1;
+ }
++
+ static int openssl_cms_get_signers(lua_State*L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+@@ -489,6 +784,7 @@ static int openssl_cms_get_signers(lua_S
+   }
+   return 0;
+ }
++
+ static int openssl_cms_data(lua_State *L)
+ {
+   CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
+@@ -541,47 +837,26 @@ static int openssl_cms_free(lua_State *L
+ 
+ static luaL_Reg cms_ctx_funs[] =
+ {
+-  {"type",  openssl_cms_type},
+-  {"datainit",  openssl_cms_datainit},
+-  {"datafinal", openssl_cms_datafinal},
+-  {"content", openssl_cms_content},
+-  {"data",  openssl_cms_data},
+-  {"signers", openssl_cms_get_signers},
+-
+-  {"detached",  openssl_cms_detached},
+-
+-  { "sign_receipt",  openssl_cms_sign_receipt},
+-  { "get_signers",   openssl_cms_get_signers},
+-
+-  { "bio_new",   openssl_cms_bio_new},
+-
+-  {"final", openssl_cms_final},
+-  {"__tostring",  auxiliar_tostring},
+-  {"__gc",    openssl_cms_free},
+-  {NULL, NULL}
++  {"type",          openssl_cms_type},
++  {"datainit",      openssl_cms_datainit},
++  {"datafinal",     openssl_cms_datafinal},
++  {"content",       openssl_cms_content},
++  {"data",          openssl_cms_data},
++  {"signers",       openssl_cms_get_signers},
++  {"detached",      openssl_cms_detached},
++
++  {"sign_receipt",  openssl_cms_sign_receipt},
++  {"get_signers",   openssl_cms_get_signers},
++
++  {"bio_new",       openssl_cms_bio_new},
++  {"final",         openssl_cms_final},
++
++  {"__tostring",    auxiliar_tostring},
++  {"__gc",          openssl_cms_free},
++  {NULL,            NULL}
+ };
+ 
+ /* int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms); */
+-static const luaL_Reg R[] =
+-{
+-  { "read",  openssl_cms_read},
+-  { "write",   openssl_cms_write},
+-
+-  { "bio_new", openssl_cms_bio_new},
+-  { "create", openssl_cms_create},
+-
+-  { "sign",  openssl_cms_sign},
+-  { "verify",  openssl_cms_verify},
+-  { "encrypt",   openssl_cms_encrypt},
+-  { "decrypt",   openssl_cms_decrypt},
+-
+-  { "EncryptedData_encrypt",   openssl_cms_EncryptedData_encrypt},
+-  { "EncryptedData_decrypt",   openssl_cms_EncryptedData_decrypt},
+-  { "compress",  openssl_cms_compress},
+-  { "uncompress",  openssl_cms_uncompress},
+-
+-  {NULL,  NULL}
+-};
+ #endif
+ 
+ int luaopen_cms(lua_State *L)
+@@ -593,9 +868,11 @@ int luaopen_cms(lua_State *L)
+ 
+   lua_newtable(L);
+   luaL_setfuncs(L, R, 0);
+-  lua_pushliteral(L, "version");    /** version */
++  lua_pushliteral(L, "version");
+   lua_pushliteral(L, MYVERSION);
+   lua_settable(L, -3);
++
++  auxiliar_enumerate(L, -1, cms_flags);
+ #else
+   lua_pushnil(L);
+ #endif
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/compat.c luvi-src-v2.7.6/deps/lua-openssl/src/compat.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/compat.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/compat.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,7 +1,533 @@
+-
+ #include <lua.h>
+ #include <lualib.h>
+ #include <lauxlib.h>
+ 
++#include "openssl.h"
++#include "private.h"
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++int BIO_up_ref(BIO *b)
++{
++  CRYPTO_add(&b->references, 1, CRYPTO_LOCK_BIO);
++  return 1;
++}
++int X509_up_ref(X509 *x)
++{
++  CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
++  return 1;
++}
++int X509_STORE_up_ref(X509_STORE *s)
++{
++  CRYPTO_add(&s->references, 1, CRYPTO_LOCK_X509_STORE);
++  return 1;
++}
++int EVP_PKEY_up_ref(EVP_PKEY *pkey)
++{
++  CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
++  return 1;
++}
++
++int RSA_bits(const RSA *r)
++{
++  return (BN_num_bits(r->n));
++}
++
++void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
++{
++  *pr = sig->r;
++  *ps = sig->s;
++}
++int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
++{
++  if (r == NULL || s == NULL)
++    return 0;
++  BN_free(sig->r);
++  BN_free(sig->s);
++  sig->r = r;
++  sig->s = s;
++  return 1;
++}
++void RSA_get0_key(const RSA *r,
++                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
++{
++  if (n != NULL)
++    *n = r->n;
++  if (e != NULL)
++    *e = r->e;
++  if (d != NULL)
++    *d = r->d;
++}
++
++void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
++{
++  if (p != NULL)
++    *p = r->p;
++  if (q != NULL)
++    *q = r->q;
++}
++
++void RSA_get0_crt_params(const RSA *r,
++                         const BIGNUM **dmp1, const BIGNUM **dmq1,
++                         const BIGNUM **iqmp)
++{
++  if (dmp1 != NULL)
++    *dmp1 = r->dmp1;
++  if (dmq1 != NULL)
++    *dmq1 = r->dmq1;
++  if (iqmp != NULL)
++    *iqmp = r->iqmp;
++}
++
++HMAC_CTX *HMAC_CTX_new(void)
++{
++  HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
++
++  if (ctx != NULL)
++  {
++    HMAC_CTX_init(ctx);
++  }
++  return ctx;
++}
++
++void HMAC_CTX_free(HMAC_CTX *ctx)
++{
++  if (ctx != NULL)
++  {
++    HMAC_CTX_cleanup(ctx);
++    OPENSSL_free(ctx);
++  }
++}
++
++#ifndef OPENSSL_NO_DSA
++DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
++{
++  if (pkey->type != EVP_PKEY_DSA)
++  {
++    return NULL;
++  }
++  return pkey->pkey.dsa;
++}
++
++int DSA_bits(const DSA *dsa)
++{
++  return BN_num_bits(dsa->p);
++}
++
++void DSA_get0_pqg(const DSA *d,
++                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
++{
++  if (p != NULL)
++    *p = d->p;
++  if (q != NULL)
++    *q = d->q;
++  if (g != NULL)
++    *g = d->g;
++}
++
++int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
++{
++  /* If the fields p, q and g in d are NULL, the corresponding input
++  * parameters MUST be non-NULL.
++  */
++  if ((d->p == NULL && p == NULL)
++      || (d->q == NULL && q == NULL)
++      || (d->g == NULL && g == NULL))
++    return 0;
++
++  if (p != NULL)
++  {
++    BN_free(d->p);
++    d->p = p;
++  }
++  if (q != NULL)
++  {
++    BN_free(d->q);
++    d->q = q;
++  }
++  if (g != NULL)
++  {
++    BN_free(d->g);
++    d->g = g;
++  }
++
++  return 1;
++}
++
++void DSA_get0_key(const DSA *d,
++                  const BIGNUM **pub_key, const BIGNUM **priv_key)
++{
++  if (pub_key != NULL)
++    *pub_key = d->pub_key;
++  if (priv_key != NULL)
++    *priv_key = d->priv_key;
++}
++
++int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
++{
++  /* If the field pub_key in d is NULL, the corresponding input
++  * parameters MUST be non-NULL.  The priv_key field may
++  * be left NULL.
++  */
++  if (d->pub_key == NULL && pub_key == NULL)
++    return 0;
++
++  if (pub_key != NULL)
++  {
++    BN_free(d->pub_key);
++    d->pub_key = pub_key;
++  }
++  if (priv_key != NULL)
++  {
++    BN_free(d->priv_key);
++    d->priv_key = priv_key;
++  }
++
++  return 1;
++}
++#endif
++
++#ifndef OPENSSL_NO_EC
++
++EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
++{
++  if (pkey->type != EVP_PKEY_EC)
++  {
++    return NULL;
++  }
++  return pkey->pkey.ec;
++}
++
++#endif
++
++#ifndef OPENSSL_NO_DH
++DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey)
++{
++  if (pkey->type != EVP_PKEY_DH)
++  {
++    return NULL;
++  }
++  return pkey->pkey.dh;
++}
++
++int DH_bits(const DH *dh)
++{
++  return BN_num_bits(dh->p);
++}
++
++void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
++{
++  if (pub_key != NULL)
++    *pub_key = dh->pub_key;
++  if (priv_key != NULL)
++    *priv_key = dh->priv_key;
++}
++
++int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
++{
++  /* If the field pub_key in dh is NULL, the corresponding input
++  * parameters MUST be non-NULL.  The priv_key field may
++  * be left NULL.
++  */
++  if (dh->pub_key == NULL && pub_key == NULL)
++    return 0;
++
++  if (pub_key != NULL)
++  {
++    BN_free(dh->pub_key);
++    dh->pub_key = pub_key;
++  }
++  if (priv_key != NULL)
++  {
++    BN_free(dh->priv_key);
++    dh->priv_key = priv_key;
++  }
++
++  return 1;
++}
++void DH_get0_pqg(const DH *dh,
++                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
++{
++  if (p != NULL)
++    *p = dh->p;
++  if (q != NULL)
++    *q = dh->q;
++  if (g != NULL)
++    *g = dh->g;
++}
++
++int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
++{
++  /* If the fields p and g in d are NULL, the corresponding input
++  * parameters MUST be non-NULL.  q may remain NULL.
++  */
++  if ((dh->p == NULL && p == NULL)
++      || (dh->g == NULL && g == NULL))
++    return 0;
++
++  if (p != NULL)
++  {
++    BN_free(dh->p);
++    dh->p = p;
++  }
++  if (q != NULL)
++  {
++    BN_free(dh->q);
++    dh->q = q;
++  }
++  if (g != NULL)
++  {
++    BN_free(dh->g);
++    dh->g = g;
++  }
++
++  if (q != NULL)
++  {
++    dh->length = BN_num_bits(q);
++  }
++
++  return 1;
++}
++#endif
++
++#ifndef OPENSSL_NO_RSA
++RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
++{
++  if (pkey->type != EVP_PKEY_RSA)
++  {
++    return NULL;
++  }
++  return pkey->pkey.rsa;
++}
++int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
++{
++  /* If the fields n and e in r are NULL, the corresponding input
++  * parameters MUST be non-NULL for n and e.  d may be
++  * left NULL (in case only the public key is used).
++  */
++  if ((r->n == NULL && n == NULL)
++      || (r->e == NULL && e == NULL))
++    return 0;
++
++  if (n != NULL)
++  {
++    BN_free(r->n);
++    r->n = n;
++  }
++  if (e != NULL)
++  {
++    BN_free(r->e);
++    r->e = e;
++  }
++  if (d != NULL)
++  {
++    BN_free(r->d);
++    r->d = d;
++  }
++
++  return 1;
++}
++
++int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
++{
++  /* If the fields p and q in r are NULL, the corresponding input
++  * parameters MUST be non-NULL.
++  */
++  if ((r->p == NULL && p == NULL)
++      || (r->q == NULL && q == NULL))
++    return 0;
++
++  if (p != NULL)
++  {
++    BN_free(r->p);
++    r->p = p;
++  }
++  if (q != NULL)
++  {
++    BN_free(r->q);
++    r->q = q;
++  }
++
++  return 1;
++}
++
++int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
++{
++  /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
++  * parameters MUST be non-NULL.
++  */
++  if ((r->dmp1 == NULL && dmp1 == NULL)
++      || (r->dmq1 == NULL && dmq1 == NULL)
++      || (r->iqmp == NULL && iqmp == NULL))
++    return 0;
++
++  if (dmp1 != NULL)
++  {
++    BN_free(r->dmp1);
++    r->dmp1 = dmp1;
++  }
++  if (dmq1 != NULL)
++  {
++    BN_free(r->dmq1);
++    r->dmq1 = dmq1;
++  }
++  if (iqmp != NULL)
++  {
++    BN_free(r->iqmp);
++    r->iqmp = iqmp;
++  }
++
++  return 1;
++}
++#endif
++
++EVP_MD_CTX *EVP_MD_CTX_new(void)
++{
++  return OPENSSL_malloc(sizeof(EVP_MD_CTX));
++}
++int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
++{
++  return EVP_MD_CTX_cleanup(ctx);
++}
++void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
++{
++  EVP_MD_CTX_cleanup(ctx);
++  OPENSSL_free(ctx);
++}
++
++void X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig,
++                             const X509_ALGOR **palg)
++{
++  if (psig != NULL)
++    *psig = req->signature;
++  if (palg != NULL)
++    *palg = req->sig_alg;
++}
++
++X509_PUBKEY *X509_REQ_get_X509_PUBKEY(X509_REQ *req)
++{
++  return req->req_info->pubkey;
++}
++
++const ASN1_INTEGER *X509_get0_serialNumber(const X509 *a)
++{
++  return a->cert_info->serialNumber;
++}
++
++const STACK_OF(X509_EXTENSION) *X509_get0_extensions(const X509 *x)
++{
++  return x->cert_info->extensions;
++}
++int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp)
++{
++  req->req_info->enc.modified = 1;
++  return i2d_X509_REQ_INFO(req->req_info, pp);
++}
++const ASN1_TIME *X509_REVOKED_get0_revocationDate(const X509_REVOKED *x)
++{
++  return x->revocationDate;
++}
++
++const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(const X509_REVOKED *x)
++{
++  return x->serialNumber;
++}
++
++const STACK_OF(X509_EXTENSION) *X509_REVOKED_get0_extensions(const X509_REVOKED *r)
++{
++  return r->extensions;
++}
++const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions(const X509_CRL *crl)
++{
++  return crl->crl->extensions;
++}
++
++void X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig,
++                             const X509_ALGOR **palg)
++{
++  if (psig != NULL)
++    *psig = crl->signature;
++  if (palg != NULL)
++    *palg = crl->sig_alg;
++}
++
++const ASN1_INTEGER *TS_STATUS_INFO_get0_status(const TS_STATUS_INFO *a)
++{
++  return a->status;
++}
++const STACK_OF(ASN1_UTF8STRING) *TS_STATUS_INFO_get0_text(const TS_STATUS_INFO *a)
++{
++  return a->text;
++}
++
++const ASN1_BIT_STRING *TS_STATUS_INFO_get0_failure_info(const TS_STATUS_INFO *a)
++{
++  return a->failure_info;
++}
++
++#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
++int i2d_re_X509_tbs(X509 *x, unsigned char **pp)
++{
++  x->cert_info->enc.modified = 1;
++  return i2d_X509_CINF(x->cert_info, pp);
++}
++
++#if !defined(LIBRESSL_VERSION_NUMBER)
++void X509_get0_signature(CONSTIFY_X509_get0 ASN1_BIT_STRING **psig,
++                         CONSTIFY_X509_get0 X509_ALGOR **palg,
++                         const X509 *x)
++{
++  if (psig)
++    *psig = x->signature;
++  if (palg)
++    *palg = x->sig_alg;
++}
++#endif
++
++int X509_get_signature_nid(const X509 *x)
++{
++  return OBJ_obj2nid(x->sig_alg->algorithm);
++}
++
++#endif /* < 1.0.2 */
++
++
++int TS_VERIFY_CTX_add_flags(TS_VERIFY_CTX *ctx, int f)
++{
++  ctx->flags |= f;
++  return ctx->flags;
++}
++
++int TS_VERIFY_CTX_set_flags(TS_VERIFY_CTX *ctx, int f)
++{
++  ctx->flags = f;
++  return ctx->flags;
++}
++
++BIO *TS_VERIFY_CTX_set_data(TS_VERIFY_CTX *ctx, BIO *b)
++{
++  ctx->data = b;
++  return ctx->data;
++}
++
++X509_STORE *TS_VERIFY_CTX_set_store(TS_VERIFY_CTX *ctx, X509_STORE *s)
++{
++  ctx->store = s;
++  return ctx->store;
++}
++
++STACK_OF(X509) *TS_VERIFY_CTS_set_certs(TS_VERIFY_CTX *ctx,
++                                        STACK_OF(X509) *certs)
++{
++  ctx->certs = certs;
++  return ctx->certs;
++}
++
++unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx,
++    unsigned char *hexstr, long len)
++{
++  ctx->imprint = hexstr;
++  ctx->imprint_len = len;
++  return ctx->imprint;
++}
+ 
+-#include "lua-compat/c-api/compat-5.3.c"
++#endif /* < 1.1.0 */
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/config.ld luvi-src-v2.7.6/deps/lua-openssl/src/config.ld
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/config.ld	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/config.ld	2019-02-13 11:53:24.275126573 +0100
+@@ -0,0 +1,9 @@
++project='lua-openssl'
++title='lua-openssl Docmentation'
++description='Openssl binding for Lua'
++format='discount'
++backtick_references=false
++dir='doc'
++readme='README.md'
++style='!pale'
++kind_names={topic='Manual',script='Programs'}
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/crl.c luvi-src-v2.7.6/deps/lua-openssl/src/crl.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/crl.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/crl.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,9 +1,10 @@
+-/*=========================================================================*\
+-* crl.c
+-* X509 certificate revoke routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++x509.crl module for lua-openssl binding, provide x509_crl as lua object.
++create and manage x509 certificate sign request
++@module x509.crl
++@usage
++  crl = require'openssl'.x509.crl
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #define CRYPTO_LOCK_REF
+@@ -13,18 +14,33 @@
+ int   X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b);
+ int   X509_CRL_match(const X509_CRL *a, const X509_CRL *b);
+ 
++#ifndef CRL_REASON_NONE
++#define CRL_REASON_NONE                         -1;
++#define CRL_REASON_UNSPECIFIED                  0
++#define CRL_REASON_KEY_COMPROMISE               1
++#define CRL_REASON_CA_COMPROMISE                2
++#define CRL_REASON_AFFILIATION_CHANGED          3
++#define CRL_REASON_SUPERSEDED                   4
++#define CRL_REASON_CESSATION_OF_OPERATION       5
++#define CRL_REASON_CERTIFICATE_HOLD             6
++#define CRL_REASON_REMOVE_FROM_CRL              8
++#define CRL_REASON_PRIVILEGE_WITHDRAWN          9
++#define CRL_REASON_AA_COMPROMISE                10
++#endif
++
+ static const BIT_STRING_BITNAME reason_flags[] =
+ {
+-  {0, "Unused", "unused"},
+-  {1, "Key Compromise", "keyCompromise"},
+-  {2, "CA Compromise", "CACompromise"},
+-  {3, "Affiliation Changed", "affiliationChanged"},
+-  {4, "Superseded", "superseded"},
+-  {5, "Cessation Of Operation", "cessationOfOperation"},
+-  {6, "Certificate Hold", "certificateHold"},
+-  {7, "Privilege Withdrawn", "privilegeWithdrawn"},
+-  {8, "AA Compromise", "AACompromise"},
+-  { -1, NULL, NULL}
++  { CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"},
++  { CRL_REASON_KEY_COMPROMISE,      "Key Compromise", "keyCompromise" },
++  { CRL_REASON_CA_COMPROMISE,       "CA Compromise", "CACompromise" },
++  { CRL_REASON_AFFILIATION_CHANGED, "Affiliation Changed", "affiliationChanged" },
++  { CRL_REASON_SUPERSEDED,          "Superseded", "superseded" },
++  { CRL_REASON_CESSATION_OF_OPERATION, "Cessation Of Operation", "cessationOfOperation" },
++  { CRL_REASON_CERTIFICATE_HOLD,    "Certificate Hold", "certificateHold" },
++  { CRL_REASON_REMOVE_FROM_CRL,     "Remove From CRL", "removeFromCRL" },
++  { CRL_REASON_PRIVILEGE_WITHDRAWN, "Privilege Withdrawn", "privilegeWithdrawn" },
++  { CRL_REASON_AA_COMPROMISE,       "AA Compromise", "AACompromise" },
++  { -1, NULL, NULL }
+ };
+ 
+ static const int reason_num = sizeof(reason_flags) / sizeof(BIT_STRING_BITNAME) - 1;
+@@ -76,6 +92,16 @@ static int reason_get(lua_State*L, int r
+   return reason;
+ }
+ 
++static int openssl_x509_revoked_get_reason(X509_REVOKED *revoked)
++{
++  int crit = 0;
++  int reason;
++  ASN1_ENUMERATED *areason = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason, &crit, NULL);
++  reason = (crit == -1) ? CRL_REASON_NONE : ASN1_ENUMERATED_get(areason);
++  ASN1_ENUMERATED_free(areason);
++  return reason;
++}
++
+ static X509_REVOKED *create_revoked(const BIGNUM* bn, time_t t, int reason)
+ {
+   X509_REVOKED *revoked = X509_REVOKED_new();
+@@ -86,9 +112,7 @@ static X509_REVOKED *create_revoked(cons
+ 
+   X509_REVOKED_set_revocationDate(revoked, tm);
+   X509_REVOKED_set_serialNumber(revoked, it);
+-#if OPENSSL_VERSION_NUMBER > 0x10000000L
+-  revoked->reason = reason;
+-#else
++
+   {
+     ASN1_ENUMERATED * e = ASN1_ENUMERATED_new();
+     X509_EXTENSION * ext = X509_EXTENSION_new();
+@@ -102,57 +126,44 @@ static X509_REVOKED *create_revoked(cons
+     X509_EXTENSION_free(ext);
+     ASN1_ENUMERATED_free(e);
+   }
+-#endif
++
+   ASN1_TIME_free(tm);
+   ASN1_INTEGER_free(it);
+ 
+   return revoked;
+ }
+ 
+-static LUA_FUNCTION(openssl_crl_add_revocked)
++static int openssl_revoked2table(lua_State*L, X509_REVOKED *revoked)
+ {
+-  X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+-  BIGNUM* sn = BN_get(L, 2);
+-  time_t t = lua_tointeger(L, 3);
+-  int reason = reason_get(L, 4);
++  int reason = openssl_x509_revoked_get_reason(revoked);
++  lua_newtable(L);
++  AUXILIAR_SET(L, -1, "code", reason, number);
++  AUXILIAR_SET(L, -1, "reason", openssl_i2s_revoke_reason(reason), string);
+ 
+-  int ret = 0;
+-  X509_REVOKED* revoked = create_revoked(sn, t, reason);
+-  ret = X509_CRL_add0_revoked(crl, revoked);
+-  lua_pushboolean(L, ret);
+-  BN_free(sn);
+-  return 1;
+-}
++  PUSH_ASN1_INTEGER(L, X509_REVOKED_get0_serialNumber(revoked));
++  lua_setfield(L, -2, "serialNumber");
+ 
+-static int openssl_crl_extensions(lua_State* L)
+-{
+-  X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+-  if (lua_isnone(L, 2))
+-  {
+-    STACK_OF(X509_EXTENSION) *exts = crl->crl->extensions;
+-    if (exts)
+-    {
+-      openssl_sk_x509_extension_totable(L, exts);
+-    }
+-    else
+-      lua_pushnil(L);
+-    return 1;
+-  }
+-  else
+-  {
+-    STACK_OF(X509_EXTENSION) *exts = openssl_sk_x509_extension_fromtable(L, 2);
+-    int i, n;
+-    n = sk_X509_EXTENSION_num(exts);
+-    for (i = 0; i < n; i++)
+-    {
+-      X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+-      X509_CRL_add_ext(crl, X509_EXTENSION_dup(ext), i);
+-    };
+-    sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+-    return openssl_pushresult(L, 1);
+-  }
++  PUSH_ASN1_TIME(L, X509_REVOKED_get0_revocationDate(revoked));
++  lua_setfield(L, -2, "revocationDate");
++
++  lua_pushstring(L, "extensions");
++  openssl_sk_x509_extension_totable(L, X509_REVOKED_get0_extensions(revoked));
++  lua_rawset(L, -3);
++  return 1;
+ }
+ 
++/***
++create or generate a new x509_crl object.
++Note if not give evp_pkey, will create a new x509_crl object,if give will generate a signed x509_crl object.
++@function new
++@tparam[opt] table revoked_list
++@tparam[opt] x509 cacert ca cert to sign x509_crl
++@tparam[opt] evp_pkey capkey private key to sign x509_crl
++@tparam[opt] string|evp_md md_alg
++@tparam[opt=7*24*3600] number period to generate new crl
++@treturn x509_crl object
++@see x509_crl
++*/
+ static LUA_FUNCTION(openssl_crl_new)
+ {
+   int i;
+@@ -208,7 +219,7 @@ static LUA_FUNCTION(openssl_crl_new)
+       luaL_argcheck(L, X509_check_private_key(cacert, capkey) == 1, 3, "evp_pkey not match with x509 in #2");
+     }
+   }
+-  md = lua_isnoneornil(L, 4) ? EVP_get_digestbyname("sha1") : get_digest(L, 4);
++  md = get_digest(L, 4, "sha256");;
+   step = lua_isnoneornil(L, 5) ? 7 * 24 * 3600 : luaL_checkint(L, 5);
+ 
+   if (ret == 1)
+@@ -247,6 +258,14 @@ static LUA_FUNCTION(openssl_crl_new)
+   return 1;
+ }
+ 
++/***
++read x509_crl from string or bio input
++@function read
++@tparam bio|string input input data
++@tparam[opt='auto'] string format support 'auto','pem','der'
++@treturn x509_crl certificate sign request object
++@see x509_crl
++*/
+ static LUA_FUNCTION(openssl_crl_read)
+ {
+   BIO * in = load_bio_object(L, 1);
+@@ -261,12 +280,12 @@ static LUA_FUNCTION(openssl_crl_read)
+   if (fmt == FORMAT_PEM)
+   {
+     crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+-    BIO_reset(in);
++    (void)BIO_reset(in);
+   }
+   else if (fmt == FORMAT_DER)
+   {
+     crl = d2i_X509_CRL_bio(in, NULL);
+-    BIO_reset(in);
++    (void)BIO_reset(in);
+   }
+   BIO_free(in);
+   if (crl)
+@@ -277,6 +296,44 @@ static LUA_FUNCTION(openssl_crl_read)
+   return openssl_pushresult(L, 0);
+ }
+ 
++/***
++list all support reason info
++@function reason
++@treturn table contain support reason node like {lname=...,sname=...,bitnum=...}
++*/
++static int openssl_crl_reason(lua_State *L)
++{
++  int i;
++  const BIT_STRING_BITNAME* bitname;
++  lua_newtable(L);
++  for (i = 0, bitname = &reason_flags[i]; bitname->bitnum != -1; i++, bitname = &reason_flags[i])
++  {
++    openssl_push_bit_string_bitname(L, bitname);
++    lua_rawseti(L, -2, i + 1);
++  }
++  return 1;
++}
++
++static luaL_Reg R[] =
++{
++  {"new",       openssl_crl_new },
++  {"read",      openssl_crl_read},
++  {"reason",    openssl_crl_reason},
++
++  {NULL,    NULL}
++};
++
++/***
++openssl.x509_crl object
++@type x509_crl
++*/
++
++/***
++set version key
++@function version
++@tparam integer version
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_crl_version)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -293,6 +350,80 @@ static LUA_FUNCTION(openssl_crl_version)
+   }
+ }
+ 
++/***
++add revoked entry to x509_crl object
++@function add
++@tparam string|number|bn serial
++@tparam number revokedtime
++@tparam[opt=0] number|string reason
++@treturn boolean result true for add success
++*/
++static LUA_FUNCTION(openssl_crl_add_revocked)
++{
++  X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
++  BIGNUM* sn = BN_get(L, 2);
++  time_t t = lua_tointeger(L, 3);
++  int reason = reason_get(L, 4);
++
++  int ret = 0;
++  X509_REVOKED* revoked = create_revoked(sn, t, reason);
++  ret = X509_CRL_add0_revoked(crl, revoked);
++  lua_pushboolean(L, ret);
++  BN_free(sn);
++  return 1;
++}
++
++/***
++get extensions of x509_crl
++@function extensions
++@treturn stack_of_x509_extension extensions
++*/
++/***
++set extensions to x509_crl object
++@function extensions
++@tparam stack_of_x509_extension extensions add to x509_crl
++@treturn boolean result
++*/
++static int openssl_crl_extensions(lua_State* L)
++{
++  X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
++  if (lua_isnone(L, 2))
++  {
++    const STACK_OF(X509_EXTENSION) *exts = X509_CRL_get0_extensions(crl);
++    if (exts)
++    {
++      openssl_sk_x509_extension_totable(L, exts);
++    }
++    else
++      lua_pushnil(L);
++    return 1;
++  }
++  else
++  {
++    STACK_OF(X509_EXTENSION) *exts = (STACK_OF(X509_EXTENSION) *)openssl_sk_x509_extension_fromtable(L, 2);
++    int i, n;
++    n = sk_X509_EXTENSION_num(exts);
++    for (i = 0; i < n; i++)
++    {
++      X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
++      X509_CRL_add_ext(crl, X509_EXTENSION_dup(ext), i);
++    };
++    sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
++    return openssl_pushresult(L, 1);
++  }
++}
++
++/***
++get issuer x509_name object
++@function issuer
++@treturn x509_name
++*/
++/***
++set issuer x509_name object
++@function issuer
++@tparam x509_name|x509 issuer
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_crl_issuer)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -300,13 +431,13 @@ static LUA_FUNCTION(openssl_crl_issuer)
+   {
+     return openssl_push_xname_asobject(L, X509_CRL_get_issuer(crl));
+   }
+-  else if (auxiliar_isclass(L, "openssl.x509_name", 2))
++  else if (auxiliar_getclassudata(L, "openssl.x509_name", 2))
+   {
+     X509_NAME* xn = CHECK_OBJECT(2, X509_NAME, "openssl.x509_name");
+     int ret = X509_CRL_set_issuer_name(crl, xn);
+     return openssl_pushresult(L, ret);
+   }
+-  else if (auxiliar_isclass(L, "openssl.x509", 2))
++  else if (auxiliar_getclassudata(L, "openssl.x509", 2))
+   {
+     X509* x = CHECK_OBJECT(2, X509, "openssl.x509");
+     int ret = X509_CRL_set_issuer_name(crl, X509_get_issuer_name(x));
+@@ -319,6 +450,17 @@ static LUA_FUNCTION(openssl_crl_issuer)
+   return 0;
+ }
+ 
++/***
++get lastUpdate time
++@function lastUpdate
++@treturn string lastUpdate
++*/
++/***
++set lastUpdate time
++@function lastUpdate
++@tparam number lastUpdate
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_crl_lastUpdate)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -341,6 +483,17 @@ static LUA_FUNCTION(openssl_crl_lastUpda
+   }
+ }
+ 
++/***
++get nextUpdate time
++@function nextUpdate
++@treturn string nextUpdate
++*/
++/***
++set nextUpdate time
++@function nextUpdate
++@tparam number nextUpdate
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_crl_nextUpdate)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -363,6 +516,18 @@ static LUA_FUNCTION(openssl_crl_nextUpda
+   }
+ }
+ 
++/***
++get updateTime time
++@function updateTime
++@treturn string lastUpdate
++*/
++/***
++set updateTime time
++@function updateTime
++@tparam[opt=os.time()] lastUpdate, default use current time
++@tparam number periord periord how long time(seconds)
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_crl_updateTime)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -408,6 +573,11 @@ static LUA_FUNCTION(openssl_crl_updateTi
+   }
+ }
+ 
++/***
++sore crl entry in x509_crl object
++@function sort
++@treturn boolean result true for success and others for fail
++*/
+ static LUA_FUNCTION(openssl_crl_sort)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -415,33 +585,61 @@ static LUA_FUNCTION(openssl_crl_sort)
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++verify x509_crl object signature
++@function verify
++@tparam x509|evp_pkey key ca cert or public to verify signature
++@treturn boolean result true for success and others for fail
++*/
+ static LUA_FUNCTION(openssl_crl_verify)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+-  X509* cacert = CHECK_OBJECT(2, X509, "openssl.x509");
++  EVP_PKEY *pub = NULL;
++  int ret;
++  luaL_argcheck(L,
++                auxiliar_getclassudata(L, "openssl.x509", 2) ||
++                auxiliar_getclassudata(L, "openssl.evp_pkey", 2),
++                2,
++                "must be x509 or evp_pkey object");
++  if (auxiliar_getclassudata(L, "openssl.evp_pkey", 2))
++  {
++    pub = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
++    ret = X509_CRL_verify(crl, pub);
++  }
++  else
++  {
++    X509* cacert = CHECK_OBJECT(2, X509, "openssl.x509");
++    pub = X509_get_pubkey(cacert);
++    ret = X509_CRL_verify(crl, pub);
++    EVP_PKEY_free(pub);
++  }
+ 
+-  int ret = X509_CRL_verify(crl, cacert->cert_info->key->pkey);
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++sign x509_crl
++@function sign
++@tparam evp_pkey pkey private key to sign x509
++@tparam x509|x509_name cacert or cacert x509_name
++@tparam[opt='sha1WithRSAEncryption'] string|md_digest md_alg
++@treturn boolean result true for check pass
++*/
+ LUA_FUNCTION(openssl_crl_sign)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+   EVP_PKEY *key = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-  const EVP_MD *md = lua_isnoneornil(L, 4)
+-                     ? EVP_get_digestbyname("sha1") : get_digest(L, 4);
+-
++  const EVP_MD *md = get_digest(L, 4, "sha256");
+   int ret = 1;
+ 
+-  luaL_argcheck(L, openssl_pkey_is_private(key), 2, "must be private key");
+-  luaL_argcheck(L, auxiliar_isclass(L, "openssl.x509", 3) || auxiliar_isclass(L, "openssl.x509_name", 3),
++  luaL_argcheck(L, auxiliar_getclassudata(L, "openssl.x509", 3) || auxiliar_getclassudata(L, "openssl.x509_name", 3),
+                 3, "must be openssl.x509 or openssl.x509_name object");
+-  if (auxiliar_isclass(L, "openssl.x509_name", 3))
++  if (auxiliar_getclassudata(L, "openssl.x509_name", 3))
+   {
+     X509_NAME* xn = CHECK_OBJECT(3, X509_NAME, "openssl.x509_name");
+     ret = X509_CRL_set_issuer_name(crl, xn);
+   }
+-  else if (auxiliar_isclass(L, "openssl.x509", 3))
++  else if (auxiliar_getclassudata(L, "openssl.x509", 3))
+   {
+     X509* ca = CHECK_OBJECT(3, X509, "openssl.x509");
+     ret = X509_CRL_set_issuer_name(crl, X509_get_issuer_name(ca));
+@@ -461,13 +659,18 @@ LUA_FUNCTION(openssl_crl_sign)
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get digest of x509_crl
++@function digest
++@tparam[opt='SHA1'] evp_md|string md_alg default use sha1
++@treturn string digest result
++*/
+ static LUA_FUNCTION(openssl_crl_digest)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+   byte buf[EVP_MAX_MD_SIZE];
+   unsigned int lbuf = sizeof(buf);
+-  const EVP_MD *md = lua_isnoneornil(L, 2)
+-                     ? EVP_get_digestbyname("sha1") : get_digest(L, 2);
++  const EVP_MD *md = get_digest(L, 2, "sha256");
+ 
+   int ret =  X509_CRL_digest(crl, md, buf, &lbuf);
+   if (ret == 1)
+@@ -478,6 +681,14 @@ static LUA_FUNCTION(openssl_crl_digest)
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++compare with other x509_crl object
++@function cmp
++@tparam x509_crl other
++@treturn boolean result true for equals or false
++@usage
++  x:cmp(y) == (x==y)
++*/
+ static LUA_FUNCTION(openssl_crl_cmp)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -488,17 +699,24 @@ static LUA_FUNCTION(openssl_crl_cmp)
+ }
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER)
++/***
++make a delta x509_crl object
++@function diff
++@tparam x509_crl newer
++@tparam evp_pkey pkey
++@tparam[opt='sha1'] evp_md|string md_alg
++@tparam[opt=0] integer flags
++@treturn x509_crl delta result x509_crl object
++*/
+ static LUA_FUNCTION(openssl_crl_diff)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+   X509_CRL *newer = CHECK_OBJECT(2, X509_CRL, "openssl.x509_crl");
+   EVP_PKEY* pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
+-  const EVP_MD *md = lua_isnoneornil(L, 4)
+-                     ? EVP_get_digestbyname("sha1") : get_digest(L, 4);
++  const EVP_MD *md = get_digest(L, 4, "sha256");
+   unsigned int flags = luaL_optinteger(L, 5, 0);
+   X509_CRL *diff;
+ 
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 3, "must be private key");
+   diff  =  X509_CRL_diff(crl, newer, pkey, md, flags);
+   if (diff)
+   {
+@@ -508,22 +726,35 @@ static LUA_FUNCTION(openssl_crl_diff)
+     lua_pushnil(L);
+   return 1;
+ }
++
++/***
++check x509_crl with evp_pkey
++@function check
++@tparam evp_pkey pkey
++@tparam[opt=0] integer flags 
++@treturn boolean result true for pass
++*/
+ static LUA_FUNCTION(openssl_crl_check)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+   EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+   unsigned long flags = luaL_optinteger(L, 3, X509_V_FLAG_SUITEB_128_LOS);
+-  int ret;
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 2, "must be private key");
+-  ret  =  X509_CRL_check_suiteb(crl, pkey, flags);
++  int ret  =  X509_CRL_check_suiteb(crl, pkey, flags);
+   return openssl_pushresult(L, ret == X509_V_OK);
+ }
+ #endif
+ 
++/***
++parse x509_crl object as table
++@function parse
++@tparam[opt=true] shortname default will use short object name
++@treturn table result
++*/
+ static LUA_FUNCTION(openssl_crl_parse)
+ {
+   X509_CRL *crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+   int num, i;
++  const X509_ALGOR *alg;
+ 
+   lua_newtable(L);
+   AUXILIAR_SET(L, -1, "version", X509_CRL_get_version(crl), integer);
+@@ -536,7 +767,7 @@ static LUA_FUNCTION(openssl_crl_parse)
+   }
+ 
+   {
+-    const EVP_MD *digest = EVP_get_digestbyname("sha1");
++    const EVP_MD *digest = EVP_get_digestbyname("sha256");
+     unsigned char md[EVP_MAX_MD_SIZE];
+     unsigned int l = sizeof(md);
+ 
+@@ -558,58 +789,50 @@ static LUA_FUNCTION(openssl_crl_parse)
+   PUSH_ASN1_TIME(L, X509_CRL_get_nextUpdate(crl));
+   lua_setfield(L, -2, "nextUpdate");
+ 
+-  openssl_push_x509_algor(L, crl->crl->sig_alg);
+-  lua_setfield(L, -2, "sig_alg");
+-
+-#if OPENSSL_VERSION_NUMBER > 0x00909000L
+-  if (crl->crl_number)
+   {
+-    PUSH_ASN1_INTEGER(L, crl->crl_number);
+-    lua_setfield(L, -2, "crl_number");
++    const ASN1_BIT_STRING *sig = NULL;
++    const X509_ALGOR *sig_alg = NULL;
++
++    X509_CRL_get0_signature(crl, &sig, &alg);
++    PUSH_OBJECT(sig_alg, "openssl.x509_algor");
++    lua_setfield(L, -2, "sig_alg");
++    PUSH_ASN1_STRING(L, sig);
++    lua_setfield(L, -2, "signature");
+   }
+-#endif
+-  if (crl->crl->extensions)
+   {
+-    lua_pushstring(L, "extensions");
+-    openssl_sk_x509_extension_totable(L, crl->crl->extensions);
+-    lua_rawset(L, -3);
++    ASN1_INTEGER *crl_number = X509_CRL_get_ext_d2i(crl, NID_crl_number, NULL, NULL);
++    if (crl_number)
++    {
++      PUSH_ASN1_INTEGER(L, crl_number);
++      lua_setfield(L, -2, "crl_number");
++    }
+   }
+-
+-  num = sk_X509_REVOKED_num(crl->crl->revoked);
+-  lua_newtable(L);
+-  for (i = 0; i < num; i++)
+   {
+-    X509_REVOKED *revoked = sk_X509_REVOKED_value(crl->crl->revoked, i);
+-    lua_newtable(L);
+-
+-#if OPENSSL_VERSION_NUMBER > 0x10000000L
+-    AUXILIAR_SET(L, -1, "CRLReason", openssl_i2s_revoke_reason(revoked->reason), string);
+-#else
++    const STACK_OF(X509_EXTENSION) *extensions = X509_CRL_get0_extensions(crl);
++    if (extensions)
+     {
+-      int crit = 0;
+-      void* reason = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason, &crit, NULL);
+-
+-      AUXILIAR_SET(L, -1, "CRLReason", openssl_i2s_revoke_reason(ASN1_ENUMERATED_get(reason)), string);
+-      ASN1_ENUMERATED_free(reason);
++      openssl_sk_x509_extension_totable(L, extensions);
++      lua_setfield(L, -2, "extensions");
+     }
+-#endif
+-    PUSH_ASN1_INTEGER(L, revoked->serialNumber);
+-    lua_setfield(L, -2, "serialNumber");
+-
+-    PUSH_ASN1_TIME(L, revoked->revocationDate);
+-    lua_setfield(L, -2, "revocationDate");
++  }
+ 
+-    if (crl->crl->extensions)
++  {
++    STACK_OF(X509_REVOKED) *revokeds = X509_CRL_get_REVOKED(crl);
++    if (revokeds)
+     {
+-      lua_pushstring(L, "extensions");
+-      openssl_sk_x509_extension_totable(L, crl->crl->extensions);
+-      lua_rawset(L, -3);
+-    }
++      num = sk_X509_REVOKED_num(revokeds);
++      lua_newtable(L);
++      for (i = 0; i < num; i++)
++      {
++        X509_REVOKED *revoked = sk_X509_REVOKED_value(revokeds, i);
++        openssl_revoked2table(L, revoked);
++        lua_rawseti(L, -2, i + 1);
++      }
+ 
+-    lua_rawseti(L, -2, i + 1);
++      lua_setfield(L, -2, "revoked");
++    }
+   }
+ 
+-  lua_setfield(L, -2, "revoked");
+   return 1;
+ }
+ 
+@@ -620,6 +843,13 @@ static LUA_FUNCTION(openssl_crl_free)
+   return 0;
+ }
+ 
++/***
++export x509_crl to string
++@function export
++@tparam[opt='pem'] string format
++@tparam[opt='true'] boolean noext not export extension
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_crl_export)
+ {
+   X509_CRL * crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+@@ -663,49 +893,57 @@ static LUA_FUNCTION(openssl_crl_export)
+   return 1;
+ }
+ 
+-
++/***
++get count of revoked entry
++@function count
++@treturn number count
++@usage
++  assert(#crl==crl:count())
++*/
+ static LUA_FUNCTION(openssl_crl_count)
+ {
+   X509_CRL * crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+-  int n = sk_X509_REVOKED_num(crl->crl->revoked);
++  STACK_OF(X509_REVOKED) *revokeds = X509_CRL_get_REVOKED(crl);
++  int n = revokeds ? sk_X509_REVOKED_num(revokeds) : 0;
+   lua_pushinteger(L, n);
+   return 1;
+ }
+ 
++/***
++get revoekd entry
++@function get
++@tparam number index
++@treturn table revoekd 
++*/
+ static LUA_FUNCTION(openssl_crl_get)
+ {
+   X509_CRL * crl = CHECK_OBJECT(1, X509_CRL, "openssl.x509_crl");
+-  int i = luaL_checkint(L, 2);
+-  if (i >= 0 && i < sk_X509_REVOKED_num(crl->crl->revoked))
++  STACK_OF(X509_REVOKED) *revokeds = X509_CRL_get_REVOKED(crl);
++  X509_REVOKED *revoked = NULL;
++  int i = 0;
++  if (lua_isinteger(L, 2))
++  {
++    i = lua_tointeger(L, 2);
++    luaL_argcheck(L, (i >= 0 && i < sk_X509_REVOKED_num(revokeds)), 2, "Out of range");
++    revoked = sk_X509_REVOKED_value(revokeds, i);
++  }
++  else
+   {
+-    X509_REVOKED *revoked = sk_X509_REVOKED_value(crl->crl->revoked, i);
+-
+-    lua_newtable(L);
+-
+-#if OPENSSL_VERSION_NUMBER > 0x10000000L
+-    AUXILIAR_SET(L, -1, "reason", openssl_i2s_revoke_reason(revoked->reason), string);
+-#else
+-    {
+-      int crit = 0;
+-      void* reason = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason, &crit, NULL);
+-
+-      AUXILIAR_SET(L, -1, "reason", openssl_i2s_revoke_reason(ASN1_ENUMERATED_get(reason)), string);
+-      ASN1_ENUMERATED_free(reason);
+-    }
+-#endif
+-    PUSH_ASN1_INTEGER(L, revoked->serialNumber);
+-    lua_setfield(L, -2, "serialNumber");
+-
+-    PUSH_ASN1_TIME(L, revoked->revocationDate);
+-    lua_setfield(L, -2, "revocationDate");
+-
+-    if (crl->crl->extensions)
++    ASN1_STRING *sn = CHECK_OBJECT(2, ASN1_STRING, "openssl.asn1_integer");
++    int cnt = sk_X509_REVOKED_num(revokeds);
++    for (i = 0; i < cnt; i++)
+     {
+-      lua_pushstring(L, "extensions");
+-      openssl_sk_x509_extension_totable(L, crl->crl->extensions);
+-      lua_rawset(L, -3);
++      X509_REVOKED *rev = sk_X509_REVOKED_value(revokeds, i);
++      if (ASN1_STRING_cmp(X509_REVOKED_get0_serialNumber(rev), sn) == 0)
++      {
++        revoked = rev;
++        break;
++      }
+     }
+-    return 1;
++  }
++  if (revoked)
++  {
++    openssl_revoked2table(L, revoked);
+   }
+   else
+     lua_pushnil(L);
+@@ -752,55 +990,38 @@ static luaL_Reg crl_funcs[] =
+ static int openssl_revoked_info(lua_State* L)
+ {
+   X509_REVOKED* revoked = CHECK_OBJECT(1, X509_REVOKED, "openssl.x509_revoked");
+-  lua_newtable(L);
+-
+-#if OPENSSL_VERSION_NUMBER > 0x10000000L
+-  AUXILIAR_SET(L, -1, "reason", openssl_i2s_revoke_reason(revoked->reason), string);
+-#else
+-  {
+-    int crit = 0;
+-    void* reason = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason, &crit, NULL);
+-
+-    AUXILIAR_SET(L, -1, "reason", openssl_i2s_revoke_reason(ASN1_ENUMERATED_get(reason)), string);
+-    ASN1_ENUMERATED_free(reason);
+-  }
+-#endif
+-  PUSH_ASN1_INTEGER(L, revoked->serialNumber);
+-  lua_setfield(L, -2, "serialNumber");
+-
+-  PUSH_ASN1_TIME(L, revoked->revocationDate);
+-  lua_setfield(L, -2, "revocationDate");
+-
+-  if (revoked->extensions)
+-  {
+-    lua_pushstring(L, "extensions");
+-    openssl_sk_x509_extension_totable(L, revoked->extensions);
+-    lua_rawset(L, -3);
+-  }
+-  return 1;
++  return openssl_revoked2table(L, revoked);
+ };
+ 
+ static int openssl_revoked_reason(lua_State* L)
+ {
+   X509_REVOKED* revoked = CHECK_OBJECT(1, X509_REVOKED, "openssl.x509_revoked");
+-#if OPENSSL_VERSION_NUMBER > 0x00909000L
+-  lua_pushstring(L, openssl_i2s_revoke_reason(revoked->reason));
+-  lua_pushinteger(L, revoked->reason);
+-  return 2;
+-#else
+-  /*
++  if (lua_isnone(L, 2))
+   {
+-    int crit = 0;
+-    void* reason = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason, &crit, NULL);
+-    lua_pushstring(L, openssl_i2s_revoke_reason(ASN1_ENUMERATED_get(reason)).lname);
+-    lua_pushinteger(revoked->reason);
+-    ASN1_ENUMERATED_free(reason);
+-  }*/
++    int reason = openssl_x509_revoked_get_reason(revoked);
++    lua_pushinteger(L, reason);
++    lua_pushstring(L, openssl_i2s_revoke_reason(reason));
++    return 2;
++  }
++  else
++  {
++    int reason = reason_get(L, 2);
++    ASN1_ENUMERATED * e = ASN1_ENUMERATED_new();
++    X509_EXTENSION * ext = X509_EXTENSION_new();
++
++    ASN1_ENUMERATED_set(e, reason);
++
++    X509_EXTENSION_set_data(ext, e);
++    X509_EXTENSION_set_object(ext, OBJ_nid2obj(NID_crl_reason));
++    X509_REVOKED_add_ext(revoked, ext, 0);
++
++    X509_EXTENSION_free(ext);
++    ASN1_ENUMERATED_free(e);
++  }
+   return 0;
+-#endif
+ }
+ 
+-static time_t ASN1_GetTimeT(ASN1_TIME* time)
++static time_t ASN1_GetTimeT(const ASN1_TIME* time)
+ {
+   struct tm t;
+   const char* str = (const char*) time->data;
+@@ -841,27 +1062,29 @@ static time_t ASN1_GetTimeT(ASN1_TIME* t
+ static int openssl_revoked_revocationDate(lua_State* L)
+ {
+   X509_REVOKED* revoked = CHECK_OBJECT(1, X509_REVOKED, "openssl.x509_revoked");
+-  PUSH_ASN1_TIME(L, revoked->revocationDate);
+-  lua_pushinteger(L, (LUA_INTEGER)ASN1_GetTimeT(revoked->revocationDate));
++  const ASN1_TIME* time = X509_REVOKED_get0_revocationDate(revoked);
++  lua_pushinteger(L, (LUA_INTEGER)ASN1_GetTimeT(time));
++  PUSH_ASN1_TIME(L, time);
+   return 2;
+ }
+ 
+ static int openssl_revoked_serialNumber(lua_State* L)
+ {
+   X509_REVOKED* revoked = CHECK_OBJECT(1, X509_REVOKED, "openssl.x509_revoked");
+-  BIGNUM *bn = ASN1_INTEGER_to_BN(revoked->serialNumber, NULL);
+-  PUSH_ASN1_INTEGER(L, revoked->serialNumber);
++  const ASN1_INTEGER *serialNumber = X509_REVOKED_get0_serialNumber(revoked);
++  BIGNUM *bn = ASN1_INTEGER_to_BN(serialNumber, NULL);
+   PUSH_OBJECT(bn, "openssl.bn");
++  PUSH_ASN1_INTEGER(L, serialNumber);
+   return 2;
+ }
+ 
+ static int openssl_revoked_extensions(lua_State* L)
+ {
+   X509_REVOKED* revoked = CHECK_OBJECT(1, X509_REVOKED, "openssl.x509_revoked");
+-
+-  if (revoked->extensions)
++  const STACK_OF(X509_EXTENSION) *exts = X509_REVOKED_get0_extensions(revoked);
++  if (exts)
+   {
+-    openssl_sk_x509_extension_totable(L, revoked->extensions);
++    openssl_sk_x509_extension_totable(L, exts);
+   }
+   else
+     lua_pushnil(L);
+@@ -889,27 +1112,6 @@ static luaL_Reg revoked_funcs[] =
+   {NULL,    NULL}
+ };
+ 
+-static int openssl_crl_reason(lua_State *L)
+-{
+-  int i;
+-  const BIT_STRING_BITNAME* bitname;
+-  lua_newtable(L);
+-  for (i = 0, bitname = &reason_flags[i]; bitname->bitnum != -1; i++, bitname = &reason_flags[i])
+-  {
+-    openssl_push_bit_string_bitname(L, bitname);
+-    lua_rawseti(L, -2, i + 1);
+-  }
+-  return 1;
+-}
+-
+-static luaL_Reg R[] =
+-{
+-  {"new",       openssl_crl_new },
+-  {"read",      openssl_crl_read},
+-  {"reason",    openssl_crl_reason},
+-  {NULL,    NULL}
+-};
+-
+ IMP_LUA_SK(X509_CRL, x509_crl)
+ 
+ int luaopen_x509_crl(lua_State *L)
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/csr.c luvi-src-v2.7.6/deps/lua-openssl/src/csr.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/csr.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/csr.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,12 +1,21 @@
+-/*=========================================================================*\
+-* csr.c
+-* X509 certificate sign request routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++x509.req module for lua-openssl binding, provide x509_req as lua object.
++create and manage x509 certificate sign request
++@module x509.req
++@usage
++  req = require'openssl'.x509.req
++*/
++
+ #include "openssl.h"
+ #include "private.h"
+ 
++/***
++read x509_req from string or bio input
++@function read
++@tparam bio|string input input data
++@tparam[opt='auto'] string format support 'auto','pem','der'
++@treturn x509_req certificate sign request object
++*/
+ static LUA_FUNCTION(openssl_csr_read)
+ {
+   BIO * in = load_bio_object(L, 1);
+@@ -21,12 +30,12 @@ static LUA_FUNCTION(openssl_csr_read)
+   if (fmt == FORMAT_PEM)
+   {
+     csr = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
+-    BIO_reset(in);
++    (void)BIO_reset(in);
+   }
+   else if (fmt == FORMAT_DER)
+   {
+     csr = d2i_X509_REQ_bio(in, NULL);
+-    BIO_reset(in);
++    (void)BIO_reset(in);
+   }
+   BIO_free(in);
+ 
+@@ -38,18 +47,95 @@ static LUA_FUNCTION(openssl_csr_read)
+   return openssl_pushresult(L, 0);
+ }
+ 
++/***
++create or generate a new x509_req object.
++Note if not give evp_pkey, will create a new x509_req object,or will generate a signed x509_req object.
++@function new
++@tparam[opt] x509_name subject subject name set to x509_req
++@tparam[opt] stack_of_x509_extension extensions add to x509_req
++@tparam[opt] stack_of_x509_attribute attributes add to x509_req
++@tparam[opt] evp_pkey pkey private key sign the x509_req, and set as public key
++@tparam[opt='sha1WithRSAEncryption'] evp_digest|string md_alg,  only used when pkey exist, and should fellow pkey
++@treturn x509_req certificate sign request object
++@see x509_req
++*/
++static LUA_FUNCTION(openssl_csr_new)
++{
++  X509_REQ *csr = X509_REQ_new();
++  int i;
++  int n = lua_gettop(L);
++  int ret = X509_REQ_set_version(csr, 0L);
++
++  for (i = 1; ret == 1 && i <= n; i++)
++  {
++    luaL_argcheck(L,
++                  auxiliar_getclassudata(L, "openssl.x509_name", i) ||
++                  auxiliar_getclassudata(L, "openssl.evp_pkey", i),
++                  i, "must be x509_name or evp_pkey");
++    if (auxiliar_getclassudata(L, "openssl.x509_name", i))
++    {
++      X509_NAME * subject = CHECK_OBJECT(i, X509_NAME, "openssl.x509_name");
++      ret = X509_REQ_set_subject_name(csr, subject);
++    }
++    if (auxiliar_getclassudata(L, "openssl.evp_pkey", i))
++    {
++      EVP_PKEY *pkey;
++      const EVP_MD *md;
++      luaL_argcheck(L, i == n || i == n - 1, i, "must is evp_pkey object");
++
++      pkey = CHECK_OBJECT(i, EVP_PKEY, "openssl.evp_pkey");
++
++      if (i == n - 1)
++        md = get_digest(L, n, NULL);
++      else
++        md = EVP_get_digestbyname("sha256");
++
++      ret = X509_REQ_set_pubkey(csr, pkey);
++      if (ret == 1)
++      {
++        ret = X509_REQ_sign(csr, pkey, md);
++        if (ret > 0)
++          ret = 1;
++      }
++      break;
++    }
++  };
+ 
+-static X509 *X509_REQ_to_X509_a(X509_REQ *r, int days, EVP_PKEY *pkey)
++  if (ret == 1)
++    PUSH_OBJECT(csr, "openssl.x509_req");
++  else
++  {
++    X509_REQ_free(csr);
++    return openssl_pushresult(L, ret);
++  }
++  return 1;
++}
++
++static luaL_Reg R[] =
++{
++  {"new",       openssl_csr_new },
++  {"read",      openssl_csr_read  },
++
++  {NULL,    NULL}
++};
++
++/***
++openssl.x509_req object
++@type x509_req
++*/
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++static X509 *X509_REQ_to_X509_ex(X509_REQ *r, int days, EVP_PKEY *pkey, const EVP_MD* md)
+ {
+   X509 *ret = NULL;
+   X509_CINF *xi = NULL;
+   X509_NAME *xn;
+-  EVP_PKEY* pubkey;
++  EVP_PKEY *pubkey = NULL;
++  int res;
+ 
+   if ((ret = X509_new()) == NULL)
+   {
+     X509err(X509_F_X509_REQ_TO_X509, ERR_R_MALLOC_FAILURE);
+-    goto err;
++    return NULL;
+   }
+ 
+   /* duplicate the request */
+@@ -57,10 +143,12 @@ static X509 *X509_REQ_to_X509_a(X509_REQ
+ 
+   if (sk_X509_ATTRIBUTE_num(r->req_info->attributes) != 0)
+   {
+-    if ((xi->version = M_ASN1_INTEGER_new()) == NULL) goto err;
+-    if (!ASN1_INTEGER_set(xi->version, 2)) goto err;
+-    /*    xi->extensions=ri->attributes; <- bad, should not ever be done
+-        ri->attributes=NULL; */
++    if ((xi->version = M_ASN1_INTEGER_new()) == NULL)
++      goto err;
++    if (!ASN1_INTEGER_set(xi->version, 2))
++      goto err;
++    /*-     xi->extensions=ri->attributes; <- bad, should not ever be done
++    ri->attributes=NULL; */
+   }
+ 
+   xn = X509_REQ_get_subject_name(r);
+@@ -71,12 +159,17 @@ static X509 *X509_REQ_to_X509_a(X509_REQ
+ 
+   if (X509_gmtime_adj(xi->validity->notBefore, 0) == NULL)
+     goto err;
+-  if (X509_gmtime_adj(xi->validity->notAfter, (long)60 * 60 * 24 * days) == NULL)
++  if (X509_gmtime_adj(xi->validity->notAfter, (long)60 * 60 * 24 * days) ==
++      NULL)
+     goto err;
++
+   pubkey = X509_REQ_get_pubkey(r);
+-  X509_set_pubkey(ret, pubkey);
++  res = X509_set_pubkey(ret, pubkey);
+   EVP_PKEY_free(pubkey);
+-  if (!X509_sign(ret, pkey, EVP_get_digestbyobj(r->sig_alg->algorithm)))
++
++  if (!md)
++    goto err;
++  if (!res || !X509_sign(ret, pkey, md))
+     goto err;
+   if (0)
+   {
+@@ -86,16 +179,24 @@ err:
+   }
+   return (ret);
+ }
++#endif
+ 
++/***
++convert x509_req to x509 object
++@function to_x509
++@treturn x509 object not signed
++*/
+ static LUA_FUNCTION(openssl_csr_to_x509)
+ {
+   X509_REQ * csr  = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+   EVP_PKEY * pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+   int days = luaL_optint(L, 3, 365);
+-  X509* cert = X509_REQ_to_X509_a(csr, days, pkey);
+-
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 2, "must be private key");
+-
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++  const EVP_MD* md = get_digest(L, 4, "sha256");
++  X509* cert = X509_REQ_to_X509_ex(csr, days, pkey, md);
++#else
++  X509* cert = X509_REQ_to_X509(csr, days, pkey);
++#endif
+   if (cert)
+   {
+     PUSH_OBJECT(cert, "openssl.x509");
+@@ -104,6 +205,13 @@ static LUA_FUNCTION(openssl_csr_to_x509)
+   return openssl_pushresult(L, 0);
+ }
+ 
++/***
++export x509_req to string
++@function export
++@tparam[opt='pem'] string format
++@tparam[opt='true'] boolean noext not export extension
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_csr_export)
+ {
+   X509_REQ * csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -151,17 +259,19 @@ static LUA_FUNCTION(openssl_csr_export)
+   return 1;
+ }
+ 
++/***
++get digest of x509_req
++@function digest
++@tparam[opt='SHA1'] evp_md|string md_alg default use sha1
++@treturn string digest result
++*/
+ static LUA_FUNCTION(openssl_csr_digest)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+-  const EVP_MD *md = NULL;
+   unsigned char buf[EVP_MAX_MD_SIZE];
+   unsigned int len = sizeof(buf);
+   int ret;
+-  if (lua_isnoneornil(L, 2))
+-    md = EVP_get_digestbyname("SHA1");
+-  else
+-    md = get_digest(L, 2);
++  const EVP_MD *md = get_digest(L, 2, "sha256");
+ 
+   ret = X509_REQ_digest(csr, md, buf, &len);
+   if (ret == 1)
+@@ -172,16 +282,25 @@ static LUA_FUNCTION(openssl_csr_digest)
+   return openssl_pushresult(L, ret);
+ };
+ 
++/***
++check x509_req with evp_pkey
++@function check
++@tparam evp_pkey pkey
++@treturn boolean result true for check pass
++*/
+ static LUA_FUNCTION(openssl_csr_check)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+   EVP_PKEY *pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-  int ret;
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 2, "must be private key");
+-  ret = X509_REQ_check_private_key(csr, pkey);
++  int ret = X509_REQ_check_private_key(csr, pkey);
+   return openssl_pushresult(L, ret);
+ };
+ 
++/***
++clone x509_req object
++@function dup
++@treturn x509_req object
++*/
+ static LUA_FUNCTION(openssl_csr_dup)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -190,6 +309,11 @@ static LUA_FUNCTION(openssl_csr_dup)
+   return 1;
+ };
+ 
++/***
++verify x509_req signature
++@function verify
++@treturn boolean result true for verify pass
++*/
+ static LUA_FUNCTION(openssl_csr_verify)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -204,129 +328,115 @@ static LUA_FUNCTION(openssl_csr_verify)
+   return 1;
+ };
+ 
+-static LUA_FUNCTION(openssl_csr_new)
+-{
+-  X509_REQ *csr = X509_REQ_new();
+-  int i;
+-  int n = lua_gettop(L);
+-  int ret = X509_REQ_set_version(csr, 0L);
+-
+-  for (i = 1; ret == 1 && i <= n; i++)
+-  {
+-    luaL_argcheck(L,
+-                  auxiliar_isclass(L, "openssl.x509_name", i) ||
+-                  auxiliar_isclass(L, "openssl.evp_pkey", i),
+-                  i, "must be x509_name");
+-    if (auxiliar_isclass(L, "openssl.x509_name", i))
+-    {
+-      X509_NAME * subject = CHECK_OBJECT(i, X509_NAME, "openssl.x509_name");
+-      ret = X509_REQ_set_subject_name(csr, subject);
+-    }
+-    if (auxiliar_isclass(L, "openssl.evp_pkey", i))
+-    {
+-      EVP_PKEY *pkey;
+-      const EVP_MD *md;
+-      luaL_argcheck(L, i == n || i == n - 1, i, "must is evp_pkey object");
+-
+-      pkey = CHECK_OBJECT(i, EVP_PKEY, "openssl.evp_pkey");
+-
+-      luaL_argcheck(L, openssl_pkey_is_private(pkey), i, "must be private key");
+-
+-      if (i == n - 1)
+-        md = get_digest(L, n);
+-      else
+-        md = EVP_get_digestbyname("sha1");
+-
+-      ret = X509_REQ_set_pubkey(csr, pkey);
+-      if (ret == 1)
+-      {
+-        ret = X509_REQ_sign(csr, pkey, md);
+-        if (ret > 0)
+-          ret = 1;
+-      }
+-      break;
+-    }
+-  };
+-
+-  if (ret == 1)
+-    PUSH_OBJECT(csr, "openssl.x509_req");
+-  else
+-  {
+-    X509_REQ_free(csr);
+-    return openssl_pushresult(L, ret);
+-  }
+-  return 1;
+-}
++/***
++sign x509_req object
+ 
++@function sign
++@tparam evp_pkey pkey private key which to sign x509_req object
++@tparam number|string|evp_md md message digest alg used to sign
++@treturn boolean result true for suceess
++*/
+ static LUA_FUNCTION(openssl_csr_sign)
+ {
+   X509_REQ * csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+-  EVP_PKEY *pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-  if (openssl_pkey_is_private(pkey))
++  EVP_PKEY *pubkey = X509_REQ_get_pubkey(csr);
++  if (auxiliar_getclassudata(L, "openssl.evp_pkey", 2))
+   {
+-    const EVP_MD* md = lua_isnone(L, 3) ? EVP_get_digestbyname("sha1") : get_digest(L, 3);
+-    int ret = X509_REQ_set_pubkey(csr, pkey);
+-    if (ret == 1)
++    EVP_PKEY *pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
++    const EVP_MD* md = get_digest(L, 3, "sha256");
++    int ret = 1;
++    if (pubkey == NULL)
+     {
+-      ret = X509_REQ_sign(csr, pkey, md);
+-      if (ret > 0)
+-        ret = 1;
++      BIO* bio = BIO_new(BIO_s_mem());
++      if ((ret = i2d_PUBKEY_bio(bio, pkey)) == 1)
++      {
++        pubkey = d2i_PUBKEY_bio(bio, NULL);
++        if (pubkey)
++        {
++          ret = X509_REQ_set_pubkey(csr, pubkey);
++          EVP_PKEY_free(pubkey);
++        }
++        else
++        {
++          ret = 0;
++        }
++      }
++      BIO_free(bio);
+     }
+-
+-    return openssl_pushresult(L, 1);
+-  }
+-  else if (lua_isnoneornil(L, 3) && X509_REQ_set_pubkey(csr, pkey))
+-  {
+-    unsigned char* tosign = NULL;
+-    const ASN1_ITEM *it = ASN1_ITEM_rptr(X509_REQ_INFO);
+-    int inl = ASN1_item_i2d((void*)csr->req_info, &tosign, it);
+-    if (inl > 0 && tosign)
++    else
+     {
+-      lua_pushlstring(L, (const char*)tosign, inl);
+-      OPENSSL_free(tosign);
+-      return 1;
++      EVP_PKEY_free(pubkey);
+     }
+-    return openssl_pushresult(L, 0);
++    if (ret == 1)
++      ret = X509_REQ_sign(csr, pkey, md);
++    return openssl_pushresult(L, ret);
+   }
+-  else
++  else if (lua_isstring(L, 2))
+   {
+     size_t siglen;
+-    const unsigned char* sigdata = (const unsigned char*)luaL_checklstring(L, 3, &siglen);
+-    const EVP_MD* md = get_digest(L, 4);
++    unsigned char* sigdata = (unsigned char*)luaL_checklstring(L, 2, &siglen);
++    const EVP_MD* md = get_digest(L, 3, NULL);
++    ASN1_BIT_STRING *sig = NULL;
++    X509_ALGOR *alg = NULL;
+ 
++    luaL_argcheck(L, pubkey != NULL, 1, "has not set public key!!!");
++
++    X509_REQ_get0_signature(csr, (const ASN1_BIT_STRING **)&sig, (const X509_ALGOR **)&alg);
+     /* (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) ? V_ASN1_NULL : V_ASN1_UNDEF, */
+-    X509_ALGOR_set0(csr->sig_alg, OBJ_nid2obj(md->pkey_type), V_ASN1_NULL, NULL);
++    X509_ALGOR_set0((X509_ALGOR *)alg, OBJ_nid2obj(EVP_MD_pkey_type(md)), V_ASN1_NULL, NULL);
+ 
+-    if (csr->signature->data != NULL)
+-      OPENSSL_free(csr->signature->data);
+-    csr->signature->data = OPENSSL_malloc(siglen);
+-    memcpy(csr->signature->data, sigdata, siglen);
+-    csr->signature->length = siglen;
++    ASN1_BIT_STRING_set((ASN1_BIT_STRING *)sig, sigdata, siglen);
+     /*
+     * In the interests of compatibility, I'll make sure that the bit string
+     * has a 'not-used bits' value of 0
+     */
+-    csr->signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+-    csr->signature->flags |= ASN1_STRING_FLAG_BITS_LEFT;
++    sig->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
++    sig->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+     lua_pushboolean(L, 1);
+     return 1;
+   }
++  else
++  {
++    int inl;
++    unsigned char* tosign = NULL;
++    luaL_argcheck(L, pubkey != NULL, 1, "has not set public key!!!");
++
++    inl = i2d_re_X509_REQ_tbs(csr, &tosign);
++    if (inl > 0 && tosign)
++    {
++      lua_pushlstring(L, (const char*)tosign, inl);
++      OPENSSL_free(tosign);
++      return 1;
++    }
++    return openssl_pushresult(L, 0);
++  }
+ }
+ 
++/***
++parse x509_req object as table
++@function parse
++@tparam[opt=true] shortname default will use short object name
++@treturn table result
++*/
+ static LUA_FUNCTION(openssl_csr_parse)
+ {
+-  X509_REQ * csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+-
+-  X509_NAME * subject = X509_REQ_get_subject_name(csr);
++  X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
++  X509_NAME *subject = X509_REQ_get_subject_name(csr);
+   STACK_OF(X509_EXTENSION) *exts  = X509_REQ_get_extensions(csr);
+ 
+   lua_newtable(L);
++  {
++    const ASN1_BIT_STRING *sig = NULL;
++    const X509_ALGOR *alg = NULL;
+ 
+-  openssl_push_asn1(L, csr->signature, V_ASN1_BIT_STRING);
+-  lua_setfield(L, -2, "signature");
+-
+-  openssl_push_x509_algor(L, csr->sig_alg);
+-  lua_setfield(L, -2, "sig_alg");
++    X509_REQ_get0_signature(csr, &sig, &alg);
++    openssl_push_asn1(L, sig, V_ASN1_BIT_STRING);
++    lua_setfield(L, -2, "signature");
++
++    alg = X509_ALGOR_dup((X509_ALGOR *)alg);
++    PUSH_OBJECT(alg, "openssl.x509_algor");
++    lua_setfield(L, -2, "sig_alg");
++  }
+ 
+   lua_newtable(L);
+   AUXILIAR_SET(L, -1, "version", X509_REQ_get_version(csr), integer);
+@@ -341,14 +451,16 @@ static LUA_FUNCTION(openssl_csr_parse)
+   }
+ 
+   {
+-    X509_REQ_INFO* ri = csr->req_info;
+-    int i, c;
++    X509_PUBKEY *xpub = X509_REQ_get_X509_PUBKEY(csr);
++    ASN1_OBJECT *oalg = NULL;
++    int c;
+     EVP_PKEY *pubkey = X509_REQ_get_pubkey(csr);
+ 
+     lua_newtable(L);
+     c = X509_REQ_get_attr_count(csr);
+     if (c > 0)
+     {
++      int i;
+       lua_newtable(L);
+       for (i = 0; i < c ; i++)
+       {
+@@ -361,10 +473,13 @@ static LUA_FUNCTION(openssl_csr_parse)
+     }
+ 
+     lua_newtable(L);
+-    openssl_push_asn1object(L, ri->pubkey->algor->algorithm);
+-    lua_setfield(L, -2, "algorithm");
++    if (X509_PUBKEY_get0_param(&oalg, NULL, NULL, NULL, xpub))
++    {
++      openssl_push_asn1object(L, oalg);
++      lua_setfield(L, -2, "algorithm");
++    }
+ 
+-    AUXILIAR_SETOBJECT(L, pubkey , "openssl.evp_pkey", -1, "pubkey");
++    AUXILIAR_SETOBJECT(L, pubkey, "openssl.evp_pkey", -1, "pubkey");
+     lua_setfield(L, -2, "pubkey");
+ 
+     lua_setfield(L, -2, "req_info");
+@@ -380,6 +495,18 @@ static LUA_FUNCTION(openssl_csr_free)
+   return 0;
+ }
+ 
++/***
++get public key
++@function public
++@treturn evp_pkey public key
++*/
++
++/***
++set public key
++@function public
++@tparam evp_pkey pubkey public key set to x509_req
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_csr_public)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -397,6 +524,17 @@ static LUA_FUNCTION(openssl_csr_public)
+   }
+ }
+ 
++/***
++get version key
++@function version
++@treturn integer
++*/
++/***
++set version key
++@function version
++@tparam integer version
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_csr_version)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -413,6 +551,17 @@ static LUA_FUNCTION(openssl_csr_version)
+   }
+ }
+ 
++/***
++get subject x509_name object
++@function subject
++@treturn x509_name
++*/
++/***
++set subject x509_name object
++@function subject
++@tparam x509_name subject
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_csr_subject)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -433,6 +582,19 @@ static LUA_FUNCTION(openssl_csr_subject)
+   }
+ }
+ 
++/***
++get extensions of x509_req object
++@function extensions
++@tparam[opt=false] boolean asobject, true for return as stack_of_x509_extension or as table
++@treturn stack_of_x509_extension object when param set true
++@treturn table contain all x509_extension when param set false or nothing
++*/
++/***
++set extension of x509_req object
++@function extensions
++@tparam stack_of_x509_extension extensions
++@treturn boolean result true for success
++*/
+ static LUA_FUNCTION(openssl_csr_extensions)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -457,10 +619,29 @@ static LUA_FUNCTION(openssl_csr_extensio
+   }
+ }
+ 
++/***
++remove attribute object from location
++@function attribute
++@tparam integer location
++@tparam nil nil, nil not none
++@treturn x509_attribute attribute removed
++*/
++/***
++get attribute object from location
++@function attribute
++@tparam integer location
++@treturn x509_attribute attribute
++*/
++/***
++add attribute to x509_req object
++@function attribute
++@tparam x509_attribute attribute attribute to add
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_csr_attribute)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+-  if (auxiliar_isclass(L, "openssl.x509_attribute", 2))
++  if (auxiliar_getclassudata(L, "openssl.x509_attribute", 2))
+   {
+     X509_ATTRIBUTE *attr = CHECK_OBJECT(2, X509_ATTRIBUTE, "openssl.x509_attribute");
+     int ret = X509_REQ_add1_attr(csr, attr);
+@@ -517,6 +698,11 @@ static LUA_FUNCTION(openssl_csr_attribut
+   return 0;
+ }
+ 
++/***
++get total attribute count in x509_req object
++@function attr_count
++@treturn integer
++*/
+ static LUA_FUNCTION(openssl_csr_attr_count)
+ {
+   X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req");
+@@ -553,14 +739,6 @@ static luaL_Reg csr_cfuns[] =
+   {NULL,        NULL  }
+ };
+ 
+-static luaL_Reg R[] =
+-{
+-  {"new",       openssl_csr_new },
+-  {"read",      openssl_csr_read  },
+-
+-  {NULL,    NULL}
+-};
+-
+ int luaopen_x509_req(lua_State *L)
+ {
+   auxiliar_newclass(L, "openssl.x509_req", csr_cfuns);
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/dh.c luvi-src-v2.7.6/deps/lua-openssl/src/dh.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/dh.c	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/dh.c	2019-02-13 11:53:24.275126573 +0100
+@@ -7,19 +7,12 @@
+ #include "openssl.h"
+ #include "private.h"
+ #include <openssl/dh.h>
++#include <openssl/engine.h>
+ 
+ #define MYNAME    "dh"
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
+-#define lua_boxpointer(L,u) \
+-  (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
+-
+-#define PUSH_BN(x)                  \
+-lua_boxpointer(L,x);                \
+-luaL_getmetatable(L,"openssl.bn");  \
+-lua_setmetatable(L,-2)
+-
+ static LUA_FUNCTION(openssl_dh_free)
+ {
+   DH* dh = CHECK_OBJECT(1, DH, "openssl.dh");
+@@ -29,19 +22,45 @@ static LUA_FUNCTION(openssl_dh_free)
+ 
+ static LUA_FUNCTION(openssl_dh_parse)
+ {
++  const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub = NULL, *pri = NULL;
+   DH* dh = CHECK_OBJECT(1, DH, "openssl.dh");
+   lua_newtable(L);
+-  OPENSSL_PKEY_GET_BN(dh->p, p);
+-  OPENSSL_PKEY_GET_BN(dh->g, g);
+-  OPENSSL_PKEY_GET_BN(dh->priv_key, priv_key);
+-  OPENSSL_PKEY_GET_BN(dh->pub_key, pub_key);
++
++  lua_pushinteger(L, DH_size(dh));
++  lua_setfield(L, -2, "size");
++
++  lua_pushinteger(L, DH_bits(dh));
++  lua_setfield(L, -2, "bits");
++
++  DH_get0_pqg(dh, &p, &q, &g);
++  DH_get0_key(dh, &pub, &pri);
++
++  OPENSSL_PKEY_GET_BN(p, p);
++  OPENSSL_PKEY_GET_BN(q, q);
++  OPENSSL_PKEY_GET_BN(g, g);
++  OPENSSL_PKEY_GET_BN(pub, pub_key);
++  OPENSSL_PKEY_GET_BN(pri, priv_key);
+ 
+   return 1;
+ }
+ 
++static int openssl_dh_set_method(lua_State *L)
++{
++  DH* dh = CHECK_OBJECT(1, DH, "openssl.dh");
++  ENGINE *e = CHECK_OBJECT(2, ENGINE, "openssl.engine");
++  const DH_METHOD *m = ENGINE_get_DH(e);
++  if (m)
++  {
++    int r = DH_set_method(dh, m);
++    return openssl_pushresult(L, r);
++  }
++  return 0;
++}
++
+ static luaL_Reg dh_funs[] =
+ {
+   {"parse",       openssl_dh_parse},
++  {"set_method",  openssl_dh_set_method},
+ 
+   {"__gc",        openssl_dh_free},
+   {"__tostring",  auxiliar_tostring},
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/digest.c luvi-src-v2.7.6/deps/lua-openssl/src/digest.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/digest.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/digest.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,17 +1,27 @@
+-/*=========================================================================*\
+-* digest.c
+-* digest module for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++digest module for lua-openssl binding
+ 
++@module digest
++@usage
++  digest = require('openssl').digest
++*/
+ #include "openssl.h"
+ #include "private.h"
++#if defined(LIBRESSL_VERSION_NUMBER)
++#include <openssl/engine.h>
++#endif
+ 
+ #define MYNAME    "digest"
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
++/***
++list all support digest algs
++
++@function list
++@tparam[opt] boolean alias include alias names for digest alg, default true
++@treturn[table] all methods
++*/
+ static LUA_FUNCTION(openssl_digest_list)
+ {
+   int aliases = lua_isnoneornil(L, 1) ? 1 : lua_toboolean(L, 1);
+@@ -20,26 +30,43 @@ static LUA_FUNCTION(openssl_digest_list)
+   return 1;
+ };
+ 
++/***
++get evp_digest object
++
++@function get
++@tparam string|integer|asn1_object alg name, nid or object identity
++@treturn evp_digest digest object mapping EVP_MD in openssl
++
++@see evp_digest
++*/
+ static LUA_FUNCTION(openssl_digest_get)
+ {
+-  const EVP_MD* md = get_digest(L, 1);
++  const EVP_MD* md = get_digest(L, 1, NULL);
+ 
+-  if (md)
+-    PUSH_OBJECT((void*)md, "openssl.evp_digest");
+-  else
+-    lua_pushnil(L);
++  PUSH_OBJECT((void*)md, "openssl.evp_digest");
+   return 1;
+ }
+ 
++/***
++get evp_digest_ctx object
++
++@function new
++@tparam string|integer|asn1_object alg name, nid or object identity
++@treturn evp_digest_ctx digest object mapping EVP_MD_CTX in openssl
++
++@see evp_digest_ctx
++*/
+ static LUA_FUNCTION(openssl_digest_new)
+ {
+-  const EVP_MD* md = get_digest(L, 1);
+-  if (md)
++  const EVP_MD* md = get_digest(L, 1, NULL);
++  int ret;
++  ENGINE* e = lua_isnoneornil(L, 2) ? NULL : CHECK_OBJECT(2, ENGINE, "openssl.engine");
++  EVP_MD_CTX* ctx = EVP_MD_CTX_create();
++  if (ctx!=NULL)
+   {
+-    int ret;
+-    ENGINE* e =  (!lua_isnoneornil(L, 2)) ? CHECK_OBJECT(2, ENGINE, "openssl.engine") : NULL;
+-    EVP_MD_CTX* ctx = EVP_MD_CTX_create();
+     EVP_MD_CTX_init(ctx);
++    lua_pushlightuserdata(L, e);
++    lua_rawsetp(L, LUA_REGISTRYINDEX, ctx);
+     ret = EVP_DigestInit_ex(ctx, md, e);
+     if (ret == 1)
+     {
+@@ -50,15 +77,30 @@ static LUA_FUNCTION(openssl_digest_new)
+       EVP_MD_CTX_destroy(ctx);
+       return openssl_pushresult(L, ret);
+     }
+-  }
+-  else
++  }else
+     lua_pushnil(L);
+   return 1;
+ }
+ 
++/***
++quick method to generate digest result
++
++@function digest
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam string msg to compute digest
++@tparam[opt] boolean raw binary result return if set true, or hex encoded string default
++@treturn string digest result value
++*/
+ static LUA_FUNCTION(openssl_digest)
+ {
+-  const EVP_MD *md = NULL;
++  const EVP_MD *md;
++  ENGINE *eng;
++  size_t inl;
++  const char* in;
++  unsigned char buf[EVP_MAX_MD_SIZE];
++  unsigned int  blen = sizeof(buf);
++  int raw, status;
++
+   if (lua_istable(L, 1))
+   {
+     if (lua_getmetatable(L, 1) && lua_equal(L, 1, -1))
+@@ -69,45 +111,106 @@ static LUA_FUNCTION(openssl_digest)
+     else
+       luaL_error(L, "call function with invalid state");
+   }
+-  if (lua_isstring(L, 1))
++
++  md = get_digest(L, 1, NULL);
++  in = luaL_checklstring(L, 2, &inl);
++  raw = (lua_isnoneornil(L, 3)) ? 0 : lua_toboolean(L, 3);
++  eng = (lua_isnoneornil(L, 4) ? 0 : CHECK_OBJECT(4, ENGINE, "openssl.engine"));
++
++  status = EVP_Digest(in, inl, buf, &blen, md, eng);
++  if (status)
+   {
+-    md = EVP_get_digestbyname(lua_tostring(L, 1));
++    if (raw)
++      lua_pushlstring(L, (const char*)buf, blen);
++    else
++    {
++      char hex[2 * EVP_MAX_MD_SIZE + 1];
++      to_hex((const char*)buf, blen, hex);
++      lua_pushstring(L, hex);
++    }
+   }
+-  else if (auxiliar_isclass(L, "openssl.evp_digest", 1))
++  else
++    luaL_error(L, "EVP_Digest method fail");
++  return 1;
++};
++
++/***
++create digest object for sign
++
++@function signInit
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam[opt=nil] engine object
++@treturn evp_digest_ctx
++*/
++static LUA_FUNCTION(openssl_signInit)
++{
++  const EVP_MD *md = get_digest(L, 1, NULL);
++  EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
++  ENGINE*     e = lua_gettop(L) > 2 ? CHECK_OBJECT(3, ENGINE, "openssl.engine") : NULL;
++  EVP_MD_CTX *ctx = EVP_MD_CTX_create();
++  if (ctx)
+   {
+-    md = CHECK_OBJECT(1, EVP_MD, "openssl.evp_digest");
++    int ret;
++    EVP_MD_CTX_init(ctx);
++    ret = EVP_DigestSignInit(ctx, NULL, md, e, pkey);
++    if (ret)
++    {
++      PUSH_OBJECT(ctx, "openssl.evp_digest_ctx");
++    }
++    else
++      return openssl_pushresult(L, ret);
+   }
+   else
+-    luaL_error(L, "argument #1 must be a string identity digest method or an openssl.evp_digest object");
++    lua_pushnil(L);
++  return 1;
++}
++
++/***
++create digest object for verify
+ 
+-  if (md)
++@function verifyInit
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam[opt=nil] engine object
++@treturn evp_digest_ctx
++*/
++static LUA_FUNCTION(openssl_verifyInit)
++{
++  const EVP_MD *md = get_digest(L, 1, NULL);
++  EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
++  ENGINE*     e = lua_gettop(L) > 2 ? CHECK_OBJECT(3, ENGINE, "openssl.engine") : NULL;
++  EVP_PKEY_CTX *pctx = 0;
++  EVP_MD_CTX *ctx = EVP_MD_CTX_create();
++
++  if (ctx)
+   {
+-    size_t inl;
+-    unsigned char buf[EVP_MAX_MD_SIZE];
+-    unsigned int  blen = sizeof(buf);
+-    const char* in = luaL_checklstring(L, 2, &inl);
+-    int raw = (lua_isnoneornil(L, 3)) ? 0 : lua_toboolean(L, 3);
+-    int status = EVP_Digest(in, inl, buf, &blen, md, NULL);
+-    if (status)
++    int ret;
++    EVP_MD_CTX_init(ctx);
++    ret = EVP_DigestVerifyInit(ctx, &pctx, md, e, pkey);
++    if (ret)
+     {
+-      if (raw)
+-        lua_pushlstring(L, (const char*)buf, blen);
+-      else
+-      {
+-        char hex[2 * EVP_MAX_MD_SIZE + 1];
+-        to_hex((const char*) buf, blen, hex);
+-        lua_pushstring(L, hex);
+-      }
++      PUSH_OBJECT(ctx, "openssl.evp_digest_ctx");
+     }
+     else
+-      luaL_error(L, "EVP_Digest method fail");
++      return openssl_pushresult(L, ret);
+   }
+   else
+-    luaL_error(L, "argument #1 is not a valid digest algorithm or openssl.evp_digest object");
++    lua_pushnil(L);
+   return 1;
+-};
++}
+ 
+-/*** evp_digest method ***/
++/***
++openssl.evp_digest object
++@type evp_digest
++*/
++
++/***
++compute msg digest result
++
++@function digest
++@tparam string msg data to digest
++@tparam[opt] engine, eng
++@treturn string result a binary hash value for msg
++*/
+ static LUA_FUNCTION(openssl_digest_digest)
+ {
+   size_t inl;
+@@ -128,6 +231,12 @@ static LUA_FUNCTION(openssl_digest_diges
+   return 1;
+ }
+ 
++/***
++get infomation of evp_digest object
++
++@function info
++@treturn table info keys include nid,name size,block_size,pkey_type,flags
++*/
+ static LUA_FUNCTION(openssl_digest_info)
+ {
+   EVP_MD *md = CHECK_OBJECT(1, EVP_MD, "openssl.evp_digest");
+@@ -142,10 +251,18 @@ static LUA_FUNCTION(openssl_digest_info)
+   return 1;
+ }
+ 
++/***
++create new evp_digest_ctx
++
++@function new
++@tparam[opt] engine, eng
++@treturn evp_digest_ctx ctx
++@see evp_digest_ctx
++*/
+ static LUA_FUNCTION(openssl_evp_digest_init)
+ {
+   EVP_MD* md = CHECK_OBJECT(1, EVP_MD, "openssl.evp_digest");
+-  ENGINE*     e = lua_gettop(L) > 1 ? CHECK_OBJECT(2, ENGINE, "openssl.engine") : NULL;
++  ENGINE*     e = lua_isnoneornil(L, 2) ? NULL : CHECK_OBJECT(2, ENGINE, "openssl.engine");
+ 
+   EVP_MD_CTX* ctx = EVP_MD_CTX_create();
+   if (ctx)
+@@ -168,8 +285,33 @@ static LUA_FUNCTION(openssl_evp_digest_i
+   return 1;
+ }
+ 
+-/** openssl.evp_digest_ctx method */
++/***
++create digest object for sign
+ 
++@function signInit
++@tparam[opt=nil] engine object
++@treturn evp_digest_ctx
++*/
++
++/***
++create digest object for verify
++
++@function verifyInit
++@tparam[opt=nil] engine object
++@treturn evp_digest_ctx
++*/
++
++/***
++openssl.evp_digest_ctx object
++@type evp_digest_ctx
++*/
++
++/***
++get infomation of evp_digest_ctx object
++
++@function info
++@treturn table info keys include size,block_size,digest
++*/
+ static LUA_FUNCTION(openssl_digest_ctx_info)
+ {
+   EVP_MD_CTX *ctx = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
+@@ -182,7 +324,13 @@ static LUA_FUNCTION(openssl_digest_ctx_i
+   return 1;
+ }
+ 
++/***
++feed data to do digest
+ 
++@function update
++@tparam string msg data
++@treturn boolean result true for success
++*/
+ static LUA_FUNCTION(openssl_evp_digest_update)
+ {
+   size_t inl;
+@@ -195,6 +343,14 @@ static LUA_FUNCTION(openssl_evp_digest_u
+   return 1;
+ }
+ 
++/***
++get result of digest
++
++@function final
++@tparam[opt] string last last part of data
++@tparam[opt] boolean raw binary or hex encoded result, default true for binary result
++@treturn string val hash result
++*/
+ static LUA_FUNCTION(openssl_evp_digest_final)
+ {
+   EVP_MD_CTX* c = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
+@@ -248,16 +404,28 @@ static LUA_FUNCTION(openssl_evp_digest_f
+ static LUA_FUNCTION(openssl_digest_ctx_free)
+ {
+   EVP_MD_CTX *ctx = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
++  lua_pushnil(L);
++  lua_rawsetp(L, LUA_REGISTRYINDEX, ctx);
+   EVP_MD_CTX_destroy(ctx);
+   return 0;
+ }
+ 
++/***
++reset evp_diget_ctx to reuse
++
++@function reset
++*/
+ static LUA_FUNCTION(openssl_digest_ctx_reset)
+ {
+   EVP_MD_CTX *ctx = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
+   const EVP_MD *md = EVP_MD_CTX_md(ctx);
+-  ENGINE* e = ctx->engine;
+-  int ret = EVP_MD_CTX_cleanup(ctx);
++
++  ENGINE* e = NULL;
++  int ret;
++
++  lua_rawgetp(L, LUA_REGISTRYINDEX, ctx);
++  e = (ENGINE*)lua_topointer(L, -1);
++  ret = EVP_MD_CTX_reset(ctx);
+   if (ret)
+   {
+     EVP_MD_CTX_init(ctx);
+@@ -266,6 +434,11 @@ static LUA_FUNCTION(openssl_digest_ctx_r
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++clone evp_diget_ctx
++
++@function clone
++*/
+ static LUA_FUNCTION(openssl_digest_ctx_clone)
+ {
+   EVP_MD_CTX *ctx = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
+@@ -289,9 +462,23 @@ static LUA_FUNCTION(openssl_digest_ctx_c
+   return 1;
+ }
+ 
++/***
++retrieve md data
++
++@function data
++@treturn string md_data
++*/
++
++/***
++restore md data
++
++@function data
++@tparam string md_data
++*/
+ static LUA_FUNCTION(openssl_digest_ctx_data)
+ {
+   EVP_MD_CTX *ctx = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+   if (lua_isnone(L, 2))
+   {
+     lua_pushlstring(L, ctx->md_data, ctx->digest->ctx_size);
+@@ -308,55 +495,34 @@ static LUA_FUNCTION(openssl_digest_ctx_d
+     else
+       luaL_error(L, "data with wrong data");
+   }
+-
+-  return 0;
+-}
+-
+-static LUA_FUNCTION(openssl_signInit)
+-{
+-  const EVP_MD *md = get_digest(L, 1);
+-  EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-  ENGINE*     e = lua_gettop(L) > 2 ? CHECK_OBJECT(3, ENGINE, "openssl.engine") : NULL;
+-  EVP_PKEY_CTX *pctx;
+-  EVP_MD_CTX *ctx = EVP_MD_CTX_create();
+-  if (ctx)
++#else
++  size_t ctx_size = EVP_MD_meth_get_app_datasize(EVP_MD_CTX_md(ctx));
++  if (lua_isnone(L, 2))
+   {
+-    int ret = EVP_DigestSignInit(ctx, &pctx, md, e, pkey);
+-    if (ret)
+-    {
+-      PUSH_OBJECT(ctx, "openssl.evp_digest_ctx");
+-    }
+-    else
+-      return openssl_pushresult(L, ret);
++    lua_pushlstring(L, EVP_MD_CTX_md_data(ctx), ctx_size);
++    return 1;
+   }
+   else
+-    lua_pushnil(L);
+-  return 1;
+-}
+-
+-static LUA_FUNCTION(openssl_verifyInit)
+-{
+-  const EVP_MD *md = get_digest(L, 1);
+-  EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-  ENGINE*     e = lua_gettop(L) > 2 ? CHECK_OBJECT(3, ENGINE, "openssl.engine") : NULL;
+-  EVP_PKEY_CTX *pctx = 0;
+-  EVP_MD_CTX *ctx = EVP_MD_CTX_create();
+-  luaL_argcheck(L, !openssl_pkey_is_private(pkey), 2, "need public key");
+-  if (ctx)
+   {
+-    int ret = EVP_DigestVerifyInit(ctx, &pctx, md, e, pkey);
+-    if (ret)
++    const char* d = luaL_checklstring(L, 2, &ctx_size);
++    if (ctx_size == (size_t)EVP_MD_meth_get_app_datasize(EVP_MD_CTX_md(ctx)))
+     {
+-      PUSH_OBJECT(ctx, "openssl.evp_digest_ctx");
++      memcpy(EVP_MD_CTX_md_data(ctx), d, ctx_size);
+     }
+     else
+-      return openssl_pushresult(L, ret);
++      luaL_error(L, "data with wrong data");
+   }
+-  else
+-    lua_pushnil(L);
+-  return 1;
++#endif
++  return 0;
+ }
+ 
++/***
++feed data for sign to get signature
++
++@function verifyUpdate
++@tparam string data to be signed
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_signUpdate)
+ {
+   size_t l;
+@@ -367,6 +533,13 @@ static LUA_FUNCTION(openssl_signUpdate)
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++feed data for verify with signature
++
++@function verifyUpdate
++@tparam string data to be verified
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_verifyUpdate)
+ {
+   size_t l;
+@@ -377,6 +550,13 @@ static LUA_FUNCTION(openssl_verifyUpdate
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get result of sign
++
++@function signFinal
++@tparam evp_pkey private key to do sign
++@treturn string singed result
++*/
+ static LUA_FUNCTION(openssl_signFinal)
+ {
+   EVP_MD_CTX *ctx = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
+@@ -393,12 +573,19 @@ static LUA_FUNCTION(openssl_signFinal)
+     lua_pushlstring(L, (char *)sigbuf, siglen);
+   }
+   free(sigbuf);
+-  EVP_MD_CTX_cleanup(ctx);
++  EVP_MD_CTX_reset(ctx);
+   if (ret == 1)
+     return 1;
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get verify result
++
++@function verifyFinal
++@tparam string signature
++@treturn boolean result, true for verify pass
++*/
+ static LUA_FUNCTION(openssl_verifyFinal)
+ {
+   EVP_MD_CTX *ctx = CHECK_OBJECT(1, EVP_MD_CTX, "openssl.evp_digest_ctx");
+@@ -409,9 +596,9 @@ static LUA_FUNCTION(openssl_verifyFinal)
+   if (pkey)
+     ret = EVP_VerifyFinal(ctx, (const unsigned char*) signature, signature_len, pkey);
+   else
+-    ret = EVP_DigestVerifyFinal(ctx, (const unsigned char*) signature, signature_len);
++    ret = EVP_DigestVerifyFinal(ctx, (unsigned char*) signature, signature_len);
+ 
+-  EVP_MD_CTX_cleanup(ctx);
++  EVP_MD_CTX_reset(ctx);
+   return openssl_pushresult(L, ret);
+ }
+ 
+@@ -442,7 +629,7 @@ static luaL_Reg digest_ctx_funs[] =
+ 
+   {"signUpdate",  openssl_signUpdate},
+   {"signFinal",   openssl_signFinal},
+-  {"verifyUpdate", openssl_verifyUpdate},
++  {"verifyUpdate",openssl_verifyUpdate},
+   {"verifyFinal", openssl_verifyFinal},
+ 
+   {"__tostring",  auxiliar_tostring},
+@@ -452,13 +639,13 @@ static luaL_Reg digest_ctx_funs[] =
+ 
+ static const luaL_Reg R[] =
+ {
+-  { "__call",     openssl_digest},
+-  { "list",       openssl_digest_list},
+-  { "get",        openssl_digest_get},
+-  { "new",        openssl_digest_new},
+-  { "digest",     openssl_digest},
++  {"__call",     openssl_digest},
++  {"list",       openssl_digest_list},
++  {"get",        openssl_digest_get},
++  {"new",        openssl_digest_new},
++  {"digest",     openssl_digest},
+ 
+-  {"signInit", openssl_signInit},
++  {"signInit",   openssl_signInit},
+   {"verifyInit", openssl_verifyInit},
+ 
+   {NULL,  NULL}
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/dsa.c luvi-src-v2.7.6/deps/lua-openssl/src/dsa.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/dsa.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/dsa.c	2019-02-13 11:53:24.275126573 +0100
+@@ -7,19 +7,12 @@
+ #include "openssl.h"
+ #include "private.h"
+ #include <openssl/dsa.h>
++#include <openssl/engine.h>
+ 
+ #define MYNAME    "dsa"
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
+-#define lua_boxpointer(L,u) \
+-  (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
+-
+-#define PUSH_BN(x)                  \
+-lua_boxpointer(L,x);                \
+-luaL_getmetatable(L,"openssl.bn");  \
+-lua_setmetatable(L,-2)
+-
+ static LUA_FUNCTION(openssl_dsa_free)
+ {
+   DSA* dsa = CHECK_OBJECT(1, DSA, "openssl.dsa");
+@@ -29,19 +22,44 @@ static LUA_FUNCTION(openssl_dsa_free)
+ 
+ static LUA_FUNCTION(openssl_dsa_parse)
+ {
++  const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub = NULL, *pri = NULL;
+   DSA* dsa = CHECK_OBJECT(1, DSA, "openssl.rsa");
+   lua_newtable(L);
+-  OPENSSL_PKEY_GET_BN(dsa->p, p);
+-  OPENSSL_PKEY_GET_BN(dsa->q, q);
+-  OPENSSL_PKEY_GET_BN(dsa->g, g);
+-  OPENSSL_PKEY_GET_BN(dsa->priv_key, priv_key);
+-  OPENSSL_PKEY_GET_BN(dsa->pub_key, pub_key);
++
++  lua_pushinteger(L, DSA_size(dsa));
++  lua_setfield(L, -2, "size");
++
++  lua_pushinteger(L, DSA_bits(dsa));
++  lua_setfield(L, -2, "bits");
++
++  DSA_get0_pqg(dsa, &p, &q, &g);
++  DSA_get0_key(dsa, &pub, &pri);
++
++  OPENSSL_PKEY_GET_BN(p, p);
++  OPENSSL_PKEY_GET_BN(q, q);
++  OPENSSL_PKEY_GET_BN(g, g);
++  OPENSSL_PKEY_GET_BN(pri, priv_key);
++  OPENSSL_PKEY_GET_BN(pub, pub_key);
+   return 1;
+ }
+ 
++static int openssl_dsa_set_method(lua_State *L)
++{
++  DSA* dsa = CHECK_OBJECT(1, DSA, "openssl.dsa");
++  ENGINE *e = CHECK_OBJECT(2, ENGINE, "openssl.engine");
++  const DSA_METHOD *m = ENGINE_get_DSA(e);
++  if (m)
++  {
++    int r = DSA_set_method(dsa, m);
++    return openssl_pushresult(L, r);
++  }
++  return 0;
++}
++
+ static luaL_Reg dsa_funs[] =
+ {
+   {"parse",       openssl_dsa_parse},
++  {"set_method",  openssl_dsa_set_method},
+ 
+   {"__gc",        openssl_dsa_free},
+   {"__tostring",  auxiliar_tostring},
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/ec.c luvi-src-v2.7.6/deps/lua-openssl/src/ec.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/ec.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/ec.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,25 +1,15 @@
+-/*=========================================================================*\
+-* ec.c
+-* EC routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++ec module for lua-openssl binding
++@module ec
++*/
+ #include "openssl.h"
+ #include "private.h"
++#include <openssl/engine.h>
+ 
+ #define MYNAME    "ec"
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
+-#define lua_boxpointer(L,u) \
+-  (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
+-
+-#define PUSH_BN(x) \
+-lua_boxpointer(L,x);  \
+-luaL_getmetatable(L,"openssl.bn");  \
+-lua_setmetatable(L,-2);
+-
+-
+ #ifndef OPENSSL_NO_EC
+ 
+ static int openssl_ecpoint_affine_coordinates(lua_State *L)
+@@ -57,6 +47,7 @@ static int openssl_eckey_group(lua_State
+   {
+     const EC_POINT* p = EC_GROUP_get0_generator(g);
+     p = EC_POINT_dup(p, g);
++    g = EC_GROUP_dup(g);
+     PUSH_OBJECT(g, "openssl.ec_group");
+     PUSH_OBJECT(p, "openssl.ec_point");
+     return 2;
+@@ -149,6 +140,22 @@ static int openssl_ec_group_asn1_flag(lu
+   return 0;
+ }
+ 
++static point_conversion_form_t openssl_point_conversion_form(lua_State *L, int i, const char* defval)
++{
++  const char* options[] = {"compressed", "uncompressed", "hybrid", NULL};
++  int f = luaL_checkoption(L, 2, defval, options);
++  point_conversion_form_t form = 0;
++  if (f == 0)
++    form = POINT_CONVERSION_COMPRESSED;
++  else if (f == 1)
++    form = POINT_CONVERSION_UNCOMPRESSED;
++  else if (f == 2)
++    form = POINT_CONVERSION_HYBRID;
++  else
++    luaL_argerror(L, i, "not accept value point_conversion_form");
++  return form;
++}
++
+ static int openssl_ec_group_point_conversion_form(lua_State*L)
+ {
+   EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
+@@ -169,16 +176,7 @@ static int openssl_ec_group_point_conver
+   }
+   else if (lua_isstring(L, 2))
+   {
+-    const char* options[] = {"compressed", "uncompressed", "hybrid", NULL};
+-    int f = luaL_checkoption(L, 2, NULL, options);
+-    if (f == 0)
+-      form = POINT_CONVERSION_COMPRESSED;
+-    else if (f == 1)
+-      form = POINT_CONVERSION_UNCOMPRESSED;
+-    else if (f == 2)
+-      form = POINT_CONVERSION_HYBRID;
+-    else
+-      luaL_argerror(L, 2, "not accept value point_conversion_form");
++    form = openssl_point_conversion_form(L, 2, NULL);
+     EC_GROUP_set_point_conversion_form(group, form);
+   }
+   else if (lua_isnumber(L, 2))
+@@ -206,7 +204,7 @@ EC_GROUP* openssl_get_ec_group(lua_State
+   }
+   else if (lua_isuserdata(L, ec_name_idx))
+   {
+-    if (auxiliar_isclass(L, "openssl.evp_pkey", ec_name_idx))
++    if (auxiliar_getclassudata(L, "openssl.evp_pkey", ec_name_idx))
+     {
+       EVP_PKEY* pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+       EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey);
+@@ -216,7 +214,7 @@ EC_GROUP* openssl_get_ec_group(lua_State
+         EC_KEY_free(ec_key);
+       }
+     }
+-    else if (auxiliar_isclass(L, "openssl.ec_key", ec_name_idx))
++    else if (auxiliar_getclassudata(L, "openssl.ec_key", ec_name_idx))
+     {
+       EC_KEY* ec_key = CHECK_OBJECT(1, EC_KEY, "openssl.ec_key");
+       g = (EC_GROUP*)EC_KEY_get0_group(ec_key);
+@@ -291,15 +289,131 @@ EC_GROUP* openssl_get_ec_group(lua_State
+   return g;
+ }
+ 
++static int openssl_ec_group_point_new(lua_State *L)
++{
++  EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  EC_POINT* point = EC_POINT_new(group);
++  PUSH_OBJECT(point, "openssl.ec_point");
++  return 1;
++}
++
++static int openssl_ec_point_dup(lua_State *L)
++{
++  const EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  const EC_POINT* point = CHECK_OBJECT(2, EC_POINT, "openssl.ec_point");
++
++  EC_POINT *new = EC_POINT_dup(point, group);
++  PUSH_OBJECT(new, "openssl.ec_point");
++  return 1;
++}
++
++static int openssl_ec_point_oct2point(lua_State *L)
++{
++  const EC_GROUP* group  = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  size_t size = 0;
++  const unsigned char* oct = (const unsigned char*)luaL_checklstring(L, 2, &size);
++  EC_POINT* point  = EC_POINT_new(group);
++
++  int ret = EC_POINT_oct2point(group, point, oct, size, NULL);
++  if(ret==1)
++    PUSH_OBJECT(point, "openssl.ec_point");
++  else
++    ret = openssl_pushresult(L, ret);
++  return ret;
++}
++
++static int openssl_ec_point_point2oct(lua_State *L)
++{
++  const EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  const EC_POINT* point = CHECK_OBJECT(2, EC_POINT, "openssl.ec_point");
++  point_conversion_form_t form = openssl_point_conversion_form(L, 3, NULL);
++  size_t size = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
++  if(size>0)
++  {
++    unsigned char* oct = (unsigned char*)OPENSSL_malloc(size);
++    size = EC_POINT_point2oct(group, point, form, oct, size, NULL);
++    if(size>0)
++      lua_pushlstring(L, (const char*)oct, size);
++    else
++      lua_pushnil(L);
++    OPENSSL_free(oct);
++    return 1;
++  }
++  return 0;
++}
++
++static int openssl_ec_point_bn2point(lua_State *L)
++{
++  const EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  BIGNUM *bn = CHECK_OBJECT(2, BIGNUM, "openssl.bn");
++  EC_POINT* pnt = EC_POINT_bn2point(group, bn, NULL, NULL);
++  if(pnt)
++    PUSH_OBJECT(pnt, "openssl.ec_point");
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++static int openssl_ec_point_point2bn(lua_State *L)
++{
++  const EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  const EC_POINT* point = CHECK_OBJECT(2, EC_POINT, "openssl.ec_point");
++  point_conversion_form_t form = openssl_point_conversion_form(L, 3, NULL);
++
++  BIGNUM *bn = EC_POINT_point2bn(group, point, form, NULL, NULL);
++  if(bn)
++    PUSH_OBJECT(bn, "openssl.bn");
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++static int openssl_ec_point_hex2point(lua_State *L)
++{
++  const EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  const char* hex = luaL_checkstring(L, 2);
++
++  EC_POINT* pnt = EC_POINT_hex2point(group, hex, NULL, NULL);
++  if(pnt)
++    PUSH_OBJECT(pnt, "openssl.ec_point");
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++static int openssl_ec_point_point2hex(lua_State *L)
++{
++  const EC_GROUP* group = CHECK_OBJECT(1, EC_GROUP, "openssl.ec_group");
++  const EC_POINT* point = CHECK_OBJECT(2, EC_POINT, "openssl.ec_point");
++  point_conversion_form_t form = openssl_point_conversion_form(L, 3, NULL);
++
++  const char* hex = EC_POINT_point2hex(group, point, form, NULL);
++  if(hex)
++    lua_pushstring(L, hex);
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++
+ static luaL_Reg ec_group_funs[] =
+ {
+-  {"__tostring", auxiliar_tostring},
+-  {"affine_coordinates", openssl_ecpoint_affine_coordinates},
+-  {"parse", openssl_ec_group_parse},
+-  {"asn1_flag", openssl_ec_group_asn1_flag},
+-  {"point_conversion_form", openssl_ec_group_point_conversion_form},
++  {"__tostring",            auxiliar_tostring},
++  {"__gc",                  openssl_ec_group_free},
+ 
+-  {"__gc", openssl_ec_group_free},
++  {"affine_coordinates",    openssl_ecpoint_affine_coordinates},
++  {"parse",                 openssl_ec_group_parse},
++  {"asn1_flag",             openssl_ec_group_asn1_flag},
++
++  {"point_conversion_form", openssl_ec_group_point_conversion_form},
++  {"point_new",             openssl_ec_group_point_new},
++  {"point_dup",             openssl_ec_point_dup},
++  {"point2oct",             openssl_ec_point_point2oct},
++  {"oct2point",             openssl_ec_point_oct2point},
++  {"point2bn",              openssl_ec_point_point2bn},
++  {"bn2point",              openssl_ec_point_bn2point},
++  {"point2hex",             openssl_ec_point_point2hex},
++  {"hex2point",             openssl_ec_point_hex2point},
+ 
+   { NULL, NULL }
+ };
+@@ -309,41 +423,89 @@ static int openssl_ecdsa_sign(lua_State*
+ {
+   EC_KEY* ec = CHECK_OBJECT(1, EC_KEY, "openssl.ec_key");
+   size_t l;
+-  const char* s = luaL_checklstring(L, 2, &l);
+-  ECDSA_SIG* sig = ECDSA_do_sign((const unsigned char*)s, l, ec);
+-  if (sig)
++  const char* sdata = luaL_checklstring(L, 2, &l);
++  ECDSA_SIG* sig = ECDSA_do_sign((const unsigned char*)sdata, l, ec);
++  int der = lua_isnone(L, 3) ? 1 : lua_toboolean(L, 3);
++  int ret = 0;
++
++  if (der)
+   {
+-    PUSH_BN(BN_dup(sig->r));
+-    PUSH_BN(BN_dup(sig->s));
+-    ECDSA_SIG_free(sig);
+-    return 2;
++    unsigned char*p = NULL;
++    l = i2d_ECDSA_SIG(sig, &p);
++    if (l > 0)
++    {
++      lua_pushlstring(L, (const char*)p, l);
++      OPENSSL_free(p);
++      ret = 1;
++    }
+   }
+-  return 0;
++  else
++  {
++    const BIGNUM *r = NULL, *s = NULL;
++    ECDSA_SIG_get0(sig, &r, &s);
++
++    r = BN_dup(r);
++    s = BN_dup(s);
++
++    PUSH_OBJECT(r, "openssl.bn");
++    PUSH_OBJECT(s, "openssl.bn");
++    ret = 2;
++  }
++  ECDSA_SIG_free(sig);
++  return ret;
+ }
+ 
+ static int openssl_ecdsa_verify(lua_State*L)
+ {
+-  size_t l;
++  size_t l, sigl;
+   int ret;
+   EC_KEY* ec = CHECK_OBJECT(1, EC_KEY, "openssl.ec_key");
+   const char* dgst = luaL_checklstring(L, 2, &l);
+-  BIGNUM *r = CHECK_OBJECT(3, BIGNUM, "openssl.bn");
+-  BIGNUM *s = CHECK_OBJECT(4, BIGNUM, "openssl.bn");
+-
+-  ECDSA_SIG* sig = ECDSA_SIG_new();
+-  BN_copy(sig->r, r);
+-  BN_copy(sig->s, s);
+-
+-  ret = ECDSA_do_verify((const unsigned char*)dgst, l, sig, ec);
+-  if (ret == -1)
+-    lua_pushnil(L);
++  int top = lua_gettop(L);
++  if (top == 3)
++  {
++    const char* s = luaL_checklstring(L, 3, &sigl);
++    ECDSA_SIG* sig = d2i_ECDSA_SIG(NULL, (const unsigned char**)&s, sigl);
++    ret = ECDSA_do_verify((const unsigned char*)dgst, l, sig, ec);
++    if (ret == -1)
++      ret = openssl_pushresult(L, -1);
++    else
++    {
++      lua_pushboolean(L, ret);
++      ret = 1;
++    }
++    ECDSA_SIG_free(sig);
++    return ret;
++  }
+   else
+-    lua_pushboolean(L, ret);
+-  ECDSA_SIG_free(sig);
+-  return 1;
++  {
++    BIGNUM *r = BN_get(L, 3);
++    BIGNUM *s = BN_get(L, 4);
++    ECDSA_SIG* sig = ECDSA_SIG_new();
++    ECDSA_SIG_set0(sig, r, s);
++    ret = ECDSA_do_verify((const unsigned char*)dgst, l, sig, ec);
++    if (ret == -1)
++      ret = openssl_pushresult(L, -1);
++    else
++    {
++      lua_pushboolean(L, ret);
++      ret = 1;
++    }
++    ECDSA_SIG_free(sig);
++    return ret;
++  }
++}
++
++/* ec_point */
++static int openssl_ec_point_copy(lua_State *L)
++{
++  EC_POINT* self = CHECK_OBJECT(1, EC_POINT, "openssl.ec_point");
++  EC_POINT* to = CHECK_OBJECT(2, EC_POINT, "openssl.ec_point");
++  int ret = EC_POINT_copy(to, self);
++  return openssl_pushresult(L, ret);
+ }
+ 
+-static int openssl_ec_point_free(lua_State*L)
++static int openssl_ec_point_free(lua_State *L)
+ {
+   EC_POINT* p = CHECK_OBJECT(1, EC_POINT, "openssl.ec_point");
+   EC_POINT_free(p);
+@@ -398,11 +560,119 @@ static int openssl_ec_key_parse(lua_Stat
+   return 1;
+ };
+ 
++# ifndef OPENSSL_NO_ECDH
++static const int KDF1_SHA1_len = 20;
++static void *KDF1_SHA1(const void *in, size_t inlen, void *out,
++                       size_t *outlen)
++{
++#  ifndef OPENSSL_NO_SHA
++  if (*outlen < SHA_DIGEST_LENGTH)
++    return NULL;
++  else
++    *outlen = SHA_DIGEST_LENGTH;
++  return SHA1(in, inlen, out);
++#  else
++  return NULL;
++#  endif                        /* OPENSSL_NO_SHA */
++}
++# endif                         /* OPENSSL_NO_ECDH */
++
++# define MAX_ECDH_SIZE 256
++
++static int openssl_ecdh_compute_key(lua_State*L)
++{
++  EC_KEY *ec = CHECK_OBJECT(1, EC_KEY, "openssl.ec_key");
++  EC_KEY *peer = CHECK_OBJECT(2, EC_KEY, "openssl.ec_key");
++
++  int field_size, outlen, secret_size_a;
++  unsigned char secret_a[MAX_ECDH_SIZE];
++  void *(*kdf) (const void *in, size_t inlen, void *out, size_t *xoutlen);
++  field_size =
++    EC_GROUP_get_degree(EC_KEY_get0_group(ec));
++  if (field_size <= 24 * 8)
++  {
++    outlen = KDF1_SHA1_len;
++    kdf = KDF1_SHA1;
++  }
++  else
++  {
++    outlen = (field_size + 7) / 8;
++    kdf = NULL;
++  }
++  secret_size_a =
++    ECDH_compute_key(secret_a, outlen,
++                     EC_KEY_get0_public_key(peer),
++                     ec, kdf);
++  lua_pushlstring(L, (const char*)secret_a, secret_size_a);
++  return 1;
++}
++
++static int openssl_ecdsa_set_method(lua_State *L)
++{
++  EC_KEY *ec = CHECK_OBJECT(1, EC_KEY, "openssl.ec_key");
++  ENGINE *e = CHECK_OBJECT(2, ENGINE, "openssl.engine");
++#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L
++  const ECDSA_METHOD *m = ENGINE_get_ECDSA(e);
++  if (m)
++  {
++    int r = ECDSA_set_method(ec, m);
++    return openssl_pushresult(L, r);
++  }
++#else
++  const EC_KEY_METHOD *m = ENGINE_get_EC(e);
++  if (m)
++  {
++    int r = EC_KEY_set_method(ec, m);
++    return openssl_pushresult(L, r);
++  }
++#endif
++  return 0;
++}
++
++static int openssl_ec_key_export(lua_State *L)
++{
++  EC_KEY *ec = CHECK_OBJECT(1, EC_KEY, "openssl.ec_key");
++  unsigned char* der = NULL;
++  int len = i2d_ECPrivateKey(ec, &der);
++  if(len>0)
++    lua_pushlstring(L, (const char*)der, len);
++  else
++    lua_pushnil(L);
++  if(der)
++    OPENSSL_free(der);
++  return 1;
++}
++
++static int openssl_ec_key_read(lua_State *L)
++{
++  size_t len = 0;
++  const unsigned char* der = (const unsigned char*)luaL_checklstring(L, 1, &len);
++
++  EC_KEY* ec = d2i_ECPrivateKey(NULL, &der, len);
++  if(ec)
++    PUSH_OBJECT(ec, "openssl.ec_key");
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++#ifdef EC_EXT
++EC_EXT_DEFINE
++#endif
++
+ static luaL_Reg ec_key_funs[] =
+ {
++  {"export",      openssl_ec_key_export},
+   {"parse",       openssl_ec_key_parse},
+   {"sign",        openssl_ecdsa_sign},
+   {"verify",      openssl_ecdsa_verify},
++  {"compute_key", openssl_ecdh_compute_key},
++  {"set_method",  openssl_ecdsa_set_method},
++
++#ifdef EC_EXT
++  EC_EXT
++#endif
++
+   {"__gc",        openssl_ec_key_free},
+   {"__tostring",  auxiliar_tostring},
+ 
+@@ -411,8 +681,9 @@ static luaL_Reg ec_key_funs[] =
+ 
+ static luaL_Reg ec_point_funs[] =
+ {
+-  {"__tostring", auxiliar_tostring},
+-  {"__gc", openssl_ec_point_free},
++  {"__tostring",  auxiliar_tostring},
++  {"__gc",        openssl_ec_point_free},
++  {"copy",        openssl_ec_point_copy},
+ 
+   { NULL, NULL }
+ };
+@@ -452,8 +723,9 @@ static LUA_FUNCTION(openssl_ec_list_curv
+ 
+ static luaL_Reg R[] =
+ {
+-  {"list", openssl_ec_list_curve_name},
+-  {"group", openssl_eckey_group},
++  {"read",     openssl_ec_key_read},
++  {"list",     openssl_ec_list_curve_name},
++  {"group",    openssl_eckey_group},
+ 
+   { NULL, NULL }
+ };
+@@ -462,7 +734,7 @@ int luaopen_ec(lua_State *L)
+ {
+   auxiliar_newclass(L, "openssl.ec_point",   ec_point_funs);
+   auxiliar_newclass(L, "openssl.ec_group",   ec_group_funs);
+-  auxiliar_newclass(L, "openssl.ec_key",   ec_key_funs);
++  auxiliar_newclass(L, "openssl.ec_key",     ec_key_funs);
+ 
+   lua_newtable(L);
+   luaL_setfuncs(L, R, 0);
+@@ -474,4 +746,3 @@ int luaopen_ec(lua_State *L)
+ }
+ 
+ #endif
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/engine.c luvi-src-v2.7.6/deps/lua-openssl/src/engine.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/engine.c	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/engine.c	2019-02-13 11:53:24.275126573 +0100
+@@ -8,18 +8,28 @@
+ #include <openssl/engine.h>
+ #include "openssl.h"
+ #include "private.h"
++#include <openssl/ssl.h>
+ 
+ enum
+ {
+   TYPE_RSA,
+   TYPE_DSA,
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+   TYPE_ECDH,
+   TYPE_ECDSA,
++#else
++  TYPE_EC,
++#endif
+   TYPE_DH,
+   TYPE_RAND,
+-  TYPE_STORE,
+   TYPE_CIPHERS,
+   TYPE_DIGESTS,
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++  TYPE_STORE,
++#else
++  TYPE_PKEY_METHODS,
++  TYPE_PKEY_ASN1_METHODS,
++#endif
+   TYPE_COMPLETE
+ };
+ 
+@@ -140,6 +150,7 @@ static int openssl_engine_register(lua_S
+       else
+         ENGINE_register_DSA(eng);
+       break;
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+     case TYPE_ECDH:
+       if (unregister)
+         ENGINE_unregister_ECDH(eng);
+@@ -152,6 +163,14 @@ static int openssl_engine_register(lua_S
+       else
+         ENGINE_register_ECDSA(eng);
+       break;
++#else
++    case TYPE_EC:
++      if (unregister)
++        ENGINE_unregister_EC(eng);
++      else
++        ENGINE_register_EC(eng);
++      break;
++#endif
+     case TYPE_DH:
+       if (unregister)
+         ENGINE_unregister_DH(eng);
+@@ -164,12 +183,27 @@ static int openssl_engine_register(lua_S
+       else
+         ENGINE_register_RAND(eng);
+       break;
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+     case TYPE_STORE:
+       if (unregister)
+         ENGINE_unregister_STORE(eng);
+       else
+         ENGINE_register_STORE(eng);
+       break;
++#else
++    case TYPE_PKEY_METHODS:
++      if (unregister)
++        ENGINE_unregister_pkey_meths(eng);
++      else
++        ENGINE_register_pkey_meths(eng);
++      break;
++    case TYPE_PKEY_ASN1_METHODS:
++      if (unregister)
++        ENGINE_unregister_pkey_asn1_meths(eng);
++      else
++        ENGINE_register_pkey_asn1_meths(eng);
++      break;
++#endif
+     case TYPE_CIPHERS:
+       if (unregister)
+         ENGINE_unregister_ciphers(eng);
+@@ -201,22 +235,20 @@ static int openssl_engine_register(lua_S
+ static int openssl_engine_ctrl(lua_State*L)
+ {
+   ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
+-
++  int ret = 0;
+   if (lua_isnumber(L, 2))
+   {
+     int cmd = luaL_checkint(L, 2);
+     if (lua_isnoneornil(L, 3))
+     {
+-      int ret = ENGINE_cmd_is_executable(eng, cmd);
+-      lua_pushboolean(L, ret);
++      ret = ENGINE_cmd_is_executable(eng, cmd);
+     }
+     else
+     {
+       long i = (long)luaL_checknumber(L, 3);
+       void* p = lua_touserdata(L, 4);
+       void* arg = lua_isnoneornil(L, 5) ? NULL : lua_touserdata(L, 5);
+-      int ret = ENGINE_ctrl(eng, cmd, i, p, arg);
+-      lua_pushboolean(L, ret);
++      ret = ENGINE_ctrl(eng, cmd, i, p, arg);
+     }
+   }
+   else
+@@ -225,27 +257,35 @@ static int openssl_engine_ctrl(lua_State
+     if (lua_isnumber(L, 3))
+     {
+       long i = (long)luaL_checknumber(L, 3);
+-      void* p = lua_touserdata(L, 4);
+-      void* arg = lua_isnoneornil(L, 5) ? NULL : lua_touserdata(L, 5);
+-      int opt = luaL_optint(L, 6, 0);
+-      int ret = ENGINE_ctrl_cmd(eng, cmd, i, p, arg, opt);
+-      lua_pushboolean(L, ret);
++      if (lua_isstring(L, 4))
++      {
++        const char* s = lua_tostring(L, 4);
++        void* arg = lua_isnoneornil(L, 5) ? NULL : lua_touserdata(L, 5);
++        int opt = luaL_optint(L, 6, 0);
++        ret = ENGINE_ctrl_cmd(eng, cmd, i, (void*)s, arg, opt);
++      }
++      else
++      {
++        void* p = lua_touserdata(L, 4);
++        void* arg = lua_isnoneornil(L, 5) ? NULL : lua_touserdata(L, 5);
++        int opt = luaL_optint(L, 6, 0);
++        ret = ENGINE_ctrl_cmd(eng, cmd, i, p, arg, opt);
++      }
+     }
+     else
+     {
+       const char* arg  = luaL_optstring(L, 3, NULL);
+       int opt = luaL_optint(L, 4, 0);
+-      int ret = ENGINE_ctrl_cmd_string(eng, cmd, arg, opt);
+-      lua_pushboolean(L, ret);
++      ret = ENGINE_ctrl_cmd_string(eng, cmd, arg, opt);
+     }
+   }
+-  return 1;
++  return openssl_pushresult(L, ret);
+ }
+ 
+ static int openssl_engine_gc(lua_State*L)
+ {
+   ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
+-  (void*) eng;
++  (void) eng;
+   return 0;
+ }
+ 
+@@ -297,11 +337,11 @@ static int openssl_engine_flags(lua_Stat
+   lua_pushinteger(L, ENGINE_get_flags(eng));
+   return 1;
+ }
++
+ /*
+ int ENGINE_set_ex_data(ENGINE *e, int idx, void *arg);
+ void *ENGINE_get_ex_data(const ENGINE *e, int idx);
+ */
+-
+ static int openssl_engine_init(lua_State*L)
+ {
+   ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
+@@ -310,7 +350,6 @@ static int openssl_engine_init(lua_State
+   return 1;
+ }
+ 
+-
+ static int openssl_engine_finish(lua_State*L)
+ {
+   ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
+@@ -319,7 +358,6 @@ static int openssl_engine_finish(lua_Sta
+   return 1;
+ }
+ 
+-
+ static int openssl_engine_set_default(lua_State*L)
+ {
+   ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
+@@ -340,8 +378,7 @@ static int openssl_engine_set_default(lu
+     }
+     else
+       luaL_error(L, "#2 must be a number or string");
+-    lua_pushboolean(L, ret);
+-    return 1;
++    return openssl_pushresult(L, ret);
+   }
+ 
+   while (first <= top)
+@@ -355,12 +392,18 @@ static int openssl_engine_set_default(lu
+     case TYPE_DSA:
+       ret = ENGINE_set_default_DSA(eng);
+       break;
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+     case TYPE_ECDH:
+       ret = ENGINE_set_default_ECDH(eng);
+       break;
+     case TYPE_ECDSA:
+       ret = ENGINE_set_default_ECDSA(eng);
+       break;
++#else
++    case TYPE_EC:
++      ret = ENGINE_set_default_EC(eng);
++      break;
++#endif
+     case TYPE_DH:
+       ret = ENGINE_set_default_DH(eng);
+       break;
+@@ -384,36 +427,156 @@ static int openssl_engine_set_default(lu
+       return 1;
+     }
+   }
+-  lua_pushboolean(L, ret);
+-  return 1;
++  return openssl_pushresult(L, ret);
++};
++
++static int openssl_engine_set_rand_engine(lua_State *L)
++{
++  ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
++  int ret = RAND_set_rand_engine(eng);
++  return openssl_pushresult(L, ret);
++}
++
++static int openssl_engine_load_private_key(lua_State *L)
++{
++  ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
++  const char* key_id = luaL_checkstring(L, 2);
++  EVP_PKEY *pkey = ENGINE_load_private_key(eng, key_id, NULL, NULL);
++  if (pkey != NULL)
++  {
++    PUSH_OBJECT(pkey, "openssl.evp_pkey");
++    return 1;
++  }
++  return openssl_pushresult(L, 0);
++}
++
++static int openssl_engine_load_public_key(lua_State *L)
++{
++  ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
++  const char* key_id = luaL_checkstring(L, 2);
++  EVP_PKEY *pkey = ENGINE_load_public_key(eng, key_id, NULL, NULL);
++  if (pkey != NULL)
++  {
++    PUSH_OBJECT(pkey, "openssl.evp_pkey");
++    return 1;
++  }
++  return openssl_pushresult(L, 0);
++}
++
++static int openssl_engine_load_ssl_client_cert(lua_State *L)
++{
++  ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
++  SSL* s = CHECK_OBJECT(2, SSL, "openssl.ssl");
++  STACK_OF(X509_NAME) *ca_dn = SSL_get_client_CA_list(s);
++
++  X509 *pcert = NULL;
++  EVP_PKEY *pkey = NULL;
++  STACK_OF(X509) *pothers = NULL;
++
++  int ret = ENGINE_load_ssl_client_cert(eng, s, ca_dn,
++                                        &pcert, &pkey, &pothers, NULL, NULL);
++  if (ret == 1)
++  {
++    PUSH_OBJECT(pcert, "openssl.x509");
++    if (pkey != NULL)
++    {
++      PUSH_OBJECT(pkey, "openssl.pkey");
++      ret++;
++    }
++    if (pothers != NULL)
++    {
++      openssl_sk_x509_totable(L, pothers);
++      ret++;
++    }
++    return ret;
++  }
++  return openssl_pushresult(L, 0);
++}
++
++struct _engine_exdata
++{
++  int l;
++  unsigned char p[1];
+ };
+ 
++static int openssl_engine_ex_data(lua_State *L)
++{
++  ENGINE* eng = CHECK_OBJECT(1, ENGINE, "openssl.engine");
++  int idx;
++  int ret;
++  if (lua_isnoneornil(L, 2))
++  {
++    idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, NULL);
++    if (idx == -1)
++    {
++      lua_pushnil(L);
++      return 1;
++    }
++    lua_pushinteger(L, idx);
++    return 1;
++  }
++  idx = luaL_checkinteger(L, 2);
++  if (lua_isnoneornil(L, 3))
++  {
++    void *p = ENGINE_get_ex_data(eng, idx);
++    if (p)
++    {
++      struct _engine_exdata *ex = p;
++      lua_pushlstring(L, (const char*)ex->p, ex->l);
++    }
++    else
++      lua_pushnil(L);
++    return 1;
++  }
++  else
++  {
++    size_t l;
++    const char *s = luaL_checklstring(L, 3, &l);
++    struct _engine_exdata *ex = OPENSSL_malloc(sizeof(struct _engine_exdata)+l);
++    ex->l = l;
++    memcpy(ex->p, s, l);
++    ret = ENGINE_set_ex_data(eng, idx, ex);
++    if (ret != 1)
++    {
++      OPENSSL_free(ex);
++      lua_pushnil(L);
++    }
++    else
++      lua_pushboolean(L, 1);
++    return 1;
++  }
++}
++
+ static luaL_Reg eng_funcs[] =
+ {
+   {"next",      openssl_engine_next},
+   {"prev",      openssl_engine_prev},
+   {"add",       openssl_engine_add},
+-  {"remove",      openssl_engine_remove},
+-  {"register",    openssl_engine_register},
++  {"remove",    openssl_engine_remove},
++  {"register",  openssl_engine_register},
+   {"ctrl",      openssl_engine_ctrl},
+   {"id",        openssl_engine_id},
+   {"name",      openssl_engine_name},
+   {"flags",     openssl_engine_flags},
+ 
+-  {"init",      openssl_engine_init},
+-  {"finish",      openssl_engine_finish},
++  {"ex_data",               openssl_engine_ex_data},
++  {"set_rand_engine",       openssl_engine_set_rand_engine},
++  {"load_private_key",      openssl_engine_load_private_key},
++  {"load_public_key",       openssl_engine_load_public_key },
++  {"load_ssl_client_cert",  openssl_engine_load_ssl_client_cert},
++
++  {"init",          openssl_engine_init},
++  {"finish",        openssl_engine_finish},
+   {"set_default",   openssl_engine_set_default},
+ 
+-  {"__gc",      openssl_engine_gc},
++  {"__gc",          openssl_engine_gc},
+   {"__tostring",    auxiliar_tostring},
+ 
+   {NULL,      NULL},
+ };
+ 
+-
+ int openssl_register_engine(lua_State* L)
+ {
+   auxiliar_newclass(L, "openssl.engine", eng_funcs);
+   return 0;
+ }
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/hmac.c luvi-src-v2.7.6/deps/lua-openssl/src/hmac.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/hmac.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/hmac.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,33 +1,127 @@
+-/*=========================================================================*\
+-* hamc.c
+-* hamc module for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++hamc module for lua-openssl binding
+ 
++@module hmac
++@author  george zhao <zhaozg(at)gmail.com>
++@usage
++  hamc = require('openssl').hmac
++*/
+ #include "openssl.h"
+ #include "private.h"
+-#include <openssl/hmac.h>
+ 
+ #define MYNAME    "hmac"
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
++/***
++get hamc_ctx object
++
++@function new
++@tparam string|integer|asn1_object alg name, nid or object identity
++@tparam string key secret key
++@tparam[opt] engine engine, nothing with default engine
++@treturn hamc_ctx hmac object mapping HMAC_CTX in openssl
++
++@see hmac_ctx
++*/
+ static int openssl_hmac_new(lua_State *L)
+ {
+-  const EVP_MD *type = get_digest(L, 1);
++  const EVP_MD *type = get_digest(L, 1, NULL);
+   size_t l;
+   const char *k = luaL_checklstring(L, 2, &l);
+   ENGINE* e = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, ENGINE, "openssl.engine");
+ 
+-  HMAC_CTX *c = OPENSSL_malloc(sizeof(HMAC_CTX));
+-  HMAC_CTX_init(c);
++  HMAC_CTX *c = HMAC_CTX_new();
+   HMAC_Init_ex(c, k, (int)l, type, e);
+   PUSH_OBJECT(c, "openssl.hmac_ctx");
+ 
+   return 1;
+ }
+ 
++static int openssl_hmac_free(lua_State *L)
++{
++  HMAC_CTX *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
++  if(!c)
++    return 0;
++  HMAC_CTX_free(c);
++  FREE_OBJECT(1);
++  return 0;
++}
++
++/***
++compute hmac one step, in module openssl.hamc
++
++@function hmac
++@tparam evp_digest|string|nid digest digest alg identity
++@tparam string message
++@tparam string key
++@treturn string result binary string
++*/
++/***
++alias for hmac
++
++@function digest
++@tparam evp_digest|string|nid digest digest alg identity
++@tparam string message
++@tparam string key
++@treturn string result binary string
++*/
++static int openssl_hmac(lua_State *L)
++{
++  if (lua_istable(L, 1))
++  {
++    if (lua_getmetatable(L, 1) && lua_equal(L, 1, -1))
++    {
++      lua_pop(L, 1);
++      lua_remove(L, 1);
++    }
++    else
++      luaL_error(L, "call function with invalid state");
++  }
++  {
++
++    const EVP_MD *type = get_digest(L, 1, NULL);
++    size_t len;
++    const char *dat = luaL_checklstring(L, 2, &len);
++    size_t l;
++    const char *k = luaL_checklstring(L, 3, &l);
++    int raw = (lua_isnoneornil(L, 4)) ? 0 : lua_toboolean(L, 4);
++    ENGINE* e = lua_isnoneornil(L, 5) ? NULL : CHECK_OBJECT(5, ENGINE, "openssl.engine");
++
++    unsigned char digest[EVP_MAX_MD_SIZE];
++
++    HMAC_CTX *c = HMAC_CTX_new();
++    HMAC_Init_ex(c, k, (int)l, type, e);
++
++    HMAC_Update(c, (unsigned char *)dat, len);
++    len = EVP_MAX_MD_SIZE;
++    HMAC_Final(c, digest, (unsigned int*)&len);
++
++    HMAC_CTX_free(c);
++
++    if (raw)
++      lua_pushlstring(L, (char *)digest, len);
++    else
++    {
++      char hex[2 * EVP_MAX_MD_SIZE + 1];
++      to_hex((const char*)digest, len, hex);
++      lua_pushstring(L, hex);
++    }
++  }
++  return 1;
++}
++
++/***
++openssl.hmac_ctx object
++@type hmac_ctx
++*/
++
++/***
++feed data to do digest
++
++@function update
++@tparam string msg data
++*/
+ static int openssl_hmac_update(lua_State *L)
+ {
+   HMAC_CTX *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
+@@ -38,6 +132,14 @@ static int openssl_hmac_update(lua_State
+   return 0;
+ }
+ 
++/***
++get result of hmac
++
++@function final
++@tparam[opt] string last last part of data
++@tparam[opt] boolean raw binary or hex encoded result, default true for binary result
++@treturn string val hash result
++*/
+ static int openssl_hmac_final(lua_State *L)
+ {
+   HMAC_CTX *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
+@@ -70,6 +172,11 @@ static int openssl_hmac_final(lua_State
+   return 1;
+ }
+ 
++/***
++reset hmac_ctx to reuse
++
++@function reset
++*/
+ static int openssl_hmac_reset(lua_State *L)
+ {
+   HMAC_CTX *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
+@@ -77,61 +184,6 @@ static int openssl_hmac_reset(lua_State
+   return openssl_pushresult(L, ret);
+ }
+ 
+-static int openssl_hmac_free(lua_State *L)
+-{
+-  HMAC_CTX *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
+-  HMAC_CTX_cleanup(c);
+-  OPENSSL_free(c);
+-  return 0;
+-}
+-
+-static int openssl_hmac(lua_State *L)
+-{
+-  if (lua_istable(L, 1))
+-  {
+-    if (lua_getmetatable(L, 1) && lua_equal(L, 1, -1))
+-    {
+-      lua_pop(L, 1);
+-      lua_remove(L, 1);
+-    }
+-    else
+-      luaL_error(L, "call function with invalid state");
+-  }
+-  {
+-
+-    const EVP_MD *type = get_digest(L, 1);
+-    size_t len;
+-    const char *dat = luaL_checklstring(L, 2, &len);
+-    size_t l;
+-    const char *k = luaL_checklstring(L, 3, &l);
+-    int raw = (lua_isnoneornil(L, 4)) ? 0 : lua_toboolean(L, 4);
+-    ENGINE* e = lua_isnoneornil(L, 5) ? NULL : CHECK_OBJECT(5, ENGINE, "openssl.engine");
+-
+-    unsigned char digest[EVP_MAX_MD_SIZE];
+-
+-    HMAC_CTX ctx;
+-    HMAC_CTX *c = &ctx;
+-    HMAC_CTX_init(c);
+-    HMAC_Init_ex(c, k, (int)l, type, e);
+-
+-    HMAC_Update(c, (unsigned char *)dat, len);
+-    len = EVP_MAX_MD_SIZE;
+-    HMAC_Final(c, digest, (unsigned int*)&len);
+-
+-    HMAC_CTX_cleanup(c);
+-
+-    if (raw)
+-      lua_pushlstring(L, (char *)digest, len);
+-    else
+-    {
+-      char hex[2 * EVP_MAX_MD_SIZE + 1];
+-      to_hex((const char*)digest, len, hex);
+-      lua_pushstring(L, hex);
+-    }
+-  }
+-  return 1;
+-}
+-
+ static luaL_Reg hmac_ctx_funs[] =
+ {
+   {"update",  openssl_hmac_update},
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/lbn.c luvi-src-v2.7.6/deps/lua-openssl/src/lbn.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/lbn.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/lbn.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,9 +1,10 @@
+-/*
+-* lbn.c
+-* big-number library for Lua 5.1 based on OpenSSL bn
+-* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
+-* 11 Nov 2010 22:56:45
+-* This code is hereby placed in the public domain.
++/***
++big-number library for Lua 5.1 based on OpenSSL bn
++
++@module bn
++@author Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
++@license This code is hereby placed in the public domain.
++@warning verson 11 Nov 2010 22:56:45
+ */
+ 
+ #include <stdlib.h>
+@@ -22,17 +23,11 @@
+ 
+ #include "private.h"
+ 
+-#define lua_boxpointer(L,u) \
+-  (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
+-
+ #define MYNAME    "bn"
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2010 / "\
+       "based on OpenSSL " SHLIB_VERSION_NUMBER
+ #define MYTYPE    "openssl.bn"
+ 
+-
+-static BN_CTX *ctx = NULL;
+-
+ static void error(lua_State *L, const char *message)
+ {
+   luaL_error(L, "(bn) %s %s", message, ERR_reason_error_string(ERR_get_error()));
+@@ -42,9 +37,7 @@ static BIGNUM *Bnew(lua_State *L)
+ {
+   BIGNUM *x = BN_new();
+   if (x == NULL) error(L, "BN_new failed");
+-  lua_boxpointer(L, x);
+-  luaL_getmetatable(L, MYTYPE);
+-  lua_setmetatable(L, -2);
++  PUSH_BN(x);
+   return x;
+ }
+ 
+@@ -183,7 +176,9 @@ static int Bsqr(lua_State *L)     /** sq
+ {
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_sqr(c, a, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -236,7 +231,9 @@ static int Bmul(lua_State *L)     /** mu
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mul(c, a, b, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -246,7 +243,9 @@ static int Bdiv(lua_State *L)     /** di
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *q = Bnew(L);
+   BIGNUM *r = NULL;
++  BN_CTX *ctx = BN_CTX_new();
+   BN_div(q, r, a, b, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -256,7 +255,9 @@ static int Bmod(lua_State *L)     /** mo
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *q = NULL;
+   BIGNUM *r = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_div(q, r, a, b, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -265,7 +266,9 @@ static int Brmod(lua_State *L)      /**
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *r = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_nnmod(r, a, b, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -275,7 +278,9 @@ static int Bdivmod(lua_State *L)    /**
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *q = Bnew(L);
+   BIGNUM *r = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_div(q, r, a, b, ctx);
++  BN_CTX_free(ctx);
+   return 2;
+ }
+ 
+@@ -284,7 +289,9 @@ static int Bgcd(lua_State *L)     /** gc
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_gcd(c, a, b, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -293,7 +300,9 @@ static int Bpow(lua_State *L)     /** po
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_exp(c, a, b, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -303,7 +312,9 @@ static int Baddmod(lua_State *L)    /**
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *m = Bget(L, 3);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mod_add(c, a, b, m, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -313,7 +324,9 @@ static int Bsubmod(lua_State *L)    /**
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *m = Bget(L, 3);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mod_sub(c, a, b, m, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -323,7 +336,9 @@ static int Bmulmod(lua_State *L)    /**
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *m = Bget(L, 3);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mod_mul(c, a, b, m, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -333,7 +348,9 @@ static int Bpowmod(lua_State *L)    /**
+   BIGNUM *b = Bget(L, 2);
+   BIGNUM *m = Bget(L, 3);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mod_exp(c, a, b, m, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -342,7 +359,9 @@ static int Bsqrmod(lua_State *L)    /**
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *m = Bget(L, 2);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mod_sqr(c, a, m, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -351,7 +370,9 @@ static int Binvmod(lua_State *L)    /**
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *m = Bget(L, 2);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mod_inverse(c, a, m, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -360,7 +381,9 @@ static int Bsqrtmod(lua_State *L)   /**
+   BIGNUM *a = Bget(L, 1);
+   BIGNUM *m = Bget(L, 2);
+   BIGNUM *c = Bnew(L);
++  BN_CTX *ctx = BN_CTX_new();
+   BN_mod_sqrt(c, a, m, ctx);
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -387,7 +410,9 @@ static int Bisprime(lua_State *L)   /**
+ {
+   int checks = luaL_optint(L, 2, BN_prime_checks);
+   BIGNUM *a = Bget(L, 1);
++  BN_CTX *ctx = BN_CTX_new();
+   lua_pushboolean(L, BN_is_prime_fasttest_ex(a, checks, ctx, 1, NULL));
++  BN_CTX_free(ctx);
+   return 1;
+ }
+ 
+@@ -450,7 +475,6 @@ static const luaL_Reg R[] =
+ 
+ int luaopen_bn(lua_State *L)
+ {
+-  ctx = BN_CTX_new();
+   ERR_load_BN_strings();
+   RAND_seed(MYVERSION, sizeof(MYVERSION));
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/lhash.c luvi-src-v2.7.6/deps/lua-openssl/src/lhash.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/lhash.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/lhash.c	2019-02-13 11:53:24.275126573 +0100
+@@ -8,6 +8,7 @@
+ #include "private.h"
+ #include <openssl/conf.h>
+ 
++#if 0
+ static void table2data(lua_State*L, int idx, BIO* bio)
+ {
+   lua_pushnil(L);
+@@ -27,6 +28,7 @@ static void table2data(lua_State*L, int
+     lua_pop(L, 1);
+   }
+ }
++#endif
+ 
+ static LUA_FUNCTION(openssl_lhash_read)
+ {
+@@ -44,7 +46,6 @@ static LUA_FUNCTION(openssl_lhash_read)
+     lua_pushfstring(L, "ERROR at LINE %d", eline);
+     return luaL_argerror(L, 1, lua_tostring(L, -1));
+   }
+-  return 0;
+ }
+ 
+ 
+@@ -128,19 +129,25 @@ static void dump_value_doall_arg(CONF_VA
+     }
+   }
+ }
+-#if OPENSSL_VERSION_NUMBER >= 0x10000002L
++
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L && defined(LIBRESSL_VERSION_NUMBER)==0
++IMPLEMENT_LHASH_DOALL_ARG_CONST(CONF_VALUE, lua_State);
++#elif OPENSSL_VERSION_NUMBER >= 0x10000002L
+ static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_value, CONF_VALUE, lua_State)
+ #endif
++#if defined(LIBRESSL_VERSION_NUMBER)==0
+ #define LHM_lh_doall_arg(type, lh, fn, arg_type, arg) \
+   lh_doall_arg(CHECKED_LHASH_OF(type, lh), fn, CHECKED_PTR_OF(arg_type, arg))
+-
++#endif
+ 
+ static LUA_FUNCTION(openssl_lhash_parse)
+ {
+   LHASH* lhash = CHECK_OBJECT(1, LHASH, "openssl.lhash");
+ 
+   lua_newtable(L);
+-#if OPENSSL_VERSION_NUMBER >= 0x10000002L
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L && defined(LIBRESSL_VERSION_NUMBER)==0
++  lh_CONF_VALUE_doall_lua_State(lhash, dump_value_doall_arg, L);
++#elif OPENSSL_VERSION_NUMBER >= 0x10000002L
+   lh_CONF_VALUE_doall_arg(lhash, LHASH_DOALL_ARG_FN(dump_value), lua_State, L);
+ #else
+   lh_doall_arg(lhash, (LHASH_DOALL_ARG_FN_TYPE)dump_value_doall_arg, L);
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/misc.c luvi-src-v2.7.6/deps/lua-openssl/src/misc.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/misc.c	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/misc.c	2019-02-13 11:53:24.275126573 +0100
+@@ -25,10 +25,10 @@ BIO* load_bio_object(lua_State* L, int i
+     /* read only */
+     bio = (BIO*)BIO_new_mem_buf((void*)ctx, l);
+   }
+-  else if (auxiliar_isclass(L, "openssl.bio", idx))
++  else if (auxiliar_getclassudata(L, "openssl.bio", idx))
+   {
+     bio = CHECK_OBJECT(idx, BIO, "openssl.bio");
+-    CRYPTO_add(&bio->references, 1, CRYPTO_LOCK_BIO);
++    BIO_up_ref(bio);
+   }
+   else
+     luaL_argerror(L, idx, "only support string or openssl.bio");
+@@ -39,29 +39,40 @@ int  bio_is_der(BIO* bio)
+ {
+   byte head[1];
+   int len = BIO_read(bio, head, sizeof(head));
+-  BIO_reset(bio);
++  (void)BIO_reset(bio);
+   if (len == sizeof(head) && head[0] == 0x30)
+-  {
+     return 1;
+-  }
+ 
+   return 0;
+ }
+ 
+-const EVP_MD* get_digest(lua_State* L, int idx)
++const EVP_MD* get_digest(lua_State* L, int idx, const char* def_alg)
+ {
+   const EVP_MD* md = NULL;
+-  if (lua_isstring(L, idx))
++  switch (lua_type(L, idx))
++  {
++  case LUA_TSTRING:
+     md = EVP_get_digestbyname(lua_tostring(L, idx));
+-  else if (lua_isnumber(L, idx))
++    break;
++  case LUA_TNUMBER:
+     md = EVP_get_digestbynid(lua_tointeger(L, idx));
+-  else if (auxiliar_isclass(L, "openssl.asn1_object", idx))
+-    md = EVP_get_digestbyobj(CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object"));
+-  else if (auxiliar_isclass(L, "openssl.evp_digest", idx))
+-    md = CHECK_OBJECT(idx, EVP_MD, "openssl.evp_digest");
+-  else
++    break;
++  case LUA_TUSERDATA:
++    if (auxiliar_getclassudata(L, "openssl.asn1_object", idx))
++      md = EVP_get_digestbyobj(CHECK_OBJECT(idx, ASN1_OBJECT, "openssl.asn1_object"));
++    else if (auxiliar_getclassudata(L, "openssl.evp_digest", idx))
++      md = CHECK_OBJECT(idx, EVP_MD, "openssl.evp_digest");
++    break;
++  case LUA_TNONE:
++  case LUA_TNIL:
++    if (def_alg != NULL)
++      md = EVP_get_digestbyname(def_alg);
++    break;
++  }
++
++  if (md==NULL)
+   {
+-    luaL_error(L, "argument #1 must be a string, NID number or asn1_object identity digest method");
++    luaL_argerror(L, idx, "must be a string, NID number or asn1_object identity digest method");
+   }
+ 
+   return md;
+@@ -70,20 +81,30 @@ const EVP_MD* get_digest(lua_State* L, i
+ const EVP_CIPHER* get_cipher(lua_State*L, int idx, const char* def_alg)
+ {
+   const EVP_CIPHER* cipher = NULL;
+-  if (lua_isstring(L, idx))
++
++  switch (lua_type(L, idx))
++  {
++  case LUA_TSTRING:
+     cipher = EVP_get_cipherbyname(lua_tostring(L, idx));
+-  else if (lua_isnumber(L, idx))
++    break;
++  case LUA_TNUMBER:
+     cipher = EVP_get_cipherbynid(lua_tointeger(L, idx));
+-  else if (auxiliar_isclass(L, "openssl.asn1_object", idx))
+-    cipher = EVP_get_cipherbyobj(CHECK_OBJECT(1, ASN1_OBJECT, "openssl.asn1_object"));
+-  else if (auxiliar_isclass(L, "openssl.evp_cipher", idx))
+-    cipher = CHECK_OBJECT(idx, EVP_CIPHER, "openssl.evp_cipher");
+-  else if (lua_isnoneornil(L, idx) && def_alg)
+-    cipher = EVP_get_cipherbyname(def_alg);
+-  else
++    break;
++  case LUA_TUSERDATA:
++    if (auxiliar_getclassudata(L, "openssl.asn1_object", idx))
++      cipher = EVP_get_cipherbyobj(CHECK_OBJECT(idx, ASN1_OBJECT, "openssl.asn1_object"));
++    else if (auxiliar_getclassudata(L, "openssl.evp_cipher", idx))
++      cipher = CHECK_OBJECT(idx, EVP_CIPHER, "openssl.evp_cipher");
++    break;
++  case LUA_TNONE:
++  case LUA_TNIL:
++    if (def_alg != NULL)
++      cipher = EVP_get_cipherbyname(def_alg);
++    break;
++  }
++
++  if (cipher==NULL)
+     luaL_argerror(L, idx, "must be a string, NID number or asn1_object identity cipher method");
+-  if (cipher == NULL)
+-    luaL_argerror(L, idx, "not valid cipher alg");
+ 
+   return cipher;
+ }
+@@ -105,6 +126,11 @@ BIGNUM *BN_get(lua_State *L, int i)
+   }
+   case LUA_TUSERDATA:
+     BN_copy(x, CHECK_OBJECT(i, BIGNUM, "openssl.bn"));
++    break;
++  case LUA_TNIL:
++    BN_free(x);
++    x = NULL;
++    break;
+   }
+   return x;
+ }
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/ocsp.c luvi-src-v2.7.6/deps/lua-openssl/src/ocsp.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/ocsp.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/ocsp.c	2019-02-13 11:53:24.275126573 +0100
+@@ -36,7 +36,7 @@ static int openssl_ocsp_request_new(lua_
+     ASN1_BIT_STRING *ikey = X509_get0_pubkey_bitstr(issuer);
+ 
+     OCSP_CERTID *id = NULL;
+-    OCSP_ONEREQ *one;
++    OCSP_ONEREQ *one = NULL;
+     char buf[1024];
+     int nonce = lua_gettop(L) > 2 ? auxiliar_checkboolean(L, 3) : 0;
+     req = OCSP_REQUEST_new();
+@@ -48,7 +48,7 @@ static int openssl_ocsp_request_new(lua_
+       for (i = 1; i <= len; i++)
+       {
+         lua_rawgeti(L, 2, i);
+-        if (auxiliar_isclass(L, "openssl.x509", -1))
++        if (auxiliar_getclassudata(L, "openssl.x509", -1))
+         {
+           X509 *cert = CHECK_OBJECT(2, X509, "openssl.x509");
+           id = OCSP_cert_to_id(NULL, cert, issuer);
+@@ -65,18 +65,32 @@ static int openssl_ocsp_request_new(lua_
+           {
+             id = OCSP_cert_id_new(EVP_sha1(), iname, ikey, sno);
+             one = OCSP_request_add0_id(req, id);
+-          };
++          }
+           ASN1_INTEGER_free(sno);
+           BIO_free(bio);
+         }
++        if (!one)
++        {
++          OCSP_CERTID_free(id);
++          OCSP_REQUEST_free(req);
++          req = NULL;
++          lua_pop(L, 1);
++          break;
++        }
+         lua_pop(L, 1);
+       }
+     }
+-    else if (auxiliar_isclass(L, "openssl.x509", 2))
++    else if (auxiliar_getclassudata(L, "openssl.x509", 2))
+     {
+       X509 *cert = CHECK_OBJECT(2, X509, "openssl.x509");
+       id = OCSP_cert_to_id(NULL, cert, issuer);
+       one = OCSP_request_add0_id(req, id);
++      if (!one)
++      {
++        OCSP_CERTID_free(id);
++        OCSP_REQUEST_free(req);
++        req = NULL;
++      }
+     }
+     else
+     {
+@@ -87,7 +101,13 @@ static int openssl_ocsp_request_new(lua_
+       {
+         id = OCSP_cert_id_new(EVP_sha1(), iname, ikey, sno);
+         one = OCSP_request_add0_id(req, id);
+-      };
++        if (!one)
++        {
++          OCSP_CERTID_free(id);
++          OCSP_REQUEST_free(req);
++          req = NULL;
++        }
++      }
+       ASN1_INTEGER_free(sno);
+       BIO_free(bio);
+     }
+@@ -108,15 +128,12 @@ static int openssl_ocsp_request_new(lua_
+ static int openssl_ocsp_request_export(lua_State*L)
+ {
+   OCSP_REQUEST *req = CHECK_OBJECT(1, OCSP_REQUEST, "openssl.ocsp_request");
+-  int pem = 1;
++  int pem = lua_gettop(L) > 1 ? auxiliar_checkboolean(L, 2) : 0;
+   int ret = 0;
+   BIO* bio;
+   BUF_MEM *buf;
+-  if (lua_gettop(L) > 1)
+-    pem = auxiliar_checkboolean(L, 2);
+ 
+   bio = BIO_new(BIO_s_mem());
+-  /*
+   if (pem)
+   {
+     ret = PEM_write_bio_OCSP_REQUEST(bio, req);
+@@ -125,8 +142,6 @@ static int openssl_ocsp_request_export(l
+   {
+     ret = i2d_OCSP_REQUEST_bio(bio, req);
+   }
+-  */
+-  ret = i2d_OCSP_REQUEST_bio(bio, req);
+   if (ret)
+   {
+     BIO_get_mem_ptr(bio, &buf);
+@@ -153,8 +168,6 @@ static int openssl_ocsp_request_sign(lua
+   int ret;
+   int sflags = 0;
+ 
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 3, "must be private key");
+-
+   if (lua_isnoneornil(L, 4))
+   {
+     sflags = OCSP_NOCERTS;
+@@ -172,16 +185,47 @@ static int openssl_ocsp_request_sign(lua
+   return 1;
+ }
+ 
++static int openssl_push_ocsp_certid(lua_State*L, OCSP_CERTID* cid)
++{
++  ASN1_OCTET_STRING *iNameHash = NULL;
++  ASN1_OBJECT *md = NULL;
++  ASN1_OCTET_STRING *ikeyHash = NULL;
++  ASN1_INTEGER *serial = NULL;
++
++  int ret = OCSP_id_get0_info(&iNameHash, &md, &ikeyHash, &serial, cid);
++  if (ret == 1)
++  {
++    lua_newtable(L);
++
++    PUSH_ASN1_OCTET_STRING(L, iNameHash);
++    lua_setfield(L, -2, "issuerNameHash");
++
++    PUSH_ASN1_OCTET_STRING(L, ikeyHash);
++    lua_setfield(L, -2, "issuerKeyHash");
++
++    PUSH_ASN1_INTEGER(L, serial);
++    lua_setfield(L, -2, "serialNumber");
++
++    PUSH_OBJECT(md, "openssl.asn1_object");
++    lua_setfield(L, -2, "hashAlgorithm");
++  }
++  else
++    lua_pushnil(L);
++  return 1;
++}
+ 
+ static int openssl_ocsp_request_parse(lua_State*L)
+ {
+   OCSP_REQUEST *req = CHECK_OBJECT(1, OCSP_REQUEST, "openssl.ocsp_request");
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+   OCSP_REQINFO *inf = req->tbsRequest;
+   OCSP_SIGNATURE *sig = req->optionalSignature;
+-
++#endif
+   BIO* bio = BIO_new(BIO_s_mem());
+   int i, num;
+   lua_newtable(L);
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+   AUXILIAR_SET(L, -1, "version", ASN1_INTEGER_get(inf->version), integer);
+   if (inf->requestorName)
+   {
+@@ -189,39 +233,33 @@ static int openssl_ocsp_request_parse(lu
+     lua_setfield(L, -2, "requestorName");
+   }
+   num = sk_OCSP_ONEREQ_num(inf->requestList);
++#endif
++
++  num = OCSP_request_onereq_count(req);
+   lua_newtable(L);
+   for (i = 0; i < num; i++)
+   {
+-    OCSP_ONEREQ *one = sk_OCSP_ONEREQ_value(inf->requestList, i);
+-    OCSP_CERTID *a = one->reqCert;
+-    lua_newtable(L);
+-    {
+-      openssl_push_x509_algor(L, a->hashAlgorithm);
+-      lua_setfield(L, -2, "hashAlgorithm");
+-
+-      PUSH_ASN1_OCTET_STRING(L, a->issuerNameHash);
+-      lua_setfield(L, -2, "issuerNameHash");
+-
+-      PUSH_ASN1_OCTET_STRING(L, a->issuerKeyHash);
+-      lua_setfield(L, -2, "issuerKeyHash");
+-
+-      PUSH_ASN1_INTEGER(L, a->serialNumber);
+-      lua_setfield(L, -2, "serialNumber");
+-    }
++    OCSP_ONEREQ *one = OCSP_request_onereq_get0(req, i);
++    OCSP_CERTID *cid = OCSP_onereq_get0_id(one);
++    openssl_push_ocsp_certid(L, cid);
+     lua_rawseti(L, -2, i + 1);
+   }
+   lua_setfield(L, -2, "requestList");
+ 
+-  if (inf->requestExtensions)
++  num = OCSP_REQUEST_get_ext_count(req);
++  lua_newtable(L);
++  for (i = 0; i < num; i++)
+   {
+-    lua_pushstring(L, "extensions");
+-    openssl_sk_x509_extension_totable(L, inf->requestExtensions);
+-    lua_rawset(L, -3);
++    X509_EXTENSION* e = OCSP_REQUEST_get_ext(req, i);
++    PUSH_OBJECT(e, "openssl.x509_extension");
++    lua_rawseti(L, -2, i + 1);
+   }
++  lua_setfield(L, -2, "extensions");
+ 
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+   if (sig)
+   {
+-    BIO_reset(bio);
++    (void)BIO_reset(bio);
+     X509_signature_print(bio, sig->signatureAlgorithm, sig->signature);
+     for (i = 0; i < sk_X509_num(sig->certs); i++)
+     {
+@@ -229,7 +267,7 @@ static int openssl_ocsp_request_parse(lu
+       PEM_write_bio_X509(bio, sk_X509_value(sig->certs, i));
+     }
+   }
+-
++#endif
+   BIO_free(bio);
+   return 1;
+ }
+@@ -268,7 +306,6 @@ static int openssl_ocsp_response(lua_Sta
+ 
+     int i, id_count, type;
+     BIO* bio = NULL;
+-    luaL_argcheck(L, openssl_pkey_is_private(rkey), 4, "must be private key");
+ 
+     type = lua_type(L, 5);
+     if (type != LUA_TFUNCTION && type != LUA_TTABLE)
+@@ -305,7 +342,7 @@ static int openssl_ocsp_response(lua_Sta
+       if (lua_istable(L, 5))
+       {
+         BUF_MEM *buf;
+-        BIO_reset(bio);
++        (void)BIO_reset(bio);
+         i2a_ASN1_INTEGER(bio, serial);
+ 
+         BIO_get_mem_ptr(bio, &buf);
+@@ -406,15 +443,12 @@ static int openssl_ocsp_response(lua_Sta
+ static int openssl_ocsp_response_export(lua_State*L)
+ {
+   OCSP_RESPONSE *res = CHECK_OBJECT(1, OCSP_RESPONSE, "openssl.ocsp_response");
+-  int pem = 1;
++  int pem = lua_gettop(L) > 1 ? auxiliar_checkboolean(L, 2) : 0;
+   int ret = 0;
+   BIO* bio;
+   BUF_MEM *buf;
+-  if (lua_gettop(L) > 1)
+-    pem = auxiliar_checkboolean(L, 2);
+ 
+   bio = BIO_new(BIO_s_mem());
+-  /*
+   if (pem)
+   {
+     ret = PEM_write_bio_OCSP_RESPONSE(bio, res);
+@@ -423,8 +457,6 @@ static int openssl_ocsp_response_export(
+   {
+     ret = i2d_OCSP_RESPONSE_bio(bio, res);
+   }
+-  */
+-  ret = i2d_OCSP_RESPONSE_bio(bio, res);
+   if (ret)
+   {
+     BIO_get_mem_ptr(bio, &buf);
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/openssl.c luvi-src-v2.7.6/deps/lua-openssl/src/openssl.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/openssl.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/openssl.c	2019-02-13 11:53:24.275126573 +0100
+@@ -1,10 +1,11 @@
+-/*=========================================================================*\
+-* openssl.c
+-* lua-openssl binding
+-*
+-* This product includes PHP software, freely available from <http://www.php.net/software/>
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++lua-openssl binding, provide openssl base function in lua.
++
++@module openssl
++@usage
++  openssl = require('openssl')
++*/
++
+ #include "openssl.h"
+ #include <openssl/ssl.h>
+ #include <openssl/asn1.h>
+@@ -12,6 +13,12 @@
+ #include <openssl/opensslconf.h>
+ #include "private.h"
+ 
++/***
++get lua-openssl version
++@function version
++@tparam[opt] boolean format result will be number when set true, or string
++@treturn lua-openssl version, lua version, openssl version
++*/
+ static int openssl_version(lua_State*L)
+ {
+   int num = lua_isnoneornil(L, 1) ? 0 : auxiliar_checkboolean(L, 1);
+@@ -20,7 +27,6 @@ static int openssl_version(lua_State*L)
+     lua_pushinteger(L, LOPENSSL_VERSION_NUM);
+     lua_pushinteger(L, LUA_VERSION_NUM);
+     lua_pushinteger(L, OPENSSL_VERSION_NUMBER);
+-
+   }
+   else
+   {
+@@ -31,6 +37,13 @@ static int openssl_version(lua_State*L)
+   return 3;
+ }
+ 
++/***
++hex encode or decode string
++@function hex
++@tparam string str
++@tparam[opt=true] boolean encode true to encoed, false to decode
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_hex)
+ {
+   size_t l = 0;
+@@ -59,6 +72,14 @@ static LUA_FUNCTION(openssl_hex)
+   return 1;
+ }
+ 
++/***
++base64 encode or decode
++@function base64
++@tparam string|bio input
++@tparam[opt=true] boolean encode true to encoed, false to decode
++@tparam[opt=true] boolean NO_NL true with newline, false without newline
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_base64)
+ {
+   BIO *inp = load_bio_object(L, 1);
+@@ -75,7 +96,7 @@ static LUA_FUNCTION(openssl_base64)
+     BIO_push(b64, out);
+     BIO_get_mem_ptr(inp, &mem);
+     BIO_write(b64, mem->data, mem->length);
+-    BIO_flush(b64);
++    (void)BIO_flush(b64);
+   }
+   else
+   {
+@@ -84,7 +105,7 @@ static LUA_FUNCTION(openssl_base64)
+     BIO_push(b64, inp);
+     while ((inlen = BIO_read(b64, inbuf, 512)) > 0)
+       BIO_write(out, inbuf, inlen);
+-    BIO_flush(out);
++    (void)BIO_flush(out);
+   }
+ 
+   BIO_get_mem_ptr(out, &mem);
+@@ -108,6 +129,12 @@ static void list_callback(const OBJ_NAME
+   lua_rawseti(L, -2, idx + 1);
+ }
+ 
++/***
++get method names
++@function list
++@tparam string type support 'cipher','digests','pkeys','comps'
++@treturn table as array
++*/
+ static LUA_FUNCTION(openssl_list)
+ {
+   static int options[] =
+@@ -124,6 +151,22 @@ static LUA_FUNCTION(openssl_list)
+   return 1;
+ }
+ 
++/***
++get last or given error infomation
++
++Most lua-openssl function or methods return nil or false when error or
++failed, followed by string type error _reason_ and number type error _code_,
++_code_ can pass to openssl.error() to get more error information.
++
++@function error
++@tparam[opt] number error, default use ERR_get_error() return value
++@tparam[opt=false] boolean clear the current thread's error queue.
++@treturn number errcode
++@treturn string reason
++@treturn string library name
++@treturn string function name
++@treturn boolean is this is fatal error
++*/
+ static LUA_FUNCTION(openssl_error_string)
+ {
+   unsigned long val;
+@@ -159,13 +202,21 @@ static LUA_FUNCTION(openssl_error_string
+   return ret;
+ }
+ 
++/***
++load rand seed from file
++@function rand_load
++@tparam[opt=nil] string file path to laod seed, default opensl management
++@treturn boolean result
++*/
+ static int openssl_random_load(lua_State*L)
+ {
+   const char *file = luaL_optstring(L, 1, NULL);
+   char buffer[MAX_PATH];
++  int len;
+ 
+   if (file == NULL)
+     file = RAND_file_name(buffer, sizeof buffer);
++#ifndef OPENSSL_NO_EGD
+   else if (RAND_egd(file) > 0)
+   {
+     /* we try if the given filename is an EGD socket.
+@@ -173,8 +224,9 @@ static int openssl_random_load(lua_State
+     lua_pushboolean(L, 1);
+     return 1;
+   }
+-
+-  if (file == NULL || !RAND_load_file(file, 2048))
++#endif
++  len = luaL_optinteger(L, 2, 2048);
++  if (file == NULL || !RAND_load_file(file, len))
+   {
+     return openssl_pushresult(L, 0);
+   }
+@@ -183,25 +235,39 @@ static int openssl_random_load(lua_State
+   return 1;
+ }
+ 
++/***
++save rand seed to file
++@function rand_write
++@tparam[opt=nil] string file path to save seed, default openssl management
++@treturn bool result
++*/
+ static int openssl_random_write(lua_State *L)
+ {
+   const char *file = luaL_optstring(L, 1, NULL);
+   char buffer[MAX_PATH];
+-  int n;
+ 
+-  if (!file && !(file = RAND_file_name(buffer, sizeof buffer)))
++  if (file == NULL && (file = RAND_file_name(buffer, sizeof buffer)) == NULL)
+     return openssl_pushresult(L, 0);
+ 
+-  n = RAND_write_file(file);
++  RAND_write_file(file);
+   return openssl_pushresult(L, 1);
+ }
+ 
++/***
++get random generator state
++@function rand_status
++@tparam boolean result true for sucess
++*/
+ static int openssl_random_status(lua_State *L)
+ {
+   lua_pushboolean(L, RAND_status());
+   return 1;
+ }
+ 
++/***
++cleanup random genrator
++@function rand_cleanup
++*/
+ static int openssl_random_cleanup(lua_State *L)
+ {
+   (void) L;
+@@ -209,6 +275,13 @@ static int openssl_random_cleanup(lua_St
+   return 0;
+ }
+ 
++/***
++get random bytes
++@function random
++@tparam number length
++@tparam[opt=false] boolean strong true to generate strong randome bytes
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_random_bytes)
+ {
+   long length = luaL_checkint(L, 1);
+@@ -251,6 +324,42 @@ static LUA_FUNCTION(openssl_random_bytes
+   return 1;
+ }
+ 
++/***
++set FIPS mode
++@function FIPS_mode
++@tparam boolean fips true enable FIPS mode, false disable it.
++@treturn boolean success
++*/
++
++/***
++get FIPS mode
++@function FIPS_mode
++@treturn boolean return true when FIPS mode enabled, false when FIPS mode disabled.
++*/
++static int openssl_fips_mode(lua_State *L)
++{
++#if defined(LIBRESSL_VERSION_NUMBER)
++  return 0;
++#else
++  int ret =0, on = 0;
++  if(lua_isnone(L, 1))
++  {
++    on = FIPS_mode();
++    lua_pushboolean(L, on);
++    return 1;
++  }
++
++  on = auxiliar_checkboolean(L, 1);
++  ret = FIPS_mode_set(on);
++  if(ret)
++    lua_pushboolean(L, ret);
++  else
++    ret = openssl_pushresult(L, ret);
++  return ret;
++#endif
++}
++
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+ static int openssl_mem_leaks(lua_State*L)
+ {
+   BIO *bio = BIO_new(BIO_s_mem());
+@@ -263,15 +372,23 @@ static int openssl_mem_leaks(lua_State*L
+   BIO_free(bio);
+   return 1;
+ }
++#endif
+ 
++/***
++get openssl engine object
++@function engine
++@tparam string engine_id
++@treturn engine
++*/
+ static const luaL_Reg eay_functions[] =
+ {
+   {"version",     openssl_version},
+   {"list",        openssl_list},
+   {"hex",         openssl_hex},
+   {"base64",      openssl_base64},
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+   {"mem_leaks",   openssl_mem_leaks},
+-
++#endif
+   {"rand_status", openssl_random_status},
+   {"rand_load",   openssl_random_load},
+   {"rand_write",  openssl_random_write},
+@@ -280,6 +397,7 @@ static const luaL_Reg eay_functions[] =
+ 
+   {"error",       openssl_error_string},
+   {"engine",      openssl_engine},
++  {"FIPS_mode",   openssl_fips_mode},
+ 
+   {NULL, NULL}
+ };
+@@ -289,10 +407,46 @@ void CRYPTO_thread_setup(void);
+ void CRYPTO_thread_cleanup(void);
+ #endif
+ 
++static int luaclose_openssl(lua_State *L)
++{
++#if !defined(LIBRESSL_VERSION_NUMBER)
++  FIPS_mode_set(0);
++#endif
++#if defined(OPENSSL_THREADS)
++  CRYPTO_thread_cleanup();
++#endif
++  CRYPTO_set_locking_callback(NULL);
++  CRYPTO_set_id_callback(NULL);
++
++  ENGINE_cleanup();
++  CONF_modules_unload(1);
++
++  ERR_free_strings();
++  EVP_cleanup();
++
++  CRYPTO_cleanup_all_ex_data();
++#ifndef OPENSSL_NO_CRYPTO_MDEBUG
++#if !(defined(OPENSSL_NO_STDIO) || defined(OPENSSL_NO_FP_API))
++#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L
++  CRYPTO_mem_leaks_fp(stderr);
++#else
++  if(CRYPTO_mem_leaks_fp(stderr)!=1)
++  {
++    fprintf(stderr,
++            "Please report a bug on https://github.com/zhaozg/lua-openssl."
++            "And if can, please provide a reproduce method and minimal code.\n"
++            "\n\tThank You.");
++  }
++#endif
++#endif /* OPENSSL_NO_STDIO or OPENSSL_NO_FP_API */
++#endif /* OPENSSL_NO_CRYPTO_MDEBUG */
++  return 0;
++}
++
+ LUALIB_API int luaopen_openssl(lua_State*L)
+ {
+-  static int init = 0;
+-  if (init == 0)
++  static void* init = NULL;
++  if (init == NULL)
+   {
+ #if defined(OPENSSL_THREADS)
+     CRYPTO_thread_setup();
+@@ -309,15 +463,26 @@ LUALIB_API int luaopen_openssl(lua_State
+     ENGINE_load_dynamic();
+     ENGINE_load_openssl();
+ #ifdef LOAD_ENGINE_CUSTOM
+-    LOAD_ENGINE_CUSTOM();
++    LOAD_ENGINE_CUSTOM
+ #endif
+ #ifdef OPENSSL_SYS_WINDOWS
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+     RAND_screen();
+ #endif
+-    init = 1;
++#endif
+   }
+ 
+   lua_newtable(L);
++  if(init==NULL)
++  {
++    init = lua_newuserdata(L, sizeof(int));
++    lua_newtable(L);
++    lua_pushcfunction(L, luaclose_openssl);
++    lua_setfield(L, -2, "__gc");
++    lua_setmetatable(L, -2);
++    lua_setfield(L, -2, "__guard");
++  }
++
+   luaL_setfuncs(L, eay_functions, 0);
+ 
+   openssl_register_lhash(L);
+@@ -382,6 +547,11 @@ LUALIB_API int luaopen_openssl(lua_State
+   luaopen_dh(L);
+   lua_setfield(L, -2, "dh");
+ 
++#ifndef OPENSSL_NO_SRP
++  luaopen_srp(L);
++  lua_setfield(L, -2, "srp");
++#endif
++
+ #ifdef ENABLE_OPENSSL_GLOBAL
+   lua_pushvalue(L, -1);
+   lua_setglobal(L, "openssl");
+@@ -389,4 +559,3 @@ LUALIB_API int luaopen_openssl(lua_State
+ 
+   return 1;
+ }
+-
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/openssl.h luvi-src-v2.7.6/deps/lua-openssl/src/openssl.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/openssl.h	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/openssl.h	2019-02-13 11:53:24.275126573 +0100
+@@ -11,6 +11,7 @@
+ #include <lualib.h>
+ #include <lauxlib.h>
+ #include "auxiliar.h"
++#include "subsidiar.h"
+ 
+ #include <assert.h>
+ #include <string.h>
+@@ -26,7 +27,8 @@
+ #include <openssl/pkcs12.h>
+ #include <openssl/opensslv.h>
+ #include <openssl/bn.h>
+-
++#include <openssl/hmac.h>
++#include <openssl/ts.h>
+ 
+ /*-
+ * Numeric release version identifier:
+@@ -42,19 +44,16 @@
+ * 0.9.3a         0x0090301f
+ * 0.9.4          0x0090400f
+ * 1.2.3z         0x102031af
+-*
+-* For continuity reasons (because 0.9.5 is already out, and is coded
+-* 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level
+-* part is slightly different, by setting the highest bit.  This means
+-* that 0.9.5a looks like this: 0x0090581f.  At 0.9.6, we can start
+-* with 0x0090600S...
+-*
+-* (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.)
+-* (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
+-*  major minor fix final patch/beta)
+ */
+-#define LOPENSSL_VERSION_NUM  0x00500001
+-#define LOPENSSL_VERSION  "0.5.1"
++
++/*History
++  2017-04-18  update to 0.7.1
++  2017-08-04  update to 0.7.3
++*/
++
++/*                              MNNFFPPS  */
++#define LOPENSSL_VERSION_NUM  0x00703000
++#define LOPENSSL_VERSION  "0.7.3"
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ #include <openssl/lhash.h>
+@@ -78,14 +77,13 @@ __pragma(warning(pop))
+ /* Common */
+ #include <time.h>
+ #ifndef MAX_PATH
+-#define MAX_PATH PATH_MAX
++#define MAX_PATH 260
+ #endif
+ 
+ #ifdef NETWARE
+ #define timezone _timezone  /* timezone is called _timezone in LibC */
+ #endif
+ 
+-
+ #ifdef WIN32
+ #define snprintf _snprintf
+ #ifndef strcasecmp
+@@ -93,8 +91,13 @@ __pragma(warning(pop))
+ #endif
+ #endif
+ 
+-#define LUA_FUNCTION(X) int X(lua_State *L)
++#ifdef _MSC_VER
++# ifndef inline
++#  define inline __inline
++# endif
++#endif
+ 
++#define LUA_FUNCTION(X) int X(lua_State *L)
+ 
+ int openssl_s2i_revoke_reason(const char*s);
+ 
+@@ -127,6 +130,25 @@ void openssl_add_method(const OBJ_NAME *
+ #define CHECK_OBJECT(n,type,name) *(type**)auxiliar_checkclass(L,name,n)
+ #define CHECK_GROUP(n,type,name)  *(type**)auxiliar_checkgroup(L,name,n)
+ 
++static inline void* openssl_getclass(lua_State *L, const char* name, int idx)
++{
++  void **p = (void**)auxiliar_getclassudata(L, name, idx);
++  if(p)
++    return *p;
++  return NULL;
++}
++
++static inline void* openssl_getgroup(lua_State *L, const char* name, int idx)
++{
++  void **p = (void**)auxiliar_getgroupudata(L, name, idx);
++  if(p)
++    return *p;
++  return NULL;
++}
++
++#define GET_OBJECT(n,type,name) ((type*)openssl_getclass(L,name,n))
++#define GET_GROUP(n,type,name)  ((type*)openssl_getgroup(L,name,n))
++
+ #define PUSH_OBJECT(o, tname)                                   \
+   MULTI_LINE_MACRO_BEGIN                                        \
+   if(o) {                                                       \
+@@ -135,8 +157,11 @@ void openssl_add_method(const OBJ_NAME *
+   } else lua_pushnil(L);                                        \
+   MULTI_LINE_MACRO_END
+ 
++#define FREE_OBJECT(i)  (*(void**)lua_touserdata(L, i) = NULL)
++
+ int openssl_register_lhash(lua_State* L);
+ int openssl_register_engine(lua_State* L);
+ 
+-#endif
++LUA_FUNCTION(luaopen_srp);
+ 
++#endif
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/ots.c luvi-src-v2.7.6/deps/lua-openssl/src/ots.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/ots.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/ots.c	2019-02-13 11:53:24.298459641 +0100
+@@ -1,9 +1,10 @@
+-/*=========================================================================*\
+-* ots.c
+-* timestamp module for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++timestamp module for lua-openssl binding
++create and manage x509 certificate sign request
++@module ts
++@usage
++  ts = require'openssl'.ts
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #include <stdint.h>
+@@ -14,6 +15,202 @@
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
++/***
++create a new ts_req object.
++@function req_new
++@tparam[opt=1] integer version
++@treturn ts_req timestamp sign request object
++@see ts_req
++*/
++static LUA_FUNCTION(openssl_ts_req_new)
++{
++  TS_REQ *ts_req = TS_REQ_new();
++  long version = luaL_optinteger(L, 1, 1);
++
++  int ret = TS_REQ_set_version(ts_req, version);
++  if (ret == 1)
++  {
++    PUSH_OBJECT(ts_req, "openssl.ts_req");
++    return 1;
++  }
++  TS_REQ_free(ts_req);
++  return 0;
++}
++
++/***
++read ts_req object from string or bio data
++@function req_read
++@tparam string|bio input
++@treturn ts_req timestamp sign request object
++@see ts_req
++*/
++static LUA_FUNCTION(openssl_ts_req_read)
++{
++  BIO *in = load_bio_object(L, 1);
++  TS_REQ *ts_req = d2i_TS_REQ_bio(in, NULL);
++  BIO_free(in);
++  if (ts_req)
++  {
++    PUSH_OBJECT(ts_req, "openssl.ts_req");
++    return 1;
++  }
++  return 0;
++}
++
++/***
++read ts_resp object from string or bio input
++@function resp_read
++@tparam string|bio input
++@treturn ts_resp object
++*/
++static LUA_FUNCTION(openssl_ts_resp_read)
++{
++  BIO* in = load_bio_object(L, 1);
++  TS_RESP *res = d2i_TS_RESP_bio(in, NULL);
++  BIO_free(in);
++  if (res)
++  {
++    PUSH_OBJECT(res, "openssl.ts_resp");
++  }
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++/***
++create ts_resp_ctx object
++@function resp_ctx_new
++@tparam[opt] x509 signer timestamp certificate
++@tparam[opt] evp_pkey pkey private key to sign ts_req
++@tparam[opt] asn1_object|string|nid identity for default policy object
++@treturn ts_resp_ctx object
++*/
++static LUA_FUNCTION(openssl_ts_resp_ctx_new)
++{
++  TS_RESP_CTX* ctx = TS_RESP_CTX_new();
++  int i = 0;
++  int n = lua_gettop(L);
++  X509 *signer = NULL;
++  EVP_PKEY *pkey = NULL;
++  ASN1_OBJECT *obj = NULL;
++  int ret = 1;
++
++  for (i = 1; i <= n; i++)
++  {
++    if (auxiliar_getclassudata(L, "openssl.x509", i))
++    {
++      signer = CHECK_OBJECT(i, X509, "openssl.x509");
++    }
++    else if (auxiliar_getclassudata(L, "openssl.evp_pkey", i))
++    {
++      pkey = CHECK_OBJECT(i, EVP_PKEY, "openssl.evp_pkey");
++    }
++    else if (auxiliar_getclassudata(L, "openssl.asn1_object", i))
++    {
++      obj = CHECK_OBJECT(i, ASN1_OBJECT, "openssl.asn1_object");
++    }
++    else if (lua_isnumber(L, i) || lua_isstring(L, i))
++    {
++      int nid = openssl_get_nid(L, i);
++      luaL_argcheck(L, nid != NID_undef, i, "invalid asn1_object or object id");
++      obj = OBJ_nid2obj(nid);
++    }
++    else
++      luaL_argerror(L, i, "not accept parameter");
++  }
++  if (signer && pkey)
++  {
++    ret = X509_check_private_key(signer, pkey);
++    if (ret != 1)
++    {
++      luaL_error(L, "singer cert and private key not match");
++    }
++  }
++  if (ret == 1 && obj != NULL)
++    ret = TS_RESP_CTX_set_def_policy(ctx, obj);
++
++  if (ret == 1 && signer)
++    ret = TS_RESP_CTX_set_signer_cert(ctx, signer);
++  if (ret == 1 && pkey)
++    ret = TS_RESP_CTX_set_signer_key(ctx, pkey);
++
++  if (ret == 1)
++  {
++    PUSH_OBJECT(ctx, "openssl.ts_resp_ctx");
++    openssl_newvalue(L, ctx);
++  }
++  else
++  {
++    TS_RESP_CTX_free(ctx);
++    ctx = NULL;
++    lua_pushnil(L);
++  }
++  return 1;
++}
++
++/***
++create ts_verify_ctx object
++@function verify_ctx_new
++@tparam[opt=nil] string|ts_req reqdata
++@treturn ts_verify_ctx object
++*/
++static LUA_FUNCTION(openssl_ts_verify_ctx_new)
++{
++  TS_VERIFY_CTX *ctx = NULL;
++  if (lua_isnone(L, 1))
++  {
++    ctx = TS_VERIFY_CTX_new();
++  }
++  else if (lua_isstring(L, 1))
++  {
++    BIO* bio = load_bio_object(L, 1);
++    TS_REQ* req = d2i_TS_REQ_bio(bio, NULL);
++    BIO_free(bio);
++    if (req)
++    {
++      ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL);
++      TS_REQ_free(req);
++    }
++    else
++    {
++      luaL_argerror(L, 1, "must be ts_req data or object or nil");
++    }
++  }
++  else
++  {
++    TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
++    ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL);
++  }
++  if (ctx)
++  {
++    PUSH_OBJECT(ctx, "openssl.ts_verify_ctx");
++  }
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++static luaL_Reg R[] =
++{
++  {"req_new",         openssl_ts_req_new},
++  {"req_read",        openssl_ts_req_read},
++  {"resp_read",       openssl_ts_resp_read},
++
++  {"resp_ctx_new",    openssl_ts_resp_ctx_new },
++  {"verify_ctx_new",  openssl_ts_verify_ctx_new },
++
++  {NULL,    NULL}
++};
++
++/***
++openssl.ts_req object
++@type ts_req
++*/
++/***
++make a clone of ts_req object
++@function dup
++@treturn ts_req
++*/
+ static int openssl_ts_req_dup(lua_State*L)
+ {
+   TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -22,6 +219,17 @@ static int openssl_ts_req_dup(lua_State*
+   return 1;
+ }
+ 
++/***
++get cert_req
++@function cert_req
++@treturn boolean true for set or not
++*/
++/***
++set cert_req
++@function cert_req
++@tparam boolean cert_req
++@treturn boolean result
++*/
+ static int openssl_ts_req_cert_req(lua_State *L)
+ {
+   TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -38,6 +246,17 @@ static int openssl_ts_req_cert_req(lua_S
+   }
+ }
+ 
++/***
++get nonce
++@function nonce
++@treturn bn openssl.bn object
++*/
++/***
++set nonce
++@tparam string|bn nonce
++@treturn boolean result
++@function nonce
++*/
+ static int openssl_ts_req_nonce(lua_State*L)
+ {
+   TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -61,6 +280,17 @@ static int openssl_ts_req_nonce(lua_Stat
+   }
+ }
+ 
++/***
++get policy_id
++@function policy_id
++@treturn asn1_object
++*/
++/***
++set policy_id
++@function policy_id
++@tparam asn1_object|number id  identity for asn1_object
++@treturn boolean result
++*/
+ static int openssl_ts_req_policy_id(lua_State*L)
+ {
+   TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -68,21 +298,39 @@ static int openssl_ts_req_policy_id(lua_
+   {
+     ASN1_OBJECT* obj = TS_REQ_get_policy_id(req);
+     openssl_push_asn1object(L, obj);
+-    ASN1_OBJECT_free(obj);
+     return 1;
+   }
+   else
+   {
+-    int nid = openssl_get_nid(L, 2);
+-    ASN1_OBJECT* obj;
++    ASN1_OBJECT* obj = NULL;
+     int ret;
+-    luaL_argcheck(L, nid != NID_undef, 2, "must be asn1_object object identified");
+-    obj = OBJ_nid2obj(nid);
++    if (auxiliar_getclassudata(L, "openssl.asn1_object", 2))
++    {
++      obj = CHECK_OBJECT(2, ASN1_OBJECT, "openssl.asn1_object");
++    }
++    else
++    {
++      int nid = openssl_get_nid(L, 2);
++      luaL_argcheck(L, nid != NID_undef, 2, "must be asn1_object object identified");
++      obj = OBJ_nid2obj(nid);
++    }
++
+     ret = TS_REQ_set_policy_id(req, obj);
+     return openssl_pushresult(L, ret);
+   }
+ }
+ 
++/***
++get version
++@treturn integer
++@function version
++*/
++/***
++set version
++@tparam integer version
++@treturn boolean result
++@function version
++*/
+ static int openssl_ts_req_version(lua_State*L)
+ {
+   TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -99,6 +347,19 @@ static int openssl_ts_req_version(lua_St
+   }
+ }
+ 
++/***
++get msg_imprint
++@function msg_imprint
++@treturn string octet octet string
++@treturn table with algorithm and paramater
++*/
++/***
++set msg_imprint
++@function msg_imprint
++@tparam string data digest value of message
++@tparam[opt='sha'] string|evp_md md_alg
++@treturn boolean result
++*/
+ static int openssl_ts_req_msg_imprint(lua_State*L)
+ {
+   TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -110,9 +371,8 @@ static int openssl_ts_req_msg_imprint(lu
+       ASN1_OCTET_STRING *s = TS_MSG_IMPRINT_get_msg(msg);
+       X509_ALGOR *a = TS_MSG_IMPRINT_get_algo(msg);
+       PUSH_ASN1_OCTET_STRING(L, s);
+-      openssl_push_x509_algor(L, a);
+-      ASN1_OCTET_STRING_free(s);
+-      X509_ALGOR_free(a);
++      a = X509_ALGOR_dup(a);
++      PUSH_OBJECT(a, "openssl.x509_algor");
+       return 2;
+     }
+     return 1;
+@@ -121,9 +381,7 @@ static int openssl_ts_req_msg_imprint(lu
+   {
+     size_t size;
+     const char* data = luaL_checklstring(L, 2, &size);
+-    const EVP_MD* md = lua_isnoneornil(L, 3)
+-                       ? EVP_get_digestbyname("sha1")
+-                       : get_digest(L, 3);
++    const EVP_MD* md = get_digest(L, 3, "sha256");
+     TS_MSG_IMPRINT *msg = TS_MSG_IMPRINT_new();
+     int ret = TS_MSG_IMPRINT_set_msg(msg, (unsigned char*)data, size);
+     if (ret == 1)
+@@ -144,28 +402,11 @@ static int openssl_ts_req_msg_imprint(lu
+   }
+ };
+ 
+-static LUA_FUNCTION(openssl_ts_req_new)
+-{
+-  TS_REQ *ts_req = TS_REQ_new();
+-  long version = luaL_optinteger(L, 1, 1);
+-
+-  int ret = TS_REQ_set_version(ts_req, version);
+-  if (ret == 1)
+-  {
+-    PUSH_OBJECT(ts_req, "openssl.ts_req");
+-    return 1;
+-  }
+-  TS_REQ_free(ts_req);
+-  return 0;
+-}
+-
+-static LUA_FUNCTION(openssl_ts_req_gc)
+-{
+-  TS_REQ *req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+-  TS_REQ_free(req);
+-  return 0;
+-}
+-
++/***
++create ts_verify_ctx from ts_req object
++@function to_verify_ctx
++@treturn ts_verify_ctx object
++*/
+ static LUA_FUNCTION(openssl_ts_req_to_verify_ctx)
+ {
+   TS_REQ *req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -174,19 +415,11 @@ static LUA_FUNCTION(openssl_ts_req_to_ve
+   return 1;
+ }
+ 
+-static LUA_FUNCTION(openssl_ts_req_read)
+-{
+-  BIO *in = load_bio_object(L, 1);
+-  TS_REQ *ts_req = d2i_TS_REQ_bio(in, NULL);
+-  BIO_free(in);
+-  if (ts_req)
+-  {
+-    PUSH_OBJECT(ts_req, "openssl.ts_req");
+-    return 1;
+-  }
+-  return 0;
+-}
+-
++/***
++export ts_req to string
++@function export
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_ts_req_export)
+ {
+   TS_REQ *ts_req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -201,6 +434,11 @@ static LUA_FUNCTION(openssl_ts_req_expor
+   return 0;
+ }
+ 
++/***
++get info as table
++@function info
++@treturn table
++*/
+ static LUA_FUNCTION(openssl_ts_req_info)
+ {
+   TS_REQ *req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+@@ -217,41 +455,52 @@ static LUA_FUNCTION(openssl_ts_req_info)
+     STACK_OF(X509_EXTENSION) *extensions; /* [0] OPTIONAL */
+   } TS_REQ;
+ #endif
+-  PUSH_ASN1_INTEGER(L, req->version);
++  lua_pushinteger(L, TS_REQ_get_version(req));
+   lua_setfield(L, -2, "version");
+ 
+-  AUXILIAR_SET(L, -1, "cert_req", req->cert_req, boolean);
++  AUXILIAR_SET(L, -1, "cert_req", TS_REQ_get_cert_req(req), boolean);
+ 
+-  if (req->policy_id)
++  if (TS_REQ_get_policy_id(req))
+   {
+-    openssl_push_asn1object(L, req->policy_id);
++    openssl_push_asn1object(L, TS_REQ_get_policy_id(req));
+     lua_setfield(L, -2, "policy_id");
+   }
+-  if (req->nonce)
++  if (TS_REQ_get_nonce(req))
+   {
+-    PUSH_ASN1_INTEGER(L, req->nonce);
++    PUSH_ASN1_INTEGER(L, TS_REQ_get_nonce(req));
+     lua_setfield(L, -2, "nonce");
+   }
+ 
+   lua_newtable(L);
+   {
+-    ASN1_OCTET_STRING *os = req->msg_imprint->hashed_msg;
+-    AUXILIAR_SETLSTR(L, -1, "content", (const char*)os->data, os->length);
+-    openssl_push_x509_algor(L, req->msg_imprint->hash_algo);
++    TS_MSG_IMPRINT *msg_inprint = TS_REQ_get_msg_imprint(req);
++    ASN1_OCTET_STRING *os = TS_MSG_IMPRINT_get_msg(msg_inprint);
++    X509_ALGOR *alg = TS_MSG_IMPRINT_get_algo(msg_inprint);
++
++    AUXILIAR_SETLSTR(L, -1, "hashed_msg", (const char*)os->data, os->length);
++    alg = X509_ALGOR_dup(alg);
++    PUSH_OBJECT(alg, "openssl.x509_algor");
+     lua_setfield(L, -2, "hash_algo");
+   }
+   lua_setfield(L, -2, "msg_imprint");
+ 
+-  if (req->extensions)
++  if (TS_REQ_get_exts(req))
+   {
+     lua_pushstring(L, "extensions");
+-    openssl_sk_x509_extension_totable(L, req->extensions);
++    openssl_sk_x509_extension_totable(L, TS_REQ_get_exts(req));
+     lua_rawset(L, -3);
+   }
+ 
+   return 1;
+ }
+ 
++static LUA_FUNCTION(openssl_ts_req_gc)
++{
++  TS_REQ *req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
++  TS_REQ_free(req);
++  return 0;
++}
++
+ static luaL_Reg ts_req_funs[] =
+ {
+   {"dup",           openssl_ts_req_dup},
+@@ -271,43 +520,10 @@ static luaL_Reg ts_req_funs[] =
+   { NULL, NULL }
+ };
+ 
+-/***********************************************************/
+-static ASN1_INTEGER *tsa_serial_cb(TS_RESP_CTX *ctx, void *data)
+-{
+-  lua_State *L = (lua_State*) data;
+-  ASN1_INTEGER *serial = NULL;
+-
+-  lua_rawgetp(L, LUA_REGISTRYINDEX, ctx);
+-  if (lua_isnil(L, -1))
+-  {
+-    TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+-                                "could not generate serial number");
+-
+-    return NULL;
+-  }
+-
+-  if (lua_pcall(L, 0, 1, 0) == 0)
+-  {
+-    lua_Integer i = luaL_checkinteger(L, -1);
+-    serial = ASN1_INTEGER_new();
+-    ASN1_INTEGER_set(serial, (long)i);
+-    return serial;
+-  }
+-  TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+-                              "could not generate serial number");
+-
+-  return NULL;
+-
+-  /* Acquire an exclusive lock for the serial file. */
+-  /*********************************************************
+-   * Merge server id and serial number                     *
+-   * example : server_id = 0x0F , serial = 2               *
+-   *           result = 0x0F2                              *
+-   * Modification made by JOUVE <opentsa@jouve-hdi.com>    *
+-   *********************************************************/
+-}
+-
+-/**************************************************************/
++/***
++openssl.ts_resp object
++@type ts_resp
++*/
+ static LUA_FUNCTION(openssl_ts_resp_gc)
+ {
+   TS_RESP *res = CHECK_OBJECT(1, TS_RESP, "openssl.ts_resp");
+@@ -315,6 +531,11 @@ static LUA_FUNCTION(openssl_ts_resp_gc)
+   return 0;
+ }
+ 
++/***
++duplicate ts_resp object
++@function dup
++@treturn ts_resp object
++*/
+ static LUA_FUNCTION(openssl_ts_resp_dup)
+ {
+   TS_RESP *res = CHECK_OBJECT(1, TS_RESP, "openssl.ts_resp");
+@@ -323,8 +544,14 @@ static LUA_FUNCTION(openssl_ts_resp_dup)
+   return 1;
+ }
+ 
++/***
++export ts_resp to string
++@function export
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_ts_resp_export)
+ {
++  int ret = 0;
+   TS_RESP *res = CHECK_OBJECT(1, TS_RESP, "openssl.ts_resp");
+   BIO *bio = BIO_new(BIO_s_mem());
+   if (i2d_TS_RESP_bio(bio, res))
+@@ -332,21 +559,42 @@ static LUA_FUNCTION(openssl_ts_resp_expo
+     BUF_MEM *bptr = NULL;
+     BIO_get_mem_ptr(bio, &bptr);
+     lua_pushlstring(L, bptr->data, bptr->length);
+-    BIO_free(bio);
+-    return 1;
++    ret = 1;
+   }
+-  return 0;
++  BIO_free(bio);
++  return ret;
+ }
+ 
+-static int openssl_push_ts_accuracy(lua_State*L, const TS_ACCURACY* accuracy)
++static int openssl_push_ts_accuracy(lua_State*L, const TS_ACCURACY* accuracy, int asobj)
+ {
+-  lua_newtable(L);
+-  PUSH_ASN1_INTEGER(L, accuracy->micros);
+-  lua_setfield(L, -2, "micros");
+-  PUSH_ASN1_INTEGER(L, accuracy->millis);
+-  lua_setfield(L, -2, "millis");
+-  PUSH_ASN1_INTEGER(L, accuracy->seconds);
+-  lua_setfield(L, -2, "seconds");
++  if (accuracy)
++  {
++    if (asobj)
++    {
++      unsigned char *pbuf = NULL;
++      int len = i2d_TS_ACCURACY(accuracy, &pbuf);
++      if (len > 0)
++      {
++        lua_pushlstring(L, (const char*)pbuf, len);
++        OPENSSL_free(pbuf);
++      }
++      else
++        lua_pushnil(L);
++    }
++    else
++    {
++      lua_newtable(L);
++
++      PUSH_ASN1_INTEGER(L, TS_ACCURACY_get_micros(accuracy));
++      lua_setfield(L, -2, "micros");
++      PUSH_ASN1_INTEGER(L, TS_ACCURACY_get_millis(accuracy));
++      lua_setfield(L, -2, "millis");
++      PUSH_ASN1_INTEGER(L, TS_ACCURACY_get_seconds(accuracy));
++      lua_setfield(L, -2, "seconds");
++    }
++  }
++  else
++    lua_pushnil(L);
+ 
+   return 1;
+ }
+@@ -358,7 +606,8 @@ static int openssl_push_ts_msg_imprint(l
+   lua_newtable(L);
+   if (alg)
+   {
+-    openssl_push_x509_algor(L, alg);
++    alg = X509_ALGOR_dup(alg);
++    PUSH_OBJECT(alg, "openssl.x509_algor");
+     lua_setfield(L, -2, "algo");
+   }
+   if (str)
+@@ -373,62 +622,53 @@ static int openssl_push_ts_msg_imprint(l
+ static int openssl_push_ts_tst_info(lua_State*L, TS_TST_INFO* info)
+ {
+   lua_newtable(L);
+-  if (info->version)
+-  {
+-    PUSH_ASN1_INTEGER(L, info->version);
+-    lua_setfield(L, -2, "version");
+-  }
+-  if (info->policy_id)
+-  {
+-    openssl_push_asn1object(L, info->policy_id);
+-    lua_setfield(L, -2, "policy_id");
+-  }
+-  if (info->msg_imprint)
+-  {
+-    openssl_push_ts_msg_imprint(L, info->msg_imprint);
+-    lua_setfield(L, -2, "msg_imprint");
+-  }
+-  if (info->serial)
+-  {
+-    PUSH_ASN1_INTEGER(L, info->serial);
+-    lua_setfield(L, -2, "serial");
+-  }
+-  if (info->time)
+-  {
+-    openssl_push_asn1(L, info->time, V_ASN1_GENERALIZEDTIME);
+-    lua_setfield(L, -2, "time");
+-  }
+-  if (info->accuracy)
+-  {
+-    openssl_push_ts_accuracy(L, info->accuracy);
+-    lua_setfield(L, -2, "accuracy");
+-  }
+ 
+-  AUXILIAR_SET(L, -1, "ordering", info->ordering, boolean);
++  lua_pushinteger(L, TS_TST_INFO_get_version(info));
++  lua_setfield(L, -2, "version");
+ 
+-  if (info->nonce)
+-  {
+-    PUSH_ASN1_INTEGER(L, info->nonce);
+-    lua_setfield(L, -2, "nonce");
+-  }
+-  if (info->tsa)
+-  {
+-    openssl_push_general_name(L, info->tsa);
+-    lua_setfield(L, -2, "tsa");
+-  }
+-  if (info->extensions)
++  openssl_push_asn1object(L, TS_TST_INFO_get_policy_id(info));
++  lua_setfield(L, -2, "policy_id");
++
++  openssl_push_ts_msg_imprint(L, TS_TST_INFO_get_msg_imprint(info));
++  lua_setfield(L, -2, "msg_imprint");
++
++  PUSH_ASN1_INTEGER(L, TS_TST_INFO_get_serial(info));
++  lua_setfield(L, -2, "serial");
++
++  openssl_push_asn1(L, TS_TST_INFO_get_time(info), V_ASN1_GENERALIZEDTIME);
++  lua_setfield(L, -2, "time");
++
++  openssl_push_ts_accuracy(L, TS_TST_INFO_get_accuracy(info), 1);
++  lua_setfield(L, -2, "accuracy");
++
++  AUXILIAR_SET(L, -1, "ordering", TS_TST_INFO_get_ordering(info), boolean);
++
++  PUSH_ASN1_INTEGER(L, TS_TST_INFO_get_nonce(info));
++  lua_setfield(L, -2, "nonce");
++
++  openssl_push_general_name(L, TS_TST_INFO_get_tsa(info));
++  lua_setfield(L, -2, "tsa");
++
++  if (TS_TST_INFO_get_exts(info))
+   {
+     lua_pushstring(L, "extensions");
+-    openssl_sk_x509_extension_totable(L, info->extensions);
++    openssl_sk_x509_extension_totable(L, TS_TST_INFO_get_exts(info));
+     lua_rawset(L, -3);
+   }
++
+   return 1;
+ }
+ 
++/***
++get info as table
++@function tst_info
++@treturn table
++*/
+ static LUA_FUNCTION(openssl_ts_resp_tst_info)
+ {
+   TS_RESP *resp = CHECK_OBJECT(1, TS_RESP, "openssl.ts_resp");
+-  TS_TST_INFO *info = resp->tst_info;
++  TS_TST_INFO *info = TS_RESP_get_tst_info(resp);
++
+   if (info)
+     openssl_push_ts_tst_info(L, info);
+   else
+@@ -436,6 +676,11 @@ static LUA_FUNCTION(openssl_ts_resp_tst_
+   return 1;
+ }
+ 
++/***
++get info as table
++@function info
++@treturn table
++*/
+ static LUA_FUNCTION(openssl_ts_resp_info)
+ {
+   TS_RESP *res = CHECK_OBJECT(1, TS_RESP, "openssl.ts_resp");
+@@ -443,26 +688,28 @@ static LUA_FUNCTION(openssl_ts_resp_info
+   lua_newtable(L);
+ 
+   {
+-    lua_newtable(L);
++    TS_STATUS_INFO *si = TS_RESP_get_status_info(res);
++    const ASN1_BIT_STRING *failure_info = TS_STATUS_INFO_get0_failure_info(si);
+ 
+-    PUSH_ASN1_INTEGER(L, res->status_info->status);
++    lua_newtable(L);
++    PUSH_ASN1_INTEGER(L, TS_STATUS_INFO_get0_status(si));
+     lua_setfield(L, -2, "status");
+ 
+-    if (res->status_info->failure_info)
++    if (failure_info)
+     {
+-      openssl_push_asn1(L, res->status_info->failure_info, V_ASN1_BIT_STRING);
++      openssl_push_asn1(L, failure_info, V_ASN1_BIT_STRING);
+       lua_setfield(L, -2, "failure_info");
+     }
+ 
+-    if (res->status_info->text)
++    if (TS_STATUS_INFO_get0_text(si))
+     {
+-      STACK_OF(ASN1_UTF8STRING) * sk = res->status_info->text;
++      const STACK_OF(ASN1_UTF8STRING) * sk = TS_STATUS_INFO_get0_text(si);
+       int i = 0, n = 0;
+       lua_newtable(L);
+-      n = SKM_sk_num(ASN1_UTF8STRING, sk);
++      n = sk_ASN1_UTF8STRING_num(sk);
+       for (i = 0; i < n; i++)
+       {
+-        ASN1_UTF8STRING *x =  SKM_sk_value(ASN1_UTF8STRING, sk, i);
++        ASN1_UTF8STRING *x = sk_ASN1_UTF8STRING_value(sk, i);
+         lua_pushlstring(L, (const char*)x->data, x->length);
+         lua_rawseti(L, -2, i + 1);
+       }
+@@ -473,35 +720,21 @@ static LUA_FUNCTION(openssl_ts_resp_info
+   }
+ 
+ 
+-  if (res->token)
++  if (TS_RESP_get_token(res))
+   {
+-    PKCS7* token = PKCS7_dup(res->token);
++    PKCS7* token = PKCS7_dup(TS_RESP_get_token(res));
+     AUXILIAR_SETOBJECT(L, token, "openssl.pkcs7", -1, "token");
+   }
+ 
+-  if (res->tst_info)
++  if (TS_RESP_get_tst_info(res))
+   {
+-    openssl_push_ts_tst_info(L, res->tst_info);
++    openssl_push_ts_tst_info(L, TS_RESP_get_tst_info(res));
+     lua_setfield(L, -2, "tst_info");
+   }
+ 
+   return 1;
+ }
+ 
+-static LUA_FUNCTION(openssl_ts_resp_read)
+-{
+-  BIO* in = load_bio_object(L, 1);
+-  TS_RESP *res = d2i_TS_RESP_bio(in, NULL);
+-  BIO_free(in);
+-  if (res)
+-  {
+-    PUSH_OBJECT(res, "openssl.ts_resp");
+-  }
+-  else
+-    lua_pushnil(L);
+-  return 1;
+-}
+-
+ static luaL_Reg ts_resp_funs[] =
+ {
+   {"dup",           openssl_ts_resp_dup},
+@@ -516,7 +749,22 @@ static luaL_Reg ts_resp_funs[] =
+ };
+ 
+ /********************************************************/
+-
++/***
++openssl.ts_resp_ctx object
++@type ts_resp_ctx
++*/
++/***
++create response for ts_req
++@function create_response
++@tparam string|bio|ts_req data support string,bio ts_req content or ts_req object
++@treturn ts_resp result
++*/
++/***
++sign ts_req and get ts_resp, alias of create_response
++@function sign
++@tparam string|bio|ts_req data support string,bio ts_req content or ts_req object
++@treturn ts_resp result
++*/
+ static LUA_FUNCTION(openssl_ts_create_response)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+@@ -545,268 +793,189 @@ static LUA_FUNCTION(openssl_ts_create_re
+   return 1;
+ }
+ 
+-static LUA_FUNCTION(openssl_ts_resp_ctx_new)
+-{
+-  TS_RESP_CTX* ctx = TS_RESP_CTX_new();
+-  int i = 0;
+-  int n = lua_gettop(L);
+-  X509 *signer = NULL;
+-  EVP_PKEY *pkey = NULL;
+-  int nid = NID_undef;
+-  int ret = 1;
+-
+-  for (i = 1; i <= n; i++)
+-  {
+-    if (auxiliar_isclass(L, "openssl.x509", i))
+-    {
+-      signer = CHECK_OBJECT(i, X509, "openssl.x509");
+-    }
+-    else if (auxiliar_isclass(L, "openssl.evp_pkey", i))
+-    {
+-      pkey = CHECK_OBJECT(i, EVP_PKEY, "openssl.evp_pkey");
+-      luaL_argcheck(L, openssl_pkey_is_private(pkey), i, "must be private key");
+-    }
+-    else if (lua_isnumber(L, i) || lua_isstring(L, i) || auxiliar_isclass(L, "openssl.asn1_object", i))
+-    {
+-      nid = openssl_get_nid(L, i);
+-      luaL_argcheck(L, nid != NID_undef, i, "invalid asn1_object or object id");
+-    }
+-    else
+-      luaL_argerror(L, i, "not accept paramater");
+-  }
+-  if (signer && pkey)
+-  {
+-    ret = X509_check_private_key(signer, pkey);
+-    if (ret != 1)
+-    {
+-      luaL_error(L, "singer cert and private key not match");
+-    }
+-  }
+-  if (ret == 1 && nid != NID_undef)
+-    ret = TS_RESP_CTX_set_def_policy(ctx, OBJ_nid2obj(nid));
+-
+-  if (ret == 1 && signer)
+-    ret = TS_RESP_CTX_set_signer_cert(ctx, signer);
+-  if (ret == 1 && pkey)
+-    ret = TS_RESP_CTX_set_signer_key(ctx, pkey);
+-
+-  if (ret == 1)
+-  {
+-    PUSH_OBJECT(ctx, "openssl.ts_resp_ctx");
+-    openssl_newvalue(L, ctx);
+-  }
+-  else
+-  {
+-    TS_RESP_CTX_free(ctx);
+-    ctx = NULL;
+-    lua_pushnil(L);
+-  }
+-  return 1;
+-}
+-
++/***
++get signer cert and pkey
++@function signer
++@treturn x509 cert object or nil
++@treturn evp_pkey pkey object or nil
++*/
++/***
++set signer cert and pkey
++@function signer
++@tparam x509 cert signer cert
++@tparam evp_pkey pkey signer pkey
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_singer)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    if (ctx->signer_cert)
+-    {
+-      X509* x = ctx->signer_cert;
+-      x = X509_dup(x);
+-      PUSH_OBJECT(x, "openssl.x509");
+-    }
+-    else
+-      lua_pushnil(L);
+-    if (ctx->signer_key)
+-    {
+-      EVP_PKEY* pkey = ctx->signer_key;
+-      CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+-      PUSH_OBJECT(pkey, "openssl.evp_pkey");
+-    }
+-    else
+-      lua_pushnil(L);
+-    return 2;
+-  }
+-  else
++  X509 *signer = CHECK_OBJECT(2, X509, "openssl.x509");
++  EVP_PKEY *pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
++  int ret = X509_check_private_key(signer, pkey);
++  if (ret != 1)
+   {
+-    X509 *signer = CHECK_OBJECT(2, X509, "openssl.x509");
+-    EVP_PKEY *pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
+-    int ret;
+-    luaL_argcheck(L, openssl_pkey_is_private(pkey), 3, "must be private key");
+-    ret = X509_check_private_key(signer, pkey);
+-    if (ret != 1)
+-    {
+-      luaL_error(L, "signer cert and private key not match");
+-    }
+-    if (ret == 1)
+-      ret = TS_RESP_CTX_set_signer_cert(ctx, signer);
+-    if (ret == 1)
+-      ret = TS_RESP_CTX_set_signer_key(ctx, pkey);
+-    return openssl_pushresult(L, ret);
++    luaL_error(L, "signer cert and private key not match");
+   }
++  if (ret == 1)
++    ret = TS_RESP_CTX_set_signer_cert(ctx, signer);
++  if (ret == 1)
++    ret = TS_RESP_CTX_set_signer_key(ctx, pkey);
++  return openssl_pushresult(L, ret);
+ }
+ 
++/***
++set additional certs
++@function certs
++@tparam table certs array of certificates
++@treturn boolean success
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_certs)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    if (ctx->certs)
+-    {
+-      openssl_sk_x509_totable(L, ctx->certs);
+-    }
+-    else
+-    {
+-      lua_pushnil(L);
+-    };
+-  }
+-  else
+-  {
+-    if (ctx->certs)
+-    {
+-      sk_X509_pop_free(ctx->certs, X509_free);
+-    }
+-    ctx->certs = openssl_sk_x509_fromtable(L, 2);
+-    lua_pushboolean(L, 1);
+-  }
+-  return 1;
++  STACK_OF(X509) *certs = openssl_sk_x509_fromtable(L, 2);
++  TS_RESP_CTX_set_certs(ctx, certs);
++  return 0;
+ }
+ 
++/***
++set default policy
++@function default_policy
++@tparam asn1_object|integer|string policy
++@treturn boolean success
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_default_policy)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    if (ctx->default_policy)
+-      openssl_push_asn1object(L, ctx->default_policy);
+-    else
+-      lua_pushnil(L);
+-  }
+-  else
+-  {
+-    int nid = openssl_get_nid(L, 2);
+-    if (ctx->default_policy)
+-      ASN1_OBJECT_free(ctx->default_policy);
+-    ctx->default_policy = OBJ_nid2obj(nid);
+-    lua_pushboolean(L, 1);
+-  }
+-  return 1;
++  int nid = openssl_get_nid(L, 2);
++  int ret = TS_RESP_CTX_set_def_policy(ctx, OBJ_nid2obj(nid));
++  return openssl_pushresult(L, ret);
+ }
+ 
++/***
++set policies
++@function policies
++@tparam asn1_object|integer|string|stack_of_asn1_object|table policies
++@treturn boolean success
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_policies)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
++  ASN1_OBJECT *obj = NULL;
++  int ret = 1;
++  int nid;
++  int i;
++  int n = lua_gettop(L);
++  luaL_argcheck(L, n > 1, 2, "need one or more asn1_object");
++  for (i = 2; i <= n && ret == 1; i++)
+   {
+-    if (ctx->policies)
++    if (lua_istable(L, i))
+     {
+-      int i, n;
+-      lua_newtable(L);
+-      n = sk_ASN1_OBJECT_num(ctx->policies);
+-      for (i = 0; i < n; i++)
++      int j, k;
++      k = lua_rawlen(L, i);
++      for (j = 1; j <= k && ret == 1; j++)
+       {
+-        ASN1_OBJECT* obj = sk_ASN1_OBJECT_value(ctx->policies, i);
+-        lua_pushinteger(L, i + 1);
+-        PUSH_OBJECT(obj, "openssl.asn1_object");
+-        lua_rawset(L, -3);
+-      }
+-    }
+-    else
+-      lua_pushnil(L);
+-  }
+-  else
+-  {
+-    if (lua_istable(L, 2))
+-    {
++        lua_rawgeti(L, i, j);
++        if (auxiliar_getclassudata(L, "openssl.asn1_object", -1))
++        {
++          obj = CHECK_OBJECT(-1, ASN1_OBJECT, "openssl.asn1_object");
++        }
++        else
++        {
++          nid = openssl_get_nid(L, -1);
++          obj = nid!=NID_undef ? OBJ_nid2obj(nid) : NULL;
++        }
+ 
+-    }
+-    else
+-    {
+-      int n = lua_gettop(L);
+-      int ret = 1;
+-      int nid;
+-      int i;
+-      for (i = 2; i <= n && ret == 1; i++)
+-      {
+-        if (lua_istable(L, i))
++        lua_pop(L, 1);
++
++        if (obj)
+         {
+-          int j, k;
+-          k = lua_rawlen(L, i);
+-          for (j = 1; j <= k && ret == 1; j++)
+-          {
+-            lua_rawgeti(L, i, j);
+-            nid = openssl_get_nid(L, -1);
+-            lua_pop(L, 1);
+-
+-            if (nid != NID_undef)
+-            {
+-              ret = TS_RESP_CTX_add_policy(ctx, OBJ_nid2obj(nid));
+-            }
+-            else
+-            {
+-              lua_pushfstring(L, "index %d is invalid asn1_object or object id", j);
+-              luaL_argerror(L, i, lua_tostring(L, -1));
+-            }
+-          }
++          ret = TS_RESP_CTX_add_policy(ctx, obj);
+         }
+         else
+         {
+-          nid = openssl_get_nid(L, i);
+-          if (nid != NID_undef)
+-          {
+-            ret = TS_RESP_CTX_add_policy(ctx, OBJ_nid2obj(nid));
+-          }
+-          else
+-            luaL_argerror(L, i, "invalid asn1_object or id");
++          lua_pushfstring(L, "index %d is invalid asn1_object or object id", j);
++          luaL_argerror(L, i, lua_tostring(L, -1));
+         }
+       }
+-      return openssl_pushresult(L, ret);
++    }
++    else
++    {
++      if (auxiliar_getclassudata(L, "openssl.asn1_object", i))
++      {
++        obj = CHECK_OBJECT(i, ASN1_OBJECT, "openssl.asn1_object");
++      }
++      else
++      {
++        nid = openssl_get_nid(L, i);
++        obj = nid != NID_undef ? OBJ_nid2obj(nid) : NULL;
++      }
++      if (obj)
++      {
++        ret = TS_RESP_CTX_add_policy(ctx, obj);
++      }
++      else
++        luaL_argerror(L, i, "invalid asn1_object or id");
+     }
+   }
+-  return 1;
++  return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get accuracy
++@function accuracy
++@treturn integer seconds
++@treturn integer millis
++@treturn integer micros
++*/
++/***
++set accuracy
++@function accuracy
++@tparam integer seconds
++@tparam integer millis
++@tparam integer micros
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_accuracy)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    lua_pushinteger(L, ASN1_INTEGER_get(ctx->seconds));
+-    lua_pushinteger(L, ASN1_INTEGER_get(ctx->millis));
+-    lua_pushinteger(L, ASN1_INTEGER_get(ctx->micros));
+-    return 3;
+-  }
+-  else
+-  {
+-    int seconds = luaL_checkint(L, 2);
+-    int millis  = luaL_checkint(L, 3);
+-    int micros  = luaL_checkint(L, 4);
+-    int ret = TS_RESP_CTX_set_accuracy(ctx, seconds, millis, micros);
+-    return openssl_pushresult(L, ret);
+-  }
++  int seconds = luaL_checkint(L, 2);
++  int millis = luaL_checkint(L, 3);
++  int micros = luaL_checkint(L, 4);
++  int ret = TS_RESP_CTX_set_accuracy(ctx, seconds, millis, micros);
++  return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get clock_precision_digits
++@function clock_precision_digits
++@treturn integer clock_precision_digits
++*/
++/***
++set clock_precision_digits
++@function clock_precision_digits
++@tparam integer clock_precision_digits
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_clock_precision_digits)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    lua_pushinteger(L, ctx->clock_precision_digits);
+-    return 1;
+-  }
+-  else
+-  {
+-    int ret;
+-    int clock_precision_digits = luaL_checkint(L, 2);
+-    if (clock_precision_digits > TS_MAX_CLOCK_PRECISION_DIGITS)
+-      clock_precision_digits = TS_MAX_CLOCK_PRECISION_DIGITS;
+-    if (clock_precision_digits < 0)
+-      clock_precision_digits = 0;
+-    ret = TS_RESP_CTX_set_clock_precision_digits(ctx, clock_precision_digits);
+-    return openssl_pushresult(L, ret);
+-  }
++  int ret;
++  int clock_precision_digits = luaL_checkint(L, 2);
++  if (clock_precision_digits > TS_MAX_CLOCK_PRECISION_DIGITS)
++    clock_precision_digits = TS_MAX_CLOCK_PRECISION_DIGITS;
++  if (clock_precision_digits < 0)
++    clock_precision_digits = 0;
++  ret = TS_RESP_CTX_set_clock_precision_digits(ctx, clock_precision_digits);
++  return openssl_pushresult(L, ret);
+ }
+ 
++/***
++set status info
++@function set_status_info
++@tparam integer status
++@tparam string text
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_set_status_info)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+@@ -816,6 +985,13 @@ static LUA_FUNCTION(openssl_ts_resp_ctx_
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++set status info cond
++@function set_status_info_cond
++@tparam integer status
++@tparam string text
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_set_status_info_cond)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+@@ -825,6 +1001,12 @@ static LUA_FUNCTION(openssl_ts_resp_ctx_
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++add failure info
++@function add_failure_info
++@tparam integer failure
++@treturn result
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_add_failure_info)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+@@ -833,51 +1015,35 @@ static LUA_FUNCTION(openssl_ts_resp_ctx_
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get flags
++@function flags
++@treturn integer flags
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_flags)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    lua_pushinteger(L, ctx->flags);
+-  }
+-  else if (lua_isnumber(L, 2))
+-  {
+-    int flags = luaL_checkint(L, 2);
+-    ctx->flags = flags;
+-    lua_pushboolean(L, 1);
+-  }
+-  else if (lua_isstring(L, 2))
+-  {
+-    /* TS_RESP_CTX_add_flags(ctx, ) */
+-    luaL_error(L, "not support");
+-  }
+-  else
+-    luaL_error(L, "not support");
+-  return 1;
++  int flags = luaL_checkint(L, 2);
++  TS_RESP_CTX_add_flags(ctx, flags);
++  return 0;
+ }
+ 
++/***
++set support digest method
++@function md
++@tparam table mds support digest method
++@treturn boolean result
++*/
++/***
++add digest
++@function md
++@tparam string|evp_digest md_alg
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_md)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    if (ctx->mds)
+-    {
+-      int i;
+-      int n = sk_EVP_MD_num(ctx->mds);
+-      lua_newtable(L);
+-      for (i = 0; i < n; i++)
+-      {
+-        EVP_MD* md = sk_EVP_MD_value(ctx->mds, i);
+-        PUSH_OBJECT(md, "openssl.evp_digest");
+-        lua_rawseti(L, -2, i + 1);
+-      }
+-    }
+-    else
+-      lua_pushnil(L);
+-    return 1;
+-  }
+-  else if (lua_istable(L, 2))
++  if (lua_istable(L, 2))
+   {
+     int i;
+     int n = lua_rawlen(L, 2);
+@@ -886,7 +1052,7 @@ static LUA_FUNCTION(openssl_ts_resp_ctx_
+     {
+       const EVP_MD* md;
+       lua_rawgeti(L, 2, i);
+-      md = get_digest(L, -1);
++      md = get_digest(L, -1, NULL);
+       lua_pop(L, 1);
+       if (md)
+       {
+@@ -903,12 +1069,17 @@ static LUA_FUNCTION(openssl_ts_resp_ctx_
+   }
+   else
+   {
+-    const EVP_MD* md = get_digest(L, 2);
++    const EVP_MD* md = get_digest(L, 2, NULL);
+     int ret = TS_RESP_CTX_add_md(ctx, md);
+     return openssl_pushresult(L, ret);
+   }
+ }
+ 
++/***
++get tst_info as table
++@function tst_info
++@treturn table tst_info
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_tst_info)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+@@ -923,6 +1094,11 @@ static LUA_FUNCTION(openssl_ts_resp_ctx_
+   return 1;
+ }
+ 
++/***
++get ts_req object
++@function request
++@treturn rs_req
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_request)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+@@ -938,9 +1114,7 @@ static LUA_FUNCTION(openssl_ts_resp_ctx_
+ 
+ typedef struct
+ {
+-  lua_State* L;
+   int callback;
+-  int ctx;
+   int cb_arg;
+ } TS_CB_ARG;
+ 
+@@ -949,112 +1123,186 @@ static const char* serial_cb_key = "seri
+ 
+ static ASN1_INTEGER* openssl_serial_cb(TS_RESP_CTX*ctx, void*data)
+ {
+-  TS_CB_ARG *arg = (TS_CB_ARG*)data;
+-  lua_State* L = arg->L;
+-  ASN1_INTEGER *ai = NULL;
+   int err;
+-  (void)ctx;
++  TS_CB_ARG *arg;
++  lua_State* L = data;
++
++  openssl_valueget(L, ctx, serial_cb_key);
++  if (!lua_isuserdata(L, -1))
++  {
++    TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                "Error during serial number generation.");
++    TS_RESP_CTX_add_failure_info(ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE);
++
++    lua_pop(L, 1);
++    return NULL;
++  }
++  arg = lua_touserdata(L, -1);
++  lua_pop(L, 1); /* remove openssl_valueget returned value */
++
+   lua_rawgeti(L, LUA_REGISTRYINDEX, arg->callback);
+-  lua_rawgeti(L, LUA_REGISTRYINDEX, arg->ctx);
+   lua_rawgeti(L, LUA_REGISTRYINDEX, arg->cb_arg);
+-  err = lua_pcall(L, 2, 1, 0);
++  err = lua_pcall(L, 1, 1, 0);
+   if (err == 0)
+   {
++    ASN1_INTEGER *ai = NULL;
+     BIGNUM *bn = BN_get(L, -1);
+-    lua_pop(L, 1);
++    lua_pop(L, 1);  /* remove callback returned value */
+     if (bn)
+     {
+       ai = BN_to_ASN1_INTEGER(bn, NULL);
+       BN_free(bn);
+     }
+     if (ai == NULL)
+-      luaL_error(L, "serial_cb not return openssl.bn");
++    {
++      TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                  "Error during serial number generation.");
++      TS_RESP_CTX_add_failure_info(ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE);
++      luaL_error(L, "Error during serial number generation.");
++    }
++    return ai;
+   }
+   else
++  {
+     lua_error(L);
+-  return ai;
++  }
++  return NULL;
+ };
+ 
++/***
++set serial generate callback function
++@function set_serial_cb
++@tparam function serial_cb serial_cb with proto funciont(ts_resp_ctx, arg) return openssl.bn end
++@usage
++  function serial_cb(tsa,arg)
++    local bn = ...
++    return bn
++  end
++  local arg = {}
++  ts_resp_ctx:set_serial_cb(serial_cb, arg)
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_set_serial_cb)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  int cbref, argref;
+   TS_CB_ARG* arg = NULL;
++  int top = lua_gettop(L);
++
+   luaL_checktype(L, 2, LUA_TFUNCTION);
++  arg = (TS_CB_ARG*)lua_newuserdata(L, sizeof(TS_CB_ARG));
+ 
+   lua_pushvalue(L, 2);
+-  cbref = luaL_ref(L, LUA_REGISTRYINDEX);
+-  lua_pushvalue(L, 3);
+-  argref = luaL_ref(L, LUA_REGISTRYINDEX);
+-
+-  arg = (TS_CB_ARG*)lua_newuserdata(L, sizeof(TS_CB_ARG));
+-  arg->callback = cbref;
+-  arg->cb_arg = argref;
+-  arg->L = L;
+-  lua_pushvalue(L, 1);
+-  arg->ctx = luaL_ref(L, LUA_REGISTRYINDEX);
+-  openssl_setvalue(L, ctx, "serial_cb");
++  arg->callback = luaL_ref(L, LUA_REGISTRYINDEX);
++  if (top > 2)
++    lua_pushvalue(L, 3);
++  else
++    lua_pushnil(L);
++  arg->cb_arg = luaL_ref(L, LUA_REGISTRYINDEX);
+ 
+-  TS_RESP_CTX_set_serial_cb(ctx, openssl_serial_cb, arg);
++  openssl_valueset(L, ctx, serial_cb_key);
++  TS_RESP_CTX_set_serial_cb(ctx, openssl_serial_cb, L);
+   return 0;
+ };
+ 
+ static int openssl_time_cb(TS_RESP_CTX *ctx, void *data, long *sec, long *usec)
+ {
+-  TS_CB_ARG *arg = (TS_CB_ARG*)data;
+-  lua_State* L = arg->L;
+   int err;
+-  (void) ctx;
++  TS_CB_ARG *arg;
++  lua_State* L = data;
++
++  openssl_valueget(L, ctx, time_cb_key);
++  if (!lua_isuserdata(L, -1))
++  {
++    TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                "could not get current time");
++    lua_pop(L, 1);  /* remove openssl_valueget returned value */
++    return 0;
++  }
++  arg = lua_touserdata(L, -1);
++  lua_pop(L, 1);  /* remove openssl_valueget returned value */
++
+   lua_rawgeti(L, LUA_REGISTRYINDEX, arg->callback);
+-  lua_rawgeti(L, LUA_REGISTRYINDEX, arg->ctx);
+   lua_rawgeti(L, LUA_REGISTRYINDEX, arg->cb_arg);
+-  err = lua_pcall(L, 2, 2, 0);
++  err = lua_pcall(L, 1, 2, 0);
+   if (err == 0)
+   {
+-    if (lua_isnil(L, -2))
+-    {
+-      lua_pop(L, 2);
+-      return 0;
+-    }
+-    else
++    if (lua_isnumber(L, -2))
+     {
+       *sec = (long)luaL_checkinteger(L, -2);
+       *usec = (long)luaL_optinteger(L, -1, 0);
+-      lua_pop(L, 2);
++      lua_pop(L, 2);  /* remove callback returned value */
+       return 1;
+     }
++    lua_pop(L, 2);    /* remove callback returned value */
++
++    TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
++                                "could not get current time");
++    return 0;
+   }
+   else
++  {
+     lua_error(L);
++  }
+   return 0;
+ }
+ 
++/***
++set time callback function
++@function set_time_cb
++@tparam function time_cb serial_cb with proto funciont(ts_resp_ctx, arg) return sec, usec end
++@usage
++  function time_cb(tsa,arg)
++    local time = os.time()
++    local utime = nil
++    return time,utime
++  end
++  local arg = {}
++  ts_resp_ctx:set_time_cb(time_cb, arg)
++*/
+ static LUA_FUNCTION(openssl_ts_resp_ctx_set_time_cb)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
+-  int cbref, argref;
+   TS_CB_ARG* arg = NULL;
++  int top = lua_gettop(L);
+   luaL_checktype(L, 2, LUA_TFUNCTION);
++  arg = (TS_CB_ARG*)lua_newuserdata(L, sizeof(TS_CB_ARG));
+ 
+   lua_pushvalue(L, 2);
+-  cbref = luaL_ref(L, LUA_REGISTRYINDEX);
+-  lua_pushvalue(L, 3);
+-  argref = luaL_ref(L, LUA_REGISTRYINDEX);
++  arg->callback = luaL_ref(L, LUA_REGISTRYINDEX);
++  if (top > 2)
++    lua_pushvalue(L, 3);
++  else
++    lua_pushnil(L);
++  arg->cb_arg = luaL_ref(L, LUA_REGISTRYINDEX);
+ 
+-  arg = (TS_CB_ARG*)lua_newuserdata(L, sizeof(TS_CB_ARG));
+-  arg->callback = cbref;
+-  arg->cb_arg = argref;
+-  lua_pushvalue(L, 1);
+-  arg->ctx = luaL_ref(L, LUA_REGISTRYINDEX);
+-  arg->L = L;
+-  lua_rawsetp(L, LUA_REGISTRYINDEX, ctx);
+-  TS_RESP_CTX_set_time_cb(ctx, openssl_time_cb, arg);
++  openssl_valueset(L, ctx, time_cb_key);
++#if defined(LIBRESSL_VERSION_NUMBER)
++  ctx->time_cb = openssl_time_cb;
++  ctx->time_cb_data = L;
++#else
++  TS_RESP_CTX_set_time_cb(ctx, openssl_time_cb, L);
++#endif
+   return 0;
+ }
+ 
+ static LUA_FUNCTION(openssl_ts_resp_ctx_gc)
+ {
+   TS_RESP_CTX *ctx = CHECK_OBJECT(1, TS_RESP_CTX, "openssl.ts_resp_ctx");
++  openssl_valueget(L, ctx, time_cb_key);
++  if (lua_isuserdata(L, -1))
++  {
++    TS_CB_ARG *arg = lua_touserdata(L, -1);
++    luaL_unref(L, LUA_REGISTRYINDEX, arg->callback);
++    luaL_unref(L, LUA_REGISTRYINDEX, arg->cb_arg);
++  }
++  lua_pop(L, 1);
++  openssl_valueget(L, ctx, serial_cb_key);
++  if (lua_isuserdata(L, -1))
++  {
++    TS_CB_ARG *arg = lua_touserdata(L, -1);
++    luaL_unref(L, LUA_REGISTRYINDEX, arg->callback);
++    luaL_unref(L, LUA_REGISTRYINDEX, arg->cb_arg);
++  }
++  lua_pop(L, 1);
+   openssl_freevalue(L, ctx);
+   TS_RESP_CTX_free(ctx);
+   return 0;
+@@ -1095,180 +1343,125 @@ static luaL_Reg ts_resp_ctx_funs[] =
+ 
+ /********************************************************************/
+ 
+-static LUA_FUNCTION(openssl_ts_verify_ctx_new)
+-{
+-  TS_VERIFY_CTX *ctx = NULL;
+-  if (lua_isnone(L, 1))
+-  {
+-    ctx = TS_VERIFY_CTX_new();
+-    ctx->flags |= TS_VFY_SIGNATURE;
+-  }
+-  else if (lua_isstring(L, 1))
+-  {
+-    BIO* bio = load_bio_object(L, 1);
+-    TS_REQ* req = d2i_TS_REQ_bio(bio, NULL);
+-    BIO_free(bio);
+-    if (req)
+-    {
+-      ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL);
+-      TS_REQ_free(req);
+-    }
+-    else
+-    {
+-      luaL_argerror(L, 1, "must be ts_req data or object or nil");
+-    }
+-  }
+-  else
+-  {
+-    TS_REQ* req = CHECK_OBJECT(1, TS_REQ, "openssl.ts_req");
+-    ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL);
+-  }
+-  if (ctx)
+-  {
+-    PUSH_OBJECT(ctx, "openssl.ts_verify_ctx");
+-  }
+-  else
+-    lua_pushnil(L);
+-  return 1;
+-}
+-
++/***
++openssl.ts_verify_ctx object
++@type ts_verify_ctx
++*/
++/***
++get x509_store cacerts
++@function store
++@treturn stack_of_x509
++*/
++/***
++set x509_store cacerts
++@tparam x509_store cacerts
++@treturn boolean result
++@function store
++*/
+ static int openssl_ts_verify_ctx_store(lua_State*L)
+ {
+   TS_VERIFY_CTX *ctx = CHECK_OBJECT(1, TS_VERIFY_CTX, "openssl.ts_verify_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    /*
+-    if (ctx->store)
+-    {
+-      STACK_OF(X509) *cas =  X509_STORE_get1_certs(ctx->store, NULL);
+-      openssl_sk_x509_totable(L, cas);
+-    }
+-    else
+-    */
+-    lua_pushnil(L);
+-  }
+-  else
+-  {
+-    X509_STORE* store = CHECK_OBJECT(2, X509_STORE, "openssl.x509_store");
+-    if (ctx->store)
+-      openssl_xstore_free(ctx->store);
+-
+-    CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
+-    ctx->store = store;
+-    ctx->flags |= TS_VFY_SIGNER | TS_VFY_SIGNATURE;
+-    lua_pushboolean(L, 1);
+-  }
+-  return 1;
+-}
+-
+-static int openssl_ts_verify_ctx_certs(lua_State*L)
+-{
+-  TS_VERIFY_CTX *ctx = CHECK_OBJECT(1, TS_VERIFY_CTX, "openssl.ts_verify_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    if (ctx->certs)
+-    {
+-      openssl_sk_x509_totable(L, ctx->certs);
+-    }
+-    else
+-      lua_pushnil(L);
+-  }
+-  else
+-  {
+-    if (ctx->certs)
+-      sk_X509_pop_free(ctx->certs, X509_free);
+-
+-    ctx->certs = openssl_sk_x509_fromtable(L, 2);
+-    lua_pushboolean(L, 1);
+-  }
+-  return 1;
++  X509_STORE* store = CHECK_OBJECT(2, X509_STORE, "openssl.x509_store");
++  X509_STORE_up_ref(store);
++  TS_VERIFY_CTX_set_store(ctx, store);
++  return 0;
+ }
+ 
++/***
++get flags
++@function flags
++@treturn integer flags
++*/
++/***
++set flags
++@function flags
++@tparam integer flags
++@treturn boolean result
++*/
+ static int openssl_ts_verify_ctx_flags(lua_State*L)
+ {
+   TS_VERIFY_CTX *ctx = CHECK_OBJECT(1, TS_VERIFY_CTX, "openssl.ts_verify_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    lua_pushinteger(L, ctx->flags);
+-    return 1;
+-  }
+-  else
+-  {
+-    ctx->flags = luaL_checkinteger(L, 2);
+-  }
+-  return 0;
++  int flags = luaL_checkint(L, 2);
++  int add = lua_isnoneornil(L, 3) ? 0 : lua_toboolean(L, 3);
++  if (add)
++    flags = TS_VERIFY_CTX_add_flags(ctx, flags);
++  else
++    flags = TS_VERIFY_CTX_set_flags(ctx, flags);
++  lua_pushinteger(L, flags);
++  return 1;
+ }
+ 
++/***
++get data
++@function data
++@treturn bio data object
++*/
++/***
++set data
++@function data
++@tparam bio data object
++@treturn boolean result
++*/
+ static int openssl_ts_verify_ctx_data(lua_State*L)
+ {
+   TS_VERIFY_CTX *ctx = CHECK_OBJECT(1, TS_VERIFY_CTX, "openssl.ts_verify_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    if (ctx->data)
+-    {
+-      BIO* bio = ctx->data;
+-      CRYPTO_add(&bio->references, 1, CRYPTO_LOCK_BIO);
+-      PUSH_OBJECT(bio, "openssl.bio");
+-    }
+-    else
+-      lua_pushnil(L);
+-    return 1;
+-  }
+-  else
+-  {
+-    BIO* bio = load_bio_object(L, 2);
+-    if (ctx->data)
+-      BIO_free(ctx->data);
+-    ctx->data = bio;
+-    ctx->flags |= TS_VFY_DATA;
+-    lua_pushboolean(L, 1);
+-    return 1;
+-  }
++  BIO* bio = load_bio_object(L, 2);
++  BIO_up_ref(bio);
++  TS_VERIFY_CTX_set_data(ctx, bio);
++  return 0;
+ }
+ 
++/***
++get imprint
++@function imprint
++@treturn string imprint
++*/
++/***
++set imprint
++@function imprint
++@tparam string imprint
++@treturn boolean result
++*/
+ static int openssl_ts_verify_ctx_imprint(lua_State*L)
+ {
+   TS_VERIFY_CTX *ctx = CHECK_OBJECT(1, TS_VERIFY_CTX, "openssl.ts_verify_ctx");
+-  if (lua_isnone(L, 2))
+-  {
+-    lua_pushlstring(L, (const char*)ctx->imprint, ctx->imprint_len);
+-    return 1;
+-  }
+-  else
+-  {
+-    size_t imprint_len;
+-    const char* imprint = luaL_checklstring(L, 2, &imprint_len);
+-
+-    ctx->imprint = OPENSSL_malloc(imprint_len);
+-    memcpy(ctx->imprint, imprint, imprint_len);;
+-    ctx->imprint_len = imprint_len;
+-    ctx->flags |= TS_VFY_IMPRINT;
+-    lua_pushboolean(L, 1);
+-    return 1;
+-  }
++  size_t imprint_len;
++  const char* imprint = luaL_checklstring(L, 2, &imprint_len);
++  unsigned char* to = OPENSSL_malloc(imprint_len);
++  memcpy(to, imprint, imprint_len);
++  TS_VERIFY_CTX_set_imprint(ctx, to, imprint_len);
++  return 0;
+ }
+ 
+ static LUA_FUNCTION(openssl_ts_verify_ctx_gc)
+ {
+   TS_VERIFY_CTX *ctx = CHECK_OBJECT(1, TS_VERIFY_CTX, "openssl.ts_verify_ctx");
+-  if (ctx->store)
+-    openssl_xstore_free(ctx->store);
+-
++  /* hack openssl bugs */
++#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
++  if (ctx->store->references > 1)
++    CRYPTO_add(&ctx->store->references, -1, CRYPTO_LOCK_X509_STORE);
+   ctx->store = NULL;
++#endif
+   TS_VERIFY_CTX_free(ctx);
+   return 0;
+ }
+ 
++/***
++verify ts_resp object, pkcs7 token or ts_resp data
++@function verify
++@tparam ts_resp|pkcs7|string data
++@treturn boolean result
++*/
+ static LUA_FUNCTION(openssl_ts_verify_ctx_verify)
+ {
+   TS_VERIFY_CTX *ctx = CHECK_OBJECT(1, TS_VERIFY_CTX, "openssl.ts_verify_ctx");
+   int ret = 0;
+-  if (auxiliar_isclass(L, "openssl.ts_resp", 2))
++  if (auxiliar_getclassudata(L, "openssl.ts_resp", 2))
+   {
+     TS_RESP *response = CHECK_OBJECT(2, TS_RESP, "openssl.ts_resp");
+     ret = TS_RESP_verify_response(ctx, response);
+   }
+-  else if (auxiliar_isclass(L, "openssl.pkcs7", 2))
++  else if (auxiliar_getclassudata(L, "openssl.pkcs7", 2))
+   {
+     PKCS7 *token = CHECK_OBJECT(2, PKCS7, "openssl.pkcs7");
+     ret = TS_RESP_verify_token(ctx, token);
+@@ -1296,12 +1489,10 @@ static LUA_FUNCTION(openssl_ts_verify_ct
+ static luaL_Reg ts_verify_ctx_funs[] =
+ {
+   {"store",             openssl_ts_verify_ctx_store},
+-  {"certs",             openssl_ts_verify_ctx_certs},
+   {"flags",             openssl_ts_verify_ctx_flags},
+   {"verify",            openssl_ts_verify_ctx_verify},
+   {"data",              openssl_ts_verify_ctx_data},
+   {"imprint",           openssl_ts_verify_ctx_imprint},
+-//  {"info",              openssl_ts_verify_ctx_info},
+ 
+   {"__tostring",        auxiliar_tostring},
+   {"__gc",              openssl_ts_verify_ctx_gc},
+@@ -1309,17 +1500,6 @@ static luaL_Reg ts_verify_ctx_funs[] =
+   { NULL, NULL }
+ };
+ 
+-static luaL_Reg R[] =
+-{
+-  {"req_new",         openssl_ts_req_new},
+-  {"req_read",        openssl_ts_req_read},
+-  {"resp_read",       openssl_ts_resp_read},
+-
+-  {"resp_ctx_new",    openssl_ts_resp_ctx_new },
+-  {"verify_ctx_new",  openssl_ts_verify_ctx_new },
+-
+-  {NULL,    NULL}
+-};
+ #endif
+ int luaopen_ts(lua_State *L)
+ {
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/pkcs12.c luvi-src-v2.7.6/deps/lua-openssl/src/pkcs12.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/pkcs12.c	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/pkcs12.c	2019-02-13 11:53:24.298459641 +0100
+@@ -11,6 +11,25 @@
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
++/***
++Provide pkcs12 function in lua.
++
++@module pkcs12
++@usage
++  pkcs12 = require('openssl').pkcs12
++*/
++
++/***
++create and export pkcs12 data
++
++@function export
++@tparam x509 cert
++@tparam evp_pkey pkey
++@tparam string password
++@tparam[opt] string friendlyname
++@tparam[opt] table|stak_of_x509 extracerts
++@treturn string data
++*/
+ static LUA_FUNCTION(openssl_pkcs12_export)
+ {
+   X509 * cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -65,6 +84,14 @@ static LUA_FUNCTION(openssl_pkcs12_expor
+   return ret;
+ }
+ 
++/***
++parse pkcs12 data as lua table
++
++@function read
++@tparam string|bio input pkcs12 content
++@tparam string password for pkcs12
++@treturn table result contain 'cert', 'pkey', 'extracerts' keys
++*/
+ static LUA_FUNCTION(openssl_pkcs12_read)
+ {
+   PKCS12 * p12 = NULL;
+@@ -114,7 +141,7 @@ static LUA_FUNCTION(openssl_pkcs12_read)
+ static luaL_Reg R[] =
+ {
+   {"read",    openssl_pkcs12_read },
+-  {"export",    openssl_pkcs12_export  },
++  {"export",  openssl_pkcs12_export },
+ 
+   {NULL,    NULL}
+ };
+@@ -124,7 +151,7 @@ int luaopen_pkcs12(lua_State *L)
+   lua_newtable(L);
+   luaL_setfuncs(L, R, 0);
+ 
+-  lua_pushliteral(L, "version");    /** version */
++  lua_pushliteral(L, "version");
+   lua_pushliteral(L, MYVERSION);
+   lua_settable(L, -3);
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/pkcs7.c luvi-src-v2.7.6/deps/lua-openssl/src/pkcs7.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/pkcs7.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/pkcs7.c	2019-02-13 11:53:24.298459641 +0100
+@@ -1,10 +1,10 @@
+-/*=========================================================================*\
+-* pkcs7.c
+-* PKCS7 module for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++PKCS7 module for lua-openssl binding
+ 
++@module pkcs7
++@usage
++  pkcs7 = require('openssl').pkcs7
++*/
+ #include "openssl.h"
+ #include "private.h"
+ 
+@@ -12,6 +12,16 @@
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
++/***
++read string or bio object, which include pkcs7 content
++
++@function read
++@tparam bio|string input
++@tparam[opt='auto'] format allow 'auto','der','pem','smime'
++ auto will only try 'der' or 'pem'
++@treturn pkcs7 object or nil
++@treturn string content exist only smime format
++*/
+ static LUA_FUNCTION(openssl_pkcs7_read)
+ {
+   BIO* bio = load_bio_object(L, 1);
+@@ -27,12 +37,12 @@ static LUA_FUNCTION(openssl_pkcs7_read)
+   if (fmt == FORMAT_DER)
+   {
+     p7 = d2i_PKCS7_bio(bio, NULL);
+-    BIO_reset(bio);
++    (void)BIO_reset(bio);
+   }
+   else if (fmt == FORMAT_PEM)
+   {
+     p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
+-    BIO_reset(bio);
++    (void)BIO_reset(bio);
+   }
+   else if (fmt == FORMAT_SMIME)
+   {
+@@ -57,11 +67,18 @@ static LUA_FUNCTION(openssl_pkcs7_read)
+ }
+ 
+ #if OPENSSL_VERSION_NUMBER > 0x10000000L
++/***
++create new empty pkcs7 object, which support flexble sign methods.
+ 
++@function new
++@tparam[opt=NID_pkcs7_signed] int oid given pkcs7 type
++@tparam[opt=NID_pkcs7_data] int content given pkcs7 content type
++@treturn pkcs7 object
++*/
+ static LUA_FUNCTION(openssl_pkcs7_new)
+ {
+   int type = luaL_optint(L, 1, NID_pkcs7_signed);
+-  int content_nid = luaL_optint(L, 1, NID_pkcs7_data);
++  int content_nid = luaL_optint(L, 2, NID_pkcs7_data);
+ 
+   PKCS7 *p7 = PKCS7_new();
+   if (p7)
+@@ -81,23 +98,6 @@ static LUA_FUNCTION(openssl_pkcs7_new)
+   return 0;
+ }
+ 
+-static LUA_FUNCTION(openssl_pkcs7_sign_add_signer)
+-{
+-  PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+-  X509 *signcert = CHECK_OBJECT(2, X509, "openssl.x509");
+-  EVP_PKEY *pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
+-  const EVP_MD* md = get_digest(L, 4);
+-  long flags = luaL_optint(L, 5, 0);
+-  PKCS7_SIGNER_INFO *signer = 0;
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 3, "must be private key");
+-  luaL_argcheck(L, X509_check_private_key(signcert, pkey), 3,
+-                "sigcert and private key not match");
+-
+-  signer = PKCS7_sign_add_signer(p7, signcert, pkey, md, flags);
+-  (void) signer;
+-  return openssl_pushresult(L, signcert != NULL ? 1 : 0);
+-}
+-
+ static LUA_FUNCTION(openssl_pkcs7_add)
+ {
+   PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+@@ -107,10 +107,10 @@ static LUA_FUNCTION(openssl_pkcs7_add)
+   luaL_argcheck(L, lua_isuserdata(L, 2), 2, "must supply certificate or crl object");
+   for (i = 2; i <= n; i++)
+   {
+-    luaL_argcheck(L, auxiliar_isclass(L, "openssl.x509", i) || auxiliar_isclass(L, "openssl.x509_crl", i),
++    luaL_argcheck(L, auxiliar_getclassudata(L, "openssl.x509", i) || auxiliar_getclassudata(L, "openssl.x509_crl", i),
+                   i, "must supply certificate or crl object");
+ 
+-    if (auxiliar_isclass(L, "openssl.x509", i))
++    if (auxiliar_getclassudata(L, "openssl.x509", i))
+     {
+       X509* x = CHECK_OBJECT(i, X509, "openssl.x509");
+       ret = PKCS7_add_certificate(p7, x);
+@@ -179,12 +179,11 @@ static BIO *PKCS7_find_digest(EVP_MD_CTX
+       return bio;
+     bio = BIO_next(bio);
+   }
+-  return NULL;
+ }
+ 
+ static int PKCS7_SIGNER_INFO_sign_0(PKCS7_SIGNER_INFO *si)
+ {
+-  EVP_MD_CTX mctx;
++  EVP_MD_CTX *mctx;
+   EVP_PKEY_CTX *pctx;
+   unsigned char *abuf = NULL;
+   int alen;
+@@ -195,8 +194,9 @@ static int PKCS7_SIGNER_INFO_sign_0(PKCS
+   if (md == NULL)
+     return 0;
+ 
+-  EVP_MD_CTX_init(&mctx);
+-  if (EVP_DigestSignInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
++  mctx = EVP_MD_CTX_new();
++  EVP_MD_CTX_init(mctx);
++  if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0)
+     goto err;
+ 
+   if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
+@@ -210,17 +210,17 @@ static int PKCS7_SIGNER_INFO_sign_0(PKCS
+                        ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
+   if (!abuf)
+     goto err;
+-  if (EVP_DigestSignUpdate(&mctx, abuf, alen) <= 0)
++  if (EVP_DigestSignUpdate(mctx, abuf, alen) <= 0)
+     goto err;
+   OPENSSL_free(abuf);
+   abuf = NULL;
+-  if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
++  if (EVP_DigestSignFinal(mctx, NULL, &siglen) <= 0)
+     goto err;
+   abuf = OPENSSL_malloc(siglen);
+   if (!abuf)
+     goto err;
+ 
+-  if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
++  if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0)
+     goto err;
+   if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
+                         EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0)
+@@ -229,7 +229,7 @@ static int PKCS7_SIGNER_INFO_sign_0(PKCS
+     goto err;
+   }
+ 
+-  EVP_MD_CTX_cleanup(&mctx);
++  EVP_MD_CTX_free(mctx);
+ 
+   ASN1_STRING_set0(si->enc_digest, abuf, siglen);
+ 
+@@ -238,7 +238,7 @@ static int PKCS7_SIGNER_INFO_sign_0(PKCS
+ err:
+   if (abuf)
+     OPENSSL_free(abuf);
+-  EVP_MD_CTX_cleanup(&mctx);
++  EVP_MD_CTX_free(mctx);
+   return 0;
+ 
+ }
+@@ -307,34 +307,31 @@ static char *memdup(const char *src, siz
+   return buffer;
+ }
+ 
+-static LUA_FUNCTION(openssl_pkcs7_sign_digest)
+-{
+-  PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+-  size_t l;
+-  const char* data = luaL_checklstring(L, 2, &l);
+-  long flags = luaL_optint(L, 3, 0);
+-  int hash = lua_isnoneornil(L, 4) ? 0 : lua_toboolean(L, 4);
+ 
++static int openssl_pkcs7_dataFinal(PKCS7 *p7, BIO *bio)
++{
+   int ret = 0;
+   int i, j;
+-
+-  const EVP_MD* md;
++  BIO *btmp;
+   PKCS7_SIGNER_INFO *si;
+-  EVP_MD_CTX mdc;
++  EVP_MD_CTX *mdc, *ctx_tmp;
+   STACK_OF(X509_ATTRIBUTE) *sk;
+   STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
+   ASN1_OCTET_STRING *os = NULL;
+ 
+-  if (p7->d.ptr == NULL)
++  if (p7 == NULL)
+   {
+-    luaL_error(L, "pkcs7 without content");
++    PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER);
+     return 0;
+   }
+ 
+-  flags |= PKCS7_DETACHED;
+-  PKCS7_set_detached(p7, 1);
+-
+-  EVP_MD_CTX_init(&mdc);
++  if (p7->d.ptr == NULL)
++  {
++    PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT);
++    return 0;
++  }
++  ctx_tmp = EVP_MD_CTX_new();
++  EVP_MD_CTX_init(ctx_tmp);
+   i = OBJ_obj2nid(p7->type);
+   p7->state = PKCS7_S_HEADER;
+ 
+@@ -349,7 +346,11 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+     os = p7->d.signed_and_enveloped->enc_data->enc_data;
+     if (!os)
+     {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       os = M_ASN1_OCTET_STRING_new();
++#else
++      os = ASN1_OCTET_STRING_new();
++#endif
+       if (!os)
+       {
+         PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
+@@ -363,7 +364,11 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+     os = p7->d.enveloped->enc_data->enc_data;
+     if (!os)
+     {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       os = M_ASN1_OCTET_STRING_new();
++#else
++      os = ASN1_OCTET_STRING_new();
++#endif
+       if (!os)
+       {
+         PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
+@@ -378,7 +383,11 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+     /* If detached data then the content is excluded */
+     if (PKCS7_type_is_data(p7->d.sign->contents) && p7->detached)
+     {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       M_ASN1_OCTET_STRING_free(os);
++#else
++      ASN1_OCTET_STRING_free(os);
++#endif
+       os = NULL;
+       p7->d.sign->contents->d.data = NULL;
+     }
+@@ -389,7 +398,11 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+     /* If detached data then the content is excluded */
+     if (PKCS7_type_is_data(p7->d.digest->contents) && p7->detached)
+     {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       M_ASN1_OCTET_STRING_free(os);
++#else
++      ASN1_OCTET_STRING_free(os);
++#endif
+       os = NULL;
+       p7->d.digest->contents->d.data = NULL;
+     }
+@@ -407,24 +420,21 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+       si = sk_PKCS7_SIGNER_INFO_value(si_sk, i);
+       if (si->pkey == NULL)
+         continue;
++
+       j = OBJ_obj2nid(si->digest_alg->algorithm);
+-      md = EVP_get_digestbynid(j);
+-      EVP_DigestInit_ex(&mdc, md, NULL);
+ 
+-      if (hash)
+-      {
+-        if (l == (size_t) mdc.digest->ctx_size)
+-        {
+-          memcpy(mdc.md_data, data, l);
+-        }
+-        else
+-        {
+-          EVP_MD_CTX_cleanup(&mdc);
+-          luaL_argerror(L, 2, "data with wrong length");
+-        }
+-      }
+-      else
+-        EVP_DigestUpdate(&mdc, data, l);
++      btmp = bio;
++
++      btmp = PKCS7_find_digest(&mdc, btmp, j);
++
++      if (btmp == NULL)
++        goto err;
++
++      /*
++      * We now have the EVP_MD_CTX, lets do the signing.
++      */
++      if (!EVP_MD_CTX_copy_ex(ctx_tmp, mdc))
++        goto err;
+ 
+       sk = si->auth_attr;
+ 
+@@ -434,7 +444,7 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+       */
+       if (sk_X509_ATTRIBUTE_num(sk) > 0)
+       {
+-        if (!do_pkcs7_signed_attrib(si, &mdc))
++        if (!do_pkcs7_signed_attrib(si, ctx_tmp))
+           goto err;
+       }
+       else
+@@ -446,7 +456,7 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+         if (!abuf)
+           goto err;
+ 
+-        if (!EVP_SignFinal(&mdc, abuf, &abuflen, si->pkey))
++        if (!EVP_SignFinal(ctx_tmp, abuf, &abuflen, si->pkey))
+         {
+           PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_EVP_LIB);
+           goto err;
+@@ -459,20 +469,16 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+   {
+     unsigned char md_data[EVP_MAX_MD_SIZE];
+     unsigned int md_len;
+-    md = EVP_get_digestbynid(OBJ_obj2nid(p7->d.digest->md->algorithm));
+-    EVP_DigestInit_ex(&mdc, md, NULL);
+-    if (l == (size_t) mdc.digest->ctx_size)
+-    {
+-      memcpy(mdc.md_data, data, l);
+-    }
+-    else
+-    {
+-      EVP_MD_CTX_cleanup(&mdc);
+-      luaL_error(L, "data with wrong data");
+-    }
+-    if (!EVP_DigestFinal_ex(&mdc, md_data, &md_len))
++    if (!PKCS7_find_digest(&mdc, bio,
++                           OBJ_obj2nid(p7->d.digest->md->algorithm)))
+       goto err;
++    if (!EVP_DigestFinal_ex(mdc, md_data, &md_len))
++      goto err;
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+     M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
++#else
++    ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
++#endif
+   }
+ 
+   if (!PKCS7_is_detached(p7))
+@@ -485,16 +491,67 @@ static LUA_FUNCTION(openssl_pkcs7_sign_d
+       goto err;
+     if (!(os->flags & ASN1_STRING_FLAG_NDEF))
+     {
+-      char *cont = memdup(data, l);
+-      long contlen = l;
+-      ASN1_STRING_set0(os, (unsigned char *) cont, contlen);
++      char *cont;
++      long contlen;
++      btmp = BIO_find_type(bio, BIO_TYPE_MEM);
++      if (btmp == NULL)
++      {
++        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
++        goto err;
++      }
++      contlen = BIO_get_mem_data(btmp, &cont);
++      /*
++      * Mark the BIO read only then we can use its copy of the data
++      * instead of making an extra copy.
++      */
++      BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
++      BIO_set_mem_eof_return(btmp, 0);
++      ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
+     }
+   }
+-
+   ret = 1;
+ err:
+-  EVP_MD_CTX_cleanup(&mdc);
+-  return openssl_pushresult(L, ret);
++  EVP_MD_CTX_free(ctx_tmp);
++  return (ret);
++}
++
++
++static int openssl_pkcs7_final(lua_State *L)
++{
++  PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
++  BIO *data = load_bio_object(L, 2);
++  int flags = luaL_optint(L, 3, 0);
++
++  BIO *p7bio = PKCS7_dataInit(p7, NULL);
++  int ret = 0;
++
++  if (p7bio == NULL)
++  {
++    lua_pushnil(L);
++    lua_pushstring(L, "PKCS7_dataInit fail");
++    ret = 2;
++  }
++  else
++  {
++    SMIME_crlf_copy(data, p7bio, flags);
++
++    (void)BIO_flush(p7bio);
++
++    if (!openssl_pkcs7_dataFinal(p7, p7bio))
++    {
++      lua_pushnil(L);
++      lua_pushstring(L, "PKCS7_dataFinal fail");
++      ret = 2;
++    }
++    else
++    {
++      ret = 1;
++      lua_pushboolean(L, 1);
++    }
++    BIO_free_all(p7bio);
++  }
++
++  return ret;
+ }
+ 
+ int PKCS7_signatureVerify_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509,
+@@ -502,14 +559,16 @@ int PKCS7_signatureVerify_digest(PKCS7 *
+ {
+   ASN1_OCTET_STRING *os;
+   const EVP_MD* md;
+-  EVP_MD_CTX mdc, mdc_tmp;
++  EVP_MD_CTX *mdc, *mdc_tmp;
+   int ret = 0, i;
+   int md_type;
+   STACK_OF(X509_ATTRIBUTE) *sk;
+   EVP_PKEY *pkey = NULL;
+ 
+-  EVP_MD_CTX_init(&mdc);
+-  EVP_MD_CTX_init(&mdc_tmp);
++  mdc = EVP_MD_CTX_new();
++  mdc_tmp = EVP_MD_CTX_new();
++  EVP_MD_CTX_init(mdc);
++  EVP_MD_CTX_init(mdc_tmp);
+   if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7))
+   {
+     PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE);
+@@ -518,15 +577,27 @@ int PKCS7_signatureVerify_digest(PKCS7 *
+ 
+   md_type = OBJ_obj2nid(si->digest_alg->algorithm);
+   md = EVP_get_digestbynid(md_type);
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+   if (!md || !data || (hash && len != (size_t) md->ctx_size) )
+     goto err;
+ 
+-  if (!EVP_DigestInit_ex(&mdc, md, NULL))
++  if (!EVP_DigestInit_ex(mdc, md, NULL))
++    goto err;
++  if (hash)
++    memcpy(mdc->md_data, data, len);
++  else
++    EVP_DigestUpdate(mdc, data, len);
++#else
++  if (!md || !data || (hash && len != (size_t)EVP_MD_meth_get_app_datasize(md)) )
++    goto err;
++
++  if (!EVP_DigestInit_ex(mdc, md, NULL))
+     goto err;
+   if (hash)
+-    memcpy(mdc.md_data, data, len);
++    memcpy(EVP_MD_CTX_md_data(mdc), data, len);
+   else
+-    EVP_DigestUpdate(&mdc, data, len);
++    EVP_DigestUpdate(mdc, data, len);
++#endif
+ 
+   pkey = X509_get_pubkey(x509);
+   if (!pkey)
+@@ -538,7 +609,7 @@ int PKCS7_signatureVerify_digest(PKCS7 *
+   * mdc is the digest ctx that we want, unless there are attributes, in
+   * which case the digest is the signed attributes
+   */
+-  if (!EVP_MD_CTX_copy_ex(&mdc_tmp, &mdc))
++  if (!EVP_MD_CTX_copy_ex(mdc_tmp, mdc))
+     goto err;
+   sk = si->auth_attr;
+   if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0))
+@@ -548,7 +619,7 @@ int PKCS7_signatureVerify_digest(PKCS7 *
+     int alen;
+     ASN1_OCTET_STRING *message_digest;
+ 
+-    if (!EVP_DigestFinal_ex(&mdc_tmp, md_dat, &md_len))
++    if (!EVP_DigestFinal_ex(mdc_tmp, md_dat, &md_len))
+       goto err;
+     message_digest = PKCS7_digest_from_attributes(sk);
+     if (!message_digest)
+@@ -564,7 +635,7 @@ int PKCS7_signatureVerify_digest(PKCS7 *
+       ret = -1;
+       goto err;
+     }
+-    if (!EVP_DigestVerifyInit(&mdc_tmp, NULL, EVP_get_digestbynid(md_type), NULL, pkey))
++    if (!EVP_DigestVerifyInit(mdc_tmp, NULL, EVP_get_digestbynid(md_type), NULL, pkey))
+       goto err;
+ 
+     alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
+@@ -575,14 +646,14 @@ int PKCS7_signatureVerify_digest(PKCS7 *
+       ret = -1;
+       goto err;
+     }
+-    if (!EVP_VerifyUpdate(&mdc_tmp, abuf, alen))
++    if (!EVP_VerifyUpdate(mdc_tmp, abuf, alen))
+       goto err;
+ 
+     OPENSSL_free(abuf);
+   }
+ 
+   os = si->enc_digest;
+-  i = EVP_VerifyFinal(&mdc_tmp, os->data, os->length, pkey);
++  i = EVP_VerifyFinal(mdc_tmp, os->data, os->length, pkey);
+   if (i <= 0)
+   {
+     PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE);
+@@ -593,118 +664,25 @@ int PKCS7_signatureVerify_digest(PKCS7 *
+     ret = 1;
+ err:
+   EVP_PKEY_free(pkey);
+-  EVP_MD_CTX_cleanup(&mdc);
+-  EVP_MD_CTX_cleanup(&mdc_tmp);
++  EVP_MD_CTX_free(mdc);
++  EVP_MD_CTX_free(mdc_tmp);
+ 
+   return (ret);
+ }
+ 
+-static LUA_FUNCTION(openssl_pkcs7_verify_digest)
+-{
+-  PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+-  STACK_OF(X509) *certs = lua_isnoneornil(L, 2) ? NULL : openssl_sk_x509_fromtable(L, 2);
+-  X509_STORE *store = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, X509_STORE, "openssl.x509_store");
+-  size_t len;
+-  const char* data = luaL_checklstring(L, 4, &len);
+-  long flags = luaL_optint(L, 5, 0);
+-  int hash = lua_isnoneornil(L, 6) ? 0 : lua_toboolean(L, 6);
+-
+-  STACK_OF(X509) *signers;
+-  X509 *signer;
+-  STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
+-  PKCS7_SIGNER_INFO *si;
+-  X509_STORE_CTX cert_ctx;
+-
+-  int i, j = 0, k, ret = 0;
+-
+-  if (!PKCS7_type_is_signed(p7))
+-  {
+-    luaL_error(L, "pkcs7 must be signedData");
+-  }
+-
+-  /* Check for no data and no content: no data to verify signature */
+-  if (!PKCS7_get_detached(p7))
+-  {
+-    luaL_error(L, "pkcs7 must be detached signedData");
+-  }
+-
+-
+-  sinfos = PKCS7_get_signer_info(p7);
+-  if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos))
+-  {
+-    luaL_error(L, "pkcs7 signedData without signature");
+-  }
+-
+-  signers = PKCS7_get0_signers(p7, certs, flags);
+-  if (!signers)
+-  {
+-    luaL_error(L, "pkcs7 signedData without signers");
+-  }
+-
+-  if (!store)
+-    flags |= PKCS7_NOVERIFY;
+-
+-  /* Now verify the certificates */
+-  if (!(flags & PKCS7_NOVERIFY))
+-    for (k = 0; k < sk_X509_num(signers); k++)
+-    {
+-      signer = sk_X509_value(signers, k);
+-      if (!(flags & PKCS7_NOCHAIN))
+-      {
+-        if (!X509_STORE_CTX_init(&cert_ctx, store, signer,
+-                                 p7->d.sign->cert))
+-        {
+-          PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB);
+-          goto err;
+-        }
+-        X509_STORE_CTX_set_default(&cert_ctx, "smime_sign");
+-      }
+-      else if (!X509_STORE_CTX_init(&cert_ctx, store, signer, NULL))
+-      {
+-        PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB);
+-        goto err;
+-      }
+-      if (!(flags & PKCS7_NOCRL))
+-        X509_STORE_CTX_set0_crls(&cert_ctx, p7->d.sign->crl);
+-      i = X509_verify_cert(&cert_ctx);
+-      if (i <= 0)
+-        j = X509_STORE_CTX_get_error(&cert_ctx);
+-      X509_STORE_CTX_cleanup(&cert_ctx);
+-      if (i <= 0)
+-      {
+-        PKCS7err(PKCS7_F_PKCS7_VERIFY,
+-                 PKCS7_R_CERTIFICATE_VERIFY_ERROR);
+-        ERR_add_error_data(2, "Verify error:",
+-                           X509_verify_cert_error_string(j));
+-        goto err;
+-      }
+-      /* Check for revocation status here */
+-    }
+-
+-  /* Now Verify All Signatures */
+-  if (!(flags & PKCS7_NOSIGS))
+-    for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
+-    {
+-      si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
+-      signer = sk_X509_value(signers, i);
+-      j = PKCS7_signatureVerify_digest(p7, si, signer,
+-                                       (const unsigned char*) data, len, hash);
+-      if (j <= 0)
+-      {
+-        PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_SIGNATURE_FAILURE);
+-        goto err;
+-      }
+-    }
+-  ret = 1;
+-
+-err:
+-  if (certs)
+-    sk_X509_pop_free(certs, X509_free);
+-  sk_X509_free(signers);
+-  return openssl_pushresult(L, ret);
+-}
+ #endif
+ 
++/***
++sign message with signcert and signpkey to create pkcs7 object
++
++@function sign
++@tparam string|bio msg
++@tparam x509 signcert
++@tparam evp_pkey signkey
++@tparam[opt] stack_of_x509 cacerts
++@tparam[opt=0] number flags
++@treturn pkcs7 object
++*/
+ static LUA_FUNCTION(openssl_pkcs7_sign)
+ {
+   BIO *in  = load_bio_object(L, 1);
+@@ -713,7 +691,6 @@ static LUA_FUNCTION(openssl_pkcs7_sign)
+   STACK_OF(X509) *others = lua_isnoneornil(L, 4) ? 0 : openssl_sk_x509_fromtable(L, 4);
+   long flags =  luaL_optint(L, 5, 0);
+   PKCS7 *p7 = NULL;
+-  luaL_argcheck(L, openssl_pkey_is_private(privkey), 3, "must be private key");
+ 
+   if (!X509_check_private_key(cert, privkey))
+     luaL_error(L, "sigcert and private key not match");
+@@ -734,6 +711,18 @@ static LUA_FUNCTION(openssl_pkcs7_sign)
+   return 0;
+ }
+ 
++/***
++verify pkcs7 object, and return msg content, follow by singers
++
++@function verify
++@tparam pkcs7 in
++@tparam[opt] stack_of_x509 signercerts
++@tparam[opt] x509_store cacerts
++@tparam[opt] string|bio msg
++@tparam[opt=0] number flags
++@treturn[1] string content
++@treturn[1] boolean result
++*/
+ static LUA_FUNCTION(openssl_pkcs7_verify)
+ {
+   int ret = 0;
+@@ -741,10 +730,14 @@ static LUA_FUNCTION(openssl_pkcs7_verify
+   STACK_OF(X509) *signers = lua_isnoneornil(L, 2) ? NULL : openssl_sk_x509_fromtable(L, 2);
+   X509_STORE *store = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, X509_STORE, "openssl.x509_store");
+   BIO* in = lua_isnoneornil(L, 4) ? NULL : load_bio_object(L, 4);
+-  long flags = luaL_optint(L, 5, 0);
+-  BIO* out = BIO_new(BIO_s_mem());
++  long flags = luaL_optint(L, 5, PKCS7_DETACHED);
++  BIO* out = NULL;
++
+   if (!store)
+     flags |= PKCS7_NOVERIFY;
++  if ((flags&PKCS7_DETACHED) != 0)
++    out = BIO_new(BIO_s_mem());
++
+   if (PKCS7_verify(p7, signers, store, in, out, flags) == 1)
+   {
+     if (out && (flags & PKCS7_DETACHED) == 0)
+@@ -773,6 +766,15 @@ static LUA_FUNCTION(openssl_pkcs7_verify
+   return ret;
+ }
+ 
++/***
++encrypt message with recipcerts certificates return encrypted pkcs7 object
++
++@function encrypt
++@tparam string|bio msg
++@tparam stack_of_x509 recipcerts
++@tparam[opt='rc4'] string|evp_cipher cipher
++@tparam[opt] number flags
++*/
+ static LUA_FUNCTION(openssl_pkcs7_encrypt)
+ {
+   PKCS7 * p7 = NULL;
+@@ -801,6 +803,15 @@ static LUA_FUNCTION(openssl_pkcs7_encryp
+   return 1;
+ }
+ 
++/***
++decrypt encrypted pkcs7 message
++
++@function decrypt
++@tparam pkcs7 input
++@tparam x509 recipcert
++@tparam evp_pkey recipkey
++@treturn string decrypt message
++*/
+ static LUA_FUNCTION(openssl_pkcs7_decrypt)
+ {
+   PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+@@ -821,7 +832,11 @@ static LUA_FUNCTION(openssl_pkcs7_decryp
+   return 1;
+ }
+ 
+-/*** pkcs7 object method ***/
++/***
++openssl.pkcs7 object
++
++@type pkcs7
++*/
+ static LUA_FUNCTION(openssl_pkcs7_gc)
+ {
+   PKCS7* p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+@@ -829,17 +844,26 @@ static LUA_FUNCTION(openssl_pkcs7_gc)
+   return 0;
+ }
+ 
++/***
++export pkcs7 as string
++
++@function export
++@tparam[opt='pem'] string support export as 'pem' or 'der' format, default is 'pem'
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_pkcs7_export)
+ {
+-  int pem;
+   PKCS7 * p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+-  int top = lua_gettop(L);
+   BIO* bio_out = NULL;
+-
+-  pem = top > 1 ? lua_toboolean(L, 2) : 1;
++  int fmt = lua_type(L, 2);
++  luaL_argcheck(L, fmt == LUA_TSTRING || fmt == LUA_TNONE, 2,
++                "only accept 'pem','der' or none");
++  fmt = luaL_checkoption(L, 2, "pem", format);
++  luaL_argcheck(L, fmt == FORMAT_PEM || fmt == FORMAT_DER, 2,
++                "only accept pem or der, default is pem");
+ 
+   bio_out  = BIO_new(BIO_s_mem());
+-  if (pem)
++  if (fmt == FORMAT_PEM)
+   {
+ 
+     if (PEM_write_bio_PKCS7(bio_out, p7))
+@@ -901,19 +925,28 @@ static int openssl_push_pkcs7_signer_inf
+ 
+   if (info->pkey)
+   {
+-    CRYPTO_add(&info->pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
++    EVP_PKEY_up_ref(info->pkey);
+     AUXILIAR_SETOBJECT(L, info->pkey, "openssl.evp_pkey", -1, "pkey");
+   }
+   return 1;
+ }
+ 
+-static LUA_FUNCTION(openssl_pkcs7_signer_info_gc)
++static LUA_FUNCTION(openssl_pkcs7_type)
+ {
+-  PKCS7_SIGNER_INFO *info = CHECK_OBJECT(1, PKCS7_SIGNER_INFO, "openssl.pkcs7_signer_info");
+-  PKCS7_SIGNER_INFO_free(info);
+-  return 0;
++  PKCS7 * p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
++  int i = OBJ_obj2nid(p7->type);
++
++  lua_pushstring(L, OBJ_nid2sn(i));
++  lua_pushstring(L, OBJ_nid2ln(i));
++  return 2;
+ }
+ 
++/***
++export pkcs7 as a string
++
++@function parse
++@treturn table  a table has pkcs7 infomation, include type,and other things relate to types
++*/
+ static LUA_FUNCTION(openssl_pkcs7_parse)
+ {
+   PKCS7 * p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
+@@ -993,16 +1026,13 @@ static LUA_FUNCTION(openssl_pkcs7_parse)
+   case NID_pkcs7_digest:
+   {
+     PKCS7_DIGEST* d = p7->d.digest;
+-
+-    ASN1_OCTET_STRING *as = ASN1_STRING_dup(d->digest);
+-    PUSH_OBJECT(as, "openssl.asn1_string");
++    PUSH_ASN1_OCTET_STRING(L, d->digest);
+     lua_setfield(L, -2, "digest");
+   }
+   break;
+   case NID_pkcs7_data:
+   {
+-    ASN1_OCTET_STRING *as = ASN1_STRING_dup(p7->d.data);
+-    PUSH_OBJECT(as, "openssl.asn1_string");
++    PUSH_ASN1_OCTET_STRING(L, p7->d.data);
+     lua_setfield(L, -2, "data");
+   }
+   break;
+@@ -1026,13 +1056,417 @@ static LUA_FUNCTION(openssl_pkcs7_parse)
+   return 1;
+ }
+ 
++/***
++pkcs7 sign add signer
++
++@function add_signer
++@tparam x509 cert used to sign data
++@tparam evp_pkey pkey used to sign data
++@tparam evp_md|int digest method when sign data
++@tparam[opt=0] int flags switch process when add signer
++@treturn boolean result true for success
++*/
++static LUA_FUNCTION(openssl_pkcs7_sign_add_signer)
++{
++  PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
++  X509 *signcert = CHECK_OBJECT(2, X509, "openssl.x509");
++  EVP_PKEY *pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
++  const EVP_MD* md = get_digest(L, 4, NULL);
++  long flags = luaL_optint(L, 5, 0);
++  PKCS7_SIGNER_INFO *signer = 0;
++
++  luaL_argcheck(L, X509_check_private_key(signcert, pkey), 3,
++                "sigcert and private key not match");
++
++  signer = PKCS7_sign_add_signer(p7, signcert, pkey, md, flags);
++  (void) signer;
++  return openssl_pushresult(L, signcert != NULL ? 1 : 0);
++}
++
++#if OPENSSL_VERSION_NUMBER > 0x10000000L
++/***
++pkcs7 sign hash data
++@function sign_digest
++@tparam string data to sign data, maybe already hashed
++@tparam[opt=0] int flags when sign data
++@tparam[opt=false] boolean hashed when true will skip hash process
++@treturn boolean result true for success
++*/
++static LUA_FUNCTION(openssl_pkcs7_sign_digest)
++{
++  PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
++  size_t l;
++  const char* data = luaL_checklstring(L, 2, &l);
++  long flags = luaL_optint(L, 3, 0);
++  int hash = lua_isnoneornil(L, 4) ? 0 : lua_toboolean(L, 4);
++
++  int ret = 0;
++  int i, j;
++
++  const EVP_MD* md;
++  PKCS7_SIGNER_INFO *si;
++  EVP_MD_CTX *mdc;
++  STACK_OF(X509_ATTRIBUTE) *sk;
++  STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
++  ASN1_OCTET_STRING *os = NULL;
++
++  if (p7->d.ptr == NULL)
++  {
++    luaL_error(L, "pkcs7 without content");
++    return 0;
++  }
++
++  if (flags & PKCS7_DETACHED)
++  {
++    PKCS7_set_detached(p7, 1);
++  }
++
++  mdc = EVP_MD_CTX_new();
++  EVP_MD_CTX_init(mdc);
++  i = OBJ_obj2nid(p7->type);
++  p7->state = PKCS7_S_HEADER;
++
++  switch (i)
++  {
++  case NID_pkcs7_data:
++    os = p7->d.data;
++    break;
++  case NID_pkcs7_signedAndEnveloped:
++    /* XXXXXXXXXXXXXXXX */
++    si_sk = p7->d.signed_and_enveloped->signer_info;
++    os = p7->d.signed_and_enveloped->enc_data->enc_data;
++    if (!os)
++    {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++      os = M_ASN1_OCTET_STRING_new();
++#else
++      os = ASN1_OCTET_STRING_new();
++#endif
++      if (!os)
++      {
++        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
++        goto err;
++      }
++      p7->d.signed_and_enveloped->enc_data->enc_data = os;
++    }
++    break;
++  case NID_pkcs7_enveloped:
++    /* XXXXXXXXXXXXXXXX */
++    os = p7->d.enveloped->enc_data->enc_data;
++    if (!os)
++    {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++      os = M_ASN1_OCTET_STRING_new();
++#else
++      os = ASN1_OCTET_STRING_new();
++#endif
++      if (!os)
++      {
++        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
++        goto err;
++      }
++      p7->d.enveloped->enc_data->enc_data = os;
++    }
++    break;
++  case NID_pkcs7_signed:
++    si_sk = p7->d.sign->signer_info;
++    os = PKCS7_get_octet_string(p7->d.sign->contents);
++    /* If detached data then the content is excluded */
++    if (PKCS7_type_is_data(p7->d.sign->contents) && p7->detached)
++    {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++      M_ASN1_OCTET_STRING_free(os);
++#else
++      ASN1_OCTET_STRING_free(os);
++#endif
++      os = NULL;
++      p7->d.sign->contents->d.data = NULL;
++    }
++    break;
++
++  case NID_pkcs7_digest:
++    os = PKCS7_get_octet_string(p7->d.digest->contents);
++    /* If detached data then the content is excluded */
++    if (PKCS7_type_is_data(p7->d.digest->contents) && p7->detached)
++    {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++      M_ASN1_OCTET_STRING_free(os);
++#else
++      ASN1_OCTET_STRING_free(os);
++#endif
++      os = NULL;
++      p7->d.digest->contents->d.data = NULL;
++    }
++    break;
++
++  default:
++    PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
++    goto err;
++  }
++
++  if (si_sk != NULL)
++  {
++    for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(si_sk); i++)
++    {
++      si = sk_PKCS7_SIGNER_INFO_value(si_sk, i);
++      if (si->pkey == NULL)
++        continue;
++      j = OBJ_obj2nid(si->digest_alg->algorithm);
++      md = EVP_get_digestbynid(j);
++      EVP_DigestInit_ex(mdc, md, NULL);
++
++      if (hash)
++      {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++        if (l == (size_t) mdc->digest->ctx_size)
++        {
++          memcpy(mdc->md_data, data, l);
++        }
++#else
++        if (l == (size_t)EVP_MD_meth_get_app_datasize(EVP_MD_CTX_md(mdc)))
++        {
++          memcpy(EVP_MD_CTX_md_data(mdc), data, l);
++        }
++#endif
++        else
++        {
++          EVP_MD_CTX_free(mdc);
++          luaL_argerror(L, 2, "data with wrong length");
++        }
++      }
++      else
++        EVP_DigestUpdate(mdc, data, l);
++
++      sk = si->auth_attr;
++
++      /*
++      * If there are attributes, we add the digest attribute and only
++      * sign the attributes
++      */
++      if (sk_X509_ATTRIBUTE_num(sk) > 0)
++      {
++        if (!do_pkcs7_signed_attrib(si, mdc))
++          goto err;
++      }
++      else
++      {
++        unsigned char *abuf = NULL;
++        unsigned int abuflen;
++        abuflen = EVP_PKEY_size(si->pkey);
++        abuf = OPENSSL_malloc(abuflen);
++        if (!abuf)
++          goto err;
++
++        if (!EVP_SignFinal(mdc, abuf, &abuflen, si->pkey))
++        {
++          PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_EVP_LIB);
++          goto err;
++        }
++        ASN1_STRING_set0(si->enc_digest, abuf, abuflen);
++      }
++    }
++  }
++  else if (i == NID_pkcs7_digest)
++  {
++    unsigned char md_data[EVP_MAX_MD_SIZE];
++    unsigned int md_len;
++    md = EVP_get_digestbynid(OBJ_obj2nid(p7->d.digest->md->algorithm));
++    EVP_DigestInit_ex(mdc, md, NULL);
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++    if (l == (size_t) mdc->digest->ctx_size)
++    {
++      memcpy(mdc->md_data, data, l);
++    }
++#else
++    if (l == (size_t)EVP_MD_meth_get_app_datasize(EVP_MD_CTX_md(mdc)))
++    {
++      memcpy(EVP_MD_CTX_md_data(mdc), data, l);
++    }
++#endif
++    else
++    {
++      EVP_MD_CTX_free(mdc);
++      luaL_error(L, "data with wrong data");
++    }
++    if (!EVP_DigestFinal_ex(mdc, md_data, &md_len))
++      goto err;
++    ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
++  }
++
++  if (!PKCS7_is_detached(p7))
++  {
++    /*
++    * NOTE(emilia): I think we only reach os == NULL here because detached
++    * digested data support is broken.
++    */
++    if (os == NULL)
++      goto err;
++    if (!(os->flags & ASN1_STRING_FLAG_NDEF))
++    {
++      char *cont = memdup(data, l);
++      long contlen = l;
++      ASN1_STRING_set0(os, (unsigned char *) cont, contlen);
++    }
++  }
++
++  ret = 1;
++err:
++  EVP_MD_CTX_free(mdc);
++  return openssl_pushresult(L, ret);
++}
++
++/***
++pkcs7 verify signature or digest
++
++@function verify_digest
++@tparam[opt] table certs contains certificate used to sign data
++@tparam[opt] x509_store store to verify certs
++@tparam string data to be signed
++@tparam[opt=false] boolean hashed true for data already hashed
++@treturn boolean result true for success
++*/
++static LUA_FUNCTION(openssl_pkcs7_verify_digest)
++{
++  PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7");
++  STACK_OF(X509) *certs = lua_isnoneornil(L, 2) ? NULL : openssl_sk_x509_fromtable(L, 2);
++  X509_STORE *store = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, X509_STORE, "openssl.x509_store");
++  size_t len = 0;
++  const char* data = luaL_optlstring(L, 4, NULL, &len);
++  long flags = luaL_optint(L, 5, 0);
++  int hash = lua_isnoneornil(L, 6) ? 0 : lua_toboolean(L, 6);
++
++  STACK_OF(X509) *signers;
++  X509 *signer;
++  STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
++  PKCS7_SIGNER_INFO *si;
++  X509_STORE_CTX *cert_ctx;
++
++  int i, j = 0, k, ret = 0;
++
++  /* Check for no data and no content: no data to verify signature */
++  if (flags & PKCS7_DETACHED)
++  {
++    if (!PKCS7_get_detached(p7))
++    {
++      luaL_error(L, "pkcs7 must be detached signedData");
++    }
++    luaL_argcheck(L, data != NULL, 4, "need data to be verified");
++  }
++  else
++  {
++    ASN1_OCTET_STRING *os = NULL;
++
++    luaL_argcheck(L, data == NULL, 4, "must be nil or none");
++    os = PKCS7_get_octet_string(p7->d.sign->contents);
++    data = (const char*)os->data;
++    len = os->length;
++  }
++
++  sinfos = PKCS7_get_signer_info(p7);
++  if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos))
++  {
++    luaL_error(L, "pkcs7 signedData without signature");
++  }
++
++  signers = PKCS7_get0_signers(p7, certs, flags);
++  if (!signers)
++  {
++    luaL_error(L, "pkcs7 signedData without signers");
++  }
++
++  if (!store)
++    flags |= PKCS7_NOVERIFY;
++
++  /* Now verify the certificates */
++  if (!(flags & PKCS7_NOVERIFY))
++    for (k = 0; k < sk_X509_num(signers); k++)
++    {
++      signer = sk_X509_value(signers, k);
++      cert_ctx = X509_STORE_CTX_new();
++      if (!(flags & PKCS7_NOCHAIN))
++      {
++        if (!X509_STORE_CTX_init(cert_ctx, store, signer,
++                                 p7->d.sign->cert))
++        {
++          PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB);
++          goto err;
++        }
++        X509_STORE_CTX_set_default(cert_ctx, "smime_sign");
++      }
++      else if (!X509_STORE_CTX_init(cert_ctx, store, signer, NULL))
++      {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB);
++        goto err;
++      }
++      if (!(flags & PKCS7_NOCRL))
++        X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl);
++      i = X509_verify_cert(cert_ctx);
++      if (i <= 0)
++        j = X509_STORE_CTX_get_error(cert_ctx);
++      X509_STORE_CTX_free(cert_ctx);
++      if (i <= 0)
++      {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY,
++                 PKCS7_R_CERTIFICATE_VERIFY_ERROR);
++        ERR_add_error_data(2, "Verify error:",
++                           X509_verify_cert_error_string(j));
++        goto err;
++      }
++      /* Check for revocation status here */
++    }
++
++  /* Now Verify All Signatures */
++  if (!(flags & PKCS7_NOSIGS))
++    for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
++    {
++      si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
++      signer = sk_X509_value(signers, i);
++      j = PKCS7_signatureVerify_digest(p7, si, signer,
++                                       (const unsigned char*) data, len, hash);
++      if (j <= 0)
++      {
++        PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_SIGNATURE_FAILURE);
++        goto err;
++      }
++    }
++  ret = 1;
++
++err:
++  if (certs)
++    sk_X509_pop_free(certs, X509_free);
++  sk_X509_free(signers);
++  return openssl_pushresult(L, ret);
++}
++#endif
++/***
++verify pkcs7 object, and return msg content, follow by singers
++
++@function verify
++@tparam[opt] stack_of_x509 signercerts
++@tparam[opt] x509_store cacerts
++@tparam[opt] string|bio msg
++@tparam[opt=0] number flags
++@treturn string content
++@treturn stack_of_x509 signers
++*/
++
++/***
++decrypt encrypted pkcs7 message
++
++@function decrypt
++@tparam x509 recipcert
++@tparam evp_pkey recipkey
++@treturn string decrypt message
++*/
++
+ static luaL_Reg pkcs7_funcs[] =
+ {
++  {"type",          openssl_pkcs7_type},
+   {"parse",         openssl_pkcs7_parse},
+   {"export",        openssl_pkcs7_export},
+   {"decrypt",       openssl_pkcs7_decrypt},
+   {"verify",        openssl_pkcs7_verify},
+-
++  {"final",         openssl_pkcs7_final},
+ #if OPENSSL_VERSION_NUMBER > 0x10000000L
+   {"add_signer",    openssl_pkcs7_sign_add_signer},
+   {"add",           openssl_pkcs7_add},
+@@ -1060,7 +1494,7 @@ static const luaL_Reg R[] =
+   {NULL,  NULL}
+ };
+ 
+-static LuaL_Enum pkcs7_const[] =
++static LuaL_Enumeration pkcs7_const[] =
+ {
+   {"TEXT",         PKCS7_TEXT},
+   {"NOCERTS",      PKCS7_NOCERTS},
+@@ -1084,7 +1518,6 @@ static LuaL_Enum pkcs7_const[] =
+ 
+ int luaopen_pkcs7(lua_State *L)
+ {
+-  int i;
+   auxiliar_newclass(L, "openssl.pkcs7", pkcs7_funcs);
+ 
+   lua_newtable(L);
+@@ -1094,11 +1527,6 @@ int luaopen_pkcs7(lua_State *L)
+   lua_pushliteral(L, MYVERSION);
+   lua_settable(L, -3);
+ 
+-  for (i = 0; i < sizeof(pkcs7_const) / sizeof(LuaL_Enum) - 1; i++)
+-  {
+-    LuaL_Enum e = pkcs7_const[i];
+-    lua_pushinteger(L, e.val);
+-    lua_setfield(L, -2, e.name);
+-  }
++  auxiliar_enumerate(L, -1, pkcs7_const);
+   return 1;
+ }
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/pkey.c luvi-src-v2.7.6/deps/lua-openssl/src/pkey.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/pkey.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/pkey.c	2019-02-13 11:53:24.298459641 +0100
+@@ -1,10 +1,9 @@
+-/*=========================================================================*\
+-* pkey.c
+-* pkey module for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
+-
++/***
++pkey module for lua-openssl binding
++@module pkey
++@usage
++  pkey = require'openssl'.pkey
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #include <openssl/rsa.h>
+@@ -16,70 +15,71 @@
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
+-static int openssl_pkey_bits(lua_State *L)
+-{
+-  EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+-  lua_Integer ret = EVP_PKEY_bits(pkey);
+-  lua_pushinteger(L, ret);
+-  return  1;
+-};
+-
+ int openssl_pkey_is_private(EVP_PKEY* pkey)
+ {
++  int ret = 1;
++  int typ;
+   assert(pkey != NULL);
+-
+-  switch (pkey->type)
++  typ = EVP_PKEY_type(EVP_PKEY_id(pkey));
++  switch (typ)
+   {
+ #ifndef OPENSSL_NO_RSA
+   case EVP_PKEY_RSA:
+-  case EVP_PKEY_RSA2:
+-    assert(pkey->pkey.rsa != NULL);
+-    if (pkey->pkey.rsa != NULL && (NULL == pkey->pkey.rsa->p || NULL == pkey->pkey.rsa->q))
+-    {
+-      return 0;
+-    }
++  {
++    RSA *rsa = EVP_PKEY_get0_RSA(pkey);
++    const BIGNUM *d = NULL;
++
++    RSA_get0_key(rsa, NULL, NULL, &d);
++    ret = d != NULL;
+     break;
++  }
+ #endif
+ #ifndef OPENSSL_NO_DSA
+   case EVP_PKEY_DSA:
+-  case EVP_PKEY_DSA1:
+-  case EVP_PKEY_DSA2:
+-  case EVP_PKEY_DSA3:
+-  case EVP_PKEY_DSA4:
+-    assert(pkey->pkey.dsa != NULL);
+-
+-    if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key)
+-    {
+-      return 0;
+-    }
++  {
++    DSA *dsa = EVP_PKEY_get0_DSA(pkey);
++    const BIGNUM *p = NULL;
++    DSA_get0_key(dsa, NULL, &p);
++    ret = p != NULL;
+     break;
++  }
+ #endif
+ #ifndef OPENSSL_NO_DH
+   case EVP_PKEY_DH:
+-    assert(pkey->pkey.dh != NULL);
+-
+-    if (NULL == pkey->pkey.dh->p || NULL == pkey->pkey.dh->priv_key)
+-    {
+-      return 0;
+-    }
++  {
++    DH *dh = EVP_PKEY_get0_DH(pkey);
++    const BIGNUM *p = NULL;
++    DH_get0_key(dh, NULL, &p);
++    ret = p != NULL;
+     break;
++  }
+ #endif
+ #ifndef OPENSSL_NO_EC
+   case EVP_PKEY_EC:
+-    assert(pkey->pkey.ec != NULL);
+-    if (NULL == EC_KEY_get0_private_key(pkey->pkey.ec))
+-    {
+-      return 0;
+-    }
++  {
++    EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
++    const BIGNUM *p = EC_KEY_get0_private_key(ec);
++    ret = p != NULL;
+     break;
++  }
+ #endif
+   default:
+-    return -1;
++    ret = 0;
+     break;
+   }
+-  return 1;
++  return ret;
+ }
+ 
++/***
++read public/private key from data
++@function read
++@tparam string|openssl.bio input string data or bio object
++@tparam[opt=false] boolean priv prikey set true when input is private key
++@tparam[opt='auto'] string format or encoding of input, support 'auto','pem','der'
++@tparam[opt] string passhprase when input is private key, or key types 'ec','rsa','dsa','dh'
++@treturn evp_pkey public key
++@see evp_pkey
++*/
+ static int openssl_pkey_read(lua_State*L)
+ {
+   EVP_PKEY * key = NULL;
+@@ -96,6 +96,8 @@ static int openssl_pkey_read(lua_State*L
+       type = EVP_PKEY_DSA;
+     else if (strcmp(passphrase, "ec") == 0 || strcmp(passphrase, "EC") == 0)
+       type = EVP_PKEY_EC;
++    else if (strcmp(passphrase, "dh") == 0 || strcmp(passphrase, "DH") == 0)
++      type = EVP_PKEY_DH;
+   }
+ 
+   if (fmt == FORMAT_AUTO)
+@@ -107,9 +109,9 @@ static int openssl_pkey_read(lua_State*L
+   {
+     if (fmt == FORMAT_PEM)
+     {
+-      key = PEM_read_bio_PUBKEY(in, NULL, NULL, (void*)passphrase);
+-      BIO_reset(in);
+-      if (key == NULL && type == EVP_PKEY_RSA)
++      switch (type)
++      {
++      case EVP_PKEY_RSA:
+       {
+         RSA* rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
+         if (rsa)
+@@ -117,21 +119,109 @@ static int openssl_pkey_read(lua_State*L
+           key = EVP_PKEY_new();
+           EVP_PKEY_assign_RSA(key, rsa);
+         }
++        break;
+       }
++      case EVP_PKEY_DSA:
++      {
++        DSA* dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
++        if (dsa)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_DSA(key, dsa);
++        }
++        break;
++      }
++      case EVP_PKEY_DH:
++      {
++        DH *dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
++        if (dh)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_DH(key, dh);
++        }
++        break;
++      }
++      case EVP_PKEY_EC:
++      {
++        EC_KEY *ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL);
++        if (ec)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_EC_KEY(key, ec);
++        }
++        break;
++      }
++      default:
++      {
++        key = PEM_read_bio_PUBKEY(in, NULL, NULL, NULL);
++        break;
++      }
++      }
++      (void)BIO_reset(in);
+     }
+     else if (fmt == FORMAT_DER)
+     {
+-      key = d2i_PUBKEY_bio(in, NULL);
+-      BIO_reset(in);
+-      if (!key && type != -1)
++      switch (type)
++      {
++      case EVP_PKEY_RSA:
++      {
++        RSA *rsa = d2i_RSAPublicKey_bio(in, NULL);
++        if (rsa)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_RSA(key, rsa);
++        }
++        break;
++      }
++      case EVP_PKEY_DSA:
++      case EVP_PKEY_DH:
++      case EVP_PKEY_EC:
+       {
+         char * bio_mem_ptr;
+         long bio_mem_len;
+-
++        const unsigned char **pp;
+         bio_mem_len = BIO_get_mem_data(in, &bio_mem_ptr);
+-        key = d2i_PublicKey(type, NULL, (const unsigned char **)&bio_mem_ptr, bio_mem_len);
+-        BIO_reset(in);
++        pp = (const unsigned char **)&bio_mem_ptr;
++
++        key = d2i_PublicKey(type, NULL, pp, bio_mem_len);
++      }
++      /*
++      case EVP_PKEY_DSA:
++      {
++        DSA *dsa = d2i_DSA_PUBKEY_bio(in, NULL);
++        if (dsa)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_DSA(key, dsa);
++        }
++        break;
++      }
++      case EVP_PKEY_DH:
++      {
++        DH *dh = d2i_DHparams_bio(in, NULL);
++        if (dh)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_DH(key, dh);
++        }
++        break;
++      }
++      case EVP_PKEY_EC:
++      {
++        EC_KEY *ec = d2i_EC_PUBKEY_bio(in, NULL);
++        if (ec)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_EC_KEY(key, ec);
++        }
++        break;
+       }
++      */
++      default:
++        key = d2i_PUBKEY_bio(in, NULL);
++        break;
++      }
++      (void)BIO_reset(in);
+     }
+   }
+   else
+@@ -139,25 +229,61 @@ static int openssl_pkey_read(lua_State*L
+     if (fmt == FORMAT_PEM)
+     {
+       key = PEM_read_bio_PrivateKey(in, NULL, NULL, (void*)passphrase);
+-      BIO_reset(in);
++      (void)BIO_reset(in);
+     }
+     else if (fmt == FORMAT_DER)
+     {
+-      if (passphrase)
+-        key = d2i_PKCS8PrivateKey_bio(in, NULL, NULL, (void*)passphrase);
+-      else
+-        key = d2i_PrivateKey_bio(in, NULL);
+-      BIO_reset(in);
+-
+-      if (!key && type != -1)
++      switch (type)
+       {
+-        char * bio_mem_ptr;
+-        long bio_mem_len;
+-
+-        bio_mem_len = BIO_get_mem_data(in, &bio_mem_ptr);
+-        key = d2i_PrivateKey(type, NULL, (const unsigned char **)&bio_mem_ptr, bio_mem_len);
+-        BIO_reset(in);
++      case EVP_PKEY_RSA:
++      {
++        RSA *rsa = d2i_RSAPrivateKey_bio(in, NULL);
++        if (rsa)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_RSA(key, rsa);
++        }
++        break;
+       }
++      case EVP_PKEY_DSA:
++      {
++        DSA *dsa = d2i_DSAPrivateKey_bio(in, NULL);
++        if (dsa)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_DSA(key, dsa);
++        }
++        break;
++      }
++      case EVP_PKEY_DH:
++      {
++        DH *dh = d2i_DHparams_bio(in, NULL);
++        if (dh)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_DH(key, dh);
++        }
++      }
++      case EVP_PKEY_EC:
++      {
++        EC_KEY *ec = d2i_ECPrivateKey_bio(in, NULL);
++        if (ec)
++        {
++          key = EVP_PKEY_new();
++          EVP_PKEY_assign_EC_KEY(key, ec);
++        }
++        break;
++      }
++      default:
++      {
++        if (passphrase)
++          key = d2i_PKCS8PrivateKey_bio(in, NULL, NULL, (void*)passphrase);
++        else
++          key = d2i_PrivateKey_bio(in, NULL);
++        break;
++      }
++      }
++      (void)BIO_reset(in);
+     }
+   }
+   BIO_free(in);
+@@ -232,7 +358,7 @@ err:
+     size_t l = 0; const char* bn = luaL_checklstring(L, -1, &l);                      \
+     if (_name == NULL)  _name = BN_new();                                             \
+     BN_bin2bn((const unsigned char *)bn, l, _name);                                   \
+-  } else if (auxiliar_isclass(L, "openssl.bn", -1)) {                                 \
++  } else if (auxiliar_getclassudata(L, "openssl.bn", -1)) {                                 \
+     const BIGNUM* bn = CHECK_OBJECT(-1, BIGNUM, "openssl.bn");                        \
+     if (_name == NULL)  _name = BN_new();                                             \
+     BN_copy(_name, bn);                                                               \
+@@ -241,6 +367,40 @@ err:
+   lua_pop(L, 1);                                                                      \
+ }
+ 
++/***
++generate a new ec keypair
++@function new
++@tparam string alg, alg must be 'ec'
++@tparam string|number curvename this can be integer as curvename NID
++@tparam[opt] integer flags when alg is ec need this.
++@treturn evp_pkey object with mapping to EVP_PKEY in openssl
++*/
++/***
++generate a new keypair
++@function new
++@tparam[opt='rsa'] string alg, accept `rsa`,`dsa`,`dh`
++@tparam[opt=2048|512] integer bits, `rsa` with 2048, `dh` or `dsa` with 1024
++@tparam[opt] integer e, when alg is `rsa` give e value default is 0x10001,
++ when alg is `dh` give generator value default is 2,
++ when alg is `dsa` give string type seed value default is none.
++@tparam[opt] engine eng
++@treturn evp_pkey object with mapping to EVP_PKEY in openssl
++*/
++/***
++create a new keypair by factors of keypair or get public key only
++@function new
++@tparam table factors to create private/public key, key alg only accept accept 'rsa','dsa','dh','ec' and must exist</br>
++ when arg is rsa, table may with key n,e,d,p,q,dmp1,dmq1,iqmp, both are binary string or openssl.bn<br>
++ when arg is dsa, table may with key p,q,g,priv_key,pub_key, both are binary string or openssl.bn<br>
++ when arg is dh, table may with key p,g,priv_key,pub_key, both are binary string or openssl.bn<br>
++ when arg is ec, table may with D,X,Y,Z,both are binary string or openssl.bn<br>
++@treturn evp_pkey object with mapping to EVP_PKEY in openssl
++@usage
++ --create rsa public key
++   pubkey = new({alg='rsa',n=...,e=...}
++ --create new rsa
++   rsa = new({alg='rsa',n=...,q=...,e=...,...}
++*/
+ static LUA_FUNCTION(openssl_pkey_new)
+ {
+   EVP_PKEY *pkey = NULL;
+@@ -252,10 +412,11 @@ static LUA_FUNCTION(openssl_pkey_new)
+ 
+     if (strcasecmp(alg, "rsa") == 0)
+     {
+-      int bits = luaL_optint(L, 2, 1024);
++      int bits = luaL_optint(L, 2, 2048);
+       int e = luaL_optint(L, 3, 65537);
+-      RSA* rsa = RSA_new();
++      ENGINE *eng = lua_isnoneornil(L, 4) ? NULL : CHECK_OBJECT(4, ENGINE, "openssl.engine");
+ 
++      RSA *rsa = eng ? RSA_new_method(eng) : RSA_new();
+       BIGNUM *E = BN_new();
+       BN_set_word(E, e);
+       if (RSA_generate_key_ex(rsa, bits, E, NULL))
+@@ -272,8 +433,9 @@ static LUA_FUNCTION(openssl_pkey_new)
+       int bits = luaL_optint(L, 2, 1024);
+       size_t seed_len = 0;
+       const char* seed = luaL_optlstring(L, 3, NULL, &seed_len);
++      ENGINE *eng = lua_isnoneornil(L, 4) ? NULL : CHECK_OBJECT(4, ENGINE, "openssl.engine");
+ 
+-      DSA *dsa = DSA_new();
++      DSA *dsa = eng ? DSA_new_method(eng) : DSA_new();
+       if (DSA_generate_parameters_ex(dsa, bits, (byte*)seed, seed_len, NULL, NULL, NULL)
+           && DSA_generate_key(dsa))
+       {
+@@ -285,10 +447,11 @@ static LUA_FUNCTION(openssl_pkey_new)
+     }
+     else if (strcasecmp(alg, "dh") == 0)
+     {
+-      int bits = luaL_optint(L, 2, 512);
++      int bits = luaL_optint(L, 2, 1024);
+       int generator = luaL_optint(L, 3, 2);
++      ENGINE *eng = lua_isnoneornil(L, 4) ? NULL : CHECK_OBJECT(4, ENGINE, "openssl.engine");
+ 
+-      DH* dh = DH_new();
++      DH* dh = eng ? DH_new_method(eng) : DH_new();
+       if (DH_generate_parameters_ex(dh, bits, generator, NULL))
+       {
+         if (DH_generate_key(dh))
+@@ -324,7 +487,6 @@ static LUA_FUNCTION(openssl_pkey_new)
+       }
+       else
+         EC_GROUP_free(group);
+-
+     }
+ #endif
+     else
+@@ -345,22 +507,59 @@ static LUA_FUNCTION(openssl_pkey_new)
+         RSA *rsa = RSA_new();
+         if (rsa)
+         {
+-          OPENSSL_PKEY_SET_BN(1, rsa, n);
+-          OPENSSL_PKEY_SET_BN(1, rsa, e);
+-          OPENSSL_PKEY_SET_BN(1, rsa, d);
+-          OPENSSL_PKEY_SET_BN(1, rsa, p);
+-          OPENSSL_PKEY_SET_BN(1, rsa, q);
+-          OPENSSL_PKEY_SET_BN(1, rsa, dmp1);
+-          OPENSSL_PKEY_SET_BN(1, rsa, dmq1);
+-          OPENSSL_PKEY_SET_BN(1, rsa, iqmp);
+-          if (rsa->n)
++          BIGNUM *n = NULL, *e = NULL, *d = NULL;
++          BIGNUM *p = NULL, *q = NULL;
++          BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
++
++          lua_getfield(L, 1, "n");
++          n = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "e");
++          e = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "d");
++          d = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "p");
++          p = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "q");
++          q = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "dmp1");
++          dmp1 = BN_get(L, -1);
++          lua_pop(L, 1);
++          lua_getfield(L, 1, "dmq1");
++          dmq1 = BN_get(L, -1);
++          lua_pop(L, 1);
++          lua_getfield(L, 1, "iqmp");
++          iqmp = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          if (RSA_set0_key(rsa, n, e, d) == 1
++              && (p == NULL || RSA_set0_factors(rsa, p, q) == 1)
++              && (dmp1 == NULL || RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp) == 1) )
+           {
+             if (!EVP_PKEY_assign_RSA(pkey, rsa))
+             {
++              RSA_free(rsa);
++              rsa = NULL;
+               EVP_PKEY_free(pkey);
+               pkey = NULL;
+             }
+           }
++          else
++          {
++            RSA_free(rsa);
++            rsa = NULL;
++            EVP_PKEY_free(pkey);
++            pkey = NULL;
++          }
+         }
+       }
+     }
+@@ -372,23 +571,46 @@ static LUA_FUNCTION(openssl_pkey_new)
+         DSA *dsa = DSA_new();
+         if (dsa)
+         {
+-          OPENSSL_PKEY_SET_BN(-1, dsa, p);
+-          OPENSSL_PKEY_SET_BN(-1, dsa, q);
+-          OPENSSL_PKEY_SET_BN(-1, dsa, g);
+-          OPENSSL_PKEY_SET_BN(-1, dsa, priv_key);
+-          OPENSSL_PKEY_SET_BN(-1, dsa, pub_key);
+-          if (dsa->p && dsa->q && dsa->g)
++          BIGNUM *p = NULL, *q = NULL, *g = NULL;
++          BIGNUM *priv_key = NULL, *pub_key = NULL;
++
++          lua_getfield(L, 1, "p");
++          p = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "q");
++          q = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "g");
++          g = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "priv_key");
++          priv_key = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "pub_key");
++          pub_key = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          if (DSA_set0_key(dsa, pub_key, priv_key) == 1
++              && DSA_set0_pqg(dsa, p, q, g))
+           {
+-            if (!dsa->priv_key && !dsa->pub_key)
+-            {
+-              DSA_generate_key(dsa);
+-            }
+             if (!EVP_PKEY_assign_DSA(pkey, dsa))
+             {
++              DSA_free(dsa);
+               EVP_PKEY_free(pkey);
+               pkey = NULL;
+             }
+           }
++          else
++          {
++            DSA_free(dsa);
++            dsa = NULL;
++            EVP_PKEY_free(pkey);
++            pkey = NULL;
++          }
+         }
+       }
+     }
+@@ -401,22 +623,47 @@ static LUA_FUNCTION(openssl_pkey_new)
+         DH *dh = DH_new();
+         if (dh)
+         {
+-          OPENSSL_PKEY_SET_BN(-1, dh, p);
+-          OPENSSL_PKEY_SET_BN(-1, dh, g);
+-          OPENSSL_PKEY_SET_BN(-1, dh, priv_key);
+-          OPENSSL_PKEY_SET_BN(-1, dh, pub_key);
+-          if (dh->p && dh->g)
++          BIGNUM *p = NULL, *q = NULL, *g = NULL;
++          BIGNUM *priv_key = NULL, *pub_key = NULL;
++
++          lua_getfield(L, 1, "p");
++          p = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "q");
++          q = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "g");
++          g = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "priv_key");
++          priv_key = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          lua_getfield(L, 1, "pub_key");
++          pub_key = BN_get(L, -1);
++          lua_pop(L, 1);
++
++          if (DH_set0_key(dh, pub_key, priv_key) == 1
++              && DH_set0_pqg(dh, p, q, g))
+           {
+-            if (!dh->pub_key)
+-            {
+-              DH_generate_key(dh);
+-            }
+             if (!EVP_PKEY_assign_DH(pkey, dh))
+             {
++              DH_free(dh);
++              dh = NULL;
+               EVP_PKEY_free(pkey);
+               pkey = NULL;
+             }
+           }
++          else
++          {
++            DH_free(dh);
++            dh = NULL;
++            EVP_PKEY_free(pkey);
++            pkey = NULL;
++          }
+         }
+       }
+     }
+@@ -482,8 +729,14 @@ static LUA_FUNCTION(openssl_pkey_new)
+       EC_GROUP_free(group);
+     }
+   }
++  else if (auxiliar_getclassudata(L, "openssl.rsa", 1))
++  {
++    RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
++    pkey = EVP_PKEY_new();
++    EVP_PKEY_assign_RSA(pkey, rsa);
++  }
+ 
+-  if (pkey && pkey->pkey.ptr)
++  if (pkey && EVP_PKEY_id(pkey) != NID_undef)
+   {
+     PUSH_OBJECT(pkey, "openssl.evp_pkey");
+     return 1;
+@@ -491,15 +744,27 @@ static LUA_FUNCTION(openssl_pkey_new)
+   else
+     EVP_PKEY_free(pkey);
+   return 0;
+-
+ }
+ 
++/***
++openssl.evp_pkey object
++@type evp_pkey
++*/
++/***
++export evp_pkey as pem/der string
++@function export
++@tparam[opt='pem'] string support export as 'pem' or 'der' format, default is 'pem'
++@tparam[opt=false] boolean raw true for export low layer key just rsa,dsa,ec
++@tparam[opt] string passphrase if given, export key will encrypt with des-cbc-ede,
++only need when export private key
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_pkey_export)
+ {
+   EVP_PKEY * key;
+   int ispriv = 0;
+   int exraw = 0;
+-  int expem = 1;
++  int fmt = FORMAT_AUTO;
+   size_t passphrase_len = 0;
+   BIO * bio_out = NULL;
+   int ret = 0;
+@@ -509,19 +774,16 @@ static LUA_FUNCTION(openssl_pkey_export)
+   key = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+   ispriv = openssl_pkey_is_private(key);
+ 
+-  if (!lua_isnoneornil(L, 2))
+-    expem = lua_toboolean(L, 2);
+-
+-  if (expem)
+-  {
+-    if (!lua_isnoneornil(L, 3))
+-      exraw = lua_toboolean(L, 3);
+-    passphrase = luaL_optlstring(L, 4, NULL, &passphrase_len);
+-  }
+-  else
+-  {
+-    passphrase = luaL_optlstring(L, 3, NULL, &passphrase_len);
+-  }
++  fmt = lua_type(L, 2);
++  luaL_argcheck(L, fmt == LUA_TSTRING || fmt == LUA_TNONE, 2,
++                "only accept 'pem','der' or none");
++  fmt = luaL_checkoption(L, 2, "pem", format);
++  luaL_argcheck(L, fmt == FORMAT_PEM || fmt == FORMAT_DER, 2,
++                "only accept pem or der, default is pem");
++
++  if (!lua_isnoneornil(L, 3))
++    exraw = lua_toboolean(L, 3);
++  passphrase = luaL_optlstring(L, 4, NULL, &passphrase_len);
+ 
+   if (passphrase)
+   {
+@@ -533,7 +795,7 @@ static LUA_FUNCTION(openssl_pkey_export)
+   }
+ 
+   bio_out = BIO_new(BIO_s_mem());
+-  if (expem)
++  if (fmt == FORMAT_PEM)
+   {
+     if (exraw == 0)
+     {
+@@ -544,29 +806,25 @@ static LUA_FUNCTION(openssl_pkey_export)
+     else
+     {
+       /* export raw key format */
+-      switch (EVP_PKEY_type(key->type))
++      switch (EVP_PKEY_type(EVP_PKEY_id(key)))
+       {
+       case EVP_PKEY_RSA:
+-      case EVP_PKEY_RSA2:
+-        ret = ispriv ? PEM_write_bio_RSAPrivateKey(bio_out, key->pkey.rsa, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)
+-              : PEM_write_bio_RSAPublicKey(bio_out, key->pkey.rsa);
++        ret = ispriv ? PEM_write_bio_RSAPrivateKey(bio_out, EVP_PKEY_get0_RSA(key), cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)
++              : PEM_write_bio_RSAPublicKey(bio_out, EVP_PKEY_get0_RSA(key));
+         break;
+       case EVP_PKEY_DSA:
+-      case EVP_PKEY_DSA2:
+-      case EVP_PKEY_DSA3:
+-      case EVP_PKEY_DSA4:
+       {
+-        ret = ispriv ? PEM_write_bio_DSAPrivateKey(bio_out, key->pkey.dsa, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)
+-              : PEM_write_bio_DSA_PUBKEY(bio_out, key->pkey.dsa);
++        ret = ispriv ? PEM_write_bio_DSAPrivateKey(bio_out, EVP_PKEY_get0_DSA(key), cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)
++              : PEM_write_bio_DSA_PUBKEY(bio_out, EVP_PKEY_get0_DSA(key));
+       }
+       break;
+       case EVP_PKEY_DH:
+-        ret = PEM_write_bio_DHparams(bio_out, key->pkey.dh);
++        ret = PEM_write_bio_DHparams(bio_out, EVP_PKEY_get0_DH(key));
+         break;
+ #ifndef OPENSSL_NO_EC
+       case EVP_PKEY_EC:
+-        ret = ispriv ? PEM_write_bio_ECPrivateKey(bio_out, key->pkey.ec, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)
+-              : PEM_write_bio_EC_PUBKEY(bio_out, key->pkey.ec);
++        ret = ispriv ? PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get0_EC_KEY(key), cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)
++              : PEM_write_bio_EC_PUBKEY(bio_out, EVP_PKEY_get0_EC_KEY(key));
+         break;
+ #endif
+       default:
+@@ -577,41 +835,45 @@ static LUA_FUNCTION(openssl_pkey_export)
+   }
+   else
+   {
+-    if (ispriv)
++    /* out put der */
++    if (exraw == 0)
+     {
+-      if (passphrase == NULL)
+-      {
+-        ret = i2d_PrivateKey_bio(bio_out, key);
+-      }
+-      else
+-      {
+-        ret = i2d_PKCS8PrivateKey_bio(bio_out, key, cipher, (char *)passphrase, passphrase_len, NULL, NULL);
+-      }
++      ret = ispriv ?
++            (passphrase == NULL ? i2d_PrivateKey_bio(bio_out, key) :
++             i2d_PKCS8PrivateKey_bio(bio_out, key, cipher, (char *)passphrase, passphrase_len, NULL, NULL))
++            : i2d_PUBKEY_bio(bio_out, key);
+     }
+     else
+     {
+-      int l;
+-      l = i2d_PublicKey(key, NULL);
+-      if (l > 0)
+-      {
+-        unsigned char* p = malloc(l);
+-        unsigned char* pp = p;
+-        l = i2d_PublicKey(key, &pp);
+-        if (l > 0)
+-        {
+-          BIO_write(bio_out, p, l);
+-          ret = 1;
+-        }
+-        else
+-          ret = 0;
+-        free(p);
++      /* output raw key, rsa, ec, dh, dsa */
++      switch (EVP_PKEY_type(EVP_PKEY_id(key)))
++      {
++      case EVP_PKEY_RSA:
++        ret = ispriv ? i2d_RSAPrivateKey_bio(bio_out, EVP_PKEY_get0_RSA(key))
++              : i2d_RSAPublicKey_bio(bio_out, EVP_PKEY_get0_RSA(key));
++        break;
++      case EVP_PKEY_DSA:
++      {
++        ret = ispriv ? i2d_DSAPrivateKey_bio(bio_out, EVP_PKEY_get0_DSA(key))
++              : i2d_DSA_PUBKEY_bio(bio_out, EVP_PKEY_get0_DSA(key));
+       }
+-      else
++      break;
++      case EVP_PKEY_DH:
++        ret = i2d_DHparams_bio(bio_out, EVP_PKEY_get0_DH(key));
++        break;
++#ifndef OPENSSL_NO_EC
++      case EVP_PKEY_EC:
++        ret = ispriv ? i2d_ECPrivateKey_bio(bio_out, EVP_PKEY_get0_EC_KEY(key))
++              : i2d_EC_PUBKEY_bio(bio_out, EVP_PKEY_get0_EC_KEY(key));
++        break;
++#endif
++      default:
+         ret = 0;
++        break;
++      }
+     }
+   }
+ 
+-
+   if (ret)
+   {
+     char * bio_mem_ptr;
+@@ -637,20 +899,24 @@ static LUA_FUNCTION(openssl_pkey_free)
+   return 0;
+ }
+ 
++/***
++get key details as table
++@function parse
++@treturn table infos with key bits,pkey,type, pkey may be rsa,dh,dsa, show as table with factor hex encoded bignum
++*/
+ static LUA_FUNCTION(openssl_pkey_parse)
+ {
+   EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+-  if (pkey->pkey.ptr)
++  if (EVP_PKEY_id(pkey) != NID_undef)
+   {
+     lua_newtable(L);
+ 
+     AUXILIAR_SET(L, -1, "bits", EVP_PKEY_bits(pkey), integer);
+     AUXILIAR_SET(L, -1, "size", EVP_PKEY_size(pkey), integer);
+ 
+-    switch (EVP_PKEY_type(pkey->type))
++    switch (EVP_PKEY_type(EVP_PKEY_id(pkey)))
+     {
+     case EVP_PKEY_RSA:
+-    case EVP_PKEY_RSA2:
+     {
+       RSA* rsa = EVP_PKEY_get1_RSA(pkey);
+       PUSH_OBJECT(rsa, "openssl.rsa");
+@@ -661,9 +927,6 @@ static LUA_FUNCTION(openssl_pkey_parse)
+ 
+     break;
+     case EVP_PKEY_DSA:
+-    case EVP_PKEY_DSA2:
+-    case EVP_PKEY_DSA3:
+-    case EVP_PKEY_DSA4:
+     {
+       DSA* dsa = EVP_PKEY_get1_DSA(pkey);
+       PUSH_OBJECT(dsa, "openssl.dsa");
+@@ -703,104 +966,115 @@ static LUA_FUNCTION(openssl_pkey_parse)
+     luaL_argerror(L, 1, "not assign any keypair");
+   return 0;
+ };
+-/* }}} */
+ 
++/***
++encrypt message with public key
++encrypt length of message must not longer than key size, if shorter will do padding,currently supports 6 padding modes.
++They are: pkcs1, sslv23, no, oaep, x931, pss.
++@function encrypt
++@tparam string data data to be encrypted
++@tparam string[opt='pkcs1'] string padding padding mode
++@treturn string encrypted message
++*/
+ static LUA_FUNCTION(openssl_pkey_encrypt)
+ {
+   size_t dlen = 0;
+   EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+   const char *data = luaL_checklstring(L, 2, &dlen);
+   int padding = openssl_get_padding(L, 3, "pkcs1");
++  ENGINE *engine = lua_isnoneornil(L, 4) ? NULL : CHECK_OBJECT(4, ENGINE, "openssl.engine");
+   size_t clen = EVP_PKEY_size(pkey);
+   EVP_PKEY_CTX *ctx = NULL;
+   int ret = 0;
++  int typ = EVP_PKEY_type(EVP_PKEY_id(pkey));
+ 
+-  if (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_RSA2)
++  if (typ != EVP_PKEY_RSA && typ != EVP_PKEY_RSA2)
+   {
+     luaL_argerror(L, 2, "EVP_PKEY must be of type RSA or RSA2");
+     return ret;
+   }
+ 
+-  if (openssl_pkey_is_private(pkey) == 0)
++  ctx = EVP_PKEY_CTX_new(pkey, engine);
++  if (EVP_PKEY_encrypt_init(ctx) == 1)
+   {
+-    ctx = EVP_PKEY_CTX_new(pkey, pkey->engine);
+-    if (EVP_PKEY_encrypt_init(ctx) == 1)
++    if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 1)
+     {
+-      if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 1)
++      byte* buf = malloc(clen);
++      if (EVP_PKEY_encrypt(ctx, buf, &clen, (const unsigned char*)data, dlen) == 1)
+       {
+-        byte* buf = malloc(clen);
+-        if (EVP_PKEY_encrypt(ctx, buf, &clen, (const unsigned char*)data, dlen) == 1)
+-        {
+-          lua_pushlstring(L, (const char*)buf, clen);
+-          ret = 1;
+-        }
+-        else
+-          ret = openssl_pushresult(L, 0);
+-        free(buf);
++        lua_pushlstring(L, (const char*)buf, clen);
++        ret = 1;
+       }
+       else
+         ret = openssl_pushresult(L, 0);
++      free(buf);
+     }
+     else
+       ret = openssl_pushresult(L, 0);
+-    EVP_PKEY_CTX_free(ctx);
+   }
+   else
+-  {
+-    luaL_argerror(L, 2, "EVP_PKEY must be public key");
+-  }
++    ret = openssl_pushresult(L, 0);
++  EVP_PKEY_CTX_free(ctx);
+ 
+   return ret;
+ }
+ 
++/***
++decrypt message with private key
++pair with encrypt
++@function decrypt
++@tparam string data data to be decrypted
++@tparam string[opt='pkcs1'] string padding padding mode
++@treturn[1] string result
++@treturn[2] nil
++*/
+ static LUA_FUNCTION(openssl_pkey_decrypt)
+ {
+   size_t dlen = 0;
+   EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+   const char *data = luaL_checklstring(L, 2, &dlen);
+   int padding = openssl_get_padding(L, 3, "pkcs1");
++  ENGINE *engine = lua_isnoneornil(L, 4) ? NULL : CHECK_OBJECT(4, ENGINE, "openssl.engine");
+   size_t clen = EVP_PKEY_size(pkey);
+   EVP_PKEY_CTX *ctx = NULL;
+   int ret = 0;
++  int type = EVP_PKEY_type(EVP_PKEY_id(pkey));
+ 
+-  if (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_RSA2)
++  if (type != EVP_PKEY_RSA && type != EVP_PKEY_RSA2)
+   {
+     luaL_argerror(L, 2, "EVP_PKEY must be of type RSA or RSA2");
+     return ret;
+   }
+-
+-  if (openssl_pkey_is_private(pkey))
++  ctx = EVP_PKEY_CTX_new(pkey, engine);
++  if (EVP_PKEY_decrypt_init(ctx) == 1)
+   {
+-    ctx = EVP_PKEY_CTX_new(pkey, pkey->engine);
+-    if (EVP_PKEY_decrypt_init(ctx) == 1)
++    if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 1)
+     {
+-      if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 1)
+-      {
+-        byte* buf = malloc(clen);
++      byte* buf = malloc(clen);
+ 
+-        if (EVP_PKEY_decrypt(ctx, buf, &clen, (const unsigned char*)data, dlen) == 1)
+-        {
+-          lua_pushlstring(L, (const char*)buf, clen);
+-          ret = 1;
+-        }
+-        else
+-          ret = openssl_pushresult(L, 0);
+-        free(buf);
++      if (EVP_PKEY_decrypt(ctx, buf, &clen, (const unsigned char*)data, dlen) == 1)
++      {
++        lua_pushlstring(L, (const char*)buf, clen);
++        ret = 1;
+       }
+       else
+         ret = openssl_pushresult(L, 0);
++      free(buf);
+     }
+     else
+       ret = openssl_pushresult(L, 0);
+-    EVP_PKEY_CTX_free(ctx);
+   }
+   else
+-  {
+-    luaL_argerror(L, 2, "EVP_PKEY must be private key");
+-  }
++    ret = openssl_pushresult(L, 0);
++  EVP_PKEY_CTX_free(ctx);
+   return ret;
+ }
+ 
++/***
++return key is private or public
++@function is_private
++@treturn boolean ture is private or public key
++*/
+ LUA_FUNCTION(openssl_pkey_is_private1)
+ {
+   EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+@@ -813,35 +1087,37 @@ LUA_FUNCTION(openssl_pkey_is_private1)
+     luaL_error(L, "openssl.evp_pkey is not support");
+   return 1;
+ }
+-
++/* private usage, and for sm2 */
++/***
++return public key
++@function get_public
++@treturn evp_pkey pub
++*/
+ static LUA_FUNCTION(openssl_pkey_get_public)
+ {
+   EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+-  int private = openssl_pkey_is_private(pkey);
+   int ret = 0;
+-  if (private == 0)
+-    luaL_argerror(L, 1, "alreay public key");
+-  else
++  BIO* bio = BIO_new(BIO_s_mem());
++  if (i2d_PUBKEY_bio(bio, pkey))
+   {
+-    BIO* bio = BIO_new(BIO_s_mem());
+-    if (i2d_PUBKEY_bio(bio, pkey))
+-    {
+-      EVP_PKEY *pub = d2i_PUBKEY_bio(bio, NULL);
+-      PUSH_OBJECT(pub, "openssl.evp_pkey");
+-      ret = 1;
+-    }
+-    BIO_free(bio);
++    EVP_PKEY *pub = d2i_PUBKEY_bio(bio, NULL);
++    PUSH_OBJECT(pub, "openssl.evp_pkey");
++    ret = 1;
+   }
++  BIO_free(bio);
+   return ret;
+ }
+ 
++/* private useage, and for sm2 */
+ static LUA_FUNCTION(openssl_ec_userId)
+ {
+   EVP_PKEY* pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+   ENGINE* engine = CHECK_OBJECT(2, ENGINE, "openssl.engine");
++  EC_KEY *ec = NULL;
+ 
+   int ret = 0;
+-  if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_EC || !pkey->pkey.ec)
++  if (!pkey || EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC
++      || (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL )
+   {
+     luaL_argerror(L, 1, "only support EC key");
+   }
+@@ -851,7 +1127,7 @@ static LUA_FUNCTION(openssl_ec_userId)
+   if (lua_gettop(L) == 2)
+   {
+     ASN1_OCTET_STRING *s = ASN1_OCTET_STRING_new();
+-    ret = ENGINE_ctrl(engine, 0x474554, 0x4944, pkey->pkey.ec, (void(*)(void))s);
++    ret = ENGINE_ctrl(engine, 0x474554, 0x4944, ec, (void(*)(void))s);
+     if (ret == 1)
+       lua_pushlstring(L, (const char*) ASN1_STRING_data(s), ASN1_STRING_length(s));
+     else
+@@ -864,11 +1140,19 @@ static LUA_FUNCTION(openssl_ec_userId)
+     size_t l;
+     const char* data = luaL_checklstring(L, 3, &l);
+     ASN1_OCTET_STRING_set(s, (const unsigned char*) data, l);
+-    ret = ENGINE_ctrl(engine, 0x534554, 0x4944, pkey->pkey.ec, (void(*)(void))s);
++    ret = ENGINE_ctrl(engine, 0x534554, 0x4944, ec, (void(*)(void))s);
+     return openssl_pushresult(L, ret);
+   }
+ }
+ 
++/***
++compute dh key, check whether then supplied key is a private key
++by checking then prime factors whether set
++@function compute_key
++@tparam string remote_public_key
++@treturn string
++@todo: more check
++*/
+ static LUA_FUNCTION(openssl_dh_compute_key)
+ {
+   BIGNUM *pub;
+@@ -879,16 +1163,18 @@ static LUA_FUNCTION(openssl_dh_compute_k
+   EVP_PKEY* pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+   size_t pub_len;
+   const char* pub_str = luaL_checklstring(L, 2, &pub_len);
++  DH *dh = NULL;
+ 
+-  if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh)
++  if (!pkey || EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_DH
++      || (dh = EVP_PKEY_get0_DH(pkey)) == NULL)
+   {
+     luaL_argerror(L, 1, "only support DH private key");
+   }
+ 
+   pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL);
+ 
+-  data = malloc(DH_size(pkey->pkey.dh) + 1);
+-  len = DH_compute_key((unsigned char*)data, pub, pkey->pkey.dh);
++  data = malloc(DH_size(dh) + 1);
++  len = DH_compute_key((unsigned char*)data, pub, dh);
+ 
+   if (len >= 0)
+   {
+@@ -906,78 +1192,109 @@ static LUA_FUNCTION(openssl_dh_compute_k
+   return ret;
+ }
+ 
++/***
++sign message with private key
++@function sign
++@tparam string data data be signed
++@tparam[opt='SHA1'] string|env_digest md_alg default use sha-1
++@treturn string signed message
++*/
+ static LUA_FUNCTION(openssl_sign)
+ {
+   size_t data_len;
+   EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+   const char * data = luaL_checklstring(L, 2, &data_len);
+-  int top = lua_gettop(L);
++  int ret = 0;
++  EVP_MD_CTX *ctx = NULL;
+ 
+-  const EVP_MD *mdtype = NULL;
+-  if (top > 2)
+-  {
+-    mdtype = get_digest(L, 3);
+-  }
+-  else
+-    mdtype = EVP_get_digestbyname("sha1");
+-  if (mdtype)
++  const EVP_MD *md = get_digest(L, 3, "sha256");
++  ctx = EVP_MD_CTX_create();
++  ret = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey);
++  if (ret == 1)
+   {
+-    int ret = 0;
+-    EVP_MD_CTX md_ctx;
+-    unsigned int siglen = EVP_PKEY_size(pkey);
+-    unsigned char *sigbuf = malloc(siglen + 1);
+-
+-    EVP_SignInit(&md_ctx, mdtype);
+-    EVP_SignUpdate(&md_ctx, data, data_len);
+-    if (EVP_SignFinal (&md_ctx, sigbuf, &siglen, pkey))
++    ret = EVP_DigestSignUpdate(ctx, data, data_len);
++    if (ret == 1)
+     {
+-      lua_pushlstring(L, (char *)sigbuf, siglen);
+-      ret = 1;
++      size_t siglen = 0;
++      unsigned char *sigbuf = NULL;
++      ret = EVP_DigestSignFinal(ctx, NULL, &siglen);
++      if (ret == 1)
++      {
++        siglen += 2;
++        sigbuf = OPENSSL_malloc(siglen);
++        ret = EVP_DigestSignFinal(ctx, sigbuf, &siglen);
++        if (ret == 1)
++        {
++          lua_pushlstring(L, (char *)sigbuf, siglen);
++        }
++        else
++          ret = openssl_pushresult(L, ret);
++        OPENSSL_free(sigbuf);
++      }
++      else
++        ret = openssl_pushresult(L, ret);
+     }
+-    free(sigbuf);
+-    EVP_MD_CTX_cleanup(&md_ctx);
+-    return ret;
++    else
++      ret = openssl_pushresult(L, ret);
+   }
+   else
+-    luaL_argerror(L, 3, "Not support digest alg");
++    ret = openssl_pushresult(L, ret);
+ 
+-  return 0;
++  EVP_MD_CTX_destroy(ctx);
++  return ret;
+ }
+ 
++/***
++verify signed message with public key
++@function verify
++@tparam string data data be signed
++@tparam string signature signed result
++@tparam[opt='SHA1'] string|env_digest md_alg default use sha-1
++@treturn boolean true for pass verify
++*/
+ static LUA_FUNCTION(openssl_verify)
+ {
+   size_t data_len, signature_len;
+   EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+   const char* data = luaL_checklstring(L, 2, &data_len);
+   const char* signature = luaL_checklstring(L, 3, &signature_len);
++  const EVP_MD *md = get_digest(L, 4, "sha256");
++  EVP_MD_CTX *ctx = EVP_MD_CTX_create();
+ 
+-  const EVP_MD *mdtype = NULL;
+-  int top = lua_gettop(L);
+-  if (top > 3)
+-  {
+-    mdtype = get_digest(L, 4);
+-  }
+-  else
+-    mdtype = EVP_get_digestbyname("sha1");
+-  if (mdtype)
++  int ret = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
++  if (ret == 1)
+   {
+-    int result;
+-    EVP_MD_CTX     md_ctx;
+-
+-    EVP_VerifyInit   (&md_ctx, mdtype);
+-    EVP_VerifyUpdate (&md_ctx, data, data_len);
+-    result = EVP_VerifyFinal (&md_ctx, (unsigned char *)signature, signature_len, pkey);
+-    EVP_MD_CTX_cleanup(&md_ctx);
+-    lua_pushboolean(L, result == 1);
+-
+-    return 1;
++    ret = EVP_DigestVerifyUpdate(ctx, data, data_len);
++    if (ret == 1)
++    {
++      ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)signature, signature_len);
++      if (ret == 1)
++      {
++        lua_pushboolean(L, ret == 1);
++      }
++      else
++        ret = openssl_pushresult(L, ret);
++    }
++    else
++      ret = openssl_pushresult(L, ret);
+   }
+   else
+-    luaL_argerror(L, 4, "Not support digest alg");
++    ret = openssl_pushresult(L, ret);
+ 
+-  return 0;
++  EVP_MD_CTX_destroy(ctx);
++  return ret;
+ }
+ 
++/***
++seal and encrypt message with one public key
++data be encrypt with secret key, secret key be encrypt with public key
++@function seal
++@tparam string data data to be encrypted
++@tparam[opt='RC4'] cipher|string alg
++@treturn string data encrypted
++@treturn string skey secret key encrypted by public key
++@treturn string iv
++*/
+ static LUA_FUNCTION(openssl_seal)
+ {
+   size_t data_len;
+@@ -993,7 +1310,7 @@ static LUA_FUNCTION(openssl_seal)
+       luaL_argerror(L, 1, "empty array");
+     }
+   }
+-  else if (auxiliar_isclass(L, "openssl.evp_pkey", 1))
++  else if (auxiliar_getclassudata(L, "openssl.evp_pkey", 1))
+   {
+     nkeys = 1;
+   }
+@@ -1006,7 +1323,7 @@ static LUA_FUNCTION(openssl_seal)
+ 
+   if (cipher)
+   {
+-    EVP_CIPHER_CTX ctx;
++    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+     int ret = 0;
+     EVP_PKEY **pkeys;
+     unsigned char **eks;
+@@ -1046,20 +1363,20 @@ static LUA_FUNCTION(openssl_seal)
+       eksl[0] = EVP_PKEY_size(pkeys[0]);
+       eks[0] = malloc(eksl[0]);
+     }
+-    EVP_CIPHER_CTX_init(&ctx);
++    EVP_CIPHER_CTX_init(ctx);
+ 
+     /* allocate one byte extra to make room for \0 */
+     len1 = data_len + EVP_CIPHER_block_size(cipher) + 1;
+     buf = malloc(len1);
+ 
+ 
+-    if (!EVP_SealInit(&ctx, cipher, eks, eksl, (unsigned char*) iv, pkeys, nkeys)
+-        || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len))
++    if (!EVP_SealInit(ctx, cipher, eks, eksl, (unsigned char*) iv, pkeys, nkeys)
++        || !EVP_SealUpdate(ctx, buf, &len1, (unsigned char *)data, data_len))
+     {
+       luaL_error(L, "EVP_SealInit failed");
+     }
+ 
+-    EVP_SealFinal(&ctx, buf + len1, &len2);
++    EVP_SealFinal(ctx, buf + len1, &len2);
+ 
+     if (len1 + len2 > 0)
+     {
+@@ -1079,7 +1396,7 @@ static LUA_FUNCTION(openssl_seal)
+         lua_pushlstring(L, (const char*)eks[0], eksl[0]);
+         free(eks[0]);
+       }
+-      lua_pushlstring(L, iv, EVP_CIPHER_CTX_iv_length(&ctx));
++      lua_pushlstring(L, iv, EVP_CIPHER_CTX_iv_length(ctx));
+ 
+       ret = 3;
+     }
+@@ -1088,7 +1405,7 @@ static LUA_FUNCTION(openssl_seal)
+     free(eks);
+     free(eksl);
+     free(pkeys);
+-    EVP_CIPHER_CTX_cleanup(&ctx);
++    EVP_CIPHER_CTX_free(ctx);
+     return ret;
+   }
+   else
+@@ -1096,6 +1413,62 @@ static LUA_FUNCTION(openssl_seal)
+   return 0;
+ }
+ 
++/***
++open and ecrypted seal data with private key
++@function open
++@tparam string ekey encrypted secret key
++@tparam string string iv
++@tparam[opt='RC4'] evp_cipher|string md_alg
++@treturn string data decrypted message or nil on failure
++*/
++static LUA_FUNCTION(openssl_open)
++{
++  EVP_PKEY *pkey =  CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
++  size_t data_len, ekey_len, iv_len;
++  const char *data = luaL_checklstring(L, 2, &data_len);
++  const char *ekey = luaL_checklstring(L, 3, &ekey_len);
++  const char *iv = luaL_checklstring(L, 4, &iv_len);
++
++  int ret = 0;
++  int len1, len2 = 0;
++  unsigned char *buf;
++
++  const EVP_CIPHER *cipher = NULL;
++
++  cipher = get_cipher(L, 5, "rc4");
++
++  if (cipher)
++  {
++    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
++    len1 = data_len + 1;
++    buf = malloc(len1);
++
++    EVP_CIPHER_CTX_init(ctx);
++    if (EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, ekey_len, (const unsigned char *)iv, pkey)
++        && EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, data_len))
++    {
++      len2 = data_len - len1;
++      if (!EVP_OpenFinal(ctx, buf + len1, &len2) || (len1 + len2 == 0))
++      {
++        luaL_error(L, "EVP_OpenFinal() failed.");
++        ret = 0;
++      }
++    }
++    else
++    {
++      luaL_error(L, "EVP_OpenInit() failed.");
++      ret = 0;
++    }
++    EVP_CIPHER_CTX_free(ctx);
++    lua_pushlstring(L, (const char*)buf, len1 + len2);
++    free(buf);
++    ret = 1;
++  }
++  else
++    luaL_argerror(L, 5, "Not support cipher alg");
++
++  return ret;
++}
+ 
+ static LUA_FUNCTION(openssl_seal_init)
+ {
+@@ -1110,7 +1483,7 @@ static LUA_FUNCTION(openssl_seal_init)
+       luaL_argerror(L, 1, "empty array");
+     }
+   }
+-  else if (auxiliar_isclass(L, "openssl.evp_pkey", 1))
++  else if (auxiliar_getclassudata(L, "openssl.evp_pkey", 1))
+   {
+     nkeys = 1;
+   }
+@@ -1133,7 +1506,6 @@ static LUA_FUNCTION(openssl_seal_init)
+     eksl = malloc(nkeys * sizeof(*eksl));
+     eks = malloc(nkeys * sizeof(*eks));
+ 
+-
+     memset(eks, 0, sizeof(*eks) * nkeys);
+ 
+     /* get the public keys we are using to seal this data */
+@@ -1235,55 +1607,6 @@ static LUA_FUNCTION(openssl_seal_final)
+   return 1;
+ }
+ 
+-static LUA_FUNCTION(openssl_open)
+-{
+-  EVP_PKEY *pkey =  CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+-  size_t data_len, ekey_len, iv_len;
+-  const char *data = luaL_checklstring(L, 2, &data_len);
+-  const char *ekey = luaL_checklstring(L, 3, &ekey_len);
+-  const char *iv = luaL_checklstring(L, 4, &iv_len);
+-
+-  int ret = 0;
+-  int len1, len2 = 0;
+-  unsigned char *buf;
+-
+-  EVP_CIPHER_CTX ctx;
+-  const EVP_CIPHER *cipher = NULL;
+-
+-  cipher = get_cipher(L, 5, "rc4");
+-
+-  if (cipher)
+-  {
+-    len1 = data_len + 1;
+-    buf = malloc(len1);
+-
+-    EVP_CIPHER_CTX_init(&ctx);
+-    if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, (const unsigned char *)iv, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len))
+-    {
+-      len2 = data_len - len1;
+-      if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0))
+-      {
+-        luaL_error(L, "EVP_OpenFinal() failed.");
+-        ret = 0;
+-      }
+-    }
+-    else
+-    {
+-      luaL_error(L, "EVP_OpenInit() failed.");
+-      ret = 0;
+-    }
+-    EVP_CIPHER_CTX_cleanup(&ctx);
+-    lua_pushlstring(L, (const char*)buf, len1 + len2);
+-    free(buf);
+-    ret = 1;
+-  }
+-  else
+-    luaL_argerror(L, 5, "Not support cipher alg");
+-
+-  return ret;
+-}
+-
+-
+ static LUA_FUNCTION(openssl_open_init)
+ {
+   EVP_PKEY *pkey =  CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
+@@ -1349,6 +1672,14 @@ static LUA_FUNCTION(openssl_open_final)
+   return ret == 1 ? ret : openssl_pushresult(L, ret);
+ }
+ 
++static int openssl_pkey_bits(lua_State *L)
++{
++  EVP_PKEY *pkey = CHECK_OBJECT(1, EVP_PKEY, "openssl.evp_pkey");
++  lua_Integer ret = EVP_PKEY_bits(pkey);
++  lua_pushinteger(L, ret);
++  return  1;
++};
++
+ static luaL_Reg pkey_funcs[] =
+ {
+   {"is_private",    openssl_pkey_is_private1},
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/private.h luvi-src-v2.7.6/deps/lua-openssl/src/private.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/private.h	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/private.h	2019-02-13 11:53:24.298459641 +0100
+@@ -1,6 +1,16 @@
+-#include "openssl.h"
++#ifndef OPENSSL_PRIVATE_H
++#define OPENSSL_PRIVATE_H
++
++#if defined(__cplusplus)
++extern "C" {
++#endif
++#include <lua.h>
++#include <lauxlib.h>
++#include <lualib.h>
+ 
+-#include "lua-compat/c-api/compat-5.3.h"
++#if LUA_VERSION_NUM < 503
++#include "c-api/compat-5.3.h"
++#endif
+ 
+ #define luaL_checktable(L, n) luaL_checktype(L, n, LUA_TTABLE)
+ 
+@@ -29,6 +39,110 @@
+ #endif
+ #endif
+ 
++#include "openssl.h"
++
++#if OPENSSL_VERSION_NUMBER > 0x10100000L
++#define CONSTIFY_X509_get0 const
++#else
++#define CONSTIFY_X509_get0
++#endif
++
++#define PUSH_BN(x)                                      \
++  *(void **)(lua_newuserdata(L, sizeof(void *))) = (x); \
++  luaL_getmetatable(L,"openssl.bn");                    \
++  lua_setmetatable(L,-2)
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
++int BIO_up_ref(BIO *b);
++int X509_up_ref(X509 *x);
++int X509_STORE_up_ref(X509_STORE *s);
++int EVP_PKEY_up_ref(EVP_PKEY *pkey);
++
++DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey);
++int DH_bits(const DH *dh);
++void DH_get0_key(const DH *dh,
++                 const BIGNUM **pub_key, const BIGNUM **priv_key);
++int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
++void DH_get0_pqg(const DH *dh,
++                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
++int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
++void DSA_get0_pqg(const DSA *dsa,
++                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
++
++EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey);
++void ECDSA_SIG_get0(const ECDSA_SIG *sig,
++                    const BIGNUM **pr, const BIGNUM **ps);
++int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
++int RSA_bits(const RSA *r);
++void RSA_get0_key(const RSA *r,
++                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
++int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
++int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
++int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
++void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
++void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
++RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey);
++
++DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey);
++int DSA_bits(const DSA *dsa);
++void DSA_get0_key(const DSA *d,
++                  const BIGNUM **pub_key, const BIGNUM **priv_key);
++int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
++void DSA_get0_pqg(const DSA *d,
++                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
++int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
++
++HMAC_CTX *HMAC_CTX_new(void);
++void HMAC_CTX_free(HMAC_CTX *ctx);
++
++EVP_MD_CTX *EVP_MD_CTX_new(void);
++int EVP_MD_CTX_reset(EVP_MD_CTX *ctx);
++void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
++void X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig,
++                             const X509_ALGOR **palg);
++X509_PUBKEY *X509_REQ_get_X509_PUBKEY(X509_REQ *req);
++int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
++                           const unsigned char **pk, int *ppklen,
++                           X509_ALGOR **pa, X509_PUBKEY *pub);
++const ASN1_INTEGER *X509_get0_serialNumber(const X509 *a);
++const STACK_OF(X509_EXTENSION) *X509_get0_extensions(const X509 *x);
++int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp);
++const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(const X509_REVOKED *x);
++int X509_REVOKED_set_revocationDate(X509_REVOKED *x, ASN1_TIME *tm);
++const ASN1_TIME *X509_REVOKED_get0_revocationDate(const X509_REVOKED *x);
++const STACK_OF(X509_EXTENSION) *X509_REVOKED_get0_extensions(const X509_REVOKED *r);
++const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions(const X509_CRL *crl);
++
++void X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig,
++                             const X509_ALGOR **palg);
++
++const ASN1_INTEGER *TS_STATUS_INFO_get0_status(const TS_STATUS_INFO *a);
++const STACK_OF(ASN1_UTF8STRING) *TS_STATUS_INFO_get0_text(const TS_STATUS_INFO *a);
++const ASN1_BIT_STRING *TS_STATUS_INFO_get0_failure_info(const TS_STATUS_INFO *a);
++
++
++int TS_VERIFY_CTX_add_flags(TS_VERIFY_CTX *ctx, int f);
++int TS_VERIFY_CTX_set_flags(TS_VERIFY_CTX *ctx, int f);
++BIO *TS_VERIFY_CTX_set_data(TS_VERIFY_CTX *ctx, BIO *b);
++X509_STORE *TS_VERIFY_CTX_set_store(TS_VERIFY_CTX *ctx, X509_STORE *s);
++STACK_OF(X509) *TS_VERIFY_CTS_set_certs(TS_VERIFY_CTX *ctx,
++                                        STACK_OF(X509) *certs);
++unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx,
++    unsigned char *hexstr,
++    long len);
++
++#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
++int i2d_re_X509_tbs(X509 *x, unsigned char **pp);
++#endif
++#if OPENSSL_VERSION_NUMBER < 0x10002000L
++void X509_get0_signature(CONSTIFY_X509_get0 ASN1_BIT_STRING **psig,
++                         CONSTIFY_X509_get0 X509_ALGOR **palg,
++                         const X509 *x);
++int X509_get_signature_nid(const X509 *x);
++#endif
++
++#endif
++
+ #define AUXILIAR_SETOBJECT(L, cval, ltype, idx, lvar) \
+   do {                                                \
+   int n = (idx < 0)?idx-1:idx;                        \
+@@ -51,7 +165,7 @@
+   const char* bn = luaL_checklstring(L,-1,&l);              \
+   if(_type->_name==NULL)  _type->_name = BN_new();          \
+   BN_bin2bn((const unsigned char *)bn,l,_type->_name);      \
+-  }else if(auxiliar_isclass(L,"openssl.bn",-1)) {           \
++  }else if(auxiliar_getclassudata(L,"openssl.bn",-1)) {           \
+   const BIGNUM* bn = CHECK_OBJECT(-1,BIGNUM,"openssl.bn");  \
+   if(_type->_name==NULL)  _type->_name = BN_new();          \
+   BN_copy(_type->_name, bn);                                \
+@@ -77,7 +191,7 @@ extern const char* format[];
+ 
+ BIO* load_bio_object(lua_State* L, int idx);
+ int  bio_is_der(BIO* bio);
+-const EVP_MD* get_digest(lua_State* L, int idx);
++const EVP_MD* get_digest(lua_State* L, int idx, const char* def_alg);
+ const EVP_CIPHER* get_cipher(lua_State* L, int idx, const char* def_alg);
+ BIGNUM *BN_get(lua_State *L, int i);
+ int openssl_engine(lua_State *L);
+@@ -87,14 +201,13 @@ void to_hex(const char* in, int length,
+ 
+ int openssl_push_asn1type(lua_State* L, const ASN1_TYPE* type);
+ int openssl_push_asn1object(lua_State* L, const ASN1_OBJECT* obj);
+-int openssl_push_asn1(lua_State* L, ASN1_STRING* string, int type);
+-int openssl_push_x509_algor(lua_State*L, const X509_ALGOR* alg);
++int openssl_push_asn1(lua_State* L, const ASN1_STRING* string, int type);
+ int openssl_push_general_name(lua_State*L, const GENERAL_NAME* name);
+ 
+-#define PUSH_ASN1_TIME(L, tm)             openssl_push_asn1(L, (ASN1_STRING*)tm, V_ASN1_UTCTIME)
+-#define PUSH_ASN1_INTEGER(L, i)           openssl_push_asn1(L, (ASN1_STRING*)i,  V_ASN1_INTEGER)
+-#define PUSH_ASN1_OCTET_STRING(L, s)      openssl_push_asn1(L, (ASN1_STRING*)s,  V_ASN1_OCTET_STRING)
+-#define PUSH_ASN1_STRING(L, s)            openssl_push_asn1(L, (ASN1_STRING*)s, V_ASN1_UNDEF)
++#define PUSH_ASN1_TIME(L, tm)             openssl_push_asn1(L, (ASN1_STRING*)(tm), V_ASN1_UTCTIME)
++#define PUSH_ASN1_INTEGER(L, i)           openssl_push_asn1(L, (ASN1_STRING*)(i),  V_ASN1_INTEGER)
++#define PUSH_ASN1_OCTET_STRING(L, s)      openssl_push_asn1(L, (ASN1_STRING*)(s),  V_ASN1_OCTET_STRING)
++#define PUSH_ASN1_STRING(L, s)            openssl_push_asn1(L, (ASN1_STRING*)(s),  V_ASN1_UNDEF)
+ 
+ int openssl_push_xname_asobject(lua_State*L, X509_NAME* xname);
+ int openssl_push_bit_string_bitname(lua_State* L, const BIT_STRING_BITNAME* name);
+@@ -112,27 +225,42 @@ int openssl_register_xalgor(lua_State*L)
+ 
+ int openssl_pushresult(lua_State*L, int result);
+ 
+-int openssl_newvalue(lua_State*L, void*p);
+-int openssl_freevalue(lua_State*L, void*p);
+-int openssl_setvalue(lua_State*L, void*p, const char*field);
+-int openssl_getvalue(lua_State*L, void*p, const char*field);
+-int openssl_refrence(lua_State*L, void*p, int op);
++int openssl_newvalue(lua_State*L, const void*p);
++int openssl_freevalue(lua_State*L, const void*p);
++int openssl_valueset(lua_State*L, const void*p, const char*field);
++int openssl_valueget(lua_State*L, const void*p, const char*field);
++int openssl_valueseti(lua_State*L, const void*p, int i);
++int openssl_valuegeti(lua_State*L, const void*p, int i);
++size_t openssl_valuelen(lua_State*L, const void*p);
++int openssl_refrence(lua_State*L, const void*p, int op);
+ 
+ int openssl_verify_cb(int preverify_ok, X509_STORE_CTX *xctx);
+ int openssl_cert_verify_cb(X509_STORE_CTX *xctx, void* u);
+ void openssl_xstore_free(X509_STORE* ctx);
+ 
+ STACK_OF(X509)* openssl_sk_x509_fromtable(lua_State *L, int idx);
+-int openssl_sk_x509_totable(lua_State *L, STACK_OF(X509)* sk);
++int openssl_sk_x509_totable(lua_State *L, const STACK_OF(X509)* sk);
+ STACK_OF(X509_CRL)* openssl_sk_x509_crl_fromtable(lua_State *L, int idx);
+-int openssl_sk_x509_crl_totable(lua_State *L, STACK_OF(X509_CRL)* sk);
++int openssl_sk_x509_crl_totable(lua_State *L, const STACK_OF(X509_CRL)* sk);
+ STACK_OF(X509_EXTENSION)* openssl_sk_x509_extension_fromtable(lua_State *L, int idx);
+-int openssl_sk_x509_extension_totable(lua_State *L, STACK_OF(X509_EXTENSION)* sk);
+-int openssl_sk_x509_algor_totable(lua_State *L, STACK_OF(X509_ALGOR)* sk);
+-int openssl_sk_x509_name_totable(lua_State *L, STACK_OF(X509_NAME)* sk);
++int openssl_sk_x509_extension_totable(lua_State *L, const STACK_OF(X509_EXTENSION)* sk);
++int openssl_sk_x509_algor_totable(lua_State *L, const STACK_OF(X509_ALGOR)* sk);
++int openssl_sk_x509_name_totable(lua_State *L, const STACK_OF(X509_NAME)* sk);
+ 
+ X509_ATTRIBUTE* openssl_new_xattribute(lua_State*L, X509_ATTRIBUTE** a, int idx, const char* eprefix);
+ 
++#if !defined(OPENSSL_NO_SRP)
++#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER <= 0x10002000
++#define OPENSSL_NO_SRP
++#endif
++#endif
++
+ #ifdef HAVE_USER_CUSTOME
+ #include HAVE_USER_CUSTOME
+ #endif
++
++#if defined(__cplusplus)
++}
++#endif
++
++#endif /* OPENSSL_PRIVATE_H */
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/rsa.c luvi-src-v2.7.6/deps/lua-openssl/src/rsa.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/rsa.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/rsa.c	2019-02-13 11:53:24.321792707 +0100
+@@ -7,19 +7,12 @@
+ #include "openssl.h"
+ #include "private.h"
+ #include <openssl/rsa.h>
++#include <openssl/engine.h>
+ 
+ #define MYNAME    "rsa"
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
+-#define lua_boxpointer(L,u) \
+-  (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
+-
+-#define PUSH_BN(x)                  \
+-lua_boxpointer(L,x);                \
+-luaL_getmetatable(L,"openssl.bn");  \
+-lua_setmetatable(L,-2)
+-
+ static LUA_FUNCTION(openssl_rsa_free)
+ {
+   RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
+@@ -29,11 +22,9 @@ static LUA_FUNCTION(openssl_rsa_free)
+ 
+ static int is_private(const RSA* rsa)
+ {
+-  if (NULL == rsa->p || NULL == rsa->q)
+-  {
+-    return 0;
+-  }
+-  return 1;
++  const BIGNUM* d = NULL;
++  RSA_get0_key(rsa, NULL, NULL, &d);
++  return d != NULL && !BN_is_zero(d);
+ };
+ 
+ static LUA_FUNCTION(openssl_rsa_isprivate)
+@@ -43,21 +34,29 @@ static LUA_FUNCTION(openssl_rsa_isprivat
+   return 1;
+ };
+ 
++static LUA_FUNCTION(openssl_rsa_size)
++{
++  RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
++  lua_pushinteger(L, RSA_size(rsa));
++  return 1;
++};
++
+ static LUA_FUNCTION(openssl_rsa_encrypt)
+ {
+   RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
+   size_t l;
+   const unsigned char* from = (const unsigned char *)luaL_checklstring(L, 2, &l);
+   int padding = openssl_get_padding(L, 3, "pkcs1");
++  int ispriv = lua_isnone(L, 4) ? is_private(rsa) : lua_toboolean(L, 4);
+   unsigned char* to = OPENSSL_malloc(RSA_size(rsa));
+   int flen = l;
+ 
+-  flen = is_private(rsa)
++  flen = ispriv
+          ? RSA_private_encrypt(flen, from, to, rsa, padding)
+          : RSA_public_encrypt(flen, from, to, rsa, padding);
+   if (flen > 0)
+   {
+-    lua_pushlstring(L, to, flen);
++    lua_pushlstring(L, (const char*)to, flen);
+     OPENSSL_free(to);
+     return 1;
+   }
+@@ -71,15 +70,16 @@ static LUA_FUNCTION(openssl_rsa_decrypt)
+   size_t l;
+   const unsigned char* from = (const unsigned char *) luaL_checklstring(L, 2, &l);
+   int padding = openssl_get_padding(L, 3, "pkcs1");
++  int ispriv = lua_isnone(L, 4) ? is_private(rsa) : lua_toboolean(L, 4);
+   unsigned char* to = OPENSSL_malloc(RSA_size(rsa));
+   int flen = l;
+ 
+-  flen = is_private(rsa)
++  flen = ispriv
+          ? RSA_private_decrypt(flen, from, to, rsa, padding)
+          : RSA_public_decrypt(flen, from, to, rsa, padding);
+   if (flen > 0)
+   {
+-    lua_pushlstring(L, to, flen);
++    lua_pushlstring(L, (const char*)to, flen);
+     OPENSSL_free(to);
+     return 1;
+   }
+@@ -87,27 +87,111 @@ static LUA_FUNCTION(openssl_rsa_decrypt)
+   return openssl_pushresult(L, flen);
+ };
+ 
++static LUA_FUNCTION(openssl_rsa_sign)
++{
++  RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
++  size_t l;
++  const unsigned char* msg = (const unsigned char *)luaL_checklstring(L, 2, &l);
++  int type = luaL_optint(L, 3, NID_md5_sha1);
++  unsigned char* sig = OPENSSL_malloc(RSA_size(rsa));
++  int flen = l;
++  unsigned int slen = RSA_size(rsa);
++
++  int ret = RSA_sign(type, msg, flen, sig, &slen, rsa);
++  if (ret == 1)
++  {
++    lua_pushlstring(L, (const char*)sig, slen);
++    OPENSSL_free(sig);
++    return 1;
++  }
++  OPENSSL_free(sig);
++  return openssl_pushresult(L, ret);
++};
++
++static LUA_FUNCTION(openssl_rsa_verify)
++{
++  RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
++  size_t l;
++  const unsigned char* from = (const unsigned char *)luaL_checklstring(L, 2, &l);
++  size_t s;
++  const unsigned char* sig = (const unsigned char *)luaL_checklstring(L, 3, &s);
++  int type = luaL_optint(L, 4, NID_md5_sha1);
++  int flen = l;
++  int slen = s;
++
++  int ret = RSA_verify(type, from, flen, sig, slen, rsa);
++  return openssl_pushresult(L, ret);
++};
++
+ static LUA_FUNCTION(openssl_rsa_parse)
+ {
++  const BIGNUM *n = NULL, *e = NULL, *d = NULL;
++  const BIGNUM *p = NULL, *q = NULL;
++  const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
++
+   RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
++  RSA_get0_key(rsa, &n, &e, &d);
++  RSA_get0_factors(rsa, &p, &q);
++  RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
++
++
+   lua_newtable(L);
+-  OPENSSL_PKEY_GET_BN(rsa->n, n);
+-  OPENSSL_PKEY_GET_BN(rsa->e, e);
+-  OPENSSL_PKEY_GET_BN(rsa->d, d);
+-  OPENSSL_PKEY_GET_BN(rsa->p, p);
+-  OPENSSL_PKEY_GET_BN(rsa->q, q);
+-  OPENSSL_PKEY_GET_BN(rsa->dmp1, dmp1);
+-  OPENSSL_PKEY_GET_BN(rsa->dmq1, dmq1);
+-  OPENSSL_PKEY_GET_BN(rsa->iqmp, iqmp);
++  lua_pushinteger(L, RSA_size(rsa));
++  lua_setfield(L, -2, "size");
++  lua_pushinteger(L, RSA_bits(rsa));
++  lua_setfield(L, -2, "bits");
++  OPENSSL_PKEY_GET_BN(n, n);
++  OPENSSL_PKEY_GET_BN(e, e);
++  OPENSSL_PKEY_GET_BN(d, d);
++  OPENSSL_PKEY_GET_BN(p, p);
++  OPENSSL_PKEY_GET_BN(q, q);
++  OPENSSL_PKEY_GET_BN(dmp1, dmp1);
++  OPENSSL_PKEY_GET_BN(dmq1, dmq1);
++  OPENSSL_PKEY_GET_BN(iqmp, iqmp);
++  return 1;
++}
++
++static LUA_FUNCTION(openssl_rsa_read)
++{
++  size_t l;
++  const char* data = luaL_checklstring(L, 1, &l);
++  const unsigned char* in = (const unsigned char*)data;
++  RSA *rsa = d2i_RSAPrivateKey(NULL, &in, l);
++  if (rsa == NULL)
++  {
++    in = (const unsigned char*)data;
++    rsa = d2i_RSA_PUBKEY(NULL, &in, l);
++  }
++  if (rsa)
++    PUSH_OBJECT(rsa, "openssl.rsa");
++  else
++    lua_pushnil(L);
+   return 1;
+ }
+ 
++static int openssl_rsa_set_method(lua_State *L) 
++{
++  RSA* rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
++  ENGINE *e = CHECK_OBJECT(2, ENGINE, "openssl.engine");
++  const RSA_METHOD *m = ENGINE_get_RSA(e);
++  if (m) 
++  {
++    int r = RSA_set_method(rsa, m);
++    return openssl_pushresult(L, r);
++  }
++  return 0;
++}
++
+ static luaL_Reg rsa_funs[] =
+ {
+   {"parse",       openssl_rsa_parse},
+   {"isprivate",   openssl_rsa_isprivate},
+   {"encrypt",     openssl_rsa_encrypt},
+   {"decrypt",     openssl_rsa_decrypt},
++  {"sign",        openssl_rsa_sign},
++  {"verify",      openssl_rsa_verify},
++  {"size",        openssl_rsa_size},
++  {"set_method",  openssl_rsa_set_method},
+ 
+   {"__gc",        openssl_rsa_free},
+   {"__tostring",  auxiliar_tostring},
+@@ -121,6 +205,10 @@ static luaL_Reg R[] =
+   {"isprivate",   openssl_rsa_isprivate},
+   {"encrypt",     openssl_rsa_encrypt},
+   {"decrypt",     openssl_rsa_decrypt},
++  {"sign",        openssl_rsa_sign},
++  {"verify",      openssl_rsa_verify},
++  {"size",        openssl_rsa_size},
++  {"read",        openssl_rsa_read},
+ 
+   {NULL, NULL}
+ };
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/sk.h luvi-src-v2.7.6/deps/lua-openssl/src/sk.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/sk.h	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/sk.h	2019-02-13 11:53:24.321792707 +0100
+@@ -1,18 +1,28 @@
+-/*=========================================================================*\
+-* sk.h
+-* stack routines(MACRO) for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++Provide STACK_OF(object) maintance in lua.
++STACK\_OF(CTYPE) object just like STACK\_OF(X509) are high frequency used,
++in x509, pkcs7, pkcs12 and others module, and it has complex APIs in openssl.
++In lua-openssl, all of STACK\_OF(CTYPE) C side objects are mapping to array
++actually table in Lua side, and follow the rules of the Lua array, start
++index from 1, not 0 in C world.
++E.g C side STACK\_OF(X509) and Lua side array {cert1,cert2,...,certn} can
++be automatic convert in lua\-openssl if need.
+ 
++@module sk
++*/
+ #include "openssl.h"
+ 
+ #ifdef CRYPTO_LOCK_REF
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ #define REF_OR_DUP(TYPE, x)  CRYPTO_add(&x->references,1,CRYPTO_LOCK_##TYPE)
+ #else
++#define REF_OR_DUP(TYPE, x)  TYPE##_up_ref(x)
++#endif
++#else
+ #define REF_OR_DUP(TYPE, x) x = TYPE##_dup(x)
+ #endif
+ 
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ #define TAB2SK(TYPE, type)                                        \
+ STACK_OF(TYPE)* openssl_sk_##type##_fromtable(lua_State*L, int idx) {     \
+   STACK_OF(TYPE) * sk;                                            \
+@@ -35,7 +45,7 @@ STACK_OF(TYPE)* openssl_sk_##type##_from
+ }
+ 
+ 
+-#define SK2TAB(TYPE,type)  int openssl_sk_##type##_totable(lua_State* L, STACK_OF(TYPE) *sk)  {  \
++#define SK2TAB(TYPE,type)  int openssl_sk_##type##_totable(lua_State* L,const STACK_OF(TYPE) *sk)  {  \
+   int i=0, n=0;                                                                           \
+   lua_newtable(L);                                                                        \
+   n = SKM_sk_num(TYPE, sk);                                                               \
+@@ -47,6 +57,42 @@ STACK_OF(TYPE)* openssl_sk_##type##_from
+   }                                                                                       \
+   return 1;                                                                               \
+ }
++#else
++#define TAB2SK(TYPE, type)                                        \
++STACK_OF(TYPE)* openssl_sk_##type##_fromtable(lua_State*L, int idx) {     \
++  STACK_OF(TYPE) * sk;                                            \
++  luaL_argcheck(L, lua_istable(L, idx),  idx,                     \
++         "must be a table as array or nil");                      \
++  sk = sk_##TYPE##_new_null();                                    \
++  if (lua_istable(L,idx)) {                                       \
++    int n = lua_rawlen(L, idx);                                   \
++    int i;                                                        \
++    for ( i=0; i<n; i++ ) {                                       \
++      TYPE *x;                                                    \
++      lua_rawgeti(L, idx, i+1);                                   \
++      x = CHECK_OBJECT(-1,TYPE,"openssl." #type);                 \
++      REF_OR_DUP(TYPE, x);                                        \
++      sk_##TYPE##_push(sk, x);                                    \
++      lua_pop(L,1);                                               \
++    }                                                             \
++  }                                                               \
++  return sk;                                                      \
++}
++
++
++#define SK2TAB(TYPE,type)  int openssl_sk_##type##_totable(lua_State* L, const STACK_OF(TYPE) *sk)  {  \
++  int i=0, n=0;                                                                           \
++  lua_newtable(L);                                                                        \
++  n = sk_##TYPE##_num(sk);                                                                \
++  for(i=0;i<n;i++) {                                                                      \
++    TYPE *x =  sk_##TYPE##_value(sk, i);                                                  \
++    REF_OR_DUP(TYPE, x);                                                                  \
++    PUSH_OBJECT(x,"openssl."#type);                                                       \
++    lua_rawseti(L,-2, i+1);                                                               \
++  }                                                                                       \
++  return 1;                                                                               \
++}
++#endif
+ 
+ #define IMP_LUA_SK(TYPE,type)   \
+ TAB2SK(TYPE,type);              \
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/srp.c luvi-src-v2.7.6/deps/lua-openssl/src/srp.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/srp.c	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/srp.c	2019-02-13 11:53:24.321792707 +0100
+@@ -0,0 +1,202 @@
++#include "openssl.h"
++#include "private.h"
++
++#ifndef OPENSSL_NO_SRP
++#include <openssl/srp.h>
++#include <openssl/bn.h>
++
++#define MYNAME    "srp"
++#define MYVERSION MYNAME " library for " LUA_VERSION " / May 2018 / "\
++  "based on OpenSSL " SHLIB_VERSION_NUMBER
++
++/* server side */
++static int openssl_srp_create_verifier(lua_State *L)
++{
++  const SRP_gN *GN = CHECK_OBJECT(1, SRP_gN, "openssl.srp_gn");
++  const char *username = luaL_checkstring(L, 2);
++  const char *servpass = luaL_checkstring(L, 3);
++  BIGNUM *salt = NULL, *verifier = NULL;
++  int ret = SRP_create_verifier_BN(username, servpass, &salt, &verifier, GN->N, GN->g);
++  if (ret==1)
++  {
++    PUSH_OBJECT(salt, "openssl.bn");
++    PUSH_OBJECT(verifier, "openssl.bn");
++    return 2;
++  }
++  return openssl_pushresult(L, ret);
++}
++
++#ifndef BN_RAND_TOP_ANY
++#define BN_RAND_TOP_ANY -1
++#endif
++#ifndef BN_RAND_BOTTOM_ANY
++#define BN_RAND_BOTTOM_ANY 0
++#endif
++
++static int openssl_srp_calc_b(lua_State *L)
++{
++  int ret = 0;
++  const SRP_gN *GN = CHECK_OBJECT(1, SRP_gN, "openssl.srp_gn");
++  BIGNUM *v = CHECK_OBJECT(2, BIGNUM, "openssl.bn");
++  int bits = luaL_optint(L, 3, 32*8);
++
++  BIGNUM *Brnd = NULL, *Bpub = NULL;
++  Brnd = BN_new();
++
++  ret = BN_rand(Brnd, bits, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
++  if (ret==1)
++  {
++    /* Server's first message */
++    Bpub = SRP_Calc_B(Brnd, GN->N, GN->g, v);
++    ret = SRP_Verify_B_mod_N(Bpub, GN->N);
++    if(ret==1)
++    {
++      PUSH_OBJECT(Bpub, "openssl.bn");
++      PUSH_OBJECT(Brnd, "openssl.bn");
++      ret = 2;
++    }
++  }
++  if(ret!=2)
++  {
++    ret = openssl_pushresult(L, ret);
++    if(Brnd) BN_free(Brnd);
++    if(Bpub) BN_free(Bpub);
++  }
++  return ret;
++}
++
++static int openssl_srp_calc_server_key(lua_State *L)
++{
++  const SRP_gN *GN = CHECK_OBJECT(1, SRP_gN, "openssl.srp_gn");
++  BIGNUM *Apub = CHECK_OBJECT(2, BIGNUM, "openssl.bn");
++  BIGNUM *v = CHECK_OBJECT(3, BIGNUM, "openssl.bn");
++  BIGNUM *u = CHECK_OBJECT(4, BIGNUM, "openssl.bn");
++  BIGNUM *Brnd = CHECK_OBJECT(5, BIGNUM, "openssl.bn");
++
++  /* Server's key */
++  BIGNUM *Kserver = SRP_Calc_server_key(Apub, v, u, Brnd, GN->N);
++  PUSH_OBJECT(Kserver, "openssl.bn");
++  return 1;
++}
++
++/* client side */
++static int openssl_srp_calc_a(lua_State *L)
++{
++  int ret = 0;
++  const SRP_gN *GN = CHECK_OBJECT(1, SRP_gN, "openssl.srp_gn");
++  int bits = luaL_optint(L, 3, 32*8);
++
++  BIGNUM *Arnd = NULL, *Apub = NULL;
++  Arnd = BN_new();
++
++  ret = BN_rand(Arnd, bits, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
++  if (ret==1)
++  {
++    /* Client's response */
++    Apub = SRP_Calc_A(Arnd, GN->N, GN->g);
++    ret = SRP_Verify_A_mod_N(Apub, GN->N);
++    if(ret==1)
++    {
++      PUSH_OBJECT(Apub, "openssl.bn");
++      PUSH_OBJECT(Arnd, "openssl.bn");
++      ret = 2;
++    }
++  }
++  if(ret!=2)
++  {
++    ret = openssl_pushresult(L, ret);
++    if(Arnd) BN_free(Arnd);
++    if(Apub) BN_free(Apub);
++  }
++  return ret;
++}
++
++static int openssl_srp_calc_x(lua_State *L)
++{
++  BIGNUM *s = CHECK_OBJECT(1, BIGNUM, "openssl.bn");
++  const char *username = luaL_checkstring(L, 2);
++  const char *password = luaL_checkstring(L, 3);
++
++  BIGNUM *x = SRP_Calc_x(s, username, password);
++  PUSH_OBJECT(x, "openssl.bn");
++  return 1;
++}
++
++static int openssl_srp_calc_client_key(lua_State *L)
++{
++  const SRP_gN *GN = CHECK_OBJECT(1, SRP_gN, "openssl.srp_gn");
++  BIGNUM *Bpub = CHECK_OBJECT(2, BIGNUM, "openssl.bn");
++  BIGNUM *x = CHECK_OBJECT(3, BIGNUM, "openssl.bn");
++  BIGNUM *Arnd = CHECK_OBJECT(4, BIGNUM, "openssl.bn");
++  BIGNUM *u = CHECK_OBJECT(5, BIGNUM, "openssl.bn");
++
++  /* Client's key */
++  BIGNUM *Kclient = SRP_Calc_client_key(GN->N, Bpub, GN->g, x, Arnd, u);
++  PUSH_OBJECT(Kclient, "openssl.bn");
++  return 1;
++}
++
++/* both side */
++static int openssl_srp_get_default_gN(lua_State *L)
++{
++  const char *id = luaL_checkstring(L, 1);
++  SRP_gN *GN = SRP_get_default_gN(id);
++  if(GN)
++    PUSH_OBJECT(GN, "openssl.srp_gn");
++  else
++    lua_pushnil(L);
++  return 1;
++}
++
++static int openssl_srp_calc_u(lua_State *L)
++{
++  const SRP_gN *GN = CHECK_OBJECT(1, SRP_gN, "openssl.srp_gn");
++  BIGNUM *Apub = CHECK_OBJECT(2, BIGNUM, "openssl.bn");
++  BIGNUM *Bpub = CHECK_OBJECT(3, BIGNUM, "openssl.bn");
++
++  /* Both sides calculate u */
++  BIGNUM *u = SRP_Calc_u(Apub, Bpub, GN->N);
++  PUSH_OBJECT(u, "openssl.bn");
++  return 1;
++}
++
++static luaL_Reg srp_funs[] =
++{
++  /* both side */
++  {"calc_u",          openssl_srp_calc_u},
++
++  /* client side */
++  {"calc_a",          openssl_srp_calc_a},
++  {"calc_x",          openssl_srp_calc_x},
++  {"calc_client_key", openssl_srp_calc_client_key},
++
++  /* server side */
++  {"calc_b",          openssl_srp_calc_b},
++  {"create_verifier", openssl_srp_create_verifier},
++  {"calc_server_key", openssl_srp_calc_server_key},
++
++  /* prototype */
++  {"__tostring",      auxiliar_tostring},
++
++  {NULL,  NULL }
++};
++
++static luaL_Reg R[] =
++{
++  {"get_default_gN",  openssl_srp_get_default_gN},
++
++  {NULL,  NULL}
++};
++
++int luaopen_srp(lua_State *L)
++{
++  auxiliar_newclass(L, "openssl.srp_gn",       srp_funs);
++
++  lua_newtable(L);
++  luaL_setfuncs(L, R, 0);
++  lua_pushliteral(L, "version");
++  lua_pushliteral(L, MYVERSION);
++  lua_settable(L, -3);
++  return 1;
++}
++#endif
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/ssl.c luvi-src-v2.7.6/deps/lua-openssl/src/ssl.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/ssl.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/ssl.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,9 +1,10 @@
+-/*=========================================================================*\
+-* ssl.c
+-* SSL modules for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++ssl modules for lua-openssl binding, provide ssl function in lua.
++
++@module ssl
++@usage
++  ssl = require('openssl').ssl
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #include <stdint.h>
+@@ -15,6 +16,13 @@
+ 
+ #include <openssl/ssl.h>
+ 
++/***
++create ssl_ctx object, which mapping to SSL_CTX in openssl.
++@function ctx_new
++@tparam string protocol support 'SSLv3', 'SSLv23', 'SSLv2', 'TSLv1', 'TSLv1_1','TSLv1_2','DTLSv1', and can be follow by '_server' or '_client'
++@tparam[opt] string support_ciphers, if not given, default of openssl will be used
++@treturn ssl_ctx
++*/
+ static int openssl_ssl_ctx_new(lua_State*L)
+ {
+   const char* meth = luaL_optstring(L, 1, "TLSv1");
+@@ -24,12 +32,17 @@ static int openssl_ssl_ctx_new(lua_State
+   SSL_METHOD* method = NULL;
+   const char* ciphers;
+   SSL_CTX* ctx;
+-  if (strcmp(meth, "SSLv3") == 0)
++  if (0);
++
++#ifndef OPENSSL_NO_SSL3
++  else if (strcmp(meth, "SSLv3") == 0)
+     method = SSLv3_method();    /* SSLv3 */
+   else if (strcmp(meth, "SSLv3_server") == 0)
+     method = SSLv3_server_method(); /* SSLv3 */
+   else if (strcmp(meth, "SSLv3_client") == 0)
+     method = SSLv3_client_method(); /* SSLv3 */
++#endif
++
+   else if (strcmp(meth, "SSLv23") == 0)
+     method = SSLv23_method();   /* SSLv3 but can rollback to v2 */
+   else if (strcmp(meth, "SSLv23_server") == 0)
+@@ -73,22 +86,21 @@ static int openssl_ssl_ctx_new(lua_State
+   else if (strcmp(meth, "SSLv2_client") == 0)
+     method = SSLv2_client_method();
+ #endif
++#endif
+ #ifdef LOAD_SSL_CUSTOM
+   LOAD_SSL_CUSTOM
+ #endif
+-
+-#endif
+   else
+     luaL_error(L, "#1:%s not supported\n"
+-               "Maybe SSLv3 SSLv23 TLSv1 TLSv1_1 TLSv1_2 DTLSv1 [SSLv2], option followed by _client or _server\n",
+-               "default is SSLv3",
++               "Maybe [SSLv3] SSLv23 TLSv1 TLSv1_1 TLSv1_2 DTLSv1 [SSLv2], option followed by _client or _server\n"
++               "default is TLSv1",
+                meth);
+   ciphers = luaL_optstring(L, 2, SSL_DEFAULT_CIPHER_LIST);
+   ctx = SSL_CTX_new(method);
+   if (!ctx)
+     luaL_error(L, "#1:%s not supported\n"
+-               "Maybe SSLv3 SSLv23 TLSv1 TLSv1_1 TLSv1_2 DTLSv1 [SSLv2], option followed by _client or _server\n",
+-               "default is SSLv3",
++               "Maybe [SSLv3] SSLv23 TLSv1 TLSv1_1 TLSv1_2 DTLSv1 [SSLv2], option followed by _client or _server\n"
++               "default is TLSv1",
+                meth);
+   openssl_newvalue(L, ctx);
+   SSL_CTX_set_cipher_list(ctx, ciphers);
+@@ -98,6 +110,14 @@ static int openssl_ssl_ctx_new(lua_State
+   return 1;
+ }
+ 
++/***
++get alert_string for ssl state
++@function alert_string
++@tparam number alert
++@tparam[opt=false] boolean long
++@treturn string alert type
++@treturn string desc string, if long set true will return long info
++*/
+ static int openssl_ssl_alert_string(lua_State*L)
+ {
+   int v = luaL_checkint(L, 1);
+@@ -119,16 +139,66 @@ static int openssl_ssl_alert_string(lua_
+   return 2;
+ }
+ 
++static int openssl_ssl_session_new(lua_State*L)
++{
++  SSL_SESSION *ss = SSL_SESSION_new();
++  PUSH_OBJECT(ss, "openssl.ssl_session");
++  return 1;
++}
++
++static int openssl_ssl_session_read(lua_State*L)
++{
++  BIO *in = load_bio_object(L, 1);
++  SSL_SESSION* ss = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
++  if (!ss)
++  {
++    (void)BIO_reset(in);
++    ss = d2i_SSL_SESSION_bio(in, NULL);
++  }
++  BIO_free(in);
++  if (ss)
++  {
++    PUSH_OBJECT(ss, "openssl.ssl_session");
++    return 1;
++  }
++  return openssl_pushresult(L, 0);
++}
++
++static luaL_Reg R[] =
++{
++  {"ctx_new",       openssl_ssl_ctx_new },
++  {"alert_string",  openssl_ssl_alert_string },
++
++  {"session_new",   openssl_ssl_session_new},
++  {"session_read",  openssl_ssl_session_read},
++  {NULL,    NULL}
++};
++
+ /****************************SSL CTX********************************/
++/***
++openssl.ssl_ctx object
++@type ssl_ctx
++*/
++
++/***
++tell ssl_ctx use private key and certificate, and check private key
++@function use
++@tparam evp_pkey pkey
++@tparam x509 cert
++@treturn boolean result return true for ok, or nil followed by errmsg and errval
++*/
+ static int openssl_ssl_ctx_use(lua_State*L)
+ {
+   int ret;
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+   EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-  X509* cert = CHECK_OBJECT(3, X509, "openssl.x509");
+ 
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 2, "must be private key");
+-  ret = SSL_CTX_use_certificate(ctx, cert);
++  if(lua_isstring(L, 3)) {
++    ret = SSL_CTX_use_certificate_chain_file(ctx, luaL_checkstring(L, 3));
++  } else {
++    X509* cert = CHECK_OBJECT(3, X509, "openssl.x509");
++    ret = SSL_CTX_use_certificate(ctx, cert);
++  }
+   if (ret == 1)
+   {
+     ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+@@ -140,6 +210,13 @@ static int openssl_ssl_ctx_use(lua_State
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++add client ca cert and option extra chain cert
++@function add
++@tparam x509 clientca
++@tparam[opt] table extra_chain_cert_array
++@treturn boolean result
++*/
+ static int openssl_ssl_ctx_add(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -155,7 +232,7 @@ static int openssl_ssl_ctx_add(lua_State
+       lua_rawgeti(L, 3, i);
+       x = CHECK_OBJECT(2, X509, "openssl.x509");
+       lua_pop(L, 1);
+-      CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
++      X509_up_ref(x);
+       ret = SSL_CTX_add_extra_chain_cert(ctx, x);
+     }
+   }
+@@ -181,6 +258,17 @@ static int openssl_ssl_ctx_gc(lua_State*
+   return 0;
+ }
+ 
++/***
++get timeout
++@function timeout
++@return number
++*/
++/***
++set timeout
++@function timeout
++@tparam number timeout
++@treturn number previous timeout
++*/
+ static int openssl_ssl_ctx_timeout(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -220,6 +308,23 @@ static const char* sMode_options[] =
+   NULL
+ };
+ 
++/***
++clean given mode
++mode support 'enable_partial_write','accept_moving_write_buffer','auto_retry','no_auto_chain','release_buffers'
++@function mode
++@tparam boolean clear must be true
++@tparam string mode
++@param[opt] ...
++@treturn string
++@treturn ...
++@usage
++ modes = { ssl_ctx:mode('enable_partial_write','accept_moving_write_buffer','auto_retry') },
++
++  for  i, v in ipairs(modes)
++    print(v)
++ end
++ --output 'enable_partial_write','accept_moving_write_buffer','auto_retry'
++*/
+ static int openssl_ssl_ctx_mode(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -253,7 +358,30 @@ static int openssl_ssl_ctx_mode(lua_Stat
+   return ret;
+ };
+ 
++/***
++get options
++@function options
++@treturn table string list of current options
++*/
+ 
++/***
++set options
++@function options
++@tparam string option, support "microsoft_sess_id_bug", "netscape_challenge_bug", "netscape_reuse_cipher_change_bug",
++"sslref2_reuse_cert_type_bug", "microsoft_big_sslv3_buffer", "msie_sslv3_rsa_padding","ssleay_080_client_dh_bug",
++"tls_d5_bug","tls_block_padding_bug","dont_insert_empty_fragments","all", please to see ssl_options.h
++@treturn table string list of current options after set new option
++*/
++
++/***
++clear options
++@function options
++@tparam boolean clear set true to clear options
++@tparam string option, support "microsoft_sess_id_bug", "netscape_challenge_bug", "netscape_reuse_cipher_change_bug",
++"sslref2_reuse_cert_type_bug", "microsoft_big_sslv3_buffer", "msie_sslv3_rsa_padding","ssleay_080_client_dh_bug",
++"tls_d5_bug","tls_block_padding_bug","dont_insert_empty_fragments","all",  please to see ssl_options.h
++@treturn table string list of current options after clear some option
++*/
+ static int openssl_ssl_ctx_options(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -275,8 +403,8 @@ static int openssl_ssl_ctx_options(lua_S
+         int j;
+         for (j = 0; ssl_options[j].name; j++)
+         {
+-          LuaL_Enum e = ssl_options[j];
+-          if (strcasecmp(s, e.name))
++          LuaL_Enumeration e = ssl_options[j];
++          if (strcasecmp(s, e.name) == 0)
+           {
+             options |= e.val;
+             break;
+@@ -285,7 +413,6 @@ static int openssl_ssl_ctx_options(lua_S
+       }
+     }
+ 
+-
+     if (clear != 0)
+       options = SSL_CTX_clear_options(ctx, options);
+     else
+@@ -298,8 +425,8 @@ static int openssl_ssl_ctx_options(lua_S
+   ret = 0;
+   for (i = 0; ssl_options[i].name; i++)
+   {
+-    LuaL_Enum e = ssl_options[i];
+-    if (options && e.val)
++    LuaL_Enumeration e = ssl_options[i];
++    if (options & e.val)
+     {
+       lua_pushstring(L, e.name);
+       ret++;
+@@ -309,6 +436,25 @@ static int openssl_ssl_ctx_options(lua_S
+   return 1;
+ }
+ 
++/***
++get quit_shutdown is set or not
++Normally when a SSL connection is finished, the parties must send out
++"close notify" alert messages using ***SSL:shutdown"*** for a clean shutdown.
++@function quiet_shutdown
++@treturn boolean result
++*/
++/***
++set quiet_shutdown
++@function quiet_shutdown
++@tparam boolean quiet
++When setting the "quiet shutdown" flag to 1, ***SSL:shutdown*** will set the internal flags
++to SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN. ***SSL:shutdown*** then behaves like
++***SSL:set_shutdown*** called with SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN.
++The session is thus considered to be shutdown, but no "close notify" alert
++is sent to the peer. This behaviour violates the TLS standard.
++The default is normal shutdown behaviour as described by the TLS standard.
++@treturn boolean result
++*/
+ static int openssl_ssl_ctx_quiet_shutdown(lua_State*L)
+ {
+   SSL_CTX* s = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -326,6 +472,16 @@ static int openssl_ssl_ctx_quiet_shutdow
+   }
+ };
+ 
++/***
++set verify locations with cafile and capath
++ssl_ctx:verify_locations specifies the locations for *ctx*, at
++which CA certificates for verification purposes are located. The certificates
++available via *CAfile* and *CApath* are trusted.
++@function verify_locations
++@tparam string cafile
++@tparam string capath
++@treturn boolean result
++*/
+ static int openssl_ssl_ctx_load_verify_locations(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -335,22 +491,33 @@ static int openssl_ssl_ctx_load_verify_l
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get certificate verification store of ssl_ctx
++@function cert_store
++@treturn x509_store store
++*/
++/***
++set or replaces then certificate verification store of ssl_ctx
++@function cert_store
++@tparam x509_store store
++@treturn x509_store store
++*/
+ static int openssl_ssl_ctx_cert_store(lua_State*L)
+ {
++#if OPENSSL_VERSION_NUMBER >  0x10002000L
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+   X509_STORE *store = NULL;
+-#if OPENSSL_VERSION_NUMBER >  0x10002000L
+   if (lua_isnoneornil(L, 2))
+   {
+     store = SSL_CTX_get_cert_store(ctx);
+-    CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
++    X509_STORE_up_ref(store);
+     PUSH_OBJECT(store, "openssl.x509_store");
+     return 1;
+   }
+   else
+   {
+     store = CHECK_OBJECT(2, X509_STORE, "openssl.x509_store");
+-    CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
++    X509_STORE_up_ref(store);
+     SSL_CTX_set_cert_store(ctx, store);
+     X509_STORE_set_trust(store, 1);
+     return 0;
+@@ -361,6 +528,32 @@ static int openssl_ssl_ctx_cert_store(lu
+ #endif
+ }
+ 
++#ifndef OPENSSL_NO_ENGINE
++static int openssl_ssl_ctx_set_engine(lua_State*L)
++{
++  SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
++  ENGINE* eng = CHECK_OBJECT(2, ENGINE,  "openssl.engine");
++  int ret = SSL_CTX_set_client_cert_engine(ctx, eng);
++  return openssl_pushresult(L, ret);
++}
++#endif
++
++/****************************************************************************/
++/***
++create ssl object
++@function ssl
++@tparam bio bio
++@tparam[opt=false] boolean server, true will make ssl server
++@treturn ssl
++*/
++/***
++create ssl object
++@function ssl
++@tparam bio input
++@tparam bio ouput
++@tparam[opt=false] boolean server, true will make ssl server
++@treturn ssl
++*/
+ static int openssl_ssl_ctx_new_ssl(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -369,15 +562,15 @@ static int openssl_ssl_ctx_new_ssl(lua_S
+   SSL *ssl = SSL_new(ctx);
+   int ret = 1;
+ 
+-  if (auxiliar_isclass(L, "openssl.bio", 2))
++  if (auxiliar_getclassudata(L, "openssl.bio", 2))
+   {
+     BIO *bi = CHECK_OBJECT(2, BIO, "openssl.bio");
+     BIO *bo = bi;
+-    CRYPTO_add(&bi->references, 1, CRYPTO_LOCK_BIO);
+-    if (auxiliar_isclass(L, "openssl.bio", 3))
++    BIO_up_ref(bi);
++    if (auxiliar_getclassudata(L, "openssl.bio", 3))
+     {
+       bo = CHECK_OBJECT(3, BIO, "openssl.bio");
+-      CRYPTO_add(&bo->references, 1, CRYPTO_LOCK_BIO);
++      BIO_up_ref(bo);
+       mode_idx = 4;
+     }
+     else
+@@ -415,6 +608,14 @@ static int openssl_ssl_ctx_new_ssl(lua_S
+   return 1;
+ }
+ 
++/***
++create bio object
++@function bio
++@tparam string host_addr format like 'host:port'
++@tparam[opt=false] boolean server, true listen at host_addr,false connect to host_addr
++@tparam[opt=true] boolean autoretry ssl operation autoretry mode
++@treturn bio bio object
++*/
+ static int openssl_ssl_ctx_new_bio(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -445,7 +646,7 @@ static int openssl_ssl_ctx_new_bio(lua_S
+       openssl_newvalue(L, bio);
+ 
+       lua_pushboolean(L, 1);
+-      openssl_setvalue(L, bio, "free_all");
++      openssl_valueset(L, bio, "free_all");
+ 
+       return 1;
+     }
+@@ -460,17 +661,17 @@ static int openssl_ssl_ctx_new_bio(lua_S
+   }
+ }
+ 
+-static int openssl_ssl_getpeerverification(lua_State *L)
+-{
+-  long err;
+-  SSL* ssl = CHECK_OBJECT(1, SSL, "openssl.ssl");
+-
+-  err = SSL_get_verify_result(ssl);
+-  lua_pushboolean(L, err == X509_V_OK);
+-  openssl_getvalue(L, ssl, "verify_cert");
+-  return 2;
+-}
+-
++/***
++get verify depth when cert chain veirition
++@function verify_depth
++@treturn number depth
++*/
++/***
++set verify depth when cert chain veirition
++@function verify_depth
++@tparam number depth
++@treturn number depth
++*/
+ static int openssl_ssl_ctx_verify_depth(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -503,6 +704,31 @@ static const char* sVerifyMode_Options[]
+   NULL
+ };
+ 
++/***
++get verify_mode, return number mode and all string modes list
++@function verify_mode
++@treturn number mode_code
++@return ...
++  none: not verify client cert
++  peer: verify client cert
++  fail: if client not have cert, will failure
++  once: verify client only once.
++@usage
++  mode = {ctx:verify_mode()}
++  print('integer mode',mode[1])
++  for i=2, #mode then
++    print('string mode:'..mode[i])
++  end
++*/
++/***
++set ssl verify mode and callback
++@function verify_mode
++@tparam number mode, mode set to ctx, must be ssl.none or ssl.peer, and ssl.peer support combine with ssl.fail or ssl.once
++@tparam[opt=nil] function ssl verify callback in lua function, not give will use default openssl callback, when mode is 'none', will be ignore this
++verify_cb must be boolean function(verifyarg) prototype, return true to continue or false to end ssl handshake
++verifyarg has field 'error', 'error_string','error_depth','current_cert', and 'preverify_ok'
++@treturn boolean result
++*/
+ static int openssl_ssl_ctx_verify_mode(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -522,13 +748,13 @@ static int openssl_ssl_ctx_verify_mode(l
+     if (lua_isfunction(L, 3))
+     {
+       lua_pushvalue(L, 3);
+-      openssl_setvalue(L, ctx, "verify_cb");
++      openssl_valueset(L, ctx, "verify_cb");
+       SSL_CTX_set_verify(ctx, mode, openssl_verify_cb);
+     }
+     else
+     {
+       lua_pushnil(L);
+-      openssl_setvalue(L, ctx, "verify_cb");
++      openssl_valueset(L, ctx, "verify_cb");
+       SSL_CTX_set_verify(ctx, mode, openssl_verify_cb);
+     }
+     return 0;
+@@ -568,6 +794,17 @@ static int openssl_ssl_ctx_verify_mode(l
+   }
+ }
+ 
++/***
++set certificate verify callback function
++@function set_cert_verify
++@tparam[opt] function cert_verify_cb with boolean function(verifyargs) prototype, if nil or none will use openssl default callback
++verifyargs has field 'error', 'error_string','error_depth','current_cert'
++*/
++/***
++set certificate verify options
++@function set_cert_verify
++@tparam table verify_cb_flag support field always_continue with boolean value and verify_depth with number value.
++*/
+ static int openssl_ssl_ctx_set_cert_verify(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -578,13 +815,13 @@ static int openssl_ssl_ctx_set_cert_veri
+   if (lua_istable(L, 2))
+   {
+     lua_pushvalue(L, 2);
+-    openssl_setvalue(L, ctx, "verify_cb_flags");
++    openssl_valueset(L, ctx, "verify_cb_flags");
+     SSL_CTX_set_cert_verify_callback(ctx, openssl_cert_verify_cb, L);
+   }
+   else if (lua_isfunction(L, 2))
+   {
+     lua_pushvalue(L, 2);
+-    openssl_setvalue(L, ctx, "cert_verify_cb");
++    openssl_valueset(L, ctx, "cert_verify_cb");
+     SSL_CTX_set_cert_verify_callback(ctx, openssl_cert_verify_cb, L);
+   }
+   else
+@@ -600,7 +837,7 @@ static DH *tmp_dh_callback(SSL *ssl, int
+   lua_State *L = SSL_CTX_get_app_data(ctx);
+   int ret = 0;
+   /* get callback function */
+-  openssl_getvalue(L, ctx, "tmp_dh_callback");
++  openssl_valueget(L, ctx, "tmp_dh_callback");
+ 
+   /* Invoke the callback */
+   lua_pushboolean(L, is_export);
+@@ -627,7 +864,6 @@ static DH *tmp_dh_callback(SSL *ssl, int
+     lua_error(L);
+   }
+ 
+-
+   lua_pop(L, 2);    /* Remove values from stack */
+   return dh_tmp;
+ }
+@@ -640,7 +876,7 @@ static RSA *tmp_rsa_callback(SSL *ssl, i
+   lua_State *L = SSL_CTX_get_app_data(ctx);
+   int ret = 0;
+   /* get callback function */
+-  openssl_getvalue(L, ctx, "tmp_rsa_callback");
++  openssl_valueget(L, ctx, "tmp_rsa_callback");
+ 
+   /* Invoke the callback */
+   lua_pushboolean(L, is_export);
+@@ -654,11 +890,9 @@ static RSA *tmp_rsa_callback(SSL *ssl, i
+       lua_pop(L, 2);  /* Remove values from stack */
+       return NULL;
+     }
+-    bio = BIO_new_mem_buf((void*)lua_tostring(L, -1),
+-                          lua_rawlen(L, -1));
++    bio = BIO_new_mem_buf((void*)lua_tostring(L, -1), lua_rawlen(L, -1));
+     if (bio)
+     {
+-
+       rsa_tmp = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
+       BIO_free(bio);
+     }
+@@ -668,7 +902,6 @@ static RSA *tmp_rsa_callback(SSL *ssl, i
+     lua_error(L);
+   }
+ 
+-
+   lua_pop(L, 2);    /* Remove values from stack */
+   return rsa_tmp;
+ }
+@@ -682,7 +915,7 @@ static EC_KEY *tmp_ecdh_callback(SSL *ss
+   lua_State *L = SSL_CTX_get_app_data(ctx);
+   int ret = 0;
+   /* get callback function */
+-  openssl_getvalue(L, ctx, "tmp_ecdh_callback");
++  openssl_valueget(L, ctx, "tmp_ecdh_callback");
+ 
+   /* Invoke the callback */
+   lua_pushboolean(L, is_export);
+@@ -700,7 +933,6 @@ static EC_KEY *tmp_ecdh_callback(SSL *ss
+                           lua_rawlen(L, -1));
+     if (bio)
+     {
+-
+       ec_tmp = PEM_read_bio_ECPrivateKey(bio, NULL, NULL, NULL);
+       BIO_free(bio);
+     }
+@@ -710,11 +942,30 @@ static EC_KEY *tmp_ecdh_callback(SSL *ss
+     lua_error(L);
+   }
+ 
+-
+   lua_pop(L, 2);    /* Remove values from stack */
+   return ec_tmp;
+ }
+ 
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++/***
++set temp callback
++@function set_tmp
++@tparam string keytype, 'dh','ecdh',or 'rsa'
++@tparam function tmp_cb
++@param[opt] vararg
++*/
++/***
++set tmp key content pem format
++@function set_tmp
++@tparam string keytype, 'dh','ecdh',or 'rsa'
++@tparam string key_pem
++*/
++/***
++set ecdh with given curvename as tmp key
++@function set_tmp
++@tparam string keytype, must be 'ecdh'
++@tparam string curvename
++*/
+ static int openssl_ssl_ctx_set_tmp(lua_State *L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -736,20 +987,20 @@ static int openssl_ssl_ctx_set_tmp(lua_S
+     switch (nwhich)
+     {
+     case 0:
+-      openssl_setvalue(L, ctx, "tmp_dh_callback");
++      openssl_valueset(L, ctx, "tmp_dh_callback");
+       SSL_CTX_set_tmp_dh_callback(ctx, tmp_dh_callback);
+       break;
+     case 1:
+-      openssl_setvalue(L, ctx, "tmp_rsa_callback");
++      openssl_valueset(L, ctx, "tmp_rsa_callback");
+       SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_callback);
+       break;
+     case 2:
+     {
+       luaL_argcheck(L, lua_isstring(L, 4), 4, "must supply curve name");
+-      openssl_setvalue(L, ctx, "tmp_ecdh_callback");
++      openssl_valueset(L, ctx, "tmp_ecdh_callback");
+       SSL_CTX_set_tmp_ecdh_callback(ctx, tmp_ecdh_callback);
+       lua_pushvalue(L, 4);
+-      openssl_setvalue(L, ctx, "curve");
++      openssl_valueset(L, ctx, "curve");
+     }
+     break;
+     }
+@@ -806,6 +1057,7 @@ static int openssl_ssl_ctx_set_tmp(lua_S
+ 
+   return openssl_pushresult(L, ret);
+ }
++#endif
+ 
+ static int tlsext_servername_callback(SSL *ssl, int *ad, void *arg)
+ {
+@@ -820,11 +1072,11 @@ static int tlsext_servername_callback(SS
+     return SSL_TLSEXT_ERR_NOACK;
+ 
+   /* Search for the name in the map */
+-  openssl_getvalue(L, ctx, "tlsext_servername");
++  openssl_valueget(L, ctx, "tlsext_servername");
+   if (lua_istable(L, -1))
+   {
+     lua_getfield(L, -1, name);
+-    if (auxiliar_isclass(L, "openssl.ssl_ctx", -1))
++    if (auxiliar_getclassudata(L, "openssl.ssl_ctx", -1))
+     {
+       newctx = CHECK_OBJECT(-1, SSL_CTX, "openssl.ssl_ctx");
+       SSL_set_SSL_CTX(ssl, newctx);
+@@ -843,17 +1095,26 @@ static int tlsext_servername_callback(SS
+   return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ 
++/***
++set servername callback
++@function set_servefrname_callback
++@todo
++*/
+ static int openssl_ssl_ctx_set_servername_callback(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+   luaL_argcheck(L, lua_istable(L, 2) || lua_isfunction(L, 2), 2, "must be table or function");
+ 
+   lua_pushvalue(L, 2);
+-  openssl_setvalue(L, ctx, "tlsext_servername");
++  openssl_valueset(L, ctx, "tlsext_servername");
+   SSL_CTX_set_tlsext_servername_callback(ctx, tlsext_servername_callback);
+   return 0;
+ }
+ 
++/***
++flush sessions
++@function flush
++*/
+ static int openssl_ssl_ctx_flush_sessions(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -862,6 +1123,10 @@ static int openssl_ssl_ctx_flush_session
+   return 0;
+ }
+ 
++/***
++set ssl session
++@function sessions
++*/
+ static int openssl_ssl_ctx_sessions(lua_State*L)
+ {
+   SSL_CTX* ctx = CHECK_OBJECT(1, SSL_CTX, "openssl.ssl_ctx");
+@@ -890,6 +1155,18 @@ static int openssl_ssl_ctx_sessions(lua_
+   }
+ }
+ 
++/***
++get current session cache mode
++@function session_cache_mode
++@treturn table modes as array, mode is 'no_auto_clear','server','client','both','off'
++*/
++
++/***
++set session cache mode,and return old mode
++@function session_cache_mode
++@tparam string mode support 'no_auto_clear','server','client','both','off',
++'no_auto_clear' can be combine with others, so accept one or two param.
++*/
+ static int openssl_session_cache_mode(lua_State *L)
+ {
+   static const char* smode[] =
+@@ -966,12 +1243,19 @@ static int openssl_session_cache_mode(lu
+   return 1;
+ }
+ 
++#ifdef SSL_CTX_EXT_DEFINE
++SSL_CTX_EXT_DEFINE
++#endif
++
+ static luaL_Reg ssl_ctx_funcs[] =
+ {
+   {"ssl",             openssl_ssl_ctx_new_ssl},
+   {"bio",             openssl_ssl_ctx_new_bio},
+-
++#ifndef SSL_CTX_USE_EXT
+   {"use",             openssl_ssl_ctx_use},
++#else
++  SSL_CTX_USE_EXT
++#endif
+   {"add",             openssl_ssl_ctx_add},
+   {"mode",            openssl_ssl_ctx_mode},
+   {"timeout",         openssl_ssl_ctx_timeout},
+@@ -979,16 +1263,20 @@ static luaL_Reg ssl_ctx_funcs[] =
+   {"quiet_shutdown",  openssl_ssl_ctx_quiet_shutdown},
+   {"verify_locations", openssl_ssl_ctx_load_verify_locations},
+   {"cert_store",      openssl_ssl_ctx_cert_store},
+-
++#ifndef OPENSSL_NO_ENGINE
++  {"set_engine",      openssl_ssl_ctx_set_engine},
++#endif
+   {"verify_mode",     openssl_ssl_ctx_verify_mode },
+-  {"set_cert_verify",    openssl_ssl_ctx_set_cert_verify},
+-  {"set_servername_callback",    openssl_ssl_ctx_set_servername_callback},
++  {"set_cert_verify", openssl_ssl_ctx_set_cert_verify},
+ 
+   {"verify_depth",    openssl_ssl_ctx_verify_depth},
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+   {"set_tmp",         openssl_ssl_ctx_set_tmp},
++#endif
+   {"flush_sessions",  openssl_ssl_ctx_flush_sessions},
+   {"session",         openssl_ssl_ctx_sessions},
+   {"session_cache_mode",        openssl_session_cache_mode },
++  {"set_servername_callback",   openssl_ssl_ctx_set_servername_callback },
+ 
+   {"__gc",            openssl_ssl_ctx_gc},
+   {"__tostring",      auxiliar_tostring},
+@@ -1015,30 +1303,26 @@ SL_SESSION *(*SSL_CTX_sess_get_get_cb(SS
+   SSL_SESSION *session;
+ */
+ 
+-
+-static int openssl_ssl_session_new(lua_State*L)
++/***
++get peer certificate verify result
++@function getpeerverification
++@treturn boolean true for success
++@treturn table all certificate in chains verify result
++ preverify_ok as boolean verify result
++ error as number error code
++ error_string as string error message
++ error_depth as number verify depth
++ current_cert as x509 certificate to verified
++*/
++static int openssl_ssl_getpeerverification(lua_State *L)
+ {
+-  SSL_SESSION *ss = SSL_SESSION_new();
+-  PUSH_OBJECT(ss, "openssl.ssl_session");
+-  return 1;
+-}
++  long err;
++  SSL* ssl = CHECK_OBJECT(1, SSL, "openssl.ssl");
+ 
+-static int openssl_ssl_session_read(lua_State*L)
+-{
+-  BIO *in = load_bio_object(L, 1);
+-  SSL_SESSION* ss = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
+-  if (!ss)
+-  {
+-    BIO_reset(in);
+-    ss = d2i_SSL_SESSION_bio(in, NULL);
+-  }
+-  BIO_free(in);
+-  if (ss)
+-  {
+-    PUSH_OBJECT(ss, "openssl.ssl_session");
+-    return 1;
+-  }
+-  return openssl_pushresult(L, 0);
++  err = SSL_get_verify_result(ssl);
++  lua_pushboolean(L, err == X509_V_OK);
++  openssl_valueget(L, ssl, "verify_cert");
++  return 2;
+ }
+ 
+ static int openssl_ssl_session_time(lua_State*L)
+@@ -1165,8 +1449,23 @@ static luaL_Reg ssl_session_funcs[] =
+ 
+ 
+ /***************************SSL**********************************/
++/***
++openssl.ssl object
++All SSL object IO operation methods(connect, accept, handshake, read,
++peek or write) return nil or false when fail or error.
++When nil returned, it followed by 'ssl' or 'syscall', means SSL layer or
++system layer error. When false returned, it followed by number 0,
++'want_read','want_write','want_x509_lookup','want_connect','want_accept'.
++Numnber 0 means SSL connection closed, others means you should do some
++SSL operation.
++@type ssl
++*/
+ 
+-/* need more think */
++/***
++reset ssl object to allow another connection
++@function clear
++@treturn boolean result true for success
++*/
+ static int openssl_ssl_clear(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1174,6 +1473,13 @@ static int openssl_ssl_clear(lua_State*L
+   return 1;
+ }
+ 
++/***
++tell ssl use private key and certificate, and check private key
++@function use
++@tparam evp_pkey pkey
++@tparam[opt] x509 cert
++@treturn boolean result return true for ok, or nil followed by errmsg and errval
++*/
+ static int openssl_ssl_use(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1181,7 +1487,6 @@ static int openssl_ssl_use(lua_State*L)
+   EVP_PKEY* pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
+   int ret;
+ 
+-  luaL_argcheck(L, openssl_pkey_is_private(pkey), 3, "must be private key");
+   ret = SSL_use_PrivateKey(s, pkey);
+   if (ret == 1)
+   {
+@@ -1194,6 +1499,12 @@ static int openssl_ssl_use(lua_State*L)
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++get peer certificate and certificate chains
++@function peer
++@treturn[1] x509 certificate
++@treturn[1] sk_of_x509 chains of peer
++*/
+ static int openssl_ssl_peer(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1217,6 +1528,12 @@ static int openssl_ssl_gc(lua_State*L)
+   return 0;
+ }
+ 
++/***
++get want to do
++@function want
++@treturn[1] string 'nothing', 'reading', 'writing', 'x509_lookup'
++@treturn[1] number state want
++*/
+ static int openssl_ssl_want(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1235,7 +1552,12 @@ static int openssl_ssl_want(lua_State*L)
+   lua_pushinteger(L, st);
+   return 2;
+ }
+-#ifndef LIBRESSL_VERSION_NUMBER
++#if !defined(OPENSSL_NO_COMP) && !defined(LIBRESSL_VERSION_NUMBER)
++/***
++get current compression name
++@function current_compression
++@treturn string
++*/
+ static int openssl_ssl_current_compression(lua_State *L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1248,6 +1570,11 @@ static int openssl_ssl_current_compressi
+ }
+ #endif
+ 
++/***
++get current cipher info
++@function current_cipher
++@treturn table include name,version,id,bits,algbits and description
++*/
+ static int openssl_ssl_current_cipher(lua_State *L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1276,6 +1603,11 @@ static int openssl_ssl_current_cipher(lu
+   return 0;
+ }
+ 
++/***
++get number of bytes available inside SSL fro immediate read
++@function pending
++@treturn number
++*/
+ static int openssl_ssl_pending(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1330,6 +1662,11 @@ static int openssl_ssl_pushresult(lua_St
+   }
+ }
+ 
++/***
++get socket fd of ssl
++@function getfd
++@treturn number fd
++*/
+ static int openssl_ssl_getfd(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1337,6 +1674,33 @@ static int openssl_ssl_getfd(lua_State*L
+   return 1;
+ }
+ 
++/***
++get value according to arg
++@function get
++@tparam string arg
++ <br/>certificate:  return SSL certificates
++ <br/>fd: return file or network connect fd
++ <br/>rfd:
++ <br/>wfd:
++ <br/>client_CA_list
++ <br/>read_ahead: -> boolean
++ <br/>shared_ciphers: string
++ <br/>cipher_list -> string
++ <br/>verify_mode: number
++ <br/>verify_depth
++ <br/>state_string
++ <br/>state_string_long
++ <br/>rstate_string
++ <br/>rstate_string_long
++ <br/>iversion
++ <br/>version
++ <br/>default_timeout,
++ <br/>certificates
++ <br/>verify_result
++ <br/>state
++ <br/>state_string
++@return according to arg
++*/
+ static int openssl_ssl_get(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1429,7 +1793,7 @@ static int openssl_ssl_get(lua_State*L)
+     }
+     else if (strcmp(what, "state") == 0)
+     {
+-      lua_pushinteger(L, SSL_state(s));
++      lua_pushinteger(L, SSL_get_state(s));
+     }
+     else if (strcmp(what, "hostname") == 0)
+     {
+@@ -1441,6 +1805,25 @@ static int openssl_ssl_get(lua_State*L)
+   return top - 1;
+ }
+ 
++/***
++set value according to arg
++@function set
++@tparam string arg
++ <br/>certificate:  return SSL certificates
++ <br/>fd: return file or network connect fd
++ <br/>rfd:
++ <br/>wfd:
++ <br/>client_CA:
++ <br/>read_ahead:
++ <br/>cipher_list:
++ <br/>verify_depth:
++ <br/>purpose:
++ <br/>trust:
++ <br/>verify_result:
++ <br/>hostname:
++@param value val type accroding to arg
++@return value
++*/
+ static int openssl_ssl_set(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1482,7 +1865,6 @@ static int openssl_ssl_set(lua_State*L)
+       int depth = luaL_checkint(L, i + 1);
+       SSL_set_verify_depth(s, depth);
+     }
+-
+     else if (strcmp(what, "purpose") == 0)
+     {
+       //FIX
+@@ -1505,14 +1887,6 @@ static int openssl_ssl_set(lua_State*L)
+       const char* hostname = luaL_checkstring(L, i + 1);
+       SSL_set_tlsext_host_name(s, hostname);
+     }
+-
+-#if OPENSSL_VERSION_NUMBER > 0x10000000L
+-    else if (strcmp(what, "state") == 0)
+-    {
+-      int l = luaL_checkint(L, 2);
+-      SSL_set_state(s, l);
+-    }
+-#endif
+     else
+       luaL_argerror(L, i, "don't understand");
+ 
+@@ -1522,6 +1896,12 @@ static int openssl_ssl_set(lua_State*L)
+   return 0;
+ }
+ 
++/***
++do ssl server accept
++@function accept
++@treturn boolean true for success
++@treturn string fail reason
++*/
+ static int openssl_ssl_accept(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1529,6 +1909,12 @@ static int openssl_ssl_accept(lua_State*
+   return openssl_ssl_pushresult(L, s, ret);
+ }
+ 
++/***
++do ssl client connect
++@function connect
++@treturn boolean true for success
++@treturn string fail reasion
++*/
+ static int openssl_ssl_connect(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1536,6 +1922,13 @@ static int openssl_ssl_connect(lua_State
+   return openssl_ssl_pushresult(L, s, ret);
+ }
+ 
++/***
++do ssl read
++@function read
++@tparam[opt=4096] number length to read
++@treturn string data, nil or false for fail
++@treturn string fail reason
++*/
+ static int openssl_ssl_read(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1558,6 +1951,13 @@ static int openssl_ssl_read(lua_State*L)
+   return ret;
+ }
+ 
++/***
++do ssl peak, data can be read again
++@function peek
++@tparam[opt=4096] number length to read
++@treturn string data, nil or false for fail
++@treturn string fail reason
++*/
+ static int openssl_ssl_peek(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1581,6 +1981,13 @@ static int openssl_ssl_peek(lua_State*L)
+   return ret;
+ }
+ 
++/***
++do ssl write
++@function write
++@tparam string data
++@treturn number count of bytes write successfully
++@treturn string fail reason
++*/
+ static int openssl_ssl_write(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1598,6 +2005,12 @@ static int openssl_ssl_write(lua_State*L
+   }
+ }
+ 
++/***
++do ssl handshake, support both server and client side
++@function handshake
++@treturn boolean true for success
++@treturn string fail reasion
++*/
+ static int openssl_ssl_do_handshake(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1605,6 +2018,12 @@ static int openssl_ssl_do_handshake(lua_
+   return openssl_ssl_pushresult(L, s, ret);
+ }
+ 
++/***
++do ssl renegotiate
++@function renegotiate
++@treturn boolean true for success
++@treturn string fail reasion
++*/
+ static int openssl_ssl_renegotiate(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1620,6 +2039,19 @@ static int openssl_ssl_renegotiate_abbre
+   return openssl_ssl_pushresult(L, s, ret);
+ }
+ #endif
++
++/***
++get ssl renegotiate_pending
++@function renegotiate_pending
++@treturn boolean true for success
++@treturn string fail reasion
++*/
++/***
++do ssl renegotiate_pending
++@function renegotiate_pending
++@treturn boolean true for success
++@treturn string fail reasion
++*/
+ static int openssl_ssl_renegotiate_pending(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1627,6 +2059,23 @@ static int openssl_ssl_renegotiate_pendi
+   return openssl_ssl_pushresult(L, s, ret);
+ }
+ 
++/***
++shutdown ssl connection with quite or noquite mode
++@function shutdown
++@tparam boolean mode
++@treturn boolean if mode is true, return true or false for quite
++@treturn string if mode is false, return 'read' or 'write' for shutdown direction
++*/
++/***
++shutdown SSL connection
++@function shutdown
++*/
++/***
++shutdown ssl connect with special mode, disable read or write,
++enable or disable quite shutdown
++@function shutdown
++@tparam string mode support 'read','write', 'quite', 'noquite'
++*/
+ static int openssl_ssl_shutdown(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1674,6 +2123,10 @@ static int openssl_ssl_shutdown(lua_Stat
+   return 0;
+ };
+ 
++/***
++make ssl to client mode
++@function set_connect_state
++*/
+ static int openssl_ssl_set_connect_state(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1681,6 +2134,10 @@ static int openssl_ssl_set_connect_state
+   return 0;
+ }
+ 
++/***
++make ssl to server mode
++@function set_accept_state
++*/
+ static int openssl_ssl_set_accept_state(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1688,6 +2145,11 @@ static int openssl_ssl_set_accept_state(
+   return 0;
+ }
+ 
++/***
++duplicate ssl object
++@treturn ssl
++@function dup
++*/
+ static int openssl_ssl_dup(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1696,6 +2158,10 @@ static int openssl_ssl_dup(lua_State*L)
+   return 1;
+ }
+ 
++/***
++get ssl session resused
++@function session_reused
++*/
+ static int openssl_ssl_session_reused(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1722,6 +2188,17 @@ static int openssl_ssl_set_debug(lua_Sta
+ #endif
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x0090819fL
++/***
++get ssl_ctx associate with current ssl
++@function ctx
++@treturn ssl_ctx
++*/
++/***
++set ssl_ctx associate to current ssl
++@function ctx
++@tparam ssl_ctx ctx
++@treturn ssl_ctx orgine ssl_ctx object
++*/
+ static int openssl_ssl_ctx(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1741,7 +2218,18 @@ static int openssl_ssl_ctx(lua_State*L)
+ }
+ #endif
+ 
+-
++/***
++get ssl session
++@treturn ssl_session session object
++@function session
++*/
++/***
++set ssl session
++@function session
++@tparam string|ssl_session sesion
++ reuse session would speed up ssl handshake
++@treturn boolean result
++*/
+ static int openssl_ssl_session(lua_State*L)
+ {
+   SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
+@@ -1794,7 +2282,7 @@ static luaL_Reg ssl_funcs[] =
+   {"getfd",     openssl_ssl_getfd},
+ 
+   {"current_cipher",        openssl_ssl_current_cipher},
+-#ifndef LIBRESSL_VERSION_NUMBER
++#if !defined(OPENSSL_NO_COMP) && !defined(LIBRESSL_VERSION_NUMBER)
+   {"current_compression",   openssl_ssl_current_compression},
+ #endif
+   {"getpeerverification",   openssl_ssl_getpeerverification},
+@@ -1834,16 +2322,6 @@ static luaL_Reg ssl_funcs[] =
+   {NULL,      NULL},
+ };
+ 
+-static luaL_Reg R[] =
+-{
+-  {"ctx_new",       openssl_ssl_ctx_new },
+-  {"alert_string",  openssl_ssl_alert_string },
+-
+-  {"session_new",   openssl_ssl_session_new},
+-  {"session_read",  openssl_ssl_session_read},
+-  {NULL,    NULL}
+-};
+-
+ int luaopen_ssl(lua_State *L)
+ {
+   int i;
+@@ -1855,7 +2333,6 @@ int luaopen_ssl(lua_State *L)
+   auxiliar_newclass(L, "openssl.ssl_session",   ssl_session_funcs);
+   auxiliar_newclass(L, "openssl.ssl",           ssl_funcs);
+ 
+-
+   lua_newtable(L);
+   luaL_setfuncs(L, R, 0);
+ 
+@@ -1863,12 +2340,7 @@ int luaopen_ssl(lua_State *L)
+   lua_pushliteral(L, MYVERSION);
+   lua_settable(L, -3);
+ 
+-  for (i = 0; i < sizeof(ssl_options) / sizeof(LuaL_Enum) - 1; i++)
+-  {
+-    LuaL_Enum e = ssl_options[i];
+-    lua_pushinteger(L, e.val);
+-    lua_setfield(L, -2, e.name);
+-  }
++  auxiliar_enumerate(L, -1, ssl_options);
+   for (i = 0; sVerifyMode_Options[i]; i++)
+   {
+     lua_pushinteger(L, iVerifyMode_Options[i]);
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/ssl_options.h luvi-src-v2.7.6/deps/lua-openssl/src/ssl_options.h
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/ssl_options.h	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/ssl_options.h	2019-02-13 11:53:24.321792707 +0100
+@@ -4,7 +4,7 @@
+ #include <openssl/ssl.h>
+ #include "auxiliar.h"
+ 
+-static LuaL_Enum ssl_options[] =
++static LuaL_Enumeration ssl_options[] =
+ {
+ #if defined(SSL_OP_ALL)
+   {"all", SSL_OP_ALL},
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/th-lock.c luvi-src-v2.7.6/deps/lua-openssl/src/th-lock.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/th-lock.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/th-lock.c	2019-02-13 11:53:24.321792707 +0100
+@@ -60,6 +60,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <errno.h>
++#include <openssl/crypto.h>
+ #ifdef OPENSSL_SYS_WIN32
+ #include <windows.h>
+ #endif
+@@ -76,25 +77,10 @@
+ #include <pthread.h>
+ #endif
+ #endif
+-#include <openssl/lhash.h>
+-#include <openssl/crypto.h>
+-#include <openssl/buffer.h>
+-#include <openssl/x509.h>
+-#include <openssl/ssl.h>
+-#include <openssl/err.h>
+ 
+ void CRYPTO_thread_setup(void);
+ void CRYPTO_thread_cleanup(void);
+ 
+-static void irix_locking_callback(int mode, int type, const char *file, int line);
+-static void solaris_locking_callback(int mode, int type, const char *file, int line);
+-static void win32_locking_callback(int mode, int type, const char *file, int line);
+-static void pthreads_locking_callback(int mode, int type, const char *file, int line);
+-
+-static unsigned long irix_thread_id(void );
+-static unsigned long solaris_thread_id(void );
+-static unsigned long pthreads_thread_id(void );
+-
+ /* usage:
+  * CRYPTO_thread_setup();
+  * application code
+@@ -105,6 +91,8 @@ static unsigned long pthreads_thread_id(
+ 
+ #ifdef OPENSSL_SYS_WIN32
+ 
++static void win32_locking_callback(int mode, int type, const char *file, int line);
++
+ static HANDLE *lock_cs;
+ 
+ void CRYPTO_thread_setup(void)
+@@ -149,6 +137,9 @@ static void win32_locking_callback(int m
+ 
+ #ifdef SOLARIS
+ 
++static void solaris_locking_callback(int mode, int type, const char *file, int line);
++static unsigned long solaris_thread_id(void );
++
+ #define USE_MUTEX
+ 
+ #ifdef USE_MUTEX
+@@ -246,6 +237,10 @@ unsigned long solaris_thread_id(void)
+ #endif /* SOLARIS */
+ 
+ #ifdef IRIX
++
++static void irix_locking_callback(int mode, int type, const char *file, int line);
++static unsigned long irix_thread_id(void );
++
+ /* I don't think this works..... */
+ 
+ static usptr_t *arena;
+@@ -316,6 +311,10 @@ unsigned long irix_thread_id(void)
+ /* Linux and a few others */
+ #ifdef PTHREADS
+ #ifndef OPENSSL_SYS_WIN32
++
++static void pthreads_locking_callback(int mode, int type, const char *file, int line);
++static unsigned long pthreads_thread_id(void );
++
+ static pthread_mutex_t *lock_cs;
+ static long *lock_count;
+ 
+@@ -335,7 +334,7 @@ void CRYPTO_thread_setup(void)
+   CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
+ }
+ 
+-void thread_cleanup(void)
++void CRYPTO_thread_cleanup(void)
+ {
+   int i;
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/util.c luvi-src-v2.7.6/deps/lua-openssl/src/util.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/util.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/util.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,6 +1,6 @@
+ #include "private.h"
+ 
+-int openssl_newvalue(lua_State*L, void*p)
++int openssl_newvalue(lua_State*L,const void*p)
+ {
+   lua_rawgetp(L, LUA_REGISTRYINDEX, p);
+   if (lua_isnil(L, -1))
+@@ -14,14 +14,14 @@ int openssl_newvalue(lua_State*L, void*p
+   return 0;
+ }
+ 
+-int openssl_freevalue(lua_State*L, void*p)
++int openssl_freevalue(lua_State*L, const void*p)
+ {
+   lua_pushnil(L);
+   lua_rawsetp(L, LUA_REGISTRYINDEX, p);
+   return 0;
+ }
+ 
+-int openssl_setvalue(lua_State*L, void*p, const char*field)
++int openssl_valueset(lua_State*L, const void*p, const char*field)
+ {
+   lua_rawgetp(L, LUA_REGISTRYINDEX, p);
+   lua_pushvalue(L, -2);
+@@ -31,7 +31,7 @@ int openssl_setvalue(lua_State*L, void*p
+   return 0;
+ }
+ 
+-int openssl_getvalue(lua_State*L, void*p, const char*field)
++int openssl_valueget(lua_State*L, const void*p, const char*field)
+ {
+   lua_rawgetp(L, LUA_REGISTRYINDEX, p);
+   if (!lua_isnil(L, -1))
+@@ -39,10 +39,43 @@ int openssl_getvalue(lua_State*L, void*p
+     lua_getfield(L, -1, field);
+     lua_remove(L, -2);
+   }
++  return lua_type(L, -1);
++}
++
++int openssl_valueseti(lua_State*L, const void*p, int i)
++{
++  lua_rawgetp(L, LUA_REGISTRYINDEX, p);
++  lua_pushvalue(L, -2);
++  lua_remove(L, -3);
++  lua_rawseti(L, -2, i);
++  lua_pop(L, 1);
+   return 0;
+ }
+ 
+-int openssl_refrence(lua_State*L, void*p, int op)
++int openssl_valuegeti(lua_State*L, const void*p, int i)
++{
++  lua_rawgetp(L, LUA_REGISTRYINDEX, p);
++  if (!lua_isnil(L, -1))
++  {
++    lua_rawgeti(L, -1, i);
++    lua_remove(L, -2);
++  }
++  return lua_type(L, -1);
++}
++
++size_t openssl_valuelen(lua_State*L, const void*p)
++{
++  size_t s = 0;
++  lua_rawgetp(L, LUA_REGISTRYINDEX, p);
++  if (!lua_isnil(L, -1))
++  {
++    s = lua_rawlen(L, -1);
++  }
++  lua_pop(L, 1);
++  return s;
++}
++
++int openssl_refrence(lua_State*L, const void*p, int op)
+ {
+   int ref;
+   lua_rawgetp(L, LUA_REGISTRYINDEX, p);
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/x509.c luvi-src-v2.7.6/deps/lua-openssl/src/x509.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/x509.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/x509.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,9 +1,12 @@
+-/*=========================================================================*\
+-* x509.c
+-* x509 modules for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
++/***
++x509 modules for lua-openssl binding
++create and manage x509 certificate
++@module x509
++@usage
++ x509 = require'openssl'.x509
++*/
++
++
+ #include "openssl.h"
+ #include "private.h"
+ #define CRYPTO_LOCK_REF
+@@ -13,21 +16,326 @@
+ #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2014 / "\
+   "based on OpenSSL " SHLIB_VERSION_NUMBER
+ 
+-int openssl_push_x509_algor(lua_State*L, const X509_ALGOR* alg)
++static int openssl_push_purpose(lua_State*L, X509_PURPOSE* purpose)
+ {
+   lua_newtable(L);
+-  openssl_push_asn1object(L, alg->algorithm);
+-  lua_setfield(L, -2, "algorithm");
+-  if (alg->parameter)
++
++  AUXILIAR_SET(L, -1, "purpose", purpose->purpose, integer);
++  AUXILIAR_SET(L, -1, "trust", purpose->trust, integer);
++  AUXILIAR_SET(L, -1, "flags", purpose->flags, integer);
++
++  AUXILIAR_SET(L, -1, "name", purpose->name, string);
++  AUXILIAR_SET(L, -1, "sname", purpose->sname, string);
++
++  return 1;
++};
++
++/***
++return all supported purpose as table
++@function purpose
++@treturn table
++*/
++/*
++get special purpose info as table
++@function purpose
++@tparam number|string purpose id or short name
++@treturn table
++*/
++static int openssl_x509_purpose(lua_State*L)
++{
++  if (lua_isnoneornil(L, 1))
++  {
++    int count = X509_PURPOSE_get_count();
++    int i;
++    lua_newtable(L);
++    for (i = 0; i < count; i++)
++    {
++      X509_PURPOSE* purpose = X509_PURPOSE_get0(i);
++      openssl_push_purpose(L, purpose);
++      lua_rawseti(L, -2, i + 1);
++    }
++    return 1;
++  }
++  else if (lua_isnumber(L, 1))
++  {
++    int idx = X509_PURPOSE_get_by_id(lua_tointeger(L, 1));
++    if (idx >= 0)
++    {
++      X509_PURPOSE* purpose = X509_PURPOSE_get0(idx);
++      openssl_push_purpose(L, purpose);
++    }
++    else
++      lua_pushnil(L);
++    return 1;
++  }
++  else if (lua_isstring(L, 1))
++  {
++    char* name = (char*)lua_tostring(L, 1);
++    int idx = X509_PURPOSE_get_by_sname(name);
++    if (idx >= 0)
++    {
++      X509_PURPOSE* purpose = X509_PURPOSE_get0(idx);
++      openssl_push_purpose(L, purpose);
++    }
++    else
++      lua_pushnil(L);
++    return 1;
++  }
++  return 0;
++};
++
++static const char* usage_mode[] =
++{
++  "standard",
++  "netscape",
++  "extend",
++  NULL
++};
++
++/***
++get support certtypes
++@function certtypes
++@tparam[opt='standard'] string type support 'standard','netscape','extend'
++@treturn table if type is 'standard' or 'netscape', contains node with {lname=...,sname=...,bitname=...},
++               if type is 'extend', contains node with {lname=...,sname=...,nid=...}
++*/
++static int openssl_x509_certtypes(lua_State*L)
++{
++  int mode = luaL_checkoption(L, 1, "standard", usage_mode);
++  int i;
++  const BIT_STRING_BITNAME* bitname;
++
++  switch (mode)
++  {
++  case 0:
++  {
++    const static BIT_STRING_BITNAME key_usage_type_table[] =
++    {
++      {0, "Digital Signature", "digitalSignature"},
++      {1, "Non Repudiation", "nonRepudiation"},
++      {2, "Key Encipherment", "keyEncipherment"},
++      {3, "Data Encipherment", "dataEncipherment"},
++      {4, "Key Agreement", "keyAgreement"},
++      {5, "Certificate Sign", "keyCertSign"},
++      {6, "CRL Sign", "cRLSign"},
++      {7, "Encipher Only", "encipherOnly"},
++      {8, "Decipher Only", "decipherOnly"},
++      { -1, NULL, NULL}
++    };
++    lua_newtable(L);
++    for (i = 0, bitname = &key_usage_type_table[i]; bitname->bitnum != -1; i++, bitname = &key_usage_type_table[i])
++    {
++      openssl_push_bit_string_bitname(L, bitname);
++      lua_rawseti(L, -2, i + 1);
++    }
++    return 1;
++
++  }
++  case 1:
+   {
+-    openssl_push_asn1type(L, alg->parameter);
+-    lua_setfield(L, -2, "parameter");
++    const static BIT_STRING_BITNAME ns_cert_type_table[] =
++    {
++      {0, "SSL Client", "client"},
++      {1, "SSL Server", "server"},
++      {2, "S/MIME", "email"},
++      {3, "Object Signing", "objsign"},
++      {4, "Unused", "reserved"},
++      {5, "SSL CA", "sslCA"},
++      {6, "S/MIME CA", "emailCA"},
++      {7, "Object Signing CA", "objCA"},
++      { -1, NULL, NULL}
++    };
++    lua_newtable(L);
++    for (i = 0, bitname = &ns_cert_type_table[i]; bitname->bitnum != -1; i++, bitname = &ns_cert_type_table[i])
++    {
++      openssl_push_bit_string_bitname(L, bitname);
++      lua_rawseti(L, -2, i + 1);
++    }
++    return 1;
+   }
++  case 2:
++  {
++    static const int ext_nids[] =
++    {
++      NID_server_auth,
++      NID_client_auth,
++      NID_email_protect,
++      NID_code_sign,
++      NID_ms_sgc,
++      NID_ns_sgc,
++      NID_OCSP_sign,
++      NID_time_stamp,
++      NID_dvcs,
++      NID_anyExtendedKeyUsage
++    };
++    int count = sizeof(ext_nids) / sizeof(int);
++    int nid;
++    lua_newtable(L);
++    for (i = 0; i < count; i++)
++    {
++      nid = ext_nids[i];
++      lua_newtable(L);
++      lua_pushstring(L, OBJ_nid2ln(nid));
++      lua_setfield(L, -2, "lname");
++      lua_pushstring(L, OBJ_nid2sn(nid));
++      lua_setfield(L, -2, "sname");
++      lua_pushinteger(L, nid);
++      lua_setfield(L, -2, "nid");
++      lua_rawseti(L, -2, i + 1);
++    };
++    return 1;
++  }
++  }
++  return 0;
++}
++
++/***
++get certificate verify result string message
++@function verify_cert_error_string
++@tparam number verify_result
++@treturn string result message
++*/
++static int openssl_verify_cert_error_string(lua_State*L)
++{
++  int v = luaL_checkint(L, 1);
++  const char*s = X509_verify_cert_error_string(v);
++  lua_pushstring(L, s);
+   return 1;
++}
++
++/***
++read x509 from string or bio input
++@function read
++@tparam bio|string input input data
++@tparam[opt='auto'] string format support 'auto','pem','der'
++@treturn x509 certificate object
++*/
++static LUA_FUNCTION(openssl_x509_read)
++{
++  X509 *cert = NULL;
++  BIO *in = load_bio_object(L, 1);
++  int fmt = luaL_checkoption(L, 2, "auto", format);
++  if (fmt == FORMAT_AUTO)
++  {
++    fmt = bio_is_der(in) ? FORMAT_DER : FORMAT_PEM;
++  }
++
++  if (fmt == FORMAT_DER)
++  {
++    cert = d2i_X509_bio(in, NULL);
++  }
++  else if (fmt == FORMAT_PEM)
++  {
++    cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
++  }
++
++  BIO_free(in);
++
++  if (cert)
++  {
++    PUSH_OBJECT(cert, "openssl.x509");
++    return 1;
++  }
++  return openssl_pushresult(L, 0);
++}
++
++/***
++create or generate a new x509 object.
++@function new
++@tparam[opt] openssl.bn serial serial number
++@tparam[opt] x509_req csr,copy x509_name, pubkey and extension to new object
++@tparam[opt] x509_name subject subject name set to x509_req
++@tparam[opt] stack_of_x509_extension extensions add to x509
++@tparam[opt] stack_of_x509_attribute attributes add to x509
++@treturn x509 certificate object
++*/
++static int openssl_x509_new(lua_State* L)
++{
++  int i = 1;
++  int ret = 1;
++  int n = lua_gettop(L);
++  X509 *x = X509_new();
++
++  ret = X509_set_version(x, 2);
++  if (ret == 1 && (
++        auxiliar_getclassudata(L, "openssl.bn", i) ||
++        lua_isstring(L, i) || lua_isnumber(L, i)
++      ))
++  {
++    BIGNUM *bn = BN_get(L, i);
++    ASN1_INTEGER* ai = BN_to_ASN1_INTEGER(bn, NULL);
++    BN_free(bn);
++    ret = X509_set_serialNumber(x, ai);
++    ASN1_INTEGER_free(ai);
++    i++;
++  }
++
++  for (; i <= n; i++)
++  {
++    if (ret == 1 && auxiliar_getclassudata(L, "openssl.x509_req", i))
++    {
++      X509_REQ* csr = CHECK_OBJECT(i, X509_REQ, "openssl.x509_req");
++      X509_NAME* xn = X509_REQ_get_subject_name(csr);
++      ret = X509_set_subject_name(x, xn);
++
++      if (ret == 1)
++      {
++        STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(csr);
++        int j, n1;
++        n1 = sk_X509_EXTENSION_num(exts);
++        for (j = 0; ret == 1 && j < n1; j++)
++        {
++          ret = X509_add_ext(x, sk_X509_EXTENSION_value(exts, j), j);
++        }
++        sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
++      }
++      if (ret == 1)
++      {
++        EVP_PKEY* pkey = X509_REQ_get_pubkey(csr);
++        ret = X509_set_pubkey(x, pkey);
++        EVP_PKEY_free(pkey);
++      }
++      i++;
++    };
++
++    if (ret == 1 && auxiliar_getclassudata(L, "openssl.x509_name", i))
++    {
++      X509_NAME *xn = CHECK_OBJECT(i, X509_NAME, "openssl.x509_name");
++      ret = X509_set_subject_name(x, xn);
++      i++;
++    }
++  }
++
++  if (ret == 1)
++  {
++    PUSH_OBJECT(x, "openssl.x509");
++    return 1;
++  }
++  else
++  {
++    X509_free(x);
++    return openssl_pushresult(L, ret);
++  }
++};
++
++static luaL_Reg R[] =
++{
++  {"new",           openssl_x509_new },
++  {"read",          openssl_x509_read },
++  {"purpose",       openssl_x509_purpose },
++  {"certtypes",     openssl_x509_certtypes },
++  {"verify_cert_error_string", openssl_verify_cert_error_string },
++
++  {NULL,    NULL}
+ };
+ 
+ int openssl_push_general_name(lua_State*L, const GENERAL_NAME* general_name)
+ {
++  if (general_name == NULL)
++  {
++    lua_pushnil(L);
++    return 1;
++  }
+   lua_newtable(L);
+ 
+   switch (general_name->type)
+@@ -137,37 +445,17 @@ static int check_cert(X509_STORE *ca, X5
+   return X509_V_ERR_OUT_OF_MEM;
+ }
+ 
+-static LUA_FUNCTION(openssl_x509_read)
+-{
+-  X509 *cert = NULL;
+-  BIO *in = load_bio_object(L, 1);
+-  int fmt = luaL_checkoption(L, 2, "auto", format);
+-  if (fmt == FORMAT_AUTO)
+-  {
+-    fmt = bio_is_der(in) ? FORMAT_DER : FORMAT_PEM;
+-  }
+-
+-  if (fmt == FORMAT_DER)
+-  {
+-    cert = d2i_X509_bio(in, NULL);
+-    BIO_reset(in);
+-  }
+-  else if (fmt == FORMAT_PEM)
+-  {
+-    cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+-    BIO_reset(in);
+-  }
+-
+-  BIO_free(in);
+-
+-  if (cert)
+-  {
+-    PUSH_OBJECT(cert, "openssl.x509");
+-    return 1;
+-  }
+-  return openssl_pushresult(L, 0);
+-}
+-
++/***
++openssl.x509 object
++@type x509
++*/
++/***
++export x509_req to string
++@function export
++@tparam[opt='pem'] string format, 'der' or 'pem' default
++@tparam[opt='true'] boolean noext not export extension
++@treturn string
++*/
+ static LUA_FUNCTION(openssl_x509_export)
+ {
+   X509 *cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -213,19 +501,25 @@ static LUA_FUNCTION(openssl_x509_export)
+   return 1;
+ };
+ 
+-
++/***
++parse x509 object as table
++@function parse
++@tparam[opt=true] shortname default will use short object name
++@treturn table result which all x509 information
++*/
+ static LUA_FUNCTION(openssl_x509_parse)
+ {
+   int i;
+   X509 * cert = CHECK_OBJECT(1, X509, "openssl.x509");
+   X509_ALGOR* alg = 0;
+   lua_newtable(L);
+-
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+   if (cert->name)
+   {
+     AUXILIAR_SET(L, -1, "name", cert->name, string);
+   }
+   AUXILIAR_SET(L, -1, "valid", cert->valid, boolean);
++#endif
+   AUXILIAR_SET(L, -1, "version", X509_get_version(cert), integer);
+ 
+   openssl_push_xname_asobject(L, X509_get_subject_name(cert));
+@@ -238,16 +532,31 @@ static LUA_FUNCTION(openssl_x509_parse)
+     AUXILIAR_SET(L, -1, "hash", buf, string);
+   }
+ 
+-  PUSH_ASN1_INTEGER(L, cert->cert_info->serialNumber);
++  PUSH_ASN1_INTEGER(L, X509_get0_serialNumber(cert));
+   lua_setfield(L, -2, "serialNumber");
++
+   PUSH_ASN1_TIME(L, X509_get_notBefore(cert));
+   lua_setfield(L, -2, "notBefore");
+   PUSH_ASN1_TIME(L, X509_get_notAfter(cert));
+   lua_setfield(L, -2, "notAfter");
+ 
+-  alg = X509_ALGOR_dup(cert->sig_alg);
+-  PUSH_OBJECT(alg, "openssl.x509_algor");
+-  lua_setfield(L, -2, "sig_alg");
++  {
++    CONSTIFY_X509_get0 X509_ALGOR *palg = NULL;
++    CONSTIFY_X509_get0 ASN1_BIT_STRING *psig = NULL;
++
++    X509_get0_signature(&psig, &palg, cert);
++    if (palg != NULL)
++    {
++      alg = X509_ALGOR_dup((X509_ALGOR*)palg);
++      PUSH_OBJECT(alg, "openssl.x509_algor");
++      lua_setfield(L, -2, "sig_alg");
++    }
++    if (psig != NULL)
++    {
++      lua_pushlstring(L, (const char *)psig->data, psig->length);
++      lua_setfield(L, -2, "sig");
++    }
++  }
+ 
+   {
+     int l = 0;
+@@ -312,6 +621,17 @@ static LUA_FUNCTION(openssl_x509_free)
+   return 0;
+ }
+ 
++/***
++get public key of x509
++@function pubkey
++@treturn evp_pkey public key
++*/
++/***
++set public key of x509
++@function pubkey
++@tparam evp_pkey pubkey public key set to x509
++@treturn boolean result, true for success
++*/
+ static LUA_FUNCTION(openssl_x509_public_key)
+ {
+   X509 *cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -329,6 +649,7 @@ static LUA_FUNCTION(openssl_x509_public_
+   }
+ }
+ 
++#if 0
+ static int verify_cb(int ok, X509_STORE_CTX *ctx)
+ {
+   int err;
+@@ -360,14 +681,31 @@ static int verify_cb(int ok, X509_STORE_
+     return 1;
+   }
+ }
++#endif
+ 
++/***
++check x509 with ca certchian and option purpose
++purpose can be one of: ssl_client, ssl_server, ns_ssl_server, smime_sign, smime_encrypt, crl_sign, any, ocsp_helper, timestamp_sign
++@function check
++@tparam x509_store cacerts
++@tparam x509_store untrusted certs  containing a bunch of certs that are not trusted but may be useful in validating the certificate.
++@tparam[opt] string purpose to check supported
++@treturn boolean result true for check pass
++@treturn integer verify result
++@see verify_cert_error_string
++*/
++/***
++check x509 with evp_pkey
++@function check
++@tparam evp_pkey pkey private key witch match with x509 pubkey
++@treturn boolean result true for check pass
++*/
+ static LUA_FUNCTION(openssl_x509_check)
+ {
+   X509 * cert = CHECK_OBJECT(1, X509, "openssl.x509");
+-  if (auxiliar_isclass(L, "openssl.evp_pkey", 2))
++  if (auxiliar_getclassudata(L, "openssl.evp_pkey", 2))
+   {
+     EVP_PKEY * key = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+-    luaL_argcheck(L, openssl_pkey_is_private(key), 2, "must be private key");
+     lua_pushboolean(L, X509_check_private_key(cert, key));
+     return 1;
+   }
+@@ -375,8 +713,20 @@ static LUA_FUNCTION(openssl_x509_check)
+   {
+     X509_STORE* store = CHECK_OBJECT(2, X509_STORE, "openssl.x509_store");
+     STACK_OF(X509)* untrustedchain = lua_isnoneornil(L, 3) ?  NULL : openssl_sk_x509_fromtable(L, 3);
+-    int purpose = lua_isnone(L, 4) ? 0 : X509_PURPOSE_get_by_sname((char*)luaL_optstring(L, 4, "any"));
++    int purpose = 0;
+     int ret = 0;
++    if (!lua_isnone(L, 4))
++    {
++      int purpose_id = X509_PURPOSE_get_by_sname((char*)luaL_optstring(L, 4, "any"));
++      if (purpose_id >= 0)
++      {
++        X509_PURPOSE* ppurpose = X509_PURPOSE_get0(purpose_id);
++        if (ppurpose)
++        {
++          purpose = ppurpose->purpose;
++        }
++      }
++    }
+ #if 0
+     X509_STORE_set_verify_cb_func(store, verify_cb);
+ #endif
+@@ -388,8 +738,73 @@ static LUA_FUNCTION(openssl_x509_check)
+   }
+ }
+ 
++#if OPENSSL_VERSION_NUMBER > 0x10002000L
++/***
++check x509 for host (only for openssl 1.0.2 or greater)
++@function check_host
++@tparam string host hostname to check for match match with x509 subject
++@treturn boolean result true if host is present and matches the certificate
++*/
++static LUA_FUNCTION(openssl_x509_check_host)
++{
++  X509 * cert = CHECK_OBJECT(1, X509, "openssl.x509");
++  if (lua_isstring(L, 2))
++  {
++    const char *hostname = lua_tostring(L, 2);
++    lua_pushboolean(L, X509_check_host(cert, hostname, strlen(hostname), 0, NULL));
++  }
++  else
++  {
++    lua_pushboolean(L, 0);
++  }
++  return 1;
++}
++/***
++check x509 for email address (only for openssl 1.0.2 or greater)
++@tparam string email to check for match match with x509 subject
++@treturn boolean result true if host is present and matches the certificate
++@function check_email
++*/
++static LUA_FUNCTION(openssl_x509_check_email)
++{
++  X509 * cert = CHECK_OBJECT(1, X509, "openssl.x509");
++  if (lua_isstring(L, 2))
++  {
++    const char *email = lua_tostring(L, 2);
++    lua_pushboolean(L, X509_check_email(cert, email, strlen(email), 0));
++  }
++  else
++  {
++    lua_pushboolean(L, 0);
++  }
++  return 1;
++}
++
++/***
++check x509 for ip address (ipv4 or ipv6, only for openssl 1.0.2 or greater)
++@function check_ip_asc
++@tparam string ip to check for match match with x509 subject
++@treturn boolean result true if host is present and matches the certificate
++*/
++static LUA_FUNCTION(openssl_x509_check_ip_asc)
++{
++  X509 * cert = CHECK_OBJECT(1, X509, "openssl.x509");
++  if (lua_isstring(L, 2))
++  {
++    const char *ip_asc = lua_tostring(L, 2);
++    lua_pushboolean(L, X509_check_ip_asc(cert, ip_asc, 0));
++  }
++  else
++  {
++    lua_pushboolean(L, 0);
++  }
++  return 1;
++}
++#endif
++
+ IMP_LUA_SK(X509, x509)
+ 
++#if 0
+ static STACK_OF(X509) * load_all_certs_from_file(BIO *in)
+ {
+   STACK_OF(X509) *stack = sk_X509_new_null();
+@@ -417,7 +832,19 @@ static STACK_OF(X509) * load_all_certs_f
+   }
+   return stack;
+ };
++#endif
+ 
++/***
++get subject name of x509
++@function subject
++@treturn x509_name subject name
++*/
++/***
++set subject name of x509
++@function subject
++@tparam x509_name subject
++@treturn boolean result true for success
++*/
+ static int openssl_x509_subject(lua_State* L)
+ {
+   X509* cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -434,6 +861,19 @@ static int openssl_x509_subject(lua_Stat
+   }
+ }
+ 
++/***
++get issuer name of x509
++@function issuer
++@tparam[opt=false] boolean asobject, true for return as x509_name object, or as table
++@treturn[1] x509_name issuer
++@treturn[1] table issuer name as table
++*/
++/***
++set issuer name of x509
++@function issuer
++@tparam x509_name name
++@treturn boolean result true for success
++*/
+ static int openssl_x509_issuer(lua_State* L)
+ {
+   X509* cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -450,13 +890,19 @@ static int openssl_x509_issuer(lua_State
+   }
+ }
+ 
++/***
++get digest of x509 object
++@function digest
++@tparam[opt='sha1'] evp_digest|string md_alg, default use 'sha1'
++@treturn string digest result
++*/
+ static int openssl_x509_digest(lua_State* L)
+ {
+   unsigned int bytes;
+   unsigned char buffer[EVP_MAX_MD_SIZE];
+   char hex_buffer[EVP_MAX_MD_SIZE * 2];
+   X509 *cert = CHECK_OBJECT(1, X509, "openssl.x509");
+-  const EVP_MD *digest = lua_isnoneornil(L, 2) ? EVP_sha1() : get_digest(L, 2);
++  const EVP_MD *digest = get_digest(L, 2, "sha256");
+   int ret;
+   if (!digest)
+   {
+@@ -474,6 +920,16 @@ static int openssl_x509_digest(lua_State
+   return openssl_pushresult(L, ret);
+ };
+ 
++/***
++get notbefore valid time of x509
++@function notbefore
++@treturn string notbefore time string
++*/
++/***
++set notbefore valid time of x509
++@function notbefore
++@tparam string|number notbefore
++*/
+ static int openssl_x509_notbefore(lua_State *L)
+ {
+   X509* cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -491,7 +947,7 @@ static int openssl_x509_notbefore(lua_St
+       at = ASN1_TIME_new();
+       ASN1_TIME_set(at, time);
+     }
+-    if (lua_isstring(L, 2))
++    else if (lua_isstring(L, 2))
+     {
+       const char* time = lua_tostring(L, 2);
+       at = ASN1_TIME_new();
+@@ -504,6 +960,7 @@ static int openssl_x509_notbefore(lua_St
+     if (at)
+     {
+       ret = X509_set_notBefore(cert, at);
++      ASN1_TIME_free(at);
+     }
+     else
+       ret = 0;
+@@ -511,6 +968,16 @@ static int openssl_x509_notbefore(lua_St
+   };
+ }
+ 
++/***
++get notafter valid time of x509
++@function notafter
++@treturn string notafter time string
++*/
++/***
++set notafter valid time of x509
++@function notafter
++@tparam string|number notafter
++*/
+ static int openssl_x509_notafter(lua_State *L)
+ {
+   X509* cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -528,7 +995,7 @@ static int openssl_x509_notafter(lua_Sta
+       at = ASN1_TIME_new();
+       ASN1_TIME_set(at, time);
+     }
+-    if (lua_isstring(L, 2))
++    else if (lua_isstring(L, 2))
+     {
+       const char* time = lua_tostring(L, 2);
+       at = ASN1_TIME_new();
+@@ -541,6 +1008,7 @@ static int openssl_x509_notafter(lua_Sta
+     if (at)
+     {
+       ret = X509_set_notAfter(cert, at);
++      ASN1_TIME_free(at);
+     }
+     else
+       ret = 0;
+@@ -548,6 +1016,21 @@ static int openssl_x509_notafter(lua_Sta
+   }
+ }
+ 
++/***
++check x509 valid
++@function validat
++@tparam[opt] number time, default will use now time
++@treturn boolean result true for valid, or for invalid
++@treturn string notbefore
++@treturn string notafter
++*/
++/***
++set valid time, notbefore and notafter
++@function validat
++@tparam number notbefore
++@tparam number notafter
++@treturn boolean result, true for success
++*/
+ static int openssl_x509_valid_at(lua_State* L)
+ {
+   X509* cert = CHECK_OBJECT(1, X509, "openssl.x509");
+@@ -595,42 +1078,76 @@ static int openssl_x509_valid_at(lua_Sta
+   return 0;
+ }
+ 
++/***
++get serial number of x509
++@function serial
++@tparam[opt=true] boolean asobject
++@treturn[1] bn object
++@treturn[2] string result
++*/
++/***
++set serial number of x509
++@function serial
++@tparam string|number|bn serail
++@treturn boolean result true for success
++*/
+ static int openssl_x509_serial(lua_State *L)
+ {
+-  BIGNUM *bn;
+-  ASN1_INTEGER *serial;
+   X509* cert = CHECK_OBJECT(1, X509, "openssl.x509");
+-
+-  if (lua_isnone(L, 2) || lua_isboolean(L, 2))
++  ASN1_INTEGER *serial = X509_get_serialNumber(cert);
++  if (lua_isboolean(L, 2))
+   {
+-    int asobj = lua_isnone(L, 2) ? 0 : lua_toboolean(L, 2);
+-    serial = X509_get_serialNumber(cert);
+-    bn = ASN1_INTEGER_to_BN(serial, NULL);
++    int asobj = lua_toboolean(L, 2);
+     if (asobj)
+     {
+-      PUSH_OBJECT(bn, "openssl.bn");
++      PUSH_ASN1_INTEGER(L, serial);
+     }
+     else
+     {
+-      char *tmp = BN_bn2hex(bn);
+-      lua_pushstring(L, tmp);
+-      BN_free(bn);
+-      OPENSSL_free(tmp);
++      BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
++      PUSH_OBJECT(bn, "openssl.bn");
+     }
+-    return 1;
++  }
++  else if (lua_isnone(L, 2))
++  {
++    BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
++    char *tmp = BN_bn2hex(bn);
++    lua_pushstring(L, tmp);
++    OPENSSL_free(tmp);
++    BN_free(bn);
+   }
+   else
+   {
+     int ret;
+-    bn = BN_get(L, 2);
+-    serial = BN_to_ASN1_INTEGER(bn, NULL);
+-    BN_free(bn);
++    if (auxiliar_getclassudata(L, "openssl.asn1_string", 2))
++    {
++      serial = CHECK_OBJECT(2, ASN1_STRING, "openssl.asn1_string");
++    }
++    else
++    {
++      BIGNUM *bn = BN_get(L, 2);
++      serial = BN_to_ASN1_INTEGER(bn, NULL);
++      BN_free(bn);
++    }
++    luaL_argcheck(L, serial != NULL, 2, "not accept");
+     ret = X509_set_serialNumber(cert, serial);
+     ASN1_INTEGER_free(serial);
+     return openssl_pushresult(L, ret);
+   }
++  return 1;
+ }
+ 
++/***
++get version number of x509
++@function version
++@treturn number version of x509
++*/
++/***
++set version number of x509
++@function version
++@tparam number version
++@treturn boolean result true for result
++*/
+ static int openssl_x509_version(lua_State *L)
+ {
+   int version;
+@@ -650,12 +1167,25 @@ static int openssl_x509_version(lua_Stat
+   }
+ }
+ 
++/***
++get extensions of x509 object
++@function extensions
++@tparam[opt=false] boolean asobject, true for return as stack_of_x509_extension or as table
++@treturn[1] stack_of_x509_extension object when param set true
++@treturn[2] table contain all x509_extension when param set false or nothing
++*/
++/***
++set extension of x509 object
++@function extensions
++@tparam stack_of_x509_extension extensions
++@treturn boolean result true for success
++*/
+ static int openssl_x509_extensions(lua_State* L)
+ {
+-  X509 *peer = CHECK_OBJECT(1, X509, "openssl.x509");
++  X509 *self = CHECK_OBJECT(1, X509, "openssl.x509");
++  STACK_OF(X509_EXTENSION) *exts = (STACK_OF(X509_EXTENSION) *)X509_get0_extensions(self);
+   if (lua_isnone(L, 2))
+   {
+-    STACK_OF(X509_EXTENSION) *exts = peer->cert_info->extensions;
+     if (exts)
+     {
+       openssl_sk_x509_extension_totable(L, exts);
+@@ -666,89 +1196,45 @@ static int openssl_x509_extensions(lua_S
+   }
+   else
+   {
+-    STACK_OF(X509_EXTENSION) *exts = openssl_sk_x509_extension_fromtable(L, 2);
+-    sk_X509_EXTENSION_pop_free(peer->cert_info->extensions, X509_EXTENSION_free);
+-    peer->cert_info->extensions = exts;
++    STACK_OF(X509_EXTENSION) *others = (STACK_OF(X509_EXTENSION) *)openssl_sk_x509_extension_fromtable(L, 2);
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++    sk_X509_EXTENSION_pop_free(self->cert_info->extensions, X509_EXTENSION_free);
++    self->cert_info->extensions = others;
++#else
++    int i;
++    int n = sk_X509_EXTENSION_num(exts);
++    for (i = 0; i < n; i++)
++      sk_X509_EXTENSION_delete(exts, i);
++    n = sk_X509_EXTENSION_num(others);
++    for (i = 0; i < n; i++)
++    {
++      X509_EXTENSION* ext = sk_X509_EXTENSION_value(others, i);
++      if (exts!=NULL)
++        sk_X509_EXTENSION_push(exts, ext);
++      else
++        X509_add_ext(self, ext, -1);
++    }
++    sk_X509_EXTENSION_free(others);
++#endif
+     return openssl_pushresult(L, 1);
+   }
+ }
+ 
+-static int openssl_x509_new(lua_State* L)
+-{
+-  int i = 1;
+-  int ret = 1;
+-  int n = lua_gettop(L);
+-  X509 *x = X509_new();
+-
+-  ret = X509_set_version(x, 2);
+-  if (ret == 1 && (
+-        auxiliar_isclass(L, "openssl.bn", i) ||
+-        lua_isstring(L, i) || lua_isnumber(L, i)
+-      ))
+-  {
+-    BIGNUM *bn = BN_get(L, i);
+-    ASN1_INTEGER* ai = BN_to_ASN1_INTEGER(bn, NULL);
+-    BN_free(bn);
+-    ret = X509_set_serialNumber(x, ai);
+-    ASN1_INTEGER_free(ai);
+-    i++;
+-  }
+-
+-  for (; i <= n; i++)
+-  {
+-    if (ret == 1 && auxiliar_isclass(L, "openssl.x509_req", i))
+-    {
+-      X509_REQ* csr = CHECK_OBJECT(i, X509_REQ, "openssl.x509_req");
+-      X509_NAME* xn = X509_REQ_get_subject_name(csr);
+-      ret = X509_set_subject_name(x, xn);
+-
+-      if (ret == 1)
+-      {
+-        STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(csr);
+-        int j, n1;
+-        n1 = sk_X509_EXTENSION_num(exts);
+-        for (j = 0; ret == 1 && j < n1; j++)
+-        {
+-          ret = X509_add_ext(x, sk_X509_EXTENSION_value(exts, j), j);
+-        }
+-        sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+-      }
+-      if (ret == 1)
+-      {
+-        EVP_PKEY* pkey = X509_REQ_get_pubkey(csr);
+-        ret = X509_set_pubkey(x, pkey);
+-        EVP_PKEY_free(pkey);
+-      }
+-      i++;
+-    };
+-
+-    if (ret == 1 && auxiliar_isclass(L, "openssl.x509_name", i))
+-    {
+-      X509_NAME *xn = CHECK_OBJECT(i, X509_NAME, "openssl.x509_name");
+-      ret = X509_set_subject_name(x, xn);
+-      i++;
+-    }
+-  }
+-
+-  if (ret == 1)
+-  {
+-    PUSH_OBJECT(x, "openssl.x509");
+-    return 1;
+-  }
+-  else
+-  {
+-    X509_free(x);
+-    return openssl_pushresult(L, ret);
+-  }
+-};
+-
++/***
++sign x509
++@function sign
++@tparam evp_pkey pkey private key to sign x509
++@tparam x509|x509_name cacert or cacert x509_name
++@tparam[opt='sha1WithRSAEncryption'] string|md_digest md_alg
++@treturn boolean result true for check pass
++*/
+ static int openssl_x509_sign(lua_State*L)
+ {
+   X509* x = CHECK_OBJECT(1, X509, "openssl.x509");
+-  if (lua_isnoneornil(L, 2) && x->cert_info != NULL)
++  if (lua_isnoneornil(L, 2))
+   {
+     unsigned char *out = NULL;
+-    int len = i2d_X509_CINF(x->cert_info, &out);
++    int len = i2d_re_X509_tbs(x, &out);
+     if (len > 0)
+     {
+       lua_pushlstring(L, (const char *)out, len);
+@@ -757,14 +1243,13 @@ static int openssl_x509_sign(lua_State*L
+     }
+     return openssl_pushresult(L, len);
+   }
+-  else if (auxiliar_isclass(L, "openssl.evp_pkey", 2))
++  else if (auxiliar_getclassudata(L, "openssl.evp_pkey", 2))
+   {
+     EVP_PKEY* pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
+     const EVP_MD *md;
+     int ret = 1;
+     int i = 3;
+-    luaL_argcheck(L, openssl_pkey_is_private(pkey), 2, "must be private key");
+-    if (auxiliar_isclass(L, "openssl.x509_name", 3))
++    if (auxiliar_getclassudata(L, "openssl.x509_name", 3))
+     {
+       X509_NAME* xn = CHECK_OBJECT(3, X509_NAME, "openssl.x509_name");
+       ret = X509_set_issuer_name(x, xn);
+@@ -784,9 +1269,7 @@ static int openssl_x509_sign(lua_State*L
+ 
+     if (ret == 1)
+     {
+-      md = lua_isnoneornil(L, i) ?
+-           EVP_get_digestbyname("sha1") :
+-           get_digest(L, i);
++      md = get_digest(L, i, "sha256");
+       ret = X509_sign(x, pkey, md);
+       if (ret > 0)
+         ret = 1;
+@@ -798,11 +1281,16 @@ static int openssl_x509_sign(lua_State*L
+     size_t sig_len;
+     const char* sig = luaL_checklstring(L, 2, &sig_len);
+     int nid = openssl_get_nid(L, 3);
+-    int ret = ASN1_BIT_STRING_set(x->signature, (unsigned char*)sig, (int)sig_len);
++    CONSTIFY_X509_get0 ASN1_BIT_STRING *psig = NULL;
++    CONSTIFY_X509_get0 X509_ALGOR *palg = NULL;
++    int ret;
++
++    X509_get0_signature(&psig, &palg, x);
++    ret = ASN1_BIT_STRING_set((ASN1_BIT_STRING*)psig, (unsigned char*)sig, (int)sig_len);
+     if (ret == 1)
+     {
+       ASN1_OBJECT *obj = OBJ_nid2obj(nid);
+-      ret = X509_ALGOR_set0(x->sig_alg, obj, V_ASN1_UNDEF, NULL);
++      ret = X509_ALGOR_set0((X509_ALGOR*)palg, obj, V_ASN1_UNDEF, NULL);
+     }
+     return openssl_pushresult(L, ret);
+   }
+@@ -811,22 +1299,31 @@ static int openssl_x509_sign(lua_State*L
+ static int openssl_x509_verify(lua_State*L)
+ {
+   X509* x = CHECK_OBJECT(1, X509, "openssl.x509");
+-  if (lua_isnoneornil(L, 2) && x->cert_info != NULL)
++  if (lua_isnoneornil(L, 2))
+   {
+     unsigned char *out = NULL;
+-    int len = i2d_X509_CINF(x->cert_info, &out);
++    int len = i2d_re_X509_tbs(x, &out);
+     if (len > 0)
+     {
++      CONSTIFY_X509_get0 ASN1_BIT_STRING *psig = NULL;
++      CONSTIFY_X509_get0 X509_ALGOR *palg = NULL;
++
+       lua_pushlstring(L, (const char *)out, len);
+       OPENSSL_free(out);
+-      if (x->signature != NULL)
++
++      X509_get0_signature(&psig, &palg, x);
++      if (psig != NULL)
+       {
+-        lua_pushlstring(L, (const char *)x->signature->data, x->signature->length);
++        lua_pushlstring(L, (const char *)psig->data, psig->length);
+       }
+       else
+         lua_pushnil(L);
+-      if (x->sig_alg)
+-        openssl_push_x509_algor(L, x->sig_alg);
++
++      if (palg)
++      {
++        X509_ALGOR *alg = X509_ALGOR_dup((X509_ALGOR *)palg);
++        PUSH_OBJECT(alg, "openssl.x509_algor");
++      }
+       else
+         lua_pushnil(L);
+       return 3;
+@@ -846,6 +1343,11 @@ static luaL_Reg x509_funcs[] =
+   {"parse",       openssl_x509_parse},
+   {"export",      openssl_x509_export},
+   {"check",       openssl_x509_check},
++#if OPENSSL_VERSION_NUMBER > 0x10002000L
++  {"check_host",  openssl_x509_check_host},
++  {"check_email", openssl_x509_check_email},
++  {"check_ip_asc", openssl_x509_check_ip_asc},
++#endif
+   {"pubkey",      openssl_x509_public_key},
+   {"version",     openssl_x509_version},
+ 
+@@ -868,181 +1370,6 @@ static luaL_Reg x509_funcs[] =
+   {NULL,      NULL},
+ };
+ 
+-
+-static int openssl_push_purpose(lua_State*L , X509_PURPOSE* purpose)
+-{
+-  lua_newtable(L);
+-
+-  AUXILIAR_SET(L, -1, "purpose", purpose->purpose, integer);
+-  AUXILIAR_SET(L, -1, "trust", purpose->trust, integer);
+-  AUXILIAR_SET(L, -1, "flags", purpose->flags, integer);
+-
+-  AUXILIAR_SET(L, -1, "name", purpose->name, string);
+-  AUXILIAR_SET(L, -1, "sname", purpose->sname, string);
+-
+-  return 1;
+-};
+-
+-static int openssl_x509_purpose(lua_State*L)
+-{
+-  if (lua_isnoneornil(L, 1))
+-  {
+-    int count = X509_PURPOSE_get_count();
+-    int i;
+-    lua_newtable(L);
+-    for (i = 0; i < count; i++)
+-    {
+-      X509_PURPOSE* purpose = X509_PURPOSE_get0(i);
+-      openssl_push_purpose(L, purpose);
+-      lua_rawseti(L, -2, i + 1);
+-    }
+-    return 1;
+-  }
+-  else if (lua_isnumber(L, 1))
+-  {
+-    int idx = X509_PURPOSE_get_by_id(lua_tointeger(L, 1));
+-    if (idx >= 0)
+-    {
+-      X509_PURPOSE* purpose = X509_PURPOSE_get0(idx);
+-      openssl_push_purpose(L, purpose);
+-    }
+-    else
+-      lua_pushnil(L);
+-    return 1;
+-  }
+-  else if (lua_isstring(L, 1))
+-  {
+-    char* name = (char*)lua_tostring(L, 1);
+-    int idx = X509_PURPOSE_get_by_sname(name);
+-    if (idx >= 0)
+-    {
+-      X509_PURPOSE* purpose = X509_PURPOSE_get0(idx);
+-      openssl_push_purpose(L, purpose);
+-    }
+-    else
+-      lua_pushnil(L);
+-    return 1;
+-  }
+-  return 0;
+-};
+-
+-static const char* usage_mode[] =
+-{
+-  "standard",
+-  "netscape",
+-  "extend",
+-  NULL
+-};
+-
+-static int openssl_x509_certtypes(lua_State*L)
+-{
+-  int mode = luaL_checkoption(L, 1, "standard", usage_mode);
+-  int i;
+-  const BIT_STRING_BITNAME* bitname;
+-
+-  switch (mode)
+-  {
+-  case 0:
+-  {
+-    const static BIT_STRING_BITNAME key_usage_type_table[] =
+-    {
+-      {0, "Digital Signature", "digitalSignature"},
+-      {1, "Non Repudiation", "nonRepudiation"},
+-      {2, "Key Encipherment", "keyEncipherment"},
+-      {3, "Data Encipherment", "dataEncipherment"},
+-      {4, "Key Agreement", "keyAgreement"},
+-      {5, "Certificate Sign", "keyCertSign"},
+-      {6, "CRL Sign", "cRLSign"},
+-      {7, "Encipher Only", "encipherOnly"},
+-      {8, "Decipher Only", "decipherOnly"},
+-      { -1, NULL, NULL}
+-    };
+-    lua_newtable(L);
+-    for (i = 0, bitname = &key_usage_type_table[i]; bitname->bitnum != -1; i++, bitname = &key_usage_type_table[i])
+-    {
+-      openssl_push_bit_string_bitname(L, bitname);
+-      lua_rawseti(L, -2, i + 1);
+-    }
+-    return 1;
+-
+-  }
+-  case 1:
+-  {
+-    const static BIT_STRING_BITNAME ns_cert_type_table[] =
+-    {
+-      {0, "SSL Client", "client"},
+-      {1, "SSL Server", "server"},
+-      {2, "S/MIME", "email"},
+-      {3, "Object Signing", "objsign"},
+-      {4, "Unused", "reserved"},
+-      {5, "SSL CA", "sslCA"},
+-      {6, "S/MIME CA", "emailCA"},
+-      {7, "Object Signing CA", "objCA"},
+-      { -1, NULL, NULL}
+-    };
+-    lua_newtable(L);
+-    for (i = 0, bitname = &ns_cert_type_table[i]; bitname->bitnum != -1; i++, bitname = &ns_cert_type_table[i])
+-    {
+-      openssl_push_bit_string_bitname(L, bitname);
+-      lua_rawseti(L, -2, i + 1);
+-    }
+-    return 1;
+-  }
+-  case 2:
+-  {
+-    static const int ext_nids[] =
+-    {
+-      NID_server_auth,
+-      NID_client_auth,
+-      NID_email_protect,
+-      NID_code_sign,
+-      NID_ms_sgc,
+-      NID_ns_sgc,
+-      NID_OCSP_sign,
+-      NID_time_stamp,
+-      NID_dvcs,
+-      NID_anyExtendedKeyUsage
+-    };
+-    int count = sizeof(ext_nids) / sizeof(int);
+-    int nid;
+-    lua_newtable(L);
+-    for (i = 0; i < count; i++)
+-    {
+-      nid = ext_nids[i];
+-      lua_newtable(L);
+-      lua_pushstring(L, OBJ_nid2ln(nid));
+-      lua_setfield(L, -2, "lname");
+-      lua_pushstring(L, OBJ_nid2sn(nid));
+-      lua_setfield(L, -2, "sname");
+-      lua_pushinteger(L, nid);
+-      lua_setfield(L, -2, "nid");
+-      lua_rawseti(L, -2, i + 1);
+-    };
+-    return 1;
+-  }
+-  }
+-  return 0;
+-}
+-
+-static int openssl_verify_cert_error_string(lua_State*L)
+-{
+-  int v = luaL_checkint(L, 1);
+-  const char*s = X509_verify_cert_error_string(v);
+-  lua_pushstring(L, s);
+-  return 1;
+-}
+-
+-static luaL_Reg R[] =
+-{
+-  {"new",           openssl_x509_new },
+-  {"read",          openssl_x509_read },
+-  {"purpose",       openssl_x509_purpose },
+-  {"certtypes",     openssl_x509_certtypes },
+-  {"verify_cert_error_string", openssl_verify_cert_error_string },
+-
+-  {NULL,    NULL}
+-};
+-
+ int luaopen_x509(lua_State *L)
+ {
+   auxiliar_newclass(L, "openssl.x509", x509_funcs);
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/xalgor.c luvi-src-v2.7.6/deps/lua-openssl/src/xalgor.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/xalgor.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/xalgor.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,10 +1,11 @@
+-/*=========================================================================*\
+-* xalgor.c
+-* * x509_algor routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
+-
++/***
++x509.algor module for lua-openssl binding, Provide X509_ALGOR as lua object.
++Sometime when you make CSR,TS or X509, you maybe need to use this.
++
++@module x509.algor
++@usage
++  algor = require('openssl').x509.algor
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #include "sk.h"
+@@ -12,19 +13,44 @@ IMP_LUA_SK(X509_ALGOR, x509_algor)
+ 
+ #define MYNAME "x509.algor"
+ 
+-void openssl_xalgor_free(X509_ALGOR* alg)
++/***
++Create x509_algor object
++
++@function new
++@treturn x509_algor mapping to X509_ALGOR in openssl
++*/
++
++static int openssl_xalgor_new(lua_State*L)
+ {
+-  X509_ALGOR_free(alg);
+-}
++  X509_ALGOR* alg = X509_ALGOR_new();
++  PUSH_OBJECT(alg, "openssl.x509_algor");
++  return 1;
++};
+ 
++static luaL_Reg R[] =
++{
++  {"new",           openssl_xalgor_new},
+ 
++  {NULL,          NULL},
++};
++
++/***
++openssl.x509_algor object
++@type x509_algor
++*/
+ static int openssl_xalgor_gc(lua_State* L)
+ {
+   X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
+-  openssl_xalgor_free(alg);
++  X509_ALGOR_free(alg);
+   return 0;
+ }
+ 
++/***
++clone the x509_algor
++
++@function dup
++@treturn x509_algor clone of x509_algor
++*/
+ static int openssl_xalgor_dup(lua_State* L)
+ {
+   X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
+@@ -34,6 +60,11 @@ static int openssl_xalgor_dup(lua_State*
+ }
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x10002000L
++/***
++compare with other x509_algor object
++@function equals
++@treturn boolean return true if two x509_algor equals
++*/
+ static int openssl_xalgor_cmp(lua_State* L)
+ {
+   X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
+@@ -44,28 +75,38 @@ static int openssl_xalgor_cmp(lua_State*
+ #endif
+ 
+ #if OPENSSL_VERSION_NUMBER >= 0x10001000L
++/***
++set message digest object to x509_algor
++@function md
++@tparam number|string|evp_md md
++*/
+ static int openssl_xalgor_md(lua_State* L)
+ {
+   X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
+-  const EVP_MD* md = get_digest(L, 2);
++  const EVP_MD* md = get_digest(L, 2, NULL);
+   X509_ALGOR_set_md(alg, md);
+   return 0;
+ }
+ #endif
+ 
++/***
++get x509_algor properties
++@function get
++@tparam asn1_object ident algorithm, nil for fail
++@tparam asn1_string attached paramater value
++*/
+ static int openssl_xalgor_get(lua_State* L)
+ {
+   int type;
+-  void* val;
+-  ASN1_OBJECT *obj, *dup;
++  CONSTIFY_X509_get0 void* val;
++  CONSTIFY_X509_get0 ASN1_OBJECT *obj;
+ 
+-  X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
++  CONSTIFY_X509_get0 X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
+ 
+   X509_ALGOR_get0(&obj, &type, &val, alg);
+   if (obj != NULL)
+   {
+-    dup = OBJ_dup(obj);
+-    PUSH_OBJECT(dup, "openssl.asn1_object");
++    openssl_push_asn1object(L, obj);
+   }
+   else
+     lua_pushnil(L);
+@@ -73,33 +114,50 @@ static int openssl_xalgor_get(lua_State*
+     lua_pushnil(L);
+   else
+   {
+-    ASN1_STRING *s = ASN1_STRING_dup(val);
+-    PUSH_OBJECT(s, "openssl.asn1_string");
++    PUSH_ASN1_STRING(L, val);
+   }
+ 
+   return 2;
+ }
+ 
++/***
++set x509_algor properties
++@function set
++@tparam asn1_object obj ident algorithm in openssl
++@tparam[opt] asn1_string val attached paramater value
++@treturn boolean result true for success, others for fail
++*/
++/***
++set digest algorithm, alias of set()
++only when OPENSSL_VERSION_NUMBER >= 0x10001000
++@function set
++@tparam string|evp_digest digest algorithm
++*/
+ static int openssl_xalgor_set(lua_State* L)
+ {
+   int ret = 0;
+   X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
+   ASN1_OBJECT* obj = CHECK_OBJECT(2, ASN1_OBJECT, "openssl.asn1_object");
+   ASN1_STRING* val = lua_isnoneornil(L, 3) ?
+-                     NULL : auxiliar_checkgroup(L, "openssl.asn1_group", 3);
++                     NULL : auxiliar_checkgroup(L, "openssl.asn1_string", 3);
+   obj = OBJ_dup(obj);
+   val = ASN1_STRING_dup(val);
+-  ret = X509_ALGOR_set0(alg, obj , val->type, val);
++  ret = X509_ALGOR_set0(alg, obj, val->type, val);
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++convert x509_algor to txt string of asn1_object
++@function tostring
++@tparam string txt of asn1_object
++*/
+ static int openssl_xalgor_tostring(lua_State* L)
+ {
+   int type;
+-  void* val;
+-  ASN1_OBJECT *obj;
++  CONSTIFY_X509_get0 void* val;
++  CONSTIFY_X509_get0 ASN1_OBJECT *obj;
+ 
+-  X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
++  CONSTIFY_X509_get0 X509_ALGOR* alg = CHECK_OBJECT(1, X509_ALGOR, "openssl.x509_algor");
+ 
+   X509_ALGOR_get0(&obj, &type, &val, alg);
+   if (obj != NULL)
+@@ -114,6 +172,15 @@ static int openssl_xalgor_tostring(lua_S
+   return 0;
+ }
+ 
++/***
++check with other x509_algor whether equals, alias with == operator
++only when OPENSSL_VERSION_NUMBER >= 0x10002000L
++
++@function equals
++@tparam x509_algor other to compare
++*/
++
++
+ static luaL_Reg xalgor_funcs[] =
+ {
+   {"dup",               openssl_xalgor_dup},
+@@ -132,20 +199,6 @@ static luaL_Reg xalgor_funcs[] =
+ 
+   {NULL,          NULL},
+ };
+-
+-static int openssl_xalgor_new(lua_State*L)
+-{
+-  X509_ALGOR* alg = X509_ALGOR_new();
+-  PUSH_OBJECT(alg, "openssl.x509_algor");
+-  return 1;
+-};
+-
+-static luaL_Reg R[] =
+-{
+-  {"new",           openssl_xalgor_new},
+-
+-  {NULL,          NULL},
+-};
+ 
+ int openssl_register_xalgor(lua_State*L)
+ {
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/xattrs.c luvi-src-v2.7.6/deps/lua-openssl/src/xattrs.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/xattrs.c	2019-02-13 11:31:40.327301704 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/xattrs.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,49 +1,145 @@
+-/*=========================================================================*\
+-* xattrs.c
+-* x509 attributes routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
+-
++/***
++x509 attributes module for lua-openssl binding, Provide x509_attribute as lua object.
++Sometime when you make CSR,TS or X509, you maybe need to use this.
++
++@module x509.attr
++@usage
++  attr = require('openssl').x509.attr
++*/
+ #include "openssl.h"
+ #include "private.h"
+ #include "sk.h"
+ 
+ #define MYNAME "x509.attribute"
+ 
++/***
++x509_attribute contrust param table.
++
++@table x509_attribute_param_table
++@tfield string|integer|asn1_object object, identify a asn1_object
++@tfield string|integer type, same with type in asn1.new_string
++@tfield string|asn1_object value, value of attribute
++
++@usage
++xattr = x509.attribute.new_attribute {
++  object = asn1_object,
++  type = Nid_or_String,
++  value = string or asn1_string value
++}
++*/
++
++/***
++asn1_type object as table
++
++@table asn1_type_table
++@tfield string value, value data
++@tfield string type, type of value
++@tfield string format, value is 'der', only exist when type is not in 'bit','bmp','octet'
++*/
++
++/***
++Create x509_attribute object
++
++@function new_attribute
++@tparam table attribute with object, type and value
++@treturn[1] x509_attribute mapping to X509_ATTRIBUTE in openssl
++
++@see x509_attribute_param_table
++*/
++static int openssl_xattr_new(lua_State*L)
++{
++  X509_ATTRIBUTE *x = NULL;
++  luaL_checktable(L, 1);
++
++  x = openssl_new_xattribute(L, &x, 1, NULL);
++  PUSH_OBJECT(x, "openssl.x509_attribute");
++  return 1;
++}
++
++static luaL_Reg R[] =
++{
++  {"new_attribute",         openssl_xattr_new},
++
++  {NULL,          NULL},
++};
++
++/***
++x509_attribute infomation table
++
++@table x509_attribute_info_table
++@tfield asn1_object|object object of asn1_object
++@tfield boolean single  true for single value
++@tfield table value  if single, value is asn1_type or array have asn1_type node table
++*/
+ static int openssl_xattr_totable(lua_State*L, X509_ATTRIBUTE *attr)
+ {
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+   lua_newtable(L);
+   openssl_push_asn1object(L, attr->object);
+   lua_setfield(L, -2, "object");
+ 
+-  AUXILIAR_SET(L, -1, "single", attr->single, boolean);
++  lua_newtable(L);
+   if (attr->single)
+   {
+     openssl_push_asn1type(L, attr->value.single);
+-    lua_setfield(L, -2, "value");
++    lua_rawseti(L, -2, 1);
+   }
+   else
+   {
+     int i;
+-    lua_newtable(L);
+     for (i = 0; i < sk_ASN1_TYPE_num(attr->value.set); i++)
+     {
+       ASN1_TYPE* t = sk_ASN1_TYPE_value(attr->value.set, i);
+       openssl_push_asn1type(L, t);
+       lua_rawseti(L, -2, i + 1);
+     }
+-    lua_setfield(L, -2, "value");
+   }
++  lua_setfield(L, -2, "value");
+   return 1;
++#else
++  int i, c;
++
++  lua_newtable(L);
++  openssl_push_asn1object(L, X509_ATTRIBUTE_get0_object(attr));
++  lua_setfield(L, -2, "object");
++
++  c = X509_ATTRIBUTE_count(attr);
++  lua_newtable(L);
++  for (i = 0; i < c; i++)
++  {
++    ASN1_TYPE* t = X509_ATTRIBUTE_get0_type(attr, i);
++    openssl_push_asn1type(L, t);
++    lua_rawseti(L, -2, i + 1);
++  }
++  lua_setfield(L, -2, "value");
++  return 1;
++#endif
+ }
+ 
++/***
++openssl.x509_attribute object
++@type x509_attribute
++*/
++
++/***
++get infomation table of x509_attribute.
++
++@function info
++@treturn[1] table info,  x509_attribute infomation as table
++@see x509_attribute_info_table
++*/
+ static int openssl_xattr_info(lua_State*L)
+ {
+   X509_ATTRIBUTE* attr = CHECK_OBJECT(1, X509_ATTRIBUTE, "openssl.x509_attribute");
+   return openssl_xattr_totable(L, attr);
+ }
+ 
++/***
++clone then asn1_attribute
++
++@function dup
++@treturn x509_attribute attr clone of x509_attribute
++*/
+ static int openssl_xattr_dup(lua_State*L)
+ {
+   X509_ATTRIBUTE* attr = CHECK_OBJECT(1, X509_ATTRIBUTE, "openssl.x509_attribute");
+@@ -59,6 +155,22 @@ static int openssl_xattr_free(lua_State*
+   return 0;
+ }
+ 
++/***
++get type of x509_attribute
++
++@function data
++@tparam integer idx location want to get type
++@tparam string attrtype attribute type
++@treturn asn1_string
++*/
++/***
++set type of x509_attribute
++
++@function data
++@tparam string attrtype attribute type
++@tparam string data set to asn1_attr
++@treturn boolean result true for success and others for fail
++*/
+ static int openssl_xattr_data(lua_State*L)
+ {
+   X509_ATTRIBUTE* attr = CHECK_OBJECT(1, X509_ATTRIBUTE, "openssl.x509_attribute");
+@@ -68,12 +180,14 @@ static int openssl_xattr_data(lua_State*
+     size_t size;
+     int ret;
+     const char *data = luaL_checklstring(L, 3, &size);
+-    if (attr->single)
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++    if (X509_ATTRIBUTE_count(attr) == 1)
+       ASN1_TYPE_free((ASN1_TYPE*)attr->value.ptr);
+     else
+       sk_ASN1_TYPE_pop_free(attr->value.set, ASN1_TYPE_free);
+     attr->value.ptr = NULL;
+-
++#else
++#endif
+     ret = X509_ATTRIBUTE_set1_data(attr, attrtype, data, size);
+     return openssl_pushresult(L, ret);
+   }
+@@ -82,12 +196,20 @@ static int openssl_xattr_data(lua_State*
+     int idx = luaL_checkint(L, 2);
+     int attrtype = luaL_checkint(L, 3);
+     ASN1_STRING *as = (ASN1_STRING *)X509_ATTRIBUTE_get0_data(attr, idx, attrtype, NULL);
+-    as = ASN1_STRING_dup(as);
+-    PUSH_OBJECT(as, "openssl.asn1_string");
++    PUSH_ASN1_STRING(L, as);
+     return 1;
+   }
+ }
+ 
++/***
++get type of x509_attribute.
++
++@function type
++@tparam[opt] integer location which location to get type, default is 0
++@treturn table asn1_type, asn1_type as table info
++@treturn nil nil, fail return nothing
++@see asn1_type_table
++*/
+ static int openssl_xattr_type(lua_State*L)
+ {
+   X509_ATTRIBUTE* attr = CHECK_OBJECT(1, X509_ATTRIBUTE, "openssl.x509_attribute");
+@@ -103,14 +225,27 @@ static int openssl_xattr_type(lua_State*
+   return 1;
+ }
+ 
++/***
++get asn1_object of x509_attribute.
++
++@function object
++@treturn asn1_object object of x509_attribute
++*/
++/***
++set asn1_object for x509_attribute.
++
++@function object
++@tparam asn1_object obj
++@treturn boolean true for success
++@return nil when occure error, and followed by error message
++*/
+ static int openssl_xattr_object(lua_State*L)
+ {
+   X509_ATTRIBUTE* attr = CHECK_OBJECT(1, X509_ATTRIBUTE, "openssl.x509_attribute");
+   if (lua_isnone(L, 2))
+   {
+     ASN1_OBJECT* obj = X509_ATTRIBUTE_get0_object(attr);
+-    obj = OBJ_dup(obj);
+-    PUSH_OBJECT(obj, "openssl.asn1_object");
++    openssl_push_asn1object(L, obj);
+     return 1;
+   }
+   else
+@@ -146,6 +281,7 @@ X509_ATTRIBUTE* openssl_new_xattribute(l
+   size_t len = 0;
+   int nid;
+   const char* data = NULL;
++  ASN1_STRING *s = NULL;
+ 
+   lua_getfield(L, idx, "object");
+   nid = openssl_get_nid(L, -1);
+@@ -178,18 +314,17 @@ X509_ATTRIBUTE* openssl_new_xattribute(l
+   {
+     data = lua_tolstring(L, -1, &len);
+   }
+-  else if (auxiliar_isgroup(L, "openssl.asn1group", -1))
++  else if ((s = GET_GROUP(-1, ASN1_STRING, "openssl.asn1group")) != NULL)
+   {
+-    ASN1_STRING* value = CHECK_GROUP(-1, ASN1_STRING, "openssl.asn1group");
+-    if (ASN1_STRING_type(value) != arttype)
++    if (ASN1_STRING_type(s) != arttype)
+     {
+       if (eprefix)
+         luaL_error(L, "%s field value not match type", eprefix);
+       else
+-        luaL_argcheck(L, ASN1_STRING_type(value) == arttype, idx, "field value not match type");
++        luaL_argcheck(L, ASN1_STRING_type(s) == arttype, idx, "field value not match type");
+     }
+-    data = (const char *)ASN1_STRING_data(value);
+-    len  = ASN1_STRING_length(value);
++    data = (const char *)ASN1_STRING_data(s);
++    len  = ASN1_STRING_length(s);
+   }
+   else
+   {
+@@ -207,23 +342,6 @@ X509_ATTRIBUTE* openssl_new_xattribute(l
+ }
+ 
+ 
+-static int openssl_xattr_new(lua_State*L)
+-{
+-  X509_ATTRIBUTE *x = NULL;
+-  luaL_checktable(L, 1);
+-
+-  x = openssl_new_xattribute(L, &x, 1, NULL);
+-  PUSH_OBJECT(x, "openssl.x509_attribute");
+-  return 1;
+-}
+-
+-static luaL_Reg R[] =
+-{
+-  {"new_attribute",         openssl_xattr_new},
+-
+-  {NULL,          NULL},
+-};
+-
+ IMP_LUA_SK(X509_ATTRIBUTE, x509_attribute)
+ 
+ int openssl_register_xattribute(lua_State*L)
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/xexts.c luvi-src-v2.7.6/deps/lua-openssl/src/xexts.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/xexts.c	2019-02-13 11:31:40.323968393 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/xexts.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,10 +1,11 @@
+-/*=========================================================================*\
+-* xexts.c
+-* * x509 extension routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
+-
++/***
++Provide x509_extension as lua object.
++Sometime when you make CSR,TS or X509, you maybe need to use this.
++
++@module x509.extension
++@usage
++  extension = require('openssl').x509.extension
++*/
+ #include <ctype.h>
+ #include "openssl.h"
+ #include "private.h"
+@@ -14,176 +15,21 @@
+ 
+ #define MYNAME "x509.extension"
+ 
+-static int openssl_xext_totable(lua_State* L, X509_EXTENSION *x)
+-{
+-  lua_newtable(L);
+-  openssl_push_asn1object(L, x->object);
+-  lua_setfield(L, -2, "object");
+-
+-  PUSH_ASN1_OCTET_STRING(L, x->value);
+-  lua_setfield(L, -2, "value");
+-
+-  AUXILIAR_SET(L, -1, "critical", x->critical, boolean);
+-
+-  switch (x->object->nid)
+-  {
+-  case NID_subject_alt_name:
+-  {
+-    int i;
+-    int n_general_names;
+-
+-    STACK_OF(GENERAL_NAME) *values = X509V3_EXT_d2i(x);
+-
+-    if (values == NULL)
+-      break;
+-
+-    /* Push ret[oid] */
+-    openssl_push_asn1object(L, x->object);
+-    lua_newtable(L);
+-    n_general_names = sk_GENERAL_NAME_num(values);
+-    for (i = 0; i < n_general_names; i++)
+-    {
+-      GENERAL_NAME *general_name = sk_GENERAL_NAME_value(values, i);
+-      openssl_push_general_name(L, general_name);
+-      lua_rawseti(L, -2, i + 1);
+-    }
+-    lua_settable(L, -3);
+-  }
+-  default:
+-    break;
+-  }
+-  return 1;
+-};
+-
+-static int openssl_xext_info(lua_State* L)
+-{
+-  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+-  return openssl_xext_totable(L, x);
+-};
+-
+-static int openssl_xext_dup(lua_State* L)
+-{
+-  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+-  X509_EXTENSION *d = X509_EXTENSION_dup(x);
+-  PUSH_OBJECT(d, "openssl.x509_extension");
+-  return 1;
+-};
+-
+-static int openssl_xext_export(lua_State* L)
+-{
+-  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+-  unsigned char* p = NULL;
+-  int len = i2d_X509_EXTENSION(x, &p);
+-  if (len > 0)
+-  {
+-    lua_pushlstring(L, (const char *) p, len);
+-    OPENSSL_free(p);
+-  }
+-  else
+-    lua_pushnil(L);
+-  return 1;
+-};
+-
+-static int openssl_xext_free(lua_State* L)
+-{
+-  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+-  X509_EXTENSION_free(x);
+-  return 0;
+-};
+-
+-static int openssl_xext_object(lua_State* L)
+-{
+-  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+-  ASN1_OBJECT* obj;
+-  if (lua_isnone(L, 2))
+-  {
+-    obj = X509_EXTENSION_get_object(x);
+-    obj = OBJ_dup(obj);
+-    PUSH_OBJECT(obj, "openssl.asn1_object");
+-    return 1;
+-  }
+-  else
+-  {
+-    int nid = openssl_get_nid(L, 2);
+-    int ret;
+-    obj = OBJ_nid2obj(nid);
+-    ret = X509_EXTENSION_set_object(x, obj);
+-    return openssl_pushresult(L, ret);
+-  }
+-};
+-
+-static int openssl_xext_critical(lua_State* L)
+-{
+-  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+-  if (lua_isnone(L, 2))
+-  {
+-    lua_pushboolean(L, X509_EXTENSION_get_critical(x));
+-    return 1;
+-  }
+-  else
+-  {
+-    int ret = X509_EXTENSION_set_critical(x, lua_toboolean(L, 2));
+-    return openssl_pushresult(L, ret);
+-  }
+-};
+-
+-static int openssl_xext_data(lua_State* L)
+-{
+-  int ret = 0;
+-  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+-  if (lua_isnone(L, 2))
+-  {
+-    ASN1_STRING *s = X509_EXTENSION_get_data(x);
+-    s = ASN1_STRING_dup(s);
+-    PUSH_OBJECT(s, "openssl.asn1_string");
+-    return 1;
+-  }
+-  else if (lua_isstring(L, 2))
+-  {
+-    size_t size;
+-    const char* data = lua_tolstring(L, 2, &size);
+-    int type = lua_isnone(L, 3) ? V_ASN1_OCTET_STRING : luaL_checkint(L, 3);
+-    ASN1_STRING* s = ASN1_STRING_type_new(type);
+-    if (ASN1_STRING_set(s, data, size) == 1)
+-    {
+-      ret = X509_EXTENSION_set_data(x, s);
+-    }
+-    ASN1_STRING_free(s);
+-    return openssl_pushresult(L, ret);
+-  }
+-  else
+-  {
+-    ASN1_STRING* s = CHECK_GROUP(2, ASN1_STRING, "openssl.asn1group");
+-    if (ASN1_STRING_type(s) == V_ASN1_OCTET_STRING)
+-    {
+-      ret = X509_EXTENSION_set_data(x, s);
+-      return openssl_pushresult(L, ret);
+-    }
+-    else
+-    {
+-      luaL_argerror(L, 2, "asn1_string type must be octet");
+-    }
+-  }
+-  return 0;
+-};
+-
+-static luaL_Reg x509_extension_funs[] =
+-{
+-  {"info",          openssl_xext_info},
+-  {"dup",           openssl_xext_dup},
+-  {"export",        openssl_xext_export},
+-
+-  /* set and get */
+-  {"object",        openssl_xext_object},
+-  {"critical",      openssl_xext_critical},
+-  {"data",          openssl_xext_data},
+-
+-  {"__gc",          openssl_xext_free},
+-  {"__tostring",    auxiliar_tostring},
+-
+-  { NULL, NULL }
+-};
++/***
++x509_extension contrust param table.
+ 
++@table x509_extension_param_table
++@tfield boolean critical true set critical
++@tfield asn1_string value of x509_extension
++@tfield string|asn1_object object, object of extension
++
++@usage
++xattr = x509.attrextension.new_extension {
++  object = asn1_object,
++  critical = false,
++  value = string or asn1_string value
++}
++*/
+ static X509_EXTENSION* openssl_new_xextension(lua_State*L, int idx, int v3)
+ {
+   int nid;
+@@ -205,13 +51,11 @@ static X509_EXTENSION* openssl_new_xexte
+     luaL_argerror(L, idx, lua_tostring(L, -1));
+   }
+   lua_getfield(L, idx, "value");
+-
+-  luaL_argcheck(L, lua_isstring(L, -1) || auxiliar_isgroup(L, "openssl.asn1group", -1),
+-                1, "field value must be string or openssl.asn1group object");
+   if (lua_isstring(L, -1))
+   {
+     size_t size;
+     const char* data = lua_tolstring(L, -1, &size);
++    lua_pop(L, 1);
+     if (v3)
+     {
+       const X509V3_EXT_METHOD *method = X509V3_EXT_get_nid(nid);
+@@ -291,13 +135,25 @@ static X509_EXTENSION* openssl_new_xexte
+   }
+   else
+   {
+-    value = CHECK_GROUP(-1, ASN1_STRING, "openssl.asn1group");
+-    y = X509_EXTENSION_create_by_NID(NULL, nid, critical, value);
+-    lua_pop(L, 1);
+-    return y;
++    value = GET_GROUP(-1, ASN1_STRING, "openssl.asn1group");
++    if(value)
++    {
++      y = X509_EXTENSION_create_by_NID(NULL, nid, critical, value);
++      lua_pop(L, 1);
++      return y;
++    }
+   }
++  luaL_argerror(L, 1, "field value must be string or openssl.asn1group object");
++  return NULL;
+ }
+ 
++/***
++Create x509_extension object
++@function new_extension
++@tparam table extension with object, value and critical
++@treturn x509_extension mapping to X509_EXTENSION in openssl
++@see x509_extension_param_table
++*/
+ static int openssl_xext_new(lua_State* L)
+ {
+   X509_EXTENSION *x = NULL;
+@@ -316,6 +172,12 @@ static int openssl_xext_new(lua_State* L
+   return 1;
+ };
+ 
++/***
++read der encoded x509_extension
++@function read_extension
++@tparam string data der encoded
++@treturn x509_extension mappling to X509_EXTENSION in openssl
++*/
+ static int openssl_xext_read(lua_State* L)
+ {
+   size_t size;
+@@ -330,6 +192,23 @@ static int openssl_xext_read(lua_State*
+   return 1;
+ };
+ 
++/***
++get all x509 certificate supported extensions
++@function support
++@treturn table contain all support extension info as table node {lname=..., sname=..., nid=...}
++*/
++/***
++check x509_extension object support or not
++@function support
++@tparam x509_extension extension
++@treturn boolean true for supported, false or not
++*/
++/***
++check nid or name support or not
++@function support
++@tparam number|string nid_or_name for extension
++@treturn boolean true for supported, false or not
++*/
+ static int openssl_xext_support(lua_State*L)
+ {
+   static const int supported_nids[] =
+@@ -369,7 +248,7 @@ static int openssl_xext_support(lua_Stat
+     };
+     return 1;
+   }
+-  else if (auxiliar_isclass(L, "openssl.x509_extension", 1))
++  else if (auxiliar_getclassudata(L, "openssl.x509_extension", 1))
+   {
+     X509_EXTENSION* ext = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
+     int ret = X509_supported_extension(ext);
+@@ -402,6 +281,251 @@ static luaL_Reg R[] =
+   {NULL,          NULL},
+ };
+ 
++/***
++openssl.x509_extension object
++@type x509_extension
++*/
++
++/***
++x509_extension infomation table
++@todo double check
++@table x509_extension_info_table
++@tfield asn1_object|object object of x509_extension
++@tfield boolean|critical true for critical value
++@tfield string|value as octet string
++*/
++static int openssl_xext_totable(lua_State* L, X509_EXTENSION *x)
++{
++  ASN1_OBJECT *obj = X509_EXTENSION_get_object(x);
++  int nid = OBJ_obj2nid(obj);
++  lua_newtable(L);
++  openssl_push_asn1object(L, obj);
++  lua_setfield(L, -2, "object");
++
++  PUSH_ASN1_OCTET_STRING(L, X509_EXTENSION_get_data(x));
++  lua_setfield(L, -2, "value");
++
++  AUXILIAR_SET(L, -1, "critical", X509_EXTENSION_get_critical(x), boolean);
++
++  switch (nid)
++  {
++  case NID_subject_alt_name:
++  {
++    int i;
++    int n_general_names;
++
++    STACK_OF(GENERAL_NAME) *values = X509V3_EXT_d2i(x);
++
++    if (values == NULL)
++      break;
++
++    /* Push ret[oid] */
++    openssl_push_asn1object(L, obj);
++    lua_newtable(L);
++    n_general_names = sk_GENERAL_NAME_num(values);
++    for (i = 0; i < n_general_names; i++)
++    {
++      GENERAL_NAME *general_name = sk_GENERAL_NAME_value(values, i);
++      openssl_push_general_name(L, general_name);
++      lua_rawseti(L, -2, i + 1);
++    }
++    lua_settable(L, -3);
++  }
++  default:
++    break;
++  }
++  return 1;
++};
++
++/***
++get infomation table of x509_extension.
++
++@function info
++@tparam[opt] boolean|utf8 true for utf8 default
++@treturn[1] table info,  x509_extension infomation as table
++@see x509_extension_info_table
++*/
++static int openssl_xext_info(lua_State* L)
++{
++  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
++  return openssl_xext_totable(L, x);
++};
++
++/***
++clone then x509_extension
++
++@function dup
++@treturn x509_extension clone of x509_extension
++*/
++static int openssl_xext_dup(lua_State* L)
++{
++  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
++  X509_EXTENSION *d = X509_EXTENSION_dup(x);
++  PUSH_OBJECT(d, "openssl.x509_extension");
++  return 1;
++};
++
++/***
++export x509_extenion to der encoded string
++@function export
++@treturn string
++*/
++static int openssl_xext_export(lua_State* L)
++{
++  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
++  unsigned char* p = NULL;
++  int len = i2d_X509_EXTENSION(x, &p);
++  if (len > 0)
++  {
++    lua_pushlstring(L, (const char *) p, len);
++    OPENSSL_free(p);
++  }
++  else
++    lua_pushnil(L);
++  return 1;
++};
++
++static int openssl_xext_free(lua_State* L)
++{
++  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
++  X509_EXTENSION_free(x);
++  return 0;
++};
++
++/***
++get asn1_object of x509_extension.
++@function object
++@treturn asn1_object object of x509_extension
++*/
++
++/***
++set asn1_object for x509_extension.
++
++@function object
++@tparam asn1_object obj
++@treturn boolean true for success
++@return nil when occure error, and followed by error message
++*/
++static int openssl_xext_object(lua_State* L)
++{
++  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
++  ASN1_OBJECT* obj;
++  if (lua_isnone(L, 2))
++  {
++    obj = X509_EXTENSION_get_object(x);
++    openssl_push_asn1object(L, obj);
++    return 1;
++  }
++  else
++  {
++    int nid = openssl_get_nid(L, 2);
++    int ret;
++    obj = OBJ_nid2obj(nid);
++    ret = X509_EXTENSION_set_object(x, obj);
++    return openssl_pushresult(L, ret);
++  }
++};
++
++/***
++get critical of x509_extension.
++
++@function critical
++@treturn boolean true if extension set critical or false
++*/
++/***
++set critical of x509_extension.
++
++@function critical
++@tparam boolean critical set to self
++@treturn boolean set critical success return true
++@return nil fail return nil, and followed by error message
++*/
++static int openssl_xext_critical(lua_State* L)
++{
++  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
++  if (lua_isnone(L, 2))
++  {
++    lua_pushboolean(L, X509_EXTENSION_get_critical(x));
++    return 1;
++  }
++  else
++  {
++    int ret = X509_EXTENSION_set_critical(x, lua_toboolean(L, 2));
++    return openssl_pushresult(L, ret);
++  }
++};
++
++/***
++get data of x509_extension
++
++@function data
++@treturn asn1_string
++*/
++
++/***
++set type of x509_extension
++
++@function data
++@tparam asn1_string data set to self
++@treturn boolean result true for success
++@return nil for error, and followed by error message
++*/
++static int openssl_xext_data(lua_State* L)
++{
++  int ret = 0;
++  X509_EXTENSION *x = CHECK_OBJECT(1, X509_EXTENSION, "openssl.x509_extension");
++  if (lua_isnone(L, 2))
++  {
++    ASN1_STRING *s = X509_EXTENSION_get_data(x);
++    PUSH_ASN1_STRING(L, s);
++    return 1;
++  }
++  else if (lua_isstring(L, 2))
++  {
++    size_t size;
++    const char* data = lua_tolstring(L, 2, &size);
++    int type = lua_isnone(L, 3) ? V_ASN1_OCTET_STRING : luaL_checkint(L, 3);
++    ASN1_STRING* s = ASN1_STRING_type_new(type);
++    if (ASN1_STRING_set(s, data, size) == 1)
++    {
++      ret = X509_EXTENSION_set_data(x, s);
++    }
++    ASN1_STRING_free(s);
++    return openssl_pushresult(L, ret);
++  }
++  else
++  {
++    ASN1_STRING* s = CHECK_GROUP(2, ASN1_STRING, "openssl.asn1group");
++    if (ASN1_STRING_type(s) == V_ASN1_OCTET_STRING)
++    {
++      ret = X509_EXTENSION_set_data(x, s);
++      return openssl_pushresult(L, ret);
++    }
++    else
++    {
++      luaL_argerror(L, 2, "asn1_string type must be octet");
++    }
++  }
++  return 0;
++};
++
++static luaL_Reg x509_extension_funs[] =
++{
++  {"info",          openssl_xext_info},
++  {"dup",           openssl_xext_dup},
++  {"export",        openssl_xext_export},
++
++  /* set and get */
++  {"object",        openssl_xext_object},
++  {"critical",      openssl_xext_critical},
++  {"data",          openssl_xext_data},
++
++  {"__gc",          openssl_xext_free},
++  {"__tostring",    auxiliar_tostring},
++
++  { NULL, NULL }
++};
++
+ IMP_LUA_SK(X509_EXTENSION, x509_extension)
+ 
+ int openssl_register_xextension(lua_State*L)
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/xname.c luvi-src-v2.7.6/deps/lua-openssl/src/xname.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/xname.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/xname.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,10 +1,11 @@
+-/*=========================================================================*\
+-* xname.c
+-* * x509 name routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
+-
++/***
++x509_name module for lua-openssl binding, provide x509_name as lua object
++Sometime when you make CSR,TS or X509, you maybe need to use this.
++
++@module x509.name
++@usage
++  name = require('openssl').x509.name
++*/
+ #include "openssl.h"
+ #include "private.h"
+ 
+@@ -12,6 +13,120 @@
+ 
+ #define MYNAME "x509.name"
+ 
++int openssl_push_xname_asobject(lua_State*L, X509_NAME* xname)
++{
++  X509_NAME* dup = X509_NAME_dup(xname);
++  PUSH_OBJECT(dup, "openssl.x509_name");
++  return 1;
++}
++
++static int openssl_new_xname(lua_State*L, X509_NAME* xname, int idx, int utf8)
++{
++  int i, n;
++  luaL_checktable(L, idx);
++  luaL_argcheck(L, lua_istable(L, idx) && lua_rawlen(L, idx) > 0, idx,
++                "must be not empty table as array");
++
++  n = lua_rawlen(L, idx);
++  for (i = 0; i < n; i++)
++  {
++    lua_rawgeti(L, idx, i + 1);
++    lua_pushnil(L);
++
++    while (lua_next(L, -2) != 0)
++    {
++      size_t size;
++      const char *value;
++      int ret;
++      int nid = openssl_get_nid(L, -2);
++      value = luaL_checklstring(L, -1, &size);
++
++      if (nid == NID_undef)
++      {
++        lua_pushfstring(L, "node at %d which key (%s) is not a valid object identity",
++                        i + 1, lua_tostring(L, -2));
++        luaL_argerror(L, idx, lua_tostring(L, -1));
++      }
++      ret = X509_NAME_add_entry_by_NID(xname, nid, utf8 ? MBSTRING_UTF8 : MBSTRING_ASC, (unsigned char*)value, (int)size, -1, 0);
++      if (ret != 1)
++      {
++        lua_pushfstring(L, "node at %d which  %s=%s can't add to X509 name",
++                        i + 1, lua_tostring(L, -2), value);
++        luaL_argerror(L, idx, lua_tostring(L, -1));
++      }
++      lua_pop(L, 1);
++    }
++  }
++  return 0;
++}
++
++/***
++Create x509_name object
++
++@function new
++@tparam table array include name node
++@tparam[opt] boolean utf8 encode will be use default
++@treturn x509_name mapping to X509_EXTENSION in openssl
++@usage
++  name = require'openssl'.x509.name
++  subject = name.new{
++    {C='CN'},
++    {O='kkhub.com'},
++    {CN='zhaozg'}
++  }
++*/
++static int openssl_xname_new(lua_State*L)
++{
++  X509_NAME* xn;
++  int utf8;
++  luaL_checktable(L, 1);
++  utf8 = lua_isnoneornil(L, 2) ? 1 : lua_toboolean(L, 2);
++  xn = X509_NAME_new();
++  openssl_new_xname(L, xn, 1, utf8);
++  PUSH_OBJECT(xn, "openssl.x509_name");
++  return 1;
++};
++
++/***
++Create x509_name from der string
++
++@function d2i
++@tparam string content DER encoded string
++@treturn x509_name mapping to X509_NAME in openssl
++*/
++static int openssl_xname_d2i(lua_State*L)
++{
++  size_t len;
++  const unsigned char* dat = (const unsigned char*)luaL_checklstring(L, 1, &len);
++  X509_NAME* xn = d2i_X509_NAME(NULL, &dat, len);
++  if (xn)
++    PUSH_OBJECT(xn, "openssl.x509_name");
++  else
++    openssl_pushresult(L, 0);
++  return 1;
++};
++
++static luaL_Reg R[] =
++{
++  {"new",           openssl_xname_new},
++  {"d2i",           openssl_xname_d2i},
++
++  {NULL,          NULL},
++};
++
++/***
++x509_name infomation table
++other field is number type, and value table is alter name.(I not understand clearly)
++@table x509_extension_info_table
++@tfield asn1_object|object object of x509_name
++@tfield boolean|critical true for critical value
++@tfield string|value as octet string
++*/
++
++/***
++openssl.x509_name object
++@type x509_name
++*/
+ static int openssl_xname_gc(lua_State* L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -19,6 +134,12 @@ static int openssl_xname_gc(lua_State* L
+   return 0;
+ }
+ 
++/***
++get oneline of x509_name.
++
++@function oneline
++@treturn string line, name as oneline text
++*/
+ static int openssl_xname_oneline(lua_State*L)
+ {
+   X509_NAME* xname = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -29,6 +150,12 @@ static int openssl_xname_oneline(lua_Sta
+   return 1;
+ };
+ 
++/***
++get hash code of x509_name
++
++@function hash
++@treturn integer hash hash code of x509_name
++*/
+ static int openssl_xname_hash(lua_State*L)
+ {
+   X509_NAME* xname = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -37,10 +164,17 @@ static int openssl_xname_hash(lua_State*
+   return 1;
+ };
+ 
++/***
++get digest of x509_name
++
++@function digest
++@tparam string|nid|openssl.evp_md md method of digest
++@treturn string digest digest value by given alg of x509_name
++*/
+ static int openssl_xname_digest(lua_State*L)
+ {
+   X509_NAME* xname = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+-  const EVP_MD* md = get_digest(L, 2);
++  const EVP_MD* md = get_digest(L, 2, NULL);
+   unsigned char buf [EVP_MAX_MD_SIZE];
+   unsigned int len = sizeof(buf);
+ 
+@@ -52,6 +186,15 @@ static int openssl_xname_digest(lua_Stat
+   return 1;
+ };
+ 
++/***
++print x509_name to bio object
++
++@function print
++@tparam openssl.bio out output bio object
++@tparam[opt] integer indent for output
++@tparam[opt] integer flags for output
++@treturn boolean result, follow by error message
++*/
+ static int openssl_xname_print(lua_State*L)
+ {
+   X509_NAME* xname = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -68,42 +211,73 @@ static int openssl_xname_print(lua_State
+   return 1;
+ };
+ 
+-static int openssl_push_xname_entry(lua_State* L, X509_NAME_ENTRY* ne)
++static int openssl_push_xname_entry(lua_State* L, X509_NAME_ENTRY* ne, int obj)
+ {
+   ASN1_OBJECT* object = X509_NAME_ENTRY_get_object(ne);
+-  ASN1_STRING *s;
++  ASN1_STRING* value = X509_NAME_ENTRY_get_data(ne);
+   lua_newtable(L);
+-  openssl_push_asn1object(L, object);
+-  s = X509_NAME_ENTRY_get_data(ne);
+-  PUSH_ASN1_STRING(L, s);
++  if(obj)
++  {
++    openssl_push_asn1object(L, object);
++    PUSH_ASN1_STRING(L, value);
++  }
++  else
++  {
++    lua_pushstring(L, OBJ_nid2sn(OBJ_obj2nid(object)));
++    lua_pushlstring(L, (const char*)ASN1_STRING_data(value), ASN1_STRING_length(value));
++  }
+   lua_settable(L, -3);
+   return 1;
+ }
+ 
++/***
++return x509_name as table
++
++@function info
++@tparam[opt=false] boolean asobject table key will use asn1_object or short name of asn1_object
++@treturn table names
++@see new
++*/
+ static int openssl_xname_info(lua_State*L)
+ {
+   X509_NAME* name = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+-  int i;
+-  int n_entries = X509_NAME_entry_count(name);
++  int obj = lua_isnoneornil(L, 2) ? 0 : lua_toboolean(L, 2);
++  int i, n;
+   lua_newtable(L);
+-  for (i = 0; i < n_entries; i++)
++  for (i = 0, n = X509_NAME_entry_count(name); i < n; i++)
+   {
+     X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, i);
+-    openssl_push_xname_entry(L, entry);
++    openssl_push_xname_entry(L, entry, obj);
+     lua_rawseti(L, -2, i + 1);
+   }
+   return 1;
+ };
+ 
++/***
++compare two x509_name
++
++@function cmp
++@tparam x509_name another to compare with
++@treturn boolean result true for equal or false
++@usage
++  name1 = name.new({...})
++  name2 = name1:dup()
++  assert(name1:cmp(name2)==(name1==name2))
++*/
+ static int openssl_xname_cmp(lua_State*L)
+ {
+   X509_NAME* a = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+-  X509_NAME* b = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
++  X509_NAME* b = CHECK_OBJECT(2, X509_NAME, "openssl.x509_name");
+   int ret = X509_NAME_cmp(a, b);
+   lua_pushboolean(L, ret == 0);
+   return 1;
+ };
+ 
++/***
++make a clone of x509_name
++@function dup
++@treturn x509_name clone
++*/
+ static int openssl_xname_dup(lua_State*L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -112,6 +286,12 @@ static int openssl_xname_dup(lua_State*L
+   return 1;
+ };
+ 
++/***
++get DER encoded string of x509_name.
++
++@function i2d
++@treturn string der
++*/
+ static int openssl_xname_i2d(lua_State*L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -120,13 +300,19 @@ static int openssl_xname_i2d(lua_State*L
+   if (len > 0)
+   {
+     lua_pushlstring(L, (const char *)out, len);
+-    CRYPTO_free(out);
++    OPENSSL_free(out);
+     return 1;
+   }
+   else
+     return openssl_pushresult(L, len);
+ };
+ 
++/***
++get count in x509_name.
++
++@function entry_count
++@treturn integer count of x509_name
++*/
+ static int openssl_xname_entry_count(lua_State*L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -135,6 +321,14 @@ static int openssl_xname_entry_count(lua
+   return 1;
+ };
+ 
++/***
++get text by given asn1_object or nid
++
++@function get_text
++@tparam string|integer|asn1_object identid for asn1_object
++@tparam[opt=-1] number lastpos retrieve the next index after lastpos
++@treturn string text and followed by lastpos
++*/
+ static int openssl_xname_get_text(lua_State*L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -156,18 +350,35 @@ static int openssl_xname_get_text(lua_St
+   return 2;
+ };
+ 
++/***
++get x509 name entry by index
++@function get_entry
++@tparam integer index start from 0, and less than xn:entry_count()
++@tparam[opt=false] boolean asobject table key will use asn1_object or short name of asn1_object
++@treturn x509 name entry table
++*/
+ static int openssl_xname_get_entry(lua_State*L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+   int lastpos = luaL_checkint(L, 2);
++  int obj = lua_isnoneornil(L, 3) ? 0 : lua_toboolean(L, 3);
+   X509_NAME_ENTRY *e = X509_NAME_get_entry(xn, lastpos);
+   if (e)
+   {
+-    return openssl_push_xname_entry(L, e);
++    return openssl_push_xname_entry(L, e, obj);
+   }
+   return 0;
+ };
+ 
++/***
++add name entry
++
++@function add_entry
++@tparam string|integer|asn1_object identid for asn1_object
++@tparam string data to add
++@tparam[opt] boolean utf8 true for use utf8 default
++@treturn boolean result true for success or follow by error message
++*/
+ static int openssl_xname_add_entry(lua_State*L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -189,6 +400,15 @@ static int openssl_xname_add_entry(lua_S
+   return openssl_pushresult(L, ret);
+ };
+ 
++/***
++get index by give asn1_object or nid
++
++@function delete_entry
++@tparam integer location which name entry to delete
++@treturn[1] asn1_object object that delete name entry
++@treturn[1] asn1_string value that delete name entry
++@treturn[2] nil delete nothing
++*/
+ static int openssl_xname_delete_entry(lua_State*L)
+ {
+   X509_NAME* xn = CHECK_OBJECT(1, X509_NAME, "openssl.x509_name");
+@@ -197,10 +417,8 @@ static int openssl_xname_delete_entry(lu
+   X509_NAME_ENTRY *xe = X509_NAME_delete_entry(xn, loc);
+   if (xe)
+   {
+-    ASN1_OBJECT *obj = OBJ_dup(xe->object);
+-    ASN1_STRING *as = ASN1_STRING_dup(xe->value);
+-    PUSH_OBJECT(obj, "openssl.asn1_object");
+-    PUSH_OBJECT(as, "openssl.asn1_string");
++    openssl_push_asn1object(L, X509_NAME_ENTRY_get_object(xe));
++    PUSH_ASN1_STRING(L, X509_NAME_ENTRY_get_data(xe));
+     X509_NAME_ENTRY_free(xe);
+     return 2;
+   }
+@@ -234,85 +452,6 @@ static luaL_Reg xname_funcs[] =
+ 
+   {NULL,          NULL},
+ };
+-
+-int openssl_push_xname_asobject(lua_State*L, X509_NAME* xname)
+-{
+-  X509_NAME* dup = X509_NAME_dup(xname);
+-  PUSH_OBJECT(dup, "openssl.x509_name");
+-  return 1;
+-}
+-
+-static int openssl_new_xname(lua_State*L, X509_NAME* xname, int idx, int utf8)
+-{
+-  int i, n;
+-  luaL_checktable(L, idx);
+-  luaL_argcheck(L, lua_istable(L, idx) && lua_rawlen(L, idx) > 0, idx,
+-                "must be not empty table as array");
+-
+-  n = lua_rawlen(L, idx);
+-  for (i = 0; i < n; i++)
+-  {
+-    lua_rawgeti(L, idx, i + 1);
+-    lua_pushnil(L);
+-
+-    while (lua_next(L, -2) != 0)
+-    {
+-      size_t size;
+-      const char *value;
+-      int ret;
+-      int nid = openssl_get_nid(L, -2);
+-      value = luaL_checklstring(L, -1, &size);
+-
+-      if (nid == NID_undef)
+-      {
+-        lua_pushfstring(L, "node at %d which key (%s) is not a valid object identity",
+-                        i + 1, lua_tostring(L, -2));
+-        luaL_argerror(L, idx, lua_tostring(L, -1));
+-      }
+-      ret = X509_NAME_add_entry_by_NID(xname, nid, utf8 ? MBSTRING_UTF8 : MBSTRING_ASC, (unsigned char*)value, (int)size, -1, 0);
+-      if (ret != 1)
+-      {
+-        lua_pushfstring(L, "node at %d which  %s=%s can't add to X509 name",
+-                        i + 1, lua_tostring(L, -2), value);
+-        luaL_argerror(L, idx, lua_tostring(L, -1));
+-      }
+-      lua_pop(L, 1);
+-    }
+-  }
+-  return 0;
+-}
+-
+-static int openssl_xname_new(lua_State*L)
+-{
+-  X509_NAME* xn;
+-  int utf8;
+-  luaL_checktable(L, 1);
+-  utf8 = lua_isnoneornil(L, 2) ? 1 : lua_toboolean(L, 2);
+-  xn = X509_NAME_new();
+-  openssl_new_xname(L, xn, 1, utf8);
+-  PUSH_OBJECT(xn, "openssl.x509_name");
+-  return 1;
+-};
+-
+-static int openssl_xname_d2i(lua_State*L)
+-{
+-  size_t len;
+-  const unsigned char* dat = (const unsigned char*)luaL_checklstring(L, 1, &len);
+-  X509_NAME* xn = d2i_X509_NAME(NULL, &dat, len);
+-  if (xn)
+-    PUSH_OBJECT(xn, "openssl.x509_name");
+-  else
+-    openssl_pushresult(L, 0);
+-  return 1;
+-};
+-
+-static luaL_Reg R[] =
+-{
+-  {"new",           openssl_xname_new},
+-  {"d2i",           openssl_xname_d2i},
+-
+-  {NULL,          NULL},
+-};
+ 
+ IMP_LUA_SK(X509_NAME, x509_name)
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/src/xstore.c luvi-src-v2.7.6/deps/lua-openssl/src/xstore.c
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/src/xstore.c	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/src/xstore.c	2019-02-13 11:53:24.321792707 +0100
+@@ -1,18 +1,71 @@
+-/*=========================================================================*\
+-* xstore.c
+-* * x509_store routines for lua-openssl binding
+-*
+-* Author:  george zhao <zhaozg(at)gmail.com>
+-\*=========================================================================*/
+-
++/***
++Provide x509_store as lua object, create and manage x509 store object
++@module x509.store
++@usage
++  store = require'openssl'.x509.store
++*/
+ #include "openssl.h"
+ #include "private.h"
+ 
+ #define MYNAME "x509.store"
+ 
++/***
++create or generate a new x509_store object.
++@function new
++@tparam table certs array of x509 objects, all x509 object will add to store, certs can be empty but not nil
++@tparam[opt] table crls array of x509_crl objects, all crl object will add to store
++@treturn x509_store object
++@see x509_store
++*/
++static int openssl_xstore_new(lua_State*L)
++{
++  X509_STORE* ctx = X509_STORE_new();
++  int i, n;
++  luaL_checktable(L, 1);
++  n = lua_rawlen(L, 1);
++  for (i = 0; i < n; i++)
++  {
++    X509* x;
++    lua_rawgeti(L, 1, i + 1);
++    luaL_argcheck(L, auxiliar_getclassudata(L, "openssl.x509", -1), 1, "only contains x509 object");
++    x = CHECK_OBJECT(-1, X509, "openssl.x509");
++    lua_pop(L, 1);
++    X509_STORE_add_cert(ctx, x);
++  }
++  if (!lua_isnoneornil(L, 2))
++  {
++    luaL_checktable(L, 2);
++
++    n = lua_rawlen(L, 2);
++    for (i = 0; i < n; i++)
++    {
++      X509_CRL* c;
++      lua_rawgeti(L, 2, i + 1);
++      c = CHECK_OBJECT(-1, X509_CRL, "openssl.x509_crl");
++      lua_pop(L, 1);
++      X509_STORE_add_crl(ctx, c);
++    }
++  };
++
++  PUSH_OBJECT(ctx, "openssl.x509_store");
++  return 1;
++};
++
++static luaL_Reg R[] =
++{
++  {"new",           openssl_xstore_new},
++
++  {NULL,          NULL},
++};
++
++/***
++openssl.x509_store object
++@type x509_store
++*/
+ void openssl_xstore_free(X509_STORE* ctx)
+ {
+-#if OPENSSL_VERSION_NUMBER < 0x10002000L
++  /* hack openssl bugs */
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+   if (ctx->references > 1)
+     CRYPTO_add(&ctx->references, -1, CRYPTO_LOCK_X509_STORE);
+   else
+@@ -29,6 +82,14 @@ static int openssl_xstore_gc(lua_State*
+   return 0;
+ }
+ 
++/***
++add lookup path for store
++@function add_lookup
++@tparam string path file or dir path to add
++@tparam[opt='file'] mode only 'file' or 'dir'
++@tparam[opt='default'] format only 'pem', 'der' or 'default'
++@treturn boolean result
++*/
+ static int openssl_xstore_add_lookup(lua_State* L)
+ {
+   X509_STORE* ctx = CHECK_OBJECT(1, X509_STORE, "openssl.x509_store");
+@@ -60,7 +121,12 @@ static int openssl_xstore_add_lookup(lua
+   return openssl_pushresult(L, ret);
+ }
+ 
+-
++/***
++set verify depth of certificate chains
++@function depth
++@tparam number depth
++@treturn boolean result
++*/
+ static int openssl_xstore_depth(lua_State* L)
+ {
+   X509_STORE* ctx = CHECK_OBJECT(1, X509_STORE, "openssl.x509_store");
+@@ -69,6 +135,12 @@ static int openssl_xstore_depth(lua_Stat
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++set verify flags of certificate chains
++@function flags
++@tparam number flags
++@treturn boolean result
++*/
+ static int openssl_xstore_flags(lua_State* L)
+ {
+   X509_STORE* ctx = CHECK_OBJECT(1, X509_STORE, "openssl.x509_store");
+@@ -77,6 +149,12 @@ static int openssl_xstore_flags(lua_Stat
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++set prupose of x509 store
++@function purpose
++@tparam integer purpose
++@treturn boolean result
++*/
+ static int openssl_xstore_purpose(lua_State* L)
+ {
+   X509_STORE* ctx = CHECK_OBJECT(1, X509_STORE, "openssl.x509_store");
+@@ -85,6 +163,12 @@ static int openssl_xstore_purpose(lua_St
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++set as trust x509 store
++@function trust
++@tparam boolean trust
++@treturn boolean result
++*/
+ static int openssl_xstore_trust(lua_State* L)
+ {
+   X509_STORE* ctx = CHECK_OBJECT(1, X509_STORE, "openssl.x509_store");
+@@ -93,6 +177,13 @@ static int openssl_xstore_trust(lua_Stat
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++load certificate from file or dir,not given any paramater will load from defaults path
++@function load
++@tparam[opt] string filepath
++@tparam[opt] string dirpath
++@treturn boolean result
++*/
+ static int openssl_xstore_load(lua_State* L)
+ {
+   X509_STORE* ctx = CHECK_OBJECT(1, X509_STORE, "openssl.x509_store");
+@@ -109,6 +200,12 @@ static int openssl_xstore_load(lua_State
+   return openssl_pushresult(L, ret);
+ }
+ 
++/***
++add x509 certificate or crl to store
++@param ... support x509 object,x509_crl object or array contains x509,x509_crl object
++@function add
++@treturn boolean result
++*/
+ static int openssl_xstore_add(lua_State* L)
+ {
+   X509_STORE* ctx = CHECK_OBJECT(1, X509_STORE, "openssl.x509_store");
+@@ -124,12 +221,12 @@ static int openssl_xstore_add(lua_State*
+       for (j = 1; j <= k; j++)
+       {
+         lua_rawgeti(L, i, j);
+-        if (auxiliar_isclass(L, "openssl.x509", i))
++        if (auxiliar_getclassudata(L, "openssl.x509", i))
+         {
+           X509* x = CHECK_OBJECT(i, X509, "openssl.x509");
+           ret = X509_STORE_add_cert(ctx, x);
+         }
+-        else if (auxiliar_isclass(L, "openssl.x509_crl", i))
++        else if (auxiliar_getclassudata(L, "openssl.x509_crl", i))
+         {
+           X509_CRL* c = CHECK_OBJECT(i, X509_CRL, "openssl.x509_crl");
+           ret = X509_STORE_add_crl(ctx, c);
+@@ -140,12 +237,12 @@ static int openssl_xstore_add(lua_State*
+         }
+       }
+     }
+-    else if (auxiliar_isclass(L, "openssl.x509", i))
++    else if (auxiliar_getclassudata(L, "openssl.x509", i))
+     {
+       X509* x = CHECK_OBJECT(i, X509, "openssl.x509");
+       ret = X509_STORE_add_cert(ctx, x);
+     }
+-    else if (auxiliar_isclass(L, "openssl.x509_crl", i))
++    else if (auxiliar_getclassudata(L, "openssl.x509_crl", i))
+     {
+       X509_CRL* c = CHECK_OBJECT(i, X509_CRL, "openssl.x509_crl");
+       ret = X509_STORE_add_crl(ctx, c);
+@@ -186,47 +283,6 @@ static luaL_Reg xname_funcs[] =
+ 
+   {NULL,          NULL},
+ };
+-
+-static int openssl_xstore_new(lua_State*L)
+-{
+-  X509_STORE* ctx = X509_STORE_new();
+-  int i, n;
+-  luaL_checktable(L, 1);
+-  n = lua_rawlen(L, 1);
+-  for (i = 0; i < n; i++)
+-  {
+-    X509* x;
+-    lua_rawgeti(L, 1, i + 1);
+-    luaL_argcheck(L, auxiliar_isclass(L, "openssl.x509", -1), 1, "only contains x509 object");
+-    x = CHECK_OBJECT(-1, X509, "openssl.x509");
+-    lua_pop(L, 1);
+-    X509_STORE_add_cert(ctx, x);
+-  }
+-  if (!lua_isnoneornil(L, 2))
+-  {
+-    luaL_checktable(L, 2);
+-
+-    n = lua_rawlen(L, 2);
+-    for (i = 0; i < n; i++)
+-    {
+-      X509_CRL* c;
+-      lua_rawgeti(L, 2, i + 1);
+-      c = CHECK_OBJECT(-1, X509_CRL, "openssl.x509_crl");
+-      lua_pop(L, 1);
+-      X509_STORE_add_crl(ctx, c);
+-    }
+-  };
+-
+-  PUSH_OBJECT(ctx, "openssl.x509_store");
+-  return 1;
+-};
+-
+-static luaL_Reg R[] =
+-{
+-  {"new",           openssl_xstore_new},
+-
+-  {NULL,          NULL},
+-};
+ 
+ int openssl_register_xstore(lua_State*L)
+ {
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/0.engine.lua luvi-src-v2.7.6/deps/lua-openssl/test/0.engine.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/0.engine.lua	2019-02-13 11:31:40.293968598 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/0.engine.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -5,7 +5,13 @@ TestEngine = {}
+         local eng = assert(openssl.engine('openssl'))
+         assert(eng:id(),'openssl')
+         assert(eng:set_default('RSA'))
+-        assert(eng:set_default('ECDSA'))
++        local _,sslv
++        _, _, sslv = openssl.version(true)
++        if sslv>=0x10100000 then
++          assert(eng:set_default('EC'))
++        else
++          assert(eng:set_default('ECDSA'))
++      end
+     end
+ 
+     function TestEngine:testLoop()
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/1.asn1.lua luvi-src-v2.7.6/deps/lua-openssl/test/1.asn1.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/1.asn1.lua	2019-02-13 11:31:40.293968598 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/1.asn1.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -1,6 +1,5 @@
+ local openssl = require'openssl'
+ local asn1 = openssl.asn1
+-
+ local first = true
+ 
+ TestObject = {}
+@@ -27,15 +26,19 @@ TestObject = {}
+         o3 = asn1.new_object(self.nid)
+         o4 = asn1.new_object(self.oid)
+         o5 = asn1.new_object(self.oid,true)
+-
+-        o6 = asn1.new_object(self.ln,true)
+-        assertEquals(openssl.error(),218513530)
+-
++        assert(o1)
+         assert(o1==o2)
+         assert(o1==o3)
+         assert(o1==o4)
+         assert(o1==o5)
++
++        assertEquals(openssl.error(),nil)
++
++        o6 = asn1.new_object(self.ln,true)
+         assertNil(o6)
++        assertNotNil(openssl.error())
++        assertNil(openssl.error())
++
+         o6 = o1:dup()
+         assert(o1==o6)
+ 
+@@ -64,9 +67,10 @@ TestObject = {}
+             ln  ='CCSTC GMSM2 EC1'
+         }
+ 
++        assertNil(openssl.error())
+         o7 = asn1.new_object(options.sn)
+         if not o7 then
+-            assertEquals(openssl.error(),218513530)
++            assertNotNil(openssl.error())
+             o7 =  asn1.new_object(options)
+             assertStrContains(tostring(o7), 'openssl.asn1_object')
+             assertEquals(o7:txt(), options.ln)
+@@ -81,13 +85,16 @@ TestObject = {}
+             first = false
+ 
+             assertIsNil(asn1.new_object(self.ne_sn))
++            assertNotNil(openssl.error())
+             assertIsNil(asn1.new_object(self.ne_ln))
++            assertNotNil(openssl.error())
+             assert(asn1.new_object(self.ne_oid))
+ 
+             o1 = assert(asn1.new_object({oid=self.ne_oid,sn=self.ne_sn,ln=self.ne_ln}))
+             o2 = assert(asn1.new_object(self.ne_oid))
+             assertEquals(o1,o2)
+ 
++            assertNil(openssl.error())
+         else
+             assert(asn1.txt2nid(self.ne_oid))
+ 
+@@ -151,4 +158,4 @@ TestTime = {}
+         assert(at:set(self.time))
+         local t1 = at:get(self.time)
+         assertEquals(self.time,t1)
+-    end
+\ No newline at end of file
++    end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/1.x509_attr.lua luvi-src-v2.7.6/deps/lua-openssl/test/1.x509_attr.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/1.x509_attr.lua	2019-02-13 11:31:40.287301977 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/1.x509_attr.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -36,10 +36,9 @@ TestX509attr = {}
+         local n1 = attr.new_attribute(self.ca)
+         assertStrContains(tostring(n1),'openssl.x509_attribute')
+         local info = n1:info()
+-
+         assertIsTable(info)
+         assertEquals(info.object:ln(), "X509v3 Basic Constraints")
+-        assertEquals(info.single,false)
++        assertEquals(#info.value, 1)
+         assertEquals(info.value[1].type, asn1.OCTET_STRING)
+         assertEquals(info.value[1].value, "CA:FALSE")
+         local n2 = n1:dup()
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/1.x509_extension.lua luvi-src-v2.7.6/deps/lua-openssl/test/1.x509_extension.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/1.x509_extension.lua	2019-02-13 11:31:40.290635288 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/1.x509_extension.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -35,8 +35,9 @@ TestX509ext = {}
+         local info = n1:info()
+         assertIsTable(info)
+         assertEquals(info.object:ln(), "X509v3 Basic Constraints")
+-        assertEquals(info.critical,true)
++        assertEquals(info.critical,false)
+         assertEquals(info.value:tostring(), "CA:FALSE")
++
+         local n2 = n1:dup()
+         assertEquals(n2:info(),info)
+         assertEquals(n1:critical(),false)
+@@ -54,6 +55,7 @@ TestX509ext = {}
+         assertEquals(n1:data(), self.cafalse)
+ 
+         local time = ext.new_extension(self.time)
++        assertEquals(time:critical(),true)
+         local der = time:export()
+         local t1 = ext.read_extension(der)
+         assert(der==t1:export())
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/3.cipher.lua luvi-src-v2.7.6/deps/lua-openssl/test/3.cipher.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/3.cipher.lua	2019-02-13 11:31:40.283968667 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/3.cipher.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -91,7 +91,7 @@ TestCipherMY = {}
+         b = assert(obj1:update(a))
+         b = b..assert(obj1:final())
+         assertEquals(b,self.msg)
+-        assert(#a>#self.msg)
++        assert(#a >= #self.msg)
+ 
+         obj = C:encrypt_new(self.key)
+         aa = assert(obj:update(self.msg))
+@@ -101,7 +101,7 @@ TestCipherMY = {}
+         bb = assert(obj1:update(aa))
+         bb = bb..assert(obj1:final())
+         assertEquals(self.msg,bb)
+-        assert(#self.msg < #aa)
++        assert(#self.msg <= #aa)
+ 
+         local r = openssl.random(16)
+         local k,i = C:BytesToKey(r)
+@@ -113,3 +113,33 @@ TestCipherMY = {}
+         assertEquals(#k,t.key_length)
+         assertEquals(#i,t.iv_length)
+     end
++
++    function TestCipherMY:testAesCTR()
++
++        local C = cipher.get('aes-128-ctr')
++        local key = '0123456789abcefg'
++        local iv = string.rep('\0',16)
++
++        local a,b,c,aa,bb,cc
++        local obj,obj1
++
++        obj = C:new(true,self.key)
++        a = assert(obj:update(self.msg))
++        a = a..obj:final()
++
++        obj1 = C:new(false,self.key)
++        b = assert(obj1:update(a))
++        b = b..assert(obj1:final())
++        assertEquals(b,self.msg)
++        assert(#a>=#self.msg)
++
++        obj = C:encrypt_new(self.key)
++        aa = assert(obj:update(self.msg))
++        aa = aa..assert(obj:final())
++
++        obj1 = C:decrypt_new(self.key)
++        bb = assert(obj1:update(aa))
++        bb = bb..assert(obj1:final())
++        assertEquals(self.msg,bb)
++        assert(#self.msg <= #aa)
++    end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/4.pkey.lua luvi-src-v2.7.6/deps/lua-openssl/test/4.pkey.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/4.pkey.lua	2019-02-13 11:31:40.297301909 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/4.pkey.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -20,7 +20,7 @@ TestPKEYMY = {}
+                 {'ec','prime256v1'}
+         }
+     end
+-
++--[[
+     function TestPKEYMY:testModule()
+         for i,v in ipairs(self.genalg ) do
+                 --print(v)
+@@ -30,7 +30,6 @@ TestPKEYMY = {}
+ 
+                 local t= k:parse()
+                 local len = t.bits/8
+-                --print_r(t)
+ 
+                 local msg = openssl.random(len-11)
+                 if t.type=='rsa' then
+@@ -54,17 +53,16 @@ TestPKEYMY = {}
+ 
+                 assert(k1:export():find('^-----BEGIN PUBLIC KEY-----'))
+ 
+-                assert(string.len(k:export(true,true))>0)
+-
+-                assert(string.len(k:export(true,true))>0)
+-                assert(string.len(k:export(true,false))>0)
+-                assert(string.len(k:export(false))>0)
++                assert(string.len(k:export('pem',true))>0)
+ 
+-                assert(string.len(k:export(true,true,'secret'))>0)
++                assert(string.len(k:export('pem',true))>0)
++                assert(string.len(k:export('pem',false))>0)
++                assert(string.len(k:export('der'))>0)
+ 
+-                assert(string.len(k:export(true,false,'secret'))>0)
+-                assert(string.len(k:export(false,'secret'))>0)
++                assert(string.len(k:export('pem',true,'secret'))>0)
+ 
++                assert(string.len(k:export('pem',false,'secret'))>0)
++                assert(string.len(k:export('der',false,'secret'))>0)
+         end
+     end
+ 
+@@ -84,17 +82,16 @@ TestPKEYMY = {}
+         assert(t.e)
+         t.alg = 'rsa'
+         local r2 = pkey.new(t)
+-        assert(r2:is_private()==false)
++        assert(not r2:is_private())
+         local msg = openssl.random(128-11)
+ 
+         local out = pkey.encrypt(r2,msg)
+         local raw = pkey.decrypt(rsa,out)
+         assert(msg==raw)
+     end
+-
+-    function testRsaFmt()
++--]]
++    function testKeyFmt()
+     local keys = {
+-
+ RSA= {[[
+ -----BEGIN PRIVATE KEY-----
+ MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet
+@@ -114,6 +111,7 @@ mu/UpE/BRZmR
+ -----END PRIVATE KEY-----
+ ]],
+ "3082025D02010002818100BB247A097E0EB23732CC3967ADF19E3D6B8283D1D0ACA4C018BE8D9800C07BFF0744C9CA1CBA36E12769FFB1E38D8BEE57A93AAA16433954197CAE692414F664FFBC74C6676C4CF1024969C72BE1E1A1A34314F4778FC8D0855A3595AC62A9C1210077A08B9730B45A2CB8902F48A005284BF20F8DEC8B4D034275D6AD81C011020301000102818000FCB94A260789512B537291E0183EA65E31EF9C0C162442D02833F9FAD03C540406C015F51B9AB32431AB3C6B4743B0D2A9DC05E18159B604E96661AAD70B008F3DE5BFA2F85E256C1E220FB4FD41E203315FDA20C5C0F3550EE1C9ECD73E2A0C01CA7B22CBACF42B27F0785FB5C2F9E8145A6E7E86BD6A9B200CBACC972011024100C9599F298A5B9FE32AD87EC2409FA845E53E118D3CED6EABCED06546D8C70763B52334F49F7E1CC7C7F965D1F4044238BE3A0C9D0825FCA371D9AE0C3961F489024100EDEFABA9D5399CEE591BFFCF48441BB632E74624F3047FDE95086D759E6717BA5CA4D4E2E24D77CEEB6629C596E062BBE5ACDC44625486ED640CCED060039D49024054D9187227E4BE76BB1A6A282F955812C42CA8B6CCE2FD0D1764C818D7C6DF3D4C1A9EF92AB0B92E12FDECC351C1EDA9FDB7769341D8C822941A77F69CC3C3890241008EF9A708ADB52A04DB8D04A1B5062034D2CFC089B17231B8398BCFE28EA5DA4F451E534266C4304B298EC16917298C8AE60F8268A141B3B6709975A92718E4E902410089EA6E6D70DF255F183F48DA63108BFEA80C940FDE9756538994E21E2C743C9181340BA640F8CB2A608CE002B78993CF189F4954FD7D3F9AEFD4A44FC1459991",
++"30819F300D06092A864886F70D010101050003818D0030818902818100BB247A097E0EB23732CC3967ADF19E3D6B8283D1D0ACA4C018BE8D9800C07BFF0744C9CA1CBA36E12769FFB1E38D8BEE57A93AAA16433954197CAE692414F664FFBC74C6676C4CF1024969C72BE1E1A1A34314F4778FC8D0855A3595AC62A9C1210077A08B9730B45A2CB8902F48A005284BF20F8DEC8B4D034275D6AD81C0110203010001",
+ "30818902818100BB247A097E0EB23732CC3967ADF19E3D6B8283D1D0ACA4C018BE8D9800C07BFF0744C9CA1CBA36E12769FFB1E38D8BEE57A93AAA16433954197CAE692414F664FFBC74C6676C4CF1024969C72BE1E1A1A34314F4778FC8D0855A3595AC62A9C1210077A08B9730B45A2CB8902F48A005284BF20F8DEC8B4D034275D6AD81C0110203010001"
+ },
+ 
+@@ -126,7 +124,8 @@ zo0MUVPQgwJ3aJtNM1QMOQUayCrRwfklg+D/rFSU
+ -----END PRIVATE KEY-----
+ ]],
+ '30770201010420622AD3652C7EE4EF18EAD9467246BA5BA6ED262A1C76B76895F72E912A13124FA00A06082A8648CE3D030107A1440342000424BCF36EECF6B519CB16538BFBA6D35FA82255ABC0B1CE8D0C5153D0830277689B4D33540C39051AC82AD1C1F92583E0FFAC5494C0452AB5987B7C90E216ACF7',
+-'0424BCF36EECF6B519CB16538BFBA6D35FA82255ABC0B1CE8D0C5153D0830277689B4D33540C39051AC82AD1C1F92583E0FFAC5494C0452AB5987B7C90E216ACF7'
++"3059301306072A8648CE3D020106082A8648CE3D0301070342000424BCF36EECF6B519CB16538BFBA6D35FA82255ABC0B1CE8D0C5153D0830277689B4D33540C39051AC82AD1C1F92583E0FFAC5494C0452AB5987B7C90E216ACF7",
++'3059301306072A8648CE3D020106082A8648CE3D0301070342000424BCF36EECF6B519CB16538BFBA6D35FA82255ABC0B1CE8D0C5153D0830277689B4D33540C39051AC82AD1C1F92583E0FFAC5494C0452AB5987B7C90E216ACF7'
+ },
+ --]=]
+ DSA={
+@@ -142,103 +141,154 @@ vgPnEUG6Mk9bkxMZKRgsiKn6QGKDYGbOvnS1xmkM
+ -----END PRIVATE KEY-----
+ ]],
+ '308201BC02010002818100AA0930CC145825221CAFFA28AC2894196A27833DE5EC212707916894207774A2E7B238B0D36F1B2499A2C2585083EB01432924418D867FAA212DD1071D4DCEB2782794AD393CC08A4D4ADA7F68D6E839A5FCD34B4E402D82CB8A8CB40FEC31911BF9BD360B034CAACB4C5E947992573C9E90099C1B0F05940CABE5D2DE49A167021500ADC0E869B36F0AC013A681FDF4D4899D69820451028181008C6B4589AFA53A4D1048BFC346D1F386CA75521CCF72DDAA251286880EE13201FF48890BBFC33D79BACAEC71E7A778507BD5F1A66422E39415BE03E71141BA324F5B93131929182C88A9FA4062836066CEBE74B5C6690C7D101106C240AB7EBD54E4E3301FD086CE6ADAC922FB2713A2B0887CBA13B9BC68CE5CFFF241CD32460281802B260EA97DC6A12AE932C640E7DF3D8FF04A8A05A0324F8D5F1B23F15FA170FF3F42061124EFF2586CB11B49A82DCDC1B90FC6A84FB10109CB67DB5D2DA971AEAF17BE5E37284563E4C64D9E5FC8480258B319F0DE29D54D835070D9E287914D77DF81491F4423B62DA984EB3F45EB2A29FCEA5DAE525AC6AB6BCCE04BFDF5B6021500A535A8E1D0D91BEAFC8BEE1D9B2A3A8DE3311203',
+-'0281802B260EA97DC6A12AE932C640E7DF3D8FF04A8A05A0324F8D5F1B23F15FA170FF3F42061124EFF2586CB11B49A82DCDC1B90FC6A84FB10109CB67DB5D2DA971AEAF17BE5E37284563E4C64D9E5FC8480258B319F0DE29D54D835070D9E287914D77DF81491F4423B62DA984EB3F45EB2A29FCEA5DAE525AC6AB6BCCE04BFDF5B6'
++"308201B73082012C06072A8648CE3804013082011F02818100AA0930CC145825221CAFFA28AC2894196A27833DE5EC212707916894207774A2E7B238B0D36F1B2499A2C2585083EB01432924418D867FAA212DD1071D4DCEB2782794AD393CC08A4D4ADA7F68D6E839A5FCD34B4E402D82CB8A8CB40FEC31911BF9BD360B034CAACB4C5E947992573C9E90099C1B0F05940CABE5D2DE49A167021500ADC0E869B36F0AC013A681FDF4D4899D69820451028181008C6B4589AFA53A4D1048BFC346D1F386CA75521CCF72DDAA251286880EE13201FF48890BBFC33D79BACAEC71E7A778507BD5F1A66422E39415BE03E71141BA324F5B93131929182C88A9FA4062836066CEBE74B5C6690C7D101106C240AB7EBD54E4E3301FD086CE6ADAC922FB2713A2B0887CBA13B9BC68CE5CFFF241CD3246038184000281802B260EA97DC6A12AE932C640E7DF3D8FF04A8A05A0324F8D5F1B23F15FA170FF3F42061124EFF2586CB11B49A82DCDC1B90FC6A84FB10109CB67DB5D2DA971AEAF17BE5E37284563E4C64D9E5FC8480258B319F0DE29D54D835070D9E287914D77DF81491F4423B62DA984EB3F45EB2A29FCEA5DAE525AC6AB6BCCE04BFDF5B6",
++"308201B73082012C06072A8648CE3804013082011F02818100AA0930CC145825221CAFFA28AC2894196A27833DE5EC212707916894207774A2E7B238B0D36F1B2499A2C2585083EB01432924418D867FAA212DD1071D4DCEB2782794AD393CC08A4D4ADA7F68D6E839A5FCD34B4E402D82CB8A8CB40FEC31911BF9BD360B034CAACB4C5E947992573C9E90099C1B0F05940CABE5D2DE49A167021500ADC0E869B36F0AC013A681FDF4D4899D69820451028181008C6B4589AFA53A4D1048BFC346D1F386CA75521CCF72DDAA251286880EE13201FF48890BBFC33D79BACAEC71E7A778507BD5F1A66422E39415BE03E71141BA324F5B93131929182C88A9FA4062836066CEBE74B5C6690C7D101106C240AB7EBD54E4E3301FD086CE6ADAC922FB2713A2B0887CBA13B9BC68CE5CFFF241CD3246038184000281802B260EA97DC6A12AE932C640E7DF3D8FF04A8A05A0324F8D5F1B23F15FA170FF3F42061124EFF2586CB11B49A82DCDC1B90FC6A84FB10109CB67DB5D2DA971AEAF17BE5E37284563E4C64D9E5FC8480258B319F0DE29D54D835070D9E287914D77DF81491F4423B62DA984EB3F45EB2A29FCEA5DAE525AC6AB6BCCE04BFDF5B6",
+ }
+ }
+ 
+         for k,v in pairs(keys) do
+-                print(string.format('Test %s export format',k))
+-
+                 local pri = pkey.read(v[1], true, 'pem')
+                 local pub = assert(pri:get_public())
+-                -- evp_pkey:export ([pem=true[, raw_key=false[, passphrase]]])
+ 
+-                --begin test pem format
+-                -- pem=true, raw_key=false, passphrase=nil
++                -- evp_pkey:export ([format='pem'[, raw=false[, passphrase]]])
++
++                -- private
++                --1 format='pem', raw=false, passphrase=nil
+                 local pem1  = pri:export()
+                 assertStrContains(pem1,'-----BEGIN PRIVATE KEY-----')
+                 assertStrContains(pem1,'-----END PRIVATE KEY-----')
+ 
+-                local pem1  = pri:export(true)
++                local pem1  = pri:export('pem')
+                 assertStrContains(pem1,'-----BEGIN PRIVATE KEY-----')
+                 assertStrContains(pem1,'-----END PRIVATE KEY-----')
+ 
+-                local pem1  = pri:export(true, false)
++                local pem1  = pri:export('pem', false)
+                 assertStrContains(pem1,'-----BEGIN PRIVATE KEY-----')
+                 assertStrContains(pem1,'-----END PRIVATE KEY-----')
+ 
+-                local k1 = pkey.read(pem1,true)
++                local k1 = pkey.read(pem1, true)
+                 assertEquals(pri:export(),k1:export())
+ 
+-                -- pem=true, raw_key=false, export_private=false, passphrase=nil
+-                local pem1  = pub:export(true)
+-                assertStrContains(pem1,'-----BEGIN PUBLIC KEY-----')
+-                assertStrContains(pem1,'-----END PUBLIC KEY-----')
+-
+-                local k2 = pkey.read(pem1,false)
+-                assertEquals(pub:export(),k2:export())
+-
+-                -- pem=true, raw_key=false, export_private=true, passphrase='secret'
+-                local pem3  = pri:export(true, false,'secret')
++                -- format='pem', raw=false, passphrase='secret'
++                local pem3  = pri:export('pem', false,'secret')
+                 assertStrContains(pem3,'-----BEGIN ENCRYPTED PRIVATE KEY-----')
+                 assertStrContains(pem3,'-----END ENCRYPTED PRIVATE KEY-----')
+ 
+-                --ispriv = true,
+                 local k2 = pkey.read(pem3, true, 'pem','secret')
+                 assertEquals(pri:export(),k2:export())
+ 
+-                -- pem=true, raw_key=true, passphrase=nil
+-                local pem2  = pri:export(true, true)
++                --2 format='pem', raw=true, passphrase=nil
++                local pem2  = pri:export('pem', true)
+                 assertStrContains(pem2,'-----BEGIN '..k..' PRIVATE KEY-----')
+                 assertStrContains(pem2,'-----END '..k..' PRIVATE KEY-----')
+                 assertNotStrContains(pem2,'Proc-Type: 4,ENCRYPTED')
+                 assertNotStrContains(pem2,'DEK-Info: DES-EDE3-CBC,')
+ 
+-                local k2 = pkey.read(pem2,true,'pem')
++                local k2 = pkey.read(pem2, true, 'pem')
+                 assertEquals(pri:export(),k2:export())
+ 
+-                -- pem=true, raw_key=true, passphrase=nil
+-                if k~='EC' and k~='DSA' then
+-                        local pem2  = pub:export(true, true)
+-                        assertStrContains(pem2,'-----BEGIN '..k..' PUBLIC KEY-----')
+-                        assertStrContains(pem2,'-----END '..k..' PUBLIC KEY-----')
+-                        local k2 = pkey.read(pem2, false,'pem',k)
+-                        --pem=true,raw_key=true
+-                        assertEquals(pem2,k2:export(true,true))
+-                end
+-                -- pem=true, raw_key=true, export_private=true, passphrase='secret'
+-                local pem4  = pri:export(true, true, 'secret')
++                -- format='pem' raw=true,  passphrase='secret'
++                local pem4  = pri:export('pem', true, 'secret')
+                 assertStrContains(pem4,'-----BEGIN '..k..' PRIVATE KEY-----')
+                 assertStrContains(pem4,'Proc-Type: 4,ENCRYPTED')
+                 assertStrContains(pem4,'DEK-Info: DES-EDE3-CBC,')
+                 assertStrContains(pem4,'-----END '..k..' PRIVATE KEY-----')
++
+                 local k2 = pkey.read(pem4,true,'pem','secret')
+                 assertEquals(pri:export(),k2:export())
+-                --end of pem test
+ 
+-                --test der
+-                -- pem=false, export_private=true, passphrase=nil
+-                local export = pri:export(false)
++                --3 format='der', raw=false, passphrase=nil
++                local export = pri:export('der')
++                local hex = openssl.hex(export)
++                assertEquals(hex:upper(),v[2])
++
++                local k2 = pkey.read(export,true,'der')
++                assertEquals(pri:export(),k2:export())
++
++                local export = pri:export('der',false)
+                 local hex = openssl.hex(export)
+                 assertEquals(hex:upper(),v[2])
+ 
+                 local k2 = pkey.read(export,true,'der')
+                 assertEquals(pri:export(),k2:export())
+ 
+-                -- pem=false, export_private=false, passphrase=nil
+-                local export = pub:export(false)
++                local export = pri:export('der', nil)
++                local hex = openssl.hex(export)
++                assertEquals(hex:upper(),v[2])
++
++                local k2 = pkey.read(export,true,'der')
++                assertEquals(pri:export(),k2:export())
++
++                -- pem=false, raw=false, passphrase='secret'
++                local export = pri:export('der',false,'secret')
++                local k2 = pkey.read(export,true,'der','secret')
++                assertEquals(pri:export(),k2:export())
++
++                local export = pri:export('der', nil, 'secret')
++                local k2 = pkey.read(export,true,'der','secret')
++                assertEquals(pri:export(),k2:export())
++
++                --4 pem=false, raw=true, passphrase=nil
++                local export = pri:export('der', true)
++                local hex = openssl.hex(export)
++                assertEquals(hex:upper(),v[2])
++
++                local k2 = pkey.read(export,true,'der', k)
++                assertEquals(pri:export(),k2:export())
++
++                -------------------------------
++                -- public
++                --1 format='pem', raw=false, passphrase=nil
++                local pem1  = pub:export()
++                assertEquals(pem1,  pub:export('pem'))
++                assertStrContains(pem1,'-----BEGIN PUBLIC KEY-----')
++                assertStrContains(pem1,'-----END PUBLIC KEY-----')
++
++                local k2 = pkey.read(pem1,false)
++                assertEquals(pub:export(),k2:export())
++
++                --2 format='pem', raw=true, passphrase=nil
++                local pem2  = pub:export('pem', true)
++                if k~="EC" and k~='DSA' then
++                        assertStrContains(pem2,'-----BEGIN '..k..' PUBLIC KEY-----')
++                        assertStrContains(pem2,'-----END '..k..' PUBLIC KEY-----')
++                end
++                local k2 = pkey.read(pem2, false, 'pem', k)
++                assertEquals(pub:export(),k2:export())
++
++                --3 format='der', raw=false, passphrase=nil
++                local export = pub:export('der')
+                 local hex = openssl.hex(export)
+                 assertEquals(hex:upper(),v[3])
+ 
+-                if k~='EC' and k~='DSA' then
+-                        local k1 = assert(pkey.read(export, false,'der',k))
+-                        local p1 = k1:export()
+-                        assertEquals(p1,pub:export())
++                local export = pub:export('der', false)
++                local k2 = pkey.read(export,false,'der')
++                assertEquals(hex:upper(),v[3])
++                assertEquals(pub:export(),k2:export())
++
++                local k2 = pkey.read(export, nil,'der')
++                assertEquals(pub:export(),k2:export())
++
++                --4 format='der', raw=true, passphrase=nil
++                
++                local export = pub:export('der', true)
++                local hex = openssl.hex(export)
++                if (hex:upper()~=v[4]) then
++                  print('XXXXXXXXX', k)
++                  print('PUB:', hex)
++                  print('---:', v[4])
++                end
++                assertEquals(hex:upper(),v[4])
++
++                if (k~='EC' and k~='DSA') then
++                        local k1 = assert(pkey.read(export, false,'der', k))
++                        local p1 = k1:export('der', true)
++                        assertEquals(p1, export)
++                        assertEquals(k1:export(), pub:export())
+                 end
+-                -- pkcs8 der
+-                -- pem=false, export_private=true, passphrase='secret'
+-                local export = pri:export(false,'secret')
+-                local k1 = pkey.read(export,true,'der','secret')
+-                assertEquals(pri:export(),k1:export())
+         end
+     end
++
++--""    #EXPORT_ASSERT_TO_GLOBALS = true
++--""    #require'luaunit'
++--""    #    LuaUnit.run()
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/5.ts.lua luvi-src-v2.7.6/deps/lua-openssl/test/5.ts.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/5.ts.lua	2019-02-13 11:31:40.290635288 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/5.ts.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -2,58 +2,499 @@ local openssl = require'openssl'
+ 
+ local asn1,ts,asn1,csr = openssl.asn1,openssl.ts,openssl.asn1, openssl.x509.req
+ 
+-local timeStamping = openssl.asn1.new_string('timeStamping',asn1.OCTET_STRING)
+-local timeStamping=asn1.new_type('timeStamping')
+-timeStamping = timeStamping:i2d()
+-local cafalse = openssl.asn1.new_string('CA:FALSE',asn1.OCTET_STRING)
++
++testTSRequest = {}
++
++    function testTSRequest:setUp()
++        self.msg = 'abcd'
++        self.alg = 'sha1'
++        self.hash = assert(openssl.digest.digest(self.alg, self.msg, true))
++    end
++
++    function testTSRequest:testReq1()
++        local req = assert(openssl.ts.req_new())
++        assert(req:msg_imprint(self.hash, self.alg))
++        assert(req:cert_req(true))
++        local der = assert(req:export())
++        local req1 = assert(ts.req_read(der))
++        local t = req1:info()
++        assertIsTable(t)
++        assertEquals(t.cert_req,true)
++        assertEquals(t.version,1)
++        assertEquals(t.msg_imprint.hashed_msg,self.hash)
++        assertEquals(t.msg_imprint.hash_algo:tostring(), self.alg)
++        return req
++    end
++
++    function testTSRequest:testReq2()
++        local req = assert(openssl.ts.req_new())
++        assert(req:msg_imprint(self.hash, self.alg))
++        local nonce = openssl.bn.text(openssl.random(16))
++        assert(req:nonce(nonce))
++
++        local der = assert(req:export())
++        local req1 = assert(ts.req_read(der))
++        local t = req1:info()
++        assertIsTable(t)
++        assertEquals(t.cert_req,false)
++        assertEquals(t.version,1)
++
++        assertEquals(t.nonce:data(), nonce:totext())
++        assertEquals(t.msg_imprint.hashed_msg,self.hash)
++        assertEquals(t.msg_imprint.hash_algo:tostring(), self.alg)
++        self.nonce = nonce
++        return req
++    end
++
++    function testTSRequest:testReq3()
++        local req = assert(openssl.ts.req_new())
++        assert(req:msg_imprint(self.hash, self.alg))
++        local nonce = openssl.bn.text(openssl.random(16))
++        assert(req:nonce(nonce))
++
++        local oid = '1.2.3.4.100'
++
++        local obj = assert(asn1.new_object(oid))
++        assert(req:policy_id(obj))
++
++        local der = assert(req:export())
++        local req1 = assert(ts.req_read(der))
++        local t = req1:info()
++        assertIsTable(t)
++        assertEquals(t.cert_req,false)
++        assertEquals(t.version,1)
++
++        assertEquals(t.nonce:data(), nonce:totext())
++        assertEquals(t.policy_id:data(), oid)
++        assertEquals(t.msg_imprint.hashed_msg,self.hash)
++        assertEquals(t.msg_imprint.hash_algo:tostring(), self.alg)
++        return req
++    end
+ 
+ local first = true
+-TestTS = {}
+-    function TestTS:setUp()
+-        self.alg='sha1'
++testTSSign = {}
+ 
+-        self.cadn = {{commonName='CA'},{C='CN'}}
+-        self.tsadn = {{commonName='tsa'},{C='CN'}}
++    function testTSSign:setUp()
++        local timeStamping = openssl.asn1.new_string('timeStamping',asn1.OCTET_STRING)
++        local timeStamping=asn1.new_type('timeStamping')
++        self.timeStamping = timeStamping:i2d()
++        self.cafalse = openssl.asn1.new_string('CA:FALSE',asn1.OCTET_STRING)
+ 
++        self.dat=[[
++[test]
++basicConstraints=CA:FALSE
++keyUsage = nonRepudiation, digitalSignature, keyEncipherment
++extendedKeyUsage = critical,timeStamping
++]]
++        self.alg='sha1'
+         self.digest = 'sha1WithRSAEncryption'
+         self.md = openssl.digest.get('sha1WithRSAEncryption')
++        self.hash = assert(self.md:digest(self.dat))
++        if first then
++            assert(asn1.new_object({oid='1.2.3.4.5.6',sn='1.2.3.4.5.6_sn',ln='1.2.3.4.5.6_ln'}))
++            assert(asn1.new_object({oid='1.2.3.4.5.7',sn='1.2.3.4.5.7_sn',ln='1.2.3.4.5.7_ln'}))
++            first = false
++        end
++
++        --setUp private key and certificate
++        local ca = {}
++        self.ca = ca
++        ca.dn = {{commonName='CA'},{C='CN'}}
++        ca.pkey = assert(openssl.pkey.new())
++        local subject = assert(openssl.x509.name.new(ca.dn))
++        ca.req = assert(csr.new(subject,ca.pkey))
++        ca.cert = assert(ca.req:to_x509(ca.pkey))
++
++        local attributes =
++        {
++            {
++                object='basicConstraints',
++                type=asn1.OCTET_STRING,
++                value=cafalse
++            }
++        }
++        local extensions =
++        {
++            openssl.x509.extension.new_extension(
++            {
++            object='extendedKeyUsage',
++            value = 'timeStamping',
++            critical = true
++        })}
++
++        local tsa = {}
++        self.tsa = tsa
++        tsa.dn  = {{commonName='tsa'},{C='CN'}}
++        tsa.pkey = assert(openssl.pkey.new())
++        subject = openssl.x509.name.new(tsa.dn)
++
++        tsa.req = csr.new(subject,tsa.pkey)
++        assertEquals(type(tsa.req:parse()),'table')
++
++        tsa.cert = openssl.x509.new(1, tsa.req)
++        assert(tsa.cert:validat(os.time(), os.time() + 3600*24*365))
++        assert(tsa.cert:extensions(extensions))
++        assert(tsa.cert:sign(ca.pkey,ca.cert))
++
++        assertEquals(type(tsa.cert:parse()),'table')
++
++        ca.store = openssl.x509.store.new({ca.cert})
++        assert(tsa.cert:check(ca.store,nil,'timestamp_sign'))
++
++        local args = {}
++        args.attribs = {}
++        args.extentions = {}
++        args.digest = 'sha1WithRSAEncryption'
++        args.num_days = 3650
++        args.serialNumber = 1
++    end
++
++
++    function testTSSign:testSign1()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq1()
++
++        local tsa = self.tsa
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey))
++        assert(req_ctx:md({'md5','sha1'}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++        assert(t.status_info.status:tostring()=='02')
++        assertEquals(#t.status_info.text,1)
++        assertEquals(t.status_info.text[1],'Error during response generation.')
++    end
++
++    function testTSSign:testSign2()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq2()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.5.7'
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, oid))
++        assert(req_ctx:md({'md5','sha1'}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),'01')
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++
++        local now = os.time()
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++
++        local res = assert(openssl.ts.resp_read(res:export()))
++        local vry = assert(req:to_verify_ctx())
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++    end
++
++    function testTSSign:testSign3()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq3()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.100'
++        local obj = assert(asn1.new_object(oid))
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, obj))
++        assert(req_ctx:md({'md5','sha1'}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),'01')
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++
++        local now = os.time()
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++
++        local res = assert(openssl.ts.resp_read(res:export()))
++        local vry = assert(req:to_verify_ctx())
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++    end
++
++    function testTSSign:testSign4()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq3()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.100'
++        local obj = assert(asn1.new_object(oid))
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, obj))
++        assert(req_ctx:md({'md5','sha1'}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),'01')
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++
++        local now = os.time()
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++
++        local res = assert(openssl.ts.resp_read(res:export()))
++        local vry = ts.verify_ctx_new(req)
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++    end
++
++    function testTSSign:testSign5()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq3()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.100'
++        local obj = assert(asn1.new_object(oid))
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, obj))
++        assert(req_ctx:md({'md5','sha1'}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),'01')
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++
++        local now = os.time()
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++
++        local vry = assert(ts.verify_ctx_new())
++        vry:imprint(self.hash)
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++    end
++
++    function testTSSign:testSign6()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq3()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.100'
++        local obj = assert(asn1.new_object(oid))
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, obj))
++        assert(req_ctx:md({'md5','sha1'}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),'01')
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++
++        local now = os.time()
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++
++        local vry = assert(ts.verify_ctx_new())
++        vry:data(self.dat)
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++    end
++
++    function testTSSign:testSign7()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq3()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.100'
++        local obj = assert(asn1.new_object(oid))
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, obj))
++        assert(req_ctx:md({'md5','sha1'}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),'01')
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++
++        local now = os.time()
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++
++        local vry = assert(ts.verify_ctx_new())
++        vry:imprint(self.hash)
++        vry:data(self.dat)
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++    end
++
++    function testTSSign:testSign8()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq3()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.100'
++        local obj = assert(asn1.new_object(oid))
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, obj))
++        assert(req_ctx:md({'md5','sha1'}))
++        assert(req_ctx:policies({assert(asn1.new_object('1.1.3')),assert(asn1.new_object('1.1.4'))}))
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),'01')
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++        local now = os.time()
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++
++        local vry = assert(ts.verify_ctx_new())
++        vry:imprint(self.hash)
++        vry:data(self.dat)
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++    end
++
++testTSComplex = {}
++
++    function testTSComplex:setUp()
++        local timeStamping = openssl.asn1.new_string('timeStamping',asn1.OCTET_STRING)
++        local timeStamping=asn1.new_type('timeStamping')
++        self.timeStamping = timeStamping:i2d()
++        self.cafalse = openssl.asn1.new_string('CA:FALSE',asn1.OCTET_STRING)
++
+         self.dat=[[
+ [test]
+ basicConstraints=CA:FALSE
+ keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+ extendedKeyUsage = critical,timeStamping
+ ]]
++        self.alg='sha1'
++        self.digest = 'sha1WithRSAEncryption'
++        self.md = openssl.digest.get('sha1WithRSAEncryption')
+         self.hash = assert(self.md:digest(self.dat))
+         if first then
+             assert(asn1.new_object({oid='1.2.3.4.5.6',sn='1.2.3.4.5.6_sn',ln='1.2.3.4.5.6_ln'}))
+             assert(asn1.new_object({oid='1.2.3.4.5.7',sn='1.2.3.4.5.7_sn',ln='1.2.3.4.5.7_ln'}))
+             first = false
+         end
+-    end
+ 
+-function TestTS:testAll()
+-    local args = {}
+-    args.attribs = {}
+-    args.extentions = {}
+-    args.digest = 'sha1WithRSAEncryption'
+-    args.num_days = 3650
+-    args.serialNumber = 1
+-
+-    local cakey = assert(openssl.pkey.new())
+-    local careq = assert(csr.new(openssl.x509.name.new(self.cadn),cakey))
+-    local cacert = assert(careq:to_x509(cakey))
+-
+-    local pkey = assert(openssl.pkey.new())
+-    local subject = openssl.x509.name.new(self.tsadn)
+-    local attributes =
++        --setUp private key and certificate
++        local ca = {}
++        self.ca = ca
++        ca.dn = {{commonName='CA'},{C='CN'}}
++        ca.pkey = assert(openssl.pkey.new())
++        local subject = assert(openssl.x509.name.new(ca.dn))
++        ca.req = assert(csr.new(subject,ca.pkey))
++        ca.cert = assert(ca.req:to_x509(ca.pkey))
++
++        local attributes =
++        {
+             {
+-                {
+-                    object='basicConstraints',
+-                    type=asn1.OCTET_STRING,
+-                    value=cafalse
+-                }
++                object='basicConstraints',
++                type=asn1.OCTET_STRING,
++                value=cafalse
+             }
+-    local extensions =
++        }
++        local extensions =
+         {
+             openssl.x509.extension.new_extension(
+             {
+@@ -61,75 +502,86 @@ function TestTS:testAll()
+             value = 'timeStamping',
+             critical = true
+         })}
+-    x = csr.new(
+-        subject,
+-        pkey
+-        )
+-    t = assert(x:parse())
+-    assertEquals(type(t),'table')
+-    --print_r(t)
+-
+-    local x509 = openssl.x509.new(
+-        1,
+-        x
+-    )
+-    assert(x509:validat(os.time(), os.time() + 3600*24*365))
+-    assert(x509:extensions(extensions))
+-    assert(x509:sign(cakey,cacert))
+-    t = assert(x509:parse())
+-    assertEquals(type(t),'table')
+-    --print_r(t)
+-
+-    ---------------------------------------------------
+-    local req = assert(openssl.ts.req_new())
+-    assert(req:msg_imprint(self.hash,'sha1'))
+-    assert(req:cert_req(true))
+-    local der = assert(req:export())
+-    local req1 = assert(ts.req_read(der))
+-    local t = req1:info()
+-    assertIsTable(t)
+-    --print_r(t)
+-
+-    local req_ctx = assert(ts.resp_ctx_new(x509, pkey, '1.2.3.4.5.7'))
+-    assert(req_ctx:md({'md5','sha1'}))
+-    --assert(req_ctx:policies({'1.1.3','1.1.4'}))
+-    local res = req_ctx:sign(req)
+-
+-    t = assert(res:info())
+-    assertIsTable(t)
+-    --print_r(t)
+-    t = res:tst_info()
+-    assertIsTable(t)
+-    --print_r(t)
+-
+-    local skx = openssl.x509.store.new({cacert})
+-
+-    assert(x509:check(skx,nil,'timestamp_sign'))
+-
+-    local res = assert(openssl.ts.resp_read(res:export()))
+-    local vry = assert(req:to_verify_ctx())
+-    assert(vry:store(skx))
+-    assert(vry:verify(res))
+-
+-    local vry = ts.verify_ctx_new(req)
+-    assert(vry:store(skx))
+-    assert(vry:verify(res))
+-
+-    local vry = assert(ts.verify_ctx_new())
+-    assert(vry:imprint(self.hash))
+-    assert(vry:store(skx))
+-    assert(vry:verify(res))
+-
+-    local vry = assert(ts.verify_ctx_new())
+-    assert(vry:data(self.dat))
+-    assert(vry:store(skx))
+-    assert(vry:verify(res))
+-
+-    local vry = assert(ts.verify_ctx_new())
+-    assert(vry:imprint(self.hash))
+-    assert(vry:data(self.dat))
+-    assert(vry:store(skx))
+-    assert(vry:verify(res))
+-    res = ts.resp_read(res:export())
+-    vry:verify(res)
+-end
++
++        local tsa = {}
++        self.tsa = tsa
++        tsa.dn  = {{commonName='tsa'},{C='CN'}}
++        tsa.pkey = assert(openssl.pkey.new())
++        subject = openssl.x509.name.new(tsa.dn)
++
++        tsa.req = csr.new(subject,tsa.pkey)
++        assertEquals(type(tsa.req:parse()),'table')
++
++        tsa.cert = openssl.x509.new(1, tsa.req)
++        assert(tsa.cert:validat(os.time(), os.time() + 3600*24*365))
++        assert(tsa.cert:extensions(extensions))
++        assert(tsa.cert:sign(ca.pkey,ca.cert))
++
++        assertEquals(type(tsa.cert:parse()),'table')
++
++        ca.store = openssl.x509.store.new({ca.cert})
++        assert(tsa.cert:check(ca.store,nil,'timestamp_sign'))
++
++        local args = {}
++        args.attribs = {}
++        args.extentions = {}
++        args.digest = 'sha1WithRSAEncryption'
++        args.num_days = 3650
++        args.serialNumber = 1
++    end
++
++    function testTSComplex:testCallback()
++        testTSRequest:setUp()
++        local req = testTSRequest:testReq3()
++
++        local tsa = self.tsa
++        local oid = '1.2.3.4.100'
++        local obj = assert(asn1.new_object(oid))
++        local req_ctx = assert(ts.resp_ctx_new(tsa.cert, tsa.pkey, obj))
++        assert(req_ctx:md({'md5','sha1'}))
++        assert(req_ctx:policies({assert(asn1.new_object('1.1.3')),assert(asn1.new_object('1.1.4'))}))
++
++        local sn = 0
++        req_ctx:set_serial_cb(function(self)
++            sn = sn + 1
++            return sn
++        end)
++
++        local now = os.time()
++        req_ctx:set_time_cb(function(self)
++            return now
++        end)
++
++        assert(pcall(function()
++        local res = req_ctx:sign(req)
++        t = assert(res:info())
++        assertIsTable(t)
++
++        assert(t.status_info.status:tostring()=='0')
++        assert(not t.status_info.text)
++        assert(not t.status_info.failure_info)
++        assertIsTable(t.tst_info)
++        assertIsUserdata(t.token)
++
++        local tst = t.tst_info
++        assertEquals(tst.serial:tostring(),string.format('%02x',sn))
++        assertEquals(tst.version,1)
++        assertEquals(tst.ordering,false)
++        assertEquals(tst.policy_id:txt(true),oid)
++
++        local function get_timezone()
++          local now = os.time()
++          return os.difftime(now, os.time(os.date("!*t", now)))
++        end
++        timezone = get_timezone()
++
++        assertEquals(tst.time:tostring(),os.date('%Y%m%d%H%M%SZ',now-timezone))
++        assertIsString(tst.nonce:tostring())
++        local vry = assert(ts.verify_ctx_new())
++        vry:imprint(self.hash)
++        vry:data(self.dat)
++        vry:store(self.ca.store)
++        assert(vry:verify(res))
++
++        end))
++    end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/5.x509.lua luvi-src-v2.7.6/deps/lua-openssl/test/5.x509.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/5.x509.lua	2019-02-13 11:31:40.293968598 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/5.x509.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -2,6 +2,8 @@ local openssl = require'openssl'
+ 
+ local csr,x509 = openssl.x509.req, openssl.x509
+ 
++local helper = require('helper')
++
+ TestX509 = {}
+     function TestX509:setUp()
+         self.alg='sha1'
+@@ -13,33 +15,24 @@ TestX509 = {}
+     end
+ 
+ function TestX509:testNew()
+-        --cacert, self sign
+-        local pkey = assert(openssl.pkey.new())
+-        local req = assert(csr.new(self.cadn,pkey))
+-        local t = req:parse()
+-        assertEquals(type(t),'table')
+-
+-        local cacert = openssl.x509.new(
+-                1,      --serialNumber
+-                req     --copy name and extensions
+-        )
+-
+-        cacert:validat(os.time(), os.time() + 3600*24*365)
+-        assert(cacert:sign(pkey, cacert))  --self sign
++        local pkey, cacert = helper.new_ca(self.cadn)
+         assertEquals(cacert:subject(), cacert:issuer())
++        assert(cacert:parse().ca, 'invalid ca certificate')
+ 
+         local c = cacert:pubkey():encrypt('abcd')
+         d = pkey:decrypt(c)
+         assert(d=='abcd')
+         assert(cacert:check(pkey),'self sign check failed')
+-        assert(cacert:check(openssl.x509.store.new({cacert}) ))
++        local castore = openssl.x509.store.new({cacert})
++        assert(cacert:check(castore))
+ 
+         --sign cert by cacert
+ 
+         local dkey = openssl.pkey.new()
+         req = assert(csr.new(self.dn,dkey))
+         local cert = openssl.x509.new(2,req)
+-        cert:validat(os.time(), os.time() + 3600*24*365)
++        cert:notbefore(os.time())
++        cert:validat(os.time(), os.time() + 3600*24*360)
+         assert(cert:sign(pkey,cacert))
+ 
+         local c = cert:pubkey():encrypt('abcd')
+@@ -47,7 +40,7 @@ function TestX509:testNew()
+         assert(d=='abcd')
+         assert(cert:check(dkey),'self private match failed')
+ 
+-        assert(cert:check(openssl.x509.store.new({cacert})))
++        assert(cert:check(castore))
+ end
+ 
+ function TestX509:testIO()
+@@ -75,8 +68,6 @@ sggwDQYJKoZIhvcNAQEEBQADQQCU5SSgapJSdRXJ
+         assert(x:notbefore())
+         assert(x:notafter())
+ 
+-        print(os.date('%c', x:notafter():get()))
+-
+         assertIsNil(x:extensions())
+ 
+         assert(x:subject())
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/5.x509_req.lua luvi-src-v2.7.6/deps/lua-openssl/test/5.x509_req.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/5.x509_req.lua	2019-02-13 11:31:40.290635288 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/5.x509_req.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -160,7 +160,7 @@ TestCSR = {}
+                 assertEquals(req1:subject():tostring(),self.subject:tostring())
+ 
+                 local s = req1:digest()
+-                local r = req1:digest('sha1')
++                local r = req1:digest('sha256')
+                 assertEquals(r,s)
+                 assert(req2:check(pkey))
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/6.cms.lua luvi-src-v2.7.6/deps/lua-openssl/test/6.cms.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/6.cms.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/6.cms.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -0,0 +1,86 @@
++local openssl = require'openssl'
++local bio, x509,cms,csr = openssl.bio,openssl.x509,openssl.cms,openssl.x509.req
++local helper = require'helper'
++if not cms then
++  print('Skip cms test')
++  return
++end
++
++TestCMS = {}
++
++--need OpenSSL build with zlib support
++--[[
++  function TestCMS:testCompress()
++    local msg = openssl.random(1000)
++    local cs = assert(cms.compress(msg, 'rle'))
++    local out = bio.mem()
++    local ret = assert(cms.uncompress (cs, msg, out))
++    assertEquals(msg, out:get_mem())
++  end
++--]]
++    function TestCMS:setUp()
++        self.alg='sha1'
++        self.cadn = openssl.x509.name.new({{commonName='CA'},{C='CN'}})
++        self.alicedn = openssl.x509.name.new({{commonName='Alice'},{C='CN'}})
++        self.bobdn = openssl.x509.name.new({{commonName='Bob'},{C='CN'}})
++
++        local cakey, cacert = helper.new_ca(self.cadn)
++        self.cakey, self.cacert = cakey, cacert
++        self.castore = openssl.x509.store.new({cacert})
++
++        local pkey = openssl.pkey.new()
++        req = assert(csr.new(self.alicedn, pkey))
++        local cert = openssl.x509.new(2,req)
++        cert:validat(os.time(), os.time() + 3600*24*365)
++        assert(cert:sign(cakey,cacert))
++        self.alice = {
++          key = pkey,
++          cert = cert
++        }
++
++        pkey = openssl.pkey.new()
++        req = assert(csr.new(self.bobdn, pkey))
++        cert = openssl.x509.new(2,req)
++        cert:validat(os.time(), os.time() + 3600*24*365)
++        assert(cert:sign(cakey,cacert))
++        self.bob = {
++          key = pkey,
++          cert = cert
++        }
++
++        self.msg = openssl.hex(openssl.random(128))
++        self.digest = 'sha1WithRSAEncryption'
++    end
++
++    function TestCMS:testEncrypt()
++        local recipts = {self.alice.cert}
++        local msg = assert(cms.encrypt(recipts, self.msg))
++        local smime = assert(cms.write(msg))
++        local ss = assert(cms.read(smime,'smime'))
++        local raw = assert(cms.decrypt(ss,self.alice.key, self.alice.cert))
++        assertEquals(raw,self.msg)
++    end
++
++    function TestCMS:testSign()
++        local c1 = assert(cms.sign(self.bob.cert, self.bob.key, self.msg, {}))
++        local smime = assert(cms.write(c1))
++        local msg = assert(cms.verify(c1, {self.bob.cert}, self.castore))
++        assertEquals(msg, self.msg)
++        msg = assert(cms.verify(c1, {}, self.castore))
++        assertEquals(msg, self.msg)
++    end
++
++    function TestCMS:testEncryptedData()
++        local key = openssl.random(24)
++        local c1 = assert(cms.EncryptedData_encrypt(self.msg, key))
++        local smime = assert(cms.write(c1))
++        local msg = assert(cms.EncryptedData_decrypt(c1, key))
++        assertEquals(msg, self.msg)
++    end
++    function TestCMS:testDigest()
++        local key = openssl.random(24)
++        local c1 = assert(cms.digest_create(self.msg))
++        local smime = assert(cms.write(c1))
++        local msg = assert(cms.digest_verify(c1))
++        assertEquals(msg, self.msg)
++    end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/6.pkcs7.lua luvi-src-v2.7.6/deps/lua-openssl/test/6.pkcs7.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/6.pkcs7.lua	2019-02-13 11:31:40.293968598 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/6.pkcs7.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -1,5 +1,6 @@
+ local openssl = require'openssl'
+ local x509,pkcs7,csr = openssl.x509,openssl.pkcs7,openssl.x509.req
++local helper = require'helper'
+ 
+ TestCompat = {}
+     function TestCompat:setUp()
+@@ -11,18 +12,7 @@ TestCompat = {}
+     end
+ 
+     function TestCompat:testNew()
+-        local cakey = assert(openssl.pkey.new())
+-        local req = assert(csr.new(self.cadn,cakey))
+-        local t = req:parse()
+-        assertEquals(type(t),'table')
+-
+-        local cacert = openssl.x509.new(
+-                1,      --serialNumber
+-                req     --copy name and extensions
+-        )
+-        cacert:validat(os.time(), os.time() + 3600*24*361)
+-        assert(cacert:sign(cakey, cacert))  --self sign
+-
++        local cakey, cacert = helper.new_ca(self.cadn)
+         local dkey = openssl.pkey.new()
+         req = assert(csr.new(self.dn,dkey))
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/7.pkcs12.lua luvi-src-v2.7.6/deps/lua-openssl/test/7.pkcs12.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/7.pkcs12.lua	2019-02-13 11:31:40.293968598 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/7.pkcs12.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -1,5 +1,6 @@
+ local openssl = require'openssl'
+ local csr, x509, pkcs12 = openssl.x509.req,openssl.x509, openssl.pkcs12
++local helper = require'helper'
+ 
+ TestCompat = {}
+     function TestCompat:setUp()
+@@ -12,17 +13,9 @@ TestCompat = {}
+ 
+ 
+ function TestCompat:testNew()
+-        local pkey = assert(openssl.pkey.new())
+-        local req = assert(csr.new(self.cadn,pkey))
+-        local t = req:parse()
+-        assertEquals(type(t),'table')
+-
+-        local cacert = openssl.x509.new(
+-                1,      --serialNumber
+-                req     --copy name and extensions
+-        )
++        local pkey, cacert = helper.new_ca(self.cadn)
+         local dkey = openssl.pkey.new()
+-        req = assert(csr.new(self.dn,dkey))
++        local req = assert(csr.new(self.dn,dkey))
+ 
+         local extensions =
+         {{
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/8.ssl_options.lua luvi-src-v2.7.6/deps/lua-openssl/test/8.ssl_options.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/8.ssl_options.lua	2019-02-13 11:31:40.290635288 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/8.ssl_options.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -1,13 +1,15 @@
+ -- Testcase
+-local ssl = require "openssl".ssl
++local openssl = require'openssl'
++local ssl = openssl.ssl
++local helper = require'helper'
+ 
+ local proto = 'TLSv1'
+-
+ local SET = function(t)
+   local s = {}
+   for _, k in ipairs(t) do s[k] = true end
+   return s
+ end
++local libressl = helper.libressl
+ 
+ TestSSLOptions = {}
+       function TestSSLOptions:setUp()
+@@ -18,16 +20,18 @@ TestSSLOptions = {}
+             local t, e = self.ctx:options()
+             assert(type(t) == "table", e or type(t))
+             t = SET(t)
+-            
++            assertIsTable(t)
++            assertEquals(0, #t)
++
+             t = self.ctx:options(ssl.no_sslv3, "no_ticket")
+             t = SET(t)
+             assertIsTable(t)
+-            assert(t.no_sslv3)
++            assert(libressl or t.no_sslv3)
+             assert(t.no_ticket)
+ 
+             assert(not pcall(self.ctx.options, ctx, true, nil))
+             assertIsTable(t)
+-            assert(t.no_sslv3)
++            assert(libressl or t.no_sslv3)
+             assert(t.no_ticket)
+       end
+ 
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/9.issue.lua luvi-src-v2.7.6/deps/lua-openssl/test/9.issue.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/9.issue.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/9.issue.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -0,0 +1,76 @@
++local openssl = require'openssl'
++local hmac = require'openssl'.hmac
++
++TestIssuer = {}
++    function dump(t,i)
++        for k,v in pairs(t) do
++            if type(v) == 'table' then
++                print( string.rep('\t',i),k..'={')
++                dump(v,i+1)
++                print( string.rep('\t',i),'}')
++            elseif type(v) == 'userdata' then
++                local s = tostring(v)
++                if s:match('^openssl.asn1_') then
++                    if type(k)=='userdata' and tostring(k):match('^openssl.asn1_object') then
++                        print( string.rep('\t',i),k:sn()..'='..v:data() )
++                    elseif s:match('^openssl.asn1_integer') then
++                        print( string.rep('\t',i),tostring(k)..'='..tostring(v),v:bn())
++                    else
++                        print( string.rep('\t',i),tostring(k)..'='..tostring(v),v:data())
++                    end
++                elseif s:match('^openssl.x509_name') then
++                    print( string.rep('\t',i),k..'='..v:oneline())
++                    print( string.rep('\t',i),k..'={')
++                    dump(v:info(true), i+1)
++                    print( string.rep('\t',i),k..'=}')
++                elseif s:match('^openssl.x509_extension') then
++                    print( string.rep('\t',i),k..'={')
++                    dump(v:info(true), i+1)
++                    print(string.rep('\t',i),'}')
++                elseif s:match('^openssl.x509_algor') then
++                    print(string.rep('\t',i), k..'='..v:tostring())
++                else
++                    print( string.rep('\t',i),k..'='..v)
++                end
++            else
++                print( string.rep('\t',i),k..'='..tostring(v))
++            end
++        end
++    end
++
++    function TestIssuer:test75()
++        local certasstring = [[
++-----BEGIN CERTIFICATE-----
++MIIDATCCArCgAwIBAgITEgAFDVkfna1KLEIuKgAAAAUNWTAIBgYqhQMCAgMwfzEj
++MCEGCSqGSIb3DQEJARYUc3VwcG9ydEBjcnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJV
++MQ8wDQYDVQQHEwZNb3Njb3cxFzAVBgNVBAoTDkNSWVBUTy1QUk8gTExDMSEwHwYD
++VQQDExhDUllQVE8tUFJPIFRlc3QgQ2VudGVyIDIwHhcNMTUwNjEzMTczNjQ4WhcN
++MTUwOTEzMTc0NjQ4WjATMREwDwYDVQQDEwhuZ2F0ZS5ydTBjMBwGBiqFAwICEzAS
++BgcqhQMCAiQABgcqhQMCAh4BA0MABEBn4s6r6zCgimGfiHg4o0FpNaGv1jGzmqSD
++chsnAiqcV8fQ4Y6p/o0x8CZEXAC+hzdf5w2f1VxzbJaGCTQslmNYo4IBbTCCAWkw
++EwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgQwMB0GA1UdDgQWBBT4x4Lz
++iE6QcS3Qnmz03HNroSojbzAfBgNVHSMEGDAWgBQVMXywjRreZtcVnElSlxckuQF6
++gzBZBgNVHR8EUjBQME6gTKBKhkhodHRwOi8vdGVzdGNhLmNyeXB0b3Byby5ydS9D
++ZXJ0RW5yb2xsL0NSWVBUTy1QUk8lMjBUZXN0JTIwQ2VudGVyJTIwMi5jcmwwgakG
++CCsGAQUFBwEBBIGcMIGZMGEGCCsGAQUFBzAChlVodHRwOi8vdGVzdGNhLmNyeXB0
++b3Byby5ydS9DZXJ0RW5yb2xsL3Rlc3QtY2EtMjAxNF9DUllQVE8tUFJPJTIwVGVz
++dCUyMENlbnRlciUyMDIuY3J0MDQGCCsGAQUFBzABhihodHRwOi8vdGVzdGNhLmNy
++eXB0b3Byby5ydS9vY3NwL29jc3Auc3JmMAgGBiqFAwICAwNBAA+nkIdgmqgVr/2J
++FlwzT6GFy4Cv0skv+KuUyfrd7kX4jcY/oGwxpxBv5WfNYDnHrVK90bNsXTqlon2M
++veFd3yM=
++-----END CERTIFICATE-----
++]]
++        local x = openssl.x509.read(certasstring)
++        local t = x:parse()
++        assert(type(t)=='table')
++        --dump(t,0)
++    end
++
++    function TestIssuer:test141()
++        local c = openssl.cipher.decrypt_new('bf-cbc', "secret_key", "iv")
++        local out = c:update("msg")
++        local final = c:final()
++        c:close()
++        c = nil
++        collectgarbage("collect")
++    end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/9.srp.lua luvi-src-v2.7.6/deps/lua-openssl/test/9.srp.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/9.srp.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/9.srp.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -0,0 +1,63 @@
++
++local openssl = require'openssl'
++local srp = openssl.srp
++if srp==nil then
++  print('Skip test srp')
++  return
++end
++
++local GN = assert(srp.get_default_gN('1024'));
++
++local self = {}
++
++TestSRP = {}
++    function TestSRP:setUp()
++        self.user = 'zhaozg'
++        self.pass = 'password'
++    end
++
++    function TestSRP:tearDown()
++    end
++
++    function TestSRP:test_1_SRV_CreateVerifier()
++        self.salt, self.verifier = GN:create_verifier(self.user, self.pass)
++        assert(self.salt)
++        assert(self.verifier)
++    end
++
++    function TestSRP:test_2_SRV_Calc_b()
++        self.Bpub, self.Brnd = GN:calc_b(self.verifier)
++        assert(self.Bpub)
++        assert(self.Brnd)
++    end
++
++    function TestSRP:test_3_CLI_Calc_a()
++        self.Apub, self.Arnd = GN:calc_a()
++        assert(self.Apub)
++        assert(self.Arnd)
++    end
++
++    function TestSRP:test_4_Calc_u()
++        self.u = assert(GN:calc_u(self.Apub, self.Bpub))
++    end
++
++    function TestSRP:test_5_cli_key()
++        local x = assert(GN.calc_x(self.salt, self.user, self.pass))
++        self.Kclient = assert(GN:calc_client_key(self.Bpub, x, self.Arnd, self.u))
++    end
++
++    function TestSRP:test_6_srv_key()
++        local Kserver = assert(GN:calc_server_key(self.Apub, self.verifier, self.u, self.Brnd))
++        assert(Kserver==self.Kclient)
++    end
++
++    function TestSRP:test_7_cli_key()
++        local x = assert(GN.calc_x(self.salt, self.user, self.pass..'1'))
++        self.Kclient = assert(GN:calc_client_key(self.Bpub, x, self.Arnd, self.u))
++    end
++
++    function TestSRP:test_8_srv_key()
++        local Kserver = assert(GN:calc_server_key(self.Apub, self.verifier, self.u, self.Brnd))
++        assert( Kserver~=self.Kclient)
++    end
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/ec.lua luvi-src-v2.7.6/deps/lua-openssl/test/ec.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/ec.lua	2019-02-13 11:31:40.290635288 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/ec.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -14,7 +14,7 @@ testEC = {}
+         }
+         local ec = assert(pkey.new(factor))
+ 
+-        local pem = assert(ec:export(true))
++        local pem = assert(ec:export('pem'))
+         assertEquals(pem,[[
+ -----BEGIN PRIVATE KEY-----
+ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgH+M5UMX0YRJK6ZLC
+@@ -27,7 +27,7 @@ jcWtqOmp3Xyzxw30SJhuUb3l0VdvmZAfnCxqgGpH
+     function testEC:testEC()
+         local nec =  {'ec','prime256v1'}
+         local ec = pkey.new(unpack(nec))
+-        local t = ec:parse().ec:parse(true) --make basic table
++        local t = ec:parse().ec:parse('pem') --make basic table
+         assertEquals(type(t.curve_name), 'number')
+         assertStrContains(t.x.version, 'bn library')
+         assertStrContains(t.y.version, 'bn library')
+@@ -63,5 +63,24 @@ jcWtqOmp3Xyzxw30SJhuUb3l0VdvmZAfnCxqgGpH
+         ec2p.d = ec:parse().ec:parse().priv_key
+         local ec2priv = pkey.new(ec2p)
+         assert(ec2priv:is_private())
++    end
++
++    function testEC:testEC()
++        local nec =  {'ec','prime256v1'}
++        local key1 = pkey.new(unpack(nec))
++        local key2 = pkey.new(unpack(nec))
++        local ec1 = key1:parse().ec
++        local ec2 = key2:parse().ec
++        local secret1 = ec1:compute_key(ec2)
++        local secret2 = ec2:compute_key(ec1)
++        assert(secret1==secret2)
++
++        local pub1 = pkey.get_public(key1)
++        local pub2 = pkey.get_public(key2)
++        pub1 = pub1:parse().ec
++        pub2 = pub2:parse().ec
+ 
++        secret1 = ec1:compute_key(pub2)
++        secret2 = ec2:compute_key(pub1)
++        assert(secret1==secret2)
+     end
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/helper.lua luvi-src-v2.7.6/deps/lua-openssl/test/helper.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/helper.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/helper.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -0,0 +1,46 @@
++local openssl = require'openssl'
++local ext = openssl.x509.extension
++
++local M = {}
++
++local default_caexts = {
++  {
++     object='basicConstraints',
++     value='CA:true',
++     critical = true
++  },
++  {
++    object='keyUsage',
++    value='keyCertSign'
++  }
++}
++
++function M.to_extensions(exts)
++  exts = exts or default_caexts
++  local ret = {}
++  for i=1, #exts do
++    ret[i] = ext.new_extension(exts[i])
++  end
++  return ret
++end
++
++function M.new_ca(subject)
++  --cacert, self sign
++  local pkey = assert(openssl.pkey.new())
++  local req = assert(openssl.x509.req.new(subject, pkey))
++  local cacert = openssl.x509.new(
++    1,      --serialNumber
++    req     --copy name and extensions
++  )
++  cacert:extensions(M.to_extensions())
++  cacert:notbefore(os.time())
++  cacert:notafter(os.time() + 3600*24*365)
++  assert(cacert:sign(pkey, cacert))  --self sign
++  return pkey, cacert
++end
++
++M.luaopensslv, M.luav, M.opensslv = openssl.version()
++M.libressl = M.opensslv:find('^LibreSSL')
++
++return M
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/luacrypto/ca/README luvi-src-v2.7.6/deps/lua-openssl/test/luacrypto/ca/README
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/luacrypto/ca/README	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/luacrypto/ca/README	2019-02-13 11:53:24.321792707 +0100
+@@ -0,0 +1,17 @@
++Testing x509 certs for luacrypto
++
++# Make the CA cert
++openssl genrsa -des3 -out ca.key 4096
++openssl req -new -x509 -days 365 -key ca.key -out ca.crt
++
++# Make server cert and signing request
++openssl genrsa -des3 -out server.key 4096
++openssl req -new -key server.key -out server.csr
++
++# Sign the server csr and generate a crt
++openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
++
++# Output unencrypted server key
++openssl rsa -in server.key -out server.key.insecure
++
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/luv_ssl/ssl_c.lua luvi-src-v2.7.6/deps/lua-openssl/test/luv_ssl/ssl_c.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/luv_ssl/ssl_c.lua	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/luv_ssl/ssl_c.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -1,84 +1,84 @@
+-local uv = require('luv')
+-local ssl = require('luv.ssl')
++local uv = require 'luv'
++local ssl = require 'luv.ssl'
+ -----------------------------------------------
+ local count = 0
+ local ncount = arg[3] and tonumber(arg[3]) or 40000
+ ncount = ncount or 40000
+-local step = 1000/2
++local step = 1000 / 2
+ local tmp = true
+ 
+-local function setInterval(fn, ms)
++local function setInterval (fn, ms)
+   local handle = uv.new_timer()
+   uv.timer_start(handle, ms, ms, fn)
+   return handle
+ end
+ 
+-setInterval(function()
+-	print(os.date(),count)
+-	print(ssl.error())
+-	collectgarbage()
+-end,
+-1000)
++setInterval(function ()
++    print(os.date(), count)
++    print(ssl.error())
++    collectgarbage()
++  end, 1000)
+ --------------------------------------------------------------
+-host = arg[1] or "127.0.0.1"; --only ip
+-port = arg[2] or "8383";
++host = arg[1] or "127.0.0.1" --only ip
++port = arg[2] or "8383"
+ 
+ local address = {
+-	port = tonumber(port),
+-	address = host
++  port = tonumber(port),
++  address = host,
++
+ }
+ 
+-local ctx = ssl.new_ctx({
+-   protocol = "TLSv1_2_client",
+-   verify = {"none"},
+---   options = {"all", "no_sslv2"}
+-})
++local ctx = ssl.new_ctx {
++  protocol = "TLSv1_2_client",
++  verify = ssl.none,
++  --   options = {"all", "no_sslv2"}
++
++}
+ 
+ 
+ local new_connection
+ 
+-function new_connection(i)
++function new_connection (i)
+ 
+-	local scli = ssl.connect(address.address,address.port,ctx, function(self)
+-		count = count + 1
+-		self:write('GET / HTTP/1.0\r\n\r\n')
+-		if tmp then
+-			self:close()
+-		end
+-
+-		if count <= ncount then
+-			new_connection(i)
+-		end
+-
+-	end)
+-
+-	function scli:ondata(chunk)
+-		--print(chunk)
+-	end
+-	
+-	function scli:onerror(err)
+-		print('onerror',err)
+-	end
+-	
+-	function scli:onend()
+-		--print('onend********8')
+-		--count = count -1
+-		self:close()
+-	end
+-	function scli:onclose()
+-		count = count -1
+-		--print('closed')
+-	end
+-	return scli
++  local scli = ssl.connect(address.address, address.port, ctx, function (self)
++      count = count + 1
++      self:write 'GET / HTTP/1.0\r\n\r\n'
++      if tmp then
++        self:close()
++      end
++
++      if count <= ncount then
++        new_connection(i)
++      end
++    end)
++
++  function scli:ondata (chunk)
++ --print(chunk)
++       end
++
++  function scli:onerror (err)
++    print('onerror', err)
++  end
++
++  function scli:onend ()
++    --print('onend********8')
++    --count = count -1
++    self:close()
++  end
++  function scli:onclose ()
++    count = count - 1
++ --print('closed')
++       end
++  return scli
+ end
+ 
+ tmp = true
+ local conns = {}
+ 
+-for i=1, step do 
+-	new_connection(i)
++for i = 1, step do
++  new_connection(i)
+ end
+ 
+-uv.run('default')
++uv.run 'default'
+ 
+-print("done")
++print "done"
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/luv_ssl/ssl_s.lua luvi-src-v2.7.6/deps/lua-openssl/test/luv_ssl/ssl_s.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/luv_ssl/ssl_s.lua	2019-02-13 11:31:40.320635083 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/luv_ssl/ssl_s.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -1,83 +1,82 @@
+-local uv = require('luv')
+-local ssl = require('luv.ssl')
++local uv = require 'luv'
++local ssl = require 'luv.ssl'
+ 
+ -----------------------------------------------
+ ---[[
+ local count = 0
+ 
+-local function setInterval(fn, ms)
++local function setInterval (fn, ms)
+   local handle = uv.new_timer()
+   uv.timer_start(handle, ms, ms, fn)
+   return handle
+ end
+ 
+-setInterval(function()
+-	print(os.date(),count)
+-	print(ssl.error())
+-	collectgarbage()
+-end,
+-1000)
++setInterval(function ()
++    print(os.date(), count)
++    print(ssl.error())
++    collectgarbage()
++  end, 1000)
+ --]]
+ --------------------------------------------------------------
+-host = arg[1] or "127.0.0.1"; --only ip
+-port = arg[2] or "8383";
++host = arg[1] or "127.0.0.1" --only ip
++port = arg[2] or "8383"
+ 
+ local address = {
+-	port = tonumber(port),
+-	address = host
++  port = tonumber(port),
++  address = host,
++
+ }
+ 
+-local ctx = ssl.new_ctx({
+-   protocol = "TLSv1_2_server",
+-   verify = {"none"},
+-   key = "../luasec/certs/serverAkey.pem",
+-   certificate = "../luasec/certs/serverA.pem",
+-   cafile = "../luasec/certs/rootA.pem",
+-   verify = {"none"},   
+---   options = {"all", "no_sslv2"}
+-})
++local ctx = ssl.new_ctx {
++  protocol = "TLSv1_2_server",
++  key = "../luasec/certs/serverAkey.pem",
++  certificate = "../luasec/certs/serverA.pem",
++  cafile = "../luasec/certs/rootA.pem",
++  verify = ssl.none,
++  --   options = {"all", "no_sslv2"}
++
++}
+ 
+-function create_server(host, port, on_connection)
++function create_server (host, port, on_connection)
+   local server = uv.new_tcp()
+   uv.tcp_bind(server, host, port)
+-  uv.listen(server,64, function(self) 
+-    local client = uv.new_tcp()
+-    uv.accept(server, client)
+-    on_connection(client)
+-  end)
++  uv.listen(server, 64, function (self)
++      local client = uv.new_tcp()
++      uv.accept(server, client)
++      on_connection(client)
++    end)
+   return server
+ end
+ 
+ local p = print
+ local server = create_server(address.address, address.port, function (client)
+ 
+-	local scli = ssl.new_ssl(ctx,client,true)
+-	scli:handshake(function(scli)
+-		print('CONNECTED')
+-		count = count + 1
+-	end)
+-
+-	function scli:ondata(chunk)
+-		print("ondata", chunk)
+-		self:close()
+-	end
+-	function scli:onerror(err)
+-		print('onerr',err,ssl.error())
+-	end
+-
+-	function scli:onend()
+-		print("onend")
+-		uv.shutdown(client, function ()
+-		  print("onshutdown")
+-		  uv.close(client)
+-		end)
+-	end
+-
+-end)
++    local scli = ssl.new_ssl(ctx, client, true)
++    scli:handshake(function (scli)
++        print 'CONNECTED'
++        count = count + 1
++      end)
++
++    function scli:ondata (chunk)
++      print("ondata", chunk)
++      self:close()
++    end
++    function scli:onerror (err)
++      print('onerr', err, ssl.error())
++    end
++
++    function scli:onend ()
++      print "onend"
++      uv.shutdown(client, function ()
++          print "onshutdown"
++          uv.close(client)
++        end)
++    end
++  end)
+ 
+ local address = uv.tcp_getsockname(server)
+ p("server", server, address)
+ 
+-uv.run('default')
++uv.run 'default'
+ 
+-print("done")
++print "done"
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/sm2.lua luvi-src-v2.7.6/deps/lua-openssl/test/sm2.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/sm2.lua	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/sm2.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -0,0 +1,74 @@
++local openssl = require'openssl'
++local pkey = openssl.pkey
++local sm2  = openssl.sm2
++local unpack = unpack or table.unpack
++local helper = require'helper'
++
++_,_,opensslv = openssl.version(true)
++print(opensslv)
++if opensslv >= 0x10101007 and (not helper.libressl) then
++  print('Support SM2')
++  testSM2 = {}
++
++    function testSM2:testSM2()
++        local nec =  {'ec','SM2'}
++        local ec = pkey.new(unpack(nec))
++        local t = ec:parse().ec:parse('pem') --make basic table
++        assertEquals(type(t.curve_name), 'number')
++        assertStrContains(t.x.version, 'bn library')
++        assertStrContains(t.y.version, 'bn library')
++        assertStrContains(t.d.version, 'bn library')
++
++        local k1 = pkey.get_public(ec)
++        assert(not k1:is_private())
++        local t = k1:parse()
++        assert(t.bits==256)
++        assert(t.type=='ec')
++        assert(t.size==72)
++        local r = t.ec
++        t = r:parse(true) --make basic table
++        assertEquals(type(t.curve_name), 'number')
++        assertStrContains(t.x.version, 'bn library')
++        assertStrContains(t.y.version, 'bn library')
++        assertEquals(t.d, nil)
++        t = r:parse()
++        assertStrContains(tostring(t.pub_key), 'openssl.ec_point')
++        assertStrContains(tostring(t.group), 'openssl.ec_group')
++        local x, y = t.group:affine_coordinates(t.pub_key)
++        assertStrContains(x.version, 'bn library')
++        assertStrContains(y.version, 'bn library')
++        local ec2p = {
++            alg = 'ec',
++            ec_name = t.group:parse().curve_name,
++            x = x,
++            y = y,
++        }
++        local ec2 = pkey.new(ec2p)
++        assert(not ec2:is_private())
++
++        ec2p.d = ec:parse().ec:parse().priv_key
++        local ec2priv = pkey.new(ec2p)
++        assert(ec2priv:is_private())
++
++        local nec =  {'ec','SM2'}
++        local key1 = pkey.new(unpack(nec))
++        local key2 = pkey.new(unpack(nec))
++        local ec1 = key1:parse().ec
++        local ec2 = key2:parse().ec
++        local secret1 = ec1:compute_key(ec2)
++        local secret2 = ec2:compute_key(ec1)
++        assert(secret1==secret2)
++
++        local pub1 = pkey.get_public(key1)
++        local pub2 = pkey.get_public(key2)
++        pub1 = pub1:parse().ec
++        pub2 = pub2:parse().ec
++
++        secret1 = ec1:compute_key(pub2)
++        secret2 = ec2:compute_key(pub1)
++        assert(secret1==secret2)
++      end
++else
++  print('Skip SM2')
++end
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/test/test.lua luvi-src-v2.7.6/deps/lua-openssl/test/test.lua
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/test/test.lua	2019-02-13 11:31:40.293968598 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/test/test.lua	2019-02-13 11:53:24.321792707 +0100
+@@ -3,8 +3,7 @@ EXPORT_ASSERT_TO_GLOBALS = true
+ require'luaunit'
+ 
+ openssl.rand_load()
+-v = {openssl.version(true)}
+-print(openssl.version())
++print('VERSION:', openssl.version())
+ 
+ dofile('0.engine.lua')
+ dofile('0.misc.lua')
+@@ -23,11 +22,15 @@ dofile('5.x509_crl.lua')
+ dofile('5.x509.lua')
+ dofile('5.ts.lua')
+ dofile('6.pkcs7.lua')
++dofile('6.cms.lua')
+ dofile('7.pkcs12.lua')
+ dofile('8.ssl_options.lua')
+ dofile('8.ssl.lua')
++dofile('9.srp.lua')
++dofile('9.issue.lua')
+ dofile('rsa.lua')
+ dofile('ec.lua')
++dofile('sm2.lua')
+ 
+ --LuaUnit.verbosity = 0
+ LuaUnit.run()
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/.travis/setenv_lua.sh luvi-src-v2.7.6/deps/lua-openssl/.travis/setenv_lua.sh
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/.travis/setenv_lua.sh	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/.travis/setenv_lua.sh	2019-02-13 11:53:24.105128513 +0100
+@@ -1,3 +1,3 @@
+-export PATH=${PATH}:$HOME/.lua:$HOME/.local/bin:${TRAVIS_BUILD_DIR}/install/luarocks/bin
++export PATH=$HOME/.usr/bin:${PATH}
+ bash .travis/setup_lua.sh
+-eval `$HOME/.lua/luarocks path`
++eval `$HOME/.usr/luarocks path`
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/.travis/setup_lua.sh luvi-src-v2.7.6/deps/lua-openssl/.travis/setup_lua.sh
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/.travis/setup_lua.sh	2019-02-13 11:31:40.330635015 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/.travis/setup_lua.sh	2019-02-13 11:53:24.105128513 +0100
+@@ -8,16 +8,13 @@
+ 
+ set -eufo pipefail
+ 
+-LUAJIT_VERSION="2.0.4"
++LUAJIT_VERSION="2.0.5"
+ LUAJIT_BASE="LuaJIT-$LUAJIT_VERSION"
+ 
+ source .travis/platform.sh
+ 
+-LUA_HOME_DIR=$TRAVIS_BUILD_DIR/install/lua
+-
+-LR_HOME_DIR=$TRAVIS_BUILD_DIR/install/luarocks
+-
+-mkdir $HOME/.lua
++LUA_HOME_DIR=$HOME/.usr
++LR_HOME_DIR=$HOME/.usr
+ 
+ LUAJIT="no"
+ 
+@@ -54,10 +51,7 @@ if [ "$LUAJIT" == "yes" ]; then
+   fi
+ 
+   make && make install PREFIX="$LUA_HOME_DIR"
+-
+-  ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit
+-  ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua;
+-
++  ln -s $HOME/.usr/bin/luajit $HOME/.usr/bin/lua
+ else
+ 
+   if [ "$LUA" == "lua5.1" ]; then
+@@ -67,18 +61,14 @@ else
+     curl http://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz
+     cd lua-5.2.4;
+   elif [ "$LUA" == "lua5.3" ]; then
+-    curl http://www.lua.org/ftp/lua-5.3.2.tar.gz | tar xz
+-    cd lua-5.3.2;
++    curl http://www.lua.org/ftp/lua-5.3.4.tar.gz | tar xz
++    cd lua-5.3.4;
+   fi
+ 
+   # Build Lua without backwards compatibility for testing
+   perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile
+   make $PLATFORM
+   make INSTALL_TOP="$LUA_HOME_DIR" install;
+-
+-  ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua
+-  ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac;
+-
+ fi
+ 
+ cd $TRAVIS_BUILD_DIR
+@@ -103,8 +93,6 @@ fi
+ 
+ make build && make install
+ 
+-ln -s $LR_HOME_DIR/bin/luarocks $HOME/.lua/luarocks
+-
+ cd $TRAVIS_BUILD_DIR
+ 
+ luarocks --version
+@@ -118,5 +106,5 @@ elif [ "$LUA" == "lua5.1" ]; then
+ elif [ "$LUA" == "lua5.2" ]; then
+   rm -rf lua-5.2.4;
+ elif [ "$LUA" == "lua5.3" ]; then
+-  rm -rf lua-5.3.2;
++  rm -rf lua-5.3.4;
+ fi
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/.travis/setup_ssl.sh luvi-src-v2.7.6/deps/lua-openssl/.travis/setup_ssl.sh
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/.travis/setup_ssl.sh	1970-01-01 01:00:00.000000000 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/.travis/setup_ssl.sh	2019-02-13 11:53:24.105128513 +0100
+@@ -0,0 +1,52 @@
++#!/bin/sh
++if [ -z "$SSL" ]; then
++	echo '$SSL not set, use default openssl' >&2
++	exit 0
++fi
++
++source .travis/platform.sh
++
++case "$SSL" in
++openssl-0.9.*)
++	SSLURL=https://www.openssl.org/source/old/0.9.x/$SSL.tar.gz
++	;;
++openssl-1.0.0*)
++	SSLURL=https://www.openssl.org/source/old/1.0.0/$SSL.tar.gz
++	;;
++openssl-1.0.1*)
++	SSLURL=https://www.openssl.org/source/old/1.0.1/$SSL.tar.gz
++	;;
++openssl-*)
++	SSLURL=https://www.openssl.org/source/$SSL.tar.gz
++	;;
++libressl-*)
++	SSLURL=https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/$SSL.tar.gz
++	LIBRESSL=$SSL
++	;;
++*)
++  echo $SSL where to download?
++	exit 1
++	;;
++esac
++
++if [ ! -d "$HOME/opt/$SSL" ]; then
++	wget "$SSLURL" || exit 1
++	tar -xzf "$SSL.tar.gz" || exit 1
++	cd "$SSL" || exit 1
++	export OPENSSL_DIR=$HOME/.usr
++	if [ "$PLATFORM" == "linux" ]; then
++		./config shared --prefix="$OPENSSL_DIR" || exit 1
++	fi
++	if [ "$PLATFORM" == "macosx" ]; then
++		if [ -z "$LIBRESSL" ]; then
++			./Configure darwin64-x86_64-cc shared --prefix="$OPENSSL_DIR" || exit 1
++		else
++			./config --prefix="$OPENSSL_DIR" || exit 1
++		fi
++	fi
++	make && make install_sw || { rm -rf "$OPENSSL_DIR"; exit 1; }
++	cd ..
++fi
++
++# vim: ts=8 sw=8 noet tw=79 fen fdm=marker
++
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl/.travis.yml luvi-src-v2.7.6/deps/lua-openssl/.travis.yml
+--- luvi-src-v2.7.6.orig/deps/lua-openssl/.travis.yml	2019-02-13 11:31:40.277302045 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl/.travis.yml	2019-02-13 11:53:24.105128513 +0100
+@@ -3,17 +3,21 @@ language: c
+ sudo: required
+ env:
+   global:
+-    - LUAROCKS=2.2.2
++    - LUAROCKS=3.0.3
+   matrix:
+     - LUA=lua5.1
+-    - LUA=lua5.2
+-    - LUA=lua5.3
+-    - LUA=luajit
+-    
++    - LUA=lua5.1 SSL=openssl-1.0.2p
++    - LUA=lua5.2 SSL=libressl-2.8.0
++    - LUA=lua5.3 SSL=openssl-1.1.1
++    - LUA=luajit SSL=openssl-1.1.0i
++    - LUA=luajit2.1
+ os:
+   - linux
+   - osx
+ 
++matrix:
++  allow_failures:
++    - env: LUA=lua5.2 SSL=libressl-2.8.0
+ 
+ branches:
+   only:
+@@ -22,16 +26,20 @@ branches:
+ before_install:
+   - source .travis/setenv_lua.sh
+   - bash .travis/setup_uv.sh
++  - bash .travis/setup_ssl.sh
+   - git submodule update --init --recursive
+   - git submodule update --recursive
+ 
+-install: 
+-  - sudo $HOME/.lua/luarocks make rockspecs/openssl-scm-1.rockspec
++install:
++  - 'if [[ "$TRAVIS_OS_NAME" == "osx" && -z "$SSL" ]]; then sudo $HOME/.usr/bin/luarocks make openssl-scm-5.rockspec OPENSSL_DIR=/usr/local/opt/openssl; fi'
++  - 'if [[ "$TRAVIS_OS_NAME" == "osx" && -n "$SSL" ]]; then sudo $HOME/.usr/bin/luarocks make openssl-scm-5.rockspec OPENSSL_DIR=$HOME/.usr; fi'
++  - 'if [[ "$TRAVIS_OS_NAME" == "linux" && -z "$SSL" ]]; then sudo -H $HOME/.usr/bin/luarocks make openssl-scm-5.rockspec OPENSSL_DIR=/usr; fi'
++  - 'if [[ "$TRAVIS_OS_NAME" == "linux" && -n "$SSL" ]]; then sudo -H $HOME/.usr/bin/luarocks make openssl-scm-5.rockspec OPENSSL_DIR=$HOME/.usr; fi'
+ 
+-script: 
++script:
+   - cd test
+   - curl https://raw.githubusercontent.com/bluebird75/luaunit/master/luaunit.lua > luaunit.lua
+-  - lua test.lua
++  - lua -e "package.cpath='../?.so'" test.lua
+ 
+ notifications:
+   email:
+diff -purN luvi-src-v2.7.6.orig/deps/lua-openssl.cmake luvi-src-v2.7.6/deps/lua-openssl.cmake
+--- luvi-src-v2.7.6.orig/deps/lua-openssl.cmake	2019-02-13 11:31:40.273968734 +0100
++++ luvi-src-v2.7.6/deps/lua-openssl.cmake	2019-02-13 11:49:06.031947286 +0100
+@@ -1,19 +1,32 @@
+ set(LUA_OPENSSL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/lua-openssl)
++if(DEFINED ENV{LUA_OPENSSL_DIR})
++  set(LUA_OPENSSL_DIR $ENV{LUA_OPENSSL_DIR})
++endif()
+ 
+ include_directories(
+-  ${LUA_OPENSSL_DIR}/deps
++  ${LUA_OPENSSL_DIR}/deps/auxiliar
++  ${LUA_OPENSSL_DIR}/deps/lua-compat
+   ${LUA_OPENSSL_DIR}/src
+ )
+ 
++add_definitions(
++  -DCOMPAT52_IS_LUAJIT
++)
++
+ if(WIN32)
++  add_definitions(
++    -DWIN32_LEAN_AND_MEAN
++    -D_CRT_SECURE_NO_WARNINGS
++  )
+ else()
+   find_package(Threads)
+   add_definitions(-DPTHREADS)
+ endif()
+ 
+ add_library(lua_openssl
++  ${LUA_OPENSSL_DIR}/deps/auxiliar/auxiliar.c
++  ${LUA_OPENSSL_DIR}/deps/auxiliar/subsidiar.c
+   ${LUA_OPENSSL_DIR}/src/asn1.c
+-  ${LUA_OPENSSL_DIR}/src/auxiliar.c
+   ${LUA_OPENSSL_DIR}/src/bio.c
+   ${LUA_OPENSSL_DIR}/src/callback.c
+   ${LUA_OPENSSL_DIR}/src/cipher.c
+@@ -40,6 +53,7 @@ add_library(lua_openssl
+   ${LUA_OPENSSL_DIR}/src/private.h
+   ${LUA_OPENSSL_DIR}/src/rsa.c
+   ${LUA_OPENSSL_DIR}/src/sk.h
++  ${LUA_OPENSSL_DIR}/src/srp.c
+   ${LUA_OPENSSL_DIR}/src/ssl.c
+   ${LUA_OPENSSL_DIR}/src/th-lock.c
+   ${LUA_OPENSSL_DIR}/src/util.c
+@@ -52,7 +66,7 @@ add_library(lua_openssl
+ )
+ 
+ set_target_properties(lua_openssl PROPERTIES
+-    COMPILE_FLAGS "-DLUA_LIB -DCOMPAT52_IS_LUAJIT")
++    COMPILE_FLAGS "-DLUA_LIB")
+ 
+ if (WithSharedOpenSSL)
+   target_link_libraries(lua_openssl ssl crypto)
