diff mbox series

package/luvi: add patch to fix build issue with OpenSSL 1.1.1a

Message ID 20190213220812.29978-1-joerg.krause@embedded.rocks
State Superseded
Headers show
Series package/luvi: add patch to fix build issue with OpenSSL 1.1.1a | expand

Commit Message

Jörg Krause Feb. 13, 2019, 10:08 p.m. UTC
Bump the bundled lua-openssl version to 0.7.4 for compatibility with
OpenSSL 1.1.1a.

Note, that luvi 2.7.6 is the latest version providing a release tarball.

Runtime tested on Banana Pro, note that version string for lua-openssl
does not match the tag name (0.7.4):

```
luvi v2.7.6
zlib: 1.2.11
libuv: 1.25.0
ssl: OpenSSL 1.1.1a  20 Nov 2018, lua-openssl 0.7.3
```

Fixes:
http://autobuild.buildroot.net/results/e87994a3dc987f5aa101a5e721ac927e21453373
http://autobuild.buildroot.net/results/ea725ad90cfcd3c5e242268a593dcabd7297fe70
http://autobuild.buildroot.net/results/f2fb9eea0044e4a5f674742d29ea95af49cf5a45
http://autobuild.buildroot.net/results/de4daa1b930f907f06640dc98a708016217ddea5
.. and many more.

Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
---
 ...bundled-lua-openssl-to-version-0.7.4.patch | 31718 ++++++++++++++++
 1 file changed, 31718 insertions(+)
 create mode 100644 package/luvi/0003-Bump-bundled-lua-openssl-to-version-0.7.4.patch

Comments

Thomas Petazzoni Feb. 14, 2019, 8:43 a.m. UTC | #1
Hello,

On Wed, 13 Feb 2019 23:08:11 +0100
Jörg Krause <joerg.krause@embedded.rocks> wrote:

> Bump the bundled lua-openssl version to 0.7.4 for compatibility with
> OpenSSL 1.1.1a.
> 
> Note, that luvi 2.7.6 is the latest version providing a release tarball.
> 
> Runtime tested on Banana Pro, note that version string for lua-openssl
> does not match the tag name (0.7.4):
> 
> ```
> luvi v2.7.6
> zlib: 1.2.11
> libuv: 1.25.0
> ssl: OpenSSL 1.1.1a  20 Nov 2018, lua-openssl 0.7.3
> ```
> 
> Fixes:
> http://autobuild.buildroot.net/results/e87994a3dc987f5aa101a5e721ac927e21453373
> http://autobuild.buildroot.net/results/ea725ad90cfcd3c5e242268a593dcabd7297fe70
> http://autobuild.buildroot.net/results/f2fb9eea0044e4a5f674742d29ea95af49cf5a45
> http://autobuild.buildroot.net/results/de4daa1b930f907f06640dc98a708016217ddea5
> .. and many more.
> 
> Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>

This is really a huge patch.

Why is luvi using a bundled lua-openssl version instead of some
external lua-openssl package ?

I see that the change has been applied upstream
(https://github.com/luvit/luvi/commit/0d5959a33cde81ed49314bd6c56f6906a83d2fa1),
which is good.

Thanks,

Thomas
Jörg Krause Feb. 14, 2019, 9:20 a.m. UTC | #2
Hi Thomas,

On Thu, 2019-02-14 at 09:43 +0100, Thomas Petazzoni wrote:
> Hello,
> 
> On Wed, 13 Feb 2019 23:08:11 +0100
> Jörg Krause <joerg.krause@embedded.rocks> wrote:
> 
> > Bump the bundled lua-openssl version to 0.7.4 for compatibility with
> > OpenSSL 1.1.1a.
> > 
> > Note, that luvi 2.7.6 is the latest version providing a release tarball.
> > 
> > Runtime tested on Banana Pro, note that version string for lua-openssl
> > does not match the tag name (0.7.4):
> > 
> > ```
> > luvi v2.7.6
> > zlib: 1.2.11
> > libuv: 1.25.0
> > ssl: OpenSSL 1.1.1a  20 Nov 2018, lua-openssl 0.7.3
> > ```
> > 
> > Fixes:
> > http://autobuild.buildroot.net/results/e87994a3dc987f5aa101a5e721ac927e21453373
> > http://autobuild.buildroot.net/results/ea725ad90cfcd3c5e242268a593dcabd7297fe70
> > http://autobuild.buildroot.net/results/f2fb9eea0044e4a5f674742d29ea95af49cf5a45
> > http://autobuild.buildroot.net/results/de4daa1b930f907f06640dc98a708016217ddea5
> > .. and many more.
> > 
> > Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
> 
> This is really a huge patch.

Yes, unfortunately!

> Why is luvi using a bundled lua-openssl version instead of some
> external lua-openssl package ?

I spent some time trying to make lua-openssl an external package. It is
certainly feasible to get luvi to work to use an external lua-openssl
package, but it requires some changes in lua-openssl first, as
installing header files in staging, naming convention for the shared
library, etc.

Right now, it was easier for me, to just bump the bundled lua-openssl
version.

> I see that the change has been applied upstream
> (https://github.com/luvit/luvi/commit/0d5959a33cde81ed49314bd6c56f6906a83d2fa1),
> which is good.

Yes, there was a commit [1] on the master branch before, which bumped
lua-openssl to version 0.7.3. However, this version does not build with
OpenSSL 1.1.1.

Unfortunately, the luvi maintainers are not able to create new releases
right now. Hopefully, someone of the maintainers with push rights will
have the time soon to do so.

[1] https://github.com/luvit/luvi/commit/a981c704b960e52974ec5746a25b86de40b2cb67

Best regards
Jörg
Jörg Krause Feb. 19, 2019, 8:46 p.m. UTC | #3
On Thu, 2019-02-14 at 09:43 +0100, Thomas Petazzoni wrote:
> Hello,
> 
> On Wed, 13 Feb 2019 23:08:11 +0100
> Jörg Krause <joerg.krause@embedded.rocks> wrote:
> 
> > Bump the bundled lua-openssl version to 0.7.4 for compatibility with
> > OpenSSL 1.1.1a.
> > 
> > Note, that luvi 2.7.6 is the latest version providing a release tarball.
> > 
> > Runtime tested on Banana Pro, note that version string for lua-openssl
> > does not match the tag name (0.7.4):
> > 
> > ```
> > luvi v2.7.6
> > zlib: 1.2.11
> > libuv: 1.25.0
> > ssl: OpenSSL 1.1.1a  20 Nov 2018, lua-openssl 0.7.3
> > ```
> > 
> > Fixes:
> > http://autobuild.buildroot.net/results/e87994a3dc987f5aa101a5e721ac927e21453373
> > http://autobuild.buildroot.net/results/ea725ad90cfcd3c5e242268a593dcabd7297fe70
> > http://autobuild.buildroot.net/results/f2fb9eea0044e4a5f674742d29ea95af49cf5a45
> > http://autobuild.buildroot.net/results/de4daa1b930f907f06640dc98a708016217ddea5
> > .. and many more.
> > 
> > Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
> 
> This is really a huge patch.
> 
> Why is luvi using a bundled lua-openssl version instead of some
> external lua-openssl package ?
> 
> I see that the change has been applied upstream
> (https://github.com/luvit/luvi/commit/0d5959a33cde81ed49314bd6c56f6906a83d2fa1),
> which is good.

Fortunately, the maintainers of luvi released version 2.9.0 which
includes the updated lua-openssl to fix the build issues with OpenSSL
1.1.1a.

Therefore, this patch is superseded.

Jörg
diff mbox series

Patch

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)