summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwilliam <william@25thandclement.com>2015-04-17 16:08:24 -0700
committerwilliam <william@25thandclement.com>2015-04-17 16:08:24 -0700
commitc6a00deb359b38ec72aeeba3b07a22fdda209dbc (patch)
treeef36b220a4c2c210702359b9989ccdf79d3c500d
parentb5c0bb622f55b6e52a1ae1a5ec5a4ded0cded96b (diff)
downloadluaossl-c6a00deb359b38ec72aeeba3b07a22fdda209dbc.tar.gz
luaossl-c6a00deb359b38ec72aeeba3b07a22fdda209dbc.tar.bz2
luaossl-c6a00deb359b38ec72aeeba3b07a22fdda209dbc.zip
pin the module in memory when installing external app data callbacks, as these can be never be uninstalled
-rw-r--r--src/openssl.c358
1 files changed, 234 insertions, 124 deletions
diff --git a/src/openssl.c b/src/openssl.c
index 90db798..0894fcf 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -23,9 +23,6 @@
23 * USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * ========================================================================== 24 * ==========================================================================
25 */ 25 */
26#ifndef LUAOSSL_H
27#define LUAOSSL_H
28
29#include <limits.h> /* INT_MAX INT_MIN UCHAR_MAX */ 26#include <limits.h> /* INT_MAX INT_MIN UCHAR_MAX */
30#include <stdint.h> /* uintptr_t */ 27#include <stdint.h> /* uintptr_t */
31#include <string.h> /* memset(3) strerror_r(3) */ 28#include <string.h> /* memset(3) strerror_r(3) */
@@ -33,8 +30,7 @@
33#include <math.h> /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ 30#include <math.h> /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */
34#include <time.h> /* struct tm time_t strptime(3) time(2) */ 31#include <time.h> /* struct tm time_t strptime(3) time(2) */
35#include <ctype.h> /* tolower(3) */ 32#include <ctype.h> /* tolower(3) */
36#include <signal.h> /* sig_atomic_t */ 33#include <errno.h> /* ENOMEM ENOTSUP errno */
37#include <errno.h> /* ENOMEM errno */
38#include <assert.h> /* assert */ 34#include <assert.h> /* assert */
39 35
40#include <sys/types.h> /* ssize_t pid_t */ 36#include <sys/types.h> /* ssize_t pid_t */
@@ -80,6 +76,10 @@
80#include "compat52.h" 76#include "compat52.h"
81#endif 77#endif
82 78
79#ifndef HAVE_DLADDR
80#define HAVE_DLADDR (!defined _AIX) /* TODO: https://root.cern.ch/drupal/content/aix-and-dladdr */
81#endif
82
83#ifndef HAVE_SSL_CTX_SET_ALPN_PROTOS 83#ifndef HAVE_SSL_CTX_SET_ALPN_PROTOS
84#define HAVE_SSL_CTX_SET_ALPN_PROTOS (OPENSSL_VERSION_NUMBER >= 0x1000200fL) 84#define HAVE_SSL_CTX_SET_ALPN_PROTOS (OPENSSL_VERSION_NUMBER >= 0x1000200fL)
85#endif 85#endif
@@ -573,6 +573,83 @@ static void lib_setintegers(lua_State *L, const integer_Reg *l) {
573} /* lib_setintegers() */ 573} /* lib_setintegers() */
574 574
575 575
576/*
577 * Auxiliary Lua API routines
578 *
579 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
580
581typedef int auxref_t;
582typedef int auxtype_t;
583
584static void auxL_unref(lua_State *L, auxref_t *ref) {
585 luaL_unref(L, LUA_REGISTRYINDEX, *ref);
586 *ref = LUA_NOREF;
587} /* auxL_unref() */
588
589static void auxL_ref(lua_State *L, int index, auxref_t *ref) {
590 auxL_unref(L, ref);
591 lua_pushvalue(L, index);
592 *ref = luaL_ref(L, LUA_REGISTRYINDEX);
593} /* auxL_ref() */
594
595static auxtype_t auxL_getref(lua_State *L, auxref_t ref) {
596 if (ref == LUA_NOREF || ref == LUA_REFNIL) {
597 lua_pushnil(L);
598 } else {
599 lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
600 }
601
602 return lua_type(L, -1);
603} /* auxL_getref() */
604
605
606/*
607 * dl - dynamically loaded module management
608 *
609 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
610
611/*
612 * Prevent loader from unlinking us if we've registered a callback with
613 * OpenSSL by taking another reference to ourselves.
614 */
615static int dl_anchor(void) {
616#if HAVE_DLADDR
617 extern int luaopen__openssl(lua_State *);
618 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
619 static void *anchor;
620 Dl_info info;
621 int error = 0;
622
623 if ((error = pthread_mutex_lock(&mutex)))
624 return error;
625
626 if (anchor)
627 goto epilog;
628
629 if (!dladdr((void *)&luaopen__openssl, &info))
630 goto dlerr;
631
632 if (!(anchor = dlopen(info.dli_fname, RTLD_NOW|RTLD_LOCAL)))
633 goto dlerr;
634epilog:
635 (void)pthread_mutex_unlock(&mutex);
636
637 return error;
638dlerr:
639 error = -2;
640
641 goto epilog;
642#else
643 return 0;//ENOTSUP;
644#endif
645} /* dl_anchor() */
646
647
648/*
649 * compat - OpenSSL API compatibility and bug workarounds
650 *
651 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
652
576#define COMPAT_X509_STORE_FREE_BUG 0x01 653#define COMPAT_X509_STORE_FREE_BUG 0x01
577 654
578static struct { 655static struct {
@@ -632,7 +709,9 @@ static void *compat_EVP_PKEY_get0(EVP_PKEY *key) {
632} /* compat_EVP_PKEY_get0() */ 709} /* compat_EVP_PKEY_get0() */
633#endif 710#endif
634 711
635/* X509_STORE_free in OpenSSL versions < 1.0.2 doesn't obey reference count */ 712/*
713 * X509_STORE_free in OpenSSL versions < 1.0.2 doesn't obey reference count
714 */
636#define X509_STORE_free(store) \ 715#define X509_STORE_free(store) \
637 (compat.X509_STORE_free)((store)) 716 (compat.X509_STORE_free)((store))
638 717
@@ -672,14 +751,14 @@ static void compat_SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store) {
672} /* compat_SSL_CTX_set1_cert_store() */ 751} /* compat_SSL_CTX_set1_cert_store() */
673#endif 752#endif
674 753
675static void compat_SSL_CTX_onfree(void *_ctx, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { 754static void compat_init_SSL_CTX_onfree(void *_ctx, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) {
676 SSL_CTX *ctx = _ctx; 755 SSL_CTX *ctx = _ctx;
677 756
678 if (ctx->cert_store) { 757 if (ctx->cert_store) {
679 X509_STORE_free(ctx->cert_store); 758 X509_STORE_free(ctx->cert_store);
680 ctx->cert_store = NULL; 759 ctx->cert_store = NULL;
681 } 760 }
682} /* compat_SSL_CTX_onfree() */ 761} /* compat_init_SSL_CTX_onfree() */
683 762
684/* helper routine to determine if X509_STORE_free obeys reference count */ 763/* helper routine to determine if X509_STORE_free obeys reference count */
685static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { 764static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) {
@@ -693,90 +772,89 @@ static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPT
693 772
694static int compat_init(void) { 773static int compat_init(void) {
695 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 774 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
696 static volatile sig_atomic_t done; 775 static int store_index = -1, ssl_ctx_index = -1, done;
697 int error; 776 X509_STORE *store;
777 int error = 0;
698 778
699 if ((error = pthread_mutex_lock(&mutex))) 779 if ((error = pthread_mutex_lock(&mutex)))
700 return error; 780 return error;
701 781
702 if (!done) { 782 if (done)
703 /* 783 goto epilog;
704 * Test if X509_STORE_free obeys reference counts.
705 */
706 if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, 0, NULL, NULL, NULL, &compat_init_X509_STORE_onfree))
707 goto sslerr;
708 784
709 if (!(compat.tmp.store = X509_STORE_new())) 785 /*
710 goto sslerr; 786 * We need to unconditionally install at least one external
787 * application data callback. Because these can never be
788 * uninstalled, we can never be unloaded.
789 */
790 if ((error = dl_anchor()))
791 goto epilog;
711 792
712 CRYPTO_add(&compat.tmp.store->references, 1, CRYPTO_LOCK_X509_STORE); 793 /*
713 X509_STORE_free(compat.tmp.store); 794 * Test if X509_STORE_free obeys reference counts by installing an
795 * onfree callback.
796 */
797 if (store_index == -1
798 && -1 == (store_index = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, 0, NULL, NULL, NULL, &compat_init_X509_STORE_onfree)))
799 goto sslerr;
714 800
715 if (compat.tmp.store) { 801 if (!(compat.tmp.store = X509_STORE_new()))
716 X509_STORE_free(compat.tmp.store); 802 goto sslerr;
717 assert(compat.tmp.store == NULL); 803
718 compat.tmp.store = NULL; 804 CRYPTO_add(&compat.tmp.store->references, 1, CRYPTO_LOCK_X509_STORE);
719 } else { 805 X509_STORE_free(compat.tmp.store);
720 /*
721 * If X509_STORE_free does NOT obey reference
722 * counts, then make sure that our fixed version is
723 * called on SSL_CTX destruction. Note that this
724 * won't fix code which doesn't properly obey the
725 * reference counts when setting the cert_store
726 * member.
727 */
728 if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, 0, NULL, NULL, NULL, &compat_SSL_CTX_onfree))
729 goto sslerr;
730
731 compat.flags |= COMPAT_X509_STORE_FREE_BUG;
732 }
733 806
734 done = 1; 807 if (compat.tmp.store) {
808 /*
809 * Because our onfree callback didn't execute, we assume
810 * X509_STORE_free obeys reference counts. Alternatively,
811 * our callback might not have executed for some other
812 * reason. We assert the truth of our assumption by checking
813 * again after calling X509_STORE_free once more.
814 */
815 X509_STORE_free(compat.tmp.store);
816 assert(compat.tmp.store == NULL);
817 compat.tmp.store = NULL; /* in case assertions disabled */
818 } else {
819 /*
820 * Because our onfree callback was invoked, X509_STORE_free
821 * appears not to obey reference counts. Ensure that our
822 * fixed version is called on SSL_CTX destruction.
823 *
824 * NB: We depend on the coincidental order of operations in
825 * SSL_CTX_free that user data destruction occurs before
826 * free'ing the cert_store member. Ruby's OpenSSL bindings
827 * also depend on this order as we both use the onfree
828 * callback to clear the member.
829 */
830 if (ssl_ctx_index == -1
831 && -1 == (ssl_ctx_index = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, 0, NULL, NULL, NULL, &compat_init_SSL_CTX_onfree)))
832 goto sslerr;
833
834 compat.flags |= COMPAT_X509_STORE_FREE_BUG;
735 } 835 }
836
837 done = 1;
736epilog: 838epilog:
737 if (compat.tmp.store) { 839 if (compat.tmp.store) {
738 X509_STORE_free(compat.tmp.store); 840 X509_STORE_free(compat.tmp.store);
739 compat.tmp.store = NULL; 841 compat.tmp.store = NULL;
740 } 842 }
741 843
742 pthread_mutex_unlock(&mutex); 844 (void)pthread_mutex_unlock(&mutex);
743 845
744 return 0; 846 return error;
745sslerr: 847sslerr:
746 error = -1; 848 error = -1;
747 849
748 goto epilog; 850 goto epilog;
749syserr:
750 error = errno;
751
752 goto epilog;
753} /* compat_init() */ 851} /* compat_init() */
754 852
755 853
756typedef int auxref_t; 854/*
757typedef int auxtype_t; 855 * External Application Data Hooks
758 856 *
759static void auxL_unref(lua_State *L, auxref_t *ref) { 857 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
760 luaL_unref(L, LUA_REGISTRYINDEX, *ref);
761 *ref = LUA_NOREF;
762} /* auxL_unref() */
763
764static void auxL_ref(lua_State *L, int index, auxref_t *ref) {
765 auxL_unref(L, ref);
766 lua_pushvalue(L, index);
767 *ref = luaL_ref(L, LUA_REGISTRYINDEX);
768} /* auxL_ref() */
769
770static auxtype_t auxL_getref(lua_State *L, auxref_t ref) {
771 if (ref == LUA_NOREF || ref == LUA_REFNIL) {
772 lua_pushnil(L);
773 } else {
774 lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
775 }
776
777 return lua_type(L, -1);
778} /* auxL_getref() */
779
780 858
781struct ex_state { 859struct ex_state {
782 lua_State *L; 860 lua_State *L;
@@ -835,16 +913,43 @@ static void ex_onfree(void *parent NOTUSED, void *_data, CRYPTO_EX_DATA *ad NOTU
835 free(data); 913 free(data);
836} /* ex_onfree() */ 914} /* ex_onfree() */
837 915
838static int ex_initonce(void) { 916static int ex_init(void) {
917 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
918 static int done;
839 struct ex_type *type; 919 struct ex_type *type;
920 int error = 0;
921
922 if ((error = pthread_mutex_lock(&mutex)))
923 return error;
924
925 if (done)
926 goto epilog;
927
928 /*
929 * Our callbacks can never be uninstalled, so ensure we're never
930 * unloaded.
931 */
932 if ((error = dl_anchor()))
933 goto epilog;
840 934
841 for (type = ex_type; type < endof(ex_type); type++) { 935 for (type = ex_type; type < endof(ex_type); type++) {
936 if (type->index != -1)
937 continue;
938
842 if (-1 == (type->index = CRYPTO_get_ex_new_index(type->class_index, 0, NULL, NULL, &ex_ondup, &ex_onfree))) 939 if (-1 == (type->index = CRYPTO_get_ex_new_index(type->class_index, 0, NULL, NULL, &ex_ondup, &ex_onfree)))
843 return -1; 940 goto sslerr;
844 }; 941 };
845 942
846 return 0; 943 done = 1;
847} /* ex_initonce() */ 944epilog:
945 (void)pthread_mutex_unlock(&mutex);
946
947 return error;
948sslerr:
949 error = -1;
950
951 goto epilog;
952} /* ex_init() */
848 953
849static int ex__gc(lua_State *L) { 954static int ex__gc(lua_State *L) {
850 struct ex_state *state = lua_touserdata(L, 1); 955 struct ex_state *state = lua_touserdata(L, 1);
@@ -967,6 +1072,25 @@ static void initall(lua_State *L);
967 1072
968 1073
969/* 1074/*
1075 * compat - Lua OpenSSL
1076 *
1077 * Bindings to our internal feature detection, compatability, and workaround
1078 * code.
1079 *
1080 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1081
1082int luaopen__openssl_compat(lua_State *L) {
1083 initall(L);
1084
1085 lua_newtable(L);
1086 lua_pushboolean(L, !!(compat.flags & COMPAT_X509_STORE_FREE_BUG));
1087 lua_setfield(L, -2, "X509_STORE_FREE_BUG");
1088
1089 return 1;
1090} /* luaopen__openssl_compat() */
1091
1092
1093/*
970 * OPENSSL - openssl 1094 * OPENSSL - openssl
971 * 1095 *
972 * Miscellaneous global interfaces. 1096 * Miscellaneous global interfaces.
@@ -6257,18 +6381,11 @@ int luaopen__openssl_des(lua_State *L) {
6257 * 6381 *
6258 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 6382 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6259 6383
6260#ifndef HAVE_DLADDR
6261#define HAVE_DLADDR (!defined _AIX) /* TODO: https://root.cern.ch/drupal/content/aix-and-dladdr */
6262#endif
6263
6264static struct { 6384static struct {
6265 pthread_mutex_t *lock; 6385 pthread_mutex_t *lock;
6266 int nlock; 6386 int nlock;
6267
6268 void *dlref;
6269} mt_state; 6387} mt_state;
6270 6388
6271
6272static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUSED) { 6389static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUSED) {
6273 if (mode & CRYPTO_LOCK) 6390 if (mode & CRYPTO_LOCK)
6274 pthread_mutex_lock(&mt_state.lock[type]); 6391 pthread_mutex_lock(&mt_state.lock[type]);
@@ -6276,7 +6393,6 @@ static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUS
6276 pthread_mutex_unlock(&mt_state.lock[type]); 6393 pthread_mutex_unlock(&mt_state.lock[type]);
6277} /* mt_lock() */ 6394} /* mt_lock() */
6278 6395
6279
6280/* 6396/*
6281 * Sources include Google and especially the Wine Project. See get_unix_tid 6397 * Sources include Google and especially the Wine Project. See get_unix_tid
6282 * at http://source.winehq.org/git/wine.git/?a=blob;f=dlls/ntdll/server.c. 6398 * at http://source.winehq.org/git/wine.git/?a=blob;f=dlls/ntdll/server.c.
@@ -6309,12 +6425,16 @@ static unsigned long mt_gettid(void) {
6309#endif 6425#endif
6310} /* mt_gettid() */ 6426} /* mt_gettid() */
6311 6427
6312
6313static int mt_init(void) { 6428static int mt_init(void) {
6314 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 6429 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
6315 int bound = 0, error = 0; 6430 static int done, bound;
6431 int error = 0;
6316 6432
6317 pthread_mutex_lock(&mutex); 6433 if ((error = pthread_mutex_lock(&mutex)))
6434 return error;
6435
6436 if (done)
6437 goto epilog;
6318 6438
6319 if (!CRYPTO_get_locking_callback()) { 6439 if (!CRYPTO_get_locking_callback()) {
6320 if (!mt_state.lock) { 6440 if (!mt_state.lock) {
@@ -6324,11 +6444,20 @@ static int mt_init(void) {
6324 6444
6325 if (!(mt_state.lock = malloc(mt_state.nlock * sizeof *mt_state.lock))) { 6445 if (!(mt_state.lock = malloc(mt_state.nlock * sizeof *mt_state.lock))) {
6326 error = errno; 6446 error = errno;
6327 goto leave; 6447 goto epilog;
6328 } 6448 }
6329 6449
6330 for (i = 0; i < mt_state.nlock; i++) { 6450 for (i = 0; i < mt_state.nlock; i++) {
6331 pthread_mutex_init(&mt_state.lock[i], NULL); 6451 if ((error = pthread_mutex_init(&mt_state.lock[i], NULL))) {
6452 while (i > 0) {
6453 pthread_mutex_destroy(&mt_state.lock[--i]);
6454 }
6455
6456 free(mt_state.lock);
6457 mt_state.lock = NULL;
6458
6459 goto epilog;
6460 }
6332 } 6461 }
6333 } 6462 }
6334 6463
@@ -6341,27 +6470,11 @@ static int mt_init(void) {
6341 bound = 1; 6470 bound = 1;
6342 } 6471 }
6343 6472
6344 /* 6473 if (bound && (error = dl_anchor()))
6345 * Prevent loader from unlinking us if we've registered a callback 6474 goto epilog;
6346 * with OpenSSL by taking another reference to ourselves.
6347 */
6348#if HAVE_DLADDR
6349 if (bound && !mt_state.dlref) {
6350 Dl_info info;
6351
6352 if (!dladdr((void *)&luaopen__openssl_rand, &info)) {
6353 error = -1;
6354 goto leave;
6355 }
6356 6475
6357 if (!(mt_state.dlref = dlopen(info.dli_fname, RTLD_NOW|RTLD_LOCAL))) { 6476 done = 1;
6358 error = -1; 6477epilog:
6359 goto leave;
6360 }
6361 }
6362#endif
6363
6364leave:
6365 pthread_mutex_unlock(&mutex); 6478 pthread_mutex_unlock(&mutex);
6366 6479
6367 return error; 6480 return error;
@@ -6381,15 +6494,6 @@ static void initall(lua_State *L) {
6381 } 6494 }
6382 } 6495 }
6383 6496
6384 /* TODO: Move down to after SSL_load_error_strings */
6385 if ((error = compat_init())) {
6386 if (error == -1) {
6387 throwssl(L, "openssl.init");
6388 } else {
6389 luaL_error(L, "openssl.init: %s", xstrerror(error));
6390 }
6391 }
6392
6393 pthread_mutex_lock(&mutex); 6497 pthread_mutex_lock(&mutex);
6394 6498
6395 if (!initssl) { 6499 if (!initssl) {
@@ -6404,17 +6508,25 @@ static void initall(lua_State *L) {
6404 * already been configured. 6508 * already been configured.
6405 */ 6509 */
6406 OPENSSL_config(NULL); 6510 OPENSSL_config(NULL);
6511 }
6407 6512
6408 if ((error = ex_initonce())) { 6513 pthread_mutex_unlock(&mutex);
6409 if (error == -1) { 6514
6410 throwssl(L, "openssl.init"); 6515 if ((error = compat_init())) {
6411 } else { 6516 if (error == -1) {
6412 luaL_error(L, "openssl.init: %s", xstrerror(error)); 6517 throwssl(L, "openssl.init");
6413 } 6518 } else {
6519 luaL_error(L, "openssl.init: %s", xstrerror(error));
6414 } 6520 }
6415 } 6521 }
6416 6522
6417 pthread_mutex_unlock(&mutex); 6523 if ((error = ex_init())) {
6524 if (error == -1) {
6525 throwssl(L, "openssl.init");
6526 } else {
6527 luaL_error(L, "openssl.init: %s", xstrerror(error));
6528 }
6529 }
6418 6530
6419 ex_newstate(L); 6531 ex_newstate(L);
6420 6532
@@ -6436,5 +6548,3 @@ static void initall(lua_State *L) {
6436 addclass(L, CIPHER_CLASS, cipher_methods, cipher_metatable); 6548 addclass(L, CIPHER_CLASS, cipher_methods, cipher_metatable);
6437} /* initall() */ 6549} /* initall() */
6438 6550
6439
6440#endif /* LUAOSSL_H */