pax_global_header00006660000000000000000000000064142627336760014532gustar00rootroot0000000000000052 comment=247c0d9e12d2c654284c259f8cdb2a6ecf9d81b5 luaossl-rel-20220711/000077500000000000000000000000001426273367600142345ustar00rootroot00000000000000luaossl-rel-20220711/.gitignore000066400000000000000000000001261426273367600162230ustar00rootroot00000000000000*.o *.so *.rockspec *.rock config.h doc/*.aux doc/*.idx doc/*.log doc/*.toc doc/*.out luaossl-rel-20220711/GNUmakefile000066400000000000000000000201631426273367600163100ustar00rootroot00000000000000# non-recursive prologue sp := $(sp).x dirstack_$(sp) := $(d) d := $(abspath $(lastword $(MAKEFILE_LIST))/..) ifeq ($(origin GUARD_$(d)), undefined) GUARD_$(d) := 1 all: # default target # # G N U M A K E F U N C T I O N S # KNOWN_APIS = 5.1 5.2 5.3 5.4 # template for invoking luapath script LUAPATH := $(d)/mk/luapath LUAPATH_FN = $(shell env CC='$(subst ',\\',$(CC))' CPPFLAGS='$(subst ',\\',$(CPPFLAGS))' LDFLAGS='$(subst ',\\',$(LDFLAGS))' $(LUAPATH) -krxm3 -I '$(subst ',\\',$(DESTDIR)$(includedir))' -I/usr/include -I/usr/local/include -P '$(subst ',\\',$(DESTDIR)$(bindir))' -P '$(subst ',\\',$(bindir))' -L '$(subst ',\\',$(DESTDIR)$(libdir))' -L '$(subst ',\\',$(libdir))' -v$(1) $(2)) # check whether luapath can locate Lua $(1) headers HAVE_API_FN = $(and $(filter $(1),$(call LUAPATH_FN,$(1),version)),$(1)$(info enabling Lua $(1))) # check whether $(1) in LUA_APIS or $(LUA$(1:.=)_CPPFLAGS) is non-empty WITH_API_FN = $$(and $$(or $$(filter $(1),$$(LUA_APIS)),$$(LUA$(subst .,,$(1))_CPPFLAGS)),$(1)) # # E N V I R O N M E N T C O N F I G U R A T I O N # -include $(d)/.config prefix ?= /usr/local includedir ?= $(prefix)/include libdir ?= $(prefix)/lib datadir ?= $(prefix)/share bindir ?= $(prefix)/bin lua51cpath ?= $(libdir)/lua/5.1 lua51path ?= $(datadir)/lua/5.1 lua52cpath ?= $(libdir)/lua/5.2 lua52path ?= $(datadir)/lua/5.2 lua53cpath ?= $(libdir)/lua/5.3 lua53path ?= $(datadir)/lua/5.3 lua54cpath ?= $(libdir)/lua/5.4 lua54path ?= $(datadir)/lua/5.4 AR ?= ar RANLIB ?= ranlib M4 ?= m4 MV ?= mv RM ?= rm CP ?= cp RMDIR ?= rmdir MKDIR ?= mkdir CHMOD ?= chmod INSTALL ?= install INSTALL_DATA ?= $(INSTALL) -m 644 TOUCH ?= touch TEE ?= tee TEE_A ?= $(TEE) -a # see Lua Autodetection, below .PHONY: $(d)/config PRINT_$(d) = printf "%s = %s\n" '$(1)' '$(subst ',\\',$(2))' | $(TEE_A) '$(3)' LAZY_$(d) = \ prefix includedir libdir datadir bindir \ lua51cpath lua51path lua52cpath lua52path lua53cpath lua53path lua54cpath lua54path \ CC ALL_CPPFLAGS CPPFLAGS ALL_CFLAGS CFLAGS ALL_LDFLAGS LDFLAGS \ ALL_SOFLAGS SOFLAGS ALL_LIB LIBS \ $(foreach API,$(KNOWN_APIS),ALL_LUA$(subst .,,$(API))_CPPFLAGS) \ AR RANLIB M4 MV RM CP RMDIR MKDIR CHMOD INSTALL INSTALL_DATA TOUCH \ TEE TEE_A NONLAZY_$(d) = \ LUA_APIS \ $(foreach API,$(KNOWN_APIS),LUAC$(subst .,,$(API))) \ $(foreach API,$(KNOWN_APIS),$(and $(call WITH_API_FN,$(API)),LUA$(subst .,,$(API))_CPPFLAGS)) $(d)/config: $(TOUCH) $(@D)/.config.tmp @$(foreach V,$(LAZY_$(@D)), $(call PRINT_$(@D),$(V),$(value $(V)),$(@D)/.config.tmp);) @$(foreach V,$(NONLAZY_$(@D)), $(call PRINT_$(@D),$(V),$($(V)),$(@D)/.config.tmp);) $(MV) $(@D)/.config.tmp $(@D)/.config # add local targets if building from inside project tree ifneq "$(filter $(abspath $(d)/..)/%, $(abspath $(firstword $(MAKEFILE_LIST))))" "" .PHONY: config configure config configure: $(d)/config endif # # L U A A U T O D E T E C T I O N # # set LUA_APIS if empty or "?" ifeq ($(or $(strip $(LUA_APIS)),?),?) override LUA_APIS := $(call HAVE_API_FN,5.1) $(call HAVE_API_FN,5.2) $(call HAVE_API_FN,5.3) $(call HAVE_API_FN,5.4) endif define LUAXY_template # set luaXYcpath if empty or "?" ifeq ($$(or $$(strip $$(lua$(subst .,,$(1))cpath)),?),?) override lua$(subst .,,$(1))cpath := $$(or $$(call LUAPATH_FN,$(1),cdir),$$(libdir)/lua/$(1)) endif # set luaXYpath if empty or "?" ifeq ($$(or $$(strip $$(lua$(subst .,,$(1))path)),?),?) override lua$(subst .,,$(1))path = $$(or $$(call LUAPATH_FN,$(1),ldir),$$(datadir)/lua/$(1)) endif # set LUAXY_CPPFLAGS if undefined or "?" (NB: can be empty if path already in $(CPPFLAGS)) ifeq ($$(and $$(findstring undefined,$$(origin LUA$(subst .,,$(1))_CPPFLAGS)),?),?) override LUA$(subst .,,$(1))_CPPFLAGS = $$(and $$(call WITH_API_FN,$(1)),$$(call LUAPATH_FN,$(1),cppflags)) endif # set ALL_LUAXY_CPPFLAGS if empty or "?" ifeq ($$(or $$(strip $$(ALL_LUA$(subst .,,$(1))_CPPFLAGS)),?),?) override ALL_LUA$(subst .,,$(1))_CPPFLAGS = $$(LUA$(subst .,,$(1))_CPPFLAGS) endif # set LUAXYC if empty or "?" ifeq ($$(or $$(strip $$(LUAC$(subst .,,$(1)))),?),?) override LUAC$(subst .,,$(1)) = $$(or $$(call LUAPATH_FN,$(1),luac),true) endif endef # LUAXY_template $(eval $(call LUAXY_template,5.1)) $(eval $(call LUAXY_template,5.2)) $(eval $(call LUAXY_template,5.3)) $(eval $(call LUAXY_template,5.4)) # # A U T O D E T E C T C O M P I L A T I O N F L A G S # cc-option ?= $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi;) VENDOR_OS_$(d) := $(shell $(d)/mk/vendor.os) VENDOR_CC_$(d) := $(shell env CC="$(CC)" $(d)/mk/vendor.cc) # # ALL_CPPFLAGS # ifeq ($(origin ALL_CPPFLAGS), undefined) ifneq ($(VENDOR_OS_$(d)), OpenBSD) ALL_CPPFLAGS += -D_REENTRANT -D_THREAD_SAFE -D_GNU_SOURCE endif ifeq ($(VENDOR_OS_$(d)), SunOS) ALL_CPPFLAGS += -Usun -D_XPG4_2 -D__EXTENSIONS__ endif ALL_CPPFLAGS += $(CPPFLAGS) endif # ALL_CPPFLAGS # # ALL_CFLAGS # ifeq ($(origin ALL_CFLAGS), undefined) ifeq ($(VENDOR_CC_$(d)), gcc) ALL_CFLAGS += -O2 -std=gnu99 -fPIC ALL_CFLAGS += -g -Wall -Wextra $(call cc-option, -Wno-missing-field-initializers) $(call cc-option, -Wno-override-init) -Wno-unused endif ifeq ($(VENDOR_CC_$(d)), clang) ALL_CFLAGS += -O2 -std=gnu99 -fPIC ALL_CFLAGS += -g -Wall -Wextra -Wno-missing-field-initializers -Wno-initializer-overrides -Wno-unused -Wno-dollar-in-identifier-extension endif ifeq ($(VENDOR_CC_$(d)), sunpro) ALL_CFLAGS += -xcode=pic13 ALL_CFLAGS += -g # # Solaris Studio supports anonymous unions just fine; but it complains # incessantly about them. # ALL_CFLAGS += -erroff=E_ANONYMOUS_UNION_DECL endif ifeq ($(VENDOR_OS_$(d)), Darwin) ALL_CFLAGS += -Wno-deprecated-declarations endif ALL_CFLAGS += $(CFLAGS) endif # ALL_CFLAGS # # ALL_SOFLAGS # ifeq ($(origin ALL_SOFLAGS), undefined) ifeq ($(VENDOR_OS_$(d)), Darwin) ALL_SOFLAGS += -bundle -undefined dynamic_lookup else ALL_SOFLAGS += -shared endif ALL_SOFLAGS += $(SOFLAGS) endif # ALL_SOFLAGS # # ALL_LDFLAGS # ifeq ($(origin ALL_LDFLAGS), undefined) ALL_LDFLAGS += -L$(DESTDIR)$(libdir) -L$(libdir) ALL_LDFLAGS += $(LDFLAGS) endif # ALL_LDFLAGS # # ALL_LIBS # ifeq ($(origin ALL_LIBS), undefined) # put $(LIBS) first as they're more likely to be higher-level dependencies ALL_LIBS += $(LIBS) ALL_LIBS += -lssl -lcrypto -lpthread # NetBSD, FreeBSD, OpenBSD (and presumably descendants) lack any libdl; # dlopen, et al are part of libc. ifneq ($(patsubst %BSD,BSD,$(VENDOR_OS_$(d))), BSD) ALL_LIBS += -ldl endif # This only seems to be necessary on Linux. Darwin and OpenBSD lack a librt. # On OpenBSD clock_gettime is part of libc. Others have librt, but linking # it in is unnecessary. ifeq ($(VENDOR_OS_$(d)), Linux) ALL_LIBS += -lrt endif ALL_LIBS += -lm endif # ALL_LIBS # # P R O J E C T R U L E S # include $(d)/src/GNUmakefile $(d)/config.h: $(d)/config.h.guess $(CP) $< $@ # # C L E A N R U L E S # .PHONY: $(d)/clean~ clean~ $(d)/clean~: $(RM) -f $(@D)/*~ clean~: $(d)/clean~ # # D E B I A N R U L E S # ifneq "$(filter $(abspath $(d))/%, $(abspath $(firstword $(MAKEFILE_LIST))))" "" DPKG_BUILDPACKAGE ?= dpkg-buildpackage FAKEROOT ?= fakeroot DPKG_BUILDPACKAGE_OPTIONS ?= -b -uc -us .PHONY: $(d)/debian $(d)/debian-clean debian deb debian-clean deb-clean $(d)/debian: cd $(@D) && $(DPKG_BUILDPACKAGE) -rfakeroot $(DPKG_BUILDPACKAGE_OPTIONS) $(d)/debian-clean: cd $(@D) && $(FAKEROOT) ./debian/rules clean debian deb: $(d)/debian debian-clean deb-clean: $(d)/debian-clean endif # debian guard # # R E D H A T R U L E S # ifneq "$(filter $(abspath $(d))/%, $(abspath $(firstword $(MAKEFILE_LIST))))" "" .PHONY: $(d)/redhat $(d)/redhat-clean redhat rpm redhat-clean rpm-clean redhat rpm: $(d)/redhat redhat-clean rpm-clean: $(d)/redhat-clean endif # redhat guard # # R E L E A S E T A R B A L L R U L E S # ifneq "$(filter $(abspath $(d))/%, $(abspath $(firstword $(MAKEFILE_LIST))))" "" LUAOSSL_VERSION := $(shell $(d)/mk/changelog version) .PHONY: $(d)/luaossl-$(LUAOSSL_VERSION).tgz release $(d)/luaossl-$(LUAOSSL_VERSION).tgz: cd $(@D) && git archive --format=tar --prefix=$(basename $(@F))/ HEAD | gzip -c > $@ release: $(d)/luaossl-$(LUAOSSL_VERSION).tgz endif # release guard endif # include guard # non-recursive epilogue d := $(dirstack_$(sp)) sp := $(basename $(sp)) luaossl-rel-20220711/LICENSE000066400000000000000000000021721426273367600152430ustar00rootroot00000000000000Copyright (c) 2012-2017 William Ahern 2015-2019 Daurnimator 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. luaossl-rel-20220711/Makefile000066400000000000000000000001161426273367600156720ustar00rootroot00000000000000.POSIX: all: +gmake -f GNUmakefile all .DEFAULT: +gmake -f GNUmakefile $< luaossl-rel-20220711/config.h.guess000066400000000000000000000606461426273367600170130ustar00rootroot00000000000000/* ========================================================================== * config.h.guess - Preprocessor-based feature detection * -------------------------------------------------------------------------- * Copyright (c) 2015-2016 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #ifndef CONFIG_H_GUESS #define CONFIG_H_GUESS /* * A U T O G U E S S V E R S I O N * * Change AG_VENDOR if maintaining a fork. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define AG_VENDOR "william+autoguess@25thandClement.com" #define AG_VERSION 20170511L /* * C O M P I L E R V E N D O R / V E R S I O N D E T E C T I O N * * See http://sourceforge.net/p/predef/wiki/Compilers/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define AG_GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p)) #define AG_GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && AG_GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= AG_GNUC_2VER((M), (m), (p))) #define AG_MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p)) #define AG_MSC_PREREQ(M, m, p) (_MSC_VER_FULL > 0 && _MSC_VER_FULL >= AG_MSC_2VER((M), (m), (p))) #define AG_SUNPRO_PREREQ(M, m, p) (__SUNPRO_C > 0 && __SUNPRO_C >= 0x ## M ## m ## p) /* * C O M P I L E R / L A N G U A G E F E A T U R E D E T E C T I O N * * NOTE: The has_ and test_ macros are separate because if the test * expression uses the preprocessor "defined" operator the operand * identifier may be replaced before the expression is evaluated. Most tests * will only use arithmetic operations, but if this is not possible then the * test must be written inline, for example * * #if has_attribute(x) || (!HAVE_C___HAS_ATTRIBUTE && defined FOO) * #define HAVE___ATTRIBUTE___X * #endif * * NOTE: Solaris Studio 12.4 supports __has_attribute, but we must enclose * it in parentheses because the expansion results in a token sequence that * chokes the compiler: __has_attribute(nonnull) becomes * __has_attribute__ (nonnull), with a literal space between the preprocessor * identifier and the open parenthesis. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if defined __has_attribute #define ag_has_attribute(a) __has_attribute(a) #define ag_test_attribute(a, E) (ag_has_attribute(a)) #else #define ag_has_attribute(a) 0 #define ag_test_attribute(a, E) (E) #endif #if defined __has_extension #define ag_has_extension(x) __has_extension(x) #define ag_test_extension(x, E) (ag_has_extension(x)) #else #define ag_has_extension(x) 0 #define ag_test_extension(x, E) (E) #endif #if defined __has_include #define ag_has_include(p) __has_include(p) #define ag_test_include(p, E) (ag_has_include(p)) #else #define ag_has_include(p) 0 #define ag_test_include(p, E) (E) #endif #if defined __has_builtin #define ag_has_builtin(f) __has_builtin(f) #define ag_test_builtin(f, E) (ag_has_builtin(f)) #else #define ag_has_builtin(f) 0 #define ag_test_builtin(f, E) (E) #endif #ifndef HAVE_C___ATTRIBUTE__ #define HAVE_C___ATTRIBUTE__ (__GNUC__ || AG_SUNPRO_PREREQ(5,9,0)) #endif #ifndef HAVE_C___ATTRIBUTE___CONSTRUCTOR #define HAVE_C___ATTRIBUTE___CONSTRUCTOR ag_test_attribute(constructor, __GNUC__) #endif #ifndef HAVE_C___ATTRIBUTE___NONNULL #define HAVE_C___ATTRIBUTE___NONNULL ag_test_attribute(nonnull, AG_GNUC_PREREQ(3,3,1)) #endif #ifndef HAVE_C___ATTRIBUTE___UNUSED #define HAVE_C___ATTRIBUTE___UNUSED ag_test_attribute(unused, __GNUC__) #endif #ifndef HAVE_C___ATTRIBUTE___USED #define HAVE_C___ATTRIBUTE___USED ag_test_attribute(used, __GNUC__) #endif #ifndef HAVE_C___ATTRIBUTE___VISIBILITY #define HAVE_C___ATTRIBUTE___VISIBILITY ag_test_attribute(visibility, __GNUC__) #endif #ifndef HAVE_C___HAS_EXTENSION #define HAVE_C___HAS_EXTENSION (defined __has_extension) #endif #ifndef HAVE_C___HAS_INCLUDE #define HAVE_C___HAS_INCLUDE (defined __has_include) #endif #ifndef HAVE_C___EXTENSION__ #define HAVE_C___EXTENSION__ (__GNUC__) #endif #ifndef HAVE_C___TYPEOF #define HAVE_C___TYPEOF (_MSC_VER || __GNUC__ || AG_SUNPRO_PREREQ(5,9,0)) #endif #ifndef HAVE_C___TYPEOF__ #define HAVE_C___TYPEOF__ (__GNUC__ || __xlc__ || AG_SUNPRO_PREREQ(5,9,0)) #endif #ifndef HAVE_C__GENERIC #define HAVE_C__GENERIC ag_test_extension(c_generic_selections, (AG_GNUC_PREREQ(4,9,0) || __STDC_VERSION__ >= 201112L)) #endif #ifndef HAVE_C_STATEMENT_EXPRESSION #define HAVE_C_STATEMENT_EXPRESSION (__GNUC__ || AG_SUNPRO_PREREQ(5,9,0)) #endif #ifndef HAVE_C_TYPEOF #define HAVE_C_TYPEOF (__GNUC__ || __xlc__ || AG_SUNPRO_PREREQ(5,9,0)) #endif #ifndef HAVE___ATOMIC_FETCH_ADD #define HAVE___ATOMIC_FETCH_ADD (defined __ATOMIC_RELAXED) #endif #ifndef HAVE___ATOMIC_FETCH_SUB #define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD #endif #ifndef HAVE___BUILTIN_CHOOSE_EXPR #define HAVE___BUILTIN_CHOOSE_EXPR (AG_GNUC_PREREQ(3,1,1) || __clang__) #endif #ifndef HAVE___BUILTIN_EXPECT #define HAVE___BUILTIN_EXPECT ag_test_builtin(__builtin_expect, __GNUC__) #endif #ifndef HAVE___BUILTIN_NAN #define HAVE___BUILTIN_NAN ag_test_builtin(__builtin_nan, AG_GNUC_PREREQ(3,3,1)) #endif #ifndef HAVE___BUILTIN_TRAP #define HAVE___BUILTIN_TRAP ag_test_builtin(__builtin_trap, AG_GNUC_PREREQ(3,3,1)) #endif #ifndef HAVE___BUILTIN_TYPES_COMPATIBLE_P #define HAVE___BUILTIN_TYPES_COMPATIBLE_P (AG_GNUC_PREREQ(3,1,1) || __clang__) #endif #ifndef HAVE___BUILTIN_UNREACHABLE #define HAVE___BUILTIN_UNREACHABLE ag_test_builtin(__builtin_unreachable, AG_GNUC_PREREQ(4,5,0)) #endif #ifndef HAVE__STATIC_ASSERT #define HAVE__STATIC_ASSERT ag_test_extension(c_static_assert, (AG_GNUC_PREREQ(4,6,0) || __C11FEATURES__ || __STDC_VERSION__ >= 201112L)) #endif /* * S Y S T E M E X T E N S I O N S * * We must set these before including any headers for feature detection. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if AG_USE_SYSTEM_EXTENSIONS /* Solaris */ #ifndef __EXTENSIONS__ #define __EXTENSIONS__ 1 #endif /* AIX */ #ifndef _ALL_SOURCE #define _ALL_SOURCE 1 #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #ifndef _MINIX #define _MINIX 1 #endif /* Solaris */ #ifndef _POSIX_PTHREAD_SEMANTICS #define _POSIX_PTHREAD_SEMANTICS 1 #endif #endif /* AG_USE_SYSTEM_EXTENSIONS */ #if AG_SYS_LARGEFILE /* NOTE: BSDs and musl-libc always provide a 64-bit file API */ /* Apple */ #ifndef _DARWIN_USE_64_BIT_INODE #define _DARWIN_USE_64_BIT_INODE 1 #endif /* Solaris and glibc (per Large File Summit recommendation) */ #ifndef _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #endif /* AIX */ #ifndef _LARGE_FILES #define _LARGE_FILES 1 #endif #endif /* AG_SYS_LARGEFILE */ /* * S Y S T E M D E T E C T I O N (S T A G E 0) * * Define HAVE_FOO macros as arithmetic truth values for any predefined * system macros which have truth values solely based on whether they're * defined. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* NOTE: None so far. See stage 3 below. */ /* * S Y S T E M D E T E C T I O N (S T A G E 1) * * Include any headers necessary for minimal libc feature checking, defining * any prerequisite feature macros. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * NOTE: will indirectly include , , * , , , and similar * system headers which define most of what we care about. Among the typical * feature macros, we also get _DTRACE_VERSION. */ #include #ifndef AG_MUSL_MAYBE #define AG_MUSL_MAYBE (__linux__ && !__GLIBC__ && !__BIONIC__) #endif #ifndef HAVE_SYS_PARAM_H #define HAVE_SYS_PARAM_H ag_test_include(, !AG_MUSL_MAYBE) #endif /* * NOTE: Conditionally load so we don't unnecessarily pollute * the namespace. */ #if HAVE_SYS_PARAM_H && !__linux__ && !__sun && !_AIX #include /* __FreeBSD_version __NetBSD_Prereq__ BSD OpenBSD */ #endif #include /* F_DUPFD_CLOEXEC */ /* * S Y S T E M D E T E C T I O N (S T A G E 2) * * Macros which determine libc vendor and version. * * See http://sourceforge.net/p/predef/wiki/Libraries/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define AG_AIX_PREREQ(M, m) (_AIX # M # m) #if defined __GLIBC_PREREQ && !defined __UCLIBC__ #define AG_GLIBC_PREREQ(M, m) (__GLIBC_PREREQ(M, m)) #else #define AG_GLIBC_PREREQ(M, m) 0 #endif #define AG_FREEBSD_2VER(M, m, p) (((M) * 100000) + ((m) * 1000) + (p)) #define AG_FREEBSD_PREREQ(M, m, p) (__FreeBSD__ > 0 && __FreeBSD_version >= AG_FREEBSD_2VER((M), (m), (p))) #define AG_IPHONE_2VER(M, m) (((M) * 10000) + ((m) * 100)) #if defined __IPHONE_OS_VERSION_MIN_REQUIRED #define AG_IPHONE_PREREQ(M, m) (AG_IPHONE_2VER((M), (m)) <= __IPHONE_OS_VERSION_MIN_REQUIRED) #else #define AG_IPHONE_PREREQ(M, m) 0 #endif #if defined __NetBSD_Prereq__ #define AG_NETBSD_PREREQ(M, m, p) (!__minix && __NetBSD_Prereq__(M, m, p)) #else #define AG_NETBSD_PREREQ(M, m, p) 0 #endif #define AG_MACOS_2VER_10_9(M, m, p) (((M) * 100) + ((m) * 10)) #define AG_MACOS_2VER_10_10(M, m, p) (((M) * 10000) + ((m) * 100) + (p)) #define AG_MACOS_PREREQ_10_10(M, m, p) (((M) > 10 || ((M) == 10 && (m) >= 10)) && AG_MACOS_2VER_10_10((M), (m), (p)) <= __MAC_OS_X_VERSION_MIN_REQUIRED) #define AG_MACOS_PREREQ_10_9(M, m, p) (((M) == 10 && (m) < 10) && AG_MACOS_2VER_10_9((M), (m), (p)) <= __MAC_OS_X_VERSION_MIN_REQUIRED) #if defined __MAC_OS_X_VERSION_MIN_REQUIRED #define AG_MACOS_PREREQ(M, m, p) (AG_MACOS_PREREQ_10_10((M), (m), (p)) || AG_MACOS_PREREQ_10_9((M), (m), (p))) #else #define AG_MACOS_PREREQ(M, m, p) 0 #endif #define AG_OPENBSD_PREREQ_0_0 (__OpenBSD__) #define AG_OPENBSD_PREREQ_5_5 (OpenBSD >= 201405) #define AG_OPENBSD_PREREQ_5_6 (OpenBSD >= 201411) #define AG_OPENBSD_PREREQ_5_7 (OpenBSD >= 201505) #define AG_OPENBSD_PREREQ(M, m) (AG_OPENBSD_PREREQ_ ## M ## _ ## m) #define AG_SUNOS_PREREQ_5_10 (__sun && _DTRACE_VERSION) #define AG_SUNOS_PREREQ_5_11 (__sun && F_DUPFD_CLOEXEC) #define AG_SUNOS_PREREQ(M, m) (AG_SUNOS_PREREQ_ ## M ## _ ## m) #define AG_UCLIBC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p)) #if defined __UCLIBC__ #define AG_UCLIBC_PREREQ(M, m, p) (AG_UCLIBC_2VER(__UCLIBC_MAJOR__, __UCLIBC_MINOR__, __UCLIBC_SUBLEVEL__) >= AG_UCLIBC_2VER((M), (m), (p))) #else #define AG_UCLIBC_PREREQ(M, m, p) 0 #endif /* * S Y S T E M D E T E C T I O N (S T A G E 3) * * Define HAVE_FOO macros as arithmetic truth values for any system macros * which have a truth value solely based on whether they're defined. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE___EXTENSIONS__ #ifdef __EXTENSIONS__ #define HAVE___EXTENSIONS__ 1 #endif #endif #ifndef HAVE__ALL_SOURCE #ifdef _ALL_SOURCE #define HAVE__ALL_SOURCE 1 #endif #endif #ifndef HAVE__GNU_SOURCE #ifdef _GNU_SOURCE #define HAVE__GNU_SOURCE 1 #endif #endif #ifndef HAVE__MINIX #if defined _MINIX || (defined __minix && defined _NETBSD_SOURCE) #define HAVE__MINIX 1 #endif #endif #ifndef HAVE__POSIX_PTHREAD_SEMANTICS #ifdef _POSIX_PTHREAD_SEMANTICS #define HAVE__POSIX_PTHREAD_SEMANTICS 1 #endif #endif #ifndef HAVE__REENTRANT #ifdef _REENTRANT #define HAVE__REENTRANT 1 #endif #endif /* * H E A D E R D E T E C T I O N * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE_DLFCN_H #define HAVE_DLFCN_H ag_test_include(, 1) #endif #ifndef HAVE_IFADDRS_H #define HAVE_IFADDRS_H_ (!_AIX && (!__sun || AG_SUNOS_PREREQ(5,11))) #define HAVE_IFADDRS_H ag_test_include(, HAVE_IFADDRS_H_) #endif #ifndef HAVE_INTTYPES_H #define HAVE_INTTYPES_H 1 #endif #ifndef HAVE_MACH_CLOCK_H #define HAVE_MACH_CLOCK_H ag_test_include(, __APPLE__) #endif #ifndef HAVE_MACH_MACH_H #define HAVE_MACH_MACH_H ag_test_include(, __APPLE__) #endif #ifndef HAVE_MACH_MACH_TIME_H #define HAVE_MACH_MACH_TIME_H ag_test_include(, __APPLE__) #endif #ifndef HAVE_MEMORY_H #define HAVE_MEMORY_H 1 #endif #ifndef HAVE_PORT_H #define HAVE_PORT_H ag_test_include(, AG_SUNOS_PREREQ(5,10)) #endif /* TODO: Maybe test _POSIX_THREADS from . */ #ifndef HAVE_PTHREAD_H #define HAVE_PTHREAD_H ag_test_include(, !__minix) #endif #ifndef HAVE_STDINT_H #define HAVE_STDINT_H 1 #endif #ifndef HAVE_STDLIB_H #define HAVE_STDLIB_H 1 #endif #ifndef HAVE_STRING_H #define HAVE_STRING_H 1 #endif #ifndef HAVE_STRINGS_H #define HAVE_STRINGS_H 1 #endif #ifndef HAVE_SYS_AUXV_H #define HAVE_SYS_AUXV_H_ (AG_GLIBC_PREREQ(2,16) || (!AG_GLIBC_PREREQ(0,0) && __linux__) || __sun) #define HAVE_SYS_AUXV_H ag_test_include(, HAVE_SYS_AUXV_H_) #endif #ifndef HAVE_SYS_EPOLL_H #define HAVE_SYS_EPOLL_H ag_test_include(, __linux__) #endif #ifndef HAVE_SYS_EVENT_H #define HAVE_SYS_EVENT_H ag_test_include(, BSD) #endif #ifndef HAVE_SYS_EVENTFD_H #define HAVE_SYS_EVENTFD_H_ (AG_GLIBC_PREREQ(2,8) || (!AG_GLIBC_PREREQ(0,0) && __linux__) || defined EFD_CLOEXEC) #define HAVE_SYS_EVENTFD_H ag_test_include(, HAVE_SYS_EVENTFD_H_) #endif #ifndef HAVE_SYS_INOTIFY_H #define HAVE_SYS_INOTIFY_H ag_test_include(, __linux__) #endif #ifndef HAVE_SYS_RANDOM_H #define HAVE_SYS_RANDOM_H_ (__sun && defined SYS_getrandom) /* requires #include :( */ #define HAVE_SYS_RANDOM_H ag_test_include(, HAVE_SYS_RANDOM_H_) #endif #ifndef HAVE_SYS_SIGNALFD_H #define HAVE_SYS_SIGNALFD_H_ (AG_GLIBC_PREREQ(2,8) || (!AG_GLIBC_PREREQ(0,0) && __linux__) || defined SFD_CLOEXEC) #define HAVE_SYS_SIGNALFD_H ag_test_include(, HAVE_SYS_SIGNALFD_H_) #endif #ifndef HAVE_SYS_SOCKIO_H #define HAVE_SYS_SOCKIO_H ag_test_include(, (__sun || BSD)) #endif #ifndef HAVE_SYS_STAT_H #define HAVE_SYS_STAT_H 1 #endif #ifndef HAVE_SYS_SYSCALL_H #define HAVE_SYS_SYSCALL_H_ (BSD || __linux__ || __sun) #define HAVE_SYS_SYSCALL_H ag_test_include(, HAVE_SYS_SYSCALL_H_) #endif #ifndef HAVE_SYS_SYSCTL_H #define HAVE_SYS_SYSCTL_H ag_test_include(, (BSD || __GLIBC__)) #endif #ifndef HAVE_SYS_TIMERFD_H #define HAVE_SYS_TIMERFD_H_ (AG_GLIBC_PREREQ(2,8) || (!AG_GLIBC_PREREQ(0,0) && __linux__) || defined TFD_CLOEXEC) #define HAVE_SYS_TIMERFD_H ag_test_include(, HAVE_SYS_TIMERFD_H_) #endif #ifndef HAVE_SYS_TYPES_H #define HAVE_SYS_TYPES_H 1 #endif #ifndef HAVE_UNISTD_H #define HAVE_UNISTD_H 1 #endif /* * T Y P E D E T E C T I O N * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE_CLOCKID_T #define HAVE_CLOCKID_T (defined CLOCK_MONOTONIC) #endif #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN #define HAVE_STRUCT_SOCKADDR_SA_LEN (!__linux__ && !__sun) #endif #ifndef HAVE_STRUCT_STAT_ST_ATIM #define HAVE_STRUCT_STAT_ST_ATIM (defined st_atime && ((!__APPLE__ && (!__NetBSD__ || AG_NETBSD_PREREQ(7,0,0))) || !HAVE_STRUCT_STAT_ST_ATIMESPEC)) #endif #ifndef HAVE_STRUCT_STAT_ST_CTIM #define HAVE_STRUCT_STAT_ST_CTIM HAVE_STRUCT_STAT_ST_ATIM #endif #ifndef HAVE_STRUCT_STAT_ST_MTIM #define HAVE_STRUCT_STAT_ST_MTIM HAVE_STRUCT_STAT_ST_ATIM #endif #ifndef HAVE_STRUCT_STAT_ST_ATIMESPEC #define HAVE_STRUCT_STAT_ST_ATIMESPEC (__APPLE__ || defined st_atimespec || defined st_atimensec) #endif #ifndef HAVE_STRUCT_STAT_ST_CTIMESPEC #define HAVE_STRUCT_STAT_ST_CTIMESPEC HAVE_STRUCT_STAT_ST_ATIMESPEC #endif #ifndef HAVE_STRUCT_STAT_ST_MTIMESPEC #define HAVE_STRUCT_STAT_ST_MTIMESPEC HAVE_STRUCT_STAT_ST_ATIMESPEC #endif #ifndef HAVE_STRUCT_STAT_ST_BLOCKS #define HAVE_STRUCT_STAT_ST_BLOCKS 1 #endif #ifndef HAVE_STRUCT_STAT_ST_BLKSIZE #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 #endif #ifndef HAVE_STRUCT_STAT_ST_RDEV #define HAVE_STRUCT_STAT_ST_RDEV 1 #endif /* * D E C L A R A T I O N D E T E C T I O N * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE___DECL_LIBC_ENABLE_SECURE #define HAVE___DECL_LIBC_ENABLE_SECURE 0 #endif #ifndef HAVE_DECL_CLOCK_GETTIME #define HAVE_DECL_CLOCK_GETTIME HAVE_DECL_CLOCK_MONOTONIC #endif #ifndef HAVE_DECL_CLOCK_MONOTONIC #define HAVE_DECL_CLOCK_MONOTONIC (defined CLOCK_MONOTONIC) #endif #ifndef HAVE_DECL_CLOCK_REALTIME #define HAVE_DECL_CLOCK_REALTIME (defined CLOCK_REALTIME) #endif #ifndef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME #define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME (__linux__ && HAVE__GNU_SOURCE) #endif #ifndef HAVE_DECL_PTHREAD_MUTEX_ROBUST #define HAVE_DECL_PTHREAD_MUTEX_ROBUST (defined PTHREAD_MUTEX_ROBUST || AG_GLIBC_PREREQ(2,12)) #endif #ifndef HAVE_DECL_RANDOM_UUID /* RANDOM_UUID is an enum, not macro */ #if (HAVE_SYS_SYSCTL_H && defined __linux__) #define HAVE_DECL_RANDOM_UUID 1 #else #define HAVE_DECL_RANDOM_UUID 0 #endif #endif #ifndef HAVE_DECL_STRERROR_R #define HAVE_DECL_STRERROR_R 1 #endif #ifndef HAVE_DECL_SYS_SIGLIST #define HAVE_DECL_SYS_SIGLIST (!AG_MUSL_MAYBE && !__sun && !_AIX) #endif #ifndef HAVE_DECL_SYS_GETRANDOM #ifdef SYS_getrandom #define HAVE_DECL_SYS_GETRANDOM 1 #else #define HAVE_DECL_SYS_GETRANDOM 0 #endif #endif /* * V A R I A B L E D E T E C T I O N * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE___LIBC_ENABLE_SECURE #define HAVE___LIBC_ENABLE_SECURE AG_GLIBC_PREREQ(2,1) /* added to glibc between 2.0.98 and 2.0.99 */ #endif #ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME #define HAVE_PROGRAM_INVOCATION_SHORT_NAME (__linux__) #endif #ifndef HAVE_SYS_SIGLIST #define HAVE_SYS_SIGLIST HAVE_DECL_SYS_SIGLIST #endif /* * F U N C T I O N D E T E C T I O N * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef HAVE_ACCEPT4 #define HAVE_ACCEPT4 (defined SOCK_CLOEXEC && !__NetBSD__) #endif #ifndef HAVE_ARC4RANDOM #define HAVE_ARC4RANDOM \ (__APPLE__ || __DragonFly__ || __FreeBSD__ || __NetBSD__ || \ __OpenBSD__ || __minix) #endif #ifndef HAVE_ARC4RANDOM_ADDRANDOM #define HAVE_ARC4RANDOM_ADDRANDOM (HAVE_ARC4RANDOM && !AG_OPENBSD_PREREQ(5,5)) #endif #ifndef HAVE_ARC4RANDOM_BUF #define HAVE_ARC4RANDOM_BUF_APPLE_ (!__APPLE__ || AG_MACOS_PREREQ(10,7,0) || AG_IPHONE_PREREQ(4,3)) #define HAVE_ARC4RANDOM_BUF_NETBSD_ (!__NetBSD__ || AG_NETBSD_PREREQ(6,0,0)) #define HAVE_ARC4RANDOM_BUF_IFF_ (HAVE_ARC4RANDOM_BUF_APPLE_ && HAVE_ARC4RANDOM_BUF_NETBSD_) #define HAVE_ARC4RANDOM_BUF (HAVE_ARC4RANDOM && HAVE_ARC4RANDOM_BUF_IFF_) #endif #ifndef HAVE_ARC4RANDOM_STIR #define HAVE_ARC4RANDOM_STIR HAVE_ARC4RANDOM_ADDRANDOM #endif #ifndef HAVE_CLOCK_GETTIME #define HAVE_CLOCK_GETTIME (!__APPLE__ || AG_MACOS_PREREQ(10,12,0)) #endif #ifndef HAVE_DLADDR #define HAVE_DLADDR (HAVE_DLOPEN && !_AIX && ((!__GLIBC__ && !AG_MUSL_MAYBE) || HAVE__GNU_SOURCE)) #endif #ifndef HAVE_DLOPEN #define HAVE_DLOPEN HAVE_DLFCN_H #endif #ifndef HAVE_DLSYM #define HAVE_DLSYM HAVE_DLOPEN #endif #ifndef HAVE_DUP2 #define HAVE_DUP2 1 #endif #ifndef HAVE_DUP3 #define HAVE_DUP3 (AG_GLIBC_PREREQ(2,9) || AG_FREEBSD_PREREQ(10,0,0) || AG_NETBSD_PREREQ(6,0,0) || AG_UCLIBC_PREREQ(0,9,34) || AG_MUSL_MAYBE || __BIONIC__ || AG_OPENBSD_PREREQ(5,7)) #endif #ifndef HAVE_FDOPENDIR #define HAVE_FDOPENDIR ( \ (!__APPLE__ || AG_MACOS_PREREQ(10,10,0) || AG_IPHONE_PREREQ(8,0)) \ && (!__NetBSD__ || AG_NETBSD_PREREQ(6,0,0)) \ ) #endif #ifndef HAVE_EPOLL_CREATE #define HAVE_EPOLL_CREATE HAVE_SYS_EPOLL_H #endif #if HAVE_SYS_EPOLL_H #include #endif #ifndef HAVE_EPOLL_CREATE1 #define HAVE_EPOLL_CREATE1 (HAVE_EPOLL_CREATE && (defined EPOLL_CLOEXEC || AG_GLIBC_PREREQ(2,9))) #endif #ifndef HAVE_EPOLL_CTL #define HAVE_EPOLL_CTL HAVE_EPOLL_CREATE #endif #ifndef HAVE_EPOLL_PWAIT #define HAVE_EPOLL_PWAIT (HAVE_EPOLL_WAIT && (AG_GLIBC_PREREQ(2,6) || (!AG_GLIBC_PREREQ(0,0) && defined EPOLL_CLOEXEC))) #endif #ifndef HAVE_EPOLL_WAIT #define HAVE_EPOLL_WAIT HAVE_EPOLL_CREATE #endif #ifndef HAVE_EVENTFD #define HAVE_EVENTFD HAVE_SYS_EVENTFD_H #endif #ifndef HAVE_GETAUXVAL #define HAVE_GETAUXVAL (HAVE_SYS_AUXV_H && !__sun) #endif #ifndef HAVE_GETENTROPY #define HAVE_GETENTROPY (AG_OPENBSD_PREREQ(5,6) || (HAVE_SYS_RANDOM_H && __sun)) #endif #ifndef HAVE_GETENV_R #define HAVE_GETENV_R (AG_NETBSD_PREREQ(4,0,0) || __minix) #endif #ifndef HAVE_GETEXECNAME #define HAVE_GETEXECNAME (__sun) #endif #ifndef HAVE_GETIFADDRS #define HAVE_GETIFADDRS (HAVE_IFADDRS_H && !__sun) #endif #ifndef HAVE_GETPROGNAME #define HAVE_GETPROGNAME (HAVE_ARC4RANDOM || AG_SUNOS_PREREQ(5,11)) #endif #ifndef HAVE_GETRANDOM #define HAVE_GETRANDOM (HAVE_SYS_RANDOM_H && __sun) #endif #ifndef HAVE_INOTIFY_INIT #define HAVE_INOTIFY_INIT HAVE_SYS_INOTIFY_H #endif #ifndef HAVE_INOTIFY_INIT1 #define HAVE_INOTIFY_INIT1 (HAVE_INOTIFY_INIT && defined IN_CLOEXEC) #endif #ifndef HAVE_ISSETUGID #define HAVE_ISSETUGID ((!__linux__ || (AG_MUSL_MAYBE && HAVE__GNU_SOURCE)) && !_AIX) #endif #if HAVE_SYS_EVENT_H #include #endif #ifndef HAVE_KEVENT #define HAVE_KEVENT (defined EV_SET) #endif #ifndef HAVE_KQUEUE #define HAVE_KQUEUE HAVE_KEVENT #endif #ifndef HAVE_KQUEUE1 #define HAVE_KQUEUE1 (HAVE_KQUEUE && AG_NETBSD_PREREQ(6,0,0)) #endif #ifndef HAVE_OPENAT #define HAVE_OPENAT \ ((!__APPLE__ || AG_MACOS_PREREQ(10,10,0) || AG_IPHONE_PREREQ(8,0)) \ && (!__NetBSD__ || AG_NETBSD_PREREQ(7,0,0))) #endif #ifndef HAVE_MKDIRAT #define HAVE_MKDIRAT HAVE_OPENAT #endif #ifndef HAVE_MKFIFOAT #define HAVE_MKFIFOAT (!__APPLE__ && (!__NetBSD__ || AG_NETBSD_PREREQ(7,0,0))) #endif #ifndef HAVE_PACCEPT #define HAVE_PACCEPT AG_NETBSD_PREREQ(6,0,0) #endif #ifndef HAVE_PIPE2 #define HAVE_PIPE2 (AG_GLIBC_PREREQ(2,9) || AG_FREEBSD_PREREQ(10,0,0) || AG_NETBSD_PREREQ(6,0,0) || AG_UCLIBC_PREREQ(0,9,32) || AG_MUSL_MAYBE || __BIONIC__ || AG_OPENBSD_PREREQ(5,7)) #endif #ifndef HAVE_PORT_ALERT #define HAVE_PORT_ALERT HAVE_PORT_CREATE #endif #ifndef HAVE_PORT_ASSOCIATE #define HAVE_PORT_ASSOCIATE HAVE_PORT_CREATE #endif #ifndef HAVE_PORT_CREATE #define HAVE_PORT_CREATE HAVE_PORT_H #endif #ifndef HAVE_PORT_DISSOCIATE #define HAVE_PORT_DISSOCIATE HAVE_PORT_CREATE #endif #ifndef HAVE_PORT_GET #define HAVE_PORT_GET HAVE_PORT_CREATE #endif #ifndef HAVE_PORT_GETN #define HAVE_PORT_GETN HAVE_PORT_CREATE #endif #ifndef HAVE_PORT_SEND #define HAVE_PORT_SEND HAVE_PORT_CREATE #endif #ifndef HAVE_PORT_SENDN #define HAVE_PORT_SENDN HAVE_PORT_CREATE #endif #ifndef HAVE_POSIX_FADVISE #define HAVE_POSIX_FADVISE (defined POSIX_FADV_NORMAL || AG_GLIBC_PREREQ(2,2) || __sun || AG_MUSL_MAYBE || AG_FREEBSD_PREREQ(9,0,0)) #endif #ifndef HAVE_POSIX_FALLOCATE #define HAVE_POSIX_FALLOCATE (_AIX || AG_FREEBSD_PREREQ(9,0,0) || AG_GLIBC_PREREQ(2,2) || AG_MUSL_MAYBE || AG_NETBSD_PREREQ(7,0,0) || __sun) #endif #ifndef HAVE_RENAMEAT #define HAVE_RENAMEAT HAVE_OPENAT #endif #ifndef HAVE_SIGNALFD #define HAVE_SIGNALFD HAVE_SYS_SIGNALFD_H #endif #ifndef HAVE_SIGTIMEDWAIT #define HAVE_SIGTIMEDWAIT (!__APPLE__ && !__OpenBSD__) #endif #ifndef HAVE_SIGWAIT #define HAVE_SIGWAIT (!__minix) #endif #ifndef HAVE_STATIC_ASSERT #if AG_GLIBC_PREREQ(0,0) && !HAVE__STATIC_ASSERT #define HAVE_STATIC_ASSERT 0 /* glibc doesn't check GCC version */ #else #define HAVE_STATIC_ASSERT (defined static_assert) #endif #endif #ifndef HAVE_STRERROR_R #define HAVE_STRERROR_R 1 #endif #ifndef HAVE_SYSCALL #define HAVE_SYSCALL HAVE_SYS_SYSCALL_H #endif #ifndef HAVE_SYSCTL #define HAVE_SYSCTL HAVE_SYS_SYSCTL_H #endif #ifndef HAVE_TIMERFD_CREATE #define HAVE_TIMERFD_CREATE HAVE_SYS_TIMERFD_H #endif #ifndef HAVE_TIMERFD_GETTIME #define HAVE_TIMERFD_GETTIME HAVE_TIMERFD_CREATE #endif #ifndef HAVE_TIMERFD_SETTIME #define HAVE_TIMERFD_SETTIME HAVE_TIMERFD_CREATE #endif #ifndef HAVE_UNLINKAT #define HAVE_UNLINKAT HAVE_OPENAT #endif #ifndef STRERROR_R_CHAR_P #define STRERROR_R_CHAR_P ((AG_GLIBC_PREREQ(0,0) || AG_UCLIBC_PREREQ(0,0,0)) && (HAVE__GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600))) #endif #endif /* CONFIG_H_GUESS */ luaossl-rel-20220711/debian/000077500000000000000000000000001426273367600154565ustar00rootroot00000000000000luaossl-rel-20220711/debian/changelog000066400000000000000000000236011426273367600173320ustar00rootroot00000000000000liblua-openssl (20220711-0) unstable; urgency=low * fix luaL_Buffer usage (#189) * fix OpenSSL 3 compatibility (#199) * add cipher:getTag() / cipher:setTag() for AEAD (#201) -- Daurnimator Mon, 11 Jul 2022 15:39:13 +1000 liblua-openssl (20200709-0) unstable; urgency=low * fix loading from DER files when type set to any (#177) * fix lifetime of certificates from <2000 (#178) -- Daurnimator Thu, 09 Jul 2020 23:09:31 +1000 liblua-openssl (20190731-0) unstable; urgency=low * introduce workarounds for LuaJIT 47bit userdata (#173) -- Daurnimator Wed, 31 Jul 2019 23:14:21 +1000 liblua-openssl (20190612-0) unstable; urgency=low * Add kdf module for key derivation (#154) * Add cert:verify() to verify certificates without a store (#167) * Add support for arbitrary pkey types (#161) * Rename :setCurvesList() to :setGroups() (old alias kept for now) * Note: This is the last release to support OpenSSL 0.9.8 (#169) -- Daurnimator Wed, 12 Jun 2019 17:24:48 +1000 liblua-openssl (20181207-0) unstable; urgency=low * Add context.pushffi * Add :setCertificateChain() and :getCertificateChain() -- Daurnimator Fri, 07 Dec 2018 14:42:26 -0800 liblua-openssl (20181102-0) unstable; urgency=low * Update SSL options * Add Basic TLSv1.3 support * Cache objects so that equal pointers result in same lua object * Fix non-DER value for CA basic constraint * Add context:getContext() * Add context:addCustomExtension() and openssl.extensionSupported() * Add context:useServerInfo() and context:useServerInfoFile() * Add ssl and context getter+setter for readahead flag * Add ssl and context :setCipherSuites() for TLSv1.3 * Add conspicuously missing ssl:setCipherList() -- Daurnimator Fri, 02 Nov 2018 17:37:23 +1100 liblua-openssl (20180708-0) unstable; urgency=low * Fix incorrect class check in :getTLSextStatusType() * Update lua-compat-5.3 * Add context:setTicketKeys(), context:getTicketKeys(), context:getTicketKeysLength() -- Daurnimator Sun, 08 Jul 2018 23:49:25 +1000 liblua-openssl (20180530-0) unstable; urgency=low * Bind functions for manipulating csr requested extensions * Add :toPEM() to various objects * Bind modular bignum functions * Add ssl:getMasterKey() * Add ssl.pushffi() * Add ssl:getCertificate() and context:getCertificate() * store:add("./empty-file") no longer throws * Add ssl:getServerTemporaryKey() * Add x509.crl:lookupSerial() and x509.crl:lookupCertificate() * Fix precision loss when using Lua 5.3 with 64bit integers. -- Daurnimator Wed, 30 May 2018 17:44:42 +1000 liblua-openssl (20171028-0) unstable; urgency=low * Add win32 support * Fix bug where exp would be NULL in pkey.new() -- Daurnimator Sat, 28 Oct 2017 13:19:32 +1100 liblua-openssl (20170903-0) unstable; urgency=low * Fix pkey.new failing when generating RSA keys * Fix loading C modules clearing interposed fields * Fix building compat-5.3.o -- Daurnimator Sun, 03 Sep 2017 22:39:20 +1000 liblua-openssl (20170901-0) unstable; urgency=low * New openssl.ocsp.basic and openssl.ocsp.response modules * Add x509:getOCSP() * Add x509:getSignatureName() (#79) * Add crl:verify(publickey) * Add pkcs12.parse(bag[, passphrase]) * Add context:setStore(store) and context:getStore() * Add context:setParam(params) and context:getParam() * Add context:setCurvesList(string [, ...]) * Add context:setAlpnSelect(cb) * Add context:setTLSextStatusType(type) and context:getTLSextStatusType() * Add ssl:getVerifyResult() (#75) * Add ssl:setContext(context) (#84) * Add ssl:setVerify([mode][, depth]) and ssl:getVerify() (#84) * Add ssl:setCertificate(crt), ssl:setPrivateKey(key), ssl:setCurvesList(string [, ...]) (#84) * Add ssl:setTLSextStatusType(type) and ssl:getTLSextStatusType() * Add ssl:setTLSextStatusOCSPResp(or) and ssl:getTLSextStatusOCSPResp() * Use lua-compat-5.3 (fixes LuaJIT header file compatibility) (#94) * Add generator field to replace exp when generating a DH key * Move away from interfaces deprecated in OpenSSL 1.1.0 -- Daurnimator Fri, 01 Sep 2017 14:20:00 +1000 liblua-openssl (20161214-0) unstable; urgency=low * Refactor of bignum operations, fixes bn:sqr() -- William Ahern liblua-openssl (20161209-0) unstable; urgency=low * Add ssl:getVerifyResult() -- William Ahern liblua-openssl (20161208-0) unstable; urgency=low * openssl.x509.store:addDefaults() new function to add the operating system's default ca's to a certificate store. * openssl.x509.store:add() can now take a CRL * openssl.ssl.context:getStore() new function that returns a reference to a context's certificate store * openssl.pkey:encrypt() and openssl.pkey:decrypt() * openssl.ssl.new() to construct an SSL* given a SSL_CTX* * Bindings for X509_VERIFY_PARAM* -- William Ahern liblua-openssl (20161101-0) unstable; urgency=low * Rename bignum methods tobin, todec, tohex to CamelCase: toDecimal, toDecimal, toHex -- William Ahern liblua-openssl (20161029-0) unstable; urgency=low * Add lots of bignum methods * Allow hex strings creating bignums * Expose openssl.x509.csr * Use autoguess project to get platform features -- William Ahern liblua-openssl (20151221-0) unstable; urgency=low * Add :tohex and :todec methods to bignums, and make metamethods accessible directly. (daurnimator) * Add __idiv metamethod for Lua 5.3. (daurnimator) -- William Ahern Mon, 21 Dec 2015 02:35:12 -0800 liblua-openssl (20151218-0) unstable; urgency=low * Add :tobin method to bignums. (daurnimator) * Add :getParameters method to pkeys. (daurnimator) * Fix build when SSLv3 support is not present. -- William Ahern Fri, 18 Dec 2015 03:09:29 -0800 liblua-openssl (20150727-0) unstable; urgency=low * More extension work from Kaarle Ritvanen. * Add DTLS support. * More extension work from kunkku. * Fix bug in ex_newstate which could cause application data attached to OpenSSL objects using OpenSSL's external application data API to be prematurely invalidated as-if the Lua interperter was destroyed. -- William Ahern Mon, 27 Jul 2015 01:42:46 -0700 liblua-openssl (20150504-0) unstable; urgency=low * Use lightuserdata as registry keys. C function hashes aren't stable in LuaJIT. * Add openssl.version as binding for SSLeay_version. * Fix build on OpenBSD 5.6 libressl. -- William Ahern Mon, 04 May 2015 17:49:08 -0700 liblua-openssl (20150422-0) unstable; urgency=low * Add support for ALPN server callback, SSL_CTX_set_alpn_select_cb. * Fix X509_STORE double-free bug on older OpenSSL releases (< 1.0.2) by implementing and using our own X509_STORE_free routine which properly checks reference counts. Workaround adapted from Ruby OpenSSL bindings. * Fix strerror_r usage on glibc. -- William Ahern Wed, 22 Apr 2015 15:39:14 -0700 liblua-openssl (20150304-0) unstable; urgency=low * Merge ALPN support from quae@daurnimator.com. -- William Ahern Wed, 04 Mar 2015 18:11:13 -0800 liblua-openssl (20150225-0) unstable; urgency=low * Add DES module to help implement NTLM authentication protocol. -- William Ahern Wed, 25 Feb 2015 12:46:41 -0800 liblua-openssl (20141028-0) unstable; urgency=low * Add ssl:getVersion and ssl:getClientVersion. * Fix "TLS" and "SSL" method names for context.new. OpenSSL TLSv1_method() literally only speaks 1.0, not 1.0 and above. "TLS" now uses SSLv23_method and disables SSLv2 and SSLv3. "SSL" uses SSLv23_method and disables SSLv2. -- William Ahern Tue, 28 Oct 2014 21:03:23 -0700 liblua-openssl (20140923-0) unstable; urgency=low * Add more CRL support from Kaarle Ritvanen. * Add prelimiary 5.3 support. * Add SSL_CTX and SSL option support. * Add ephemeral key support. * Add Server Name Indication (SNI) support. * Fix issue which prevented loading public and private keys together. * Add bindings to opensslv.h and opensslconf.h. -- William Ahern Tue, 23 Sep 2014 20:32:32 -0700 liblua-openssl (20140718-0) unstable; urgency=low * Add CRL spport from Kaarle Ritvanen. * Add PKCS1 support from Kaarle Ritvanen. * Add AIX platform support. * Add rand.stir. -- William Ahern Fri, 18 Jul 2014 22:44:31 -0700 liblua-openssl (20140328-0) unstable; urgency=low * Add DER input/output formats. * Add GEN_DIRNAME alternative names. * Change the return value of several methods from boolean true to the method object, to allow easy call chaining in Lua. * Fix rand.uniform to use lua_Unsigned when it's a 64-bit type (Lua 5.3). * Rename openssl.pubkey to openssl.pkey. -- William Ahern Fri, 28 Mar 2014 22:44:31 -0700 liblua-openssl (20140322-0) unstable; urgency=low * Add Lua 5.3 support. * Add user guide. -- William Ahern Sat, 22 Mar 2014 20:23:56 -0800 liblua-openssl (20140131-0) unstable; urgency=low * Add multi-threaded re-entrancy protection, including explicitly synchronizing OpenSSL initialization because OpenSSL doesn't appear to use its own locking callbacks from initialization routines. -- William Ahern Fri, 31 Jan 2014 14:27:30 -0800 liblua-openssl (20131209-1) unstable; urgency=low * Initial release after splitting from cqueues project. -- William Ahern Sun, 09 Dec 2013 21:17:33 -0800 luaossl-rel-20220711/debian/compat000066400000000000000000000000021426273367600166540ustar00rootroot000000000000009 luaossl-rel-20220711/debian/control000066400000000000000000000006621426273367600170650ustar00rootroot00000000000000Source: liblua-openssl Section: unknown Priority: extra Maintainer: William Ahern Build-Depends: debhelper (>= 9), m4, dh-lua, libssl-dev Standards-Version: 3.9.2 Package: liblua5.1-openssl Architecture: any Depends: openssl, liblua5.1-0 Description: Comprehensive OpenSSL bindings. Package: liblua5.2-openssl Architecture: any Depends: openssl, liblua5.2-0 Description: Comprehensive OpenSSL bindings. luaossl-rel-20220711/debian/copyright000066400000000000000000000022631426273367600174140ustar00rootroot00000000000000Author: William Ahern Download: http://25thandclement.com/~william/projects/luaossl.html Files: * Copyright: © 2012-2013, William Ahern License: MIT 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. luaossl-rel-20220711/debian/liblua5.1-openssl.files000066400000000000000000000000671426273367600216620ustar00rootroot00000000000000usr/lib/lua/5.1/_openssl.so usr/share/lua/5.1/openssl* luaossl-rel-20220711/debian/liblua5.1-openssl.install000066400000000000000000000001571426273367600222260ustar00rootroot00000000000000debian/tmp/usr/lib/lua/5.1/_openssl.so usr/lib/lua/5.1 debian/tmp/usr/share/lua/5.1/openssl* usr/share/lua/5.1 luaossl-rel-20220711/debian/liblua5.2-openssl.files000066400000000000000000000000671426273367600216630ustar00rootroot00000000000000usr/lib/lua/5.2/_openssl.so usr/share/lua/5.2/openssl* luaossl-rel-20220711/debian/liblua5.2-openssl.install000066400000000000000000000001571426273367600222270ustar00rootroot00000000000000debian/tmp/usr/lib/lua/5.2/_openssl.so usr/lib/lua/5.2 debian/tmp/usr/share/lua/5.2/openssl* usr/share/lua/5.2 luaossl-rel-20220711/debian/rules000077500000000000000000000007171426273367600165430ustar00rootroot00000000000000#!/usr/bin/make -f CFLAGS := -O3 -g -fstack-protector --param=ssp-buffer-size=4 DESTDIR=debian/tmp prefix=/usr build=liblua5.1-openssl liblua5.2-openssl install=$(addsuffix -install,$(build)) %: dh $@ override_dh_auto_configure: true override_dh_auto_build: make DESTDIR=$(DESTDIR) prefix=$(prefix) $(build) override_dh_auto_install: make DESTDIR=$(DESTDIR) prefix=$(prefix) $(install) override_dh_auto_clean: make clean override_dh_auto_test: true luaossl-rel-20220711/doc/000077500000000000000000000000001426273367600150015ustar00rootroot00000000000000luaossl-rel-20220711/doc/luaossl.pdf000066400000000000000000012130171426273367600171630ustar00rootroot00000000000000%PDF-1.5 % 2 0 obj << /Type /ObjStm /N 100 /First 798 /Length 958 /Filter /FlateDecode >> stream xڝVMoFW11 ygA#ȡuJNmȔ@RiF_\4 Xh{CLY&OPAA @l #, DHrCHB $ȓd Y bK'rƷZ!f({8r $ǸP#N9|XrœAȣ,={Mz p)y|`(`)H!(zB1HTEHSi#7@1^@ڰ^8,[0o2l~3JkP+[[xYTDfH9tbyHȝQӶi/0vPa' UMAa|K~=MsT!h00Fڸ&qz Ŷ0ʣ"*0.1VdXCl uj QIl}WI,nTF)QA;՗]^ӛ6ͻjU_L-eUwڷAu:SHJg{ ࿯SSvU}GǶK9˹fMٜzCMIn?M͎&ʱz:|7\jX +ݖX]\2Q7r']!Fƹe0^my^nWrdEh+8ݶ/qq4?N2bNk2ݬ׫K1aV՛~&ugNzզўNǁ*q5Oj$tc?%\uAm>ofjl4K#Iy? . a]ūdqW5npàPRؘa}aSUX @ˡ{]M~+=C_jƟ=S;G(*)5;o:bD񯒡xu_CLƧ~; endstream endobj 203 0 obj << /Type /ObjStm /N 100 /First 855 /Length 944 /Filter /FlateDecode >> stream xڕVˎF+hg`w S.Z--XH%ߧZk 5 9UIk,&X,|$ˆR,XX=q5gc?0}6gg# bH\$G|X9י;K.:!Y`|@|og/R.Wت)A iz닽'gnJt18Ǻ7CNpfb'fWC mm>CSqEK(n׾?s\pVbij3TrBgKRKRKg>yu~gD_GuIṜ}Apߟ%+_ı8ݡ-1Ș] ~ꢦ?Ϳ%'xwoEN~'^s3<gNY7v3{;RO}7'JS xǗ7thfV۾ԏ @tO%?} DX%('QGa endstream endobj 404 0 obj << /Type /ObjStm /N 100 /First 854 /Length 960 /Filter /FlateDecode >> stream xڕVMoFW1A ԋl36[YH*u}8r%Ғ9K7ofެe_;ב`IX)y,B\۪.` ĪX3q&/ĥʋ'ߑ$1Dy|C9%!c1k[qy)'^ƙ=IaBmR5P5SM?8.T>x)& GkDdlk,8f?91Vm?O(#(!3^,Dfp0f*c%0'ŋ#N")`@^a ;ְs/쐍>!?^A-b}}F?+PScYXh%,s1uVKVq8+YƎ9Ef'~q2S MC]3R"6s&Uq F 넣(Զb> D&W"8E࠸lcȞ*>ĆQ$(Z,(džP4; rp\zE ]}s=O_Ջ뾻mOqf5t=Kt yaloC)\Dqx{0##y7y+HcrysSBÀ*vϢӔ7u#'nG~m˷"GEM[bĀX$Q&Fp ~@]]?]?6]9='Oy#TO~guˉs{e/2Ջ'Y]aw|ٮS#OS6,s{_Էv+rin:f7}h6"?՞ŗT-T9~ٖ3vg?N'7O{ {5; endstream endobj 605 0 obj << /Type /ObjStm /N 100 /First 856 /Length 995 /Filter /FlateDecode >> stream xڕVMo7W1A~ 7MQ=ld^X 4yt q$Λ7|oo,5@`d=y҈P XGCg8(!C*:88@g4%sFP9CV/_نz:i;u5N^#z~^vn?ЏƼԏoPTYO~wT Sgɧd3<}ngc~=佱9fQ]j%8[[j^⭊sEpLPQ ӘP\C{_Ă$6i?UA\-ItTšn)8on_ix9+CПS]*-i#Ćnݔ?$ ۡ? WNݧݝ8+.w\7CJh ~iy۽owUx9K.66S;wQt,//.MyH /' ^ o<ǴIÇ4k@T?tLjΏ߿82FwqV |wOe?Xpzq,A'kY_fmf-Z !A endstream endobj 806 0 obj << /Type /ObjStm /N 100 /First 861 /Length 989 /Filter /FlateDecode >> stream xڕVMoFW1Aޙ#EZ4M]iB $odJ9;Z{3ސpXL&k8!p&CI 3ʂ 9vy9c1,p8pd0;Kzqxӓ|W^L`eMP2xZ9GAo$""QC"`6Q$$'(b SЂ*J()̢nQ HWE3rGfXFڦ37`AaFl ŊzͲf ``Hs`c 4Ǭ"?ft'0pug= tA5>i`A9!;9R{gS՛͛YMm4o7>nv5+@7C{s_AUp{  K07j9ɇP;Pynjg[TTThs4Éf~<ڢ+0~n*\_qV\ /dă*"ìۦ; lCv"|n2fyضS3`Rħnr>7ݢYqs] ]kߋ lbZN~SuK|A^,.]T` |u0wsӞ4xmS_9o6X4-OϷ[O-W"uԼfOٺS&OO7vm~=2O9cSM7S us!⸶d !u7qy[p'j}Wvq9m' 4]}tG'cd_vߴ]^ endstream endobj 1058 0 obj << /Length 315 /Filter /FlateDecode >> stream xuPN0+HkOGVj4R4c8o `"XLJBq4#NdPTc/(1[dS(Y@Ep_ Dr4:TK_m8wpF+pSvci}Skxjj~Re3&x(@ !([*s<6uj`<__*JT=MѕC# {MS-%7G;tt-0ḑzX,P Uj 6{ endstream endobj 1101 0 obj << /Length 981 /Filter /FlateDecode >> stream xZn@+fiz:Oe4jQ!+ jd4^c ~%XHf̹{ h:?!s+' l;6E;d3d1@>G~S#%lt (׈o~ǫPD VDMW!ȴD-’Ub>Lك&I-S1i| k[Ofl9L!$G&X8æ0fMc<87arwMpLI.B/TW먏5,g A][o/[rıs*gSS![%f;/ܪJ]/RZgy ]Mlc^;Cƫ`X TaaQ^e?D׉_> AQ[I֤@͜,ɜ0rC~o&*ny%PXң0U/ޚCvݲ7㎴߽)-I6`ĶM[6(~AOy,nRuq5D + )؞ǣ R"`z8L2dr3G.2ccivwBS2}w$7UmagG:Bƒku-p:u<ϥHmvfL,9%+SJ)K-Xk{K%Snook͐l,S> stream xݚKs68&#xodfڴɁhrI}dRI$NNzXXXw Kڽ"A}~vu7{2THapw0z  b*?^3ՑBOB# !^y\BT7 ~\'A+ jIFV> zRjHR&)Y_v V`@`7rCۻ3\g؃''Fa+ ǏAG@!~&Bwu`AB2 I)^n,A'rċ (ĐgC)n9֏A$+ĵ4[m" SXuhH޺;+R3S=rFBڥڜ)GF%0u戳K| +WmbmQO%V]}J`X*fm>K҃1,֌rnZ9]r*mL܀GgҶQp9PI& xױ#دX9y>S(kZc\aU;DQ͙.>ה%s&tK~Z\ y pO:2 S&Av̉p[%[ IzQ}<{)Ұ#zh-!I6A<^9큩e±o0Oϻ|O2dVVaj2D/ԉ R13б<(w@ŸPBzZ J}\#B)H#فSʁ! ؋+? (Ic_IP8AP4/ح0"pr7΅/oV45t~]7Q3 Dn1{*25us0Ʌqo4(v@7&Dmt OG~qLOQqx|N#4LtE/"J\:h%AIoC-;zuv:]Cx;O/tGtm޲kv^01ϫEP[bNdvwk:рw=itH;-CKf;9dΗ\>{"M >FuMȺw9r!GOS*qG{dse2=a1D^uy݄.Rg Rya9@]DNX L_iLZ endstream endobj 1007 0 obj << /Type /ObjStm /N 100 /First 970 /Length 2411 /Filter /FlateDecode >> stream xڵZߏ ~߿B%k8\m.Ij$g^o(Nxh>}")C.bp\]bYɵWd$A+ o(;xFqppptD☋6ܟT'A9:Ad}%I# Kq)X)@8GmKFJ."rSs%+r>/ Cp`DsP& S2nk &'Jt ί0d :zG*{RS,UM:Yt!( JsLEVE~!9[ :.~BBX[J&~qWp i(ϤC#9)+4Ŏb\>ߖ!B3kU*& jIKZ˱u  \+0RCЊCNXJ)QJK"kf_T(>N=S]=PMZZH`+ŪoZdЪU.VOz٠ aEqJoNi7֟s wCx[=sϷnt_o7}of~ݽ/?:|;t/ϿM׷n߬_ow>=yFw͛_ VNg陨^n8OR}{xǙf[k?利C?|3⏳x6{g7=v~:呏~tMi3E}_@/ gz޿TǏV?7v6;]V?Owtwp_Ep._qCpp js˯w*NO鴞vr@v8sÇvۛg޽4xVϧ{w'|9xj6-^t(vlkTkckDk5b C.\ r1jՐ!WC\ r5jՐ!7Cn r3f͐?%yzvj޼Z}aav-?z"U T^oR ‡pՈ>FWa^/H"#X77ig Z<o](H"_R0<q'S eRHA_e/X)T+D>pTNl*{̪frJe M[N6״\|EMs[x1^K 4MgOPUK$.\ yi Y< H ,88.M]j}%soiF*1gx|$W&.'yЀ ܼ XwxY놪z qHk>s=bja8v<FQ vD9<@~Vl+iL<.k,$MH[Lkžg c֊d_ʈ/_3TA&Z|]b9Z 3Z^`q@1SE8FYh'C 0ZҢ'v"4'k5H$|: ǻ !ٻ~d"^^qcXc#Zk$kdkr4hddddddddddllllllllllbbbbbbbbbbɐ!'CN 9r2dɐ!gCΆ 9r6dMGMGMGMGMGMGMGMGMGMGMGMGMr:y1(gX.esþNϟiG 9"Ұ\oM"N(.UL5袆H5.O$7z`m~j( R*vq;vXTCC$u"İ!D4bd0 sXfȟLK#2 14XbL"2CbId@fj:*HEa ZѢ}.Ҁlj$JkM9 9zXS9>3eD#E֓ N̾4SsR^OQKVL3=b^f"<`o&"5GKLlDNYd"2ZNUD%D).i|>liT<2 TVyG6SN^{)ēO|GhjDDOfF B:+sDxy P7"qfʀ.Џ7-k@oȀ.dD_KkAn4SFDi⁘sF8̃5ͅD 0骜|m endstream endobj 1254 0 obj << /Length 1412 /Filter /FlateDecode >> stream xZr6+LF~xNLM79%sAR,I$AAvȑ ssMp?&?]N^%" lHpy"P yp!2^}q+L=ބ$YgҎ(Wo.d$Bog~pc'MO4=+9 sR w/JR` n0ެvG|@Q;_0NVH(6#b&uB>N|v{`Ch;]Y'85|xjDF jP>I 0H _i QxNjVet:?!j/RnXސcѶeo87U}9A-olfC0$HXoa YRD#b9HA_RvB 8 fwk Z٣wee{m SdM9'R!OIGE7`1:3& 3z[XZYNg8LWrjoϛ%zRe(OZuX5&9'G"CY78:ۤR@i>JDsMAFp.vmFqҝxHvp"•8_pqUy4{49R%=Vdko2$kO `N2P1&T(%}DJ;EҷӻN5ˏEbp!}IDD!9IDKTԫm$V8b ) 5 ' QQ6ϷT&K)9X|naXېX-L(:-8l9?VTLI~w:aď#Mi.juXWS~솹b 7 *fM sZm˽v4B]Iö8RhKh}~ ˞iܨnfqy'Y׏YF{d; :nn9$+ލdPHYiwk4F4C8+ o g?u6=/㕧f ZyYW~Pn$UR6HX=ZCJC)Hck{DgYګ # 눲XՀd]D6#mFU2bn cYxBai2[xyS)u>s8= 2j/oIҒ\vNy Nk{a"MGo8nYJeXi|N̦@ EQ)(-~Zj> endstream endobj 1183 0 obj << /Type /ObjStm /N 100 /First 1019 /Length 2402 /Filter /FlateDecode >> stream xڵ[[\~_яIzn}a-=Dnzf,6m͞3ߩSkdIs7uҼ$t^T`paf\/c1;HCo`ů%sDm.de;M\tS'jby%ֹ6 ְWkIܫ_*'$ 7ǂ[\ՒΫ5jK\IFeQG2q[IS_25ɦ>|: K9ZMVRKFh=6s `ŬjPUn*jnb-}/Ցꨎ /cPj,~upjUIͦ퇦Vu^Zsͣ65zy۞aU QA 9n(R, B!4Tإr|\F\Li~ݝy顼9ӷi~;}wSzqœcR,ɭ:={N鏏?LJ?dO_}uOt,~,p:p8% rupj%L)ocCJ vx#nȩ@ú!^ءa#nH=a[ 92jCxú!;D&g:Fۆ*fmHؼb]`y $<myx@>p%Sް3~rEk^KWU ^Pl|CaM66z7 ު W ^Ekz^Y!͓SrǢfC95}CQƆ&bM GElmCll_^Yle f%^yd3*vJgT6l0#vH>h/fo\v>({A?wL* D+-D\y4 ɆT6AlaI}zU?:`:0n IZBngWU\V3*;f& =hcnl8}>f'MmᲗy p/o^WNP33#+ؕ !|ĩ5,w F]!apWm*\qɴSPv2V|6b DtdCFƹa^]혩{"7$ &cc`l2{`1v+C;.ԭq0y%G0ˆى0czhvbGg}IZm5B; +mƊ߳<:u61vIȃ6iܖK'b: ȣqmG  .?#2G5[c- l裐y SEՕ ?~;h*?;Ə4߉1L1|Ef3rdnjs7$ +$Bx8=Ef' endstream endobj 1329 0 obj << /Length 1168 /Filter /FlateDecode >> stream xOs8>Tɒl).fK/Ա=6~?Pl-O$zyѫW@kiAnBVx~cz A!Gta!vB Q[_͢P6r,/'xoӿ>#ŹT-u€^XB)_=>A%J$~*/?YRICؐ[&6x?\u]rCDw*%/"񂫉cOI$#9!}Ɵ@Q,]`lde[|R"^;(j"=Nor0컐HE P[O#^S1ɫH ѵA c|NerC0uBX#b3rfl (,(Nqf(V,iW+ 5E]ٮʜB̩<֚iǡg:K3JIO*yC2D0'X{w!Ȗ"%s,%C[m/сuR6WuT-U%2ևenH=';iY}x@RBa*MYq i_Z gyi EW۴6m'5ّ l N%+G-7nDNEOB$ںM7scqemhv/4Q;mAiPʓ;yIJ]nTfYE)0R9@tO!tm@ԢnֵfvhQ]un}l؋ճ{zq91uͫAˢv:ɓ*Qcǀb۷oCֈ`%6tm_v/Z"شxv[Er5;E>USߢ < L{t\0ǶoR?~yBlKz6.j07WV/ެw_6ٵ,Ú`ޓ67]h]@Z8+cQk* eEeajyM co\~W>|#O* TZl`,y>758+RdQΥuu}JU=eBo9`ŸپTlP\~lnz?U@W endstream endobj 1351 0 obj << /Length 759 /Filter /FlateDecode >> stream xMO@{z9RRD\(o"NmC˿8vh6)&jEO^>~1#S=$Nhptf8M璂RD3Cक़\{rftqt&aq [>-lZ3mV=,0}A`LszR6 ߄_1AMbExj˓HPr+F'f:ŠldTfE'njv u3C-}>Ԛ\Qt/N!`(]1Y13.c4DY<~y2ylf?)ИUjM>({_ɿDr  A9Z?5&kUǃ溷K뀆 ROIߨ4aU+A6U˵RK1ޡhVzAvy̱HL7sP)$QLҀs2oaTX>:'G3r9RwnpSu2{!'&.Tb,k ̎ ^Q5|NDHyOArq)dqBT0#M ~͉l_y_bft#{]<=>' ^~%*OjР"ӟ|1جPj,ܥPN#ޥMdxK)6/o8*]Juo> stream xڵ[]\}_$jJ%Y]$YC2SnaWeƣ-j JM N74>-޽a捞Fc4TS !;zhc9R>-KiO?FZ #l oaĘ[M\ sTLΕ|DĬs&>Gĭؚ?VGq.m$)\Q%"J80Mқa-i)s%%絞9b$#z*?om`taΥKjTf?MN<,N-5=of`7(Y17jZ#;$t_ 6@l Kx=rq)B1kspԭ-I塥Ҁmx%By V mwux1Zz :9[ ->JL4\l̾í lVhWӴ'Ef_ (,/q"ls$9mG n~a~ۇܝz|Pޜr4?ܝCz]3؉ӛD|2 >wsB't=|ë{K_ӷ?Ho~/k ?|x8|?Ǐ~|W? Ć߽hr8=&QA˥AѰhhD[tFrip4$@nr={ @r#G @<yqȥAѨhH44-@@@@@@@@@@@\r 5lxm KVҖj,O'=M'M7&dXϊW=3X1i4ky6QĒ xjP}6̬ >N ϊo |0[1Ѳ nfRkuy+==dnL /V!ndBؐwc ¦LBخL &a &DŽMu]6ݐ**1a bە!a bOӵ "fϰViTmHu@+^T=z,C׫H6s_>~/hk ZWEjO&\sCQ R{Z4swAT~͔mD ͰK6؉0ijDҒɆZN2䥙lE9+u7`X6"xdžpZɯ.Ɏ-lX}?WwDI֕ xPD׺bA_ f|mW֖Rye,EJXueČ]o9CR|mW&ͽW|_W6D ];T 1jC *@p!z+LV7WxHTn2}i HIr$"W@pX1 𕈯LKkpV!:Dվ4 *^i &>Bحj"4 gB 9x|fL˫ӾA^//=~:ݬ vlW[ vlW6ON#顕 r6`}e?;1e56,sɳFrgKKݠ#]F{: ~=⑊:`O&\3xlR;i{"<&?$dؒlXytlIj)bqESvPx bzB +e |ϡ᧟NK"n2ǗwTF%@y%Yj bόvCܫpC~UUilp>g|^ bAR|n!ڊǎ"ڋ9h%;h/V瘕Ў"ڋ\䐕m]\y߫,^\x\ZUx\=QaQaQaQaQQQQ(Q(,,,,,,,I/^vc9o|UvTзZAY($l~ }cbWv ]$N>}ҐqYC鈩-%|"oHKY X(D9pHM-e}C~,dD,6 > stream xڥXݏ6 _:lǏ-7\?a=b%f[,"87(DHJ)'*Y}g/*q~Ue(C=Jכ*4R}Vχl*\&MVY-X44͊ [t .4NZd8b)8-sNڃrz#"zmFٞ?~L7 txu1>cYH3y[E37-ՆI5 rvg: !Ɓ G (]1oulSk}\:fhaKi$|F_5A+bAx{hgrmaoͤ'=i,5]׈˝?!o? ]&$qJ6!?kk.w9`sb=8`*Ӹ.)̋8 &w˾ lߊ$.B|/ʪD;L' < Rf`H})^j1˼ؖ=Ibg@`G]g->plQ3@.?ɶq+&輧O7G8~H޴ptWY}KIMg Jp3 $t8;gg(%GNN{>Ш7[|f/ a:inG'ӝ!]N ɾyI1 =/Y(E{hw}^Hki)|<1 D\R"(nG`zD+4n^Cx(rjP@[0W`zoFo@/B 9S4*q7 K. )dOTXJDAGT"oнe4Th +)B"z+"|RᲷ[æyөΧW!lCfyԂ˃Ԁ8K$E2TnZ^k$3S_iVDia1H}PU)T:.c2-y铀 ǶіdܙV}" kߘ$e'iލp !$9fp|E.T-$u|sp (/%pAyOa{X.1q27X!Z9Y->mg$-䁥 vw8`fU1Z^TVh\DZKv@, v<:U\lhu/ h0ҽvZf}RQ'S_":?(` [DZy:YtK'Vp6`ZD\ӗe \sp%LK`n 6n]&3N:xcdU\+бIwwv(38KCd l.=GrW} (x'q,|1#N ۉ t$K/ZnҩeYËeĶ r ڜ㧇g} endstream endobj 1362 0 obj << /Length 1691 /Filter /FlateDecode >> stream xڽXߏ6 ~_ β$؞k{kQt.{ZQ lG(>~ngY/.ވxH-׳,dRe53J meӔCm_woqaųQ z4NeѰ$\ck$}3L񨧉ou3XsPSG_]x~hF3nu[o[rWHWN0p N`=Faz/Iag+)TR}Bm}% [weCM 'һ6z`44~Νيj7+ap8>YPp݋$t(K1G궪6V{1ˮ¶ -em:t°7n<2ݠ:< aSQ$.YH 9YҮ@w&p,yP"ZJ8Kx|p֤`YyŻfxYp;{!)`oo,̰WB()O)Dz-,)ybO`32tS$Y A鍶Ԫ#ni;ܾxGK<ލz;*XUX;d/w?üZW—J!Qnu?\bCK&d82! ?ﳬ,<+/]&=\|F.|%pbeu}Ԗb W|ڲ۝X3=^,paRXg _WfxuCm_5ѯ!]z}@rApc'by 98$+Q^-?['-s |(SP*,Eš_Sx={&Tםi$mzCOlڟtN!KaAr R16{`d hV{.rYK䁖-Q SEf2Ǣlz7#%H,5J,T, ƕ]5CC?"0s]SSvrc|BdYK@"Z³aEv_ .8\L+|DU{dM*.(QqAޢiO/6}P,R tW"%!CO[e&83ܨ-vէ Gw TFF[% SeGk/OB&zlY>u`Gh{ݸn{eu/T.; hJC\HSiLI=0hQMY{ОۨCѣYITBE 5q9/.|Md6=HXczyF{Ʌ6,%^s*y29%:ׂ/][꾧kd!BYDʕČJ"4ۅAN;1Tc1Yuz]:1K7=EE77YZLYz\CyIq|̒g)P2*8lM0MYU5¦t08}gRΊq(ބ ߅W??pOqC`!}K4w]%x;@h}Y>;i"-:q'L&?~UL_8 ┨-XD]o_Rh4vpā<)/ endstream endobj 1366 0 obj << /Length 375 /Filter /FlateDecode >> stream xڽ=O0@  D.;WE lhV m?N-tRLH@ Fi!4 dVz>E P"B˼Y,È6RAb\|ܴr2hL6e^<05aGV={ZzUyl-⦆ "C؀@|_Nܮmx9:MYO`'3>fn@55^ $غ44*ȪibC-ay{n H M|Ku͎[6ᢣqQ,AR dح}TL endstream endobj 1370 0 obj << /Length 2016 /Filter /FlateDecode >> stream xڭYKo۸Wh7 Psħe37dsN$d#MCv.E <ΛN(~?K< Nit,R B.|S …b>fLe '|F);ilH( f[ J@ȚeQw] hBLbgr"ews)-Ux>g:!3*/mW6D|*|д z̄6#~* |5xWNdPbۄx:1} Łt r\} ٸ6 ܁夵9 ?nWulYmKү5۝߼3vyMf*uP( ?w`ѸKZDP 4zS.jdǖ6*qV VuAgO4ֶim8vƊu4(.x Y Ypid6#@>]nJz)`ŚvY?C!:miJ++MU5v]j5IV&=TQ6 pߘ˩q*_Qd,wv@ dz D!$C#f*tꉙ|c7$lwfHL9۬VO"ν8h㚪m2kLu@61oit0>\;v"̷gƷW 1g2{ h "1ՌTH1H}W#hPcAPoX43(Ƀ%\|\$leJlkz$/a*}3o.{[i-0Yݜ2&=eZZXΜO!1*Y)<(rZD1ier1Sm-`y_ r?!PN{j1"ٻ endstream endobj 1375 0 obj << /Length 2093 /Filter /FlateDecode >> stream xڵYs۸~_K}6nIӇ$4Q RV|s|w"dJiEK`op=DIUtwpфINuX$FS|_=4 is"ŗ 6"e$sXʃ6^.X+e6jIQ9Z$9-YBd.MKy?jЁv$YY,)j7-LT1rs x Wxe 6;6n_,e[YU]YU<|mf4q('!@ɨT56۶ӧ҃FRC xY(rb퍵anI8;9 J<i麚lϳ1ŃyQYu,5M7?w 麺y\nM.zA`[0S14{av?WT#8Q,dӨ\}D+xsgފn"NGp?%$%f$,s(uRvc`I:fH1 ܔd'_NA7r!}X7_C7. `l㞽G~_zwI s CZ\Fٹ )X,tEkQiH$ ip="$sS˦1⿜&. G%秦ꫢ~R\lv1;нXvKHeo~X{7ć_T6j+' &U$/J#GWz]ᲁ,Hϔ_,# %*]߂UY?!P5۝;dlr4p* wY qh*4AC\Fqhpɗp@@\ߌ:zSCx<U}K'湩uk6ʗ]W6UgTTaWӢX3Ӛ CnpIN! P T~f֣ٴ J SG=ŏ,u'lHQAzjRΠ H8 XgJ2ּ*$%"Qٮ>_*°aуg X4vh(ΐ|g6HdXÝ3^eρE)1@ 8tT IvH%B \q'qC8;Ckq(4/,k÷^FOqX G _i ZSVrie`o_ b&j> stream xYK80$/b(R%tX A-mmd#JUlti6Iz}`U.w+'k_LJ.bN8\g8]ad1;MuțgPt"TL=FY!4"D(#_UId|m#DIDߛi`4i`]'Z(ҵ]ï?y*TƖ}a*Z{@r~} H8iKGT|aJuHHsy4sM#ntEu]]E3OR*(SEIXD{:6}Uts.Eb?Ҡ-8]Ӕ+-f@Klm"(Wo`!<(%iZzHN mce,;( (:WN GQy=wѓ8VXJZfp;,L|ǩ۪Oc]3ʅ<3~3!k\9&CTP( ;MwNuhZZ/֎{R u9b)P֟Cגfբq(0H|L ʛZﴤ%vv1 \y%*n`kr@kzRd>1C4>a[ZRP@(f,R(>L>mџh @QM|*R!D"L H>Iе3kDz4r( whO'kkn$ VV fz{3i$Hs|bp:%?^L)w,)tYd8 6? D~s$1!W^$92B =+N]0AE90%(X>q"ZP"UPWi%`sYG3 .,cͰTI [rYaH0 1u1p= \vvrp3# |c~/EcC1}s%bwp@vhLRњBdYD_=KtPs3e1:PXrLSĒpJ^#5xhKIw!J3Վm=q+ZΔP$`PkTeXJ< -9E/2sn7GpƗ'2W{>s3;>Άipl$<\Sp > stream xڵXo6_ae2Pq$EoKR`@Erwǣɖݤ˞DQGgg| W'?LpL.D1m1ʼ\߀^`ZiQww0񤣫%gR%=ۄ`Jooq<0 ͯ*wZbG^Hq$nQ  841XM^52Y6ʃ2ݖ?5-ZfYO%rDO\|=p UNY: 0ev(WH PW.N$pY]QJmJ=Xgi!gl}DY O=(}`@φr2]FE HRN1I'I,!:ǂ*Hqc(n8(U\,O@L9dwDwr<6X.mB [DD!xidkBUvٙ6\n!^Ӂ[> TFŢ~ٟ=W/P,$S Oa(m_[.tX>Mr8R9))Yt"0;A$a}%iJˆ:/[{,ʠ%rF$gf5.V.רtf~+`D抝*Auc͡Qd P M]^;cI1,&&!< *0C*+];C#)fč,wTԱ>:)'O?4Y#sbpEꤨPˇMt+ ؎XDE(~'P E],h9-dE[#RE_R)@g 4B3^ȁ4J]6%scaT+Nw0<ԽJ^_]xA֐1o;}lw; w_:'Ј篆9h9Qu|+̺k;2?8OǁpCd 7p@9 ߠp2?nb94n 6ZF;&_#"99bRs;~T' "r.oo^5X@ά"b p5rm1R _)d}T/ҜRru})ڱI[+ .d[R<0~~-0\縂rpJh˘ClP): 5J:4s7S=Hdyٶ7;~5Յ9J,yן endstream endobj 1395 0 obj << /Length 1772 /Filter /FlateDecode >> stream xڽYKs6Wpr 5c!xធIqI؝錓-B6t@N}w&-J\D{5 <[!FIJS\1M ʃ˰tٛٗu4`e\.? _JDv:D|hEaBfF$b,mV#U1T["*n7j $a?qyP[UfFѢ&kkZ'}O{Uwv#׉6dLk^+7 ],\gE:v6a.6_?&h- JNI< !B@=  s@uU&aӚvF hArsP"a! HGf@\y&a$rhdhvZ})Wf³ -UTc"{6EC]0^`e)52RT ̔yC#G3kpMB KX 53H :@JuS@bdP9 'twk.A*X⇵K|er8aBA67k?U{@̍rh)F&8D=p/- ^$G}LIU:ƚ0@ۘz[ 4׫lSۂWpG`1 m8a7 =K'=0 L0Wї)F8菎uWtR^UI9|)#㗭;Yf/El8$PqJ$[0܂f{O _|&|&AkݞW;#1m"PgH(s2_\2_& 'p+U.3 ҹYg,iVj~Iz2SyާjUena76p_Wj܏K8硹MPw.'B2O?,.' endstream endobj 1400 0 obj << /Length 1362 /Filter /FlateDecode >> stream xXS6tN$t]砝"V]}8RByؒwW/f#<ɇOF 2da0U1F-wc#>|"|#.qL)\=P1-}H8ňd#= $"Vt HY:(6ElYNL,?I.L$G՘DM=m}K -frxve&_&5̆g^~9vX`ANfN>3Bg0o9"0X}oYe(yPl].8 B KY 9)&Ol5t (TP8K[#BfӮhp\\/ `5jVu3$RNHR$v XĄiH$IiG8yR[9/.ϘjeͮrZ@ICaܧnj}ըDz^m59w<\*q]6u4xPˏֶi ۀh(_PA7Zmgv^kՔ Tk1d梀D}Xx?ce#'b;-0ppDiyPpOQ[(a4v_!}T9WkP94\iZM; 3 cyV2|*0+?qhha^zռou'H \3<婧C +$ ISu=˛~ endstream endobj 1353 0 obj << /Type /ObjStm /N 100 /First 900 /Length 1636 /Filter /FlateDecode >> stream xY[oT7~_a/{f|*B FI*AQBX *ݍB}q J6B|3".Ȓ\AvTۛ$ K$rf{Sr5W̏N&19䢺2\`(N#,8Kj_eLo\ퟌRtxbvdJ^L*.Mg蘋X3P5Ն IA֤8"&gߩ+ 'fMVu$Ÿ$jR 5a"*N!~!@EU4ff\I{J\pdcj-6p:s5c1_%Dy8Y 1Ps.Y*oɆ\R[ixkp\4r!T;$I1( b )N"( $Bg1A8F/ $7_k4? T YXA N"LJ=É '((DU #lSEr)'&.&D0(Tٸp5+i,ڒ%QfRؘ {Oݰ9͗aͲ=r4s2< Ӱ?< ^0vK*FK/F7<š&,m 7 ݽ&g}݃uxIыq:do4zmT)R8lj^0-3 L[Y<(.+*80%Ot@a{(Suǁ0*ma1d=O(wɞLٓٓqtV@ؑ<6q*b}a:o5o9~%}Jj^GsJXz h~WVq uT;P Go (͙L@VW:pV%v3- . Q@FIq84 y:fBI<D5qZƁtb_!8*{Ď]܎!5a~CnJgnLFGKU;l"|n>_b~E^]C\zL#L`d!mns8:ż#@XbRnd*wHZE] [6U/gL-RMueDmV!@N>wXN)8?P:VY|oL]!+yΗ[=ӧ]o]]wZXB+8+:$])asc0lC;\/~O>tX|b88>^ Sп|;l|ޓ~{{q[I.mAm8-it՞&J;5Ts0Rum") 8Z:tP cꥷ=wnwтKXs&zB{d|xe L(tc_ @8u"zZD:ǁfMh/ɘh endstream endobj 1404 0 obj << /Length 839 /Filter /FlateDecode >> stream xڵWMo0Wp۽U[zhR$gq6TDYɲIz5xޛ,>'#ƚDHHb0,:}ͯo<\G:v$!!lVܕNVxW%+*c{M.߄BS.GM*"67"blD ,0ZxɊCƶ ol L8OD"r_o5 b# )? 4EbelSL]SdTW#vX]B]d%iz2/ڭJMLU" =Z DfDž5-h퇭lX|gMS?g)7 lucʭPv +)wkY]7ju;'HۚEll+=|#\]JX<_Z妀ZV5 .KDɔ{:G~8ݎ*HH@Ȓ7\8vsbDEzP *A/c:u;&*Xʱ.&O\m*)8 uu0 GÉ?T9Lx!`I{'">v&r9s W/y*K 6>겟/y1 &/i TӁ|L khB#?p endstream endobj 1409 0 obj << /Length 1440 /Filter /FlateDecode >> stream xڭXQo6~029E{jn:EMkU%CIIMɲ>/ng|oG"V/{m>¼EWX?;@EBR.`k`ݶrHWmSB(uZTj,M\q#8H~^NFwMn%-[__],W4`y]T$t&j:mzUczDs$|dMh3@:~~4( XJ0}$|Ntggх=x>je)\/иkD"*,ONݓ*'tQ|ˠL(sgj7.ݱn+qh'mI(O.^=nnsS7EdV…0F݈J]2%N\uswzT37zx6QV9WZ D[ko&oej _@wA)nh;mܚ7L=#*;LV?e[ O\D!Hn6,d0{#o).6+R "HpA 6!u9(ڮӴGJ`76RD}[Bzsc'JvGa76s4hP젝@L$òu.s?XaþНٸȍRZA>=/+d}d {( 'f1N! 'g1$r:烀V4  Uv1`p XA²mdW1I2:u%}__Qb*-7mu q8;Z\yӷwC HܢKWnPxr=i{x4']Դfc(Cg} r]ۉM?~#sMEEw WP\~Fa,r6.ј3 -ia0IR%!խl7ySo a?95S(f}u0{bcęBQpM@A|d?$N[BLW endstream endobj 1413 0 obj << /Length 1941 /Filter /FlateDecode >> stream xڭYK6P$W 8{$]ڢIT_dɦI.-Hd!nxx~}w_Ng[m\&9kU%o z7x՛ܧw‡rq >JS\l!2Vh9JzKkəoJãf4a% 1OZi۸'s[׹f*ǹO4+GԖʰ",l\K25I߯&KPPPjL/!d1uL ѝ3w~[?~@zU+&q}ΤD_kEkg7][-tZyh.& x;L= n.LCW7,f53GLOL] 5X0EB.ڷuۀ Ю$T~l-ࣘ >ُ(D쾤H-ۖݔ-= {GTF|)'ax\'_&ё|zEh<>?%(tuC )w"ǫZ1z3o_oZ|q-"%394"~R2o&]9'ܤ8!S0 !2D遜Ta(OCOa 8p`8T)b1`Csez+DHoFsFCnV)( 9Hx|FnvPP 䣲Q;Gg#@ HPH}49LO"D6hK0qe P]]yem^g^ͮ6gY/ma5\ E Ȋa`{9Kҷ۶I z 5GHg^ qm\#G<ɗCy.|t9mhfҙdNzOL rzd' )|dzZ"eQt4P"%-+Tþۢ5CQٗԴu8R#03$VJA~W͛_oyvJq) M"<ݼ}ϓ &@nEEP] m8w*i`Z MG9 tʙi͋BsQ ]٥y_p|c*!SчJyr/]i>=}X6Hh"ϖ8 gNǑWsVeZKɉOf3ii ÃqvXQߗ4wha_á<- _pTGrp /`*\mJ:sl6p KBُ(?oKA w<2Xc!+z?!=5@O?q<V+Q!qlxt:Ur_ex),\/!CDoW ٽ^4 ʕ.8Fzp {!TZfݹ*w҇;\|fEb*K-T.U",qKu*gExghg3RF\!©ƃEhv3ؒ"|a3BS+HN.4 x</Ow_Muj;*v !tC84׷3 L{C"!Fb )Bc endstream endobj 1417 0 obj << /Length 1290 /Filter /FlateDecode >> stream xڵXMo6W{O}E[n@,3YRv]wHʲiSӤ'Yh4ޛR8p fx@0pF A39-P-,#}{Aoք}Q6Z nגm %4ZG4 aDIInv(-B|G$f "Ȅ,<Kٛf8K{ʺ+:(+[.BX݃ jmEy 3_>S !(KF^=p‪.t\r{'퀂Jnat@f:SC,ksk66VTRv}%AMG֭|*^s# 7^??*H4N"SzIa@Yx0WG~Zl}3ALNq})C?' \ =I^͍Xf,ٕ%tRuR=ȥ]5gFMꑎGխս7m&Gه>ϒA@ /I8ArSM_ ha7 9<u2A/ 'c4C ;!߼_zown~:S:,:yMV~ȤS"9$F0C8{+a0L=9j!CՄ)lkvv~sLY#O*_S _$g̒5*=4-dZ,>$0(Mҥ8SY8kLGd@Rs-@4j,W#nUp9} groKz a|k=q)Θp+,}Py7} 00~1Mkjq(!"_f endstream endobj 1422 0 obj << /Length 1330 /Filter /FlateDecode >> stream xXr6+4YQ `vItqӌ^"d#HRjnl =>'w<.fxBJ$'s2&WC 4fZUD6˥AĄ`3eF1p_<3XTkG 8ŭuYkL<[*)b:lm[v&Gԭ<XNgBFFMƷBp r5ʛmsAš& 0"q_$1"6`e*Jm܀$aQ{ |gޔ9RE٩[i` lǰ(pnOGga)LmҥGgn.1 vZ79`mߝ:s6^LsGvYa b!C*PbCpn1^ij^[U1w/OhzrBd ?^g)+@~AXϼ <Ӌt|WcF@bZ o:OW:*QwB_;lyGrPbx̲!^@Pg#mDLmA ; =AXXt>M|hDݩA)QI^'.ej2 x;NZzA}5l=H܂F7bhm=uxZf?5i꾺Y:bf!\oVCo$"'6Q;w)K.I_@ww% İ]G_= endstream endobj 1426 0 obj << /Length 1407 /Filter /FlateDecode >> stream xڭXYs6~ׯ􉚱P<'u:mq{:@ņ&Y8Hd˙HX~{ {w~]`f{=Qclz!+iSdS'6[,p!b|,ф9XCEĘjEE HPgY\1D}q?%gYmwc޿$@=٫z?b("aO_+ȴ/T |P6|Ij"o;fEP7o_>;P xsDx[i>nה rN5䜍!M 9? 9!Wz1X݉;Tq+b pc`8xQZ~H֩ћmbX!a@`q/gfUTpV_&69ha,pJtQ)dod,?:ie]Ioȣ!~5;*aժ2:r`p.&6(XV6׊@6ʄZKfwMQ%6Il]ZmbX`iT^4ZygC^^bO>Ɖ%7nT̖|3:ݽ>=X{Vm~w4 fc" "Ģp 5pL%ej,vu~4'id@7L!!gZz$ڧ >Ay=A6EqE,#=|'e-N^vVmdCy-7 Pe|a恨TʴzY'Lf!CŤ-qwb 0Ik1f h9c$:`iɓݣ OA9Tя']!#*J5ՠڂ&3TWYuH&XF\x9L~0N_p8ȏL7Rfi_J 0[/t}sgJ9;o@׿L/>)QXժrl&bBx d endstream endobj 1430 0 obj << /Length 2055 /Filter /FlateDecode >> stream xYKo8WsY53|-$&XdX[L[d{*Raؗ=dXWU4M'4傆7 0FR4kQ~l e]\Xr!flC { R_`Bc|, ȽJ {3v?_fW*V*ˈys&z5'bG*OYI瘟H ^׃CMvC{ >R8O0mmmjlJ9vi8 vMq_w,S ipyV2ciٸM9D ~0lr OH^Z|xHЄIv HZzZϣ8<ØG3Z2ޞ$;^o~3k` ֿ 3qvVWfZUv쫠Ժ:؈cGH{pf4nat'1AE8st$q(29&c<>27y9rH~ÀyAK?/ ۻ70VMaiͧ4OYka+K^hz->(d @K8gۀZEYq/̍eX`*a~`#`5VC5DSfTp09E5C%ʔHrJăə-^yF$#.q(ꋧ]6as[3_3s`)6YKʃ;o.o=&!LMH>h6QXPklC(.\^Ja_%,~-?qڣBZ` {V0i(uU"b{MTUSjY*УF K"K26;2O3\s# % ,nDCG;:d>>  w{L "OCg{Li$P经W5c5J)6//pˆǷ~e`mEi|]Իγ|?} Ybj ]φq#r`Ӹo9!3 x zBǞ-K>02T s+Z{ z=N0Y-3 x3Πe^(K 3v}؏"r02F,Y9M!qU=yŁ80.OB*6ܼ RAvd7eA)\f| e9[Q+֞]5DJeʿIqWk4ɾ$,Q}};oQ^ ȫڽ }ﳣԇ"YgA@@lH,)Yzܕ <˽[0(7vV𿄦dhv\7źhF&XlQ]S U弯!޸%B cPAW"]%Yb(4(]3ls!aW6#sh});5։mwܒB_ܣ? ?,΂ OyhEE|xޖV@ *W 3P9Zj-WGnx;~û| vbFZ!h QjU\Gwf| w{q,{jo(,N:~(iX1,e:Zzˣc endstream endobj 1436 0 obj << /Length 2275 /Filter /FlateDecode >> stream xڭYKs6Wr Ua=M&Tg3kj2Z%V(JKRo7RLɞXF/&˄&?nv=S $Kf kC-,Kfc4f7a&,Lm_iM뛏h?'&u"7FerwQ̐L!yYjmڎ0׌*a FKa&\ekC2}3LǒLy]%KZd=3q`5tL]rʴ5DZ~h,bP>؛BSL!=x?=Ph!Np2K;b@~۸înU4 ͏7g΁U,Ƭ #MQ8gDl(f̂ЄJ=dZ!nj5hUC.Ɉ6(ʅAOerŦHL Lqp:b'fFu=bq ~RVS:3na €sXؐyZg^|='d2RX%`8Q`@I{$Wz3v -Wվ a K8`3[vQyS׮z7բ3&< \s6o§MeXSTށJQŀEͷ "n:X 1($^S2J 1DѨkuX~sbx\r[AubJ펯4_GeT5ˈI:y%%+%pLBN, ]5/ b#b'y0'9pgT.Uz*S9C ODRD7PڟTBאTf 6r~8 ?%fre@"ԘHn2;CDq[DmS, gY 3R`:+)9H$E%.RR"-ՅS`=qP KN8Ჯ>/Tfb-IBb/ZQQVPlZť$㉰Xbe+ DnJBz5oNT7ҏ nUA&Xq~ |qЬz7[**jX; c@]MBrВ ߻m:* g:ib|z jL?_տ[( PؼyNHt*oY ]H.haۈ.!'պox1:|3@^5{"U^T7[2,'Ҡ0F%*;c tu3$^ iP^,E,]] Z9b Q Ы hv׮nݣ+ M .Iv¹ҞdE4HZhA9M]UhBdK6\yxhO08DgJ PF [ƞQ"pbW."_b5O!_a0 ZY5⺨ܑu@Ň0{rKӿJa~,OqKL3;}; 8aU;T{{?ϟdJ! LIq6;@of|ep6Q69v"x!~pvhKmu1 v9:mZ^.7@f訚4!PM6maSσT:}tUw T+n@=^&ޛ! Njv܏O{`,:OQ8^3`g!WaTrbQ 8Ċ?nSϠ!}|7niжILAХU1Gdh\$7Π6S$bU\ @q#\&5~}zv$K8ԭC_1.m%_ao uNu,eov L M 5<1C,qp5!O×al E;ehŸJ%hLn@' h?5e'\$Z}Y8iÏnN,ɰB#jPD[ o! {)oA`vzΠ! q|n׋3>fJ AX>8٫H V #0ym0ƖA[r>XcPl!-kT tSNn /Ų 0| endstream endobj 1406 0 obj << /Type /ObjStm /N 100 /First 900 /Length 1410 /Filter /FlateDecode >> stream xXmoF~b?—˾UR Q %DE+D gtw)yW!Ŝk*x}̳IHCt8ɑD ײ1%m,;p99'qQL .i2 \Tqьr0(2 *@U `@ &#B9a!pch$ZXafqH]-O{r=Wj1*6;]nrAõ_=? Ε/dM4<<)-:$MfЫa@B(@I)7#$ZšzI yaR_cߔ"|x#ם@D-'VJPC03=_Wg˭V|q9%GFťt cM>em Ni(K-@)[ky c, @q<5灤sH;AeX>L$_KJ ;oHu8YoGz;j>2D4Au@L^ 6W<Zj)RlӒRZKEKQKwqIEeo }<=/15x<Z}Th vPmq0X@8EX?{x3b߯bF@FsC0, oJrxO/t!(ڢRk1p~][=v#HRfBx***{*V=f}" _pzǢ{د_/׃p=v.h8]!$۷[ 8G>T{4I;> stream xXKo6WZ ː)R9nh$YwUk]E|gHJkm8@ 9| f8  ~:}zqɀQЄW⁢ Fy6,nuh> stream xڽZKsFW*=%:al o$%gz3:MB%:6>3*i1{>[IYuE=U/XLJ!B VUCFsM4$6bH%7"wWl]ͻbE)RW8"]qJSQJՍ+6W&}|ڮn|m}(6[+)e[7U%KUx,Ly8ɾ\ZKSH?zɋ\q Ag `rbil6x% 0D rv}eb¹"G]vMY}u|҆zE~u qp[Vy%ռ]8Za7#ȡT^n: amdV}%o'KA|8 =p^T54@'p!8;s[YEa,{rbLj!д}v/u~ērN/&Q+V?\/-([/Ԕhm&H~Mc]6 qvQ̛/.M'ٍ#G7V\K -7iS_162KGnxvO^o'%gyt{/`DQ*^A]oqA{кFi\/gʴy~qĤr"Qmەݺ+R6\3T0a0)d  0HPbyvI?lW&j~.0"~ y}KWkqFy{' 64n]!bg#6"c`(M/s?x rg, 7EL!\XnM?~M,Y(NW@ NR}^~w:1"rJPgla0E3o'o铒!0@_Hcb W`:D!̅(ÜsG cl 1mC0_O)݇qH>H$ QJfz_ylsTy._/¥x`ț߮#qdJsܐc4!^ce\Gf8AN?WZ\nCc:¬0I|"KЗ)e>dԩ&.)ԩ԰W4He}b.+̗eѳД)oqO<79]k#P,jJ{,5Jd틾nDruP'fjb;)].Q\֯_|mFNy0=>ˢhM`MXR4xa8P`pDa0A3s jYp}=z^źnB*$ uv?o"YJR~l/P5 Z7w7P(׾5H(j呋}$wR6M1ڎ {1IP 0\- "A MPHb"C"vf>\2,ĉy\* {Q2h}R^Ge #yMcS_pEQS 繁PkyTB籕OJWVG/}S)Sam8d@UJ%-sH!cxqnK=cƴdl'c:  |!ZG)5pqDv<⃼2 xP_MyWp9Bw3TEd]N`sGoPyYxOg{@$n;<& o;~uTx Kj/%vݦ!ËdOChyT^f龂!p^f5qeV(;'yw[{/${<{OcgQw>}7kJ>hԓ]isJpE> stream xڵ[[w8}ϯUT/Rf&@BU3鿟-NQ*gƖsE:ާ9)S=F&=c3g%g|5h49cc=,qBƖϿh/Q"} M{p#p荏~2 OySbC;Ad0\PI e:oպxy*WR[l%ʋx 3@J?[e]o7U`T<niDA4"N5B PBEONui5Rb}WD, b-B: %tV.?k2ePV<;XF]9QՋlGl3Fm2ץD.1<YEqDaM$SWٟ7D6}7>fF|:>-UpX+WzZVVŗy Pߎb*G*QOU|vkfHxO?\y9 f~3+)b7eg茩駦Ee̗z$7;.(f[ gy=i1׃1イ>ݞ{uPtUXfD܋(Y/GfY?xaFͪ6{+8*86v a74x89Q/޷_.|ihM^k}=Ơܣh8Wj z4M>NjɉP3|a^025VN ?Oܽ˹TA9T`lMQV=N#:f70 S)84&-I=h^쁔~r|y: [KT@dm<탣FpPn=={D"R>Mr\'fwHm o诧c<>_xKhs@&Yq orlfޖ»QD1;Rsv?it WVtſ/r^ΤUUOE|9/oW}|}ˢNq6)jC;@nL{5BCN*C-/ |h0/F(!:Х dx|t&ׇq dKM`Y.5EFRK`;>|t*7޵2ť_EfȜb0,լx9}gepal=݇gH8aTwkB xt*lj .g=Oqd8IK?l'PIxѸdh-hA Ag>H=cMЕBQЦ #ȒTW,P,"SهY:" T@IBNp)^;0ՑF=O"OzY%bw avkdnRgnZ1l7> sy~2GXADbMfOp|~5:mGjt:՘)Pn;:rVb@PҵJ?r6KCԉfT_ uo[`׊ Fꌀ ˄Tgr>M`l'm'_]SD }Bn8)*Iw V:"_0~;:~8D!RK_Y%I  K&W $ta;@;[dOOGCCDӈh܆P &Q-:ߞ=[$z @(Y ̕9A)au~n|Nt0)~WA/qBD~nMDt7Ee"+:AՐ e)7M|ۨWY"dtʑ{ZWe$Vx 1CNPt ҐX muJȈInGK\umkK-ݝwsx~6L;@mۜ{p2R̽;Nwm6̗17{5Dm͉s.@#*"D^$N4)~*nrʟCLuryYv [: XX*Rn>9L绗Z hVUQ4rI[9ˁy Hߨê5Xpr},jz=_ױ4> stream x͛[s6+t;EV암mm/5%Rf)H)3;h; h ~_N^\fzLX™jf7ڿ9}hv ÃzL:"(7Zf{'N{wclK'JѢ7=WSq"A/qKBec`nx=ӄ1q&\{Gtt봛2J4>#w. EUp2ɣOIb(?7`R`2ƾOFM܌If<^^&\n:vLL"I+ALSbPDew:`(b,;DeחMڰ~':xw4< [1t_BԶ ;bqa^Åy1JK #!'7c"]`__Oc^x}X➲/{;Af]OAGIE*aBQ +OTp! bq" $ތbWaVԹtiWT. DNQ}[ i`"nBLcfKc"٭`S,b3M(]R­E*ݼ]&f#ɜ1LZ'AHJDRE#Nc@׆J퓴}83-)q-3dnUd w6(We 4rz0嘲&ښty;1j(\frq=]iÍ)؜*do2f ojIT ɽCx_u.O54Jm|~_b鰌%Ej$dZHYRnFZp +1r3sJ,B-RsD߽tGurpiO'،|,Y)UpVwuar1ǥ`J*BQ̪G$ir3ES%%6 B0S'HcɥN䒕e~VO;內bowkyV,*Qel!9'\ Bp`A&G'1&MI%b* bt4w#.{T/LFFd}-QĠH:ZUPU4Yuuh/ F˟ ?c]y*yhۼZ/כ<ɲh{+p_fx|OX%0Tl"K,Pcv7_[b(֡˗OM~`wDܗo_("KLbz>_gP>XL_Z,gA+ﻼJ $4Pu[q',-ѻTKi Q3? $,͐FU94 -BY2%Gd W"8bf璌G1p;@Oe qK~dE p5eh$r_m)*y $tXKЬiy׋NaҖ)=e *aߕp/inS $YY<#Z$R|D>ytW8~a%4, ˂ǭ PE۰LNhk3>qXu,otȡK3环nݤKκ:shp%l=i"θ=ѿ/R)׺OtP. m`  byF|$`"|D6!".#6wDIHEuhaxCx9}qmd(Jj]s, ]5IBDo|"-w"-_7_#A39,Cn(Dh̀:.K#pmQ R & +9+e| b2eaPHXV}|So4DVvSF4~] ,qmiN6rm߁7? lj_t5<|؝c[0vDEпC `r꒨}2ĐCzH SwZQ[u|*?I#&C^F{:֫riCIF053)[#tzzf =b^ ? H#Ea!TaX0%}EuKtcծr|^z<qWSYԨїpDݮ:|+ avEVy&Qn;+|*h-MF\F6ABsZ΢{0p endstream endobj 1464 0 obj << /Length 1900 /Filter /FlateDecode >> stream xڭY]s۶}ׯ['-cIscOw<0l(G)Qe9Cݳg?H&nG\ 0J2><4#Tn<]Z:]|}X*?l_.O3Nʔ~U3!ĸ[ ǫ/TVR8nEQVu^N-ww 1L^go]=l[.5om&)Ts+:ZU׸ϻǢ?2jݳcnsL)4aǕ_eDY6 F{ǫ<\FqaY{a+/*X7F*1#-w7%"S=CMZ!TfTt^ݭgDDpIR^%R7ꛪL[DĤR֡h˪Z gi Sl:?妃SQϣ ă b EtgH29Rv|j[4~-(O!Kp8tPPrhMqKS笺]Ą<4M`(}ΗcA/Dʄ9%}so.}q\1EFjX[ VuQx2Qtm.~_ەTI4 /s]܎>\n K!ڤ^=]>dK($Oe"Er3_ؐpgI;@E81 2N!ʨAoTL;h~.!򛛶vo ?>hSX@  Ӻ-]텶:ʒ RN]uţ)AуEpV^dz&01A?I(*@/Ck~ ؼ(C*q'ISBՔtGcr8m]XfDw.^r..JVy*nKN$3Y7W̿Kwf_|E19i}ySaf.ˀp~]!|h!c9}tJQTD5}5]I{&^{)d#m̀#9g0T?R(͛\r5)}WWæWE{SΊʵx'.$D/ymUv](-ڰ&o1Vpöt\+&+ PRj; f>qw5("s#eӢшww2|9a߼}SFlOX*N#45M* 54;P&Y_XgB,PkO91=;!f^H<28$Jn_0P7G |^\E2zN"==w|}u~(h&N]wW۹獭`wISN<4hfռ?3YwEV4r;IڧG]#&(cڒP7?ڔ77YGl6T̍bq〮,uG=Кpj)-A?#R30'*)C+R]g@<M_Hs"˔Mr]>6H20V/ ё_DS;Wc> stream xXKsF WHu>uMf:t&ɁkR_`Ll bǚ/.quҁ,V7A,kXaZ{~ȳ־ßX_05`)93!ٶfԉۭ%wfx$sT I$&N`)=j8?V,[Kc?lXtd'+`O&7V-]]T~MLpFeW.ͪY R(ftJojl[Tm;LFxS2Itˆp_/L52\ݢq3WMLX ~EErkDhsS'ɘ8@I4Iڶ%#8J3Γf ·] .W}!Bڃ@@p/@1.>B^ه2$ Kӡqpd#hJ%ȉ1|%)!ض0QHv[pKt0#r 3WnT< b\Px'-*3$sBu#G&t_Mo%>qa>x%yDfiDV{ꝻCYD iWص17gbf_voFFvA!3E h.k.k(+2t;_Nz {aD6WK +P>.Nh Γ۵EYx^G"EkBA(hm3)gWD ̙ʤSeBƾ &]z}Caՠav\̌~JH7^uj!?.v)vEeZ>)ql:ϓMsgآ_;Ð+ƿfR -B֩oqBm倳83'qt_[d@ =Ȝ??{w H#kt8$p"?-%]g/]]xyVXj("jA' yRɌgsL!ez󂊹L@#a2&wo` {q$s@1ep}ıSL/!T589-$ uV9n0~Di41ɔL?{,t\xgK 'yXĽd)Ҿ F*G?<ϝ':UVmlCw[`ͮtk|hK `K_`DqK"(L:\^e0\Q9΁`xx>eI샅dSFgH-VdUY͚<6roٴâ`| X}FKC 7(Ϟ%jvh_ ܛDc|}+*Cd!˃o%>$"w|v &%/(|jɸ%.AD&&1\_q(th@N-ixN>/"C{J5_ɒ endstream endobj 1475 0 obj << /Length 2695 /Filter /FlateDecode >> stream xr6_P;+Af;MKI;v4K\K$CRq{(2x:-<_pg:_g߽TLpT.gV,O0[~n] hY|\]mr3uG7q/:GEKKe~" WvxeDV"e]Q\?//ڕt?.B1SkH+DqXGс;׹=!+u'MQ6amQ?8QCT*p'is C"U(2I.ZIZ hRz׶YS4 *e46űdV|w|`Lփ@vڟ-M~=FX,߼{bq* Nc&A#?T)x Zfm:F1&4Nz=Oi3n՗cX> ,%:}Ć$fŔLNӠU>J]<(-x%-t,ݕ[ZXm~ V)wr12m x( p q'JR v]5d-pӄ_J&+׎I顤R&Lp s uʑSH4 lGn )‘H  dRu(TOsd֭o?5 Ir TۖMoSi:L9:w4sG5C"h4*V]J6i̒Ct>a4}yH[Lvs0EآaA0ř Ʊt[w4j D.n H! ϶۫,KchemUzi_5i3RaOS %j d\\˜X& uٍ7qϦVfjSq# ?9!{jWGO9PwJPA?t(GC0O'OPwes7F'>xjTA0n\oJ x'" qd3Xzl?BKYLTXAx>^V{PHAê"^Wm ʛj˯ @$JhXbEW(V(Idyd^bmnwoh/ /EJCn0hK04 C=1N6}I~"E 'R 99vT iJa}8p '\WхY WyKc?qR^tqbi=Ŀ̽`wv euv v et 1W?bN8yWG@:o}m"VjpP}Hه/ m *WaSSE)P6thۏ1eJFoVO|$Nz$R"k,UGC^{0 >X{ }(@ w %T'1<^dXT"!n'_6ooaŴ~H (x4X"'gՕ"@4r`82OSoNV*/\-U~K\xA%l{U!7~췅Q9ϫfE*'sUd#IF WܲK k1$4 Qe-EhR=>:?9iO¿ jU&h {Hzɨas_,HxTUZz&>{l6tѤ/j-&ۂU76%%yq@^昸k4/=;'h.{&<{UU#!>J<#"~ 'M\k2`qTYS7A0161j_&iye@饧cFk3:c}%k= g N(c``ilr1?J/b$x;mSf00?D2 Q{N"6/7S-0L,'!W`W`@.&}c"ܔ/a7>4#/ܢ2\s@BuֶҡH{}1(3=h~ܻkY[aJѦI}48\*De>ϻ') vJG0XZ) endstream endobj 1483 0 obj << /Length 2297 /Filter /FlateDecode >> stream xZYoF~ DVo$L4w=v]$y%&F"$=jJlvp]]U_].'ܷ?.OQHpLD(Q35o񪮺s ;Be~͕ظjR̘~?\+h0]sاdv_];}ACLqGM^-m.هX5wEU4y6ŪL3jȩ$NMiȃLOe6 7LbOڿ횲~};]wD)B3:ۛ{h*Q)_o2fkn=1Chf^w@qRh&J8%5m6NPi>v3#⺙ TefdeՂnkQ]_ӄ`p3Φx@3e/00~s܃͟r"mINJo 7Fxs'kjx'xkmcK쏵..Ldu|)~K|IрjRDY# nO#j=NIN`5ِ4<$40@?iZ^@Юi; XngJ|Q~X&3Azx GN`D.wjugڑY\|w>)#_dgT!I}JU黙>0%=u2,T(s&; J,:Jv8ŧ \-6I/d2;nx8;~KN ZjEjJ_KjdDŽd,,3ثt%ȡCD! Oٱ\P…A #ܝ<>{'i}J삖W3!D#*i7\;:❰E% &Kll4e\HwKM&+\e2JAr ݀{P&2b+Qg3zw(PЊ9zH%Xzȇ,EtiKR#K2+Q2'lW?.xbW8w욢QpDe-uśvUN~ 2f+P&hd %*fJ(17}*GOߢLB.!MK*< UoճO/>-.T?bgϚ<ą'yȾ + &oU zxzX)0Y&K`:CG!5ʲ*1 :Ӱ;v)>e;}&M~ qPWӝo'wULS@m٫4P/ endstream endobj 1488 0 obj << /Length 2953 /Filter /FlateDecode >> stream x[]s6}3oOifV}`$V&]r$EPƘ\03>ZRf˛YJ 3rfhJ4z[ey33D0j,~%¦Ln6@5D:D~#&`'Z8BAڄ޼y{ׇIgZ B8NgJTh?6yYUYυI1j|}/VfWZS&|kT[_C ݙ3A7o=+n}Qc*MΕN.fVu/y]_^C0O$bM^ݟ~oZm&MJH;s!=6ꗹRM5eܮ1͟s.I2 W8VXƢ86e7lʱ%ǁBX>)ILQ0!`nrDpA5Bԯ-'`dTho/ߜ"H蠚 _!)XHoJKb \g}`M@m*h6|q0hΕP_/m=ժ,ꤸ-+ J7oyܴʮ| hc@ ڧG2"kgeaKtO%Q`XcI6OS 4QFfI,wx?bO+, _qЯsJfHF''J\(ۑR=y ݒRC`ٴIFT:*y}?XB&Hp, rLdY-Sۢ^|{j18I5 ɐ@C෗Sv8FjqӿX^L\cHÏ[PzنlBdtn/ZŞkf:U/mfR$eؐE(]4ڃ⫢O̵zZAX=wamץ]\,.pW ' p[FQ%ZH3va4ur׻fFOOm&Ɓo—V"S-S$BV"GQ0[`^/cynA+Sԁ52Dx3(ΰ&\Sx|op'Gc3Uuwwtx>QdJqmIN"J ؎(C#Z: fG!iDeQ%T̰22O #'b`0rZǡI(%(sq/XN2C49#_kGA)$S8n^Hyz^`&X@(3krţ|rGXIlD m@(-# |$*T\qph^-Wp*rqzًZ[ H ^Xۧ4qh!ے'1 lK`t 0O[/8L0$F/<œPj$/mhpzCs\g\rvߕׇZy) 5W1%Kڲz7r7N\}7=985L7r5ySuq[fn  ts~cO\ =</l*:5=g~ͤ /&audWJ[>N'C5q’ix>Ią4 :㙪ʦE[ ^9݀Sd[CQ;Dh7Vﳢ,{ ^Ȧzܧض?J+5 QLf 7 \Vw}6JQG0]:EYCTdY?#*/!hpO˱$ BKV.4ӤO7sEX]f \* $[הI$Y׿~vm~[ԍm7 8V?@TA%v-cđCѢnPdeEv K\}j5޵5d`椧buZo>=6°mS~q!>[O⢓]mh '[Mg>@6 `~a-}>Y_\?oJLF5팾~)x"? l`{Rh|NN}\suz^.CKqYL9DlM7xVz1WEeh7 f׬}]7=w8o|Quw;͊²GoD .;iumi (g +yqQEhIhJHj(IJz e%iM$4̉ڏXӬBL /AL dJabq1S"y`$z쫸p:5 t"JA2r Ef/N /DEw#UJݓ^^N ;%DXB5'2e(DP`:T:h:ԫ0֡6j'c(SMӣT^@ Ԧ5Ima{Ϗ Ād=k OnkʰVCmlMM5ގ)Kz5 GiCs#L a0@Ӭ@- gi1RVccpá cyLc 7BH?K endstream endobj 1492 0 obj << /Length 1358 /Filter /FlateDecode >> stream x͘Ko8ž$ fbEq.EӃ"Ѷ#m%=!D )o3\`g"Ēw A%[/1y֫hfu/HG4 wYY./ u3ڪR!ïQf&ݮNk# Ip>|ftYF _^6ZemQ0ei y2Z M{K8.+$EhB}+Jb,ƥľ/:cI-=noQyy.ANw_Bm&卙TXzƼFmVvnHd(Frӛz)"`}$FQ>sTcGw$;%JS3"!]^]W!f嬵?B:>VARKS_aٻ]4 8[=ȅrܕ6VIt/X5,T6AYw}V 4\+az4=Ԡ:5_;+OFPBq&4 P(~[/^;C>f}EYghhM} $ΫP#ڡ}hOe1!8hʽ{a $Ya)9h]E9OiV &ZM|xtb~([U\߹|FP)'})]}.ňSr VH8*եo!HXX=V%9Po:"|nep,]6ǕO [/<4WVC[.fx9zR1:W?Y 0ZhH%> stream xڵYo9 xkp*Hp'qPk(I)ƥl)=gGeUh ڬ(ze_cTXeO'\hPl$_.a#{rT:Ű V11`T$ V9~69 J:QIUʺ`1ƴl sDbdKI6 n2 g lyٱhL/҂a=bu=Ze쒕ޘX7IAybv;Xw)8SFĜV*ʎKSq&qaO TvҀi9`LV84W0wDyF@CñUآ[B%|hʈlO\RFS :ZyJ$aO2#Qf #\LE IbjFb8h ,>ld,$N aJ|EK,:+p;fvBpJ9`ggP=QoAg8TgxǪdnW`6X_'kkזzL r0[".٭Rj_$d(>xwޓ' {VI0EzzOUuX]~pT{XI=].)3 zќΏV~{Y7_[tA;Lt4hq 3pv$g)tAq}, đɤ@s t>hhcWrOHʠ؃1r0X1dL\ɘpΘjw:m`yʔ-AbͼUϫ=twc,TFbYD…%LV/ON=^i5>x.?.UuvvY=],&NEN5M3qy] /a>pIdqyzdS*n %/t!u>@:x|g[\upkS`rg0Rl3P"g-NZ t$ڡliIjհ :#QD /Ԣ^^ZA pSF 8S^dvk4 w|h4Oy (' i5("= n^#{BlK\&CM٤d䍋FsȾoEczutVQ~YۜY('Q70Du{pjjnCMEKQ u$]խ!-[ )Zmp`[aid=7::xg{{_?{z0z|x8ur-hzHitZ8\ta2%d,lk(2BY^8ƛ+L|[yV'W=8c9^N{|hp4<ԟR^LN't6kdTO&cԠǣzqEΡC+ɭGML@N>St"Y+Z\}Cy"S3{s 6_lj?ٞOtNV@Nr_sO!]SZ4"hm>]r­ϸ˸GCko- O!GT9=p|aOn`ȥ,@2^?Jy endstream endobj 1497 0 obj << /Length 1320 /Filter /FlateDecode >> stream x՘o6WQj}ۂm0@ <(csdÒCdS+Дݏwl9ó߯p۫~c|F02ؐLљarv5mcۛv?`  /lI.:YHC-(Fˆ sl[;_0Fv\E*ĸVlm @v̳5 HaOz/> ldAMm1x\Fp줭?c]qi%tgB(o8 o GbY8[/?WO.'7@|]ML"e.+йI1.!Ŧns{R:JudPD19a<.~ov[Iلm5!Cv10oe ; LCĔA$S㣛?G{WŃx@5ăs|.k=K (vު.\|T1"}aiwV&na ku Ax ^j/]vVzi-BiSK@6HqTaCށL4FP4]ʮ34ꎩIݔ "A-9N8yHv,CB;Thm |kr,B+eK&7QG%s!l\b 0Ԩ3ysHr#ux,qJ&2.ZZ*} n<#.3B##CJ)Ҙ$O-KpX1H1%=@nmT(-lx;<:=| CB!k}9Sb85'1uU.q\h_؁ZvJ-;C`6E&"5є^d'RkQ?<5Sܯ1P=dє_oMeZ endstream endobj 1502 0 obj << /Length 2195 /Filter /FlateDecode >> stream xڭY[s6~Kō fzqޝI@Sņ"U)SJ&8΁x+]}ґq'(Qѻﺢ-?e}=O/~(bk%9̜Y-Y"κ12%gKhmwM @UbbP:>=!ڥL3nvE a\T2!8~u b~/~~%Y k/. 6I5ziɨ}lX۲~_7u ˦Ieq2 96 uCR2#VDbSN @ad9g5ؒAfˬ=EѾ.ھ|(s;>ۢ߷5Bh%QsF-(=:'AW.2*3 Xx |9<9UT\DeWūk0w\ZeUԜj"NnѼ-` =b+7W0u|i`/}Pߚ5lC_vEˇeqh 5R (X%Ȱ܋]Y .Z8.w؇ P恞%nQ8P03߷mAh@S@+"* :L9!tQqꇻ?ky$TicZ(^5 qѓEUt{o:,.x{]ty[Q/Á!$J“`*16eu-Θ}!s R#{a(1b>62sI8h@ o~/+@"\F[53]F!e =FWeߝϓ pH53-'lts@YX=@tZ9͸:@%SJ/&Nڙ'he]FM4e:R.RH<2P!LnTG Jͤ6t>ݯ.>0դ <.Oz ߤE75$ ,Y֟' Ō=K+.2$0EF2Tи-@D.hk, @Q͍'x } '9dqWTDU-W#Dqd)u k}]3N GY= Tx3-]ƼOWؕkj EVA{6ed6d$*\Q>hsb#.Zvqː4u@yK'"ݗ |*Q0x{ x_4A>tzO2M6M!YX ̦cӗ477\v`@dLCzjQ0אRWI1)7?9Z4gL{΁K[p$;>?r_t{ e}B=%=#sE u 3WӠi̘{ &运aK4+YXd0iAQs@?PT/ iHS;^{4=|Eǜ)\$Mև+|Ώ<О] :w,H1.fߠ=/mGQYKQmDU3^>s!,&2H"VPum;kriTd} Y۟ 92zGY{!O— PkPX xh4ה4<]$(Tt}vH`4ꡒA}WLy|(ӝKaJ Rz &nJi5dL`npm}` u}U,[z*B =a,!l TVM endstream endobj 1508 0 obj << /Length 1567 /Filter /FlateDecode >> stream xXMsHWP{BUd>!l*Img#U.NX[b o73( T=a= 4 hvF7L,X ,⁦D,V*̓;;z7{}1x,`ZXǰT-Y]}n ( KpyD,Xkv7^Wi٤Eؼe%1ZxҴM 8bryG"FxK9t4bAq1bxh˿.OcMz`E봙/=wtc9a~L~R#F`G- oQQ+pGK^')1\ ǾC 8 J8j"⸺X1c "H_đCMNQIL8Mqx!9 |BLz2 z)D%1R&iDAv/{Fl2I8f9l2fC, Cgbq#ϰE ;姳#^Y~sX|E L,M?f b7B-Zt܂M]g/nm*Km|U ?nv9!uqϰ%͘Yxt-bJ㰐w؃6*!Fֺ ^+ݭwe:TTݸkD`5BlT߶~mjHp&~Q_uddѦ(r{[4i Ϥ ֎a#tz.=c( ֏˄$LL_&5$-H52*h^!uS6%W@*$ 82Y49w ɲr&ux!$VT\EH~pۢJF_L)~Q3,JEԱqΤ9[֓AAUPmdƤAv)l[mH[mS? hrm ҁ;y$gUDV,Ob> ? `ScƩ]pea)Sƕ:Ű`$ J7x׺v[,piAG*v夊7TL"ݝ=蹻b1@t 2/ 3D<1`# I8Fd@%'&kx/ӡ?_nmi;(tafR ?Ƹ"N+g,]a$ͮ^=vR^Sr\4OCi)+uVfQknGIڎ`v,HD4Zm2u0!g]Uy tG3~ɝ=o m >Vۺ&~䟪m哪7{b"+ kYRf{7]ڇ׶_!+q˻<ٿWxdj u dubL^AH|rw-=@QA endstream endobj 1512 0 obj << /Length 1566 /Filter /FlateDecode >> stream xڵXKs6Wprf,O>rK$L:NcZ%&T\b!Jy!\.yx愇狋g9Etq2Jyθyt;zŻsow]57TrfrCMRʸ[Z\lʕuEgiܑ},#àEO xcvcU(DnGKP[Y]u`f=0ԉ:׌sogn2UJQq8>A5x'_:z6mk (whǗF3 WKI=d4L@"02e5ï^ϼߑ@0%gcE˄>Z?X` rbN.js]",KͰk}{ [jZx;];Ls㏠ ζ_Qj[z fe8SG+ wƋ l8-EB>Sˢef9Q/C6mr?# xM(bA\ޖrEfvEH'pت&eʤ[wU)a)`P*obY8k`b,7FW&a"I!9KE@vI_u2):/u6 E me^m8HH @Q'W<ǷLzE^uARUt~'`+Yƍ%F5NS7P2t'ᄏ(Mğ'BE> stream xYMsWDUY)';2Y;[h YԒh_n4H2r6F~h%_ONeV$#%",[GάX]?%YX>,Y,SOAr,ˋ^j\1E/`<ޗ%LHՋރ~x6[r&dEF?ְLbC?_,y|~Z?Bl9SJ=tPmX_,A/.LX.&ŦrL=[OH݋4K3g.Pv)Wmz1!}5Vg/J'>b5J926*gi&.`E:Qb#@<𤮅8/:Pt^؂l/ QFl>ܟ?W7wW^q*x$u2VI?Fы ۫R2O+3ְdހSkﰫ,t׵ݔ{@g>fW^ex٩k,i.͡rYX'nkwlHvdZ ~m\(q6$sh`f4f>Be&1v BfkwA輔;ON6ШkAe c:qkW[h}[v{jٴfS#KP:d+2lvtKDP_@ee5yPuP-)X_Ux07PI<Գdi8O8/ X+_鱻+ݶ!pyWmsx>F#ienzmrhRz=9+b Iס_/S)R"@oB4~<}q(V*H~CXc+9wL(|dWSȿ>)I<bw2! ɛ%z-=ɒ@YSX )6{}89tabBT~ ӻ>Eh޿3k0՟"\OH^,cPH sqQOWŽiƀ]]PĂQ'!' v)Ov͇蜭*j \Ⱥ\vײU +KQ}8ŭd|ĝ TT8ιg s_%.JgoHIwꂷvs=@yB"jYŗID"i|? (Ո ev ㉺Fe_z@Ɋs`\`pWGG-ZUYoܶ#z M y\Lm , @50M`Qh^@[Sconfi0H\ygO02peėJK55uEWݡs CukTm_ٕuU;~}-M5R:x"< )P +\ X$Lp*V s)gSAEx0yhRJFj{ hmI?_VokD EG$x9#@f-{M=<=~I9eqp]3 u  \O޷keqZkѶ2K5"ū$z'BKHjm`9kVÎ=2cOdv~c|yt4cp|OFE-R^pt4}r]]z mTjʪk[BুXMŲm-:  J~̻׭ P{*Hu*E)w{LcX둚u燊;> stream xڵXKs6WVz&B#&fir{q|)HbJ* .H>.6.v߾ȃM}}X"^i FG:eiltLٖnj.O}|!\pXI8 `jhq4~#\^jp,r" ,r?g Xf`"'hB.SECp{Y[{~6l5Z8I(UOw0n˟M 7Huqu}ZlpRe,rwqs˃;8ςK b&c`y\W(2$%,~^G%'3)Xi.kg e9;A,g/D=*,bwMqW~([TQاVNcv a{5'pMDܧ(O,(@6|uXwˮ;O a !GFG1.{YC?\GP9**'y+O!3Yu&O2DY,R)F)&J8ORL 0_̜JA.&9lXSX'z~4Yf\&y"+ߛslNd|<;3BD>Y,~ 7hM'R_gY)&%XlU6 Slyrcv0 d6(ͿHXgU FEV;/9.{/7P˺71(Wծq`?tH5~$]6D8ZK_|)po60YnӮl蜎mCN>_^yۍE 5 ::ŵ@t5 U(3҅N<7h5 endstream endobj 1527 0 obj << /Length 2826 /Filter /FlateDecode >> stream xڭYK۸ϯPbΖ%|%'{ıS9>p$Ę"|x2U5H g*E to*\z/~E EfrfUf"4mW&0 /?VX,˰}y*Q6%):̀&Wk(j)p|[L7ݱwM~,mr2\_4TymQJ L\}Sa]HiA z0^n:$Ed2f˵xci;K3t{۶ ǍpJ{uGOZkv+.4%"f(ͷw(o|VΌ0.-ɑnB$uAEط{5pFvv07<6wZϩV9 LH~n:УvE呺}2΃ep[%#e[3,:{8?C32pRksR*w[[LM0ɋ@ Thr _ZCqZՀ{ opc0˫sF!o^?BJLj}DEçpGR,]:J hſФK/s _^qe3]QW_fy UdI88"@,c==>E?gU-:C^0co;Gu@vֶ^Wse\k/ P6.o R\}WMƇ%wBr1#7*{ۨ8ubǀg'tڏYA:#uAfľ\F ?~X :E8ERASH %Qd¤р$?QP:f8VLKHZxaևk|A-lmDI=c,0pjfQC򥡜@C w><&1 D@DM& جiWm\ F[=urQ$U:S}HH!(SluR;W:VsCwZs_ e'~sIgn@iyyʏ4&{{G;;Afc:4 J_;? ChfT/D7Ieoy7 ;$cx֎r.9&2!nIpN]/)I걱eNht pVP4[f~ |y& O/$O6!Y1yQB CrY!EAk)-POst"9R[mcǞŶEr5rR^`y𫟯x0\ls#r&Bl/]ՆD'.BdVMNI#"IuP.=ScE\-7 8y%gmMO5)ty/$FZKP ;~ȫ܅~}:VPV4CmU|m</X23_΃'#W(b~V-6#"dzjyV='+iǴ|QH'OC |$fN{_ [;"ޔuwI`7I6/Xq4d>T[=8&oH%fod_;YjD'2ŕ&Ι&; o^PQTs 1G;F$Z*XNbDNTz9w9$pvhDUHex4znɷd/IW[_Niqcyt! uOT838HQKp iHI6LP%j2SeI?Mh`:d; ĉoxuH nyRkt)L4+YXΌWN*zbRs>_? ixHkNa2 :FfSPNQ Q!BLOjƵD.1PFTHF7L.@f@ΕǏa :mËb2{N ۛf^{`w1ܾM D}9Akijpk2u^B]ku:ՉkRC}{!+T$1\GJjmiz^\5"RJs]i쟊Η.l ]#`[ (KYř;Hm7aP@q7 /jZRh|HwqhF䊣31]Umeb5yG0 "-g%ohKǪ00aGZ-݂}W*ː#m~qQ]{l7݁ۺz񐯨(m>, #yFS$V1POI:w:JcǎDBBCY=)P^Bۗ©?x8[׺V_@*%'"!#gk~b^.r{G* JX3K!mK~⡆wPkV=m ?D) endstream endobj 1533 0 obj << /Length 1429 /Filter /FlateDecode >> stream xڭYrF+P:Ud%7'8cf#eA0R,hy."1l gp|y15`CLLa0UqeuV.Xŧ7p!)2}kjG38!<+"V`Ʋb$Ư v3EM؆smuZ] ̎`p?-r|U^bl ?^nnȝkVۯ>=$|bƮKYNA*ft2PH0N]g~}`"\!y>~ ~|aČξyӍ3 !L4"&ipRIIQruzS4{ I3$=}'7O  @;M]no&hOGdʹdr^ckKzܭnׄE?CjZp_x{A$1:ȣ࿂v;Ick)gv缮&-`Vg%xQ#! _N<&Na`hxqDp!!cB~þF GqnSSIr6@v;n?vьfaS&3y3);fqǁB"!:R6ǂ#i&BgH-7}/cvuZV[D\yGf#̙&⇓{''rQyU};Mrao)2|~28Oв' OEmQ=Lq#tP,obՈJڑwRЂi)} OFw4}7M'^7^G# {.g)\Gs^ܖbNF7 2߆ˎvxscڨem'*kbF)PHh4$And 'qge:b7 쭝ȹ\ĸHĐCzc> stream xY_o60$oCJ( CClAĉ#&(w)ю;IStKOs_ |ulm":qĝԨip'R^bt溸#E?9N/}KqxZJ$QI=]ved'Ӡj_Ӳ1^%(Fnrэ誫uT' /QYP{$YNMYF=D1d?O1[RurSKH2`^)Dge4YO=M5`Hͭm->$] =ȦFEI<\Dc $mI6I>dЀ0'(E4$b)iT?n)d6feq5XhH:n&耩+Dy-dx@р^蜠~ 8QNQcR72db>it`hW3YjNCG:W[1yu@S6>~jgcY"!BA p PUDu/Mh#␈Dam14P͍n; Sg#M ߉$OWlmN V9^NYFːEy X BB67dƣl"v) >lZ6-M*$~fzg]fOv,,E;FB C$'{sD/3 wȝ!wi9` xá:MA؅ ƀWTS]*Y'LڷQ``wD[1_o$K'v;[a VsBް?BZ7=7˛\[0.~]2[aT[p5BQ ԮR MSd%U\.*#5pi26hո ˖QV6(9WO!21`ҖArgKΫ{|*q3W9ԙr\)8'a'p~̖J:v\I|T抉:8.KρY-A5VڕXNVX5;D,ࢀpA Ђ-}%8rc,w,==jKZyM4][noc6l52iBy㾼!UEK\b6vafCySfO0OGقX <%$`a+ٲM͕Cc ɷiUPM*MN|wWv2`zjNb4.w>x/`7^XVz@C^)E2=k}%]xwymCqMymmLIІi3ݱ[M#5F]Sݍ-[.-$&ks[VNV.ek\k|W^K]C6qD'nGIj8OM:CKiM8,פzWfG[.P&rc<-ѵ.EBiqvվNv{1,"y[bv%S AG^|yV/? hA=ۙVL;C9Ǟؼ[hZKw8܍:t~܏+1J7@4Sg{ju]f[5g&! D0GC+B ^kGƺNv仵l\>KJ[Gj{l-DwA}6r_q G G>eȏ~LQqrMbKhLO9|?3G endstream endobj 1494 0 obj << /Type /ObjStm /N 100 /First 930 /Length 1477 /Filter /FlateDecode >> stream xڭX[o7~_kHTj%{sj-Rr.@ECK-g΁AH OIF58mO /XȚr*,V (ߓߘ f)-29X kH".aSuXAi_}͵7bњdj` h h_ޠ6j@W> 3!X H)I4Eb3HRd'I5\\'H8'? )AR d 0B/p"'^8`g*4@}@ױ< c\Zr0 8cpf. 9\I's1; ;J-|pA;qnBjAri\#Rmi fi0,33 n8?=y G9%!(2{HNj^}{~e߻W'.A7s~+j0@K sl5(f4iZƎ s}>/Շ\PG˓v[vܓmkvCǩhfڨd  (s-y7_ HɃ1fC|W@-uWk %*>_D*XY8hH&>8ׁ#UX7k|;;;,#,\U}RJHܢRs@m-I RcR~,y[4-[sy+G4BP:D:F `\l$$yi4ĊE;7b }c ҡ7gJN)&?VO"mAbU^~vpѥ`/;Tk!ZD#)S wsӴ*4 Jddc۾96bFsZ>/&L.AE;{~붼rs5bv;|s{a h任`#=J=*JFxQ4ok *|: endstream endobj 1586 0 obj << /Length 580 /Filter /FlateDecode >> stream xڝTMo1WX=9^rlE!7i"lP3C\؞xZoכjEP9IlwJg/J;#6tnn*8$2@vY, 얕|MDF[cc#s]̧;YS̶;Y[iqcq{[|llC3),فwV{l' @fTG1EUQʃ?Eti'v33l)~ 鑐_pT*TOe.R%؎<;'s_$ɡ,Ytv^b 7ۤB aX4Ǧ{MAϤ=:du̖sdt8!3.XdxChm\Z@i$a"n;\'l3ev^u~˿iNmQ=ښN;B2aw/Ջ+ծz?50Mk#ˮH~<\;~U_e0#Q}"{/x7%9G`=otg_xaʚamT%QURuxYFT endstream endobj 1598 0 obj << /Length 1491 /Filter /FlateDecode >> stream xڽXMoFW.Z@D'wI AEM(;󆤖2eqh\ξyR2SW;2 J~̂ɂ tvzϴ6>uۛfq<oWZߎ+/ݹw!+*{̴-*벙EUiG ']!h23fdzH<"Y(]xVryER/!Qa(T ɘA\AV1{ZK59- t?l WJ,P7mWy1`6>BY.PkB%b2/{ϐ {vEȿ $\Aos1v|WCny)S vOAےV)r (R8,WVC">mvQt ia2]0vfZrl V[sBC)@8I^&8s)[6 el?@1[k8,Q2e5#EvkWYȒӍ1o`hd$#r ЁJqPz@Y ^A7oqHgbU4H9 ̄Ъ*PqU.@89U PЗ\NrIB`Nwhi'O4f,3C0hդ!LJZ`}6S=g#!+JIrf#Q7jF$! Cw&-2D$Thb%,Dsh_TdⅼTOܟUܠ3:2iqjDK̑Iڷe~fI)E` Y ӄ=< 0,kpa?D~ M(Ktᱎ2*Kh7%%n IsJT/}I9;jÁJ{tH쫤3b_ Po 7Bx-7 Q(S=ݚa1KITt)>܁t?1No~NīLGF?#z cd^IȵlH.iZ$ez82ڥ|5j+I8O* %AO} |r&y15Ռ;gww&I?6ܯ]%heM0/Z7?<L!w2VƢtц&6)KEM6u׉u}CY's YGlm=&t7 ?]ϒ{˶:R/ _VZWxÇDOW熸J*‹|^#LYb&)2$`ߵf> stream xYM] ϯ/HHIExW Hh;HE.lH}ϡ{@7Y< DTk-TYj= ߞ(73I1V DM2: I*&y\ S`=1uʲ(kI.+8˨ꖆQsi6tBw'vB-ڈޱP;D߱ Nj u:4XhJ P+e12BI^6v2mRu) ;fs]:k3P #OiS";"O;?"|(?ߞg=}s|hvo)~ɧg^x6j茍 >ChԶ ҳjYbA87q+M7qEmlĦ7یZ3Xg; E&D876̣ vcf7D\v^&-x[\b)l j<75ɺm2lv_<>k7:$0.Jk nqϑO/$zyc~#7tgƎVGRsԚSѼ3SV59zϜ ! ~糭qG=5TP4M5Hp[ m(wLd} y&lyjlO+#[P=߽chq9Zu겲X{Zd *l Zt6p.72i7 s6;\{ǸoJ4d?Fhv f&܂ ppE9|˵nѵFr FgX\jCNc3š"yO:]k,)(vzĺ%8;Z @Ӱ>tԏ}n<R49ĸ$X k9 _<Кk\U5Do'ӸdyLo^"- ƎIİr6t=6 F )PCDgsmO3X*g }~<̝pvyny舜]OcGct칟|r:ƣGf)."`W8^Nw$ٓތt8k.xaߖ9W<诩 Ɖ>y/f|*O+{qriu)5> ߫Ό endstream endobj 1652 0 obj << /Length1 1416 /Length2 6197 /Length3 0 /Length 7160 /Filter /FlateDecode >> stream xڍwTTk6!!) C7 "C7 ) CPҍtHHwH+ %79=}k~yk9YvH[*@:J`3 EI89N G"dB M"u @D ")+"% D@H,@ 4tA1Bx)_EW  :#[ qP8 u͛v㟚s#`H4g+43Sƒ ѿ H@P( + Vv0_t !l;?"y"@Q- 1?}b̿_u(Vm/`0($z;ԩ*"1{3fS TޗOPGۯͯޝej!xlxwnh8H2=L=|K՛Fw?]97jr{HSQxuyWwO|~)Ez^2*gkT8Ιkt#x7gC?X4I |?>>`H`N i@w3wc$r_h6ݽE&&eAoVII.άk_{])3q`@0Gec﹵tBѩզWv'̲;3P^Q|ZUzdZcXu_+8Z y*߀lh^WOhF)>~|/fqbsi<^h7V N\._.IÑ {<>'H|Sbn5zI@ 'Yo# Rx-_z7&^{Cʰ Za0KN+bW݋NƘ `CܒSS!'|@yj[ >;ݲ^nshܩݒXqzIaL_Bd-&X+)rUg|`>.ѕ5ʾ/9=и9kW0P`yqՎ蜰8le]وh)daW53vf{g"-BΤZKŗVyJCľ*\# UWN0Fq ݼtn!.wo߸ԡ)tَ❻zm(殖8y9C݆*9~@+)J(r9iDžX ǧLk}nKqV+xVm*+ėWxt 5b0)Fb)+4}y1s` ޝőKJD{5Qdc^e]Jt{`pg 3"ǯ |~ZbWrp-QNa(uwsΦ)!8q*+#'R}U$;OPO8NGvW^zұ(.;= i<ښqO] "H:"#NH*n01/[+*U{],-#zpځOxtĂ{,-MgƗ~jvA\sx5PXI@ H*&n($>+K9.ξfUW# Wfͱl-OmʣaV/^3OUr&Hyo+a{ $i++)8V2ׯW!t>uf"0똝pcr͡UOhvQ,9/5e-nrVVRY Z/*!|]׹WXG.–MA7E^mA>=$L^ fe[)affwLĀB&)dqx1gì'-_a)I&R@&G!Iي|T'ZQ6Pjv pxm`b*ްO]ϣ88Iw~ n},~y7_ m|o9 `ʕnM|JJk"̕ݘSux˗@Yql0oa5u1ǗCDco"Bp0=C*䕊X؇FS`19<#bٕϜ ?q`Z+[˷mMntQlsmMĠ\tXE'JV1zL.`ge2FZ'Fʈ^:$!ɝ"-HH"OQٚ63:0FLµ%G ~51lCAȈ@zLXN-ɺr<;5-E3 eٴ]$T8+{d>tlvr&ZWT#XW3Sՙ ]׌6T]DE-/vIq-^z0vNjrSEL 3e~}x#5ڸhx3C/ASTIUeɈ Vh_דڞ;_*fgP^yXR mQu'|F@[< -玔6n:VӍ%I͏U,?+6sMyT1.^C=Z\ zx7s3II2 5: ž9 ]=TDEJv6{."c˄r'QP> aHAIV`[O .7VsHEt1~-lן-Qխ&nЭG򴭂["은h:Q=u("CH7L1ت+Fiʊ(‰=`|H \l߫ ▅ Ys=qSQ2ndKxG98|@FBޗݶޡP\3$Ksz}ׄ]G- wă'y"eQvt&#TS44@cAu_,.gW^^(Kv|C1A0s6[I gE݂ #Ƃ6umjR殣gom]^&-O6<ٍ\yrWDҲnY=4+ p!!faw?h6\f2!Rq>I-Ӷ/#g%a i1i='ejZw`^(~I1(Sꜥ'P9-dL R} ]č,C}_;,Sfˌ$ q֮!P=}oA TOP Eg`^PZn ݰZD &.'x [DccAߺfAM!zif~H^~`KCⳛ6n BmJ>wJ(i)ق\RJLݞL]c ̥֮Ա1}1=S<]> Gu8ymw@YarN_ʴ;v WW#B|n6oGkyQMtRwo7XesG:KO\xFo7(xq$ߧW=]Axk\\P<!BY.\6ʟTYh)G:̀=pͭx[,;q*gOt?Y+H+ݧgtoGr{1N>Ho+ =v&>Q-BsnG^5ũ9բ lC~:ǟwJr0P|* ,O Mw:"O"#Y֫_!vpPWG)؏iI /r8ET'7ve;iM26 >j n}NPɌz V92]5Ek1"ܽI{A a7?@g#Kif_mbzwdՉnA%fdg<\x%M@}JyөGOD5{e8o{ȃ^ŚWMXFRZvaoV]@M+똕/nHT5{xfPw35yNq#/|zLTFAzax@Ƿ 4M^osSI˃:WZ=zr볻UiRޠd|!t.̹+Vbmg"h ЈeAJ@;7.v׫VVSxiIK˧ Y[4-_ }Wh%dLAWlņrUiܫ0uk9+/${IOl]Ƶ_}ؕ[ޝHg̞KZ >O˘tcLO9Es|Dsta\I#iXs%Д BUmzcT#qӻ=b,).'*7$%Fg[m~dV[uNOEv yodLhjgSm$dFIٜk3E'K&ܴ!<0gH3{0AI49s!V L7b*dwCpûV1Il~")MWR&ۜU2ێ[U LC !멚'约2S[ gf&*'@Z\g r|cuMGk?AZsݥ:&ZFkaUJ D,:?|8%8X˧3t^ gb#ȩ{3> siaJ*%F!kj%'} 1Sy*/WȤL=,o{ilQQJS7o%ǽy^ĆzB*}b;tyrj޽:(ZG0/1"`ҽW=sg1ʩUZ8܁~hMϻȑt?bրjTqq_qz.|^4k&DK+A1NJVYpu= ~oVR|hJ({$y/ڣ3Drj/Y7Qtz"NK9$iBr})7e6a"> stream xڍP%h!HXpwwwKpw .\߫55\J¦ cΙ */`bbe`bb''WtGOttBh.3r~7dY<̜9 >C)r"Y-j13kj_H1w{VOXt, ÄŇ 'ˢ2wÂNGzդd"|P:=2}}e8EDB$bv Q@ UGSh-ό+K T_!qiN_d>Rݫ:ŭl>N`-h6 v"՛/{#qJ\b 4gPR}T'kChC65pqIFWls3$DvjRxF.9xdNU':ŤjEq:~TyjyNKSD $C(&Hq`7M~ڹB> dgM_pCn~i,*AUKE .OvIkYL2=rQI`:Iveu{C̑9,#ץayh#'lv.| du~r:#*3)x/<KH$[Ox33*` \⷟FX~#$KA^,7Fj-P9yAv `䇕W+ %Owؾl!N4Z/}K߬ӯM}}ҹvzX ZXCȓ9&/<| z{" lv‚ԟ';TXcfZ[Ǒ`]I Q U+e>$:jEb .yL:FBbUNNCM,.k`BMr ;PK:/C>߹jc;'⻙ն 6uZD&dJy(YOctoAFwat3܉cDEǽ'LK3U^c[thb,ۼԌnXoizOoAR#4uַ%i`{HpW~`CL5rCl#G>ҵ53[Ty.wW^S8dGh)oYB`xQEc96 I*M]]bMa>ÝL;j#s0(2$Q|&'9eɣx9/1 .r-> ĬZ{Is&1ߙ  Pʣ`xJoj0 dӞiK~rV,1uL_4]d Tii BH9#bVJdLyFhU ۡF$N+Y׿zUO _TwW󰎌=80=;벅tXq LvU)$R\] <<+^LV"TȾAe#O\Bʪ'_FΓ<^slYo-e+DN'F/;j ^t&kjˠZ0#[ɶFS`A->} Oni1ry?lLPX^_n^AuqŒ8pu'/Jk2HHQ.C<R!!8 ?V܀ X7ZIjω5[5*l2/+_h#q*@Ub22dfF.$ Wiy SsFC1Pꅹ!~cSpD1G!WladʆJVy\-ܼ~][* UXcO9r4ߣEeJLAA#> 5WwÕʷfB[͌u:,Q[a^PӞ2&*EvT(+YWw je2R*F7CsJu/InYBQ|LS%/!^XR{7L$#.2dZㅋ΍a8g_Sߧ˗^U<<ͨP q"=#RFbRտ8؜:Qe;qEd+Dma9)sl(@[.c\Hpͼxt}5AEc3 oKF/<.Q0 7Z$uXXb<(Ǻ-ǐ+糛~n4Zď̀Kc)eJRK:Z& %2 2x@!/-#aYe_ e!YfڀBv%q *3O? oHD |`.4'q[6yx)ꄂUHu\vߙ58e.sۧ4 eI`B!o9j,tpo1dy/=Eڀx_/a:0 =I Uf4 f qS(2HK1-"M w_N?E6{▤-@ƭ +61$vhY׭{ڎL,d͢6DStʠa 414')#0kBTݪ Lឤ‘ܼau]U~1 X6t`h5ǎ}5Rz(z/)$QimI[- Wӯȕ6NJl{Bfpk\ zݽQWp+x0ŗrϵkb0aeYdK6uypbOJ #2\8$nNqwdN (oPK*d6 s03O z0kaTJ> |wVTLJ% Kx4b3--8SSWɹI6Ւ -vt &:i\DždpnOj_S2cfzA05q7V B{b0Dl4fMf۝($:mt))PVe o !<LepLˆ;f6A1VR-K+j;SրuU+NB[,KWNWS|_3spd2 `hk=Ñ(~S>dQIjQ}^FZ6܅j:$qWZ֙XWF o!|fytĀ䌣ծ.>kS3o/a-v5O21LB7J5?; u^]2g NJ;&X Q-Nځ#Q!l´t6EW~'_lU6 G栉:)W+7gU*}%):~뫜'_k> /9~z@o\|-9Uvxˉnwyd~Y~#|Vo@_i㆓_V(ݾF'eLa<Ռ$?'<`.sSpX豟|eKJ>my%Q&Cϓm)[XdJ~HzG ϣ>"XuM^!4?,)DsJY[ij 2L> փh$rʞϙ)럤p~L3j<)NO^OomwEA,O[}EK(AνeޢXY|l9"\Ui%R4(Z.Uj_|דv`6:2^e(L2uI=SA,'ckjyyDL 85 ԏ>$YᗷR(mlġfrq3cQ8]ç">*}^lT'Iyna)4epp!ƂׯJ7*0I Oˣ#"U֙gf_%"T93]GUpnI**֡\!)]dAd!_?Cr)6bju'l̨A bIgf귣7 ! .8TUOv45֩mh9̐ͪexᝇTA ) wD1` /zT|Jy@ZUTg6 \ a{RL$IޅY2nډUji(|pXFv釅OxԌk_WgB_B(,侗>FT[1vJ#'V܅K> p(|UhFyGwyE }`ܢJ~sb`\Z/CȳsvI3GaKDWfxݘ!_~V@*rbmJ&B:E- |~Z0ʧv7~BLY `LKïq)/ԐE FtbamA/EdD/Vل?pbfAI$'دK 5.ט} BXߦiaB??Uo/,JK@wil y7_)ޏi5epΟݙsxJSy>]x`z*NiL "oYem<[DlhQ^%46\Aq Ӝ%_3# 15@;Fx*U iK(sEy}S^95I}]{A4p_OVZp,<|.ALm@oPD`rE#r$EQ-}2Wєߵ// "֡c^E~ۗ?؅p2Zd}MKN4͒M%QJipWW$I;!NU6%8;Q d0⺸rƢb ͫDcbT=4wl5Lȶwc$Nl;G7$0ws|Ϝ5xzg\[M9βvozT*'Þ& _$ o*2+OYR_WWTӬӬ<"v5(Hz%hY#X=y9\=nCtal>*5 đ)CQ#;\?)'58\d#@.Y;c]7]3|IY ?T¿ىw}Gz {"Z^}tJ{>he$w7/aDm%`j,+avM5kĜcS&ɈrY{wKȧ>EfH 0PS8Ib+r-"3!tAP5|)"ܒI݉h=7GE>ꥨ+Hv.ƺ顿1F:@#'$:}GtA[CT4Ut 뺂 mBgX1k@DJak5AHp'!ڴJLfZ%&eҙ_GUU]܂jOJh;1'/X~ȯ}1=z*#y.xI^IimXTYI<$ۋ;Uh`l8'kݼ,@$MaLo7Yeצ6ZX1.h>hk3p43ZmͫJEk] @%}[#r/7.)>U),R ]1o>>i64۬{{5=4tM]/I7u!IzwK)m3SX1*0-~Uɼ1&žޅH2E0]Dڏ(kb(Osr?R]}1io>{"11E:hj^71$t#"TQ]eyY;_9HG \V|b][ʏ>$'w)ECy)*?Qol{DhG}E"ȭw"§#EPn12x'yOGF Qb=V %r|Jkw)+Oia{'Ny sknHwz)f1CNN"TH"4?̌.2=a|miذ4;QV*90#B:9DLKm9f dvT*:KU /Wq$-*ܐ ]S'`6: `QX @ v49̋?bsT ߭ϙ!M| KP/Qte2QC ʦV9N*4X9O+5e`P-k{a7@Yqr" f0Qbu/M:w'Lo<3QP[y-iOsF +ꢧH (cZJf#o## IMrh!H:iéT-S<gUn^2JxgCHW$g)j(sĥ+9ˉj}g+VZcP9D['Ra O_f2_gw6N~oWѿJ̪ ]mO4P0[4gE&~UHT=ep(tDO65ͥBGUHm(=bK\\-9ԨHp4gG6"I4&jI뙾T:k8'))gAz.X&cB eF?:Y^2Rn`W*}\$"f=#DD0"D,'2HSDM+_z o_ սs偫 Y߂c${~|h;C32(k5 \YQO[mXyRiC{$L=Kk-%RnyFjHp(YeOm?.B0c9^SjS x,Q+mSH1 $]^ endstream endobj 1656 0 obj << /Length1 2126 /Length2 14559 /Length3 0 /Length 15837 /Filter /FlateDecode >> stream xڍPj #= <;K Aܝ݃;gws{a e!;#Sq;[gfF&3 Blm9<Ζ"2QCwCY;[5`ab#@deHٚ:S{8-+ژI/w# klajlg 2u|<@ = lP2u2ut55E ghcoj e;3g7CGSdljbkbxPۛm,=0327ܿ `6ȋ0:; mM24v{7t5YtC"9;읝@qb&"v66N' r45~ߏkekfd51=Pb*)ow3`0u7@_J|f4L}@fཛྷ ]MΎ.>^T/gfF [?ŦfwǏO=1PRIM^Iߔsx1Xؙ̬Nv&Q0?fv}Jv P{AhK}rM]ߔuoE.Sm7Y{}r]߷@}l߫+lgmuΆ dkn6A& gco_f 5UsuZ LLG]V}&2}_M)fklgזs  =G&bN`f׋rpFA'3(Sz)ǔcqGQ@?T3qg0/b}`hc>]ڼKElϕ͟{ س]/?M+S;w {[]|o?;[w6 ;?]mgwv;z?f7dv1r:2uwss= ?N\w?±S{oU` Kj1Z yc/U7O ,F]^H}%la3U4OT& -H2y N3*߬ '!-Gץ:!Bl;/hNƤYHu~~$cQΩN.Nu=_`$L\q|Qsj]_ӥ;4 UNÇch]`+$_LTbLHQ_NDp[ukPyąݧPs㘰i@c^ jCW})mo@YmNX[hM83BIX @h?y(Tۿ/[o}pSbʜ7 xc÷Dg#+]pyړ%*귐8Hx!=6J#MI& CAY'fi)ҰUk;ؓc,DRڈ?)a$Yu}~`iۜx%)aݓM?Cjeya{*Z %l,JL.Z ả0Q. M¹1ұՐ L5U~Uht? Ֆ؏`D4{e{Ql3*W]8g~; G|U]qVN%) ):1bB)'ܡn+<9nRh9DTvKŘ'}EL$v6Ihۉtu93I@ytaCޯm_h?}4P]: փ(p@`֖AsPp3l$ʇꩥH'3$wvKL9"#:o7{*"(); AөE Yv3C}nr'tCuyj@Q45{q/I< 3.@3-yjթ(Nƴ[DB~ Rq5L)I|El-2 fz:aIdۋX!4X;zMO\H}&V ~Wel^4`!ꢭ&-vGKZI`SO _eތbnH9:e4= 2B|Ni(pdYPV+6r3q om~_.]JJJ t~&cve&>,DIC7%ZA>rֽ iI*[KT:c>%cςϋ S^ju*~/pP3 DIb$?nVr*ᓯOkI6';5GŐEMV^%RI*eX+ )MeᚥB /Bi}*ůB8h29<@^ݡ%?+gP,c¨ETR-D铗 qwY3E g-F,kt6 M}f+@VJާd gW9þކm2p='=7!nNL%qL9D8ʔ 8?kX7}L8q෥p׆@hAec)S{A{-R/Yë|wڶ˯ ba177炸;HMa'g~g'~F@/ETp#.'k ^y)z 'Ԁjp|u_8=1+Lz@rBkKN*?>H/Ȋ޹Ι͐*?|la0i%'(.QBpSc`=K~N3*,KVE=:^`b/Vs⪑`lS19X%'|ah1FW~>H7lVv4 :w۟ {1I{>EpZMׁ4}֥9_ٽ4diXY ݖȜˀ/ۺbDZY˵ZkJq$8AY ٍ./162GCoĻM;z+stԗo`G)k=,1z}$ijqE<Zپ?l%Ug3O]<Iۉ37ཌྷdI荔Y}YM{]e0jX0O6Ī|sC|ӯsJS〈й^{r񵉢R5?3-2Ggah5Sj Z'D`7I@, N\2F.}& uk%-i99)ä9sVE:B<;y i%o> ׯzV"?=PW(_i&(lgſ0eQS=1g}NA9!"*A%tJiAlZj`36j`KO 74`&K )վ,m*  #~qvTp; s.#B8n푚MWGכt2$YF-w-2=% AU(J^fNJ"}JM:ao}kI*!Z^2'nZ)5wNQѧ qս,FiG#5>SRaN;s8pEk52^B:`JS4QSzz ~5$#4^0azۇ/4 턢Z gMbBz1e!A}WP7nq8 "׭FoC[PLI)%z8!!ZKƆp$eXc@nj2I5:*-Leh8vE_ yyPL yOhӟb9u "YoAU^i7"~ϫPa)PBu}/^ 0WSv.HT=2ޒ*OmbƑ=kѪI}"VV,?fv3 :z6MmW; R}vŚ. YD+Z<燪+߾`b163\#*軵K6P5C>5l84tR= qj若+I:F ג1oC-{^TT:jNʬ3Wՠ [o߿zܘQc[½G<}䲦J_^>ha4iU? 3UGo?ȴV,x|竉gI}ւ|]ݒ^Ss] J+“c@8$F(\T 靟;^i&] rĞyv5Yk|mNr[>W;%/E,=k0~}#Dzxi*^ e]^C@i$L\upEV,t4usIjNa z|BD94AWh*z#Őnd!mAjkBW^RР` = *]:ջKi-KrA MSZܪ'=a<K, ]SK!㮑3k3>·P¿w@M9rX4mڶMQ H lxʑV4ᚰ} O/.o~u P5?=VlO}]3sY]%F=mMmyғx0i!, IQz~#>m־ (ӐGOfRL 6(idg بlHcBRWIXౢҳ+vZnFWA$@>obؘ"8Qtzw wIj$7dT pY<,`1`Jf*k>U:mG\Wo5{4|kAm8ft'bA(:MsᄔŞF: MVOkHvb^޲̠ۃ6T8 :^y/򗞚MɁ.EŹne\y}:yLKY)XA^&*0߻ ?V J%odRHޮ=I߅.Ľ0ZBrSxXq׋oZj+QYɲQf:4ܯ5J1~!.fؒ~⭝Wu46vn=@笱25:>o=|P8(Уd5:B*?KtJPVmےU}«N t:һ?d]z^*-߭ nQ[[=b5.ޏP6QFv!8scUq 99: ;$@uwRERB>Vå[%j)S8PoTi+ճ`a UPorqqP8U4ǰ3k%[h -ycS ^_?pP 4y'\=y\U{Ƅ h0r4MdkD2r!XȒ>fOHrͩͥz DB 4e-@qR Ll+=G_{51)LԺ2iFv"UQ 75Cįa d[]71ށ|yP0B1w(-Ŭ]@ro1u׍bqm/&Ǔ$|ZUɇڳ=#->)Õ]|]&P3(r[ \@ݓ L/_j8g0u R`1A[ךFWMwgPNg:ːm"tދR峞ٗ`9fvbwl-Hpav sF0 U]C{< $xǢ 1iNIwtE G6£|s;eʈ^gqz-B?n* gW1${>L9J2s`:X'$k.υ84,`LZ=}ױ-ru&ZXqpf(ƒr(6$4;Emf/ꣻ][m\~店ED-j#oMӕzM2 wϐU;G^tj ]6!NnC3o*mD6 }8FU33ɼ՗ 8\xښ=K'&*C(,20ЉCe8ƄA¾5 н/ P:prT0B0zzG=i-p9&_ܞ GZhrSz-_3xpB9%sU1Ix.G|xuufvyu[߿]+F?2,**rIFgżU2RϜ,uyB+,ٝI[-w|7)bdPERΔA.XUQe{=a#WB`>|m 2=TYz7MOCr[eޟ:wU{VJSvۭgʱ-w<,5P{qHOnKDwon(ZGpV@~Rz%S`MV%ڳsh mÅIz%3ncWd/az$DF)4mxש^'_~5` fJ .gNG4keNܹNNז`r($FO AgdNZ}3[$UK 28[ToiY1kl%9)+rRww~8}G>!Bj'Ss;>%_ }%h /~}c1^rrWdDS|Q8 PdO ~+&Z=x9?>x͡nLd:n?2i]0mמ ?_/⩻E u'ji9z~59N('rK";,aѪ,X:hE&A$:7{f.;uGG􂃍gF='O\\V){Ͻ(@am&廻P3Jry}IiVۏ9(Q{{E( ^h؊muYҕ33F;BN|!%́VAjecXؘ'͌B7}_X%9)oa[l (:Ǐ;ƭ*(0 rg}'rW0}#plCRh0EY펶a\KXVh|Ԓř~kQDT\AQDTH|ԟ^Y<8X>6T~Co.j{ߢ4m~m$LaD'{qc"JI?mxk<>tiK %FNї~;`  L+$;q1idOc1e RY׸?m/xa]zGQge0{'&J4)LgmP/ 00 o$5?~T5E p7{&VZediL6/||1U_=W*[d1mir?N(8p,۷Q>,݊#Zo;NP#RN;$+_jUSePN@g)tkc/ y#]/aZyH9ATg)`};&&wai?x BƻTRZIƭwM//s Ql]yȄY.2êe!{T~E=ѿ+@@m̧s#"Os|L$J."D1d+1ٝ̆uJh}4BԢ=cNF~qϪrIdz4\ZX-/m2? bQ G!f6gmX=5-w.Jŧ3/#񍣋}َ;TF78p"LEDafK ~`y0L6OFcE'M '̘&}d+ 6LEK0AAQ4xg9G)sYVJ1! ^ "~LW^uȲg=եg-6U $#t.&jxi)ݟ-!PoUrY;p$^Tǭ鏩/w?̇61zPUeytˣOƦy9a_o 04qoJ)ų\1xX>+5Vg M\:Ph`I7?(rmBl>>K ,swZ$,9O/:3*iWGɰIUĐ~InyuTU0迃I͛ܶ? Ua bNůTܿ 23]]nR7+M/II~Y32qesm L^[WV*,Zne BfBYŽ4)"Odn/TG0jK%FG.xJ  yfWOx.dBrbL+ߛRsn3iaD 5D 4saFOeadn.N|4Esmb)7 yh]w\q$k 3%Au0 iW:6|7\1vqef`>ν;c&=W1K2ǷDw3Pfh.^۔(XAA#AVrSv"mcu0cs!WR`#,^c)_48y@aj+?n჊7UT~,ZcTILDD>-=ZeXљpۊ)̶=32YIݪ#ӏ;Zg7WۘqM52]?3VUO]Nro]IשּRCFEhJ+qnGvK=_/h"cRWvmG3I&Fs=&Vt?M$j-],`AXq6#޺z~#},G^+IW(H?.'G],xL>r%UCn/XnAuWuԌ:C]cKmrs\ϭRۉfrV ?z﹎"y_Ó= y->": 6"4/oq[#'ɱ XP|B2ɶ~Ifl]i49y l%Z{Zs%0{^VI0(Fɽ\hcĸQ33G:;W?Yn.0,ii:_Ό ۚHDAalUr/(Ț If$s).3bA|QfbʉJ#RY;B VbMU{BFա>~کU%I!+2*}H:!$xQZԁ<+ }a .^s%ՆPGd lø>̌1i$YCW5GWK.rNNFIDjUqrSSpi/Q>Y5 O+61~Yw1M"vvc۝rm1e9AlJw OoT8YUNt2yD Ygw-#dN{& xlUk ܘiÈbC'yHJc)n#{a ^\/3 ;Veu(V U %#z_Vf?Xy ;_cQpV=cLfr< Ӻ,: (\iSݗc7Dg&*V;rc:%$dhc9OXw;So_ba8{4i[yuLM/ yG-9:WAxYN z5Hթ+%=Nhټ!A7;$;<| k0FV8-=%C{%o~j y%Z}|3fd,q};bfM/FDzktu4:)+E9y+~[L+Cz 1o:8ǎ?ہ`9]Jxe\UpjC€a_#g%E~ =زeU7prC1MO:x);0 `vjYetyk>?I@ f{saA@- {9hlj.)X8ޅ`ZeUiۗS&'qZ8ϐf KMvF˼3FBeY`Re;Y9 G0}/.uYGO6hN }(~ۂޏܹ?vPe`m(4&q (aNs{,ͩ-Yb/fBU~PAB.Hhqodo٤0 ;eѷyX4 @2>šm1c?OnfZɱ3dtY)S)Pg4xͯd.;s)Ll94;ax : .]}zů&=I2'7Bsp-C)j&BT:;{ZTh᫶s [nRI]3['%r}1(WQIFpW/wt#. :*P`_\2H)ÿdqwԌVHTSeF>9BuT߳(k$y:9I+hk7 U2gnJŠ>NX""sʞ;':f)M'&'{Wql4u ;[]/YOahײB7EJuW%FPrYWE>ܽ Kb&BY{A2c3RyǠ%>Fgud:ף)+r>VBː}y/ۊW˺#ƶLF0,Ly,]敋w-:l _>KUp># `G7mQ@z㱙\/޺gX_n V\g;PxΔ_pr{R;;Z(2C㱦HC6!7PGm 륳H䦇JqӜf)<Ձ-'t8KMlIyH(5}q.C}1 z}fq:m;cwtXw!«dE!:BN*t)lkNধ?-0EZ{M~ۥ {`"`xqrt33|㹙"lqUSVo{Ɩ0kZe3%RA/:9*XZ*I?rG ӠJ>xW H_ „_ClSr0*fkD\$~U Ps>;S{>㉘AwgI[+lYX2=| Xf 5fRa (\G}E戺xɒ; ")AVis,5ۃ,\lvɒ6KQ"rj*frfXl`t I9}k~=]+O}cDUbʛܴWRם4)^5ܶg8d7UP2XIҒɥӞYCK q) : C3ab{)^uڄET5vBol 6T5Hs޷ YV'tŖr`LVP2+jO'KH5ϚWxU{h#˶> 5Q2?"- endstream endobj 1658 0 obj << /Length1 1535 /Length2 2918 /Length3 0 /Length 3885 /Filter /FlateDecode >> stream xڍT 8T%R JS }d6Ü`HHE!JvE-Z(JIYk̹~~j%c84X:zykb 3? 65a 3],)  gLb<KMdsI %hy5΅|W@ Dcp r!*Rt WR' Rh| CS<4dA|:P )Llh COv ? DŽh .d$$NqM)T*ɡ!V1@ 6K0xl8J0aw `gP ȣr!A!1iseѬL&@\ |8dX` ĢB `YPph bXcc"J̖ sNܬBas@xP"G >7F7Bp `Bg`O K XX8;bng{?^++ ##"`D4q@G#+ v C@׊h"a킀ּԷ` T ~.l[n.#hb 1Q`Epe7u#s}]AבO’ZG@c ?4wOi{v tgُ u'!Ҝs]֖Eef ohP\J8 + oh_=4P0'ffp(\YOd`lA8c?ayd`\oF&It8I1=uxûUg̭o#= UnvWV;_&6ܥM\>3 ?`/]ʩoN.Nȕ#:Zd w?GϽ߮WlLj݈;oi+Oи^ፉn( 7*+ G\ȃ\,d&!MvtD/߼Šxؕ4NοG`e%ib8{B׋@La(=tE)8ZYdzBFx;SJ%jG 6OBmza'wK{[qlօ:\l[L|μ/t6?%joU9k|.2Qɴp0zl=cӇϜ%d~w@/ ix(Ou{TҿS'HZqǚӎa\*& 2uJt/ij^tzNǂ:[om1(9CFv M9SʦMFŹK᥅y ٭z޾+'R;sY<:# :hQJZ4mAkv~k5M-ڊEO/UXuk9#R໸nZ/Z9 Uu!}aEYfKí~y~έb*3F_ĪVTkVxm2S=܆A{}$Zɮ\9^66A_^T>Zz۠2=xla$sHc+8AHdྏ+}/ gQݏu.4m.o ?tצ%+k,Ld]}NN}h0j[Ul =z~ŗƾ!@ T[ YmB/{&%3մoS* ZCE4ɵګDlZ!)B0=M,[7Z %AJ+peo|S Di0icUT†K!+Z [&. t5N&ȅɆ'ߗ*{b5U[`o$wm}"Uы4 tIY/_g»bmbhT&;6V-)p*V5"&ק[/l[`s'r` &>)٬UP Z#2ҤceX~NQm!m$"" >xcX+ӰFW*jJ߃!H5&WSP#R/:^zefh@3G;\T:!Ry;8qFOU̶"vEK d:kiIRbtX[; ^L}Z{!oޢu+EuU dr,S)揮5Z H*L:;>L~ūBLNH𔟪NZ=-䧲Iގ+rvAɒ#4d;Xj~(*^X)Dk\MԚKg?B4 nY T\uy\BaȘY!%{}wN6Ikd0wzHSQH#3{T؆ k@7gY־}zp^1X{|YЇ7uv|xY~W{g[/:wd*LG*5!痨Lhm=Y޴  7=|зMc\iA|DHaWVɪ9]e2753W νM:E=l<uXW &k0ޛz/i01/g%}-Y)jvHYm;kuEҴs".z_mǝu]TfhuLfKJcW{_˿9șiZY#S dvJ^ݧ[46G7cUz.ۑBSMk"z eTwy2Q;wݓ{ԏ5lI-`Vb)]&6_ݨFQۊ|1ǃ$]dT?'6~ƽLw>cc鷸ÄˏNlmOՙ1 ec$pwteWn@8Up}=ڞvVvMSˬ1*5-C/j޲ =x9PJu.m4j,B‰31X+kՔ#:DB''*|oJ^^N"= FzY3{d=5o"VYV>65pGTYÿ+)Rb5Ɩk)KgF2/ w endstream endobj 1660 0 obj << /Length1 1828 /Length2 11885 /Length3 0 /Length 13037 /Filter /FlateDecode >> stream xڍP\ K;www 4hpxs=1sjwj "f`$Ή `ffcdffET9cGBA`;?" @cK l`app23Xyč]@fF,D)w,,^#ڔEW:@,/+ trebruue4udC,i 'K*q~ P4#%@C lj ^ 6 SKxY&#P,w=0?ٿ J665۹,  @IR͉`lg;ob 16y 1@RD`?9B@N =2.vfb`[[#o~ eݙ9\k;9wfLv g?1/&m@'377Z2^@oO{= 7h8Aޞ:!@N/f! 7.X̿?}Q𿎘IGKFJ^<X fvn˃Q6\;s0w|_6?]?Bb*]J'U_I:;ol q'EN/c~{vf gq2~;I332m9J܀f 'S˿e]ـ`GWK3LkE_F鯃/C<$Lf` # x/uN/)`068LEl&;I_ `/yb/zxLED{,&d|d|!e0//l/Tl/g_hK%MB||Y? 3?K=? 3! 3? 3(y_#"^@i~ldUq[#Bʰ={v0V`'1i W&9EKQʏ ϭzwkR] RWӉ7of[RDIx!}Pđ݈Bf}j^z]pJ$d;;kJhn: os\ٰ ܌ OU CJpX\J%_%`" So8;|'_9.X&Rf}4)u[﨓,̣X=1pD ;fCI_7&8j{V*7eC{'~9˥Q+$s/oj%+fºzҖB#gk`64qeoprcf>J.x0 8ʭ < F*Z9n\^jPϝfL"d[Ov~!s8jA uYFwf~ݍ3DS :쎏şjdб؆Aٍ)8͔[Q]*f ^fγ_7i.o*^t* T4Czd3a&(`b{[/*B |x By=AV)gct)/u@[o~pco9TX?d7 HMx>jּ6(݆;.)ꛂׯ/NG!.Ֆ_k.t](6~pf,+)¯!4hDexǽ,e d>6Ԭk_a*g>M9tMXߐ։qs%@IiZ\Eĉ~mϪk5"5{]jҳmdJYm"uOaT 1{Qa^1(.u$ҧ_wqwEBc6˪`xIs%Л%9%w7L UTW(&KgkVu4?kav{-t7Zs PW~;h71Xf)+F:O O!h_VJ~$5"70!j\#OcIsN7\bDw:WiizZEd_:`MVUǩnuj^7 } m"$#$6X1OJa.CkN(6ECqVZPVդD ۥ]!^$iFb|_uyo&1kCOJO\xȉx0ēWoWQS̠.&a߄ml"ލ8:Y2buh$ނ|"/J ES[J .M.A,kr |C)WrA[5zX!X@YUwMWNO4Ⰾw m'iqx%Z ,RfDHKÑ!y<`0MNIXizf_&k?NrkyyM^lz-49Xk Ty̳-ttu6>Ͱ=>A5P42b08TֱzdϜB"q:4|]6j7؉i9 6~1mĐ@SsB-08[ q` ɋvE4>)WEGeS-f-'JQ{;7!+5I.$tK^W<6^{|NَTMR!C3EmŻ̮"89ɬh䏔pіH]ǞZLw*ZȀi?źp]6rYxŰ@ΏmSX@Diqו>çUpK"ܶ"W?`:ȶ}&J:W;Sq[Ť|]sbtLmuZ2!CC}{~($қhYO\VmUݿL*YUȖMl5 Q7|긫Ӗm IIZld$ I|}> ~DI]WMԹ?jZjsF]+Fw<'{ q1zDYt-*JlӪ6(ӆݣX:O1vok G=R_ -i3[A&SŽnRό!J7!"7%qԗ:SQ]w4Oj/ӳ3f"}59r y>N|[l $AǧgpjKg[`C/> bP+lDG^3𯜘QJY.C"ʟЃ)`hyZ->)e19shudG눔4ծn`0 {(9{S']XOX>X=U_ ݣ/7|! o&][]>&u ʹ9}3t*&܋529D`G"^-` R_țCM,-X]PY櫾mp֨.2hh1jױE0ѱ :dXWRDOyq䊥ɫkcf A 6j髓 1XgȖ+'LhaGN">i֪uB6] u8X[OPʅ7 N,1sLoMC=W&cA7 (1:7+N%=Pq+KƜ .gKq78`FBS|xhC˿sp&_Ƚb\R1iw߈xDx((2i9-!WI|h~Z}%f>7ROicP+,[Mn2JY\WgYl>25_y^]`t+~:X>XjERB` 8P?APOFm; x8d]&"G- IEIEI0u~toP^{r#i '* VG2o9Wщ6g,J;1eqqdI:!QݛWErBRR/=؏/JR1G ˝Ԅl^pPKJE>竷:|:/}CiA"D*qTQm ´uWc&׌Xhzn 2$n('ơU+]H-\O|(Tj1eSAiqɜa3Q\YL]Ni|GHLn&lݚ|92AX-KRZǛ>iECHo8D 84bceODX u]uH nE:6Z˞k]ud Y!% 8wN뱇ie8 VsvB>#eS"dLER[B-oX-B{tXAfKQ4+\>g,| -b-H(?ӭ}ti.B*HVk?'~ANb1ǀ lP9Ąz&5]X)E{8G4v5k_j_74t.U'w]cE/DA|x;/KHq:2\e'!۝ጯ>I#Ɏk 'QD1 | |ԂwX@(9p{N Ca^p< `*Y쏊s{V8 H/L߫L9LàFVQJ{pqGt rhrLM%8ek?c`':H/J.Ix*|_*UZA'݃)Ub=OڝkV/٘L0{rhnǡeΕ._ȑJD4'~Y ϊ*_வv/4fa zfKqR  ӻ.zq4c+ z]{9ҴH}h*A/kV@ۯEHE'!{ ,bdRo s7Wz D{(윇6&7X<:|FZok#xޗ3^'9RӼZDM\DA(ܐCv9 {sg +/Y p$#9B>avHZ5b@m̮ĭA6iьESC$Zx889q\ƨ6.Y⫕mm|w,U_(BiM""n6*NPsU8|~%^{od4߉S֡RC\8/eClRk* ,[Yjv`Rl?(\ Wisk ӶpGf[rGx[ϊ*4pLZsR5I^mSxl@0I>x;,cj5=2!룝v'/Hŝã2W𧠄ޟ$q$s,Z3S7:' Pdr7b'EP,rCޯh7 _pKwћ4+vgJ.E8̻"O// \9!\rMG_w mZ:#=!GGAAHvA ) 3cc!=rU&v%jZ͉R^ܦ\ %̀aAe񙕽Cf}fQb/b5o#۽M\@!g@dȂ 3^؇sYݞ }@eķ7L=zV "n˼tMXal!W;j}d^8pηjl*X {nzmzm{egW\rFy[8BfIItˁ ζԐB,*ٔ.9rpez/Ns*KAx9( Ra@H'f{Uo g~>¾y7IbVtkb[ ݝXw4YmIM75?@mᦙyT/s:VyK)ݦuiò;g/: ʰn%O_YNkIBRW d+J.g}Q؄WqRT+d WDƗeJt._HV03fڍL Hʋ,>jukآ!i|ak,ye }J^= 9"Вbh"rSS~_h+YָlZNe&-Tww#Dzai?iO;B ZwodMEMF(Jwp rp7 hؽ5c%p̃ׯgGٕpఛ 8h25 hWZ͂he[ICwp7E̥msGJ>+ c2E Ⱦ[ ^s3zp"-札КcOEXLE\o"a09gWշLǒYƎ~f/&zg3-H8ڙa.0 fhX BRQ'j$ɼ3NF1WJ A[h#J^f~쐵iE 'ͤS" {ASPgUЂĕ'K׾p`\8!ӂ0V.QɯKx ܍F&iwDfl#Š1#Iiw/s,2MR"q!,l~5!oQe}U#s51s⍺ rES:\n\O:zr"OG_4?^zxxאu+Ϧ\Kmt_0HBVM'_2i<=YZxHj[;iַ7{ 1"yp*8H4: W[coo09 +CAL~5C QǬr7:K/xYo|47鱗=ҶʯYr*:M,| jOtz}ܨҧ͈QY㑐wy"{|vك&AűOČ/ÜQ@=?,jT:LOrŹNgfzGA9AŤ gz ZK?#lpgT#PNExSxG逡srvG+p΢"*zqtiKCiWC,8#gK;z(ΦU5%OeeI;zQKX7Vd^9Ώ+n/>tI蟰`canD Es񮛢%OYc3 4zcSt|ۛԞ[1-T'$*t$ݖ%9s7ND$m]gq]t$7cp~ήq1g8vI}VkHTe_ #SA'jqFvϡSqf#Fd;x|ʳ?g•$tU'OVoZIbLV7XG&7CS=uY| 3+n/y=YA>,#=‘qE/=끪Z^M)19jPVl&Yf}AU&y*6O*n="-m@՝_!j*\d M G\L/3ItLeLeiHg\]@Wܟ&K]F1vUZ3\"?^/#NC 3*0_B=NI1otFN#KnO6[`DzYI'NQϣ wQ\3 ߇"R<@2JԪfO?g~WXQd&.{Q`}rH|z{6q}>[!(Db'fޣ#6""\ԪHXmO7Di4|̘͟$_Լu\Կ0Jk#>/#}d7+yE|zOKS&"{6s iozH*j\bLP~vIFq"Ȟj#/±~)~ƀϜf7be&Y)p#E&x-O9V$n`oLƾNHc4UErWNT!bfz!py^4#} n`XVcF5VGN͹]˪C jsxcCL?ray(B~xHGx% FHzQeRgOyvk4H/4kU,hH%G4ᰓ@CadԤ+ΐ$mN$Ck`LgdYH7c!| cmVSȦ9n҅(f@ϗ jD3X. C RgXMvH'~O|5  NR[]OZN %n3y/]kV|ϗzN]&PjxNfDvW{hV[yo3JI_v:zyж\)uV=F z 6㷏b4 \[``ɵU{+Q)!f3on/}O\F]G)r3\,"|_ endstream endobj 1662 0 obj << /Length1 2713 /Length2 23778 /Length3 0 /Length 25295 /Filter /FlateDecode >> stream xڌP HwI,-!))ݝ% Jǻs~Gfw~(HDM Ff^* 3BdG O tqvt@hM@`;G `ef /@utS9:yX[Zi@mF` bt63q(f&v5G3k ?!@ '^&&F{WFGKAz5 t(ne\avf@W9NP(96ۀl,,W kML,v@<#D0q0ehb7q731U @RD`n\\@vZdG8_S-G4vZ D,'\df7[k2;k - _* rR׉rpL\\LK# ́,]m$K70F\&߈$$E\&߈$#6o.F 8oή/gWU~#pv]7b0FZ4~#p-\oE_4-M?);&W0Ǭ]m;MM#p.&f@K[W_fh&տ9ImL@pJ 77qCȘY@_`r`%eG6w-Zy9Y nޟ8鯧1b5jp'+?<`gG_o;9v[7 »OξAP͐_e)ݸs1n=z2I#$3STm޳8 >yq5Z5ʡ}de; 7FL#R%V( P5-pBtZ&`{ `I(yepMXr`VVP ^oa2L hUP~#I(ϻ {||ff]nSlߋ~hsv//_$ès$"rVcTj%L،^2R=;slxO55Z?r䩐lG1 \o^b8jޝ{~P ɉP tU,%LSuQwX-u/%2T }r} z#~6ִ+RC |H]"3jlԼx}~K3}tdxrǮ\ .dn+0jM::"iUCn:mpx`Zu;3ر4 *}Ue6!f;C8IUf'h~$PᛉGOY=rTKߦFm[WR&fM˳BTe*!~g?C9Pt&C[F&bRD^KȑrTa=JS2veM 8zG~|8<9JV DJ7#xX{qW?gMm׍T:uhM7O.یwxfC2 TN)TaǃG{nyXSZآp'>3G,L?OHtrO&n)z˿Nbyln8*dQsDO%aqxY8ou.%Bp8.=(*3oxqⷩGdf}),Pf3X0_:)H{fqM)R`hS^$%0YɰkP`%Qg/>([ɰD&k׆q'HQwGUǡ6:e* 먀`1;L׎䵭X]m~c$Vb9aʀ Nl`""e07!էe_=-ݮ䮔[V=)%J෧IzYm`>,hL U2]9q]z2 ޘf8NJ$u嗟w!xE`7싏!tv>p7@ُF8lk&xXFUYtKYhKc+cM|VJFakj納O!#W(1*e[ӷqsZf JIު>uh}X4^BҴ_243tg®‚S5(t,h*)Ļڞ亚Hs@{];K g! $]Q#JA\F2Ad톃{7JrovG>%~˥ܫٙZZ e{jz_D 5 M.trB |=W"AФ#V.r *1&)↘U|?%W=ŗy8`$yO 0xo}2q-ۗO[}!%P_xb$C5r{)T$ {7'тK>N(Ƹ򼇤2*'B:vYԺUL,8pٟH, knHJ^l獰K>ͪuQX%oTKШV$ ch7჉*JҖ,[c_*͍(k[b+T?=8qU DW?& !{|}>%9"MUS/"<"~IJ+x̶s@;С^2nP﹠v ^` JV>:If/{x"^GN~m6tX2n$_#1}L~me7=K y˩'oWkP[o\;a y"G1j628 :Z*3L_WMQ;}FoB@mO޿gMj*r&0zU} UϹ=ڐ&y$x3IKq-=H^rHR3zQt, qR; ~cd;ĕb5wʞҡXf1Qu0HDp,\=nHN޲$}>1P)qdm}we:lQ쉥B ԫMrk %V%1Ĥ Njt<*U5$T5zYk=[áPX {yCk9Jۀ&U#qJ-YfrX=L~yۛ yR$TApHJ[ Ey$d!UlC%KzLo|1DU'ErW9 ]ĕqMv_UKsh:2 .b^Q!6AVbzKP3K `-8PܟhN|ʗ[N^%A1 7 Hh;j›EL Oǟ8JuT6Iaq(T=9Q pPeIC R Kӳ4j)Tmz BFOp㠸\-W,wI݂9v|Id{U4ےiƍB[2fjҔI/0m@wn w[%l}W&"$^^m[Stf$y0ILg#6,֒ҎoJ'QY(N&x{ol魏1D'8R~@ltŷf2 nS=&` |u Pg5'֓᪮ r܌7&eu E" /ca]  ɖ&t|l|^VPe?W=R:I̅L9s27D:R2hZjǔfb !ޚ^d1dۤxɝ*ߞjTm[ud+;QXmyAaCT/( isujrpqA?'X]K+r>H3;yRr|G2.g"El"tЬW{.'ώ븠捍Y4'zZH!1|Ǥl1)lћ.t{S呋 AU+6&LhP |ֹ?8 Z:CDӬ׊<[|CcGN ]S.^x~_:z`~Hc[WeXu 9ߞ2ezM>@ԫD51"slB1{R$fjoP!/rǯ/eLRh}+t> G 6q;1OR=@ (rOW~3ǚ}R(R4[jX t$}P{rdG:=^+M%ei^ X^ itd/NML5p:֤h\#Op |˿,1UKQ遏x*?+IǝΗ[yP/Ot _% P7H:'zHieԸ;u*al)/"ҕmnC_DC^A[!>Vx'1Nu}|s c)%?KOU&nT\=x i݇RvwKT"^ Fde+ kYo+ oO4eg|[ZQ& \"p #X>JɋOTド$j"SnD1N"ćBP ImEi"*Cmϓ1o)EH65Pi:jP7AU3l YVWA]c^΄$*"euq~J̥ N!uy3=j]+e4VZA͒VKh `&B<u$& T Ĩ뽻ھ7̃Nu68cq$$vqIqT3P6:W;(F(9?i)q0(&ٛK1įٓCXk-̆25iu!5amǤEL$> |VL.نcΪO| RQMas~$p~J[MC_uAEVATY2+ct.ۚ$OMN ms{~Z?32y26J}Kئ)N%Z[+!H{tc+Zڑ/Ut<Гo3t[/hSzQk k[@m!,A5#r{ 7Ғts}S<"*t#xlCI}^>h|f͚eyY_z ,鯫h/GiY% ~r|w!1w o 1#aOsrHZ=$-pڑk5%z Af;JgN 9ۑ>2tÔ$ӡY 2ݧdt.}iû9a*>NpjzHԍNמJ&Um"ANNHID}L&خFh8%~-/(ԴNtҊ!loyKxO+C_ms2PNZ 6LDщ; W,q-N$ēUxH+SH!7PXҽZZ@*1+4$~ft$0a]̗3Ǎ=9JԚ|yyjer aM+ZݵIC#ݾ8l,(3Fٲ¾gr9P B$%thފ붇*3~N˵N> ءoVi}I/1s;9!나` 09ab#e {\($\e%s\`x)'%9dFk_ 2l-PF>&1J{RU  %KX~6r$ vi }P/dE6:Q&ȑo#a :x{1< X1Q(J0;|(}bTۜO-*qo MK%(_Fr@;˿E>RpZA__!O]l=%k7MT`F{zBn΂cQ0VU|(Nm x,] dW`+F4ٌc5cD_fa px"%ΐF|r?B Kơ@<q+-cۨa21R>:^gCuyײ%M1A ъz-iGQ]GK6octՑQV7,80elVIʹ7Pصl_?d4G-lg͉@ '.ehVtޯ Q ar-`_-%){UtYum1Uaqn$6-O*r-\aZ R?[l>0]&D=U b&>&'AjK`*2G(Tv+ܣ.21}[Z$Ka;oLtWD_>!I9p:|RrRc+ߢ{Bƈͩ1棋F90ytV!,3"A4)ٔk=w@Qu0{ Υ@9<_mZ-i9m-0 _̛lcM|jP0D~&yߩ\G>zJh{sC -Y&&#ZߞQN$^ =8n{kR'a/+(^3ȶm^E򋥮]əAE4ل*Y `lxYNI<Ih.J äո C  NktRq%u|lV!-2{J?b7H0].21F).2H:q%o|'Ih2(a{b[5S_:VlHm*L  FA{ײl3򮟿F;]Хoَ_< AB|q{8!Biq =E2I^6u!CSwd  kPENOtFx$P% heCQ32WSlUON ؏^3$^L3;х2n X2 7YĘʀ#0(8#w1]ֲ<9wyX 8:WXerފi.}Qٲi!'!"`5~,`|/mZ@fO(RҖW۷"M*E\GrrLN\^4ֱ/D+G}+#.⬓l4V%>TErȯR@6lMyk^D.Yf;;2z3B0t?=<.ոVp 9+i)/H)/`so!bl'eI-n-{2#ݓ\EBOb}K(.9I`cے)C'|gW>!dLj6' \bC]_OGhHa,,vdyCP*I#A ,G=]VFƢmkhY=-2ɠ"q'q$^?'%H1b >By4b<{=6\md_ħ۲aWmap/ӿo ikY] #̱󰡡p4)eN{"} +s"rDV,lVkΞb5Z fh&q 55|x=c q'?oqlU!ڝ c  g 5S(vp{9›ЙR%M82  :z 5oMl0MLxR I*ĂpsM^o \2b_T[iS6^nys>njNBVQ-Fc3&1E^lnvҽZi+ݭKMNt7$\4n(lX( ]YjP^x쥤IjmBsB{ Ĥ%Q䴗N"(#Ԕ'=cKșP@E2 㬉!.[a xekش8#rPrIҊ YCC5wJš!3q'=jPLWYjAdKjbU'[ٞOA|f~:<~ц-D/|M.۪n Mj&W`BqfO$SJ?ήFnȢ]T%i%⋼:Y%$=-6|d%Nt/" 8ˑJRBM[2EHbl7ph2Ʌ.g|ʡBuX1'祟>OѽܫL|: R mBT,7TYOuf5}e6j Ȕ9&:gK2Aj*6"iuɮ[1R!Kh)ZxO< r}dժ6 :>lS/BD]u$PIs`FؖQO~VZ%tnZi >tSfh [0rm_]6`,F{p=dyJO&b}ΦS'iQ&0r=ݒӒܢD} JJH>×XcZt'S$p B` ²k(ۗan_R>HSTnsa2'}ҘހPP!J$͛ gZ~|K4mKcN89Z ,=Ge߹XN͎PDr13ǐI*W(c9xah Cn&LT5btrQGx@;뻢)0cYX:nJw'"El># y1`75(UFδgJlmE{IP7_%¸Cjk[1̾w!"CNO,Ԇ =j D s EQ~t, .e%(i }l\N#j~8$mǿS9BUwX@*e:A1txੴZ<TmN7WĹsgm!zEʈ3 &+C?@KqZ` Z#JqMu|r7XRuӱ w3`1Abl忪Kt7g U"9皛yIxu˕N|ݤcQ,~%?o `mz:ڎ v |7Ќ$Բڮ X/\KUS;'uUT{k3z7~E>bb~.Ԙъ534+馛ua#}R?|j %<6Ӻi~赳tԷ6aQbZJb1!$%Bֺ区@'ә 3S;Qv6+X2XaY͆0%FֽgjG\Vݓ64.nT,u ڻ8syIR"? aš񒊘X*4L#a *Pdafٗ*wZ߈d]8b0%~HKDQhu+~lmg3MU",~ًO\$m?7L@s7m\QgXa<-Dm;gr{1gNk?Ib;du,"Llẋ "t ؚbDS ?{+oGWDF#v)lhe+oz:"h %%؎c-`0y.ǘg3N;)ƈgg0)UY!٘n7UbmZUI8tB!#mڕ⸉N>a4F*)uy{KT;1u7ҰqF<@FE-}k^|鰬]%I6m>*)VC!uޔ E+jTYHʄ3s4B%)wZgnE0v9ּa+'#wLr.\6W?fX k-Bs{xw%v+SVk繮/hX[xIAQsLcb= *>,0h?[bJjl _fS<AnI#pmcShsQӕc~cwIKv[U jtA>)DVk4(zZm!& 9wW_fo/|YT" *XZZǭ"R*gv1Ö|ƛ@v(dL"?'}n*iWh6bhOQ9^m׫wP+6MDǼ+}s&*y:( Lzo+\tfEB⸅;6q,?MUڥslR|f4o'ݐ V Ev;Ỽ*|&vm΃"ږ[Ä] hh#i$BRCgvS?^¦b4-cqsZZes7;P`5 "T6/k˜<ĜJ*|.3m}I\3|4WFu,;P浧)i@ %m?p^)3Q)R6!ZAW٭D˼"o9tO]-/.*{QlD5zXWB+E3ӧϳJؠbE! O3 c! mO8*bCq8;B;듧,JwRl*ܽ* yhR9QrF7; 0jA#"QΈNzٟZ*]/Μ@ksG۞(>j%;(˸Pduz|('+ `^! 4JԺh c7K3cEtatYSOMODϡ7%QipVƔ,y,ܞ᫸:hy@gFEyߠ,ߚ߯(d=(q5)nda%(G:,u)Bh}M;ΖZG@ u^~hU+obeʮgz[|m3A $-z)͇p1D=sTb+UۺI|ҫ߆Y0aEnȗڴ ={2HaDW>̆ٚ: 3P1yCeӯ?][ )}8^uR>h J7'@:NuͧKB UKi[W} U-O1}40Ќ8_Z>f9IX#4ǣ-Ǹ3hWnT%i8W{ z4$lӳRcR`<3KDr#4~v&&\2} ߮bwe,?'sƟRȜ8)g>j=iFd&:mDp+$c*aC5\(L4[˟B(ͰVو6XMϪb#)+[4Х3 3a B`)@3Ŀ)(>X߬OEcou @-j ?׹g-^CK\ʕ93N-cz ]5G1,2b;B3LX ^Nb|A#tCI4C|w؉V?>љJ+PufCn.?o:CsToA"纊TT23Wvy,tOϰ)`\7rvެG5d XL6QYiOo7PTcQh+Idog=N06G` gS^|lzVnm4 QܺJ~EKͳ{#"а")MNz=s2[%%at/Xj:Z9'*5>h" ZW뷓_}˞rϵٖ.p+6Fleȏ ˶UcdqDrخrw<-ှKcyX3!yoc44+q}A5Ɠ&mi& y\6Mu_/4&쀓\y+31 cXfrl} Tx(z?y@A7o"v% $C%=v#ҒҬt].A<* oQ:;dusaf3uS~H:@EG3]_HFJu6ބu/xv7'HSC{[wH~._cYAtӮ$4 19M%OaN&@X7FVΏ %;L`-; VOn0X}ax6Ru 듇%~CYϬ%_#1&@ 6'ep CJ`^MeC0:_e=u'~V.YzO ܁dZ !miu_M!$ ,?{Y5&( OVt ד5ꅶl%]jV|rˬ7Kw")Jbk[[nsLjKcJ f mLtTuj>!vuz޲z?Ttj Xi۵{1Cu t&Z7,-vRGP.ęm w9"g? Ƞޝh"С_swbЀmo;"T͡=9c?[#7)<>F B6<NFݣ߭\CN5cr{ ;))QiG¦K&=ˑ|=ӷpjW'I傷һqu`^cdwCF@;5mֵ)>G \ӱ*ثj4+l ݯZkJ LFh3ʶ2,jl7DqS3=C.;hޒz] I^fc_%0vU&N(Mulx0c=Rz>U񉆲y]<ۗ7{nI F ez0e1-,!ѿ@ۤkÃtُ m}FA*qx.7FxuRtaiQYo+8~x:gfU d^mw? d~`˶ZrR D+[ƕ!i3+2cC=uĿ]cFr.ktvIsE6nwp?ߔA wRy: [j~ QenYgΏo>\=jTq0/R{F5(!ވi\7]IMiTB$ki!#@4v>8K$aauQdVce F |8KC[Yx#={ X-I 1B̗= LzgY"{`ݽ1#֬һyҘlAOբ҆HB6x8]8$h<Ċu_ ,Kd) Qc6t2o1d@jhRP]2?YY w9QV~D܏%BnZ_tbs%B#$8HswU,xDɕo~?"jؙ8tk6w CtFo;X2?ImώAV¬Z"%bx6s##| bY[GaqQl\5'c׎TXkaU/gD[ý0kF Mi!醰)~;r^=le+VK|dl "ZDYpqRMv8vxrԤKBUw0idDʄ,nq*\V $!y(f4HvZ!|b@6Uujq8oRGkIA]09vh-vy갌ocq⫹ C xI!H :RئUh4 8/ח)8]U.KQit0(0VZ2>{o.GĻgjC{~%yRMg$K ޜ(5lk|1L2wh zsI+BvL۞PA;ZS]Ԝ4F.a`5+]mSQEB>f"3,4▿A#0DtBD?R߇`6DSTv&&\rur?gk* $R=}ߋ1(~ec1^Sd~+OYlq748M%[G&5ݸA, +s6Go:Rj"Oji?ʻSxGy!hV0̒&"85^XtuTaM"! ) 6WLI!ݚOd ?KE+)/$Qe(̬Q)σV>3}xiJS6KdzD"{uo{ҩ^JH㨼vB5}hHC$eXb-5+gWm$K![`R@ZZc[1TժSlXKR#kIкv,97.#ǐ3x@3rU}ӗ^4ySH8nXrQe;{?etoG姄V-r*Ϊw ,bQWe}x44ؔ63oK;e7A0U;2Iֺn6G=BD89HDWPg[] ʝwEiƚ4,įx~G藶RhAR+Q%WyQ)UVsVz#zb#RFeN#}XU9[%A@|'B 6F\>vwҕf$cI2D to<`ƓiZ%$m%s7"G=#Zpg WsC]sI'6QL'碓_4c] T-_#{%A}d]BM_Br/\{)rBIk bփs1?ѕMddv.Cn h0OW[½sS\vټGe^jo8WI#kDT9EJ$+ʼnr>N-OO4 ] že ;6ЭAf\P }VN]58No:t@m2^2~ hxbB>zBKLO8l{|yˎ]xdcpl 9PdR,N?oXk%X~s4ɕ5<΄Mp |'QIEvKw7$"ά^n xH yU:&k#)}!\€aGr}+.lJLf1$Z@W{kYN4: X[Ʊ3y$% pFTh턣i^j -!n2u><~!aㅞ*;^G;n"7|h+G l"iJǞY,<GpƮ6TjZVGv+燲*eYaτ}h" } -CPr[pp/ՔG:^Wavp pܤX #)g1DwFe2P4% J{z4l2T8$%HN۾՚ɂڴdNI fQIM,O =JnT"xvJmd;7W fZQfUh߲ C=;'{UӇxrl?OO[ pZ(x*n(!c@ 4>LMގJ4 &.Ns?~а.k5l(zJUAv7<MMas9yн'`Fx=KcGڿ2AC9; ) Jet\ f:R-\ns4Q f)]KjCS+VE"Maz$'&NUG}gKy1q*Kż=TdCVRIm2by8rr=Ëx;6kȵB#!m`i!RKnM'n3_P:ܥ><'߇Ձw3YoAd vSeCP|n2 dj%n:?˫: 1bb[p 5%0.XapW`dhq{6R71LnAv'ܡSD?0Ac93O ||RZ~9NPUs-$f;+vu#pH_3@Z!3]8T* L:-] I"qbݸé C>BxV ȶᒕǐYv?QT=ؒEӁ"y ̯?2؆.ZdAI7;'{I&!4TRI|(}RPZٌ6//~ f,eeQ9ŝR\8"3|XnIe1qn^=!~Tڪ޸|V#4 psC٪ .>J*`6cal(E{r2$`WM[gd @!GP #1KCuYK0N)ܖu/Ľ6Z.B~ǯ3g8GAPC-Bh; yP'CНZV%"saBj{.].9hVzZ|\u`ȗU&'z>0 寐ң#OD\10_3`ʅ9.PTLǞ[U_*h|qyA)yw lN$e^o! GQf+B;1є~ɼ?-RW)ZP̃HKԻ endstream endobj 1664 0 obj << /Length1 1637 /Length2 9044 /Length3 0 /Length 10120 /Filter /FlateDecode >> stream xڍP.w! ` =XH dwUT|OvWL-r+@|<@q?1 p'_fLf#0A?0=<l|bb"\0i;?hcw>MwrvqIs p{ hY9``qӮb ' ajOڮ`w'@qqv@v[ XAAVN.VV'+G[tV ՞ wq8nw)+AA .`(w}q>ެ# @AyB!n`5ſ(&lv`8@ n=>?|͏l@l?~V`&v(?`? 3ߟr:C~y8o7[@/E WBՠ.?} vry-Ɵ6_|J#O࿳4){89fq[9C|" _H @]!.07*,mxF"^HYQG㱐s@> /_13_P > nS y^N+פm<`wx `o ʢDCCXU{9g~+n\TڜM؅\۹*ݝ߷&d_/f:1?L|k6o܎ث\!SDt58\6VXb;0yyBr487co9:DǸ~[q U}L4焓3,~idK~oK7a S)|Nl{ZzWS iq6 r^db1Ios7NEڭݹ N"BzXb{7l$ z$tAF=XGm6&6p-hڻvr6 ׽O}g#=v9d~r9SX 277Hu+bqR&m̥kBeL*hh}aް =vs *r.qaŃ\muhA *z|u+RʇmqŏqlEgϪΦzΎ̋<vxZN)Dy O ㄨ,ĚhtpP {FU,*qmRrB"vZ{Kkg5<8 p;Yx>K eC~-閧Ϭ.fv6\㎥\BB).+/U?3^O6$eP 5M˧Nj8]REeS5ZGݾa~ȐĒ}@ *ȖD#0Eg7kZ59e z@eQ@F<=Ģ%p.?]u{-F-v=1Gda6&&1 ~![y_^ K!!a'(ډ^+Z!2ʛ\*J)S=gLĥL?űLTmEK(zo)ҙIڠ{ڱnU&43KfJ<]Q^*v4A]XRu )v;ds> ̔&z?cF)f]h4+O9ŵy'-/eC 5Uccc4ZS%K PI~@K/y(>If#=FV\Fk3uH_S\jM"p)4~|άzğ/IX(}Xt0na)7[6gS.N/. +^[K4,R=W$WFW:d(eO:OX,{ù*.b} dAz%Dx=^JVK?[!9T5ZY)3/5 NN+F3-y%pP9jAZG!)O>[y ҿwa!dFf5s~\@_3"r\Lf1:  ?jE†TJ[хYJ) ³1µ2z[!`Lh=1dkWon51~Ko^뻴.T~M-t0IlEu.M-/-˛}Zހ*޴>y;oӅE& 0+XedQ捎uXL87$1d\5d2>~^f-"VJ74pzx=O1䪐5sM3ckU$m‰QeB0;n!FTDm )O= (eNj*mFP+++4=&͠Ei FGJ#p;b" *28MX=/%( s| Kނv+BRy(3}hYaTH\92nxn7=L%mÛsIi_@[v.W9rKbwo9ݰW$e!x9HuE|O* ?5 6ѸI_$j>Ud*NiY-̼|u\T-F-O0 aY8z""G2v[v~'X)ֻ;CR6#hkE [K%"r?sKRZ3JdO|h'D4%%`|r+blLn&jMM4_I_żǮ6c#̒>C@+q..to^+YYO=ӏD᭙kڌ ht{vau+$EIZ}X7a{1k9dX-ڔ5 ,t-%n&ԸhS41X_[TK|[JNH$wpjR m]*\ ?@+ZDXJRFToeV)]/}p8G e%"1g=$FL8mv'it3Z?"B ڋ ܭ7ͼl0q}Ex;ь:vk\y>xa@I(C9-eK㔜'ʞF#(e|&E#q?MCbi"?t~mvr EE#uS%iyߐJ Mc":輫rx%8ToC {畃fxt@>1,)e,cHAaˀxmW 1'i8tv=計N.w ̾RCLo =$[IԅT/&'#o%6Q]>:xwNLm @\"Zv ԵHEGyKV % ?WqHd阚5*͚uǦEy8詼GW0 `AEhG?O=[ ъ ҐՒ͈Fqi[;i:c]dV(2L]D=3%X*P]aXP}X\E/WJ :9jz[LPpyf|*_~Pe<`ŝixmbI'5m)~) `$dž{B]끇7~- z#' tǣ/j3m}ݐ 6#PCMk"d9Z̵;lX>ƓZR1Vm^$ڥJϽΫNIkx=Wm0ٴk[k˱Y&<@>ifB2=GOhʓ۫cOo9>,/Ĩ !(D]UE72$t'U&A{,WTv/0E{㖾"b M~ K3='L>u>75;';ꈄ3+ IRVJ䦓*M{ԑ;nrg"O}E9GR]oS֡XwsΎoD7&Fqp \Me-B'G߄@D\[+[RCtV64ᴒd?ˬ9ra]B,xݺDmCK^;bqٰѳ zcypqo`Tn!Z_a7JFڥjd_GUp|")#l9kF1SLg=G0y*PUP a|;<[uDh\5;J93^9s6<80}oɶK}Pz|1v3]@lֆg,_޲2^_ ˊYYH4"\>Ȓ\`܆s?(x&# #t⺹fO ~Y|jen,̹ xe*uڳ^y5l@}Û<WKLXԆ~41-ogB䣨1nEVړnQ (;jݴr[PmbKּ{yti0w:esZy@tRֿhDhAG\Nkًͯ/-]mB֌EӕH |ҕ3Bo ȏtj[V~x3}iFKHF>R!nP:f_g>r-\/*.;6Z??oT۸<Ԋ\K,Q~/+"{,WV:ul/ujƥ0U9> A̍||]vXmqM+΄;|'f\A#Nysw~Y|W(1 ɟڈWB+vT3W)cTV/UwL f+]c* 1Cļ6hzs~ 2><9 -o-#9r{,ԡ z3RQiWvrɬ: R89zBυ=e,uzɚz^$)Ic5=9~NP7Oea $#sZZ!T4_Ib5H ;bؾ!DY}K573s*n[ԨēD7zF0a CeW 2:ǒޗiI~2۳A}gz[AkOWɽ=8Fpms3ŪTDK Nޟ..d, B#eN|>4cޗklHc `m|SsSI1}_&~RwFC7]EB>df*dRQ?DgVV]=nYMf!HV gIS2O{7ALIoК{1ߞ7/ճma`7|/U*̯B&2m09䀍5@ZXCɲ6D>VfXSƘFT)9ԓ<ۤ3'zrѢeTy9F @ s=Qnڟ2!T0Lhoн1`pş,+wfe*y=BѸ|SӃݵk[M J߼ğ,-wL-8]3x.Qc?hu7= q)^M\Yy`.>0OIc h_<ı* 8 e7J`4x!47rBZUE8 c}ƘV!$~<<(ÿ]@~]իϲ1/f8=Jť:k5Û+dj^At_s_ũz뿎/YW:|X ^beJb8U}_i-}M䆻Nlgl̲9'YsO=0 p]vDvK=[x|tvQKxG934=Exkmqv67qצJ2_ڏ*Tx3ųHۧj$x^oG{7)>?ؖ8{EN մϒ7.G&jQ~3x]}>3_haz7WB,m ,z9pQi#ӹ@VPqQ"g3-t3Sh{ed؄2`"!~f_*N+jyPhDH>|zgSL.7E{I6 +Ņ*Kߞn4b|߼*܊g%X"ADv$mIMULa,&F Ejz?}aOӅA7ES'kc{&m}q %?d-Pli0ǥpe4~cUfյ !XPPeE\tϑB\;+^&[쌻?un]J}Љ쏆2Bxꕞoo3ܰ)z"pZdnV\DIzS$Ƴ&Cۄ੠ÙTY5EJ Dђa(cP[SWKW}lxJ$G}Tۭ63N׵i_+FvJ)~B"Z|9b$ZĶ6wk` ⇢ӏqA>^ME{% *,FX-V#CaBSu>0GdևIݘnqy]~/T07cc#'/Y+5eBDM׈Z^(Ҿ/~R [k+ge"{h%VrJ|wŎft\T˖\ǡR)SiB xL2`쾮3kg'NlnI#r}/C%6 ΪLè >rxc}Ihźz Ұʚ$!0Bd/~{7c{y"B4$F8,Skjˋ"s[|~|0C~Dl(Uu!&&n~I) A(I\k{k 鷧 Rچi/d]/yjP?lzfhtiнR1>1->v"4үk:VDWmJe,t#訞{fOZڃ*g!ƃt)uAi)2J^ݗiz EqH3"WJg[Q1L: ߅z<0o$;|h*_H{Z4l5.ȯ 4ݣdޘ(03ʖ"P[j~T"=M,1Lpbxtr,3vL.ve'eJ.'r;.}Oh>C䈇$F|UtIEF%;F5-JY4wG͈'jpEe,z)'&5ʘ-}LED_Ti'qnV)-]0n[C0c.JȲSc^Xxso$8ɠ<^CkqEm&5J4;aEl_rQwn ο$SAdyzZ҇}eBŻF2Ą ka Y:|JaW^2.[}5%^%?k} vdR}ʭc.z#*WEweZ C\w?8+b uT> n0̚(~RO4 eJFB)G]j׀'Z6_7/K29iXofifN~R`Vb}IuЌy_ 43M*!%a~zd BDl_zBj pN+ kgma޷"3E ՆtNfz()b?[Ld1Xe/"/N˥#^hN@!^Q,Y]a$/!=`H`5+Z#A"a@w_!# )SNv[e@,.C%}F)7 > stream xڍwPjn8JqZhp @!SHq-V(RR;w̽gٝ .5"89"Yu 00A?(AE^!4SA*n^c@nk:'@0œ<[;V,naaAiG0bA;#F+@f#<Yprww9p,wvր_4@߅q0 .`]  uA:Bpn@ cǀWkܜW 3 zBƉ@@P_ 8, d}Ub8!\8] *dy, EO[!Y0w jmkW'.}(,#@ PPHv=~tVrz;60 `_ X!`[HlGF<0" }2Crur))h.o p¼AQ@ $v ci!)hoEQpupe? G_z$_]HÐoSCqU[C\[!g@jw!. ae*p_`._  9UVȥo94Rj5]<A>1Rxs#.N( t 8ޓeARx7' B. \.`7BC"H-svp"wo_[M/dmo 0l3?  yQ~^+؝cmT|a0{zR):p<7;mo|u&|'+ڑn~¡'schS!U_ܽWѣ|cz*u$G~i`4Ce 9- ѡϩGycwOUp|wcyWy.f*x\()ɩ>8-B6x1}cc &ך9|9#Ø39}b蘕6$R$ EcVKv$ȝ`=ZT ͺ%};+QE5Q#Ś jJn[~R(<p2sw-=5#l| RHb8` gyu{!596ґXLC[=WaZOSܓ JKۗ<"[\r5~Jtx0+{c;DTn`Fvc"sezB-XžQ⁂c͓êI5]<%*nr`2j@U<7~LK9y2}{Y\(y6,mt뺞c)P.Ĭ`3G,ː)~f 4N ȭ-ׄ^:A=l$hqnn,vDdsdy32<?D{ -jU@ >qVB]Q^}F|:!܀ОWHɶy#{\c^AhըvY1LɼmSTf=qyYY$bU>Nrw3#rS{2Gk|Ll:'/:y7.OQXz}_diSB3PX-uPxp{zNj^ŒVOgTҨ}o(sNRm3J7eh4ɤ_o7舆!>g'&nO\˓7YAQ_$`(!wM@͐imQܟ:<%d4j\vQ?14)-b e6m4) !+ɞۃyzwo Ewbr)'UUG'TiKx m#C|8,.H8$KkCo1$ͭ-$imUU1!ma!AL7df:A9C;,J/uDLic{?:[}tg{!zqÄl%;6ف fQўiP;'01ƹ;o7jey\,oc39cD!RݝS#XDs{BC,1z]1MNM SM`]GBg>? 1.W=߷;)Sl PXsUǬLOw5^甆M%m,] (pQ .ԏ]Z-)d 5w*=i`%N+J|KiM=-^SLIIH}ȝ.C;d46 ;3bMmq /1WgSQV*_^IIhR[*m(ϨqUS{qA e\=L sdVN̉:J&G+7M U_5Xv)(^3ߧUXwsHr6r2be%$j3w pZ2$$ݿ6'}#T>ݩƵ #5܃}:o~TeZi3YaǿQU?RMAŋwAh{"+$2Fە`Z8?0`hﲯɮ9LG^ac68NaBhC2lQzq] =0%[me8g+Z"%ڸrcL䫇(ݺPI*pZ[*[W&voP nnptpB^7gWLЏV=)hy0Olkc+hA7faJ[2m\jD?+P5S&Q=u1Xġsf2聘B4ЏNӂnΆx"L0J{j4GG(܋e N/q(|N3&a62~ͤF 71 J).IepB̙kvr8A>Yb ^nVۘi{⮾tMTSxTѵw"YƢf%lV#6d Dy%X69.ɍھT9=6>{XOi">ۜ7*lWhuEH24Y2~I/`DHk~0RQ9PA+J2K.ߺQ⠹>I41j[~Hlv o ".f*}L5EUΛ{6Xf=ßi[OzwF!\-'1Wy¤&Z:V?n9Gy[7ho8ߡY yr(ABԯ*v37x/jtjW{DMeӉ@<;&>k:Z&ٷCY֭ ĝ="rTpeVɠ) L<uClkaLᅟ{M>%Y\[rᗫod.a б-l 0+{F m=t[ `w>Վċi漱>u6PK,s:4]`)Z vUƾU$+Y*]L*[{SB#aF k7)tMAwg Ochxi`Nt{\3p4(H&w>QE._q ~ :\^\pH#Wa<_#%*U_b() ^ \>HoU [ 1v"2@GX3`ͫjG /AB־zOb\L=wLIŜS.>+zy3v&-C\k&m4))✬劗Of{;տ-F WMaCP&1qǬ99Qow.72xGWp%UЬup749?W&90>~44uiK%. }1@;\9;NU㎻%&PYnzl0W9z6=.puƂʐE[CTi~{6f/X=^{.hF۲ODgE+Ķ2l[Wݛw?b^ blc$('8Z`ln!hLzPϞGjil"#̥'8-\ 38ټ%Gds^e?dRǩqX55ZJ'(M_)DtcG ,<˛q]u맞tMαQTϾ&'gǰNNtW'A):Aua{xVXSوlO #|-֖.!LboU zL4&N!m՚^qr^S5ڝzOws&3Ro~R- n.5]>Kzo)W2N7bia* \P.79*,̢LMO;лSXVvw#a+ |4Q9%vuf٠Wg4qM=+W4YG3y<| ?+kIxجm\݉ /|e c *rÓ5a=@mD}lmKjpzyr֧s+^vU"H8~~0>zg y8]wguo"F|c DېUqkgJm*5]'k5]C#)>ں8Vc}spDCnW1|Zs4]]:',1{WR$B gv* hsfٿyξ(D}>4ƌ;A鱨RxL<_t2as$/O/oP 0Ld?js ?S:˨l7@7xDB^{aV Y^jyi *ޜyf:#6x&l¤>j OLߵ %։0 u%= _3s [#_t|#A:kU/HޘQIGo{ Impy O3m ]9/ "E3V3_FVs#ѻ 7HмC MOD,U8+T-ԩҡi;($s6(g-tm#>~ˣ\ʜ&2of^>op]-DK3,hoP=nӧf}p.8_ZLQwlԸyQ֪u}[kEe#[V`kB @Ly[r n65OZ7"M`- | ^ <^M1Mur2>̷.}M2+oge^4$w.~R"p# Qv!a{ F?>ޅQ΢ʯe.KcxHg1feWlFɹ8kKS>j jn?9p:(w 5Xwo{K2˿:Վ.Jdâ~'7׶YS329ufwMb8k޾\l]GӀp`{3*C *WO\ضL'v_",l6;i:[F nTK6 [1[{="N0y+aH $xxhuJ;BJVl O$;˅XEvV_tѠ?IEc4~Apsп@YM8Y?Kݩ؋J/GSB5bGwt<=jml= 5`Ѿ9^* 1 K*#p(T^l3e'hYJg UO;Aqd#ZZ2#p>rgɌ,Uݽ.1cjbK+Mu0uv>Vez|靣?X endstream endobj 1668 0 obj << /Length1 1460 /Length2 6964 /Length3 0 /Length 7954 /Filter /FlateDecode >> stream xڍTl7NI6RPFl(%H ҂4R" !M}y?w}U@PiSA"!B`) po7i B+zL 1B">n@".` ^R@%/%@"`("# #Ǟwyhu 0! AQBH/'^C|a_ߍ 8p1@a|0/ &7@]C1c j! G{@ph y{ _P7ݠv߅C*z@(C{=QB(ۯA`.Y᠈tw!Q_)`[+@9;Zp!>0u,0 ` w n1=@GL `# @0,ߊK?10񏌙h}pp pAfZ[%b` ", E ?G$PO[OM;6X[/3W 7Z_w K᫏7ZH g]`pժ{C1; pr(?Am*p_ Gt((G*{Ẉ YTF#~m8 `FĀhf `  ! `# kb"@#CY H o@TBB|1/v ! i?fw=x}V+'>*=ɹn+j #H}u*6CqMDn 5E2Mz`vس~f"&AC+ pWW؝>wtT+EͬmO`Qexgi:6|oAfBS'7ǮY4 "%heӁ 9qOnB+lk~@,OYƊ|²R Y%ORvuin'q0B@5f>ƕ@UhI`(>zfS[gg YVc4YOSY̳ӧװFHYHUȴBA xXabT2$?R42 YEX7ii15Ǹ:WLm!:tHٰ zs(6[ Btt$&7/%} U(3n)QkoF\^yusj/8&)q:߈lZ#~}u~'dG~4ۚ:ngꬣV~`UW0ʷiv.z9lR5`mWNcr/pK!H!YPmj!%Yz >$[y=˥+K~Cf߯IN缒d< ^X7̺š9zDW^Pfؖ(Y멅\*% q簃yigڥwRIHEj0嘼p2u^B Kzj67KaT)$ԫ#MF<\yHh,N uy;HظyZ[ nd, ]m6t?a~֣z-SiY-f,#%/Kr[o׿ T26 }3iF0x1-?Sٹ#6z|W8iBrN=W2ʃ{yϞP'YpЀ'7[7X"&u~E\aZw{pYFDY,X}$W8,Mi1dD[Lޝt#eDxDZ ,2SFBVK< p|_q+Ke? : ^sjXڲ 1Ә]}wmQVץ j,?Wn"`sJKe8z/Na։ވ^'"%9]jഫ`U%=NI<پ=Lkif:jEjv&fߛܣ(c 8dXKV`Jg^y-컑S=F2,Mz|.'[)fI8ntK E<38+=܀ a FRKu dS|qRH6ؼқ;Z9 _bWU :SgӦO2Dgg{힎/KVQ/]xgJ:$6>tZ zPy5,q}|`Y CUe)ǺJcnX5) =xh/=_rI^+_VRl [IIM]psحpL<s[ʓ²Ob w\V-f)#iiV:g ~ʰ'Ɨ./~[;<76";658jn'RБwHsEAIr?|h \#r鋗!Rcl*^|HD!"8DfjR8P's,Գ68-PG2I1 p\y`EE3Z, ջuqņO,] ůc(kN6C!M=仱 CpY8w~L_7kABvR4GLP 툖=o+gV :0{ Tdֻ$٣;%כ ijtfJ"=I)L,u%3Vw [k=#+/$+aEoQK3gdRjs6/_+#ܷI3-FC>E'*W&ea V3]EAf|Nުt}2κ=c1\^R(z@x<BBP Y|&2z&dҧ-N㥋Dp𾵉56ONW;^x|‡UkT$ NNv_o45]; _T)sDE'nj+}![ML-c +Lw?vp{ giVMkWidⱧ;!mZ-˟*/'8Rb7@eWӶe 0*S?LEQzxzC%Nl|jE,@E˩BsR@*?UɲM.Ì h`}~g*l1MK}Bn,'`K̳ǑV4OO ~,k#irw躙򗟾3W-wdmS^V>^i4Ϡ풘6G|ղ3:Ef,h[ExOhpXa73<9xm989,ri(p]ka)A×5.lN "ꌚ+Zm@o\[7FCo wWU$x`[w Woik2Ej*ǎ\TJN}pR&~oBĜ?]0''^41AcϤGQt94i$́ViN^\]۪3e_:+nҘF!_X{6 ?ZQRm;NCj*;h_ Ѽ1,6J+aKI_INq(ڙ$K"8\ T͔۔MiV˽.qW#^Ըn!I|:|l~ 4&"+M3~BtHx'{üe,I*s{sei߮]F9ŝ:5W̯ Ҡ%R eg|y;v8]&yUq&k5+5W)cXݱ 9vn}P# EJQDkZpރvd~,`Iy5Bs#bWGw݆7}zA b(b&їS׽4QWbXLt+P[$)AYEC[D;ՒII=nP][V1yVͿ'>OQjM2SfUS$5ć+g_p(N:KQrf<}p;4y6TgW7Z%8:pHE4%ik?JsGϦjFlRvjZ j~{tGӄ[!8BCunާ9RO e8JzI0sB)PE(A^c(ѽr*TF6-NXq %1"wJɔ8oCvAeHӚfzr]8V9' %&;_}:SC?pR".IhwSQWٶ &@H_veո[P;fm}jFzǎ|֑㱣 TLIBժSRUZ*iCkA}J9Mp<lcM &qO$r;4oM~3'T4ՋߨyaH'o"q|vq"_v/"DD~i~{d@!tc;f<7CfϦ $rGw+be. kvOkJ~aVIw7[ V0d27z9FdOۥ(P$?w/ne*gyS$; ZKƺu}(GC.T#ݷ&fׇRi\Gx#E3O8 f=oԚ_#Ue*ć>ˬЇ\5r$/?TSW51I5&&Vy8+9MP`#akkrˍFNdaHt}:PzGV,gia`瓂{5w DξH []:Uze]=\{`VCv`Kj ;-$Us8y%: Oh*h<4 KCu"QCfE(O=x|zf 6j&x 77L!w--&p<ɾp@z7g}Ƈ=:}Qp yns<.Ps.Xv"+bu`oIW܋xur**Fo kD=DAk㟍|mNli3 =xhܨ cG;Pj[v=Vl-m 8ueDD\0ʭjJ6p.*dW\ ۫u!,KdZwbdj=- B^˂xpf8.>ƲwC9麊Q3\K11SEl:+ЮGKíȱyaq :Ww٘۳UkF{E2jC>ƺ  {dZg[*ZBOdFV^,JS)-FYJ^:>L{2@E~# %#XqXs=+o^/ T53;\ѰdI̙04N#~g(8o/~,ſleM)$uw=W>#']3sCY"}}196f~IJ?ܺg^Ǵ{ht}sk ӳ[p:~cqBSAE̕r^o 6_~&ТˍxK(T/W۹pplʆRW/و*__8p5*HرUPSREYɋvhu.+ۨ++_Kg]UQu "{W\džҭKeR[R!>i2ʕف 94jΒ[lۜZDIƼ6;7];/i $' 33#H.% 4&z%ԋY endstream endobj 1670 0 obj << /Length1 1459 /Length2 6962 /Length3 0 /Length 7951 /Filter /FlateDecode >> stream xڍtTk/!)=tJwHJ 00-J "-ҍ(ߨ=;kݻf<ٿ٘`v U(J،HJf #0+AHlDMO( IťB1ʶ^`?@!ؔ`p3uN{.PRR;@ B:HgF{[f!}StuCNx`3@_tm@ '`;`##E< 8u7HC1c i@~ lkossNG0SG yP_ oe ڡ ~'n PU0آ:=D#_ zd E"~ Q+𻭮P7 upU  P9QAAAqI ; n wQ% ? @=A[o8;JOt r#:,Q>YB|1\:j*< [ D@AqA8(࿲WHIJIs5\҅ pCpKAQA{M.7v  rRZ[70/=Hu` CПq9=[È #`>i*p_CA0BK*{W@[B ͿT~M%@%1tf0@ C\08~ (ʢ? yD$(@B-2 t 'B|@3S0{.UO*6d6󟁷x^pUdc̀kPW6MO b<3N5ꮒ 1-«18XТ \I$#78y-f"AnpPB#-+9 #1(KͻKI@߆|5;۰'-&FLRz[sH撏O;^V"^Ely4Z!&I?5$3<ISQK3ZZR+{A%LiT_3Wiu|ND}i?{48vMA8m)ԺzT+Vvup;'[+`4\MQ_^sC}W6ݸ&i Y<58󎔏v=D]ƣ`:[R DN]J*D*mA"6f1At]ޱ#Q,w15I K>b4Ԟد8OK4|&z!CEHTM.LjɶFaI;gқ#KVHLW{~TlOJȞ#R*h#Z\◆j&Y7wKLD4p|&ᶄW,=e"CIyh=70AʉF.W:Q F @UtyDhu?ckd,ȨDzJ NbE2,E/5nga0M+$ygL}MCxfSsb Sa`k,_ ^>!Xy@O ctTQ:NFѫ .F9fy=Eݥ2Ve0zH݌Q'#9el o' N=ȌC&ִrFD3Ahqko9~R`Z)UcXB9,դi2w4[fyvWs ao;Z7*$\Zh5綕R`MWzP N_J+7!J ? mSH.ښF*9[5Fyͣ#.n|L#0szg@Lor%fp-ﵱGe}|!⯶bc⤈8zӱՖ pޢ/-I!9@7{vlfϐXg[6XpL-_$_gjU\-s=mU 1e(S&2{Õ[^MյU>h^6"At4D(kh7דG8VH ɩhw"lXJ2RahX`N|3X)SvckLXg=&ٯD蔒#}%ucz`gYyxã Z4fsݶ X`gԸf'/NT|4/\T :sњ`2LDHԆ0n_ yfϽ!]XAɿ#cp*(\rΡʅFy۴:m5a 2- ǒ$0X{إvRC=Yi! ׎3>rsQ($rZk84F <[Br~) o Bg'>/ZJ[>Ĺ#͘<pS\v%.{y>}4S^wf޲X﹈og|2IK3:s=}<EkrO.HV >!wUƊԅ[r #{f>> ׃<"'.iT봵'z^qϬSSvv2Ŧ9ZIJo]=?S]GDnRҞ).3Q cw7 nE=ˬ/8֖]@g[Ew*9)ⵜ'x:|tcCGW$䴃{Ͽ0_̦ٵAjfRyjepUSRmv[VRS/& eX\=N!u4zT6.'Nt_7]8y2M%qӲԞ"ǒ68>5;RuG{Wo}T{6]`"q$1JA*;}}K}뇧X& | @TU4D ^!cLkS94ux_n1g`֕8} 4m0t@Ǩ6iuҢtBwzP.z@ qKPa<ו?{h?ddlgYٿ,<T'NIjgU4X%F.&OPdʑx^VNT U,] P& fthsË]sa@껋8-J͒Y@v rWSLeOͯ2anpvE2ZǦ30bT_տ5f}u GJuA!Fh0!i3uOX#rpܣksQg&kG-6 t6˨.(ԦV|z`DTVðex*~9!?lZjɖMhoEWͱV~OسL o[d\V3>9$R•ثg._"3"8A|$q)qt `_+HO|.8i u=WS3?{.[(f 0M{u '! y Ĕ+Z𩈫fӁ;#a#MK^}?`n56}܋7ܘؑWZ3IXyVo%z@H;MkZ"ţ+;Mqnvf28vj r!-%\a^:4g;,OTa[בYqInjc%A5/TP֦g^d@E0rcQrrf u\`=O$i*sy@):ȭԗ^Ay pO}z 3x8??!Mvȗ=,v6k&B4"x8/USz<:{Al҄~n$"16rZޡVuBR -\?{5ݸAD/f>szyŢJ/=2/H7uGV18JMDRilf G?Yr{Lt<%LSJ%ģ16N+Mڕ"{1 ;GϳkqD ?-uOtj'Ʀub}N@Y 5G2$(ؽ|œ nz{V: % \̎}wi|Bl f^`L<70ZXnUm\t"YI.X_|QΘ-pR#wύO:i|fxj),s;xS9 JLgmNwڎif'K CY)h8(fqYagcm[TlɊ>X\>]1!jIH7Zڷ*܊no y*ye;6[In3DËzh3{Rݻ2u9֬ m{^=t)n8dF)T'S!^Za"A*/BO %9} jͶ2䤇{*UDlB |(<ρ҃CF Z*et1`]_|U*|lw9RZ1[sɪ+| /,;c:[e=#Uz[ZxV Ӟ>2AK<4a瞗kb&oA]Wj[u t2/cAGW Y!㡉:LaOҼr:o9jy>]'5Fudw@h/&]~F)ss&9TIx0{ D{uhBjG_@kHoCR{ uRʸ[N2K܈/|/oJBrwqҒg,E'9,<>Q_}jOZ|ؙSȂ]_5\sܹWuKH*:w3~ 4N|}+TH k`AmDޝҭ՘Ӆꅛ~`#_ xfǃ:"i2!5t3p!rz73h=]ŘNō/"_ud+n.<9ۺݾFz?2NKvG֎ E y'ϞB{/ЍzhLKʘf-e]g9Lb!"ŒE$ .350 |őή{dxE4uZD6+ =jCg[;ބV3fw/c ]QгM~%qvRBϭ :^m֣&%b~y?Q+Bb}{?k &1i"$gbX שCKw,}?iCsCևdNra/ԅx O9KY`!%jtݽ|EF&jI酫և2 a^XIS2'[͋VW?34?/Ψ &ˢ;8g22Cq^aA'Bf-<\?ڂ+ l;Q%1D K.h0pP'cU)Mʲddu*yNR5+=XpveJl U& C?{1Yx@'<% S?63R#W-Sh2|W^P2ٌ :eD Ř)cXiQܦ˛TK(.{ _؃$|j.DnH+8h3U)`dٍ$bVT СmJ3Zohk~y[ᰚ5Oy|o֑ݼ?/ؚ;:L=$IdJLϯ 5a:.wƹpߣAw&Xh]$V##"%l?X0Q TS֢#'?4y\e1,J?7Jݼ}&kWn{wo7"otrI{ tbƟ{ŬVcx h7tlDJ~=~+xV~kwGk"瀥b zQƧ~ٖ%> stream xڌP.[p:Hpwwww`w'%X es}j}պf:)Hޕ `aagbaaCAj `^t}I]rnVv++7 @w9@ `rA r};4fV^^nv gtٽh;A^FՑà hl)DZ@. gw9tJ@;߉1!}hX]%Vwp:o[ x;.PvKY_ woc# lo ۂR L _@[7{;l 4}S;p @JT|ٹ9]]\e"Kڛ;ف]]O 2{mw׳5Nn Yk,ANn^6 4b˹#o/[~>@~`  puvo 0LA`{? ;=,o `'÷2wwsE4N?'`eap= Qp+ط*O>Ϳ߾&3,,fooct2;)7[ۿY zW7׷Wtx ׺*nvu퀨v{UfV5Z0[=Hׅ`dea_Vټ].o7z[>Rb^Ho-~Cַ54y=f&{7[z~ g `K/ `x/Y?,e .ff٩Af?EE8|]:vf`d[l `lo ;s՟6x-, 9wps?[,x릕oͱ|?[l e3盩ېß`ތ~K[M vkj sS[[v?Ŀ0f[frUOJoF. ;?Kr9qyyK!oTnoUv|;#floES7So|M`=MvMK!,:Z7v׋z0O }ΠeYqr J[K4u}}WVd礽>Kjǣq~7ܯ'MCĈD"NZA6=r xPU==*&U=U2j(4]'se$FüD5?J*H3Go-a{Zͥ={=|b[̉*49%˞%( Llu`hnֽT@(5W䆊6lcgreh,vaF/> tU٦W7YrJ^_/2{a~dibcL;U>s Yxog9j8q CLكmOdKkBm훻/$˭)>Z 6&3yԣ*,QQwa4"."H ~2]|)-4LL⬫<+曅Y` ܘ&!BKŇ\ǤRݭדoN5n(rDz#S:9 EMwY&?ػ[mo(Q:tkESPsT=du_D8fͿbvcYo~ tG`D?ժvƧ{hA|b.ƀcȐ<"kǭ̴΂>m<59wi5_4awhǦI馎ے+,5f:/U X7gqrL~g^vdewJ/tj^.)'|̧M"L10X>+[ܵsw߅rh*h!'U#{ۥŦ[i-rFZ~"i0 Ұ#dǓ/i. "~wT>\*nBȳ~yG;û܎a ׽dcyD b7_0ם&i+Y 8a]7sȫGMvgq+vN-?ٶܿ_1n.ҨMNK''Ɠ]VVeԵ nse qC؎80hZ5-4͌4I Ƿ@|@<.ɠyPdJ+Xu\(O<')rƗ:Mh.6( aTR2"7|ʕ3V+|(;%>zkzɴ|qiO6\WJYUj2S?k a1]`0h~Q@Uʰ3JJF?gXzCsJcPR;|$(nN>ql3xTpFEnFVG7:[t&؏5qyޫkmvys\Y1wԮP-35s^iDMMٳW.nQ1+ ӗ15"SYNSZ]C4G[*m-ZMI<6j7Sp2%y2oqfa~cP #b{B."H􄺢)n҃bqITV鵪wWLwN{\3|Fٍ^ϽH%`ުj+,iFy=o+:gS,JULP}25CP Jƨ'Y}1>460int\Gp~?ȞK[⇮Z17œ02*{W 6rlC{PE7Ze6d ֙o:VT˿lv5>L\'9L.ɩvTEџ@9Bm=Fq3~;QF SaU8bo vT$T^xLǎ!`%v*gvqȟLE$Y՝YA?[7Jk Pr4zcu:O BO2'Uhة]&ͥv)4!1iA y @ hz$lV2\FQxa+)#ңYw0F b{r- Kb"2ѥ:kW"1f1%s; EΦWFn s$1vjkb )CcM5Y/G _ Qt1u@r%:Ȫax;Qi7-0+U_2d*cPWT⫉&X/U!,u-McZށ&|wYQ. bc`9M%l7?wX ]īoK P|<єvRe:Hs;NjwGkg؁| 꼽iEJw4}sq]݀!?gƅ~$~n_fک AMϏ!^ѐI/| /H%J١?&F0$UX*?;Xc9]cȊc5s`s(Ԯs~|AqP&R)1f ""JŦF91fbys @]j'FcnxI$* pKUVQƐq{2!5Eg&*GkC'kV/nCL WU+)"3j?F ,mu!A=x A,&URj.5&^'%]8 FT`sHtf[/x]Y^:.5XH&X{{K֚p,Qm#;fh>EWl$.4 ܍?~W'Xć 23To"E}~[I9Vyr+cc4\JǴ-cHY^K=A A zG"(iK)}Vmsn0;S,uD~?$J'[7=`NBTH.C0qH !I]Mb7˂p Rؠ6ڇw.fdfExW@ϋj題yR1i̤ܿ%0:XWI`(7E"pU1Rzjq=B9# Uo?ݹۓ-h&;$ɮՕd֯i\iMYBeԡHt95 kkkn_fgQ)6 FLRW@3>2gد+D^2aFY Hm}~4'5l|1z<;4Iyɔ0ڇWO_w[ְ`? y2IiG)DM7sPn aN]t8yՕ< |F pz_}"ZD^-ixGJpp3=z;ZO.k`8 ~xWƁţ>-S}LJcl-ׯ7u`f)5/> = סwk,2;̄$K:=Ts_Ɛ /r R鲊qh +!)|UF$[\O`( q>qp5]=< N2HKdg ;DSE~X/Qw=~ <燐w,@yOEl&ǘnDM,H򗔪l|جCqemN8HҶ1MɅy)l:fĸ` [ORGOZ?p}f4%mOcH%Kve+c66M. VGUZa(k>G @iE44?=+t˄S8Iy;ule%4nJ.]$lrp|:SN=Xy_uAOhCnWٮMD蝩͎sd"J,|grje|F6G|g'M@m^!"&a[~IeV^2$&ua`E[e4B-aYUrpm7:h[2EncskG@ 7|B i_.w{A+1.\RDq΍'_f9EhSsP3!/fVIh_='@lJߧiW/9Xݞ1V:;IxޖQo+!nֵ@h2J?,P 0;#<`95W\?g]v0SIs䋺YķDx}ZѱYj#J1UYa­#I]L|2<w~"GCD Ogn/9Bfc"E{PpOlC'C(ߑ/f@Z텭jcg_j B^&Ub?Z{,.9fCI.P6Nq7uq.,E9/9rIG[% Cn6K$oKl5ɏ*62 .1KOc]3Vu~R':r癄Vniw[#iUޑƹ|[a*a֣qBGjCMLRQ]QdiqR(h׃a"-6b.x)nj Py{٨qRSڽ&ӟE!gֿt~b|eCJîzk2 @ z~+@Xx3cE&Fo z5؋G(Y9~B7Qr]L%[v{!n4<uAeCܱd`oP/Ά#g A*s4OH !mj{[2.ˉTdԔ67]yׂU'Ja[y:7ن7a %JCSm,(~ԯq:Tt9;M"|4+gA<ļ02WoW%~ b]DVSeN,*PlHnaQG1-[9_v3:n% T|{3m%X9hGLζj7p+M*#BᚎG0p4= [+c͠gM誘DQ_ɈT(gCEդ=8Ҕ 75v_-B,F~YS4n|ؠ-, 'u߉v8{Kw-F#jijB?JX Wvbr2 7|v5[M*b2$ ˮ.3,yd2oސS@lOS+ŕ?NL5%۸o_(|,;BU|Zh;uW;wn&R/.z(θ7-q*)i[ Ur1@<۴9z gVxF\6j`l>aPu$jQ=,;3y̧/ú&i8{,ǻ_4Hp_І,/7SJ` ~JVwtb*bY3d,s-VS[Y~Ք rzj0?ў@¥X:qӠFJ[DkQa3)fwDBOOWp 6?IBpC6i{"B{Z2י:LUoY'odڶv5IXQi3L68Gŧ8anW_"j13X^4x"ֺ?c-[dɄeX9 uχns2|~Oſ?iLx!{}2,g$L^Ц0ɜs˜T{BwFZmiCCsW3|pY\2;F'l)4d컠0-ʦpp:HQݶŵF-gUk[{z;`!{ (BtXNXsDݻJQW"*E[ÃݝYL rZ̗ȏ\piʁn0OFilI#K.)D{¾n03>rM[)уpա+$t cqk ==q1{=# 3yߪm+e㝒{%$ϽDXOGɺokrPxP:vq?϶HBi<9Jái [^+$mi. bSmph#=Jen痊KFIc?dN_j>_[i"%kNDR/l@E%NoPaL#]i l(ѯ-(RHeaJU8 ]>Iz:LDlAJ9ƛwKԒgaZKn _&HW,Tsǰzp|)u-0;6خvA_JzpYSnݡ1p+H jC x HLT LC-ڄw𢴱LΧ,3n}y=~2ر,w'>K@!oEîy^}dMcH*,NzƯg`'FƝάB{ݥގ<tM!JkA{m AK3'Ѓn795?c>@M&!Iz9;6.5צAvu(BoXt ~݃т; Ճ9hBv 6AaYûׇ}xTn-I=41P2d%ttڬpѠӮi^HνdIj_7@{A wSA>9}FOQJDJc_v&9 4F[ 5Z;:6U&k[[,wiBdqd`R֧v3Wk >}[2k|5n}l'R5˨=Y ci ]ڳ\ &]%1>4w&X S#+H2آه!R35@$OBB>LgE5c`4(W^#^շЂ-z7zQbpc/ײ+e^юw\˳j.Aئ|tj<6Z+=V>+cs'/_m̐|gu7_(nzB !NXzFGA|JNvLJrGV+>g`{X'Jj\6*q(6Jkf3AU0ONH1[]gS=j=*T_ P{Ghn"phhVR&_6uI OJ\e㚲X.H1gmJ+z(~x$n6l|\>̥)JS#LoQWZaykg7akм3L\5/CJ﨡§MG>y\\hcuz۾5j=Á~:|%VE,u}32{1/mqDxAePZ\Ñ,Uv]R(Eʁ)0̦tMt}}Hg*L̳7= EvzXƷYG1FN, ?S b+<\0|0>گo@Snv *w ~nW bP{!<00ZJ-uS푚B(T}V4tGw]3 j6 c=Ez7v>2CEtVXWbf>+~vf|H^ P}^FW!J12[V[35EYdVA+Gļ7ˬrxL 4]_ޕN{)ƈ7xVVKGOCx GG]iDu3Pm[Hu =acA,ƅ$H|[ϓ3#jً>*wK䊜srue%jfc =%K@>Ju_(0!,qA`y07L#7:"J}fVEA#A-}2CbJ؈ :riR,"ڳ#ٍ5)bWs Ni(BN&vGaR r_`B0gs)$1o ȗz a"Mh'L}ti3,B.hVs18:>yՍ$;xPnNUã_o:Fa\Co&_sJ}κ։,_ʷą,`Ő1kZyu\V(h';|)J-Zn@wIp~*Zb{sS $ov%$( 0奈\#~ws;&J\qOڋ&." &PfcZs7E uEkù|5-w \!& S OSq9`Z{0Tg߲spM7ܳ*sf5 ӓ*X PI~ƨ-*SLRb/Qn;nPiH9uQ'v3[$Fn#ò3#9z`!Dh=;#mn8k!C<}$X}ZPBcCGN,Jy7xwcB zR;8pN$"*^ ]3PݓԔXۏF̊>]K>TV0'Ŗ4pVEWQ )}Bpd:!z <8 N`1 ;4S9/03KhB&$uca|#ФPPUY{ҭ$y,*d+_\}M9v"6 x ,5P|d(._ 6&jK(WfŽX}L8 묉;N#FQEjWPSύ; d+bZ7Kw<_#oZWRm.\0usCvq93"Z6O[wl`֙tfe=#24WE%3`X @J4s|Cpi{Ů5&MȸTqCg|^*Q$dhyBڿ="Nu\R;jP7l9޼袍q_sz Ԣ8 JWuL dajXT.)tA\q:%88(х u.>!ѭ =&.{w_?#;W^6/&#`݄ ?:V]UfZ9Skx]ȔL'GrRp-׎oҲjс=ƟH*o)wy( ڛA`{|# B G܍,㾁BmYNP̢"QfhX1kgĄ^0gZ:y+]kCjhJx@V}"5zSnƼ0rV-uWCybJ)TWߣ3;W'- V|Z#ibXuFDQ'}/ƨ]#DQG\PSf 洼pu9o%E^x^J;VTf8La8w; ȼ\ 'ܐx ^pfϣI-;ȅGMy,cnG2ЋȨ0 RPy$1'n-Nc Df^`/ ǡGq']X?sݚ,aQ+k-x%p9Ԩ"Q,ρ"r)qr5 B׺ [';oJHNƧ"!7(aox(!C3@{| ߌ }&e!e"s܏N;(Atz҆WO8lD܊:3``ȫ_dmK&J5@#Wu3CLNKFXmKsS?*G#ْ1KQX)š\-W+L{.3 &W_봶΢^4Fz/0A OOG# pS$)O b ˖ŨYX@ H%gKϰƩ\+i):$FHn7>SD_D{{.D Lĝ aD: rZ `:zbilJ$ xI?@ = LC !k#nx>"&xܿ"!A)^JU*0o>Js_)DDR8 sN`a\ǽ6N ÞGnkKf0roM]$~֩d@IWV-e^L5C>{$sYdtBU|.J{~`x׹;eF=og]LХ+)׮t+;rF KϞ/B?S(a8`d2dMip*P[ʽEC Cl]V %>zbBhw=|dM.8+t瞏fQ'v<4es++[._"6EG(Yk1&=fKîTT\;&?9@/16-ɗaj|x/=]=e ouHw%gZ!g_Ur0tʽĽzU]b4^Ye,MKdU9vM3ȥۿOp#~?'zpsn]S MEOuҩs0@6_a kAXWc5krJ9g4/;`PO9Lq53}k"WIauO'rG%3q1iko2_8 |2hJ͋,J$̕.R%WXv2 5PW#0^'{$9978(H[~(;{Ř4|qkKc(Í+)h9N~}1$!9qΌ  >;{R)".~$V_ P2,MG&'WՌ?̎{/H:k/ǘW(&(A;1_GN\_3_W AK`.1׉PߕMz\ endstream endobj 1674 0 obj << /Length1 1711 /Length2 8499 /Length3 0 /Length 9583 /Filter /FlateDecode >> stream xڍT"(CJwwww0J( %"%s5k1&W`aP'&6fV~@M qG!0(pӃLP ;8ll<@vVV@I7 3P;%`pC҂l||<݁bv`8d*9Y2l0_!hYX޾}lf [ 1B`G0 e֘@Mk_ [38 Pg|ԐS؃+epllW 7BV@K-"4Z24u=1ؚ?. (-4{Ap##W,<Bfg:9~' A@ao!KW,ZP3XNo_ ;. k_ 4]l=x쁖m=!/0 tS`cZ@@N@s 7l??4`}?6 ?&uhkj*1?Jqq Н <Q5]뿮rPKj?{h:R= .Hr?Oo!:[o=_ouvzX%*@T*- vs2{X1? q-T!N /֯M@0Gȯ?<C[~؞N),~;7 7s>;Нa-. 9=Z_wd%M$D8=:euW g8O>.``fx}e[K+MA:hRݭdFM- UG&=/\ [.ɦ8=\?fJj&Z aE` ֙ƱUy严Ϸfc9%7!S8b|r֔E_7\[Xq^]MkFgTUȺ꾄4!FT^;_vv !#> ni҈EO*n,/;wC,~$,ճlLfm G `ɣZ ܴerN+ ^=mHG#6q`R(hb qI,^(8%Jl@x%1ahlKqO_T-ʋ71_)OԎy}&ZgNFes6S=2QIΥgD WtQ2z'oD3}[gkIy/aHV͆ K $d%׺a-!~lEoI:IW-Xd&}UhX?5S[PG>0$-SdMA`w~*q΂hʘ؟ ɕ3$]\[4ˡf$HXjErNbWƒf%RNXl\r ~OE*YBm`^KTHC] &F'@ O7}>l}uAAGԄ%+F4oF;r ՝E;LRoL2yzP kcb|vjK-cox89]دԏ&Y$9+}PZ.m4zE7֚Xx!:?8ׂOd*mL]2`3{ 9+Ր >T&Zyw;"X|ӥ{۾,FJ=w^};HPD V3la5CwUôA-H.um8  5eIL5].O%lh_2ڿYTGTdEdy"k=ݗxOW:<:$,_7aR(qh }BvIX4w%t0-ϧ$bt0r'^X ٦6q CoJ9%EԊϫ в>'pR5ɢEsOi6*0&P٧*Ml?LC@HZKPLâF+Z,"-Yqں6l7+Cl>QzU5^cUq wyG7jG.\H"*/[(>{mtp}ҼrGl[8amoSƪGfB#;¬zbDʉHGXZM1&v]^h8:n;#[Jd+yE[-EOz3b$;:ť% |-AhNE0Ep 2麶sugs/:nOy^KQ$}2G:=J ~2۵["}Ӹů>gt;@\~#;|ZӒ}j,I~&֮V긆XaJiC,;j;8Wn h?V)buEB1{eX^c]+U BJEN~^Bp5wP$jB'(Gcn,;*3b^`p_7U~SvFEIWhm璵8DY-i~vg`48M|˜&Iٝ!f*ݵ SW*4LN41>kgoA>9i {(*-E^k8:8U̲T>Ҙ/%׏mENkg3ڧf_.dhq19|+thf?\!m{QVP=C]~L>rtL4/iBPp}Kg[+6`lϰ?q玄^谵?w$w:|lGzMsM[Ox*ܕ¢{.MY87,/hAU!Duc #*S{UKc*!ߦz I|Xmfpd+JY4'u>k @zY°ASû@p2KVkD&`EܔR/?mpy(Ϋ`HcOQhupeWha:ެUom!o@6G,OS0D$>6|n{IV83@,Ʃީq{N,ĻK۸!a` BG7IQlC&VTxu"pkiiY~-rl4&PٕWk{͗JY*[}0o_'#SAЫV‹ѣ;^c6C{z'y/l"Qu{w y/ך*jRwG9|߼R6c (Dw*_|JZ~n"Vq[쭯v/<1-kBJ ë>9%HjklHsyqGy[[ovٚVkYG_j{hZv?%(ȥծ- BZl7W 2OU-ozŸ7(70[˝)*wxѕ#nRFͥ2$ o= ]"\C!x_.辒c%i]ε3JeX]TuT O&2]͹컐.YY"ީ4~ GRG{> !yBAvd5.Z(23@X-ZOE)u#CnLrK@gd*<5w#//Meő.(=ݲMQ>ǖHg5սw-78:W(e:$7Q+/={Uia;!/P{@X슲?*; (>x\b m@f3_f댂¬0!äU7ہ gV7wY1?K{)ǎA…sCǥ'SVn5q?GWHpbs{zHzF=sgQDsL$ +LJ\ 'vnZqkd/` .a(|U#m$MKJ4b^ޜ*<34UKϊ2Nuj}1b,#|.H+|8#K+ /:0I$1tm{Dž~ `X "+BM\)-_Tz2f*cRp,\@Yh (וsg<<Ǫ墨`א NFBf7&}|{t4<<|$ύ]^|]AűWp.-Yl2?եL[aü =XR !}|0M$-9oRc5n"ZJ=D? W~EF3R61ǃdBeg>Q1F!RTkދ<\r5n;M(/m?O{^iXAׁx$ ܒP<3V*6M%;ܲ+ڔKiƹgkJ;Ao6>ġ}VɧUYtq{E,2H-CEתo)qf&{^PVXUڍG-3; ;P;м: 4 UWrSJjtPYj/p)Eq $mU)H(W<aD/ KB`uEˈ,EUu:\SD[s7dv=gۚ!ixx1|]9A]mV e.w銇彎l^7bb6.#Y5US͐oދ 17,\Iˏ993e%єB1$%^?u>;Jm|r$Kڃb[* @kgXq:n$WCMR;iq4di ] 4Nu0W <7:YuUG?o[|e*~T;נӥ%ǯchx|dP "&.YJaWlWh鞫`&>IxeޕR![AO;C71{ 9 C.*T-  Z"0v^z8y{6M͛~ <˓X?|7(}ؗ2q~FV+Ƿ|<+t|r'/1b4LeBJI/ rY<} sdэ' kNvw`2c*ҏ(I{VW=@Kᦴ%4+U)JSu.] ]װ{mwQy9Ȕ}07Zoq8=watYeDbPsm)K?v;'XG?J@[c]{_r[ɢVDd[}3Gda '1 P;<zjM|i930qMMfžեnC l&+0W?:*+ꂫXUg+Y1^z|/ԉvOU98ZY nF3sFR;ho)ۨyZ ]X d)~:fl8[}D&"Xڢ5mF^b⒳2^ ۠wD|;_f蹟$NIUKF:;oG/z6JzֻɄ_e@lϭ])n6熳\Ve>pl0D۽o<}m-fßr3c Ev{N6CѤ򧹿PAud̗r]wj~Vipx/ᛍhXR&v%X݊Gri|{=B(=hFԲEq{OukQMGU[<+>r7ìV2t3s2lي(ϛˆ.U>nh;w[\;M/l !B AʿV->W'=դyElҌc ?7,]{4 TLbyxMA%`x8k ~ZptN$K ŶX#!j|"D왖CC H4I^1F8pDL~Ϋm6 Rnks`q|"3FY]P6IWHBtՃʨgOhRcȠ1v`2䎕T1) B˦sc F"wBO_ԂXmfT}})OyghEs^[ڱsW|w?|alU_{Tn~N-sUrc v"UQ zORpLGSn 1 oX"> stream xڍxXm>")stwHncC6SKC@.钒>>>w8}]U}vIGW(!(^>8@^ST@A|VV( ێjqABp@Ȼ@Qh5 Dj0@@D\@Tb.k7(PC!H|Vy # u@Ap5℮ (Q(gq~~www>k'$NE H 52@ g4>|V=Carv#!p0Wh;C5l@O_DJNpO(` AJ|(!xk7k( ݺ5@IV`|H CBaf͊p< G!upw+[(lk 3!6fAb""3d3=3` ?n`(AΎ6ClZ0'z007+j)q_N99WP +&DẸc ĪmE-pK f.o? A73X+JH 0?4s]Qhh"Z7t5!`{UQh5Ќx|Tz@:P/e77A nt_>@[oU_bXX{x U x&3@C}_+(uuA\ \ѧvNP+%A..h׿x@@sD*Y:wa8Ӟpa+o{ grV Tْi:STrP=rǼNAZQԈuңx]b+3l3DN7ۑ[ONs:Tlv S&UԀS{.fiט/1rQ4d wUTѐ{1e&Pg5 1Ki BٖDL i~>TZ\>4OHݘaS"Z 8H;taS2pj~jN"/L50p Y|Έ4O=ZNDVY~"ЬZϥsȶمÍg:#gCĄ+4ļ >Gh=V(8 ð߀IS홱h$||ED\Mϯ*TzMGhOYDG-sgt M8WNCILcLt5-V4 T<&hw;Z]i|Zߍ3e(&7Nb`KZOWIOS^ R͗ŠQ_09`/v m;Jwp&MZg>+l^AZ^?äz7[_Ho,QC_\e8&YUZhS~7b,[Y&Q4o,6{6-YK Қt Bj#B(GcdjH06pش5}YnӏYF V\t{uc^.O2iJI&:sMPI. }וe-# 6k6h=u Â9k ˁ'XB+OzMvzj6fA`xx#;=}M.ypw޹l-Zeߛ72 GpZgA4o_=tԖ:)6$/xt/>;b~L"{e6τadv{)%b-jĜ,9v?nm͂3`ߚspnf2M9W"v;C?_V$]DNt! nW[=2~QBfΏ3>/3>Jtd= _X4]JUqdϊVs hYʧ ,7 .0?ۖ!<8AIDjuZ Ո,tt/hrh}/QP$ewmQ̑4N%YVf@s 5&~l^i,/Y*pgڮN,f$#g[0{yfoS=A ~߰E*'WyDFߝEOFs呙*N9Ӿ>Yz& d'╩3¹c?;/AM(8LB/L(>ޖIqY];e%b^];`D|Kn6STz$Iwy\~cwb(9޽s=l֕ $#tNGvMpYYėp7'ۼN W*]TVFԗHrh-1ײKefo҇&B#/Ś9 '>M {[*8G>x*۷V^afQv#} ^=rkacщ}c;·Q3^pBǺY 7e]FЎ{"NtH:xdDt9}N]yV4d'?@49㖘Mpe?nET^)Js2f;<8×6Uotf4t` \g'mLVp DQ9Q\Ra_1)R,7XJw¹^#1&o;D~p0\0\8yۣk%`AF7rs@(هWN0BsV}>B7 Pz? w=1LaO>X,7_>`sʆ"@/R7 E4YzORm5ɧBz_aO>1K|@c`sWY4#I\~7tV,nDkT_k8-p4EXu77E 0ؼl]W:nz'Q=ܓ!Yy;ѻ5SI]q #+Dj{G'; kcq㗋L_ȗ þdb<&lg;nL'jGgTLN62CKcf">?O{I2AaR@̯S G)u$~|;JttM^js$&3;HdcP- Q+SUxWvOhMbC9˱b^3e$ si@KoەBJv5_ʥood[m{vxʻuaqcotl?)?9[oM%,~齛'ֺTg~,?s vG|sF%5S-+ '3%+2Qݺ5VʇÿCfnE!MKM)5{鵔 dȗ%O #y˗>:RM~yJh[PW{Ҫ- %itU5Ҽ$4e^G;Ve~ ^bky2ғz8N{Pu\)w¿qsOv}tÝ1g&v"ZʵGӤ0{9ރ HzI)Kj]j2D{?1b{ĵرSy?PY$Up_k4'hVL(z0GNBaeO:rdqtd1WI} m^I"m"s2xCy}nD6ΧN_$>kWmy3%K#3I=ƛKTG6NɺTthv/v.g&'tSQ'x%N4كgMɫky8+XKHZul3-2)G+Gfy;muh,YJ~ ɒ8I̅JiSv0X4}Uhw %Wn8T ;\(ҒtB e5)Μ87Y3H88glƯ &|V_9p!)QYnOlm~$EjWKP v(4# Шs{T7. f롄g1<7VMUlZT݃,L3hx_(LQQ;1v>Om"YfUl 9;UVձyUkֈ:`/wl@iJ8w,+i4dz{PHELذ# a9C$D&EK8$L!ƭ(Z}zc~?n얙0 SPӔgttnJnb vr/Fztc$,tcKup r`4̱ƁX}Ŀn*ЗWB`S-=w#ɾydqǝ띖2])$(*Ѭpܛm|VxBTaݬNPS&~M#%nGMAc1)ߒew*gsCihasQøi~3IH{5aQG~* O1x=F|ΐHJa6=pY5~r/kDb@xc]ke5Tl2\/.>wcO9GlmGx\6׍ݧØ.]|(~kZ_[LIJnЎmҞ.HWYKa{~nޙXZuKv&L),K:Ms.Ŏ 282w`](ݬ z}sJ\! —sUȢ''xME_>mل뾥=;҇q9z`,=g#SzEu~A˳1 ԤBq>O 7J |Hd&5n~}uP(̔jeqvv,vWrO^)uz]YaRd2Pd*5VF~Ex, 0؈Ӱ}* n*S+bTpUC!aֶMIwVΠQX˟*itUMK7 )=7*NOPOq˻e+9} s6PŬ'E#`,1=;ӗX5C"o+8qertD;,h vk'j׊KSRqa)s4_ _DAڱp3ʦoʢ'] ̪8/%Q/j6SklhԩF>"\*d!&nw.ELcf%=fPm9͐1/.(ոx3״v;/^Ό[$s֝Eoj> stream xڍtT.)HHIPJ ݍt3 00! -JwJH(! sw]5k}~~~ H{JTt ͥ@(Lea".( C"Aa1U暧D<!4ED O#B"h". 脹_0/@HJJw:@Au  `v?7@z!.`ï! nTS/"ĀRb@; *o_Ot8\ 9@ O(?WDBB CaTחy,f}-/ ji3cHo_JL $$*> r5Hԟn_{_sYKyZ(?"oN)W!58ww\apkz` ⿩?ՁB`Āp3PC}G2p_VP}$rW_`ZCks0gb !^IXL 'tmH$:p=c"uB@a= ¡__%/oy\7oCP0їOH'-'5J^KC7f"{0w&s 2ݕ tK>3q2mo{SEtWWQbL裧Մƺ,vRN_vgNb|">G]`bLqbknD=zRYghuFUU4l14kw3];;/?F/sW@Q| KptPWt.5bQsSv+܄f&?o SP^l]OcK.S"b_#DJlxf`xg†:zKȢqQVJ{?DE\Ӓ}g/%‡EPSvM^L):96STкP䴬bf}OVWsC5)nu޳p-fD S;2D^tc>b}R0_pBc".N}zhۂs`nLJli%v%Xwңwf0{{2e%m2FMrN{@s R(l|cwKEՅaNus۱.m4[5O-?7ou0Pzewkt.VYegTy9/Ol ([ƲdѰ QP #Q g^ cBۅY2vu𗪵CCK-5UǮK\RGrp]k 得mVY7Y豸Rz=x_} M6*{%$V"7Ĕ[b*^pܝIPRf3W/tZy6#hBYK /Yuf3KJKĉ\K+z'J,nB 134!LW"~VcR|Բb䷛"n>:W_LE]' ,6Eg&j vGӵ}ʸ Se)_0~l1e`t&lN_¸ Vb$VFȗСk,K͒ϏZ_W`"}^ה_g1g }JlEc5ԤϧɁ[L,19NU&BjG-fݼKTYW#h}K3 ? (-Ⱄ|~VMЍizec,5Xv =0W25s{}F^җ%$Wl 9?VFExDidxIh-kb/m#㤀qBuhZ'b/&wx7w N[dnKG[ !/A·k2c4I <ͧ/v}ƬJff7"V,FbO<,Amęa?<}F`=Zc۬[h6u_|Z"$J~cw[ff!ʬO^r6bg27ɋ)TWKNg(8_kWnVnZd0Hvg/g~3t8i]{+e֕<~[ƙ#@ؙL˱z}(e/#3GzYL N=켐&+YIfL21-.ԯulfdCVmh*MgB1v]i^ȹ3taAATH~a\p|ۋ"cv65 PɷrJG*\_BùɳOqKx+9g䮿My*22]ﺚ0xH㭉㙫dXr:@DOj׻ui,IC-;Z9(D ~6٠J$b[i?|~w*G$Z&g]>26~?t~mht7TCERK<㝳<4dob8 u~IPOreȇ +cGpp1aHINlzZ&S{OmlC_Ei[HSN䬁W,um xӹYUV ~{v2&-4..boa?ks]F hA6y">k웓lt$w)1Yxّ> EjM h*T4U`QBڷ~0^y ~"ӯ& z'dصS!da-@d&>maG#P9tFKzVYȩ9%NX^A4ا͜2c'kɹ)gSp]SCǣ`$OpM17[s1'&Oǃrmqu~95~|aËnCTL?bsu}~\ͺdFj lH{ߝ4ʴ;ׂBmA͖fҠx|jԦ,MF5S4šz7X*[*uV&I1 lb ñIiH5U9+4Ngz6=ŹeyT{cNjoh%0\=Ve'ǘI_ޓXvKv~[ 48vxu7Z5b$eاry,uZP~& A}O>yT~S ̶nDzFlb8=3u(1w\qE)Յ o){x?o~* QA0vrR^UB]' }D7!]a1^ӀtjiJc.kݬ G{EūODexPy `J]WFoy{ǰ-p}  eS*)qSMpFQQa%vy#I7%e|9j5fJG;3YLniͲ/g#4‘Hyn$gr>=1㠆bvGiDN&,3]Rjaz/¹'}NQ ]8~9P*mɣ=Cc %hMkjcvV1f<+쨰=9!H΋.!qxo{6׈{&hmN8b}hcZ1cL cdL4~,N5:676ƉZw$=:U3ۯv^/$R4^SJ2R|+8"XKG1e/d|ݞs/I0*K蛇B!OmxiSyg" _a9di㚹XN}<%=08J9y_^8_vW0 RKlVi Vn#s>+oa՝r2%ӏ+܉"~¬ݪи{}eiA(t3<-22a$YYGA͞EZŽ_ӏIhS6\ADGL*`,4;xGCqNZ)l'G+مI꠱fǤκ†0#{Q,0 ֖'&<Y@iL|,ሎ]a5%؛R5pm$5b8?֖ɮ/ee6$p uEZx*y3=_Bz |+Ge]F\Ӫ.) aZđDOII"R<8a߷] fYYuʸ]mP(_EF]Вl|,}A-όQX^>/Z8]t{k$r\`|yC$tt^&;e WT"ϝmnǧNp+}EB3xi|6\\iY+p/{x c9U z: ]> stream xڌP]k l%Cw` z9sf&gv~* Pޕ *& `ffcdffPrGGtvr3C&fa(`qX8yYx<1tp[2@8 QG/g+ K׏8yPXxxELƮ@ƶUS+tuueb`4satpxXZT.@gw௒ vGPr[`a |lL.7{33#:@UZXoz`adrde/Pcttۛehl7v7560W eGՅrfq{3Q;; _Y9M?õw273 37G&u{+'7ؿm>Dpd@W3337+7zZ2@/%_|ép>.@矊Ep,,3+SW 1oqV]c0DŽ9z13h|wU~ a`0r0XXX\/~Gy+mo;ݏ>'e>&3z̦/)ߌ$lmGolgeousy]WWhffҮ bo1 ,˭\$F_*o\q{S`lqf@ 3` rrDLbI$ 6 `>(qxQ>x;I#3"x.cb#]?#‡d`~D0?V_@-?-@^w?~TbQLpq09 a#U?eoo 4w#e-?z6 :\?SGne~=?rYS7B\uW}>>@'ne/Ժ!N߃`q*Fs_P9X0zYog6)k{oF4/JS,өO^#6{3 6Qlz˃Yǒm5ՖT-cqBEk>Ջ,,H\ ON&8~`^?9At:rω'k4 XyN 6qT"˖ޟڏVhJN ؆45+ZIU+f㠪诬D\*+W?6d撚QL?ޢzev":9ΊS7^JHN,[Ízd)x gS`"_ΙII|g.*Q$S3ܑ<%A͉hCσKp9rOi e8-~W;> Fp!k.sV {`q_Ygf_hO'FW;҇ W|n?Qmlt%Oij$%lP+J(t q rUYYVZ61m_KTWs{0PO6%/Pmhv0ZЉ(IzZk?(Tm)"`,HstoP  Y|;fKۊ} ֛:^111<?|0|ruIP 3W(r5%ҮX~(9= ʞCzdۋ_ ^@#Qs(eORS-( sm8U{D;漲,y:+~茟tߑ|ST⌖%u+1=g y\([Fp(`h~P$"x'ʰIP 'o_ϛ1UX\N܍=GRl%hR`pIcmQoJkuV?C߂\@j 5ϩ*ޖ4#Q[nkH6Q"'OYu7ipqX奒g@D"@ȉYd/vɛ_%eH1Y;/y6f[a[%?#ޙj״j ^Ж$OgMXZ+[|-:4vUN!m'+$B(x&d+x0]ΕX/w|-iR Dq&cm E34Uu4|6CJw,DH 8 ]Wx W4M?AD<43Fbd{ź?Bޠr6oaNL/ÂKW(poB4,93T\R@0\jOQ^-OKb@}qlc>uk:y[dKf XC|xWv&Kdѷ5<|$Ag|¶PN%.Gr¸˄{P C'^ 7<)\p& rA:w{YʾN!H/Uy$%I1V<}/BV:{"{:՘S~{f['Ʉ1N:鵳PwØWI;v_ױ(וc[kS H'hoPv;Om,(&`b%<~FK*!}wT&9ɍfNWwDl θ AJV^ye^>iNkwa6mCT 6P?u3->3葟eyLg&&DtNq(ߌ !H080ESyTj7g}th|!DJMA=cťi?a-7Xf~}=!ihB 2rjt%[r, fW !XH%,$E #y-uᚤn3/cg=痗:tajxVDזw)YWsIoޟ?lo F'+}LՍ/Duq'OT ciZBK0W!k}BvNOQ>ǃj=u|Bα۳Z}BiJƼΙOQ6oJ#ث( >025G 7 2CR]hdd(PtzJVwD [w͙BP01߆nC FAJJoih̬:$'n'+usB $Q1$[ۗl/07ͶJt]kE{>y9lW#Kgwd[ ;ݷ〞^A'56Jű58za0>JEܳ Ѯmo{ $S[G)Fiw샨Op3hR+YLT0s/n&C8;ƪ6=6S"N]7;z<ţ@v#A/xR{0Xm /w%^f/jԞ.c Sߑr~teLN&\Sy+1~z>z*+qt^}8#'&-yZy݆@+ I eہUɍU Bm:_p '`_šr)Tl>2f%{wsnyYdpE 74ME^ Gش72|5S@ROd #!uX>XG2i陓Kp%z j=ۃS ڙWʅn-9h?]T˾1OfKDʌX$ZZvuO :+-3@VNCoC SџCpBX{c?ouGk2XS# 0KdB]=SX:id1§ 7=/WYo}Ǫ4FɤEuu] ʬC [my!xxΚc%k* #3p׎W;褱S]/H4q=ZD&vn_ukɭ)^{T)')ktYR*A"e7bBͅ%s΋lR-;C~yh`~J h" ]y(Svq_tv뜾 >Md*qF\}+|IRҹKkNQuoIt졤4c)LnȄy8m5Ώ  dD (VTJYA[ n~m ˨">%l*:f$K. {&4=a 5|/~|zJ Ð(%ZwdLﺲ鷥J`!25L M'ǎUio=$rr/d\$|1k2g?!q7K&鿱䡁A=slG}>r[P&yD\woR%3p/!Mk3KV兤C/RVbviu6}/ ):YMY Ħޡ'c5s$~әH/0kWܣo*Nf+A3cÚwFsYp&B\e>5dVשrbu] j1WP»](27wlɄjLЏZ,YQo",L ́{h1t}'5ҋ$+wM껧 POje.Oaw}r;R(!(7DkjYRߌ4Z*ްGPd3 ㋭b F 4b/ bÄ9*{R㹿SpZt!{lW|5 #K^?r&OȪFiL$_ ЁjG طԥwK̺ 蟂]I,)ւ%wXgG}vߒ]7Rv8.A@51X5P 7A_҄| 7? PzR58xqZ^d1VU5C˫/3̇pa _.Ox~ G C<{\_m=i@LjRUQ/#\mʧ?%escbL,9;_VV%⚽Dd˝ٍ9T6mmi5ײ*3qK㥔_UrxNo6i⬅z)%HՌާڤ E5H{1mnEr?g\ S0QЛǐ,La4} f1GJ7y?˃ٰHBpr}a=3^2Q|4 #`S6O>[DQ |(wpLB96?d>mQ=*Q6%yؑJ Ts ⏿Zi.ձ l{`Q Đuy>WniFhuAEc[ʼn+*kEMykthlWqpGaFTwȨTց%fmLUK?|ϱX;  Yaoóo>~I{yRhҼmt"x1=m ><Ș. ,h{m \ҽș0~ׇrr};A"GW&_P; ֫^@|Nf9qʈ O7۪՛Dߠ-sIC};8*(Ry]<|;uJn%7% 1Ŗu&Qx~("Y1wa}Wrs)08E/R<6c@a6;[(u';&KDw URƅ2̠奱eˍ0h vQIyz:E#gq%2<5uK_%b=bA!6?bV0m[۶ή\+#> ͪz] 4LlF&8B~|4Z)g 2GJ= Jݟ48)X)W3_NNKmF٬Q#ǤNt sۚ\r%Ul'JaZ8vVIF]b>ͫ8D^Uy1jkV! Hph+;Qq8yK)kyKQ7<א%~=up\w<'\wZ?PNq)"ގu$f8KzdM_H*8cXL/UHacU2ɟ5oMÜ{eaK?%w0Dy"R}KT Ԯk¾1Ҩ|aw2J+, Rj {ARQ"#byl ^k)DrVpja)ަ<r!E5='Y?QQzj2S( uآ(ZvU K H lC߱`jg`];eO2jQkh y eY-o8/ϗzNE%?\k6cfhn~`-;pH:k j]Zl,px(Utc*E ECNi9s5,7D,_ÓTbƳ2^1i4:"a'yRWb4'9 ŘWnb:_(]y̍2}A*Mk1_3yrm4xX`Mws-4[t׀ZA;-&^L#9M!I1aSof#~Ow7Iv56lV p{Eكt̿3)᠍nÞ3~ hP4tO9`YE,Mv.$(T=g8'ChjEWN̲pt7dڜתQ^V- @-²:7G`zgzcv/&u^PzmN&<+l)ρHj qɵ ő*=8z$n9<1$yዴÎ>ݑ#4 dqqՓ!X2(YXMORG{j'̴{ O >.~dg\v[eWs⟿ 7/)A'/%T>v7M2YU@&h~!@d-/!; zL[^ 0bs7-:!Q:-Pßnmg6*!@Ann\t80m5!c੺5c*P+nO:Ax V{q\dڧkޥqC Ud%tZN I7| bM(pK1ilέs,Ei8"HUworn-,T}F;9Ɯy'Ss~_/K8]3xROYypG70.𖆎MYGA?oy3.̕[^̉=Rv+ STcp*uoSrˇ+I ɂőʼnzeXn"\@~Tlk3Kר[< ڐa2Os"Nd i jY* y037QHMk)jB(5Y^j-3AK8rhA tgΰ`xxsp?K{cg=>[yy"JT}-dk !p;Y}Ɣ iJ@ZHUn+Ljrv6zX3?O Ԏ3afqxf2MS@FDmƾQ!:OeL&ܲ{!+^[vqCj,|.Aj8~Xj`lNGUZ-|)gKQ$c"9qHP: p{L=yeˑ|f6.+Jl~gޓ!zNStk0w0LċP˟P73R!l\^WMU, A-<{Ir] $P{Xy{%k%ZDB0IZ({!p>&  }Y2_|;Nq4VTmDŒu_g^:Lʤd *ұi*KN'Axcj'"hxqdk GjQ%,b*,Z|AЈqd nLI %8pywKSs7QWV#]Y֐Ÿ~Ng0=>OLUL'+ww+&t Sn'dCJ+uQ[܌Ntb"g4Q{)Blx_1WR_I$<Ұ KwJ{EQi {bdb&֜eoRa)5*C "pTzYb/VD{TIvm؞. V)yEpGMOP32lu\u('+Pj{]H¾N,?+n]-ޔ#Y=Ͱ_Vzw ED b5W/6{Lix}y7Ins Jė J_ʒ͋aKv=gxy@[1LgBS5ޒ_Tl[UTNq30:_+ u%uݤ ; $5P6 X ɍ SsGL:lᄒXf㪞0Dmz~j7&4}C[ ţ'_l+;S"QM"ճ{|>ZbV"Lϩ~:1,WH]fTZ=T70%Cwy5G(Ju@[2R\Fb 1>+gSfPY_f#ec .!]/?K a6XLgY֍HMR[YfۆA"NC`[G[q;{'/qiHҚ0D!6M܀o(~lsW)IqfC)#΅d4:"LE8Z 3K{/k=sR 1P-\dlaVZbF^YIޕ|xK8R#%0AYҘO, -BCu$<*0B͚0\AC 2n8c"m_J'Fk_@c"ǒCGO?*!SUċC;~FM'rS%ޱuW`h5}H6/M* >0;~ \涭L_;%}±3`r.~xFLOǡ+n\/LФ;,q)֕E@/oԈB_x5! i)0(hRd"р;Q4ViuE'R^ =G*O f=Do5uy/,p{wǐq{M#|5l$MIDwҔs`0W%&YNlwڜO_|@8bRq&9͖ؗ>qS\^AbŻ<%jnΒ2[!~„Uu|9n( %GsIqLz5iM~jSEՏ g tmؗ$P76"V1D}ΆV-.NR"B`zqha P@߳&e35N ME[`"0ss}|#LÖrqjG {ӛrKD*$o[?l%oCsj3bRlqݘn0S09 NBDGFY[#HRnUZ"Ǝwbq"Đ_@F!AC伲PVRڅ],+}^}Y)N)2fvC``ٺ9!ᾍߎ*rh|xt"{ ~Aun X\=T5w$]f,<`WdCj Se˃zBmT] a_NCTNR?OU(ݾfaCHW.VA'9zZ-F[-%=v "y*f>w!y-!jy*$}=1ZA b (a'>~{ɐ(`Ybi"_"#VRv;Ƈi gF*#4-n'1=ܹdLrկH_sRgG\@RԱ[O8rrpD/Duŕqots_fύ\GF5š|R޿jIՌ?l3j*qUEt5ZBd00~'So#zk`1dhuקߓǞPTQG%JK!!Oba054ҁ\PLUž i$i +xT' ,;+ch>/t3ssAUH %$`zE-<8d*¯$oȨ 6g9KQ,%ÏWV(H 9;`Gy.N$}0*q혯ZH5M: ]<{7N}R,\߯~nm[ ~Іej*&Q8尖ʹ֞U79nbrbQ[YR3+:W1b! pWev`PzW uۗ5R*|idT2yP!QYШ!gYTQ#\>}r#-pS>czDB\ U7S 5bBW! N$@'8v>ﮀ9޻TDtN~5zkndE(k3=)5KߢGGiA\forPJalZ{NP8~ca"S01XlQ.݈J 7&l]Vz'Dnpӵ1棆AajNW@N+f6ۥB+{M⾭yF|de3bN Y\h-&I)vf!6$Vz}P.ǁ|dǕkCi_а9:m~Nh{b 7Я|0~J ѓDv {L& Iz3_VgdiN3 Xfl_k6Xں-|$A:ܧaN'2C);Qnn$ztkak9 xwD{bcذQROoA8{Umb*Egc}1#xeiQ7iKqMQs?G$i*#+ ̌|D'OC^ɥ ce$wY/*MD:6Mcc*~-ɕUdf={j_zoz I6IY&z&1diLhaL? W"q)B2HΏ7nE %PIXH s>cz`E+Gi8ܣCy%d L QSSzqFuqFې9PSnjVI09XX -B,+|#u޵ $ߜ&Oe[T Ҷ]lBˋLYdKZ"GK^t@ne;vKG-|ӉN&*ʕ̴l3&; '$e}_my!{$V7n5l @nnc)73Fhǡd ŰO7i ak< RGImoEL8E㩧hFɲUF^,Q:]ad-2f} c|bo~`m{C^ƒϭױǷЌp ` OU? bcGk3Jǧ' 9s yWbD*ظ׿-/*/w77`P AHY/0@>%@\/᫢*hx &2!%Bi֎!K9d-O] }+Ǯ#!H{![z41>0*{ z>yV?\d <&[J2DNelcood bZ>r2Z&o 1] X3v,&- {FG25ȹ,8{u.ˌ3-N`*7436 kƟx9 qg{ jZ%dV/?!d?iCKa|eU endstream endobj 1682 0 obj << /Length1 2642 /Length2 19270 /Length3 0 /Length 20790 /Filter /FlateDecode >> stream xڌP wwwww`pww Np[ !@ gbi}Wz_)4ŭ-2N,lIe--v6' 5_9$,2*;;<vv^66 R^ +2 @ D-O%=ow# diP6:3Z;4-A@ A'd"bf#By4@7/௒*JcAhقt6w%dt4.@+ǀ Os,@ --]̝|AN6k*0woer0M #0WO}n ww_5fi'+IgGG;_@n@Kp}Y9\{'go'"k_eXyj;\=R؀EHe6@7' Xڲ@/1@g5 ` Bw7<<*!@ wth >7 <~>2Oo󿏘UIV_OAUJH8nN^? a񇧼3?d]/a&o,gt܈o:zAXMp,2 ]wq wJ ailGמ9jn3;с|{Go;Q%"'F+C `eqrݐ:Rn_ o `R?U_`U7F슿8oήF">pv]7g5#.oF`.o/s1~".0swhY9,)[[g=90{7xwM)տ(+g?9/*V` $K .Xvӵy/9&6@0O߬ݱu:a`Vv@IK!ve^-grt뚴gu/vvp..#?=Et?0[r}V\8x,qDWOgų4\`;Io 0wsw?D~?X=l݀-Ro?1<%/;? cCa}༾ic.TKO7p{=~o_a@%ʒ`]sD]87ޔ4R;AYoQK{ 7XEӯ )Hop#"4 ƚ8T_U!bcb<`⇀<> U`w kg=M3f2*MGocU|V`OO~4OZo#"muH|zv Q# (˫jl7}2qV'|YF:vYn;/hu6bQ?(᪌7׋%|~$mXv)? pC1-(6 ܽSfU/6-s 9}poZShƆDP$f ꎐApaYIP$dMq< j.\&:uGa]>5èFbuqdZ؇W5ۆ$VeO,4$4G7} ե2L?ȣjZ'T yzɎy*xu\~ݰwr䯞`Fv' ,mLzB٘q-V"Nt鰹b!섟5˘hf2d\TES<&@1xppV}6jfw׋Y驾@[*Į&0Y? *OV^i3 Ugec?o鎄>M r/Ss_a,:}]j%y4R QcN[ rIg7W?EHP}?KmӥgxA!dvK*XGH0@W`OJSy^to>T`ΚAe9<"+Ң+nϣҊaKo0 (irrhm2/%҆|;cq {O\tf^S=R2YiVWwk`3gM2>:5Q'm6*Ja .N3{=,O0۴5@Ju:춗b~L|{ Nhv*2 4:aZ}bUZHf4$tC,IE^!flm.Sn╮AJmnZqLr7,մC-D[AKXxWI/MKPmXX1 ~> qoCbqJy/N4㮼Cj& D)l$ǂ2[{\e*R{ZKЁn-|L'T׾WꬡTgx1򿮢sbʢllVQm94x!(0'~S'sB4@r 7u^/g~VD J"̱B(%*˔mrT_jE6_b_'(і4'2xW kh|Q~V\)% :HCf-\fmtu ?Ɣk [hQZ$Pˆo^*iR5> J9A6P 9A磙e0ǰLbi;PcȾAC+n9xllmT+1yMhy:w |$mndcImx˾Nlט<ܤ`w1>ѶN< ޗÌ.yhtѼЛ 驑|kd ׿ vɡ 9 oYrl4MS lnavfay!'J9{a 4-NBD6lNQ""OU#x<˒,A>ܾaѸɟa%&v`"kkZ^AS4/$*7NxFF^<ƢP. N6%a*ŵJ/ɑӪIꤥ[6s}GT[u{45鯀 UPc{*1Jn!}h2wC hX5Vxy*~ݹaܲA cxZ,ȸc w?is]֚.Fg n a2ˇ4\H*<3OM̡=wsjO >-|_G5Hmy~5č!&o>Iz0Zts RQ o;~y.ߌ{Iծ7#Q>c+.hqƽZyQ'+.;W&|…x_i{3%vcrJCGAPqZкoXT(") Gς)@#Bi-6Π\LS8֟p\GIxe3m[hhQ Youizq;t #gGxT?pՍ2O$lX/pǧ"cT#=mǯ"o=̝h(-~WbFՉwiHz!V%?LK`p@R5d"DkN,R8e.7mVEjդ]hWC?lr4|*ѡVҟ h妣 4 2.(6|Æ5ǧQe6襍OZ7.HaC1Loų4&ABZ{ieɨ'f1S1jùI7Z FlZȓd#{*(͢lY.?^[ZPWUDCz-[}O?ji:JYk0vX ^k.8:Ƈ~kP:4Η Lhl<'m;hFq8@n&V]Fh~RpB Hk`d5ihgOńNCY-Ut/U2zpЋ/oTݝXm,NScPg@~9n4P%4 gigahÍ`OR ZyDmQlWz'͌%X_fIgJyhf%`>5cTp{iZ5lm jQ;3 Q^_ ЏON#jKٙ7|sOͨ *7D8N B x`Fu{,'wB, q`$G g@q_s͛8Sdnt5IƲ* ^q+- {1UE?_ ixGot~~'JY"X/3*]*P=#_]ޛH^o-.3AJ+ϕ;",!U㱏B<02(\IoAL|z#TkokJY$M<$յ,S넲oqE>(eW-Ed >o GYPɦ=c;"4E' jH{.M Qb́&A_6;B)>m 9vz%ڰTRU0NoGtHX\Z#jt{9PԁnO\]?"@̺9=Ǵx] cV.̪L-nDkuh}qP&@v+IJ^֧_QMiJC <.<.Q0WS5r++cb3-`z&G> :M`zF%C&$cUUrആgtGXW=w]9( " Om'1LEwlG;DcTX\*88@Utb;n<;zרz$ TnbOcͪL%6l+\/P(GY.2 *)߾rvgћ^Heoᬘ'4{ц311 E+(y-C5>Ò 7cВH|A]It*Z>otjxFi15g[i>x(oZQnggՔ WA"1Uy &e 0թ}kQ؆"ZmKΊ0k$6NIdAU1/J`qQ~ޅhy@}'ς`roE:,UT7,큣K_-gwkNo>lM-]E = OB\d̼?NJoў3M{4STs 0$X[y} :\L"C@rt8/NX34(d< +lj nO3{*976 aao?d}?Hgx\P.|=j ,2S69NOR)?h{SY嶙[ir َ2B׫Wy+임i1J>*cG0: .MZZχVy,ܜד$0xV@a Ad fָ@Wj*aސ :o{Wp²?HE˿ m@={9-cGs>/}#Mo}]MHGh_)),1}=ր gm$F|屛0^k;"Ǽlh6 ^NAb!C7Zń'NMrܻFL?K u̒@M~Z}sҢ 35p#t?xZEy6ȣLwP *_Eͩ|׊l%N. bUj;ex}M 2Tkpszi,0MFaz^4Mȧ`|4mBV2`?7geM(siTtGM "V`y^6kQ9\^HUޥPN_7veX/CG%"5UεuWS`k+ ŎmBnM!* 5Ų .ܡ81dũ>@m~'-]% #.*HD'҃Jy*Z|L̨8`99o~ D7 cb`4%奠*[~qk|8mТ%m>H:{G-&)Yec0Gs^M( `}z ʤ@bU^>~ORv^/cuK^?yY ]v]$ JC$b츒87Qmp);ijr i9‚OozxtScm1e4DPq؄(bG\9\/߿=æ gr`hr8kpZ;y/:}&rmn:_X&[nhBĄ/?+sb$a5Ak̦l '/dج 1A!,Lvc܆B>E\ 1W[xD Cˆk"i~Ë/ 2㨪aQ[i@A'n+C7uάHQ]IZM M !1IPl%2NCRok5O3t+5a;S3rx#8^3,{(?j&ALr>-3L~y;чܚ~9~Oc6IG&g'iiF %DBGk/ ?oJKgsC#"[HBRhĩ5!\@ TS_Tw ~:ԄAYz~9f~0?;Bsg!j²SL>g-lqV0-֏NN]ٷj|@A!.׌nO\('>7.zJR犯q tNogRW3s~K՟p",9aHM wg>Bfj>/0#[]d TXЅA~T~5!R˸";d*ex˳׌7C9OF{oȦhuUМr[&AW3.s$7lmlMB?+,CO7:$2Pw[T""J* Ws g$H[|I%hkc.+ڞ< azdk[coRsDink|/J҃mE{JBFbsy2,b̿'3$p_kLM L%X`*GK[sq}NLGI_b2[EFMpBxy*y7VO许(쭾`s-Һc %/PJyв5AOEh6?]ORW?uKa}eT387;mBY:}6}2]|$d NNq5 Vh]|9 ,)9֫t}MGXzZA:Y+i,Z^Kڛgr_]SZ˦kI] {ƻ0n&[MѲ\â]KfZk/q!W(ޖjmL?yO6Zүt¡s͒h@|3jj9gZ \Lf!I0x%$|9‡<υbŦ[)KRo  jHt$xUqb>֛SMCRY)oQ? ushp󖙄^UP$SM_+SvNG ,Q ؼ䏝~\>aξ?q->@sR}GǤPW։|>FV`\vk\+3o%3"H{-8`5_v=PeRsUT1c!` V^`B3cuZWƾ~1=|jv* R}w6g*X ,324svZ. U'S lEYx%-T.w浖sT?z>qovʓ'aE>|U[}UzElVZK+r/kM(Ix?IoDP5ƭlp3:=qE-'}EC6ҿvuht񱺨[Gd1! Z$槵G]6([<&le I*$ΩZ\aF Y\WNin`te ŸP(ĥ8`$bIy.Oߥ|QaѵX|rޯ1IK9qUX+y 7XB)XC ׈>XY:_S<Վv+,uvp]ܥn+#Έbwƭ84] 5Pm$l@tCQQV Va̫pjjr 7ҡ14UMh ڀ {䟐Y*/*՚O0R׼$Tꍃ5r76UHiSR$ :+:5pei9.G2%ܦ;%Mr]`qLv-~Z!*vElOMFrF^[ҩft#QP+:g^v+uٗ4tԹ#1P5viԍ/3?ֱ*{f>'}4-xD!뤨%$re*TߒRgq].*d`S~~N+1ߣUa!^ ک8}#GO`p5j'񕛴_o;"`r Fskvt]sU-2|FE\37#OP1Lʜf z+sf^ju0:z]Ρg#\}DŽbF/|U瀍, ǪX秏gR`#~woԝ.VO, 8DJNg*{9V2 ]! ]t8(ScR݉$T{8 )YX)4] h5Iўjil_()Ƚ n|TBn~0"&:-bO}oK} oGCgNH瑉2{#l.fgݞb̏qGhv0_6sA/~cÛc#mvP tcbW쒑VHloY9,{  YHhʣvu|)V@‰|gr#c=O¯X ow.Uh%Wc>8J,/05\cyViP&US5aXΤqbL׳{.@J/1&z̎'Na:h#]ٱn}O1P7fQ NI`Ptye<ⅆ?sI~q* {_Hi=&>ý{r԰_{C,-nY/$P* SO@-off㞣K:=~o`/rmjC ?R\@|Ql9X76Dž_ۻgbŬn_u:[Ek 3E f|ڦe8iѬ8:9A cT4p +>a^vT'[?e-k扵2')M/)ۋ"O9N:fnhthHVUvXv u/ޥTi>Ʉ4 \ҍF4+#y|}.uۭMb5R!cE> Dj"˧/\焚KLӄjc*e}sf 4!z R^j=ZX}DNru・b3MIXᾝ NwkY+%#{,n i?^y.xh)gK0SDQQ+L&ՆVDqTޙ󓘱+De~ #s,`8=x|Nɠ!W&9WbǫS5r'%ZΠvA'0k+ےX'OyB{1ZȸOToOtL '~8Z+'µ3y> `Яtn|,A8;?ϙi IyQINrSK*_BwU5STᜫNƿ6e {߹z%{ 7 si=ł ̇Dd#Wvc!aD-LGhSd[KcLrst!;PxEQ1 ʻoLe[cB3o]w=_v1dGX͑$`\Nyđm~ tzub67$c\U5 CTŋt4X68 f8X8WlyuLJ3crLDQΡI_<0j?rfV];1N+uWA۠AʭaX$1!W kw# i .TE;jж^=՜w\hAR,*"%Ϫ^%my O|[_϶~{JrZ#L+\-̅<0&P*30&}ր J=ТxXsngM];Z՘zo' 5]@ɖSR竗OZYHBU]BC4\W?BV8$yi?[밵fiHH9!Q"(eG< ,3Oq 4< 3q`1{$dJdbՋL'ۤ.}z=t%2IO<-,m퓑\[ l%f!LMXr';KMsԢ4 o;NOK!ƣ'\܋B}*.:DGh0߳PYӍ [CF >"O ?aW]2R07KvaY7+ CI$lg(Mzr4&MJ52\$tP6*=Y (5K )VBZiSB`Vla?1sp|,~LjGt/hwfs7,M+[ITM=aOFAnҮ~_dޠWǎǯ?P1pܯvĺB?:G ԐwhypJhDG$/Z=Jh֋2y-l^Hd:^'vA0GԖ.ktW3pwM|Eq;R;" th^MkteN(dp9JޝE-_L87*#L~ǸVAS ڿ m;JnDid)nX]ĥ̂l&@&,9rH+23e ^8M͊hAY*OQ+?#B5ٷ[2T Qjc(9w"\f_ˁm'5Pye ;^(ooH15dnb$U nq<̵$)-z#gгZߤxt9'Xr=!UCM;fΗ6ml=XG)86LDu3JZ2P˶+$W.r4* 9,}}AqjF8Uj좚]V#y4zc04z<ɋ􈑀GQԝ1݌ oE>+abvH7m,>{q 1vJ'j.> Օ1Ɠܽ|+:^&ofW-NGm*‚뼷RLU~%áK( h1+;01@Gx3tp*yU\VKǃ=23 -':UK_%# }#tf+^tie<QDy栌"KjʡR3Jxx%4 pE3b}ʁ2i2YHM<rYFp9^'N0TH_ YCzlĜ{iʪ7ET$_;O NQ6;AIgV)i qaUg%.kD[~$9U+e[f;ĈZ,q3,YonV Cw_x? *`C3)ξE!ˆڃ_ kFÐJwv/#I Ys/5W6t$S6eHfV4ġB́>ׄ3粒I~X1T$,7=hl!q>̝q1^y7ڃȇC{ʇ ؽ~*i*Gh)g{yH`";KZbUpڤ)KVi+vT.lkMC4 Č_X78F:k$ o(8E%T V;?6L;i3 tK;Wƾ:zNAƀ- EY~>.?hygMI'6'{%(Bbo;AڑYԭ>9JyI,xj20.ioCYՑ)Νմ k%y`5,f]k{Ӎ{|Si\25E(3pĸ|9?j]: {ToJ<=ԧU}rL7R,ܷ尘e5<>ʞ 0i[ 7vc 鏊_t;#{h~ fY֥x)qQ$/2i(ѧc)!I:0G.^QFa43cc{ELcdceޓC_poB~28_:WuPIJ%& p,I+(7uXwU#oIo^y״N.$LГ>v4>1V8ʒ렗mwݥBh7V=vVl+IJn :1qZ<\ !Jc٢|f )~>3k^z}f7`Gh.SǥɒH0(*ߒgN6g j^Ax d+awS)P8Ve2X#yyiUvc=xj"[>m}l&a6xvP(̆˦[q +uE(젓˶َs)/;WIV= j;YHHb!Hh mE|SWE{_ U7V>GoYb;=bCjed01A/zX̪_gEte_ߴq9ybxU6z$#~ξ1+D@v-tzZxR#pLw N %,"%%\"ZCM"MDϘvry%Mv4/敆@dC_ru- }gu(30:> B; U^tRL4= ~'P-=pJ4|vcfw7UyLXؒ9OYN4PVN}{^zlam.RK$[|yˊ8켅Z?UN9.)!e>twSYizavEX]<;P}^O#]\j=}ZNc lQת2Qխ{+N^jAŎrP;kN]Y~9g-)KaS]@l> ͠f@ԗfM-f(`@8ڬOpr1]MR +:Rz#uֻw]E|zKo~!_0mêDH_%޼b1_ L›'=md)9lm~qðlN($m oiyO6G@_kXS\Z;'e Ǭ_(BuAQ Yog"|_‘n_OA1,MݕYצv'()Qޞb9yu?463,Q`v-XNXgЯh^$3Hue)6"|@٪G()2e7'ہ"!ͨǧX XYr/r5zd.!9Mt2 ^ TPa^"u<WYY16YbG JkC/jqJ?3?d+.hJ RhÙ~:Be7F]OY1`aC+U!6eB^{ϗG]F % KA's}?Doh1$Ji4f*gH(v.3s:EiG=H]gy-~[QnNj+DkW.TW{p=eom׮PA K>݁?󞻾nwD##(ߘ3"ޑ3?n䀲ŌfȬgYh>.ۍHlf(sF$]+(1*hK'\ >l#Y>j@k.`)B2+m!{zQF]M\8V"է ƥC(. b||xkYgQL4_) mҬLϖ<>ɩY0"?`zB, ŠKy_"G 8/NEp&e 28y*Nf1lvcC@|8V6j~cMVn jXcPY?j z+t.ԍ]ʃ^#QDϘqp` {'HOn{[k;a _ԮV"vبsqU[x+N.d]㧀-ґj { "X;@%ZJv֫?ȑ 2V`ltX5*J~QЛhC7 CRv4bf ݸ)iZDi:m !^թ~؃t5/섐9MSm2,גc D4~gF O98٢50-g!d*'wD@$ڵ/\0Li*չM7A$qm`$ F]]MQTŅ6 Mam :qXrU@^/KL$aPADC֟SChJ7aYx14WEwg ~c1ա 2[!CwjI]~toۆh>\e"ƉawR; |3Ugp6*nVD..CTT endstream endobj 1684 0 obj << /Length1 1783 /Length2 5186 /Length3 0 /Length 6275 /Filter /FlateDecode >> stream xڍtXk> mhVbt s0bm 4"VP@nPIAq_]mr*!PX A"T`FFq ixy'v^bdPMN °@ HIY, 2bq*`b&`]ph;{ (9ph{3#bh_% YC E40@Q8w>2wFM0G: 8 Nh 'a(@jh.(`" b^ G .pcآP 1p'<w෈?u%}N|xBNg}/CӺIe:>"U"'bX.b#xqOr,Hy-in+{xm796j[M>Afف/WOW,&q򂴴i:bJ}< Ů8v/-ЩBR g\6>7Kjt}3j7knE^f5ڨ\u U-\tM#% !;Y1Qme)xU@ZheέܫxGf ]CR(:'v}s%24ް^b_OƷ O'z=(o'mW/Emgggn.=1+ ŶćLH tUq %z\/1`>u}ͣrB>O }׾3 S=.nj>uXOTݳz[Utx& Bc{gj̃-;"W[L87N>\UjVr11jא]o82dZPq+&ɞ~Ş# z)g{FȲbJQB)D586%"4pR3-꼾=7LpgݨY3e,|/>{׎ ,w;.02!Ye]?R+Wg9 Ő)=V"ښmO3Np\z/,zmB|nn"hեeQ7J- ~/m>jC?o[SNRTyМśhg< l"LM&h9[ W埫u dkԻF}S+[ͫ4^ ?Y2`Tlƫ&Ü*76^m UrFup ʅpܦB9hx` Y0Ixy@:iCE5vR櫗,_(L([;$-<| 7.{d,)Oj7l#[W}OVFE$8A7v9yf,յ, J.7jvYl[Z5i w[mSo*KnVK-hU* HLҜ. 񾤪ڦ/(&+SR-~0NO3rW^ ^J\r-v$O\E뽳.V#"N3d1ujm'JznDFD88_`m:A}qMdkRezމPU]?p9.P`ka2/o@fFN i0ŧX3PhfXe'% g忮Dm3C ǗEcsy-e7҉:2ݨWosĩ$uH5e6$i85;JŇ3]s *"H,D_?8^2U?U&eĊ|w iVB4ah7VTe`l@t fvj<$h>4)-A.=Bk)yhy%,coI.Z& \1 5a$Xx@T=2c yrIWble3n-[Io)u9aݼNz<ҩ`bf`TiƑ1)@[ :9[ t j4bCY,ZǙb7`#dEjyC-F֬VℲrF'"W#X̶bَMp +Saka3|EYӺpR]z x)8# vgyPeG:kEl]׬=-!%VE{o҈X%. v=Yr7v}ЉineQʎ)O+dy81K+ĒmeD2yuYaYH6S<u#Q+]t ֶ͜V Ǣx֩+ *% fDg.) h}M;o+}RÄY];pI`.!RSZ`Hs=u&%.w֑^Z4gPkvf&%Eפ%6xξ.Y eY }Ihw%AML9FiI橓>ҫZdgDHwVʲ2/$"T[ԫ}2$j"`af]C J𹜖1saw^c^ImKޜc~Ew3N{S=S <'+*+e:1;fWܡaO%3|U~ B v`t;)CIl,`n4b<'79n.5 5~|a`EZjx 5ɰQm{B`b󉘋_/ɇ{aM▚x[7G,C/2on^yqD ?`=9Rϝ֕gЋ*oۼE LhQfIGrp!DPbƅ1q73nÜk-4SDZ]z&iQC$ zːn:G~PA6bQGkQvѦA\Ly:#V#Ͳ  %^گÀ_ad^wL/0`=[>+xtj[HfE$n ڏ"?͚вAԜ/ Pg,_0M2Vtfnŧws*Q IC tb 6䰡Gj),tA~Yborf>ΤIԎza2 -+?@үXɨF?fe!:I[tt07=|5>uO}΍dT6RSe 3vκz+_k0L,"vj]#n19Ry㓝54.qxFm oSիPk-ehQ.sEY%\q0jиe d=ی֏͙[lϡ}4IUf犥 4 t%aD@DShj04 ;;\VJTkW5y//u 9χ_`F6*++)Slه7rU฿ ]iȘ+tYk͎>Jq85]TXI= }ިfxz"LBP!c&kS8.&?r|qebL[kEkEi˜N>TI{f, :Tt_M;B#N/] g9=K{NV6$̉}35|%!ثp.ǢnS])jC>څC[Z@g2Og6 E<یqc9F홧P,bO\ {2/g컜Βru5zؠWţhhax:}bIW>n_?1z`&Y>X]pܣMK5Qr$iKFp6tXi#977u.L_J+Z.$ b8hٹ"7Pj9dMfQYzf%FN`iN bۂ>m1$f.1..WqƸMFtL{ WԳL^7L|תb{gRm*?/M>R>Kli>SdI"f$z?tT "\zٽ~if;Y6:F5DQ>~5o/چiK[}C.x>/ű=ϟ"zq4t=O*dRQsM.9LZ٧\5XJͺ9VWy`9 +0Ȓ<]|Myx#[6 cYWK E˭Uwxr OW}ټ*Amv#cfߥR ^q߲1>4s|V$c KkӠ>~kF2|a2®8О=yY ;0hC0ekơo3,Jd~utۤQұCo3S1~;jT҅P @3uɪoeIpQWwx[8ysS/Lέ Lၕ,i';-JMv$`b -6$q·FtϽ/s٬ LʴIE_tt:Յ,>g3ޕ^JU?++!#Ŵ}jt1ùv܉HaFpRx/ O;ucQX0 z lŴգڍ٥Q*vW|g-ތw^kMJGjex50Bmhf VwR'~yypbZ~Ȕ$)yd&6_Vk51ӬL u##N'ww-'gF_v SJlaQ endstream endobj 1686 0 obj << /Length1 2084 /Length2 12525 /Length3 0 /Length 13785 /Filter /FlateDecode >> stream xڍP\-hݝHw [p'hp'H{q䞜{z{1}9njrU fqK9P&|`cdac@ִuM#Qk]\mARtrRfnzoA=#+`c"E enk xP9]%AN^.6na2iwZ9ޚ^#Z4@@7rA'd$brgxغԁ@w%f*cAhغk<\Wjv^4*N@ǿR`; ?Ñf '3G/[Gk="0sCjonfkofgfq5kjbjkGy$G~R.@׶{uv GEXXm@yU^)ߜ5 :6r)~ z-gk|Aq5s\@? !,m-@k[G_i_]l=l`ϓxY~yzZ:ULB a0spr8<|vjfwl-@r}mu^ zR,@{ ٸ,^Om7!b? # v{%p_U_+hi v_;ZF[W[O͟NJ:UA)fv6:k-@7 u8>쯋h s, Wku~+  ` X~#~?*qX~#No `UxJk5? ^}j_6^X_#X_f| ?3u;_klm_ӵ|_5}ߐ55d@Ky}}KzNůN=77*CՈWƾj8Anr7_{/|^gů7_ז_[/oj/z kU,.=p.{ݣ?K@'ied!!N؃yN=ϊK >6+xV) K>e%1K9l,ˎ}Ʒ̲K%3;gKWmjwiz 3-zlJ =c*}BmΧG䶆96Eͺm4t,n3%,}a !lpevIk*R`ϯǭ3Ez-CqNlB#!L)D4C ,R %KUVj1e9jYjiG^!-,H`Q|m8qy1Ep*9s+Qpgٜ[y%*NUS4*4/m~;ܩtQL>aEǏIsX*SR{ΰwFI7WлT MGS!qix+8w#Y#=;G) }jM 0&J_vtǬ)%e,qQeX=itg- f]W#@mby)m7A`hbh5 [@q~ї&NN{G?az$b'aѢ㝫dжB_ .䥅fY=g-`80OY1) _ v4n[vW >#lj"%$ x!J&\eF;r[mk{q+_"thݍq+&y )i@̓ɗ|KΟ ,FL"x+C sG~Tuo2+}z҅/S(yOxe0 u`(ҽY7 c'1S6NXn}|qݦ! Av.^\U8@ɾ%!􈧕|~.?òPLh߿d"YT}ùWgrMقQ?}(Hd9t?l3θ (GfNc)ƍ8{,Om<^fІ}lq]ҽ@e5:<< ip w?|^|r!W6AzЃ˫;)dU[sM1<:2a˜'Ş6 iӀw-#,#߸dv2 6>>h}#XхIEktwhn 2oKlM˫ }>TN2'>8< L7ُ.f;lE㋃ b0qh4'$lHlǴau<߂74N P_CGS.,Fp~~'~8R}Ύ4|lv.8"Uz)MG>һȁT/Aff=.nǶQC &|ݙ-P9݆E X͚cg#b1ߴ?7d[۷CVGKS+B{ okWn#.k=yJ8[Rΐ:C9N?r?qdP7X&"*PV8+lӷJm}9oe MlJɷcZ е}զeͺ-ɥ|\/UC=v:ymЎI!;44\ȸ>)܀0hoWOZUY Jr7/Pa?Hh'm͘=2N#_8ZM64)QB7J4ܓ./й֓ӁL~L?N 2dH[3tI(~͡A>SѠbm-wa՛k=hr .=Gȴ ݠE*D@S \垪x3s?GﭴO&$~z[')+)0dj;G' c{j( ac70aQvWh$9Ś;T󌚦ga7PT5Kx3gQʷ $[V?dBݩWIp,yEjf ^@P =b^H5֜x Xc@,"`c*BALJsOs۝ yEo@ZOVsW> wr1_c(6 QvWFI5 pݣ`s ejG^}1>DL-(}oۛak9u*=ʿpZ_"!c0Sq#;6lh+ѵ@o.sXh,YaNu~ 6 #8GwiGIRi$D {Qn."zr\RV-y%+@fWի#U,PzC_]:>x N4R#e{E*RC:Z &ԸUM/G9GmtTݶ.|[&XIsLFwQPI|vD?!}&!hmF=hd`hςuW4!ogacK3DT\5a[e?ϥ,嚼ϰ}v;$ao\X[nGVPnHs y^%F*Bkb2B,F$PDb>lA붛|Ds&kc"jEENP54쇵3sGB|&()=[U92Sǚ!}(Fl<ۯI26Z_ȑX ܍nϼר]!sWnd% J8xG /r=89oĩ茤T,VĀa\y\#jb'u2^Yb.ou[Q3UK"cQIM+Mg"Б"ul>=5%O,Q'pnK4qDOI|} '}ր%ćxf&RP_vETg!{=)MEZN9&ү# N |E)vs:#~&FU~| *fic\VW?|ZUev SBUC#6.b}P:ra![ on;w\EIs2L2L/a:f"-W'%@ĜrZ^Kl3+tkeY낸t_[_\Uu~#Mjllm)f.Ƿ c6ݗ:Uz*_:²wA ^ެlv8ڐ4˶PFm֯Ttz !=SAnEFGi⭍͎jzB:swhMQĠ˒݅" hT){Ƌ#OE㾧t'v#D='_c?B;O)zTItX|5U+޴nKB1RdbM|h¨i_V}G"TGQ85`G-ȌChW[-w#Йbxjb;0eFM ef`AB8+D7*,L?+c@޾}71܅7-_,t,hk#h,\ZbL:x+̙JiX(.=LǓdhtRM _|bvѱ^Iv;6d5Z>O@rr_<_d8ɯ aG3y~ ٥Up5@;) Ob@;F&n!3Q<} c\/ ^<XMrl46ޕ)Wϯ3?'0g|3.Ƥa&3쎩mhr )[0AXRddS*gwdtqpJxִSRuB6 , ePϸw&OYH(&&Un!rAfƜN,a~goLd;NH6oqQ&e- N!9 {Gu_\>E튤}Uc,)NmLLc)a*̏]vW >H_j*Fecv#B=ypZ܎rWPRm!a׾5VpHFp%7DaY¦>SVK DszDMxIa )m8Q<SC,Տ僡ʍ!aYOРPQ Feo$I[d͘053BP.隳hA&<&zgbhD.^}<Wwyg{:w¬ şWŻ(tS {(a9?7Ceӈ%e~ٗ7 ]qلFDs9sĞy>[FȮ-6X3ն/XggqXyrj!F9a껱ۉcZ AaΉZPrm̤}- @* Qb(!<.yonQvg#MbKwPrWi xxRıI<`qn㒚χ,5İ;XL"q+5x?М~2_{]Xc`{%69)Lɡf2*/ :݂2oQl^58@_d7@qׯ2Ol:/3,6=ZSb˃ΐer(:ΙBvQ6O,& οτY0:T5y" Cy-ٟwHEcvKɄ M8E4cvLNN7‚$Hֿ @bpL->'äCDөCg$GKKQN@![Z?[oH(X/n̮;æƙ*lf"x)*/Bqԉݓw[U\N!/ӶcWM{xT[ByN5"^w-vlEQNDz&AR}h>;{Oxr ym6Ծ4nbiaHJ39@(.`SʦTlYʃ=hR`cד/@uUl8Xjwk8A2!2p,qq%R6E|JH̴e^GNԊآ|*3suQMEwtz*| ` ~MDS'7ձ5nS4*TI=V#NW0>`f 4pdݑx4~?~]_,jQ8Gb54&/#.(:6Ort!̓%ƹ)R 2 N `tO]?qe^a&jO1p2D{JG׹^)NoXx1Ĝ` AɑQYI>xGa#Ȅd3yepÎs$׳tcF̎~{̼=3.K0hJWh<|kD9M1ZwAJk7y5EOyNLgM:庴9 mN~ksy9Ub7NJ~?FWeȴ]e٫ZqNEً0dl'Gƥ݄*n-!9-d 'NHN型.kz/I`dyc7׎h0K'_ ׿^wa#;UW#N)(!(xe 5cJ^s$.cJ}:%mpÎn69,bGK!?I&6 ux qUHBni :Oy !R6W5ҝRZY$%IUaQN]+/hbGpHNodhHL"5hJ70H˜V?/q.( ߢBcOf^ׯt7?>с\=EI9A)aMWؘwΊKovi1jG0G0xzfQ3`,ȵ(F8}gӓ{#:%SV@ y'Bq ?iO)}RXS%dejvwcn0etCMU"htUP!'q9Uӛ:ԷH{oPۣ>"9ڛ_[6ܳ}BigZmv'jT  b,GO!J#O1r1Ul+nR5lK)VŽ (}?|x:<ұyEͼ]{Ȋ R7trJ>HX:- -¤]K]/aN |x^AqfA^?B{W> 3-~-sFH$\*ovWF\u#6> azߪ<6wԃV{b)M mvSgܹZ~~nQ򻶋g'|`%#VHdLsi̞^{X,"'6B/jhDڻsDyرU& BXId@=&{YLSbT;&xqn%RQ\#;I:ƌwh6oTC3TEZ^ܗ(ĮFQG(;O||ZveT q,ZrB:܏lגK;>p HGC55f4kXTZ9 y&X_WjEGJ 8<Ul &(8y¥:렕0k_.."|_{fS˵`~2'Pq;BdE\2: JKle6ntZpae*fbf88.LspMDA@nݷdʷ(Rgh7J!ZO7UoNBGf  {ك-ZLcnzjv)㦃 0[Wd5jqBȣ}Rh$'_41QGEL}L7AbP6W7/ն}[u<)<cǘ6'אye5.Kvx+DõPBB ST ql`ӟebX5NxA'ut.T#8I'\1=z w6&ɘX͘GL1Pl/i+mWȬLUwSQ9[A(s9ȞМSo,#358y Z[[ͥ+[W8脩/WMhY28&H7ӲyϟTa36 s^0w 1ʴ׆iÐߴĕǦa$JHrҚ{W@9ٻK !znYKU]:yDWuEG5d .P_K ;V,4SvDok؄p+6Pc5T^  A%&v(˷>]><Ͳ?$o|хb9}dg Fq7Χ:ZUsǀ# Kt̀[oBGC*AD܌s: xnfS-@@>A`ajTRB8;'PͦU|#lUGpeh[pJNKJAA8JaX?,W尼CU/A:Y$48 R3WŸqbu޴37'|2 H,gHoC5Z >Mױʵ)X,XO\gXiȚx|:yWЎ8TPz精"P! o1ܝ2/B76'ߖ_a]@~ÖM4D|ȡs$fTl,likKvk>cg&U |7}|`W.Oq8SxZ=Db's_A/i^i3g}~R`݌L#~%IN<-`>|_O9e" hz _QJ&HQgiЪrCdrVHmkMx`UM/8C&qr iKx d)_Q(=&d[}t-/$_< 3=yKb)UقRxǢ]=''z)ӇhyZbΔ0qtCf\nQYSrUT3Y t#1X۬qL{KHkrUFsᣜ/nR͠/0OV%?`~7ex:Ӫ# BHp I̙F;kĆz;H-S5,ƻۚ5˦d[͛_%9t4o_=E!-e/$4LXXRo8/en{uouj5՚x1@g_`X"դ(|VoZ~Fz Ac6"|)J˄ܪҢ`At1ɳ{6$VȕAK ÐJٯlį礉,TC ~6ogY7$ }=V=l?CA>8Q(%O;C7/X#b(=kK!xS<s pܽ[Z0Zɖ4 &(~syU{p5߅ ?,6˪&x<NCLC8۩T-QeI|ڵWrp+ W<}1,T"n+yԯVqHyNjA2ZDiM>GR.kLyNe5b~Om`LvvϤ iVYjvV ũ^3[%N>* 8- & ;̓Z`&xX:Bɟ̓NKqsHUuFm[6V)!lF.P@uKS(=٫dHφa&\/ĺpi/~?YԮ;fw4pp?V.';?/> stream x[YO~_{u}F#$ 'LMLf~S ܇+])r8T *a2AlF ÑyA)bG2cRpf*|hƹ#+?'3:B `*U04S3 p$3)SI)m3E4)f0<9dDδ` DdڢSC6L 8Z)r#243 %Tf Mb.YV++@'5@YbB jQEYZ1@ IAs`&>@Yɔu\"(HA(2"rqkN9GMD ɔ"#"f g":RFZV1 ) AI 8D@94 F ħsh5Rhb0FYolf\=G `%&:_:gb qH!k˙4P0PeHP0=73:( A.\"Z Nf-\b("FA˅F˅ Z.0Y Z.4dA!& {S)jF4\ R3l*PnLK Y&d ;JK(\!61/\bGr ( q+^0Z+צ ڸiԘTR ˜iāFD3VM)~ B+7mYAz3^9E9` UAwcFj9JsH3 t|@A$~\^V8a s k9 8ュZky[=-"IBrM* !0ޔq@ ІnuBCSjrh-LO7eݿ8xx8r.$!/U!%b  ܭRذ4+(PZaF!ƕQ( SZb?0pM˕/1(9hWlAsµ@gM}\ 6-8o cؤAIyư)v-$ikCy}rOQO?,ߞVobr/F99x}[2~Gy~[@!寖Wl;! y={WLެaQrRO'Wf_J(?Ts`r3^_b|UL/+?Z{}'R xG~]}xhSeBm QǾm8ʯ"2__IG>oY>"˗r#_嫛EQ?b,v~=<:X,8b]/Xl4v0?O_]Xg%t5;Ke7 fu@Pﰮ }#+Xu0x{`{rpp``PALi1ޖCEϧ:Ɯm'0F?Ƨ Z&쟀})§3pG lwqsQJaNOsz}r9gAWe^m/cK~T vdxtX~(Ve)+|zɋ&UN;24WgkUƋbp#Bp|U\_N݂x׸jO쿝x :i5QZ=|{=ek 9o=p88p cZɶ3].bfP_t\cz.0j] ܰt~qs~KuTGX{`ink5h 縣"꥜תg>}:GKm6Z 6b scY/gJw[ Ux?;or5 p]5Km d!luìߚ~m_QImɎk=-ߖk]iV} Zਓi=t{Lx(>n'eü/<;`Ŀw Nuც^8:Nwղ vq2lK2 @ ;_MD &嵻\eI:YᑋoWkp?ꗴw=w4E tŏ8C8x<,b -5ƣuJPfV6$ljCĨ5MOD',]tY+*/p3D/./ \ JЩI7/Oͻ*/!/UtoO Ҳ++/Hb;벖U^f&^`]^xS/Zyn^vyT^ZD 4BդmGB㻬i jæц/telM+iʦ))FSn /KV z7Z6xUAJxua_ubO:ĦFbtbՉMՉ>Ħ3 endstream endobj 1692 0 obj << /Type /ObjStm /N 100 /First 883 /Length 1682 /Filter /FlateDecode >> stream x}A$7EyaI$a`0Ø  6Lư*"bA-mb[߱k,i۔1K0?hc,P0n{8q;&[To]U6Y1x2vOc2x2x2 ?gZ}uNOoS'v*p!Ԙ`[g`19 n89;8=;K2 Y%dpOK av`X,LN D7y}uAlUZdKKKZ%*-]Z,/-EAkdZ^Kk^%׌8{)K`{qRd쇳%K~8QgK={ɾ#cߝ}/ٷg웳oVjI7u^h2Zs-õoZgZ{fвDk-ײRKVϴԵJEϒ~g`?3٣d~f66"{"sK/_},s?2?y첥7bS^<\6C,kyt4!K jVheMQoJK%%N[J..qR^2G~~)>h9QgK={ɾ=cߝ}+ٷg웳o%`g-g*{fyz>K>]bR=2ۅ.Vv.vԒ3-u}]d ]̒}]d ]̒}]d ]dlm(FfpJ#c]a=2(ky-kQz-"ZעZEpE^k^k½"x-2{-JEZd^ Z|mwWqz}nWmhm8+>pmoF^<ܓww!kD.֪VךZ-j|rfӞ%AkdZ~g`?3٣d~fQG`?3p([`9{+[`9{+[`o{sꌶ:m1=,w<][zSҔ\6ա A 2JІXfVnŊ}bͬX݊%`V72 endstream endobj 1693 0 obj << /Type /ObjStm /N 100 /First 874 /Length 1728 /Filter /FlateDecode >> stream x}Y˪+G+WF xe 0Ɵ?QNe'WjdEeDd)Z}jQ1:_! |-0ZN)?kz4e-e=*p!Gy:Zk9ZG-2/irz>cR[{dqS7`(1 /XY,,TLœZha"I-,^$ڂY7yrTU{ Am$[Yv I A5w[G-` /H$XAuD&A} ֱ":$X'9paLՏ&>̣a;<9&N{!kUi,nbbqgq',}[6HU8xq襍rt=;5ˮ 瀀ŕ+,nO[^]}{B}j{9tpIn{!=%z2بFw?_G^ߞ'뗿__8*?cuabUR K.:3V US,8a5^5^M{MW}W^?Z#ԆW׷F4(׻~70yf )./l@V b6HO a_b6R,gDRfUSh%+:?26V 뚆R,uXaUÒ k7VHkv]i?>cu VS{ϏNo~̯.o+¸ˋ|o-vo]"]Xw,gCؗ. R_b.k&XA;Vpd ê)V԰J5ߟ]zy=cՈV7[dl{u'@9焜c;;'rDl0j݅:2Fɰs!쫛 X#3;Rչ]8.Bp=|n"\h5]\ \h%ê΅j.Ԟb9OZI5O*R:x'jjk|:w5uq674K[sD\agYȠqWJCjf -ōD_L^^Luɾb?:[ޮd}ĩkScݶ% -J_ ,{],ns-vo{?"~Gqki{ [/j.Y}> endobj 1694 0 obj << /Type /ObjStm /N 99 /First 980 /Length 3712 /Filter /FlateDecode >> stream xڝ[[ }|lKDIa HPhMal|wݾBVX?iǻO2S_~| ?{zOnbO<}5v]fXīXڏ1:|~h41 (3W+Xbai?Nl~S?2v2ꕅ wBilIC;b{5gܙ36/Mٻdfcۗ0k4u~Bབྷ4R6ZK<]ѻQb7canOTyw{շ~}ͧ |~ /PQL"ًjߋ#ٴN5bݻG菕ֹ!W~LJO(1&^$Fuuv v ڷo޿y_< V_d^ơ* W**:dn#v F*VQ·FU6*urʣUe`^t{¼ցJ%t=5!yC<<PI0^lu⑇H=#zG"ZSUi/淪5#=4 UqT*XxT*O[nOWt2RYj5q Az 2ܪ ͭ+mnL#)4򐞂L#)4򐞂LyT$SGb=azFRp=9< 0rܸz1涩7rz<pY+oެKujζkcc*˱_E8kiնU)V[Hӫ6WQR6[xU"ch67M 4FǗfctSD3;D=c Vњ^L=źcCxн5;Lbev2gx I鷆>c15^&Ҟ5> aSe<{kvogJTw#5u?GJx\Vc`:E^̼HJl"4Fwu*=0yvx;ضfN gNz܉:!F,~M]!o?1+D?E+<'CϿS m;1f Dg Dg DC &ӥo>$~ ?KeS~fchd [ [( 8V8 ~OD`bv ~8,~0 78x^34[`-R0 RRd8<ß/bzϸb0]-~0]-R0]sq#L}Yt)N2K5946*J/ O $Lg&S"e-R0mQeԷӨl d0 ~v1(˓- 2c0-$0m i^L NPCkzԑ]|Y.YY.6<@yB,~!M1g-P!+|׌*L!t~/9<'dჱ4 KBiQ@4[ -R-R RM|>bW0]n0] qn|M&PC: !0]"b B|%f]z#qn9|BWUB'#șY.< |QL}?YH-$oXE7Q#rD5r!GHς3q}4@b7 ։`︗ ) 4݅c<АААh`Y>x~]( \0 [0 [#D20k rg?`VҶ``r``SMz\f!_۞lnRbC)NtFqoswʗ!D-'"l4lBl4Hb<Kwȗ!-G^"=qRh& ˊ|č$@u;Gb͓eITy@noG?:vZȭPZa~o:bm|]djDZZ7*7 VZr}_^ _y;i ͐kj^ |jqJ $'9eJtQ3 F'5<}ǓЬ͊ЬG'릪al͆lLv̈́LḦ́M M_;ՁR 5 R 5BSCszu2>U7x1_)_ % f.78An#቉]Yϥ_Q򛛇7r ^UԾrԃJ~/~}\rի~w/}k$? ?|}G m endstream endobj 1780 0 obj << /Type /XRef /Index [0 1781] /Size 1781 /W [1 3 1] /Root 1778 0 R /Info 1779 0 R /ID [ ] /Length 4091 /Filter /FlateDecode >> stream x%G5]ZS7|9s_9D @PEIݪVq$ ZNl(@ݭhdZ=jk>g4wl4?åьfcc[hq0AMN9L066 тƋfA h iV "" t1XB[FX і&`m-na%XE[ICW5`m#mh/Ѝ`m33lm}Bmv vѶޣn;t/GC{h{io^a~+8J;@{i=NҎҞi13 8K;N{i'hO "$1z \=BӴ5pvn.mOC˴hOBě>]FӮfҮn1i7hqi1/ih(k}ZV-*O{H! |=]Fpii1M}ȉ'N\q{aJSNRKyTʺ+ZvE_΢E.v.Cww4넽Gn']3(*읰Wc4jvNث t {5I; {' u {5vN+MuJV;aT {Ny 앦:7JSJSڅƅ {7-4Lثla4کmhJ+v*n5,F; {N0ZEۄrg'jZ 1gw^m@JHT'&=NثhQZI&Nثha a& Nثha)a&Nثw^E^ {'U4鰲w^E^ {'U4鈁w^E^ {'U4t؋>띰WX@+Whq az D=0{aqBۂ/7փ {AP{APDc bոh@[ۊ {qW(wCv2 6ػeaoM담{Sq N]G':u} թl N]Aaou4:{קЅ@[>. t)Vwˁc} ] j XAaou0{1ևЍ@[>njuBao5{1ѝ@[Mއj^4@[Mރ{ oj.4.\[MVw1`ju\n 64 %jE64 "m406baom@aoEynaoCoaoEiao^5=ax"PV@=JX GCY>h(a nZ/C_hV~"fA|ޏhO@h<1E }t{oZGǁA/a51z { +@{!z {o_|({ 콦ZE㄰j/7^S-oqAke}܌cy찌KA찼F7;,㶢xޛW( 0M]-/a[p20M#:pyCԯTAR_y!®ۖj9Ham˳tvݶA؇n[F}% >DMʓv]A؇.ZG}A؇U@ćuh؟\HT%+j &  6  .pppp} ƝǐX ưG=P=/F+8n+gBUiѥ"gુNXt݁n`ApDm`A8Fy`Az2V4mi`A#u4aژ` 0 f` 怹``X `XV`X ր`X6` `v ,pǸ](0}`?888 8 N 8 ΁.  n x x x ^ x ށ>@ʪU?~VYgʝ;=K fK1ؙ2d>| A2d>| A2d>| A2]`7T?~VYgϪU?~VYgϪU?~VYgϪU?~VYgϪU?~VYgϪU?+|SN}72 d,Y @f2 d,Y aO56  6ϋoK&/~GbtwYn-ˍب]Rux)o`V -oL۟-kk;я}'Ni8T~dKKr|1ri. {7b?g; dO 5SWsb.N0}[b7*h;o^h1kD1q"mbCz1_ gކYrS1?EHAgEr'B}'LփXYoRhȓm,epW`xR|`u pĒ8^%|._yVbnX#;qϋb u뙺}U[^ŗc 6`5XPǿ'l”ƠeK) c~({erCEq@9-p(= -\l8vQ 7w}c߀E?qIEC{bBjZVsQ $ɾYQ%+d,7eLVɒ1Y#&dO+yk N2L/PK1~KC([J~(%OeIW21LdLӎ;;iWQ|fPaJNJ)Y%kdvpQT_jɢ&Y$˖d,LHHJcl$$%d5,BdE,~Òl${(-d⟸8'sd֓yz&) ol$ G2GO&^Fbd"~9*&Ϣ]@% Eqb(~q4<8Y8UV.>(cz.cr>s&{тbha1kG]-.{q?e/|Gˋ8bJ[ze<?]oMo&~?8ӆO>m IAO>miç 6>mӆO>m%X4VÝ w6pgÝ w60ff7Ӹ:ă1lă1lă1l_0fØ c60fØ c60fØ c60fØ c60fØ c6HTÝ w6pgÝ w6pgÝ w6|.&~ԏɅyH endstream endobj startxref 328975 %%EOF luaossl-rel-20220711/doc/luaossl.tex000066400000000000000000002274001426273367600172120ustar00rootroot00000000000000\documentclass[11pt, oneside]{memoir} \usepackage{fullpage} \usepackage{xspace} \usepackage{makeidx} \usepackage{listings} \usepackage{multicol} \usepackage{graphicx} \usepackage[colorlinks=true, linkcolor=blue]{hyperref} \setlength{\parindent}{0pt} \nonzeroparskip % add padding to ctabular tables \renewcommand{\arraystretch}{1.2} \makeindex % % COMMANDS % \newcommand*{\luaossl}[0]{\texttt{luaossl}\xspace} \newcommand*{\key}[1]{#1\index{#1}\xspace} \newcommand*{\syscall}[1]{\texttt{#1}\xspace} \newcommand*{\routine}[1]{\texttt{#1}\xspace} \newcommand*{\fn}[1]{\texttt{#1}\xspace} \newcommand*{\method}[1]{\texttt{#1}\xspace} \newcommand*{\module}[1]{\texttt{#1}\xspace} \newcommand*{\errno}[1]{\texttt{#1}\xspace} \newcommand*{\crlf}[0]{$\backslash$r$\backslash$n\xspace} \newcommand*{\lf}[0]{$\backslash$n\xspace} % % ENVIRONMENTS % \lstdefinelanguage{lua}{ morekeywords={break,goto,do,end,while,repeat,until,if,then,elseif,else,for,in,function,local,nil,false,true,and,or,not}, sensitive=true, morestring=[b]" } \lstnewenvironment{code}[1]{ \lstset{language=#1} }{ } \lstnewenvironment{example}[1]{ \lstset{language=#1,numbers=left,numberstyle=\tiny,stepnumber=2,tabsize=4} \ttfamily\small }{ } \newcounter{toccols} \setcounter{toccols}{2} \newenvironment{Module}[1]{ \subsection{\texttt{#1}} \addtocontents{toc}{ \protect\begin{multicols}{\value{toccols}} %\renewcommand*{\cftsubsubsectiondotsep}{\cftnodots}% } }{ \addtocontents{toc}{\protect\end{multicols}} } \lstdefinelanguage{lua}{morekeywords={break,goto,do,end,while,repeat,until,if,then,elseif,else,for,in,function,local,nil,false,true,and,or,not},sensitive=true,morestring=[b]"} \begin{document} %\pagestyle{empty} \title{ \vspace*{10ex} \HUGE\sffamily User Guide to \luaossl, \\ %\vspace*{20pt} %\hrule \HUGE Comprehensive OpenSSL Module for Lua \\ \vspace*{30pt} \hrule } \date{\today} \author{ William Ahern \and Daurnimator } %\setlength{\droptitle}{85pt} \maketitle \thispagestyle{empty} \clearpage \maxtocdepth{subsubsection} \setsecnumdepth{subsection} \setcounter{page}{1} \pagenumbering{roman} \tableofcontents \clearpage \setcounter{page}{1} \pagenumbering{arabic} \chapterstyle{section} \setlength{\beforechapskip}{1ex} \setlength{\afterchapskip}{1ex} \chapter{Dependencies} \section{Operating Systems} \luaossl targets modern POSIX-conformant systems. A Windows port is feasible and patches welcome. Note however that the module employs the POSIX thread API, POSIX dlopen, and the non-POSIX dladdr interface to protect OpenSSL in threaded environments. \section{Libraries} \subsection{Lua 5.1, 5.2, 5.3} \luaossl targets Lua 5.1 and above. \subsection{OpenSSL} \luaossl targets modern OpenSSL versions as installed on OS X, Linux, Solaris, OpenBSD, and similar platforms. \subsection{pthreads} Because it's not possible to detect threading use at runtime, or to \emph{safely} and dynamically enable locking, this protection is builtin by default. At present the module only understands the POSIX threading API. \paragraph{Linking} Note that on some systems, such as NetBSD and FreeBSD, the loading application must be linked against pthreads (using -lpthread or -pthread). It is not enough for the \luaossl module to pull in the dependency at load time. In particular, if using the stock Lua interpreter, it must have been linked against pthreads at build time. Add the appropriate linker flag to MYLIBS in lua-5.2.x/src/Makefile. \subsection{libdl} In multithreaded environments the module will initialize OpenSSL mutexes if they've not already been initialized. If the mutexes are initialized then the module must pin itself in memory to prevent unloading by the Lua garbage collector. The module first uses the non-standard but widely supported dladdr routine to derive the module's load path, and then increments the reference count to the module using dlopen. This is the safest and most portable method that I'm aware of. \section{GNU Make} The Makefile requires GNU Make, usually installed as gmake on platforms other than Linux or OS X. The actual \texttt{Makefile} proxies to \texttt{GNUmakefile}. As long as \texttt{gmake} is installed on non-GNU systems you can invoke your system's \texttt{make}. \chapter{Installation} All the C modules are built into a single core C library. The core routines are then wrapped and extended through Lua modules. Because there several extant versions of Lua often used in parallel on the same system, there are individual targets to build and install for each supported Lua version. The targets \texttt{all} and \texttt{install} will attempt to build and install both Lua 5.1 and 5.2 modules. Note that building and installation and can accomplished in a single step by simply invoking one of the install targets with all the necessary variables defined. \section{Building} There is no separate \texttt{./configure} step. System introspection occurs during compile-time. However, the ``\texttt{configure}'' make target can be used to cache the build environment so one needn't continually use a long command-line invocation. All the common GNU-style compiler variables are supported, including \texttt{CC}, \texttt{CPPFLAGS}, \texttt{CFLAGS}, \texttt{LDFLAGS}, and \texttt{SOFLAGS}. Note that you can specify the path to Lua 5.1, Lua 5.2, and Lua 5.3 include headers at the same time in CPPFLAGS; the build system will work things out to ensure the correct headers are loaded when compiling each version of the module. \subsection{Targets} \begin{description} \item[\texttt{all}] \hfill \\ Build modules for Lua 5.1 and 5.2. \item[\texttt{all5.1}] \hfill \\ Build Lua 5.1 module. \item[\texttt{all5.2}] \hfill \\ Build Lua 5.2 module. \item[\texttt{all5.3}] \hfill \\ Build Lua 5.3 module. \end{description} \section{Installing} All the common GNU-style installation path variables are supported, including \texttt{prefix}, \texttt{bindir}, \texttt{libdir}, \texttt{datadir}, \texttt{includedir}, and \texttt{DESTDIR}. These additional path variables are also allowed: \begin{description} \item[\texttt{lua51path}] \hfill \\ Install path for Lua 5.1 modules, e.g. \texttt{\$(prefix)/share/lua/5.1} \item[\texttt{lua51cpath}] \hfill \\ Install path for Lua 5.1 C modules, e.g. \texttt{\$(prefix)/lib/lua/5.1} \item[\texttt{lua52path}] \hfill \\ Install path for Lua 5.2 modules, e.g. \texttt{\$(prefix)/share/lua/5.2} \item[\texttt{lua52cpath}] \hfill \\ Install path for Lua 5.2 C modules, e.g. \texttt{\$(prefix)/lib/lua/5.2} \item[\texttt{lua53path}] \hfill \\ Install path for Lua 5.3 modules, e.g. \texttt{\$(prefix)/share/lua/5.3} \item[\texttt{lua53cpath}] \hfill \\ Install path for Lua 5.3 C modules, e.g. \texttt{\$(prefix)/lib/lua/5.3} \end{description} \subsection{Targets} \begin{description} \item[\texttt{install}] \hfill \\ Install modules for Lua 5.1 and 5.2. \item[\texttt{install5.1}] \hfill \\ Install Lua 5.1 module. \item[\texttt{install5.2}] \hfill \\ Install Lua 5.2 module. \item[\texttt{install5.3}] \hfill \\ Install Lua 5.3 module. \end{description} \chapter{Usage} \section{Modules} \begin{Module}{openssl} Binds various global interfaces, including version and build information. \subsubsection[\fn{openssl[]}]{\fn{openssl[]}} Table of various compile-time constant values. See also \fn{openssl.version}. \begin{ctabular}{ c | p{12cm} } name & description \\\hline \small{\texttt{SSLEAY\_VERSION\_NUMBER}} & OpenSSL version as an integer. \\ \small{\texttt{LIBRESSL\_VERSION\_NUMBER}} & LibreSSL version as an integer. \\ \small{\texttt{NO\_[feature]}} & If defined, signals that this installation of OpenSSL was compiled without [feature]. \\ \end{ctabular} \subsubsection[\fn{openssl.version}]{\fn{openssl.version($info$)}} Returns information about the run-time version of OpenSSL, as opposed to the compile-time version used to build the Lua module. If $info$ is not specified, returns the version number as an integer. Otherwise, $info$ may be one of the following constants. \begin{ctabular}{ c | p{12cm} } name & description \\\hline \small{\texttt{SSLEAY\_VERSION}} & OpenSSL version description as a string. \\ \small{\texttt{SSLEAY\_CFLAGS}} & Description of compiler flags used to build OpenSSL as a string. \\ \small{\texttt{SSLEAY\_BUILT\_ON}} & Compilation date description as a string. \\ \small{\texttt{SSLEAY\_PLATFORM}} & Platform description as a string. \\ \small{\texttt{SSLEAY\_DIR}} & OpenSSL installation directory description as a string. \\ \end{ctabular} \subsubsection[\fn{openssl.extensionSupported}]{\fn{openssl.extensionSupported($ext\_type$)}} Returns a boolean indicating if the extension $ext\_type$ is handled internally by OpenSSL. \end{Module} \begin{Module}{openssl.bignum} \module{openssl.bignum} binds OpenSSL's libcrypto bignum library. It supports all the standard arithmetic operations. Regular number operands in a mixed arithmetic expression are upgraded as-if \method{bignum.new} was used explicitly. The \fn{\_\_tostring} metamethod generates a decimal encoded represention. \subsubsection[\fn{bignum.new}]{\fn{bignum.new($number$)}} Wraps the sign and integral part of $number$ as a bignum object, discarding any fractional part. \subsubsection[\fn{bignum.interpose}]{\fn{bignum.interpose($name$, $function$)}} Add or interpose a bignum class method. Returns the previous method, if any. \end{Module} \begin{Module}{openssl.pkey} \module{openssl.pkey} binds OpenSSL's libcrypto public-private key library. The \fn{\_\_tostring} metamethod generates a PEM encoded representation of the public key---excluding the private key. \subsubsection[\fn{pkey.new}]{\fn{pkey.new($string$[, $format$])}} Initializes a new pkey object from the PEM- or DER-encoded key in $string$. $format$ defaults to ``*'', which means to automatically test the input encoding. If $format$ is explicitly ``PEM'' or ``DER'', then only that decoding format is used. On failure throws an error. \subsubsection[\fn{pkey.new}]{\fn{pkey.new\{ $\ldots$ \}}} Generates a new pkey object according to the specified parameters. \begin{ctabular}{ c | c | p{5in}} field & type:default & description\\\hline .type & string:RSA & public key algorithm---``RSA'', ``DSA'', ``EC'', ``DH'', or an internal OpenSSL identifier of a subclass of one of those basic types \\ .bits & number:1024 & private key size \\ .exp & number:65537 & RSA exponent \\ .generator & number:2 & Diffie-Hellman generator \\ .dhparam & string & PEM encoded string with precomputed DH parameters \\ .curve & string:prime192v1 & for elliptic curve keys, the OpenSSL string identifier of the curve \end{ctabular} The DH parameters ``dhparam'' will be generated on the fly, ``bits'' wide. This is a slow process, and especially for larger sizes, you would precompute those; for example: ``openssl dhparam -2 -out dh-2048.pem -outform PEM 2048''. Using the field ``dhparam'' overrides the ``bits'' field. \subsubsection[\fn{pkey.interpose}]{\fn{pkey.interpose($name$, $function$)}} Add or interpose a pkey class method. Returns the previous method, if any. \subsubsection[\fn{pkey:type}]{\fn{pkey:type()}} Returns the OpenSSL string identifier for the type of key. \subsubsection[\fn{pkey:setPublicKey}]{\fn{pkey:setPublicKey($string$[, $format$])}} Set the public key component to that described by the PEM- or DER-encoded public key in $string$. $format$ is as described in \fn{openssl.pkey.new}---``PEM'', ``DER'', or ``*'' (default). \subsubsection[\fn{pkey:setPrivateKey}]{\fn{pkey:setPrivateKey($string$[, $format$])}} Set the private key component to that described by the PEM encoded private key in $string$. $format$ is as described in \fn{openssl.pkey.new}. \subsubsection[\fn{pkey:sign}]{\fn{pkey:sign($digest$)}} Sign data which has been consumed by the specified \module{openssl.digest} $digest$. Digests and keys are not all interchangeable. Returns the signature as an opaque binary string\footnote{Elliptic curve signatures are two X.509 DER-encoded numbers, for example, while RSA signatures are encrypted DER structures.} on success, and throws an error otherwise. \subsubsection[\fn{pkey:verify}]{\fn{pkey:verify($signature$, $digest$)}} Verify the string $signature$ as signing the document consumed by \module{openssl.digest} $digest$. See the :sign method for constraints on the format and type of the parameters. Returns true on success, false for properly formatted but invalid signatures, and throws an error otherwise. Because the structure of the signature is opaque and not susceptible to sanity checking before passing to OpenSSL, an application should always be prepared for an error to be thrown when verifying untrusted signatures. OpenSSL, of course, should be able to handle all malformed inputs. But the module does not attempt to differentiate local system errors from errors triggered by malformed signatures because the set of such errors may change in the future. \subsubsection[\fn{pkey:toPEM}]{\fn{pkey:toPEM($which$[, $which$])}} Returns the PEM encoded string representation(s) of the specified key component. $which$ must be one of ``public'', ``PublicKey'', ``private'', or ``PrivateKey''. For the two argument form, returns two values. \end{Module} \begin{Module}{openssl.x509.name} Binds the X.509 distinguished name OpenSSL ASN.1 object, used for representing certificate subject and issuer names. \subsubsection[\fn{name.new}]{\fn{name.new()}} Returns an empty name object. \subsubsection[\fn{name.interpose}]{\fn{name.interpose($name$, $function$)}} Add or interpose a name class method. Returns the previous method, if any. \subsubsection[\fn{name:add}]{\fn{name:add($type$, $value$)}} Add a distinguished name component. $type$ is the OpenSSL string identifier of the component type---short, long, or OID forms. $value$ is the string value of the component. DN components are free-form, and are encoded raw. \subsubsection[\fn{name:all}]{\fn{name:all()}} Returns a table array of the distinguished name components. Each element is a table with four fields: \begin{tabular}{ l | l} field & description\\\hline .sn & short name identifier, if available\\ .ln & long name identifier, if available\\ .id & OID identifier\\ .blob & raw string value of the component \end{tabular} \subsubsection[\fn{name:each}]{\fn{name:each()}} Returns a key-value iterator over the distinguished name components. The key is either the short, long, or OID identifier, with preference for the former. \subsubsection[\fn{name:\_\_pairs}]{\fn{name:\_\_pairs()}} Equal to \module{name:each} \end{Module} \begin{Module}{openssl.x509.altname} Binds the X.509 alternative names (a.k.a ``general names'') OpenSSL ASN.1 object, used for representing certificate subject and issuer alternative names. \subsubsection[\fn{altname.new}]{\fn{altname.new()}} Returns an empty altname object. \subsubsection[\fn{altname.interpose}]{\fn{altname.interpose($name$, $function$)}} Add or interpose an altname class method. Returns the previous method, if any. \subsubsection[\fn{altname:add}]{\fn{altname:add($type$, $value$)}} Add an alternative name. $type$ must specify one of the five basic types identified by ``RFC822Name'', ``RFC822'', ``email'', ``UniformResourceIdentifier'', ``URI'', ``DNSName'', ``DNS'', ``IPAddress'', ``IP'', or ``DirName''. For all types except ``DirName'', $value$ is a string acceptable to OpenSSL's sanity checks. For an IP address, $value$ must be parseable by the system's \fn{inet\_pton} routine, as IP addresses are stored as raw 4- or 16-byte octets. ``DirName'' takes an \module{openssl.x509.name} object. \subsubsection[\fn{name:\_\_pairs}]{\fn{name:\_\_pairs()}} Returns a key-value iterator over the alternative names. The key is one of ``email'', ``URI'', ``DNS'', ``IP'', or ``DirName''. The value is the string representation of the name. \end{Module} \begin{Module}{openssl.x509.extension} Binds the X.509 extension OpenSSL object. \subsubsection[\fn{extension.new}]{\fn{extension.new($name$, $value$ [, $data$])}} Returns a new X.509 extension. If $value$ is the string ``DER'' or ``critical,DER'', then $data$ is an ASN.1-encoded octet string. Otherwise, $name$ and $value$ are plain text strings in \href{https://www.openssl.org/docs/apps/x509v3_config.html#ARBITRARY_EXTENSIONS}{OpenSSL's arbitrary extension format}; and if specified, $data$ is either an OpenSSL configuration string defining any referenced identifiers in $value$, or a table with members: \begin{ctabular}{ l | l | p{8cm} } field & type:default & description\\\hline .db & string:$nil$ & OpenSSL configuration string\\ .issuer & \module{openssl.x509}:$nil$ & issuer certificate\\ .subject & \module{openssl.x509}:$nil$ & subject certificate\\ .request & \module{openssl.x509.csr}:$nil$ & certificate signing request\\ .crl & \module{openssl.x509.crl}:$nil$ & certificate revocation list\\ .flags & integer:$0$ & a bitwise combination of flags \end{ctabular} \subsubsection[\fn{extension.interpose}]{\fn{extension.interpose($name$, $function$)}} Add or interpose an extension class method. Returns the previous method, if any. \subsubsection[\fn{extension:getID}]{\fn{extension:getID()}} Returns the ASN.1 OID as a plain text string. \subsubsection[\fn{extension:getName}]{\fn{extension:getName()}} Returns a more human-readable name as a plain text string in the following order of preference: OpenSSL's short name, OpenSSL's long name, ASN.1 OID. \subsubsection[\fn{extension:getShortName}]{\fn{extension:getShortName()}} Returns OpenSSL's short name as a plain text string if available. \subsubsection[\fn{extension:getLongName}]{\fn{extension:getLongName()}} Returns OpenSSL's long name as a plain text string if available. \subsubsection[\fn{extension:getData}]{\fn{extension:getData()}} Returns the extension value as an ASN.1-encoded octet string. \subsubsection[\fn{extension:getCritical}]{\fn{extension:getCritical()}} Returns the extension critical flag as a boolean. \end{Module} \begin{Module}{openssl.x509} Binds the X.509 certificate OpenSSL ASN.1 object. \subsubsection[\fn{x509.new}]{\fn{x509.new([$string$[, $format$]])}} Returns a new x509 object, optionally initialized to the PEM- or DER-encoded certificate specified by $string$. $format$ is as described in \fn{openssl.pkey.new}--``PEM'', ``DER'', or ``*'' (default). \subsubsection[\fn{x509.interpose}]{\fn{x509.interpose($name$, $function$)}} Add or interpose an x509 class method. Returns the previous method, if any. \subsubsection[\fn{x509:getVersion}]{\fn{x509:getVersion()}} Returns the X.509 version of the certificate. \subsubsection[\fn{x509:setVersion}]{\fn{x509:setVersion($number$)}} Sets the X.509 version of the certificate. \subsubsection[\fn{x509:getSerial}]{\fn{x509:getSerial()}} Returns the serial of the certificate as an \module{openssl.bignum}. \subsubsection[\fn{x509:setSerial}]{\fn{x509:setSerial($number$)}} Sets the serial of the certificate. $number$ is a Lua or \module{openssl.bignum} number. \subsubsection[\fn{x509:digest}]{\fn{x509:digest([$type$[, $format$]])}} Returns the cryptographic one-way message digest of the certificate. $type$ is the OpenSSL string identifier of the hash type---e.g. ``md5'', ``sha1'' (default), ``sha256'', etc. $format$ specifies the representation of the digest---``s'' for an octet string, ``x'' for a hexadecimal string (default), and ``n'' for an \module{openssl.bignum} number. \subsubsection[\fn{x509:getLifetime}]{\fn{x509:getLifetime()}} Returns the certificate validity ``Not Before'' and ``Not After'' dates as two Unix timestamp numbers. \subsubsection[\fn{x509:setLifetime}]{\fn{x509:setLifetime([$notbefore$][, $notafter$])}} Sets the certificate validity dates. $notbefore$ and $notafter$ should be UNIX timestamps. A nil value leaves the particular date unchanged. \subsubsection[\fn{x509:getIssuer}]{\fn{x509:getIssuer()}} Returns the issuer distinguished name as an \module{x509.name} object. \subsubsection[\fn{x509:setIssuer}]{\fn{x509:setIssuer($name$)}} Sets the issuer distinguished name. \subsubsection[\fn{x509:getSubject}]{\fn{x509:getSubject()}} Returns the subject distinguished name as an \module{x509.name} object. \subsubsection[\fn{x509:setSubject}]{\fn{x509:setSubject($name$)}} Sets the subject distinguished name. \subsubsection[\fn{x509:getIssuerAlt}]{\fn{x509:getIssuerAlt()}} Returns the issuer alternative names as an \module{x509.altname} object. \subsubsection[\fn{x509:setIssuerAlt}]{\fn{x509:setIssuer($altname$)}} Sets the issuer alternative names. \subsubsection[\fn{x509:getSubjectAlt}]{\fn{x509:getSubjectAlt()}} Returns the subject alternative names as an \module{x509.name} object. \subsubsection[\fn{x509:setSubjectAlt}]{\fn{x509:setSubjectAlt($name$)}} Sets the subject alternative names. \subsubsection[\fn{x509:getIssuerAltCritical}]{\fn{x509:getIssuerAltCritical()}} Returns the issuer alternative names critical flag as a boolean. \subsubsection[\fn{x509:setIssuerAltCritical}]{\fn{x509:setIssuerAltCritical($boolean$)}} Sets the issuer alternative names critical flag. \subsubsection[\fn{x509:getSubjectAltCritical}]{\fn{x509:getSubjectAltCritical()}} Returns the subject alternative names critical flag as a boolean. \subsubsection[\fn{x509:setSubjectAltCritical}]{\fn{x509:setSubjectAltCritical($boolean$)}} Sets the subject alternative names critical flag. \subsubsection[\fn{x509:getBasicConstraints}]{\fn{x509:getBasicConstraints([$which$[, $which$ $\ldots$ ]])}} Returns the X.509 `basic constraint' flags. If specified, $which$ should be one of ``CA'' or ``pathLen'', which returns the specified constraint---respectively, a boolean and a number. If no parameters are specified, returns a table with fields ``CA'' and ``pathLen''. \subsubsection[\fn{x509:setBasicConstraints}]{\fn{x509:setBasicConstraints\{ $\ldots$ \}}} Sets the basic constraint flag according to the defined field values for ``CA'' (boolean) and ``pathLen'' (number). \subsubsection[\fn{x509:getBasicConstraintsCritical}]{\fn{x509:getBasicConstraintsCritical()}} Returns the basic constraints critical flag as a boolean. \subsubsection[\fn{x509:setBasicConstraintsCritical}]{\fn{x509:setBasicConstraintsCritical($boolean$)}} Sets the basic constraints critical flag. \subsubsection[\fn{x509:addExtension}]{\fn{x509:addExtension($ext$)}} Adds a copy of the \module{x509.extension} object to the certificate. \subsubsection[\fn{x509:getExtension}]{\fn{x509:getExtension($key$)}} Returns a copy of the \module{x509.extension} object identified by $key$ where $key$ is the plain text string of the OID, long name, or short name; or the integer index (1-based) of the extension. Returns nothing if no such extension was found by that name or at that index. \subsubsection[\fn{x509:getExtensionCount}]{\fn{x509:getExtensionCount()}} Returns the integer count of the number of extensions. \subsubsection[\fn{x509:getOCSP}]{\fn{x509:getOCSP()}} Returns the OCSP urls for the certificate. \subsubsection[\fn{x509:isIssuedBy}]{\fn{x509:isIssuedBy($issuer$)}} Returns a boolean according to whether the specified issuer---an \module{openssl.x509.name} object---signed the instance certificate. \subsubsection[\fn{x509:getPublicKey}]{\fn{x509:getPublicKey()}} Returns the public key component as an \module{openssl.pkey} object. \subsubsection[\fn{x509:setPublicKey}]{\fn{x509:setPublicKey($key$)}} Sets the public key component referenced by the \module{openssl.pkey} object $key$. \subsubsection[\fn{x509:getPublicKeyDigest}]{\fn{x509:getPublicKeyDigest([$type$])}} Returns the digest of the public key as a binary string. $type$ is an optional string describing the digest type, and defaults to ``sha1''. \subsubsection[\fn{x509:getSignatureName}]{\fn{x509:getSignatureName()}} Returns the type of signature used to sign the certificate as a string. e.g. ``RSA-SHA1'' \subsubsection[\fn{x509:sign}]{\fn{x509:sign($key$ [, $type$])}} Signs and updates the instance certificate using the \module{openssl.pkey} $key$. $type$ is an optional string describing the digest type. See \module{pkey:sign}, regarding which types of digests are valid. If $type$ is omitted than a default type is used---``sha1'' for RSA keys, ``dss1'' for DSA keys, and ``ecdsa-with-SHA1'' for EC keys. \subsubsection[\fn{x509:verify}]{\fn{x509:verify\{ $\ldots$ \}}} Verifies the certificate against to the specified parameters. \begin{ctabular}{ c | c | p{9cm}} field & type & description\\\hline .store & \module{openssl.x509.store} & The certificate store to verify against, any custom settings from the store will be used. \\ .chain & \module{openssl.x509.chain} & A collection of additional certificates to consider \\ .params & \module{openssl.x509.verify\_param} & The verification parameters to use; overrides any parameters in $.store$ \end{ctabular} Returns two values. The first is a boolean value for whether the specified certificate $crt$ was verified. If true, the second value is a \module{openssl.x509.chain} object validation chain. If false, the second value is a string describing why verification failed. \subsubsection[\fn{x509:text}]{\fn{x509:text()}} Returns a human-readable textual representation of the X.509 certificate. \subsubsection[\fn{x509:\_\_tostring}]{\fn{x509:\_\_tostring}} Returns the PEM encoded representation of the instance certificate. \end{Module} \begin{Module}{openssl.x509.csr} Binds the X.509 certificate signing request OpenSSL ASN.1 object. \subsubsection[\fn{csr.new}]{\fn{csr.new([$x509$|$string$[, $format$]])}} Returns a new request object, optionally initialized to the specified \module{openssl.x509} certificate $x509$ or the PEM- or DER-encoded certificate signing request $string$. $format$ is as described in \fn{openssl.pkey.new}---``PEM'', ``DER'', or ``*'' (default). \subsubsection[\fn{csr.interpose}]{\fn{csr.interpose($name$, $function$)}} Add or interpose a request class method. Returns the previous method, if any. \subsubsection[\fn{csr:getVersion}]{\fn{csr:getVersion()}} Returns the X.509 version of the request. \subsubsection[\fn{csr:setVersion}]{\fn{csr:setVersion($number$)}} Sets the X.509 version of the request. \subsubsection[\fn{csr:getSubject}]{\fn{csr:getSubject()}} Returns the subject distinguished name as an \module{x509.name} object. \subsubsection[\fn{csr:setSubject}]{\fn{csr:setSubject($name$)}} Sets the subject distinguished name. $name$ should be an \module{x509.name} object. \subsubsection[\fn{csr:getSubjectAlt}]{\fn{csr:getSubjectAlt()}} Returns the subject alternative name as an \module{x509.altname} object. \subsubsection[\fn{csr:setSubjectAlt}]{\fn{csr:setSubjectAlt($name$)}} Sets the subject alternative names. $name$ should be an \module{x509.altname} object. \subsubsection[\fn{csr:getPublicKey}]{\fn{csr:getPublicKey()}} Returns the public key component as an \module{openssl.pkey} object. \subsubsection[\fn{csr:setPublicKey}]{\fn{csr:setPublicKey($key$)}} Sets the public key component referenced by the \module{openssl.pkey} object $key$. \subsubsection[\fn{csr:sign}]{\fn{csr:sign($key$)}} Signs the instance request using the \module{openssl.pkey} $key$. \subsubsection[\fn{csr:\_\_tostring}]{\fn{csr:\_\_tostring}} Returns the PEM encoded representation of the instance request. \end{Module} \begin{Module}{openssl.x509.crl} Binds the X.509 certificate revocation list OpenSSL ASN.1 object. \subsubsection[\fn{crl.new}]{\fn{crl.new([$string$[, $format$]])}} Returns a new CRL object, optionally initialized to the specified PEM- or DER-encoded CRL $string$. $format$ is as described in \fn{openssl.pkey.new}---``PEM'', ``DER'', or ``*'' (default). \subsubsection[\fn{crl.interpose}]{\fn{crl.interpose($name$, $function$)}} Add or interpose a request class method. Returns the previous method, if any. \subsubsection[\fn{crl:getVersion}]{\fn{crl:getVersion()}} Returns the CRL version. \subsubsection[\fn{crl:setVersion}]{\fn{crl:setVersion($number$)}} Sets the CRL version. \subsubsection[\fn{crl:getLastUpdate}]{\fn{crl:getLastUpdate()}} Returns the Last Update time of the CRL as a Unix timestamp, or $nil$ if not set. \subsubsection[\fn{crl:setLastUpdate}]{\fn{crl:setLastUpdate($time$)}} Sets the Last Update time of the CRL. $time$ should be a Unix timestamp. \subsubsection[\fn{crl:getNextUpdate}]{\fn{crl:getNextUpdate()}} Returns the Next Update time of the CRL as a Unix timestamp, or $nil$ if not set. \subsubsection[\fn{crl:setNextUpdate}]{\fn{crl:setNextUpdate($time$)}} Sets the Next Update time of the CRL. $time$ should be a Unix timestamp. \subsubsection[\fn{crl:getIssuer}]{\fn{crl:getIssuer()}} Returns the issuer distinguished name as an \module{x509.name} object. \subsubsection[\fn{crl:setIssuer}]{\fn{crl:setIssuer($name$)}} Sets the issuer distinguished name. $name$ should be an \module{x509.name} object. \subsubsection[\fn{crl:add}]{\fn{crl:add($serial$ [, $time$])}} Add the certificate identified by $serial$ to the revocation list. $serial$ should be a \module{openssl.bignum} object, as returned by \fn{x509:getSerial}. $time$ is the revocation date as a Unix timestamp. If unspecified $time$ defaults to the current time. \subsubsection[\fn{crl:addExtension}]{\fn{crl:addExtension($ext$)}} Adds a copy of the \module{x509.extension} object to the revocation list. \subsubsection[\fn{crl:getExtension}]{\fn{crl:getExtension($key$)}} Returns a copy of the \module{x509.extension} object identified by $key$ where $key$ is the plain text string of the OID, long name, or short name; or the integer index (1-based) of the extension. Returns nothing if no such extension was found by that name or at that index. \subsubsection[\fn{crl:getExtensionCount}]{\fn{crl:getExtensionCount()}} Returns the integer count of the number of extensions. \subsubsection[\fn{crl:sign}]{\fn{crl:sign($key$)}} Signs the instance CRL using the \module{openssl.pkey} $key$. \subsubsection[\fn{crl:verify}]{\fn{crl:verify($publickey$)}} Verifies the instance CRL using a public key. \subsubsection[\fn{crl:text}]{\fn{crl:text()}} Returns a human-readable textual representation of the instance CRL. \subsubsection[\fn{crl:\_\_tostring}]{\fn{crl:\_\_tostring}} Returns the PEM encoded representation of the instance CRL. \end{Module} \begin{Module}{openssl.x509.chain} Binds the ``STACK\_OF(X509)'' OpenSSL object, principally used in the OpenSSL library for representing a validation chain. \subsubsection[\fn{chain.new}]{\fn{chain.new()}} Returns a new chain object. \subsubsection[\fn{chain.interpose}]{\fn{chain.interpose($name$, $function$)}} Add or interpose a chain class method. Returns the previous method, if any. \subsubsection[\fn{chain:add}]{\fn{chain:add($crt$)}} Append the X.509 certificate $crt$. \subsubsection[\fn{chain:\_\_ipairs}]{\fn{chain:\_\_ipairs()}} Returns an iterator over the stored certificates. \end{Module} \begin{Module}{openssl.x509.store} Binds the X.509 certificate ``X509\_STORE'' OpenSSL object, principally used for loading and storing trusted certificates, paths to trusted certificates, and verification policy. \subsubsection[\fn{store.new}]{\fn{store.new()}} Returns a new store object. \subsubsection[\fn{store.interpose}]{\fn{store.interpose($name$, $function$)}} Add or interpose a store class method. Returns the previous method, if any. \subsubsection[\fn{store:add}]{\fn{store:add($crt$|$filepath$|$dirpath$)}} Add the X.509 certificate $crt$ to the store, load the certificates from the file $filepath$, or set the OpenSSL `hashdir' certificate path $dirpath$. \subsubsection[\fn{store:verify}]{\fn{store:verify($crt$[, $chain$])}} Returns two values. The first is a boolean value for whether the specified certificate $crt$ was verified. If true, the second value is a \module{openssl.x509.chain} object validation chain. If false, the second value is a string describing why verification failed. The optional parameter $chain$ is an \module{openssl.x509.chain} object of untrusted certificates linking the certificate $crt$ to one of the trusted certificates in the instance store. \end{Module} \begin{Module}{openssl.x509.verify\_param} Binds the ``X509\_VERIFY\_PARAM'' OpenSSL object, principally used for setting parameters to be used during certificate verification operations. \subsubsection[\fn{verify\_param.new}]{\fn{verify\_param.new()}} Returns a new verify\_param object. \subsubsection[\fn{verify\_param.interpose}]{\fn{verify\_param.interpose($name$, $function$)}} Add or interpose a verify\_param class method. Returns the previous method, if any. \subsubsection[\fn{verify\_param:inherit}]{\fn{verify\_param:inherit($src$)}} Inherit flags from $src$. $src$ can be either another \fn{verify\_param} object to inherit from, or a string referring to one of the OpenSSL predefined parameters: \begin{ctabular}{ l | p{5cm} } name & description \\\hline default & X509 default parameters \\ smime\_sign & S/MIME sign parameters \\ pkcs7 & Identical to $smime\_sign$ \\ ssl\_client & SSL/TLS client parameters \\ ssl\_server & SSL/TLS server parameters \end{ctabular} \subsubsection[\fn{verify\_param:setPurpose}]{\fn{verify\_param:setPurpose($id\_or\_name$)}} Sets the verification purpose of the $verify\_param$. Valid argument can be either an integer which corresponds to OpenSSL's internal purpose ID, or string indicating predefined purposes: \begin{ctabular}{ l | p{4cm} } name & description \\\hline sslclient & SSL/TLS client \\ sslserver & SSL/TLS server \\ nssslserver & Netscape SSL server \\ smimeencrypt & S/MIME encryption \\ any & Any Purpose \\ ocsphelper & OCSP helper \\ timestampsign & Time Stamp signing \end{ctabular} \subsubsection[\fn{verify\_param:setTime}]{\fn{verify\_param:setTime([$timestamp$])}} Sets the verification time in $verify\_param$ to the provided Unix timestamp. By default the current system time is used. \subsubsection[\fn{verify\_param:setDepth}]{\fn{verify\_param:setDepth($depth$)}} Sets the maximum verification depth to $depth$. That is the maximum number of untrusted CA certificates that can appear in a chain.\footnote{OpenSSL's behaviour in regards to depth changed between OpenSSL 1.0.1 and OpenSSL 1.0.2; similarly for LibreSSL} \subsubsection[\fn{verify\_param:getDepth}]{\fn{verify\_param:getDepth()}} Returns the current maximum verification depth. \subsubsection[\fn{verify\_param:setAuthLevel}]{\fn{verify\_param:setAuthLevel($auth\_level$)}} Sets the authentication security level to $auth\_level$. The authentication security level determines the acceptable signature and public key strength when verifying certificate chains. For a certificate chain to validate, the public keys of all the certificates must meet the specified security level. The signature algorithm security level is not enforced for the chain's trust anchor certificate, which is either directly trusted or validated by means other than its signature. See \href{https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html}{$SSL\_CTX\_set\_security\_level(3)$} for the definitions of the available levels. The default security level is -1, or "not set". At security level 0 or lower all algorithms are acceptable. Security level 1 requires at least 80-bit-equivalent security and is broadly interoperable, though it will, for example, reject MD5 signatures or RSA keys shorter than 1024 bits. \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{verify\_param:getAuthLevel}]{\fn{verify\_param:getAuthLevel()}} Returns the current authentication security level. \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{verify\_param:setHost}]{\fn{verify\_param:setHost($name$)}} Sets the expected DNS hostname to the string $name$, overriding any previously specified host name or names. If $name$ is $nil$ then name checks will not be performed on the peer certificate. \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{verify\_param:addHost}]{\fn{verify\_param:addHost($name$)}} Adds $name$ as an additional reference identifier that can match the peer's certificate. Any previous names set via \fn{verify\_param:setHost} or \fn{verify\_param:addHost} are retained. When multiple names are configured, the peer is considered verified when any name matches. \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{verify\_param:setEmail}]{\fn{verify\_param:setEmail($email$)}} Sets the expected RFC822 email address to the string $email$, overriding any previously specified email address. \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{verify\_param:setIP}]{\fn{verify\_param:setIP($address$)}} Sets the expected IP address to $address$. Can be dotted decimal quad for IPv4 and colon-separated hexadecimal for IPv6. The condensed "::" notation is supported for IPv6 addresses. \emph{Only supported since OpenSSL 1.1.0.} \end{Module} \begin{Module}{openssl.pkcs12} Binds the PKCS \#12 container OpenSSL object. \subsubsection[\fn{pkcs12.new}]{\fn{pkcs12.new\{ $\ldots$ \}}} Returns a new PKCS12 object initialized according to the named parameters---$password$, $key$, $certs$. FIXME. \subsubsection[\fn{pkcs12.interpose}]{\fn{pkcs12.interpose($name$, $function$)}} Add or interpose a store class method. Returns the previous method, if any. \subsubsection[\fn{pkcs12:\_\_tostring}]{\fn{pkcs12:\_\_tostring()}} Returns a PKCS \#12 binary encoded string. \subsubsection[\fn{pkcs12.parse}]{\fn{pkcs12.parse($bag$[, $passphrase$])}} Parses a PKCS\#12 bag, presented as a binary string $bag$. The second parameter $passphrase$ is the passphrase required to decrypt the PKCS\#12 bag. The function returns three items; namely the key, certificate and the CA chain, as their respective objects. If an item is absent, it will be substituted with nil. \end{Module} \begin{Module}{openssl.ssl.context} Binds the ``SSL\_CTX'' OpenSSL object, used as a configuration prototype for SSL connection instances. See \method{socket.starttls}. \subsubsection[\fn{context[]}]{\fn{context[]}} A table mapping OpenSSL named constants. The available constants are documented with the relevant method. \subsubsection[\fn{context.new}]{\fn{context.new([$protocol$][, $server$])}} Returns a new context object. $protocol$ is an optional string identifier selecting the OpenSSL constructor, defaulting to ``TLS''. If $server$ is true, then SSL connections instantiated using this context will be placed into server mode, otherwise they behave as clients. \begin{ctabular}{ c | p{14cm} } \multicolumn{2}{c}{$protocol$ identifiers}\\\hline\hline name & \href{https://www.openssl.org/docs/ssl/SSL_CTX_new.html}{description} \\\hline TLS & Supports TLS 1.0 \emph{and above}. Internally uses \fn{SSLv23\_method} and disables SSLv2 and SSLv3 using \texttt{SSL\_OP\_NO\_SSLv2} and \texttt{SSL\_OP\_NO\_SSLv3}.\\ SSL & Supports SSL 3.0 \emph{and above}. Internally uses \fn{SSLv23\_method} and disables SSLv2 using \texttt{SSL\_OP\_NO\_SSLv2}.\\ SSLv23 & A catchall for all versions of SSL/TLS supported by OpenSSL. Individual versions can be disabled using \method{context:setOptions}. Internally uses \fn{SSLv23\_method}.\\ TLSv1\_2 & Supports \emph{only} TLS 1.2. Internally uses \fn{TLSv1\_2\_method}.\\ TLSv1\_1 & Supports \emph{only} TLS 1.1. Internally uses \fn{TLSv1\_1\_method}.\\ TLSv1 & Supports \emph{only} TLS 1.0. Internally uses \fn{TLSv1\_method}.\\ SSLv3 & Supports \emph{only} SSL 3.0. Internally uses \fn{SSLv3\_method}.\\ SSLv2 & Supports \emph{only} SSL 2.0. Internally uses \fn{SSLv2\_method}. \\ DTLS & Supports DTLS 1.0 \emph{and above}. Internally uses \fn{DTLS\_method}. \\ DTLSv1 & Supports \emph{only} DTLS 1.0. Internally uses \fn{DTLSv1\_method}. \\ DTLSv1\_2 & Supports \emph{only} DTLS 1.2. Internally uses \fn{DTLSv1\_2\_method}. \end{ctabular} \subsubsection[\fn{context.interpose}]{\fn{context.interpose($name$, $function$)}} Add or interpose a context class method. Returns the previous method, if any. \subsubsection[\fn{context:setOptions}]{\fn{context:setOptions($flags$)}} Adds the option flags to the context instance. $flags$ is a bit-wise set of option flags to be ORd with the current set. The resultant option flags of the context instance will be the union of the old and new flags.\footnote{This idiosyncratic union behavior is how the OpenSSL routine works.} \begin{ctabular}{ c | p{8cm} } name & \href{https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html}{description} \\\hline \small{\texttt{OP\_MICROSOFT\_SESS\_ID\_BUG}} & When talking SSLv2, if session-id reuse is performed, the session-id passed back in the server-finished message is different from the one decided upon. \\ \small{\texttt{OP\_NETSCAPE\_CHALLENGE\_BUG}} & Workaround for Netscape-Commerce/1.12 servers. \\ \small{\texttt{OP\_LEGACY\_SERVER\_CONNECT}} & $\ldots$ \\ \small{\texttt{OP\_NETSCAPE\_REUSE\_CIPHER\_CHANGE\_BUG}} & As of OpenSSL 0.9.8q and 1.0.0c, this option has no effect. \\ \small{\texttt{OP\_SSLREF2\_REUSE\_CERT\_TYPE\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_TLSEXT\_PADDING}} & $\ldots$ \\ \small{\texttt{OP\_MICROSOFT\_BIG\_SSLV3\_BUFFER}} & $\ldots$ \\ \small{\texttt{OP\_SAFARI\_ECDHE\_ECDSA\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_MSIE\_SSLV2\_RSA\_PADDING}} & $\ldots$ \\ \small{\texttt{OP\_SSLEAY\_080\_CLIENT\_DH\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_TLS\_D5\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_TLS\_BLOCK\_PADDING\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_ALLOW\_NO\_DHE\_KEX}} & Allow a non-(ec)dhe based kex\_mode. \\ \small{\texttt{OP\_DONT\_INSERT\_EMPTY\_FRAGMENTS}} & Disables a countermeasure against a SSL 3.0/TLS 1.0 protocol vulnerability affecting CBC ciphers, which cannot be handled by some broken SSL implementations. This option has no effect for connections using other ciphers. \\ \small{\texttt{OP\_NO\_QUERY\_MTU}} & $\ldots$ \\ \small{\texttt{OP\_COOKIE\_EXCHANGE}} & $\ldots$ \\ \small{\texttt{OP\_NO\_TICKET}} & Disable RFC4507bis ticket stateless session resumption. \\ \small{\texttt{OP\_CISCO\_ANYCONNECT}} & $\ldots$ \\ \small{\texttt{OP\_NO\_SESSION\_RESUMPTION\_ON\_RENEGOTIATION}} & When performing renegotiation as a server, always start a new session (i.e., session resumption requests are only accepted in the initial handshake). This option is not needed for clients. \\ \small{\texttt{OP\_NO\_COMPRESSION}} & $\ldots$ \\ \small{\texttt{OP\_ALLOW\_UNSAFE\_LEGACY\_RENEGOTIATION}} & $\ldots$ \\ \small{\texttt{OP\_SINGLE\_ECDH\_USE}} & Always create a new key when using temporary/ephemeral ECDH parameters. \\ \small{\texttt{OP\_NO\_ENCRYPT\_THEN MAC}} & $\ldots$ \\ \small{\texttt{OP\_SINGLE\_DH\_USE}} & Always create a new key when using temporary/ephemeral DH parameters. \\ \small{\texttt{OP\_EPHEMERAL\_RSA}} & Always use ephemeral (temporary) RSA key when doing RSA operations. \\ \small{\texttt{OP\_PRIORITIZE\_CHACHA}} & Prioritize ChaCha20Poly1305 on servers when client does. \\ \small{\texttt{OP\_ENABLE\_MIDDLEBOX\_COMPAT}} & TLSv1.3 Compatibility mode. \\ \small{\texttt{OP\_NO\_ANTI\_REPLAY}} & TLSv1.3 anti-replay protection for early data. \\ \small{\texttt{OP\_CIPHER\_SERVER\_PREFERENCE}} & When choosing a cipher, use the server's preferences instead of the client preferences. \\ \small{\texttt{OP\_TLS\_ROLLBACK\_BUG}} & Disable version rollback attack detection. \\ \small{\texttt{OP\_NO\_SSLv2}} & Do not use the SSLv2 protocol. \\ \small{\texttt{OP\_NO\_SSLv3}} & Do not use the SSLv3 protocol. \\ \small{\texttt{OP\_NO\_TLSv1}/\texttt{OP\_NO\_DTLSv1}} & Do not use the (D)TLSv1.0 protocol. \\ \small{\texttt{OP\_NO\_TLSv1\_2}/\texttt{OP\_NO\_DTLSv1\_2}} & Do not use the (D)TLSv1.2 protocol. \\ \small{\texttt{OP\_NO\_TLSv1\_1}} & Do not use the TLSv1.1 protocol. \\ \small{\texttt{OP\_NETSCAPE\_CA\_DN\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_NO\_TLSv1\_3}} & $\ldots$ \\ \small{\texttt{OP\_NETSCAPE\_DEMO\_CIPHER\_CHANGE\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_NO\_RENEGOTIATION}} & $\ldots$ \\ \small{\texttt{OP\_CRYPTOPRO\_TLSEXT\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_PKCS1\_CHECK\_1}} & $\ldots$ \\ \small{\texttt{OP\_PKCS1\_CHECK\_2}} & $\ldots$ \\ \small{\texttt{OP\_NO\_SSL\_MASK}} & $\ldots$ \\ \small{\texttt{OP\_ALL}} & All of the bug workarounds. \\ \end{ctabular} \subsubsection[\fn{context:getOptions}]{\fn{context:getOptions()}} Returns the option flags of the context instance as an integer. \subsubsection[\fn{context:clearOptions}]{\fn{context:clearOptions()}} Clears the option flags of the context instance. \subsubsection[\fn{context:setReadAhead}]{\fn{context:setReadAhead($yes$)}} Sets if read ahead is enabled for the context, $yes$ should be a boolean. \subsubsection[\fn{context:getReadAhead}]{\fn{context:getReadAhead()}} Returns if read ahead is enabled for the context instance as a boolean. \subsubsection[\fn{context:setStore}]{\fn{context:setStore($store$)}} Associate the \module{openssl.x509.store} object $store$ with $context$. Replaces any existing store. \subsubsection[\fn{context:getStore}]{\fn{context:getStore()}} Returns the \module{openssl.x509.store} object associated with $context$. \subsubsection[\fn{context:setParam}]{\fn{context:setParam($params$)}} Causes $context$ to inherit the parameters from the \module{openssl.x509.verify\_param} object $params$. Only parameters set in $params$ will take effect (others will stay unchanged). \subsubsection[\fn{context:getParam}]{\fn{context:getParam()}} Returns an \module{openssl.x509.verify\_param} object containing a copy of $context$'s parameters. \subsubsection[\fn{context:setVerify}]{\fn{context:setVerify([$mode$][, $depth$])}} Sets the verification mode flags and maximum validation chain depth. \begin{tabular}{ c | l } name & description \\\hline VERIFY\_NONE & disable client peer certificate verification \\ VERIFY\_PEER & enable client peer certificate verification \\ VERIFY\_FAIL\_IF\_NO\_PEER\_CERT & require a peer certificate \\ VERIFY\_CLIENT\_ONCE & do not request peer certificates after initial handshake \end{tabular} See the \href{http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html#NOTES}{NOTES section} in the OpenSSL documentation for \fn{SSL\_CTX\_set\_verify\_mode}. \subsubsection[\fn{context:getVerify}]{\fn{context:getVerify()}} Returns two values: the bitwise verification mode flags, and the maximum validation depth. \subsubsection[\fn{context:setCertificate}]{\fn{context:setCertificate($crt$)}} Sets the X.509 certificate \module{openssl.x509} object $crt$ to send during SSL connection instance handshakes. \subsubsection[\fn{context:getCertificate}]{\fn{context:getCertificate()}} Returns the X.509 certificate \module{openssl.x509} object to be sent during SSL connection instance handshakes. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{context:setCertificateChain}]{\fn{context:setCertificateChain($chain$)}} Sets the X.509 certificate chain \module{openssl.x509.chain} object $chain$ to send during SSL connection instance handshakes. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{context:getCertificateChain}]{\fn{context:getCertificateChain()}} Returns the X.509 certificate chain \module{openssl.x509.chain} object to be sent during SSL connection instance handshakes. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{context:setPrivateKey}]{\fn{context:setPrivateKey($key$)}} Sets the private key \module{openssl.pkey} object $key$ for use during SSL connection instance handshakes. \subsubsection[\fn{context:setCipherList}]{\fn{context:setCipherList($string$ [, ...])}} Sets the allowed public key and private key algorithm(s). The string format is documented in the \href{http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT}{OpenSSL ciphers(1) utility documentation}. \subsubsection[\fn{context:setCipherSuites}]{\fn{context:setCipherSuites($string$ [, ...])}} Sets the supported TLS 1.3 cipher suites. The string format is a list of colon separated curve names similar to \texttt{ctx:setCipherList(...)}. \emph{Only supported since OpenSSL 1.1.1.} \subsubsection[\fn{context:setGroups}]{\fn{context:setGroups($string$ [, ...])}} Sets the supported groups. The string format is a list of colon separated group names similar to \texttt{ctx:setCipherList(...)}. A list of supported EC groups can be found by running \texttt{openssl ecparam -list\_curves}. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{context:setEphemeralKey}]{\fn{context:setEphemeralKey($key$)}} Sets \module{openssl.pkey} object $key$ as the ephemeral key during key exchanges which use that particular key type. Typically $key$ will be either a Diffie-Hellman or Elliptic Curve key. \emph{In older version of OpenSSL, in order to configure an SSL server to support an ephemeral key exchange cipher suite (i.e. DHE-* and ECDHE-*), the application must explicitly set the ephemeral keys. Simply enabling the cipher suite is not sufficient. The application can statically generate Diffie-Hellman public key parameters, and many servers ship with such a key compiled into the software. Elliptic curve keys are necessarily static, and instantiated by curve name\footnote{OpenSSL < 1.0.2 only supports a single curve, \href{http://en.wikipedia.org/w/index.php?title=Comparison\_of\_TLS\_implementations&oldid=629779090\#Supported\_elliptic\_curves}{according to Wikipedia} the most widely supported curve is prime256v1, so to enable ECDHE-*, applications can simply do \texttt{ctx:setEphemeralKey(pkey.new\{ type = ``EC'', curve = ``prime256v1'' \})}. For OpenSSL versions >= 1.0.2, see \fn{context:setGroups} instead. To achieve Perfect Forward Secrecy for ECDHE-*, applications must also do \texttt{ctx:setOptions(context.OP\_SINGLE\_ECDH\_USE)}. The \texttt{ctx} object must then be used to configure each SSL session, such as by passing it to \fn{cqueues.socket:starttls()}.}.} \emph{In addition, to attain Perfect Forward Secrecy the options \texttt{OP\_SINGLE\_DH\_USE} and \texttt{OP\_SINGLE\_ECDH\_USE} must be set so that OpenSSL discards and regenerates the secret keying parameters for each key exchange.} \subsubsection[\fn{context:setAlpnProtos}]{\fn{context:setAlpnProtos($table$)}} Sets the advertised ALPN protocols. $table$ is an array of protocol string identifiers. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{context:setAlpnSelect}]{\fn{context:setAlpnSelect($cb$)}} Sets the callback used to select an ALPN protocol. $cb$ should be a function that takes two arguments: an \module{openssl.ssl} object and a table containing a sequence of ALPN protocol strings; it should return the ALPN protocol string it selected or $nil$ to select none of them. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{context:setHostNameCallback}]{\fn{context:setHostNameCallback($cb$)}} Sets the callback used to process the SNI in a ClientHello. $cb$ should be a function that one argument: a \module{openssl.ssl} object; it should return $true$ to indicate success, $false$ if no acknowledgement should be send to the client, or $nil$ and an integer to send an error to the peer. \emph{Only supported since OpenSSL 1.0.0.} \subsubsection[\fn{context:setTLSextStatusType}]{\fn{context:setTLSextStatusType($type$)}} Sets the default TLS extension status for SSL objects derived from this context. See \fn{ssl:setTLSextStatusType} \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{context:getTLSextStatusType}]{\fn{context:getTLSextStatusType()}} Gets the default TLS extension status for SSL objects derived from this context as a string. See \fn{ssl:getTLSextStatusType} \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{context:getTicketKeysLength}]{\fn{context:getTicketKeysLength()}} Returns the expected length of ticket keys data. See \fn{context:setTicketKeys} \emph{Only supported since OpenSSL 1.0.0.} \subsubsection[\fn{context:setTicketKeys}]{\fn{context:setTicketKeys($keys$)}} Sets the current random data used to generate tickets. $keys$ should be a string of the length returned by \fn{context:getTicketKeysLength}. \emph{Only supported since OpenSSL 1.0.0.} \subsubsection[\fn{context:getTicketKeys}]{\fn{context:getTicketKeys()}} Returns the current random data used to generate tickets. See \fn{context:setTicketKeys} \emph{Only supported since OpenSSL 1.0.0.} \subsubsection[\fn{context:useServerInfo}]{\fn{context:useServerInfo($version$, $serverinfo$)}} If version is $1$ then the extensions in the array must consist of a 2-byte Extension Type, a 2-byte length, and then length bytes of extension data. The type value has the same meaning as for \fn{context:addCustomExtension}. If version is $2$ then the extensions in the array must consist of a 4-byte context, a 2-byte Extension Type, a 2-byte length, and then length bytes of extension\_data. The context and type values have the same meaning as for \fn{context:addCustomExtension}. If serverinfo is being loaded for extensions to be added to a Certificate message, then the extension will only be added for the first certificate in the message (which is always the end-entity certificate). \emph{Only supported since OpenSSL 1.0.2, ServerInfo version 2 is only supported since OpenSSL 1.1.1} \subsubsection[\fn{context:useServerInfoFile}]{\fn{context:useServerInfoFile($file$)}} Loads one or more serverinfo extensions from $file$ into $context$. The extensions must be in PEM format. Each extension must be in a format as described above for \fn{context:useServerInfo}. Each PEM extension name must begin with the phrase ``BEGIN SERVERINFOV2 FOR '' for version 2 data or ``BEGIN SERVERINFO FOR '' for version 1 data. \emph{Only supported since OpenSSL 1.0.2} \subsubsection[\fn{context:addCustomExtension}]{\fn{context:addCustomExtension($ext\_type$, $ext\_context$, $add\_cb$, $parse\_cb$)}} Adds a custom extension with the TLS extension type (see RFC 5246) $ext\_type$ that may be present in the context(s) specifed by $ext\_context$, which should be a bitmask of the flags: \begin{ctabular}{ l | p{8cm} } name & description \\\hline EXT\_TLS\_ONLY & The extension is only allowed in TLS \\ EXT\_DTLS\_ONLY & The extension is only allowed in DTLS \\ EXT\_TLS\_IMPLEMENTATION\_ONLY & The extension is allowed in DTLS, but there is only a TLS implementation available (so it is ignored in DTLS). \\ EXT\_SSL3\_ALLOWED & Extensions are not typically defined for SSLv3. Setting this value will allow the extension in SSLv3. Applications will not typically need to use this. \\ EXT\_TLS1\_2\_AND\_BELOW\_ONLY & The extension is only defined for TLSv1.2/DTLSv1.2 and below. Servers will ignore this extension if it is present in the ClientHello and TLSv1.3 is negotiated. \\ EXT\_TLS1\_3\_ONLY & The extension is only defined for TLS1.3 and above. Servers will ignore this extension if it is present in the ClientHello and TLSv1.2 or below is negotiated. \\ EXT\_IGNORE\_ON\_RESUMPTION & The extension will be ignored during parsing if a previous session is being successfully resumed. \\ EXT\_CLIENT\_HELLO & The extension may be present in the ClientHello message. \\ EXT\_TLS1\_2\_SERVER\_HELLO & The extension may be present in a TLSv1.2 or below compatible ServerHello message. \\ EXT\_TLS1\_3\_SERVER\_HELLO & The extension may be present in a TLSv1.3 compatible ServerHello message. \\ EXT\_TLS1\_3\_ENCRYPTED\_EXTENSIONS & The extension may be present in an EncryptedExtensions message. \\ EXT\_TLS1\_3\_HELLO\_RETRY\_REQUEST & The extension may be present in a HelloRetryRequest message. \\ EXT\_TLS1\_3\_CERTIFICATE & The extension may be present in a TLSv1.3 compatible Certificate message. \\ EXT\_TLS1\_3\_NEW\_SESSION\_TICKET & The extension may be present in a TLSv1.3 compatible NewSessionTicket message. \\ EXT\_TLS1\_3\_CERTIFICATE\_REQUEST & The extension may be present in a TLSv1.3 compatible CertificateRequest message. \end{ctabular} $add\_cb$ should be a function with signature \fn{add\_cb($ssl$, $ext\_type$, $ext\_context$, $x509$, $chainidx$)}; it will be called from the relevant context to allow you to insert extension data. It receives the $ssl$ object of the connection, the $ext\_type$ you registered the callback for, the current $context$ and, for only some contexts, the current \module{openssl.x509} certificate and chain index (as an integer). You should return the extension data as a string, $false$ if you don't want to add your extension, or $nil$ and an optional integer specifying the TLS error code to raise an error. $parse\_cb$ should be a function with signature \fn{parse\_cb($ssl$, $ext\_type$, $ext\_context$, $data$, $x509$, $chainidx$)}; it will be called from the relevant context to allow you to parse extension data. It receives the $ssl$ object of the connection, the $ext\_type$ you registered the callback for, the current $context$, the extension $data$ as a string, and for only some contexts, the current \module{openssl.x509} certificate and chain index (as an integer). You should return $true$ on success, or $nil$ and an optional integer specifying the TLS error code to raise an error. \emph{Only supported since OpenSSL 1.1.1.} \end{Module} \begin{Module}{openssl.ssl} Binds the ``SSL'' OpenSSL object, which represents an SSL connection instance. See \method{cqueues.socket:checktls}. \subsubsection[\fn{ssl[]}]{\fn{ssl[]}} A table mapping OpenSSL named constants. Includes all constants provided by \module{openssl.ssl.context}. Additional constants are documented with the relevant method. \subsubsection[\fn{ssl.interpose}]{\fn{ssl.interpose($name$, $function$)}} Add or interpose an ssl class method. Returns the previous method, if any. \subsubsection[\fn{ssl:setContext}]{\fn{ssl:setContext($context$)}} Replaces the \module{openssl.ssl.context} used by $ssl$ with $context$. \subsubsection[\fn{ssl:getContext}]{\fn{ssl:getContext()}} Returns the \module{openssl.ssl.context} used by $ssl$. \subsubsection[\fn{ssl:setOptions}]{\fn{ssl:setOptions($flags$)}} Adds the option flags of the SSL connection instance. See \fn{openssl.ssl.context:setOptions}. \subsubsection[\fn{ssl:getOptions}]{\fn{ssl:getOptions()}} Returns the option flags of the SSL connection instance. See \fn{openssl.ssl.context:getOptions}. \subsubsection[\fn{ssl:clearOptions}]{\fn{ssl:clearOptions()}} Clears the option flags of the SSL connection instance. See \fn{openssl.ssl.context:clearOptions}. \subsubsection[\fn{ssl:setReadAhead}]{\fn{ssl:setReadAhead($yes$)}} Sets if read ahead is enabled for the SSL connection instance, $yes$ should be a boolean. \subsubsection[\fn{ssl:getReadAhead}]{\fn{ssl:getReadAhead()}} Returns if read ahead is enabled for the SSL connection instance as a boolean. \subsubsection[\fn{ssl:setStore}]{\fn{ssl:setStore($store$)}} Associate the \module{openssl.x509.store} object $store$ with $ssl$ for both verification and chain building. Replaces any existing stores. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{ssl:setChainStore}]{\fn{ssl:setChainStore($store$)}} Associate the \module{openssl.x509.store} object $store$ with $ssl$ for chain building. Replaces any existing store. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{ssl:setVerifyStore}]{\fn{ssl:setVerifyStore($store$)}} Associate the \module{openssl.x509.store} object $store$ with $ssl$ for verification. Replaces any existing store. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{ssl:setVerify}]{\fn{ssl:setVerify([$mode$][, $depth$])}} Sets the verification mode flags and maximum validation chain depth. See \fn{openssl.ssl.context:setVerify}. \subsubsection[\fn{ssl:getVerify}]{\fn{ssl:getVerify()}} Returns two values: the bitwise verification mode flags, and the maximum validation depth. See \fn{openssl.ssl.context:getVerify}. \subsubsection[\fn{ssl:getVerifyResult}]{\fn{ssl:getVerifyResult()}} Returns two values: the integer verification result code and the string representation of that code. \subsubsection[\fn{ssl:setCertificate}]{\fn{ssl:setCertificate($crt$)}} Sets the X.509 certificate \module{openssl.x509} object $crt$ to send during SSL connection instance handshakes. See \fn{openssl.ssl.context:setCertificate}. \subsubsection[\fn{ssl:setCertificateChain}]{\fn{ssl:setCertificateChain($chain$)}} Sets the X.509 certificate chain \module{openssl.x509.chain} object $chain$ to send during SSL connection instance handshakes. See \fn{openssl.ssl.context:setCertificateChain}. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{context:getCertificateChain}]{\fn{context:getCertificateChain()}} Returns the X.509 certificate chain \module{openssl.x509.chain} object to be sent during SSL connection instance handshakes. See \fn{openssl.ssl.context:getCertificateChain}. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{ssl:setPrivateKey}]{\fn{ssl:setPrivateKey($key$)}} Sets the private key \module{openssl.pkey} object $key$ for use during SSL connection instance handshakes. See \fn{openssl.ssl.context:setPrivateKey}. \subsubsection[\fn{ssl:getPeerCertificate}]{\fn{ssl:getPeerCertificate()}} Returns the X.509 peer certificate as an \module{openssl.x509} object. If no peer certificate is available, returns $nil$. \subsubsection[\fn{ssl:getPeerChain}]{\fn{ssl:getPeerChain()}} Similar to :getPeerCertifiate, but returns the entire chain sent by the peer as an \module{openssl.x509.chain} object. \subsubsection[\fn{ssl:getCipherInfo}]{\fn{ssl:getCipherInfo()}} Returns a table of information on the current cipher. \begin{tabular}{ c | l } field & description\\\hline .name & cipher name returned by \fn{SSL\_CIPHER\_get\_name}\\ .bits & number of secret bits returned by \fn{SSL\_CIPHER\_get\_bits}\\ .version & SSL/TLS version string returned by \fn{SSL\_CIPHER\_get\_version}\\ .description & key:value cipher description returned by \fn{SSL\_CIPHER\_description} \end{tabular} \subsubsection[\fn{ssl:setHostName}]{\fn{ssl:setHostName($host$)}} Sets the Server Name Indication (SNI) host name. Using the SNI TLS extension, clients tells the server which domain they're contacting so the server can select the proper certificate and key. This permits SSL virtual hosting. This routine is only relevant for clients. \subsubsection[\fn{ssl:getHostName}]{\fn{ssl:getHostName()}} Returns the Server Name Indication (SNI) host name sent by the client. If no host name was sent, returns $nil$. This routine is only relevant for servers. \subsubsection[\fn{ssl:getVersion}]{\fn{ssl:getVersion([$format$])}} Returns the SSL/TLS version of the negotiated SSL connection. By default returns a 16-bit integer where the top 8 bits are the major version number and the bottom 8 bits the minor version number. For example, SSL 3.0 is 0x0300 and TLS 1.1 is 0x0302. SSL 2.0 is 0x0002. If $format$ is ``.'' returns a floating point number. 0x0300 becomes 3.0, and 0x0302 becomes 3.2. If the minor version is $\geq$ 10 an error is thrown.\footnote{This condition shouldn't be possible.} The following OpenSSL named constants can be used. \begin{tabular}{ c | l } name & description \\\hline SSL2\_VERSION & 16-bit SSLv2 identifier (0x0002). \\ SSL3\_VERSION & 16-bit SSLv3 identifier (0x0300). \\ TLS1\_VERSION & 16-bit TLSv1.0 identifier (0x0301). \\ TLS1\_1\_VERSION & 16-bit TLSv1.1 identifier (0x0302). \\ TLS1\_2\_VERSION & 16-bit TLSv1.2 identifier (0x0303). \\ \end{tabular} \subsubsection[\fn{ssl:getClientVersion}]{\fn{ssl:getClientVersion([$format$])}} Returns the SSL/TLS version supported by the client, which should be greater than or equal to the negotiated version. See \fn{ssl:getVersion}. \subsubsection[\fn{ssl:setCipherList}]{\fn{ssl:setCipherList($string$ [, ...])}} Sets the allowed public key and private key algorithm(s). See \fn{openssl.ssl.context:setCipherList}. \subsubsection[\fn{ssl:setCipherSuites}]{\fn{ssl:setCipherSuites($string$ [, ...])}} Sets the supported TLS 1.3 cipher suites for this SSL connection instance. See \fn{openssl.ssl.context:setCipherSuites}. \emph{Only supported since OpenSSL 1.1.1.} \subsubsection[\fn{ssl:setGroups}]{\fn{ssl:setGroups($string$ [, ...])}} Sets the supported groups for this SSL connection instance. See \fn{openssl.ssl.context:setGroups}. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{ssl:getAlpnSelected}]{\fn{ssl:getAlpnSelected()}} Returns the negotiated ALPN protocol as a string. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{ssl:setAlpnProtos}]{\fn{ssl:setAlpnProtos($table$)}} Sets the advertised ALPN protocols. $table$ is an array of protocol string identifiers. \emph{Only supported since OpenSSL 1.0.2.} \subsubsection[\fn{ssl:setTLSextStatusType}]{\fn{ssl:setTLSextStatusType($type$)}} Sets the TLS extension status. Only the $type$ ``ocsp'' is currently supported, this is used by a client to request that a server sends a stapled OCSP response as part of the TLS handshake. See also: \fn{context:setTLSextStatusType()} \subsubsection[\fn{ssl:getTLSextStatusType}]{\fn{ssl:getTLSextStatusType()}} Gets the TLS extension status. As set by \fn{ssl:setTLSextStatusType} or \fn{context:setTLSextStatusType}. Only the type ``ocsp'' is currently known. \emph{Only supported since OpenSSL 1.1.0.} \subsubsection[\fn{ssl:setTLSextStatusOCSPResp}]{\fn{ssl:setTLSextStatusOCSPResp($or$)}} Sets an \module{openssl.ocsp.response}. Used by a server to staple an OCSP response into a TLS handshake. \subsubsection[\fn{ssl:getTLSextStatusOCSPResp}]{\fn{ssl:getTLSextStatusOCSPResp()}} Returns the \module{openssl.ocsp.response} associated with the ssl object (or $nil$ if one has not been set). \end{Module} \begin{Module}{openssl.digest} Binds the ``EVP\_MD\_CTX'' OpenSSL object, which represents a cryptographic message digest (i.e. hashing) algorithm instance. \subsubsection[\fn{digest.interpose}]{\fn{digest.interpose($name$, $function$)}} Add or interpose a digest class method. Returns the previous method, if any. \subsubsection[\fn{digest.new}]{\fn{digest.new([$type$])}} Return a new digest instance using the specified algorithm $type$. $type$ is a string suitable for passing to the OpenSSL routine EVP\_get\_digestbyname, and defaults to ``sha1''. \subsubsection[\fn{digest:update}]{\fn{digest:update([$string$ [, ...]])}} Update the digest with the specified string(s). Returns the digest object. \subsubsection[\fn{digest:final}]{\fn{digest:final([$string$ [, ...]])}} Update the digest with the specified string(s). Returns the final message digest as a binary string. \end{Module} \begin{Module}{openssl.hmac} Binds the ``HMAC\_CTX'' OpenSSL object, which represents a cryptographic HMAC algorithm instance. \subsubsection[\fn{hmac.interpose}]{\fn{hmac.interpose($name$, $function$)}} Add or interpose an HMAC class method. Returns the previous method, if any. \subsubsection[\fn{hmac.new}]{\fn{hmac.new($key$ [, $type$])}} Return a new HMAC instance using the specified $key$ and $type$. $key$ is the secret used for HMAC authentication. $type$ is a string suitable for passing to the OpenSSL routine EVP\_get\_digestbyname, and defaults to ``sha1''. \subsubsection[\fn{hmac:update}]{\fn{hmac:update([$string$ [, ...]])}} Update the HMAC with the specified string(s). Returns the HMAC object. \subsubsection[\fn{hmac:final}]{\fn{hmac:final([$string$ [, ...]])}} Update the HMAC with the specified string(s). Returns the final HMAC checksum as a binary string. \end{Module} \begin{Module}{openssl.cipher} Binds the ``EVP\_CIPHER\_CTX'' OpenSSL object, which represents a cryptographic cipher instance. \subsubsection[\fn{cipher.interpose}]{\fn{cipher.interpose($name$, $function$)}} Add or interpose a cipher class method. Returns the previous method, if any. \subsubsection[\fn{cipher.new}]{\fn{cipher.new($type$)}} Return a new, uninitialized cipher instance. $type$ is a string suitable for passing to the OpenSSL routine EVP\_get\_cipherbyname, typically of a form similar to ``AES-128-CBC''. The cipher is uninitialized because some algorithms support or require additional \textit{ad hoc} parameters before key initialization. The API still allows one-shot encryption like ``cipher.new(type):encrypt(key, iv):final(plaintext)''. \subsubsection[\fn{cipher:encrypt}]{\fn{cipher:encrypt($key$ [, $iv$] [, $padding$])}} Initialize the cipher in encryption mode. $key$ and $iv$ are binary strings with lengths equal to that required by the cipher instance as configured. In other words, key stretching and other transformations must be done explicitly. If the mode does not take an IV or equivalent, such as in ECB mode, then it may be nil. $padding$ is a boolean which controls whether PKCS padding is applied, and defaults to true. Returns the cipher instance. \subsubsection[\fn{cipher:decrypt}]{\fn{cipher:decrypt($key$ [, $iv$] [, $padding$])}} Initialize the cipher in decryption mode. $key$, $iv$, and $padding$ are as described in \fn{:encrypt}. Returns the cipher instance. \subsubsection[\fn{cipher:update}]{\fn{cipher:update([$string$ [, ...]])}} Update the cipher instance with the specified string(s). Returns a string on success, or nil and an error message on failure. The returned string may be empty if no blocks can be flushed. \subsubsection[\fn{cipher:final}]{\fn{cipher:final([$string$ [, ...]])}} Update the cipher with the specified string(s). Returns the final output string on success, or nil and an error message on failure. The returned string may be empty if all blocks have already been flushed in prior \fn{:update} calls. \subsubsection[\fn{cipher:getTag}]{\fn{cipher:getTag($len$)}} Returns the authentication tag for the ciphertext (GCM ciphers only) as a binary string. This method can only be called when encrypting data, and must be called after all data has been processed (i.e. after calling \fn{:final()}). \subsubsection[\fn{cipher:setTag}]{\fn{cipher:setTag($tag$)}} Sets the provided binary string as the expected authentication tag for the forthcoming ciphertext (GCM ciphers only). This method can only be called when decrypting data, and must be called before \fn{:final()} to ensure the ciphertext integrity can be verified successfully. \end{Module} \begin{Module}{openssl.ocsp.response} Binds OpenSSL's \texttt{OCSP\_RESPONSE} object. \subsubsection[\fn{response:getBasic}]{\fn{response:getBasic()}} Returns a \module{openssl.ocsp.basic} representation of the object contained within the OCSP response. \subsubsection[\fn{response:tostring}]{\fn{response:tostring()}} Returns a human readable description of the OCSP response as a string. \subsubsection[\fn{response:toPEM}]{\fn{response:toPEM()}} Returns the OCSP response as a PEM encoded string. \end{Module} \begin{Module}{openssl.ocsp.basic} Binds OpenSSL's \texttt{OCSP\_BASICRESP} object. \subsubsection[\fn{basic:verify}]{\fn{basic:verify([$certs$ [, $store$[, $flags$]]])}} Verifies that the OCSP response is signed by a certificate in the \module{openssl.x509.chain} $certs$ or a trusted certificate in \module{openssl.x509.store} $store$. \end{Module} \begin{Module}{openssl.rand} Binds OpenSSL's random number interfaces. OpenSSL will automatically attempt to seed itself from the system. The only time this could theoretically fail is if /dev/urandom (or similar) were not visible or could not be opened. This might happen if within a chroot jail, or if a file descriptor limit were reached. \subsubsection[\fn{rand.bytes}]{\fn{rand.bytes($count$)}} Returns $count$ cryptographically-strong bytes as a single string. Throws an error if OpenSSL could not complete the request---e.g. because the CSPRNG could not be seeded. \subsubsection[\fn{rand.ready}]{\fn{rand.ready()}} Returns a boolean describing whether the CSPRNG has been properly seeded. In the default CSPRNG engine this routine will also attempt to seed the system if not already. Because seeding only needs to happen once per process to ensure a successful RAND\_bytes invocation\footnote{At least this appeared to be the case when examining the source code of OpenSSL 1.0.1. See md\_rand.c near line 407---``Once we've had enough initial seeding we don't bother to adjust the entropy count, though, because we're not ambitious to provide *information-theoretic* randomness.''}, it may be prudent to assert on rand:ready() at application startup. \subsubsection[\fn{rand.uniform}]{\fn{rand.uniform([$n$])}} Returns a cryptographically strong uniform random integer in the interval $[0, n-1]$. If $n$ is omitted, the interval is $[0, 2^{64}-1]$. The routine operates internally on 64-bit unsigned integers.\footnote{Actually, \texttt{unsigned long long}.} Because neither Lua 5.1 nor 5.2 support 64-bit integers, it's probably best to generate numbers that fit the integral range of your Lua implementation. Lua 5.3 supports a new arithmetic type for 64-bit signed integers in two's-complement representation. This new arithmetic type will be used for argument and return values when available. \end{Module} \begin{Module}{openssl.des} Binds OpenSSL's DES interfaces. These bindings are incomplete. No modern protocol would ever need to use these directly. However, legacy protocols like Windows LAN Manager authentication require some of these low-level interfaces. \subsubsection[\fn{des.string\_to\_key}]{\fn{des.string\_to\_key($password$)}} Converts an arbitrary length string, $password$, to a DES key using DES\_string\_to\_key. Returns an 8-byte string. Note that OpenSSL's DES\_string\_to\_key is not compatible with Windows LAN Manager hashing scheme. Use \fn{des.set\_odd\_parity} instead. See examples/lm.hash. \subsubsection[\fn{des.set\_odd\_parity}]{\fn{des.set\_odd\_parity($key$)}} Applies DES\_set\_odd\_parity to the string $key$. Only the first 8 bytes of $key$ are processed. Returns an 8-byte string. \end{Module} \begin{Module}{openssl.kdf} Binds OpenSSL's Key Derivation Function interfaces. \subsubsection[\fn{kdf.derive}]{\fn{kdf.derive($options$)}} Derive a key given the table of $options$, different KDF types require different options. Accepted options are: \begin{ctabular}{ c | c | p{5in}} field & type & description\\\hline .type & string & key derivation algorithm---``PBKDF2'', ``id-scrypt'', ``hkdf'', ``TLS-PRF1'' or other depending on your version of OpenSSL \\ .outlen & number & the desired output size \\ .pass & string & password \\ .salt & string & salt \\ .iter & number & iteration count \\ .md & string & digest to use \\ .key & string & key \\ .maxmem\_bytes & number & amount of RAM key derivation may maximally use (in bytes) \\ .secret & string & TLS1-PRF secret \\ .seed & string & TLS1-PRF seed \\ .hkdf\_mode & string & the HKDF mode to use, one of ``extract\_and\_expand'', ``extract\_only'' or ``expand\_only'' \\ .info & string & HKDF info value \\ .N & number & scrypt ``N'' parameter to use \\ .r & number & scrypt ``r'' parameter to use \\ .p & number & scrypt ``p'' parameter to use \end{ctabular} \end{Module} \chapter{Examples} These examples and others are made available under examples/ in the source tree. \section{Self-Signed Certificate} \begin{example}{lua} -- -- Example self-signed X.509 certificate generation. -- -- Skips intermediate CSR object, which is just an antiquated way for -- specifying subject DN and public key to CAs. See API documentation for -- CSR generation. -- local pkey = require"openssl.pkey" local x509 = require"openssl.x509" local name = require"openssl.x509.name" local altname = require"openssl.x509.altname" -- generate our public/private key pair local key = pkey.new{ type = "EC", curve = "prime192v1" } -- our Subject and Issuer DN (self-signed, so same) local dn = name.new() dn:add("C", "US") dn:add("ST", "California") dn:add("L", "San Francisco") dn:add("O", "Acme, Inc") dn:add("CN", "acme.inc") -- our Alternative Names local alt = altname.new() alt:add("DNS", "acme.inc") alt:add("DNS", "*.acme.inc") -- build our certificate local crt = x509.new() crt:setVersion(3) crt:setSerial(42) crt:setSubject(dn) crt:setIssuer(crt:getSubject()) crt:setSubjectAlt(alt) local issued, expires = crt:getLifetime() crt:setLifetime(issued, expires + 60) -- good for 60 seconds crt:setBasicConstraints{ CA = true, pathLen = 2 } crt:setBasicConstraintsCritical(true) crt:setPublicKey(key) crt:sign(key) -- pretty-print using openssl command-line utility. io.popen("openssl x509 -text -noout", "w"):write(tostring(crt)) \end{example} \clearpage \section{Signature Generation \& Verification} \begin{example}{lua} -- -- Example public-key signature verification. -- local pkey = require"openssl.pkey" local digest = require"openssl.digest" -- generate a public/private key pair local key = pkey.new{ type = "EC", curve = "prime192v1" } -- digest our message using an appropriate digest local data = digest.new "sha1" data:update(... or "hello world") -- generate a signature for our data local sig = key:sign(data) -- to prove verification works, instantiate a new object holding just -- the public key local pub = pkey.new(key:toPEM"public") -- a utility routine to output our signature local function tohex(b) local x = "" for i = 1, #b do x = x .. string.format("%.2x", string.byte(b, i)) end return x end print("okay", pub:verify(sig, data)) print("type", pub:type()) print("sig", tohex(sig)) \end{example} \appendix \printindex \end{document} luaossl-rel-20220711/examples/000077500000000000000000000000001426273367600160525ustar00rootroot00000000000000luaossl-rel-20220711/examples/lm.hash000077500000000000000000000033201426273367600173300ustar00rootroot00000000000000#!/bin/sh _=[[ : ${LUA:=$(command -v lua-5.2)} : ${LUA:=$(command -v lua5.2)} : ${LUA:=$(command -v lua-52)} : ${LUA:=$(command -v lua52)} : ${LUA:=$(command -v luajit)} : ${LUA:=$(command -v lua)} exec ${LUA} "$0" "$@" ]] local des = require"openssl.des" local cipher = require"openssl.cipher" local bit32 = require"bit32" local function lm_encrypt(key) return cipher.new"DES-ECB":encrypt(key, nil, false):final"KGS!@#$%" end -- lm_encrypt local lshift = bit32.lshift local band = bit32.band local rshift = bit32.rshift local bor = bit32.bor local function lm_string_to_key(s) local s0, s1, s2, s3, s4, s5, s6 = string.byte(s, 1, 7) local k0, k1, k2, k3, k4, k5, k6, k7 s0 = s0 or 0 s1 = s1 or 0 s2 = s2 or 0 s3 = s3 or 0 s4 = s4 or 0 s5 = s5 or 0 s6 = s6 or 0 k0 = s0 k1 = bor(band(lshift(s0, 7), 255), rshift(s1, 1)) k2 = bor(band(lshift(s1, 6), 255), rshift(s2, 2)) k3 = bor(band(lshift(s2, 5), 255), rshift(s3, 3)) k4 = bor(band(lshift(s3, 4), 255), rshift(s4, 4)) k5 = bor(band(lshift(s4, 3), 255), rshift(s5, 5)) k6 = bor(band(lshift(s5, 2), 255), rshift(s6, 6)) k7 = band(lshift(s6, 1), 255) return des.set_odd_parity(string.char(k0, k1, k2, k3, k4, k5, k6, k7)) end -- lm_string_to_key local function lm_hash(pass) pass = string.upper(pass) if #pass < 14 then pass = pass .. string.rep(string.char(0), 14 - #pass) end local key1 = lm_string_to_key(string.sub(pass, 1, 7)) local key2 = lm_string_to_key(string.sub(pass, 8, 14)) return lm_encrypt(key1) .. lm_encrypt(key2) end -- lm_hash local function tohex(s) return (string.gsub(s, ".", function (c) return string.format("%.2x", string.byte(c)) end)) end -- tohex local pass = ... or "passphrase" print(pass, tohex(lm_hash(pass))) luaossl-rel-20220711/examples/pkey.info000066400000000000000000000002221426273367600176730ustar00rootroot00000000000000local pkey = require"openssl.pkey" local rsa = pkey.new{ type = "RSA", bits = 512 } for k, v in pairs(rsa:getParameters()) do print(k, v) end luaossl-rel-20220711/examples/self.x509000077500000000000000000000030311426273367600174320ustar00rootroot00000000000000#!/usr/local/lua52/bin/lua -- -- Example self-signed X.509 certificate generation. -- -- Skips intermediate CSR object, which is just an antiquated way for -- specifying subject DN and public key to CAs. See API documentation for -- CSR generation. -- local keytype = ... local openssl = require"openssl" local pkey = require"openssl.pkey" local x509 = require"openssl.x509" local name = require"openssl.x509.name" local altname = require"openssl.x509.altname" -- generate our public/private key pair local function genkey(type) type = string.upper(type or (not openssl.NO_EC and "EC") or "RSA") if type == "RSA" then return pkey.new{ type = "RSA", bits = 1024 } elseif type == "DSA" then return pkey.new{ type = "DSA", bits = 1024 } else return pkey.new{ type = "EC", curve = "prime192v1" } end end local key = genkey(keytype) -- our Subject and Issuer DN (self-signed, so same) local dn = name.new() dn:add("C", "US") dn:add("ST", "California") dn:add("L", "San Francisco") dn:add("O", "Acme, Inc") dn:add("CN", "acme.inc") -- our Alternative Names local alt = altname.new() alt:add("DNS", "acme.inc") alt:add("DNS", "*.acme.inc") -- build our certificate local crt = x509.new() crt:setVersion(3) crt:setSerial(47) crt:setSubject(dn) crt:setIssuer(crt:getSubject()) crt:setSubjectAlt(alt) local issued, expires = crt:getLifetime() crt:setLifetime(issued, expires + 60) -- good for 60 seconds crt:setBasicConstraints{ CA = true, pathLen = 2 } crt:setBasicConstraintsCritical(true) crt:setPublicKey(key) crt:sign(key) print(crt:text()) luaossl-rel-20220711/examples/vrfy.sig000077500000000000000000000023561426273367600175550ustar00rootroot00000000000000#!/usr/local/lua52/bin/lua -- -- Example public-key signature verification. -- local keytype, hash = ... local openssl = require"openssl" local pkey = require"openssl.pkey" local digest = require"openssl.digest" -- generate a public/private key pair local function genkey(type) type = string.upper(type or (not openssl.NO_EC and "EC") or "RSA") if type == "RSA" then return pkey.new{ type = "RSA", bits = 1024 } elseif type == "DSA" then return pkey.new{ type = "DSA", bits = 1024 } else return pkey.new{ type = "EC", curve = "prime192v1" } end end local key = genkey(keytype) if hash == nil then hash = key:getDefaultDigestName() end -- digest our message using an appropriate digest local data = digest.new(hash) data:update(... or "hello world") -- generate a signature for our data local sig = key:sign(data) -- to prove verification works, instantiate a new object holding just -- the public key local pub = pkey.new(key:toPEM"public") -- a utility routine to output our signature local function tohex(b) local x = "" for i = 1, #b do x = x .. string.format("%.2x", string.byte(b, i)) end return x end print("verified", pub:verify(sig, data)) print("key-type", pub:type()) print("hash-type", hash) print("signature", tohex(sig)) luaossl-rel-20220711/mk/000077500000000000000000000000001426273367600146435ustar00rootroot00000000000000luaossl-rel-20220711/mk/changelog000077500000000000000000000025071426273367600165240ustar00rootroot00000000000000#!/bin/sh set -e # strict errors set -u # don't expand unbound variables set -f # disable pathname expansion set -C # noclobber \unalias -a # no command surprises export LC_ALL=C # no locale headaches unset IFS # no field splitting surprises RELPATH=${0%/*} : RELPATH=${RELPATH:-.} CHANGELOG=${RELPATH}/../debian/changelog ROOTDIR=${RELPATH}/.. GIT="$(command -v git)" changelog() { if [ ! -f ${CHANGELOG} ]; then printf -- "${CHANGELOG}: No such file\n" >&2 exit 1 fi cat ${CHANGELOG} } usage() { cat <<-EOF usage: ${0##*/} [-h] version|author|commit -h print this usage message version most recent package version number author author of most recent log message commit Git hash of most recent commit Report bugs to EOF } while getopts h OPT; do case "${OPT}" in h) usage exit 0 ;; *) usage >&2 exit 1 ;; esac done shift $(($OPTIND - 1)) case "${1:-version}" in version) changelog | sed -ne ' s/.*(\([1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\).*).*/\1/ t Found d :Found p q ' ;; author) changelog | sed -ne ' s/.*<\([^>]*@[^>]*\)>.*/\1/ t Found d :Found p q ' ;; commit) test -n "${GIT}" -a -d ${ROOTDIR}/.git || exit 1 cd ${ROOTDIR} ${GIT} show --pretty='%H' HEAD 2>/dev/null | sed -n '1p' ;; *) usage >&2 exit 1 ;; esac exit 0 luaossl-rel-20220711/mk/luapath000077500000000000000000001025641426273367600162370ustar00rootroot00000000000000#!/bin/sh # # This script is used to derive compiler flags and filesystem paths # necessary to utilize Lua, LuaJIT, and particular versions thereof in both # simple and mixed installation environments. # # For usage help information use the -h switch. # # This script attempts to adhere strictly to POSIX shell specifications. The # known non-POSIX features used are the path of the shell at the very first # line of this script, the default compiler command name of `cc' instead of # `c99', and the use of /dev/urandom for generating a random sandbox # directory suffix. All of these can be override. For any other issues # please contact the author. # # WARNING: When searching for a Lua interpreter this script may execute # various utilities in an attempt to deduce their fitness and release # version. By default this script will search for and execute utilities # using the glob patterns luac* and lua*. But this script CANNOT GUARANTEE # that executing such utilities, or any other utilities, either wittingly or # unwittingly, will not result in your COMPUTER EXPLODING. You have been # warned. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Changelog: # # * 2013-08-02 - Published. Derived from an earlier script, lua.path, # written for the cqueues project. # # * 2013-08-05 - Redirect stdin from /dev/null when probing so we don't # freeze if a utility tries to read from stdin. # # chdir to a read-only directory by default to try to prevent creation # of temporary files. These features address the issues of LuaTeX # reading from stdin and creating a luatex.out file in the current # working directory. By default a directory with a random suffix # generated from /dev/urandom is placed in TMPDIR and removed on exit. # # If CPPFLAGS is empty and no -I options directly specified then set # INCDIRS to "/usr/include:/usr/local/include". # # * 2013-08-07 - Add pkg-config support and refactor header probing to delay # recursive searching. # # * 2013-09-09 - NetBSD's sh gets upset over the noclobber option and # redirection to /dev/null, so use append operator. And check $# # before iterating over a null parameter set with `do X; ... done` # when `set -u` is enabled--it complains about $@ being unset. # # * 2013-10-22 - Initial ldflags detection. # # * 2014-01-26 - Migrate CC vendor detection from external script. # # * 2014-09-29 - Add ldir and cdir modes which print install path by parsing # package.path and package.cpath. # # * 2014-12-18 - Add -e GLOB option. # # Deprecate ldir and cdir modes. # # Add package.path and package.cpath to replace ldir and dir modes. # Optional arguments to the new modes are preferred install paths, # rather than globs for finding the lua utility path (use the new -e # option, instead). # # * 2014-12-19 - Fix pkg-config version matching. The --modversion of # the lua package might be stale. For example, it's 5.2.0 on Ubuntu # 14.04 even though the Lua release is 5.2.3. # # Use the interpreter path as a reference point when searching for # headers. $(dirname ${LUA_PATH})/../include is a very likely location # as bindir and includedir have the same prefix in most installations. # # * 2015-01-15 - Quote more command names and arguments. Still need to # handle space characters in code that employs command substitution. I # think we could handle all whitespace characters, including newlines, # by using a control character in IFS and using --exec printf "%s\1" {} # rather than -print with find(1). # # * 2015-01-19 - Add fix for LuaJIT's default package.cpath, which tends to # hardcode /usr/local/lib/lua/5.1, ordered before the LuaJIT # installation prefix. # # * 2015-07-14 - Add recursive glob function implemented in shell code # and use instead of find(1). # # * 2016-03-18 - Fix bug in tryluac where a continue statement was used # instead of return 0. # # * 2016-03-25 - Support ${CC} values with trailing flags, which invoke # the compiler through env(1), or which otherwise are intended to # expand as multiple words. # # OpenBSD 5.8 sh does not suppress strict errors within an eval # invoked from an if condition compound-list. Workaround by changing # trylua to return 0 on matching failure, like tryluainclude and # tryluac do. # # Undeprecate ldir and cdir. The names are more intuitive and # convenient as evidenced by the fact that I keep using them instead # of package.path and package.cpath. Try to maintain backwards # compatibility by using a simple heuristic to differentiate lua # interpreter glob patterns from preferred install directory # string.match expressions. # # * 2016-10-10 - Fix issue with passing empty CPPFLAGS to ${CC}. /usr/bin/cc # in NetBSD 7.0.1 does not tolerate an empty string argument. This # exposed a bug in NetBSD's and FreeBSD's /bin/sh, triggered by how we # pass CPPFLAGS (see evalmacro and runcc routines, below). # # Some Ash variants (confirmed /bin/sh in NetBSD 7.0.1 and FreeBSD # 10.1) will expand unquoted ${UNSET-} and ${UNSET:-} as an empty # string rather than eliding it during argument processing. That is, # # nargs() { printf "%d\n" "$#"; } # nargs ${UNSET} 2 3 # nargs ${UNSET-} 2 3 # # prints "2" and "3", whereas every other shell tested prints "2" and # "2" (confirmed dash in Ubuntu Xenial; bash 4.3 in Ubuntu Xenial; # pdksh in FreeBSD 10.1, NetBSD 7.0, OS X 10.1, OpenBSD 6.0; ksh93 in # Solaris 11.3 and AIX 7.1; ksh88 in AIX 7.1). # # A workaround in set -u mode (where unbound variable expansion aborts # execution) is to substitute a known empty value. E.g. # # EMPTY= # nargs ${UNSET-$EMPTY} # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Copyright (C) 2012-2016 William Ahern # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # set -e # strict errors set -u # don't expand unbound variables set -f # disable pathname expansion set -C # noclobber \unalias -a # no command surprises export LC_ALL=C # no locale headaches unset IFS # no field splitting surprises : ${TMPDIR:=/tmp} # sane TMPDIR : ${CC:=cc} unset LUA_PATH || true # interferes search for module install directory unset LUA_CPATH || true MYVERSION=20161010 MYVENDOR="william@25thandClement.com" EMPTY= # empty string for parameter expansion workaround for Ash bug DEVRANDOM=/dev/urandom SANDBOX="${TMPDIR}/${0##*/}-" CPPDIRS= # -I directories from CPPFLAGS INCDIRS= LDDIRS= # -L directories from LDFLAGS LIBDIRS= BINDIRS= RECURSE=no MAXDEPTH=5 # maximum recursion depth SHORTEST= # continue searching until shortest pathname found PKGCONFIG= # path to pkg-config, found by `command -v` when -k option invoked GLOB= # -e GLOB expression for lua, luac, ldir, and cdir GLOB_LUA="lua:lua[5-9]*:lua-[5-9]*:luajit*" GLOB_LUAC="luac:luac[5-9]*:luac-[5-9]*" API_MIN=500 API_MAX=999 API_VER= API_DIR= JIT_REQ= JIT_MIN=20000 JIT_MAX=99999 JIT_VER= JIT_DIR= LIBLUA_VER= LIBLUA_DIR= LIBLUA_LIB= LIBJIT_VER= LIBJIT_DIR= LIBJIT_LIB= LUAC_PATH= LUAC_VER= LUA_PATH= LUA_VER= # # warn FORMAT [...] # # Print message to original stderr. # exec 9>&2 warn() { printf "%s: %.0s${1}\n" "${0##*/}" "$@" >&9 } # # panic FORMAT [...] # # Print message to original stderr, then exit with failure. # panic() { warn "$@" exit 1 } # # parse CPPFLAGS -I or LDFLAGS -L directories # xdirs() { OPTC="${1:-I}" DIRS= set -- ${2:-} while [ $# -gt 0 ]; do case "${1}" in -${OPTC}) shift if [ -n "${1:-}" ]; then DIRS="${DIRS}${DIRS:+:}${1}" fi ;; -${OPTC}*) if [ "${1}" != "-${OPTC}" ]; then DIRS="${DIRS}${DIRS:+:}${1#-${OPTC}}" fi ;; esac shift done printf -- "${DIRS}" } idirs() { xdirs "I" "${1:-}" } ldirs() { xdirs "L" "${1:-}" } # count ":"-delimited substrings count() { IFS=: set -- ${1:-} unset IFS printf "$#" } # append to ":"-delimited string variable append() { NAME=${1} eval VALUE="\${${NAME}}" shift IFS=: TMP="$*" IFS="\n" read -r "${NAME}" <<-EOF ${VALUE:-}${VALUE:+:}${TMP} EOF unset IFS } # # glob PATTERN [MAXDEPTH] [EXEC-COMMAND] [INTERNAL:GLOB-COUNT] # glob() { glob_N="${4:-0}" IFS= set +f for F in ${1}; do [ -e "${F}" ] || continue if eval "${3:-printf '%s\\n'} \"\${F}\""; then glob_N=$((${glob_N} + 1)) fi done set -f unset IFS if [ "${2-0}" -gt 0 ]; then glob "${1%/*}/*/${1##*/}" "$((${2} - 1))" "${3:-}" "${glob_N}" || : fi [ "${glob_N}" -gt 0 ] } # glob # # runcc [...] # # Wrapper for invoking ${CC}. Some build system include flags in ${CC}, # invoke the compiler through env(1), or employ other hacks. # # TODO: Optionally handle unescaping of words in a manner similar to how # ${CC} would be evaluated from a make rule--typically by being passed # through system(3). # runcc() { (unset IFS; exec ${CC} "$@") } # # evalmacro PATH MACRO [REGEX] [SUBST] # # PATH Header identifier--#include # MACRO Macro identifier # REGEX Optional regex pattern to match macro evaluation result # SUBST Optional replacement expression # evalmacro() { printf "#include <$1>\n[===[$2]===]\n" \ | runcc ${CPPFLAGS:-${EMPTY}} -E - 2>>/dev/null \ | sed -ne " s/^.*\\[===\\[ *\\(${3:-.*}\\) *\\]===\\].*$/${4:-\\1}/ t Found d :Found p q " } # # testsym PATH NAME # # Test whether global symbol NAME exists in object file at PATH. Exits with # 0 (true) when found, non-0 (false) otherwise. # testsym() { # NOTE: No -P for OpenBSD nm(1), but the default output format is # close enough. Section types always have a leading and trailing # space. U section type means undefined. On AIX [VWZ] are weak # global symbols. Solaris and OS X have additional symbol types # beyond the canonical POSIX/BSD types, all of which are uppercase # and within [A-T]. (nm -Pg ${1} 2>>/dev/null || nm -g 2>>/dev/null) \ | sed -ne '/ [A-T] /p' \ | grep -q "${2}" } tryluainclude() { V="$(evalmacro "${1}" LUA_VERSION_NUM '[0123456789][0123456789]*')" : ${V:=0} if [ "${1%/*}" != "${1}" ]; then D="${1%/*}" # cleanup after Solaris directory prune trick if [ "${D##*/./}" != "${D}" ]; then D="${D%%/./*}/${D##*/./}" else D="${D%/.}" fi else D= fi [ "$V" -gt 0 -a "$V" -ge "${API_VER:-0}" ] || return 0 [ "$V" -gt "${API_VER:-0}" -o "${#D}" -lt "${#API_DIR}" -o \( "${JIT_REQ}" = "yes" -a "${JIT_VER:-0}" -lt "${JIT_MAX}" \) ] || return 0 [ "$V" -ge "${API_MIN}" -a "$V" -le "${API_MAX}" ] || return 0 if [ -n "${JIT_REQ}" ]; then J="$(evalmacro "${1%%lua.h}luajit.h" LUAJIT_VERSION_NUM '[0123456789][0123456789]*')" : ${J:=0} if [ "${JIT_REQ}" = "skip" ]; then [ "${J}" -eq 0 ] || return 0 elif [ "${JIT_REQ}" = "yes" ]; then [ "$J" -ge "${JIT_VER:-0}" ] || return 0 [ "$J" -gt "${JIT_VER:-0}" -o "${#D}" -lt "${#JIT_DIR}" ] || return 0 [ "$J" -ge ${JIT_MIN} ] || return 0 [ "$J" -le "${JIT_MAX}" ] || return 0 JIT_VER="$J" JIT_DIR="$D" fi fi API_VER="$V" API_DIR="$D" } # # foundversion # # true if found the best (maximum) possible version, false otherwise # foundversion() { if [ "${API_VER:-0}" -lt "${API_MAX}" ]; then return 1 fi if [ "${JIT_REQ}" = "yes" -a "${JIT_VER:-0}" -lt "${JIT_MAX}" ]; then return 1 fi if [ "${SHORTEST}" = "yes" ]; then return 1 fi return 0 } # # luapc # # wrapper around `pkg-config ... LIB`, where LIB is derived by # searching for all libraries with "lua" in the name that have a # --modversion equal to the release version printed by ${LUA_PATH} -v. # LUAPC_LIB= luapc() { [ -n "${LUA_PATH}" ] || return 0 [ -n "${PKGCONFIG}" ] || return 0 # find pkg-config library name if [ -z "${LUAPC_LIB}" ]; then V="$("${LUA_PATH}" -v &1 | head -n1 | sed -ne 's/^Lua[^ ]* \([0123456789][0123456789]*\(\.[0123456789][0123456789]*\)*\).*/\1/p')" [ -n "${V}" ] || return 0 V_N=$(mmp2num "${V}") for LIB in $("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p'); do M="$("${PKGCONFIG}" --modversion ${LIB} || true)" # break immediately on exact match if [ "${V}" = "${M}" ]; then LUAPC_LIB="${LIB}" break fi # # NOTE: On Ubuntu 14.04 pkg-config --modversion # lua5.2 prints 5.2.0 even though the release # version is 5.2.3 (what lua5.2 -v prints). # # If the major.minor components match, then # tentatively use that package name. # M_N=$(mmp2num "${M}" 0 0 0) if [ "$((${V_N} / 100))" -eq "$((${M_N} / 100))" ]; then LUAPC_LIB="${LIB}" fi done [ -n "${LUAPC_LIB}" ] || return 0 fi ${PKGCONFIG} "$@" "${LUAPC_LIB}" >/dev/null || true } # # findinstalldir package.path|package.cpath [preferred-path ...] # findinstalldir() { V_DIR=$((${LUA_VER} / 100 % 100)).$((${LUA_VER} % 100)) if [ "${1}" = "package.cpath" -o "${1}" = "cdir" ]; then ARRAY="package.cpath" DIR="$(luapc --variable INSTALL_CMOD)" [ -n "${DIR}" ] && set -- "$@" "${DIR}" DIR="$(luapc --variable INSTALL_LIB)" [ -n "${DIR}" ] && set -- "$@" "${DIR}/lua/${V_DIR}" DIR="$(luapc --variable libdir)" [ -n "${DIR}" ] && set -- "$@" "${DIR}/lua/${V_DIR}" DIR="$(luapc --variable prefix)" [ -n "${DIR}" ] && set -- "$@" "${DIR}/lib/lua/${V_DIR}" # LuaJIT installations tend to include # /usr/local/lib/lua/5.1 as one of the first paths, ordered # before the LuaJIT installation prefix, and regardless of # whether there exists a /usr/local/lib/lua/5.1. set -- "$@" "${LUA_PATH}/../../lib/lua/${V_DIR}" set -- "$@" "${LUA_PATH}/../../lib/*/lua/${V_DIR}" # e.g. lib/x86_64-linux-gnu else ARRAY="package.path" DIR="$(luapc --variable INSTALL_LMOD)" [ -n "${DIR}" ] && set -- "$@" "${DIR}" DIR="$(luapc --variable prefix)" [ -n "${DIR}" ] && set -- "$@" "${DIR}/share/lua/${V_DIR}" # See above LuaJIT note. Although the built-in package.path # usually orders the LuaJIT installation prefix first. set -- "$@" "${LUA_PATH}/../../share/lua/${V_DIR}" fi shift if [ $# -eq 0 ]; then set -- "/nonexistent" # cannot expand empty $@ on some implementations fi "${LUA_PATH}" - "$@" <<-EOF -- -- actual pkg-config variable on Ubuntu 14.04 -- -- /usr//share/lua/5.1 -- local function fixpath(path) local stack = { path:match"^/" and "" or "." } for ent in path:gmatch"([^/]+)" do if ent == ".." and #stack > 1 then stack[#stack] = nil elseif ent ~= "." then stack[#stack + 1] = ent end end return table.concat(stack, "/") end local function topattern(path) if string.match(path, "*") then path = string.gsub(path, "%%", "%%") return string.gsub(path, "*", "[^/]+") end end local dirs = { } for dir in ${ARRAY}:gmatch"([^;?]+)/" do dir = fixpath(dir) if dir ~= "." then dirs[#dirs + 1] = dir end end for _, arg in ipairs{ ... } do arg = fixpath(arg) local pat = topattern(arg) for _, dir in ipairs(dirs) do if arg == dir then print(dir) os.exit(0) elseif pat and string.match(dir, pat) then print(dir) os.exit(0) end end end if dirs[1] then print(dirs[1]) os.exit(0) else os.exit(1) end EOF } # # findversion # findversion() { tryluainclude "lua.h" if foundversion; then return 0 fi # iterate through CPPFLAGS to probe different precedence if [ "${API_VER:-0}" -lt "${API_MAX}" ]; then IFS=: set -- ${CPPDIRS} unset IFS if [ $# -gt 0 ]; then for D; do tryluainclude "${D}/lua.h" if foundversion; then return 0 fi done fi fi if [ -n "${PKGCONFIG}" ]; then PKGFLAGS="$("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p' | xargs -- ${PKGCONFIG} --cflags 2>>/dev/null | cat)" PKGDIRS="$(idirs "${PKGFLAGS}")" IFS=: set -- ${PKGDIRS} unset IFS if [ $# -gt 0 ]; then for D; do tryluainclude "${D}/lua.h" if foundversion; then return 0 fi done fi fi IFS=: set -- ${INCDIRS} unset IFS if [ $# -gt 0 ]; then for D; do tryluainclude "${D}/lua.h" if foundversion; then return 0 fi done fi if [ "${RECURSE}" != "yes" ]; then [ "${API_VER:-0}" -gt 0 ] return $? fi # recurse into CPPDIRS IFS=: set -- ${CPPDIRS} unset IFS if [ $# -gt 0 ]; then for D; do glob "${D}/lua.h" "${MAXDEPTH}" tryluainclude || : if foundversion; then return 0 fi done fi # recurse into INCDIRS IFS=: set -- ${INCDIRS} unset IFS if [ $# -gt 0 ]; then for D; do glob "${D}/lua.h" "${MAXDEPTH}" tryluainclude || : if foundversion; then return 0 fi done fi # if we can find the lua interpreter, use it as a reference for # header locations. if findlua; then D="${LUA_PATH%/*}" D="${D%/*}/include" if [ -d "${D}" ]; then glob "${D}/lua.h" "${MAXDEPTH}" tryluainclude || : if foundversion; then return 0 fi fi fi [ "${API_VER:-0}" -gt 0 ] } # # Unlike API version checking, this is less likely to be accurately forward # compatible. # trylib() { testsym "${1}" "lua_newstate" || return 1 # exclude C++ [ "${1#*++}" = "${1}" ] || return 1 V=0 J=0 D= F="${1##*/}" L= if [ "${1%/*}" != "${1}" ]; then D="${1%/*}" # cleanup after Solaris directory prune trick if [ "${D##*/./}" != "${D}" ]; then D="${D%%/./*}/${D##*/./}" else D="${D%/.}" fi fi L="${F#lib}" L="${L%.so}" L="${L%.a}" L="${L%.dylib}" # FIXME: need more versioning tests if testsym "${1}" "lua_getfenv"; then V=501 elif testsym "${1}" "lua_yieldk"; then if testsym "${1}" "lua_getctx"; then V=502 else V=503 fi else return 1 fi [ "$V" -gt 0 -a "$V" -ge "${LIBLUA_VER:-0}" ] || return 1 [ "$V" -gt "${LIBLUA_VER:-0}" -o "${#D}" -lt "${#LIBLUA_DIR}" -o \( "${JIT_REQ}" = "yes" -a "${LIBJIT_VER:-0}" -lt "${JIT_MAX}" \) ] || return 1 [ "$V" -ge "${API_MIN}" -a "$V" -le "${API_MAX}" ] || return 1 if [ -n "${JIT_REQ}" ]; then # FIXME: need more versioning tests if testsym "${1}" "luaopen_jit"; then J=20000 fi if [ "${JIT_REQ}" = "skip" ]; then [ "${J}" -eq 0 ] || return 1 elif [ "${JIT_REQ}" = "yes" ]; then [ "$J" -ge "${LIBJIT_VER:-0}" ] || return 1 [ "$J" -gt "${LIBJIT_VER:-0}" -o "${#D}" -lt "${#LIBJIT_DIR}" ] || return 1 [ "$J" -ge ${JIT_MIN} ] || return 1 [ "$J" -le "${JIT_MAX}" ] || return 1 LIBJIT_VER="$J" LIBJIT_DIR="$D" LIBJIT_LIB="$L" fi fi LIBLUA_VER="$V" LIBLUA_DIR="$D" LIBLUA_LIB="$L" } # # foundlib # # true if found the best (maximum) possible version, false otherwise # foundlib() { if [ "${LIBLUA_VER:-0}" -lt "${API_MAX}" ]; then return 1 fi if [ "${JIT_REQ}" = "yes" -a "${LIBJIT_VER:-0}" -lt "${JIT_MAX}" ]; then return 1 fi if [ "${SHORTEST}" = "yes" ]; then return 1 fi return 0 } findlib() { if [ -n "${PKGCONFIG}" ]; then PKGFLAGS="$("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p' | xargs -- ${PKGCONFIG} --libs 2>>/dev/null | cat)" PKGDIRS="$(ldirs "${PKGFLAGS}")" PKGDIRS="${PKGDIRS}${PKGDIRS:+:}/lib:/usr/lib:/usr/local/lib" NUMDIRS="$(count "${PKGDIRS}")" PKGLIBS="$(xdirs "l" "${PKGFLAGS}")" NUMLIBS="$(count "${PKGLIBS}")" ALLDIRS="${PKGDIRS}${PKGLIBS:+:}${PKGLIBS}" IFS=: set -- ${ALLDIRS} unset IFS I=1 while [ $I -le ${NUMDIRS} ]; do K=$((1 + ${NUMDIRS})) while [ $K -le $# ]; do findlib_L=$(eval "printf \${$I}") findlib_l=$(eval "printf \${$K}") #printf -- "I=$I K=$K $findlib_L/lib$findlib_l*.*\n" glob "${findlib_L}/lib${findlib_l}*.*" 0 trylib || : if foundlib; then return 0; fi glob "${findlib_L}/lib${findlib_l}*.*" ${MAXDEPTH} trylib || : if foundlib; then return 0; fi K=$(($K + 1)) done I=$(($I + 1)) done fi ALLDIRS="${LDDIRS}${LDDIRS:+:}${LIBDIRS}" IFS=: set -- ${ALLDIRS} unset IFS for findlib_D; do glob "${findlib_D}/liblua*.*" "${MAXDEPTH}" trylib || : if foundlib; then return 0 fi done # if we can find the lua interpreter, use it as a reference for # library locations. if findlua; then findlib_D="${LUA_PATH%/*}" findlib_D="${findlib_D%/*}/lib" if [ -d "${findlib_D}" ]; then glob "${findlib_D}/liblua*.*" "${MAXDEPTH}" trylib || : if foundlib; then return 0 fi fi fi } # check setuid and setgid mode safeperm() { [ -f "$1" -a ! -u "$1" -a ! -g "$1" ] } tryluac() { tryluac_F="${1}" [ -x "${tryluac_F}" ] && safeperm "${tryluac_F}" || return 0 tryluac_V="$("${tryluac_F}" -v &1 | head -n1 | sed -ne 's/^Lua \([0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" : ${tryluac_V:=0} tryluac_V="$((${tryluac_V%%.*} * 100 + ${tryluac_V##*.} % 100))" [ "${tryluac_V}" -gt 0 -a "${tryluac_V}" -ge "${LUAC_VER:-0}" ] || return 0 [ "${tryluac_V}" -gt "${LUAC_VER:-0}" -o "${#tryluac_F}" -lt "${#LUAC_PATH}" ] || return 0 [ "${tryluac_V}" -ge "${API_MIN}" -a "${tryluac_V}" -le "${API_MAX}" ] || return 0 printf "return true" 2>>/dev/null | ${tryluac_F} -p - >/dev/null 2>&1 || return 0 LUAC_PATH="${tryluac_F}" LUAC_VER="${tryluac_V}" } # # foundluac # # true if found the best (maximum) possible version, false otherwise # foundluac() { if [ "${LUAC_VER:-0}" -lt "${API_MAX}" ]; then return 1 fi if [ "${SHORTEST}" = "yes" ]; then return 1 fi return 0 } findluac() { if [ $# -eq 0 ]; then IFS=: set -- ${GLOB:-${GLOB_LUAC}} unset IFS fi for findluac_G; do IFS=: for findluac_D in ${PATH}; do unset IFS glob "${findluac_D}/${findluac_G}" 0 tryluac || : if foundluac; then return 0 fi done IFS=: for findluac_D in ${BINDIRS}; do unset IFS glob "${findluac_D}/${findluac_G}" "${MAXDEPTH}" tryluac || : if foundluac; then return 0 fi done unset IFS done [ "${LUAC_VER:-0}" -gt 0 ] && [ "${#LUAC_PATH}" -gt 0 ] } isinteger() { I="${1}" [ "${#I}" -gt 0 ] || return 1 while [ "${#I}" -gt 0 ]; do if [ "${I##[0123456789]}" = "${I}" ]; then return 1 fi I=${I##[0123456789]} done return 0 } checkints() { while [ $# -gt 0 ]; do if ! isinteger "${1}"; then warn "%s: not a number" "${1}" return 1 fi shift done } # Only major.minor for matching LUA_VERSION_NUM in lua.h. Also, _VERSION # only includes major.minor. lua2num() { M=0 m="${2:-0}" IFS=. set -- ${1} unset IFS M=${1:-${M}} m=${2:-${m}} checkints $M $m printf "$((${M} * 100 + ${m}))\n" } # All major.minor.patch for matching LUAJIT_VERSION_NUM in luajit.h. jit2num() { M=0 m="${2:-0}" p="${3:-0}" IFS=. set -- ${1} unset IFS M=${1:-${M}} m=${2:-${m}} p=${3:-${p}} checkints $M $m $p printf "$((${M} * 10000 + ${m} * 100 + ${p}))\n" } mmp2num() { M="${2:-0}" m="${3:-0}" p="${4:-0}" IFS=".+-_" set -- ${1} unset IFS if isinteger "${1:-}"; then M=${1} fi if isinteger "${2:-}"; then m=${2} fi if isinteger "${3:-}"; then p=${3} fi checkints $M $m $p printf "$((${M} * 10000 + ${m} * 100 + ${p}))\n" } trylua() { trylua_F="${1}" [ -x "${trylua_F}" ] && safeperm "${trylua_F}" || return 0 trylua_V="$("${trylua_F}" -e 'print(string.match(_VERSION, [[[%d.]+]]))' >/dev/null | head -n1 | sed -ne 's/^\([0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" : ${trylua_V:=0} trylua_V="$((${trylua_V%%.*} * 100 + ${trylua_V##*.} % 100))" [ "${trylua_V}" -gt 0 -a "${trylua_V}" -ge "${LUA_VER:-0}" ] || return 0 [ "${trylua_V}" -gt "${LUA_VER:-0}" -o "${#trylua_F}" -lt "${#LUA_PATH}" ] || return 0 [ "${trylua_V}" -ge "${API_MIN}" -a "${trylua_V}" -le "${API_MAX}" ] || return 0 if [ -n "${JIT_REQ}" ]; then J="$("${trylua_F}" -v &1 | head -n1 | sed -ne 's/^LuaJIT \([0123456789][0123456789]*\.[0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" J="$(jit2num ${J:-0})" if [ "${JIT_REQ}" = "skip" ]; then [ "${J}" -eq 0 ] || return 0 elif [ "${JIT_REQ}" = "yes" ]; then [ "${J}" -gt 0 ] || return 0 [ "${J}" -ge "${JIT_MIN}" ] || return 0 [ "${J}" -le "${JIT_MAX}" ] || return 0 fi fi LUA_PATH="${trylua_F}" LUA_VER="${trylua_V}" } # # foundlua # # true if found the best (maximum) possible version, false otherwise # foundlua() { if [ "${LUA_VER:-0}" -lt "${API_MAX}" ]; then return 1 fi if [ "${SHORTEST}" = "yes" ]; then return 1 fi return 0 } findlua() { if [ $# -eq 0 ]; then IFS=: set -- ${GLOB:-${GLOB_LUA}} unset IFS fi for findlua_G; do IFS=: for findlua_D in ${PATH}; do unset IFS glob "${findlua_D}/${findlua_G}" 0 trylua || : if foundlua; then return 0 fi done IFS=: for findlua_D in ${BINDIRS}; do unset IFS glob "${findlua_D}/${findlua_G}" "${MAXDEPTH}" trylua || : if foundlua; then return 0 fi done unset IFS done [ "${LUA_VER:-0}" -gt 0 ] && [ "${#LUA_PATH}" -gt 0 ] } ccname() { runcc -E - <<-EOF | awk '/sunpro/||/clang/||/gcc/||/other/{ print $1; exit; }' #if defined __SUNPRO_C sunpro #elif defined __clang__ clang #elif defined __GNUC__ gcc #else other #endif EOF } usage() { cat <<-EOF usage: ${0##*/} [-I:L:P:d:De:krm:xsv:j:JVh] cppflags|version|lua|luac|... -I PATH additional search directory for includes -L PATH additional search directory for libraries -P PATH additional search directory for binaries -d PATH use PATH as sandbox directory; a random 16 byte suffix is generated from /dev/urandom and the directory removed on exit unless a trailing "/" is present (default sandbox is \$TMPDIR/${0##*/}-XXXXXXXXXXXXXXXX) -D do not create a sandbox -e GLOB glob pattern for finding utilities (lua, luac, etc) -k query pkg-config if available -r recursively search directories -m MAXDEPTH limit recursion to MAXDEPTH -s find shortest pathname, otherwise print first best match -v VERSION require specific Lua version or range (e.g. "5.1" or "5.1-5.2") -j VERSION require specific LuaJIT version or range (e.g. "2.0.1"; empty ranges like "-" force any LuaJIT version) -J skip LuaJIT if encountered -V print this script's version information -h print this usage message cppflags print derived additional CPPFLAGS necessary version print derived Lua API version from cppflags discovery ldflags print derived additional LDFLAGS necessary (TODO) libs print derived additional LIBS necessary (TODO) libversion print derived Lua API version from ldflags/libs discovery luac print path to luac utility ($(printf "${GLOB_LUA}" | tr ':' ' ')) lua print path to lua interpreter ($(printf "${GLOB_LUAC}" | tr ':' ' ')) package.path print preferred module install path package.cpath print preferred C module install path ccname print CC name (e.g. sunpro, clang, gcc) evalmacro run internal macro evaluator for debugging testsym run internal library symbol reader for debugging This utility is used to derive compiler flags and filesystem paths necessary to utilize Lua, LuaJIT, and particular versions thereof. On success it prints the requested information and exits with 0, otherwise it fails with an exit status of 1. Note that cppflags may not print anything if no additional flags are required to compile against the requested API version. When searching, the highest Lua version is preferred. Searching stops once the highest version in the allowable range is found unless the -s flag is specified. LuaJIT is treated like any other Lua installation. If an explicit LuaJIT version or range is specified, then only LuaJIT installations will match. To exclude LuaJIT entirely use the -J switch. This utility processes the environment variables CC, CPPFLAGS, LDFLAGS, and PATH if present. If recursion is requested, then directories specified in CPPFLAGS, LDFLAGS, and PATH are also recursed. If the environment variable CPPFLAGS is empty and no -I options are specified directly, then /usr/include and /usr/local/include are used when probing for cppflags and API version. Report bugs to EOF } version() { cat <<-EOF luapath $MYVERSION vendor $MYVENDOR release $MYVERSION EOF } while getopts I:L:P:d:De:krm:xsv:j:JVh OPT; do case "${OPT}" in I) INCDIRS="${INCDIRS:-}${INCDIRS:+:}${OPTARG}" ;; L) LIBDIRS="${LIBDIRS:-}${LIBDIRS:+:}${OPTARG}" ;; P) BINDIRS="${BINDIRS:-}${BINDIRS:+:}${OPTARG}" ;; d) SANDBOX="${OPTARG}" ;; D) SANDBOX= ;; e) GLOB="${GLOB:-}${GLOB:+:}${OPTARG}" ;; k) PKGCONFIG="$(command -v pkg-config || true)" ;; r) RECURSE=yes ;; m) if [ "${#OPTARG}" -eq 0 -o -n "${OPTARG##[0123456789]}" ]; then panic "%s: invalid maxdepth" "${OPTARG}" fi MAXDEPTH="${OPTARG}" ;; x) # # NOTE: This option was # # -x do not cross device mounts when recursing # # but is currently unsupported as our built-in glob function # does not implement this functionality. Previously this # option caused -xdev to be added to invocations of find(1). ;; s) SHORTEST=yes ;; v) MIN=${OPTARG%%[,:-]*} MAX=${OPTARG##*[,:-]} API_MIN="$(lua2num ${MIN:-0} 0)" API_MAX="$(lua2num ${MAX:-99} 99)" if [ "${API_MIN}" -gt "${API_MAX}" ]; then panic "%s: invalid version range" "${OPTARG}" fi ;; j) MIN=${OPTARG%%[,:-]*} MAX=${OPTARG##*[,:-]} JIT_MIN="$(jit2num ${MIN:-0} 0 0)" JIT_MAX="$(jit2num ${MAX:-99} 99 99)" if [ "${JIT_MIN}" -gt "${JIT_MAX}" ]; then panic "%s: invalid version range" "${OPTARG}" fi JIT_REQ=yes ;; J) JIT_REQ=skip ;; V) version exit 0 ;; h) usage exit 0 ;; *) usage >&2 exit 1 ;; esac done shift $(($OPTIND - 1)) [ "${RECURSE}" = "yes" ] || MAXDEPTH=0 for U in "${CC}" grep od rm rmdir sed xargs; do ! command -v "${U}" >>/dev/null 2>&1 || continue # ${CC} might have trailing flags or invoke the compiler through env ! command -v "${U%% *}" >>/dev/null 2>&1 || continue warn "%s: command not found" "${U}" done if [ -n "${SANDBOX}" ]; then if [ "${SANDBOX}" = "${SANDBOX%/}" ]; then if [ ! -c "${DEVRANDOM}" ]; then # TODO: expand DEVRANDOM into set of different possibilities to check panic "%s: no character random device available" "${DEVRANDOM}" fi TMP="${SANDBOX}$(od -An -N8 -tx1 < ${DEVRANDOM} 2>>/dev/null | tr -d ' ')" if [ ${#TMP} -ne $((${#SANDBOX} + 16)) ]; then panic "%s: unable to generate random suffix" "${SANDBOX}" fi SANDBOX="${TMP}" trap "cd .. && rm -f -- ${SANDBOX}/* && rmdir -- ${SANDBOX}" EXIT fi if [ ! -d "${SANDBOX}" ]; then OMASK="$(umask)" umask 0777 mkdir -m0550 -- "${SANDBOX}" || exit 1 umask ${OMASK} fi cd ${SANDBOX} fi CPPDIRS="$(idirs "${CPPFLAGS:-}")" if [ -z "${CPPDIRS}" -a -z "${INCDIRS}" ]; then INCDIRS="/usr/include:/usr/local/include" fi LDDIRS="$(ldirs "${LDFLAGS:-}")" if [ -z "${LDDIRS}" -a -z "${LIBDIRS}" ]; then LIBDIRS="/lib:/usr/lib:/usr/local/lib" fi case "${1:-}" in cppflags) findversion || exit 1 [ "${API_VER:-0}" -gt 0 ] || exit 1 [ -z "${API_DIR:-}" ] || printf -- "-I${API_DIR}\n" ;; version) findversion || exit 1 printf "$(((${API_VER} / 100) % 100)).$((($API_VER) % 100))\n" ;; ldflags) findlib [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 if [ "${#LIBLUA_DIR}" -gt 0 ]; then printf -- "-L%s\n" "${LIBLUA_DIR}" fi ;; libs) findlib [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 printf -- "-l%s\n" "${LIBLUA_LIB}" ;; libv*) findlib [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 printf "$(((${LIBLUA_VER} / 100) % 100)).$((($LIBLUA_VER) % 100))\n" ;; luac) shift if [ $# -gt 0 ]; then append GLOB $* fi findluac || exit 1 printf -- "${LUAC_PATH}\n" ;; lua) shift if [ $# -gt 0 ]; then append GLOB $* fi findlua || exit 1 printf -- "${LUA_PATH}\n" ;; ldir|cdir) # # ldir and cdir were deprecated on 2014-12-18. On 2016-03-25 they # were revived because their names are more intuitive than # package.path and package.cpath. For now try to support the # semantics of both by assuming interpreter glob patterns only match # file names, while preferred install directory string.match # expressions have directory components. # if true; then MODE="${1}" # move command to end; rotates to ${1} after loop set -- "$@" "${1}" shift cdir_I=0 cdir_N="$(($# - 1))" while [ "${cdir_I}" -lt "${cdir_N}" ]; do if [ "${1#*/}" = "${1}" ]; then append GLOB "${1}" warn "%s: passing glob patterns to %s is deprecated" "${1}" "${MODE}" else set -- "$@" "${1}" fi shift cdir_I=$((${cdir_I} + 1)) done fi findlua || exit 1 findinstalldir "$@" || exit 1 ;; package.path|package.cpath) findlua || exit 1 findinstalldir "$@" || exit 1 ;; ccname) ccname ;; evalmacro) shift evalmacro $* ;; testsym) shift if testsym $*; then printf "found\n" exit 0 else printf "not found\n" exit 1 fi ;; *) if [ -n "${1:-}" ]; then warn "%s: unknown command" "${1}" else warn "no command specified" fi exit 1 ;; esac exit 0 luaossl-rel-20220711/mk/vendor.cc000077500000000000000000000003471426273367600164560ustar00rootroot00000000000000#!/bin/sh set -e : ${CC:=cc} ${CC} -E - <<-EOF | awk '/sunpro/||/clang/||/gcc/||/other/{ print $1; exit; }' #if defined __SUNPRO_C sunpro #elif defined __clang__ clang #elif defined __GNUC__ gcc #else other #endif EOF luaossl-rel-20220711/mk/vendor.os000077500000000000000000000000241426273367600165020ustar00rootroot00000000000000#!/bin/sh uname -s luaossl-rel-20220711/regress/000077500000000000000000000000001426273367600157065ustar00rootroot00000000000000luaossl-rel-20220711/regress/00-store-verify.lua000077500000000000000000000005031426273367600212650ustar00rootroot00000000000000#!/usr/bin/env lua require"regress".export".*" local st = store.new() local ca_key, ca_crt = genkey() st:add(ca_crt) local key, crt = genkey("RSA", ca_key, ca_crt) local ok, proof_or_reason = st:verify(crt) check(ok, "%s", proof_or_reason) --for _,crt in pairs(proof_or_reason) do -- print(crt:text()) --end say"OK" luaossl-rel-20220711/regress/104-interposition-discarded.lua000077500000000000000000000005521426273367600235460ustar00rootroot00000000000000#!/usr/bin/env lua require"regress".export".*" local ssl_context = require "openssl.ssl.context" local value = {} ssl_context.interpose("foo", value) check(ssl_context.new().foo == value, "interpose failed") require "openssl.ssl" -- Pick a module that doesn't get loaded by regress.lua check(ssl_context.new().foo == value, "loading a module reset methods") luaossl-rel-20220711/regress/115-test-aead.lua000066400000000000000000000016221426273367600205650ustar00rootroot00000000000000local regress = require "regress"; local openssl = require "openssl"; local cipher = require "openssl.cipher" -- Test AES-256-GCM local key = "abcdefghijklmnopabcdefghijklmnop" local iv = "123456123456" local message = "My secret message" function test_aead(params) local c = cipher.new(params.cipher):encrypt(key, iv) local encrypted = c:update(message) regress.check(encrypted) regress.check(c:final(), "fail final encrypt") local tag = assert(c:getTag(params.tag_length)) regress.check(tag and #tag == params.tag_length) -- Now for the decryption local d = cipher.new(params.cipher):decrypt(key, iv) d:setTag(tag); local decrypted = d:update(encrypted) regress.check(decrypted == message, "decrypted message doesn't match") regress.check(d:final(), "fail final decrypt") end test_aead { cipher = "aes-256-gcm"; tag_length = 16; } test_aead { cipher = "aes-256-ccm"; tag_length = 12; } luaossl-rel-20220711/regress/148-custom-extensions.lua000077500000000000000000000031711426273367600224370ustar00rootroot00000000000000#!/usr/bin/env lua local regress = require "regress" local cqueues = require "cqueues" local cs = require "cqueues.socket" local openssl_ctx = require "openssl.ssl.context" local cli_ctx, srv_ctx local call_check = 0 cli_ctx = regress.getsslctx("TLS", false, false) regress.check(cli_ctx.addCustomExtension, "Custom extension support not available") local function c_add_ext(ssl, ext_type, context) -- luacheck: ignore 212 call_check = call_check + 1 return "from the client" end local function c_parse_ext(ssl, ext_type, context, data) -- luacheck: ignore 212 call_check = call_check + 2 assert(data == "from the server") return true end cli_ctx:addCustomExtension(5000, openssl_ctx.EXT_CLIENT_HELLO + openssl_ctx.EXT_TLS1_2_SERVER_HELLO + openssl_ctx.EXT_TLS1_3_SERVER_HELLO , c_add_ext, c_parse_ext) srv_ctx = regress.getsslctx("TLS", true) local function s_add_ext(ssl, ext_type, context) -- luacheck: ignore 212 call_check = call_check + 4 return "from the server" end local function s_parse_ext(ssl, ext_type, context, data) -- luacheck: ignore 212 call_check = call_check + 8 assert(data == "from the client") return true end srv_ctx:addCustomExtension(5000, openssl_ctx.EXT_CLIENT_HELLO + openssl_ctx.EXT_TLS1_2_SERVER_HELLO + openssl_ctx.EXT_TLS1_3_SERVER_HELLO , s_add_ext, s_parse_ext) local srv, cli = regress.check(cs.pair(cs.SOCK_STREAM)) local main = regress.check(cqueues.new()) main:wrap(function () regress.check(cli:starttls(cli_ctx)) end) main:wrap(function () regress.check(srv:starttls(srv_ctx)) end) regress.check(main:loop()) regress.check(call_check == 15, "callback count doesn't match") regress.say "OK" luaossl-rel-20220711/regress/167-verify-cert.lua000077500000000000000000000026711426273367600211740ustar00rootroot00000000000000#!/usr/bin/env lua local regress = require "regress" if (regress.openssl.OPENSSL_VERSION_NUMBER and regress.openssl.OPENSSL_VERSION_NUMBER < 0x10002000) or (regress.openssl.LIBRESSL_VERSION_NUMBER and regress.openssl.LIBRESSL_VERSION_NUMBER < 0x20705000) then -- skipping test due to different behaviour in earlier OpenSSL versions return end local params = regress.verify_param.new() params:setDepth(0) local ca_key, ca_crt = regress.genkey() do -- should fail as no trust anchor regress.check(not ca_crt:verify({params=params, chain=nil, store=nil})) end local store = regress.store.new() store:add(ca_crt) do -- should succeed as cert is in the store regress.check(ca_crt:verify({params=params, chain=nil, store=store})) end local intermediate_key, intermediate_crt = regress.genkey(nil, ca_key, ca_crt) do -- should succeed as ca cert is in the store regress.check(intermediate_crt:verify({params=params, chain=nil, store=store})) end local _, crt = regress.genkey(nil, intermediate_key, intermediate_crt) do -- should fail as intermediate cert is missing regress.check(not crt:verify({params=params, chain=nil, store=store})) end local chain = regress.chain.new() chain:add(intermediate_crt) do -- should fail as max depth is too low regress.check(not crt:verify({params=params, chain=chain, store=store})) end params:setDepth(1) do -- should succeed regress.check(crt:verify({params=params, chain=chain, store=store})) end regress.say "OK" luaossl-rel-20220711/regress/177-reset-bio.lua000077500000000000000000000015221426273367600206210ustar00rootroot00000000000000#!/usr/bin/env lua local regress = require "regress" local ok, err local key = regress.pkey.new() -- generate a minimal certificate and export to DER local x509 = regress.x509.new() x509:setPublicKey(key) x509:sign(key) local x509_der = x509:tostring("DER") ok, err = pcall(regress.x509.new, x509_der) regress.check(ok, "failed to load DER certificate: %s", err) -- generate a minimal crl and export to DER local crl = regress.crl.new() crl:sign(key) local crl_der = crl:tostring("DER") ok, err = pcall(regress.crl.new, crl_der) regress.check(ok, "failed to load DER CRL: %s", err) -- generate a minimal csr and export to DER local csr = regress.csr.new() csr:setPublicKey(key) csr:sign(key) local csr_der = csr:tostring("DER") ok, err = pcall(regress.csr.new, csr_der) regress.check(ok, "failed to load DER CSR: %s", err) regress.say "OK" luaossl-rel-20220711/regress/53-csr-extensions.lua000077500000000000000000000116121426273367600216260ustar00rootroot00000000000000#!/usr/bin/env lua local auxlib = require"openssl.auxlib" local pkey = require "openssl.pkey" local x509_csr = require"_openssl.x509.csr" local x509_altname = require"openssl.x509.altname" local x509_name = require"openssl.x509.name" local _basename = arg and arg[0] and arg[0]:match"([^/]+)$" or "UNKNOWN" local function cluck(fmt, ...) io.stderr:write(_basename, ": ", string.format(fmt, ...), "\n") end local function croak(fmt, ...) io.stderr:write(_basename, ": ", string.format(fmt, ...), "\n") os.exit(1) end local function OK() cluck("OK") return true end local _testno = 0 local function testnames(altnames, expected) local matched = {} _testno = _testno + 1 for type,data in auxlib.pairs(altnames) do local found for i,e in ipairs(expected) do if not matched[i] and e.type == type and e.data == data then cluck("expected match #%d.%d found (%s=%s)", _testno, i, type,data) matched[i] = true found = true end end if not found then return false, string.format("extra name in test #%d (%s=%s)", _testno, type, data) end end for i,e in ipairs(expected) do if not matched[i] then return false, string.format("expected match #%d.%d not found (%s=%s)", _testno, i, e.type, e.data) end end return true end local function checknames(altnames, expected) local ok, why = testnames(altnames, expected) if not ok then croak(why or "UNKNOWN") end return true end key = pkey.new({ bits = 4096 }) data = [[ -----BEGIN CERTIFICATE REQUEST----- MIIFQjCCAyoCAQAwUzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1OMRQwEgYDVQQH DAtNaW5uZWFwb2xpczEhMB8GA1UECwwYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVk MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4sXzE3GQtpFKiuGe389k MB0OaGXQxiI/yl6zm9PyYWe5aMpx1THDVhkWXemDVkduEqtLfa8GSNT0ps3BPdTx qxNwZ3J9xiVfNZZYO5ZSxs1g32M1lw20wIezLpbQ1ggyt01o9VTQDY6kA+D0G87B 4FtIZxVaXM2z5HVaGYyivxAygDukDsO+RU0NC9mYOfAP4rt/u/xp8LsW0b4aIFqx gPcBZj92B+Wi2B4sKSe1m5kMfmh+e8v981hbY7V8FUMebB63iRGF6GU4kjXiMMW6 gSoc+usq9li8VxjxPngql9pyLqFIa/2gW0c9sKKB2X9tB0nmudjAUrjZjHZEDlNr yx15JHhEIT31yP9xGQpy5H+jBldp/shqaV4Alsou9Hn9W71ap7VHOWLrIcaZGKTn CVSSYPygn4Rm8Cgwbv5mP6G+SqGHAFqirEysAARUFxsjBLlkNaVFOA38l2cufH8n 1NE/B4iOG/ETvQDR/aKrbyKKo2k/hO941h3J9pwJcCikE0NsRcH6WAm8ifJ0Zd/q u8fqI8g9mYPbMWy11+njnfNOVFVhNOmM1/ZM66ac9zgGYncaHu4UzYnvWw75tDbF vA+oIJlcxBUtWeTcYRf4xEcRL8IcHEwh1BZq7bgP42Wu+0aBuaa3eYXNBApCNP39 QmnHlo0iGH2rVeOfcq/wULcCAwEAAaCBqTCBpgYJKoZIhvcNAQkOMYGYMIGVMAkG A1UdEwQCMAAwCwYDVR0PBAQDAgXgMHsGA1UdEQR0MHKCE3NlcnZlcjEuZXhhbXBs ZS5jb22CEG1haWwuZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbYITd3d3LnN1 Yi5leGFtcGxlLmNvbYIObXguZXhhbXBsZS5jb22CE3N1cHBvcnQuZXhhbXBsZS5j b20wDQYJKoZIhvcNAQEFBQADggIBAMiFPtDKVsy4HBhVkHSnbbIl41baaGGFjI/O MG8fI7P9jplq5rNZcLxSW2zLzMVuYzCoC+q5roRE5zVVyJlB+5dY0A8e2xKaWVOT AB9WvgepPvXDoGNViMBoX/idj3J2BU3e/cX08QWRPjKigwQWQWvUGsZYitGJv+Yv /LbIDlxr8Jr+1Txcm1EdXcff6Owlh6Nu59bgCMRdZvABmWfU5ULmUDTJnmc3P9St onz07v8ku8/XL7wwOfLJWVSVOk7RONySIJiPfVkgrU3YWiT64JaluDbFEIwnEgJS 04xL6Pl66bADXCaeG3pZ8ypCs41+4bqFvCnOYma0Sk8fv8hSCWvJfMQI+nQslPJu UuGK4C4EEnYvoh/Qs/XEshfrVaNcG0zER3XtsRPAjhZjTPTcRgEjpOI0w3TJAvlN LSQV4mXN6E2bcU+cRYvNSgqITwJ7c6wpsONwApIQwFryLsFSCHaIdSLpAZbEPNEW UPa3uWXk5lWrBBPPkxyPbt8D3zpzahY4ycYEFKdz8MLdgA7pDalI2XpwgmoUybkw AJnsFg7fnFc03R4FsqxCqvbRYj3Bccb8Uhg1zTeXU+7nxjP2yYdT+In16L9SYOsU 4ozEPqnGY9aI11i6C7hBwrUTvHYD6ZSDlylsUXKw/VZXQvS3+C0h6NuRmjBx8jNU RG1EyxL4 -----END CERTIFICATE REQUEST----- ]] -- baseline do local expected = { { type = "DNS", data = "server1.example.com" }, { type = "DNS", data = "mail.example.com" }, { type = "DNS", data = "www.example.com" }, { type = "DNS", data = "www.sub.example.com" }, { type = "DNS", data = "mx.example.com" }, { type = "DNS", data = "support.example.com" }, } checknames((x509_csr.new(data)):getSubjectAlt(), expected) end -- modifying existing altnames do local expected = { { type = "DNS", data = "foo.com" }, { type = "DNS", data = "*.foo.com" }, } local csr = x509_csr.new(data) local gn = x509_altname.new() gn:add("DNS", "foo.com") gn:add("DNS", "*.foo.com") csr:setSubjectAlt(gn) csr:setPublicKey(key) csr:sign(key) -- check modified object checknames(csr:getSubjectAlt(), expected) -- check after a round-trip through PEM checknames(x509_csr.new(tostring(csr)):getSubjectAlt(), expected) end -- adding altnames where none existed do local expected = { name = { { type = "CN", data = "example.com" }, }, altname = { { type = "DNS", data = "foo.com" }, { type = "DNS", data = "*.foo.com" }, }, } local csr = x509_csr.new() local name = x509_name.new() name:add("CN", "example.com") csr:setSubject(name) local gn = x509_altname.new() gn:add("DNS", "foo.com") gn:add("DNS", "*.foo.com") csr:setSubjectAlt(gn) csr:setPublicKey(key) csr:sign(key) checknames(csr:getSubject(), expected.name) checknames(csr:getSubjectAlt(), expected.altname) local csr1 = x509_csr.new(tostring(csr)) checknames(csr1:getSubject(), expected.name) checknames(csr1:getSubjectAlt(), expected.altname) end return OK() luaossl-rel-20220711/regress/82-bn_prepops-null-deref.lua000077500000000000000000000031531426273367600230470ustar00rootroot00000000000000#!/usr/bin/env lua -- -- The following code could trigger a NULL dereference. -- -- bn_prepops(lua_State *L, BIGNUM **r, BIGNUM **a, BIGNUM **b, _Bool commute) { -- ... -- *b = checkbig(L, 2, &lvalue); -- ... -- } -- -- bn_sqr(lua_State *L) { -- BIGNUM *r, *a; -- -- bn_prepops(L, &r, &a, NULL, 1); -- ... -- } -- -- Caught by clang static analyzer. This was introduced with a patch adding -- the :sqr method. This should have been caught sooner as the :sqr method -- couldn't have possibly ever worked--a missing or non-numeric second -- operand would have thrown a Lua error, and a numeric second operand -- triggers the NULL dereference. -- require"regress".export".*" local function N(i) return bignum.new(i) end -- passing a second numeric operand triggered a NULL dereference local r = N(4):sqr(0) -- check minimal functionality of all our operators local tests = { { op = "add", a = 1, b = 1, r = 2 }, { op = "sub", a = 2, b = 1, r = 1 }, { op = "mul", a = 2, b = 2, r = 4 }, { op = "idiv", a = 4, b = 2, r = 2 }, { op = "mod", a = 4, b = 2, r = 0 }, { op = "exp", a = 2, b = 2, r = 4 }, { op = "sqr", a = 4, b = nil, r = 16 }, { op = "gcd", a = 47, b = 3, r = 1 }, } local function tdescr(t) return string.format("%s(%s, %s)", t.op, tostring(t.a), tostring(t.b)) end for i,t in ipairs(tests) do local a = N(t.a) local op = a[t.op] local ok, r if t.b then ok, r = pcall(op, a, t.b) else ok, r = pcall(op, a) end check(ok, "failed test #%d (%s) (%s)", i, tdescr(t), r) check(N(r) == N(t.r), "failed test #%d (%s) (expected %s, got %s)", i, tdescr(t), tostring(t.r), tostring(r)) end say"OK" luaossl-rel-20220711/regress/95-kdf.lua000077500000000000000000000025421426273367600174160ustar00rootroot00000000000000#!/usr/bin/env lua local regress = require "regress" local kdf = require "openssl.kdf" local function hexstring(str) return (str:gsub("..", function(b) return string.char(tonumber(b, 16)) end)) end -- Scrypt Example regress.check(kdf.derive{ type = "id-scrypt"; -- the nid short-name is id-scrypt pass = ""; salt = ""; N = 16; r = 1; p = 1; outlen = 64; } == hexstring"77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906", "scrypt output doesn't match test vector") -- PBKDF2 Example regress.check(kdf.derive{ type = "PBKDF2"; pass = "password"; salt = "salt"; iter = 1; md = "sha1"; outlen = 20; } == hexstring"0c60c80f961f0e71f3a9b524af6012062fe037a6", "PBKDF2 output doesn't match test vector") -- TLS1-PRF Example regress.check(kdf.derive{ type = "TLS1-PRF"; md = "md5-sha1"; secret = hexstring"bded7fa5c1699c010be23dd06ada3a48349f21e5f86263d512c0c5cc379f0e780ec55d9844b2f1db02a96453513568d0"; seed = "master secret" .. hexstring"e5acaf549cd25c22d964c0d930fa4b5261d2507fad84c33715b7b9a864020693" .. hexstring"135e4d557fdf3aa6406d82975d5c606a9734c9334b42136e96990fbd5358cdb2"; outlen = 48; } == hexstring"2f6962dfbc744c4b2138bb6b3d33054c5ecc14f24851d9896395a44ab3964efc2090c5bf51a0891209f46c1e1e998f62", "TLS1-PRF output doesn't match test vector") regress.say "OK" luaossl-rel-20220711/regress/regress.lua000066400000000000000000000103321426273367600200620ustar00rootroot00000000000000local require = require -- may be overloaded by regress.require local regress = { openssl = require"openssl", bignum = require"openssl.bignum", kdf = require"openssl.kdf", pkey = require"openssl.pkey", x509 = require"openssl.x509", name = require"openssl.x509.name", altname = require"openssl.x509.altname", chain = require"openssl.x509.chain", store = require"openssl.x509.store", verify_param = require"openssl.x509.verify_param", crl = require"openssl.x509.crl", csr = require"openssl.x509.csr", pack = table.pack or function (...) local t = { ... } t.n = select("#", ...) return t end, unpack = table.unpack or unpack, } local emit_progname = os.getenv"REGRESS_PROGNAME" or "regress" local emit_verbose = tonumber(os.getenv"REGRESS_VERBOSE" or 1) local emit_info = {} local emit_ll = 0 local function emit(fmt, ...) local msg = string.format(fmt, ...) for txt, nl in msg:gmatch("([^\n]*)(\n?)") do if emit_ll == 0 and #txt > 0 then io.stderr:write(emit_progname, ": ") emit_ll = #emit_progname + 2 end io.stderr:write(txt, nl) if nl == "\n" then emit_ll = 0 else emit_ll = emit_ll + #txt end end end -- emit local function emitln(fmt, ...) if emit_ll > 0 then emit"\n" end emit(fmt .. "\n", ...) end -- emitln local function emitinfo() for _, txt in ipairs(emit_info) do emitln("%s", txt) end end -- emitinfo function regress.say(...) emitln(...) end -- say function regress.panic(...) emitinfo() emitln(...) os.exit(1) end -- panic function regress.info(...) if emit_verbose > 1 then emitln(...) else emit_info[#emit_info + 1] = string.format(...) if emit_verbose > 0 then if emit_ll > 78 then emit"\n." else emit"." end end end end -- info function regress.check(v, ...) if v then return v, ... else regress.panic(...) end end -- check function regress.export(...) for _, pat in ipairs{ ... } do for k, v in pairs(regress) do if string.match(k, pat) then _G[k] = v end end end return regress end -- export function regress.require(modname) local ok, module = pcall(require, modname) regress.check(ok, "module %s required", modname) return module end -- regress.require local counter = 0 function regress.genkey(type, ca_key, ca_crt) local pkey = regress.require"openssl.pkey" local x509 = regress.require"openssl.x509" local name = regress.require"openssl.x509.name" local altname = regress.require"openssl.x509.altname" local key type = string.upper(type or "RSA") if type == "EC" then key = regress.check(pkey.new{ type = "EC", curve = "prime192v1" }) else key = regress.check(pkey.new{ type = type, bits = 2048 }) end local dn = name.new() dn:add("C", "US") dn:add("ST", "California") dn:add("L", "San Francisco") dn:add("O", "Acme, Inc.") dn:add("CN", string.format("acme%d.inc", counter)) counter = counter + 1 local alt = altname.new() alt:add("DNS", "acme.inc") alt:add("DNS", "localhost") local crt = x509.new() crt:setVersion(3) crt:setSerial(47) crt:setSubject(dn) crt:setIssuer((ca_crt or crt):getSubject()) crt:setSubjectAlt(alt) local issued, expires = crt:getLifetime() crt:setLifetime(issued, expires + 60) crt:setBasicConstraints{ CA = true, pathLen = 2 } crt:setBasicConstraintsCritical(true) crt:setPublicKey(key) crt:sign(ca_key or key) return key, crt end -- regress.genkey local function getsubtable(t, name, ...) name = name or false -- cannot be nil if not t[name] then t[name] = {} end if select('#', ...) > 0 then return getsubtable(t[name], ...) else return t[name] end end -- getsubtable function regress.newsslctx(protocol, accept, keytype) local context = regress.require"openssl.ssl.context" local ctx = context.new(protocol, accept) if keytype or keytype == nil then local key, crt = regress.genkey(keytype) ctx:setCertificate(crt) ctx:setPrivateKey(key) end return ctx end -- require.newsslctx local ctxcache = {} function regress.getsslctx(protocol, accept, keytype) local keycache = getsubtable(ctxcache, protocol, accept) if keytype == nil then keytype = "RSA" end local ctx = keycache[keytype] if not ctx then ctx = regress.newsslctx(protocol, accept, keytype) keycache[keytype] = ctx end return ctx end -- regress.getsslctx return regress luaossl-rel-20220711/src/000077500000000000000000000000001426273367600150235ustar00rootroot00000000000000luaossl-rel-20220711/src/GNUmakefile000066400000000000000000000173611426273367600171050ustar00rootroot00000000000000# non-recursive prologue sp := $(sp).x dirstack_$(sp) := $(d) d := $(abspath $(lastword $(MAKEFILE_LIST))/..) ifeq ($(origin GUARD_$(d)), undefined) GUARD_$(d) := 1 # # E N V I R O N M E N T C O N F I G U R A T I O N # include $(d)/../GNUmakefile # # C O M P I L A T I O N F L A G S # CPPFLAGS_$(d) = $(ALL_CPPFLAGS) -DHAVE_CONFIG_H -DCOMPAT53_PREFIX=luaossl CFLAGS_$(d) = $(ALL_CFLAGS) SOFLAGS_$(d) = $(ALL_SOFLAGS) LDFLAGS_$(d) = $(ALL_LDFLAGS) LIBS_$(d) = $(ALL_LIBS) # # C O M P I L A T I O N R U L E S # OBJS_$(d) = openssl.o $(d)/config.h: $(abspath $(d)/..)/config.h $(CP) $< $@ define BUILD_$(d) $$(d)/$(1)/openssl.so: $$(addprefix $$(d)/$(1)/, $$(OBJS_$(d))) $$(CC) -o $$@ $$^ $$(SOFLAGS_$$(abspath $$(@D)/..)) $$(LDFLAGS_$$(abspath $$(@D)/..)) $$(LIBS_$$(abspath $$(@D)/..)) $$(d)/$(1)/%.o: $$(d)/%.c $$(d)/config.h $$(MKDIR) -p $$(@D) $$(CC) $$(CFLAGS_$$(" help: $(d)/help endif # include guard # non-recursive epilogue d := $(dirstack_$(sp)) sp := $(basename $(sp)) luaossl-rel-20220711/src/Makefile000066400000000000000000000001161426273367600164610ustar00rootroot00000000000000.POSIX: all: +gmake -f GNUmakefile all .DEFAULT: +gmake -f GNUmakefile $< luaossl-rel-20220711/src/openssl.auxlib.lua000066400000000000000000000004641426273367600205000ustar00rootroot00000000000000local auxlib = {} if _VERSION == "Lua 5.1" then local _pairs = pairs function auxlib.pairs(t) if type(t) == "userdata" then local mt = getmetatable(t) if mt and mt.__pairs then return mt.__pairs(t) else return _pairs(t) end end end else auxlib.pairs = pairs end return auxlib luaossl-rel-20220711/src/openssl.bignum.lua000066400000000000000000000000671426273367600204740ustar00rootroot00000000000000local bignum = require"_openssl.bignum" return bignum luaossl-rel-20220711/src/openssl.c000066400000000000000000011513271426273367600166640ustar00rootroot00000000000000/* ========================================================================== * openssl.c - Lua OpenSSL * -------------------------------------------------------------------------- * Copyright (c) * 2012-2017 William Ahern * 2015-2019 Daurnimator * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #if HAVE_CONFIG_H #include "config.h" #endif #include /* INT_MAX INT_MIN LLONG_MAX LLONG_MIN UCHAR_MAX ULLONG_MAX */ #include /* uintptr_t */ #include /* memset(3) strerror_r(3) */ #include /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ #include /* struct tm time_t strptime(3) time(2) */ #include /* isdigit(3), isxdigit(3), tolower(3) */ #include /* ENOMEM ENOTSUP EOVERFLOW errno */ #include /* assert */ #include /* struct stat stat(2) */ #ifdef _WIN32 #include /* AF_INET, AF_INET6 */ #include /* struct in_addr, struct in6_addr */ #include /* inet_pton */ #include /* CryptAcquireContext(), CryptGenRandom(), CryptReleaseContext() */ #include /* CreateMutex(), GetLastError(), GetModuleHandleEx(), GetProcessTimes(), InterlockedCompareExchangePointer() */ #define EXPORT __declspec (dllexport) #else #include /* inet_pton(3) */ #include /* dladdr(3) dlopen(3) */ #include /* O_RDONLY O_CLOEXEC open(2) */ #include /* struct in_addr struct in6_addr */ #include /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */ #include /* RUSAGE_SELF struct rusage getrusage(2) */ #include /* AF_INET AF_INET6 */ #include /* struct timeval gettimeofday(2) */ #include /* ssize_t pid_t */ #include /* struct utsname uname(3) */ #include /* close(2) getpid(2) */ #define EXPORT #endif #if __APPLE__ #include /* mach_absolute_time() */ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LUA_VERSION_NUM < 503 #include "../vendor/compat53/c-api/compat-5.3.h" #endif #ifndef LUAOSSL_USE_47BIT_LIGHTUSERDATA_HACK /* LuaJIT only supports pointers with the low 47 bits set */ #if defined(LUA_JITLIBNAME) && (defined(_LP64) || defined(_LLP64) || defined(__arch64__) || defined (__arm64__) || defined (__aarch64__) || defined(_WIN64)) #define LUAOSSL_USE_47BIT_LIGHTUSERDATA_HACK 1 #else #define LUAOSSL_USE_47BIT_LIGHTUSERDATA_HACK 0 #endif #endif #if LUAOSSL_USE_47BIT_LIGHTUSERDATA_HACK #define LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(p) ((void *)((intptr_t)(p) & ((1UL<<47)-1))) #else #define LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(p) ((void *)(p)) #endif #define GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p)) #define GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= GNUC_2VER((M), (m), (p))) #define MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p)) #define MSC_PREREQ(M, m, p) (_MSC_FULL_VER > 0 && _MSC_FULL_VER >= MSC_2VER((M), (m), (p))) #ifdef LIBRESSL_VERSION_NUMBER #define OPENSSL_PREREQ(M, m, p) (0) #define LIBRESSL_PREREQ(M, m, p) \ (LIBRESSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12))) #else #define OPENSSL_PREREQ(M, m, p) \ (OPENSSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12))) #define LIBRESSL_PREREQ(M, m, p) (0) #endif #ifndef __has_builtin #define __has_builtin(x) 0 #endif #ifndef __has_extension #define __has_extension(x) 0 #endif #ifndef HAVE_C___ASSUME #define HAVE_C___ASSUME MSC_PREREQ(8,0,0) #endif #ifndef HAVE_C___BUILTIN_UNREACHABLE #define HAVE_C___BUILTIN_UNREACHABLE (GNUC_PREREQ(4,5,0) || __has_builtin(__builtin_unreachable)) #endif #ifndef HAVE_C___DECLSPEC_NORETURN #define HAVE_C___DECLSPEC_NORETURN MSC_PREREQ(8,0,0) #endif #ifndef HAVE_OPENSSL_ZALLOC #define HAVE_OPENSSL_ZALLOC OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_OPENSSL_CLEAR_FREE #define HAVE_OPENSSL_CLEAR_FREE OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_OPENSSL_MEMDUP #define HAVE_OPENSSL_MEMDUP OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_ASN1_STRING_GET0_DATA #define HAVE_ASN1_STRING_GET0_DATA (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DH_GET0_KEY #define HAVE_DH_GET0_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DH_GET0_PQG #define HAVE_DH_GET0_PQG (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DH_SET0_KEY #define HAVE_DH_SET0_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DH_SET0_PQG #define HAVE_DH_SET0_PQG (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DSA_GET0_KEY #define HAVE_DSA_GET0_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DSA_GET0_PQG #define HAVE_DSA_GET0_PQG (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DSA_SET0_KEY #define HAVE_DSA_SET0_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DSA_SET0_PQG #define HAVE_DSA_SET0_PQG (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_DTLSV1_CLIENT_METHOD #ifdef OPENSSL_NO_DTLS1 #define HAVE_DTLSV1_CLIENT_METHOD (0) #else #define HAVE_DTLSV1_CLIENT_METHOD (1) #endif #endif #ifndef HAVE_DTLSV1_SERVER_METHOD #define HAVE_DTLSV1_SERVER_METHOD HAVE_DTLSV1_CLIENT_METHOD #endif #ifndef HAVE_DTLS_CLIENT_METHOD #ifdef OPENSSL_NO_DTLS1 #define HAVE_DTLS_CLIENT_METHOD (0) #else #define HAVE_DTLS_CLIENT_METHOD OPENSSL_PREREQ(1,0,2) #endif #endif #ifndef HAVE_DTLS_SERVER_METHOD #define HAVE_DTLS_SERVER_METHOD HAVE_DTLS_CLIENT_METHOD #endif #ifndef HAVE_DTLSV1_2_CLIENT_METHOD #ifdef OPENSSL_NO_DTLS1 #define HAVE_DTLSV1_2_CLIENT_METHOD (0) #else #define HAVE_DTLSV1_2_CLIENT_METHOD OPENSSL_PREREQ(1,0,2) #endif #endif #ifndef HAVE_DTLSV1_2_SERVER_METHOD #define HAVE_DTLSV1_2_SERVER_METHOD HAVE_DTLSV1_2_CLIENT_METHOD #endif #ifndef HAVE_EVP_CIPHER_CTX_FREE #define HAVE_EVP_CIPHER_CTX_FREE (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_CIPHER_CTX_NEW #define HAVE_EVP_CIPHER_CTX_NEW (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_KDF_CTX #define HAVE_EVP_KDF_CTX OPENSSL_PREREQ(3,0,0) #endif #ifndef HAVE_OSSL_PARAM #define HAVE_OSSL_PARAM OPENSSL_PREREQ(3,0,0) #endif #ifndef HAVE_PKCS5_PBKDF2_HMAC #define HAVE_PKCS5_PBKDF2_HMAC (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_SCRYPT #define HAVE_SCRYPT OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_EVP_MD_CTX_FREE #define HAVE_EVP_MD_CTX_FREE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_EVP_MD_CTX_NEW #define HAVE_EVP_MD_CTX_NEW (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_EVP_PKEY_GET_DEFAULT_DIGEST_NID #define HAVE_EVP_PKEY_GET_DEFAULT_DIGEST_NID (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_PKEY_BASE_ID #define HAVE_EVP_PKEY_BASE_ID (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_PKEY_CTX_NEW #define HAVE_EVP_PKEY_CTX_NEW (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_PKEY_CTX_KDF #define HAVE_EVP_PKEY_CTX_KDF OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_EVP_PKEY_CTX_HKDF_MODE #define HAVE_EVP_PKEY_CTX_HKDF_MODE (HAVE_EVP_PKEY_CTX_KDF && OPENSSL_PREREQ(1,1,1)) #endif #ifndef HAVE_EVP_PKEY_GET0 #define HAVE_EVP_PKEY_GET0 (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_PKEY_GET0_RSA #define HAVE_EVP_PKEY_GET0_RSA (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,5)) #endif #ifndef HAVE_EVP_PKEY_GET0_DSA #define HAVE_EVP_PKEY_GET0_DSA (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,5)) #endif #ifndef HAVE_EVP_PKEY_GET0_DH #define HAVE_EVP_PKEY_GET0_DH (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,5)) #endif #ifndef HAVE_EVP_PKEY_GET0_EC_KEY #define HAVE_EVP_PKEY_GET0_EC_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,5)) #endif #ifndef HAVE_EVP_PKEY_ID #define HAVE_EVP_PKEY_ID (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_PKEY_KEYGEN #define HAVE_EVP_PKEY_KEYGEN (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_EVP_PKEY_RAW #define HAVE_EVP_PKEY_RAW OPENSSL_PREREQ(1,1,1) #endif #ifndef HAVE_HMAC_CTX_FREE #define HAVE_HMAC_CTX_FREE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_HMAC_CTX_NEW #define HAVE_HMAC_CTX_NEW (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_I2D_RE_X509_REQ_TBS #define HAVE_I2D_RE_X509_REQ_TBS OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_RSA_GET0_CRT_PARAMS #define HAVE_RSA_GET0_CRT_PARAMS (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_RSA_GET0_FACTORS #define HAVE_RSA_GET0_FACTORS (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_RSA_GET0_KEY #define HAVE_RSA_GET0_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_RSA_SET0_CRT_PARAMS #define HAVE_RSA_SET0_CRT_PARAMS (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_RSA_SET0_FACTORS #define HAVE_RSA_SET0_FACTORS (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_RSA_SET0_KEY #define HAVE_RSA_SET0_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_SSL_CLIENT_VERSION #define HAVE_SSL_CLIENT_VERSION OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_SSL_CTX_ADD_CUSTOM_EXT #define HAVE_SSL_CTX_ADD_CUSTOM_EXT OPENSSL_PREREQ(1,1,1) #endif #ifndef HAVE_SSL_CTX_GET0_CHAIN_CERTS #define HAVE_SSL_CTX_GET0_CHAIN_CERTS OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_CTX_GET0_PARAM #define HAVE_SSL_CTX_GET0_PARAM (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_SSL_CTX_GET0_CERTIFICATE #define HAVE_SSL_CTX_GET0_CERTIFICATE (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_SSL_CTX_SET_CIPHERSUITES #define HAVE_SSL_CTX_SET_CIPHERSUITES OPENSSL_PREREQ(1,1,1) #endif #ifndef HAVE_SSL_CTX_SET_CURVES_LIST #define HAVE_SSL_CTX_SET_CURVES_LIST (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,5,1)) #endif #ifndef HAVE_SSL_CTX_SET_GROUPS_LIST #if OPENSSL_PREREQ(1,1,1) #define HAVE_SSL_CTX_SET_GROUPS_LIST 1 #elif HAVE_SSL_CTX_SET_CURVES_LIST #define SSL_CTX_set1_groups_list SSL_CTX_set1_curves_list #define HAVE_SSL_CTX_SET_GROUPS_LIST 1 #else #define HAVE_SSL_CTX_SET_GROUPS_LIST 0 #endif #endif #ifndef HAVE_SSL_CTX_SET_GROUPS_LIST #define HAVE_SSL_CTX_SET_GROUPS_LIST OPENSSL_PREREQ(1,1,1) #endif #ifndef HAVE_SSL_CTX_SET_ECDH_AUTO #define HAVE_SSL_CTX_SET_ECDH_AUTO ((OPENSSL_PREREQ(1,0,2) && !OPENSSL_PREREQ(1,1,0)) || LIBRESSL_PREREQ(2,1,2)) #endif #ifndef HAVE_SSL_CTX_SET_ALPN_PROTOS #define HAVE_SSL_CTX_SET_ALPN_PROTOS (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,1,3)) #endif #ifndef HAVE_SSL_CTX_SET_ALPN_SELECT_CB #define HAVE_SSL_CTX_SET_ALPN_SELECT_CB HAVE_SSL_CTX_SET_ALPN_PROTOS #endif #ifndef HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK #define HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_SSL_CTX_SET1_CERT_STORE #define HAVE_SSL_CTX_SET1_CERT_STORE (HAVE_SSL_CTX_set1_cert_store || OPENSSL_PREREQ(1,1,1)) /* backwards compatible with old macro name */ #endif #ifndef HAVE_SSL_CTX_SET1_CHAIN #define HAVE_SSL_CTX_SET1_CHAIN OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_CTX_SET1_PARAM #define HAVE_SSL_CTX_SET1_PARAM (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,1,0)) #endif #ifndef HAVE_SSL_CTX_UP_REF #define HAVE_SSL_CTX_UP_REF (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_SSL_CTX_CERT_STORE #define HAVE_SSL_CTX_CERT_STORE (!OPENSSL_PREREQ(1,1,0)) #endif #ifndef HAVE_SSL_CTX_SET_TLSEXT_STATUS_TYPE #define HAVE_SSL_CTX_SET_TLSEXT_STATUS_TYPE OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_SSL_CTX_GET_TLSEXT_STATUS_TYPE #define HAVE_SSL_CTX_GET_TLSEXT_STATUS_TYPE OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEYS #define HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEYS OPENSSL_PREREQ(1,0,0) #endif #ifndef HAVE_SSL_CTX_GET_TLSEXT_TICKET_KEYS #define HAVE_SSL_CTX_GET_TLSEXT_TICKET_KEYS OPENSSL_PREREQ(1,0,0) #endif #ifndef HAVE_SSL_CTX_USE_SERVERINFO #define HAVE_SSL_CTX_USE_SERVERINFO OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_CTX_USE_SERVERINFO_EX #define HAVE_SSL_CTX_USE_SERVERINFO_EX OPENSSL_PREREQ(1,1,1) #endif #ifndef HAVE_SSL_CTX_USE_SERVERINFO_FILE #define HAVE_SSL_CTX_USE_SERVERINFO_FILE OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_EXTENSION_SUPPORTED #define HAVE_SSL_EXTENSION_SUPPORTED OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_GET0_ALPN_SELECTED #define HAVE_SSL_GET0_ALPN_SELECTED HAVE_SSL_CTX_SET_ALPN_PROTOS #endif #ifndef HAVE_SSL_GET0_CHAIN_CERTS #define HAVE_SSL_GET0_CHAIN_CERTS OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_GET0_PARAM #define HAVE_SSL_GET0_PARAM (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_SSL_SET_ALPN_PROTOS #define HAVE_SSL_SET_ALPN_PROTOS HAVE_SSL_CTX_SET_ALPN_PROTOS #endif #ifndef HAVE_SSL_SET1_CHAIN_CERT_STORE #define HAVE_SSL_SET1_CHAIN_CERT_STORE OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_SET1_VERIFY_CERT_STORE #define HAVE_SSL_SET1_VERIFY_CERT_STORE OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_SET_CIPHERSUITES #define HAVE_SSL_SET_CIPHERSUITES OPENSSL_PREREQ(1,1,1) #endif #ifndef HAVE_SSL_SET_CURVES_LIST #define HAVE_SSL_SET_CURVES_LIST (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,5,1)) #endif #ifndef HAVE_SSL_SET_GROUPS_LIST #if OPENSSL_PREREQ(1,1,1) #define HAVE_SSL_SET_GROUPS_LIST 1 #elif HAVE_SSL_SET_CURVES_LIST #define SSL_set1_groups_list SSL_set1_curves_list #define HAVE_SSL_SET_GROUPS_LIST 1 #else #define HAVE_SSL_SET_GROUPS_LIST 0 #endif #endif #ifndef HAVE_SSL_SET1_CHAIN #define HAVE_SSL_SET1_CHAIN OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_SET1_PARAM #define HAVE_SSL_SET1_PARAM (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,5,1)) #endif #ifndef HAVE_SSL_GET_CLIENT_RANDOM #define HAVE_SSL_GET_CLIENT_RANDOM (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_SSL_GET_SERVER_TMP_KEY #define HAVE_SSL_GET_SERVER_TMP_KEY (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,5,3)) #endif #ifndef HAVE_SSL_GET_TLSEXT_STATUS_TYPE #define HAVE_SSL_GET_TLSEXT_STATUS_TYPE OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_SSL_UP_REF #define HAVE_SSL_UP_REF (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_SSL_OP_NO_SSL_MASK #ifdef SSL_OP_NO_SSL_MASK #define HAVE_SSL_OP_NO_SSL_MASK (1) #else #define HAVE_SSL_OP_NO_SSL_MASK (0) #endif #endif #ifndef HAVE_SSL_OP_NO_DTLS_MASK #ifdef SSL_OP_NO_DTLS_MASK #define HAVE_SSL_OP_NO_DTLS_MASK (1) #else #define HAVE_SSL_OP_NO_DTLS_MASK (0) #endif #endif #ifndef HAVE_SSL_SESSION_MASTER_KEY #define HAVE_SSL_SESSION_MASTER_KEY (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_STACK_OPENSSL_STRING_FUNCS #define HAVE_STACK_OPENSSL_STRING_FUNCS (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_X509_CHAIN_UP_REF #define HAVE_X509_CHAIN_UP_REF OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_X509_CRL_GET0_LASTUPDATE #define HAVE_X509_CRL_GET0_LASTUPDATE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_CRL_GET0_NEXTUPDATE #define HAVE_X509_CRL_GET0_NEXTUPDATE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_CRL_GET0_BY_CERT #define HAVE_X509_CRL_GET0_BY_CERT (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_X509_CRL_GET0_BY_SERIAL #define HAVE_X509_CRL_GET0_BY_SERIAL (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_X509_CRL_SET1_LASTUPDATE #define HAVE_X509_CRL_SET1_LASTUPDATE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_CRL_SET1_NEXTUPDATE #define HAVE_X509_CRL_SET1_NEXTUPDATE (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_GET_SIGNATURE_NID #define HAVE_X509_GET_SIGNATURE_NID (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_STORE_REFERENCES #define HAVE_X509_STORE_REFERENCES (!OPENSSL_PREREQ(1,1,0)) #endif #ifndef HAVE_X509_STORE_UP_REF #define HAVE_X509_STORE_UP_REF (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_UP_REF #define HAVE_X509_UP_REF (OPENSSL_PREREQ(1,1,0) || LIBRESSL_PREREQ(2,5,1)) #endif #ifndef HAVE_X509_VERIFY_PARAM_ADD1_HOST #define HAVE_X509_VERIFY_PARAM_ADD1_HOST (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL #define HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_X509_VERIFY_PARAM_SET1_EMAIL #define HAVE_X509_VERIFY_PARAM_SET1_EMAIL (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_VERIFY_PARAM_SET1_HOST #define HAVE_X509_VERIFY_PARAM_SET1_HOST (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HAVE_X509_VERIFY_PARAM_SET1_IP_ASC #define HAVE_X509_VERIFY_PARAM_SET1_IP_ASC (OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,0)) #endif #ifndef HMAC_INIT_EX_INT #define HMAC_INIT_EX_INT OPENSSL_PREREQ(1,0,0) #endif #if HAVE_EVP_PKEY_CTX_KDF || HAVE_EVP_KDF_CTX #include #endif #if HAVE_EVP_KDF_CTX #include #endif #ifndef STRERROR_R_CHAR_P #ifdef __GLIBC__ #define STRERROR_R_CHAR_P (_GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)) #else #define STRERROR_R_CHAR_P (0) #endif #endif #ifndef LIST_HEAD #define LIST_HEAD(name, type) struct name { struct type *lh_first; } #define LIST_ENTRY(type) struct { struct type *le_next, **le_prev; } #define LIST_INIT(head) do { LIST_FIRST((head)) = NULL; } while (0) #define LIST_FIRST(head) ((head)->lh_first) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_REMOVE(elm, field) do { \ if (LIST_NEXT((elm), field) != NULL) \ LIST_NEXT((elm), field)->field.le_prev = (elm)->field.le_prev; \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ LIST_FIRST((head)) = (elm); \ (elm)->field.le_prev = &LIST_FIRST((head)); \ } while (0) #endif #define BIGNUM_CLASS "BIGNUM*" #define PKEY_CLASS "EVP_PKEY*" #define EC_GROUP_CLASS "EVP_GROUP*" #define X509_NAME_CLASS "X509_NAME*" #define X509_GENS_CLASS "GENERAL_NAMES*" #define X509_EXT_CLASS "X509_EXTENSION*" #define X509_CERT_CLASS "X509*" #define X509_CHAIN_CLASS "STACK_OF(X509)*" #define X509_CSR_CLASS "X509_REQ*" #define X509_CRL_CLASS "X509_CRL*" #define X509_STORE_CLASS "X509_STORE*" #define X509_VERIFY_PARAM_CLASS "X509_VERIFY_PARAM*" #define X509_STCTX_CLASS "X509_STORE_CTX*" #define PKCS12_CLASS "PKCS12*" #define SSL_CTX_CLASS "SSL_CTX*" #define SSL_CLASS "SSL*" #define DIGEST_CLASS "EVP_MD_CTX*" #define HMAC_CLASS "HMAC_CTX*" #define CIPHER_CLASS "EVP_CIPHER_CTX*" #define OCSP_RESPONSE_CLASS "OCSP_RESPONSE*" #define OCSP_BASICRESP_CLASS "OCSP_BASICRESP*" #if __GNUC__ #define NOTUSED __attribute__((unused)) #else #define NOTUSED #endif #if HAVE_C___BUILTIN_UNREACHABLE #define NOTREACHED __builtin_unreachable() #elif HAVE_C___ASSUME #define NOTREACHED __assume(0) #else #define NOTREACHED (void)0 #endif #define countof(a) (sizeof (a) / sizeof *(a)) #define endof(a) (&(a)[countof(a)]) #define CLAMP(i, min, max) (((i) < (min))? (min) : ((i) > (max))? (max) : (i)) #undef MIN #define MIN(a, b) (((a) < (b))? (a) : (b)) #ifdef _WIN32 #if !defined(S_ISDIR) && defined(_S_IFDIR) && defined(_S_IFDIR) #define S_ISDIR(m) (((m) & _S_IFDIR) == _S_IFDIR) #endif #define stricmp(a, b) _stricmp((a), (b)) #else #include /* strcasecmp(3) */ #define stricmp(a, b) strcasecmp((a), (b)) #endif #define strieq(a, b) (!stricmp((a), (b))) #define xtolower(c) tolower((unsigned char)(c)) #define SAY_(file, func, line, fmt, ...) \ fprintf(stderr, "%s:%d: " fmt "%s", __func__, __LINE__, __VA_ARGS__) #define SAY(...) SAY_(__FILE__, __func__, __LINE__, __VA_ARGS__, "\n") #define HAI SAY("hai") #define xitoa_putc(c) do { if (p < lim) dst[p] = (c); p++; } while (0) static const char *xitoa(char *dst, size_t lim, long i) { size_t p = 0; unsigned long d = 1000000000UL, n = 0, r; if (i < 0) { xitoa_putc('-'); i *= -1; } if ((i = MIN(2147483647L, i))) { do { if ((r = i / d) || n) { i -= r * d; n++; xitoa_putc('0' + r); } } while (d /= 10); } else { xitoa_putc('0'); } if (lim) dst[MIN(p, lim - 1)] = '\0'; return dst; } /* xitoa() */ static _Bool checkbool(lua_State *L, int idx) { luaL_checktype(L, idx, LUA_TBOOLEAN); return lua_toboolean(L, idx); } /* optbool() */ static _Bool optbool(lua_State *L, int idx, _Bool d) { if (lua_isnoneornil(L, idx)) return d; return checkbool(L, idx); } /* optbool() */ static void *prepudata(lua_State *L, size_t size, const char *tname, int (*gc)(lua_State *)) { void *p = memset(lua_newuserdata(L, size), 0, size); if (tname) { luaL_setmetatable(L, tname); } else { lua_newtable(L); lua_pushcfunction(L, gc); lua_setfield(L, -2, "__gc"); lua_setmetatable(L, -2); } return p; } /* prepudata() */ static void *prepsimple(lua_State *L, const char *tname, int (*gc)(lua_State *)) { void **p = prepudata(L, sizeof (void *), tname, gc); return p; } /* prepsimple() */ #define EXPAND( x ) x #define prepsimple_(a, b, c, ...) prepsimple((a), (b), (c)) #define prepsimple(...) EXPAND( prepsimple_(__VA_ARGS__, 0, 0) ) static void *checksimple(lua_State *L, int index, const char *tname) { void **p; if (tname) { p = luaL_checkudata(L, index, tname); } else { luaL_checktype(L, index, LUA_TUSERDATA); p = lua_touserdata(L, index); } return *p; } /* checksimple() */ static void *testsimple(lua_State *L, int index, const char *tname) { void **p; if (tname) { p = luaL_testudata(L, index, tname); } else { luaL_checktype(L, index, LUA_TUSERDATA); p = lua_touserdata(L, index); } return (p)? *p : (void *)0; } /* testsimple() */ static int auxL_swapmetatable(lua_State *, const char *); static int auxL_swapmetasubtable(lua_State *, const char *, const char *); static int interpose(lua_State *L, const char *mt) { if (!strncmp("__", luaL_checkstring(L, lua_absindex(L, -2)), 2)) { return auxL_swapmetatable(L, mt); } else { return auxL_swapmetasubtable(L, mt, "__index"); } } /* interpose() */ static int auxL_checkoption(lua_State *, int, const char *, const char *const *, _Bool); #define X509_ANY 0x01 #define X509_PEM 0x02 #define X509_DER 0x04 #define X509_TXT 0x08 /* "pretty" */ #define X509_ALL (X509_PEM|X509_DER) static int optencoding(lua_State *L, int index, const char *def, int allow) { static const char *const opts[] = { "*", "pem", "der", "pretty", NULL }; int type = 0; switch (auxL_checkoption(L, index, def, opts, 1)) { case 0: type = X509_ANY; break; case 1: type = X509_PEM; break; case 2: type = X509_DER; break; case 3: type = X509_TXT; break; } if (!(type & allow)) luaL_argerror(L, index, lua_pushfstring(L, "invalid option %s", luaL_checkstring(L, index))); return type; } /* optencoding() */ static _Bool rawgeti(lua_State *L, int index, int n) { lua_rawgeti(L, index, n); if (lua_isnil(L, -1)) { lua_pop(L, 1); return 0; } else { return 1; } } /* rawgeti() */ /* check ALPN protocols and add to buffer of length-prefixed strings */ static void checkprotos(luaL_Buffer *B, lua_State *L, int index) { int n; luaL_checktype(L, index, LUA_TTABLE); for (n = 1; rawgeti(L, index, n); n++) { const char *tmp; size_t len; switch (lua_type(L, -1)) { case LUA_TSTRING: break; default: luaL_argerror(L, index, "array of strings expected"); } tmp = luaL_checklstring(L, -1, &len); luaL_argcheck(L, len > 0 && len <= UCHAR_MAX, index, "proto string length invalid"); luaL_addchar(B, (unsigned char)len); luaL_addlstring(B, tmp, len); lua_pop(L, 1); } } /* checkprotos() */ static void pushprotos(lua_State *L, const unsigned char *p, size_t n) { const unsigned char *pe = &p[n]; int i = 0; lua_newtable(L); while (p < pe) { n = *p++; if ((size_t)(pe - p) < n) luaL_error(L, "corrupt ALPN protocol list (%zu > %zu)", n, (size_t)(pe - p)); lua_pushlstring(L, (const void *)p, n); lua_rawseti(L, -2, ++i); p += n; } } /* pushprotos() */ static _Bool getfield(lua_State *L, int index, const char *k) { lua_getfield(L, index, k); if (lua_isnil(L, -1)) { lua_pop(L, 1); return 0; } else { return 1; } } /* getfield() */ static _Bool (loadfield)(lua_State *L, int index, const char *k, int type, void *p, size_t *l) { if (!getfield(L, index, k)) return 0; switch (type) { case LUA_TSTRING: *(const char **)p = luaL_checklstring(L, -1, l); break; case LUA_TNUMBER: *(lua_Number *)p = luaL_checknumber(L, -1); break; default: luaL_error(L, "loadfield(type=%d): invalid type", type); break; } /* switch() */ lua_pop(L, 1); /* table keeps reference */ return 1; } /* loadfield() */ #define loadfield_(L, idx, k, type, p, l, ...) loadfield((L), (idx), (k), (type), (p), (l)) #define loadfield(...) EXPAND( loadfield_(__VA_ARGS__, NULL) ) static void *loadfield_udata(lua_State *L, int index, const char *k, const char *tname) { if (!getfield(L, index, k)) return NULL; void **p = luaL_checkudata(L, -1, tname); lua_pop(L, 1); /* table keeps reference */ return *p; } /* loadfield_udata() */ /* Forward declaration */ static void ssl_push(lua_State *, SSL *); /* * Auxiliary C routines * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define AUX_MIN(a, b) (((a) < (b))? (a) : (b)) static size_t aux_strlcpy(char *dst, const char *src, size_t lim) { size_t n = strlen(src); if (lim > 0) { size_t m = AUX_MIN(lim - 1, n); memcpy(dst, src, m); dst[m] = '\0'; } return n; } /* aux_strlcpy() */ #define aux_strerror(error) aux_strerror_r((error), (char[256]){ 0 }, 256) static const char *aux_strerror_r(int error, char *dst, size_t lim) { static const char unknown[] = "Unknown error: "; size_t n; #if _WIN32 errno_t rv = strerror_s(dst, lim, error); if (rv) return dst; #elif STRERROR_R_CHAR_P char *rv = strerror_r(error, dst, lim); if (rv != NULL) return rv; #else int rv = strerror_r(error, dst, lim); if (0 == rv) return dst; #endif /* * glibc snprintf can fail on memory pressure, so format our number * manually. */ n = MIN(sizeof unknown - 1, lim); memcpy(dst, unknown, n); return xitoa(&dst[n], lim - n, error); } /* aux_strerror_r() */ /* * Auxiliary OpenSSL API routines * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void auxS_bn_free_and_set0(BIGNUM **dst, BIGNUM *src) { if (*dst) { BN_clear_free(*dst); } *dst = src; } /* auxS_bn_free_and_set0() */ static size_t auxS_nid2sn(void *dst, size_t lim, int nid) { const char *sn; if (nid == NID_undef || !(sn = OBJ_nid2sn(nid))) return 0; return aux_strlcpy(dst, sn, lim); } /* aux2_nid2sn() */ static size_t auxS_obj2sn(void *dst, size_t lim, const ASN1_OBJECT *obj) { return auxS_nid2sn(dst, lim, OBJ_obj2nid(obj)); } /* auxS_obj2sn() */ static size_t auxS_nid2ln(void *dst, size_t lim, int nid) { const char *ln; if (nid == NID_undef || !(ln = OBJ_nid2ln(nid))) return 0; return aux_strlcpy(dst, ln, lim); } /* aux2_nid2ln() */ static size_t auxS_obj2ln(void *dst, size_t lim, const ASN1_OBJECT *obj) { return auxS_nid2ln(dst, lim, OBJ_obj2nid(obj)); } /* auxS_obj2ln() */ static size_t auxS_obj2id(void *dst, size_t lim, const ASN1_OBJECT *obj) { int n = OBJ_obj2txt(dst, AUX_MIN(lim, INT_MAX), obj, 1); /* TODO: push custom errors onto error stack */ if (n == 0) { return 0; /* obj->data == NULL */ } else if (n < 0) { return 0; /* memory allocation error */ } else { return n; } } /* auxS_obj2id() */ static size_t auxS_nid2id(void *dst, size_t lim, int nid) { ASN1_OBJECT *obj; /* TODO: push custom error onto error stack */ if (!(obj = OBJ_nid2obj(nid))) return 0; return auxS_obj2id(dst, lim, obj); } /* auxS_nid2id() */ static size_t auxS_nid2txt(void *dst, size_t lim, int nid) { size_t n; if ((n = auxS_nid2sn(dst, lim, nid))) return n; if ((n = auxS_nid2ln(dst, lim, nid))) return n; return auxS_nid2id(dst, lim, nid); } /* auxS_nid2txt() */ static size_t auxS_obj2txt(void *dst, size_t lim, const ASN1_OBJECT *obj) { size_t n; if ((n = auxS_obj2sn(dst, lim, obj))) return n; if ((n = auxS_obj2ln(dst, lim, obj))) return n; return auxS_obj2id(dst, lim, obj); } /* auxS_obj2txt() */ static const EVP_MD *auxS_todigest(const char *name, EVP_PKEY *key, const EVP_MD *def); static _Bool auxS_isoid(const char *txt) { return (*txt >= '0' && *txt <= '9'); } /* auxS_isoid() */ static _Bool auxS_txt2obj(ASN1_OBJECT **obj, const char *txt) { int nid; if ((nid = OBJ_sn2nid(txt)) != NID_undef || (nid = OBJ_ln2nid(txt)) != NID_undef) { return NULL != (*obj = OBJ_nid2obj(nid)); } else if (auxS_isoid(txt)) { return NULL != (*obj = OBJ_txt2obj(txt, 1)); } else { *obj = NULL; return 1; } } /* auxS_txt2obj() */ static _Bool auxS_txt2nid(int *nid, const char *txt) { /* try builtins first */ if ((*nid = OBJ_sn2nid(txt)) != NID_undef || (*nid = OBJ_ln2nid(txt)) != NID_undef) { return 1; } /* OBJ_txt2nid creates a temporary ASN1_OBJECT; call sparingly */ if (auxS_isoid(txt) && (*nid = OBJ_txt2nid(txt)) != NID_undef) { return 1; } return 0; } /* auxS_txt2nid() */ /* * Auxiliary Lua API routines * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ typedef int auxref_t; typedef int auxtype_t; static void auxL_unref(lua_State *L, auxref_t *ref) { luaL_unref(L, LUA_REGISTRYINDEX, *ref); *ref = LUA_NOREF; } /* auxL_unref() */ static void auxL_ref(lua_State *L, int index, auxref_t *ref) { auxL_unref(L, ref); lua_pushvalue(L, index); *ref = luaL_ref(L, LUA_REGISTRYINDEX); } /* auxL_ref() */ NOTUSED static auxtype_t auxL_getref(lua_State *L, auxref_t ref) { if (ref == LUA_NOREF || ref == LUA_REFNIL) { lua_pushnil(L); } else { lua_rawgeti(L, LUA_REGISTRYINDEX, ref); } return lua_type(L, -1); } /* auxL_getref() */ static int auxL_testoption(lua_State *L, int index, const char *def, const char *const *optlist, _Bool nocase) { const char *optname = (def)? luaL_optstring(L, index, def) : luaL_checkstring(L, index); int (*optcmp)() = (nocase)? #ifdef _WIN32 &_stricmp #else &strcasecmp #endif : &strcmp; int i; for (i = 0; optlist[i]; i++) { if (0 == optcmp(optlist[i], optname)) return i; } return -1; } /* auxL_testoption() */ static int auxL_checkoption(lua_State *L, int index, const char *def, const char *const *optlist, _Bool nocase) { int i; if ((i = auxL_testoption(L, index, def, optlist, nocase)) >= 0) return i; return luaL_argerror(L, index, lua_pushfstring(L, "invalid option '%s'", luaL_optstring(L, index, def))); } /* auxL_checkoption() */ /* * Lua 5.3 distinguishes integers and numbers, and by default uses 64-bit * integers. The following routines try to preserve this distinction and * where possible detect range issues. * * The signed range checking assumes two's complement, no padding bits, and * sizeof lua_Integer <= sizeof long long. Which is a safe bet where OpenSSL * is typically used. */ #define auxL_Integer long long #define auxL_IntegerMin LLONG_MIN #define auxL_IntegerMax LLONG_MAX #define auxL_Unsigned unsigned long long #define auxL_UnsignedMin 0 #define auxL_UnsignedMax ULLONG_MAX #define lua_IntegerMax ((1ULL << (sizeof (lua_Integer) * 8 - 1)) - 1) #define lua_IntegerMin (-lua_IntegerMax - 1) static void auxL_pushinteger(lua_State *L, auxL_Integer i) { /* * TODO: Check value explicitly, but will need to silence compiler * diagnostics about useless comparisons. */ if (sizeof (lua_Integer) >= sizeof i) { lua_pushinteger(L, i); } else { /* TODO: Check overflow. */ lua_pushnumber(L, i); } } /* auxL_pushinteger() */ static void auxL_pushunsigned(lua_State *L, auxL_Unsigned i) { if (i <= lua_IntegerMax) { lua_pushinteger(L, i); } else if (i == (auxL_Unsigned)(lua_Number)i) { lua_pushnumber(L, i); } else { luaL_error(L, "unsigned integer value not representable as lua_Integer or lua_Number"); } } /* auxL_pushunsigned() */ #define auxL_checkinteger_(a, b, c, d, ...) auxL_checkinteger((a), (b), (c), (d)) #define auxL_checkinteger(...) EXPAND( auxL_checkinteger_(__VA_ARGS__, auxL_IntegerMin, auxL_IntegerMax, 0) ) static auxL_Integer (auxL_checkinteger)(lua_State *L, int index, auxL_Integer min, auxL_Integer max) { auxL_Integer i; if (sizeof (lua_Integer) >= sizeof (auxL_Integer)) { i = luaL_checkinteger(L, index); } else { /* TODO: Check overflow. */ i = (auxL_Integer)luaL_checknumber(L, index); } if (i < min || i > max) luaL_error(L, "integer value out of range"); return i; } /* auxL_checkinteger() */ #define auxL_optinteger_(a, b, c, d, e, ...) auxL_optinteger((a), (b), (c), (d), (e)) #define auxL_optinteger(...) EXPAND( auxL_optinteger_(__VA_ARGS__, auxL_IntegerMin, auxL_IntegerMax, 0)) static auxL_Integer (auxL_optinteger)(lua_State *L, int index, auxL_Integer def, auxL_Integer min, auxL_Integer max) { return (lua_isnoneornil(L, index))? def : auxL_checkinteger(L, index, min, max); } /* auxL_optinteger() */ #define auxL_checkunsigned_(a, b, c, d, ...) auxL_checkunsigned((a), (b), (c), (d)) #define auxL_checkunsigned(...) EXPAND( auxL_checkunsigned_(__VA_ARGS__, auxL_UnsignedMin, auxL_UnsignedMax, 0)) static auxL_Unsigned (auxL_checkunsigned)(lua_State *L, int index, auxL_Unsigned min, auxL_Unsigned max) { auxL_Unsigned i; if (sizeof (lua_Integer) >= sizeof (auxL_Unsigned)) { /* TODO: Check sign. */ i = luaL_checkinteger(L, index); } else { /* TODO: Check sign and overflow. */ i = (auxL_Integer)luaL_checknumber(L, index); } if (i < min || i > max) luaL_error(L, "integer value out of range"); return i; } /* auxL_checkunsigned() */ #define auxL_optunsigned_(a, b, c, d, e, ...) auxL_optunsigned((a), (b), (c), (d), (e)) #define auxL_optunsigned(...) EXPAND( auxL_optunsigned_(__VA_ARGS__, auxL_UnsignedMin, auxL_UnsignedMax, 0) ) static auxL_Unsigned (auxL_optunsigned)(lua_State *L, int index, auxL_Unsigned def, auxL_Unsigned min, auxL_Unsigned max) { return (lua_isnoneornil(L, index))? def : auxL_checkunsigned(L, index, min, max); } /* auxL_optunsigned() */ static int auxL_size2int(lua_State *L, size_t n) { if (n > INT_MAX) luaL_error(L, "integer value out of range (%zu > INT_MAX)", n); return (int)n; } /* auxL_size2int() */ typedef struct { const char *name; auxL_Integer value; } auxL_IntegerReg; static void auxL_setintegers(lua_State *L, const auxL_IntegerReg *l) { for (; l->name; l++) { auxL_pushinteger(L, l->value); lua_setfield(L, -2, l->name); } } /* auxL_setintegers() */ #define AUXL_REG_NULL (&(auxL_Reg[]){ 0 }) typedef struct { const char *name; lua_CFunction func; unsigned nups; /* in addition to nups specified to auxL_setfuncs */ } auxL_Reg; static inline size_t auxL_liblen(const auxL_Reg *l) { size_t n = 0; while ((l++)->name) n++; return n; } /* auxL_liblen() */ #define auxL_newlibtable(L, l) \ lua_createtable((L), 0, countof((l)) - 1) #define auxL_newlib(L, l, nups) \ (auxL_newlibtable((L), (l)), lua_insert((L), -(nups + 1)), auxL_setfuncs((L), (l), (nups))) static void auxL_setfuncs(lua_State *L, const auxL_Reg *l, int nups) { for (; l->name; l++) { int i; /* copy shared upvalues */ luaL_checkstack(L, nups, "too many upvalues"); for (i = 0; i < nups; i++) lua_pushvalue(L, -nups); /* nil-fill local upvalues */ luaL_checkstack(L, l->nups, "too many upvalues"); lua_settop(L, lua_gettop(L) + l->nups); /* set closure */ luaL_checkstack(L, 1, "too many upvalues"); lua_pushcclosure(L, l->func, nups + l->nups); lua_setfield(L, -(nups + 2), l->name); } lua_pop(L, nups); return; } /* auxL_setfuncs() */ static void auxL_clear(lua_State *L, int tindex) { tindex = lua_absindex(L, tindex); lua_pushnil(L); while (lua_next(L, tindex)) { lua_pop(L, 1); lua_pushvalue(L, -1); lua_pushnil(L); lua_rawset(L, tindex); } } /* auxL_clear() */ static _Bool auxL_newmetatable(lua_State *L, const char *name, _Bool reset) { if (luaL_newmetatable(L, name)) return 1; if (!reset) return 0; /* * NB: Keep existing table as it may be cached--e.g. in * another module that isn't being reloaded. But scrub it * clean so function interposition--which will presumably * run again if the C module is being reloaded--doesn't * result in loops. */ auxL_clear(L, -1); lua_pushnil(L); lua_setmetatable(L, -2); #if LUA_VERSION_NUM >= 502 lua_pushnil(L); lua_setuservalue(L, -2); #endif return 0; } /* auxL_newmetatable() */ static _Bool auxL_newclass(lua_State *L, const char *name, const auxL_Reg *methods, const auxL_Reg *metamethods, _Bool reset) { _Bool fresh = auxL_newmetatable(L, name, reset); int n; if (!reset && !fresh) return fresh; auxL_setfuncs(L, metamethods, 0); if ((n = auxL_liblen(methods))) { lua_createtable(L, 0, auxL_size2int(L, n)); auxL_setfuncs(L, methods, 0); lua_setfield(L, -2, "__index"); } return fresh; } /* auxL_newclass() */ #define auxL_addclass(L, ...) \ EXPAND( (auxL_newclass((L), __VA_ARGS__), lua_pop((L), 1)) ) static int auxL_swaptable(lua_State *L, int index) { index = lua_absindex(L, index); lua_pushvalue(L, -2); /* push key */ lua_gettable(L, index); /* push old value */ lua_pushvalue(L, -3); /* push key */ lua_pushvalue(L, -3); /* push new value */ lua_settable(L, index); /* replace old value */ lua_replace(L, -3); lua_pop(L, 1); return 1; /* return old value */ } /* auxL_swaptable() */ static int auxL_swapmetatable(lua_State *L, const char *name) { luaL_getmetatable(L, name); lua_pushvalue(L, -3); lua_pushvalue(L, -3); auxL_swaptable(L, -3); lua_replace(L, -4); lua_pop(L, 2); return 1; } /* auxL_swapmetatable() */ static int auxL_swapmetasubtable(lua_State *L, const char *name, const char *subname) { luaL_getmetatable(L, name); lua_getfield(L, -1, subname); lua_pushvalue(L, -4); lua_pushvalue(L, -4); auxL_swaptable(L, -3); lua_replace(L, -5); lua_pop(L, 3); return 1; } /* auxL_swapmetasubtable() */ #define auxL_EDYLD -2 #define auxL_EOPENSSL -1 static const char *auxL_pusherror(lua_State *L, int error, const char *fun) { if (error == auxL_EOPENSSL) { unsigned long code; const char *path, *file; int line; char txt[256]; if (!ERR_peek_error()) return lua_pushliteral(L, "oops: no OpenSSL errors set"); #if OPENSSL_PREREQ(3,0,0) code = ERR_get_error_all(&path, &line, NULL, NULL, NULL); #else code = ERR_get_error_line(&path, &line); #endif if ((file = strrchr(path, '/'))) { ++file; } else { file = path; } ERR_clear_error(); ERR_error_string_n(code, txt, sizeof txt); if (fun) { return lua_pushfstring(L, "%s: %s:%d:%s", fun, file, line, txt); } else { return lua_pushfstring(L, "%s:%d:%s", file, line, txt); } #if HAVE_DLADDR } else if (error == auxL_EDYLD) { const char *const fmt = (fun)? "%s: %s" : "%.0s%s"; return lua_pushfstring(L, fmt, (fun)? fun : "", dlerror()); #endif } else { const char *const fmt = (fun)? "%s: %s" : "%.0s%s"; return lua_pushfstring(L, fmt, (fun)? fun : "", aux_strerror(error)); } } /* auxL_pusherror() */ static int auxL_error(lua_State *L, int error, const char *fun) { auxL_pusherror(L, error, fun); lua_error(L); NOTREACHED; return 0; } /* auxL_error() */ static const char *auxL_pushnid(lua_State *L, int nid) { char txt[256] = { 0 }; size_t n; if (!(n = auxS_nid2txt(txt, sizeof txt, nid)) || n >= sizeof txt) luaL_error(L, "%d: invalid ASN.1 NID", nid); lua_pushlstring(L, txt, n); return lua_tostring(L, -1); } /* auxL_pushnid() */ static const EVP_MD *auxL_optdigest(lua_State *L, int index, EVP_PKEY *key, const EVP_MD *def); /* * dl - dynamically loaded module management * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Prevent loader from unlinking us if we've registered a callback with * OpenSSL by taking another reference to ourselves. */ /* dl_anchor must not be called from multiple threads at once */ static int dl_anchor(void) { #if _WIN32 EXPORT extern int luaopen__openssl(lua_State *); HMODULE dummy; if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN|GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (void *)&luaopen__openssl, &dummy)) return GetLastError(); return 0; #elif HAVE_DLADDR extern int luaopen__openssl(lua_State *); static void *anchor; Dl_info info; int error = 0; if (anchor) goto epilog; if (!dladdr((void *)&luaopen__openssl, &info)) goto dlerr; if (!(anchor = dlopen(info.dli_fname, RTLD_NOW|RTLD_LOCAL))) goto dlerr; epilog: return error; dlerr: error = auxL_EDYLD; goto epilog; #else return 0;//ENOTSUP; #endif } /* dl_anchor() */ /* * compat - OpenSSL API compatibility and bug workarounds * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !HAVE_OPENSSL_ZALLOC static void *OPENSSL_zalloc(size_t num) { void *ret = OPENSSL_malloc(num); if (ret != NULL) memset(ret, 0, num); return ret; } #endif #if !HAVE_OPENSSL_CLEAR_FREE static void OPENSSL_clear_free(void *str, size_t num) { if (str == NULL) return; if (num) OPENSSL_cleanse(str, num); CRYPTO_free(str); } /* CRYPTO_clear_free() */ #endif #if !HAVE_OPENSSL_MEMDUP static void *OPENSSL_memdup(const void *data, size_t siz) { return BUF_memdup(data, siz); } /* OPENSSL_memdup() */ #endif #define COMPAT_X509_STORE_FREE_BUG 0x01 static struct { int flags; void (*X509_STORE_free)(X509_STORE *); struct { X509_STORE *store; } tmp; } compat = { .flags = 0, .X509_STORE_free = &X509_STORE_free, }; #if !HAVE_ASN1_STRING_GET0_DATA #define ASN1_STRING_get0_data(s) ASN1_STRING_data((s)) #endif #if !HAVE_DH_GET0_KEY #define DH_get0_key(...) EXPAND( compat_DH_get0_key(__VA_ARGS__) ) static void compat_DH_get0_key(const DH *d, const BIGNUM **pub_key, const BIGNUM **priv_key) { if (pub_key) *pub_key = d->pub_key; if (priv_key) *priv_key = d->priv_key; } /* compat_DH_get0_key() */ #endif #if !HAVE_DH_GET0_PQG #define DH_get0_pqg(...) EXPAND( compat_DH_get0_pqg(__VA_ARGS__) ) static void compat_DH_get0_pqg(const DH *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { if (p) *p = d->p; if (q) *q = d->q; if (g) *g = d->g; } /* compat_DH_get0_pqg() */ #endif #if !HAVE_DH_SET0_KEY #define DH_set0_key(...) EXPAND( compat_DH_set0_key(__VA_ARGS__) ) static void compat_DH_set0_key(DH *d, BIGNUM *pub_key, BIGNUM *priv_key) { if (pub_key) auxS_bn_free_and_set0(&d->pub_key, pub_key); if (priv_key) auxS_bn_free_and_set0(&d->priv_key, priv_key); } /* compat_DH_set0_key() */ #endif #if !HAVE_DH_SET0_PQG #define DH_set0_pqg(...) EXPAND( compat_DH_set0_pqg(__VA_ARGS__) ) static void compat_DH_set0_pqg(DH *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { if (p) auxS_bn_free_and_set0(&d->p, p); if (q) auxS_bn_free_and_set0(&d->q, q); if (g) auxS_bn_free_and_set0(&d->g, g); } /* compat_DH_set0_pqg() */ #endif #if !HAVE_DSA_GET0_KEY #define DSA_get0_key(...) EXPAND( compat_DSA_get0_key(__VA_ARGS__) ) static void compat_DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) { if (pub_key) *pub_key = d->pub_key; if (priv_key) *priv_key = d->priv_key; } /* compat_DSA_get0_key() */ #endif #if !HAVE_DSA_GET0_PQG #define DSA_get0_pqg(...) EXPAND( compat_DSA_get0_pqg(__VA_ARGS__) ) static void compat_DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { if (p) *p = d->p; if (q) *q = d->q; if (g) *g = d->g; } /* compat_DSA_get0_pqg() */ #endif #if !HAVE_DSA_SET0_KEY #define DSA_set0_key(...) EXPAND( compat_DSA_set0_key(__VA_ARGS__) ) static void compat_DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) { if (pub_key) auxS_bn_free_and_set0(&d->pub_key, pub_key); if (priv_key) auxS_bn_free_and_set0(&d->priv_key, priv_key); } /* compat_DSA_set0_key() */ #endif #if !HAVE_DSA_SET0_PQG #define DSA_set0_pqg(...) EXPAND( compat_DSA_set0_pqg(__VA_ARGS__) ) static void compat_DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { if (p) auxS_bn_free_and_set0(&d->p, p); if (q) auxS_bn_free_and_set0(&d->q, q); if (g) auxS_bn_free_and_set0(&d->g, g); } /* compat_DSA_set0_pqg() */ #endif #if !HAVE_EVP_CIPHER_CTX_FREE #define EVP_CIPHER_CTX_free(ctx) compat_EVP_CIPHER_CTX_free((ctx)) static void compat_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) { EVP_CIPHER_CTX_cleanup(ctx); OPENSSL_free(ctx); } /* compat_EVP_CIPHER_CTX_free() */ #endif #if !HAVE_EVP_CIPHER_CTX_NEW #define EVP_CIPHER_CTX_new() compat_EVP_CIPHER_CTX_new() static EVP_CIPHER_CTX *compat_EVP_CIPHER_CTX_new(void) { EVP_CIPHER_CTX *ctx; if (!(ctx = OPENSSL_malloc(sizeof *ctx))) return NULL; memset(ctx, 0, sizeof *ctx); EVP_CIPHER_CTX_init(ctx); return ctx; } /* compat_EVP_CIPHER_CTX_new() */ #endif #if !HAVE_EVP_MD_CTX_FREE #define EVP_MD_CTX_free(md) EVP_MD_CTX_destroy((md)) #endif #if !HAVE_EVP_MD_CTX_NEW #define EVP_MD_CTX_new() EVP_MD_CTX_create() #endif #if !HAVE_EVP_PKEY_ID #define EVP_PKEY_id(key) ((key)->type) #endif #if !HAVE_EVP_PKEY_BASE_ID #define EVP_PKEY_base_id(key) compat_EVP_PKEY_base_id((key)) static int compat_EVP_PKEY_base_id(EVP_PKEY *key) { return EVP_PKEY_type(EVP_PKEY_id(key)); } /* compat_EVP_PKEY_base_id() */ #endif #if !HAVE_EVP_PKEY_GET_DEFAULT_DIGEST_NID #define EVP_PKEY_get_default_digest_nid(...) \ EXPAND( compat_EVP_PKEY_get_default_digest_nid(__VA_ARGS__) ) static int compat_EVP_PKEY_get_default_digest_nid(EVP_PKEY *key, int *nid) { switch (EVP_PKEY_base_id(key)) { case EVP_PKEY_RSA: *nid = EVP_MD_nid(EVP_sha1()); break; case EVP_PKEY_DSA: *nid = EVP_MD_nid(EVP_dss1()); break; case EVP_PKEY_EC: *nid = EVP_MD_nid(EVP_ecdsa()); break; default: *nid = EVP_MD_nid(EVP_sha1()); break; } return 1; } /* compat_EVP_PKEY_get_default_digest_nid() */ #endif #if !HAVE_EVP_PKEY_GET0_RSA #define EVP_PKEY_get0_RSA(key) compat_EVP_PKEY_get0_RSA((key)) static RSA *compat_EVP_PKEY_get0_RSA(EVP_PKEY *key) { RSA *ptr = EVP_PKEY_get1_RSA(key); RSA_free(ptr); return ptr; } /* compat_EVP_PKEY_get0_RSA() */ #endif #if !HAVE_EVP_PKEY_GET0_DSA #define EVP_PKEY_get0_DSA(key) compat_EVP_PKEY_get0_DSA((key)) static DSA *compat_EVP_PKEY_get0_DSA(EVP_PKEY *key) { DSA *ptr = EVP_PKEY_get1_DSA(key); DSA_free(ptr); return ptr; } /* compat_EVP_PKEY_get0_DSA() */ #endif #if !HAVE_EVP_PKEY_GET0_DH #define EVP_PKEY_get0_DH(key) compat_EVP_PKEY_get0_DH((key)) static DH *compat_EVP_PKEY_get0_DH(EVP_PKEY *key) { DH *ptr = EVP_PKEY_get1_DH(key); DH_free(ptr); return ptr; } /* compat_EVP_PKEY_get0_DH() */ #endif #if !HAVE_EVP_PKEY_GET0_EC_KEY && !defined(OPENSSL_NO_EC) #define EVP_PKEY_get0_EC_KEY(key) compat_EVP_PKEY_get0_EC_KEY((key)) static EC_KEY *compat_EVP_PKEY_get0_EC_KEY(EVP_PKEY *key) { EC_KEY *ptr = EVP_PKEY_get1_EC_KEY(key); EC_KEY_free(ptr); return ptr; } /* compat_EVP_PKEY_get0_EC_KEY() */ #endif #if !HAVE_EVP_PKEY_GET0 #define EVP_PKEY_get0(key) compat_EVP_PKEY_get0((key)) static void *compat_EVP_PKEY_get0(EVP_PKEY *key) { void *ptr = NULL; switch (EVP_PKEY_base_id(key)) { case EVP_PKEY_RSA: return EVP_PKEY_get0_RSA(key); case EVP_PKEY_DSA: return EVP_PKEY_get0_DSA(key); case EVP_PKEY_DH: return EVP_PKEY_get0_DH(key); #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: return EVP_PKEY_get0_EC_KEY(key); #endif default: /* TODO: Use ERR_put_error */ break; } return ptr; } /* compat_EVP_PKEY_get0() */ #endif #if !HAVE_HMAC_CTX_FREE #define HMAC_CTX_free(ctx) compat_HMAC_CTX_free((ctx)) static void compat_HMAC_CTX_free(HMAC_CTX *ctx) { HMAC_CTX_cleanup(ctx); OPENSSL_free(ctx); } /* compat_HMAC_CTX_free() */ #endif #if !HAVE_HMAC_CTX_NEW #define HMAC_CTX_new() compat_HMAC_CTX_new() static HMAC_CTX *compat_HMAC_CTX_new(void) { HMAC_CTX *ctx; if (!(ctx = OPENSSL_malloc(sizeof *ctx))) return NULL; memset(ctx, 0, sizeof *ctx); return ctx; } /* compat_HMAC_CTX_new() */ #endif #if !HAVE_RSA_GET0_CRT_PARAMS #define RSA_get0_crt_params(...) EXPAND( compat_RSA_get0_crt_params(__VA_ARGS__) ) static void compat_RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp) { if (dmp1) *dmp1 = r->dmp1; if (dmq1) *dmq1 = r->dmq1; if (iqmp) *iqmp = r->iqmp; } /* compat_RSA_get0_crt_params() */ #endif #if !HAVE_RSA_GET0_FACTORS #define RSA_get0_factors(...) EXPAND( compat_RSA_get0_factors(__VA_ARGS__) ) static void compat_RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) { if (p) *p = r->p; if (q) *q = r->q; } /* compat_RSA_get0_factors() */ #endif #if !HAVE_RSA_GET0_KEY #define RSA_get0_key(...) EXPAND( compat_RSA_get0_key(__VA_ARGS__) ) static void compat_RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) { if (n) *n = r->n; if (e) *e = r->e; if (d) *d = r->d; } /* compat_RSA_get0_key() */ #endif #if !HAVE_RSA_SET0_CRT_PARAMS #define RSA_set0_crt_params(...) EXPAND( compat_RSA_set0_crt_params(__VA_ARGS__) ) static void compat_RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) { if (dmp1) auxS_bn_free_and_set0(&r->dmp1, dmp1); if (dmq1) auxS_bn_free_and_set0(&r->dmq1, dmq1); if (iqmp) auxS_bn_free_and_set0(&r->iqmp, iqmp); } /* compat_RSA_set0_crt_params() */ #endif #if !HAVE_RSA_SET0_FACTORS #define RSA_set0_factors(...) EXPAND( compat_RSA_set0_factors(__VA_ARGS__) ) static void compat_RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) { if (p) auxS_bn_free_and_set0(&r->p, p); if (q) auxS_bn_free_and_set0(&r->q, q); } /* compat_RSA_set0_factors() */ #endif #if !HAVE_RSA_SET0_KEY #define RSA_set0_key(...) EXPAND( compat_RSA_set0_key(__VA_ARGS__) ) static void compat_RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { if (n) auxS_bn_free_and_set0(&r->n, n); if (e) auxS_bn_free_and_set0(&r->e, e); if (d) auxS_bn_free_and_set0(&r->d, d); } /* compat_RSA_set0_key() */ #endif #if !HAVE_SSL_GET_CLIENT_RANDOM #define SSL_get_client_random(...) EXPAND( compat_SSL_get_client_random(__VA_ARGS__) ) static size_t compat_SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen) { if (outlen == 0) return sizeof(ssl->s3->client_random); if (outlen > sizeof(ssl->s3->client_random)) outlen = sizeof(ssl->s3->client_random); memcpy(out, ssl->s3->client_random, outlen); return outlen; } #endif #if !HAVE_SSL_SESSION_MASTER_KEY #define SSL_SESSION_get_master_key(...) EXPAND( compat_SSL_SESSION_get_master_key(__VA_ARGS__) ) static size_t compat_SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *out, size_t outlen) { if (session->master_key_length < 0) { /* Should never happen */ return 0; } if (outlen == 0) return session->master_key_length; if (outlen > (size_t)session->master_key_length) outlen = session->master_key_length; memcpy(out, session->master_key, outlen); return outlen; } #endif #if !HAVE_SSL_CLIENT_VERSION #define SSL_client_version(...) EXPAND( compat_SSL_client_version(__VA_ARGS__) ) static int compat_SSL_client_version(const SSL *ssl) { return ssl->client_version; } /* compat_SSL_client_version() */ #endif #if !HAVE_SSL_GET0_PARAM #define SSL_get0_param(ssl) compat_SSL_get0_param((ssl)) static X509_VERIFY_PARAM *compat_SSL_get0_param(SSL *ssl) { return ssl->param; } /* compat_SSL_get0_param() */ #endif #if !HAVE_SSL_SET1_PARAM #define SSL_set1_param(ssl, vpm) compat_SSL_set1_param((ssl), (vpm)) static int compat_SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm) { return X509_VERIFY_PARAM_set1(ssl->param, vpm); } /* compat_SSL_set1_param() */ #endif #if !HAVE_SSL_UP_REF #define SSL_up_ref(...) EXPAND( compat_SSL_up_ref(__VA_ARGS__) ) static int compat_SSL_up_ref(SSL *ssl) { /* our caller should already have had a proper reference */ if (CRYPTO_add(&ssl->references, 1, CRYPTO_LOCK_SSL) < 2) return 0; /* fail */ return 1; } /* compat_SSL_up_ref() */ #endif #if !HAVE_SSL_OP_NO_SSL_MASK /* SSL_OP_NO_SSL_MASK was introduced in 1.0.2 1.0.1 had up to TLSv1_2 0.9.8-1.0.0 had up to TLSv1 */ #ifdef SSL_OP_NO_TLSv1_2 #define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2) #else #define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1) #endif #endif #if !HAVE_SSL_OP_NO_DTLS_MASK && HAVE_DTLS_CLIENT_METHOD #define SSL_OP_NO_DTLS_MASK (SSL_OP_NO_DTLSv1|SSL_OP_NO_DTLSv1_2) #endif #if !HAVE_SSL_CTX_GET0_PARAM #define SSL_CTX_get0_param(ctx) compat_SSL_CTX_get0_param((ctx)) static X509_VERIFY_PARAM *compat_SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; } /* compat_SSL_CTX_get0_param() */ #endif #if !HAVE_SSL_CTX_SET1_PARAM #define SSL_CTX_set1_param(ctx, vpm) compat_SSL_CTX_set1_param((ctx), (vpm)) static int compat_SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) { return X509_VERIFY_PARAM_set1(ctx->param, vpm); } /* compat_SSL_CTX_set1_param() */ #endif #if !HAVE_SSL_CTX_UP_REF #define SSL_CTX_up_ref(...) EXPAND( compat_SSL_CTX_up_ref(__VA_ARGS__) ) static int compat_SSL_CTX_up_ref(SSL_CTX *ctx) { /* our caller should already have had a proper reference */ if (CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX) < 2) return 0; /* fail */ return 1; } /* compat_SSL_CTX_up_ref() */ #endif #if !HAVE_STACK_OPENSSL_STRING_FUNCS #define sk_OPENSSL_STRING_num(s) sk_num(s) #define sk_OPENSSL_STRING_value(s, i) sk_value((s), (i)) #define sk_OPENSSL_STRING_free(s) X509_email_free(s) #endif #if !HAVE_X509_GET0_EXT #define X509_get0_ext(crt, i) X509_get_ext((crt), (i)) #endif #if !HAVE_X509_GET_SIGNATURE_NID #define X509_get_signature_nid(crt) OBJ_obj2nid((crt)->sig_alg->algorithm) #endif #if !HAVE_X509_CRL_GET0_EXT #define X509_CRL_get0_ext(crt, i) X509_CRL_get_ext((crt), (i)) #endif #if !HAVE_X509_CRL_GET0_LASTUPDATE #define X509_CRL_get0_lastUpdate(crl) ((const ASN1_TIME*)X509_CRL_get_lastUpdate(crl)) #endif #if !HAVE_X509_CRL_GET0_NEXTUPDATE #define X509_CRL_get0_nextUpdate(crl) ((const ASN1_TIME*)X509_CRL_get_nextUpdate(crl)) #endif #if !HAVE_X509_CRL_SET1_LASTUPDATE #define X509_CRL_set1_lastUpdate(crl, s) X509_CRL_set_lastUpdate((crl), (ASN1_TIME*)(s)) #endif #if !HAVE_X509_CRL_SET1_NEXTUPDATE #define X509_CRL_set1_nextUpdate(crl, s) X509_CRL_set_nextUpdate((crl), (ASN1_TIME*)(s)) #endif #if !HAVE_X509_EXTENSION_GET0_OBJECT #define X509_EXTENSION_get0_object(ext) X509_EXTENSION_get_object((ext)) #endif #if !HAVE_X509_EXTENSION_GET0_DATA #define X509_EXTENSION_get0_data(ext) X509_EXTENSION_get_data((ext)) #endif #if HAVE_X509_STORE_REFERENCES /* * X509_STORE_free in OpenSSL versions < 1.0.2 doesn't obey reference count */ #define X509_STORE_free(store) \ (compat.X509_STORE_free)((store)) /* to support preprocessor detection below */ #define compat_X509_STORE_free(store) \ compat_X509_STORE_free((store)) static void (compat_X509_STORE_free)(X509_STORE *store) { int i; i = CRYPTO_add(&store->references, -1, CRYPTO_LOCK_X509_STORE); if (i > 0) return; (X509_STORE_free)(store); } /* compat_X509_STORE_free() */ #endif #if !HAVE_SSL_CTX_SET1_CERT_STORE #define SSL_CTX_set1_cert_store(ctx, store) \ compat_SSL_CTX_set1_cert_store((ctx), (store)) static void (compat_SSL_CTX_set1_cert_store)(SSL_CTX *ctx, X509_STORE *store) { #if !HAVE_SSL_CTX_CERT_STORE || !HAVE_X509_STORE_REFERENCES if (store != NULL) X509_STORE_up_ref(store); SSL_CTX_set_cert_store(ctx, store); #else int n; /* * This isn't thead-safe, but using X509_STORE or SSL_CTX objects * from different threads isn't safe generally. */ if (ctx->cert_store) { X509_STORE_free(ctx->cert_store); ctx->cert_store = NULL; } n = store->references; SSL_CTX_set_cert_store(ctx, store); if (n == store->references) CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); #endif } /* compat_SSL_CTX_set1_cert_store() */ #endif #if HAVE_SSL_CTX_CERT_STORE static void compat_init_SSL_CTX_onfree(void *_ctx, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { SSL_CTX *ctx = _ctx; if (ctx->cert_store) { X509_STORE_free(ctx->cert_store); ctx->cert_store = NULL; } } /* compat_init_SSL_CTX_onfree() */ #endif #if defined compat_X509_STORE_free /* helper routine to determine if X509_STORE_free obeys reference count */ static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { /* unfortunately there's no way to remove a handler */ if (store != compat.tmp.store) return; /* signal that we were freed by nulling our reference */ compat.tmp.store = NULL; } /* compat_init_X509_STORE_onfree() */ #endif #if !HAVE_X509_STORE_UP_REF #define X509_STORE_up_ref(...) EXPAND( compat_X509_STORE_up_ref(__VA_ARGS__) ) static int compat_X509_STORE_up_ref(X509_STORE *crt) { /* our caller should already have had a proper reference */ if (CRYPTO_add(&crt->references, 1, CRYPTO_LOCK_X509_STORE) < 2) return 0; /* fail */ return 1; } /* compat_X509_STORE_up_ref() */ #endif #if !HAVE_X509_UP_REF #define X509_up_ref(...) EXPAND( compat_X509_up_ref(__VA_ARGS__) ) static int compat_X509_up_ref(X509 *crt) { /* our caller should already have had a proper reference */ if (CRYPTO_add(&crt->references, 1, CRYPTO_LOCK_X509) < 2) return 0; /* fail */ return 1; } /* compat_X509_up_ref() */ #endif #if !HAVE_X509_CHAIN_UP_REF /* * NB: this operation dups the chain (but not the certificates within it) */ #define X509_chain_up_ref(...) EXPAND( compat_X509_chain_up_ref(__VA_ARGS__) ) STACK_OF(X509) *compat_X509_chain_up_ref(STACK_OF(X509) *chain) { STACK_OF(X509) *ret; int i; ret = sk_X509_dup(chain); for (i = 0; i < sk_X509_num(ret); i++) { X509 *x = sk_X509_value(ret, i); X509_up_ref(x); } return ret; } /* compat_X509_chain_up_ref() */ #endif #if !HAVE_X509_VERIFY_PARAM_SET1_EMAIL /* * NB: Cannot emulate. Requires dereferencing X509_VERIFY_PARAM_ID objects, * which were always opaque. */ #endif #if !HAVE_X509_VERIFY_PARAM_SET1_HOST /* * NB: See HAVE_X509_VERIFY_PARAM_SET1_EMAIL. */ #endif #if !HAVE_EVP_KDF_CTX /* * Emulate EVP_KDF_CTX API (introduced in OpenSSL 3.0.0) */ #ifndef ERR_LIB_KDF #define ERR_LIB_KDF 0 #endif #ifndef KDFerr #define KDFerr(f,r) ERR_PUT_error(ERR_LIB_KDF,f,(r),__FILE__,__LINE__) #endif #ifndef EVP_F_EVP_KDF_CTRL #define EVP_F_EVP_KDF_CTRL 0 #endif #ifndef EVP_F_EVP_KDF_CTX_NEW_ID #define EVP_F_EVP_KDF_CTX_NEW_ID 0 #endif #ifndef EVP_R_UNSUPPORTED_ALGORITHM #define EVP_R_UNSUPPORTED_ALGORITHM EVP_R_UNKNOWN_OPTION #endif #ifndef EVP_R_COMMAND_NOT_SUPPORTED #define EVP_R_COMMAND_NOT_SUPPORTED EVP_R_UNKNOWN_OPTION #endif typedef struct { int nid; union { #if HAVE_PKCS5_PBKDF2_HMAC /* Arguments for PKCS5_PBKDF2_HMAC */ struct { unsigned char *pass; size_t passlen; unsigned char *salt; size_t saltlen; int iter; const EVP_MD *md; } pbkdf2; #endif #if HAVE_SCRYPT /* Arguments for EVP_PBE_scrypt */ struct { unsigned char *pass; size_t passlen; unsigned char *salt; size_t saltlen; uint64_t N; uint32_t r; uint32_t p; uint64_t maxmem_bytes; } scrypt; #endif #if HAVE_EVP_PKEY_CTX_KDF EVP_PKEY_CTX *pctx; #endif }; } EVP_KDF_CTX; static void EVP_KDF_CTX_free(EVP_KDF_CTX *kctx) { if (kctx == NULL) return; switch(kctx->nid) { #if HAVE_PKCS5_PBKDF2_HMAC case NID_id_pbkdf2: OPENSSL_clear_free(kctx->pbkdf2.pass, kctx->pbkdf2.passlen); OPENSSL_clear_free(kctx->pbkdf2.salt, kctx->pbkdf2.saltlen); break; #endif #if HAVE_SCRYPT case NID_id_scrypt: OPENSSL_clear_free(kctx->scrypt.pass, kctx->scrypt.passlen); OPENSSL_clear_free(kctx->scrypt.salt, kctx->scrypt.saltlen); break; #endif #if HAVE_EVP_PKEY_CTX_KDF case NID_tls1_prf: case NID_hkdf: EVP_PKEY_CTX_free(kctx->pctx); break; #endif } OPENSSL_free(kctx); } /* EVP_KDF_CTX_free() */ typedef int LUAOSSL_EVP_KDF_PTR; #define LUAOSSL_EVP_KDF_UNDEF NID_undef static LUAOSSL_EVP_KDF_PTR EVP_KDF_fetch(void *libctx, const char *algorithm, const char *properties) { LUAOSSL_EVP_KDF_PTR kdf; (void)libctx; (void)properties; if(!auxS_txt2nid(&kdf,algorithm)) { return LUAOSSL_EVP_KDF_UNDEF; } return kdf; } static EVP_KDF_CTX *EVP_KDF_CTX_new(LUAOSSL_EVP_KDF_PTR kdf) { EVP_KDF_CTX *ret; ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { EVPerr(EVP_F_EVP_KDF_CTX_NEW_ID, ERR_R_MALLOC_FAILURE); return NULL; } ret->nid = kdf; switch(kdf) { #if HAVE_PKCS5_PBKDF2_HMAC case NID_id_pbkdf2: break; #endif #if HAVE_SCRYPT case NID_id_scrypt: break; #endif #if HAVE_EVP_PKEY_CTX_KDF case NID_tls1_prf: case NID_hkdf: { ret->pctx = EVP_PKEY_CTX_new_id(kdf, NULL); if (!ret->pctx) { OPENSSL_free(ret); return NULL; } if (EVP_PKEY_derive_init(ret->pctx) <= 0) { EVP_KDF_CTX_free(ret); return NULL; } break; } break; #endif default: OPENSSL_free(ret); EVPerr(EVP_F_EVP_KDF_CTX_NEW_ID, EVP_R_UNSUPPORTED_ALGORITHM); return NULL; } return ret; } /* EVP_KDF_CTX_new() */ static int set_membuf(unsigned char **buffer, size_t *buflen, const unsigned char *new_buffer, size_t new_buflen) { if (new_buffer == NULL) return 1; OPENSSL_clear_free(*buffer, *buflen); if (new_buflen > 0) { *buffer = OPENSSL_memdup(new_buffer, new_buflen); } else { *buffer = OPENSSL_malloc(1); } if (*buffer == NULL) { KDFerr(EVP_F_EVP_KDF_CTRL, ERR_R_MALLOC_FAILURE); return 0; } *buflen = new_buflen; return 1; } #define EVP_KDF_CTRL_SET_PASS 0x01 /* unsigned char *, size_t */ #define EVP_KDF_CTRL_SET_SALT 0x02 /* unsigned char *, size_t */ #define EVP_KDF_CTRL_SET_ITER 0x03 /* int */ #define EVP_KDF_CTRL_SET_MD 0x04 /* EVP_MD * */ #define EVP_KDF_CTRL_SET_KEY 0x05 /* unsigned char *, size_t */ #define EVP_KDF_CTRL_SET_MAXMEM_BYTES 0x06 /* uint64_t */ #define EVP_KDF_CTRL_SET_TLS_SECRET 0x07 /* unsigned char *, size_t */ #define EVP_KDF_CTRL_RESET_TLS_SEED 0x08 #define EVP_KDF_CTRL_ADD_TLS_SEED 0x09 /* unsigned char *, size_t */ #define EVP_KDF_CTRL_RESET_HKDF_INFO 0x0a #define EVP_KDF_CTRL_ADD_HKDF_INFO 0x0b /* unsigned char *, size_t */ #define EVP_KDF_CTRL_SET_HKDF_MODE 0x0c /* int */ #define EVP_KDF_CTRL_SET_SCRYPT_N 0x0d /* uint64_t */ #define EVP_KDF_CTRL_SET_SCRYPT_R 0x0e /* uint32_t */ #define EVP_KDF_CTRL_SET_SCRYPT_P 0x0f /* uint32_t */ #ifdef EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND #define EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND #elif HAVE_EVP_PKEY_CTX_KDF #define EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND 0 #endif #ifdef EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY #define EVP_KDF_HKDF_MODE_EXTRACT_ONLY EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY #endif #ifdef EVP_PKEY_HKDEF_MODE_EXPAND_ONLY #define EVP_KDF_HKDF_MODE_EXPAND_ONLY EVP_PKEY_HKDEF_MODE_EXPAND_ONLY #endif static int EVP_KDF_vctrl(EVP_KDF_CTX *kctx, int cmd, va_list args) { const EVP_MD *md; const unsigned char *p; size_t len; uint64_t u64_value; uint32_t value; int iter, mode; if (kctx == NULL) return 0; switch (kctx->nid) { #if HAVE_PKCS5_PBKDF2_HMAC case NID_id_pbkdf2: { switch (cmd) { case EVP_KDF_CTRL_SET_PASS: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return set_membuf(&kctx->pbkdf2.pass, &(kctx->pbkdf2.passlen), p, len); case EVP_KDF_CTRL_SET_SALT: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return set_membuf(&kctx->pbkdf2.salt, &kctx->pbkdf2.saltlen, p, len); case EVP_KDF_CTRL_SET_ITER: iter = va_arg(args, int); if (iter < 1) return 0; kctx->pbkdf2.iter = iter; return 1; case EVP_KDF_CTRL_SET_MD: md = va_arg(args, const EVP_MD *); if (md == NULL) return 0; kctx->pbkdf2.md = md; return 1; default: EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); return -2; } } #endif #if HAVE_SCRYPT case NID_id_scrypt: { switch (cmd) { case EVP_KDF_CTRL_SET_PASS: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return set_membuf(&kctx->scrypt.pass, &kctx->scrypt.passlen, p, len); case EVP_KDF_CTRL_SET_SALT: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return set_membuf(&kctx->scrypt.salt, &kctx->scrypt.saltlen, p, len); case EVP_KDF_CTRL_SET_SCRYPT_N: u64_value = va_arg(args, uint64_t); if ((u64_value <= 1) || ((u64_value & (u64_value - 1)) != 0)) /* is_power_of_two check */ return 0; kctx->scrypt.N = u64_value; return 1; case EVP_KDF_CTRL_SET_SCRYPT_R: value = va_arg(args, uint32_t); if (value < 1) return 0; kctx->scrypt.r = value; return 1; case EVP_KDF_CTRL_SET_SCRYPT_P: value = va_arg(args, uint32_t); if (value < 1) return 0; kctx->scrypt.p = value; return 1; case EVP_KDF_CTRL_SET_MAXMEM_BYTES: u64_value = va_arg(args, uint64_t); if (u64_value < 1) return 0; kctx->scrypt.maxmem_bytes = u64_value; return 1; default: EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); return -2; } } #endif #if HAVE_EVP_PKEY_CTX_KDF case NID_tls1_prf: { switch (cmd) { case EVP_KDF_CTRL_SET_MD: md = va_arg(args, const EVP_MD *); return EVP_PKEY_CTX_set_tls1_prf_md(kctx->pctx, md); case EVP_KDF_CTRL_SET_TLS_SECRET: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); /* XXX: the old api resets the seed when you set the secret. When * using this compat routine, make sure you set the secret before * the seed. * https://github.com/openssl/openssl/issues/7728 */ return EVP_PKEY_CTX_set1_tls1_prf_secret(kctx->pctx, p, len); case EVP_KDF_CTRL_ADD_TLS_SEED: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return EVP_PKEY_CTX_add1_tls1_prf_seed(kctx->pctx, p, len); default: EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); return -2; } } case NID_hkdf: { switch (cmd) { case EVP_KDF_CTRL_SET_SALT: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return EVP_PKEY_CTX_set1_hkdf_salt(kctx->pctx, p, len); case EVP_KDF_CTRL_SET_MD: md = va_arg(args, const EVP_MD *); return EVP_PKEY_CTX_set_hkdf_md(kctx->pctx, md); case EVP_KDF_CTRL_SET_KEY: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return EVP_PKEY_CTX_set1_hkdf_key(kctx->pctx, p, len); case EVP_KDF_CTRL_ADD_HKDF_INFO: p = va_arg(args, const unsigned char *); len = va_arg(args, size_t); return EVP_PKEY_CTX_add1_hkdf_info(kctx->pctx, p, len); case EVP_KDF_CTRL_SET_HKDF_MODE: mode = va_arg(args, int); #if HAVE_EVP_PKEY_CTX_HKDF_MODE return EVP_PKEY_CTX_hkdf_mode(kctx->pctx, mode); #else if (mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND) return 1; else /* XXX: OpenSSL doesn't set an error here */ return 0; #endif default: EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); return -2; } } #endif default: (void)cmd; (void)args; return 0; } } /* EVP_KDF_vctrl() */ static int EVP_KDF_ctrl(EVP_KDF_CTX *kctx, int cmd, ...) { int ret; va_list args; va_start(args, cmd); ret = EVP_KDF_vctrl(kctx, cmd, args); va_end(args); if (ret == -2) EVPerr(EVP_F_EVP_KDF_CTRL, EVP_R_COMMAND_NOT_SUPPORTED); return ret; } /* EVP_KDF_ctrl() */ static size_t EVP_KDF_CTX_get_kdf_size(EVP_KDF_CTX *kctx) { if (kctx == NULL) return 0; switch(kctx->nid) { #if HAVE_EVP_PKEY_CTX_KDF case NID_tls1_prf: case NID_hkdf: { size_t outlen = 0; EVP_PKEY_derive(kctx->pctx, NULL, &outlen); return outlen; } #endif default: return SIZE_MAX; } } /* EVP_KDF_CTX_get_kdf_size() */ static int EVP_KDF_derive(EVP_KDF_CTX *kctx, unsigned char *out, size_t outlen, void *params) { switch(kctx->nid) { #if HAVE_PKCS5_PBKDF2_HMAC case NID_id_pbkdf2: return PKCS5_PBKDF2_HMAC((const char*)kctx->pbkdf2.pass, kctx->pbkdf2.passlen, kctx->pbkdf2.salt, kctx->pbkdf2.saltlen, kctx->pbkdf2.iter, kctx->pbkdf2.md, outlen, out); #endif #if HAVE_SCRYPT case NID_id_scrypt: return EVP_PBE_scrypt((const char*)kctx->scrypt.pass, kctx->scrypt.passlen, kctx->scrypt.salt, kctx->scrypt.saltlen, kctx->scrypt.N, kctx->scrypt.r, kctx->scrypt.p, kctx->scrypt.maxmem_bytes, out, outlen); #endif #if HAVE_EVP_PKEY_CTX_KDF case NID_tls1_prf: case NID_hkdf: return EVP_PKEY_derive(kctx->pctx, out, &outlen); #endif default: (void)out; (void)outlen; (void)params; return 0; } } /* EVP_KDF_derive() */ #else typedef EVP_KDF *LUAOSSL_EVP_KDF_PTR; #define LUAOSSL_EVP_KDF_UNDEF NULL #endif /* compat_init must not be called from multiple threads at once */ static int compat_init(void) { static int store_index = -1, ssl_ctx_index = -1, done; int error = 0; if (done) goto epilog; #if defined compat_X509_STORE_free /* * We need to unconditionally install at least one external * application data callback. Because these can never be * uninstalled, we can never be unloaded. */ if ((error = dl_anchor())) goto epilog; /* * Test if X509_STORE_free obeys reference counts by installing an * onfree callback. */ if (store_index == -1 && -1 == (store_index = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, 0, NULL, NULL, NULL, &compat_init_X509_STORE_onfree))) goto sslerr; if (!(compat.tmp.store = X509_STORE_new())) goto sslerr; CRYPTO_add(&compat.tmp.store->references, 1, CRYPTO_LOCK_X509_STORE); X509_STORE_free(compat.tmp.store); if (compat.tmp.store) { /* * Because our onfree callback didn't execute, we assume * X509_STORE_free obeys reference counts. Alternatively, * our callback might not have executed for some other * reason. We assert the truth of our assumption by checking * again after calling X509_STORE_free once more. */ X509_STORE_free(compat.tmp.store); assert(compat.tmp.store == NULL); compat.tmp.store = NULL; /* in case assertions disabled */ } else { /* * Because our onfree callback was invoked, X509_STORE_free * appears not to obey reference counts. Use our fixed * version in our own code. */ compat.X509_STORE_free = &compat_X509_STORE_free; /* * Ensure that our fixed version is called on SSL_CTX * destruction. * * NB: We depend on the coincidental order of operations in * SSL_CTX_free that user data destruction occurs before * free'ing the cert_store member. Ruby's OpenSSL bindings * also depend on this order as we both use the onfree * callback to clear the member. */ if (ssl_ctx_index == -1 && -1 == (ssl_ctx_index = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, 0, NULL, NULL, NULL, &compat_init_SSL_CTX_onfree))) goto sslerr; compat.flags |= COMPAT_X509_STORE_FREE_BUG; } #endif done = 1; epilog: if (compat.tmp.store) { X509_STORE_free(compat.tmp.store); compat.tmp.store = NULL; } return error; sslerr: error = auxL_EOPENSSL; goto epilog; } /* compat_init() */ /* * Auxiliary OpenSSL API routines (with dependencies on OpenSSL compat) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static const EVP_MD *auxS_todigest(const char *name, EVP_PKEY *key, const EVP_MD *def) { const EVP_MD *md; int nid; if (name) { if ((md = EVP_get_digestbyname(name))) return md; } else if (key) { if ((EVP_PKEY_get_default_digest_nid(key, &nid) > 0)) { if ((md = EVP_get_digestbynid(nid))) return md; } } return def; } /* auxS_todigest() */ /* * Auxiliary Lua API routines (with dependencies on OpenSSL compat) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static const EVP_MD *auxL_optdigest(lua_State *L, int index, EVP_PKEY *key, const EVP_MD *def) { const char *name = luaL_optstring(L, index, NULL); const EVP_MD *md; if ((md = auxS_todigest(name, key, NULL))) return md; if (name) { luaL_argerror(L, index, lua_pushfstring(L, "invalid digest type (%s)", name)); NOTREACHED; } else if (key) { luaL_argerror(L, index, lua_pushfstring(L, "no digest type for key type (%d)", EVP_PKEY_base_id(key))); NOTREACHED; } return def; } /* auxL_optdigest() */ /* * External Application Data Hooks * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct ex_state { lua_State *L; LIST_HEAD(, ex_data) data; }; /* struct ex_state */ #ifndef EX_DATA_MAXARGS #define EX_DATA_MAXARGS 8 #endif struct ex_data { struct ex_state *state; int refs; auxref_t arg[EX_DATA_MAXARGS]; LIST_ENTRY(ex_data) le; }; /* struct ex_data */ enum { EX_SSL_CTX_ALPN_SELECT_CB, EX_SSL_CTX_TLSEXT_SERVERNAME_CB, EX_SSL_CTX_CUSTOM_EXTENSION_ADD_CB, EX_SSL_CTX_CUSTOM_EXTENSION_PARSE_CB, }; static struct ex_type { int class_index; /* OpenSSL object type identifier */ int index; /* OpenSSL-allocated external data identifier */ void *(*get_ex_data)(); int (*set_ex_data)(); } ex_type[] = { [EX_SSL_CTX_ALPN_SELECT_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, [EX_SSL_CTX_TLSEXT_SERVERNAME_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, [EX_SSL_CTX_CUSTOM_EXTENSION_ADD_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, [EX_SSL_CTX_CUSTOM_EXTENSION_PARSE_CB] = { CRYPTO_EX_INDEX_SSL_CTX, -1, &SSL_CTX_get_ex_data, &SSL_CTX_set_ex_data }, }; #if OPENSSL_PREREQ(1,1,0) typedef const CRYPTO_EX_DATA const_CRYPTO_EX_DATA; #else typedef CRYPTO_EX_DATA const_CRYPTO_EX_DATA; #endif #if OPENSSL_PREREQ(3,0,0) /* the function signature was fixed in version 3.0.0 */ static int ex_ondup(CRYPTO_EX_DATA *to NOTUSED, const_CRYPTO_EX_DATA *from NOTUSED, void **from_d, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { #else static int ex_ondup(CRYPTO_EX_DATA *to NOTUSED, const_CRYPTO_EX_DATA *from NOTUSED, void *from_d, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { #endif struct ex_data **data = (struct ex_data **)from_d; if (*data) (*data)->refs++; return 1; } /* ex_ondup() */ static void ex_onfree(void *parent NOTUSED, void *_data, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { struct ex_data *data = _data; if (!data || --data->refs > 0) return; if (data->state) { int i; for (i = 0; i < (int)countof(data->arg); i++) { auxL_unref(data->state->L, &data->arg[i]); } LIST_REMOVE(data, le); } free(data); } /* ex_onfree() */ /* ex_init must not be called from multiple threads at once */ static int ex_init(void) { static int done; struct ex_type *type; int error = 0; if (done) goto epilog; /* * Our callbacks can never be uninstalled, so ensure we're never * unloaded. */ if ((error = dl_anchor())) goto epilog; for (type = ex_type; type < endof(ex_type); type++) { if (type->index != -1) continue; if (-1 == (type->index = CRYPTO_get_ex_new_index(type->class_index, 0, NULL, NULL, &ex_ondup, &ex_onfree))) goto sslerr; }; done = 1; epilog: return error; sslerr: error = auxL_EOPENSSL; goto epilog; } /* ex_init() */ static int ex__gc(lua_State *L) { struct ex_state *state = lua_touserdata(L, 1); struct ex_data *data; if (!state) return 0; /* invalidate back references to Lua state */ for (data = LIST_FIRST(&state->data); data; data = LIST_NEXT(data, le)) { data->state = NULL; } return 0; } /* ex__gc() */ static _Bool ex_hasstate(lua_State *L) { _Bool has; lua_pushlightuserdata(L, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&ex__gc)); lua_gettable(L, LUA_REGISTRYINDEX); has = !lua_isnil(L, -1); lua_pop(L, 1); return has; } /* ex_hasstate() */ static void ex_newstate(lua_State *L) { struct ex_state *state; struct lua_State *thr; if (ex_hasstate(L)) return; state = prepudata(L, sizeof *state, NULL, &ex__gc); LIST_INIT(&state->data); /* * XXX: Don't reuse mainthread because if an error occurs in a * callback Lua might longjmp across the OpenSSL call stack. * Instead, we'll install our own panic handlers. */ #if defined LUA_RIDX_MAINTHREAD (void)thr; lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); state->L = lua_tothread(L, -1); lua_pop(L, 1); #else lua_pushvalue(L, -1); thr = lua_newthread(L); lua_settable(L, LUA_REGISTRYINDEX); state->L = thr; #endif lua_pushlightuserdata(L, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&ex__gc)); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); lua_pop(L, 1); } /* ex_newstate() */ static struct ex_state *ex_getstate(lua_State *L) { struct ex_state *state; lua_pushlightuserdata(L, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&ex__gc)); lua_gettable(L, LUA_REGISTRYINDEX); luaL_checktype(L, -1, LUA_TUSERDATA); state = lua_touserdata(L, -1); lua_pop(L, 1); return state; } /* ex_getstate() */ static size_t ex_getdata(lua_State **L, int _type, void *obj) { struct ex_type *type = &ex_type[_type]; struct ex_data *data; size_t i; if (!(data = type->get_ex_data(obj, type->index))) return 0; if (!data->state) return 0; if (!*L) *L = data->state->L; if (!lua_checkstack(*L, countof(data->arg))) return 0; for (i = 0; i < countof(data->arg) && data->arg[i] != LUA_NOREF; i++) { lua_rawgeti(*L, LUA_REGISTRYINDEX, data->arg[i]); } return i; } /* ex_getdata() */ /* returns 0 on success, otherwise error (>0 == errno, -1 == OpenSSL error) */ static int ex_setdata(lua_State *L, int _type, void *obj, size_t n) { struct ex_type *type = &ex_type[_type]; struct ex_state *state; struct ex_data *data; size_t i, j; if (n > countof(data->arg)) return EOVERFLOW; if ((data = type->get_ex_data(obj, type->index)) && data->state) { for (i = 0; i < countof(data->arg); i++) { auxL_unref(L, &data->arg[i]); } } else { state = ex_getstate(L); if (!(data = malloc(sizeof *data))) return errno; if (!type->set_ex_data(obj, type->index, data)) return auxL_EOPENSSL; data->state = state; data->refs = 1; for (i = 0; i < countof(data->arg); i++) data->arg[i] = LUA_NOREF; LIST_INSERT_HEAD(&state->data, data, le); } for (i = n, j = 0; i > 0 && j < countof(data->arg); i--, j++) { auxL_ref(L, -(int)i, &data->arg[j]); } lua_pop(L, n); return 0; } /* ex_setdata() */ static void initall(lua_State *L); /* * compat - Lua OpenSSL * * Bindings to our internal feature detection, compatability, and workaround * code. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ EXPORT int luaopen__openssl_compat(lua_State *L) { initall(L); lua_newtable(L); lua_pushboolean(L, !!(compat.flags & COMPAT_X509_STORE_FREE_BUG)); lua_setfield(L, -2, "X509_STORE_FREE_BUG"); return 1; } /* luaopen__openssl_compat() */ /* * OPENSSL - openssl * * Miscellaneous global interfaces. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int ossl_version(lua_State *L) { if (lua_isnoneornil(L, 1)) { auxL_pushunsigned(L, SSLeay()); } else { lua_pushstring(L, SSLeay_version(auxL_checkinteger(L, 1, INT_MIN, INT_MAX))); } return 1; } /* ossl_version() */ #if HAVE_SSL_EXTENSION_SUPPORTED static int ossl_extensionSupported(lua_State *L) { unsigned int ext_type = auxL_checkunsigned(L, 1); lua_pushboolean(L, SSL_extension_supported(ext_type)); return 1; } /* ossl_extensionSupported() */ #endif static const auxL_Reg ossl_globals[] = { { "version", &ossl_version }, #if HAVE_SSL_EXTENSION_SUPPORTED { "extensionSupported", &ossl_extensionSupported }, #endif { NULL, NULL }, }; /* * NOTE: Compile-time cipher exclusions from openssl-1.0.1i/util/mkdef.pl. */ static const char opensslconf_no[][20] = { #ifdef OPENSSL_NO_RC2 { "NO_RC2" }, #endif #ifdef OPENSSL_NO_RC4 { "NO_RC4" }, #endif #ifdef OPENSSL_NO_RC5 { "NO_RC5" }, #endif #ifdef OPENSSL_NO_IDEA { "NO_IDEA" }, #endif #ifdef OPENSSL_NO_DES { "NO_DES" }, #endif #ifdef OPENSSL_NO_BF { "NO_BF" }, #endif #ifdef OPENSSL_NO_CAST { "NO_CAST" }, #endif #ifdef OPENSSL_NO_WHIRLPOOL { "NO_WHIRLPOOL" }, #endif #ifdef OPENSSL_NO_CAMELLIA { "NO_CAMELLIA" }, #endif #ifdef OPENSSL_NO_SEED { "NO_SEED" }, #endif #ifdef OPENSSL_NO_MD2 { "NO_MD2" }, #endif #ifdef OPENSSL_NO_MD4 { "NO_MD4" }, #endif #ifdef OPENSSL_NO_MD5 { "NO_MD5" }, #endif #ifdef OPENSSL_NO_SHA { "NO_SHA" }, #endif #ifdef OPENSSL_NO_RIPEMD { "NO_RIPEMD" }, #endif #ifdef OPENSSL_NO_MDC2 { "NO_MDC2" }, #endif #ifdef OPENSSL_NO_RSA { "NO_RSA" }, #endif #ifdef OPENSSL_NO_DSA { "NO_DSA" }, #endif #ifdef OPENSSL_NO_DH { "NO_DH" }, #endif #ifdef OPENSSL_NO_HMAC { "NO_HMAC" }, #endif #ifdef OPENSSL_NO_AES { "NO_AES" }, #endif #ifdef OPENSSL_NO_KRB5 { "NO_KRB5" }, #endif #ifdef OPENSSL_NO_EC { "NO_EC" }, #endif #ifdef OPENSSL_NO_ECDSA { "NO_ECDSA" }, #endif #ifdef OPENSSL_NO_ECDH { "NO_ECDH" }, #endif #ifdef OPENSSL_NO_ENGINE { "NO_ENGINE" }, #endif #ifdef OPENSSL_NO_HW { "NO_HW" }, #endif #ifdef OPENSSL_NO_FP_API { "NO_FP_API" }, #endif #ifdef OPENSSL_NO_STATIC_ENGINE { "NO_STATIC_ENGINE" }, #endif #ifdef OPENSSL_NO_GMP { "NO_GMP" }, #endif #ifdef OPENSSL_NO_DEPRECATED { "NO_DEPRECATED" }, #endif #ifdef OPENSSL_NO_RFC3779 { "NO_RFC3779" }, #endif #ifdef OPENSSL_NO_PSK { "NO_PSK" }, #endif #ifdef OPENSSL_NO_TLSEXT { "NO_TLSEXT" }, #endif #ifdef OPENSSL_NO_CMS { "NO_CMS" }, #endif #ifdef OPENSSL_NO_CAPIENG { "NO_CAPIENG" }, #endif #ifdef OPENSSL_NO_JPAKE { "NO_JPAKE" }, #endif #ifdef OPENSSL_NO_SRP { "NO_SRP" }, #endif #ifdef OPENSSL_NO_SSL2 { "NO_SSL2" }, #endif #ifdef OPENSSL_NO_EC2M { "NO_EC2M" }, #endif #ifdef OPENSSL_NO_NISTP_GCC { "NO_NISTP_GCC" }, #endif #ifdef OPENSSL_NO_NEXTPROTONEG { "NO_NEXTPROTONEG" }, #endif #ifdef OPENSSL_NO_SCTP { "NO_SCTP" }, #endif #ifdef OPENSSL_NO_UNIT_TEST { "NO_UNIT_TEST" }, #endif { "" } /* in case nothing is defined above */ }; /* opensslconf_no[] */ static const auxL_IntegerReg openssl_integers[] = { #ifdef SSLEAY_VERSION_NUMBER { "SSLEAY_VERSION_NUMBER", SSLEAY_VERSION_NUMBER }, #endif #ifdef SSLEAY_VERSION { "SSLEAY_VERSION", SSLEAY_VERSION }, #endif #ifdef SSLEAY_OPTIONS { "SSLEAY_OPTIONS", SSLEAY_OPTIONS }, #endif #ifdef SSLEAY_CFLAGS { "SSLEAY_CFLAGS", SSLEAY_CFLAGS }, #endif #ifdef SSLEAY_BUILT_ON { "SSLEAY_BUILT_ON", SSLEAY_BUILT_ON }, #endif #ifdef SSLEAY_PLATFORM { "SSLEAY_PLATFORM", SSLEAY_PLATFORM }, #endif #ifdef SSLEAY_DIR { "SSLEAY_DIR", SSLEAY_DIR }, #endif #ifdef LIBRESSL_VERSION_NUMBER { "LIBRESSL_VERSION_NUMBER", LIBRESSL_VERSION_NUMBER }, #endif #ifdef OPENSSL_VERSION_NUMBER { "OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER }, #endif #ifdef LIBRESSL_VERSION_NUMBER { "VERSION_NUMBER", LIBRESSL_VERSION_NUMBER }, #elif OPENSSL_VERSION_NUMBER { "VERSION_NUMBER", OPENSSL_VERSION_NUMBER }, #else { "VERSION_NUMBER", SSLEAY_VERSION_NUMBER }, #endif { NULL, 0 }, }; EXPORT int luaopen__openssl(lua_State *L) { size_t i; auxL_newlib(L, ossl_globals, 0); for (i = 0; i < countof(opensslconf_no); i++) { if (*opensslconf_no[i]) { lua_pushboolean(L, 1); lua_setfield(L, -2, opensslconf_no[i]); } } auxL_setintegers(L, openssl_integers); lua_pushstring(L, OPENSSL_VERSION_TEXT); lua_setfield(L, -2, "VERSION_TEXT"); #ifdef SHLIB_VERSION_HISTORY lua_pushstring(L, SHLIB_VERSION_HISTORY); lua_setfield(L, -2, "SHLIB_VERSION_HISTORY"); #endif #ifdef SHLIB_VERSION_NUMBER lua_pushstring(L, SHLIB_VERSION_NUMBER); lua_setfield(L, -2, "SHLIB_VERSION_NUMBER"); #endif return 1; } /* luaopen__openssl() */ /* * BIGNUM - openssl.bignum * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static BIGNUM *bn_push(lua_State *L) { BIGNUM **ud = prepsimple(L, BIGNUM_CLASS); if (!(*ud = BN_new())) auxL_error(L, auxL_EOPENSSL, "bignum.new"); return *ud; } /* bn_push() */ static BIGNUM *bn_dup(lua_State *L, const BIGNUM *src) { BIGNUM **ud = prepsimple(L, BIGNUM_CLASS); if (!(*ud = BN_dup(src))) auxL_error(L, auxL_EOPENSSL, "bignum"); return *ud; } /* bn_dup() */ static BIGNUM *bn_dup_nil(lua_State *L, const BIGNUM *src) { return (src)? bn_dup(L, src) : (lua_pushnil(L), (BIGNUM *)0); } /* bn_dup_nil() */ #define checkbig_(a, b, c, ...) checkbig((a), (b), (c)) #define checkbig(...) EXPAND( checkbig_(__VA_ARGS__, &(_Bool){ 0 }, 0) ) static BIGNUM *(checkbig)(lua_State *, int, _Bool *); static int bn_new(lua_State *L) { int i, n; if ((n = lua_gettop(L)) > 0) { for (i = 1; i <= n; i++) checkbig(L, i); return n; } else { bn_push(L); return 1; } } /* bn_new() */ static int bn_fromBinary(lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); BIGNUM *bn = bn_push(L); if (!BN_bin2bn((const unsigned char*)s, len, bn)) { auxL_error(L, auxL_EOPENSSL, "bignum"); } return 1; } /* bn_fromBinary() */ static int bn_interpose(lua_State *L) { return interpose(L, BIGNUM_CLASS); } /* bn_interpose() */ /* return integral part */ static inline double intof(double f) { return (isfinite(f))? floor(fabs(f)) : 0.0; } /* intof() */ /* convert integral to BN_ULONG. returns success or failure. */ static _Bool int2ul(BN_ULONG *ul, double f) { int exp; frexp(f, &exp); if (exp > (int)sizeof *ul * 8) return 0; *ul = (BN_ULONG)f; return 1; } /* int2ul() */ /* convert integral BIGNUM. returns success or failure. */ static _Bool int2bn(BIGNUM **bn, double q) { unsigned char nib[32], bin[32], *p; size_t i, n; double r; p = nib; while (q >= 1.0 && p < endof(nib)) { r = fmod(q, 256.0); *p++ = r; q = round((q - r) / 256.0); } n = p - nib; for (i = 0; i < n; i++) { bin[i] = *--p; } if (!(*bn = BN_bin2bn(bin, n, *bn))) return 0; return 1; } /* int2bn() */ /* convert double to BIGNUM. returns success or failure. */ static _Bool f2bn(BIGNUM **bn, double f) { double i = intof(f); BN_ULONG lu; if (int2ul(&lu, i)) { if (!*bn && !(*bn = BN_new())) return 0; if (!BN_set_word(*bn, lu)) return 0; } else if (!int2bn(bn, i)) return 0; BN_set_negative(*bn, signbit(f)); return 1; } /* f2bn() */ static BIGNUM *(checkbig)(lua_State *L, int index, _Bool *lvalue) { BIGNUM **bn; const char *str; size_t len, i; _Bool neg, hex; index = lua_absindex(L, index); switch (lua_type(L, index)) { case LUA_TSTRING: *lvalue = 0; str = lua_tolstring(L, index, &len); neg = (str[0] == '-'); hex = (str[neg] == '0' && (str[neg+1] == 'x' || str[neg+1] == 'X')); if (hex) { luaL_argcheck(L, len > 2+(size_t)neg, index, "invalid hex string"); for (i = 2+neg; i < len; i++) { if (!isxdigit((unsigned char)str[i])) luaL_argerror(L, 1, "invalid hex string"); } } else { luaL_argcheck(L, len > neg, index, "invalid decimal string"); for (i = neg; i < len; i++) { if (!isdigit((unsigned char)str[i])) luaL_argerror(L, 1, "invalid decimal string"); } } bn = prepsimple(L, BIGNUM_CLASS); if (hex) { if (!BN_hex2bn(bn, str+2+neg)) auxL_error(L, auxL_EOPENSSL, "bignum"); if (neg) BN_set_negative(*bn, 1); } else { if (!BN_dec2bn(bn, str)) auxL_error(L, auxL_EOPENSSL, "bignum"); } lua_replace(L, index); return *bn; case LUA_TNUMBER: *lvalue = 0; bn = prepsimple(L, BIGNUM_CLASS); #if LUA_VERSION_NUM >= 503 if (lua_isinteger(L, index)) { lua_Integer n = lua_tointeger(L, index); auxL_Unsigned lu; if (!*bn && !(*bn = BN_new())) auxL_error(L, auxL_EOPENSSL, "bignum"); neg = n < 0; lu = neg ? (0 - n) : n; if (!BN_set_word(*bn, lu)) auxL_error(L, auxL_EOPENSSL, "bignum"); if (neg) BN_set_negative(*bn, 1); } else #endif if (!f2bn(bn, lua_tonumber(L, index))) auxL_error(L, auxL_EOPENSSL, "bignum"); lua_replace(L, index); return *bn; default: *lvalue = 1; return checksimple(L, index, BIGNUM_CLASS); } /* switch() */ } /* checkbig() */ /* prepare number at top of stack for unary operation, and push result object onto stack */ static void bn_prepuop(lua_State *L, BIGNUM **r, BIGNUM **a, _Bool commute) { _Bool lvalue = 1; *a = checkbig(L, -1, &lvalue); if (!lvalue && commute) { lua_pushvalue(L, -1); } else { bn_push(L); } *r = *(BIGNUM **)lua_touserdata(L, -1); } /* bn_prepuop() */ /* prepare numbers at top of stack for binary operation, and push result object onto stack */ static void bn_prepbop(lua_State *L, BIGNUM **r, BIGNUM **a, BIGNUM **b, _Bool commute) { _Bool a_lvalue, b_lvalue; *a = checkbig(L, -2, &a_lvalue); *b = checkbig(L, -1, &b_lvalue); if (commute && !a_lvalue) { lua_pushvalue(L, -2); } else if (commute && !b_lvalue) { lua_pushvalue(L, -1); } else { bn_push(L); } *r = *(BIGNUM **)lua_touserdata(L, -1); } /* bn_prepbop() */ /* prepare numbers at top of stack for ternary operation, and push result object onto stack */ static void bn_preptop(lua_State *L, BIGNUM **r, BIGNUM **a, BIGNUM **b, BIGNUM **c) { _Bool a_lvalue, b_lvalue, c_lvalue; *a = checkbig(L, 1, &a_lvalue); *b = checkbig(L, 2, &b_lvalue); *c = checkbig(L, 3, &c_lvalue); bn_push(L); *r = *(BIGNUM **)lua_touserdata(L, -1); } /* bn_preptop() */ static int ctx__gc(lua_State *L) { BN_CTX **ctx = lua_touserdata(L, 1); if (*ctx) { BN_CTX_free(*ctx); *ctx = NULL; } return 0; } /* ctx__gc() */ static BN_CTX *getctx(lua_State *L) { BN_CTX **ctx; lua_pushlightuserdata(L, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&ctx__gc)); lua_gettable(L, LUA_REGISTRYINDEX); if (lua_isnil(L, -1)) { lua_pop(L, 1); ctx = prepsimple(L, NULL, &ctx__gc); if (!(*ctx = BN_CTX_new())) auxL_error(L, auxL_EOPENSSL, "bignum"); lua_pushlightuserdata(L, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&ctx__gc)); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); } ctx = lua_touserdata(L, -1); lua_pop(L, 1); return *ctx; } /* getctx() */ static int bn_toBinary(lua_State *L) { BIGNUM *bn = checksimple(L, 1, BIGNUM_CLASS); size_t len; void *dst; len = BN_num_bytes(bn); dst = lua_newuserdata(L, len); BN_bn2bin(bn, dst); lua_pushlstring(L, dst, len); return 1; } /* bn_toBinary() */ static int bn__add(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 1); if (!BN_add(r, a, b)) return auxL_error(L, auxL_EOPENSSL, "bignum:__add"); return 1; } /* bn__add() */ static int bn__sub(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 0); if (!BN_sub(r, a, b)) return auxL_error(L, auxL_EOPENSSL, "bignum:__sub"); return 1; } /* bn__sub() */ static int bn__mul(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 1); if (!BN_mul(r, a, b, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:__mul"); return 1; } /* bn__mul() */ static int bn_sqr(lua_State *L) { BIGNUM *r, *a; lua_settop(L, 1); bn_prepuop(L, &r, &a, 1); if (!BN_sqr(r, a, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:sqr"); return 1; } /* bn_sqr() */ static int bn__idiv(lua_State *L) { BIGNUM *dv, *a, *b; lua_settop(L, 2); bn_prepbop(L, &dv, &a, &b, 0); if (!BN_div(dv, NULL, a, b, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:__idiv"); return 1; } /* bn__idiv() */ static int bn__mod(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 0); if (!BN_mod(r, a, b, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:__mod"); /* lua has different rounding behaviour for mod than C */ if (!BN_is_zero(r) && (BN_is_negative(a) ^ BN_is_negative(b))) { if (!BN_add(r, r, b)) return auxL_error(L, auxL_EOPENSSL, "bignum:__mod"); } return 1; } /* bn__mod() */ static int bn_nnmod(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 0); if (!BN_nnmod(r, a, b, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:nnmod"); return 1; } /* bn_nnmod() */ static int bn_mod_add(lua_State *L) { BIGNUM *r, *a, *b, *c; lua_settop(L, 3); bn_preptop(L, &r, &a, &b, &c); if (!BN_mod_add(r, a, b, c, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:mod_add"); return 1; } /* bn_mod_add() */ static int bn_mod_sub(lua_State *L) { BIGNUM *r, *a, *b, *c; lua_settop(L, 3); bn_preptop(L, &r, &a, &b, &c); if (!BN_mod_sub(r, a, b, c, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:mod_sub"); return 1; } /* bn_mod_sub() */ static int bn_mod_mul(lua_State *L) { BIGNUM *r, *a, *b, *c; lua_settop(L, 3); bn_preptop(L, &r, &a, &b, &c); if (!BN_mod_mul(r, a, b, c, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:mod_mul"); return 1; } /* bn_mod_mul() */ static int bn_mod_sqr(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 0); if (!BN_mod_sqr(r, a, b, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:mod_sqr"); return 1; } /* bn_mod_sqr() */ static int bn__pow(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 0); if (!BN_exp(r, a, b, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:__pow"); return 1; } /* bn__pow() */ static int bn_mod_exp(lua_State *L) { BIGNUM *r, *a, *b, *c; lua_settop(L, 3); bn_preptop(L, &r, &a, &b, &c); if (!BN_mod_exp(r, a, b, c, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:mod_exp"); return 1; } /* bn_mod_exp() */ static int bn_gcd(lua_State *L) { BIGNUM *r, *a, *b; lua_settop(L, 2); bn_prepbop(L, &r, &a, &b, 1); if (!BN_gcd(r, a, b, getctx(L))) return auxL_error(L, auxL_EOPENSSL, "bignum:gcd"); return 1; } /* bn_gcd() */ static int bn__shl(lua_State *L) { BIGNUM *r, *a; int n; a = checkbig(L, 1); n = luaL_checkinteger(L, 2); r = bn_push(L); if (!BN_lshift(r, a, n)) return auxL_error(L, auxL_EOPENSSL, "bignum:__shl"); return 1; } /* bn__shl() */ static int bn__shr(lua_State *L) { BIGNUM *r, *a; int n; a = checkbig(L, 1); n = luaL_checkinteger(L, 2); r = bn_push(L); if (!BN_rshift(r, a, n)) return auxL_error(L, auxL_EOPENSSL, "bignum:__shr"); return 1; } /* bn__shr() */ static int bn__unm(lua_State *L) { BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); BIGNUM *r = bn_dup(L, a); BN_set_negative(r, !BN_is_negative(a)); return 1; } /* bn__unm() */ static int bn__eq(lua_State *L) { BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); lua_pushboolean(L, 0 == BN_cmp(a, b)); return 1; } /* bn__eq() */ static int bn__lt(lua_State *L) { BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); int cmp = BN_cmp(a, b); lua_pushboolean(L, cmp == -1); return 1; } /* bn__lt() */ static int bn__le(lua_State *L) { BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); int cmp = BN_cmp(a, b); lua_pushboolean(L, cmp <= 0); return 1; } /* bn__le() */ static int bn__gc(lua_State *L) { BIGNUM **ud = luaL_checkudata(L, 1, BIGNUM_CLASS); if (*ud) { BN_clear_free(*ud); *ud = NULL; } return 0; } /* bn__gc() */ static int bn_generatePrime(lua_State *L) { int bits = luaL_checkinteger(L, 1); _Bool safe = optbool(L, 2, 0); const BIGNUM *add = lua_isnoneornil(L, 3) ? NULL : checkbig(L, 3); const BIGNUM *rem = lua_isnoneornil(L, 4) ? NULL : checkbig(L, 4); BIGNUM *bn = bn_push(L); if (!BN_generate_prime_ex(bn, bits, safe, add, rem, NULL)) return auxL_error(L, auxL_EOPENSSL, "bignum.generatePrime"); return 1; } /* bn_generatePrime() */ static int bn_isPrime(lua_State *L) { BIGNUM *bn = checksimple(L, 1, BIGNUM_CLASS); int nchecks = luaL_optinteger(L, 2, BN_prime_checks); #if OPENSSL_PREREQ(3,0,0) int res = BN_check_prime(bn, getctx(L), NULL); #else int res = BN_is_prime_ex(bn, nchecks, getctx(L), NULL); #endif if (res == -1) return auxL_error(L, auxL_EOPENSSL, "bignum:isPrime"); lua_pushboolean(L, res); return 1; } /* bn_isPrime() */ static BIO *getbio(lua_State *); static int bn_toDecimal(lua_State *L) { BIGNUM *bn = checksimple(L, 1, BIGNUM_CLASS); char *txt = NULL; BIO *bio; BUF_MEM *buf; if (!(txt = BN_bn2dec(bn))) goto sslerr; /* use GC-visible BIO as temporary buffer */ bio = getbio(L); if (BIO_puts(bio, txt) < 0) goto sslerr; OPENSSL_free(txt); txt = NULL; BIO_get_mem_ptr(bio, &buf); lua_pushlstring(L, buf->data, buf->length); return 1; sslerr: OPENSSL_free(txt); return auxL_error(L, auxL_EOPENSSL, "bignum:toDecimal"); } /* bn_toDecimal() */ static int bn_toHex(lua_State *L) { BIGNUM *bn = checksimple(L, 1, BIGNUM_CLASS); char *txt = NULL; BIO *bio; BUF_MEM *buf; if (!(txt = BN_bn2hex(bn))) goto sslerr; /* use GC-visible BIO as temporary buffer */ bio = getbio(L); if (BIO_puts(bio, txt) < 0) goto sslerr; OPENSSL_free(txt); txt = NULL; BIO_get_mem_ptr(bio, &buf); lua_pushlstring(L, buf->data, buf->length); return 1; sslerr: OPENSSL_free(txt); return auxL_error(L, auxL_EOPENSSL, "bignum:toHex"); } /* bn_toHex() */ static const auxL_Reg bn_methods[] = { { "add", &bn__add }, { "sub", &bn__sub }, { "mul", &bn__mul }, { "sqr", &bn_sqr }, { "idiv", &bn__idiv }, { "mod", &bn__mod }, { "nnmod", &bn_nnmod }, { "mod_add", &bn_mod_add }, { "mod_sub", &bn_mod_sub }, { "mod_mul", &bn_mod_mul }, { "mod_sqr", &bn_mod_sqr }, { "exp", &bn__pow }, { "mod_exp", &bn_mod_exp }, { "gcd", &bn_gcd }, { "lshift", &bn__shl }, { "rshift", &bn__shr }, { "isPrime", &bn_isPrime }, { "toBinary", &bn_toBinary }, { "toDecimal", &bn_toDecimal }, { "toHex", &bn_toHex }, /* deprecated */ { "tobin", &bn_toBinary }, { "todec", &bn_toDecimal }, { "tohex", &bn_toHex }, { NULL, NULL }, }; static const auxL_Reg bn_metatable[] = { { "__add", &bn__add }, { "__sub", &bn__sub }, { "__mul", &bn__mul }, { "__div", &bn__idiv }, { "__idiv", &bn__idiv }, { "__mod", &bn__mod }, { "__pow", &bn__pow }, { "__unm", &bn__unm }, { "__shl", &bn__shl }, { "__shr", &bn__shr }, { "__eq", &bn__eq }, { "__lt", &bn__lt }, { "__le", &bn__le }, { "__gc", &bn__gc }, { "__tostring", &bn_toDecimal }, { NULL, NULL }, }; static const auxL_Reg bn_globals[] = { { "new", &bn_new }, { "interpose", &bn_interpose }, { "fromBinary", &bn_fromBinary }, { "generatePrime", &bn_generatePrime }, { NULL, NULL }, }; EXPORT int luaopen__openssl_bignum(lua_State *L) { initall(L); auxL_newlib(L, bn_globals, 0); return 1; } /* luaopen__openssl_bignum() */ /* * EVP_PKEY - openssl.pkey * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int bio__gc(lua_State *L) { BIO **bio = lua_touserdata(L, 1); if (*bio) { BIO_free(*bio); *bio = NULL; } return 0; } /* bio__gc() */ static BIO *getbio(lua_State *L) { BIO **bio; lua_pushlightuserdata(L, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&bio__gc)); lua_gettable(L, LUA_REGISTRYINDEX); if (lua_isnil(L, -1)) { lua_pop(L, 1); bio = prepsimple(L, NULL, &bio__gc); if (!(*bio = BIO_new(BIO_s_mem()))) auxL_error(L, auxL_EOPENSSL, "BIO_new"); lua_pushlightuserdata(L, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&bio__gc)); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); } bio = lua_touserdata(L, -1); lua_pop(L, 1); BIO_reset(*bio); return *bio; } /* getbio() */ static int pk_new(lua_State *L) { EVP_PKEY **ud; /* #1 table or key; if key, #2 format and #3 type */ lua_settop(L, 3); if (lua_istable(L, 1) || lua_isnil(L, 1)) { int type = EVP_PKEY_RSA; unsigned bits = 1024; BIGNUM *exp = NULL; int generator = 2; int curve = NID_X9_62_prime192v1; const char *id; const char *dhparam = NULL; lua_Number n; if (lua_istable(L, 1)) { if (loadfield(L, 1, "type", LUA_TSTRING, (void*)&id)) { static const struct { int nid; const char *sn; } types[] = { { EVP_PKEY_RSA, "RSA" }, { EVP_PKEY_DSA, "DSA" }, { EVP_PKEY_DH, "DH" }, { EVP_PKEY_EC, "EC" }, }; unsigned i; if (NID_undef == (type = EVP_PKEY_type(OBJ_sn2nid(id)))) { for (i = 0; i < countof(types); i++) { if (strieq(id, types[i].sn)) { type = types[i].nid; break; } } } luaL_argcheck(L, type != NID_undef, 1, lua_pushfstring(L, "%s: invalid key type", id)); } switch(type) { case EVP_PKEY_RSA: if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); bits = (unsigned)n; } if (getfield(L, 1, "exp")) { exp = checkbig(L, -1); } break; case EVP_PKEY_DH: /* dhparam field can contain a PEM encoded string. The "dhparam" field takes precedence over "bits" */ if (loadfield(L, 1, "dhparam", LUA_TSTRING, (void*)&dhparam)) break; if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); bits = (unsigned)n; } /* compat: DH used to use the 'exp' field for the generator */ if (loadfield(L, 1, "generator", LUA_TNUMBER, &n) || loadfield(L, 1, "exp", LUA_TNUMBER, &n)) { luaL_argcheck(L, n > 0 && n <= INT_MAX, 1, lua_pushfstring(L, "%f: `exp' invalid", n)); generator = (int)n; } break; case EVP_PKEY_EC: if (loadfield(L, 1, "curve", LUA_TSTRING, (void*)&id)) { if (!auxS_txt2nid(&curve, id)) luaL_argerror(L, 1, lua_pushfstring(L, "%s: invalid curve", id)); } break; } } /* defaults that require allocation */ switch (type) { case EVP_PKEY_RSA: if(!exp) { /* default to 65537 */ exp = bn_push(L); if (!BN_add_word(exp, 65537)) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } break; } ud = prepsimple(L, PKEY_CLASS); switch (type) { case EVP_PKEY_RSA: { RSA *rsa; if (!(*ud = EVP_PKEY_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!(rsa = RSA_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!RSA_generate_key_ex(rsa, bits, exp, 0)) { RSA_free(rsa); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EVP_PKEY_set1_RSA(*ud, rsa); RSA_free(rsa); break; } case EVP_PKEY_DSA: { DSA *dsa; if (!(*ud = EVP_PKEY_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!(dsa = DSA_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!DSA_generate_parameters_ex(dsa, bits, 0, 0, 0, 0, 0)) { DSA_free(dsa); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } if (!DSA_generate_key(dsa)) { DSA_free(dsa); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EVP_PKEY_set1_DSA(*ud, dsa); DSA_free(dsa); break; } case EVP_PKEY_DH: { DH *dh; if (!(*ud = EVP_PKEY_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); /* DH Parameter Generation can take a long time, therefore we look * at the "dhparam" field, provided by the user. * The "dhparam" field takes precedence over "bits" */ if (dhparam) { BIO *bio = BIO_new_mem_buf((void*)dhparam, strlen(dhparam)); if (!bio) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (!dh) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } else { if (!(dh = DH_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!DH_generate_parameters_ex(dh, bits, generator, 0)) { DH_free(dh); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } } if (!DH_generate_key(dh)) { DH_free(dh); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EVP_PKEY_set1_DH(*ud, dh); DH_free(dh); break; } #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: { EC_GROUP *grp; EC_KEY *key; if (!(*ud = EVP_PKEY_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (!(grp = EC_GROUP_new_by_curve_name(curve))) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_NAMED_CURVE); /* compressed points patented */ EC_GROUP_set_point_conversion_form(grp, POINT_CONVERSION_UNCOMPRESSED); if (!(key = EC_KEY_new())) { EC_GROUP_free(grp); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EC_KEY_set_group(key, grp); EC_GROUP_free(grp); if (!EC_KEY_generate_key(key)) { EC_KEY_free(key); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } EVP_PKEY_set1_EC_KEY(*ud, key); EC_KEY_free(key); break; } #endif default: #if HAVE_EVP_PKEY_KEYGEN { EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(type, NULL); if (!ctx) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (EVP_PKEY_keygen_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } if (EVP_PKEY_keygen(ctx, ud) != 1) { EVP_PKEY_CTX_free(ctx); return auxL_error(L, auxL_EOPENSSL, "pkey.new"); } break; } #else return luaL_error(L, "%d: unsupported EVP_PKEY base type", EVP_PKEY_type(type)); #endif } /* switch() */ } else if (lua_isstring(L, 1)) { int type = optencoding(L, 2, "*", X509_ANY|X509_PEM|X509_DER); int pubonly = 0, prvtonly = 0; const char *opt, *data; size_t len; BIO *bio; EVP_PKEY *pub = NULL, *prvt = NULL; int goterr = 0; /* check if specified publickey or privatekey */ if ((opt = luaL_optstring(L, 3, NULL))) { if (xtolower(opt[0]) == 'p' && xtolower(opt[1]) == 'u') { pubonly = 1; } else if (xtolower(opt[0]) == 'p' && xtolower(opt[1]) == 'r') { prvtonly = 1; } else { return luaL_argerror(L, 3, lua_pushfstring(L, "invalid option %s", opt)); } } data = luaL_checklstring(L, 1, &len); ud = prepsimple(L, PKEY_CLASS); if (!(bio = BIO_new_mem_buf((void *)data, len))) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (type == X509_PEM || type == X509_ANY) { if (!prvtonly && !pub) { /* * BIO_reset is a rewind for read-only * memory buffers. See mem_ctrl in * crypto/bio/bss_mem.c of OpenSSL source. */ BIO_reset(bio); if (!(pub = PEM_read_bio_PUBKEY(bio, NULL, 0, ""))) goterr = 1; } if (!pubonly && !prvt) { BIO_reset(bio); if (!(prvt = PEM_read_bio_PrivateKey(bio, NULL, 0, ""))) goterr = 1; } } if (type == X509_DER || type == X509_ANY) { if (!prvtonly && !pub) { BIO_reset(bio); if (!(pub = d2i_PUBKEY_bio(bio, NULL))) goterr = 1; } if (!pubonly && !prvt) { BIO_reset(bio); if (!(prvt = d2i_PrivateKey_bio(bio, NULL))) goterr = 1; } } if (prvt) { #if 0 /* TODO: Determine if this is necessary. */ if (pub && EVP_PKEY_missing_parameters(prvt)) { if (!EVP_PKEY_copy_parameters(prvt, pub)) { /* * NOTE: It's not necessarily true * that any internal errors were * set. But we fixed pusherror() to * handle that situation. */ goterr = 1; goto done; } } #endif *ud = prvt; prvt = NULL; } else if (pub) { *ud = pub; pub = NULL; } done: BIO_free(bio); if (pub) EVP_PKEY_free(pub); if (prvt) EVP_PKEY_free(prvt); if (!*ud) { if (goterr) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); /* we should never get here */ return luaL_error(L, "failed to load key for some unexpected reason"); } else if (goterr) { /* clean up our mess from testing input formats */ ERR_clear_error(); } } else { return luaL_error(L, "%s: unknown key initializer", lua_typename(L, lua_type(L, 1))); } return 1; } /* pk_new() */ static int pk_interpose(lua_State *L) { lua_settop(L, 2); luaL_getmetatable(L, PKEY_CLASS); if (!strncmp("__", luaL_checkstring(L, 1), 2)) { lua_insert(L, 1); } else { lua_getfield(L, -1, "__index"); lua_getupvalue(L, -1, 1); lua_insert(L, 1); lua_pop(L, 2); } return auxL_swaptable(L, 1); } /* pk_interpose() */ static int pk_type(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); int nid = EVP_PKEY_id(key); auxL_pushnid(L, nid); return 1; } /* pk_type() */ static int pk_setPublicKey(lua_State *L) { EVP_PKEY **key = luaL_checkudata(L, 1, PKEY_CLASS); const char *data; size_t len; BIO *bio; int type, ok = 0; data = luaL_checklstring(L, 2, &len); type = optencoding(L, 3, "*", X509_ANY|X509_PEM|X509_DER); if (!(bio = BIO_new_mem_buf((void *)data, len))) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (type == X509_ANY || type == X509_PEM) { ok = !!PEM_read_bio_PUBKEY(bio, key, 0, ""); } if (!ok && (type == X509_ANY || type == X509_DER)) { ok = !!d2i_PUBKEY_bio(bio, key); } BIO_free(bio); if (!ok) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); lua_pushboolean(L, 1); return 1; } /* pk_setPublicKey() */ static int pk_setPrivateKey(lua_State *L) { EVP_PKEY **key = luaL_checkudata(L, 1, PKEY_CLASS); const char *data; size_t len; BIO *bio; int type, ok = 0; data = luaL_checklstring(L, 2, &len); type = optencoding(L, 3, "*", X509_ANY|X509_PEM|X509_DER); if (!(bio = BIO_new_mem_buf((void *)data, len))) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); if (type == X509_ANY || type == X509_PEM) { ok = !!PEM_read_bio_PrivateKey(bio, key, 0, ""); } if (!ok && (type == X509_ANY || type == X509_DER)) { ok = !!d2i_PrivateKey_bio(bio, key); } BIO_free(bio); if (!ok) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); lua_pushboolean(L, 1); return 1; } /* pk_setPrivateKey() */ #if HAVE_EVP_PKEY_CTX_NEW static int pk_decrypt(lua_State *L) { size_t outlen, inlen; EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); EVP_PKEY_CTX *ctx; const char *str = luaL_checklstring(L, 2, &inlen); BIO *bio; BUF_MEM *buf; int rsaPadding = RSA_PKCS1_PADDING; /* default for `openssl rsautl` */ int base_type = EVP_PKEY_base_id(key); if (lua_istable(L, 3)) { if (base_type == EVP_PKEY_RSA) { lua_getfield(L, 3, "rsaPadding"); rsaPadding = luaL_optinteger(L, -1, rsaPadding); lua_pop(L, 1); } } bio = getbio(L); BIO_get_mem_ptr(bio, &buf); if (!(ctx = EVP_PKEY_CTX_new(key, NULL))) goto sslerr; if (EVP_PKEY_decrypt_init(ctx) <= 0) goto sslerr; if (base_type == EVP_PKEY_RSA && !EVP_PKEY_CTX_set_rsa_padding(ctx, rsaPadding)) goto sslerr; if (EVP_PKEY_decrypt(ctx, NULL, &outlen, (const unsigned char *)str, inlen) <= 0) goto sslerr; if (!BUF_MEM_grow_clean(buf, outlen)) goto sslerr; if (EVP_PKEY_decrypt(ctx, (unsigned char *)buf->data, &outlen, (const unsigned char *)str, inlen) <= 0) goto sslerr; EVP_PKEY_CTX_free(ctx); ctx = NULL; lua_pushlstring(L, buf->data, outlen); BIO_reset(bio); return 1; sslerr: if (ctx) { EVP_PKEY_CTX_free(ctx); ctx = NULL; } BIO_reset(bio); return auxL_error(L, auxL_EOPENSSL, "pkey:decrypt"); } /* pk_decrypt() */ #endif #if HAVE_EVP_PKEY_CTX_NEW static int pk_encrypt(lua_State *L) { size_t outlen, inlen; EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); EVP_PKEY_CTX *ctx; const char *str = luaL_checklstring(L, 2, &inlen); BIO *bio; BUF_MEM *buf; int rsaPadding = RSA_PKCS1_PADDING; /* default for `openssl rsautl` */ int base_type = EVP_PKEY_base_id(key); if (lua_istable(L, 3)) { if (base_type == EVP_PKEY_RSA) { lua_getfield(L, 3, "rsaPadding"); rsaPadding = luaL_optinteger(L, -1, rsaPadding); lua_pop(L, 1); } } bio = getbio(L); BIO_get_mem_ptr(bio, &buf); if (!(ctx = EVP_PKEY_CTX_new(key, NULL))) goto sslerr; if (EVP_PKEY_encrypt_init(ctx) <= 0) goto sslerr; if (base_type == EVP_PKEY_RSA && !EVP_PKEY_CTX_set_rsa_padding(ctx, rsaPadding)) goto sslerr; if (EVP_PKEY_encrypt(ctx, NULL, &outlen, (const unsigned char *)str, inlen) <= 0) goto sslerr; if (!BUF_MEM_grow_clean(buf, outlen)) goto sslerr; if (EVP_PKEY_encrypt(ctx, (unsigned char *)buf->data, &outlen, (const unsigned char *)str, inlen) <= 0) goto sslerr; EVP_PKEY_CTX_free(ctx); ctx = NULL; lua_pushlstring(L, buf->data, outlen); BIO_reset(bio); return 1; sslerr: if (ctx) { EVP_PKEY_CTX_free(ctx); ctx = NULL; } BIO_reset(bio); return auxL_error(L, auxL_EOPENSSL, "pkey:encrypt"); } /* pk_encrypt() */ #endif static int pk_sign(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); EVP_MD_CTX *md = checksimple(L, 2, DIGEST_CLASS); luaL_Buffer B; unsigned n = EVP_PKEY_size(key); if (!EVP_SignFinal(md, (void *)luaL_buffinitsize(L, &B, n), &n, key)) return auxL_error(L, auxL_EOPENSSL, "pkey:sign"); luaL_pushresultsize(&B, n); return 1; } /* pk_sign() */ static int pk_verify(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); size_t len; const void *sig = luaL_checklstring(L, 2, &len); EVP_MD_CTX *md = checksimple(L, 3, DIGEST_CLASS); switch (EVP_VerifyFinal(md, sig, len, key)) { case 0: /* WRONG */ ERR_clear_error(); lua_pushboolean(L, 0); break; case 1: /* OK */ lua_pushboolean(L, 1); break; default: return auxL_error(L, auxL_EOPENSSL, "pkey:verify"); } return 1; } /* pk_verify() */ static int pk_toPEM(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); int top, i, ok; BIO *bio; char *pem; long len; if (1 == (top = lua_gettop(L))) { lua_pushliteral(L, "publickey"); ++top; } bio = getbio(L); for (i = 2; i <= top; i++) { static const char *const opts[] = { "public", "PublicKey", "private", "PrivateKey", // "params", "Parameters", NULL, }; switch (auxL_checkoption(L, i, NULL, opts, 1)) { case 0: case 1: /* public, PublicKey */ if (!PEM_write_bio_PUBKEY(bio, key)) return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); len = BIO_get_mem_data(bio, &pem); lua_pushlstring(L, pem, len); BIO_reset(bio); break; case 2: case 3: /* private, PrivateKey */ if (!PEM_write_bio_PrivateKey(bio, key, 0, 0, 0, 0, 0)) return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); len = BIO_get_mem_data(bio, &pem); lua_pushlstring(L, pem, len); BIO_reset(bio); break; #if 0 case 4: case 5: /* params, Parameters */ /* EVP_PKEY_base_id not in OS X */ switch (EVP_PKEY_base_id(key)) { case EVP_PKEY_RSA: break; case EVP_PKEY_DSA: { DSA *dsa = EVP_PKEY_get1_DSA(key); ok = !!PEM_write_bio_DSAparams(bio, dsa); DSA_free(dsa); if (!ok) return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } case EVP_PKEY_DH: { DH *dh = EVP_PKEY_get1_DH(key); ok = !!PEM_write_bio_DHparams(bio, dh); DH_free(dh); if (!ok) return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: { EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); const EC_GROUP *grp = EC_KEY_get0_group(ec); ok = !!PEM_write_bio_ECPKParameters(bio, grp); EC_KEY_free(ec); if (!ok) return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } #endif default: return luaL_error(L, "%d: unsupported EVP_PKEY base type", EVP_PKEY_base_id(key)); } lua_pushlstring(L, pem, len); BIO_reset(bio); break; #endif default: lua_pushnil(L); break; } /* switch() */ } /* for() */ return lua_gettop(L) - top; } /* pk_toPEM() */ static int pk_getDefaultDigestName(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); int nid; if (!(EVP_PKEY_get_default_digest_nid(key, &nid) > 0)) return auxL_error(L, auxL_EOPENSSL, "pkey:getDefaultDigestName"); auxL_pushnid(L, nid); return 1; } /* pk_getDefaultDigestName() */ enum pk_param { #define PK_RSA_OPTLIST { "n", "e", "d", "p", "q", "dmp1", "dmq1", "iqmp", NULL } #define PK_RSA_OPTOFFSET PK_RSA_N PK_RSA_N = 1, PK_RSA_E, PK_RSA_D, PK_RSA_P, PK_RSA_Q, PK_RSA_DMP1, PK_RSA_DMQ1, PK_RSA_IQMP, #define PK_DSA_OPTLIST { "p", "q", "g", "pub_key", "priv_key", NULL } #define PK_DSA_OPTOFFSET PK_DSA_P PK_DSA_P, PK_DSA_Q, PK_DSA_G, PK_DSA_PUB_KEY, PK_DSA_PRIV_KEY, #define PK_DH_OPTLIST { "p", "g", "pub_key", "priv_key", NULL } #define PK_DH_OPTOFFSET PK_DH_P PK_DH_P, PK_DH_G, PK_DH_PUB_KEY, PK_DH_PRIV_KEY, /* * NB: group MUST come before pub_key as setting pub_key requires the group * to be defined. :setParameters will do the requested assignments in the * order defined by this array. */ #define PK_EC_OPTLIST { "group", "pub_key", "priv_key", NULL } #define PK_EC_OPTOFFSET PK_EC_GROUP PK_EC_GROUP, PK_EC_PUB_KEY, PK_EC_PRIV_KEY, #define PK_RAW_OPTLIST { "pub_key", "priv_key", NULL } #define PK_RAW_OPTOFFSET PK_RAW_PUB_KEY PK_RAW_PUB_KEY, PK_RAW_PRIV_KEY, }; /* enum pk_param */ static const char *const pk_rsa_optlist[] = PK_RSA_OPTLIST; static const char *const pk_dsa_optlist[] = PK_DSA_OPTLIST; static const char *const pk_dh_optlist[] = PK_DH_OPTLIST; static const char *const pk_ec_optlist[] = PK_EC_OPTLIST; static const char *const pk_raw_optlist[] = PK_RAW_OPTLIST; const char *const *pk_getoptlist(int type, int *_nopts, int *_optoffset) { const char *const *optlist = NULL; int nopts = 0, optoffset = 0; switch (type) { case EVP_PKEY_RSA: optlist = pk_rsa_optlist; nopts = countof(pk_rsa_optlist) - 1; optoffset = PK_RSA_OPTOFFSET; break; case EVP_PKEY_DSA: optlist = pk_dsa_optlist; nopts = countof(pk_dsa_optlist) - 1; optoffset = PK_DSA_OPTOFFSET; break; case EVP_PKEY_DH: optlist = pk_dh_optlist; nopts = countof(pk_dh_optlist) - 1; optoffset = PK_DH_OPTOFFSET; break; case EVP_PKEY_EC: optlist = pk_ec_optlist; nopts = countof(pk_ec_optlist) - 1; optoffset = PK_EC_OPTOFFSET; break; #if HAVE_EVP_PKEY_RAW case EVP_PKEY_X25519: case EVP_PKEY_X448: case EVP_PKEY_ED25519: case EVP_PKEY_ED448: optlist = pk_raw_optlist; nopts = countof(pk_raw_optlist) - 1; optoffset = PK_RAW_OPTOFFSET; break; #endif } if (_nopts) *_nopts = nopts; if (_optoffset) *_optoffset = optoffset; return optlist; } /* pk_getoptlist() */ #ifndef OPENSSL_NO_EC static EC_GROUP *ecg_dup_nil(lua_State *, const EC_GROUP *); #endif static void pk_pushparam(lua_State *L, EVP_PKEY *pkey, enum pk_param which) { const BIGNUM *i; luaL_Buffer B; size_t len; switch (which) { case PK_RSA_N: /* RSA public modulus n */ RSA_get0_key(EVP_PKEY_get0_RSA(pkey), &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_RSA_E: /* RSA public exponent e */ RSA_get0_key(EVP_PKEY_get0_RSA(pkey), NULL, &i, NULL); bn_dup_nil(L, i); break; case PK_RSA_D: /* RSA secret exponent d */ RSA_get0_key(EVP_PKEY_get0_RSA(pkey), NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_RSA_P: /* RSA secret prime p */ RSA_get0_factors(EVP_PKEY_get0_RSA(pkey), &i, NULL); bn_dup_nil(L, i); break; case PK_RSA_Q: /* RSA secret prime q with p < q */ RSA_get0_factors(EVP_PKEY_get0_RSA(pkey), NULL, &i); bn_dup_nil(L, i); break; case PK_RSA_DMP1: /* exponent1 */ RSA_get0_crt_params(EVP_PKEY_get0_RSA(pkey), &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_RSA_DMQ1: /* exponent2 */ RSA_get0_crt_params(EVP_PKEY_get0_RSA(pkey), NULL, &i, NULL); bn_dup_nil(L, i); break; case PK_RSA_IQMP: /* coefficient */ RSA_get0_crt_params(EVP_PKEY_get0_RSA(pkey), NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_DSA_P: DSA_get0_pqg(EVP_PKEY_get0_DSA(pkey), &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_DSA_Q: DSA_get0_pqg(EVP_PKEY_get0_DSA(pkey), NULL, &i, NULL); bn_dup_nil(L, i); break; case PK_DSA_G: DSA_get0_pqg(EVP_PKEY_get0_DSA(pkey), NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_DSA_PUB_KEY: DSA_get0_key(EVP_PKEY_get0_DSA(pkey), &i, NULL); bn_dup_nil(L, i); break; case PK_DSA_PRIV_KEY: DSA_get0_key(EVP_PKEY_get0_DSA(pkey), NULL, &i); bn_dup_nil(L, i); break; case PK_DH_P: DH_get0_pqg(EVP_PKEY_get0_DH(pkey), &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_DH_G: DH_get0_pqg(EVP_PKEY_get0_DH(pkey), NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_DH_PUB_KEY: DH_get0_key(EVP_PKEY_get0_DH(pkey), &i, NULL); bn_dup_nil(L, i); break; case PK_DH_PRIV_KEY: DH_get0_key(EVP_PKEY_get0_DH(pkey), NULL, &i); bn_dup_nil(L, i); break; #ifndef OPENSSL_NO_EC case PK_EC_GROUP: ecg_dup_nil(L, EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))); break; case PK_EC_PUB_KEY: { const EC_GROUP *group; const EC_POINT *pub_key; if ((group = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) && (pub_key = EC_KEY_get0_public_key(EVP_PKEY_get0_EC_KEY(pkey)))) { bn_dup_nil(L, EC_POINT_point2bn(group, pub_key, EC_KEY_get_conv_form(EVP_PKEY_get0_EC_KEY(pkey)), NULL, getctx(L))); } else { lua_pushnil(L); } break; } case PK_EC_PRIV_KEY: bn_dup_nil(L, EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(pkey))); break; #endif #if HAVE_EVP_PKEY_RAW case PK_RAW_PUB_KEY: EVP_PKEY_get_raw_public_key(pkey, NULL, &len); EVP_PKEY_get_raw_public_key(pkey, (unsigned char*)luaL_buffinitsize(L, &B, len), &len); luaL_pushresultsize(&B, len); break; case PK_RAW_PRIV_KEY: EVP_PKEY_get_raw_private_key(pkey, NULL, &len); EVP_PKEY_get_raw_private_key(pkey, (unsigned char*)luaL_buffinitsize(L, &B, len), &len); luaL_pushresultsize(&B, len); break; #endif default: luaL_error(L, "%d: invalid EVP_PKEY parameter", which); } return; } /* pk_pushparam() */ #define pk_setparam_bn_dup(L, index, dst) do { \ BIGNUM *tmp = checkbig((L), (index)); \ if (!(*dst = BN_dup(tmp))) \ goto sslerr; \ } while (0) static void pk_setparam(lua_State *L, EVP_PKEY *pkey, enum pk_param which, int index) { BIGNUM *i; switch (which) { case PK_RSA_N: pk_setparam_bn_dup(L, index, &i); RSA_set0_key(EVP_PKEY_get0_RSA(pkey), i, NULL, NULL); break; case PK_RSA_E: pk_setparam_bn_dup(L, index, &i); RSA_set0_key(EVP_PKEY_get0_RSA(pkey), NULL, i, NULL); break; case PK_RSA_D: pk_setparam_bn_dup(L, index, &i); RSA_set0_key(EVP_PKEY_get0_RSA(pkey), NULL, NULL, i); break; case PK_RSA_P: pk_setparam_bn_dup(L, index, &i); RSA_set0_factors(EVP_PKEY_get0_RSA(pkey), i, NULL); break; case PK_RSA_Q: pk_setparam_bn_dup(L, index, &i); RSA_set0_factors(EVP_PKEY_get0_RSA(pkey), NULL, i); break; case PK_RSA_DMP1: pk_setparam_bn_dup(L, index, &i); RSA_set0_crt_params(EVP_PKEY_get0_RSA(pkey), i, NULL, NULL); break; case PK_RSA_DMQ1: pk_setparam_bn_dup(L, index, &i); RSA_set0_crt_params(EVP_PKEY_get0_RSA(pkey), NULL, i, NULL); break; case PK_RSA_IQMP: pk_setparam_bn_dup(L, index, &i); RSA_set0_crt_params(EVP_PKEY_get0_RSA(pkey), NULL, NULL, i); break; case PK_DSA_P: pk_setparam_bn_dup(L, index, &i); DSA_set0_pqg(EVP_PKEY_get0_DSA(pkey), i, NULL, NULL); break; case PK_DSA_Q: pk_setparam_bn_dup(L, index, &i); DSA_set0_pqg(EVP_PKEY_get0_DSA(pkey), NULL, i, NULL); break; case PK_DSA_G: pk_setparam_bn_dup(L, index, &i); DSA_set0_pqg(EVP_PKEY_get0_DSA(pkey), NULL, NULL, i); break; case PK_DSA_PUB_KEY: pk_setparam_bn_dup(L, index, &i); DSA_set0_key(EVP_PKEY_get0_DSA(pkey), i, NULL); break; case PK_DSA_PRIV_KEY: pk_setparam_bn_dup(L, index, &i); DSA_set0_key(EVP_PKEY_get0_DSA(pkey), NULL, i); break; case PK_DH_P: pk_setparam_bn_dup(L, index, &i); DH_set0_pqg(EVP_PKEY_get0_DH(pkey), i, NULL, NULL); break; case PK_DH_G: pk_setparam_bn_dup(L, index, &i); DH_set0_pqg(EVP_PKEY_get0_DH(pkey), NULL, NULL, i); break; case PK_DH_PUB_KEY: pk_setparam_bn_dup(L, index, &i); DH_set0_key(EVP_PKEY_get0_DH(pkey), i, NULL); break; case PK_DH_PRIV_KEY: pk_setparam_bn_dup(L, index, &i); DH_set0_key(EVP_PKEY_get0_DH(pkey), NULL, i); break; #ifndef OPENSSL_NO_EC case PK_EC_GROUP: { const EC_GROUP *group = checksimple(L, index, EC_GROUP_CLASS); if (!EC_KEY_set_group(EVP_PKEY_get0_EC_KEY(pkey), group)) goto sslerr; break; } case PK_EC_PUB_KEY: { const BIGNUM *n = checkbig(L, index); const EC_GROUP *group; EC_POINT *pub_key; _Bool okay; if (!(group = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey)))) luaL_error(L, "unable to set EC pub_key (no group defined)"); if (!(pub_key = EC_POINT_bn2point(group, n, NULL, getctx(L)))) goto sslerr; /* NB: copies key, doesn't share or take ownership */ okay = EC_KEY_set_public_key(EVP_PKEY_get0_EC_KEY(pkey), pub_key); EC_POINT_free(pub_key); if (!okay) goto sslerr; break; } case PK_EC_PRIV_KEY: { const BIGNUM *n = checkbig(L, index); /* NB: copies key, doesn't share or take ownership */ if (!EC_KEY_set_private_key(EVP_PKEY_get0_EC_KEY(pkey), n)) goto sslerr; break; } #endif #if HAVE_EVP_PKEY_RAW case PK_RAW_PUB_KEY: case PK_RAW_PRIV_KEY: luaL_error(L, "%d: EVP_PKEY parameter is immutable", which); break; #endif default: luaL_error(L, "%d: invalid EVP_PKEY parameter", which); } return; sslerr: auxL_error(L, auxL_EOPENSSL, "pkey:setParameters"); return; } /* pk_setparam() */ static int pk_getParameters(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); int base_type = EVP_PKEY_base_id(key); const char *const *optlist; int nopts, optoffset, otop, index, tindex; if (!(optlist = pk_getoptlist(base_type, &nopts, &optoffset))) return luaL_error(L, "%d: unsupported EVP_PKEY base type", base_type); if (lua_isnoneornil(L, 2)) { const char *const *optname; /* * Use special "{" parameter to tell loop to push table. * Subsequent parameters will be assigned as fields. */ lua_pushliteral(L, "{"); luaL_checkstack(L, nopts, "too many arguments"); for (optname = optlist; *optname; optname++) { lua_pushstring(L, *optname); } } otop = lua_gettop(L); /* provide space for results and working area */ luaL_checkstack(L, (otop - 1) + LUA_MINSTACK, "too many arguments"); /* no table index, yet */ tindex = 0; for (index = 2; index <= otop; index++) { const char *optname = luaL_checkstring(L, index); int optid; if (*optname == '{') { lua_newtable(L); tindex = lua_gettop(L); } else { optid = luaL_checkoption(L, index, NULL, optlist) + optoffset; pk_pushparam(L, key, optid); if (tindex) { lua_setfield(L, tindex, optname); } } } return lua_gettop(L) - otop; } /* pk_getParameters() */ static int pk_setParameters(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); int base_type = EVP_PKEY_base_id(key); const char *const *optlist; int optindex, optoffset; luaL_checktype(L, 2, LUA_TTABLE); if (!(optlist = pk_getoptlist(base_type, NULL, &optoffset))) return luaL_error(L, "%d: unsupported EVP_PKEY base type", base_type); for (optindex = 0; optlist[optindex]; optindex++) { if (getfield(L, 2, optlist[optindex])) { pk_setparam(L, key, optindex + optoffset, -1); lua_pop(L, 1); } } return 0; } /* pk_setParameters() */ static int pk__tostring(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); int type = optencoding(L, 2, "pem", X509_PEM|X509_DER); BIO *bio = getbio(L); char *data; long len; switch (type) { case X509_PEM: if (!PEM_write_bio_PUBKEY(bio, key)) return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; case X509_DER: if (!i2d_PUBKEY_bio(bio, key)) return auxL_error(L, auxL_EOPENSSL, "pkey:__tostring"); break; } /* switch() */ len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* pk__tostring() */ static int pk__index(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); const char *const *optlist; int optoffset, listoffset; lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, 2); lua_gettable(L, -2); if (!lua_isnil(L, -1)) return 1; if (!lua_isstring(L, 2)) return 0; if (!(optlist = pk_getoptlist(EVP_PKEY_base_id(key), NULL, &optoffset))) return 0; if (-1 == (listoffset = auxL_testoption(L, 2, NULL, optlist, 0))) return 0; pk_pushparam(L, key, listoffset + optoffset); return 1; } /* pk__index() */ static int pk__newindex(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); const char *const *optlist; int optoffset, listoffset; if (!lua_isstring(L, 2)) return 0; if (!(optlist = pk_getoptlist(EVP_PKEY_base_id(key), NULL, &optoffset))) return 0; if (-1 == (listoffset = auxL_testoption(L, 2, NULL, optlist, 0))) return 0; pk_setparam(L, key, listoffset + optoffset, 3); return 0; } /* pk__newindex() */ static int pk__gc(lua_State *L) { EVP_PKEY **ud = luaL_checkudata(L, 1, PKEY_CLASS); if (*ud) { EVP_PKEY_free(*ud); *ud = NULL; } return 0; } /* pk__gc() */ static const auxL_Reg pk_methods[] = { { "type", &pk_type }, { "setPublicKey", &pk_setPublicKey }, { "setPrivateKey", &pk_setPrivateKey }, { "getDefaultDigestName", &pk_getDefaultDigestName }, { "getParameters", &pk_getParameters }, { "setParameters", &pk_setParameters }, #if HAVE_EVP_PKEY_CTX_NEW { "decrypt", &pk_decrypt }, { "encrypt", &pk_encrypt }, #endif { "sign", &pk_sign }, { "toPEM", &pk_toPEM }, { "tostring", &pk__tostring }, { "verify", &pk_verify }, { NULL, NULL }, }; static const auxL_Reg pk_metatable[] = { { "__tostring", &pk__tostring }, { "__index", &pk__index, 1 }, { "__newindex", &pk__newindex, 1 }, { "__gc", &pk__gc }, { NULL, NULL }, }; static const auxL_Reg pk_globals[] = { { "new", &pk_new }, { "interpose", &pk_interpose }, { NULL, NULL }, }; static void pk_luainit(lua_State *L, _Bool reset) { char **k; if (!auxL_newmetatable(L, PKEY_CLASS, reset)) return; auxL_setfuncs(L, pk_metatable, 0); auxL_newlib(L, pk_methods, 0); for (k = (char *[]){ "__index", "__newindex", 0 }; *k; k++) { lua_getfield(L, -2, *k); /* closure */ lua_pushvalue(L, -2); /* method table */ lua_setupvalue(L, -2, 1); } lua_pop(L, 2); } /* pk_luainit() */ static const auxL_IntegerReg pk_rsa_pad_opts[] = { { "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING }, // PKCS#1 padding #if RSA_SSLV23_PADDING { "RSA_SSLV23_PADDING", RSA_SSLV23_PADDING }, // SSLv23 padding #endif { "RSA_NO_PADDING", RSA_NO_PADDING }, // no padding { "RSA_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING }, // OAEP padding (encrypt and decrypt only) { "RSA_X931_PADDING", RSA_X931_PADDING }, // (signature operations only) #if RSA_PKCS1_PSS_PADDING { "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING }, // (sign and verify only) #endif { NULL, 0 }, }; EXPORT int luaopen__openssl_pkey(lua_State *L) { initall(L); auxL_newlib(L, pk_globals, 0); auxL_setintegers(L, pk_rsa_pad_opts); return 1; } /* luaopen__openssl_pkey() */ /* * Deprecated module name. */ EXPORT int luaopen__openssl_pubkey(lua_State *L) { return luaopen__openssl_pkey(L); } /* luaopen__openssl_pubkey() */ /* * EC_GROUP - openssl.ec.group * * NOTE: Ensure copy-by-value semantics when passing EC_GROUP objects as it * doesn't support reference counting. The only persistent reference should * be the Lua userdata value. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef OPENSSL_NO_EC static EC_GROUP *ecg_dup(lua_State *L, const EC_GROUP *src) { EC_GROUP **ud = prepsimple(L, EC_GROUP_CLASS); if (!(*ud = EC_GROUP_dup(src))) auxL_error(L, auxL_EOPENSSL, "group"); return *ud; } /* ecg_dup() */ static EC_GROUP *ecg_dup_nil(lua_State *L, const EC_GROUP *src) { return (src)? ecg_dup(L, src) : (lua_pushnil(L), (EC_GROUP *)0); } /* ecg_dup_nil() */ static EC_GROUP *ecg_push_by_nid(lua_State *L, int nid) { EC_GROUP **group = prepsimple(L, EC_GROUP_CLASS); if (!(*group = EC_GROUP_new_by_curve_name(nid))) goto oops; EC_GROUP_set_asn1_flag(*group, OPENSSL_EC_NAMED_CURVE); /* compressed points may be patented */ EC_GROUP_set_point_conversion_form(*group, POINT_CONVERSION_UNCOMPRESSED); return *group; oops: lua_pop(L, 1); return NULL; } /* ecg_push_by_nid() */ static int ecg_new(lua_State *L) { switch (lua_type(L, 1)) { case LUA_TSTRING: { const char *data; size_t datalen; int nid, type, goterr; BIO *bio; EC_GROUP **group; data = luaL_checklstring(L, 1, &datalen); if (auxS_txt2nid(&nid, data)) { if (!ecg_push_by_nid(L, nid)) goto sslerr; } else { type = optencoding(L, 2, "*", X509_ANY|X509_PEM|X509_DER); group = prepsimple(L, EC_GROUP_CLASS); luaL_argcheck(L, datalen < INT_MAX, 1, "string too long"); if (!(bio = BIO_new_mem_buf((void *)data, datalen))) return auxL_error(L, auxL_EOPENSSL, "group.new"); goterr = 0; if (type == X509_PEM || type == X509_ANY) { goterr |= !(*group = PEM_read_bio_ECPKParameters(bio, NULL, 0, "")); } if (!*group && (type == X509_DER || type == X509_ANY)) { BIO_reset(bio); goterr |= !(*group = d2i_ECPKParameters_bio(bio, NULL)); } BIO_free(bio); if (!*group) return auxL_error(L, auxL_EOPENSSL, "group.new"); if (goterr) ERR_clear_error(); } return 1; } case LUA_TNUMBER: { int nid = luaL_checkinteger(L, 2); if (!ecg_push_by_nid(L, nid)) goto sslerr; return 1; } default: return luaL_error(L, "%s: unknown group initializer", lua_typename(L, lua_type(L, 1))); } /* switch() */ return 0; sslerr: return auxL_error(L, auxL_EOPENSSL, "group.new"); } /* ecg_new() */ static int ecg_interpose(lua_State *L) { return interpose(L, EC_GROUP_CLASS); } /* ecg_interpose() */ static int ecg_toPEM(lua_State *L) { EC_GROUP *group = checksimple(L, 1, EC_GROUP_CLASS); BIO *bio = getbio(L); size_t len; char *bytes; if (!PEM_write_bio_ECPKParameters(bio, group)) return auxL_error(L, auxL_EOPENSSL, "group:toPEM"); len = BIO_get_mem_data(bio, &bytes); lua_pushlstring(L, bytes, len); return 1; } /* ecg_toPEM() */ static int ecg_tostring(lua_State *L) { EC_GROUP *group = checksimple(L, 1, EC_GROUP_CLASS); int how = optencoding(L, 2, "pem", X509_PEM|X509_DER|X509_TXT); BIO *bio = getbio(L); char *bytes; int len, indent; switch (how) { case X509_PEM: if (!PEM_write_bio_ECPKParameters(bio, group)) goto sslerr; break; case X509_DER: if (!i2d_ECPKParameters_bio(bio, group)) goto sslerr; break; case X509_TXT: indent = auxL_optinteger(L, 3, 0, 0, INT_MAX); if (!ECPKParameters_print(bio, group, indent)) goto sslerr; break; } len = BIO_get_mem_data(bio, &bytes); lua_pushlstring(L, bytes, len); return 1; sslerr: return auxL_error(L, auxL_EOPENSSL, "group:__tostring"); } /* ecg_tostring() */ static int ecg__tostring(lua_State *L) { return ecg_tostring(L); } /* ecg__tostring() */ static int ecg__gc(lua_State *L) { EC_GROUP **ud = luaL_checkudata(L, 1, EC_GROUP_CLASS); if (*ud) { EC_GROUP_clear_free(*ud); *ud = NULL; } return 0; } /* ecg__gc() */ static const auxL_Reg ecg_methods[] = { { "toPEM", &ecg_toPEM }, { "tostring", &ecg_tostring }, { NULL, NULL }, }; static const auxL_Reg ecg_metatable[] = { { "__tostring", &ecg__tostring }, { "__gc", &ecg__gc }, { NULL, NULL }, }; static const auxL_Reg ecg_globals[] = { { "new", &ecg_new }, { "interpose", &ecg_interpose }, { NULL, NULL }, }; #endif /* OPENSSL_NO_EC */ EXPORT int luaopen__openssl_ec_group(lua_State *L) { #ifndef OPENSSL_NO_EC initall(L); auxL_newlib(L, ecg_globals, 0); return 1; #else return 0; #endif } /* luaopen__openssl_ec_group() */ /* * X509_NAME - openssl.x509.name * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static X509_NAME *xn_dup(lua_State *L, X509_NAME *name) { X509_NAME **ud = prepsimple(L, X509_NAME_CLASS); if (!(*ud = X509_NAME_dup(name))) auxL_error(L, auxL_EOPENSSL, "x509.name.dup"); return *ud; } /* xn_dup() */ static int xn_new(lua_State *L) { X509_NAME **ud = prepsimple(L, X509_NAME_CLASS); if (!(*ud = X509_NAME_new())) return auxL_error(L, auxL_EOPENSSL, "x509.name.new"); return 1; } /* xn_new() */ static int xn_interpose(lua_State *L) { return interpose(L, X509_NAME_CLASS); } /* xn_interpose() */ static int xn_add(lua_State *L) { X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); const char *nid = luaL_checkstring(L, 2); size_t len; const char *txt = luaL_checklstring(L, 3, &len); ASN1_OBJECT *obj; int ok; if (!(obj = OBJ_txt2obj(nid, 0))) return luaL_error(L, "x509.name:add: %s: invalid NID", nid); ok = !!X509_NAME_add_entry_by_OBJ(name, obj, MBSTRING_ASC, (unsigned char *)txt, len, -1, 0); ASN1_OBJECT_free(obj); if (!ok) return auxL_error(L, auxL_EOPENSSL, "x509.name:add"); lua_pushvalue(L, 1); return 1; } /* xn_add() */ static int xn_all(lua_State *L) { X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); int count = X509_NAME_entry_count(name); X509_NAME_ENTRY *entry; ASN1_OBJECT *obj; const char *id; char txt[256]; int i, nid, len; lua_newtable(L); for (i = 0; i < count; i++) { if (!(entry = X509_NAME_get_entry(name, i))) continue; lua_newtable(L); obj = X509_NAME_ENTRY_get_object(entry); nid = OBJ_obj2nid(obj); if (0 > (len = OBJ_obj2txt(txt, sizeof txt, obj, 1))) return auxL_error(L, auxL_EOPENSSL, "x509.name:all"); lua_pushlstring(L, txt, len); if (nid != NID_undef && ((id = OBJ_nid2ln(nid)) || (id = OBJ_nid2sn(nid)))) lua_pushstring(L, id); else lua_pushvalue(L, -1); if (nid != NID_undef && (id = OBJ_nid2sn(nid))) lua_pushstring(L, id); else lua_pushvalue(L, -1); lua_setfield(L, -4, "sn"); lua_setfield(L, -3, "ln"); lua_setfield(L, -2, "id"); len = ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)); lua_pushlstring(L, (char *)ASN1_STRING_get0_data(X509_NAME_ENTRY_get_data(entry)), len); lua_setfield(L, -2, "blob"); lua_rawseti(L, -2, i + 1); } return 1; } /* xn_all() */ static int xn__next(lua_State *L) { X509_NAME *name = checksimple(L, lua_upvalueindex(1), X509_NAME_CLASS); X509_NAME_ENTRY *entry; ASN1_OBJECT *obj; char txt[256]; int i, n, len; lua_settop(L, 0); i = lua_tointeger(L, lua_upvalueindex(2)); n = X509_NAME_entry_count(name); while (i < n) { if (!(entry = X509_NAME_get_entry(name, i++))) continue; obj = X509_NAME_ENTRY_get_object(entry); if (!(len = auxS_obj2txt(txt, sizeof txt, obj))) return auxL_error(L, auxL_EOPENSSL, "x509.name:__pairs"); lua_pushlstring(L, txt, len); len = ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)); lua_pushlstring(L, (char *)ASN1_STRING_get0_data(X509_NAME_ENTRY_get_data(entry)), len); break; } lua_pushinteger(L, i); lua_replace(L, lua_upvalueindex(2)); return lua_gettop(L); } /* xn__next() */ static int xn__pairs(lua_State *L) { lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, &xn__next, 2); return 1; } /* xn__pairs() */ static int xn__gc(lua_State *L) { X509_NAME **ud = luaL_checkudata(L, 1, X509_NAME_CLASS); if (*ud) { X509_NAME_free(*ud); *ud = NULL; } return 0; } /* xn__gc() */ static int xn__tostring(lua_State *L) { X509_NAME *name = checksimple(L, 1, X509_NAME_CLASS); char txt[1024] = { 0 }; /* FIXME: oneline is deprecated */ X509_NAME_oneline(name, txt, sizeof txt); lua_pushstring(L, txt); return 1; } /* xn__tostring() */ static const auxL_Reg xn_methods[] = { { "add", &xn_add }, { "all", &xn_all }, { "each", &xn__pairs }, { NULL, NULL }, }; static const auxL_Reg xn_metatable[] = { { "__pairs", &xn__pairs }, { "__gc", &xn__gc }, { "__tostring", &xn__tostring }, { NULL, NULL }, }; static const auxL_Reg xn_globals[] = { { "new", &xn_new }, { "interpose", &xn_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_name(lua_State *L) { initall(L); auxL_newlib(L, xn_globals, 0); return 1; } /* luaopen__openssl_x509_name() */ /* * GENERAL_NAMES - openssl.x509.altname * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static GENERAL_NAMES *gn_dup(lua_State *L, GENERAL_NAMES *gens) { GENERAL_NAMES **ud = prepsimple(L, X509_GENS_CLASS); if (!(*ud = sk_GENERAL_NAME_dup(gens))) auxL_error(L, auxL_EOPENSSL, "x509.altname.dup"); return *ud; } /* gn_dup() */ static int gn_new(lua_State *L) { GENERAL_NAMES **ud = prepsimple(L, X509_GENS_CLASS); if (!(*ud = sk_GENERAL_NAME_new_null())) return auxL_error(L, auxL_EOPENSSL, "x509.altname.new"); return 1; } /* gn_new() */ static int gn_interpose(lua_State *L) { return interpose(L, X509_GENS_CLASS); } /* gn_interpose() */ static int gn_checktype(lua_State *L, int index) { static const struct { int type; const char *name; } table[] = { { GEN_EMAIL, "RFC822Name" }, { GEN_EMAIL, "RFC822" }, { GEN_EMAIL, "email" }, { GEN_URI, "UniformResourceIdentifier" }, { GEN_URI, "URI" }, { GEN_DNS, "DNSName" }, { GEN_DNS, "DNS" }, { GEN_IPADD, "IPAddress" }, { GEN_IPADD, "IP" }, { GEN_DIRNAME, "DirName" }, }; const char *type = luaL_checkstring(L, index); unsigned i; for (i = 0; i < countof(table); i++) { if (strieq(table[i].name, type)) return table[i].type; } return luaL_error(L, "%s: invalid type", type), 0; } /* gn_checktype() */ static int gn_add(lua_State *L) { GENERAL_NAMES *gens = checksimple(L, 1, X509_GENS_CLASS); int type = gn_checktype(L, 2); X509_NAME *name; size_t len; const char *txt; GENERAL_NAME *gen = NULL; union { struct in6_addr in6; struct in_addr in; } ip; switch (type) { case GEN_DIRNAME: name = checksimple(L, 3, X509_NAME_CLASS); if (!(gen = GENERAL_NAME_new())) goto error; gen->type = type; if (!(gen->d.dirn = X509_NAME_dup(name))) goto error; break; case GEN_IPADD: txt = luaL_checkstring(L, 3); if (strchr(txt, ':')) { if (1 != inet_pton(AF_INET6, txt, &ip.in6)) return luaL_error(L, "%s: invalid address", txt); txt = (char *)ip.in6.s6_addr; len = 16; } else { if (1 != inet_pton(AF_INET, txt, &ip.in)) return luaL_error(L, "%s: invalid address", txt); txt = (char *)&ip.in.s_addr; len = 4; } goto text; default: txt = luaL_checklstring(L, 3, &len); text: if (!(gen = GENERAL_NAME_new())) goto error; gen->type = type; if (!(gen->d.ia5 = ASN1_STRING_type_new(V_ASN1_IA5STRING))) goto error; if (!ASN1_STRING_set(gen->d.ia5, (unsigned char *)txt, len)) goto error; break; } /* switch() */ sk_GENERAL_NAME_push(gens, gen); lua_pushvalue(L, 1); return 1; error: GENERAL_NAME_free(gen); return auxL_error(L, auxL_EOPENSSL, "x509.altname:add"); } /* gn_add() */ #define GN_PUSHSTRING(L, o) \ lua_pushlstring((L), (char *)ASN1_STRING_get0_data((o)), ASN1_STRING_length((o))) static int gn__next(lua_State *L) { GENERAL_NAMES *gens = checksimple(L, lua_upvalueindex(1), X509_GENS_CLASS); int i = lua_tointeger(L, lua_upvalueindex(2)); int n = sk_GENERAL_NAME_num(gens); lua_settop(L, 0); while (i < n) { GENERAL_NAME *name; const char *txt; size_t len; union { struct in_addr in; struct in6_addr in6; } ip; char buf[INET6_ADDRSTRLEN + 1]; int af; if (!(name = sk_GENERAL_NAME_value(gens, i++))) continue; switch (name->type) { case GEN_EMAIL: lua_pushliteral(L, "email"); GN_PUSHSTRING(L, name->d.rfc822Name); break; case GEN_URI: lua_pushliteral(L, "URI"); GN_PUSHSTRING(L, name->d.uniformResourceIdentifier); break; case GEN_DNS: lua_pushliteral(L, "DNS"); GN_PUSHSTRING(L, name->d.dNSName); break; case GEN_IPADD: txt = (char *)ASN1_STRING_get0_data(name->d.iPAddress); len = ASN1_STRING_length(name->d.iPAddress); switch (len) { case 16: memcpy(ip.in6.s6_addr, txt, 16); af = AF_INET6; break; case 4: memcpy(&ip.in.s_addr, txt, 4); af = AF_INET; break; default: continue; } if (!(txt = inet_ntop(af, &ip, buf, sizeof buf))) continue; lua_pushliteral(L, "IP"); lua_pushstring(L, txt); break; case GEN_DIRNAME: lua_pushliteral(L, "DirName"); xn_dup(L, name->d.dirn); break; default: continue; } /* switch() */ break; } /* while() */ lua_pushinteger(L, i); lua_replace(L, lua_upvalueindex(2)); return lua_gettop(L); } /* gn__next() */ static int gn__pairs(lua_State *L) { lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, &gn__next, 2); return 1; } /* gn__pairs() */ static int gn__gc(lua_State *L) { GENERAL_NAMES **ud = luaL_checkudata(L, 1, X509_GENS_CLASS); if (*ud) { sk_GENERAL_NAME_pop_free(*ud, GENERAL_NAME_free); *ud = NULL; } return 0; } /* gn__gc() */ static const auxL_Reg gn_methods[] = { { "add", &gn_add }, { NULL, NULL }, }; static const auxL_Reg gn_metatable[] = { { "__pairs", &gn__pairs }, { "__gc", &gn__gc }, { NULL, NULL }, }; static const auxL_Reg gn_globals[] = { { "new", &gn_new }, { "interpose", &gn_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_altname(lua_State *L) { initall(L); auxL_newlib(L, gn_globals, 0); return 1; } /* luaopen__openssl_x509_altname() */ /* * X509_EXTENSION - openssl.x509.extension * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static _Bool xe_new_isder(const char *value, _Bool *crit) { if (!strcmp(value, "critical,DER")) return (*crit = 1), 1; if (!strcmp(value, "DER")) return (*crit = 0), 1; return 0; } /* xs_new_isder() */ static CONF* loadconf(lua_State *L, int idx) { CONF *conf; size_t len; const char *cdata = luaL_checklstring(L, idx, &len); BIO *bio = getbio(L); if (BIO_write(bio, cdata, len) < 0) return NULL; if (!(conf = NCONF_new(NULL))) return NULL; if (!NCONF_load_bio(conf, bio, NULL)) { NCONF_free(conf); return NULL; } return conf; } static int xe_new(lua_State *L) { const char *name = luaL_checkstring(L, 1); const char *value = luaL_checkstring(L, 2); ASN1_OBJECT *obj = NULL; ASN1_STRING *oct = NULL; CONF *conf = NULL; X509V3_CTX cbuf = { 0 }, *ctx = NULL; X509_EXTENSION **ud; _Bool crit; lua_settop(L, 3); ud = prepsimple(L, X509_EXT_CLASS); if (xe_new_isder(value, &crit)) { size_t len; const char *cdata = lua_tolstring(L, 3, &len); if (!(obj = OBJ_txt2obj(name, 0))) goto error; if (!(oct = ASN1_STRING_new())) goto error; if (!ASN1_STRING_set(oct, cdata, len)) goto error; if (!(*ud = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct))) goto error; ASN1_OBJECT_free(obj); ASN1_STRING_free(oct); return 1; } switch (lua_type(L, 3)) { case LUA_TNONE: case LUA_TNIL: break; case LUA_TSTRING: { if (!(conf = loadconf(L, 3))) goto error; ctx = &cbuf; X509V3_set_nconf(ctx, conf); break; } case LUA_TTABLE: { X509 *issuer = NULL; X509 *subject = NULL; X509_REQ *request = NULL; X509_CRL *crl = NULL; int flags = 0; ctx = &cbuf; if (lua_getfield(L, 3, "db") != LUA_TNIL) { if (!(conf = loadconf(L, -1))) goto error; X509V3_set_nconf(ctx, conf); } lua_pop(L, 1); if (lua_getfield(L, 3, "issuer") != LUA_TNIL) { issuer = checksimple(L, -1, X509_CERT_CLASS); } lua_pop(L, 1); if (lua_getfield(L, 3, "subject") != LUA_TNIL) { subject = checksimple(L, -1, X509_CERT_CLASS); } lua_pop(L, 1); if (lua_getfield(L, 3, "request") != LUA_TNIL) { request = checksimple(L, -1, X509_CSR_CLASS); } lua_pop(L, 1); if (lua_getfield(L, 3, "crl") != LUA_TNIL) { crl = checksimple(L, -1, X509_CRL_CLASS); } lua_pop(L, 1); if (lua_getfield(L, 3, "flags") != LUA_TNIL) { flags = luaL_checkinteger(L, -1); } lua_pop(L, 1); X509V3_set_ctx(ctx, issuer, subject, request, crl, flags); break; } default: return luaL_argerror(L, 3, "invalid extra parameter (expected string, table or nil)"); } /* * NOTE: AFAICT neither name nor value are modified. The API just * doesn't have the proper const-qualifiers. See * crypto/x509v3/v3_conf.c in OpenSSL. * * Also seems to be okay to pass NULL conf. Both NCONF_get_section * and sk_CONF_VALUE_num can handle NULL arguments. See do_ext_nconf * in v3_conf.c. */ if (!(*ud = X509V3_EXT_nconf(conf, ctx, (char *)name, (char *)value))) goto error; if (conf) NCONF_free(conf); return 1; error: if (obj) ASN1_OBJECT_free(obj); if (oct) ASN1_STRING_free(oct); if (conf) NCONF_free(conf); return auxL_error(L, auxL_EOPENSSL, "x509.extension.new"); } /* xe_new() */ static int xe_interpose(lua_State *L) { return interpose(L, X509_EXT_CLASS); } /* xe_interpose() */ static int xe_getID(lua_State *L) { X509_EXTENSION *ext = checksimple(L, 1, X509_EXT_CLASS); ASN1_OBJECT *obj = X509_EXTENSION_get0_object(ext); char txt[256]; int len; if (!(len = auxS_obj2id(txt, sizeof txt, obj))) return auxL_error(L, auxL_EOPENSSL, "x509.extension:getID"); lua_pushlstring(L, txt, len); return 1; } /* xe_getID() */ static int xe_getName(lua_State *L) { X509_EXTENSION *ext = checksimple(L, 1, X509_EXT_CLASS); char txt[256]; int len; if (!(len = auxS_obj2txt(txt, sizeof txt, X509_EXTENSION_get0_object(ext)))) return auxL_error(L, auxL_EOPENSSL, "x509.extension:getName"); lua_pushlstring(L, txt, len); return 1; } /* xe_getName() */ static int xe_getShortName(lua_State *L) { X509_EXTENSION *ext = checksimple(L, 1, X509_EXT_CLASS); char txt[256]; int len; if (!(len = auxS_obj2sn(txt, sizeof txt, X509_EXTENSION_get0_object(ext)))) return 0; lua_pushlstring(L, txt, len); return 1; } /* xe_getShortName() */ static int xe_getLongName(lua_State *L) { X509_EXTENSION *ext = checksimple(L, 1, X509_EXT_CLASS); char txt[256]; int len; if (!(len = auxS_obj2ln(txt, sizeof txt, X509_EXTENSION_get0_object(ext)))) return 0; lua_pushlstring(L, txt, len); return 1; } /* xe_getLongName() */ static int xe_getData(lua_State *L) { ASN1_STRING *data = X509_EXTENSION_get0_data(checksimple(L, 1, X509_EXT_CLASS)); lua_pushlstring(L, (char *)ASN1_STRING_get0_data(data), ASN1_STRING_length(data)); return 1; } /* xe_getData() */ static int xe_getCritical(lua_State *L) { lua_pushboolean(L, X509_EXTENSION_get_critical(checksimple(L, 1, X509_EXT_CLASS))); return 1; } /* xe_getCritical() */ static int xe_text(lua_State *L) { X509_EXTENSION *ext = checksimple(L, 1, X509_EXT_CLASS); unsigned long flags = auxL_optunsigned(L, 2, 0, 0, ULONG_MAX); int indent = auxL_optinteger(L, 3, 0, 0, INT_MAX); BIO *bio = getbio(L); char *data; size_t len; if (!X509V3_EXT_print(bio, ext, flags, indent)) return auxL_error(L, auxL_EOPENSSL, "x509.extension:text"); len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* xe_text() */ static int xe__gc(lua_State *L) { X509_EXTENSION **ud = luaL_checkudata(L, 1, X509_EXT_CLASS); if (*ud) { X509_EXTENSION_free(*ud); *ud = NULL; } return 0; } /* xe__gc() */ static const auxL_Reg xe_methods[] = { { "getID", &xe_getID }, { "getName", &xe_getName }, { "getShortName", &xe_getShortName }, { "getLongName", &xe_getLongName }, { "getData", &xe_getData }, { "getCritical", &xe_getCritical }, { "text", &xe_text }, { NULL, NULL }, }; static const auxL_Reg xe_metatable[] = { { "__gc", &xe__gc }, { NULL, NULL }, }; static const auxL_Reg xe_globals[] = { { "new", &xe_new }, { "interpose", &xe_interpose }, { NULL, NULL }, }; static const auxL_IntegerReg xe_textopts[] = { { "UNKNOWN_MASK", X509V3_EXT_UNKNOWN_MASK }, { "DEFAULT", X509V3_EXT_DEFAULT }, { "ERROR_UNKNOWN", X509V3_EXT_ERROR_UNKNOWN }, { "PARSE_UNKNOWN", X509V3_EXT_PARSE_UNKNOWN }, { "DUMP_UNKNOWN", X509V3_EXT_DUMP_UNKNOWN }, { NULL, 0 }, }; EXPORT int luaopen__openssl_x509_extension(lua_State *L) { initall(L); auxL_newlib(L, xe_globals, 0); auxL_setintegers(L, xe_textopts); return 1; } /* luaopen__openssl_x509_extension() */ /* * X509 - openssl.x509.cert * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void xc_dup(lua_State *L, X509 *x509) { X509 **ud = prepsimple(L, X509_CERT_CLASS); if (!(*ud = X509_dup(x509))) goto error; return; error: auxL_error(L, auxL_EOPENSSL, "X509_dup"); } /* xc_dup() */ static int xc_new(lua_State *L) { const char *data; size_t len; X509 **ud; lua_settop(L, 2); ud = prepsimple(L, X509_CERT_CLASS); if ((data = luaL_optlstring(L, 1, NULL, &len))) { int type = optencoding(L, 2, "*", X509_ANY|X509_PEM|X509_DER); BIO *tmp; int ok = 0; if (!(tmp = BIO_new_mem_buf((char *)data, len))) return auxL_error(L, auxL_EOPENSSL, "x509.cert.new"); if (type == X509_PEM || type == X509_ANY) { ok = !!(*ud = PEM_read_bio_X509(tmp, NULL, 0, "")); /* no password */ } if (!ok && (type == X509_DER || type == X509_ANY)) { BIO_reset(tmp); ok = !!(*ud = d2i_X509_bio(tmp, NULL)); } BIO_free(tmp); if (!ok) return auxL_error(L, auxL_EOPENSSL, "x509.cert.new"); } else { if (!(*ud = X509_new())) return auxL_error(L, auxL_EOPENSSL, "x509.cert.new"); X509_gmtime_adj(X509_get_notBefore(*ud), 0); X509_gmtime_adj(X509_get_notAfter(*ud), 0); } return 1; } /* xc_new() */ static int xc_interpose(lua_State *L) { return interpose(L, X509_CERT_CLASS); } /* xc_interpose() */ static int xc_getVersion(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); lua_pushinteger(L, X509_get_version(crt) + 1); return 1; } /* xc_getVersion() */ static int xc_setVersion(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); int version = luaL_checkinteger(L, 2); if (!X509_set_version(crt, version - 1)) return luaL_error(L, "x509.cert:setVersion: %d: invalid version", version); lua_pushboolean(L, 1); return 1; } /* xc_setVersion() */ static int xc_getSerial(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); BIGNUM *serial = bn_push(L); ASN1_INTEGER *i; if ((i = X509_get_serialNumber(crt))) { if (!ASN1_INTEGER_to_BN(i, serial)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:getSerial"); } return 1; } /* xc_getSerial() */ static int xc_setSerial(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); ASN1_INTEGER *serial; if (!(serial = BN_to_ASN1_INTEGER(checkbig(L, 2), NULL))) goto error; if (!X509_set_serialNumber(crt, serial)) goto error; ASN1_INTEGER_free(serial); lua_pushboolean(L, 1); return 1; error: ASN1_INTEGER_free(serial); return auxL_error(L, auxL_EOPENSSL, "x509.cert:setSerial"); } /* xc_setSerial() */ static int xc_digest(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); const char *type = luaL_optstring(L, 2, "sha1"); int format = luaL_checkoption(L, 3, "x", (const char *[]){ "s", "x", "n", NULL }); const EVP_MD *ctx; unsigned char md[EVP_MAX_MD_SIZE]; unsigned len; lua_settop(L, 3); /* self, type, hex */ if (!(ctx = EVP_get_digestbyname(type))) return luaL_error(L, "x509.cert:digest: %s: invalid digest type", type); X509_digest(crt, ctx, md, &len); switch (format) { case 2: { BIGNUM *bn = bn_push(L); if (!BN_bin2bn(md, len, bn)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:digest"); break; } case 1: { static const unsigned char x[16] = "0123456789abcdef"; luaL_Buffer B; unsigned i; luaL_buffinitsize(L, &B, 2 * len); for (i = 0; i < len; i++) { luaL_addchar(&B, x[0x0f & (md[i] >> 4)]); luaL_addchar(&B, x[0x0f & (md[i] >> 0)]); } luaL_pushresult(&B); break; } default: lua_pushlstring(L, (const char *)md, len); break; } /* switch() */ return 1; } /* xc_digest() */ static _Bool isleap(int year) { if (year >= 0) return !(year % 4) && ((year % 100) || !(year % 400)); else return isleap(-(year + 1)); } /* isleap() */ static int yday(int year, int mon, int mday) { static const int past[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int yday = past[CLAMP(mon, 0, 11)] + CLAMP(mday, 1, 31) - 1; return yday + (mon > 1 && isleap(year)); } /* yday() */ static int tm_yday(const struct tm *tm) { return (tm->tm_yday)? tm->tm_yday : yday(1900 + tm->tm_year, tm->tm_mon, tm->tm_mday); } /* tm_yday() */ static int leaps(int year) { if (year >= 0) return (year / 400) + (year / 4) - (year / 100); else return -(leaps(-(year + 1)) + 1); } /* leaps() */ static double tm2unix(const struct tm *tm, int gmtoff) { int year = tm->tm_year + 1900; double ts; ts = 86400.0 * 365.0 * (year - 1970); ts += 86400.0 * (leaps(year - 1) - leaps(1969)); ts += 86400 * tm_yday(tm); ts += 3600 * tm->tm_hour; ts += 60 * tm->tm_min; ts += CLAMP(tm->tm_sec, 0, 59); ts += (year < 1970)? gmtoff : -gmtoff; return ts; } /* tm2unix() */ static _Bool scan(int *i, char **cp, int n, int signok) { int sign = 1; *i = 0; if (signok) { if (**cp == '-') { sign = -1; ++*cp; } else if (**cp == '+') { ++*cp; } } while (n-- > 0) { if (**cp < '0' || **cp > '9') return 0; *i *= 10; *i += *(*cp)++ - '0'; } *i *= sign; return 1; } /* scan() */ static double timeutc(const ASN1_TIME *time) { char buf[32] = "", *cp; struct tm tm = { 0 }; int gmtoff = 0, year, i; if (!ASN1_TIME_check((ASN1_STRING *)time)) return 0; cp = strncpy(buf, (const char *)ASN1_STRING_get0_data((ASN1_STRING *)time), sizeof buf - 1); if (ASN1_STRING_type((ASN1_STRING *)time) == V_ASN1_GENERALIZEDTIME) { if (!scan(&year, &cp, 4, 1)) goto badfmt; } else { if (!scan(&year, &cp, 2, 0)) goto badfmt; year += (year < 50)? 2000 : 1900; } tm.tm_year = year - 1900; if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_mon = CLAMP(i, 1, 12) - 1; if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_mday = CLAMP(i, 1, 31); tm.tm_yday = yday(year, tm.tm_mon, tm.tm_mday); if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_hour = CLAMP(i, 0, 23); if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_min = CLAMP(i, 0, 59); if (*cp >= '0' && *cp <= '9') { if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_sec = CLAMP(i, 0, 59); } if (*cp == '+' || *cp == '-') { int sign = (*cp++ == '-')? -1 : 1; int hh, mm; if (!scan(&hh, &cp, 2, 0) || !scan(&mm, &cp, 2, 0)) goto badfmt; gmtoff = (CLAMP(hh, 0, 23) * 3600) + (CLAMP(mm, 0, 59) * 60); gmtoff *= sign; } return tm2unix(&tm, gmtoff); badfmt: return INFINITY; } /* timeutc() */ static int xc_getLifetime(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); double begin = INFINITY, end = INFINITY; const ASN1_TIME *time; if ((time = X509_get_notBefore(crt))) begin = timeutc(time); if ((time = X509_get_notAfter(crt))) end = timeutc(time); if (isfinite(begin)) lua_pushnumber(L, begin); else lua_pushnil(L); if (isfinite(end)) lua_pushnumber(L, end); else lua_pushnil(L); if (isfinite(begin) && isfinite(end) && begin <= end) lua_pushnumber(L, fabs(end - begin)); else lua_pushnumber(L, 0.0); return 3; } /* xc_getLifetime() */ static int xc_setLifetime(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); double ut; const char *dt; lua_settop(L, 3); if (lua_isnumber(L, 2)) { ut = lua_tonumber(L, 2); if (!ASN1_TIME_set(X509_get_notBefore(crt), ut)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #if 0 } else if ((dt = luaL_optstring(L, 2, 0))) { if (!ASN1_TIME_set_string(X509_get_notBefore(crt), dt)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #endif } if (lua_isnumber(L, 3)) { ut = lua_tonumber(L, 3); if (!ASN1_TIME_set(X509_get_notAfter(crt), ut)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #if 0 } else if ((dt = luaL_optstring(L, 3, 0))) { if (!ASN1_TIME_set_string(X509_get_notAfter(crt), dt)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setLifetime"); #endif } lua_pushboolean(L, 1); return 1; } /* xc_setLifetime() */ static int xc_getIssuer(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_NAME *name; if (!(name = X509_get_issuer_name(crt))) return 0; xn_dup(L, name); return 1; } /* xc_getIssuer() */ static int xc_setIssuer(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_set_issuer_name(crt, name)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setIssuer"); lua_pushboolean(L, 1); return 1; } /* xc_setIssuer() */ static int xc_getSubject(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_NAME *name; if (!(name = X509_get_subject_name(crt))) return 0; xn_dup(L, name); return 1; } /* xc_getSubject() */ static int xc_setSubject(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_set_subject_name(crt, name)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setSubject"); lua_pushboolean(L, 1); return 1; } /* xc_setSubject() */ static void xc_setCritical(X509 *crt, int nid, _Bool yes) { X509_EXTENSION *ext; int loc; if ((loc = X509_get_ext_by_NID(crt, nid, -1)) >= 0 && (ext = X509_get_ext(crt, loc))) X509_EXTENSION_set_critical(ext, yes); } /* xc_setCritical() */ static _Bool xc_getCritical(X509 *crt, int nid) { X509_EXTENSION *ext; int loc; if ((loc = X509_get_ext_by_NID(crt, nid, -1)) >= 0 && (ext = X509_get_ext(crt, loc))) return X509_EXTENSION_get_critical(ext); else return 0; } /* xc_getCritical() */ static int xc_getIssuerAlt(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); GENERAL_NAMES *gens; if (!(gens = X509_get_ext_d2i(crt, NID_issuer_alt_name, 0, 0))) return 0; gn_dup(L, gens); return 1; } /* xc_getIssuerAlt() */ static int xc_setIssuerAlt(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); GENERAL_NAMES *gens = checksimple(L, 2, X509_GENS_CLASS); if (!X509_add1_ext_i2d(crt, NID_issuer_alt_name, gens, 0, X509V3_ADD_REPLACE)) return auxL_error(L, auxL_EOPENSSL, "x509.altname:setIssuerAlt"); lua_pushboolean(L, 1); return 1; } /* xc_setIssuerAlt() */ static int xc_getSubjectAlt(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); GENERAL_NAMES *gens; if (!(gens = X509_get_ext_d2i(crt, NID_subject_alt_name, 0, 0))) return 0; gn_dup(L, gens); return 1; } /* xc_getSubjectAlt() */ static int xc_setSubjectAlt(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); GENERAL_NAMES *gens = checksimple(L, 2, X509_GENS_CLASS); if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, X509V3_ADD_REPLACE)) return auxL_error(L, auxL_EOPENSSL, "x509.altname:setSubjectAlt"); lua_pushboolean(L, 1); return 1; } /* xc_setSubjectAlt() */ static int xc_getIssuerAltCritical(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); lua_pushboolean(L, xc_getCritical(crt, NID_issuer_alt_name)); return 1; } /* xc_getIssuerAltCritical() */ static int xc_setIssuerAltCritical(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); luaL_checkany(L, 2); xc_setCritical(crt, NID_issuer_alt_name, lua_toboolean(L, 2)); lua_pushboolean(L, 1); return 1; } /* xc_setIssuerAltCritical() */ static int xc_getSubjectAltCritical(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); lua_pushboolean(L, xc_getCritical(crt, NID_subject_alt_name)); return 1; } /* xc_getSubjectAltCritical() */ static int xc_setSubjectAltCritical(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); luaL_checkany(L, 2); xc_setCritical(crt, NID_subject_alt_name, lua_toboolean(L, 2)); lua_pushboolean(L, 1); return 1; } /* xc_setSubjectAltCritical() */ static int xc_getBasicConstraint(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); BASIC_CONSTRAINTS *bs; int CA, pathLen; if (!(bs = X509_get_ext_d2i(crt, NID_basic_constraints, 0, 0))) { /* FIXME: detect error or just non-existent */ if (lua_gettop(L) > 1) return 0; lua_newtable(L); return 1; } CA = bs->ca; pathLen = ASN1_INTEGER_get(bs->pathlen); BASIC_CONSTRAINTS_free(bs); if (lua_gettop(L) > 1) { int n = 0, i, top; for (i = 2, top = lua_gettop(L); i <= top; i++) { switch (auxL_checkoption(L, i, 0, (const char *[]){ "CA", "pathLen", "pathLenConstraint", NULL }, 1)) { case 0: lua_pushboolean(L, CA); n++; break; case 1: /* FALL THROUGH */ case 2: lua_pushinteger(L, pathLen); n++; break; } } return n; } else { lua_newtable(L); lua_pushboolean(L, CA); lua_setfield(L, -2, "CA"); lua_pushinteger(L, pathLen); lua_setfield(L, -2, "pathLen"); return 1; } } /* xc_getBasicConstraint() */ static int xc_setBasicConstraint(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); BASIC_CONSTRAINTS *bs = 0; int CA = -1, pathLen = -1; int critical = 0; luaL_checkany(L, 2); if (lua_istable(L, 2)) { lua_getfield(L, 2, "CA"); if (!lua_isnil(L, -1)) CA = lua_toboolean(L, -1); lua_pop(L, 1); lua_getfield(L, 2, "pathLen"); pathLen = luaL_optinteger(L, -1, pathLen); lua_pop(L, 1); lua_getfield(L, 2, "pathLenConstraint"); pathLen = luaL_optinteger(L, -1, pathLen); lua_pop(L, 1); if (!(bs = BASIC_CONSTRAINTS_new())) goto error; } else { lua_settop(L, 3); switch (auxL_checkoption(L, 2, 0, (const char *[]){ "CA", "pathLen", "pathLenConstraint", NULL }, 1)) { case 0: luaL_checktype(L, 3, LUA_TBOOLEAN); CA = lua_toboolean(L, 3); break; case 1: /* FALL THROUGH */ case 2: pathLen = luaL_checkinteger(L, 3); break; } if (!(bs = X509_get_ext_d2i(crt, NID_basic_constraints, &critical, 0))) { /* FIXME: detect whether error or just non-existent */ if (!(bs = BASIC_CONSTRAINTS_new())) goto error; } } if (CA != -1) bs->ca = CA ? 0xFF : 0; /* use DER value */ if (pathLen >= 0) { ASN1_INTEGER_free(bs->pathlen); if (!(bs->pathlen = ASN1_STRING_type_new(V_ASN1_INTEGER))) goto error; if (!ASN1_INTEGER_set(bs->pathlen, pathLen)) goto error; } if (!X509_add1_ext_i2d(crt, NID_basic_constraints, bs, critical, X509V3_ADD_REPLACE)) goto error; BASIC_CONSTRAINTS_free(bs); lua_pushboolean(L, 1); return 1; error: BASIC_CONSTRAINTS_free(bs); return auxL_error(L, auxL_EOPENSSL, "x509.cert:setBasicConstraint"); } /* xc_setBasicConstraint() */ static int xc_getBasicConstraintsCritical(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); lua_pushboolean(L, xc_getCritical(crt, NID_basic_constraints)); return 1; } /* xc_getBasicConstraintsCritical() */ static int xc_setBasicConstraintsCritical(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); luaL_checkany(L, 2); xc_setCritical(crt, NID_basic_constraints, lua_toboolean(L, 2)); lua_pushboolean(L, 1); return 1; } /* xc_setBasicConstraintsCritical() */ static int xc_addExtension(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_EXTENSION *ext = checksimple(L, 2, X509_EXT_CLASS); /* NOTE: Will dup extension in X509v3_add_ext. */ if (!X509_add_ext(crt, ext, -1)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:addExtension"); lua_pushboolean(L, 1); return 1; } /* xc_addExtension() */ static int xc_setExtension(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_EXTENSION *ext = checksimple(L, 2, X509_EXT_CLASS); int nid, crit; void *value; nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext)); crit = X509_EXTENSION_get_critical(ext); value = X509_EXTENSION_get_data(ext); if (!X509_add1_ext_i2d(crt, nid, value, crit, X509V3_ADD_REPLACE)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setExtension"); lua_pushboolean(L, 1); return 1; } /* xc_setExtension() */ static int xc_getExtension(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_EXTENSION *ext = NULL, **ud; int i; luaL_checkany(L, 2); if (lua_type(L, 2) == LUA_TNUMBER) { /* NB: Lua 1-based indexing */ i = auxL_checkinteger(L, 2, 1, INT_MAX) - 1; } else { ASN1_OBJECT *obj; if (!auxS_txt2obj(&obj, luaL_checkstring(L, 2))) { goto error; } else if (!obj) { goto undef; } i = X509_get_ext_by_OBJ(crt, obj, -1); ASN1_OBJECT_free(obj); } ud = prepsimple(L, X509_EXT_CLASS); if (i < 0 || !(ext = X509_get0_ext(crt, i))) goto undef; if (!(*ud = X509_EXTENSION_dup(ext))) goto error; return 1; undef: return 0; error: return auxL_error(L, auxL_EOPENSSL, "x509.cert:getExtension"); } /* xc_getExtension() */ static int xc_getExtensionCount(lua_State *L) { auxL_pushinteger(L, X509_get_ext_count(checksimple(L, 1, X509_CERT_CLASS))); return 1; } /* xc_getExtensionCount() */ static int sk_openssl_string__gc(lua_State *L) { STACK_OF(OPENSSL_STRING) **res = lua_touserdata(L, 1); if (*res) { sk_OPENSSL_STRING_free(*res); *res = NULL; } return 0; } /* sk_openssl_string__gc() */ static int xc_getOCSP(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); STACK_OF(OPENSSL_STRING) **res = prepsimple(L, NULL, &sk_openssl_string__gc); int num, i; *res = X509_get1_ocsp(crt); if (!*res) return 0; num = sk_OPENSSL_STRING_num(*res); luaL_checkstack(L, num, "too many authorityInfoAccess"); for (i = 0; i < num; i++) { lua_pushstring(L, sk_OPENSSL_STRING_value(*res, i)); } sk_OPENSSL_STRING_free(*res); *res = NULL; return num; } /* xc_getOCSP */ static int xc_isIssuedBy(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509 *issuer = checksimple(L, 2, X509_CERT_CLASS); EVP_PKEY *key; int ok, why = 0; ERR_clear_error(); if (X509_V_OK != (why = X509_check_issued(issuer, crt))) goto done; if (!(key = X509_get_pubkey(issuer))) { why = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; goto done; } ok = (1 == X509_verify(crt, key)); EVP_PKEY_free(key); if (!ok) why = X509_V_ERR_CERT_SIGNATURE_FAILURE; done: if (why != X509_V_OK) { lua_pushboolean(L, 0); lua_pushstring(L, X509_verify_cert_error_string(why)); return 2; } else { lua_pushboolean(L, 1); return 1; } } /* xc_isIssuedBy() */ static int xc_getPublicKey(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); EVP_PKEY **key = prepsimple(L, PKEY_CLASS); if (!(*key = X509_get_pubkey(crt))) return auxL_error(L, auxL_EOPENSSL, "x509.cert:getPublicKey"); return 1; } /* xc_getPublicKey() */ static int xc_setPublicKey(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_set_pubkey(crt, key)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:setPublicKey"); lua_pushboolean(L, 1); return 1; } /* xc_setPublicKey() */ static int xc_getPublicKeyDigest(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); EVP_PKEY *key; const EVP_MD *md; ASN1_BIT_STRING *bitstr; unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int len; if (!(key = X509_get_pubkey(crt))) return luaL_argerror(L, 1, "no public key"); md = auxL_optdigest(L, 2, key, NULL); bitstr = X509_get0_pubkey_bitstr(crt); if (!EVP_Digest(bitstr->data, bitstr->length, digest, &len, md, NULL)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:getPublicKeyDigest"); lua_pushlstring(L, (char *)digest, len); return 1; } /* xc_getPublicKeyDigest() */ static int xc_getSignatureName(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); int nid; if (NID_undef == (nid = X509_get_signature_nid(crt))) return 0; auxL_pushnid(L, nid); return 1; } /* xc_getSignatureName() */ static int xc_sign(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_sign(crt, key, auxL_optdigest(L, 3, key, NULL))) return auxL_error(L, auxL_EOPENSSL, "x509.cert:sign"); lua_pushboolean(L, 1); return 1; } /* xc_sign() */ static int xc_verify(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); X509_STORE *store = NULL; STACK_OF(X509) *chain = NULL; X509_VERIFY_PARAM *params = NULL; X509_STORE_CTX *ctx = NULL; int ok, why; STACK_OF(X509) **proof; if (lua_istable(L, 2)) { if (lua_getfield(L, 2, "store") != LUA_TNIL) { store = checksimple(L, -1, X509_STORE_CLASS); } else if (!(OPENSSL_PREREQ(1,0,2) || LIBRESSL_PREREQ(2,7,5))) { /* Without .store OpenSSL 1.0.1 crashes e.g. #0 X509_STORE_get_by_subject (vs=vs@entry=0x6731b0, type=type@entry=1, name=name@entry=0x66a360, ret=ret@entry=0x7fffffffe580) at x509_lu.c:293 #1 0x00007ffff69653ca in X509_STORE_CTX_get1_issuer (issuer=0x7fffffffe620, ctx=0x6731b0, x=0x665db0) at x509_lu.c:604 #2 0x00007ffff696117c in X509_verify_cert (ctx=ctx@entry=0x6731b0) at x509_vfy.c:256 Was fixed in LibreSSL somewhere between 2.6.5 and 2.7.5 */ luaL_argerror(L, 2, ".store required in OpenSSL <= 1.0.1"); } lua_pop(L, 1); if (lua_getfield(L, 2, "chain") != LUA_TNIL) { chain = checksimple(L, -1, X509_CHAIN_CLASS); } lua_pop(L, 1); if (lua_getfield(L, 2, "params") != LUA_TNIL) { params = checksimple(L, -1, X509_VERIFY_PARAM_CLASS); } lua_pop(L, 1); if (lua_getfield(L, 2, "crls") != LUA_TNIL) { luaL_argerror(L, 2, "crls not yet supported"); } lua_pop(L, 1); if (lua_getfield(L, 2, "dane") != LUA_TNIL) { luaL_argerror(L, 2, "dane not yet supported"); } lua_pop(L, 1); } /* pre-allocate space for a successful return */ proof = prepsimple(L, X509_CHAIN_CLASS); if (chain && !(chain = X509_chain_up_ref(chain))) goto eossl; if (!(ctx = X509_STORE_CTX_new()) || !X509_STORE_CTX_init(ctx, store, crt, chain)) { sk_X509_pop_free(chain, X509_free); goto eossl; } if (params) { X509_VERIFY_PARAM *params_copy = X509_VERIFY_PARAM_new(); if (!params_copy) goto eossl; ok = X509_VERIFY_PARAM_inherit(params_copy, params); if (!ok) { X509_VERIFY_PARAM_free(params_copy); goto eossl; } X509_STORE_CTX_set0_param(ctx, params_copy); } ERR_clear_error(); ok = X509_verify_cert(ctx); switch (ok) { case 1: /* verified */ if (!(*proof = X509_STORE_CTX_get1_chain(ctx))) goto eossl; X509_STORE_CTX_free(ctx); lua_pushboolean(L, 1); lua_pushvalue(L, -2); return 2; case 0: /* not verified */ why = X509_STORE_CTX_get_error(ctx); X509_STORE_CTX_free(ctx); lua_pushboolean(L, 0); lua_pushstring(L, X509_verify_cert_error_string(why)); return 2; default: goto eossl; } eossl: if (ctx) X509_STORE_CTX_free(ctx); return auxL_error(L, auxL_EOPENSSL, "x509.cert:verify"); } /* xc_verify() */ static int xc_text(lua_State *L) { static const struct { const char *kw; unsigned int flag; } map[] = { { "no_header", X509_FLAG_NO_HEADER }, { "no_version", X509_FLAG_NO_VERSION }, { "no_serial", X509_FLAG_NO_SERIAL }, { "no_signame", X509_FLAG_NO_SIGNAME }, { "no_validity", X509_FLAG_NO_VALIDITY }, { "no_subject", X509_FLAG_NO_SUBJECT }, { "no_issuer", X509_FLAG_NO_ISSUER }, { "no_pubkey", X509_FLAG_NO_PUBKEY }, { "no_extensions", X509_FLAG_NO_EXTENSIONS }, { "no_sigdump", X509_FLAG_NO_SIGDUMP }, { "no_aux", X509_FLAG_NO_AUX }, { "no_attributes", X509_FLAG_NO_ATTRIBUTES }, { "ext_default", X509V3_EXT_DEFAULT }, { "ext_error", X509V3_EXT_ERROR_UNKNOWN }, { "ext_parse", X509V3_EXT_PARSE_UNKNOWN }, { "ext_dump", X509V3_EXT_DUMP_UNKNOWN } }; lua_settop(L, 2); X509 *crt = checksimple(L, 1, X509_CERT_CLASS); unsigned int flags = 0; const char *kw; int found; unsigned int i; BIO *bio = getbio(L); char *data; long len; if (!lua_isnil(L, 2)) { lua_pushnil(L); while (lua_next(L, 2)) { kw = luaL_checkstring(L, -1); found = 0; for (i = 0; i < countof(map); i++) if (!strcmp(kw, map[i].kw)) { flags |= map[i].flag; found = 1; } if (!found) luaL_argerror(L, 2, lua_pushfstring(L, "invalid flag: %s", kw)); lua_pop(L, 1); } } if (!X509_print_ex(bio, crt, 0, flags)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:text"); len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* xc_text() */ static int xc_toPEM(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); BIO *bio = getbio(L); size_t len; char *bytes; if (!PEM_write_bio_X509(bio, crt)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:toPEM"); len = BIO_get_mem_data(bio, &bytes); lua_pushlstring(L, bytes, len); return 1; } /* xc_toPEM() */ static int xc__tostring(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); int type = optencoding(L, 2, "pem", X509_PEM|X509_DER); BIO *bio = getbio(L); char *data; long len; switch (type) { case X509_PEM: if (!PEM_write_bio_X509(bio, crt)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:__tostring"); break; case X509_DER: if (!i2d_X509_bio(bio, crt)) return auxL_error(L, auxL_EOPENSSL, "x509.cert:__tostring"); break; } /* switch() */ len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* xc__tostring() */ static int xc__gc(lua_State *L) { X509 **ud = luaL_checkudata(L, 1, X509_CERT_CLASS); if (*ud) { X509_free(*ud); *ud = NULL; } return 0; } /* xc__gc() */ static const auxL_Reg xc_methods[] = { { "getVersion", &xc_getVersion }, { "setVersion", &xc_setVersion }, { "getSerial", &xc_getSerial }, { "setSerial", &xc_setSerial }, { "digest", &xc_digest }, { "getLifetime", &xc_getLifetime }, { "setLifetime", &xc_setLifetime }, { "getIssuer", &xc_getIssuer }, { "setIssuer", &xc_setIssuer }, { "getSubject", &xc_getSubject }, { "setSubject", &xc_setSubject }, { "getIssuerAlt", &xc_getIssuerAlt }, { "setIssuerAlt", &xc_setIssuerAlt }, { "getSubjectAlt", &xc_getSubjectAlt }, { "setSubjectAlt", &xc_setSubjectAlt }, { "getIssuerAltCritical", &xc_getIssuerAltCritical }, { "setIssuerAltCritical", &xc_setIssuerAltCritical }, { "getSubjectAltCritical", &xc_getSubjectAltCritical }, { "setSubjectAltCritical", &xc_setSubjectAltCritical }, { "getBasicConstraints", &xc_getBasicConstraint }, { "getBasicConstraint", &xc_getBasicConstraint }, { "setBasicConstraints", &xc_setBasicConstraint }, { "setBasicConstraint", &xc_setBasicConstraint }, { "getBasicConstraintsCritical", &xc_getBasicConstraintsCritical }, { "setBasicConstraintsCritical", &xc_setBasicConstraintsCritical }, { "addExtension", &xc_addExtension }, { "setExtension", &xc_setExtension }, { "getExtension", &xc_getExtension }, { "getExtensionCount", &xc_getExtensionCount }, { "getOCSP", &xc_getOCSP }, { "isIssuedBy", &xc_isIssuedBy }, { "getPublicKey", &xc_getPublicKey }, { "setPublicKey", &xc_setPublicKey }, { "getPublicKeyDigest", &xc_getPublicKeyDigest }, { "getSignatureName", &xc_getSignatureName }, { "sign", &xc_sign }, { "verify", &xc_verify }, { "text", &xc_text }, { "toPEM", &xc_toPEM }, { "tostring", &xc__tostring }, { NULL, NULL }, }; static const auxL_Reg xc_metatable[] = { { "__tostring", &xc__tostring }, { "__gc", &xc__gc }, { NULL, NULL }, }; static const auxL_Reg xc_globals[] = { { "new", &xc_new }, { "interpose", &xc_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_cert(lua_State *L) { initall(L); auxL_newlib(L, xc_globals, 0); return 1; } /* luaopen__openssl_x509_cert() */ /* * X509_REQ - openssl.x509.csr * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int xr_new(lua_State *L) { const char *data; size_t len; X509_REQ **ud; X509 *crt; lua_settop(L, 2); ud = prepsimple(L, X509_CSR_CLASS); if ((crt = testsimple(L, 1, X509_CERT_CLASS))) { if (!(*ud = X509_to_X509_REQ(crt, 0, 0))) return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); } else if ((data = luaL_optlstring(L, 1, NULL, &len))) { int type = optencoding(L, 2, "*", X509_ANY|X509_PEM|X509_DER); BIO *tmp; int ok = 0; if (!(tmp = BIO_new_mem_buf((char *)data, len))) return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); if (type == X509_PEM || type == X509_ANY) { ok = !!(*ud = PEM_read_bio_X509_REQ(tmp, NULL, 0, "")); /* no password */ } if (!ok && (type == X509_DER || type == X509_ANY)) { BIO_reset(tmp); ok = !!(*ud = d2i_X509_REQ_bio(tmp, NULL)); } BIO_free(tmp); if (!ok) return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); } else { if (!(*ud = X509_REQ_new())) return auxL_error(L, auxL_EOPENSSL, "x509.csr.new"); } return 1; } /* xr_new() */ static int xr_interpose(lua_State *L) { return interpose(L, X509_CSR_CLASS); } /* xr_interpose() */ static int xr_getVersion(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); lua_pushinteger(L, X509_REQ_get_version(csr) + 1); return 1; } /* xr_getVersion() */ static int xr_setVersion(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); int version = luaL_checkinteger(L, 2); if (!X509_REQ_set_version(csr, version - 1)) return luaL_error(L, "x509.csr:setVersion: %d: invalid version", version); lua_pushboolean(L, 1); return 1; } /* xr_setVersion() */ static int xr_getSubject(lua_State *L) { X509_REQ *crt = checksimple(L, 1, X509_CSR_CLASS); X509_NAME *name; if (!(name = X509_REQ_get_subject_name(crt))) return 0; xn_dup(L, name); return 1; } /* xr_getSubject() */ static int xr_setSubject(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_REQ_set_subject_name(csr, name)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:setSubject"); lua_pushboolean(L, 1); return 1; } /* xr_setSubject() */ static int xr_getPublicKey(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); EVP_PKEY **key = prepsimple(L, PKEY_CLASS); if (!(*key = X509_REQ_get_pubkey(csr))) return auxL_error(L, auxL_EOPENSSL, "x509.csr:getPublicKey"); return 1; } /* xr_getPublicKey() */ static int xr_setPublicKey(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_REQ_set_pubkey(csr, key)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:setPublicKey"); lua_pushboolean(L, 1); return 1; } /* xr_setPublicKey() */ static int xr_modifyRequestedExtension(X509_REQ *csr, int target_nid, int crit, void* value, unsigned long flags) { STACK_OF(X509_EXTENSION) *sk = NULL; int has_attrs=0; /* * Replace existing if it's there. Extensions are stored in a CSR in * an interesting way: * * They are stored as a list under either (most likely) the * "official" NID_ext_req or under NID_ms_ext_req which means * everything is stored under a list in a single "attribute" so we * can't use X509_REQ_add1_attr or similar. * * Instead we have to get the extensions, find and replace the extension * if it's in there, then *replace* the extensions in the list of * attributes. (If we just try to add it the old ones are found * first and don't take priority.) */ has_attrs = X509_REQ_get_attr_count(csr); sk = X509_REQ_get_extensions(csr); if (!X509V3_add1_i2d(&sk, target_nid, value, crit, flags)) goto error; if (X509_REQ_add_extensions(csr, sk) == 0) goto error; sk_X509_EXTENSION_pop_free(sk, X509_EXTENSION_free); sk = NULL; /* * Delete the old extensions attribute, so that the one we just * added takes priority. */ if (has_attrs) { X509_ATTRIBUTE *attr = NULL; int idx, *pnid; for (pnid = X509_REQ_get_extension_nids(); *pnid != NID_undef; pnid++) { idx = X509_REQ_get_attr_by_NID(csr, *pnid, -1); if (idx == -1) continue; if (!(attr = X509_REQ_delete_attr(csr, idx))) goto error; X509_ATTRIBUTE_free(attr); break; } if (!attr) goto error; } /* * We have to mark the encoded form as invalid, otherwise when we * write it out again it will use the loaded version. */ #if HAVE_I2D_RE_X509_REQ_TBS (void)i2d_re_X509_REQ_tbs(csr, NULL); /* sets csr->req_info->enc.modified */ #else csr->req_info->enc.modified = 1; #endif return 0; error: if (sk) sk_X509_EXTENSION_pop_free(sk, X509_EXTENSION_free); return 1; } /* xr_modifyRequestedExtension() */ static int xr_setSubjectAlt(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); GENERAL_NAMES *gens = checksimple(L, 2, X509_GENS_CLASS); if (xr_modifyRequestedExtension(csr, NID_subject_alt_name, 0, gens, X509V3_ADD_REPLACE)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:setSubjectAlt"); lua_pushboolean(L, 1); return 1; } /* xr_setSubjectAlt */ static int xr_getSubjectAlt(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); STACK_OF(X509_EXTENSION) *exts; GENERAL_NAMES *gens; exts = X509_REQ_get_extensions(csr); gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); if (!gens) goto error; gn_dup(L, gens); return 1; error: return 0; } /* xr_getSubjectAlt() */ static int xr_addRequestedExtension(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); X509_EXTENSION *ext = checksimple(L, 2, X509_EXT_CLASS); int nid, crit; void *value; nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext)); crit = X509_EXTENSION_get_critical(ext); value = X509_EXTENSION_get_data(ext); if (xr_modifyRequestedExtension(csr, nid, crit, value, X509V3_ADD_APPEND)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:addRequestedExtension"); lua_pushboolean(L, 1); return 1; } /* xr_addRequestedExtension() */ static int xr_setRequestedExtension(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); X509_EXTENSION *ext = checksimple(L, 2, X509_EXT_CLASS); int nid, crit; void *value; nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext)); crit = X509_EXTENSION_get_critical(ext); value = X509_EXTENSION_get_data(ext); if (xr_modifyRequestedExtension(csr, nid, crit, value, X509V3_ADD_REPLACE)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:setRequestedExtension"); lua_pushboolean(L, 1); return 1; } /* xr_setRequestedExtension() */ static int xr_getRequestedExtension(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); STACK_OF(X509_EXTENSION) *exts = NULL; X509_EXTENSION *ext = NULL, **ud; int i; luaL_checkany(L, 2); ud = prepsimple(L, X509_EXT_CLASS); if (lua_type(L, 2) == LUA_TNUMBER) { /* NB: Lua 1-based indexing */ i = auxL_checkinteger(L, 2, 1, INT_MAX) - 1; exts = X509_REQ_get_extensions(csr); } else { ASN1_OBJECT *obj; if (!auxS_txt2obj(&obj, luaL_checkstring(L, 2))) { goto error; } else if (!obj) { goto undef; } exts = X509_REQ_get_extensions(csr); i = X509v3_get_ext_by_OBJ(exts, obj, -1); ASN1_OBJECT_free(obj); } if (i < 0 || !(ext = X509v3_get_ext(exts, i))) goto undef; if (!(*ud = X509_EXTENSION_dup(ext))) goto error; sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); exts = NULL; return 1; undef: if (exts) sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); return 0; error: if (exts) sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); return auxL_error(L, auxL_EOPENSSL, "x509.csr:getRequestedExtension"); } /* xr_getRequestedExtension() */ static int xr_getRequestedExtensionCount(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); STACK_OF(X509_EXTENSION) *exts = NULL; auxL_Integer len = 0; exts = X509_REQ_get_extensions(csr); len = sk_X509_EXTENSION_num(exts); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); auxL_pushinteger(L, len); return 1; } /* xr_getRequestedExtensionCount() */ static int xr_sign(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_REQ_sign(csr, key, auxL_optdigest(L, 3, key, NULL))) return auxL_error(L, auxL_EOPENSSL, "x509.csr:sign"); lua_pushboolean(L, 1); return 1; } /* xr_sign() */ static int xr_toPEM(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); BIO *bio = getbio(L); size_t len; char *bytes; if (!PEM_write_bio_X509_REQ(bio, csr)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:toPEM"); len = BIO_get_mem_data(bio, &bytes); lua_pushlstring(L, bytes, len); return 1; } /* xr_toPEM() */ static int xr__tostring(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); int type = optencoding(L, 2, "pem", X509_PEM|X509_DER); BIO *bio = getbio(L); char *data; long len; switch (type) { case X509_PEM: if (!PEM_write_bio_X509_REQ(bio, csr)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:__tostring"); break; case X509_DER: if (!i2d_X509_REQ_bio(bio, csr)) return auxL_error(L, auxL_EOPENSSL, "x509.csr:__tostring"); break; } /* switch() */ len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* xr__tostring() */ static int xr__gc(lua_State *L) { X509_REQ **ud = luaL_checkudata(L, 1, X509_CSR_CLASS); if (*ud) { X509_REQ_free(*ud); *ud = NULL; } return 0; } /* xr__gc() */ static const auxL_Reg xr_methods[] = { { "getVersion", &xr_getVersion }, { "setVersion", &xr_setVersion }, { "getSubject", &xr_getSubject }, { "setSubject", &xr_setSubject }, { "getPublicKey", &xr_getPublicKey }, { "setPublicKey", &xr_setPublicKey }, { "getSubjectAlt", &xr_getSubjectAlt }, { "setSubjectAlt", &xr_setSubjectAlt }, { "getRequestedExtension", &xr_getRequestedExtension }, { "getRequestedExtensionCount", &xr_getRequestedExtensionCount }, { "addRequestedExtension", &xr_addRequestedExtension }, { "setRequestedExtension", &xr_setRequestedExtension }, { "sign", &xr_sign }, { "toPEM", &xr_toPEM }, { "tostring", &xr__tostring }, { NULL, NULL }, }; static const auxL_Reg xr_metatable[] = { { "__tostring", &xr__tostring }, { "__gc", &xr__gc }, { NULL, NULL }, }; static const auxL_Reg xr_globals[] = { { "new", &xr_new }, { "interpose", &xr_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_csr(lua_State *L) { initall(L); auxL_newlib(L, xr_globals, 0); return 1; } /* luaopen__openssl_x509_csr() */ /* * X509_CRL - openssl.x509.crl * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int xx_new(lua_State *L) { const char *data; size_t len; X509_CRL **ud; lua_settop(L, 2); ud = prepsimple(L, X509_CRL_CLASS); if ((data = luaL_optlstring(L, 1, NULL, &len))) { int type = optencoding(L, 2, "*", X509_ANY|X509_PEM|X509_DER); BIO *tmp; int ok = 0; if (!(tmp = BIO_new_mem_buf((char *)data, len))) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); if (type == X509_PEM || type == X509_ANY) { ok = !!(*ud = PEM_read_bio_X509_CRL(tmp, NULL, 0, "")); /* no password */ } if (!ok && (type == X509_DER || type == X509_ANY)) { BIO_reset(tmp); ok = !!(*ud = d2i_X509_CRL_bio(tmp, NULL)); } BIO_free(tmp); if (!ok) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); } else { ASN1_TIME *tm; if (!(*ud = X509_CRL_new())) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); /* initialize last updated time to now */ if (!(tm = ASN1_TIME_set(NULL, time(NULL)))) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); if (!X509_CRL_set1_lastUpdate(*ud, tm)) { ASN1_TIME_free(tm); return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); } ASN1_TIME_free(tm); } return 1; } /* xx_new() */ static int xx_interpose(lua_State *L) { return interpose(L, X509_CRL_CLASS); } /* xx_interpose() */ static int xx_getVersion(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); lua_pushinteger(L, X509_CRL_get_version(crl) + 1); return 1; } /* xx_getVersion() */ static int xx_setVersion(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); int version = luaL_checkinteger(L, 2); if (!X509_CRL_set_version(crl, version - 1)) return luaL_error(L, "x509.crl:setVersion: %d: invalid version", version); lua_pushboolean(L, 1); return 1; } /* xx_setVersion() */ static int xx_getLastUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updated = INFINITY; const ASN1_TIME *time; if ((time = X509_CRL_get0_lastUpdate(crl))) updated = timeutc(time); if (isfinite(updated)) lua_pushnumber(L, updated); else lua_pushnil(L); return 1; } /* xx_getLastUpdate() */ static int xx_setLastUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updated = luaL_checknumber(L, 2); ASN1_TIME *time; if (!(time = ASN1_TIME_set(NULL, updated))) goto error; if (!X509_CRL_set1_lastUpdate(crl, time)) goto error; lua_pushboolean(L, 1); return 1; error: ASN1_TIME_free(time); return auxL_error(L, auxL_EOPENSSL, "x509.crl:setLastUpdate"); } /* xx_setLastUpdate() */ static int xx_getNextUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updateby = INFINITY; const ASN1_TIME *time; if ((time = X509_CRL_get0_nextUpdate(crl))) updateby = timeutc(time); if (isfinite(updateby)) lua_pushnumber(L, updateby); else lua_pushnil(L); return 1; } /* xx_getNextUpdate() */ static int xx_setNextUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updateby = luaL_checknumber(L, 2); ASN1_TIME *time; if (!(time = ASN1_TIME_set(NULL, updateby))) goto error; if (!X509_CRL_set1_nextUpdate(crl, time)) goto error; lua_pushboolean(L, 1); return 1; error: ASN1_TIME_free(time); return auxL_error(L, auxL_EOPENSSL, "x509.crl:setNextUpdate"); } /* xx_setNextUpdate() */ static int xx_getIssuer(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); X509_NAME *name; if (!(name = X509_CRL_get_issuer(crl))) return 0; xn_dup(L, name); return 1; } /* xx_getIssuer() */ static int xx_setIssuer(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_CRL_set_issuer_name(crl, name)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:setIssuer"); lua_pushboolean(L, 1); return 1; } /* xx_setIssuer() */ static int xx_add(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); BIGNUM *bn = checkbig(L, 2); double ut = luaL_optnumber(L, 3, time(NULL)); X509_REVOKED *rev = NULL; ASN1_INTEGER *serial = NULL; ASN1_TIME *date = NULL; if (!(rev = X509_REVOKED_new())) goto error; if (!(serial = BN_to_ASN1_INTEGER(bn, NULL))) goto error; if (!X509_REVOKED_set_serialNumber(rev, serial)) /* duplicates serial */ goto error; ASN1_INTEGER_free(serial); serial = NULL; if (!(date = ASN1_TIME_new())) goto error; if (!ASN1_TIME_set(date, ut)) goto error; if (!X509_REVOKED_set_revocationDate(rev, date)) /* duplicates date */ goto error; ASN1_TIME_free(date); date = NULL; if (!X509_CRL_add0_revoked(crl, rev)) /* takes ownership of rev */ goto error; lua_pushboolean(L, 1); return 1; error: if (date) ASN1_TIME_free(date); if (serial) ASN1_INTEGER_free(serial); if (rev) X509_REVOKED_free(rev); return auxL_error(L, auxL_EOPENSSL, "x509.crl:add"); } /* xx_add() */ #if HAVE_X509_CRL_GET0_BY_SERIAL static int xx_lookupSerial(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); ASN1_INTEGER *serial; int status; if (!(serial = BN_to_ASN1_INTEGER(checkbig(L, 2), NULL))) return auxL_error(L, auxL_EOPENSSL, "x509.crl:lookupSerial"); status = X509_CRL_get0_by_serial(crl, NULL, serial); ASN1_INTEGER_free(serial); switch(status) { case 0: /* failure (not on CRL) */ lua_pushnil(L); return 1; case 1: /* succeeds (on CRL) */ lua_pushboolean(L, 1); return 1; case 2: /* *was* on CRL, but not any more */ lua_pushboolean(L, 0); return 1; default: return luaL_error(L, "x509.crl:lookupSerial: unexpected return value"); } } /* xx_lookupSerial() */ #endif #if HAVE_X509_CRL_GET0_BY_CERT static int xx_lookupCertificate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); X509 *crt = checksimple(L, 2, X509_CERT_CLASS); switch(X509_CRL_get0_by_cert(crl, NULL, crt)) { case 0: /* failure (not on CRL) */ lua_pushnil(L); return 1; case 1: /* succeeds (on CRL) */ lua_pushboolean(L, 1); return 1; case 2: /* *was* on CRL, but not any more */ lua_pushboolean(L, 0); return 1; default: return luaL_error(L, "x509.crl:lookupCertificate: unexpected return value"); } } /* xx_lookupCertificate() */ #endif static int xx_addExtension(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); X509_EXTENSION *ext = checksimple(L, 2, X509_EXT_CLASS); /* NOTE: Will dup extension in X509v3_add_ext. */ if (!X509_CRL_add_ext(crl, ext, -1)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:addExtension"); lua_pushboolean(L, 1); return 1; } /* xx_addExtension() */ static int xx_setExtension(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); X509_EXTENSION *ext = checksimple(L, 2, X509_EXT_CLASS); int nid, crit; void *value; nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext)); crit = X509_EXTENSION_get_critical(ext); value = X509_EXTENSION_get_data(ext); if (!X509_CRL_add1_ext_i2d(crl, nid, value, crit, X509V3_ADD_REPLACE)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:setExtension"); lua_pushboolean(L, 1); return 1; } /* xx_setExtension() */ static int xx_getExtension(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); X509_EXTENSION *ext = NULL, **ud; int i; luaL_checkany(L, 2); if (lua_type(L, 2) == LUA_TNUMBER) { /* NB: Lua 1-based indexing */ i = auxL_checkinteger(L, 2, 1, INT_MAX) - 1; } else { ASN1_OBJECT *obj; if (!auxS_txt2obj(&obj, luaL_checkstring(L, 2))) { goto error; } else if (!obj) { goto undef; } i = X509_CRL_get_ext_by_OBJ(crl, obj, -1); ASN1_OBJECT_free(obj); } ud = prepsimple(L, X509_EXT_CLASS); if (i < 0 || !(ext = X509_CRL_get0_ext(crl, i))) goto undef; if (!(*ud = X509_EXTENSION_dup(ext))) goto error; return 1; undef: return 0; error: return auxL_error(L, auxL_EOPENSSL, "x509.crl:getExtension"); } /* xx_getExtension() */ static int xx_getExtensionCount(lua_State *L) { auxL_pushinteger(L, X509_CRL_get_ext_count(checksimple(L, 1, X509_CRL_CLASS))); return 1; } /* xx_getExtensionCount() */ static int xx_sign(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_CRL_sign(crl, key, auxL_optdigest(L, 3, key, NULL))) return auxL_error(L, auxL_EOPENSSL, "x509.crl:sign"); lua_pushboolean(L, 1); return 1; } /* xx_sign() */ static int xx_verify(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); if (!X509_CRL_verify(crl, key)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:verify"); lua_pushboolean(L, 1); return 1; } /* xx_verify() */ static int xx_text(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); BIO *bio = getbio(L); char *data; long len; if (!X509_CRL_print(bio, crl)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:text"); len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* xx_text() */ static int xx_toPEM(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); BIO *bio = getbio(L); size_t len; char *bytes; if (!PEM_write_bio_X509_CRL(bio, crl)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:toPEM"); len = BIO_get_mem_data(bio, &bytes); lua_pushlstring(L, bytes, len); return 1; } /* xx_toPEM() */ static int xx__tostring(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); int type = optencoding(L, 2, "pem", X509_PEM|X509_DER); BIO *bio = getbio(L); char *data; long len; switch (type) { case X509_PEM: if (!PEM_write_bio_X509_CRL(bio, crl)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:__tostring"); break; case X509_DER: if (!i2d_X509_CRL_bio(bio, crl)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:__tostring"); break; } /* switch() */ len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* xx__tostring() */ static int xx__gc(lua_State *L) { X509_CRL **ud = luaL_checkudata(L, 1, X509_CRL_CLASS); if (*ud) { X509_CRL_free(*ud); *ud = NULL; } return 0; } /* xx__gc() */ static const auxL_Reg xx_methods[] = { { "getVersion", &xx_getVersion }, { "setVersion", &xx_setVersion }, { "getLastUpdate", &xx_getLastUpdate }, { "setLastUpdate", &xx_setLastUpdate }, { "getNextUpdate", &xx_getNextUpdate }, { "setNextUpdate", &xx_setNextUpdate }, { "getIssuer", &xx_getIssuer }, { "setIssuer", &xx_setIssuer }, { "add", &xx_add }, #if HAVE_X509_CRL_GET0_BY_SERIAL { "lookupSerial", &xx_lookupSerial }, #endif #if HAVE_X509_CRL_GET0_BY_CERT { "lookupCertificate", &xx_lookupCertificate }, #endif { "addExtension", &xx_addExtension }, { "setExtension", &xx_setExtension }, { "getExtension", &xx_getExtension }, { "getExtensionCount", &xx_getExtensionCount }, { "sign", &xx_sign }, { "verify", &xx_verify }, { "text", &xx_text }, { "toPEM", &xx_toPEM }, { "tostring", &xx__tostring }, { NULL, NULL }, }; static const auxL_Reg xx_metatable[] = { { "__tostring", &xx__tostring }, { "__gc", &xx__gc }, { NULL, NULL }, }; static const auxL_Reg xx_globals[] = { { "new", &xx_new }, { "interpose", &xx_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_crl(lua_State *L) { initall(L); auxL_newlib(L, xx_globals, 0); return 1; } /* luaopen__openssl_x509_crl() */ /* * STACK_OF(X509) - openssl.x509.chain * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void xl_dup(lua_State *L, STACK_OF(X509) *src, _Bool copy) { STACK_OF(X509) **dst = prepsimple(L, X509_CHAIN_CLASS); if (copy) { int i, n; if (!(*dst = sk_X509_new_null())) goto error; n = sk_X509_num(src); for (i = 0; i < n; i++) { X509 *crt; if (!(crt = sk_X509_value(src, i))) continue; if (!(crt = X509_dup(crt))) goto error; if (!sk_X509_push(*dst, crt)) { X509_free(crt); goto error; } } } else { if (!(*dst = X509_chain_up_ref(src))) goto error; } return; error: auxL_error(L, auxL_EOPENSSL, "xl_dup"); } /* xl_dup() */ static int xl_new(lua_State *L) { STACK_OF(X509) **chain = prepsimple(L, X509_CHAIN_CLASS); if (!(*chain = sk_X509_new_null())) return auxL_error(L, auxL_EOPENSSL, "x509.chain.new"); return 1; } /* xl_new() */ static int xl_interpose(lua_State *L) { return interpose(L, X509_CHAIN_CLASS); } /* xl_interpose() */ static int xl_add(lua_State *L) { STACK_OF(X509) *chain = checksimple(L, 1, X509_CHAIN_CLASS); X509 *crt = checksimple(L, 2, X509_CERT_CLASS); X509 *dup; if (!(dup = X509_dup(crt))) return auxL_error(L, auxL_EOPENSSL, "x509.chain:add"); if (!sk_X509_push(chain, dup)) { X509_free(dup); return auxL_error(L, auxL_EOPENSSL, "x509.chain:add"); } lua_pushvalue(L, 1); return 1; } /* xl_add() */ static int xl__next(lua_State *L) { STACK_OF(X509) *chain = checksimple(L, lua_upvalueindex(1), X509_CHAIN_CLASS); int i = lua_tointeger(L, lua_upvalueindex(2)); int n = sk_X509_num(chain); lua_settop(L, 0); while (i < n) { X509 *crt, **ret; if (!(crt = sk_X509_value(chain, i++))) continue; lua_pushinteger(L, i); xc_dup(L, crt); break; } lua_pushinteger(L, i); lua_replace(L, lua_upvalueindex(2)); return lua_gettop(L); } /* xl__next() */ static int xl__pairs(lua_State *L) { lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, &xl__next, 2); return 1; } /* xl__pairs() */ static int xl__gc(lua_State *L) { STACK_OF(X509) **chain = luaL_checkudata(L, 1, X509_CHAIN_CLASS); if (*chain) { sk_X509_pop_free(*chain, X509_free); *chain = NULL; } return 0; } /* xl__gc() */ static const auxL_Reg xl_methods[] = { { "add", &xl_add }, { NULL, NULL }, }; static const auxL_Reg xl_metatable[] = { { "__pairs", &xl__pairs }, { "__ipairs", &xl__pairs }, { "__gc", &xl__gc }, { NULL, NULL }, }; static const auxL_Reg xl_globals[] = { { "new", &xl_new }, { "interpose", &xl_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_chain(lua_State *L) { initall(L); auxL_newlib(L, xl_globals, 0); return 1; } /* luaopen__openssl_x509_chain() */ /* * X509_STORE - openssl.x509.store * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int xs_new(lua_State *L) { X509_STORE **ud = prepsimple(L, X509_STORE_CLASS); if (!(*ud = X509_STORE_new())) return auxL_error(L, auxL_EOPENSSL, "x509.store"); return 1; } /* xs_new() */ static X509_STORE *xs_push(lua_State *L, X509_STORE *store) { X509_STORE **ud = prepsimple(L, X509_STORE_CLASS); X509_STORE_up_ref(store); *ud = store; return *ud; } /* xs_push() */ static int xs_interpose(lua_State *L) { return interpose(L, X509_STORE_CLASS); } /* xs_interpose() */ static int xs_add(lua_State *L) { X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); int i, top = lua_gettop(L); X509 *crt, *crt_dup; X509_CRL *crl, *crl_dup; for (i = 2; i <= top; i++) { if ((crt = testsimple(L, i, X509_CERT_CLASS))) { if (!(crt_dup = X509_dup(crt))) return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); if (!X509_STORE_add_cert(store, crt_dup)) { X509_free(crt_dup); return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); } } else if ((crl = testsimple(L, i, X509_CRL_CLASS))) { if (!(crl_dup = X509_CRL_dup(crl))) return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); if (!X509_STORE_add_crl(store, crl_dup)) { X509_CRL_free(crl_dup); return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); } } else { const char *path = luaL_checkstring(L, i); struct stat st; int ok; if (0 != stat(path, &st)) return luaL_error(L, "%s: %s", path, aux_strerror(errno)); if (S_ISDIR(st.st_mode)) ok = X509_STORE_load_locations(store, NULL, path); else { /* X509_STORE_load_locations on a file returns 0 if no certs were found */ ERR_clear_error(); ok = X509_STORE_load_locations(store, path, NULL); if (ok == 0 && !ERR_peek_error()) ok = 1; } if (!ok) return auxL_error(L, auxL_EOPENSSL, "x509.store:add"); } } lua_pushvalue(L, 1); return 1; } /* xs_add() */ static int xs_addDefaults(lua_State *L) { X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); if (!X509_STORE_set_default_paths(store)) return auxL_error(L, auxL_EOPENSSL, "x509.store:addDefaults"); lua_pushvalue(L, 1); return 1; } /* xs_addDefaults() */ static int xs_verify(lua_State *L) { X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS); X509 *crt = checksimple(L, 2, X509_CERT_CLASS); STACK_OF(X509) *chain = NULL, **proof; X509_STORE_CTX *ctx = NULL; int ok, why; /* pre-allocate space for a successful return */ lua_settop(L, 3); proof = prepsimple(L, X509_CHAIN_CLASS); if (!lua_isnoneornil(L, 3)) { if (!(chain = X509_chain_up_ref(checksimple(L, 3, X509_CHAIN_CLASS)))) goto eossl; } if (!(ctx = X509_STORE_CTX_new()) || !X509_STORE_CTX_init(ctx, store, crt, chain)) { sk_X509_pop_free(chain, X509_free); goto eossl; } ERR_clear_error(); ok = X509_verify_cert(ctx); switch (ok) { case 1: /* verified */ if (!(*proof = X509_STORE_CTX_get1_chain(ctx))) goto eossl; X509_STORE_CTX_free(ctx); lua_pushboolean(L, 1); lua_pushvalue(L, -2); return 2; case 0: /* not verified */ why = X509_STORE_CTX_get_error(ctx); X509_STORE_CTX_free(ctx); lua_pushboolean(L, 0); lua_pushstring(L, X509_verify_cert_error_string(why)); return 2; default: goto eossl; } eossl: if (ctx) X509_STORE_CTX_free(ctx); return auxL_error(L, auxL_EOPENSSL, "x509.store:verify"); } /* xs_verify() */ static int xs__gc(lua_State *L) { X509_STORE **ud = luaL_checkudata(L, 1, X509_STORE_CLASS); if (*ud) { X509_STORE_free(*ud); *ud = NULL; } return 0; } /* xs__gc() */ static const auxL_Reg xs_methods[] = { { "add", &xs_add }, { "addDefaults", &xs_addDefaults }, { "verify", &xs_verify }, { NULL, NULL }, }; static const auxL_Reg xs_metatable[] = { { "__gc", &xs__gc }, { NULL, NULL }, }; static const auxL_Reg xs_globals[] = { { "new", &xs_new }, { "interpose", &xs_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_store(lua_State *L) { initall(L); auxL_newlib(L, xs_globals, 0); lua_pushstring(L, X509_get_default_cert_dir()); lua_setfield(L, -2, "CERT_DIR"); lua_pushstring(L, X509_get_default_cert_file()); lua_setfield(L, -2, "CERT_FILE"); lua_pushstring(L, X509_get_default_cert_dir_env()); lua_setfield(L, -2, "CERT_DIR_EVP"); lua_pushstring(L, X509_get_default_cert_file_env()); lua_setfield(L, -2, "CERT_FILE_EVP"); return 1; } /* luaopen__openssl_x509_store() */ /* * X509_STORE_CTX - openssl.x509.store.context * * This object is intended to be a temporary container in OpenSSL, so the * memory management is quite clumsy. In particular, it doesn't take * ownership of the X509_STORE object, which means the reference must be * held externally for the life of the X509_STORE_CTX object. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if 0 static int stx_new(lua_State *L) { X509_STORE_CTX **ud = prepsimple(L, X509_STCTX_CLASS); STACK_OF(X509) *chain; if (!(*ud = X509_STORE_CTX_new())) return auxL_error(L, auxL_EOPENSSL, "x509.store.context"); return 1; } /* stx_new() */ static int stx_interpose(lua_State *L) { return interpose(L, X509_STCTX_CLASS); } /* stx_interpose() */ static int stx_add(lua_State *L) { X509_STORE_CTX *ctx = checksimple(L, 1, X509_STCTX_CLASS); return 0; } /* stx_add() */ static int stx__gc(lua_State *L) { X509_STORE **ud = luaL_checkudata(L, 1, X509_STORE_CLASS); if (*ud) { X509_STORE_free(*ud); *ud = NULL; } return 0; } /* stx__gc() */ static const auxL_Reg stx_methods[] = { { "add", &stx_add }, { NULL, NULL }, }; static const auxL_Reg stx_metatable[] = { { "__gc", &stx__gc }, { NULL, NULL }, }; static const auxL_Reg stx_globals[] = { { "new", &stx_new }, { "interpose", &stx_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_x509_store_context(lua_State *L) { initall(L); auxL_newlib(L, stx_globals, 0); return 1; } /* luaopen__openssl_x509_store_context() */ #endif /* * PKCS12 - openssl.pkcs12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int p12_new(lua_State *L) { char *pass = NULL; loadfield(L, 1, "password", LUA_TSTRING, &pass); EVP_PKEY *key = loadfield_udata(L, 1, "key", PKEY_CLASS); STACK_OF(X509) *certs = loadfield_udata(L, 1, "certs", X509_CHAIN_CLASS); PKCS12 **ud = prepsimple(L, PKCS12_CLASS); int i; int no_kcert = 0; X509 *cert = NULL; X509 *kcert = NULL; STACK_OF(X509) *ca; if (!(ca = sk_X509_new_null())) goto error; for (i = 0; i < sk_X509_num(certs); i++) { cert = sk_X509_value(certs, i); if (key && X509_check_private_key(cert, key)) { if (!(kcert = X509_dup(cert))) goto error; X509_keyid_set1(kcert, NULL, 0); X509_alias_set1(kcert, NULL, 0); } else sk_X509_push(ca, cert); } if (key && !kcert) { no_kcert = 1; goto error; } if (!(*ud = PKCS12_create(pass, NULL, key, kcert, ca, 0, 0, 0, 0, 0))) goto error; if (kcert) X509_free(kcert); sk_X509_free(ca); return 1; error: if (kcert) X509_free(kcert); if (ca) sk_X509_free(ca); if (no_kcert) luaL_argerror(L, 1, lua_pushfstring(L, "certificate matching the key not found")); return auxL_error(L, auxL_EOPENSSL, "pkcs12.new"); } /* p12_new() */ static int p12_interpose(lua_State *L) { return interpose(L, PKCS12_CLASS); } /* p12_interpose() */ static int p12_parse(lua_State *L) { /* parse a p12 binary string and return the parts */ PKCS12 *p12; /* gather input parameters */ size_t len; const char *blob = luaL_checklstring(L, 1, &len); const char *passphrase = luaL_optstring(L, 2, NULL); /* prepare return values */ EVP_PKEY **ud_pkey = prepsimple(L, PKEY_CLASS); X509 **ud_cert = prepsimple(L, X509_CERT_CLASS); STACK_OF(X509) **ud_chain = prepsimple(L, X509_CHAIN_CLASS); /* Note: *ud_chain must be initialised to NULL, which prepsimple does. */ /* read PKCS#12 data into OpenSSL memory buffer */ BIO *bio = BIO_new_mem_buf((void*)blob, len); if (!bio) return auxL_error(L, auxL_EOPENSSL, "pkcs12.parse"); p12 = d2i_PKCS12_bio(bio, NULL); BIO_free(bio); if (!p12) return auxL_error(L, auxL_EOPENSSL, "pkcs12.parse"); /* the p12 pointer holds the data we're interested in */ int rc = PKCS12_parse(p12, passphrase, ud_pkey, ud_cert, ud_chain); PKCS12_free(p12); if (!rc) auxL_error(L, auxL_EOPENSSL, "pkcs12.parse"); /* replace the return values by nil if the ud pointers are NULL */ if (*ud_pkey == NULL) { lua_pushnil(L); lua_replace(L, -4); } if (*ud_cert == NULL) { lua_pushnil(L); lua_replace(L, -3); } /* other certificates (a chain, STACK_OF(X509) *) */ if (*ud_chain == NULL) { lua_pop(L, 1); lua_pushnil(L); } return 3; } /* p12_parse() */ static int p12__tostring(lua_State *L) { PKCS12 *p12 = checksimple(L, 1, PKCS12_CLASS); BIO *bio = getbio(L); char *data; long len; if (!i2d_PKCS12_bio(bio, p12)) return auxL_error(L, auxL_EOPENSSL, "pkcs12:__tostring"); len = BIO_get_mem_data(bio, &data); lua_pushlstring(L, data, len); return 1; } /* p12__tostring() */ static int p12__gc(lua_State *L) { PKCS12 **ud = luaL_checkudata(L, 1, PKCS12_CLASS); if (*ud) { PKCS12_free(*ud); *ud = NULL; } return 0; } /* p12__gc() */ static const auxL_Reg p12_methods[] = { { "tostring", &p12__tostring }, { NULL, NULL }, }; static const auxL_Reg p12_metatable[] = { { "__tostring", &p12__tostring }, { "__gc", &p12__gc }, { NULL, NULL }, }; static const auxL_Reg p12_globals[] = { { "new", &p12_new }, { "interpose", &p12_interpose }, { "parse", &p12_parse }, { NULL, NULL }, }; EXPORT int luaopen__openssl_pkcs12(lua_State *L) { initall(L); auxL_newlib(L, p12_globals, 0); return 1; } /* luaopen__openssl_pkcs12() */ /* * SSL_CTX - openssl.ssl.context * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void sx_push(lua_State *L, SSL_CTX *ctx) { lua_rawgetp(L, LUA_REGISTRYINDEX, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&initall)); if (LUA_TNIL == lua_rawgetp(L, -1, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(ctx))) { SSL_CTX **ud; lua_pop(L, 1); /* pop nil */ ud = prepsimple(L, SSL_CTX_CLASS); SSL_CTX_up_ref(ctx); *ud = ctx; /* Add to cache */ lua_pushvalue(L, -1); lua_rawsetp(L, -3, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(ctx)); } lua_remove(L, -2); } /* sx_push() */ static int sx_pushffi(lua_State *L) { SSL_CTX *ptr; lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, 1); lua_call(L, 1, 1); luaL_argcheck(L, lua_toboolean(L, -1), 1, "SSL_CTX* ffi pointer expected"); lua_pop(L, 1); ptr = *(SSL_CTX**)lua_topointer(L, 1); luaL_argcheck(L, ptr, 1, "SSL_CTX* pointer must be non-null"); sx_push(L, ptr); return 1; } /* ssl_pushffi() */ static int sx_new(lua_State *L) { static const char *const opts[] = { [0] = "SSL", [1] = "TLS", [2] = "SSLv2", [3] = "SSLv3", [4] = "SSLv23", [5] = "TLSv1", [6] = "TLSv1.0", [7] = "TLSv1_1", [8] = "TLSv1.1", [9] = "TLSv1_2", [10] = "TLSv1.2", [11] = "TLSv1_3", [12] = "TLSv1.3", [13] = "DTLS", [14] = "DTLSv1", [15] = "DTLSv1.0", [16] = "DTLSv1_2", [17] = "DTLSv1.2", NULL }; int method_enum; _Bool srv; SSL_CTX **ud; int options = 0; lua_settop(L, 2); method_enum = auxL_checkoption(L, 1, "TLS", opts, 1); srv = lua_toboolean(L, 2); switch (method_enum) { case 0: /* SSL */ options = SSL_OP_NO_SSLv2; break; case 1: /* TLS */ options = SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; break; case 2: /* SSLv2 */ options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_SSLv2; break; case 3: /* SSLv3 */ options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_SSLv3; break; case 4: /* SSLv23 */ break; case 5: /* TLSv1 */ case 6: /* TLSv1.0 */ options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_TLSv1; break; #if defined SSL_OP_NO_TLSv1_1 case 7: /* TLSv1_1 */ case 8: /* TLSv1.1 */ options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_TLSv1_1; break; #endif #if defined SSL_OP_NO_TLSv1_2 case 9: /* TLSv1_2 */ case 10: /* TLSv1.2 */ options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_TLSv1_2; break; #endif #if defined SSL_OP_NO_TLSv1_3 case 11: /* TLSv1_3 */ case 12: /* TLSv1.3 */ options = SSL_OP_NO_SSL_MASK & ~SSL_OP_NO_TLSv1_3; break; #endif #if HAVE_DTLS_CLIENT_METHOD case 13: /* DTLS */ break; #ifdef SSL_OP_NO_DTLSv1 case 14: /* DTLSv1 */ case 15: /* DTLSv1.0 */ options = SSL_OP_NO_DTLS_MASK & ~SSL_OP_NO_DTLSv1; break; #endif #ifdef SSL_OP_NO_DTLSv1_2 case 16: /* DTLSv1_2 */ case 17: /* DTLSv1.2 */ options = SSL_OP_NO_DTLS_MASK & ~SSL_OP_NO_DTLSv1_2; break; #endif #endif default: return luaL_argerror(L, 1, "invalid option"); } ud = prepsimple(L, SSL_CTX_CLASS); switch (method_enum) { case 0: /* SSL */ case 1: /* TLS */ case 2: /* SSLv2 */ case 3: /* SSLv3 */ case 4: /* SSLv23 */ case 5: /* TLSv1 */ case 6: /* TLSv1.0 */ case 7: /* TLSv1_1 */ case 8: /* TLSv1.1 */ case 9: /* TLSv1_2 */ case 10: /* TLSv1.2 */ case 11: /* TLSv1_3 */ case 12: /* TLSv1.3 */ *ud = SSL_CTX_new(srv?SSLv23_server_method():SSLv23_client_method()); break; #if HAVE_DTLS_CLIENT_METHOD case 13: /* DTLS */ case 14: /* DTLSv1 */ case 15: /* DTLSv1.0 */ case 16: /* DTLSv1_2 */ case 17: /* DTLSv1.2 */ *ud = SSL_CTX_new(srv?DTLS_server_method():DTLS_client_method()); break; #endif default: NOTREACHED; } if (!*ud) return auxL_error(L, auxL_EOPENSSL, "ssl.context.new"); SSL_CTX_set_options(*ud, options); #if HAVE_SSL_CTX_SET_ECDH_AUTO /* OpenSSL 1.0.2 introduced SSL_CTX_set_ecdh_auto to automatically select * from the curves set via SSL_CTX_set1_curves_list. However as of OpenSSL * 1.1.0, the functionality was turned on permanently and the option * removed. */ if (!SSL_CTX_set_ecdh_auto(*ud, 1)) return auxL_error(L, auxL_EOPENSSL, "ssl.context.new"); #endif /* Add to cache */ lua_rawgetp(L, LUA_REGISTRYINDEX, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&initall)); lua_pushvalue(L, -2); lua_rawsetp(L, -2, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(*ud)); lua_pop(L, 1); return 1; } /* sx_new() */ static int sx_interpose(lua_State *L) { return interpose(L, SSL_CTX_CLASS); } /* sx_interpose() */ static int sx_setOptions(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); auxL_Integer options = auxL_checkinteger(L, 2); auxL_pushinteger(L, SSL_CTX_set_options(ctx, options)); return 1; } /* sx_setOptions() */ static int sx_getOptions(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); auxL_pushinteger(L, SSL_CTX_get_options(ctx)); return 1; } /* sx_getOptions() */ static int sx_clearOptions(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); auxL_Integer options = auxL_checkinteger(L, 2); auxL_pushinteger(L, SSL_CTX_clear_options(ctx, options)); return 1; } /* sx_clearOptions() */ static int sx_setReadAhead(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int yes = checkbool(L, 2); SSL_CTX_set_read_ahead(ctx, yes); lua_pushboolean(L, 1); return 1; } /* sx_setReadAhead() */ static int sx_getReadAhead(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); lua_pushboolean(L, SSL_CTX_get_read_ahead(ctx)); return 1; } /* sx_getReadAhead() */ static int sx_setStore(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509_STORE *store = checksimple(L, 2, X509_STORE_CLASS); SSL_CTX_set1_cert_store(ctx, store); lua_pushboolean(L, 1); return 1; } /* sx_setStore() */ static int sx_getStore(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509_STORE *store; if((store = SSL_CTX_get_cert_store(ctx))) { xs_push(L, store); } else { lua_pushnil(L); } return 1; } /* sx_getStore() */ static int sx_setParam(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509_VERIFY_PARAM *xp = checksimple(L, 2, X509_VERIFY_PARAM_CLASS); if (!SSL_CTX_set1_param(ctx, xp)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setParam"); lua_pushboolean(L, 1); return 1; } /* sx_setParam() */ static int sx_getParam(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509_VERIFY_PARAM **ud, *from; /* X509_VERIFY_PARAM is not refcounted; create a new object and copy into it. */ ud = prepsimple(L, X509_VERIFY_PARAM_CLASS); if (!(*ud = X509_VERIFY_PARAM_new())) return auxL_error(L, auxL_EOPENSSL, "ssl.context:getParam"); from = SSL_CTX_get0_param(ctx); if (!(X509_VERIFY_PARAM_set1(*ud, from))) /* Note: openssl doesn't set an error as it should for some cases */ return auxL_error(L, auxL_EOPENSSL, "ssl.context:getParam"); return 1; } /* sx_getParam() */ static int sx_setVerify(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int mode = luaL_optinteger(L, 2, -1); int depth = luaL_optinteger(L, 3, -1); if (mode != -1) SSL_CTX_set_verify(ctx, mode, 0); if (depth != -1) SSL_CTX_set_verify_depth(ctx, depth); lua_pushboolean(L, 1); return 1; } /* sx_setVerify() */ static int sx_getVerify(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); lua_pushinteger(L, SSL_CTX_get_verify_mode(ctx)); lua_pushinteger(L, SSL_CTX_get_verify_depth(ctx)); return 2; } /* sx_getVerify() */ static int sx_setCertificate(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509 *crt = X509_dup(checksimple(L, 2, X509_CERT_CLASS)); int ok; ok = SSL_CTX_use_certificate(ctx, crt); X509_free(crt); if (!ok) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCertificate"); lua_pushboolean(L, 1); return 1; } /* sx_setCertificate() */ #if HAVE_SSL_CTX_GET0_CERTIFICATE static int sx_getCertificate(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509 *x509; if (!(x509 = SSL_CTX_get0_certificate(ctx))) return 0; xc_dup(L, x509); return 1; } /* sx_getCertificate() */ #endif #if HAVE_SSL_CTX_SET1_CHAIN static int sx_setCertificateChain(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); STACK_OF(X509) *certs = checksimple(L, 2, X509_CHAIN_CLASS); if (!SSL_CTX_set1_chain(ctx, certs)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCertificateChain"); lua_pushboolean(L, 1); return 1; } /* sx_setCertificateChain() */ #endif #if HAVE_SSL_CTX_GET0_CHAIN_CERTS static int sx_getCertificateChain(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); STACK_OF(X509) *certs; if (!SSL_CTX_get0_chain_certs(ctx, &certs)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:getCertificateChain"); xl_dup(L, certs, 1); return 1; } /* sx_getCertificateChain() */ #endif static int sx_setPrivateKey(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); /* * NOTE: No easy way to dup the key, but a shared reference should * be okay as keys are less mutable than certificates. * * FIXME: SSL_CTX_use_PrivateKey will return true even if the * EVP_PKEY object has no private key. Instead, we'll just get a * segfault during the SSL handshake. We need to check that a * private key is actually defined in the object. */ if (!SSL_CTX_use_PrivateKey(ctx, key)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setPrivateKey"); lua_pushboolean(L, 1); return 1; } /* sx_setPrivateKey() */ static int sx_setCipherList(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); const char *ciphers = luaL_checkstring(L, 2); if (!SSL_CTX_set_cipher_list(ctx, ciphers)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCipherList"); lua_pushboolean(L, 1); return 1; } /* sx_setCipherList() */ #if HAVE_SSL_CTX_SET_CIPHERSUITES static int sx_setCipherSuites(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); const char *ciphers = luaL_checkstring(L, 2); if (!SSL_CTX_set_ciphersuites(ctx, ciphers)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCipherSuites"); lua_pushboolean(L, 1); return 1; } /* sx_setCipherSuites() */ #endif static int sx_setEphemeralKey(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); void *tmp; /* * NOTE: SSL_CTX_set_tmp duplicates the keys, so we don't need to * worry about lifetimes. EVP_PKEY_get0 doesn't increment the * reference count. */ switch (EVP_PKEY_base_id(key)) { case EVP_PKEY_RSA: if (!(tmp = EVP_PKEY_get0(key))) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); if (!SSL_CTX_set_tmp_rsa(ctx, tmp)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); break; case EVP_PKEY_DH: if (!(tmp = EVP_PKEY_get0(key))) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); if (!SSL_CTX_set_tmp_dh(ctx, tmp)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); break; case EVP_PKEY_EC: if (!(tmp = EVP_PKEY_get0(key))) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); if (!SSL_CTX_set_tmp_ecdh(ctx, tmp)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setEphemeralKey"); break; default: return luaL_error(L, "%d: unsupported EVP base type", EVP_PKEY_base_id(key)); } /* switch() */ lua_pushboolean(L, 1); return 1; } /* sx_setEphemeralKey() */ #if HAVE_SSL_CTX_SET_GROUPS_LIST static int sx_setGroups(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); const char *list = luaL_checkstring(L, 2); if (!SSL_CTX_set1_groups_list(ctx, list)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setGroups"); lua_pushboolean(L, 1); return 1; } /* sx_setGroups() */ #endif #if HAVE_SSL_CTX_SET_ALPN_PROTOS static int sx_setAlpnProtos(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); luaL_Buffer B; size_t len; const char *tmp; luaL_buffinit(L, &B); checkprotos(&B, L, 2); luaL_pushresult(&B); tmp = lua_tolstring(L, -1, &len); /* OpenSSL 1.0.2 doesn't update the error stack on failure. */ ERR_clear_error(); if (0 != SSL_CTX_set_alpn_protos(ctx, (const unsigned char*)tmp, len)) { if (!ERR_peek_error()) { return luaL_error(L, "unable to set ALPN protocols: %s", aux_strerror(ENOMEM)); } else { return auxL_error(L, auxL_EOPENSSL, "ssl.context:setAlpnProtos"); } } lua_pushboolean(L, 1); return 1; } /* sx_setAlpnProtos() */ #endif #if HAVE_SSL_CTX_SET_ALPN_SELECT_CB typedef struct { /* input arguments */ SSL *ssl; const unsigned char *in; unsigned int inlen; /* space to store the selected protocol in our callback */ unsigned char selected[UCHAR_MAX]; } sx_setAlpnSelect_cb_struct; static int sx_setAlpnSelect_cb_helper(lua_State *L) { sx_setAlpnSelect_cb_struct *tmpbuf = lua_touserdata(L, 1); /* swap out nil for SSL object */ ssl_push(L, tmpbuf->ssl); lua_replace(L, 3); /* swap out nil for actual protos */ pushprotos(L, tmpbuf->in, tmpbuf->inlen); lua_replace(L, 4); lua_call(L, lua_gettop(L)-2, 1); return 1; } /* sx_setAlpnSelect_cb_helper() */ static int sx_setAlpnSelect_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *_ctx) { SSL_CTX *ctx = _ctx; lua_State *L = NULL; size_t n, protolen; int otop; const void *proto; sx_setAlpnSelect_cb_struct *tmpbuf; *out = NULL; *outlen = 0; /* expect at least five values: helper, space, userfunc, nil, nil */ if ((n = ex_getdata(&L, EX_SSL_CTX_ALPN_SELECT_CB, ctx)) < 5) return SSL_TLSEXT_ERR_ALERT_FATAL; otop = lua_gettop(L) - n; tmpbuf = lua_touserdata(L, -n+1); tmpbuf->ssl = ssl; tmpbuf->in = in; tmpbuf->inlen = inlen; /* call protected helper */ if (LUA_OK != lua_pcall(L, n - 1, 1, 0)) goto fatal; /* did we get a string result? */ if (!(proto = lua_tolstring(L, -1, &protolen))) goto noack; /* will it fit in our return buffer? */ if (protolen > UCHAR_MAX) goto fatal; memcpy(tmpbuf->selected, proto, protolen); /* * NB: Our return buffer is anchored using the luaL_ref API, so even * once we pop the stack it will remain valid. */ *out = tmpbuf->selected; *outlen = protolen; lua_settop(L, otop); return SSL_TLSEXT_ERR_OK; fatal: lua_settop(L, otop); return SSL_TLSEXT_ERR_ALERT_FATAL; noack: lua_settop(L, otop); return SSL_TLSEXT_ERR_NOACK; } /* sx_setAlpnSelect_cb() */ static int sx_setAlpnSelect(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int error; luaL_checktype(L, 2, LUA_TFUNCTION); /* need to do actual call in protected function. push helper */ lua_pushcfunction(L, sx_setAlpnSelect_cb_helper); lua_newuserdata(L, sizeof(sx_setAlpnSelect_cb_struct)); /* move space and helper to bottom of stack */ lua_rotate(L, 2, 2); /* room for SSL parameter and protos */ lua_pushnil(L); lua_pushnil(L); lua_rotate(L, 5, 2); /* stack: self, helper, space, userfunc, nil, nil, ... */ if ((error = ex_setdata(L, EX_SSL_CTX_ALPN_SELECT_CB, ctx, lua_gettop(L) - 1))) { if (error > 0) { return luaL_error(L, "unable to set ALPN protocol selection callback: %s", aux_strerror(error)); } else if (error == auxL_EOPENSSL && !ERR_peek_error()) { return luaL_error(L, "unable to set ALPN protocol selection callback: Unknown internal error"); } else { return auxL_error(L, error, "ssl.context:setAlpnSelect"); } } SSL_CTX_set_alpn_select_cb(ctx, &sx_setAlpnSelect_cb, ctx); lua_pushboolean(L, 1); return 1; } /* sx_setAlpnSelect() */ #endif #if HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK typedef struct { SSL *ssl; } sx_setHostNameCallback_struct; static int sx_setHostNameCallback_helper(lua_State *L) { sx_setHostNameCallback_struct *tmpbuf = lua_touserdata(L, 1); ssl_push(L, tmpbuf->ssl); lua_replace(L, 3); lua_call(L, lua_gettop(L)-2, 2); return 2; } static int sx_setHostNameCallback_cb(SSL *ssl, int *ad, void *_ctx) { SSL_CTX *ctx = _ctx; lua_State *L = NULL; size_t n; int otop, status, ret = SSL_TLSEXT_ERR_ALERT_FATAL; sx_setHostNameCallback_struct *tmpbuf; *ad = SSL_AD_INTERNAL_ERROR; /* expect at least four values: helper, space, userfunc, nil */ if ((n = ex_getdata(&L, EX_SSL_CTX_TLSEXT_SERVERNAME_CB, ctx)) < 4) return SSL_TLSEXT_ERR_ALERT_FATAL; otop = lua_gettop(L) - n; tmpbuf = lua_touserdata(L, -n+1); tmpbuf->ssl = ssl; if (LUA_OK != (status = lua_pcall(L, n - 1, 2, 0))) goto done; /* callback should return a boolean for OK/NOACK * or nil + an integer for a controlled error * everything else will be a fatal internal error */ if (lua_isboolean(L, -2)) { ret = lua_toboolean(L, -2) ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK; } else { ret = SSL_TLSEXT_ERR_ALERT_FATAL; if (lua_isnil(L, -2) && lua_isinteger(L, -1)) *ad = lua_tointeger(L, -1); } done: lua_settop(L, otop); return ret; } /* sx_setHostNameCallback_cb() */ static int sx_setHostNameCallback(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int error; luaL_checktype(L, 2, LUA_TFUNCTION); /* need to do actual call in protected function. push helper */ lua_pushcfunction(L, sx_setHostNameCallback_helper); lua_newuserdata(L, sizeof(sx_setHostNameCallback_struct)); /* move space and helper to bottom of stack */ lua_rotate(L, 2, 2); /* room for SSL parameter */ lua_pushnil(L); lua_rotate(L, 5, 1); if ((error = ex_setdata(L, EX_SSL_CTX_TLSEXT_SERVERNAME_CB, ctx, lua_gettop(L) - 1))) { if (error > 0) { return luaL_error(L, "unable to set hostname selection callback: %s", aux_strerror(error)); } else if (error == auxL_EOPENSSL && !ERR_peek_error()) { return luaL_error(L, "unable to set hostname selection callback: Unknown internal error"); } else { return auxL_error(L, error, "ssl.context:setHostNameCallback"); } } SSL_CTX_set_tlsext_servername_callback(ctx, sx_setHostNameCallback_cb); SSL_CTX_set_tlsext_servername_arg(ctx, ctx); lua_pushboolean(L, 1); return 1; } /* sx_setHostNameCallback() */ #endif int TLSEXT_STATUSTYPEs[] = { TLSEXT_STATUSTYPE_ocsp }; const char *TLSEXT_STATUSTYPEs_names[] = { "ocsp", NULL }; #define checkTLSEXT_STATUSTYPE(L, idx) \ (TLSEXT_STATUSTYPEs[luaL_checkoption((L), (idx), NULL, TLSEXT_STATUSTYPEs_names)]) #if HAVE_SSL_CTX_SET_TLSEXT_STATUS_TYPE static int sx_setTLSextStatusType(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int type = checkTLSEXT_STATUSTYPE(L, 2); if(!SSL_CTX_set_tlsext_status_type(ctx, type)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setTLSextStatusType"); lua_pushboolean(L, 1); return 1; } /* sx_setTLSextStatusType() */ #endif #if HAVE_SSL_CTX_GET_TLSEXT_STATUS_TYPE static int sx_getTLSextStatusType(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int type = SSL_CTX_get_tlsext_status_type(ctx); switch(type) { case -1: lua_pushnil(L); break; case TLSEXT_STATUSTYPE_ocsp: lua_pushliteral(L, "ocsp"); break; default: luaL_error(L, "unknown TLS extension %d", type); } return 1; } /* sx_getTLSextStatusType() */ #endif #if HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEYS static int sx_getTicketKeysLength(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int res = SSL_CTX_set_tlsext_ticket_keys(ctx, NULL, 0); lua_pushinteger(L, res); return 1; } /* sx_getTicketKeysLength() */ static int sx_setTicketKeys(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); size_t keylen; const char *keys = luaL_checklstring(L, 2, &keylen); if (!SSL_CTX_set_tlsext_ticket_keys(ctx, (void*)keys, keylen)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setTicketKeys"); lua_pushboolean(L, 1); return 1; } /* sx_setTicketKeys() */ #endif #if HAVE_SSL_CTX_GET_TLSEXT_TICKET_KEYS static int sx_getTicketKeys(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); int keylen; char *out; luaL_Buffer B; keylen = SSL_CTX_get_tlsext_ticket_keys(ctx, NULL, 0); out = luaL_buffinitsize(L, &B, keylen); if (!SSL_CTX_get_tlsext_ticket_keys(ctx, out, keylen)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:getTicketKeys"); luaL_pushresultsize(&B, keylen); return 1; } /* sx_getTicketKeys() */ #endif #if HAVE_SSL_CTX_USE_SERVERINFO_FILE static int sx_useServerInfoFile(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); const char *file = luaL_checkstring(L, 2); if (!SSL_CTX_use_serverinfo_file(ctx, file)) return auxL_error(L, auxL_EOPENSSL, "ssl.context:useServerInfoFile"); lua_pushboolean(L, 1); return 1; } /* sx_useServerInfoFile() */ #endif #if HAVE_SSL_CTX_USE_SERVERINFO_EX || HAVE_SSL_CTX_USE_SERVERINFO static int sx_useServerInfo(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); unsigned int version = auxL_checkunsigned(L, 2, 1, (HAVE_SSL_CTX_USE_SERVERINFO_EX) ? auxL_UnsignedMax : 1); size_t serverinfo_length; const unsigned char *serverinfo = (const unsigned char *)luaL_checklstring(L, 3, &serverinfo_length); #if HAVE_SSL_CTX_USE_SERVERINFO_EX if (!SSL_CTX_use_serverinfo_ex(ctx, version, serverinfo, serverinfo_length)) #else if (!SSL_CTX_use_serverinfo(ctx, serverinfo, serverinfo_length)) #endif return auxL_error(L, auxL_EOPENSSL, "ssl.context:useServerInfo"); lua_pushboolean(L, 1); return 1; } /* sx_useServerInfoFile() */ #endif #if HAVE_SSL_CTX_ADD_CUSTOM_EXT typedef struct { /* input arguments */ SSL *ssl; unsigned int ext_type; unsigned int context; X509 *x; size_t chainidx; } sx_custom_ext_add_cb_struct; static int sx_custom_ext_add_cb_helper(lua_State *L) { sx_custom_ext_add_cb_struct *tmpbuf = lua_touserdata(L, 1); ssl_push(L, tmpbuf->ssl); lua_pushinteger(L, tmpbuf->ext_type); lua_pushinteger(L, tmpbuf->context); if (tmpbuf->x) { xc_dup(L, tmpbuf->x); lua_pushinteger(L, tmpbuf->chainidx); } else { lua_pushnil(L); lua_pushnil(L); } lua_call(L, 5, 2); return 2; } /* sx_custom_ext_add_cb_helper() */ static int sx_custom_ext_add_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg NOTUSED) { SSL_CTX *ctx = SSL_get_SSL_CTX(s); lua_State *L = NULL; *al = SSL_AD_INTERNAL_ERROR; /* expect three values: helper_function, space, table of callbacks indexed by ext_type */ if (ex_getdata(&L, EX_SSL_CTX_CUSTOM_EXTENSION_ADD_CB, ctx) != 3) return -1; sx_custom_ext_add_cb_struct *tmpbuf = lua_touserdata(L, -2); tmpbuf->ssl = s; tmpbuf->ext_type = ext_type; tmpbuf->context = context; tmpbuf->x = x; tmpbuf->chainidx = chainidx; /* replace table with callback of interest */ lua_rawgeti(L, -1, ext_type); lua_remove(L, -2); /* call protected helper */ if (LUA_OK != lua_pcall(L, 2, 2, 0)) /* leave error on the stack */ return -1; /* callback should return a string for OK, 'false' to skip, * or nil + an integer for a controlled error * everything else will be a fatal internal error */ if (lua_isstring(L, -2)) { *out = (const unsigned char*)lua_tolstring(L, -2, outlen); /* leave `out` on the stack, we need it to remain valid */ lua_pop(L, 1); return 1; } else if (lua_isboolean(L, -2) && !lua_toboolean(L, -2)) { /* leave false on the stack */ lua_pop(L, 1); return 0; } else { if (lua_isnil(L, -2) && lua_isinteger(L, -1)) *al = lua_tointeger(L, -1); /* leave something on the stack */ lua_pop(L, 1); return -1; } } /* sx_custom_ext_add_cb() */ static void sx_custom_ext_free_cb(SSL *s, unsigned int ext_type NOTUSED, unsigned int context NOTUSED, const unsigned char *out NOTUSED, void *add_arg NOTUSED) { SSL_CTX *ctx = SSL_get_SSL_CTX(s); lua_State *L = NULL; size_t n; if ((n = ex_getdata(&L, EX_SSL_CTX_CUSTOM_EXTENSION_ADD_CB, ctx)) < 1) return; /* should be unreachable */ /* pop data pushed by ex_getdata * TODO: ex_getdata alternative that doesn't push in the first place? */ lua_pop(L, n); /* pop the item left on the stack by add_cb */ lua_pop(L, 1); } /* sx_custom_ext_free_cb() */ typedef struct { /* input arguments */ SSL *ssl; unsigned int ext_type; unsigned int context; const unsigned char *in; size_t inlen; X509 *x; size_t chainidx; } sx_custom_ext_parse_cb_struct; static int sx_custom_ext_parse_cb_helper(lua_State *L) { sx_custom_ext_parse_cb_struct *tmpbuf = lua_touserdata(L, 1); ssl_push(L, tmpbuf->ssl); lua_pushinteger(L, tmpbuf->ext_type); lua_pushinteger(L, tmpbuf->context); lua_pushlstring(L, (const char*)tmpbuf->in, tmpbuf->inlen); if (tmpbuf->x) { xc_dup(L, tmpbuf->x); lua_pushinteger(L, tmpbuf->chainidx); } else { lua_pushnil(L); lua_pushnil(L); } lua_call(L, 6, 2); return 2; } /* sx_custom_ext_parse_cb_helper() */ static int sx_custom_ext_parse_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, X509 *x, size_t chainidx, int *al, void *parse_arg NOTUSED) { SSL_CTX *ctx = SSL_get_SSL_CTX(s); lua_State *L = NULL; *al = SSL_AD_INTERNAL_ERROR; /* expect three values: helper_function, space, table of callbacks indexed by ext_type */ if (ex_getdata(&L, EX_SSL_CTX_CUSTOM_EXTENSION_PARSE_CB, ctx) != 3) return -1; sx_custom_ext_parse_cb_struct *tmpbuf = lua_touserdata(L, -2); tmpbuf->ssl = s; tmpbuf->ext_type = ext_type; tmpbuf->context = context; tmpbuf->in = in; tmpbuf->inlen = inlen; tmpbuf->x = x; tmpbuf->chainidx = chainidx; /* replace table with callback of interest */ lua_rawgeti(L, -1, ext_type); lua_remove(L, -2); /* call protected helper */ if (LUA_OK != lua_pcall(L, 2, 2, 0)) { lua_pop(L, 1); return -1; } /* callback should return true * or nil + an integer for a controlled error * everything else will be a fatal internal error */ if (lua_isboolean(L, -2) && lua_toboolean(L, -2)) { lua_pop(L, 2); return 1; } else { if (lua_isnil(L, -2) && lua_isinteger(L, -1)) *al = lua_tointeger(L, -1); lua_pop(L, 2); return -1; } } /* sx_custom_ext_parse_cb() */ static int sx_addCustomExtension(lua_State *L) { int error; SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); unsigned int ext_type = auxL_checkunsigned(L, 2, 0, 65535); unsigned int context = auxL_checkunsigned(L, 3); SSL_custom_ext_add_cb_ex add_cb = NULL; SSL_custom_ext_free_cb_ex free_cb = NULL; SSL_custom_ext_parse_cb_ex parse_cb = NULL; lua_settop(L, 5); if (!lua_isnoneornil(L, 4)) { luaL_checktype(L, 4, LUA_TFUNCTION); switch (ex_getdata(&L, EX_SSL_CTX_CUSTOM_EXTENSION_ADD_CB, ctx)) { case 0: { /* first time */ lua_createtable(L, 0, 1); /* need to do actual call in protected function. push helper */ lua_pushcfunction(L, sx_custom_ext_add_cb_helper); lua_newuserdata(L, sizeof(sx_custom_ext_add_cb_struct)); lua_pushvalue(L, -3); if ((error = ex_setdata(L, EX_SSL_CTX_CUSTOM_EXTENSION_ADD_CB, ctx, 3))) { if (error > 0) { return luaL_error(L, "unable to add custom extension add callback: %s", aux_strerror(error)); } else if (error == auxL_EOPENSSL && !ERR_peek_error()) { return luaL_error(L, "unable to add custom extension add callback: Unknown internal error"); } else { return auxL_error(L, error, "ssl.context:addCustomExtension"); } } break; } case 2: lua_remove(L, -2); break; default: return luaL_error(L, "unable to add custom extension add callback"); } lua_pushvalue(L, 4); lua_rawseti(L, -2, ext_type); lua_pop(L, 1); add_cb = sx_custom_ext_add_cb; free_cb = sx_custom_ext_free_cb; } if (!lua_isnoneornil(L, 5)) { luaL_checktype(L, 5, LUA_TFUNCTION); switch (ex_getdata(&L, EX_SSL_CTX_CUSTOM_EXTENSION_PARSE_CB, ctx)) { case 0: { /* first time */ lua_createtable(L, 0, 1); /* need to do actual call in protected function. push helper */ lua_pushcfunction(L, sx_custom_ext_parse_cb_helper); lua_newuserdata(L, sizeof(sx_custom_ext_parse_cb_struct)); lua_pushvalue(L, -3); if ((error = ex_setdata(L, EX_SSL_CTX_CUSTOM_EXTENSION_PARSE_CB, ctx, 3))) { if (error > 0) { return luaL_error(L, "unable to add custom extension parse callback: %s", aux_strerror(error)); } else if (error == auxL_EOPENSSL && !ERR_peek_error()) { return luaL_error(L, "unable to add custom extension parse callback: Unknown internal error"); } else { return auxL_error(L, error, "ssl.context:addCustomExtension"); } } break; } case 2: lua_remove(L, -2); break; default: return luaL_error(L, "unable to add custom extension add callback"); } lua_pushvalue(L, 5); lua_rawseti(L, -2, ext_type); lua_pop(L, 1); parse_cb = sx_custom_ext_parse_cb; } if (!SSL_CTX_add_custom_ext(ctx, ext_type, context, add_cb, free_cb, NULL, parse_cb, NULL)) /* In OpenSSL 1.1.1, no error is set */ return luaL_error(L, "ssl.context:addCustomExtension: extension type already handled or internal error"); lua_pushboolean(L, 1); return 1; } /* sx_addCustomExtension() */ #endif static int sx__gc(lua_State *L) { SSL_CTX **ud = luaL_checkudata(L, 1, SSL_CTX_CLASS); if (*ud) { SSL_CTX_free(*ud); *ud = NULL; } return 0; } /* sx__gc() */ static const auxL_Reg sx_methods[] = { { "setOptions", &sx_setOptions }, { "getOptions", &sx_getOptions }, { "clearOptions", &sx_clearOptions }, { "setReadAhead", &sx_setReadAhead }, { "getReadAhead", &sx_getReadAhead }, { "setStore", &sx_setStore }, { "getStore", &sx_getStore }, { "setParam", &sx_setParam }, { "getParam", &sx_getParam }, { "setVerify", &sx_setVerify }, { "getVerify", &sx_getVerify }, { "setCertificate", &sx_setCertificate }, #if HAVE_SSL_CTX_GET0_CERTIFICATE { "getCertificate", &sx_getCertificate }, #endif #if HAVE_SSL_CTX_SET1_CHAIN { "setCertificateChain", &sx_setCertificateChain }, #endif #if HAVE_SSL_CTX_GET0_CHAIN_CERTS { "getCertificateChain", &sx_getCertificateChain }, #endif { "setPrivateKey", &sx_setPrivateKey }, { "setCipherList", &sx_setCipherList }, #if HAVE_SSL_CTX_SET_CIPHERSUITES { "setCipherSuites", &sx_setCipherSuites }, #endif { "setEphemeralKey", &sx_setEphemeralKey }, #if HAVE_SSL_CTX_SET_GROUPS_LIST { "setCurvesList", &sx_setGroups }, /* old alias */ { "setGroups", &sx_setGroups }, #endif #if HAVE_SSL_CTX_SET_ALPN_PROTOS { "setAlpnProtos", &sx_setAlpnProtos }, #endif #if HAVE_SSL_CTX_SET_ALPN_SELECT_CB { "setAlpnSelect", &sx_setAlpnSelect }, #endif #if HAVE_SSL_CTX_SET_TLSEXT_SERVERNAME_CALLBACK { "setHostNameCallback", &sx_setHostNameCallback }, #endif #if HAVE_SSL_CTX_SET_TLSEXT_STATUS_TYPE { "setTLSextStatusType", &sx_setTLSextStatusType }, #endif #if HAVE_SSL_CTX_GET_TLSEXT_STATUS_TYPE { "getTLSextStatusType", &sx_getTLSextStatusType }, #endif #if HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEYS { "getTicketKeysLength", &sx_getTicketKeysLength }, { "setTicketKeys", &sx_setTicketKeys }, #endif #if HAVE_SSL_CTX_GET_TLSEXT_TICKET_KEYS { "getTicketKeys", &sx_getTicketKeys }, #endif #if HAVE_SSL_CTX_USE_SERVERINFO_FILE { "useServerInfoFile", &sx_useServerInfoFile }, #endif #if HAVE_SSL_CTX_USE_SERVERINFO_EX || HAVE_SSL_CTX_USE_SERVERINFO { "useServerInfo", &sx_useServerInfo }, #endif #if HAVE_SSL_CTX_ADD_CUSTOM_EXT { "addCustomExtension", &sx_addCustomExtension }, #endif { NULL, NULL }, }; static const auxL_Reg sx_metatable[] = { { "__gc", &sx__gc }, { NULL, NULL }, }; static const auxL_Reg sx_globals[] = { { "new", &sx_new }, { "pushffi", &sx_pushffi, 1 }, { "interpose", &sx_interpose }, { NULL, NULL }, }; static const auxL_IntegerReg sx_verify[] = { { "VERIFY_NONE", SSL_VERIFY_NONE }, { "VERIFY_PEER", SSL_VERIFY_PEER }, { "VERIFY_FAIL_IF_NO_PEER_CERT", SSL_VERIFY_FAIL_IF_NO_PEER_CERT }, { "VERIFY_CLIENT_ONCE", SSL_VERIFY_CLIENT_ONCE }, { NULL, 0 }, }; static const auxL_IntegerReg sx_option[] = { { "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG }, { "OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG }, { "OP_LEGACY_SERVER_CONNECT", SSL_OP_LEGACY_SERVER_CONNECT }, { "OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG }, #ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG { "OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG }, #endif #ifdef SSL_OP_TLSEXT_PADDING { "OP_TLSEXT_PADDING", SSL_OP_TLSEXT_PADDING }, #endif { "OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER }, #ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG5 { "OP_SAFARI_ECDHE_ECDSA_BUG", SSL_OP_SAFARI_ECDHE_ECDSA_BUG }, #endif { "OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING }, { "OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG }, { "OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG }, { "OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG }, #ifdef SSL_OP_ALLOW_NO_DHE_KEX { "OP_ALLOW_NO_DHE_KEX", SSL_OP_ALLOW_NO_DHE_KEX }, #endif { "OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS }, { "OP_NO_QUERY_MTU", SSL_OP_NO_QUERY_MTU }, { "OP_COOKIE_EXCHANGE", SSL_OP_COOKIE_EXCHANGE }, { "OP_NO_TICKET", SSL_OP_NO_TICKET }, { "OP_CISCO_ANYCONNECT", SSL_OP_CISCO_ANYCONNECT }, { "OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION }, #ifdef SSL_OP_NO_COMPRESSION { "OP_NO_COMPRESSION", SSL_OP_NO_COMPRESSION }, #endif { "OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION }, { "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE }, #ifdef SSL_OP_NO_ENCRYPT_THEN_MAC5 { "OP_NO_ENCRYPT_THEN_MAC", SSL_OP_NO_ENCRYPT_THEN_MAC }, #endif { "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE }, { "OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA }, #ifdef SSL_OP_PRIORITIZE_CHACHA { "OP_PRIORITIZE_CHACHA", SSL_OP_PRIORITIZE_CHACHA }, #endif #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT { "OP_ENABLE_MIDDLEBOX_COMPAT", SSL_OP_ENABLE_MIDDLEBOX_COMPAT }, #endif #ifdef SSL_OP_NO_ANTI_REPLAY { "OP_NO_ANTI_REPLAY", SSL_OP_NO_ANTI_REPLAY }, #endif { "OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE }, { "OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG }, { "OP_NO_SSLv2", SSL_OP_NO_SSLv2 }, { "OP_NO_SSLv3", SSL_OP_NO_SSLv3 }, { "OP_NO_TLSv1", SSL_OP_NO_TLSv1 }, #ifdef SSL_OP_NO_DTLSv1 { "OP_NO_DTLSv1", SSL_OP_NO_DTLSv1 }, #endif #ifdef SSL_OP_NO_TLSv1_2 { "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2 }, #endif #ifdef SSL_OP_NO_DTLSv1_2 { "OP_NO_DTLSv1_2", SSL_OP_NO_DTLSv1_2 }, #endif #ifdef SSL_OP_NO_TLSv1_1 { "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1 }, #endif { "OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG }, #ifdef SSL_OP_NO_TLSv1_3 { "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3 }, #endif { "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG }, #ifdef SSL_OP_NO_RENEGOTIATION5 { "OP_NO_RENEGOTIATION", SSL_OP_NO_RENEGOTIATION }, #endif #ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG { "OP_CRYPTOPRO_TLSEXT_BUG", SSL_OP_CRYPTOPRO_TLSEXT_BUG }, #endif { "OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 }, { "OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 }, { "OP_NO_SSL_MASK", SSL_OP_NO_SSL_MASK }, #ifdef SSL_OP_NO_DTLS_MASK { "OP_NO_DTLS_MASK", SSL_OP_NO_DTLS_MASK }, #endif { "OP_ALL", SSL_OP_ALL }, { NULL, 0 }, }; static const auxL_IntegerReg sx_ext[] = { #ifdef SSL_EXT_TLS_ONLY { "EXT_TLS_ONLY", SSL_EXT_TLS_ONLY }, #endif #ifdef SSL_EXT_DTLS_ONLY { "EXT_DTLS_ONLY", SSL_EXT_DTLS_ONLY }, #endif #ifdef SSL_EXT_TLS_IMPLEMENTATION_ONLY { "EXT_TLS_IMPLEMENTATION_ONLY", SSL_EXT_TLS_IMPLEMENTATION_ONLY }, #endif #ifdef SSL_EXT_SSL3_ALLOWED { "EXT_SSL3_ALLOWED", SSL_EXT_SSL3_ALLOWED }, #endif #ifdef SSL_EXT_TLS1_2_AND_BELOW_ONLY { "EXT_TLS1_2_AND_BELOW_ONLY", SSL_EXT_TLS1_2_AND_BELOW_ONLY }, #endif #ifdef SSL_EXT_TLS1_3_ONLY { "EXT_TLS1_3_ONLY", SSL_EXT_TLS1_3_ONLY }, #endif #ifdef SSL_EXT_IGNORE_ON_RESUMPTION { "EXT_IGNORE_ON_RESUMPTION", SSL_EXT_IGNORE_ON_RESUMPTION }, #endif #ifdef SSL_EXT_CLIENT_HELLO { "EXT_CLIENT_HELLO", SSL_EXT_CLIENT_HELLO }, #endif #ifdef SSL_EXT_TLS1_2_SERVER_HELLO { "EXT_TLS1_2_SERVER_HELLO", SSL_EXT_TLS1_2_SERVER_HELLO }, #endif #ifdef SSL_EXT_TLS1_3_SERVER_HELLO { "EXT_TLS1_3_SERVER_HELLO", SSL_EXT_TLS1_3_SERVER_HELLO }, #endif #ifdef SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS { "EXT_TLS1_3_ENCRYPTED_EXTENSIONS", SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, #endif #ifdef SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST { "EXT_TLS1_3_HELLO_RETRY_REQUEST", SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST }, #endif #ifdef SSL_EXT_TLS1_3_CERTIFICATE { "EXT_TLS1_3_CERTIFICATE", SSL_EXT_TLS1_3_CERTIFICATE }, #endif #ifdef SSL_EXT_TLS1_3_NEW_SESSION_TICKET { "EXT_TLS1_3_NEW_SESSION_TICKET", SSL_EXT_TLS1_3_NEW_SESSION_TICKET }, #endif #ifdef SSL_EXT_TLS1_3_CERTIFICATE_REQUEST { "EXT_TLS1_3_CERTIFICATE_REQUEST", SSL_EXT_TLS1_3_CERTIFICATE_REQUEST }, #endif { NULL, 0 }, }; EXPORT int luaopen__openssl_ssl_context(lua_State *L) { initall(L); auxL_newlib(L, sx_globals, 0); /* FFI argument checking */ lua_getfield(L, -1, "pushffi"); luaL_loadstring(L, "local ffi = require 'ffi'\n" \ "if not pcall(ffi.typeof, 'SSL_CTX*') then\n" \ " ffi.cdef 'typedef struct ssl_ctx_st SSL_CTX;'\n" \ "end\n" \ "local ffi_istype = ffi.istype\n" \ "local SSL_CTXp = ffi.typeof('SSL_CTX*')\n" \ "return function(p) return ffi_istype(SSL_CTXp, p) end\n" ); if (lua_pcall(L, 0, 1, 0)) { /* failed (probably no ffi library available) */ lua_pop(L, 1); /* use dummy function instead */ luaL_loadstring(L, "return false\n"); }; lua_setupvalue(L, -2, 1); lua_pop(L, 1); auxL_setintegers(L, sx_verify); auxL_setintegers(L, sx_option); auxL_setintegers(L, sx_ext); return 1; } /* luaopen__openssl_ssl_context() */ /* * SSL - openssl.ssl * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void ssl_push(lua_State *L, SSL *ssl) { lua_rawgetp(L, LUA_REGISTRYINDEX, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&initall)); if (LUA_TNIL == lua_rawgetp(L, -1, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(ssl))) { SSL **ud; lua_pop(L, 1); /* pop nil */ ud = prepsimple(L, SSL_CLASS); SSL_up_ref(ssl); *ud = ssl; /* Add to SSL* cache */ lua_pushvalue(L, -1); lua_rawsetp(L, -3, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(ssl)); } lua_remove(L, -2); } /* ssl_push() */ static int ssl_pushffi(lua_State *L) { SSL *ptr; lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, 1); lua_call(L, 1, 1); luaL_argcheck(L, lua_toboolean(L, -1), 1, "SSL* ffi pointer expected"); lua_pop(L, 1); ptr = *(SSL**)lua_topointer(L, 1); luaL_argcheck(L, ptr, 1, "SSL* pointer must be non-null"); ssl_push(L, ptr); return 1; } /* ssl_pushffi() */ static int ssl_new(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); SSL **ud = prepsimple(L, SSL_CLASS); *ud = SSL_new(ctx); if (!*ud) return auxL_error(L, auxL_EOPENSSL, "ssl.new"); /* Add to SSL* cache */ lua_rawgetp(L, LUA_REGISTRYINDEX, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&initall)); lua_pushvalue(L, -2); lua_rawsetp(L, -2, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(*ud)); lua_pop(L, 1); return 1; } /* ssl_new() */ static int ssl_interpose(lua_State *L) { return interpose(L, SSL_CLASS); } /* ssl_interpose() */ static int ssl_setContext(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); SSL_CTX *ctx = checksimple(L, 2, SSL_CTX_CLASS); if (!SSL_set_SSL_CTX(ssl, ctx)) return auxL_error(L, auxL_EOPENSSL, "ssl:setContext"); lua_pushboolean(L, 1); return 1; } /* ssl_setContext() */ static int ssl_getContext(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); sx_push(L, ctx); return 1; } /* ssl_getContext() */ static int ssl_setOptions(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); auxL_Integer options = auxL_checkinteger(L, 2); auxL_pushinteger(L, SSL_set_options(ssl, options)); return 1; } /* ssl_setOptions() */ static int ssl_getOptions(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); auxL_pushinteger(L, SSL_get_options(ssl)); return 1; } /* ssl_getOptions() */ static int ssl_clearOptions(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); auxL_Integer options = auxL_checkinteger(L, 2); auxL_pushinteger(L, SSL_clear_options(ssl, options)); return 1; } /* ssl_clearOptions() */ static int ssl_setReadAhead(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); int yes = checkbool(L, 2); SSL_set_read_ahead(ssl, yes); lua_pushboolean(L, 1); return 1; } /* ssl_setReadAhead() */ static int ssl_getReadAhead(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); lua_pushboolean(L, SSL_get_read_ahead(ssl)); return 1; } /* ssl_getReadAhead() */ #if HAVE_SSL_SET1_CHAIN_CERT_STORE static int ssl_setChainStore(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509_STORE *store = checksimple(L, 2, X509_STORE_CLASS); SSL_set1_chain_cert_store(ssl, store); lua_pushboolean(L, 1); return 1; } /* ssl_setChainStore() */ #endif #if HAVE_SSL_SET1_VERIFY_CERT_STORE static int ssl_setVerifyStore(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509_STORE *store = checksimple(L, 2, X509_STORE_CLASS); SSL_set1_verify_cert_store(ssl, store); lua_pushboolean(L, 1); return 1; } /* ssl_setVerifyStore() */ #endif static int ssl_setParam(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509_VERIFY_PARAM *xp = checksimple(L, 2, X509_VERIFY_PARAM_CLASS); if (!SSL_set1_param(ssl, xp)) return auxL_error(L, auxL_EOPENSSL, "ssl:setParam"); lua_pushboolean(L, 1); return 1; } /* ssl_setParam() */ static int ssl_getParam(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509_VERIFY_PARAM **ud, *from; /* X509_VERIFY_PARAM is not refcounted; create a new object and copy into it. */ ud = prepsimple(L, X509_VERIFY_PARAM_CLASS); if (!(*ud = X509_VERIFY_PARAM_new())) return auxL_error(L, auxL_EOPENSSL, "ssl:getParam"); from = SSL_get0_param(ssl); if (!(X509_VERIFY_PARAM_set1(*ud, from))) /* Note: openssl doesn't set an error as it should for some cases */ return auxL_error(L, auxL_EOPENSSL, "ssl:getParam"); return 1; } /* ssl_getParam() */ static int ssl_setVerify(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); int mode = luaL_optinteger(L, 2, -1); int depth = luaL_optinteger(L, 3, -1); if (mode != -1) SSL_set_verify(ssl, mode, 0); if (depth != -1) SSL_set_verify_depth(ssl, depth); lua_pushboolean(L, 1); return 1; } /* ssl_setVerify() */ static int ssl_getVerify(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); lua_pushinteger(L, SSL_get_verify_mode(ssl)); lua_pushinteger(L, SSL_get_verify_depth(ssl)); return 2; } /* ssl_getVerify() */ static int ssl_getVerifyResult(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); long res = SSL_get_verify_result(ssl); lua_pushinteger(L, res); lua_pushstring(L, X509_verify_cert_error_string(res)); return 2; } /* ssl_getVerifyResult() */ static int ssl_setCertificate(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509 *crt = X509_dup(checksimple(L, 2, X509_CERT_CLASS)); int ok; ok = SSL_use_certificate(ssl, crt); X509_free(crt); if (!ok) return auxL_error(L, auxL_EOPENSSL, "ssl:setCertificate"); lua_pushboolean(L, 1); return 1; } /* ssl_setCertificate() */ #if HAVE_SSL_SET1_CHAIN static int ssl_setCertificateChain(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); STACK_OF(X509) *certs = checksimple(L, 2, X509_CHAIN_CLASS); if (!SSL_set1_chain(ssl, certs)) return auxL_error(L, auxL_EOPENSSL, "ssl:setCertificateChain"); lua_pushboolean(L, 1); return 1; } /* ssl_setCertificateChain() */ #endif #if HAVE_SSL_GET0_CHAIN_CERTS static int ssl_getCertificateChain(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); STACK_OF(X509) *certs; if (!SSL_get0_chain_certs(ssl, &certs)) return auxL_error(L, auxL_EOPENSSL, "ssl:getCertificateChain"); xl_dup(L, X509_chain_up_ref(certs), 1); return 1; } /* ssl_getCertificateChain() */ #endif static int ssl_setPrivateKey(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS); /* * NOTE: No easy way to dup the key, but a shared reference should * be okay as keys are less mutable than certificates. * * FIXME: SSL_use_PrivateKey will return true even if the * EVP_PKEY object has no private key. Instead, we'll just get a * segfault during the SSL handshake. We need to check that a * private key is actually defined in the object. */ if (!SSL_use_PrivateKey(ssl, key)) return auxL_error(L, auxL_EOPENSSL, "ssl:setPrivateKey"); lua_pushboolean(L, 1); return 1; } /* ssl_setPrivateKey() */ static int ssl_getCertificate(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509 *x509; if (!(x509 = SSL_get_certificate(ssl))) return 0; xc_dup(L, x509); return 1; } /* ssl_getCertificate() */ static int ssl_getPeerCertificate(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); X509 **x509 = prepsimple(L, X509_CERT_CLASS); if (!(*x509 = SSL_get_peer_certificate(ssl))) return 0; return 1; } /* ssl_getPeerCertificate() */ static int ssl_getPeerChain(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); STACK_OF(X509) *chain; if (!(chain = SSL_get_peer_cert_chain(ssl))) return 0; xl_dup(L, chain, 0); return 1; } /* ssl_getPeerChain() */ static int ssl_getCipherInfo(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const SSL_CIPHER *cipher; char descr[256]; if (!(cipher = SSL_get_current_cipher(ssl))) return 0; lua_newtable(L); lua_pushstring(L, SSL_CIPHER_get_name(cipher)); lua_setfield(L, -2, "name"); lua_pushinteger(L, SSL_CIPHER_get_bits(cipher, 0)); lua_setfield(L, -2, "bits"); lua_pushstring(L, SSL_CIPHER_get_version(cipher)); lua_setfield(L, -2, "version"); lua_pushstring(L, SSL_CIPHER_description(cipher, descr, sizeof descr)); lua_setfield(L, -2, "description"); return 1; } /* ssl_getCipherInfo() */ static int ssl_setCipherList(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const char *ciphers = luaL_checkstring(L, 2); if (!SSL_set_cipher_list(ssl, ciphers)) return auxL_error(L, auxL_EOPENSSL, "ssl:setCipherList"); lua_pushboolean(L, 1); return 1; } /* ssl_setCipherList() */ #if HAVE_SSL_SET_CIPHERSUITES static int ssl_setCipherSuites(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const char *ciphers = luaL_checkstring(L, 2); if (!SSL_set_ciphersuites(ssl, ciphers)) return auxL_error(L, auxL_EOPENSSL, "ssl:setCipherSuites"); lua_pushboolean(L, 1); return 1; } /* ssl_setCipherSuites() */ #endif #if HAVE_SSL_SET_GROUPS_LIST static int ssl_setGroups(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const char *list = luaL_checkstring(L, 2); if (!SSL_set1_groups_list(ssl, list)) return auxL_error(L, auxL_EOPENSSL, "ssl:setGroups"); lua_pushboolean(L, 1); return 1; } /* ssl_setGroups() */ #endif static int ssl_getHostName(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const char *host; if (!(host = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) return 0; lua_pushstring(L, host); return 1; } /* ssl_getHostName() */ static int ssl_setHostName(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const char *host = luaL_optstring(L, 2, NULL); if (!SSL_set_tlsext_host_name(ssl, host)) return auxL_error(L, auxL_EOPENSSL, "ssl:setHostName"); lua_pushboolean(L, 1); return 1; } /* ssl_setHostName() */ static int ssl_getVersion(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); int format = luaL_checkoption(L, 2, "d", (const char *[]){ "d", ".", "f", NULL }); int version = SSL_version(ssl); int major, minor; switch (format) { case 1: case 2: major = 0xff & ((version >> 8)); minor = (0xff & version); luaL_argcheck(L, minor < 10, 2, "unable to convert SSL version to float because minor version >= 10"); lua_pushnumber(L, major + ((double)minor / 10)); break; default: lua_pushinteger(L, version); break; } return 1; } /* ssl_getVersion() */ static int ssl_getClientRandom(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); luaL_Buffer B; size_t len; unsigned char *out; len = SSL_get_client_random(ssl, NULL, 0); out = (unsigned char*)luaL_buffinitsize(L, &B, len); len = SSL_get_client_random(ssl, out, len); luaL_pushresultsize(&B, len); return 1; } /* ssl_getClientRandom() */ static int ssl_getMasterKey(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); SSL_SESSION *session; luaL_Buffer B; size_t len; unsigned char *out; session = SSL_get0_session(ssl); if (!session) { lua_pushnil(L); return 1; } len = SSL_SESSION_get_master_key(session, NULL, 0); out = (unsigned char*)luaL_buffinitsize(L, &B, len); len = SSL_SESSION_get_master_key(session, out, len); luaL_pushresultsize(&B, len); return 1; } /* ssl_getMasterKey() */ #if HAVE_SSL_GET_SERVER_TMP_KEY static int ssl_getServerTemporaryKey(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); EVP_PKEY **key = prepsimple(L, PKEY_CLASS); if (!SSL_get_server_tmp_key(ssl, key)) return 0; return 1; } /* ssl_getServerTemporaryKey() */ #endif static int ssl_getClientVersion(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); int format = luaL_checkoption(L, 2, "d", (const char *[]){ "d", ".", "f", NULL }); int version = SSL_client_version(ssl); int major, minor; switch (format) { case 1: case 2: major = 0xff & ((version >> 8)); minor = (0xff & version); luaL_argcheck(L, minor < 10, 2, "unable to convert SSL client version to float because minor version >= 10"); lua_pushnumber(L, major + ((double)minor / 10)); break; default: lua_pushinteger(L, version); break; } return 1; } /* ssl_getClientVersion() */ #if HAVE_SSL_GET0_ALPN_SELECTED static int ssl_getAlpnSelected(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); const unsigned char *data; unsigned len; SSL_get0_alpn_selected(ssl, &data, &len); if (0 == len) { lua_pushnil(L); } else { lua_pushlstring(L, (const char *)data, len); } return 1; } /* ssl_getAlpnSelected() */ #endif #if HAVE_SSL_SET_ALPN_PROTOS static int ssl_setAlpnProtos(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); luaL_Buffer B; size_t len; const char *tmp; luaL_buffinit(L, &B); checkprotos(&B, L, 2); luaL_pushresult(&B); tmp = lua_tolstring(L, -1, &len); /* OpenSSL 1.0.2 doesn't update the error stack on failure. */ ERR_clear_error(); if (0 != SSL_set_alpn_protos(ssl, (const unsigned char*)tmp, len)) { if (!ERR_peek_error()) { return luaL_error(L, "unable to set ALPN protocols: %s", aux_strerror(ENOMEM)); } else { return auxL_error(L, auxL_EOPENSSL, "ssl:setAlpnProtos"); } } lua_pushboolean(L, 1); return 1; } /* ssl_setAlpnProtos() */ #endif static int ssl_setTLSextStatusType(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); int type = checkTLSEXT_STATUSTYPE(L, 2); if(!SSL_set_tlsext_status_type(ssl, type)) return auxL_error(L, auxL_EOPENSSL, "ssl:setTLSextStatusType"); lua_pushboolean(L, 1); return 1; } /* ssl_setTLSextStatusType() */ #if HAVE_SSL_GET_TLSEXT_STATUS_TYPE static int ssl_getTLSextStatusType(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); int type = SSL_get_tlsext_status_type(ssl); switch(type) { case -1: lua_pushnil(L); break; case TLSEXT_STATUSTYPE_ocsp: lua_pushliteral(L, "ocsp"); break; default: luaL_error(L, "unknown TLS extension %d", type); } return 1; } /* ssl_getTLSextStatusType() */ #endif static int ssl_setTLSextStatusOCSPResp(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); OCSP_RESPONSE *or = testsimple(L, 2, OCSP_RESPONSE_CLASS); unsigned char *resp = NULL; long resp_len; if (or) { resp_len = i2d_OCSP_RESPONSE(or, &resp); if (resp_len <= 0) return auxL_error(L, auxL_EOPENSSL, "ssl:setTLSextStatusOCSPResp"); } else { resp_len = 0; } if (!SSL_set_tlsext_status_ocsp_resp(ssl, resp, resp_len)) return auxL_error(L, auxL_EOPENSSL, "ssl:setTLSextStatusOCSPResp"); lua_pushboolean(L, 1); return 1; } /* ssl_setTLSextStatusOCSPResp() */ static int ssl_getTLSextStatusOCSPResp(lua_State *L) { SSL *ssl = checksimple(L, 1, SSL_CLASS); OCSP_RESPONSE **ud = prepsimple(L, OCSP_RESPONSE_CLASS); const unsigned char *resp; long resp_len; resp_len = SSL_get_tlsext_status_ocsp_resp(ssl, &resp); if (resp == NULL) { lua_pushnil(L); return 1; } if (resp_len == -1) return auxL_error(L, auxL_EOPENSSL, "ssl:getTLSextStatusOCSPResp"); *ud = d2i_OCSP_RESPONSE(NULL, &resp, resp_len); if(*ud == NULL) return auxL_error(L, auxL_EOPENSSL, "ssl:getTLSextStatusOCSPResp"); return 1; } /* ssl_getTLSextStatusOCSPResp() */ static int ssl__gc(lua_State *L) { SSL **ud = luaL_checkudata(L, 1, SSL_CLASS); if (*ud) { SSL_free(*ud); *ud = NULL; } return 0; } /* ssl__gc() */ static const auxL_Reg ssl_methods[] = { { "setContext", &ssl_setContext }, { "getContext", &ssl_getContext }, { "setOptions", &ssl_setOptions }, { "getOptions", &ssl_getOptions }, { "clearOptions", &ssl_clearOptions }, { "setReadAhead", &ssl_setReadAhead }, { "getReadAhead", &ssl_getReadAhead }, #if HAVE_SSL_SET1_CHAIN_CERT_STORE { "setChainStore", &ssl_setChainStore }, #endif #if HAVE_SSL_SET1_VERIFY_CERT_STORE { "setVerifyStore", &ssl_setVerifyStore }, #endif { "setParam", &ssl_setParam }, { "getParam", &ssl_getParam }, { "setVerify", &ssl_setVerify }, { "getVerify", &ssl_getVerify }, { "getVerifyResult", &ssl_getVerifyResult }, { "setCertificate", &ssl_setCertificate }, #if HAVE_SSL_SET1_CHAIN { "setCertificateChain", &ssl_setCertificateChain }, #endif #if HAVE_SSL_GET0_CHAIN_CERTS { "getCertificateChain", &ssl_getCertificateChain }, #endif { "setPrivateKey", &ssl_setPrivateKey }, { "getCertificate", &ssl_getCertificate }, { "getPeerCertificate", &ssl_getPeerCertificate }, { "getPeerChain", &ssl_getPeerChain }, { "getCipherInfo", &ssl_getCipherInfo }, { "setCipherList", &ssl_setCipherList }, #if HAVE_SSL_SET_CIPHERSUITES { "setCipherSuites", &ssl_setCipherSuites }, #endif #if HAVE_SSL_SET_GROUPS_LIST { "setCurvesList", &ssl_setGroups }, /* old alias */ { "setGroups", &ssl_setGroups }, #endif { "getHostName", &ssl_getHostName }, { "setHostName", &ssl_setHostName }, { "getVersion", &ssl_getVersion }, { "getClientRandom", &ssl_getClientRandom }, { "getMasterKey", &ssl_getMasterKey }, #if HAVE_SSL_GET_SERVER_TMP_KEY { "getServerTemporaryKey", &ssl_getServerTemporaryKey }, #endif { "getClientVersion", &ssl_getClientVersion }, #if HAVE_SSL_GET0_ALPN_SELECTED { "getAlpnSelected", &ssl_getAlpnSelected }, #endif #if HAVE_SSL_SET_ALPN_PROTOS { "setAlpnProtos", &ssl_setAlpnProtos }, #endif { "setTLSextStatusType", &ssl_setTLSextStatusType }, #if HAVE_SSL_GET_TLSEXT_STATUS_TYPE { "getTLSextStatusType", &ssl_getTLSextStatusType }, #endif { "setTLSextStatusOCSPResp", &ssl_setTLSextStatusOCSPResp }, { "getTLSextStatusOCSPResp", &ssl_getTLSextStatusOCSPResp }, { NULL, NULL }, }; static const auxL_Reg ssl_metatable[] = { { "__gc", &ssl__gc }, { NULL, NULL }, }; static const auxL_Reg ssl_globals[] = { { "new", &ssl_new }, { "pushffi", &ssl_pushffi, 1 }, { "interpose", &ssl_interpose }, { NULL, NULL }, }; static const auxL_IntegerReg ssl_version[] = { { "SSL2_VERSION", SSL2_VERSION }, { "SSL3_VERSION", SSL3_VERSION }, { "TLS1_VERSION", TLS1_VERSION }, #if defined TLS1_1_VERSION { "TLS1_1_VERSION", TLS1_1_VERSION }, #endif #if defined TLS1_2_VERSION { "TLS1_2_VERSION", TLS1_2_VERSION }, #endif { NULL, 0 }, }; EXPORT int luaopen__openssl_ssl(lua_State *L) { initall(L); auxL_newlib(L, ssl_globals, 0); /* FFI argument checking */ lua_getfield(L, -1, "pushffi"); luaL_loadstring(L, "local ffi = require 'ffi'\n" \ "if not pcall(ffi.typeof, 'SSL*') then\n" \ " ffi.cdef 'typedef struct ssl_st SSL;'\n" \ "end\n" \ "local ffi_istype = ffi.istype\n" \ "local SSLp = ffi.typeof('SSL*')\n" \ "return function(p) return ffi_istype(SSLp, p) end\n" ); if (lua_pcall(L, 0, 1, 0)) { /* failed (probably no ffi library available) */ lua_pop(L, 1); /* use dummy function instead */ luaL_loadstring(L, "return false\n"); }; lua_setupvalue(L, -2, 1); lua_pop(L, 1); auxL_setintegers(L, ssl_version); auxL_setintegers(L, sx_verify); auxL_setintegers(L, sx_option); return 1; } /* luaopen__openssl_ssl() */ /* * X509_VERIFY_PARAM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int xp_new(lua_State *L) { X509_VERIFY_PARAM **ud = prepsimple(L, X509_VERIFY_PARAM_CLASS); if (!(*ud = X509_VERIFY_PARAM_new())) return auxL_error(L, auxL_EOPENSSL, "x509.verify_param.new"); return 1; } /* xp_new() */ static int xp_interpose(lua_State *L) { return interpose(L, X509_VERIFY_PARAM_CLASS); } /* xp_interpose() */ /* * NB: Per the OpenSSL source, "[t]he 'inh_flags' field determines how this * function behaves". (Referring to X509_VERIFY_PARAM_inherit.) The way to * set inh_flags prior to OpenSSL 1.1 was by OR'ing flags into the inh_flags * member and restoring it after the call. The OpenSSL 1.1 API makes the * X509_VERIFY_PARAM object opaque, X509_VERIFY_PARAM_inherit, and there's * no other function to set the flags argument; therefore it's not possible * to control the inherit behavior from OpenSSL 1.1. * * For more details see * https://github.com/openssl/openssl/issues/2054 and the original * https://github.com/wahern/luaossl/pull/76/commits/db6e414d68c0f94c2497d363f6131b4de1710ba9 */ static int xp_inherit(lua_State *L) { X509_VERIFY_PARAM *dest = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); X509_VERIFY_PARAM *src = testsimple(L, 2, X509_VERIFY_PARAM_CLASS); int ret; if (!src) { luaL_argcheck(L, lua_isstring(L, 2), 2, "expected " X509_VERIFY_PARAM_CLASS " or string"); src = (X509_VERIFY_PARAM*)X509_VERIFY_PARAM_lookup(lua_tostring(L, 2)); luaL_argcheck(L, src != NULL, 2, "unknown param preset"); } ret = X509_VERIFY_PARAM_inherit(dest, src); if (!ret) /* Note: openssl doesn't set an error as it should for some cases */ return auxL_error(L, auxL_EOPENSSL, "x509.verify_param:inherit"); lua_pushboolean(L, 1); return 1; } /* xp_inherit() */ static const X509_PURPOSE *purpose_checktype(lua_State *L, int index) { const char *purpose_name; int purpose_id; int purpose_idx; const X509_PURPOSE *purpose; if (lua_isnumber(L, index)) { purpose_id = luaL_checkinteger(L, index); purpose_idx = X509_PURPOSE_get_by_id(purpose_id); if (purpose_idx < 0) luaL_argerror(L, index, lua_pushfstring(L, "%d: invalid purpose", purpose_id)); } else { purpose_name = luaL_checkstring(L, index); purpose_idx = X509_PURPOSE_get_by_sname((char*)purpose_name); if (purpose_idx < 0) luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid purpose", purpose_name)); } purpose = X509_PURPOSE_get0(purpose_idx); return purpose; } /* purpose_checktype() */ static int xp_setPurpose(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); const X509_PURPOSE *purpose = purpose_checktype(L, 2); if (!X509_VERIFY_PARAM_set_purpose(xp, X509_PURPOSE_get_id((X509_PURPOSE*)purpose))) return auxL_error(L, auxL_EOPENSSL, "x509.verify_param:setPurpose"); lua_pushboolean(L, 1); return 1; } /* xp_setPurpose() */ static int xp_setTime(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); time_t t = luaL_checkinteger(L, 2); X509_VERIFY_PARAM_set_time(xp, t); lua_pushboolean(L, 1); return 1; } /* xp_setTime() */ static int xp_setDepth(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); int depth = luaL_checkinteger(L, 2); X509_VERIFY_PARAM_set_depth(xp, depth); lua_pushboolean(L, 1); return 1; } /* xp_setDepth() */ static int xp_getDepth(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); int depth = X509_VERIFY_PARAM_get_depth(xp); lua_pushinteger(L, depth); return 1; } /* xp_getDepth() */ #if HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL static int xp_setAuthLevel(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); int auth_level = luaL_checkinteger(L, 2); X509_VERIFY_PARAM_set_auth_level(xp, auth_level); lua_pushboolean(L, 1); return 1; } /* xp_setAuthLevel() */ static int xp_getAuthLevel(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); int auth_level = X509_VERIFY_PARAM_get_auth_level(xp); lua_pushinteger(L, auth_level); return 1; } /* xp_getAuthLevel() */ #endif #if HAVE_X509_VERIFY_PARAM_SET1_HOST static int xp_setHost(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); size_t len; const char *str = luaL_optlstring(L, 2, NULL, &len); /* NULL = clear hosts */ if (!X509_VERIFY_PARAM_set1_host(xp, str, len)) /* Note: openssl doesn't set an error as it should for some cases */ return auxL_error(L, auxL_EOPENSSL, "x509.verify_param:setHost"); lua_pushboolean(L, 1); return 1; } /* xp_setHost() */ #endif #if HAVE_X509_VERIFY_PARAM_ADD1_HOST static int xp_addHost(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); size_t len; const char *str = luaL_checklstring(L, 2, &len); if (!X509_VERIFY_PARAM_add1_host(xp, str, len)) /* Note: openssl doesn't set an error as it should for some cases */ return auxL_error(L, auxL_EOPENSSL, "x509.verify_param:addHost"); lua_pushboolean(L, 1); return 1; } /* xp_addHost() */ #endif #if HAVE_X509_VERIFY_PARAM_SET1_EMAIL static int xp_setEmail(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); size_t len; const char *str = luaL_checklstring(L, 2, &len); if (!X509_VERIFY_PARAM_set1_email(xp, str, len)) /* Note: openssl doesn't set an error as it should for some cases */ return auxL_error(L, auxL_EOPENSSL, "x509.verify_param:setEmail"); lua_pushboolean(L, 1); return 1; } /* xp_setEmail() */ #endif #if HAVE_X509_VERIFY_PARAM_SET1_IP_ASC static int xp_setIP(lua_State *L) { X509_VERIFY_PARAM *xp = checksimple(L, 1, X509_VERIFY_PARAM_CLASS); const char *str = luaL_checkstring(L, 2); if (!X509_VERIFY_PARAM_set1_ip_asc(xp, str)) /* Note: openssl doesn't set an error as it should for some cases */ return auxL_error(L, auxL_EOPENSSL, "x509.verify_param:setIP"); lua_pushboolean(L, 1); return 1; } /* xp_setIP() */ #endif static int xp__gc(lua_State *L) { X509_VERIFY_PARAM **ud = luaL_checkudata(L, 1, X509_VERIFY_PARAM_CLASS); X509_VERIFY_PARAM_free(*ud); *ud = NULL; return 0; } /* xp__gc() */ static const auxL_Reg xp_methods[] = { { "inherit", &xp_inherit }, { "setPurpose", &xp_setPurpose }, { "setTime", &xp_setTime }, { "setDepth", &xp_setDepth }, { "getDepth", &xp_getDepth }, #if HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL { "setAuthLevel", &xp_setAuthLevel }, { "getAuthLevel", &xp_getAuthLevel }, #endif #if HAVE_X509_VERIFY_PARAM_SET1_HOST { "setHost", &xp_setHost }, #endif #if HAVE_X509_VERIFY_PARAM_ADD1_HOST { "addHost", &xp_addHost }, #endif #if HAVE_X509_VERIFY_PARAM_SET1_EMAIL { "setEmail", &xp_setEmail }, #endif #if HAVE_X509_VERIFY_PARAM_SET1_IP_ASC { "setIP", &xp_setIP }, #endif { NULL, NULL }, }; static const auxL_Reg xp_metatable[] = { { "__gc", &xp__gc }, { NULL, NULL }, }; static const auxL_Reg xp_globals[] = { { "new", &xp_new }, { "interpose", &xp_interpose }, { NULL, NULL }, }; static const auxL_IntegerReg xp_inherit_flags[] = { { "DEFAULT", X509_VP_FLAG_DEFAULT }, { "OVERWRITE", X509_VP_FLAG_OVERWRITE }, { "RESET_FLAGS", X509_VP_FLAG_RESET_FLAGS }, { "LOCKED", X509_VP_FLAG_LOCKED }, { "ONCE", X509_VP_FLAG_ONCE }, { NULL, 0 } }; EXPORT int luaopen__openssl_x509_verify_param(lua_State *L) { initall(L); auxL_newlib(L, xp_globals, 0); auxL_setintegers(L, xp_inherit_flags); return 1; } /* luaopen__openssl_x509_verify_param() */ /* * Digest - openssl.digest * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static const EVP_MD *md_checkdigest(lua_State *L, int index) { const char *name = luaL_checkstring(L, index); const EVP_MD *type; if (!(type = EVP_get_digestbyname(name))) luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid digest type", name)); return type; } /* md_checkdigest() */ static const EVP_MD *md_optdigest(lua_State *L, int index) { if (lua_isnoneornil(L, index)) return EVP_get_digestbyname("sha1"); return md_checkdigest(L, index); } /* md_optdigest() */ static int md_new(lua_State *L) { const EVP_MD *type = md_optdigest(L, 1); EVP_MD_CTX **ctx; ctx = prepsimple(L, DIGEST_CLASS, NULL); if (!(*ctx = EVP_MD_CTX_new()) || !EVP_DigestInit_ex(*ctx, type, NULL)) return auxL_error(L, auxL_EOPENSSL, "digest.new"); return 1; } /* md_new() */ static int md_interpose(lua_State *L) { return interpose(L, DIGEST_CLASS); } /* md_interpose() */ static void md_update_(lua_State *L, EVP_MD_CTX *ctx, int from, int to) { int i; for (i = from; i <= to; i++) { const void *p; size_t n; p = luaL_checklstring(L, i, &n); if (!EVP_DigestUpdate(ctx, p, n)) auxL_error(L, auxL_EOPENSSL, "digest:update"); } } /* md_update_() */ static int md_update(lua_State *L) { EVP_MD_CTX *ctx = checksimple(L, 1, DIGEST_CLASS); md_update_(L, ctx, 2, lua_gettop(L)); lua_pushvalue(L, 1); return 1; } /* md_update() */ static int md_final(lua_State *L) { EVP_MD_CTX *ctx = checksimple(L, 1, DIGEST_CLASS); unsigned char md[EVP_MAX_MD_SIZE]; unsigned len; md_update_(L, ctx, 2, lua_gettop(L)); if (!EVP_DigestFinal_ex(ctx, md, &len)) return auxL_error(L, auxL_EOPENSSL, "digest:final"); lua_pushlstring(L, (char *)md, len); return 1; } /* md_final() */ static int md__gc(lua_State *L) { EVP_MD_CTX **ctx = luaL_checkudata(L, 1, DIGEST_CLASS); EVP_MD_CTX_free(*ctx); *ctx = NULL; return 0; } /* md__gc() */ static const auxL_Reg md_methods[] = { { "update", &md_update }, { "final", &md_final }, { NULL, NULL }, }; static const auxL_Reg md_metatable[] = { { "__gc", &md__gc }, { NULL, NULL }, }; static const auxL_Reg md_globals[] = { { "new", &md_new }, { "interpose", &md_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_digest(lua_State *L) { initall(L); auxL_newlib(L, md_globals, 0); return 1; } /* luaopen__openssl_digest() */ /* * HMAC - openssl.hmac * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int hmac_new(lua_State *L) { const void *key; size_t len; const EVP_MD *type; HMAC_CTX **ctx; key = luaL_checklstring(L, 1, &len); type = md_optdigest(L, 2); ctx = prepsimple(L, HMAC_CLASS, NULL); if (!(*ctx = HMAC_CTX_new())) goto eossl; #if HMAC_INIT_EX_INT if (!HMAC_Init_ex(*ctx, key, len, type, NULL)) goto eossl; #else HMAC_Init_ex(*ctx, key, len, type, NULL); #endif return 1; eossl: return auxL_error(L, auxL_EOPENSSL, "hmac.new"); } /* hmac_new() */ static int hmac_interpose(lua_State *L) { return interpose(L, HMAC_CLASS); } /* hmac_interpose() */ static void hmac_update_(lua_State *L, HMAC_CTX *ctx, int from, int to) { int i; for (i = from; i <= to; i++) { const void *p; size_t n; p = luaL_checklstring(L, i, &n); HMAC_Update(ctx, p, n); } } /* hmac_update_() */ static int hmac_update(lua_State *L) { HMAC_CTX *ctx = checksimple(L, 1, HMAC_CLASS); hmac_update_(L, ctx, 2, lua_gettop(L)); lua_pushvalue(L, 1); return 1; } /* hmac_update() */ static int hmac_final(lua_State *L) { HMAC_CTX *ctx = checksimple(L, 1, HMAC_CLASS); unsigned char hmac[EVP_MAX_MD_SIZE]; unsigned len; hmac_update_(L, ctx, 2, lua_gettop(L)); HMAC_Final(ctx, hmac, &len); lua_pushlstring(L, (char *)hmac, len); return 1; } /* hmac_final() */ static int hmac__gc(lua_State *L) { HMAC_CTX **ctx = luaL_checkudata(L, 1, HMAC_CLASS); HMAC_CTX_free(*ctx); *ctx = NULL; return 0; } /* hmac__gc() */ static const auxL_Reg hmac_methods[] = { { "update", &hmac_update }, { "final", &hmac_final }, { NULL, NULL }, }; static const auxL_Reg hmac_metatable[] = { { "__gc", &hmac__gc }, { NULL, NULL }, }; static const auxL_Reg hmac_globals[] = { { "new", &hmac_new }, { "interpose", &hmac_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_hmac(lua_State *L) { initall(L); auxL_newlib(L, hmac_globals, 0); return 1; } /* luaopen__openssl_hmac() */ /* * Cipher - openssl.cipher * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static const EVP_CIPHER *cipher_checktype(lua_State *L, int index) { const char *name = luaL_checkstring(L, index); const EVP_CIPHER *type; if (!(type = EVP_get_cipherbyname(name))) luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid cipher type", name)); return type; } /* cipher_checktype() */ static int cipher_new(lua_State *L) { const EVP_CIPHER *type; EVP_CIPHER_CTX **ctx; unsigned char key[EVP_MAX_KEY_LENGTH] = { 0 }; type = cipher_checktype(L, 1); ctx = prepsimple(L, CIPHER_CLASS, NULL); if (!(*ctx = EVP_CIPHER_CTX_new())) goto eossl; /* * NOTE: For some ciphers like AES calling :update or :final without * setting a key causes a SEGV. Set a dummy key here. Same solution * as used by Ruby OSSL. */ if (!EVP_CipherInit_ex(*ctx, type, NULL, key, NULL, -1)) goto eossl; return 1; eossl: return auxL_error(L, auxL_EOPENSSL, "cipher.new"); } /* cipher_new() */ static int cipher_interpose(lua_State *L) { return interpose(L, CIPHER_CLASS); } /* cipher_interpose() */ static int cipher_init(lua_State *L, _Bool encrypt) { EVP_CIPHER_CTX *ctx = checksimple(L, 1, CIPHER_CLASS); const void *key, *iv; size_t n, m; key = luaL_checklstring(L, 2, &n); m = (size_t)EVP_CIPHER_CTX_key_length(ctx); luaL_argcheck(L, n == m, 2, lua_pushfstring(L, "%d: invalid key length (should be %d)", (int)n, (int)m)); iv = luaL_optlstring(L, 3, NULL, &n); /* Set the IV length before init */ #if defined EVP_CTRL_AEAD_SET_IVLEN if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, n, NULL) <= 0) { #elif defined EVP_CTRL_GCM_SET_IVLEN /* https://github.com/openssl/openssl/issues/8330#issuecomment-516838331 */ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, n, NULL) <= 0) { #else { #endif /* wasn't able to set IV len; check if it's already correct */ m = (size_t)EVP_CIPHER_CTX_iv_length(ctx); luaL_argcheck(L, n == m, 3, lua_pushfstring(L, "%d: invalid IV length (should be %d)", (int)n, (int)m)); } if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, encrypt)) goto sslerr; if (!lua_isnoneornil(L, 4)) { luaL_checktype(L, 4, LUA_TBOOLEAN); if (!EVP_CIPHER_CTX_set_padding(ctx, lua_toboolean(L, 4))) goto sslerr; } lua_settop(L, 1); return 1; sslerr: return auxL_error(L, auxL_EOPENSSL, (encrypt)? "cipher:encrypt" : "cipher:decrypt"); } /* cipher_init() */ static int cipher_encrypt(lua_State *L) { return cipher_init(L, 1); } /* cipher_encrypt() */ static int cipher_decrypt(lua_State *L) { return cipher_init(L, 0); } /* cipher_decrypt() */ static _Bool cipher_update_(lua_State *L, EVP_CIPHER_CTX *ctx, luaL_Buffer *B, int from, int to) { const unsigned char *p; size_t n; int i, out; for (i = from; i <= to; i++) { p = (const unsigned char *)luaL_checklstring(L, i, &n); if (!EVP_CipherUpdate(ctx, (void *)luaL_prepbuffsize(B, n+EVP_MAX_BLOCK_LENGTH), &out, p, n)) return 0; luaL_addsize(B, out); } return 1; } /* cipher_update_() */ static int cipher_update(lua_State *L) { EVP_CIPHER_CTX *ctx = checksimple(L, 1, CIPHER_CLASS); luaL_Buffer B; int top = lua_gettop(L); luaL_buffinit(L, &B); if (!cipher_update_(L, ctx, &B, 2, top)) goto sslerr; luaL_pushresult(&B); return 1; sslerr: lua_pushnil(L); auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } /* cipher_update() */ static int cipher_final(lua_State *L) { EVP_CIPHER_CTX *ctx = checksimple(L, 1, CIPHER_CLASS); luaL_Buffer B; size_t block; int out; int top = lua_gettop(L); luaL_buffinit(L, &B); if (!cipher_update_(L, ctx, &B, 2, top)) goto sslerr; block = EVP_CIPHER_CTX_block_size(ctx); if (!EVP_CipherFinal(ctx, (void *)luaL_prepbuffsize(&B, block), &out)) goto sslerr; luaL_pushresultsize(&B, out); return 1; sslerr: lua_pushnil(L); auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } /* cipher_final() */ static int cipher_get_tag(lua_State *L) { EVP_CIPHER_CTX *ctx = checksimple(L, 1, CIPHER_CLASS); luaL_Buffer tag; size_t tag_size = luaL_checkinteger(L, 2); luaL_buffinit(L, &tag); /* EVP_CTRL_GCM_GET_TAG is works for both GCM and CCM and across all * supported OpenSSL versions. We can switch to the unified identifier * 'EVP_CTRL_AEAD_GET_TAG' in OpenSSL 1.1+. */ if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, (void*)luaL_prepbuffsize(&tag, tag_size))) { goto sslerr; } luaL_pushresultsize(&tag, tag_size); return 1; sslerr: lua_pushnil(L); auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } /* cipher_get_tag() */ static int cipher_set_tag(lua_State *L) { EVP_CIPHER_CTX *ctx = checksimple(L, 1, CIPHER_CLASS); size_t tag_size; const char* tag = luaL_checklstring(L, 2, &tag_size); if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_size, (void*)tag)) { goto sslerr; } lua_pushlstring(L, tag, tag_size); return 1; sslerr: lua_pushnil(L); auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } /* cipher_set_tag() */ static int cipher__gc(lua_State *L) { EVP_CIPHER_CTX **ctx = luaL_checkudata(L, 1, CIPHER_CLASS); EVP_CIPHER_CTX_free(*ctx); *ctx = NULL; return 0; } /* cipher__gc() */ static const auxL_Reg cipher_methods[] = { { "encrypt", &cipher_encrypt }, { "decrypt", &cipher_decrypt }, { "update", &cipher_update }, { "final", &cipher_final }, { "getTag", &cipher_get_tag }, { "setTag", &cipher_set_tag }, { NULL, NULL }, }; static const auxL_Reg cipher_metatable[] = { { "__gc", &cipher__gc }, { NULL, NULL }, }; static const auxL_Reg cipher_globals[] = { { "new", &cipher_new }, { "interpose", &cipher_interpose }, { NULL, NULL }, }; EXPORT int luaopen__openssl_cipher(lua_State *L) { initall(L); auxL_newlib(L, cipher_globals, 0); return 1; } /* luaopen__openssl_cipher() */ /* * openssl.kdf * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int EVP_KDF__gc(lua_State *L) { EVP_KDF_CTX **res = lua_touserdata(L, 1); if (*res) { EVP_KDF_CTX_free(*res); *res = NULL; } return 0; } /* EVP_KDF__gc() */ static int kdf_derive(lua_State *L) { LUAOSSL_EVP_KDF_PTR kdf; luaL_Buffer b; EVP_KDF_CTX *kctx, **kctxp; #if HAVE_OSSL_PARAM OSSL_PARAM params[15], *param = params; #endif unsigned char* out; size_t outlen = 0; const char *str = NULL; size_t len; _Bool seed = 0; int mode; unsigned int iter; uint64_t maxmem_bytes, scrypt_n; uint32_t scrypt_r, scrypt_p; luaL_checktype(L, 1, LUA_TTABLE); { const char* type; if (!loadfield(L, 1, "type", LUA_TSTRING, &type)) return luaL_argerror(L, 1, "missing 'type' field"); if ((kdf = EVP_KDF_fetch(NULL, type, NULL)) == LUAOSSL_EVP_KDF_UNDEF) return luaL_argerror(L, 1, "unknown 'type'"); } /* ensure EVP_KDF_CTX is collected on error */ kctxp = prepudata(L, sizeof(EVP_KDF_CTX*), NULL, &EVP_KDF__gc); if (!(kctx = EVP_KDF_CTX_new(kdf))) return auxL_error(L, auxL_EOPENSSL, "kdf.derive"); *kctxp = kctx; lua_pushnil(L); while (lua_next(L, 1)) { switch (auxL_testoption(L, -2, 0, (const char *[]){ /* special fields */ "type", "outlen", /* general options */ "pass", "salt", "iter", "md", "key", "maxmem_bytes", /* KDF specific */ "secret", "seed", "info", "hkdf_mode", "N", "r", "p", NULL }, 0)) { case 0: /* skip 'type' */ break; case 1: outlen = auxL_checkunsigned(L, -1, 1, SIZE_MAX-1); break; case 2: str = luaL_checklstring(L, -1, &len); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, (void *)str, len); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_PASS, (const unsigned char*)str, len) <= 0) goto error; #endif break; case 3: str = luaL_checklstring(L, -1, &len); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, (void *)str, len); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, (const unsigned char*)str, len) <= 0) goto error; #endif break; case 4: iter = auxL_checkunsigned(L, -1, 1, (int)-1); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_uint(OSSL_KDF_PARAM_ITER, &iter); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_ITER, iter) <= 0) goto error; #endif break; case 5: #if HAVE_OSSL_PARAM str = luaL_checklstring(L, -1, &len); *param++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, (void *)str, len); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, md_checkdigest(L, -1)) <= 0) goto error; #endif break; case 6: str = luaL_checklstring(L, -1, &len); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (void *)str, len); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, (const unsigned char*)str, len) <= 0) goto error; #endif break; case 7: maxmem_bytes = auxL_checkunsigned(L, -1, 0, UINT64_MAX); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, &maxmem_bytes); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MAXMEM_BYTES, maxmem_bytes) <= 0) goto error; #endif break; case 8: str = luaL_checklstring(L, -1, &len); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET, (void *)str, len); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_TLS_SECRET, (const unsigned char*)str, len) <= 0) goto error; #endif break; case 9: str = luaL_checklstring(L, -1, &len); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SEED, (void *)str, len); #else seed = 1; #endif break; case 10: str = luaL_checklstring(L, -1, &len); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, (void *)str, len); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_ADD_HKDF_INFO, (const unsigned char*)str, len) <= 0) goto error; #endif break; case 11: mode = ((int[]){ #ifdef EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND, #endif #ifdef EVP_KDF_HKDF_MODE_EXTRACT_ONLY EVP_KDF_HKDF_MODE_EXTRACT_ONLY, #endif #ifdef EVP_KDF_HKDF_MODE_EXPAND_ONLY EVP_KDF_HKDF_MODE_EXPAND_ONLY, #endif 0 })[auxL_checkoption(L, -1, 0, (const char *[]){ #ifdef EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND "extract_and_expand", #endif #ifdef EVP_KDF_HKDF_MODE_EXTRACT_ONLY "extract_only", #endif #ifdef EVP_KDF_HKDF_MODE_EXPAND_ONLY "expand_only", #endif NULL }, 0)]; #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_HKDF_MODE, mode) <= 0) goto error; #endif break; case 12: scrypt_n = auxL_checkunsigned(L, -1, 0, UINT64_MAX); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_N, &scrypt_n); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_N, scrypt_n) <= 0) goto error; #endif break; case 13: scrypt_r = auxL_checkunsigned(L, -1, 0, UINT32_MAX); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_SCRYPT_R, &scrypt_r); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_R, scrypt_r) <= 0) goto error; #endif break; case 14: scrypt_p = auxL_checkunsigned(L, -1, 0, UINT32_MAX); #if HAVE_OSSL_PARAM *param++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_SCRYPT_P, &scrypt_p); #else if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_P, scrypt_p) <= 0) goto error; #endif break; default: return luaL_argerror(L, 1, lua_pushfstring(L, "unknown field '%s'", lua_tostring(L, -2))); } lua_pop(L, 1); } #if HAVE_OSSL_PARAM *param = OSSL_PARAM_construct_end(); if(EVP_KDF_CTX_set_params(kctx,params) <= 0) { goto error; } #else /* XXX: seed must be set *after* secret * https://github.com/openssl/openssl/issues/7728 */ if (seed) { lua_getfield(L, 1, "seed"); str = luaL_checklstring(L, -1, &len); if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_ADD_TLS_SEED, (const unsigned char*)str, len) <= 0) goto error; lua_pop(L, 1); } #endif if (outlen == 0) { outlen = EVP_KDF_CTX_get_kdf_size(kctx); if (outlen == 0) goto error; if (outlen == SIZE_MAX) return luaL_argerror(L, 1, "missing 'outlen' field"); } out = (unsigned char *)luaL_buffinitsize(L, &b, outlen); if (EVP_KDF_derive(kctx, out, outlen, NULL) <= 0) goto error; EVP_KDF_CTX_free(kctx); *kctxp = NULL; luaL_pushresultsize(&b, outlen); return 1; error: if (*kctxp) { EVP_KDF_CTX_free(kctx); *kctxp = NULL; } return auxL_error(L, auxL_EOPENSSL, "kdf.derive"); } /* kdf_derive */ static const auxL_Reg kdf_globals[] = { { "derive", &kdf_derive }, { NULL, NULL }, }; int luaopen__openssl_kdf(lua_State *L) { initall(L); auxL_newlib(L, kdf_globals, 0); return 1; } /* luaopen__openssl_kdf() */ /* * OCSP_RESPONSE - openssl.ocsp.response * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int or_tostring(lua_State *L) { OCSP_RESPONSE *resp = checksimple(L, 1, OCSP_RESPONSE_CLASS); BIO *bio = getbio(L); size_t len; char *bytes; if (!OCSP_RESPONSE_print(bio, resp, 0)) return auxL_error(L, auxL_EOPENSSL, "OCSP_RESPONSE:tostring"); len = BIO_get_mem_data(bio, &bytes); lua_pushlstring(L, bytes, len); return 1; } /* or__tostring() */ static int or_toPEM(lua_State *L) { OCSP_RESPONSE *resp = checksimple(L, 1, OCSP_RESPONSE_CLASS); BIO *bio = getbio(L); size_t len; char *bytes; if (!PEM_write_bio_OCSP_RESPONSE(bio, resp)) return auxL_error(L, auxL_EOPENSSL, "OCSP_RESPONSE:toPEM"); len = BIO_get_mem_data(bio, &bytes); lua_pushlstring(L, bytes, len); return 1; } /* or_toPEM() */ static int or_getBasic(lua_State *L) { OCSP_RESPONSE *resp = checksimple(L, 1, OCSP_RESPONSE_CLASS); OCSP_BASICRESP **basic = prepsimple(L, OCSP_BASICRESP_CLASS); *basic = OCSP_response_get1_basic(resp); if (!*basic) return auxL_error(L, auxL_EOPENSSL, "OCSP_RESPONSE:getBasic"); return 1; } /* or_getBasic() */ static int or__gc(lua_State *L) { OCSP_RESPONSE **ud = luaL_checkudata(L, 1, OCSP_RESPONSE_CLASS); if (*ud) { OCSP_RESPONSE_free(*ud); *ud = NULL; } return 0; } /* or__gc() */ static const auxL_Reg or_methods[] = { { "tostring", &or_tostring }, { "toPEM", &or_toPEM }, { "getBasic", &or_getBasic }, { NULL, NULL }, }; static const auxL_Reg or_metatable[] = { { "__tostring", &or_tostring }, { "__gc", &or__gc }, { NULL, NULL }, }; static const auxL_Reg or_globals[] = { { NULL, NULL }, }; EXPORT int luaopen__openssl_ocsp_response(lua_State *L) { initall(L); auxL_newlib(L, or_globals, 0); return 1; } /* luaopen__openssl_ocsp_response() */ /* * OCSP_BASICRESP - openssl.ocsp.basic * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int ob_verify(lua_State *L) { OCSP_BASICRESP *basic = checksimple(L, 1, OCSP_BASICRESP_CLASS); STACK_OF(X509) *certs = testsimple(L, 2, X509_CHAIN_CLASS); X509_STORE *store = testsimple(L, 3, X509_STORE_CLASS); unsigned long flags = luaL_optinteger(L, 4, 0); int res = OCSP_basic_verify(basic, certs, store, flags); if (res == -1) return auxL_error(L, auxL_EOPENSSL, "OCSP_BASICRESP:verify"); lua_pushboolean(L, res); if (res) { return 1; } else { auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } } /* ob_verify() */ static int ob__gc(lua_State *L) { OCSP_BASICRESP **ud = luaL_checkudata(L, 1, OCSP_BASICRESP_CLASS); if (*ud) { OCSP_BASICRESP_free(*ud); *ud = NULL; } return 0; } /* or__gc() */ static const auxL_Reg ob_methods[] = { { "verify", &ob_verify }, { NULL, NULL }, }; static const auxL_Reg ob_metatable[] = { { "__gc", &ob__gc }, { NULL, NULL }, }; static const auxL_Reg ob_globals[] = { { NULL, NULL }, }; static const auxL_IntegerReg ob_verify_flags[] = { { "NOSIGS", OCSP_NOSIGS}, { "NOVERIFY", OCSP_NOVERIFY}, { "NOCHAIN", OCSP_NOCHAIN}, { "NOCHECKS", OCSP_NOCHECKS}, { "NOEXPLICIT", OCSP_NOEXPLICIT}, { "TRUSTOTHER", OCSP_TRUSTOTHER}, { "NOINTERN", OCSP_NOINTERN}, { "TRUSTOTHER", OCSP_TRUSTOTHER}, { NULL, 0 }, }; EXPORT int luaopen__openssl_ocsp_basic(lua_State *L) { initall(L); auxL_newlib(L, ob_globals, 0); auxL_setintegers(L, ob_verify_flags); return 1; } /* luaopen__openssl_ocsp_basic() */ /* * Rand - openssl.rand * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct randL_state { #ifdef _WIN32 DWORD pid; #else pid_t pid; #endif }; /* struct randL_state */ static struct randL_state *randL_getstate(lua_State *L) { return lua_touserdata(L, lua_upvalueindex(1)); } /* randL_getstate() */ #if HAVE_SYS_SYSCALL_H #include /* SYS_getrandom syscall(2) */ #endif #if HAVE_SYS_SYSCTL_H #include /* CTL_KERN KERN_RANDOM RANDOM_UUID sysctl(2) */ #endif static int randL_stir(struct randL_state *st, unsigned rqstd) { unsigned count = 0; int error; unsigned char data[256]; #ifdef _WIN32 HCRYPTPROV hCryptProv; BOOL ok; if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { error = GetLastError(); goto error; } while (count < rqstd) { ok = CryptGenRandom(hCryptProv, sizeof data, (BYTE*)data); if (!ok) { CryptReleaseContext(hCryptProv, 0); error = GetLastError(); goto error; } RAND_seed(data, sizeof data); count += sizeof data; } CryptReleaseContext(hCryptProv, 0); st->pid = GetCurrentProcessId(); #else #if HAVE_ARC4RANDOM_BUF while (count < rqstd) { size_t n = MIN(rqstd - count, sizeof data); arc4random_buf(data, n); RAND_seed(data, n); count += n; } #endif #if HAVE_SYSCALL && HAVE_DECL_SYS_GETRANDOM while (count < rqstd) { size_t lim = MIN(rqstd - count, sizeof data); int n; n = syscall(SYS_getrandom, data, lim, 0); if (n == -1) { break; } RAND_seed(data, n); count += n; } #endif #if HAVE_SYS_SYSCTL_H && HAVE_DECL_RANDOM_UUID while (count < rqstd) { int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID }; size_t n = MIN(rqstd - count, sizeof data); if (0 != sysctl(mib, countof(mib), data, &n, (void *)0, 0)) break; RAND_seed(data, n); count += n; } #endif if (count < rqstd) { #if defined O_CLOEXEC && (!defined _AIX /* O_CLOEXEC overflows int */) int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); #else int fd = open("/dev/urandom", O_RDONLY); #endif if (fd == -1) { error = errno; goto error; } while (count < rqstd) { ssize_t n = read(fd, data, MIN(rqstd - count, sizeof data)); switch (n) { case 0: errno = EIO; /* FALL THROUGH */ case -1: if (errno == EINTR) continue; error = errno; close(fd); goto error; default: RAND_seed(data, n); count += n; } } close(fd); } st->pid = getpid(); #endif /* _WIN32 */ return 0; error:; struct { #ifdef _WIN32 DWORD pid; SYSTEMTIME tv; FILETIME ftCreation, ftExit, ftKernel, ftUser; #else pid_t pid; struct timeval tv; struct rusage ru; struct utsname un; #endif uintptr_t aslr; #if defined __APPLE__ uint64_t mt; #elif defined __sun struct timespec mt; #endif } junk; #ifdef _WIN32 junk.pid = GetCurrentProcessId(); GetSystemTime(&junk.tv); GetProcessTimes(GetCurrentProcess(), &junk.ftCreation, &junk.ftExit, &junk.ftKernel, &junk.ftUser); #else junk.pid = getpid(); gettimeofday(&junk.tv, NULL); getrusage(RUSAGE_SELF, &junk.ru); uname(&junk.un); #endif junk.aslr = (uintptr_t)&strcpy ^ (uintptr_t)&randL_stir; #if defined __APPLE__ junk.mt = mach_absolute_time(); #elif defined __sun /* * NOTE: Linux requires -lrt for clock_gettime, and in any event * should have RANDOM_UUID or getrandom. (Though, some middle-aged * kernels might have neither). The BSDs have arc4random which * should be using KERN_URND, KERN_ARND, and more recently * getentropy. (Though, again, some older BSD kernels used an * arc4random implementation that opened /dev/urandom.) * * Just do this for Solaris to keep things simple. We've already * crossed the line of what can be reasonably accomplished on * unreasonable platforms. */ clock_gettime(CLOCK_MONOTONIC, &junk.mt); #endif RAND_add(&junk, sizeof junk, 0.1); #ifdef _WIN32 st->pid = GetCurrentProcessId(); #else st->pid = getpid(); #endif return error; } /* randL_stir() */ static void randL_checkpid(struct randL_state *st) { #ifdef _WIN32 if (st->pid != GetCurrentProcessId()) #else if (st->pid != getpid()) #endif (void)randL_stir(st, 16); } /* randL_checkpid() */ static int rand_stir(lua_State *L) { int error = randL_stir(randL_getstate(L), auxL_optunsigned(L, 1, 16, 0, UINT_MAX)); if (error) { lua_pushboolean(L, 0); lua_pushstring(L, aux_strerror(error)); lua_pushinteger(L, error); return 3; } else { lua_pushboolean(L, 1); return 1; } } /* rand_stir() */ static int rand_add(lua_State *L) { const void *buf; size_t len; lua_Number entropy; buf = luaL_checklstring(L, 1, &len); entropy = luaL_optnumber(L, 2, len); RAND_add(buf, len, entropy); lua_pushboolean(L, 1); return 1; } /* rand_add() */ static int rand_bytes(lua_State *L) { int size = luaL_checkinteger(L, 1); luaL_Buffer B; randL_checkpid(randL_getstate(L)); if (!RAND_bytes((void *)luaL_buffinitsize(L, &B, size), size)) return auxL_error(L, auxL_EOPENSSL, "rand.bytes"); luaL_pushresultsize(&B, size); return 1; } /* rand_bytes() */ static int rand_ready(lua_State *L) { lua_pushboolean(L, RAND_status() == 1); return 1; } /* rand_ready() */ static unsigned long long rand_llu(lua_State *L) { unsigned long long llu; if (!RAND_bytes((void *)&llu, sizeof llu)) auxL_error(L, auxL_EOPENSSL, "rand.uniform"); return llu; } /* rand_llu() */ /* * The following algorithm for rand_uniform() is taken from OpenBSD's * arc4random_uniform, written by Otto Moerbeek, with subsequent * simplification by Jorden Verwer. Otto's source code comment reads * * Uniformity is achieved by generating new random numbers until the one * returned is outside the range [0, 2**32 % upper_bound). This guarantees * the selected random number will be inside [2**32 % upper_bound, 2**32) * which maps back to [0, upper_bound) after reduction modulo upper_bound. * * -- * A more bit-efficient approach by the eminent statistician Herman Rubin * can be found in this sci.crypt Usenet post. * * From: hrubin@odds.stat.purdue.edu (Herman Rubin) * Newsgroups: sci.crypt * Subject: Re: Generating a random number between 0 and N-1 * Date: 14 Nov 2002 11:20:37 -0500 * Organization: Purdue University Statistics Department * Lines: 40 * Message-ID: * References: <3DCD8D75.40408@nospam.com> * NNTP-Posting-Host: odds.stat.purdue.edu * X-Trace: mozo.cc.purdue.edu 1037290837 9316 128.210.141.13 (14 Nov 2002 16:20:37 GMT) * X-Complaints-To: ne...@news.purdue.edu * NNTP-Posting-Date: Thu, 14 Nov 2002 16:20:37 +0000 (UTC) * Xref: archiver1.google.com sci.crypt:78935 * * In article <3DCD8D7...@nospam.com>, * Michael Amling wrote: * >Carlos Moreno wrote: * * I have already posted on this, but a repeat might be * in order. * * If one can trust random bits, the most bitwise efficient * manner to get a single random integer between 0 and N-1 * can be obtained as follows; the code can be made more * computationally efficient. I believe it is easier to * understand with gotos. I am assuming N>1. * * i = 0; j = 1; * * loop: j=2*j; i=2*i+RANBIT; * if (j < N) goto loop; * if (i >= N) { * i = i - N; * j = j - N; * goto loop:} * else return (i); * * The algorithm works because at each stage i is uniform * between 0 and j-1. * * Another possibility is to generate k bits, where 2^k >= N. * If 2^k = c*N + remainder, generate the appropriate value * if a k-bit random number is less than c*N. * * For N = 17 (numbers just larger than powers of 2 are "bad"), * the amount of information is about 4.09 bits, the best * algorithm to generate one random number takes about 5.765 * bits, taking k = 5 uses 9.412 bits, taking k = 6 or 7 uses * 7.529 bits. These are averages, but the tails are not bad. * * (https://groups.google.com/forum/message/raw?msg=sci.crypt/DMslf6tSrD8/rv9rk6oP3r4J) */ static int rand_uniform(lua_State *L) { unsigned long long r; randL_checkpid(randL_getstate(L)); if (lua_isnoneornil(L, 1)) { r = rand_llu(L); } else { unsigned long long N, m; N = auxL_checkunsigned(L, 1); luaL_argcheck(L, N > 1, 1, lua_pushfstring(L, "[0, %d): interval is empty", (int)N)); m = -N % N; do { r = rand_llu(L); } while (r < m); r = r % N; } auxL_pushunsigned(L, r); return 1; } /* rand_uniform() */ static const auxL_Reg rand_globals[] = { { "stir", &rand_stir }, { "add", &rand_add }, { "bytes", &rand_bytes }, { "ready", &rand_ready }, { "uniform", &rand_uniform }, { NULL, NULL }, }; EXPORT int luaopen__openssl_rand(lua_State *L) { struct randL_state *st; initall(L); st = lua_newuserdata(L, sizeof *st); memset(st, 0, sizeof *st); auxL_newlib(L, rand_globals, 1); return 1; } /* luaopen__openssl_rand() */ /* * DES - openssl.des * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int de5_string_to_key(lua_State *L) { DES_cblock key; DES_string_to_key(luaL_checkstring(L, 1), &key); lua_pushlstring(L, (char *)key, sizeof key); return 1; } /* de5_string_to_key() */ static int de5_set_odd_parity(lua_State *L) { const char *src; size_t len; DES_cblock key; src = luaL_checklstring(L, 1, &len); memset(&key, 0, sizeof key); memcpy(&key, src, MIN(len, sizeof key)); DES_set_odd_parity(&key); lua_pushlstring(L, (char *)key, sizeof key); return 1; } /* de5_set_odd_parity() */ static const auxL_Reg des_globals[] = { { "string_to_key", &de5_string_to_key }, { "set_odd_parity", &de5_set_odd_parity }, { NULL, NULL }, }; EXPORT int luaopen__openssl_des(lua_State *L) { initall(L); auxL_newlib(L, des_globals, 0); return 1; } /* luaopen__openssl_des() */ #if !OPENSSL_PREREQ(1,1,0) /* * Multithread Reentrancy Protection * * Pre-1.0.2, OpenSSL needs to be given locking primitives * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static struct { #if _WIN32 HANDLE *lock; #else pthread_mutex_t *lock; #endif int nlock; } mt_state; static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUSED) { if (mode & CRYPTO_LOCK) #if _WIN32 WaitForSingleObject(mt_state.lock[type], INFINITE); #else pthread_mutex_lock(&mt_state.lock[type]); #endif else #if _WIN32 ReleaseMutex(mt_state.lock[type]); #else pthread_mutex_unlock(&mt_state.lock[type]); #endif } /* mt_lock() */ /* * Sources include Google and especially the Wine Project. See get_unix_tid * at http://source.winehq.org/git/wine.git/?a=blob;f=dlls/ntdll/server.c. */ #if __FreeBSD__ #include /* thr_self(2) */ #elif __NetBSD__ #include /* _lwp_self(2) */ #endif static unsigned long mt_gettid(void) { #if __APPLE__ return pthread_mach_thread_np(pthread_self()); #elif __DragonFly__ return lwp_gettid(); #elif __FreeBSD__ long id; thr_self(&id); return id; #elif __NetBSD__ return _lwp_self(); #elif _WIN32 return GetCurrentThreadId(); #else /* * pthread_t is an integer on Solaris and Linux, an unsigned integer * on AIX, and a unique pointer on OpenBSD. */ return (unsigned long)pthread_self(); #endif } /* mt_gettid() */ /* mt_init must not be called from multiple threads at once */ static int mt_init(void) { static int done, bound; int error = 0; if (done) goto epilog; if (!CRYPTO_get_locking_callback()) { if (!mt_state.lock) { int i; mt_state.nlock = CRYPTO_num_locks(); if (!(mt_state.lock = malloc(mt_state.nlock * sizeof *mt_state.lock))) { error = errno; goto epilog; } for (i = 0; i < mt_state.nlock; i++) { #if _WIN32 if (!(mt_state.lock[i] = CreateMutex(NULL, FALSE, NULL))) { error = GetLastError(); #else if ((error = pthread_mutex_init(&mt_state.lock[i], NULL))) { #endif while (i > 0) { #if _WIN32 CloseHandle(mt_state.lock[--i]); #else pthread_mutex_destroy(&mt_state.lock[--i]); #endif } free(mt_state.lock); mt_state.lock = NULL; goto epilog; } } } CRYPTO_set_locking_callback(&mt_lock); bound = 1; } if (!CRYPTO_get_id_callback()) { CRYPTO_set_id_callback(&mt_gettid); bound = 1; } if (bound && (error = dl_anchor())) goto epilog; done = 1; epilog: return error; } /* mt_init() */ #endif /* !OPENSSL_PREREQ(1,1,0) */ static void initall(lua_State *L) { static int initssl; int error = 0; #if _WIN32 static volatile HANDLE mutex = NULL; if (mutex == NULL) { HANDLE p; if (!(p = CreateMutex(NULL, FALSE, NULL))) auxL_error(L, GetLastError(), "openssl.init"); if (InterlockedCompareExchangePointer((PVOID*)&mutex, (PVOID)p, NULL) != NULL) CloseHandle(p); } if (WaitForSingleObject(mutex, INFINITE) == WAIT_FAILED) auxL_error(L, GetLastError(), "openssl.init"); #else static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex); #endif #if !OPENSSL_PREREQ(1,1,0) if (!error) error = mt_init(); if (!error && !initssl) { initssl = 1; SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); /* * TODO: Figure out a way to detect whether OpenSSL has * already been configured. */ OPENSSL_config(NULL); } #endif if (!error) error = compat_init(); if (!error) error = ex_init(); #if _WIN32 ReleaseMutex(mutex); #else pthread_mutex_unlock(&mutex); #endif if (error) auxL_error(L, error, "openssl.init"); ex_newstate(L); auxL_addclass(L, BIGNUM_CLASS, bn_methods, bn_metatable, 0); pk_luainit(L, 0); #ifndef OPENSSL_NO_EC auxL_addclass(L, EC_GROUP_CLASS, ecg_methods, ecg_metatable, 0); #endif auxL_addclass(L, X509_NAME_CLASS, xn_methods, xn_metatable, 0); auxL_addclass(L, X509_GENS_CLASS, gn_methods, gn_metatable, 0); auxL_addclass(L, X509_EXT_CLASS, xe_methods, xe_metatable, 0); auxL_addclass(L, X509_CERT_CLASS, xc_methods, xc_metatable, 0); auxL_addclass(L, X509_CSR_CLASS, xr_methods, xr_metatable, 0); auxL_addclass(L, X509_CRL_CLASS, xx_methods, xx_metatable, 0); auxL_addclass(L, X509_CHAIN_CLASS, xl_methods, xl_metatable, 0); auxL_addclass(L, X509_STORE_CLASS, xs_methods, xs_metatable, 0); auxL_addclass(L, X509_VERIFY_PARAM_CLASS, xp_methods, xp_metatable, 0); auxL_addclass(L, PKCS12_CLASS, p12_methods, p12_metatable, 0); auxL_addclass(L, SSL_CTX_CLASS, sx_methods, sx_metatable, 0); auxL_addclass(L, SSL_CLASS, ssl_methods, ssl_metatable, 0); auxL_addclass(L, DIGEST_CLASS, md_methods, md_metatable, 0); auxL_addclass(L, HMAC_CLASS, hmac_methods, hmac_metatable, 0); auxL_addclass(L, CIPHER_CLASS, cipher_methods, cipher_metatable, 0); auxL_addclass(L, OCSP_RESPONSE_CLASS, or_methods, or_metatable, 0); auxL_addclass(L, OCSP_BASICRESP_CLASS, ob_methods, ob_metatable, 0); if (LUA_TNIL == lua_rawgetp(L, LUA_REGISTRYINDEX, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&initall))) { /* Create cache for pointers */ lua_newtable(L); lua_createtable(L, 0, 2); lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); lua_pushliteral(L, "luaossl cache"); lua_setfield(L, -2, "__name"); lua_setmetatable(L, -2); lua_rawsetp(L, LUA_REGISTRYINDEX, LUAOSSL_UNIQUE_LIGHTUSERDATA_MASK(&initall)); } lua_pop(L, 1); } /* initall() */ luaossl-rel-20220711/src/openssl.cipher.lua000066400000000000000000000000611426273367600204570ustar00rootroot00000000000000local ctx = require"_openssl.cipher" return ctx luaossl-rel-20220711/src/openssl.des.lua000066400000000000000000000000561426273367600177640ustar00rootroot00000000000000local ctx = require"_openssl.des" return ctx luaossl-rel-20220711/src/openssl.digest.lua000066400000000000000000000000611426273367600204640ustar00rootroot00000000000000local ctx = require"_openssl.digest" return ctx luaossl-rel-20220711/src/openssl.hmac.lua000066400000000000000000000000571426273367600201220ustar00rootroot00000000000000local ctx = require"_openssl.hmac" return ctx luaossl-rel-20220711/src/openssl.kdf.lua000066400000000000000000000000561426273367600177550ustar00rootroot00000000000000local ctx = require"_openssl.kdf" return ctx luaossl-rel-20220711/src/openssl.lua000066400000000000000000000000311426273367600172030ustar00rootroot00000000000000return require"_openssl" luaossl-rel-20220711/src/openssl.ocsp.basic.lua000066400000000000000000000000641426273367600212340ustar00rootroot00000000000000local ob = require "_openssl.ocsp.basic" return ob luaossl-rel-20220711/src/openssl.ocsp.response.lua000066400000000000000000000001151426273367600220060ustar00rootroot00000000000000local ocsp_response = require "_openssl.ocsp.response" return ocsp_response luaossl-rel-20220711/src/openssl.pkcs12.lua000066400000000000000000000000421426273367600203070ustar00rootroot00000000000000return require('_openssl.pkcs12') luaossl-rel-20220711/src/openssl.pkey.lua000066400000000000000000000000621426273367600201560ustar00rootroot00000000000000local pkey = require"_openssl.pkey" return pkey luaossl-rel-20220711/src/openssl.pubkey.lua000066400000000000000000000000751426273367600205110ustar00rootroot00000000000000-- for backwards compatibility return require "openssl.pkey" luaossl-rel-20220711/src/openssl.rand.lua000066400000000000000000000000571426273367600201360ustar00rootroot00000000000000local ctx = require"_openssl.rand" return ctx luaossl-rel-20220711/src/openssl.ssl.context.lua000066400000000000000000000026661426273367600215060ustar00rootroot00000000000000local ctx = require"_openssl.ssl.context" local pack = table.pack or function(...) return { n = select("#", ...); ... } end -- Allow passing a vararg of ciphers, or an array local setCipherList; setCipherList = ctx.interpose("setCipherList", function (self, ciphers, ...) if (...) then local ciphers_t = pack(ciphers, ...) ciphers = table.concat(ciphers_t, ":", 1, ciphers_t.n) elseif type(ciphers) == "table" then ciphers = table.concat(ciphers, ":") end return setCipherList(self, ciphers) end) -- Allow passing a vararg of ciphersuites, or an array local setCipherSuites = ctx.interpose("setCipherSuites", nil) if setCipherSuites then ctx.interpose("setCipherSuites", function (self, ciphers, ...) if (...) then local ciphers_t = pack(ciphers, ...) ciphers = table.concat(ciphers_t, ":", 1, ciphers_t.n) elseif type(ciphers) == "table" then ciphers = table.concat(ciphers, ":") end return setCipherSuites(self, ciphers) end) end -- Allow passing a vararg of curves, or an array local setGroups = ctx.interpose("setGroups", nil) if setGroups then local function varargSetGroups(self, group, ...) if (...) then local group_t = pack(group, ...) group = table.concat(group_t, ":", 1, group_t.n) elseif type(group) == "table" then group = table.concat(group, ":") end return setGroups(self, group) end ctx.interpose("setGroups", varargSetGroups) ctx.interpose("setCurvesList", varargSetGroups) end return ctx luaossl-rel-20220711/src/openssl.ssl.lua000066400000000000000000000030501426273367600200070ustar00rootroot00000000000000local ssl = require"_openssl.ssl" local pack = table.pack or function(...) return { n = select("#", ...); ... } end ssl.interpose("setStore", function(self, store) self:setChainStore(store) self:setVerifyStore(store) return true end) -- Allow passing a vararg of ciphers, or an array local setCipherList; setCipherList = ssl.interpose("setCipherList", function (self, ciphers, ...) if (...) then local ciphers_t = pack(ciphers, ...) ciphers = table.concat(ciphers_t, ":", 1, ciphers_t.n) elseif type(ciphers) == "table" then ciphers = table.concat(ciphers, ":") end return setCipherList(self, ciphers) end) -- Allow passing a vararg of ciphersuites, or an array local setCipherSuites = ssl.interpose("setCipherSuites", nil) if setCipherSuites then ssl.interpose("setCipherSuites", function (self, ciphers, ...) if (...) then local ciphers_t = pack(ciphers, ...) ciphers = table.concat(ciphers_t, ":", 1, ciphers_t.n) elseif type(ciphers) == "table" then ciphers = table.concat(ciphers, ":") end return setCipherSuites(self, ciphers) end) end -- Allow passing a vararg of curves, or an array local setGroups = ssl.interpose("setGroups", nil) if setGroups then local function varargSetGroups(self, group, ...) if (...) then local group_t = pack(group, ...) group = table.concat(group_t, ":", 1, group_t.n) elseif type(group) == "table" then group = table.concat(group, ":") end return setGroups(self, group) end ssl.interpose("setGroups", varargSetGroups) ssl.interpose("setCurvesList", varargSetGroups) end return ssl luaossl-rel-20220711/src/openssl.x509.altname.lua000066400000000000000000000004171426273367600213370ustar00rootroot00000000000000local altname = require"_openssl.x509.altname" local auxlib = require"openssl.auxlib" altname.interpose("__tostring", function (self) local t = { } for k, v in auxlib.pairs(self) do t[#t + 1] = k .. ":" .. v end return table.concat(t, ", ") end) return altname luaossl-rel-20220711/src/openssl.x509.chain.lua000066400000000000000000000000711426273367600207740ustar00rootroot00000000000000local chain = require"_openssl.x509.chain" return chain luaossl-rel-20220711/src/openssl.x509.crl.lua000066400000000000000000000000441426273367600204720ustar00rootroot00000000000000return require('_openssl.x509.crl') luaossl-rel-20220711/src/openssl.x509.csr.lua000066400000000000000000000000441426273367600205010ustar00rootroot00000000000000return require('_openssl.x509.csr') luaossl-rel-20220711/src/openssl.x509.extension.lua000066400000000000000000000000521426273367600217250ustar00rootroot00000000000000return require('_openssl.x509.extension') luaossl-rel-20220711/src/openssl.x509.lua000066400000000000000000000000661426273367600177170ustar00rootroot00000000000000local x509 = require"_openssl.x509.cert" return x509 luaossl-rel-20220711/src/openssl.x509.name.lua000066400000000000000000000004031426273367600206310ustar00rootroot00000000000000local name = require"_openssl.x509.name" local auxlib = require"openssl.auxlib" name.interpose("__tostring", function (self) local t = { } for k, v in auxlib.pairs(self) do t[#t + 1] = k .. "=" .. v end return table.concat(t, ", ") end) return name luaossl-rel-20220711/src/openssl.x509.store.lua000066400000000000000000000000711426273367600210460ustar00rootroot00000000000000local store = require"_openssl.x509.store" return store luaossl-rel-20220711/src/openssl.x509.verify_param.lua000066400000000000000000000000551426273367600224000ustar00rootroot00000000000000return require('_openssl.x509.verify_param') luaossl-rel-20220711/vendor/000077500000000000000000000000001426273367600155315ustar00rootroot00000000000000luaossl-rel-20220711/vendor/compat53/000077500000000000000000000000001426273367600171645ustar00rootroot00000000000000luaossl-rel-20220711/vendor/compat53/.gitignore000066400000000000000000000001101426273367600211440ustar00rootroot00000000000000# generated files *.so *.dll *.o *.obj HISTO # vim temporaries .*.swp luaossl-rel-20220711/vendor/compat53/.travis.yml000066400000000000000000000025141426273367600212770ustar00rootroot00000000000000language: 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 luaossl-rel-20220711/vendor/compat53/LICENSE000066400000000000000000000020721426273367600201720ustar00rootroot00000000000000The 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. luaossl-rel-20220711/vendor/compat53/README.md000066400000000000000000000230521426273367600204450ustar00rootroot00000000000000[![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_getextraspace` (limited compatibilitiy, see [here][24]) * `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_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 [24]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_getextraspace luaossl-rel-20220711/vendor/compat53/c-api/000077500000000000000000000000001426273367600201555ustar00rootroot00000000000000luaossl-rel-20220711/vendor/compat53/c-api/compat-5.3.c000066400000000000000000000700021426273367600221060ustar00rootroot00000000000000#include #include #include #include #include #include #include "compat-5.3.h" /* don't compile it again if it already is included via compat53.h */ #ifndef COMPAT53_C_ #define COMPAT53_C_ /* 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 #endif /* VC++ _fsopen for share-allowed file read */ #ifndef COMPAT53_HAVE_STRERROR_R # if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || \ defined(__APPLE__) # 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) i += lua_gettop(L) + 1; return i; } static void compat53_call_lua (lua_State *L, char const code[], size_t len, int nargs, int nret) { lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); if (lua_type(L, -1) != LUA_TFUNCTION) { lua_pop(L, 1); if (luaL_loadbuffer(L, code, len, "=none")) lua_error(L); lua_pushvalue(L, -1); lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); } lua_insert(L, -nargs-1); lua_call(L, nargs, nret); } static const char compat53_arith_code[] = "local op,a,b=...\n" "if op==0 then return a+b\n" "elseif op==1 then return a-b\n" "elseif op==2 then return a*b\n" "elseif op==3 then return a/b\n" "elseif op==4 then return a%b\n" "elseif op==5 then return a^b\n" "elseif op==6 then return -a\n" "end\n"; COMPAT53_API void lua_arith (lua_State *L, int op) { if (op < LUA_OPADD || op > LUA_OPUNM) luaL_error(L, "invalid 'op' argument for lua_arith"); luaL_checkstack(L, 5, "not enough stack slots"); if (op == LUA_OPUNM) lua_pushvalue(L, -1); lua_pushnumber(L, op); lua_insert(L, -3); compat53_call_lua(L, compat53_arith_code, sizeof(compat53_arith_code)-1, 3, 1); } static const char compat53_compare_code[] = "local a,b=...\n" "return a<=b\n"; COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op) { int result = 0; switch (op) { case LUA_OPEQ: return lua_equal(L, idx1, idx2); case LUA_OPLT: return lua_lessthan(L, idx1, idx2); case LUA_OPLE: luaL_checkstack(L, 5, "not enough stack slots"); idx1 = lua_absindex(L, idx1); idx2 = lua_absindex(L, idx2); lua_pushvalue(L, idx1); lua_pushvalue(L, idx2); compat53_call_lua(L, compat53_compare_code, sizeof(compat53_compare_code)-1, 2, 1); result = lua_toboolean(L, -1); lua_pop(L, 1); return result; default: luaL_error(L, "invalid 'op' argument for lua_compare"); } return 0; } COMPAT53_API void lua_copy (lua_State *L, int from, int to) { int abs_to = lua_absindex(L, to); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushvalue(L, from); lua_replace(L, abs_to); } COMPAT53_API void lua_len (lua_State *L, int i) { switch (lua_type(L, i)) { 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, (lua_Number)lua_objlen(L, i)); break; case LUA_TUSERDATA: if (luaL_callmeta(L, i, "__len")) break; /* FALLTHROUGH */ default: luaL_error(L, "attempt to get length of a %s value", lua_typename(L, lua_type(L, i))); } } COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p) { int abs_i = lua_absindex(L, i); lua_pushlightuserdata(L, (void*)p); lua_rawget(L, abs_i); return lua_type(L, -1); } COMPAT53_API void lua_rawsetp (lua_State *L, int i, const void *p) { int abs_i = lua_absindex(L, i); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushlightuserdata(L, (void*)p); lua_insert(L, -2); lua_rawset(L, abs_i); } COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) { lua_Number n = lua_tonumber(L, i); if (isnum != NULL) { *isnum = (n != 0 || lua_isnumber(L, i)); } return n; } COMPAT53_API void luaL_checkversion (lua_State *L) { (void)L; } COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg) { if (!lua_checkstack(L, sp+LUA_MINSTACK)) { if (msg != NULL) luaL_error(L, "stack overflow (%s)", msg); else { lua_pushliteral(L, "stack overflow"); lua_error(L); } } } COMPAT53_API int luaL_getsubtable (lua_State *L, int i, const char *name) { int abs_i = lua_absindex(L, i); luaL_checkstack(L, 3, "not enough stack slots"); lua_pushstring(L, name); lua_gettable(L, abs_i); if (lua_istable(L, -1)) return 1; lua_pop(L, 1); lua_newtable(L); lua_pushstring(L, name); lua_pushvalue(L, -2); lua_settable(L, abs_i); return 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 = lua_tointegerx(L, -1, &isnum); lua_pop(L, 1); if (!isnum) luaL_error(L, "object length is not an integer"); return res; } COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup+1, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; lua_pushstring(L, l->name); for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -(nup + 1)); lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ } lua_pop(L, nup); /* remove upvalues */ } COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname) { luaL_checkstack(L, 1, "not enough stack slots"); luaL_getmetatable(L, tname); lua_setmetatable(L, -2); } COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname) { void *p = lua_touserdata(L, i); luaL_checkstack(L, 2, "not enough stack slots"); if (p == NULL || !lua_getmetatable(L, i)) return NULL; else { int res = 0; luaL_getmetatable(L, tname); res = lua_rawequal(L, -1, -2); lua_pop(L, 2); if (!res) p = NULL; } return p; } static int compat53_countlevels (lua_State *L) { lua_Debug ar; int li = 1, le = 1; /* find an upper bound */ while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } /* do a binary search */ while (li < le) { int m = (li + le)/2; if (lua_getstack(L, m, &ar)) li = m + 1; else le = m; } return le - 1; } static int compat53_findfield (lua_State *L, int objidx, int level) { if (level == 0 || !lua_istable(L, -1)) return 0; /* not found */ lua_pushnil(L); /* start 'next' loop */ while (lua_next(L, -2)) { /* for each pair in table */ if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ if (lua_rawequal(L, objidx, -1)) { /* found object? */ lua_pop(L, 1); /* remove value (but keep name) */ return 1; } else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */ lua_remove(L, -2); /* remove table (but keep name) */ lua_pushliteral(L, "."); lua_insert(L, -2); /* place '.' between the two names */ lua_concat(L, 3); return 1; } } lua_pop(L, 1); /* remove value */ } return 0; /* not found */ } static int compat53_pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_pushvalue(L, LUA_GLOBALSINDEX); if (compat53_findfield(L, top + 1, 2)) { lua_copy(L, -1, top + 1); /* move name to proper place */ lua_pop(L, 2); /* remove pushed values */ return 1; } else { lua_settop(L, top); /* remove function and global table */ return 0; } } static void compat53_pushfuncname (lua_State *L, lua_Debug *ar) { if (*ar->namewhat != '\0') /* is there a name? */ lua_pushfstring(L, "function " LUA_QS, ar->name); else if (*ar->what == 'm') /* main? */ lua_pushliteral(L, "main chunk"); else if (*ar->what == 'C') { if (compat53_pushglobalfuncname(L, ar)) { lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); lua_remove(L, -2); /* remove name */ } else lua_pushliteral(L, "?"); } else lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); } #define COMPAT53_LEVELS1 12 /* size of the first part of the stack */ #define COMPAT53_LEVELS2 10 /* size of the second part of the stack */ COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; int top = lua_gettop(L); int numlevels = compat53_countlevels(L1); int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0; if (msg) lua_pushfstring(L, "%s\n", msg); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { if (level == mark) { /* too many levels? */ lua_pushliteral(L, "\n\t..."); /* add a '...' */ level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */ } else { lua_getinfo(L1, "Slnt", &ar); lua_pushfstring(L, "\n\t%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); lua_pushliteral(L, " in "); compat53_pushfuncname(L, &ar); lua_concat(L, lua_gettop(L) - top); } } lua_concat(L, lua_gettop(L) - top); } 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, serr); else 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 = { 0, NULL, 1, 0, 0 }; compat53_data.reader = reader; compat53_data.ud = data; 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(__APPLE__) && defined(__MACH__))) /* some form of unix; check feature macros in unistd.h for details */ # include /* check posix version; the relevant include files and macros probably * were available before 2001, but I'm not sure */ # if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L # include # define l_inspectstat(stat,what) \ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } # endif #endif /* provide default (no-op) version */ #if !defined(l_inspectstat) # define l_inspectstat(stat,what) ((void)0) #endif COMPAT53_API int luaL_execresult (lua_State *L, int stat) { const char *what = "exit"; if (stat == -1) return luaL_fileresult(L, 0, NULL); else { l_inspectstat(stat, what); if (*what == 'e' && stat == 0) lua_pushboolean(L, 1); else lua_pushnil(L); lua_pushstring(L, what); lua_pushinteger(L, stat); return 3; } } COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) { /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ B->b.p = NULL; B->b.L = NULL; B->b.lvl = 0; /* reuse the buffer from the 5.1-style luaL_Buffer though! */ B->ptr = B->b.buffer; B->capacity = LUAL_BUFFERSIZE; B->nelems = 0; B->L2 = L; } COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s) { if (B->capacity - B->nelems < s) { /* needs to grow */ char* newptr = NULL; size_t newcap = B->capacity * 2; if (newcap - B->nelems < s) newcap = B->nelems + s; if (newcap < B->capacity) /* overflow */ luaL_error(B->L2, "buffer too large"); newptr = (char*)lua_newuserdata(B->L2, newcap); memcpy(newptr, B->ptr, B->nelems); if (B->ptr != B->b.buffer) lua_replace(B->L2, -2); /* remove old buffer */ B->ptr = newptr; B->capacity = newcap; } return B->ptr+B->nelems; } COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l) { memcpy(luaL_prepbuffsize(B, l), s, l); luaL_addsize(B, l); } COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B) { size_t len = 0; const char *s = lua_tolstring(B->L2, -1, &len); if (!s) luaL_error(B->L2, "cannot convert value to string"); if (B->ptr != B->b.buffer) lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ luaL_addlstring(B, s, len); lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); } void luaL_pushresult (luaL_Buffer_53 *B) { lua_pushlstring(B->L2, B->ptr, B->nelems); if (B->ptr != B->b.buffer) lua_replace(B->L2, -2); /* remove userdata buffer */ } #endif /* Lua 5.1 */ /* definitions for Lua 5.1 and Lua 5.2 */ #if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM <= 502 COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i) { index = lua_absindex(L, index); lua_pushinteger(L, i); lua_gettable(L, index); return lua_type(L, -1); } #ifndef LUA_EXTRASPACE #define LUA_EXTRASPACE (sizeof(void*)) #endif COMPAT53_API void *lua_getextraspace (lua_State *L) { int is_main = 0; void *ptr = NULL; luaL_checkstack(L, 4, "not enough stack slots available"); lua_pushliteral(L, "__compat53_extraspace"); lua_pushvalue(L, -1); lua_rawget(L, LUA_REGISTRYINDEX); if (!lua_istable(L, -1)) { lua_pop(L, 1); lua_createtable(L, 0, 2); lua_createtable(L, 0, 1); lua_pushliteral(L, "k"); lua_setfield(L, -2, "__mode"); lua_setmetatable(L, -2); lua_pushvalue(L, -2); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); } lua_replace(L, -2); is_main = lua_pushthread(L); lua_rawget(L, -2); ptr = lua_touserdata(L, -1); if (!ptr) { lua_pop(L, 1); ptr = lua_newuserdata(L, LUA_EXTRASPACE); if (is_main) { memset(ptr, '\0', LUA_EXTRASPACE); lua_pushthread(L); lua_pushvalue(L, -2); lua_rawset(L, -4); lua_pushboolean(L, 1); lua_pushvalue(L, -2); lua_rawset(L, -4); } else { void* mptr = NULL; lua_pushboolean(L, 1); lua_rawget(L, -3); mptr = lua_touserdata(L, -1); if (mptr) memcpy(ptr, mptr, LUA_EXTRASPACE); else memset(ptr, '\0', LUA_EXTRASPACE); lua_pop(L, 1); lua_pushthread(L); lua_pushvalue(L, -2); lua_rawset(L, -4); } } lua_pop(L, 2); return ptr; } COMPAT53_API int lua_isinteger (lua_State *L, int index) { if (lua_type(L, index) == LUA_TNUMBER) { lua_Number n = lua_tonumber(L, index); lua_Integer i = lua_tointeger(L, index); if (i == n) return 1; } return 0; } 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); lua_pushvalue(L, b); lua_replace(L, a); lua_replace(L, b); } } COMPAT53_API void lua_rotate (lua_State *L, int idx, int n) { int n_elems = 0; idx = lua_absindex(L, idx); n_elems = lua_gettop(L)-idx+1; if (n < 0) n += n_elems; if ( n > 0 && n < n_elems) { luaL_checkstack(L, 2, "not enough stack slots available"); n = n_elems - n; compat53_reverse(L, idx, idx+n-1); compat53_reverse(L, idx+n, idx+n_elems-1); compat53_reverse(L, idx, idx+n_elems-1); } } COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i) { luaL_checkstack(L, 1, "not enough stack slots available"); index = lua_absindex(L, index); lua_pushinteger(L, i); lua_insert(L, -2); lua_settable(L, index); } #if !defined(lua_str2number) # define lua_str2number(s, p) strtod((s), (p)) #endif COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) { char* endptr; lua_Number n = lua_str2number(s, &endptr); if (endptr != s) { while (*endptr != '\0' && isspace((unsigned char)*endptr)) ++endptr; if (*endptr == '\0') { lua_pushnumber(L, n); return endptr - s + 1; } } return 0; } 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"); luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); if (lua_getfield(L, -1, modname) == LUA_TNIL) { lua_pop(L, 1); lua_pushcfunction(L, openf); lua_pushstring(L, modname); lua_call(L, 1, 1); lua_pushvalue(L, -1); lua_setfield(L, -3, modname); } if (glb) { lua_pushvalue(L, -1); lua_setglobal(L, modname); } lua_replace(L, -2); } #endif /* Lua 5.1 and 5.2 */ #endif /* COMPAT53_C_ */ /********************************************************************* * This file contains parts of Lua 5.2's and Lua 5.3's source code: * * Copyright (C) 1994-2014 Lua.org, PUC-Rio. * * 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. *********************************************************************/ luaossl-rel-20220711/vendor/compat53/c-api/compat-5.3.h000066400000000000000000000311441426273367600221170ustar00rootroot00000000000000#ifndef COMPAT53_H_ #define COMPAT53_H_ #include #include #include #if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) extern "C" { #endif #include #include #include #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 */ # if !defined(COMPAT53_API) # define COMPAT53_API extern # endif #else /* COMPAT53_PREFIX */ /* - make all functions static and include the source. * - compat-5.3.c doesn't need to be compiled (and linked) separately */ # define COMPAT53_PREFIX compat53 # undef COMPAT53_API # if defined(__GNUC__) || defined(__clang__) # define COMPAT53_API __attribute__((__unused__)) static # else # define COMPAT53_API static # endif # define COMPAT53_INCLUDE_SOURCE #endif /* COMPAT53_PREFIX */ #define COMPAT53_CONCAT_HELPER(a, b) a##b #define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b) /* declarations for Lua 5.1 */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 /* XXX not implemented: * lua_arith (new operators) * lua_upvalueid * lua_upvaluejoin * lua_version * lua_yieldk */ #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; typedef struct luaL_Buffer_53 { luaL_Buffer b; /* make incorrect code crash! */ char *ptr; size_t nelems; size_t capacity; lua_State *L2; } 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); #define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith) COMPAT53_API void lua_arith (lua_State *L, int op); #define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare) COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op); #define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy) 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)) #define lua_setuservalue(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 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) #define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p); #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_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); #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); #define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable) COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name); #define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) 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); #define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable) COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname); #define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname); #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); #define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult) COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname); #define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) COMPAT53_API int luaL_execresult (lua_State *L, int stat); #define lua_callk(L, na, nr, ctx, cont) \ ((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))) #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); #define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53) COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s); #define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53) COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l); #define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53) COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B); #define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53) COMPAT53_API void luaL_pushresult (luaL_Buffer_53 *B); #undef luaL_buffinitsize #define luaL_buffinitsize(L, B, s) \ (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) #undef luaL_prepbuffer #define luaL_prepbuffer(B) \ luaL_prepbuffsize((B), LUAL_BUFFERSIZE) #undef luaL_addchar #define luaL_addchar(B, c) \ ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ ((B)->ptr[(B)->nelems++] = (c))) #undef luaL_addsize #define luaL_addsize(B, s) \ ((B)->nelems += (s)) #undef luaL_addstring #define luaL_addstring(B, s) \ luaL_addlstring((B), (s), strlen((s))) #undef luaL_pushresultsize #define luaL_pushresultsize(B, s) \ (luaL_addsize((B), (s)), luaL_pushresult((B))) #if defined(LUA_COMPAT_APIINTCASTS) #define lua_pushunsigned(L, n) \ lua_pushinteger((L), (lua_Integer)(n)) #define lua_tounsignedx(L, i, is) \ ((lua_Unsigned)lua_tointegerx((L), (i), (is))) #define lua_tounsigned(L, i) \ lua_tounsignedx((L), (i), NULL) #define luaL_checkunsigned(L, a) \ ((lua_Unsigned)luaL_checkinteger((L), (a))) #define luaL_optunsigned(L, a, d) \ ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) #endif #endif /* Lua 5.1 only */ /* declarations for Lua 5.1 and 5.2 */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 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))) #define lua_getfield(L, i, k) \ (lua_getfield((L), (i), (k)), lua_type((L), -1)) #define lua_gettable(L, i) \ (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); #define lua_getextraspace COMPAT53_CONCAT(COMPAT53_PREFIX, _getextraspace) COMPAT53_API void *lua_getextraspace (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)) #define lua_rawgeti(L, i, n) \ (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); #define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti) COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i); #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) #define luaL_newmetatable(L, tn) \ (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, lua_CFunction openf, int glb ); #endif /* Lua 5.1 and Lua 5.2 */ /* declarations for Lua 5.2 */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502 /* XXX not implemented: * lua_isyieldable * lua_arith (new operators) * lua_pushfstring (new formats) */ #define lua_getglobal(L, n) \ (lua_getglobal((L), (n)), lua_type((L), -1)) #define lua_getuservalue(L, i) \ (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)) #define LUA_KFUNCTION(_name) \ static int (_name)(lua_State *L, int status, lua_KContext ctx); \ static int (_name ## _52)(lua_State *L) { \ lua_KContext ctx; \ int status = lua_getctx(L, &ctx); \ return (_name)(L, status, ctx); \ } \ 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) #define lua_callk(L, na, nr, ctx, cont) \ lua_callk((L), (na), (nr), (ctx), cont ## _52) #define lua_yieldk(L, nr, ctx, cont) \ 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) #endif #ifdef lua_pcall # undef lua_pcall # define lua_pcall(L, na, nr, err) \ (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) #endif #endif /* Lua 5.2 only */ /* other Lua versions */ #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 504 # error "unsupported Lua version (i.e. not Lua 5.1, 5.2, 5.3, or 5.4)" #endif /* other Lua versions except 5.1, 5.2, 5.3, and 5.4 */ /* helper macro for defining continuation functions (for every version * *except* Lua 5.2) */ #ifndef LUA_KFUNCTION #define LUA_KFUNCTION(_name) \ static int (_name)(lua_State *L, int status, lua_KContext ctx) #endif #if defined(COMPAT53_INCLUDE_SOURCE) # include "compat-5.3.c" #endif #endif /* COMPAT53_H_ */ luaossl-rel-20220711/vendor/compat53/compat53/000077500000000000000000000000001426273367600206175ustar00rootroot00000000000000luaossl-rel-20220711/vendor/compat53/compat53/init.lua000066400000000000000000000323061426273367600222710ustar00rootroot00000000000000local 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 : luaossl-rel-20220711/vendor/compat53/compat53/module.lua000066400000000000000000000612641426273367600226200ustar00rootroot00000000000000local _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 : luaossl-rel-20220711/vendor/compat53/lbitlib.c000066400000000000000000000115431426273367600207550ustar00rootroot00000000000000/* ** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ #define lbitlib_c #define LUA_LIB #include "lprefix.h" #include "lua.h" #include "lauxlib.h" #include "lualib.h" #if defined(LUA_COMPAT_BITLIB) /* { */ #define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) #define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) /* number of bits to consider in a number */ #if !defined(LUA_NBITS) #define LUA_NBITS 32 #endif /* ** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must ** be made in two parts to avoid problems when LUA_NBITS is equal to the ** number of bits in a lua_Unsigned.) */ #define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) /* macro to trim extra bits */ #define trim(x) ((x) & ALLONES) /* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ #define mask(n) (~((ALLONES << 1) << ((n) - 1))) static lua_Unsigned andaux (lua_State *L) { int i, n = lua_gettop(L); lua_Unsigned r = ~(lua_Unsigned)0; for (i = 1; i <= n; i++) r &= checkunsigned(L, i); return trim(r); } static int b_and (lua_State *L) { lua_Unsigned r = andaux(L); pushunsigned(L, r); return 1; } static int b_test (lua_State *L) { lua_Unsigned r = andaux(L); lua_pushboolean(L, r != 0); return 1; } static int b_or (lua_State *L) { int i, n = lua_gettop(L); lua_Unsigned r = 0; for (i = 1; i <= n; i++) r |= checkunsigned(L, i); pushunsigned(L, trim(r)); return 1; } static int b_xor (lua_State *L) { int i, n = lua_gettop(L); lua_Unsigned r = 0; for (i = 1; i <= n; i++) r ^= checkunsigned(L, i); pushunsigned(L, trim(r)); return 1; } static int b_not (lua_State *L) { lua_Unsigned r = ~checkunsigned(L, 1); pushunsigned(L, trim(r)); return 1; } static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { if (i < 0) { /* shift right? */ i = -i; r = trim(r); if (i >= LUA_NBITS) r = 0; else r >>= i; } else { /* shift left */ if (i >= LUA_NBITS) r = 0; else r <<= i; r = trim(r); } pushunsigned(L, r); return 1; } static int b_lshift (lua_State *L) { return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); } static int b_rshift (lua_State *L) { return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); } static int b_arshift (lua_State *L) { lua_Unsigned r = checkunsigned(L, 1); lua_Integer i = luaL_checkinteger(L, 2); if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ if (i >= LUA_NBITS) r = ALLONES; else r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ pushunsigned(L, r); return 1; } } static int b_rot (lua_State *L, lua_Integer d) { lua_Unsigned r = checkunsigned(L, 1); int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ r = trim(r); if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ r = (r << i) | (r >> (LUA_NBITS - i)); pushunsigned(L, trim(r)); return 1; } static int b_lrot (lua_State *L) { return b_rot(L, luaL_checkinteger(L, 2)); } static int b_rrot (lua_State *L) { return b_rot(L, -luaL_checkinteger(L, 2)); } /* ** get field and width arguments for field-manipulation functions, ** checking whether they are valid. ** ('luaL_error' called without 'return' to avoid later warnings about ** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { lua_Integer f = luaL_checkinteger(L, farg); lua_Integer w = luaL_optinteger(L, farg + 1, 1); luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); if (f + w > LUA_NBITS) luaL_error(L, "trying to access non-existent bits"); *width = (int)w; return (int)f; } static int b_extract (lua_State *L) { int w; lua_Unsigned r = trim(checkunsigned(L, 1)); int f = fieldargs(L, 2, &w); r = (r >> f) & mask(w); pushunsigned(L, r); return 1; } static int b_replace (lua_State *L) { int w; lua_Unsigned r = trim(checkunsigned(L, 1)); lua_Unsigned v = trim(checkunsigned(L, 2)); int f = fieldargs(L, 3, &w); lua_Unsigned m = mask(w); r = (r & ~(m << f)) | ((v & m) << f); pushunsigned(L, r); return 1; } static const luaL_Reg bitlib[] = { {"arshift", b_arshift}, {"band", b_and}, {"bnot", b_not}, {"bor", b_or}, {"bxor", b_xor}, {"btest", b_test}, {"extract", b_extract}, {"lrotate", b_lrot}, {"lshift", b_lshift}, {"replace", b_replace}, {"rrotate", b_rrot}, {"rshift", b_rshift}, {NULL, NULL} }; LUAMOD_API int luaopen_bit32 (lua_State *L) { luaL_newlib(L, bitlib); return 1; } #else /* }{ */ LUAMOD_API int luaopen_bit32 (lua_State *L) { return luaL_error(L, "library 'bit32' has been deprecated"); } #endif /* } */ luaossl-rel-20220711/vendor/compat53/lprefix.h000066400000000000000000000103561426273367600210130ustar00rootroot00000000000000/* ** $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 #include /* 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 luaossl-rel-20220711/vendor/compat53/lstrlib.c000066400000000000000000001341071426273367600210110ustar00rootroot00000000000000/* ** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 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 #include #include #include #include #include #include #include #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 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= 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 #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') return 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) return 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; } luaossl-rel-20220711/vendor/compat53/ltablib.c000066400000000000000000000323561426273367600207520ustar00rootroot00000000000000/* ** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ #define ltablib_c #define LUA_LIB #include "lprefix.h" #include #include #include #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 /* 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; } luaossl-rel-20220711/vendor/compat53/lutf8lib.c000066400000000000000000000156431426273367600210720ustar00rootroot00000000000000/* ** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ ** Standard library for UTF-8 manipulation ** See Copyright Notice in lua.h */ #define lutf8lib_c #define LUA_LIB #include "lprefix.h" #include #include #include #include #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)) return 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; } luaossl-rel-20220711/vendor/compat53/rockspecs/000077500000000000000000000000001426273367600211605ustar00rootroot00000000000000luaossl-rel-20220711/vendor/compat53/rockspecs/bit32-5.3.5-1.rockspec000066400000000000000000000012761426273367600244500ustar00rootroot00000000000000package = "bit32" version = "5.3.5-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.9.zip", dir = "lua-compat-5.3-0.9", } description = { summary = "Lua 5.2 bit manipulation library", detailed = [[ bit32 is the native Lua 5.2 bit manipulation library, in the version from Lua 5.3; it is compatible with Lua 5.1, 5.2 and 5.3. ]], homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", license = "MIT" } dependencies = { "lua >= 5.1, < 5.5" } build = { type = "builtin", modules = { bit32 = { sources = { "lbitlib.c" }, defines = { "LUA_COMPAT_BITLIB" }, incdirs = { "c-api" }, } } } luaossl-rel-20220711/vendor/compat53/rockspecs/bit32-scm-1.rockspec000066400000000000000000000013041426273367600245520ustar00rootroot00000000000000package = "bit32" version = "scm-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/master.zip", branch = "lua-compat-5.3-master", } description = { summary = "Lua 5.2 bit manipulation library", detailed = [[ bit32 is the native Lua 5.2 bit manipulation library, in the version from Lua 5.3; it is compatible with Lua 5.1, 5.2 and 5.3. ]], homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", license = "MIT" } dependencies = { "lua >= 5.1, < 5.5" } build = { type = "builtin", modules = { bit32 = { sources = { "lbitlib.c" }, defines = { "LUA_COMPAT_BITLIB" }, incdirs = { "c-api" }, } } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-0.1-1.rockspec000066400000000000000000000016721426273367600250060ustar00rootroot00000000000000package = "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", } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-0.2-1.rockspec000066400000000000000000000017671426273367600250140ustar00rootroot00000000000000package = "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", } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-0.3-1.rockspec000066400000000000000000000017671426273367600250150ustar00rootroot00000000000000package = "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", } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-0.4-1.rockspec000066400000000000000000000017671426273367600250160ustar00rootroot00000000000000package = "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", } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-0.5-1.rockspec000066400000000000000000000017671426273367600250170ustar00rootroot00000000000000package = "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", } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-0.7-1.rockspec000066400000000000000000000017671426273367600250210ustar00rootroot00000000000000package = "compat53" version = "0.7-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.7.zip", dir = "lua-compat-5.3-0.7", } 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", } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-0.8-1.rockspec000066400000000000000000000017521426273367600250140ustar00rootroot00000000000000package = "compat53" version = "0.8-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.8.zip", dir = "lua-compat-5.3-0.8", } 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.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.5", --"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", } } luaossl-rel-20220711/vendor/compat53/rockspecs/compat53-scm-0.rockspec000066400000000000000000000017571426273367600252750ustar00rootroot00000000000000package = "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.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.5", --"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", } } luaossl-rel-20220711/vendor/compat53/tests/000077500000000000000000000000001426273367600203265ustar00rootroot00000000000000luaossl-rel-20220711/vendor/compat53/tests/test-bit32.lua000077500000000000000000000002271426273367600227350ustar00rootroot00000000000000#!/usr/bin/env lua local bit32 = require("bit32") assert(bit32.bnot(0) == 2^32-1) assert(bit32.band(1, 3, 5) == 1) assert(bit32.bor(1, 3, 5) == 7) luaossl-rel-20220711/vendor/compat53/tests/test.lua000077500000000000000000000573231426273367600220250ustar00rootroot00000000000000#!/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 c = coroutine.wrap(function() mod.extraspace("uvw") print("getextraspace", mod.extraspace()) coroutine.yield() print("getextraspace", mod.extraspace()) coroutine.yield() print("getextraspace", mod.extraspace()) end) c() mod.extraspace("abc") print("getextraspace", mod.extraspace()) c() local d = coroutine.wrap(function() print("getextraspace", mod.extraspace()) mod.extraspace("xyz") print("getextraspace", mod.extraspace()) coroutine.yield() print("getextraspace", mod.extraspace()) coroutine.yield() print("getextraspace", mod.extraspace()) end) d() print("getextraspace", mod.extraspace()) mod.extraspace("123") c() d() ___'' 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 ___'' luaossl-rel-20220711/vendor/compat53/tests/testmod.c000066400000000000000000000210061426273367600221500ustar00rootroot00000000000000#include #include #include #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; } #ifndef LUA_EXTRASPACE #define LUA_EXTRASPACE (sizeof(void*)) #endif static int test_getextraspace (lua_State *L) { size_t len = 0; char const* s = luaL_optlstring(L, 1, NULL, &len); char* p = (char*)lua_getextraspace(L); lua_pushstring(L, p); if (s) memcpy(p, s, len > LUA_EXTRASPACE-1 ? LUA_EXTRASPACE-1 : len+1); 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); errno = 0; 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 }, { "extraspace", test_getextraspace }, { "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