pax_global_header00006660000000000000000000000064130243433530014512gustar00rootroot0000000000000052 comment=b4bf06dcb61dbd735b328f47d8a36afb856d5d16 luaossl-rel-20161214/000077500000000000000000000000001302434335300142165ustar00rootroot00000000000000luaossl-rel-20161214/GNUmakefile000066400000000000000000000125601302434335300162740ustar00rootroot00000000000000# 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 # # 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 AR ?= ar RANLIB ?= ranlib M4 ?= m4 RM ?= rm CP ?= cp LN ?= ln LN_S ?= $(LN) -s RMDIR ?= rmdir MKDIR ?= mkdir CHMOD ?= chmod INSTALL ?= install INSTALL_DATA ?= $(INSTALL) -m 644 .PHONY: $(d)/config $(d)/config: printf 'prefix ?= $(value prefix)'"\n" >| $(@D)/.config printf 'includedir ?= $(value includedir)'"\n" >> $(@D)/.config printf 'libdir ?= $(value libdir)'"\n" >> $(@D)/.config printf 'datadir ?= $(value datadir)'"\n" >> $(@D)/.config printf 'bindir ?= $(value bindir)'"\n" >> $(@D)/.config printf 'lua51cpath ?= $(value lua51cpath)'"\n" >> $(@D)/.config printf 'lua51path ?= $(value lua51path)'"\n" >> $(@D)/.config printf 'lua52cpath ?= $(value lua52cpath)'"\n" >> $(@D)/.config printf 'lua52path ?= $(value lua52path)'"\n" >> $(@D)/.config printf 'lua53cpath ?= $(value lua53cpath)'"\n" >> $(@D)/.config printf 'lua53path ?= $(value lua53path)'"\n" >> $(@D)/.config printf 'CC ?= $(CC)'"\n" >> $(@D)/.config printf 'CPPFLAGS ?= $(value CPPFLAGS)'"\n" >> $(@D)/.config printf 'CFLAGS ?= $(value CFLAGS)'"\n" >> $(@D)/.config printf 'LDFLAGS ?= $(value LDFLAGS)'"\n" >> $(@D)/.config printf 'SOFLAGS ?= $(value SOFLAGS)'"\n" >> $(@D)/.config printf 'AR ?= $(value AR)'"\n" >> $(@D)/.config printf 'RANLIB ?= $(value RANLIB)'"\n" >> $(@D)/.config printf 'M4 ?= $(value M4)'"\n" >> $(@D)/.config printf 'RM ?= $(value RM)'"\n" >> $(@D)/.config printf 'CP ?= $(value CP)'"\n" >> $(@D)/.config printf 'LN ?= $(value LN)'"\n" >> $(@D)/.config printf 'LN_S ?= $(value LN_S)'"\n" >> $(@D)/.config printf 'RMDIR ?= $(value RMDIR)'"\n" >> $(@D)/.config printf 'MKDIR ?= $(value MKDIR)'"\n" >> $(@D)/.config printf 'CHMOD ?= $(value CHMOD)'"\n" >> $(@D)/.config printf 'INSTALL ?= $(value INSTALL)'"\n" >> $(@D)/.config printf 'INSTALL_DATA ?= $(value INSTALL_DATA)'"\n" >> $(@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 # # S H A R E D 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) ifneq ($(VENDOR_OS_$(d)), OpenBSD) CPPFLAGS_$(d) += -D_REENTRANT -D_THREAD_SAFE -D_GNU_SOURCE endif ifeq ($(VENDOR_OS_$(d)), SunOS) CPPFLAGS_$(d) += -Usun -D_XPG4_2 -D__EXTENSIONS__ endif ifeq ($(VENDOR_CC_$(d)), gcc) CFLAGS_$(d) += -O2 -std=gnu99 -fPIC CFLAGS_$(d) += -g -Wall -Wextra $(call cc-option, -Wno-missing-field-initializers) $(call cc-option, -Wno-override-init) -Wno-unused endif ifeq ($(VENDOR_CC_$(d)), clang) CFLAGS_$(d) += -O2 -std=gnu99 -fPIC CFLAGS_$(d) += -g -Wall -Wextra -Wno-missing-field-initializers -Wno-initializer-overrides -Wno-unused endif ifeq ($(VENDOR_CC_$(d)), sunpro) CFLAGS_$(d) += -xcode=pic13 CFLAGS_$(d) += -g # # Solaris Studio has a brain-dead function call analyzer which counts # arguments before preprocessor expansion. # CFLAGS_$(d) += -erroff=E_ARGUEMENT_MISMATCH endif ifeq ($(VENDOR_OS_$(d)), Darwin) CFLAGS_$(d) += -Wno-deprecated-declarations endif ifeq ($(VENDOR_OS_$(d)), Darwin) SOFLAGS_$(d) += -bundle -undefined dynamic_lookup else SOFLAGS_$(d) += -shared endif # # 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-20161214/LICENSE000066400000000000000000000021041302434335300152200ustar00rootroot00000000000000Copyright (c) 2012-2015 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. luaossl-rel-20161214/Makefile000066400000000000000000000001161302434335300156540ustar00rootroot00000000000000.POSIX: all: +gmake -f GNUmakefile all .DEFAULT: +gmake -f GNUmakefile $< luaossl-rel-20161214/config.h.guess000066400000000000000000000571151302434335300167720ustar00rootroot00000000000000/* ========================================================================== * 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 20161019L /* * 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_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_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 #define HAVE_DECL_RANDOM_UUID (HAVE_SYS_SYSCTL_H && defined __linux__) /* RANDOM_UUID is an enum, not macro */ #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 #define HAVE_DECL_SYS_GETRANDOM (defined SYS_getrandom) #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_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_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_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_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 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-20161214/debian/000077500000000000000000000000001302434335300154405ustar00rootroot00000000000000luaossl-rel-20161214/debian/changelog000066400000000000000000000106071302434335300173160ustar00rootroot00000000000000liblua-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-20161214/debian/compat000066400000000000000000000000021302434335300166360ustar00rootroot000000000000009 luaossl-rel-20161214/debian/control000066400000000000000000000006621302434335300170470ustar00rootroot00000000000000Source: 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-20161214/debian/copyright000066400000000000000000000022631302434335300173760ustar00rootroot00000000000000Author: 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-20161214/debian/liblua5.1-openssl.files000066400000000000000000000000671302434335300216440ustar00rootroot00000000000000usr/lib/lua/5.1/_openssl.so usr/share/lua/5.1/openssl* luaossl-rel-20161214/debian/liblua5.1-openssl.install000066400000000000000000000001571302434335300222100ustar00rootroot00000000000000debian/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-20161214/debian/liblua5.2-openssl.files000066400000000000000000000000671302434335300216450ustar00rootroot00000000000000usr/lib/lua/5.2/_openssl.so usr/share/lua/5.2/openssl* luaossl-rel-20161214/debian/liblua5.2-openssl.install000066400000000000000000000001571302434335300222110ustar00rootroot00000000000000debian/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-20161214/debian/rules000077500000000000000000000007171302434335300165250ustar00rootroot00000000000000#!/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-20161214/doc/000077500000000000000000000000001302434335300147635ustar00rootroot00000000000000luaossl-rel-20161214/doc/luaossl.pdf000066400000000000000000010646111302434335300171510ustar00rootroot00000000000000%PDF-1.5 % 2 0 obj << /Type /ObjStm /N 100 /First 797 /Length 947 /Filter /FlateDecode >> stream xڝVMoFW1 ywrH]A4Seml"2)T([reҨa̼YҤȑ2% LZQ iH[D`!hX*"v!{b8aKF16d ij|eu@Z)F"g#V9\ ВWyźǾGQqtEOxECQE " E)DEMI"T%$1QJp>$5˅VR-AI+XF,*[Q!N-'@0M2TeQZd_[t%2@pV(  fm/@{QKaV.ނcQE$pQzrۓbDwƄt cF:QXM^L Z$d% S^"$b8Иk19f,`zJBAVI(F 'l+޾9}h4tvA|WMf_ӻwū_u߽\/:\_Wx=un˾oh~n;ehfq'ܔfI"?TW痓p6XÃO_7cjU y_oޏˏR7Ɣ I}_&?_]5j∘Lƛ}#P{mwz ǥ1mQԛ4nfug돰nvtyg~$K&/FX_Xp߯GfQN[(9?J5j8? ,>r ە/׺wŸrOXY.1_b#΄Wl's)S&x1ƈ'&ƙNpM;E4ovZ> endstream endobj 203 0 obj << /Type /ObjStm /N 100 /First 855 /Length 915 /Filter /FlateDecode >> stream xڕUMHWO`fV$V{ɘlbG ~_C6z^ 9IKe]}#9 +@(`I /ٙ#U<+9j;ƚ+ZB>K#^UĄ Oq*ܱM\c?|`MvCtϗj>;Q3n,OKݺ.$/} 0,T Ex[)_vG9=>-v endstream endobj 404 0 obj << /Type /ObjStm /N 100 /First 853 /Length 954 /Filter /FlateDecode >> stream xڝVMF Wr4(m4=^e#Ե In}{-IAٙH>>J<9 .,fJP+i$k!N #F$VAI^I^2I |Uɧ5/#67~HcU&੐fŪ9ah)IX(!wLJAKfF[nlPc6~*T,vT,~Tb^d;;F 4GD9j,!QEF uhQ+utE [+ =:O'"9j(R$(-AE [DQp'$8aaGGyq(]w_S41xbs{;,#䛇ϘQv/Ӕ |{x00{zs׼ n6dq1W+i!>l궛Oh4aG܌vvn^"?ʌzv2e,׶T0~AΊ#2:1cMl̛,N4϶!PF$:|nu~Ϭe,j.U6y*q)\ez]}N 1][j:eNY>Uۺ%NW7]\|Evwؿk臫џLv~uq\6s+ra g?Y= endstream endobj 756 0 obj << /Length 314 /Filter /FlateDecode >> stream xuQn0+Hx˱HH@)Br'gLsl:C*|h!ӄI yk6L<2><6b:S-E%MUc祮uB8 -@J宩OҼ/?z:E1Zc}l_&Reo {C`dR M^v5[o$/@YjHuT=_T=TNT*sUUnkrBo=^AE8|wI(r$+ڋ*#y endstream endobj 798 0 obj << /Length 944 /Filter /FlateDecode >> stream xZ]s@}ϯG)6iLۤ4ƍebLߋњ}ݻ=!"숤ד/ &u͐ug|NH's?' :PD VDͪdZsrUXR-$M J*ފ5=hBB:c*&z1ڿte mfgkЕ}BH-Lʱv(E)a 2Ёyܸz #PZgZcJBwJmPX>L 0f)^?pD{&_v3cƗXf7E-bz]Q{o_b0,,orN)}\PGG.IjoRʃKK m6DaXL)Ì_!X I" nj``Ryo(uisea곦BwUJ8)rbo֘߸ CmwWv$NQ*"qڴG:C-ˆ< > stream xڵXn7}߯cRCFĩqPuH-DVk4Yѱ6qV* ^q̙!wA9DPQX! oDFD 16Jy<:a\„(LJk 6sN3 gp8 uj- ?sªa0ErU%|f20]tCTpJ-uT5rntRIKܮ 0uwo[?Yw Ţ.wG_]OgRc=[]1{="vj|xi`bX3̎ݶ~Y{>yލچ`OuPvZXWvmGOb<ߎZ-zqѴ׻HR0]ԗC~Σy#մ]t`gWjOezZ',ktqYd)`M6׹gG1y,?CbrΙ訚|]e1y7>5Z}^77,.<_L_6_ęF%s^] =X}\  *bQwF?@M𚙝N!W'b!W‡NS_qO^u3]Mfe e22nl322>*|TQG/Xbዅ/Xbዅ/XRK/TRKo$&7Elyn{iLHZ*\ИKnq? '+0{!~sP7,I-ۀ4fnܝ"䛣7V&_~KGnL >O6o6I丰s8?4; KAM˘ ]C՛hYT9><6!֜ 8)}o|&Yw@2}q/_\Sy'?RQ?q !$3G98JpHq:Hxcd"8 (%Adq'CG6Gwv%/qU16Ic/[TJabscT,Cpdq45Q ⏚ ^]-X\ߠ ހbtfF)&EkhKٸlw>9&4qiaHo>P endstream endobj 874 0 obj << /Length 1223 /Filter /FlateDecode >> stream xr6z ,/vi鴍LĨȒK{x DD?E vD֯QWo?ގFp(X * J M,&4E_,/ү/?ݽ[{͑cH3KBz0 kywvL9nf2EIm4RǑȮJa/\h4&l~|y*|!wm R)+OMc\ч!ڲ5'58bI:s5tT H܀ce5drű|HE1O$t~ .e'ȗ/s^I1fKj_M"Ghk LCOoA> ngV#2]f2zgRf>.[.J7'.o?y0}ZAl}`SbLy 4tVj lҢ<9KZf {/AUbQ<W@*xw:)/:r.NQ%CIҝR!zN%/R}s],Kǽ\EHt &=& 's} s"QY[u(W du1= ځ @&7EQ g28fSK#8Trf;0HK$밮kxwӀn PI hdEo'(W"eY+U~{<&߆1O65ϐ:E6^EaJjEpLgL@.~3Xbvl1na"w\Q,o&'"?@eLߜASy:Uta7O;sXH<#N &Gb"\ .Z`臠 TpVoL*(]%YLȎlz WG_QV (kݫ%Cjj`wip615‚,cvS$a,/8(݊e[a' endstream endobj 939 0 obj << /Length 1199 /Filter /FlateDecode >> stream xr6z ,Ȯ8iL6j7/4p**$RlIDTz҅lsA4G#Ae/?ގ~^Q 1s%PD &lckPy $Q2..EX '͖inGpڄW|ܗu znlirPGXFܓ0͵]Cˇ&D0ɋ?IqR"kj`DG00F/6;;p̓0 - og 13' Hb ꡰImPњ08Nu~IYP f{ʺkcb`Įp7|ٰ:j(c^!@= s+$%|Xh;QT&j]kkK9ʱ7ZHukudK9*) 'm{0`$Ke"\ۻPEl/Lu?ĺ&ʼ.촰3K墳`\;M74F6*IH7%f{яW RSB`{[t5 kv endstream endobj 804 0 obj << /Type /ObjStm /N 100 /First 916 /Length 2580 /Filter /FlateDecode >> stream xڵ[]\}_$UU 'I!,3Twu8$e3:[*UCJ-}Bhpc+m/Q e0{-- ΅X覻ΒV`0BAcbW);$£כQGQV"<?Hc E:1Ԋ 9 7q7Fi2߰YTZ?p%)Z-. 3kQ[*nӌf(5.y8R*Fg8#Ś-T~\|8@0aT$\רt.冑M0p7(8gxK=M؟-^UoW*̩ǥV\zj!@x"4JaG60DE2RǨ^?a;#DCq1D 8(%]ʭa rW) c#Bp=ǟn??Cǃj}IȢf V}[=+WpM[3d&Ké{̰315DS*Əil~gMLS6h'&džF۴|E|m^ ~jǀ:ݎy}S$19O":jyT7vP]`TtŶ\䰡L HmN[C PE܎)tO,0$c)RX tB/Xs+j<yOj+˛Q $~? W[7w_uZOO@Jy@A|߿;//n{7's>ӑbOᄏi=G< Gz 6>=ۑZRd۲Mbu DhQj R@2VRBLmkǧ6r;1dCDCGpN3/9H! v"[b5 Gxg,(9Q@L}!"u!"mQrv,XC=!")a?>ZJ{rڂӺV7e^ӎf.'vvET7k& |CW! ,'lﻯP~iz$QN+$hȪzݯ<ې+_  ﱚ}+,e}+bȮ`4gk"} ͟n`] ~"1,! AWp$nW_)d걐Or_#d)p)p)p)p)p)))))7o$H> stream xXr@{J>f_>&eʷT. Z* …@rrk5%cBM0dMsq-0 ZF#ЀPH4@џ }7nB.0} {qzJ/B/)ԺYi&~H%T{މGq`ók(cGZQlC|AM_9)*Eq093> ).C `Tfŋu |إ͡)@X > 5_K((ze-kHD\!h`1.iߑZmuX{8չDmE .&/mNJdZSBH(+I> stream xڥXK7 W1C:&HlyES4=h=-tFӬKxLER"E~&ZW_=<{&VWUB"W ^o" ^# @uZ ?~vS'(6Ieʢ!qXH=i? V^XQXEU,!=(ah3" <h+;7"ς_iZ?~lnכVvkX2QL%]#VxtzB;%(ɮfni(} W6|M_C5۾U"x[ДQpт=HGm&8pq=RȚ8_~Guӣv sC ~3ͤ'= 5]ӈɭ;lOGZ"~M:H`UMT4Mߵ4p0c ~4\yVY6y&Dnp7~L[Y%;ӰHM)|30xu>q.Ya훤;\s3. _0J. 8ʁB&p.?ʦqa+yOn"q|o7t_r,A9in[t씝}bVfN^>h [\~fN/ a:inF'խrN ɼr~4I(y;՜,JPQNlnDI>DWo(| 13DTTQ ,r n`zD+O4NEt*(r4jP݌@1wP> eW&!_ D:*J(\{!K )$OTWBDAuGT!oнy0Th + )B"ͺQ._)pYMϦ9㱁֥`!hC&iЀj˽Ԁ8rK,r*L7 /ԅ5 ܱqp4+4K@WE*Ӳ 3HG?s8/?iY|048*J> L|j͝he:,0v}IVF-8JcvsX#)6#-ro ׫Cxyh ||S<,p1t5ēq jv>Gq&,ow`@>;I*AhEяdkw"cyW%ŮV쁚H_va#iea֫ڎ.zR|jXl+ lhBkl*ъRQf#A0L7: 8\>jvP͎|V9~). K~_r G{.0׮ 9y{n{h7m.$`tcFFG^>]s6kӻ }HGˊ&NA< $^dW.O$Hw[fq86j %G~t Z'Q߀ԮfE~ɎQm@JU璬yˏbݏ|/A—·Pgw1' ͨFm\.%X]؟s}FqM;~Jݷ,CS/pyiڃ qgzYp?@dktK=U5UvIt2Q9y";aI 'p3cŇkrx6|i^gSז3}sy)pH=G"y+t6$K/^%~}ô$}2}a[/ѢL79O endstream endobj 979 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 984 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 941 0 obj << /Type /ObjStm /N 100 /First 903 /Length 2135 /Filter /FlateDecode >> stream xڵZQ ~_ǦZ") 0$1hC[hwH}?l$+h8OGƽDJIpIqdpԭQ k;x_I r As/5QI\Z@3^؋%'Oll^:ᥝJP@-1T)Vu5!ڀSK-d2LT+ ~PR L jq+}6XAI"E S;n$kM"ѫ0TQU-15&aśan2Z(Gӽ&BtyಌLH=o3s0Q>22OCk3/ 24B2,`TaX"T8Eq 6a>!$4a"xE0$k afl!\޷1±k4BO^6Pp0zL;CNBx }!\'l6FH+= ʂG+W;^(5tl2ϮP2{Hq o߽<c:>,_~KoOtuwz^yw]NіvoN98ԌKqX*U׫׶^}Juէ>]OW}Ulg>[٪V}U{sӊfghَqwBJ9}o4D2 l"hɄd$ibX5Υ b/mOr3JZaf+%upH&ID {MgߛDУZ}&2(RJ|$ң۰mPꫣ[Q :Bj[kQ.J+$E? C`ُM>:_?y> ? %Jeo%K|z*`Зݿtw\g=ׂ~۫v!yU=Q ګ[:Bkƽj?S \ 2f 6rhzx,,> HgC1n=7d~~/ ~g?JŕW{U˨a' 6Xvy[Ǧoױ A}M[Bn endstream endobj 989 0 obj << /Length 1945 /Filter /FlateDecode >> stream xڭYr6++5ē2n;NJ;4 Zev(R%8<(2%c-2 \׹H,("򿗳(`ILC@ł"ɔ2Ԥlep)Kҋ:RdJ.6ER. ]V %Vb:+pT4":S/9eZ8˼\48׉aZO,>-8/', ۬~H8obe IJɫM DxɋE桪Wi !.'uDح"l@}9MÁͫ:/inl׌vHi2 !û˦ES)EAz@FH nE#("bP+]W/((G/Q_pOVteaREpwsIX[%DuαȚy[rѫ % ?+hhŔE$eDtQrwws:)EDP' |D1'GR RY˄Ę( 8R&gp_djqL]7L1 q+9^!@hEx^,Q&nEcuʤ*" SgQ8bIi}uvȜ›3'dhb3&z<%6cDׁ1Yn@%}צ0dwDE-Lc"le:>iۍr?zR̹ouy2fJB_S>Nm]@T_،ST (>Zd䗲Rx.BFݏp1ؽņtP\ rAn3ِ bn5ㄆכWpWE7SڸO}ݿzgufc*ۙߎ(37wI`UC.!A5u#1&х}2$+Z7hcsCsεAf 3jr6*6ylV gvRڦW )o7c^xyʮR'ݽUq*,{ڒ-EMI•\M[m@VႣf1Ti2p6.(Inz9#Ql0E;a&_Y5(=\; Sτw_I$… zgئ!-ʼn@@a%>kDc2bUܹOnrwt;}?|ѵE>#1l6L}nāaPE,ю&,'x4v+ɽ'\~u.z2&jEhd?Yc;/Xۋ}3'E51ƭC +'E7[1Hݼx1<:S TZCy}DZKɈ& poY]Hbsq[CChmL}ݛ5JYlŴ |=g/P3ջ1\g]@Pkϑq.}7 Ÿ%t +nOb݁Nip̐ 송#(R 't3G6C΍M7I0@A $$kU endstream endobj 994 0 obj << /Length 1903 /Filter /FlateDecode >> stream xYKw۸WdS'D  H劣t=%YdC*I%ќ~xRtc~~}]W;I42 dm #eݫvt],1/%a)êfV]씓VORc'ri!J |ٮ"g^eS/-8RT̥"*sDDILD.7*bMyX֫$ (!`h짝L YEmYAY}>vxHڱ&P $'YJK<1NI:^]W긄e=O-mzW(,|7?h膫ΌopWhߖV" ^_5/- axի۫_Q 繕Wjsº/aUvk(+v:|ae4'5էuuhNd5i-xvd1R碌X E6 X?]6ЌD M ?q L܊P}YToPF@g3o >K{;m}KkcFE@&Y7ӰƷ~hNmSK0pY}u}b I2hPoԶ8Tò2<Ï^WAABe-}뢪zqe?M@H2a!D'iƌVêO{аja +4H̄CLh^:P!Cبvvh۴sRڡScgCbX*av׵TաUîm Lm۴O Ny eeŌװC*O5i:d 5>Iaj-bo!'1o1[uw٥9fOԺ|laC:bGlGM|!I@rIiBR (.%=H$GOY@Kdu[թY{v~ΠF*P ta 8+9,.@mq ?#͇:"aɔ}KQ7m?>HH?忾DTVmKS> uQّ׎2V# n"gH|FP)'H#Cl&N(.{yr0۶ЖY h;l𨟧SGpY`*/^ds]IѤÄ_uWcns2:g哉X쀣p?홑/9Z94t)u?91#S34^_X-. v`윛nU 7bKXS6vz:>Y5X8t;{5cewO9"_W2J̜gnٴ]@_ ;w,K7SS1}r|)Մ{߻>H"w"xr.P5ꡋ p}D|pj~r˨v,0vzcudѴF_ksgqʲ\ȧ'.=I_4Nzߍ=FRe zQ“@?|0 endstream endobj 1000 0 obj << /Length 2231 /Filter /FlateDecode >> stream xڕXKs8WDUY_ss*̬ڪ$$n(R!HkT?~ }& _r7?EgrqJUgW0+WW}T/(liyY֛0y{ +XJZ%M ƫM(h}y(NX>7q ы1Acxg{MK$̤WT}֒f/Ժ=ƘZgVJCyJsBX7*T{ېyF+Z@ݗN#EFTFeA^wdȼph&43?k} ,D,]ձ?Y1tOVl4a MfhDC;YJ7o\P0بq'h ` Kchayq 4f8th;M۟Q l\rt|ZN8Q!@WS9|#rnm cmcݙ/+U(-'y'LEgRmE%t u-dsiAT-l(ȘSJ5'U54SKyfmʱpx_)\]Q,bms`YA -IƱA<5fne|`~We*& 9{D"BekD,y02 Dfo0j{F=3%=YrYY5.gt00,?K\"cy;zǼpݙ F@8'ɘym:IXqZD"q{b0}COcRp.zQk(w鈰=M4 p/C.dlɇ1l̄iexb%HDnLaڝz(`xm\:T!j͡03㢆UHPeٷC]6 vHr:;􅡓f,ixۖJ%y)RHE7 & kX6֭_CglIJXΥ$Z y%e8ƅy߅Ձ1wgi4aPmd;F*KZU H^&su*Nws"} -fv48p7I4, \x. %}n;_(}^ȲrVN|Zb~crއPi:#+?"4n s )1;x̂X ṭٌ;98)-j,,%蚉溇Tġ+%b?^RWb<s?Gw}]EzٕskkAMn>?-7&qpurGփ6>Y./2HRZ)M?f@g益43`L `Cò2=Pv[zvow I G--aT`p oy3Xu-Q= 5b 3hv+j^?P4u-+y="qghjyZck5LL#ߟW AC6RSD3<+y|7l ڭ-<Tˍvt{y~꫙(Mڟ _*y,3,ߣk²߃I@ & >Rʾ3PgW"|`&HHVUjlNva%S2zp/z `f>|p][L*Y+vDZg>O\'O8v8: -߰M2 R\> stream xڵX_o6ϧ2X")o KR`@Er|y-9C`tf/2srm6Mձ?MTy8U^T8~Me's*7{3, )لfifs#I9{yHnyv,\%) $MQ)T}W9VXSg.w3}g WpZ[)XW 'j!Z\V&x^ztC~p;6m rXl) , DJw`q&mMʜA ||I3]Ƙ u9? `\<)WA\9 ~DrH|tk ۪7 CEG Xh\,2*7UK|^A^_aM秖ה` SBAM۔8#.Hl9ƢBղgn˹۾p Ҙ>O6EHf,ӋJ;?'d`ȈE꟯q;#vEQub[Qv4q= S(m{MW`,z-EMMv?m#yīg&a@Z.(g wܛ4ߌ xryg7}#,̽ <0BNntEB \ H Oıt{qh v$zk7Ths!j@@{r C+K?9QܗMwѴ1g LkC}򮗘KHFam[Z}(aadvI3NxSԓE,?$&&vI$5Ln$e)TK}j$b3&T^ ,yvX(U%SR0?Lx]^xt]^ͷ]9?ۇ,KaW'%#جaNMH3 dL&<FrM endstream endobj 1013 0 obj << /Length 1399 /Filter /FlateDecode >> stream xXKs6Wpr)ՑPH0=%uqƝ؇9"dI I )RNO">>|Xz~9?c$4aʋ/ FwFuVT(^$)aIPi LIӚObp!Z"|73O I]s1m7SըIa!Xf@`R +"a?fSlW1;XYBW)t"W@vYȜ#͍MVxB~+;SVtYeMTvLS.'a vs: Βm@ÔDP T)#GXSZ9c@HoP&|W R?֓P`KF`'atetH(;(6u2|_ddppq1xׯGޅ8]w.AQTyW%&Ӫ% X#d(g+[M2tO>x0$p,;(^%WX}TӢSGh =D1$U镮pTT5M@+.:dIc+%B'S`!0cΊFWWsug7Ҥ$F roRWd+qj[ mKKous8s7NDkJefw!be[,I>]5\usrڗiNOK[ea˒'2y: W2ZZ ,VJT]j|%(;(3(3;HgjUyw:eΖ+g; 5!':s,kxSV.&~FfmŰZ\3tˁy**C-ITE_cuCl.M#޳囖뎯z;-dY3N|pD?vjT;XQa)s6W"q.$$f^0Ф5T[̩\zfE:=L`jL T_zpÞ߿jICT&o`ӽvCD> stream xڭXMo8W>@[޶vE@cѶlT7wariHf7 )rG_xps##QK2Yr:q0jt= \oݚzaLoxCW搨esB*  Q)&圢j"$`q1{e:ם! pP 5xZ;$HWKmS6EB=>lS{wINs3M.3\FdRHHr:-xՖQgigVV<6z#RMShc2:xƳ$r  snfͮàm,l $30$xϗRy Y!gMy);w`ܣY)2^.*PeqF.Q!nQҠso0g-@ݫG0چ 瞋ǽs]eU7q9O?oX> aVT>>\Fxg»o!3:dvu}AGzp4$Y w0Z*ߚݺF[68#PXم4%N3!N0CGfk֒MH~?OwyJO03)t >*޽Tz[ E !B1P,9寑s$*eն[W!O_#1\ |qB^^HKryQDxRZkH ghsͰS@[6Bdo'ղD5~H?S"U[o%-RϺ֦빶a?{}?QJ/ ĩ/'>₏f] ˝Փ Շ1 Z(@ $?onRE endstream endobj 1023 0 obj << /Length 1047 /Filter /FlateDecode >> stream xڵWKo8W ,[l]a$ʲP@w,TlaDMgG#ŠD7 ao6!zX]/wY8ZSn_޷uZ3b+̀ǥ&Jmۊq&+H7fvGNX"J(=PR֯n6H/+sBgTHHzd ,~/M ZBȽI#‡s0 MG .3) >7_\_A_ƞtHm&ZygN9N%'#,R `ml^%y0d '|> e-ug&"{Adq4Udqv3q3S4|*Kd?ܳR$* plny /Y"(BL,"9O*x){{O\BYWM6+kn/w]5Q!_{:hPB1{kAEK"b恂!R4TŒF1蘱##P["0vOE^ç*(ˬ_}unB]o6ޓ;W~=L>ez_YER\y,d$nTK8<W[ W\,~ VfסK#vCpП=&e5=I. v`Pw>kEn$14mVhM%Uw;5#\i2[DPL".~!(:2ݠ.lJ~ ׹D"nm(+0j2ׄoLn$ݖ͑ma-V iVoέy0/P򎨗ն8?aS/%]q_YcOXs),=ڨ?(MQ Д9ߪ]]=# (PO~s/pL endstream endobj 1027 0 obj << /Length 1648 /Filter /FlateDecode >> stream xXɒ6Wr,X 9Ilv9jEBc )sT H* C7}oW~{w\x'җԻz"__S-_~dc:/w~//ω/aZzlhvƊV+Jc…V' u|Xqœ,+ʲ_="sǵ~ILξ,WAC]V2QUHF+EzI ;|!`UPONC vHXc[մU 1cYhE@KLWefِ&?'0-W/GqgWrM) E1aOX-BCƷ#DwM;['"p@D.#7h~iJxZHt Pz_Vi0d?;bv:2hHH$4t~4Əg[jlYBB?EsDUn(Mpm7%Ve[dA0Ml" = *I3;c7+fb ^sAE۩08`kƷ'l_5/=b^nUiN$u嚜ݼ1F6"#YV7(Kg$ήգd]22`QBegH&vsӟ%<݀30y,TOe eNũe -)n!́6+`xe>A]5HGS+ 2ȡ͓x@H Gvޤ!?\cݧɃP*>ONZ*8} @'L5Dx.dcLa se!jcbFΤR%ܢ!)&Qy~@ѤʹϛF_XG-9w`GO!6]d῅JV=Hyw}|6 5 cZI>9co" EfuBxYpeo^s,ia?MՐJ%Y9nu> stream xX]oT7}R_3*B )ZTFJQӽQv!Arw6Y>}s|<3ޒ8Sr6L)P&&aMLs20zR1%xq_)=\~2)7td 9191DhxmFm$C!H˜xcAC")ސ\$בz<@̉ llJ]hv {FFGS)Y)ut1[%M)'1`w%9FŅ2zZ2̃Xa(aJ3|"1xl C#Ph| y c>(/Q6A7'l{9>C7G@D0xpEY " 'P҆7IF]XXV`pa4;;߃r/G?E˃]j8;-ͱ?3ҜtRG_0pv`|6_.p~l]S/X >4W8q?6$ƅxF/.N6b`L01zQyUÅm5zk8` !Vq$bqcnfVRtkDCm%;@ H]0*85XLf u+VP ɯp\-lVqr R'Q*49}{\^.~k;\ŅEzy?D Άv|ѓg>;5~+@/k1d2uCbG:GOF7[9\DׁKZPqwB @&^Z_)9"xLiLĥQfMnmQ-ɉ Fׁ!iU&:УN%ׁ%;9 C`!I)9 wH!twarK,X:mQfaNӠj GK@I& @NVGR=qlNiz-zz+zPp X[O>Yg ?FAr$[t endstream endobj 1032 0 obj << /Length 1422 /Filter /FlateDecode >> stream xڵXKs6Wpr:'%ۙ4mSE6T҉:]EH,Ij.pp >^M`WwALsxZajT7X;ЧC}A/VJ(5N;3ߒiPM=$,{9{>{$F$;$8\g,xIWnoxF"`F1iRMg04hs-?R5Zg%5|K@iV(ʢ)U\ZASY̓1ɼ/=LFJЗ#7#A{rY7t5҇S#}Nx. 8p釋˙,ʄXhyUe1%!yaf뺛ițh}$kٽR(WKX`a`(FC7VWϝE}uƁWP?Gc܈yթ@Xʻ]5f-&h})F֛JImƇp$$=\e?JWO܅8-s]|>ާʉv@!Knft tX37-WRVC҃}?ѯljXT[mŝ8NziG|w/?d#M x:^Lk٣Ú퀺:rɹn*Mo Wjٮ16P-plQ-p1FS3o~h"Yn_`>~4JyRUJۅ{2Iwz':p…FYd_Z>B $yv4{'|baGzcDwIN9 mW 8}E %v+ f!4w!r cS ؄tEw ,F bI|@"8pbQ&>J§!14JƩqty)1Z{rq54ў"ȤqK]K\ qV|t.|ś`Pen*X?F6HCn%dPu5Ö7!v `=9B];XHwan,98|'7ݿ-剉`?2(p:rn{.Vf+"6O cXz977ـKw>븠z_ٛ {+ٟyV'Թf\lhf-=@ɩw~]" @ ?=#՟(pO|'ᮄ[>̲,WFݘIqW::М՞ endstream endobj 1036 0 obj << /Length 1380 /Filter /FlateDecode >> stream xXIs6WHX(@lO]Ҏ;v&{IrEb**A&".(iҜayx{[@]o/pwR e8#B 3+ouCef_s|;JLJFDT&S2v]-`tպ-*&QE/#~]+"RDbb37X4˒Z*.WL\?mӦs]n*)rK^kn}?uwzϔ2yX*P?/:h3 NT1X|iLL҉EiڲJA{׸xz|Hw=ihzzqQU q|khm"C"l@|>lX"I & R,;vH =<٢ ( =bl^s.`(]bY>vz ;deGyǷsuӖ0akn-% ݲoCT}.M, Gd>~0Ԃ6ϵkA5jp퀗qb(u}E6"/;_ueݔG]A@5"ȁ8x)-K&Xc&>7M_Z zA6 hfinA37$42|X+9[ak f%3\n@f B8(C&*+^1 IRXMdCަytȳYm]C$3"~VC. hYO>{~FG "P :./+o[l4m*T` %N?0 ?pF:6o 4`5^ZV7B%YFRnD=نbMcJPѓډ'i^Q1fUgrҡ]շq{Wݼ=[V=vMht8ƌF3=/^ ?h endstream endobj 1040 0 obj << /Length 1191 /Filter /FlateDecode >> stream xWMsHWL優d>-q[͖w-R0l`ȉ|@Ǝ`LO!nA,ax{$h}bbb"[Y[-O]]ԧͶWD˯oϩ (dT޶u 9灾+̅zɒ@Edrϛ؇%enne'aմ,U*vUumm xX p ǹ4‰`@ $$VS`:W}z]lu+<8tH]7߇ٴ͘G|\  >-pܐI8bXCWኘr޹ƫ:l CcBoU徴Ŧ-6J '4+ /eTY8[/]PxLE#$# *_|JP>"yv=X*Z3Ў03pLI8N6s|nx'$ȋ|dv1;0PJzJO',1NݧO )Ж8}(K\IpEX:48` _lu`DH$)87S 2%vjI'w5Q􉻳gFUգ\Qi6dlBUyӴPF6ېڈe Rua G K]X?^8^E pzbOLwx:evtsRAku?,i"t9&wTK \/.޸wfeY&y46yS43UrkE拂Ed`s@M &vvo4;Hpz'=|dϫ~`*2P{أQ(ǩf(^g":z; ?혙_pxbF?v] endstream endobj 1046 0 obj << /Length 1978 /Filter /FlateDecode >> stream xڝXs_IJ($t.M&m퇛y<I?XdACZ,_cģ^q/?%*:2Ҽ`\qmYןxWw?y| L!Nհy<9JHX3̘zXn㦅gm9mBlg O.g[7$9~IhAmAT"=)X)MYZD]]n,VfO\LHL!5\m_/r&L8'Z]n/Oes0 %AY%Ȫ]_brLAp&L Tt귭5no$) ϴ [*ނvwF8_, @D$\@z6C~9KZYu:Cdnʦ Gr]dHpvCk+v:iyfqV7 A #x[ X2k*f`oi@:IZEΒdѣߚn["v8:?iPɓ˩;ګP1yӺlGsMIx2gJ2)4pFMq8 MH[` %d)KkxNxס|![ڦbMg^Q+* SSt3U$ݳ.-|{aQ1pÍq*='t 4(W0-\K0$B*r)NngxINRoniO*z'/$0 y)X_Hb֙#Nw|`ǥ[3 Q{ +=?WRm+Ŷjh.\Y6g9TU? ۔᥃\PKb-gR(bm9{iu=FUC{ 9Z3˙U&)VWC:JJ^MtL"~kM9%٢:"Fؼ>#uUB 0.|<8P 7*at^ کZ 6=+u=3Js^v)oMO=R*I6r~&9H}`L ͣ,ȣ|O?<9fWLHPǀ:<ۃbf^t5i$WA4?ˋʋҮ'( 5\CfymH9Gi8t*oHfQwM_43C<7C?E X.YRaaF&4g0}L NSjڲD) z2Q:?r Ez*[um;!s̓Wm`SAs:lC^iZ#5dvp _˒Z*Hq$2= 544ج6)YL[*o_ hRSUg!g  L3ŹISjr$1OG}_K!?`'aǃs-AߛAQ!fg"4^| *]%?D 2ܵ0QI~p˫!*#O”e:~ 6'\10(m!Қ"7ُM>XH4|e훶uՎ25-mYzHʞqHmq eK٬oǞ1K 은b2\M#ܧ_Gj([QAA-;}?Rdluz>Ƕ endstream endobj 1052 0 obj << /Length 3007 /Filter /FlateDecode >> stream xڽ[]w8}ϯַ4o$1MzCz왝#{KM!3O#JUW$uv|{}1y޹e^vls=ޝ׿]yh.%sңdV??ɘSsÄ?G4S^+50nc|}9MÐʩԆfEViTf)85S4q0V2/e-g.sAyWQ{}ẳr+@g;jcLIp:Fk%/=ͻ<>SVYgXoE8xϧûiE(@UgXfu`p ss 6Ѯh0$LEuDE3f|y;&(=˲ b./,MOw29WR2^פE$3V,Bq{0:~5ְ9#8ɘyqt`ZøUu̵۞9]0ae ? ~XZ2qmn?I#Zq4&HNGI40N⹟dOB} )_YR-!i>$\-*n, ;Uy_Ua#00TIK h8~ Wը\Q0 GVUXA} V%\UL4sN&U1lW\Lt*fRrx [ݪɵ̍bZNslK*G'l +޹5 xgv?17!/@x =#^__`sFw x0O`n Fh8IǗ[RerHty//CVHycyg*IJ I"I1"IR ߙ̈́𹇃ad(8ڥI`Ul~ րy1NWXF4B5=#q߿kZ#UzK8ezDH׭z[s.gᭉK`G=D^珝/vCT;Ȗݠ +"jiԗEM q޷k:{~厒@a'}K*!hlI3 1yLZ^<2C<lH5VjBrnL[S͕R՛Fjotl{fUܾ$Ze?Wі_E_%jWQ.ׂM-yUQjhrT֭v;6`hĴV%c0CwX#=()5cJ=n鬭xi&x|zhXVKF\+&֢݁fgզg,e̞ENr-8B_\ȝUr տnM5Wgx}6ش!ҡ'ہD%cH6{T!D׎q+jYl"_ˀ eʳZqOɎx37>\w5g6$f%Ss" :W+őcؙ;)F]7fFe?.VømWr5h-6lM~J+TGoq)znX; p]l2,5>3?dY4]ײle0-N7&r8,5;!31I1aNGͻŸ`b*7SʪS)78a(cc#op1ZyODÄ6|[Zz=M Fn(=N®=ǟDHW?6ׇ1$+C!-=i"Yp%bd 37Kf-'CUӋ8a1L_ġ7EGB$W/yDŽF&dփfF=x ¥a->KqT;P5 Sbu<\N,:B#7աgAtT~HP?&0(%[Q\|v $dFkDnOKV`I.w-| O$.=j :OƱ<_ KR_jcs>W@s d >pD-~CO+>:/) `dqK)!L F&t4ӏ7}9<ܚM< 8B5WE=}J%ç=hA&]qUl\]N?%1DOtiم |}և dtRE ?}Ԫztي+Bpu/aqf?QH-,CtbA;4 B̦d:7E1jAή~=Jb+85ؓˋe?]z6Xgaa[[h,p ,gzߩ;4 `X*u૳σ*P*R")'?}H2Nd B㴾ʺ6`5n갍isgׁZ=F,ކ>+;耹?un6F%(v|+i:>h`M(41ٴ ]ю$ک6-$zX~1A7w&L-8w6` lLwɅ^_۰ڊא~sF@ <,D!@WYYJ9gǩ|h^\\kB'.Kkž~H ՘i3l9:f+d/ڬib~v| _2PPZa e>G.h*NGjۀ׼5f3Hm Ut8i;5VY+[਴8V;@‘wM~WH9Pw'lc:4n۪ϷC*&X-ʇog=ỏKů!eDwPw.'<{gPtڶSK%,Euߪ endstream endobj 1057 0 obj << /Length 2805 /Filter /FlateDecode >> stream xڽ[w)x;de@ i>8'a@jL/dw'lOI]Ώhvv材=G7c\MyPK4smwGG 1av,h<w=JՇ LX\-zӣژ]ʜ]N[&M[B^߷`!T,X,)btw0H)rDYڠNf|o1uMr %B7^7'L&h s =gzyO;N^:D.\7|UBGx4kJk@z1'mXˈ* JHW[t1bTLh6ݭZLS_ %R&6%L;_׋r}|(f<涿)X?Ue/כ7& Bxub3B?V bYV|1xX\J(o6]zk}YlrׁZ_,o!}C֡jo_<>܅~|(j&*A}nC,14B~YUoV˥bڏNxi0ԯ!!Dq`NqNAF/bDq Hb84%> 'mSJ4rj1&ž}3<*>[lߢQ\tPER$,UiFno$OoOG=m2ɧ"n1(=ebuAU L`~8a.g%PSL,UkKLλT\cw2Rnb WYUYã7Z0jCTlAs# 5)cy1jG8Te`Sx4i33vi:Q'*!gw5m:/` iȁdz t8^Gmzh1Y6[&w2~@hފz OحLL4d9 xvqP Y4tx]a]1FЇo*j3/bP+? ¢ ~/!G,lie~W蜔s&sqkb۸USxS~/uM)//c)m_{d'-yIʐHGzpdDaUG˲ ) sk -$s~*Ci3~ؔEbBM56N"vY{_MvY9E s$.u騆_P!d[Ik{y9m9g9)hz-ԇ8YH#Dp/秃O#9ìujƵ"dJtJ.K5̧4Xfqm,iS=iOٷmѰ9!CP?LR("͓$Ep7U_3qO"/s 'ғ/ܔ1DXy)ˇһ0=_{^RDNj*.ÞAVPp"̧<+"Mnz‘p L::M-vpiɱ]یuxprzٮ&~@a\tU,$ؿӐ i[&J`+/og".|iMPb&]=O[{#]e$.y0&zT%8X,T%u2Y6x%pVCJ],(?X{LP)2j^'Tê*au~mFQ}iH7t?XX˪ը˛1~]Y֚1Zd2:;%= ?sTRRTVYH^b9^~{D2WD;S44Mz Lr "Qu9f@nDbt3ɱ (Goa(vC"PU9@rL&9Z$c 6~&H ïI:Pp_ Ey#? iK$IA.8{eH{9G,hͤ0Φӫֵ:tɻ d"aEJPEa9Z6gԎ(T91{sD팄i l}]^'%TXM`\}kaL*BCUJݵ28 Sw>ţSU;)K'™LH]6U[%ؓh́'a"5mWդM o5 5HxڀUiX.ؠv1]v)j,\`9 J퉃=#pLLX)vQO5~a/aU~wPF'Cp,Z]nVM曻r3z~!1:6R :j{nLJ*>4> stream xڵZms_oGuNBL?rɍ}=i:̈́`$H/X&%Zuz@pv}tQ$̭l=Bc+q-yoY¢`\H0ia`Y9<pD7YV(XCbp>|G.;,tx71G)*Sz|D)$qqŇJ_/LP+d2@)h52<:dumQPȨna6fNPl$PD.8TRo,X|8vᖒ[وx 4#M"P%Q)=zj%j]6_ZJsleESdKXٝ#K۩r@%DG3B3`wA;$r*/g$]ۼ-vRj{OH3sjveMYHL:JK9Mj8`gd2P4K*CmDk q(Q*)ɁV`ZUA6f#z(*ad7ѦhB5(Ft>8>f[ µ[ J~?*uѠCQO۝ޥ[71$&fkyS87h+)}"i]W ͘[ɗ;@m'o,RZ`Sn캮Wك"û,S^O ٌYAJv6SMIgs/۪XҘ2% %kjy!Ёp6͂)J^@ْ@ҡN {W? OUq>C|m=:$%^88X"?AGUB-O](lZ=(p!PH 0L~/Wvj;$Ћ0AwT$~_lX+=^7|B Qg+lC؁APRlƒh,]uf{,r i6q{-o˪h+<> rǛ3Uи[t,Go:б$ӮgGM-%wtۦXRyo6[5n|8+[eCiA"{;iM!VLc㍎r69K"m!}1|4ݫ P"D"C;<6)P}/+׷&ه KXH6|*@M9;0~M\<Єi8o%~qJVX>0OBmg3b?ry>UzrEs=VDf{B:!ΠbiΤ}5906 s։X|J7P{zZwO-P5$>屁\Sw9 c,2 evբ}:/DCIԉ`$"`yQ  ں>p,[7${'{pwEڴϺ׃p N:Hu8U26ޑpE f2-[GiIvDMi ۱3:W m'X?шUEĎ~w)֡fuS҈r.Q4O&?8TemTqjm]gUAidϓE_Ț O.C-lu{'"sGu"8wMarP'wb2޴''D<| T;hHCNP9(hF:nwM@M?yq&;!j"Lq+<'C18vY }3+ǀp:Nx!@VV=.i?'(uA[oX"JT붹\Pg@<lm<6&ɛ)닛%bW7,{<n?͛ hn+#PpD3¸Hё~~x$=/v&?ᜭn|@\xg{.S9U'@OtA  Rz&j!uIQ IIv.;4 DS7u_{A<.d.>8{oAQB)E#h)1A+$X g=ŽV7GVB9HkAD-[5l.h 4w +h4PV|lgʰhw1xn[5Bo282bu=WÝL2.tۗs endstream endobj 1072 0 obj << /Length 1681 /Filter /FlateDecode >> stream xڭXKo8W{S{KiEd7Y`Ecmeɕ;P(Eѐ3曇BF&4y/҈Qba"<*a5錫$+,3WG *ܢv*κ.+mvxw(x?:۬*Qxa""ԾCj/?y/徣\SD~;焁F,JS!.|5Fsx)D4H*ɟКPh&\|]ÉNԫ5 }DH6%cDk3)FaHfI>Y5 %T"%W>~ó"('Rװ"ivOOb!2ebUpb~Vf2^yQpkڴnQ-vzg̋6w-JC,m vr5*wF|+Ŀfqp|Uז&OITЬ(:onQE^>1g{]P(87bCuHZ`y?pLW(#m"($雩p_ s;)ܩlɨڐdӡCxB.OVw&sܡ^z ]]VnWW|Lf̜Bed$gUl)fS;.5o*ɮ F`% IˈQ0 B Rzm- 8hcK'yh +p|wj:;פoE]:7v@6@a j!kfpFn)؍mI[?l6_GWc(0ohrN3r4`}H:8 ړo |k@Ca>*w8 c A-HPFѣ=@rrX8WWYHH^!Y7uCr*͋xwB^!G.[6뺵ƿt].J6!Fڠu4ZJ*PxS!GcŸ '7j]q yb[ /s&!ݦ7E%b[43NF M@0g'q@d4S! v&V~̃m <*x<{ffuO*`A4B8Tb ӟ9@ѝ.Lc{3Ex gয়/㗗6k^`zⶹnVlF/`aca 5`s?8ts?CF9eGL|3 L<9qa;FaqE >l\Ίeaw6ZI %Y/g`=Ijvtcrc C\޹u]tE;eQax:@dF-﫢{ Ňt Ek5aت6ENzh0^m:;|=×Ad8⿝`Y?uWSHqƈ(cH͎~`>@;)K|ɇ9 X*۵:Mӄ/ 9 ^kl_)\ \aftz9_ endstream endobj 1029 0 obj << /Type /ObjStm /N 100 /First 909 /Length 1767 /Filter /FlateDecode >> stream xXmo7~R_x/UJӦ RS,tw!MtMU?$}y{fql B'w$a!*:&P2!c0 8 )Q\vF-d6fs X<~IA:R@2 gĔH#  *RaAT hM`+X>0D:!C#UܳZ T`X8x(#YE|;b Ro2KeB2bX勂S2kaq΂A7Ő'_0yN=/5Nc^( >aQIHsHs(9, P ! Ρ 9%ҌQQWC:<#X[@> $pZ?3B= ?x~& X(~5LbCxZe50vA% <ωUDTS/jIT?dXM@I"PNO=)\ I^'tB:2-T Ԉ4p UDCD?QyHC4ɎllN: ƒtW hvOnތ_bmӜnW6ɪC3LO}~3{}|)[h[^3x-|`kX- 16OQg_uZK  a %C.6Ut taRfVaqΦ`慣/[W7$˦$z1e H/ >lz䎉$~[XNMub}rY.is9,}}!༜%^m޽mWiwG?ܺl$d^: qlVVhXu(<{hݣ/VI@[#>2ooDѴ8ܡ6=ǣU-?ۓܞO.+ϛ}g߭Yp{8^NW|ҽ'7YYpoaRq-rݞNl}299[mW;rEsi(`aDŽ!U\bh*dcNK3wA>ޣjwf[WO5w[N[~J5'q3Wq> stream xڵYKsFWO%);Q%g-m.0 I%ߧCR^`_O7=M&4޾% I2Id% KW QT]uk@<#<Ӹ- Y> _P|eGtm+dTٿA 1,+^3,;  Bg@TLG&u.oYMl9^wE8眧N-m[+?mLd{H$"@p'=d:6NWbs 7b`5ƽ- P!2<`{L鉲s&1<[mNJSܖWZMYPrfٓKdY Uo)rn d g͝e wxGP̓T;@LyP3h:` Yf2DHf"̈|`Whc]< o=0Ӕ}(Tua7Qi0:@ <͹,QoT,rQo#!$ N8Zh~4cӏ )ӼUvOU|7Y˪,-=WTHUk[)o8T,c]wqլcC[ee4sfX&/Q.Z }y[^]ik_+?qax&wfjuH;](nWpZ?V!)n*25M]=*|P67M +BH oc'  6V=68ԞS'5qtݰIm#:&Hiɥ1 o i.'>Deájh(Jk/rŔkZ}-v1~\=."/D64)PZ`4:r\aL#tbZS.QeR Z^MW]K[4ՅwNX0ׯ|[u7Xρ:O'-r8xM[)v._loe_gr|7X7給lYAT +1"m9Z|U& "Ƥ)Կ̭B3@ ,!2S,(,p#qx11f!2 pAeL u2'lrg}4.)GHlevoPl-Nyqg4[` CKa|Ѹ.{.q 196Я<]EݵUv>d{ObnXǖAp) ̄⺷MSU^k~]|Y(ҏ5v{8: "&8.eSv}!b幌\<+73eb(>NY^5GfB8}` BrؾD׻69ϔcT$~Žala)_jGE%QLN#:'3TE~$0I24EoO,$8uIC"vZӺ M]kA5jop;AUjZ." LXC>x2*0kLoܸ+0eeK8NMMS uKLntY~96OǥݷM8/* !CeobG߈CuغP2Wڷeo --j*H)a$*0dx<;/MF6Yoik>o*4Ha:n;xpL)HS%24JuCwƇPn6巪Ҋat @(eD endstream endobj 1085 0 obj << /Length 1714 /Filter /FlateDecode >> stream xڵXKs6Wprf,o9iN&mthD$}wDJ"ApLJ}ģ_xx:#YS]E2m]u=]|U~Ͳ \Ppx j&ƒy*ieA )aRc!-2@3!˼GcTr8~IUS>^|}]D;.,5t?I3$-?Yܩ y=W]'hnU4/qUS|BM׋IIXіqq^FF 6݌72E99~yyy&U2`1-sXX` 90gK!6-LsX򛢜BXe(2IBw|Bg;C#`::ei!(Nh8>8S"RLͣ˳?#베{FT0nm۫_Q Ql33'Sē+b2WU^ca%qS\F*&YW E^}N/!ay.۱P蔼e j2u~YlAEY7Y9Pm$"Ӭ(Z- Svӆe U+[L݊@ u9ie9RƷ`$}1 =JOm[Y!685guEMl4Zͺ*wXWm ?2\:-"Bx5"9PHAۆ=YKm d[=fB)Ͷu &4}}C Z 8CQS .T  J e|k+ȱl"`zӇlvv+Sx3Xea4|Ҝi2-g‰[~lҞ!0 Pl3~Py'] Bk: 2Zt 1ƎrJtN9[d2J[/w0<⦑y&L+UI#D3҅9dv(p.é&InC<o= ]4|AdͼdkPmL2lakePCjG}KQ_\9mE/|΂f`ZJ8 D9Хx/`5p}l]se}ͶЉu/ lI xG|ݽrAǸYvG3_=p{ިo qۿrͬRG]"oRy~v/6p^R4:V^/h6 J2zzPA {aě_fPXb^P  endstream endobj 1089 0 obj << /Length 2312 /Filter /FlateDecode >> stream xYMsWLŜ* vDdWvu rL_n4!%&\4ݯ_7xuW=볷'sVX]VXqbWS0xb&)sVxkk5ǽH+2.9o„YZ4i*ȬܚG{M<|e.~;}`O(X&p&^UU̒X=x*a"OUIG+ӌYגWǿ]|c1l,|Fn~vIWuЊE7۵ȣ= ti5s>mǣk:u)Kl v JA$SV3rg"+$IZZ9N0ML9Kd@Mziq$2nq֙YZR±Nz|GG}xJTA0@6=%[0ѶR]??vaafU$1U|S &`*TB!5 (pZpT˒$Oxx[+u"яPMd1`^|}֙&ݷ(m߯ mG=᜵2: +A"8=3>\qƱVK7'KlT 8BPi9ce)L=o^ $;AdREO\9 @(I;B{c|j`_"{| T VS>0ɲ|t©nMGRrԪusd ! m YɲL D' `zD&Bc(4I=Sjk] AI !֍s֞*%߰L R-}4tsj,"z؇:U3b6[PlXF;\ R#^Xبi95p TC/_qK0*oU :xnYt'AT 8" '3@1b,Ȕ!<t;)Z~il(@ۢkkK?~ޠ3$7"O` u꡼@Fw,?$vy,y^?_A?=uh@_Aq֡/9m٤<{)E$x_ppOy+;Xn;ٸPr,nGJWf.snZs~cJ9A%dp6 w({f(^,NONZ tirgSmm RGMuD~Js䧻%1"PH)[m9!Gާ@>W-$um7XKi$)SCy=x'(\N: i B\;j6okn#m}Rpk/kWlgB xJ EG0;$ fP~^>R'(MWWPػ"T™,C㫋%P渠'#e '(`x2.NjdRd >G]$3 *Cqg@F/ˁ ãLL-A)Ϙ,4 F: ;|3)d94x<0kŗK#< ֝VDG7`*ZHk k?[PtCm%k!x ]\܃ endstream endobj 1095 0 obj << /Length 2781 /Filter /FlateDecode >> stream xڭYKsܸWLbj˃ŋ}d)ǛN`@@3rY>j|F)QZWYl6rӅ ߽n&՛TBZQ[{quۻ=ߑh9f8X'"zaTP?ЇeݔUE5V;y}ß^y.v9){^ 27)E0(k08=;ƗD}<3V=BY#3ìe \8QwCxwvw=T<Dŏ/~PܨͬG+]ٝ.>|=>ƃ6F`Tm]Rm$OY Y>`~-U߶]їMeBCO@QEFq)R %jٳv OaY׹6{S7?/a^l*}y3@dC0uӞLJ5wI25zFO?mtyq 't&YAzw  ̬}c(NM"Lxÿ`kN0sP]HrY<O ~^C mǥS$-3S 9ZIcJ&(Oǎq7)6IXBٝzhXX`,,\̠[. 1PyC > ;՞< ' mcv~ʎ=:Z852`<^d2*);, 5B_AkRbM!AB'ח;>HkJG]x<эՋnv-SOwGHRϭxCk2z0,>XFWeG|AaX>D^!0RpGȧW'dMmn\GzLwQЄZ%T|ΦiȑJ]"}W>W%g.EXw<^Ⱥ|`7,G! e詈:z0H `S*Dϱܪ>FP +#N^i!lݮgHLZ:=E 7}qU寗A01v iR 1Xy޿ je;V)fSp҅2xXOfA9HՇYt8ɞΪIYBgY!7+Hm,b>R%_c i8M𦬻kia󂮕c]c̷ -"ݬ?^AyG%쉌AsI N6@qVf*$0S94 ZxBc H%&kkB> djtd=2kY5Ӧ\mg=7K1hޛk2RMS͆Tkؠ%vS"6Zd~&KkB6A<R^b20{rP>rUyݔI`S 0 O AE5GloD[#M,_qiL'ב|O3KG8WH`ρTK*%3奷kդ&xYw+6z5wV'AYo(`{8AAUHg&{ӈ23σ|9Xwh:d;+č/xuPH ,H_Q7e}C R*x s<)Rσ4F z4kbOM󠆇}vB,(׉42넞tNGp[R,D o}Dd7Ym)d|9zfr h t]I8y α^m|1YMbbNq "ʠ81]S77Glެ $d ܜ)jpW:zF)q%%9rמdo_wEB 5TsvKgP n:<@|xD6ypX<͕ؑФ0HeP>?e!тw9Wtzk1, mY<薔olUiL `冤^|հs{f8y\e_&N:O_> 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ȏ~LQqrMbKhLH-Mys3 endstream endobj 1149 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%QURr,~FzT endstream endobj 1075 0 obj << /Type /ObjStm /N 100 /First 950 /Length 1468 /Filter /FlateDecode >> stream xڭXn\7 Whntŗ$F<@ Im,dZ <@=ccW \Hʕz*J+I){f!Į:VSeNZ+kRL;5YǺ\VxRmPPk**,7 j\梫 vb5h6aL-tx(H[Xx8> V*~iʫ{mx:Н5Uav+;>Cm-q&%J<$N$pÝk͆ȕCRQn r𥃧K qjyEeXIdSP!H! I!U"H-JxtHHbTXi"PT񐠹gqpA!Iz G p88A&(R6h@곤U հNT\la ܰRācHp(pGIp8rpH)Gh@>k#>M%8u $z%szA- *"P:M ]rlw'Of"::qa( ]=pr| ulj\=n@5:|xH'iz8Mo_.W+ \h}zqx^7gۺ16_IT[s~gx;oOOO7v-[a-\~1?lsq}6+/聯ӏž wxn-KClٯo&!$߽c:+3;FA(s!_Q6Шg3YivxHpK蔫D)z3&%{ù|}i7Q4tbnF3]uȊ ͗qhQR2{{0Q{1,j5s(*xȍ-74e\nGɺx=p(N袝`Sj߷Y=<`Vs?R;?6›u6 ]UzX8s#@C[n@sq^vh-ghDo@,m |V<½ %:kШaYpPQtt}D!cJH[%ɭ(,G-cVFDz&}D#.EG4 vHh2oAۧ6P&9r <шFdB:uBh֑ Ř tB1Tam$q W:R\PT(H"sF42ˑ Emh¿1W? ;ȃGݿ FS{H\Mp endstream endobj 1161 0 obj << /Length 1662 /Filter /FlateDecode >> stream xڽYoD*OBBB\ CI@;cNxw׻3rDr+Q~{46J/'LϒRӉʦWi]O'|9_Oj_ϯI'!O~{YgL mYWI^G <,$$*VLN'u4DBeMtRt zKTwo@^`閨O?]^"l+Lk&^&,.lz~ ~ NU2AOg96rب_1Ҋ4-묥}n3mAӤ?ӨtLosnAͬ4&=, uN;*ɋ$ۯNЂKg$ "9iFԎ"7ӍFٽvp<_[tzD{-"Ueut:e ]>kvG>ۼ`K9χ 2hyf)Ty˰!9~T=Ƭ>h#>C̫hv ~^/+xxgHjOjkEPl]vRc6PU&'- U4fs>.,> +Hɢ28[n@%42!.@Kk(x"Gзqy"W"=DH}3mjٛy^P4GnmaHc#ކŊ)f1NX uv-G]DUv*P sd4rG_=^gѥʚoawufR? F`C`y6ǹ(G8 _'Yd֍^c<3],X2 񶲋am$`!2:Z8ŰEZ#ڽ sɎ/NCDUe7sha\l tɠ"r02tݰ*/Z iƌh5rPC-ڃˇBՋKl-Fzc4S2*ޔDQU/"enfjdy؃L96Gx\GM̳nXԮ[_VZ-n p?; Qcg gFՈxT <ڣf:;<~`{ 3('vBTF=[ȾK8$IJTcLXgU[ 1>X΋umDLvC'?rou;uct/BWZ7\V *@@t#_B6Qd:_ʪhD8ZG+i%޶+pOPǨ#M;FU5e}vS\]G|RSgDMPA8JA:6e~U!|V#/e,Ӿ#Y7 -nWua(;LsK4JZi1$.AZ(r x<_iYgce7{+IjZ֕ݢGtNqZ߱á{^D rD).3Uf<&omտK]* endstream endobj 1215 0 obj << /Length1 1751 /Length2 12141 /Length3 0 /Length 13253 /Filter /FlateDecode >> stream xڍP 4N 4!Hwww.Asg~_^uUY{"S`3w0J;ػ21$uX̬TT W[T@g=,$&2IwC%{- `ge3?@dPb;]$AVy{КxtAf&%W+{F3[?!h\]YX<<X}2|0s{[l1*_V;x|L\66nN}eTWu(go/&oeyhV.V/K#ߊlmGob}\wC}C? -`kur&"foi5\A@sU]xn :xpLlGsf6{TWSJٛ9{}7qv6Bxo;/90;,(78!H,R#?7hcޣb/` ,nҿg|O|d/^{f gvr۾?R/_?err{.W³ <>37g{( 4CXw0 x#`IcYr 6:#p^,qmuGNt礵k[Zq^;$DX1<䀘gV.y'7^g;7kHۥ0iY4ϙ h{#ngUQПT'-CфCjK- m<ڽj.ХIuz(%xMܜ IU2Y:]AJ>9MpsY4@{ NQx za탻Rw\⥚Sv|I: d3 v{ᓨMk wy^(] KIE>%Z2O缈0yyV~&iҰ^-b4/ vSBٱ1mm `[nE=!G>Ofw ipZ]'?k͊lD,GR&YֱX&²󜑘OӦ(ZS$XgohE{JL6!pҧ\_2M+ǖ 765Y+-E(blOˉ{-!<ݡ?%O!b2j=WPӔW|3T?D^kŷg5bgqyx²\Rh@᳖T8`KR)-D˖bv7Mqd"wQ%{*Lx4mmM:<ɍ76qlRQ\?=Wk }ϸ7lgL3nTZ,eyT!>yM/U.JjL}4aJu< IzPğ|[;QOk"%#o,bOG:w?$d},p]:\"B6gXw3za_H|ͫ.3G<IT$DZ(lm_-GiU#7FѻtYyb+BXe61B%ӻ;eO S; RޠmDl9dbT 7TfҨ@7Īn[Yȑ6q桜yi.ڄ76yds?Gv|oCwFhnϖ(̃O8HFbBhȆ'oKaV=}xph1݂uX@{A" rі^ Y w֡Vċ|9y~(]eKa/T-l՚c@ikۻ(xqKDYt:8Hfwt=T[z@ʦ! z-"k8LY@ͽ»wƒgT=/dRo1-Z˽ŧuڂ*x+ަЬ;?4k|:e/b"w1mŇ_8#BݿBqZjLi4^Sgxwp:VPB KU|!6(y_}ZarQewHhVUV^d;6?5~T|C|Դap2!8 IEKQL* tZ2urfNsZ o;D->8OCUbBBw]O{vw k!>,Sހ)]TҚ  ͔!R54ޅoif ,2UK|/l:yxoIA0M@QWp}Fth{aj}q鯝댊TvZD zR{-]6e~~OkH>[DT]uMܯpdTZXVaօڠbFVfw<иqchן?BXZՉ*zKҥ !L9$Nbẏ-щ_t.[~>H99-%rOlvMIf7 tOTc5dr^]FKԶ(n9oo*KA5Q?dv_qmFMޔS:]VZ7Q:焥#Ծ[f@Ʀ2 (oAL Jcv= FtCv1x5x0&4K\o}`$|&bXQ`ƅ1"TfE˕&9j5jyԗzF5-_J\fxzc#X3|Xyߦ;CLn{8C /7$'fOl.D%=Pg̑_#H[+"x#8XkSb(]u,+}Fݿ,!I8k<<\nr,E5j#$.զ^w1 TVyp\:LąUM;6LA8Nx&UI§^hg/FLgK~)~s7:rl`B!pbr =H y2ژ:0BhKD9I(Q$NF!'й }6c$Es4fMU\鰄:aE˦pʘlj V)W7g)!2"1.Ro+Nu`# "QyR&,FD;ڔn g7h5d4S+ -A>QC3LTGI)cexҾ pĩsm!ۜ\_ ֒8uMQ9 5xI5~<<C) p" ٴ4yǚLo'ZT0`9kv+y`N!sb'{Ma:n "ُ. s;~_n%X>ǡr 4kPFkDsZPjb)L_!pٜ>" ̮o͔WF9Œ2W Ӳdp۰;q5*XQS #S4*,; vZzSO֦xb 7fM0?!(Уk-F:I Bt+(,R.ITFܲ*M&rг*~>]l󛁬?R${eiY..è:%7>>Aʹ eס<[T,Sa? grkT8=M<@gMRl 7A6rz2)H;*.I\yP%ę/vŏ^oQȺ8*`NLO GSu{@Dp>KJoޞpa;>E/p`: R:Ifyyj N{)Qd8 TcuoB8Q7:M/{;8ӍUMtɑ8O:^~x޽5CYQyt!Xdz+s f=Ǵ{yxC1x̙G8C`!z!Uy)~|Sgh1*'͢#mzR02_j&~ӈ`V(˦q1'󊿘+rS;lJ9snۉ@˧ȶUPQ~DpeCyzR-6ҽyoz)1<T.$"T8^=e:JK5~cOc?3-K-,_l 4aWp9Lm]׶*ے,e&]?Jud2}U9u (4eW(z A<;h4>ZUJM=):HMXjז ߕ+m9I<CD)=̪u6~Hz =oi AqߡPe0_ACj;"CO80lЀ X,[,C uwng XPx[낍iīEoɒp_Sq@a[H0qW(R驫;H!}>X"o?̠AC H>t4)ހ"?bH\mass֫Ѡxunf3E}Ibp=:\ރn ۳Eψť!LOPk6}- nJW=(Ds@+奦q6~0ewpR tq3_rƓJc%S?uhzz2nкEׂ @ ,Ѷt咰_Χ#5@mnM2J9q2'X/]713nu 1U $%Fdx7[\byWNXD:*H*]5.- sXC«dFtd|r- dbW6LV2-c 'ùHֱ4.+:X0߾XRXI1Dz2:\lo翙N=pk27zgWL,YMޜvu%+Arf7ٯ&C3Ī/u h a#oJߢX'DJ^CzǷBJl-&~caM&@t9՚_tn,yvpt[ߌ #ң2*kzi"S-)R}FMшV-o ވ!w,'1h¬8X$ `CegH06Uz)Es#CY*OgB şOhsgq U19-v>y<{A.Vmv)99l/ Ro.69w״%?*<{Vv1Ϭ"ȈdF655!rl:&K:1vR?s(!nγ`Nh" =7J`'JJֺA# y+Hh9%PL`ش ")_= !,yk_99 Hae\Sō,X9l._ʋͱ1M7>˫`&EtV,-$2ITډ, +s|n:GIQ'4<כݒRi\r{8piyީ׾avۮ"}34tH!x pVD-C #%2ݡ[*ʈ-smAYEYƴY=( ca-gVLe+&KIh9PPVnՠVCtXH,*|_A!v;?)Ӱ|43+ Ȃؐ+xM34 i,w0*CI[LeP [)<~wݜ;Wfu $*JQ0*L8lK[Cnr֡y3qg -Vv܆/(Źrʛ)i#~꽔5{x} 0ohK=?C8AHSZ;>|JUB %SqK_D9}5^=BNW.^4kzʁ.S]+Ѓl+/B׺͕XTzeX-Ng%9gt+k5 O lz ,V Ev $1RaYvJfYnp ]##eT~zIdjdgCѿCR\щ;{z]r~4,>M\iJUD ఇmjY2" w}*\ (l֩l57}b۲o|ݧgP0b}t]SUcb֗WmodQ+dw2%p6p<lzg-Ķ*nw-^;hg wm,E _ Yj*Iu(g6jEdj$C9˸.N(0ge+6^k&-sI knxsWZ?y6G9 zn% --^W**;n;,Ͽ٦|ǖ 3&#1)83 n[,~8ouK*JRq]LߨTO Rfޠ#-&S:]Hqt3- ljrud=h߬41!hC} 5 nwxf! J<~`q/!:<CT5ilD{˷v칼H1KU?'1&y#$NS۫D}>DM[\}:K~S|.7yy0f.\Q-N$׭1HyNa%/HSguK*>j̎wAHs`̆S?pM2MY|H9uu׊F [D务1w=b5U;iC cAQ3egz }ڼ"4 0=vJPDιmH s:'Z\Z>6Yos0r 4/9i'S)ƭK.tܰڳu9l8ܘvQ*Ll`]jA{ipѺ_>5tEOWZ)GIZM|D 0y ý23\ !Pc/{|jml#"?|˱1GE#z؞ϑ #zqSx̷պkӰ|B@aBhBؔI1nDpֆEjppL4}aHD=PTq16g|CGx#-vŏ1W R~~ϏC!j2o+,y"EW;\a|rL5:eUa۪(&3\idCW=r]* ᯹ų18ӻn۱,HzXf_ZDP,^7^%l)rz ) ,'l׋*7!xJk^ Q?R`]YvcVp&E"L`k{$s{'bLox#'=_dax0IDoX ۄl_)iOpX c:f5-\I¡H ڷfV 1e4pp:Tk-EPJbbDFQZc#Rf,܆d"<7Q֗we4_Y1c l^O[LT[-V s~j*}5aiAO)?%OJ +u])բvNsT .=Md?V{oŠd9gE[ʷ k{E2$'|*%ů[#4ɤ5͝#8$Dt CkpUUA[in>{ YVt=k4HJ5RFHU&(k/@9zf !;do>Mt½dAP4_%&NюaMwRA,[[{`í~w,V_[β盈@迒 8,N:EKEh_ $bS`HZN%xe u+XT8:dj, f$٠U96lJVؽ|şU> +O>qe^^ #^'V|pv6^,볪N.UlX'iG`WW_=tX{㕛,!hDZVW%S"7| DxEdZ>|rWL Nhw.|_΅Zv8Ԃ7)b^i3Q׶4,H=/4ɢs*mzwzء>z$6*gci{W>%B]yFIV<6s'VM(woݠ e5ė& VJs)UhOfLh*`~|Z;$ױ9{iD*<ptET^)Y7rг^Mt)Ec<) EoqdLnڅƒiQ*rL!D!o]GiA~PIUx[1~*6_ʪ ޔJ/oNukO*_bf/+2~MjA7U7}p֍^ O*[XoȀ;NHDcn[[%;h%N2\џFji|5&c|8,xZu'[x~>i>w|?\7c&B浡7DnCu_2/; Arb~ݷ邉!'Yhqk]ĀW8H{_~)$2PWNcq޽dke=wT=s*hݗJ!?NsiՆs+ 8=\H;ӂàMܡ+0bFutSN %52v=òC9UlX<]NЖBǛuϏ^yR_X}n55&6*7-CQok? ~sjo:^@|jmK- ^P |#}vjױ#7BW^AD5yV%E\ŀvSʇߜqTTb{\P=͐!rĸp^/>݉j=ū Rn'VTehpBif!~zXV7 >cyA?pk 7t&2T]h2]u&a`G[KH4-}&wChk,zPMf??5έpbAQ( N*.ıDB">3c4a"EUl/a!uNbN EXA>Mc endstream endobj 1217 0 obj << /Length1 2148 /Length2 14559 /Length3 0 /Length 15844 /Filter /FlateDecode >> stream xڍP #= <;K Aܝ݃;s+Y-ݽDAAT֙ "+`bbedbbP9[OfGM=P b `f0s0s01Xh5tdRvN"v s : 60sss1ud -Lm+ZACAgl1819 @%S'SGWS_r6OP9ˡlgfh x7XMmS\lMLʒ2y{S+K쿈@'zlf kS 3=@Ck'|CWC{G7 ) [#ى dF_4m51uv| GS{}Vvn^Af [dUmA.y7:ؙ89Swc _T~M}Ll=}@I%5y%yKSX ``ag03r8ٙ>GVCпOQ/O׆@guؙ??/)f/'wO vbCMv&'l!Bm#Injr6ɭA vN3~WLWKۙ{,CGGCxcagx1/߳ 29QP/ӿ'(q7(_ JACsA;)_΢*;WP/~`_^}Dzn5Wzlpu@wkf_'/v.1|?şkxD@-|Wk.d~=}Wk{Ooތf.CY C {#'Os ?. \w?X <7]2vqt|{_LMMy-W 1OS쪧0x-:<"$T~\wJF]DuT ֜407w,TAӞZdxE Bƽ[{ͯй]ŽJi)h/:3F?fqI`i/Qfnn3߈}NY6Xbf=WTX:p oG&)p潊 bB ̈P تI:J7qDJP'Cc(3qѳj8 ^s_=g; Y9*||C-~v<ϱwߧlg./Cwv>**`dC$}oVѓҖ#Ro=rAKz|{!6Tv]LJM'c,yl? K?E(Ti'!l.8R& h0/9" 1Ngvx*ФRdYg=pYqS2Qs #WR3D|)*x'uxerXɈ[Ad Z]9ut)nokvz&t6EզtںYѐf/QeCJc<̔=6:6F{ ]cn\hd],cfDf }p:;gwM&іNY3_9h-T)65֔TJK+.8:.`0PR&T,65h6 IL1܇7_إӘNpH^`!=o]fAH|coA)/xE\ACJ}:(Ec9z:Ҟ/0H&HVk(9.}{hC1Ӯown`/&j1T&wUΨ/I'U"4g_0cŗ<SrC}9\CL7\&cjʼn>)u ־-lܺan]`í\g?LEvv*h k.EIe`ݱB&'w&oq}w8 }^h#Č[_@V<\ja/#>f-BN  Oo^@//ndLL`0o,q6i`I'׿JFcFmlLE'ӊ9  \-:5JƔ7,jdc6'H^m!$c Mji~_鷾y)Do1Ie<I1V|.`YռIsu[H`$t{j\,K߃Piت5Ý}ڱJZ|Y"kn)mĿ0,:>?|QmN<ɉ!Ųؼ0Bz= p-EP{u 6 %fT ?D\UsN(Kv&HjR*L?IӪCET:djKG0" ˽2(K+.wZfYIBQ>B*s.z8~'ؒ 1PF̜M7)"@tKp`%bǿV>&;E$4L$<0A!׶/Y>m.QFAj}a8F ]0k U~GIq6l uCR$Гg;RrH%Yto7={_{ cTX{"c,_Nʙ!>yvr!򺼌r5(JHȚ$M{ g"CTGM…btGkBgv$EW,Z}l|=Z_ۦrY|'z.\NC>oIz@u^Bث2FEi/EQuV;|ӣ%t$|P0)'2oFedP2 FZSw>o482 f,([jZոJZӷ6G/.JM_T6~~>F\ dHyxrtô5a;l,6q KW*s"!w%EیT%:?12 "䂍$ڡd m 9xC%*SegM٩bt/j:F?8V ($P1@7B+ZcWۧJ[ʎ$ʚbHo"~&+W)$2H\ЦpR_!>tN!drp~J s/ P3(YR1a"QN*jrcfո;F,pAq "ZxO#ju5Y:া~3z ono%m2g؎a_?ro6PJaE'8wUWuezHEMe>LQ& E8ZRրkC 21RH ʽwz)ؗU>;mہok1ǰsA\GdVDD̂cd#T"*qތ˵/Zj@h8A:/U֞y&= 95åK'W@dEvLAFfHrM604蒏eLXY!|V)10ܞ%uoqa/rV0fo o+IRk IqH0)ј RCO0[C+[W?kWB6+~ֻOyAtR8 @>DORǜ/^4 NbxdnKde~ӗm]p`]yJ-ҬZ 5{8DϠ,AFZG7ݦ| չ[:K705ZM >k8"iPlПyt.HäęL OF2$FʬR{æֽ2J5,'  bUg>X 9ѡE>9g)q@Do\=9DQ{)ΊlE#볰\4)j5`ab"$D~o'?jlu#>uOlk:5KÒuat^GFD Jۼv4Ē7]akW=+k(+4`~3WZmK ɜLatZ_O%4ĠLppg6d5]݈i%Vs0k%j_Y ?8 ;*VC89l!7Hͦ嫍Mu ,X#˖maLВqvIO@/cE>&C ێ5$l-/q7-_rN;dS8^ ɴeS0OI9K_t/!0) r(O9e)UBKDuq}iT&|' b}|({\Hai4 -  P~SD3Cm͹B3 qp|>&y~ْg#*j\l7Z}kwܫٽMyu妨M)5ǡi-$ BQZMJ{ܷҨ<y$%p"o: r)jB7m[I>m_escbrEȡ8JcG$<2͓ӣ,ty{c*#EA3Q(/Pu'#<#B& qgC~AH ^#f E<ׂ707Am3>V)=V ͉sK/ 0=CX ?oovB&}1!=C堾ca8N`D|V7!-(s&TQ=kt%cC2,ֱm G5ʤCLOE4x/b e{xc-{CUo_`0|iFi%!R6 ep:Yy 8Eb}5Rڕ$vzu#ELkIh\֡=vpSK5'O ~EVeS\MÂ]jPZs-ȷ_=n̨T-ǁ#{JT>@rYSc//fmoO/IL40ob4|왪dZ[+cp@슂Τ>kAnQ`)B빍ExSɱDN#.nO]J4.Ybsjhg!FSqH =IH}EbHj|?J 5hfw!`T+fD)NhPP[rmzISՀs.r%^H%Ц)u_nՓ0BR?.֩%qHfC[k; K,rmۦ(}VS\< ~+pM>'kv7Fjwɚ+FLԹ񬮒 #S66pI޼GF&, W/SH}D݃+72)$o۞$B^`rr!)OlAoxyFfv SI%:l(mI*@;rU:ݟA2Bsݮx=J[YYN 娭ȭKGp̋_(#Hu1*8Mq^;)A")a!-n^5Gu)U7 RGnVvV^ȅ*pu88{(*Q sicؙM4bo <o[vl8I{̼j.X.q*tcZVZ|tlpeC&5"V]sp,d]n3ymo$]9R=wsvOxF`W[&Yߕã ǯ=&j]4D#qPuoyф]aW0Yl⭮E-pWڞ\[zC@O.>.]L``-`.sEIRL 5`3T:{)[me`kM3j(3 eH6} :EBYόK`3d1;}${809# t׍Mh= :-x,R88M3A9ZA@s\"6{3eI6srWh"U" f5ϑTJY&Bׄ;gȪ#/BQQ}:}.T'!ř7R"yU{>|TOtd^K s. m͞my!QߏYywFu_!KxNncB a_ф ^_}Ty\K9*^`=pno4Z/n#-S49)/u<8~!r̒^Ū{n#W̺l3;L꼺-`׮Kz֕ K#\yZ  fu9VtD#b^*ggxJếrAs4UDر/9ed2 nm|(\}F('OW?vmL<ێ7dϋE27G`dv4 .Ķkrs{ПٯgW݋G:[Fb=n˜'q9ls tpJ hE-tL':bغaO]H4>1Zจ G/>&Xɒ7s],ݾj)"̞j1ox%BY)?_ŋM#1O0gB>xnKG~ wcs Aӌq~DH2C^LwjE-W%y؋B%Vu$'1ni`8"[]jCC3Vbٱs^ȵߧ~M 2*\ 帏 yUCޠc@9ph)xN/~nVr}c4j$eϴϷ~?.^d헖)2SK0%6!L+Ws:$纫dlR&"u(y|ؕzC:K)ߧpώ P ͆ݨ2K"pR =3ƺ#p#FzF3|#z'.hp=^06]xDRdnӼsċ4ǜl(ý="v/GlE׶ Bʙ #C!Z>m@+\ ]K Duf5Ųrرu_l`lUfƌB!ڛ/,J~r蔷m-ys|Pye9só>P+K[ ?>z8!c)4jvG[0%c,+4ajIL(׃j" (c"f*$>\OXdxLEhX_ZfroApsAG燡7]huoQhz]6l6QnkD "ʓ@ϸ_@[qQ%b$ɟ6Vv4 8S"(XI" 8+2$I-E5@kVlH#Y,x?A3`DA@F:}Fl`]+l=!E|4C=pMM7hߤY:0Ⱥ,s z)8Kr#TK0T&YR⇕ KTȸP42]Vɧ`ۘӲOmg,kܟ6IM0[N.ߨE2Dnu V]ڶXGLV7M*b"=+O4M>*/מ+DKyoж49}'Z~Ct_8NVs(|nőDkh`ue)n'T/V*AKl']e ɳ:51t ɑxė0PfxN!^jQ1'@gU$lj,Ys&O%F2;Ɯ|H% z; =, 䬞V=|/;?@XMI:I__7"r؇eL'PQr66t8!̻ TJX{63YBc҉$;#'kPzbwr+DcgR 禝͵l޴? ԇ@qt4aHvn8_8B,5c~>>"q8xQY+#P!'mJјQÒpa HF.-,tܖy6kveUiw|vGpqhc;E>lGRtd*p8JG u0 %K?0[ vX% R(ɜ}^|Ź,D+Gp~pА/؁g? &+{T:dٳ3˖wje:R|hϔAσϖN\*?P/ԗ;Cy=mn(*2<ѧ}ZcӼ‡\8зZД}YX<,?v~x^rf3{.TH(]uUQkŶ N!\Dz6ሥko e9;Y-z'B XBzxydXΤ*UbQ ?YJ:*Wg\TܤMRn[0a1W*_j.{.7$}9W\6A&Kv/­t++bXS-V貄gJ3!,aGJ^eF^'2keN*#E5Υn#Ofy}a%V{tb'p.P8230~ ^͝1On잫|t\Gfqo sHu(34mJ{HS +yƊD);6G޺cS+)uq΂e /[Я]a< 0ȕ 7MQA䉪~*?RE1$L&?NavڞY_eڲY,L}mŔsp`fFڞƬ nUFGFRsoSmL QSw.\L?.V'Rs7VǤ?)͡q#ewY4\ w8]ţ;Rщtj?W1)V+֙$^Z}[y#wBTG+&PK5ޖ.0w 8^{ zbo] N=U?x澿Dk#Wـ+gۣ. S<&!,r7~^_SދDຫujFhpOՑfI#.,ܨCC@h;qUH-؍Nfoc%69eVD3`9+h \@<j҅\cmsI fbmڑXJA,ItG!ud[fkl6ή4vAو<]6-߽O-` 9p=/$T#^^Uf.\1bܨ# KTqZ[7 jô4}y?gF^vmp$" F0l D 9LJdMw׃Bt $3[ P 1Šor(3uj%,!XQ+䪽_!PlǪƤiBF$(-@`[>0jCT(# 26~aLXAjfuƇԫF#Uӫ%mr N'?'p$tA"TfvRj))(ÍuXЬՋ&Frqx;;1ANs9wȏh ^ ;p7*g v*kIjz:wT<",ʳ`2'=E]<*5Ʉ n̴aD!]R<$1Ô 7MRAI/RX2 ^+uX{S /+WCl 3,ݼ Z˝(LA+jKnj1 {3u9i]W`NJݩyf1؈ij[Qm DIKŒ LhK41R_EOݻ)7/@0 e =r4˭Ѽ:IlHYyfnf o,'oZT_l'{kkl^ W]m5U}#+Kbs!7?i5gQ>QX N3a2Lew8߾s&vq#s"X=^5x y::տ˕"ޜ׼ ?-&SQve=7lcǟ@j%fh2VIK!eaᰯuwwsɑ3z"X[Da lٲJSXDyD9ۋ&'`qA~qm%gBh mS8*%yfۚ/tT̀;oZ!JneָY+bGWhG38s/oe2Mʨ=.+Cw}[Q)fS*\Kxj4(ko<`v<(c8H?›Lb'f{Dx x'Oۏ$t`rP6UfnNKU9·\Rw]JJ\;ā1u8-@Ntj< DX\ާ }v\QE;t5ɬ?<5\B[W9m PE=w4TYd6KW5du Bp2 *T4)V8^gHH3DoU%{X;Ne^{mcg|2GROEzU0)cҌi꾌ߺrx 4 >B?mARG\WX(@IpZ}06\gj^09=pOCr탖`]V3n*?(O!$и72YܷlRjȝWNpߛh9}u D5X!*e=-lV*U[_έ}|7ZO䌮֙ɀk߾ӫ$#8૗ T;jt(\0/.Y̔_2m8;jF}*2 :*YD5w<5ț}*O37bPDPY| eϝۓ\OSBrKH&XH _6RuጝJ@Oz.,'0ZkY!"tOpjк+Ԓf#(lvJhcZޅjes@XZ1^Im8!yq>r>8T;T:,ɻqvowO|UF2"xorue5'pӟ}" -&a00<89>L8J Lʷ=h{cKRh{T&3eJ`$OoMnIDf[|Ėo 点J:}iQ8tvs."sD]dHw]+P49 AQr.oqpdI( 5393\YA_TQ6le0R 5M'1 *1`Mnk +_Yen[XyL|R5MnW y3θ"?P˽HW[ a`;f`V5w"m1aLkz e{] 8昘 |—#G%W>+kqݍSyϚ:6lrd#pEתtOFz*lNܭn0oB\+b7LPkm;J,vT x3oOȪ'<O_8[^ddeQ*^("3ɫv틛:c(T SKL&`s7+-K!U +Ƭi !%i4]ϚRsȁ%br3k2(l wRdiXtryiϬ%8nqu0 = ˔ jz/okvz:gm";F6u`oa$k[hr|:bK}0&+o z 5ۧsťOsg+ުpe[W٨SzD endstream endobj 1219 0 obj << /Length1 1557 /Length2 2918 /Length3 0 /Length 3894 /Filter /FlateDecode >> stream xڍT 8oif,3dߗAhcyf331()Dɖ,)E%-Z(JIYů]]s]3sss<#P(/8(˃,?(\‡m6>tep$ X,7%6P'6 !PlN8 BT-G$΅L Q),§L"`hH 4[՝:?9yu _]̆'4` Kp5 ߦ6>]1G b#‡Õ / ԍϥviP^G>^KVx;ٜ wﲶ,*6xCRXx@Js#`,6`B Eެ5Dfd0`>qGe9c9K0W ̄ hf"%Bgl6Yf1W1%dD:b^~QS2Iث2r^[:[}3-[릡`7q%ճn]Z1cn(Û612$.u|p$yitBb%ma=v%"#R$٢^Q?C㺅7']R%(* Jq=2r2o7ޙնt|aWBL%>S(;OsGOѮ|,Uʑ"9m!1]Otg5湧J^jdɫ Fu^H-7_RO7Աp9 NKD>*g&xr%d_=^fD'|+AgCӢFۧ峁ȥ M 6uhN|P0s:U}$ycJ&eLvt㎵g{1¸D S- ],NxAnu'SOޢw{C~28)`P6h4.[0/=CdUnכ E_=֙2ǎirpwE Taw*Z'c[ѭ:)lmt2Q>3c)uy9Pٗ^M$KO{խ(8)sژ ñj*ͯ0Lm4ʽ6ЩXn :^_-V-+'nA䦵 I6F~ϣ [{M< N8%2pGUޗ3}kI G96o.8 ת)+<^핬^ɜ5V~4-|hPz 2 rn/!?|&& 1I:^Q4sk$vqn)P5e?:Q@)ڬW ]DyQiα,۶6 ~jnE}IXe%5AѐQ;pu݂߭DQ7FG/Op:3m8|@ݣ9K/)eμ}z qVWfɅS$"j ֲ{;$z/j>8uZ"M]8P; |Es{e㜄#w}Ej/=V@5⎙Zz?S(5Xd &Gj>:lc0bqf-iJNuxQb+72bKTZ.EV6UC,oYN <r zHOi.{K[{wǀl1cϵ G>39|зU}υ<)A|DH);oȨ:]ҷիV οM>E=l<uHU&0ћ֑4Vs>S.sKQRZSsɾϬtk|}L;pn͎(dڡNtQ'ofӚ^9m5ZgCBEڳ$]I= =fsnq?dopyXgqoM6RT⯜>zt{ E!ωq23\G[dNw,w}M֡m5?Fl.lڮ,BA 67_\e*b̾G 鶺eqj5C%?Bc%VaڻJG,ܳemzy(Q8~6|%{=bDZ ]DMϺ鶝\d=P+mbl젺h>Q&beeœ**]>W{Ke<KPj~u\;% 6>wѶ$R~ endstream endobj 1221 0 obj << /Length1 1780 /Length2 10582 /Length3 0 /Length 11703 /Filter /FlateDecode >> stream xڍT6tHʐ݈ 5Htw4 Ҩ4HHws<5k1ϵ:, $lllltt _vt:-j'G#{I`OP;{;'GW @@ 1(v`'t:I#tο v~~mS@>h CM!``@V+B5;f-T@ZcEhXBvCa. G0`19=3;N+Tv+Y]߅ v%LM ;7b(\a ;߁ 'S><EW:?'SG=̉ bG2O,mg& 8M p.vB;3mjAރy2fx9` 7{_N<6^s 9{yo0&` ?;B\zlOcIafP;5b;ZSB `ppٸO^]7AaGEy;s(xu4F}4q>aނRUH潍_~?~-퟈'A=-2iE7TF+ m+=-œYعXٸCd `7b4ΰ؁@ _Ѳ>>Q|.D|a.*?o'*'*N@|bT?㉙_fhi-Ӏzɂ`SoPS֫Jq2Q!Ô+|CTXjnj9^vC ̥5n\,2[&1/M{\SiNx)P"M̢OUuϏxz"^Vʢ %"r~oaM&gį~FE&Q+ _ǹT .Rt*8mɥP*r w=Ld vJUN,Ov :y-#ܯ)%R63)D/zR!rKRX+*MLܽWL`x'PUGl2 o](q?C6_eȧff\y8n iL 2=GщwDzWZv9lG4*g.cCv̛ꅎhm.li pSXz7^X?.\ha% %ɔ0hi5G#Tir>}H#Ч˃eQ_ZЃ.iS/M- .b"Fl`N35ω,`ƫs"2QN | ZDUUf\Nh͏́+"ӑ첊bI[(]W _D\"aa(.Rjgfؽ; XG(=&SWI|{ra:ݗ; p>9A|Y{dTQr'jj8?6 Nx_=jɓT"09*S_||KTv8 L! GC-nL]rUg?tC]Hw8_39s{zQEjny sx)iUD̏ y:CN%BlD\tv~FV#:x˰ЦSR1Թ[K5 `o[7~XW!52  M2&ErDMv V ?1O>?6y\V)Ы]5Lt7&wUnPzd׼j}:F͙Z[~ $/)ɬAzD #)U>I8ZqJU:YQEUAc$wTPAl#VsU}% !H:WӈHhl Mu ֜H"6^e1'w+힏R;|['S'T 2aC#asJFԒi뛓zt~پu"S#6: #)oFn1k$QhQTo}n6 ~kJϚ`-ٔ1{[h$bLD11Mڪ,sIߺ"p*7Ar/QqS/<>kT%j)Ori+zL%yP$̶g9:5)xnU=p;g?9kb*ki_"emlW~p8sP.c]4n1I j%0b.t+*4**pU!VO[TR~y&C߈]vܷyBdDqVlkV%Jz,e {[EmIюH8;+%J_DoK}d2'G8ǝ%z53Tqe-2lIT߳Y4e'Yݶ(, _[2]T'>kڷ`4i)=ϑGG: |2US'[/7H~WϪ](v/_N[ 1_y|DtC^bs5~.VhhgM=gmX 3h RP2p7 h,>rmh蕋 A9~ DZ y@keB9d;cݬɦ6WlQy! Ds$QS7Ͼk| qjiKd"m_,s"n@mh\%S|xY{+M/5,h]A3s2|q*Kz.bMPcu5-П|卓yBm^}[SkvheD.`ג=A:y)m~_޾CV^؋MWdH>G*֤ta4}j?:(M0kN b!Čjbظ0Y;t/;߰۰z}teF`[1֦Yii-?\;D.}to3p,v>*n%PNڳ']cF`>3~H)(*}HN_|OˁF=͞nfN?Rq#Rs&_@4 KƺDNtDml]f\(XPQl˖-Z4|.C3'M1zzϷC $0u=\ێAuE`,Am#ɚe7j"R(\ j<-p@$tS\}}<)mXF#8:v85iȫ])q?cKy;z#¥_x)*Msn2zg՚f1,NL=SLN u¤pҡA~}AbQ\ϥmx$4 -yUp4>".2geCM1i?2ΒZnDe-C2aGRSW6y.U',d<~MaeW'!fɄJ&hdkPn2\C=~? >(5.̬ͩKb:5 L 0a K0 mU #.VUWZ8_xQW:$e|Fl5TߠgF!ڭ'Ɋ5w4]~;9k[8( h,JD"BQұn9gUr^Y nZF]b\~kB7q;hI ZfLASC/-q ^N-bJe1W_we)Ci,'4zO6f)`A,l:lg~e&qq@6%W<7qbaRr4[X["Nex;v~v}]|=%tFZzW$!C?K4m>jZf/, 4uo RI 1£ҕ]oDɻnr25scke"gEtt6:1PR b;dWO &feLEo=H & O{e~NM*HZF}p{e3'T,C1t⮦~F$h)l˜pH 8⻟?ר@ue&{XNi uWSBp^N'Gq텶CݐSr2E.ЕeNan. ѣ =6S@ʚ<FI^-a:9 ̼Y8q%rm71@$1.Ť q3>X૲v/uT|ͦꦼB1߯| {3EUfV_> ֽma^C %uʓvIj1ETM޻Oh~&vbnq8#ߤ1~5 S]_l\0W&ga Ώq;DZ_W!G#GYx&MgoŃ2ZX1B*+Fal`j̙?Q7CdGֆJLO)eq_fDEI\I􏈦${t.[j4s=XoZ8JFo.,p ʒ;گ}+LgTVq=&>6A\2쩳ܚER[6vo-xaBRt]doVUOy^ %GR0XV"S\,_i_fÔOs !~#jz "C\Y)wE7U AIk\jCNgٯoeڱKQ$}f}OHڐ#p0i^^E"=Yl,/[.R<&:Vc$/dHK1fq.\ei~|kDصg^EqD8|,nALIKx^ʖxlwtg} >ewE>]N&|+SrۮD3kox!2BlȊ}OK&g|j*4Wώul,:Pwnjf]0ɳ1od蝎%\qx$H]r+4sN{>60G= ]#ׄ\| NY r㾨'htm%ZV\[-KC3K_=F E NX@57X#\1Q7a]kSLs#1؟Vwy~*ctm=[BFtJwI~8hrl$h8cC~Ub!3qT%Q'wNB|C?df"hX4ÝlGQ=am.ξAg|}Dd( 9 -'߿ >&\8ћ'0>N\Ԗ]V@@[+T4Rؐӝn8E9*GvԷxʏY'7|\?0|tSFЃ\X/?[Q`EK-i#^@`=zN?!m+t "dUi]<vl=*!d%w 64AP6f7)]񪞷ǵ)Ȧ͗Y)ـl<:"zUEJjp ~ZgsabO~20BGZ`*&4f7'{_ddB7ʋq6t/MҔ[Ey}}i4իհ]GKi>{f/y :.rl }_2hɛ$1R_ Mͬhz\(߱<뮉eS嫐?n/DeG:dԳ'99NcYn"\, #P$llfmbӳ3mi 3uoW&G_ $&>| |e\nYi|.2Mtj;TSFC3_G5za}_)u7q?$Xޤ9#μ70Jz_j?MmeS۸tH w WjdĉZ uͷ X'ecфA~&Lj5~xutA}uci-i#0U d\ƙ1+=7F$0k=ցX}ofr[~Mv8=εI܍JJZݦ*L}Ģd_,C*su.ym.Sk~;+. ЂJ+a–$~L8Y\u7I+3;;[ԏѤR~4b+?qLiFVV q~߅"C!<Ţ<ꣷy7%e%CT.-_XPoy*NRc\z6d?~hGmJ5Ϡ ^XZWZ_NF#\Gٳ%TY [}f:Ƃ+N$UYzW`}lC۫ʩqNcQyֻ uo|v\*hW~XWWlj":Q"7or:MGm$@Ep$.%{3[p!T~Y8` endstream endobj 1223 0 obj << /Length1 2721 /Length2 23516 /Length3 0 /Length 25039 /Filter /FlateDecode >> stream xڌP\ !4N@p -xp-Xv;3M2{UUMmk9MA bh ttpc`ad)0Y((ԭ(4.֎M@2q7@`eef23х namP`::](]-@4 6pX8Lܬ F3;5?!ܜx<==M]],inVU+hU0@wepu+k׿jn&.@H`gmtpy;] r<@ z`ad7?޿Y;lbfhdm` $ݼ& M\A&&v& 27HL@S+ݯ~uY\ +?qkLO`a`nsw'& kgw?& o% :^fVL«{;R*urtX[[A|]M<7w"8hi;:H bc ߿ @e`2)J)hj+]:QQG//;3kɸ@_&$GD G5:kꬮݸ为8hcӔɲ E^E9) (5֪Q}ucK,T軉ueF.J5_lk7=6)<>fuZz|FFnCSFGwzJ,=Yh%"WWx3S!2(MB}?\>l23rCq]|jع9`fĩjڕG!qf(u^DODz, _=q6fx7|6yTBHo{3*/q*$'Q ㇍âA!<77G?nsEtt*IDA5%;U oERx.~/*ZR;[2X/í Ɗn`PCDYHIf1Ҭy'~O ַm|]~ { #: .da' jC::"e]Sa.cvq2<%JCpDPXF._D:m%@"P_qR!߭N!.秜o^Ry*C鑸5I$ p`uz?wӐD[h5;D៣MPEWf# fCB|AEa^u+傉㬃# Ԝ>Ob*E\$HP 'y tT8H6~ğE\~1s}znFQlccmmW1X.ާ+n/e~v9+;iedD>δ9w#t 10htiowfDmmJ$zF2mk0͢7+.drt+b=|97p.9#lIYtWpcKJewzP#EQ*1hTs(==T0$bouG`q(Y),Lk|nep)T'rҦ-FE~(/K2:y2ǭRldGcώv\sE}‰eI"-V/Cngyo;vY4E~>0'9ܓOPWuM`zno8md"ڟI`6 .&Ö {s~^^J";p]zR1dKܕ|Jإ{nyR|hUB @{cB[7wS*|n֚ )_5`^J}0N?~ӟdqݗeA,K)B&*ϴ_uƁ^.-RqeWmQA&6 ,,Wu1_zH{9?Gx#-ԍD]W΀:Î[lbXa%<,0 &6o"3d)5=H6h0o+H{ePZ4qPj+ָy%hX-XE_$c ;;䡦q&5Q~ +^{G^\[%>$c]GUn㌄-97M<}p51js1u+XhwbjbLB|Vajj-浏 !U+1*eoZӷssWX l Jn>Iީ>wj~Z6VFrX>h(@ xY ηUdRx PA?Xig=ҵQ*QL8D(jcS%qBQ{5=yy\4[2ωn+O8N˲=bRɰPR30EB!Z%+'Z>,9zZkRqV$SwyJ$}OX1sP5 ϊmr\5ti'z.EO::@EE0凟p'W/?f䂺琥uU'e6( v_3Ji);r&ptfWLz.]n199|ÂN?:WըH+'ٸ6t;ScB<ߧp4sն|ğ,]E^\?a^]:n@Ҧ}(uᘁa*=K"&Fm˨^h~)U9՜aZfb6Rߩ ]FHrĐwGQOhXNOV!vXW a}&$ܸsp+a8K$o`${ɁHs?L|KA|)amLbD/ŝ{tH.7ZO |+RD(:l?9ﶤIg*`X'N8xʝYd>_52AE6YR,TGrԫOrh %V%1Ġ nč9*W5$T5:l[ϡPRq*FL6!Ky$IgZ*ڭ0%cn2Uo1.\/:`V$ Bϡ/P2."l"6tP+zv.;O鸠_,Q-\$"3clYmO͖ª%˕hzZ$6)mCxE;xCP'۠pȗt5YuokLy~щx8?,dl{7vWQFѢ[O) ! gk]#Bm_ ?E&`?n*ZЭwg;Y*x3}erdc{dtZKym;İ+6Ao{tx~eaϔ<б>3UmQB `UC\6D[i鑯x*?۳{׽G[ eӐۯϏtK'%(Ì߷HHieWԸuj` mV )-"Uw~E[FNV#WSA [Oye(9;9/m)%?OOwY)RiR5rn=\yKT,^&v DK9TXײ2Uh|]y}<KikF.sT>yH-HHR烎$i!WmF}?{5M$ăK{] Q}Uey**Kmؔϋ#1o) El&<׳LB^\/VvAF{HN)I>zER*tH:EKSB꼧‹oԴ{֘+iXmjv[J7[Ů0.~V1Tf qUlYs  l靽MiEg8[QWOLF_vBPX0< >qZ#Ĉ\1 ?L>"&9ƲňdRaȵF(D\87'O_1gy7mȊZkV1í8e:"2 'AJqVLA?t/}\B>5GXٷ􊰝Pgl޼$d'[ `ȁK$fut G/ˆOqqpO* z=ڼPWn(6ޞ*~YU SM7ߟP}mдLkf SywHbHRէS_J'b.#o`jw<)ǎG;(ǀU5^-R.Eԏտyۘ9┴2Wv ѩήCBAhv9+J}H+-CdCN`߉ay\5||s\ (bF4UԝTUJ"o 8IRE WŚ(VC0Aѵh 굠l'ELgIK},'NRL&َsj@|\YMa{n,`~ JKm@um#(!:|&||^4,SKb!ar49yƹ>d(aBc;hen.B!TϴcŬ)gՃb:@Y_^~/i5RzRho_Cmwʥ\ȍ ǔﮉ:p5܈:1mڏ ?<]o@݇fHuEؓxt¨o 9Cf|Q7苝EkjG;MvU؂z6͌Wy}#.G/ Af`GtGÏF`o}HL.wŒN_>j̳.5.<E,d 5TwMO"wY%|JeXUɆyC~P$m$-pڙo5#zETm $Q,NxVUuBAvO!y0#(ݬCxZ|ÓLџ._PBE`Jj_Mqj~?"Ω~=B!D80cGIB}L&ءFh8#~%/(ҲFtc!4 f,h? ;.ewa"Z^t;%jXB1(D]Z-K kоaUFr([&?on4 4ÝBexHMI7ӘFVjP+ .j *5X݄51hu7.)ijZ@ঔǘ6sWv C-G"R֏i5>wt -L?dP%$/Kv/~Y(Kʛ&_FYBI ;XFfwe&P8NIi &?s;惲-'%<ҕm3lK:LUur-֣{kYC9QOHyRHM ?J/j>ݎyHp7,6㇒M0ΞB- r {rk~)RF:!1IxVUB ɭQ-Z&иWob9 ƈB/42E?)Hu |lx,>Ղn| ^ (xVBhk$np%>UrKfcUƂbM%^dѴZR)50Bpؖ 5X>HKi mpVp0}wSbf\?`O7Uk Bٹ8b>BFgXDTa0Q43`ajZ_~oZ9EgЁ\S>HJzϏԸ l(c%iM>Iub6n0X17enY!׫ v66u=\ 4AYg!< ("BJ^2Od&$'Ӳ)eޣϘgHȄq izU@,9gہ1I447qvN@[ 6iLx]3byRӫ |˶Yin2eruQYXxvf4؏Oc;Os Ivh,'2EiehSE^ìVxXuK˲7~=*c@l䦛^?PVhZVcYvdIQ;r@"lٵ0QmDeyҠMIj d`ԙo¦wn iEG=t߭xj㩧-qZJ?))[h{նmI?&Fh'(#zma"]pqR՝H^arsVO(Q٢+m#>ODǬlfSeHؒ駊g5(l)Ɍpi)}s<[^wJA, F1n_bxG\F$9. i`~0 [l_\i4]5%ҝC: $4t1v޵_^Y!&Z^8[Y\3F8ڶVH؀A1CVΙ =Ջ"=OϹqj|T!m06Ƭ/}?ಠE= sȏMi^lL{0\ '),IΙh"XX8dOv%2Mgy'"`kyՆ <^e\/~ v27t*?wҶU,F<ǔtߎ|^&vm}ھ*+@DTUm%5W$kf^ڭ䮎f~*ʰĨ^p-ce[D%[P'̲/-L jʯ  T+g 1U 1h?v"ZNː-)/01iVYU5Έ _Ӵ' |G!h6"uo5V]axsDSuoz:iƊb[Qޱ@3õdDOC7G%5"ObP(ИXoǛͦPnGvEcwG5p3C٨٪s++M|*"΍mlԔV!.A Qn$B ͐?YACМB\*{oڃ>3[;F\8$dN" +$m޲ZT]HuَC<Guͮ_4.c2i|qhѶ"!fAE 7c ځ y[&1}[x`+؋P.SdǥIɻ - 䖃]VDuksV4L4HNBLVe7ma.&r(EvĔ=k/v9ўs M<5EkK2bLJ[뒤c(9he&cxX+iJD;"<.[t=־(|ψ(ɤ:bw'R˷7iY|A&%>s= ;zO):{H/ɫ^CX1cL4Tp`l摥.m2svG o[/i ىےZlW=hc)̟7s.r00~JK]~ _>#(]: ysN>#-K]VMd-UGqQt"MzOA EfsnI~a߰Bޟ}8d1/[>2uQAN嬞AwEܩe;ϴwq0BvKNK5&ҧj-l ’1;[eΪߏs6(8G<ގbYWST8*>Ӕ&˜:g! pknNq/v> TX|PAe+&wx\6r+qwR{(P 2K3k r/r^>>ߘVP>x_>wB/s3j\*A7yt̬i_wgi!' @/ɴ>FtgLu,Ou}zWxP̓7YR"⟈Y vM]#]bjTC5dO*ĭm &cAue#߫S߶ҽ(!bs$߄vbqr;} RFt3r<]Ԥ侪.!ʎ nothOmbiE;M1n>XX,Nh@kIb#_&hkVRIT8~G R@Uu^(f%||Ȍq69KB#nԺQ-PD;ޚ8jlςB7Z|%M>ZtNM6$߸ͣlD+Ws{zi65Qh 2nGwH&dDH<4ҵkI?}o)t]j釡sC Ի5XȾ֢%43lk_%}! >N /ݹij}߸Pŵ|D'?v8q ! ]ttaa܀o%צbPjjӐ\> +>rǐT5jpLRe}_Y S;3C:%}0qUjgc Ǯ\隠=m;o]wQwui0aJU-,Y絪f Sdr^4\,MyaVg:'X"s+ߘRT~Z'r)3! j^6}ޖWDɃҮR}pNpS 675{t$eb3 <0Pca+]tk .Q?k=p-ua$HQ_mU}oWP'(X=::}>9^oZ/!-nZ| V; ;<%E l>3.Ldž\>p;f7~Eu;- <p|6{OE8/h T+U, cG#[Pt0ŌsQ ;{fVu!%S:X m96hf&m >BnoXIP0$=Bqթ*+kl~kob#_7xՙ"v#KhrkvА}Ă BJp:LEZ?n6c*ZD1gJǢ^=kM2p$d) c& ;ыg$VS]aX. %hofi{֢gd1;%#=;J֯inGnc7՘(^ ^?!a.F`-YD":'Bʹ1%FsԉfM&zw߂љy%0(y% cnMZ7X,\?/2T9ue98u@,CIdbKV!plo?ؑ1t~ϹQ$%?5?| fD@8 h5$.nlXh<1gEAu\T9xVIa=$˃U Yp77\߶?;-'bO4Ub(8o ZGyMܭ IItÿA˚&o1rbLdbA:IẑTZ"S3%X"5$Jsn;O݀hd\⦂[J .LIYt`tWcm!cI>a}ƫP~xk)P.t-W̖!1-B g^v)vd/5F6©7Y#xT!sL)=y3}wnR'IXitjf>z\ aObl&q`Se㹖>b%z Ot-𿖸3%IMAkBG1fD"-Z7CZ}}qr;ѐn*E?K lZ'`;%`f~rS@DX0.6TgP#ó}|W~;ΩcQɏVZE%Zi?f D8LٲwLnRm(kJTB̧ fc(tseyCA5^39ho%{fNpnez{mc u}Qh(c uѫ҃<))4F,8=r9>b[nWk]f ٌJKh(3~s?z?V mN(l|֐'"}ӦbZtѥh!0{Wi`6r.Uo}?/@J@ܾMW{Vyx`F[$&FWH^ǡ}) ᔪKjGѪjR{lз0`ە5}JBP,L-kk YVqHI?Tla B/|jH! Qa1/*}[pWGbu7Ir4_(JohJмWpZ~N0%lZjŏ̈-QN!+=f!o+=]&0ᒫq܎A{h1懲"fua w ]u)N`dZj,8hana{vi[ dc~~}qùy܉sL\zP.OM;é!~[ƾ=즐C@^F=FF'! ; cNbae@u mj;txCפIV (]M``7i#(CaX™h-K :TANvʗcS[Qq8 iw +8$-B]2kY΄ VŔ-l&<C*G'EF^u6#$k)IkѡdW̷bf!57qxDhCdGC+kKo0_č[Hj\C,ҌtH>M]S,PJ\ҫUvD&q|H/hm!o?؇]<nVTXqWfv7ogs OV'RY!Fq㦀513!.TE5LRllMAm,#mQMID^@y5$aNԣ mcQ/ "ip %*uˌÈ|<){JŕK#?f%d4ᦄԞu q)=jrw 'c}Lv%SR3 S9)܃:7żh_/`%K|; \f/8D3E#i%d9Xi Jd_4(ł̀({l`2/V\:;cW쪿~Nhf_O;nD' Pr*9ՀAYg TjoӤ|w)+0"ߋЛZ>\[WؠN*Ȓ\pz=@Rv[54Ճ,I0"RH1wcOץ~i];S[[|g{:^л!"TWʵЉIo^>D6Phj8Z>@JEYA`/m7,7Y@o[2,SXļMXcK vek-Uy C_yI9qJJaW7Smq6֬Na V0P\R,mr4t"VǨM{8[ELrbg–T:zk^ƐfjiԎ I)Ďpg~ V#9c(X{BG>;lE S 7ڲVJ[ʼn $JPC<&{B6 K{q{;hGK"NJ*~W^OۅP%v6%rT i)n8'jF9# `f'%Oj]tk0V 2"d-k;*;c }fF3_J꡿oc3Ow{1^xxeo'Dأ '>ǡчw3x9dcmT*Y, #;(l*`.L8K~[y@;А}ښ/FD*rq5h,#7.-i6 2}Ks*fJ$|V{:,?iHe`B mJŎL1،qL*LٻC1T,/1FU*]mCkԉة:'A>b97LFޱ7d3~rrоTbݫb!H>MȂxaDXcSzg'Xj3#͹>Ŀ-ʃec_}X(5[W٣LNbJ˳ :hmHX Fv3ݯ,f1&m3MGyNiGޑf`{f|mLٶ"H|/Ȩ *I 'c$wY-qaƟɒvzDڅJ \n( t3MkfFOB#=`s4G턹bb"ƪ\D-C(mV1$f%|\b9=XVl|z' n>  sT$LgIrN| b8X2 3 bA6)d$[ Q~+i2@,x c0t԰C)ZR%av @N~x¥ ghQlfz~ʤB[H^cnʄJmqyi? z!G^[w|4~\l ~uS%K)'u bsԾ,h,|p=V>vc1ڎM*LZ'\cq ` fEcgȮ3A%)Ԏ j?br&P VV~ Lj}`qT&~.C]!vO JP"fiH@:A"=lH Gų5( OeT + Y2OO|*Va-ڮ5PI2$& 6< KqgȪBǩ۾ <\0882))'êDvvnL"):?M&Ÿĸj}@>ޏL%rvn(U0IC !wƯKlP'~qOp^H4 Q72Jx0۪$b5~^JO,g]=:yc`* &|0' J3{! ۲1v$zuǃLSevQ"AkY:W׼8yDSo,v:6/-Vσ4|?I2^Ǚy7٪roig"Y 'fL؈+wt+?I( z0zhlZVl5óӘӻ d<UقBH߷l2 X!vUzL5ppB@>u_薪ufNupܥ0Nk.Bc{=~e@lHOS _!ъ7S\qbiSz 6(.|F Ix3Q)g@p@0ahVTƮ( 0p83 }ql.ME"0 ?IIӱW9Vy,2x]D\P=(G^Orr>׿#ﳹ8y< PNVj_ s'NC' XL em|Y,Wz:gԯRԉi [M B-&v!^Q0lB(fq@R혋'ҙ`~Xa1Yc +]DבP٥Y 8訰'$%6-G%{l*܄Ds6+8Uy(w8 Vh+|g AXkNNŸP^L `-sv ZCO u(0PkarC' .2dFO& b+ f,#( y&#(]Q'飆 @*/EC/2/aV{ǖ> [Q+ jܽꃭ'OhPZɵt0@g3Xsy0m=u;M*";rhnwMTebN*e+ _pnqp?⊚fA,؅? r}z 7شw?CMϻv\LN2\ <:_VML~GB(Q\TnM@! @y}pb݌k~̩Wp9uMn{ Ūg?y"HM`]hs\Gv%l$\Is b_˄[UԷr@D*oMN&bK[N ܺFSK =%]q\W[y&Ӵ9[ "4R )`{vN/ mX6-y{ oug^X16l"/dY-JRЌ7IA.\ڍ2lD 7آ籐LS:Oj])$ٯW_3HQoP1t.`@3~w'#؋tAPw`p7%̡Aɵ\Vq׎ __ %3Va\On8]4KO,7g mq=  Vk7<ʪEO$1)`{%B 9,ӗI 4Gmmޣ%rt汜r{-M=HF/h˪4clA]4.}1 i$$0mz>8IxCLBʧƺNQt)1{|le~炱[~\Q귾Եx՟MϚhgPEۗÁ{I贈>]/L_Ǧ ', ʲ\~T^E wWoOMw]M6?2hvq?ŕ-ujX~{ij$;iDA/4x5u {PRu˖A kDbeELm5GH+Õ_+-KhzT*>qfkuJ7ۦYmV- :Q,3'{[\}(Ջ#IVЯufOp\J1pAjxUcW{x Ak+ʇowTGAUjF2]BśF}E*+9ǝx b!VG#WJE)~ -#0_鹰>RfM =z& ~>Vs" endstream endobj 1225 0 obj << /Length1 1661 /Length2 9087 /Length3 0 /Length 10165 /Filter /FlateDecode >> stream xڍT- )^ CpwBq])ŝť)N(PiytfkVa唱v):B]9y9u^b02]! *9&oA<|AQ!Q  '& p[ԹP  lk?,V!?2  Pp9[[!( x$=+Յ Mw)+@@PW@VcfP jm󛄵>R+ф B"3ie'o#?'G'# b@~>v7X\ [0f͟a`O1Q{<Lexrhio'+ ~]oUـT8D8pK,m +;h8>J`G@/g'Uo)A Y`_Jvs} u݀o П9Wq;dvQ{VvJ?X]'?}|O\q ,`0 / ࣼx>< j Cn.c F2M"aHXo$,A ߈=?6 >vs?:KiX'qܮxl iY[`oxE"8s;H%;_MI20 $>9R5jg.Fʰmqf<3S y9xY\JOEI$әw\ٺ14⟚cԚ Q4+^ٺmXn^fwE ~HN?uЪ`d~+cd3gEz5qFi{B^1] 焺N ts*Ê \2~Jv:I&?RQ kگ"v(~fB! a8|$!d%ۄ~*P{ G2%;o.DH2)!UQ(^GqdNo[trZN m ̩e„)*2l +4:OȔuU oHBJ+'ym 5n?xL$J>){j`I$deSv*Vi {1NYwIƢofLu~уXzΧRLf] 1:zӗj w-H/#P q|E6SJs>P3w(^>:q9#iio^\QFQl ψ.-ď)@%YyΔS6g_xT(>6_pz%M41<@FV246Z_㊜dBT5e4 *MK&dT@H׳%_wS"̐28ef ~ceiQGXҺ3Itr3ofV Ta`OQdŢ!|;-1Rpߴp/~Us"G/k؛$M b F?Y+O@M\(~ %XXV`hSGI^A-@r|`]|Y.I|_`OQ!Է0sӵ)j֌1o )JH>5a_-zAWw=?}4OISb*aeKlmN=bqٯ*'RR a0L?񹐑@Km4ǀrug}wڻVAp\DJn9T[NL(h襰(w[9QS)_Jz`@x ˂s\89]&5@h3'@M J~m898PS ^?Yp[Zs _ޒ,U 5:c_v`GgҮBSāi(Kok-_[KFS<Mmѿwt/ˎ@-P&L*v9Ҹ2@xqמ0EdR)%zbƻ24c󂈐 NIh> X%:mݖx}GC~OV"7%Pzqo1,~YGRYۺ߭I[ G`VI hnЗhOsб\ZC:=;QMMMZmQ/x/43zrX(Psah`]ply' '2ȷU:>DƩ )Wh"_sSgƙjsRcڊ%m(|ГBt=N~uC^;6E!Y2|R \:x8(4 }_RV}*FؤbDTB5%4gWєBMcS1vƼ-r*+6-I'| wpFyLsۋboLmP^bQKiY:clpu܅77g<%X`UY6#v=S.]l;3!+ضFj:%#*/TA362b=39#Xq <}W)^-֥/s`l/œ0Pq~( <ƆS8/+0uގNG_ۧx2ưwJ]継uL!x!?McK l!Zj )7R~tDǣ{c_~lKgn,jE\C}(FOδ\ݓ6)/69] =z{s@}b=L$Yi ~~*kdfKY-kbөxiZܾ|Y*mbxun=p/! /Fw-wEAt$#.i# `yJޯ4vdı4ϿJ Lp <߼%dG ao.%^CɎ";%MK J*N{ؔ'c9}.t a *I|lyAWn*04ngtIlkN}?I6o: oV qXNh{r0ѓ3*|́6DBh&'$>ԉr bڮ( _f4|O3+'NlXAf`L* AmT(K;_Dzu3KXO`.UdϖL}F@҃j8}:/^fFIX)T\O6QNs8΄Ntd49fin\P/s! d[Ӎgcbs>}ꂈ_xdLL}KQ7r=I^'{:K(t3X9U yzm,Ŀz o[}ݥp'+q&v ZV=fԓKa})I誨/}hI[AܙCܟa#k7I35f85H_CVqm} wǰhal'ԯ6twƵ@M}aJx 8,9.wy0$bn<KJ˻Zw| <ụ̈̌?.(dd+XYӠ\],ޔ٪NK ?o#*nEc4XAx߯|5sT +ߗ5&#ux wL{mEhgB 6_8 T4I54Θtʮ74+uB}}wdg2c<:`sT:V~}Ob C`K02*,9_-) A5T;zeҠWסAJ%xv<㋱[gPKFrHszRh;nXBgǟ-iȱU jr& zIN/sm%OεMM:f8W̼`٩ܔQ ig*.U,<cI!R!7Bg%sU:(bCK#ƻq.C֡(>]dMxOoUhCb+Цhv;p:EM#(z7PD?ni(+$ +[+?ɜtEvMr7_)#s˕1$\EoA󑕔Z<5/:vJzjXFX$)%sItd~#a{g{[Hi8mϼ 7%m* %V;BX- 5O`)OQZu9qmN7#}Y#~ZBnmr1뚷F1׿O`ԶK,&F2T}-2'!p JaWNk򝣒uM"l2$ &lw™X"u^^utNLN~g[&Kf؊~~始{sTR鶗1h#M@MhTw8eU8[v<Y)h{`"ܵe/F~$~p$ȯ\3$(Zv?+m:}g $LS:7ֿ;}I׷RQ 'DHeƕURIAy&"_Zv4O( *殍L4 6wY ϸ,ځ z,114*9UΙio8|G r?I3A+!XL9&W=:}&)%9]؇X ,DϏcu;@ת@c$$Ȇ}l⌙aHR}iK`YRiA.J19@b?/3ÏϦ]:ne]SKauGX+ѦCcsWiŸ#MH}lOh L e|Cyϯ}=:<@3]M=k=,'9 w[Wn<*/7c~EfB,<]I v؜jwStqe9"[oMlhd8&s5S:w^,7<KĈ܋= 8Nm`vpn \s,GZKBa17fVJ㹊ICx_IQ}xJe+Xl7yf2?mGI,4v=NɎ"֪siޓ!E+)>:fMuz5 {5б=VWӋ8fpL\؄GkN | pqp~/طЭ&Wp k}Ig>b#}jÉ7֝[Ǣn| i: 6N&r64u`panUbI90n0F2)sTCwaoՕ/N\䤁2Ry̝cfAQYʲ%5C]J5l^2+ X5"Ў5$vv#W=f&r_v э. jP_`W } Q,9ؐ@'x[g7˓OZ5R4Xw6.tYfupB'Gރ 2J>C)\hOo >}ҵ{ƆܯuiMtb~4'ފc3v[oZ17!b~væR#gՙ %}ݥ%eU&6|J|cviju;s9 8ԾA^0AW}I3$H-yTۺ[d k^v~rraXʡ=mOIV!b]1e#7UѾTju/["*q~`%t=g3$ԦR|VFu KZX=[!Ͼfˡ 6lZfˠZ=n1o&TwPI|D_Ir+QdYC\Wx1.i醷o{kb|ԣB w|Eh; dyC9 u_TUP#FŚ#`|VkDʰ|||%i{Wyw=}sy[ t$Ϭ*!O*ofY.R49vWyq_+ҕvh\jM%6CVmkG q]'Fo s)/QKEdU2^^Z> stream xڍwT\6" C7-ݝR  %t4HHIwRHHѷ]ώs}VF]^9{-XE-}( B.?PVc0J_A0E*L {@HTE/=@=X`n>p_K'$..; Cl- f#|UC pqe8y@{m\ 0  @.;0 j70`?x^ ܟٿ Am`n6Pqt5Hj+ʷ񲁸آ~,Ab ꒕ 0WW0A|8u> yCX;@({A!`5?#P?#b;sU s8( `{oC[#JOu vFuÁ(_W(mà.>n.)oaH+ @Q"Uߨ ϳuhx ?Dža(( C}*<ʞ..bOj"`w !C<]۫AMKx(C`{]Ty zf |YsF=%NvQ-v0_3' ,m|PGY?j8ߺAaT E/꧰ 2 @0O߀8 @oG8D!ްk PL`0lG0? Rz^-Gͻ>"=ɺn7o$M ]K躻ETvo79YUz eh۞y e7C1߫{擝{PA)]Yۨ *}fgR<Śg5M̈́}uI2uc^-z"7A3B?5irC37ԩf‡^LS rMlrk÷JpPcƭ6&3&e,"ՎDl=xt :.XE(n׍n+ #$Up%]% u R2y-ޚ;:iI87Q?Kpν>bhFBwj7``q:&ӦHrrWR3EKяM:μ*V ɪ}T2O5OS2"i._ HluTͩ95rg<3exMOeJl<.iaSaF4Ԯew >lTL\hB,TDy"ۓU6q$vٴA,Jz>WV„ndJ|ؿ >,-^M=|edH蹑e+\*ơl?Kh#}e 1KKϮ.ՁQ&A'򛍨iڳ +3C2ǬC;J899AA98O͕@tގ<)'0-:jx #r QƤs' .h !yVXШKɂJM瓥AY0;̎Ȧ},]𻹤9e5Y&l,8$_(}pD3ji%֋,r*IμSɯy :.^~@PAzwO,dZB"<0ttu'1`;L;]VEVw8(Nb{_SS:ajy /i\b8>i={;Ґ7>FٽrƕLcěYŰJb~= +"4|R 9 am7 $Ne߯ j4_mHHx1]rV"rcDt2y0^qF#5#;*b딢X_c4|zSUi.s$zx>eY[ *{9k4K1blѭoӄF޻ 7dLd]RTw?b4:?o}1pI2_)'ǓםU%L$wi'4wDZXf 7b*t F E4IaX^9LrVPaP5w`7ȁBxWclA־5Ou iEWfw%wryvR˗l~E]' ir_ /n؛tt6nzQ'rw$Zjv%裉ڋnP4AB&̲SIQsKe˧c>iP'CxT8cnuVʋSElj\l?gt#N:;]:} >*OD|I} &nc%Ȇz;o(ΞH1~u0mojM1zR>:>JZƨIUVqdB@aO2[vyY,Qbˌ#հD&j[Dʝ@|]GøoYG(." R!sRRvO TRRERDo^H3Z\Mz:WÜIVəZiYp}q*ۑu#HD*;ϑ{j/,ެVFZ1Wlxx$eZ bubЃ4gsw"V 6O>x ndFexm)f;o>`@kX{tJVw*24uv R4W|xTUf*it^΋LZe{h-6 VwUi y׼ҵ]0\A\AR< Ϛ0l߂,gՏ;ҺLldY^!m?= 2؄zQ=qӫ},YRCn]eVx([/ \{]"V57U7J  ^݁;RSXbU-v:f>Y8?*vWbq{;L+](_QtyEXsDc mp=U7p9A6VYLhJ׈nϏmDBϔPċQu,%A'Œe'#@iFmRaKFjRg YG.N~Av4˼`Y "ubBz!\ފ_ ,3MF3 ٵ>U$R1OnVr;1\~TO}U|s.SuH_NWdg=͋޹pahPGm v1fNਲ+Ѐ̿ޖ]m6D GSu}uۂ$ҭ[yU^F@ 顧_rãfo\ =H,xBy}`)6](PtFRكtJqC41_GS^ʄц {ڱqR.zeHm ^#ZXڱls&{`"z2:O~-[ x8。<&䕾02%gÏHZLx5˧|?6P~:qS@D| k|dޏ$A+V'Y9νV$xc2bH(ᬄ8ADMձ4?ݠ`R1dseO\mqK,̽E-.#b{ӯЬmA/(-đW30'Ţ/~xo\ٻ"iq#OaoU ?w X;DFmK,}#d4MNcjy!#i0~ j F$p&ÕʼnEW1ZAj"xCauF.u *b Qf1]ޢ\W+' *5+SA'^|6A10vHu!-N1.>4͋t>9/BH1u9 ďFʜ9B՟G)EKk?~Պ==\2xX'Kq4?>ܔG^[V2ky#pdRWV7%1~ o @_\}oq: IBƞVBՊl\$]׭1;nR!ǤGڠat6 qkz;W,&`qi%֩Zx7{e~쒙("kbvDipc!( qk$NNqs]gJMۙ.>77f4i]XsϾBf.|fWXF2S'}ŠORgsT~( &ܒS|.)>lٞ6tQW/JX\D{% HrOç}P1;Y,*dTYnh1kQ%`r? _x( :wLrtSS b~b]b&SeQ!WwSu'*sڟ'Ki?`+2A!43ZĔXq9f2|C &dh18g٩4au[7=\ɩ/Ǻъlz$h\{Z65ݏNNKߘ$Cy+{^4k^Xat7XޞrLvS ޿! h,q3LLt^UDIU-b]euxMҐتLc bg[3ݑ횳RZ@3ClO .5w z˜שY[D=š?\YuUvt)6^W2nAw;=%dG`Fo> ¯GО};X8v~tn"@>.B0C+S p%$ǟ%0{Ա; oǢrOWJBr+&C_YgT̚ܤr`A|~ߘKOzjn֬u`:uki'bF+?$k̚ )+p_NN0Ғ7,piXkW#VtɄ, 06"aC_2 @˺^XEnRǚqu)5je;ljM U≀enKY۪V-xnZџSbt 7ta(\SoǕbAs ^{nJX5[Cڌ 84a-ug6o`0kkXPض/5Z ŜoɁ*zl?\S. ɓ>כ1wNʱw `s'ЙIS⧯mrãCh;;Z.䔐/i1B f.)jcv#{E)v&O>y/T%)^tư1<ڍ'^W۽6 -wiTDImԕ)9d>uড়?Ďͳ[2ƈMY>ܩs#~jDg(f#Pި&鄳o[lqG>&x٬S@^`l9*ȴ&;d@f^xO**y^QOL^VL|gjZ^(3 sSV)]1Ϸd^^#LGAjܘ#R񑦕*j> stream xڍvT>%1ZFF7HAE FF)AAZDZPRJR$图{9wv<}=u?gFJNH:# Ut `, 6x@ܦ0D]`1UMjz!b@ DJ 9"Q2@U #B"`h +wqHKK *yPpG(qybOtzpORɺxɀ@"PO"/ ahE &&FHg( pG E8P@@;@=/g?^ ";ݟѿHO/("p:=`@=um! Fb~Pp(P]A~^I CS`[n;v#Qp ޾;z`!? (@7 8 cx!X 3 ~0Oÿww:\?ٱ0=(x {eՖ-t4 ۤ bE¢` "* .BoqC'3(EOM9.G` # e_dzx2?V'#O;Vž>؉Ab߮f?Xo(v2._"9}]_=#`H43eΚ;)Ac;ÎҿTC8"~͜$BAcw@ ;NߺDHlK/D~SB rcED ! KAcOa~wo`"Bag~@`#`f x[ͽ7'J«rܫf˜TQ˧ c.O+j|GluD1)-vɆc-Q#Ϸj{YIXׂ/M#_kqyޢ/9-{=jR.ED눒 |g >¬('ǯ\i% BŊ0O'>0Ew0r1Z2]?ƃQHע)-/-ԁc:L"%OJ}ev;i BH#j6ڥPEX(?j3Z~⹔I]֍eɸp-Nv&9#T}ԃY?6Y6C*h9:N]h3&@>_;3p7\F)EH˶>3#Mm h3A`k8F'm<}w5;?bor 'bSsR't0 $wŧ$ZV6v]''MRH' s &jlKMdzWU CUP 4'5;~OfZJ7wOnwۛbߑ]ߩVa$ZoOꦬs)J8aԎko|WՉ6zZq2s8FNi@bq˜4|%4);ٯ幙/6BӼsYWe7p_y/>ֿY+s=ed4}+w[qS-IY9W2TIH)yZ02+2qQrGn ^L7cӰjh9-MJ2Tm@d$V mi+HԴ}_w<]g1|( fk4<1yK$yiVWlCE_Ln6M)վ jl7 PnVlR>`V}Kb *p?v3vh/pL\H0xK!0ne;Cj7̻3Yb qp~^)q.Sf"]RRUfń #+rvY+?+wG뜥l>F텈`.fݪď&,u߉p^ hV{H|c3./@!@@ RؐOODS_TzJvʚg2}9Z-J /==mʱno⻍2퓬m) pA{yURg5`i .Fãi{X4\>:_Pv ʕS]Ej"4$dy@݊BM@at͓W <$];pƩ&g )0NsfaO.0fCĽN;RA&Cѫ*.w3$TDM('9dg,׽c|7 Fn͹`lqx}滤a(wEz 7-)^?ř!ΰenH}OFԭLimJԣ_mxZGFDR{jM*o-d$Z$o̰"p8Ӊ.𕸁WrU])5iNuPK$v-2e+쾰GOC sJUߞ;dX\m-gy] ~&aZ@Pʟp1%?v/;:VY">cw3[wqIl"{MVMT̻IBߏ81;;k%g72,zsVw5+M(ͪm\0qɕu.fUXz'bڕbN/׵6YOhwwP9Lnx3nDOT uIzc{m[{V2l*25TqLO %E\9ArMBwӒyYqI>,=d5"~0v!uA!^Q08qe#2k:Y]p_sn~CsJN֦"t78NeJ|mL#Nzn%Β1oۄ /d *mz:kk&}W]s7~[@GhG|bsl^4ĥ۵teS'k 5humKTÏK8} 7>/mPy0^ { fYxqxf#ՐظN!G%wzӾctgc xF;]|ԸudJMyA"D*SѴ^F~_iѫ~t}3G\VPz8טCx;lw6^qF^z4oH:3Any21i'` oJ|#wZVc ȗj7<'lB[SO˦[ ᔊW e{,w5][fwHMښcط͘ #񂊟DtNHb_058e?=e,h\T9am)!7m. #1d [ج'@go2BUn1 q]'g_sXky{"UjזLDJ^]rA"w?\}4ݜ7Fb@Up>i8i9$9j#8;}'>Mom25eN7cFw x 1hx.WzFY#0@ri-o'\ G/GJ {EvjJ{Dp"{. 'xT,AD?<\yXzJRMj/$Nۨká #-Hr_96? h(URY\ohpI8561Z=Yv_ܯĩ-iS0a&c{jg~(6qp; ʑ185ĠmN4JtpmnԂYtՍ MTY!~e)ƿ8+ɠQj,5<RD6Uygh(n&J7AJO(u_\>X#}T941kRC- T@ p^`FcPay X-UA֟_F?CVbMGu5ɘI&`O٣;ڑSaåst+wI>v+z%2oHts$Z궘xι@nR:=N;u)08 ~. 9vgRTp.=șsAHYګVdp? WLu lLJZ7IdFCK=ƧhDwR[tپįyʘ8[HG mEkO \vF} ݤIP%@[a,! |yP;~N໙uݷZQ۫m[JY·P U*2.Imi {|L.E⟞N\D)\ ))(EU,9XfyΊR{vx{;)~+QvG9sZ% DԛU@8i- 5SWqgLQޑUٖp":rtF6[ETȉn9*4:cȊr7k,uߢH k!rC [ DAkYvO>>YZ'V+HY YuO7gwq_ #]sVfR*qjŷNy̱j_F4mL`xQW>¯fkz#`$TPQEe4fLS Ut[taw譏PEJ=̈́F5K0& wP<[Iڞy$k2_jR "_+s?{_-s汀y4$&)CQ1@?eG6['>#,kdث=zORdj-ӗ ΃syage^"V_vM^qrR*,dm&$>qvB$O: ™ccZZ.1HAWDZ .fХNF|mp{ںK,O'ZŔ=[2p11| ە iKF4Y%GpVQ=nD8R做yun˳a%mժ}\H4$9kH;\2 _e֢RŤDLV 6EYZCbh | rAɔ|vvFdr.,e mRA".WӋ46Ma8f4a BϣC W H. 3ts~燧/C3jrx6&y7VRv a׍'GF_.IY>p7y ɼ@-v<2nRӝO $$ϔMJ .F\ir|\"9KD'+8|R Bc㞝2^˞;ZVLxz?jk-ѲbZсWoYsۉ C߿V ?Yܬ@Q|V| w0X)/ oepHHٸtYUCS\5&f){_iHAurn#tB~؇`m\XU38p+T?hV}V?9o Nj nD<]zۺp&Ms}W}eӘUeT@cUBORlv~/v7m3/PJxvHdȞmJ6{&WU^̊O"<u4*4~dVRXf^S yK>/*QcTUX-ά?HZi3.?'vH:ٵ{En|־,NE֍V0=GNRt:Z0ܳCl`tMq5Y0{#Eq80$ OR)k үW 7djlTRA^NT!v&.T׵?SjcGm:B$ZPWN< iqRߔ5Uo{ec] GJjJJWRvٗF5okUȾślF7ׄ$[vXYtaܽDMS*$Gm&ܯehc zᰗiJc{WhͰ=vTϊdy)Idc(bf̀U) >$?B_ endstream endobj 1231 0 obj << /Length1 1463 /Length2 6830 /Length3 0 /Length 7815 /Filter /FlateDecode >> stream xڍtT].- ]2t"" 303ttHJ7!!Htt}}u~sgV&m=^[5HErOYYHOGaP嗃(L ӀAn1("  >* B\`{$jNPLLw:@XAVH3jG+@f!S$EÃ?x]w~hZ9~g;z0;@ @%AmApjo:@3X_W)WB`d+ ؁! : `|+w+0VE_6p C~1Uu P[93D:<Aݺ:AaP?v`/ n.ϡ`W7_(_  WƁWq}/oou~? E}V ߎ@- كVG ?mT`OJx@?+3laP׿Ί˯a?.YY'WPX~Ysj[:Uv0؟Pw7 4׸psMJ ǿ7A}*y ^_k xG  j.klnUAZ&CjE'VqS@Uag /jlPO թ.jsK p+/|TQ0N[o]0$*S12 D07? G #!B<`8bB1Z@ i+W-2tÒ/p[.pVe\ʤ$Yq"=x^XSNEF3Qޑ2u= xқ7AN9nO=l8h:ZN9V9!~'`2hc*i</j8cT&|d.5SQzij'>X4x(83D0 KX%}II@\G嬏U0z)v,IcujsŁ KJVe礯@7ZU4am_vv ʃCL5?Ԩy+DbDJ?-[0ŷvCBՓM o4"2Gk!@5œtKy.h}?5!j=$3$3n|{N!H}o8 t.edy|瘳W츻4mk%$#ܺtJ7.^G=}\lԩ΀-[h)#549#aRXMR-{Jm'q`!&Pݬ^G=yylqL]G5i> F6d=;` {zbXhTMGb6$yIT0ۧ-k̍j̇Ö /68yӨLo˥š'cӵOuY^Kȷ%LP8UL*ޚN$6W;Lqʣ%)~("\/kfg@D{j5vh׍er!6uP7+qDIb7*&I x&Ȓ Qpr) $<' t+p5؃8ub3Atw-10ql|}Vu78mI pcݷMW$4߄)E2*jwfC{HLabark}$7 qj\4){*Iңι-SjW}-t3u6| nؔX9[Oqfccs)Fˤ'>थq`﫝9IE>ȷ*a9+[b+9}-UKB 5LkO 3]؄N(iޟjk ]cCS)1F{>zx31&wSJr'NyA ZY0#L2L +ZX`$ m@ W_K}]ƻqRo<)&n z14fqÙ]>5ȕ l\l7uhNR^x欎 -z^ԔQϠ:N-ΞX%\ܙ 2U;18HqnFس>g, Y4gF::շ5o.i&UcJZ:B|nպz񦅐Fq @:N QdRcݥm26M\h2B >8Bw{X'UL|۲jW T/0u/%~AZ4$7 ?b$6ǼZ̉$QEbgydFL^ZCF+(W%PlA1Jq$-?%3Uy8{dSoe DKx9Z܌Ͽ4^zKkT*tyO8;7ɭO֫nz, y#"-gF֌f:13v{q.A$4a';<>ᵵ7 &/7.43uұ.en\GcPl< qKE;}8eDt̶|V^jq^PV=7'/wfyyo:v!aW:l%M}tm;M̪9|0Is6c$^_S}djz_h[uN |zjvl(fqi}h{ DG -Ba_ !4lZxGG^=o>*y4iB;>7́ލ! 6-'?ܭA]W+:) (pP ",eDT9V&u4v\u]NĀf>~d};l d=liu'S_;{~IQC`Of63M;HQXip+D=~I|3wqe,2Up,W'-0Tzhi_Und=LD *Icw~dig>V`i"|0ȣUYVQ= TԱb4Gؑؒcn'yt:h kC wW3Sjq1>B^P} 7"#5n=1{.67x`U߂jEFU$0ʛ|XiFi?Fs*ųvIS_NgYf~fėz OZ-˪>bύ0O3.=1-Sˣ7ٍ!_B3éٹ@1|(J$bp4 a_*lGN{?,Ao1-xT}`Bh>7R1p&| NOljjG̭æI;s ;\Zm6-!G>gphkU ]269hT|RB} Ƅ82G?Y*u 3 к=.c *;1 vIl_!X4Բsu==-~mBn4g^O#qqvAhM8YoysPR7!-H[`fE6.p#KÅyajskܡ-A/g\[8j@oi7p|g*) jWâCa(4}{Yq N%"<|ۺ@E|tI@FDԇQ{](fSs50  Yh1@J%~3xVGȤx7|8o;_½UGYhfؙdX[&u[M?քG, 3Pd)XRˬTSv._𸟷h_)]'-euav]4#=DClc2޾髙.[ꬠڗĝADh6)料 \!M9ad596f uW bWH~Y?-Z^# #fTT $F?U-3hkq)ZL axEN$M@+>>)atj TQ۔A:.!@UhW!eBva8Y@".5 zw3WؚmYֳIo^ E/ @\Z_3L!twD(Wވw*TsN !`DֵUt:z;;p"({LWb{Nw4{>wu.=۸-Wpsoiؤ59璘N`;ۍz3"z!u.̼y!]b?7%(fk0 ww7!o&'x.h1}pZ"BeC4YWcX1Xmhn̓q(4&avkXE4ʈg.inȄ7n3ZsFi2`4wy[5o!kQgu>˺c/X& "3Ozd[rj owHmfҸ90WK𨐮$4$n.ݾ ;Z9*ݕzO-ȟJ~Wt+`kǂ<]g{/Nlatv+[5yMƪ@!f6:!w'C+d_ i=ӫ2+fOgSf9x>*m} Ǻir.!? g0XƜlB&zW?3ҬʱkYߘ<*p&.ECPS·CA77 7e.Ks߭( /j\-RӮXx cJSfγʼnvYVYmc@oO⧜C:Az xJdb,|FGLŷQB*H e֗hS;&?EW. =[K`݇b "θ!O鯒?Kf2IwH9|[ZTrA W [&.w-+cy"b29nΆA%jzE u+wgNWYq&y||R( `U fS Y&X+㝞c?#+%f~W 0R"<%èU%Gk IA~m(9RwQ8 z(RTEc}G#G7>/t) vzǒULJ;TZfTlxp#l68 7J:}6]lVLtT[Sj.ܒF}Y)@dXO(h!c뒼J2h2i藻DZ*ixo?$YE|R*̉lWyET|Qbn& k@eAw? &U2aą8¦-K]WTr%`pN+e¯h{hi?H -};,i:%k5tҋA[6]i'Җ+gƃR* ң~NM;iPEjߴz+g/.8)aHG@H[Y=oƲCE)l*٣ɏ79_b$ 0NP&H~tIҡȡKͻ 4ٿȈeAK?D endstream endobj 1233 0 obj << /Length1 2236 /Length2 16959 /Length3 0 /Length 18292 /Filter /FlateDecode >> stream xڌpk ǶgN2mN&fǶmN<$۶mۚdΩ~u&%RP45821pe8 t Lp*NVIHՀ6\N25Y[`b`@ K:‘ ڹ;9}G%os5 kd8 lkdtrRz?~< \'g?Epcs#'!1_n-c0lXQ*B'_JH I ebe020?OK 6&QP9ۏ9(6+eo:O6V_!v8E z? @/e;";?Nb+A,z?#2?#EˇOǏ;ZQ00>B2cqe_7d@?T>N52/de qo#xghGCfQsX~oϬ6#}?|#Col468`fC/oŌGDJWX*z'W;~#(> @5rvpx}~߯L h4okdQX%J7;Csɡ7teeFý`p(ŝ2IsthKb׋^^+/ɼ~|X;>W/9i7?hAN g^6ҴE7~P527#7r5!᮶oH8"1 (SmFO<*V2tRVw L[1V&JZs&$QATP .t"0^Nrt1;UY+KKx!hqf=ِ2q LWw4%yԓ[*NLD#mu/c5W`:kj6g"()]4{;1R֏ګ}C1\l C-2V"MllY12M742 y#5G& 줒}O >',ZXU͵>bh)D}Z*hd 44]DOV|5F*:ǝxٺHdpUNJ1% !Y@#UpD7I҆w'- bE1 ~.]6fqJa.&_?@^k|[HE4&ے%pАy-K+8Z!Lؤ{_deo<^p>9YuB JG!Xձ.fWW>j?޳J^|l%1Vo#xؐfgjj#-doC-UfH" I7a1m.xd) jBꅅ-N? 9M`LM_w`פcݴ4MVoy8]& D(8'i"mX~w~bb^t'6@Y+eɼeAxQ0mQE =ȑGFg͵CEVw@dnY⢮}ͿONkR<1)\sZ^˷`DP̪eNMILAuISKFͲK]go!켦N-WPB9^ff}lg ͣ/˭wF\*s21 :z;N5Hjvo?獣f*fi'2EbyU4aOWy8u'au1_WAcsyOC>59+FdOG-9[L^E V MOU=S܁ro}aT`Y77|};E->曯 2`cA7?iN6f%N&md(yrLYa@Inf̠yA` bFQ` EA['.ۧ|zK$՜쫙mi{IYM_K_w&. ~5îUrt``4rzH'^h=5+ t*[ ױaɖo?3GgRްKu͇,iiݣt3>eڊ6v#?+.10 jK6ɳ^z t$T ؍}+BL8`5ØEeLy_|,Y=>Dq5J-l Xŏ.',s 23šk_3$8$NhϬv|^rdj< tEiemi jk֮Ӆ lXJGdAй|OKc))ACL!=I3XOK-ϭ`M:ϊ=zl0 `JxĺT֘jK6:WDZfκ }U=\O!w G 6k@$1_ &8Nlt^|K{)T|Z}✇uUFt좐K`ysR>D| ` m|.êjaQOSl(k11g &6m9* <Ģ-9Pd+Nm)q0.T0KpxlG]L7 ؚRn o%Bx+lpGȻI}5~Oٞ.FZ !Xdr]Dߦ0#QB-8մ.H| a\4w`O6`4Q}ZH3;R}qhjץX1ܩZseC4@Qi+%@AԁgL ;WÎcN%~JT^7h,XK3x-.~4Ki_Ή2q gy}4H[T7 Qty ahA3#CZP:e4 ~vGt93ϠM[e _yWq+'Xv#NɅ&jB)nժ%!F͘ +prB:gn ]Zpæzn{DtJ4@NY?A+a=㢈v۰nD&,."!r{-oYK ,S28[xܰ=A5]鲑:xyWt?~ޏil`N虐r8l9=m@6 W,8#LuJM"dPh 3IyBk?UbJ=;X* $ t.GϴpT4_X =N, -/\äTD=6*uv&}HS:@IYsD{4)Zթ|OۃJ{Ǫ #-r}TơBu5:69!Ky@d{OK!o!c|Tߪ`whD vkPۇ]O gX#~I $N/DsM{?r#fNˡ6и$& /VpeYMʪ]Ĺc3Qo0Ӆ a}?#a6"U^A9,,_S!a(aPvѸ&V+Qv#86Ky%랑ۘ+ ]4:,\ɋ/}9[M)dG`!Evb<fYTP {2ƆD`73 EKB| if~Z<troga4qDxH&2S> g+t&i1L6wF4k$!M^GA֕ У{ӶRv}QWuΞghyo X8d*ݹD'`k{_EfHdͺ˷8Bt4VGh*h,JIe*J9pVJt׻4Y6bY,A)J ((*IlaE"vBl,EԈ(͚4o(!ys0BQ)HbWbsIq6_S$!eQwqT=AtGڿϷ?-AjH:|u,G'c˕'Ya\y`Zt+Eʴ򷍌㮧ƈŧz7 ek;(nښ\pn@#(Oj~wy}M) y.xFښ6qbmLŨy; v* jp խS9caak\5պ1\%oSAT"5H _c~ HGf>R˰dL# ԭY;1k~Lhj!@j(`S;C3Cܛ2g/EWMSQM\6+;_kEy \ ]rČ\.NfO/BK>H:V ߘ3|!,sE됙1ε4`i_P id`ZD?V?gGQ_#:u%\ e0mOU7/|*G/&P)ɡ>L؀ֹ!^9f7Գ/H!I>`?~x>sӊsiV>jp違6'W۔բXv0h(}a^]|KȌZofDkYi+aGMhGo\Qi^(:ˉr,Ҟӈߴ `3{[mt:Kw¼$ӽ,aN_pb\εf:OUb} @ #4]O)Acm]=<6KOXjp8] ͨx}]9[<144f;JF=m,FqlRm;Ba%*ٶYpw!˳0"+Fpni7K=$ނ[u0f tTlA ʞR9o3;Պ8ndp-%y*r̷QmO U ٘sO2Q{LcF#ƺA,n(XҀ'! >VϰpG+݋3B vl4p1>-tu''.1}oYdl-=d4B~>õzl _0Eϖ}}Y2;KxPTM 5~J$6ZW?ICU.~ EIe; ߏ"Ͼuf#TחJ|[3ڹv}]!.'X'q#epb Nگb,0QJBHթB,-f{2$Lò൙Gb1̴1B$h`Bbd|WB;'h|#pPfV$5+27_潝7 CtG+#2K,oQΑ\uu)H7z1+q;jVfrр1*ovhkb} IKKAC'KĩE\QV$e[“Ҕl*E1 [RFђPiJgUIƠcOUqbۮhL}ٱa\\ϼ h-8\Q6C7KA6vꂇ24gցVeɏ5(q7ODP{UJY&Z\\9!Crm7I`hT?E8B^I`vQuHxG*OL_H/~A]4) } 0Nտ9*F{c,WяmI-_<\AeMkwD;3#MkQDA”@6Ysھx[{eL˻sW;W籫d"7|%5>覆 7yN3o5}E /c(X|@r4U[N%Xݕ W_ֹx?ANGI; B@پ z[5|A9u]姙R94!10\pl pG~Z|z{L|%#?GJP*R*UbH?bLFī:*$ax/UV-Π9Fd(jS @J1A%;m"nG?Cł6[=$nj_Ot6:pa R#g YD$ŒyJ e/T% -m$j Z UC_GʟO ۜhTǹ1@BA בuLrڃdSu9lr e{*G)'j8(}26=?V (ۑGaUSȍ**H݋Is^%~al[X!^YiaC{Y >/,[ߖKqџ|{@%^L"8,&:֦tW3q+,,hyὙR<w <GD |'[hf;GJJcF?Ly#&Db9b8l e~s/X'xBMcޅ( BQ_=d?t~1k.9n-2F 5XӽiD]\Cg=pmOaER$L(}s=;1AnȣwhX9N-=T@i 6w!T)4qxl0qܧ8'8:\掙tEPݴ`/cҼ8 Hd.r+=& ༄߂=7I<%VKQd jdu ߂H9rA ?{52L.Ϯ,Io)ږo5EvETp=DE۝A"QWo,o`v(m]VbU o`yoxPx+)->om_`=⸀<(WBȎޓ"$ΠQkۡrf$FO 0%|aKFvJIáhh!k4Hl4:6^%.Jzt"sJ-Ql($y^Rv=r_UsITn{ < 6:++Iۏ)(NA$ZB-a_|HGчߒϜVhEa VWR]~Vp uAtZk)EϩOw=kͭ2XyFuh+xE0dI#'6̔Ȯ,p8h}?$!ut|Jqg4ςt`YɒJXmxa5Z֦c4.@V<['k!Xp^0y>i9QGh8ܘW'ecT "ňwF}[$GK],GKO;9D ڰisx5=E(Fϱ`vMK"(_Üq˽ۤ]1zV^(;i\Y).L X 劀\7VQPB)}_LȞHx9byWDpNa!n, Aض:olVAod 6J_l?JyKĠ>*?Owɘ\F[.Z֭IFATbW|I57+YHAx|mKW,cw ɠP4<҈l\A+Y)0ւk MFVxW:V/T2#$]# phhkV?Q1=9=dv8$P!av@oPG:lhۃsQFiM Zt1f<6%ElwIigou!9% p4Vs|~C,pBwﰇ(+J4`UpjE:+eS>QV? :⩁_}djay3I}e vD/JAvߡ<i*F4B0WLE 6r!,fF.(:Mp!dx5kR\槪ӋTWc=s;5!|_)᪚eFrɺ#6}_Hicq%Go~~coh%+ߨ9Ҡ U2^9Qa^OSF{UsS'Lщ-FD5a$7Pɥmlue U?<|aQB"h0O%g^xZ{KlvO]boJ M/_"D9V?8r*ҝnC KҲp= n5Oа>QX, @1VARFś/NZAZFl0LBڲqL<Uo=*7̆泚UBŇVV?`d{6Ӿ /9ڧ8Q͑]v_dg *(T,Feڞ"),ڑEg8||Q[Q3pM$r7"Y˚yy~;:c-SKJ[q~3~A+%xl4J F]~'#QV"qhؓY9Zn[̇'/Sb(ͱہ{E2~cפx,͑"]۳ܦV=4\fzb?5GX,'2->[,+KHp M'8i}pLCXpйm6n$k$C4C )L< MFœ>/`یNC@hH:.*7,B ʋ A)A^i<t͌f֒ujwh/x{>(g@li҉PJ ax;(RB!IDkDL;YN"n.+@?vI˥5pؓ^:.Ks 2N.Q<&]]()g Lz.pЂ R^aD_~T;S3 EiY=^#OpThE"|$h=%ӹ t.׀&Ij暽C|>񾌞g>R1P Ibcw\]A\mm'qVr55qn+KYtz%+{`JK`(I[i'lmKjLQ*c ; U/,[ﺚolwp{5&s^ fﴮfi3WD XK`¶*ո[cyh `P\ 1 8MU+z<3ip\B'a]K`!TJS72A$|Ohyyb;g=dso>&)xaoԳ;Zld΂:h%);۳m`"nlX*+Ǘ3zd–&v嫍)ajl85%~Hsޅ+Ł򰜏i\ 5eZ?3upjᆾy#u}?\Yɒ&*Z_!LpX=JZ]VxzOY=t%{aEaD6ev}ȯ[6 X\_ R<0Qq |Vo٠h؄vKXmG 3>o*ɘ/ΆxC~6k۪Bޑ4VW"G ZNlr^@)euKWq>1}ya+'蕺ۂPK+ʢ\Zkj+ēpgZeP>y-wgM950f3Y#)HYxu4 [ɬc5U2O_rQΦRЉ2[k@Gvew@weppR]u$^BhvK6QUwDUI)AB &AٛNm_Nj w9-%;*+"ۜ^dVjX!lH+C))7{s ~x.:~p@ɫDcȉS%+7hui`@&_5Sti,3!ȏD9}٘Xm+K3N O줱\~͕#Օ7s .'fܧYƄq|=}g!:$(&@Yy^ pjKL/14* 0(\x {T1Zdk%7=YCH EnUW巄%KYsh²bV>{Rq930Ofg7/U_t)T9M]"1P{p2$+eW)x1Un.'0$0w\'}%^- ./d"Ƨd4Z1kV]޹j+i~v88D m8nxxCUE1 Rwv#h8'd2O+<x$@kPk`8K<1@ xSx͋@3'/X6Ҡ\FpB֬$uzU~, h|*$H$UZ?zb9M 87D h"|Rig '67<؞9׿"~I.0BfdYHئ~֖[*8Wh1!Ɏi#@B?lbC,5KJɭb;?:/@x6{2;nĬ(0섔ϿtJ/ЪNH)1YbF:=|ZH:Sd"eK{2lk!Q`d;]L9 2a6ͫoK#aU>[nsV^ӈB+eV*Fr@(xDG N4FNq-oó?NzӥQ fF2ݥ⯀Z8@$Mm߂@x`} B" gEg'E&FyNd3"+qE 9 ^"1-XtsrsߣagÌzTu F΂_eQ?*d oɓgPrm \ svõa#5a]&zfL uȚ-7VLj118PZgi˽pY_3R%A,jAKZжNU!ʢY+ !'W+jAUo]ah-L׳=ӻcZ T]./>/lR[ئ:)E<!u쥴;w-sI̫I< BeUS90^~{}e4﯄,2[]E[]{V#}EBI3pQfOZ=Vc&hDs3]ld!N1:ؘJr M٤K"ocբ+ϷsURVAr@3UUɉm<ؒ8~v?>:/:I]9CRǥ!h7HXI-Bմ>4ԣG!/1, <οf?^d` wh5\CN΀.cΣAckwnv-~'T)X L]/G+U0A];a+$HA C7> stream xڍPl." (KJwwwHw. .,%- -"%qMgΙa_30#3+?PBI]ր8ڀp l 4u|0TAN6@6 7??++oC(i 1*1aPZfXZ9>'Dda(f C@P!#An A+hhlj [ 1] V@5 6 T6E@ ԰8PY8 :<8ApCv"P XOF_1/_ ?MA ) Z@l@iEfGWGF)bcj`G@i1Uÿ9;Gf/,l9 j#fQVPb?Jqq+Ѓ <CWqZ|rxh@k '9>FB!`G՟[@0ȯ?Y?*C~`濎h X6 p`? 9>y-`prY$~@i/d{H >$~q >pt >Ϭ@NpC== oǫ AIH bD.LOVBvp9L{X)"'Ɍڋ'.$?r5h䷘ HsM){%Fh9̓uJa*V{&cfmÖ{I@!ڴKNاkICNs!y!mM?cBϧDL⠗18џшsKRX.x}|';EtdTIi#JU"Ρ1S4X3bD"x;tv|YΕNȾLr:/6uvȣ7go=㾝.B lxt4_ѓJ2KKN(Cv"v*2lYt=0_3,=yF\r0 䘟]vBNsv%vЫ7v&L w%w5QQ9. ՠ܈ T$9ƶ$9J58ޢpLpFzz4r=pj00,{V}׷U؝홍Jr.=&Jw]w @]m);Un-wǫJ(@pCԴ1MkǨs `KB^ۮ+Y|&c-SAO;^eĈzxb0t֝21=s>1ǀY`cK2lH2E(-s0F+*0H“ Ϥo$gz#|fH{s {<=էw|( x Y$y) \G+ȜSErΜnFڝj*$8dȑꨭ^'fIlRѽ?(pr ]۟23#I|0⛽cȋg mK(!Y,s5GCWnX0}ϕÖ9u8Dw'vS$lQOT I(2#ɹA29޽mHՕQА5\eϩ*`UW]T(jAƽ+e j3@hG_- Kf?+q e^UEZ7(+Kݳdipz1aL87biVQTTV'aE6њ1zHTl#5"+(@)xv{ ݖSe&jXڅFHײd FA~U@L6\}w:mUi]%x5ּ0KB !Z[E8z1s/wC:Hza \mʾ= @PjF(z3+<FzB&!al,3$gcC_{boaqygHEELcDT`>F'@ L7 }D-}\^(K };}Xs,]J=!* `'Hf_ZXWL#:ǟQW%>$/hʷbw Vd@~8)Dxm% gσG׀?1%KRR7sQu0{7ZUmGZfͯ}Ԝ ݡFc ^gt&!ָ/ܢ' E&ru5:ph! _Fovm]HLa(OaZ\_w}*aAsFw.  0"K/.+tW_k{rylٹ `tfn @&H@&X0'VKSdЕ_42G8>5șzb%Y'DVl |(4)br+?)Ba NफwK7Ŋ棟lTb0MO0b5ATzL47q_Q,iah6d%Z6ory$F,=DW_izoo{MH[-8:G|QHfGQU.fWJf!4%)8tKK#0&zEx jTŸM"K"ԱJmxJ}OmC5GItmmDpe7C5Z5)N A֤+&Hauvl \nЦ>oTC>Xi(F%z&Cn:_MEjE!%ڍA5n‰zۗJ3BvjU5 +>sCa$4[6̶@ OuC&] zdI}ϛ~ʸԓ/vBfH|)OgJŶo>ԧ𬚝.bTMkX|kڀJ_8'J0W !LQ="#<ٝ\gG ZM ʍ;%}Z-sH_BߧϠ(cߵM{%JAH)KGnTyFMdx ZFt`ƌ$1/ۀ\;QQU$[,8 QVp Oqcd>ixP*3ČUg-;T] >c!MZH%ʉ`bn3[o^hF,#1JJ4ėT5emn؉̲fUTҘ/%׏mDNCjgղڧf_.EZ'&diq19&0R5!Vj~i9# E T(x%$r&+G3.h^Ko&)駄<.oZ26`lϰ?p珄]h?w&M:|lGzMwM_Hh*ҍ¼{.MI8?,/k$UQxD4M RaIej6wZWJu3\Sjb,,>5ŒUxOBȒz-G@zo$)(pI:Lr=Rc^+oOX^|mSjbjM )ڣJ,` =R1t0]l{.g^wDҖ#RNl`h&n{ǻԧTL|ɷ(ٞ}W*]{;F,RB[@wnU>Sdtb*;偀B-՗݀qqlgGX{,"9_phObElܿԋ_q;e~ V20D:}e-&RvڀK$efwcNOq _TH[~ w'Ozkioǡe6Pw[^=ZeVVnK0;YQʼbb DA՚ ˠ9j>-p> $゠#u5oʳPϡ{) 8ef2ԫ`uPV"#.wR $s_0L,wގ'_̽=:k ❒{nպdžZ 25XU2Cb"OՔKX&"H`lf]Vn'|L[Uo =ɢ& 7Q* 6Dg1`uWv*><6O@;^|S=]u4bY=Vay-^I3÷>w Ҙ;/*iHG餞'W_e+;zG.y D_9vp=},aĂ )]%5"SP"y~Zw8Ϋ`Hce1hQoupeWha:ެUom!k@1C,NP0DU&>6xnIV83@,Ʃ޷ם\։w+q/?C*62'Jg\MM0f<EpkaaQq-rl4:@ٍOk{،*Y:6ۻY0A߾vFwW׭7g wĽ3lDM`{zՇ8yOl"1u{aw /b*ӪRwGy|߼ 6c (NJw*_|ʌyZ|Jn"Vq[⣧v/<1-sRZ ͙ëyHFnklHs QYGQ[[7lM+%¬#PՅ5,{]jU@ {*-Kfr[Tǫ$b'*"7`@^r&l,߬:h) :nq#o]CKz[gwnc٧RHu:^#7r6,);uл|yVc[B?T2@ޭWtBjG f72kt3}OƛW&OO,. az5_@)#ݮΆ*J_9Dbĺי]% ` KkoHX=G?!$O ]6&Z\˸%1XcK j`>W,ándx'WR.2 ODKKcvYq$ J綷lsϱ%RtzMt.d+Lߏԣ+JL/FKr$m}UVN 1<<c܃pK,_ۂWM?y~tUTA4d{;Al! ?I|o,?Q'HPqYT+lM&G\A9^1XDTQ& Al4Is @[$؎MNj͝eWL% w*wd͝sɞT˛sR'w&9 9#V\V1NOFެigdi^%9'f7X$C"xnm\yP,708O /(BC r/e-'sA&2Eza]µI_c$|y E0" NFbfk}w&}{t <|$]ޔ|]e%Wp.-Y| 2?եlaJʏ=XR >E!=|0M$-9oRc5n/ 4{ @f<MJ%cOkG΢}c BÍ$$}=\5\6f]' g3^UG"<dƵ'^4%eUMno>ŎN{"{D%66myqNfL`Z ;~^ kU|[%UOG `jHxTBUPt,+<8`jVaӌKQ\`EzXFxGc2>̬3@ ^I ݄y/?L&P.<%_4/dd* ʜ"%aI U*4oq|ݥZ2EheލR1[AW+S'9w 9 }>*T5X Z" v>Y13^ Ɲok1U)H bERK7ūp+ܞdX P pFc8tkɊ8%!ΝsPO.;jI[5zSQfZ$>_b]0FO. b}BeJsb-"ktI`>Wr1y],^~\pΤ9RFSEvI"=̘# [eRUU@1#mw)- x M5ze8[M :ҮbHk(m3vg['TXg"{@3;c(' 6CgϺ(+s֗5b H[ޤ۾8U@-6QFħ`*/M6wH>7SMFpØ^A '\ݡSOȔo-2 Q;C|7@Ho)_]66n2^ysr.+*CL2c=U|4Zx47L]n^R跐m8l,r,{Ô>{Nd7c|U֢9}Z^b⒳*Û^ K趿Q;Χv8if>z3cVW 9!\=utOwd¯D օVn7gZkAsYZ.2\7x ao۳DXYj\=Hd4i$TqP=iGG_"2Nw-|1KTĮEܭ{4ߣtb>c0ihMT-+( ؤp\?ІQeuS#)G}>h%s45#ۘ\y:)`R1ƺS-!EKxqK8 6ԟ D,*uu<;S&ǎb;`Aco&eT˫Fk *S%\T⌤2'%]_|n( W=$`ϤR=DbcGXGjضs>Z`Ylu~vu%܌IbZ4&cnT=xLC "xJ\kZܡj^*.mtB}[bt.Z}9)0]N6Z ԴJ/I O չpKb[qJM;`ZأZoO0:ГRxTf}K~y-C"[Du3 aTOWJ`"bjѽ( 9.w͡K͔:[kr8_3FDzֶ*=@ׅUAO9ޙ/f41MőC_:޶n-ô8֊Ye Y,Lrbq7ogZ$6/1}'WS;[1'xnA$E` endstream endobj 1237 0 obj << /Length1 1473 /Length2 6583 /Length3 0 /Length 7581 /Filter /FlateDecode >> stream xڍxXm> )@:7nc؈ %%J4  %%R~}ϫގq (:j($Z$([ PD&0пqb3eO(Th. F@"H\ ;<*`#@WBB9Qp'g4ߏn$));CH. uTcE#3.%$+vDy:|hg u AP$8ý2`h_'p F:B=cM;_? ODp`0rs#H' t~h~Ba>`8qu0@M0 wG{ z8 J9fU2 D{ڟ  П"QW08) Tチ9AQ(@ B C(w C A1ā^`( O?W ANp$c`(5p?5#?'QHXJ[OYۀP~@aI⢀ 7jdDPɿH`No">glx E<CHm?={1L]͡ .VM43#H'@^jp? qKK7SGB P^_& /f Ӳ&(fYW A9AaQ1OQf% af[!A$ `8`(O_B`"7. 9PoL6Bnpo;x{zb0{ƀBiD:Edy"0jW\e_(sIAc #ي F/#~_-giT֕}?~eqD18?[) b2cuY/iN:sێCfꉰ7;/5EO?P񪊡gPv<ɓ!F]V clf"E&3&:[XzDRQdT_*W"") |0vxCp/~aw<C!aB[.+g2=.-xng%ˉCBk; aI߶N -bq!vO3wZ'1ehq{H0.5YjNmS^꧎3tz5|'YIsܤw~Q顤E5%)^)KkBM)x)\x) k&@kZ?ll~x˴DV$59) W1Y(d/_]Jn+~录b:Wv­7kZ+P Z v;Q?0f&Ob\pfg#Cm z΢Vf4/A|n(-Y&dM"`twLX/5!F՟l*ݢ7(>"+M$jLx1bz\:oheT7Mf T+GdvKV3<@i+ԬI7Λ-]* ގ0C5rl n31=٤P>y-DbKQ!w.QF+7L$"%]؞񠩁f,P{b؋!˰emGѾОQ֋Y"[2\IZOB|RٜMtOvWy#}fhe @^ DmE2L6$`mҘV}Fj (Hug?ҌRöcl)UOd6sr֔2v+q)/ <|`aHG2{pE{yU_vJaV_2@>\!LzˑϓQ3/96l(%/Z9##_ 䲚l cVkX 4f+NymeG(z#$KP\1Y'I`? P8)NvqG[Xo8XIWur:&|cl~cd \ksY~{]HvKcWoA2`cj~F:StIU YIW$&4wiw3t}PԡQMRC<Gxtės}ְXPgO/[~v~yיzws#Wuf7@k3[a,!>פnƄEZZK7:dN!CMsy:%ڴO xx,@,3K nSOPh 2ÿb:;@{F(ToAKaUϼվڬgm׆^}Q[Y ՞[d;V6"-5vfuMdcy;<+dyIb'MwF攙f=s͍3PnŦ.LRG TH*!/h{lJzy5B<\h~;`ٳn_B-P.7>>@hy.`B*25NK=@}x+-NJ1Մ oWg[72Z_w]#WEX&a~^#QqOЊRXi| ˹G<Ζ8{dk5wߺp%]"$71mӣUzNʃǩroHo*/A?hKˎ+C1?L|Xr5>s)j$>sMJҫP90 ;k6@N::d,;W{ sB^Uѻc>C%e(Wʱ_8>EaMл.AI$i:-%lc֓=8y܍6K8SÆӾ$A4lQAd<_?1c: ]ǻ,T2"ϙWxĽLWnsDNihxP#z*;y7:3kxʿ/gxO: ő7QN$#xk,um tJ/0ð{%8i.|́"y4:mޝ0 f9nL}ъA5*կe;Q)[3Vb1;y~(ZF"KFPq/^Y{r>o)WZx1z8D~g&xg)c_@ `t N;x>+N]zc";Lg!cdΨ`pQ/iGԆs2 ut5a7uV m⿉3hV{@ iTt{TT΂[&'ۄ\iRdI;%}hƒ7-61 TM,}6GC)Nm̀? pewue[K{hW5R8:y|°I᧜8\rj!MOL=%p)ӺT~i'rHLu[ߏ4?KsajryaJp="v)g^d(c0drz<X `!{cLF!lgi W7X!g@Zj6;ON:mB5JXH3:s_lM~V;n )uݝ\b)y%M7uuۈ"I=}8kϔW6Eu|M Si:F  <(2}^[Ht4_UDŽeTJXŝyJwddivr%|}RS %ai)OcRϟZj0;қ5[|#l-sP;2cw?"z`CM=g_)tH]{^u Nl2 MhHf2+#2=̷*hZju>؈<`>~y(嚞+|yBx䳺}`;,"?X{d]ʜ^6ϝ(l<5iH;iDqeTɂ&b7_z᜚l3T-/[ͻ栌ǨY_j>+ͼ|N`R,zfB={ṛΠxKvHju}6W]he+үȯy6#6}gSb&Ywюed\~" z%{%|0nc4,4^4*z*vS nEg=[T &).)GvvG*qdǜWo$$ڷ| |!|$DKc9'rcH"M-)tl EXͺc\גN!Z_Kiɩ{dL^-H]fD(bHr22|GsYd:RKm8&H%>}&đ%v4e_;vkj(7.kG5lyҕ'|I:V5L֯HͫtS!َrElg>>lW+ԆBoJ6uL5`s/u8&nߩ?åC3TYk]W+A4Wl+r. b+kt%ep5Ns!v-Y+u]X~#A'^^~%2jڔ1xe7[袰ǝ̭n%hq;-X|FTJű닮lDڍũYEƆl7ǿ;y\Kal׃0Ȍ`nz< Ӳ[V5hq|&Z4e\Y8/ۗcW)sZr' tfi{\> ;&i|p(v<#Sĕ*HCߔa*&lO^G"j>rYPVf'vR𵁕 XV0'3./AԬr "DގS3xr_'O0*i${yNaቯXZǕU{AL%"4@>[ 록8wrW] =PWOD2qhOo8y>  /Ͻdn&V󽙫*:b ]Z-C :cĭBS@ =C=rA*z#.hTwסf(*aZϤ&L[ށbgަw=п6zW?Mrɨ\YJۑaIxzp_Q9)/>>g%ب't<ՎM]҈RC$ s~ϯ&nzv}*cM ;֫-o{Kgww^qIiOCFMY~jd3֝Ƿ&.G_3f_ktYQSwVR ^v9Ft>Ħd2xKmӺ9 h&ƛW$=.fxL328O-fT0U^Ng$(:Z,9[6Г0 SiXʇwid{玊RG?ve+<*tEͷ=}b/V-44.<>iEc KĽr~S~ά$~Eܶǻ v- 6J|ti7uK/ &d Fet$yt>[O,^`_P[ tMݻb'465F]M]yʵN[X{Γ+6<@\T_N:MwgeWYNZK9.? ,eI6Gx A;EKn 6C}ܰ;!Z֫$!?* endstream endobj 1239 0 obj << /Length1 1423 /Length2 6215 /Length3 0 /Length 7176 /Filter /FlateDecode >> stream xڍtTTm.)HHIPHIJ7 ҩtwHt c9kZ{빞.6}C~%D`Cs)(" qq0pBÐ堂0ט*sD<!4vD O#B"h". 脹./ Pr``8A]+Ap! b|G q(Gy^> xECQP'a. "0^ p a`(}၀@QCMmYOD0į`tu!|`G i `1|G#A dk tM=4sà0O?\=D E`D? CA#.8$p4F=\!0G( 7Igz#7/OA pMs^ O(oÿWDBB Ca_P`KA">ꯠ_Ǧ K$BB @& lOFM ,x /tZxP ~ fI72f+ ZA^]MGY yU%DqZ 0`B50Tq]OVA z=T{FB~N8B|" ])KAsp@~U( GP8nO_u(T^Po(G$Xs㖓%F/3smqb;9~NvJTOac~?|<׻ße G$R#( ,,M?^JtT-\W,6#rFLRVN9f܊<eaiu|GJ0^Fzxd@R1 k[=,3gx#N_ev*HuA`Fϵ;ș˗+P po({~FtR%x8w:G+SКST1GZ)RB%nB dݷөn(/6쮧1I%)c"y:bm<30<3aC]KA=I{dQѸl5;%"i}{g/%܇E!PSvM^L):96STкP䴬bf}OVrC5)nu޳p-fD S;2D^tc>`}R0qBc".N}zhۂs`nLJli%v%Xwңwf3{{2e%m2FMrNOs R(l|mwKEՅaNus۱.m4[5O,?5ou0Pzewkt.ZYegTy1/Ol ([ƲdѰ QP #Q g^ cLۅY2vu𗪵CCK-5UǮK\RGsp]k 従mVY7Y豸Rz5xO= M6*{$V"7Ĕ[b*^pܝIPRfStZy6#hBYK /Yuf3KJKĉ\K+z'J,nB 134!LW"~ZcR|Բbכ"n>:WLF]' ,6Eg&j vGӵ}ʸ Se)_0~d1e`t&lN_ܸ Vb$VFȗСk,s͒O[_W`"~Zה_g1g }JlEc5ԤϧɁ[L,19NU&\jG-fݼKTYW#h}K3 ? (-Ⱄ|~TMЍiec,5Xv =0W2s{}F^%$l 9?VFExDidxIh-kb/mC㤀qBuhZ'b/&7x7w N[dnKG[ !/Ak0c4I <ͧ/v}ƬJff7"V,Fb<(Amęa7<}F`=Zc۬[h6u_|Z"$J~#շ[ff!ʬ_<ߨUb*q)XǞ&Y)w)Js`_ cgc鐋R5) ̲7XTМUj;rr6bg27W(TWKJk((_kWnVnZd0Hvg/g~3t8i]{+e֕<~[ƙ{#@ؙL˱>z}(y/#3GzYL N=켐&/+YIfL21-.{ԯtlfdC/Vmh*MgB1v]i^ȹ3taAATH~a\p|ۋO#av65 PɷrJG*\_@ùɳOqKx+9g& U~Nw]MO ?;^I#Dbu-{CIokPF:K24`F")A%JYzQX`DvzG1*r$̇' C\h92_I1l_8fJ|$'x6eD-=xwȶ]HjGRJB$)ǫ]rL+޺7Æl\zw,*iGŽD|LH1Y0plp,Q{Jy5I6x2 r ;qƔ,I^"Ds TAVi4Tk*(![F/|Wct=y]B2jfکaA^zM0FY(Byxm:Ul=Âa Ԍ~ϋ fb5Jĩ 8ܮa0'r&b߀뭹'AZJOIܶ8:?ښe?0EO!*fP}?b'cZk)kcZCy絪}O:50mKdxۚ@66:T{q2!1 'j}+(+?s tN{琞Rˌ"xlgFi.K1kA6&GfL Zu R[bTjjrh-ndL uѹmc?gf hwp6WeZkA fK3i aVOE5ZxzZEjSI&)P=`ٛd,ѭP:C+]RϤ61QwXݤ4~$my*ɜ3c=S\<*܁6D'Unk7R4]`W^GCV@cʤ/I,Fg]-SNg~mA5C tFqpx;<º{xQ12EhZ' 97u="/K%W#*Lh~|zمbxiM!Y˃2؏bT]I0CSDΉ3" oAV7ㆵ=tS{qql۴$f~5#*s6FY'c6>s 9DܹQjyc8}jGF!_F]Lo[L1tv|dH8ZIC*T9h# `,C\I >y`'tF[^WVd|=N%МlLM@)2:fnr!rx:T{墲Ed% ړh^r]hg[^ɍ؀mO9ь"9M _RbVn lio|Dir9uTY,U$=eI/Fd,U ,nv@Ϋ&.˳f<;z;¿Bc \]wD!#=iTjr8*<[y;q?6̪FX7gIБ ZcE iӌ2m8GxLm'a#ǂ$`l*œ)m€ri\<"n_,o ox?cMcYPA5|}pOY:4?Sbj$ei,C!x# 3,C`[a E6 u fzۯ$rQXkDHMI# 9 nh$8?n¸qW/ϖNv )1M65k?#ScU87΋Q$vvzEhRQq"=B)a[{\E8oS8rY:}ŷCy>,KAR&PkU<ZS]L|k0ۮi٫e5Lԭף|Fs Tn4~$G; yMF w%N- ~܄tz{mOҩi?(u/j>?wTBq//x[u[(umL&[T^튾Av©#|471OpML/6==v|BDEL$)nܔh17K[P\)Er'2 {JQc7˂>YWo.TGvj u^)5+?*O#ruL5aR ӛ~ſ?s̏|Jr<ȹ~JViKc`h/DP=nZ U4^%1kY^aGW@w7u }{MsF3ASosűކ@:`hs'c#qQ77Nv$ѩ~3^Y 閒Qj=ǝ U[1J\?t){.+|MRFwU!Mo^D<|X yl{ģH xs>Y&KṊr)qU:af"rAZrf+Ls+m1=27^ˈV݉l!';/Sh9=Rz-(+ڭ 'aWvB7"Cl,v~|IuD,Q[>hČ:5jM}WSqoѱ|4D d 5֙M|R{]zh—w.PyKԆ{csr<*GRKK܊+ըF xnx+LTZhĴv"1`w^ 9_z0l ˇokjT(IJvx0So%S>[ (6Kɼ(|3 _Ib[0,o_tr }"&=flw, MH* f vR"9xIW;hS[:cӵ*$jZB3Aog:E95:N<c.qIoݧF[˚וx"N?Yr#KLyd"V$b8 ,Du? 4^o{sIBo ]t/j#eMtLY$bOpQkuFSqٖ9˄}yí:h,>@!*o`7Ẹ@Tg%-L*剄 xsPFqf/+n? D8cgjWyMI6v??ys~"fĤT sK>}vx O_aes닺tx -ܮ;wF>mtL^`DϗП03Q+zW@״.Kt8hq4F;zθ4rlYCVd=Ze\`sz("Qw#.hXHC>> ؖgF(,{nъś-.Fmp]wLm>?TH:e}2KsgNն^SR F'>"!4>@.yy4,E ]ΕC_x c9U z: ]> stream xڌt]k ǶvضcFc'McvMcQ_y?=뚾=(HTDL ,̼Qy5if33#33+-?r8 =?,DƮ21cCy{- `ef3/@ qQ:8z9[YX~+ڔE;@lejl7v}d45:Z]'5#/ =t:Q(Mfi/3!2ڻ|ٛrEGe@ws,, oYllj`hleeo0%]=]fۺ8|[|]1@BD`\L]]]lW6ۛ:]]Ohw/_4܀bY]ܬijW5/GJ|4~V?8cw O"8+hae'h/qV]c0DŽ9z1TuUT>>9x|8 VvNjooտGDi{sϿH|t?D=^fPpg 1s0~c7>6j@3+7v5{9g`agdfEhdjjYa|䰵*9Xu|x13|-.G YWd;;{}L|01;~>8:XN._!n`/b0IA&? $q(EQ??_QG>cñrcQG Od`~d0?ͭ࿴[~[-?n?`bAu]$CQ'hGo鿶⏓s?W'?x~xR&W?h~t(-Oi@0us ]@O)ʒ)_uChC4+;U 8r(5[aHmSֲV-,f-ߌh^.Hs=zY4S97֟:FlfXm*7 4N߳%)j-ϡZ~1"MFCps!vdu|YX&wL(q14ʱ;ZAjr({u"娟Oh@/@|Dm2*DƗ-?{%u+b&5 >.@z +iBkG+VVAU_Y).  ? +1+1UW~l.@%5{!~"EI˜)Dtsn½Xh3E]R$QDdE3gxzL;L#T4Ow50J8%%P1~KxcHJ~٠W8WcE9Qd䪲­lbͿ dz0`lJ^ ڜjar/Qh~P",q!>SnEX:COB9o7-8ߠ$; .5w-wb!cb.y0h Ca^[T@gPp,kJ]Ps{="J-*<;{G(Qʞ1ɫ[ QFbtqNg|LwZyeY  :fuVl?Iȩ9#2ܟ-KVbz,Pp8Q hH~EN*a8Nɋ'޾7c ϱ f){JѤpڢ4+-2׬rOԇ9ac%3:.ρ@kST-iFRѕ套(Q)G"MVa+ã_JZ'Lz Gwgh*!ftyۛ>:6N,`=2㐏zyO&a!$+рf$}BV$T ~xΚ11]t {LpyO;߻-eJ πy+\vɥ$E,ǵZaɴTKȠڄ4՛z3Ag =YUgoUQ`-RZ/Lêmr(k%, AKC,Hdz,at@: J7N([B'ie6^ '\y8y }LjwcT s[>f`jC 4 x1^]%rvd7Ij%iQqwE͖rU*-7J7MM S(kG?}IE<>.>aatvcWu}Cg/{̛nHL}-p9hv13Sm6чҕX"`?.%F}/ p1 Ÿuy^'t9ff̄2(1KlXPU^U 擙 t)OgT&f;50to0k5q)C/σ oEnK-iuGWwEu6eK6%tjr-n7 jV%}~8[Aїmԝ,*_`0%PބXi 1Y## DMە >ȢokxH.9m UKM\8r 4xx";DܤJe$vWڄgmQA9Yo|q+ ZAOox RL`YuT5ܕ}ǝC,^ +IJqb\1~xY^pŅ+xAt+ERW}u1ͶN cEu$kg+116 J;w%(vP1ca33#cQ+Ƕ֦9t Nwƃy_XcQLZJx^&$"zM[ TC>;6yY Mzs8U͜ށ7VQ2q;E/X]:3oʼJ3]}zg}%wLmۆr mP~fZ|0Qg#?ϧ):LN .MLd033Y6+QBQABa!p` =2D/H1n(+rCl{ƊKD D [n x+ zC`фHe> #K@-%X=?+ͮz/Cѳ?Kj)XHR@FZ5If^)v7*,e[{//u¢٭-;*%Sh>{->5>~*?3 N*WrL 5_&Nd1lSoAt(|}`B-8A휞\|zlMg&=cg5dyI黝3lXRGW9P#a} wQ#adj|/ASnnd"|qQw!`{6.&3`c z݆>eИYuHOݪOV"t Ib~I]/G@s9_aomlq֊ui$}3@sTٮF:|1| Vm:YO TW̓ʶ9{?q edWuV(lOO5R :;䩐ٜ}"eJA Bohڛ,>$9@/io.ej%ɴAFJCݵ ꜱ|"d''KfA7z3~/ [rJ~*U}cf >‰3:H-',=$6u W*[HfbS ކ4?ଅ~*\?nۏd汦Fna1:z$4u0cvOn0W}{^ȳU)qiBIsL뺶Yxh*H o9<IG߄l(|[Dk` ٠݀@'G1!Zȡlt Autr +WޭR鑴3΂}X;Bz95 5WǖKDU/FW_gwIc5^hz ډ(Lv쵃|מ[S,)RN!Sg!鲤U$E:#~oׅ K٤Zw":M\ gx3fAD(A*I1afWQ09}qA <7|ȦU(G-IDV81Ls ,x0ߢ(CIi:nRFH pD/jM! *!2#AE x=>Q*>k9`)r@."QEr}J$P 22Tt̚I '˗^]>ALhz&y,A@X䫽_C2ycC)`b]BCc^qguWł2| J!Ol;"`'k`e6N7+mno9 9X#Dמ>ӗ[V4wP1RZb֑tMZ&b(QxΜkb(x x&z_Vo]FnZ\+DK%KN3N%Y3v C0 %^bMmNPkUffa>pO#Oգ2T<-#؏M0~ҴlpZ5_ɹTnK3XgU~]; 3䢘j=n~N ‰DંK^hK*NgZ4nΔYyK4;{IGż޳yX]y/8L cףv1nLv !B.4`C< ޼!#u6cmQB@D|<j<;ϟ_ b@!QJrɘueoKfџ3B.ekқN ?girzH^ɸJ3IbveL,2Y~.CN;o>:McCzَ"0}Ye>MvoߤJg<_Cg:.;y4M_U@Q Z _m|!|4 I݇^*I  l^*Sp˼> w'+BldSB_H)K\} 6\niSCpe-LIg獹׬N֌d!}]b(WJD1rp|F׮GGU*\VfƆ5 zL;4|jxS$gw[ 2N'cLwyPdPo?;:; )b5XzeDX@KRc' |OjI"VHwO+]8zv6'Q*"=9BiIK)Q8o9XiVUaٟf[%A 7T/siĢ_2` sTs" G!&CٮkF MNgUq0H;MդߏFuoKuA5: Pubn&=U7A[撆vpUQ\1x" v8J6ioJ.c-'LP*Eb0U%(+:wїSapJ_إpyl17mPǂOcÐmvPOw]MF8F e1AKcʗ!alEtFKdx8 kk\#ZKi zĂBl]a-ڶm-]u=WG|UWJ@Z5,iPMpKƻidb1Sm0len+z1? !i٫kqS%0IS>fLOM ژݍY?3 E?BeGI,35'Jtv)lYObô(qۓg0 l$Z|W#q0)󄅵ctվ׬BfU7X!~/Vw? ٣:q'RB1ny!K@5 z عxNQj~R:EwH0: Dgeb~htDBuO֍8 iOsA1ۯt4Q$ 'eT !Dcf aMi$QE:F)[hJ~Яw.ZLUGt5sPI7Cb$¡&"Fnj^Gmج:(Xm香)*g>SAZ=g64F)5wsиáiQs&1h)YXPO8\HPzd,pNԊ!wenȴ9U9[*⡼ھ xsAOqS6-vj.nHp$7 JሒEyTCk=t8mvR.w>[/bo줃 P(Iָ sgYt[QWRfƙy'R>F^EBыv2{S1Qt+jDP"PhN ,ەzh:leYmz=/f rk,,2p#ie6Aڌta N`-DN,Uv>d_DŽ~{|g+0LyWjS&W$n!>,WLk#U {pIXs>yb,I&o_ܡi}#9G8h%,A.9'Cp5d#Pjy~P4oPto|y‡'8LB\#?梞/bm?^EkFVf+FD uMF 'ɥo4d^|5n)F?cűcPuS`roQ׿dlb(*AXޗgpv=iQv63kL27'G_}KSv٫@0Ҭ>^3n6tܰD&آB:X.>ĐVuxm:c>LAs;=pWdf=Z8qKNnv+-IgyXڶpͶV86Z+y+]M9d}r͖ o9a'U+1 qfX}n|& !kyIb1e:s"@%oVt a{lNgCA|iNiWQo55|1;|\ ɜ(΢ = J?+ An^R0N^ J|nd%UMBZ^Bvt )<`n !3ZtCjt[.*_?mЩU7B\j&p*qajB Suj>UVx=u'vARNO޽Kd?K贜nĚQd'[bZ پ[Y0*:`qD,9(ߖ1[Y"fggk.9wr 9OX<^pỾg'tHҏn`\- &~.~gpC]5+{WYsAbW j U4PZ]) 9WU#ʰEEft`QyR!du?kEҶԲTV`g(o飐RԄbQJk tZlgxpp.ZAΜa5~Vzr=V{|ԉtEj-IZCv0 -)fӔ.e'V$(&>=mf9oBu8@gb14NMթge ;.끌qAB ">}B"Yu(Wu/8wÙL^ /eBV:~{+3X:\q^_Q4"v&[RΖXIEsTu6+>zHK˖##l]V 24l'C֧#*`~`D=$V?:4o6_gC>!lΛXh3([ly0'* ҥI6;uw;T JKX3)`Pz)={C*9| M:`dzSw8hۈοR[ϼPu2IT.c T6N$$Ӊƞ16NDФք +FKXX4/xU@5Yn 0ݘJ#6Jp3r4)Tq8n+F& !?j{az|NV=WL.@lIGO:Y>Wc*4}M h%+?X'DhɣFpS+Nb58H&!#(wya?H,SKɕ$R#,7օŔM19ޤRjTDd^9橒$۰=I]S:]j6$gdzPOV."l}7Z Y~&W8}$Z)%5۟G.zaUl-j^@m2 ?q.<` n44=9:/%–~}{H c>Ek%ض۝e"f`ttW@,K"I1 wHjm28 I_m')qwǏt؀}}U='aYoԌoLhEA|GO1,/MmVWvBTEiŧ%Eܫg},?ESt82cX^ͨ Ƶz 3;na'J0k&71P"`e7`QTc|d W~c}C\86FJ@]Bwl_4~@mp>86ϲ›.+駷 `EV =X$rwO^Ґ57$`HB^EmP dRڏ͆R F o59it&E qfb^(~' zbqv!0c #Z$0^v1 +#zp<1(FdK`V 1XXr#[,6Hx,ٗU`&5a< d6j qD,O\=D6D" %>` f?d9UB62'v>O䠧K ዽc<j,bm|%_$ >0!&Ux0}aw#J(I/%m[ && wJ4cg^ 6 \="~CW-%ܸ_"KIw$SYR+&_$&̳jB?&SDa )QjERQ_iqwh҄;?OȥzU:zނ?j@^X̏!GjH)' 'b aL 'ZKME 9џ><4q6="Q Lr/-}@!?8ߧ1п2Ŋw!"xTK,=ҕ%7dhCZ ["E"sQJ><8kxԦ@9Kc?ڰ/Io=&=l D΅b\χ

>ƋgMf49{k'#E a&F-\Ԏ*7JTNUI߶~J LOegĤex1,aqya(sA*6Fy+BGDGܪ2D2fΥ$}DO!Ci˿V6Bye9'0qݥ #XV4SRd'u5rNCV}U8cDAx1OzjI(Xx/ $"` (,25ۅڨ\'9¾::laJ;ꫪQU T}p ÒPӑ3-:]Ns] [n6Z)K{D| TTs?C} 6|y~`in/0G!^s(VK<{Qa0՞\fJ jq=Er/zƊ9k ‚',چPgޤh ȝh@()K'ٓi$h l=-K:7O܂N|WH`=| 1t́Hl'RӯyIvKZTE!'LIEq|H~^b<5;8|ކFnb3!%#)%T! LoF=. KV^ϖ 7:Lha& -!Mv]Z>]Ǭ!{[O@[_뷫a|'Z/Q A̼|iOUޣhgB`hLqDbZZw0²+V[b3P7j`+6#`JXo\(.Y˾S\eOq}q+B d|zw3{h_J #Z(*ţ,uG&a~J2*|ICI[Bf^gT&7Hzb*x ɛi1APO}!QE"7ĔuEnA#ԇEGvק.p ,TFh[8T׵?Nbzsɘ_䏸\'cp("_7D1$w뺋+̞繎D'jr5+ՒI fjU.j6D"(%OaaNا(d5NF~9;׶bBׯOӽ߿'KǏ=BC/&(K6CCak6_i&!<}1c = H.ŸW>NSYv,IMW i}^f.{?#dkJHI.Zxqu[ݡT_I &ߑQ/ $l%80s藢2XfK6PX asw( $ ):1=] e?2 fIfaTX41_\-vktQtxnz=2X U?P_pݷ B TLW qFa-s=w'W, or>Ţlk,gVr5tbļChฯj*Y4ԯN%sK׷/kDUE +dBQCβh%(G(|FZb|g2Ty0Q6uҽ/h#"JJSK9 2 a|RokĄ !m,XVUu[ ;HuJmO!*۝,_)V Oe%jSvݠ.H֒s@jQxƠ^6aeuG8F*qn!qW@ғVz$wfq{Mtf%} ?TA.JݞUB.@-Wi "}##J΍G1ɗjŇaw> +J&4Q W[>$'frB -N]2? OJLc%G=d0 {{/+rQ#<^D"=R"',ͬp@1IWh6\"y@F!B!L q\t)셆i+.0bxOUS}"aU''ywW7pT cFN%ӢnӖ/~ҏH<$ӶUFW08_[)3hO8Nӟ.KqHZ*_:U,?2 t(<lMQm1MbӘØ?&@)?D8Se0Ao݊@J*>\8A p|lǞWxq}OGKl_XU+52TICL㺍!sԬ ar3T1[̅  $XWF0k53I9iM8hĿmل fV%@\/᫢*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|e endstream endobj 1243 0 obj << /Length1 2672 /Length2 19272 /Length3 0 /Length 20799 /Filter /FlateDecode >> stream xڌP c]7@n -XpH}=sNrz^lYiT5,@NLl̬ %MM6V++3++;"=rD*m# ;X& t+*99=l6n~6~VV;++\@O 3@H%jceߏZs:19t9#N6 wqA+h tpcvrcxٸ[An WO௔@?1#R4msdt{s Gh)TAQV#ؘu_l6;98}l6 ";#h" l S@pfjfcW,YB?IW9>,44,9 4{7C WUuVYx8S9w xC-7BomANn67&6Vs^9s;nG FoD)Gs'Vtu 狝 Q ߣ `avtr,\j)7E/7E7HF߈"/aHFl߈"qX~#pt]7GWѕ#pt/8oF'E7s\#0E7s5"Nptxl~El`f@?`f@s=1?Կ#>ǿck/1w߿988⯹drKcdo'gx 6Mt-m<ױǟ1*V@0O߬ձq9lNJ!e l^%Grp0bgq+66pο1v|8\l~\3g{?b%.݀0#y6³  l~ ft oවG{9aw7sp/E{+Nwёd>؉ywd\qIS_;W*ŃUאwpTʡQ-SSVaHUY[rXw&bxz+oۻE̼WRĀX?}5)CbNSl 1ClO O](aڻLQt6"#dj:78e)Ti+2>@tePS;];U8l50C@lߒ|p V%q_lUAY7h;{}=R%8% 8j< `]Zk`J?Wˋ>yT c1 !:Ԓ YԘ͇|Daz{灷+&3듲[Gg?GZږq>aO _l0bU;[JsVX1,S2^mgIakԏAz`[qNSZ/r8GBnx (&ئң*j4ǭ p\ğGzRU]E\r]ܧ|gXNVsHٌe+ /.lmfٻ/kP#%є0䰬(t ZF*c,`UaI6D_H(@RՖF5 wk r>rRb%@ksN>-]j6tuPe0 AX]$)'%f=q6c =1{_'Ki~^Gh՞al.y'{)P=3Hi !Gesx/6اS'fyrF>m P,W *6>$]>[Z]P:< \U-7LzUhihx%_' ggHkŗ˝c;.a}/̓E:_{I GTNf錅<.Vu[c^ݚ(J2%xkaHMPWV`tU)Q"c\GCrAdTxsL4V:E|X5qJ ?M6&fz:[gg1x2m츄F .lHּO㕿 ݗ{j*nONw`tHH,ݔ!ml,S J;_l#2 ic-x8:fw9"k՗HzV|qF9FHvxІT[ 8c\Y;|~y N"8oҴ;i+=/Kk,M>5J3ż;Fѧ"?B l*:צ=x"CөI1SUuί_KO2oeIӮG'ߺK4Khn)^jF%jH5ǘcXc^B%#ua[T1 }]q'fօi` \M+vc2\ [LqΗWMteXu4N>2h/(!(}5{N*&/DGD[Hz~@ީf"38)pz}a߾fEjZ7`i=K׊c8 pܟ?ӗX~<[pG1\1* DۇW)0#-2gHVi! 4/9ɲc} Liijk/'T(F,5-baD@i/eԉ=CRHFgC0"tS8,@twwIdxWJuY!}ٶ))qZCtlmx){8AuM CFϙMvfr}iVڏl_,q?>!;-j=|ݎt!͘L>&ro&7;3뿹!3e뛡@,2.9{v7 ,v>.F{!:;U}h^ofh",0mM y m~B=筯Gq;6M#[Ԯ}D(rgqq&!(lgo~@=ԣfJWf\3N67rv~[0]6IsSyv"0bۧUgX yE6\,1,,)~To=syMݵHVjfB4-E#MถevBo7qFXn:>LimyY%?|X@i2|(DEn?k/ׇu7%aA&}M94y~f%vf#!Y N-֐G|Ar$%Db/Z*1cI K>3cMiv;=賑Cb֜>/>!ZGsizEyF93܏*R̚f큙&څM_a9OqϮvQQQ*>Sz6'0.z1c2Xt4EC80v/ Γ\Ip $tuϖOYMWaRE%~Z+G^ʚOdxRK4/al @1Qb/`Tr5d/,ek]F7Mƥ.h߾=s!gIM,4HlL<]U6p !-aSB+m[dxw)_,jXI|V ¦pF ГS05سx/M]uNF^G08e4}F%2Qu$~*NӏސUijL|0_9A kr3USnS=_@eCa`kjҲ(/ʴcZ.Fl.ΐ:C ԫ[Նn/KҜÇ Zų!lYVX/\oI⦲㺾Jc_ܨ@_{8 4a`ap5 43yUP8YKVyK/W& ltb+~?훿[O*UWHXU?'=Wge;Q a2\u-GIà4vF{4r0{"X.t3r[ 0G\ :+e%V\6`~Eq#"Jx`1[8Xa>^ރ^d϶dJlVDcl=0?m`O>؉$@ Էd}xkD>ew |0N#`/Ds}~7c$6ѫwH  ;=#b һzw:p5d'wrO_ z1TDpԽ"GjDsu?qJօ1>Q-=OM΋@Nw# G:&f W?IC)cX@XH^A # : )?u7TSoSB9I$5U$ c딒OYi6ބy/S3_yvx'?C3o"C9ݒ6/{Dz"*f$Q2u]"i)3 :ȴ{X 5^րfZ504[cA ,L ?,=. 1Qq)&Qc~]N aA):C.:0;lqŜSgSZ"\)`V]#L53\JɎKii <݂e~8t ̀H<}+q#()^VϦHeSg2㙽SvvIZ!}m#+-{6F.*wQjQzǦ&;$eK.קXd7CJգߎzKӀ~fN YrGZo8c{\E0h*Ў 5VV 6lV4>l7\؆}*zI*-QBScA ݶX"h7 X+0Ѵ~f{[ێ0`y@ hnjc)N@BWk^fÛ<=y~sJPKvDf~ x Or ܱF1>ޥ`1?;#GҠ%yS; ̅&afgwUlg-+O~UYm۸S+?"!S抶 \am!6 uoɘH9\)о餾XYX.gŸ "U-Olա'֗ɊV= F8gm< ^uάujIg _]cϢk6.?x U%V1{+fk CYKq<BdzGi35r,ܧw-]2aC8I}mMro33^ϋlh&O|C g+0FMr|T=Y,@ct{[C֞"k^`$.Usḵ_P2dg>Gнv3ȓDWhu=a:9.LV4qCT{kK\ILS Ӌ=D(h zP5*1~8íc?8MoO*i{jw~K|]p]Qm#1`=(hVYy>DZG>)HEV?7@I5i\$:2?JF^?ߡЗ2%;=1Wtbb><(+*DN%Cx"X4ϠuA־F#/חOe[x#|Aۭ& "$t,fuA# n쬿P!C.4v ,WS4H&'hyD J/ޝjظP:4c0Jnm~.SzىA% (+)z}Dd; G2d&i 9ұAO YΖOrB(s{Q6iNk!ap-pWZ:ىoO8>EMC (- mF |.urJfp$0/}pr.S L⵩'Sf#|ǩ*M] t(i_SH%'Pa<>o Ĥ Fv&3#VN\$W ښyx,^VsPɹ9/rѕH$S(&ŐaT4Ga -@HY|Ur2nB{a^f)Iqv?z>|Z\g9,q]t|Lk>K¡cD!_Q42U^{)Rvn%)sx[VGJ^cˠ1y&E3ӓgxi#4ƽ*WIvUjXSjS|ְƘ oŎ$o}`tҥjEw/g-Q޳lļFڼyS/ܛ}?*u-{ROZ5[V/nrr3y:hLsVňUJ1&tPENwǮ jF|8W/T߫ 6{ٴ{-KΌə0Xؿ[qV`;Q<;%wUtnrP6URS珚\z6yrJ"`g1Jϯ䒗Ŧ./{nG~`7odAL*2q UlZ`d'pLN˩=ΦNvoode V@TjG{dKވMR5Zn>u nYg: Nd""dZuS*#F&>&eCmjX$`@'7bZʮ`rvPhu~7I0"A$,ɀ!dy+9]A"/w:m$0?3}Q&~1EI}F&C`X@K( C܆ D@̩U:@!ڇʉԥSHM FJ21yBSw5d=\RzXW.oÑ9}l%)"|F5o%tp+Oy=Jv0^Q$7TS7&ʬW杣*#)2B 49e (Ί온8(/c:Bq,wMعө ˀ\vzɵeeYV,7? /S/)BO+:K#C3P:?Ij?>ǡ:2Tk& v xUbHlh۔t2.n >U(DMaj p^gةJ)\>dAZ:VQN@݄Z͇u|?e`Id3U5'(k,xb\~j\V%dk!;d(щ@M)9(`(So'9gȪp nhV5瑨̠DTOg|BdK~u8+#c;Z 'c|9KA3A#MB}ي/㱵wTʷ$sYoh3 /TXuz}e*p\G-оYvy9k "&:Ftf昊j 3ք*40jx.042¨Ҍ^1_-&|ιIw@I Y(@0(kcJ#+Y B;" Cwjœ|1Ԧ0)27LZsKsǺHw9F/sF }VxRYB˙Ҏ/I$NN7 D?`,ɫIHX/δ Tf5ajX܉o4 #ѿഘFMT. ~}` ČpN^ H8'Im?!C3 2hk:n^)PGj&wN,E0SRnVJ`ڲV;0|ҾTfp+-K i{Ťd)9\;" 8"z;E)7IzbY#/) ؑ!yn[SDX պLN ixy1O-:x#lr5ڋL /WwigL K=Jna-&4(JwӺ]GWiIDfw7OVaK RxlV^$u5*d525ay(6K:_X݆3G'8pR-(L:Df΋ rC>)wYys{^pɉh/M){Y,>6Gd"j$Tۜ>?e@$`-U,򤺦z |K ݽ =$6 j^uds'~C"zFzɌNMˣ2چa#2ŤOYN8"Q_1p!|*2J$ IiB@s],9#g֟yCMΒC+S[{:"|>9%=IG r\)-"Kz+wh̻]ncpԠb"ulZvZ=}yLk ʾ4ډY:%@'0Nu~y2^:,AL jɼܼx!\2ZF%9Q2j"SyX"!ayÖ˱=,1Nw%VcWu1AQ1S"YFnxr9,֭E]%Kw)QqnB .l13uu # /1zBDf}0d:AKsmұQQv7.9Q>#9;E|I-)U_[-֦)lʺ0Pb"fwR`_%??zb{_0B5ɷ;e?D *B̥ҒGO!&kǂבwwT8) J7rHQ4e9}]wuW.ZsDQ]%&8|o4} Ԥ[p ng悭͓ legģcϏ,j› Y|3=_#-UBBR!ROJDN6(|7ݐtM~QMIU{qufY±Ql<ȐTB-cU"w [&ʯS3\+GpUZj (-(Lؽ_/I`I71lL+{xF0[:ٌxkm>[Fyu[\LmC0nh < eIJ2g>լnQFJk|Gzhr|Kڀ%[確UAcLxOh&iGMIcFD/(ZfH+扶 *[IM ]w2ͷ-_S5qZ|:?}h7H9ꓠO?ƬL]4k&RVy2Y勶{8lpGWV= e\v2?PWv~騉'X8[;$Ff3@XkV()xpڭ"8=~=1PLD*) \›ӍSZSt"(5DrP\r- mc'}]b"eGo@x}D ȧ21rJ_z! e(ZD)P`n}O-ۚ(*]vygٗ afk247O(K EYV7lN=AQ WyH۴̱Qx. BMEw-s5.Aԥ0$h|-gi:?bz){bx3Vstck*>$ng'Ѭ=+TO_Dpn+n =KLd̻)8y*Z[kۏ\QAme"iTZvwĺI/|hB@%kpbsm?U,F8>_o7#`- 2&-j)tCUl?YLv!TEXŜYet;Е΋)QM8wVdO|XȷweIS< BXsla?3jLugCjKbXxy~}C')B2ccD r!zVݓ*bxA; ) 2_y?aklhc //>^*4Vv*ૅW, z#? HFZA>֓VN!b $|%HXh 0W5 dg6 Ҭo3i)P Ju32j2gS?() j6IG'&7kV'ewp+gz}F\>ĆHbb ;o0`wW+-4i aO6kO>(S}JbOJߏºji'%vUv"jMks3yX' >,S3SC M^r[MHy|ۜ^e N 6M.0)}D"vHU[+\S&>Q>'=L[{msZ @99}lҹN#w/w 5&&2pM?F3YMZ{:r))Gb~) JmG58X\)Sqrv!}(c(8(eX.sڹ#F`qh~Ci^P5tOx[qA.ǸwJ.e}0n&wco# H]uk(oU|]CEX08o,>qZ8'io< ]^~% _ne*b> zkHɲX_y0Fo&2De(V#wN*~ٺCG&o]rRǴ&LuSϞ?Kה쭟e>Vk[a֖7j("&Pz{bkVݼl,05*Dk59h]Q8‹՝A2x5#eYn^\5O~ff\̪e&Ǖ hUTnZvoGͼe7d.aڞLhq),9^2BAFrꩀQ`$zA;q/f+v]vX oђ\tf6/JKd7M]UzrWf4կg~Cȥ3@z˱>T5 Tڍ٣9DQ2G?0+ƃem4:ٰÃݮ7a $v$x։A\zoyO-7Ch}࿎|G]ZI5Oe0l&5‽n> ' 'K7jh:TN$R M旛ĚB)e<Ӑ]ɉ~B9:?]G+toR\/'ЁA*EˁI5 θ|\:DL%&g`(} S\9ty@Z_13R(ck2\R[-r/s`:ޮ\5-H u1؏RŰ,Pu߆E-qQx:8 ځm;1$|ӮHlϝ76#P&E.Kz֣nдx ~n)T+^D>V#Qz/67ŕݪJgK e~hq qfj(ƕPӠzaFJX~~[4pG:m' aRiğ;/ ]mKs8ʿ:#?!HPz_'eښMPh1xFȚyG3fs:kWx,"c7P]=/ȭh햷hO ~@Ԯ]EzH1L]Q'QTPb~wFE7KRV㨨8cVyruHe$fSY_eBF;tV1Wuy ^UpU,~`AGʾ?X4U%F/ FV'l16g]ZYHJx82#H+K0Bc.oj|U-݈v1pl8e)11>`n B k2"_9uZҁ?"]WF5! i txlɚ6 kƼ]FJkZµ69Dwt"PD) CpQJ\-%o+s s#ej? Oї6 n>}ʗg~nf8*T҆ EJㄬc ۦkg 6H0΅B/ä4R.l,ia[vPnj?@ķ͂_8EJKhɤFaNMGA *-\]hfraEe4M{9(RI ǭP $K9`28Q,c}:}v.ו=>1Ր>T 慨jƍM!}F4.T7pEߜLy@>p׉>YE uC*솄|MS_(='9o$i\59.ϋ~i9Ij㮔8KQ[RZPN#zl!Y>".%7IJ㈣@LYِ*dD40OoDY/6WO (ӄQ˪NHdrQRr㼎@!R i`}ꖄ*ê+'sDxyO2[$>WA78\ O k'o,vҥYmw7 25rZ$ E#}U!bm;N604 N iLIDr5q͜@ۯ϶FהÂ}Mho>}(@(<@.1䳆i)JdO)Ո&:8]r6aH˳h |SX8jyzF{<τ8` 4_1~l`>8fb~o7~ Q(dqX| q gGI%\{/l\0jdJ%qhf.S,rrCzKE2뜻n)LDHBϊ)qaJ(Obs$C7yJhysN] yݛF1cѾ[vk#c&%EkmteSu (%K9=ئXJo>(q2%27QSmzk[,e\`iS)faP R!`K^ a0Ui>m'hc (i΅mi幅U%}&T;fwNA"-a8@ iބ$9?ͲYJF=j 1S[@V~f=a;' =Or[EMzF(5C0ZYqU2?+qئL k_?M u=eA~).j?"FԩtMM ʸu{L-&U*;-`b[#QgD7-lW7w֕8=O;쯌.fSd H~$E#L!&Q(ɯ0G Ugɘ\ ?әZ/=9'~CyyLىS'pidu )|iAyd_'Fڷjf״1iZz%+r*]9e~r7iNδo/nI`aYE/%?'>1! gt 6`5#r.#At+(fL `:sovtm [(ו >K5iצ^T6ux)ڏ6=Y;w8&vpfIm}'Dqß*/zU5 r- s1/yb4S0%:wqK{C~=8KngJ궠4!^K$)f{Vމ\  !|53wRId(_5ZTxR/kk(,$ r0v=xs΍5KwVޖ2. Iƹʱ;[`7z;͜ 9dVCg˷obt <OYU;EbK r!8-b!upB(,':ZkIɺ .UdCŲ벽aC8`& ΀9]ocGa87t~JG}bmZIun3P丮߬O<.Nd 9xK9D7"g D$x!v'8;MCn [.uaC7b:Hh*DT(|V{:5LݙqGkmLȄ^3#tnfš~USΈ$^Q\ 5iY2iCV^}6e7GЕݘs8btFZ^2&f)ȵ]bmYڣHlG?VRNzd_z'{Jۣ۰ sV;8,r{Qh0;ڙAꄧQ>ETj/v_QEdN|?%Fͭ2%1g/(x`,ؗmR`~V]M|igjY왎R{ă*,MHd9tJVD,]ergҹ/.#Ww- nl{6}4 #M^Gʇ2VW|xǴ?ߘB>;ՕFbR6gjhJ?I'Ou(.d炫׬/׳94 QJCSAJ,猇ʍWU3Zڜv2iS6|d>Ҫ@GSflj 3ln|7K;n#vj6?$Jܧq& %xyj_[ b;0r2:d9glí^"ڋ&}ưT/υG#:^ڐr  djXl!pŗLns*@K$hP !ku$mAoM?JaDMj+J dν'2-%m% iw)9HUSxlT4 :dnĠJ@:@g,,YZBnOĴ_5Z[ʠoCN2k&¿)JKJ<"-{nIUVE"?o& c3a"6ݴ 9, h岯-ŽR:RMW-Aykh$/̡ȘM:`L7745s&6SFyIo.UL!E`@Y*(Y;D#">o"5,#^(F'^A iЮoڮ{r hl$o2Ӊ.<*O' Kir/qT񐩇l~,Qq=쉐 > stream xڍt<?"%EF?l{Ź;qYJJ(!#HDd'lZ~{qw]7PhN@H" ( UAD 2F\d SD$P 8M;Q+ t& oG4FPz!ဎ F!d %/B n E:P _u0$N8$-u 1<7"| B c'$'avyC1opE(,>G`|uHCsG~:kt~ $(O_!Q?0E+S( E^P+u(`@ 0HwVt= UPp%Ò}OA u.(77r@e=&('BCDDU |`N}?Hf~hw/qa^D7"HG8"Qd` ~hW VRQ0R%RQ WEQa@LB,UO> )vex _K.?[CD!0y~&{uۑCݐќ]x5xqvUMGg905A;U^RS7|A( c#2<1#a*U%U=u6r)_5/d.|jlҴezwm9A֬RneHzYIR[IZ=˭X:/98x"X WSf{|ad^ ECruv%k=NVgˋcR(+t-'TBeuaA3_Xljk 蜺(Y6܃?mTFl'Z8rOuǏsw0HZ~YoA~،(\>vĹn[\MMsR@W1 CB4;(PcVv_"7ZBII&Y*=(a-zۍ9 G1$1R!qk/x@$枕VeesNД%Y'x3-8muJs΋+^OgOlj0à3{TAeDO+l_%̾@(sEsM;5_0/eyu/N1.U;EZؔ9nŚ-q61+7qĞE}MaR/\ZJN!=1 `Ϙˡ_lOv}uHц{iB'>/x鿍[:o0D{\ΓzLB턭bxڢ:\Kע^e䕐ʰLxD~0wc }|X>,jjmUmL6#(%jh'{:C C%, {hs&=_#lO <&݊*tB`0aTݲҀu Y7w;:BU8 ?ծ JNUV;l&M~!r}D*]]M^Vi +ޜAn111#uZjudM\+Mސw> ڃhVWm;;7K%rȟ~z}s*mP]8{}vf@-rь:#/b04*3)i*X2hc4&UՔ][j"}v@ Ѷ9l=>wQ8Mh俙vLL={}",p]swK C ::vl}Ydlk@Y#o沎B2Uӽ~xr>2uA pmWƞ8MfQVgn+D;ܝZ6:L]$,8AZEr.C{azV]τI`Euĺz&움Y'3K14K "gpi Oًsl$Z7XR|n|$7TOZ<|IABz*Ñ%+An{֊ک[,_>>0{G~8h9/y9kIZDaHo>;|ݲ̻M[4ytJ4sQ*h?FĐ19 J P^9*[mި>XAqiW"7lm-_iĖi%Eow$RmI0W'_,[G3U ۹ 2ji)V"4DDHb5g w$$d}#k9roDy}܇DvUǴz$F3X[vm)cGzd|New? # {T-htJR}2TE^f)#ڏӟG>쎉W!oYYhqyUmƔFJ=בߦ U\ddp>T:Į"FYXyo6}_ՔgO#å'cu1ݪʚ6a -ph#r tim2RWt_(V=JX IV1'Ȳ8sd&MwmHut8SD5ǺYNP{inȻ GL3E5fb #rϽDE?MM2D 'rv"'St-9N+'7^q$%zbf*Ti^Tyw|sYgWң*$Y9D(V҄+SY@r6>;9eJfRY6|)_";:W9EX?uW6=$gr~ÓxQ5YB9mڦ#MJa7SC CtbwVDoN&_8Rx2L(&q3%]: (`6 .{=XM!v?ٌsaS7.4wGN V͔R)H>yeqJV9vKؙ'FiĚ7CRÎΩswO -  l-^cʳ[bJ;Ǯ/OZ}`;OHR*qW{>-.r.+=IФ~DN*-|V> vN KcJ,v[>Ƀh,G<+<}sD*nrXYm`P+S\P %ګ7z8\˘XBW9x(0cYچqd|$2PrAy)Q&c5N}mldUW˺,b Vyr8βKM>,nj&OLh >O+L(dKf[xT%r ud럯X&^`1M8\цn8:&+eּϲ\O]q>@1sf Mi3蝷O!(|i޽9R$Uv &9Qvم)#ih궹;yonK|IlM4Mu/)$,6EF) 2dK}t]#R2u&!Z J&w̳݈3?Id{ 2?L.. N$2l3H"[UBHx!il.NF;םae&FʻfOkLUG}o kS]/A`vOx_Ԡ== /9 :y^k*]WM*%|d@C.q]Hˋ԰$P"tw3h-:;r䵉 gu> stream xڍP.Nq8A PwR)EZ܋rv9?sd&zzRkJZ,r 'wVN6!kmmA7 -o1 .$/iW;D&c{ r(N>!N~! ABs;+k6 B+ rvu#)(;@jgixmn td4wh,AYӓэ j#sh݀@+mk=];Y]-E3/c XOd%`mɩ{̝04wpA=- VnCMݍtYJtrwC>;W%o`mde +3 ( D[ftrppps.-ᵽ*C:@;k pw}o tXmP~Gay8 ϓ1d@N޿<_vE=ymy|Y\^.C?]xN _  awUd߃<MQoɁT36 2Ap_S=_hev_9d9$liJq!@;9Anv4VNArAOLQdq]]ͽQ8 儬Ϲ9!.;5K! e~#A?.q~#no `W*$oɠFZ$?HRobd9@ Gt_  bBj"Tk/)_Rÿ |ߐRӿ o*[_j98VC|!Wo_r0ΐB,\ w[89!=pw!J7%[ 2!- BZ/)7x+4V wd|[^@KpZIRO֝ Y4FVe=b2cMVȆdp/Yk'ߣF$G6)#Ɇ2W~O.~-]J.` |;~yձ>e:oKh,牨Yɐpν0ofq>MP(%0.55R˭ؐ glWj?Epѷ8vCt1 jɩ'\䆽U~9bzGlsE m>V0>^g)x.^fnYMJE=0MWc~ '@P}:CUO3b3Qܞp`&*;xL-֙ou1UW)uf ɱ(g&!DC*kQV%ъM`Vpf:xW=U˟[~G1-| f258<}e}Tv% FpPPeJ̜!'9坵%Sq7Cp.n{Ϫ'+WPm?0iXc]u)/ŝ>`Yf7hQS7OVߍVQHljaEsW-ʔ$FE]$-Z{qL,Dww1Z'<[TϹ8B|b$Mn)5ЈF0QDz 1XbNL VY0JRu$z5s|*Js5/E4 rgHÐ0ެd}̚zpzmYX4Av/( }D8vUl"4f3>$0;l/[GRR G?8P|>L| h&.90x„vŒC;0 N"h=̘gpGQJ4RPS'1!b2O {jօN,1 i0vvKt'R^$id_+_vFWwʐo,:zI23#oF=c:/Kx=(*JlfgNVI NAg}{om]Y 2HrЗyWF}2o"kf$ÊƳ0?h~\[͏/[tDRd(T1EkJPr79H]i[%GO6Cw8V6P{>aepFn4Y-ijR64?a%x]dg(Nja겦Jj@I~NsRX;,y:d{73x}I}ʽPE& J yhm䟨OB/7A[o0Cv&o*өԛNys%x**aۂ/SE^iS}l҇z/[Rlgn`|@ųK lؒ؜_I:Xc6lVra˗92,'!^rMnpMH)Gc0MpqE5er_9?| Nu&:΋PJ'ӐLɅ,i rdKJEҞq@=?/VI ?WzTLFnb-=dJ֔|.'|"e9WHU/8h.ܺvpٯ7QVP^UfحlxXPq[[ww] Qi۔Y:0sn*qB ~q6>[p9]^X_jTb}+Lױa=n~" ,t7R/m;${5ƘlSH-6-X\F ]8vЬ\&[Y4l{I.yJ)M꒲ڊ+ ɉww$)?[T}X*D2 {3NuVWPGADm oS*޳{ue[3؊Z ԨWO4CJveo ;7rJ5)Bdy3k\ύEIt@Rn_X>՞2#z)k]Fp!ǴRuiMC'FSˀ)ys(B$!,EUEyhVZebW jjNAGbj;Q&2|F'hӵ>%X& TH*!r/9(Ob_8ʆnP58=K&\! Ty{Xw+&l>A R%vN =Xv5 GXo+7i°DRuN+qL]SƜȺ ysnᘢE y7Mteņc_e#ˁh.~"Ym ӋaMʕsCM^i=!xF47W8bC#ti`E VicW՚2E~z]U[h9,ja:E”!fITαOc)t9uьć=?[7^膟`ߤgh~!ߘ9>t#Z \mj+9~7LkN;7@$@v}N4m/϶t 8+}$Iӹ׏ogpDӉ|z[L!:]o{}6\h6s1ԂY~U <ћMmIVs?Bh NU-,$ͨ JMM{- 1:~H[ŖDGaϐ=g 5kc&ObP/܉iV̼eԪ_Pif%!KTw9zFr.?<ɽsHLyAVvAkm=NXߛJvDWƴEpO6kHk6uU:GΡxT[PUC@T4︝ɎeʶՓ;Έ;ܔ:F;5g`&SK RjKU'OUݖ9_NVBuq.lM9xgPK"״Jq^ecMstk[Otg SHw/BlL  GNZvH&Z+}uT:-p - J ̱QfV[a9wՒV&K=m Rz͇zAm+r=emcsA,n]֪@ ҂n~ɱE:\xCi 8׮p;G#(2!hW/aY}M٧ iXqjUi%DŽdanK8aђvv`p-yRdRnsB;8*._J<Ϫ>q B)2b>8D'4[H2WFm{n"2|i6B5ɥ$s$m/Gϔy)hWT}`(gxm"ZX븝 njB 'yખyQ du`rgco%){vfGZO[B+[RQj&>jAsܶɈż>]XJ>*>;0QxbiK M*&j5"{Z؉w&L'e}KA:Ź*k|v4 m;,S;@( ưla{+D87ldt۵?u*k\qQ^PrB#SΡ!SWK9 5'ݓ5_<oZɥ{ZS;G82ܤ[Hڙ&2l">4n, }dܟVS8FCDustxJ .adW[fVB ׭PKWZH³D8}&,>tG(ݓlv9Q;q:TzgYbj)7/8AU"K›'cgEīK_mJ'%#6OdM26ֱvCKNL(~'x@|DǢ@}3VLn7t_R}8$r/k}"9OgEW{Z׷E_FW$;4S퉂'*%iH[6PPjdI$(d}*ؓ!4_sހEp>{șu.GNȩ+1T3ݲ$(\`oqPu qLv̾smu 8Ş4##5à ڙ ^g9[Ԕ%B\sj^Q\\njEǕ(j젊3x%Ig 3=rt;Т55OwI&iQ e>MF#)mV@6  (ЬR c s]օK)eX>@I>l439۶&ʑ> GByrÏKܿ}mmy{OHM鶧;. ^p>#\OKqeS/=̾oU@OxoPQ,xOJr!UOĖPQnxҠ'S#JxGTƏ&dx5sMW]WDe&)@-`1fz W\p',C.xo`maѪetFM2k9]ӝ!#lW꼄YGL$)v\Șsin 1`{Xr=<$n_lmLzm a9-.V0? lNC6P+Ŵ5\R| Թm&b?30j =\dq$#?}* 8+<>Xd/ $1H2Lz,K ђ~(h"us#lQ|$o*chQw{W1_TmYxwٟ'`[f=RӍnʰ$4aswΠ+T!uPym%G^,j>^_p2/eL($ <+|4M ;b2s]J9ܡcBh Ffa2C3(v|/^0pcLՑC{INx7Ơ#C pP8ѯJ`yR9 V34y|Sb*jҢC"i{mmakeA.9nph.P26y7c%^MMc]XeO&PҦcr}cw.rdq&S嬼 p2u]|χ(%,=4,4#-;0*lT( Ⱦ|&?*γ~'*,ҀءYC!>)ӯLm gS*^rFOR+is.~{7Oj_NēFsQs516z-n CXz=j^\ ۏ3jSޏ0GaٌDKmhIv+85x55e՞YyIAvn&h! @ӂӈP O &.Ο$ $+$v: ]}'yC΀ތ!;E#00ǬwH2l5A  &.-^WWM3 z6lA`wݒ[AZ@x%qMpFB\AV\C?3L嫌w *ZnrMlxإ}&Wy/CxMO"׿]t`^hCI0SUr'4eRF;{gix)Y +CUJүJ*G87]xa{EL$W\:vǃ8hn_vpf>5EW؋#~B%N,tN>Rb&2p\#J27IRECv b7J\ϸ~uL"\k$+'I'# x)8 T7kَ?u6Sh:WU!O* z8 hd4aK_h% /a|9!it͉v=j$^CiūMr,㝝-tRӖT*+QļF x^snE+"l-n80%%53I7+8Q_v覮K`bH~!z8Ɛ#?4+f0+y\Zz%7*w܅T>l`:=GxO;%OD6YRUX^4pKJ 'I_|0[`f<-*9&ªbFNiRNÈ9DsQ*'LeϗM e=418BTbCtOe=vo_,>~&MQ8o~[)˦^-72=&{d :;2tΑM$*w>HT`0yjHw+l8i~G;S[j2:Ń ]o0}(^̺_)5WFjgL+ 6xQ,i,t̓da<l*IdƯMs;1Wm%5iT0 {?~ ,Jwi콎,4pˋOyңvGWMsm>j{|j %6N v#m**"h-!kI&28 <NS]ŧ WUxo%D[PnY_Qȣo&yȭ&(C̸b}y>Oz>QwlƞjnR'-nHן]d\Xk}e7`k4oG\'w_wJ瞻6ainHQa5_)P}lLˤ+.;7V/E2˨[iI(O4ey.S`t(Rd] "62':.a"XWٷyԊ-~HN^.qD^) @5gܔ!Nڡ)k-'Djn}l V{,3컉^`b[a{t$b23;b%~z0S-1ߍq(S{/wfőiݤ4[,5S/)^yCEbEƾ.5s;/B?t]K{X.qzc; \J:cX&&(,xZ4ɗCZ6>CNrтP*e@d FV9K/ǝf$i6E%|NYO$3m| ɍ1l*IF=&C]@$u{/m}^lM ho_EGnUc-=H#e uoERg2 /"L2K`ށT_֫TMAwC7%c?(w(֋xۤCS* iuްR܏=j`~ByQh< {|*Ÿ|˷ ;WpwPG & +m~n~ԖX_l#׍AqKIAx0H,|Wl$qh{~Qc˯󠞂}u)Ք YMKR 7h>JџZ註a@R`ښ,f*J_WMqjJV)jp/ KRgC6tRIz GؗVIEmsOE˵Io6e̯t1ey1gB3% ԦY)LJLuKWCa*7ڍ`vk1&>-HKG)SJn]p=PA'gCz♹mRpN4}bsq1`P~tѵp{./CrzR"`-\Vg|{gxjf/# ԪpE,%aǑ#p;-;j޽M,3]ֺn?6O6bUW6M&c SώRP3Ťa-B|y⾵F&ǧ?L"ʹe m/,R'X t|QEM(R]wcf#}_q{bpK;|Q[.ûŮu`)> :Wga.g+Sv?{$|?xUiTXhe!0)I {k5dT[?LKrJLbA =I%-]R]F -jk\(7u}ONafG1X%r t\Vj^9$Q$ѼVE\aI=ge;Z CR=)*N1]x|P@C8GK!eN3٬MW ՁF@( 27PxʚⷈD+Ry-,sDpt$ipa{6:}_t1sWߞA6+0b4rF2-/%y8$P΁:s5;qWEr h<_<@: $r_A V3)a-slz@װx$n+}ʷuF /T%)'4ðxa2=F[@RJ?Ngip~S>!=NgY;|G`VQ=ca;:eMj22KۡS4P⤡:ZW 7g^v<{ܢ/i/eٷl`Z7)m;7:ßI窤yS1$2"þq~ۉa.Qi9q^BA-~~^# 4WvVvZLO<V endstream endobj 1158 0 obj << /Type /ObjStm /N 100 /First 991 /Length 4056 /Filter /FlateDecode >> stream x[YoG~ׯ],<|[qCRlنhrjH6I8,@j}uוrJb+&2c+0q4I&AU6DLK;ѫ+ 6c*@(*P 'x@<*ģ!h@3* EP" 4$R DV8 h8;(g$( L !F&hBF <#@-ĢeX6O0ʀF4XF>44jf2^Ć]ih6`Hk+CʴI"@'RXF6LtLÂhc!AF*Ƣ]toH4Yb!F5!erPR)U0#PeXO+ fmUƱa Tbiao)vln'6Nu=ɱ#*Cw6tb%Af w ivd>.DrgEĚ XL2WN "GCExw2.=)9ܽ|\5jϋ!|4l:'"4p"Ak{꽢@a@cz-B6BK@l@!\ .g><'Ǡ|Вg56X[u}0*[ϺF svm a}0:[5Yu<^:zres!uR>bM θZQ0mTFϱЦT/ {f\mzD}2u=̚T>ŮJcR\n켧Z_j=G?i[SvqCT| h6 \+Fkj4[qdPhW264δ˂\F弄4)Gƒ7$"Gn.4ߣM KpJ4F<# fE'hHQMli)0R %%n<)uLiR;i֚j~Gy [x A$µ#ܕ껭 *F8QH;+ŏlX<\:X)ץ~5|p$<Ҷq#JzЎ`RŜ шk=,فsp h"8^mhd43J ==B@,sR !BH\P#>FނIED $8-ԕ]:mV7hH'Uxh 0p=dv4ǐ4dg\=K?k))P,cd[N]D,Ft;Kn@#JDc},k7pk8 кX2^sVHRSg|Vck.ۯkl`R B$ h_(x3SЦk=gخ,FUJtDAް[2M@l@lI"o)l@sbX ^K2 lv_`U,'j= 3zn{84.(g%% [Ef‹].\getm"9YJ2򽂽7k\VmEQRxVFؒN%BN*Utxdm[^Qxߋ:5_J\:+TZkzdSњ/C ͚O Rd.'PxÃڑD乘(+)d.t6+WՒ3}k~?شt;O2Xnx/ yKdGC1_"TIednՙcJ카ȓshp\jѡwEW関@|z-Ƃ3ڴ#EVLC\A(iFntf SŽh,h3w'ɰ[9ˬCe*#: :6J bSZ¾X]z(+b~n+qI'Rk=ѐymhM E{Xfr/(+"BqBozn]nS ?k^5yb%,܎#‡jR~p<ȩ-Zu;# Ic_$梨jg(ģAo9HTⴙ9,67kec op\8唘rlDTc.y,M9/$s^.: %R; elWЊ<[h)PZ [+i؇52<N>GCx>8;^={?Ҋn L*'];+ v{Ox2A>\<|v;7wѧ{g_N?O_84GCdqu0;4ͣf4f|>7_Q[sҜ6gys~6l.I3m_a3Oai|gxٽI_==Xϱvrxºk7/搴28'#5Ũ}kkϋóBg#Llt~܌I7/58n㷏~t{xlZ-2APX%rbe߁Cc}Iu $"bJ_~wD"v5m8)6΍ q!PZ2L^VۨG.-85ӂ?yLlq9j.E`2%L~#%~>6 ?Og1G{r~k3<IyrEt{9>.O?'/w0<Z~y>˓;>ǻWWE=_fB29.?,[4̦'_m;oprAbvVѳG+t4ۼ1έ߰=u;Ѯ'o=}䐵ёNC?LH?kYy^k{Jum1rޥ(^|E`2/'*.C~?Xy<OH m7׉`lkVOH `@ X;ZUB,8H~~=+Qk*}:5 wkK]I X9dXKlOyF>]~Iz=*uKK7un{{5nC/Whk lTz _'1{l==*y|ZnnW7k-A[XÀ/Av}k `&gZ6w[NKfxR5]E+~3ΟYb!˧[dE^Kƫts*ZIo83[jѳa-h endstream endobj 1250 0 obj << /Type /ObjStm /N 100 /First 890 /Length 1845 /Filter /FlateDecode >> stream xڝY$0+JU &6!w!|!~{MTF\zT9-rⲥ-Vn9wJ-[Q捤nW.) L[Zo x/RT˦E|㳎9aQG-|3 6tT.#і&ftZ6i( Z&`V7,1I B+#b\VJ2+D4:1Z TE0+@tE 1^юW" ^) c@ "T*oD8  PUF .h[IZ2֮5-#FƩԭֶ1ƂP"A:䒍 0'! q@FO>oȉ;(/p 9B7O)ô ?*_ʒ(R5{;\F8ɾ?2f#D{^e7WOc+Oo}g$5c6f.y>[sc3r2IWR"kI,}6wtrw e݋ :,&AɫӖf(tȎ:t\ Ӟsg;sG's4W4uҤYd=E&=e9THy5@ܰ.iMa.'mi/>}(Yv].#sCl'MͮѴTP]fU_RSAiTRSAzudG* +A*]sS+ 2nM+BeSA"PiT21֑`+Pa|UNY`F-Q_E#s`xv*pL~9sĽ9F8ӬVZ`_7ȉiߎ_xK,vX%ªUXuv9a  > stream xڅYM519$!!rx<)C/ SlO{{!z3rWUssqNd .$rSsM.悿k\\rK^[ (QG5B](5v7BBO.ckǔNTQ88(UP\P\99A)b"QuH ^.8jbp+~~:}ڏϾt}/><3q ?} cs%V8bXXX IH5*K[<|:K=OWMQ j.hMbC,ʆdņK,eWX-SXLb,,QjS;b]D{ZjOJ{'ўړҞ,IKҞ,hګ;brR{AK>X{/J{oiS[iOMi {]Kik}> =ղJ Оj,^b߻DԾei_DԾ²/}Yj^bR{d.IR^jb%]JKU$!Li}RgK{IWZ+E}e֒Z$ki%ZZf-%+kIYK*kZe֒Z$ki%ZZf-%+kIYK*kZ{Y{Ym-JSG# X.GIPO9mEd8{Dn- )8BV Դƣ.{K]GHy ڬWQw~T륛Y%C~.`.j\ Xu_:RQ~1y)뭭.F\%7 tFb} t^[w/~O燗kWߟϏo랑q>Mt9>x:[O~zw`<5͝<._ǗzgbKN4Benq:t~M#l >nܴ a{m:~ïhMx+_ 楱j{3_[m:_qƊVoYqVk4.5R;_*R.qKm\bfٚ[p,h8DC4Q. ׻nê!7 " e 2AlD ۗ5f՚?l'[w]vכeCo-x-x-x-;oCy>v`2 endstream endobj 1320 0 obj << /Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.14)/Keywords() /CreationDate (D:20151217153944+08'00') /ModDate (D:20151217153944+08'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013) kpathsea version 6.1.1) >> endobj 1262 0 obj << /Type /ObjStm /N 58 /First 573 /Length 2318 /Filter /FlateDecode >> stream xڕZMo$7W^ 'I```sK6Y$`/=߯UŐII||(J>C.Fr)4+UY1'4y'o: %h%Vpa)0t\(CF:Jǒ Z_Ucc{ QEѥZB~K%)K,K"gXrNaCˢc%TXWR|B/kD-U(,-(r(j# xIVv :k#Xitv\ǔ †~; ,j.G@c5$ H:8I"'K. /իO/=>}6S]))וTAUePe?R%U**TEU 77?< aon&;tU5tOTEP#g5A(ɌgE-V]H@EA:tP';jZˋȢ./JcS@!4:TJ1b5^pOa`R,y(@Aģ*\{4B1ET݈ b8'@l$=O5'll#+l#3b#;bჱ5IwRF "dhHA43IJ rO#d1@֊]Hme)F\.-gldb>v@Sݮ́t a-tZA?gGaSd Lg Lr# h9vgi4H8. LlCnE?@+RZ, YWsW|±?s@0"+dtFi Pd q@ɬT ǎrz7}B-Zk2ɜefFkbbu"E+=2`-%ͼ`Iܰ[.aZ'}H#i/F K~0/1:qy/~!`H l~F_T]!'H>,ҳlR.6r]=l䇐{HYޡNY.ĒAbnEf܇]vCn ܣFj ܣUzJ:WI3ǧPޕy `*ȐhGŪ-9ˬx,~V*l!a0 l0kGI*̊fͦ*`0`l:If Dg}4 ̚=E`)f/5{ 8{ӮH)Od$ ㉢UfJ+4]!S9Aj Vfps@&sf!p<;̚[>ԚZsPk)/ܠܥԚZC&ܯ, y)ǧ_BbvB+lo= 8v!'}LNdRJK&_nQeY4 ?a#'k-͍&c 5:` y]dl]|%@>k߅#_tڸ c) jp3cgw4v|AT^:$9#syG5Fj55Lt :͵zt?Zz!Y,̓<fA ?C棿6'LO >7ܸu8 79Nnx7fJҜ4>m1l i.\Mxyxx2]ˡHAJZ[9C{vBnk#_"D/oŝqt7սU;9UKS0C?]?޿{|ӗ-ݝ绻$o*ϟ.k5Ǡ endstream endobj 1321 0 obj << /Type /XRef /Index [0 1322] /Size 1322 /W [1 3 1] /Root 1319 0 R /Info 1320 0 R /ID [ ] /Length 3053 /Filter /FlateDecode >> stream x%IgZ{oyx8rq<|ql'<<;6H `CmBj ! !T 6ذhT6?T4 Z@ds[UUU/jj?sϟj0why@K{6`  ,ݧ=Fhh`%!! O{L{khOhѵ`|@{InihwM`356l}Gn.jyMt;@ut'E[B-m)*|B[FҖ.gUK~9-u_V.!y08B[K;%m,z|E[O;iN'״-S7[VI4p- }H?GN͍_}D˟C_G`Wh--žFC Mn>QS[/SZ)GG;ƘhѲ1#~!4xB;LKyg#/RڗKkv[h_>C] a_8,cAa} 4}״OPa} a}v֢> Ma}v Aghr4 Qa}v&>HAgh; ˴Qa+8aJۊ%7iTn2aEی۴F'aOS݈fa4$i>$oh [2T؇-6!aO^ dMEE}Fi 7hs[%kҤPaIN4}P&MB}&=&[>X=;T٬ 3JTKhL>XF_5䢖 eGKˏi53tКhK] A]B7a/in-@؋ۀ# {ƭh4\*7)%q3Ƙ{Ic܈faRa/in4< %mz{Is^v֠yqc(鲛>z oIJNY-iZ+o4$z{IӊU.iZ@KQlv{I3Z^re7Ek:UW+T>&N:qd{;.!x')x%x^7 W~sv&vۥ.&v0)Zo1Ӿ: }Wuv-0A&`mn pXv'0¶^`HmiH00r4ۣx0Jd{؞F<0q ګ9ڛ ڻ5uﲺqc>gsH־bkվ]-G.sD) Gyi}^pD$*!A^(| uyɡ}^m(| +| +| +| +| +| ߧj{,zYgzYgzYgzYgzYgzYgzU?RW~%7y;NA{'^-guuQ:m]A>ٓtκu]]jj2uuvɎf 5u'љ0;79/g]uc՚u~uILd]Omb1gE{^WPc@ci_GP t`Cl1q0s2z/d0tRoo[M&AGR]|\g4qZ]wNۍ#mg< Y)yZWgIv{uhr8D3l;oq)+N[dZWt.CMP){_8f P ܀V_C5Fݗl&ج\ z-bɆkJYrjaKTKWlŚrJ+YdtfSl; \SŨ[r<Ibh؄K`0,q;v*tcnIpD;fΰؙ;`ǻcHי:C[jgX3uƲd;Tٝw΍rwݩogMAdg3tɥwщA)3t,ߩ~wߩ~wW>j3Og;i>Y>v̧ t$TMr='R?z~OZ={z=E>ݨܬyc>ݪwU>8_/+ꅫO&/(~(/(|dU&9*LN"ML;q%L\2q%L\2q%L\2q%L\2q%L\2q%L\2q%L\2q%L\2q%O\2q%L\2q%L\2q%Ӊzŏs endstream endobj startxref 285847 %%EOF luaossl-rel-20161214/doc/luaossl.tex000066400000000000000000001467311302434335300172030ustar00rootroot00000000000000\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} %\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} \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 or Diffie-Hellman exponent \\ .curve & string:prime192v1 & for elliptic curve keys, the OpenSSL string identifier of the curve \end{ctabular} \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. For example, an elliptic curve key requires a digest of type ``ecdsa-with-SHA1'', while DSA requires ``dss1''. OpenSSL supports more varied digests for RSA. 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:\_\_pairs}]{\fn{name:\_\_pairs()}} 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. \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 an OpenSSL configuration string defining any referenced identifiers in $value$. \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: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: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: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: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.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. \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\_MICROSOFT\_BIG\_SSLV3\_BUFFER}} & $\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\_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\_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\_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}} & Do not use the TLSv1.0 protocol. \\ \small{\texttt{OP\_NO\_TLSv1\_2}} & Do not use the 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\_NETSCAPE\_DEMO\_CIPHER\_CHANGE\_BUG}} & $\ldots$ \\ \small{\texttt{OP\_CRYPTOPRO\_TLSEXT\_BUG}} & $\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: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: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: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 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{\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'' \})}. 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.} \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: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: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: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.} \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. \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} \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 ("ecdsa-with-SHA1" for EC; -- "dss1" for DSA; and "sha1", "sha256", etc for RSA). local data = digest.new"ecdsa-with-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-20161214/examples/000077500000000000000000000000001302434335300160345ustar00rootroot00000000000000luaossl-rel-20161214/examples/lm.hash000077500000000000000000000033201302434335300173120ustar00rootroot00000000000000#!/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-20161214/examples/pkey.info000066400000000000000000000002221302434335300176550ustar00rootroot00000000000000local 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-20161214/examples/self.x509000077500000000000000000000030311302434335300174140ustar00rootroot00000000000000#!/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-20161214/examples/vrfy.sig000077500000000000000000000024471302434335300175400ustar00rootroot00000000000000#!/usr/local/lua52/bin/lua -- -- Example public-key signature verification. -- local keytype = ... 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) local hash = key:getDefaultDigestName() -- digest our message using an appropriate digest ("ecdsa-with-SHA1" for EC; -- "dss1" for DSA; and "sha1", "sha256", etc for RSA). 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-20161214/mk/000077500000000000000000000000001302434335300146255ustar00rootroot00000000000000luaossl-rel-20161214/mk/changelog000077500000000000000000000025071302434335300165060ustar00rootroot00000000000000#!/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-20161214/mk/luapath000077500000000000000000001025641302434335300162210ustar00rootroot00000000000000#!/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-20161214/mk/vendor.cc000077500000000000000000000003471302434335300164400ustar00rootroot00000000000000#!/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-20161214/mk/vendor.os000077500000000000000000000000241302434335300164640ustar00rootroot00000000000000#!/bin/sh uname -s luaossl-rel-20161214/regress/000077500000000000000000000000001302434335300156705ustar00rootroot00000000000000luaossl-rel-20161214/regress/00-store-verify.lua000077500000000000000000000005031302434335300212470ustar00rootroot00000000000000#!/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-20161214/regress/53-csr-extensions.lua000066400000000000000000000115721302434335300216120ustar00rootroot00000000000000local 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-20161214/regress/82-bn_prepops-null-deref.lua000077500000000000000000000031541302434335300230320ustar00rootroot00000000000000#!/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-20161214/regress/regress.lua000066400000000000000000000061551302434335300200540ustar00rootroot00000000000000local regress = { openssl = require"openssl", bignum = require"openssl.bignum", pkey = require"openssl.pkey", x509 = require"openssl.x509", name = require"openssl.x509.name", altname = require"openssl.x509.altname", store = require"openssl.x509.store", 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 local counter = 0 function regress.genkey(type, ca_key, ca_crt) local pkey = require"openssl.pkey" local x509 = require"openssl.x509" local name = require"openssl.x509.name" local altname = 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 = 1024 }) 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 return regress luaossl-rel-20161214/src/000077500000000000000000000000001302434335300150055ustar00rootroot00000000000000luaossl-rel-20161214/src/GNUmakefile000066400000000000000000000166331302434335300170700ustar00rootroot00000000000000# non-recursive prologue sp := $(sp).x dirstack_$(sp) := $(d) d := $(abspath $(lastword $(MAKEFILE_LIST))/..) ifeq ($(origin GUARD_$(d)), undefined) GUARD_$(d) := 1 # # E N V I R O N M E N T C O N F I G U R A T I O N # include $(d)/../GNUmakefile # # C O M P I L A T I O N F L A G S # OS_$(d) = $(shell $(d)/../mk/vendor.os) CC_$(d) = $(shell env CC="$(CC) "$(d)/../mk/vendor.cc) LUAPATH_$(d) = $(shell env CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" $(" help: $(d)/help endif # include guard # non-recursive epilogue d := $(dirstack_$(sp)) sp := $(basename $(sp)) luaossl-rel-20161214/src/Makefile000066400000000000000000000001161302434335300164430ustar00rootroot00000000000000.POSIX: all: +gmake -f GNUmakefile all .DEFAULT: +gmake -f GNUmakefile $< luaossl-rel-20161214/src/compat52.h000066400000000000000000000106461302434335300166170ustar00rootroot00000000000000/* ========================================================================== * compat52.h - Routines for Lua 5.2 compatibility * -------------------------------------------------------------------------- * Copyright (c) 2012 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #if LUA_VERSION_NUM < 502 #define LUA_OK 0 static void luaL_setmetatable(lua_State *L, const char *tname) { luaL_getmetatable(L, tname); lua_setmetatable(L, -2); } /* luaL_setmetatable() */ static int lua_absindex(lua_State *L, int idx) { return (idx > 0 || idx <= LUA_REGISTRYINDEX)? idx : lua_gettop(L) + idx + 1; } /* lua_absindex() */ static void *luaL_testudata(lua_State *L, int arg, const char *tname) { void *p = lua_touserdata(L, arg); int eq; if (!p || !lua_getmetatable(L, arg)) return 0; luaL_getmetatable(L, tname); eq = lua_rawequal(L, -2, -1); lua_pop(L, 2); return (eq)? p : 0; } /* luaL_testudate() */ static void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { int i, t = lua_absindex(L, -1 - nup); for (; l->name; l++) { for (i = 0; i < nup; i++) lua_pushvalue(L, -nup); lua_pushcclosure(L, l->func, nup); lua_setfield(L, t, l->name); } lua_pop(L, nup); } /* luaL_setfuncs() */ #define luaL_newlibtable(L, l) \ lua_createtable(L, 0, (sizeof (l) / sizeof *(l)) - 1) #define luaL_newlib(L, l) \ (luaL_newlibtable((L), (l)), luaL_setfuncs((L), (l), 0)) static void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) { lua_pushcfunction(L, openf); lua_pushstring(L, modname); lua_call(L, 1, 1); lua_getglobal(L, "package"); lua_getfield(L, -1, "loaded"); lua_pushvalue(L, -3); lua_setfield(L, -2, modname); lua_pop(L, 2); if (glb) { lua_pushvalue(L, -1); lua_setglobal(L, modname); } } /* luaL_requiref() */ #define lua_resume(L, from, nargs) lua_resume((L), (nargs)) static void lua_rawgetp(lua_State *L, int index, const void *p) { index = lua_absindex(L, index); lua_pushlightuserdata(L, (void *)p); lua_rawget(L, index); } /* lua_rawgetp() */ static void lua_rawsetp(lua_State *L, int index, const void *p) { index = lua_absindex(L, index); lua_pushlightuserdata(L, (void *)p); lua_pushvalue(L, -2); lua_rawset(L, index); lua_pop(L, 1); } /* lua_rawsetp() */ #ifndef LUA_UNSIGNED #define LUA_UNSIGNED unsigned #endif typedef LUA_UNSIGNED lua_Unsigned; static void lua_pushunsigned(lua_State *L, lua_Unsigned n) { lua_pushnumber(L, (lua_Number)n); } /* lua_pushunsigned() */ static lua_Unsigned luaL_checkunsigned(lua_State *L, int arg) { return (lua_Unsigned)luaL_checknumber(L, arg); } /* luaL_checkunsigned() */ static lua_Unsigned luaL_optunsigned(lua_State *L, int arg, lua_Unsigned def) { return (lua_Unsigned)luaL_optnumber(L, arg, (lua_Number)def); } /* luaL_optunsigned() */ #ifndef LUA_FILEHANDLE /* Not defined by earlier LuaJIT releases */ #define LUA_FILEHANDLE "FILE*" #endif /* * Lua 5.1 userdata is a simple FILE *, while LuaJIT is a struct with the * first member a FILE *, similar to Lua 5.2. */ typedef struct luaL_Stream { FILE *f; } luaL_Stream; #define lua_rawlen(...) lua_objlen(__VA_ARGS__) #define lua_pushstring(...) lua52_pushstring(__VA_ARGS__) static const char *lua52_pushstring(lua_State *L, const char *s) { (lua_pushstring)(L, s); return lua_tostring(L, -1); } /* lua52_pushstring() */ #endif /* LUA_VERSION_NUM < 502 */ luaossl-rel-20161214/src/openssl.auxlib.lua000066400000000000000000000004641302434335300204620ustar00rootroot00000000000000local 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-20161214/src/openssl.bignum.lua000066400000000000000000000000671302434335300204560ustar00rootroot00000000000000local bignum = require"_openssl.bignum" return bignum luaossl-rel-20161214/src/openssl.c000066400000000000000000006617721302434335300166570ustar00rootroot00000000000000/* ========================================================================== * openssl.c - Lua OpenSSL * -------------------------------------------------------------------------- * Copyright (c) 2012-2015 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #if 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 /* strcasecmp(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 /* ssize_t pid_t */ #include /* struct timeval gettimeofday(2) */ #include /* struct stat stat(2) */ #include /* AF_INET AF_INET6 */ #include /* RUSAGE_SELF struct rusage getrusage(2) */ #include /* struct utsname uname(3) */ #include /* O_RDONLY O_CLOEXEC open(2) */ #include /* close(2) getpid(2) */ #include /* struct in_addr struct in6_addr */ #include /* inet_pton(3) */ #include /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */ #include /* dladdr(3) dlopen(3) */ #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 #if LUA_VERSION_NUM < 502 #include "compat52.h" #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))) #define OPENSSL_PREREQ(M, m, p) \ (OPENSSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12)) && !defined LIBRESSL_VERSION_NUMBER) #define LIBRESSL_PREREQ(M, m, p) \ (LIBRESSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12))) #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_ASN1_STRING_GET0_DATA #define HAVE_ASN1_STRING_GET0_DATA OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DH_GET0_KEY #define HAVE_DH_GET0_KEY OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DH_GET0_PQG #define HAVE_DH_GET0_PQG OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DH_SET0_KEY #define HAVE_DH_SET0_KEY OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DH_SET0_PQG #define HAVE_DH_SET0_PQG OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DSA_GET0_KEY #define HAVE_DSA_GET0_KEY OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DSA_GET0_PQG #define HAVE_DSA_GET0_PQG OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DSA_SET0_KEY #define HAVE_DSA_SET0_KEY OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DSA_SET0_PQG #define HAVE_DSA_SET0_PQG OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_DTLSV1_CLIENT_METHOD #define HAVE_DTLSV1_CLIENT_METHOD (!defined OPENSSL_NO_DTLS1) #endif #ifndef HAVE_DTLSV1_SERVER_METHOD #define HAVE_DTLSV1_SERVER_METHOD HAVE_DTLSV1_CLIENT_METHOD #endif #ifndef HAVE_DTLS_CLIENT_METHOD #define HAVE_DTLS_CLIENT_METHOD (OPENSSL_PREREQ(1,0,2) && !defined OPENSSL_NO_DTLS1) #endif #ifndef HAVE_DTLS_SERVER_METHOD #define HAVE_DTLS_SERVER_METHOD HAVE_DTLS_CLIENT_METHOD #endif #ifndef HAVE_DTLSV1_2_CLIENT_METHOD #define HAVE_DTLSV1_2_CLIENT_METHOD (OPENSSL_PREREQ(1,0,2) && !defined OPENSSL_NO_DTLS1) #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,1,0) #endif #ifndef HAVE_EVP_CIPHER_CTX_NEW #define HAVE_EVP_CIPHER_CTX_NEW OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_EVP_MD_CTX_FREE #define HAVE_EVP_MD_CTX_FREE OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_EVP_MD_CTX_NEW #define HAVE_EVP_MD_CTX_NEW OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_EVP_PKEY_GET_DEFAULT_DIGEST_NID #define HAVE_EVP_PKEY_GET_DEFAULT_DIGEST_NID OPENSSL_PREREQ(0,9,9) #endif #ifndef HAVE_EVP_PKEY_BASE_ID #define HAVE_EVP_PKEY_BASE_ID OPENSSL_PREREQ(1,1,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_GET0 #define HAVE_EVP_PKEY_GET0 OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_EVP_PKEY_ID #define HAVE_EVP_PKEY_ID OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_HMAC_CTX_FREE #define HAVE_HMAC_CTX_FREE OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_HMAC_CTX_NEW #define HAVE_HMAC_CTX_NEW OPENSSL_PREREQ(1,1,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) #endif #ifndef HAVE_RSA_GET0_FACTORS #define HAVE_RSA_GET0_FACTORS OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_RSA_GET0_KEY #define HAVE_RSA_GET0_KEY OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_RSA_PKCS1_PSS_PADDING #define HAVE_RSA_PKCS1_PSS_PADDING (defined RSA_PKCS1_PSS_PADDING || OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0)) #endif #ifndef HAVE_RSA_SET0_CRT_PARAMS #define HAVE_RSA_SET0_CRT_PARAMS OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_RSA_SET0_FACTORS #define HAVE_RSA_SET0_FACTORS OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_RSA_SET0_KEY #define HAVE_RSA_SET0_KEY OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_SSL_CLIENT_VERSION #define HAVE_SSL_CLIENT_VERSION OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_SSL_CTX_GET0_PARAM #define HAVE_SSL_CTX_GET0_PARAM OPENSSL_PREREQ(1,0,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_SET1_CERT_STORE #define HAVE_SSL_CTX_SET1_CERT_STORE (HAVE_SSL_CTX_set1_cert_store || 0) /* backwards compatible with old macro name */ #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_CERT_STORE #define HAVE_SSL_CTX_CERT_STORE (!OPENSSL_PREREQ(1,1,0)) #endif #ifndef HAVE_SSL_GET0_ALPN_SELECTED #define HAVE_SSL_GET0_ALPN_SELECTED HAVE_SSL_CTX_SET_ALPN_PROTOS #endif #ifndef HAVE_SSL_GET0_PARAM #define HAVE_SSL_GET0_PARAM OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_SET_ALPN_PROTOS #define HAVE_SSL_SET_ALPN_PROTOS HAVE_SSL_CTX_SET_ALPN_PROTOS #endif #ifndef HAVE_SSL_SET1_PARAM #define HAVE_SSL_SET1_PARAM OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_SSL_UP_REF #define HAVE_SSL_UP_REF OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_SSLV2_CLIENT_METHOD #define HAVE_SSLV2_CLIENT_METHOD (!OPENSSL_PREREQ(1,1,0) && !defined OPENSSL_NO_SSL2) #endif #ifndef HAVE_SSLV2_SERVER_METHOD #define HAVE_SSLV2_SERVER_METHOD (!OPENSSL_PREREQ(1,1,0) && !defined OPENSSL_NO_SSL2) #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) #endif #ifndef HAVE_X509_UP_REF #define HAVE_X509_UP_REF OPENSSL_PREREQ(1,1,0) #endif #ifndef HAVE_X509_VERIFY_PARAM_ADD1_HOST #define HAVE_X509_VERIFY_PARAM_ADD1_HOST OPENSSL_PREREQ(1,0,2) #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) #endif #ifndef HAVE_X509_VERIFY_PARAM_SET1_HOST #define HAVE_X509_VERIFY_PARAM_SET1_HOST OPENSSL_PREREQ(1,0,2) #endif #ifndef HAVE_X509_VERIFY_PARAM_SET1_IP_ASC #define HAVE_X509_VERIFY_PARAM_SET1_IP_ASC OPENSSL_PREREQ(1,0,2) #endif #ifndef HMAC_INIT_EX_INT #define HMAC_INIT_EX_INT OPENSSL_PREREQ(1,0,0) #endif #ifndef STRERROR_R_CHAR_P #define STRERROR_R_CHAR_P (defined __GLIBC__ && (_GNU_SOURCE || !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600))) #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*" #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)) #define stricmp(a, b) strcasecmp((a), (b)) #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 optbool(lua_State *L, int idx, _Bool d) { if (lua_isnoneornil(L, idx)) return d; luaL_checktype(L, idx, LUA_TBOOLEAN); return lua_toboolean(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 prepsimple_(a, b, c, ...) prepsimple((a), (b), (c)) #define prepsimple(...) 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) { if (!getfield(L, index, k)) return 0; switch (type) { case LUA_TSTRING: *(const char **)p = luaL_checkstring(L, -1); break; case LUA_TNUMBER: *(lua_Number *)p = luaL_checknumber(L, -1); break; default: luaL_error(L, "loadfield(type=%d): invalid type", type); break; } /* switch() */ lua_pop(L, 1); /* table keeps reference */ return 1; } /* loadfield() */ static 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() */ /* * 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 STRERROR_R_CHAR_P char *rv = strerror_r(error, dst, lim); if (rv != NULL) return dst; #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)? &strcasecmp : &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() */ NOTUSED 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(...) 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(...) 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(...) 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(...) 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; 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, ...) \ (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_pushstring(L, "oops: no OpenSSL errors set"); code = ERR_get_error_line(&path, &line); if ((file = strrchr(path, '/'))) { ++file; } else { file = path; } ERR_clear_error(); ERR_error_string_n(code, txt, sizeof txt); if (fun) { return lua_pushfstring(L, "%s: %s:%d:%s", fun, file, line, txt); } else { return lua_pushfstring(L, "%s:%d:%s", file, line, txt); } } else if (error == auxL_EDYLD) { const char *const fmt = (fun)? "%s: %s" : "%.0s%s"; return lua_pushfstring(L, fmt, (fun)? fun : "", dlerror()); } 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. */ static int dl_anchor(void) { #if HAVE_DLADDR extern int luaopen__openssl(lua_State *); static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static void *anchor; Dl_info info; int error = 0; if ((error = pthread_mutex_lock(&mutex))) return error; 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: (void)pthread_mutex_unlock(&mutex); return error; dlerr: error = auxL_EDYLD; goto epilog; #else return 0;//ENOTSUP; #endif } /* dl_anchor() */ /* * compat - OpenSSL API compatibility and bug workarounds * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #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(...) 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(...) 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(...) 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(...) 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(...) 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(...) 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(...) 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(...) 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(md) 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(...) \ 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 #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: if ((ptr = EVP_PKEY_get1_RSA(key))) RSA_free(ptr); break; case EVP_PKEY_DSA: if ((ptr = EVP_PKEY_get1_DSA(key))) DSA_free(ptr); break; case EVP_PKEY_DH: if ((ptr = EVP_PKEY_get1_DH(key))) DH_free(ptr); break; #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: if ((ptr = EVP_PKEY_get1_EC_KEY(key))) EC_KEY_free(ptr); break; #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(...) 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(...) 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(...) 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(...) 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(...) 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(...) 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_CLIENT_VERSION #define SSL_client_version(...) 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(...) 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_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_X509_GET0_EXT #define X509_get0_ext(crt, i) X509_get_ext((crt), (i)) #endif #if !HAVE_X509_CRL_GET0_EXT #define X509_CRL_get0_ext(crt, i) X509_CRL_get_ext((crt), (i)) #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 #if !HAVE_SSL_CTX_CERT_STORE || !HAVE_X509_STORE_REFERENCES #define SSL_CTX_set1_cert_store(ctx, store) \ SSL_CTX_set_cert_store((ctx), (store)) #else #define SSL_CTX_set1_cert_store(ctx, store) \ compat_SSL_CTX_set1_cert_store((ctx), (store)) /* to support preprocessor detection below */ #define compat_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) { 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); } /* compat_SSL_CTX_set1_cert_store() */ #endif #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 /* 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() */ #if !HAVE_X509_STORE_UP_REF #define X509_STORE_up_ref(...) 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(...) 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_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 static int compat_init(void) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static int store_index = -1, ssl_ctx_index = -1, done; int error = 0; if ((error = pthread_mutex_lock(&mutex))) return error; if (done) goto epilog; /* * 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; #if defined compat_X509_STORE_free /* * 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; } (void)pthread_mutex_unlock(&mutex); 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, }; 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 }, }; #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 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) { struct ex_data **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() */ static int ex_init(void) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static int done; struct ex_type *type; int error = 0; if ((error = pthread_mutex_lock(&mutex))) return error; 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: (void)pthread_mutex_unlock(&mutex); 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, (void *)&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, (void *)&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, (void *)&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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 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() */ static const auxL_Reg ossl_globals[] = { { "version", &ossl_version }, { 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 ssleay_version[] = { #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 { NULL, 0 }, }; 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, ssleay_version); auxL_pushinteger(L, OPENSSL_VERSION_NUMBER); lua_setfield(L, -2, "VERSION_NUMBER"); lua_pushstring(L, OPENSSL_VERSION_TEXT); lua_setfield(L, -2, "VERSION_TEXT"); lua_pushstring(L, SHLIB_VERSION_HISTORY); lua_setfield(L, -2, "SHLIB_VERSION_HISTORY"); lua_pushstring(L, SHLIB_VERSION_NUMBER); lua_setfield(L, -2, "SHLIB_VERSION_NUMBER"); #if defined LIBRESSL_VERSION_NUMBER auxL_pushinteger(L, LIBRESSL_VERSION_NUMBER); lua_setfield(L, -2, "LIBRESSL_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(...) 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 (!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() */ 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, (void *)&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, (void *)&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__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_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); int res = BN_is_prime_ex(bn, nchecks, getctx(L), NULL); 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 }, { "exp", &bn__pow }, { "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 }, }; 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, (void *)&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, (void *)&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); ud = prepsimple(L, PKEY_CLASS); if (lua_istable(L, 1) || lua_isnil(L, 1)) { int type = EVP_PKEY_RSA; unsigned bits = 1024; unsigned exp = 65537; int curve = NID_X9_62_prime192v1; const char *id; lua_Number n; if (!lua_istable(L, 1)) goto creat; if (loadfield(L, 1, "type", LUA_TSTRING, &id)) { static const struct { int nid; const char *sn; } types[] = { { EVP_PKEY_RSA, "RSA" }, { EVP_PKEY_DSA, "DSA" }, { EVP_PKEY_DH, "DH" }, { EVP_PKEY_EC, "EC" }, }; unsigned i; if (NID_undef == (type = EVP_PKEY_type(OBJ_sn2nid(id)))) { for (i = 0; i < countof(types); i++) { if (strieq(id, types[i].sn)) { type = types[i].nid; break; } } } luaL_argcheck(L, type != NID_undef, 1, lua_pushfstring(L, "%s: invalid key type", id)); } if (loadfield(L, 1, "bits", LUA_TNUMBER, &n)) { luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `bits' invalid", n)); bits = (unsigned)n; } if (loadfield(L, 1, "exp", LUA_TNUMBER, &n)) { luaL_argcheck(L, n > 0 && n < UINT_MAX, 1, lua_pushfstring(L, "%f: `exp' invalid", n)); exp = (unsigned)n; } if (loadfield(L, 1, "curve", LUA_TSTRING, &id)) { if (!auxS_txt2nid(&curve, id)) luaL_argerror(L, 1, lua_pushfstring(L, "%s: invalid curve", id)); } creat: if (!(*ud = EVP_PKEY_new())) return auxL_error(L, auxL_EOPENSSL, "pkey.new"); switch (EVP_PKEY_type(type)) { case EVP_PKEY_RSA: { RSA *rsa; if (!(rsa = RSA_generate_key(bits, exp, 0, 0))) 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 (!(dsa = DSA_generate_parameters(bits, 0, 0, 0, 0, 0, 0))) 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 (!(dh = DH_generate_parameters(bits, exp, 0, 0))) 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 (!(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: return luaL_error(L, "%d: unsupported EVP_PKEY base type", EVP_PKEY_type(type)); } /* 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); 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_optint(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_optint(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; if (LUAL_BUFFERSIZE < EVP_PKEY_size(key)) return luaL_error(L, "pkey:sign: LUAL_BUFFERSIZE(%u) < EVP_PKEY_size(%u)", (unsigned)LUAL_BUFFERSIZE, (unsigned)EVP_PKEY_size(key)); luaL_buffinit(L, &B); n = LUAL_BUFFERSIZE; if (!EVP_SignFinal(md, (void *)luaL_prepbuffer(&B), &n, key)) return auxL_error(L, auxL_EOPENSSL, "pkey:sign"); luaL_addsize(&B, n); luaL_pushresult(&B); return 1; } /* pk_sign() */ static int pk_verify(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, 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_pushstring(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, }; /* 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; 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 (_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, void *base_key, enum pk_param which) { union { RSA *rsa; DH *dh; DSA *dsa; #ifndef OPENSSL_NO_EC EC_KEY *ec; #endif } key = { base_key }; const BIGNUM *i; switch (which) { case PK_RSA_N: /* RSA public modulus n */ RSA_get0_key(key.rsa, &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_RSA_E: /* RSA public exponent e */ RSA_get0_key(key.rsa, NULL, &i, NULL); bn_dup_nil(L, i); break; case PK_RSA_D: /* RSA secret exponent d */ RSA_get0_key(key.rsa, NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_RSA_P: /* RSA secret prime p */ RSA_get0_factors(key.rsa, &i, NULL); bn_dup_nil(L, i); break; case PK_RSA_Q: /* RSA secret prime q with p < q */ RSA_get0_factors(key.rsa, NULL, &i); bn_dup_nil(L, i); break; case PK_RSA_DMP1: /* exponent1 */ RSA_get0_crt_params(key.rsa, &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_RSA_DMQ1: /* exponent2 */ RSA_get0_crt_params(key.rsa, NULL, &i, NULL); bn_dup_nil(L, i); break; case PK_RSA_IQMP: /* coefficient */ RSA_get0_crt_params(key.rsa, NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_DSA_P: DSA_get0_pqg(key.dsa, &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_DSA_Q: DSA_get0_pqg(key.dsa, NULL, &i, NULL); bn_dup_nil(L, i); break; case PK_DSA_G: DSA_get0_pqg(key.dsa, NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_DSA_PUB_KEY: DSA_get0_key(key.dsa, &i, NULL); bn_dup_nil(L, i); break; case PK_DSA_PRIV_KEY: DSA_get0_key(key.dsa, NULL, &i); bn_dup_nil(L, i); break; case PK_DH_P: DH_get0_pqg(key.dh, &i, NULL, NULL); bn_dup_nil(L, i); break; case PK_DH_G: DH_get0_pqg(key.dh, NULL, NULL, &i); bn_dup_nil(L, i); break; case PK_DH_PUB_KEY: DH_get0_key(key.dh, &i, NULL); bn_dup_nil(L, i); break; case PK_DH_PRIV_KEY: DH_get0_key(key.dh, NULL, &i); bn_dup_nil(L, i); break; #ifndef OPENSSL_NO_EC case PK_EC_GROUP: ecg_dup_nil(L, EC_KEY_get0_group(key.ec)); break; case PK_EC_PUB_KEY: { const EC_GROUP *group; const EC_POINT *pub_key; if ((group = EC_KEY_get0_group(key.ec)) && (pub_key = EC_KEY_get0_public_key(key.ec))) { bn_dup_nil(L, EC_POINT_point2bn(group, pub_key, EC_KEY_get_conv_form(key.ec), NULL, getctx(L))); } else { lua_pushnil(L); } break; } case PK_EC_PRIV_KEY: bn_dup_nil(L, EC_KEY_get0_private_key(key.ec)); 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, void *base_key, enum pk_param which, int index) { union { RSA *rsa; DH *dh; DSA *dsa; #ifndef OPENSSL_NO_EC EC_KEY *ec; #endif } key = { base_key }; BIGNUM *i; switch (which) { case PK_RSA_N: pk_setparam_bn_dup(L, index, &i); RSA_set0_key(key.rsa, i, NULL, NULL); break; case PK_RSA_E: pk_setparam_bn_dup(L, index, &i); RSA_set0_key(key.rsa, NULL, i, NULL); break; case PK_RSA_D: pk_setparam_bn_dup(L, index, &i); RSA_set0_key(key.rsa, NULL, NULL, i); break; case PK_RSA_P: pk_setparam_bn_dup(L, index, &i); RSA_set0_factors(key.rsa, i, NULL); break; case PK_RSA_Q: pk_setparam_bn_dup(L, index, &i); RSA_set0_factors(key.rsa, NULL, i); break; case PK_RSA_DMP1: pk_setparam_bn_dup(L, index, &i); RSA_set0_crt_params(key.rsa, i, NULL, NULL); break; case PK_RSA_DMQ1: pk_setparam_bn_dup(L, index, &i); RSA_set0_crt_params(key.rsa, NULL, i, NULL); break; case PK_RSA_IQMP: pk_setparam_bn_dup(L, index, &i); RSA_set0_crt_params(key.rsa, NULL, NULL, i); break; case PK_DSA_P: pk_setparam_bn_dup(L, index, &i); DSA_set0_pqg(key.dsa, i, NULL, NULL); break; case PK_DSA_Q: pk_setparam_bn_dup(L, index, &i); DSA_set0_pqg(key.dsa, NULL, i, NULL); break; case PK_DSA_G: pk_setparam_bn_dup(L, index, &i); DSA_set0_pqg(key.dsa, NULL, NULL, i); break; case PK_DSA_PUB_KEY: pk_setparam_bn_dup(L, index, &i); DSA_set0_key(key.dsa, i, NULL); break; case PK_DSA_PRIV_KEY: pk_setparam_bn_dup(L, index, &i); DSA_set0_key(key.dsa, NULL, i); break; case PK_DH_P: pk_setparam_bn_dup(L, index, &i); DH_set0_pqg(key.dh, i, NULL, NULL); break; case PK_DH_G: pk_setparam_bn_dup(L, index, &i); DH_set0_pqg(key.dh, NULL, NULL, i); break; case PK_DH_PUB_KEY: pk_setparam_bn_dup(L, index, &i); DH_set0_key(key.dh, i, NULL); break; case PK_DH_PRIV_KEY: pk_setparam_bn_dup(L, index, &i); DH_set0_key(key.dh, 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(key.ec, 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(key.ec))) 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(key.ec, 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(key.ec, n)) goto sslerr; 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); void *base_key; const char *const *optlist; int nopts, optoffset, otop, index, tindex; if (!(base_key = EVP_PKEY_get0(key))) goto sslerr; 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_pushstring(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, base_key, optid); if (tindex) { lua_setfield(L, tindex, optname); } } } return lua_gettop(L) - otop; sslerr: return auxL_error(L, auxL_EOPENSSL, "pkey:getParameters"); } /* 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); void *base_key; const char *const *optlist; int optindex, optoffset; luaL_checktype(L, 2, LUA_TTABLE); if (!(base_key = EVP_PKEY_get0(key))) goto sslerr; 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, base_key, optindex + optoffset, -1); lua_pop(L, 1); } } return 0; sslerr: return auxL_error(L, auxL_EOPENSSL, "pkey:setParameters"); } /* 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); void *base_key; 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 (!(base_key = EVP_PKEY_get0(key))) 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, base_key, listoffset + optoffset); return 1; } /* pk__index() */ static int pk__newindex(lua_State *L) { EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS); void *base_key; const char *const *optlist; int optoffset, listoffset; if (!lua_isstring(L, 2)) return 0; if (!(base_key = EVP_PKEY_get0(key))) 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, base_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 }, #if HAVE_EVP_PKEY_CTX_NEW { "decrypt", &pk_decrypt }, { "encrypt", &pk_encrypt }, #endif { "sign", &pk_sign }, { "verify", &pk_verify }, { "getDefaultDigestName", &pk_getDefaultDigestName }, { "toPEM", &pk_toPEM }, { "getParameters", &pk_getParameters }, { "setParameters", &pk_setParameters }, { 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 { "RSA_SSLV23_PADDING", RSA_SSLV23_PADDING }, // SSLv23 padding { "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 HAVE_RSA_PKCS1_PSS_PADDING { "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING }, // (sign and verify only) #endif { NULL, 0 }, }; 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. */ 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_checkint(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_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[] = { { "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 */ 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 }, { 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 }, }; 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_pushstring(L, "email"); GN_PUSHSTRING(L, name->d.rfc822Name); break; case GEN_URI: lua_pushstring(L, "URI"); GN_PUSHSTRING(L, name->d.uniformResourceIdentifier); break; case GEN_DNS: lua_pushstring(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; len = strlen(txt); lua_pushstring(L, "IP"); lua_pushlstring(L, txt, len); break; case GEN_DIRNAME: lua_pushstring(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 }, }; 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 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; lua_settop(L, 3); ud = prepsimple(L, X509_EXT_CLASS); if (!lua_isnil(L, 3)) { size_t len; const char *cdata = luaL_checklstring(L, 3, &len); _Bool crit; if (xe_new_isder(value, &crit)) { 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; } BIO *bio = getbio(L); if (BIO_puts(bio, cdata) < 0) goto error; if (!(conf = NCONF_new(NULL))) goto error; if (!NCONF_load_bio(conf, bio, NULL)) goto error; ctx = &cbuf; X509V3_set_nconf(ctx, conf); } /* * 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 }, }; 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 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)) { 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_checkint(L, 2); if (!X509_set_version(crt, version - 1)) return luaL_error(L, "x509.cert:setVersion: %d: invalid version", version); lua_pushboolean(L, 1); return 1; } /* xc_setVersion() */ static int xc_getSerial(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); BIGNUM *serial = bn_push(L); ASN1_INTEGER *i; if ((i = X509_get_serialNumber(crt))) { if (!ASN1_INTEGER_to_BN(i, serial)) return 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; #if LUA_VERSION_NUM < 502 luaL_buffinit(L, &B); #else luaL_buffinitsize(L, &B, 2 * len); #endif for (i = 0; i < len; i++) { luaL_addchar(&B, x[0x0f & (md[i] >> 4)]); luaL_addchar(&B, x[0x0f & (md[i] >> 0)]); } luaL_pushresult(&B); break; } default: lua_pushlstring(L, (const char *)md, len); break; } /* switch() */ return 1; } /* xc_digest() */ static _Bool isleap(int year) { if (year >= 0) return !(year % 4) && ((year % 100) || !(year % 400)); else return isleap(-(year + 1)); } /* isleap() */ static int yday(int year, int mon, int mday) { static const int past[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int yday = past[CLAMP(mon, 0, 11)] + CLAMP(mday, 1, 31) - 1; return yday + (mon > 1 && isleap(year)); } /* yday() */ static int tm_yday(const struct tm *tm) { return (tm->tm_yday)? tm->tm_yday : yday(1900 + tm->tm_year, tm->tm_mon, tm->tm_mday); } /* tm_yday() */ static int leaps(int year) { if (year >= 0) return (year / 400) + (year / 4) - (year / 100); else return -(leaps(-(year + 1)) + 1); } /* leaps() */ static double tm2unix(const struct tm *tm, int gmtoff) { int year = tm->tm_year + 1900; double ts; ts = 86400.0 * 365.0 * (year - 1970); ts += 86400.0 * (leaps(year - 1) - leaps(1969)); ts += 86400 * tm_yday(tm); ts += 3600 * tm->tm_hour; ts += 60 * tm->tm_min; ts += CLAMP(tm->tm_sec, 0, 59); ts += (year < 1970)? gmtoff : -gmtoff; return ts; } /* tm2unix() */ static _Bool scan(int *i, char **cp, int n, int signok) { int sign = 1; *i = 0; if (signok) { if (**cp == '-') { sign = -1; ++*cp; } else if (**cp == '+') { ++*cp; } } while (n-- > 0) { if (**cp < '0' || **cp > '9') return 0; *i *= 10; *i += *(*cp)++ - '0'; } *i *= sign; return 1; } /* scan() */ static double timeutc(ASN1_TIME *time) { char buf[32] = "", *cp; struct tm tm = { 0 }; int gmtoff = 0, year, i; if (!ASN1_TIME_check(time)) return 0; cp = strncpy(buf, (const char *)ASN1_STRING_get0_data((ASN1_STRING *)time), sizeof buf - 1); if (ASN1_STRING_type(time) == V_ASN1_GENERALIZEDTIME) { if (!scan(&year, &cp, 4, 1)) goto badfmt; } else { if (!scan(&year, &cp, 2, 0)) goto badfmt; year += (year < 50)? 2000 : 1999; } tm.tm_year = year - 1900; if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_mon = CLAMP(i, 1, 12) - 1; if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_mday = CLAMP(i, 1, 31); tm.tm_yday = yday(year, tm.tm_mon, tm.tm_mday); if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_hour = CLAMP(i, 0, 23); if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_min = CLAMP(i, 0, 59); if (*cp >= '0' && *cp <= '9') { if (!scan(&i, &cp, 2, 0)) goto badfmt; tm.tm_sec = CLAMP(i, 0, 59); } if (*cp == '+' || *cp == '-') { int sign = (*cp++ == '-')? -1 : 1; int hh, mm; if (!scan(&hh, &cp, 2, 0) || !scan(&mm, &cp, 2, 0)) goto badfmt; gmtoff = (CLAMP(hh, 0, 23) * 3600) + (CLAMP(mm, 0, 59) * 60); gmtoff *= sign; } return tm2unix(&tm, gmtoff); badfmt: return INFINITY; } /* timeutc() */ static int xc_getLifetime(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); double begin = INFINITY, end = INFINITY; ASN1_TIME *time; if ((time = X509_get_notBefore(crt))) begin = timeutc(time); if ((time = X509_get_notAfter(crt))) end = timeutc(time); if (isfinite(begin)) lua_pushnumber(L, begin); else lua_pushnil(L); if (isfinite(end)) lua_pushnumber(L, end); else lua_pushnil(L); if (isfinite(begin) && isfinite(end) && begin <= end) lua_pushnumber(L, fabs(end - begin)); else lua_pushnumber(L, 0.0); return 3; } /* xc_getLifetime() */ static int xc_setLifetime(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); 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_optint(L, -1, pathLen); lua_pop(L, 1); lua_getfield(L, 2, "pathLenConstraint"); pathLen = luaL_optint(L, -1, pathLen); lua_pop(L, 1); if (!(bs = BASIC_CONSTRAINTS_new())) goto error; } else { lua_settop(L, 3); switch (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_checkint(L, 3); break; } if (!(bs = X509_get_ext_d2i(crt, NID_basic_constraints, &critical, 0))) { /* FIXME: detect whether error or just non-existent */ if (!(bs = BASIC_CONSTRAINTS_new())) goto error; } } if (CA != -1) bs->ca = CA; if (pathLen >= 0) { ASN1_INTEGER_free(bs->pathlen); if (!(bs->pathlen = 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_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 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() */ #if 0 /* * TODO: X509_get_signature_type always seems to return NID_undef. Are we * using it wrong or is it broken? */ static int xc_getSignatureName(lua_State *L) { X509 *crt = checksimple(L, 1, X509_CERT_CLASS); int nid; if (NID_undef == (nid = X509_get_signature_type(crt))) return 0; auxL_pushnid(L, nid); return 1; } /* xc_getSignatureName() */ #endif 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_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__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 }, { "getExtension", &xc_getExtension }, { "getExtensionCount", &xc_getExtensionCount }, { "isIssuedBy", &xc_isIssuedBy }, { "getPublicKey", &xc_getPublicKey }, { "setPublicKey", &xc_setPublicKey }, { "getPublicKeyDigest", &xc_getPublicKeyDigest }, #if 0 { "getSignatureName", &xc_getSignatureName }, #endif { "sign", &xc_sign }, { "text", &xc_text }, { "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 }, }; 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)) { 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_checkint(L, 2); if (!X509_REQ_set_version(csr, version - 1)) return luaL_error(L, "x509.csr:setVersion: %d: invalid version", version); lua_pushboolean(L, 1); return 1; } /* xr_setVersion() */ static int xr_getSubject(lua_State *L) { X509_REQ *crt = checksimple(L, 1, X509_CSR_CLASS); X509_NAME *name; if (!(name = X509_REQ_get_subject_name(crt))) return 0; xn_dup(L, name); return 1; } /* xr_getSubject() */ static int xr_setSubject(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); X509_NAME *name = checksimple(L, 2, X509_NAME_CLASS); if (!X509_REQ_set_subject_name(csr, name)) return 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.cert:getPublicKey"); return 1; } /* xr_getPublicKey() */ static int xr_setPublicKey(lua_State *L) { X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS); EVP_PKEY *key = checksimple(L, 2, 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_setExtensionByNid(lua_State *L, X509_REQ *csr, int target_nid, void* value) { 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 SAN * 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, 0, X509V3_ADD_REPLACE)) 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 lua_pushboolean(L, 1); return 1; error: if (sk) sk_X509_EXTENSION_pop_free(sk, X509_EXTENSION_free); return auxL_error(L, auxL_EOPENSSL, "x509.csr.setExtensionByNid"); } /* xr_setExtensionByNid() */ 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); return xr_setExtensionByNid(L, csr, NID_subject_alt_name, gens); } /* 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_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__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 }, { "sign", &xr_sign }, { "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 }, }; 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)) { ok = !!(*ud = d2i_X509_CRL_bio(tmp, NULL)); } BIO_free(tmp); if (!ok) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); } else { if (!(*ud = X509_CRL_new())) return auxL_error(L, auxL_EOPENSSL, "x509.crl.new"); X509_gmtime_adj(X509_CRL_get_lastUpdate(*ud), 0); } 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_checkint(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; ASN1_TIME *time; if ((time = X509_CRL_get_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); /* lastUpdate always present */ if (!ASN1_TIME_set(X509_CRL_get_lastUpdate(crl), updated)) return auxL_error(L, auxL_EOPENSSL, "x509.crl:setLastUpdate"); lua_pushboolean(L, 1); return 1; } /* xx_setLastUpdate() */ static int xx_getNextUpdate(lua_State *L) { X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS); double updateby = INFINITY; ASN1_TIME *time; if ((time = X509_CRL_get_nextUpdate(crl))) updateby = timeutc(time); if (isfinite(updateby)) lua_pushnumber(L, 1); 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 = NULL; if (X509_CRL_get_nextUpdate(crl)) { if (!ASN1_TIME_set(X509_CRL_get_nextUpdate(crl), updateby)) goto error; } else { if (!(time = ASN1_TIME_new())) goto error; if (!(ASN1_TIME_set(time, updateby))) goto error; if (!X509_CRL_set_nextUpdate(crl, time)) goto error; time = NULL; } lua_pushboolean(L, 1); return 1; error: if (time) 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() */ 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_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_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__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 }, { "addExtension", &xx_addExtension }, { "getExtension", &xx_getExtension }, { "getExtensionCount", &xx_getExtensionCount }, { "sign", &xx_sign }, { "text", &xx_text }, { "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 }, }; 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); X509 *crt; int i, n; if (copy) { if (!(*dst = sk_X509_new_null())) goto error; n = sk_X509_num(src); for (i = 0; i < n; i++) { if (!(crt = sk_X509_value(src, i))) continue; if (!(crt = X509_dup(crt))) goto error; if (!sk_X509_push(*dst, crt)) { X509_free(crt); goto error; } } } else { if (!(*dst = sk_X509_dup(src))) goto error; n = sk_X509_num(*dst); for (i = 0; i < n; i++) { if (!(crt = sk_X509_value(*dst, i))) continue; X509_up_ref(crt); } } return; error: auxL_error(L, auxL_EOPENSSL, "sk_X509_dup"); } /* xl_dup() */ static int xl_new(lua_State *L) { STACK_OF(X509) **chain = prepsimple(L, X509_CHAIN_CLASS); if (!(*chain = sk_X509_new_null())) return 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); ret = prepsimple(L, X509_CERT_CLASS); if (!(*ret = X509_dup(crt))) return auxL_error(L, auxL_EOPENSSL, "x509.chain:__next"); break; } lua_pushinteger(L, i); lua_replace(L, lua_upvalueindex(2)); return lua_gettop(L); } /* xl__next() */ static int xl__pairs(lua_State *L) { lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, &xl__next, 2); return 1; } /* xl__pairs() */ static int xl__gc(lua_State *L) { STACK_OF(X509) **chain = luaL_checkudata(L, 1, X509_CHAIN_CLASS); 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 }, }; 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 ok = X509_STORE_load_locations(store, path, NULL); 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 nr = 0, ok, why; /* pre-allocate space for a successful return */ lua_settop(L, 3); proof = prepsimple(L, X509_CHAIN_CLASS); if (!lua_isnoneornil(L, 3)) { X509 *elm; int i, n; if (!(chain = sk_X509_dup(checksimple(L, 3, X509_CHAIN_CLASS)))) goto eossl; n = sk_X509_num(chain); for (i = 0; i < n; i++) { if (!(elm = sk_X509_value(chain, i))) continue; X509_up_ref(elm); } } 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; lua_pushboolean(L, 1); lua_pushvalue(L, -2); nr = 2; break; case 0: /* not verified */ why = X509_STORE_CTX_get_error(ctx); lua_pushboolean(L, 0); lua_pushstring(L, X509_verify_cert_error_string(why)); nr = 2; break; default: goto eossl; } X509_STORE_CTX_free(ctx); return nr; 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 }, }; 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 }, }; 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__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 }, { NULL, NULL }, }; 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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * NOTE: TLS methods and flags were added in tandem. For example, if the * macro SSL_OP_NO_TLSv1_1 is defined we know TLSv1_1_server_method is also * declared and defined. */ 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] = "DTLS", [12] = "DTLSv1", [13] = "DTLSv1.0", [14] = "DTLSv1_2", [15] = "DTLSv1.2", NULL }; /* later versions of SSL declare a const qualifier on the return type */ __typeof__(&TLSv1_client_method) method = &TLSv1_client_method; _Bool srv; SSL_CTX **ud; int options = 0; lua_settop(L, 2); srv = lua_toboolean(L, 2); switch (auxL_checkoption(L, 1, "TLS", opts, 1)) { case 0: /* SSL */ method = (srv)? &SSLv23_server_method : &SSLv23_client_method; options = SSL_OP_NO_SSLv2; break; case 1: /* TLS */ method = (srv)? &SSLv23_server_method : &SSLv23_client_method; options = SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; break; #if HAVE_SSLV2_CLIENT_METHOD && HAVE_SSLV2_SERVER_METHOD case 2: /* SSLv2 */ method = (srv)? &SSLv2_server_method : &SSLv2_client_method; break; #endif #ifndef OPENSSL_NO_SSL3 case 3: /* SSLv3 */ method = (srv)? &SSLv3_server_method : &SSLv3_client_method; break; #endif case 4: /* SSLv23 */ method = (srv)? &SSLv23_server_method : &SSLv23_client_method; break; case 5: /* TLSv1 */ case 6: /* TLSv1.0 */ method = (srv)? &TLSv1_server_method : &TLSv1_client_method; break; #if defined SSL_OP_NO_TLSv1_1 case 7: /* TLSv1_1 */ case 8: /* TLSv1.1 */ method = (srv)? &TLSv1_1_server_method : &TLSv1_1_client_method; break; #endif #if defined SSL_OP_NO_TLSv1_2 case 9: /* TLSv1_2 */ case 10: /* TLSv1.2 */ method = (srv)? &TLSv1_2_server_method : &TLSv1_2_client_method; break; #endif #if HAVE_DTLS_CLIENT_METHOD case 11: /* DTLS */ method = (srv)? &DTLS_server_method : &DTLS_client_method; break; #endif #if HAVE_DTLSV1_CLIENT_METHOD case 12: /* DTLSv1 */ case 13: /* DTLSv1.0 */ method = (srv)? &DTLSv1_server_method : &DTLSv1_client_method; break; #endif #if HAVE_DTLSV1_2_CLIENT_METHOD case 14: /* DTLSv1_2 */ case 15: /* DTLSv1.2 */ method = (srv)? &DTLSv1_server_method : &DTLSv1_client_method; break; #endif default: return luaL_argerror(L, 1, "invalid option"); } ud = prepsimple(L, SSL_CTX_CLASS); if (!(*ud = SSL_CTX_new(method()))) return auxL_error(L, auxL_EOPENSSL, "ssl.context.new"); SSL_CTX_set_options(*ud, options); 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_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_optint(L, 2, -1); int depth = luaL_optint(L, 3, -1); if (mode != -1) SSL_CTX_set_verify(ctx, mode, 0); if (depth != -1) SSL_CTX_set_verify_depth(ctx, depth); lua_pushboolean(L, 1); return 1; } /* sx_setVerify() */ static int sx_getVerify(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); lua_pushinteger(L, SSL_CTX_get_verify_mode(ctx)); lua_pushinteger(L, SSL_CTX_get_verify_depth(ctx)); return 2; } /* sx_getVerify() */ static int sx_setCertificate(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); X509 *crt = X509_dup(checksimple(L, 2, X509_CERT_CLASS)); int ok; ok = SSL_CTX_use_certificate(ctx, crt); X509_free(crt); if (!ok) return auxL_error(L, auxL_EOPENSSL, "ssl.context:setCertificate"); lua_pushboolean(L, 1); return 1; } /* sx_setCertificate() */ static int sx_setPrivateKey(lua_State *L) { SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); EVP_PKEY *key = checksimple(L, 2, 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() */ 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_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 static SSL *ssl_push(lua_State *, SSL *); 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, tmpsiz; int otop, status; const void *proto; void *tmpbuf; *out = NULL; *outlen = 0; /* expect at least two values: return buffer and closure */ if ((n = ex_getdata(&L, EX_SSL_CTX_ALPN_SELECT_CB, ctx)) < 2) return SSL_TLSEXT_ERR_ALERT_FATAL; otop = lua_gettop(L) - n; /* TODO: Install temporary panic handler to catch OOM errors */ /* pass SSL object as 1st argument */ ssl_push(L, ssl); lua_insert(L, otop + 3); /* pass table of protocol names as 2nd argument */ pushprotos(L, in, inlen); lua_insert(L, otop + 4); if (LUA_OK != (status = lua_pcall(L, 2 + (n - 2), 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 (!(tmpbuf = lua_touserdata(L, otop + 1))) goto fatal; tmpsiz = lua_rawlen(L, otop + 1); if (protolen > tmpsiz) goto fatal; memcpy(tmpbuf, 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; *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); /* allocate space to store the selected protocol in our callback */ lua_newuserdata(L, UCHAR_MAX); lua_insert(L, 2); 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 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 }, { "setStore", &sx_setStore }, { "getStore", &sx_getStore }, { "setParam", &sx_setParam }, { "getParam", &sx_getParam }, { "setVerify", &sx_setVerify }, { "getVerify", &sx_getVerify }, { "setCertificate", &sx_setCertificate }, { "setPrivateKey", &sx_setPrivateKey }, { "setCipherList", &sx_setCipherList }, { "setEphemeralKey", &sx_setEphemeralKey }, #if HAVE_SSL_CTX_SET_ALPN_PROTOS { "setAlpnProtos", &sx_setAlpnProtos }, #endif #if HAVE_SSL_CTX_SET_ALPN_SELECT_CB { "setAlpnSelect", &sx_setAlpnSelect }, #endif { NULL, NULL }, }; static const auxL_Reg sx_metatable[] = { { "__gc", &sx__gc }, { NULL, NULL }, }; static const auxL_Reg sx_globals[] = { { "new", &sx_new }, { "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 }, { "OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG }, { "OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER }, { "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 }, #if defined SSL_OP_NO_TLSv1_1 { "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1 }, #endif { "OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS }, { "OP_ALL", SSL_OP_ALL }, { "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 }, #if defined 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 }, { "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE }, { "OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA }, { "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 }, #if defined SSL_OP_NO_TLSv1_2 { "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2 }, #endif { "OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 }, { "OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 }, { "OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG }, { "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG }, #if defined SSL_OP_CRYPTOPRO_TLSEXT_BUG { "OP_CRYPTOPRO_TLSEXT_BUG", SSL_OP_CRYPTOPRO_TLSEXT_BUG }, #endif { NULL, 0 }, }; int luaopen__openssl_ssl_context(lua_State *L) { initall(L); auxL_newlib(L, sx_globals, 0); auxL_setintegers(L, sx_verify); auxL_setintegers(L, sx_option); return 1; } /* luaopen__openssl_ssl_context() */ /* * SSL - openssl.ssl * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static SSL *ssl_push(lua_State *L, SSL *ssl) { SSL **ud = prepsimple(L, SSL_CLASS); SSL_up_ref(ssl); *ud = ssl; return *ud; } /* ssl_push() */ 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"); return 1; } /* ssl_new() */ static int ssl_interpose(lua_State *L) { return interpose(L, SSL_CLASS); } /* ssl_interpose() */ 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_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_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_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_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_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__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[] = { { "setOptions", &ssl_setOptions }, { "getOptions", &ssl_getOptions }, { "clearOptions", &ssl_clearOptions }, { "setParam", &ssl_setParam }, { "getParam", &ssl_getParam }, { "getVerifyResult", &ssl_getVerifyResult }, { "getPeerCertificate", &ssl_getPeerCertificate }, { "getPeerChain", &ssl_getPeerChain }, { "getCipherInfo", &ssl_getCipherInfo }, { "getHostName", &ssl_getHostName }, { "setHostName", &ssl_setHostName }, { "getVersion", &ssl_getVersion }, { "getClientVersion", &ssl_getClientVersion }, #if HAVE_SSL_GET0_ALPN_SELECTED { "getAlpnSelected", &ssl_getAlpnSelected }, #endif #if HAVE_SSL_SET_ALPN_PROTOS { "setAlpnProtos", &ssl_setAlpnProtos }, #endif { NULL, NULL }, }; static const auxL_Reg ssl_metatable[] = { { "__gc", &ssl__gc }, { NULL, NULL }, }; static const auxL_Reg ssl_globals[] = { { "new", &ssl_new }, { "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 }, }; int luaopen__openssl_ssl(lua_State *L) { initall(L); auxL_newlib(L, ssl_globals, 0); 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 = checksimple(L, 2, X509_VERIFY_PARAM_CLASS); int ret; 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 } }; 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_optdigest(lua_State *L, int index) { const char *name = luaL_optstring(L, index, "sha1"); const EVP_MD *type; if (!(type = EVP_get_digestbyname(name))) luaL_argerror(L, index, lua_pushfstring(L, "%s: invalid digest type", name)); return type; } /* md_optdigest() */ static int md_new(lua_State *L) { const EVP_MD *type = md_optdigest(L, 1); EVP_MD_CTX **ctx; ctx = 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 }, }; 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 }, }; 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); 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, *pe; size_t block, step, n; int i; block = EVP_CIPHER_CTX_block_size(ctx); if (LUAL_BUFFERSIZE < block * 2) luaL_error(L, "cipher:update: LUAL_BUFFERSIZE(%d) < 2 * EVP_CIPHER_CTX_block_size(%d)", (int)LUAL_BUFFERSIZE, (int)block); step = LUAL_BUFFERSIZE - block; for (i = from; i <= to; i++) { p = (const unsigned char *)luaL_checklstring(L, i, &n); pe = p + n; while (p < pe) { int in = (int)MIN((size_t)(pe - p), step), out; if (!EVP_CipherUpdate(ctx, (void *)luaL_prepbuffer(B), &out, p, in)) return 0; p += in; luaL_addsize(B, out); } } return 1; } /* cipher_update_() */ static int cipher_update(lua_State *L) { EVP_CIPHER_CTX *ctx = checksimple(L, 1, CIPHER_CLASS); luaL_Buffer B; luaL_buffinit(L, &B); if (!cipher_update_(L, ctx, &B, 2, lua_gettop(L))) goto sslerr; luaL_pushresult(&B); return 1; sslerr: lua_pushnil(L); 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; luaL_buffinit(L, &B); if (!cipher_update_(L, ctx, &B, 2, lua_gettop(L))) goto sslerr; block = EVP_CIPHER_CTX_block_size(ctx); if (LUAL_BUFFERSIZE < block) return luaL_error(L, "cipher:update: LUAL_BUFFERSIZE(%d) < EVP_CIPHER_CTX_block_size(%d)", (int)LUAL_BUFFERSIZE, (int)block); if (!EVP_CipherFinal(ctx, (void *)luaL_prepbuffer(&B), &out)) goto sslerr; luaL_addsize(&B, out); luaL_pushresult(&B); return 1; sslerr: lua_pushnil(L); auxL_pusherror(L, auxL_EOPENSSL, NULL); return 2; } /* cipher_final() */ static int cipher__gc(lua_State *L) { EVP_CIPHER_CTX **ctx = luaL_checkudata(L, 1, CIPHER_CLASS); EVP_CIPHER_CTX_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 }, { 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 }, }; int luaopen__openssl_cipher(lua_State *L) { initall(L); auxL_newlib(L, cipher_globals, 0); return 1; } /* luaopen__openssl_cipher() */ /* * Rand - openssl.rand * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct randL_state { pid_t pid; }; /* 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]; #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) goto syserr; 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(); return 0; syserr: error = errno; error:; struct { struct timeval tv; pid_t pid; struct rusage ru; struct utsname un; uintptr_t aslr; #if defined __APPLE__ uint64_t mt; #elif defined __sun struct timespec mt; #endif } junk; gettimeofday(&junk.tv, NULL); junk.pid = getpid(); getrusage(RUSAGE_SELF, &junk.ru); uname(&junk.un); 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); st->pid = getpid(); return error; } /* randL_stir() */ static void randL_checkpid(struct randL_state *st) { if (st->pid != getpid()) (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_checkint(L, 1); luaL_Buffer B; int count = 0, n; randL_checkpid(randL_getstate(L)); luaL_buffinit(L, &B); while (count < size) { n = MIN((size - count), LUAL_BUFFERSIZE); if (!RAND_bytes((void *)luaL_prepbuffer(&B), n)) return auxL_error(L, auxL_EOPENSSL, "rand.bytes"); luaL_addsize(&B, n); count += n; } luaL_pushresult(&B); return 1; } /* rand_bytes() */ static int rand_ready(lua_State *L) { lua_pushboolean(L, RAND_status() == 1); return 1; } /* rand_ready() */ static unsigned long long rand_llu(lua_State *L) { unsigned long long llu; if (!RAND_bytes((void *)&llu, sizeof llu)) 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; if (sizeof (lua_Unsigned) >= sizeof r) { N = luaL_checkunsigned(L, 1); } else { N = luaL_checknumber(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; } if (sizeof (lua_Unsigned) >= sizeof r) { lua_pushunsigned(L, r); } else { lua_pushnumber(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 }, }; 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 }, }; int luaopen__openssl_des(lua_State *L) { initall(L); auxL_newlib(L, des_globals, 0); return 1; } /* luaopen__openssl_des() */ /* * Multithread Reentrancy Protection * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static struct { pthread_mutex_t *lock; int nlock; } mt_state; static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUSED) { if (mode & CRYPTO_LOCK) pthread_mutex_lock(&mt_state.lock[type]); else pthread_mutex_unlock(&mt_state.lock[type]); } /* 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(); #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() */ static int mt_init(void) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static int done, bound; int error = 0; if ((error = pthread_mutex_lock(&mutex))) return error; 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 ((error = pthread_mutex_init(&mt_state.lock[i], NULL))) { while (i > 0) { pthread_mutex_destroy(&mt_state.lock[--i]); } 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: pthread_mutex_unlock(&mutex); return error; } /* mt_init() */ static void initall(lua_State *L) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static int initssl; int error; if ((error = mt_init())) auxL_error(L, error, "openssl.init"); pthread_mutex_lock(&mutex); if (!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); } pthread_mutex_unlock(&mutex); if ((error = compat_init())) auxL_error(L, error, "openssl.init"); if ((error = ex_init())) 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); } /* initall() */ luaossl-rel-20161214/src/openssl.cipher.lua000066400000000000000000000000611302434335300204410ustar00rootroot00000000000000local ctx = require"_openssl.cipher" return ctx luaossl-rel-20161214/src/openssl.des.lua000066400000000000000000000000561302434335300177460ustar00rootroot00000000000000local ctx = require"_openssl.des" return ctx luaossl-rel-20161214/src/openssl.digest.lua000066400000000000000000000000611302434335300204460ustar00rootroot00000000000000local ctx = require"_openssl.digest" return ctx luaossl-rel-20161214/src/openssl.hmac.lua000066400000000000000000000000571302434335300201040ustar00rootroot00000000000000local ctx = require"_openssl.hmac" return ctx luaossl-rel-20161214/src/openssl.lua000066400000000000000000000000311302434335300171650ustar00rootroot00000000000000return require"_openssl" luaossl-rel-20161214/src/openssl.pkcs12.lua000066400000000000000000000000421302434335300202710ustar00rootroot00000000000000return require('_openssl.pkcs12') luaossl-rel-20161214/src/openssl.pkey.lua000066400000000000000000000000621302434335300201400ustar00rootroot00000000000000local pkey = require"_openssl.pkey" return pkey luaossl-rel-20161214/src/openssl.pubkey.lua000066400000000000000000000000751302434335300204730ustar00rootroot00000000000000-- for backwards compatibility return require "openssl.pkey" luaossl-rel-20161214/src/openssl.rand.lua000066400000000000000000000000571302434335300201200ustar00rootroot00000000000000local ctx = require"_openssl.rand" return ctx luaossl-rel-20161214/src/openssl.ssl.context.lua000066400000000000000000000010111302434335300214470ustar00rootroot00000000000000local 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) return ctx luaossl-rel-20161214/src/openssl.ssl.lua000066400000000000000000000000561302434335300177740ustar00rootroot00000000000000local ctx = require"_openssl.ssl" return ctx luaossl-rel-20161214/src/openssl.x509.altname.lua000066400000000000000000000004171302434335300213210ustar00rootroot00000000000000local 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-20161214/src/openssl.x509.chain.lua000066400000000000000000000000711302434335300207560ustar00rootroot00000000000000local chain = require"_openssl.x509.chain" return chain luaossl-rel-20161214/src/openssl.x509.crl.lua000066400000000000000000000000441302434335300204540ustar00rootroot00000000000000return require('_openssl.x509.crl') luaossl-rel-20161214/src/openssl.x509.csr.lua000066400000000000000000000000441302434335300204630ustar00rootroot00000000000000return require('_openssl.x509.csr') luaossl-rel-20161214/src/openssl.x509.extension.lua000066400000000000000000000000521302434335300217070ustar00rootroot00000000000000return require('_openssl.x509.extension') luaossl-rel-20161214/src/openssl.x509.lua000066400000000000000000000000661302434335300177010ustar00rootroot00000000000000local x509 = require"_openssl.x509.cert" return x509 luaossl-rel-20161214/src/openssl.x509.name.lua000066400000000000000000000004031302434335300206130ustar00rootroot00000000000000local 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-20161214/src/openssl.x509.store.lua000066400000000000000000000000711302434335300210300ustar00rootroot00000000000000local store = require"_openssl.x509.store" return store luaossl-rel-20161214/src/openssl.x509.verify_param.lua000066400000000000000000000000551302434335300223620ustar00rootroot00000000000000return require('_openssl.x509.verify_param')