pax_global_header00006660000000000000000000000064136232672670014530gustar00rootroot0000000000000052 comment=3ea2ada80f1df13a2a60db98f6b927a0da8cf80f libfido2-1.3.1/000077500000000000000000000000001362326726700132245ustar00rootroot00000000000000libfido2-1.3.1/.github/000077500000000000000000000000001362326726700145645ustar00rootroot00000000000000libfido2-1.3.1/.github/workflows/000077500000000000000000000000001362326726700166215ustar00rootroot00000000000000libfido2-1.3.1/.github/workflows/windows.yml000066400000000000000000000002451362326726700210370ustar00rootroot00000000000000name: windows on: [push] jobs: build: runs-on: windows-latest steps: - uses: actions/checkout@v1 - name: build run: .\windows\build.ps1 libfido2-1.3.1/.gitignore000066400000000000000000000000721362326726700152130ustar00rootroot00000000000000build/ cscope.out fuzz/build/ fuzz/obj/ fuzz/*.so output/ libfido2-1.3.1/.travis.yml000066400000000000000000000037471362326726700153500ustar00rootroot00000000000000language: c matrix: include: - os: linux compiler: clang-7 dist: xenial sudo: required addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-7 packages: - clang-7 - cmake - libssl-dev - libudev-dev script: /bin/sh -eux .travis/build-linux-clang - os: linux compiler: gcc-7 dist: xenial sudo: required addons: apt: sources: - ubuntu-toolchain-r-test packages: - gcc-7 - cmake - libssl-dev - libudev-dev script: /bin/sh -eux .travis/build-linux-gcc - os: linux compiler: i686-w64-mingw32-gcc-4.8 dist: xenial sudo: required addons: apt: sources: - ubuntu-toolchain-r-test packages: - binutils-mingw-w64-i686 - gcc-mingw-w64 - g++-mingw-w64 - mingw-w64-i686-dev - cmake script: /bin/sh -eux .travis/build-linux-mingw - os: osx osx_image: xcode10.2 compiler: clang sudo: required script: /bin/sh -eux .travis/build-osx-clang - os: linux compiler: clang-7 dist: xenial sudo: required addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-7 packages: - clang-7 - cmake - libssl-dev - libudev-dev script: /bin/sh -eux .travis/fuzz-linux-asan - os: linux compiler: clang-7 dist: xenial sudo: required addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-7 packages: - clang-7 - cmake - libssl-dev - libudev-dev script: /bin/sh -eux .travis/fuzz-linux-msan notifications: email: false libfido2-1.3.1/.travis/000077500000000000000000000000001362326726700146125ustar00rootroot00000000000000libfido2-1.3.1/.travis/build-linux-clang000066400000000000000000000006701362326726700200560ustar00rootroot00000000000000#!/bin/sh -eux ${CC} --version # Check exports. (cd src && ./diff_exports.sh) # Build and install libcbor. git clone git://github.com/pjk/libcbor cd libcbor git checkout v0.5.0 mkdir build (cd build && cmake ..) make -C build sudo make -C build install cd .. # Build, analyze, and install libfido2. mkdir build (cd build && scan-build cmake -DCMAKE_BUILD_TYPE=Debug ..) scan-build --status-bugs make -C build sudo make -C build install libfido2-1.3.1/.travis/build-linux-gcc000066400000000000000000000005321362326726700175230ustar00rootroot00000000000000#!/bin/sh -eux ${CC} --version # Build and install libcbor. git clone git://github.com/pjk/libcbor cd libcbor git checkout v0.5.0 mkdir build (cd build && cmake ..) make -C build sudo make -C build install cd .. # Build and install libfido2. mkdir build (cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..) make -C build sudo make -C build install libfido2-1.3.1/.travis/build-linux-mingw000066400000000000000000000024031362326726700201070ustar00rootroot00000000000000#!/bin/sh -eux # XXX defining CC and cross-compiling confuses OpenSSL's build. unset CC sudo mkdir /fakeroot sudo chmod 755 /fakeroot cat << EOF > /tmp/mingw.cmake SET(CMAKE_SYSTEM_NAME Windows) SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc) SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) SET(CMAKE_FIND_ROOT_PATH /fakeroot) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) EOF # Build and install libcbor. git clone git://github.com/pjk/libcbor cd libcbor git checkout v0.5.0 mkdir build (cd build && cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/mingw.cmake \ -DCMAKE_INSTALL_PREFIX=/fakeroot ..) make -C build sudo make -C build install cd .. # Build and install OpenSSL 1.1.0j. git clone git://github.com/openssl/openssl cd openssl git checkout OpenSSL_1_1_0j ./Configure mingw --prefix=/fakeroot --openssldir=/fakeroot/openssl \ --cross-compile-prefix=i686-w64-mingw32- make sudo make install_sw cd .. # Build and install libfido2. export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig mkdir build (cd build && cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/mingw.cmake \ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/fakeroot ..) make -C build sudo make -C build install libfido2-1.3.1/.travis/build-osx-clang000066400000000000000000000007561362326726700175350ustar00rootroot00000000000000#!/bin/sh -eux ${CC} --version # Build and install libcbor. git clone git://github.com/pjk/libcbor cd libcbor git checkout v0.5.0 mkdir build (cd build && cmake ..) make -C build sudo make -C build install cd .. # Install mandoc from Homebrew. brew install mandoc # Build and install libfido2. export PKG_CONFIG_PATH=/usr/local/opt/openssl@1.1/lib/pkgconfig mkdir build (cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..) make -C build make -C build man_symlink_html sudo make -C build install libfido2-1.3.1/.travis/fuzz-linux-asan000066400000000000000000000034661362326726700176210ustar00rootroot00000000000000#!/bin/sh -eux ${CC} --version FAKEROOT=/fakeroot sudo mkdir ${FAKEROOT} sudo chmod 755 ${FAKEROOT} # Build and install libcbor. git clone git://github.com/pjk/libcbor cd libcbor patch -p0 < ../fuzz/README mkdir build cd build cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \ -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \ -DCMAKE_INSTALL_LIBDIR=lib .. make sudo make install cd ../.. # Build and install OpenSSL 1.1.1b. git clone git://github.com/openssl/openssl cd openssl git checkout OpenSSL_1_1_1b ./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \ --openssldir=${FAKEROOT}/openssl make clean make sudo make install_sw cd .. # Build libfido2. mkdir build cd build export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCMAKE_BUILD_TYPE=Debug .. make # Fuzz with ASAN. mkdir corpus tar -C corpus -zxf ../fuzz/corpus.tgz fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_cred fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_assert fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_credman fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_mgmt fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_bio libfido2-1.3.1/.travis/fuzz-linux-msan000066400000000000000000000035411362326726700176270ustar00rootroot00000000000000#!/bin/sh -eux ${CC} --version FAKEROOT=/fakeroot sudo mkdir ${FAKEROOT} sudo chmod 755 ${FAKEROOT} # Build and install libcbor. git clone git://github.com/pjk/libcbor cd libcbor patch -p0 < ../fuzz/README mkdir build cd build cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \ -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \ -DCMAKE_INSTALL_LIBDIR=lib .. make sudo make install cd ../.. # Build and install OpenSSL 1.1.1b. git clone git://github.com/openssl/openssl cd openssl git checkout OpenSSL_1_1_1b ./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \ --openssldir=${FAKEROOT}/openssl make clean make sudo make install_sw cd .. # Build libfido2. mkdir build cd build export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCMAKE_BUILD_TYPE=Debug .. make # Fuzz with MSAN. mkdir corpus tar -C corpus -zxf ../fuzz/corpus.tgz fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_cred fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_assert fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_credman fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_mgmt fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \ -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_bio libfido2-1.3.1/CMakeLists.txt000066400000000000000000000252601362326726700157710ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. # detect AppleClang; needs to come before project() cmake_policy(SET CMP0025 NEW) project(libfido2 C) cmake_minimum_required(VERSION 3.0) include(CheckCCompilerFlag) include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckTypeSize) include(GNUInstallDirs) set(CMAKE_COLOR_MAKEFILE off) set(CMAKE_VERBOSE_MAKEFILE on) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(FIDO_MAJOR "1") set(FIDO_MINOR "3") set(FIDO_PATCH "1") set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR}) add_definitions(-D_FIDO_MINOR=${FIDO_MINOR}) add_definitions(-D_FIDO_PATCH=${FIDO_PATCH}) if(WIN32) add_definitions(-DWIN32_LEAN_AND_MEAN) endif() if(APPLE) set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") endif() # /dev/urandom if(UNIX) add_definitions(-DHAS_DEV_URANDOM) endif() # Observe OpenBSD's library versioning scheme. if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") set(LIB_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}) set(LIB_SOVERSION ${LIB_VERSION}) else() set(LIB_VERSION ${FIDO_VERSION}) set(LIB_SOVERSION ${FIDO_MAJOR}) endif() if(MSVC) if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR (NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS)) message(FATAL_ERROR "please provide definitions for " "{CBOR,CRYPTO}_{INCLUDE,LIBRARY}_DIRS when building " "under msvc") endif() set(CBOR_LIBRARIES cbor) set(CRYPTO_LIBRARIES crypto-45) set(MSVC_DISABLED_WARNINGS_LIST "C4200" # nonstandard extension used: zero-sized array in # struct/union; "C4204" # nonstandard extension used: non-constant aggregate # initializer; "C4706" # assignment within conditional expression; "C4996" # The POSIX name for this item is deprecated. Instead, # use the ISO C and C++ conformant name ) # The construction in the following 3 lines was taken from LibreSSL's # CMakeLists.txt. string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR ${MSVC_DISABLED_WARNINGS_LIST}) string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 ${MSVC_DISABLED_WARNINGS_STR}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi") else() include(FindPkgConfig) pkg_search_module(CBOR libcbor) pkg_search_module(CRYPTO libcrypto REQUIRED) # XXX workaround libcbor's missing .pc file if(NOT CBOR_FOUND) check_include_files(cbor.h HAVE_CBOR_H) if(NOT HAVE_CBOR_H) message(FATAL_ERROR "could not find cbor header files") endif() set(CBOR_LIBRARIES "cbor") endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") pkg_search_module(UDEV libudev REQUIRED) set(UDEV_NAME "udev") # Define be32toh(). add_definitions(-D_GNU_SOURCE) elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") set(BASE_LIBRARIES usbhid) endif() if(MINGW) # MinGW is stuck with a flavour of C89. add_definitions(-DFIDO_NO_DIAGNOSTIC) add_definitions(-DWC_ERR_INVALID_CHARS=0x80) endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wwrite-strings") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wbad-function-cast") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic-errors") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g2") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer") if(FUZZ) if(LIBFUZZER) set(FUZZ_LDFLAGS "-fsanitize=fuzzer") endif() add_definitions(-DFIDO_FUZZ) endif() if(ASAN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,leak") endif() if(MSAN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins") endif() if(UBSAN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-trap=undefined") endif() if(COVERAGE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping") endif() endif() # Use -Wshorten-64-to-32 if available. check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32) if(HAVE_SHORTEN_64_TO_32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshorten-64-to-32") endif() # Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-result") endif() # Decide which keyword to use for thread-local storage. if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang") set(TLS "__thread") elseif(WIN32) set(TLS "__declspec(thread)") endif() add_definitions(-DTLS=${TLS}) # endian.h check_include_files(endian.h HAVE_ENDIAN_H) if(HAVE_ENDIAN_H) add_definitions(-DHAVE_ENDIAN_H) endif() # err.h check_include_files(err.h HAVE_ERR_H) if(HAVE_ERR_H) add_definitions(-DHAVE_ERR_H) endif() # unistd.h check_include_files(unistd.h HAVE_UNISTD_H) if(HAVE_UNISTD_H) add_definitions(-DHAVE_UNISTD_H) endif() # signal.h check_include_files(signal.h HAVE_SIGNAL_H) if(HAVE_SIGNAL_H) add_definitions(-DHAVE_SIGNAL_H) endif() # strlcpy check_function_exists(strlcpy HAVE_STRLCPY) if(HAVE_STRLCPY) add_definitions(-DHAVE_STRLCPY) endif() # strlcat check_function_exists(strlcpy HAVE_STRLCAT) if(HAVE_STRLCAT) add_definitions(-DHAVE_STRLCAT) endif() # recallocarray check_function_exists(recallocarray HAVE_RECALLOCARRAY) if(HAVE_RECALLOCARRAY) add_definitions(-DHAVE_RECALLOCARRAY) endif() # XXX getpagesize is incorrectly detected when cross-compiling # with mingw on Linux. Avoid. if(NOT WIN32) check_function_exists(getpagesize HAVE_GETPAGESIZE) endif() if(HAVE_GETPAGESIZE) add_definitions(-DHAVE_GETPAGESIZE) endif() # sysconf check_function_exists(sysconf HAVE_SYSCONF) if(HAVE_SYSCONF) add_definitions(-DHAVE_SYSCONF) endif() # memset_s if(APPLE) add_definitions(-D__STDC_WANT_LIB_EXT1__=1) endif() check_function_exists(memset_s HAVE_MEMSET_S) if(HAVE_MEMSET_S) add_definitions(-DHAVE_MEMSET_S) endif() # explicit_bzero if(NOT LIBFUZZER) check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) if(HAVE_EXPLICIT_BZERO) add_definitions(-DHAVE_EXPLICIT_BZERO) endif() endif() # timingsafe_bcmp check_function_exists(timingsafe_bcmp HAVE_TIMINGSAFE_BCMP) if(HAVE_TIMINGSAFE_BCMP) add_definitions(-DHAVE_TIMINGSAFE_BCMP) endif() # readpassphrase check_function_exists(readpassphrase HAVE_READPASSPHRASE) if(HAVE_READPASSPHRASE) add_definitions(-DHAVE_READPASSPHRASE) endif() # getline check_function_exists(getline HAVE_GETLINE) if(HAVE_GETLINE) add_definitions(-DHAVE_GETLINE) endif() # getopt check_function_exists(getopt HAVE_GETOPT) if(HAVE_GETOPT) add_definitions(-DHAVE_GETOPT) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual") else() if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-discarded-qualifiers") endif() if(CMAKE_C_COMPILER_ID STREQUAL "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers") endif() endif() # usable sigaction set(CMAKE_EXTRA_INCLUDE_FILES signal.h) check_function_exists(sigaction HAVE_SIGACTION) check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T) if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL "")) add_definitions(-DSIGNAL_EXAMPLE) endif() set(CMAKE_EXTRA_INCLUDE_FILES) # arc4random_buf check_function_exists(arc4random_buf HAVE_ARC4RANDOM_BUF) if(HAVE_ARC4RANDOM_BUF) add_definitions(-DHAVE_ARC4RANDOM_BUF) endif() # getentropy check_function_exists(getentropy HAVE_GETENTROPY) if(HAVE_GETENTROPY) add_definitions(-DHAVE_GETENTROPY) endif() # export list if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") # clang + lld string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/export.llvm") elseif(NOT MSVC) # clang/gcc + gnu ld string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/export.gnu") if(NOT WIN32) string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") string(CONCAT CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") if(FUZZ) file(STRINGS fuzz/wrapped.sym WRAPPED_SYMBOLS) foreach(s ${WRAPPED_SYMBOLS}) string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -Wl,--wrap=${s}") endforeach() endif() endif() else() string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"") endif() include_directories(${CMAKE_SOURCE_DIR}/src) include_directories(${CBOR_INCLUDE_DIRS}) include_directories(${CRYPTO_INCLUDE_DIRS}) link_directories(${CBOR_LIBRARY_DIRS}) link_directories(${CRYPTO_LIBRARY_DIRS}) message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}") message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}") message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}") message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}") message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}") message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}") message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}") message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}") message(STATUS "VERSION: ${FIDO_VERSION}") message(STATUS "LIB_VERSION: ${LIB_VERSION}") message(STATUS "LIB_SOVERSION: ${LIB_SOVERSION}") message(STATUS "FUZZ: ${FUZZ}") message(STATUS "AFL: ${AFL}") message(STATUS "LIBFUZZER: ${LIBFUZZER}") message(STATUS "ASAN: ${ASAN}") message(STATUS "MSAN: ${MSAN}") message(STATUS "COVERAGE: ${COVERAGE}") message(STATUS "TLS: ${TLS}") if(CMAKE_SYSTEM_NAME STREQUAL "Linux") message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}") message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}") message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}") message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}") endif() subdirs(src) subdirs(examples) subdirs(tools) subdirs(man) if(NOT WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(NOT MSAN AND NOT LIBFUZZER) subdirs(regress) endif() endif() if(FUZZ) subdirs(fuzz) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") subdirs(udev) endif() endif() libfido2-1.3.1/LICENSE000066400000000000000000000024451362326726700142360ustar00rootroot00000000000000Copyright (c) 2018 Yubico AB. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libfido2-1.3.1/NEWS000066400000000000000000000053051362326726700137260ustar00rootroot00000000000000* Version 1.3.1 (2020-02-19) ** fix zero-ing of le1 and le2 when talking to a U2F device. ** dropping sk-libfido2 middleware, please find it in the openssh tree. * Version 1.3.0 (2019-11-28) ** assert/hmac: encode public key as per spec, gh#60. ** fido2-cred: fix creation of resident keys. ** fido2-{assert,cred}: support for hmac-secret extension. ** hid_osx: detect device removal, gh#56. ** hid_osx: fix device detection in MacOS Catalina. ** New API calls: - fido_assert_set_authdata_raw; - fido_assert_sigcount; - fido_cred_set_authdata_raw; - fido_dev_cancel. ** Middleware library for use by OpenSSH. ** Support for biometric enrollment. ** Support for OpenBSD. ** Support for self-attestation. * Version 1.2.0 (released 2019-07-26) ** Credential management support. ** New API reflecting FIDO's 3-state booleans (true, false, absent): - fido_assert_set_up; - fido_assert_set_uv; - fido_cred_set_rk; - fido_cred_set_uv. ** Command-line tools for Windows. ** Documentation and reliability fixes. ** fido_{assert,cred}_set_options() are now marked as deprecated. * Version 1.1.0 (released 2019-05-08) ** MacOS: fix IOKit crash on HID read. ** Windows: fix contents of release file. ** EdDSA (Ed25519) support. ** fido_dev_make_cred: fix order of CBOR map keys. ** fido_dev_get_assert: plug memory leak when operating on U2F devices. * Version 1.0.0 (released 2019-03-21) ** Native HID support on Linux, MacOS, and Windows. ** fido2-{assert,cred}: new -u option to force U2F on dual authenticators. ** fido2-assert: support for multiple resident keys with the same RP. ** Strict checks for CTAP2 compliance on received CBOR payloads. ** Better fuzzing harnesses. ** Documentation and reliability fixes. * Version 0.4.0 (released 2019-01-07) ** fido2-assert: print the user id for resident credentials. ** Fix encoding of COSE algorithms when making a credential. ** Rework purpose of fido_cred_set_type; no ABI change. ** Minor documentation and code fixes. * Version 0.3.0 (released 2018-09-11) ** Various reliability fixes. ** Merged fuzzing instrumentation. ** Added regress tests. ** Added support for FIDO 2's hmac-secret extension. ** New API calls: - fido_assert_hmac_secret_len; - fido_assert_hmac_secret_ptr; - fido_assert_set_extensions; - fido_assert_set_hmac_salt; - fido_cred_set_extensions; - fido_dev_force_fido2. ** Support for native builds with Microsoft Visual Studio 17. * Version 0.2.0 (released 2018-06-20) ** Added command-line tools. ** Added a couple of missing get functions. * Version 0.1.1 (released 2018-06-05) ** Added documentation. ** Added OpenSSL 1.0 support. ** Minor fixes. * Version 0.1.0 (released 2018-05-18) ** First beta release. libfido2-1.3.1/README.adoc000066400000000000000000000051111362326726700150070ustar00rootroot00000000000000== libfido2 image:https://api.travis-ci.org/Yubico/libfido2.svg?branch=master["Build Status (Travis)", link="https://travis-ci.org/Yubico/libfido2"] image:https://github.com/yubico/libfido2/workflows/windows/badge.svg["windows build status (github actions)", link="https://github.com/Yubico/libfido2/actions"] image:https://img.shields.io/badge/license-BSD-blue.svg["License", link="https://raw.githubusercontent.com/Yubico/libfido2/master/LICENSE"] *libfido2* provides library functionality and command-line tools to communicate with a FIDO device over USB, and to verify attestation and assertion signatures. *libfido2* supports the FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2) protocols. For usage, see the `examples/` directory. === License *libfido2* is licensed under the BSD 2-clause license. See the _LICENSE_ file for the full license text. === Supported Platforms *libfido2* is known to work on Linux, MacOS, Windows, and OpenBSD. === Documentation Documentation is available in troff and HTML formats. An https://developers.yubico.com/libfido2/Manuals/[online mirror of *libfido2*'s documentation] is also available. === Installation ==== Releases The current release of *libfido2* is 1.3.1. Please consult Yubico's https://developers.yubico.com/libfido2/Releases[release page] for source and binary releases. ==== Ubuntu $ sudo apt-add-repository ppa:yubico/stable $ sudo apt update $ sudo apt install libfido2-dev Or from source, on UNIX-like systems: $ (rm -rf build && mkdir build && cd build && cmake ..) $ make -C build $ sudo make -C build install Depending on the platform, the PKG_CONFIG_PATH environment variable may need to be set. *libfido2* depends on https://github.com/pjk/libcbor[libcbor] and https://github.com/libressl-portable/portable[LibreSSL] (alternatively, https://www.openssl.org[OpenSSL] may be used). On Linux, libudev (part of https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also required. For complete, OS-specific installation instructions, please refer to the `.travis/` (Linux, MacOS) and `windows/` directories. On Linux, you will need to add a udev rule to be able to access the FIDO device, or run as root. For example, the udev rule may contain the following: ---- #udev rule for allowing HID access to Yubico devices for FIDO support. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \ MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050" ---- On Windows 1903 and newer versions, access to FIDO devices has been restricted to applications using the operating system's native API. Use of *libfido2* is still possible in privileged applications. libfido2-1.3.1/debian/000077500000000000000000000000001362326726700144465ustar00rootroot00000000000000libfido2-1.3.1/debian/changelog000066400000000000000000000051171362326726700163240ustar00rootroot00000000000000libfido2 (1.2.0~ppa1~bionic1) bionic; urgency=low * Credential management support. * New API reflecting FIDO's 3-state booleans (true, false, absent): - fido_assert_set_up; - fido_assert_set_uv; - fido_cred_set_rk; - fido_cred_set_uv. * Command-line tools for Windows. * Documentation and reliability fixes. * fido_{assert,cred}_set_options() are now marked as deprecated. -- pedro martelletto Fri, 23 Aug 2019 12:08:02 +0000 libfido2 (1.1.0) bionic; urgency=low * MacOS: fix IOKit crash on HID read. * Windows: fix contents of release file. * EdDSA (Ed25519) support. * fido_dev_make_cred: fix order of CBOR map keys. * fido_dev_get_assert: plug memory leak when operating on U2F devices. -- pedro martelletto Tue, 07 May 2019 08:03:21 +0000 libfido2 (1.0.0) bionic; urgency=low * Native HID support on Linux, MacOS, and Windows. * fido2-{assert,cred}: new -u option to force U2F on dual authenticators. * fido2-assert: support for multiple resident keys with the same RP. * Strict checks for CTAP2 compliance on received CBOR payloads. * Better fuzzing harnesses. * Documentation and reliability fixes. -- pedro martelletto Tue, 19 Mar 2019 07:38:36 +0000 libfido2 (0.4.0) bionic; urgency=low * fido2-assert: print the user id for resident credentials. * Fix encoding of COSE algorithms when making a credential. * Rework purpose of fido_cred_set_type; no ABI change. * Minor documentation and code fixes. -- pedro martelletto Mon, 07 Jan 2019 08:22:01 +0000 libfido2 (0.3.0) bionic; urgency=low * Various reliability fixes. * Merged fuzzing instrumentation. * Added regress tests. * Added support for FIDO 2's hmac-secret extension. * New API calls: - fido_assert_hmac_secret_len; - fido_assert_hmac_secret_ptr; - fido_assert_set_extensions; - fido_assert_set_hmac_salt; - fido_cred_set_extensions; - fido_dev_force_fido2. * Support for native builds with Microsoft Visual Studio 17. -- pedro martelletto Tue, 11 Sep 2018 09:05:32 +0000 libfido2 (0.2.0) bionic; urgency=low * Added command-line tools. * Added a couple of missing get functions. -- pedro martelletto Mon, 18 Jun 2018 10:44:11 +0000 libfido2 (0.1.1~dev) bionic; urgency=low * Added documentation. * Minor fixes. -- pedro martelletto Wed, 30 May 2018 13:16:28 +0000 libfido2 (0.1.0~dev) bionic; urgency=low * Initial release. -- pedro martelletto Fri, 18 May 2018 08:47:01 +0000 libfido2-1.3.1/debian/compat000066400000000000000000000000021362326726700156440ustar00rootroot000000000000009 libfido2-1.3.1/debian/control000066400000000000000000000035671362326726700160640ustar00rootroot00000000000000Source: libfido2 Priority: optional Maintainer: Yubico Open Source Maintainers Uploaders: pedro martelletto Standards-Version: 4.1.2 Section: libs Homepage: https://github.com/yubico/libfido2 Build-Depends: debhelper (>= 9), pkg-config, cmake, mandoc, libcbor-dev, libssl-dev, libudev-dev Package: libfido2-1 Architecture: any Multi-Arch: same Depends: libcbor0, libssl1.1, libudev1, ${shlibs:Depends}, ${misc:Depends} Description: library for generating and verifying FIDO 2.0 objects A library for communicating with a FIDO device over USB, and for verifying attestation and assertion signatures. FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2) are supported. This package contains the runtime library. Package: libfido2-dev Section: libdevel Architecture: any Multi-Arch: same Depends: libfido2-1 (= ${binary:Version}), ${misc:Depends} Suggests: libssl-dev Description: library for generating and verifying FIDO 2.0 objects (development headers) A library for communicating with a FIDO device over USB, and for verifying attestation and assertion signatures. FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2) are supported. This package contains the development headers. Package: fido2-tools Section: utils Architecture: any Multi-Arch: foreign Depends: libfido2-1 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Description: command-line tools to configure and use a FIDO 2 token A set of tools to manage a FIDO 2 token, generate credentials and assertions, and verify them. Package: libfido2-udev Section: libs Architecture: all Multi-Arch: foreign Depends: ${misc:Depends} Conflicts: libu2f-udev Description: udev rules for access to U2F and FIDO2 devices A set of udev rules allowing unprivileged system-level access to U2F and FIDO2 USB devices for logged-on users. libfido2-1.3.1/debian/copyright000066400000000000000000000067441362326726700164140ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: libfido2 Source: https://github.com/yubico/libfido2 Files: * Copyright: Copyright (c) 2018 Yubico AB. All rights reserved. License: BSD-2-clause Files: openbsd-compat/strlcpy.c openbsd-compat/strlcat.c Copyright: Copyright (c) 1998 Todd C. Miller License: ISC Files: src/compat/timingsafe_bcmp.c Copyright: Copyright (c) 2010 Damien Miller. All rights reserved. License: ISC Files: openbsd-compat/bsd-getpagesize.c openbsd-compat/err.h openbsd-compat/explicit_bzero.c openbsd-compat/explicit_bzero_win32.c openbsd-compat/types.h Copyright: Public domain License: public-domain Files: openbsd-compat/recallocarray.c Copyright: Copyright (c) 2008, 2017 Otto Moerbeek License: ISC Files: openbsd-compat/readpassphrase.h Copyright: Copyright (c) 2000, 2002 Todd C. Miller License: ISC Files: openbsd-compat/readpassphrase.c Copyright: Copyright (c) 2000-2002, 2007, 2010 Todd C. Miller License: ISC Files: openbsd-compat/getopt.h Copyright: Copyright (c) 2000 The NetBSD Foundation, Inc. All rights reserved. License: BSD-2-clause Files: openbsd-compat/getopt_long.c Copyright: Copyright (c) 2002 Todd C. Miller Copyright (c) 2000 The NetBSD Foundation, Inc. All rights reserved. License: ISC and BSD-2-clause License: BSD-2-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: public-domain Public domain. License: ISC Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. . THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. libfido2-1.3.1/debian/fido2-tools.install000066400000000000000000000000101362326726700201660ustar00rootroot00000000000000usr/bin libfido2-1.3.1/debian/fido2-tools.manpages000066400000000000000000000000661362326726700203260ustar00rootroot00000000000000man/fido2-assert.1 man/fido2-cred.1 man/fido2-token.1 libfido2-1.3.1/debian/libfido2-1.install000066400000000000000000000000301362326726700176570ustar00rootroot00000000000000usr/lib/*/libfido2.so.* libfido2-1.3.1/debian/libfido2-1.symbols000066400000000000000000000114521362326726700177130ustar00rootroot00000000000000libfido2.so.1 libfido2-1 #MINVER# eddsa_pk_free@Base 1.1.0 eddsa_pk_from_EVP_PKEY@Base 1.1.0 eddsa_pk_from_ptr@Base 1.1.0 eddsa_pk_new@Base 1.1.0 eddsa_pk_to_EVP_PKEY@Base 1.1.0 es256_pk_free@Base 1.1.0 es256_pk_from_EC_KEY@Base 1.1.0 es256_pk_from_ptr@Base 1.1.0 es256_pk_new@Base 1.1.0 es256_pk_to_EVP_PKEY@Base 1.1.0 fido_assert_allow_cred@Base 1.1.0 fido_assert_authdata_len@Base 1.1.0 fido_assert_authdata_ptr@Base 1.1.0 fido_assert_clientdata_hash_len@Base 1.1.0 fido_assert_clientdata_hash_ptr@Base 1.1.0 fido_assert_count@Base 1.1.0 fido_assert_flags@Base 1.1.0 fido_assert_free@Base 1.1.0 fido_assert_hmac_secret_len@Base 1.1.0 fido_assert_hmac_secret_ptr@Base 1.1.0 fido_assert_id_len@Base 1.1.0 fido_assert_id_ptr@Base 1.1.0 fido_assert_new@Base 1.1.0 fido_assert_rp_id@Base 1.1.0 fido_assert_set_authdata@Base 1.1.0 fido_assert_set_clientdata_hash@Base 1.1.0 fido_assert_set_count@Base 1.1.0 fido_assert_set_extensions@Base 1.1.0 fido_assert_set_hmac_salt@Base 1.1.0 fido_assert_set_options@Base 1.1.0 fido_assert_set_rp@Base 1.1.0 fido_assert_set_sig@Base 1.1.0 fido_assert_set_up@Base 1.2.0 fido_assert_set_uv@Base 1.2.0 fido_assert_sig_len@Base 1.1.0 fido_assert_sig_ptr@Base 1.1.0 fido_assert_user_display_name@Base 1.1.0 fido_assert_user_icon@Base 1.1.0 fido_assert_user_id_len@Base 1.1.0 fido_assert_user_id_ptr@Base 1.1.0 fido_assert_user_name@Base 1.1.0 fido_assert_verify@Base 1.1.0 fido_cbor_info_aaguid_len@Base 1.1.0 fido_cbor_info_aaguid_ptr@Base 1.1.0 fido_cbor_info_extensions_len@Base 1.1.0 fido_cbor_info_extensions_ptr@Base 1.1.0 fido_cbor_info_free@Base 1.1.0 fido_cbor_info_maxmsgsiz@Base 1.1.0 fido_cbor_info_new@Base 1.1.0 fido_cbor_info_options_len@Base 1.1.0 fido_cbor_info_options_name_ptr@Base 1.1.0 fido_cbor_info_options_value_ptr@Base 1.1.0 fido_cbor_info_protocols_len@Base 1.1.0 fido_cbor_info_protocols_ptr@Base 1.1.0 fido_cbor_info_versions_len@Base 1.1.0 fido_cbor_info_versions_ptr@Base 1.1.0 fido_cred_authdata_len@Base 1.1.0 fido_cred_authdata_ptr@Base 1.1.0 fido_cred_clientdata_hash_len@Base 1.1.0 fido_cred_clientdata_hash_ptr@Base 1.1.0 fido_cred_display_name@Base 1.2.0 fido_cred_exclude@Base 1.1.0 fido_cred_flags@Base 1.1.0 fido_cred_fmt@Base 1.1.0 fido_cred_free@Base 1.1.0 fido_cred_id_len@Base 1.1.0 fido_cred_id_ptr@Base 1.1.0 fido_cred_new@Base 1.1.0 fido_cred_pubkey_len@Base 1.1.0 fido_cred_pubkey_ptr@Base 1.1.0 fido_cred_rp_id@Base 1.1.0 fido_cred_rp_name@Base 1.1.0 fido_cred_set_authdata@Base 1.1.0 fido_cred_set_clientdata_hash@Base 1.1.0 fido_cred_set_extensions@Base 1.1.0 fido_cred_set_fmt@Base 1.1.0 fido_cred_set_options@Base 1.1.0 fido_cred_set_rk@Base 1.2.0 fido_cred_set_rp@Base 1.1.0 fido_cred_set_sig@Base 1.1.0 fido_cred_set_type@Base 1.1.0 fido_cred_set_user@Base 1.1.0 fido_cred_set_uv@Base 1.2.0 fido_cred_set_x509@Base 1.1.0 fido_cred_sig_len@Base 1.1.0 fido_cred_sig_ptr@Base 1.1.0 fido_cred_type@Base 1.2.0 fido_cred_user_id_len@Base 1.2.0 fido_cred_user_id_ptr@Base 1.2.0 fido_cred_user_name@Base 1.2.0 fido_cred_verify@Base 1.1.0 fido_cred_x5c_len@Base 1.1.0 fido_cred_x5c_ptr@Base 1.1.0 fido_credman_del_dev_rk@Base 1.2.0 fido_credman_get_dev_metadata@Base 1.2.0 fido_credman_get_dev_rk@Base 1.2.0 fido_credman_get_dev_rp@Base 1.2.0 fido_credman_metadata_free@Base 1.2.0 fido_credman_metadata_new@Base 1.2.0 fido_credman_rk@Base 1.2.0 fido_credman_rk_count@Base 1.2.0 fido_credman_rk_existing@Base 1.2.0 fido_credman_rk_free@Base 1.2.0 fido_credman_rk_new@Base 1.2.0 fido_credman_rk_remaining@Base 1.2.0 fido_credman_rp_count@Base 1.2.0 fido_credman_rp_free@Base 1.2.0 fido_credman_rp_id@Base 1.2.0 fido_credman_rp_id_hash_len@Base 1.2.0 fido_credman_rp_id_hash_ptr@Base 1.2.0 fido_credman_rp_name@Base 1.2.0 fido_credman_rp_new@Base 1.2.0 fido_dev_build@Base 1.1.0 fido_dev_close@Base 1.1.0 fido_dev_flags@Base 1.1.0 fido_dev_force_fido2@Base 1.1.0 fido_dev_force_u2f@Base 1.1.0 fido_dev_free@Base 1.1.0 fido_dev_get_assert@Base 1.1.0 fido_dev_get_cbor_info@Base 1.1.0 fido_dev_get_retry_count@Base 1.1.0 fido_dev_info_free@Base 1.1.0 fido_dev_info_manifest@Base 1.1.0 fido_dev_info_manufacturer_string@Base 1.1.0 fido_dev_info_new@Base 1.1.0 fido_dev_info_path@Base 1.1.0 fido_dev_info_product@Base 1.1.0 fido_dev_info_product_string@Base 1.1.0 fido_dev_info_ptr@Base 1.1.0 fido_dev_info_vendor@Base 1.1.0 fido_dev_is_fido2@Base 1.1.0 fido_dev_major@Base 1.1.0 fido_dev_make_cred@Base 1.1.0 fido_dev_minor@Base 1.1.0 fido_dev_new@Base 1.1.0 fido_dev_open@Base 1.1.0 fido_dev_protocol@Base 1.1.0 fido_dev_reset@Base 1.1.0 fido_dev_set_io_functions@Base 1.1.0 fido_dev_set_pin@Base 1.1.0 fido_init@Base 1.1.0 fido_strerr@Base 1.1.0 rs256_pk_free@Base 1.1.0 rs256_pk_from_RSA@Base 1.1.0 rs256_pk_from_ptr@Base 1.1.0 rs256_pk_new@Base 1.1.0 rs256_pk_to_EVP_PKEY@Base 1.1.0 libfido2-1.3.1/debian/libfido2-dev.install000066400000000000000000000016231362326726700203060ustar00rootroot00000000000000usr/include usr/lib/*/*.so usr/lib/*/pkgconfig/*.pc usr/share/doc/libfido2/es256_pk.html usr/share/doc/libfido2/fido.html usr/share/doc/libfido2/fido_assert.html usr/share/doc/libfido2/fido_assert_allow_cred.html usr/share/doc/libfido2/fido_assert_set.html usr/share/doc/libfido2/fido_assert_verify.html usr/share/doc/libfido2/fido_cbor_info.html usr/share/doc/libfido2/fido_cred.html usr/share/doc/libfido2/fido_cred_exclude.html usr/share/doc/libfido2/fido_cred_set.html usr/share/doc/libfido2/fido_cred_verify.html usr/share/doc/libfido2/fido_dev_get_assert.html usr/share/doc/libfido2/fido_dev_info_manifest.html usr/share/doc/libfido2/fido_dev_make_cred.html usr/share/doc/libfido2/fido_dev_open.html usr/share/doc/libfido2/fido_dev_set_io_functions.html usr/share/doc/libfido2/fido_dev_set_pin.html usr/share/doc/libfido2/fido_strerr.html usr/share/doc/libfido2/rs256_pk.html usr/share/doc/libfido2/style.css libfido2-1.3.1/debian/libfido2-dev.links000066400000000000000000000303061362326726700177600ustar00rootroot00000000000000/usr/share/man/man3/es256_pk.3 /usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk.3 /usr/share/man/man3/es256_pk_free.3 /usr/share/man/man3/es256_pk.3 /usr/share/man/man3/es256_pk_from_EC_KEY.3 /usr/share/man/man3/es256_pk.3 /usr/share/man/man3/es256_pk_from_ptr.3 /usr/share/man/man3/es256_pk.3 /usr/share/man/man3/es256_pk_to_EVP_PKEY.3 /usr/share/man/man3/fido.3 /usr/share/man/man3/fido_init.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_free.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_count.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_user_display_name.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_user_icon.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_user_name.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_authdata_ptr.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_clientdata_hash_ptr.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_user_id_ptr.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_sig_ptr.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_authdata_len.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_clientdata_hash_len.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_user_id_len.3 /usr/share/man/man3/fido_assert.3 /usr/share/man/man3/fido_assert_sig_len.3 /usr/share/man/man3/fido_assert_set.3 /usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set.3 /usr/share/man/man3/fido_assert_set_clientdata_hash.3 /usr/share/man/man3/fido_assert_set.3 /usr/share/man/man3/fido_assert_set_count.3 /usr/share/man/man3/fido_assert_set.3 /usr/share/man/man3/fido_assert_set_options.3 /usr/share/man/man3/fido_assert_set.3 /usr/share/man/man3/fido_assert_set_rp.3 /usr/share/man/man3/fido_assert_set.3 /usr/share/man/man3/fido_assert_set_sig.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_free.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_fmt.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_authdata_ptr.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_clientdata_hash_ptr.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_id_ptr.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_pubkey_ptr.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_sig_ptr.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_x5c_ptr.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_authdata_len.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_clientdata_hash_len.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_id_len.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_pubkey_len.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_sig_len.3 /usr/share/man/man3/fido_cred.3 /usr/share/man/man3/fido_cred_x5c_len.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_x509.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_sig.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_clientdata_hash.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_rp.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_user.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_options.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_fmt.3 /usr/share/man/man3/fido_cred_set.3 /usr/share/man/man3/fido_cred_set_type.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_new.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_free.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_ptr.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_path.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_product.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_vendor.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_manufacturer_string.3 /usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_product_string.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_close.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_new.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_free.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_is_fido2.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_protocol.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_build.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_flags.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_major.3 /usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_minor.3 /usr/share/man/man3/fido_dev_set_pin.3 /usr/share/man/man3/fido_dev_get_retry_count.3 /usr/share/man/man3/fido_dev_set_pin.3 /usr/share/man/man3/fido_dev_reset.3 /usr/share/man/man3/rs256_pk.3 /usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk.3 /usr/share/man/man3/rs256_pk_free.3 /usr/share/man/man3/rs256_pk.3 /usr/share/man/man3/rs256_pk_from_RSA.3 /usr/share/man/man3/rs256_pk.3 /usr/share/man/man3/rs256_pk_from_ptr.3 /usr/share/man/man3/rs256_pk.3 /usr/share/man/man3/rs256_pk_to_EVP_PKEY.3 /usr/share/doc/libfido2/es256_pk.html /usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk.html /usr/share/doc/libfido2/es256_pk_free.html /usr/share/doc/libfido2/es256_pk.html /usr/share/doc/libfido2/es256_pk_from_EC_KEY.html /usr/share/doc/libfido2/es256_pk.html /usr/share/doc/libfido2/es256_pk_from_ptr.html /usr/share/doc/libfido2/es256_pk.html /usr/share/doc/libfido2/es256_pk_to_EVP_PKEY.html /usr/share/doc/libfido2/fido.html /usr/share/doc/libfido2/fido_init.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_free.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_count.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_user_display_name.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_user_icon.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_user_name.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_authdata_ptr.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_clientdata_hash_ptr.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_user_id_ptr.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_sig_ptr.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_authdata_len.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_clientdata_hash_len.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_user_id_len.html /usr/share/doc/libfido2/fido_assert.html /usr/share/doc/libfido2/fido_assert_sig_len.html /usr/share/doc/libfido2/fido_assert_set.html /usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set.html /usr/share/doc/libfido2/fido_assert_set_clientdata_hash.html /usr/share/doc/libfido2/fido_assert_set.html /usr/share/doc/libfido2/fido_assert_set_count.html /usr/share/doc/libfido2/fido_assert_set.html /usr/share/doc/libfido2/fido_assert_set_options.html /usr/share/doc/libfido2/fido_assert_set.html /usr/share/doc/libfido2/fido_assert_set_rp.html /usr/share/doc/libfido2/fido_assert_set.html /usr/share/doc/libfido2/fido_assert_set_sig.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_free.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_fmt.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_authdata_ptr.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_clientdata_hash_ptr.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_id_ptr.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_pubkey_ptr.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_sig_ptr.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_x5c_ptr.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_authdata_len.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_clientdata_hash_len.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_id_len.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_pubkey_len.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_sig_len.html /usr/share/doc/libfido2/fido_cred.html /usr/share/doc/libfido2/fido_cred_x5c_len.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_x509.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_sig.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_clientdata_hash.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_rp.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_user.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_options.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_fmt.html /usr/share/doc/libfido2/fido_cred_set.html /usr/share/doc/libfido2/fido_cred_set_type.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_new.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_free.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_ptr.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_path.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_product.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_vendor.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_docufacturer_string.html /usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_product_string.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_close.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_new.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_free.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_is_fido2.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_protocol.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_build.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_flags.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_major.html /usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_minor.html /usr/share/doc/libfido2/fido_dev_set_pin.html /usr/share/doc/libfido2/fido_dev_get_retry_count.html /usr/share/doc/libfido2/fido_dev_set_pin.html /usr/share/doc/libfido2/fido_dev_reset.html /usr/share/doc/libfido2/rs256_pk.html /usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk.html /usr/share/doc/libfido2/rs256_pk_free.html /usr/share/doc/libfido2/rs256_pk.html /usr/share/doc/libfido2/rs256_pk_from_RSA.html /usr/share/doc/libfido2/rs256_pk.html /usr/share/doc/libfido2/rs256_pk_from_ptr.html /usr/share/doc/libfido2/rs256_pk.html /usr/share/doc/libfido2/rs256_pk_to_EVP_PKEY.html libfido2-1.3.1/debian/libfido2-dev.manpages000066400000000000000000000006341362326726700204340ustar00rootroot00000000000000man/es256_pk.3 man/fido.3 man/fido_assert.3 man/fido_assert_allow_cred.3 man/fido_assert_set.3 man/fido_assert_verify.3 man/fido_cbor_info.3 man/fido_cred.3 man/fido_cred_exclude.3 man/fido_cred_set.3 man/fido_cred_verify.3 man/fido_dev_get_assert.3 man/fido_dev_info_manifest.3 man/fido_dev_make_cred.3 man/fido_dev_open.3 man/fido_dev_set_io_functions.3 man/fido_dev_set_pin.3 man/fido_strerr.3 man/rs256_pk.3 libfido2-1.3.1/debian/libfido2-udev.install000066400000000000000000000000211362326726700204620ustar00rootroot00000000000000lib/udev/rules.d libfido2-1.3.1/debian/rules000077500000000000000000000002731362326726700155300ustar00rootroot00000000000000#!/usr/bin/make -f DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) %: dh $@ override_dh_auto_configure: dh_auto_configure -- -DUDEV_RULES_DIR=/lib/udev/rules.d libfido2-1.3.1/debian/source/000077500000000000000000000000001362326726700157465ustar00rootroot00000000000000libfido2-1.3.1/debian/source/format000066400000000000000000000000151362326726700171550ustar00rootroot000000000000003.0 (native) libfido2-1.3.1/docker/000077500000000000000000000000001362326726700144735ustar00rootroot00000000000000libfido2-1.3.1/docker/bionic/000077500000000000000000000000001362326726700157365ustar00rootroot00000000000000libfido2-1.3.1/docker/bionic/Dockerfile000066400000000000000000000012051362326726700177260ustar00rootroot00000000000000# unlock-yk # docker run --rm --volume=/home/pedro/projects/libfido2:/workdir \ # --volume=$(gpgconf --list-dirs socketdir):/root/.gnupg \ # --volume=$(gpgconf --list-dirs homedir)/pubring.kbx:/root/.gnupg/pubring.kbx \ # -it libfido2-staging --install-deps --ppa martelletto/ppa \ # --key pedro@yubico.com FROM ubuntu:bionic ENV DEBIAN_FRONTEND noninteractive RUN apt-get -qq update && apt-get -qq upgrade RUN apt-get install -qq packaging-dev debian-keyring devscripts equivs gnupg python sudo ADD https://raw.githubusercontent.com/dainnilsson/scripts/master/make-ppa /make-ppa RUN chmod +x /make-ppa WORKDIR /workdir ENTRYPOINT ["/make-ppa"] libfido2-1.3.1/examples/000077500000000000000000000000001362326726700150425ustar00rootroot00000000000000libfido2-1.3.1/examples/CMakeLists.txt000066400000000000000000000021131362326726700175770ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. list(APPEND COMPAT_SOURCES ../openbsd-compat/getopt_long.c ../openbsd-compat/strlcat.c ../openbsd-compat/strlcpy.c ) if(WIN32) list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c) endif() # drop -rdynamic set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # manifest add_executable(manifest manifest.c ${COMPAT_SOURCES}) target_link_libraries(manifest fido2) # info add_executable(info info.c ${COMPAT_SOURCES}) target_link_libraries(info fido2) # reset add_executable(reset reset.c util.c ${COMPAT_SOURCES}) target_link_libraries(reset fido2) # cred add_executable(cred cred.c util.c ${COMPAT_SOURCES}) target_link_libraries(cred fido2) # assert add_executable(assert assert.c util.c ${COMPAT_SOURCES}) target_link_libraries(assert fido2) # setpin add_executable(setpin setpin.c ${COMPAT_SOURCES}) target_link_libraries(setpin fido2) # retries add_executable(retries retries.c ${COMPAT_SOURCES}) target_link_libraries(retries fido2) libfido2-1.3.1/examples/README.adoc000066400000000000000000000053501362326726700166320ustar00rootroot00000000000000= Examples === Definitions The following definitions are used in the description below: - The file system path or subsystem-specific identification string of a FIDO device. - , [oldpin] Strings passed directly in the executed command's argument vector. - The file system path of a file containing a FIDO credential ID in binary representation. - The file system path of a file containing a NIST P-256 public key in PEM format. === Description The following examples are provided: - manifest Prints a list of configured FIDO devices. - info Prints information about . - reset Performs a factory reset on . - setpin [oldpin] Configures as the new PIN of . If [oldpin] is provided, the device's PIN is changed from [oldpin] to . - cred [-t ecdsa|rsa|eddsa] [-k pubkey] [-ei cred_id] [-P pin] [-T seconds] [-hruv] Creates a new credential on and verify that the credential was signed by the authenticator. The device's attestation certificate is not verified. If option -k is specified, the credential's public key is stored in . If option -i is specified, the credential ID is stored in . The -e option may be used to add to the list of excluded credentials. If option -h is specified, the hmac-secret FIDO2 extension is enabled on the generated credential. If option -r is specified, the generated credential will involve a resident key. User verification may be requested through the -v option. If option -u is specified, the credential is generated using U2F (CTAP1) instead of FIDO2 (CTAP2) commands. The -T option may be used to enforce a timeout of . - assert [-t ecdsa|rsa|eddsa] [-a cred_id] [-h hmac_secret] [-s hmac_salt] [-P pin] [-T seconds] [-puv] Asks for a FIDO2 assertion corresponding to [cred_id], which may be omitted for resident keys. The obtained assertion is verified using . The -p option requests that the user be present. User verification may be requested through the -v option. If option -u is specified, the assertion is generated using U2F (CTAP1) instead of FIDO2 (CTAP2) commands. If option -s is specified, a FIDO2 hmac-secret is requested from the authenticator, and the contents of are used as the salt. If option -h is specified, the resulting hmac-secret is stored in . The -T option may be used to enforce a timeout of . - retries Get the number of PIN attempts left on before lockout. Debugging is possible through the use of the FIDO_DEBUG environment variable. If set, libfido2 will produce a log of its transactions with the authenticator. libfido2-1.3.1/examples/assert.c000066400000000000000000000175321362326726700165170ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" #include "extern.h" #ifdef SIGNAL_EXAMPLE extern volatile sig_atomic_t got_signal; #endif static const unsigned char cdh[32] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, }; static void usage(void) { fprintf(stderr, "usage: assert [-t ecdsa|rsa|eddsa] [-a cred_id] " "[-h hmac_secret] [-s hmac_salt] [-P pin] [-T seconds] [-puv] " " \n"); exit(EXIT_FAILURE); } static void verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len, const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext, const char *key) { fido_assert_t *assert = NULL; EC_KEY *ec = NULL; RSA *rsa = NULL; EVP_PKEY *eddsa = NULL; es256_pk_t *es256_pk = NULL; rs256_pk_t *rs256_pk = NULL; eddsa_pk_t *eddsa_pk = NULL; void *pk; int r; /* credential pubkey */ switch (type) { case COSE_ES256: if ((ec = read_ec_pubkey(key)) == NULL) errx(1, "read_ec_pubkey"); if ((es256_pk = es256_pk_new()) == NULL) errx(1, "es256_pk_new"); if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) errx(1, "es256_pk_from_EC_KEY"); pk = es256_pk; EC_KEY_free(ec); ec = NULL; break; case COSE_RS256: if ((rsa = read_rsa_pubkey(key)) == NULL) errx(1, "read_rsa_pubkey"); if ((rs256_pk = rs256_pk_new()) == NULL) errx(1, "rs256_pk_new"); if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) errx(1, "rs256_pk_from_RSA"); pk = rs256_pk; RSA_free(rsa); rsa = NULL; break; case COSE_EDDSA: if ((eddsa = read_eddsa_pubkey(key)) == NULL) errx(1, "read_eddsa_pubkey"); if ((eddsa_pk = eddsa_pk_new()) == NULL) errx(1, "eddsa_pk_new"); if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) errx(1, "eddsa_pk_from_EVP_PKEY"); pk = eddsa_pk; EVP_PKEY_free(eddsa); eddsa = NULL; break; default: errx(1, "unknown credential type %d", type); } if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); /* client data hash */ r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); if (r != FIDO_OK) errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_assert_set_rp(assert, "localhost"); if (r != FIDO_OK) errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); /* authdata */ r = fido_assert_set_count(assert, 1); if (r != FIDO_OK) errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r); r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len); if (r != FIDO_OK) errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r); /* extension */ r = fido_assert_set_extensions(assert, ext); if (r != FIDO_OK) errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), r); /* user presence */ if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); /* sig */ r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len); if (r != FIDO_OK) errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r); r = fido_assert_verify(assert, 0, type, pk); if (r != FIDO_OK) errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r); es256_pk_free(&es256_pk); rs256_pk_free(&rs256_pk); eddsa_pk_free(&eddsa_pk); fido_assert_free(&assert); } int main(int argc, char **argv) { bool up = false; bool uv = false; bool u2f = false; fido_dev_t *dev = NULL; fido_assert_t *assert = NULL; const char *pin = NULL; const char *hmac_out = NULL; unsigned char *body = NULL; long long seconds = 0; size_t len; int type = COSE_ES256; int ext = 0; int ch; int r; if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); while ((ch = getopt(argc, argv, "P:T:a:h:ps:t:uv")) != -1) { switch (ch) { case 'P': pin = optarg; break; case 'T': #ifndef SIGNAL_EXAMPLE errx(1, "-T not supported"); #endif if (base10(optarg, &seconds) < 0) errx(1, "base10: %s", optarg); if (seconds <= 0 || seconds > 30) errx(1, "-T: %s must be in (0,30]", optarg); break; case 'a': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); if ((r = fido_assert_allow_cred(assert, body, len)) != FIDO_OK) errx(1, "fido_assert_allow_cred: %s (0x%x)", fido_strerr(r), r); free(body); body = NULL; break; case 'h': hmac_out = optarg; break; case 'p': up = true; break; case 's': ext = FIDO_EXT_HMAC_SECRET; if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); if ((r = fido_assert_set_hmac_salt(assert, body, len)) != FIDO_OK) errx(1, "fido_assert_set_hmac_salt: %s (0x%x)", fido_strerr(r), r); free(body); body = NULL; break; case 't': if (strcmp(optarg, "ecdsa") == 0) type = COSE_ES256; else if (strcmp(optarg, "rsa") == 0) type = COSE_RS256; else if (strcmp(optarg, "eddsa") == 0) type = COSE_EDDSA; else errx(1, "unknown type %s", optarg); break; case 'u': u2f = true; break; case 'v': uv = true; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 2) usage(); fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); r = fido_dev_open(dev, argv[1]); if (r != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); if (u2f) fido_dev_force_u2f(dev); /* client data hash */ r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); if (r != FIDO_OK) errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_assert_set_rp(assert, "localhost"); if (r != FIDO_OK) errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); /* extensions */ r = fido_assert_set_extensions(assert, ext); if (r != FIDO_OK) errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), r); /* user presence */ if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); #ifdef SIGNAL_EXAMPLE prepare_signal_handler(SIGINT); if (seconds) { prepare_signal_handler(SIGALRM); alarm((unsigned)seconds); } #endif r = fido_dev_get_assert(dev, assert, pin); if (r != FIDO_OK) { #ifdef SIGNAL_EXAMPLE if (got_signal) fido_dev_cancel(dev); #endif errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r); } r = fido_dev_close(dev); if (r != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); if (fido_assert_count(assert) != 1) errx(1, "fido_assert_count: %d signatures returned", (int)fido_assert_count(assert)); verify_assert(type, fido_assert_authdata_ptr(assert, 0), fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); if (hmac_out != NULL) { /* extract the hmac secret */ if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0), fido_assert_hmac_secret_len(assert, 0)) < 0) errx(1, "write_blob"); } fido_assert_free(&assert); exit(0); } libfido2-1.3.1/examples/cred.c000066400000000000000000000170451362326726700161320ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" #include "extern.h" #ifdef SIGNAL_EXAMPLE extern volatile sig_atomic_t got_signal; #endif static const unsigned char cdh[32] = { 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, }; static const unsigned char user_id[32] = { 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, }; static void usage(void) { fprintf(stderr, "usage: cred [-t ecdsa|rsa|eddsa] [-k pubkey] " "[-ei cred_id] [-P pin] [-T seconds] [-hruv] \n"); exit(EXIT_FAILURE); } static void verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr, size_t authdata_len, const unsigned char *x509_ptr, size_t x509_len, const unsigned char *sig_ptr, size_t sig_len, bool rk, bool uv, int ext, const char *key_out, const char *id_out) { fido_cred_t *cred; int r; if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); /* type */ r = fido_cred_set_type(cred, type); if (r != FIDO_OK) errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); /* client data hash */ r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); if (r != FIDO_OK) errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); if (r != FIDO_OK) errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); /* authdata */ r = fido_cred_set_authdata(cred, authdata_ptr, authdata_len); if (r != FIDO_OK) errx(1, "fido_cred_set_authdata: %s (0x%x)", fido_strerr(r), r); /* extensions */ r = fido_cred_set_extensions(cred, ext); if (r != FIDO_OK) errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); /* resident key */ if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); /* x509 */ r = fido_cred_set_x509(cred, x509_ptr, x509_len); if (r != FIDO_OK) errx(1, "fido_cred_set_x509: %s (0x%x)", fido_strerr(r), r); /* sig */ r = fido_cred_set_sig(cred, sig_ptr, sig_len); if (r != FIDO_OK) errx(1, "fido_cred_set_sig: %s (0x%x)", fido_strerr(r), r); /* fmt */ r = fido_cred_set_fmt(cred, fmt); if (r != FIDO_OK) errx(1, "fido_cred_set_fmt: %s (0x%x)", fido_strerr(r), r); r = fido_cred_verify(cred); if (r != FIDO_OK) errx(1, "fido_cred_verify: %s (0x%x)", fido_strerr(r), r); if (key_out != NULL) { /* extract the credential pubkey */ if (type == COSE_ES256) { if (write_ec_pubkey(key_out, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) errx(1, "write_ec_pubkey"); } else if (type == COSE_RS256) { if (write_rsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) errx(1, "write_rsa_pubkey"); } else if (type == COSE_EDDSA) { if (write_eddsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) errx(1, "write_eddsa_pubkey"); } } if (id_out != NULL) { /* extract the credential id */ if (write_blob(id_out, fido_cred_id_ptr(cred), fido_cred_id_len(cred)) < 0) errx(1, "write_blob"); } fido_cred_free(&cred); } int main(int argc, char **argv) { bool rk = false; bool uv = false; bool u2f = false; fido_dev_t *dev; fido_cred_t *cred = NULL; const char *pin = NULL; const char *key_out = NULL; const char *id_out = NULL; unsigned char *body = NULL; long long seconds = 0; size_t len; int type = COSE_ES256; int ext = 0; int ch; int r; if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); while ((ch = getopt(argc, argv, "P:T:e:hi:k:rt:uv")) != -1) { switch (ch) { case 'P': pin = optarg; break; case 'T': #ifndef SIGNAL_EXAMPLE errx(1, "-T not supported"); #endif if (base10(optarg, &seconds) < 0) errx(1, "base10: %s", optarg); if (seconds <= 0 || seconds > 30) errx(1, "-T: %s must be in (0,30]", optarg); break; case 'e': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); r = fido_cred_exclude(cred, body, len); if (r != FIDO_OK) errx(1, "fido_cred_exclude: %s (0x%x)", fido_strerr(r), r); free(body); body = NULL; break; case 'h': ext = FIDO_EXT_HMAC_SECRET; break; case 'i': id_out = optarg; break; case 'k': key_out = optarg; break; case 'r': rk = true; break; case 't': if (strcmp(optarg, "ecdsa") == 0) type = COSE_ES256; else if (strcmp(optarg, "rsa") == 0) type = COSE_RS256; else if (strcmp(optarg, "eddsa") == 0) type = COSE_EDDSA; else errx(1, "unknown type %s", optarg); break; case 'u': u2f = true; break; case 'v': uv = true; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, argv[0])) != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); if (u2f) fido_dev_force_u2f(dev); /* type */ r = fido_cred_set_type(cred, type); if (r != FIDO_OK) errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); /* client data hash */ r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); if (r != FIDO_OK) errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); if (r != FIDO_OK) errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); /* user */ r = fido_cred_set_user(cred, user_id, sizeof(user_id), "john smith", "jsmith", NULL); if (r != FIDO_OK) errx(1, "fido_cred_set_user: %s (0x%x)", fido_strerr(r), r); /* extensions */ r = fido_cred_set_extensions(cred, ext); if (r != FIDO_OK) errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); /* resident key */ if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); #ifdef SIGNAL_EXAMPLE prepare_signal_handler(SIGINT); if (seconds) { prepare_signal_handler(SIGALRM); alarm((unsigned)seconds); } #endif r = fido_dev_make_cred(dev, cred, pin); if (r != FIDO_OK) { #ifdef SIGNAL_EXAMPLE if (got_signal) fido_dev_cancel(dev); #endif errx(1, "fido_makecred: %s (0x%x)", fido_strerr(r), r); } r = fido_dev_close(dev); if (r != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), rk, uv, ext, key_out, id_out); fido_cred_free(&cred); exit(0); } libfido2-1.3.1/examples/extern.h000066400000000000000000000015601362326726700165220ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _EXTERN_H_ #define _EXTERN_H_ #include #include #include #ifdef HAVE_SIGNAL_H #include #endif /* util.c */ EC_KEY *read_ec_pubkey(const char *); RSA *read_rsa_pubkey(const char *); EVP_PKEY *read_eddsa_pubkey(const char *); int base10(const char *, long long *); int read_blob(const char *, unsigned char **, size_t *); int write_blob(const char *, const unsigned char *, size_t); int write_ec_pubkey(const char *, const void *, size_t); int write_rsa_pubkey(const char *, const void *, size_t); int write_eddsa_pubkey(const char *, const void *, size_t); #ifdef SIGNAL_EXAMPLE void prepare_signal_handler(int); #endif #endif /* _EXTERN_H_ */ libfido2-1.3.1/examples/info.c000066400000000000000000000107711362326726700161470ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" /* * Pretty-print a device's capabilities flags and return the result. */ static void format_flags(char *ret, size_t retlen, uint8_t flags) { memset(ret, 0, retlen); if (flags & FIDO_CAP_WINK) { if (strlcat(ret, "wink,", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, "nowink,", retlen) >= retlen) goto toolong; } if (flags & FIDO_CAP_CBOR) { if (strlcat(ret, " cbor,", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, " nocbor,", retlen) >= retlen) goto toolong; } if (flags & FIDO_CAP_NMSG) { if (strlcat(ret, " nomsg", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, " msg", retlen) >= retlen) goto toolong; } return; toolong: strlcpy(ret, "toolong", retlen); } /* * Print a FIDO device's attributes on stdout. */ static void print_attr(const fido_dev_t *dev) { char flags_txt[128]; printf("proto: 0x%02x\n", fido_dev_protocol(dev)); printf("major: 0x%02x\n", fido_dev_major(dev)); printf("minor: 0x%02x\n", fido_dev_minor(dev)); printf("build: 0x%02x\n", fido_dev_build(dev)); format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); } /* * Auxiliary function to print an array of strings on stdout. */ static void print_str_array(const char *label, char * const *sa, size_t len) { if (len == 0) return; printf("%s strings: ", label); for (size_t i = 0; i < len; i++) printf("%s%s", i > 0 ? ", " : "", sa[i]); printf("\n"); } /* * Auxiliary function to print (char *, bool) pairs on stdout. */ static void print_opt_array(const char *label, char * const *name, const bool *value, size_t len) { if (len == 0) return; printf("%s: ", label); for (size_t i = 0; i < len; i++) printf("%s%s%s", i > 0 ? ", " : "", value[i] ? "" : "no", name[i]); printf("\n"); } /* * Auxiliary function to print an authenticator's AAGUID on stdout. */ static void print_aaguid(const unsigned char *buf, size_t buflen) { printf("aaguid: "); while (buflen--) printf("%02x", *buf++); printf("\n"); } /* * Auxiliary function to print an authenticator's maximum message size on * stdout. */ static void print_maxmsgsiz(uint64_t maxmsgsiz) { printf("maxmsgsiz: %d\n", (int)maxmsgsiz); } /* * Auxiliary function to print an array of bytes on stdout. */ static void print_byte_array(const char *label, const uint8_t *ba, size_t len) { if (len == 0) return; printf("%s: ", label); for (size_t i = 0; i < len; i++) printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); printf("\n"); } static void getinfo(const char *path) { fido_dev_t *dev; fido_cbor_info_t *ci; int r; fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, path)) != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); print_attr(dev); if (fido_dev_is_fido2(dev) == false) goto end; if ((ci = fido_cbor_info_new()) == NULL) errx(1, "fido_cbor_info_new"); if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); /* print supported protocol versions */ print_str_array("version", fido_cbor_info_versions_ptr(ci), fido_cbor_info_versions_len(ci)); /* print supported extensions */ print_str_array("extension", fido_cbor_info_extensions_ptr(ci), fido_cbor_info_extensions_len(ci)); /* print aaguid */ print_aaguid(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); /* print supported options */ print_opt_array("options", fido_cbor_info_options_name_ptr(ci), fido_cbor_info_options_value_ptr(ci), fido_cbor_info_options_len(ci)); /* print maximum message size */ print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); /* print supported pin protocols */ print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), fido_cbor_info_protocols_len(ci)); fido_cbor_info_free(&ci); end: if ((r = fido_dev_close(dev)) != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: info \n"); exit(EXIT_FAILURE); } getinfo(argv[1]); exit(0); } libfido2-1.3.1/examples/manifest.c000066400000000000000000000020111362326726700170060ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" int main(void) { fido_dev_info_t *devlist; size_t ndevs; int r; fido_init(0); if ((devlist = fido_dev_info_new(64)) == NULL) errx(1, "fido_dev_info_new"); if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); for (size_t i = 0; i < ndevs; i++) { const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n", fido_dev_info_path(di), (uint16_t)fido_dev_info_vendor(di), (uint16_t)fido_dev_info_product(di), fido_dev_info_manufacturer_string(di), fido_dev_info_product_string(di)); } fido_dev_info_free(&devlist, ndevs); exit(0); } libfido2-1.3.1/examples/reset.c000066400000000000000000000022731362326726700163340ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * Perform a factory reset on a given authenticator. */ #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" #include "extern.h" #ifdef SIGNAL_EXAMPLE extern volatile sig_atomic_t got_signal; #endif int main(int argc, char **argv) { fido_dev_t *dev; int r; if (argc != 2) { fprintf(stderr, "usage: reset \n"); exit(EXIT_FAILURE); } fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); #ifdef SIGNAL_EXAMPLE prepare_signal_handler(SIGINT); #endif if ((r = fido_dev_reset(dev)) != FIDO_OK) { #ifdef SIGNAL_EXAMPLE if (got_signal) fido_dev_cancel(dev); #endif errx(1, "fido_reset: %s (0x%x)", fido_strerr(r), r); } if ((r = fido_dev_close(dev)) != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); exit(0); } libfido2-1.3.1/examples/retries.c000066400000000000000000000017551362326726700166730ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * Get an authenticator's number of PIN attempts left. */ #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" int main(int argc, char **argv) { fido_dev_t *dev; int n; int r; if (argc != 2) { fprintf(stderr, "usage: retries \n"); exit(EXIT_FAILURE); } fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK) errx(1, "fido_open: %s (0x%x)", fido_strerr(r), r); if ((r = fido_dev_get_retry_count(dev, &n)) != FIDO_OK) errx(1, "fido_get_retries: %s (0x%x)", fido_strerr(r), r); if ((r = fido_dev_close(dev)) != FIDO_OK) errx(1, "fido_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); printf("%d\n", n); exit(0); } libfido2-1.3.1/examples/setpin.c000066400000000000000000000022361362326726700165130ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * Configure a PIN on a given authenticator. */ #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" static void setpin(const char *path, const char *pin, const char *oldpin) { fido_dev_t *dev; int r; fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, path)) != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); if ((r = fido_dev_set_pin(dev, pin, oldpin)) != FIDO_OK) errx(1, "fido_setpin: %s (0x%x)", fido_strerr(r), r); if ((r = fido_dev_close(dev)) != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); } int main(int argc, char **argv) { if (argc < 3 || argc > 4) { fprintf(stderr, "usage: setpin [oldpin] \n"); exit(EXIT_FAILURE); } if (argc == 3) setpin(argv[2], argv[1], NULL); else setpin(argv[3], argv[1], argv[2]); exit(0); } libfido2-1.3.1/examples/util.c000066400000000000000000000145531362326726700161730ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef _MSC_VER #include "../openbsd-compat/posix_win.h" #endif #include "../openbsd-compat/openbsd-compat.h" #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" #include "extern.h" #ifdef SIGNAL_EXAMPLE volatile sig_atomic_t got_signal = 0; static void signal_handler(int signo) { (void)signo; got_signal = 1; } void prepare_signal_handler(int signo) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_handler = signal_handler; if (sigaction(signo, &sa, NULL) < 0) err(1, "sigaction"); } #endif int base10(const char *str, long long *ll) { char *ep; *ll = strtoll(str, &ep, 10); if (str == ep || *ep != '\0') return (-1); else if (*ll == LLONG_MIN && errno == ERANGE) return (-1); else if (*ll == LLONG_MAX && errno == ERANGE) return (-1); return (0); } int write_blob(const char *path, const unsigned char *ptr, size_t len) { int fd, ok = -1; ssize_t n; if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { warn("open %s", path); goto fail; } if ((n = write(fd, ptr, len)) < 0) { warn("write"); goto fail; } if ((size_t)n != len) { warnx("write"); goto fail; } ok = 0; fail: if (fd != -1) { close(fd); } return (ok); } int read_blob(const char *path, unsigned char **ptr, size_t *len) { int fd, ok = -1; struct stat st; ssize_t n; *ptr = NULL; *len = 0; if ((fd = open(path, O_RDONLY)) < 0) { warn("open %s", path); goto fail; } if (fstat(fd, &st) < 0) { warn("stat %s", path); goto fail; } if (st.st_size < 0) { warnx("stat %s: invalid size", path); goto fail; } *len = (size_t)st.st_size; if ((*ptr = malloc(*len)) == NULL) { warn("malloc"); goto fail; } if ((n = read(fd, *ptr, *len)) < 0) { warn("read"); goto fail; } if ((size_t)n != *len) { warnx("read"); goto fail; } ok = 0; fail: if (fd != -1) { close(fd); } if (ok < 0) { free(*ptr); *ptr = NULL; *len = 0; } return (ok); } EC_KEY * read_ec_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; EC_KEY *ec = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { warnx("EVP_PKEY_get1_EC_KEY"); goto fail; } fail: if (fp != NULL) { fclose(fp); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ec); } int write_ec_pubkey(const char *path, const void *ptr, size_t len) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; es256_pk_t *pk = NULL; int fd = -1; int ok = -1; if ((pk = es256_pk_new()) == NULL) { warnx("es256_pk_new"); goto fail; } if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("es256_pk_from_ptr"); goto fail; } if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { warn("open %s", path); goto fail; } if ((fp = fdopen(fd, "w")) == NULL) { warn("fdopen"); goto fail; } fd = -1; /* owned by fp now */ if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("es256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(fp, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: es256_pk_free(&pk); if (fp != NULL) { fclose(fp); } if (fd != -1) { close(fd); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } RSA * read_rsa_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; RSA *rsa = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { warnx("EVP_PKEY_get1_RSA"); goto fail; } fail: if (fp != NULL) { fclose(fp); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (rsa); } int write_rsa_pubkey(const char *path, const void *ptr, size_t len) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; rs256_pk_t *pk = NULL; int fd = -1; int ok = -1; if ((pk = rs256_pk_new()) == NULL) { warnx("rs256_pk_new"); goto fail; } if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("rs256_pk_from_ptr"); goto fail; } if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { warn("open %s", path); goto fail; } if ((fp = fdopen(fd, "w")) == NULL) { warn("fdopen"); goto fail; } fd = -1; /* owned by fp now */ if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("rs256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(fp, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: rs256_pk_free(&pk); if (fp != NULL) { fclose(fp); } if (fd != -1) { close(fd); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } EVP_PKEY * read_eddsa_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } fail: if (fp) { fclose(fp); } return (pkey); } int write_eddsa_pubkey(const char *path, const void *ptr, size_t len) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; eddsa_pk_t *pk = NULL; int fd = -1; int ok = -1; if ((pk = eddsa_pk_new()) == NULL) { warnx("eddsa_pk_new"); goto fail; } if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("eddsa_pk_from_ptr"); goto fail; } if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { warn("open %s", path); goto fail; } if ((fp = fdopen(fd, "w")) == NULL) { warn("fdopen"); goto fail; } fd = -1; /* owned by fp now */ if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { warnx("eddsa_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(fp, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: eddsa_pk_free(&pk); if (fp != NULL) { fclose(fp); } if (fd != -1) { close(fd); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } libfido2-1.3.1/fuzz/000077500000000000000000000000001362326726700142225ustar00rootroot00000000000000libfido2-1.3.1/fuzz/CMakeLists.txt000066400000000000000000000031511362326726700167620ustar00rootroot00000000000000# Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. list(APPEND COMPAT_SOURCES ../openbsd-compat/strlcpy.c ../openbsd-compat/strlcat.c ) list(APPEND COMMON_SOURCES mutator_aux.c uniform_random.c ) # fuzz_cred add_executable(fuzz_cred fuzz_cred.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) target_compile_options(fuzz_cred PRIVATE ${FUZZ_LDFLAGS}) set_target_properties(fuzz_cred PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) target_link_libraries(fuzz_cred fido2_shared) # fuzz_assert add_executable(fuzz_assert fuzz_assert.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) target_compile_options(fuzz_assert PRIVATE ${FUZZ_LDFLAGS}) set_target_properties(fuzz_assert PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) target_link_libraries(fuzz_assert fido2_shared) # fuzz_mgmt add_executable(fuzz_mgmt fuzz_mgmt.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) target_compile_options(fuzz_mgmt PRIVATE ${FUZZ_LDFLAGS}) set_target_properties(fuzz_mgmt PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) target_link_libraries(fuzz_mgmt fido2_shared) # fuzz_credman add_executable(fuzz_credman fuzz_credman.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) target_compile_options(fuzz_credman PRIVATE ${FUZZ_LDFLAGS}) set_target_properties(fuzz_credman PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) target_link_libraries(fuzz_credman fido2_shared) # fuzz_bio add_executable(fuzz_bio fuzz_bio.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) target_compile_options(fuzz_bio PRIVATE ${FUZZ_LDFLAGS}) set_target_properties(fuzz_bio PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) target_link_libraries(fuzz_bio fido2_shared) libfido2-1.3.1/fuzz/README000066400000000000000000000120701362326726700151020ustar00rootroot00000000000000libfido2 can be fuzzed using AFL or libFuzzer, with or without ASAN/MSAN/UBSAN. AFL is more convenient when fuzzing the path from the authenticator to libfido2 in an existing application. To do so, use preload-snoop.c with a real authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1 -DAFL=1, and use preload-fuzz.c to read device data from stdin. Examples of this approach can be found in the harnesses under fuzz/harnesses/ that fuzz the standalone examples and tools bundled with libfido2. libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses, use -DFUZZ=1 -DLIBFUZZER=1. To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of libcbor and OpenSSL built with the respective sanitiser. In order to keep memory utilisation at a manageable level, you can either enforce limits at the OS level (e.g. cgroups on Linux) or, alternatively, patch libcbor with the diff at the bottom of this file. 1. Using ASAN + UBSAN - Make sure you have libcbor built with -fsanitize=address; - Make sure you have OpenSSL built with -fsanitize=address; - Rebuild libfido2 with -DASAN=1 -DUBSAN=1. 1.1 Decide where your workspace will live $ export FAKEROOT=/home/pedro/fakeroot $ mkdir -p ${FAKEROOT}/src 1.2 Building libcbor with ASAN $ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor $ cd ${FAKEROOT}/src/libcbor Assuming libfido2 is under ${FAKEROOT}/src/libfido2: $ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README $ mkdir build $ cd build $ cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \ -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \ -DCMAKE_INSTALL_LIBDIR=lib .. $ make $ make install 1.3 Building OpenSSL with ASAN $ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl $ cd ${FAKEROOT}/src/openssl $ ./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \ --openssldir=${FAKEROOT}/openssl $ make clean $ make $ make install_sw 1.4 Building libfido2 with libFuzzer and ASAN + UBSAN $ cd ${FAKEROOT}/src/libfido2 $ mkdir build $ cd build $ cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCMAKE_BUILD_TYPE=Debug .. $ make 2. Using MSAN + UBSAN - Make sure you have libcbor built with -fsanitize=memory; - Make sure you have OpenSSL built with -fsanitize=memory; - Rebuild libfido2 with -DMSAN=1 -DUBSAN=1. 2.1 Decide where your workspace will live $ export FAKEROOT=/home/pedro/fakeroot $ mkdir -p ${FAKEROOT}/src 2.2 Building libcbor with MSAN $ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor $ cd ${FAKEROOT}/src/libcbor Assuming libfido2 is under ${FAKEROOT}/src/libfido2: $ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README $ mkdir build $ cd build $ cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \ -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \ -DCMAKE_INSTALL_LIBDIR=lib .. $ make $ make install 2.2 Building OpenSSL with MSAN $ mkdir -p ${FAKEROOT}/src $ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl $ cd ${FAKEROOT}/src/openssl $ ./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \ --openssldir=${FAKEROOT}/openssl $ make clean $ make $ make install_sw 2.3 Building libfido2 with libFuzzer and MSAN + UBSAN $ cd ${FAKEROOT}/src/libfido2 $ mkdir build $ cd build $ cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ -DCMAKE_BUILD_TYPE=Debug .. $ make 3. Running the libFuzzer harnesses When running under ASAN, you may want to set ASAN_OPTIONS to 'allocator_may_return_null=1:detect_stack_use_after_return=1'. The recommended way to run the harnesses is: $ fuzz_{assert,cred,credman,mgmt} -use_value_profile=1 -reload=30 \ -print_pcs=1 -print_funcs=30 -timeout=10 -max_len=17408 CORPUS_DIR You may want to use -jobs or -workers depending on the number of logical cores available for fuzzing. 4. Auxiliary scripts A set of harnesses and auxiliary scripts can be found under harnesses/. To compile coverage reports, adjust the harnesses to your setup and run 'report'. diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c index aa049a2..e294b38 100644 --- src/cbor/internal/memory_utils.c +++ src/cbor/internal/memory_utils.c @@ -28,7 +28,10 @@ bool _cbor_safe_to_multiply(size_t a, size_t b) { void* _cbor_alloc_multiple(size_t item_size, size_t item_count) { if (_cbor_safe_to_multiply(item_size, item_count)) { - return _CBOR_MALLOC(item_size * item_count); + if (item_count > 1000) { + return NULL; + } else + return _CBOR_MALLOC(item_size * item_count); } else { return NULL; } libfido2-1.3.1/fuzz/corpus.tgz000066400000000000000000042424141362326726700162760ustar00rootroot00000000000000] |TŹI6E[AyQFF Y" !አDT("|֪U{k^Ql $Μf6D_vwcg|7s&zMm i<%ǡ_J_b8x@R4S ;[Dͼj*'TjjUE;utʚy 4 | pyŲ2Gq,CLDt*@q*ŝz<˞C2 3E%RͣŖ ;m t}b3U]/NI|rBGӜP YF*,2I(%zljCG󟣸c N`b#`<̜WqXEl A!Y'GBm t, q5b^Q6q8e7)eM00񊆄DuhL~~(jlltLYL0BQ4^i4Sj Wb`?&p&fL I'Y5cdS'P<*2+)qϒ1 $S9+`?>u>GEX߲եT7_hI>9Āi9{/޳iK7#I_rY~Yi9۫I(>xDc\xC/y7wߣ7էfSe'{kzzsw RHJlʲ/ %?z;N9ɇ}F}urnK 2M<ŋ2C4O@ljx)L+;00'B`fel (?0{ o-ӦheeWj|qɶhl$/m1?0b~-{(D{avXm Sio2,6hVFh9h?e܀ .r1bE^euZ*躦d@&u-<:?%l45ߎQ9_1yeC<ۃuZb ]h$'OB]i9tx5RT[YS?5_x S| Ql<|j.[8+ ޸hHf@ òű桲4&`o~#1o=˗WzM\R h:Kq2IND Td;Vt( W; JXsnZ53'٦f~tlAۘ~Է6r5IRb5i0 / 6z& N|~©pW1bjA8eY7r:-x,ț_6N3-N:hg{.XvWqz1 G^MɭjVySYT9[3mpCfUͯWoYUWWXnIfCj*ݲx)լ;8`ÐK:- ocRe% Q~~^O~low#+%OF c10`Gtq' } 6d'Mk΢N @a [ [7aUF ErBqʬHpX14y&'*w bXc_b }g7oaΓK`~['mݒ^{6ud? qy90O:/t#u 8jT@јHc?MKweɯa̐XðU{,]d:#]9רs Nņ XcuDo:ʩf'{@,aX̂6NJVB BE%H~d? UlY!n2.^Vc뷃#0EYhSk-YVTje5u'Y~'xh]P~9 C%q1}GTCՍF 5,yK&6NKR0ߪhUYNE9m4vώ˼zH 7_ `{{WTVw[5;n\5;xBoo2m&+eֿu ~t!-:`X>IXf%(5֡peiA9FSDYa8u_۱ '_`_p괁}=aN|w7VFAō>?*V9SrNqvl,}4Πc-ƸГF rA/)|sύřN H Hcxߋ߬4>6E3V3>#j稓9۷CU4>!bNnjďӥprR>ʔ0-tb˰KAg#=c>gBgU̫tVdby.|])5o;yr\/jSU(fA|5OV}+ғ4J2\t6jBk,0Ϊ*ќFuEu+:~;v?]<x{eۇ<}=Bo=6_xhߓTxU6RImࡍZRfQ; 6WU-(CH$/@ H熬t,)`x1r *C12P4i+hL)(&Alg]a'DW\(r4۾}R2@ݭo^\PˑItZ;o~66q-4.7 Y}EVU"ղYɖyY>tMv"j % h4%ъ**$\* %iX7b5=0|޽JLǣ_Aϑ~L%`P3z8Oۙ:B"h5Ƭp#F 1dD^g[7V7q7`,?^T%MWAI&@tNх/%D_ஞ?;>svI':ı}4u/O?ݱ󓭵|ʂJA@;CӅwCM~UCaH5^'bGeUҝgs#&:IK< :sB*3Eۿw_4]̝JYcɖ%s1_G?Ll"Ӫ_SX [ݐ&;21)$%I5,g\dH>fE1}YD(x(`'_(7f˥G׬ډbZ(u<`&xCBBHwOL (KF "PqQWݣ Օջ\r\eI$uY3td{zu,\Ng?KQ4*q^SyAHYTJ$pΥF8"wA} @Vjd3׏-pώ:%+`+<p,@ Z~ @K(HE'p%#w7?)$+#1L1 鞐Yl ._DAҿm!q9?8(FY\YdDfpN"I (ݗƙw?_&/G:VssŤ?>j;7!_,x `YI^a&`F$ (z~}:Qk+NAo}lձU*VUxo5LYbyZÁ8Ӳ×(%*rXEYI ӂF R)6t!;Nc_Q,s/94 -/h-1R`%#PaVeSMдd}\; V@*Nk-Aω˰N?QT!e0/,,A"Nv_Ih~$ĝqd?P ˱gC7?HȶoDvUVq]QF%|=jM' |%x(甓^[wo&}^z7fl3S2_  >.NO8aHxUIY(WY#=!bF>$? @w#q+ Az+>8 u僃55w$bRQf\6jo)!q3)`ITJU(EaVQD5̉$#a%UAd-=@0'QoBqlN`ҖX0JFCVR;yPXa1n-m(5PgQp[ [bԮkD8" <],C߮ 9B@;T,v߅0jnVZz? q, űz!`^8O$ !aPU%Qi),2*.q4)%4ujϰ?)HJŪz +O1 Kb+<+8fVu֭&$|+Cq{ iIMb\1[z.P=h4f% ]8(Q\8V"A-@E/ /NYZT\#2KvC'KDc!y/CV¦[<ktJ䁹a@X+}(Z$/6=}ÇVBh3`ؾm[}E[ ⓋxD| !?x3 !tZQhtjy4˗_J爵;<3* bzEmQpaS*T)/+aJ’6)Ey^ %JLSʼnRn$I&uӂN?8lps (KD?要8?u1Pggϴ 33}}yCeYF#AP (͏ `|'Jq;c }A]A J}߮ 1)iW)%f%ReZI'8RiYYRN?irSfY&-;b`W5)~ ٿhW.b c***۳iӊ^rCRd=Y&`pR>)$+$TieZyIH.\rGz4:T?Dphoڰ=xO$o?'8+wyz,JWJǓm/ē Df'\rI&kؓ g',{V^2rYGU7`dG!mkk?aauQxT,x~`X= A/@/E*]اs{\ЬShu!Bcu2kD&-@v0vϞA!6߃(MbγkġnX3D3 x 1{,\rnX 9_e7ڈu6FPwYRD_tj:>bfTbxo+rpN^fe/+hgOu\HFp… E,Iɟ`SiA٦HdSh>w ~'gG]4 %ݘ>!0a㺴]ՙM;RDkw˲m-Ag#M pB&!wUyX:C U'}ْ:~bRέ沨.>`aC#GwUAn 祿U_1j?0-yh\ vM Mغ|ߥ=BBFhҠ4(9IxMK -xui'5#l\"mFNzS$?}WZ2_U 7g)Yb1V0`: ]ep7}hh||u`o ^zE+`^ܩw׶>"w~_Wk-A7 ̎Zϲ+o{3Ԭ,0o*iWw+ |lokqw`oך7Vu)DI׿IE}zvhTNN=p3eVnZ {^(Ыt^ql1.PЎ9uR}CmE yCvaYis̴o9b \ɛ+֓zDd`rzjŋb!b|XE#_HMlׂN'k86;x\ ,Ӓ /qRQÊ@\W"X(πBB DP!xOῚpԅHl֥!nG`MOwj9N)[ \䟠(heppFTQPDxOpa?*p1/ A?E3v(;;8sgg̬7긃/+Nq\>K=փ|\_+1179VX>6qXh' \T;٦ihw tp)HPTIUcXVYYI%I h#A_W%v?pB r:/!?qaCyWRہ8g6nonn3Mߚ?Mv?yɾsNs?\[bYz6uIYԋBCʲulG'/ycM7oJmg&/9fvfH~HmĀ6k&qtvځ$pɨŻXh 2KhfFbf0A_w.bPs`?80B@_YV% CyӁf;mv];' k3||N^qwǼѧc'СL`?;^g:*~wX gʯ@O?ÇC-G$MOS"E.c  ! vn?%OrM${O3m6S |`a t:]_aMw&փ?Ma\yo^Ek kН-_bUe]cJ?*qϚ-ZQD+co*Wr\2MS2])gN LՎ_wrk3 2fLZC}pkbcE!Vr{C#K[,D+'yZSiUdeQd#HXrTd'1\B\Pu|K(oihQͱ4 =iz8ۑhc(y5FZj";[WMOK[~ ~fon꽠pp( FPqHtT2BG]]\9 NF*gg9,-Pj x+WT{sc ~X<><ݹ ޞ6+3|LJ(@tXC;oeBdP0#TXGd"^yT)8٤11/]zPm<_@ޞv -HCBj |?n=GJJJt'i"4>a~lVu{%>yB"-!I'wW%Q(bA11(XB.IF?e]g ef^?%pt]jj4=-}\22k~GǏ˶y@Ak<`noY>;SF ` zܧ !ǃ|+`7wmĠuW-]vjeef79DV(\dA&q)%(Q9LxLpG.ƅX'`ems~gi͓4g0uA7C =/<@~9q!s/Jv6s?93ھ=wY%E*I*GLj*,)'"OHND[7*?Ws}8gem ME>CQ3>?#vfhg݃ě󮾬#&X_6x}G}cPpa5X;`:{nĐ2#K,*r q$M),3",+8c @{ȿ/Fm%{Chp2[9wos?޺LXXRw>zAy3w+ ^eǹ&dP"0\`d&hJ@ $&5įo0`(p-ӆËJ2*(p*E Jo @gOOr1PA]'"aPFA_3eVE4AQPqMF@m::xj mun#l,{?%}~ + LunM >.UC5n:Z̩ԟ6e-Pu N-xь?W&URXL wZ!akxQ8/F3pVZ]kaZk!K+k>+L:qlgO?Ut=%nmUK-rzn?s'S8Oˬ8f#ؘoT27UhW ? ` Vl =؀iyIfLUB&g=|s3TWŀ4Ze=Ϸꨱ?hpee(% n*O *2%b$8oI)=a4 ׸ȿ[TCbA7 ︫ [5<8 4< '{hR"{U-G6獆 dzHo&ӱݖ>恘/Ș$@4„tˤxxNZcE?C،p…eTYd0V U8zNH:G.}{?zC\4M}}ZN&-{{`0e5֬4{QZeċy+կޚm> xyqW{,d" L3\꯱Nb^ aE'>bVW]^^=jVQ]i Q}ͭu 75s;.PQh׭s6L/,=f?x]Bl?) _ygz힟~M5Qw45-2j4-+)篟/)Eqυ>r_wi]i=iGNr)~qo_ z7?44|o07&_k= RGDif4\X9'ERTNiEFULVpLd4"ӡ_s_bsyHOt/uK;ECg{9NyzLng#X:{OQzuEōyԗzkz/t=v-U1FQhq 'xEa15\TL? ]40_?2LMqe}9v, yzm @$wZInoT8QAC_}:*d`뵌\A;:P|b9yNSK>jo/TN~~+)^F\.cSA0~_`r_nKȣT,ׇ^`GŸ#̌׭o*R34+A FR/(,ms,cd,'*00`#\j{T $~&nmHc]NnZBOHi#}߫uYs$ӗG}ӪsAeq~7*m佯UK?iqĽ-m#Yqo1!9YWۻ[DVҪ2}Rb7ʎ왇li)rG֜Df'j2Di=epv.?++?{Eu.5! pIHx$lPySyGV W"Qzb[[QVb}]ڊ^WU#ΙǷ`y33;|;>fdx]aXdVu` A$%&}L>_0qHp0}sf'm ݝv{xhXݧMF!Cox. x|$m|}SdK8b xme'zlQ)kb&Jނ 7=K+ULOے`eObzUub$ jw rC[3-7*HJӪK@Rn]G_L/pWFl>_u+ygR(?Fg/z ab=Lv f3f}-DC':sxιũ!ąa4y=+lZ"k2_ >4>O "%d hJj J"6)AJ )H>#$ߕf[w0j# BOo;jw-w>=?ӄ ^) -m `==43Avx|TX*LRNRahJF5hR ])5Hj(N;XrG7#.>@dmUQO:)zؒ(3{ !Q<8ǣb/1yY F51$RRD8ՐY>_?gg 4" %mߕ\pAm :$\ЊIi}S8n" L9' &OkYRʊnVoݚY*/"Pc E 1/azdӉ{&pgԘh!cVցY̹npWlúF:LFUg= Q[7oMs+u M-NYκܓ~rçHJV N`9$FRI^iJTR TIv]?#hwC;_+_x~D_}]_dY-?lˆn{k^u(w÷ qG'D^ڪ"j` < AfA}oͩAX$VؠNN_/ ?#Wd_% E$anYpYgoS>7ex IR]K53}wǪ"Οَ92,bTu>9Y+9 LS?. <ݞpo7G󇯼7?}sqboSiÖ,YT#q.7v`[Wd{2l'yݹ' |?:jdH 2+ #ɜ(ЬjH4v2@ͼ(UB{цӈDޏBaD 3=< A[ߥ @>|{Y4N8q_hY1(E9eE`tYO > joߞ0c $GbYU?cݜN@BE9"Ƙ;ߘ;hР4({ƦAK-t O:+վ>3Cy^"|RpHNvE)u#{=Y%n63Yc֙ބo?_^nӯZTdAtQ8Qu MTQ v]*%/N ?sCOׄujRBQMA6|O?-f)GA_y_02+z&yEXgJk<7Y_^c̯x<C(?/unå`_%_YzQ?o4"Gj, Ӳ1.'uJ:%1cNj)RyZ ";ov='{~͇"{њFZ7$jv%i' nǕ*xES>V JUiNRUIi9I=}_$ ?__u_*ۀ.CŪ ⁜bFf9EUiZ I5PIUe6}?$O ?2?i?hP̈{g3b̙sv;/[zUW xL31ItPzqRLU<KB(uXYQ ? URQj9AxEeN f.^]i׃C_k}b(rkEсGk]8F]U]39]N7z{c{$IX4:N^|k=b1Bwq-1ڝF/#s:ÊWX?*RKBO8[& ?RiʎV9vSNeE2~Fo[j,Ao7>얬y)Mjt—cJbAkt]2wp.v$ЪvYx_wm;7hS=JB'<2QayETG^;t.19v |+҅M¬!ǝ}ͷn;D[n{OwFĺcPZܑE݌wez=Oܥj]]վ໰|BJ.Ny#\녨vCq(Z ww"iϪQ(s]-1*):x:H{Cd+=MthiY{з1#]bG,Pu'OcfV)ǘx՟)}΃3U<6-@͸#=J-W'h$qٴ&ǖ۱e+Ԗn}{>ct蜿4p`6峍}`o+p"O$) HS$q-2;> )21 ) /MyUTGa6p]K$Ui*H$kguDWh4x-[՛HWAT y~ ὍunZ鳇X<ÂcѐCś>tH2c!yH;]=DZ`XD#?'9| 2Z_%R3P)]ctEItUn_,@ rl l8;V9Uh@H8m{JDh.n[D]"ٶnMdre C߫ :ђJt7Y2v3s< iنN%= (;adžxaE7_#)CWT 5AHQ6TCM2'1H(j/pl+#ǀ$'`]R6,˕PSKO-HtMsNoR[@ك9^5W.E֖Zar2wۛޕWQe[/ dC"BhMpqiL t:. @kJ臊c+JNZ\vcZE?Cel׭"ǝ{k9WdOw^Wu޺U{9?6,PN0@A+b?s.hᚼ*cå'Zzn_P[o7Edޖ,a:Fre[e5s# l1Z?2\E"* ewvC/ʰ‡&9?3!8~%qo)/x~n.-q.OxJvc<S{MvZvU来&wu斎ʹ͝< nvF+4Dm:n4&.cCQ;]A=>K{ѻ$rGA2XE[pޙ6@C׿rHg7''qGEt9MGvDٖ.˦nZ6oڂep?d?o?4?TEY[rgB@w Gs Er>rPڋ>g9EW,[@0R : GQyRh&j`.\H#a\\Y#3hqgo̚ 5-jqhfGٽwhvAW? tY_BoOg >yn-}?^~~kޟ^=?69$ܽpiwvo@0?& )gR]?^?C OA~+zCSUtWw?L^ltjDG(j}` UMA h[Hc`z{nT'Ros ϭRGߩҝOx~~anovrC@_ᓢI ݎr[ `~(caވrZ)(DL[5$u]LUe5C-Y43z}#7g'T%0sU6ӓme~C:s5$"8hC}pX, Pe䏋 0Aw6o(6o;ĪmO8uId05S3YJN ECOX X1g0o STGN/c3$O@<69,#xbCf`fD'BnBQQLE&VmGU SL]ayՑEE>c_X9=[?p'_$oYKa`??{$Pm࿠RODW~b }ر=XCϯDUȚ=z1.ZWWW_}ߩ5`4Pȡ Z@?_S[SY3[~w-s<*ۚdiKcZmWiH@^?K{+wFÀ>1e{kze\yjJ twb|i߹9?ఎ$cH{AYQ9Sr,[TE]GO\Y!GG__67&{k:Y{=jc#oźDg SDrq=!yȭ8DvuW AE]8[t]#Y<ĥWxm, os?_yn0JW OpKZ{ƻ [凴٣}gy4sV UVƶzDo(" ;EÂY{C5η/~^t_?U՛Ls7r2^O}泀 5;~f ]R9rwEū#$,lTnEТEo>22)j²6;a(kjb hɎ$1*J&P\0߿0+Bo27TX2`1hi2 _- U X):E_m2 ~m놣ۼ-q" WyA3Q I] :*'p)ٖ#flU4?e _OcT8-!٥kpռ:`!,8Ǔ8p@/[@:zغ%aBAxh)2;*;LOlYld#R.VF P%0LYlۺŜƦ/뛾8 0T[e0jLx?x):%nWW=\`\K^̒8a.'BFn398B̞޿gwRʙ8Y舶,+6oə"i_wvׅWfh9v Zauf*zgT.R9hf2m,y^VMSq8ېK4BeCGaO_WX'j [NcNi{M"TXF.0KI8A?G pBslY0vs5Rnd_;6y6G 6g{"@/o)/]yW iB<|V4|մ fҬkv\=HN蕖NxŸQ'3*(#>t']m >۷? +vN݆Sv|-h/"+2;cA?wnKKV`m5s"X<@S/$Y@h,.$MƱ$BaKKXtG@`p.x@Vf_mCW~6C&m0z /C1?V@*CG2y1k'Nږ9Kծ;][VT8ipvV$UMړ7ӹ~Y_ǹ355ȯ~9j|/r%[_dYHSHYIEdQiHN2 Q3/1=\={O3u y7[-7lue rGڞH8pfxD%32nغSF!OC>ܟ||/hz%d-W_K__p'4%A ɸ$QhBɟq)?:?Z 㿦f  wjJGQKrَtXJzGsun:8I::*M7<'0'ˆig.+$ŲLsE lpCD?#"}s ִx ñϾ SIG)V=yX_d׫xt* RY%|֪rvnj7WI2C5uΦqT!OJT葬]Fx1>~L/O?i~\:xd y+0P93:EZ!:ycQuB/|_*n߸ (f'I8UyMTP531,'6Vc#"0=?m?~>;LZ^_ZzthZRdxF||'i`aIwOʅup'$'Q4AEby^M08GD?,z#Mscs2hXr{?CؓpG}w߳ŌS՗ܐO߃>.{ ҺA:NĵZRCOhwsU"nFEXI4Sp Eej/"uK[߽'/.t4`JɖU"Ogm(mZd f\%I)8gpyM^|4~Jkn u<_=-c_`8X`/iWyiU$B5k2 @r/Ʉ٨egw> ]c" 1Q~GJe{ -$]pGM~!qJIi,˔2E8!32Op4+a@\4c쑘Pߓ~>?{7Y ;) xci)LesڌvDw6\6ϗʪ'?8)ͭHk‡ꂾ̧ߙ!v{؁fc.AjXdZٷwE.#ScI?V%G vubD9w*:9lkݽ˄5y'쉰t¿~l!%泍ʼn|dgdV܀dJSDQq4-ld? FȈ] A_ź@\t4:zy< m eQ<ﴖﭤMQqSe5 W9TM1( I(20J/κF]KOrroC,XZ1j :?` zEIYYT6̘GTsfo=kk6~%]ch٫ƛ^R;PvűZ u΁;TuMd=h-R1$iv,A\TYdpMQUpU53MBLJ\-f""?O'cŀcˏ T6T[L`McTC->"IM0;Jjk\4z? 8[=k橿up+8}O3G?M]M?tF+l`èܽ gڃ_m Eɨl⧷pcm34́=PL߫OSDCЗՇuO-ЂMztRBd N5ƐM1痋ӌm+fo{*5liH/)-uMM/qq$8ų$q($K i<*"/4%G|/D @2b33Nű%&&;k,=xWo[2hNz_NQA fvߖSWaƄYy轔G~ӏ.aj '*:tЭK|-1EOGRب+@Z'zGٜ}\z =(CMͧ~~#7ߗ[iȰߞLwcm^ݙ>uŭ-~|iivT4iA/Ǭi_9s7F_UOs P~QJ'%f$Z4\&IyeYyd2rg]ǘh8c-x'qUӮІXd74ߣnۚd CH=Y޽?aJП C>_q=? zLōwU!n_IXfUPTA8#Ve4BYZY&Fcv߈ /t`30kL7"]ƿS@@XD|<`} ٢@{3R}9.I>ߘ>eYRY1=#J0h/~pqEz ~);ysc]-v4w3ŗE_j"{TU~98bUܼe1%_ޞ$lX+h}bשBRݱyoO覃9Y(A$8BeUUVU(!|_`_QDąs0a2<H5_H"nmqw/FP[x,3MtVդ<3~s7f7T}en`Ԯ6"mK=mٻ(l}{ Ò KSY`>tx`SIEBD\pCp 0\>|Oqyçut !wout1} Uu޺U{99w$}b~*gygDMUZd5FfeZ” YLQ59Zz>-O"  7x>o;IwA:ii|gtisQ|'Fx?p1 {AJ_ף=C\W?qZS|~K^X!Y!ͅO{vnC9wWc.C0V6b˿srds1; Xt[&'}H:߃'Flp_D:mv<O"<#oٟ}mWn f'ftg 3XQH4c0Y&fd 9*eO o'?_\Qo]Y]֦Oq㈨yxx#^&y]`Y>2hLڧZmϳh|lޖ(gJ}Og6p_\HwvfyW++*qd nX1J S0^(^Tc|i6?ȧs=ʝ ^i TOvUc jK#&d=";X2rD W^ٟ+3w8[W|︪j;.|tw\nu:閘b[nƄn݃j5݌bk_ nқeoI^ H,`Գ:KAp&Ȣ)?IB=^-ߘtWWoC~V0b X^>8=}n?Xv7o%DsSme[1z6T}=tD]]]^kҁ!``bNU 4)A)NR3dTxC )S?Bw<Ǣg1Y5lv6ݱqgQ\w +ڋdGFNР7LQ<2j&CU7۶[ ,_TSSjKڸqc]B*>)Xzg:yiiʴA1f*"˫(Ӛ&2uqKM y?菻#m=Os#?x.`uTZ)ۧr2ߙ3C0z+cy;S9&J^_E^W()VDYUhEIU^QyC5o\G'?[5,+-v"(Ɣq:FFH"sɧ"=XQ۱ pm 9񏦦#l?0q3]#ʖ+p}wV"􌝇9ߟuO{9-؍Z˱Gꊍ<^aqՑ^@{WEʏww".L֟ '-#OtϜ- !ꍤ |5>؞zVGw/4zA*/i炖e;uO?cO[vgR}N"j(׏ d_C?DЋAȋq͑WAO-H)qڈ?YE u|nt];o *_NHzݻhAW4_{RopAgƼzG%s1%Óf8WoܑAX6w;w)ޡ!o.|LAKvB):%y :U9Z$IYS XREr|7$5'``0߷X3g<tJR5++]k^K:,+]kq wk!4?ǯ#ipe=׸prhuRV{ΆVc%%ڬ};#~b :0%')wV[=~ioR( a!#Q\6>>W{$[BUu݁^,$;xsP$W63jOyw&(\8;|'ɋqf?7 30iEQeIUShEu?XC'Ĭ='S1ZЀH?t%ёWǃa{19Z\mY%~T`k5/A{AkVfGDK3 fMV19fY15вlH =;SOK }):suUD3Df(EUFVMB@b?+9o_/#}\!O?8 r(-#KNd͒`.qqvbۈ s wtlpQΞyh>nި};wf,,;YT{^6`޼rwYG$E'ک)p3=g?ifXIc9xUKDzsTC6=F+mx^ߜ Ϳ-`3Pg=9> ˣ?{f;.[z{f<dωlEO8G "?<M^(ӊnpMqp" F)bHf,(q)R 7b ?aH ݵW[s@r9SG 5 +v3fĸ@4'pOϻyXcYyduLɢ^?>5oA"_==@)߱0a}u`SUC4q+37P\JQB_y9af혷Q8|7.)Z|0ph&u8.|H.~Vn֩ACxR]7 'oA~ᡞ>hkOs:%H&eUEIWxNuYq$d蘿{\y/z?7\+ 5үR02 +1|"Ѝ˓&Ӫ2i lRhr"*wq;a(N?/cgO6wۉi7[&3S(|lm)mmZ(gA[ׯCh";Ѵ >VEG&MXCǠpat>p mdG {qYO(YǐɆL뼦:#ri-)6[HK yhŀKCo@+Uy^\0$Z8E|zk I2-:EV &#ݹj4 %!E8Z~`syihqy}V* DAaʳ?' ߇"a(=!d7%RC~맚CIWD'P['KI-~L|0?[Ow?SPh B(ԟwEGfVu^UX/ fu_ ʣ aMy"K?[U̪a+sQMLDU6DxSP(Zh$t]ދͲ ] mS^]vГ~n{" 3/ŷhfܯ;p_ʻfʹ`?Ot3_MG_??:">TS MOޜF=z ei9z/t/eFP_[ш϶z$t7h|d~afI]nC6\4'@wK"@);-4 |ҿMYc"^Ӑߟ | faTNM^?Ei&pH) #°$̛nOH)Ϥo?_/dhu~zNA0^6Y0=qԓ,g9n/ϳ uOrɯ-J,e53뽀B~/\g{𯨲Ni2kr`Rə, ˪R,t(6!MP))ceEY^U%^)U.((mEiYg;;lgr-aԕ#_]yΥα;PՅ]:^YN,O+5e+zv)1Xgu78u45SU(C$?#G?[?D?ߠ'0&!9=03GZ{"!g_ehs~1b]eBw/H=\"Yu&gˇ|$)` `JIBF,υy_e]UѰH (GjgŔwr?<Y_XoKٲncyҲ$HFb |m_}+hT1Ol-^wЃ{ @x@+4&"2' P /*-j tN5EoJB"c??/` =:M1e]-焖4~ mm!h6%7tږnȾ|s3<2D]zUʊvh?2v#Ud v9w0ifr?s9X/PnԱO(%A$Q(Gw y5ݶ lۦw֝_v z:'_ 4^: OWp{߉SĘ뢻1ԿT: _E;:Nm˻??MliܲƌD@&~~֮R)wIV㧀wKW!XbHEpKI.";iYN$EJa%NI ԦYs#8OYMӷb?@F/6^NG6-YŮ+XS%6Ӣxh%'^qJ¨|1%zЍωWȴ&]vm96KED8r=v`_3mUIvHF]R9'iyMѸ!_a0/:ư_+^?nSG3#NFO5hwITgx[F_QE= $sI)hS◠7(m>C'~J\Anm _2]VPwIW:BU?zQZҗ[.+(XxZd&2G~vCyAWΆjjh C:Rͻq@hI@+m9P^uJl) @2^%h顶ֳ֝j}P>l_d멕zlϽ0:9~wlc>l}޵u_J>ri5[Q0`NjeZ܇.~,oSX +V)XsX_oå+IP )HL EK !)N^"yɅX2mX7j3@Ӂ/WpJlPO< FL=&'wڎōQEP}vDr8 xA?ZaYqG` +~P V_ V_SzX}}uK]"+)B2I$%9IQIFRd"`(ѡP8,_0ӌy B 3KxAhp]50_퀢(v.C/N_?Nyc#˲Gr :0h-NY%3+*0 F̬kF TiOO&lp*:nEs.[S|qfsj! >o/~.eٖmu?>ʃ928_ *\rkyцrA܎O>qْ;|0FoPafȬ[2UJ.{AY>צdt\$@Ej KcƸPM#$x.4z@Ô@ܽtɒWRUL-wY>{ß&w# q$}%*i[UHTr3([)yWBHs¡!җ<'Co]Bgˤ֗x[F6| ( =iIJln&b.c:jsv> - vG.%H#Dο9'V :LqP(b8JWa eQP/)JFM2/P0oi1Ä?(!,[/bwclo'`RJ{*:3T?PES{i%>lLl1dы}l`ꖲKNBԟk/s݄RXڥc /_.(?EQ:~f Io,yǟ "ÊNT$^&id_W6GP\(wPE'jX ?2Ұ'ԟ Mlc}+!RkO(>qu>IX`m^c:C󸄚ĉHsKQ} tWsÄP`e$nV9&y'EB ˆ nU`B/8߆$]X?bya"Q D-[FGVX[ v2 Ƥ;Ƙ2 "o3ނ\+F}\@,;pU/Ăw7 7CM 8Eb]KY7pBc?˂8k?f*h]l(vz- S7=>G-Z/`>Y^>yJ}n+/ʴKd}p7Ź$ %WoAAk4 Yq <˓QeR8B"ҭp32ų3-8 ,ݱ7?O7_wՓ8+~o?~^56%HF6Qp.0TET!ܶ  ^V7Umx\pIv"K~F 0n7|"dC8h1N>#3+0h^ϳo}8`Agk﵁1~q+{Ӥwpa[g0|'\ zU>WA1 -_B|z% hM|a`4Պ)Q8 ˿M$U=/ɄM:20=hVl0cr3fuCEԀkF *;H1K~=},'W 8aյpWAC ,(X!zv =eqW͉.OԬL|eXKo6HYe4w6]_{3 }j wKSvp,s$s,B,A8{mI6'(%S.afßq۟3VRfVrOCfWv͖'IyAT&fG\ZT,L#ٞlȓ;"M\׬o{43e ,_ %E'/dA%xVrr˩I܁C~`Xw򿇡(,Znaؘ !>l?T\TE&)/K4)MOܭyE'y悈 Mc#^u>:ӌ_1q M{`g$vorA$ xW|;LcZaɓ.HH!%YP$МBNF`] GhC, x,_v',7yʲ"7dׯ ׯ#_aaoTQ]T JI711]O{ |HitdؿÊX~2Gh:qcxA9 (6񥕾'9Gvd~6ǜogJfp\(!(JlBO(TMhVΎ(Lˇa= c\a~QXgޛ4ZPLS|g_礈Ǯ=tv+:֗ khNkKPdڬC~ !osB:~QCWJyD@y. jGeQ /k#'''7C"g 3X"]O^_++jp"S!JVyiytadJHC=?@ ->+@A?ܥ%]TpFL g)lk|D}fd^ T74UTAQ O\̺Oˁ;1ofeIbcsZzC#/me6aDCfo;ap:X{o9FYR2.qv?M!?inc0Wcq,؋/:1QR H2>ҡGAJ-|`TѸWvBD8٦TַږහG|w_l!q}%$|&_uW>CDmu9TR9zW۪ta9,sM2r&Q]|u?\X/a:[0_m?"/shghEۜ-}E9qG+ { ¹[rP: c9̥P:.1ڰo ǺvFνם4)?Iڴ{(I)ea&( v$ 2KS`X?v(}ֆ! Cp¡~bȎxQ5|F?VX$;JYadMP4yU;^#C PæX#m^?^;{~*h~4C9l"j̫wKʜnne|(٘""m^Q˧e\^>5[.͕շqRZ k#˴-2V(VyVV]1d]bN?c_1o&pW;:?1ب%jL;v(iX[ '#-n[[a*'b9I>D`/j[/o7nI 7 mojyذa{1RxPp`/nu(|Lyq낱c\zNw='X^R\ ^p 9Oc䟢!IUPa/ȍif5uY q2"Ī/PR?Q=Gs _urm);1W$0"sN.$N&B؏ϰ"\݄̯92[7՘ !`#p)yȰҹ:Fk;7O^B(ZUuVUiZ)dYK(t >IG_$$1C ~Zs2wʽlpǴp@%e(<^0^VUU-3<ػ NqV⧌3ZHS W݆'ENrli!-v|D:}WqO5ZB Ӱx="ifLLq2_ƒn= .,j?rj;g1{MLd_木 &hYu..4!nq j5EYd^Kp!U1l9JUN`x`:2/)B7Fv="to_yYNb^5c ʭW*#H 92T3yOޱ-݇8w_]YD5eFqV$rgI-ֹ<*n?={]WׇkE9)սdkЖ6Hz@-:]ګwNqKh+dC˧u_<l]`VghGmmn^/FC:YU2X%(Hd8&k2Ls_/K%`@lIq&c|g_Y O@F FgʘkY75߷:"[B@X[.Kn 5`嗟ǃ@L^k~qb/}eQ@ y@aky )JDuZXQ$Z4q:4t|q'_1V=-z#ek^ɢʆO>@2yڐ†*fgZMhx)E~ io"r2Y1#4426rE9P^t?+]/>XL};qN9r\x![娽uտs}i7C!νM{`7`d}j Vφ^cY6Dspa/jdVb&)^l?$?Y㿵ͪU >N [=HϲCf17xi;m#.YYBT!RK]8(b Ufx:2ʢ^3`r/_x3gh^xPBˈ X4+ T4}M e[lc,8e``oNKQ#mҫb!{ gVug:VE%5ER8"ExYPؤdi~ǔ#0Z=}Z1CwS47|oRּawD'N f/K^}M[ϡ<,E-H".qNk:Yó[|펭+ "ckWY^zt+09 <%3!B2Xf%<IHI ))'!X&T=5hMTyhEͯ+޶]F'phWTxo{_3BEvgVjzQڽW/zAE~ɖs)F6 }hС&>ߺ @P3K5?%:6e,A k+chFE8<,I<k4$G;#l<9H,9W&Ąw:|ReU{!tӤ*ㅿR%-eP tn_h0`yA b5$H R Zu^i9q?ƷS g'A_QٻzC0,ppm wtv|^i c;PXiDAB2T]v`{?K_J }#Za/֑^x=I̅r!ɔ h2Iɔ E)i:Ѽo4?Y_J+=k/u_9 qQOo#jGF62>j4Bz|Ozr`~I̓sC<4s`+l-D6˚(UR|zj׸pUU5Ek̯&u q- :̜tM ^_yREZTTV%0Xk“< xShU!_4 L?cot)x?'az~4! #y TD=(Z!(/|Ģ ӭE8*aI@6,<&:5oXwf碼H>D!2f|+讼| ($ݝ#xg.:N!1)O7Hk!2ce%%50hPDEnsH6.}?%??GtO8Nx[/ PQ|N-*h^'Q1q;sU ;H) -0/eR|-I*<%$IJ$ 12JIDWZo w A'"8B֤ϻ_N(V­yEA_6[/,TMD ,ߞ31zQ5i>*8:1Պ#^t7M ']?4FUi9^$iFhRdUfTAYJ9G\s/)_j;Ńv?_M,--(C3mj_`ى0l:klL25帶o{:vwb%Pt-7y@^UA_^E#]ʏTVTA,?%x5*ҔAӺhH*-JreD^(6.}_J=Ri s *w\^i+׷uk>p}` <;[$~y)EMz^ܰ?ƳQYc dMsB\ Yw5 ?gYwgd,ChE>Pq)?@>6ۦMm^xq!#9!#j! |pj}9xW9Q_ N8R X-!$>.~)<@_W}?w@⌥MsaEC XfU V1*9OȻYu:2pu/<<?cFҐ_?&~}!~}[qϳ+?1co"o-3lMؒ-wP[SGY\%5WjN'ؿOWɚdYS2- z-8@p*{zKS#yo"K)(e`K@$?tAPuK$/I 4oi'F384Oxihq5[:7N_;Ox-#Ƶ^H1V_5kHWqa!3YY4hSC3uTVVN*+WYp&j Tiaؾ?29=R@.a~ntX(E(/'ВƓvRF|4*J| ,o/Kip<_^Iѱ.񢢳,˂d"j,#2)ta#H 4#@'A? hw?ao?6m?zD&-cmr?41Li4ivyԩ@kBmtX%{%9B[5*ORS7E?_nU?H2]W02QR2 SUD,j0LJDЍUz ^h Ç(=,Be 99 JkQN +2*2##BHq?Yί`d`d?F>sL0_nX%{儨1/l7pZP7»`Db&vXW3w~k.~.~{2kf#q32(>241(⃵t{n:6>u(軿 @}!S77FQWF ֦ݰ;}_~z6[NHo]w}H(q೷o+ܼwbwTO ^5E8]EI9Jg&($M 'K E6.O.>?{!>M4k*Ϫ=&%BmҦ÷1}(v `onW\;-$vrnn,oo{ nڣ[?C%=UҭZrݴ6Y<ڜpAS+dݝl_CD ~ц[z >|Sj9w04u0G~u0[WU Mz5 ao^ M<9jOlh,u|WUvZ3O^~с#!\wc3o':+J?e_ Gs_ͧoٝoU=hBhS3Jn%n?Vn[C.wǍ!}pϛ~;UZ)gcCw4U#e֥ӗL7>:gz>|8|Çħth t<4f n|xG鸥΁eɎ|=^SNBlD#L|Jj@݁J99\swG+ɿyE>T#(Et ʻz0:z+Y-ƢXvm;*)YoqD;|;~$aIj)H s}ȕ:&y|"BV }uO0)ffw3$1ar5 ؗbN"KTzɬG>o.Eox<;v<2<][`&K hLh,CRtR8(n|sJRHBV㻜d+4{]rS~yȶnw/w&뽯M]9l!Ž+V@-3|tmozף h@d)5V,WyMLuC0xIguM ҍOOSw1XoA0u~OhQ kVR=]Ԯ\TYigm66 =ӫ82Y?@3O!X7s>]]xPnoM<#pⶠWJ=Ƿɿ3I`/Q|>A^6SI*cVlO>_6t0%A,UiːdAEQLVESdfMS/ W;*Qԉk>udx_|l<7!u6n'ѻΧSoZ{?WRSpSTM1 MT 5XE-9eUY]&x_H$ JA@fb?3Q&ҿy},3 )+>ڶuW诏&XA3XמbE^Gc[_5?fxP3(x[G{뭷}|Oh~hTSTCbMEau4]g96fa9.AR?9 ,E Gv>B@qTMo_mҶ`W~eg_}ߤ~n迴۸We,dzKu<6|kG n~fiH5Ʌ%~s &c6|N{=wv3ѩ  w鯍~1gaOMc,a,ZiŐ$N4Mu^afiKT 6) ;%409uvW^}W(Pzo793D' :N76}̙}Pݘ-6r=7BVQ[}|[On_8;q$ [aձU|4V[xx s^O.ÇY)9?5ZUZRtv6K oI?|S>?V3ߗ σFF G}{{1v"UX>{4n(DsMц[xQ7GJ'Wc3Ƀh},Z`~  `?0{~9|OhXtV% HKF4V5m' ORx +̾>̾@ÞQA-A>6Z㸳})4 _,K-N">`l)ːpGsmjO)b7>5 $?.MTէ_s92媳d›~n~DFnvwÛ{JiW j%.oק#JQڠ}8wP8b*HerƲVDhl H|'˄Onb}ta!%EZPnK[6w0~u$'jI<I@3͇KAم(-G<՘n:_uF{b]<2ZetkۙFDϊE9mFAU=O_&䠢IɊ \_Њ Xi,l1- "Ț%5ůOOGY fB''y;7 [#C^Fv bЭŊ-tmo=|k{' cVdZ,83i0X%1%T)AOR _ OcWJ/>1ے*p4p ĆP(wz1%eqGr>lȍ=O,3f&=F9K܏y>>98<#-Y]%E7Mid]5Qd8IO7g/J]>ۿEΌD.=gBduoMH<|e:xb- ܴCUwޔv: FqgīGLvncAzܴHԉ-tT0S}FO킃5MuFRMZDQfXZWLQ-2PuOSOۀ}qۅs +Povl6mFP=f_4-Do9 8)߀ P<' ~?oҢ E4VLY3YaTP^buВ8KI?G s|_e>yg^|_Pp 4;:Z dnaWA74ijo| QAoҙ=UƖ 1&$aUU)aIgѴ5oOɧGi'y1PL+'~_E,-<@;Bh_ġ:"λMYS1u6+LrU^TۼH*"-1ϺO58B2ΎGl{zn9])ub /#]Ō=69T,Zc4QUiNMhbߛ?&% |%>c?++>c{vZH8-mcDDz=Mm-~'gη D<9SzH{J7&֞I5|7{I\{W_qct+d0 4v/-giUTY3yVy1DJ[&XA*6r|*_R|P,b?\=H4l-]偽~W3ש .f}`,qa.{k$8~'9wޗ0Ϳxt.x>T㻤VNj"sΨ͚laHhO~lO |3 g ?'i_ C JNρDgXDEKdxi@<%N׼eԯ؄%~݆,|oal$`sEA6k~!U-)/^[]\ع7yG~hoX^ҽKҩRLpȎޕGQeKBBOdP 1$j_LG3!H@!#<4< e| (:aqo#)A@ zӝtA B_Znߺs=a,vYb.N#kjWt_Bx܌;m%G)}1=vau"tQID^NQl@s"' O8c(^۽lϬ*Bg}N+%Z(4cj?PmjU}j>rxVy-lV>#ff(0s{;(:fk}K=YmՀc!^}ƒYJE(NMi^%EP9tBhQl<&@@]:6_..f;}u&pџ6?K禿0>6 Erɍ mҎOфS{J :E0V{j.=8_9R?0R-W'\\kų'nu{G ?[m'`9$$ #'e#,K`a:ZIec!{4jecÑo%M`F)XK̤B̴[Ҟ#k#}m R Rɦ(߀E9C~>66Te9p<eh?zXRA"bh|8/׼DZ:JDR ^!3}` l=+vh@L=KbLkt+Wguh~kט  ú';'{-i.q#n&ش ,in4ta:܁~&:'gu+__W-Lѷz$e4XnT.zn֜sW_CWGuLIp BT*ǩ`| Cjyu!_guL]pQÃEMtYNatFRYc)JYY`uǴJd-pS@>S2P#{)9_ȹ$Ϭ)/QL`Ǎ;n[f?K#F^cͤW @HsŃ(8(U9FYA'UNSdNb4)AN__Ń#@O|V6DW/uwH |T?tpUO"0`3cڀ*NJI3(ф,(" 3H&x=%%uJ[ urqBX2e-Gdx|m)sSfF G#uVIMHҪiUܫ&+,AsNR,sn?Hʣ@67-ʃwcZVq~_]nP|+9}ẓ`w !,}Qҧϟg֚Uo7|Fx6+5Mq[ ޑذ#w%hÜ6OHE|"7uĚ|%7XfS,iuFp+_| pDX<#Ag&uz:ϰj*-K '+,%Ry&ZO\_{:9QX/Ju3_H@s>蹧3ׇP[|搜;.M/vn[ ҩME,X:E[*YPh{p)V*{Q > t,* ¸ \Ď[{DDbF7mj| ZGBkq};$> [8;x5ZZIEThFHMtUNc~F": gA[j &kR]6hkLL{v!;ف]\j1=$6<SKQ;x|H9,B?s( :90<tk{d6w0*㹨#29b3/j,3 sJQDp*GII ʼn.`h { _ FDŽң<\y Lg㉷e$@` şNF7cV"p}d@SעS`2iMu~aq5B7XaˏXPQ~Y.Ro7-|mȟ_^m6t=طofu_ @!`0e\r щGo}@3Bn8m~`한'!?uVN) M$yi^!H$q*v7aC@oo@f.^3^On)Db Vl/!|~ne-^bg뇚Vs8<7okꟇ9#[U^L} //]cڼ=]}틲]wMKhMq¾ŎAGKvi*C]v8AW "t_L39ٖIO3Ւn}Sykp+|[hؼCM8ٍc~y qfGO~󇻗sL=rwr(4qYZhB7 7Ї75tm֝l8qsM?)p35^IK >;;:-`<. TZ`%_R}cLQ% U_cZmI].}m5 w Swo\$gSFL.ܼCBm ,9Vn6$ |y, kԎtoO ' ;܊1BG2ez7se3>=pۗIFG=@{I3#m0~00 F2XMFKDHnb&WfXڝcT d[Sڶ5Jѹy|gaë`^иػC#6ܽwoY1>q[u5Y9}v:$2,K?:$'gJ$->h^= 8h;'"+vK F)f+6z97 E.o#nP م"K/-cc /J,&FJAŊ"ӂmA'481ĉ? ĉH o?: y 2osv{? 53c<1 bshYHEicn=(ĸqFh3XGwUdaύWߢVI|Eh} mt7xŠzSP2H}fv%P2qP[X{~adѽhwcچWJ5gIS) `UL M,nI* V݀_ NIT`-}ӏY@]:@6m7m=4ӄeQuBTiO.tw6l'Zqs~F)WƼ4.MOq3zØύ̠Q.104hNi3 2I1~?QDo\ *Á{>8Bl21޵GQe[ $$<­1 Y׎#b$5 ~3Egutԙ]ŝ"y&[UtƦ%RtWuws9 18 '{.lVy9ߝ`Ֆ-ݲ> !ҭCv'.b=yCUGЫsPDZ܁ uTqQ:sɻ(Ю8ӻQOY׿TgbM>gVX ^"0e& ! 9zR?V$wA%+7W? ?k"ys0'|<0(rx}; F#&x<(PQԔ?/++q-KQKq{쪊Xl|XG'n0 Ke)D5l&#H[тɎA{ X p'M]?/h_c1~oqi`ѡRogAL5Z&qDm/Wɴ)IXMvw'7fO9bt!* T,C,_3KR!*{^TAc`MV,M8LV%7MGÚ_n U g%_) [f)#h" b8*Sr2ːI f00ora_&7B錼1shdA7s64{ۧ͢vR&~ܱǓjɟ=1yq\4=|=?#t; qj",kHDEATTmJ0!)E!+kA?_Ӡ'~37+.QOE^g:~`+c"oђ_9e<@28gAjZ`:v_iΌ rTN@j><>HnlӱοG9OtȪUK΍7wٯU L2(79 հ`:Fpү@7tM+kDeGkBBxih)9cE Ő3+a9 hd{W <ge!B"D!KQ tUAW攫m? |zWP"zf4EW`ۯFO@!2fLTC,8ؑ56-lfvu75W M:Q@!9X뿺-ِMQ,[$4TՠoIjXi7_! @K??ۅ&j j8?n6V!V Wb9@c1!u"pQ+1agU*5O Oʍ8S XM*ϋS;MCѱ !T}^Ŕ?^z_L"54asd?w[#Ev\LzԑL}OqZC[ӳg3휊z9'&4L㼷5ǫV A?|yw7 9ztota1h(92z,_KgHچ`˱莥i@eo˚hXf^W0/+`豠7a 0ݎOf{ K# WAUV9?UtE͛ Z7a@``dK^TSU^@E, V5's?Yg@0{AWm+t#_a=.@A^e?*GE\ * hW P84~]WLqGr~E-~ b?UݒyjقnY!Haɰ-cH)?% @ 俼ៜ_./k6u ްV^Kv]zwuuꢕ0WlEs橷z:Ꭶozwrݾ?ryY`k)%%QeWd9 jhX2ɿ36 --;5eA& P?C6.; x =~|~H#| w_=tTJD#|:u0~^bwY xgٯNn0_,]&*u鶠5ђmb*Z@"!%/ڵeoGHw_?7ǩUwx@BuZ4ڢ7leeYuN]-s;Ļ]P_w47-K" u"P[@<*hTʽ7)?, %?ր~,Ot^#;ؔ)=z<+H|A98sF,CE .b׽!tñ7RmL5ƒ݌1{F +Q':^W`Otjӣ_zMԽ]?uҥSƖzK~?d4z0?†aZ.Ӏ75M DW5CTc-ݐyѶLA Sâh t5? a'+`;ayI/a{•C>FEz8D,EUڂeaے`I1xxQT^X'̈| @?G@C@ȴH{^Z\5yǟ+{m/% GҘVoQBGx- Pg-9F?aTэI]:˝;ܥ*a.Ip!{9&y kiDYTdJAp>ljACܔ͛(qtS0UL2 Kd"/->_F7/g 0`Panxx߈z}Qd5\,gH$?~[K/܁>wPkQMUO _>m 6jyy Mk)?ŐHSc[6$C4Ylc+Hd[ tKIr9;`M&^*{ ?1eg좟]˒muu*K @ۇr9_.@o}pߜ.5]wAnݚRz 'ZZW%D3TbȺ*bl*De n)eϰ3?Y%s#qa'{LT+Bz:֙/nm_BXCDW5MƊ8 uQ(ni>ze)%ŰOVKAof]87dpF.'\&\61w\uiMxLro 5Q*Q|^36M I܇jA}0Zkj@zO*0_2 [&U$,bCWxUk!d3ųa/+ʐd?{q3>fL5mDOVgFj.hs/ޟh Ssn{ wzosU̾P'%,:oc?|2~Ds_]ܢ\G(Y~=4ݰ#\.9K 4v۴1[QdU20k:gfl~$@ VhR\2 #JX Ղ6<+Xj v]mТV [uu}R <f9$#4̝;shTy(k?|  St?dvu@0 rFfDPfت[a1_BDB7_࿂T?ALV0%oӲn]YM~N kX}| |%#Kɓ۶mn\s P=|Tj5 aF3ЃrA˴) 4H؄Ki?)/(HfVN]yAM7 kLz$NgXN  Qh^MBl<3xt3w;쓭n ï;?2=Qf{0O?hiAhz):|8JPˏ)d]H^0%˙v;@j Pc@Υ |q@o]4? +GVZYa9g`t!m#ﶃ4Z*޳W ZUeUUzcUMK1ũ cHyNȓZ񟆻0\4"М,QRo0iE JtIyLhe',|pMpߴ[f#`Lq 0{ú rڷ'\e Tt%Nź)uL#_b 9]2VUdK뿤/Be9[yn ]KQNES .Wo'_V!`ߛb@,ps8\[7l\7_0΁w'̾a}'艴ǚ:ljfkj c*gɋ`OP;A2,-x1d UIG]8wǽuhiF3 )?v[Og1Tb= . ]m;ܽ Q(ЉIy)OXZ9XDUMU%MYCVy0$Fa)!`mVEXk@^}؄؂>u~S,[EhWm K/&Q=|4E:j#u7g*-FPv3A ncܾ)D(ۋ!q&yZS%2hZeNWf?RB!D8"77ߡ)3 _ŽQ䁸0@g0M T ?t6>MI%L1LAS)JgdK|4,hfHīFR/M)!?"_SK@odիW75iMskr.c"@1k Cy_ u~%"(LwM'0i `Xt|uS3Ǩ<ʲ.r:IxsĴ/%C)EV/ P\N?k fCW־c6sW!J)W*k#%ՙࢱv".M]K:iuhVbA2)I$$3(NOM }??87}M Tȵ;tmSXݻ#zȲr OZw:0'úm*e)$8YY3Y6dT4CDFO ,w࿆oЩr\Vi/]v,<i}2`_#u(Vg3ػ_78xQՁF'<~{S<ʤ|98v{u)edh5pcay6vc}f_fnfk>/ϲZY٧;d#g;Ԣ_/vc\ډ;jj Bw: 3Y<u?NJGoǢV5= te>`?U 5=+6IH`DiŶt a)t*!*~=9&ۥ]?Gy'As/vozqT s sA9#L>d +~3* M H +TL\ǥSB׆j''uQ?ݰaS-vXoA3~l2bco22%HFkҚ-*Q&ϋq8*PdE&Mkj?y֨W ~'h?~ e2vni|'u#Bh"?/ Hl~}>Ow-GOY#^ d GMwV$WUEf8QGعTQ[.{I]l{Q ݍ}diT9S5J4]SNx9c[CSBo>g1`?<͋clco|QGƜw jVN:Qá8r -} >Sܥ9D{j(aL ૔Wngϰ6TU_GvC=G Z|ߊZQR@a#8?u9B"R4-J)Khsxʗo&%񺑴 KKN I-ȪV}pkǻPO?7WS_dݩm۶_jAevmx^k z)ÀJۢت(=~SWफ&|ʺ;u}Ag;5;kݹjMmܝT܀z,6M| P]w`rluUrEXKCNn_ѐb'fe[>Wn{~.2^Ϙ xc gu$G$7zk>żIzn77=]x'~˗h ˑœ==0,LAiJH?ɱ, qX0%<&qIBKI\:#%W4}dciQT^Ì@h^18ΰ!AIG IOߔ # ?gd!So$?<'p~: >}h_ tyn@^}qv$oSofOצVqڲmSnDj2MJ,XH$, "늮뜢J`2N(@k!&1;SLSBウ?6w WzN}v|DL./ـm`qH<3o/ ƭ ?uO 44A X2+s@NV(*4eȚ(,cВL t\')!Oπ gkE4}ED9W CD×2gk~i/PJODX rZk|凤Xoݺ_oY:yURХ؉1DW*B/gqDA ~qU4R?PޗQacTTpV*Mg9_JDuSw{c4#-4?s=i=oyYMapƪwߐ jE'}}*nwJd q<R"#xj/7}&1_)r x0^(ydK #z/+bˤb3 6jWN=Dy_zNQ- Y~_)V\4uiה4QMQiڮ,rɜ3aKOqqhNLzOC* bM `D&΢O'mnMEP=o +n @mu=EA;] 5pԞL\$e~slvzs!!XX0,Xɿ/F霬iO+,/j2:/(i(FuA7n/?/N&$Oڸ>4؍,?ZYjhC+X9ݛM{0~hN_KOQ%/]]pЊkx_)? $ jl:+p񒒴4%RB'oc5m^FDv|#=?% eնgZf5 PGIߊ0& %2>VEwd]W2⠃8F?7y%HjoUW+п[Qs9瞋޿jx= 㶕CQ7&=|F7ywV5 \Z_1aُS50̲x[3h?x'M@=:庼6 grla\|ȰR_UgPX4}DkD)),Ҋ’(ˆ.qs?x.S O_ _p4~_Sݷ 3\!YMRx+~4`lX] cǗMEp((H*Ɠ˳&s_k^п #A)>E6(-MMMD{#[Ц/Xz4"',/M9\(7ZW1j7"2 ڶڹ)7#06Zt[aF?0~xwasTKKJﳼ!h.є딨0&j1d6z^+=ˁsxo[En[CC >3g@Æ~Iܕ\=cJ&|j K]H%֠ .Z5!ÛR}g)ZߩU+;(e4R̻ ]_5϶5 O-bT\y`j9 }u } ݷC ND6]HXAk n}$?Bڹ3`B0VFvZ?Y0.)*J. P*\3 vb~l~܀s6ރnvZMUU۔E ,EEo(YЬe>*(KP)n*xk{t/)LO,FUo$3s]9TUsD=\Q% bcKÝca‡PKa"Ks~/h ݯi< x=OuaSϋuYfy;0=, RB`.X9 0`^J$=JfgxD摿c@GiC,}Eh9Y!m`LJ:]ow]Húm~{#0˰^j,M~="P*K2HK*K*rENYPr[185&xQ7!B:8b1pCb pӾYP BՍJ H6}<ŷ 4gE]u$(8r}7RMD#1n#HKU >v6FB Z5!gGH KG]`:f=Ide]_M28^3*/^~{\eʆ%Y-_T-؍_3pԈG|S+hDAƚOYqO&w6ѭV8yA*h 0,#Α!r!oh:+@@7aW8}نQ`Fh<'w4юC\UGkBMy6>{ah* 6,'`pA{ټoơ~__ԶLBC{m)$ ?6>ȧve( xP7eZ {d7C{ >AyEdtRIxTN2 < aE?(:Z%?0?hjX>/pbӏ߲w Nw A`&0;a6#O"JjiB򢡉+(c(K+ do 8Ruτ7OHAD?4 dC{(1(]J :W-474h@sG(0P?,_<@3$c ıg,eU |`(oM{Wz4 Ffg]"p7C6/{P`ͭoY Tu؋yR3{m:йf?UwFpS5%>Ɏa$T/9VdّX8`@U +!eLn*,@y/WX[+'e23SZ|b 2t'eVC)Y朇J\{/qʿW.y) S~dŎ⥋'.;?)Ocw?n̉N Lˈ'?O~fN#o/*/.g͛Rn˟f^7,,g;b8~?mew~V#j?|mR2^n@|寵vuu~GYkW TxJcPcE#RB twpCiR]R}sw~FL&.Bcek5[/⹷C,Pi $OO|zfiJSx9eUe98ŐU5`hF4>578]9#OtN;H -&Ga/#9g|8(-yB?ZZ] v.^?HӺ*JΒ@ꪠK2"Izύ0/*eOZP<'[J^[[BgLL< XAQ\"㳹NP" ,;~[UHTpMhr~5a^nőHlx8R|`/ )iK$OHīJQʚ,ĝGW?;?'WOy\ y7{ed%tս.Ʃ'H$MqNJ=\޾t_7OqxBYoٕ Yir^U:) CA?29$(%8ª3{bTSl"4~>o<=:,Pob:?w|Q8~e|[>oI>x7k% '׊-C_{sZ7 0ow>7v幼;ЉS[~=~]e3zܴ;m] ăCuSyƮ;/{aCCE`TR#+:{xF U(ZUb:n?QJ(ag[ uv{ ͈԰9uW I5 L AU%I:|\Kl2ՈievI Ib5#sX 8A'uRQXfHMfhIV9UQ; JST KA(6% o B0$g"EYΜm肬ykDxQ,IW? e{g>^) <83>4w1xg ÷6tO2 L"E12 O#3G(gt'" Z2.?FW=9^7ggoc}>{s78Yfz8xg0?ph2?^è ST!ERC51A8Ef!FΦw;^iJꝃk 0Uo۷o~ _3zeZ ~W f_bXrJJy@:Gڸ3㿳ow}LOѩ|z{~ȥT&d-zsp'"O9YgL33{ҼN{<{F>yp$WN[z@G#J8E*ʼn#)"1<˄&s #u1%.?1C3_|s?uy>2V/0~RRL8w!goă$P]>߭?-EsM'sm-M2؛XKƌ7# ap5_etPAAi^%x]TJ YTZA?)>E0a3Wm?1?zΖ/>+);g3^A/khL[fWb7!MglQ@cPza -~^(czvn`ft}Jɲ毨>+ ObTE܊ x쯨2aYp5#7$  oz> ߎPl,?l,? dRi$%MbeaduV)Ze :OvIch o_uj//F }S25ƵK8y*Ymv. "ˢ5=VeyN!UAyU!UT8.,CF"B0_b)/!ɞMI}go\?._.:#|q kz(Ht"T mBâQNh,asl!‡~`PK P2 Ϊ bK؆}#%cKØ{Lcek!u'*tupn7?&eǩ?z 0xoїsy/9Mz5pfG0?J&HJt]pcp'vj{0n3:WUSSS~6`b@.IES(tMbuRU JU*3-J:L J#A._A$uVpUx߼fwYhC0L)oK? 5;R*53\1ki.h372 p*dĞ6ο)/OCL0.? x8 JAl"?vsʯoYZrx݂؆]\ƯdW4~cp{Pf~PoƔөNV|k 99yv,l{ftݞ݊/|ux \mPIH Tՠm @.qrUEAIgTEd%^SdEyUE^tej""CX[8,W_ >10뮫777r!cqE(Bc)P6a`Z i^6UݳxxaT|/1{{GYO`j;ScCǽ 4|z/lKn,3(B,DS:˫:qP9#xBk6CGE0gc/vJ\\-R6iRSO7B5=̬T/$ =̜s 135k;^&~5k:_h|qMzť~fiB<$͐IHќ,:Y)Y;lii'>jxKx/0Y6l#) n'֨QvPK~_~z߲)}O/<߾\~|_?,l>uϒ7cWɁ@zL3 Gx q9c!hakP r"0P!ɀZ'@XUI(| ([u ?#>z#'{8_ M*d[c>w"e;#O}3̆{W%𭘔XQF"5؞/J`U wS[7jh) ;͵ڏ.}w𮝛 - =1fEq_P2Wȼ-y5KOp,_Vg[H6f+w-o|Cn٧{C}+o?Oua=&\_>GE{[ퟰ 43_񇝐Q:u_$zm3o[,ALFCܹA7?kVCa/t_QL*?;c}Vl̰_8ԯ$yR~nwY AAmF Kxs[Ϋ$WUow{gX9rظ ]՛kqn ;K";_#<Ն{?߲v-ͷ TAգpeZI/尴Qأ!TcKPM90ߓzؾ^-D,+ (пJпL,%4@'q ,Eɢ$LD.'%G@7$ߢ9k7+}Ck1Sx) 5~5~ǓS[~,;9?r=,.cI-CsGO¥9@sΩ&1pq4Keʆh ctoZLN2M??9ZNݗU^p^9LnxhhjXji{b=I`VE[}4h.ʃh &@+ŵIhc5a\~aPEl<)  <&e@t]hfNSd^MxtK"?9 5?m?HgNAg](@AN*0C=b*X$+,f3"-o K$-FYNxO$VZ/wy(z['r:'#A?MQ6tlgЬ!w˲+,-IܕOL%EW4RҫjYqx܉0%VY eK7,x<@hRdr?r? |#SG ҷo}rku{_/bb~ys3)`L^ Bђ$L ,˳۳v*5hsG3Cn jxj%2&O)3/*:YՐi]4.'T/9/ Qwye` GԳڦ6| ,tiگ|1>Ck'^48lDpY??ڽ=j?䣃ݬC|7chY$m\|~dʵc}K!rMM=j=9Zfߌs^74.:}rΩr{yQ#>n%k]0i& ߨ ^R&Lr*۹9,S.\uc; g*[ L/0r8inظ8Wq >Ywvv 4JKxz;OSh5w^gҿ}?>H#].0!lQ]ݻ "v/2灃5bhK"'(qh %d/`@fS4K o}ஓӦ\p~:?k=J.fpQ m~9a u+>yaƄo7̯ [pVK3lbo0<' Bkꔠe?h/!O4!qCd= _/ܳơWqW/\SL& %nZO7GvcivvG-I2rg> LF1$Xi,ӧ*ct:C ߅Y$ΡOB9%[׏4Hfg0pЪjʘ ͱj*"+*cv _?z>+X}˨g*bܕOE-51cU82"f )l-N'O?{y=n_:ޏ!XXwu>BuJP'?MS6hV$S0%L@THG@׀g̷n =̉PRr~n7#LY> miwm[4ϊ$V۽|7%/}8mL-׽ߚxv+/ײԆGOʅe$bw(}Su%)oi2D|O.Ai75aTZuU Sχ>3eԘ /4/%EH@/-{??#m koʚ.8 ?OaR3kT776566rږc8uZR(G(ڲW768twt1kJ,3dYyhX) tReUzqXJJJcoo;;c{|(ڄ7π+D1R}6d^+a`fa}fK2a0)S<++dzXY#@2etP|*//  ?ѷQ64z[~E#3C^^޿kG!3}_ W?GF\8y74=\C4:rQt nz_7m;?%IѮUxE^eMuUd VTCS4FƠII]A@E}aC8yC}tdFF5+mHjD(Ǝ G_IVu$( w0pxA8>ģtkJӷHHLE14@:~" G8̢pH=%ad!GYXwPudaGttYψfs|*Hjﭮ$MlA:VU?@q ^a HH!7}=_ȩI-S+K,*kr4i $gg{ @A@gFI-73gwӰA)T(dut(ѺE{:l LqIx5vҀ *݋#X#dK\8{$Y#G~WҠAʠ!h9t 3` O[` P+zQ$US ^ÐyJEdf ? A7?#KNם{^ R8|);Jz-.pڡu@EcuĭVf[?)G;íiv==|j:P* "/ӚAɚ+`d\J __U /cۜf?QpqƥpQ(BRjTRgK\J߈BMM n1K`]DҖ-iiAdYim-ҽR -i#mߋEn'SMqb4y'ir7)PLZHGA5AdZ7lJJ.Qx~ ͤ'׫w džir~.:Ńwt[V7!bc]ʇﴱ~E!fh]bU7ZpHV3"4z 0?#6(Wh."CZ\$L~rj&+2,/R4ϲ}\s\Z97^wv(oD7Q-~F$>GF!:$G*+I|{ɿe,0Ayl ]n⿖ez~%Uxș;soS~JϿzɑ{:SKՐtpquE`ߵ1JUjmDb%^ Ym ujXgLP7H'1 2oP*/e/Kd/'?~;`Vv+0{zPS_OOj#)~_Ӽ]bTi"2bxqyp "0"RFɚ*#kNkRQ߆{SƶH,uXl#]ŧ uXdg?.E,GU=ItxQ{ʞChTE Ց7ۈOO0n xU'/tI3 P"*&k(J ( :kxGYFLy1ga}I KO9/lVn(q+&pp=m@\I\O4_fL@JmqMk8a^SU:lJzգU^84e{BWZI) fŤZVA8*D*Ttu$\*RT] ĄO]._.bvLHFwBWIH}#Y$Xϯǯ㟅5SzԘPcCP;:UAspD(29Zٖ۲zp5|CCTwbMQUV(Vb] ghhZZPi?~!@@[lG%}{ ۇ\5&$sfps+Bv|J|~RdJ>+P>"?op)Qg:-3N?!9v+ǟ!fY^C^r6TJy6Q>j]Κ& o:q4H~O.آb.]gwo2;a0cyw}!û;~ 3'"*M4V6e:{ėX?r^ V#qh &-:kPe'1eNTds/;Yo'wª &_nl _vZ 0BG|=ÿt;z ;48aCQ["e:;`cK[ގމaƇKym7~IT\Xc"ѵc4ئ z`Zd_ys?j4UT,4 l @5{D>vjٓ]2o~74wg9_ @~aH(qNjF))C ə,+$pg_?rH4Hx?5g̠@#.8o[W@gT9XZَеQO u#>f|tmRx0[Cںi+f۷o辽>{E\) 0=(SoSDVx3"nu=]slY5 C4YN^b5kw\6KX:Zz;?^yѽ ԑD%\b)pcw"Z?W )'? ?QUd %g{-ث<ՠՂGD<"pFАlmm#|dUWV &2?pS"(0* $^&*++fGϦ +7׋z<]~r|2]I1 Gi׺9c'5W ii} ;D Qz pֿW9y LTmxof3_*8u>e얆L ፯wkob^5.>}UJhxktW9qs'~LɘGs) /y?%1U#ki*9uM|K/[/OJAe ߴi7l1?hݝmi̱Xkӗ_}`Ŕr %¾Cбs>ATnWD$yߘAC-B"tY5E%6J|ʃlҧ8ݼwa0 vs4ve7__bbS[πCP7[i~/BS2)AgiΤeIuV24Tx^)CfVE:-  MO~>ߥ N'/S+Ůt.)uo5g&҇+Z^q^=jmEhomu3dR)))fR%r<Ӧnjc ?rSkOWyڼP[v ;yrSQhuQA+[lk<^{UkN͟?2qLUV Վqa o4FnH,#yZ4]xC9^ɚb&\91>oLBgiYg5~L|Tr $j|2g_:toyxOۂ)FG#w;{kf57 $͔N%C`ufM]b я%0 mS3;; ^[1?&' + ع.O#u3'H3_ˁ!(#@` 8>ъ*ҊHI3lpʈ$rJٛ4 N?_6}w5e\mKu^ z (0dI_YW5O)qv{:BjqocL(z E5PPĥ@9qTdN4L= kzH9Jfe)OfS/O ˷ؑ&7Z9挕+JІ4$ss-`J>jje^i{3,]ϷV>WtuшW>ʅrٮܚ5k#;`W / ˛Gȿ06REpd]$Y˗Ӌ Y5%֟߮iA|77w~gZJ?nƭ=w ]IZGJ|( ilJ%21" *D4.]|#)?^0׾9ścNedW*@[У߭'o-9?3*XxE}ayY쥍ze1K7/%lA d"Pºsj" g:O@Q?l0qRI(+sEc?#[㖚.pԚYOtfIJdV8p`h~|,/d 'T^~g҄e/6mh=:q74e4f5_:ç6E|=Z~10/wX}w]^{ΏӦ|_bwq?ugןucyw E_-StɆ;?=_ z(aX:?x:?>mxп,4M")u4U34^EMS 6S<@xR P9h=}@- ԙ!*NT䟷c:DQDGkQ7]u@URPxc-a**Z@.V;WX}W ֞5B'E#kn Cʀa +2x'ȝ;j,ͨ,ɇ{#`&< )l kW9El0W9I/<s@?[U+r&OZ?ޝR#-]muwƠ5̏ژ_rzM0y~M!z#f8BW,n]>|Yܜ')MR$A5MySÊV9U7E]U%֐e?bBNLN lOz3b~ P^t%h֍#+]9+te 59UY/'iaBf#w5g@;iqR?H*@i9=Zvt:uχ(m_hSx]0{Q[oj2w]qlFnj#Fv8BaaWђ4GN]}q>)yG1_asw+'ȍFi؊9ϓ_uߟcv_4uM[s;~>!͵~[ Ohz:Gnmy?4u9t>dҩUk8?0~Sow?~^ŤFʒʪJ9?iՍc;sXblӒu Ysyٮ(5qH/4Btr޽Yr%ᐟwP#VpoxW-V^x18Y̯4 + 2`\0L, _B o_%=0~uONb&YcLIn犗=$Kr: | ZZ^n >r4:cv3oH lyɱ80.Q[%}׷imwŘfie159!}x,/V_nZ .Alw<+*ʚ!7EJ& +kkzH ,-y6KHIo)HAc?~U+6ܹId8wlw~}y VybEu bo쥵'l;G׬ktԥf\_T5>Yc h5yRj׹}݅:c]3 |Ww3aeCl;+Jv`dô$L1n?]nB@8pQE],t69hfD{ADU4u45Q5)a4B Ys?_)oo0{4xbO!2\+-:̹h @*~| G rŇM}2 (ǐ| \[tрSPY 65.d\*k*WMe`B)̸q?mN+r]^ 3LΙ; ;n`p(vڐ44R.ML#, tS2g9;B5o@7 yګIɬqI<6X6I*G D:1OVJ'@mE@O aLZ/:t1*PD*z#:'E h' Y[PN3z;ceK Ϟ½1LAj{wmZ ZhZIHP: j*@o7f_a,d!~'eF&f0,lO~8:F|j7)yM?c?(nߙw̍&7UY8z7Gwoo*Ev-F,mCw]L}r)\BP9F_C/dTN=Kj]i۶kǴ߯h'W7yi-ߧkӦV4+gVw2t'Z2nxdz{ i,^;ᓉh묳Ȁ]!x.].px)|I/)f! jju/ı!񒬚z3YN_$#N2&?+gˍWv |q!t]a5dy,Uu1vݒ 4i#J4tŗ&hRI"wy>ƒ5"i&D#|f~B&B&J?BB?IHM <=+k(,Do0r~&ʱ+לWk)~&9W{ŕ.μ*>O[-"m跆7A ^ӡ__jڻni]NI>[;-wMҭ D{oHu _vDȖwfۯe%5x}C[PCfqG,x9c=J1 >޸q ^y%TCY2({.GR?TGW&UwH5?QAUd^VQk>zh:*Lݕn+]VвdD,JI~z dIR $^yO#x2ASp8Dq$+A" j!1HsI_Iп?"=c$1c n5r7Y 퀯n?r݌nc:,t;]njuT`A?9@óReoA cƔ>U[Aػ*,]}MHHBCIo pBDdpXSd 0::QD>atAq(3[U&ī|Щ?9uʢ]=  &$x_W#J4/`*1K&"Ӭl*jPTV[aŘOx$?DF %SojiX-jIG3=P0-m <@r|_-Ǐ2MP3Cv6?Bu}e817߂qTQv͝xRmznn@nwGgB@N{psjBGڂu[~,*y8Ѥy?#s EL]%U3% "Ⱥ*Ft'%?>aN??K o3V0>xѪ(]oj gm ߽Mܛ돗}#Z֕Gm1%SSY4fwEx{eMkp&&m&iu(/N|(^rΛj鉙5L_*x.swnNX-KgZ~tkϣD{9pE_N :kk}}LE]-]9(22+ FzЗ-Fa]mԨ$ऱm@^+A?`AƐh5h vX p"2:)©!Hj9Zf_q!"Y"ˉ/%S?;w$낷8Q/׮T2}`lY o8OCQfF|$'vd$-vdMd={qWovx|_׋6 _#Cbկ>m !kvmor*M j.}++y~K8<# {2\_貙@E^ԡF/j$* U?-4L8܉Ki`Ï8om݃@/k|:@/N@NqPbf(*C':O>zG{p4^:NS F9yeG܉M?>Vp~ٻxZׇ>kQ/H6W&kbl_!/"9be6ÓO : B4-=ז9h*} 07c̨9QIȁDC 'jd%H?6yoi$3, 뭗c$ y"뿱D+=޿,{abO?l*9#szONbhCT^ ,Txa ɱn@yp܊s| * FP񍱟<6 / PI s/WӠISb]ncZklNR3|s5M_T3/֕/15zGnCؠ\=]z{w|k96<ܙV[R;*lKAoZ ?ʦȷW23^UD9{,)ě7)!oPIsosΰz@k[4wbo/9PD=(Q"K&yn M '"J'pj< 隁 P@+1_O E'w(|4dn3{˿=9wwgug_\X-?QyL(\v2ΗGU:՗˹*ȥA2ʦ~(fny3FgWҸ(9 2{jƼSgQjPX]Ki :2akT^PsuAT= A[Xv {'׃d7\JS44UbhYeXVQ0AYYTL E[mTb3q! 0:n^S$g/!>0v|1ٔE9; Tg[ ܩ=XtP`F]m 0[֌F5ooz;;I>>)OMP-udS.C^֣Pr#lxو1oG.hVOL6^zdEYO~EĤ"&%fؔ챳RRuG6JרT5 _MSmVr'Η2+ŘTbjސ~}>dj*wMM%T(k\,C?~# s/EIAZ1LZ_Ќ̛*:48]i_3q!84bΉpNQRTqpM^\ypW@tF&}")#KUpAߴ lHjtٽ7n,/}Ƣlxhٙn3g/zpI]>sҰW–`$rd<=r0%}c^_-\QT}`RƷ5&s5uMV4M ID^Yd5u\i/?Ň\M? 1Dc&%;K:1t ݉NɏmTfEM K˺r0hyAFaʈ 򕶮b'q!E= ;vɓK;_njb33k䬅MO;`; LIﰩchS>l.-ZZ Hi)a>Ott׺Bʃ#Cò9p D /&"«}w'NjkM+&3BT}vKK"|PWttK N5SS *s)LU5DQ5dFbԠpe/È']?% ?$_W9煬oE/G2'C=ѽ`CU Za^ԋWŗ~{3H[g-ڮ_[2,}s3C;Q

$?f m-X\2 $W]Q.I( NGKG8 gwx $Ov"T1vU)8q}*Xy^o!Ag8Q2AҼ3$(jd*˷&Cek\"xG?'ƺILCnO&&P |>灼ԝU<(^Gp#Ӳ J])s 3zy_!1𓻵Ouٰfr!_Ŵ^a]?[[9@1p등dL̼}2:qR7۝Ɲl*$~yJuGb`^wY#QCd~k˾\@IͽOQZzӴLULMjX7_|V -Ss%:( < #I4-!U.HfXN6Ņ"?\ _ĭ#?(%%dd/7xъS ʼn(f5w֬dL FB[OSӓlm&&2Ԝ`PӔeZ98C?^4FaM]YIҾ`+1!BD ?{OEuf7laxjb$ٙ](M("H ACv"PQFSkնZ?"ꓪEF"UKw uO{ιk 2ej4S s\g("R/b~^%6 ?qU?1O;;OČӢ [K\D+mU~.gd3/`p|\{UZY.C?RJ9]XndIB.i=G':k|]!]Zh/2DXڗQ})Sg 3| B|^a _#c,ZӷC'nY9L̦:TP4^G9]!1Gy^AVL$=*iJdgU`(5& hn6V`0s5#?k#W9IrASAoË/ .-_hΟ! %%;wV2'/z_*ohؗ?twd7hB.Tq%jTL/t&B3qv>MP! F;H,3m1bRW5,TY+^g>x. ł1ג6ۘ.qfiw껣^Yqߨ\\K>5R(icz82pJSd14:o*%(>(>Qut}ѧ.]]]-wv~3c# &u: ke|VZ ˖y:cL'M3uZn_R0;0.ksђb{Aht/`ٞμ>3=Ri{ H4:tٻ<ɑ Yx>V%)"ÑzJ@gɦC#h˖oz/q^xZ&;ӎgF)S 9>NH}OrO PP:e)$?$K> &9yIpOg3;SBxu(BZʇ'n7~=f|IΘGa7-l~ׂ: d2]IB17 {Wrz~Q{PP;%1,ޠ'vtw n)gXK2-]dJ9׾ħӂTS3OzfS 4x+ ; ZCV<zV.nl LH 4*o*Ϻ~@b7t|'feK,9fMZV)fs~H<;?HgGD|{^Lt7Nшbf1s2=r Ca_0 0<.! s P Y_p|a8Q*0 ߶ެMjh>M\h5kz^ οTd/f!f1kl@4թ l^26CE#֐к45'`P@◤XP j1K%.l1d쿉0nԥZXZ em~|}^/d"ԥuO@Jq)!m`9bg4PD6Lf|o=`P9|d)˘icK̿ȼ?,xB? DĻ@xPSsv_;7|`xlMf+Y0S)Sf`dֲ+ TJ#$|$prVV gп lWI VfwvUV`SQd\{R[Yo99Tm-;C{h,t]dG`DQD\'кS%#z\!I<'~,!(NL3o(٪ 8wY*zai404[Kk!u?~Ut8-~#OԑPE+ĸVˇ sS%r>w٭JCF?*ǦMD n9 KA%^> xD9蕥=C%_a&?Ly##3:t:ְg!쳇bҬd!p}s?AdHgnkw?3mpI< N% ~ %ud*HP֣IS?V<| l_UuZwR-u1Nܨ#8h]u(7hԒ T9vnW9FVʼn6Yr/זжQy`M-Ojt=NTWf8s8 e){!6*eL~<{`4z,jxu&##0E yqj(l7Wƌ,F z 걖hMn4. Q2յDdR9^ΕjEiO#Ag rUʧa&R]goյI)jAfOMuY_.Y(-H/)Jjw=M6|xkZ ]E.1VXh.RԬV&+-ߧ'+J+ͪPS0P5jBkH3hSOL \8ŮW.|-U [>jƖYyz +U=P n yN?A,! JCuUof&T"%zh$آqBN{%aA JaW!pzBAGe.&26IokCsmŏ:(fp+IgA[ ;Æ amxwrpWE0[0ie+{YLv,60p;렜K3 H/'vkRMa#ʏwH`!;a=nWt>(>1 G6/DrkXi)Hwo"}4%ϱzaC(U!{ԣONA>U%S7(#Aۥ@LwHupΦF }]RQ ]njNoss-ALFU؀UhUr$tĶSR9G߼BOZVXc+BG!a48 lqhy&<U[PPoAP{Mp#0 E;hf̶uՖsS6cQ]dc {bV]EgOGdE6t‚̇dIA3,$7]A)Irǩ%ﰀo QpeL ڭߛ |Cj#eorؒN2p;:C+t'kiʭwʍ?cNj%$/! ^OXa3$e^pWprH?d>sXΐmW g/0ߪ6[)^ˆ \ؿ}1QN!| 5~Eh*$;\k|!Ҁ.bzTNsӛ/,w gI|W: `B!p:[A/p&FQ7GQfTϑDtuQAG2WU:}TW_d?ㅰI͈"E$V( AOcV;tOffv ,WG>_"Vooˁ2bFN3]_38|(S)̈́ );2t3_~Χ[eW]7s[-Z5B7lP2Rb?99=kf3ԷG}Z6ZGT~Uc!sB CE;gQ{?9XY5*̙3gE3'; DnhfiQd.&Ă$?Z/2>br3]OrG}G mDY%2r.~X%M։>E}8@Cm1WV~)ņ/0e@clX`6#O#^b0X?D;Rf}N~w,n,.3>Ҕc;[XK@}oH͵HZymTfUq샇g ʙY8ϊa!(F,$yLH 1)?YMd9ㆨ+wmzy| Է{Bs!?'{?NT"zڂݏL+WEWV-j|AشG|E%ZwʋVRHߡ}gnx t@)E"w+ʲ5K J=6y`8+/Yӎd@k0WS}WM[DsމKHH"w*~)DHuHȇm1uօHD% TC"l{*ΡRVƇ$_ФiΒ&-`tHR?$$wqv؀R>_/H:,?c1_$EN(-y/D Ab<EX.{)@I]xxDz/N-Y $ $ ƀ.'P؆l%.L0A~Rt# 4*~e 8S Ed| nT5{WwT qNhq :8 ʈWG7ύ.鿨vK贜eC:tȨ=Cz ,%@֞3, 'AL i&(Yd E):2Y)> ꟽZ)r?;JfuJ8*p·m SzE6;LHJҝG!Dv=/= JD' 6; b4?ūȳ /1H|"E"HQa:?cfg@_?_兊 Hמw@9Qw.I?Ybsu}hmG=79L]D}DQ_G Rp38w^w{}=b _[pC_낾ADзy}i6,{A8ɃЪM }v/x[U~7I--rfy1p1D,Imϳ-dM>Yms˵b5c0ȹlĩQ.ho(hB6(kTub_QŨ6RDҥK| n?zz ٶ쾓,,럏4JtDd,\i)(hA"t7ͱ>:w /5x p]ώwQ'Ix̃e[ ]@R)ϔ;U|'Bw&+ PWyJI^xC&Ikr-^[*_\6Bfl'1ocb_= =\K=ꐘ ZQKu쐳T|mn|T-d evFb ?"g^jڢx>t tqq&J\#IGixJb2?Ufa: |^ uKVɽ^=^gb+"G,J@/QůooZ0@&>bTF۴6ލgeN+LG3/azH;첵tL!W3jg>SqntGpq-zE.Ȩ]ϤsA''Qc3vք&x6pNQ܄9y>`qפg#3=OݏJ8_\Z'=M|cIJ6 gxWwpc{]U\PZ, $DY?f$ޏ 6H\ YAkr ;(}+KKaaBnѡ(9yheGUG-i{lLv99`{@7wkfb{*v2&: Ft{AOA%[Ҥ<Tr?$Nn]ݻ;C󝪧>!b2B<7FIjĻSoo mmðfɮ+*ٍj[޸7LOVUn_Ǫ˜߅ei%46O48IU3K2QL~ ЬȽ5hT}ZHO8sY9!ܗ%\$ёHNLG 8>Sn\UFgӣ6hmklh|r}#'p1jYj7o"N/|{cnvXֿnDh%B~DR>r람xVz`󨥥Eڼr|NW\6F)2R̅0 M ⺆}G7/&݇f o[co*W*&(m^%)g ZC@#M0GO> hdoa}>f|ŭҋڞܝɆ/c~(k+Ϗu1}d\b?M&B&㫮ʭN8T*aUm 6JgkB9F.Ujlhr˛#m-nudDkrŠk^ђׇӭ-Mv5yoߨM. QdtB#-N^~dGe8j,q#2( 8zBZh8DA.BxFFD{@?,棛ZsEK.־RiZ`Q*i̜irk&0(2!!h!kg! YB/ 9ZEKk ‹ 7Gsz>9 8e/i kF 3 't/FŒŨ $q3 u $2": ;!,Ν 3$W;8@(^qrt_R_!иzi o0:|jcACU2&Y6qz[)ʅп\?>p}5v$j,ALdyz$W~0 6{D}g&jҵ|HHɏP?iXKӼW%eZJ. կ\۷Z*AьhC ~XnKrgdy w4^Qf'UC,ojօi#?j>$o=+('4oWoOBKTTKG߫u6ŵX2kTrZ?.\%V1IJV?,Fi=,[q8l-?5`CKqBxd~,n\ А;6+G*Pi#^en9V2^%kޥ`ں{PZQU,QZ,YiJ; hPW5=ä )k(|b>r-#%#rgW7BiM>bX>-(8 aR=]p4z 0yb` .Cӑ@3eKW!!hp֜'ЯJ(h O/C J`fhV)k0F˽P}ͺۑ<rQȃh`PeOTS h4Uю1k?I4 ,®RLfh@Z*[\XD E[\(->UT.T*VQ*j?B3sNҴ"k'3̝{9{=7EU~c\Y\hh^\vUU wI|K / t/(ܜ]!6Ϲyw }b7N)oq^zm' fZ>y ҏO޸,xXͯ[Q_DS"X$5~Ǝ}ybh%:y nağ,bݿjJvjLpm X̮oz_3l6 !p;-vF= j#894~!w6*EUDf\g{~G#70nK&/g=U<<^EK^ .RI-o:F*++{aF2SzRyqYYH>ʨ%[A|T {#b2/.)VNeDKٸ;J? WT;ݢzDUe$T'T|ǣeߍ-Tգ{+|ͻ=گyM=ӓ˛uJLU-Ԙk ;8X44ߧ%g 8]s>μɶ>akj*.u{ɠ:{h,E й;uD9ܩ|5ZA.apg pH&`Dвp`GG\J`Wzmx^8dpe}/;cFC&:xjT8+ A2`TgO4(("}2o*/d?+<ʃOOlQ& K[bqSs2d4 ] ZZcl?FU a>xX_/0} /D}jKn"&fulXIum )isJH)ݠ𿝺{*"RnQ)E RH`6.; 4uR>|ABpN vdiw>6O{A [YW:G:/Қ^V/GP@| W%"n"ֿLEs,OjO4sP]i>>\_:e_X6 cu`<;++fX92];8i6\+`.23[''IҼ ,+Ce7?貝6&ՁR x5IIf{OgđWm6+W$7WҨ#8(7,>N`] =pr\b9qN;/9NZO(N @6*)(5){p Z.)$<0.7u`">!h@yQʮ,0 ` 0SSVeb>MZ9q:ґ6(xp O}>}n/t\@  .Wwi?sǎX s~@Yxɼ^uQ˶sA]glVN!mDqOzѠ&3!)nFCI6$3887&ÎYu(A-5"j7뇮&+Ȓ2W:_;xI=@uUW.Nja)!'rCv "#B\HV1!% 1oa:0*{hf7,,%r*Bzzݳ*ҟ2ÊI~S?uKSH-#e_'v8{vg=az=:ީ]${{TKW] GpYHr_TkR]AZɗ+Vm$v+v#YY1PTv 7j%jRLI<|IX,%$rRB2F FN鶎?ESe" [q]A"UR;ĝR{?[쩡K:Jk彐 R㊛!3ف5Kg`vղXꥪ ^0Lk8chMC儺t܀2=ԑoJ85>UǡM l3tc{+[]| o9 m+`&f~ vgl҆]`/&,Y$oE$-"kh{Z#f݈-!qDp( NGݎG'#W@t!]tP޳ʉad DܪaljT ݣ܅ zSF + H|cf!c!%b%*fT9,l5dX!l$Υ&δolj e#ik/Jr_q:0*3($leYag OV*yt4|dImut-xgsVq}kFL;hcnM%s}T5,SD I*1']y-nJ)cQmΫ?,4[ g뺋^o :PAlofJFmG܀LОؙ>f`JmcL)_Ԉ߯`u _ 5Rq~zQWRYir$ƒ(a&R ēPgڎҖY{b: ˔+xY7j!Ix8|QN;Sn sc2i;dj>>I_uDf?bQPVnG~^ $֤3hDYvIO$k¤$]zx͍(?hfʁo|#wڜKtb*ɨfCr&jflV>>& ɰ$GwD % J{/kiٻ& c+tZ#׼@96/%G b6ÉӿVv#:1La*zuS1K ]NEp۝B28:X/D9{Ǎ(wζZ (_]`T^ jeٻFƍ Ǡ_rfT8FeBM 4ΣNH(HVgq&R;2ߗ)󝯭H@Kns>1`.pn! lơޞ$kvz_I;5//?)wHo\yΛƁBJ[9xYvLK8 Zc0J{UV| F?Qu)zE瑾Hq 1It4i̅xb Ɗb o"xI Z]AK z=!at u/, Iwmĉa%O(CJs2 ||vȩ?1 }0P|j:i%W M9 1p 03ko?#@K!x\A{(|< ~X ASnqnwJQ-4[ɗz vyy~rI$&Iv竾.*:r jqMyB{9$) G~BA٩AmP[}اsCb^#.ꦖ&g/uXpm:Y(gf_GYfN$cIKd+ Ol(w'#H C^xj)JҜkJW3R73$&K^h.t83+[ Y7UI# p"; ؛^v>POd2E$H^H, "s@I#1T$`*%W/:);7>㕡z:2655烶w + bLQ] T|CYscbSD-GAPd_ZZ")&Ճ¿B+n p8ߞ ФV 9w#0 @&eIvݑpeT /;;~)r=Ҥ4_xuvGiH)U$\usMQEemQ`*WIyPc$f12!z>y8nrB-s*>(B+1P؎ OfXKc޽ٔ6i 0;= ^~cm]=)wH PIq zu*gùzs2 -M<ZZ4d@Jc=*/=I(/zX"eV~.g@6H J'}sJwPq}cP)HRjNsI^_pI9;۾ _)ߪi$2gYlĠ!̆"!@b 3;@jAc-B |P ϶~@Hܙ9syA}b^.WS]ܲ''#"r$u?B=[Np=^E++GLbDMR EhYQ"a&( aYcD&0JD̈́i9GaS;}7Oyl0x ֱ P - UIfX hG{8紿8$}{6c=?]헶"8xg߱8uF/γ~r׀<}a}Z*Lݮ$ v(8O[2]"^4:OFǐ ~0m%k(⨆_ }GZamgП0X(5hy|pT0~sلN|L[eᤜxk_IaV/8DsIDQXx|8X%RxmnZBcג'} Ҍjlee'Z#}"g+#u\uBӆ_œ>[>Ldw)գ7NrKD߆R}ƌdLO i:5"䃑m>a;ի^upϸuPV\ I=/)pw`096 YRTET1(B9)n_/qTEQ|X3u(v tw]w^$ |p^ @|I^p)R3\I‡q`v'nD,Zowwm᜔ v]*#8Nd>t}OYb]qNBSTo41AZ09VQEU̅l8(^sZ_W@ Z@t3@6hhz-ۋWǖ/_n!d6Yc 17^vYQ-?ٹ70oX`a]뇰W@8PR9rJl(B_c;{1bώ9\J90Cx6ܨs}eq\nS|NC"^`5ei^0TYe.ܞA뿘lnYd]2 qVI c0A7m߅OH0@` 48` S@_ϊ-^fw&1o黽٦ &4` |bU⃁$A"@Nj PXه{Ӌ7e^·S mI)2`g9 ˎ/Odٔv.N|o]K',N}k V}7 )=ue`f =(ڿU¯N>#I!)HO'ĖEC ^lȓu&Țउ3pz{BTy(멋ܷQyB.Y+Ľ$pY^u= Зݔ$a&rb@ȇ /t " XF*:E΄[$Kt jAD!(i^Q"b|nx=h9 kk~ .nxEˆXjtj ؋[F 0"jG|; Y$ZNY!*!- d8_S@ ydf%-eKAG3ɯ7pa(htDP¢,"JPR9Ii>̳\ZWMvPvaV,j/0.bhK@ NEF-7idS7; L#hzE7WbF!OU)oƪ|>1Hk[/Yj`G+ J05w L܍a&aq޻̽(//Gߎ WLk*"DiQ(j;T<!qC{sBWe g4:@ta_YhQ\fWVTe*OΗe]5ɶ~>S8Jcf dvqT\nx^^fQye~2o0o}2OՃJX45 Y ]rQ ąR7f7YAn2dNI-i>xoN@~SCp p (iuך{aSЮHBP"! kd5>EpPTFܞ8;ǹ쬟,`Y6FQ=ʨm"\Gܞ2`QWZ`zU{'sw 1-y ,#9IP$:, axEh.KҎ,ͳS?;SkHUZS.c2&j0컼Mu|ym7Zx>u]oA6iHBq%.'G,g}@r9dĞ\ n PHM<&*)8ׁX#AnuƎmq:!h."#r>~~#^jyx+ kɷ2A?x-3}M MGjFSngOA K07?M?`uQe<ٔ(g⦏r gQmcWQ]GޱcO ė,ٳ[hP@)`~|@Ğ i[-;s' O2bL|D#޹8? (Uy={z)1eݮdwU 8EsjVIc2$\\.N/MW~\y&s{k]ԮueӦ(0 ysJQ(whHѵ.4!{'Y/}vFcŠ˜.@ *rszh#d)T^I~ZȌ K8sǂUϫ(Ai̸3:?p Wz.uҤs]:חh:t\Z 2elD PڏyJ0=fmݝp)z f;J[) >8a9ٞhw}@ȆCEt~^YUlRj+_x|]/, n(멁an$UMErӇ#UĖx@acs@;a]36snF;>Bγ1ǖS o2:pfRXEk)߰,El|\ :&[/ۏFq*Z\(i 5fޚ*c3nܽ^,{r]űUn|Am>{9p5i9S2+}Mֽ:rNP3?35۶ݾQu?8?$a5Y`́ gR ;z"moco5.tް׽k5m\_'Z<\ pҫe-wWfKwҫplމ18bXyA|lؼ+&esӓͫcيmCUgt}t=]2:~}3+o8Fk{F䯐Zxd '-kSa,G {D4 -|?GԱn&x}"CBb S%Pi8EEb@1JLLWwUu_戚=ړ++%DSVq+}(gD/1{`wz6}Ͻ[ʭ'mi/cX^ <V$Z?n#>h4arlvQݖ= >$ E$r+'DQ %HP ey@d_w&clp xbSmC@~q;b[ 2{Ty'H@9.U4A6^Em(?c678hrS9 yh b? l2aI?E*yOգ RأB%P|K_9 gi~3;`?[2%GOxMo1%cfRTp`ۃ905 [s ]m6q ~=oQt6v)Y:dҕ?wDսb8Dk% A7G&͟<*[ {I¤$/"KՐ׫Xnե aU"n!Ⓖjx yWw83yaAM{Y^$7{Qtg l|P]DnGUmA-c2t0#n)f|!q{xUʑpuְD# R=/+_pxtEkMۮl6 ,WŘ;+bep_د3X)E6lpPRd7ii L-wln$ 步ϻ6a}"e86ɆL,0E7q[K! hor]`a9GS0ԻVŁd=ea)),7=FkM{󢆔iГF͆./CxZ(tњ2LO7x&ٝ>{t^837ή 7 Џ {!E_8+/t ҝhHȐQ]{4vI|,ܐµG 8B5)qOŴԽX|0,DnKJ+RxA=JX8J3(h$r[ R)4JKGbYw9b8BKmyxxz WV2=Z ŭَE Ġk5A7:t]}1KQMQNOQ+Aw+0"Gg4;wG+bu%dPy'vx?f]C>>ָOdj46"tvxT凌dҮy Ad+yˍy8Uӂ^UY2z8=FlOjr15&,i~16~"r|mV| 0X|(<7Ir$Q79JB{$tzrj0lidŨᇍpÍ- ?eB0|t^OPS6ph4Qi7|']έ7FgRwhI/.˹kӠKmsIXr߁_Z81ᆔN~Aq Ԗ.m?θlY+{;.anӏcon'Ԑ}kL=qM˘w.cQA;YGSBT]!NpR(pϦܨs->z$5?zV{Ql#(Bj#MdMՖ"B@clz臨AiE-;ޒog`gOdQ,4fL{sph7ܪU͕wɋKDm&-0wo7w@|V`d㣬X8meVjZUUJc S3tFMq 1ncc!JOLricUx]6c|d&W3Hcto }b^UZS-`_߽>.'7'L2tY[w{Bi" $GaYo\VYy])[YiG+_/>+|84wɷ~5m-EE?\Xhw7RbT}tuD/}O;-ѴW4OOhWYO-`".r; IKQƣա'Ɩ&Ftw4.F:bS;V3ϖ^qETF,쵹EHk߄$s% j_}8S76dAdM5YVqOu3B!%MȪ KS85l 5 O*HȪNY& txG,6~#Fc[<:UWh%H-5xb7b>_rb g:#?\|/cw;>;8 ѵ-MM7k)eOb[EAAG|6THRnP}B$4鯿>dbSnPeď8:d6iS6/0NhftVwY g2:]x =v& Jīnɥʼ*Ua>);kP].QxIy9ޠ JDzyǣT^UCr+]%>}4Ʒ^a6!7Q] X;-'~l%Ҍ_bZHh+~U!n~W|;;!l鄳s?Ƒ!)Gd⪟#nAuz`+hqy Wv7ϻ^WPA[BC|8ᕐ AɍCo-{/e_l:2Yg}Vׅ9L;fѩ?[MZWlrV8:d:HK\ٲvr ^i=nprJd&3I4{U;CE%8S ǖu[$5ax/*y x+QC.~?$1 metW಼9gVU.xUU䳝l(3p0}u($Oz։fC|Fo#EW =%ٷՁ:Z*(VХ=:-k,ε^3ɁW 08:MVoӴ+MPI9C0C+L#0G&˘"> ãX;{NB϶Ê>/cYq\#1|G );-ǖ8xLbp0s{%x[RFti,NRb@  Q[nUtK@ St2 2 3 +ݾ3|l>Lb~yB N{>Cֻ.ɩ;ҹI.XI}\:HgIݩ ;ҳsS ƁQg ٟ>W?AY ѭ*)zÂ+ K$1)1և*Zrf^v`sM%kRRu*b y: fcij`b~%R/oեߥ?V*q[ʙѡGAM|d#kPrF9Jtc󀥼OTӍRչi4蹕(3i#).YCc R>xTnTQVvu0 W5 뚴) LۚKܽ1US"mcݣiՑut%' sxns%Sv wݧnF\c2*VxfCVY+ <I {-IIk6g?ezm.V4The]Sآ{f %k!]1]x6A*r+7%WzĀ[jX8nѝ 7`~yS;aGٻ(,} DEX@ M@:#8 3 (D)&aFa";"8nt*.<{yai8s#hEv޻){7p :܆gԐ|ms5R[^sC;5cKSyBcن)ZM ǧoIZ/jwzm_M.ƥ.~I Hi_Gc(ի?*??WJ_f{,bGg)E궘U<H=K;ܼiKMg+d n} :R%n3Q~jIa7\DٷZ->҆ONh|\YdUAE L\F5LĪh6h$7wXTYRICA*2`ؒ u>%:&!nsMPa !ks^T_ٖ!%9Αq݇'C#zQ|֐+ zesqwAby ffψr7țqEH[y_h$ _@ =J.:#P \3sVܲUr0?fC8F\M6>^=Ua,#Y|&mk s|^/Cv !f?w ir&q;Mbs;&a2ɉФppxuN7:(<˜9 e\32rߩ@*!<Mh~ze=alYIj,Yaa2M vpVZ&(zpZCfkgZ{fҘ8*E^ʹr& `d7ILDq)e} [x]jYj QG\RZdDpIC6NOXW~rMCW:#e1,U;yD 1/m tJJWWƁ:6d5juE񧗔^xa?6\^EJIӜ$HEıQ,\\.lS=.wҞ1G%KО @ݙT֚zpmH:y 'ؕ$]1/r^H6ؙw:TS?&F.?@Yy%l,^g*B b&ЂYz]aokWxwrhZau&&~ boooRR<CA*Nk} \~-L/ݜg vb×EwYI?7I ezŁAdo ׆޹$fDO3~bK6ݨ?)Kt[Eo}?vmct[R<#߯Ⱥo)%= t[x4ufd 9lrfYUK@o`Ɵ p",<od6‰Y^EM-ܤMف!a F8`ayȱ< A*kFגw,N_O.Vn`G1R ]%Iɿ%08][7&kV<Ĉ<+HFoԩ.bdg'榰!|A+Ju0;R{V4|<o-7d$I-NO٢f,UB9!+PF 8MH҉RŰqJvAϠ$! 7(]Јhg ÷HV)ZI oQSgLK}Dօe,%nh &#MQ7IIt w DBS9ɞ5ȜЇ=Nɛ)RIE^83 v9KyN6}5>ƦJ*7,(J ]"MAB?Qsj,`vdQ)9ٜKn.$sPpWt?]>?GoD9G_`p{kdջ[<&c|0כ4;ZWv(왡ô?}2Hɨi ݬ:| 1sL]}i_zLվfRkUv}<  R9#XU^%'Q$Ji2D:сjHW2Frc26ٸpU4.Ey5-mW])I>ݒaR<4{>esyu9.|r_W'7;skS:iP*pA%S1r#Y z/bN,ShWJ5ďmLX";9a!k"d`'ψĭ 9XoCѢ&a\0@MG;;X#k+Bx6~hVbO`w_֓hZVD#5OQ/# eR6J{0WC-ǚ(Wb:PԊ{Rv'$ 麑> 9-|TFWQf~N;Nv. `/ x oQb+xd_"e5ΚB6zNKhQLcw~@Oe:ZZG[?4U?u> lK` X;K}U=&~g:t?uOupfKMHZ- 1 I= %j~9=2x2:K0.m O(+z&P<1kc̚j[:ʫ򾼙lѴd.?|d/۳~DɇDZ|9/,SpwkRkV{m OW RŽ=]ןxw[=GCJ䙽@P)r_LE3a̫2YXc**;v8W^p7T4_9O믇ӍyKQKŜ m$ZѿnGlA`7~: w/ BqMt4˹"UX:߱2s#jnwa_edG(]|'vHN$ N=ۋwlϜ2dz y eZǮG~B<]2ٌyϥ6:XnuRG.&G7vӂZtTI4;$g@&'sĨPTY@5R% hgyzíQ%ڻ߻ =qφx4)u3Fk &.IPBo:Š/:17[9^sg&%3g4W_q8nW[&Xeɨ")Dܽ)BKe:}3P.tv fR˷Kes3St|s#qk,K9S*ydG2u+^; dijEY{ *VN7V}bz^3A [CUќ?EE9 ];&3 mNaxCm)U5b.!s`Aה<sz: wR e* 6zH5)[3|$#Zg/7Jx7+~a7rpņqP7_AN%RS qi)Br^Ԯt C$DȽ<BĮp|~Iȑҍ< W`Qx"136-C:VDP>(NIrC sE0/WB:蟔D岉!;-WtYvgf5nZM 613K^ #=~_r^ a͖`8vJ.T WŔZ%ܪ) ljŽ@A)+&pU|2=i_=v2%}U\S+>(kJ5QET?t']W1r7T5pGb_dqP/K$Hzr<ia]4DY͟l Eڳ0,bm5$WD [.#nCpTT"*K >*XVߓ]ֳΙ$/iHC&ך^98d-F_o9'Xh=| (i7MVoä;ݓ }M ?k>7$~/`,&S0^iVgc5W40?n7!Ec{_GM*m^HU|n$J89QKĻ.jaYGO$1D9h18]Hꚶ–";lt4v,d6U%nmzJt{nk?Za㗛;5𫑖jz ]3 L0E2)y&KK P lUixy>g ѻI7y4.}mÔ8m`gg (Wh+K (X;ra>!rT$T&Wo,oyRsgpM2c#kH.=oCYj|vVo 1>ef-MCbЧi)K^"/˝+Q۱)9o,fc؀NJTWfk=4E%eѷwNZ\zEG'~)J/^ˊ/'>>eȟ)ڄ=yWU~Xs5> =+ϫ?:zk'ʆpuy>D!VWc=ϴJrJIR|}xQiPO,D)W<p#'Z[E)4lZգ*Lzt̮J/g` JtA<Zlt=u5tAQkV/nfE%еds^c3]&k[Y3Rf3G=UTúk,2"`!o+$Q{ hh[ԠZ01noixbY;76=m;wEa:1 M\kGvW>z qV.0Bf7FG%HBɢø!@ʂY${@DYѝrw@c27١l,Ff]?CɎQtxʳG*.F>\zZ%~Eķ,C: f2܃ 8x]Aе"~`F|+Ȳ& kYwyŚ=]q[mF7|2Ohg3ztғ+zJ^VASзԹ]>4}fTZxs2db~ڨILYO쫀n !zi,hg/ȅ5@51 F}N3og=myǻ.FCgIDaIAu/=(3QD7nhԔt)N%[ &( [~/±{ oM9RYBi5ܡT~qr/-PlJcx#h¦h u熇Pڢ [S0 x tV#nj1۽g&ZyR3" bO{4k4dK#V R~US u!˥!r$$-Rk ~dґkΖ R%Kh24TEھS  ]/ $/ϔ55l,z:Kz z= 4"EW*9}\ffSʨPbfLo@P>uYUš F!Vl0qXvv3@G/O.Ë8_aچ@ $()<ܡ@Tq{H;cGmmmc6PV6U(WA58&WUU3JD& {;1)Drt AnAqVbAP$Z@]ԈG*<.'cقrL*nuߊF鸏%ӡc1.F,JGE.fq,?2Z:Ą*I<2F3Mi,[ -Q kn!jڻiػŸԂIo?xLWI3O'k_vCE96@SnDjj=Rv'eyI,!\(dB_7Iv?txs4;Wk1.^h} g~a4=KOfM)ygZꇡ62S4S& L)}0*{ѫ&ce7CvN@''o c=/-tϱ ,sGeQN dkMM1JR$ EˊJQ1K;HCe#|ϴλs98$@#g/,/ʼ J =7#=,gnU~Al.p8ӆ UL\_#kFGKhŢٽ;wZ:í؂;6vyJ.(ӦK?׋z^E"8?f-N;gTbQO: i̧;C^/=MN382 5=Fl6MRB"M)4'M-29<6)9,Q xS2`8eYcD^kF+{Ԃb1*vf~\aFXP)@a6~ r^W:y:zDw* \\ [-.'H5 =7)%p/eZMF2[^31&yxLi7.2dMOG<&%)iq"YV+f8fPQPjB&|6 QeyGg>h>s8_X>٢!D`"̴9n?Yc; D`.](,7+YKl}ּmd9 .~xKqE ֐3ڽrĮ}A']&0`zP:` 16-AJ,gI\0w QkSn_TݐJ@/'wס2E7Zs+o&Dt@7ue"dlmpkdBs / *\"ׯ~eC(\:-GGɦ(eF "]Vٜ,FtFq.ZunH'2%GtJ )Ep*Ml1Ь 3h@Ah*}!^WXMX̱oעf%60ƙOkqCGNL7;~U/9nG)tXl6MMW@s|GTBc*B_M𝙴rW>\9 }@!4` p6,ر#Ԃ9D3OQ;F\'w~R9&Ȣ/rLj'h(Fb3C- q~Ç=n;}&wjFjJ?9r{T kڳFҞ9a,ڷ:)N˾aT< [7O]PK$F\'Xz0OSI\"Y9ɵ+'i|Nd9[Y30Ip,[t+ V܆mʕ٪e<2v^\pI{d=r<>*w$&9 Ud1t%[0(ɸ:,#33E$:#!W^9!SHwUuջᕲ} pUHE@LE$B4,<_zEY<( =K ^ӄZT>]1zTRl>bx{ )XW.N=藏N`Ƨկ@nRVj%EVUTMWhBUnM.(^Ǔ<?IG$'E?[Qim?2: y? v:ګ+ͪǘ2*5#2X[W\X؛%?fnfHdjg#TdInT EH&g*@#+v'@4QG*n 8ڢf ( ϵeU[,h9 ѿ[T^JiGv${nw;7߿ugA%} Tj!FTJ<~hzbABwNm['@{'umW19Tr2S\"D;. 6j!n"e7[uk^Vp>v$H~EU̟}4B4OGJ|$&Ű;BH<ި[߼'7h̚2(p~-`> g ]W "UVBXts~"Bn(dO߻aFLߐ/Y}m[*@ ML 6R'@rtIM:L0%nN}ƞ]A4]Uf şdX0`k3` F=#0`AVjcgnRw5G]m]rR}-+.0SOS[DǪ4/M->+m_o:uADUqra}lQCtjR[*[nvJOophڜX^ CЏ0_V /1]F0`@7QU~b~TD]"͉:lǰb )  ?tF]@7mwy.9jj1w2IT9ڜ4~,v:Cm~<;LV|G7wSM:- y&`C 6Ԁ /[]0`e{0u0QajrD H!OI^YBpHEbnoܢ:O9?{$s3?\f56f\3iK=cvV14{!4(NDžynI`+~b] +_D&!u|}!UӘ={f)vkkTV;k Y[vp@jݔhAsTT'Đ7}Tڂv,# qۓ(:< W+%.z$ei҅|n9E #LH蚐#QmQTT9'@6Zqnf(WP%JCܧikHz;r{\pǭ/NyޱGOcy}}{awt4^1XLДqD_@wME!#ot0άߏuuI1/ƿG )!jrl zo/fW ĔՃ p{g=Y!}T0_ߘ'}}w8m! E-B$"Wd+@TQ_M[ ƻ|>\w6dh6E@is>~c[fT)Ze ҙ1JUf?.CK,"Q+|poXUhʪ2I =ג-?t $UAk#x$5i׎*,[NJ.R+9m]w"Y 4q uR(MGKjZut9rBպvP#x |OC і%;k@.БhkC)i"(`;7ECiC9|! 8Zp(UzR w]gЇi4q|KDb;4y;4\k\V)z GEO@Ƥ,#|8xĈe_8*D<=M[b_F,1)l?'L N0`!c\əqD-kmE~? ܫ;]ږPKOf8o*?'rB1염 1rvp=;}zlק(G*2u\53j4H!6t|h:f]DrvK`"r!M,Ե8ߋ;Z-C*^ARi } = v69L~YiP,}GG| xe!b'? 0"# 0z:`z]MI`kSU-Ȓ? qn]ygj!-M8KbLܐ^,z-s:D`JV^qt{EPNAy!͚XrZ偿]jB,:]쮶z#RnQ+ڡr3b9&fl6qbw-NѱvIv8TQup 7tf&B|>q,8TMu2+f -Avp۪ ء?T8Ĥ58=;ѠdrYh_.;7 IB/? o؋~Qoq{w MՐ8[50}lBO@'6H2ȻU.X iydE3c%9 mmf1nJ&i4c($d6 2pvfkd"˂_<8:^O#;t按ZwՐ +6)Pe"(RF<[-9:[|OxZN<ȎNeXgּ<~=] V8ak P#ZX_3U.jjjj䚚5诓[wvT*Շ[FKj(FԔ 2 k6d|d VfX̣;Oul׳s EuԪHjc;{kNj#?GRVEz EPSOSXK[;^.>5 -F׿Y}߇eylexh8ݙMƍY˫Ȇٱ*O)avۏ~ԭ(#%tЏp7"w$` d zN"FܤjI00b) c3,S%t ݪZi;}n Nڨ55ŁGfzlA4 39H-ɕ$=lܦI5"ۭQi 1r}tǕ>Rx*砪Lʾa!lv5S1M1SFz`u-ڛ8ކn]o9m:npVv۰lU#h!PĹ9P@N6]s퇗:k6lJQ?LZpkbUh}0-0jC{t[:ĥӴ.FS^E0 OaD@HD?"$c 19*=)u{3IGG_T=<,uLA$dUWf;%t8\M z5?d%{UA-vN@B& j K N[M `V [U;mlvS0 LyXi Z.<>Y>,?_ԹL([XDWS}y}j̯}%^Sq]E?qqe+)-KhrhF_mgށ`ɶ<<= T5[Z^UsV)].:ezJ@mz'?2!P@rS%:iMJK?L^I~g{ Xjb [ ]OmL␕z[Ϧ}G+fV۱ 1 ~4= tU;ݝ@ a6$&CR逈he0Hwu5`2dq#D]EGX!gTK\goj{U;?!sޫWu pC΍e,uJl:<{Z'_>%rsK/U yP>sˢOy1NK _%HԾ,9I_ڷGoIvkt4$ד5`_X]JYH[Su:E*, #FMd_[M@;!.xG9 DW$+>p}+\"_ >C?`S3[cÀ[23oɼE[ѺEٱ#74k s"mLO˔z3DL16Ԁx ug LmGh>"9wqTŹ@U.-"7YO7q_B@[ =nI n J #y|rO?8^!/@=^շjGIm?AMe6n2,E_-Tkxp:ݧ.6eM38x7xlw~˼ٟ Uқs5oi!.ݹ~Iv 6BU~BCϊ.74As{OftU Ѿ1L5'8D?.scY >yta?(_K i6,LHA#ls +j$t]t9\0hK}+{=¹= @(!/bÒط%?S_JUKHt]qR_|A{[i|ŀ1Ƥ $s"I h;~#:eE*}B~SR݋)qO3~?ct~ydxtRȣ礠5%D=QƶUTCt+鼡-˜㼜y6(H¼ȊP(̊;>8N)`Ld;5DzKÔо45q$?%EIĐ٪i$LG%Wy$d1!W]QA`$ɥ{?K 'X&:ժ55UI0H` }569*( ;7s`1܍$@|"@NSoYcwRFT<:= 0pFM*@Dj9/5.Djӊ6J77JקķH˳8Isؘv֘ +.9qb=L˧~Ԛ#1p` Xl7-dHӜ:zs)G//>1vK#l$W o`i9I,%ϴ hM.[x>)SVvQTn8=z}ھT#=D6.ٯ"8vl H@$|9SY4v3hOw V]DXWHlk 7ma’[y!(y+BJ}^EdpKхW䥶??xmSz W`ؓye6ӄq4KDgfZ:x͎B8L LBTFw6*5N']. ,MV;4 T(U]FsĔ/xž;%3:\96Z 3ç5'gW$\bS.wCZ\^9СSm/IkpuhS%oz]d[=Q\Jcz@?,WdMa`CÆ{MRJG[MKZxt#voX"[~ 7EjSu6Emg2ޒ7 =x/+;Y!<=T5 ҇ǖhlTfa<[PWNkhPr|6hWBRZȔ*#:CHn;?LhB*󩃺{D~b#?ip3V~75G-b}nσwɭtynexiӔo6{!m^&xN/$ --2[3Fv&9{1] J>)*i^m?Ƀ۠@~PJMG}Ȍώb.|*vI< }ż~FGraWcpTQkE<w ::icK'PqXbtr guso0@[&\@}GKoZ0a"GKwÉ[fvos a8! (7 x|̺IX@i0t; FҬiF9o p/^Q ʬGvd^!+CR⿛~ʵP\A  Rz-? `%d9̺G!eNj`,fPw%)%>~8ٯ&phޱE4@$z?n n?#1`7wE84Sտs!{׵?mFg7>scYLY[_1(AJu(3zN;& `p4w8r(}nYWk1DԪUXFjWE])d-7M_Q`LczR>FiEi:fe_ nA>8 Rт{qt, o]kS"Jr?b˨y7n iyɴc}?-:/p( N,*f2 f'0TS6Q\168OJ9QWFO&!^x.* PIt m?( rp}ǭO2;-N?W7Hte<fׯu{='X\_*Fj""Jĭn6xCz:N'ҏnoҿJO+aFMbņMUpjiM|*_roR#3]Vs}`6j{]:CuZgknn.n8}Eofx GK ="!1IG$QFRq>\GR>W˓?@xU+Q{_樈7H+Y5#yaMaوqGvwzC,Lǵ+.'oV}yE 7ZfQȢ8V<Ȳ|׷}p z ]\ 8w`. M0~!DNZ((/Yga9}lja n!{CIeQvr\xo cɶhOdӯQpXR4IԐ;IPviMj޷ ʐfH< 6E#XM}YߞT2^N,D?tj<=HMEߩ`l ː 5{(lv7(!$$`$̲<6bARdggת(bS)H"Z+>?j QK mO+Hv{d_y{= rGvhŐp$++y:)Y*At_ RsXo8Ս$U3ο0Ìe\gb;qeI)b7YO\sԄ >f̶uv#j6șNفg>Iys;ۿ" g=T-n;Wȶ(VYИvA{g]q>`C% rm8JexX._. 4 ]^,D+8Tw:=s^AM<:مWm6RiW#(xU'~ 0հVNQG?JbPfm:IWy VΠkbT*>XIoYӼ2!o1NK7%>qcΔ-/'O$@f{9䤖&xF$4O?"WLp=}tI(%"iˆ^w$xӟyUU=Udݳ_mIn퇨p=%R'v7eΆQ[tw?B&&|AX~\KKRZz݌Z 'o;&kFЕ5Z qgX5g\^?闔ڛ(wľ1$<*pATaް*{Y^aWT{g+Rt ^俉3T߿jo@cM3&T c>kv#:̅?d`F;CŊ4^qv򠪆TFUK&%oE]jc!N&RDuJ>zIКUYbPN*n-)ף"nQlw9K}+Xݺ=/fyw(ur{ ]Ņk08-HΟZ~`d*n7XS/ξ Σήl߲Z8w<{?"`e*+3nIJ-l4ņ>i]^oy3@m5MjXk/xL?ҡvPZ\I@; ε^a}5ܥ'c~b~;خ|ht3m[gj2 ŦO) ׹@voȞrWhŵ:tW@Y[FW/QШ~+ĊR1~Nd|vnm">M 5xNB׋$A],W :(R3?.#l6nb$9uѦ>m~1.T{C6<` ܎tKrVv-\Gp,gf~p!ͦ|MuX2J$ЮDRmI:#վ{LBW`/dN37O=曕9))KKb歊ѻx渮i 1m((A$NR$ݔ"6QϬ9 -/(iW?{rByY|@T7щXHD#~h Vfث^=zVNK3ըgjY̳Ծ.S,>><@{OBVtȬsK[l#Lz|;^-ӴUh OknKe9JeZbc$#@߈7-uߗwϋc 8Giŷht}(zԡnq/,bN`AJE*Z\, n &{@E4bxf4z*}j}F×3rBWw4nKi|W9dU㺥vvmy%Mp|;Ne.4oul '@ӡ:M;_{54*!( $'@8lk1F-a RY+2:%*UU}_-/yj'xBް`ثz7UVA/ˉiBOSnSnbe0ZC yÍ҉eOǀ%3є'6FNypd* ]Oʆ`iֲV$_D_2i<j=^PA~\qGs͇=Yj\ȤVl78cnױؐゝmTL(j1Gѕ.Unw;_WObRljCޅwz}kWFq,!Lq6p6QFZlԴ{hMHɕPhRw@#n.QAy''8\*`;̴nwۄ$?s+*zEaP,B`PQ_K$[ ЏrSs$(\S 2CT0pZ7]ÐjYg=xlpYɒ̟wQάC 9^Fs_l[ll #8IBg 舋hk,:cمػ=IKa9"FxJ,*8cHQh1Ppݳy1i_ wFJ:=RjNk\ɌM\Omy|ž }ѫM/ȏ/ɖ?k_,^֐S|S_;̓ +#H2zV=m66~YxǡMh~4_ bX7PzNI=JD!x 8%B!3ŤPB9zt, ZZ#*Z`S9%rR0dz4$$t Хٖæ__/ e[,-#~Vt"v쫹QTyM;?v~bnru,-, -^ڠ (&alzU1~Cf-ikB'Դ[s7B$6h^ c4V_5mZo~⨍W6sf*MkF,m4q^58zf|K^r/19E* j)XTQ`H,T^wHhF>Wt.P 4P)UB$]oLW]!Rr j<բjS#VG`qUwјfHֻ 8>$J'nIUa /rRT8>,^M?> c쇋S,Itcrw(߱hV99ϊmuʷ\0;968j'^3 N 1$*Cy;tٱ/!;Du#ɬQU)(VUVT z2 /$ t@%.C%igѴϷ@Suuj؄3BߗNM8n@=(9F݁WOvw:2)sg>7uݭ֌ /A5)Q}N,D3=4&kkrn|%>7 >X14:7 |>:_"0ڊOxz٘ 'ȥXmQVݴs]aDOSNÇ\5G=pUy7 Ïy.A$Xܾsgq W`u=`ƺeZ%ׄ4K954԰!C v%Hsn[|!%")!,pI]pIΜ]IB#֨e!,y{)!oq2C0ite&>HG"sUg aʞidD1& fIи :{ vf$5a;iLXL|)6G?Cf7o#wI4:%NdaMIL=cJƷiQ”d[4%ޖ5L2c0:ymqI?1m#XgxK6.t2"00#Tp^MP[_Z{k $Gf%U)AtsUQR}TK*7^P6yy؎l3/ZpqGcM:Z /cRuĎ7YOxCGA߁I%D[NxWp8(V# ףx)IHjѡ']l| M+1I i '2Wܩs7 w`<a>|8xp?wҬnyi9NZ$HT#|$B9xE%0"dUG?l_^r8,@j2d.Y4ݞc5Ty0'Z )r^RpH}d8h19#4#J\({ʑeg28ַTF6>|Lt_PP@F{}T%ǖ͒1؁Tap Z8eޜ%5/3_l!) U ba-!#)_ G,5"*/q&(cM/%}DX6# TwW,o e.˻#9>cy;kj؊HP6{͍jt6](nHn7W󵐙WQTvVG XYq[Ϡ!ks|n i󴸧:z v{c쵫=:Gx fvU7Bi#* |PέB rYh6NАM:+m2( 4E_g܉_ɁcbI9p9hp"uMW%ޕ@GQzKсQb"״@x0q$W $-ȑPq|AEg 3̈"ܞ:#0[!LO+ݭyvG1h3{ua"t@vc!Z ɰGE`.0_:!7Zhj.H gH(C䕐&wz Y;rLPKȖO=[r]+5Y[eR>d+`M/BOoSS=8nn; q?-w81g .,O@j8m) j߮AXt4%`(s0tuO#j G2p"7ihpQqW[s@*ޒpI# ZW#{;8'{N}Vaw]>x8}>L5%H@8c~b?׷w a UFq+ VcUP0@i%˗AS,t8)4FʕC:m"K,l@hvʩUoq^X>[yJCDKkb̘1~6٘&v/>[cixc ٌ%1L#ʁYH+[È]dk%O/{ǹG̿dFq SjG4$kz3,H})6lj,?9-yxN<`l9xY#ժu 㓢^g;{({ٍaqmq;B鑝6ӹijΝ+u=.p萗<2l|NouRp 9uP xG4Htd?iY!6 B%g PȤF\ i.jP*m.Q efW $IJ##(>-ƹ'W!@?@RRXv-4_?!S j9ED:XL"w=yWb37qYk?`f*?*X?2`˻d[ߑL@ФܼI\0ȼIy`ZJU5pA,¢l&1? 0}k1`Ѣ3{1ud5tL }$0p"UPB ? PS` 8Yom>FXgUYa3zulOCbbLAnb$-@g&rEPR#b)R$tݸ줼@*f<:̛cm6+1Uy 9V@ODfaeېx?eo R[ F۲iF7Pd7=G!݊u=/4h(--}mAbQZzi{Zxii@:5K [:*AiF;CAt#~n"̐F1|N1=5zC̈́;*5S$ G3?b;f $ ۔.=_mTIbBLn'3OǾ@jWar_#'@ݷ>yOY8h ӽB yѤd`Xwi8?a<{xq{rpR_hȰC BKB!qm_aawYUBUF@eTF !-2*#  QPBEW@g-HY!ZF,a]V6fڜ8c;=S?w .ٖhsrqN[Qqޗݽ7}d36IsMY2VT.$)͋Kh?NCʔHC X#d%}ވ 5g0Ǐ?֮O)~9Iq]+o~ {_wW NkҪ Uu #(.3ۨF`Lq N'Zn[-ӳ^kw:,ܙ;Z]si/]w'+qH%F~C/2E88DwDqFMuR1vh1t/JV{mLO+={PqJs\^g>-Xgqxec=ʻ6Yoŵsgmg]:"E8W>JR#ݙ!%+s3m'{.Bϑ]HuL%{pegSc{xlQTna!^._"~#ܨ]aFM*S5sG,H|jl: xb$_~ty<>7 S'`Yޒ4tF4|gVE,bxv`.]6xKbl>)=_\+8 g+οN%³&q5EkD +SUҰ4o8#]l r Zoqɔ31IIKD$kiz-fo}yKeݦp1m[VWF\zAt\^FEGd2tWgON4䋭7%%-FẰ_KD,Ď.|3xVgo X_y_gaW.3Xq8Vve  <+N#hOuXB֏s{ @~xWAQV=9F]{Eso7'~}û5 ? ݯQ /iY&N{$^36^E[edg[ (_ȵ>{tְXNKzy;&@M勵)+#Q(3**ө ҋ^I`h0]^)[KTqÈRi+YJ䎺m$G/:OjlS(\uP_z~7*,>Q2qtt?>d;[X,YͣɒY;#чQk|ζ$YURŒˢ!ƥ0[/u`P >(N“H䠅NVVJIE&XW#zWqNS-V$퍣OSnYh:Hč9Ǵ#CwՓ;7ꁌoqc  <bSj|F)1?nqoRE{.-]#iWEk+)l_- cJK *`n')W),ANQzIl6R֙yTC=SKDj482OdZLk'լ eԫs%>o{;]. +-@g,T]F^FmC6ÄT!nE?iq45k'(a[֠1ɫ*%b m; rP|e!#vZd}LXcq ^ّ2fsĮq:w ŗ|2& XQ>{ 2ڢ;*]wT|XǔGB\@l 9~탾۽.l ^R&b Vc]P&aȦO=[ .>͡w % c PawIcM=Ch)IzD+V%X*+*V+qȔ&gB *lI<-A#dOP1NAQD ezY5OA)}˶{:ktN7̠c.[l8\Fhrȶx 3M=,bRE ,IzA<6.{kӣG) i݋2%4K*--=4++NUnz冼 ObQYHE7W"ʝM8)~9'6{;n\P@*XB3$:1Bx=vzRʉOX=Y~9Ddp[]YExЯ33LB/3=UU_}wXN8W'TXBK>OLx{0GtXINl,bٳFϴ =0jԨ&=`(C?9n52΋KhZ@GnA4EbE$:I!f| ^;zr=r̐Cz:/g .WHx M˾D0]>!.1(3DI$~uQC!\_r( []d2RKO("+ 6l aCN1$$_|$.qb)yp07P)J% 89źUK}X}Vt+CL͓:Hoh~2Rĭ֥Zط#ʧIo`Fe4I:pvttF *>Tq>X.hE7}lʟJU怫{n>1\Ѿ31@pC@YrDhV>Y~e־En4  Z %U`jC|; SM>eGh3PA)CNO/J2X0!h-ߊ"˥TP𑕪q ;RN2߄-l/9^, EIk{*DW 0ïg]r\3n;b I"}u.0K'K[z۞x,G [TUжCMf{E/_x״uVRJʽ(jɪ -e}!fC ϭ^-jL)<@S~ŕ~Ϗt#Š3~u:a*%VUvqN\IW`h*$LI>3$L1GI7i-'2F,:TFFd+Zwrv饻~z],!e,/S:k6&TEҫe\,q_OBGnUtMIٞ?BM@Q#}JUҺ#Qw$ZSp>Fv37Q?˦Ȱ4vT4C!'wpOQ'Ŕvޫ.ŶKɶV2۰vTLH";ަO2ٗF Wn!KG$ial^+kXk`BU˪yx!wh\ 0D[Ż@^gOs}+1}4n_*k4U[q5xn!2 8E'@g),Wj-uz&('xV|~is9?%u bmڼ tsiiRO2?? EK<7_ t흋r|/h F1 !r؞~' XIWswR,kli{Bg ^ar+f) v?`k&KWԇּ28y@zalMf%SR0 /Cf+ KD)h@ތFFʝ}DU8E\+]!6 uj/?S?](rc:͜E3SR;h<|z;1 pDM+Մ 7X!+nnur$T#Ӟډhr22 <'"~?+ܤ* S޸.tV_"y/ge0G ѶYZWO^[,z*D}C1'{,{ `v|P8>H\$~s{7ɖ=!'[Pvi$>fqcs*ilrn?CA~_!kb#Vpؤq$"bM+^WuwSk*32a(A'nO? ?]4H&pҥ)Q}Nεxzds׌0-Ϛe7Y2^r(Hv!cP^7B?20j_uQRU)D SUB3 D%%io?^ÂHqSm&nuk#H/8/z555;NհHr7Kn親a.eH;TjTbj sƞUq%I?Igb4G\P.)H""_xKb Z>9ẂҎ<#^`%$v 8}bV7Ȳ‎mxr4Z6ܶB[IhZ֯}0/[BD {BGRfN z݂ Q-9qf &G{}}e34 3sI_iTUɂ$2?0p4 {ĉ[sQg(b;T߀e4W;zVQf-̈́L7VciJI//UO%SQZ|0.|S~yNmw`׵K_oۼՍ+xhuxگFŏsՕ/SG+AuPQz[=]=0Р xn74j@U4_<:ɦU-u -zM*@1lj}Avk=^= ;;DdJuƐh#d ޟ )-pQk\ S3d7 ?Iд87*z+uM]Tv*A]3v&Mdش ^$p+p+a;:Gxy _<ԎF/*XVWyNBo]0'w O~l؂l6UHt`v;m7ϟ><wM'iOeVf^5:=Y6:(\o_0['Cc΀EԠ4`59}NZ]KG&wI# 7xF^a`jv6`,f['wdэ\sSR F8bX$:Tz .BgFzr)1> yhv"uN47֖,J|gb ݼ*oMQi*E#h^d'J1O}i2`L^{h9Еd-9ls?t?SR( ôOK., W d#c854:ZZeBk1ӳ| @`pnj)ZZ%6erFnMVg}N0.0V=]*"0yTaAf!.[u)ż=d`ހS5!+6mE+N'qETEhF>W~ZhYt%M@Nq05bf"pj'ss}~A97 V m2]HMhu)DJb>l@Hu泚BǺ4 {OhC v˗4)nZF[i fMQ4%0]D 0")L 쥋9[,&ul;_D |m!l9mjCyW{rgxn{wUUU/X;VՓ{XUU@>q-xBay! {WN3/\-/L9U/C]|ʆGXS+C5|*+$ POBRZr"~hO_`d&ՄRPSp\`c uk7?\^>&}rgQqJ䳮P9NF$Gb}N]w1+_WW`B$ x! ܭ(-"/0c| pIrD#+!?Hsby(Ҷ F pd8R[ aÐ,R}8K{'m92$юuL#B@bP :.O98 E% K>ՌoaS+eG@#1-9XJ)ѷoؿ?'k%e{`e>jC`ª0!#0@L֡M"$aH. .XXr<^d()H.E,LɅ@I$.p5P;B'D49yA |+B@^4<>SGG4lNw 8MG^) I0?oyMZ.}?Qd?PraL,С\ζrXJXf I.gʞ, gan"wLbe?8 (iŋ{?)sBhﮍQ}wd!bw8Wmc6kCcx /+܀\ uřxwQX# Қ?\X6 řZKSoE/Y%.zĭ/Ŵh6Z:0yTr􉣾.# Cf^# 5)4\6#=g});Y^윺9ڄG~`w#XF/HJ/p-r_ m![#cC!_VY1/~}Rw.|s}ڰGZH9njRt%y^;,äWŒu}JYP=L7s{ QiJV'4VRl @j8¾f:FL`mʉzktyjfGG0)򭐶Raŧ!b\&+Q)/4edd3_{?9~yw@|[\`^;b{AéaP;:ETRhT^Rg&l Z\%i4OCu,ݹC76c5U3qSG$35^߰X_x%8KBnv4;- w'aa{y-O9fH gl}NkhbZp|1Y|*&]gh&A-8]V.ޕGU]3[f&BHޛ7k"! Pe |ȞYqaKčF \pD@D(H)5ED@}UZB{{w7IKa&o޻9{N*P+Op_oŦ;<ۅ1Z-+VIK*Db`D0"7|0L;Rᨻ2A[u91tz|fDZ1 meU2 $Xܔ4 Dש!y{si 2kIptzQ*KjPE!״{Rˆ/JJGWW5IPP2)JmaQ4FŠ3.PMm Bh!&CS^+ys#69N# >̎ǿaq~ߵt w5<UVSʕeq1oaxU1:Z(,QSų;:h\iuJ>\T}K@ N!aq99ؽ/|齒,v!nU7N-(j}&؊jh}{W*{dX23|O/?){s?(6ƾ R)>sҳE_gu8D**u/U8(y,oQ!;=!' EEgʎnFx&`[*iǣt8 :.x|>K As?9`z/߿78QQ2ZEW;hP 2Ҳ9X8FqY㿶M mD.:%o%Q gQ.} B4u8=Z)18s੡KJX~RTTc޵|͍"z AWV[.cw6'ح&X]JF qU&ܘ+fHc0<("(Y)ִU*Ѣ̲1C4`݉8K0MP*j["ЋE4R%(IN:m'AJE 31Q^F2W*1w?iO 8d+Н]iE/쟚Q-:_O8N;$N $<͔¥O03 tc<4d=ؘg=2 `8M}m-.X4EDgX_ jJoCu~+0lS y4,eb-%}!G_}!ǯdC83Ji8_g N;}V6[mV{ZG_mj/>ԛ3pcd^y),J|jGD4ߖ4(*Ia.p.R Fp^݃Bj(Il"4*[ T1)40'ǿt8{x /j}={V%y4oYEYm*hی 1?N.Ɵ2(q|"L-%L?>̐m_i@l٪9H~M>$_@9Yɴ@9I] h6BV="??05$- pz\VBꕦ*La=A85xދdg wfszWPYj*`\UضT]gA͚f zN&77D!7EHrMlQf\v ;uݭ\_SǸOFpI>E99YSM^g>ۛyV! ?i H(o4Ȥ D51GlՓn!I0s6u[!&L*HJP(n ]8 I$,>y .U&߻±q'YgѓO(N[+/I=!"բZv&2$ҵZt8^h:ՆNeI1\Uq\]MO/+Nr%W_r%*B#A1/XYoJI{jJ<|29CiS]&dKU5\\+J܋EQ-8$:~\rC í+AqqH\G8$Dz~9cv p\b <{KhNⰫq?6ظs^N~݋I16Z +[30-4"w[n1 5aR1SSI -ʄ 2)}qqzbDX]' BAؼAlVg<AAo%y47GN5>@!py1Qҳx":5o wwE #>:t$C>5!wV3+X(s`}}G-f2,ci1v%q4 N-A_0 lvy8ux]dn6ZjlxߊYl(7(@K)EGbqo R NW04snDyy8)IF L6Ѝ .?Ѹkڤl40=o e96̦%P` ֠|G.< \`KhָwVQ͇twJa*Kxq$yB|o4# | $& H$"$wKbs-<}ԓ$zLC{ 6*3YrwƗ< Nٶo>o}ğá8Ś ^@M+Yv[۞`!Ak^]A\R,S8t]٩A{GOY}rdRdym'oTI Yd@ǘy˘>yi^p3P~Ktq~[6.[`^G\I?V31IѾ.01gnʘN}LtrFw۞ ᏖOΕRGFnBX%wr:Ŗ%YreQx]=RTaӦvȵBJ1nʂPh V.*,nwz{w7&ݴ'O[iќ;O h[6ᯚ'lڴi=CװH׉qFHO޽yhyawۻݳtdN'_DɅAg4~1/m[@4(t!-º)"Q~AK yjM7 2o(q_9VqctOGG(n_9r L,_OYH} 1d:覕mbI5;?1040*dzLNdoI͐S=0&i(v뜢{ ;3eob$H A ֆYeV-Ma7嫬H}f=e:QO V9I V|qfP]VܞM  ~܃4vQŦEM'%ȷ.>PAI~ܙ60O; {:Uz+7f'Z2z;I7i&z rI5>dUgMj @;w/y턟ɾ $!H&N7anTQeN5~ s;uwU1jfeTLrX6hۃE\*=cSLp_{SYO:%=OzxD1ӺJsr*ﰞ-^&1k:k9#*РXNA?xRl>] ktf*i԰1wi[y &5+W*TM&'΂. $qPZk5^2N- F8=ҬR4!3yJqGq_(vq8*"#Q[O1C1^e0DzzFztB~AI> x+ Ydp}1mo[&Fou<.,g`0Y"釴ZƓ!5[^1:kV: ㉆L_C<_@Hmz)ΪnPQ_ QQe5x=Ϳc5kȮ:͍&;؀ȉkC АODyb)vU@.z N_=tn |S:6— nM;jsD%SQBhHtz_~9?ڸT+Ք+؁pelxGRK+lH^AZq#z\a=Nk_JXBk9uNEoY߈ru_E[}d*G'>dDvv@*\l0x!m)qOn7Fx\\SG3."2;7P mN:yT f,yo9S:WQMڡ*=ihX..hFMT7jS}Jz54+޳@GQeytG,G !H3 /aBɀ U5@@t?'㸣|t38+(:.ݳ DV!$@j{N1#czw}`KRS}3&pϊC+pd{ WȊ#"5|T>wowp żhA[*;% duq3g-a_{p.?{fӻ,@Xf66׏\99gd */Nڙ.l띣m,蠛-J)BPf˷ץWBi#|>7`:\0D?:v[@ Qs|4 90O a \+ef B33|aM0.xқ+Iy86JV4h'$W*W ~+, 8._LoCiw;28Zg3Ґ bXzz#Zr>* 4}U=Rzlb1.a Mvq2On-E"Pַ2+PC/4-O ފLV(Z.5JDme3wAtp\!]Q5OdwV3E2tt+uխz\󌀶8w&>ʬĚ9|ң`(_&sZE/kHv7u|^+a{AAF {E O˥3{IFprG: DJ FRrj ĝa3 v!޽tƍvWsUwUTT/GFG񟓨dx_H-VilS!LhuEzh]j>X&4@q6 ρuqp"j'e#l%3=N{>]RCP2Hi[3m}φCF*Zb$ƴІp_aڊRaRT} A/tmOO;~D>!LtsלJIHHZ ܡF Ż@!(5'ʭ`g07i< UtyR}q{$Ǘ$WGkEyxmyX;s0*N_w͂xZSy$mlT=8B:2n&oLzC;~VIЇ-9soM!s`+ Vn`:j@1`֍ZjǤ)$, X.RX˲,A[2 I`^D178I c- 0%^x(ex(!ҵ.F^*N__#7uڸVB9fRn'HYP*P}JKi@W*o#EVי6fL`{ab8);QWPLUOg)zo˟Kप)E2 RuWK2pʛ- 6*߄ϟie$|`-EFa@zB :Er(Z NU;xχk e'x9&|]'Aw㙠Y#Db7NK{IL#"抇t+a WCjuq+V: x#ۑ^>8`~by!d~*=ZKEWl0~n)d&fEA*FPj OնݡV3+ŋZ `zV*.WڐfobUxu79sEGj JdV CQ!Zj:dTϗ8QCi)g/ڕtN;4ʾj"i/`"͈Z$UmEj岕4?0ptOqW/T@謰ݽ/z. (N/1w: F \Qo @p;OW}j=Ygu U?n91LjϴhV3c$tDyQg1rEhL2\4spj 27~Nse7|L= ;dJa*a!]%NHtp8 -|)pAxډʑ[GV!,9JRN7!<*D7M=9\ O Da7&0my ~~Wc+ YP@A6bs:j| JkX%Xdpko={>Bz~|eC/r@0bKkkσ bLN\9Rك8dHy!鬪ơtz>jLd?󿾩J$$r49rL\HTZ1(Zm&(bV 4^ ccI& Օ&‹G圝pa),=JJڕ-F\3h?{*=rvx:5߭oBrfO8ټ셛9,[hbޏh[!pg|Y>aFH5Bw18+1%FZ`nZii[H{YgɢWLbᕲ*3׿;b^yp4; 8Y׾.!*N9Y_x _hdA0߿/;V,Cq?0eēh׶@}NI>7)PO³x)]0:RՑ6ʷYEoo{xQ sD.8ɶY0!ⷞJm;jf& r6L)ȢW/ "(&T7<7HQžTR amzIPRB_\3BKꊥ^cA7qEAŨ|<+2PM N!7$#+i?C]>0zE6ӢS1/Ia/͡U^?[w`£VTB% _Xvʸ'O2z%? {SLޭ4 ?wDB |, }V+pK_ycH}m[0=Bg0@U75W=O;^/ߣgɮj817` @"^}y©- )Ӷ{V#UY `SPɸ}ާH Ln<߿3} pH[tpn"r 4SAAq}3yrKM"i1@˼刮6j"m9:|4[Ľxg `M h$cҶohMF[QICQ^)Vc 1߅=={N:?֚qP#3`h\ y$C'4hƑ?!P{I&rDSSs_j-3Zds*mHYY#Ms^tW-@tȈ*Qf kIR96%h$prWt;p](wub7aWs2?]lơc4v !?l}WwugHsM$dکns%o-/ 7U]J?_vZJFJ)|~.IcKmV@劵 'viN"TN^l ,ʷ `) pMMo]7-lRnfaNY*Je!NQb"t0G]s_ׇp)V.ɇ5wsjs=)GfwMtZ-+I2_5Ck:#\5#.,Eԩy,BC $VT!_P#jJ4SKk⩴bq}\;lSm7m9EX%m@n0,jA`2߲%M>)_t9@;n Rː/XZ5*Lm%^cQJRy d< M8pu<>O<b\R.k.>Q\Fe7v݂[PՖna_?͂ N9l$w+qQv'-8ߐ@ G"bgr)m7!h#n ]s;]9"_$qljApeLr׭HlqfeDIF'%,37wCq\"Ex0DBH~?),jSBƲ*g C(삌[*4!+dR\9=RӃ?]Nεp'׉lv+u EZDI*A ksʀ+”:>[٭eQ7{ -BR +vy@K`)z&3Nyw͒AJgܫ5ͪT jrFu1`aIzX#Xh\w\W"9p?B01F`% 46T6J FU6c9@'FN̬ Kid^DsTJɫح[jkdyR)'*rPŇjk,QF/kɄd!=.O^^qb@y$+h_u8nf'Wm̎e /b 2+pT5Y uB!;9ƅ[MKv%2 Ng=(E gt_q6{hD3)T}jQki %x9jWj$2dUY0@?(Lf0fX%(ȀSD]^tAy5K$o?aLm P$AJl4sLL^Jje:xT8O LJ'^=O 9?oRGmmm8f%`"0+1pR8y &T^!eDR ,zg͂k~Ջ{5f~9.F87sk7Nq9]oy= xU'i&Ŧ^+ݶ CO^Jö𯃿ޥz;Z"]WHC瘻}\Ҁ?}C4܋>mi!(=;Pv+NSUΠJLnPV Y+TwNQ{,kq2vN룗t+Pa~DDy^z RH |pa5cFiy1cH9N/,z\?tNUG57ј:i(PK0]f=q^3 nN'ųW!#s֎:z!sʫPVJbiT4&|,T҈Mg^|{Z'~)roz# -J{_n-XM^X_VsJ\+@u _i?xffA @00 Lr>h@\c3[Jzl*- pzvasQy{İܽmTM3Mz- .,k,54(Q4"Q+jg@RkxEYŘ_8A_96]QxqO^@ '_M<:f?W٣a\phcˈ0* =E(>R?h@U[̆4( E@@z}Բ  PIn?4%4q6O s{,k(@ p2u:C2x:'䓰?.Xڎ5.(t4'iqU$VCLTdcDRd9b’X69y ʿ},Uc7zͭ֏?r=(~6EՍfծ4,}u10J Hl[S(9B.~`9zKq\[tD.LE3a`x (cIYQ2*TU!VȦ?eIErscO;4K5FĠȡvpgd) E/%xC^>QA "0ʋ8Vl;35RtꜶ3GH+wBZMm1PʈNmgIet:1qo-ċf~XwUlOޖ; ,U r<$)%nọ|9y7uqȟ9me"4}@ޤbL̘)pƻaɩ0g7AY6#bMN"dž $?Xxo&MY8"x~펧L~L{8/ 6㸁~+xHۤB;W̤ XقCPYINhIgieQyP shQ>QC_d">jmi_LT{2:N]upNRq8rA&o y)WҎl[@=(VuS|S Kϳt ЛڷAc98:)}?]db/ 簟^&)1f&8l&&CugwbcЗ\he$Yc3oК.[?7u{~V;쳱eV]U]OD2BFLf*#,vv8[ZWKFlݻ孉 I~%OdNA(V5OԛxD`/PDvnV^=GٷEC#tkm"2܀N4k~ڳ0%9 @?Cb B2<9I(aFB òN y*դq@rg$cU"Ȏv/HH; "2]j p<aEm&S9!~ G+ky:Jߚ<&жnݺD6ݡ~k:r)ؤ2g:vœgT$I7ݘ<%YR`FBCnD>&%M7Y nK?ƒ. MID:{N?pB!%ĩjp0$^fCQUF.2+D/KyL_+RSow=A""ͬ`;!L:ehAH@RwYFI'*:AȲAʹ U +1uvE"W$3 ۔)Li-!e/rA8&lc\ Av+PpJWidz:(3t%Fc(y1@nYt Yn2˹<:  YHT\knirW46$0QGVj LB\ F`E.βN'O[}EfO TpA6^녩۽抵W`6`4WCً+"J|oA=H;g{:#X@B$_`0y$˧>}[[8iw 4wj~w.uK;vH]QFXExHUT>&)LL8NTCJkb(h _Ga8>T7{6]7nܼZXU6°]X | w>o~h/OcQL2fعzU:lhܤ"y8R=0Q>"߆="bVՌSgN5)Ⳣ,G3i~Bq~Ǝoydl=U|ưF7n+ <c\X$Wc,ǣb\bհ!*)"/2M]'* q"}O=@C_\DW’M4ol9IzG:KJwFp"P>DWM HB_>.W)}\vn(զ4oS(} vZZ[i5[sE7h-k}ÞdTXE!*0x,D-xc0 \.?W %)Sl(!a ~Zk@p^h2`$HΩp!gIs!0izmH'9vaA }¦g P I?t OJ }w/O$c}L7!dixfE6rJ`x;`*w gd-.1bLc9^`(QBLDI)aYe'\3C!3/@*'x~k(P0"(9z!U|pːKˍRoNju/EHO3RF >?PchsTʩo~G pzc _"׏&u;7"S.22qܸnw1>j^=~τ{7+@;U 4S }IjXbš Xb1**ƕxHI$1,SsHYN_S\$ B>6>CW2+VXv5xpa.aRtѨg\ xёZw:YlŮ!w?0ۜ`6|M) U,}H[7 @duҺ݉ ̎œs| ylO'z]\P|3*0kدd?۝諔4 7AC!\+t5&f>,[pel@,kn׻&5!:ݺno.eCnD-m_ K*9J.NSg9 VioJ6r@w_ox>8"^2#@P{R)6~g'+оEPi1~{ߓ3H6O2ToʝP<_6Q!G?Ql2s \b# ؐw2+'^3s&c|Y?$Iilc% k\X!6bhHi??|߶{e] (;mلmOl&Mled'n5*JN|T%.qChg/ԜnpO]Rz &*7;O,m@" ]7F|"K0`vRئ4@p}GZ_WG6`K(ojS;MmPҥ]sO?>':%,&`MH $̝;wHJ$’$ *V.ЧZ~(. PPQ j_dΙܹkird2sC{^?R&J֎ ݚ Xfef̾m&͑Yx9bPܖ_3#5_f.QP'6G8^ pU0laNaXHS Hat-o갂_Q K%4ڔ%_V$'w D? q; ^vN'8 ]ϓ`^G8ʾh1*O0W` 02~[ BߝF ?9>%Dw0 릙 w%$Uϟ!=K0;fL0QL֤b?cc[lo 'W} [f`ʑod[=YPhPp ˕."u #v,Ѓ !2̙vc:Ǽ|s} aZSp)v7.Aue .[?Єq+*F↏q5XIx>/(:VF .Vw6z(Q.2,GJִ_uo0T9$:N6Ry2??dQ=A tZk( TY|J*eDYw qsIBMDC-]EVHpTyw0)CVm#l(Pw ٛ hG7AH P_:hJ~{?!U{g96lB1?Z=m(]oǵNU ) 7iֵj`I&ZHXIu<ӓ4Uu6+*$LUeoDO,wwro}*FˡZtէ蜻a W0Y3c*761Z=9x]Au؀r1 xs8LAP{ypUQ eϬjܯ2vBM/ ?fa4Ii\ f!T# 4ݰf]L+S5+-#^$j̍aUiUc钧2@r d?rT-UFӧc1*m?Rr!JƧj&*Ba񐌃{ܜ:#I3OD[Ԧ2*J)`"N."iȴ4e]\R ,}_jеnjv@̲H Hp tCC:)ۣ=ܸyh=dj)@>jy HҔw*'KFhrD gݏ[ڭ,ˑy#ӯ݋LK(.yށG }~OC&P䶸DCn9%pn! An9.6 Sc]pH]?Bld>%&| Hυjg^sf6'.2 HLGLOק̖Fl \1w "e⡷Hшogl >-",{)#hSUw ̘^xGFcÉP B(Z"d(٭OgU6CTy,ӡ~oNk0t26ۮ^ C]^7/; >v3s飽!6Xz[8c%TDmiV.Ɂ9V=uMoѩ~*RpmH7iM?Ϡa<gÔ'L\@V9x;VnL[29Jtw!V +x!;kE`Y7w!{PukA_zF3d zʛr42P0!!+7j2БJt;mDI$H$x?-)ewrHLX7H'{_e*uo 6Zf!a괎mKRfW[;!$7/_Y@r?Ό j?CH}.,`;#MH}:Euwi3W<;U^{cUXaHi4TY)7"ɤ[=|:2_ɉ9Xy]}Nfv?0)Ѽ1x7G5۾ ?(zZ2 3R {a(uo-r"R  h=cRZNONDd7%)#g݄'~懰I YwB]A|wĠbr㺵3& z$3+J_Ϙ#Đ]IWuciL"m zKKqJ X%y!;ZWvt+| [xhL|,۵/na!I|^R,$F j Z:yNEp'z<[fƎ4iXk#~@bXyE'4&!QLW.cd !˹.wϳ_p=_K^YJR̔65.|Nƴ%+]#d[=%v`rxf`QѫI8!\bȏ3{/b.ɺXխXǩ~S6-cBF5ͺXOwIRTV*Ƽ #0X#UYQGvȤ' > (`A*͜' lrv ۰l-[N~Qل/ɈÊX7DY.hwxމ__px}X{B"ptv=a͗axsz0 P 23 iGXm3tU(UQ@o QvxlʒMm{۹%^?^pxڽ]9 ˰Nr|ӦΪsdsu9}9b.XF\ G6{XŐ^5d@'K$3|1;g 2w7gZnBhw98ӏ򇇴g8`ㄵ\{-RW|Xh4K˥2 k ?2t&͡>/3NB!ziI=7?QC.D"$ D[E[ 5I 5as sM9jkj^cZl䫴 $Fێ_QUHIMUAl}Wl'V uȄv)[ +ic] \t쨨0kuIkYsnɒQC|#)EF:!/~=y;O*X(}Q7̐S jYapV C?"3wkMeQ I@a{abw⾵ {DAQ[ 5 Y{R[*Zrνs ra$g3(Dɞ"&^]-uT^'_Rk<rUr ^;RtISRdȩֵ͢fɲMt=elYDS-Pf2~h~O)LغjTi.]kp >C [N=^I~N;p^)L$kesUl}XL䗰$d#P-%MX:|'\C9K\XoޝTٯwkU [57C'rSmRu߇#kK6͑9(Rzw_xIUu aeJKlRKuRR}9˔_GRڰdaQp_lnpKdְJu.e(&A-b:lw>z>er vīa{6g6gJ"Ud}TROUa7zb>S]V]OQJkAAnR٭ ^gIҫ"cDbֲ<{NԏeNZ LWp斜f*.18]uZ]8r+ r\4>lؽZ`%XI3ӠPF aª qżU[׺ KnƤ<&JM}<:K>e~5\z oV:6( >ؗxm#41[kr*&"WڦJ|DNLW W9SVsy\N+k4W@".cn7Wg4ϔ7Svf>ƬߠƙX%(R. NOeXfm풩G'?pwΣs d~2흟~h219=hoLI=6Ղ ~m`$3$ G#m'g t5%*ig}&uP"@n Ց1иW:M^ &mk3?ڔզ$N""&09ne"󥑂ý80 _X&gZJ5RexatH B<+p%>ވq ui|J%Es4b%c;E}5%"WdWMkvZJς z\çXrKL>5i05*AEq*bW+0?c\U ]M~G~YhX Ҽ?xyaQ&pH/rY/J =NNr)KpΖo&2k\^Q>n"9mra>GxH?7B5VߩvK?4QhӮK:K$GH.О \d˧ \xF8: ڤpa 3f%Z.r*M=לʒQelj-{ m%6&#FhEAXnr|*n ¿P#{zvuD%irU瞮g`hNvۏѲz'A2S񋨥ah^ UTgJr]zeπu;3WCy7(}}>ܗ=WI_D-4 RWu,0{A GȄm/I.735 ͷ >rU|yE:kG c?`ۆbATBka_h+彸Q-/ -ԋU8PU" +^uJthtIJEF dyFx.wVP3)X[ ql cZZK; -|$h2{`vzUy vU!F/? HOG!:c#L(xoEـ$G F_V LϤS͹˗/E q ye{MJkF퇎Θf}36s"lk]-2d΋-@L͍mY&'xX:qn̜{JK.?^z"Ww EvIE4i7@BmF}p5귎+8Q@ˬ툯\jLoCWߴe V9]KSP:oA3?_ƈT;)x C\"3@BH>!E0EYf ?X034 YkQH+_{?~qNw=g,2s$bQjcWU؆Z [jthNFQozGh=_X()`V)Ua¯vgģ|h^)1ô>mUM&X!SBv$sZ`fW+ꏡ@3>WWr2}Y P6s(P7[8*r4{L-ciIIɫvVW?[]-Usebqb*ǖ"ljj-}mҏys vKJ_@S.((J'GR6 e:;zQjbuKXUWaW$C_-TH'agp]ouUM>rHy|獄<B4!&罁@ >VN9?ǘd@Up(זߪ];Cy}~r:6{||U9їsBT^edbٝXKD,xβh('*u:}7SO/K{ZNTѠ^RN?'wU}N8 tucF]1$l|GBnRWʒRqep/Ou`"L,)\e$2m?otR,8 +8V(楯oo6o=`l hiA7sq4b2!!_ }T`˵enk_RXe[sAr=Q8Ǜ5x;4: pMoJezyIdzy?v⪻Hǿhesz$ׯ]~7@]G ?m# @TYCp5q /MO*݀ZׯxxMyy#ߋ~b* x[D" R;M]^DĢ0r 8e9bj޵Jؾd2Qd⟄_iP}6ۏtq>YDv27J2i{\1-O(ʱXA™]Hu3$H\zrػw/( 珳q^Q!@G|C!c1?G34LجALLG]iQ'mm14;Jm LNi.#'uc dM,AQg˺$hA98MȰ w ]=!lBwӈ*IL}k"O' ӮImA5Dm#$DcfBV16@\#]lWy@,=7v~$XQ¬/1X /_VgPZ8|XuPo-rS:1iѩƯ'0 6;M6[x;;bDbʀQ2~ӄap=hNS'ASlgq0Zf^Xz߳б un*QM5HvQI 2ωX3n!] xTŽl+APLMy잳FLVS>n}WA!bD6 WQE*XЪ{KBV/Zkӄd̜9lHA gcfΜ9rH"TrZ ((…lW0e5 }c&ز  C ) ?'̥wɠ8#;ȻÂ(.BH$!,KNYHW =(9fF? `?\ȇL[j{ainw 8z $p hnSck!XBBЈ}q|a>0yft.eh"/G;ݼ$#r  [ nIT"_eOɮ3H A7g2n\q>. KGt8\87zwc۹~c_)O^ghhR ͣ .P"}rLcoltLdGvvÎDW 5HG/ESZbӏJOOL]?{=qj\&1{XC\"p:. mu%MsSx5y4.[_y @X}/`?y )j0kY+[&Nqzؔ|i_  u-aqEn8;G/Hq}߆^ ,ûL;uI?\CL^}}D| 2!&{+I8=qd]V&VYh ?=5~u3hLe`T>_0om-_f"L0Ate8k9.̼o̍ 5hzn)XLwq~>Ԕ?gJ}~ݏ 0^xw?`cF@4M+؆h420f,ҲX}ĠÏ9QVs5ۺK݁ HňG%W3"{KpJ] ;Ez7y,&,f@s;Fjf*^<M)i<v#'?s]<JÚH"箈dz\5tP6;_z}^;q4 K6mm*!k`Gee.m^i{WZ-]eҴِ*.^^wtxF\}g^u p޺3 VUR>r G 9G޹Sa_+:=ظgaV >h ғZRn.zvʭ= 6E3lfki2"frvUt|$TxnT-7أ̘1 }zo/0m^4(jö{[sPj2j[@SrS < b)ЎEfG@b4`ͪ5?V]Al]70bxGg]n1cQy6L })V粊ȓ:W;K< X8p<ր40amUӆ`n9i絨=@Ӂk\Dl~SGno͝kd gs?Õ;1b6@&i\'}j1MdO=JI)%_(!,m uo^,#B?\.Ad /CQdoA[ F^elԍ+'Г<.惍f/H(ffLBA( Loڨ t赤2=zX 7wxQ;BG/kA%ޱY/;cMO^|Q *g1t,=VWYPxHH?8tQ(&DoÆqL];O3r+Ԉ);#;h" a&I>7 Ͽ8؆ƏjXOd=a?8<VFK k\gm2Ώy{o5V,my[urt6~:h?zb%H2H չT-΁_7KL+re}LcXA%fۉWSӺ=nߕnJlyaM7ܰ] yk#oMC^=SWy/9Kb zU 2 *iuì_ypu;Ν( P?o;w:JIB@E|'aoعE_bk5&1?XhbXy|+0dL|4u t2zQS i߉{k(D1N{EBu59gȄE}L[TuR!]ig$ܶ1 \gh` c9'F_5. R4fQEfCZ(yŠh{WfS3M?(;Fg,E#="q >­%\ qR?Q4:Ӗq0܂wжK  >|X}=CuBEkL#,HDt,:0jtCFQ^>a+؞2*Q!i3$J0rT P%UU>$ݼ;"M:$w%w`4ibzb- 7bXbٳ̆!Q?W[X Ś[薦m0cV݂Caxmjѧ7N8kCؒf1| )ంye'u^ 6o.}tcA)]fHPevuXmί39[Z]tOAA#v}z)\f5 `f3wy) Lt>?NpŤ-=s3 3jiR}_}>p80뿂1Z.ͤ(dY,Þ8 2_0"lK{6ab\x>8V"*>6aEٶ!L8MZ?j"{X^>\+%*Rp.Ynj,X.#atŸnMP |q>bl^Lc=bc?xSq(T$A@I;_q$*?b$4P>rFCdYz SD%#&n\qT}ۊ0q\1gΜ6>P"^N*)0e_ G5sW ANA3*z $|-'{B\^ȸO"H4r:8k;jha/,̙7R@+.n>]*χy7e)=$:%#;U_\+?q`deڮM2e~栵>ev>kQ|2e7Ѝ-q斥 ddŨf @G}<Ιer֬5{Z\_F`܈N o3[NaQK( ɲ[QSwJIA]G%GSlʘY 'XF&c(Kܴ.ɟ{2~( pvqJ>ޒ'O"M.B.x ;}a;06mA#Cj-X_%L?u߸H; ˢH(3"R%[v G8a産 +y_&3BiqՃ%D mAw_ kj^?D_%;ăI~N JhxkqH-dmdl~zVA^,hZТ« (5`3g Wa7tT7mdR8 K` PPĭ(AUB*y9+~$w%# w`j Xccɫ2M|5 $shqvO+ dr? EH;q 7sgQ?S㨶vY!sf!L.lô B6N6uO+?1tߐCvCRXRޕGQIdfPê\0s%bVT @B攈r68QS.*y ɲAW.,_UwWMtϕ7?>&GUW_wx~DCv2ψyS)=؊E'B}Cl'tz|"KDj/_ҁ>6o8p~9M%ɡ+uAdn1SQnW )t{་栗?fd(! b63|6t*R`,=Ti ؉:Ym h^`CG;jK nGT;H BS , 1UNUn}(m)叵^e*lG=DmJqO *Z vGL&#T(dDDIh)3q=\A7]p}~mxߏ@ &8?MgObݵg:hPw[~V,UdUdDIŕ4S,TƼ*#TC:Vr7 WO)vw`vH|M*yՆIJ!_bj*ݮ-K% 瞣:zfKI]_8~+.UYd(:2>աN{H~LR%Ȋ4MRw7D%i4^/=G/B35q`dSJ~S)BulmXRCˍ'Yq\ԡTwAs%~A=bIl}I}lYa?D:x Ճ"|WNP"E f0!4\,wt<#Տܺ`p0/u'Hǚ2^8slr}tޡVu DL.[z!U^Ssa! F`ᙏJ  (f vQxDC9SAxz&{o cy1͈ gO>z/gFL!0eMxRk7j-\K96q9NaRX&%s E :WCh:qbN#f0+qtM4QF i$hirNuA|A2+[gyDmK$g_+Ⱦl޾w}\)pv_#PAsiS'R6x;A蘷䜁ou/Y5?!G@,"H GxsÇW wP=ߧ>LSacā/.2VxPS|}$ESiN=M߲ʩ(5 CHSܒpMQv5O\xV$BXڎ䠶gM<<HP;!JiJTF^%No*XK2;T>Váj6ɵ'g  *l@xcNR%azBzVaqX$F"{9er,LGFS=!eAXodSvZ2 ;&x4Bp)y<mz]ˍAwp4ڝM#9S3`* ^V^4*ɨGY+G3*jS¤5~u1!11MI"R辒̄3K[ۖwfΨWl=οg,bWúnvndG;_dBf*2B9wD2cD~f$rN!La)"՗}cI=O++q鳟0ٍ袑,1-[ qwϞD rpAַL@j=5Րǁ]^lػ"[T K-6) !VA+nYnᬮd(8MyT^ff^ E!Rp>DzĤNekDD!~|؋mk@lS[4OqTiH >P/gjT^ bsDlML2b-HII?L3ӳҀ]j? %6*t~ :?Bhxg.!y.yAt[8Ho6#Gkk(9L[s].5TRbx,q}y$gM5ޖ;Dz(>eFGJl}e! KI[rBYI4]6 _ ]9]N9.Qe"/W{ttaSA|tC1WW3&iZk<>4uN櫟m B6KYӯx/w%`#\iuXTJo/Դzt],FM?ҫWw{XJ|?̺/m3Z''b1@3 '`|ANz].{ ?f;"8=ZBPQ!4nlNuӌ &Uikکn!dkNu- /񏩄h#Kc$f՘E<ˆ-M9:'VF=3*~vV7S6Vz3aa'EC6>>Q.|n)J~2l7!Nbm]LלA+1S.-o"*(PȵdjADtoyn< j}~UT?oVr C^Yf ft:V黟IrH;JYv NL2˗%ڕGiI.1n`c35YU%fE/\x25uR`+M\r]J⡁j&my L6 66:[4ĚۉM(jNlE :ۦ|psw}H8cY3Fl bm!On+$omkZ,!)%rɽw<[ *j'wS2j|L6yo՟Z<_^},?WZhko q%IBA:C߷f`FX﻽e{5 DF 7|_ɒWgwA r[ O姲(l:$Ua_.0l]\,B_w۱f/y3h7_q՘񓻻.uKfe*.S.?.hroFPVSɒ*:PP$ }@Ѳ+O!4fT' * v&8ޗ Cr2RJ,I:삌'[Idd-EЫŸv41[hn%opPt|hBR$˱06]T¥YS0o^_l\2LJ~T+/Ut?TqK~=E31"џ>,/熔<65P9ג׺ZvoPsN娤] mfc;j;0Ew#9&$aS_p;]t|VSz}s9yF'?[JGC?vMdztQMgF:J?JBݥw˭%9w:DZ2: EY%Cp6Gڂ|\^7ٜcBV{Jgc ~svr%=5gEKX,.OOC` dЁ;z%8wو+$T<)d"vܚ=Mc3UH0Ek cC2m5m.dbոe WPm;,i>TR̨[J;yF9_k=w @^P'7c:+|4)g( X `1Ա7\͹eSh.=9,LQàajmHI X0%%jnn r.s.ހsnQH_R{ 1SZ "d%2nHE[3/T= 㔤b#p"zZ/;/,Ve=9xq)@:h?-x}!ѽo|kn;l躜%mR3e곊`¡28XjbՊ"7%lbnl(E8Hd#OOo r}*x|\s~N@)/g66s*{!g t`ܩ.H^̀il(Wq@u_ܧd"@HBUUw|03ϭ[ngguϩHi4.g~@* ?fmf֐U5jC>n\c#,$p, /aZCP\8w/W/??3+ڟ~#i҈Q'I/fco-6 #IZQY>cs GcV}{~-{ Bq h!` X4%,t, Ò4WڤJFƛ.k5dKߵ}zWB-㵖ߍ<5+]*!!B79 UEԌa JL[_NY.6 { ~9sqn*fmZ*:tPs_զךG(Ma {G)^`5W/eꟗA>UOf f\#:(XB2=O|,Bf0pXFC =L؛I.I%!K{ڵRRϫwgs3J~5rمEp!u?:|~t2uR,X\Y~aMI@VGDC4Bo0Di"̻2r݌oB~G =kй4$%%e8 GT#u?s \*< 0"-:j/8ܰhckiRЩH T0VBfpgW\3PmO,'À1`+vM!g?ɞ}{b xthހ>OñF,d,d &MB|]Y  Bv #AP/,d! ?ut'r,"]Pt ]/vs?՝AΌD%02SV߸ S OFx7SxޓǶ=CX+MsxK{bر)@;8%_n`cǎ7'Va:-$pVzgէLP'KU zLToY MG,MgDgΛ#ֱpyX74Wz)dVi#]t(@ӗX;>ToqZ&gjKӯet9Xe)`{7I%: fPޛyI$PTZl P&1^XĀ)xvM*Ͽ E{/^vnLә.)$Qw{\òA <=n'oO4߲_-"jd7TY$y>~5I-W$ݠQq9Xɀe'`L';ZeyAؙ}I"R Вiq~X!}~E:i'{US/9'_E$-)N] h/( W)Enœ#y2?NRN"Nq$@aVRg]^*ՀH&od^ 8gBna~#p8$(B  q!6 f_#/ؓ_ͦ`YKȑ!^{קJmĄ}ĸ"ˋ@.P`:)NS,~Q#z$8b "Q;XgkiWRGkͣU%׍1)e+]ɒ4KVH֜>="T&傜MUmو!bMuvz]ۆvړ_Rro_ϣ w( dBZpAxeWQ>i5q@jpJCd~2pnr"6rUo%_D%,ǓȏȪ*IPt2nhQѕr=>zn':ub@=wȹ2rv6u.'6w^X[Ho1Gr?]O(cߺQiY`{sS 4J HW{=ɬuΗJ1۴dKe|O? $mxB#f7w˿4)⤻$Is"c:+FYy>qn͉z6ەb{zt*-2]|XٶJ"AkA~]i'CM|<|36sK XP3C.(I 7]h?Vj tSYpFB;[¹Fݻ0~胹oE! & چz! )PtE8A 1 z]"Pn}fg}J7&;{(mw]9忪ZBk:Ê[f}DC=FnH6S=#cCS u)},_l$(xX/DD/q!W0a"l0ʄM%Y_dOcxz;Yך '[jDS)Qi}$w ^ /NK J!NHg,S/NUSLө/#Wiu@71O]Dۓ1~:6 wE&[LuudӱKӕYAW]P'TT.#Yrr˴?2v.FWkaEZ>BcE)!`zE璎p @+I>nZ_ѲtF32W5Q7u>QM280hrJ4g=J»| 2\Qέ*j໓ͅiL~jH:B@o"!d^ aѠY&,=![ȼϺ߇(K@RpH!{)j=Wj.V0BAwr톷(Bm'.n]}҂wY}F4 ڮqHU T:UvOlyxXBv"Y&C?ΐWzyL(DhG A8-"ߓY֕x߽]?,~JdS6%(4fԏ*XX0 T؞CcF:*G}EˣJbڡƚ, IdvS;G־r]!'';_ԎGGX4Lr#}6)A VM+ *Z?aх/92}}&UCI&5LP¾[0T_LXpMܔ@CVtDN@&] bLpE_Ơ" E@Z>yrf}%ҭp۪aiW*&HF+c+ͽ`uwhbhx~8zH\ݾ UO٥kv^1uTCw={Ӥ,ǜo,hYV\ A"^Azp 5A~ L0t 0Hܬ3"GEsAp2)7 S /07WiҊhґ)np>Xx*oZAPc!F'%^`&#,td,?S6AdE3i""_rdrHb^ babun9|y:ů}f3TDr ^%YjYkx;|zo~:8VwCͨmӅ~KٮmD1F& 1x:&#F}=7,G`cpw,O*YiS:D+xhn! Y/1 o8ؔeo]JN_?dղifdD= ;ёzM,moh_0bù)湰> F.7,ݜ;"lO J!#ؼR ? oy\*4=8yZ2f ^6(5Ni]z^^ H_H}h,vR]nP͵6BNPqR6r[MÌ]|#kZs ȏ F;hk][t:*K4CWlա_^20i i_^ ) ^Hf8EKmQTi K6KR=H$p8"rnq .Wt$;@]^ E}RޢwwU=Lը k[mMZ 8LRw+]"acQr|aڧ׊CQը['@ZTC=2MlQq7b%kM}i:fqRTgD: :63_}NoGu#/JiD=SRAuB]yQlj:^SV ϏMX*APgdd6ƽ'(,TCBKTr4gz!q'kDtB"͵NC9&B& hﴷʟ*^Np /²!K-ˆ0 l"Iro@g:Fy{l 8)--eqh{9u)S2?G]n{bZ :X>~1r= xTչLf H"[B2sƨP1Yy#KŰ2` GP򴟯E)V)j* u{X$s2wlfz9ο iƲwt?~󗻄w#\EW E}Qo(D#x"- wYîp$9+utf3 SVV)=ptcͅSj`:ȇ*C0ɼp+a .V6wmU&dI9d!‡KȺh&=]Ht3Xĸ+B}}3(|5'F+ g"$E.w0vh4:=.2H4BCGgGy^*Ihys{][9`v'k:mЎnd6e$4 qv>-./jog㵺cLWmf{xm5])Iay3ݚQY5M\-'.NLg{LsZZ47C]'E;z9vU}jz{iFbV=Rz[Bعg b:sKoֹ? R!{4Dak"~${A' D"eB|.(ğ.̸{e`NoZbXe u*aY ˥{&5γ UĐ[s0l|݁G`vGѨ9w(pn]Ka _qn)6;R& b+j-Ʀ 09\@ C8­%yb{#w&YƗ~Ă!$;@Flc9!u(~p-K,Kwq=䚍ҳk G"LHc`-t(FOElEke&LsHy98}KV}G_ɤM0z^Y+2* I ތŶ.:8X ?*v[5w80Z»"uyQEh__Chx/Sixqѷ|%㵸Ɓ9Y)Wz!bX;w4d'ÀGn«n;:{=;]o'~,6q_1߳2W.#7ύG{ KqzqSmlNƐ흫nd75`zlYEhhȟ>C7;@  HHpآG@4 9B%?S?6;߫h_UJ/P%_~,n`ʇ盳(L* 'UZ틛b"Ǘ%+|Hip[ҀTs 7W~{{M TR#d%R%Y%մ(t=~Л~AHOfA }G|C vqc4~yKm-%.#=q"/97- rb \&2" jDDH\/ T 螱=; ]Hik縌fdGK*Br /R4 LeO>]RPIhr@"M^ }^Ei.4YJM:Xɧ-oۈ:OdJG@8UTQ:{A;֊ ԝadJtD"-Es>V1JF!3()l,ew*٪vlzΪI ~ ИP }B9%W4[' +ߡ_%zsf˦H- /S9n o[ I08M>e"v ڣJoQ'7-<|-S^S)dNh h|-8<}v!_KM^]JF}R6ȧեЩR08)0hoA_/#Rނn=~%Si~[lGgr)i 'ɐ.lm-pk?AMOF#P7Y/ kGJ^+c8¼<ljMH5) k(֊2.Ay,BL,rsE"w]) B+f9͒k8d & y %[0.NB^l_v<$o@%3!6]JHv$~YkƺG 9)hU>7M=RN+|2*w|:01SV\Rkh c(2n Gh(k6iSU|/ݵv{;OtP353DTPt^yDTqAB QE)~?!T[f#mQ O@m3XlJE5frv 3N[}.X~ 6gRɖT.+ ][4PC3L.CA-VO8ᣎn֔G +SR@=*r Bb,>XT۰yD•. !dStpd SϛKdέZC!oMԒBzTZyRz?oi iĒXm83|HIadMB*"_W^!9Ep@m}Lj@i"%HC Bv$L2E EtpY~NJLgChJ_qX D:ﲬ@j~rcPצQf! גVFG7_PgH/aOx%xLVm""|vJU\؇XJ(+2bk(0:f]͉y5p{(ab'oU,"G0Јc"VY"q`sC6+;t! iQԙ1<pF55NԴ)vSM'豩q@{H'ɻmXXU#MM0Q/Hۄ @ɻSp`vnd~:Ioz@;ß ,(!Q[eD.5hwЌDtN3wk4?xgo"?7m~05 ȏOo7g Q;cvVM1eFMUI&=|Nt-fZo*1h5T;@(b㓟lzs3k.\x OCVȃȇlX9ujA8[nUMRJ++Zi/oUR64? U uwn R?;-.!v"OH8aMG@>+9; pҎwQV_SV*Nu2z݊iB[8@e_!RCkֶ#5R,իSpuO)wd_-~{e(H, Mr%m IUr D[V}~?Ш,7;(U9 $TTNi"qYJB.oz8H@m֞d[$m* 'XN2J\<6PO\fN; 5lJ]wlϥ;B>$M8kd9V*a>B\輒C ظdF K(PтP'ɖ'^ʕo1l澼BEV) i`,Bn=d [14AeI*=7MӴP@ Ж]͞ & 갵vVY.Ot|O+2OQG<|Π" ..IU߼~Io/9Y6A[f:CzSN-NFcspL9itOˬp 4N+}tk$PP)7" azЏ̅e;Oè_bEXHW?1M%7S*I5@ K,+q> +z(:ʥ Nzo H@߂^Q ]0Tha,Aobĩ $ ~qnX~ ~C|x:cKCqmѐZF5ۛY>opHd+26,&HG AozxAa^-_$Jt#kGI+_X`zrF9lF0C*~ՁAW'%ğc[#1N^U٥uLcrd!='wɞcKն/KZX]mg?p򇲣?4.*lDFqJ8osq!(~c}v+ 6ey>,N[LOX,z}?[ XSD$K30kE9 D^ܿP&T黙s^|u~cP3,70mHX@KzJ "Wu4ʜ)\|SMƤ@i[ySRK{YikiL)(M*dp1g0 ln_hzO+- sjyUpm|x1A^Dء2j>jx>\vM&[+4)WϩS/\P!qCC@fz$&bv=px􇀎q7jn~$acG ;~>HR]Ӄ\Д)I Af$,O}xHu٬ZcQYlS9_iqL>F]MIt14z4b;A1z=nˠ Fڴ<H˖`c&r,%/S]fvXA;;'oRt-6MzC+{m1 E%Pٴr, 8B Q\ɤR$Vj8Hc:v\{꣫Vzfz*xXi'{zyU~gҠOf5O1R'?1[A-@Sw]˜_U?Y7 7g>>< xt9d:P幀wϣqjtm5_uU@G$~D9* 0^2Gп'*)sn~ύ8nM᰼j2 $UMU*!BPVq0ป02Œ=%K|F-!)rN HYB99bo8Um0W9]+0o7gU1'ThϠB~, CNM)~ԩh{P@n# C u S FmEzu厙!Cu߆gޞ֊r瘇Y 䳜6!e|U*[|k.,`X-ɷt)YJ|WG (pc΀rhTԳN=u:,hէF!u>p5JfoJq J:Pm)aAs}AR|LnjPPy3Z0^5 xa#@׬nF*rj\nX B9e KHpCMpOq)0s5~u5\y2iAouN'fB;t>?b[B @]Q*̟ro'uoM5AUnmt0r%x"Rp[&7TJ4*]|69}6>dEYCVp!%d YfqvgIv ? ;b+GGu 80+4d&R9aG܎עH5K/ьIB.x8FJoJ)A1ߎde Kiȩۜwe|Qxddh"N!@dSZ]w'r*8B6  {f^hlr;"7`hw^gsBAE&ʻQJW, 7U$$⇏dtFTRDG"&leiEyLYŒT,;"Ψ ^d&|0*B-x)o6|(b%WekaAӌj;uj-N8!‹ LZE(1˳n+krvbw;X <[.ou]|9yK14ESQIL>f.zJ*s3Xۼq{BrN1GP!FI8Jj=( 94y{dR/_:΄IPi=pf ?~&X]g}AǺN6p>8[ C2f:n|$cI)9F}=5{olC Öf&@rR^SO` !JRT +3p˃EIQRk!~αڗ[Q !0R(7} y p-\TB`@q856WRb IGH<ͩz9Wp4Iuץz2vKQj ;!(xk4O1A)LIFG䞘YEM+0@V`U Il-*{+q `b{B`C̉LC W!ډ@NߛW/+Rʃ[ɺ(/ ;'p\\:RxJ+r%w [XI( Y]> v5:"-P=bw_RjU`tJɌ|0[~}!hӴUɩP  &n(pPXkh1=+9# 0S Nd#P  Q;⑺orU1bOYS#|&5|4~N{mVxYff{kc }OR)YjJm_h9m>e Ɔ|ր:m6;uϫoaD&]>;u+J ND*҇wU5)7GK7@?Q^V5%u^dfv.u)XX FT@P DՆ!яVoWF t  :0kF߃WHo&^h97ic} %YzWY'J(&t F YЊ23i{gb!J`jBkvt>s˟* h-m`y&l7S^##<_g#d J6;oqrXXB@, n;,r[N_rN.!([N|be8/ld9xH2"a@vBHEYIPtp'_UK Ǔ=w9_ P4݅ni3vy =/f?}fיg-nJ4;Xx LQۅ2K&De+]?&#@) L<΀kXXW:-.i3WC !nO)mNIm=:3zѐMф:qv6gEi۶N}8qbLrtdݳ*籤5k^5oM!dXgCK80YStikYYsk9WB6 2REmfq֭I %4hegXj_1]k*ᦽEJ{BV~[OgaުU\jv!_K+&U'hTCv2%0VWb!:};>;B.³pSVe'nIqq}dŐ#_/w h8]'4~wʉGzp>IC55"BYB'teS8^Y_OD,?KˑA,_T%GSx#QZBL/g-=h p>i ]䭬9֐%?Y@;_ܐvLT}H'KB gr¼ԙԙuBUrtQΕxW^IXr Hq̟u_dZ!>9;x5ee'ȶ^o Q~Y@A>q L6Y' Qst糖WmQA|όrpF4:$꽪~f{^˭սoUé@rZhPaGe>~ X=KQWI7F iiVRqlc+73+HL^G >۾\QCWouBa)1mH#lŢBoIZh1Fq+O2*O0v].Ba/AAxGF$AjD?&Cc!s:4 ċRozҽФ+4: =jƶ跓<fsa[r|sJ!T3j{/Ex +|S" })^n)@)ƒEYL̳WNYPsY;UBUy3{1Ae8Ƹ]ǀ\[KI"]z.˥+ | 3U# EYmPs`140E/e5I/ Ջ>8u}aVm-&k^dވ-U:3rXrNÀw;9IH3"QPЩ~DEeu8JH,3̈(-5#'r \U2`_a*cĻ<6&=~ROP(4ҏ{XC{ .'{/J(In|+rHD[zLx_YRj3߿zg^zgxY+ye'iT8íƈ#Q~sЮ6 ]DPH)Sڔ(C?lO w5F+75 A?)-bOv<^!,$UiR*g@a[:p zkdP7I).A:~qF>9y^ M` 8> iʸh%,t_!!ԣRl)  "evw7 b~gr۲m8/f1Q۸Z!cLJF$-f VU)5kƣ#3 _yE' A >BĠ|ԑd^J>WXMH)_Gjù ]0/t G}mZƛ>7X9s+&ZX$񧝼)np2ێ߶coa<)p: Olub8sWq8ގϪ^HMk!/(K'FVIQS -6woa288۞E%i$0`v\ԟ ݒex4bn0,RKRU"V ҎF`ɤlZ"1z 5{YjvP 5[O!FF2^q;fB +cf2V;.HVI UۭSKSj ;XtLRcC0n1XrB=y}O}2/?S}Hʌ%xmE=uѳ|<>?VޘkI8( ? ՈE-BG%>9OռzZ鵙|Ǧ{YӔ3ѓ%4)&K+aX 2\Dsҗ`~n'dV=+B,'uIB<ԑdKS>ۘp9C-WX華k>$Zت"|i~b%pU͔B0;SSyPoPuT]Wg<bs-/'\kUO+%숧*Jhߘzҩ[:"e N4u"Y(sh$? O5'h?/viC.U%?NSdSs׭u߬FߒA֫$s&HUơmDQe @T#,!!OM`9돹b_{uíYFIB]*ps ΞL $9xuye pU%(S7f ~辈j|AJŊW-:S3(ݲOHE";&up!+ΠnT>&PQ[}VOzjLE"mjuobb%CavI+BRXԑAH} $ۗo1k(Fo!XK?eQQW*|R錑p`aBH[4C?x8(.;QkG}9+ ?D _Py(a^_ `zڡ˙g,^z1]ksQ:@S(^wL<U`:PXz|;0M'k)%@G({cKNUOX%^+ (d@]rŻ<>! ܂?<ސ_tIGL>lH|z-r~ _ =Y8C -9!ֳG#Bx,4f`w kq}o?áA>UTU6SCP#78A6 3,Xبa˵Х[agv *7ͅh7҂*+30IJ]8yGTlv-m)g="fNY5#t5( eZ\) h2uپ(D 703DC`~~cbbƻ̏X:bޥĴ Miav:wd7b_Y 8Ș&>ʌ#nr@q)B4TQ;# )~&jrk%F@;Q2Zq<8F# E y3x@f22#7Jflx>")RǼ!C-ۋ [ѡsrx6iZ󾿴ti)a!^sy>H5w@diG7l s@}b7^Qa4Ș:O6689="'7n,F&+qR`f * UTFTN\'\XUfsofSsA^hr [8F MݺeMZ'xqP_&FPǁUd/htU/ `e N(J}F>zPӂ7ZT%ZDC؃y2mW lGڲLh9$<g%BbUS" o}Qx:t66 2[ eɾ ?HvtB˷M@ư솙uM`mn#X֊oh8(ps1ѩÄL(HO4gUu81̩Բ͍ub޽o¼&pX^N51/5i;Q7Q` mC6 +gn|s:>@ H{Om~O`htYV3;k4P{!z ׂe-u?FPEPRy?QzifDsY ߷D5u^l!(I.)Jw$Jpg==[ PAƔϮcV=zX_\T˟8Y$RӡJE!`c=U{n~S ofP|mf,\/,kZMRa[+H#f ,XsfCÉ{\ɼY=ggk uΨG1{#q 8,cGVs>Y(%럘\5I"\ft\ ,!H6`Btẅ́ PEUA6ր7)yҒټPe]Qhbt] 0fcV=1*4FZu)LO9sm +s"d #mcXI|gu6{xgfڊ^[?ӘKYq)_&P<f-0J#ƞ6c15k9Vm&{ezTS {*df9ƞ[rI66:l̝C^,?kz[xjqIh `P&_"ds!sXТ1:\z|RtԈhD@nva:W$(+/K4+7d0d-2,|eʉ.-ZbGcY^ō's~ 6]UW/| Kx!0R2waR^;#="A :wD;!9Z&'.=Z佋u/w21˛·+DA#]Nϑ\mdyRi̙_QS븥\5<ǶB8rUJL%SuT#K:;p/z}Wa.q\-Z& PQ:cKu O|ꠙ&tST/i.IRX"q.z7>(yeE$!w'x|r@vxWOLHjVߌY|Qi7WLtB{?Ѣ<[{ӃZ͊Y-%VעϣG:?xf.qӃV%V :]C~2.!NMRr$gvdD7w !K3煆Dy%;ئ3N[ ]$yz]r W{5K+O@|8C0fEO^86sG;A+ZmL^Fg4#NL0qf#P  V2u8֎$iXh7Qm 彀i;xu+T p=O<7_N?¿ch/~>1Q/F\8[[0RS`)$h3f6 l=a|,{ݢ(C>OUBAWɽz''`?ZSJbH)2q)Eևu;A}gZ(דɄ1 A!Bb;3=  "@F $z:WWDşz bPWU]3ILO?  Bl'H˞3G". >"2H#7Ҟ`hvȶ9g&)9*O|Z!9 z?ڏ ]mQ[m:!IudCfOgٙ(-[e'J. /{O[\"xVt6N(kI_~:gξL.$fIr36e7_8euh`%I'Y L!\S٠%JK x$Iӛ`:-f2etb)O4lź#ʆmLJX=zI6yq"j:GԜZ6)Rv`lux+8GQ4C W,,:6rʓJhĴ`Zxo DWIdHTLS׈+I:|nyf66z76ҫ@2%k9fkceFK^U"{M֩fbg>.4Z" +"N"'}-Sk ֺT$%^$5G.qٮOTWNl{~Ay\{DX!ϵ*B>X9"t ڪ ꎘFNj5pb2W8pV=wt$4w~p`#xt̺cʬnɗHe{JC a}6X[~f&wET5c_'Q6tMKMkoǽΎWE^n}jqh˽g2U|l%'[|FgHjwTt^/ӗe-d"KTʓ"lq4[~Lgˏ/vYyQFr >(~bzxa=-v&7/ 5f'054}3D|@+@sscN#U#Iu*F*$-u e땤dVRrhyD5wdpc+ m&ɂ2'04 #@h}vgu.k[fO4 o6 g0ߡW==Oկ&,xhZ?- Ucۘܨ_޺ao$E*5տٍ\-81[/o[tw:kNF`s;c_oyuwYYԩeeQvo9d\V.dֲE;NbM{#S+4ZFhM 0'R3@ҕV ѿ?< !lkm~WZ) ~l|gy{oq_ 5l/Xp}ŀ@ cBS&T (C+W@beXwmFAū/.l^.%C^Y!SՂ\PǑ(9NuZUS`UgFO ծhW0'8\ύ~uCb Z,oa0t0a/?~3§u/huy-8G^wCa]=B kq?ֽuٻ6ALp8{jP1`?B'.K'cIOԒ7p*<[ (K$8.1O3:}Z 9qSA"q?3oC ҕ+3U4C ?~O絒FVAĝc L$oJӤ3 ڼ40"d+z2d (:ΑZ1KxiF0m(V&Bb$iT UYB:.Ik 9q N>T!RLEjC'gV=w{,f(Ԝ)ّsI0} 2U2*< %r =hU UwMQ4f8 GM^t}D( jܨzҮ)0dRҴަt ma d{2%TdEu-<6HKHZ* bKx @:!;y` dOGA--;6h9##M-d]FN p2|"Wo?Pݿj %yU~[!@Cݦ s/:FM*^r)=u_03MD`sW`?pv ][/*fXJDO|'djDU:"uI|${,7p H* YQlYA.oo#*i'B =L$R ]q+}1@AӋ6uD]@/B(,-M'}P-IJ7֋?u0V^t N?gR%zd6Qk ;7VVE #TKj2MqwgE@..rrVUMYIY黊1 osyG"9|~zlnX~1Gq_ZMaXWllhg.ྒྷ?/\e{ ߆rP#!ArY-ɥ !k-]Vו)Ӄ=z wIˀ-3OTomfkw)y)ͨae"fb<bJPѕm}Sh['P9 _q8dwQf:;Ba=w:X00LǝX.gדDr:?t: 1):+TbrG2qw3R$*f: M1)sQN"N'StLV.M4+dug{sfL=ʍD3OObeȵJ>9ə+xPvagdzfU:Wk~9+5:޿"Bfpsh8:Y[[P2J Ǯ]p>9a0asޖ>bkk+{X! !:?|eXJ^]*G(K`w5p[l2vH,p@gyT>6鿿ub3iv[Q({{|J0I<Avudۯ=r)&[ߞSK?RV|Fv rR 8үS~8|T֓MѭV+yKcA0eiP($#]_pxf؞X0%O8nꗠv>BMp!^-%0q'aC 1 1E DA/U"Sz(BL!bqHx7<^ȁxrg[I~kV.6p~3<.'?y(bpanLEw%dσɠ>`?|af$JI讈ݓ SSSn)I)CSRPH]|K&%sgwV5Μ8CnjO&hVO7E;6hr.=&c;CEW "l xk XnVES SbjՉ 뜬 D85EkD.OQo7f5k H WN{synol!7+l]Q _8^,ukGtl KΐXWv\RX&;#t~EaxKtY;uuMN-oU9FS*t=i ]#![T'-PFkHt$G#iM2]#Bh2cTq%[[7 k't PƁ{kHiDt]5n,U⃟C%JSPI3acP}.sȹb!b!~VQ |I0_4z>2n!= qA14 \گ|*oIj9ɩ6s >;`PB[)qA#} @̋|L{ ٜ^.3:u'|hzQv H퐮֩PHeȘ)E T<٨Mu:e j0Тzb !eaib( BHMQғ,^ ǟvڥkw~χTSBg"4]7U~{= xTE+p( &r4tw#@"A.js x,a<Aq`NHmUӝl@/U`j0絩QZqz+Aۦ 2((XWe}  ֮ FaihljC.heeVՊG WA|<0$g3AH7dpRɚ/PaYTnԁE:|%OTC PڪDzS4益™J^ŰTTkq|2"iDEz.'k]KI p`0dTr9 (,Bk" ]8"@ɫ 3yWdACԩ/'oԏ #|Qqvߚ[yO8ve P2 hC#h@s|g!Ԝk&k_5o80_SFd|_K\6v؍@"u+kԱ" [J𼃩NRN)w ~Q E!zpmJ;O':֑|?Ol+2RG=/ÿ-['+2 #B*=B~]*`LJ)~)?NR#ñ-* sut~0JW ai3zVΥ]Zlfģ,&9G5"?{UW'Ď0:n1"@pdVylBd9My8P^8r="?n*ht #Zd 941ifkH rxIdJʥF3[+^ r@5o)'7-x~);({K&5)2"!gIB Ⱦuʟ0kߛ>)U҈`tHPp3v[g͠5]3.;˟xDTsL9 6TtL5xϗ;| KfLjeqjՊm!DZeuX/|~G@ax3{a/lPkۮG{Il\Ҭ# ,U-4V șځŊbE/[9;m՝գԪQeFM6J"N.s$Ufmd*7>ψʥb_z(z._YIń='<-+.'4~Cʓ>E_oL,ȗJfN6m+l]KJkńlDOE!EY&kR9N&w>*^3?<|o;M2C>HqDFT &\4of<ߵ?#\ve݃šC\7p<2d"&X#rcY_ !+`8DrRG"pwu,ǶIJLm AvVXL>~D5Ythɂͬ 􊈺t6h)՚cU2aKSg>R;ž۳vrN}hx`Lye~|~4p Qr[> [^Eg'Ur#i`{|-4&[^7عb(/n1AvXтQ,a.L~|leatM?"9ow0I(pW-l pHi)T =S 'FP5.G_q} L(..aw16]?1/bQj+ Έv=99 ?6qBdXdy(F祣$CۢA ~ ʊzZa0(cxhĸ. A9o6YxPYFEs۷露bM-HdOnCTr{ɸji%^ȀRBx7M+_׉ r@@2w=4<6I)1mL463ޟ]FqF[%])(?Wxx+%*Xu.LQ9Tyyvxh/U0)`&eY:!NR[O٨s=mv,6f4JJ\%n͆3XyLOϖk߯M ތ:$ xMm'lJJ-,%Pi\~ lƿ$s~W[e?AMM=)Ǿn%Uy~3yr`=U|q7X9K'~&MWUR(mO0=1P&ID"#^Vaxd1^r/Gĕ#BG Dd d ե~ z-rẃBJg6VcpZKlVMlz:T]M hc'c?U'6ۆ>G + Ϝ=u&LAeEQ |dWܑha";B ; U?|߸RGe _oz 2nt/o6W15Vmp NPx]$qrZphM|b_Y10D-8UnTQQ:*gcfF"֟lYGMoߥYpm*AzbOK=l~lmI2 ۜSϞ A۝EM鏜h^Xqĉw~ b4s)B%I Hb{T(UY/W3V}~UT}ݰ?O)kxAe^\D_͒J +m).WJƣ%m)]/Hşb1E _,pxF搌P82M&WKr1<-k[^]ܢGa y9E,u#1E~w875GɈ#9=9E7Ws!*"'$#jEڮP};bjoB> WG??<ij{ftXlr" 叭gBɒO]>\r P2}߉ H8-uupfRHiixmI<M+`XQlo` |d)EyO OPg CS ;]Ks=$9z&d~ ?Aŧ m$V풚ֺ6 KnbC\+=)I.9%/<̝N߳)0%Jй$7j+r[U(@g)d޳@GQd{{>I 0$G ^&e\&; *J&GUoWVT\OsQAWX]W>{SzU5_"1s^IzS]]}ֽ9zim?Py*ǒNnSr}jQ?<)p cQ&LlgBM+r}>_L C4&أB>ƶgc3kd^SS~q!Qd䶶8([ifY&SF *HؒLz/$LNrqz|׎w%9@b,*CJ$wEL6Sǻ.s +xF âI5{s˦>8-< `XXSR+SDĹ4~% ?>'k['#gj- /hIZEnKn7Y_[M`+`F We/BiO 34ǯSp3oyrۻn `00t{#7ԽZ|x%׶ 6wCzc꣏Ɂʰi#!WOz5wJj$lbJrF 0>k^w/'[tW>LN0^(:[䓪ٳx?Qxѫ02 &\H J*2_|3kD`1 RZ79VpjslIU9djbrx24ti88I4 V1Y?z{:f}?Mw2.e'9 _ $ $[++m]8. qK+v6RN̵SŏLkCt hR&_~jslIlװIƵw$:5Bq?C?\Ѕ-3Bz=:/?77ZOR.Kwt#SM ?C*͙{ff僛Sm]H큌_Xh?q .HtLș MQ[$KHUzst϶Jez΅F5Ib]eA~'WɁ1??_Gt[T8.?_I'q9}i0HDZ,12 ##exz+C?g4eu2+Rà2 WXꨄʸrbД^ %ST47~"k.H: %Y$;VV,º ɵo@ STyMM^$^$~QԤP5>Xy"1bzе1Bpuz3+ fΊ2D jtTJ,Mҷŝ ^#xj$9Sy,('*kݔB<8EEVp8&h6h B~m!7 $C|A}$Nßx=C1'+w$59v_s6=A 0JgF g *NU web#J飀Z.vZl43Y@o~eҤ\%*)7&+l4Ir.Ҫ(ZdUO hkIѡaR*Tj̥6K5䥭rar}_d7Gy(.eK5 .!F&)| G7}~X>|ߔR3wҝ`iTդUEǒt=SLbywLFM\j*++ *+W-fˤ'wJvL!l>3$-YL1N%cTfes1(~QLRL.^Imfȥ3{IzܶXQNpJs5=UUЈ' ߾ݚg4@¥x\*hAO!P$ =T:DT]j뀎o#7FPpL^ZEZ\A4%@+8| r!48 x%A"0TOk^Ǘd7Ku((Gd&&h'3ijĬoƯ%=HLr9TT[U.}@ _ot$!_WPCrI+*2(~rm!b3aNE9hsh,H6)-}]zb_1?]eiϭXz45wW o$7!ySp/q$o-%Y=;54ǂm" S]m kz.˅OG>^Y<9I+_ԝ"YP\uXU>zyb݌0(7!U-)ͳw!p|Վ({dGAW _/ NZ@҈T~öA$WaIeO0OB.雀(턶s߀Dh%B ;釱O>I[h#d?R0㫣O,ު@J_^jP"!ɺ9t RY3|D"eH߲qs Q{X Y*O_선`҅I: _&v_a eli%:b|͒0'>&'2kb `-c1ѭ lT|XIDtl@] ڣ Jc5>W2I!dm)FTb ܧXMrz4 `jMj(^/ˢ^:Ȭ.MQ bI1 xl?$9l;PX A'q;DA͖~@+5 [ۂY+9APGx',DQ (R!{ ozJ<|(IY%\A`%'#L{3OfHUܖtg |^x8Fo "]\i[X!a3:r0(v"M3ҁw:b Q/BTr,e'VD?hF[7ъgu Ӥ,?tgJJs`'Dݑʺ Ň Ĵ(Ob՝h+"p"p!Y%rPm'rPY{BAż19^Ԏx4 :I`HreX(Lf ʴsS4E'=,B 1%%NTWh4YF9>O?+99N` oݴZ4h_;n}b+4Tߺ\tEcHK8P]5 ܃2Ȝu9M`CF%7dUBQgLXD_/tR5<år||` +è'(!UEUVŰ!ü"ENQ!MY>?N^ ?W(7- mvԯOq=`1+h<[5`iR<}Fq&4>jj(pcJ]Ȭr3`bCNe0ZB-ozW[@im5nCt-Eߚ=FHd^yJ4\+ݐtM5$ep =sڵx# ?Y0-lп #,3m)n@@.!9>$+B$M B8⢠JPe%^ ̧fE?cło@߳sG~|63^5D_Ȍ`]mnm-;s.h2{r5Hcƣ~*FIԽ> [_hٹلBlGdA { ve;t}3D#{BL=9u,KI~r}=54ɳ9.(J"qMkaUƣ,Sy!(iwB^ Y4wdeP`hnrfU$z Q ]TWXfe/ET'k?U5U]sP5'c?:Rf<,5`#eS]~yWk\w΍kSz$ gR&;cSYH.P\xYĸ !F%irHah Ȁ筠BJx݌^'v?׺hU=dqѧC|4Tk<;$f& ׭kkekk+vonD [j#VWhmM}Mŏssi! a5=5 ʊ 'aVBB0,q 1s @"eOy(}ݖ$ׯ0~o;4@֮m+= *;JK4;U8Ua?Qz6؟Tkxγ [s/_p}YY7~C7p,76qD9,pV=f3+BI66 ly.Cek֏ϴk"R.JW0Lzp{ȸ)U(eP9om/ s)4FΧ~s Ѭ[2 "*Cbm 9ï 0`kFFc5~L>֪j0j"xrnҢ_E>Z ܯ?۰0U:Px:Ӌ5k2WⵒY\nǴߓ,;LB̧8<) xvY_Z?:΂[oCVl H#l OWtiH2mQ V׫d9MR ޑ'hq*Noky_KzJgk*D^g\~˜&tw@ @lzѨM0既 *9: Q~[^g4hR$C05._xey#"Rh@NZ,qpt ɱMj;֝'~d7j@9!NN)g=SEuǞMD|/ x-JIղ}sI&Rw|]t_2LR3鲗:imtfN'G,aJ_O0J^^Jmk3nvy%|@: *5y/az*tڿYI&GMbt kP}(z\2:c!Z1W@5㋍#*8(<:N_7`=~:PBE( H&Y 7TfE',~K!s~n3]J,~rk] h|hH4tD„4q>} paW-a1xqC:l ƣY  bA-Ix>? A!Uϱ|WSP}՗xaro/}//Zt|(&m1`N_UD(EuFj^{ۗx&"hXTC(|^S݊cw8dcǹ(gSBZݥͿR NuqGdTC:NP'E.zR4 ndz q;.{m-dcֱ/OnV&80ukzՃjRkBY7l?+)78vs:ft|G.e[YKh19 .6CY1^ӆM9Fx$b #(r!Y hW crg*r^?!X#Aƾ_-ݻ.g[` ߯X/4x_5!s)Z6(_oo3rPEa39n\ԊڏǙcgP.j/Z?[H; Tذjر0\~e'nA&blᐝ؇nh"C*|XǔPH8A YҢa%d^S$%/O#X>mY?b>ӟ\: 3>V$rx>%hoı{D8Cy$@/V3@lƁ9jSTMXLDĚÃC5VUqNx0xqJP,tPWLt2ֵ T8.&(ybD!+_MX7VC3h3Zfi;ИMK dI5?j@Ld\3p^(ǡCۋ/7oc.KϿkwU=a u_xRk7 R͘XUᲹ=Hŗ9/BLiA%z C2F'J1H"MBB{+ÔZzߞ<K<ඖ|ݻB+:Cgy,HMc}\1AJ9dSA\5]l^ۇ?"cFmjzPwfL<\ O0}Ț{]8q5Fg2j AN#{eL#UQR+5Ɖ&sP1^*q^J]\HB7b\KG= 0nx f FN+ @㞠t[#X^6iaF-\dGe $cŴM`񿞝ea7 a uLQ [ E@L'F+b]r`=F/Og%=O *4hDܳirKf$o,h͐ }jz0gg}Ecfjl8P!:p_//F$2`h+ K1 BU8JL +|8Md%J,JY_DgWt~̨.Uch80yGQ*< .d^Hbk]|LI\2 ;Z-}[`'շR3t3 &SJy"غ^? `.Ok+FH.$,o9YgXsud3_pӡIA'73(BQD ]yyrfsGcDLl5T g? @nC9?j`3L$π>s̟qWzf$.LMb] #7en laSej9~P$pm؋lMYoCInibL'%xUd'֞p;j,*b Pe.}{L)$,2},Y1{V̙1-">Oϯim.LR>ZRy [,QTEE&~ESYKsU+ 0ŚlmF5ގݍY!=Ld88i :3 T$G # 'Qq5"M&쪜SV3x<'*e"Ƈ%M䐠ܕ:xg_+T{tk=y*g:dj & $@{dP!VR",1{`r!d(.U7`P[abZ<hخ"P]K]=m:\i@u; Ωj\z4sp.7L=&шbӇMt2888@Vme)bp~F5 mC7fq{@B>b,Ȕ lYrżyq-(oCecXI"$|LP1L4N0fuJp5Z0Wո#]\4ƆٙgL!(Tp=7b;5I'tU1fjƏ1b\d^/:4iNT؂ G.$hR%Vlo8(r;'|Ft'|tP:HM}{AA[x"h5_?K}2VyԪh2gtP(sZ AN(. !2ap.Xt[,@|W'~]8{R]Zⴏx_n|WG{u=sRBnF]B<~Y _GKdb="u\{{4ܛw u.E쑴Gw7$B_[Wt"n#kAJ+،+oSZnV8 if4QmĖ4au^F~vv͹k!MwlB?޹!d F{+/u` ??2$CڐL@%¾!QDAFI=H?', YRA)A0\bd0GI.[LHG*B}}=.& پO]z^)!}݄)EG뢨ꢊ/.*!j'g`'[q>'n#}$I_8q˔e^$O"I&*NBꁦ燦1SS֠oYȚڞҔj4tf N fKA7V0 R5w_pqȢ Q˒X2+ydR-n^E{8Otnjv#5pyGBS0jH-J!d(V(2;u8JKށNPoby;z,BNzj J?7rx8L},aBn[_4E>HCŞK_e#k9y >;Q?WU~qNſl&D&!.DyV)Mny9y)Ҽ+@S/E~3ˌhpm Ad +MZ 2w^1p=mG:>>T:L% rn.@XR.^54끁Ye z&d8C{H)mj2'Fw r3 Q| DxIECss S1~.?wm1Ӝoh1דk6\Ж==.,!hX sm)>|+}>ֹe[x TG Ϝ5:Y -y#?,V\**Z |76޼WuMPp&;fj7sja9p9ZF\։eU=T tK:~Gs}cgAyDGQ%Ю7f!P9I1lO8|D0 CÈ O>> {蓴zӦ^_T`'1ĹM`UB_}b+\mЇU.Z ŝx>aǡug5ѵ8^XɅup]G潊P%O~ظqsFt g1UZ 0Eg7_|> c\FT"KC Qmn+5]*0"kOTZšEi?Q((=Gf<h3~YГgĭ@f_c pupw>awi.6,L-46p^5d uF#}^vʹBonHDAj4oJY?h615(V /hT0x* I>nk~$  yOI) 2;F-&ǜ{>C7CGӴD$* $K"+݌,I*$ANlwSH*+l rmp7* @Tc_]ր74u (Ϝv}wy \DotƧn 8Np'YVe-?E/܌Gܔ풫s:G)Vlt sFנ؎ڛlF˗ Eߧ 4H-Ͽ`GT>}j"&:zBn]Ltu.JJJrrrJJ:hR/i~M>0y&Fd1&CltT1c*hj)b{g{b^>lƐA~(; Bw"w~QXl|Z1\2Y?lp6=ơAji (^e:HœVpqUQ=UP|3l 8- VzUAO@= SC] ds-?U6tN4*+xQ r~?!YM23ŸGerbB||isqϱ7[zL];uYU; ɶ>U{^gF|28Y u%x ڕ`L7~ݦf᧻֧F4ڳΔL4wFIM; $_aN8b=T\WaJ6dQMibAtE$F9_}g,-q_4&Ϸ.L7 AF #j\)Z-_W(N?@GEXkW_&IJ5%;`kzתz8}xky3>Vxû WƩ0%xػGwn= >Ecv`{#t3?o-8,ZZ ACU7eVLgCZׯ{.?mh3h@![߻"DәP(%"^Eie2HkпϿ(铂:~c&S&~Euiٵ@)<1t R8LE3!vql Ќsؕ Ko_jʛ$$! IHB?Rx2ow#75pJ_[˻b! 7!+8dkֱ&+,P_( -<@ ì/<ܹ#5,UvRev&*GXŏD$ %!O'QE?tDR{]~$12͈ #/wdD{(4+ ( I !骾Ӱ9$xAHI $9%@utrYYFWg]QYOЏUWGI 2}C:Օz`w}lO?ZQY/ЃeMZ.QKl8\*|fl|!UW*q>Җf k.l1;5s9ta#ov4u[{?Y :^;XwrrNvc?X~_:<7S (Vy3Re9'kCp&&RnMЕ'::JT|kQ,*<°`i>5+X3+ړaj.W HYUu:tcwwNX;gu.W#קE\1/쭻;}|,"Lj/XJ|`0ڏbK:d''%kjQG>M_j g?l#  fH;"/ftR WXjpϪƨ<(ItyX( nPأYxPR\8W{UNjڗcw[pHc.{jJe첳0m/n>ߚܪAg"|!Y,>w8}du:` hseuZ./ ~FwTQ݌!gtB֏^5;G A8/ ɔ;wKХ{ `D }25 [ |^8PM]i`A-ԋ'7㑠$z-4BAȗTB}Ji\Dh!*A+IB(Ax ,J(E[0N)=${4Ȍ,a[z~K汋9SLN~LY@zyo_بO?h?iueJAq[·+4](q <4D*[E/mA>Zd]ϫ2#b7"}NJk(@NcԤֆ> Ai*o%,:s;Q_NuV{0h?vup治xqk*(w-)KTST2D9Q]BEޕ`ٹ2hN yjL+vCCw-]R .Ԫd Ws%d?;>/ :8\1MFSe%?^B v6܏X`*Ol4 mWL$ggVB'dZC&R^S)z d/\ZE`U&RRf-%%9ap aV .b pfFy59)kt"g?~D.pnͪuQvuof;" Z}<F L6D^ 0h}_ 3#>0By-tF8LPYinn54Y7`^?5۠onN,ѿ)=TA b 7D-I9HZC$9"I-V! Ҡ}p cQ(("P 8p{S'zz<&F_(ѭ`;(O=iD8r(b0Q/0+9jٙ3T"4aFJuqxC%(*#W<d NruezquIMvC+GNw(pv۸syC~־m5e ,U߮j/i]qqH9K@-wCxG?U7| ][tAĔ-b90_/>nSfso۾Y8aPSrڟFMk "}f9 z .֘?_$c{d7 (}{(&*m/LŢk% o?kj.:Hz&7A\MMARl 5CnըxOK2 D)ÔCEf9T7#ϧmexvɈK"}ظLC[pP$E0R~uMXK4TjZB5b98ʼn/۵mZ21P"ڽ`YiЌbi slRe#4@9o3S`Mcc!uvNb 1w 8P`$і?6h<": FOc-g>(τEœM;!|uTJaS$yc ~C3WR;*)) D  bDO94ϪLHOP.uD|asx} UJZa5#?ʭ5+<*fv6fS=g+nzyWtZX~TY:"&UŕȇƁ[uD6\2`znb<Y ^o *ME g<c"exs*)̺&V!Ν:)Zx\k^ZraBO`R +!/g_F_BwPϳ' sF] N1NdМX!N yFŹ(~yr޿\\>De(BPi^.[yk@%݆"*F[)"#d2*Kq樂bDF'zt<J ~Pҽ݁ȏ[F% Ϣ0xS=S幃y<ݯiHcJX\b;oB>6` | x/󿱤({_Q˦s/x%1^86S>ZE&lmCX>S.\S37l{LUV`*8聒Қ0(= K|ro_ۥY2 ̅4Al V[LjM-8G{8E,KU),07ݓD1"1=wa{O53GAkQDy0k< O*iRAG\A5^m_&lߣ54pP-;_F h|!:egI ,R?!A6 ̋@@& C]p"?  n㯮)[[huڻSKŹB^t ڝ?k8=Ye;c==ݣUd8"m[lt?$R(2!SXKSTyW9"J4d/<>3Y33#judj AZI7d%0 "m :n"5j`y)mLjTźkJ)<G7Rـ2'&\PdM΢p_4W@4#KL{5ڑ%%wpA5&D_XBd$AHQ}#KK d +3MI[kV 8Zi}+2jUb#6?Q] |Ez^D!!$ILϋH28^d,xQ0$CY]O񵫬,箞.뺇'ؽ% p!Iꪪ{^I\@T׻{RLӐ 5mX[c)RKo>"D" #A=JEҎM{djˎmH@]3_[PLKK9y$/"څs!' 4Jq@Mg(Ml"2 bw:m&B>#l ]~=w ߲bsp+5 '31.3G?O|y'w(+!Ӧo<;ͬw{q#Y*8gW +;~?@Oa\]IlIh-N.4o)L@h^8}rGN#fEZCn݊O_^rg=ΝO>՝Ukś ) Ov.>4)d$6M_c0L0.p9@wL7^ m^ו&&TFG 0uCѣK#b= ~-y>pA_( 9t[Ul1OϦO&H8 zؘޓh’2]F:qQ ,8$l)BSe-Am[#DUal9YP}~ b;ϧI&2m s޲R5Ԭd*m#4Cag(tK7e^h~+Vm@WxyvZ6ZB>uƌ@ _a_‹R[X!λWM!bbZD Zd"YZ%b굃T.`X5jH"4@"&@fW6i pkG*(:D,}f v5٨,o|jR]QSD֖C2qN?NH9Tw/Өg4Zny%5 ]yx^\&Fb6)\ˣ q>鶲G|J[55i Xk(5G F&F`̭n׸^UVc0ph ٪3UbE̪9<'ҡ塒9W=ϊQ/3E02= 4 1m!- Ga=dɽj7UG>Sb nq37gLMP;‹yo>'jDSЍ!9js6jzsFbrm;5/:}MFF|(hrүoh"S~GOènӍ !Ss+N[?~6RƔgmaiFnd^_/uy 󆶮2O۵:e,bnDcrv7Q yv=~G@'xߦB!.hg#ۊlT28c_ ϚLz\EE)\xi/P7/#$E`krq,胨?wv #HʔɽhnNQL;ΥQJ^Rçљ9%w,2&|xGPw(5#Ԭ<4H g̃71D9"“D~-UgK%fH0٦TIK=ZsP HIOy2==iU_C/}T'rFą|w@_o}{]wr%h|:':zԬ^=d4S &ke"-#j>#THt3}&+*rMO#  !:~hZ}|wNﭘt 1x E#Gz,cӀmgdg'"ſJ3Qeukzf`4..^ފO߬ iPǷJʶf)-P#98A"lu!a ?׺~>C aX}>#p'3 B.`eWUbS^1(BäX%S6obuGm͞q\w%Ξ[q\ѼeRŢxu[h?!jX7%/T*b/EFlЏ~*Бj{ n:]o7[)4v}v93!Up NrVkHpNB>hfhKc{&U\W})-Izg EjUxtZI~nIZqȔu+Ƌ0Y'C䡏lxNNGI~H`DGȱ n'{SeD=`7H3-}) D*#dĥ> _іO1zi$TO2 s< K-N^ IЏwOw74`em3ƉϠ35 }f(|^> E sCz[:. Ř}q#XHEO\e%GM+/Y'Udl!)vٳPϥ'e #M(fJH09*ԗB>-@%?Uj1A6~0c}nkcuy6'SpV>pmn; \mo۝o:{Su)}8gWȯa+{Gz2nApt"ٕ(W^SQ \$"f:7qOJk`4,ljE٤g/e|$#ە\oVb?qL|C?b^Fg*5CiAՈ@MۑiGuj#u*Jо3<b0dg&`1IQXUjժ'$hĎR 8c+Q1"E{^&6 Yޙa(̙  d1X7scE-]OOb3W;+]Dx[4F4*oQ 2#I tazADov q`[F%+D8u,,L|T@KĦg@1"4M.bFk$VC./LЯq p8M2W]xk6]CL"= Mɽx5Xd%|}έ}EB瞧 whFgv ff/+Sv3mM"uJl[dSIK#% # BD]gTk!PxMʼ Cg,DtO̯ >$=3H`ѬHeybnҞ| JfkˢLdI3"Nə`@%im ¦4|Ԓj@=OWKgIytK@$uœnϟp)d‡wޤ7r&^-"g7ţn7tBP;6?8)혟!QYk)>g< ]{d< ơ0:wߒ_Ǿ HRЖk ;:Q(ZL9~]:'o>Vȯw(p^?YdUU0~F2~i,buPeD_5ďWOb'xP1K){D3)3NWɚ{ CԮ׈JD`A@ 810"PKk)aɂj͝uM})}Y []V:ꡨ&IΛձh&Rr唛KtQ d0Ķh&^ OEQs3m:@$ h"jje`^@͂'eju@V 7vGo}`mc;&mp$+&j%6 M2YLS25>B#̬XʺVKWq"Ukp]1T9#-?%98>r{ <{訪kL& d b1>d'12XD(#MnxHPj0B*>Z}Vl-bAy%}gs; V2wZ7b~FiP u~ ZWPEЫ9YqO@q2 ->09,fv"Wg9į,@v]6i۽98NV[sh DmgeAoD i9<_ldƓMo(EPےڄUXe 'r_HE[Hv&S%QO5h6H\ޯM  <i_WVk,^3Hv3py/6fخB9I\QJݥq(x:ERIfJi@kfhH?PwɏhZYԜL RL o>36ig<79MD2uwiBo-PfIMT'BɪL\))a}@EkdLdCx<`La|/gjJިyLN&] jOx0XΊ=kNR D*AWZ\AyNW0(Au[|Cј.6sJ},+ *򈬤|s.$3;9O+u,ehgJ!ѭ$Wwr\rwb4U9%_)U:AqU*mط%OVpEְ[ҿ챀~eOVE_,t#Wz>sG=G˱lp-6>#L)PfԖٴn2ĵ),0.o/íW❬/Jl&E4_GD4Ϋ I*Bc57oLabf_V=(}ՙ4?vv,6O4}p5|lAYF-~pĉ_W`B.ٵ(HR(uQ.c*J9=L?#:>N?;n0落P8.VnXÑ*+goɗYSϘZP׾'-cyF})R``ie…Jkw큛6 "Saɳn 'Fu)U+`m|?F,f4Qi32k-i= |PC!$23'lTgqԒïxKH%jWXbU;U^}FOVut~d7fnFKW+6tƎ"92't+pⵂ0 XȗnȺiҒ/5%5]QRE2L\J3@LYKLpĖ),~QjəJdTs)m􄑫oѹjHwGp$:"WnMv<#d $!ˮ}砀a{RO0j*Z ]K)iB{@G!u FУ@|YflآSs'LEZt;^T]F6`,6Ć[TS3_ ,HOUUL3_h቎w@UV՞L: uh՛q8tO)S4P(rZ\ -K;2VWz>};,Q@W>E"Ǣ)" $VNG)w[y6 v֮f: ǙuquoB–W[-Y_$ [!W%C~r0<3"6O#;.PA! %8@EtIv2 YCjbP f^F.jCuxA6dyzJ[īh͵{iͧM64AȥWdD.X',hfє8)蟫QTַL]D),%vKz\vj&)0 ;EdA;ņ]fg"7(_ioi/Px'~| jj Im֐#dwyW0v#q8n=^JN% Ap$7:45GQ }f@)6ftƹ8Z)tBd!!X+*&IuA%4 ); 9O+Ig2.TWWqbn u7E|[񤨮,|꽁dE詂KSRhQdܩlQt=]+t ҁ}c7h=?s2 AYD 7L&Q\TNaP2ZF1#^f|3oc7>Vd$* =ʂ,-4xL;5ӱI9ZztWLG]JPzutaA,[Fdoyۿ]VMTIxdbkk~'{ n(k;9\.scEʳ`/DDD ©:P$Ӷ5i4n 35Q^i*5[:YWÛ{U r_!d_l7NUA#V\gm:r!@ O4 EwNh5i5se?Q18ɼ鍞pp2hn4̸nR}3ֽ3O{k[jM8V%ЃQNHL2H1/GQd@O̖,o{ҎC>.ݩ!֠Pf:PR}l-yc}:]5V ^ jJ_=O")(4k vG-i#4+lNc ;a@  ˡ@!rX3lg=3(<_C _Zko`|Et||W*.B,)Z755 DuA8TbKLw0u#uKGx78I=-\=]%JɿaՍĘQ _\z] iEkHE};NICyд2ԤJ1p9Oд2V ފG:NOד\g{Rb+\ 4Vt\GEו2 $0EAA jVDb/hE21ķ1FEo:`-#MBLmdw术Gp Oz7!c]7 q''-^/G.{kؽ.Y[en##z9 ;C=zj!ߔȯTQipْ^3pZFdW-P Y#]qFnS5+f~~[ԯ  Ϧ*G o63tj떁B/hH%WT,^-_<>^~R1GU=x~zqȫ/Vй@HV.4WmǒBs˹ 5yex#X,7\C_v<B]m1?? 6KUXuvkBf,zhzHpFB69zܲ-trYG7=紺`@ߒӶAυvݴF.l[#ԢG=뻉ݨTNr';8.^KLoR[),!i i{Kl)b=j]3Fd '4d.L|Gy3;IReu6yMX+M}Az#[.{caLSwH j,^ȏa|\}(ܡ ݩ^CN׿'q\VO0=v=tm~p{d?@a?!oP@3iS}A1MPY9S/Lcݬu< eB*=1#{Y#[rg\ di5O׸V?LVu9L6}"iRB3|Sh. ʘ1!lKR¯^ߤB|5b؞ 4q)՜݊˞IbN^7@5F0CnwQbns`4ܑ e#4gc-7F{8mһȖ3#$nA,e4(?4@bELiT{>֐ o1Qz*8Ut}\smSBG{&RxU4XT%LTOyHyR=E^/%+_b~e{XU_ҋ*}N`^Wަ6n=_iOaHw6.3Z ނ)MYSyB'8݆X4Ì!4*xHCZQBh\}rRɷ3Bn劂ޟ*k; :u>Nj3+Hs I$}O fpWW"b03=3"G , r *,l~Tԇ( "+ HH>N&Ɦ;B'?Ҿ^quV }|~޽s?{ʣ BcYqm4\wڐ 4 `uѯJJGVe*eLӥwns@ UbYC[F 5el~ݵ(0<H*aUyبBO[ u>p,j p2=j91 /vJ<9܎m0eKtzj{ V˪ԘgmL[-]Q[ts#h c 7EY\` <ǰ:N1i 'C?h׬*8~sW= m<@htAFW͗ 3N߅,=zlLvYԑf`1@Ú8⇹,`Lj{d BN&7gr*QO]n',Pqv?Âb$"ghl6w"7ĵ:WYq1bђdAvXw dY-r/tsb%Ӝ/:+-A]QhGOT8ؽX{#>ZOGS<_{kОҪRg7YAhHykMgجr,B>!;LlIDY痢`XEw~E˹Ab4lh%.%h#`QJxCST*?ᔑyOh{FLpy][zSUEt8&Iǔ `f|-ZˈN|=net$N u9|g:(o/Lv `zcns.B<}l53}l׼c_='E' Ο<ڤ9CeQUs*q ^$ӟImg#fG2-H! ?\q> 3E.)#TX(+!P\JH뮾nu[es ;xeꀎF/xouju1UVʇ8gڰjmo< ?('e)eIC"+ E5ZmA^?L^Vz,<} ,Es1sJ4s {'j[UW};~Xˇ>LTz`z9"'' xG1p,.9wMb'F^9>S,5vr~f~p59MU Ԩ8&GG=|_ X a5l}`_8`΍6ͻ]f.(wOF?FX0 *#yOcyvq[K͜OAxR{֗uL4[w 8<cལHj@1*kU]! 鏄n3*{,heol! txj+f(|`:ǮT)~#E5MuEAz!cnFPpLZmj4G͋J4 h^FtC"ϒ;NXUٛ2s@mꎾBȼT+❩(5[44~EEEW"UUrњwn$(cy?yF`k"EwwCFo}V$ǜm.;_?#J$p_86Cd8_36WuD}k)[BZn*$lS;~LG[pdHɐOcO5LqOGf?qfB*r+47I$DJ:n#*Cg6Z"% &$hӄ4oV# 9H]T.d'kvCSsT=o …b0Q>{ˉa4/1Yj"asAQQUT xuދEhW{"nxw=p39xR<&}SP 5 nC&3ǸfY:8AϚZZTMCnX70jGO#1v-ǼcYM85',Y"h|Vkt+,}W&PnJ5T@5kb\)w/] Ϊ`.ےI9&3XD6CxuOٝהּܞTf:݇D}LUN6TѥAv u(H)/ -W,GSZO+܍.+ D?X?_8/Du1. \HAWdl?b +Cnk>X~Z0QW;^}fJot4!J5`i3'(cUtFmbaE/,9qKwU^ V+a335np0dqcZ/1c`@p>̻8lX`>֕\LKO;瑔*=ߢ؍o_>RȭM8ZBL,Dv ~?8Ns ~^t\Y0(x*6ooLfK:lA pQ֟aph5scA-@_xr[wnign;Iq&"/ʏ͙Fٌ؍l޵kbA2ű!:Gz\[8*vY4p9_=h% ,y<{Qc`bUMXK+7ZXHdJj4æ%z26+c뀓3OZis@eXYV{o wUDs}[#9@^#6g`c*7r )k&;;4 E笙>pa݈Q"z( #>,",8Ab>5DphMaSuPFE5yt0 1yЙm"o ,@57Tŧ8KrxNUgn]t4v1*S̯Xpg)4#Euː׬Yr̟럗?דK=>zUpvUҼD;)%)>]#D'@<A>IANiQi[r˴e?/ӹ\gcW& 5+^V e:R[6d3Q8g}fJFnTOKDOgT67oGD@$w32b?QxXH8M%zPaBJkOj{-Pkn5a|hr:v 8tIa"aAU_槄;Mqƅ= ͸;\mJ 'I[Ev-HF#o|iBL,3vRMuF|GcEH\wtH=V[m2pQ!]Xص} (/'zrA} Vg.~.|s @9W0|eWUÏS,_J`OUQa)37@=2Sb0߅}/v}EҫĀ+EQڇ`˜pASo.fh/\BLOYd Äc'}@ RPfT2H/p$p~\rBkϛi3q2pÓ-ŁhP%梗y#AY'}a,ڄl7?{ooSf4^߽}Ry=rtG ^y]mu* 9O۸7.i_`_oFz9OvyHlxG#Y[۾!D>ʔɸT$T- h$uo_Y 0VĢ"-Kv8X5gdA$˾7L6> ت79A"^zP=|&5(,_ASyU3>ekk@yiç<%C}o.TA+8p/MDН‚l@ A-.%bDwK>Qv"͵|f-csb6kF@ԑ4ٙA|i 3_Jd0؃ڟ;D/冞Y8Ƀk[V@^p?4XjCdn9< oXE>q ' IgAFNA2&~Y8z rp~^J5=IJNg|؉u٧_lzX-P'y+ =ם ~q9~ ծ0 defɑ'uĬ i!n&9`w0:D4˲,e6iNpdgdSIo*osv%DA礹<鴃!iW=T©ӕ+s 2rtGM`tޕƵ(^P`ty;7=Xӓ]XyU/;prn'=1({F3w#/ҬDK,hQ`y)ZEF_Ik.NW!+gd{cۊ0T6wurDi%߆AKHzlPT+͸ەZm~O[e?'lic;jR(#+-`78s{W6lmO^mB͠qNXonƖ J{E⺌:;b2Xj!7 CZt;փ j/<-+cQOQmТA5~kq,(`/ٲimҨvXPQ k?<2W}倘D( t@EE㠀'Js@;,1\"|r72 nj(Q3%rtHj+} 4;UU{a ЏYi&uK^5`D6[T!jm:L}5)M:(&dsqnCop vbnbGki_ANGG&l%?#ު^eghζоVxD*365$kJk`io w HD\[0|C"p"$!"RDi%mmbݜfnC"ӆ@fv8rpep^Z?aO?\s! `2\z/ 3H}8|.|w㻀Ď=E^ސU+qoۂ+]mQi-1n4;mF6:f#pqh6 wgG \#; ,h PzG}Սx}ʇXEn(Kjuɾ^zvtW`@%嶞Oj6ם&m@Q*#W>3VHxFvALxЗ})@H2TXy IWW ֊Z;Cw ^A~$}$f~0ɧ"<yRc1ׂuwzͽRIkWqռ'vvv.'c;ƺ-,p&3MlS?L0\d%ĔR:J" 1.\<uuO=npC=4Ik0wc4,s@18zyS.X~K\%Kx1Ql ˹,z0z z=ø-`f]vi4GŠW # ڜ?iT3M**G{̔(oź t %V Cd~3Thf'NUr,VOVafg#FBParJ\3WnjΉ(OydhqK%ӋP̢OE"眓TCBj?;M{ʗnzՖքqe8\OawS@dRw䝉z~wWr){Z//ꞷ{!R^!C q wB/wԈ#dtJ3Swl|D##V/V ~Kzp,jb\GW59/ + k%DunuGض/ lB@-", %ʡF!R B$| }^Nj҅篽?00AJDmӖ1'w|GUv@#;x#6uj@ |⛪}`̯lӖΘ_!t tq `噛1^f!zD5ze(tmx!gS5Œ=I%pO R#!pZ ˋzb.-JOE^e^8au{>k*vN3[}.{OeI^dqt |̟Il.vЋ}Sk@J1{ \ !#,U!ϟ}y3Q Ax&虠;((MMm9͢7z8pVE}ְp-jKW_;o7BTl_@m PZ= /iNDh8?p1(6cţ%*,\#hxm$?=Z+  sq8TxC 쬀 r DǼ* Gaq\ '<i< 2;DxDxi -%MQgM,gիEnx4Q[bWL,c,.#JrShbɜ h#p m Duy  x\['7yN;fo2ߠ^ӨJ_nE ؍&'͸ƨ׻&88q:Q?!^oM!ƕiJ!̼{#tGE΀ ߿d >{_1:, _X^HWtblF![5wX*W%lӰ_b&>77!ϗ)~PA<9oyt͂,8QSOz'}'D|r$?X䋧>4/ < ^jI\pvAmx̧2S*هe 꽓g8[lee_R>Qޞo Pmݦ#D;Ɂؑ8&8%|9k' :dp$2NXlDP͗ Yz^N/¢ޖu?XRPwxQ`jz1ڧHE~W[~KAm頻2 n+[bԾ~!ܛ$l*,fυ-SqDp=ْtV]`C<6)B|VIzG-W Kw <_MTAb&NKogR:)&&F9PrE\WCrvx?(_(\+׽I Abzf 0`Tt=p_vK|:|^وo'h[tъlOZ46-J ;!yl%EXg'mX2ljf˶h 1H__8t |Ö:,/10׺(_4kwEWq,;|};]N?r^>Ч,SEp~$F<$H>#"=!m-m9$ƫiWϩ`w:Mvu-C;²Nb7ŰFSb'@8f6qXb <$/_D^j'j{O;~QJ'W5?w5Z5(?W7}R[W=ATRDIIt:'JJ,Ľ &Ho~߂ $> ľRf6 B.lugx;<01e6zɅze(tS#Kۈ篝C@@'1YlFaw1v74ʹX٭7F+_e?rTJcU}~ǎ]cƗ42p՞F[=VPur\=AAU~A_{|;&D #D(P3@&t>.T2IjMT?V) rM`<}퇅u;Lˇ1_9\u|Ճ5TjvReEvSߑs$?`_\\W%ts'Îkd+s{U/#o%a'`5|p+V<V>wnzzZƩgA1Mݲڻ ~>䜷GVUUt/ N^~.Ds_fV"\\R::#gH>?}GtHB [tz׉9gOj9߳2fH(j2IZ3>΋vzٽ+{7]~qsv*6&r17_Z7/ cC鮙}6TOi_cSb`]2Go\~aIyy ƻ'ǟr̺*`*k{ #y8ڬt/A~Z$0gƉm sfŊP VجwUOv }7yO]뭵JG$K=5kf .^a& 8%%u+S/_ 0b+. DG ))l2Lq>OJiO`]ʩ)pCPa{t^jHZH 6;u b'z3?t,ufsFd\zuY.0\?#2@tɽ |2!@ طZ?1\>~:LbDgA$F又N9SQOP;㸆EO#\ 1_?% <$cY_2$VϿk HC~! %)-T_[)ms:`XBAԻ 4bBݴF^d&48L':Mbi['1_J&g|ۭ%hH&x5Lz|B/,ôSsл95$qd cg ߕSuHaNP!T"rbW8(H&i5Mflݢ$piv;;gX QU.(g:G !5#94ݤcJs}+SQYk9TaAG_) Llw$uk+…C%y'5+>X>Z$~͌#o*oxo' tYz͜s0sqN1yO+q.MjoH&1*41**krNu=3Y"qȟո&"]5Da&RtJ-QC_T-4sSb>ȒDllWM6yvەImTPD7l/]!Y>q·zH:Fp57: jJ̻4cON4}̫uHDMzcIk#1Mx2o@d*8s)J@)A&Sj5:5G7%< ϛ7n Y;x*Ȧ BF*qmo\V="dWb9ԌcIc<_+}=B"\c{|̃ a0F ^Qi4V計!ekwoLնvw7Om{}͙3Hn͟3gΜ+1˄1xw&yi})Tpd1H 4L!u lL HD!\2V;0L~rӒaHJ Rj(&!lUKI 7i̼.c'tdՓIwCot{\Fl^496FKCwb&k (嫩=%7YBLM'Ng}ʎ}Y-#Ϊri@O'Pp**"TIQҰ;Dm|2gFOKW$ k'qgY$1BUr5~VZ+TB07ي"\f2_|{ q0*о齓#Xu? :xIO"/ETt&(5U aHO]e_GoS="BQA'[3!4̶D dbf+RQ҃1z,͌egh9B\Ksܪi=l[գg@U$?\pB3~7YY2.(M1}d `۠t<$t<+`0o )@(or[vg>`4YVm2\>C9_X0X?Ae',6* JFbJE;_'*&gI|q1>l%ybC rҥTRђ;t 0_Nsy6l|,67q lٓF+gi΋ P1meViW X&b,~Ѯ3I`!=R]-9# MH()8bS5bepuxBv9v-9N/&rI"/,'_:[%$ΞF6ʕ]8zx5CȣI=zu-]po2F:'K\g I+^*v/u Ysy5Bs 0DDJs+:OhmRBf⚈8{57>M .\UiB2 *jX1"8 }^lyM:A㺴Il~}Zx-@(-?ضbBB3BU4f 8H;IUFtK-~!hEG`"L:]8!q $DXp@ UAI>eOB}]bT&n.>:9\X/[bkV7= BE] ~hw/˫*0MxT#@m/Ó޴Kc< f454XV6~Hoq9 #avaJYfЩcbCE'#O*w9Jy [$.RKy^ #JEĭ#DcbwQp.^~)ڸ\ bQwܪvm¤XQwF72}E͙ƻ"jָ,ȬQL7 E ܑɳb:/;43¬tf u@V|^_tTŌnN=?9 S@me@%Uߌg noשmKgH] (:Ӛp:c,A”c&P¿Jw|j\iYrWNFSPC5Zx"`[\ 1w#xMΧ/Kyϐ ^<3؊d_NlSZy3~%WK^a|-?ի&@j>CXU>/_Ԯtg{!eئז:CaH o';=0,o /K r1bl^p#LFҥ[-& 'g2ܬłi*5VÒ@>t]'Zs4 dPfkT^3*ؙ7{9ĥa̽POb/%t`:a(iYGpy@DףV,㫫y1 O&Kw2o"ҟ Ĕ|B/ dqVb=p156" nznkq-6$f 68&lcWnyS7MLdje (~ؼNL'|F83]B(*̔P4QBaUEqW' Z!E;=v/Ez&_+8}Aj%g:Y&Vٖ)9_̡,&@<_s.yฒyq#I <:vmܵed~PY}4q!5m4s p'~hךʍ&=hͼX[ , {FKWWe7Y´:WY'(>/Xb[/1Fn<zdz JN/E*MqbPW;+(-(W=acpeZo44 >WK2q3eJt;&v.l@@QXVO0}.ca6=ߴ+ij @sV |usI1p.:W;vDS TaaR5%S旕\uPUVq?]xSU.#qmͿ\,SN3"d:t:S,]@Z nAr}3Ygj%/gngIb\(9wXr̾zT0&1ԑ E!t9 s 2 k't O J,UY$BzdNϚЖ.WƗCUs(rrDh3+~ C ͳ IXWR{r3:C<a'e_,Ue[G)!t,ny k4,ݒgy>ms[-^&M bgm1 ԌP%z '~2-ZN&v[OLOݰY`ƫХo,h}SS^: 5/Rk?`Al.ߣ>G:E3o63aBﱙM>ct,FĤY=k PoG(xV$J$7-wd\MRi"5e46~"FWs7GWpueRqހA] `)VHȏ3h0@'RmH9$ z$w[V[OD4sE0Ǩ \ 2<g=+jxyYm܉VbJ4`r1#G[S Os|޳X*EV9 vLV)թݜ`4x<.ml^"kw-fSK;!lsQ撺{3RBBtt7jFM5e%]Bq7!i@ň? ?&XhA|o9l07->ǑunU jnԊAqū*h.!Ĭ:Wy7Zг~U0p G\4AzBnZmvd5x\v/ޮ.!ϓg}f'L?Xހ5,P!=|s&#Jb &,:l7'hr42$WujF?ޒk'܎N|f8Q9d?p)j{~* ^˹ .6ўg6hwyqdQE$ (D.ٕE]eЕ}#˷,CE!L 92Ʉ@%=}TWWWUl7٬' ֱc$p?R޵he"O+lw=@OޣCKLm= ڲhMԪAiT*.Bc؃߱α~Œf]*|cjѳ9d3B[ ?K( ZO}_YҞ@/a)ˇ:hX&HEAcMQdzFKw{J@кp! )fByT`_82ge>v)$ņ&R=DؒdB@ZaNΆp$$S&Wͬ%_[|Pms$84ѡ qQA@+]H!*Rs)A8u ژvB vv/1)|!QQՁ|4f/H1{K465J̩S1Xd3~ٲe+ly&ܴ2mƗ[Z" s;|[т;hIXA򺃇=2pHOP-1RMs aDRI >9A mA%=$b( , \V*UNS娴dRy[~{) Kn$XFw태x=q D9ӓNi`=dbXw]\Cq :|Ut(/'|v?naSp(cW3SY3"/3e8 bn^4HYJz Fa)Nyh?yI@dDD(QƹP wg U Lܼun7~(.MJ*ɶty9 A]Ps$[A{4w!0`,hq#jHƟj ԟO-K[xnoO-^>zULϏ_K]+ J"$&,ebAN^D3m. u~VPpEdp13$W(U_BR-m:W Xow/?^.<\Ez8ÏtHvHCVgeu&reL#ND93~ %#0@@>1! GBr!I]8,`fX0!P#(4=;PW:b,Z#-lh8ࡱ!h'=۠@aͬ.1bտƉJjE_[pp{}q{fz{(C}BMRE+2GayVi/,9 =Oq˜ SAy4fMpU]|\u]V5qʯz t2N4,r -e;` 8ůcs<|\fJJ7/pbLMME4 3hׯ/BT.Ӕ?c)3w35/X4,[/_7Vc02FTΞD3#AF !ˠIhRӯpr r8ڷ6bJBMu{Ո1l1)9bDൡkȆ W1K)ە"R\kG2]5EҞ!YK0-y<@:dAHnZnٗS{ɤQR%HTb+jk}FMF)mr%~ % f8F)\(M1.3}e]IѭA2 QsI{%kɈYnMT*8|Gըe&D>'Iv=,I ޼Cj"^M3#˦E}On#Si_-7ONwMSJ$V_CZq?- SO/ooi``v\P;4:nVZ@ט OHoPO^Jb_w`1z.zܘ!'_X@%?L(e٬z}NzR$9\|2#!@Zб<gF*ǽ{H|y٫0ް +IzA$B16t0;Vfr>iU\>8{+BO1,|>sYݮ/|](QSo(SnVb %,Vύ#ҵ 푑{r(|F¢<a!9"Bhi͏TD`r 3{)0PJth^/.+"B W,.F{,8dVI03hF.#d 0Ȓ"wb0~ۂ0.9}3dKqZ(F`= (=5m]BAT  hWR 8wC|< At=Prq";~`P5WF=Ai/B.ԛz;wn03 0==Y@qݑ\?;x}?wni;]1/|y\i_iiH#wa`fH[߿0z=H3)p݊Mx}Ф`|`fw_CJ"Bad=NpubP5*.=JpYChlF` *T\~8#((p_j]8 +kn-(4gZn2)wr7K ij+ \Ɩ;j!(Fs7*Rs؋qw)e1fpO"+ѝkmG ~/n7xm OO1$!ٿxU R/Dy(#EҢߤ/Lh2iZFfw qx_]nf^ò W+j}mH+",=1n=i!Q HjE88h™N_zh/WO׻ 4}Yw'܇fvsjt0%BU*l֬.!<#/ t4g bkx Mt3̻)t8d8!LģY.mޝݴ8 <366" ;5 WhnyG}&@|B3AW^œ5 RP+OI-l/!c">l99k"wJvo)GtihSu篣u?TGcKf_cP{!hUPB :V}tF;Rp x=-%hqFV8|K{8%MB D(`<; 31ecٲyz-?ǖT:U$gsnIㄈ<ѐCwI:xte(i`&nc V p q}gѰVGj,Vn, u>GrN҆ ycәᜠHPFp  Kӡ)=2'rG\gN\Yfh|̬@oVNFDHSYI*T;U0U˝v\Yv~!=0[TOWMSCY7ɘ|lгn`E6&ggZ bEqСty;&R aA_\ `bEF\(ڙG !b x[%f1)͛Y:FQ͚4Gv8MNynMa؞w6n. *=BYXa.+8+mkA\Qe8v[R} mG',tv3Me8׉eU~:NP}}u܍g=)p!3"y 6^Nbed3,3^?f @Q/& "mm]uo blVSn-);bcq$PG/;K SqwI$A"'HvBCp^X*/G6U@z}wQŷ~l] !A  mUf\gZx<˙ N0^n6vyt赺of *|@f*@ň7@z´^}cλϝiQFA_~ >,& *BC>Ҋňb;K9@_ǵӦA vdXqAg -{7R^[nAn" xPlWKqɸAɕR>N KKXs..k3ȕw#A,X_ D|zzmAcLom?j]~J@`"gܑc.> 'Ў<04]傌VLb1{Nj0t$l?{WEL2AHa$ȑ{"`C!.` fJ0H2jQA*"QY|z>T\UWWD‘I&f絛&Їgϑad$C{r~Fzhs$)YH -ico|NH\8^XB<#]M :d#xH(AŌ߳lD2>aHڥgԝOz+REb>=FT&OȆtD ed@++qhL52dtT[eA .HeTj{h+}Tl_Qeݙ\Ԝl;1(*RAN?TdcHNH5hFĂ-j}m5(2lQ&IIpsit;93gd,k1<&osVI-͡Fkt+@6M¶qێZzz i4Ҁ50wr| CBH=,#1LW0)-'>S@6"jqGA<9nq:-.Epw8zxʻxm7:}c]:=650~h"M_Y2^IeIl`O2{ONjgKR᱇ !vh aD4I%e"˄yD_uohpren ={;guIFip E9e7*{F\!f F3M`Nf8vI-] o_h)~+9B _tq}V`$cC-/r(=Y_I3&Bvv3jo~9C6GvR'T 1dG$An+36D^wɴxGʆѿPV. 239&Ό)yfsNӁ'km{(?G#I2Hvzy n  |!\=RWTKjZU{xrQ5aJ6nzmo$'LytF^<0;zXq{f3vfV<l:XHhiFsHƨ39pZ(_X̼8ԥOzkabAtyV7) 0He{uRaI:dԖ ,TExeE\/gL>C{˞uW{0S"zRQIk\ -* 3Q)0 dV)aZ݆eN{4Gx }VnS.647%%9}~7edw LaftKٟO)|bKžq#)o"aiuT l@ lW=qpY |@-kD/h~9+&_;5? *^VOMYrb}5*ӏ"(h?A:RPi1%wϞ=V{dPV5msɁŗ$6-d %>z,U8\"T8~JR`yr%kwbQ'Nt';%O< ؅BY=h)XBsIc4Έ&)Z5B-K1N$sಭXKadjTgoChN0]kJaOR6>Vi/ezVnPR=vD2RI_{,Bԃejˤ\3Q$t@7,&aU*%VVC&Dgey^̍k>ǽq0 5Jsr˔WeS}JkW z 7ZXS׊a㴣jS%% H;</R,+V eۜe{4Fuj\7++ѱ1v6< ɎI)jacrSud Ŋ>=R{YHSA,m"mEڙ1yeFP=V5LNZs; lQgG7,on|*:"A._7U> /SѠbKT]>Ɵ%띣@|_tJHQlG_xg*|\?;?+)&?QeW_( ('cvX|‰K {5?֏8ݞ%5fp& ՞ulաGp>Oe\N;fcU J]n2zĚ+](:BY U|)Nlѿ1A:)i+T7SJf@P[\r!宂v@w+p9Q;uūF(5\aWĩ/TןP#1C_ zlC>, a . VXTeCoHާzx/f`(2pg_ OU*6\I Ȭђ*dU+fn1Cmuۍ+=Pm;-!m'/R]٭JPWBa,2C⊶CBrH'}8$@!lޓI.S+Uh+Z4(|-ޏtKɾ1\gwEI$ia gUQ}S3x*{v yp1(h "g穢fZFbr6i<hvu;Gps`gHh™B.>abꬔIinsmBqf4eIs+J*M%s )b*=#Mmg ~|_wEMAwib)KXp?U\TXE'xL RdVCV䊾3[m)>ί*n#&x1(b-ݚAp {hQK*[ՍBZLM'gV=fQ?Ȩs>0[ ?M]vVrz7IR}5M=~?ō壕4KeMjhT~K ֬\Zw6myE4xOb4?-eWw]4 m`Ѧ|!i8ZԔCbWʂ4mF GD`:\g^wZ߶fmsydl&=\͇IoMD3}{oc T~٢r?"\Un"yzE9|nu;۱M: k9}x%}N)n2@u%F4d 1ހ`|->OQPgh@RZ#q>j1>P"Wr *뀓S7Ky.N5j! [v?_ Ix柽n2`^xT)Wp}}H{=%+ `30aNMmMͲJ!%dKTYb)( g!>WkT}f4t&3˔%o}kXL=f;87'X]fڬ6<l)wtǙ8%@wu-fGĤ36l?7-Ҫkvur]֩k{ɠ=. .R,JX;({_\nްge4<q߳WbչˏC1EdjTD,k$μAHT R>-y`D=$Z-yoomL5zH Az/֏P߷I8HmH$bmX0,O QMz!ttx 2M4?SO>ժ6Ne/>4FS]MVdZ?o`,k/!WԢᮧDZUFE 3Y} 2~^xr+q TA17TG 6 8#o'HHD$<0(V֭Ś{FHW_=(..ާGbR= tU:ݝ' : K@oWi> "b0hR H4Q29 8 ;,#*s9?$$^{6:='O{u߫G?E7j"7 F/_{e-Wq燍/C b ^C_.e r16Mw]-\.L!WX-[Z}֙Ž0\Ӿ&gJyxZ?X))JrWҌm9HXO>Ng7no=72'!{/? ]8wc*/@o)fj;$X?jj0zlR8 ST0{qosb,+-ԌW5­KfaOv'p,u{|V/QC>jEՆ*j[^v(MՎxU$TQmH&<%̔ڶ se3@4gBg'|@e#hAVi%U ++$p-hoMMs`u(|S`կ$WXAPХSMFahS0_l>  $`LKFۋQ>cmVe`7)E5!AY_8Uh\Rc`of&+'DF;A>y5,ry0<%&qvK4iZ?1wÊĢi$+8tɠjݮ@?&VW*؃ .BlF֣:ՒY6ֱJg8e-G-te6 a(櫦k@1ǙRdz9ZìvO Sl&+.ntc~f(&׷2NW8' '`Gu%*J=`1}SNjۻeYkqus8nBǵpAT;.946s" Aakpi6N~R*~`wGq 72 uV^IMļz6GB)Ê, 4ZX)\O&Qwӣxq`p=HכSgpy)d+ ͣѦ/fU-׏*MQa:X:ʌ,.$PĜ e5Ȭ!A##sb@Sehd8i-f !O!޸Í%evڦOoAypgu|Xx <1PoUc_Mlotl$hm>D?v._vKƔ9~wI` CP]W8$K̳1BDZYE998Y'4//Sر?.Qanv!p \CCkPۀI~ȍ $4iwL;˭@> ,Ϳ?Jl'V96<˦WB5ו!C3o:(wT7^Ku&Qaւ?_!iW&VyV]IJF-3i+ ˟ :/ڢ=}Wf(h@֟>멎Ja?Z10 %H[-騤.H l& $1_/+DRIhH>)L?xd65lJ`*т"Z)D f }A- ZtG`/䊇D!NC^':|H|CdecF=|U0m6ZpKMv%|hZԵ;^d#ȉtaEJ$,IDN 9!/u)ag~z7I.e}jaߓFISNR$zf¹p)2W"!W 'Hux#"hg"TuuґEI 'z\ Lqt|$pZ w0|w3!ym5 )aO)hoL/uy$DڿƻO6B= B; +ƏRRda؄۝jUp-;?ª&K!)4©r ²lX )PaơKL)GX^L FWEk޺|x7D-8U 3~d}}c>-duy:"Q~q}XDcL6=_cWk֤yBl=gYұ6 1|'oN3(jOIGa O2r}w^$c^є˚Ad|IȘL)M`ͥfN6ɲ7l>,V& "Y>8݇Wl̈́ ˖Uc6U Gp 'a1 5 qJ3<HA+ zPU3ϺiЮcwzzĂs:D\u&q5, ZB\K*cS OS |{KoW>>;E&EπuvdFEQ[寲/w 7j ]|H&8QЄ0#"-93Mb5V`d5*7rNKE2N= 2D?x8d 5kXp/#\n@2x6y&a^1杧"`%\>ytR |qJ-5)^Z>?4̶* p|N $ASIV$N#-Üb+1r!?)b@o3ˉyc39O]]]7u 躵00y/;B'V}e;_h?8shμD}pO^z争&{qҩfݒsVkeܖUk ~q\g|.=KJh U7ROg ޢ 죖!08ljbOw 0d0CWF= ̿ZMNbFpQY&9F J R)( l?2i8?(:ǝ@HC^wLLkT(%|9gKz;.xñogaU:7E [mʇPs#Joˑ\H& e7*e.u==] |TŹI ȓ$=JlRDh,V#.$6+B'ԋZ(*_JxGQJsg朙=l잝3sf{g9d 72b B,+ |)=2:HV&M\wWP;8~ n)0ˍ^2W8Ƥ@Wh&ep0pFTgiؿ̫GUoڳߔ^p@%x+$Ig${7IR$_/Mn3T BUުP6Wj%'6}P]U+ӷu\UC*܁\:pSw\j:.SJHjP[&mN+aeV"SNI^X|-4 A_gvT#֡B,I\}]īdR}xg^9a|-i2`MQ b%pMu#oAwߨ8 Lxd&Σ>EYHRCWXޥAj|^+8Xd :ݐ/7HtF 5'ZT_w5N+w6IiM8DsFTd=p7l%{H- {`Qsq|JQkU*LH#yOɜu,}86+%K$hx'8021oŶ K:o h(ÿmU3J=U(qu Foj>˸\4gP$w%z?g!^¯H8Ŕ7e_+ax|rp3Ox,7~!8f[ v0AmEdprqҚ1h/=id&̋STAҭ֧?:z# :D Vx֫m[b(F1)1̩¢,5>̩drRoS!i):I&f/=1 ) f6Du҂PR Li  s^\V I8T*|˭>(}&g^1 >:R|"= UMۂ yQ?96``ݘk9/ '&r(`I!bJɒa W˝++Ow"\&Zbq/([z`ePܐbְ>)'@d#GG 3R0vm||* p.kDX< ֭n m0 Y,9|V{dEX {[h &OtO3ofiVL2wfj ,MmzUUCD#ؑ5ؑM6DlMINW>+Шx ipsHWأt;0QԳKv@GFO;_05k*L(FuZmy,C/x6*ǎf[~P6MwvC`G%é-S_:DuM*w=^fp-M߰:Ʈcx}2͢zZA)1XYX1μMKO*a& 'ݡfuGIss(x0i?{6"& 7s!:V~#eb'.:619qmo$:mZFx<~+>1y*鬲9f볻>ǎʼnݝ::#wzQp :_Q֓STq M a-wUHZ JyH*Cdb )8ũ.ŕ,Z@+z7W,1ULݰ\IL{}'H6bi!Ti>$}xa'ӇxrHb0>%ckf-ǂKIvpy*qmݰhqم3 hrkIQ{N\y2 )*zs /7g2~P=R8Q;q"!c^ Z\6SUU-pXfF?Ya_[C2o[ٲh%n;L0Cێ3w4q<5ߌx͕l15\K?`E_DTy}N]*{k#ELss~oLƽUci)ŋwuj〻F 6Lg${ DzSbzT3z^Tn;}6O!u^"gZ]%0j $sJK^LqΆ`׌$ HtZ+W*4z{90L誋Gl;~Byv|K0*Cͱ>!f( <,Yl!0ꕝΗ!N>cѺwzRY>+iڈ3=(虓Oqt' u`b88laN>qCSI)1;87d20a-H!4!?Uɪ"60 ALERm^Ā*9u_h7fWt'̱\!k~w{+ff7}s ᑢQ/kBP@U/Dͨs'f%mN:,F siR&hŧFhz-]b7oABx=U,vˎ6벛=NkwT'F>!6s9ÁLL޿03)`;[h~X<ROK fz6Tރ=焴!$ZS+ɾMYkmuЯ^ _"^0/am,T>KDgsV ŀXeFB;uD`sk oKV/dւOP-/AyLM>^iY:dZ!DžQ~pWB"S[A.S7^(/-c U}:n~$K~M]l;qAdVިDqi"J75\jظqq&͗^I+\~g-׌bo3^}r=:H5HZU&D ٷ`'jKu]!/↤ fQAJdZ%췎;$*rOjN \= eB*TI[iW8IE?ăFj ]Zg5U }bKUDcyJr}׸T5 2JG1oM/W?7W&nkc-)$J>#~t-bN1itN{vL~8q` ́[ K I%9-i.2/Xg#ND.wWo*C]4sdz<^{@9wiAp"\&8t5~w W* y}(F1񪺖㵨CL%h1L;M I7_ys*ѧBGݝo:eGv_n⯍Uw]V eW$QTitiDV:$$rTGD:GP$HCH  r,0#+HpQ@P!^U>rATWWt0ڇ;J 6:jG$*@TJ++D9WRm񯦣rxe D[gxuӳ^;KH7R4%\I妻Hbi),`KKμS gZi t &zS"@xJnO[p^[Ve+.m޻6l~Z6 L\ؕLB%>jMi9w}CG_$)_)~q$D "qȥx`'&O<$} GW%&m^L;]Ʋc^i Ʋ/.&Wstu,KEc;HЍ2Yhd^E|[6wN_m%>Ȇ9ap3J_1ⳐKU  z1e {,;.7#^ƳMolӽ6]ػ@'yQ9aځ6t\Ͷ52F](_㟵6vE|-Gt2y{s|t- )-(z$i1h!6J G@D\n燢z;!,v\|*+ :W‡ua'[lw08IuE >p$F,L]iha;tLRYQoDbI0O$>W<]K@>z՝MS{'[6!1;f_tgŭVoRt-BVfܟ#nbDuNZV6NR<t{F CSv6r;~|"6ra\హBNVOf5: [jFtu7W VBf gI2t~L KE7mO4f8cQi~lǭ, ~TNTp y_D,AĤt;4j-pGIĎhj 3;R 'CiލZxuûR&QjɌL9g1dz,:d:*{=m/#p2^ϧy̅k'+s YVW>+Z Tc؂?)DVwYt.s\RGweo'nA1Y0^n@ BX%^J'.LV?+lu2jҪi TH΅A[Ѹ|PFu%r7uK1œ|'Ͳ!Ȫc%:0|݀Y3eӞB*M|9nnj\d -B%Qݔ@.V6A5)tmkCr1RXMjWcf MF[:\ZSWWorUrW R}T}KȉK"'œtN;3dN<1p4aJ .gB&;։41}GEpH8O4jAd]N[W]Dm"[6aާI_!!)n$=StڇD$AI-:&P"`2{0O])4. u_||}6!C&Lpv=VwegW.lh7~_;E]B Lk> )rVH?P/?*Nᝑ $ D.®El36QRْ-2WJ ߓL0ixy+چ@(ml[6o"q[LO)MDZCґWD<@,E0$-ĎZAtKRrKR3M?!qq&:{ H#HY^w6xr@$BS H!! ^ mЖűHuOA)9 IхIT$ΜN浽?ŧjHR@`.9a0"bӨQcOP)-e6^5ond55T fv"YBv^ŝq7Vte3e2 /mÏguCZ8P_^E BqoiU!piuOHÉZrkʎ K9('TZ?{YA.hKzqXH؊ 0mN:_u.[]ڒG#i@9ƒV2XIqNC FJ%M)B c}.?B!&DXJsDQ#A$yL:u6b58nkVGS#]/P^zE@.#ޫ ŷSl\'A=,aH8R=hk3r]!s8Cf{bZjwleXrI ڱZF}׆|gxm"\9RHd#jOMT,Fj*Paަ MUΦ:hu6b3bOs{({ J1^?]Y}ƍ{"LNh%w 4y;;#[:k?zumDS#p-b6 0c՘=BP?F'Sh%P#Ŭ!1oFa*0ӋbQ_+NQS-T{ o3߳E1%( E :A\դ^!DmucQ%Ypds_W!a23!#Y.b(:?f. p?B6p↨ BF{kw xU3n}%+ath1{ 6ߑ~5n\ H߼a5*pH)/_:< p6G3Rp.M7+_&H}coouϕO>z@wW+jvS|ꈄOb⁆HQ-ZJJHN&Lø{7S^85hT:FQ VXFH)˄[D)e$`<.:AU7 Ѭ4`3-V=ⷯ~Pbk?*SP\}a^ tL&鸉>*<.ZPb@:0tΐ2Wߥf ֒¡G?Xq(פ+596j9QK<5᝴iwc.U!(){ -haXF׉hŝ =rp>E?P=bjh`emmZpHFYBYaF "O?(mPwl`r-vlўa`2tcYzW`bAψ~y?پ'TǾLJ,(!J +[gɮ *9P$S? [l%#1x֋0EW=ShV1^7}A/tJKe,!!Ij>S ׆%ol?i|)aK=@NS߯ @, ׷Q^eKxfIԞ̛ߏ7~xpe&kS(-Ca_TPL8æ}Fy$I4Kdޱ\2>+)g"\>fYGEGgK}3\7Mkȇ F̝>` 7]REh C^0l21*7x!]HUMNsoGEfu9׏kvHi)+WK*"tJq2+2}g HLoٻ(,}WGH U]Hph',oHwU7\‚&a!BGA1#*DvU :~VVBR{ﭪ$+z{[u=sz''5BC!7-ENr!tu{ix!n3f$eSGg#BW9+g`bV<4I \F]kpx(vSv]TɔjUT<:nj2ZQ~ b/(˕rD]K\k䚥/Xfqr3l3/C8M8tH&CtF`ң.=#vK䖈gׅ!?$gC~p, Hح9t/VztWď>~ij+[<ѪF?lʹK K}p7yRo4 @;qIQmԷ (b@typC ~"J wwYE'3{t?GP rp(e񿉏(arr;Wy7zK+`_y|35HXXS"2[8;D:,7(r+Gj#OG{O4qyh3zTųDGƩulqM7m䈳@t'xyB(8.wzP[,;=:kwN R?Zj}9]hwћX-\}/ZOד,V%\tdQQOWus[3GXb_t1[b]bH.WK<#?g Ŷ+W]%ί)>,O}`ϟFŞ9#KSE Q҃;i 4'n;'[W23ǟVVf4Vk QXR_KvuɎgΥѳޤq9}tfw A݅u}/X'3]4sO}#Z:G*-Z p0؊і0AٌqM9%?LG;CnfA`4AX}ψ&'MF!'{? ,ѹgdiŢGU<ߞo#6k"X^wյᬥ?nPyIͯm^UhN0I OpVQ}QGU%j6e,cz56ļލ8͹WްS,Wـ}9iA>Xش_+h~qqD2v;"66f{ͯ,A]sY桟N^ tJ Tznز-CoP6"ʘbwvbμcq3onP 9as"ڋt <& /D|&tΕ%}姞IuTvժ^(ky fw2~qU(3ӧ)2C&Solo7a>UMuQ-ƀ{7n]:MR.nKs=u7Dg "? m70 HL$eᔺIh$Wę\+ԙ[GchеV(#ug+6R^ji2v[D +D &b?y҃8oˎtC4l [q9 7'Bx0%R_O?|*G@ }͗bJ!2*lwk@^?x`cLǙK˸i2JvJ_)IۜZY38'Oe۸_%|&Ghc+EueH٘ϓZG&+\pH'g@h2rAR,NJxA9yjwGT3 }"ZkVbGF􅽰]9O R,rkijOՠW뜕2P s"P`y>F@z^n5St_OAwpjCw!~ǮO\_meXP9t y>0 lo :j e>}iVMekXrq^_ B_Āe$xB+ԝgf?{B=_-7i3aVaa 0ZMPͅis &Hzc?X\g7B96^܃ O!{I<*3jU0 q涁&*P%6sƘ!G;+04wיar3\ڥAGxy@}۴^r';oFm&r`ӤÍFi>* T]{"viT^ڨ#l.&'O :TO V Pq4G!/]3_~g+xs.8S`~Qp\Pb]tЭ;{pfO V5Ϡzvy'NO_bck~6֍z\AT_ɕkKEMB=6OK}Ǩ= sH>IYv_:8}L=sY:ZʟXٔ[х,$ZXU^NUiG>̈́%3MVx;S,"];ehZް 4B 6#п)9A!/1|i$ ~NQE!?)ܫ(Pq?/:` /:E.Gn$͊^n"dA u?"Hk.eggfU}eN6L841Ng=) ,Eu1Nߔug>ԛ +׋yUObc֚av?:]hhcgRE`ki#WϾnip99Z|VH6o gAk,YEVexZI a|҃ؠ=^'+In?/pp:\+uѭ?N!('B)Wزi$ eֻC^Qaʙ{5 4g4ؗR5Hzx_،e][*M)Ͽݲ^K*oZMТu} *ty%6J)iėy8sq.5߆m•p:7j7 GXl'D)h[:? M.p{xKoANus=F_>SLt$PJ<Օ`=RS: @y6Ė֘+)"Iml)L\:uan`kbVXԠd V=MH3"MI5U'M^'!rj؛62)FXW$rTP0Q.ul#[~5>yU[Z% 1H/GNJzS<> b~8 DW@` 9X_ eyg ?g!z,ymN* X]K?)ƲW7m~Kg;c&QWZqҰLqbw<[߮S)JS܄Yc_Q֧~Owns'DE#"ދX$WYPa j;IJT/!LŔ`iVi-Ҁn;|ơ3ٷ/z[bFjʊ;o 9㇜jSjǏi_½=q_má%ux,Ƞ[Yt>qN9_x.؝?qp=*a.r*"rrnb%z4/Nۂe<Sb[OJkNw5X< Tk) )t }uL-Gu#g9eiR 9\7tR9?`V 1c:NI,`f;kEK˒-}o<'o,T`-tSTQYsqQA zXtng#B~Ɋ"φX6N Xϱ P/&+ځ1_f yEO7VAڨՑ+*mUe-WWt2ڨ^ϸ4"3N~1xTVbI|G+M[9⛰oc`ƽ򤫜KnI=r*JvE[ %Cg$@c^"4D~#^M_DH fvNm?X9J<|lF0LQ:]R7~rv-ʻ/6]5#V3IVչAu  7;]/{OE^%J'YBR[WwYf zDR|(Fufg|G<(QQu` U%$B{u}wwR_+[gM͙&(Bk{ Ns$ ~_eg^jta2o+؛Y_;¼>^ޑ ɘď&5;']aif"LS҅ivE_+ UdYz(sEf4Ƚ&_i jȹ[Icw~`~D>.eIZ%{Ze&j:o"{Xߘ [ݖLO9qr8_}̧ƘWzhk_ Q.rT8u;,0a%͟U<>V눸!b_dP-\RCxNJvѧ ؞vd_* F/{6zOm]Nn;.øl 3<>=ceO.ЬN3R=nIU#ʪŭ7'BζC7՞z*6SLmyD|}`{/ e2Vtڦk7Oh_> SLP:O2#SVg?I2gYOdd/8E/U\sx TilMyN.9꒦$#. ?"b+ A 7W2 S ~h5[Q;w뱣+Bq}.WϙH?w~-}MDI}$/SvB@8u>yO(Yɕ%`sbi1D9fXFGA p[uO8ѾWuȬ] NwNc;{ G;2!JYtQ$>?JnB]";]FF$jg}'w%<^x@v̆܎ε0BBl$.69߾ sp9E?VVB/|%RWM#cp?- V_XV덌2CQ8BR !ZE#UTq}-5>; dzkD2tB p>Iv\Pt{!VpI {xVBɔYf%!Kr޽z P޴?v/ý t붋z), A!p6gmM?\a88MGȽL|iWw,&Z|>K1A Me7'BYn69֗/|)]_ 2&(PE jFEks&_Q=ϝm<^1;Nޢcᤩ83,r$e Z?qqNbŠ(K8]X?b+}W/ֿ n6%h }ۯHqer 9݁`Nc^ WC")p.HKVCN*f}5kcKS |ܰ^ܼ\cʤjǿK;d;vmMYism9W/~#4+4s(AXzf(P޶5jv}, 37^HyTfp8wk~LH8Ev"=CCLXzǯS"Pӎ~4=Vvj(sA5Qw4K hIϜBDeM9k-lg燵С -Ȍ8GE7%(f@L[Fd)2~&zLӰnkmyЌE3\Q l zl@}+OL25@d1?FZ&]^Um!e ^"gjf^h}d ԏL"#}tRb`.&h0 X)y苫R*&RH1Ԥ @`5ffXThQɟ! e֕NO NqJH򯀡#PC,N מNKZV³hDVt)a/=ۑ dg?]QJ`6rGn0C0+JIW2#T{Ԅۏފ\ 1@@ 8d]AY9/Yω>ZISCR++V(oIϭ"AQ96MBap%d,T0 UeFg="J !$K$-S&E8H.`GW!V3t2<`IojE#\aka:PTǭv- PIr̸lq♧3D= _$Ps6Rd"G|l#ۋ 5y6M4`dw\fX@STo$=G{<8KQ֠:3OTw/+&5_ HWq=]=ąh>"'nV`][pK>^iNDϱb*Kq!4=P)SnߺrZv]õz Q@s7rQK"1f\'VҶV?,Q b%][ĨY]n7Yn|01 ά:h 0}ƷQW&#$f~?y Z},h,T?>̍g M.=%ٌ7\F->҃)]9 q;h8=XҬ9LFfuO 1_b΀s~\? IͳB%І/&tvfOYYE'aeeA[F2lٷ x1ez5ph_.h7C[m {F vSoU!Z}g^J~TӜfrgAYy[s OyX1ca)rય*!V>Y3t$«f?W1@x\2*J:^_: &V1Zt΍"_w)ցᇈkaYcnϞ>{`\Z=AP6l5Ա=z#ۀYE$2xТkrF$< f,(^ހz2 8p D:cKR!Cpn-1ߕi4c*dx` eu <&JvdoyHGxO&f{oLL2Eg/"Tⵖ+**'pg堡jE>u&xB&GV#+>e/xLx6s#:}~3XTِd[{882#lZ}{+ʧ>ET>m>6 9=55'e¸su/8]Hy/Ag_@`75ؑ_xŏw8TFSMeUp +H,{TLjmfnڜ|\S0U8Xc?ơu0rӊs[Fo~ŏ0Agy70 r -\H)ґ0nRSHo_jVuF]m}qo 1aD+~&Zc 4 6JTq)C|28E|JvG&7OI:|JpMR%UOL3d\mm" X#X}]!p{ kUR5!Д4pN- M< ڷHv!}M9cL1YW((zdN=( NG8E &c1/.* wU[&}ŭ r+)kO=٣z[JڡJkXZR9 (>m-) ,JNU-uhB-A PE_W5i\MpcUaޣE?F8ܤSmy\/iԬ=&f}%Kv۵NwR0 ۑ b?HKʼy?93 WJ3Ð8?; hCd%)Qә&YI0u¡(Tj\+p#YL"k%`2`Q6-z| EJLq9l[0Zzk"|ոۗjW;u>kei9`TC>wV̫?8`\].5{pmDX<3و@Hj f '!,BDBY•GH"`5@Z_R-WjmBZW^P&$sf+Y 'yb-.k,=@'SF< hPH$x{(m]{{zO$h/Vj4z~ f @=_eJNl[E'*ogaLuzt\Xl~ўJ#+5}4Y),K# Q9& g=_6rΠVSx翉K4@?jݻ{$e6^sdR~2:Q6N:;L :7O&o@H47 &,ٓoxe;]Kl¨Cp07ǿ;ft-z?`*a^&`.aȔ|?S9㝫07\.+v'{!*t61UV>֔ɓ;O`% Ag@.KFWCAO$ָE`zgFy,+doy!b]*ͫ#W쾀3۝vcmN쩍jOg,*/zx;&2}dH4QńiF[ ,うP S?9+}#X (BI֨#00U系6^mgk=Yl04{z kvVߟLq?e- TefMkQffbHKC:Hr[D;Jm?.M ^\$O-{8EJ,>e]o=}>dVX!^2Ʊs^GgNljNx O0 00^_d"Ή}Xb2nX [%PE^Y(T zamz;p_>Gdj!K~s:⥏^ovB9BK5%_q=z4*n"U+Cnapxǐ"=R#@pX1[d>7hoTWg־ ~~Mk@ykާxl?EI+]^9 `=kIFS;&u0P0hf q>*4f;{V{qr{7)c쩥}QIc:3*̠NAӐ4!Y,‡4sFdCSN"-Uj^=nJ V_sPe ޹9zdP3届 "/ yjպ`UL])!E(˄-Ҳ"$QBKdw;J ʎn8*A ^/^f~ҷz/.Q6ɢ)B!2=y? `i{" rϺٹ/J3 I64XZN$5u(-#ӫ#TkJ-dHPV22'!AUYs /+;/ÇJ=:EY@x-~FT9(H=9%ώt $D$DvX]y{[50ػ>T?KV8?WR GϝT~29#5ei18/-i컨#ZEz'g견%kIц"T¾ZgCݠ27aQ[s3:0`,EBGQڄ`&w8'҄@#ݗ+nzrJ˩nHu,{l=ȇpM!Ư:/ YڏFB1 y5=FPl֖ 0-mk'I Gх# S`sŮ i߳_}E- -"g&ֲfdL)ƚL%. r aU6%HCBVQh F A[cN-$|'سw:`!)âF8fIF=~HǨ>cge |VOr؝Vo9]Nc-.J8fVwS@ nȵqt"um/pJVY*w%[G C&Bnl ApeЛ 338ǔdHBfTOVj(;"tѦfϵw\*,Ma'&È,m />8!zitUR{qt'D8@tLzWv=%ŌN:jx]S׀{Ie`#ڕ|]r,L]zNw[i&6&#¥²)_Q~dDzM =  9-NSU¾5v:&هl3$%jo%3$ bdld3$1e%NsdjQ9A2\':P]/Y&cY?F/|p٨%w-8dA w@R2I-$U1I}36(H*YfwM m-#9rfVkEPAxlMS8>Ek!ƣ@3EIoRP( :]v+^X|stlx-)zUFY @QQ J unNAA؎쑭s@#1GD,;Yj\Ukͪ%tE5 f+KPܧ)T빇DWCxB(r*GiT[1f)I}' d t$(+g_&3),"D80>q*Pg:0 Z%Dwaz>Cg/ qXM\ ?ӏ34q v"Wޠ`'쒒&%o*Ƒ0"L]š_e!3 ¯LWG9vSL =Bv}}7Rb'zbh 0R6*4s<]w's gCmbH^C̯.(J0yT%&n63`ux/cTbte:R,'h7Fd'Ȱ q2.]A+읚C'm:Qcd OkG_+ 9~F#y8/ e>tM2X Yn[b n&Tp3B %45QZEm`e"# +SV2Y%$@Y)EYc!@C79(}.<0*^tȣ/H[wCлڲ*$M¡ b7 < =?Y~[cv9U^$M T˭ Z`ty 5 [XK a &EW}ni-\ W Jj -,,*\ \PPGaOP)!r5vC4R6 %hK̾ oȵ D3$= _40/yдvMZ# Zf?j'-[T8#‚уիWF g&pW (Ak<lN,~`~ovbY4E@n鰦?o\Tq$ǜz<"RtZE*ڔ*p#tGxiW7fqsTpZcčXS*mp쀙G of23 ! ـ,/i&"Dbf B*`R[[_PP(p b+qKUBwg# !is>sgyQJci%y-;GiWߡ!?vhaFGg̫MGJӍ?"n)!wG+)%M#ih/B3eUUVҲWTCxMh;"_\ׄgj|u_KW@4B# +5U&̌ũ5ep - -t9ö SLZS&=}딫:v+!(h4f|aX䩻1A\:aY1uEU9R-}vb]UA֝tA??]~ExBt~(D! o@)ᔍi8šm'*ŘDMot GQP&qR)&|,!r)~HM!.դ`eR[0SU0D$hjB '3B?l;#Y;$mBe%\{5G5u3۷Zсh[3>A1TTU ^|4B' s[A(Knd Ї};%~[#hw/r~Rl~'ݠ'饯xx!b~Hg@5xKS{c揜.;{AKNol̥+k1 _7Id~O-MuHprlkVo';J~e)ㇻM[aK`/9wUSKX/oXZ 'J?D]~8U+ɘqʏ"3Eg"2KHu -2+ 'Cł'(|tr8Rr=> AbdM| ǘ<Ǘcf,%ۣ >bm"[7ċQUH# }qVmPrv,K'?B,[B={&x]ځv_tvКL#}$9=8r,seґ6B }V@Jj9)&0WF|=* Q I%.KloJiA|zΔSG< Ar$yMQo瓣<%ԔB# .%s;].K! ǎG&]/EĜ<-Uv⃲B_ҥTpad]\kuvO"UTsMW\/_fZY{ݸY2Iۋsbg|Sg Pt}Jڝ"ݴ[k&:` FXF(S^('U)tK-C뗏x/ z(85#6.-iC]foybDV2P.x>%qY\x?PuuxGɷ L"d /q+^u;8J>tm,>Mi0fƦ9\7|Eo2}5, =t|׶fZ(ޕ=e O˵xEsI1$]`h%;r̠#&OZF dF˃'Q+kO7Ke}(q?` /u *0r2, I(lЂC?\LKƏssBrC 2*sX$cÌu3w^< A{87H]uW)km.8i+Y>C8r&x%̋}TI= @A#2"g_F Hnz.:䦫 N:HKD-"Պ'0ҹ Y|*cG-mhGt@:NvRL(akkpI!bѧ`]Е^[LpxsMΧ"+Iƥ/.yի$TgmZ8NP7 1"X@T&Z`u"'7W^+Q&^}/`=ڦy^Q_XA} /,HEȭUО:R\=n g :noӱmt8+xD\6at0AzDQHRѳ PHI!LTopAiUa vzh5u&g0:ݝ A7Fu `Z9_;0P@*C26O~#?@BLzd0]y3t㎕q4Ф|n^vnwgw&FV= =$|H㴶ENU-:7TCa0p _ZSn˪|&mv{zѣNqt])so%D/[Q >#]?.bZG|@MH)+:'r7oUM7 _m+c 0%R'ט?-q Noi>=Ш_I8/GZFG9Ӛ Fb:Zf1zMFh4nV9=Iu&)!w]$o[".FәUw#ETP/#ʒ8i$J@nzyߎ AE kBTj]M%H(I \@9.˴4<#TH;ŋ$OG.+\FjJ3S޹eBf4TʘPӓpD}\d v8c&Ŏ(2ӱZ#EГu XڍUҬcI3Bpm!Y:PB{~h+"kP\񛼶)!gFŕÅq_g5{Vϣ3\l|&m6|ZY}>_OLKgF p%q~p2 (Y1GRH x xo2ETX!Nc D4+Sc{*LU i\L 5=- 5 f]R̳C'uH4זXw`%x1=nβ5ܸke⹏m/xtW;B{m TSsM\A;9XvtEF˧ػʆ77]yӟY;:/؀ߴ,w _7|Ne;L+H2x6ţwNōgg4;=nOpBcx 0ς3x*1u ==d:&E`keR w#lǶTfEJc !$G?c9^$5pC|T_ߍ ]>`W &h^ǿuզF9RkUj&jpTsvLL0zn~JGZQۚpʁ{y(hWHh;zpM7M4 * S,qp%}A* :'dSdjJ(KҠ_$$Uv1zMK,>iۜze0:x':#o@G߶ Jz y*)97hß k@㬾 *1 :sOҿ[ Tc?z#6zHxvI0afy$/߄!U% ܥ<МV-"&7ie}e#Ii&s+H n i\=%Mj63naOw' L3=Z|ܘ=h N?U3TnF|BͫFWgqYl{^i6{]N֥z'봖o" cdh$}\t̴-GED͏'JhiP̓ghM@KG3XN>u܉hFC$JD@8@> S7myOYnV4Hly-@rCa 7A.jxM` xU9 .ǠzX/2cTw"[cp 04^Wmͩ,B1)ӷjL' +_o85F ZtWAT.Yt] #NXIfowsuq9MiBfFqxc{L~Ad"F銡$8Z, 6"@p%ueL֒\p *@ uWoA}I_^/xl~$is :}<0_RZ3?L6`Z=V?ԆOdw̬vc-7K;ӻVj. 0A=GBgD4ԡ=RQj1rF^ A^<$0p@ d%&C/̟;VK(9tDА w8 }N)HUx*N{RgH^c_Gzw1Oj/ZzeuC vI e`pYmǚ 9Pac\9P?{Ixq2 z}Yn ^g>(vK%>FqƖw 6.*qw«䪺L>6=_|zeբ.p97=V#XvԨ$<8OX9/zQ u(d~e(/W~^5m:L&Ok ÀUY1\ ~Kk@`q ւp@G~i AtKqNGm1%/G_ (`[1?ȥ{t/X} 3JM;LBY}AJOfXˌ=6b'i@] &3*ƺy7d$wΎ1R^\KEͼF ,Fl0m>؋Tc-'=$&}4wb8q rؘQZ[脼&,la@GŃ_2;#td, Ļn3tI*S[)"^`}0,IN$<'AgsJpqB3q$ȥmX.Ͼ9t)#7_xa$Uͤ]CՑ>[L0`fC[d`.ŁJDa-D9J/QbyюBc"ym;d\4>۵u>,IY={.-ʸ"gV3YR_ 11zpgAԲ'ssѳ$/v - j n@?̇M1? w_tP\Vq8n86=3Ro'7jS33z }/m c@X&2dSL@w }htWYFr e -n~9Hݾ޾{ : !+b 8XJ> e)N.\#)c;t Py]b,ƖxNzc&P+̠}ko&~3Dfz В({#m.<S}-"? *& )X..n :9_?AMfPUmxl˖-lTcMMZF w'lRc55Hl3{KF!h391ME2Y*)z,Er M>eZ~EHYj[f"/SfJ4l=/ajFų)9+LN^թZ5bee;:E5δyRDP$IYtS4 丠z}|EbŦ=)Mttur`*, ZAT45lfvQ'7+lʔ9 OqBP9O-۫5{0ۀr-_ ˧4~?$TY⼜(Y$;8TĀ1?? ?vWT/_CKRHX-%_?65^<ꥨMXUX4x#rL'E:Ug,><;*b$wTmQC ;bӰSoE?G 6d8 NLJM ` 4Vm<_1x%Kl88<F[ib7|] $?:x9(H`^p>3Ѝ 1_N FdYB e&^jvmB$":pؙ s\&~n0[C r"*t݉u/R;3/>Wo'-wvtE$*d/4@5VK@nNK78BE_k5c~<&MGR)M ǵ&Bxr)gXt_'^tVek׏Afާgz}@ź#Pu[8f0a~} :P`@3rA%pV06"g Ճ  &[^Xdb)ι̞ O!TRAQ*h=D \^71pfkI;4hKP6Iv~N=I}1 녷T\{+Џ!n 8&}#ہwWZ.cc$ VU{;- j]S ܳѮ!#öq#I# \PU_Amf<`d!$=j 20SVBp!BOP y,Nbnhj}n40N#3@I W,Mf'Y08~t؍aW<<(󋨷c}v-Z>;7< ~vw4v!H#sIs]2KG«5/|ѫfūmj R4D(.>(KR@b]"$9(#ya$ic5=AiЕAcwɓa4*,Dnݮz,!{+HN$V74aJrJ?0iI"vYK!ij 4f}]pM؎vW~1FnqbzoNfbkXP*Y^etw[]aP2z";-JArS/;3eiJ;zk\PN:be?7`OVY '0iu|n ܭjJXC$)hE6ϝ7DڀL%w1[әt3)"J>ū.sX; y;"׍Colz#?r~b#}mj\}բpuFųZ0\rlӗxdT؄ԉut̃nD6kzB7b)D3amL*PKؙ&=B-11z@ɣCEqi &!mo5WgֳPOoBnx#ZZ8bv{sZj6 \x}`RN4pE4<=nI4m~R+JF>Q^[T4䨨x~X/x0(9},uD|{"~C&dN%^YhD'雁Dk:Nbl ?Kyau/]C?B~줁VZLҲ㈽|(y=sU?5fyxw 8rmHAckb)qNсQڭǩTqm~2n6qm=ͮu !D0l`_uz+soE=s^F ZQa(!`֓֜~^{Z/ɮ+lu,$;>ܙ2frlLdU%-S:*S׸bԔ(!hJ'q,Uܑ}/AƉFh:gZJhLYwiiM^cZΩNΠu[#Kl4=: n?_ߴ{fkW]c.Ndu皙pLɄt, vp u XlYpٻ(42$eV;.đ(h&]U]KR( QfG:*cQftwxd5#c#$ԾW룺;4:ޫUYDbh!#Iq@+6̐+( 2O s ]ߌ=Ww( +u%xh[=<u@˗A\>'Է:!7qߏ^v}Jkv 0B= BdT،0{[tu6`c6f`&<'[HJC 0+HQ$4GRd( tV?4mrBl5x/1ļbepZz֌Ⲻ0c\%e$r3ƣ KrA{뮵!*w h'RCEB̏崢_E@Zs7?xbDfAFV4ȃ`.8KGTŪs763tvM3q~ݺLv L@=e}s_g`GV[Jgg5ц*'x}&[54$+9D= 9e~_)V&o=ޚ ?MJ^HRH/P6\?Q_3 h5)!5!^MJ ӂiE߉VcLMiEFwDŠ_x .{^d"Zɡ˲fp~l EfV}0#?dP%.z}%藺yA:T[LP 2XDޒB+vt[o1oYjF)1 Co4*6M[?fO D[vwiao}p0L#$bLp#:dQ|,mbt. 'Yy׺Š%X T*f=<ٴx-wSC Pg9R惜(D(Ea%12):I sAiiOo=e1go]3]Kl!v=G` Qـ7a[i2_5Xt:u䡘0@S<=]p;Z8AOr֠sA=o=@gmkXhN<=H2 6\k#QaUwms4w,A 5!+%f1F)Z7|>oFD0I-?g=ɳ{ NQPVWl`GMG_`XOecɹ9 _܋\)̂y)*&Kfmig-'IV)˔8KbX A1DQ"2)pB"Ai qR6?ƦIQl~ #̝96c"QcP~n+r|)i?rᆊ 5Na`r卪$N_qƭ(|}yc Đuz]|YսЉoj27Gf!0~ymx{{ A,:b랩<}ߺq䕉bLJ5mV.()u4^h+x5 {[T}PBUG&2gN$›6 )ҫL>9~C$y(lhFA3s]qѣ&HDhh_2NVn;7)ua̋ҏ4bI6bs^ > `K't8 &شMg747-xٜ 0z&[fe%~H{$'YL*I |'egBL$DsrF]OʆQlbOh=tb *,#J ls!B V#I}]?94Ie 1߈4; UG\h7 yf%?}ɢVlnF$!QҐ)7,>k(Pd7o9߻wUU~Tu9}l'O0+ ,)T\)O ( 8ZO^:,.j+1nfV'X_ץ[p.|q[{ۅgBq|:49C 0=ZX6^8 5[\gqp-Ye/본#%GMۘ&m02`@V?eI$Z^W',Zq9I*N#f,-,&0A)o>nV)}E9>QP"<#HTv{-&,SKc|Qo!l.(cFdtOZNq -cW+zHN'JR?\:N!Nt~.v$Rd[vW%oHnwt/_G9ۑ#S};ʷv%19Ȝ1N }o qN! qN2ͷuⷂ<ٰfꇅ~j ݛތQΛ;^tLPm}K$E`|١5f1 O18u`L"?wڂ)[МSg,P"aQT<:pHɠ̉TP3^̪706O>oJVz(-q]u:QLh:Diz!:ǮQ2" }CwC٣/^^v8LՈl>ȟ/B"QHHDJ20"ÉٴhON첯tU2dXeE`'s܍]NU]RYiݗ-ws;Vȉ2mFO:Z Sh7 Z泝\Ӱ)EY .?^oh@7OH\t嘁K0VT2 :~퇹20v8IRNES߿"NxGy: mKޙ{pCt%︃8>Ē^۝BJ<]yK!Gv! /&<]E bbIUuead|A,9Hۀ oВ?X񈨝gq7NRdg?<AayH6G(ZI&2B*!9²<#p,%a )?y:+'ۀ~$`3P yf 2Kt"/`$R9 )k6jb2N=Y'eE&`Oitf|)#}ansX$t;LOHFeQ]sDwW'f}#I!Iy:02+r8 i* !b/d ei%o;;ͽ](eR.ო'b g41PB8qGN(aRwBdT|cG6g,ZiOAi?geUJ3\J?T M$bV "fh.ۓHhiѩz<TaV=ӽ1X*X*Q'u֜2_kbyQlFHGZ &?Gn0IJu޶J9y6:E#aCa3 ɛS&I[ wWQiR x+\OݬMG*hxL-y1z"p rEvuĥ#;@/Aŧ1ouR̷A͠iucjSE|wqղA27ÈdauWĬ.Bv[& Jb8 %< *!8yFL[+")2/]) 1 oܞ%g%xysڬn6jarYJ j1oR/ #[n7^-`Q ^`?e~dD6±"ъ"#³b2GEI28_0}Ɂ0^{Fգ ! NsV\o-;-jtVHu{rJ~~? EDN={}.l[ x]~`pDv ,8꥔B:8oPwpK8ꆴ}njntG /z% @kz&}%xA Lmls䃿6iLiaIZ)tZEƒ^=:PZ7{PM0<,?ߎcǡXW^NA)S^E # hQD*VAaX1E!ʊ0 ߠ[yaf%N-}H±[.rZi ̥k%$"_"9-pO\@R *Et ZnPzclQ7][qúe~Mкq:V(DpӇ7RӍ,—ΦP16Fw٩`[$m;{l Em|MIa`E XlaSvQ! @8][!Ha! b' U]U KͱscZ#t{ 2͝`{Xƶ` mh{∉smJk"KaFk AhD+" ੆h̄aC #8~Šxh$rm683s5~KC#O\wb9Kwsց2,e)KK(!{?@9[ |#yDsd՛~453C:&HuVEl 8o/Q4_jGf`(ثxm L &&vMo)b`(w*#=ΠmB=O֑o1EqFJZmH_ GPz=ZԺ\Jlk+iˈ|a), ,RkB4ˇv2J&&}ڮEC ~YtDް5MVHN {nހK࿑/:Z;Y1γz|E^c!+>[ȑYR@1?n b[~cg͚f[ǚh2mkWHl}r!0= W" Z<:7aG^;d>m Ϳvw"8sv*xR7-s=fű³ -|J㖹V±4B@h53] d)D_P #r(--r^.x7#DYLYZU9{=Q[qD xU:EKs섔ҝaw7ޝa}]91'm 0wno*״E;g#b=zs6"|Cy(*zE^m?[>#r{u>w#_;R/%J[6nב FCd(v >qO>ǎ-YySgד6h %O6xׂ&DI;SǪNƔ,9T'/f'6R{>;.'&ɻkwx^dO+bVnp:Kr TX1Ƥ:)Ger9YU,Һ9:!2Su++uqAF>g:@\5|@_N27.P;H9_gJu y<(2d2|`'*P: )( A^a' υxDQT%@T9l_F(SkA|h۵ŽLm-N}U1 G-41_` A;\`h Y7dv T僴 yB+pχi,g \ aķ{8~}(wl5-Nelf&@׃(ͪv ,V3uѧuQwAYUo5D"Lo9ab|-՗H'*z]koq]o)[acCW ȲHOUN}! LX,wZ9_^͎XN Tw~^;rMe:4Aˍ z=BN<`%u6Zt :S^Uy٬{,eWY'JcG\rf3r/O+/'CGxRr?d~?7t90 OKl_F#-p]_c i?~}22?1^DDV -*$*7(r0䮴щ_,!lٌ%#ܙaw#@zP>vȃ'$tZriNlBW>mn:l\/oߤqrπ7$K޾;QwP{xYk.S Y >xE ѼKBH |RA Vѱo$߫<}# b3Y(ң1[z*'?q;H|%.E{&7^dȯ9LWL Yױ |7lKGԙv:6gcqS.uZ64>.Ů~tsJGN 5-Kh .rEK|C[>(+a ךsr.6dvj QY3嗠ixmGoJLگzᱣVPgJ2yu'Ge[f򒩹e6L=)$mG ͓Ί}üS@YYy T[퉟P&+P~ވ_AgXNTF/5ϿeK7/Jf/ްRU>1W|:by{|vvsY㛰d hD>Xk*͘xOb,g λ,qDtFT&(͞eHBqo`5j*z!IPZWy Z/C(jby`@)wR(4?nd)$.SG0 H,Ͱ>! J 2vN8>#!"?b紱;~:l#?Csvn1RR]7Z䭟[}.5$]Hk$Tw%)It<˻Өtqj >{m0l>H>MqFGS7ZB!)=Ƅx.ooW9!?cOgd:aY>|blvcnxrl̻LM+}x_SLLuLbey%^ 2Ҳ 4 _hfLPؤA~4:Y P>πCI~‡Aks)_8l' 8zSl9F8F4#VTITT %NH',QiV3 dŠKBHB=C>w}q'efzPB/#QTDV9 >u[."ⲋqOTAyebNLUU]w|l'W*4d#Ø( 0Q">b޽ 0m.#}a挪<سZ2'¦T^~1}PpWQ)2ހ 0<d|# .sm,cP{k^TH}Lm(@)"jtmL|SU m7!dFf}b0xF~# 1WqH_ AIp ~ jۙ2(ЃK U4p5? g`8}g1Lĺj& 4W/~j(ݼ|gr(Ԍ0(͖Sr+&ggge/foz2Kv1#f10GΙދ*A%1oE-,T}{*ʣ$%]y9+r.``r9.$blJ3(@? r'KBOo`)nY}|F[f޻ML,j ا1V9z)Qfi-Ƒe w_FC Y8 bw`@ Px,7l걝/׫k7oCC׾)ⵯ`okQqk Vpnn0۾lPl*P,a |0lӌan|ĕY >e( m[ )e0?|/KMp&| pQh߰q ؁#u@\9ܤQ,kʮiB5et3?kqwoG0ziW0BDMq,/Η"k4G>êxzL3(5x0N1<|pȻ%'.Np+~wzYۧXw3qp5pZ8?дH~p~cmp->lLBRBxeh oPϠlg|hjIt*8;̕iWڴtp}'1ԦQ7f4EkzaWo4=5/ eL"kw0yr+(a1㴪fD{ꚟ>rfI-QZI%ԗtְlhfYfa,>h: ^ LP[an:uO7u $ᦾ''6|@rB?w  9=u%:yAd]q?/=_N[SݚXRKAHWYd(a. 发7zۀ`1Xqyn.T۷D׆ c|`6ej"d/lO;1HcXٛaLYQtÉ`tΊAȬ4# rdP}Cl~ly R5"CXת9;'+ 8TǷLkPkvI*O?jh\ 㞎*a@J;}2w*H5<\! ?{Do! !WP4 c])>v(噙tnVpַ5F&(꽮XK{șmV,g@09wvUAb>SW|~ݜCr9j]˱ o;׌i7SfTgM\^*RHh'ye- `.=@?/D)S`oKmR?OpnGòA!n xy)K.'r1?YcS0~^͋Byk/-J.lT~=hs,82>HvҞT4 Fy=)5gQ>F@L ^-O=FEAk[qJȠ+?r=o39|V蠺<ۂC6j dY50A+)tT#BrrMCOCn35iVLoRߺY$FŚuml8r3C Н ,w t9} oώEik=KW}iz0zVN^ C˫t:phPpinh]T2JOg3aa~0~YUJ8WCڶ>NsiK70]҅ =]uQ]5ɘFli? A|yt9Tfu] 2sWֲhRv%$>]ʑZ4FG󁩕w>J0оG2> M*4@=QĽ$s^m,G,<]،?$.tYXC J@(gJ($9 918!% P/59ԝ? 1Qɚah|f;A%l; S˯*ƪYK*s3kY 22]yWJйU "x3#i氏=ק>(RdNJQQ&Z4)=GS!nQȁïS'0OݝڗfRf.aEX5$(LT퓮-Y^k Ɗӵ;bA⌦,ە!E"|Հ\*Bχ#% Ǩ_+] !{axSǻ%Q"hY7q [gIm6OxQ2yl:mѰ}e\Ati |ZOA >7 #J"lkؑG$4QG:J(bK]^ :YƨRD $QVϕIae$.&d tɀL# >S̉d8CeU3xWO|Qĕu]WQWdA\YAWk#aQWUW].`8e`;?]4$ fq1N;1Fv9t< ]bdcH]O/$_$TPze7znpp}YvNɱn'g08l449)u O)"23?P|DێyA_ MXӌ|Nl;*gT׎DNUό6)A)M?Rh~/aުBrMܞFl7/(zR!<21av S0WEg7T*ȯS W<rvl2rPb(1J!g0:NkT t.8a?./]KFЕO<{ ?@Cx 4oDYV<̀O_6Yr{#GhC!?9GL GV$hطj O 1iu+Cc҄ ˀevN<נvS 4 /U(6n(ELo + fLY/H B[g 2ߴҥh!FHddt@n_Lir0/7ǰ'hd pN֓_9#-uPr.#nPApD~JVCg8Nٿ8  $hT\U*M\?ЗZ mx1A%wx'ci5OM48Y&j?cXlb gH)ban!REHggg ds(ٹXC'5~Q+2Td.)N"#hnLГq nc1!(c MRdǰ{d0 êYx@*qtEű0zqU%BUHɔ b FAA7"!ȽP' ZY^jA,x1 qEh`*=뚡|CD^DޮU)]^ ?%],c|qi@%#BGe"B@RQ֬4:&ʎx򑕰䁉2e+Z[æj;ֹ5;3JԶ{8lmm:*{{*4bZmf hiʧވ|E qPس*xykKDҎMH̼X>AL &=nLe.OHt@|ϹHγf;9n! sK~PX=2N2q~O" ~Y#P4; ,R-d4Ptbj!ÿmq鱷'/nbz{KKK_iJKAiKcD(GLܛ/KǍ*7]68J/\wU$c,C!o-$ ՏdϟQbFeցD4[!7%S)G aB{ҲUdga͝b k0O%X-~ie=?QZPvHd 9R3:ya`4Wbrfms&WbY㍜/13.DEˮiՑE!YfgzbvժWP1?Rn}*t=7(g=u>z0#fgDFaT"&* $A c +uTdK"fU[z} {'2Fe&pSo_l\n{9LΚ3`)1I.d7:*1rnɚ.6p&7R/.Jڐ]q? F1Tj_pO&W @ TfOmNf#@Z8E¾TV5\'[rQRCk_C`Gk qpnH"faځg䆴S3*<ھkp ƙ%?tG*l4P ?s3hD$'V1-<',~>5 ZmDԣQm/o@1Vx#^$n\jѬ!v ðrY76x7axvyFcG~B*die"qyG=.)OzX~ 6߰ꐝfRWElu(Wf%&F8D$.L^f@/^o-V l>1b%J o7pI8ֻHY~34πpLԣ^._¼sYִK KGB0 2E|6*h~&4YC`ńH_tM6p.nK\.cNzfNg nOzwP`UMl5}M"SGU.:*и[:%fUR#VvUf7֩VOAGrq4KS vBE4hꨦփy۔ޛ1ۜ!>vɐ~;%]M2 4]ybm ($3A: d] { :͞g|ݣW%x,\ )2Y1cC.detxѿ 35_X!%FLo!IUWo WLW86C_?~~@x֝%RxpAXcn d4))Usdv12y\/! Ts4{ Z:և{pBZk^*H„ɜ=OXۧ 8'g9\?Vt׹"A+@ڳAbMH mR!"##BLnnbtM~A =yBqo7@ZwA>.vvHK살޻Z;W܆M אַKpԥ! ?#мH "0uOLoat>? M-u;c//D~.woߔБb^[1vN 0"arA4̅$ st!G3CPqmY'9OgOGEr1^ΤG ࿎n‰hg+4]?%vm4nrhp2r9h8m$at.8s~DGvFw=5ׁk \ )@5ajδz+7zj v.ؗuy`8G>tk jYSO?ҘP[VY- -= Gq_f`XÇ,NgXXleAU;{ڪOoظ׶e_fRAi!aÃ<2a,_[Ϲҫo7]B4@@^:WP!R`p&v8Q.cٱ~sTQWj(Z>Tl41ILu̞MZ{_y%`JkkWKV8hWQ5+lsa;UfWWNATN&4@͆aLDL,j[6$kɿnC4@y iɨ|aAD"{A/~)u>#|/J%(lFTBT8Ȟ !- .gY7><˫TBeы,qN662W1J ҭQi{bx+&56x"6EͼC&-AV2* .ըV0Tr^OfC=BzPpC_-ʖa!ԭ~UGa m HApaJzU^n;ET zX!òM|b9UV<^n>pX;rp4O~!^r枢.c QݍƗ1farprb9r-<,G³FXJDc J} JBHi  ={T;];q;͏#2,WbwNØ9hd y\%k@_f:KH^#~N `}y):: hLrfR†gL ~z%H5 rw1@ۑ+hˎf;?dJ!z' :h mY`b&\@-gkڀBw4ax0\ᑹ% O,RUA/>^ Vܲ;#Z6hEEf "J3,Y#q3Y#gi3i{x#qH91b$eT58 iA@DM4;g7B iΌDp$`N/Ӊ4kY=ӇLu_FBO% [ZOB ₾er2?iӧ'bX*j#.`D~شYX↦KDw9L&@sf]8v0;r14G;;"1k WCSM_KGJڴ*ܗ6C16OXb}̕XhyP` |L S/@xpU6F{B"-Kї Y؛߯`AH)hPp9exUfgA-Yd-ޅj^M͒%5j6nXX[Xy7X7l{x"rVrwH HK]Np'!+ KFn@TQj Z&WEtlap@0bYggjSQh*$}򎢵/ B7|:r7 iHC* rf:ChHlE{ ޞ9IM!:l ߞ!2\o[G8%e3 5N~X-+IgJ(}dDK%dsg` gDC2'9$q]YɷpdY5{<Wc UUw$]/=}UWտ~J~ @q޾#gL_xW8涶m%c^\9Ҩ ?o&ӜΩ 1,amFW*%FpwXb`xU8NV%x(\w^7\.Nld剧Jt8XE{{qs7^)g ={\*IVB0nl:>:G&LZ'՘ |\rn(*g[2R ){p KwI3nsK6'jQ&[CMB9**tv곲؍{6MZztXPKb~ItH*;ƘEI7.&hR OSAx4-/MPP0&MLL w)Z{B\Dld `td3vt1y}SoPyV+ Ļ~,>n.c9/[ckW@lmnUO6S%t N0鷀Qj湵PL&GMrY:a IM:eJdmkHuwmgԸz Tں &jcߨ.vƳ6l,VyqUt{r]'16{EGWGy`W+Zc#JcM#߰]6w`Ϛ0jbx2 UϜXSҽ+BܔN&JT]'>]~j19e6s\>n^=ٔBW?0p/hk5\"M쨥 SEy/\G_&J "+:D NBm?z+@D.9`-\|n;s38ÁJd {L9' uV_ Ӊ.9ӜλLr:QDe'E*;,ID*;ÇQJ*R4,$JE(yJ=ʐ_(]M6b3q"FX\I (oq{f?k4Y9mFzo[ld]6K*-?S@h²Gcv<$DF #f-G[V3 [@7̝&70T4#1ρ^^d`*gXu@.u`DnrHK0v#tMI%nţ2U,u}Ð'k=AmiRZ |A#npzci1MιnD&6nN8扡Se1`k}!* Vgر؀~'=@ }QF=krY6sV+fs{VkWH&y#cJ{ ?}UB n,K[3#?s@VCxdG*ِq8 qФ1ȷyׂo_Cp& $LyNVKCNbdYzDv&`vfUƿHɆ3VvdNAdq@;􇙂̩ZrՁbE3Cc@@wه2mkAB x((=ދ[|L=/抝_ǎNL)BuR_D!F?7= y '~5J3|Tn朐I0vqZ@Cm%SzGoerfeM>cu[ͨC`{rh7SW\#@G ʐ ɏyx+~˙m Y7V a;,51h~ou^/wNKm 4ظ4L HrQ3hƄToG V33wB~nt>j*sMۿ%gg9Ho;}zB\)u3Weꫵg/Z`3w@F-MZ  ­Yi~ 52= ց-rujBi- 0:y誤LBCmY KRq3!Y)eDl.ks^&V㲰6?8'<:Rsuvji#Y^~891p@&WR*˹ȟ'l`Ew౹5_,剌G'=0-wt!^}.\sk|.be=Z9S AGJ?gCy7n"&4iN"piѡ uf|{\::[bTBV\"<4zTjmKESPTFjgT@Wy_\*$Va&ZJBiЂy|;鬞h7b@4Ȕ8 F&a߈~Af0XE֏˅_T=&jVcڌp6eYZ{p3fKd7ZT PQ#AEέ3!R; yGoPH۔)v(}#C8"B4&IaױmLC(8ƽnW+E3B--'s C@*z\"0+=.m"9ƅvBtwn%™>+#]#P:Fa7X#F"˦#̋?*~DwZOGK/&x ^x~_$ѳU_}x4#9K#6tt&Jzu%E'g@9PKݣWvF3eꮕẌ=QAVt1m (ʻ8]4u֘*^AҡTڕ6$ãa|{Rd?dV0N  1jZ,ޏ -z%) {;GP;VI ǹ k,L<:駍͖-: =@ H056>xU:-K8CǶ}GDЗxacUO 2:b奈舽akG#v\NW=FzO< =zXh":tm"/ ǁܗӂjpqL֩yczxl6aF/^9TZO| P_ tq$"vt ``9*}Z8Y߫ҟ[7r66VkLzHb,`vt -ר6e wQ&E*PW{~7`;0CaM #SIqQL_`zVuJPD B2LOLO~@5[\&#{65k[.jxx3|]"H2k1 GK-ۛ鷝5-=%2}@G6^PC?H]mmP'4n`Chho+y<<,=V3t kN5Xuێ?aW@x bty&h~wC7e^ ir9˃ 9TkX`J\Sp5iXM:-!A'_4q@F``?`k6Xc dFݱM4 ܨAڛOC6s҇,H!r҄!gĆKIҼrbCLC³P6 %1 ) Y/ĞQN/sΤrP'C sH*XQ9Z[?9~k[ak16:n ֒}9@s 0_P`|/tM<4K96€ l+Z&0bT̵s/顔F?ķ~։-BC +]VBD*K^ ;N?$=M("ro(t"7 kVT=:%C*h}@OyIv488 :RX!Z%8]钧 knRpNЅMȺ& 0o?T58IHB@ů\}! IH?% q!/ <ωuE!pI>_ D/? ۓ_dշ(~OTz @wa}Qʫ8V\,(m* z`bs4U`@NR͡Sc?b@JH^DȰaܿBYq*1ĮdT2b(2mCPҟ.%':_xr:熲a LM lmI|HQe^ fSοr/e:$zs8t}srlld~ߢfJ._$-zA8/i )C,U8?lyN' kx~ _ pgnӝ wAO~A!XSH(taw Hdj˪JS a8Bvp gNqN{D`@g~먑5j-1F߯(U Ŧ4 ` h6E?6`% .ϗ[50F0s2A K_dBLVI_ba)V.u *S45|mTcjv:SIWpW2SPW]^Ԍ%G?aHdq" 5Xizn>3 =A4wr(| 0Ռjړi44vJv1B\d4< \bxU?eG7*7}R]0C?Q٧ Jv8^fņt|W'O _f^# mg ᒽ_3鈍q& ڇg],TzhN,Q/5q TMW]C {#P8= ] P+Sr^mh MbĞS[ F)]cj&z,Fq[7~!f=Pnw"@Z㿢O;iRBW^;3> <¤/cT%ɸ=CbIm3Lf3Ir3G6# 7X LA_O !m9=[m(y~aEΤGxt3b7~ mW@NNRK zW:ɝ8WnpeNpv#Nq3˜yb @b+-5??ffŴtF,VA]c7hNbPv:L7V'UK{ю5ۢ%!65@d,XtD'6d, R0tCe[:&e!ܕF3%4%DsHK>N%.N|).sDgB :tJ`-?[ˡl$ai>iXW)+YI,r6N8( ~3ο>vEeٮe-~lMPW^Z苔0.1Zk#.3CaQXguh:%sIJƙ:E%tMV+4`@O<δ@C7xD`rodeJ3l?hJw8'HsoFS% );\آ^LX;= Ssbݪ˃ot Ir ?,rئṔXb7~xV6'S .y "ͳ=Ae2)CcTzaJevjf@ew2դ=őO(J-G0,Q'[OG_dlѡy%!<W,*١U (|vP1" \;@0:+xߍCٌo5BiMN")3Л{ݵ?f݈^5A|<}c :ES4i jSQ0n;NtbD*(ymg!bvV^|s;K'!&LcGO?ϻBANbe;v }{}\ޗ_V t7xԾ)75iGU䁬rpPOp% X *,S&/{B<:~uj?2ʜEEĄhѢ* n۲~|ݓeBk[SP}`CX=D }/gokc F  M7Og,~vzfWI@ _wn"hV,2YD9a]s"o:@Lql)ppfe"9RYPU ssss˝HNz.̽f0cF"ޟs27|r߶y果8` @*T|4 KA?x#͹31uZs"HٮSk>'Ij!si+,kD'7_|^PF"$7#+G+6g.c:~x@&֒O1w#UoUKcNX- ‘h:]4fpV埭u5| ;qLʷlyi7`goXXϲzC Xohm%`KGXHv &U7a =1JmjL}2mQ#;^!y&͡TF51L5 zg2uަ_6LmJ𵬡fm??Z& o۪Xy  J;C%"uQev~ Z$UmWObvr@>YDN"g:\.Iv>3 1?g2_ÿȞH鿑`֕E_YfvG_cf, eRc|9Gq}9g}MsZqW)8^aibK2ʿ4\ οo-.+3H1]Jsec|`N .\Ro*t{O8{RDvD{L$ljjMBfZM͌&C5v>/|PsDk! _@kR9,D7#B2[]QB KG:, hfJ81 ܘv`ǘ W-"ƪS#,,UJǂp6S`V7L#4G rUk@:w>?z`^_9gY(}h/>^d$s _L}Mr-醫r[2+OO-F=c?= DQB?hhv,=\2# ֗xBY]b*k? ꀊ]QNb-Xd/?Su^UVG>EєR1mԊ. ($Gg{F'ee6gB#%MKons(?c_x3bFx{7;)\5~hc"{hiwGRKQsD/gS{i zi݀濫V;w=Mf¤;lP] r_Ew9c_f;shc٤_5֯?MiS2+Sl\Hυ,4SJEj\|$~@x*TJ0 CY?jh*I( Aڞ CMb<,SvjNGd֜9;N`j: ҍ==}ouC.C5Cm #RJyg!XkGoƮAP(<ÎŦLUMtRGX+L}$ N@{xp,:kwoIl1: h5cUU6z0@)")p&eB壅=ޅ˻VhVwmX+j:\+*F=)`BƇyG +ˆs+n$U!\3;K@TTTh%$D#, *H,*}^=^+>mD*}ZEj-GalBa3~w8͕ljE?pH@(bx4CH81R04Y6=>#t vRyACgFΘeK_ 뵓&ByYqiv6o W쉷Dw١"̃a.DhPjfP=V/px~6&E9A aJ6@B\p\n9ߺff7֛dϩ/O""LsMTAz(=4?ѐWzty3wl뗦k-qX|H:Msij~dj_4Q1}QG|vYϚ~ ]d-gSO&ew2a-%³^= c_\&K!C_=g:/h>6',_X$ ECA!Kq!,>_eì_ R m \^[~ofq[&/"UpjE{hwA`5nYk̒C(ܱ|jCse.LLCXC 4FJ/rT}!ѾwK1$ >DQAKp^`CB("/Άbp(YI ųI#/'g 6qEUpE?̈sk\mZ =6n.Ix-'@~K뿛|W0'$fڭ(G.GzXx."AL?K |(Ġdza.?>NC#?T' `?&14S(*Ж>. *]8s(56:mk|<Yܶ.J_ [W,@œ1.,cp؏C $6EKpʱ&u?}fTu|mm-ݺ}99'޾# 2ڠ4>#] .P+$~m\M33,r~c#2esJZhAw%~8Y׹^D'4C18ԺMLgnpJGJ pd9wȲOޤG!IXզ ~.9"犐C?p?pC%*^: sꥮve6dSit){xS +pm1.{RRaX' ZW HK-]ozQi}" PC\&`iMv_MHN_n'[i'恷{Q>u<_dQLAC)vC1 >CX^@^jʴM% M+@LY-v`JJ6f~/QpsW(K;.xEʿԣʁν\@fn"4dy6fgxSY HCHl88/x1E)e\̡7?Fz7Tqz0-s׮][VDŽ+ ֚>}sbu5KC4M2o CS/u>Y]h_iGv;](ؔl [v™NPcC 'Ҋ֑~ >Vw[WH#&}YΦI#چr% z#yMpWPN%9JԏD}%hէe3~jNdߵRRA>.pjSKم?ʠ1U+̀jfr GQn;$_B3 YnD3\O"[ov#-| <հgj[K}1E;Hq(҈ 6b@pC[w e~Y`ZyRy9|z򫮺j (Wj/0~SLm<-̝/$7{ue'=KHMue-ZRniGνM fF?wH1>"8(Hq!·Na$IB0…\w b~oؚp yz3̧ԉ4$7ye۸؀G% Y,Q.IhuW Νn0GiKImx V[lmCꅙϡNp k mZe3${κ7&%ٔ:E.N0X)EH'sJîG)K?خSn#@`%?yQ1,usD_"BxAp>0EYQȥ/[b^[@O,8 ^jgeU.VD=8e,hW03> ϔme{Yҽ˰jN|c'} Dr6^).6hS]2,VVM4* ^M6Hu#&t ԓ](v&VO(QF(i}jis2rٲeoTsC:2ӡ۫lOzfO',˲(p{62S&0y2b`֌o\LUU džae4X Ndž3ټg<6P7@~Q0.cmB !.$2 jh7^Di Su;=8?XNC.ȅ8|x$bBT`X0X[D>G=CUνJ͊.!S9_F{ANؒX4-NE0YRNj6YN pϭqL1fF |u)hLo:hE( ݒ KBSkIC`$/8\"iTȖSI*$,&:i`] @YVΟLCHgR5mɪƁtFU572(X\嘽#<(gե3&Ƀ/߾!yP8Lɸ 8!4怢wSLĄ|T^$!wrL|5MjG3{0);#@ Yt#tԃ>8|i捜jQR}AI4ēZ'CcΣ{bЂ7ߵǟim?en'1~䵅Ɉ87 tQ e`#i3O@g1v.%֦˵I& KHxwn(;sO7m5qɓ͗^6-; oCISao*c#LuԜe?7WD֫3Rm{!"P!Y qQ6X9>]6as\(x&_ȴDRk PCI RWGX^ Хb,w@fUWk=cw ]xQ&^FqL*f)= JFg( HW }Xѽ5Bv]\#Kթ: ~ R-h6Gx\o@=Ʊmf~RAܟɠznUgh+i&Zr4y'~#[a3O>II2P71j$L N,N3QNo- {i' Zx^Ńq,6>%fIHqiҀgvuũw$1w  핧ak*HU3`o<45R bL: !u}~#yx^7I6c:ВLБ,eWNqȀ7,bҮ#lFO80t4>ђ\$IeDǑߓ ]ס1mo*ڶ`mH;^K=_{5+P(ު3p-EW쪧x%;lʉ7NDN8>3I F)XJ/т ԒD $˦ Y* JL *WWe{,u6NIIm$6jS~i0Ew A6.FCD. %I; KY!R+m?v 2hd 0cߔokd%TUWy⬀֝Fl^ 4&T 斞!*]& XgIȇEx[ݒ )9ŸHƈ:գSPVO#'d]~=|SoL2KIS,锇tl^:GUGt qbBIM:4*=p8yaNjAnRCb@y h8 P6i!KuBJ|V~`$#C w6LUO3YT- t~/SWRp!UzU@lYz. F7jYbӢt晪̓4QLS`4urp꜎'b0 ٤&<j9y Rq <~hbP&A}!_bK! | 1>D-`Όf\4hLN7T~*ۉ-O俎ҸE`WfOc|1ԂLr*#!Ib2`-I[l/-=O^' =|jY˳ !^f"W-4do }.Hh8ɱfj$ V a}I DtQlt`] Fʍ=}'8g[-hq;됲 % H3hlzJ]F1+ /\JO)g{lmb'e{gPvE{.IufzZ̥QzWQPu6Pvs~@%Ghۏ}ۥ/e]B NKU )tc>F(I4}9=wv8R`#$1ٰ$$\$}:}~u5jw%QzL‘DH|b+$sz:“4ffۍB0!"+a rʪ+<\ Zt _W5=s:IwOU}Uw ȹ}iL(*äIs^M>&[ qGgoH`[%hr+S׎$ ױc@iMN*e$:z JfPJJAWu\T9/47kG>&\md“6 _i{/isvD [qX_ȷZXm' {w !@*}TIfo[~pM2|QTJrmN?yB,!p~z& IW;*?I?%@.QJ 41h|u8bnML$e sg|( ]r*W+T(U_/. o 6f|Aږs%μC-NSR?ʟ?"b.¸BාKR[(_.Ww>گ{.56TmXdΝH`8b WD8s<n=>)Hc׮OSiLJK3ؾvDL+4N=j)y@(EV*\uQP$sԖWJaв+=<[8+%78t 9%=7׾DJ>+q=SxqGyp9O Ky71."M. j<6B;8pq=ُUN}PEŰqbińA"¯ȸwT'2( ldZc>햖 w,|wi!Ij5jw.ެUQ˫^ *oO_g:{l -߅&)45{*i+6&(eMWS^ R>)Gk7l6LRW7d yRyjtzm$S;;R%}d,_'. J!!ٿ_}27#]a)Q4jtb }2X[ˇdXdū;$PWUʨ$ ~6Qf\*p-R>z,?rFMq~@'Xž849oGNe,bv{ҩ;,\y4Wvbk>Po4ݭ΁M 2v(t`|W/igtFaLYWR>30aO'r b0~y3Auߜ}}@> ^rˀPS.C>Op3'N 1F\pF"[y1Az( O}iӏU6/[gF_*1>8^Eg |Wnu,* ty>0kmaUY~=k^4sTT<.EZYG2H*ӥ4#viE 7ϓ>8I-I6Mfp:01uB p/|yTM>VWtp Ԋ5p9 {c|&mHl%''EVKX!VT tzXK4]$NP΋ϲ>nQscr(j}~\uUe7OD >YZ>[!H_ R΍\$nZvX'ݴ$Oʠ!7)AEG_AK=d.Nn}tlgr=!He%XP~21v?:ܑZUȿ6-gDcYФVI-q\_hɊl1:Y% ʁWYsmElPb} XW;Hpan-7rPd%^`tPDهü%c2iKFs8jm0DS]9C=os)!)WcW=ufٓܿ}0iQߎebq'h-pA0~|nH&@ Wdʈ'c])Dz>nnDy$>:Vꬣ,r۾B2E+<)t꟨Eaݖ%c|yYx,U=|L #^[=c G2Zd W;RԠgPq7dawꜨ#BbhAY!<ͺ=nA,X* e /K㿧TBCrIq_,MNTް[' LChl9g//ܷl]~mLJ9fڃɡAbNn l/4rRSG>QbG^ñ܉^++D-`Ȱ >VǮG2uqgzz7d2c{u>g317kP+=3c_@sCMcqBVh$$;igBXpf%Nidr]`4ڦA@6\IVԉ*:W(/j|h)dv+'Sq2.w|c'\}QAyiC87_?NƯyRoL+ֳ'%(#Pb{񑢝V)@.u՜ My3UKh_UALaP-@4 1.,ܤr+2' oQZՎC>J\mr)SLkOյ篽ֲǵK{I0' "tg {S,Kns(7Ǹivd{7b;a[vq{OoM*XV҇qt3LvؗMπAowo˘7YO xK3Y (쮾ϣkUfMU5فm?'>E0n(IFϸ 7qG(#D{j!nzѽvd|ï|3j71| ٥NHT1ɓ&[}fίZgVo7=Ǒ I5 +Z{ 8Z5ɳpԙh"x*OFN^(ԲloE?i<*d/Ss3joۙSj 1,ףzPNPnJb#v͡Z5R~w2/ GY@Af -.Xu}Ψ u o^>wCo`w=0J->iԿc*y=~gHw /$36DZ#IN: f"_Aˠ`w /xn49zviM6Ųe׫Ey;p"ѓ3C_w.Sr kD_2.nB;[m[FDE +zug :~nNeK۷)*jq#Q.C=\h߮=3kmX.5ƽv})wuퟩ2}KC?e;ҼjNx1؝ݺݿNm!VFa?7 In۶mwiCn}tT3KнpnO'5Ma&U<  pܥ=Uqд>Yc ~zG+ֺO?{WEgo+SDsg2+IZ Z1M4R+K*ϲ#;3ټ $عF4 (BP<Չo0>Z[KЩ:@v_fx\mV5x\fۉӿ9}î?2|QM xsXn5r/nchGpK΢w* h,DQH+υ*C;}@dzkl׊~~ WdRr\T" ϧE{"+fxK%Dz?iO جTұwbd⸢&mH|du@3+?&}4\ayfGroͯ7sx62u.Cw-\yZylg}⻷)fڸ2# =RHNEGH\#%g޹7!{;1Ύ2do~yiV5orfm>5ߴnuVi=9vVl hmgEzst9Cϫ(@ף_g6]EǛ|"A9)+ڶ/-QZxpUo]&aZaI-f Uc\})k@ )FkE׶3GQmM0F 9cHB)eHa38e2!l5QGHo uK`>$IU4I${nW m [;d^nJOY?DeY_$KCrc2jn?Ib 9-ۂ zGV2T=%3$҂y竡19 ~1'?Ta{U\0Ax / IÛ- XL(EUe,_ʣ X4os=%;YA[ K+ A:C1|}$1/<ށ8 H`pA!L.׶uYu»r2gr$] 5]!B  "k{2dȐAMQ5nMQRK'eT n#83,0 h!X'`7fGX*GQO`O`ÃAol#3Yzlp&뤝11>_M~vk]UݜvT^oNH pmL_^{l!Bނs zBGQ@?mz) V*۶Xg8­k~J.,r➝ Ae{i* mUuBei%,u[g#liV187ôCH14 &ĂRQ?bn?"0*x?@W/bx$7+*`咷 dh(%CUwPAJf{677FHl!(|4;4i@GM$p{Ͱb?" 1n185?X_!/ zXUz{>@ Let4M=վJO*v۰eb320Tr }gZ~(Yî  e+U'C׫;0_eNjQ/^r3kh˦oε70 1eXT/I(?q^>W^:o&Њ~gN7铺[{iᚤW+6uQvO{)3xzAjԾ[3] 'VܹHJЉe4C `9YXyK+E:%z֟c?wْajӮ1s t-Z7ٶJ ^I5coDfHۦj?ޟ]Nf]ѳuumZl;%%ec[20"ϳAO>{|k7v^Es^ֶ}/t6ʫQ-F3C~>)Øݓ&-s]jOE] NWJ~}t _0-.}k"Tӏ]xݫw,:F]o7WOnn7ɸa[ߘ{|A51;H7cc>"}tqo?́;)~b=!.m]3q1tRqH?hsO/wE+Y_^|'AW#(mf8ނX( b`&WWAJ +<" L6N(gQ*3,ƠJe k˗.>/KߪReVup1wI )H@e|SQQ(;e\=(-6rb਀] v +8*R&~OQX):*6\SQѺ >\(@+qTrz*O +tLWD /m\/mm`)wG14Pg,(IAHij Pf?* a<PN$ƗjUulk.Jrr'A5d?[W!~+K P霫wU O*s8/q52-\ 3v6IuY UGć{ Urn '@r Anc>2S/M je׷Has]whEcuOtWRɨ6?<",ʙ5a)-y$Mr&稤SVMrw-'MQe"jZ/p!sg5R.)w};9.\pRs~@֭LjH[Ŝ@ܟ57ނ:=A3W2B/d|XX3O!S1Ǟx>8\k[I6}%1ZV99oNΛRޜd]qGss'6a7L[%8c23R4aȌ[֕53nF<:"{?wHvHVGWmަ#|O!yZܗN 6K× #*m ,ʶSL6fl&d(e]/PBʸbUnX  E2!ɄoY%L($NWn_`W?Q3 NOG5 ; P jNzG2RUL>`)iԃz+M}.-uTCe!Vbe!b)}=s 57y2ca1&(q,‹` jp7Eq7^/Q '$~NHʀ g PTɗ(SRRMk8 (r&g*ui)3Ճ)k{}pDG|#2WL\S~aU_=ò{߁۞AR ǠUZ퀔Єp7Ѿg26<,f&Q 6cR$2&20G#,T72#Q/HPkq_"~) 0?= -kkaCUP^䰀k[ͅɏ/4bA[WGfn؏yx%+Y]wӠ?  E3/W8R| a=y$yĀ1:3GeVN5!"QMxP3O4kMܟ7I p(Ţ<@f_@ ("UA*˒N|L5FD&FvZ'<2 ?ҭXpR0Ô3 ~ XJ9U00"'rW;<)Ө\n4+Ы̭VBV"H]ɩtrm,xV\YCkPSJR-eekȷ7~iڧ-<3 ۓ67i/CAC9M:Pwh{7gU`my#D6gLz|dgaߒwk"tVB'X{,Iu6Fp7䞸aQ3(ו4=Wjz)AFOhɢG&~_HqexŞ{Ȯ~W\Bi^bmc{:!75AknzI0|ISa+&zajl6K%x,B8buVDAf4SQUNu}+PMHn[#`K] -qrmZ.t~V<&{~, cnֆGF5FjOqUهcmrm@# oxcE6l4-BVwC<*f v 7z7:{j-[]11+RjhW2o@o`U95ׯ'뫪QC$Q(e`&AķEw#Wt;JA(C?-ɟx?Ƴ*˼,1J(Ft|JEVVXZjG?ӞAe@k|e#-R2JwH#VI'q]~+povH } G<| S7F0Bm&^Q< eA&MU!yIT0 g=?9*L m_ o{ &,D5#o(I CϜ!ӦeNnԼ=;o!4xqsCÌpF〒-6&eF;4ky(P\II|@]n_oc?eG]HNyIb&F}UfxZTЉ_IPl0'@S#@=}GB kI&l\R==WHIqՁ vpq3#'_:64q:dgw0436cT{z37QfR"X‡5T>*JҺ Izee?OKs#@ Ct& &ׇ*!@; Kޞr4VOa |`3V 2'?Q Av *%J RE+aSSIEWY4r$Kj(XFNK1O̸GA礮8. a*ṺU&Px:[??c9Uap3@i=+s6#jI떒Q%L3I_w|LJGe{kk+"KB"mkkTLLx^ՂxC%(^^3NHK4#j˚鼬QE -4<+,<_IUY^%^!9JbbzQiN&YDQ$v H>H .*gǗOqQ~Df;`]8yu ҍt6k.D>Y^b,*@\oMGa0EF-ώ<U= 5* [ DzuNWFg\[OMg|`> g,0|X8+}JзBMOXU`c S 1J"Gm1?'d@K @[ch-ʿsl*_,6fZԺzϸ׿:}p**UpChxiBF5A}>hoc{eD/3I Fw{F \CFح}vKyl;7aQh}Gs3ۧͿ=~2ll΁>wbRuzx7Z{S/trGڪnʧ L<+1bL9E KNQR/oR 1~(p>o7˱ߎ?z:/⼻P(A n1`|"fsjXx lY]s9BkJ֓)uAx5QxUS*&*S(gtVYIIM"ǁO)ߒehw G;2CzC"3znE_/x@;C⑃Vf;3~3{s}N OÐ7bvʁ8tC c<#bJ$eUUI(Z"IōwRgΆW%? K@_~Q}6 UO-0ATowt %54Ҫ`e0Rz_ȍ/XC1SYo?06o0oR=f@8$/$*e!aU.O֟ws  wYV_o5b͌?U5 󭍿ۉ?EA}pp r(0'Tw,+iV5_cD1J܉7c+9hS Ԉg2vƄ6|#lO:GsQ`gg<oIM0Kp<+k2u^ye%^/Cg 3) s" }Uh[U-]1@R9Zhazwű^r⊔ 7g5 @,>riGhJqr3\OVhwpF ML#+!ܯ7\,yܬԆEtR)vۊ ~ԫuG~>w5S[ocGh͟kGQh2D𰜲tyUP [m!iR[}*fz͌fh&*(ڞZ`t!D?&];:hߵ۟ԓ`y Y>P&@a owް9kK!*-,d?kF=}\D ÎE=(_f`[GX{9RlZ)D" dmZ`ey E8^uSzCaEP v* 0*$A &4Ŝ7#"#Ƕ'GB`h^f m]:k9,ob6Jw'd;ymç;(@7ъМD,)s%("J4):) \XHs|y1E`~f_gIBNQ8c: >q# Ҧ0 '?> Tӑ}} "WrﯷRH^8="tN}37a0*k(:kO!;`cq2:#: Z{[d9۷V&l>yz*L=A S-nFVI>,B [5aw݇-E|X lC&oc$iECNLɷgWvL6zި.E@&G@N# Y:޼UY>kVfk樑"h=}"M45VSi(uMUE5-ROl#H;:f K^9 @ +Ӣt-&y,;F/[h^։? _$Q$VJeQ(HT$NUh 5ڗW?jF7=GA_ ?/0@'MDmܗ<5?o~RһG N@hJWzK̳X0H%=%\ϚYUiE4N%QdDci,´ }Hv'yΗM*:0AT(c#(6 [V"@UFO Fu$x8'748'g>略4/D(_5Oo;A%*_6<:iGba=z=H\?)GXhfC/t,t(%?vj2Vu*p 8^|\_ER5k}VtA@9"ر'qL_JAgS1B e'\=vkǍGLye43ʜa3I!&#>mj{ZM(i(+pL=ZdƛPsKe!" h ^/&~i5Co*?nًcoZW'>q8];7aLG %dh5pP>7.kqʟGaˎX'((:Ql:xYMk=?Ui8ad$3V5Ttp,KO띸F;iNpRA?9|kaNJy!d7|sv+ ۚظm l0e7D}k#=~M;__ 8GyZj\Y7cux5Sc6Z#*sT3xq㯕[:kt+8#.0d~E'Kٽ,ǎh5L t|q]. g@ga's: 7[ s~]ǂ!cAԣ=:+hYJFWmy? }g-;^RWfA.n(Is - EOrTDxQyIxдڍ ??75Nrա <x> 1n7mnH1eG[ jDӖ؍M-bhi-;F[Ozak6t?Z&RӆcC_v)eP&цIFsAl\$ɑ|CxْMOV;VFWn"tȞ<3MC@[%@=e#>Km$ ) h<5"'j k?KS_1Qrk Xz9amwcE F0bKJzϚ,&P@5VǀjM۠bW?r0k=>,"4]n"{W1&g].,|A':hG 4'*U5J[A"wcs{=J!ւ^_;u2ֲ W݆[<8z [퓖}_8x`gJ$bcO Cߍl$֎}kf?Y|dMO; P E@J<P*h5Ć/H\bOƁ~r#;oOo٘Z\gyuDO>_O i 6{ӖZ{lǃmA[ZAEk;0|*rHE\Y `N qˡ-j{Dl_~˷SyPzB)G/~FH_Y|vE8(P`-?/spুȺaXAÑ2/$a85McW6c&9;?cJ os֩!1~U+ e#UL7M!@k"!9/)!hА?_ )~_/)))#甶̄6 TӱF1dJ$V%4UT(tITQԸjl%Iw_j1=yD@N+\ $i^Pozo%Έx*2:FCs+ *uǚӝϽKK[kH\mu > D4s[gPZ1d+ ++n!'6تIAxQDJH$6"pȲ VF{OҮH?̏t#p FTU4xI #:0#p Nug~oJ(<.m##{2pg=0 <1\uH!ԏfjscsWx{\lm/op7Z0Y7bU b.<RE ^_1|t/_daYUE^V#3,Kc%QuVyh=@_RէAT;l*u,폠}\'˳amWӯ>mNd_J!^dL_8>2 Q _"1yԲjz]ћ_]!;[!;˛8IRYNEX%Ua5Jt5B'Ӽډk/o)G_?wqo/xl/!Ae3A/W鿫l(;gJ Thd%;o&+TWWV'4G9#C^>sZ}M3fOˈp+^/8՜a= dPodx+@Xޙ?4E籱eUheY]itHgX{??oO @oZ?[Č2+d߹gFU3gkG=rJ܆qFD!G6eWţQcst[F3Ώ[# N\iv2!os\ݕhwPK'߿ejgoiK|IwqU*Or<,gv{HyPG:5g8ݗ]SvA兜1tyV"r7% O(eyeIH(Ff"$ZUI!uʱ %l'.c QPX<(f=0dv_L,&Vh`a0$#Vy R"x0Σ0{,Q*l#]W`1[iѲ.1 3jD6X66.g26nvIR~V Zgli}E,X ^._Pdumu¥K K6o=\˱b#+9[URTS!U]**mN+2% c~["7*8bUˢkv{UעOo{=WdYTY5(UE^%Eu㺯dzY J?(C}l&q9f_5@vgn(Gޓ+H^` 螤a|BQ:(0`T玿 ( z(@AyHYl M'@DaFn "ntw(z+jW%jVRY jki3ctV7݂NE}̆| !޽ZYno ~y|/fStkjӞٻtȴPD.---}P~᱀ U^$Z ^!+?"W_T/ p,oU@47I4i;2$99'9^ϤFζh?P a^AxgxZ($\ ܤ%i["KF?Xҏ`vY )~4, 9vXs0KQYTtlEҊ>LNmK_ٟ*?=tzD[ '0%lW/lee,9u{ާ뎯::k_ Y Cɹwu]D#)CpRzKg X"/߀ `(%G'r$G)#/P~k HҦha1?迵9S*~Έf OdCk rGے'$eW(Y# {@r'"d4YQ muC[ks'B<Ðs&"#JHpZ-Śa/QEQ@urϽ,@K!ϜxEhۣW!IWSݣ TAuWpr*#0WHFݽ*|PŃz`=iyb?]c5:#$-b OQa$ˈ8@b~XQPAw Tbm?* ?@yI#o_ip !dtegHMwՎ?Lf{LT7߀{IOCkoՒId{3Jp:iF͘2֌jՌjƈ,QE-}GU]Y B$l.9yb[TFt1&&ag1/8OeSa┈mE׏h^ECky'y`'OX< p溑]fwD$)LJn1? bVy«Bax+LT^q 1yKK0y1^bY'fGS7QG ? j^\=<玗AD`Yi \V i24MpȵEu;-lI%(1O"-y9JbH"1"%BhU/ʞ1RV?:8/YK_ _aӿs"c8V0B]AYΒ>$|/ -7ŚD@,? B!T|2g' '>6bj1!>-.AߖQ Aa>t7I}oI{]U*vaoS:­&kI4+;R?j^5Cኚ)o*鿀{Ea}qњg~5IS |-ZMnp!+dx" $̴ANU޾tXS5}ذaÆ 6l4&?!$(+Q," "NG>HlFM&O5$G-,kAZ*.n i1ilcs+( xWi*\(xExj˩wԿ %zrC-0T?\ޕ~kXNmN=XWkg-O?4-E&ge CIX ])* 6'"y!TsB͑--[}@z75cciÛfv'%ø|*Q $ xh*aM/LLuKYW& tjvujp2&`{OUa*,Fe͉Krs/7kܜxBW՜S̉'hNDiq9cX&Rh!80DZ jVq(E7+qdԀ3/8-`eLshVF(!;&"2#¬[[̎%7>>sxlxě4<^[~7f7ƃe$Id#θF-)=%)I ߹BRIT8" ! s@$gx\•~K+Dߌ>'OH/*e(El`,Vw F_ sDn[yf1c@ Ye Jd%"?sLkJ$0?X+8#CZQ1wB~;=F\4~V[,Jc$du)tKѻ ;DžBᦥRvVdh{urEsRB&}>UW%RpD"^($~eWΏɺ}4>EӶ'*FBN`&L~ty7^Wjؕ#Q:2BAC_G(M'>zSClذqPn95V$@@̽/#N tԶzBe}^H8b%U>ρAǴ2uLE=WZц 6lذq- N0^CkWmfzk-Z"py~w}g.ئ T6(-(Df@,Rr -RDy ]7&Ak%udO*/Ł&pa0#q2 EO8k,sWK[Gr=&ƭnqޘ<2TuF],PjS-Ɣ<xau< r=tA<=$~r,}4W[)7r *7)75AS`.`֬6yu &v<ԻUW]ꏱtQHg~SΪV~9Cȁ%#pNeNXcII%p i(6.&e/Hbj!`2YME8K9'[xcz =G+My*wjY=9cDd)#jJ(rl%]6UZ2ӡZVF!f^W!Hiqr.Ezo仼adD@pp|yK?Β"-4U?pܦhg4@ ?uZb=bmJ[xln[N]"(>mNmi2HehTy9+)s03p+1@ϲ,(\_Q[ {Zҷ+7cъ'|zCuY -V@}x4 A*.=,\ #y~F'G PfH+).{ %=cBng2mRZ20!tn\(#p-lcKو&}(@IͰ>$EK~^cx=@,A2˲$6Bcu=Ȯ>u83d8*>LmO U6n{UNuÌRSz42]7L@xGcYkBHnUۭ׷tk~Bwuwq{{[J aԽ)#jikJ)x46#z9J98{iFOb13\sxsS1̮X@mArWIIiZ>6YBpHKkNa `MnS;i 1Jۋxw[Pe_Q͒3>H W Tڱ~\y|xՠo63O}>V+V}v f4ա#vu=%Y_ ;\C)RUmg W%#U-bN ar:nmۻwԦYS>nc֦_ye=jE|iF6PT0u;tpYNL*e`#~J'{ZQ#pj9-OR=#w4#4k3>aLȊvN1fJ&O8Nf?Z{ggr͠w_ RB.+]aDoٸ-k&)n8H`jݩ &%Nj!*-J d*Fm=;W]Z\'{*zQz  vPAa?| h7g-~dOJgZࣨlلK5< yl RR>4 f#&iyI1D-Q`gA>  C (bE)W әݙ cd=3wf9V"*i&~3\ \2¦щ[a"%z̘1Q-!E׶c1!86At eXLhQ`4ާhж'P>mֺzٶ8ֺFDmV51S{ԤfDȐhl=q3ڳ@e=XJꤾ6 j^}6 ٮZQd@mύD ${|̭Aj)oH.I[9uwvGr<\iuMz!b<`wh4SnOz=\},+WTfǂoֽ#PP6<xOU9IВe &!+mVOe^(OOa_S$i9;%xId} c9Y+xYӒ?HVza֤moҤI j`Q;4=0g/r@UU]UUZ`hUպ*&rtdpp˹'Y%4˿r帏֜D|a:p%t -.kz͇}n¹M9:Lܫ> Xύx@^=Ɠ4ա h=MD'TK`H҄+w ^G|H8E/=$xEZ IsU7v7 `Wi:Zk7OpҌY/CS%1 4 @}=kQ9_jׂ?rȐr35ǦMv,F5XvS'lM4ႝ gqEN\ Y{Y~}ҁ(TO+ϵT7yt/#Ko:Gw^1ʅ%hWfܡ(11"}Lpi6N4`N5W4SghYV+S1$FGWn Q1f޶Դk2:@XF"IbY]X?TZ O7<䧶;|۬:2IT#췝v"1ؔe`Iب+azfp j82K}Jw(ӫrw ֳPaS[$0J(,FdXUlky~WsI*Hio $0F9m!׃F\)/iV =""#bWYK,sX%j@X*<% C?]U?~؀ގXAޡ/ H1־U3-&--p` tпc :¶o~u)/B(6pMCVCK:G(uLq d 3mEڕUi#o7A3mX|Lv-Pд+?ƍ+ؔ_oL(V0X4;` +WMy&)$N @/E28% ,قao.o?5 i%vF,t0`N°MCJR֞cV-GݻcӰg)^Dtyz.b.`(KUs|f)I'trB .ɞzlV@ vRoh&$LAF\ {"6XT[6I[o;T|0, .Gjڥ{۴n˂͛d&?vNp8d gy\w fVδE8g yoA?0qHM#<0l(M71/c4P)+*N.XZ2iDfԅ茶 ,ĵ!l˪rtRxEGHÉK5O3o +2h#sc9!h6ÿx_E;RRʁ"P*M 2cmLza٘A6fMtN"IWP$|CsR&D+`pR^sGpOp9;=xC"0MVO?% -,]Y>8pY>>` !e` >Pk2"˽u.Po;\cJϙtǀ7,ˑs+(RMaX7.䊐. 4r:N>/t+JǗ[KŬ22`Έغe݃75];.og@''j'j'O<Ê+u Tk'I.ħ b'ޅLoPv4h㫰}eU)D3ȟ)Dcb S8_oNY^kP#'`K}sXXl\pIMƶ8kjſ*j }U?} M$ `qW?h"S /* Ն_&G;QHq JcC{+vV!?wڥ=u'꓉nI|$+x8y(X=Ζ ?Ҵ w3X+ ?1^UJta~@ $mª]0x3`7$ᥒC,N1e;BQW @,,l2>".t~osBj.U5x)GIt{I'zgC3g9ywK8 u  s'hc`qUhYS*ԏZ=UZ%}QWA|x- [hgӫ]͘P|h6i.c&л"cJμI1rfZ6ڮ5'%&vM~xD@%TՇ0I#GR2Oy HQm)c kZ0?*`~d;:?3`gK'LǎOt#Pͯ4ǵMb8Ջ "P5WIM-dқ&I[ ZbaZoskІu{_XWj5]̓ Kkq'즷ǖ+|tva֧kk@Ƥ<Гdϣ)_E aꅕydٺ^XD6;_u>OwMs9> G"E.q8uܜ@ Ez8 " RRsBϩnUDסUyUcmQɣ0/m[Jz<7g+QO{tmYW^C w87,ˤ{2}{Ƀ RanUGoBO=wśiwopo=ߔڡoxM {V-:] mtc~2*oY?D|#[azMwqȯ]Wu{\ j }L{oP,lǁ%MA5ӯ>i nR5ǁGD//n%8yp,'8M^\8ۂ?Y 1fa11`MIcDW7|M40TKxI. %2NlF\ `a.} 6R}c kԄlK Abʷ%ECJQXF+5v%JP"jc~gFӔ˱5HŻ$%Ju?uÄ"៦ m&76}ӫqItפ'ӽu|džɪBpWV绂[6kQ^,NyAyD' =y^p"4!A[5J{i P?^0mv>jrN鴀"BK ,UPeҬP-(@/Q|.?W'>ׇOyLʹtP4_dre29'gضn*O!N}@FO 9<7a=aqߪrpAc9?0]`BexDiFVXEA%qI[X#P c1F+0OX? Jن_Δ#+fsqE|(~`ěPd<6>Y߃lˋkMU0֏㣃Hm-7V&+:Ժ==O{Z [ۡeD/!*2_󹠺v!K300Gy+ׇ|yO_OvGX#78$}rci= 5~bqSƷ<tzX\iA!8,!P&eUDdPVlcT?:?ƽ^00Jd`.@?]/vToB7kWhM)JT oֲ/Ղ>QO[?+{W1mVuB;Xߗq!]GyOw340r5/a$s S ~8A1䂢0E GYb( ld?[7+?y'D/g9*i'Wl Y7d҆e,NK‚Œƒƒƒ~U,/XRǒa¾6mK|K=t℆)zf8a ߶ӊ;+|qm}/U;20N$N3Nh>ӃWksp`ED 59EJd$%Q U(8\Gitp@_:]O4 C =S-QB&z iv 2Lz?wdLwG)hzFh &I4ݾ[4u^I~BC(͓<.N(_SDUz\5d0K`2Q 3 \L*'sPf'dܤ6.R`BD 2 PE()(̇0#ppˠs  |Ӯ0H5eHS{{k-77B׹$&"=VG aK)HceUib#6ߩSo//D\robLRF6ډ Vdd^qqN8 \^b4_I%(B1Z Efegq^3e>?Qj8pmh-p x05eɣ3=FtiW~ KG' L~D*|碼n!l )= ZtZQtb\`E1..3}ĥ#g3ð`XNyDeFDQfp0\xP o0gWx m\ ߓTTM BH1:B|-ONNdqNgbݸ*:X)5OEOqP A53&M}&l&07<+^A ψ*wL~epgY~uizgnN5 fpwA7~PG?~&SYPxPOC3q*HT*꺟^E&9R3S0Co" ⠝8SJ17gعݮPzWP?WPCeFyVHVeVHJ%"Li I‰/3el?98vkGbMgcԮ^&#VO{ox9ɽ84#g3:bnl)8)x8]AMGOs\0d: &30| .**/@%o2}<_U,m$S:gוQ:gnsձe'vq,[_3VHa;GgEk3ΛVL" /pxQ.^kF9I #;zE?5dΨަt >,^XuXi{ 4X$4Sp?߆CT8]G^)|ΦAbӴ_M$,(c), "c@j]??x: ǫ0W`ĭ[szd Q]rN_=hpyϺFS)TN*f+o E2X58պ*<h6WD^NUZ[q%\&(x'dxAe֞( ~h?Z? KX2tGT5f-^h|&SzsD8X~z|T?Q"{ݽ+`$XUչd~y+ѕGA1 !CVTk{da zޡ<Пz_"#]Ϯկmر 3nc'wr# 箹פ=yqEW`Ӹϓ_-杏U?SWlM [vӻlطn5wWjStzdb߅ >P (t̽S7wGbhn{g%jzH5uKb$ʢO͙ӣ5BQ%(9>BO'8bhJPe>>MC=a#g𵗿~ۀn>R}ێlqEYȱ;=7azwI};ܐŵGY kIG/zjQW2zsA~n|ߺ~b~z6/ƺ-˨(,?rKV3iBUt~<"j8bEb ;ndG2dkv[>o6n5LaүoDiyU[w=d$}'͚zo;;?_g1r_ԗzr>I,:9ȄQYG/IWrN?kg 䑨ws\2nKBI+jN+aUfZJfjk6ktwih齃s k1f2,&$,#(ɤS +h(eJ8ȣ_Br&B.? WiZ#0,32VCˮ ZvӦQ-rcg{jc(d{rzQ)C=ǥv͌@$AOpc0 c8YQAY88^ o`EI"1y?v?aF_ foOfj2sv,+y ~ɲTmVXdf)ʦϚc/q^XPqsk M䧺3ir֜D^nץmXd۷t#DG8ppW#ЫbOY-bRy|Z$П2M  PEC FuB'I(t ;P8&%?2_r * +0!ɊIO>ϥn#iiO5wy֜^ {=1 wXu_Z\o<4[\:yfS2˗&ڒx! +@֖Jy+$ʓ6$jhY X&e=!e)xM.{|OyB,2P __oʵ"7@{Qo OQu.nRёƆE9ܑ3X~^>_Dw2?(k(uRD(RrnY|Un< aΖd?iVgz" ?kr* 5MYW Sl(އ4wØ%Y;1ܿAd$x?#F?,r>_4rǂ =F:~lY\4f(:Q(*fo^Bޕ`/mrbtN4VE(15AĚ6'%F^#tk* _V{@?q@eeempx{'<6{̷(/qS| Bѵ!6n▩ @§VrvB#v>qR?X kEC9[Yr\#/' D0A` TFƬ`&$3{gh5B@H+9>_5&X?掬cV❊y1?cw HmM%9΂/,T]<>cק REGZSPwr! -yrD(ǫt;C5%x?B}4- )OO%<=Wӣ&TyϼmD;''L^>Wr6'&o LGC4d6%ZӰcM a+/4 P Ppl7CL緌¼-ns̙ĖzCySpj2`ˮCы/_{N.޻k7oX-ww݈g6m[B!j^]իAv6^Wu&VhBb$VHb<W\w8XxIytA4źƪKʋ&e0il r$7+/_ B^o2UWX5H8Tif A\Z2UHeMC QW?kh%?ݕ/ikCU9Oy{uYDnY}^=3ʝOsUH`E<ü~_yOі)/5MIgYSU%ZN0UA +j*GlLH?%oM3^+MTY??ѕ?}d&d ݟ&hC!Hll@M5tFB&5![:cn&JDQRqR-^2|~_a a_0p hWL{5<{bD:|h}ߛ:u*oqiϊpoQ=}/֡T`o ӂ!1j2˼f N81#J&aGNd?1qkO?a7,? R`/5 lپ=?l˕7;W=-hjF9q}÷xu&Y+F)F?6'eHsLxyV&͓n3r XahYvҀ(`I9WTCIl0/vP/:XK94Y:?$>?Too]G.C3w#4E Yh\ WY|SodTxUc%0i* & "a `cV" s@Q'?\+A󖭿&}4o~}/oxiyD?Aj! hÊ34FK΍pl)ک zsl 8M䅞>GulY E"=ǥ9,dG9Thh>M?+`BA ?Zv_i# xp;nO.ܱǣgT/İ"q0_E7ߒd1 M{cƄ3ʴ O<*XYti1epN@Kg/RP!_f@ߚVkYk0/9 S6Q/ۓDm|]>m[TfQ o l?J&x*C3=(؞ 1/BKUEo%beB<"]damɲosAWhᲸ GbĒwD'/Y#PțVv\H 6dN YVh"٬[RԓE_i#_nLHC?_s0pytF*+ HA`~Ё PQÆ P5[PAXH*R׳6ѝL1+<"cg*Hdee0ĒٗOYA+C&G7F_E}{MXTx{OjWG% ݗE}&c}]}m[ڈs}wu~t0@,\z2vK'mw iMROޥ~O\dNKعvwAL`ZVh8 BV-U/7&uyL⊆aWt_b>J̘Nba$9l-1vgrţ➶2 "7vooV[W=7m@m~;jA}=*L-]_?2*ӿ=n ÇzOf ΨNAM>nS܍֩7onI"4:Jt`A4y7gJ%+&"6TUw!DA@(b¦0AsC#>AgAypEħ,ꈲ I{k9IUgAS[K9EUUʪ* ,+EiN%]DMoF˰/oy7@/םa'p" d/ m28NA5͊X.@PUrc3/qWCїK-x9gH{Y~KOzYT,SYŢ 1,1Yl_rh/%cU3:\AP;FtOXP\'+CFYnDֻ:;y#-wֲAk} kE]*yd-K f$JN9y'aȉf"3~xՄe?wP0.=ldx]:wZד~%&醒$XDBI(L耫S sC',TJ^lzFj|i7m3u K-uFf$r@wjndd?$|\}p8;Nƨ1Flr8:^=,YxglK߯֟^˨Vu֟= % D?R|WoXTνǩСw\hSYS+qڙXqȜ̘}}W d;d. {|2S BmG8Ig.V;K1BqvA#e& `޼L"S#Y2@JrZ;KŨvh=B smU]n_=( n@8V%~;?F5˴2dtuOt50 !mF_#%aAYwU~{Th;XVU8X]loTTT̩pPRRrm qN#qZGmahB3&*STde5g h#YEYk3#zҿJ`W{3E+=4=ٲhƐF[`=:]Vgd nu@1F^v#n wM ϹN9J7 މSM5*| yZYY2%wfJ)YETitI%YUUiV+;͈~OJGb"P ?l@bVdi?,W?,LU~ )ܲgRO=-hZQc5,rJT=Ʊјˌ2M6g/#u? ?\`ϣk!,.Xt6z # D8= ٲ<Ќ /xOFD9%ZJdJ{u(Q"߃7xs[Lo#N )JZ) @Ц(:p6챰@i %E]2C]7PbM]N.u)sIK"yYT*.r}Q>*>졏J mi"e+e=Jz/ ok>aHNԝ1 P]@CMvY8>?IV;aR\[+ [1~f~I:@4ϰsr̛KyV_;j ;p WTvAΩT;؇|(]iI`heeYUUNRu& 0Rѐs?) o{գ{0L˝6 F2&A? ^-H5M@μg1juWeVT:^:Z(\ WhYrɓ9mLj5 4T}#y}"<ݧ~*kCL\=Zc ׼?LE(x |$KcSZhZAY-*2juIsVhO<'6ca @ 'X ;Qwg\p1=w!Y0MvRza;Is,]CEX>{u =$vƺ⛋͛#E4/(Sx7;- 9nv!!cm_).6th*WzӇq֟83>3!oig2)L9h)EN;(g+I37d(Q5VDQcuZ`E5R*r4jGI i?쿟$d~فٟHq}U`(@qdG_o[x=jL4x4d=G{;֫oQgL˞=.e䲛.{7v݆qtk@g*.Zt@  ]x0?x;3QZuE"ڀ'*F,)22Ճh8kJ7`xXq6u mw#I {MdO텍%Xg'#-_ #x:g׶]>K{$ϒ]G&ք6kTAˆ<;0l<@< Cp|TDrQ CQQY$Ѩ7a ]4Ӿ /ـ?-_(a?s @ҝqyD"++ƣ?9l F[MF\u/ZJp¸?a0MnF#o͛pb/'6 4N ͼbpI,%,:K(4GJY*cdEfx:yCj19 sxo2Î+n؊"|9=F{2گvO}.mU¡vW##O iY!MwϾCOqȵg35S⤟X-i_`\xOliühfkiKO:)K ϨX鳺*h Q %Zsb^=_OvtiV5gy/3L\E͠m;=j}\aѽZ4r;Ök_p7t8k-L ;{~cK.r ,)lTX1J$ +6c%.?%俸^ Ml2 "/D g9/**<tBFcG'M&_~bYh|ؑ [H4OոT0YWd:} O!Fb>&BVtQHXHf99nR:ǗT,v ga砦;N +֣V-a@c Dxb Ma6.#WbKڼm;{ūga2z[4totB{V0B-Ik w 9^<3 .e9'_Y- O5 g_YBK32@#* &PPݨӺ22)?p|f$!ir:mZ4+c :ciBex:"Ϗro"7ܽ!>w\eM}˨9׏ƨdYL`˧Θ{ 8ރ.ooID#D!B"Dp8ɋ⏘?7ҶbcdPzT]7~$2*"C2~~6^Y(b@![=<-"GebeINce0 Tcq2 @z%& sFn' +UtE@RG{{آ%i8t{("+"biIo qdr )a."=E K[Z?z_3 ӽ {:R~ ?^f*o^pJ'Lx\ONw%#?>p?\)ey1,}b[ fk>=(CԄ׉2q;mnuM%(;C+jwܲt-kF{bwUs}>wkrOk #.нr#AnWv9-Ԅϱ5M_-5t?I蟓ydDA$@˲d*%<+j(w&@w*'c;l1*@J񠺬.!i^5lͬ)svqwڭH)wiѷ%F읖>Fw^7'9oxjD1]3D2jɨa_!t8 d#862=4Ʊ$M5QUcSz@^0ƃfnG? VDVtVfYIMS QL^EMZҀnI+_?- "sLP0W9b}y?p%AH;W<=Kg15n/NTM,NU_]O ^aޡ=>1 )_GMG맣鱯Cjg17'Q_E%42{D?rR&I'[eOoJ_[YaֽV[Ȯ@sac~p藦832rB_߳_USrjL>}ֳ{q+FNW5?kM_ ֆ t_V3&:1]~߆~Y7җu<#r+`(ܗ35d'A}%VwR^Q}٭IG?<\6'Rs pKTsd?Ft[)QWfN8YF fO,.vzt^͋8 /S}a{WBSq }jn {W݁)NڨXsӓoǝ\}7KzjeY2iQTij/'*jI=7$;dTf0D8ΤN`cxƇ}e5-;\\ uJv֙Y= 3Eޞ7܎¨ifm \yנg ˠggSqKGoNKa7u%NWtY4uVtMt4 VM%?, HQğK .1\.1rD)Y9su8eLKSs/|;喇\Te}{s‰^K2j#dzaB zz)qeFqYhmn}Yw.C:=$ܾdd2X"?u}$qw>3ي'7xFx@  fw5:$R比D6,uGoW!q7ͦ9EQw[9K/GN |awBcJzdj'oW!hSTXVW, IJ+r\>/LR`) !ߧ{k jL( Py,r-&ںy= hJ: ,A~b2D4iNf8Ւe]IRP,ID`͞I ?>oYҽoF~v%xXb9FAWWw3pEhP_ x8 yq۟C蒢d/s˞K/D(V )z@z am`506Z"Mj3ľ}HռE C9EUTUXV ^cYQ' xᕾ^ᕮxNWd'{]w ?Dh,)gRoTʹ=Y7[.DT\s ־XFL=DȵYs% _? ̳;imKyJl\2SU=Y}! ˘H"𺡋&/i1xj *$|yA BdU?fF@t] @`ma sג1;_~۴Ykgꬪ+ sVm)5q:wq/{%ǣY@Ӄp?`@S4 _+>`?˔eY`T]Eْ8SUd8Kio$SݎbC3_?&(0!\2$!fBEj*1`(QA/1앟|+7;GxlNDgeY*a_U*?pU񪙞4!C}p(9EgtIdK5E8UDQQ9a?:. b=%$W}F r_PG*irSARA]II1\"alL w-m[(:]s]Vǩ-:gnx3[}o=᫉7ioo7w&:m쵵3snM9mJiںx7|yŵiKs (B"u5ɔ-9c$EWM9t,ʬԳE ?5ϟݒAN/v= 22նXsW|=-#i^l.zZؓbxdowx/eL}Qso\;7!C1jjOxvI+!H0-:+'c7') j4#ȼyܣ"߂ %KxZ~"}w+b]11ʆ"{vu~sIV9_qԔ!77wwŏ񾴷̩~VG= xT'wmЖe`B.PZro*' #ǁb]bMd0(0`QOg'8˸0:t2 س3lc0"3̚?Ug0imUK6-!t㍾y?j(0Ñ  u_dIY`GѢ,)&ܣaoGz]?@D`6x;U@qiH02ms^JJG2^֡#K'Z} .jT!QxApXiJ(%̩ \s[;^gK,N._4KrB$`'؀?;g9O R b_ YVa! 4ewcQb@Ȟ[3MXPN璁i %rrrTieUE#'1 J2*7'qeF.?_=v_tgljn~&87~7`o[eLU +8gWXbTŚ~E p$eEJR6cIx-gQ޵Z}X8YՅ%ʰJˌӪȓ+EeU B5Ei8/e ـOXk8uw.)FO5^S4MuXa%@xIR,;&WPJXo6|˓ Ǐ?N/$Ǫ$s$˱H$#K4/0R Ą&ܣ~Ǽ7 K g sd"S8=Z 1|!/pUr'~t?k)U0RȄ mKreKטӡB%` #dr{D * ڟps U* zσJxx Y؋{I^YzT)`{gDՠK{!C侉fEO@GzrE;fۦX񬦙W+颔/%up/K@y_;Ĵ8ar㻹*tFӎ{3kX")v\b˦*։_kVqfTVr z\BphcCZ˦9zQWL%}{1P p̭cTJeRV┰Js2eeʫao?ƒR <(/:xpjwAh!HN|hOͽ~=/ؿi ;TLB>_KoN/3mҕ'J5\;=[VGY*?B[Y*IiApS"*Ê,K1B&Âf)ȴҜaG7[\Bhk\bhP_E׏!$Z&Je]3bğNXOj$)jelNB)xt=dP}joևѬu7%d8S( GE+ b)%YJ&ܣI[E1.lV Y7\DA> 8L]%Hg#:>;.ds&TjokS[mvZqj_wjY=c(ᳯUU"UI_T$A9iQ%Q5[ ?Rmo}`za܊QEf7), 8Q)OaJ $GYUJDFXio vz 3*5Y曠 .ַ ÙKhTr`~x T^zB67'?C5jl7IZB}o{)w ;WN}!@)[w3DwmHtW-4Q 6ՙQ*555'5Aeߒ`3]|-=}J {noLw[ϩb 5$a/ɾYiFE?R8UćՈGKda$?I]s-@ a.;5iwA϶u 2Tǂ).&H&,MΙs kǘʰo_ۊt.mJY=?SϘs8fc2F|sWm:W(+@vAIF`p~D&6ayMLyx0l# I.݇(^!5l@jkm|%Ozsh_|Z JYb{/Zqonh,F@qy٩6VC+=myzD+w{s2 n܊0U@S;ЯA4%WҲU*74o)xC {zo y,(PPQ$67b4O ,0*K[SD\B]Px9e)-Y]7u6WQƈ04-͙3j@ NcQw˫o(.G OKp)PNJŰBQ"BK )4tqS(E ־`mq7梃+LK5 <8;k2ItZ 6^tE9i] !T*j3r`Gd3Ol[sRB:fe NtM;֦<b=ތ.oF.oaW c/V'yGZ!0;I 5FTj,(MFES6C;w MIpjɗmЍ8\TS/^LнK<a2L #%}AH3,ͱG G.fu="Di"5%w|/@O݃OHG&rt[]@0;<=_5v45~gB%qm0l6^~O_%[]e yo+[P+B(/6NnY^C)p2Nj*ʼvs09UEzQ^Ta]$m J+ߘV] XmcЭ~Y(n{{?XۣG5UݘT4hm?]y(\^p +?u;[=n,9lKo\[)ڛ#su ѿC#V"3:$OR1z}]#$)a,IQ}f3U3G8&n.ٵ5}p-7 }#n/t/c߾4 jjjצo6Z_:xщ {m>#+ux#'LC'8EUۇfݼC z^˧uׅ~smcܾs}Ύ9UtrȬ%#q_Fڶi }U:@I 3tDu]l;կ&uC]nn:g=}RmꦩUv>q"p懶>*ͿN:!:b+BIAd]T %2* : "`Aq=7:x-2:@j>Nh]{z7_iO ^}gf㍋}u҂YwK}|=m3FVN84Jwך=q༱CJ>*}o٭+>%Mߝ2>z\߬'wfmC^4] ݅wǿ}_0nl.3RҭiUl Vm7oO -}y4+q҅:btY9h 0DjHʂLҚDH.qGHW _s}?C;˚ -B)?\La|dm(1Hk.7umL(rY"wb+5ɐq yOqpXE*ډmx9Ǐm+\A^L1 @LN>c d(I#2'i* *2ʒ@ LctV2'p##yJҍ4fftۑow!tϽ=YG;@]^u}fQAW4W:§\#8Gcy) M @ܠ,v\+TsCbQQdx\;';%'hEk]qcd2Kiww,|"-;_|{DךM[_C~f>&"%r[QJ|ng5>*+r=&s_M|zZqƂt{OȓvMq_ ǿvmz W@g=WrڹMi"$h j(0RJRDJtct&qW#1}?.ѷo,]wB`T,] M. [k+%QdXt\q:JƖQ*WFhsMy4J[FwokӵT;\}ԅy_ ;^nm %F_6fH5›8mj~I,rV7xRuZ'P3=U&p 02o_!6˓)$tMU5)tN5thy2‡@>P"- 2V^^/[!xWªgW^[M/d^okVصWbQ^f}(3{{;4?JINT)5Bj((V2^IF$5IW.E|oʚ`?yR p_^=z,`6vc -3Ӕ|A|$uc ::J_%[88&P#ayR_x00`bM!ɑSEN742N=xf3*q J#Ir<Ū,1a%ID| g[_2 Bp5*ٶvlo{{ c֭ܶ.muU42YU4*-niPgرjXTY8VMN@2ȊV ߥ'pόL>_ wB]umO>Y__ȭfM;/TQ;mDVﭏԪGKS܃dMۮZ,p2dj 1M鿯7Z@/Mɼ% ɚRQƙR|V)~+KAn%s_Nuoem/ u Jv="B;8^$U%YXEVTQ8AcU9|tf_C>!~6~էV 6]P/qrGTkjj;0”́0 <"-"K* ,꿐@1_> ? nzE W?wuW|O }C\ۋ^nlފ¨dE;A7^Β4a}WdU`Nx20[bq"+Ch :4nn/0)0Z~:f9" =~kh?͝%;jeidSS>c>,}iܰGu3ڌ`Kt~sT89Q_Rϳ=x_`y9ͤJg5X%iQdAte?bOF37v_r-ͿF0湻ʞCLJEs]Yc0WW _ur6χX3𒕧ТrG[zwcI?]s%})>f'/SVD4Z9-Lޗ7Yd e19'lZZ 9~ð:ӄbނxD4Zd%UeUFS4F8xgE1"~c8pG0ϯ], Y6\], +V\Xkg>Fc?DK]+[Cs':[*/:< uAhlBDBi݌8DXmw۱Ԝ^M͚S  9XCpм`^y\VI'w a5Z籧u]u6Qb```dRՑ|wNɇ[@ASJ lyaiö]ѾZxgc84Sle\;*:_v<%?ڎ?]xUw*v?adOD SӪJ,[xdg.iOƧ@cO&dqU ,tI#zT$lzQuCWl  soܞ s`O.?Y!zVfwk|~uY#2 R.\. ~?ܸ91T2Y) 㽲D ):oAUa&<Jp,),++HUՈ`DY)t6_=8_FO8UdYEeR"tM͙kueS21@Ol̉qS50t @2tu뭋G]a&˗)zYĥɦNcDċ[8[cMvP\\Z\2{R},,h|xV^ /›W&YFY+ 'hHʚƓ]hFP#yʛ20=@/7Iy#vTs: B/b,{0|lo,pΉ MҢgE͛wB%#_gV s`lCƦV\;m rSiYo˲lцF=ma.YMѻmA9j|uYXOxTEYS5REUdXQu$Z4FZ溰I>pߌ~->} ݟzll< b32#^4 `Wg=7~-J/QV^ƤEV- WX9 SQ~_u#*[ ,iz!g/߉j"`^l"iчJ$v硓7MqٍI7Fi'J:gBU01r]]!@ rHDB0A@'r( (2rȪ #8̠K`@ I꪿SE.c+ׯz}ϳW~`(ȔL0H e\EDWq[m ވgY 6+?~cqv b8v)^lgS\A* c!Q6E`y 鸗PwևcӖPS(=u6 ݾlY/ybtMHFx=ddV$ˢRLHc4~] ; ~Uo'pU11ϴ(H.cVe`#}& _h9FUNVdNEV=HWZKr=# 'CpCHSBS}wu*"[۵ jup?o}o=hUtu:= ɏyNsSO^Zyl]`ykPlHIhSy3ZYiK~u0tyVTWZP\=hV4wgwN"A+TD7EbѬ:;iV]XciVf~kVTO Ӡtpk.}e7c:Ot/O:# ΊB(2񰌬6tИ 1!ҟ=<_av!%MzQjK#{FOx爫UŠ";G[G]o_ j]##V93{sZ4誣o:Աǖ?-b֊|k7ǿh}غ?,N?hUmVM>AJ.Wh%U2fx3=1uu?|wK~(.u֒.dC["Q89Sypl" 'X,-|ˣ@3O/:Ǔ>qZ r,GARo+3m/0X1h5Jj婝sV'{ wsn+~,Gigr$m> ]N}C/,?xg4|gnnh=7r~q‡#Irٵy[k!͑9K"s/x)D%>=ғ6|lM^~{t֭κvxg_ÏcgoPi~dg:/z{_x}Ec|+~Č+?xn6ם[K}Xf!n];fK9狮{aIzq|=8񨇦}~W-++Įfa%@ߺeogUAxE%hNBU XC$.pEA$?3 S 'O\h#ou5" h~1ptXdEź~YAeg*`fL.? DqI&r< RTe=הM05=m9kԃXb\Al!xD9;hUbe?QPpz _`&O4? ! x<$˴ ")P~8oECߠX .i@\pO8Gt2KhXpD-OPrIti$ Lص[,|߳V~#UŢIQ1ʊ(9u-.ԋ3ƛ]~8 #yض=#HDG0aTM?Iބ^vK0"kK=9(r2' < 2=XBUaxfIVEnex-*E?CtnזmS \7ZIFr;_DܹZu.;Wm0A'\aENTLsEY6'[  :s|,W!7,\XVg]8;v轚~7a?R=I S" - <,fƆAO |Q mǰ+$0ZXVK:PxӽY?,Dz*͜=SO\3yoYOX]). F^zI#gu 1棿$0o1r~`I<#ẢpD }L$ߚߤc6C.8K/u?q<bFq0cĸ@C]f_l.8)B.:˰s0ߨ.w>l֖cß֦,_Y⑋}بEz 舘z59嫋-Nys|ܬOƌh (88YpN"BCRUT)Lxz,jSŰYmnجKݔ>囩4TLuN+oE?q-^ѰpOgZMx]Nx ũE[lhlZ!Z>%N]- {zIAˑ+cz=Fk5- ? '9= p>$UdpU$Eoο|S EÚ%5 CO7owi__X@ܼ_;0 +ŞմM|~57P4mФ7W]nog{@b%VTyOUEp%3(K@zD%*4IJ$0M*ҪDʍw ИǒÆ??Tx;˝՘9TN6vP-kuDJ>슱b3mR|qȹ|Mg'_2dϝͯӰY'5쉽ӣFޞy6PKK{fj 33@+5~o5 V![J3;,^Su&L8r߀nu# )N'R*:yI%8W$\S8+$aX1Fc&DQ $ r,Հ8vRu|T>=Ӊ}%/0T `؅{Qŭ ȅY;=9y$ $BKUe$J(\mb6&0DрwY6ۿ.Zjbۛ_\ ]W-v_u./rUF8</¨XetNJ\[ч;X8f ;:V7ްD+.Wt2V;!3yǞzkS %IHW$HQ "8)"nRGa10ФGSLqcEo+} ӄ(1qjh~F#_K|,::x5u-MSa. kS ?J I"ݟVqid$UR*#Ȍ̰?q @<$ci]@^(q&H[n7)HB3,ZjF܎Hl~ju_xC0b\Hku#v7GRoj]+w?_"XQ N4CJ4"WJ7|klp"#8 [ςvq.[(@x̲e#Skd I7$Al^=xd~?%QȰ }1Lև`X*M{h# yre- 8mNd^a ia^8u 9m~0Dߺ/Ha/HR۴·N y AK#J+ ATdFd9$Y8Fi%l?n=m@;?` d Z4#(شG\%hZk XE`|'~sǴiNfƦX"S/GKفG]iz.ś@,Ѿ ڏ\ZRjotS^#qgnPp) V= V)=*# ${VciʖC? oo#|-+|B _DN4:4 bE[H̍r_Aɰ ̈́0H3쉿G(kU. ?y*i?n~+c({h &X7oK@R] |TOf7CS)};T׋G$*hC2" .,/?EAAPuEETp}¢+J $9i2~?h9Ir=  RId䊋 zDߖ`P1/J0r򌌉;]ĝNS'etB0_u8s.[!yYR FYotUNqrv)fȥVC Q,I3".}:vﯜ5JZ2DHɌ "\6MˠΕ>V7(V7(V7ש&4[LZ?=Tƛ7N)[;8_ դ z1Ĩu555@3“"bvŐU@$Tx X "|-8P X5Vb4&c::q(tf7)K5ۊ6+C sxyx7?ϻԤ|;0P/VdC?('g^vcN"9ZJ 3ʎ,un!IFJ[IQ}d{ܧol Uqͻާ"*WS5Juc`Bp2Z:nlO,Q-hB̌?oƋ%-!DRlT,_`0@RmQ -El50MJMH@b$(kDZ 9ZYV 5ɨp.C?SGGg&*ߐh46a?~;¥,93 U0G؄^5 >0B? }%틛D]:\ u>BS:(P'[{m +N]ZAKfs8H Z*pZ"?ybX^:&0HG3Ɋj{gq%;? } {/c?ܰΑ<ݽz?wM+f}}Ig_yU ΦG;^8]m4v+hQM1"tǺj :^&vTAtɢ:TCat % d6h(T]j{v}/<> 4>}YK*}v=ι>ͿnN.(uuرΝ8S=vqb$K> Hk/:dc_k3k \hl u!ȃ<oʚGґö[cDjd,#/;:BWF#9̴ds>2}%Hܫ%(K@jf\#b'cRtoTfߣ=\[#,O*).IoW^t^zA!>-W\|Hx^yɚ,9֟FoI? UefҨ Ԇ(C|aQ'kO> 0͓(%pX/ 1rא"[濢t4~6?*r:Ӧ\xַԬA$m|P: qԧ+PyBO/{NX*˕_XPF9vn|iK^nE6tހlNeLw֤|ݓv7gp),20)_~^st=½_?+J\gDX)Q9E'%PXl3?*dWզ8P)?A0=&cDHe:;en!4}$SmQpЁnXFg!zbu7t#Ww^g[n׊~ꡥܸ+s-LcWhy#'7c>%,sYH'Y:*3r< |u_45ԑaEgE<$TI ' $vr9nT's+)%Qǫ b)R*JEbjYzAE\}|E) +=S9q3-]#8`4OӀJP{]/¬wˆ]Mzm2f}v{9_~O7j.Nۼr~V丹{9osPSVyсNʶKq=$;Gumˡ6xA[V/J螺)g)KuvRyi+@,-qy|ܠ7,13p֎u^!тknYsO@gͩUowۗg>u'zo- ےG+,XĠR`&kg x'{ FPx%"F3"eD׈ )Œ_Q!(忷oJύW'9'om٤^:EsfdIr{{FODK!?kΝzEj"Oo{ !#^;?6, kGlڑrڕvϿ?CjmS3vh߲ڟ'ߴDTFiD)Ǩ9dN|1@<1 >9ӊ?&{Q! .pwc+48H G. ezZO} ИU~j_P(zؽrFb"bi8p~" r a3ٸo^Hf(?XAW$+fJ5фf3 m&uD=$+A ?MI /6ǂ| c ?zv6v|̀6l/6CTzHXf3lgl6~LMyLC󘺚:1ZPuNZ1$bBdOOؘ:h-,S𦭯-ڜA-Yʜ|G)pt> A](rKyB1+*rEV.HE#|,DX<ӌWļ(`XS-l!6Ao<h Dqː%xg7??IQ!_?7qm :r,W^X_#4BC.CcQVigLP}]d@nËrvl{Q}mӇX=x^+ cʐ7+s~Zqߪۆ2k?1;T_ >knwx- qbɲ%4I{EK3ī22brs^3C'*:`[؀[@Ӭe\-MؒeNSD9qo PI8<*oprW.RBv"%*HV/24bS@>K<΋AH̒BpSp?Ohe$t)ΜBs  ({mcg[4`ٯ̇@0ٌ-c#gt4UQGFyF{2'+YJ9!ɋ^pj8Oi7 _kclZ#r GdΛwtX'$J8M @N@p*\YܖԤ>hFBL)!Q &ODS"P( ߡ 6HZܢ^_8k\sDI*75-!}\6ڣ ?,\ Xo'Dkj۟c"1h bE)FIn6 Gld7m?8$=!aܣ܀*t;:s *B_q e;>>Gz$Qd9HgiXLI)фStk&0k7 б _6@!٪68gęiNG  *][näOZm_NHY-CJj3aqL@zEQEp}(~珩E-ڤF mUۄTilB[xP*NQo~Wxw@om3Pm a(-i+VamkXN ltkd0@K`n' !H7hㇲӵ͚1F$8qcuO$4iN1*f An#Bozö,^v9\w^ xm9)v0*HN»OI?^)ް:J M%mzIQΝpʚ_~VffIndvJ$El۽hy4nLR|={OyYx9Z-҉|1q,+}rCyK ,qԌkDk1OTO@? I7 Pg`61,48qǨ+9 Bէ %PN>N{R;j@dS` uݤ@PV@ A4K;Lgv`؝;}>d}ɕN=Z7>Ӭ Q5$H@hBq2x%Ҥ d'YR\a?Ot mp mbg3/X g'; @s+,L]VYF7^`rdZkTu89o'g^P{tG:ulUbQ)|'NCi|h_CoI1BDgo)tZuЙAtPr6`hVz:&zaX#,nTZ_I 8qG89q%P RD,Q8  LH" `u` ЪnJd?0DTAW[2e cHF7(9orxk?Zx%sV__A.EK Wx(j)l:@9^GJ6/kxs;N j7jh%Vdm} $C>ˤ=ᚏ4_1 h TAQE 7ء`!^aaqq5GܼSV]xf& pZ;#oB(5&2'Be'IH`)V8%sN*p?!(Pk!7͛8gE<<zt(" xB,nَe^k/|5Oi.Kt]*+}zV}txR} ͥCϭl.~-GwfXZYQ+isK+Úqq #q2$7٤Xwvc ҳwEJˬaOC@\ȑ"fkdN6O@\' %BtNLQ406ׯc:;d!yBX k p_ 'p Np5;pNx5x E< EF$,qh>cI\tII2.b<\:>c<>X "}P+W/~r{e.ҿWSAsz#H*(H1w,aWw_QEymKG{ͨiȜA($+('\:!p0V sgQAO _}@PC> &|T~1<#!x!\䞄֖(FbB :7GZ*tÎZeeZcu7}^(l? 9U7tճ{,j`G}YDVʞ6)Tg jzmrw@T;R:ZY5c:q^כ|jO{x~wO皡tiހͿݭ}QϿP={z4]'J;!QdedH.%b2$+3HJ È1?Q_Db,GFa6!k{?|/cJK\㡒5WMhBk}2͔qƌ$1QrSab7o~•nʹ}jKCO97l+h|KQwY\-DY%?h/+d}]5X*dN;G)D[2L'޳4h%Rfv- r2]?O ,yМhQR@q.IUX"?E-$<:G6/op 1_}<C 3N+J1MSugÇt__{Z{tT:x-eƦ`m2:Hdξgk"wú^0;\0aJzBJR RӒ0PZ;qSp yWn+'8b4<JU˭[ۣ [[{@ۑk_/+Zf˽,K_;KgZMn;z6䄬c)-?'-YCHSȟaíC,\Z_x!}]nr~Yv_ԶZ;8s;g,.|.=mqGvZ!Ktf̧ `>K2~DщpzCI=8?7?^ջK~7'G~y<>_ggdu)ه<6TbH>hZjv1i۟_UդO͖~~p& Ozm-}^)v;8qs2}-}{{5ypŎu_i.Ys@Zd?0Tր &4R ZU3TR;Z=uF#Z(՟LIE E2)-"8#IfY@5#! NC/6Xc PëRw {@OӐoK$幎>)T3NyfKsQ5=yzT&ݬvPNjؖz=knI+ťu1BVJzu]Y?\>q[:C $!ڲI&p8Y.Rxd &Qt8?h܌E#BC6 #U<(^0x>`0a1o)a=k)1˟z CCbc;+hk ]$ Pڐ%e %I8B% `L`xA"`\I H$ap(CϲslhPȂ?{ӹِ㛏`wַJLe& )_eTSQv=>ul pt(RNtՐ韖TI!"8ԻrrS&kz'F }Fi`!WX(]ˆ5u.o_ ~Uk\M|ӓZ}!Up>ʃᐞl`W9PdˊO>rޢ^ozY$ \bI;_qٷؑVhKn n uT+8YuQ8j$g$B 9J N?AҦO #BpZp{ɥ(.?9|Sy[:M˳( : C7fv/Tbucֻ;;rQ J:\L,i񼃋;R+۔VV.uTmRD4@+ھ&h 0y@Pf]OF.H:(wy+<I-bGiEs8I+4HDDm>_Cx+10Xc.U:V{?[lݐ-)Ɓ+67rFNw8sSF];REIƍۣ_j;M}݇iDorWVn\ut7A*neoڳ'ȱBД%:W~T>h Rؕ ]-vu+@5 #tuG7RݑL]ѫ2#2pŰ(ʂ16v2K8188%.0Q9Q"JJ?cpN?є0"N2 P@HF 4#BPA?-,]? 3Lkwp|0a(Ga7 6ڧT/1DŽؖ$eJC+0{oˇ&2',`e-2EʌY(B(,Xs(LK - cp9px X_;zn': ^/8g&xtݱ1E.[/Lz}[!ԡ p&U]!-i]Gp":: wtRԞnbü[YG4|wlsjm{ݏ|ı _]^YIZ%RiVURdXD/cX"#S!!)( AO =J6IT0־{@{ʎx4=Y4/XI61luδDb_!! }'ԣ@l1aUz#8W+gA@];0Pd9h E6C͐XSE fi2kgT)MLe%&ɲ*Z(E? NX\A4|}ۗ)u\f7]]&u]`}=ew{83~6R CeC_]u{5dEIPl@`Țk- &,hfePC2\$E`2a5{@Bߴ t Sӝ0 2 ;,OFz^/7[Kq٢7~sKsķl?^cU9EeE^9-˚95Fs}hGl8Q{9;5 |4&& Ђy-Lz xhq "^nKȾZ»d3?>cQs3Hg1d3"}a׃ lѾoJW77+:?^(ͱf5UeU˲ PYE8(?" DG~W&a[n*f1• ̍mĶmR7Ԋ;4mefa-Ճ4c!K3+\XZZdmP#I *ƱL 2ŰJe)mB?QqN;#GLu. v 5yq8[?R@3.}ԼX!dȾY^ = 8#0b(L{nպ޵U󿊜(˚ij-2HInRiNͲȀ5_Q7|%N0Z"m< 0;ep5] d?]n D-2QA?!:`UD^2/]lO4vܴcOeIoH)J)_D W[ԺܛwRY#JԜvU프N4pK91_8.<^yA|k=Bd+G=٩,kO|ܯjBC22$%k+.s*) .*" OAD D3>_݃1ronDq} OwJo<դ֜)x\,ud3NeV{ڤ]NNř^0߱=lm|.@_B?1:-Ѣ q,oM$is27uOs(?X1*wUcB$!oLL_ǘl>7< idg k]ll{0[@6ϳs7y{b},=1{Z Ð8iӺܹ|ں)f+ Cwm%."vbwsݶsE+)K<ӲJVi]bDA 'fA]^Kz]ߗy|?{ّ QoC@/?u_v,4Nef w[=yE"Awp'eut)yşr⨇&{LyDsIOEHƥf8vqK/E;YrsYmVa  aNF&sڋd{3ע,wvP29ݮ:N5Z,ﰂڒ59VzQ \ʮwB EDv= Jo+ln.uyonӀh%D0;Gg5iQ(2* 1 j4' C?2`C2Qע0O1KNkWU7Y3 )3JMbړC'bNW32WlܜK&@ =~UG|!]!x#Bz;F!SJwVZZ8{A=SfhQlidtճ8˒(,**1w$_Q8@vȀ.(*J ɗx~@ rR1wxA{[>[}[?럝^^;iE0ܑ_XjBVw_w^1o2YNiIWdEh]IR#4#Q/%8Ek0-OyGm0`9DXL~`9;V;^R]oͶM~ 뢛ԨDxw1uީD뉗iJV HKФɵ9e+Q|Ca*ZqEhjv'? 6^TWScp׬3(A'쳬͘ƍ Cg1_xZiRŬJ,4" I.˓ _D 7O|cCkW#=V8{C)M4oYE]XY5f.Kk&lVQ&>QHK ]Y!#_xQx?jHw"$=L>󫼈l% 抈bG/"寯`+vH)7r_fI0(PJHYTUVAUx1+ glVQFu9:x7x#UayKxǖkHa+?4ebOJI>:OMyZ7"h&cNn/8yWm?oX U]&:̩W5\3LӊЊ&i"E2 ɩL4)b_ X$e!QW wJP |cQz|.0]ud8q(UJlALЭe%@^>Nǀsc ?^mrΞNdIɛL> B8Q&͆ׄE]JPXe'L#09Q 4I3J 9+*{ dOsG[p3PS )eEeh76ExkO~cn>Ht W׼Y|[ FA[N?GrHNxn:Dr,'t>/e_ſ"4 QX P<+0(kMJև6 ?E C!?/ p~7GՏ,M` XiWe\wm8ty}.WRRJd>աA\(B,"Z"DpP@Am{*".t̝3M9h&{gn{ιOKL]r+̤/GpPC(>1N!,-Lo{ȉp0K5A ű8˫Lk,@ޒ_)mlO !'{"D< },) *܌@/$6f4u} l|cdi3AcZ f$ј?2~|cvg'ۛ)SޕYTMsq˘[dse圴1Wnsn:ˍ6acn1W7Ø5 ϶woبmԕUm78oumnqۨuzXم".'F WFu0#6NUAtQHxOO]W#+@BʿpVEkMPc.fux7i45iRCT+>;9f8ō{_A,58>ZbQ/'%_D&eYQeN9QPH^`$J WhIT*#)H?HBh' |evЊ yd 9('P{\3W茔}YUu/ *_F{BEn~sKs?|ӻn:alcȅdS!gIŸNUpVE^$$Ze$H'.K ࿰Hqݑ, зˎ27# _Ilm46^aʰ-O^~aԱRVl |^lT8woȒwoژ :ssǼ=uʣAS/E |fX$UC: Ī$/Ѫ3l%1DcH'\9H{f ?s+4m5Z0Yyh.^ 陿0.{FQ%F`IlC^"aI &EHkx]<'N$g]1W/ RLb`یfػ4q mgИ s7S;>W-*=IpFVEX)qxQ4$ Y!w(GO6rY!/!eUGs/Ě2`As}kp4>pVyZ*|" ?Xoan2-X j`Q.9-iɲe W%yMYհTJ%ZE54$?°1?lB| O9FS85v孋_=m04/^1!$m!PC/!T?O(N^7?{ԃэZ7*j mTjK2%mes=~j'eWܞ*=f}z創V4&"$]b j>Er_X%J(Y4&(Ob?Q)B"g!_!EB' }x{_&f/QsQ$Xg]9(9'xeA;{ʶfN;Jp~Z<1wxCSz4m, 3fHwA- A7y’n1 0a<1i"eyJS#G"S hlq=&ӷ}XDuRجv2w[2wqzX{2-t2me$1㯻;"zni D_ۯ~ҹk=Q2m;ׅkhԷDRmoofRw=V^*c R n9OޙO?Fɼ,IH2O*J@%(K-0OKO ?[-wAOv#?mS7 W#6v דGl(0,< #X1w=e !<6BjRӺBYjh** n>]uoxf&MD.rebuyץO /RBCdCTRRZ Ix iBsq_5mvr-[T@Sb ,[; m[}w-a*̦J0):ȉ 4:hԈ«d:Dib_3-4p*ęM|F͙d9=|sO#M"*ŒXcv2*s'"G),ɚBH"0T `oc?ɤdZHڎhD42w&xA{|{Rjm-HX_ Χ |@Br`D  .lyf}Gw, ;kL ؘ0Y4eN 1n3͢d NxU):`Q8I$xJXd^ERE뿑ä.ǐ(*v.w'* tىuŔW%?eo }AˇL+|]ڮzCu.%=]kp(GK)=m Eg:9MSdE5eWUEFdE(eN$[t '9R3 B~8j ݲǃ5#6|jA$XxlGDݿ._aògA\z2" .@akAiS4gEIxO !7^YT5k2UvVPO}:*cǼfn;!N[VU ru%k{r'󯊅Dh*tN<#ۛĿ)Ч:r`E[1Ю]KdO*9_ZTYINpE"5RXdB#IC hI߹$ZB@?%u@Sob?40Fr1<B" W¾=z:@`O+wiJ(eQ^zUcZF^Xo\&}6+`8py/8 XݷN'i'D%U5'e0)ǴH0Cxc$/Be/Dt'lVh^>j|ޠ/ļ} ` XfI=6*royP4ٚ?)i8OO\?V4B_l-?>,B3` y)ߞ SꑫY?2I/KTŢz^ϞaT7o%2_YU0 >vx8szȨᨽ|/DmQ{wzݶۇWw nF$SX`\_AAIAAނw }Sg%iX#X)1𐑬=,YRF7txhfI\Ed^dRIWIN[K\_983ԕ6mՋ@k$f`A%ϝ YwxDtIs "|W08%BdLz$'d (L4~h@G7#IOAH a$NX!$t/-~,HKEfq)ߙj P5 nͫZ\^6ɘPdd-@huoqF)[03wȲ}7{},m2%EZY)G/^YH23S`yUI 2¨4K )U\Q \\mO\t'&'/ r3Wy_oؑ^}$sݶ ]|BޛV?75YfzY_wvVC+jM?tcbgYcc7F?d@#'"F=77X)cnm7Q8:8"8ppG@`C\L2|s8eQ 5l֮C tè _ΓYkqz|PDQTܾOtS緿ӌ)YbɆvzgN 3Y?H⧷|ynWqwe߲+Yʦ:t@iSo DAГ4C yhp4+TUHR3‹,ň*)P}3J rbA{ ▶= j+5=w4#~ߗmJM#@w_cఒm6Jue ۆbyZ5k&oip[ڷ}T1iJ1OZS!jUǤVhԓ?||Rԓþý?Z֘Z_rwT˝-w#ks(y:"Cp$#9dYIFdI(V[UI\z<?vs:`ya{tޯwx ܷu|zX9z F.MBC׷;/ѣ!l+/BJǒ$ӤAEHS2 Y'Չ`+++KL?rZmNJ c.>ڒe4d% Lk N7M.j L/πpb`M -^YVPqdB}>5@&O-1f2TDƺV|Fk>?eZIP K R0 ʂJJӢ>;`h#h/){=R\`8 75.X5)ϊ֌CabuQwU2>.!cgϟQnb__u񁭾"C[׹;n̐.wΏo^sѥ$DITRi^-"HĈbh;x?$UwA ?)gkSQ@|Ttm-g;9@h0[`41]j @ j7ڷt:4~\{K~o:Rnz EI@?4?;?(').!'1@Vl 5+bz@iϼE 3#eӿ&x`?»?@"%!*iyWZ3wU9xW*jRg&ͽSWr&Sv@rQ@_n^}jJ0;3$I^O`HsFfYͧK]P#ozT?k;?ݧt .Aݔ~y&/}ϟ1|K?>iwAe⮝3Usb_VQ f+%,aj?-'D.=d̆I>j'=q-{|L3:Ӥ (G/E>]:*3*&yF߰`˧zE oZZS" Cڷuno E\&|8p F$% ?"U$AbI~>}ljz8qx,{h-xքKP,Hb'A\He92T:P)@&9?ڋN j ~r%.NH3d+L8p'L8VZ.D~[d.h_oj(CoTwq*-R li=V^0%ZdspjnG# )roo^Np?2B1©lE\U O U [8Gc?ICR0׸~N)Lvx:;]uuԑ?por_HAy+~!YkW#\w|hg@?ni ) ۅCץi?G>W2DϤlXgYUlZߣy]CJ5NY-viB7ίkV4>{v`}2UnHO<\pE)eh]j+dSiti$8or_?\4LK`I+0p-+guHI۲eKĉ-9nb/mKr|G`%h `Y0}%J-BxjhGE9:wn;PCa}?|U5x.Tk핎J Xڼ'N B](ΫPn!&sA6la17˴L'Pج/b%KGi!#N8sQG$fX$$F习@(>?(}FN) @)d"?`(kRkA𿧇e XK8 : c( _V 'Aſ1.jf/5_i[|_L^nӼM-L}2O}ei̟ɗ铕װ}!?)qt244ƸM?:.C&Lhe1~s.\#9]nZSns9~QFCȘv@;hkD/?͂H?JO-|m"֔3y.(*"DE p͐.8SYIUTEE RLC(L"AF[1Yw$5TO B˻q{7hZmcBA>PԮM} oZQ19hA_nX۽?)?ja뀛nhkm^Umt쵿_NU(s/܋2̛-x8S^RR *˲YEQ[hOr)幖RsyiI/ٗ-̀n>aBu7{o)GvQp>3 TW^Kʺ tUeee]hD)gM VGxsio>=Ag.t(&:5r}ho/"^G9xyT 4i Tb5@ Кh&x2K=8cAHMjU7h2v8{oyNI7m={sYo.ele Cb*Z_YYU%xZYQ%EVf8%I$8G|XΑ^GR_ @+ScffiiRgGX#<]{WeZwϱ)q\ * sS-g.iһ]v-cotʦ"%bvzmy=/q"4l ߿~[o<RdH$)*dUPI`EȀhMEgOke@j濚T^! 7Q-F6} Lr wm(*M\:xvqݵ1A Z1R9 ,ͳnǴ蛒WGh/Eҧqkzw۹~{fv32M0*A)%(A$eIbqh,&_%.`xA/{nDGq9 зudXL-(ٻ(l}; vX0AA AUW0A Q\䩀 " o=}3    ;nuj$Z|tWU׭ι忏WϏ>;sh2w JWzW˴plȲYod^1ICgcv#4nN=/j{) i3.z(F7b? Djϐ:iʙAar?)#>3yԏ$d}h:iH{u+6ϭo.Eb' ^߻@hbv">vr4N;}bۀұ=QdAg{:/%xR%)bHF (S* ‰*%G3'rU` ;:pmKdq+2d1w4>V|mƠfnmr |Rm@ H3enÍϲ(D##dxE Nn" ؛v]k\-6.nv1DH)TMdEB!T&J!i@O%IO ;S\5RԘA#}(ĉ!ue1<ޭ5.*iƍOI3}f/.3{K`$G-!Æ(K-kHVYyrC5oq-2-c:]jQ7ul-9m0z-Ǹ7ξ]PSih]6779U:x"7됿2_ ȊT]O!W,3zqgi b9*u 뇒O`B}r&F׆ۛAPMtȉ($ˆ!EI"$HQBRp&\_ !Fix -)S;ez@:YsΙ>9bn#(co=PMv/ j~x=5ud$Çc˚~V6Ve(d˻|BAXaU/au9&";@&%95=PgQ\pGeB!'pM0-R(14sZ#B 2X:jщsIτ RH岦~E{:c=;G|L%Gm?3VδR[#_:<ϩSMF$A'z wypG:⎴ LAHzM43v&ˢNF9IFrNPDTiJu)LS)LHRI$N"B _:jѬH%\4\FR0Y/G o<"or<޽Llf#t(Z4ӗ&$\qXronk~cIIQIAP%)%DIETRU%ZEZc4QGm$'sx`1;9#F ͲѓA _itakmsf-޷56*h0eFF#nȂ=>ibmtLmQ]Ȱ2wkqr.M[\= fYVVv_d?xzmm(` 8~T4׾cc'HZ?sӇ82( y+9l秧hzf$ ĖndGҶEfA˯yRU(MyFW%`RE]cporN$@g }AO.t= &a s\mN۷mo @s(9N$xt"A'lik}]B=1c€I $B0r硆KyWI]ENT&+ 麼5Mg,B.S]ҽ~1EkÒB *-Ͱ@'X|X}=a!\DhFU~-aHmsDJA+$IB$N$-*!Y1$OS5`'?H Vn[]vo`w(|j;ZIVa)ibÃF$؏[5qߛ_ Qa6!r8Z'EaB a$6j*q☑ЦҖ+0З9%^ee5ZeuyE *1 h#xIptA^tAh7  At>ȁj8ȁ/@V ҬbߒߒaC%\ tp]>uFt}W|FGx?Y]ހ|`*[~:<.mҳ,hxz2};dރIsl"58%1)ROLDKxPd3!d]-hHs?Q%?pFZmj™@Ae;Ă,Y6U@B츲|jfC2ͻqOVyP yI876Fn[J% ,,,,)ݐ꼓Yi鬛޹{NuO||̠6%hqM m’n^?uٽ\o۽8ꉸ|jX*KW>>ɾ#,ӱ<܂z#~\><&.\>}ѷ<yS?~wzMca6XaɦWytlHO[W}5pҢl.oyp6e͝EAOL? PX4e31hCU>o ,}OzWdzɚG7y6ńyzo (7/^]zqxv# jU [v(x!ܩ1(Rk]gL49ֽkpt"h9 #ʴ )s"CʺV!?IObEuns,6DN wt#H90tm:ϺApqës~>PFȄc!2SU!cn&@]Qܯ:$95Vu 4Be2 D$ s@p Twy*% o5[0нEEAO<|=ޚgA $~ d:RWWuͳ;5)Pf#J JdO 4W5٬kMj^9{ZK_Q̪Gtt?ąD{pL^O$}=)½77k3cN,a%y~EayI1$$QHMU ʳ*pVj8__Bew_8Nw.H?HQi:f[K%[_ϨĿ|Gr{WVV2Tob~"w[ʱdz -dEgT01GG[>Th`4BN_絔H %' z#BbYEHFB$chJ6$9_ 6  @,qz(x@8u?wߺ~alU׋:#|oaG?<0 ]4>F|HmCX 6_/hc2.>Vzcs+z}>056s+ץVY+q3s+ :n fn tĦayW.}0gj]Sg6KlV_E<&)"e-P[ΐ ˼kE}юv9?HMVUUS9p)&2ـu1|7{S_;uEF= 6) oδܲ$ ,rNp8t9 ߛ䍍+_eJic0q"]_Ϫq>mmt ElZhGj *ifPX<}CUin޽L©|C$ʕ/r,yO^> Wv>peI A[H7s}N H!#)XJ)RQ)A.__X8$BU@kM#P 莴(,嚚 ]}^0 ׸$ 9[s6n[ :![s`8s 4߅ 9ǵ3u0@giܰ{{nZԖAْ{UHU^:JUn-9_o,7wLѭꡣ% h"r:h`$ퟅ% @U2ox`3ghHn*I~&Xݟ#G\Οl!ϐS]8Kmu9$żW=u&oюgNEhv( tWΖ E)Jw9-ꪊm6Ef-2U[K4lp! ?يɉ83>#?]QV `.(sJgpGSE>fUN0Q5i1^~|ƻH@a=tüNޯie8rΊӧ y/fZ_T88*ؖEՔxl*FgQw^')cɔe]`׆%J5_dN ~mEC)iguw/mѳ7'[,m%NJ{o> '(s!Z*rhٚiͪ?R`/+O _7rIwC$A׸E6{sewXwˋ;bWuf2tw<[wݚw$aN\^#Z@9`щ?95 C/,Dyu1ƠXBxm/o2k-&迒AA-Ũg)݌l#B R{A7,veQ{NgGr"# e /:g66TA&iY*;k1òRdEG\Jk[߿n'7?Z?*Q>+;:ϕڭ}OZ7++K|^UΖ-&q3*3 _NMd^Q>[鏀u *X)iX1LRX[a( E??2ܑ>|ıVF`4!eyWta{u ;@ڳ'=9zNra5e$a_|YAKmC kR2C-!±ŠH̚jT+J!XR9!ϋku!3_@,sW. ]J֜t{XIPPur=ٛ;v3= 0>w2^o=>'OMrth)B[OIC30}%8gɫ`*f-qE }- aO,#3+7i%诘d&x1ES!"0 zO2)N8aᢍ:o4e^X\KςnB$g>o|G?5jI1dD QxΈ#DS,D=6"`,K˒s]+]*{nbxj cǏyԳ}eCjVr|:^z?'7:wƼrO9xOuc/f%~Xx|Ef'ݷ_{gu%}Ĩ-UFy+kBdIY ,h9 MԱڜdq21yeCJzHO? !`/,뗾f~Uӏcq2 cpcFi1,Q-͛7xC\8z,o?TiuZI)eŗGvE^ P-H: F6 /E.(@W'% h5В5tLf~%=036yf*;n ~P[w;8Wxq@iAǽ0|x0޺әqC.B~4y,LhMp2CJi\IWZV,,8t/u9)*anY_ՍqU~W%?.-ZKM~]H~r4vB8۷-OF:|Py=^ > EQH/ E!}!7;)aaRdz&ٯԯq '*8xyX2^G %_VƢQy.t~ݒS--%8 [7d]eYmQYNPM,kyULS07k"?RcBYeߵ@~kΚat͛ S,tNrm ]o>Ҳui$!*S=7#bZĦ65)32 `m*ek* ilP5A4i6b^½?N"`1!sJ x;2̳P:08P7n׫n*k6 |qe%bI4yw>L6f|7wҪTbLOwֿҠ.Bwf`o'oH/jOyu+2j جY5Y AO"߄:~G^[cc!i#&pY7cPYtU5D ,,/iP0̔f/o ߠByU{mjaLiq L;W{r2Ô]0SvJ lfb'bLIq'_rK"mcH7{W('5ũ#X!.vKhWݒ*6p<ѻ:ndHp)fjʒn[ɪaI%ʚe}#'`1^@wHs]\i>j`?ǰUĎ]#IrX yݔE{wb{c߆}ys&(fc3 杛߅ӧʄĥuig!yoV͂a,4$3oիU//JA5Y864˶m%H³bqMkChc ,E@@O/y,G7 ˋV/*M]Nh\m-]ƶp21+Sha:BEG!={| ZJ9 Ѽ :kXaDYqѤU8SH άKnvP^9݀qȶ3`X}"Ŭq;?}6r53 ,A萯l6b sDMDY2,{(߃oX"!`>;'a5}K5,:&h2yU`-V#*T!?#ENX QVnoWe;ӿv.nc Ǚ3WK.Ζ# Hgt.kzO7COnڥ]n*VoL6H^"!jI,{,IceMeYdcNrW_~oe2?*[>ӡ fH6v3 RTքںnv(\v/W+7Tu:fd7$% aYdCR5edQd'Uu /Qw^_`ITA֘Y}O|pۭivdzYh`Z(0[QJ] |Q&}_ĥ) /qHDzzB?`ئ5͔ 9LL,S% GhC.7,^ wl?=99SO| BWե%FXKw Y[{OFxgESGQ}T RT'|z7\osi i$6/r`<Ry^596l'/9ZƐ\@`r}GBpR*>EuX< /QwW5Kŋ;Z2f/}8P!Wnfn},˳%cvdĤkRǒa #yP'6n:6@wP|HY#v˰K8riw{zx ཏOM Z{wp'ܡM3d}~*rl'XKwYF_'p_|(:Cuq* c${T&벩+͛enJ*36 \yЃztvnވʤ%gJ}P0W`?VE X'U[d}Cuƴ^? Gұ{\0;917~b1XV}kJ5qnм:3Vg,]ЅbQv֞ XaaEV9NQ S,]DV-}`OAGgQm6q/wL!M28hĻ:ږ6UD6^6_rJ7U:g8Za9]<} tqx ].JMtB YX%AMV-NM5EDEuEcM43ϏKqp9?R+j4ϒ=*o-W' 2];Z: _#"55BK UGW!Z[<1,|-j~4U5V+-NC_,oiybR-w/B 2%H*J$DuQeAWFծe_krH@|P~CUy\ wȫV$I.zԂ4]ĕy4J+Ȗ\]8"˜T7QOj^SEM8نy%PyR/y-eۄ +-uM+:S0Nkɉ)(9EjēM(jr/"OviRE@98Mҽ~e2d^,n>wFiOMC%^O~tm(=6)fYZ6+k|1\LVmØdQC߅1p Mmnl c3MKTWsf0;J5pH2vE/IuL֟LS5H׌y Rذ(P|*˖z9>K֎uωfGN/Y awoϳ?,7?ݓ؜&}w.y2|>ܡNmpL{~>iF)7ϻg[R2LpwY&j4 fO_4+kWC`lK`Ued(r\Es]6Eoy;h}W1͜71>˘GS'|*)l:`jk.1q+dcZ9>g䆕.j٤oF)B2#bH>WVIHWd6%kړH.?/A{ [A[:Пر2ݻ0e4xS7 rwnXhy Sbe\*r㚃G>\]@A>DU5s/pi3Rd撺^\jcJ ଷH]gxFܝl6dovXs qЃSN>~>D`gT-%P˰II2Ϧ4US(UK؋?ɑ?. B?!G/AW) 4%%Xs~wޗsdaH s"J\8u5&_pWluLDAEI99Ufi^dSn <)4WeL/E_ )[{s&A̟c"AYG3Hʭq ֙~F2ƚdȸҏ]{?$AC.~]Ɵ OG<:a,Z"?_|'[4"õԶއ; 2+P" A[{zYV_Q`؂TkoڒX45wqa6aV۷ִ0Hqg{ӈWK׵ΨMU5j[+808rN^DwCgyX h>:^wqo1iϓL YAO* )2H$KĐ$K$Gr)AH,?p/;p8!_Ë3"͟`o GAMyg_}ů=Irݾ?n WN 2KQJl"JTƟQRg>}Y^4*a0Jl SU[o8}S?0֞4%_HrNJƥTV#ɔqZ5RTFdQ4Id @'@ ? N_o<?4\ FQ#iӉgjylxb*SyS9ڜҋ\Zjy20둑-m,mVgEy:|Dvȷ&"%1BTL\f(S'`)Jxa( =FW<M׉6seH%zqX8 `o),z(ɘ2yEmVX##\ ܀S1Xǜ鑑-zELZ|ReC&}c wbC0 ԃ$<*%QyR« + ()IS bQgyWHo'o^|6^?;od O=t-es"T` mҫ? qhgUU.Oq4')28?+ H)&ejt/,g,xk -cr sU$TWPn\4᪛DLCrOJEU`Q[?1BxUv(|Iy.uMC%Cph|4l=¡p ɐN:jMDJ)hEUch9%@^{, >xiru;>gSV?n6뺪M qfX{Tbiw1DGWH̗q$3K[8x:| ju8/&)ջAz4ju*t+(ZSAռdߏ ӂR[EHЭ mN5v<+Xn>EoO+c'VߚQ@\_@P'')M3i+뺬̈sZJcd50=`gOY,FHaF1hw4(45K LIRHL&oˋS:54d/{o;73yM㈹3+dV,"f̭$dV)Ab!'<ɢF49Nb'֭oF"WtR,J,+MКD|NKdm H.V&.MxWL#|N3_h+F?ƍx|nK _4SRĔ̋UK$YQ4N蔮qF(3;׵^fx]Ր~P'9 "i" m/oAa\ˌ:Z@r/Q%_ˇqir-7^-sWd5M~៵3=$?_9]]]vݐf&RJ4 \tQ9ZI$z1bo#:/fsCkk ^  [#?""ou@i>.1ԼZ_5zê{ıf=qh:^]~Bه8zWy Bi2Yݨp%t ZWOxg7B_A(NQRR$TAcIAqbG R l w-Q C\G By? VcVɼV"HaATEDTQ^zQV^OaV~3;sfvgfA2;3;߼ϙ9(qwg9YQx"!sSў2Θ?p=Ӿ61%-̲i>@@JӐ] e4ZgtRI^D]8â-?MYJDc7G>?olS2t{̾CYw---?--n K}4t-h}g=8,_{"={O1x3霬ܣ=EX@qڜ,wϝԅtş uC]9l߳g+uJaUvK~P_r&g6),EIYeAYh^8%DZUZ8+}\KBL?i\k?gOl&yA|kaԲ;1*=?9=yz4l2=1S]$%,*"#J*ň\Re%3t șgC\ AwO?1`\{Fyw_r,gbhص `0_MUgɑk2$;Yw:a-Hok&_g7:g&O^z1bHERu`&?l&ٗT#JX"F p.zJEoԐ枭s{ό'l*bq{i.nxqW]˂{vOlg?k:`-+wϒnq珠c#V0C{SaR}@[M[T{`yO0|m Oz@ll7>ÖnO'}.uH9s զ{dVX#p-:A;b(U 3r3YtSl-w_z4FtRxU4FH Tpς `oTv `iPEiGX6^pRL5Z_W+}=K.%n[ጥ=^c_0j,;p^{v#"v@AFѽatw oqȊ. 7:),Lj4ϫ?/Y^Pe>*]G.SA2$WufI3$l?9fOQ݋1AEE5sI S3}Pyr 3071Ȥڒ?{ ~kq}ͮRr c% L2Dd}ThI>E!SWHfQox{(ǿP^ tJZcLr-r&rKшP׻"y)Kq1K \"0sn_d #iJyrbė(fgHIat5KI[]qcY_ak x~v7+kR : ]/cy3r rg ;]Ҩɾ@3#.L16L,hn=!s?xaŏ{E 廪{حNZ:R|Wes໫`}:&M_y4xD xNsvT9^VsڵDz#5eXᙩ qO-ɨVqU 7TЎGɼ :0, 4Q:QFK7 ȡ'fD?QłK7zǹpyIfW2}9NH#^*Ih wiwؔ X-I!$Ŋ$)H ⪑9*DDHy[_+/v+Ƿy9(ne=&Ǻ4cΓ}׉J|ouzйX $8W9!rvwR:M2ήN3_:~F<#rz@J6߂ԌQ|^tt!}p! O9Դdua$2)PIIA|Q` o0kÌ!,rl0 Ro_?/&0 0h?{fL6fBgΛPENRdFKO}_qb-:c!c뿊$)I^"$~ $#4++IRS'P/!0#a qd![]ٓW{CZrslXNcprc k^5Pm+aet,?>oI'&NeDÿ~ngK |<< `KͲ3r90։GJON@?լ OkLKI%bMk¨+Z>PTX ]p,"03(`Ȧ) Oh7#ǎ:.{/Y¬67L5+o Nih Ǫ86/4ȳy|DwJ4?|kk"UIhe4E()JҒq'I߇zw{b穯U3&u9zzS;pc;xO3l ^r7 }s7Dh˞6ʈ_,Խ%v$L22oeƒea~g!z۳&F}փk:מ x^bUJ E* u5IJVRhdR)?'gWSk0sՃ% 1}cA[2&=dn?Ԑ7  /ȔFF}ӆ 4 kB| t>zH:ه`C}.{Y_ML+S4^q"-3dMP8^u9?I6 ߙ[?d@}|z2%tFEh6koC2^׾`K /a`yLG6~ X!췈g6wh{{`@3 a}QCmor,cO~+,di_͍2*NδW*Ï؁ѥIe/yaҴ):]\7Y.d$c,2K$IMN #IJR87/ PѭLW@=Pop)k#~$X!2v@0QI8F5h+[TQ= \4 m  ^Cl'^و_h"1Ǜ[8mFZEOuJm }o"*$ɚ,4E9U q*'T )h 7Tߙr7cEO]qk5[%ثB 8L…YpES0ZrZ8OJOmӛ0˧ EXAE<8?g{"2MQ:P2-"⤪$hJ~AKn3@\wDnB3;5 ;75 ?hOM1mb5;0qu2UW ng4Zuڐue%=v?_d8XeQREMQ%9yJN/ZA""r@sHIG@:'+L{&/OMwѬ&F( {2軥O:}3D/[Y6\s &9>`[/G#nՌUlM/g'=]?71aу36 Nܘxy濪gz;i>Uox=.(;$'g&~G?z-8b'S\qޛ ¤pOä0, 02 0`}>uPo:2Ǩ: jRœ2#+]G!!oɫ]ކ_{‘q Z nˑ rd9urdkꥎ qd#9YC)e]bގr83Jn.i7pDK?ců`5b9!gN6? HF#XP'enTd =|P&PLHIJկRfh r1\X`iA|4$)D@fITY5))SM&-9Yr Ey6#L_wdz ?H<z`wRa+˝ڦMp`8,;dKuߙ.'};5c:r& s/m_m*Q:JߋMDתm7rsO&$ttd\ MeyYbeH,p$4+~i@ujGtcm?7֪:=bxw=)w=BFA6 %ibȱHBDtQ2Q #jdI^!^'pAKOV} G2҂*'埬хb씫W8@ Y';5ٽfX˪z+7 <>OSN ps*Ӟ Ƿt9ks4N@?p/02iNVh@u_ _ǠT)FZ @R[&'I}ޕ`lצּP'İev҉aG%A?1G`95&#bU)tM4ҥjսRIЭ )h[qXAF[2Bd_"n"{Id?w5o3RD`^`H2OJ͒y躧0\c@ 4UM0&«cզ]B}2OFD!W5+|VT`Ddx'(ϊII|LO6 Kσ2'_dW܆)A>85Fa0pgb8vk֏ui5.K &`*JQq(qK~gS;j0| E:(NQ,eOߌJJ܁nL+"@B|EE)?,#-]ew7҃ô(ob7N'go0x[+@XWab0:֕qM5YVC[)$rA_1ƺ ] H$SzLͯ%pa g5|)GW<n^t#!__xIPPÇ1 W:Fho~NxтU~I >.haBYmMovEaЩM6T8!Ӛp|AߗC w52@>sP_0}F@ 9[ۃFq̞fxQjS>^0L^O:ټ` -mz4 Ծ] %nǯV$*Z@D$̏tn]`|<[? -ː.aGj?LK r+ekPٞk&BY[j!tN@s}ɆX?KLr>RU4Y'IBмHInB*pFo6C<_O52'jw D]QAKh?zĄɒJO͆-WzMQ]53$뵑yCxp]a2>|NӬyxy*uOV+ּ5`.\]V5IZYm΂B2tEOEX;vkW]Rt2G\ `)A%i8N KR>eI QWW-q'SMl]W9} 8W? yY5 %EB)DS xRDiZj?u_3x(9nn` u!֐ڄ-_U^_Қ=M&<_5z3UpϜ4x%&?ba+j=a96S5Q]ƺW>?[}-~WRyq6/{L*ܰpKo)~mP뼯,D 㝦I z{ zLk70ܜQmܟ:lC ɷLt;4|lhNs 7ժO?9]S}ٕ4A/8\;cNTeOCTi-EiI>ءm$㴾'\KH̰"IO2E3hn|\@)K o-ka^{՛~ŲOcI.[uƜ}/s2%9'5i<"-,i#jqKN?_axfͩ󻗽ީ?N VӢ!~?žbst+SN$%*׹*՜Ѹ^_t;܉.Ms~ ?!CxZմ|y|S& Ǿ?_~3'vxxے8`#C<{!mrO.V+˛27 jZXuS~dR&qqxH񸠕53o:#VrX1Yˀth6o4z< @QA +#hc|dZi'_)oXw;H+t"o-q}p `dTE7ѹs-s_f 3 QspⷢށitLDFw4jFFƮ [vؑ78jE( Y' 9c(A"h'l ~/dʇM!H$pG,`ca&i"=Io~}! {|bGߞox.( n})Tn6 J.G(yPp5P4 4~ %vUpi p|_/j|' oor]HhM9}'S2Ќ$ӸSZn8cs.G Ŕ)M?F&@:)n7Sn_w}pw6L>qTxb y )sBis )#16>MorRm ԁ[ᄗ+ -e?tQ17aHR߇F¾ ZI{a JJ;jUPyFNW~]?; E6q &6 M5B/N~Mu@7XmiRJ BF'jĹ'́L1$/,-~1* YMdi/|5;xع@07BW!x}%@D*w0$-߄RJЪT!qLjW(Tu*/V7  #~zj|}',]4F>.ƋS!) ~5X^ϧITRV!u)w*NtVc3Ϙj~%DO]4&]Q`DW;R^B Kc[ct1t?TgK]?)?gu\E>?6}]-sgK_xڧq˷ۍ%#nn W`y 9p$/Ѵ 4 $A>Q?PRCWxCpm|4嗃Hh+CXUGكʧ* 2XF-z+ Zo꧇/{¨v:,X90FL&?Փw ;z0ԷRVwxۯ= xEՙ$A0A68!H!,AU !D @"XdY},, .H$ LwI #cWuuW%a$gGB VXR:xڀ3 XL {1yFp$MEE{Dk(6+4ѴM3 ~aQ"3,bi )c[-<=cqR; E!9&+sJ|kW-Y=kW;IM!OmeAC+ʜ胉S^iP4H{AQ} *U+HRE'<2d%R5902.b&B *IIPq ?AS_P?$W!!Cq[qUYZzx&o6ܖ=l8deC]cze̽iՑB9C:<[(9 S*⻉i5N-gsFmnVo?ʠici-R zPY9lբZUQ-^ѷP)~w ?PT E < p- W@`X 3fWs%DZL.pF#bY4Dx)󂌇"b-Y5!8%\ o-f_ @0,zP\ ]QzLk~ <,4cK.}HwEK_04hviǙS1] b&5!֐^3ẓ'̜g*ADlX>ep+DHq9Th8a?):'X/]AP3wݠ?j3p9'Eu ؄[a8^p#8=)kh4)Bp%;jQne'$u̬61+ {R4=>I$JsYE0D \mj߆H-[6eڹ@+p!vżW /Oԍy2Lˋh|Qp@+׵o:-!G 9Z`HYXPË,C8PnIOK$M&'ϐ3 ympȋ:D/׶ϰ}Z|k}=?r|OR& f tV?nt n)ݱRIh.0/suU 0Ƞw_!}+H.i2ӃG.Ma~>` p>mɲ-Y7%CI5%d%j2$#wFKW~r%@foN I'E^\ Eˈ,-T>݂iF(Ő_gQ1=gi߾7ި s=iGGԁp lu`|G ڟz4-6ޑ8O+fWdvl$ {{-F۰jci3.NpJoJxW|W#X }G}H&om~I0T Q^S8Oa4)C(AP ' &Gc_" XX23!_fs-K'z7a!4XݙEU(ԱaMoKka+t'ĈACyWD3lW%,dA57 IC2 nah$PS„Ľ'G?m @ρ"ck_AkE3O=u N2{T謃~9_@(u=ѷQ_4ݫj0S&_Nv:&EôN-uLU3(:mccZk13X4L)tGزݛg{3ehq~^Ky3:?Wt"Z}.E ꘼Ă-Dg_ц 1QQF둥@d9E2 lp @+Atj_C|&nΐ-` S(H}S)=~q |M\R1!A%d8ϕ@UꩰrW uUՄxNX'x#p4p#DcDP-X 1SG?!/_@r[g7;7;u^z-7W h]sRԌ{3 8E2H%H%6Rgr:6/?Cl]"q2u2zLM]*IM]Foj2Vb3\ZS"kNJ+V"9>. b6t^Q S@FJ_{wguX)'#kGs|TiQnݺ:5D 09R=@VLߗz969njx':;U@#鿢` ܬ@z+2x1tűRn oCφrUP߀ R[f;l_1T/Zj")^G~EiA}\trɅR/WhkQm2$2QH|K?X~Eq6^AJ1 >xw s&D%n̜?$_fO_1zpQ,N8Htgm/>  rFDCӅ?jxբn.(0)H{c0>eCuEh^`ZzXBdDy'zxw&( ?,*.K/}_zy/?,ȇ2t勯TM^xIҺZH5 lQ#[!/i;ˋ"he^#ĒktD%Ў悫wﯪb@b56SC+뾛Vmݶ,kU_=sOluӁe/vlLD?1i^Ac-iy~Eo=XԇLK»}:tapt!BkݏM D+\`8nJ1^((O&4.0`$ʠuJ{EYԎf$4xn`q7Mn%UnF ]7;!]7; VGHog;* /ye=}s1{tAKYϬ%?)[iiR[u[h+\uai]#ޮ/jvI7 z野kTE'] OzѩOV;C|K"vobmg˭=ӷMN3oɏEI}t`q%[>xi0ś#~Q_8Dg\ŘT뉟޻`ōouEOZg:9[=OY4W|ɴ#D%2}:o䨏'9G¾kr3akZ 6!1_?sي0}̘C袃~ky636m_bi/ޯl:4Y'QAQS<( >oPyn ڒ?LP X R0 ,Q(1s$/!/u{H ޖQx?C(ߵPiV$&nx=ڶk`J=bW3k`T4(C`(V>Hp2%!UfF;:vG:$)])C4NUTȣJ }:kZIan # B3V6CxU7@c6{aBMwu,I199\9R ܟcn-=[UwOqYgm՞\Ium,,cOz.pm+:f/tiU=dzRr <c 0sa;\}188ѐny՜$! )!u}zHyzlfc@W^/ENyWFaN/HN޵H!VyXU,ˋ󽡐 ly9thL!DYcZ>uQ!(0"'``w3(4)<$ΰ +,+2-疹L3g,~< -? wa0s s #Z3 :EkT>WbPMNϦE&i{R&?.S噣|ٷ+=Bv{} nwtl!A(BzR.9yS׬1m>jpCwc"Jn\@-҄p%?ԃ"I@?J_BPe!`% Z!?I `ZG}®d.7U[i+t?9.l̔g AfBPŐ\K +_RU0>jؤnZUG x}FfDUPQ71L+wi e f_g;&GL[2LZ/IÛaQu,?n9w>[d?ĺu)ZaӪ>b07y4+-byoNKr??)p2'Pk$&$4AO)b#7Ǻ '~AӈNo^ox`D[ α/9+ u/{ِfG s<]?M-D"1;K^cyny[T˻v"NډΌfqMg/TRe$ZcTJSYQ#(Z"TAiEqv?hV_p^h;俕1bѿ:/.Fm+m˰$K٦Pu> <;R}f`^A>?>e^eo)*g$6a+ۺpxKنCv̋ڪ DꞃaϹ\g$aiaXVx eNVd\E%LcY#1+m$'bcpo{ H_!\ݾ&#o 2ܵ RyL)O{M]r3mZ(胣_qKjZ^7>H<{660Z9ŧ9M.y2@Ǩ[ [#փK39^>4Z4-!]?=Nj%}?yֲw;Qv RfKͪMPkhjJa ۬K\qNY #Amg4ucng4N>UJf \OGw˟?17":XR+O^g Ct|N݀?#:ќFdOGtlbvɘa6>!N>62˷G  Gs3\1YPj4TU5T'h?t /ø㿶@?·Z?p%)pE$b)^`IaIq !$,HE/D?cM(Ĵ9 S"F_7eUkf:f|.734cZ\3 ĂEt:PEm5s>`$,*ܻwޙ55y55Kn9EpUHZAHQ Q%EDfF9Z/3A=Iwgoc細 ^y*H #yc "u-v_h ) $ΟvQ.\p… .N <.'"&. 1eBֲK@p+^IHUä׭%W4[Ga݆@raM1xW\\XLJ[Y*T:rrUɔ`Ōɉf*|R&dɦw6O?1FQ\>.|Ğ$1 $$usOp{vh)E+nc#Ɍހl4'Y_gB3P-q* G ?9I,s88+ɒȴԊYih_mԨUFMk"5jv6~J|IvDS+h 6|߾}Zf$؍_oĈt-FM=K{Vv)#?]O~SQOp]~NB&FƜu[K>QOl5\|S>&=w!pC[,!GrA (\ 4 GQ`jB\q=WnF{k '[ǰxYI8^3 -Zm~@S `.Az5nEoNFlQ92i%x! p"8?0$I2$ GJNQ"-(*i<-iHڂs4?)7w <ւ_#N>̗_NQZ[6M7\(dp){݄Zn--avLʁJ #,cU< %ڽ{~8W|xXߟ c⮻n@ٳ̔wx,w471mlnąnr薳[ãjJyQHIK-LER`QdN]O#n:XՆ֌KN>Ja怙0wtCe `]][|Buq[a$9DyJ%gؐEN5#YoqmrQvh#?-Z_;#}*Գz< ~""~}cov `gYyg)N KژSF;ou}?1l &e(IfyR)Q$$Mde^eN{n;o1"`|\b|xoTƺyEb;ܩ) mow>dI/d}tWc Nد\uc2 XʻR+*+I6I-ɭE W.-w>хÚ˶C타k4gqINGqWo%@sK H2'ȲE0 #24 I{hNij( A?'}4U퉽%U_U6yyf󖵜iE)HYX6Px _O9V;(z/eh4XwYw tr[(]^_Xvo.ͻcC 6bWn}v1)&R7xc<wWyߕ7ouҾ㠘o:`;׬+x5wa#ʯ)uy2n\B>~ŁR0}@HoU:]Y`?*)G\!s2E#7ʶsGE-^b-:K#Wc^e@YuH 0ĮfyJ!JyolNzC=x'F.#nNubz|QLMVN+Rf\tK/{gϼؙzwF_]FLi젃tzxgo`gVUTwKYJ U?9V{+¿jdO%?>)4^2$:pP*Oq^K 8~-z+ 9HQCPuۭW|>ĺ;M^( M-7ønn_.-.$)J*I" -"ɪĩēJ"wf&?In&@gdnl+ D +6BiTs VclZM_f}=_W{ÆtxR $j^𓷸ך=%ee4՛f`øI!mհ#<; RN.ɭ/=[xO$BJRP+*DѸeX5|J8{z$QUk;H #ཱིfniʝwE@ RA4Կ̗)oQsC%+"^"p"ϹΝ`0使7r;vI_0ɏ*}ۧ~ktISN?C|5Xף^)^Od?gDЖp* 6X/xZYؒS3ӷ>.ۛ敌5;aaOQ綣G$WLQd̥ Ie-xW\7>q*+?[ ) +#VPdJhR}kS ,_ikO+Pa{Ag_iܢUkHj 6j_V[Fޤo;uڢ* n %?IHl0,Oatp ëzO%GzyM-Ʉ(,]\$PnPi7oU[8GIƣ&#&T"gz-c?&+ 9vU# p?"T2 MI¡q,֯= :W/K_w1SLyA o(ex)z* ρz$7g`)`ǕEL9pg.c0:HS-4RBI7"%(]|g0 '7|`;(B"F!g1g -:>.d̜  qg`o@GV5?  $θb̈́Fg6PjWK-R*a'Nwa9!'0~ 7B_zz܃B Ҡ&JCkhƨiu Y)֓ň5Ψr6ƿΉ';ջ!Q0'.2RoKZ}7&1%+|"?>:I$I2a8 송&d K<@ҕ2Ƚ 'ʧ&*SHN*X0>5;Ev6ۭp`BvXo}hroPd/|o)[ȉs31bM(q:4U yEvHLAeR p0Sv|^|E|q`P6Qt $DE]a A>E @r\[q @/ $_;) iiiii_9@^A$O,atcbl =w=HҤxVb76 ۠A&}v83Q!bd3GA|m`֛kB?+0Ûfض2ZYàwQ&֣F+)+$2g5d|R nRkQ`=Z6xFe n>K npCgc;WFwS&2+p*yL*nI6.a$qIýe&-mbގl7q\7(-Q .PJO!'y׷d]R\̳=Q|;󥜋¢)]>8 r11}C;o,E/8b\g/Nͺ oAkz2YUW+=c,yAUܔc /Ny0qB˿qT}z)LU[j+=jĻۧ㵛c߲!_A.} r.Uܼ|GF.mXQJe8;j[J~_#vڦoj_ʳ/T0bKzGS ߢo7K({^{+n@ݝYtaYh߮?_NC< _"} _z T 5~(3wu1oY{ js(yǜZKN}p!?\悁CnXusQ9}#WӅ 87xɣc:" }OTx㆕{.*c5X=vT}Y6_l7 &L&KGUz{GS'TUNvZA~\ЬH"@˜y7D6?0ei.Ce<,a*HVۈ\JglzZO  QT4a5FѬ FEhWE{wbٻ"e"~Ύ0'NĢ#]jp'1K 3}T$h0}J= :tj&<ƢTW͓L%GEE!(]\'&xp|mkO?PxTѡkECFf1Fn|Nf+Ŷ;~mgdR`ׁ0"&v1-ZF]kOGY6ZLumN{p\:T ^0%/fb?W>0BAQQ*5a@8фNshHUtȁhgCPU1%rnW#?6~͡raVlMmdY,eC,&}}ѱŤ}]qO3[[L)yob-&t<.0luLL&fυ㈼O v`B &DՑUK%K iʅ7Mp_h2RJM:hQ4Iɤ2٢5LDG@hkN3QSP(pu_,& :k|ڳ h+.>Opu%^׫u^<y(xAsU_&-5M&&53y DjsaN icx9yST4ב 3p_n s]0sE#5͐ p3eskX^gxkƱ&#yn 8jİWS |֎׬]m_/f.X̗ =嵭凼6Q/xmYcyze 76!oHbO6[&E /˕wULʷ$f*96(>]! '^3 ʠj NCt7-zRCj і_O4p΀VS<>{CU ^۩X}sl|NTUrn0HW!}к5l!"(IT)G7Y q"a%Q`H6tyc,|5m?>jtT4˜)?Kl(q?9}{JX_0y2;foBxS" }ѾjjsK|&܎6 fޓ۷-pAKhL&2Hu`T-uf"9ϽW't$6`+M&ysA:k,_ʳl0𖉶5#6"ҳ- ,bEжuG0dʽܻP{gqdwn_ K|4< @rr<֋=1$-9?tsvp }}{Eh(_U &sЇ{^Lmݛ}.>)?9_ aL: PA`\b\hѭr:#SMd'1>ym~&v?:#MFHBQojzJU@uF{NևQ f[,/:º3CuC^Z= xUUW! Uw"Dc%ER H\C#8 ʡ" ʠ,*:GaYޫӝN`uWw叟Z.2 Й"xA{)zd3g*|)5T`CT987Sο85K^۸;_8cmN!Ye=lyF,]?в`H{l6ux¤G.2}dM7lX\i-avNJJجuP{lV]-q}:uh 2fp8Ǵɮ~@yB?HWu>?7VP!tj<.P<&?2bWH.q՟z_+]k Bs,9X 1.Ɋ?YtTt~!U9,Ak:!=ʑBsKUd$t (,W&D^().ۗ1Zc5|)|EKanSKF)xxҴ+|g\z^cjs[x XlD6eEԠ`f=]ulxSE?zT~Cz@w֠⁙'I8/EW#^x=ꆱ^vEtÃݩgs8 M2ZG5I?n>: c0N齂)tY0vfD!A&$ee3JR~e*3JP]5@b5<{ZCGS3;֟d08ZD9Pٶ~3T Dr!*v, $Zd0WApnMWA YrP.Λ-L\t,wNwPUD9v_ucE&z3vxD-!;ߐrSK!iyce2v҈HӟVljkGSWoMiG^[$񼔅b0d HMk2^2QtZxxrpfWƒ gPoKz+:v2Rgc8+B߿~#U<?MxDKh<ގ8/Bm:6"\=0Jt}[هGF{N#CH=ݘ.VjHj/^&8U$K$XT֖Dr%ޗVDA"/Vf$&bx*1fǠ)q4]nhݓlڻw$qC*ѝP2%!`_GGX"DFF CƘ򄠃2 6˙]k4>$~M[7~* A>?Gbg6XC#ڜ~wbڍZ0#e/2.h_0]t6%C?<'9{,GͼaV;N nGwL!mMl15㋮S)< qw~جZD#@*K[]`,Yۚ{D% bHL]K|ciG39gmy׷#xmEr{9Cݸb+JxppTh0fہiܩ< ٽZ6rN/~ j' !'̖$}kOnvkfG"I z5,J<vJgz#f"=KhR7"*HqIJ?tχ xR"LH*#;htx!*BC+S{/|ԗo /w/q"\;k~TjT"#p! 6ގG4AԡH1n)ޅ\ j&YE䱛݂xcX8ofS⿹q7o) H.N=E} AL9#Ό G   mF)qt/n8 !㿙͂`7E-]6b.]p _^3Bߠ0x Za͓ާQL=wĔddHڟ֌ex'3SRvf_m{U3rUZq ^3k""5DEu.@B)oL\qR ~zz6zx6i7 4MgJ6 d^íĵul*\x*-f" 1O77q*JAпn*UWWU{Kިܨ/^=,<Uo.h1_]ŤRԬdb0n5$TUbC Mʦ!pܦ|:O hgu4_PE)HE_r(z\WjDfo(-ɂ_>QY/zI%PF26]$-pRj1tD -F][7;p 5ݎB€3_ _օkNwr3sz_)#BMWJp-gpI ~?#B+҄vG^I^?Lu5 8S{ E; 6uV»]Y\y Os$o@y'(ޥI͟U)cۤ1`ʎn 9V(b2 ].`. +,˻q{mLW˔偆m Rjܵ|c`O'bhoQO#4SFyRsus>d(DN}JAI>,6v =4μ;jR{az}Z)>B*aD_As  }!"Q5DRbw2$xlĹ=uYybyα.%&D$tFZ%s~8$[0ߢ5cPFTsb+AMM)K =|5/ztۻ3pA"!6^ه(.?h߄Zjc(Oב~ډ(uz ђ3wٲS-M[c>Bp:_fK~Y3*@+=vO8&(>iW_H %>+Mohը/IA0$YГU$"C3XYv-s:(?227D[@ծ*o~DF$^VgmOF꧍F͓'B|/]BSC7ȴ`h<)$U@kPM\{ 䭂[`yl9ݎhAN4 ^p[lq 3#jXM_(iT5`r>c~Tc<ѷ!j.|NGF\ 7`dZ ]wi"|F麄y{c>a͆),PH\pيC}RΉCrΥS$@D#0iQ8SWKH [H ZНcj,"[,NrN^nd7n8d8x}럵FO@j^URbw8jgTiAr^&F2Bxuq'&](M63-wL]}Ggcj9Lr$R(]'"ϭ826&MZBɂ|]"FMr]o?,%C+4&=!d?8,;yt6)8]6S{oc#z45)@Q, SQYJyһ | #6 C х154oV oZ<3T%O!_Aq+CSmV[19rKͽPX4;H\i.b$ oH҆}wf¥i3@H m#%bL3Uɲ&ܘj&:+R/$T QdM} Fzsx1>MpԱo5WOz?2A&mR4TuCAܳf'wU{^|g/ytO0B$JPL4l|ɮmԖiU7lnW]b0oPs *F{qJa(kBR" 'lw&p[MF4ˀ@tyx6erʉn[*Ϥa4a:hP5O%t]m?~zHIŌ:qZkfkᙿ7uqػ(l}{ !L@cLҐ֮nc FudHbHӉxPgPƧc_=T輧#2ҍU '6h/Ot3z+oC(H4'^J$^57?M6+-GpBAF7P:m Dwٳ=>H5GbWF8RJpbKpF0U,,>LB՗Gb4B}DC{/*c}A0Ebp[VG K;ǁH1"1 Z{17p$FqHE"O2!;`T-k0`qo(xg@=T@yDzg$ᥟ{usLO ^:Pv UʃSPFX膟P *d{ s _ĩ_>R"yغةڥ*{ɊV#UTt0΋ƠC; ?tNw6Ҭ>}~_f7.*777+whѣG|Z|V>Ha̽K0J,ۂ^[Ɏ撓.C *h) w>n)dWfAӐQJ0f bl8)_$Cra<4 (IgX`4z+MY(O\ a ,ÙPZ"m(K>Z3"Ի>|!Nd`vT6Ȃܕ۽2f"#b*(ld]Og5@0! i$hzD;R#f]-e'EϔL,EbָIa`c$ʮ &ŨMҗʞdI"@7QՃk_:~W!r쨮)^cgϓWx/Πe,W m мiB(K>' $Dd^P5gs^[񞢢=n3z|X s`gn 5$yۓ{sY 4@Jԝ{. 8~cMFQh{#'8F|(XOO^bOb̎~!ߥ(6!A, 5pn6ԄO]&s)qCћR!_֠;$H'ݶ ,|.(Ô`S3sti"߈ (adžm/a]`yßBQ>"h~ nȥ p!rEv]!xC|_Y J_J6!wGC,4:6ixKwCm\/XF0t TXmI2B 1s&MkO 9 /:2ԡ!#~ zItzi[S준ޯgMנDC>tBo l-}5& zg0a}eA|WIZA4bm7 蝋D$]9kv+(q3蝎RzW7M{$"A *==4ȡzoB~Hο(NiVW-,i_Ŀ K.̿<*r#%1fQ*z#`GI(6jz?ѯJ. H7g[r/%׼Y&$ 2!疝 o՛DBA j¶6,vA Ƞ5ͫm:tk R4|i4oTZ~A_15쓫s} ^Z=͛. \j{Wl'A4ohަu]=0^F z5A_\DcЗnJ8O6n|L2[OenUF2J,ܔ[%|]IY n`V/i/my5ΥCq`?ZRjبy?P/xVlt <@%zi;/ex ;!=^\}I秨~zaOs?Oq%{K [?2'?U;Vbׇ,V~B*<r7_@ lw@VfB͙PuRmL`aO14 (M6A<ndž7\vN+cɃr@ee"<^ֳv s6,TpWwAir9reH VZT6+J,O0 K +"W$G)aa׽ڠ럳$_}AxOKzG o]1#i 7Kv/$JrR ӷW3B^9%n!a_!.XwU ߖb?]K iaa70;6Wwfs<|9N}W, e_vM?EE<^/ZcEr2_V8x[?:'1M㿞~/}^x-AfcR/////J{3⋻o=? >}p/,*; Cq/iV bT#;|=SeV( F[[m gdm}5[NȝT^-uפ)?(U@2r,6M}FvfhЕ+jd'm̅hi hM;Уp..ׁYx=<%q؀W8{~IXb_@*u-O&>D}ٿP:B@t8̀GY~&hvUrz0+ m;A X.UaC/ 2Ԏ:ኵs@UĀ%jx}Vӯ$WGsJv;ͲLS69CN&>7Ӡ$i?/ҟ%B9aGCxU؄[ͻ4!y!%>Y?/BOOє#M l.mʵC ?32@-} jŕ yQ e͵{;Bi8>%B( s%f#BO9Dm0Tfm[p4TuTo¶WgTܳv[Is^[7i Qݣ!Pɶ(ۇҶ Ty +WcΉysr0ugoO/]׏;oo5hc?[1[?z_fI!WHX _'o?io5B_}ŤCǟGdn _#iyG{`]gݪX:;<WgLFւUw+{(̿t`)*3: 2.Fy9jڟ~qdg vv~/j'I`"aCiOoo?)ґbqx\,  e hng-]/¿ oҗJY).UP6ƠaSUҙ,iXNjϻ/N1R$*@"AcXQaNGooAi',D3sܩAK byw U)+'0C X#/RޏǕ9P9 R( 9 ߍ-Qn=iIP^+}uF/J-wQ<=&C_m ?Sa}_Gl,J| ؓw?Ô5zM_}&,h˜uىyղk89S=TO(ZCWͱs` 6 Z,2(i $QT%[ )U [¢ G:IG"8Ld@Dq0~t# ~Aዀ|iZ:$L39TkyOY66FG chl+?_E!,E;F2tBAS,.kwzingn7diҫ~Yq8L޷%ѐF>R/'R)g&L@,i4A*9Lbw:gK|o+w-^UvBtA88+te|7(wꛥC['@,,Z,6ls6ccX8rsa-e:@:zPR;@x {B!/YqIj$J{II"l~s铱ǡo=T }+.|ZXrզ+Am5c:@Z W+}s*8_"<KSa :cII Ԉ\=#h:mnf4;h+ﶰ qA* tv5g;?:ZTEǠHGT{lH n=gFzB}:U U2'YŸw8P.hItbEp@>("/;DIASCºRx HOQJeR Ll7:lVmp.3uڬМNØnf=bo_fV7k-2υOxT)tF!hy2Oz|>O|Z2<ˮFL% $cǙw->[_D5rF->]`邪~`X",<~vX _CR7d⺥_C3bqux{-}xqw]iM'r"7Ȟ#HA) pZH&o1ꌹ҆`9GP҃O(e6sJ{ipf5{xf=iFC;@ E풎VL80zvkш!cP<BL5r1qMp.F]AE.n`T68ޡџb~g(Ta|v_\Q P7ƿ;~bra6P2 'ALឿ9zWm$N'Ai:n os9Yg=<UaK_Nɏ8W7&TDH E `L2@\"SCKwDz,Gp:U][Zޫ3@r iH5pMҒ;`5-DO/A-_c0)-w &ķ馵^{uGr&t ^>E'`IZFF.)ǥ{)[g7o㺃Ɵj9 *FH Ù˯%gŸ]_?n~I *7A#NE/N?R@j`LK0}R'dzT GGL?|}UOrTs8lZ45}i5aք{0~4Մ|(/s0M!@qST_N8Ьp1[-zh hL;nw. VBA=c;:ZKU/^yt>V;G~ F#U%䂻7|1( 0*fY'1yG1pxcX]e|"z2u˘CW]Ī@F,NeRb -/ $g;Ew\\܆S d3d(QT1PxS҃a}?^o0+I^9Cdjڠj]$=ը)Ub@eu_̓;mB`^ U-HR‡=P96RrA7 T&p04b2%&S0UgS#@E=LU(w훿e$_03J8oT[cB_ϧuA|fbT2o2*pY~!A lQv?BuGPtV?y"/y9WVOɣ*z3oGKGaEтGm%dآ}Dud"Y蓏JA! WnXQ l| rc@y ~$_nBX#ҍ/HK[{gY~?2fH8,6I '8IRB J }" AQS=k2_pIH *ܓWGu`zJ0.ɦ`p *CɘN=!^հd}3sj/R3F [yK,[N^d7=K3/lV릩ԚBiRօ͗]S q:iλgb̈́ P w@GώDb_'Z#Pu,yo[6T-6\BjŘI-M_M0 b⸨,Y󟴞͹ߧ4 @JWs;Vm+@Q?bz>#.6;v-7{Br\Sv©PjWő6j7\*o`W(В**1Jj`Duʓ YAMRd"<\"X(b鮢50v[LbHX!3n .h.Yp6ɴ$kH8)XTWr?n n m/^rqS WMb"*#vV Źqfc xnJ5ɚ|7wv k:d'casw__e SM溦%տ%oy@„(a\XO4[l <$HT|Ѽ ơp YM" 5M*na)$x_$ >1$Xr#I8;-|xA.,3(0y[0*~4Qq o2L5{%:Z_=lZn0XyV]a;;4weSz;FzSV<{yލ}SHZl +AyʥOUB~W"؀Ё) x.aP#uřU*-qW9? -}~q_ss8#.TqSv*bF7y~>73)\?WxҚ)A0~M}ځYȸA>v++}M3~ﲱ6 1;,n1vrn cN,:%;'wN%L>d0x=&F\qcc)=j>8}>~;s,Ԯ0 t "Yjޙ+Մ%G,d..8e:',(T oqZ4u&#±5]K`$;\ 8߽W5473EqbJdݝqa.*SVb<zd'TG__v]3pZ:% )f:]v3Pl6]G.l!@!Xn^#[7lҔن>r-Z ^ke\d/,"5E@1 9 +znUM%C~P됵Ƀb3A5'蟅W}l^>xS4ǧ-<[/LW P7iSv gTag!Q?ieqwg]u p۸h|9{kwptjub7Vwlڲw|~|>;G^7noL= YKھQ}~_WXV ߾>H/K &|;8Tpr &w'JL)aO~swW}>Ӿ6AZz}о)OďA(&0A=X :ϒ⼛Lo쐘9\uȨI6zI2oǙKOo]dš7̓~ԞݹI%gsM[~{)|=2&ak]Af,nqJP%~^rGw% 8uDƭ.+ee'~kkO8zzϷ(+W'B(;S;bIܑ ;Jq'+p{"=ٌy-7 fz]2Nb֚]\ZʠbnV5w쿕fɋ{'K7M\`J<G(r4 腦U =*Ò,l+ IBnCm<8)_r9f_5 @mmVmm(2&tҙ2(}"=*4(Df'_Wʳ$Ol6n>j'RIj_&P݇-ʴ}4[Uw]qm|uέPC!_ _A)ʭ?IMK >}S@%&Q!E2^۾*Ћɭ~f5~Ty4⯏ogTյ+OC {ỷPϯ0h&`sv2/t0xw WAٹLmHCIm}p4_'Ln vMo 14ia}of\le(@]s,DP[ڝ|:8Ac5%|ҁVK7c{{&W$t7:j(ل;G;6Y~,T9OkG}`eoi3=pr`C&/7P%r`=θ8V 2H,M\PrXԥo^@jQ*J@R)(>#LW"7{ⷊe?1rw;9;1LV5@*oU?`F] #au0U38uj smya:?]cl Jha,__[˵>7 |S]<9!wѢ֗,$qК:Q)(GZwS@WQQ_M7ެ&׆9P[ś,?G "i=)l&eNb[TJb8Rd gȖT]vn5SW X_l-ep*Ă1` r%/ ]lQf?O3vⰹ:NgtFIsh.ɥ`֚nUO?Asg{7JƖRzbsH:+?;.{.T;._`ڲϭl=4}] Far@ZS]S+PsKU*un [r6Omcw_˅zhn$jĞ]3KE|Q\xb$[@= h{xa~3غ2`S{) %;CJz|U'%%nW7i A ! UA3dLsP%󭈒hPر., 0h ?Vcv, ۃXӨ hV,bb5C}:< 80yXVxJGX$ lEވ;L )Ѣ֓V Ić7VK%-RVFmAKPsgڬwq~:<Ѣd u+F|[)nGnREi$Ol_{\F_W'nu+b\DG!iHϴ(eUxg|"ՉBZ!JJl~B֟yfT("8{[A p2#j $;N-VAҷ}{ga慨#> ɠfM|R:2n󬲩MQɠdD޾_E/_ nHG/;o`Af/^W.V35nL-3')(c3gpF3(Bo5v3e4{CzAxkJӲt7 ,G6s4*,؋],1W[:,ݩeeӝ,BvI*iP!pG@/k7j jO8y3Rߛ?e6E9vE4sitzNgUw[\Cm!UaXE\5[.[#r-`R) b|] 0,= Ê<[*{j +bg `<U=h" Z E!fCC8u^3H)Ek.>=v{7< f= 2tXq,sOmhW'8-cJ%!AY!{, ÚL ]ݡ YFAH3>Ysd*O>6Q(ˆʀdwo-$C}T/Uu{==M.`66ȳ<0#g29w8DMAo h"_j@ڣslB;t&@ifEMՖ `6fէeus3 2 Χ?vv.4Xc&*YpxGRRjl+cU! ݼ-ku^u{_t2u*'J+SvI9T/*;M!BkeZJR >nưk|WnU"1?SX\8{*`[=#1^w|>;%'%wSya/y=79AX{% 6)VzzwůчB::J bIʽN&U\OC+˧7,v><$9K:YqcQBbG{nB3U/=SuˁO08Q,Pa UWc;UȕCx_m&?8lAE4LlAOyr_<- /9v=Û'wqPS,x7s+ʘ6W2j7Hps $p<)O"TUwAA(>g|O>9HX*09L6F+jw~q;|Y?ɬYפqp^h އ e !U"O#w4a9w';JKW^a[(;nnc-&;g28Yjqلa5HE 4Ȯu,mx4V@܏=TeB+Qyuϥ>'XT} LT鞸"샀⫏=7NLJtO҆,)`s?= %3.C}&=YY^){r OUkٯ s6Zο[Q}!羗ik0(ji)*Iz/\PŋGJg^['{v26H9oN;H$HH xBSOJH`q^Qʯ7(q)b%+!VSᖑB }N~^{f a=hnf6~NMQUzJ#R5a *θ'"HWy b 3urHJR2!*QٲWxwKOiR1YLu+@YٯVf Ϫ `!Dqٽ鿾:iAMS*g e$x#'wTgyk( 4?F<]ѡ-w8r(r,HzJX616rro,kchHYI~͗^xE4`^Ly4HۼלY2*ebiˤHjw /KDҪJ)Bq/a{/OkhJjϿ8E?ZTm۵{tmdչ6hiv F PC;`zY ^#-#nK_aIE|dEv4~ k{Fk)բ` +ӸvDۗ~蜖qD7Ν[sn~;66C4LpCtSB;_&*M'9x .2V|%"D晸 f[$ -Gz/GHO=D#P)t+3КLZs"f5FVFXn7ao {uYQg5cs W5DliL6 !CHU}V !Qpx] 54eA[[*ETi'Ե+g%t*щBsZ^|nj17i-kɒk*vi$OR/j9OVrkLŃ(M,xsp]|m? =Hbpqb!E.4SeqԎ5bcs3#I[aIMd`1Mv,&bjSîUPqę(M|T{*.WKuΉ{nX.ꬴX=jDcᔐa5W@!K~{pc@vHw%6}EOkM5OLQٲYrі!kpDdpXp;#Gؑ8xN 0 g bp#A)mtgŒ~xc}26VuQ \bFSw h_aaMIl>^t KAV6rŋoܙ;#ǿ'|bT\[Fkϛx|4/c۴&e}_Džw_zE(a~..;9i=T[;ԩeq4ON"f 7!L?7 î@_ î0,5pQ~ҖɟB3LN o23hv3nf1-kdM ?CUojDy#}GJ(4?\:{xPNzx%{]޼z?;OmOc DcF}S/1LC >nLc Y2쎸gy*f7L9;dU?3ЈB/gcF f$bjґi^.l_Ƀ (\3e>VR&&y~uSg6 .TsGdJ'SE$1A]$ČH IMNрLF槯YOeNE65:;q MY/276(kAWCCɻ ^S"OyJ/ȃQ5)U'')Z.1ԃ+ uQ4K?76} RLbsJA e $$\D:q89sP?Q[0@uՁ usxF\:{r.WĸȒ;q[Ղx =QcڷFLCRC"{xݬ芜`pzEzMvˍjぃ3ɾ6"Gr4{_4<;]ʬT._+(ʠx&IРF?izu;݅/hGÕ`ͼdX7@ %jc!0g_[hz6>xRПV&>^F^+o/} / D]r;\`Лφ̎gN\D?FӧX pa*siw?qL]F3oX7p!2ȳ,òj0SUk(8WS{#Dw4h4)zk=bϣM!& n!&=7 0ZveB6RODk@,W_P"/Q0\zE83N@&ȧXSiiihag`$M>͕iA $z6 = ohPHGnq8yvX`FȘ6u\<ǹNV1b  B Va^_SJ4ʾ3Ql][qB7œ)o!vyy~x&olؽ1S$+ַ$-AZVCҤ+Q@ՏE$IUWU&t!@xJ 8 J\Y<|8(0eE''Adwom]d1o&s9s«vtP0sew-dsf情b\_:5{>ݦWMkw3imtؾ"`tԏ M"MŗH VnԜߑ`H/Pb0wtg fbsDcM6ayG_vmY!7p2sNAz8Z)80IV8e:!+ F* x9 ۶TJy^3%R_MxЍ[%# TB9(L`ůdxA}ho0?Xo"rMMWkKݪ3iކ2S$xTOy]ӆ/qUޚʗM?MF. X܎@XQ*g _xG ú0|A}Os,m]J9s8au2R?E7(NN=O/|t]m<O_xCfq,d #+9[ [~d-whY5rfTh2¨?VjٜEDQ(6 OH~`O wT GQŊ|r6l|ʯH?$E@{Y #)qQv"m8y.6a!1_>R>I~\y)|XU]bm 2@`(:` ƥa--Օ 1H'05PHI-BLP5y „Ņ ȿf =5z&,%%!*p@۠(bpkQi75>|^\tO˂(ͻ@N _C6hгw=ZM:X[g׃ 1ȜE`miӐ?]t͊Afq yd"/\gVZ~`Ǥv{#-ϿG?Pؙ`TO78[_nӫԼPxuqGMm=M :QE^/ҢJ[Yěo w.iљOKd8FZ#e,N{1Е&`W[e|CtVP!,!A#hXrw奕-DJ@~QѺsL~R ٫,/sxZ^-ź2WmʭJ#SU}DB,+[g[qvz9dlŭve}k:{rzD)Q1ඹ[#Q H7cDszSTP.Zѭ?! L:_DQ%,7z_ąU^jb0^&wFx) Kn2pdIAC״:tІ*܉,lrNS[RvÜ+g~jwua33g0^(ūGŤ|-ʗ%m59Q@ʜփ%_/?]y-;+W/kQgҔGKѺ(I 86o [l@[W6*VF0g='(I yt"5`lyo&RS56x 0[l@tU: UPP?D%7=ܾ8u:.a׾esN땺a+*i t R @<S@@ĿԈ['E\Հf 6i*EM:E]PTpXʥ juXŸ09>~ՎGFT3+݌4tKsR@ %"#K?vNz A+6纈7fHKO(PRջJ.uqK5A߯-qRIl1N@jp$|m!YÉ[p֕}򒿮 '066@,>چ@rN׵wto]o>o|̔8 2Lm1,w ^=2a72 V@B-ٓTu,b3> [`GjaH $ϳXT^FHor^8oܼy>Д?eQÉՃoTx~x78)YB4W``C+q/<0YvN?uwҎpP8"=kn%<6ˁј88 #=0Sk%;"d1QT^0Eɝ47 y3_S4 #/c0<Z /9v4č~n1 0Z, > +5+(KA템{@~9)W,L.+]R\[٩S ,AhBxwV Q)qz!!+4P7GuVsu\s -r)H?t`s`v$,k'Hmw w6pnc[!o0g #.S){h5dxfF@>6CH_kxaISۧ&#Tdqߪu`5p7W_@> 3{6]zsKқWb_u&vG"_=t[H̹8!|8u$fy y)Oi=ң#+ v9#]/KӁ?1 _4֠EkQ8&Ia*T I@}(_apDjۤ6[7Ziҟ[b8BE整hְ475!-ըݰ&Vdt E.*òבl2#Na#f$[Wg"S5!fAR$r  mfJ?lvK^ ܑY#V65ܽEj,WpbVkl6gHVp C-Bi@z=PH (VMt2`(l: ctA [p+R­HLE)[IՍc{;~VrN nMe+h U1#V9j s':tc}>" Xp,q<#@To{6X[Vyl_`9mbz?7|Ke@?Ib6Q=Wb'CǝCg "p^(߾W9b*oq2vR3~arF$CZ]9tHE}?Y;B%qԕIGKC#PfyLBFq&HfOлE4." Eho\_E\BJ.4]B6233E78uWa~ܯå_ k{l. c)90;Myi'Yt4m8[{іB?KXw)BtECQ̓TFlx0`3HN.׹%f^ FPaSo:xtk%x[xrF`0gHBx[|9&l̈́xO]|\ZXWТ۞ɿFm8C`X8fi;i#p(.ϸujeOW""2h?Rs7_|iPrHt3#j򆀊D~\C89MA4ƶ]HKlqU r%7͈P 'p(NE{lI;=V#Yiwx0;l}H(!sCH UG::(DZ`^oWW7O\5S IM9 _m 00fwt =J'cҪޞYsqzC ÒP^!qcyT?7-*5^X3jx]"`]` ../8g7'?ڠ^%T$NU§WH~g_Xrj2mиPM\Pճ` Xͬ X(r**W,VFKd 7;j#>GKtCfQ*77`ٶ6 6TuM͹ |<񌠫I@mmshP#9 ZC+u/6$(9.z1hPїIݖMۉNyF&~$4kKfo/#ת԰кUKVWF 2A_aԝ{z4Y/?'C4]`Qc̳Du KE'T1d)X7'tR3[ŕ A eO 2E,\pѻ,*у5 R҈0XzIO0 KZ)[B ?Z-c&y-uGQ(k3=UtyWBOUղo@}SG*Ouin|}*@29 OÖj.ZrfiѽT'Z_G]{E1s Bn$`L 4U+I1c~T9ofխ~h =؄V&@o&:!tEԯR筙T7C0tEp(Z?o!F0F=et®aFg<[;&'3z܍ b# Nĩ`"6=s:Ym8bI T{іg 9#?lf0s0'b$-{ /31,OJIm5[+GIW@b*FuoKUq*T>%Z,@pV铢#Z)N'Na8F8[1NZIRVp9$l/[cv3WbՄ)r/y>v3?;O/l ZF+܌Gf;` 3-)h5usjX@Jn X Bަ3VVn i&/}y<@ݧ隆f[]i\8ty0FAmc$ Uljns?3gPy4B)[d{qX)?{WUyÀ` .8o3Y̛6L!ҬB3E+̿i}Ka}ўieI%b "}˼Y88ۛ{ߞI%ISٹF#f@\ %^Ր80ģPkxorD E(V}9`mO7Mt(O8D!ї#]Y=WA_ Lb׀TM\Io]Dq99ˏҝ)UR=ӏFw_^ޠЖ$탧Zy\Wiz0E"$|ou`K٨(F<"ʫ)K%rxYI(K#>*E+߽^HY7vEG3 `%-Ȑ %+U d+3ݐCvׄG|P.//ۓRHAҳe-A:H[4G㻰'#ߵ[ : R\B/SF\<4~?WD FՈʪM {#Neb9s&ϚYXdϿrf x1 `b#ӁN)W`WG{ZIt;52W4-ΉRUD8;<NbbH{~S"Gus#2'0˄H˱xLڦ/J-u-88Aub\E.z~Qt> ;oSV윳Cb$cINrGr>I~?0FLw0l|6E_zJ&0S<\k90R9(NZ܀٫+**W^=R!NXY['^LVV=7qLO$u@#:>rh$ E&;XLtDy,ݯ &A!hBA/Q5,qFLj_A/PĴDK3_ (Jr%v+8 %g |cJa;C)M a/.MG~'l(OT _T-bE;wEp{J?ްW}jWUmG=vCc"0k=2uL~/$1h^"yGxZ<@{M{'0YtuɎar 4puQ`G7IҴd>~ʞ[]#,(&]{&}WNQNBZk2XtwKV'ڲj{Y hmyۈIyD#=i\B7 ../P:%}+N펋+woQwӞ^?+f?g]ve`$Lq0:`LcɄuxF8~F8&_l g74Je*%8&®E-獑MEYwARjDy{S Bu[hJr#ssLu31'l.Pt]4 恃2NJ}TN uѲUIO|jp)x=憎;CJFc%$X6M&'M 'IRs#eDA1^% H/DaT>8Yי? a<[kھt)3jQKdɚk4E?ivVf(,M3ZgxË]Y)DiEpdtW}ʘmݼ{jڐP.>[ `ҧ>Zz-񎏑@_{6mɺ(0o 2^ I 3<| jWghPA dKvքװdwpsm x[-qmo,r)HtLMhi"a(6&Ps׌ Qj WiDu6E5)Rz٠ _?:3 Na?njΐ>)ڻIp#KӑcTFxDڍT0gHHa}N4B?:^F3(5&="!YX/@tVlsf%ѢANԖU&SUݧ>꘲on^ؔ*}ˤy9P}!{'+YuԸpfgL ڂ Ibv 󌐀,JFLVAMt:BI6X mњګ''swyIq% 1 x$-.༔li% 3إJ ͨ /3<=P\0,a41v}6j~E)NLmWt oA\ߙ<֢6Q6Z5Jb*J٦5uVIiCڭ T8#HfPe,{6&f?ֺIv=jIO[M 3_ۢCQ,F'WhHق@#xH0 l{11Hh1alֿIx 7|4#@|z^S)7b tRƠKZ?*G?(ZJJ[tzJa&%mk(JGWTvsw Y? 'D#܋_4ݑ?hԨQ)uWil 1evKVo቟DıHDcd@~cAhTNi&G"QOмN6l 6uqiePk񠘆{LG: ;"U]m?*` B l0 UkǃLJWAژ V∴򹴜QP~wרdsUUô;yumK)LxYiQ.ױfUц>Hv̄ϰ;Kư5_~#HʙĮ/gYo |pɭ=Tx7g 36/z,InwJoMz[U wxiBƣW@ܓXkD4$4]!KxS`vszHzz(MP>[T߈,emdO¿M@?n*$BO 6+l zt÷7~2鱀rOG"\窓l ,`6YQA bNIx~9q `zi޳q0@ߠW:I2lZV[(eZմkZ?hnC(#O7̐qE͙DK 9pխwVްɡA};U>}EQO~>?۲b i^;}˞Szpdd#'oIY8=g\zkgn# ]_x`-fg{^@ҧﯻd3#ڴlߪɶɯȿJL:!H;t_}">]lQb֢ļB;ٻ^8dެ7ΰk7>i}̜AsXͦٳ2ri)/͚u.u[w&ˈvd$EqN;!cxմ Kz `VX+;RU;zq(-6.~jpvZe_C㮵wjygG=lXTR=_,]ۻ*ʑ z\>q5z\PQbyN/UZe~w|鞋ɟes~!d [~o!uD,g\>#:ybF_a~<:۳Lyrj7m.?b[[WrX)bչoUe4;M_ظ窓~igիBYljAg֨mjfE?j-Zͬ:m:Q\JU'k0 T H KR qR^d1y+td(ŪQØEC+7,T{鑃y869ʼB@Jzylzs'97f ZfPL,zBmzMP[qhB) d*]̌x(y&Y m(~d3Q -LHA)gA+Uk %lC5}hD䁯q\O·?(lC]|XB̪ `N8q"D\ytX, xA,TŤ `/be ('P,@g% @yAg?}*Ĺ%>@^Bh;-兢DBEhk%{+tf)2)rQ$ ާ\9 gˋ ʍ*,HP*nᥢ"`cB\ۊ gA.KX"w^IJ[t UiUkQk566[J4e J^OyPBr_Z)e<41$INkA2 p?4[W 8wp_PAt7]u҅9;9*8GlyNqvpwww-Bb,q8o;qX9 /_ `ފxvz(}񟖉tVFl˅/bo(wFh[G y*^Q+J=G.IEHs (\ !CAꢆK1ED *(*`VEE? B{}s!Nc3z^d8 Ϊ7.#6uNΚvw{۸j?])lčaWi8.Cr"-5Sv;m ~G`K.46- 20?0`P?`Հ oVWOw?}_濉0jpϫN?cM&^:Nơ3$1Mnh0ZY?^8}D"߹`H@ ?43QXG7ZA;5F{?Sv`j76IV_'Un8loºQoPM$H@W0`ݣM^-Op=繰*+̈jIp0 뾚]{}I7?[|  Ù5K:?q_pX!"v0$J7вa4^0;yjO ik~S7su&;c4XN@Ѥsaavj,` ",WA RxSaRjgGwkGJ-9r%?@_&hrR+xjKp&h&dJ- pK pڏmԒZr -v~ZS}MX-%p RKt~OEnGOr;Sj]2mpHQ)\J-B8@RipkKRT0)εpC2_J &3sVSjpcC"#*qs0Gr,/*oY(v@ӬKq!O7=4u `<^K ӁKcm{.G6/<+Ҡ\Xj<ׯz_eJFW,}Q\>,ҡWqYF&w&aNnR 0uQo0g%~zm:2r Wg[:F-QbV(9 iSX"4}A +kjX4(h# BFg灒60 eY7k1zl6\VsL3104u"oHT7HG_:%˖f.&qJ+%CiH#DS][oٵ_CO(TU]hlY q3o,7f$d&i1x(f*I@z*fdf2-0W$njtr.֊f__Rk[*rW_0B?'.ev"ŏqn'c.b1:j4XNow6H!3t,Bb˼yK_nHXTB Yz:,z^ɖe"MR<B 5V8:šVd9D!gf¹lנ]BjHޗ4T :)٤T"(^T>T!J*snlzDU%yxc FÊ1ߡPuNgwtμ#,2:m*ti#<>-#DC&Z?qO~~WUXYFb礄T͢j6($ݟ:=ʼnRwgD"-{a;>_$`4ln}Y4 I*F.<11PNp8*y}~, -H")Yçۭ"òξ>$0LČcZDҨ #Eh[h떧{%["tޙ(Fߣ!*]b)>p _U;SH"3B|L83<ǹsx1q&-71Vnc$2ZٳG,=olT/^ۅE U (+2}e*]-&onP+gI-5b 0R(o`/hR?6;G}eIQ;wڱ+(F*As=\9-M#B`u/hg5УQ2&@\7&`iTᎷ(d%P.${p?OѧyC|qY`#=23s2 2`<}|u!E9t_nMu_J~ɦui?yرfA%dc3X3F) w @jAoNgy/vĮmSSDɪvi5_ź:(lfXf~; ͬwXnFՠgYE`u&mfn0}u!]CcQUK>{yX"^%l޳BE 8^m:L/쪫k V9.!":5\7ZL7qzU*x$XQ,j _/ _!NY![QK_a=[@bz XHȷnBfjBsIJ.:NqZVk;΀DW5H=精*ܻ` NpO8(hsk1>b=tSéB *&mƒFjw M+PM<>NmiPCŞ72 m۳@g#1+n]- ;4- /T̐MV'kjUTr.J]"JCu[ _7z eNbOT=#ۚJ$ٷҦ!yO&u?k^)yҍQ|"e":MܹD4ȱ/r>GG(BP"Z/N,U93[!\tn_{U8\{c ϞϏkk1V6z1{Lwxpq'}dT/.RfZ&@QjwQ*+i0r 0ϫbeUY%Mᗆ#J{dZ]u{Mi ;ݷU?,-0[^ '=iYQ?g*8+0s ;*,(.;~4ᵢm .qG/CK-zB]$Gd0U @oP0>(B ͕/ٶ1D-rx'Zk<(̡3慹Kg4z<t3^j?Wx_ x$lІjQOlnըC޵hOl&eq#sZQs+W)ͪ”*i@ ?#>>/ӓ%1M)>^(48 R+(1*.yrԊT㎽rΰæVb&jT"li߷В:A:0t(7&LQv\O&,!nk:})a} Ubc} >4NqY?n]cZg%!QdIOߴ;HI5/',@Tч)P}|iۥ=eALO2JpAu  rC*.'H%JL es = x/ ׻VY8u rtv3c`n#03֥:)'cD-L$KX:Kl sF ㊳2ڕu+ N# #.19 ݎN?<'8}*Ġz)NA0]:| mPgg? ^POur8UȖ:y"zə{F*:_|NF>쿻ͅA5Mff@"JGLLEI4QH@?_ H[T" |Uժ_[;{e7! hA2=y}CYi6IÕzNRJg`?.IT(%tJl q no4[[B\N5M7a-S=IH͉)~yjC*եg3 Oijt8ZZ(sBz~RLe Eheh)9XPSwz[wVnq^#o? ; ˇo_o?U@OVeM ?w hb*EZҭ a`]o8^OW%av̪%U# q4!7xOyS=p G9Yd\[ o,FGkؖE-?]h*ӓyxF y ?YSO$7NӼ=naLyi[ERmF6(~#y(Ԃ⇢Hhcg@ktg\Z4VSϹ.M+cbTpzdq_emo|૥9/̻y׭C'zx_㎗R<(oF,!}'Tg jmXLcF]* ʻ#wo_9r1~cpVoۣ3[bZ=QbTnxpvVhb aͬx6L9#o-7_JD )?PRG0[VNN)5S˦rj}x丅y$V>+J=w3M.q0]wm)q.CXmNVtv痬=C4[6uh/ي(S,"g_>Ne*LE]ZO>x6wQ2@.Su?[oq>1د3$T>i<pjˇpԦo|G֣*S^ȇ![7ngGp>s D鷦Ne.zMׂZ K;|8p33e+qz/9x% ӼBq^=h',orZF iaYh1s6xh4˰. >#7)R_H"*MYϸsev*tQ$tK4_x W$Gu*?ę <Çŋ/R4/ܡ| ?=PU:@)g-#8HMF ^CC= 1$ 僌,_}ʲe/[%^(iA럳'=R[ؒq+o_Az4,y[}7[(l I}yhtPv( (GYHG"P ᛃeb:2HgP*ƨ GmQrI˗^ $d( X#)~FG*UEU18Y@2 09!+4Fٗ>'Gfn_˔PUմ?Ӱ& seUQ85XwU]/<OC<̣F8)V'LI9Xz~X.ԎL:LniEɰf! `Ji *Մ!Ҩ$}t9XoD hYƈS64e$5Ҩބ(n73zˣSà)""! :rsS)^| OpZdh.<2EsD"D(f\ rp9Ɂ#,ee jkBg7hy~Z쭈Sk_#,YyOQDm|xEXzx}r*qS*+kq:`e͏N\ʘ/B/t5mp3N%S[ιJI1Ǧxhy,n_Pd1j~jtүx¿)b)4 \.|@N S+%WK$<5 * ß +c+sSژ1& IF'=9|49pSẢzżn&q@MOXC'bѹkozrpMeHs]ac;Jf0 5cemuf]|76mJl@SYazRZ'p3"tvo> t/W|nQ0jRg)㔩mU=44{)=HzăqJCaE(BFcBM!Ϩt<%Bc ]R@~ [ބ(5Æ(!a1o8"eM ~5PI3="K:0} K:FK+~HϫԽ[A])xH8ǯSDZ%Bs 7Hze(hLnwVfPlJQfSUbMۻxuaآ(q B}NΛmF#i+x1v Ǚx갑3B'["vLtt$'\`P>IjCZ/I>]qTmQT/;Cj@}м%v;HT1xT f7x>5Nvխ'5 G&F\;Kk]PU=(> ⃵=&tS!F:N}@`x*ktW69.oZñ>UAߎchWMV@lKk+aF M\*E+clĂ/!#Ve;+S ,mG*BQt/sh9ԫLp+p8QT3@fnbƧ}%۟i\U^ۡ-:ef @F+b{B0l9t}ܸv~jaZmCj#{[@omTXʻpbx Ï\'cv[ha>fe棺AZJjiݑ ''y=Sȿ6/=qrnU6DL;bߛJ߽>pÀ Ayw4],M\ 6A{r e~h^E$"ZE%2gãqPZO/[EFx 8i7 7}JiǓ_9.m_yq.ohȐ$/Ӕ-EAAŅjv-lBֳf!3}1Z%`& ax4f]4> FϮz24?b)g{k9mmu --×0Q0[oqI٦Jܶ6o7.܅_Wo3p4ֹچ-hx/N(]y(;Ek]tg(cCM]?r,^]eڞݡD\U9sLj"Ȱe82 Ft K }d3ײ\?)Wdkb գWcRpB-G9RKO hzB ѫQ/YK Ω'k]J8+lR;ɪһ(+_TRqSJ++6<0_BtD f@,G߆"pr^:%YRDYƞQ2>JP:ߠ)뮑zB,ۉ4@X4`婅؋Lb@ A\f̯OկN?y!}M"aYvKtE#$گ/G1?SNa0+G4D\Ѓ l񛀃rl!D޾A4~@F/F V2k@%:cQc_iq7?\U[??Ǝ~FrT] KxR6Jlց\xݟϋC;)M3^ù+H(3~r 򐞶њf# Vד |a.ۢ2J֠NQX&) 5&^+Bq t(V&k>sl=N+v{b;Rg`IcY|-6(*S倒xB+Q60M㯙,.sׄ"Y8NqI,Sn8=|OWwp:;b WŶ_HŅ`{ҕmN'(1H"780[%-#?${nDl*o䰡XZ8JTX*28=Ɔ%0,U;OQGm/X]~ރ- n*1&;@SN.˯ȵ!Y^FRAfQOs!N~gG_0Z=%VJWgHp%@KF'm% |i:Wy.˲n-YŽ܎ -9r=Mrg7I`RQB@pˇ r~F+. ] >UkRKCY1*uF-O%|Ծ).Fx ]K͐$0d6n XX;D!!~5'}}Znj؊wUjE[:lE=3o:6M'\/<',xX((Ad%VJ$z$!MUIG[C[pYnM֒MH _ tbd.;JZ|*Szx! LcXGre[fAư"G5Ue1hblcjoq: 6y6d9x pVFF?"z?l[׎ސr|YpHYAU& 8 /5g?ˊVF3uDJD#!"Ɍ&5_8fhX_g(K[/"ӌ-B?Pi^pݵ {Zd0So!n1/|?dt)2&¸ YR!# R7Ւ$:l0S$v>M ܢs87{|ôkEq?X=kHUTc!2[7yb@ohSSܱGHRa4['ѽzٺtѬKBY[Y&) D]X _ *WҜT(0 H ?FX}JO`]qkd[4GQ' JĸV$u2+HSpT[h 'Mw܁ @LY>';V '7o/XPe֊N8Ϡ$M ׳C @E௃ LɫRO(\t{ԟ}(0"bD\ԾsSOQtsNe}$}CaiQt=P=(JZ6<tw`ckO$c` 7#r3ԏA Y9'Hȥ6J`r B;[/{Uי <E5d35|)fj$83: %/M"-553ݺiY>zv*Z) ¹{לy2,Qkqk+>̫ۋa|}6mț;qn" ^ D% 5/J OmK.;Xj}hpG gZFI?)ׯu C_8?zCi52LCáU5:ު3tz`uk?nmYCX DrEIø?i tb =$)4ZF!^ʘ0-kW@T7hѓXG-j>6Zѣ&  dAcMS)$ 23>Onf.E.Dp+1c[llj~8b֭q x#nl2arF.av@IyU>ZE@ l]u^sڄ30]xxD0DH&̲E˗ݴ"Wo޸S zW٢y^EH; "6TE%ARfD-g z eSPtDk9ЛAhe#`H+Arw{*"y3p2CBv)[٧آ* F.bk\L`'FT (w⢨DCظt\={CR۞qz'[Rnpm/6Z%l=F޵h]?wb.8{ÄK*AR;Ov7W(F]xި'XM`饔W>`^#> ?܏gRO[ B3 YCQSaZӹ?I 4;zώ.J}Ѿn/$vaFիfC]"ĤVjPGJ?ЏuIWѱScqr]IuRxeb%)H0)|$i%4dfni49 u(5&H#b8$-7i`=F(JKw'wOJTL:3Sﰓv^2fLdw2Z?kFO>}C_wT~$ 'e2~ZgkJ_h\CĸsǢ sP꒺Dq ;-@?30p`8 )andQ%d VO/Z@qkG# Y0[>s_Y~2Y(1܁N!; S8ZSB܉ce8f'p`:MrC$`^wHnfg_Bt&\?^f^xQ=ڹiɁp?zf+Qg.&je6$)Xw /oEι|hkn(\ަ?>#/ o?V qTW2?V?ydߟ$z_oA騰fo )Xc2vyo]Y>ҠoOBS࿌"@""H}/nr)a@&/Y'ݞtۖ-''rYB):wQKR\X!Nlk$| AC/Q:*$u: Ijtv] z.j4*c#]Cm7x$R$~rÏhދ?:|֚zjk)pÝqT1[KeRG" D$}wf9,DJ[Aؾ-zZ^C @4r UPUt{@td'I@92vםȩ6j8LVP=H1__eٴҠ[:$f:3mZdS]}FgZO1Pwj[_گh,aictA y=i5t'P)Ocitd^ dpj,w)/ 9  b(o9ALLj|C kӬAAώ~|y&=C*Yt50t?W 4h߄|tȚBlSP2`s )wB~^f]k{X7;F]::ɤ2F;1hzF9ժz0_SO7wޣ :HpxUg.CHe=! )]ds  xcz=7-h~ūN=7 ¿RqP_? [?3_?!3Qh L4h uD8@ ];hcs8mx"-c:er)nVCwPp` =ɯѦgZF^D_k5"fTlH[I]e3:VԁB|9/|y`?xrUwgΜI8CR6ž:;|<Kܩ%A8;{`BlH6}dُG:w7}+b7H.KHxtoc) }n>-/CG5Zȳ|==[>!2xB7'.{Fޛv nMHbCv@wHqѹ,XvNu̒ҜWPSff)-8_ {ʤos 8?"2ubQԉQub8N(O®x'<<7%7:'lN}ՠVL&FNf8 Zè14IzF !O5/og_D~܃;j05o'ċ mץ>៖/?V_9>޹$D@DȐ\F cs+ \Va(XbP)O e&9[j ͲF xfs4' ,rlD1>.rJ,?|릱, .+H(@2@! Co܏!m|xZǺKg? }Yf֔!ZX榩e겲rØ2O~RO#RV wQN)`(@xOD88NV\g'?v[4A;xqB*@?ౠZC]͹{oS<]Ћ&jZvͶujfMJX0lʨ,Xq&V82v zԴdK1'+) >IYF[5-VO{W8gNx v MNT#mOZQ"pGSt~QeUj1qx$\㾻ZyQE+V<ʕ|1OWCU4piBMQ (jaYUHDQ h3`Fbg' QZPlPW蜯x`8_@KRCTtcpL)H,ǰU$XTe!q ' T"EGۓ]ZHoeJ"RDAW2ZR ͚BZy+X=j ذ;7F5#u2l޿-xs4Lcel h98rĥ;`)a6 _Пp' ˮ |y@f>2NʥJ< ^CL'"KdDQQJ_8U\Nn.FmeYX$Ʀ g[['r\R9бHHQj@klmՃj#c 3tYi,(.p"f@2g*&e>oD-^HG(!"h`=2!hJVT&pR.EE_Y ҧa;ѾE2 ZK'"f+o?I5˨=KUQ!jEt(8{5ĊYuR$6,U*VEI,J,E1*:Uts)AQ3*?G-y:pt2*+\'sS 5,XMBˣ_xJz׷hZ㇨ z␹Y;>驗_SNQ(U 9vG8pIp:^ zf|}#c428Z, >{:Uޯp$PZKJ-xRJ+-)w-QYNw aR:{o$Q@0Fr_΃qH(D0ÑqqdwuDaQuOeGܭN 1|_oo׭:ԩsSU8Q|⊉,˽64oz9M{He;tEk'?[ha aw/ȯjh[qf>^lIX~LeyP/ X~7F_~u'iMG?@~"?lc}YQWeV$^SdR`*Fֿ߭_iJ<*TR_5.o_A ] e ۰Ŭj)^~!Ҥ=v knYޣ/vy Q 8;$#<6fdcJY338f%Wmja[5V PQxU] o(Oʣ`ǣgL;>؞P럘Z(Ce^Vg=lPUuEjwY-Wq*;2kY˶Ƅ: =:}>[[>4P_tI ͡An6D:E+t9qxZ;+/c kګ^",M[3$A0@_4ATPh0YYRqxgb Rf#KZ? <x W >XC1d'+lM^10jTWǔkhk-+Qe !-CPfBᨉ⬭-t]} &Ӽ?X2j{}OTۛKܹꕘ.-cpCfYмFyLc JXrћ}1mܶfٰ93#@6-r+1Z>*mYN[64ߌ;LÉ~*tPQAeye$305"H%]kn{sP9waJ#,èzߒJfVrrbt3sQynBEvw8n8l?뎇~dwI!\6e{$cqV/qNEY?qxvt uuoVnZ+|[ (][`OA. [M\-_۴ޜGlϠ$=&!R=>߀ +\Jktm??>tBXGk@ J. zt8,; 񿺄: \ht+Q{{kr(05LRk_L8S;"e\9DOSrNqjϧ+.oztڻNN˰CG M@%gYY?Ew2` 48[XGA0#v yX CZ,N:7^w uo]Orl̥͂Ƙw~GݒG6,Z[)Ѽ& o`6 n ,ݽJ+E;~Ww|lc /*KŴ,d__7HM~ i9p98bE=,h\lLh `d,$|2^j(ᫎs|LTޔ6Dtx_*;hg՜Gkiy6 I4Uf qE`6pB6ڤQ6o.[s0m ,\ X;]@[paFe#&@b, QF6M!FI }SϺG!?o.f=z\h Z,<`ޭtGSnrrY!a'"@vH9$ 1Ktc`ȿ$SrK zBX0_Oq" qgPLs}`H*Tcl$XpH 04,xqR9RXCK *!DTcz#{4oq;i~`@`MO#S#ZZD5 0dwu} 2׳#; C?sdvSmD &C˭Y2FڃZ#S\)khzF2]:A["ˡ ̀f'6Fo))gn|"%uu";`&:eC8b _o 'q6!_ HTpFE}T~ "7@ꢴFG d:„/nx 4/a4;UQ̔hj@ kK d@|ŽsQS{sxV%8r^SS(#$|B?r(c(`3obH*T@]}𚉱fߙu`!?oWe?y؟@$UM*d?RB|oîiPV&pE0D%H4Lw/#?_!MTjϷ}zIsqvJ7屩wm۟jΞm&XE᝴#?hK9KKJP}j ǒo?/z{?#O}X#_itR|w^K#:1"n*x~bU#z1}޾OhCdVU7;kz;+`ͿtH!?ysJNg{Xl%lY?V;d9.'#4e(w2JբSb^R#ЋG xxxIo ٓ@j~چr-Z9lX$ԯIhE=4flS%BQ(@4''sdzǩd??,2A,jN^EjJ\4yD:o}î>H2&^cH1[:jVؐd^3џ|_BA-.*+o֠J}${)ӭ;특J} Qо[tLʢa!da^27-/lăGiu [v[0bpVh*B-P U\KC,wQ ԀY̺k.4])դYJEPzޮWՆR+IoqÈSG|x=ey Q=I cTz6㱝;Ti+ߧk{1kw^B& 'NFu誨sDs 2iQzBOeG"+`]1Ycu[iI a9c^uXQvߵ Yxp֨Ȱ,* 9yfϙfkY2 ˆcg6*д,[-N*1O.$ύ>?A?.!}Lh C 6PfE pP,JM.*Fc@YyIƹ>pDf|eĥ9n<#'S?[X,½mQDMaN:GN%nIS&]߻ɔX5*Q'Pq^oz#9cѯ[$@"IlӜ|ϒ9`xBdY'7oK~rM$M*I4kZE4uj`Ri1 #yT]?:(g̐DDr=|w#Š!Jhcv1 J7 i*w /3)ѕS<6vkfX XLzS5??c'F\;q6L\&=u&L36C*qG0q S-UWQ/[;Xh) 2ɀ!i:?})C?t~ou?x *l/i7DUy$qqlߎ850}rqS|c'Ҿf>5ZR?ЪH#ITJ]OOtra :D t.ہ"!^SYtJџ ,"'FE/ m~ &0PZ6QF2U&]'ԉ纸'EA 6p` |˕h5`\Ee_#z14$qb藄Ρ8~wP`\=_V-M7%¼4Y"j?+?m>aXts?;ЏͲxxzmX,F\ҏz [mN7@0pы:Z[BҒD̚ 5G9D[pت=/`P/>4#Eٌ3164ct6<DZ6lG#V 3p#ݦC>nD{^@5Mvn7w%ZF4#ذQ7ƴoXL}uS+a7;>;6Qcώ>vr;.:}ՀQfʍw0`"EMak,<";]6^~EFR#!Į2[0L <]1zA0\R+n-77Vji!R:kqE' d_M޿j1 MXW#́2Pa3m1˼+P6$[Pa.J[~] e7g冃Inb?8< 8&*lesǡB6ved{ZnY𧦖N[ pc' ]x4pL@ݼmt+f *Low ?VExFX9>Ee@L(SIҚa 5_oXӪp)]79وO%xaΧ ^|rOEur[OƔOщz`nA0UhVTD];,WYLʣDvWLnBbz Uނn,lr/۶#.L`۔mve1FGķ$P[y( ?gϗ@@|@|䠩n.iz'gĈy5-+/{PDkO%C݈$ ̊qJ$#x]⥸91&펙t_|u+ x 5AR V^I1Ou;X)^3kӅYD݁X"gdsQo:hnBsߟ g>CzjUTp\cYt^\•6s\S˓j3yXU3ݷ9=zݥ+>8g˱o#'^K8d^< gO5je80]9F8jc1N];{m{kj?!zί#W<8U6Ny}6d8:\trQ_sfʾy37/6Ld? ipsOa^%}#i kTONKN9WNTpdi,Y%sw#ÎK|]7@m |[h VxܾI!}Mml5a3!Xvļ™6ei(#,;c c3 8e~EysQsmCr^bow)k}ڰJ-ԿU8{%/PM $?I75uZ@eY!))__ȿߖvv,<=pTґtHߔA 368O~S7>[ewޠ֪QmP6jd&2ZkZ f0/Oyuf75ʤC(PנGK`$L@؈fwiK:`e@ FMJV ;^?=Z^_K^N̢Xc-Y (u4-qۻ'Dgi;mΐ9-nB(i.&VJY7Ѓ& )CJu-g爙m 썱Hه~+Ag:I<(@eP YU; ,t Aь<'!JN|<<Ѹl3 'G1tVMۍ̮| 7Qs so DH | <ýH;Zv#mixŻualhl/~m1-JhPe| MDqA.cq鑰},&\a]#>zļY#1-1->Y s3J3J(${>qgA GPN;8bHtpva2o11 fqa?|XkZ}4@/L\ x:M̉2Y.kFkc[s4hcFV.|CҜq>X$BX28WiI2J+W6ӳL$M H'O+$pֶI,$ȭXH\׎4Lf{{;.c!iQHNfZuVUZYFPeFkP N]5ee0Urrq9zx 'Ls9sVJ\b,GfM\ TIUyuN9mE(ZٵP3bh Fr:*m%yL{i4\݀ίӎ)!߉H?f*V@2ec ?$W鋭5naT+eҗ熔;!4lwheg4 WҮHګsGk핾LE|DW$%m+}ݧW'&Kl-|J_che"zn<Vȣƾ9gI^r$D#f`I֏ҡGaXO! .7p BwR&%QTjn!SS|5T0֡N5AٱNh *&na6[:11﹁O'9Hŵ0I\ I$ 4f薪diϣ= yW7/J'A҈ѐ9f. K9D|wER s 2ENOm|E͡%P 눌$RW㽕֠Y'\v]D⪰4bHV(BܩW9L8$=*Ӏ_obf3(Ӝ1.c˗|^O.Ҳ?}!%N=*k |s^CCufʆ:9 R647 b.m?b?] xU]ݝ $BcȾl3&01yTwut7i"$$aS!0(B#8lty3YZ$_A:KN7.?8-}߳KWcYGNƿ uݏ?fЉa78 n@9<=]pCx>t#`ϲ _5h¹/eN/lp=43\}'9rK5g`/ ~jx> L6%6)$QZTЦ0T?ucTm,A^KbEgJO+nYm݂orCK>7Ο>}mɀN/J"LOS7_e [)?CZ0{KB;海̇/ZfCB:*s"\G= |WWۅ2G'pG 0ȣè2OyeSÒ4xcC/o{k3 *sDz8Js(ѥ9y_կ=uGx Cٳ=r!GC$u9 No),+:؊lP?2W1_8ŒyoN'_2ܱaaiaaa)Կo}6-Nߣ |a X,3-(B/=+HtI@{\TG8Lz$`?|&9R/iN@頡ܑ>nc_j)zܬiuj3ӛzBɻ;-]9˂B\:.,CA>!}…0?&ƦQ@o8 f̙$70   7sÑ?G2ܤRL2^e@ȍfQYmЙnwT)z!<#DQ[60]?V0!@I~!}sGN^>or+o!påB(!F.1}+sI&O<츂 ? 1¶~ERW89ty yy(?+ |{䓎edye+NN.~^!a|InyN KyyCy__f|eTg2׻_K/Z/o. g:ߚ` XF x|8V X9c&~1y!"pyOD8N"WtqYCe{˼P㭟S^腙fy.п4n vG`q[OO/vu(D]eCcQR}4pnQ㙟ZG.?X^D r3ly0H%`^rt"/HÛ>~`-?Useh'%/A A6AC yPNWcHCgsA'x \sK6s/1l6N[\O$43N6V)y3gj+i!&u ou; ~%n!n|n:B6QGOQ`BEasfOQ͒4ru$5ybW~2!#9wU3#ykt&niuFJk05jR JIUz\hQaI.]|"qY-ř^Nx9EpAqH]vz;ʂ~4  ko Bv$=y͡c\nt%Ʌ B8io,_B(աK Gz aP#%<2+%5vνL`O$pƬrƒ], )7v;Gݠ-tG8$ڨؕk>P $Z>}F~qGs -?y[ mf(8c9' |h};(r>.P^΃>nD&lD0UO&9imX:{i3\a }E"5~Żr,9Aw-|ɯg{qw+)Ӱ)6lsyga N`C+nl;$YtE|hƇGkDqeu[''ЧOwWF)uw{RgAq^mVj]:ڰoֱ>;" #xӢhk|=Xd'i~V֭oy49=ysv[6l@TE1TצC[ytY9,( `A~4qEx̒& S$IRC2XYdE4zvVfK>or+&hX 3* UFD}|e0<CUC{6fcgF_?k03)Z#c ~_"pNٟU};rBHhk_IA_~X"dCL_1i< 3~ьCIl'SN6A$_ED%P%y[#a {5b HR &B/*MlE3p6Z݋Iuϑq`?@oeHo@fؽ*uqƠίR#ќtcظ"v?/LCrOc⭐R߁go1HR܀ҴzZc  ?iOvT+?pN]Ճ_+yzJ̇VƎq\ :ʼ*z]RajEd{KD>Я%$ k[[TٳGIDӺvE~ݵh^>Emƒmd N2f<Ԉh_9yН#"4@Ju uo57bkMsкgK|JLse%1';ڵMt|F3IQ*ga!?N BEWX[h*3bcd?,WEOX&X?[_U=ugYqNO~yz\gD 5 ڜG'{z!D ?NK h.'npگ ؐ¢7ǣEiOdjѯ^_|/}3ѫ2e+:ٌ/~*̂>BXj}cC{_Jlq3l3qC9n*pf&Փd]9Vͷ]1z7&4N#wxgwN;"^٘~ +wQ}9g2e5oo M٣.Mm(wR$1UL`qɹ6B)FP:5xItR]{Aw Ju PT<+s UB4 MF(RcoсzƁbA% .#v}ށbT9V5ހPo2nVYژ/@n#0_Hԏҙʝq@)Zj0;D3gYu=;ǐgj*scv= ]afu(K]^>r = t&{S05Щ(#UBjFtbht*3tJJcN!"!ي5B)2`+Wm"ȎKXG4Q|3846^RV;h0j5O=ް.h~G-e(Sz/8㜰$-k׼NH߆$ĢH"v]>aBHR+@?mx.lg}P PJBn.n t?F p6F½OPEE@egggeC͊c,΋zoh0@}+~)rw-MTz$=(}dDx {d&1[*pzHA\{>D=.|~ 6}ȤIJA`:dffZ{ǕlbK.VɐdT5/]g#- @55JgӅhƑ֤T?/YΏ6kv^|Ǔ@YS^03O Z2IkR]6K koɻ!WܧD/ TOt.6HBӻHR\}> Ney{#jV7$Zrlq?#{&Ix[5A8Hxih]P .?`X3An%%Ϟٓ|}!tRxCU ڹ͏\" ݚerI.©xO*Lw81) qr滔yn kHB!'a-&@7I4 !,t6}ŝrKb6:CkC5_  0aVS/J,,,zG(kw@|IRV#YKt$P_I?w{$0i8m3HG/IEA#H/RjOзKvܲEUuz 0;],i%WT{ݼ`moh2L*JfM) /7p~p=LRTuY ^J~ꏖΞy߾}<=+?T9r B)ih$Z(@[D%~HbV+$ɺD 4|8-쩍{A ;㧊@AFy.S [6-RmlC|=0#1sAvb9KĺtD.v$;qqRqJ=Μ%P`t՝eΪ @šWijbg(ݪK?нtd+sCӜ#NW7I]7Wͯ2NMDdr{v]/BG+PG-Jsx~ wU v xF3f ƶKcGר׿[h"i!DLV\a#1^ψLNix^đ:R@S⠑fv`{6Ri,X:JVpe:М [Mxomv .3gsr.Y\Vx3xb,n?g4!1#QGIXs%[gE˩濤^0bɼCd%]SL L bpWx<9ƽ] igwV/-j8P.Hi  -ǁ@̷~9?5Va& M,ka 3ӉflelmML!Ԃca;]:ny\M%[hPG.E*. UC pFWЍFzҕjϜ}%"ޛ8{%mr_{K%}QnA c־JSj M ˥oS iTf~M⚚rZi#xs܀luxbnhٌyVƢZ=_\])1l\{`R]cזvf_t_%b};uZmK_?I)e<ͣ@!7dICVEINA5(A+{Z+Ac8UXi䷇\ܨ;I|#'f~#Y>ѱ̨ڼ%vy 6:K%3σS2RizAQyF<gp$UZ{H|q([8𬑧īAmtk5c)nIƌ^IDlF#{Ϙ;`!3bjo0ݐ0&@q 9T};mOjY2_ԡ 'fbA* '06 \Fr̂逭-#rM? YT&RQ6kd0RS:>RZpP7Ko}B B mQ5i@֊?}e c$܏A뿭l7(gF 6 f fyŻ9at"?C,H$DY|>'F2Rr` <u UKlۀ@<5@ -ec+4`-a+Cڀv+b{mlSrh-G^f"Gk^;R"Gr˺ܹҬ,mОAe+&eZ,n'hbi6]/+m-ؤg $BQ+/tE$Eb.|Nfw.&Jt9RdZ4%URZk jJK㔖id1Ԉ@Ȟ31Y&f͘G l_,5@ mm7FVӥfvz"o7 l8: 6 ʛ{yy3U=<{Hsu=_yfPf7JsK&Q+kZ(:]F dXMF[Yp8M6`3[Bkˈ YBx)tzL9=_#)qݏ?)q$pwOV qiNMc?S^kzOٱDK /<ɧbyH2FLNvW~~!gIKLy/6t'ceZH+N^-f˟?i~H BbgԘ'*;X snEXɢ*6w-†C/ +w9$¡~F7?ҰD6W +([ hQv 7fHc&#] 8D6SE|eh&DPs}%c*S E,4y,'- z4M+X5'CoNA5.Ww,DhKTQխpi50F -.cvՉF>4+4"E,˘B1R.$aJW0 td .g.%ߜd8$[#S&-Ρ6-< Ԁ!E<cɽeC:yWD] cv2u5Ql#!1qrʄ:jOl,HJ0ԉ~ zjS/1ÇKW>Θ2%)nd p6Af79d%#҉s4P=pDԩzJeeIn&=%vXQbɇTa0w_gIDzl%+|+V*%5e盱(]u 7#j6cp/kL<'L bMrO)O&GHtRP?I( %ww"f*"a d|.v]E¶̮}p;7LD@ 8,ܲPq z9" Mߗ*?<_e`’;hO WZ,c:1W/Y1숍-jx=:"Q-«HbL1@~fG J& +`̂sᴹ/yiӲ()$m;4]$)i(}8 Rep)RDe e@PG\@TZ(okڄ6@K]~-}^%" \.qKkDh~J 14?VO#z^udH(x^7rD8R@QTF?WU|>Z[aQ.$GGD+YXzRLB_j%"E(à^dh!?D23"p}ᶙϢ%1gE{jgw^<]|ִ! Ӑ#dh('zc.̈́ȅP>~PA:zߚ |k htomv )9)|_B'z ~KIµ:m+8-Ua{\6.C^M:\&X‡ebgل9$Nr⏾|iQE#4 l\@Jho&jkl\xV1T%pDYp굹=dxm6k23L^=klz 絲vM!mƨC F Nhh=*6:zckznron:A(5ՙj<t.#94A/-!@Xn—!jو.L˝* O9Zݪ^ղ[˨{(_ \{AVsŴ'rӬ++|U ݮȐW-^ kv T"p6E"afL{6\RR&Pۂ~_JG2";+{/<"`\a"@ MI'i%m.鼒Q=Uפ4oycMRGI|bU%)nvڿ6‚d&~w۩qQEC8uM6j7z{f: zƦqfe#TFa G?w%'#<#Y?c=4H@,AAߕzN^O9V@9ԙ'gDEؘHEp%o0傢tjjW)#EL[S:KoZ%1kAڟ.>/odTQ_nr~OMab?ʘ@rkeZxvf8f*ײcOh I۽٘I@)B;"j>@Or1\ĚMP&OSxpס"K?--ā[.F' ȣʃm_njQ\i\z\BU^-)~1EKKf׬"99":Csdybvڍ*ɩTm_a^@k~Jw#/Go(B{HAۆ[y?qS RHCKe!(kX'7i$_\PQI;(4T6U G @;;8;=U ?ʙݤUT>DB33m4[674OkF1LRf#4wNCsZAi%ݳc{ ~*k)Z وX_ppq9#$}E!#sy2apc9SMB(A>.O;qUm8LnZpMX=1 ]C sq$g)k% PLԘCrQt@_ juW<S}8P-B aUIcK1م<xk7L)]H.j%-ɰS:ק7LW+`Rx BPRxsYaPߨ7O*ɫbvIw#w㊼%.g|{NKr ' k~-qUxutmq,nIkG~oS3ӊ2x~`].Š0􇕏]8zh_ƹ"TxLzs䙮ǜp̠);>\ K?}-rxLxJMp#W r"u, 7ܿ$~i~O_Nx"53Z'Lf* g U.ȼdo3,Vb|K {3tW]\->X$y5$:{;N Ta7޸Wa㿚6Yn1&d6:`aHhWo j$X5QqeiBԛPMUh!!!Ȩ+b(H^?B%E՝Z(m^J:裴yAL_6u3|Va7prB qd>: jȀxnPG{g 0F3<#7(k zAvAؑoyPASp7c\ Kc@g& +FOfF”V߾~ibP[(2H bX?0_ګ%LPQMtI[ؚ%/_(E+pH6]BL? 0E{JG! Mz8x _P#5AGCr3dy9] ϑpo3<2w^d[ۑ#dx"$e>iīВ%hu弒4YKprx0>t c^eee劕v$u_Ή1d~ 2Sn ؽ|+.`sNq(!K08 T.b1I z^do@7LQoro} {)5UL}o ţg';0,* (D>dff2p}nAc;00a!r r^"C^4˭l%,}]ܹmsR4r}/afuv|۠3š_1kD+rϮ?HyH/gQK@Pv]cY`:{xןMg.OZ%רHazw$VRK~el!JVR9/M~PyVLKayfsݩWlØ76cPyns\ii=mnj++O]}7(lFY[%CtzK1 c6$6"V2糕F8ࠨ:8h T{*%!v$ZIi3.(a,îo2T@\47S\)99Mկ[z4\zYPiqX͛e?GSoA f9:2$$˫UWX/unBw -΂l8sx a3%${s~4cf1fʋBnv'ؓ 7kp|!F? R-reӣb^h3;ÿAng͒|";U(X˰>YG  ~]nsŜOկt9Ikȫ|^ iru $-&c2 Wh0RVF c9mJ^" isTɔ=6oG wU5+ 9_k3kZce,jiFsTnX㨤 N̓Dnm#ۊGkʈbW'o@BE2!0U}Xڷ]pOe1LL3c9SMD%䌸w=ݩԆM*/=7!M&/w"ԭu%֜p_q}5H,(S/>)<]a SrF0#g'r)#/ E0j5|9/|5?Myd;D1_{Qµ4; SOa-t@@8'?nDQG)#s?ڟ-hKg4}Uk0t> U iS>Nxkf|~ÇfyiHq E" /|x5eݔWe6:IC:\GFJtT`,Pmeg4lÇUOX3eݡ9FbxO&\`.?uQ/R,ț0lo"ֲum&rh.[TUc&?jwJvpp B_ZFE)2c8M^`V\ Rx(Cju 0̪Q︛E[&.9' G>{Иk=ua\%/B6+\ Ep䄐lK -o{yⷅ)brn.^YA´uKuCEA/V<a Ю#WjyMRdΜ~߂,'h&>2Opm2VanRm_4fW 6#&jqg_^{h7̲qcI]7&Z߁픩xFx`ᆘu g  A$E]9Hҹ^#iPs968Kđ#/}ߡb LH\Ip8-#9(ƑxXrOW!S+G -,UBÄl,0Q#H8|E?ϻÞ밾p8t,<$HGar6dgi蚚W Kv-*GB|~$d#yDuđTJ6`GrXʩ~smdC~ԣ8ՈebX"/ſgcaH7$N9#G2KsKH+a<I=ő\R q$aq$JP'eS`"V ܒ'6+wZKSdILiצ~@y)†"Нݻ`4iƼ "}P: ?Qn$3 e4"]ٱOEjɠg`alfJ&H+NAρD4ՋfqGXHI^RW)D-ZG^^ϻ¤W1I?1 5 "5h`Rt6}fM¨/+ZrĞh;)+:63ƒm-0{pEɵFtJȯE :z=i(Nz4kC55(iN ]k 7Ig)HEZ!H3m8K* ?뤀#&)G.TEBBxA_'%W,dž|  'Y`VVol>E I?@N"] MB~MVrɌf2i]hݯǨߙ}\N+{y=jTAV~+ח!{Jn<ݥ&3GmL|s0ŎbMrcHv ~;Жa3͜'_CJW/iIkbC.NΡ:;'iu4j4}qk, ܚ.&;bW%,x_<^ -}{經K?$lƇTtL93ttuqߊ  TcЛN- g$f Fi?i*S~-L|D(AkY f{ЄD(}JOoVd6۝gJmew  Kqkq2zGHɑ,z{K4I).y74Y;c/\Îg䊵m2#`bɬw AR<(T}]"?>Y9fگ%mW=1V&H]GV_􇐺:.fk;\sH'AZfj=zRG׻^#"Q`A]7C.I AaxK fgJYD2S rxr]^oHp)de'pEED=q7i QF>?9rAtX" &y78aѮ7<$M0&ظ T ES.q~T8nwʌ`gۯh.$uL'Bzܿ) =0f`FR5 w~[7mÒO Ƶ[OPl\s^?:dR}glZϨ fVc0kt:AYi>uV~Uf 5ṣ6J"_h{y~|.F}G)zGFҝdGJAۓ(pӛfExT6XՄ<~blrsJKcG1qRYŵgHp)3>GWC.+~vExr+b,'B3['R VUJ\AH=!)b;2* vi;nL*ɔlc)(+VbX#F[O2sΚ#Yzyj[*oJR0ػ6M$.)XޣO7j<5T Jpd׮SB-vC$B=_uk=IQ16;d/}UX$hbg;vB,eAӋXf,4Ir8N|[Vo1tHJU[_OI&\0]mE9znZ㼸sw w,[Ė@Ew[PT c5nqSҗ9LXH6,Q=W7%h}q n/Ht݌JTů&NzqJs3Y\8/ZcĮDM|d҃{"|?AVo JQt1řlRY;SpSk{H>j,~Cqmo;MCu.7r.)׫K~_RJRcco ql}K1NzY6`"Z 'rH| z3y`dHVW˩sS7F^gװ|eM pI (!UZ!췉ZǗYRVv7?=9&SND|WgVOI#``n,t͏!fS, KӢLF,rX:ϓdXryUvѳci6$Pۇ{WD`EP3czb{侔;Ӓm/M+[wdM B K@M&3,^95xj o}sXNu+j j" 0 C ҢWw30À % YiYٛijY_[iHYDs89wasIKy~?;۝{sγ?+_TY?RC<Ǭ7=C=5'h5LA"owUݝX8Pq1ׁ/#?EosyPS&b .)zM t[F] _@;FJ3M'4AAQ}$aM㩞 u-<S4AAT>fI!Mv# }5ӄ2I5GLܹpOG:5@L趵4^s͵ϛ&s17MZ7b .h<#gdʆx3@\0l/3M`]Nyp@\4y!hxOxvRsvo05V _ _0:~Ǻ}%(LQ3b'rX!&! hƾEX׿@ AɚMx@D tNX汮,}{ufݱU?mk73Xב|I}uO l, Wf玈YMߝu]y 5An.nB%;c%Ac!чp)`~aᶚL0G̿';FOgɕʝi||g!<2Su -?ˆ|vIa&V7oNxRtcNy쀭w7\ha:该KC _=,ޑ}ZAzuѲ:ڰ>@dJf/Q)?aO^/YgT"hfs'%٣b ߉Q@MyVeCsI8ix(4B Dm}W%@ץ.GLr9.GVrnEp}H׎?pv8]7 Eݲ?:;ݛz%7z1DѪǨZi hQK4hҠ1DUj y3tjm(WǿxEGI}鼏eKK[=;Z 00G4 >>a!ֲ'sD'~Z{o&?b$r8+miavp]anUtb(kwk`JLiN `R6GM)^ydhܑL,U|1m|kť.k$||w2lT˝E=c- i6s67^kLۇ@iWX `vGL ϥOFJRͅՅUOVb*(,Ə[H],rIwg`G%*d~|x$"\<\<筴x*vE=Ȩ`49UѤӘHJөM)gg Л._K$J"BBH9/M\̉-{Z  } q:]\]γ(~#և[ |A[2#%Aޏk`h@&0O54ihbɿJ[_U_qӮ>i'Rǣpo3P B﷡Oٗ|?x{S[3+"1U}{w/@V]1a Vŕ_09𫏗ѹi/Ɲq^]! i@ryb  %蒫:ur {'k}N\Ohv KNE~{}}گZ&loH;6r6L2ؐu6z:o+~Vr=E9J zKg7}@NV9\L]7c֙ _-9'wհC"\Iӱ gׯ$IYd2Эs|ޞ\K-ǂ3lnM_v6V 2픽q0O_OQz#5\[ +GibVmz%bńG8"Jf ^r$&DP QY^]T${u6g9 Zs0 twEhԋtU2ܯs ?d+,@)̽LR)!HG0Bu^{w7"^aRv)k@o}߭gǾ{p왐 zEc5x]x{:؃cÎhoM/vNAǀ@|2mtUwu>cX5Aރ 0T&zb?"BHMqrC%Q9Yt¬(pm%߸mpwFiޛ(h 8i9rvAC4VA`{;$.Lψdf^c4G@P!(aV@`Q І]:_Höpg <. 3 HK,9y QV\FsE0^u63.mAw5I]U]S+p$ݳ\a6 oۍlΤVvzB<Ĵt;煽2Vx+*;foh]x=b?5ha'd+U`)"ɒ<`d7܎!뽆<~䫁skHn/|?7ж; w~-]g=K6ns_?pO?(|ChL,ǯZ)G,ޅ6LO\)RD[Ϯ^} B|r2ro_ \hMF.Ǡ5:"MHJcTG(6PI7Q] 񢩴{L)Er^$4}D8!YIwa{/M(Qf" BltxP78dgOGTOodC:JNRZ?fH`v"32D{c5_@X-׿8`[| "l'XKx7pV{vz,[8hOHŦö`аapvؘOOUáWfn!IDjB?ƠԤN!) )I ?.weZM -zxN3*! ZLgf_A~di;X\v ڽ,] K7:&,Oҥ8pW I!VI_ju$ WS/z'.yCP$AASɠ9694ث>-˨_K+LiLa{s ,{ kkk`qCI`L-ؖ6n9|Ck'}n1Fm + gX0(u8&~]BsY%)$z_D@0*.FĈ ;M;tߴ́x!]$VU/F+oRdj:LC>1u7~(*5%X1&%#tA@?\"8\(9ʏ`j*\ R=C'o4(I~C\v'CBBAR|𹯾1YC L:/6 A)E?#b;F""8梪E1Oru:y~tN J; WC*wC C/}6(N(FY7- R,pd~]he#x/Yd;?ES g5_vRƲ?fW2/gYeT$S[@h"Һ$ަU\AfڝUĭ&Z@OYstaqjp@J7S*ŌuXO|>vS#!pYC1Eh֟ETPUrT2"?_ |}!&Ia`}eN=t ~=7,8RqLƯ3;_-o{ZWC-7x+ A`xQ/GtǗ?y ?,Umd8fx##5%KOfqP(!أ>2w;s;{W,X7)%, 2pF5,LNdĠSD3Ne%b*[(Mr8 lX/_n=Pp`U#$IPa9eVЅ/rOji`-Ch4#vʚrRyGh%,A Qc.Y0&'@}z.*yfol%Or@SʁzP?_⹁. Mc[N? w=#щ;c7}ȷa@[ ku_۟G˅XC'Z5hfwgKv7Ok-_O\'\כt?y J`|rkLK%W'o5σ`X?ƳXȟWg}v=IqO&QO[Oww$b >*.#SxX].waDz{ɝOՎ5|9wrk1jqR !h[d[Kr" !p|.hy_ |̑E7(7⅐<;oc a8tviDcYQ'@Kf P-?vnXN77Ѽ0~f((]G8R!a$L(]PkؕzO"GzF 3!P' Or3=2ppL vTs-kڼT]5So6Ap5UzxF/(OM^z4n[@8~DoRdm.jA9tЊ6lX'Xma+ ~ƑUF>6"yܷOkUeRJt~S"Q+< Ȩ BB3]ѝVR>a[}S맹T?~scU^oɦ1t͜i1v]hg,vguz:]FWz8S.Um`%årNHY1OL옶#Y,Qx*=L.讴B$~is1 踓SC6@9JxNi؋fybkʕ(Lƹ dIkOcL3[yV䤱_{\bEg5/*Cӯ`~`?S=ڈj?U\X=J:9oL;L؋TK:4qj.?oAmPN,/I=2NF"t* }S~!0ABhL-Kc/E=LjRGY&MVE֊r7%f)d ̛h`"J Ka͒kttǨ';J+6SJr. 6yUOeӟ|R\4$Ed"i̓J˙4A9&+n />`)jؾݍz_\rtAtAtŐf;b~:rJ1s!WȨ8)dVcV!vJJmWfu|Yr20pzخ䞈8罭IVO5dPZ;֔v%cǃ^;Xmr+oPX{gKg`5.N BT_;Wi?O>wT}52>UVzQ#+b%@"n`P6}hӘFVd-S'5B,FgZJA9+{ן%=F8;'56 :,8!Ϛ 'ʖ焙H,e;u8 '(=8}~7ߘ@9!كꞠ<N tx )HaDTw "u˚!![$)T[yiXO~,%U@KwdrQ$,ayzFEWR Op>Z!0 bWOD(xFXn Ռ7 #h<{(f{2ÿHLh;A z{/?냮O- uSS_i=)qœk_z1J)na1Z'N %.0^pE bH -UvK$*-"!ɡ$Oͧ[)\G}*PI"W٢_LŔi0 :6ݚn61luBZhjt'hHAAUcO,$Qvɖ[aT F9*Y=ċίPv.K{6#V<֑ƿf"dunh2bI[5Zl k 3)[7(G J>s%@wB7soαR$;=2}U ҸiO~?{2gӸ-L~.U=q|z<S0- I tkPr30H-Yd-&Y״LE:CoOg3ɢ;΁3ř MKoJ٩.lj->E4.^ne9b~ YܻZ]Dn`pvsߜnv2sByϐZ0#ßV=rf^z( 3oN:5eT9sW\g7Gh?ɔj 'O)!W#N;0jw`zv6??*1gG l8 rA|:\Ī:3jǯkUHG.N޶ؕ,h}|WI GuP:jNZ2DX?"( ® ˂_o%{I)v&/H>ahަ+FcxLn:dbfr .N2b9Yݖ% |+pdqCu*S:.D>P:tOi) U+G;}6'KQzM@R;_{Lmǔms DnZblS@lhhH?.OEwӌ)0?811u:O"97˔,S:g ,[|SGav3o֠M]zVk[uvmVg B>jz.u1`?Mt14.a(e@%5U{qg4{([CdUTp;հ"YpqL^m4KTR42xwLQQ1c1=c`7Hɘyb^T(?^ڮ('UTvgɩE_+B?flZlX vlj-ZnMz)ƿV==@ߕ;X UpRݘ %Vr;ԣY:?ΟD#_.NV Ԇ/U {t~f10sV׃wL҂l#qAj`@LOmc/o;Mm'ox_feY>9Wnbmͷm|ˇډo16YYT.66kQB޹)[~EqzTpn-~a٪Ѽ*c;F]_ LSI3uBjԘLzjdYk_uqyaS&E+cdgnxQ\[ZcA>"X@\XKSx5;.?+'OTW hTW|AۈHkn kn!ҨZaFk l?SBW; P6~qC[̳{V7$K'k={o')en/f7$6$6Pyvߞ.5F7)'nˤɌr/ P_%K޿HpYՖʢ cIon`-BB7ZIZa,,6-֡Ѳ9( ˀ,⠀ . @}XYts$]-U$sso_'z&[H_]xq?%,I8ǎW舷lDN^&|c:dwGE(_x~c~~pMshɉE/p}W֭j ኦ5<>5bn]ˋ&#v?S7O"fS`Qfbo<m.d;9W"9Vf]{SW|=7Kjm_ݷ\qq?:qû̶seJThGutRЁ LoOym+P+|m r"ι6K vա3cړݡՙM`[FZggMֶњ?jOrS! U_3@RIdWcGeDi:^\NUKpYB9v[2'-5kj⊹=r25p5vEnCZq>\GlFTgܽ ;xv[nTOM;/sB';x9 _o/y(w  WCqpPҧ ăLz-lo2&Ȳ֚vΖl5Mf6m&m8?”qQznLf4x?&eddP-YȔ[;gLY[xz_lԏ2xHZX}pypM3!Gq+qX^=:v靪! ;IwzFK6ѭJp[aOmPfD=nw IDf%,zCk߶k7ۻJ3W=9996QRqTt^8Nk߮"CGQtx5r~j=2{8sfԓC`:N3 mb5vhQk5 k ln3.GxR-ٹ?heHYGWju|Ӧ}xŒXPIi7ys|o7`qZT# WBxOda͐LIY)Vq5 3VL=vZdW#3VmHBsfQ1;Qqu" vkD(`:)~x%ъf(p8W[PXZ!!L.MlFO\'C=r ).h":\Ec^  %TIlN̞jqits,YЗ{>\jNɶBТf \z.^\#ҶK{ >4 FSЦGϿ:8rc; |n"+;YDV苬EVam>Qd{0gפS]i'uyZꡥ}-,a‡{F^۰/vx#+=@1큕^H A#+dk'uzcci1fmNu-MFk23جCud+ҠCvwZ3[05!Ѷh= :ZQ%~ndmbb`PH˦8V@㙹'l __ a8sWxtAkI͝=?^՘ ZʲQ7XM&ѦZkMvi kV+׿^="H+X/_رCȯ~+T 'loJX,Tr΄sP݄Vbfe ł WW,| n3(2 ޢ!8rcH>*vhrpWE&ciF[2[Ru3 V`# t5WɄB[nUD:)H'0!67_4 fڻ;H0^'`g"s[ǹNN:MtjtW=b ['Ǯ9(|5bQ3ܱ:eu=@,B Ucdͪf6kfUof :dZa_.sywߋK8 w3(ޡO[b~r,2FP< .A@Fz )+0ޘ k1҆J׆Y:NtdJjQ¾_+~ *G%c+B3HA ~QH> .S\ӊA)'ƻT }H\zTdehihK4skmx' =L=DF }dVqCpdu'2,Kqu 7\Ҟ%6IaZǤ6\}9lUDT-9>S}/-dz l8$DI ÖXUˆfyA/p#«jNۺa TT_hHއ2!![7na纄Γ%~֪W_̵nr֘{Ii(n ng3VhAW0 ?5t >xHnpL|#"vDLTCV(hФ1eͰ(ԯf`8.́PO%ժ =48 K`-%"`=u%t/BNO3a3td$FI~dWƠ@exciX³1&an=T`S6I}xsL8s7dr\,c1wɷF[1QP}*;FEEq2W\w$N9ttkzVCZ fZg39h-h6hn^juF_wd%Y] |UW` DI`cIH>Hb@u@% ; v&W#*  ( "*ά?qe<\W2?$ԾuDbFgSJw};IGE2t99B^ vr&$u[.E{qN9zi\+=9h!|$FX.G|r_uWtc+;\rbΟ m9(Sr:_ͲE$};Vp8i !tSէŋc[mIȦ rO=KI^+J^¹(- nU3eE?gG?}9WpNw;9SdW4f3t_u{hbilzNv"_ed0X{3pO׫87|6'}MQ?K~#BMeE({}~o/~oȦݻbYu_(@']F#? 8`֔r8kݴ eׁD#„l1d+Dvق^Q$p@1p@6y3m}{[8p@QK2ڧ\T3y:nX%7DDƴ) Q+6#N1_YQ| <P~47xOP~XwP"LxƢ Pf =Ṿ!Ls&UKz@6Ƥ\I9';:>6}L!L,Pj*mԖ}0RQ.]+Y\rԼҩ>c\^2z)D}0A|Wy޷Ȥzf3Fa@uk9lS_6f)K ~7v")-?;p3  @Q{X/XD EW1]y {Q›IPDh!"Hk`n>=#:TF;ÕLk14eX%}=Ћ`{a0=*3zf;2)؞) |t0E?,5,h[CXz/Z>]2n;n 3P/)€Pn"ԭn]xPA^E )n P"ԍjx@/pXc=5FX{iR'K7s;̬_TG? C]ѕs{?_jy5w}L%1;GˏI*( +^mi!q"0 Έ$l2c gxq~ij ?~)k/Jx*[kK8ږ/}牢CCm,W -CMAҤ*.{I۳a6 X~t( x "ѐm ˨&:mQͭƛ_3Xː{%(A J/ $s$Yrn'vK뗻2'gWMr+nzz>5̆HBHPK=٘2\@Y6oQdZq 7`6SEVV]U I/V hlGZ.$~ /~Tn_32Wo%n `pLQ"}fÂѫmtAv%?0},QPayhHVS/NúYyW"=GQEwo\;"%8bVM핺iQM6./O&ugW39(gSf0=jl+s0:.\8 e'۰n9qZMܺ >\ ͤ*6C{ 뭠v4m1EN1'Sh5C* KE!aƙ@ZWm"MMfrt{5~0R練+ U־jޥ/.WT2{nM;/⡠с+^:Sk(2P5ئQ;ϡdKQ ̳ Vf mt&YGUdWѸ.I#7`ͼN\Ѡ(j3>ң& sgjaD1.PBz@6ٺWhO\o>9Ե PŅ j3)ح ۟[r𣣨BNQxY^Ⱥ|nWzB$7ԁ6jJ}.3h^U*{!#G1v^)4%59dټR$5*0;lBMU㣷j&E² 7@* ! i:*Q/ +;);ht Ef\6̍ qU_fP;6RAM.1VErQ݅!{יO\O6ޞp(Qߛpo g4 p`Ɠ@aݛ[{2cp7FFz N&=5Esmf23h=@xؖR]lɓ+xe.+p{}>Q$/~Q`^+?\ 2"3B(88R v+h6 E#gJ^p,"ȚE B9&@ַJm<ףý(PP>|u]W,/U7M8{,:aI}B;sx沉rRjr-N`C?GگlgАr8qV,kBsvnhzEY5/'B~\KgyWӧ(Qy$ʊg'D?W5^e~ 隭_BY7X~Ymi<SZ{V6#t #ֵ/RUr`Z#Y=Q~%D[t _BSdPM]</&K|JcAD?'TVЊNpNE L -lVܫ_ERMEJU8J @`\;tlcT;QJi 10m0L[#Xm.jGo 4Ղ]-=;##XV6UGX`vn"ajGQ_o;2A}D nˢr)~e7Y<>r;^vsGg"O(NPG XO[Ǫ *`K/Λ{jO耩VmSΡ@De :QPhõprvmZg7PP^櫪 "1CZ@nRxNb=GH :U4Y`G ¥.\rB 8 s&Bɐ*“a{j2BEPxpD%&+fSB(ϗtczpz HN8n_|y^+?+DO_{F)R/I]j1H@kc P S Sj LM2%Ar!l=C&6v /jEo_&} v/ a@VܓW#[p$^Ģ6B#Ǜ[>04Z []+ʫ0iuA9oX|qC+d7pp;=ʻƚl6ٮ٪6dsPdSR[#U}ulYj&^ >IZ8h=on>7S) b6؃]p.DisE6GF"F踚K汈4}?`N:@y0)dmWh7-֍ I&F69~NѦBrU],81[<3NcOt(|V {wO~cOc7fZ7do@e835Cs_9'^N՜* s@:i#taMQBT1rA)]^ ^}e%Qx'pK! IbFC|{ B[ `L,5 6ǃ~dg{IMQ 9ɣ x_+P%k}C5/i}1z AƓĮ Ѐڇ$.hr*+Co1J܀+<}Ǵj0}L"Ut,Ճ*a%RfnWB x1QZ$MxvP>}f1N޷AUQ2#:7)!W:,O"19eoS ǟC3EO DS w /&>Qrf̹N p8R}RN0ȴ践S-X~@R%/1-n6߭'.xg~M[w)Fd]{8'FE{G8 ?cCG ZRC?6O?IY^.rrwɂe}DnA_8XL] \UU_f13b? A ,v,ijMff0:Ӡf)j<_gas؏߷pK\ ^7} 'MDk̦9Yuh8Yzz ũI>8W,vv5å~7ɲ8>'SumsrZ3oъ  3~3`f 3M}9fkŬC7}Ah t0ХRgeMxpg4O{8 hAD\ L`Z; b gh&]AK66zֱ$Gƨ5'*G; WT)ʺuuCrvxǩ#'\.+xҚHMW>R$E4*9;Y rjt>l3.q#2w ƎPYhG^+vGwvC3$5U(sOuK95]᫈ HKƣɥKߛ圾~:\ |((O>Gus!ՇzX/ N8kD?B\"0a=>y[e8^?8rrN"X k0`sq{}ڳ2``: 4suu HRR_IUfwq)-%㛀Dqs94Ha>h4%_س݈ Dg\C7U亠Nߣ(;"X<Zu>@UM\9mZ,I483W4#`ʂCBߌ{nE'sw97Z_ܚ{H=jR 63y=p8Ȋmz tʅ"%NN Ghx,PDlL,|oaOY}/Z"EL9B0D{ " > ^s ,pH, $,Osnq7s2JjO %d`/ۡqٚ> .:`Ru[A.O㝛o^>3佩z5Pc,]Qڐ[jMίx>Q7,v3U- br_$?AN]5iJU~q1X˄5>w1D1L2d"$H=!,! <^0 vV/T/E󿺄L,G٦U&$sksRL@ZF%q,x|u[>I甥PF)Ֆl`VNʯnX:J .ԁ%*̦n _G΢LE W9 dZ0߾E)J(匌V1]q'OVz LVZ{^x% l{P*Q0|kQQ6k͡k. "'?0)$3<ÈbH ad͐I^/ pKԓsnRPF<$㤄#7ˊ$en'β@ ]B&ۂO:#t T]@\lTu^2`wFو充V@)|.ۺ (V[tjW+?y`}gG6WĐ~p;Qecөɘj]Fv^K+{H4rrP0RUЭwSߔ(HMAEY'P+.^(j^~R\T.(K7|.uOؾexjϙ˗QMeq]j궂7GLW?ISbuhypEwI{y0i2:j{5a'^3?=t0i)gҠpZZ 5iEig@~4bHG~ӱ͏fnѪxٶ3Ҵi]_p\Y% v؋"$/Fw?^ t41QYj Q|{eYpU)͙(hArw􌢤9b z6ͨRB/}R9 M hVEgiAr{Y#xN (]Af/`hlշءwKJ]x3EMudpmUkćg<CԦzoiD&>q.,USH_Kz8((Y$wˬ,(2q6/2`dҶeAis~!@9=KP7GHK֪_޶gTgZQ8BQ"Oq3 +D87Ĝ+/2Pt,0r*GX(h5 X' ǤV?T<xxW,G^,wD6:pL>|߂iG*˦|i (dx(R%IhLQ2SĈnr]C&4F8~H,E}[OgFk큤HۮV? U# |YGEo^ݲ_j&5(@Ue5Kv& L:!Q5PN(-{.)84˕]B9rHHuHÁl O=~vC$(co5P}\kx\$4ۇ( 3Zq7CT}i_LPΝhPNfҥb[9oS iŨ-\RØ{^c}wm滋A57UY]}2fh*&Js?5fי @Z/NcbE/RE7]dr:woAYPF8n΋Py+A~d.KnKnYB$(Q`; '?xx 2\9{[LㆷތzAdC5<׃3Aܒ#g ߰ϙ S7T.="i~onG 0}μ0P(DQA`Y8K^Yh yR ;I&M]B& n&1Y򯃦82f̃FMڽI Jm8F h y|ݽn/FT5}?t< KWg m:xmǻFL٠pѷ.qR}pg&pkv3}PەH]:z,m6GcEG#(vk[a켥cC7:=pϽ~]nu}BWXʕ-TW<?p9ӡ/EȂp"9yH?T(Ӊ_T%^V͗#vBM,|ۙ'̪߬`k+"D5X rg4"K6x9s |7'߮P[zUkz#.u Wݑb-0kT|Za RՃP5yʪUT QO ||lJ3SaYQ(/p8K %pÒ,Iv3RMwZI?K(NhSo VW^dcF5Clm",x;3}@ IF@EUҔ{0MEuro7r) j] ,G}.[E76%Ò^INHw^H'q3Gqkq`]B3o,3 c_ݥdQMi1']UI߮^t_˫ O?6+V >x]U'o{MS_]{A0eݹ=^3 Y).%Ф@̻',AI$Z$(Og;%axfUKi̅=n٤\., W.,AA>BXm`lLEzpw.8\P<_APDwi-66`+GCQ1eáTڀOYtzjth da @V1UdY(}gv$(%3;{EPz\ַU=s[[ 7H7,M,V43Vm:M,7rz⿼$h%+ߠP.b {C,?'Wr! 5<gW=B t'{>'*Ļ @Ú"xzxÃYgFp,\0V\'[=p vD69ʂ?c͌f el&_뭔wStBQN̖d{`*uZC "և]qSե'T]DүjK-8}`FEm=Hl~b`L7Z]ɮ!i܉''ƏπP:Cڟ3Q>*{vѧK?}[m۫+#/ kKr@m#u!zQ\)1VlrlZt($=޲u]\ (wcR}`Q$lDAgSY5;q"zޚ«)bnW&Z5G:E|4XcvP8Fwi#ICHE$OEjŪG@]W=Zs$%u!5yJZǢ Uը+enWVCf IuJ6ę#FP#rmi `Sު DcQ{}0h5i[V]@,9PG~qA5hU5't8\f窦 ^W5Rx6dtiZ%].Rj%e[|>q 4I׍fj&F"JE>u{,([ n_ Y!: m6f~fGqv߫}][G y4BX? ѐۛ`ޅ#>=5 ص%7x.<ذMe?p4=lĴ{60,@|@|} k^8)?s=npH܌}&OF2Qѣ eT\[022םq9bd\=䑿{M|.cd[ӕ&=rYf2k2k$l-[q!þ~io-oe.`W[m<\wH(ƨ79,c`pfɚMvŠgi4>Og677 A t`"Q߼r-YxqŹSb> /O@ɉ Pq ؍uA9w4j2V}5`d h{ZJ~nL) ~j57+K^J2OJnP 1pGMFggz=y>h,S7ePnVz%o֠}v@vP7mHqgg {@lNL)CΜJBrEpS4#@[owb}]աhNtqYc/ek Y܇.hƏ3/>~O̷M5|s3t pJX[s2seǃmG AvpC6F3M??aƸvUR qѮ4"{1U8"qT]`sG*Ģ?E Ȳe(f>?Whecl&dMAOYΉ@Nj%_f_Noߔp*_u}'APQjRsUT>!"SyPK_XRw'-B?Ȟ#kB¢6-gyֿfr8&cXtl0ѢiAdwTg=cj}_9vV>.OulaÊ?=y>TkY)$/kxNW*< v.-I-La4X +k!3$gAP:~̅8Dx2dž@_e7qNbR(q@2/0= _3FL-M(+ gl&2gK,cЦ3^!0$/UR SSP쮖~!Jxm:HQﱀꐌ3_ W x<e5XF|7IdH5Y#b,gȡ0G&x͂Lptx{kD)62̫GZz0 7Q|&Deص9uof6Yf&-W0`phQ@2;Z (Oo x~n^URvG#\,a_O}|}&BL|#(>HZ(Ox?TRd|BE :saw=X9o@)pѦhUs1G|;k2Va+v[t^[ kٝ,N=7XfP,t?vWOѾN?tWZ٘ƹdhRo{+lt# eF=3GEQ*,a!C@zޓp7 ͵%J.G]]x\pW7ߤps!b$kǣxtA ˔Ke#?RK2$?" BH]~.R%O/*ڜ FY3kefJo5ZLF=kZӊ~ipR݈3Oiv E J.E AxBJk,-U;4p藜獇wp84rm,t(յ,$wbW~&b@i͢P;pN~o~"~n]uڹ<`˳񂭜\_ξ# 82ָ|[ s_lɱ{{Sm49}t8MyoVڲlOop4GQ^޴1yl' g3)o3< 3,{d*똞`/TӷTx]U ;¸|Цo+{0"E¦6`#K]ey_(L.-lh3uK z#p6ٝFVc8M[Ve;O}:xs?i=}8i] )4:'ZBb\}ky)<_FȮ -8ݲd} P#B, %rP[%iHy<|=*cH+p4^z|\}SOK*#< Ljt|0"Gl <m5_ g3(oҵ!@'^,JJ| ORVzXL $Kj>K'eAoD?KIO9"Jw:m:DxTW J?ePbFuv r\.(1(QzQb B:]-bL(m2uJ H(0bWo-v{DWF /V J:y%"G:BJenctJ$X2 Bk &z$V%'Ì 2:9wM,2a|_`@Zw7S2 "4=oH^ޕOX 3Sf.g/yoSE>1ytҔ1{W:4jml/Bᢈ!B[l2V!B|rV(ˍJ{l7)"2T^\6 `kg@Zj` 7]wyW"$th\"N5 ږEhUMjF(Xwd."fgU%BmEEŔ ~z /C "!-֧cȨJa:] P/:)F1 'Uu%"wu(0|6bj겅XGR ˍ;`pٜ2%U]2/R #/X3nU8ICAE{[̬݁fJ4koАq;_=lQLS _E͜o:&pyx: I-jQߙnSoդZ!*Ń`zW ZЬ4\8T9N䏻!WƔnL1".{nmv2(m(Sb]PMw"4A&|6tzl2[$`}]ݫ SŅq mohB]zF`D>lЍZG Cޢv_5퐇&pΘs8cue_#˒kZd(ŵm;.ȯah6h3( /j>6m@K9$ij+{)H ŗHPHV_~yO.43̈́:!Nl- F)Oוǥ3nQ/9*x6pΘQ?(ZX~'7ay6 H+= -~X a"cCXa /X^ж?.87E4j 2rq sK)/OQ3Kzȅ9_>  AzE*-XEvZ:8D5,<YZ|8g+ւm2:Z&EeH9, i`{4wK\@^pJ rJ"GNPKQ~st^v{ -ׯ2t&Ro/ %}hRv4+$A2UX`(D7*RܿO6C6[Ie}M.**Qtm {!(ȯ $1`:sh<~?\/Jn^X78njsߔ+b?BgF c4.pJRVfTEQA!tʡCA.3.U?6_|96<Ƕ?Y\D ~3*qbimH hO"2H=0M ]iG]AմMxlS, y8j~%ڣF霠fOn䉎o'?I6'm=Z~bC+@ O4m~rKx~rq/+kN<&H6n Z;ہoo4 ݪ40Moi` d[w|Fo k27mkiaj[:gTv-Km]SR`T+r~et)~JQCPL1?5 k;}ItbBRq Q,9WF\?+2E$- .72μ4Do@ hAbX|6{aeDΟLꆜ,bHIk{-3IdXmS@dߘ)pEȂg頌0H F2g)dO }p:1T܎j 5~>f-C!3/Sۀ;w=d1~ROXVK è9 nf3@ȉp<Sk`J˛86])4SwՉa# cKS+6עfDRZꨶw#G­T zSUZ*Ckݤz{፨ٶCU_vXɑԮ^£GEMn=xޙ=k.Yo^=\)p@3 *@ˎ%ƹb [p{(xDNpݬ P(Tl^!Cϋi8[x~#^h0qp%C N(격n 8Bo  ӕฅOfGйNʐ -26n2+Z Yg ; Ηkθu(|]c'l0H.]˂EZ2Ib"hAEZ>[=cSǘ[k > ( ]4]khY,9O-Rܔ ;H^Jpz(cYSdE?z ώ#Kpd;f<2ai ~/6W [O@B7C=w N[|AQ etSg۵t_˧+D $ ෿U*~f9UgH%+k@;--Xq6GOѕ"P*%G&xdVF| ʁg e { VTL2ѹD\G#h8_*dY>l+"NfVTӃ_amM59fՃsY Uh词3=]яqeNAų,f4-H"J?G1W"XJoje&v DP@?OAzHAJQ ji>>a8.8:_(s k|GFCQW`iq~'Xp7aX'--9_+&A:mV Hav܉dܗEUVj@=W`T&ܗc#jfgqpk@ ,2>uh叡ЖPiym_Ҿ*bĹVOkˉ#=s8] XO(o5$>r#3aw.ewd4DP V{ V;/NU&DS3Å`bhmbS4'"@I P98%6q$etL{:4C$*y-ψh6E'I߽v@>/ *5]t^DV9gh mY;.\}4oY㕖 !EVVS ,p |!ZñknYSR00 J&@? B Ϳ"w-pQU[  b y€&9gpP|izSPiMMMɼe~Ì|e>OAη9g 0b>{uZe|"v~DVɡpYEV Br|-a6))2Ǻg<ɻsBt*j I nxr%d+*6 Gϩ:VMئ%rl/n>>@K9ʟ*$!rz e5>vW8}9-X|?6ɪ7k ֚L%Ӕݵooވj#"Iiͨs@Qk,;MҙHAZY wrRk.fDA_ypo/atz>EWQ/c.5(K8,Km~'5eO쮋.`_xT?*)A3N<{"Yt'sE |Ub+;]gC ? ps>;jϰu?Z/l… ssmLr jyejÀ cD鐵a7[v-+c1Bdp,(hw@{ /G[ҷB}}LI~|di|j?T[Α$(Npp,l6P3؝?nJD&8na8jILWP妟8z܈ Sbl9Ώ<?7]-k!*>S4E:"^(cI1Qj3֠56m @PVYݥ7B7sIZ$.gc Ġ~0e\Pݨ+A9/a~<,iey`sAV8:-V̱ ºDhn;^L5 g)_DKFD,"X+X?"=G ڇNjK߱=G?za5gtF'N38X{ N{qQYE{ONͲmY6W42h-&rNJɐs{O7GW=rI\ʷT>k0kr Dm>O?BtdAI.E,ߛg+5+nkXex ?OHǭ^-ub`r ]K5Ir'|oW Yw#a>m_Wyз֓X:2k ׆_/(X#ꡓZ$ɰqyhㅙ$w\usp^"o{)^o&T󢿾d~C@ٷ?MsaD{o?y3] XO|NJg !3g2!Og($>C'>_Ad]D 'ijH01/gc/vIX7ځ;@!JLkf`DkbۺnfӝWE< q$$t hso֪u9aw\ LH8,e_Ee"pr}:G\S'q 6!r* J7L8޵s8Ew}WodS=V3I$f"j 1Ql):00Ln5v\o;>BJɵ=tPED {, <ۇZ1 9V_!+퀃F^i$<d@d΋Q ۸!a٣LFѯ>y֒B*:֎qp ϲ&woتƁ/6VKgUh;h6a8.('< nc\/I`!ױo-"~#NYGܦFLZ7S!`b)2٠'EZ7?OhJDyERufWF1T(nW^[[~D hM8хw3Aw ˲JNKJ@Eypjʲe;>۩y Of`K5r,i[?^5#C\tW ?65!"4j9!V5OR|qXA`J󋳅Rܮt4zK>g2T20S7~:/(;-B:z|@©0 !\ˡUc:z{baRX:VX:[a|DSs2vsdsz)qힲyL}/z h-IHoFIG6 V}25[wGkh908'U*I.Nj|B|-h |] L(U8{8çOk ;@(SF ɽ*\& VEIehiж5K8<l(OW,R7n͔?[|?M%>:,u#ŜT;#yN``]0^cwyOB OHUtUY}XD3 qdȳUveԐEBG Y%zߓtmQoXnV-zK}B5[NߙH?xj 4MQJY[>ݚ馄o&,vQ‹gvǣ0KfO^YY霵NtoTmCNwVgntЛo7MYxK&]o8 nDGw7oJ۵Eږm±׎msktcw]/{/5@?xWWf ^-}ӸBX{ڥǵݔψ˗;ZUKg%l0R:D ªE`ԛR)]4Z2|=q/m94BZz$u ,pxjW2FƎ !>mN#Oݗ98?l´m:I7ΗYl(Tc1?3 AebgdO/E[/,&\v4 (n.!صrLn64=a$iIZ=A IZ5ҿzCK7Ew>21 !4)Ț;ziȰpU tPqǢԞ&MWAHі u;0\ kY :.+8_fVs/(d狟SnT&i$k)sVz?g5No89L緊>4 ~xOL\qINc\ ?1~n ?l:~^PS}827n[?P5'~\Ao{׌;{f~#d)\yJ0+J_/ok9jJp_ p?^_ O9k/>O2%dA/JM2n;ǔ?>z}ɊDjl{&եS]i99Av\-Zw@]q_G{xۻc54ko^<3U?\2jn^\+Gnqַ?zG%kJ($XWT 0 Ph?M-Cu"Xs^'_o֚HMg"4S1Zkr F@L1w+Kd/==UIĬ?<1Ͱ^2uknnnU WWwxrw>~{/YvO^GM.<;d5¯vx/ l.Yr.BXv4p~^쓝zHaJ(}LO2H0`&$ LϝKˢ "鞞rBH"PPr(x"\_U1=IP!O21$&Q+āKQqP|y (D?|R0xcwɤ*G=`&QN`b}KKKKJKޤOPBhMBK!%8~֡Zj ϡsf81yMJUsMho77M`UlL81ԙk1wc3pXsR=n[={ƚM&feN1(&m5iZogp.JgJ{tt U'`xgMSkGq=p* +6Ahn@E;!Eݩr߭7=Ҟ()l1ZCQN;0a3(u-zqeW[#b _c"D5@"R5zs7\\?P GEBT' /pw7x0B\Px}W,M en Pve<_&y@j_/X;QЏҔ f%I/܁Aɱa_. d_cPÙ[xBiJzǬw,Jߤ7XZa1Y^f1ƁChv7M=;#ovcOn}O wIX/wuX`|z;\(U"/_5S$w4v3 1 O\p\ WXh?M zb2  0đ>Vdp ~WF "r7lEfN3:; oЇ}G~$aZjʱcyr~ޟ׼*^9vKAT F^->$t9 jx府mW8YDaj͠¥߽"#Fq EYL]ٌhVkS"PNdiw3ii #mXbB^ȗiA^ ̒쁜[Ƃ舘 @'@N`4s:)DžX?ER;K?D²2rEfyEwbtJ5_;vS] 쇢OQA Ǘ0xiW2 ];=þQZm&0&hfϮy-vd(û0P2l"/[P)~מ]"O$Mf#v1}Ck!T"1Ll:bۙ 29 ~@K_d{Q\$CA%5$ 6^ UNFH:]@2 sڕػ$3C4`2Ύ}=GL` z_&)d; VߢzNTEz]E/)frR0qQXi k/=G:Tae 8@)kb3>'DKjHq]բE׉.! ДTX;B'<5'AC@g@!4sĖ/qi 㟕_oŁC n]}Դ_7 `~8R/e%VJmPs__nRj`Lf#mVҌћi;M𜢘//e2A0^?qܽ  wQ2~Mtc"Hj3^'>rw]Z [-oZҊKP/cҞ d({eEY5=zJy)q/~I<9MH94&lkzGir^?.isf$4 @Q dTPc~YS& u6dk A>M&2N䫍tZq%=|vߏfT&ض: xy駼&UdH~G Q(=a7I3/?_7t{djTW r@u-'2d5x_7K^VXv%"hƧB45(3IFȨɽI"+IBMIz"G))2el3E|,P8Znx-S/@jP,߶xk'qo۪9Ŷ - \<>֧"SDE ob"e*,"mmY ƳӞXp7:yEbWҐ1zkQj#ZK*zMjˋr1 }7Q\FGr0F.8Aow6f[I_="R f|)Usɞ%RE5٥A-\0iɻ㈘cȓյ`%v}&e|sWҊt/Quo?$8pk =ܑgpİSW}:/}eToE\*,۫Cϧm}b XIUdm3;@߱pږ!P|iw.|ʋ68m:tD,|y Onx+Fm/WFi6⩘+°dOfyV.]^_M+NH]%)j;NKIn)*OYFd:HQ; hu:RTDԉ?~I!EU$u|N!͇*:}Hl Nmޟ3H>?"u:~:YI+:?ԉ:\}CWvF5CNY1)21]R'HfˤoJFJ&H*Z܈it[O!uj_`@ioǤN;)wVt~:y̓: eEP}R`_?>bŠ١ ;ԺwY"5E02&"mi4mZ.֋Y8*+|ׇ5 Ԭ8&T97Hx6lEbs=rHzg".s;Ed#.ϑy"?Ԇj9iEqCpS}^jan9%=I|(mNcNq_5?9$o`]f@ӛ9B1jn7q &V=:H,vҞ>_AL/e+'Uf ZJ^uh~a/:oӪel`d8:iJ7kor!t^ _ 9ن` $.VgY(8ŋEⰢ Ge7l~؇{|' !4ke Adh5\%d[VIn=z1,޲^ O AM'Wy21+7#)##=##}#U U}\t[>B6A(?9ΛE=4ۻcbl,7v`[kvmfet`[{!RGv[ry~INb~8E sFEФ ?/;&HD![X~#v;u)"p8fi\yCpOșF<hv%# x URÍ'e])JJqB%BUOߴ!䉋y᭡XO jdZw 8TK?_%7ycoůڗ7}Q@˾iVev:)Z3ZlF豝 ^zS[=qL4ѣ\X'B7I%lvRU9!Z|󆂺c0.^A\jc˦J2ulb 6Gl ;ٽ˚"xY~>]w ȀMc._-s}qFjoQR,.1v Fy.b1d83w%PQ%fFK4wBo7BCQL%s&KkQ1j2&8'>8J5FcbV%FX,*8֭+VqFqWGgPs? -;i/~BR5X>)2hL=b3V,[WMkܼ8)2%wSҼhGBu) DY;7 ;F}vz(e+L3ɈywUTV_MRI '#,_hnt(oF&jMvXt g,M oMFnJjo-mTBjicMn= dti0`@3_˘3AqjMSqo)ͻyqZ|zdOE3Z\3yI䓫$ i,?ih$ChA76x0"LwT*(.T tq+OIץrN (|Y=:H*/_aFCthә?lpb?Z!eݳt_Z Asm,NI`ɨIp&FvDWL&Gi\r#_lIW/\"عIMҒֺ= ]o%$HM7sU7|YMu\r\L4_>xvW)qGqb( ֠ĻšX8{0M3'T3 HL\P˲_\om1DOrPCeڸ$aF`kn:OҜssm9|HҜҮ *>{eKDYH%Ǜhˀy,ϭG~}GZ߂M#SwQ}}\ _o)qY]\^k~Mf`kFls)]xC6"r/u9 ֋:;but"6Kʠ|D+Qg R~5q'Π _f2'g)LMA;&?%a-лAyM^N`*ϲ-g,{Ke ɁD9r<,z3 呩QP2ۧ!7tPcW($ +/8G3 D;rgZ~x@&Ҝrfё!`{_bEmx堃 )ޮBg}J;G?|\ji;)r(c:w lөw!1uG!l0I{А2 =ȲF9Yx5![eeq 3>"0HC2f&8 d2ci1DXfu7-Yᦖ6MYdSgߪj!8Oq?4C5eUK\6-Avv_:~zף?qw=!޹lj%s'd4VF!=[5AmLL"ty?$V 5vO~*ͧX&wP fWa>`v\[_g,;9֝z|3DnffZ >Wp"By#⮭y8lnkrE{&h~:ٛlUlj9N&/⽎Ւ1k4V%HQFc4y4MoGeRb=$'^;t, ~T%jxh&( ΉjAY3rrID,؟{*A4{k׶5QK?~JjFͭpwhݣf#lQ0Y'/g?%)%L//iFh.>"A+ۻ BMswBR篏W~Ҫ55>@ʘjp%Lb-ęo/IYcigU[)\є *=1 H&;Ċpf qrǘO)OCȻ_ܳvBi_J֏J(YÇm::D\FoEC _!E#rF4Swad}|*ː+'w.@SdH۱ч]xSTN_* Tx-ZlU'M3! Ƕm"c<,2He$g7dMgD{3z{3=dיƧ[]~vL3ӝ?^t2m) ~3LMZ<(܂cmԏ62ü;k7θ(3(ޔ2İzf$HEe`+T9'*W3ՌOp+O}` {f ONq¡/=.;Fvhmo`mczl1ctP" sbxjlC1LCm !' LtM{#f[,H aeCG_::H6Jj2wjݐ_b6è-]k5&>őuz] 3| dGo{Z g`BRQ<@wd@}DV3,c஌ҙF3B CJn`jw-M걃*E{TB?ul_:墯kL Ţ-!K[/!?VxWD"W8dYߪN Q$抍͗lsuy>2 [T޼9|Xj-$[xo6ACUzo|F5$so ,9aVeee4+uf§]zy U'U / \s)꬀cѐ 5-]/Y'^z&Ó!l0c;:ṁe/S<,h۲rLd0+&f+Ԡc@d+(zLYi3,%VHYZ~+;#\r'Jí 97< I2@ma< mh5+嫥2ʗwl~$F5]<č&T;ƄN7Ei~>'.09s ɖy.El|o|O+d!L;4 9PQH8s35gܙ!퍧YAԚI]ZƬYi"{i{)l1K K\f} T@|y~`K4L4Y 6uYuY2;,fNdxy39V7 NjhxmjGôD.=}%4G+J\o$2{Js;y?z[My-y`\2Hz31 Oi8Y|_עMơh,oꓭVgh9;faGC>5E⼟~*ZRZ6$p_Sȉ%g GOH>DR'̤y64][>}I;m:A™ɼMZmv-š TgKFm}H6)8ڶ 1fnI6`[wHC o/Elt&/[|-#_ib*y ƒvqDQߊ1e6'Π1RR46{աj vb[r&՘-9"C|~-)IJȺ$4oؕa$0" HP w`׵&DpTvW='>Aaa+/vG RsdhG,:?2YiU;W 7㍩wStƒwO/?); dS*ޕEqeE6Ezo#q-"]дʢ3Ah1j2٣$D3L(.15 >t5Խ,p*@`4E|7^=ڀO"ms?/_X8W|ɱgn9`6euvFP ~ꞀRPy%e&MD31/M/;^L/@1@'eف<#a]3ָi{`vZj!v6Nk̚%idibW| [/EȢ+]9YWK?e}=sڵr7е*ص][k-6&z r ZmU+ "/[ pM(uETlPm{3#gn;u]ޢ5w eL#Fٽ7Oe ß9Lɐɟ9ߙv wۧhl\,YVsXEs˶'d-VQE6;#RZsƞ9Jܵ>h{m)ULYW )1p@&3}}=~M5{uW'a*OS=ަ( ?ֺj4zKjJSR?p7Gg14%Jo/]pSR?KD}ص Ȅ{wp(A l_ v>p ^`QGr_2oN: ڿ 4 ElMNm6'> K#m_>,N J A[ | 樆3ǂ{:_O e9X8z|sI8g"; /}x{!,X5F{`>~ۓv8u?n"HLh fڤPjHzIꍔj|3ӈ"*UR6a`D)T @s*pv >gr@E7BD??cнoG z(z x^8D6W7v?VD&Kg!Q7G8A*!=Պo_A R߼nPV"9?~M"ܰ\V Vd{\sEjŤ\RQԨle9r hEY)f+W !eckS8ʛ!: @dNe% JXELY/Syz_x5Fƨը)3MA:Q1$m:7QV\k9CD__7Q~&P9(Z%Eg' D.V%@]g'M%*8]hR"I$d\ 5dq /R96™}@aYTfmVerkTS[{)syE};ZaTgg%f2 hփ ،$%B)J09_#)?v%-j0>;kg6LJ/V 0Ӗ3) |>ŝ+F@D:7![3EM! jAńAc j1Hj I,Q;D~qJ4#nfr5fr m|DzW#"&Ls%n3іJr4eTC9a-t;HJX9Qoq'e ܯyUܹ5S\rr9h)knZf`;}/u]8#0.g99C]o$)) k3 8?,.+yٞ3_)&&K mA!5K6dn +]~-SaZP̏C2m8EQ1 +t1<9Y.aiRlˋ|';싐~)τ_z5tNl:r|y_dp]n^Tp4/V'sH3%鎂,Ogş~F# '"IUr9bt,e  4(tM o_ߠ 0f5~@Q p9knkRDÂO>hp].\.t> (m'>)MK8\|[v]cpubp/;uiΟK#ih,:d4j&J1:\ |#{jtV)`G)55eb(E, hM;A?(g]e"[`)هN_E`nƘ_? ze2or!Յ~?gaͷ٠BVHU(7.a=6ed->9H \ab@܂y]8x ..sS%|]&ZSi,}/4E X-Z3ai5aIHS?:xN4/Z2דI4I=a:Z7SVLMIcl'7BԾCD ,@n=atBZ梟=n:xŒ~[ re?SG{s::7w> \Y^޿Y3뢉PjG J~_' ?`:13:Gi%k]6|,hP4ČdePifc'=xtvnСƂ4Yb.1p 2]o),0'eӅP%cİC5L2 %XVLT"+cFgg]keV<3Nʞ;e0}RqQո NG~\Q|"3PQ/ߞn^uݶTfPTJ?8]gsY6 P+/G-G.@Hs"10l^m3>4A.g7+S< f6%Kv,12 l<ǣν_<5Z0*,z@WNMtr'bȹ{:__eÖӱ;`ݚ2]A{k'c'yx ƀm\fVWqʉ7A _{JMR(0aw',Sg??;d]_2҃NRȐʼnh Q^e-:#\)z fRP+d`!CKCJ+,H2d!C)dȉFBJ;BhRM| Cƌ;!C,{0Tc!Ct[D#8QmKm }AR-8A[%i E MI0@39dK{g.o/bݱ^JSVMb'sa! . a }c#ɱgQm?LYR0*+ll|IʟWv*4c?U%m* qPٕGd'bmsiZ#ҵuAdm/ѝ t93.o)]KJ؟i!}l֋ƏnG%ᰡ#g7\K3 S]c1Kc1Ҳ 27e(*׎pРǏQxb7Knp+?Nh'أPx{9ݓ6F"+EbFnc/PtwѸojFѯvwVpƳ`)ꭗ>x~o7ar([\>1|e[{ kZ@P)XDﶵrLm״z9&зM7,.~߿<[dLGC~Ź+ ܵz5I;nlnCCA(6Kja^%Nh;48hIUG? jVeQrr$(]J*Lߏ_v%^X,f VWSFBmQ[)@(&`6J ;@3b|eZࢪ<P 8 OE`={^LS1df V<DS{EfZhvI2O޺io3&~ Fֽc=3{=_$J#&21&%yG|sCm1Z)aVKmU} wtsjtBj=)6b%[KFA=P`$nd_6thYI Ӌ$_g-XȈtbHp =IRG3U)4D*@^-TW mK3's`bCSNưmEg^LU̲_IA Fލ7a& ] pmwY3r ntU) ; 5KK+}tʂ>.)vlEEbEMMZQo_1sVmEē@g@s^3l㰃^d #Nx܂Ei/Lx5n-N )!+@z+Ƣɋ!X I%@bP\f`ľ,*ILq\nddA _,:b6 Gz~5:Jkް'wjp"gHI!b8myG͘l%vєrTbn#L>Jo'wd8˳=*M#7 Iț[*Vu =}̕q!ae6Ar}ˇ t*egZhO Tۓ}=)C%Z);J =P<sN59-`97V;vnuo T@NBjbVDC" nj]?@x­T7;_Z+֏OܸG !Mx C(VQuJXr͚~R hCyة >: LhC̿jf'!:Lm.1$HM駄sr2 ۱ Ropn fěm@6'^hl|G῱s7r !g/8 ^ R!x^0|\WPJ-wZE`{>R`{z彣Wy'hJ]|Krf$JYC4%],Jrnd[HHQ2ܑoU h<'=QS"f[zĔvsn-RRL!]M͔P:,nABhck;jS_M}jr50U !z. bWC ZuG󰚬Ɣx׏RbJ{#vzrNfJcʢP8B!\1v&0_-\$/JbJ]ۡ^)eǔVHw)4S}\Kh|(I@8g]rΔ\.IUq~,~ .^X7Tvu]ﭥGA׿a\Via,6sMv;m,r qQKO󆐺Z> SA@ˁܥ/ +Q0dU EH$ZcI\M꺹$ЂvGeA.%-[L`2LNO M N #ז:<;lѫ9[쉷i@C 4V%Nwq5_l{y7+`8.W?4`_]m[PP_N-LbZ8qZxj[&3k?5jeW6=:,)7Dg ._;ڒ+mm\62wfiq2lmi[m_ם*?]{U :Sl2rD4}dzzszӠѻ\!ٙ pn.Փ~xkF ri&24,1qQ%5A 6oAți/:̅dAhphVrlv+s*Dṛ~]ܰPb+T=;Iť*ᤈ$͑\3Ng^hHX2EF@=wv׽OM h2wV'OLIP 2\Py%/775 xG?1"`KrF7 {؋yifwah{dljž9.ؗ($${3̃To;\6ϕ'ē27OG K"~lRXrrq=eΊ)2Z*O/_2gQROi'5#e.j#dQ_ORd3E4ϬBDx;LSj+$ԗi'(hWm1gFhúlƎw9?,9c}CH䪅KNTmz o\,2b'xϘ.L>/gv ix@q!_'=OIGǚás3A$BUBsU7݇ykX%vhmo::[F3&" n7v=jZl,|pt ) I# SŀvĎ dEY oȕYM;ߝb IE-XpV:"|}e"=A^jafkf= qQk'u'--WhJݤ ;Q2U "{nES~9xYdC2n`f"^X^&@CZWFX 5ga*3҇@@fT=̤'6SWuFwR$4H1? &AɻV3X5yQc6l0hJۡy$(CM@/sZ#G< ̵i[IG:.C a(h#Ff\]h0x܆2[|Gze~7,T_/<8v@*B/ˢ<Ҁɏ@[`FU jq,#i;Vamq,V̳,os;vp|jiC2 Cc7ȕ`Q F<=uQmT٧p͎0CB8wV>7W7o] n:eeKsitT*f0֧'Qۥj܎H.HNK^T0?J b#biz#WQ..%Dk]]X gf)a;> @${ ?= ]CA+rL ׬{>f`ߊd nc]Vލlf;g1iVAe8&ovcH";!: M򻥩n|wM>zVhD9~/wuQZO RA1ci'̜i>{(5I&ww&@FI6Z/4J?kA kO1^u,1Ok*VUi6cu 6%iNϳJjJe͎nw7)<٠t Jw9XmQ989#w C5̈0ﱅ"I?] xEڮ I,X9 I_3*9$O$}ML&A !ȯP9VqE]w1.ꢂ"?*B$WoW_sd&<9zz{WА`oTȫHâ7Q#-1˫2rf(d]sq~]r?^:COGy ,dO pV.N|0X0Y9}1e;7kO ݫe{ !ƹS#D]_t"Uӥ7i [~$}5%*B3'R N+V698sS-G?yldMCoFܩ;5VRqەd$V zMĹww3{(_a푗%4mO"*0S lge) e"esЫ 'Ea$>д]ȹ϶Tu*)Q .&mdmm;;yfoAnHpW'>u ȌҞg,B:KSp7͊=y^WT:Mo\Ww`hZZ֡j. ZK &miD9(ZyU{<'o2`;w.76\G8b$Navc4N09nF:`7;:14AG2,Ze#zZH1i ᪮+ԗ8Bu t"HP_+8cL[ ̱ҟ _,W=1ɗޣ9w_ ZNCbBzƬ0,P '@|"̿T bnԟ.9'_,Ujk fH< ;~J\X2jis7l&L~J tU|;Wk7} \|FҏWR\f9o<~|*_xU[4˧ rT0, (0+QP)0wAkn-r9i~P_3x0h0pŪ?}eQYQ.WSnj /|3ҜW_-_vyW)S?/lZ~U/E{eϲ>>5tϷ' _{>AE;Ekߟ|nqw6Rk} ɤWz᫠Nx"Υ/!NKs  Q/2[z"ϻ$C`cl 4' I70 ()ӌ,U_Ϥz,9 %0{V)0q(9syE0:n|/ HώSO379oSGP)]!dEM{2)nx :2{k Dd?/O8`'[`<'m$u1:&Yg;ZB\w78x|-~W4Q|Y \-\0AE=03S zsJ OACAa(`L\RXYR8ϛ~7jar8)҉ 9ڜܸCp^#LH2(  ZɟigvHğ %HUX& , 5)ĭʊ Sů!K􏙿~3;/`bBG3;dx 'C8D^, Di>D˂ȯ wGMyY&!bvE\Sfgn$ ' IG1 $m$w'Ƞ?fcPKW҉A؍Q?$('qLUNH4PAV +!p?X Ά@cE}8dq2Ywc:?TEr5\zq23jnE1{^QٜO/'1Sas*9}]}{rl@Bʱy*)ztwLE1PJZUXq?H/MY&@mk@Owp(_@~݇pc\ũŀV,; DҎb5jn^qf8ű<6aNcpF`1[ĉ?ǢOe8 kTW˨F-ݮ>K|/@ϕG 5g ZUZAe^(I_|p+}o}+6[Ļ)H3ў=%݉ N&&;[ARkKZ_Z 5B\p`2Ҵe|RZ%CC2X1'`PyՏMVsYDWo׌1N'4Ip6ih%0γt#DTS,_tQfE0sIsn("nha h BCw'z^(9Gk=c_}oQZw$[>DD(Dj8Uvg0bRClCR*(cYD?ғ0,ł1MD]@LPnqĘ]֔z"vR1fMh_pj=dL>ybp6_v8k`\?ry5ip"3CPpU, c8Õ=?>?V@9yx qI~8}aJ#%`??{uqxfbÈAV.}n 5\#D;,}rqT _ 7s{' b.V)͆Q%,[T1 = (|YpxJvt&$I6"@-rr73H tҺ?`r3!pIPOILZa' qv'G63tEh#8b1o Wm9+=]vAa#-3a@^-I5S 7W6oC^fpYc&*PjZi<#w|y鹿4irI!4?^(K3b7eaBTXJmm+E@ \ͬD/ڑ"#y0!&w O;lcXQ6<(:QCgk/Plt 2JL[_hA߮,(a5, \]qSc"aN06/V䄚%/;ek=Cb4$rpHI.#.I|(5jt  Z^u!4&L4lnNI#2%piv'C H.a8_b:?i|ɻS]Ok_WBpڀN2YA|ߴ%GpDNذ>_ÆE3|}3kLpkN? $/-$8 + CpZ,RNt@A5?`b€ԝ2?i^xSMSbJ izԟt#wX)߇t#~+ux@:_])-)G N`uT'OX;u?/UNGMmϟ16LXIpKp \bHn2[HSWN` *S/]- Ōa(f|'2fhlA iCٰVrD59OTK&B4(xo*CXm&]oРA7 +%OOԘSPs_Td>m̺ULl>8&CbFwv gvz|?aԿGM3 ĝ'x}o>"=LLb" IHB{YL_ALw'ɋ #E%pAVT ..("jsW]U2$~oꫯǿ +~ 4&Pfi}A(4p[ ]m]3km?M-+dPwgG(/lrRhTCU[wnu"=JB|5On\eo))P\'~/ X>\*d E,I遠{9w{<\qő G#&9%z})*gKoiË9!تߺb-`c?E$ʘv.7^{?V+9(KR+YV~VA;=W gT-Y;8?%QJec%zN@rgJ$)K!R 1[2uIX|Ưi>^(}ZQuS?AIe#iE$c])q],_எ||e숃jRu>CTt[3b8גs:\xudJ-U^KV@e씟HRK%~#s'Aݏ*ݭ=4)>KN>v{w!?;恳 Y@9.N3bUV+^r*6V.–SAs̩f dP[Vrbu>~HsV$:xDENtX-i_::3c;dPQ<И1,1IIy -)UY]:PCvR:g:&=BZ+7kcfDDAdo|۫T=[Z(Ti'k*'LY1lR=eeJ&OcʯL}aܗ`SMWSv}/+dhIP$_AoNQ-if P~ vF\#v;:z70M[u&=caY%rHwY\+{ %cpklĦ aM]6jv^vYT]1H&+9(jC_FދOwՆ )HA 7I9:;rMw 5eh؅-p4kJ3Dq=3wj Q n,_cF z| l>f|ĮiAWT}{MǖČi ӝ?ie(1tH?o;FˠDZclAv sr˩jS~ °aYjs]0[lhhaY33W[Gf?Op!?:9?H&>5 ~s~)&W,hfeA%W(=MP6 $̯3TCNkA Piލɕ uzj7N2 ݟ2fjng%̗ŝb$7llxƅz=-96~˗&!gI&4'Y2 ?iU^IȩLB'bA󶟼]K.I}%OOkܩ+ 2Qn#, %Ǘq_A 7#xjW_I2$a: Qk/DAȬd.LPia^ClnB&ϫ`{QQKhn"UZ? H50-Ym VeE %zqswغ.]俅~"Trv@,{kN7`]K ^\ESo!m#/ZDB;"V !}B5טRdem6$S@wǸi#ן J+K*\?Rޱ:!OgN_{CrDC3<#ӌqYҖP[Ӑ!Q$6E@5˵xɻ!J%gڿtr7Cnmnq҅p2Z%4#48M<.W?s-L2Gm6;W+7&cCNkP,vqۿvhZxn)M6 ɚ2Dnh A(m?ㆼ! /e^VXPD ON!õ]ynB{okݴ CHSҔdmDiY5Z=NU^.5zG8jw"fE,MVm6E3f)WamAWH? 5сO-Z=X$C|!+cu>-Ow},&u @(''k_8FzWb?"p)hrH pƖ+|Ͳ9ܑFrmrĒ%sxN%x.ÎNDT Q I3"ډPj4FhV,'; ]{0Y,XhwfLl`2^@R4um\=sjHƴ!&oby'qɀs# ۢ>,[p2[PY>c|q5GG0-_ x@}4Gy55 =΃C~8A~Ld4,?[N9V|12 +8 Wo7 H -#m[/ڏޝ"Z,nCC~s دIA~;R(pze 'ԐifX3k A&_yD2Eg3)`mVu d3 c%h?/'i&u;/s'\M! 6/eXfӧqS3ޏGxLcOq,~n覥_:=0+\]ǭӍYFU|A[q_Qma%*ZWTǁmAHx-[^Z@I/L?{2xNZQ'Pe/@oxBrgxA!dՁ+#vHn^Ok6!.XhwXYFMZmE*`8ΚW[GW1A^!MgN0A}V9сxB(} @$2esJ>wu_#WQ{(ob:!INf*v~bxUڙs'c#Kv C6g>|yW?O#/tRW *#xʫfgƚi;?E*F\oUjJqv䄿T_}7[Ww/> R6ݗH6k0A{L*9A%P_lƎe#s`;X9"dHoy,#zQ@X-ª^QԽ@6us$S!U37.O.k3R ,Mx-3/#u/h3nhLn7Ѣfc&21~?LAoP'?R^tMF{x<3\HHp9n-S=J䷩ Jqѫb BX\(@L|z2% y9*9nt}.wP1sL%O~hªۖ@H@}6;ľd}@Ij #AmƂ%䷼65 Ή.՚ bb6t/JPz? r̵_CMas >k԰j*ҙ=)!%y5 _n"a7HȐBjܙ_vE#ռx= b;s`A߬[LaęgCNG~<19!)HNػ}kLŵihˤʯDMz^*)2ȳ6FYtܼCdhnȱg!d3~?kp^!jb6u]͏~8]PX(&?TitυT$; B61œ~ دgMεmSi&YӱqxEJ])]:$W _9-o^Gvo-=Ms3GgSg-+Ǐg?D+9?Qnx(Y+ǚǿ NNoZtނ_cSޛ,g9Tw}Hi 1ObJB[lپ.ARR=i+e^7 Uϳ@j(MV*i?m~I$4C%u 9`2)W$eoNx(SUQqQArIٝH:ҫ{罿b]Mwޒ1݋t]wTN/&6}۾NLN񆾵 $N0Rls<܊ԱR+fU i"ׅK#/{WEكKC)PE@VC4044fwfA|D-R13M35{?aYʋv geG":^~e_e@?Eޮ2Ȗl(kȢ t2  P"2pe7k),gM򯜨:~EIIr'\l|}v-‟`V(kX:prK(yL#w("jT[@:`\hVHdEA ]4>:l8OMe tpY  n_,#3Koh,?7~)y,U\-Ƀdd/ ~<F".}6ՕdoK1TZ V5*[/Xnn2˂ d~v=nBE1T\Da>z9 ))OoE߷ѭh nt]l8յu-lVtR'Do'@Zd X*K$_EЬ4*hjw4Uf3 ȝϣ4G1h$Leȵ@e|#f,9u2s{h `d+~k =(h]ND縗}IZ]heOf(w&UQ]{ͮՈNu@֦HCg@8P!^R`[&]/۶`")~@}bPMH^Be\c< 5BL *QmH#d"E~LqLP_e3|Vly5\bЗ~[$0CSI^Ȯ%ݠAsR?n\Ơ {iu6<pjw.be[Ey{}kȌbD Yt9}S{` DH<ڼzd 0|syNF'P&N\P C0?89pw[WwE]Yۻ ˨U qY*ƹ|b7-ڰzֹ:!΅Msʂ(ak 'G~i"Qf<|[j7ZAS k6I9̬Lv3no8N^_#maA6ˆCqQBP  o`zb1AQϯ9,&(?^@{3@oS\=aț͒s+6XDo3#uÎpe/ߣ̀[1Z|AuaOp.@י=5鶄K!)2%Fdfⳉ2ǝa:8il.jm ggW$; S]Dtl/sH9C Y.6,MRqL<$ ҭBG"4phb4&÷ ڱ}vuyV^UC>)iim!(fvR&A;6ʲ6 KZ/A׹#%;d^;TJWN2wXB7)C\KteRBRXp%[w=% #ɆGK#8V7b{~5Zl1-࿟ /:à,AÃ6O}NyC52O[Z{a#r m|wUӼg|/XMx."Nɓ^In.<0+c7;֞ ^˦iF46^#QA_!vˉD۫*V_Y]7pm۽xyt{io_ͺsWX[>e{9뽉Oo1kݷ鋊DǤW7TOjf̮;<0xFB1{G_^ۗ86WdӖ3>.Ϻ Η9D«-:%{^dJ}3w_]p/R7L<Qq`kC0,%:t@?.rVj6r0f3]?qN#Hu%N7HqGi\_>h%&: ШŴSݙ81/̘ A1W|:?{6%v-..^0~|Hsi\p@Ui䭫k3oFjYEcppH3h3ict Ujm[U?!yv֟LM>Vdb  \);ib`[-Z/uM8nY'&nؐ`_ہ=y\*M硓uK|a |BxnY4 z;&d0!gv~"· aB<{?< l!L 5<~ȑ-Q@mtTX-Ӹ3w,4nRr6Y8첺(EXe5Yq0Y,H׿҉!Ԃo=&N81(vXqt=flP$/Ap1b/r,xC`kjQn+j ;eyp#(֠_hoŏѪ;lh@Ӻ?k;|I,A 緇 .>| 3mjP8 h{ g3(c;/6Gmh)n6D08ᎀ,KmXN!LҾ/ɦ!DU) .&K/?p^1<4_^sm3H~Uaytd'2֕o\KƂD >^IkR&r.&!3Yp LBf2b&ѥa'u A4\<)Ikx#0]4*h*S/; -(q9=tK* |nA]xi(lcƒyD܀ oE)AFkhp A0җC|OMSX%;70n@D:oUyg}t]`.df2~&]H%S̬#+-AJwodG?o2`k1LkH #yViF4TN2y!f%&,t:YǚpX6f!]g{& !$QQ]:Y[.%M?n7ɓ 7 Yk/,Ȟ ge-$W,=tbKE*nI~An?%CpDly:mfnKZ I+K޳QMiIW_>nKQwO=/pp(-n%AH W8shóO͚%5U F~:d省ɕ ] CáyɆSqiǦ ߈raQӰ޺&P5~X:}DžӺ6,-?kЪÙ;?}750>qjS9HƏ'?>~:, I7t>})xlS='n%7F<%،6Y6jx"$\_kdŞXu5':&p:8eHY mbLL:& kgS2[?XNCHN^19._i&96^xH_- U$J$d&Q!bq6 @ RUK UBuH^d3#"0gJ(~͑ &@$!'IzDAft$ $xBV |YǢ|#X!~J诪Hl1^z^{)39OM;?ECm?$oߖ%hscU{~Hor(Nu JK )oܰO= 3eP?2-ܱ >BuuFVIWhtCE{G.ͫ`#X* pj<*F!Mhqޓ/s 8~\ecER0+ DeE㳝TEݕ 7RV4)@;R G0qw` A,Yj^# pxfDKHE2Rd>M<6AY3HAM1]ԋ1EoîxH6Ys?]h.v):Ao. ! 'u ggཥnˋM6)8Vϥhį%{%I&46TvE\#}mF7<- V8|)R&89d%LPCA'q~ /Orl$ ,W3[7~ tNֿ!X%9M:Y|GN MQ\ëD$#/ i[z𯎫դ1.QTWwAC^0|AވPZ*(FI-'G!U<ꟵD7ۺ?y ,L@7Wi+^',#V 2])s2`C (d▒GE} R=7)D? W'(g n޷lȑ#soԇ"SJ]Q1~v02W7!Zm.$ azR^}Mt CkwB>Pd鱾F]8e7V,Ftt$d\xtIADP- 7 #ؖ(:PH7?[n;ޢ0u*qh9(l yBiќj8g 8ppd<VMdY5H@#?? Or :+MDL9Qy{;Faj==>+]B{ɼPRC <Z3bs{ƥfvy7b%3چDl@I/H{:CiFvSN.p\0k> "+|(i) lyKIQʑ{"8BP@ 8 y(P9) ϞvoTnΉ}E=x3]kQQQ%ƹ\@>N~$R EL M&fsD? ML(l$ڹbza/leP2]ji oduSѽ5=A ]3[KI@ڡ$\a\m.V#Y{ElKg"Wglw[d$ ^#,EQ-~%ę8 Ƚ?T%ȹ(/G6{qoI,9[Nv+^?.8v/d\wW'g=>>^qex־pG5E_mG@Q$ׂq'.GdЏ8"^x ސ.ޥV[o4o嚯*_oi7 )n䶐T[*ok;{17啒W޺؊+~EQ|| !`O]{xWbғ+ĎVWY2؉%%v$`XoI"hg[3a &by59i3쬝3cs_?fs_$E_'WPݾVLQ" /i)F֢')EIuڧJ0x?6GGjx EFdDi7掏׃IpAvo٤-}dXT iTYfL st SAh[N-gf4m̜hV;4'LN+ o|Ľ?|/x*cJ7lkla(h'HO46ѶG}Q:ƥ@U0P.F#P -m{*"`Hpus™.Gd."āX9# JffzZ X@[ @s]4h&] Y!4W"`%7IK;w}IXRq\ٸZT򜗍u)3n]P:,,)s9.>7xO>ܟFK>i7?-eC ϝdJZ^f 5xgΡwG J[(]mU7)<c^sjZ;P=$cGM؃5sMg5:)ol9X>.+Oo/@ hQ9~K>ʘv432 J*2B(Fj UoM_,X2)aw4fbv`oq^w0)|aJ\3@8@ 6~nfY\j ZYn5HhC^).TH3`-kWgY>/\# 35_]ZuX@2z2&ɨXZp:y (cx_iA_Hwdd2 m͢s'aɇ3GVTmv):=ÚlA[ڋL_pAEj/[純j8aMj-d#ǁz?EjNk_Cvϔ O6nX'I>R(#/׆NOp2pk?6Ec[^H+KD$ԻQڠ]-$.{Z閽1xJw:e7~NFE{BگO5˓6o q^%kQө/~ ݵe_`؆iS8LO[m7>Wȸ#oG~),53GLzpqGO__5XƯj[z*asSch'5T__{@JfOUP~[#(:W~q+!4j*_|rD ݜ:z߼n7+K7988'-]kk=w# _+cē!)p-,C 2 e"#NPxEViM.!hV;ka 93X'9=g_~4|-hx.gJ#"T fn(V!EG¤(kR1&TTRGIw5ҷ} oSңBsG_0 [N][SbHqke`(MԺbr*y5Ȓ7G5^[S+378]J Xfa2zj4&1ZSF'gppF1Y^g&ɤ _HSK}06Ĭ9bepr~wf}]1?)3 $,0 @ sz2F3 '* ]BٚNEjC#4 \6~Vf%%`lNQ飵w E3M$uhM!X_s,JB' n+HՒXS 6@VdG8,|)%Bf b|A D\ ˥GIe\0_fSHrd+TPh8,PO1hHzq(_ Sk@k*TJ1|Id\ D>4R0͹~! >mp <;v-ZygN3,:ʛ5;9b5z{?/$KUrŚr$bty%Y1._;49q47Tbm%JѴ|`do;ʳmb1A;[Sp0Ca!PzA+bŕHQ ;.zfdznpNUn|X涂\}wĺk/wPf& ] ׁJ t1'B=xoo*b e.CXUXذuӀD]?HAEbE.\@hD9AA_'ք *6]# 6\ )XKPi:Ե75ɯ]+Bi2? 2/ʁ#.4>%!N hJ# $@~ @I w%w𖄹P+s$$ $A # 8exGs+†tZ# IB%fơpc6Bstp0LrkFK&Nd:mu;! {HU?+AJQ"x0 j?/>S :_A@*{Jp0O˂02X%*97o"AΜ"^%Wap>A[*bеc+`;6bͨ^kU|9[.o6y%kL8UB[+!I`M ޒժHlFI…;S r$0x O%qN1 *2, 4\$$ 7V D 75"ӣÿ{$٭Q,(q#/aMs }#Qy9xzy?܎vx}En5Sb)]ϰ,Xh Fkыf0+NLJY" pDJ`.13-1h++MB=KCL-2R R9 .pr9Z{X{_73/8xO6\R:6޷f? vx!:on;`*|Co+M-9wmToB]omD2n-1fE7E8N]܊=5|8t]Nnct ,[@`(s4g]!ƒ @V ᝖Ɖ[ѝBPE.[?]#Ej\( BƢ3r!פ0Ԋ:pnf_O[}0VdI~(+}{?Q)4ϼӰExBD>xO*N>y%Z_ntT=agϧ ~Nq|r c4aF5 kGP7I|hVZM"O&B;!;?āF@ԏ$A.RX2,h@/%`[*KK3pi[NtF _U{z9/ɄXk)6xŽN gG@7$zv3b/t$ã/y}&ނ18܋Dv F !tJ A9!mbA[k \@־mX[ b#s_R]u 8`Sӭw My~t2~56(R `_Q*竖 KtvhdD#W7cP>vU+ W% g/R)3 bDr]࿟d@ <0yyIhSIJP`0?nM׀)T\;l|C$x:5At57ğq#hu|aT#h p?AGqhh/2ov:yaat"yfRr-1L Dk5@VESM$*ل " ̗h`e w46Iە"ۋyd^9Yă.p+GҔ{ZoD 92>r1HT)_ɉu=y`w(#WW5 ż[A ]PYnϙ<8(5 Gv@o* 0oŕE][mv9Ͱ^0!DMmq.@7h&ѡ9A_BXGh7}\PVwj)(\/CFζ \kEVpgkVtۆ@}֬hV0 ʄ ae6۩927zYq7lf3R@y ~J^Y͌%nNfd\'g_M lDrVEeXh,2GzEunv~sЎ7zN׌ĐZ-/v]qUl;PQnؙkM=2G/=˧] gB9~4R/PyV9܋Z'\Y CUpƢs@-C' H#qҩRP_kGՆ {c@`Mrc E|C ZɢK̃98 D"fcS_p>:E* Y&^,KNx'grE鎏7[ ƳqtM' ~ޱ5\Fڂ%`Ϻ;PPK],G,}rEtڶogKXðjг4BQb^L0R H}byH̄{Tb)Sa5@"g1ye("G|F\66>z $>yx'G z sm~_M;3\8pdX t  5.k/Z5Yq7"8OLHpcYPo%W/~"?tV51*t4۠T*J0:"W1JRh_V խ `eQafϐaIyxc&p S&_RNRXsX|CV|wc Cel i؄L#d,2ВWV8v<]ս3UyD(8 6Cpx #86( |m#A5 YGPk77F—*#h!uHpGGiT.+ ocM?8 "Z֢U(JY)-*Jk1LJyJeyQ9RnWYHuܤ2~ E 6h* @yC ('Z5ԽR ij,ɽq2NXvHWy+5}svM̄1Ye?''4xoy1t 6VJ9[;xt+b78CO?^ W[܃7e; s0?}HڿJc6[,uNעR &ɬreAg+7oJ-~!ޙh/Yu u IoI FgY4*#"G@N!#@4Qu{r?b.qu"@\)@}Τ,;z+tʐ W嫤niceLf]r uWv1hoUua9tSMv|8-'m{֯o+3>Fhs ?d %|h?iD@kJpNkCRXcq?2+[Smcf:L|zO?(𝔫,k+ֲs3КTl9ˮ㚘Z0Iv_\;כI>|Ko޵Y ʃ]w?Rҹx%{nBOU-@XJ.%XgY~l>nn#Ҡ &F)k&O՘ r8PFoQhn Q $T%V̚7ۓR._`B Βq~̩eO:=v˿&MJ}vG]=Rp62s~-ǯڽr?rˆ3U[/zIz[^OyuӢʶHoύZ?ЪtC^/^J/0RE0=VX]D(t I٘!֑0Ia~μ:qb 򹾰.UH͒M&=_8, hOa\'Gu;Ϧ^2M;}Ҽy-gPlWfO_(:a]Kg?3at$K9(R[E =σ+ (YS  1 I~kGAf}temm8zk+ GAf[.2n 2+udVٲ췵 v: K}|$G{yQYmt%0ă} { lcSjϧSVo.]QyN Ϭ@=AV{jʉtt\~豳KcG :1q[Zo~Lq Pw UKݞ߸[JG5quqٚxӣ/lOnK<x9xu߻%mGf+agb?obw<"5;ye螅X۾y!?/)}Z1AǶECn_@'c6a)>,)$~?.~;MoQ~ @a\4ҠmW!Dh_E<^"qV2Z#8L mq'f۶1qY%?X3iYT:ڤH{r9Pu[}lqzuE3rFQŔh c<ٝq?_F;;`#@ڰ& E량O-"S21je.Eń"D>nN+_%񆅶ج]UDL~9H-b 0{#n2,6- W3RJUA6 ‚6س EEm<h#$ޕGQW}$ $H`@;*t0o0IuWuHIDcΨhPQ$?fG] 8:D9yޫ;ƬAR鮪_}s[ɉ[aUMY}`@VreK19`&W"5C- s,(/8E91$rEr$R 1P@Cۼ?R~>p+38@/KfCW+I=#hŅ>Taj >B+&5h|t$G sh np˘GDzLj`&ߪ4 V5J!Uӆ}ѹDG˲4È̂UCIT>LpQmtզ¤l F+|NBˆ!*(,wEͤ"Rm߲jCk_YRÈ[P<:ίz"6KTID16 DMFQmp<%4g sÈ!$Rln_̚CsaDQ9JМn*6uflth%M]af{/Gcalha؊0ڰbVl2 c+ƖiR|Xٔ*Ѭ6߻%u5a`D1=ISqyߌ+5K+Kph.Ps#PL cH C:ҍ|j0L? !@'2hqPVGi$* Qn^mHEY SE#u:!"_0D}MS0ĸKKaA #x?$FK7C\uĆ!el?<5FSPTdʤKk.pNgYh<(7х0˖u|)f2{X#G8;.&"_Ktcky7;g0{h1f>{:o~ {43)3Z۵CW<#戮Þ]// `.Ψ?L=Q/ȡO0zB:Hɐf W鴑H*1?zP >37^-`c1a(I1AP;ݭѧuE1 +1ހE|^!A<QEq޲\~լa9-8ƅe]Tμj[[[ֆ.\DN B#ߞϹd| hwۄ/btf.=nڭ~eϭ5dco-2wGO1!a X x`x "/)!![hT)ϰmz|pS>Huni{z%_zG+:< sP_UBes)}rKTߖ6<÷7ߑ>›F”P-Ȉ9ɷOݬG@押sڟIB$xsHUP>t5u8ףLy鞊e-3Wd-h R8I4/ ``G/*iJ1$&!Wr4G n]%~Q PƋ8J#O3@*GHN8:4tZ'׃:F>/C7Y Âc#Yc~Q ^;h F3zp8tI]c^jf !:ixj,5"N c8NƯB?x|!`ka(pY]Z H4-d8taf`0`G(ƤݾFw66?|ۍ <:0'/=4|ŸaPCEh*\noϮ?Z2AaЪ}v MpVOG4A>-` 5sz3:w:v`AWjj&ޘ4pfv xxvgK%wz'9^~\6iADh 4ݠ_mUInOOOX4PvAĖ 8p{j}ԛva2t1e~]f~‡Z#]nRw1;rz~>Zg)8`͆VN1ƕ>\b  x`=U4 _/E0aKWJĴ۴Aw٨Fܿ_6- Z<-w#p F1^0{q0n $7WS,O <(A >JAᤐ A6 ((1\o! o6x˛oi4< 2TyG-UU\ aނC@K: N|}¹2-:^5Y0bѸbO0N9$ 4Dz(2J2'P [_x~O&^5ln(S3ӳbr$[Sh"XcID$8BZrl\IX׮c[k8 Gq8K;'Py ]̩&9q >ok(CIy~Bʏv!EÚN[Vo{Lr\}@*Iʿ;X PAN:uVd 7jٹ5B8a)cKvCͿY}0r@Ŕ ?Ɯ&ŔD/s,^$ɜ"{i9COOb^chm1>%(cj1^?/fDET-B6Tzw3!P N8N@?!ޡ`qQ60b0RBݻÜZĎuj]P[W?U \CDV\Nw NU N(ȣH@ W'-+Hu$/.K\'I=OSw^$}d%lQ=&E~6vU‘!ZpqDj*I"E~p$[2)$(#_$ -SjY<m]"IH8EtՇ^<~#l's22#o 6Uyc@H.윀*eغRQTՐSm]Pu#=Y%DWd)EN֚+2Olz|N] f=n$lNa/qM7^vWlW@J='~$ؖ5f`Pd2.ela[,ltؖqa[ DJr_c=mO+r͛E˻Ry$Zd2%mbxl)Zi.h-S+ %/ r$ݸWUWذ-:"elΉH.8ؖxQQ~d~/SQkؖo̰ RrI_-+"`[&x]x ۰-W$m?X_`[X l\~mćmŃm[sF5`3mA8+lˏY=qJmqq?zz ]Ou`^D#&ء.׽nXTeZqeHEAUQ]U[`<|z_*-٬ Dƥ"7{"~J[||FZ+9|9^rN) ;!Z_Tq)ֽ^ $SbԦ[&<:$])p<}e&cod5Z {R1|}a,UfYX{Φ5[_SCP۔bv\Y2{zpGTN<"[WL^<3H L@==d#qQ5L`^$<A uիq rayFY.>ɘ@uDE]p9ђl`&e(Z\pi3/uwJk ib A;%B Bˋ*2_f(3_TޑGp*'d-u-By`pIK?8#`8V)<&ЪH K[D[Lޔ~o( NAlN?JЌM~X?æ!Pmd XeכjdNPNb+`'b x~մ?l9k t\>HLBhijgnz x~vFG7u.Tk|nE!5s'}Kn =,Rd ~^%H%3Z5tFX+]benI&5g! !<_r_ t HDMːRx*NYAMɫr/9rsTwGTUwRyt,8e!jxn@WNˉ[+]&P<O}nwr-:]E[ᴝHCv{,@2x&U+yP cc? 5^J(ON-ם%-cs>t[lfܴ7[+as" Z;tńf2=FFU$P FBHBtgs4&H 4r3rssyK}c5t.W ?G%Jd]gL/I}kYnXn1{w;5(ۉ 1#;+SZIR ܹ/_Rk(:\v /*6oH]8ʤw/lWjPӄȦȼ=# /A/m(k_%_ʧЅ/J&{ve54 ?)Y qFۿ| 6>"9RgfKx|"@2P(y/'! / L2̾GĥS:2 93Ԯ.Mȁ@V( R1 j(2ٟnFAFM)wU/4 hy张dXj0L_?i'tx|6(Zn'>vr_{el!DCE @:J>דC:<ѹ]gݰ{ %*:Uߊ4xPP6)a7"+91i>R;Zג{a|_@>:WOq`bAA TCb0"?ܣ1>z?m{S3Lpu>}f9@@ 20 5rTm)O+؆0HAcCx* #0nȟv&tL2U 4 dT Lo %n%|QW:[ڵ`ܨ}Y;zRM7V9 u{% e[Kɮc5j,ߎwv+E^Ŋ# O^nx0@8͘ISR4˖u fukoj8nj9p uW%w $c م2%FCe(:SpbDe2],@B2$IM,Ge ] Р\"fEB.L#2S)!ظj-pлE! y:f^/P*.(p cb/#Z~LY6g kEw*@_~[T6iizors% Yd&R]JG=OKV#PDЅ$6Fil?4jN 'ȃ'Sp<{6!`} iGB ZI3{h2{f/Zz^{":"93ȟp:,GFQYOc̢6%ӂK¸Ї^ʨb=o>subFUk<1n WBY\ a)JR3Rjh-$/Zc6|H}]Fc`̛a.cy#K}FYpA|?9/VfϚЫdk=<9qHu yvަF)_F e{).v}V߶Wfb83Z<+:Y찹ylg,㱘賵tg! JWG-LƜl˶'ŢT$[Hx4l%F-`*AEhrW1Xvf~%?Vv"ݠJzUO |Y(W;6?I >Npk 'MW;q$7׿#:mt']ٓ!!q' {M4Iwߖ.JveDFcƽ]I~'?pz16f^j_iZvbfi/㱳aܜm^ cr--#%gNWPC.H:q  -ʻ@@;F7sh5TxKF"V) q7S':AZp5A ޲隮y(O/D}AW쥼_ ifz9Ii[86el7v" خ-; <4ߌ槽SWjtW$_1>%9$D1:# 9)- kTph&pN8?])@Ʀ-ȿ?I&V)P]P_7,3+4?B(nM\ʜ2@d~U<쁇}H/God@F5_O4_vthef8=n㣽8ɵL;u;XvKGrjB609 T,s\ͯ1Ɔ])2~yrxʽK{ -S ! ۉ^ح qF4x+5毤/NN @\ 俐x jYÊG^D'X[q'p[8H xu YGDF>JxI`zYsxv'5(@:' w{lnADo0D5χBg0u/4~5=(@_.CTf0mLWZTSA/gmWۮCM6.%oUpWޠq:t*J>jH'TQ<1 $)凾E W~# ""Y@{c14JţJ KmtK0!K@ aJ\P#}?SoqgȇD|ɌH&jzDIwhI9. G|b<+"=#;Gˣq&K>;cy1Hm'JȕX޾+8 0&=SPqbL#̪. Cpj<5?~zECisz8u}mw:vf̼D~HYl oAd_3#wi#~Rg[^tAo^?`p}! '&i<@|  yS"ݞjYwY,. [[xt . Pa.ʰBRS|{3pR<Cu"{> qCO=N[NJa։K-3opM+G]5ń' TbD=\^~;6٣(|%yNEu+BQaXĚԏE37f[MچVAaH}ϔPQ_0qi#2]4ex7}*B/?_2Crз١Esʼٜm(Ç!Fm>OwrB{0 ,ۋɑp\Wq(/)KOJsgOrG\x!]j~o, QXި$m!ýjXty":4C t1WQv>q@?7Śh/wku a0ƀaU Дq+>ژ8>w 521Lb>}z/)9֯i:mC,j)g'ŇjĄ#&c@^mH U:mޔsA5y`@HDVe<du?N{iBn% . yKFE}iOSr%ыFJC7JJPJ̢L_%pI\OLT#Et=Sp>) \Cȑ ~w-`Q;Z m`tHf̌ 4B\UQ67, t%3]A8}6gӅyĹs{bKVDTbu f#(ab _+O)]zxr*Gcqr ņ f( Њ?HA[{̎Iިy>沯DA~*OY" E6u\QڛIG}xqU8ʊWN .Xqݑhcd8ڍؿ|XL1,!Unկm/ KP:9]γ"0OpLv%gCCBF^cgl`zS>23YkHb^Ykw|ˢ-Q0Hb0l~"8u\B@o7xOµނO fYQ.Yv~t;sGc顡١Vfoi*{¨̚sxXe͡2>`B*J\c,NHjj?m-߻C?:KD8mj,(/( *ȾՀw7~'@g ѺiP"y@gZ/*Lt/mam2Sl00u>܃DA˝Y2o rj`/EԺ($9 R^|Xׁ?21G56LsBR8h5I"Jh×T%`c긺04]e"8鶬@!9tK\hrb'&,@:4ϝYp4{+?\cD84/NSèԒRdcTh'xV, gq+ʭݻ+g7)(/Ǹ-m?DJӷkN${gmU[Ѯ ymr@om'GG72KR$+Q[(K`5z@Nz8_PL"G"x/(q;Re?`t t앾9! N%Z )V~LG ByϿ > `/Ν{z~"҃2&uP ȍ'ԽHw+V#`{=\S}n)-aǪʷ]K.`)Ȫp[UmWi+dȂSfyx OſxOGifQQxaKww 7fNZ}/7J늾]\0Kn^wm%*^ݟHⰸBޚT0(&<߁.ձhL;xo~k_:vWs,[<]dRDt˪uIqM_u.=wk:'N3 !?&̔B Z.v}fN*%v}Rs'NbOiu?:Imv|LL+卣~!@G?F>ߏ ^cHC\W]cf7\MŰqFALT&?~ Dmh@(`#[[)eff4v  7yZ:{hn׽Znǥpw.Et*"* u1(Z jC7gJH&4Zl!~dW}'ʌDzB2 LQ}%&|n[;C,m( p;W-7,d2;34T_>s/"ui#Ly fF4*̨U4zVk2N0jTfQse }!.WrѿEv[6yTW@ ܱx qjG^JvXҜ$ھ}&:(?PwJד•IP:ri%gimG2J<FSgd ac|̃p 2"!ߏ{+DxbV({QT|x8#m6¦ΗЏ]d kgze̫bsT] }g=侖 ҦGq_8<1\||Ri QpڙWË3.Wqp<)[F1j(i'9>泥Jn p}Ft4AGۖs|{Gl(lӶrefY9!y&C-TP~.Av DذHeo]m$? Z@2pCbmszb lʅP4^%1ł ,KO<\Y]<n.,SkAZ-*Dgf?o"rY7.5xؕ]E]E]E*rqt.6"@vo/ }gw5r'CQ^]^ڡ4w^ׁl̳R/kxhRLzI ٩es=XO%^\-EhBy.5 v &Cy\U%B݉5a:*%@p&@{64}z D'L=7GCGFT>{Qԝdhδ6]h<2dˮ޽(L?ZPQK?$\`15g("0k@>k%h28lBCkʅwPCrZ +A xg/Oo'izң7ӓ |Vӝ3.ggx|σ i`,R*05MrC~ $YB CaO_ٰDPP(QY_ Wu֖;2 4RVOT_.ڼ;G[ԼY#Q{rc[?B#`1ʓ(:R|%%؀ +YTqTG:WZ, &]Pm88l԰N/.EO2\iz`)*\cTBiЙ Yo6k;;Ms%S+6uT{[q66 3އ}Y'8$㕁NC |ñ1yJE`|8KG8?~y`VS>4$(ȳƌTQjx 0q4celzQ' Bˤ¨ʠ\"7j(5* IGtn6]q?ĥZ"P%[q(DECćA'Pˡ XW'y=ԛĢωIX6w<^շ]Y` 1!}Š7zMCHdws8:jsV!.=f"@5^ ɞ$o!ܟU 9J"dK x@XLf z i߉*(-?ZdYS=TK(ГAO2Fpf *69xn@pN<} y@K 6Jz*huD 2RsWz-yrPGI_n}&Pu frs'WTGlK?FA8@pqWgj^ڙ/bF8H(4N-d AgV%$m-dq\>pJM謿dӊy,"?.dz`lDOz}Qd}x8Ȗ.A|?8"oP\Q1+Qw8S8oV8s='rO DNn,X KE$"VfnL7i%b_uO]A[Y$cSo*/9jDos &)V8jPý~H)xz&f_FA8õHYBnK913j0PҺwCMv^ H)1o/e1mpX>X4izzP ǚ>p qb>Xb68N]2d8$8L1O'xj/%C䂣߮i3H^ߖnXU1h\! 7ٳ-}FGE.\h]V4z vX(|[uQ?feBcŅEid~\ɽIjO^?8O!pߙKTRƜDV믐~o|n(jGm?p$G=tSpT4Ip\zZ03HM.aco[8pF??91!=ɿ]5l\ËӺk=PRѿZɿq^_0~`=\kEal>M/8yOIϺʿBs}ȿgؾV,/9_ȿGW=[E (ު\H+P뗑(ʹ~bNl6mYbQf1ВϹY48yvܶ:)sD&Z nI 'd-$c 8Juڊǧȭv@GhGt!r6X=>:ѝẑ'N2ʥRTo6jYoRQcʌA!WAىӭVYRv uXX@ s ] |E=gB9H" $d$AH8#L $ApA%((!~+ *"" rxp$A92WpfO?]#];:@x7ъE/p@ȯ(|6O #q4,Srq=60Q~hUꭏonqiP,kFO*]f汹bv.'{m4Mvxd `( 橃D-h@YZϻ}HȎ4lëOv Dqܿ">[t][@aoLfڟ>E8Z3{OY_٥ҽ虼ٻB4{u6^{oυÛ~xOx!MJ~>ܲm"&C} "Ek}c75XKf{Ffw7f5ŬoNٷ7{K=A<}йʟ}X7Epu\u{u/N;.vb17lf2{'/}*XW ^%_}7ٍ­NX}}ْaPЦ" =Փ\ghA䉫|G11⿋u\uၢ:0Q7i_.3A$lH`̢n^+:ls\5R;PUT|qq8pR/ æu{^Yz۬fՓf-mB =dw>vO,*UCc=W~A^kj%#Ο^ZwZAA‚ qoԧ7 J՞Mש٫dun`fQA_T:5b؟|S1sV t4j^\H 6;IR,ndb,89nn3,$ @,NR+(>mGv;o/r dnj"'쪯^ʆž~TgVbD0\M㪡e 딿RGaalfd47/__nueꖿSck# Cbg=!ġ,rt1OE*}hWq<>ꕿ/u#{QQ*ö)_O[\7fn!*?Cu_!XLDƇtP%ߠ48<8:H%gHE~4muMf;lNc(7MQ&b]ۤMhI B:IN&8wMF;!DK<| дrW1(w=ݠS|j裂nn@`[uih}f%o~uh}滁_yIwom{&N%p}Ԣy| }{,üVdlavLMN.d'f!xo/~^8ZɜtK/mGH{csGеZ!*)9XOƼq5d$ֱR`++ s0ӝ~hU%n4k3ͫgl ]mAEKe+eBw֒UbJY8/{u 0N8֪dx Dž=̀kEAj?TI 2a? ]=:~p7=u[{ʎZ(5" fxZ9xI%G<5qN5AqY$SЕ90,ضDZcDB*կ(&S-Na43%՞*'0?+|8_Jh_BWq|TXr6^b􏔘jYkͳm|9vQDRҤu%W1uT*nf|+fVЕk,} 8͔N4VX'cN+hM?T@7 ɡ}`[+FIVu;>_TJd1Roԟtej5njԔR :JB O;  /zxġQê>Yn%:/\8+IQ0έP'oЇz21 Dh|j_ѷxzkP]*2"rlg[*1?⥖rxY#έ{Paݗ=6ݢ?AaGC"W͓/9H3# WfGVY5V,#D(߼*ͺ 2Y[^ `(i8-Vmu̔f3N1;3K(Ww iki%B:)CEW/=oqm+pY^E@.>tx?Rۙ8<XVW;#.I"sn4T@5\ ʹdeΨwH` փ@Kuu@(`c@e@ð }£uhBa#qn`eܰiO>k1|0gik1.98]$UVl .w4wlz,GtamW*!mlG'Ace:{6u~xOs8ke("O=\hڛyoŪLIѓh?<1OM >hF۽pڼ9Wo 6oc!6yʉ@m)& 4@D\K}ۼgy!5z!y âbKr5R*BZ C;>DtPƞt++HT=>Hr[~!T %H8D:j/_RxCi"$=HbIDJm5(V=@u}IFvǃ~'63o;|UOou'Plzx02,氎5#0 (LYU(; Hd4h)SALJ]Ǟ.1L<]j7:rG7,cDt'W.K.̘T93;YJb)_Z#r[7i6+۠1 UXWR%SPHRRXh]YiTR4sK~גgM'B5TzP~RwqZzV&_jA~\&O;] tIaͧc$gGf<ѮQ ^~zG셟ZKG&{3OpepwPs+/ a5ʸhnTkП7H\q[K$ 9V }ݢfYoKv$1ۮZ{K!< "utל[>+f{wSNA UWFv\nɱ#e܆zeY=k!&^+|e˽&>Ţ݌BP-{ kojYF  Gk/ۋShE%)Gg9>N7!7q+U.)>Ix$?\k"T^s#gR0S#7oD֒Z鶮%1 P7)) wՏf?uW9 %?erᴒM.zvMX5ۅJZ,f!z~1ضzZ5 }Fn Pwto2G]ʑ67kծ >Y/|S2o^RK,+ǛKh̹5K7Tw5pd)Al HR'` ^,= "NLI}P^.\0z v=db#kb]rѾ S֍7a=64<.dnk0V.fm)^C:)G)myf<'_DZ|^t됢 8hQ-UQM:|&q7Ɔ1&oLTKoQcLZC%[W~-!j8|H6T8:1?+ ح /ZRUu At;.A84qS<T jk/,R1RSa+yƛKC%l.Mxt] |:Q[)0Y {~ݺzx2$8̐ص98KLe0D1!KGށSCkd!HPʎ;Fr6dmLh\wjɤ!jd0_T8ѝW\Rw^@"T:*T0ԥ$#1q8S z=q)e-6>fcХS 7 I!4L4&[J^tÙfڦݲpg4aW4LB.8Laz?q|&ϝ.p1E_(%ž,~lWRpĂnG!-=]EE`MZip@sZN'5}iƈm /R`#>=hgU‹r$Ftb\&p&=Z}EJ*WB|MAy!j!*K_ @+1]|N|vpVMQEtYq!ol|^3ێ/[}i tQhS :$vMisaEɄ[G|vLGjKp$&T7HvSk2z+U-P\4o3!RH;%e i.`|ieJޅV(ElнLIBn/.q57g+{}ӻ/)yy0|QUk9]ߏn˛CoxùbRU?o0=qR.i>v.qE 0I,BCrH6۷U[]SvL<۠LTer~ޤMKNtAWR U­nF #Y(@^8*"Z ZoC :B@xDG-:‘'QU]0]䤘f1b5є6V3 'f;HBq2ZLJ<+9.qީPGkSKA?54z?neK86 E?Z }˽ $@}n^JAF?h!ɪ~ؽ2O>QDcJDlڄEw-69a96B$h bu@I?;7THE3JĬL6+ t_^ӱ\qՋn̑<7y:{0*IϢ+oó :Ņ?!/1<٤W;0u1BF5uz-8l"A1wmI;XMJ{<& q|TٱlpWf}"񧖫hqGQMچ sa2/)ߟzAi//QhQj9 ղ?߫#A]=`ҡj9A H|}=9zJibx59?a-T4߫`bˎm<jޓP-MjنP-퐣Zim%T CP-3 8C,%,kY,Vݠg;'zˍAޱR oCrJl_>Vp2(hY^0j .ːW_?=9rKnGF9h3zvz< &y|ӨUP@@dށ" ^@= !y.Jمi*IH0'$!MPyXYY?[5/,H+y?2 CfW]PNI =l: Jd jbEjCCgh2žs.Vn~\h5Ҫ8}M÷'yHh2,]tXtx-ŝٓ޷ݞ vRʐϰ9tJЋ;y5,J;]mU/MomxI>xHaߒP{5~ weBƽ,^n_B]jޝ gќ`*wr+iOcs|;} Sͫp:m-qWс&Nw ;OǠtldџKpR?3mj1j " PL7trS'*aEVd'vw 됅-=jGxJ)|mcBPs<2e#S_ІN})ǟCu8BFK'PV1mEMMM9`o}|U$P5:8+ľUcw;!G^}- [_:XX Wi5ͩ.ڙt:Ĵc.Uk5w#"M~pioHH zXFnҺ-g5[vVj_3~'˝zّ5>42~tT2MM襏V[Ͱ,rU.o},)IF/'1)Y6 qX4<{l[S:? oufI86r넲#Ȋ}BYcj`yAEű`D4 Z4vQ@W-1V>OUri>J)ƍ?nc'WoWgZ'9E#_ #$v٧KNPh'/n'RT-fTzT*/g+4bg;N>p/.?TAhʵSz:I8=# ۠-O?˃HQE>!2$6E`}3vb:l2i'tj7ÛpŦ^iz?bae1++Gvg S$ )#x I5,D&n!PK4uo#nHЌP- Q:jy: 0`fF(6Sydʮ #б>{oHA\7*bn/-'Q#e{Pxa 3]N JGEIT? xNJf\'4S WX%>4`w*qI^ITZI*x&Rgzyu7#KQX6h,IɫcȀZG.Y1( O" 8,32y<=<;F4P?TgtlP)ֈx̹T3iy bRulf "Ӑ1;—[*fl"c$WXF>p >>ty(uw[>_6| 0 fT+b06dc0[]9 lEaZR%iA:NH4Fq#mu1 hNP#!`+qAzᴳX/fZ-2i007Ж+/t[pQC,Ci>FgH0c "EvHS`ٳg?PbUO*h[,h*i#$vzg IiیV Ifq̂r6r9\6;l`R ߂~fcX slMʗa Q.RW(&a¿'ωjM[TEz16C/[W19NE:NlA#rsJ߉㚪~dԸ3Ve9^M:k,sD'8دgT^2|E 4p޽,{vf̍[X/Nn|"M&2WBeCV`|go34ݍ'$>#N痐 TyA]}tA{o􋺭Kxe,wTՓ9 {A qy#|aBsX#jW7+OmQѠؐaW@ufr9~ ;pﷇ\C~{%_tyхq lĝGe/bheWݰ#a{8ƍ2^Zq,E`v#1Z11dpIpN;{-(䢊?-BDP"E(xcx7 dt^菧N?"tQ"M&lv&d"Fd11;INΐf`aoͯ?R0\ O6Q>Ux֠BIȏq4wnA.-F? }b"5\!0OVYd<$?Rie2SYb.YԒ{)Ԓ;dvsldȓ<k$σmRilnd11t5 /V&0mA4KXUrO~+'4TCJvVN&Ȇr rޔ0;:ӻ`){m7rvӪ;{o&\Ơ3fUN&G?QMSP*#jU1\(RāһrEH6D_ "?cwF#`4J}nL"qLewٸXa8|lasn6P?WP[~oL!7R(i%z_3l?nX)yc/ =#x_|_Ez]yM< N4ưv`wmw6M޹ӆqz5x3Az8J "{1vn??%C um׵P΍{FELxq>oTɵ)WC? ?F-o-4(ސBOGx}<?d ׀G˥*y/[Si2S ̗RN]P PM`V 7Y1;EX-FŁ6 'h^86Ff{s {h A7_d_pkʵnӲ!j5͂-ra(g9ק\7zz/g,%곊Y&Y2 >?ߕ@î]9OW>4rWvƁk(Nro%%ov.3f`ffvb6i")Ea.69N9:Kcfo D?_HF:2n.Ěv1 b2&٘dsǬXi~ Z:31 x"OJ25a3J)3+,\去mF֖9܎²GuI SfHLe!'EHHi[$Navp phpN:5Yo' 0\y̋ʱrj$/9`W36?PoL~U3^x 1:%,,XaDh8JJsyC#x7U RwN|^9"%L)d$1I;+aB^i0B6̡l[p?O9<ډ9-e<Ii=;66:zBs_Me`\3{S yqFd A!(g* Ea]6[=x~N>8ŹbMH>?@+4ٻ?IWESP= []BE{4iZOD), EЇ<'Oy,>E,A{Knr,}.9?Zn{93̜x͖Ēz4m9y|5ڦ}*I}i"n+YU%%$π 0O/߱y˕OԸ\XJ\8^4ә=4_@ Q3U#zO#K=m2i'i(֪Μ@$iUuR'^H?`KDI @0?El9f3e+80fXq%/RQ.r'X+[-H|’\DhDD%+"XbH8ӶP 3Vw͹4M(m̸oRAL(4Xx@8x8#Y 7dR_yH]T3E*+^oBvH im jbdQx^"/GUD!Pտc{@O`Ho"ASU?6U4 i-9f**AdƢQEZؠ>s{߬Xp/g:1*뿗g_ ]oahkoq躶Gw`_Zv$!j-vN?OO_vQ:jC*,ܭF&j.Xm;.E⑹} WD*17MC} -;H{PZ@ԙLդݪYdUZi5F#'i7'Dڈ7p$kj,UWWUs\҈RU1< (-SӀU cHu+tjl*TKQY@L$EtxPľ@b5$~UVX虈 ,SLaA_[w&tL2( ")P 3ķaIa䟊:$hy0L%ӊe?V\gA"|ݿ"CG y<@$[^1ϒ<ΆFώwUnDy.>{}6 o+Ol:Ҥ֪6tCЪuUzd0(HKw1w+!瀘M8CgB.V3gq7ʵ }o ۯTyڏ2,  `tPx.W fYGSn@>2v:}0l6B(Y*藅{D)lwPELw=Et-_olȞf]~{>@nu55DWuΦtv ʦ!U,5+OtRGͳ"Oxb ߶jж3xajϵ.";ɶB$TBqah$j[ <;?Rd~ (-HbPxE-AI@G# {jJMtVkt62IaқL:]'^- OHh)wb %Ew/W,x @c Ǩ+ vT^.㹁μ=-]d/# DاQ{廕҉sc ͭ_nb|)N`>ăiᯉ{^Nj|eED'Do$lD86>QMH}fLO?<]Ѿf*LORh1.% [>N{YB"㦊#*")/"ER+((/@W.b&\"ڼ_X`ʄ!ey&0c[ln"\3Cvg:jQgVpqD2a!%yeRz TeN7 W=&O[AAl:ޙm Q6A^ڞ^+ՀTZjRjo2Ưyxy{ {MhaCk!#'"V1dT/ Y ^0a諯rί QP ->9TpH~ɗFM{-P0f9L>mJ]"/czsyPW.?}p֏ӟyYCۨ~H:oQ>{wh >߫DB-+$_@A A$+n.*YJsP{aU4=M7Flaqk^Tj_/YCB[uwzHZmT-;=ӖIQ97CSIKcsAD!{W,(~hџ h6Ą_puAgȄc -8MkE0h(ԁ#Sc|Z֧<] kB 5_twa͠#dqH| [^"$/jlq*d@aa;$ =NXie oҷ'!'9.>os ^ D#骫˹Npշ  ͨ!Vn. gq1h냉ll/q0\ %)ד /t܁&ҲeC 9h[Qq#4uP/FdBX{?a"7͸ صfZ=|䡪grkFJ,ΞFx]uNw8N6t%(b" =߮K뢘υ@&˖KԎ&J |ET%P}a9~}P{d.2zLg~,j\+eqYYfmY57ݞ'S_%!~uE4uY6y7(Wj=Ӆ_k$xw*3ǭ&r {mDXmw<}w%ߡ50znuҡ56FQ&cJ{ORoJw;!R|AJ m<҅c(nJ`GZtoX#Pv_A}JDy3;J 1'P"8y2%ϼe@DPf_Ԏ(K$(=7ޮy< HhXH| n4ĆMHp'3BW0N68Lj@"Jn DDvM!X%RB qj ąxl rmHۏ@I@B@b@bY Ds K %x!+KಡQGVئP%[&6$pItg.9g~%!0Үr j>|T 峅"pѝa{cZflAu'( 3[!P seX/dh@^wE@)Хnf֏dJI'PQ&\BT33W@?"PS ]pfGBRi%tg.7!4X(N`6K4pfZJsn@),M\K%퀊o@iQGS#aWBt?ڒ{,tLojħ=ֹs?ztJECKo.8A"Pڐ8SJdg@*Z#P%q^S PұJ$N)O~~Ft~"TT6 π6j.aEo, ь|]}Í =5~iHfOWMEk24험pYBBnbUUcDY 8![-;Mw"򦰏QnZ3b/9p0xB+$ l{ZiT?$ZN-ik@4 U.)@}ؖ%hΒy~a1{:'-l׶?)Xɾ j&o~.?2Z^k)iMjD7&U&Ѷ'5*$VPLՆz 4?8A\ˢ\y  NdYҘlp 7yX<¹½ڱC;vۇd)vkCZ8"iO2}zc3 lߏ'SBw%MTkL6emKR蒆.^-pQD:)hE"ZPx@Ry~7@dr >U*h395i6E7Md|g9ߙ{.CvL *22>:kF%5TL>+RS Jnqr`t)AٝdqtPa+hlxʭL|rO4 )Ʃ/cJ<^~wE%׌95(KvIG;-u%t"QP,vF*#tk8+j5(6M*t"O ž`4&[)cOn3aq]ZP )ʍPs SuE-߼i~WH7ϖn> šN}z ~o 6ϑķ~}ŁB+[wiEo/2e%,aHGDc&G>>z/>pYV́ʁ6nLU ˗řS5 =-T0G-Bm[g'ÅUh:|/a #nV# D:^1h)h,Pg(!Japzχ>8[˓`@pkȵD+!zxX %< ~6* ʫ|gШaUJl?ԓ PA V\1dXg Y>uU.={`CgKKb2\Z 4]m߇;e#o39/3nLPȥuD¦@P&*"""Ph"ײ_g?߹}Wl_nYe/ uW-nӞWgR֤di/e?_YmV_>ҁ!R׶5(B3q=wXfo8f޳6;Xp/3]uۺ_i_W.sOP{AN?8+7^{h{{M_$]Fs.aZXh%/-0z`z6VJ+M=Cv1p52~? "^ŧ0K(ŷ?L;7R vK8Y xMR%(hh&Ƙ-bәi E)1B-=Lp 6?[ucO#ys&s3mT V{~(A?rKBdp^jsp_?xRS#kM@&)iIDiy?xwI 7LF\ PV6UOM6cY6@3ͳ'D8 #EnEEeb"–I<^ą"a| MlM\ةą~N[ċAuᎩϙ1xOdz1@k~w}3X?Lڢnwʱ`Ua@1:u oTUt]8b֌A5wxǽڠ4,@ۼrGQ%Ŀ",UԂןp̍Gb&TFh툤ћDFE+rmrS%ON14e 7le&#a0]OC-=QzOд3M:hnv oh<~u"veqُJ`&'d%\p{=veɀR,['*4Z|i$"cb{jfRVP2ƯDxNVdxUT +K.]$nt{HlX0:~D%Ȼ.nHtA\w vT[׏-ӂu~3.;Wz)W ٙU%+V$^)+GvNw)&| BwP{^b;.;ò˹^9/bMLƞJ5HCiO " SFZXjX1mhQ*+Qs$xsSʽ^|q57׸*P4fY;N-r, 3%TѨ[ܻ 8Ϊ!9[OƝ}~83>mڴ=^Ƙwl E@biZZ [c_Du$M28n6zi֛a4lfL̵4L~_zCCDIʌ;5Â)Uµlkؾ''QWuKᖟ]3@L8Thz&ڪ[E0@G ^!e#~ץIF%V=Ԡ;=+i{v;oH~xmLa tZ_ќKOORE*˾lzZr}RANe;AP-kNv@&8 (qWsV(Xh B YDU5ua[{vmM#5o mL̈m-w Fx5ݿb[dlk~#Ķ/1~lk3E!b m`˛m5bd~lkPosd+E ¶6mKS!F8_B^,K(mǶz[lku@5|Vb[MlA͏ŃD%˶vElA!F^zn+%պƯ;;_.geǟADb^غF  3HxT [1b$Ql"&nx/}!n ݕsk{uMf\i"qpυtWQ}\gyߗcl[ފmmm'c^-/0Dܿv{m n!bj5@meBtbo?_5F`[  q"C˶[w 6 ζ &0|QDͤA~qAGlQ:bN`As_`hLF&򣢦]÷|?F蒴2I/h _8IgsD%i*ٳj:Gxܨ+߼{yFVyHps߂uW㵼\0QD@!81')8?-Y.Zy VCN&u]#c`Hj1a3坽oBǟ{W]iXnI!iqʮ# 6wK63&XHB-_ocucDaaEB`| 'wZ buG Geؚ,pEHR#Jp_5/Ҵ}G/&'Բ:4]Q!.5kgT8ke?C\'S-ծY~_9b?Уs!DB|љG辎ۏ;v;"XESAb `/#X=`!Hz=Ϩ75,,S; ܃2=<ѣA9lDƩ#=AI%'^qf~XŽTcQ#a@]O?b Nm><E ,jm=3 A s nDF1Үrx3`qedrA (Q*T:$BHeBw=1_2};W0~p,o;[]Kr6@n5;{_z09Oz~ݎ-E}mB++sm[rcCk/N}stk֬z+@ŝ&k4OzS30că/Mu *9u J$&͹:W`B>B!~3a(0:>C[]3wN {fUkye'm",t"õѓ͊u5˟[Bu" ~N6ŗZ=>EtV#c2lf5vhmq:,i-.6.nήpN: jy=H{FgKPtVb.AF3z@ %.4ro5|NSӪ>0/6$WK\1[v ݈=b E|./V Wm;1Dt}Lvv߂.7'z]6rv_](Xg<\aAw`wf58sd1#KMGn]eV4$r9Vj[-,Ś,#m.3e-$p?QEPK{ $*?!G4c'|wlI"ZB ~hjQztvHmHD\#hPՑ*5["_SkS8KwX߇FD \$_@s Xpwf%bHm~[!5/7 ! ޮ*8$[*gL?%\=>N,Jk܁҆ t%4)8XoXiu6eUMgۼ_'Eb6'$}&MQWl$<FlA? )Ot7YogݯV)46acOr1ϖ aא{Di8B2;39$d:"C|ӘL{%Kͳoq[*TO1 I;ۻŐwaw,C/C0ێ }X"]΀ ƯO}x]2+rY#BooqO(yPyU9`+Hc xxa%axi@6+O(m/v/zut)GQd4@}pP3,F֟\Qdr}bΟDZJL0~+-[]9x3jL+=!\ ^ K~[:.Ҕ8YlFpb#e i6d?0\O9ԇS69u {NDB=#+8l$+B&`N%y#~VnXaW`BOi AcͧgM οV&lXtWSOtɫ@uq֠.A҅U/ @m0$)*6eq1żJ)lݒ!6FbA!&+ iz+5[QZNK?KO~j7N* vYx7/Q$ovl,l̜jgkulf&Y\WTZY'gUzf9HH;!f .w&n8==K_rPH8rgu~ehކ=Dɥmِϖ^㕩~hfHPZm$5*(R$_rP\Wv&~8BOݤEp6[O/m/",0FFќeI3ca B6m\BS[H^#g򿟙?3Rw3^x߃((o|8 [i\`wV+ lMA88=Fs%/+G?N4R񦙊 "o쿥Kl3>\vؙsҦ3P9Utl>}*Q=[)w)ɸ,mtڝm2(':m &vl 7Zn!AƸ~]\2>|4T]͆|%Q @LoUuwMLct}?twU,lXmAG!O=_w@0N$-P o aӼ^WĖR/gAB"2B`uS(Jѫs6G{jXǃ6^~kƜ1v%HYBڑUN=W2e9U4Ger:^ WjHCɲfxXˣ{ +PdqV ~*[ 3+gGhRIjx)E}D'q9A~@~/h7<3\U~BBCK!B~rVۥE1{ rd0N`Y&ccd˶ jNv0z]gH3O D!k ΂1}*/r؍LP +jBݰfdd)QN:WrpD&P|MSTޕ*X=𯳺Y$ ֣6j&HWn we[ơsY+l`>EVvO6'[K82o&2+-/;(u7-tuXNӷk<x_ p}7ŔRZ#]pSwlٙ{P,_7$1@ uJ7vk*[E[Cdv6ЋE.nJSﳏ(*o҆*Ѷ/ŲW⾏&gęq?~0ג&>E"a>dU8Km߬u\77( *8E]H .l,B$0픻U^yx >G 5|<8Rh]R!a6 ѰH㏻cUk(1Z+]̾ xQP]Q*`3LEd_O͸~s2w #'A@ hmPFKx^zw_K3lUo{i_Q|y"̊lw[ʞ[rCϘ ó vFyodin-f@l2N3ȶ.]omo? -@{ vTߜX91/eH}Cfr&*7+5\@h>L<j5 d҄`(;oABvBIʅE^6QQƂ BiL񔎫da/#gw*T O/a>l:~MWCT >tT%"Sjvs73؜tB}SKMU}$մ==o:R۞ hHQH,0<qU8.Z^:;;CP$WU9ؙU櫹\y<"qU?NYۏ'01axc{4 6U^DL "9:$_MW%K?gFΜGG])V䄨w1 ID mk>|hth;E9µG]kʶQW6Ut1Rj ޖI`BK 7"i8w$)G "u)_HB,޽[4c+A.h(Ik vGߟ Dž=},ֱ/!(}㦍kg2غ>>;ȍ(STc@SKt{ u I}ʱcZs@ ws>#dڜ|cr;^=TccScQ\sjcQԶ;>FqcX-)w|aesE 'b܄tI *$pA,o֦4*ǢB}mդ'C=G.'x24`܎eftV:6Dr936&r{U6&f,l23 {džs9syq/{8oA9}'˳s#_o}8l !G0H1#)N Cr_|O8{(H{UFlC O.GmcʱUWo|³u6Q]Gsy{ؠ3vS/GkSiд7>5T#F|A~_ u11-CaF°7'<%#iwm@s]48L+u vpjC9/@5" ^;ܲ1!?VpH7$<_H~U+`F>/6Ox^h5PF ~T˃N^0`΀f7+8 NB1|J;z?zL6lfm84cͦ:n6ulC:s@-O2ߢ'Gȹ#g9-[\D o(%8;* V\i᳿]TYZP7!':zzG #K~BRIpJYAIB( XQ[* Z|OdsCQ0DJ e!;e;e8S820BV ݂VW ++acJw=V2gM Gڄ Gy7llc|X]N(,bnڔqq4q3N 3L|/B\^p^RP)IsDX6zq~-tdSD1 <& }ي㷕P f <_as(9>G(e24>8Ķ J A(s5k2j2XɶbrW/&%N{|jm)*{ɫB -f ݀ T FjtjP_a/FfЎŰ;r_i nu\dB{ WbΟ&@pٹirKgdW[B`tW"x~\"3#)UW bI8Cݩ3B L$%HKdt+SyVU_4۩$B ?N$0'_1Aߡ %c[M~oLd(ٶ˃x/ QwN @6!vT{KQ'key =Dbۥ:ѮASnkOP#+ڠKlE`$bĢoF%u Ȭ+OiitF gF ^ZgC O-YRH&Ƭ:tZ[1'm_'d$U"SIic+o 0VSfi ~mi|N]՗?HU 7ȼa6*3}PܵŴE].xGsj.(Ov8%;(?O7oͼ J՛|;j6{s*$$떺YjI+™)PS]rωW!͠ %q"?.>/i-Q'4<8݌,DzX//Fmq?)NA$_0V`?7(3r=.VvEc@o9N%8 4g$+7#1dD$"1?#B6B$zVk0h?F*sQ#E]ql-1Z"RnUkI,"V9+z0yW۟e#[jbFzɅl\FezM  JW~_${ZLLt4҈{s̃,4Z0Eſ$r!`?X-WRS7_i&q00M9{'*c|Y?}q@iXq1Qh"s G ԰V t=p!o7ϔ #$!c`}}{|5wi#*+tW4YfT8eZtqx6ɪJKsJKzbWU%.ʨŵUUlaKKWU )'2Ph0] 7FoX]΁zqaAR)>W˞9 4\YK$m$ͰVF.LR3egIf-E3_B_%J)C}t#V:N#ʗ.ufa,~5Je%un׽_tt/Տnf݊G+}݃YvήF]F@0ݩq@߀_;/ə7j/a#=7 @{$uC4 #\d=]az)#@8'!F^N9?2-{0*d$X <;h HĵQ(eaG܊>_ }mp VO8bdX/y7C#lYu3"VŽWꚥ:Ӕg[@W-iU8$vU$ Kqn*x #$r"qrŋџĩ^"UNƜT8/!%NV m&&bh Z͑!񕤷:+ys.x[ݐ1}V rGțތ)ЃHBaѤ.{/pFƒ1W0# #g㚈|)3@?lĻ-}ϵڣ7 7NCKu7Fݔr"VD7k\3tktʾxUs!p?,47C VRnbw8N`X3%ji1ۅWdug,6M7ٖED$ȖC !>7o"x(9((]nT@Qbl" aޕ'~ qHdc`@XEmI|P&.c%^4X16V>h@Qo~$&"=? ~Dg*G4DCCwMd '&,cu5I&z)-:snV&:rO*xܥal""7k [s.Ptg6֒U %l"MPl:v56.-2 r6QGUlB+N,_rק_M>sEݙ}螯 lbsxHvhAa{C>~7#nt"2M~sNnllΨ[FJE=pYQWE&G5 x@K󭬧oNS(VY7٪:bUa7Zn-ZhNiڂj%$9MmI mNw ?_U?C_`39q*tAE}&p*q_0] p*G#E7?ƉnlBr7ɗו%Yuw:FhS)`w;cwqR67G:+"erj3P=S~R 4yUp3vpR 4rfmVXhi0~?iAͭ2ɔ٠fE<)CfuEd"Re:RR'dF)^GDȫ0-ui\? "ۃ]̎..+*'%mEB ![#Jn$%uᓒ y.[1/|aNbs}Iyp%nAF-%xlObI }p kZAXsikZ_5==0INWq-%o{&[Yo 0__(hMgO(qA!@Vn5S={`I@ȿז?*sKX_4.]8 S i}4p) F>_$ ?4[k&˄JhC:i91!Ĕ J'n "^\ _} ׷\\ "36on~Gm mO/jAB/-;|a hD\"_;U& n$%N}~̀#V5A)pmϒOx, :#'@%w ^* ?T ^y.8BPn4IdB#i#' m+vRB#id W}d5P~p*\&Y"5?k(x^?  ,_V?&ֿhoQ^,hJ SצVz%-o&:uXD=%۶#1119y` X^%I<3 @bR.zƀFLS,p ZQ @xT5s;2Mo5Y{&t*4Y-dPjOdI=h,W<>Ґ4jg:8{t1n! 9xnY͐e9,-wm#4GL_cЯY66弌V/2Sq,jőWԶ6 צPPY_"!B $吡@A 3(A`ׁ@Kv0ŐJ 2|=ރ@S<H+Q/Kr`(p\;*ҫ[c:a`o eܺo_n9m* V|؎:/7mmKUt ͝C>ާ37o>[(y)W;[3<67|`\oC͝3;+{l֦殹Ju39{pfwĜy Ovr3?}Fc3~Ŀ5KN38oF~>w?Pn2ꎙ?.8_̛b{ be}WǠaAwaBqOP_]m8AHAI74$#b߾ܥ/QW G]~σ9dwK6^ ,k>ДA0z bQ5Vk"p~pRl+Nt/'nvԳ"K'U ';?vr f̪grǤqi{onĵb>ءfؗbHĺ"#!ka6eؾb:KR9V`z~ҔϧϟS>2<+1eK$)O>F<3NkY`*Kid/->]SO_=> kKDVv} m0HO[fo:=6U Β#ns]$/7o/r3iJh)QN]w;${=/{㴡u~׆t{~3*$g"?U\P,L,w[DbN)|&kX*{N/_T6>ąEBgB\*M͌dĔ0SL\߼eMo&]bBA?k 3@MI.̐$G ARfgX5Zc̖=HjT@#P tLi_{枕@Kyb>|IeUs>83-/Pi>{ɒӢ WHuyP ":Q#.?=5Ru&(* L9y-V Un C-_cTxe`ډKs-yfci`3of9vtmm6_'cjR -M5 ՀN*cG(2ՒAIf(F<HQ!0;']^e2hutV/(&8B*5 7b EtyEfo))*(m&P_7B8Ml8*g!s9<"*eec^^}rWN~R{jķAXRĭU_3FxSQǤP5JC|7цDpsVc9Q ˿!6;:7백.vӡ^OӔiWvۅ i_5{4GUc:d"Zg/IM_ik/L=By`D)/4Ojʕ!\@hOV nr h,D^R~Vrpa ͥJ>oYeٍJ:5n56KygHz4wREi%,C`,1km"+ Lrj88k.d\w svhBcS5ä Rw%Qf2' ,! =s\d9 A0LL<quq Sx,x *?DtDT$HBUUW\=! ɊHtW_wXS! ,&~ƧvȌX_~yņ+$94 ~U[m3O$v> Fn U̢U<1G`3Q4hmZ?*tf&Sm 8/ڶVI5< ([dxw #?f+HS,`Yh![V1^M>G\o:^3{랓k~(.+,@J7OEس;V\|(!v&4k1C f?Nxcލ,wxE{?{Cы7? ~x7+䨃]QG>ufĿ tRQ]~Zvۿ@:w~9\y' ~'9e!u6Yp]ȵ?G?s^รԹD-8j$HKý61iJv*g$=U:u~IsX4@0Gp$:`"?]/92.12apK\@`߂+nt8_R0)8M'M7|4ɝ=ȹ ;ez캶^DSO4 й 4= #/M[.e}_uk4rSxќoINigד)9@LXt];o9TLbwPNÕp NfiTlfv$MEKG,|Fv4i%%"Ƀr}R(Uw*=}ޏ7GP.;)1l4]i. 88'b9`9Np@Y)d VGur%6w$ց@r=u>8ԩ>Oy+EkoE y|W/}+O~~~s5(̧%mw 9[B R_1)qj#^D;~(EMXΉVĹLrC'>@;ւ lpTB?dmq*ְ hbkb,rde4П DwJȾC;X`LNeq&V09=gY dzKu1]BtS,ҩ"9|{$耆LJQ8r?Qh8JeV$~ҷ"P[lTb:nr ~a3.&41@fyC(ےd+n5ğqgrev(Y*Kې3.w=f5 pkN1~USS3z2J PL)YfQWEQcmiŻ'elUPsP)F%8 J?'RPۜ&˩78Am9NlX^0ڍS%t *ɕxpp \5-`=s.Nl>$AZM@"yi`?"=uUA{ "N-cG{<<F5?yxO3'x'~ `&u/4.\4bhGF$fⶁCjDkJkPEܑߋ:T3gY,H#S:Ԑu,c:7wJաp#( pcdq>ś]yc&Z/Up٭$e_uQ*}S]K%7Qos&bv80N s,1{͘Cj;MDhN>V$uZE)H#B8@rVKΝsȝHEĸ}x e(1iS-2SzȚ>x\{Wz>U_S2c%?c֤8h02f3&Y=k7y3ktXA0Y|S j )w Qyo;@]C rY5d!5jC- gq(ݱ]T4B*ZSS@AsVҹT 3Yhrk3,1DvrFi| PJs +ykEJ j/$_U4=I!2lGB+ޣ2z]y%8B`؋>scg%LTn0*'^~𤾹Ɵu +i C"T[m:>#ΔN[S}>"Ɣ^;{Dsp;rk|*b9~CY\~̉ "lMAm&oY=&%ʓJc6TQװ(Bdb?9yslho.JY}ԶoC)gVp6϶Gҟԇ.K̭A";W4NV>쑕6CGn{MO/>\ExoYf;#8^89wXgg!h|KJ`EJ1ۯyu!`IL+]J9`Iہ,)X+,M4-aʰj/,*,[,!,i,[,ۏpSXT}qugLϗ’&òIY%C?ÒF ˶^%MAl ,[e[e3( %WCrgBÒ#%-xIes%}CށxaC!J!a-[w`g%yJaܐ02,)!X҉[]0rz#XRM/ÒbX@ ky6-%FD:6pKUAaIs{ KZ8残̆뽰Aշ oy(;"=5B_K j)4>(,i̿vЁ6P KZ7XRSw*珛K`JRhDaA %33c'P~%*3$oÁXJ T/`I}ao]W}}yf=%#,q}c6UxќK*_`I?ȏ0,W(PXROKd ۻPK/-X}8X0$n eswm߰772~'?)6L7?V_ڬ7QmrkK~#R!bǟKFRQK{S%%R'oQbtf3&3c4Y ?!%U4{ǀ`"OS4Fqu^S鳣ȹ~)-% R=_Fd['8Mt@b帝Rǂ @TpW]R43zrQ :P`;hN\悓gķi0hBr/\$_zIp3-ޮ#soሮ`抭V ?ӯamJ]*[;[K Yrz/j&+ iK+ey(N޷ /2{$ 7(lW%Näz 8E/A˨„Mor_ף58MeJC;jkYެVdC*JHʣ'eP¬4&dR'TYQ"IQÍi f\fc9zl?[z{u ALK?Y&%A2Ihť;T 9SةnZQiw7 J84y1Lj(9T|E\Jh8+}]N1 C>ͯz7Ne:=l讫㥶jUgREfyFxw D},LٲBjqI?{WEJ™D!gC~ AW B$ p.<.E@E~ªȊ ,Jcz{Q|CJI: JK| JُQF] E-*5\j;>:y/PD2MRTjơwFMs7\d:1gj{TlA"t.tO=.:լ :5`l [?E"u%GM8 8ʉb;\PP6d]̥+h6(죱De³U߲o|8TKI/D#iFЩLu8ԬI^ >̆G#U+] 3aos*͹f0I^ $5I+u5zC e k  W;p05@STc$wPi@KQz0A _ՙw>BW_}:DDۓhY )0L[w 6P}e=_gL'+wz;a"~1Ųz?c)Lz% iuV^"jHc/z ׫n-K_;!C,"Z \pVײ(Xcm= UHv&7%BE=Dw'OL`#|"$Lz:K7&=w3 z|Vi CnÁ*O@ C"7f0,z8lJo,NbvMN6q8.94iuI+{D,& [oۈF,1F 0'G~ { {h&հ34ixţ]⇥ftoQ4doTK>{,ތA7FVp&vNgVryP /3otKL,IDTb"bv2/͉v2PҔ8mzSW6^,G' آܲF/S|V [hnz^hw/;Bmz 7cLHw HwlYx;TMoAp 7F_xF`_o5<3\粒"5\'jzhL a!ʊ8\ B:&j㫁zϗ蝽yvq#d$5[;Ӽb\I)+ \㉑ -TLa\#Fw,rfZHe5vx`SZovNa2#&"MҖHѨ|$b~;^ڎ_ߎ' lp=kE =07 ѢxŞVxWS7^Ll 7=OWĄn_6gɏߪ ueo䠀x =g7~߯Gxh;ޏ7'c:kΕCsѬׂp %q9&aΒhOBF<)z'39AŻ|8r;2{[PH/ AO!^{0dqm͢vadЂ@nb8T:nb G9+R R`ȿEq)|4g+MtxX v'n)ـ`m>vU*鹾~`w8Y|_8SUpG yBrV/[TIŃzx'ֱC#XV]mrGz;'G]w}X9þ 4'gB3z̝xK/rɵ!D>4"1NWt(8;m$zdMiy.( 9[ ?Fz(Ӽ_^"D4.%DWA۠KVkKvS΋S,GCp+ffpԂvX0 FRz_+/i tI-\na].[oFnwQB=il?] p yzCb,wcw'>F(wAƐ .Eq3QT:g[D ^?>TuQ3L5n7BJ1 3wD 6mC?ำKlP,(ڜw^[w=U_K.6%t߻_ MPV+"EN&V04LN`QNlFL !=Sm"a`,_5WHQ&ӀThNublˈZVhQBX(IW6X\;vw39VM̞L@p'V$\#{,+Ft'YDطцƩ0ABLZ<6P] xUKIba;d됭zO$*BA,Uu;Nc 0&GaVE#,xcu NDAȰpY޽ݕݬKtusιsFn(o%t)Q [u~2VMbW.AtKYT#ʒg>P eis) 9{&3iHւ 6Hh-$-I\ffO{Dm޷dk?5|t%ca=쭟E?eL81'*@<΢ݞH+$bnvTCt 9"nb R"-~=aQA8.W<*LExjXfL,2GJSwxSx#Vqez{[ؒ?vfcۏAT?֡c7w|e˖6;J$_k] XXk#ehRMby2$Eo :$񟚾xJ 0h~y+>[;FoS%yҚF.E))ڦ  OH~Qz13AXoF'v6qT3Үd}![A.OYk#WK3bXB9yY9{7F&ĉ5uʬ_Y^g#M#7u eS?Oa{m͐I((3C  ilܭ^tOWdMiyyмԽ8g1%o( әYҗ8b{cpheĝ~ƃX sA<~/L8j␯5}cMiI&J4ۇGoQoM'4UmR,`XlD7Z ,Qu>HkdN[pg;"k! ڌIg dIEofVmn!I_&l)FjATA@ XsKY3Y-2H qYJBb;GNpWnW"Bl#J; q-H#p񵰔^uO ]Ȣ,E2څ1-B@| KEaGCʼKtM?J>+}O,Saw?̛ @Dh?qzψVOen5rN)V'+˹d^:U(W?OmSwb\66˙c3Uu}˰Iҍ)$QǽXq4rvg9겟^ .cTzj ޟԴ B~K+W$@h/_=XlG 0 Yg6wӶ+vAפ꘲Zv[t] t[s`F 3mE[L+^|MWt97!Æ +QJFkKOm?=S£O)$`|~3| 'tqSIU^e17ZӲϸּ@/?{"9>%ψ)UƟHw <e2? ֺ4n 1͟˿ p~A4?-߹_MrRHH8=oӣYB`&mM 3h1$!A|&hg ӹ k s|˓KkOfuQ:Kz`0Rf顁8 sQw'?l^0}f5|?Se15'a7Svv_bV-yqy {=|K`VPYϮR K3Bd"DFjpCqf-bۍ 2_,iCΗUքB[BY?asd\Uct5"Ⱥ+7Bo*ȌQtݱ%mjgu9CŴ*rw lj-Հ2 ˪~{HСe@Khxc@X  2E{ǽMndch~%J;OV$%EE^^ PW+SJ41d#w]M\r٢SGVb޲#GIlbrŸxӆۦ>Ӱ%S.[ea%AN5/, yvLtf{٩{M,zyvgXׂ>?yFHV|w_{ p:z<NwjU,ͫ_[HXlߤgr:=3٠y&Ҥ&f if{f4c2t I?*Jd/ʇL-83Z d+ѵ k_s]^ D@L"lWb 2]_E{!2 IJ~_;?D VӫlFػf+|KpAM#@q^q><p֣P:P F> Nd1ĪBOȝ W[w]'Wo w1Ysp!䝈Qǿxd}R!F ێvKS0ٹ{éPC32 ir& mykdu CYtfVݭOH=B(x###:Jt/v(̀k/]PqCܤ;U?h Fʐ Ҟ}̤~Hfؕقo\;!aTO ֋W/?RW{TB}Poɸo}WƉvu֋C# =' |F)RGnNnS#g)hY=Ͱz,f)M:6SzQh7IU+f;@%>P??/79#M;r#}Q2wP{S٠H9@.2a=tN,Iyei:>y zaߔB߼~GWƝ|͑^LύX;(~j0U t:|&;]eG_ dLvv̚c:[X1FVFO@_*Okj]l̄S|A=3 Cta;pW~'W~" ov2I^E/^B>_8 |%SOEϙo 'h!˾؃4h{Sd_,pd?r~9|zq$ <ɰ#i06= W1zfͿK7=?B7Cw[zh|ὝLhŌ p"f7pN`w %TރI%m2+`"LըT*qH*2Z#m&d9˗DZjV47+*@' Ò%Y nK^wh$pY>Z! ab( iC #"Yb:{FA\,hr8:U4e@5ؗKdWA8o"0 bUW(آ JP듗wxKWoI%I)v yݒkbVM:҃'&9AY4|Ū* -IY7IBv6쿄nw%MUMҍ4=]Ķ' P:ܤ ile")T>q~>E U=x2Q ,s$MZyJohNr9|BEh}'lÌ` ̫ -D*`&6gbM}hg ]%2OFeSS?e<\ s=jn܂KdqS:>huVQi!qhF% jNj0:#6*Q/mtbԐ:p VDc6WBĽ?M5 a? ec.eIU,RS$)|92Y)Դv3{; -HC/,#5qJr8ݯiu? շ eei;p+iDeߑ.2x<<ͷֽįaΈ&ZZ~r m]|#VR Ag$UD,2?QR dD-n?"Ρ?$d߅3ZF@4ڞqyBdo.71[&M$.E TĎ?'jN$T-V7ҴeZJMuSh=}!k_xNqzs-),oaCb60x>E'@N%SIP!P ?A-?RIEݽj~c"ծ@Mkyb݄ʠQʁEŐ_1FbTҎP1kK%)hk~*tCCuˆ,^<;6|O;ݠ%r./L@pc(5Vrj)Yo oy-NT%pZ<-n⁉F3M:ShzWX]05|)wn !t$eߞeջCv/kN8e@)iYF#-^G%}Sb6Ӂ]>HѼǢ.PsZ|la#|^M:5vij)f×;uf4uß9I N `d?`HsjwV'5ԡpM@vPzzPִ,*]4nC=ԭĤs]N]pGܰ خMy$sM=H!Jk8=Bu\?AZ?\@XQGﮰ83]C0'͜=G?smTamx.qkZvt.03ߓߖw )$K[֍H@&稛h+wn[H!=ìd?m:{V3'BIX]'MLa,a˝U&2vp#{ȪE'3{#bÓX'6(p`@~G0E`D}B$T;~w\y0<=gxtEǗgqݺfz:9G[ҝdNs8)$9U(V/F?影seiAƳ_ ]7eZͨ$DZ M C3HfY\6*A-a8 =?T3-O>|*IK=s|g.@3I.-S>8Yu ^NY"G;2@ȶRl\GpDe-1h|9e4rF0v$*ëDv6L@)22(b iZofu$iV^_=/DFUTH~Υa_.ir9]0tT)Dz "EikAӝ:!Oznnb\\>e%hrSӯ|9ycqŻ ;B;r]%Ɂ_{)IK͎οVY; 'y)ܩR t#}-1."ͪ9/~}g%3HԘz=ZY5F*C *sLU''ミx$rjbYy}^YÄ&hϐK"<<^xbX/~W}X㚳n1)įV}ָx6&A_B 3U3s=;&Rscy>߱hý`z*a^N~v4w 욈57sd$2BCzٙPx.{4kƝAQk'>CO>߉C,VVmQ!n6uF5CeT[2j+e& Rk4/o/$5 A"2a ["9 ࠄ z֋ FEp snX,!-] TbO zW1a \Əfyz7xVpe$n2D6KZTPq3СQhWZ c'myzCIJ}ǖвYi%&.=Gch`#ˮgAX$$܃VaiQ|ʺCJkzi i523Uj5Hu:Ke1hl5vWJmQjp!Z"\NҏKqy#z ɝܹ}= JeP@Lg= (WpQ|#M.@w?+B~fˇWF7ȥt6t)z8{dHIt9iv`tMS,'î~"~eX`Xdhc,x̃J?#rN1zjjl)0dК/:I}\plvlۮqDn{Pt:q~@8p|S41e~7ޮ'#;7l~%a^74)4}Io#pG>7_,-^*7c7h~Lz QGXޖV=kdEv]5$rtGSjcՆ;lU:L#|0qϛo#>T*蚛v|L /NO4ɟ$<&,!Eyü̩2%]gFG8~lK$պGqW}ChNH2ϓc.1W͚5k/2J|_D=ݲO?@b$BҏF$O醝ž,*V`DIc2lT/z.s@"]U=&q' ghwvQk[ |/S4@ws qGX]^g P3.x? 9AU{AQY%7uC>!CǣoKw@WJuhM籚Famk,"ͻ z v [V< 8=:.6[^:nYf6HBW<=U]Br3P2$B-gLmAW ::fWeuYbB!V㕐9gtA6  9]異ᎎqb|_ڑ1ᶛ $d6xo\枏B^ r6rƥ13.qI12_gv5R'xz.B%v:~xyjwwh@ &gf:<}cxydHh?@ϐO1hYIq;«2Q*:rM&S3`cUyGU2M*nZ/Iϸ{g6p+^IY^:Iϡ'g] p_߃4ڲ:yBBhhu$skR-k26|'7Κ2ݥo!mZ c{Q+L1#Lr$+ ?$CxpÙ1WsRͲi4 '/dڠu} ;3H٩ 俠A1D$e!)FcMY ˬwt* ?E qݢ "B&:keG12ekM옼T¤#;h"{GCP^G'@<=5~*Xr:CiD{HKHy$qKU9QLIUMp`"RD"a<@gt PШx XCigi;pvP?iG4E chsoRڡwox{:.uMh_iB%BRUu4HY{޹s7 \摷n4/d $UB*a"o"DzaF4C񺤳if%ڱ 俏8JJG#[!}Vɬ ֜z@ s/N-]\Va|.LvwC@ߦ!U%MDS̰ff a4CUҶ2L7wпG-To?XԸ4XȂ7K`-JY侃jF=IZ%"2ܟ䑺 aSY5̆âaJa30c )lZG8]#OXOtp["0oq) O? Kk!"IVlXȈEC?ʩ;ԶD7;Ba&ąE`QQ^@5ld0a^k1ol%Ў?sM^krr.w<ѐR {+}f kXPT ~E.z$-x%:u胊vuq֛oΙӅ d&+쭤%V5s`q3)kҪ근 ˣ(|=h!МfQ /‚,xK4=4x h ^[ KPb:3MW@Bϳ !!A$I #S@0mat 3!SJ`W=3 蒅=lOn#\S>';X #Zmu;N=O`&fX?H!#c{8oRؽ9NxO@3G›p s7j.qIazoxvR-3 Pn{巾 {;Ъ&0\tZp=/{p]i紮 wpގoztsD9XL|$P?{8ֺC5Y=@E")ϩ 7T?TώSSf{C;H1+&@uƪ솮_-bHVXYUÚ, 'b..EM=x_ p)n~LMo0j `#Y px1 RZsZªs$rl $ADi1ܗJV~;6@B/Ǫ LdM s +paWxI`PxB_)~P?뼽d Y{L⣁ܖg7Hv.rt㺋lR,Wk&A {>bnt3>nu?.DdJ`۞G7ʃ[de!ͨT *l#N_S-_|mWj>RT )l1u='9z }t>/UzA zeF7kVpfXkzU'\f¼R ZN'{2'<+k%FS%ID`DAD4a^5( /t"\w5}>' H9JN)NAvW3,FYP4GEoGIsAz-dL?ʹ9(ȻQ#-ޖ ?R a(H)U^%XQgMi|i%@z{_D7z9eBΈgl'ƶfXx^9TK;O&CvWF@rgR{ݯ 㐗I[̃i蜷Rv8nɠ)k1jFY Skw*_Q֔~u&4敍:}F<6"Zqi?A=G+ӢN JCCyYi‹|:o[jg\t;=rCgZmjy#}>}L>d.4묫w:zy8EߓysSP&PƥSV#ZFTHC(R V4oڙ=vjWhu}z5,w0.%oG`R,, }7\/JUZ !H9i_8-K/,(Moʡ]k@QslS1. ?w¡?ijG*aES5.bJ!;#"c'wBi\a/eV‹gg쳒Z+}>T(J5o15'2-?m`cc~Tqrϳ@/{ NmNESaM̰tA34EՐ!0l1LC^?HV;Z1؀_.0lJSC^$ 菄Zf@(VG#GED>=$Mz듚k^{Zz_W3/vW7:3l$;l$لG"$ب;J]?8QRO2V]O1zhbLFCZHni?}_BRӋl~|t._2XP8oևhsAo/_{LgN{& v;L Ƅ+\}Aѣ}~QWKbЏP Fx2_g PLD@K4c̨G7cLP{ȚQFfQ ת!qZDH2Ն|LǵʟշY'KS#󲽣 <ݯ|0~~F5^0~N$O8}#|d x/~ӌI%)嚁ZgAg뷂@&*Cwwrc e z=*uh = Wmv`FkOH}wf)@Hk =NX|w߳eOyHn]39@Je+# (]Og{+ XG <7c,pMI P2dMl &L?tp*6$yS@*&#Yހֶ8ުMʰs/~TX :vPv%2<Һgs*tHuMqP73Yq0͟;ܕE,[x,&0b'k޺o 'P"`º%῭Hy" j@XyjC}wGտSY%=/`xpAȵT/&K '?pA( N"XhŠmzj$Etzz_qcPwH%Ҫ4ʝrRă G¶bh3jao9}b ۗtخA}5 N}Du+Hx'/H}H3w4ths_9tRRA5NO?’Y j'%wת' 8mY&Mtey%Jٰ3b^WTm8݄MT{tUDѻ ' ((V IB2fͦT@VIю"* ~ 3[;(MϦv=zaˬH;JPKŹ_ٿƳC$Ψ;:U܎ @]og _(@HŭoxhΔ]-KB K EM&R%7څ|Ņ t06]=b1[ղSaTxx _vg.T{MŃN;kDS/][ZҸj_E m{Ag}  (YE.?xʶ"!uuV A'q krV Uq0KJ"Ms:%Y넆IɂIVYHT(MАsDKJ7ҴnʇW^Z*S$ɸc*ut#aOvM>Qss1 owpOT8ygKz}g􆕑vQ&p?'6>yBC0?#mڄ9l<>?@!q` N3:bY mYMgC5}_BR48Fhb;a8EDɄUF<3R$ѻ^ǽ1,`Vz)8祜..w}45K$ JCRTc+/r)7;Ry)o͞Tۡr[2dIև2χ#sZ kLY?q~|ޛ[Ћ }+3@r.C9I຺-u'%h  ܈Oo < EmNYg vLnHXmF AH`!B? upDpb8Q}8M iTP1~X./"1PjU}H6fF)xf vrƚqcg O :Q5qleI)9N M'[8ɩ Y%gr(X0edL0' ˛ iCN4c4jFѨ۷{%gwL.rr <'3_Ui d u(Wky7q<8DdQDsB3PffGQF[YvZkv'}Py@u]q"SΏld2vYjp]U_Wy4ZՠvljjHTȉ&:FS$GrV{L&;R3g#\GM!tFBoӓ2Y8mIԐ Jingu$a 7 IFheisԴ=@=ms򡟇2Pf}wC~'ؖT z%a,ǵc/P)R@+R+3 r)mf/_6nkv,#"d~p'YVhEsvx)jI>Ȝ2d3#kFSBSЖ_@-;h)^]Q~*A~Zw/E3x IS{)FD sޠ8IC#/o.*ȶɏ}]_&TJ*:#.Tו ڿ"*H~ P?y㟿"<.H~?)wQu{shOAOL8??H+qHq 'pz=7>ݽ"lp032 k3\\LF3N$t)c/!}{'?&=a1K֓l RoJ[݇ V߮S/}Z_3-R:a ,_e3cvpSyW꣥,T.o hei+]p #0yVǿm, \Kل[Moxy $ E/"_xwLt̶̎:evdmFs?3*])d6HHdRGzc?pvᤱoILT$)Ň2jL;̎*BLT:,~I'QQAX]Qqni3 5/S;;wB Vɢ|`63x _۵lznopKIuw5Ql#_/첃0ꃨCQ54%3e a?;oOINa);;1$!&? hNW*G:D#͗ SQPwx >2U^z`. ^d/["~DpBx2^?G-ɪ#Ys@~p;sQj#H)v}jcAf 2"lr93OFF'_^(o +62Gܘ{a@yB!H7> sj|QsF`6O0W9lN`׸Un֕G9y_ =& #4v!"7/4mhhЬzdh;]i"XȍW/- prȠ+wIG$ PXD5yGEb51sc/F9O[Ԁͤԓyjnbm;ǎ꜕X(tH p%A (t6VDu` ˥8 $':t(pTj(o| :[\[oobZ=nVSkt,֬ե.i:m'k6t%ƖT4*G\3fLi]"Jb~u iK[oE&3,N999w#`T0C@@Ef5y= 4ﵸEiAU4S.*tyE +s32U0rM.aUo&À6:<wK =ThZ{ Y=XufyQoAC%2'ht?ڼ t(좴9kQ4-T)7v!+JTR`k/|٩5X-trh:dO-Vg׻g;o2KrY R28+ǣM뙺zi:|Pf '9?P#]3dݗO%@/Al<՝Th1MX6jPhS+>@wO$"3hE-fؒ6qʈF:6׆_YiIPT-gU=_ߓ_#PiH߼%}3=K剪V'8ϲ/lc!4ybtDMèݙO4Hf䙥HV]ZthlPD0lY|bi/Rb! w蹳p7y=4+MkH3|2%᫤3Μ-5uCx<_8~;C??~ԅ]5zp~vNXZ?EyE6ɷ'6}| z[ 5w?@h8TG=tS}W~_&i$]s޴?i݇?f+)?>xZ1W?io32^_GQ*?wbI}3@/b,)͔8/FLf 3VacayЈכ7zl 6gYk/Fx{b!W($G~//cm `9+Ob{gdS ii^?*:GUX~PňGGR"_8Mϝ}|Hcx{!J-JP\XPRb?2mR7gAm|?rE7 $?el3C2- ‹C援R[ ܃QǹcuD [~V?ZC7t&zMyR6`'lC?5KkĆS''ӑ/~4H?D YadžK?/5wcыW6[,T*|ϩ e+>gQ+dۓ@F Hŷ/|vNɅh]fdM=u:6:Nި&{GMnV@Iz2m_ĝMi@:n~zԤN:9o>~asaF2!y%0z-H2gqQxYolྟ%;*@[[hԑhŝ}@ 9★?p KnOgn1NH}n8su}$S`"2{R0tQVWC k$q>?}ɵ4{_!ђt- H~O~gog[u M z~ěO@(]yUkQΓNu2؇&UmwgF -&;:Am r),,lP!R %mBݶ|vIʀix| iϏjlv7o"yc'/[o!^I2$P+??XMD1gC.4i&Ӗ%@y')zRroAtm@A B4Hk R >vixd͗3>0ZAĠÒDz9gIckkw~$?]OD͹'.}g/|ZA09t3kitٵZѨhMzLzYVmJEbQTgdqwxl@jDÕN(7G @ E*2-F.C_LeAF>2^M"G6T'bQ!l,^P~!Zru,bib) ^C K$[.ޫ aze!!BP-' xˈBסHK?T&,0/-x6Lѷ5m<ŒM *->dW@dƳ0s|{dwAnShR> )ljmp%BQ!.D_DT"`{@de|Wؘ+R!wfzNqa+6mZ@(wD;ʏ7ʠ{yo,<W&xc=ĺQ!o,ƺ>㍕$;MQ5/o,$Ʒ%77(/ò2o,l7ԟ7a?Xi=3C}CVm_3i=v_==h=н%7DXlNM'":D3|N J#:| 6,6#@<<8?f\5TT<  E,]Džȡ떺" -(-,\\lCll?:]EwfmҒ+럅?d # 1΂⒜UʬشxXUtx<ӉH+[~vJ$A{kЭVo8nfE**Վ*hY [ݳ*hy, ;QU7Lޥf >R+Rc^a挺3YfAÐz @442T`7!;wR L v /wV#aH<˂1D6x?̓ghUыʸm.#+H: `2H•\UU݉L:˪ "HIn(fPqqEadVW`DÎ12 F3WWw& ?i{|BWG"١(aUU*CSV*eGP%NS@iv3ZA Ws vS7m |iooe|U\%JR5j'e`aLIP) )ؕѤyL֞]B2Ƥܤ jQz &Ŀt0(ϪL\\j@Qe ihRBzK"/=o%1@ќd>PIIIӸ_cTle!fGv̎6h۬ $#~mݤ"5߯T l'ڔ/D:-_mRzL:cD^TW<Я/-.%ҳt:lzlRkշ*'EQ"oOjL(4 /-=zy FC 2# xK2K#88YOE# SqV4RQ)Glu\d]J_.XETtBv+] ]7s&{^.2!߲i->Qs#<^]nX/;!7&؊f0v+͊v0,vPMNxsXEn,UBaUnpՇöEd fj}p0f<1vi]BQ,: ?pY%j*0l͸\Рկ~+cF@v5LH}9;隢mýG[qmwg5`# En>{H4WfD!CCL.<^%BŶ7qn䒗AOvhsq 1i/ ԹKJHfYgdc8/R'V=w J/)S_o!WE3~zfۈNbZIFyFDD#zg!HG"'񢏑(^y&GdOwĜӚlsb &H1yX ̙S;o(N'~6Q8\ֱ`ĆشQϢBb{Q0)!S V-9pi;ϩaFiw*~~PAHڶJ\e.a5h-,E.E@Z$w'Xv-D>#HlV2u+(gf;8.q@J@C9ZH8̨gt$c@zx5S;IZfº`Q] 8A1 ײ4w $0}_}x'S}IjCw=N<{TxDXצ+q <+R:L>_"AqOY r Di#-ɫX_V5,|r_~&tN‚CnZ5HLj$iZ`iOR<ϓ8g»p?RD^}&y}9t ,xbTQSQX=>\?=oF̾|On/NӤI=ULfI]~}s3o^ju6쵿5eAs?xAB@$ELH5eݞ@@8(c{*M#[b'Gιfp?Sc'_t~ޔ2}^VEY9հWs(}OeVC }S'ɲi^.q8|]}WF3d`"NT+|4eiצ}=u/;AcZ* ;cwlv:uOΩ*V08T+X0%^tƐ(F 0A'w@?K<ГKKd$(7)$ZxiL1cS4ސIY?eNaR)(S_}(lPQwJvGnqlkops4.hD's񿿆й=Pm Ƭw4Fj(-_T zںf릍ޞF!6jKe]5oE?Z̈pyW1u+i5;]QhQ?z֓t2&ݿ 5ЙyV}U|ne' #yid eI7ødceQT@D1'c'a_&[苿B6%Nw TopK @Eex}%œ<+ Q7r!52&C`p+1jkP? O^>NVi xԱ0KP"a TuuuXy#L; e?۠o۵gCu!u)`Q_!-hW]h\^ڊىK!uB p!C /]UžU϶ 34Dv:*!?*Ţ܂dfE8Cyv sW8δC2^$_C?.\lƋۉ}]Qk(mjX.¸֮bmV߾l暦;[Tkk5+5 #=V|+̚?Ra*ˤH/+ MfVD`\=8s@i= s0'<{txc(l5z eY OЇ6IEL>8?^Zi3LJdmEF;@*܇Ñc>{Xm*=}=|8h){1hϒ>Y0^)^`c?$''a$1a^~vQ#RnϘ4WqQ_p IψTxrF(} "O{H3m;wHt7#K[!Jpa YQ*7wng1bJ8Po\l]\tϨt8QBd Ksx/DT9ф-nQh8+$O#4ːSOg,\j(0tH}˶T݉ih;\iW H!΄udG{ol,DCϖh.Auz F آ qި䎕wmX s/P ,jpO#T8R'>\ܨc?Id~4io*s3 .j!/T2_1TD)dg/{OEN$@X thd HC"!:*'8//*:_,aIR͢g39tUwwW84VP|ӫ[V%!请miB[{ 7XQ~Tu1mȁ;_FPi$iu߳H׮H4nJK/w{rV\2ciOMW^E3W}?*DM%}>B_kc dJȅG"m߂nӅ3 쾗6"t-7^nNn pA/_b{vń*fNJm Ї?oh64T#?g0 %T?}OuW W@gg×Jc쌌CT? Km70d€Oyh\\i%(/GRcWߴx,݌j]v1Yvʳf1񴫳Fk`_]^S4[!?e 4*,%"&{(QךdK|/Cdv%3uG\r`+i$œ- b7 L@yO5:եGaݙ W@P䡭.wv fn2.>xK'BwPK~>?%/lI$ٝJ䎛HtAG Bقn \oՐk%~f_kv[eo'Rꚩ :jRnzZ=K˴ڜ«:NطJߔB9o/ $QXYf!dt%/t~Kߩf.C9wx413% NQM_ Aݴ5:h6Fw3Fv,rxg0;3Ş;O{\'T2IS|%Q{1ġX1dy1QH'~CVPrAuJ~! \I.mή)9X%b$Z" #B2/ru.7+R`l#@b|N5.!HeKK^fƞ# D"at2ñOsTHarnݘ׈ZdjwGl 8!-ƜR-TjNp ~ŤՐT-rbf',Mm'֮TT>_o2^3 İ9 *RM~E '`q޼1-bt͑e[Q鞃G˖L7 wbY Bð  bdGb|ΦsO@XOPDR A;}MiI+ćeZt$ӞU(k \LF,!a*yM9d=  ubZ4%Ipe{|狉Q2')"4 (SQ{8¨FL!BwJ'D<1\Qz(ĵc9}HdmCЗaRd:M´z(+bP7t>61cXjo583qVnd\l2Z:+bv (YgύheN/wm~/ ݞ!mOHPFREV %sJazg+|-H5zx3%,">  _4Eb.y/;}ʚ`Œh>-~q" ^ӏ~o1 %ݧz(_QQ_0 H"GLL[~9~ aWL+MB?ӯ Ew_;!OE?e&qjU؈Mo7`ً{ߚȏ"Q~+$j!N|V'6ݦ/=xC?3oMA@˨724ztY,fkG>vr"$}^)OJshREOPm-V}kO9aJ[,`,6Ÿ4O[-`l&&H/%6_)"oI'^#h2rb|o|CCз4asCHCbo }_C˯?mJ 6ըO+cK٭O¢ubCc sT/Ma;p wA~}%&::T@L vܢW#6.P'eD ݅o h(-7"cP$ׂ/ʚPׂ9HՂwxZP|c|ey8E"iAw~řV6<۰L2/m9[4b]DsQ* \]kZڛv|+͏8$<~4~"n*7*<(hVuUWUPFçI<^0Ę'"DXj*WrқBs+Bo.;A=]j--V]?7q]&6Ov;kÒaY09fs6lg\M3[̶]OVBQCd~ $Pr~fK4urks&{`) ?[4oe-"c-O?nA0Xȧ6;V:yMa1,.>zu|JKu̵ T`Ϛݴˍ=02Y=26;d o5wWTP^eQH4ClȎ_}o!d( PuqARdf oZ+$$ A7,Զfޟlr\.}E]\o<֍L`^+g9vʬU]SG~!J:=e0ᅢ1;\dB]Ȣo$MOxyPwe%VDv #DžKZ- \M 0qfdk4*MbA]]HA(LeY]= Bƅ&j(Cnm.q T 6\K*JE8Շn4m5ZfL.p8Lfx;͹,Fk`?}P-P9(m7O6I܁nV[o'O S"zǯW41R8 X_JJM#]ʻ(\jau$Wm˃@$36@)gEywM!hl]6ylM\ÂV z1HsA",TN/Yy䉦؞N[z p] b{IN-=ooE _RHk#Sy[RA2O0XMʪJH0a,8.Qe&OV- F_+t?_V9cUNѦd|u88*h1HȘplsA^!`qt}iBFs S M |ZGl1煮IJ(FA F 5%B7UP !'pop\A@KMtS`H*|^ҵ,֡@n%C#/j)$4hWsZ؀f뱿5xN};ZֺN}Wn7uxߋLyƕ%e`^|ſh>8[h>hr8X;8~G seE~"2<2j σ-C tP\Xen8wB(w܇CF2~>*I*\02Q2bmj\*y7)d\\ԼzXdi&`W3'40^0=7 _W?1h.}ȃ(غFWɒqZMF+m@@C-!RȌl qeWآzI%ihϤL7)[ę<=tjhΤH,;.#uHa_o&<6@G#Yfݎ'`Vjv8Ծ/4N+_+!E]s mtsUv ';nHڑ-qa'UEpu'?/9#rHL"8o)Z_0X8D5#Љ NgNhR0t('^r&F`PoHLCc"BsvH\ȨIk?!#wHBbB(rq'عBA<.,:f BǨQoVm@i=c_w8^-wO'V*^cFռUkKb*>ђ`czW;wWD!G {}ZBdN2j >1$ ;{'V%5ɥB,k$J9?FML S]aKԫ=vum9NLF,X^@1h<Ȃ+:#iOBW_VVk2't:^Rfʬ[zmPk ZQit._wEXbII$XQW* ӶHGD.x48:?E/جȜԌe1<~ᑒ;y,Vht&^p$4&!;QeЪM* ^]WDږB(~,}#W՛`!*8B57ϢCZɁ2@`2"`\̈oN@W$jLcDGeߐ*' aխ5σ^i-S:38`&#hZA`a!d,%sOy+M{IKGzZ5k \-_"/ }L|sId%.s~>C~_=dDzeA7PxKC`$f-"G0LxX+)ܼ=0N sNXuUjM&M6AiaDYuօY+S2"9٢sS\o@$?Ek G?'?dÛ] p4__ƚ-SJܙO'7/3_)0Htm"Ef'LoV#Ec`8ENƂȴ4V<-S)Hsj-Y\5Zer<`8 g%bx"+yXz\;Z!ĂeZ HњhCR;xc0ɇ zi?mK& f 0\њ@U)3cb,;7*d41%/ H+mH%\+;HG .$H kk+M<1zT'  L>ө HI%& ">Kڶl.%yC" 3j$c&!sr|n[3dc1 6Ȱ\ӄBN-D;] p)a55ϓ=r?XzE܈1=R{T2$P*E={E)D s3RSx|ы ȀU87ִ\P 'y=8V~2p+g_eߗ7[.= e pPLҨTʔqBttNܓ8^R̐QϮ{'ՔF`i-z @ߨ} nx7rm @;p G,t6ylƮ˨1?Pu1W0\1yg8yyM'PxBgC0J4 5"/VN֯/1} -L"dDD{&zG]nI0a$ߑe0TI<̄-ؓ6&wL"'&L?MB #ёIę O.m93a& I2a,:ID+Hg;Iġ;ebqxZSgr IDqx^FCe=?/᮹1F MhOp.C!g#D iO9ў@pD= yLJMY]iObviO&ెYOvU$ 4;( eKNt٠鿀% ; ]Qln|;ŎwgQFeGaG;J&;ʦ)0;J~mO=qʎ4#h2bl";VdG1:kر4bfdǎr#;J+eGQ$^AfrRr􎔺 e3kVB/^_bR.̓Ŧ:;.-Q]D"0!8[%Ej={^\J<]y-*`kY^>@%η|j_A1_GQoVńcc.7l#4|E%[+77FK>[)|{" ~y ucLHeG,`P `rg "&K)n#=ٷ8bc;(hvg9<4:4:=mǟé~BbN/v,m\:x,81!H=#(>uD:`X$R߭p^MA*e N “@8('1tfyf${" s"QH2jk`Uy%w1FaRX+LElR+Tk>pUSۨΒ ÌpɎjoibP'a\%*[Kαf?uM%/ڬhu`ŧۈ<ҁ8xm!A7-{>薻"?8O&L&dUi5l$j*>d-V}K'iCuh(D3 )T2aᏉ@g{da)uQǏo%~Q6SYh-;2gQ~߮mȏw,\GkangY>T{$N֜IP;øO '\pE-@CCq,H-c \-xɩI վesg8DN4gW]u3եS8T@?EЍIkU9Ol>XT7r={3g\:*WI$HcBpHB֪ޓ A nH`$:(KXQqT""// $!ޫ??u߭{{w+7zWcjW_dsJ}29;>L`˰|O\yFgu#RG4XjoVIvzk|ߞZ@[2?/ǼF?[]{e# {K/\rbnQ#K~.ti֯ѥʵ'W5uYP_SMgUA&4b`QT&ks)yE=ht%Rs5^fAفR:\nAv"[ w\v׵ A[jqYE"$Q_ Y!6kks6~dc5NVqܳGC{"=|))k[,V+*0&e,n162Fv2ٺ?v qZ7r!K IAp(80k|!]U6kw=gy4+w 4gpb8^Ad˹K_u/pu=U'铺q X^I(1}Ѱܳ'AU APsT>y#$DX /K|X4I }I=3[s19{DA@, bL)p0< 4d_Rha64+_&e+lw\bWnKGvybfAp!m$1:|zzqoggTĈCʾK?FhoϽw|kdojtPW1*aV7QȺڎp,MQƛymV3.Zfo??u (ߧ$gFWھ!^}|tT41N#AX!HgQ&AQYQ^9(PV[Vԕm,+y!?(%I wcv`Np؄Xh*3P/,-@^o>|a;^AYȺ5kݰ;pJ.H9 nQ{.8/ 5 g/ܩ[-_(*9O oucwvc5& #wA~mBBhw\ӓ3]h|jF9.}!),l'2:ݍQ 1 k.46k R(vOystR(kkP:@?Ndžtes݄sBSMS Jh L)S3(t¦ʄР{#"H#u+[?rnҴ3̼ۖCfGMY1.QLa!Kw(_aR&ӕ U딗MQ d%h]_\qiaSVoY&p*|~ UC ϕ\ᾺDW8qW5Uq7/=BrOy+SnZxc&q`T˽-[/u8^8LrIqnˇz ه-Cז|y˭Ixb|#? bkB|=Ƕ ~ Vrh2;P8A-lvCkomS@BG+?][-K+̐pwP8UV2@MP:(!ƨphd):?M,?z0%$ PI C&ʠi gRB4H 禉_n^+7;v=οN+3/D5H&{ fR%8Dk/e-7L$D&9ʿMe?;HyU>vn \-so^y ?OyuXxjgͨn.g3s Ehfgu (*[' ^O?r[ 5*rfTk~OsTL۟s#>΄K/ZZ/m'ZBExÍ qW /@7:{*nX@ o-HeqxЂM\1'% F!@/#3vWMȭkO?L3Aмd3U]'w%fps,b}[Y<ܪd$}{(*<]u o,.^ @%E 2zKV}8e}ktSOBʝOx'OR$7̆ˣ˟nEz&k ʛvMp4B@OD_eX8@`fa—B31|Gr 9;x<4{neHe|~i=~_ÕZ<"߼hB+<۟ᜨYɮؙၧB6MobcL|fxn9 8 Gy k@!hxA?~~awဖ?ȴ6Y+ crYUBCc]9T 䌧g'~8 9Qk5lj2KG~ 5| @B~Ë;A 72![ :B xX&( 8$8v"x.4텂>*T 9KUPl5 Q:@ \2] /gu[> l_၂I_ Jg잚)'gd() FnVBSI8r n ج3@=PF'}iLM2 L#`Vx2Md pBx'̙KLieBZLh YKjfCZʄh(T-Ġ0uw^![=DA#5ugrhE+ "knQe^a+nׂj *$ߣB,P#TJtCѐ8t(ijz)R/VnT8*=;mZnE}]eL9v&m3nv(Bwu (Z:9T( gvo>(K!gi蟍D,!M%ͲH@ WR__zcUw5~ohU(tr(}8RK'O=aFHpp6pP#֔=ƺzUgrU:"̼q܀skG C F!:?fxϜ\"^Rr?4cL;ȟl^D!+aDZ"Ϣ%Q5%.(~YN+"1{TCEŎzg%>)xPчmj)wDڂ_'!F?eoVOIE`~)"qEϠ#Z]aUGA Hg2M6`dPߋ}"KfYe} `e\EQiIKAtp4uXY+gYbpKXE3sO)do?;_8^i+C#?d$>&p9L|P|^`Ķ^<!fY?8P1A3 x_#$CBP02aObGw/ J}t.a;Rȱ":wvj1[]艷2nحnm-n nj2m>!)pUSJ#Sq'@s{5mOTSLBWnPJ"24jġ$^)t‰+ll3RNrI{;6o~ZO$ TS +EVQ<}HIhp:=l  Z ߭SAg6\n3p0F3nq.CY>ma?]S@J/RS6d;1GORw ZV,iI"*ՅKS&V*[˛n\?):s}8;_<*[  L0# ytHXețI(cPQ>ewD%|"p4aC:atsֽιsDU;^qb r,;.h_NjT29E tѽ =C=2A ́esrMCWwEtZQD)' (B &J_j|+H (;Df|џg/WUV><$dpIIIR&w;GĔ/OrZI,-CaFIYRUl衃{ {2I9v+&gO.,r$iIiCG 6 ʎJ}ba/=}inN&~dDC`YZ6ͱzGSHJ5MI$?9N_ΐu.bxBP~A7@Pu]Cܚ},ʪU*iy;J{蕼x/RS}hZbxzQm2+.Z]X觚I<3vnܹ;tnyC*GC5 iPߓuP_ .pEbwZ9Ɖ;.w,?6sȨ{/Nˆ6o-2A>}ӉQ7?̘#lU.aPCD:{h1\:nۙT-{?sMe=Y7q%uks7o&eP6};vFylANq-H[H*_.1R[%FRjB րY>KGoyθ. UVZޢCHyV7{pXcb%Go;o˧rW-g\Q8lKQ*?Gr t+i 4@de_ݪHud6Sڰטf~_撔6m&t(͕_pF};* F2-u$լٚsfC(Z1SzU+R J:UIC&SN@&] K6jBPaf3l= _AըabG%LER/4ֶQY|W'~J "i7>_Ռ۹7;Sf"َGslҴ ?< v;xxfk' 4Mծ^7˜+~vifM̢;L [qޏObW[x*iU!~[wvX(o5B( ~!{cnjXB|"A(pl]\RLKGZq fdD4&+LD|g>;6;F%ς֝wjyמm~/oDk@FѷN?_+!GRun/d55TּP QJ/eW4V&ײ˓D/B?YN+r.Kt؜VМDf$EJ<4̈́:4jYM_"Tk9ؽZԂ6¥_ v%1BLXi9˦!lVM"tLg>RZ!aPX-78ᖑ?+Q6ڢ#սi,׻=wo(zbo2sSqQ:LawwOH3,iMw!>0R)/oyf`p,vv۬v :YqK6?CFh/Q_GA9}0WΟjz1L=4/&MzrN޷CRh clY /`UP`%7lXshI:,5g)/M+T`=rA?\H45,!grKL&߮|f? uygnl{" oM5&߫(8&=j02j([t)~N8|/NWgtBS!K ,P p  q&T27G `< 3?#H -!ϫ'ԭA}8oW9<*i?;Km9?0Mx@1֟l_z!ϼx7p=wy xa.ڥK:u1UC p6x~J %V]NXlvZ)BvV+%Ƿk  /1[bRXOex0˚< Ra{ )EPK ThXu'}[Ѵ2SvYwPV'I<"#ןؼk>ǚR"pXgm)3JHފ/[;ìC{(1r{Hjyk^ TRZgWV $mwH߄?~ߊ>߿^"=;[Q+O]O̥.]MVe(ybȭR wuEvDQ |zCXgoKyk2]s=p*"qgTגɼ~؊'`⒮'6{nE t<2XA=d[-C0r =Ɩ{d.[EWvRmŞBmˠl$J6s.u0d$6*uXBzE=Sh?Y]lу.f&E-XOK Mc Bcvۖ3Y٩:&2C3mRl¯Z#Iȫy"ti)]nٔΈ7:_$I\8\9vp"oڜ&Fp9-r+]i.?.S(D5P 4MEhYi{Pyw$PkdXRϡ-lK#ꚄK7RN5 WSXݬ!t\8{^3)*ClvO/)7BӶoPDc@;㡟~zwqdhA0;ybN*SrvvTwZ`Zt3@[!3}q`RA(D"N&qO`-5 ?ߺV]qp3UJeP6+:@,b2XvIaXFWH\n"Dc4p  D)9nrY؟T\#jm_Q6z#<u5Pye<[ fx jeKgowoCe.f%@ pK䠰y毓;`<:B8<'E-,k킝n;;- <aC2B)gi.T?lGW '(%c^?~]zU|ӦMK?2~{Klih9L?=w03yv,fJ" )HiQr{孂΢Zt! Mb`FB1#F` ;+( ~S'IǦ~s6SsQ`aj\K?!aϰ+%n"ΓG>|I?*aFmE1;c)ִdNhǫz3BTat'Fh fN'6-q}dE&ߞ%%&=GL{aKף2%k^Jab= ݜ_r6@mןg{^::yzc. DwDGV$S@2Ș1)Hc⏵P-I 3<&#x8nrИzқIt3>3zor^1"K9/gL c?~̐DgX3*$!q8dH.o jy<l)ܺշ#Vf;7` ̀b]U(5uCN9''cp79 rrs'pސ3&g?##\/;v:s4k6 ]EtnmiCE^d{'v ##d"ه?]UU5:*9̬$95AatdrlUC2KM!yBtf\Qפ,C 5L"me kߪ>ʣpyuK5LMܪ韼g,)9ưYdus69v ]VC0/ǵ!-hJe.d@:،Ǜ4jzhq)ynt'", u=qWU,8WqKKo7nq?; wv圏#Q(ȢMj_ڂY?hc?I(4Wpmv;Ybh3ZY;$s]i_^Hc@P(fHi4D zuԟxq7t+wʅn1]Z~A_ 8 @(gO-j@D #D#~oO0"Ubi"JvȱVrM9:Hgn;4獔ID>52={yu=랙"!GVGʞB溋G'o4[Kwt!miHt B^򒒦MK["XaEGVEf (P>AP7-/M[Ja$//{ι{Y胇#W]{=NbvD`+sgb7<*O=KZ2K>F6&XP6%ATܔ%o+9j V?zh~c6 =#Qًa5t G[h=$]azSGڞx%t&ٲFHU8ͱ2V;e&(gCO8oЎIk O=aL)MZLTD8a$_ bS>}_ hG0Bq 'crTAK`[|tGϣ8"Z(vLpTElZu'$㊋KX?U`/FĮ,.Kp:)ywI|&TH0F7e9i0Xf` v+ݲڍMA3f$gb0~$Ʀ#2NvkrBB-\!_ڻj8< uYF#FQ`m*G%V 9H*LqZ:/IzX_W{ԥTEJh|&zOD92%M%X` ӧg}č+N΅0)X(@d  )*p7211ϧɘ $tvSдrۂhڜLxn'.<2!?rej`)b>-tOe(K@.ozu[DeF6K DbNuc+!".\j҂FG8k'OE^yz;S K v{<%] b՚hqȬv́RtJW0H 8co2':ߨC_'t0Dx~qZT>8I=(ߢ͎IM„4VQ.2b3oK7yۢ4}r[CkU'Z}SwNչFs@WAA`6pշNQgg͉¹r958^P+s6%_hMrn`)uVna+2:&zã'o&6z%ٳ)z{ZKc7E4)]y &TKy]~ #}W]bz;ҙ& DJ*Jɷ5$Lm'_ ځEzw"a%jWޕL:,l3{h޿2iz TOU kCNքoX*ոocrY]*ẇ<ת]0Oa7F|шw#~L.H?KGHE!vgKEaKĚ7c>vQ=ggNa,a3Q/q5t n~ +9atNt@%Z1+^0"SFe ͖5-+--}OGw΢-iV^y} /,pb.LYP%ΒsC^Ijhhqz߀x)luL b[*pu8K*ŋ )7'<=oN73o*d>oDw΀,bD}UЭg 48-gzHGBɾjR9!c|/UV&UH!ބFSN>S&TbW%&[.^]'B4Y<0 z<8h, };=n"8ڢ {G\77Z hBfdX3UGv-jL7J7*!9'?%Uwkf[̷ Xk:JN!okso ]U+CZ^V t U ]ο\Aa_jj;XP|Ɋ/f`Q/ 售{gLU%1tgq=*X^ ?bxi!u Xd`O.ad=~)m"Ɵ3(}ca,H(΂2vZ+=*B: nlz!hT`Rt5%-BW3MM}S@_ 8IՂ|\ o1AX!`19fwѲxmQteA?[gf~ᠰ?dIʀ/Ul%tdj|Fh&M@ XHXbxuS#3-xr!'r LP,bZ~`5 E}A3VGه0?Hvȥ/2Um[~~{d+jUp{b%ծ(8`˴Vac+J(mLyGP`Gܿp3RI*+BcxɔdqSxIwqfl9;^vQٲfSų^B Bgr}xqˎ٫ts}nfyiBq!Oewf/zi4A//(5ͼd]=aWYD!]"3t(v#<7bsQSwnDʝ΂Ļ1{+_"?lT"@=nnYO-_B!J \~ɢ܈<NOՍ´׶kZRO#ud !5՘nRV]C'ߺ[뿛(ZA/s9C+;$YUtD!tV@%4:Ny$!M&M>P۩ A,~R608@Jk>^^2=;4~1Y=:܂9콨C?&6>-OG`z2qYܝ Ocz2+o+" S#'T?_1Bpא&&>{*$1kR+F5L T)4!~:r#UKwD:J bx)Ѧ:DWh*wďb[JQÆё}hX9kkk^tlM|Z`E}B5"b6ZXOEvHoA3OڍT}hMZt6ʖfOR T izc.3S|R W|']LTk/4|89!rohsTemn'9/(ެ f[?R5ܵٮk2[}:,lD#EaWC͛m . ӛ o=0"n Eو8ljwu<7 7$ xna6 E nr[FRIߍRHT06,2twU-zG["9dhN'__ ㅔnx H.\v}$õg> /^PUyufU!dսHj l&a -4 /8[2va ! oc)^1u3\\#G=`i4+Yߋ`jAÇbmVrXmf$ B1SIf ;xF!(IW1F!$0o@HklLHch:X/epf y0}C0/M?y̖{V=DoG :0;ece <TϵƓ{p ~uЙo3fPT[ݖae,AaMt:*LON%3lϸfHz+M9/rE4wXuuM=wCLATvǂmnCkq~2: uzM4EYofkZi\+&np0l(DvdEyЊ(ڡ8 "f7B l>w}"| ֨@&S |̩7JR!0ʽ{(%J*qIn1C<͐ݱ"m 3q?s9تa3{9\!N?n~18WĘU1n+TH9<' A:޴8[:N&!{^bUPoz>74B^4to>x<&FL,ߔ?r/t6*szF%N/(f}w?̭8;|$^^ f֛gI.m) xÚ^^H,ӣ Qr%N%q/+ n*sغfcqpfgB18GIV,S\2 6s?m}wm:?Ȳ7Nz)V-&~ Cf<7/G K΃Wx4[ű7Wp5}1s؆z~mn!ÄC]W J,.$PҊDZqv5rdX7ԲMڏg<_c_;?.6A~???H¥ϧ۟P`!BGmkI,@wRSr+%- رj@Gx_&ɋVl^*X]_/:mDaz:f/Xɽ.x/`b]Ȃ{one_a4/ wG?)o2Cb:{_B k`SN9Qkڏ}:/ / ѯ|prP7t;|oҊ;^A9sR5yokYJ<濍`r׸m'_ a_i54~јmI gm +E"(ABOER!n@gr? ͢4"^mZL?-kõu_iCeHD`\3 6i`|{7\; Nl41TM79m`ѱ,s?uzOM͸{T!z8ލy;̢- L_Rф dojmBkHvR$N(wmkxB[yjJ=DlTqn [[wlƫ/5VAbuRh3 B"46>$#!R+>l9{HB\}_iTblhsVkR0aJY(cP&l 3ul_<6ϿeKR_rUÃ6{?ʑj> &Rn R!sOuW]LT8F(SqU߽ +t#I]9aV9ϩv zM0]rd!^:T%>B[/B?Yw[dw ҀЏVX|+΄{E~U0I!MFI45?.ȝ嬰Oocu %wHPM@pA$FJHџ Nx eE(DU'܃)pD7dыcSYg`?c7!(rD7Oݶ!`8 >^k{_Lg 58ӿܙ"lVMRz+s H, ~Y* #s'Jg^|_Np@-gCD,BՏ!`iw =)AdĢ+YY%!K)-utDKN2Ԧ g"Ѡ\L&]#M|+[ ۯ.^\ C lkXyRi P}&&e5חc` T1ƢOevnXtɲ l]gAg?7ι;,HZUvbS r[g%9~I@h!HBߍ*[ &HRҕ/!PI!96ž%\pxitu|@-[$'IU]#')YdʋYX,r<9 -U$A!\cTu60OIu?7k> =rUQPz\؉+y9,K+gi/?+W'4YغboO.Oo 8]ht8B^JOC!mL]bK{!9.A9_XYSvlc+丹ٳdCvq@Xst0bm+Ը"(@Yxz2Vsr<ۑ.YjY4E- _nTJ7tC7tC7t9)%r<_6ߢ; @'Ef$%! bxRnUɞBɞk,㾾=^`zӛr*έJaiτ{&3,c6u ~&|m0%$X`b<izpHPBRzI2aJ\\]BrֱFoNXvR-ߌ!o/|acg(J\ >= {#}&^,8޻E~LEnľm!.}ӥ.C-d|R?$ūk)+5 R Y b?gߋ!;=O؏Nʞp KgIHhw"؏b؏Gt ?6{e>ƕ"έإHː5Gkc؏sK. 5w#Y+?>:QT ?x?鏎=8#A`|d(7w 68yj8BܾFg'gVΟռK;~>oXe_߳adیMIhH;s\߸~益9U f3 q;^FfU㦆=wZʉ {=[:8M;Wξxȏd㾞kf}>ٸצCuz#U __jH~Jj>UmQ^+rt੐m+/+bgS `z0&;4-Z0lcL+w[Mo2un6Eނ#[(甜˜BJ~E pRO4\L+Or ^ LE:\ahS$šM]Uq{D*+=EP~#*..]޺wi)3x]|FA{|<;^UȩJp۰;ÜLfA:MhN;\9ivqALe׫ cebn ,THoAn4YjH N -Gv+ғn2$̳'(KΆ*UW:=yJRU"Ua{#҈NVLPGCps&h2">f 3CT!UF7 #¹hG#`hBhSq_L70Ê="@Z{$'(Ix@PHnW QZ>+xgl/%,eu* a֭b_K{!7&݆͗@0l*骫@N:yva 8 'Ha@*!2=U `- *ǥ*#"y_UGk"x)Uz ESh8 uI ijQq1@A[)e)SBWy$20UeŒ8&qDX1א;pUfP!pوcoo_"=٭B'NǙd ,nIlT#c7F#gf(}?[ 8cE!.r{ϔXOgj4uiUdggɋÅV](((ղ?@.TwMWT{axn~>&{˘ЈW c\`xT2嘆 ioQhS唝5T)Qr("Z8y? = R&QB2P,iX-\/BĄ)':=Œ6w)GƼ6GydZ v8fԬ-Wcc.'[X2W?VȄCi淕(`A$ٵv4'3r0oƟR aE*x[N4si?Al5Q#0Maa-l*gI8f03gc?7_@|0{%ydΕP&d`,6ضJuvC{mc{[[V>{} 3a>s~G<h|RD@'<+G-JX /y-2PQ vA?72Gq%I^`|dƷxq;@(JfM^l ւmGRztͰ& @j GomwoCԁupk{9cl_G dK yNWu?^P[䧇ݡgɈi+ p艘64q7ډ ,wDތѫɐ4DS;Cjjm)tz;וxMxpͪP4kjv(ϲ.ӭi~~F=fLڑ/'8.2G2˹h-q4/12("?]x,O$BLLrI$?0 i;E7t]c6)T,[' 䢱e\]&W|ZpJ')8IbN@2\ c.g.~tj橓G稸ߊuPV*KΘX.J(/<'EL1,$CxD%ƹ]aD"&c,#+bU0QWlܻ:$b7a[b OUo}jrAaMId[6hMꜭXzN/bLk=gg,h'(tޏU?-?%yPpæ3 䢛!q8p6m8DL+^K0Ѕ 6"Q^$-@Oc4eVDQf@HɝGI.ٔ1 q 85rI(UOLB_+(XV9iz~i܌Rv;ͥqY{tLM9M`S3vHQ( 99gsV{mm(N;tQpimRbUIAtSqAd%^sl!ЫOԪ^j1:lKLGwZΝqoCcJBBk%&Zhb.6iUrP[ס;?AN捓|?|GlS01vFu_П#!~Eoj{ILwߊzg"OeFA B9+I(?h %x0 j NDCagOM-:c$@a%Zn/ P7n|bhh:!#7X_C;h *4%n7p*X\sԜA[Gp(n,6FXM?^>C?ʼgg %=B *P9oL@+U깔*Vn8i?X[ ?T++~T0₲Ou%+yϠ aw:nT.5*>Ge\?\W#[u"Kpl?H~89V:` X囀cޣGT1Q JjlYc֪߿(M a+M+Ʒw2pj|)ɇJa ^,TOX`/5R8VA VA& E\Wܱqz,ҪEiKLgs|5 m 漙U5\䔉YG Q--7|w6`1z^~h|!y 0;ܜAc2lQfv /ڤ=>3̴/bkBDTsX7W_}و#cK$^"9Nb$c\<+Ni<.!Z_]OoĜc @;0 Ut$ޝD~v@Ţ|%Y}ܟSNiNQ8h~Z! : 5?#}͵W 1)_^_(k+xѥ^+8*@롖߿5=$s:GYN(OH<ȷڊ|H,/X]Տu{Ia~3b0p֤:tVey`u/q.UE/vӡwŸ{$KSU |\0ػ UqCƙ@.3n5Pai>|_M0&?DnH9u1s̋.]!=8Ż؟ }!{UR>x+NT(ʎ -_'ج^A]_Ka&>B,6mډ3D42u|Q4Oy,x^5k?lוJB>E>cuQVQ|lZo`u{SzEiRoaF\Sk-)Bk"Z 7߿ǐRf"2r&cԦjFİ45yET(~JW7`A[%U2bfcqϯV MeDLujqzz鬁%rw#,rZ"|D5#g\Ei qϨLlA&jdD`f2"b>+2.;ƞsERKá6e5Gտ֯Zn׎jf;y%;eB_HNWo ]G嚼{UGDT"oK$[?AaFY<*??z,ƚ꫁CHӞ~$bRѠZxʁްuKDwsgElj,v1Dv ,IIOX}G_TDl7bNOf3nFc&i5e13HpMRϨ#i$X*|X~8=džf(2","=JT~j]O_(hԀsBv$&dFF@*@KǵI̅Ys1= ?W %# ExBo5 p1*C<DQ,Aˎ~\kSu?s!AAC]M Cf? Q(t j !U'Q7[OkC X@H,eOrP;;*୍UoGٹ`Q4ù R,LSl?_{5>N{9׈k\zGv-;5r˚Y7=k ?Ѩ?k߉ Ed׌d&ZgQ)+J@t 9yb&|>M^\[ҋeo>܆?PI ` % A I<.0aJwo6-[KH+)%{^S ,{НlciE 6D(22#&"HmΜsMn~{{oV:)AoƠ+"=]hM[x=0k- ?$/V v#;lT@eVe )o察XR TU8`p/ޗD#sjW3Si'&*1I>7*3*V;⼇&j/=,N i^f1Z-Rh{L_jmx!mʈ?sǁhOlхZiJP#}gWe0 TMC*@ qEǧY͉"+3;d(d(P?穘jj{<ڧ Ovfȁ^Sމc[Zk3 #L,ٙZL BlzrPVi)YI}Iyv)BƮǃGD?qWU}&Mޤ\Y: v֌>;Lw(O)#0,c4wiȇ⧴;(/$1C# Б䐹[Da$,,(968//ωFzE[叁_~5#sW| w\w7ؽl\n>]? 1j=ɒ!'R!jԶ 9̘x|7Vp䑙naTGKz~; D#w'kv<͛TBuNa$UECXؕw }\ȱG*?R #(8WYwh̖yxRq"!mvQe+Ct9Ca֐T^|l\󿛶UE vɵ,Z6()T5}| 5x9HD(cY1?^vSb^;k=:l+@~>Wެb}" LN`9%ڤqsUO;<'AzrfݷZ;xvкq5gv~Fb:XϾIe,3!a "_$$=$!HaSOrIѺַyf7 QYYSiv%[FdeN;V[ڜvjEg5AG.>}^p7~']{/w_ږ`iHiAhAt*?%Ne[Gv[IjkZS64_mmMif{vzG:rݵ{ޱ;VnOPkkwǴ5߄ۢچ[x w OnBgh k(>%ՊoAF:#X:2N aWyg1gѕZȏ/8 =g3c9}aqE-@8,a1E0axm-4c)3wS~x;FWQ7t5!^<_UiU-E3/JQ5GccO]Nӽ,Ew#z%!Kq1TJr2Fjz8iVв[AXED!TLb xֳK@4p}OmOa{)U(;Me3QQvaQ`TT} ?3MvXb/e BPj,3VMD\"I)oI3Ls(_g " !SnݢSV0\/( ǂJI!~'[ _XulƆObu[EKic\%n僪$fvY4Ɍh1&ձV0[l]I \/NH6P&P-ZBTKk}=N#u7[]%u-nB1ԝ2l[۽aɯ#z^jYO'Ӥ$ o?`;W]FnOT_-ŭG?7h,F :VamNلWšnfs61ٜ[вA7W@Zs? WMS漞 z湴]/Qd4# @K=M |gXshyqZ'Y;h Y'kz0!OMAgxR;M4/P3-!DHK?.]x\˚+MOжy!DX6Dk($ؗ> yA7&^{?NS̯~)G]*-kdVKCq fi D!W@'bh_e0uJ uIm2.Wd ԰icUaX_-q|sdQP1ƷZ:r4M:LNuYXfcI3ڣ:_G5XK >;EC6(9AG{rH8'V:mXzlx V%gB8>y}H5Js$|]̱*9+4s 5D~VBxS5%h 6׉'Z ]hkP=E]ZYzyuOMД$ $ekV7J80$)ILG#lI 4cAuF'Mfbpr8eLfzYMVy_˿9XK [5%iT?M$$@it|Lt`gAil,A`\DSɒ1A$wMr\IӬMB.pC{ȐNv:@mcdf2Ve3tdh;>] D\lh:*.PtUW‚+C#>%a`f *P&~!$nt "PQPTlT@ Aͷ سKn&^_c+4pdbXTJKKɔ;<jWgI0Tj7izn:3w;j4euXEtr5_4vO@u @߁&ΕQҁ/j|: "Gy]F*J$l%/u Bd;)-6-wQwa$OY.V)"9pRf+}]z؇4ޛ8մ=gQ!i9($ω᱙SJ%[%UWzrKr)q"%]1cDc\x4> RWVZ^s9SY;jg胉Mjv0k+%/ZoAV2DY+2LvnV26͐c\:h3A Oݥ%.l!vF\Pjpd$In1_GL g7D c_8x =I0g6A >A_ME@_{Np j|W}zWv7vc,66u[:a,hpndoco?g"apwm+ B·`AqGlr\%ilL[UK ,QH6J#ܻt4 "o1 "&휑'`n5MëX^,.sU`X1`j ;aө[UЍTe/Q/V3/wl: 679Ve3ZY;X0.ZN-?5h#.[ZD T6O{$ϝAp0?">Fـ̟!jdFFB^UcWW{IeJR~M. IwMܛOmi-Ж>(}&777 JQ(BaE@.$I,}"E ʊ(hB (_> mgg+7mZZ&;3g3s|\hc[a㾧Z3q E׈:,J˅"$Lڡeݩ^i~)t &!nV Lj#D`M 7&T|A&Lď4)ܽloNL|·@(տ< 9glie92q Iq8]F52W/]1}7EUHWDChUf> >zAql XE" M |Z+CF>4P@u(7`i*2A O+R\B/Ԗ;&LCb}$vC)bI7\[^CTKZp,BO?-*!ԴR]wjt«*’`V6f!-)F=qV`5{L^p ˸˱۲m,} 5ՊjY YZK"g$> PZPD'")rcɾ]#B5V{+'M0uO"Z ,KqGK; &a3XMf+cvnNotYsv}?חWHYWJgvI{{nX X-8.0Z9#^1.kO}XcWHk(gbc(B 9tl/RnZ-\T|9':G!Bī+x^UWdJ o88 21L=rDB81l :縟 E_m9:f+ɳmlE6džZ1e+{)@9hoIDAjul{sZylNtx rJ)엎8vs~ʧ,(5ozrO^v,1PCR$Kȣ?hhC⌁`hjTUzʌʠz.5YqϘ- giX?~odZi^Zl[, .Ē ]m EP!ZcN\'Hr fcfQTt}~Y9:2gm̴ Ǝ[إuEl2BrsǫbWٴKimJC$0Љ~oȾ -DyV'ˏHXϮU]PC }h,<>QJ,a}Fu1Lkߌ #0Vln#$A  kW/k[$aCB[_Ji):Ch!PpshEyoGL?밚i5f2;6fpNa8e9`3z.1{G.r*C9_vB 6q)桱*RtYkZm$>"h GVxRk鏂PJ!LkFGJ1Riۅb2&e*R.ʱfY"k2,X(\!Okm4rS0RS3u38i*_8["|mtɧfqq.2,2h4Ld_h6ڌ&{*hԳ^!E)?ukG_];LY,3B@uUd}Jw5'X {묏:MP-Q#@ o5oRgfw+eJ>^0-pGUMfì;Y Z 'd2JV d^(y2JviѿK~iS̲5ϯ?ZL&a"Пl}6> *4ԡ74ZMC-{u8:CΆy~g~pׄ₩(J32ڏTndٮ+Q6p=eш~nt2v{sM L߲.G˥77F fSovzeaL_+ GKs'O y⎞A[qW0͠&%d@9 4Ӫ2VaaXpvXl&c6⿌L;we[A]s%ByL䭀+x!XP$D+8%1 |Ь T^BWD֑셥Q.&^+Z^, \GŢ@lz)^_'b]fc 6af8+~strSz+OQ+iv\ Xм_Of`xqreE3^vS j!T 8U\,eحB1_ rGʤO1bhrmn;rQT O ?H'=!kd?R2*;O6OzͨgY3Iimz kezfx;7u-!\5`jc0 )뿥KGȗ"#(5]&uPkxFJ֛Ǫ\B/G@6!tj.?V2 hɒ)@N' %%._WGʋ1$~w| DPVL5UOI Yfsrݦ61򿊳  l0yGj2 JQ {P4"ه! mNu -f @-J1ƊݒxJJ-;F^8Iry~Rp A+63AXG>Jޕ1 4~v2T\{/n kN*C;@ngӵ$p$/laI0I?nB<صق6>Swi:O#T_ j!x_؀?ك^f@ Oh?Wρ@/ f%i޸VJ~MI9)5JdXNUyocPCqG)Ή#N/ oX8">^DV"9}F]М8LI= $1M'\P&wI /8L;L"j!w"[rV82­r`WΊ˱,uRxEKuHR.f;+l-*NRVTxb-^XhVÉ/xOH5P2hTbd_k)P;k+Y}9T`O';kbs:]EE6{\0E6ےBiwO)TΚWB:{zsYSNᓉ֯h4{i h9E*]o4s&qkyQzQ&Ӳ=bcj?kilJS;2Cn~ʞ@_IyEԼ>KJ֍?Oi2<7uU7dShy3Rߗ|r ;襼(ͷ꫒.k~!4c*9xQE| wp6YW%2KH'KEZ0 Szr1"@7@/:u1`\>'B? 6 6Cuȝ[r{UԤ ;3x,<L٬wp,p9;Yo XF?_ܷ+sFaDi޶gV3}<UgƜ`Q͏^Ugmʀie6зלH%sa}- O`5/eo*C#_mQ qoB30ʓtT"j.>nJ<ѣ}|e&V.ga g48]Vd`9zgB%# EX?׮=s\)fV٨R 8N$tbS*b.PN7l$@2?hݤq O!ѪXlɸbx+_@`Zc]o*$,G+ŖcI[JI29u)*rhLҦir[TZ`QQl=EEjDl }o$mRi:;eyciE"ֹhN>_;]؏ʠdآ̿}tWoqW)*Dxnwြum_|4plHf` :EKh1fj-,^mS:.!)*I ̡CKguO(oOxMvOGξ_ٗE9}htwv; ~޾Eo_ ޾߽n;C}7xD5:޼i!zo;^hɠVI4[$eՒڪ2h=i[mF5_]CÈRg0$0@=M[} 솿s:diS xmeBUa!ڀ_oGdl_I7^ab@;?ؔYe;uR/d$ԺRn'Upj6u2x}Rg1QDfWݵ=M1cާS,Kw9+#3LG,+ЁyPe/}G»PzBHKeł\runqD+;(=-e  0X9ކk6=Ώ,37*ЮEbtr{)s{u!R!uSxU^NdLT+8gS"$7_638TUXP86XH}<#2upaf[[Vh%\edMI'KQ~'?rå]cnr]Op5X數Q%5א~v= C/[u)ȸz QWsTk,$ol?dGRF:POuM˅wT̙0#iM N5b];,_/_0jgs2YZٕ5+9<כ]lMH_q/po-/LRԵrp{PTera[&ν8!fո7|~~/gn_jۿv@}Ԣ4 ?*4k:?:E=^SqфOW =U>=w-XԴ"gY0[NnWo9,co\ɭ˫~-yC:1rrne5%]N?S|_;9./TwK?;ֳ aM^^+<EH8wR^2rǗ!B/,xM Zxyˢ/)[>cO>602Ea,z ͪ1tF!VUC)_]C<-%,co`O;V=0fpec88ݍYY*E+q}*2-*PuAu9X6rS/l}(Sb&Zh,9zPaԲ ix[䥂LOTBT6m+xSܞpjY/ ){W*g 6- Qs /KAHr&& Dl1eaX3R?3͑DX{vk- =<.Wk/>칳._^y2"$t dZCye`EY.)5M XG? rq\ {1i%}giɫϙv?*K+X@;]j갫\c9PvaSmc9m1DzK:Ęfp;YhG6`/b2Y:pCQ3G6Ԁ}21@ +טmwk}_L^[ޢVHRMma_"ZvŕP@b\j F74dK` 7+Y FR e3Π錴CVK_ۿCPhB?#;aAX6+ lò$4JA0lWdc{ɶ8z"`ڻ7VHH| Sjm!A Œxp>@֔+ $U1 u*Tn/e~7PC{Jo{㈏jvx5݌=(^:%2( ؐ3|CX ;@ K56{ |la'sAkS e0Vi)-6JY m5MI4O2I_LrPWOq` +B(A)G,]ԧ)#qjh'/?y29U:i_]ME.NpҁE1EOɁǹL"3%FGù*iKfapeǿBr]:X *\^ x}>]]Y?7dhT "H'-}>pdN:910 ;R>.Zb_t@{FUh#L(w^43v &+aw,:h4#]T'Jكo =x36!B`#\+Y6IgPON"Ϊ-:FфQOPze،: EZ HQVl$WTsAl[ϖ qLO1I8?@3պ'u8M\ wWWXte@Z9ȱ@{OuqN_o z z>}Ԥb"?hKP TXn5,o@DnxXS}, >BDw_Qؓ|{9۩&z4{BVt}LEG\ DZ]NR*%|YA7GGOyb/:uU&&i@n;{}qpb;u5@N5ep+0K^ B^O[?6]aO.r!^Q`EY`v$B",8= غK9 E#:I=2!D\܃:ؤ: ênåNtR`IJK䍇#_ʿS"L8rblil:xHP2Js9Ha}yPؚ[v+//?#XR\`iByd i*H1a.=gt4k >ƼVybQ-B R IWw@'t5%WZHWN[:w%5hK<֤{|dCj*A:SzmzݯjD]r+ۚ_S*=q$Yo_stmgRbXjPYHd m6Mht ujK {$+PhA؎ M%~WV'/2RX[@7MEW"S>G~gg;\C)aAszNeχY,Cg# ӣrVx=lF凾*_4CuŹQK2҇kRYaȼE%"ggˬ4 Cخ0L~# |v|&ԚI m)"=# Elڠ6\m-]CKdv\B{yqW~QM"jR*\aῇ"$:5C&0w+G*bQ31Hͣ_bx (b .~:|Rҙ#"~ѯcMnFEѯ ѯUѯ*1/ѳɰ! V__PZ]f+fz.7*S՚p\ g|H9È3 ,%|kn8_u'{ZҠ&:506FOj+ַzf $$*$ n@`DRk&k+ aQFEaDA=Ep 00ꌊS$ Rں89ߗ:UnsR2C %Rikt\ɞ/4b[?/ 4BvfƁZ4pȘEX5suF>jD@ˎ)+~RݷT;ôU?,I3w|0: `G2 2C*21p(n\feef$WrS= ,G4_(,[Vj7V&̑g%oјG4xl?kIlB:bl5 j%,C:aY_׮]oG$4N‘9s'c̺I!W]:>.ٿ?= ?n*% "AܳZՂ^۴dm{S1Ek#hnfB&U0nR?G3GM<$8Nͺ"̮WE`>!dp×D+` 4_x÷*o }vѥa/n%y^`pId(YA._C0= 쟳пO3\-_ {=akT!eK<ͫ`?h*bQCb3oSA73i𴗶=8]?"C#)LnQHqgHMRn!^ z!߰aoE m Xp0=Zz754Y1?孺=7m'c(809fgbdy`Ju"?ƛ-o]78ÿ c47rR9z[#QiϹW܉_{ȱv3M} e_њ*bζXގPE`_8{qă57|'~h_ay&9n <|>#_xawkX[pgk6?54E_^HR2RX ɿIS! `tGWX+,r829 Qi6f)kk۟̚u:_rY<*9s$폊Y:KCh>Fyz7V#҂-bsONMRATU2$}BjZՆf!X?Bc8TjTK"X5C&L,6HJrԿhM,:o0_~ŖșJM9SeI.vޡ=?LO/W=?D6пu[A7@y@Z'Y4ԿHWW]P2R /DoeDPo|ϩjV5c? Oml3li ߹7?[L_*ie _W@ii{ٷ\#Nj iݣMZ"%cH)Q7<""E*"- xO7$bF͜G3wUipRe^^hQuÓ {*BǗeoZ%9a~0,"ODLyGbZɴ#*S}ă]ah/K=Af7D.kho2?hfH%6J"'Sz=B3TUX*ծv]%[|l<EMjҜs @K+ا^$8V: yEPDVp($E.NpeIf%͈FGO=vm}_?.2O2ny@KA8B[;.J|0AƺZ,ٱYQ`^ !=x4CZctܱ#Gْ)CGӾ/Tmq65'Dze_$}Z mn@+3ϩ'tjݚ- 6ʤ;'w,mnNdրpp=','$I8.*"<+H"<@Јi.vW#{ڑF#jZnvwucuhsɺj+WT@=S}ꝗN4-` À0whT[>j=\aRKS(+O|~ $?}NB_PeVP*σ˼V?juT]}ֽs>^jY̿+_#K6,,~tĜ1-֥ܹ>\ʞ>KƃQ;"h+ HmQ0q9PE'> ->`!Ҷg WiG eGq=HBJށ?0F,52wJ3-y`D7RoGګ%&][ Zo+vY6$gDy.w<#x-q'2bqD,,}/?^V6mGYY)Ai e}vfa0‹ȋ|ޙVlD'y{_&܎'^^M5o; q_&}\n/٫EPX[uTaٱSz`K/G? Hy7H)\.Dp/燃4p'4|?ve~$Ϲkݗ}پc'5R$xxXAJD^&}"55kԠ㧏[˼Ow"xKC;_ѭrB `w WYt.YfeBbX`$IQ`8^b}j 3ٷ9_qv^ /?Rܭbk4 ƪbVW[, V% D #Զk4Bţ׊ vvCz=p~ަq|bȢ#MZA_+:}p WMb,UK_z HHs}qQ,MJB G!FJ24G)#g8ݓ h5leO75l*O.pE&~rّ9ɷfC՚NKqtYۨ 7ltQae[an:tn/M\.5ض}el ^Ғ93nb"a/jYؙ}X6Y[S&%aypKl/m_ Š k8fw>|W p{[0{k DďA< 4c dhā u#/&m~yԏBf;pkMs)m`tm6çtfΜ#ǿHw{3?|ǿ:m]Џo0v0LaD <\zBzxš b)\~ a c>PLZB1 7:mB1yR]nH99T7ޏJمFK7n }Dљw##6_Tjì,tb[.b(StcBn3G7:wK^?"'² #i7r߈@Aa\THZk@ :̪~v +f3nf8H_& XvS#joƬ;.!kAsA՘* e6c?X' 0)*7 &Tx hV3Gh dza/9NI'F:ǩ9Dmkw{[d% ڕWn럧yOp׿,='_? #3CZgTh)aPfj~}Gy?-syX`ϯ]c-( D0+IedM(P cIVGmNߘ>ỷ:r8.:5pʮ_F8PgU4}άۓY)D;{E]wg%֓f{r,qԘ?12G:nHmQ`̠D!ZU5 >\W\AP`ָOSYe݌ XVhR_+@nʥ@S ]Dˬ̊L("!B'@F~? -ۋ^վ3[yG0;[1Ҵ70>}Vn#p :;Væ>3 (#wȨ WwjۃЧ!Kae-°_ E'H^`Csg]=!Ip X> [<߂~Ԗ</#`ٙ#X\)C#~ &2/s=/.t1ɰ4p.Mqi9'yv`' 6V](p<:"}:m^:6uXEKn7[oQm4@Ggg0Kceec~E,`k߻B; |kMyrHZ,':;3$lICe f# wق1 .UxVdrz2Lx1~1s{=~%6U=ԠΊwwKKw.u%~cKi;B!gχr\A(}g!}װ ?qxEyI "/q^chId\X;e 4pchLn50? 4gI* 42Qê9i /z?WI9S2 {P^@gЧF ߐ/Y;lxK՚%Gj9OU0'y%Q,)0 a2VV-cn#jj !:(ęچ xxS&}tw:~| '0xLºm }gED+5UsLڒ$7WVf2BiNFRu[g ı^)cSXϚKNO |V䛡?aMa{|ZAmfM1FCUwɃw.Vu%܂I|CmMiBm0C-uF35*?SDgQ jBo"P]>BJ0G5ގ1;H^Gҥ_qGPz91vcݎB]T ƞmx yYc<~yA={5fydAa lx@e53 2,UY&3 [X5~nUP_Y;7 ܰGN'dk;U@5vܾ_גQvL~vMG&?8?HtPP^e? g>H3ɋ.~Vr?#5fu a@NF|$ b?Y۰5rD, h6I@3wd&U.2kR>PP`0SG&=37(d)xLBkO-o*k~?Qr|Z _[N X:BJ^L&$uR(&̙Yɱ'ܫ'+B\ `W]i{S@o6Fhw;6'u64/ҬKprec}ot|[;ye ˝uGo*B`N4+QĽͧ2q &Xұ$Y br@Ы9?"9"wٰn0٬L)#ā.  !WZ Kp5x"f"i Ećd/āSJHMNm\y_bϯtz{{p^;vH6^t9i$M^ͻֿf";m}_jl^ft; M߻- %(9BaI(V-lUV=e0aλDioQ[Q@ >!m.K^SMNvYY&_D(b?|0+ë Lz2w4aysq9:;#pY &#F.`k+dpR; yViq3:{% ?%: =E5!k9k)"cDds~yˋ^5XN^QM1h_pyE]KKM\wN'Ͱqm=+K ^$_%hnZQ Ɏu.՘ԛE}/My6C?(2 ekw.b "]tGSI.?GhrJh,dVLʖX#0efYxwr?~ɸ&b£?vs_=}?3VZi"[Lm)]}Ш?h 26K ^{4BAKU\B?<)zW\"6wH} 0)Nb)OF h;I>wM:sKD5sKva]A-G[,K.D:]a W|id'tD`Qv--//'I}~$jZEʄů?ʄA럹l`ժCZOr5b:!t 56INJ9ocQI7=ZZ7ˁf3EC:\R/ "+fpz7?M&N/OVJ5Nz$;KPd&3 ) \(zTXz &`sQdߟ'yы+ZTdܚزzw//,6Nb9|@PRW6[#ܪi>>nE `eO(+||`o4[:F8l/ ߭bC x׾aMa{j{}<|C޾(k7Qr66$5,s'ɍ;v[AWƬ?[g .61sX/cQ$ЉJ dO3茩$2,Q.ѭt21{.w9a #%v4k\_}=PB顦 qr5nߴZco=e+V $H:P:AԅC=!UXP>Nf۪-|A >[:4}]LK!Xک ra|;΢f2fm#y"5Dq7np`\6H'9Ep o"tk:eܬ.J%GZ R-XNN-/7|>|-:fIyV|cM`خÌ4-LL6ƋCoMwPOԛb'Jd2 Odݣ[]h˜Ԇ&Ƒrv\ r+&JYs/<\W{I%6Ok}uVV%1'V*Qz/aLa Tv]30¼:~8U`R >UuM;(:̫3]3j7a2efg=+KgI_RO]pL$WR'I7݀lS64`}+tU莿f{-80 ?%IY!a=*u\ Sjs~jU* )0:R;upeGe`X(+,+n;yXDzar]=Vy!!;rY+nfZ=?~uyln!8XsO ##bo_.:'ikb 1Ơ| .Qܡb*ޝ>4NuoMF-q!ҧ §҇w՞SM 1G#bl{z&ڱJAR[R!%u ]ѸLrf,%RHZ EU?V= g .>ސ]ޘ>;ͫ 7 L ;wa/К=׆Y R,< G>٬-ds|S]ȼ8˰d sb_O, Nk;hx"73M\U2$ jSZ2 4;j|*U6' M7,s2T:D>x|\@)[)">$hА&:o܌΄cRk,{UϽ 8->A@ޙAYM3֔$Z̝)V,M u{l/ʭ-݌tmLk{jSLs_sD~Ν{=}]GRx 4R2PTXl1U1Eʠ*^U:juXKOm!SHw]=˽wNuW3qP*K84q A8maa%~6 KJaB&$Ee^oh.OȔFZFU;?bkظQ!!atfVdnR?)Y/¹kWR<#Rn#;r×5f E"PE"K{Oxi4aha6X&-5RzZoVZ3@?i g(w|ċ \furOu7 |~H;ʮqm qgҗO|r% ]}iVx&p=E.=/ū]pUaW=iϻ)犑:kS_ҧ8 s0Pt}pdV}]m>LUr!eN~,RыǠBm ܟ)<PflAGX5ա QGóivJ3SQNڊ2E쿕1yy# M: IB(&~)͎EjMR^ /Qܓv#@b@e%k.mDQ%]hX] K6LQD)q=DeI$n2 ~TzozQSoo$#k*LH805۔9]z?\.ޥD{Xka\=/W_gZufsݬ:h%IAzR:j5A=}$6N8^c@ p0!#{9[ARrޛU pWYsj,@.B4vp[:"Z Ӹa&t"QȄ#N-f]f3X6V06JhLIK)Jo2i k$r<{Љ]\\d$Vګ*860(S|NO&ސ : p7Tbk/rev#i:1P]Gh48H]O>_D! f{ItPaǸAva^U&}Vw|ջ2p+hn81Ld%VHho=:/I뙊MUgP7.Z3JjL)?b{}r'&s,jy8 Aۦ,:벰YhuVOgju:u]bߣo/iSx?isAp>5<$SDO46lGm/:E.ij-K*UKBn/הWLw~L )K-г`g!Oa*-7E d c]UP'MB]Ob+A>,n3y #KV f%rBZ(/ϑwky| E *I Fpxf"`ceH*q/ Yh8.:3HwӭPn1OpA J8n3+`7v9\[1:ӇZs ɹ3A~)yuj~A59_3a[QhZp ߚ`>;7PM1*``:SYo?f *hƙbX5;ϵrU¸0dX.=: %贈qVgI2al'$# eIA IaoʉF́z4\̥2œ·jvNԄi_ިҤAg(Qk0Z5Pf-%6 fsҽגG: p@!!@[+K|Lf!N\`Ջ5GÙlml硪 C|-1o'pnaqv6v lv괡puk=[fs5ù?J43vMK5eYxY=TӭoYhgJVq4zk9Phy` ]UQ"ÞNXF{ha$M((VT,[Tz?=dΦo,(`,0 6%(W_"F ľ;aU' wa7|'W -]U QߜCcM<T@6]uruFEEڣ6^x.\WQOeN}Ə%%͛r9 n.s ̇,LvuOY÷bw;xlma֖Rñ7h4H0!+@a _gz'>v㒯tn ?pMo]mtY _ /!į {Wo ncx̗(]d.ؾN|?_ϠPt4 _OW0'W>;tAwAEj"L{*z?1o?1/ͦzq:* !NɃ>6ث-nAN|kb:3 C_8(_ Y\W/Ox%l&46ZuFHLӔ:VNOUA"j*p,3ARD%  vw39 5j[ W&cb';)^Eպm<rq^LFѥ⼖Qj*?7[)=EZIʤ% ZDOMvRc2+AjH!創.\Zvxߦ3u~y܉lkdgJ(=3$IH'rHzH"AZt0LHB!QH/"뺊˱> B@dE x 譪>'3!7astW}_U}u_;*j_P%,*~>6(hC/X$s`B4ddd 9 #\tZViFi*3,Zuc d+$qahS~&֫ |_w׊)K!I;=&[7|=vI 0&ƹy"hDm#}h;Fj J!3 g[~Di E."2{yqa"wv'tO!aң׳ Ǚܬls8-&#;9d6I4ڋ!鍆EHh؄z4o}{a. 5dWz}d]+ PO?G,еK{lQhx frRQW`Y2x ;&{ա[qz\#Gwm^\K'CBz /˅a䘇`1X'?[홮`pHrW?tn-altn̚Ș V[o5Ymt_k!dw!2[k@g(y*C>jցWk9_T90Mљ 𼍺R%WN<Ӑ{ "xX2)Moݏjimg>5 OCo s}xGӿ<ꏫ?Q/G'2ۨjhx ?YDgO*꿅5:]Fel6msxH12c1;'FoԇdG2w U]bT{>E6E=vƫ^6< /.LTTwt4}]R /]֟$,kjV̺[3ut 잿 xpσOA\QΥ@k!LI)u&M{h4g&cGy #WC УZ>kqijYSBƒ$쳋ȯpB0T_JԂ\{!+ `(VM֬^ZSfѢI99odѯ߿to)8[P:+E,ϗ%b>Ti\/7<}d IU,@/0SDZROrPo~sMΓK%pjqPvra\VY&3-&fLQ/tjCP~,ݐpi0ۨo?=-i*ͺl:goS |J72>ˈͽv*8#+L=vŸ%jh؅?ť!BH ɱENVGE(O<-L-K󕄲7qa7w­PQvA W ;cv;fj7p&i0Ne,zuݝPW3uuy5 ^`/F/cEb,28qju! .CVCAɓVOTu9>C i ȍ:QC/V)Fu0Nj+N@Q!Yff"" a 5J@Ŝӧ| >"9P]4 o5E6朌b&§F/zR2ԇY&qf,GspE>/18JK˿eV7cyeUqxk*4?Pe GlΗ'nvgM3vSoL#Fg=3 4lxϦ'tDKv|!#QgY#:2 ҩ^nn[wcRS>Ǿ(Щ784OpƔ&nu7 sQ+3?:םGZѼ1B?%6Q_ m²&T^K`A|ڷ'_ *$pXԦ ٪" -  j5Gwi_*g^-:\E-.Ә<z>nu*I?wa}j%a~G.cs:cq뷫'zF×kKb%^s2QXwPYz?gg7|ֽ~LzE/zb/Ρuuu+8.߼a?׍+``=d_74 ;KNȄ`XIM PanAф^y$Q!EQ%Tͽ ahSd@gYۑ aX&[of.#r9X1m,0-zd:kb0]"r.;O$E?b³i!.M&h:@;KBT?HF8A"Y ^KDtРEāHQ<&w/YMk Νfb񲂬Ƭ/,߼W97-r݃g阚/ Ϩ6ۺ H(8lWoW(G0`|b35ZY={'z Xb ++@#<{>S%VP̕!T]&5ul$;%."g7*B깨ı f߹t)a9wg^,"Yo5ye}K'҄;.O } 36$ sA*p^3[/j $dׅ(Vz zM9`߁i}<9KHG& 2x>!+6:C^-[(;6#ڪ?.ef-R;kg9zN c#YA-&K"OB_r8 &x!w>H Օ$B*nrgȟ9(NJK T> ]Gz}EslC>DS18iV0bLudXޗO^ e'x74ˣM![A`.~x-E6ozf3w 0}4L/8mYנ?IVO?$ߒ7rLOK?ulaq| g)CaV򘎤=ӮfG3Acn'TI&O,@'VeQCŏŏ4Txreۯ/ :_ml2.sծgNj38NL&kW]$0'ULOyi?^LZ JBfu=:,_J?\: <8źe*~TyR^ʵ#&iYJ`.f49#faw嚫g;-!?Ʈ"rH hV*Ny^Vrax/RriY 5j߿uAfH\Dz< 00pIǑk+Tr%deδkд4Iyn[>=BY `>+y6sRK960q?ҀUՎhy"EzwA>"ȤU>HRa<x8: 8p̟BTN>ː61_PѮE[uxPMBg8QɉOATv&}xS&{VBLJ~~`Y6Gu[j̘̊:QGluJ0E M<ЉJf?yd3E7/wۛ-1{NIs Qv!RSG_!K*M"(3 ^>h} Q)-K@ɞUQ"%?zx{ 䦂#QnWsMybxPK]U3 zt`sP&<-.0|*bOFl|c|>_Ywvpb\ ҡ.r VO$I UR|rؤI h`iczk<?2'7Hj{y<@TΙC)*͂!_Y`^Wg^`$D4n/P0j! n#$$\ӖS1-:Q@<a,ޅ~'!"H&!ARn2O&p>C2Z!2Dl0 $Bg|nI4%.CĆ0fvSq*[l g!Fy|,Eح j y 0,VP; ¥U "bЊ1!fmAp !4dy.ȞW^@{@xTZŒ*dP%!9a;A7sO]Bݭk%,OhGKPJFZ cWJ@+0Qt}g.߄[[D `mKfiCfvs9% Hh> PtK\`0k׻rK&" !qWPjeP~g@ Wjrwx>O&(D*;Dfd2, 1GxHx! (zc9X_<#W^VySҷʺ5W$7b}RCzQḑ 8])scѷnz2rN70)RѢz",;gz]gƽu}‘+?I(_A[r1J, B[)ywJ}t e&CH+ 9Ъ"&F<Șxch]}2 pzsVis7h)u0qbh3B i4#Ī;-x & 9}ʅuZ _B(s/l Ĝ7 Dq>\Vx7dp}~w <ԗSTIڱG@{F?[82A_C.Brqq_elR%?W v{fX\dVg_@Hʹ52;0ۓ%[M\fFߞYV[%{ɓ[ݒi }眻fE Ν{v{Y6BlPuJYeZL֘2IڇSLN0vXx?ǟ$'ڹeAn_`N=A`v(6vO mGx:n&cpikNFZgazRLRtpWq=.'@7 I:.@׺h!@)Fu,N16R+4 %aɩ?iXsC|$3rEea #TJ`J*ѭ ]ؿEgKp٤S3T lY z)7bOCe;p"2쌞sQ<ރs/ e (`d{;JF%L_%XPyQ?Jb/fGa"`78C²W~ $%E&y~$ZNDv@Ny?IDt:~ɶDu*=yMT#pN{,聇v ^?4$¿%b./N!W_"@WD$(NgP*, s tP3n"%s8\]'p>gxPb0 rn/Bs' j\BCA> & iD&Mn"5{ 6l W0+kt^V>)<NH]Btw& ҏƌY3tT_ڱԡ>+e FӫrBҪ CUtUO=VKp=8\V}`-/o@.A4WOū99lN,JM1OS1o=̽g?N|em՜9&Mvƽg;EO\/Nr\q[ou.yY?/ ~+Y(}ڡw{m J GӭIsKMПS^*;#3)R2kT*Ej :JV&}+ɵJ?yms*FZ.N̜1O$E8Hj._9GR3a42 D1dZ1re%,> n˪I[-Ob7-\`o5ّuXp? Ja 45뉱Kݠ١hv(s( đPY=8}d LQ|Jp ,D <_LGAacԩ o?{G8L07s+yŏVjv7A?ԯ GwWO ԳRuxJhA&s*o7Џ8Mj\=̥F 3_(cBUҸ~_Vuchp u :APE5֞mG}E8cs~pnU^f蘱fބB %2ٸ3{d/=j=C<^NtimU_ӃO,HQ6p 4S`pRN{h2hfJ[-yuN#M]1 :yq8tuKS˸eU.W(W(Ŗ1]2ݝL#8}x4g&`/һE2ԱE2.Y'qIrI'Y,>kEMKrb:϶_8N#$x䮎 ?:d2h *ڬ4uZDU:IRI4#wQ]j&Y"8["Ŝ%R1 }In>oT`V(da dAhHLNYt w\}Mԭ&mNe?I?;:Em%EWwhVp[ᮮe\ܩ;I6M-RE+/ HQ;?3G qsss΍ױy篓KV-YdI}R_̢4ߑ:FhѨH MfI-:d1flQere{6>eFng6 "kj9CQeZEE]۴Bz:d"{kF(>?JP->[x!![O!G_-62RDr#GGS[.L"TC_zpOP̿eGZgPjY1k! jRMtz¢02GW;Rn@Kt/{WE{L– a@= 陞 LB}!5pq@|CQ*,"kBU6{2 !,N3鞮8?U@<㕿h1lDZWg}eoPOSqhAG6%%%3?y#'zU3c@eb3 0@TyQeLN?HUf%&6'E5l'ғF5–\BZAgQ0 @D#Og+B%j}T J  %B<} R,P ͆zk{[|]deOj&^.3p&RGU&<7?ﯼvJ;L83j";Aϗu%r| I@uA9/?Ey)!1$\x(:u9?vׇw5" Q~,>P>/Ѧ',vMM:3a#,YoI[ uhupќ'ɀt:Iv7I 20pd<nTP|VQų(G^׌|ŲRDs}хmX?V:i*{,ʈW%i *rPB?3;&3i4FJk,z=A -4MV` .Ԅg-?̌} f·N>y ( #LS f~81 *6A2J6-ɬSb߈}%&E!l68ՊY˷}WոEitw:AO3NH4v6PZ ٖ+}4 R -a|W5U)blMȈE, - ݯm^0eN} ~ 4maxDA%rZAgd=r!a{r(ҚC/'$l;} fy-uڕ.oË w4䠠p=,S\Er&L_b8Ys&UZeVF_?v-b?j^ӅiH֤` S:%,% jjh̠h( _YTd'2Q&X9*t2?Y9׸RjHt8L)}[|ah.("fW3 br`?~r2k\8vZa(v^{|_tMí".W7O# PmXt.sX<@Z;xӕ eÆ &ࣰGdGH+l+*9azUV9 &tf,lXFU4ZbV͈ <4u7ijǦ>d+bIiH%wStbYUdn 96/_< alj P>4DRD85Tei<[@"$H"#CXŠCd3@[a K8^ ٹzn?dR(M~ T­(*UbXm~@L6[v$(T8hٲUElp[X\8:0/2/6?5HMKf'O $_Of:GnYM#+I((.V?IQnMJ.Cyi^jS={?c}`69@U,@Ezj5̵ J]``ᦘ=v MN9 Rk^ Cמw ?ݝUBյ<[aR*w#W#7<HnTLpqM& *U$ Bَ [PbhIWO{cz9*' zy>ɚmHbcO7QmbWkWռ &.f˗{ucձ WEQfWw"~]D# ¾{Bvm*A\SrBo;h{;4ګlig4c&SΜQYP ֱqwU'˟9W=.V99;4Zz}Ci߸4 ١@=CHw8$mxpWq=:LoiP ?]>;~2~9ygdWז%)!/#4~;!O7~#ߜYӉ'*pnQ2Ȅ@L S!*^VOU髉ɠ3LMaQX XNiNyع]߳@i]&S]Fzo܋g$Zy.b||.MqR# .w!A Qū;!-07؃|&j~^ U@QᡱDEE%ː _|ܻ );Q_0O_wыóhʒ7`ѵ I$D~l1 ܜڵ7^ˤ`;r VDg o=GT f Hb3c^|<:8P@u pQ'<4^ǝiqtya拆u h?>5k D9=l+orюmR 95mUPZ=b"g@;Yf}n9rzՉsB!j 3c}_'qn=á*|C})/$Q\rit^gMyE̛'[Q*Zn@/j[Vl3y.i&B3ˬGCC1ibԳ9XyKm%l ̄iR8*+BmO~s\!e8h'2TxE,ZQiQ oC׃pv@.z?K6py QR_'䕏w$O>DRl>^k=A0ޏ)DDnv,&39e 64NR2hIԇf:>C"!WfF&H&z˭ ذwrd3{aK\{op: :#KmxQ[[Zּ,Yܵ/=7kvy¥]X1ϟgc-63gCZh# _fcx>ßeecyo;,b5,k2UԐgͰ$/qu3z4 re5da}4@}׃ ;o72C''sN^oN*/]Ti%cTGG͜{ǟ|;>Qɖ9lGu Tbrz<}VԴ::bqѩ5Pf:4) _=o,d.b O ?dY|b$E'>zfųGd.AA" j0C4vj_SY8e}'ۺf*+6I,,.,}Y3pgB|-ئ!){35)[Es}ϚubL5YJIr59Iy,W~` mWfXrh>jhMze5iVrI}xkQ.M &)51`&pM~ÕP3GLysz1R g@e%v-3;SنLsFb! :xu٠Gf"MmUD꿐&~ AMlsRH|mԑˆ˲}'\ @l,h\'|#iLV=TCxnh! V"COJcEd/b.WOׂf!g0~q@Υ{TFRԬd_^9ӁIӲfoY}%&iTb՝ל^=zp䶍kxЂn:*A '@ ǿ}O3:RMQG/ͷE}luvJmt(rDAimd'wpr=M PvTLy<xɭÌ kCGAyG͉[Z &ʸ`*0 5%ݛJL"$X#f]O#< E$eΨس󊊸[KK42L?P:U>+*gմ3Xwl:vf X0׼M9X X[Dç%hS׽I/Y%oM8f3pC/5&j/VE/N}aPPapXF4 &iʨ7Xiњm6Ylt_څŒ5S,z&JJ%@@"$H"$[PH*] ʸhMC۽^ KjRàОRûڡ!<@y7W; `ňao4MGlh08ii&֒=efZtػz)]HLZ6!BI($9x%*]Xڨ䠳%UA7D v;3/m캗=Q l'M|cH:dKZ:w,qz("Hwm{gJVH0vLB1I-UH"8"Db$U! FqGFA` '0F{*p%Avu:@ (tuwuw?gԃ&t'88\NO Sd\vʎrn5\:/랩HeDX0Cjd\4V%ج&(]ti~👔'?nI8P_QE M! X8"0T{Ю6iq[ēyo:|[ 6?W_{@% NʠVq4hJlBLƩ(wUb&&r A Y`r5fsľ_N7>__/'v|Je Қ8őԞH)$y09$?ωeIA7ւ@7,fcKB)qPS?K Y?0cfpI2J'v$B#e ̷ĵwֿX(%x)/= XR>_ފ,y]_}B/%6&UQ_=BovAxή #51umd\Mkl{?3)͊l>z+c'K96) |־5+#ԗNƮy oYN3ɝos7J=m.p{Iri*bڡd`}Vc;('Xvҷd^։26fK#CYPؑ%zOJ;A2= C$P:uQhB2d(9I~x7C>%k:-'2j}iwoQ(co bS2Hl?ѾC?Fq5cZ|ZM<C}kS?Z!9TVs64z Yڻ#1x ynj˛ ׂޜސ+QѾvy,:w1TE":dkXn1ȇI}:A[xg}ơwC!xxLP <M=g',I()ĥ| PvU4[g?zF\=]oND5urڭ—ZuY2i mAl5Dt%WMw/w~ݲQe2k`Pu~:LQ?gJƍTXj,DJD,{n(HI$xg<İDhuhR p-)hwG aSab?aݦs_vr+++cT$"AmiWҥm9bbm7 y7'wx܇6D^Pԍ Bu@'Pv\-`)v%Ny׎@o~pCԔ^UQz) ޿tȢ[%3/  sHQp{+ Bߙ!}-sfh匳*)# eL T-թ$P}QYc#30`I(I_MTD 8&IRuoR#ˀ}F6co0N/Cn,++tf4T ?\ ћ] ͂T\JOF*jح C{:sL/UIRºN[$r8y(6g$AI1 /ͫz"#y ,)ZqO)w728?بQ(6 QxBЙFb계$$ Pl(o?Ug̕Wi.mSQlR$5Pt$ vhbG *nUeJӑP  ;eU?̋t4|D P7QA?Cϯ#D:HTeB;u~lҁPkJ}jMCJinf-Z @M>|tڈr09^|9L@B> mq/-R/%}l="kH#(#~qĈd*zźHz]ʝx5@H&ɜ3"WWAH]XKvH坑Ln4+(oR`qRقP=Xd_, ~ w r̆ho:hH<οTҪk+/x`_:~Yo00ޘ'r+mݣ 𒵙l#H3CAZ Z$8ZkTV:||hN<4~ypm.?Rb}VB<~^8~h\\$ {]?(!-K5Yhb҃=@@G`́PӀh?@bT"&ă\AwO @ R.nb78#;/n^?MrC8MkoJ{iQ\ HWg6U C=CB"<BBjH^[#9 #7Az?, mɿNFRʿ?7]\}ɿD(8WE&~x00˿a"֕?ss:z?5-c_U_NC0oֵdfffWʗFcƔIglok[?!V~Rm2m} yd5T"4@9 "QS_ P3S0e CPb/MߚN$N}^?ݒ-y>V)zhf -.🬉c_P -xiFǵf_^gkɅt IP5x!@F Y(]iz}Rv v8vL RIPiЎkǵvZ-"<MCtS*i#їP;.}P,@ԤJ|tQ͆'n葢I'9?ĬrZs2[_HQINEt{X/f]$OV #^ݭ6 u!/Ҩ]y`$p׾ز#TWc4 4N0Gï@#-Zw$Rm'ϙƀ&+nZe3~i,|bi˧=cgZ/v9Afq ^$K<-:'"{][)Wo eaF@u_#bv1ȧF86p9.N]} 0? j{(ṡZ#2h!V՞>45aynr4tF3C`鮔iCZC ao!pXXhɍWrt#֮K߳x69CTMjuz̝ϋ s6^=stթ@Xg-yu{ׂj ڞdU^`r' 7Ҹou.H@3r@Ѽ$#}"M(.2T(gh>!,y2x}(82 Ng pPV'9YM ]+x[ 3UV)˿SuNXH9Buw]5E2,/7y}2^u::S! +e?+f!M6Tv$]KsV˕lG.X ?'>k"C&Ey󋢏М(zܒ0YDCdNZ0ᗩn}aE1 {{7+ިE4CR!Vv.R~H07 (742|FgVz3fNxL ?N,!悻ݢ9;wf pM:M:M:[M:?&@>K:ȉJ=O:_]kYwʦksL9rS˻>%p"=a<72ND aVWUGV$/FU.BY> .L|P^}G=y ;A=gp'] 1}j}?wp!!B3TӀc՚I+!S+/gVw@bjўG_x2 l> 9Rł5%J‚ָE3׽aֿ%H_yc="Ef<YVfONv/bYhNTPkVp"vz}MkgPĐ|L */Gƶ P( h5GVb< ۬ckҁ⶜VX 1U_ANғ=9\_Y+6#x.p3l5S@.6^4N7;@p6? kGeea?~.8`k(0" l~F{y6>y&\N`,՚wzm9MXx޲CE_]/<#FXljxퟰikawL( Ik_|ݭW)Iꛡ헴'|4&@[tY]Gp L֛[[fV+Xqwyԩȇz7KD5Ӈ9a4PmOf:X/㔟ҷd'nw3>/p>$~t.a=[JB a`gXvkWe4WU6<إA>"z_-|p HʁS_dZؿ9^5?ƺ*GVH )`GhI w{{z2[4ѬK87'r,+Q>1-ncXJO? ¾  !iW x`p?Zx)(٦hZoXbB4**٧PU>KQ QhD(k% 5(Ŗ"xԪ3?B'-yl%?^ёK]]Yὴ\"-?IW''Tc^C} l C;D܀Ҧ73wIڦr~m{ܙsΜ3g'$@.c'DC)xHc zzLxC0U<皱oڥg꠿R!k^SFU?q¸$*^mmu)._MW=r(\UI8d৥Fs4NTƅ5~b8Dz UϲH9/ǷV4ZV,]zn1Zl]Mil_3EEIc'--*J^xJR1( iILNψuVjZP{ۡK:B0 K_dXO`N;A@&ҢB8g~H 5Y-QOPw*@;=suaqja4_~.JAK-iQ3ˏR2eî;AED(ޖ5b4s4X("@#N4߿mDaR7~y2 ?G7=>TBm/rJX(9V{PBN7j{͜eݫ[nJ)&KQ푨ު\` Jy7I\[la~ltI/6$,97l9ŭ!Qr1zƏ^B)΢fu] ;xNyJ]2w%]KC n]CG-(kczp~oo^*snjجʽZW@R/WCoj}r2 d;:YH|Qp킽b=l5F#=}<2Tstj,*YS483ֽiPjb#|FqՓ'WL0.1JBM|CE(B:Ѯewk1Cn9KC~Na<+\D1tzDJX/K{Y={!$hFH&$${JO!UW TSPb>>+K)l6Y@<:o{Q[F !1"@"+B.@N`zL$do$ma-2XʥBěna# CN͛觧A*R%r*w?{uTu#2E2b83C btjaG|/:1<4> 70\U%Jn{e X2A@A@fXM \F ԪTzƦ+^=P].|oJCwDA;#Gr^7CZ4uߊUd^)~}2U<Xd ͩT-b 36 O(#?TVJLKWrn{ޚzH'zDeL+l=uzB޷f$#bUYaA-Z<(T/e],˭P-BQ*&[wꝵm3M+Mye kUL>5JJ5jw8*Rab+T9𼱂d} 9k~/m^biXw1`} "jZ,!3)xS>zMC3> 4!iLU2Mq41<$&1 $8/&4aҘ&Oc:4n⇈"K߻:ԉ\D U@Cv?R]א/|4suN6?Y K5鼻 ;06&u!Ո05151~LpC{Y'&Hߵ& Ӭ{z3gv[9aQotVSsV4^_+B l5#g~B<ܑ `#Q97s<ܮ!tLo{K=/?e S&CPirG{/iM)"O>s#-.ϼ;G24}S&=7]5gդt :(!6`}kkղc,צub;)N:= ʆ%?ц5®}_T] gw'xMY@??- ayg7Za-'.!!^C'0VFã,&81buVU7`']V3Nw˨|AֽBrqָd t4fE1$tQ&0aq$B,{а SU] B)2]ު5u2;zYnaj IDz>?xz|?QDڟ~khԗ벲ʏH/ven]jl_-hr.B ҿNn߅i놉Ly)ȧBjx_ְxLk(Qd`ⳉf4?1Xåg~At[KmVx>,OJ^VB/:xx\&h;.<MFi+bj7D^WAM f m6CcQJk(ig>xjQB2ĎZx ]W| ($\qkiD2ւ}B_w q!B}KwPP#G;A/u|m)8sX p6x4lv;Iq9-w]3j"t ;Gk)ghW񩺖`NV_r)bEnc7yӄ9B=DxvLz&\H;|gUhpCdwJRFk➙gDXh#U/:7Kup$J,Y8}ԊFnSg Ϟ)|䕀q+SS#S< <5(TҽLM,eB+^tURUk>p G똶"Mн$e3GBQ$2dpDjΩ$ψYv@)2lIb>WjIwh:^ׄrS5p^rG eT m㱎HhcEQ]ꄠyNũp1ɟق'}faxŠ.m\=#X)"r$k8yו"~\H@vaȞXh}V$iR韟)\7s]in(BD~mw.yz'E |QI^81̪lEs|z}D(pyObi =>ozuzʷ =5 !{*OKYߧY'H[`o *CCREtN=Y}IFni5(!!aDi"4c'ε{=1W1%DGt` V W/x-Ov4 t:.x^Z'[''ʗ=PHkyIwB%nϧx-'Y8vzG\|H jU'RAU^~|o4Y RB$yWʮ6D9+$u,f٣}N#Ծ$_{f:Ig$g3N,A!ɗ|[6Pi`L׮ɑ b!ȭ "/ȅ n/vV甶M$MEZx\Ao?e],zhUhS$~D<н5x5LZ3D ^%MhAw ɠm#<, {ZrIAa ]͋4QƩ y䂦V%?Vl?<*[^!£C@BWMdE`'TuUC;@Ԡ#:"ay*8 .Ȩ((#D6 ]l3SrO{{9瞣ɕiԋ2;e8QPuGV;Giݡ٠:bqߚS8[#['tvUh* U᳼g֡J:qoOMH~+RC=/L72қmF(m934p͕ ?PVk;$ w%erk̸j~C1_ę!K _L5m-Xßчl$ŨI!?| 6zm/ԢB~… sQ!y+4!Á< oc`VUT7G]Xp]K=_ +/P(眜nֈܥwQ&'Y=;6OŗGhm/QЫO[?POB)r$٣f_W}lV;_78?SfMkLj?t ?~t1c6ĿB95A_J!ц_ooo!,C C_u;z48Jw9 NS(pcء v^%k7п=ȿ q~vf z~_eQڳO^ tS2H@ ?Vj ?~G/#poķ#m%K#G c@)"+@ ~D7} ~,j~P? z `yi!UbgC>H9x& $-~l͛B0}9n?֢'D^l<'Ja_Po;0?δk}r;Ҁ#p&ҼNOc]$5~?M˲)D~R@ :X~lA~A;<|Foe4aKM,?p|4sPH"-'9S!}.!ƹR 8C{U5 bA {nP nv(repv㬴F9MY/f}x)$-iUKZ\op:t,vc2fZ AWx^ 3?SŜP3 2A-%k_/zmhzM58MUӹJ Du*K|\ډ}րv"~1_.Kll[ZF]b=[ Q=͞ H*-U]uGۼk]!߹d,*Hf;yZҭG~o d._|rw"dInX M31&5,F~ai mglzURv;e9#skF>0wG H~qKyh kP Zndh]/~`2pBP]^mZm FvGXy~Ńۯr{UO[b]0BʿeNʨv3MA KY(e;)7AF9,AҦ^.*?=q`qV@]X[ I K@ H~W}/};SƶߒT@վ<ڴ|+Y1zofԞ#9@ޅXҬ3RmAx B7^5Q%|iJCZOuǔxދ3nQWKծ '1t Y'eM4r[;$"b~Me`6}C/"1tO,[># FJVw~Xr%|5d uA5̾}垴@A]pPD[=Jw]"͝l8 r/28R^Dzu͏͓>@f< |;/lX{F W6USJa_* MMr禛P%kj`ieGv(~Y (4\3 sH+#R;zee]ñ H"Azv ơ) V1Ռw!pLWʊ=>gWsXpL\:efcl/.sndXVl^'7"Y3['2޽n+SX}2Zi[{^ˑN$u@6HVb8g[[W9t{֖$%LWC!?hbg(l5;m ~.i2qfř g1X }8O-^;H@9 &aS/MnPFkde& @qIJg?sUA\[9L̝e']$wl_vBYʖ@6 (/:;M(HwFta]]{7[~ϭڴE4ˮG]8}m Rb掞$ztOU;vϔn]S^C#^A@qi;7l(ѝsaV,@[ef^OSmGMʋb!Pdtx\7%pMn" S;v\6,#pժgGGL4 Vv &_s)0*tVMc k0wQ/ C.QE4SxY޺l SzA gzD*֚M] ꔿ ,]y]ockz?,>Gs(O[@"u],Q!h:H[L+YkG.r#7LM16Ub-sHzhWm K]0^v ?ןڿnjV}'9WC {Sn ,  }JGGZ@i;TUࠕ$Q-Gk?nL7i@2.,i_F戺zj5IG,2-IU'g[{!Js&Lo([-n‡jqo!m IRY$~$quFdb]&Knbv 'MuʨEU8uQ))XJҰ\4*?[ߨIt#?#G H?uNmZ|X+j;Sscx(>&pҷONYBMRt4SS/;[L)W>Z#pTߋ/],C?{E  vBߧ%8lȄ~102. ҪA/OR] X~bh  ;Ih^幼>) x"4u r"Ps&GJ.Hд-ٝ 7B}VKhkCq{'=1IX?~R|=_=w<Ҩ|'Nxza Z`r;DbK|ʊ|DKb"]GeZx M3O  Tef6aheH{ቿX`DE.''E|}Py(-R52qE@Q 0K,#D)"JBRnUulqKoS{ιX)c(b)q0.IG281_]!qKw.!-PhzK ?7ex}[/͒P~ k\&RYhs eʍkwZ@a4dFY-x殳+5F@~&&b7 U˧!L'%e&UsOD +k?cJ_q>T5UNttGYΆ?˵(*vi CCIev͂΁5q}#"DmWB:ue*_>`5S}7;;Q kw9f Lm.8h%\7N[ Pti73C&,tf; N?k\,&IcJWO􊗱s@+?Yn @| ^gs#uB OՕo?F(6p[qn'إUhEZv iΖl&P>]-/@H!wTzL?ACcQ"M}H+wL4_1ƙE:ʏL؄tbߚ\Ʊ"b{Lǐ' OeWRgAW#ƈGD.^l.9ht^jѴ;"q(.0P柱̃h>v2/rk =ke/L FYڥhU]QB T^72"C̝NRKM13I0dI)8[Obvo$Νۓreyu\V]4#Gz>afc$QIHXˍ׏|CS$xqQT2I_;xffh,c݅{ӝX\TCX6h*!?Y*r%Y⒧ܛYnw`w +69ekZLOE.r\/7ўY~~ǚ_z~oRp_O^{ڟZ]Hퟟ_pbg?<3T/LZMˇNmζ [-)5jjU{V;LiЂ?c^Gi|ۿ_Am$m-+* ĺt7jV @-+aun[ Ն pжͰV(wJd7gPaOG; Ixoe0tRqO sncnKЄ"`1<#B1?/#urR"5 Es-KG=Y |~ai>VaHXoҦA^yAzg#3y>p|h}#Gf竤77 WXnpK?m,s4wx7v!\8e2D4K hNѤaQ2د/{wi+:I^-5j9=x(0K P^L6{R qA gP*Zk9s LߣqF̩N5DĚbҘcp? 5L?e DbyQ<_C<Փ{zx_'|heT=7gke<%'. BgY(Ͳt# Z'RcCjM.npQn v rQpʲf8;8ި?;KHm՗M?T]KuV&MO*lܳ8wk"uص {ݴBrwfE7(ѽ~eL4Ÿ;Mƭe?Γؙ{B&M{sĄSqs K)>siω8 }vĢ7\Q4!#◥h8ߺuOZ+D<&B%W+Zx쓖`dҩ!͊xHҩ(_/τ!r~l?r~lLD:> 7S|\r,~؇ 0}"al6 9}-wU y%]]vptP_&Z˛ƲI! !j FyzpЄgWSy^nW]L>-`PS\F]YWY:ߑOsK>;?~EE;TvoY%8-L1/4Q=@=`륵MCmk KCyOkӪX+WZ8nf8 S8:Z_]?'ژ hStP2Vfd@1秊3A'lQ<1hN BmTj'x-K~nvS+ovfH/emVf#E[( H}#-(;KHZ Qk)GnGg7tFBvՊ-ͰF &(Ԝu NViY?]_=9B"+؈vt+4hx0EKVvKv{O 'Q*_.xDlFxzxxxXwU[7&\!H// Cǽ[oۃT$Q #L-` s{B!LguJ!$cY_7?őF[)hcLBy9!f@D`UC0OQ{DQj(ɪin`\/)bcRp-hŪAr !]Jq# -zJ="l R z0[Pv 7)<%JoXWTQ彋:hEZ))}骱1㖏N)G>1='bЌԍ}fE\>݌ *_P3;Z[u`6\za5Y_q4?&ogAx3wRF|TG&܈t>M,//HP@Fxer lGa:$?o^"+caDQ-a?d Ju:pxigk 4Z"hj=UK|YKoVu3ԓ!d~ѩ7߀a(V=D g91gM;R5!-w=jKIRzc+:kDx\4HAeMR7uS7uo:iRuQK:IitUq; $pT_s"rwX[r7+@sP*PTUxRNNys57 Ro%R6~9 0t/?C>L.X׷_]áttFVw/ՕXݭ_pt=XW+-Yn[ mm?m<xx.Ft< SZo)ߧk*cDFԺ~QF(|ny͛Obx%ϵ>ᐌ [1 >BȦuO>YgXOc9b>6$ƑG}EID‹yot$ {O? 7=}(Eض̭Cf櫊NrN^8iKEƘevMG;'+珌|$w'sar[;FqH7x!v] +S}G=1zz˪9g_w9o;:X[iXBSSV|5;+)%hҾЮ݆/}ZQÚ:XH}xW|n_?K6wV0%..ゅY`it]G;6jwu iFh0)χA~YC7\:A2bL}{ϩu7LCơFMa邯סOXIuJzKa̒= P"}EY9%U Um`ЕB*޳@7Ue{rmЖUSJiJKƾ:@or4RUq^Uς22OȚa9'( H)yMBg |nr{TY AD3P#;6?ַ [C Ǘ"<~(&MPR>u Gam.\fxgɳcvnj"yj}R\RBZ? &FP_!ͤNE5kw;U]Ow*{l}m)]Ÿ~>?u⒦Y: ?n?#qrGlcA<{x:ڊ$ *1 D cxo)*-c՞d"}̀an _rd}LjkJ17$_},^}>ߏ[\˵ HW?g}c˶Iض1w T6@Y2ji{/N^޸O.q5)Vt\y Ek ; T:CU\l5 r ~/akY eǍC^NM܉b!;6qAq1gHo~o庱g3MUˋnQ+߫? s> ;vzƴ<|N]4ء/$Mx .t9S*N/¿9_\:jኝկYȶ/Oe/G)͒"wG;sub.`|q͸Yg3\Oo~ն02n-xYqӞoj- S?YvH߉ ?88neB@-{s?s/gNڧ{Qe? "Tk'ۚݫOr?s꿧apH{)::}HDB7Ṏq_V oܑo|sƃy-N!A? ҍ/(E:`>VR;B,:R(D =.يnԒ" nZ4ʙs[7: X dVq +X?hhfq)_aZ49>cKvn>$9/BHH҅{9Wx !s"OBN2\ɜgm1 #PcR5МEä۹d c>0,ra &.Y}X(r-0ԅ{ g-N,f(/*0Bm(Mu=M`t! eAƬ=OFQ wIwOH+sw+K N$I ½45lv|ج $ W_]ƺuDI TT޴)t ib{*)Lq)p崜UII(3 JTЍa3և'T +||+jFOFήr< Pd4!'19oag="#oW=7jXҚI33jGAԈ&O'BN~1%?&{ӦMNm5AƗ; S@t&^.OTA33@+]5>+ZK.?>u*Bg0 "ׯ򽝍%nO #'{<0f]3#p-klpqOR:2n5b^b%2/|&l!a]L~sFj![fSAWTY_)p]m)6OnKs /MȎJ0}% f8ӔI.Y2͞Z[ܚv_'2 '=/c Z@*.*`#E:7[UZKB[U)&@g|chT 74uYch=T7tE)ډ/C_mDfaLx ޷o|Gɚ?OWHl$~ @hIRPº"-]wDSMesP,aCKl>oÏ[ZC~Ӥ%1EՆsjC0~a|` MDCF aQw~NKSxhc2:Ym3 0WcF4.Q .)_+1U+0>!X#-+ h_ m2<7m8-=:Jj$BgJňAar1E279^=H4F+e9NQ#߽@f34s@m{V͆|$t@^\f;b1݃Bf1tR gpRm{2 FΥ=y^8_¶ {t>lT''Y#ft/}$s1Y?%WJP2v.h98]"cn/pp~Y["i]z⿯$k"%DD`F&e]=nMatfF[ěucZXN/N _uZ5Q^c$Ę(C٤.رL4{]6 Ɍ&ጦe32# FYU>33;0IN:QzyJA/SIr:ی[N22 cjLb04_3EEkeACQ; ''$$Z e-z@ I|,]LJqf%a4bRv~Z8 u73ҮBN?J~ؐF$d$]!״5sٷ)^'H ܋v dSL$Jsǂ27b1cÄ4,r}0"w,&HaT22@6@&>KIԙgBlo< J/SxD?ؘK~s:"'z0Z'ryJ`/|o=8ᮩ~ym9⒌G. HW} wS@]XJ,3td]A#lJRW1"X㱥UKLٟtia9䒬jXd~d5%"dŬ`x='f8$ ON8n  Fȥ ȓhp#Rr0JXꆃ6lACɒ,4B75耴~.lXMO1K3Հr=wy܎~[zI eTͫ94~m@W-`Cf^&)/>jJ[V\~g1N>O<Ɂ^ o2_ͳ\f1ь6qYnˤ5u4Bť!}e|#-w@Y?Ug?{hH0ޤh>4]Ed:΀fad#$z-\i,0 ȫ`1~q?^|6~pPq^/i咐GMDb3\jK($DznoL#$:@\.\Zb/\8;{7! G*LinkJ_LRP{|LO3ޕ7Ue4bi i˞"EAN%%ئ$"uJePVqAqRܰ@EP}߽-ItJYA򒾼{v{WF稤ٷ=k}Sw =V2v; Zy[_$?yeG׉TzH6ZiVhh0Za(UeF\oZP(_Z^yw_.8v-I*G@=AX Ycv'!WW%'( _<f I2lM=Wў7ymUkt6Fv jh MFfdZWi_z7ۂxy.=d #9D|VFfaUoB6/xĥZ:pl3^fهO3:M5]7-j՚6TX2?HSW)M٫ޑiemQV0Z&g5V[(ZojbdE7+ad~#߅"اT*`r&PtBt9a_pK!O8.h?'&?ɠh%y%2JJrwm"#'?GJt./fBDgD @ Tܳ vU5%7ݡxӴ\}Q%7BC~FNN(Qk9Ӧ9d (Uh3aC'o):0o2|%a>p ]r~&ig I7ʌ:#lHDAySOuII->:v܎\r.}+`-R-\0o*sY4}&a2ndZ@;/pN^@;z= Y &D^ w Z'*#sCЎSb^n/vךA;D^?v:U1!VBW#7 YL!x[d!w^^hkn/bm,2 D-(_Y/3GZp9>GZBLDA䉀f}I𕭫[̩ڌS(Zo2jVG *EG6Q&BOJV_ڄ$#d2U2B%#$oh<>o*ݢ3KB\EG7!-%pX JwKARGn9Dž@:q4޲8˻CR#d wۻ!$˻e'_߻!KuK )KÃQ#D2BmiTi75~UluGL5spoĻD6a)=wLsUĻ}x+= チw[еO9sI{ YQU>}Sճff X[?,]L?yUlMe D,jF˲j#mUl*QI~6!iy3<`iyQZ:"@}%Q'r'Z Bܢ^UP_Gp\Ģ%K0M< k0stįT `OhR#X9N#єoYQׄ!1A\k+lDGYwZQ-kw9%>9R[<$8z mXtFM;.t9W#8s9.ORɎJѨP FC Op]vauOO1`= o>,_UW6{0K;lyto;]a;$̺UBS困Yۨ<"uX|9XtIȏHxӽ'"cpdi1]!^ +o2ryd~3n C]Tf3q81`񺡪,c0A=,vuDjVε8׸GhqHU|z }=z4..^*[8*$Ċq)vPt褟q O~;CG9|FBa2sd.2#6Qb5ÿnwˋ!;ӣ;DpZx򏈟q<4 #@"+++3 SxH‘{WY (X4;<-N!LSd-]8/mX)d u!)4&/14DqHj'hj!CΤ|و\$ c2 2DYkmlGV r{wqLVP3v7Fg B/mC.]X-9uσ:l|!KMnixG>Hvwd"Ԑ*'<_ѽS//)+yKto* Mq7èΪ\eKG=ФȆd|sk孛d [&jiX{ofo\32NP=Un$6TMav?H,z(n(=_1aXf#QU$_p)=^4Kk{}C8 op$><QOp&џYu'JĩOj.Gk?&74s-|kArv!A ^ܻ$X{XX N#P=J%V5˅6TU2ǜ! D ך gdˤIUUra΢ V4 oC)7Ha0.Sl"67m5e`aqF)q`8UV*c)u2~ AsFo [9ǎ?}DyyyԂ+J_lՖ-0Ʃv:xOD+NɄ,M]y׼)EQx ՗#J1%;g~nݾ:)p,,4i_4ޓ˧(EJeB% 7& I({K٫_>o2r"w T?S=8FArvk b{uH>PŇԄhEĖu]C]'E=g0)*SV~P7Dt`+탏(Ec^]koCLtL\Xv>BлDB+U ⥀75}?ȵb?B4m:=H;t}^CgTy6(Y쁽86P(s5,tAnYWaH" 63Ͻ1'e^<=:e\OC4!Oّv:ҁ|kh7D "|4ND.=\H=#=+tT8X縅и*i5~k R _t&W^X>@aԺY?_+f(G"6rh773ë: 6qywڢ|#5e;7>-]bQv^[9ۮ#pm\S--qA+Ėވ]g㠝$ڼSA z=ϊ}.k׈҄_={!dS&ym{) 7HRA5s#&ד^sk[3s nϟleIcU Qu9Wrm3Fsa-_ ;]_+ ʺ<}n5O%79v5aNplvaƍ^nno{N}{ǥӳ]In;7 "nHjquΥ'S~LBd9㦢_s[,w!DQ l ;>Hv(I>XĆgEi@ɘ-&:遝[9cu/JybCX:yGky5~+{Z^*I1ȊI=4*1XMZVFʠV ʚzhԾmASO]*-HKk]ayĽ/>xΔqoJ)oDinKk=/׼X+kʼPsu`(Dĵ{l]S*nX5+{8KR3*L?8Q=@y :+~"!CF |ڬB{tJݛͻT*AKja,Va- g!8r\lޔI}lD*?1\ b5D9Zh!eʇG-wbG \5;c@aǮڰ$H 0]%P5 pD89] P^qwC\>2?>znKZh# r22?TlpEF1h BH#j/߂z<pJMZg5tZ+Q:aXF, ըL6#hVgi}- W'PMU;v7㓱f wlshuGD"#25l p9%/YY°),Y Zo;m_$,Az.^PQ@~a]!ʇoJJ?֕j9ik_FgcYm& m3 zbS?{TWNZ@I>ғxbW͊)qy-JzkKթ->u!΀fSo/:)ߝ$ 2GhR *Bޤ84˻Aƚ%qu&˻Ü"z۴M YHDiKJFlHz\>2)'4U% ^x/m"66L|,JWjtTƑRH-,$*778g#U$ bEfA8bxiZwx[/ Ĝl&E믚!!\{nWe V\ g6Fn3[my`vsv6Lf 8l (hȪ*A%uxPgoK%jDU T5=%_҃ʂ L!!@2OhO׎k4Ali/󟳹F4͜eymal.:mlpqf7o݃G3>ߐ23bPr(d"Ǻ)pmY4Empjgύ%ƇS wPNzV@ bP BF8- *"*(G8 ˀ1bN1ьʢ Zhg1n` }C"w([єS%Bt e5+]vI(T`6NZ# . M+>2*讇 Nj , fBqbt% ½C2j8'w!Lw0a&v⟺k07;$z*j=m&|H().RA7Wt?w:z\³ܘt$ Pq!@Ȕ Fyut0mK^Azq7, `Fk>nw虷;YfuZvk364/C" k,iZFt_jxk` P*V-~SH;H Q *P:CceQf\pn#PW5 0OÇs} 7yխ0 @z'(Y ϊjShVtEqg-䪟{МǹಲfxCtӨ96|Z@Q?V ﮙ;ݰcH$hOͼg,V:ma!&\fGXDodϑW2N.FC/hz8rO"v {߈3_ =!q]j_(Ĩ)ǔ8Z|6e)վ*V8߸Ca½T3GJW9gbo•cR&ͽu?aDp%%7[c*ڿ' m\ډ zoaʙ\[?HqM]yK2Bv@]so'wTVd<*oUJRPiBTQY$Ɲ4%5޴HGPy4m~!/f6uyܞS>Wx?lF>z͎u["w}{6a'{[{wOO~sJ>W?7nitx& g>+ZtU胄pDtp߆aoHbJM}CjQ D] `|u8g GxσDU~;_?J&(ѷBg<JuY(@qG"N]OiaV-Rwx@hb-R( *tw8mP= ωʢocWVMѾ5">RjL$,[Jr5B\#L iUJ#!/GU?&t熇 BZ]˫@69%:ߡ'P׵kEwi1w8ɋ,B*!y@/Qa^HK7ԸnX~!DŽ?0Րثt?l{AZ-w ~ead_VoD] K&~t1OᙸY@JMc Vo-p!iAQ v[1z9]]g|ƾUԠ9CĿ~Ӓ9]`?e='O~; أREo@P,-ԃZJ꩑ml_h,n>-kdzZ:#{䔗`*cBat}gޙAAC-XKX96ܦgkyW G @lA (GO|~߼PһWNV$3W5B(eO| Xk|e5wzzC_^9ޒq `i|;oln) H ߫뺷 !FG&kuFBWɱ_w3 >HR Y3?Oƃ??kWQx|ǁnap=V?%[2]sh2)W\qThuC ( i&Umv?OoZ-)|M7RRa{_#f Pt7{{x)Wov|a8 -_)!kJqM>鿫1+( /9,>'^~ mIRPOοEG~.5*ylv3kJ\pC8? [ ^$eCs4:?$!|hBɳ`?v5!6^5Xp+Ǚ_O*5fm|y-kͽɏު}[TO%':aD2`':z뿀[_ ޙ!ݿˡ/G>S57/=G c=ݟsmHpԅ~Wvϊ35K`QCoΡ]MӓQiBQ=4=8~]Tk"W;KK67"MU(א$oen.h伍I]g` kЋ^Qҥ"<Ĵ?fl< TTyk]=Վe0,C.MVuLvhn32N[lF؍6JK-c翴4=$r- ]92>>+Us8 NGSqd':3a_ tĜw뮪}t)#]24E9XeX.Q"?i v[YJ&7m6mw2nn6<20aQ@@_P (JZǎ87D뒓4DYG7Lc0OаՄ0! O=ƣ?J Ec*,=C[lĆf"x) oCW2;4g ϴ\u;tM)C/sS(xd;kk":!9UxP.[ ;N~w'g3}|.3$= =$e*LK*}P)rN);u2<('-r W߭p 2 ϰSHD8lgNk&Mf䢍weg?FV4Ac?--͇.b&bk.l8w$U pk*,=S.$U)r/gYj:u&h:?ǖI:b#3+fI79 U\Y3;`{Ψݘ=a|l+JH!rI] pQBNH  a.AG]qёE+ 8;0G@{}o{߫6B>rnGp%]9ҵ 3敟>aG 2'pR\/+LY_5c=tuj'TA޹ w~CU3Lݤt߮SR f_=vk-+{k _-}Y'n6L{~llkz|_׼|ƈI3{uۑޤ"r|2?k+=]cn~>>?EBӂȓKbݼ)p +"+H2Ehd]X4mP ︠I͚|<x"}R#} H-\RT W;AA~ygs497K`v晗 DBD1|?  ʈ zB(kG?YSҨ&;A;ؽ5浢J,ar{$%nr RYQq)ƥYc FtWվh6݈X#@\Y"bN[Б|r Kk9k`ЊwTC/RE# [֒6/O;_sЖl 7e-Fnfr-J7}͉_CYU<.Ȋ KnF,0+vie%a6+30ͯ8IS̨\36 rba ҎYF/yk9mΡ5k ; K1|!U䌟V~fbǙ8<`CIa}ʵfG"2nÝs2c{2_ic"Ҟ?(GGbP:2&z (0l*l~ƇӦz)/[V}:_]_WGIb):יy_|hԀ:.QIZtKKWHYaHe"(4ë2 Pt3]?M'a&^f۲ܝ|v,$`IV(QDHFdWO.H%0 O`*hI0RZ>NJ?@O`-4w2o}\>&wz_ ɸL y,ZgrvC1CgvHD8Mӵ,/<ÈH*xsC9@KFo5 XkSP*zIk|UCRtZh1΁8͔66_|s(ZA.}$;Oy#vǂGf]+is{l#ww?:Μ dBK2:KDƆ涘8# `M ߨ*Ta- [-3avG͎H+ּzjw?qy4fI7C]gXٍXaIBOO>v(/ ā;d̔oL ֽ%Zc'sʠbɟlsiᤦ&8ɕ뚕DBFdTJsURpύd{{Ί- g|V*͕gZsZ=O@!QY_qycWf"9%ebȻ19lӭ:23ylT?ҨyuOW&v@bH3򉟤aϛĠEoHtgQsnKAIcAFlMwtgp 2 !;aeKUMlDyvB! #!A;>72$_}K]_.^|c(T;EP W,^~_ЇNٗpK>e1}d! gbD8@^`}OΌ? 6ؘ:r7Yzcc-1w.TXË8ߗIFbДxA`YHF>$X w%X'e$Zx6؄[{v~?Oza@[>ε5T9+ M #߿>` K2lm̯|I]'p] G@T `Tg||>;h -0""Ȳaz*0&NSD6g`&qk֝V_p rnTFHaDiCnie g-?>AqK^+y#ԪojRʠ`㚏"ԯ4ĭ>_j:r%#RM+@um9&P6hȗɉY*<.4zկ]\^^?-nHYtIYhҼ=2,2OQz1xob`2@ j0s4Xi:op ^Cj+\5p6O[[Xfbܥ5d 'fi-r}ի$i Zy::z. L ghR\"݂gHdA!) 1,iY"!`lL^e&}:A=HEvdjI}/ߡ 6M4MM I,Ͻ%I9F:/zW$lj5X8@|%I6- "LHhÊ4moܜ͛LE@znZkO9:Sٹާ? NPh^t ݔX7pI7)2FPKr8\֛:d/r3!&uDv5G0q~ȸ̦>X AI,'\F&kI6ABIG:P~ 8C%v0>a^ ªP,RʌB )S2E)E (pX%?96VX⼤-s2g̷H "0cNHigBefyRAi=?xi;/ ֑qN銿xۄ )Sum ]oz F Gu &B+C kqueOIDUBtϹ栀&Q" xu8韱L`MYZLHiG_P1~-wgCy]0s&>PT?@RڳPCOMF"Mۈ܄֣(iВ#vuu]]]kG`mc󳎙V_ZYdϊ"C+.Ju-P$Dr!18[yW'.~ Wn ?;_EEi?; i`@F|iM@ m>>I =n&jH?~}6gךx>:Pt cϾuC0nFq)23*,Ur#[^QbwsR E;)k@[r h?DcD)Ӟ۳xSBtw'kix\2;mZAw%Qz$KI =D_&3j$} DdB\o}b'AE]Yç'x8>ݷf&0__&TWU׿ʘ*!]:}r^y^g} vơ 1\׎D=!)#_*DE|.tJ\7'2z+Oz^[=E4aU֬ |T؏gy#:Rm<[ ouvw)bsW >${}~a?ood/\zcFSks0)GfǾQ#elp (226x6ß,X["DžFݲX|V`X)Q<$?sQs}zN0 Eb jc.C^oXVB "wt~j0?X_*8m} s{6coybX>&d*P?-2mHE{RQxG'Na\RmW}WaN(Cagߨi6J4qfܶMy–/>H{}oː0ɹ;'~:-n{}sJ ųCuD[m{vm{!Ğ C[xFD?[;or?B {"K˪&3j4W))TY_Pkka*yF8_GlϮ/RK|HA@H0ydȟy J 0]`oY!̠E}Q[,D]E鑀Vwc}PdLmnmۋ(Zh?,/N2o D*nvYWџ]d3 ~Bx`FOEik|V]QIb>2V̅Ɗٳ?z<5x p B vd;u;r"%VT#EPd(FXNT?v-cu?Dž0:W1SduFl#ӉHYq0AM6Z-x@'*̀1 Z2Rj| %p (9l$H]9+(:^\0HDs9SSMa;ُ@/ ^soa%,ВU _gI(:~:?&AJ4.(eVIeIN"0HʙB8qe#SONC~;/(TW]fv0'¿ 󜨌LZi+vd%A+6QG;5j6BtlMs ľ9o5@TZsA\vooK<]ԑwI+pX[rh:EAJu^+>$=$RٍDlNb~H[~4sɻTpdDg%aQiH|ǀELf9 6V !hĮl]LZmv"2lŊVDUeptPVSUx`>Ȩ曇qP g:t%<L14|.gB(.x+O bSsX 0å qz້O+ C!=FhE}({sj^*}$ WȓI;8Nl L,9bz٥CO!Q)4*}0QԐ4fʒ#y74րQdW/~rX?Ǣ#‘Q~G7Ȩꦵev av&ۚAזv:8hOԱQf\|v7]Dͩ"T4TDND%fXQdN_no|kOm۶+tO vzl,z ,l8M/(m .#?`PnVLgg[39]=om83GרeV\hߘ0?~[ww[5Ys\@3,粺hHIMMHM ZD_3hmmPBCAQ;Vf_>L5'aWdlYh}mD0e˭ ezْW#abוld 4xC5 zk &>X sw߂9POTn`\1CG7Y>ڰzx!<ib H i~kT;ؐiFˠlU5r6> {&="'VC'Gp%hL a잆B ZET.CON|N?h٦`vT%!7$[PlAov)MWx6v9I^}T/A\C!)XttLŔ 6ZCчo;ZoJ:VA<["cq-UĒwݤ^ d Ϧؾ9c:oa]pO"bT>!ӣZ(SBSO >(=$.i-턤LuO,ix(bnCM2mxƞ8۠re~AXj<%в(*ANT3;Cx{5h$v^s}K_%@2%PjmG3v@a#1MUDi i;Z%{/>=D6qW]'2jҼ>ތ0ęcnZX:zko" 8!ii[OK˙k#d>]1\Չ+L{ȌPkUΙw㼞 ^ܖ('N3::{*x'>"ml/;;kˀJ 63M8,Lz=7Ӗ6=?."xYvzv]^Mo{["e %ö+>?"9)')dU#x&yXVy-Hj3Y3_\zE2 ˙@ <ДCM eRAi͖=d *Ml{x?pQ3hG+Bpן톷a?YX0̢¾w>4l'^|6c~?]?9" *HJBJŨᄀط+?rOq!,2x'h<|', E}ƼeBrrW4-%fpEK' N۞s jHh!3[FܮCFi*@{= ti~Mpa |z.69(U9IPOEYFy/p(Q]$Lv\,Y"9{}<hDCc_"v.]eZΞ:fˤit*04UX(V8ZP$^S͎(xԬq_RK@;.4"S`(ݐM:J W1J~&"G_*/?y[SM(# -@WP~u{n@ ]\6wRpz2O(ߏ|O]??wrʤ&QpK)( Ê~ES*)uRN/ݝ9>{S:zxvYG՛~B%I.$7ňo4<m*ҋeCXכb~ %htRHK0a%YRW8;3Tm$OBbY;9 V3 lKSIdE=Po; V[K42 kE 4 ϫ|<ނ k@ |״s؉sn'f 9CAJ d+go&ؑ >6iPmI8B4X.73Z(zo3W#z eo$ t UXZA~ǸΌn1~R9Y9 A&jbEUD^ ܜCX? '첎y=@J ȅ1 U_J!'? Մ:zPw!kWD|m/̍`C \b 141zLn!]9i\={A)P3 PVoYhYΒeY~)Q,JPF߫YRV< |KʏkTMQz7҂ē-+Z/0 OYN~ ?k)AGE 1?wp @͓r@mIdi) YڈGT8@@(]HOt~7Fd$RUAʹFF F ŗ|R 2AO~c}g\;\WKuHu7i7W|ʖuZ8B Y euȷ~-AM,qEe`{k2-WD/t?UT!Y%UJ#*駺ta/] FHg"Hi^UnNE:J3A͖YvC S`)ü&[TfAg߿kn^ù2#l~4f?e覟-9YJq*T  ,h"ծݎ"Pt ,"r=u9^m.gx{gx=k\F'3ܹ XxoT鑌v6nH)Y*ʂ)A)Z>*Ϳ# A0!0+AuDH AES'!B A*  ^㱣8^**c ՝t'$Dez^U}iJk@Q m\ƑB=:E=o| $8r-=GNl)2n؍c>!); i ׁtj x -~7|~Y#Ab:W\qQ> ܓ<~pC ec5Y rE!Őcxab)>-}Jx_~c5x9 AzIq4t=ע`H^H@rwC/.*SFWOp ɪ8 PQBQxƚ9Y=>mquN-1x@3[qH <<-ެx ֌?p`t)[D>8DGpTJм< Xmˎ\.HTMdXCOW\6O9ܴty)O5GX}lAm7SKmLged&+f9Ļ!oב${܉v< `!x?$H?[_bOd< `5%Ql/ 7ljC:^ƊSa\UNUB&zW[`#aE2Up#(hÑVȝLяڇ$쨐;dVFdR!%.+j,1*};H%_{ˑ}751k%W炬6!;vv NVnL)vV%+*EUVdhPV4F$KPVOgo_=A/.ڟRɯ@`ju8gW~w>p/m+BUg"H .?=Iy;|ZnL1/h"g~^dUʐ%iքD=?gGO=hC>NσbENgyNpwΠZQeJ/>f$KP=bOY|Mc?2@P4qݳ6Z6X΅<;2G=YϊMM3 ʼnaq_ 1(/hhS"e]) ]UIUƎ "nUrNge\8SxG=љjKڇVi[m&"\ nD<{{)U~|QkE1Q|N;';^UXpo1~V g;Y7VO t*B8X5]ƨ-sJpfҫ>F|S#c]~m{pj6WN]8_.m=2>-0Ǐ2D^3IvΥ!(5/ a\~vӜp6_>@X Admegl>_sjwgG:%ˤΩ+QPTtyV+2߅6N7=&]39/}3B"kpwq哀{1'>~lܻF [PۣRJ 0DduY#LګLܬf5Пi5$OdwqܞuYYyhk65`q:cAϛ7?EcD֑#__.hk5ponsqh08[ ,/)*,ԳhJ2s=Kafߖd՚(϶s%n]##u9?2RNB޽7Up0oD'PUfjCԺgSM9喂ɞ!_9uJ CS8Z8QxCN]uNcE?B^ qpf'(O xi>aH0L**0m~fEә R|B=/n;)9Lu|x;&n }1е:YLYNae{Lxw?"NqtBI."bwVш,h[iJCLߤ[ z k) ׅ ÙNF' :ĕlSVU7ٸvf%#F-PMVЗ6u$"N o r:2iV)DxOi<,L :)uTYR0dtXA(XQu^%9)x69*9-D۷}vD/ۅhv3os>l T8V$C%Y6XVHc#~G~:?Nf \UC)=ꂓӖ.+@%!;]l|>\H`'«NC͟s0΃Tdķ\8in`v+Ū@ˬѣ}5o =σ ƻR $UQH$UFdIZye?&?<g\_J\?ܧle/Bumi-9_uFӨ 1ܿ6H8/h9~j˧9pӈ\[4@p"5 6T:P\RVtQᑨHf`<$+1! |Ǝ|LB X_Gݩ0-7|SS{鏆@>D>ַt83lO@{D@{* sYX9\!^fp\أ<7V.=>_rF:$v X :[NwZv."*~)łm3c[1<߯yT5]CұgH,IFsH䄤G"")(J¯p5Z% Jim=FߚKf>_.Hȸ/cm޼Ҋ+pɄzq0kA4s[u]=Vq*z;yd*`kWfڝWrW+a:GF²ml\h6,3a4VTu/yAY߁5#xDp:#t8{*H;^=Lja滿DW!Z~*'ko FcySZmu RG/mP71%?<DO`,zN {kZWq +وOو&*? u`d<ІNKٍ.^jfJwaXU`RL?%wpQkA>Ym6͕-ѕeֹ0n@\[.&_%+8#kkO%FaqΈj5JX WJetvgV;BgVMYP۽H.闒q'z;oxG,9޾}tZTۡ0TJn[q^j߽KEof%jU 8pDVuc[ԍ8=l5cP PCq:w`Wy%zϳ$M}&>Pl: Bl ㍲'mh;F 4}ȏBm3l wM!JfO#Gє|s^MRAvn4}ȆSun'(+zc,j|?ٍm ƶ"c˔fw6-3˲*Gi4)І!Q!д*)(jBq B^O_7뎞ýqvC4͠3+M0lbP`WicDv`ʦNQSm c40y?׵]{0ִJddI䌌b7/ϧegC/3,o5Tڹ}p}{ԮU+ð8~>m B蝲)qyIt'da `*ѷ[kHΚ?{WE_CM`H:!!U]U݄`M<@JjH B8VIVetAeWQE@Uvqc q|+ Ij{UL:@qIWWWzW q!sUen|~4\kqnODy!Z-U?;*? OMANbFai[EmMxY> g iH#m,/*fH6¶Xvc)jamCSLu+PЫ-bnP$X>|"@LL*`/ɒnR+RT|zx$dAɬ CE6#v~/bzx"%Qtpy<+wӲ,aP /,Gfq!OGĄ?hѾ,Ty8:].e~UgB _^CW} ϭ=ʀ& VWQtf h^3RrI7с!{pW'&Q'sP>YlWr!FY%Z"0kw^([ڗg-vV&})M7aˆDeo8Gר֧`ED "Lکt%ܺ8%L/8B8泘LiicQH&YFcq@2;+'zG7Y݇sӁ؁{$j9I h|Vu`9|L-0'}33|/ {v~05xy]5V'-7k„I>%oȬV|Zkm{ )p[ˑ)Jz:][(slL7nVXl, H\^$>9 Ě ]LQۼ᛫Bc5LQfqؼ/ąUU0,4ќe4*Τwʮ/uQ06˖e"MrE`ebbJBY, 7]>AfPR$^j!'Ն#W^*|JUiV!5$TAr^#,yy4 ۱mwd߾\~+]K𽋐, p W0r,/-keB,2Dd9]VDʴfX;fm: kniky$ri+?u 6V~i i1?J-mlk6KjbjjʴT`kmžLf`"Ov' e5Y]s0$'{Fß@(.jkUaaaċ8 UǝXc91!pEU {Us}ː  0.%݄ !N؝yF1q cokW+g{1UD&iwC;ND}?䞎'ig%QѾ폜kP8Dv'}QDQ}N%D>ycx![X)nNY{48EI\\,9`IJL\ېjEuajUH @O0ӧpN2GХV@p{Z{WsNF'#LGB'"?N):˻D^ݜY=f84eDv(&ƀVD3AzǮ&Oڱ&0RUuvӽ &Ռ~uS5,L?D +7N#2m12s)Jo/$͂D|@7Ș7:q80{M6S9p ءSnWnOMl@fzT R~'+ =ydLz~d=ن8 =0PF{4M})m˭nXh-6p=0gѤ U2݁lQnWsY,ʜG`YdHy=dZqErlHoi86^`<qzA4H]GR '\)"`\G\"O}#ucDiVddb^Vr y8HUdF:4bN8懏qC Zi8Aֱr hOأ xvvk'xY]һNk}ن2Q_^rD/|S/6>N$8jλmg@59T@#)4;MT/,g'IްWp *z"s u/"/]u]f89s4=$ 7SMYE>QypKɫx8g"`¤ 'PyIBtL63=6kDƈ#tHGڭmG]X'/{Jcd@zpjvZL&e'FvvfA__:вbCdnrQQo6" ZlG0>?'<b--6U%O_9z4f6{Uuwá{dog @SLU ^"?r+ӜHDS!b$p:Iy$x9vC~OYIu/%DG! @n D :[?v>;Y6xa9G98*jV dF@P9E(<35"q ?nXN/Ѭ8Yx<(z$Ђ>b]!)2-%TR*x?GH:lxPi=>?dGmx O~?Z`z@]83F2> A)Ԯ;FO r?Zq}cBĉ$~dg緀Sim|; {H ТuGDGݜu8e܌`xAvq`cGMtq?g"뾇 /5;Y :)4FE^Ystm)Y@uߕ}g@1}~i-cBs}ׅ'708堥d6gBzzܩ-;~@BQy%8z(!_"7`|d _DUEE=K,Ӭra ?3WӐE2qAɃIֻZHW|ƏY_ Uo2{o֮xnu, 8ݽdNNh  @NQݚMn#+/?Et F-!OAd%YbDoqZ(A\s8p/?F'k֜e^ix!qXCS|z;Qq';{ &LN 1q;Tat>%KjeSOKQ>wbyd5ƤY(tj FiwgV{mw g4ܚԮ09(tZytGW&r =aD@_`xRf6e0̵2ǡT{foNkrJY%ٿ\g #J4p_n^ZdW𖑸I?9()-/~[`dV{6rO uր݇wtM*-`vd#+puNU'ܫj L3|C@h'#<]n-+"h<҈5_hK >_D(5! 0po'aU<g '5wn\8W6_[Tw8ݔYAPl~Y8 0dA\PCeFVJ4o:c4*l`J6Bo n~/cɆa.g2%M!FѹBX<K*.͖4(bm_ySt9_‹ 5ZYC2S@;o[3fjd /xjDWupKg@i6(;U \qh\gY Gqz=N֫uGte0&8/v?NfxP˰?5kJw /?;z^R"ȸ'yE+qGqnZqO$* x#X4.?$ 90PՎ2 lPH&`%, ^O`a)8pVqQNKN6uىFEf= z{ei9Ò i&)#(U].\`<8qKyuNߛ62!͞aFiiD :dh7%-蚴.|oCerQ@EzV>AJ]7סPQ{E9} PzI5 (!`&ooWXH<% T51,l/nMpx7Y6YuލoUE6., j ٚNw:퐉RuhWxJ4c jA@LU!+VLRuX48Z]wPC ;bòRQ{:xl|\GiUca_,+  meNS;YkwZzykݭgݻ @W^IN䅉9 !rHr@>7m}=/Yٷ>s) o7b'Yt]qRH:]@Gk:ه6VךƤtg`p)) vw78zXcqCR<.XéU17t/yU3Ua\`?J3)F¡xKa"](slQ9>4/n6˸}=B:\FDjl.ܣu  . d.ľ';VS `8W Q5t]V=bL4D 7P8Qd??%? 0C?Ǘ-ˉ^ɏ7:kW,ZPˑsO+||j7Yzq!#}HqDžvu)BZvb1l,>$Rg*[_J6\m |6?l /k(Z5^f՘E׿oAz| >-zCnAoB2BD&-}ҘTUQ * B+H'u9E[sQq /Ow~k 54A'/[vO-cUyi=4ف4⸿Our. t!@{ݍ`+ ;mZap?}sU}?H1ˊb4YYTYtAqj.c7e=0^ i,t\l_2. 0/tx=Aғnmo3%-a1KXyutbRv/ڠ@~bHZ43[7L#O DH 7s$V]bYXퟍ7\S$4yO_IBS0}XZtuUQ(Z^&tȢmue5=<*@E߽|%nCMr)y"s:/]LLkFPڇ%CDimk[́ 5@L)^ųbr_;CVF\`O$&h[uuINau?D&nC.sfgFɧ(J&J:Eo9S0ZL h<2-L9|{1vҧ͓$1g&wH$Y*[ns`,_[:[.p$ONa/[)dz턧@ .8~_oeƢG hPc,?V'++Fn |,EyY(+')壺p0/E??S S{.fXϔ.BD!"۳}*qw4l,ߍͮƓʼnZ]ə-wO:+o%"d,ߍݢY= F;U)J޳}'V^V2Ȣ÷1q(|8>7Z\w6jJBwV=zS|TU.s KuA>Ţn+K}SYi^p5)=V'@nMVy#qRb`LEb~p 5ңN/a34>aJu;$MZ}^w̙/7Bz*9wkt>RBΥǾZŽspfESԼzWnU0"89I14wv\y̱kMYR=DQ4i'(ߕXݒ}K'=β *R֥|/޸lfkaGG/m/ .ka<Gn U(EWv"Xߜ5 x|,9:*o*H=.8uʪY T럺cIeNuMgChFI5g#p=E3= Kk]N>8B/G2U.L Sp :cʃ=Jy={pwz$x^ 9ĪI̳&G5.S ?xO?6 r*yE)25t3>֟ @VՔ`Ξq6X e+YL1zp~!:<&ne˖[u$jϙX籰4]p xAY Z;:QE1rV?0x꺨Q.cB8VyIb*Ꜧ r\r ^4=/ P6%ǻDџ z Y +orbfV~b%߲8L ^ɾfetd5!`Vxªm֕M]Iȧ#ҏW75W=Ɔ ⼈SƋ!q]58`S ( ) gd†5HiiNbg:d Xc\s9"cl"heuRK& wuv=WҲ5Q/V#R`Md >>}?cښ1mz'LhSw-%0NKx^3#}wPzHX`UE1hJ8N Cd]'`6MNs{z`t*OXBI:3"'[ݒX+ śAliZoq ̅$ŭ}JXLQ^r )8=1N~,0 o\8B%շx`1p f3c@zKnNt`ORu:Mu]#mc:Z x*>4]!$nO;@,;cC q>&b MXxb;Ο~lu1bss4ȣbd}Y3--hH8UYiEu؜HܒHT'{Ϟ-xGO^J=#DhwssmDͶY ׃v`.A3\J$9$&!N񰒵OTa9L+:"> 'C{&D_qC I7Ҽj ]8KPpP&1{R8m{%ƳѰ%9SÂRe]a ƕAYxJ~MU~nߋE ykƵcMC%%%X>WyϽH3OXx(tA(4>5tI(UBA\/]1A UCop¹bXգj\%55N5a!~8#? Pf{ R/boj:Z"cڕ+߾W|nڰ+#4'ױғB%}j=~ڍ K>'!g'C3nzȼXIɤPJ8{!Yۺ^0mC[*pЊ]쨳R:-jK$'Ն~s,e( +sj1 G%qQ ,۟9E v%1)X.4;JX!sѝ)0,@z&VS_Qӏ315QzTCedE$Q$ SM7-&mFnMF_%/b{[Ek'40'HH 'ոž$iihد1i!0!-vXi7|GG>wlE[^n )uj8mKkNig|KW5U䰮H*!B3^h3EE2Ⲇ {㿰-쬨 ?53 :bGS\ j ~[w#JJ&ecb`[J։'שָjl0#13Eօb $ ejy)HRɗ3gh9oހR~T_BtQXMSXVdUK1^EGl$A_Wɞ<`Gd*ĚD/] xEI@≑yBЏ陞 '(`&== Ct _XOqO9!AV\w"~z{)5IOB!/_fUKWܹda }ʎSպ@g;" !ٚd\Л5qq}"X?1W(ߠˑUIyƱ@vV/K}s/=?PM>ڽ彇s]#:z|P K< aMNz"!FlK]מjL亂փ[%d||n'O_󍜸Av=ǻAuƨ E Mz{ˍl_fTwT!z?pTh/5҇ Pܘm}7K/w-7fifW4d;ďXu9nn^[(H DwÎ.(&rKA%GC Lj+04ʺn ǠWFͷ+{vkw`, ̙<4nۢ;O<.Cpc]vlsK`͏?v98&+, rV9ϟ[ѩ!}>`l?n_XhouX !ps;Aߔrh:$J.>(H.O/}Cg!dtc hChG𻟁PQyS{&_VUt*N{QkQĽ6?^>㝅Uڱ'M=4I= 08h5wFdOJ2:u'O (qNJ^ ^sy:(J4\J<ۻVoOO`IWhl4VQ(br-4D:JkÇM '߃&ؘʊۘ #oݲeKŖm`j*2x3a;#Xh/> 'D (F"<^ $hֲaX rk!{T%ÓIQ88Ў-#6CT ~m  Ȏ{Q,lhDNDG8DT ľ#ݒvDTC}ѐo߃z:thyߘԂ$S -znG2MP,YRT DYUo&KF_EZ3*բM̚50GV ^ưgTuNY ^\;sŚMbm4|Å=[h$Ri].zvmlisͥ#l~(OAo.V#\g@ `bCQ5&]h'+Oe9̞ؒԁGy" JeהQlrn"OǛ׿ yZr]v7<~yoN }+' zDjA+P"ŋAwAKQR zW/V'0Ew@>)@ppa79R -3şW,ZxZMrO-}#ePQ+ 'h~Ӆx=~b}xob%!V/T݌ %J@hzx7llAk(1A#eA}<Q$ ܌HEт`y(E/_ xqwEiG&t`e .M̼,/M 6hac>tW1X`Y˹Q(/+P`i QP\Hz߆^2?1p[Ѩ*[s_dx1gx3S7P2@%x %>dbc"qӱ<Q挳kϠNOّ? n^3zE^N|̈́_b$\D f,7dD㽾NxXTw;S5?eJ/Җ0/Q<QuơUmus"]^ghɡG؝e.T6?uei"&vZMvdA ɰF`v9<B٣vhn3=wZ(=3&?mƀ VXS`~"B܉*L!G׼1~u'`g < ѬȻ\D1. Ҝ=;\O`?Rl?h'TXF ٜ}s2ʉf3Fq'굂?QU?bež^LOԈ`XۡC ]1<_mH贡>kp؍S+ IX \:Fx>(u*;'@)}dy|ULs}`Wh|!- :9}> {[;>n^v~v<`*~X2B:< T%+ɦ{ZxY&ٷ KVU} \SR&WMMf&mN]JYm `CW̨eki b;ex8Fdx:q.6Po{v>1&Ўl=ZnG b8ĭ.'3Q7 |a¨ߑzDOvAiC*= o櫦L jN(RiFHlBGdYpP6TV%gb'Ӝ_ayzӢټތzIP+%t0柂gXWW1 0 sMǷocFbĖn?ʰ }a谀+hW'#"(ϒ'ũ@Ap_HQ۷=$z%|DZ< oYvȤ\5bj1"ŵl-20t0i7+Ma2USgN5_zOE"ˇc[n)iǎD݀sw ])He QwMή\fУ0̱V9MÕ@Y uk 0溊w@s2 Y}|$lL?~&^xqrF 1 nWA$NPq: $R5iCzHIEٿ03q$xe%Adh%OPΑ`]#9dkcҮ. ILBAAH$#X!uB&)c`w n&|*Kسe[ыuieyѮkNE˅Ș?=p貚 .媌?^F{ZVQd:q#z#"ƿ~QS%MiQ,JD*3RB7tGClCLO ş?Y2+cAW4Χ{ዠ 瘻 JS0`0]RCNw 8`=y5o#uf'EWM.yT\2ޛoבZED]3߯**@ <1UUƱ8F_o@bݾmd(&CuQӹo57m1= M `TwB= DcSX–ߚ?ˆ<Ӳ^\.&jXf{LY.?2d 5Wm n1lC[DQ(%wK%!'hAm5^4W纥\| MOi1ԥ^5zݵllUQ}K]۰N)A0篸v4vfAWHcBEsPvuhGDoofAaH%H ؋]z_=7wQFR `c|'Z7%zǹ\ߠ<8,/ =Zx_݌0/tJ YxEz 1]e1?2Q[}R^.|W.TJZ~uM%6 E^~~M֥χZ_dVZUWtJ.:WrVAhu)nXb+C ׇXi#h6{筕x$tdqtSne2W_Rll# rf'|WĦeeWYveai㻃+!Z$W6O]†:^VdXr!u (e@Ixfs,V/5ۇ ov?{ľƶR%u@'Kl*ZbaKMQd׀dݟ86cB'KKZO 87V|ϯh| Q,@ci.C} O} /fb`ykS!b% 60+tH y[]3f)yx9dx$0RwLY3cpfzfE^&3$|_@j׺@?''Yϒ-kl[5)36ڌ-فk՝  JCGƷ"ϐO r*0h՗, 2'sG{A%Y@b|:;VV`8Ar"~d^}8?D *_ghFf,H2~M%7 \| 0b( a}K9im}gjƁNULk gY c~'Ȭ߯i(ETFW߀yd94Q1_| x>S>Zg]|yJF T5D@΄K*XljPEF gB$O|aHpm`kSx/K_axsx3> NLO`b3#qRp]r_-AYg]f^nwV{i74.Hn]KÍwLW [[=}`}"<-q%,**%OMwL!oazu هWn߳ ̈QLQ*T 9l%Bl+qԦuGI{?Jlź(TPqEuUBWtżlB!uMLXWZ}R)Ɠi t,BO1UwYc\Y^4=Z-kw@+}iɖЁsH ?l|eL fah.XejJ@t\c@oHh?.lgfSȹdG3?͛2jh.[:me򲩦WgOYg4qW)9~/zW𗙷]ǂad _ӊ)%C~|뜴#z8:pHO'@3 nhᒏ{,?]k;%g¤AlurcwhWwp^m)oQ+a_kY!s'ۡ6 kA34[ΩRAjiqs/yw:O}mxEwsmnCS)yvFlP1(sdi_ol|̻ؗAC ۶n&5;IE $sN3Hwԣ7 :]y_Λ_CG`) #) [|!KMl ť+Uj,6ζm\ pМ8 ߞ+ɭd"(K-"ɶm{Z`lץxvtGRx&׮BbvP[86^n&&W]]M~6"A3Nmu+xKىܶZߤ&㐑WWWSfd>@% <rbfŭ,neǭuDϮ0f9 s2uzB5|~Gn8\!s̹kvl8J̒feSicd͂tmQ%6F} TGPs{`'gugMY]ӍwA)c/Y836P*^^Y`\F)?>gdIG6=hfR:..@9Ǩh^a (Z7jzYeOA[IUguՐ81$J˒Y_PT/O@u#Z?ko&fpvX5K㗊p e@63ш?n38V y ]<8dw:fj%,5Y4Vxז3O)36*9*.3ьSm%}K&/p'܅`˒ѸOey2WGގci;83B/ӯZzӝm2 :cv\tT+gutg J HxӮ b[Xc'k߄KjA^wtբ/$ Q֣.ӝ. (=BL#rb[FzYQA"~s4<՟a4IeFfXVM/ZCq}GH_*' &c VW֧E'pQltt`1 5_X HbgTx~s +53BS,|ѓϪak@k-@ np{*RC%ʳ;+Ոz1bœX '늛le}odX2c1f0[5<7/\&mcP禋 ܢv@<`(I}I R"Xxƨ`zrh2]ٳg/y9~t2|7-\F(FmK>lȓrAUUW\s9}ČN+Iq2`)jX>*`[ JdNHJEYS:{oay4&T^\''ŌaEʋ\+!^OLq tqf`xHԭ4x/T pB Bz&xp@jɯ3&tf)(JQ7*Wz#Hj kf+w j92IwrLo~2׵R)8ަ. %!-GfI^a]Ud$gY'P`k hLV+p e+xh4n5k6@f \X]*˸[>M֭œjU}Led:-|!UK3z Չ\Yz\.`cm/^;.t/~ Ќӿla$}~/Iր,X:q08(eCz&'/lw *) <; `EK`>x1L-7+!;vl $jeՒ*ƣ>ec>aC}9V]^0[<OO/Z>(0uۅZ4MF٧"*m33>ǻb@TP-@AS$Mɦ׌a&:4Ž/J"\SqFYv1]Q_= :IÂQ_s0ud.Yϵ ZӋmhoW9Bnl@` ݍо.T_!'5kΡJH>(E۠@}߾9*t}w׍hRTȂG9s $e*de\Ng̘VF?a;: hƌ M1nF!9 I7b}6YlV hnnѬMcn]ДTSk-bK/v`h6},zl-*زӵ#UmbڡxG|1 ;?|0>(nXB=UO8OȨA,xpgyX&jaɜ2a{R K5M#_:]s*^^ϓ'7 :5T0QOc_K5Bjv__7x&|c Ϣr}M RaJFx lwɩ77՜Y {4_Y,Wʲ]7umP/ 7p"=J dB;e=31O`n!7UM1bC'(bԡ+{Bϊ%O}?hsKZa('q|7`2|C|g8p[8=0Q-:Qp?,|Y )_>%wtnѥU߀wT#|Jzo#iIذ(829wa$cw*1l՚q+HDNF ) (skZ6P9`/GyQn~tSZ0eSA-Mx(ՀZ*a,,_Xܗ(Ŵ&qZ7+=M HD޽^ޭZiJZ>CLC>z6wu_X#^ D}t`$qj"vE\/+BwzPdztdsTO"APL&%~bZ~QǶW Phހj6k ح^bq=NC>h7 `vcfnU]! s+[U ؉hl|ݲ%5إ`n}:=|+%q*\;1'KYSRwɄ@z%]eQb~%[!3v_<97= G'a/Ý8x> ԨWM<[-JB8z?K {ژIlNt*N|Ÿ5_2ssxIicD<8yetyymyd<F)`1ly`Tf<~juD4~:}NfG?5ZW6^NW+'!L9o܅ zu:u~! :(nOf6`3ML e] bEP^nvI.$ƅVX#V\\ u<9O^QLN4vF+W|+MsvHtK(q,Um{?aAO x0W_ܤ2Ҧu^o q^ҺAiVZcJQ{"#I<)N&(D8|J˕y,v9[HwSM> '٨PwU˘*w={Al&BqP Tbj,sjaQ{xiu.f.9"ҿB/! 0aW3.ܘbЌB؃E k/`e0a[dE|:;~CR"^L\_1 ګA)nwe%ܨihӞD̙X +!6;BKQu_yND;:h8PS5Q/T {x㹿=ݛzweQن.ݴܙ HGYgMVGFNo|` ^Z4A ae뿚ũSWL%{4("(y7d4nCh;):<%Pl)iڭC=AM-ռHEx6TUb>YU7ekr|` sDm׃milRD! )\)fŲy*KnTHdSfLF&$"-< p=ڶm0Wdyh{[ g ?{BYNŁ;mшD/Lx-V2b zwBYY9qK<$7\܈HyhfFm {ZgH:M!*E%Vtb%,j1e^BP-xIIޫbH ?uK|$?}& lTi#ET5{ؤpw!Ǐr%qtㄷXvCE,- ݥGuqEH^.C/HMT ̥^Cso1Lv\;e3 <|LFѳh`[v@jG'^W _#W 39̶{km,Dsԡ[ j_ltbh~V2ʕ\n?r7Lc9#9`US] xU>UAICCG :1tWUW (ȬDp|⌊㸂Ǒ|̺ @R{ﭪ[ Cr;Uu޺uϹ:p9)K*-1:lUi]f{gГOJ J/5bz DY|QtyϼG|S0w\-X>Vʼn gYcI,gi%$u^j]/2 3eq4OEfqT[ze~cex75Maݦ_ff߆n[U,1.LoŋAC ȯQa;}[$h"ů{yMQY&" BTIP;o?6lO(y%^~y}^S8A9EV<$IE ut'B#D{WuW4ɱZ`c +Y_>pg۸hG i[OD,Lr%R0nNVZr.wNܙ_*=f^zKӇS^ۡ5QaraCfCD;3WLsרp/@. +d9IlD SBn6[ٷ ]Gs'o=hxt#͢3e6|H˲ziu'mՎpҵ֡;fr4& McoWǔ7dz!8s.хJK*g f]%t,J% #sHN%<%6JmO&k 9IV$Y9$ef^:}rie^&(qрD=~SxUP{^k<37G\R=#eԍ){P;qg%.Ii[Ɗ<||Pa Gs߇DȼgtezIi͊l"E13!#GWtާe盠MMihj섞YdL PU8%GMшO9Y}IR"?_U$.u7^{=ByS.Ҩ+Pyt[8=F5~/d]L]E36E3وgh\a+!@qH ۄN 7YN/yz9NORq*IvNMU@Gs$W*˲OI>T?Vbgn Zmg!)] ÜHi}!##_b >׬I=&vf8c{ $l4c(v] 7" j'xҸd L+J??'(_aSP8$ ~xF<>x]C#DtgtiYRFє>f?SCy̫!!vMnb `a1ryI`윎ڑ_B 0? q21ARTU ƫ*GFE>󲟏z%|G:ʂESig%0YuSkyiŲ-~`Y4.Φ0k ibG_31/ӳ慮[1MKPr ~UZU˫4zQ2g1CXĤt8e.S7Z|6q,D낄Ql\(E#yLo8 +( "q>5uw MOUz8*2i#D@:|H&F8aqLhm~ |Gzƨr  \}(߿q|o,,Ӌ)0׼0rc֋q=n!$|`ݵքM= _1dz'ǙP{K9r [SP_#l:%*viQTMA[H/t!*snnt# WC4$hpUn4i%&;SfsV+/MzS~gY%Grz\o>X R-؜q&'CtӨ1gmuf^Gf^=>LGW'͝%JdM 2et!{muJL„1PĝMSsܳ8ŐNKc&MPvX7Biٞ)%JCTK?TJD>кtfK4%XwL|/ugZ#y("]joY=͏%V^b 4-r1r̤ {> hd1ѐix'ӗfrsQECCY)X$9.2!]N'ZO ]vn_B#կ3 I r jC=R< O0s}x]FceV#1VRT! ̏%qmPt&vSLd/α&'WZ#~ Ɠ0cs׭9h܇La4Ўw}~?p6cj0{s6mD|cgniɿ@.XL"kTJE)) Im΍h]j=01{(k}<q>jyMoNq`TladvM6-]1=TTvI#ě7O#vjX&Wi+qW`j SU5_z۶m[p6lҵd<gVxb;u5]"u[8|IMQ4Honwͦ>Yހ?fG׷˔O`-x l;=ھ_~%NmQHQ1 pNA,T^rٗrU)PZY{|_pCС2Rɯ]I#R-6YjI& tgoʬ'j)8ZJ<`Oavz?Dt<.(+$g AȴBȺ"õ(,^s݉ _H KioW0Pӷ3y ;~-u"-}⦵4Ƌ^VO" B9QbƑI9<Ոu_]j^Cr0k}jj?3Cvk肞ji8kbY 7&P R?)ȼ&.yH4"<>M H]sQ72Q|^h M]?F@YK\[ůWnvrjFUtuL?/?q{p;П|{8ùg|NT}qg=$:DW!l}{ƞ8g IX0CVFku@1qzU2-n-Ԡ Th盧Obh7F.:0IސG[6,h+;"ivE?W`a_ǝQ賴1^ά3hu{m:D̞H<W;R('nTs4E^YF/9N~ {m. ݛ9z1(񟣘@$;=#b1\)cA @/3ѣ p{Jq%cܞŃ ˕&nG{ۣT*GJJD`e9`7Ь}v8C3.GJÊ=l~|6\N *z#T$' /hIݸK(יe4z}gsdQ'ZjskZLj-$?~VIf׿"!yWcK[.|pY""^}*.bPya)Ԟ=Tʿ)n# =%~I()<(D"ݙ]H漽3D-4QT IMp|Z?o: ˻zݱo()g?l9: Yo+yV@:ƎGGӳqߋ?"F(Q{yMyD?w1#D}q)* ࢌ%"6 `;I7Bc̃PU rӱ *BZ|{/Yf{0ʝb]i_(cK0mۺ܁&qécn:%HU &&>OT hZt%=|/Q@@!)q֙[VGll#,d>k:gCBk6<򀄙WRޔ$;3@ mzAXŢV*?O{p}s93svylXowgg̜|;DD/ɕY$u XG3 ~ohXZR:g֭KJJN_;%vz!g/&40y+Un_Tz< YGѣGs"[Nz ~tN OcdJ@Bc#:OEܿ, Bx N- (Dr4|"OҟM< `+\WN޷jު%px r\Чmi` a.ld5ka:XGB>yI_<p=2xN0WA6lf@$0 8OG~~c+̵W.Lc}!$yA# +=󘱿D Hڛ?<)#c 5] /\t'e*[/x!Hb@n|E0Q90i$uez&Uo"lNB`ىJhij\ 9y6f#v?rf̊APh®=ǮN5f {~MmDN}ed3njS$wvo<_0A5BL@JLJZT[߮sUEoz>7\^| -Kk 2q<ͧQKSԝzc]DiFRN-[\N.3T-m^]-a 4<6VPkTi;dkJg ԖHMuIC}cNuT^됳 R:p)TE-qV)5lHU8`ݩ utRwݪl6>RhtyXЋobj@>32<ůԙ^Ӟ ZWa.4V/ i.4k:|z=o&of;`>zp]D0Xl\{jA2IeZm,F?ݭkOpW֤t rv@8nu06+zWi |ЎJJT]D@t\xjO ڽ w'F4*ѳQQH܇OEiCC%GnO{ dHȹ.7w9);JG?zTbiC?wQ@uЖ#fohu8WeUa،&wugqh28 ;DRҮ^`Z[گX{зڎT]ϰ_'0CA (.GYO>]*AS$?s%s)A_>u'<(;j-,mbT:=H-F&v0mu[r3u"3N.h){T1JשG((%\?pۿ+$yDIVXYzEVYaSB %3M;g_/!mEa+x-;W9vK:BAx(zp£C1/p0\Hy/x9I$=n璑, ەD_&T3?Dz\[ſcǀFoX]wi4>z*- >,"dE5،c@͟N ,X~0JT: 0SGZKWI>" +,qYW WV0x4$H%2vO3Eus|NA@'91(by fumƟ`9 p($mkw]5S6{wôg\ m^k{$-eNSKapj@5gvX|` \'̍vjYTL]f)\4O/)-Eǔ~vq<pqSHtET30}uhM6l0Rg~_K'axv0&욻am&\QT!BCbRqBp=B"ߦq0yzZ)RH!RuvP։66 Q5@ZN/ ^"$|Ǹ$qDX6tFCJWam CJXLϵ|q]JWvE} T2F|%S:hq8|_7r/ǧx\!Qr{eSB|^YWQl vÈb97e=pK% rzo c #!Ёfd aˢHTj7]x Ft h#12#)osċB S0 eY$6;i<'T0#ײ$gZ@ |4 fKX\`?~ro J=rjyYUKB*Y+.Ve8dϳnrZcnqdѫ*yؑ펮jޤFԿywĊY츃NO rgW FDV=2}?_Q!U`A:gQ8}:f?|u drǏWNs|*gA_A^ 2[La*a}$`?f%w`}Oc05,pjv /3UYPM8ڐ\@U5|MX+?W6Ҿ =e#.1Ā?Z&ҹv 1c G_T:o$4>Q:X:ȫ^rӂ3Տ|o`^4VmСh?}`tDtݬ^ǧx$Ѡ?s&7R'@GRj* mam ͘FQ9 d4\@FC$,0?'~NCn-mE mL=>((I^K zŐ-96$ aSd?q])_[oСt``?6c]M^KT++2?y,>R?C>{|?f@QFSiG7ͦ`cw!^1[aBd۫8G?RϠѴ󿓶괢ǟQ](Eɚ?ht6w@hXct`d9vi']1?O4jyu|BcRn\c =KJ0hpsFs-9l8ܖ}h |7p`Y6Asn>}ɢ/$xa=8HqBn^PxNd\`{YTsPfe}{ij c3n[vMBM :+᧫[v8gEjB7>F@xEIVLK'O¡u qX aKlkKB$Բ@>pZ۱E UҕNJu]u]\2WPy y ['%NbM9QSk8x`F >V8lԌM{7.Xc3)x pwW SN v=#67\ 319q:zZẁ^XL?KMZsoҺy*ȿi/+cV-6˳GCҍ7U >.-h%sUi3|wY" ss*Jta53]9Ѻ5c_`EFVUUQ IYz-- JپwScB*ޟ;u ?Cm8ٺڮt2zH){)A__ ߉0(>Ir%"(~^t!w{n'\!'xS_=d7Xk~aTF3uQ?? 6T"]0b6*/FevY8{Epܦv<fȱ  \3n*L\c9,.4)l_L2b%϶mtǒ Fcư8U)~@GJ粨"d1v['W|nwC |7]@nwh;u1Sm*00/8ig DKh=cbxpWFGSnQM'r+0m~1qҝI<2Q[-gGXiqKޮ@o#?T&F,P Uz3R䨸7 x 'W[f6ծ#ǻZֿڀjsz}L1/7Zn_h "<:|,aC9NyM?žNj`Z1 Z&Eb8Tۤ:v PnVWW=/8:MRG1F}pQo*oѾq]\L'IIc\VZ$y7v{[aTD 1YlC6 *fbCm֖*7($:u8h. _kk>p9~[?[q nݮj)krL(!v-asdlselS6j1 wCs5ܟ cD=RuL8.dV x TQHj" JJZy-(/Q$)hΠ/t[c8Cw)]zbW_x}A:owWwh=v"*ڤ47qx]{x=ǚH|^ï w!n̡|E Tz2֣ x ݖTUԛbq<os=,t.Oh0GLjGʈ$sR.qn;c"9ʃoZJ`y/&b];t[,wxbi8̊i1P)ڴ0ޘ Wc+>?ϐBP ЀpVw')QGN v$Q*0 yID:_⿃iO 1F؇QzƣGk-]aǫ=nzѪZ X!t (k6NuVzHnk&;_dL7R0|Q+ !QÀņUX1]BϙwI2˚Aa_HVDٟE4JJ%GO!@/L܄S"ħBAёC ׃I1uuj>ysp}opbnQkn61({'Nt4V 2j\P`$R r /3DUJjZr#]3ȭ  %~h'3)Qm+D8s&.H^5yzkMٯ}e'MսLFe%p`⤀Gu ŬMJ${ĊYX \S#qw!rs)Cf%݊\m;oS^/ # €; p,#sD38ys*&vl}d,ǟ}opKv7V m}nx7pOz C uZzY 'Qf zrЫh{5{ xĶ@ŦY ,AZNÑw"Az`J$_VxMMU@=lc?01i.eJI,2RR,)J2Xw/EW;A(1X |mLf?f Nڼ~tFD72R4i7OZgu$ z4Db/\%BJ:˚}r > Qu!c~~! /Mq8 W$x6V;z)9ozxAoG: u%Y}Dö/nR׽E! %Y :ͪ:+TIh^t]dVuMj2??LS|m5ơ짦N!vG߀\.B,MHdH̪q*/fcYQ:d~~ ^f[7xi[Dv^q^kz*jó?@ݯ#+Ἁ`U`=X)c{g1Ɍp&U=(˴,k H3$4M6]!58Fd7Rg]3O6P=i;o`G%F@B* uy3q#S0,b xJXMR,0R^XNփ$É*Ҭ978ϵSij80}2;˞ |* 6=KJ6sxdI)|nB ;]E}E"yMyyJ xˣzx8 }_>>ˣFӭΏ&,LjЦc*UeII"Sĉ*(deUOxޥ ~`X]kLEij]gz$hD帞BV͇DO<73|G=+9uQTo8Tfyĸ qv,(RwAݙB]3}*gw=IrgBӝ)Œ[Bdn C>X_YnW'q Zdũ'4]En2$451(Cs tx"R؆3@5 XQ<dO?'i4KL "0F1:+P"2Ij"L'%u:0fqSGۿ𢄲G%(e4Nl4pz0?d|O/{~^_F\=)d^P+qtG?7f~c|5S@vuubV|=meP쇨Yˬ*ê0r?Hvi/%Ћ>k_B78vB* :ZC G|.M® Qz% U+e.ڎ1P9 H[؊D^nD_Pzޑ Z/֘k~ƚJ:Y /uJSyVYUQ +(ƨ:L iOct/a8: ddh>AHԥ ':Tndq4co%S؛[u uzBE#o晑.y *1CqMaLu}ObTyZ?w|'w3i9>qZeEjidjYB5Þglx&E6K}߲F_(UJ#l8uZ5yV\_IJ NNqa"ЌjLFdlB3r3d :@UO `9WJ8!Dyg #AKlasr cFbdRꕫ̜ll`FCo8[#~{tNxƪo\OvGΏc /*_BX ]XXKzDŽ誮* =N!F#Q}OLzآե_};0ܬoDQ{vwy$Qt%n$$Q~ _+%߷tNqZ 1EI]ȩuIߡ܉ "WcZ/ /I@Lf1߃2faB5k|[[XLhOZCȄ H ݿT檷s.Qw~y^]8Wy]<+y9c%FWeUUTVVʋmB0nqyWr ׋O>BNy4J@ԷKBVTTЬWߥK4ѨXu4BȈY>9$ţaA~̘p`wq^}tM aؚav/bV315sI:wLSP&) g{a 2  L@0LCQiyA6b|fwQ 5f>,m=Lh_'|y˜3|kPĽc&޴{_.rshM m&+^ ffC9]}~V5-z?N(YpZ (rEe`^|+&^1kȳB#d̓1K>.4:]qé[ͧ ~!{Z.s9AkP΄EEsgeqYOh2 fxNICCqiN{CJUH(h<;yGR(_dgR]xG(GZObrkdDQhw{VȧE^ fI*׆ρ=~WW[_]^ASHJQ(aNJt{PUٽk̊hvDX_29m~,m> !psW'%e"uɮ%0Ѣ6"M7itsawj{M_B;18iB:}d3gVZfCjW6,Y:XX.2EfC+jn篒aŮ̢a%`"fgZU=$N_|a٬6{uml=ب ո(韙bBNJ.Vn8^%{^Q ^`G a(L"-U;zHsM5S;nH!u">bGbH֖Վ6<|(p-\{$|1y$~qI~^snOR DEZbh[9QgYދ~; Vճ?1]^b֡㳧60I(#@t (k~l!-;"pM6$A}8s@¥84zyZYpͦg67',in֘ $+`GnߕUteXr(n^QX_ȯ f*G$N%X>$M D¸Ǫ$kp(\IƸ (~/ej/v7 &qGn`| N)"!1uo ZC4%(l# q4v6f#u>QL!iң}dww[ Xmkۃ@Dlx÷,@ يB8eU{cڠ5dNo((ޘ3!^s$]:<.rsOxA1ň,7 } /xa1[Ӿ<ʆ^Be")'SEkTTYsN4vH(ƫk% %FU`(h `1F#7^t@YBqщ9Uz)4M+wߴQ$8WYr:tޫz~d`YuY/iAkH୥(7ɴW uSI!\&hk\ -ݼ(aqݤ&f}1{t)uҭҎbVҰ@Nמ&ByҐ-W ;xFNL謠bySNҐ<ۏFm?j=1 D ]*H<ϢSGJY0fKg-#:/^z@^@Lj1¨Gw8r IY8WɅadGj^DĉedmuASJ 9cx|60qCJ+jgSeۋaj5#aX ֮]KV.bUmxs nS]fbAn=`b3q)Fdԥ"MlHTbFn BICڦL Z6bImwl۶m?oBx6?܅{Zm0BtFsqNj--7 ORٖH;nm d0eg?cXT}s=ݒ[佂 >!ssd/?9kPЇ<*[J69grɏN_iӦ@`bhM P>'4Зwf6fyЈuM#q9Pc)N|z֪7H^gž~ڈ+y7'^<Xvɘ&872}H7({1g y JN! S4H \`x:?ZYw_AvK?<.'~~}1b>#"wp@4-]J翍3CD`mL"hyaеNol$N&L!{3W7!2 R uY;8gv$p1'\_PԤ<%}zO19V>v`Jh`"Ŕ/ czaR Z(Vo' R* maY"pk0B~!)Ē۪S"jYqj&dl;֤\(^5bXiS6vcnUT 8LK9ohyAHykߣOsʥ;2[7)#)Dg@*]ݘ.kϖ ә~V#FjaPL^wMn`Ot3%xd7i+Ϩ?5Q+R䑷>,X[+_n?[`=$/h~f(qJFèݨ]PPV*XXo#u  BB&ַ}ktj\ȝ+P(6"kQuW_ (޷ې/#xC`,Զ^;:N~&EbCJqׯ tPY.Vf?R ?=SiWC!Xg5<!Fmt,Z2s i3n/9OE\P*/U*9sŃpm߾jW$s5(gqcC}5'!\YCi}>g}A/z "hlYu6oƞFl䃣!<+9 + )'ah kԷXrR +J1tDcA/#"j X D2:^KHG*A \_YV a? :(*0=ǻb2{ћ_6[)㓫5DnŨ}G%]wy C)'@3VC32[{?8 E~Ϻ`)uI\T??Iu).Hկ1~ i,T]etAC?=儤^m|ONB ^XAif|\r)+jSҰlbt:isuMΒ1Y?2)D2}<7 %K(]ᥓkӰ']m( #xJ`;M"zgmd4tv{12$= oaߒB|[9T[ey7n/_!Exf4/C ,zivvɲ G WFb-fzGYdq$Du3ʳRgax, )/1 'C&BW5')Ż3s #Ь_ kblXgT(?f+;1IRtt"LcTEVB,,Gg?N俹f+eͅ5y}P.(h8Ķqz6݁]B;F@!_\~݈]W9e/ vJ .3_̏@݂[etCc]aDBb PyZtSΚ ?;dGu?I`! qP�4b3A ־,Bb_¾ʣ` /+UX3n/aF-3~P;znJee.Ĩ21x! 2֓?\|RW@in xRk𱌒'V<=a ޏZܙ~}V$R@HgQxYjjq&0 "x!Ҽ"DFA_;\PVSCm8QE1m3پ>>\m2SjmЗ ,%($v¯ &IF(ۿUp cB; P0eo2ll,c>u`wR[Ae3:cA#Wos D$^h3C#>g,BЗ}`vu"睟j)}C{);)(|ztozKwò;w ]nҺ11! w`OB8vNu/ۢ%% kTFZRSϐc5 дC3\\1[빻Sek<wwno=' ~2:{+ #B`B~ Kwй:By~!;y`cauu|׎FiSK1Yp=u#j|BD.}f7#i ja_(IoF`_h5!Wsq{MDO?TW ?`ؠ}cBj˳íCdXEaw?k>J_\; 3ydޕnzˆgdCLHT%]`A5a{p_loLQ/'$u)ʛ cC L0gҍ$`Q0K8/Lfo9ܨegoв#egpDO 9(82xyPE5 HŦZӦ]𴜱IjD&|u|Lq(˜Q֍gSIG,}_q6sO.3+0GgQ s p߃_NcVBFf0jAd;}G!}Β <σS`?&!OutD%= ?Bw?M뿽NSzlq9W mc d 5C#rg(CU$Ip)le4zs9sO.5e%+JgU9A%) ҂JA_]{XԐ2c}>aā>Hb|zbS3 ̦_P&Քkn:NÂsas#>즾,3J6?uwj!$PWY---[ZZZL4֖+râӱF Ι&[zP?~]OYʋ"AUYa@HA89Betgؤ^%ߋOU"m7yS<6_,\_\̌3s"!5؏̂+ffb03sG1>/4b!Ki]&G7 -gp/J'3~1衠.18F 1AAT- 2z_xt=O;G: ټ%=cѝ !ˁ zRH Syݐ!Ѝ<ˬiW{PWг)sʅt-!^ [(3ZVdC.cf +&nƁvĿ+uSLnoʼn7!2?5Ulp::fɚq!<QFA+YZ ~QZ3{=6༓H]#fyƀ!9iH7I(DA?C~DR8&3*0v_-6IoSD+ T;W¹`Z@ 33~=|A8LuAJXR%GCi G <) 7Xo_G6l)'i y%t3bhaӈ eQ^ގg">'fS%?g?Wy>(}U G!Ac0 g.W@C/;P-E`OKQB40#7.YxcAP8X5!7Ka5qɿ l&4; ;G-'G:EXEmnj]4 O;`D2t` \7jж4u[)竟~ê\UTtvMl 87]x :+9I9WX?[ i+ E˛IeQf Ŵ^t(xj*cd7F95"$|iв(EEW$:/iJW>q"o..uFZ Rc~o]\pxSOvqW$Ɲ~̄Jt:-mUQR5k֓zlWח.Ɏ}HW3}ߺjt$ʎ[_O}eЍOOʳd:mNPt' }7 "+Xe,a4aB)J,)>=fY:F]m/uZZ=.zFYuפϯ(sNO{Ix3qԀ;N> [dL%&5 )/TfBE ifu#.8MT=ci]G(j .d" LKN;NG+7v,[i&;DW&4U.tq辟窘Fĉ}` %+z0URDQ9|-'kxV^=8bgHt"ٸhs>ʼn!#]uc]LKLbZyquy/{Ygf7/I@A$/BH23&`6@ A dgv7&L ӫ\,Zblm |h{R>J\#pBfn^Rjnf?Μd^N>9@ qص\W+^ԻQ<t=o>۽ZԞvQ+g 5}Bw:  um@Z25' /b`8δ{BXFm͙sWn:^<|AN;CU ?'R ^7 kX!3oblcSn2Vk\i*o+=zNA('A A *4r!%$+˱@?t(=hY1Wn$-ӂ^׃,P<] ˳N\D=s*r/)ot\4nTb%e0$?*6a\@eao= !;{\^ _O 1 8L0ɔ8$7ճ x C ?G,(^},?CJI^a6*ijx?gog$V3AB)ڡ҆4 H8|3`bV0*_Æݛ#Íh?c쏴BA(d ݟfSI-@=#pWP{9+S[zHHpν<]nksrG2deHd^Lyztw+Y^бS6ʏ`)m{=v^[f;feI-%aMSp(Dh2|C|pc<$EGЧ"9d m =9 q5;;^Oi1g㬚K@erGkH>vsTQ)f>}eԕoAC屙,n8j7Vcg93Cc$ǐ@/LTYGӝT_q{i^?N4IMd6H[ xe.02.ț x]F7oN;oXp| I]4c59$@E < O=oGyxØb"N\?0?|M$mu)bڸV SBܘ0;:&.n%*~:m!) :gAa.ײA'>y7Rc&b5qV˻\n(Egь$ѷ}5#CP7TG^4H88b h8.5k&Qp.-ӭG)ĥ2F /BCvnΏoPJ.A@4"6uc[㨥qTK/t ; 6Ǻ̢en豺YQ̢&OՎAʛWNR4~onN)v.$ZJR]OHs)]RFIȾV%_S-쇕d?X5vê8&aVvUD~zemSuUB,sקUV`Nf8( B ,gi~X/V xQs8.X$1dѺ# Z ;Uo"n Fѩ`VZVZl4PD=R tZxQʽq`l D#W5 5#">@O[E՗ !R @i%dH% AO#\bi\y^;ePfY]s1Rx ˫v9jPO#)gH3Ve8dnDSDmbDf:: DRqtl}FkSߐ*FJM+̙"2^JfĈ AnbMᖣO[Mh1)u9Kos%5_)L~vmԷoZGYȼӞ~DV앿7'?!hh>WpQ$Ž!2- "QFD>ϼzXQpRb\*G06H6**:?0\jf5ڭ4 d3Nb"rfhg=&c Pgut?N U(=vcʽӿ0qnN{/!85Qy$iy"4 XcFSoeaB?gD*&\ND:-bZMmg1C̵zwӪ]n,X{p_9G!] ,A2 ܰYzPnl 6^g PjmZ.4_mr6K9K:4`Dy(|^`HUjt7D N?)ScV/~u/,i#Wfԗ=JmEsE`0!D;Y̢`k,Ng1rX."]>: jƒ?OET+\Į{|3ܓ5s\ Ni\aRa^^mCC\L]B۝RȀ dKwgKWL8QTd6m٪3I3&Hxkz+jS<8rUxI:BIrPkvިf0 bu툫'-G [ӆӑ,efJP?ﴻ& $62L/j-;:v94q'b0$$G',${k'8]>69ݦZeJKQ"s JO|tP0T$)R'A|vD۩6$W^@CeGV7ְ=3zy_3&fT?)Pi}gevF|%Fwː8RAE$}&_єUVx $^lRv\^U?t b'Ѐ>sH^*!mW^=Fj05p1K᭱8u+K[PS=qѴ#x;$ ;QDW;. [r0tSYE X :1#XT7Ҏ`۷:@x(..݋|gߟz[`S~)WBP<ioF+IJ(8 hؖ7C- i%lP Ub\ ,aWZC{F 8POqL~4)^> ')4咘A(|sJu{9=mJ{@;̘u-mv`9fv8qYX`6b,)Bp9oH?G8R'$^1?sյKĚ?jq+){ѿϔPEH~?N1=U ѬbrUk(5}RK"Ut%L|kVۖxxU)*]MU@SDDRUm*{{/tZ\LL~3"aRJq}A NXa7s>_ 8<lyʤWtļ257.-ʓ>>RA7}g |~4j-Ѧ-=<شXyeQLj!=eTo0\ ~tGh[pТylB闙 ;lm8?v[/ms"΁Nqtհ~57pp?SGiaAa31Ф}PDLJ}z <fpZlQ͵Ӽd ,>zW+NFuiuol)A7{+j||o,N&kO*e~;(gu[p_²'̉Sw R﬽K@ZsDD-x6.a_u3ē ge-:mil)q6M\9sC}ޔIB./ϳM椌"CBgv@DzS; ]0xզ$'pP+DU2MCLJi#- :4ҍLof1TtW4Q\?3ꗨb~"f/Nq\~s[nUu ME:_wիWu];s9If}^\̓ ~ ͦ9sz.8=B0lGm~㼃w=c1I~e(KVg^u^uhyR5#0m:΋nal;?[8TX$B  i1+Sc8B4勬镺>RgtS7t{{MZ=o<)@e<+',ti8&iTV|EpZ<u썙 Qd?j;?ҫ°_Qr'eܺtfkUxpb|[;Ubq܃CńJJWը|vb(8{S 'ѿco;펇({FѕkBL< Rg(:2^Ũ9w*Pz׏q@-A-N GyİW5<6J8%y< Eϩwzh8(<XfcB\m4k4麌;)f!N vվƖ缾EscWeƟ[A6>_:~g_Zi닐nHP=H.F.ܛI-zu XQy]?rES\j楕y7/XˌR%-[̽m ~jfN3TqM^rU\_.hj;G>gTTy7^'QZqw[S XÃLpc ޙ9 eqK )) Z X`&؊ؕe_Y!twIPKLrm]6NeWBly I\q:V{PzE}77d>QsF$fdmlUeYUPӴLIUFLݮ?*B-Q)z{Ot&'Js׷j NW=Dq,"%_u`Nr8;ݔEᫍqVPZ:1xuBppvl>#m<6D0$rm@~ߘ O~nll8!N#Pg)M*g$:zS4Af8 bx`dʊ[wãLgSp!3HUd%^94˩b\g4e1[B/GH ^5URla,IEUG\o1-5TAlBDGq(ݻnӇw<%HណwA07n}*OĐMGW=nbD$yÞ&F1pN;x[Daa}:wՇ=LQ>1\pm!=b?0 OQh@`TGa KqGaNV>Lm-@wq_z_h>7شkX;3Vm5(ODWZ Y]Y k["+j`Ѳs2v7 g{}q͕nvO;w>D&YG@woK;{t h ڞZ_v|=ǁ;[IްF{!8+_X4宎̵{^rۗI3nPVb0)\K}uaz[( ԏ#_֔hK[YپwS 5eT{o%Զ1weslCX|Rc`soQyߍqP?L_Ff-|nc!i +i*0H ME8e9+%/+98EO/ g;Œs?u=eUQb,-^Y4Ȗʆڵ3AdeșفDuOqTӤX {O$_+}qe|5KB_ҁE ӌֲz֬O! ZqB_R}fKTO=tœnĕ)26R< GM/aƑ;.xA8l2"2i/~Agksdhƈ!yf-ޖ00Ųu!+BDm-#^?ؖC,XFpOfn?BCWPnrL 徺Pkp(waP9; ?鷽?Fpg=ZD:s֙w=B8I޸ r"|P\c'; aoYIlۮfۣ]}ˋ~톼#AGOt}m%/ }6OiسaNP־pGL+dPz`;}A]{3pOh:GC$%4 _>~c"u_@҃e;cpP،mrl(ڶ`*+)j٢(ϝ},t0 s.$g8lmqL,-le…]B: E&fOt3q& !Pz r8 CCd-8LlN٪`Ȳdj`ʲT=fLC2 F2tQvhH]ű?Y^r "fI"ޟaiJ8 >cT MWƢcKcW}$5|{Oj&?H䖣Rjh<++MNWxV+fڈ!fʃHn`8>K }ρv=|8 x)PtU4}lUa1vA7-,MM^6hРA>DP3?p(ܐ1= 'F:Fuyx<W!Zš Fw7@hcTN|3,EdB; 2? Ide 1DQLNK_ ]2 %@eI`p/~ LA}!uMǀ>\Bc`nrY0_?DERppSKqn!^wnfFߎ3! IE(\9\ EmHG()/@8 iDr>(O3vI۔ЀYH1nS*%vQGg"w hyI'z6sv7,/s6ZYݔMYM%;a[Z'h'cĜjcl[;C(xwQH(sesO"=8Ϗ)[iwg.396RX0aicbYT14sݜ\0|( w=}%CypՆ>zyUT[C\|j =U8~iD4?o?; eNPr"?Z¸aܙs)3n)-- ' .ip6kIv-?Bd_Rqw3ٗ{k+lKOp5.  ?sġuҙz3D> pg8A(Ca8Tыˆsȩ*k3`ںݕĜjciijcZ}$!_Ðd!$b=!1$ "nfvf a!Y hC,j^/m"r z^[W[@Q[筼B&YWݟ;se`p VgYwTK,4)\]TϢޞVTEmE}LT }>]ļ&)kpy> >zE&LpcoCh2d>fbqޟ\%|M__He^E* ,#QhY'Ɂr?E?-H@ց<@mP1{-[頮M\3HHr:}usnFsh81 jS^@_bm#Ř}ڟ y p(Ύ#Wdqz5u!6DF^|m}vΩLL0ƤQ\?<]G2I"Hp# $((q"'ВZ H>nȌ/=/܉q^ǪB/:M17mvUjW;6`_y޳dxǟu%|#ߎFQK f/S PFȕƛ8ݜ~<ŻoZMIEC̍f"a&ҏFR?)h#,' 'ˬ*'SY-AWIZw]Ѳ XV`7 ǐ?6P#IFB uQ({bYS{->iQ*-IPʢMGC8sR7Ef 9w=Q[]iQLvp߹}G|GA`T ­?)58AS=0@y:2Zп}tf讦 <6ØzZ#AJ"3e^S9H C $:&?)M0O@.;ˎ-`ىVhqt /X= i,mlOT&?stW-:1P# C+^N֘! 0,h5e{RwSܸY57x L2d,e_l_Rf$mMQ#iF~AnIA(1Sbhc&(^.EyEC/J}v|1 z}'|u-'OX o^}-F;ڷAP=QE65w FRX2aY)QT$M()HRKKYF$Q鶎tb2d[?y%a+$8DnKi4}u(è}EyuFԬ>0c:8Z87֮dۃ{'U ivuyb-/L;Ew|<ElAڥ'6q%# <]pφ/F?_?'q/ah8&aNYH?g{<ML`&6ҹvY%l2(XP<ƽ9El V똪c79uSʪ9bhEERHMch"Gc$Y:$XA5\:ws~2 m>`Z)As1xôvJ(^wلfdiFĀ*,`_ %gKK L&b$g3?}NSO8eTdL>ty ru-ZdA|B*_9z6ӯGOU#L)F泺U^mIJK$ 5Db&RȈeJ 3ae$AI ՁҀ,1QiAIqL7-Hou?y._Ɉr[[[P>olc.L+'>0%+@Ij80 )I&2$$%_`w*\o%܁-ޠuϝEZMDnC)v%B[Eb]c!!.,ܑQ<O<`s߭$@u>Z?0tIE9\Ȇ~1# KDR$TPd/Y% I[k |lݍo,-9bd77cl/xb 7}QkoZ xsc]3*҅p߈ ^U3VX7rG_@UIGq_XuMg#|kj~v廯ZNgs?,+L v paPNCM5E }I_,,njf]y7䌕p?bqCLͬ ~gx:OAT) reFQ$giYUeb LL pb:f9tt_gLN "F&>y{boxa?J~?>L;h;?=pQ~G'pp{8(?2Ҫ:?cXC!fL;r:94Ǻ,YO ⫓Nds/2F꣒h"D$Mk4MD.P ̄?g,eD%%1Q sxnTAbOZ7 M!Ou5%_/K`Q#mmmz Y܉>w7L_e'f=eEnm7@$vM"Gg_ T-"NѶodP}T/A9\&XR 'Vnᒏo{JuJ:8?,WAd IXcAs[7 4e3VWGQGǟFDYօ5+>PVL dba1!fw 2g9c +fP1 Gh()ԸϚ=dwE?(}8!? X7:KpV߽]5 L6E|U8uP$jmه7Ԥ_ 6z)ߕv#7N9~{xvy׉] B߲C1$ZPpYe tG~"BjAPb{kQBBotpv_<8 磏m]oBB`[46iv0Ӱ;.xxQvD!Go ']3͵ThXڀkdZىڬwִ547>)S)sNi #Xby4 TTSj$zTTuwWiv3=.Ldg,7CŠdz{g2 {]$!.c$ 恔X;K D2{o4*#}nPwTg*+5<^pc čXs|WzVC'uW6lzfLeF3=GVTF(ψ+a-"v `L;R 97n f_U ^pƄ0f"=Єulr!3hbE7%QyU9U++r…&Oc\0 =/ŠP @9|2_-kܳx8PnEbNUvD"9L"+x8;g$X @Q‹d~ r* j(ho?'zD? Rݣ=s?HKm:H_g[lLZ3N-Ů8r!=a,Z#+ﯸ|=Ϫ+6ۨ[;\&T_60=^̘6/f#He"S7?UDW._/QCKt[z 򿦅4ՐU AUQL!$SB!# S1iP띅3O'Ct]؍@yiX{<<n@k |)Fzi~4̬ /[R;T--hLF[!YW_USd{}>1,^;z1#QrWT-i GGlY瞮A~pQDy|TxVԏ}qdhV8.Y\fW+R,[C+.\PAѪtѣ{ wի֓;B9i7m;aR-H"3q,[9ٸ)J1ߝ-ד PE0Gq_vII0ã$b佐2rPeq&fʌ%27Z`_ r@1/ (~yS 2,@"+)%pEbeL1+ $S}48[h)})c OTgWW.nЙ8cԙ%=H?4ɯA4۩ 6a0P:,:\s<>a * {MH;„ z_ǧ5Sxۑ4h0x&s!"{ZwlgNvw NtOCB*em O8/ȤpCHk=}юH4ut4no߽.@q3ة1`/"*\ \043H{i5VfWʓ>fU&L#w /l#B4"D~8?3d )V0 '˼ YQe&t .$ˍTXs8p$J V0R2 mUJP /5ǁ5۶ h6gc'Ϝ6wKB/Kj_ͨE[$_9O݁+38z-o1(Em7ge8kXGWK=xi 4Um.mH ~F~YjFm9ٸ7^m/V(`Cտ{vSN5Zw&a4)3 ??g4H+oΤsl5p}T5/E>d897ג7nyƂ/"[PѶ?Ξ~nV;g,/{9ȥ2Riᛃx OGw $7-Oݵ*1M!6ǘJp:C )n5V`"?8QWTU䪴=s PAF88: }ʩ$=7ϠnbsSCMpL$ h a@+'`d]TAAgU08Edd59ِi"BMhGlOUs~* HKSVth}~S WkIm8q;܂;; ij+Qw(9ՆZYV3&XU5Qu@jR[[m`/܋kp^i$I"24d8Ϯ~6կ{f^ )!(#) bX1( '?za힧AbK(1˭^Y.\lP~ bCܧ Q+pveQvwlq//=K030%Ty˱֭V `#0%JĩohSɳ=ˏ߲,&,1JlD3spqq|ge byt"EszZ'ߴmALJh !3k/w"/0n;^&""7YVQ!7*8g9A;\C 2qCIw#(g+|J_Q 璥:9.$|i9K5ל%+28{)w|xssn ׷wnY\ˌ] ?i7{w;BגZg ?9`y$w5XqǪ8cơ=su;hbFnrCkzvM_n >zMNoӵ~_,w &/1yJv:[ם?R# J"`ڍ|vT}i񶞇_7"0Lc =<򉄁fl52|dߌqUEx\.#qdRK{%" FG18kucp|ȑt.tM~(W(vqs<:kj^Ct,ejTuuX%F7U*{ĎT_.ebG}Ŋx8w<͸u{sN=HyΚ*w ՜ׯXZd65k}[(G=U{A#{%E/Y ki3.g{VjE 33bW ˸]Ya v[&[Oҍ}OE6__#ez"!N''cY8@qOϳSUV댲J0xŪ*V&a`>oN646>U_ކhvű [ɐ%[oq9$b)#G๪ l1TvG<P)܋[vjhvn"0ᤳtf%n){'oW w'l LI$DIt} _ΜŗLXlȐ s"bi _b`ī9^dԐ,ZP *{{(k id8pqC|o~o]O ƭkH }wY]p m5=xʗX?AQ57BI!VW1i,,I B?&󼻖M@.a& `x, 4d6n^o<~{ބp!Ogq ZE|ںҙI t2m9 W!FTo*fAOI8W/2RTUįb>d"~ $h fE!?z uGy vYǯTU#'JK;n=@1P&oTMULg5rUQ,wK{5Sݨ 7`5!8j}a=aTk=3 3Vҍ6-U~oyyc7?z_ʤElL5FtpKu!6xݦ"Zlm xgBDf]\\?ru(Y2q_1:h5 lp5\XxCm8Bi8fSGNY7*=uD g%\U]D|Z!ć7eL#_P({ :"jC6ޫiES>Qyɟ>^0Yo{ z` 𮡅B? ;…tExQv8v!}<*ͿJD@UA&ґCѕd$ťDԕGͬ+5xߊ;Ǹ,2FQc(܍?$?+K4 ZhQ$]CZ(QEɨEb/@=.! :]MvʘCیȤM3)'~x,x>y1D=+wUu/31wny<_/@$&9$tOUJq)C~55{VQp B8A1γm4'2A\ &A a͍  ɂ3I0+sBHB<@FpL?8SVXq3cwyyU-%h^\ 0t7x{ރWmq/D|$reO#!-b.Y yCś ]q(7 C21>{}QH B7fy2>??vHF56kʈ\aUrѬт]/c3QN"% /8E, ^ W :Š}W;v% sy`~7 |6#S Vg y$Bu6r $߲?R̝k+[!?MZٸ]s?{XWaE6nmj3kjs;skk<4ש6 56._hT@.ݺ\636ؼZFkj<)  -!Y qlXhY("!TTao@z_BQ DTAO z;ӽLVo37KugERX{|(1"mfUHU_,'qaRA&yUEE U!a ,ñdeY>AgvD WM·6hqcwj$qfrf%kɜZ~OfRË́ռwɭiL~ͤc4諴cfW!n&W}؏7MrO$>3]v\>#G޿i[18seg MD-v猞*9M;t~ĆǙ{Ù]<~,v @,d[QwhqceZNg!W82 FdPHX!D3IĬ_J[O[͹I\@db침v'h)1 4;*ÝN~p /6)Bs=5LTx).3Uࠖ`p,Va{ y F@VT*D GAf؂CV gԳk~CԚSx9^ndn{f $.ߠ+yjsZʹ u =3736*e)Ȁ`=o2k XI:kalEU>=KΝo_ v̇ȗ0 '*ou輆BZ(x}q0;g~MO:W{\]lwr(C⽽>Fu_f7 WTNbh8:+DYZ+QFԣ}? ΗMUDbW#3zFۢ p#C4V-\Z;: ǂssN(.{IXjÇyC3|0\f)ު[Q~^@I{^ aK&گVB>#oM^?HͩQUV%]P,!.453ЉܐSlT7NqJ-^NF:Œ{Ƚ1d^ϫ0MꤵMauw=btVڋK,]{̈{HGir3,*0yC/` P]\\\W'1rEz7d8?n"huBPg^&>`ѻ=n|uS,8LIDRڸ]CcSYH ?Y㘐$l$GufE **V>< f@ e"0@[oKΏÖ8Ե}zL ɑű97`{`ʺ"m5!fy$Z5,$kfc/?_!Ò ,B H=0fCJbSY1YAD?(WUWu,"Zsȉg~(8OHRt 7yg|N'jAIB3|],Eu CfMe=%+D;"Ta*ApӰ.;l>'upr<˶jGm38쵓/r gc%MQce"EHEQ(* (JUޱ:%B^d+6+efGp)Co:C+;˽4eðclEydƁ+A,!i7xX$sJfh9M:7nϮO@gX؊jw73mNf0|凔b~E)E0LX*qle4Iqg|%nHL+[V&%h.)J:CK:+p!!4AlXBJXYZG Ibbl)uGa!(TBW'18[cp ɲ VbfpTi.k*s-[㖧=>ɟK& ~p}㦔Y9n 䭷V=ln^ ƛ!yCݸ9x> f9H~wr4v#kXwJ?zO|)f☛9a9ݿpI kzG:i10M9\֓NυR= 6y4e{1xc} ߱m=,d! wMvɭ0p̝{>Qɲ/˾Kbgb&U܎q-WgH}EE;0#K.(!-UyqL=I$N%׋o?j$LdwWJ'7]-% zZ 4UT:T}}h_y?GZ~W5egSԚ{'ǝ|瘯a WGΟ[rzkobi*'QT *$T.j;k%O GGi]AtQDi]0!U`ò'IlV@}3ǹ{J)Fh6ߘ1ZH`qDKmUDL߬Ϧc(ͅBl7pij`CPYy11RVm`4a3| oN'Dc^P#>TAs8n((lM4 #ނrpZ P*46,Sֈ[4o/6}дj"}@7h*'~r{W&ttxw){]264)@]KBnAv4a+&Ve$Gp4nFY^AhZ̨: `'a C.\s)8t%ԍ9s+`#D\Z.њ[yϾZvc_)}݈p;g_)_`5hp_IJŢ`brЊ*o!VE_lƒC{~:*oo1sf;00m]׮.ö<~\ CBPA!ұf.p wuvd1b )Ľ@*@\͞i>XO4vn)JJxB^Tb洍!jsQhڗ^ 7<ԳdWE1Dh2V AY5*K)| O7#xZ%$,Q#$FkJkF"O3sGiVљ(͊g23 0n^H!a'dNn6qBC.3b:qyݻW]w,zoG@s8w|EO }^smKxB9=#LP@vQ 6^NiI%cD1G QUՐ< *If_/@t[cC(O? 0a"ifvmYl{N _UaVv۷^Q䅀DQeVD^+{b?iCCI,vaǻ7mn]tǻ [Űsڲh)nʠ:*90DeZqa ǻFasz"`u% hްFԀpY;tDH9MK&dIHVN 7 T rk7ߛ&};77èny%L >ylj\}B)-LQS&J(15t4( 5WVeS} }4U$I HLo'oHӈ䊣G$pF7c @ΜʓMr;Xix$`i'O݇08}㜎i:ˁq*8Mv\  )@o$|sK?FӲz=(dU}PH DбHC@Xxݺwawڣ%lYc3=QMBⲏ DlHit T`n4ĚЧќ문ZÃ% ,W:ar3Q O<}jUl_΋.0'z!KN8u1ge?jV([Ѵ^)@&z6GW4. ڂ+V8A4Vi@׆rIL^r4D?O{r1haK?y3y7'~a7aԦM8g!21cnxJܶԀw3z[VL Ca%W@.^va^{)7.3=4DJ2޹  ] zR{x~mccce#&+U}5xx kKpZfFuPc ]_?/P^k.f+U_ [ɂ_W˭.]jBe-pV3v-x|"m,:譧P-u$WR.4@ 8ЗfAYA `Pv8; ֢lۗ 9ɲ*#Vry6=lU\_UgZz lU]VE3UpN, rv-bgf66W?nU ơf%ZV WOF;WEea-2iW'UP9sI-~fζe.zn+(vTuvTpi'nl 'ss 21YҘ2~ H̅+aՐg¿lLF3:VE4&)Uq1\-=u!~]G坘 w>/v Ύ)lqCΝmhݜ3#?_jTԃoMi1S|w(yiU{iVh$á /$e9..+C!!"SM79l֭'NL8q&'a$-]'uZFO X='*$7zHSO-jzb6Bh{MqYYNfBOYmמ Se4RݼDIq9l^ՇvH^L܊PLUhCV4"hVE񣝈f8-׿b$g(dQX_Tb#:[_rWA,'n$AuI ҉ZTaN +Em^M FX*İ'LS|? x2O̫2CV4Vb<?$CBD\^E `:롐@3#dOHdf9~ɷ9.-N(OvC22A_ ʁO}gՏkXkoa޳5XE80 r~%Bqv[儼ŒTXlֵI5#oEǰ@qrɑhӤ gaAEuOvfz?Ii!zGIANzeFB1K:dsA(!\ƒb_10dm`i}NpaxѽƤi)W }|@c$ϫJPG)?=&(ۑw82|LݭvؼՅk)*B9[YyK'GyȺ:`7] v.;'Rwp;H: _1vA.Wq$|^WJ=] *7—qoD#a*VOTҦ v]Ďn ӌ5ałrx=?8ʬ@cJ2~\G2 檞[=*IQD=,;89 ry]oSt%Goo;: f?&&D"a ngx l=DȪطlȼ9aN2#ݷA}M'2;.ڀԆ|W(E1:_\ L7FL-f`_#W;P5GďWveRD'--YO{ k@~l' ,*(# MMIYJi4oh(s['lw{97ȢDRޙ`/cl?*/)E,32Y&ymv=\cA%|f)-`Eύ@P73)؋ B; ~6^fyQ!x8N@k(;gѳ3u; 4qOM͖UYn0 8<ީkgyϭ"+HpҊקTCӢ(("ӌGQ|NG)+}w~:/RH?Q^۞ʃOw(O9V!pdc6\l8 ^U,8rO)gEMH{nST2k> gcЂ Q'0NBrݸEt;m9+yB5b"M,u4zό/g◷i댍;|oH3 E4d %Sr9F̎x [Adi{Cٿ;xЙKP qsft!7G%b"8 |ܙL1pO7 ÛYħ5@f1T٫ 0O:' 77qaf#S>ZL-ۿ-#2LIe~MeFFξ5YhX\(餢jKp !b'IjQ,~Ha]ow+u^lGy/&uXtUL "黣8OEc<*G˂*yYE UiV~ji!34+d+@yS|ȅ - h65T8nKGݥ7DYk0P'/?.' ADXR_K8Jvn 3}ʃ./E9Z xX ,(+ UTK3Z?H5e?CBIƿ3c/aG$ՑH\،N8Pnu/_t#"؝%͠LԢ9*Gg~!sՕyJsԪ6(˚~h\k(Dzmm=P׭`gc9l=cW(K{p\FS܉4 v=O$StN_k |¿*?ߧ?m)WUNeaI8ڧ(pWho@T^ޓ@GQezI,qɂ!@BjjcH 2PAAIt2QYwp~(+qŅDェzݝmWo{]8e b@)ű#tNC@2ePr7A ↺i =(a5E555'MFeEc35 ^W_ۂĞy Í^qgqRW8Fg%^c7MX/R ]O#%ve;enJ:7+`;2z7R)ʩ x[ɳׇr"7 g,9;7eѰU՟ejmX1̞ke(W.|1_ݳZ(='>ʜ2ck(D"S2u͛:b_$'f>A 5 r?XSR4pIҀD*7áII!3ÐAy`kQ qI94$d48?_j?2K5.b"/2ɜ &u. +8C0@_Fc$&e 6-5$6c :}.]\ z_Ûo{#Z!YF ̕b8%in2s ."柀/>;u7 SS{eЋb* >UB 8ơp߂"AU *')1C 's*gr Mgz/B&CInV]:O}Uc93U<CTTj.AUA 8:}SOvTD#SWmf3w4um̶SzW3m/>E!&  .[xg"~dBl/V9F.)Ot,eC5 A ee6&#/~h'ϑv{꘼Ỏres.'A!r oLTNv!pٴfob죵U'EX@nyn+wL?"mSlM< 1г-ϻD$#&}zn (twrMǐS#C$qұƬr`*vxK.*6u*z^p(&bv^觡C::9s;I78É`VNf3I3ڡ@1Sf]Wu`VxQ?߼9c5ȗ?;m j55o.W_Q="nU~cmxe?W([+z _,ghKqߛFNsN79å])5N`Db?1& !(>MFq=u4peD3@ j=!3u!m1W퍓z577b{ts;9)!S xJ,'(!3,Y  l>6s)O t!<`%";$"j.˾N0in723!?v8ϤJ2\ZgEon[yeXPQ}?Tc]hnͥ} Ni/=&'pףvި{ؑS"kǯk n!VKk"(DQ%-`h dNe Uc/KIb5-V(AvɜOSI/[M4ҧ"3Zmqen~7 Gà˅}:oPO`@!:Ak.}V1,BBMUAy M$AY51%G;BR m6 ?ϗr0 }AE,RkBE?`'ri_N=bEG.%|pi~FCXOH>»5$Ss,We^E]` g( +|#)*(i!QJ%Et# D<"x}ɩ?t77G̣=CwϏŬ o0sG,bv7Ha}:aU4QL%F,ay]&&?jbj>'5* Xk oCy.&20r*_rV5jq%l>徉F 4[N14z 96ځiD*j87u&lBx]N ={1HwПl)1)>AbPg!VF8^RJ4Qe+bG/˰)OR %16mU(Osj !- Wq%! v;l$Uao5(kshϛP@:>C|= +V|GqmPk9i8oBhx <//n3H$s~2s2\r2*? ]g,g[nY AhPa@}-wE൵Y`04BW45v2J NJ(//𓑮۝*U&Y xEPN  'XX_];;Zn|r ER`Fj )e෦fM9?JAO+d.`Eh(3wZOdۼXDqiՈ09+nhOm~z=v|>Veګ/Ȗdr#sHr7-ѳa^yZH?QK~FAWE4xIfxt"2 _rl?K%GQz[",&²y.5ϟۊ/?sHCYPX w!T&/nE'Wp?`h]b Q2jw_#ɘfNfYt?3 >QLp"a"ZPve"F^tR<~XOY䠮A5Vo4^ h"'_%)@J2ν. ՗M|}.Rm'v{/q|0M`eDcJmKTv]i$EN63럹r]mOM+h_p52*ڞ`|!ݘ>|xOמu_ Ğ *PET+ u22o. @^c?$VN2`HEpo$'ʕKV9w;Y\?U]-JRs 7'$5xopDSߌNR[$gd?Wz:Ryu}momk#О7$xz )8}>'d݁Dz~tw Oںmka֭[x^+}N7noC:l+v2SpCBvH;G[=U8/)FQq~t)\8sD76S!CS;k:glHBA $!a޻CyB uhE*^Z(p} jZ^_TZ_@/ZDH 3L B.ٙsI %$z{є : :;RV?0ZF?Zos/SeGMH>8w u32B_(oӼMK4v~kyydpTi"k[ok7  L2"E*UÁQ" &6u#E,5: qq@}}Zžl;.xoP~> m0e?BI@KU%(ƉdDFetQ_GUNR婵 2> 5auHmƺE0LdJ4ÍŃ> C` 5f6dΖgU%@>7%9ܫs>c~ ޅ~9vv[.G>\0о36<j8 W]M5˫W Y7ɚVlR,]{~eTpnݱO'C`5>}XBmA"@e\_t6vQ_#j]f'5uwCá$HEё1#I7T*buj4$)ɠ̤.]]雯KJ:uk6Bj@5=)3QgL(2ZN.G zsA7Hc U] ~'1;~Y}oC ɪD$C@iHx#eXƉӉ!,<, ƤZ+ @4Ljc;vm.zD} x 8M/i/]), usuF OV >d{b[I;wu(m۽O/Jk \W>]ZQLu`X{'Ŝri&ۼr t _]Ld<"N8:GAJ^/^4sm^6e+V5k(۠jE7P{rOHEj&*~Z 4djN'?Ƃdx{hyO?:ZoEZ)|Ş{Jǵ9YRSS'TΖOcb72_RלiLlϩ |24K'8.菞搣UQT&(_^eߙ%sE{%qX v?\ ^@t |1E[tU.h1 EĴ{/Xz.X?/S\/gPIx澗zR.~%{M8c@6^~La̖!j}|Ah-o J =D&\hOZ69>22<x6id.δBzDioQ%i9ə'p<,%XV1e辢n}n֭[MolOojy+b|u\^o?lǑ bt辢zs;<%(FIm}} Wrړ1oN_ABu8w)9Xm)Ӯ'[uEWСΧw.뷠;{f7]48yG yG>'#*- Cdm_Gj?5.SAeXStY$.Ǹ\}M0cH%:J!4jbD_|u-1Ѳ\^ P I0 @*C^kZ]rcB$9(#Rb mI';K`?6Ienlp|}7|z0d㫡AB\O4|wP+I3 9ruc.C;OrG~iټ[7XF}9W0!h(Hsa'BB)*$%Qŷ4Rdcq nڰ\xWQWmw/20["_⚅E5#\U9xpo 1lqW=kqWgk@L~F+c-y~ [۲qT**){^Øxя'cdJT_ܱ|͋ 'Q!*bg1 2Y ڷ51w r8[gaDݡt@<\g;΄]BjoϤ:.>' SòS5mcV4Q|[7Wx N!(6h^eUbR'G9T"CY&; &5/Ѩ9zi:i\+(Ÿ s߇%dz^#uKKG)SOIGsO{;-7-vA4"W2+F{$#գ,2FY$W[C7F.`)b$bOkt r% rHViM`YȲAYRY%2mns{ٵ+d GIt" h76{Ofꯈx`{:8?b-pX膗Imi?H[z/vZjv־#"3>4Stz4waMBlt{strH<#ȳ| 18c4 $Ŋ"Kʔ֎-f:?uf{mouAnx&r{Z 4"0 MMUu;+ڄ: --#[c(YSo/&hhO QTFF)x.AGzN/ SV)6K:PBq(1f"Ӏ̻gPllL2}5 MZDJPiHuWƍzpS(#REXGeɤRIJ}% IHt/ϔѸX@hEE@ _/ˍBY"P!Re6(*R"I3 õ7[rP4ua%1]&ZHqDbP d:&J  u'lm2t01 Z¾ n>k\%񶖾Ǝ~*{yI D(f\O+Cl*oDK9F/T[qďc3oc?pGg :%:?ݶby$ɉ5>Y *" JXC!J4)4MJ!Eht ]QNXE9 6W}W4yEƣ;v(v2[*;JX𘂅G}5 r DJV(IaYWeX֛v/Eq!PvNݱ+-]bt[hsC9 @TdEPj6dNYR |o N^ySPtCRru_M| SSMEf꿫=\*%KX0G ;\ퟜG d8^aT BOedVV(ERE Rs;9V2_-#_;~薰;\ѰetCM:Fߔ12D"H1zy}xl`R+h#MFkpS!Wauw|)RT[_5v|jn~35Oe&l|R+ 90o:ỵ10)ߘoG h8<^2m{;v vY{:_SZuH {al:3C 'Gv}6'V4E{7GhBC+g,g4 #`ڗ˟ef>i#K0N39?Z$c r4%˜"1 $F%)T0 :$ 6,:Y뗌YD4&Ffm2AƄT5n86+OQֳw}* g屹96m= 7 >+f>aUp.1>Pqw8 /,`tW!G^4>'N^4)u 8xB^ˮgHϚWJk-d!`"|qk{9)P0?ػ(sfV`$$@3H Q 1 j|UWg{}]\X\pkjz@BH33{vټpݟ~09;;3g}! i$P6s~VIX !o4 CHAaӒK=0FBHv~u NccNFhd7ґdK!$%hU0%ogΎHda3B\˻Rus}kmֵDhrf8=YAb}64v"Kh_gx|YPRAziK=i^B(4h"a=,sФXEX$E5hABQC(˿Pzi M=]H3z}:ю倍(GE" Ҋ_{J Φďb)}:zG _uG$GA(8|ܢ#J`hW''ç"N[H4E`-nPIzzCm)cɥ5o4?NߛB*Dut]ۼ^}aJ]Z fl.v )vK%Bj-x_mkYr_h|lڦG֥mUmׅP a : 8cC8e^4QXQi4 ,qR"K %Q<%eQ|"3>Mu‹]mJ}6z/rZ.==}xkAm ۷kD+mG Vƕ/X@tg[lv-3:eƼ`2X__?o^ (xb`[K$" ~`8?%S41.sgE^yJa4i<Ía9a5ØOyKg6 @qF袎eJj74, O^wӺ,&v: L׀jxހE ,:_~`r%8i!I-TP0tWⵘkBx7O_ ?^*N~iWwŧp.<ݝ~^dX6?`y5H–zWCgoW  1~~DU5Ē%|VU ׌e^E2 ^ÐCEx Ҕ*riNq!?z0`+̊Gۼ7+£K".@!Mwꉹݦa!" ޲-rGX~0jX^sѼyPefTTsu*uZef-Pg^֠7d5Iۍd3H PZOhrMu9k+khQz;@^2=NXxYxvn &-VHYǝi%NoۓǺ5 agg)27PRь"A!i!q4mM 3jϏ]fypͰɽ/*yUxO ~^Pu]eTj_q7;BxuKԟJ9uZ,(*6Ov^}YOxfm[|,ٳ(gvdIbu6Ɖ9BEɾ/χhxoi ;WQF?{þSfh̼ cك%>DJOOŜ;ϋ~)J%A4/Ê*o4UPt,?Q|gNىMp Xr-ߗTZjS,q8ܘ ҷVNȽi~ Ё{CZtUɛ{s)'ȤрgJJ-p8#"JeD SS82{Pb l= @F_%tj Q~ZUկ oTJ?ur1i4鍍j!֊ *+.ىEˮr#B:-jGAKoZHAN\{ݑ9TC6K գ@P"2Ϟ]'eOMuU¢O۵r}9fDQ`ڛ~U_5oh^|7y|~b(]YA{xr_/mCs,|<X2u JswοEQ(JY B֔9Agd(Wt5?\Oaa$/#z/1ҳKT0P_ZrXO7?A՛hgN;f>s}a}r}+l 7mGajqQ^W0О^"c94j#2'f 28 øC(6oFޚP+/,oxt~~K9xKDΣٯvXZn櫮/?j Af_kc#x`]O+X{c7_wr~Net8S*ḭP5V%NcX(qP"wNC`{ { (Ƅ} ];iCۍ%%KkּVvBuY(4OL3(0qkͱF8eeuKlMhLٱzыeXJf< [y/*B~(QT%]Q?Ŋ`ВǴ źOŅn;Jr [t^ !=_>4#`F2@d&ړgWkwڱ)o}e~[tY_DXwO|P OQID߀:>ҒL,͋*gQ "8mǃIť\ӋCV(5砽ގS5[>^¿sQӞ3Au;ʫýqXR-2)ΑH}H-ˎXv c?ۑ91&W]yx? Fb%9`XUuN)Aj?t =[*^NAc  YvFYpaN:^rO >{:cGNb(1.a0 ȧO;7_riWuFXFAfU^uQUh)U) Q)7`EqˬoC 6dF2?HwL%/Iز4< '>19M$oF=O2`dJ֜KS%2A)$2y&R%P; )wD`LÇCBx=A@$3(P؈&z|QB3 6Q)> VIZ.\2Ҿߍ~oI}1L,<;[}FxB@ɓvD/VwI 2(UUN aYEyPS)ODžN f`~nXS$At1c]>Ҳwku`"D/1 77w3~s'yCQ8U$I)VUMTu(k4c/2_m?r?.yiQ"zN 1hrD ΀P#YDWP)>L5U]?6̉[m֦ϫʎ[mS‹l';֤ h|xvY7A$ѺIOʶN?nTS}PuIbҋP؅8KX =sܠCP/ʲIƱ+R p <ǕG% HK?0\z2<=Sii_AuA9S:;ǎpw-ˬuF vߵS~JVźR_2nn.# V,8>cX&$7HS pV4JVdAdSuD󼢲:{ s?ql{h瑤}mѲC5UN:,xTu*B_tm=o/=)0-Jt}"fEي0QQ*k$S"0sNXUyEx$eEAUbP?PoU{Xa^kY`&$Gj`ۃm-k5+K"VUVZz@QdNVg6 Xk:AߞZ@5_+篵}׮t`&PPhZ4-x? %~KǙWc,PRɧ XRQrK!142⁜o>H!'b)t-䣡tJ&pp ˪W̳tNe}:U@N#GLa<WZj=(,rrsNPbae31JŤM3C},>ky]difۋUg@= vϮ@PI\F p g' p%T~,!jBeke˅`=k#r_k `ܺzrqҭɉT"u,JYT` rg}cEYjhQYAfUAդXe? VK-y&1l͇5)#Uirv?.Dk:fb_A^BB+YbJx@@j<BPDJR GYƶWRU֋K+>k{ュ2ٳldB;~dgwfΜ93w|y.'{޲|pGwHe]UtUYEXYSXV2tMc.F2.?mGp {wg#> y{4Npba5 sT?Ht1p?MD9ZްH^qYC<#s"e)zȐM44E7_ )T+]"4÷ ^UE!  {2 X5w'jxt.F?D1>S⠯)Gvr6vGr ۗ+p K[\qUY6dyO7*y/#\g.xWd% + ,YJ(Kf:9~p^vDe#<3["X  Â%ONp3 NYT護/x?9r 7V7:#]A@r/DRUAAc1mNalX!}?]gTlQbh awk<*} *\@Cwg˽K@E}ޱaS&$Rz;Un$@<:=e۳A$K^#wb~s9I91c 5a?3ɉ,KxĈp]}.,ǟ t쬺Ši3~n:v5لFw⤥N+[ph;`0X3[=y/\-}RYqݥZEOx|;dg-_ʭ(3cq3!2L,h'vUy P Fy%z d gqXRNxb?CuX'7F:AMȲHDg&Lzg&ÿgAV.WlT[/wݹ@5SjTR%<( Lޞww|"wB!ej[1Okدbz`dUu{e2&DmOLSfXGh@g.xw9ӠiHEuZQщ2|h09"Qb/h%={YLk.H$2+~ m}+fZߙ*bOws;6"V^ %MIv?pLA%7!v $M@R䫽z?ɉO~vf#%[ TB9wyfৱ_=1z3NJˎSqjHvs`҉v"9XAU u^ 7Y%Yf%EEMЋI_z"'nύǁL:̸?5"ьÞL 闑(L/w'jZt+N%#_Y {s G3Ԅ.{7޷H4WM9Ƒav& :rRƶdZ/kI#Df,vG2?HY$,iRY08Y9)_?u|z?+א?=}: QMlZ^2щ 7#[y-*߭)óJrbLsrDŽQ@_SFmj峟Υr[w~exj}+liªJ WBBTX<.]g0 "g ^cEP5I YJ(zD!@{w?#Ao‡!?<}ꢂ!\o9Mܟ`8OX ¤UY2u1_ۤMaƾr+擨+X?BYKEU"_v}u+77\v ϝmp[J7 (ށpBڵv[QD9"/o<Idj"2RJ߮ez 1@k|T6 ޱ|RŇS3)Xxf}D[Z$ ?pѣ\;:u\D~MvP亱 Wu9u3sKv1Y1#UZ FX-vX,M״5 +yRfN}F>(:+jȡ-%-UVeV4Q4D)TAH5zAO>X6j h,'1;Z~7#j)wN5mI$᯺-cu,_H8;zLnY\ rۨmEuJM4CLD7\Z+B h,\KfV+[[-A"ѹEd:|7ִeEnd b2 >'Gc/M$xe}ưF,-C4,RAK#+&< WKNx_Fȏ]1t x#; )cp ,~,_zHt 1?@[/YTN[{Khs"PA_D6<^S,,[nr>۫s`r?n0>7qL 0Č8:ѣ @m鷶7^6looGbnn<aQȞ(753"񐏜(! f謲N[sͬ׊jcv.8#ע8SEӹ"S ѕ5FL'HQm]pɶG.˲c2o5CO"5xCٍ! !mL3P|ygj+y_W"nESZ;RR"R U8K3!x 83 ;/TccQCV5~|xu;v_-Lǎ&[Wc&tbfڭm;wΚ7~a,fC+Hw.kcrXœӿA/È!ÔDdLV%C"2Clj:3ӘӠvяs& pzDu4] pK34i_K#CHx !NeeF0MS`ʼ lE>#$poF@z;ʎ'=dx?@ ߶?⩟8,U?=O,-a8mv)lƶNvBJp q)L-G@/%ꁾ~]u6SrƷ\i銽/iAwC PU`!epnT %#MeS c[wls(doA8Q8+j!^()1ii" 'DWF@)ӗ{o"dhlʯj7bS:"Tl_f=9xnYfMģNhӧQp膦¬hG.*r!q)*EH9DleHhД3sq-2=71j1U jKWMHhJCT\=զ+Ml{f؞R@|?hvF"f;8E291 $c< c=;'c,հAw+*|Gg.)* Y;'^-xTG %wF0e[0ᇁ]FOs?ESOq ϚxՈ𦯤yҍ_"ȲV$SYY,1PEUӘY_PF k$q|`9!%g/coIJX|PgpR?j{ڥ~ԏk\R,$ddR@BR H⤀|r.gS@vF)dB[qQ@fdEfxTIZj "(.HX:L} /R,:5=ρILܿ[v;ɿw̞מ52Vnau9U9svCyS "p#st~%}+ֹ)}  Nd51 0&ò,1ECt?1?ْE/_SmolypN|U@s}~] 081ծJUɕ{6}t$gy$$yC34Mc%b"jfZ?II,f@W_8$"j`Qmdm_p%SYTaܵZkIdM;a .np LF:5^5;\EE)%u~_Ӕ?5㺷ڴIR'4N'!IՏV*8d*8}_9(%:RDUR8=XY?34vK (ES{ tVL-]:;kڥaحy.iЋUv|-X|Ho].jxHP滜2ٔWepg]1eAj$ِ,S4UMGQ49s5#4ߝ,DPx{| )l%@,vd&c}/n}|<.y S9L V:?>ƻ&JƇy߾$O] ك]su!ԙ߭C=(qB֕M~]MdZog#۩O*&W4ӑsQ?t3C`7/ˠhpч c>^VVג dP6=piׁD'u pסBo;J@ G{7iF0>y?XCwp,Ku\ڈP*U^8"=?,}j LSeU5EVmQY^3Yǒ 0yw )߃ΈY0'09t h/-_38 6vCT `| ўh&t4V&'8a }-5͘`F f f\]F&4{vO#Cq<֬0Ֆ=N(W8Xd,c6yqUq=s7# |ܲ'7>1v%r#݉1S'2~0OS3xS $: AMd8Y3lds:V܄357RMip3|M.Ȧ{N|k٬:SlVA6KaPͶbžb(Ȩq_: Hlۼkɂچ(J"aJ&D-on8?Z{j_c)oZtUhBjFЂ>X2w:*K gS?-yq5nC>F70/SlSA=s5bF0"0ou~ 2_<<0*ǫYL?諻pj+;e艓 "#F!6SMKck.>[/.).^7Z_/m&a5j%5>Ըf^y6A/8*RV Ib_baxeO5m-*gz<&֪jh-o-ǧ+3?Ȅiԏ 孢u&o[[:/,躤 +*'x0q0YQu$φh=z -mZF FsI" C| 6/Pkw7 2T&whrˡ|ypCDߐnV<ʿv| (n KY 7l6'#DPr0B^VlU5̸ p# dѫs`_݅^B}P+7>484W9CM[MKvduQUUeQ%ItpowFO{LQ87kˢe7u ֱm5-͖Lٴq!!%wtBRĭkB=kU;~6ggGRc?U=Dzl98$Sr,U)6Mwtl*|8) P2svnj?XtztqvJ&p2_=߸v]-5SNl9d⟢W'_Xv:NN)$ hgj3Q%v,X%b|CWȿ??Hq77OfpοN/?"a(ʞlODv!uO2HTT:Yǝrod$j}^$+JN~!ȣ7¼dts1ʻv-OIw] !)G$38"߅]rT+eNFofDn[[ _ XKYSyAUd6XtǔQY=pgVg$}OTn )Di2%K]{r Ictx#^X9$*(lԥpޮQ9_Qx$і hhY9*om i+/f:?"/ZT<X2M(޿G`ǽʽ˯Xw|3._}p[77Im 5>}aө x"?'I!8R 5[u8EMTQ-Cl&XX?5_ 2KkWG GOImH N_\6AptkN@ޣ 2M7S/ `7oEVJ_A %-y@8}ç>Hw3i7Q׀]30v, fsS>tYgl]?m?uf41?Ye̓MVzɣ+lZ/ )ޟqlT*xg1?,Oh둻YSM>]ホ4=/H#,VyMWDÖYֱ(MUPI,Pq Q4'/{E !B!*j^{A3 DEn5dېI "!(qWsTs?މs]tkf2_{W_}U}/QZ fJR!7|iZ<:rY6j^D$0HFtS'$3c9d;3݆LDSZn2%AvC̞:T*M=)1dQ^b9 cu& aX^ӡfc7xK;8p[G͙#<\Rb+az;g?\8Se!89%+x/v0y#v ?J# k8y88DqAIq}C+d_xX ({?﫼x=P;RC4K㌴l/QR>>K'[pOYCg"$b:hdD{=a,6){p䂩c6MPX)q#l׆˷܇gQعC}Fkd ! L G]deAd#v"bM"ۗ8ή>^Yd8i?W5sd@e{/_vmTl\!j̽&[38sG۞"%(Tz?=?)q3tX,y(ڰXhBXQ=7^z<8IAOԭ\f fVRvW[^#Ll"EW{ |AQ0 °LxBMXYF>t.`;_6 (*JJ29] i!3Ǻ߸䒉ףA5('fV&;oYJvg]'Y^x{:$kJbt(wt{zޟ$+3ԹXZ֝MF-|n#z|{^8]S>42$nNb a督?#(~s7:c{aP]Cϯ7ca1;ѸcEhGq1bHi]!oPqR/ku"9V$(Y9hib?k85 +N0`%!1Sp7IWYՂp@n5BOtӮ ~7pʂϨ}ȨhGHk7P PTh8 i0]_L/B3ڻ"e6ȲGr98oqϭK2͊cE]7"^3,\$rbWsl1X[{`l,aޛ {U%~oڂ*I O+}u }1@n&.DV@w&~"b=ms?,K"/([9|%ERd) _Wť, ,,W>x1lƌZ q@':TCDoKd %|ɻ:Wl_Z&[mE&Dnߜ݉KSI=03yEH/n`!I^@]]v0*ys̅A*XK*5l/tSڦ8wyQEN>m)uӆWb=l7a(x>Պ9迾_r8`wsç8R]ϻOF(+8s.???RAi%CcjC<_r?B,nk}'w@? zO:? ,dzhz9-|n#:%Us9m$pzT#:ݜzC',Upf5=a8@þD}CCys~,F/F [4{UЦ͜g,2/*+_'%/zsFD^d$IR*W$$%kB?I$*`餄h]4b'eueо')?0"s*TU~' v?7E#:&%CnT*T SKo2%>K2z--ULv>gf[MN- b"{<0Iaƍ޸1{@ !X}\Y_;@\8ߒSPxwphzm$ۏQ)ݣ;w0qYYYG!8"R'4-+Ņ~Uj宖`(dkIzPK bИ4#;e 'qQY?>W䆬,3ꬬ*p)lOK`#H)p]mhzƒ=6k~?L>ʵr7+!]Nsv]rNU#yT?y5jeDЏ)ݍΗ@wL`J+&lE+ :D")D痊F`@2mﮯYV]TWA(»vJosgV,+|O^WgKݿ旓g-Id^E?+IZOL*gwTJ5$\Rw]vC,ܔ7mM.I}QѪZ\?MW[Cɷl3"񲠊Asv"{vUeُhVE=oFF}ߤWtkg Z p="y0O6ͦ,KUel Z'H U^ pjϰl IӖjZR׬/m<lZN j$o-Yjtk2.{~W|k #<(=3|ۗ]Y^ &(.~Dɼbw"W#O_gȀ}3=#c4)fJkx=0`6`G }b OzJpQ2w'ݽwxgId#2'ݘ&$qo еf@Ԃ GSȢ ,mO 孳h#ab8Ybg8ҡ$X%Ƶ2J,YF%,!KL5&#Q~5s T.7,#V6l4z\cKl$EyL4gn=:; jcL/ϸ:r" 5`qqZtjQBve L"7cqo}6))cؔK.|Oq`U,5_61a_z禥J!ǫHW_Ye6Sڝ"&Y`]XgI4Lǿ#x#v 1Q0!voUBoUFX37 x$R2~b+;a/0ENe_.Cu睤u&މd)vAEG0p!R+{9.89q~Q8މooYȀ!m)huG$iԺ;s5YLZ3p3~qo;xͼ@Dtdq#cz!F(zDkadBDGj}}C+|K$ڃ"@W7~RzDZ&/*r G~8/`h "Z@/&Ǟ| 8<ƖfCL~!>J빥u CLKEh}ϽAXiIr6 Hqy"l_3l/R֛Yƒ7= a00tYSbnk6ox Q[RWe-^[O k*Zͥ遻b  V; W@Ř{۪Bt]$~3+H1i X##0 U$MUd$L`]eT>ƕqv]cuQY#WU;GߗW_U|rɭx{|`O_d}h:v#%ԋ;iq*f9([EyEmR}:;^m}U$2&2ܺ `[c3|tljvM7YddU7(;&kS@}h"#<Â"r*҂*C d_7- OF 'I̽ L^`3A- W H3 ={0{uillih+0s}R6mj>.W%%_F&t KnlZTRNm_fě1b?_H5x^AGk)|I_TuI%P$C,3qa83@F'&Ds8L?2}aȆ֘,;2X  S(0KA|J-ၗP6[@Qy̜~ ˇpl⇘G .վfŲ ~m<ºKg|X6DfhGߌ $hP"K_ZF?#Q S^[RDx)(66vHUeK6,,\Ռek| dB8eV'Р "i#M E#)45Ⱥ&'& 5,>y\_h]C"(^ $Q/;/Y!1 "YRv-_3)~1qsM}d <HR& D^dU3H|u(4 d k  8-m݃UYS4Z[=U$Y䘰ѪТ6/+PNmX'X,N}:AsPZDO, .Ue# aAgm_}v !JzʕN\yV:mfؕ'j 7>0fTeg>y=&xݖUv2)N+rϝeHWRIB5MQ(팗Iq6;":j||x$fvg_ZeѓfdYg.qgcŅ!{b2+c@ voS賁_t.18xFڍ/]-:=Oƴ삯~6O )<)67k$F8A~ȢOh?ƃ7Q_ /xp.6Dk;ЏF^7^g ~F8ٴgos3֡9mi'xr =4;`qIj=ao?5w:{D+2A<;ʀZܸTF}"O_9.#:R}dʸ&Wm&ܩ'\/J& q$EhUU q (%  > SrIvAH7f ],J,`Ys`MkPѦ1\MqI%WVa%D1pWTŞLўd%?@Ȏǻd"NOF aZThSeTtZ5e A 9ʰLr*U_o[&9aeNRv,0noK淅eIE-opzAǛEza>sl; 5!w ?~ЈCLaNV! iF ,ʌ@Exu@x7+&'(RCTzT忖8)tn'6 V G ⑯cZGCf؃FRAq* ')h3ԇf;p3lf.\uCd#\{nP0v\b=%@THu9RCt׆<}. Y@:ޚi_DqVj7B6~8$5C?C4ɺp3N9!(,Ơnn'@8݌xd:d g@{0,co)cvC}#U< w 5c`C~r]؏x5yF6y=[p'5ƴO|ױdEQ5Efd:eFeY4^fyIr WA,}MH[q4EHJ42{|tMIf7 >3r{v#~GiPcⱝ9VʸΗzQ=pdvU&IZ7aLpVߵtBH ]s~?vU[o; \A3^j%2{'0ߐZe7̫[wudx$}YXgۺ?ttC yV&V:uEb3Z?Y}{&D;'oLC|ﯵҦ]REܥ$-:V ZPA$❓:9[$f@̴~^-=p0%tY_j - |o҄Z5qz0Z,&#e"^r?~_X52WvbsSo 4bВٰ̄dR%]`X>3!a({o56>SӇ K?pŃK2Kt8痬Y@.;+,8TH5AVhNQ$ ] sa)+ X zD/&%$6wDeuSsP`UXY>OWE8ä_UuwL&/鮮r>O+.YDO oK}FBntw~D9f0:0F/.btW[z+xtF9ݧ<ѺTp"]mE#9+ r48m\e}nQɵe7#Bsg'L$\Mء̡1Gk< pgW. -]s7!w˻ٻE:D!0N?׶9׹{IЊ]D'yx;'zl"qrўl ӣ-`N[5G꤆^h!UjVmCt*Tb]!w^**j#ΘizuhAURl_Oˇ(yiX .lv8r!A/9";I.pEJT+ύ FC kȼ{ZC0QIQ{?†"0FڶZG(0Nҵ7Akp|^!8+ NNpD9^AHnet#`=7.KUBE Nר[bhG(F7i@aYXɫ?LU`g $Y86- iYpFMG+ܺO%28-VO˕gaۯ~ yUIz=xMWp>Vi8"ǿ+Iv^%;J<:t8~6CvIrudlvBsv ڐ~_woTA:\+lz8_n ]&OP/I;ҪބU'Gָ=|eWO v:MkWFII,Oͧ3,cSssʽk~`+_k"LD1NW?S8o/^$yϹ<`㽒Ӂ~z^tFHG}ψos1?cY = bKx7+X/(jC@%n*K\41/yyg}1t{ovz݆}y=. ݕtN[hKoc-;{~b,A)@ F3l+\:I۬sv dx,= ^tgI!]=OÉr8;BDØ$R9P98R`bG_}19 1a{7nƍF|9x^Q q kz^@p *4U1у4#z5+ʳFŮ( 9T# ڐŰ+!UW_sմslyjlT! 1zCICÀ %C*ՆLߨzn(s з{O8v*]b>akP+>*QZ]y~&$+bVfQά^RLp7[*58(ސ! +&sC]qw8Я 'Ǿ6I`ȒCA9ђ=5d֐{d:jH蓘܄j#G0Pe(>c;*33+w23/]`-z²{6<^Ei)Fl-z*:[{ډR &3;33Xڣ 4ssKH;窉Am=n; Zw >4 p{\+J҆(JJГ؋`1n+ly }V}KD8BR$F)fbύɓ𯃈'|nhvr]~ELRW]_= :ǔaIюOkd-vӄشy Y6V͌)fRJ+x4XTNkd())B)wRZKgRsq.%HCt8cvߛ+:\~I^;u/D _,ÅoH9!y^{ۂro敦5gl)a{Dż5]yٌwikE>+K-sjVeCQ}Hrq:qC|N*\ Ǥ A5=ĺuu r}rB7aJ5<#tTJ{qgw,S,M"-܄mnjQѥi520Jt 6^_vYoD9Ԍ睝5&[aa夲aAke9˽X>OgC5&x쥭 4&&z^&oY6biRz攮CZ<9EWݫl82 bxGtu6N_k5:JA-1iG< bRIiingծs-}udH(N\9}JH!Fq6ʼn2Ax+B2\Jxگߍk]@C*{~ˆ]KdU|*zxzD[YFBi #4i(.TqeAxtiZOdt lC֝t=R}=)\=>>͚~6}|S"_{Ǐ^/CCWX}KSF mUP5=, 蓷䈊XGݹ{ʠ?D.Qp:݂Ĺ}Ctnksy vStzk"m|O (.r MI;zyp[rN.*UUQwa0a2v`LQ8mW\L5m굔jZf;8CF2YksVNECO;PV94Sv=lFHT0q[vF?cqэͦDzD=hfV BݟaH,oi5^߿',11/1{.(Be&7J5+8fWD{'ތĺQ}#F94w4]t&8KHV$u=qrBBYaP:J*&|[_• jǥtc1_@S(#\!Ki {#&@W}Y-0Gg^#JU8o7q? H3TIR@*]"*I r2]PLͯm͓d)0vnP/`htŬYoV֭J^֭O^{\Y l1=x9[ :7d%3p#Д-2;ZnRfOF p"C3?|-M'M__8= >_8.7~3s89+K?'CHia8uFZ,9 ,,k B,(|om$+!I# 7L-qݸ4ć .:._k7Nڼ{Ҩ6]e8񸒄A _8]w` &|[*Fz4UuGdԝjrb  eꂼtN۹*OM(f iLɆx|oA5˗7CxAUUUUwȿMJy!i o B?6/^dwyissy)8](W[zLaaX~ոVV (֭5\dD-ͦ𢞼@3QEh:wZX4w/ %ğY o@a#|.Loش0I1ส eB˪I8( j\  _=:Lz/NEQ5F? o?Izp)n~`8ݶjDLe+d⫚^LeFPKb*YYnK9gCzf9oTx oFhio[=$+ mh8i}`>CfB†A5oiRv*JSXuz]2^R>֪'K&ϖ'IG>:}VHHX\bx=rc-3. wЙt;C:Yk9*"q2[f9"1] ,}G/>8Wͯ=Ko(P㭱-\KEi31S&XG >1@7(.b/eZ;=(g;}W T0+Nԗ 콈->\۵t~Cc]XŽ1)R/.0Ebj}˼_rV@xjL:J)ݡVQ|9 yu؉a[@ROVDVrD[  gZ%$iVryHU-ܨ#ǧ~C(0l&G>BZT|6EVr7OځW}F z34t"36nT~Ғe<%%z[-drHG37qjsd|ZȁV3GYk6qY++.0-"2LH~~>Jo&{aHZQe:@LC5|)%ko&Vݶ;ey&b(ׯ~*ph>. A[:֋}yawqg{QBٻ{8PԦ}8bSg֐CQ[D#%*IFQV*YT)}73;s{u,ݝ}f^ӴSA6IPwRgu:葓iY(LiP}Ww[b׹2}(7JYWohWpɚ;c]lnj_ Eŭپs=U=ghrڔ' T<YҴSTqpRKIe%󁖝ԽsL9'L-f5^x+Bg =D'4!y2=hiϝ9r3%Ӑ?rǀUs(eטy%{2Dw).v.jQ#><~@Zi{=Ub.Z^X6|tZ![w>oYWNkϜB449U4bv,{+"%`Z?@je+>4GDwWfGz|[S.8_:> ?FJQcG_0xf{0N0'lXF CB\/5xC.b쎐0$$I.jn(%ھj@)s [H\m.fGy.;O6G5 kM$Jm.j) D/c g5.1m,dsG s:DrCD _f8Lm;5Vրț+86G?{50U,dF+M4xМΧ7 S մ2/& i^Kwx1i'g^m1^%ǩBHX CV$YQe! I *)qU h d~PHWeVk&I[ŕR~6}*^֝VjX)<^"Zd # ~A"I4":>Av>f#U}꞉oaGȑcfxg="bM`I-W(KX<}@LLēO$PZ2L*3_N.>L)Vm@.Ϣ,b!gl<e%A /Xq?M ـs"Z*VK.x/l,qd)cr0 *ظR (A>`Cl? N:kuStJVݛ]h{kx>9] }^k~|+wb<[,1= uDa@AS6W_wf~sfy%4 Ǎu1J^MB{uɶ ڿ +aIPÈ "JTذE8P (%Gn)w<(nIڌcN=1  -,Vmn Eg=?osKe N!@N0Wy+ ECy{4t% 2y`H-;8n<~O5֓vݘu=߽s~½0_AR_3O&/YrAe+IR<x8.%D J墁ㄅ e`/ Z]Թ五42(bW~V3)qUydH] j㺹,":$:$1umw*R,\ܑ!\߫ • FQ^}+ۓj+g(Cu_U[ S5AǨN@##Vj@F:LpǹMU6lظ=&\libfido2-1.3.1/fuzz/functions.txt000066400000000000000000001324751362326726700170070ustar00rootroot00000000000000File '/home/pedro/projects/libfido2/src/aes256.c': Name Regions Miss Cover Lines Miss Cover ----------------------------------------------------------------------------- aes256_cbc_enc 28 0 100.00% 41 0 100.00% aes256_cbc_dec 28 0 100.00% 41 0 100.00% ----------------------------------------------------------------------------- TOTAL 56 0 100.00% 82 0 100.00% File '/home/pedro/projects/libfido2/src/assert.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_get_assert 35 3 91.43% 38 4 89.47% fido_check_flags 13 0 100.00% 18 0 100.00% fido_verify_sig_es256 17 2 88.24% 31 7 77.42% fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72% fido_assert_verify 48 4 91.67% 79 4 94.94% fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% fido_assert_set_rp 12 1 91.67% 14 3 78.57% fido_assert_allow_cred 13 2 84.62% 29 3 89.66% fido_assert_set_extensions 9 0 100.00% 8 0 100.00% fido_assert_set_options 6 6 0.00% 6 6 0.00% fido_assert_set_up 2 0 100.00% 5 0 100.00% fido_assert_set_uv 2 0 100.00% 5 0 100.00% fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% fido_assert_new 1 0 100.00% 3 0 100.00% fido_assert_reset_tx 1 0 100.00% 15 0 100.00% fido_assert_reset_rx 6 0 100.00% 24 0 100.00% fido_assert_free 6 0 100.00% 13 0 100.00% fido_assert_count 1 0 100.00% 3 0 100.00% fido_assert_rp_id 1 0 100.00% 3 0 100.00% fido_assert_flags 4 0 100.00% 6 0 100.00% fido_assert_sigcount 4 0 100.00% 6 0 100.00% fido_assert_authdata_ptr 4 0 100.00% 6 0 100.00% fido_assert_authdata_len 4 0 100.00% 6 0 100.00% fido_assert_sig_ptr 4 0 100.00% 6 0 100.00% fido_assert_sig_len 4 0 100.00% 6 0 100.00% fido_assert_id_ptr 4 0 100.00% 6 0 100.00% fido_assert_id_len 4 0 100.00% 6 0 100.00% fido_assert_user_id_ptr 4 0 100.00% 6 0 100.00% fido_assert_user_id_len 4 0 100.00% 6 0 100.00% fido_assert_user_icon 4 0 100.00% 6 0 100.00% fido_assert_user_name 4 0 100.00% 6 0 100.00% fido_assert_user_display_name 4 0 100.00% 6 0 100.00% fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% fido_assert_set_authdata 24 0 100.00% 35 0 100.00% fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00% fido_assert_set_sig 14 0 100.00% 17 0 100.00% fido_assert_set_count 10 0 100.00% 21 0 100.00% assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00% assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% assert.c:fido_dev_get_assert_rx 20 0 100.00% 38 0 100.00% assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% assert.c:fido_get_next_assert_tx 9 0 100.00% 11 0 100.00% assert.c:fido_get_next_assert_rx 16 2 87.50% 26 4 84.62% assert.c:decrypt_hmac_secrets 9 1 88.89% 15 4 73.33% assert.c:check_extensions 4 0 100.00% 9 0 100.00% assert.c:get_signed_hash 32 0 100.00% 46 0 100.00% assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% --------------------------------------------------------------------------------------- TOTAL 569 29 94.90% 901 60 93.34% File '/home/pedro/projects/libfido2/src/authkey.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_authkey 1 0 100.00% 3 0 100.00% authkey.c:fido_dev_authkey_wait 10 0 100.00% 9 0 100.00% authkey.c:fido_dev_authkey_tx 19 0 100.00% 33 0 100.00% authkey.c:fido_dev_authkey_rx 7 0 100.00% 18 0 100.00% authkey.c:parse_authkey 8 0 100.00% 12 0 100.00% --------------------------------------------------------------------------------------- TOTAL 45 0 100.00% 75 0 100.00% File '/home/pedro/projects/libfido2/src/bio.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_bio_dev_get_template_array 5 2 60.00% 6 0 100.00% fido_bio_dev_set_template_name 7 0 100.00% 6 0 100.00% fido_bio_dev_enroll_begin 24 2 91.67% 36 0 100.00% fido_bio_dev_enroll_continue 5 2 60.00% 6 0 100.00% fido_bio_dev_enroll_cancel 1 1 0.00% 3 3 0.00% fido_bio_dev_enroll_remove 1 0 100.00% 3 0 100.00% fido_bio_dev_get_info 1 0 100.00% 3 0 100.00% fido_bio_template_name 1 0 100.00% 3 0 100.00% fido_bio_template_id_ptr 1 0 100.00% 3 0 100.00% fido_bio_template_id_len 1 0 100.00% 3 0 100.00% fido_bio_template_array_count 1 0 100.00% 3 0 100.00% fido_bio_template_array_new 1 0 100.00% 3 0 100.00% fido_bio_template_new 1 0 100.00% 3 0 100.00% fido_bio_template_array_free 6 0 100.00% 10 0 100.00% fido_bio_template_free 6 0 100.00% 10 0 100.00% fido_bio_template_set_name 8 0 100.00% 9 0 100.00% fido_bio_template_set_id 8 0 100.00% 10 0 100.00% fido_bio_template 4 0 100.00% 6 0 100.00% fido_bio_enroll_new 1 0 100.00% 3 0 100.00% fido_bio_info_new 1 0 100.00% 3 0 100.00% fido_bio_info_type 1 0 100.00% 3 0 100.00% fido_bio_info_max_samples 1 0 100.00% 3 0 100.00% fido_bio_enroll_free 6 0 100.00% 11 0 100.00% fido_bio_info_free 6 0 100.00% 9 0 100.00% fido_bio_enroll_remaining_samples 1 0 100.00% 3 0 100.00% fido_bio_enroll_last_status 1 0 100.00% 3 0 100.00% bio.c:bio_get_template_array_wait 11 0 100.00% 9 0 100.00% bio.c:bio_tx 43 0 100.00% 65 0 100.00% bio.c:bio_prepare_hmac 18 0 100.00% 36 0 100.00% bio.c:bio_rx_template_array 12 0 100.00% 21 0 100.00% bio.c:bio_parse_template_array 26 1 96.15% 34 4 88.24% bio.c:decode_template_array 12 1 91.67% 23 3 86.96% bio.c:decode_template 9 0 100.00% 18 0 100.00% bio.c:bio_set_template_name_wait 19 0 100.00% 24 0 100.00% bio.c:bio_enroll_begin_wait 17 1 94.12% 24 3 87.50% bio.c:bio_rx_enroll_begin 16 0 100.00% 29 0 100.00% bio.c:bio_parse_enroll_status 20 0 100.00% 31 0 100.00% bio.c:bio_parse_template_id 8 0 100.00% 12 0 100.00% bio.c:bio_enroll_continue_wait 19 0 100.00% 25 0 100.00% bio.c:bio_rx_enroll_continue 12 0 100.00% 22 0 100.00% bio.c:bio_enroll_cancel_wait 11 11 0.00% 12 12 0.00% bio.c:bio_enroll_remove_wait 17 0 100.00% 24 0 100.00% bio.c:bio_get_info_wait 11 0 100.00% 11 0 100.00% bio.c:bio_rx_info 12 0 100.00% 21 0 100.00% bio.c:bio_reset_info 1 0 100.00% 4 0 100.00% bio.c:bio_parse_info 20 0 100.00% 31 0 100.00% bio.c:bio_reset_template_array 4 0 100.00% 8 0 100.00% bio.c:bio_reset_template 1 0 100.00% 6 0 100.00% bio.c:bio_reset_enroll 3 0 100.00% 7 0 100.00% --------------------------------------------------------------------------------------- TOTAL 422 21 95.02% 661 25 96.22% File '/home/pedro/projects/libfido2/src/blob.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_blob_new 1 0 100.00% 3 0 100.00% fido_blob_set 11 1 90.91% 25 4 84.00% fido_blob_free 8 0 100.00% 16 0 100.00% fido_free_blob_array 9 0 100.00% 17 0 100.00% fido_blob_encode 6 0 100.00% 6 0 100.00% fido_blob_decode 1 0 100.00% 3 0 100.00% fido_blob_is_empty 3 0 100.00% 3 0 100.00% --------------------------------------------------------------------------------------- TOTAL 39 1 97.44% 73 4 94.52% File '/home/pedro/projects/libfido2/src/buf.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_buf_read 4 0 100.00% 10 0 100.00% fido_buf_write 4 1 75.00% 10 1 90.00% --------------------------------------------------------------------------------------- TOTAL 8 1 87.50% 20 1 95.00% File '/home/pedro/projects/libfido2/src/cbor.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- cbor_map_iter 20 1 95.00% 30 4 86.67% cbor_array_iter 12 0 100.00% 20 0 100.00% cbor_parse_reply 27 0 100.00% 43 0 100.00% cbor_vector_free 6 0 100.00% 5 0 100.00% cbor_bytestring_copy 14 0 100.00% 22 0 100.00% cbor_string_copy 14 0 100.00% 23 0 100.00% cbor_add_bytestring 14 0 100.00% 26 0 100.00% cbor_add_string 14 0 100.00% 26 0 100.00% cbor_add_bool 14 0 100.00% 26 0 100.00% cbor_flatten_vector 14 1 92.86% 21 1 95.24% cbor_build_frame 15 0 100.00% 32 0 100.00% cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% cbor_encode_user_entity 21 0 100.00% 18 0 100.00% cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00% cbor_encode_pubkey 10 0 100.00% 13 0 100.00% cbor_encode_pubkey_list 18 2 88.89% 23 0 100.00% cbor_encode_extensions 13 1 92.31% 16 0 100.00% cbor_encode_options 13 0 100.00% 14 0 100.00% cbor_encode_assert_options 13 0 100.00% 14 0 100.00% cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% cbor_encode_change_pin_auth 44 1 97.73% 69 3 95.65% cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% cbor_encode_hmac_secret_param 41 1 97.56% 66 4 93.94% cbor_decode_fmt 9 0 100.00% 18 0 100.00% cbor_decode_pubkey 21 1 95.24% 32 2 93.75% cbor_decode_cred_authdata 31 0 100.00% 46 0 100.00% cbor_decode_assert_authdata 23 0 100.00% 44 0 100.00% cbor_decode_attstmt 8 0 100.00% 10 0 100.00% cbor_decode_uint64 4 0 100.00% 10 0 100.00% cbor_decode_cred_id 8 0 100.00% 10 0 100.00% cbor_decode_user 8 0 100.00% 10 0 100.00% cbor_decode_rp_entity 8 0 100.00% 10 0 100.00% cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% cbor.c:check_key_type 8 0 100.00% 9 0 100.00% cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% cbor.c:sha256 7 0 100.00% 15 0 100.00% cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00% cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% cbor.c:decode_extensions 16 4 75.00% 34 6 82.35% cbor.c:decode_extension 19 19 0.00% 27 27 0.00% cbor.c:decode_hmac_secret 16 0 100.00% 32 0 100.00% cbor.c:decode_hmac_secret_aux 7 0 100.00% 17 0 100.00% cbor.c:decode_attstmt_entry 29 0 100.00% 39 0 100.00% cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% --------------------------------------------------------------------------------------- TOTAL 844 31 96.33% 1319 47 96.44% File '/home/pedro/projects/libfido2/src/cred.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_make_cred 12 0 100.00% 9 0 100.00% fido_check_rp_id 4 0 100.00% 14 0 100.00% fido_cred_verify 45 0 100.00% 71 0 100.00% fido_cred_verify_self 54 10 81.48% 90 14 84.44% fido_cred_new 1 0 100.00% 3 0 100.00% fido_cred_reset_tx 1 0 100.00% 20 0 100.00% fido_cred_reset_rx 1 0 100.00% 8 0 100.00% fido_cred_free 6 1 83.33% 13 0 100.00% fido_cred_set_authdata 22 0 100.00% 36 0 100.00% fido_cred_set_authdata_raw 22 2 90.91% 35 4 88.57% fido_cred_set_x509 12 0 100.00% 16 0 100.00% fido_cred_set_sig 12 0 100.00% 16 0 100.00% fido_cred_exclude 14 2 85.71% 25 3 88.00% fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% fido_cred_set_rp 18 2 88.89% 26 6 76.92% fido_cred_set_user 33 4 87.88% 50 13 74.00% fido_cred_set_extensions 9 0 100.00% 8 0 100.00% fido_cred_set_options 6 6 0.00% 6 6 0.00% fido_cred_set_rk 2 0 100.00% 5 0 100.00% fido_cred_set_uv 2 0 100.00% 5 0 100.00% fido_cred_set_fmt 16 4 75.00% 15 1 93.33% fido_cred_set_type 17 2 88.24% 9 1 88.89% fido_cred_type 1 0 100.00% 3 0 100.00% fido_cred_flags 1 0 100.00% 3 0 100.00% fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% fido_cred_clientdata_hash_len 1 0 100.00% 3 0 100.00% fido_cred_x5c_ptr 1 0 100.00% 3 0 100.00% fido_cred_x5c_len 1 0 100.00% 3 0 100.00% fido_cred_sig_ptr 1 0 100.00% 3 0 100.00% fido_cred_sig_len 1 0 100.00% 3 0 100.00% fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% fido_cred_authdata_len 1 0 100.00% 3 0 100.00% fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00% fido_cred_pubkey_len 9 0 100.00% 20 0 100.00% fido_cred_id_ptr 1 0 100.00% 3 0 100.00% fido_cred_id_len 1 0 100.00% 3 0 100.00% fido_cred_fmt 1 0 100.00% 3 0 100.00% fido_cred_rp_id 1 0 100.00% 3 0 100.00% fido_cred_rp_name 1 0 100.00% 3 0 100.00% fido_cred_user_name 1 0 100.00% 3 0 100.00% fido_cred_display_name 1 0 100.00% 3 0 100.00% fido_cred_user_id_ptr 1 0 100.00% 3 0 100.00% fido_cred_user_id_len 1 0 100.00% 3 0 100.00% cred.c:fido_dev_make_cred_wait 10 0 100.00% 9 0 100.00% cred.c:fido_dev_make_cred_tx 59 0 100.00% 81 0 100.00% cred.c:fido_dev_make_cred_rx 22 0 100.00% 28 0 100.00% cred.c:parse_makecred_reply 10 0 100.00% 23 0 100.00% cred.c:check_extensions 4 0 100.00% 9 0 100.00% cred.c:get_signed_hash_packed 23 1 95.65% 38 3 92.11% cred.c:get_signed_hash_u2f 22 0 100.00% 20 0 100.00% cred.c:verify_sig 27 1 96.30% 40 4 90.00% cred.c:fido_cred_clean_authdata 1 0 100.00% 9 0 100.00% cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% --------------------------------------------------------------------------------------- TOTAL 532 35 93.42% 850 55 93.53% File '/home/pedro/projects/libfido2/src/credman.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_credman_get_dev_metadata 9 2 77.78% 8 0 100.00% fido_credman_get_dev_rk 9 2 77.78% 8 0 100.00% fido_credman_del_dev_rk 9 2 77.78% 8 0 100.00% fido_credman_get_dev_rp 9 2 77.78% 8 0 100.00% fido_credman_rk_new 1 0 100.00% 3 0 100.00% fido_credman_rk_free 6 1 83.33% 10 0 100.00% fido_credman_rk_count 1 0 100.00% 3 0 100.00% fido_credman_rk 4 0 100.00% 6 0 100.00% fido_credman_metadata_new 1 0 100.00% 3 0 100.00% fido_credman_metadata_free 6 1 83.33% 9 0 100.00% fido_credman_rk_existing 1 0 100.00% 3 0 100.00% fido_credman_rk_remaining 1 0 100.00% 3 0 100.00% fido_credman_rp_new 1 0 100.00% 3 0 100.00% fido_credman_rp_free 6 1 83.33% 10 0 100.00% fido_credman_rp_count 1 0 100.00% 3 0 100.00% fido_credman_rp_id 4 0 100.00% 6 0 100.00% fido_credman_rp_name 4 0 100.00% 6 0 100.00% fido_credman_rp_id_hash_len 4 0 100.00% 6 0 100.00% fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% credman.c:credman_tx 30 0 100.00% 53 0 100.00% credman.c:credman_prepare_hmac 21 1 95.24% 43 2 95.35% credman.c:credman_rx_metadata 12 0 100.00% 21 0 100.00% credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% credman.c:credman_rx_rk 20 0 100.00% 36 0 100.00% credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% credman.c:credman_parse_rk 13 0 100.00% 25 0 100.00% credman.c:credman_rx_next_rk 16 2 87.50% 26 4 84.62% credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% credman.c:credman_rx_rp 20 0 100.00% 36 0 100.00% credman.c:credman_parse_rp_count 16 0 100.00% 25 0 100.00% credman.c:credman_parse_rp 9 0 100.00% 19 0 100.00% credman.c:credman_rx_next_rp 16 2 87.50% 26 4 84.62% credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% --------------------------------------------------------------------------------------- TOTAL 381 18 95.28% 589 15 97.45% File '/home/pedro/projects/libfido2/src/dev.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_open 1 0 100.00% 3 0 100.00% fido_dev_close 8 2 75.00% 9 0 100.00% fido_dev_cancel 8 2 75.00% 6 3 50.00% fido_dev_set_io_functions 18 4 77.78% 19 6 68.42% fido_init 7 1 85.71% 4 0 100.00% fido_dev_new 9 1 88.89% 22 4 81.82% fido_dev_free 6 0 100.00% 10 0 100.00% fido_dev_protocol 1 0 100.00% 3 0 100.00% fido_dev_major 1 0 100.00% 3 0 100.00% fido_dev_minor 1 0 100.00% 3 0 100.00% fido_dev_build 1 0 100.00% 3 0 100.00% fido_dev_flags 1 0 100.00% 3 0 100.00% fido_dev_is_fido2 2 0 100.00% 3 0 100.00% fido_dev_force_u2f 2 0 100.00% 3 0 100.00% fido_dev_force_fido2 2 2 0.00% 3 3 0.00% dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% dev.c:fido_dev_open_tx 26 8 69.23% 32 12 62.50% dev.c:obtain_nonce 13 2 84.62% 18 2 88.89% dev.c:fido_dev_open_rx 14 0 100.00% 27 0 100.00% --------------------------------------------------------------------------------------- TOTAL 131 22 83.21% 183 30 83.61% File '/home/pedro/projects/libfido2/src/ecdh.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_do_ecdh 29 0 100.00% 44 0 100.00% ecdh.c:do_ecdh 39 0 100.00% 60 0 100.00% --------------------------------------------------------------------------------------- TOTAL 68 0 100.00% 104 0 100.00% File '/home/pedro/projects/libfido2/src/eddsa.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- eddsa_pk_decode 8 0 100.00% 10 0 100.00% eddsa_pk_new 1 0 100.00% 3 0 100.00% eddsa_pk_free 6 0 100.00% 11 0 100.00% eddsa_pk_from_ptr 6 0 100.00% 8 0 100.00% eddsa_pk_to_EVP_PKEY 3 0 100.00% 9 0 100.00% eddsa_pk_from_EVP_PKEY 14 4 71.43% 12 2 83.33% eddsa.c:decode_pubkey_point 8 0 100.00% 14 0 100.00% eddsa.c:decode_coord 8 0 100.00% 12 0 100.00% --------------------------------------------------------------------------------------- TOTAL 54 4 92.59% 79 2 97.47% File '/home/pedro/projects/libfido2/src/err.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_strerr 108 108 0.00% 112 112 0.00% --------------------------------------------------------------------------------------- TOTAL 108 108 0.00% 112 112 0.00% File '/home/pedro/projects/libfido2/src/es256.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- es256_pk_decode 8 0 100.00% 10 0 100.00% es256_pk_encode 56 0 100.00% 70 0 100.00% es256_sk_new 1 0 100.00% 3 0 100.00% es256_sk_free 6 0 100.00% 11 0 100.00% es256_pk_new 1 0 100.00% 3 0 100.00% es256_pk_free 6 0 100.00% 11 0 100.00% es256_pk_from_ptr 6 0 100.00% 8 0 100.00% es256_pk_set_x 1 0 100.00% 5 0 100.00% es256_pk_set_y 1 0 100.00% 5 0 100.00% es256_sk_create 39 2 94.87% 46 6 86.96% es256_pk_to_EVP_PKEY 41 0 100.00% 58 0 100.00% es256_pk_from_EC_KEY 38 2 94.74% 39 7 82.05% es256_sk_to_EVP_PKEY 27 0 100.00% 41 0 100.00% es256_derive_pk 25 0 100.00% 34 0 100.00% es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% es256.c:decode_coord 8 0 100.00% 12 0 100.00% --------------------------------------------------------------------------------------- TOTAL 273 4 98.53% 372 13 96.51% File '/home/pedro/projects/libfido2/src/extern.h': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- File '/home/pedro/projects/libfido2/src/fido.h': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- File '/home/pedro/projects/libfido2/src/hid.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_info_new 1 1 0.00% 3 3 0.00% fido_dev_info_free 9 9 0.00% 17 17 0.00% fido_dev_info_ptr 1 1 0.00% 3 3 0.00% fido_dev_info_path 1 1 0.00% 3 3 0.00% fido_dev_info_vendor 1 1 0.00% 3 3 0.00% fido_dev_info_product 1 1 0.00% 3 3 0.00% fido_dev_info_manufacturer_string 1 1 0.00% 3 3 0.00% fido_dev_info_product_string 1 1 0.00% 3 3 0.00% --------------------------------------------------------------------------------------- TOTAL 16 16 0.00% 38 38 0.00% File '/home/pedro/projects/libfido2/src/hid_linux.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_info_manifest 33 33 0.00% 40 40 0.00% fido_hid_open 6 6 0.00% 11 11 0.00% fido_hid_close 1 1 0.00% 6 6 0.00% fido_hid_read 12 12 0.00% 16 16 0.00% fido_hid_write 12 12 0.00% 16 16 0.00% hid_linux.c:copy_info 35 35 0.00% 56 56 0.00% hid_linux.c:is_fido 6 6 0.00% 14 14 0.00% hid_linux.c:get_report_descriptor 17 17 0.00% 31 31 0.00% hid_linux.c:get_usage_info 16 16 0.00% 33 33 0.00% hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% hid_linux.c:parse_uevent 16 16 0.00% 30 30 0.00% --------------------------------------------------------------------------------------- TOTAL 166 166 0.00% 287 287 0.00% File '/home/pedro/projects/libfido2/src/info.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_get_cbor_info 1 0 100.00% 3 0 100.00% fido_cbor_info_new 1 0 100.00% 3 0 100.00% fido_cbor_info_free 6 1 83.33% 14 0 100.00% fido_cbor_info_versions_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_versions_len 1 0 100.00% 3 0 100.00% fido_cbor_info_extensions_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_extensions_len 1 0 100.00% 3 0 100.00% fido_cbor_info_aaguid_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_aaguid_len 1 0 100.00% 3 0 100.00% fido_cbor_info_options_name_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% info.c:fido_dev_get_cbor_info_wait 10 0 100.00% 9 0 100.00% info.c:fido_dev_get_cbor_info_tx 9 0 100.00% 13 0 100.00% info.c:fido_dev_get_cbor_info_rx 7 0 100.00% 18 0 100.00% info.c:parse_reply_element 13 0 100.00% 27 0 100.00% info.c:decode_versions 12 0 100.00% 21 0 100.00% info.c:decode_version 4 0 100.00% 14 0 100.00% info.c:decode_extensions 12 0 100.00% 21 0 100.00% info.c:decode_extension 4 0 100.00% 14 0 100.00% info.c:decode_aaguid 8 0 100.00% 12 0 100.00% info.c:decode_options 11 0 100.00% 18 0 100.00% info.c:decode_option 11 0 100.00% 22 0 100.00% info.c:decode_protocols 12 0 100.00% 21 0 100.00% info.c:decode_protocol 6 0 100.00% 16 0 100.00% info.c:free_str_array 4 0 100.00% 8 0 100.00% info.c:free_opt_array 4 0 100.00% 9 0 100.00% info.c:free_byte_array 1 0 100.00% 6 0 100.00% --------------------------------------------------------------------------------------- TOTAL 148 1 99.32% 305 0 100.00% File '/home/pedro/projects/libfido2/src/io.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_tx 18 0 100.00% 35 0 100.00% fido_rx 34 3 91.18% 84 12 85.71% fido_rx_cbor_status 9 0 100.00% 13 0 100.00% io.c:tx_preamble 16 1 93.75% 24 1 95.83% io.c:tx_frame 16 1 93.75% 21 0 100.00% io.c:rx_preamble 11 0 100.00% 12 0 100.00% io.c:rx_frame 9 1 88.89% 12 0 100.00% --------------------------------------------------------------------------------------- TOTAL 113 6 94.69% 201 13 93.53% File '/home/pedro/projects/libfido2/src/iso7816.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- iso7816_new 4 0 100.00% 19 0 100.00% iso7816_free 6 0 100.00% 11 0 100.00% iso7816_add 6 1 83.33% 10 0 100.00% iso7816_ptr 1 0 100.00% 3 0 100.00% iso7816_len 1 0 100.00% 4 0 100.00% --------------------------------------------------------------------------------------- TOTAL 18 1 94.44% 47 0 100.00% File '/home/pedro/projects/libfido2/src/log.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_log_init 1 1 0.00% 3 3 0.00% fido_log_xxd 11 8 27.27% 18 12 33.33% fido_log_debug 4 1 75.00% 13 8 38.46% --------------------------------------------------------------------------------------- TOTAL 16 10 37.50% 34 23 32.35% File '/home/pedro/projects/libfido2/src/pin.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_get_pin_token 1 0 100.00% 3 0 100.00% fido_dev_set_pin 1 0 100.00% 3 0 100.00% fido_dev_get_retry_count 1 0 100.00% 3 0 100.00% cbor_add_pin_params 17 0 100.00% 27 0 100.00% pin.c:fido_dev_get_pin_token_wait 10 0 100.00% 9 0 100.00% pin.c:fido_dev_get_pin_token_tx 29 0 100.00% 40 0 100.00% pin.c:fido_dev_get_pin_token_rx 21 0 100.00% 36 0 100.00% pin.c:parse_pintoken 8 0 100.00% 12 0 100.00% pin.c:fido_dev_set_pin_wait 16 0 100.00% 22 0 100.00% pin.c:fido_dev_change_pin_tx 41 0 100.00% 59 0 100.00% pin.c:pad64 18 0 100.00% 24 0 100.00% pin.c:fido_dev_set_pin_tx 33 0 100.00% 48 0 100.00% pin.c:fido_dev_get_retry_count_wait 10 0 100.00% 9 0 100.00% pin.c:fido_dev_get_retry_count_tx 19 0 100.00% 28 0 100.00% pin.c:fido_dev_get_retry_count_rx 12 0 100.00% 21 0 100.00% pin.c:parse_retry_count 13 0 100.00% 20 0 100.00% --------------------------------------------------------------------------------------- TOTAL 250 0 100.00% 364 0 100.00% File '/home/pedro/projects/libfido2/src/reset.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_reset 1 0 100.00% 3 0 100.00% reset.c:fido_dev_reset_wait 10 0 100.00% 9 0 100.00% reset.c:fido_dev_reset_tx 9 0 100.00% 11 0 100.00% --------------------------------------------------------------------------------------- TOTAL 20 0 100.00% 23 0 100.00% File '/home/pedro/projects/libfido2/src/rs256.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- rs256_pk_decode 8 0 100.00% 10 0 100.00% rs256_pk_new 1 0 100.00% 3 0 100.00% rs256_pk_free 6 0 100.00% 11 0 100.00% rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% rs256_pk_from_RSA 32 6 81.25% 32 9 71.88% rs256.c:decode_rsa_pubkey 9 0 100.00% 16 0 100.00% rs256.c:decode_bignum 8 0 100.00% 12 0 100.00% --------------------------------------------------------------------------------------- TOTAL 102 6 94.12% 140 9 93.57% File '/home/pedro/projects/libfido2/src/u2f.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- u2f_register 70 1 98.57% 89 0 100.00% u2f_authenticate 27 0 100.00% 33 0 100.00% u2f.c:key_lookup 44 0 100.00% 69 0 100.00% u2f.c:send_dummy_register 31 1 96.77% 50 0 100.00% u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% u2f.c:x5c_get 21 1 95.24% 37 3 91.89% u2f.c:sig_get 8 1 87.50% 16 6 62.50% u2f.c:encode_cred_authdata 37 2 94.59% 82 6 92.68% u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00% u2f.c:u2f_authenticate_single 34 2 94.12% 53 4 92.45% u2f.c:do_auth 50 1 98.00% 72 0 100.00% u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% --------------------------------------------------------------------------------------- TOTAL 436 11 97.48% 686 22 96.79% libfido2-1.3.1/fuzz/fuzz_assert.c000066400000000000000000000521461362326726700167550ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include "mutator_aux.h" #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" #include "../openbsd-compat/openbsd-compat.h" #define TAG_U2F 0x01 #define TAG_TYPE 0x02 #define TAG_CDH 0x03 #define TAG_RP_ID 0x04 #define TAG_EXT 0x05 #define TAG_SEED 0x06 #define TAG_UP 0x07 #define TAG_UV 0x08 #define TAG_WIRE_DATA 0x09 #define TAG_CRED_COUNT 0x0a #define TAG_CRED 0x0b #define TAG_ES256 0x0c #define TAG_RS256 0x0d #define TAG_PIN 0x0e #define TAG_EDDSA 0x0f /* Parameter set defining a FIDO2 get assertion operation. */ struct param { char pin[MAXSTR]; char rp_id[MAXSTR]; int ext; int seed; struct blob cdh; struct blob cred; struct blob es256; struct blob rs256; struct blob eddsa; struct blob wire_data; uint8_t cred_count; uint8_t type; uint8_t u2f; uint8_t up; uint8_t uv; }; /* Example parameters. */ static const char dummy_rp_id[] = "localhost"; static const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; static const uint8_t dummy_cdh[] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, }; static const uint8_t dummy_es256[] = { 0xcc, 0x1b, 0x50, 0xac, 0xc4, 0x19, 0xf8, 0x3a, 0xee, 0x0a, 0x77, 0xd6, 0xf3, 0x53, 0xdb, 0xef, 0xf2, 0xb9, 0x5c, 0x2d, 0x8b, 0x1e, 0x52, 0x58, 0x88, 0xf4, 0x0b, 0x85, 0x1f, 0x40, 0x6d, 0x18, 0x15, 0xb3, 0xcc, 0x25, 0x7c, 0x38, 0x3d, 0xec, 0xdf, 0xad, 0xbd, 0x46, 0x91, 0xc3, 0xac, 0x30, 0x94, 0x2a, 0xf7, 0x78, 0x35, 0x70, 0x59, 0x6f, 0x28, 0xcb, 0x8e, 0x07, 0x85, 0xb5, 0x91, 0x96, }; static const uint8_t dummy_rs256[] = { 0xd2, 0xa8, 0xc0, 0x11, 0x82, 0x9e, 0x57, 0x2e, 0x60, 0xae, 0x8c, 0xb0, 0x09, 0xe1, 0x58, 0x2b, 0x99, 0xec, 0xc3, 0x11, 0x1b, 0xef, 0x81, 0x49, 0x34, 0x53, 0x6a, 0x01, 0x65, 0x2c, 0x24, 0x09, 0x30, 0x87, 0x98, 0x51, 0x6e, 0x30, 0x4f, 0x60, 0xbd, 0x54, 0xd2, 0x54, 0xbd, 0x94, 0x42, 0xdd, 0x63, 0xe5, 0x2c, 0xc6, 0x04, 0x32, 0xc0, 0x8f, 0x72, 0xd5, 0xb4, 0xf0, 0x4f, 0x42, 0xe5, 0xb0, 0xa2, 0x95, 0x11, 0xfe, 0xd8, 0xb0, 0x65, 0x34, 0xff, 0xfb, 0x44, 0x97, 0x52, 0xfc, 0x67, 0x23, 0x0b, 0xad, 0xf3, 0x3a, 0x82, 0xd4, 0x96, 0x10, 0x87, 0x6b, 0xfa, 0xd6, 0x51, 0x60, 0x3e, 0x1c, 0xae, 0x19, 0xb8, 0xce, 0x08, 0xae, 0x9a, 0xee, 0x78, 0x16, 0x22, 0xcc, 0x92, 0xcb, 0xa8, 0x95, 0x34, 0xe5, 0xb9, 0x42, 0x6a, 0xf0, 0x2e, 0x82, 0x1f, 0x4c, 0x7d, 0x84, 0x94, 0x68, 0x7b, 0x97, 0x2b, 0xf7, 0x7d, 0x67, 0x83, 0xbb, 0xc7, 0x8a, 0x31, 0x5a, 0xf3, 0x2a, 0x95, 0xdf, 0x63, 0xe7, 0x4e, 0xee, 0x26, 0xda, 0x87, 0x00, 0xe2, 0x23, 0x4a, 0x33, 0x9a, 0xa0, 0x1b, 0xce, 0x60, 0x1f, 0x98, 0xa1, 0xb0, 0xdb, 0xbf, 0x20, 0x59, 0x27, 0xf2, 0x06, 0xd9, 0xbe, 0x37, 0xa4, 0x03, 0x6b, 0x6a, 0x4e, 0xaf, 0x22, 0x68, 0xf3, 0xff, 0x28, 0x59, 0x05, 0xc9, 0xf1, 0x28, 0xf4, 0xbb, 0x35, 0xe0, 0xc2, 0x68, 0xc2, 0xaa, 0x54, 0xac, 0x8c, 0xc1, 0x69, 0x9e, 0x4b, 0x32, 0xfc, 0x53, 0x58, 0x85, 0x7d, 0x3f, 0x51, 0xd1, 0xc9, 0x03, 0x02, 0x13, 0x61, 0x62, 0xda, 0xf8, 0xfe, 0x3e, 0xc8, 0x95, 0x12, 0xfb, 0x0c, 0xdf, 0x06, 0x65, 0x6f, 0x23, 0xc7, 0x83, 0x7c, 0x50, 0x2d, 0x27, 0x25, 0x4d, 0xbf, 0x94, 0xf0, 0x89, 0x04, 0xb9, 0x2d, 0xc4, 0xa5, 0x32, 0xa9, 0x25, 0x0a, 0x99, 0x59, 0x01, 0x00, 0x01, }; static const uint8_t dummy_eddsa[] = { 0xfe, 0x8b, 0x61, 0x50, 0x31, 0x7a, 0xe6, 0xdf, 0xb1, 0x04, 0x9d, 0x4d, 0xb5, 0x7a, 0x5e, 0x96, 0x4c, 0xb2, 0xf9, 0x5f, 0x72, 0x47, 0xb5, 0x18, 0xe2, 0x39, 0xdf, 0x2f, 0x87, 0x19, 0xb3, 0x02, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * get assertion using the example parameters above. */ static const uint8_t dummy_wire_data_fido[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xf7, 0x6f, 0xda, 0x52, 0xfd, 0xcb, 0xb6, 0x24, 0x00, 0x92, 0x00, 0x0e, 0x02, 0x05, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0e, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0xe9, 0x1d, 0x9b, 0xac, 0x14, 0x25, 0x5f, 0xda, 0x1e, 0x11, 0xdb, 0xae, 0xc2, 0x90, 0x22, 0xca, 0x32, 0xec, 0x32, 0xe6, 0x05, 0x15, 0x44, 0xe5, 0xe8, 0xbc, 0x4f, 0x0a, 0xb6, 0x1a, 0xeb, 0x11, 0x22, 0x58, 0x20, 0xcc, 0x72, 0xf0, 0x22, 0xe8, 0x28, 0x82, 0xc5, 0x00, 0x92, 0x00, 0x0e, 0x00, 0xa6, 0x65, 0x6e, 0xff, 0x1e, 0xe3, 0x7f, 0x27, 0x44, 0x2d, 0xfb, 0x8d, 0x41, 0xfa, 0x85, 0x0e, 0xcb, 0xda, 0x95, 0x64, 0x64, 0x9b, 0x1f, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0e, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0xee, 0x40, 0x4c, 0x85, 0xd7, 0xa1, 0x2f, 0x56, 0xc4, 0x4e, 0xc5, 0x93, 0x41, 0xd0, 0x3b, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x0e, 0x90, 0x00, 0xcb, 0x00, 0xa3, 0x01, 0xa2, 0x62, 0x69, 0x64, 0x58, 0x40, 0x4a, 0x4c, 0x9e, 0xcc, 0x81, 0x7d, 0x42, 0x03, 0x2b, 0x41, 0xd1, 0x38, 0xd3, 0x49, 0xb4, 0xfc, 0xfb, 0xe4, 0x4e, 0xe4, 0xff, 0x76, 0x34, 0x16, 0x68, 0x06, 0x9d, 0xa6, 0x01, 0x32, 0xb9, 0xff, 0xc2, 0x35, 0x0d, 0x89, 0x43, 0x66, 0x12, 0xf8, 0x8e, 0x5b, 0xde, 0xf4, 0xcc, 0xec, 0x9d, 0x03, 0x00, 0x92, 0x00, 0x0e, 0x00, 0x85, 0xc2, 0xf5, 0xe6, 0x8e, 0xeb, 0x3f, 0x3a, 0xec, 0xc3, 0x1d, 0x04, 0x6e, 0xf3, 0x5b, 0x88, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x02, 0x58, 0x25, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x00, 0x92, 0x00, 0x0e, 0x01, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x04, 0x00, 0x00, 0x00, 0x09, 0x03, 0x58, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xcf, 0x3f, 0x36, 0x0e, 0x1f, 0x6f, 0xd6, 0xa0, 0x9d, 0x13, 0xcf, 0x55, 0xf7, 0x49, 0x8f, 0xc8, 0xc9, 0x03, 0x12, 0x76, 0x41, 0x75, 0x7b, 0xb5, 0x0a, 0x90, 0xa5, 0x82, 0x26, 0xf1, 0x6b, 0x80, 0x02, 0x20, 0x34, 0x9b, 0x7a, 0x82, 0x00, 0x92, 0x00, 0x0e, 0x02, 0xd3, 0xe1, 0x79, 0x49, 0x55, 0x41, 0x9f, 0xa4, 0x06, 0x06, 0xbd, 0xc8, 0xb9, 0x2b, 0x5f, 0xe1, 0xa7, 0x99, 0x1c, 0xa1, 0xfc, 0x7e, 0x3e, 0xd5, 0x85, 0x2e, 0x11, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* * Collection of HID reports from an authenticator issued with a U2F * authentication using the example parameters above. */ static const uint8_t dummy_wire_data_u2f[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x0f, 0x26, 0x9c, 0xd3, 0x87, 0x0d, 0x7b, 0xf6, 0x00, 0x00, 0x99, 0x01, 0x02, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x30, 0x45, 0x02, 0x20, 0x1c, 0xf5, 0x7c, 0xf6, 0xde, 0xbe, 0xe9, 0x86, 0xee, 0x97, 0xb7, 0x64, 0xa3, 0x4e, 0x7a, 0x70, 0x85, 0xd0, 0x66, 0xf9, 0xf0, 0xcd, 0x04, 0x5d, 0x97, 0xf2, 0x3c, 0x22, 0xe3, 0x0e, 0x61, 0xc8, 0x02, 0x21, 0x00, 0x97, 0xef, 0xae, 0x36, 0xe6, 0x17, 0x9f, 0x5e, 0x2d, 0xd7, 0x8c, 0x34, 0xa7, 0x00, 0x00, 0x99, 0x01, 0x00, 0xa1, 0xe9, 0xfb, 0x8f, 0x86, 0x8c, 0xe3, 0x1e, 0xde, 0x3f, 0x4e, 0x1b, 0xe1, 0x2f, 0x8f, 0x2f, 0xca, 0x42, 0x26, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int LLVMFuzzerTestOneInput(const uint8_t *, size_t); size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); static int unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN { uint8_t **pp = (void *)&ptr; if (unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || unpack_byte(TAG_UP, pp, &len, &p->up) < 0 || unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || unpack_byte(TAG_CRED_COUNT, pp, &len, &p->cred_count) < 0 || unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || unpack_blob(TAG_RS256, pp, &len, &p->rs256) < 0 || unpack_blob(TAG_ES256, pp, &len, &p->es256) < 0 || unpack_blob(TAG_EDDSA, pp, &len, &p->eddsa) < 0 || unpack_blob(TAG_CRED, pp, &len, &p->cred) < 0 || unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0) return (-1); return (0); } static size_t pack(uint8_t *ptr, size_t len, const struct param *p) { const size_t max = len; if (pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || pack_byte(TAG_UP, &ptr, &len, p->up) < 0 || pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || pack_byte(TAG_CRED_COUNT, &ptr, &len, p->cred_count) < 0 || pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || pack_blob(TAG_RS256, &ptr, &len, &p->rs256) < 0 || pack_blob(TAG_ES256, &ptr, &len, &p->es256) < 0 || pack_blob(TAG_EDDSA, &ptr, &len, &p->eddsa) < 0 || pack_blob(TAG_CRED, &ptr, &len, &p->cred) < 0 || pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0) return (0); return (max - len); } static void get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, uint8_t cred_count, struct blob *cred) { fido_dev_t *dev; fido_dev_io_t io; io.open = dev_open; io.close = dev_close; io.read = dev_read; io.write = dev_write; if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); return; } if (u2f & 1) fido_dev_force_u2f(dev); for (uint8_t i = 0; i < cred_count; i++) fido_assert_allow_cred(assert, cred->body, cred->len); fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); fido_assert_set_rp(assert, rp_id); if (ext & 1) fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); /* XXX reuse cred as hmac salt to keep struct param small */ fido_assert_set_hmac_salt(assert, cred->body, cred->len); fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin); fido_dev_cancel(dev); fido_dev_close(dev); fido_dev_free(&dev); } static void verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len, const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, int ext, void *pk) { fido_assert_t *assert = NULL; if ((assert = fido_assert_new()) == NULL) return; fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); fido_assert_set_rp(assert, rp_id); fido_assert_set_count(assert, 1); if (fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len) != FIDO_OK) { fido_assert_set_authdata_raw(assert, 0, authdata_ptr, authdata_len); } fido_assert_set_extensions(assert, ext); if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); fido_assert_set_sig(assert, 0, sig_ptr, sig_len); fido_assert_verify(assert, 0, type, pk); fido_assert_free(&assert); } /* * Do a dummy conversion to exercise rs256_pk_from_RSA(). */ static void rs256_convert(const rs256_pk_t *k) { EVP_PKEY *pkey = NULL; rs256_pk_t *pk = NULL; RSA *rsa = NULL; volatile int r; if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL || (pk = rs256_pk_new()) == NULL || (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) goto out; r = rs256_pk_from_RSA(pk, rsa); out: if (pk) rs256_pk_free(&pk); if (pkey) EVP_PKEY_free(pkey); } /* * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY(). */ static void eddsa_convert(const eddsa_pk_t *k) { EVP_PKEY *pkey = NULL; eddsa_pk_t *pk = NULL; volatile int r; if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL || (pk = eddsa_pk_new()) == NULL) goto out; r = eddsa_pk_from_EVP_PKEY(pk, pkey); out: if (pk) eddsa_pk_free(&pk); if (pkey) EVP_PKEY_free(pkey); } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct param p; fido_assert_t *assert = NULL; es256_pk_t *es256_pk = NULL; rs256_pk_t *rs256_pk = NULL; eddsa_pk_t *eddsa_pk = NULL; uint8_t flags; uint32_t sigcount; int cose_alg = 0; void *pk; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (0); srandom((unsigned int)p.seed); fido_init(0); switch (p.type & 3) { case 0: cose_alg = COSE_ES256; if ((es256_pk = es256_pk_new()) == NULL) return (0); es256_pk_from_ptr(es256_pk, p.es256.body, p.es256.len); pk = es256_pk; break; case 1: cose_alg = COSE_RS256; if ((rs256_pk = rs256_pk_new()) == NULL) return (0); rs256_pk_from_ptr(rs256_pk, p.rs256.body, p.rs256.len); pk = rs256_pk; rs256_convert(pk); break; default: cose_alg = COSE_EDDSA; if ((eddsa_pk = eddsa_pk_new()) == NULL) return (0); eddsa_pk_from_ptr(eddsa_pk, p.eddsa.body, p.eddsa.len); pk = eddsa_pk; eddsa_convert(pk); break; } if ((assert = fido_assert_new()) == NULL) goto out; set_wire_data(p.wire_data.body, p.wire_data.len); get_assert(assert, p.u2f, &p.cdh, p.rp_id, p.ext, p.up, p.uv, p.pin, p.cred_count, &p.cred); /* XXX +1 on purpose */ for (size_t i = 0; i <= fido_assert_count(assert); i++) { verify_assert(cose_alg, fido_assert_clientdata_hash_ptr(assert), fido_assert_clientdata_hash_len(assert), fido_assert_rp_id(assert), fido_assert_authdata_ptr(assert, i), fido_assert_authdata_len(assert, i), fido_assert_sig_ptr(assert, i), fido_assert_sig_len(assert, i), p.up, p.uv, p.ext, pk); consume(fido_assert_id_ptr(assert, i), fido_assert_id_len(assert, i)); consume(fido_assert_user_id_ptr(assert, i), fido_assert_user_id_len(assert, i)); consume(fido_assert_hmac_secret_ptr(assert, i), fido_assert_hmac_secret_len(assert, i)); consume(fido_assert_user_icon(assert, i), xstrlen(fido_assert_user_icon(assert, i))); consume(fido_assert_user_name(assert, i), xstrlen(fido_assert_user_name(assert, i))); consume(fido_assert_user_display_name(assert, i), xstrlen(fido_assert_user_display_name(assert, i))); flags = fido_assert_flags(assert, i); consume(&flags, sizeof(flags)); sigcount = fido_assert_sigcount(assert, i); consume(&sigcount, sizeof(sigcount)); } out: es256_pk_free(&es256_pk); rs256_pk_free(&rs256_pk); eddsa_pk_free(&eddsa_pk); fido_assert_free(&assert); return (0); } static size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[16384]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); dummy.type = 1; dummy.ext = FIDO_EXT_HMAC_SECRET; strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); dummy.cdh.len = sizeof(dummy_cdh); dummy.es256.len = sizeof(dummy_es256); dummy.rs256.len = sizeof(dummy_rs256); dummy.eddsa.len = sizeof(dummy_eddsa); dummy.wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, dummy.wire_data.len); memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len); blob_len = pack(blob, sizeof(blob), &dummy); assert(blob_len != 0); if (blob_len > len) { memcpy(ptr, blob, len); return (len); } memcpy(ptr, blob, blob_len); return (blob_len); } size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, unsigned int seed) NO_MSAN { struct param p; uint8_t blob[16384]; size_t blob_len; (void)seed; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (pack_dummy(data, maxsize)); mutate_byte(&p.uv); mutate_byte(&p.up); mutate_byte(&p.u2f); mutate_byte(&p.type); mutate_byte(&p.cred_count); mutate_int(&p.ext); p.seed = (int)seed; if (p.u2f & 1) { p.wire_data.len = sizeof(dummy_wire_data_u2f); memcpy(&p.wire_data.body, &dummy_wire_data_u2f, p.wire_data.len); } else { p.wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&p.wire_data.body, &dummy_wire_data_fido, p.wire_data.len); } mutate_blob(&p.wire_data); mutate_blob(&p.rs256); mutate_blob(&p.es256); mutate_blob(&p.eddsa); mutate_blob(&p.cred); mutate_blob(&p.cdh); mutate_string(p.rp_id); mutate_string(p.pin); blob_len = pack(blob, sizeof(blob), &p); if (blob_len == 0 || blob_len > maxsize) return (0); memcpy(data, blob, blob_len); return (blob_len); } libfido2-1.3.1/fuzz/fuzz_bio.c000066400000000000000000000644531362326726700162310ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "fido.h" #include "fido/bio.h" #include "../openbsd-compat/openbsd-compat.h" #define TAG_PIN 0x01 #define TAG_NAME 0x02 #define TAG_SEED 0x03 #define TAG_ID 0x04 #define TAG_INFO_WIRE_DATA 0x05 #define TAG_ENROLL_WIRE_DATA 0x06 #define TAG_LIST_WIRE_DATA 0x07 #define TAG_SET_NAME_WIRE_DATA 0x08 #define TAG_REMOVE_WIRE_DATA 0x09 /* Parameter set defining a FIDO2 credential management operation. */ struct param { char pin[MAXSTR]; char name[MAXSTR]; int seed; struct blob id; struct blob info_wire_data; struct blob enroll_wire_data; struct blob list_wire_data; struct blob set_name_wire_data; struct blob remove_wire_data; }; /* Example parameters. */ static const uint8_t dummy_id[] = { 0x5e, 0xd2, }; static const char dummy_pin[] = "3Q;I){TAx"; static const char dummy_name[] = "finger1"; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'getFingerprintSensorInfo' bio enrollment command. */ static const uint8_t dummy_info_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xf0, 0x08, 0xc1, 0x8f, 0x76, 0x4b, 0x8f, 0xa9, 0x00, 0x10, 0x00, 0x04, 0x02, 0x00, 0x04, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x90, 0x00, 0x06, 0x00, 0xa2, 0x02, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* * Collection of HID reports from an authenticator issued with FIDO2 * 'enrollBegin' + 'enrollCaptureNextSample' bio enrollment commands. */ static const uint8_t dummy_enroll_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x06, 0xb4, 0xba, 0x2e, 0xb3, 0x88, 0x24, 0x38, 0x00, 0x0a, 0x00, 0x05, 0x02, 0x00, 0x04, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0xc9, 0x12, 0x01, 0xab, 0x88, 0xd7, 0x0a, 0x24, 0xdd, 0xdc, 0xde, 0x16, 0x27, 0x50, 0x77, 0x37, 0x06, 0xd3, 0x48, 0xe6, 0xf9, 0xdb, 0xaa, 0x10, 0x83, 0x81, 0xac, 0x13, 0x3c, 0xf9, 0x77, 0x2d, 0x22, 0x58, 0x20, 0xda, 0x20, 0x71, 0x03, 0x01, 0x40, 0xac, 0xd0, 0x00, 0x0a, 0x00, 0x05, 0x00, 0xb8, 0xdf, 0x2a, 0x95, 0xd3, 0x88, 0x1c, 0x06, 0x34, 0x30, 0xf1, 0xf3, 0xcd, 0x27, 0x40, 0x90, 0x5c, 0xc6, 0x74, 0x66, 0xff, 0x10, 0xde, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0x18, 0x81, 0xff, 0xf2, 0xf5, 0xde, 0x74, 0x43, 0xd5, 0xe0, 0x77, 0x37, 0x6b, 0x6c, 0x18, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x0a, 0x00, 0xa3, 0x04, 0x42, 0x68, 0x96, 0x05, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, 0xa2, 0x05, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, 0xa2, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'enumerateEnrollments' bio enrollment command. */ static const uint8_t dummy_list_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xae, 0x21, 0x88, 0x51, 0x09, 0x6f, 0xd7, 0xbb, 0x00, 0x10, 0x00, 0x0f, 0x02, 0x00, 0x04, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x5a, 0x70, 0x63, 0x11, 0x5b, 0xa6, 0xe1, 0x8e, 0x4a, 0xb0, 0x75, 0xe7, 0xfd, 0x39, 0x26, 0x29, 0xed, 0x69, 0xb0, 0xc1, 0x1f, 0xa5, 0x7d, 0xcb, 0x64, 0x1e, 0x7c, 0x9f, 0x60, 0x5e, 0xb2, 0xf8, 0x22, 0x58, 0x20, 0xec, 0xe9, 0x1b, 0x11, 0xac, 0x2a, 0x0d, 0xd5, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x3b, 0x9f, 0xba, 0x0f, 0x25, 0xd5, 0x24, 0x33, 0x4c, 0x5d, 0x0f, 0x63, 0xbf, 0xf1, 0xf3, 0x64, 0x55, 0x78, 0x1a, 0x59, 0x6e, 0x65, 0x59, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0xb9, 0x31, 0x34, 0xe2, 0x71, 0x6a, 0x8e, 0xa3, 0x60, 0xec, 0x5e, 0xd2, 0x13, 0x2e, 0x19, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x2e, 0x00, 0xa1, 0x07, 0x83, 0xa2, 0x01, 0x42, 0xce, 0xa3, 0x02, 0x67, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x31, 0xa2, 0x01, 0x42, 0xbf, 0x5e, 0x02, 0x67, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x32, 0xa2, 0x01, 0x42, 0x5e, 0xd2, 0x02, 0x67, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'setFriendlyName' bio enrollment command. */ static const uint8_t dummy_set_name_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xac, 0x48, 0xfd, 0xbd, 0xdd, 0x36, 0x24, 0x4d, 0x00, 0x10, 0x00, 0x10, 0x02, 0x00, 0x04, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x5a, 0x70, 0x63, 0x11, 0x5b, 0xa6, 0xe1, 0x8e, 0x4a, 0xb0, 0x75, 0xe7, 0xfd, 0x39, 0x26, 0x29, 0xed, 0x69, 0xb0, 0xc1, 0x1f, 0xa5, 0x7d, 0xcb, 0x64, 0x1e, 0x7c, 0x9f, 0x60, 0x5e, 0xb2, 0xf8, 0x22, 0x58, 0x20, 0xec, 0xe9, 0x1b, 0x11, 0xac, 0x2a, 0x0d, 0xd5, 0x00, 0x10, 0x00, 0x10, 0x00, 0x3b, 0x9f, 0xba, 0x0f, 0x25, 0xd5, 0x24, 0x33, 0x4c, 0x5d, 0x0f, 0x63, 0xbf, 0xf1, 0xf3, 0x64, 0x55, 0x78, 0x1a, 0x59, 0x6e, 0x65, 0x59, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0x40, 0x95, 0xf3, 0xcb, 0xae, 0xf2, 0x8d, 0xd9, 0xe0, 0xe0, 0x8a, 0xbd, 0xc3, 0x03, 0x58, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x90, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'removeEnrollment' bio enrollment command. */ static const uint8_t dummy_remove_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x4b, 0x24, 0xde, 0xd9, 0x06, 0x57, 0x1a, 0xbd, 0x00, 0x10, 0x00, 0x15, 0x02, 0x00, 0x04, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x15, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x5a, 0x70, 0x63, 0x11, 0x5b, 0xa6, 0xe1, 0x8e, 0x4a, 0xb0, 0x75, 0xe7, 0xfd, 0x39, 0x26, 0x29, 0xed, 0x69, 0xb0, 0xc1, 0x1f, 0xa5, 0x7d, 0xcb, 0x64, 0x1e, 0x7c, 0x9f, 0x60, 0x5e, 0xb2, 0xf8, 0x22, 0x58, 0x20, 0xec, 0xe9, 0x1b, 0x11, 0xac, 0x2a, 0x0d, 0xd5, 0x00, 0x10, 0x00, 0x15, 0x00, 0x3b, 0x9f, 0xba, 0x0f, 0x25, 0xd5, 0x24, 0x33, 0x4c, 0x5d, 0x0f, 0x63, 0xbf, 0xf1, 0xf3, 0x64, 0x55, 0x78, 0x1a, 0x59, 0x6e, 0x65, 0x59, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x15, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0xb0, 0xd0, 0x71, 0x2f, 0xa7, 0x8b, 0x89, 0xbd, 0xca, 0xa4, 0x1e, 0x6c, 0x43, 0xa1, 0x71, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x15, 0x90, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; int LLVMFuzzerTestOneInput(const uint8_t *, size_t); size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); static int unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN { uint8_t **pp = (void *)&ptr; if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || unpack_string(TAG_NAME, pp, &len, p->name) < 0 || unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || unpack_blob(TAG_ID, pp, &len, &p->id) < 0 || unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || unpack_blob(TAG_ENROLL_WIRE_DATA, pp, &len, &p->enroll_wire_data) < 0 || unpack_blob(TAG_LIST_WIRE_DATA, pp, &len, &p->list_wire_data) < 0 || unpack_blob(TAG_SET_NAME_WIRE_DATA, pp, &len, &p->set_name_wire_data) < 0 || unpack_blob(TAG_REMOVE_WIRE_DATA, pp, &len, &p->remove_wire_data) < 0) return (-1); return (0); } static size_t pack(uint8_t *ptr, size_t len, const struct param *p) { const size_t max = len; if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || pack_string(TAG_NAME, &ptr, &len, p->name) < 0 || pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || pack_blob(TAG_ID, &ptr, &len, &p->id) < 0 || pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || pack_blob(TAG_ENROLL_WIRE_DATA, &ptr, &len, &p->enroll_wire_data) < 0 || pack_blob(TAG_LIST_WIRE_DATA, &ptr, &len, &p->list_wire_data) < 0 || pack_blob(TAG_SET_NAME_WIRE_DATA, &ptr, &len, &p->set_name_wire_data) < 0 || pack_blob(TAG_REMOVE_WIRE_DATA, &ptr, &len, &p->remove_wire_data) < 0) return (0); return (max - len); } static fido_dev_t * prepare_dev() { fido_dev_t *dev; fido_dev_io_t io; io.open = dev_open; io.close = dev_close; io.read = dev_read; io.write = dev_write; if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); return (NULL); } return (dev); } static void get_info(struct param *p) { fido_dev_t *dev = NULL; fido_bio_info_t *i = NULL; uint8_t type; uint8_t max_samples; set_wire_data(p->info_wire_data.body, p->info_wire_data.len); if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) goto done; fido_bio_dev_get_info(dev, i); type = fido_bio_info_type(i); max_samples = fido_bio_info_max_samples(i); consume(&type, sizeof(type)); consume(&max_samples, sizeof(max_samples)); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_info_free(&i); } static void consume_template(const fido_bio_template_t *t) { consume(fido_bio_template_name(t), xstrlen(fido_bio_template_name(t))); consume(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t)); } static void consume_enroll(fido_bio_enroll_t *e) { uint8_t last_status; uint8_t remaining_samples; last_status = fido_bio_enroll_last_status(e); remaining_samples = fido_bio_enroll_remaining_samples(e); consume(&last_status, sizeof(last_status)); consume(&remaining_samples, sizeof(remaining_samples)); } static void enroll(struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; fido_bio_enroll_t *e = NULL; size_t cnt = 0; set_wire_data(p->enroll_wire_data.body, p->enroll_wire_data.len); if ((dev = prepare_dev()) == NULL || (t = fido_bio_template_new()) == NULL || (e = fido_bio_enroll_new()) == NULL) goto done; fido_bio_dev_enroll_begin(dev, t, e, p->seed, p->pin); consume_template(t); consume_enroll(e); while (fido_bio_enroll_remaining_samples(e) > 0 && cnt++ < 5) { fido_bio_dev_enroll_continue(dev, t, e, p->seed); consume_template(t); consume_enroll(e); } done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_free(&t); fido_bio_enroll_free(&e); } static void list(struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_array_t *ta = NULL; const fido_bio_template_t *t = NULL; set_wire_data(p->list_wire_data.body, p->list_wire_data.len); if ((dev = prepare_dev()) == NULL || (ta = fido_bio_template_array_new()) == NULL) goto done; fido_bio_dev_get_template_array(dev, ta, p->pin); /* +1 on purpose */ for (size_t i = 0; i < fido_bio_template_array_count(ta) + 1; i++) if ((t = fido_bio_template(ta, i)) != NULL) consume_template(t); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_array_free(&ta); } static void set_name(struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; set_wire_data(p->set_name_wire_data.body, p->set_name_wire_data.len); if ((dev = prepare_dev()) == NULL || (t = fido_bio_template_new()) == NULL) goto done; fido_bio_template_set_name(t, p->name); fido_bio_template_set_id(t, p->id.body, p->id.len); consume_template(t); fido_bio_dev_set_template_name(dev, t, p->pin); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_free(&t); } static void del(struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); if ((dev = prepare_dev()) == NULL || (t = fido_bio_template_new()) == NULL) goto done; fido_bio_template_set_id(t, p->id.body, p->id.len); consume_template(t); fido_bio_dev_enroll_remove(dev, t, p->pin); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_free(&t); } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct param p; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (0); srandom((unsigned int)p.seed); fido_init(0); get_info(&p); enroll(&p); list(&p); set_name(&p); del(&p); return (0); } static size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[32768]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.name, dummy_name, sizeof(dummy.name)); dummy.info_wire_data.len = sizeof(dummy_info_wire_data); dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data); dummy.list_wire_data.len = sizeof(dummy_list_wire_data); dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data); dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data); dummy.id.len = sizeof(dummy_id); memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, dummy.info_wire_data.len); memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data, dummy.enroll_wire_data.len); memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data, dummy.list_wire_data.len); memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data, dummy.set_name_wire_data.len); memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data, dummy.remove_wire_data.len); memcpy(&dummy.id.body, &dummy_id, dummy.id.len); blob_len = pack(blob, sizeof(blob), &dummy); assert(blob_len != 0); if (blob_len > len) { memcpy(ptr, blob, len); return (len); } memcpy(ptr, blob, blob_len); return (blob_len); } size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, unsigned int seed) NO_MSAN { struct param p; uint8_t blob[16384]; size_t blob_len; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (pack_dummy(data, maxsize)); p.seed = (int)seed; mutate_blob(&p.id); mutate_blob(&p.info_wire_data); mutate_blob(&p.enroll_wire_data); mutate_blob(&p.list_wire_data); mutate_blob(&p.set_name_wire_data); mutate_blob(&p.remove_wire_data); mutate_string(p.pin); mutate_string(p.name); blob_len = pack(blob, sizeof(blob), &p); if (blob_len == 0 || blob_len > maxsize) return (0); memcpy(data, blob, blob_len); return (blob_len); } libfido2-1.3.1/fuzz/fuzz_cred.c000066400000000000000000001105221362326726700163620ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "fido.h" #include "../openbsd-compat/openbsd-compat.h" #define TAG_U2F 0x01 #define TAG_TYPE 0x02 #define TAG_CDH 0x03 #define TAG_RP_ID 0x04 #define TAG_RP_NAME 0x05 #define TAG_USER_ID 0x06 #define TAG_USER_NAME 0x07 #define TAG_USER_NICK 0x08 #define TAG_USER_ICON 0x09 #define TAG_EXT 0x0a #define TAG_SEED 0x0b #define TAG_RK 0x0c #define TAG_UV 0x0d #define TAG_PIN 0x0e #define TAG_WIRE_DATA 0x0f #define TAG_EXCL_COUNT 0x10 #define TAG_EXCL_CRED 0x11 /* Parameter set defining a FIDO2 make credential operation. */ struct param { char pin[MAXSTR]; char rp_id[MAXSTR]; char rp_name[MAXSTR]; char user_icon[MAXSTR]; char user_name[MAXSTR]; char user_nick[MAXSTR]; int ext; int seed; struct blob cdh; struct blob excl_cred; struct blob user_id; struct blob wire_data; uint8_t excl_count; uint8_t rk; uint8_t type; uint8_t u2f; uint8_t uv; }; /* Example parameters. */ static const char dummy_rp_id[] = "localhost"; static const char dummy_rp_name[] = "sweet home localhost"; static const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; static const char dummy_user_icon[] = "an icon"; static const char dummy_user_name[] = "john smith"; static const char dummy_user_nick[] = "jsmith"; static const uint8_t dummy_cdh[] = { 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, }; static const uint8_t dummy_user_id[] = { 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * make credential using the example parameters above. */ static const uint8_t dummy_wire_data_fido[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xb0, 0x84, 0xeb, 0xec, 0x4d, 0x97, 0x72, 0x09, 0x00, 0x91, 0x00, 0x03, 0x02, 0x05, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x69, 0xf2, 0x7d, 0x37, 0x57, 0xda, 0x11, 0xba, 0x42, 0xde, 0x79, 0xe4, 0xab, 0x8d, 0x73, 0x63, 0xee, 0x66, 0x9e, 0x8a, 0x70, 0xa9, 0xb5, 0xf6, 0x38, 0x4f, 0x5b, 0xdf, 0xe1, 0xa0, 0xa4, 0xff, 0x22, 0x58, 0x20, 0x8a, 0xcb, 0x23, 0x2e, 0x93, 0xdb, 0xe0, 0xa4, 0x00, 0x91, 0x00, 0x03, 0x00, 0xbb, 0xb5, 0x60, 0x19, 0x18, 0x8b, 0x4d, 0xb8, 0x88, 0x6e, 0x13, 0x75, 0xac, 0x00, 0x19, 0x27, 0x80, 0xcc, 0x63, 0xc4, 0xbf, 0xfe, 0x4b, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0x10, 0x89, 0x77, 0x43, 0x3a, 0x58, 0xa2, 0xc9, 0x98, 0x18, 0x1a, 0xb1, 0xcc, 0x09, 0x6b, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x03, 0x90, 0x03, 0xe1, 0x00, 0xa3, 0x01, 0x66, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x02, 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x45, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x00, 0x91, 0x00, 0x03, 0x00, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0xed, 0x88, 0x48, 0xa1, 0xdb, 0x56, 0x4d, 0x0f, 0x0d, 0xc8, 0x8f, 0x0f, 0xe9, 0x16, 0xb1, 0x78, 0xa9, 0x40, 0x98, 0x71, 0xa0, 0xb3, 0xf2, 0xcf, 0x05, 0x73, 0x6c, 0x12, 0xbf, 0x00, 0x96, 0xf3, 0x7b, 0x93, 0xba, 0x49, 0xee, 0x23, 0xb4, 0x78, 0x2e, 0xfb, 0xce, 0x27, 0xa8, 0xc2, 0x26, 0x78, 0x00, 0x91, 0x00, 0x03, 0x01, 0xcc, 0x95, 0x2d, 0x40, 0xdb, 0xd1, 0x40, 0x3d, 0x2b, 0xa3, 0x31, 0xa0, 0x75, 0x82, 0x63, 0xf0, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x9d, 0x95, 0xa1, 0xb5, 0xd6, 0x11, 0xbf, 0xe2, 0x28, 0xa0, 0x7f, 0xca, 0x1e, 0xd9, 0x09, 0x0f, 0x0d, 0xe7, 0x8e, 0x29, 0xe8, 0x2e, 0x11, 0xdb, 0x55, 0x62, 0x13, 0xd7, 0x26, 0xc2, 0x7e, 0x2b, 0x22, 0x00, 0x91, 0x00, 0x03, 0x02, 0x58, 0x20, 0xbe, 0x74, 0x2a, 0xac, 0xde, 0x11, 0x40, 0x76, 0x31, 0x0b, 0xed, 0x55, 0xde, 0xf3, 0x03, 0xe4, 0x1c, 0xac, 0x42, 0x63, 0x8f, 0xe8, 0x30, 0x63, 0xb7, 0x07, 0x4e, 0x5d, 0xfb, 0x17, 0x5e, 0x9b, 0x03, 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, 0x69, 0x67, 0x58, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xfb, 0xd1, 0x26, 0x76, 0x34, 0x74, 0xac, 0x00, 0x91, 0x00, 0x03, 0x03, 0xf6, 0xd8, 0x5c, 0x5d, 0xbc, 0xda, 0xe0, 0x43, 0xe0, 0xa5, 0x42, 0x9f, 0xc7, 0xe2, 0x18, 0x3e, 0xe2, 0x2c, 0x94, 0x78, 0xbf, 0x9c, 0xeb, 0x3e, 0x9d, 0x02, 0x21, 0x00, 0xab, 0x21, 0x1b, 0xc4, 0x30, 0x69, 0xee, 0x7f, 0x09, 0xe6, 0x6b, 0x99, 0x98, 0x34, 0x07, 0x7b, 0x9a, 0x58, 0xb2, 0xe8, 0x77, 0xe0, 0xba, 0x7d, 0xab, 0x65, 0xf8, 0xba, 0x2a, 0xcb, 0x9a, 0x00, 0x91, 0x00, 0x03, 0x04, 0x41, 0x63, 0x78, 0x35, 0x63, 0x81, 0x59, 0x02, 0xb3, 0x30, 0x82, 0x02, 0xaf, 0x30, 0x82, 0x01, 0x97, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x5b, 0x3d, 0xb6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x21, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x59, 0x75, 0x62, 0x00, 0x91, 0x00, 0x03, 0x05, 0x69, 0x63, 0x6f, 0x20, 0x46, 0x49, 0x44, 0x4f, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, 0x31, 0x32, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x32, 0x33, 0x31, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, 0x5a, 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x00, 0x91, 0x00, 0x03, 0x06, 0x55, 0x04, 0x06, 0x13, 0x02, 0x53, 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x41, 0x42, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x00, 0x91, 0x00, 0x03, 0x07, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x31, 0x32, 0x31, 0x33, 0x39, 0x33, 0x39, 0x31, 0x32, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x00, 0x91, 0x00, 0x03, 0x08, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xfb, 0x2c, 0xdd, 0x30, 0x43, 0x28, 0xc5, 0x72, 0x4a, 0x50, 0xcc, 0xe6, 0xf6, 0x0b, 0xad, 0x7d, 0x27, 0xa9, 0x1b, 0x59, 0xe1, 0xe6, 0x6f, 0x29, 0x7b, 0x89, 0xc9, 0xd4, 0x3d, 0xc2, 0xb2, 0xc7, 0x78, 0x89, 0xb4, 0xf0, 0xff, 0x9d, 0x02, 0x28, 0xcb, 0x94, 0x6d, 0xfc, 0xe0, 0x00, 0x91, 0x00, 0x03, 0x09, 0x1b, 0x19, 0x58, 0x9b, 0x67, 0x80, 0x4a, 0xac, 0x97, 0x7f, 0x28, 0x18, 0x9c, 0xcd, 0xb3, 0x25, 0x74, 0xca, 0x28, 0xa3, 0x6c, 0x30, 0x6a, 0x30, 0x22, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x31, 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x36, 0x00, 0x91, 0x00, 0x03, 0x0a, 0x30, 0x13, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x04, 0x30, 0x30, 0x21, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x01, 0x01, 0x04, 0x04, 0x12, 0x04, 0x10, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x30, 0x0c, 0x06, 0x00, 0x91, 0x00, 0x03, 0x0b, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x32, 0xf3, 0xe4, 0xbd, 0x58, 0xd7, 0x42, 0x2b, 0xaf, 0x49, 0x99, 0x86, 0x08, 0x1f, 0x0d, 0xa9, 0x3b, 0xc6, 0xaa, 0x1c, 0x72, 0x11, 0xf9, 0x28, 0x53, 0xeb, 0xf3, 0xeb, 0x00, 0x91, 0x00, 0x03, 0x0c, 0x73, 0xda, 0x69, 0x3b, 0x06, 0xde, 0x31, 0x33, 0x8e, 0x5d, 0x02, 0xec, 0xf6, 0x76, 0xe9, 0x5c, 0x42, 0xbe, 0xa5, 0x8f, 0x25, 0xd3, 0x37, 0x3f, 0x77, 0xbb, 0x2a, 0x9d, 0x7c, 0xb2, 0x3e, 0x11, 0x8c, 0x41, 0xd4, 0x9a, 0x4c, 0x9a, 0xd8, 0xf3, 0xe2, 0xa4, 0xec, 0x01, 0x77, 0x7a, 0x74, 0xa8, 0xc4, 0x12, 0x43, 0xc3, 0x1e, 0xce, 0x20, 0x8f, 0x2d, 0x0f, 0x6e, 0x00, 0x91, 0x00, 0x03, 0x0d, 0xbc, 0x61, 0x9b, 0xe1, 0x84, 0xa1, 0x72, 0xf6, 0xa9, 0xac, 0xcb, 0xf8, 0x73, 0x6d, 0x5b, 0xe2, 0x98, 0xb3, 0x6b, 0xec, 0xe7, 0x1e, 0x77, 0x8d, 0x0a, 0x69, 0xaa, 0xf9, 0x94, 0xb8, 0x63, 0x6d, 0xe8, 0xfa, 0xf6, 0x2f, 0xd3, 0xce, 0x7f, 0x04, 0x4c, 0x32, 0x2c, 0xf7, 0x26, 0x3e, 0x34, 0x99, 0xe6, 0xa5, 0xb2, 0xb0, 0x2a, 0xbb, 0xad, 0x5b, 0xd9, 0xec, 0xe5, 0x00, 0x91, 0x00, 0x03, 0x0e, 0xb0, 0x71, 0x4d, 0x73, 0xbb, 0x94, 0x61, 0x49, 0x9c, 0x94, 0x2a, 0x5f, 0x1d, 0xcc, 0xaf, 0x65, 0x03, 0x3b, 0x39, 0x39, 0xd4, 0x47, 0xd9, 0xfc, 0xc4, 0x7b, 0x0b, 0x16, 0xd8, 0xe9, 0x01, 0xfc, 0xec, 0x3f, 0x8c, 0x1b, 0xc0, 0xc6, 0xac, 0x0b, 0x5d, 0x74, 0xc7, 0xbb, 0x03, 0x05, 0x69, 0x17, 0xe9, 0x98, 0x1a, 0x19, 0xb9, 0x09, 0x5c, 0xa1, 0xf4, 0xab, 0x9f, 0x00, 0x91, 0x00, 0x03, 0x0f, 0x02, 0x7c, 0x28, 0x0f, 0x8a, 0xf9, 0xed, 0x1d, 0x29, 0x3c, 0xf6, 0xcc, 0x2f, 0x04, 0x6d, 0x9a, 0xd6, 0x62, 0xb4, 0xa9, 0x6e, 0xb1, 0xca, 0xca, 0xac, 0x5e, 0x05, 0x3e, 0x83, 0x91, 0x47, 0x7c, 0x1f, 0x8b, 0x60, 0x01, 0xde, 0x65, 0x3a, 0xbf, 0xf2, 0xaa, 0xbb, 0x55, 0x98, 0x86, 0x91, 0x7e, 0xad, 0x3b, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* * Collection of HID reports from an authenticator issued with a U2F * registration using the example parameters above. */ static const uint8_t dummy_wire_data_u2f[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x8e, 0x80, 0xd0, 0xe2, 0x3b, 0x24, 0x93, 0xea, 0x00, 0x00, 0x99, 0x01, 0x02, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x83, 0x03, 0x1e, 0x05, 0x04, 0x9f, 0xa0, 0xf9, 0x0d, 0x4c, 0xf4, 0xae, 0x96, 0x3c, 0xb7, 0x46, 0xb7, 0x5c, 0x9d, 0x8b, 0x48, 0x19, 0xdf, 0xc4, 0xad, 0xea, 0xb2, 0x70, 0x58, 0x72, 0xd9, 0xce, 0x75, 0xf5, 0xe6, 0x8e, 0x0f, 0x9c, 0x0e, 0x2e, 0x62, 0x3e, 0x91, 0xd3, 0x7b, 0x97, 0x46, 0x60, 0xb9, 0x57, 0x13, 0x97, 0x26, 0xae, 0x0f, 0xb3, 0x8f, 0x2e, 0x9b, 0x3f, 0x00, 0x00, 0x99, 0x01, 0x00, 0xa5, 0x55, 0xec, 0x8c, 0x25, 0x7c, 0x65, 0xb7, 0x09, 0x40, 0x48, 0xae, 0xa8, 0xcb, 0xa1, 0x91, 0xac, 0x40, 0x24, 0xf2, 0x34, 0x6e, 0x3a, 0x8f, 0xa5, 0xb7, 0x48, 0x54, 0x6e, 0xfb, 0xf4, 0x37, 0x88, 0x69, 0x79, 0x6f, 0x12, 0xc1, 0x32, 0xdf, 0x15, 0x5d, 0x6e, 0x82, 0x54, 0xc0, 0x6e, 0x56, 0x4f, 0x3a, 0x9c, 0xc3, 0x96, 0x7a, 0xde, 0xa5, 0xfe, 0xec, 0xd1, 0x00, 0x00, 0x99, 0x01, 0x01, 0x5a, 0x21, 0x85, 0x0e, 0x25, 0x7b, 0x8d, 0x6e, 0x1d, 0x32, 0x29, 0xdb, 0x21, 0xb0, 0xa3, 0x30, 0x82, 0x02, 0x4f, 0x30, 0x82, 0x01, 0x37, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x2a, 0xd9, 0x6a, 0xf3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x00, 0x00, 0x99, 0x01, 0x02, 0x03, 0x13, 0x23, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30, 0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x00, 0x00, 0x99, 0x01, 0x03, 0x35, 0x30, 0x30, 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x26, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x32, 0x33, 0x39, 0x32, 0x35, 0x37, 0x33, 0x34, 0x35, 0x31, 0x36, 0x35, 0x00, 0x00, 0x99, 0x01, 0x04, 0x35, 0x30, 0x33, 0x38, 0x37, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x2f, 0xe1, 0xa2, 0x3e, 0xbf, 0xa5, 0x5b, 0x3e, 0x46, 0x1d, 0x59, 0xa4, 0x35, 0x22, 0xd7, 0x97, 0x48, 0x98, 0x1c, 0xba, 0x6d, 0x28, 0x9a, 0x98, 0xf1, 0xbd, 0x7d, 0x00, 0x00, 0x99, 0x01, 0x05, 0xff, 0x65, 0x66, 0x80, 0xdb, 0xbb, 0xed, 0xbc, 0x2b, 0xae, 0x60, 0x7e, 0x6e, 0xf7, 0x72, 0xf5, 0x76, 0xb0, 0x4d, 0x54, 0xc4, 0xe5, 0xf3, 0x2f, 0x59, 0x6f, 0x26, 0xe6, 0x11, 0x15, 0xc7, 0x27, 0x2c, 0xf6, 0xca, 0x75, 0x94, 0xa3, 0x3b, 0x30, 0x39, 0x30, 0x22, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, 0x00, 0x00, 0x99, 0x01, 0x06, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x31, 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x32, 0x30, 0x13, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x04, 0x30, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x00, 0x00, 0x99, 0x01, 0x07, 0x85, 0x6a, 0xfa, 0x8b, 0xcf, 0x4f, 0x3f, 0x62, 0x5f, 0x29, 0x1b, 0xc1, 0x15, 0x8e, 0x3c, 0x7e, 0xbd, 0x25, 0x52, 0xbc, 0xf7, 0x57, 0x07, 0x53, 0xf5, 0x12, 0x1d, 0xa6, 0xa5, 0x4d, 0x24, 0xcc, 0xcf, 0xae, 0x27, 0xce, 0xd6, 0xab, 0x31, 0x12, 0x8c, 0x29, 0x7e, 0x5b, 0x5b, 0x89, 0x05, 0xdd, 0xa0, 0x20, 0x17, 0x93, 0x1f, 0x1f, 0x5f, 0x59, 0x25, 0x93, 0x59, 0x00, 0x00, 0x99, 0x01, 0x08, 0x51, 0xfc, 0x00, 0x4b, 0xcb, 0xe2, 0x0a, 0xdd, 0x7d, 0x8d, 0x05, 0x2f, 0x95, 0x43, 0xb3, 0x49, 0x6c, 0x15, 0xb8, 0x31, 0x0e, 0x10, 0xcb, 0xd9, 0xbb, 0x05, 0x38, 0x27, 0x4f, 0x58, 0x3e, 0xad, 0x1f, 0x45, 0x12, 0x88, 0xc3, 0xea, 0x76, 0xd0, 0x70, 0xad, 0x44, 0xe5, 0x3a, 0xfe, 0xa8, 0xf2, 0x2d, 0x1f, 0x73, 0x62, 0x5f, 0xf2, 0xd5, 0x89, 0xfe, 0x30, 0xdf, 0x00, 0x00, 0x99, 0x01, 0x09, 0x26, 0x62, 0xcb, 0x7c, 0xbb, 0x7c, 0x99, 0x61, 0x80, 0xad, 0xcf, 0xa9, 0x8a, 0x4d, 0x01, 0x2c, 0xf3, 0x13, 0x46, 0xcd, 0x11, 0x74, 0x6a, 0x58, 0x48, 0xe8, 0xbe, 0xed, 0xf3, 0xe3, 0x0c, 0xcb, 0xd9, 0xc1, 0xdd, 0x22, 0x16, 0x71, 0xb2, 0x83, 0x88, 0x61, 0xf6, 0x5a, 0x45, 0x36, 0x23, 0xb5, 0x18, 0xd5, 0x56, 0x7f, 0xa8, 0xf0, 0xa3, 0xce, 0x10, 0x5d, 0xf4, 0x00, 0x00, 0x99, 0x01, 0x0a, 0xf1, 0x39, 0x53, 0xe1, 0x14, 0xea, 0x59, 0xe0, 0xa7, 0xf2, 0xfe, 0x66, 0x88, 0x67, 0x43, 0x2e, 0x52, 0xfd, 0x6a, 0x2f, 0x64, 0xf7, 0x3c, 0x48, 0xcd, 0x9b, 0x38, 0xf2, 0xdf, 0xba, 0x2c, 0x7a, 0x4b, 0x3b, 0x11, 0x28, 0xdf, 0x26, 0xd6, 0x6a, 0x24, 0xf8, 0x95, 0xdd, 0xa0, 0xb6, 0x11, 0x80, 0xf4, 0x14, 0x4f, 0x6b, 0x70, 0x75, 0xc3, 0x18, 0xa4, 0x9a, 0xe0, 0x00, 0x00, 0x99, 0x01, 0x0b, 0x8b, 0x58, 0xd3, 0x6a, 0xdb, 0x1e, 0x30, 0x53, 0x67, 0x2b, 0x17, 0xc5, 0xa1, 0x9f, 0x7f, 0x0a, 0x22, 0xf1, 0x0e, 0x94, 0x30, 0x44, 0x02, 0x20, 0x07, 0x5c, 0x4f, 0xd2, 0x83, 0xb6, 0x9f, 0x0a, 0x4a, 0x4d, 0x4b, 0x08, 0x35, 0xeb, 0xc0, 0x7e, 0x4a, 0x14, 0x2e, 0xc7, 0x8c, 0xd6, 0x64, 0x2f, 0xd3, 0x1e, 0xcc, 0xb5, 0xe8, 0x42, 0xea, 0xf6, 0x02, 0x20, 0x6b, 0x00, 0x00, 0x99, 0x01, 0x0c, 0x5a, 0xba, 0x4a, 0xc8, 0xd7, 0x89, 0xcc, 0x77, 0xe6, 0xb9, 0xa3, 0x34, 0xea, 0x06, 0x85, 0x72, 0xc6, 0x28, 0xa8, 0x7a, 0xaa, 0x19, 0x88, 0x34, 0xbb, 0xdc, 0x64, 0x90, 0x0a, 0xdb, 0x39, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int LLVMFuzzerTestOneInput(const uint8_t *, size_t); size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); static int unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN { uint8_t **pp = (void *)&ptr; if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) return (-1); return (0); } static size_t pack(uint8_t *ptr, size_t len, const struct param *p) { const size_t max = len; if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) return (0); return (max - len); } static void make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, const char *rp_id, const char *rp_name, struct blob *user_id, const char *user_name, const char *user_nick, const char *user_icon, int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, struct blob *excl_cred) { fido_dev_t *dev; fido_dev_io_t io; io.open = dev_open; io.close = dev_close; io.read = dev_read; io.write = dev_write; if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); return; } if (u2f & 1) fido_dev_force_u2f(dev); for (uint8_t i = 0; i < excl_count; i++) fido_cred_exclude(cred, excl_cred->body, excl_cred->len); fido_cred_set_type(cred, type); fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); fido_cred_set_rp(cred, rp_id, rp_name); fido_cred_set_user(cred, user_id->body, user_id->len, user_name, user_nick, user_icon); fido_cred_set_extensions(cred, ext); if (rk & 1) fido_cred_set_rk(cred, FIDO_OPT_TRUE); if (uv & 1) fido_cred_set_uv(cred, FIDO_OPT_TRUE); fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); fido_dev_cancel(dev); fido_dev_close(dev); fido_dev_free(&dev); } static void verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr, size_t authdata_len, int ext, uint8_t rk, uint8_t uv, const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, size_t sig_len, const char *fmt) { fido_cred_t *cred; uint8_t flags; if ((cred = fido_cred_new()) == NULL) { warnx("%s: fido_cred_new", __func__); return; } fido_cred_set_type(cred, type); fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len); fido_cred_set_rp(cred, rp_id, rp_name); if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len); fido_cred_set_extensions(cred, ext); fido_cred_set_x509(cred, x5c_ptr, x5c_len); fido_cred_set_sig(cred, sig_ptr, sig_len); if (rk & 1) fido_cred_set_rk(cred, FIDO_OPT_TRUE); if (uv & 1) fido_cred_set_uv(cred, FIDO_OPT_TRUE); if (fmt) fido_cred_set_fmt(cred, fmt); fido_cred_verify(cred); fido_cred_verify_self(cred); consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); consume(fido_cred_display_name(cred), xstrlen(fido_cred_display_name(cred))); flags = fido_cred_flags(cred); consume(&flags, sizeof(flags)); type = fido_cred_type(cred); consume(&type, sizeof(type)); fido_cred_free(&cred); } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct param p; fido_cred_t *cred = NULL; int cose_alg = 0; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (0); srandom((unsigned int)p.seed); fido_init(0); if ((cred = fido_cred_new()) == NULL) return (0); set_wire_data(p.wire_data.body, p.wire_data.len); switch (p.type & 3) { case 0: cose_alg = COSE_ES256; break; case 1: cose_alg = COSE_RS256; break; default: cose_alg = COSE_EDDSA; break; } make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name, &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk, p.uv, p.pin, p.excl_count, &p.excl_cred); verify_cred(cose_alg, fido_cred_clientdata_hash_ptr(cred), fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred), p.ext, p.rk, p.uv, fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), fido_cred_fmt(cred)); fido_cred_free(&cred); return (0); } static size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[16384]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); dummy.type = 1; dummy.ext = FIDO_EXT_HMAC_SECRET; strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); dummy.cdh.len = sizeof(dummy_cdh); dummy.user_id.len = sizeof(dummy_user_id); dummy.wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, dummy.wire_data.len); blob_len = pack(blob, sizeof(blob), &dummy); assert(blob_len != 0); if (blob_len > len) { memcpy(ptr, blob, len); return (len); } memcpy(ptr, blob, blob_len); return (blob_len); } size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, unsigned int seed) NO_MSAN { struct param p; uint8_t blob[16384]; size_t blob_len; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (pack_dummy(data, maxsize)); mutate_byte(&p.rk); mutate_byte(&p.type); mutate_byte(&p.u2f); mutate_byte(&p.uv); mutate_byte(&p.excl_count); mutate_int(&p.ext); p.seed = (int)seed; mutate_blob(&p.cdh); mutate_blob(&p.user_id); if (p.u2f & 1) { p.wire_data.len = sizeof(dummy_wire_data_u2f); memcpy(&p.wire_data.body, &dummy_wire_data_u2f, p.wire_data.len); } else { p.wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&p.wire_data.body, &dummy_wire_data_fido, p.wire_data.len); } mutate_blob(&p.wire_data); mutate_blob(&p.excl_cred); mutate_string(p.pin); mutate_string(p.user_icon); mutate_string(p.user_name); mutate_string(p.user_nick); mutate_string(p.rp_id); mutate_string(p.rp_name); blob_len = pack(blob, sizeof(blob), &p); if (blob_len == 0 || blob_len > maxsize) return (0); memcpy(data, blob, blob_len); return (blob_len); } libfido2-1.3.1/fuzz/fuzz_credman.c000066400000000000000000000564651362326726700170750ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "fido.h" #include "fido/credman.h" #include "../openbsd-compat/openbsd-compat.h" #define TAG_META_WIRE_DATA 0x01 #define TAG_RP_WIRE_DATA 0x02 #define TAG_RK_WIRE_DATA 0x03 #define TAG_DEL_WIRE_DATA 0x04 #define TAG_CRED_ID 0x05 #define TAG_PIN 0x06 #define TAG_RP_ID 0x07 #define TAG_SEED 0x08 /* Parameter set defining a FIDO2 credential management operation. */ struct param { char pin[MAXSTR]; char rp_id[MAXSTR]; int seed; struct blob cred_id; struct blob del_wire_data; struct blob meta_wire_data; struct blob rk_wire_data; struct blob rp_wire_data; }; /* Example parameters. */ static const uint8_t dummy_cred_id[] = { 0x4f, 0x72, 0x98, 0x42, 0x4a, 0xe1, 0x17, 0xa5, 0x85, 0xa0, 0xef, 0x3b, 0x11, 0x24, 0x4a, 0x3d, }; static const char dummy_pin[] = "[n#899:~m"; static const char dummy_rp_id[] = "yubico.com"; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'getCredsMetadata' credential management command. */ static const uint8_t dummy_meta_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xc5, 0xb7, 0x89, 0xba, 0x8d, 0x5f, 0x94, 0x1b, 0x00, 0x12, 0x00, 0x04, 0x02, 0x00, 0x04, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x93, 0xc5, 0x64, 0x71, 0xe9, 0xd1, 0xb8, 0xed, 0xf6, 0xd5, 0xf3, 0xa7, 0xd5, 0x96, 0x70, 0xbb, 0xd5, 0x20, 0xa1, 0xa3, 0xd3, 0x93, 0x4c, 0x5c, 0x20, 0x5c, 0x22, 0xeb, 0xb0, 0x6a, 0x27, 0x59, 0x22, 0x58, 0x20, 0x63, 0x02, 0x33, 0xa8, 0xed, 0x3c, 0xbc, 0xe9, 0x00, 0x12, 0x00, 0x04, 0x00, 0xda, 0x44, 0xf5, 0xed, 0xda, 0xe6, 0xa4, 0xad, 0x3f, 0x9e, 0xf8, 0x50, 0x8d, 0x01, 0x47, 0x6c, 0x4e, 0x72, 0xa4, 0x04, 0x13, 0xa8, 0x65, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0x6f, 0x11, 0x96, 0x21, 0x92, 0x52, 0xf1, 0x6b, 0xd4, 0x2c, 0xe3, 0xf8, 0xc9, 0x8c, 0x47, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x07, 0x00, 0xa2, 0x01, 0x00, 0x02, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'enumerateRPsBegin' credential management command. */ static const uint8_t dummy_rp_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x87, 0xbf, 0xc6, 0x7f, 0x36, 0xf5, 0xe2, 0x49, 0x00, 0x15, 0x00, 0x02, 0x02, 0x00, 0x04, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x12, 0xc1, 0x81, 0x6b, 0x92, 0x6a, 0x56, 0x05, 0xfe, 0xdb, 0xab, 0x90, 0x2f, 0x57, 0x0b, 0x3d, 0x85, 0x3e, 0x3f, 0xbc, 0xe5, 0xd3, 0xb6, 0x86, 0xdf, 0x10, 0x43, 0xc2, 0xaf, 0x87, 0x34, 0x0e, 0x22, 0x58, 0x20, 0xd3, 0x0f, 0x7e, 0x5d, 0x10, 0x33, 0x57, 0x24, 0x00, 0x15, 0x00, 0x02, 0x00, 0x6e, 0x90, 0x58, 0x61, 0x2a, 0xd2, 0xc2, 0x1e, 0x08, 0xea, 0x91, 0xcb, 0x44, 0x66, 0x73, 0x29, 0x92, 0x29, 0x59, 0x91, 0xa3, 0x4d, 0x2c, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0x6d, 0x95, 0x0e, 0x73, 0x78, 0x46, 0x13, 0x2e, 0x07, 0xbf, 0xeb, 0x61, 0x31, 0x37, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, 0xa3, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6a, 0x79, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x04, 0x58, 0x20, 0x37, 0x82, 0x09, 0xb7, 0x2d, 0xef, 0xcb, 0xa9, 0x1d, 0xcb, 0xf8, 0x54, 0xed, 0xb4, 0xda, 0xa6, 0x48, 0x82, 0x8a, 0x2c, 0xbd, 0x18, 0x0a, 0xfc, 0x77, 0xa7, 0x44, 0x34, 0x65, 0x5a, 0x1c, 0x7d, 0x05, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x36, 0x00, 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6b, 0x79, 0x75, 0x62, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x6f, 0x72, 0x67, 0x04, 0x58, 0x20, 0x12, 0x6b, 0xba, 0x6a, 0x2d, 0x7a, 0x81, 0x84, 0x25, 0x7b, 0x74, 0xdd, 0x1d, 0xdd, 0x46, 0xb6, 0x2a, 0x8c, 0xa2, 0xa7, 0x83, 0xfe, 0xdb, 0x5b, 0x19, 0x48, 0x73, 0x55, 0xb7, 0xe3, 0x46, 0x09, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6c, 0x77, 0x65, 0x62, 0x61, 0x75, 0x74, 0x68, 0x6e, 0x2e, 0x64, 0x65, 0x76, 0x04, 0x58, 0x20, 0xd6, 0x32, 0x7d, 0x8c, 0x6a, 0x5d, 0xe6, 0xae, 0x0e, 0x33, 0xd0, 0xa3, 0x31, 0xfb, 0x67, 0x77, 0xb9, 0x4e, 0xf4, 0x73, 0x19, 0xfe, 0x7e, 0xfd, 0xfa, 0x82, 0x70, 0x8e, 0x1f, 0xbb, 0xa2, 0x55, 0x00, 0x00, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'enumerateCredentialsBegin' credential management command. */ static const uint8_t dummy_rk_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x35, 0x3b, 0x34, 0xb9, 0xcb, 0xeb, 0x40, 0x55, 0x00, 0x15, 0x00, 0x04, 0x02, 0x00, 0x04, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x12, 0xc1, 0x81, 0x6b, 0x92, 0x6a, 0x56, 0x05, 0xfe, 0xdb, 0xab, 0x90, 0x2f, 0x57, 0x0b, 0x3d, 0x85, 0x3e, 0x3f, 0xbc, 0xe5, 0xd3, 0xb6, 0x86, 0xdf, 0x10, 0x43, 0xc2, 0xaf, 0x87, 0x34, 0x0e, 0x22, 0x58, 0x20, 0xd3, 0x0f, 0x7e, 0x5d, 0x10, 0x33, 0x57, 0x24, 0x00, 0x15, 0x00, 0x04, 0x00, 0x6e, 0x90, 0x58, 0x61, 0x2a, 0xd2, 0xc2, 0x1e, 0x08, 0xea, 0x91, 0xcb, 0x44, 0x66, 0x73, 0x29, 0x92, 0x29, 0x59, 0x91, 0xa3, 0x4d, 0x2c, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0x1b, 0xf0, 0x01, 0x0d, 0x32, 0xee, 0x28, 0xa4, 0x5a, 0x7f, 0x56, 0x5b, 0x28, 0xfd, 0x1f, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc5, 0x00, 0xa5, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, 0xe4, 0xe1, 0x06, 0x31, 0xde, 0x00, 0x0f, 0x4f, 0x12, 0x6e, 0xc9, 0x68, 0x2d, 0x43, 0x3f, 0xf1, 0x02, 0x2c, 0x6e, 0xe6, 0x96, 0x10, 0xbf, 0x73, 0x35, 0xc9, 0x20, 0x27, 0x06, 0xba, 0x39, 0x09, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x19, 0xf7, 0x78, 0x0c, 0xa0, 0xbc, 0xb9, 0xa6, 0xd5, 0x1e, 0xd7, 0x87, 0xfb, 0x6c, 0x80, 0x03, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x81, 0x6c, 0xdd, 0x8c, 0x8f, 0x8c, 0xc8, 0x43, 0xa7, 0xbb, 0x79, 0x51, 0x09, 0xb1, 0xdf, 0xbe, 0xc4, 0xa5, 0x54, 0x16, 0x9e, 0x58, 0x56, 0xb3, 0x0b, 0x34, 0x4f, 0xa5, 0x6c, 0x05, 0xa2, 0x21, 0x22, 0x58, 0x20, 0xcd, 0xc2, 0x0c, 0x99, 0x83, 0x5a, 0x61, 0x73, 0xd8, 0xe0, 0x74, 0x23, 0x46, 0x64, 0x00, 0x15, 0x00, 0x04, 0x02, 0x39, 0x4c, 0xb0, 0xf4, 0x6c, 0x0a, 0x37, 0x72, 0xaa, 0xa8, 0xea, 0x58, 0xd3, 0xd4, 0xe0, 0x51, 0xb2, 0x28, 0x09, 0x05, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, 0x56, 0xa1, 0x3c, 0x06, 0x2b, 0xad, 0xa2, 0x21, 0x7d, 0xcd, 0x91, 0x08, 0x47, 0xa8, 0x8a, 0x06, 0x06, 0xf6, 0x66, 0x91, 0xf6, 0xeb, 0x89, 0xe4, 0xdf, 0x26, 0xbc, 0x46, 0x59, 0xc3, 0x7d, 0xc0, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xd8, 0x27, 0x4b, 0x25, 0xed, 0x19, 0xef, 0x11, 0xaf, 0xa6, 0x89, 0x7b, 0x84, 0x50, 0xe7, 0x62, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x8d, 0xfe, 0x45, 0xd5, 0x7d, 0xb6, 0x17, 0xab, 0x86, 0x2d, 0x32, 0xf6, 0x85, 0xf0, 0x92, 0x76, 0xb7, 0xce, 0x73, 0xca, 0x4e, 0x0e, 0xfd, 0xd5, 0xdb, 0x2a, 0x1d, 0x55, 0x90, 0x96, 0x52, 0xc2, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, 0x04, 0x0e, 0x0f, 0xa0, 0xcd, 0x60, 0x35, 0x9a, 0xba, 0x47, 0x0c, 0x10, 0xb6, 0x82, 0x6e, 0x2f, 0x66, 0xb9, 0xa7, 0xcf, 0xd8, 0x47, 0xb4, 0x3d, 0xfd, 0x77, 0x1a, 0x38, 0x22, 0xa1, 0xda, 0xa5, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x00, 0x5d, 0xdf, 0xef, 0xe2, 0xf3, 0x06, 0xb2, 0xa5, 0x46, 0x4d, 0x98, 0xbc, 0x14, 0x65, 0xc1, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x72, 0x79, 0x14, 0x69, 0xdf, 0xcb, 0x64, 0x75, 0xee, 0xd4, 0x45, 0x94, 0xbc, 0x48, 0x4d, 0x2a, 0x9f, 0xc9, 0xf4, 0xb5, 0x1b, 0x05, 0xa6, 0x5b, 0x54, 0x9a, 0xac, 0x6c, 0x2e, 0xc6, 0x90, 0x62, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, 0xce, 0x32, 0xd8, 0x79, 0xdd, 0x86, 0xa2, 0x42, 0x7c, 0xc3, 0xe1, 0x95, 0x12, 0x93, 0x1a, 0x03, 0xe6, 0x70, 0xb8, 0xff, 0xcd, 0xa5, 0xdf, 0x15, 0xfc, 0x88, 0x2a, 0xf5, 0x44, 0xf1, 0x33, 0x9c, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x0a, 0x26, 0x5b, 0x7e, 0x1a, 0x2a, 0xba, 0x70, 0x5f, 0x18, 0x26, 0x14, 0xb2, 0x71, 0xca, 0x98, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x8b, 0x48, 0xf0, 0x69, 0xfb, 0x22, 0xfb, 0xf3, 0x86, 0x57, 0x7c, 0xdd, 0x82, 0x2c, 0x1c, 0x0c, 0xdc, 0x27, 0xe2, 0x6a, 0x4c, 0x1a, 0x10, 0x04, 0x27, 0x51, 0x3e, 0x2a, 0x9d, 0x3a, 0xb6, 0xb5, 0x22, 0x58, 0x20, 0x70, 0xfe, 0x91, 0x67, 0x64, 0x53, 0x63, 0x83, 0x72, 0x31, 0xe9, 0xe5, 0x20, 0xb7, 0x00, 0x15, 0x00, 0x04, 0x02, 0xee, 0xc9, 0xfb, 0x63, 0xd7, 0xe4, 0x76, 0x39, 0x80, 0x82, 0x74, 0xb8, 0xfa, 0x67, 0xf5, 0x1b, 0x8f, 0xe0, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, 0xf9, 0xa3, 0x67, 0xbf, 0x5e, 0x80, 0x95, 0xdb, 0x4c, 0xc5, 0x8f, 0x65, 0x36, 0xc5, 0xaf, 0xdd, 0x90, 0x2e, 0x62, 0x68, 0x67, 0x9c, 0xa2, 0x26, 0x2f, 0x2a, 0xf9, 0x3a, 0xda, 0x15, 0xf2, 0x27, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xfb, 0xa6, 0xbe, 0xc1, 0x01, 0xf6, 0x7a, 0x81, 0xf9, 0xcd, 0x6d, 0x20, 0x41, 0x7a, 0x1c, 0x40, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xda, 0x2b, 0x53, 0xc3, 0xbe, 0x48, 0xf8, 0xab, 0xbd, 0x06, 0x28, 0x46, 0xfa, 0x35, 0xab, 0xf9, 0xc5, 0x2e, 0xfd, 0x3c, 0x38, 0x88, 0xb3, 0xe1, 0xa7, 0xc5, 0xc6, 0xed, 0x72, 0x54, 0x37, 0x93, 0x22, 0x58, 0x20, 0x12, 0x82, 0x32, 0x2d, 0xab, 0xbc, 0x64, 0xb3, 0xed, 0xcc, 0xd5, 0x22, 0xec, 0x79, 0x00, 0x15, 0x00, 0x04, 0x02, 0x4b, 0xe2, 0x4d, 0x0c, 0x4b, 0x8d, 0x31, 0x4c, 0xb4, 0x0f, 0xd4, 0xa9, 0xbe, 0x0c, 0xab, 0x9e, 0x0a, 0xc9, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'deleteCredential' credential management command. */ static const uint8_t dummy_del_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x8b, 0xe1, 0xf0, 0x3a, 0x18, 0xa5, 0xda, 0x59, 0x00, 0x15, 0x00, 0x05, 0x02, 0x00, 0x04, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x05, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x12, 0xc1, 0x81, 0x6b, 0x92, 0x6a, 0x56, 0x05, 0xfe, 0xdb, 0xab, 0x90, 0x2f, 0x57, 0x0b, 0x3d, 0x85, 0x3e, 0x3f, 0xbc, 0xe5, 0xd3, 0xb6, 0x86, 0xdf, 0x10, 0x43, 0xc2, 0xaf, 0x87, 0x34, 0x0e, 0x22, 0x58, 0x20, 0xd3, 0x0f, 0x7e, 0x5d, 0x10, 0x33, 0x57, 0x24, 0x00, 0x15, 0x00, 0x05, 0x00, 0x6e, 0x90, 0x58, 0x61, 0x2a, 0xd2, 0xc2, 0x1e, 0x08, 0xea, 0x91, 0xcb, 0x44, 0x66, 0x73, 0x29, 0x92, 0x29, 0x59, 0x91, 0xa3, 0x4d, 0x2c, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x05, 0x90, 0x00, 0x14, 0x00, 0xa1, 0x02, 0x50, 0x33, 0xf1, 0x3b, 0xde, 0x1e, 0xa5, 0xd1, 0xbf, 0xf6, 0x5d, 0x63, 0xb6, 0xfc, 0xd2, 0x24, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x05, 0x90, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; int LLVMFuzzerTestOneInput(const uint8_t *, size_t); size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); static int unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN { uint8_t **pp = (void *)&ptr; if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) return (-1); return (0); } static size_t pack(uint8_t *ptr, size_t len, const struct param *p) { const size_t max = len; if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) return (0); return (max - len); } static fido_dev_t * prepare_dev() { fido_dev_t *dev; fido_dev_io_t io; io.open = dev_open; io.close = dev_close; io.read = dev_read; io.write = dev_write; if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); return (NULL); } return (dev); } static void get_metadata(struct param *p) { fido_dev_t *dev; fido_credman_metadata_t *metadata; uint64_t existing; uint64_t remaining; set_wire_data(p->meta_wire_data.body, p->meta_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } if ((metadata = fido_credman_metadata_new()) == NULL) { fido_dev_close(dev); fido_dev_free(&dev); return; } fido_credman_get_dev_metadata(dev, metadata, p->pin); existing = fido_credman_rk_existing(metadata); remaining = fido_credman_rk_remaining(metadata); consume(&existing, sizeof(existing)); consume(&remaining, sizeof(remaining)); fido_credman_metadata_free(&metadata); fido_dev_close(dev); fido_dev_free(&dev); } static void get_rp_list(struct param *p) { fido_dev_t *dev; fido_credman_rp_t *rp; set_wire_data(p->rp_wire_data.body, p->rp_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } if ((rp = fido_credman_rp_new()) == NULL) { fido_dev_close(dev); fido_dev_free(&dev); return; } fido_credman_get_dev_rp(dev, rp, p->pin); /* +1 on purpose */ for (size_t i = 0; i < fido_credman_rp_count(rp) + 1; i++) { consume(fido_credman_rp_id_hash_ptr(rp, i), fido_credman_rp_id_hash_len(rp, i)); consume(fido_credman_rp_id(rp, i), xstrlen(fido_credman_rp_id(rp, i))); consume(fido_credman_rp_name(rp, i), xstrlen(fido_credman_rp_name(rp, i))); } fido_credman_rp_free(&rp); fido_dev_close(dev); fido_dev_free(&dev); } static void get_rk_list(struct param *p) { fido_dev_t *dev; fido_credman_rk_t *rk; const fido_cred_t *cred; int type; set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } if ((rk = fido_credman_rk_new()) == NULL) { fido_dev_close(dev); fido_dev_free(&dev); return; } fido_credman_get_dev_rk(dev, p->rp_id, rk, p->pin); /* +1 on purpose */ for (size_t i = 0; i < fido_credman_rk_count(rk) + 1; i++) { if ((cred = fido_credman_rk(rk, i)) == NULL) { assert(i >= fido_credman_rk_count(rk)); continue; } type = fido_cred_type(cred); consume(&type, sizeof(type)); consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); consume(fido_cred_display_name(cred), xstrlen(fido_cred_display_name(cred))); } fido_credman_rk_free(&rk); fido_dev_close(dev); fido_dev_free(&dev); } static void del_rk(struct param *p) { fido_dev_t *dev; set_wire_data(p->del_wire_data.body, p->del_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } fido_credman_del_dev_rk(dev, p->cred_id.body, p->cred_id.len, p->pin); fido_dev_close(dev); fido_dev_free(&dev); } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct param p; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (0); srandom((unsigned int)p.seed); fido_init(0); get_metadata(&p); get_rp_list(&p); get_rk_list(&p); del_rk(&p); return (0); } static size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[32768]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); dummy.del_wire_data.len = sizeof(dummy_del_wire_data); dummy.cred_id.len = sizeof(dummy_cred_id); memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, dummy.meta_wire_data.len); memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, dummy.rp_wire_data.len); memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, dummy.rk_wire_data.len); memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, dummy.del_wire_data.len); memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len); blob_len = pack(blob, sizeof(blob), &dummy); assert(blob_len != 0); if (blob_len > len) { memcpy(ptr, blob, len); return (len); } memcpy(ptr, blob, blob_len); return (blob_len); } size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, unsigned int seed) NO_MSAN { struct param p; uint8_t blob[16384]; size_t blob_len; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (pack_dummy(data, maxsize)); p.seed = (int)seed; mutate_blob(&p.cred_id); mutate_blob(&p.meta_wire_data); mutate_blob(&p.rp_wire_data); mutate_blob(&p.rk_wire_data); mutate_blob(&p.del_wire_data); mutate_string(p.pin); mutate_string(p.rp_id); blob_len = pack(blob, sizeof(blob), &p); if (blob_len == 0 || blob_len > maxsize) return (0); memcpy(data, blob, blob_len); return (blob_len); } libfido2-1.3.1/fuzz/fuzz_mgmt.c000066400000000000000000000412751362326726700164210ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "fido.h" #include "../openbsd-compat/openbsd-compat.h" #define TAG_PIN1 0x01 #define TAG_PIN2 0x02 #define TAG_RESET_WIRE_DATA 0x03 #define TAG_INFO_WIRE_DATA 0x04 #define TAG_SET_PIN_WIRE_DATA 0x05 #define TAG_CHANGE_PIN_WIRE_DATA 0x06 #define TAG_RETRY_WIRE_DATA 0x07 #define TAG_SEED 0x08 struct param { char pin1[MAXSTR]; char pin2[MAXSTR]; struct blob reset_wire_data; struct blob info_wire_data; struct blob set_pin_wire_data; struct blob change_pin_wire_data; struct blob retry_wire_data; int seed; }; /* Example parameters. */ static const char dummy_pin1[] = "skepp cg0u3;Y.."; static const char dummy_pin2[] = "bastilha 6rJrfQZI."; static const uint8_t dummy_reset_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x91, 0xef, 0xbe, 0x74, 0x39, 0x1a, 0x1c, 0x4a, 0x00, 0x22, 0x00, 0x01, 0x02, 0x05, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x90, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t dummy_info_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x80, 0x43, 0x56, 0x40, 0xb1, 0x4e, 0xd9, 0x2d, 0x00, 0x22, 0x00, 0x02, 0x02, 0x05, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0xb9, 0x00, 0xa9, 0x01, 0x83, 0x66, 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x68, 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x6c, 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x31, 0x5f, 0x50, 0x52, 0x45, 0x02, 0x82, 0x6b, 0x63, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x6b, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, 0x00, 0x22, 0x00, 0x02, 0x00, 0x65, 0x74, 0x03, 0x50, 0x19, 0x56, 0xe5, 0xbd, 0xa3, 0x74, 0x45, 0xf1, 0xa8, 0x14, 0x35, 0x64, 0x03, 0xfd, 0xbc, 0x18, 0x04, 0xa5, 0x62, 0x72, 0x6b, 0xf5, 0x62, 0x75, 0x70, 0xf5, 0x64, 0x70, 0x6c, 0x61, 0x74, 0xf4, 0x69, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x69, 0x6e, 0xf4, 0x75, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4d, 0x00, 0x22, 0x00, 0x02, 0x01, 0x67, 0x6d, 0x74, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0xf5, 0x05, 0x19, 0x04, 0xb0, 0x06, 0x81, 0x01, 0x07, 0x08, 0x08, 0x18, 0x80, 0x0a, 0x82, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x27, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x00, 0x22, 0x00, 0x02, 0x02, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t dummy_set_pin_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x59, 0x50, 0x8c, 0x27, 0x14, 0x83, 0x43, 0xd5, 0x00, 0x22, 0x00, 0x03, 0x02, 0x05, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x03, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x2a, 0xb8, 0x2d, 0x36, 0x69, 0xab, 0x30, 0x9d, 0xe3, 0x5e, 0x9b, 0xfb, 0x94, 0xfc, 0x1d, 0x92, 0x95, 0xaf, 0x01, 0x47, 0xfe, 0x4b, 0x87, 0xe5, 0xcf, 0x3f, 0x05, 0x0b, 0x39, 0xda, 0x17, 0x49, 0x22, 0x58, 0x20, 0x15, 0x1b, 0xbe, 0x08, 0x78, 0x60, 0x4d, 0x3c, 0x00, 0x22, 0x00, 0x03, 0x00, 0x3f, 0xf1, 0x60, 0xa6, 0xd8, 0xf8, 0xed, 0xce, 0x4a, 0x30, 0x5d, 0x1a, 0xaf, 0x80, 0xc4, 0x0a, 0xd2, 0x6f, 0x77, 0x38, 0x12, 0x97, 0xaa, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x03, 0x90, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t dummy_change_pin_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x48, 0xfd, 0xf9, 0xde, 0x28, 0x21, 0x99, 0xd5, 0x00, 0x22, 0x00, 0x04, 0x02, 0x05, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x04, 0x90, 0x00, 0x51, 0x00, 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0x2a, 0xb8, 0x2d, 0x36, 0x69, 0xab, 0x30, 0x9d, 0xe3, 0x5e, 0x9b, 0xfb, 0x94, 0xfc, 0x1d, 0x92, 0x95, 0xaf, 0x01, 0x47, 0xfe, 0x4b, 0x87, 0xe5, 0xcf, 0x3f, 0x05, 0x0b, 0x39, 0xda, 0x17, 0x49, 0x22, 0x58, 0x20, 0x15, 0x1b, 0xbe, 0x08, 0x78, 0x60, 0x4d, 0x3c, 0x00, 0x22, 0x00, 0x04, 0x00, 0x3f, 0xf1, 0x60, 0xa6, 0xd8, 0xf8, 0xed, 0xce, 0x4a, 0x30, 0x5d, 0x1a, 0xaf, 0x80, 0xc4, 0x0a, 0xd2, 0x6f, 0x77, 0x38, 0x12, 0x97, 0xaa, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x04, 0x90, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t dummy_retry_wire_data[] = { 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x7f, 0xaa, 0x73, 0x3e, 0x95, 0x98, 0xa8, 0x60, 0x00, 0x22, 0x00, 0x05, 0x02, 0x05, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x05, 0x90, 0x00, 0x04, 0x00, 0xa1, 0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int LLVMFuzzerTestOneInput(const uint8_t *, size_t); size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); static int unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN { uint8_t **pp = (void *)&ptr; if (unpack_string(TAG_PIN1, pp, &len, p->pin1) < 0 || unpack_string(TAG_PIN2, pp, &len, p->pin2) < 0 || unpack_blob(TAG_RESET_WIRE_DATA, pp, &len, &p->reset_wire_data) < 0 || unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || unpack_blob(TAG_SET_PIN_WIRE_DATA, pp, &len, &p->set_pin_wire_data) < 0 || unpack_blob(TAG_CHANGE_PIN_WIRE_DATA, pp, &len, &p->change_pin_wire_data) < 0 || unpack_blob(TAG_RETRY_WIRE_DATA, pp, &len, &p->retry_wire_data) < 0 || unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) return (-1); return (0); } static size_t pack(uint8_t *ptr, size_t len, const struct param *p) { const size_t max = len; if (pack_string(TAG_PIN1, &ptr, &len, p->pin1) < 0 || pack_string(TAG_PIN2, &ptr, &len, p->pin2) < 0 || pack_blob(TAG_RESET_WIRE_DATA, &ptr, &len, &p->reset_wire_data) < 0 || pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || pack_blob(TAG_SET_PIN_WIRE_DATA, &ptr, &len, &p->set_pin_wire_data) < 0 || pack_blob(TAG_CHANGE_PIN_WIRE_DATA, &ptr, &len, &p->change_pin_wire_data) < 0 || pack_blob(TAG_RETRY_WIRE_DATA, &ptr, &len, &p->retry_wire_data) < 0 || pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) return (0); return (max - len); } static fido_dev_t * prepare_dev() { fido_dev_t *dev; fido_dev_io_t io; io.open = dev_open; io.close = dev_close; io.read = dev_read; io.write = dev_write; if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); return (NULL); } return (dev); } static void dev_reset(struct param *p) { fido_dev_t *dev; set_wire_data(p->reset_wire_data.body, p->reset_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } fido_dev_reset(dev); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_get_cbor_info(struct param *p) { fido_dev_t *dev; fido_cbor_info_t *ci; uint64_t n; uint8_t proto; uint8_t major; uint8_t minor; uint8_t build; uint8_t flags; set_wire_data(p->info_wire_data.body, p->info_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } proto = fido_dev_protocol(dev); major = fido_dev_major(dev); minor = fido_dev_minor(dev); build = fido_dev_build(dev); flags = fido_dev_flags(dev); consume(&proto, sizeof(proto)); consume(&major, sizeof(major)); consume(&minor, sizeof(minor)); consume(&build, sizeof(build)); consume(&flags, sizeof(flags)); if ((ci = fido_cbor_info_new()) == NULL) { fido_dev_close(dev); fido_dev_free(&dev); return; } fido_dev_get_cbor_info(dev, ci); fido_dev_close(dev); fido_dev_free(&dev); for (size_t i = 0; i < fido_cbor_info_versions_len(ci); i++) { char * const *sa = fido_cbor_info_versions_ptr(ci); consume(sa[i], strlen(sa[i])); } for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { char * const *sa = fido_cbor_info_extensions_ptr(ci); consume(sa[i], strlen(sa[i])); } for (size_t i = 0; i < fido_cbor_info_options_len(ci); i++) { char * const *sa = fido_cbor_info_options_name_ptr(ci); const bool *va = fido_cbor_info_options_value_ptr(ci); consume(sa[i], strlen(sa[i])); consume(&va[i], sizeof(va[i])); } n = fido_cbor_info_maxmsgsiz(ci); consume(&n, sizeof(n)); consume(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); consume(fido_cbor_info_protocols_ptr(ci), fido_cbor_info_protocols_len(ci)); fido_cbor_info_free(&ci); } static void dev_set_pin(struct param *p) { fido_dev_t *dev; set_wire_data(p->set_pin_wire_data.body, p->set_pin_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } fido_dev_set_pin(dev, p->pin1, NULL); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_change_pin(struct param *p) { fido_dev_t *dev; set_wire_data(p->change_pin_wire_data.body, p->change_pin_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } fido_dev_set_pin(dev, p->pin2, p->pin1); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_get_retry_count(struct param *p) { fido_dev_t *dev; int n; set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); if ((dev = prepare_dev()) == NULL) { return; } fido_dev_get_retry_count(dev, &n); consume(&n, sizeof(n)); fido_dev_close(dev); fido_dev_free(&dev); } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct param p; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (0); srandom((unsigned int)p.seed); fido_init(0); dev_reset(&p); dev_get_cbor_info(&p); dev_set_pin(&p); dev_change_pin(&p); dev_get_retry_count(&p); return (0); } static size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[16384]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); dummy.info_wire_data.len = sizeof(dummy_info_wire_data); dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, dummy.reset_wire_data.len); memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, dummy.info_wire_data.len); memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, dummy.set_pin_wire_data.len); memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, dummy.change_pin_wire_data.len); memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, dummy.retry_wire_data.len); blob_len = pack(blob, sizeof(blob), &dummy); assert(blob_len != 0); if (blob_len > len) { memcpy(ptr, blob, len); return (len); } memcpy(ptr, blob, blob_len); return (blob_len); } size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, unsigned int seed) { struct param p; uint8_t blob[16384]; size_t blob_len; memset(&p, 0, sizeof(p)); if (unpack(data, size, &p) < 0) return (pack_dummy(data, maxsize)); p.seed = (int)seed; mutate_string(p.pin1); mutate_string(p.pin2); mutate_blob(&p.reset_wire_data); mutate_blob(&p.info_wire_data); mutate_blob(&p.set_pin_wire_data); mutate_blob(&p.change_pin_wire_data); mutate_blob(&p.retry_wire_data); blob_len = pack(blob, sizeof(blob), &p); if (blob_len == 0 || blob_len > maxsize) return (0); memcpy(data, blob, blob_len); return (blob_len); } libfido2-1.3.1/fuzz/harnesses/000077500000000000000000000000001362326726700162155ustar00rootroot00000000000000libfido2-1.3.1/fuzz/harnesses/assert000077500000000000000000000010411362326726700174400ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=assert sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../pubkey" | \ tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/assert \ ${T}/pubkey nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/assert-rsa-h-p000077500000000000000000000011501362326726700207060ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=assert-rsa-h-p sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../pubkey ../hmac-salt" | \ tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/assert \ -t rsa -h ${T}/hmac-out -s ${T}/hmac-salt \ -p ${T}/pubkey nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/assert-u2f000077500000000000000000000011041362326726700201320ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=assert-u2f sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../cred_id ../pubkey" | \ tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/assert -up \ -a ${T}/cred_id ${T}/pubkey nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/cred000077500000000000000000000010421362326726700170550ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=cred sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ -k ${T}/pubkey -i ${T}/cred_id nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/cred-rsa-h-p000077500000000000000000000010741362326726700203270ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=cred-rsa-h-p sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ -t rsa -r -k ${T}/pubkey -i ${T}/cred_id -h nodev \ 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/cred-u2f000077500000000000000000000010511362326726700175470ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=cred-u2f sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ -k ${T}/pubkey -i ${T}/cred_id -u nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/cred-u2f-exclude000077500000000000000000000011251362326726700212000ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=cred-u2f-exclude sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../excl_id" | \ tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ -k ${T}/pubkey -i ${T}/cred_id -e ${T}/excl_id \ -u nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fido2-assert-G000077500000000000000000000010321362326726700206250ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fido2-assert-G sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-assert \ -G -i - nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fido2-assert-V000077500000000000000000000010521362326726700206460ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fido2-assert-V sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../pubkey" | \ tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-assert -V \ pubkey es256 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fido2-cred-M000077500000000000000000000010311362326726700202460ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fido2-cred-M sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-cred -M \ -q -i - nodev 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fido2-cred-V000077500000000000000000000010231362326726700202600ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fido2-cred-V sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- } run() { find ${T}/queue -type f | while read f; do cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-cred -V \ -o cred 2>/dev/null 1>&2 done } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fuzz_assert000077500000000000000000000007141362326726700205240ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fuzz_assert sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- } run() { build/fuzz/fuzz_assert -max_len=17408 -runs=1 ${T}/corpus \ 2>/dev/null 1>&2 } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fuzz_bio000077500000000000000000000007061362326726700177750ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fuzz_bio sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- } run() { build/fuzz/fuzz_bio -max_len=17408 -runs=1 ${T}/corpus \ 2>/dev/null 1>&2 } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fuzz_cred000077500000000000000000000007041362326726700201370ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fuzz_cred sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- } run() { build/fuzz/fuzz_cred -max_len=17408 -runs=1 ${T}/corpus 2>/dev/null 1>&2 } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fuzz_credman000077500000000000000000000007121362326726700206320ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fuzz_credman sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- } run() { build/fuzz/fuzz_credman -max_len=17408 -runs=1 ${T}/corpus 2>/dev/null 1>&2 } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/harnesses/fuzz_mgmt000077500000000000000000000007101362326726700201630ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. T=fuzz_mgmt sync() { mkdir ${T} ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- } run() { build/fuzz/fuzz_mgmt -max_len=17408 -runs=1 ${T}/corpus \ 2>/dev/null 1>&2 } case "$1" in sync) sync ;; run) run exit 0 ;; *) echo unknown command "$1" exit 1 esac libfido2-1.3.1/fuzz/mutator_aux.c000066400000000000000000000116501362326726700167410ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include "mutator_aux.h" size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); static uint8_t *wire_data_ptr = NULL; static size_t wire_data_len = 0; size_t xstrlen(const char *s) { if (s == NULL) return (0); return (strlen(s)); } void consume(const void *body, size_t len) { const volatile uint8_t *ptr = body; volatile uint8_t x = 0; while (len--) x ^= *ptr++; } int unpack_int(uint8_t t, uint8_t **ptr, size_t *len, int *v) NO_MSAN { size_t l; if (*len < sizeof(t) || **ptr != t) return (-1); *ptr += sizeof(t); *len -= sizeof(t); if (*len < sizeof(l)) return (-1); memcpy(&l, *ptr, sizeof(l)); *ptr += sizeof(l); *len -= sizeof(l); if (l != sizeof(*v) || *len < l) return (-1); memcpy(v, *ptr, sizeof(*v)); *ptr += sizeof(*v); *len -= sizeof(*v); return (0); } int unpack_string(uint8_t t, uint8_t **ptr, size_t *len, char *v) NO_MSAN { size_t l; if (*len < sizeof(t) || **ptr != t) return (-1); *ptr += sizeof(t); *len -= sizeof(t); if (*len < sizeof(l)) return (-1); memcpy(&l, *ptr, sizeof(l)); *ptr += sizeof(l); *len -= sizeof(l); if (*len < l || l >= MAXSTR) return (-1); memcpy(v, *ptr, l); v[l] = '\0'; *ptr += l; *len -= l; return (0); } int unpack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t *v) NO_MSAN { size_t l; if (*len < sizeof(t) || **ptr != t) return (-1); *ptr += sizeof(t); *len -= sizeof(t); if (*len < sizeof(l)) return (-1); memcpy(&l, *ptr, sizeof(l)); *ptr += sizeof(l); *len -= sizeof(l); if (l != sizeof(*v) || *len < l) return (-1); memcpy(v, *ptr, sizeof(*v)); *ptr += sizeof(*v); *len -= sizeof(*v); return (0); } int unpack_blob(uint8_t t, uint8_t **ptr, size_t *len, struct blob *v) NO_MSAN { size_t l; v->len = 0; if (*len < sizeof(t) || **ptr != t) return (-1); *ptr += sizeof(t); *len -= sizeof(t); if (*len < sizeof(l)) return (-1); memcpy(&l, *ptr, sizeof(l)); *ptr += sizeof(l); *len -= sizeof(l); if (*len < l || l > sizeof(v->body)) return (-1); memcpy(v->body, *ptr, l); *ptr += l; *len -= l; v->len = l; return (0); } int pack_int(uint8_t t, uint8_t **ptr, size_t *len, int v) NO_MSAN { const size_t l = sizeof(v); if (*len < sizeof(t) + sizeof(l) + l) return (-1); (*ptr)[0] = t; memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); *ptr += sizeof(t) + sizeof(l) + l; *len -= sizeof(t) + sizeof(l) + l; return (0); } int pack_string(uint8_t t, uint8_t **ptr, size_t *len, const char *v) NO_MSAN { const size_t l = strlen(v); if (*len < sizeof(t) + sizeof(l) + l) return (-1); (*ptr)[0] = t; memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v, l); *ptr += sizeof(t) + sizeof(l) + l; *len -= sizeof(t) + sizeof(l) + l; return (0); } int pack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t v) NO_MSAN { const size_t l = sizeof(v); if (*len < sizeof(t) + sizeof(l) + l) return (-1); (*ptr)[0] = t; memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); *ptr += sizeof(t) + sizeof(l) + l; *len -= sizeof(t) + sizeof(l) + l; return (0); } int pack_blob(uint8_t t, uint8_t **ptr, size_t *len, const struct blob *v) NO_MSAN { const size_t l = v->len; if (*len < sizeof(t) + sizeof(l) + l) return (-1); (*ptr)[0] = t; memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v->body, l); *ptr += sizeof(t) + sizeof(l) + l; *len -= sizeof(t) + sizeof(l) + l; return (0); } void mutate_byte(uint8_t *b) { LLVMFuzzerMutate(b, sizeof(*b), sizeof(*b)); } void mutate_int(int *i) { LLVMFuzzerMutate((uint8_t *)i, sizeof(*i), sizeof(*i)); } void mutate_blob(struct blob *blob) { blob->len = LLVMFuzzerMutate((uint8_t *)blob->body, blob->len, sizeof(blob->body)); } void mutate_string(char *s) { size_t n; n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); s[n] = '\0'; } void * dev_open(const char *path) { (void)path; return ((void *)0xdeadbeef); } void dev_close(void *handle) { assert(handle == (void *)0xdeadbeef); } int dev_read(void *handle, unsigned char *ptr, size_t len, int ms) { size_t n; (void)ms; assert(handle == (void *)0xdeadbeef); assert(len == 64); if (wire_data_len < len) n = wire_data_len; else n = len; memcpy(ptr, wire_data_ptr, n); wire_data_ptr += n; wire_data_len -= n; return ((int)n); } int dev_write(void *handle, const unsigned char *ptr, size_t len) { assert(handle == (void *)0xdeadbeef); assert(len == 64 + 1); consume(ptr, len); if (uniform_random(400) < 1) return (-1); return ((int)len); } void set_wire_data(uint8_t *ptr, size_t len) { wire_data_ptr = ptr; wire_data_len = len; } libfido2-1.3.1/fuzz/mutator_aux.h000066400000000000000000000035361362326726700167520ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _MUTATOR_AUX_H #define _MUTATOR_AUX_H /* * As of LLVM 7.0.1, MSAN support in libFuzzer was still experimental. * We therefore have to be careful when using our custom mutator, or * MSAN will flag uninitialised reads on memory populated by libFuzzer. * Since there is no way to suppress MSAN without regenerating object * code (in which case you might as well rebuild libFuzzer with MSAN), * we adjust our mutator to make it less accurate while allowing * fuzzing to proceed. */ #if defined(__has_feature) # if __has_feature(memory_sanitizer) # define NO_MSAN __attribute__((no_sanitize("memory"))) # define WITH_MSAN 1 # endif #endif #if !defined(WITH_MSAN) # define NO_MSAN #endif #define MAXSTR 1024 #define MAXBLOB 3072 struct blob { uint8_t body[MAXBLOB]; size_t len; }; size_t xstrlen(const char *); void consume(const void *, size_t); int unpack_blob(uint8_t, uint8_t **, size_t *, struct blob *); int unpack_byte(uint8_t, uint8_t **, size_t *, uint8_t *); int unpack_int(uint8_t, uint8_t **, size_t *, int *); int unpack_string(uint8_t, uint8_t **, size_t *, char *); int pack_blob(uint8_t, uint8_t **, size_t *, const struct blob *); int pack_byte(uint8_t, uint8_t **, size_t *, uint8_t); int pack_int(uint8_t, uint8_t **, size_t *, int); int pack_string(uint8_t, uint8_t **, size_t *, const char *); void mutate_byte(uint8_t *); void mutate_int(int *); void mutate_blob(struct blob *); void mutate_string(char *); void * dev_open(const char *); void dev_close(void *); void set_wire_data(uint8_t *, size_t); int dev_read(void *, unsigned char *, size_t, int); int dev_write(void *, const unsigned char *, size_t); uint32_t uniform_random(uint32_t); #endif /* !_MUTATOR_AUX_H */ libfido2-1.3.1/fuzz/preload-fuzz.c000066400000000000000000000036231362326726700170140ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * cc -fPIC -D_GNU_SOURCE -shared -o preload-fuzz.so preload-fuzz.c * LD_PRELOAD=$(realpath preload-fuzz.so) */ #include #include #include #include #include #include #include #include #include #include #include #include #define FUZZ_DEV_PREFIX "nodev" static int fd_fuzz = -1; static int (*open_f)(const char *, int, mode_t); static int (*close_f)(int); static ssize_t (*write_f)(int, const void *, size_t); int open(const char *path, int flags, ...) { va_list ap; mode_t mode; va_start(ap, flags); mode = va_arg(ap, mode_t); va_end(ap); if (open_f == NULL) { open_f = dlsym(RTLD_NEXT, "open"); if (open_f == NULL) { warnx("%s: dlsym", __func__); errno = EACCES; return (-1); } } if (strncmp(path, FUZZ_DEV_PREFIX, strlen(FUZZ_DEV_PREFIX)) != 0) return (open_f(path, flags, mode)); if (fd_fuzz != -1) { warnx("%s: fd_fuzz != -1", __func__); errno = EACCES; return (-1); } if ((fd_fuzz = dup(STDIN_FILENO)) < 0) { warn("%s: dup", __func__); errno = EACCES; return (-1); } return (fd_fuzz); } int close(int fd) { if (close_f == NULL) { close_f = dlsym(RTLD_NEXT, "close"); if (close_f == NULL) { warnx("%s: dlsym", __func__); errno = EACCES; return (-1); } } if (fd == fd_fuzz) fd_fuzz = -1; return (close_f(fd)); } ssize_t write(int fd, const void *buf, size_t nbytes) { if (write_f == NULL) { write_f = dlsym(RTLD_NEXT, "write"); if (write_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd != fd_fuzz) return (write_f(fd, buf, nbytes)); return (nbytes); } libfido2-1.3.1/fuzz/preload-snoop.c000066400000000000000000000101041362326726700171440ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * cc -fPIC -D_GNU_SOURCE -shared -o preload-snoop.so preload-snoop.c * LD_PRELOAD=$(realpath preload-snoop.so) */ #include #include #include #include #include #include #include #include #include #include #include #include #define SNOOP_DEV_PREFIX "/dev/hidraw" struct fd_tuple { int snoop_in; int snoop_out; int real_dev; }; static struct fd_tuple *fd_tuple; static int (*open_f)(const char *, int, mode_t); static int (*close_f)(int); static ssize_t (*read_f)(int, void *, size_t); static ssize_t (*write_f)(int, const void *, size_t); static int get_fd(const char *hid_path, const char *suffix) { char *s = NULL; char path[PATH_MAX]; int fd; int r; if ((s = strdup(hid_path)) == NULL) { warnx("%s: strdup", __func__); return (-1); } for (size_t i = 0; i < strlen(s); i++) if (s[i] == '/') s[i] = '_'; if ((r = snprintf(path, sizeof(path), "%s-%s", s, suffix)) < 0 || (size_t)r >= sizeof(path)) { warnx("%s: snprintf", __func__); free(s); return (-1); } free(s); s = NULL; if ((fd = open_f(path, O_CREAT | O_WRONLY, 0644)) < 0) { warn("%s: open", __func__); return (-1); } return (fd); } int open(const char *path, int flags, ...) { va_list ap; mode_t mode; va_start(ap, flags); mode = va_arg(ap, mode_t); va_end(ap); if (open_f == NULL) { open_f = dlsym(RTLD_NEXT, "open"); if (open_f == NULL) { warnx("%s: dlsym", __func__); errno = EACCES; return (-1); } } if (strncmp(path, SNOOP_DEV_PREFIX, strlen(SNOOP_DEV_PREFIX)) != 0) return (open_f(path, flags, mode)); if (fd_tuple != NULL) { warnx("%s: fd_tuple != NULL", __func__); errno = EACCES; return (-1); } if ((fd_tuple = calloc(1, sizeof(*fd_tuple))) == NULL) { warn("%s: calloc", __func__); errno = ENOMEM; return (-1); } fd_tuple->snoop_in = -1; fd_tuple->snoop_out = -1; fd_tuple->real_dev = -1; if ((fd_tuple->snoop_in = get_fd(path, "in")) < 0 || (fd_tuple->snoop_out = get_fd(path, "out")) < 0 || (fd_tuple->real_dev = open_f(path, flags, mode)) < 0) { warn("%s: get_fd/open", __func__); goto fail; } return (fd_tuple->real_dev); fail: if (fd_tuple->snoop_in != -1) close(fd_tuple->snoop_in); if (fd_tuple->snoop_out != -1) close(fd_tuple->snoop_out); if (fd_tuple->real_dev != -1) close(fd_tuple->real_dev); free(fd_tuple); fd_tuple = NULL; errno = EACCES; return (-1); } int close(int fd) { if (close_f == NULL) { close_f = dlsym(RTLD_NEXT, "close"); if (close_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd_tuple == NULL || fd_tuple->real_dev != fd) return (close_f(fd)); close_f(fd_tuple->snoop_in); close_f(fd_tuple->snoop_out); close_f(fd_tuple->real_dev); free(fd_tuple); fd_tuple = NULL; return (0); } ssize_t read(int fd, void *buf, size_t nbytes) { ssize_t n; if (read_f == NULL) { read_f = dlsym(RTLD_NEXT, "read"); if (read_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (write_f == NULL) { write_f = dlsym(RTLD_NEXT, "write"); if (write_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd_tuple == NULL || fd_tuple->real_dev != fd) return (read_f(fd, buf, nbytes)); if ((n = read_f(fd, buf, nbytes)) < 0 || write_f(fd_tuple->snoop_in, buf, n) != n) return (-1); return (n); } ssize_t write(int fd, const void *buf, size_t nbytes) { ssize_t n; if (write_f == NULL) { write_f = dlsym(RTLD_NEXT, "write"); if (write_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd_tuple == NULL || fd_tuple->real_dev != fd) return (write_f(fd, buf, nbytes)); if ((n = write_f(fd, buf, nbytes)) < 0 || write_f(fd_tuple->snoop_out, buf, n) != n) return (-1); return (n); } libfido2-1.3.1/fuzz/report000077500000000000000000000035511362326726700154670ustar00rootroot00000000000000#!/bin/bash -e # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. # # XXX This should really be a Makefile. T="" #T+=" harnesses/assert" #T+=" harnesses/assert-rsa-h-p" #T+=" harnesses/assert-u2f" #T+=" harnesses/cred" #T+=" harnesses/cred-rsa-h-p" #T+=" harnesses/cred-u2f" #T+=" harnesses/cred-u2f-exclude" #T+=" harnesses/fido2-assert-G" #T+=" harnesses/fido2-assert-V" #T+=" harnesses/fido2-cred-M" #T+=" harnesses/fido2-cred-V" T+=" harnesses/fuzz_assert" T+=" harnesses/fuzz_bio" T+=" harnesses/fuzz_cred" T+=" harnesses/fuzz_credman" T+=" harnesses/fuzz_mgmt" clean() { echo cleaning rm -rf obj mkdir obj } build() { echo building mkdir obj/build (cd obj/build && cmake -DFUZZ=1 -DLIBFUZZER=1 -DCMAKE_C_COMPILER=clang \ -DCOVERAGE=1 -DCMAKE_BUILD_TYPE=Debug ../../..) 2>/dev/null 1>&2 make -C obj/build 2>/dev/null 1>&2 cc -fPIC -D_GNU_SOURCE -shared -o obj/preload-fuzz.so preload-fuzz.c } sync() { if [ -n "${REMOTE}" ]; then for t in ${T}; do echo syncing ${t} (cd obj && REMOTE="${REMOTE}" ../${t} sync) done else tar -C obj -zxf corpus.tgz fi } run() { export LLVM_PROFILE_FILE="profraw/%h-%p.profraw" export PRELOAD=$(realpath obj/preload-fuzz.so) for t in ${T}; do echo running ${t} (cd obj && ../${t} run) done } merge() { echo merging (cd obj && \ llvm-profdata merge -sparse profraw/*.profraw \ -o libfido2.profdata && llvm-cov show -format=html -tab-size=8 build/src/libfido2.so \ -instr-profile=libfido2.profdata > report.html && llvm-cov report -use-color=false build/src/libfido2.so \ -instr-profile=libfido2.profdata > summary.txt && llvm-cov report -use-color=false -show-functions \ -instr-profile=libfido2.profdata build/src/libfido2.so \ ../../src/*.[ch] > functions.txt) } clean build sync run merge libfido2-1.3.1/fuzz/report.html.gz000066400000000000000000006231501362326726700170510ustar00rootroot00000000000000 ]report.htmlks8TjvʒE8Ib+j+5[Db"$Kw_$,@#`NB~9l~X =<y3i*8ɶ82e?~U0AdұOVyKRv8Zsѧiv_yI8x7 ߿Ƿ^f+(oM&H\m͂yykm.H(0 &xy=f^rD, G0>(_~;,=KEReAG{D0n`8arw0}awo颀o ) .д!qKI9A:=Hn;tC_ Gb咟R! y Q`.C|Z?4)y!aг 2,HH 7YCERGdaY7~ƷsG0`|e~ؗ=e0/#~B]5Aʭ >;|W_߫p/"]'fQ8̂yQ#)bCWytWc>36jB;3p'^q(sF"z kg˹Jjv)5x6]\x.?WA0PiL߇5SV/M22'`kk"+\T -ԗ%ؿ3۠suײhb&Y2Xܬ83[Kq~B/ϽqY'-XrwRD>v.Ȋi!Wߧo"=?eS8 W(~F IMVG͇IYm< 3 mzOmV .y+я{E^  љO[]9}ͅBf?MܛC?Ig^&{ş-`'! '?љ_F>?@GL8b6Gqwi^3|>*WG.Isغ;Q7ȑ;e Gߏc ߋ 2PA=8y0v!j#~ܿlcFԯ.}1+ͥf))Ɋ k)*e*3̂q.Rj.~0A Y0@6 RTMkTc6e/m٥ ["AV x n%22 |t[fS/C@DHt61_җS*rd Q˓_Bs%^=,ZO%ܥ <+Ϗ`pN zp?w=EwW997\aopp}1@;'@c{]k[:}dy@>O/{'rg=~i~VVp!nI|ϯIw0#St힜6F]/]p|9}Ao4,[w08:~~|y"!'] hp/U?ߵ5 ! uQD.q}~ǧlbE;lݎv~]t vNQ7 Y v.yIq[䠋͜OhËA.{\ 7l0Hp8 :.*SjשG7N*FCd0HhE 7_PkڐwA4>̛iܬ>ok BrCJEJR)Ȇ" \NMSSN6!NYy|#X&I`ҔIAEtzʡp6Mq$\2q NjCGoxKey>(6({C85puQT2 LiTmu./->I$1eGPpǔi^qd8a^Y3 Gxʂ0OH06)~_$0[$|ŋ,Eߍ]`4?hߩplAGL9SZz FR:C0 eA#MASZZ'J;z`ӼsWE_$?MѦA[/x[VjR,m6e&&iSNICPݱ{׳+ϴd'&f`>МwΏcOXKP&Ac4]&`D=)*[P&A`ZlSLY wM& f#&壇:hPk5_^bQj콿k"݀Ov?eE"@^ڪFP>bQ XqP @z G>>}xq5 @qs< %"L$` &EOZ#=(`Qu%=h2hb3F6 +U&>cƀwv{k UzBNpB*c2 eL5H1(Huqr;zQ >2궡%،ART_(VeL1 fn EeR)̆^}`e-=G،jNpB*cR2*cF̨.澗A}e-WKF#BUcr=NpB*cR*c1F1v_iQQ,L'vS*' %N<CMnS۱-"Kz㒄0ʖ .qRK 6Ki;C,C$x.PH,LՈԑHT"OVeKF7-ňbmӈ[d:=+$[DjL2+Uْ1ÖbTbiTD^#XlAIK&$0ʖDÖbHb1HCJg}x ư?å#J Jըdq=sDaU$@ÕbLbpQH~S!8*#M#Uv%#Ivap W[ͦ9yo[S<%SpD(E M;fU Hm-G8\)$Pʘ%:fn؄{.Nyٌh+@'[J+2&+OG4|+@'W*/2&M\MV`jگ$GA,"2Uۃ~~<<kۖxQo [}d蹊btI5<CAR`+i8mJX|11"T5D9Z2ÕJ ŪLl6 U$5zԒQlƈPrÕJ Ūxl+1fnuv;9kɮZxpB*cgL1<<i'n9|S +U'>c m\jת7M bUPcp +UB(c OH|1 n^bQU,LH%OVeKʄ>v[1J5vyFlƈPJI%e'2&eǘbb3ya\a`뮭%،apB*c2(.cab*pa,]Q`UUZfTCG(VeL8*stꙶL=L#BUb9\'Pʘ8SN,6NG;ZaII#BU[JI%Kz>NϘzXRqKM`VMʁIK.i%,v%͢~hD#-|ѪhzVJ}G;͢2>JA1"*U#IZˆ# r%F͂ B}X JXHfpRE 6EV쬺Z6cDj4L8\#PʘSJl6LQ G iѥ>2b3FƨU։QTb_(VeL)(6sȨmu| 91"T5NJ%NbUƤ<>ǘbb3Y cׇMzC~>6cDjlz{+'͖6bU$Ϙblb3Yl*rEe>캞b3F(rj- U1eL1H,H/STM!7$b2Fƨ4ȓfKFW(VeLF1fn%wC ēt êlɘ&aK12X,.5}\]ahk7R M|X1]{\~'MJR/ob3FF*G ÕJ ŪH))6sũ&¡XL붞Sٌar9+0U)>ca`j0良F+b]W*/2&c1fncȴHC53ꆞO`3F&\+%vSJa+2&MMp%Z)(<ZrFѨEhԒLP(~pȶEr9k5B*rlQPD (-pFIE&r7_Nh(yL AEU͍f"ɿ X.T` ਉ7zx, r<8h(BT`@"HPHi[" @Aa @hoe)$*MbǶ,`"1@&vf)4* bU! @(rT @PLiPX,PTWd* wjb9=3f"4@VZU#l;k^~J*>P?ˊ%Xe aE2[@M'Pw( *$PzKyeE4 lt:קsqX%PUkVY1?˽,E~r"@6 VEX4P_h4PdE XuB@lBm%b43(J;P'PBQhK?((T`{-D@@z quBs@:TP(rTHxyhT``z 8PR*0.!0HPA2l"]@-/P ;!5PhPd Ȁ_jv VyE> H[=I* mP@ 4(,@Hhn7oY`j0b !@&W [F*0 NA@3GWs(K mWH,/_/l 5״_ڿ/ JaP )ӛ?(oq:~VZh~q#:F|zVcM6@C4Q_F}xEB[u-҆kړɗ6_V|h+4(!^~t|;&K ׁvCX1qg:T-aƝv@;C{_}xeBu}6kڊmŗ_|h4(,^jOp~zyv@;MlVp{ _.|h>=>3+7kڔmbe:|̊n״^l/mp=:{iPX(hOsfEzM{u=ך7LK^kji՞zu||^pc:&Ċ}Z_Seō$ڇ×6^{h4('^l{5ׁ"_GWǤm@޶G}㡕?p4״_5mׁ7ц^U,S_/mXqk:~qÊň@Aa =:V굚[v~MuW5km'JF @Q!K4q:0z\H;d@-$n״I_ڤ/ mׁ|Mu ,NS1q 5mׁ6_k7iܯi_wkڹܧu}x羴- 6@m!n״^z/ ׁv^{xn[X9\KqX_hi2~Ӎ%@{G7[_ڭquqϾ=:}i+;5ׁvK[IܔiS)_ڇŏK|a:n|øƋIJCu}{h.}Mu]!^q˾-:Ж}+uڥҗ/_Ӿ|h_4(,_ڊ_;[7kڔogb-:mUOO8f%MkׁGwfiR'1vd4#N@ fD!Wgc^LF>S8hBt`$`!СnoŪ;T{;}35Bt`D@Z@! ЁiPXH ЁJ7Mx&<@N(IЁD0zt4:+F'С=*CP H[?t49: nb ҠPQCIC$ D= Ïđ*TQkz;D'l0 @5Y0nP0$ tڠ(`H0Ez^+` EiP0 @ʀ7 L ]@TAqxAe2`)Vaƀ!c67 ɸ%^B`H!0qӉ!s6a!%H"L r@L qDz=`a!}v=[p,TLDH`usi/ϥDM`MC& dHK Y&E Q&EpРO`'0|斫O9Ljx'ЄjV?X10W!V (C lHL I&d m3Q00$@4(,/@AtME8[L4 &ipUWdZ/pr`#Ƴn?kbL`aDb`+G^ I&d n\`6&X C^ k00D@6k40A}y0Za< Nď8X5i''08QsY}' L`@d"I`$0Hi!Aau!6Xo'0pV9[H L`jym&럎ﭗWgmRe9EC ,4H L`.>^uߋL4H L @ڲ"a`00iPXH00p-+P5׹8ZWQcyU+1a70OC! .#X56( L @$d`H20$iPX=20 I>x1Ճ!Zry1ņ;h-ʟl=WDX48Xf50Yi! # 00eb L ֠6gqC o:0dցOҁ!ZG Y&u nt`I+ &p C Tb!^ԁ! %R:8G$޹ !dz q`80]L,6DtDP` fUC* HŠBȀ wDn7`qRm(u:F & 8S * ꋀcb@N'Z ā<z(''4=9]|ij.^lii2 )q|CoH~Wyx80o m6**Yf8Q + Iq D & $4jVт]\8K@okkժ8?X,!1q`bE! ,?'āߓdsٿ&3{aTtŸźӴr\|N'O~xT؎ﴏVgYԶ_a׭GX?<.t|wGgbM`2O>76K؄r^||1}&z4VWxzd_)P'.hp[s<_z5ǏUzgz9LDI'T_V(O%ebV~?9( +ս&2+)?r6.3>nV/|sYUbMaա/Ǔժ7zeyQ#{!-ߟ\ksyHZDfsT]zl|*k*˙- Vǿ {{w{6{M=]]w²~ oGߜ7Fo?z\7mv#T7Lw@}z՗6ϛ?n7Wt6]Wt2){Ztf|w?/A**Ibu+6@_oۮi2e /n~[oOrq]{yֵ>6 4O߾aU6>G)cXO˾Ni_⿯^:c[ߺ(y_{]FtqvG|s>]֏>LRpdm-om6gOM׮I, $7E)ӨY&MH=V@=:AM*:2ĉDt33(1$I6aqF?^6,.cY|0 xyt]6]i>_eq˜K3hEz(K3r `@N 3lv5)?Wfad˥8(Oc?=~W-*&G~ד?w?ɛ_\~[7WF q #Cﷷlm]/˛q}4/J ɗV7P#wѣy\&}kuPDNr=ƿ?G՟&CK Ә~!}aDPqh?~ZM`T/O^=y7z+j .:+L¨.:+Lh?G-*=b5&L5OaHxBvlّ8GOFu#脮IگeZ΅5aBigŅ=~utYH0Z7!eЭՎb*'C>T:ū NwNjF9iGen7 |1Lٺ֕h}ZɊY].vD2Z/+l9a ]V>&xh^,MuUMDŬ}ݻf‘(dZ|cTڳZ^xp{kVǃMףy<7o[N.oDxF*<;+Vu_U4] ;,%좒bN&7&K#400^΋qٞF0F*\8 ՗@}KDKH>I𠬒}$zWF!d#hdi)IG# #u"̫\|B1@^0"(+D#WO<}Jorq~-[.\or?}Ų8ʒ":*p?..ju#jU&¾5H׽GcgsmȞ ̓A8F>N _ ,T_-atW6zmE<-j_{mrZǽ7gX,/U5 %m.?G}x>z9=-b0] ײ䔝e>q/Gty,kzQ wq΋j6C~ޗs]L˂4mø^O\MmmGla( lQ}TtSaj=⟟{dޔw۟~xg߼~٢ޞI?{̦S>s'G~^ 3q?О{͠p޽yf?W'şN^=?ɼ2xMzѳ7/ګw}9 _βjR3U~Zt|^>2+;ߕs+ڸ&>w#q}e,+ o-3=F&Vb/|vggӯmBqn+Jf(ӫo}70.|Z~> @>$]qziCH!T\ѦYOwlp0U˴li~M6cyPӦLQ6mmd,\'ƎW9r?;z 8MqN;kٝvlΪ%Or)dcT$a/42(YS̳>4P(YS/=j54볚$e~Ac>جjD5kJk8 EQ;n]?1f2YSQ3pv]Ë'ޞDY! z\$rZhjagVٓӥi | Jo ;;SM &[I#s L7fF~v:ZG?7Wkܥ0|'Io׳lFO|fQl[ԇ4a/`Ρ=Ug'>_s׺xoZ_@bX?4bqZ}7S5¼9=gtދJ;~d;>WѴ |"}йKj}Ssx_'tlMBU8yt4MQ-xuUu+w4:j?SWqMRۤ0Wu=U_rx?WV@rOUh4:/Q+;]bٝtD@ḻ[->l|?m`no_n-&+z Vw6ÓEYXFo6*syh35S'>Ȉ(Gd.DתryRs\}>3q yՑBBlͣi +m@خz̊Wq oierTio'8[|ͅl+=.1^ǀ2Gv{m7 w)wR2<ao"F3]q$7WT] F|]>"I#w- |ڡ8rRoUe=Gۋ0gGv86ǫHY8noJ B]_8>52k p}Gb؇KA b6L# !TaS冼*'?఩C^ottEp!2vP M11,߰>_s! r8dov`\{y^'{yrz/O˓xi I㱬B^cW^Iݺ?Pz\FrܶSVǓZG[̾lot麸ٛxsx^zcr!!ᵖm>aiT^'9\7{; FBd\':˿۹շѪ(fG[O8jOV㑽gʆZ}^Uܭ=~yףzT iߌ\QqR~29evGCU27-ƭ2Sݡ&6K|,@ R= ]kITؤU`f~bu~dǹu}!XISHB0U_kCW Wh-zrwl^%lhƑj lII 5HgGMvpp'N~mWxqAʾ d_{p8cw#c7^/{=z9:B hM=TG*\yqв8^);\}(EþwDeo8Aɸ0 7Fy{R5KQ&rRiL^"MMZb{nUo‰\R^t5zXUK Ȕ H45">*eBN*1- SZ5n})+D\կهM;Ԟ?KNg㲱T;#,ˌ4O#q؄F "\L'r5t &N9˜ׇ5)_?'d 2_1ⷵ4Pf?\F|,x#d?bzĬ>.Vy%av}R*6MgWUbDz9=Z+'ڔ[eF> }'|B||5[4蚯ý4 zD09T# Yv SW}ĔLpĔMK2bIzmtE׿ѷ?;7Kͅ46FٴEˏ6ˏ{O)&h$r:J6^ls*㌀SI Y2¿vRxɲC˺9[ x{Pu1sy 4oX%">?QQ][/@ՊW./G Vr/ia)KS䪗z 7>s=oGyeٗFkǢ].E_G$[x߯l.mb|.WXIoS}ËF駗''WyBεչ\<>%_4k=ܓvآ֗ x٢  wl`[EI@Z3[*ؖs`{7Wޫ{ j`.L4@[̥y^ʲۥFFQۺU!E\g;̡6w?||wR0Eva@[qx98'$/? 'Vd 2D4]g]ͭ|9W~ڷ5S).k&O~yO?S).&"h3Egl{()R=g -h)BW5p4@,)X8,KyʣA!S\Nܪ?~էkC@LVZِyw;u'پ4Қؙ"L13Aх()G?FoZn;)bAB >hl4#MSL8p%5EZjVKrObheΫmov:L^Q?Sğ)HAV\0S)b&2PW?ٷ;)f%~XZt4?)he~E٬y*/>f֔ \Kŭ3@pZꥐS) K!{S.<S\NX;x2MR=:vYT 7Gf}"2dm;v1,AyQ!JHSLN~_D۟ue4!vydН"N1;AҗQwi#q3!N;Y?Ar!x~|G;/"7_Lwu1ް#~ꥹU.G=qT[޾=y8@eVN &<$RsU߿y1;_~W~ ?Պ:ay-AO_@ls1• ЧDaw?ZOb~}>DzB|$>Ť:X_ğ=crλ}ޡHĢLnbyܟueQl]̞"gO1=֮zyNt1)iX SL9sUb# O11-ŚFrw$"NPC"NN<9Oxe^t1r`9Ŕ:ܯ>2q8%Ϯ 8E7XɎSLbq>#o=;8.+!nɻ1,6FS657EԛbZo]d$oqnjzy J`nƄBLǶXS.9nVc'pc')K a 7?˓Mbru~IH()ˢ7bҗS)&+!BZw=^_rh\>bkJt(:Ŵ9 ph^V)Z(ʛ~YSz&M36FvV,м7==_g7i5Jp$8͕[o^4-P-F N YXxL-ir4q5ȵi4kUŷAg="xus/xqu[eC(C |HJtlH6"z֨iӴKO;$FLz]wNPϋǃ4e2͔:vP#ӤiF԰ޙ1m侲8R.7U@LW^?Ei8Q9Ӥirۖb&L3m3"j:_?ӨiR4WE Z]o4g /jd41eɔu/t1MԘfRcXI.E!b`009DK]җoPK5`P0D:ܰҺ(&L3Q0FSp%0Mxfa/aHi"4cz FKؗOȱP쥙W.Mf:\+{4].dBoL N#奉LK>M`mFK楙W/Mf*^a\D4!^xuvix>].+XqQ>Gz&K3.F;l'v?yoQxK.6WW:aHi"a{7;F Uwz_쬐I/Mv_-oi· ot0-Mv[~ٯ/aaJ].͔x u!si4,-Mf[#vx҄ei&ZDai&!o=CHbi"4KvQXMɿ.C[i⭴\x:6-M +)QVEY1T=[ʿstFloנc ՈÊsGJ\rUCZґDOi&=:ܸQP4QSIMh$4RIJ^6;pXBjѥ^أӨSiҩ4Sb}S˝^JĢJƕfW,Ѻd]iu QT4)W\wa:+ns{M,W+T|xV%ڕ,di&%Čoα:[)n $`'K3.M癓/}GKҥ]J_74]%wFKݥ]tחFa.M0f\=GK̥]0Wii:.RY,M5=:a՞ŏgi@@K=d41Ydu*RfT>VD:`}Ė&bK3-In8S,Է4[oɎk q̺uFKۥnӳul6nJ]:"`&Ks.qĶ+/W@K]AmGxѺ+k]K;ص_&#Nģ'.O`6]G;KϐJ]*YYz.?@LJ(vi&,VyT4a4+ԥ]~!0.~{ A fd(#v9"!0E4L(@n~)Ͱjdg|g£J1a +Λ͝mme $ ^Iz)Z^_yw^~%sL.'˷^jgu^$HO83H" &m3dwCoM:b1rĄ:i{HC̐If\&g2[}n V? bf13LL)>|OoB$M4C&ah>j<3dy&IAܼaπ285őb'0%NJ#ĂM d&oX[mIyAsU8nR W%cܮ^UK[ngf/==y䝴!p3zf58gZ՚ަ hH4"z"P*le~Al ` !oƅ~e{ ˇ dAUΐ*g\aeЕ3+' qB!!08kMTto89CarSS%N;!㝌!0 85`}3&֥#}@f\[ nD7fH]3.uFQCV?/.eR fY3LfM%/nQ3&%[{׿&o'f[$.~59.o?Ӵ7^y:IaJn]U68}'ܾnO'F.L6C q1lدA،T|g~z{f㛓v>&,/ jT5R [?pssT3D&i\lqīUutiOp@Af\_J~g3DTo( g3TϺj>ra'03N*]Zy;.D&ep#pM~2 4/ r|qίAvfY+;3&vHZNڙajg]ܽ+k Bg3Äκ,رtfT:3(" Ig&tVjfh2^kmQ3CqfJ}{$-~Ȓb %!R"ۅ$7e2uo෯~ۤX8f g˟_g~xf4CFi^iX%:3\je2zU dH2$ɺL!0.1?v,D5wm0C6q`n e2.̋]T40^}zg Va~ql6-kJj_/ҾDj+l*չȱe—Ryk2D{&%¦%麸=Th3&ٽle吔0T8YmT#G7J~AS̐)f\o:ٺfd,VWu}/zJ q)di3w>o,Vf\Xg׶6_ gx2ɺd" K5d铱.iV?jUjnDG׿-?dĠWf+3L7Xƣl Uӱ2CpaeD؝|:/L>Fp!:FlB2CZ]+Ђܘ!n̸;yG f\އ/' e2.KT-}?X2.+TRQI}Vw WVNDa]n{2nk~{2:<}x&5UmyZ7zͦ݋?}7՟V_^\9uy%Gf8 uIˉݤtj.[ϙo( S vh/^ԱZf\hYԿdz_eھ1g3'o>0ø=X =5CqyjAǡfK3L/?z!=0! N2<[ğv,R3LK?¾qngfnU/dѣv*j&!$&V{KnQmI2؉1bm1am1kXL`fpZLZt)o#+@ &h(ABFsۓc1it+<ʃ9,cpk[.N0SJ=,s}Rb4b2bKO~)c4b2bƝSTc%L-fbjICV1)a A)7E#nnqY׶ 1 e1 e1W(vZYLYz_11ClQI]w|q]6 =p=İD 2eleVb1Kn:LjńLCMcuG?ߚ7CoqWWLW |SFWRoPPVLPV삲d H GU®.mg2de/J1F*&*f2WڔbūwWT{-#޸>XO1^p#EJObWz0VDaWLW좽zK4عp1j_1i_K 3=~bbl36mw1jz>寵VJaK ~U& Fugxx2'Ft,&t,vcqئ_~V,*΂M aa0Yz UU32FbbX8Zc1Yc1 $bhpִ Zc1Yc1 ;V@Êʣ]RM$Y$ç76KakP+I+Z?Kf %$)u\*!0iO _b& ׻41E*,&*,fRa:H>JȅąL.;:IńL_)n33 ^]PI늙ZLRhI?F+&+v9]^u=_q]tWsOuu. sOHrDr.cieid %$8esO|ń|.kߋK{||.Knh~b i}1xY>\ƾ9`$ ,fj`BO>3- HGjWTC{B+&+f]eOIB+&+v_B!66Pń.,f1f5f==]A+h1h@o5YePhd.;//uTwyPe 6ZZLZZmhV V?I^bb=pP/Jj1Ij1SR3m@-&-fh6i-=zQLUOI34FUʩ59U6gS($LIz~r o3a5F6 9k X;h1hKE2P=I=Yf1f10cv[CLOKK3]2f~B,&,fe MM3i25sz Ř})Sń.)bb6v)4b2b15j2Yoec1c)bbaKWLWԽ{B+&+f:]$^~^Lֿf4q1=AVLVd:$ )Z1Sb\`;S/V뿆!VLV8wC p?7WLW¾{MsSh{d{. JJJlW_*WB*WUxm&퐢 sS1wbC ;s9A+!+r]*+/\ ºU |\=F&'42y޽j.vTc=& ,qQ`{ޞjǤ%.Lnh\.V\HSJMXR_4a &P,qb ڦpmE&HջaB,!,a"eȥ-Bd Ad ";Ō}'&7acDXBX4ǘ+{ ixӪPTو<$"vБ7ԻһX^ƕƕ4pG5 [ [:́VBV„׸5 *\ )\KB$m%m%.h5 *Y )YK:]\Zqה,f9,J=xqstR)?W W˾NiUBU¤T8x&}B*!*aWblZNN:EZLPJHJ/\/D*s0+^"ןaC V V  W W Ӹ RS%B"VW2}C>Ѹl/W D^ d L@-G+!+aXX^ɾJ9L~=fm>(.0|E+!+XW;{ף7oF/^/={^z'.p -atqpącyE*+!*+qQYRx|MuˍՓey_'">?QQm[v]/)NJJl׀`y9*_})98ql*:UО/ M^PJHJrWo~8W~OP}WGמ[եB+!+qy\I/ Ӄȕȕ0E+kv?`+kJJ սm<{)N;y%LKHȧ:OdW$F٭حn)ۢd&%@lbm]W|Ok?oJJHWVjBkJJחHߕߕ0÷Qt%t%L& l) k&%z+)2W00^}*TXJ\4מ{=µTXJ\WL{h0>0ݯ'JJ̗R}ᕐ0 .bKX.UsDڝ8|0%0NJ`=Q*ojKK#񪈞~{2:yTqp|BZGwګwxFXNAA0 2AbQ5Vf.<&x[XI$K"p{o-{Z02A~]7V]" fv2Bt X0[XωJ\u}Ф8_xmJQJIJ]Qr\۽Mյ?/Eh,%h,uAcR|uܖ"44佲i}Wooޝ|7z_g|kcʼnY&#a۔[[22N$|mKQ.KI.KrYom)e)e).c\J;׆߾^12 bdPV4!;`9}vuZ[tYJYEX놋.gӳztbqTTrWקȋċ\^u@"5E[,%[,b]iDU,%U,uboOKK]!~~.KUGgi1_W;tT0ў6 O>iihK{uoSDRBR.)FmwɗѾIϨ,C"=|ֵio\}/n K K]lNVK K X^_^,䄥l'K"XJ"X/{{. ]\zyj<[P 51k0 } #_)_);)-||LKX k$]O7Tᯤ~ɯȯE~yffh!>"a)!a ۗdDXJX2)}y)Zc)Yc###1Yb~XJ~X/.0 鯔Ey奻}:7dX1JWhzdz\Ӌ*95E5Qn)R_)Q_oRΙ9!OBR"\&&r5N4Dą\.liKXJXUXiD>,%>,ea2XK&^?FrruYMpn4-$L1,T/GȊĊ\V!GdRbR.+v'CȈĈ\F!GtRrR#[j`)i`K;[])]Kgůϱ (u$u.K61҈VJVTzބVJVʴx} ! !#]]袛ϒ40,LDe,rC,00ҦA@ P H zZ됡O%BYn2H eD eB9 ?Ⅎ^8!>6zXunWneH"A2^M!L~&pc}We g8<=LdQ'>@7 O<_,e|樿G ̥y$r RO&R2BPej/_Hf(e(e.D)h"%22z @=}2-zZJYJR %$ գԣ̥yz-z{{1ݣ~Ga>>ʘQs82:i/ScGgӯ rHqHCb|vˍMo__y6CC)#C)J:[ȇQJHJ\RaʳºJQRd?úKQz2MQ)@eMFk\q,jwLRFR;k0SB"J!JQ'jngŤĤ)&ӓv<<ʘQbN )cH6*g~a$o|P8;],J_V j/'zŔ)&AN7 mRan;d2b2>Xb?I0u{A"2&ě0t2r25F)#)"Lksy=rddʸ OÇH6eD6e\+( N NSpw NNp̦ͦ,1nSFnSmΪ [*wʈw\מٔٔq&ZQfSSFSD)#)L£F[7vv{{{!ϔϔqy&C7V=R2̓U` 3PZW\E)#)My,bISƕzel䔹 +%YOz:rISb/m;󖒣tCȑqʉqYS=G('(gAG7Y+G)(')(gIAzgY9A9A :2ED%۬E_.Я9j?9i?y GTATKx 4!8{>}r}r> ixڭ3^wi.ͧV<s5sqO<+߯\ qs4t1JEO`"'g>|Km_ppL'N 5@ޠa#'g?$WPNPxKo]8zŗyxuKZK  A-.&hd=@[,CDrB/  {Ez'HDLn A9A :x=GPTO'Z| ]K B9B꿤 ""1rtrrr$/>l.DAY('Y(wB1  .h˭1($.(p Hbr.SgA('(*EˌzkZf*****YE^a=hEtނ+hd\è׺QNQ5QNQYT''ʹ>Q_Egyx[TO| B9Bwrr$;k z?9y?9鵼 s/ 3;{mA'''?}V|r|r.xndQIɹOuutNuut9 >9S鵊 ǓǓ39U%$)[E]NUED% 696˵/'\ךMNM5h@MN@Mj iZVɉəLDžL8ߪLNL`*hd.P&HD.E^FjKNKu\z-#HD\(#䄺Ln^MsɉsɹK5˵!>o&hd\vKNvK~vKvKNvKn fKNKbq s~ >"^r.e^r^r&rg'HD\ ҂KNK\•^xKNK΅^z/($.lKNlKb[KNKX< ^TnnɹvK|!#.9St!.C]\ѥj2DeHx 3t0&Ca$ 0Ҡb *”8Fcː z)e=W!/C2_L-(C4_d ]8ƾ+!Y1C'V8+%!I2C$t,!3$)fȔb(*G ,3d2Rtc ]nL%!A1@PLh̐Иa 4ZIl%!Y3C5s𒂀̐!BJ J3CfLiJ 2CeL[ߒU! ]Rlt⫎̐ș!鷤 3$>fc/) ɋbcd 1J wiAyfH%%3$Kfȴd҂̐Й!҂̐!鵴&3$MfdB_QB3d*4d ]L%!1@~Li!2CBeP#xT_SC4hd ]͡gZ( I"^i=3d3w5u?DlfH̐:ق̐@a/LJd!24Cbh04:<˓ 3$@f"#3$Ff??DfHЅ )3$Rf ){aA{fH̐i>R3CfLjת̐Da/ LC3$f؋C#* @T,u$  2x==F&3 ɴNř9a`$se˲"mЙ33t93{߭ފ1CcL8KM9ejICe 4'Q,3d2]2!ӎ\1;m>/b"A3$f$hBejW=rBJ:͐ՑGXɶl{b'6gbsJ;F IsAa&gpAMwmTo ]ꍔ*C{_`&foozY)zUoD Ͱod M&t]\~:DfH͐O06S3, ]Lw>l]LxbTNVVu.Z;! ;zIΐ$!_\ۆe'?H[Wx O*=>:wG'oތ^^|7zO?aqۂMg_V1eQ eZokӜ$Ўw.nx["0j:(ox[ޘU-qܪp¹q"H$nx[\F"6e!7ت"`YHܪЩCWUmsSlwn',id[ T[`Z/<=嵛5I(&ۢȔ5I\&rɄKqjl%Ӫbu ve׾UmmeT^VMe)Jq}5W_^x1gGiyq.l+ӎxjۧUmfP:}4ƴUmvPK}Q\]~7qD:W9mUt[]g;-훝O"mUt[]Tox3iUt[]ԡVaMiKqvyUqmeS]Dn˧K:Kt*dD(F\OF?s?NGiqebs0^qq5y|X}>//'q~2n˨ : A*$'A|}v*ٶxE_V̶<1h~p^Z[UmQdrNdgm t⼞;wqԭmK o ̫觲^>cAX*ٶ2馀+yw ,kl[R `oUmfOX Jj-L]'sqmk,f[3N&k{rT,jb\?q|moټ\/f/,֟/qg/uħib].u:Yx:)>MϊGOz:=Z-_a'WEG~z#{֟pEOQt:>~O-f7'?=>XW_V ڍP0=J6mvT_>o`|/_~~t]^ɤiMzsg4߉ooU[^ē'틑o[JvVYmɤ3߲^%r,ꊻmy?:^uY\\Ϫ ?Z*t>)~&Up놧a=-:ͧYf-V]Ɵ{mmhj\}uaygtZ?:0mKUm߷ ۴ЪYH)ug7/^s5Sœb\=gՓԎ'cYE:u/;~(P] o`oZ;9* Ʀ@suDGg"=PyoWӳE쏏gY]KVe({韊cY08ՌL:aӪtwadCTk8U,j#Qfڼ̣=?+߭NX>eP~~xۓ|:+T5Ta'aȩou0v Y>lvUޒ֊h,Nj,YM&,RdI7ݒ8C>A"$C'L年C=M=7 &vOfCM M0~֓ M0`3Yt.?Vkw%zX:s%4S0FxtU>G5sgef$4I<֙3Gz٫_Wm\NД *YN6䔏/Y3a%۝ZflZg\h2l\eu1.mV6OGGk۸H?aP{fT8BDS(.Vź|^-Ehv(yTDIS?g`/&T/} |]e$bFo. ~i;8#Fh ~YY=Jb184\%2BȘ Ð=BdĐ12A 1cd11FODƈccs/bl1q|Pml=֢\Lj)d.;~*8tջя/^GuBo, 5sfRkZ]J7^΋wy*q%i[[G猔3qo-T}Ѹ8 Vx0ztHMi}+riq4Fҁ^iiL+lFS5hZA3ΘY؅7 e䓹t#eeM1\xϛ∈!z]Љ~aL;P0"˜@XŤKzM?pgQ]+"F,ٛWw&FS㧈E_<$9bLEL4:8l5iB6rXj氩05SaSavC(ræ lTm:*m߰)>ʟ717l߰<{xBH5PMQ{j{j{j"<|2ōZӗ*TY=x:gwaC.}ٍ>Y=Vu/}W#!s1jҷIqnWo^'z6P ] "@ 3ຎ od٫'?l2[T +$:2XAQ>'F< f@t4[ts{9y' RaFen! ^g2`kw\edVv;F8OS:nm˟ 'UFED]>-rt4Rҏ6{?ҏ8lXv|ߴ{X\b1=ZC*q-H yej4,$/͓t_MY!yxdea:לBݒ@d> Y-y•e|TѢbvisiPr00-z[–SG7wQu1u!mǪ} ڡ0+a P)Cc@]!n cl=ӲgQuj—$'9E1o;wucdq7-EvV!zOF/=ڭb-:EBؔb!ha~H00eZMu'rm.֊鯯0| V~ȓݣ>av@pCKtE(..?_o|iC>2D^Zz4ۙAq_s+)V\j\u xnc>fv7pQKuϱ$6qwNvy褝~q䘬]]ZoH'm%wҶ>(·<Λ[ӶDz ?OdlQf]`vGI$/ݓgIP( vPE,'@'#/#ɻ=,'aov\JCRJГBp,Hޥ[Ƕ+|sdt;O&V$/+:'|30BT/[vszQ14D@xRL [frEe*A{Z?5FC@m#Ze˸E ATzP`Ȥ+o7p$o)K~Q?`Ʒٗ~*B#_/EpeSxHp/*/oɻe)+K~=[̎O]?ۿ`S-#7;;Nbdkj/?n~`tũr=&?[^P 铬o !wJ6!<Ό_1N&1UW4ՃeX {Cd0`ԂD׶CB ZpV`Պ6bP7o "Gھ 1 c) 5@c@^ǀYUQ5~/jPǀ(v$Иa=V=QP5@c@ǀy Aui$hӃ=( 1 cpkWgoKV%Q 'yJ @ qsǀ琪K1-򳄑JliY[.W9|M>/{NU|tenj Z[Behya2ٔ?~3׍v㛓j#lN6 y3)*-kKt1.N԰7rqTnc%W):ጪ%~m/&rw?Ǻu ~⼶bD..(XlJL_{U ڪ\LKnX R.KbcBKϥ\>Wձq0vOԥln̮)݂/ehlf|XaBK VsB5-N++9^ yWyX.IRlދ}O %]vN!˥Rlsq Tp)RR}-Eʖr1[~\lGѧt"Yf1wY=*Kl.6mNFz:JY,Ջ%}2-yK>s g}N՘6 S"K,aӉW1@Jn/EcRU)&X 7.yo'fRLϪ[VB"J4ndX)buB "J*B2/{IH]"`J1XݮHk P\(ńRDbm6N+=O5q+5|U~K%Q)GkOOnqL؞+]n(iX)RLoK*OWW~iLz'SQRDC) }S--궡_~E)%i5G$J\LTm(E8rP&O'Bٳ<'Ŷ KToT HxRL FwyM 6u=^^pu6:)rvꒅ4A@ۓ/Lո@yT ]%FI#(/{N)u>{U/^i$PB!}ϗv*dR KslƄKGe!_(Ԕ"kJ1)FS)b:3"J*aͥ\:]}شLQvGY"WȫR.3qقoY(ITEQDn!Qi{T)r~,XqQ+$:nwSKՑkL5.hZmOc źL:VXSIR\ \KQRT)SK5BT$*墨FNJ'\!_QRI)'% y "WJqa)s{O@-J^To~WiQ+FuHF .b\֫!^ #hՍ Ji錪cQtvRőRF)./HH)2GJ;Pp(աz?IR\ʒT9oաGOwfE9?FQJ)\w~o>2`'J.C! =UW)`T*ezl)7ؖu<;+ 58o[ouaU*$VRL3bU*: KqUU1%k՝*EzXwRLs]aM3VUq¢I rP!HyR.j:)Rub</W]\Va #I('(#9&MfrLaG# NL8CN/%Mf Jrg0>C1O~ZPQOҤ'i~uZOS9%XYANE6LQAҤ it޻ &hFH~ ǰS $MfH<]/&H3#pFHxQuȄhZFD#i&H K+%yL&&I3$H"ir4Eh4G 1 GiX)L^Z#C!LC|~ߑ3be{'^4FD#?sv/]MyE]tRoW~[(.iK\4LH&"%Z&I3Iԗ4K/1ɣij?^WuwpV4lLt:M&t/aǀ@&:\ӝ4w#6v#iLǫ&W^6'vjZZnw]= t:i&vvi:`/Ci⡴ o )Mv)R~K_`Ii'wME_O6zQ(拉F>J|ToF#J]FTs'MvOԈ;i wj9r&'; U)i7Г&I3,ʓ&I'YMSPO W Qg_u -n5]\_vW(ˇj.gq4$4REJ{}hV`9$HJ3!) đc$`J3KêHRfJQ+{@K;PX(dzXDILsV5O]srs*BunV-4Q-VEIi4ӓg!,Ni&;%Ȱ yo~'՛)tIH{Oi⧴73&J$*Y|gQUO(Aa&J$+Zo`5U*S6Q7%\(@ &K3A,ArFK #tiS& K35޴.ĕ&J3+p*X+cUş;KJi4C>J|]_oٴrkb_^|7zO?%Ku#%VF5ZS)ʹ'-LiB 꿬", .XAi4rG>?{hD]' 6&I3m&NըV>&LnԢIqLʼnr ?`IP$AiObә8pAi&=piwQ(M(vP{b!& J(aj8ۓwW^GuћMi7mj-Fs(U(OޔvyS/nlֿ= ͠VeH2LJo{eб2Xc ]bT )UT Re2L ('SrL!3b;t4L(oͥZOٺOul[b`2L&3+A#ʐeFr{O yPA e2.G!ɸCL AN9I>dѠdu2.N& Lt&ԙmÝAdS-&*= ZM&õ67݉g N;W^2d/9f@99!Gɸ%av"!ɰD7F@#nL4>V]mL,lvD-CddQ~{MZUP2:!¦E(,.ӹ=t5.[bU >C!Iތ#yt"Չ:/ C 1zxX{u( S"RZHW?ku5 q&;壐8 AA_P2$t'Cq?36%m3}# A 2|A#ȐdFPaL#d 2.$Hakw^0h 2b1i\8f| 4$Y V8r \ԾN0(  SB#!4  2_Y !CАaBCÞ`2 &7CB]Ȑ.dPuA^/dPKu>iڧ^ C q8-h"?Dp8dJ6  BZWa}~kh!;\iT峟=>! .7ηS+۾[,.@$d5 b npBd J^ 4mn-E"T$.GqXI#2LHe۷=N1JC!Ô8u{ΐ!gpV1E"=F]dt?i{!0)#'o*ca'0#IV~2sҏK? {Rfkq՜d$㒑VG5 +J %2= ! ɸ4$aT~dRz=$CzHbX@2. d Gr."CVqYE~qO' BRd\Hѡg"2dEؠFdH#2\C>u5]~Ӊ$DL"5:/ +Dey^&TP22$d䙊 n !ɸPI]?;)#ud:2.h_'t;2I$d$IidHS2LM˅|!>0 k EuoNؖz ;w7b S:ꐊ^@Ud\TQoԉ D&NFȐSd9E tx?w|ldH62dmT2(K,h"CDaE]"NO2 7,đ!0#N2R S5JA:G ;0@D !FqcG#$XK (2Ls}{\!0"~0K2 &/Mu!dX ܝf$2dIǤD Fy4V!06r L6C|gwLZ!|ŊQI#+gWO*F(&(fDL@ݐo+F(&(fFQut1B6S1G1G18mZNIH1Ӕ2xF&&wC5&QB}:8k rL7t^1bC9A{[(SL(SB=!1ba')vMu^G...wIjKRzXX]&b$b"bĜy·%zLN(&$&.1)D7zz]<+bbb&ođb‘b&ġ0W`1I1I O`g¥q,|F<ӋW҄^ ^]gB#&a>*39&ᦘঘ 7y3Q&M0 h.aX s]ӵfcmZߝn9+dE.+ ;1R ?fe)jP1iP1SD3(NgutCAoqp؅C ._-QGU2{?,>7cb< ~<޻"܃,eYI9MVU첪"?XIbUVVL3sOXz WW3*N!,аɰUIbb&O%۞uQܸDD3%**fB3*NDјɘTc hGdGL;;4r,dILKJ2??TLTtzGŤGL=J2?,Y#xcħb§b>%OuB*&*$QIªHTȟރTLTHj/N;[՞{bbb8&N(N$N\qCMqHq*Fq*&q*S‹S1S1S1Wb$ZQIO б8sũ Dq*&q*Sk^Dѝɝ;Y)F*&*T=$XcIs)F*&*f:Uq@p$#tt3+AE᪘ઘ W1vџɟc%[*fR]l?2PI"'=+bb0"%([%$[%Lh_PUBU?7Ax*!x*aSEti1S,P=!ũĩ)Ng'E%E%.(Aą=p*A)!)qL2BGnHoJoJ\|ӗ($;%;%LIo3qp;ui( *O )O Sybepw| P(|zQ'%G VG(y{Q%uEiDnQVQKܮ6 "S !S h拸``i&*aTLqe*UB*UTYKПJȟJ#riP/;A\*!\*aR]l5Uw$U%U%Llh]XhJ> ƒ JJP}q6]A5թԩĥNJпnR ]lau'C*aR- !!0 ) ǒ0%.=& bN aN sb*$H7%D7%L7Ĺ5%5%LǁVԚҚ@+rL qLc:ǒ &O~}"ɔɔH^FY(6%$6%LUhm`,~w$u"TBT"'/OJJ\0EiE/*!/*qyQ]$"uMԟҟ$ϊ s~h?%d?%.)x'=%=%.)8m9L=7N?;AO*!O*qyR;^9a'*qTrK0aS i;z%tqA󃪏V s{7rWc^W R%.}%7 GHЯ8>zj%j%.P!89v}HJ\Vow®I\K$)J\X47aة"+q)]}D]M3;#A+!+q^ ŕŕ,@"-uhMHVBVⷾ7 7Ug3t*iŴ&XJ\Zf%.6C+e%e%.,K6,.?uel%l%.e9#0e-o?A:VBVU:Dؚ>\ׇp-Ns_OaU%s+[]!WBW:#  $Z Wb\V#ĕĕp!/6VOŹe++JJ,Woc 5^ ^ '̮ͮivu\:rWBrWⒻ>( ՠ═╸/a'ٱZmdpi晤6d98Ɂ`&&051Ir ]PaE',r`5SXJW2 JJW>ςitr~wi4_ _ ㌤WBW$84*_ )_ W5biӅ WB W_DC+!C+qZ@+!+qXaJJ\tPMLij9,VB,Vd$- ͚c1j8VJ8Vű:d&lRĬR¬Rf{"SS*ɧt"`| >b=Glٟ&k*l RRR&X: [ed)Su/ >5E*%*uUAMJJ]0|q3c9EfRRPa}'vSԦRҦR6ljej6{Lgl?gU[I3RRTҔ6f(Q$QL}^/eP^ciTJTʴ8Y4mǎŎLgݦLLLgkOj\Q@G#Z_gB<"332)k[2_W:?id\У\<؝"MM2i$ld*ƻSRRM%ȱy<6z0/E4ĤPLTJTʄ SRR&!B~>l% WdY%%2-)Fged)K)bT&]Ujoem~+GSٮ棗~|6.2u)Kԩm_`M-rS)qS)ܴ<,JLP NTTj6 {HLDLLbܩN1N-(N$NLq?W 0U)U)ӮwF*%*e W4h`d`LF*%*eW5GaIJR²R$v10ԅie1)W%ƚMVB}<"0}}լԬfuTY)Y)b\H!cu%%+e*YB~TT.RRMutRrR+?w;d_h"AAGG<*C뛢gg<+Ÿ"hh@+Y[[.*t ѝJɝJ]0tiX J]Y93WpTRRR"ukŒpԅ3޷w~nnRJnRr C|0<7E)%)uyH~IH.h }o+6J6J],3; w*\@"ZZ" ]f[\QJQ2iY? >!`0zo-INJNJ]v_V ԅ$+I*LR꒐dMcoStRrRk$ \c$(S(E(%(B4^~:q\~p٢آOCg)J)JNQYhQJhQD+ kD)$b]}2ɻыW߿vľFB`QJ`Q8/<\Ip  qXCFQPtqY F @'%'e*>—.ȧV%[isfOJfOO'%Xk?KǸANIFO} ,qd.M+b|R)feedd.Ƿ >ڀ  \~O6m@OFO~ddd.ͧ6 C'#'s>kR -stj!m ô2JWZ s7^%km~C-7C~H^ºD/m9?ҠLϓxOZ!֓֓΋_$}ɘ@1!H2<1<6gG֢x<!fddLħKz<9@Elex=m/r27"`" 'cJ8@zNFNDp(h|s2s2-5i:NF:Nqo\#(UUJwrKiMFMƔhE3|5 tW3qcUtIC 7e2,ùvYy6gfYդy4nh:JK?Bg2&:ɧ]^7 331vG 5b2!nng`2`2Ȣj}"ƪHK_?)ԗt ZB%#%sI.PjHj\Raz@HdDd.ūtCߧ;=ddLE?VȐbɈbɘKo.G%#%cb-2p.rT}.R.Q.rN'L彈_!b%#%s/;>Gkq뼰< qV׾}\2\2r-q-k׃KFKXC$#$s&c؞"O2O2~*ٓ阡\ar1Υ9{K@wngS.Uk>6{ULQKHKɘZ :T2T2&v٥b5%H%cB*] ݭC%#%c(]"vP7H7\I:I2I2Hކr9!*$)$K!uxptMI"K2&Y' *!ZZ1ђ.b)/iufӈ"T& &S0#F8&&77J*ghddd.DuMRv_^{U2K2K2\rX.C$#$s)&G>G$'$w9'%rKrKr_#WWC=9R$9Q$"?pbj'?G$'$wq%}sKrKr]ɇ/oR!'l20Ô0iP9SPaF^䨏䤏.}Ub;N' ']8a7($.$f.<%9%-9Ipv=娙䤙LLsdJrbJr.SߎKĺEJIRJ6tϢ~ nLrLrfrો܅x^ݪx\Q,{Lńs HINITM,z!NNp^䤑4$9$y bx5Zn%9%K-9p Zeŏ:V+I|iXH{GZڝtM;]䤔=*%a:]䤑LcrdGrbGr&;992$91$9!p-@t$'t$g#} 22䄈.D`Cȇćсeq1Χ7 (E{$'{$w#{/7#G$'$w1$whj'!oȰF35n,_.fY@Y$'Y$w"B#{|U "9"9#=7ȇćL>Kf}|tz#d=>L=]L>n8Q^&Orkp]OttR| z:=ZgSTTY*?ӻp\-|l1[,~~>L?fP[/DƗehy..xz*sG+Tth&\nzant^/.2jYoңt=dR֎oc/;],'Œ2Uj1NONv(Ju_}(?LbJ{qʏhd̫ \jFwSXudz*Ϳ^vY^b7|HAu\$ַ6\/.+*A׿^<_rfGnmjn(Þ]S},fWG坰uѸ7͇Ql }o`kϟm!l۔_9L/BÀTkxsxmkj0U;m3]/uR]UYOzjŚ~e;5EZ?տ<)qoɣM `|Z>XW_V ڍP0=J6mvT_>o`|/_~~t]^ɤiMzsg4߉ooU[^ē'틑o[JvVYmɤ3߲^%r,ꊻmy?:^uY\\Ϫ ?Z*t>)~&Up놧a=-:ͧYf-V]Ɵ{mmhj\}uaygtZ?:0mKU>6[چmyRwNhӬ{e~MY]6'œb\=gՓԾ,'Y?zu ~(/O{]=i/"~~ӷ3quqY Quu#jAvojټqy|"ܙ/kca|q<"zѳ٬.=N/?Dzղy <~Z+6#aWOdͫVf+H8fW-iًzY쐇p8q[ۢqV?E p]vIZ9T-|"ނ&idlx{py$d.Ti \I##qYuOw IZ \-.?PXhc0i%AgkԥVSt 7\I q_k%=2W=v 6DJ_sǪw2#==#imkiǵw]ztb~?+FZeZd*j eѫ.TZyVyJOBnm0>(Γ̓צу(OZ\UL <;zKPŅ{(?KYbߠH>`֋2 iX)qPi(s(#p .̅}9P։2Ϣ9GX/V{oוK[\cJKLiͷnl~v[MVJ/ ŗV2r">PiA*s=j(d;:؎y/+yx_/}5<Mܫ}*I*mQyNFξs}wwӶ ٧~!;j !ϝKjv;:NnpVҮo<.Oqyu\0{򞭼g+{򞭼g+{򞭼g+kgҲjZyVޫ,ܫj9*G˲L|Y1?ވ,՚fK2갞nzuI#TW]zq[=.g4a_\ӍOQ=vCY?u E2AG_?ÖF@dFmyFff W`C␅SdOw %_uqt{,H&!߾rU";Dc6$n溄 }*m> apHƍlQ(zuvBCtBtsB!H;{J~*U*TWܯR_rJ~*jݗ2pU/S_re*^͞.*쇋OW'>W|yKYbJeT*u'V},/ճ]M.Xm'=!Vt VcOFݿx2ūwvۨ㷼:Sn) /*y͋Wa6 V(u iwPKtӸ)oo&l[O尟w 2]".s.owI!>W8_j񺈞{/ދjCT1hew8Z^͊UE^/Wo*CW^{nǗif>ARAEϟ[MY٫:be,p{ | r(םW@{Ԅ!'r'3>MMCH(!@پiվlF?Np2#Qc 4Sʋͫ]y^6DmtgrjT=Ҝ'-'a|΍]U׽jS$oo_mC(..0OfhϯTOӱ0[Wq6Kp.myw ^ЂGך v_]gv S]h9Cz qm>ĉKr>VϳFY9".Ɨvhy)z0^?S]G>ߖ3iEѾH7IqmU<`ZݵeO~6^ηe% qm8wѧ6<} vl׍4CuBT+HӿGdZFQ;sYs;Gֶ+ > pl?C{zhOcꩾW;^:.I5([!u==w(ӯ."只[a_m߅_UG~xs|(;mh|B}oߠӣu=lTЕ! N{7Y곆8}'_kC%Hpʰ1HmtlN󉇊/WQ,%yo ,G]}sUg(9i!?u0Ǭm w >~<ĸ/w9#997cmnoŧ19KMz(Q)T +_NR,}Nŀ@s궧x%$x1 bosJY 1`.5@c@ƀwS Po1`.y0-% e5m&$ =ڸVw1Э?Wt8OFp(H`GXR$M)IjCMuAzJ=uivij`/hfUWy烋g|VWu8,V)jD^8 \))lݲؕ"J1Zc^i@뮹} sȹRLJ w~UܷA7Kr$e<}ף7oFo~'ҏ1S$~amOgбX'ti--EbjZc݁u՗ ,Ŕm_<Db)dtWuy󃥙-Tg8v,dj)&%ݻA7Kr#ri:"K1}ӶxiX@RL۪[mzUZHm{vUq3sa)C ؔ\:`{~Uvhĉ`&uK1-A"-Vs³SbD.ndwUXZ(dV)&Z-Dl걉n)'ms>īUW_}:;IUWi\:mQEJy Fū>w^ +RW+Įx7`)RbD.mXѯRX)`>tؤ) u,![q5dzK8śayIxaTQ65KX RLJj/-{ҭ8aq'J1+^ )+EbbVaCbY)S{_wVT+d"ػiXJR.*lG͋4va){+=)Zxx"=KCO91ܬz ,Eb"XZq#Վ,r_"Jd+FPv!00ԪqUUq|*Η񗛝F/vR52 FJb2UIG6FJFUszg{<TiSp>EY)4HiĬiVYHg#kgֆ٠*_2"Jl*n}y]l盷Y|xzuN-C& $UVl'#0HR.bJ#6v"7-\ahQ(B-_73 6~"I \"Il'Х7M&ŴGXYK-u VڶfSR))&ˉ(P#BhIRxA uBx2yBI#viۄ`"1I1ɤ!oY$E.bHBl.C8!?^mh$)BSISwzFOl8;3QRLEI`>m>sLJ4/-)W\yL̒:K&yYR-)$|ű~!md9 P"l:JIr Nޗ{GFIɤ]$8j᳧QeҤ2iFIĤ]!4K%2F6#Ei4K .ŏM[Sih.i24\cogN}Q5d4 C(D#Vn K ҾFIRU4"J%D7y%MfJ/yh(i24PEEIl%%MfJJ|V42J%d_F7In Mb‘4Gb.n"cFHyQM:-ſ^>٣ºK`fIW'6ב!7a>)i”4SEiI]uoFwI]86#B=th`FIۤ]lwZUBVK(r;+K3ME4JڒfjKK?&I3nQK)JL%2BI]>AP<$ix'7UuUZa.H#iFfks&fHrKGL)zCHhQFD#x Xlq8lkif-liX׈1Lƈwe˞ѪX׫}]q qq~d@\P<$ixrGfF[پ+[K&=l]v/SZ%9`ӃBi R ޑ&H3ky1:`JH#i4F$yVJL+b&1I3Ť#Mʑ*GBvwɽnvEB"f 3L(״I1c#͔i4AG Rs9L|":쇐#t\Ϊ,]ç3҄i&fԭ]O'\ݍkzqU44Ck=V#rmdw C!EdBՓXN \tUNݟCJ6fDyM&Lw4C+!͔Rd&2HȠphs1\$}4>EHp߶ժILhxءUDi&-Ʀ:& H31 ^Cdi -liXĈLwe EH Pk1@1oC I L-q0BC~"5.jhZ3iÎ~"]..(L(hi6\{DH_~Ѱ,! k.Eu F?.di]?6dim$HźMfF?XI1.hCa{ni]8r vI;.HkEHXb;&H3#^K|EHdS*@HRJQo"MtfEmZI-LwEHdQ6\Z Q&$iL(BH!"2 &H "bi..rPq% %#Ҿ?@l ʹD i ?'@t ԁ- +y?pjcHi"4bc1#G3-|N4@)qR_7/ ?{IOD4!C }c i†4O$4DI>i2&:n_& PaV4RK):xӠyd<2.x` G#$&gBqrJL1k od72\ިCc cd12Lƈk4 '4WN`!0"'3&`02.`34h : ^d/2\qp D)uie]!CqBo A1ZY$4b r{x^Om B c @h äش!8 Z@, ôx r4 @iu [".2 ]: ?äXH1LՇy+ j?~xv(HSjIaR@Z?M3(K7 U =  qB ؞ ;Zl&2dM&I' ID%E.#6d2LlHw:P"Y bs9[S@eS)3dP*BI .oOCH  (GȐId&]4X*2\"Wb *6 IA)u ~#b Gc;:!0^K|Gdq<fTU!-yFx>|8[/Gc QOč7b{ >NUcH"{ c\o]J{ =Iok*Q=It^"02y ]̀YF?x.Gx)鳈!Ǹ(kI4_ϛWmצmcBH~a=AX1LJ3x9/~slu{yRa1Dn/_|`%ȸ8 $3iXEI2.h*1cbMhl S믥 2@ dd't4V39^>ef_G8z<_ya%&B0 ![tY?J B $ d 2l,KxL푇U)DD"dV_ CzaA4ZfzqX2LV CFaA}>X7I1L(6bJpa=~H"z9Cqq<6l1d-'ϗxԼ]L7l">-N8,1&Γ=:ܴ!Y0en1Jq-*Ύ!g0^<3@=jG a2<<6NC~AcPO$RIa >T֗zN} >tA"B> Ä|َl}2Ga\1D&˯^:!0uϱ:{ = t q3rtM.o]7bn3Z^?ZOןjܵz5/YƾџП|B虘 tUP𛻈O b"'f=K\do.};F'&'fB>vKZe>1`Y^VorI=p\O{"`y>G8N,..3{do蚿;W~xX:F(&(vDPtpBbb$0pb&XA1E1E1-Y[3DbBb&J%E(&(fD]–~hd. bb-t bb,$|Z=շ]04b2b10$b"b&ywy5_!^5PI+ Yd3)s6.q^X? 6&ll%k󭑍V!Gb&,c}D?(&?(fA% q C(&(fJD?m u }Lhp[u|Sy]ڈQLQ̴8ףzmܶeŹi! F0:H_[AbľMx6\ͷ" 3 &R33LE2b5 5u pyiiNSş<#^]R-Ť-.m++.XI8pyu</Gvbe|K)- IiB|)&|)vK{c55.lNϾ`E#)fbMlW H@)&)frN,mj6[;;LةʍvSLvS̴8A76bSLS$X6 o]x]J/G*1M1M1of6 K)<jLST5}Z{U=;^x%f3'nbwFSLSԞ c&)ZOZ{E;WbbeG)&)fMnG`>'}8QqIq'!M},XɈFTO;Vfb&}ک~2gHFDFL2s(̩ͩiNsv ::3ѩK  ]Hb&*v!Tmrb_["ˊ G@*&*vUT;VuJc|IV/NgӳGeӵn<ƺMUdYf$.įb¯b&~(HۄULU@ c&*fBV]lc97F*&*fU]ޏ=QQL;T^fULUDk~WC*&*fU Z-ai|bbH%&DT1T1ӥ !RR3--3mQIJƞt= aUJa$)OOy3A &#Uਘ GI>z@*&*fP>*'gZTLZTԢzl6ъɊVl!3y.o҂TLT"_SLSf 8y:a+ N1tuowSLSƜj]I=WG)&)fN]򐅘ؔؔ&ΥV|%oiDSBS֞8ݴj*h \=J|n݇C T T 4/oĩ©&NexP}NH&&hY%dY%.*b3FUBUB}_cMNзJȷJUwox)xߩ V V 꽏 hh@M/c6]u2 NUBNUu<#TTpۯՕ'(N%$N%\q' וɨȨIFuIB 5ҠŹիJsܴ:>YUTRI~|200p,0UsƉɷ3 U+~A*!*aTDplr+~{dzL-k?%+?V V˴ 15̰qd;47(A=+!=+qY{k\{y@A+!A+a ZDhi%di%\Kk;X b]z@7k.u o%X V V W-CNJJޖó[UBUެElk[?^O/X X kI$UB$U%_ H%H%\@C[.-H;%D;%.ک1Ė–t1$+~[t1_U`ISqS'0J_NJNJpR[mhC&!i|XHPJ2[ޱtqYpF~7'w5K K\QdxPmJHmJ\jao%ld6%.VrC'^&9%9%LIp3m 0'𦄉7ub"?\lzݬ?{Ӊ ğ$A)!)aNwNIHI:Led);޿kJkJ^Sv?}[(!N qc2JS⢘BF)!F)q1J~B)!)qyHׯz#?)^~D D S$bdQBQԈ\//0}Ki:ח-&J&J4#/ @=zg % %\鎚,D$%\"W &4m u/ G G S8cKnQr@(!(qiD~@b(!b(qCݔh|L޵<'X#C(!(aE@ZP#JH#JQU?^~gbƁbQBbQń_t{񧓷F?ӻ?"N G< VsMkd7IH,RbIHCĪHQtx׹W7}Vms٥o9iXGNJvRg]e>h%QOǑm[M[o(o=qXWJ?ת<3}LLLSJLSdxwo}SJSʄZ$u qi) FUFR ))G)G)S?ꖓc"rr;)2E)1E):l:E(%(uQDb:7`FQON$J $J Q @uJґXmliuCУMMީMMM~96Q6QJ6QڇMT>L]iPQJPQʄޜuiV_=@(%(eDدD)D)D)'ꐄ4>,pdLqʾbUj`OqrYĈ4)dLnSDRBR&:5E992͡gޛƭEOԜȎ$ l[[2cOٞ;j)Vwnʏ~KͅV Z[9'czEX NߺXǭ=[ZAP PJI]r)QOJ}h\0=VH?P PJD$ch="ʂ}Ej NPr$qwưP PꂅgѶvV)RR<&lR@D; Q QJqYk(ZCBܾNWRR@+jD% 7=<yF@)@Kb׷AK2fz^#.nba&`((%@ܱ&R R" # ~![՟ԟpr -O OJ ?)?)Q$zgQPԅַCo~>}ݏ?}_~agq"NǏq%4(uAR4H> /g. X^ĸf&4!^;m9L/QJ Pzڏ˲;ѓQ=Ri`փ՗eUwpU $trubx}. D/%|u)9aX-JA-Jj!nurGjjU pÕxQ~t6qs%m N/)֊RЊRVDF4mzdp (%Fd\{s{ӤXJAJA)A)nVu3 2b?+P PJTpsIyvsyоQid]^F@Dw^Q ^QJΝ@Q @QJ̔wyx-xnh_+x7xd|R%l֠ܤ 7h\HJF[H%Ń-R RJzH:M UYɿlR lRJd<ظ|$s>EJEJ(cDϡ Sb^)^)%JL{J,# #Di0J0J`X'JA'J]:W5yEךPg~ԥ XE)E(bnJU"Fp1/Qf3-TB't;Pqȣ4yt+_qU4r+3R@tգτHZP@ҭ~3[ f2NXGN^J^J]3GxI`c$L5@5.#'6R0R;´R RꢕT{I)xI)K1RJaP\`Y)Y)%JdǮ \OJx1ﳼc>)>)%Il7p"a7)7)#I)Y3,+e +eDYb[V3 4e4eDTq/?TSTSF4~S~Sg2L:e@:e.iWCK"KO`f\/'n|/cӮ't`P5Xr^ ν=ΔuQNt/2TTҦYW Ps/22?ŋ;zp*sVEr'd UUv݀msʀʈ VVF䰆_A J\ E XgCr]cza ^6(*6Q^3dede.'t;ifefe.6kW M]ޅ ElλsWWvʨqJm*(ek6Z1Y[ e)ѣ}} bebeDkJ]e]eDp|nc++*XDnWa `[ ? TyvSSQwwXzTTq1422"P/ƮSb6TTQ#YTFԦWTTF WB`2";E;=@_ XvOQ PR E] \J6xX*,"U"UFN;lSVPV?a**"W822"`U75\E hX ;a22`5!TTFH|c a**#T)}Qma**#VD{N^e^e./rnωu t̥[l#r122eslb?~}: 0V悱أjU,`e `e.+e׾0nnpRc**sV1UU撨sYbKeKe.^plEeEe(nP BBLc** ChߢFj|k<\usi*]} |Ko:q_0$$!)9nCeCeDG]G=}SSFԟB$4 lr ==D)D6ǿ9rr"DHޜWm>t述8 Y\[[ʉ(_:atr/q(9rrDϢ֗NE#@*`R_ 7-(g %31הה>Ͼ]7ʹfrS! 'MFat=~ϱ9VrP&ap챻 ::僁N݇t`*< =c))JOCc))'N=}M=l'% F؍]n`ۿl?8<xTE%nf]@` +'<*wUs32rZZDj.}r"UE"<~hwnHU9U9Q"M_N=3qtA=D3=ǖUUN5&1qZ̪NN3"M< +'bX4vHqg{' kkDX+x|&9|p1|Elywc!+!+w Y: qe\zniqUZ6Sjq&+:W9U ۄ ה䬜(g-bIHHj 1LjVVND`Clh`h.CՔzݕ@hŘʁ] Zv16r0rc\ʉ^1.vDK?gǍd0r#<](k6ڋ['n\AʉZWdI WNIc++'^7i uuDK eʉPWٴٍ~Um/\}ʉ0׀Kr"E8$?O&0jAttD+t?I1XO讜HwѳSe+4\9gJ,4W4WN VWN/Eʉfp _0yyc + +'JX>cUtW>hQTy+3ʉVFw{䘺ʁʉ#;{MbX9X92 UNIYkFPrEkI: VNg`s{p&+'2YaNB<`1+1+'YõT,f fD1pC c1+1+'Y=n(,f f*fXAYyō W3pNVݦ3jzmnDǏ[ʩ V{98an_>VVNEs[[Tߊ(7r;=:_,l&tc**W'wP&xS,r]Y<qQ+ X0`**bWj1rr*u#@܊zylvy9>Pn&/U;V7yOmWcPrz,}J~k쫜h_1Ђ_丆}p +jXwQSI,5ز7l\`\TGݡz\UUNU<_*Q Ia**'JT}b6&,N N.qj{aKK.]Tb]|c`*`*wSD7}̫C}zFT2Ag q *wQ WAT"AVrPr4|ƎSSrH x\M#֚rКrDb:ޥnfv?gǫK<fr`rK_=9VrPrĎkcӳ>kPb *r}aknꦪkVt֧Dܜp])'OGӼ]tR]Ab/vQοhThTNDıJPӴ:ڜ6>myGBj(^Bu 2#Q Q$}ĻP]!KbASd_t zz]' LLDg/iqdZbUUObrUrUA0 TTD*=f)0{>`?kü7 Amn<90zU9>i~Scnu&T&TA4"Pu;v p \shY** ෤ f `֪֪ VM}xsED(Z1CgyxGWk5XI1UU cHzUzU ^qQL]@]DJ**Uؽ**!Iy1UKUHUQbԪ;\/adMO WDj1 O8-!:B\*@U*O|@\f*DUHb UCƽWUWU!1.UDrba zU}b,UUUث**yUXX*@* Un^ޜuX7z 7+\€*\՞caϪϪpyVWX+.|U|U]7 %wp1UU(@yarrp[spoo.}k ZZQТTir*f ` "E O0EeQ"r<9OQ󎽎٪ToukSawn%ѻwYȮ琏 h5f$B;"wſn0*u2s:&k  p5f,@ųQUU)TRGoea 8VҺp=u Va+BW:~f^IE~5+탬>df^iJ"xԠMv:Ь +M%BVKISU ?͓O=U븭b'M#S:A5['UhmLJ(M%$RL4&ҭ?QݚXSIT(g5pfUGD7O22*M%JQ~ . Ͼ]FۿoIQSDVM&SěΫN?4MbǦ)R˪$^u<9h6ErǗ7 ʱulˬ plpۙ< 0[=6e^Z ׋R$b>/j~lj>Ízlؔt%"]UcSJV{wYP PAںUcSQV϶ަ++S=m]Y5_OĺGn*ʔ~"%vCʷ2ht;fO'ŭvY)jq5pubpeJ8Q$;ժz<-ηenej7dE[[Md>cWbme6Up?I֘@1Q$Y\JN('5n<'CĪ艩Dr„$ 1FO6DgXcČ TX×$fh@dE**ODhUͤ;L^pO{n'S/:a'`][À җG?鑋5\Hp1r\Tb5H1R OY?5Oe 3C EסXE:3E ;z:3!JnfJ.#EgDo\"6aZ" F9͚#(udVL`=ft_~M*jf*"Nc4x>Ȭ˜Hžw׷5{/ f !2e/f>6j`nj  unAuUrS\^V M s^u窜.a>e x?ax?[ QQݟݔЫ5oݒY##.Pώ^|3:?=1zw;ػ+)s1|b9OrI\R>xu 7d\ %,cPcPeV ~j  ?} .[p^’KC/aqp&QV>' '\zDaQ}P}J1 T̯w:PL뿦e HX0"ݣY0p ^k  0 x$,rPrP^L( (\pQ^^',@P@PUQ(z _+ hcQXԠ0Ԡ RYzaQXҠ0Ҡ JT_,( ,("|Aa|AA[-,PP!^Uԏ5˦2Or\:kx@Aisufۤ $kl 3,Y};gU؍4(`Y+xrm߶o-(L( L(0azLfh>D5,Ba,BAP,PP,=?z,Ba,B?zה  :|j| l^iY0pт_ KF.Y+}gуЃHޛAaAAiw!z/(/( ] Λ@a@A/@a@AgZ0pY_B .p -OO>,>a>R k5ߓ''B >baoܴ lqybxqc{c&aUO "?6@/1Ӱ*1ƭDŽ-OOS`GhP G8ݼ^(9H>aH>A$F>gN,OO>z_bfar G-Zna`=c|¨|:-DGξT%Qs՗G#j#8Dw]gˌ*FDq0p‹iA[|H W-UOUOU5",OOI' ! ^UˬƬ.vV|/wy'y'p{ KFTjTX֝0֝ZwӨ@ a} }…H6~` xx%ҿXx0xpu^ CIE.RkR1/,/N/N8CirqˑadC ut$aj j…nּ4Z0pd7AV4Z|0|pa 0QZd4dta{}% %]GZ4tI`[EqICqI5WV\EAGZ4$VwӛXץv-NloLwwTZ4$qVe=tFT92+dDY;#vcM2ba5W{(-JJ*fPw<߃7i!U U҅Tyyl{lj˫*l8ycT\IsLUT t%]Е!#r`3xҒ$Q$]I\L,iL,I4Bn|KZT4T$RY,ުȒD k,`I`I"=3% %Vq'eGdVVh[Q;scgr5t9lJ_;qN*’D bޕASiaZ`Zia{S.i.I -KKuѳ;eْْTf+nh!Y Yd;0j<6#,aleI*EHu(Օo:VY7vYC^AVY7hYCj_&gI@.i@.I|ы/[A;zǒǒ.+Pc nswVLxm $;ikt`\-rv%(˚CVԒԒDSuĒ$Q,;F,BK -6zb% %% N/wh _~;sk ``.I8 mhX{wf]҅wʬA ڹ @~Wf%]3Xn%%]}8_OeZ&r8;DukYQu5#?WWu\488t/it/IԽ=V6$^ѵf77ND֫OFi]Ҡ]҅va%qI#qIĵUv% %]s]oα|U"%]kڮuWm%_+*쑀EmICmI"OԒ$Qdⵤ$ע36 ߒߒD|+H"k,KK>c$آװY4$z\F5l%%n׽Ͳ$z5l&&ְY4tY`J|vV6.t`q'56KF.E35l"& "&5}a2i2ID9?6K)F)DpN٢ɤ$&5zicc(d.;FBzL>1vt5l(&(&%װY֘4֘$Zc^AVY7ؘ$bcCa2i2IuV_Ezleqb[٥bÓTGVN5gͷe1/rkt2bcD㌒Hc 6 la>Ic*bLF:-ul#ֽeF! #̀{G,&rd4|7C-,6>YLlS,&:ebѾXqM_/t u_4#*ˆV_̘u{x)#IJ؈e1Q,c <責Fgы߼z~{gd!b"I擞N1Ԏ^yw::}'4:Uiqfb*gi(b×Dw\ظd1%.4F,&bd9aqvT|= Е[pYlಘ):ʷgU.[Yu'ؙZ#ßDؙR3Գبg1Q=O5㳆FNr?Ob:-&i?}N;>7 oy~*1x 6`g1;cd?7eg uowשꄽp?-p-6ZLߡ)--6"[LyzZ-&j5z04ZLф]b#TGo೘ >A3Tu[Ylmʲ~;65k]&)-,6|YLk<6-,6Y͘mYYlx8oƎ*W6f+ ,,6Y#صvvfowO,,6YLDȒ=R2bcDG;o`Rldb"@FHDΒORV54YLI雠lakN[ * Te:#4Ŗj,&fxpl!eAb"RSDl cb0#" b,#jɷ!b)ňņ]~c,v`~Bc[WlK9-+6~WLst02t\1Qb*n1^ab"H3Dh^1"-+6WL$d0(ܮظ]1cw@ۥW@#_V4XWLĺ=V4XWLĺ(9xRblDeOvf1[ab`ņ] ^ߌUM'f\ƹΕ8Tq*&W´7a޹>~/XVl`˻w+Z*_HؐX1;JF*&Wăd,*6ULԮC]XUl]1 eWƮv# U@*&T#7 3%K,e~Q~i[_ǪφT\py{]ta#[HUlTSo]50UL؉wmV1U"\)\)"p5h,JJ%+Z.LY2rV0eYWXWe]y S \־E\)C\)"qE;և) RRD_wbff ܉Wnŕ<)Ϭ)RR.Dr3sC;pT^ ^xUXRY|2|"U}5 6LY222"TlǠÔeY)cY)e4+:l:aaϿ\)\)r%[)#[)lGK?YzΩ,JJy*q SY2"S´*bsz69t* RRDO:eU)cU)UEJ%NeqVpVYJU"QF`I*e*E!V)V)"X\*e\*EtT55P* *8N%ˑRƑRDG__)y[*BAz<ԉy-DJDJ%s*V7ڛ)wY#E(~fvC)*ud;{%g>bazO'hxfRRHK9g'aeNҦѦQ'IX2"R؝A)A)"%c=d^_^+񄁠xy*6Buָ¸QF 0:QUz_JQ-=vTJS8XaV[ۏX)X)"`ww4!c6KeXXc 0rzqm)m)"q%m)#m)E9ak "\;\vV7r \sYes)cs)Ş[YjA[@[m/ -e-EԷ}bZʰZjoevVv,JJܫ=,F*e*傪,BA B55ͣp RRD*QW W\U o +e+Ed(aWZ2rWA2BuufQO RR.FkWNqRR.+L!Z2" \u؂J`t-et-EԵĸ}x, ,e,EԲ?V6&rX{Y2rW{]jWWʥ_zL/zj\,r6hՒQƒ'gmRRDOV/nse)e) U-YKYKd-D/U-e-·IcꟑQ",S-e-EŶO9 ,.e,.Ei\j9\8\p~b[[o .e.E%pc(-e(-EĈ[f2f"Y?dx<Z2"Z__KRFRD}Z(2("\{|k ]](tlR-KK.=Cer)cr)5 ,KK \Xf\\hpoaYb\1E& +Xa%N<b&FE8~BJ  >7kBKJ-D"Cp%Dk¶m%DlrhI,}+1VҷmV A7-J,+1W?|H,M+1VҴkA = Bǫ%w6?[ Q=fBj%DTOԡ$L+!bZlǠAJP,vVf1j KA$=+!Yٟ=C'd+!"[,I,v+1VBdG.Ė}+![_E`heCm%DjOۗ1Hb[ Rf3/7ŹnQ{˪K\U=ݧ餺z6)?Nˣ/gG| x#suY/8WպRs\ol|rOiۋ7_;LP%upGh\ʣuѺ\M/Gr:?˧sZ9Wߙ=[Tѭ7:}}x2/FI6qR֋tvrwEY_K몜^^UO8?RTqܼ4jN7V^ߤ}rM0Vj<ԝ|e}P>8I˳aG|&SHOv1~sڠ벾6j_Zl'\ߏDls65R{ ,f7fP\9NW(v>6Ѡu'=]ݝA{wO1]rUsJAp[i*w77Ԓ$?hco6jUe#.umX(gj韠ǚO㰝eڶ7jb^Zk]H_6j+Yݰn5unm'v'vLG] ?4mޓC7ڝzz6շOdRw\uet|Qm3~ݝpmpx>y戝|ɞ@.{̗T,ǫ/k_ߴmj,.s'yKZ MӨ(l\FU1Tzӝ:puUwcf @Wrwugگyz1]iWoWu sǗm[ۇmxAh3lGqM=X܌]?smOe9Y-oy~2Ud:n|܌|~=n?NHzߍ&vs9tMG92t,kc^@h2 ^8zX~i.Q$OD|=8z>g]zT>X7]:_e:jHATRy}M}^5Mf¼X0uո{6OOя^~wZ_쳒yuqiZ_m!vu?7mZQ IPr8םx cۍ@Jۼ-Qۍf#ĭFgE6ge|S]M՘}j#q+˨=Ip~tI`b x+؈ 'Ea_d]n#W37y< ӯ6GSC@!nBnjq*6E#Z?c;Ta'INl]7?]hD{w& q߸or[78_~x愸 b%e qÒ>arCUqm22qǙ9l['frn3>[?'`N>9sR ;zv]6()4OFݡ*qq JxʼI`Q7mP¿h=5`G ~=gFjltArXuY4fzrqqpVm,` 瀊*bAbEذ]]Ws^ E=V6nmfraso[s{cPw`MzImͭ,vAEϠAm ^W/GᗟN_f3A]Ic\3nԨ(ԭ5Ļkĝ5{ft3D֦VulF\=U7GPUh|õgM(tHMveW1f7?zo=x߹ oJ4/\1I]N6g  mBل@*@!{(O[ڜPU{wH:nN( qO&Mv2LۘPo ]K`%}CUp97sv9 I`g$uk]&*qJVe[uӫLeX "P9O[!ViG'1P7'aE=J%Jd:x2]Br~~VιZ{-O;prMV8![0=G1ۣwGQ3v`,ۊl׊GO̾+mẈMX{S7RmW N̖+W<~Gne4o@z3-f-iqv3MF:?:}aԮF.6=E[ 2s[ <xFV#y&]Jz< F+|qs0 #3q+kxJq7BqzޕʌVF2b e(#"2#7fK͟ggCcFYȨ fSoåـeTI`mbleW>U&vǪoR^h9 *sF9!:fH:e2nP&DvFA1AUz‡A1pb{cq@L} !A5ĤSLQ>*.a0AcVhUksssFq>L0Jz7R ;_ʹ ̈ p#$zĨ-f+!8a ݂dMdlK.ʱ5޽}cK%bאO"]uQWL5_h@GbO`aK%LWHvs `aK%P` Xo'+8]v  v p`wC w  nSoM> {T=r1&@. 3C a0v%$ c)k S3qܘoL1J {Qa*sÕ0A泵&[cH1^,"chk'5\Á#Dl4P{\UuXéeCKLu3F"FgFJp$XFeMlGxn$c$wL" \$rE=:»s~KlI0$4 \6r$`KI$RD :$HnS,i@۟/rSŕL%I4(]w].I"rOFIR&rtI&70Xs9Ik`9I wGo=}ʺ&׷MeK8Ip$qYӭ 5b5E^ϫh]}qJX[C {T[H˽Q(Rwi^9! R҅H韞)$"RuzEI"տغ/lUp!$RHK1Rjͣ^VW) ֔$ZS]D4%rynXF 7UP}n߅LI"2E<~Y֗Z Z к$ ,5wh[ 1@J%*+\MʿwÆJ +e@`I"E Vd+I,$$UV =ľ_J} yIǵD)IzPcR0)IĤss5%LIP$Q"δf7|E[|FI"5-$Oh?saAbI$TIcpI$]>cfI$]̒yq~Zd3IЙKg">֝$Nҥ;i~%.jD.7zzJ}7ӗu]uݺ }J(Bw="xB( D$Q=rƇ )PHBCGabJ1%kG9J$Srlz$R\$T(RJy:1n"EW*pxG|@0zc--vhǛ1bb}=c,,vgAҷ<`fAA 9fu4onR#wq-&zhfv\<ÝTs[(e 5c,,&f[M1bb*W62+d1(dK!|EEc;a18a #Piw-'6b0bS;3$a++&_}"Z6yvst_1_1}KΎ4 b" F~A81>s Q[اW4`b"V٬gWd qq.kVbPby<&S]?QY/t~?K?_1bbEA]~={w>j[ZWq%uQ&ZW7_S׽@9 WL9_\Ww|<Jr0bNs3~0c , ,&R`*eÒٷKcc5Urnx(XL8I62&l>v}k3>Ϗm`'X A J7[syQX`1 rX XLg;f犇9D,d^n&6b0b!Rxѫ~㫗oO߳b*5HyķaŠT9wJ d1d1Q ¥bŀD|G|݁#ۈZ}㿟c,,&eO>c,,&f7UwuV??'v&xZL$SAA /ƘCC]ڮ-E2Z 2ZxK]Ɨ۽RbrPWW]_R(_;Kj1HjKRvY ֳbS-S-vjA2 ߳bo-o-&zkE^>=+Dm5^XYAYP|jwbid*bg'L@TJ-da=a--l_A{‚Z ZL0S1a,,eN߬޾ٚLζ~ \YL/:;vmh)(4ib,,&e̩z+ {+]Z:e1(/>* .Z2~[ϹE(-2X"A"=~nX XL?Rm!! c]Q!55#_Y XE4f[ VmKq#.ŀ.l-XQkW}+\ss][Ф.<-voA.\x[ނ-\zzSoqoqp@ŃQn"NwNj;`,fb`b"GqӻW``D3o׊hUz h\LD{QP͟gUb\Z_714υlz>Fgzk !~a--vh}kf1hfK3<+Aȗ %bb_6 %%](^^xX xX<^E,!߲W WL4,zRaK奈[~ڰ¦KMxMTaKp5YaK_URw)"`* v)Hq)8ܻý&RD_5Q/"*^^f*L)_US`))*)PQSY_U+S)WIZC\/@>k p x85_US@)"%&09SDrn﯉*)pѕ5Q9" rC/QXS)G[_ߗDv8sі|G4vc Kt $:XJ}pv V=w_{X=B;,J /S.J+kLaO>`Sv (;ECتf@SD_V;"w_ 3v ;EdbN _lUS@)*)7Tm86piZf0p5֪SDVE8""p^ފ2k {r <9Ey|;HarN9?I:$"tr @9E[ p T8ETÿԪ0SD:WV9ڜ"jsA~_iUدS)_VQ<("x_IN+ZؾS`)};Lcljө>7<\S1tOS,=O<&Ni̋7NG|LaN^x5+>߼A;jJ%[[d@SD.P]'huѳ9[qNaAߞoНO\V7;?&wE Pfg\j  \`޶(=˧\,`6x5Qp| ܚO_||֌2 )Է\N&qڷ5Aef<OP5cO마OkY&S.oKbnru9.ooM{EL*-lT *7~y~K՛C-6PlvSx"O`/P^`S0XS )0e3e -@SD/|&KaO䧈_EުRS)*7=ڞj{H{(ĸe { =vzL*z̍W4`cE8/?5rGXS )W5}<B" y}"nlq~ D#~7E="z}y)c4Oyj\M#ݔ~ K|Vn A(NagO\ޮɇ\SDH_0e*/`t 5 =E$r~"^Dx!&XK@KX_:cukKL𽄈W7ws~g,!c" .cgy8$- ϶؝foY*,/ʒ9HJ00I H?:J0旸0?hU֗l\`//!|L%KK^w%6c#/#/!y>xaM @%D'u&KKh9?\K@w~W%D;trEsK'ԂjekV~>spˉ".%D0vwuTC\%%DT.@vVK~nKK ]t3;b]Bd䧻5}??<.!uvXK@Kիg \B+qad.!"sW`ߏ􊫑&ؠKK3ehK;Qą ?Q 4)[[B"?MfLe1pZpZ1b2sۈvv*.;ưk$/n  e +c,,qqfq),qem8\ Hf Q2SƜYYBBtʛm ؝2`ٓ>=^2VPR Nd d %SƀXXĆ1 SWWBc5dgk_ w܁ו.Zb^.60/|n,q*Ȧ16p `%D// \߀J_z._%D_"̫ͫe^ _1ppiL[%@[%.ڊUaB10YEU U ѭq9"='tn&5)ʱ6-ͧDw1>ܼpp*!S/6`?*?*qQ{pI)qiNZ)*ʘiJiJ\LS V0SBHp7)qIT\ 6J\ў*%.>:p? %%DxO!0& )tc''!>w5Wܸp'!y<}F|1_WZj j7C9wX]\zaü|Ѵ*C?v1J6jus^I2̪6MvJu3p'!<}r : סa鰼4rrC{ allY`U'U'!: ? wwI.;t\UI%t; ; QP8&IINq<ؔzxn<ۼ :6 )(=Ku/n2OI̟͟eIqN d$. {A xA 8CjPjPBTD:]`((!*@}R,'vC3Sگ8±-́7.` %.[3oqpip7T8Y__wc))qHarRRRRBx~RBo\GJ8R>ƻ 60y#[?1O~ =՗(KM1]]R"Mt3Nj J"> :ngbb(b(CͳXJAJ:YcٗH#O &zJ.P P|d8 n[N188j_ 9xH%%,NJJ]@>NII]j􄒛d. nONSDGw$aްIIO0ONSḊMG){R{R"'nݓAf| x<#:):)J9II~2g7dt*j:8II}$,vʡfS Dh{o_?g}ēē$ IJ֓}V{RP{Rڳ":2O 2OJyzćb''%b?1DP DPJ$Y1ŖP PJ92ĢP PJxwJJ]ΐ_WxR=p{=$|_ݡs2޽)RR`^%6R0RaD#E)E),D}}~ 8i%$(Q//OO|@0{6J6J]ў/\=8J]đ7/wX=JA=J]Q=#ǥ,e! Rꂐyxa(6R0Ri~5KG)HG)Q:Bp؈𶎴>-r  w@.wR, .h9Rxy]IQJԏb, @C_9l@_]u֓RГRDHqn's,%PčWLR#_/Us;t#w>#J) J)Qͣe/HJ)QRjǵ$ա:5';ԅ% $6 H)H @b߆D zR zRғvZwaRJRJ]3;p--.n;7@\JJVRM111.d#d1 H)H)QGRqq~{0%%D-)@9/`UJUJ!n]J)J)U"-[ p54)wlQU%4oEu\XQJ0þR RJzνBR BRæQ Q2ryxn67 t2`_=n0ee)#6I1ccR^1Zw ͮ 9J9J;dzҗ ;\@+JZQ!PJhoFD6O7 Oa;.xDvo{ݺqnbkO DVh ^R,DŻW}:v,uIֈ2Ј2FlI셰iEݶ^ (ˈB5&]>< BNUu62024dGa%)%)#*IswsV/[]LSn:W2,+e +eDY5M#!4} {KxK[J!yd8 2 *7ͰӔӔ&B*̩ MMl`&2 2;]?[mkyf||\wJzX=[w a * *sQ{zp5)s9Oއ:i ?ہ`**s Pϝfrr\>N33e3e.x|6-Ux}{U1wm le;P5n 𦌈7 w8 7w A8\6~i NNvW;F|a2;e;eDߩPC=F̰━>.Xu@uʈSȹNNub))siL{)MʀM\lw׿w%[e,h) Z]p4)#IRծ-%SRRFdd 8p2D-es\Oc:):)sINCҾEE\(pp&J Q2}Mc((#GMb $R"Ҧr{R6ԷU5g3L5liv(eDDiR 'Q\a '7+gXZ@Zʈ%×s0qC!:A&9EM?4Q2 wp)#2ME2v2p2'@'0ȔȔA&qlAah)h)sAK ,"e̥,E㎁822$p{P WQ2 .-eDlrh/qSSFԘXL.e@.e.riX,e,e.fi/NʀN\t{6f]z?_pܤ&QOFEڧf0Xag}0hY<0e0e.i鵯6+<N pf(1)'f1?V2P25DbcR`R ܬc**#Tܮ::)f£v2p2[mgط\:aaY⎀{!fx-磊ne.uk>a]q[Q{ZxZ"7vj4zD 22"E q}÷A̛]lre`reDb{\x\Rghy:fF)V2P2In~eNʈ%lxe`xeDËqݹf\X ̿ dX"v>IK90cE' ̺Uа111jA.4Le@eDzLe߸ 6Cn1$<,#*eLÝ$< ,#d*1gK9dQ'`wLCYYF5(|Vza,,*d;6bE|1cZ ʈ"ߞKe+/(cUc^7YN9vrprƋ * )/xc@G%d 4&V&V24ǰUUثHU9_OuQV9V9QV9V9 WR} ~7k;_ߏw/ޞg~\@ʉ-dKY9HYK[|լԬܥf162骺V>d=\\]4 4ّc++++'ZY}"hle`e.+kmle[Dc**wUXVwb>lp[)0gg8`Vس]UFMѝs?=GrzWEO{%aWo>U Ϭ>p+>fr`r;b_ޚc>,>,wa*ܱ>rrƌ .`DrhCFa++w^ȹQI>WZ93ŕ܅eߗxOgʿ}¤VVN$:S bbDOw ѹ-{X9xX997@\ʉІLbb>s;SXX.j U9UKKgQP܅R;Ӌ> v0U9J_=Oq*rT="@.c**Tq؞ IISMs PRn>^tsLQ@QDxq{Bc=7¾p+w9X{p+wX.u:^0_fQ}(''ܷTWyb 2[9I_HH_r޵+{Pr=تJ7te}!ZWZWNԺ8}ieʉHTWTWN ^9^99 ;\98\9 q)>+'YC܀a**'W}o/{u9.6r0rqe{ʁʉuAw`BoޝN$c[_v+  Ur,廝˗?sK/f1#jõX|_ra`c1<7@\~ʉҴgp1.ÀZ.jχWarHyCp033)fVrPr"5O9O9b覜D74v2[g̔̔d]c;RRNŸԭ^͔͔m~p<rr4|dRdR"Am>q=rrj:tQQN&a((F="͏o+qs -r2pt&춏+D &Cǥ ȡEڹ!7R\]'8MyQMZSbY T Gw +$OONz0𓻀;.ԇT 74\@]jO`V΃ZmA{\@ɉwAMɁɉϠ=i@.g O ORxfHP`py<sr>0"O"OAy , DyǫWպs3(SS%;C;@; CgR*tpzNzNsح?rNrNAslk1(SS=~, nPBS `MMpi:!))^ΐo o ~3ρP;9893 4¥3 %k(Eܰ[C.fϭc8`8  SS=~L@$'xMMAn3JLJLARbt݃!Xd)@d)\"˾{\@^)\J;g׈ **KPw+@)ŃB)R R@P׈[)X)Ep+J)J)PʐR R "`;; )CvO)O)\x:\E)\. RRQL_ޜ}( 1,JJTJJUb:ׇ`LL b*B熈h*QSiu~eߊ?75QW)W) BK sk++^9őv}[wu "0KAY81=+RR[k O0] p).%\n)\(L$\b) Wo$\yA)24LJz=)؍))n '3k 11U!]Kb|36d 0d !J5)) 'v\] *BJwXz)@z)ː#dL@.%؋L>sJ)J)Vʐ/K)K)\\X<)@<)\ɾf!1`R`R pRpRPAgeReRP-=qsYD .d])N N vN6` p)_d6Q 0Q ¹%oԗ 쪇98ȩ}((Ey.$myiu5a %rIIAdLd%%/ܘj쓂h}''>P P okk)h)KK0RR0rxJxJ1 TS)>+RR|MbJŔĔAŔ))E 1%dP)P)ʰP)P)'ԍ{uQ)Q)]ʨQ)Q)1*^sM)M))u0#R R "2l|XM)@M)jʰ=vS pSuS  7@\@O))zН.K_R`--ا/OR , *L4t'Af_"1e=045AԱV rBuuA7 X+/AԿ>JM\!߃ 2+ 'п5|_[&FMc) ᔺ/{a6aJcԱXMlJ뭚%L **Y”fͺ\ d Sp<`u4Vh~a'+XeN2GSeJ'L{PAV~BT V|T&r62L %M"*w Ҫ`T0"kEHIS]ʟ4A[%MI+uLVaV1 `&MQ#r+>e4Ehx>hh uV!ɕA4XPZ8+uVMMM tBuVM#+ UbSLjK^cUbS WxRf3/7y_{˪K\i*ճ}Ngg}4?BuY/8]Rs\gol|rOiۋ7_;LP%upGh\ʣuU^F|}T5q=^]NGb4:Y~^<;gZ\:fU篏Q5fO]'i!o?l+ab6DCQ*W(N>ew7ܧQsQ&蓫GoWf]o/?/:]̏qIZ]N=3XDj; >{l\SLb;2~#g}ߟ?mk`1WªmU:׿sޝ2Q}K9m/A&}Ozz;;cv}Lc'~,&'B*3~yToo<o~&I~ro6jUe#.umX(gj韠ǚO㰝eڶ7Ojb^ZKo hS j~[SvbwBmtl>Cv=i>|io>_~gٴt2);zt}:6WFwCt IaΕN2̣qb\bأH""zq|6kϺ.)c9940suhqUWu^1zK4ifw{f^aV^D9% T0%}U>x͟M Sv <'r?nX ϐt&Lf)7̈:xZG\#vR^?x{r/>>l3I9]l^۟GߟkudfC;O[9iYP=xG\KjB/p--]G/O<}4iAMXZ2x׮׺3j\M[sU`ZУhZ;|4!31T&aK.݄ÜM\`kˮ.;`>W` qJ^ӈo,OP)ĥ)}]^|3of ?摾}~y}>l/e,e,;Oz}4DfѤ<ln5|*ưk E/7TaS%מJf>|RB6[r<ŏ:Sǯ㭓`$IԎ`s=og30og={0G x%cR$ .JyѡlD+OtW' ID u̐HulsDr@H{8QM{ y?72}\ >1(-\;qbI[v$bL֫*GW:|TEדvt6[YqJj4kwxG#ȵq ^g8*3+-v1"ob 0r`뮬+ͪ"P \y=aAm\ y\7h񡮸G3*jyߣ>13C5 6="yD9meܼه|4m`W$HvT aK$HKaj; H(oLїơvy\O "ryC ft>~GD=wV}HnGq#J4hs_tD(alߢ`D3̣H4r醸r8$Q v7"nnĺB+浏7/[n}=ܨE}81A{{oQ qRQ![Qf[)wuhOnOs='g^=G;)FJ}hY9y 6^"DDzx%gpCR` ];H{2Lv;;۴-j HEdx3'ɵSb}`'.NRTa#'>N9a< m'l\U|<<2GAmUtމ}lD6 B>θaWBPt-]RʵԮrBk)͵rv3MFFFV 9ӋvM p;Eo$n*(Pڼ "Nsm'>U]R?l5x*بV~@޲ vU>uyjo_W/doB]˄C%U.Od^bFgEG&n0m Elv {XA}{+G|{*d [R}nMʏz)A(> Oeahǂtz-9m@^ K7V:y1Zͥ~MXH1~xD<\E=0;KQ7:qEYз),:E ex4XՉpIYuXMǿ(*,a1D!"nEAk>rӷoG^?}9،q{Ȉ"F/rE/|.؃jayF4rFA]NE#\uD߆n8wlp6N}.BoE8Ưz,:a),HTm?dZ3~nyO KF24F䉶>JXtx=I)Cam fvICO kO0%}GtEG^՗bvwD`f0D{:j}6a.7)؂q̮7c#͢ަc>֦cf1Ǥ+ mw`ݮK٤?0n%@.ފ1l>nh|ar;ɀu+ VfAHIX `ѱ Tf{;xG{~%D|]w}[wٗ$ [ "6fhVr|*l U>#67cȹf U#y=D2C]S pcVJ+%Bnv[7ڬVj^Lin;/3ѡZkI%T*p~s g%Dc0Oqp"$(cJy%j@+ W=x}X״M>hy@ݲ$_ EH|h>Yhfrw¥-A$<\r-. tY\BJsIb[ O$G|aUX?q7r$v$[n >#1%ڒ.hks9KZ$-钴s9|O+Ό7 gAa85f<$6$Zjj?*am, ^zY="3i, 4X=HW*]Q' ^ؾI'WN?Æh^<|E.Y,IE+[<ܤm&Fo4&k%Z*j 3~?KOĒbI"V$(Yd 7| K(OXIbE?nwJ)B\`HHi3KTI@ zrWbJR%J>fHJRt=ܙÍ`UUs??U=hyO_dΘ@XI"aEi}o']* $ Tպ w noO{I,UI$Qp!* $BT+;77GPbJ]%vUMIЦK~I( $tP;ܓI'kP_4CI"%e :I@$uD}^/n7I*+n$(ܒnIR%R2P$6$Lj2%_FcN0'IŜI],1$|TwdM' $N${I ~!vs$$J +ijIf]jV_W6$IH'%1m5o)\tnqџ1$WT^~2-JX%Id&J3xNvqU?O'Wx$fb}zpI&U0ksj7gu:3s'T1$vDډ؝O18f :`PA%KAI$R8 N6*o]t_&LEI$$X(Id*n*%$PBQ>xC( v$Q$ߐ`aJ0%froI+%DW_qEWJ>+%+%a])=ȍQd`XjUՇJox;r9JeU%$QG/w"@4mvӌV?gy) $S4Ϫ6M{aU[rZeWv|J0fK'UV2SI"Lէqs%)IT7͕ p;J(J&h}s%$pQEQB߼Ǻ`Z-%$)Im{ؒ`II%5H Ph(颡hSP((颠<M7j?BIا= SO'I@qKg3I"'[c <{p& b$M$Z7kJH,0I$Q`37@\ӀVDZrPZ [Z|W񗃃񣭹Ό捷?̽`0JR(BCrx6Լ,( H$"Qwce ֋aKJ%%c^ Rt)IԥpeJRedq!JRrc (I5z>$]hS1bbǴ)#L1 L a)݃;߈fy'Bu4/I=fNXAR%|f\" T쒦tb * *vQs{7ZT ZTLԢD#}>ĐT TL( KQ1HQ1Q$i'bb";t\*TйSLu(a**&"PIЏ0S1(pqXA! N1N1UuCc))&M}z<׎Uy18QBfW9mi!vDq)vANF {lz~JgflZ*TR;*Mf_yfH.Gj([G?}wo{X誘DWz].j%@]U~w&u,9}ddD'hNZ1Z1" yolN[1[1b?  hhBd1I,4 ma++&:X}yG1d}q+vAX=c**vW{zU zUҫ7>ܱq3oM'wG3SU UjjccLc@c.k'5?1ֱbбbŌ*g٨٬/vf]gfο$|wG??g1,JN5>s(em}^~Ѧ\WVۣj-R`b"pj\`qtŠtD+d?\슉`m5Ǫin사e>RgXӊAӊ')Ws5e y VLD(L9m1^OOu7ԞfUkrmҊҊ%aa%ܾW4OѼ71\51b0SY-5\3,haXtVn=-CȊȊD>aCpck+k+&Z[wuݲнbb"2LoѭЭnQ!ku-J+bb5`(` pY&V &VL5zD>Pgzz+BP)el]`]Ł+kjX+]koO+QRd@LnHw,ޚVf9-r9Z;,_)b)p!W3]`w}cL Poc3[_xO_v Y ,Ed%OF3<0>=mᗟN_{_5Ň'~V` @ڽ.f;\G}GuTK>1> s\ 8.(Lp) #u,XraYGrv#F=ù ,d)K"6nlЅ}@RD!+AdqBR@c)"'®ÏfR`f)E\_ g Y ,E4 ?@x;#O_n@RDjȃ hTQ.iz[ǽqg1SjJQժp%}UaJoU<V x+E;<ӗ쉡 K1,JIx Yq760O F X`QSj]3v;+EVR^)"{Eb`Q\RDŠSnvm4֝ʱǎ U *ETױD@Rd>/?R@J)*)5TvQF ?Հ(FrQxƢ0 R.EO4g|>J ARHK!<4&RHH֍Ng-XRM)6̽75ZUR.*hg-XRX)bx/kX 4,E԰ K1,~ւc$cb)p)w,+rWÏ0cR.j]0UR.eVrNNwU^!ч $盍v=9ǫKv 7HW(]p80KRDO]V7畽~f=_)~;; \ARDOB0@RDara/zl 3ؠR`P)AEIE̫9餺 U *EtPN8 ǽJ+FaWدRW)_wpI)rRV *JT(fP>MMϤruӔ=/.8)Acl/&MH69Re]G弚V_'O 'EԟFq 6Mh6 =A;OK}u5^_ pN9Qˤ*P&EDdB&|"M$h;)w\^"'Γ":O}"eG4xN9 ?ǀ ' D8m87>\cAsR4t!Ő%wSO '增v]'í}RI]q|ĺl7pc4E'i^⷇O$6Nh:Bj~(F#ӿx:a@)PQ ' ?+\,RD')jΰ…l(E&cM WYpэ ynF^_06RDl^|WrzY075\߁RDVvc#3xRI@RD1@ PQJE̾ !RTC ڳ/ńBJQ )B蛾f. R=r=lH)0ː ;O 'rdkM &Қ<ۜSrS0'œݼ;cI礈WrVgR3)"'B(5crI% $Uu܍J( i#)D9OGբOsbI*%c6Il%뱾GR^+)N(OJaxIRrGmdЇnR`7)(?{R.3  P (v-jN NKtw{<oK/z /֝R4ol޽OeO O Q~mPKٽB# f`;݆|3`-& i&ao,UURBذJJ\ծL'CJJLUp/e{"X%X%DƊ띭vֳp j"n幍[KV HV Q?b**!U`w=XJ@JrTЀ=QuUiM;$°TTBsD/<;DºTTBԥ"a**q9T^2/ylŸUU­d?(UUr"gwb_l1֫Ы^#>8K 4LT%@T%Dj(TQj G#pn{¶TTⲥ10ąA&60{nYgXJ@J"챑1w IHHBFD|HEQ&EI"MB%B%D+nXJ@JBTйSBHa**!P+~mlhC12 P P х"$a**!PR 6^*T*TRvh=O/u)+?癰(ЭY浍g[nУyqسJJ]lX`X + U'ZX8ZvXJAJ].FXJAJjUou\́u.G.@]DOZ^OЪRV^W-ЧR>E-bMLeJy4f}?SlK`KD[ imKKD\O]_>p<֥RХR.'|nv.u)m֏l7wY^ʾ7JJt%nQs?yJyJ]L5@5.YR 7@R1;܂ ,XrAVJVJRo=]RR/~ve tԥ+R( 1ݣܣW/޺}'=ƑRR"$ON0~1{}XW>X XyPRJℿnvl>J>JQ s54 p/|0NO>q(%RE}L@.hqOأ`((uiDNc((%ZDq;ֈRЈRF'Bt`<&ձXXŢ>qL@J,J,JE+J+JaES/{ aOc((RE=ivPE)*"w<`R*K4br(r(CD.\{i=.tIxl`T@X*JA*JRpWRRTDivP PJĆ(q?MkJ3B)0B);we ?P PA[', It]M痻fvEn 8O O}<.;D:'. ?@yRʳn:):) -`&&%6u II]`G*ܤܤTf~s4)p4) /Iaw XIAI͠~Ȥ.Df.^ä.ӗXIAI]:GIITno0)0)!mR_$SؑII] 3-n/QP4* *d@ǔ%&`R `@c]OPb%&%&%*1C3P^&jLJTc .PcRC}'S_:ex` 0)0)Ἐ9$faR`aR" 35엔hPxS,ä äD4="䗔(P"~6XIS̷DOWRWR2[*)X*R:`줤त.'ct:M DDEWaH%H%%B*bܾ)Bʰ=~3I HAI **Y R#c` 2r4zk3̨ddDFE`A! e56T20T2f){CΰLgEEɈ.J㺅jZ}9NǻQ`$$sA&×dd.d%#$ $Y y[."X0@0\ދK2K2^UddDFO2@O2"z2`|I|IFKIN]Fp$ D0II=0gg8{x}w`%%#*(h*#xIIFND8d JJFP} ;IIFtOt  G48dDOBm le졀|IK!NLd@d.$@=/ӡ N2N2tzٓ ؓŞ| ))KH \OIeK fQ2`Q2"ԟq\#IɈN M'ճIqz^59Χt<;Zg34?B_pKպRs\ol|rOiۋ7_;LP%upGh\ʣuU^]Gr5R;ǫZ,F'7kx^}glQU_PG^ܬQ:o\gO]'i!o?l+ab6DCQ溺*W(N>ew'r63oN7V^ߤ}rM0Vj<ެ_e}P>8I˳aG|&SHOv1~sڠ벾6j_Zl'\ߏDls65R{ ,f7JX*?WGwλU&?)_vGMJwuwwǎ!>eOvUY)LNv Tan}x<>SK'azq'mb1˶G\ڰQc?A5~a;˴moոaż~^hS j~[SvbwBmtl>Cv=i>|io>_~gٴt2);zt}:6WFwCt Ij9L/q\˂%Q}=v12',~kOjgf]W@{M}:Zc5Op/߁;;ßbTG`kѫo^C *x[VW*"q+RTO`9k57ҳ՗ 6u6:RQ6/6{yޏ/5,Ϊt>/AgE3+^4kfm\&W"@[u+^_Et߬-0v bF mq-maEϢ_.M\7rejСz"XZO|~˻ѻzoO8}?p0Ƶf !(@x7ߏwcr{:gG}Qm Ĝ2G r8~ F@k BuxOǵibn!G}囟o{ vyAާ!Sý]z\>}^5#mF>}|Ž7AkGכ+nĨ>|E|lC͇x%ԣ],^|o/߼=jnf7|\[_}.zex:3?k0jUU90yOg*? NMm*vJ[:|%N80 '>ڑbڣATFCԮ~O6Or.jq:)xM]Yf1Z7,nVr6\<'v 2{\=yϤK݃ vw۰1tؚw'ǑeUUaŪ帺b@̥m~kjy.h_;Xr1.o˻y;y]Yi͛;n;gsLzýKR>ݎ{{P״ng7mv4jo袎b4:n(=z9yx_>Gufۺ^/?~w>O߾~W![VWs -Ss:0s e1x'}4b+m[Q~"H]E,j~o{E Xwk|nADoCP6&pGH;]=DG? :k`v"n5h6uq,C7QϢA3mh ޕ 6rɵf됄ormAm\}e & v #n6d7}ۀ1V}>h&'Q <ŷ:fÜ!>bma{;ՙCq';5se ʂgdfpxS3̵Y4gěfĭ͊|NC -Po5O/N, ,}bg|4x-Lf"Жf&Lf"fxr^~{*Px2ۗ eJCl_&ۗZh2 L5%ح>1 fC 5 kFmMcJf%\wMmzO}ZMu7,pXv#,6 [¥lbK%ry k ~;W+ᒮ;[$g ^ "yNdS N0DJ[py`'bmnlb#M *;<JԪ}7eLH 0 >ڡ`>J%Tع0!%.DjI< `y"q1põ|&4:/fKj. `]DžnJL%ADňzؗ}pYVfl#+ L(0>n|/`I$lS]v 7 4d`2IęP@}Ocf6.& DtM;y:<& Nt9MY h>$?K,5I$Qjb%N'9 7䠂MCySbI$L9Ir~8& t L6{2pc %28#jQ-:DP@(I"\ >AI>q1vmw*֔$hJ)Ƀ$Rj)Il)Id KɯcOI$C{J-V=.D(I"4he%I$}sm-$QL^|P/Ib/I$yI~mI$LCy,'I$QNc7I$nǞ汋$EDi6a" 0tD{h"E$]F_$/n` PXEk\ό! +dzȭtǝ_>,tY"T㳙d߳Kzdq^}YQ{˪K\i*ճ}Ng9G_h}>tKl~Dd]tAG(:\-n擣lzbr297:_IN:tit4^.g˺*x>Z5q=^]NGb4:Y~^<;gZ\:Q:լd2_>;Dm-Vr?L^̈́;9݇,K/wUN/QN}*8Nl\gޜnI/Qja+6x2Y׿~嶞.G$.'݊ksxHOm"?\RQjnx6^rj`s{~?uس틾\ޟ6׀I5\Ϗ+aն\9NW(v>6Ѡu'==ݝA{wO1]rUsJAp[i*w77ϔ$?hc:q|Z-jl{z_%Ǧk:?vi:<)qyi.]mjV㳺aTokVNN혎g@~h>n'͇4ϛo;'koُl:VѸN&|Gϕn:^WO>wy>67'_샑ow a̡2i|IKr*ۊwUMV?6nb9>o>wr%pQt>)??haTOC5:٬WYǟ[W>6mƺt:(yW]G qlqպ::vU q_W2w|&`ս}ئ6#vDZNaԃ1fDjq]>Yբ/VW'Ysd:ROϻq3n><:j?k"*`{ Aw.}KыKsD"y"nΦ٬-$:C䘗+IL9.ET]MQ{ F ٗh}Qs}r@wc:Y}6Ut^XnuP~|b:+MvaaOxIn5:^8hFO 즾$*XgOʏ+=M MvSa v}5 ͛v$3 3aj_nqk $HaJҎ`k!c<3 pfꛞc?a8HlH6OɛS;Zݞ&gggIz0zּ﫿%JlH}+6 f?."OgܦRj2^i muO|)Zdˇ:o8k,'`Z6M3/Fݘ'ZfM{^ۙ(G(UH[`*sO,s2ð W\5@VƊ8γZBTŇu=hjrèʕG0@+.g;wm-d3hvO,*d5)WӏeFpC脟*쀼Aю,W:èd` "ߕފ,*M0rXL.EfUoft~ryr<G]S\|wG??rvTA.;IўbW; =2n}Yi ڑ4m U`AK wA!"?D[`PJgMua_x!.+@6OO'cC` !%}e>e6C.z(#ͣ gM4K& F 3^%SDT'` ~/ q~'/cuC>'@O?{}T 5rF᏾4o΀[~TBr9HAݱ[5*$Q?a qo$T`ˁ0NIb3{Cw1F@$41F%0$};j}LQ+E%Ga4FL D&1#B%4$Dn H #.Y<Z+.HD)>c $k襅CU-nVr5`~(0 Q $6TW\\-Vk\[G˛/QTAerLމZ۽!L.:3>T ^rKއ}n5Dr¿XP5Ʌ&gש7Ki>BJlޕ؜v9蕄 nܜ8 KkxM5A{Aϵ;圣Jw<݉*bN߾zw#r>.K+܌|sTrN9 .Pm.\Pks6Nz*EWR jInN>eϛ9 TݬZ~8{֭v[-P .\HOwDC=(*P-/Z^ly TzĩaFRsU8/L-"]tEdh TVgc8@kA17ch7͟=)V1Š>-ĥξt;P8 CnPr ٣qqB]EIķ['8ㄺĊY q",Xd$gKeqh,2I"a X"X<ђ uEmXX cEkU*Aī T%ɿ$$ޒ[{K鿷$$ޒ[_%dߓ$:ƜϿ\/#=o}h!>zۘ{rΝA:_&&Cl-NP^xȝNqmdbu^oNi3';is~!S73^B:Ѥlrߞ{ϧo߽zz?}H2~s]of-gqɏLYf%jiԾ3 Tz0:}WOe|]գD==u XO^*wJ12!6qq1<n<!uv9fԝF|b 7L!,=m^I98O[v 2tC )̗e]lK]kr̚LhW+2yÌ+2yg v76 oθ1R`/v},Sx/ &t="?Q[0+eA}i^6e>n_ &_5WLUL:[CՐՐk/Nݟc{rän&$7IH1R76PR7&&xyˁG](|2j960J0#z A8FUZ?+Fqh:QfTuYH?|Jf`R>!"}3ټwu/vJஅRQz(g寬4TmѺW=!D6 7)&|XM6:Ѵ*sinG_`%0/wR|>uTCsٗlC[ٺd [!yJ:NǤRg6jV)K+PV.MFuviZ_mZfn'o@p>xQ32]WHg8 n^d9qM>{ti4`ݼOwLM4MA^TWQWx+4ϺB}E4neoo]TZ_ /&bJOiD]O%;hdDN _ mZ]RM np뜯o7V76+;AS>vUJV:>Kiy'@َ`wypl݀ڛX^Dfc1?2@/1n"e #:?v@IGIhWOx:}AH d{dv z^"BH(ښm;lL~ a(/SA5,V-EX-7Ʀ` VG߰ԧ& vk`uJ7>7)`s:80泥'E#xUA]B؝у!=, ٱ a٤;ڂMNa(i T Yi`csD@q7Mf[ cIV!<aT%? 5 0? %уlt S [ZÅTi kD)vMO~9=0-."UWàV1/o,TMSaf0::FcJpJXĮK HXLpS# #eTڷ`qV a@a#/rQCf''ʘ;<#UNF0`:舡t/#,cqL#a#au<CM. @$Dbپ*ʚL ;} 2TcNpNXRaXM $VBq^:Lg€p+O€p)'jJ+TauLCM/?*1RR#^00G%ewjl T=-@sUUXYPBS}Iۦ3WWX~PnS X6P)9Ft |a  XjjHd ቩ/=?:fx_'oWr;3:<F1v@au'8KupB8(1sX=gÎau0jgvvXjP{?+rV$Oˡ_'7_]6&JrUvU W.G-ˮJeQkG+G(L<[sEVofkqY>:Qzc\>/)Rشt^@K5z.%Y^=AV9/d[ī{r^9\>M&{ildRcE'ͮ.íno{Irml2IOx$n%\oz..5,*~Ro9IKW_RT|b?DQ k+jӧӗޛ"6ec~fQ4H0hW7ŭ6@fT50̾%nwCm'aBۥ2.E0}Z.EtV,L?, V{uu_ou^&fB!N_w _N}5P ؁:CN  Pxדӷ>}x@& jMw}8?>Z`VH 6p2,P :Ó,K'M<4mC*WQGxrCCt~oz?5>P 8Xh'A)I#ljqN! {A /g?}G LdR2Xj'E?c<엳鯯OOx C1Px*u8MFp20P :@˓?~zbO8=W=̂L fFE[&2:̓&䭚?o?3"kX:ͦw8[Aa)rH"?Sg8 ϞNPZ4BR @@= Hk`CuԡZ@C8 ((Q OO?N^_H/{zƣ@)pI!Fp2:Pd :ӓޟ~8' 86<6'=ឞ8Wt?̇{08 iuشΒz0 lu'86<(7 Ձ_X`<6{PW{ 4m'E@=o z1/~:g }V*ϧe@̷]nCc  Q 8?RuWǟ@AQt=!ͣ<<#śAN>]ճ袈Gݧq&p10(fok0(f  jvPG 5PS_ . 5y}Zp@af730.3y}Zq]hv@G 4߿{{޽=ŌHD>s vvG ;/|z;Gq<<~:qg \ cx)Tlw'~u5Eyyt"Oɰ@aqv΍l}8Vt2jʚALy3%[ <+Ik9R_ߚMT=|?)hq7lxƀt LF7 t$} wN_xU!E'6yC4eZMUZY@>*ޛ"6ec~fQ4H0hW752 Yr=UԷ 0ŬWm+{oh&(E̥owD0}էhKC Ofaa8*}r/W-^ʉuo~Kζvu= ~\mPO}X6ٓRe<`+,afx}ld}reh+[-V T/A6TX]E䚤)^̤ (\߿JNǍNdsn/níV<D/c6w$5;{Iڰ-W0P?1\. \u\ VPFDCuX9S y98;򢘜 Wuׯ?|GYu'YJiʸF+IW[}vBݠJm++qnNXZXpjyjywC)ww5޵rRP>kyky5/oț?}Rlq^(G5QQGG玗S/)6nRy97p ZEZD'' 7+?PV &r&ܬPvz{9zM'RȪVq7x.n82 mԄ]Mgc#o-⽱ nU n(fuۖ J y9Rֺ@`-]EIOxȘZݸQԤVmhMh ;A|5" rr- =f|yοI: j!#x F.enNrf/~L<qB.0^;:6諒%^L_~nt/i2~65}य%+Px꫇z+j*9ha\O.m,|Բ ֍KUo:+Kr Ϋ%2^WX^-,R|0E+c aHB.Zl,`&ڵ'R J5JV:>!`꼗Kg]A8Q8c[QpmF+VG =V%7 k*8VfnY> hή~SEe:QL(u7)1QG--f2"QXZ7Mt3-5}l?LnF0VփrYEmaX^)iWu3)GZRîB-h,_ޢ;x\Z`=lcOq~yٹ+~f݅ۨJ7B7jA'} -`dnZ"r5ܦf\ԯVGg,_a %V4nr\\GwOOFWY\ߜ qhΣ)7m~ 7TZ΅͏Rm'ד۫& }w2~rFQ+׹Ou^1Jx|&t 0Rw߄( CE\ןL$#^F=FRr0IȅܬEU1ņ [$=_N``(S&wQNx˨hm7ɕrE46؆r0n[SAb>["}rU.'c4XŤ9ݭVbF.Dɕf!̪:?"% Uu{ۅ#2٣Ԃ0I$Ӷ`~VKfwŅ92D[$LUFm(Noy&EED0YK\&Qc\z!k $* bLSM{ V-aaEVgfˠJOuy[ޙ1-S*6fSc\V0[flԟq^l=45[sePr橘-z> 4)b,bޮ:mܨr)Ʃ_Is$EeRI6}Љ:_g8:ЋT5q&XM K!G})tT"q}Z)Ä&&Fd4(ah0L`,)vgbD@? M Mhb=*h8[^0~GG[X:Ĉ`);XѦ&71@71"6H[\i&^Ɔ;_<1"ɾow0Q"k{'3ФXNʺL +K1K:Ԧ ( ϤUTQ QJj0XQ ŀ P+]&=1@=:֓˖XĈ'm`cM fbfbD8S3gw?&-WSaNkaĀĈ8fN{jbjbu&ӗX Ha$VK2Yma3<5@S>>1 1"ڈ6q?quĈf}ЎwDk\:coTdKh DӨ2 vrFbudj EĠ$$VJ2twh6#/X`Zm2c(%Ff)! LiJfj[DlpTۥ(0/b/bu#* ӇXD@UF 1` 1"lQri$9C @CHj&cUnD D&j(","V#@Q'쉀?,VaBCq`СUXjv0&b&bup-@wocX^%9^*@VT #5TD죀6Ĩ!RUta6իU11*wUF 1` 1"lhp!!F5q*lVaSU 11"qSU 1 1"_^C5z B Bj&i8YA `A?À  Vš l6/Mo̶)1=$U6-Jlb"FrT'(]LM+vc@aDČi} M냅iŞ x4fZ9pp"|fc  'eV00 ݴrvvulMV--b`ٟEaRN4_1˅˅Y.QPC;1-d'|[ůq?>‰K=>;УF=|[%Ǡ5JϖJ`  'RWhJA^N7? p"D~:`,=v@gD:81tq&δ TTNZfcz<1tt+©8F:]2pS8BlfE&0vkVL<؂N_!"++H_)Zp\E*OKz ZaN$XhMDB.IUͅ!/:0J_ўbpT3 Á 0KFE+.5OU5WVex][+`LN8 #8wKpt|Nxm((É@ڷmMݹ3ဠD5=3__Yb#`  mn7®*Zs D@>y7x7Ȼ!Hn555ȯ3c: : 'iX2dQ(i.Fp@p"zlvH\l߅IfىjɆI6j?H)ukQ :1q{SPIOdn1É`s/2o vBxuȝG0}8}8 xL@$2#āA~8n's(Ŋ1EE)BMs n.l l NfQHS`Κ :`Տz@8^11__4gǎC?Vq##dy䫝Ǟ8E)jN7@\"p sшFnU7` (#NFy""NfQZ; 11dQt8xn&q :A(0pL@u!#ͤf LϦ C8@8B:h|C8@xX|pgW˱}q:p"EROȳ{;: -޿;;-V }ĉ#Kni-&+=3>'s2=lF"q@"q"R ۞$$^LV~{ĕc1)5 8xZ-dāĉĦf:58Dlfu8;kv'7ĉ'>걅tT=' a 'N>(PiOOH|֧ĉ''mc'B:‹r32np`:`'hcA~0N((NFЍ'FYZ NqNq"v@GkSSH"Hn+SS?U=M3{jQ:#MIUC,%R.vۀuH+k۾ZHMn ㄝ7@8jY`8e[%*ѝy^X24Pʼnȯ"ց}Tؙ 1 1Nd(lm0JJQbMFq@:X-c-00c"Y;Au<x\FjaM}Sݰ Hm'ho]idhdJ#kn]9c8c# Bv}C@Bftʐ輾t5c8T *҄ض?ǒs49$-7o|Ugc,xq\j_7t}*-M{vLvz!ީ44Ah}R uru8ޖ}֕44Ad7 z& "g҈33AѦgm51LLIgE<3<3Q3-0LL63&3&8cƕc jrv##SUܘ lZ:1dXt v 2M \aa R+c,, c(Jm&} }:җ;% u.k%mQQ'*aO .Qr)BS`DD #Ho*"dDyAit t 2z4I1U nn "vzYL@D[1MYYj&bi2ȣ%%\-6z,ѻɢ%% .:5d dU'3uϭa g2^5˕ϔq%q%W֪y:od c +QCs<_ _G]ٺ)%tX6/%@ZC=qo o:S u|'m%%.NC@Eu @Hrp%%`/Sz?00Q ۼs 5&5&PcOހbC=9@ 2z̧!0F1$黟Mh'&'&8&D j30)F|tbb3يi6i;&;&cޞ22QG!nf{t2t2QG'36I A&A&d0tLtLA6H%&%&Pb&IWQV9bbk:c aaHe DDM9aa#j&0&L&L1aai1U;C "&L00AĄr &&0lƄ "&M0ai5-IbHbH9ih@l{`1`1AP4$0mLmLicp\`ԘԘ _!8&8&19Mcff 2ÚX2^ L @ DbM;i!CWn/ L@DBwZ֙`1`1A(lm0iLiLPIcޙC7& gKh BÚX2TXFSH& aaH{pĺ,&,&`1& "i y¼11A䍱7 1 1Ad51o .F @ "2ocO 0ADњߊu!0KK^͖6G%%.fx `x "ËOX%%/zس.0KKy^fu]]7Gs s "ּK0KK9]:883..ADwd70KKxx(pWޜNp %%t&qc <.Qɀ[[ Bs:q) hEݠ_0[Cdk5+h:VHѢv}p:DM  TCjpZ@ZjuT-9GCh(3Z@kuh-Z:VjXc\X)RNp%;a;;ߟzc:DRM_g:q^ڭ4X(>:u/7J0^w09N9BcG\t0N̍v#nCč$7\u0s̱昩yO'V܎22 _KF@:xeo}5 pرWzTDPI W̭-FuE!Ȏ&Z[(Cdhgmm1(EFbXc2uu:!S+MA;&XLkYv0"F] ,:]RtŊW4ۥ١y'0dK_ZZ 6ߦmJ S {6Gx8{l'q[={x'5 WXi"&ȟ &W6Z`AK1Y_m$na5IS$I2 gQq߹UΕU4{KS_݆[_x<_m\Ijx I,c7/RnWŶI5V FYs!$k]&k^ IF HKFg&#АMKK! ԧc'@nN]j-9׿dh% cHi\6“_Mp$8ѷ]4޼vȝAΎb!y6ɱޗe z"@S|#_5u5q8nT_ri+;zNf[^b<+UtD\&S [zP_zI6!?:u:.4_㫨7ǽ6ц 9u9'Lœ݁*ԥ${sk(:Nld_߄i ‚pW7wJ 9@kOR*S!Bp-g*=;[Is8|A';l(U+@`ʅy̓If%b/\F IXfX]&g3]]̵"<=q-"}NpY)݂wѾ4[A0σ66ֱ6UL;:sxEJeåL\؍{^Tf1`v!.}Hks+8TJ|Y*THʃJyu@S gwx 5QdB|`0H" Ep=WWh΃yue(g2c6MЫ+gbfw9p:,7vKAezʨLUJ+hw4ȟ6T9j(" c펑qq>4_7{BB5?G TcMC;mlWP;䒡_]?`bRG 3ix4 gX⵮:+5gW8ZP쟑^`ztE` \7\4&>t%B`]@sJmqf_]?%"ioMG@6 A֕$ag!Ej|u~O,AtW"Yq~ao7!̫@f!կq! CJf+fȝ,PE.$ߏU o E5^xJ SVTll1p?WWx BjՕ79RWWp-qy;4ނ6^]i<I PzpPQ[DvF ΃yueL2SmNTeGj!U{rȾOG7rVP"B Mx.Qe@h2쎰p:^WW8Րڄ3i*"[zvuuI GLX]];wu%h*Goe1p:(UWWs{>LnU6=(bWWLa4Aն3$YK Aw! xE9 G+釜T+TG[˩9;NjftP2j * ^LIrw߃/( چ9\Օ'%B^Aը~Ǐ>yBzuhn]]):~:39EAWWO' \jՕ35N5~ F.JU#T,M^okNf7a[ә݀|x3:uԕ^ fղ ]g 7cbubg,;e@%;VWɌ^+1`*ؑw#]9tWcPU3t9<2(+Jf^@9VWd ׊cP+Պ#.=xYtU&Ey+&1X\X]8= TJ0fb X@i9VWZ@.! F;H8NQjԂS&F(wjPk"P! ʮ&Ѹ26SbCp(GtU7EH9H}3EuZB%? Ԕ#֔P(G(ivny`Z!p4s- -to;BġU'ĢB~[?\̹أ9>Uʞ8;X;1G|'0Y+.]w0W`, =mp^͋4pD:L{b{bxOBao &Ӥ@ib~0hi9B-S[zr8*eV$]LA:af.:X`,1G%着=*#RLP3kgi Ā\w'1'1G%Ss<*v=.\ s)R`ϥR`ϥK=X L\l@υux.֐ 7?/Sl0&GiT~߻Ub|ϣwS+y=2z@1٬ZcծEYqb%NJ]ʈJT %XQKm +2x3'}*)`^byg\vt38]]t\uY]kb3˽gu %X:+oy2'J:Vv?.X65A~x5dάKxN͊lhNU%sf1L{I\Ӱg)C<mV$J D}:Ti(@&?<*ļ֌QK*xzJOGq?NF*$>BR=.pvcNSi}/6SśJ8[D+?Jw6<&X7iAؽ}y_Y4L~TcE-X#iA^-X iAZU{6c#dEy@б*؏f3ˮXgJ`cE!C<*L>+Tmh^\Ni%DOdWs< T`ksb{,bؙ1cٟ0VXhAnkT = ? ς,t Yl؄>+Jnmu8bY:tջZdr0~c1ׅ Jt $+,h(g[cYC|AY0tt#ǂ6 r0D6cɛ S{+J䱲Nڪh*˞yj9u\%NSz4ܾ/D=1w%- }֮1gyEܨ,An28a1-KxXV(ƉV:_)VYM#/%cEyV1";k57w %X?'׷S'|2_lҺϸ=ߩV(M~TXZ%f=䳴O*w]8O>kB%)bU: |YlAO$?gZbWO*yT^XShI%cjrk}dx8Ucj T@XZ9nq[hIخ Ƿð"Ut^x[9Z4L+Q2ඟx#VHa9//䵌R~NAKdҟ,+vެ[EjRу{ZS毽B^NQ^!LLpNuK.&$yx.'ne sL z-Mm{kq/\UUi5-c6T wbOHң8\VƦUU ᨢWx?TӖTo˵]TA(P92[\ƀ\˖}! 1Gfˋ?I==И# ZFC:`G4成:~8G#'11G؊FjTcTcj%RnD]pb0qr9b-iNUʹɅ6 6¶,JftR/P;v`1GPyksxJ%+=:#]qa:XWV< vcvڨX*&%ݸ uLl*aL<UZ 1 1Gj}DN=9U_11GdjQ~Ta#^JJ=-*c| |oI5᛽:8@PsD[RN[k1Gd% VP{5p0?VQ#\RXrv dK*;JUhQq #`~sjH#RGE}pYګ]4P#l`RbX|Ldde~\.d 2GenNV ` ?W@S_sK+ _uZOˑzf/'f?=U b7QqG_Y:Kq/ ~%,G-ˮ‘5#))͸%G,ItB^UHQM)NJ/[1Ք^I/[m o,BaS>fjEcvu#Z#Cy/SE}{0 +}E]0Q2 OQ"忴2_ @x)'mM-9e#Al.ȏrqC= 9{chgOKz.Ǘ(Ndk\ǃA4\E8L?|˕M loZrctSkeHPavMkxI2.d΢f/Ksū~*+;79uiϵ闦 ¿Zxݿ۸ HX:yoJ_bϥݒr1mj@K*{-%CIֺM׼Ƴy_ǹWߔO.:xV,^7[k2;4A4ӈTFfq q)ʂM?'|_|W?YGi$~[D8Ο@QKlɘ_y{3"-&Aۆ NV;f5cbt^ vדcV;m ~䇽d4J}mv*Rr)Pŷ^p>}8}FNҩ*Dnn.fY⥝Z)@݇ާ_ߟ8}ӻ 3PCRZHPN(5-E*O&*"`P}Ǐg?5q5`*`VIUSrEקoUT5`+WIUC?jz!gWh0uժN0*#_U]S֕RcCMPlUZհx9r֭ UyD 0WIU['ZEeƱc5rO?N^_ȉ{z&J  VPwO?,*BEK߀B *+f.jT+7݇BE;߀m%1[6g+UZ:"459~tM5F]875dZSgodxss`2U14֘7*|ڸP Ugh&&|R$H4FX"ҫ|j m^qrv~DIu1[`<2 l5>zvsozߝ9ӘGt2rx5ay6T>;itK|rps=lCi H'7h>k2d|:?UsLGa2nlfApr/73ii[{in'}13Q3QSyEB3!0M.b~o3[=P_KϪ- u/(Mv||sf#ۍǿb02o{kKR} 1?^صmax;J,Wr#< ^}8#R;߿r:Fq ?F,"+PtAǏrL~QqŸ<9JU{J8Fqq?k!(T9CǼrqƵc k!K[{*t6:7E͵K0F6K-qzlyhQ{~9e.Us>jo% `0RHML>;Oj@OpXSjorC1LVj>ywem|j;+U- [n6G~gTm`P7iiHl%bCtw"Y4Rڢgo޽Ûӏ?iv*3_oj m9pPT`IGswuCߎ8lӳ@Խ_N~p݇jG0%d$'|=FƧkPZ\KUS\M.<-YY0I'pW3ILS@Dдu87TZxaR$q6g=Pq8N+/߶|67 GjE6yk[ SS|8*Ch!.<+9 @l#$T!f22x @JRv}hZ0\]śyԻqůBtwq? vwP֣`2t6ȷ'Mה0ʀ06taʀ6 EKc'VKs le2 S[>(( tvʕ@75[a<|2|2K7ʀ|@BWi\EWp!mñ Fƨr l#Q;1vw^R&Szj;I2iݖ\ۺ(o}&bL*N*#R]j^afʀHPV ELTeTe$B~KF\Kfi670qTW8,,5T6ɽdlmetMm4w[ޗ;szV\Zrv*COt2W\&jn^͋#^W=m+U<&۸ڶ]`\0^00xŦVvYQ XlU'?|`n0p0{rpЕlf4ƌ]]F:_bb-d-#1k=b,,#qgWןL4}'L텪ԉ # vԿeF2`2\~[;yҋ!:`gg2 ²"aW,+!mm!eO%}.YF+ Ƿð/Zd\V`VQ2~LW*b2+4+5W"5'UQ0VK6r]u ,N*QAW/qrݛ^JD74ͤn4Ϧd3sṲcө8sp$>ĭpTu9$.1y<%dOdD_||ǟ֘D́D̟ c11:$Og)]8^ܼOwsL@O4^(aaaqpjp4cGx,mәa>҇a)߈)FQ{` c: sDվ1dSvEض>z7 =Δ[pLY[e1oR\IPgOX9-%Ǒ`F1õ!hi0 { h ٮU`v 0SSotff>̆:yucc=Ûc22(DwꊦO|#&/>oRZ}~` 3 3''dffN6{<8cd4d4'!]t}EŏQ>LsLtsX$j$jQueYa44(|:DQ܏忢DgKw:́:7Jt?c44iYX|ig8JsJ`nq̕$% 8s8syP8!s!s y\KbҙhTTnij%(/;e,|#Pdx 390J/ᇾ& ddrD$efajg=7PF(U[% 2'*{8sz궋:Yx]Ç[#M! Ҝ~X9F`bsLja`|#hKqlhQtnL{c">EsE󍂢JEGyFzIrd &ξe (|#jKq<iQf]Z߇tPP7 v4)R/goz'~E4l7o}m)9l7[>8HL@i6^V]n]#͟2a?fsf'͟0{aA&L>L1w`K=9MP1hyvh'4y o4Z4*@ߐxIR-e ?`Qs,3, ׫]R077? 7ַUGTAx9KKK]۰+S8#WsW'A^&"2wwwmyԌih|4k[pljp8ZN5(zAK;8`XRaFޖQ2Fms@msj9 f]% &0=Z=Z bh2h:Fa,0YYllJ3 3 `u2nc"0eYeYlΊks-03Y3Yl&8|,|,|{ȂDvy  xP8  Ewv<GlvW6Me"o ~~¯kٿؿw0> xxFIl 犍s-%b[m oίj{]G`llRrg9+6ʜ)TwԾRp݇;yW+W+|j)7\VwHz?ٚy^o(l#5pͷZZ+WliM`5G 7/T┎)eQec6tY %uWl vbJ++|v qof1kY8rjj V~lYyxěmYe'nAQg`W98b#ZccF 0VVl|SaPaFc' VQdũ) Šǁ>ccţc-L1'V'VlkaɰȰP@Ux,LIL=Z9<Vl[qm0VVlqϾa o}]]Azo++H8ݧ`=q] $gr2xNnF׃I_,_P&Jrt2KS$'W)ٍqּWjPKy$ǖr}A'U\WxOFًp_~W{fԟkB%C)\kģA+NGQ+%v8, gWL/>:QzeILn_ OngRJ$NFN _;|lØ|"o^V7EE/z]Gu"#UȮv(F򏢡|=9K?*M&tJEV:%}{t/<[j|e m/ɕ5S'f(kjJ6Q|7) U51EA m\җ멢=_.fn{^;p(D;4LFI}E]0Q2 OQ黔iejARND[rF(5L\mzsƲΞ͗o]>nz7HR#eHb)?wKο,Mr/5쵔0q&Yr4N_bI^ S>dYL`xl Tu(PiN!,f+R̕Eדh fO(Tk?Pj:N)I>jI#,fxκy0%yZ[7]MoHK)G'=v۬v{'{ht(2{K6`˗kt40Hy@ ^QAMKO 3Т3_r/uX\IЗkHr^K{"gO?> nL^ySh{;vsMvmWJ3:<9,BP5j>#ˣru@s[M1_}P.&>#Gx=Ԯ+]_\jkS_G<Ԝ+9DMW"u56Wpv^Wrڡ@{]}vCF>qAt^W}|(T!+Bnٞ>. l:{ܤ{95s]gR~ZPRȆ!Ej0۵O\j2וdSD/~*Pda*uE'. 5J&?'^ ŋjWykWu5̈́<8uLp]`;I~BP'L&%. 5JW 5ޑuË́[K~B l˄C5_1uSV1T"+DDMyYF\WJnCo CẲUDȕB)Jf-v kո/T%uݿ>.%U% B[R۵["axuVo,ӗ;;g%om]*~:7\j֕5ru|Dq%2p niKBuVAۺ:*a. 5pJVhES6rtn]5]'S]m.e.2n,e.Z|yCD7VpZ} @3x`Teuu7sY]\lˠJ.k&P}How4Ump\ߖA}[樾mNɊC^#]8r@=EreuEr=L%MACJX 2d,%N'eLNɡy<&9[I S0sМ& =\A!bs( ^Z G0hKNV+ V"@&ReFr)wz?}wrk[(g!t+dq.%N!wcӥ+y "c#Tm|5"sPSwa[Ssƚ˜F4pLe+DԹ)@0ab;97P/ ѫ%9ÀÈ|}Ä800"yS*1FNyr? Hk"PW=$D:z}mçS94XBȉ6 X[h{a1"-Ҫ;R !Ĉ &2?L b bλ-)Q8XԺDtO31݆d h Fdu_6bFd4lP3aaDYk[p|C.a#}Hm*vcaDUKb7:F4QGJ=ptF`Ā`ĈU9F.%' cĀcĈ #Na11" I]0 QĽvKDlZ6;2ppqACw0#e3CPX6Q61JKEĀJf- #1$1"!}'0X$ &1@:&wV0AM<͢hl|E FH01u|@AĈ &\^v,8VÈ88FDSB#/#ˁ`c``'(EYcHH'B2ic' tt{c'ҏzS8PxSG @)_YUMejtA "_F?P.-0;XcXsQ.;ґ49t%t%N+.*ݘw*q*q"TXXP垥n*fQػlaKRڠE'a/ &N1!ue}y~vۢOR'ݕܵ/ĉ8&źʯ /ͨC4q*?n_W刳""LJE:RI n̯Բ(CSMԎ:5qЛ8dUK,K2( D0%/\]0Ol:88d.30'0'N9QӜ8М8DRc s9yLJ Dwz_/I#c1ZZSJ n`ulғrlT/N.Og? ~75`āĩ&~i 2TN㇓_N{gg2ey6VQ9:b`'^v쇚@p-f8((ND5Q:`>ā8MwL> LD+ 0ܟGI{l їaI\GA4q"Sp73M&&^l KDu%o*&fRu,%s1}b0<<IQa||'ⓚH/gāĉԤ&Z(;;u#&8xȈ擩|Y(sEx~UkL6@6Dddĉ Um?0oB {F G}Ty ULnl0**ס G, \ѺM]08Dڎ1H" " "܆~Y`""#"yDh~Y`LLQ2ުmf ` "{FT!T!A qVh_8?Ąmc92-4Y`HH B DB1DwETeH!H!AD QdG-nVL@Dy^+᱓D "]RClIU+8: x|"8`mD30&4ARꦈHE(N^@}jQގx>RsHQ4oR'gGɤnXpgOCiRcE'ͮ.í$W<'JOe̛7.I|Jߥp:~Z׷fE0U5ߏ?B=ZM?'_1>)͸%G,ItB^UHQMFY{,xńVSz'Vn1㾱MY߮Y) Ս?h mha\O0̾%nwCm'ʡBSAd"N_Fai+O_l":LgAԟƓqT.u;K9nmo.0gsA~ԏiF;{7_jճw=x~7l=cA{OΓ}'3q~Sfx!hD:dZmyɉ$7KrNlDIn1g2Q~q@5r|l;N/K3bt=~g\@b6Y#btA>vSlR ] Q2j%g3 R0puVke/.cSq4NSIn(Nib4e@gKƓ/8nyn[hf.8x@BzU-MLxkuӣ bC&6GM7 3m&`>b.t0].71\غD.Mō@@LnsXt30u] I7\tv~r򫡱0_`֡|1Dס*0}H_Z{T_4El b/p-!C_U ˞2G_#mD" pRZfLZK}&0.L5$$1Hb0aZorT\)vxܭc1+"l`1Ǖ=6 1dL>5p |c"޸؆5] :p*R#Pq<6ܣb ;뭙~q{f⸎pt-L.p1[l%m[ȩΘH3&Amŀ/&ҋ}Zaz1Gj>&WrN^^m7<y}m04}NMW6}n % o8b:2JVjg1H8ueww?rrO}4L'eW$>vL/a2`eN ߅ήnophKM~9]{ *R5UմaȠ Z{j 30YJta33='y xΌs&ۧ-@ߊpjYRmtyfyfDq![(I2hVvٌY fuPiK3/c1vZPbu%c E%%VQoS~JlKd8rVRζNĮ2݂$XɜY3B&q*t:;0B3)ŀ)RU]"%1bbu`)cEňԨfRFŀQ tc @(VGdԊ O ODZ+0gW |b@|bTSgO O}:l>㽼N._yMqmV5@< @NHr:tz9{b{bTS03*go~m*2z@vbTS#[%(N NJwjO)N 0Nq"5/nsIP+LtbtbTy U^[㇓_N{ggϧOޞ t'x'F;5ri"b &F65]0QL XL cj$i0K K?=(Ur)Jق5b1*+?f?V\j1%&Q9I^Z >b@>bD,r:Lqs ӏD^ vTxFbFbT8Qd/I IJI"ɿ1B0AB161RSA[A5ibٮ؁MsE_Zn(ו.)X5v{bu'o Wn*ұTʭF \X^[iI:s~T @bD_[C E1"*n+g[)FeR RH2Zif<`#uAR HRo0P)T)FJ1@VS^#I&f\ @9y7n 3̖bbDMg/!f+go{a# {O]CvJBkQ|:Wc^#,E {0'(IQT +WT`ŀň0#0ua#hAhȕ0ZKs b@bu/Ulɕ^o~FDktS?ueHjva8H1܊݊VOoՎY YzU{T#80bT>͟2e~Ԃ]/ڻA٠fŨ-0Jzɬ{EԃcrՊ+U11''9iM$gyVHTV^w OT~A2VX ƩD5 DϜ1JJSQj T0;@q*BjVN>׿( l2qq*_z@k=N qq*>jvcTA  #8 x|Za::ɷkomf&r'H=3jI:_&aٿQ({%wqe:%hK*ޛ"6ec~fQ4H0hW752 Yr=UԷ 0•Wm+o*p(D;4LFIiIaZv7uHR:L\]F2p3[Zd={}zTQdhY/׍S r=_Av}p de8VI9Ofs]/39vw]m$[TF]ʩ6{ޏZE O⦄Vztp %܏K8@g<lgYjݸ,8%D(R\Ąd>)Ztu |'TȹtDFw`zAyjk׉r%D dGVtsޜ"Da]6N&_Kd@&#ХMOTTz| Dk!ե(-`. \!ބ(Uv,Cϣ[0p xQ(I_lnŊ 3p_:bD2 ܥJсܨPcٜ; V´I_\ \C=_KݵM\YK5Ý`)J-Rz|81]V \j!i{P jK-;-1C_QzrCKOg~9հBBS0,3r';|4SP>2 . 3FDվbv\MbFn/ԩRT o68a[|N\ s6vl&au|AK$JA<$dKw Q <]یiRB+C}a6 Cs?wHsHiU9>RA8D^0zī34ȥ.M:D-n*/]ʅ4!KZ/һ{)AZ)A){j%{# P*ւ>= )zD 5Qllzo? GLNJVQoS,HQRγPT/jZԸQSon> -XA5So:+bgYuzylfYJz֙*u7gmV;LV[6m^VyV OŒ;}zx&6zXtC7]VKxԋB]L"3zP7әíy2fl!kY|WYa'60n8[Aҋ,J?=Xʿm~]L>u(ro; in{Ubۀ핯Li#)rfpOk2@|{1V;[z5n&[ёJ? 'BCމpN\;{u6֗gnC<6 6H+ 6& L;v9\ܬn$_>(G7HdC\&wI2; ߆v往X$%˂pH;f`ס w6V1ih<زvWtmu)O$&_јz7_/gOUel>^||{ۋۋϷo/o8o/&D?E||.OjќZx-P"w{Dqjg'Âdx}$QlC/=vy& TGe{lu\/CKȺWTٹ3%P)`("xw=aO]HؒC\#?8{JD=RMI*Jzzm>/z]sTK5I飯>|;0v$%`.7Y0Py&o7V{R&":K\u.JR0(=,JM[RhKGڃ#O]Im@_u6~si!ٞw~ ")eu|审2+~ߗ,Qpag5U@a[g3Gi'e2@i@.{~S)0!hSBE7A}TZD7(ҷ:"C RP~7AEUCAqT, -e 8lmoTL ET1m} fy2Su.R_}mlvQbj.ҬJ*N^<6ivMO~9=xĢ\M6Gb;J۴>r{H%_4dgu:zGlߎ,V ZibZЊz ѡV\ihjUfT5U+UJo\kVx:{EE^~39ٕStqsDxqt*Kܦ.]\:('L>Τ [/NIg2?; n*摺uQm,X~KojEp˩gg^F t.f4qQhGKޙuP@TxEM7[]EM;MKR[Vt`P>'qȷ4hlZGI&[Tjx0I[v]O(-j~niI.tDX|j]{ڃL}b7t)m'.7ҺMlMa#于ru=0[|omGo;rt%JWǠ7sä#r?wDsM&wQ}%Ydg z֬LL#v#oF^lpH-: CPs` X$F"QAMQɆHnl0{(߬$!(!Vff1:ZE:_D&%JOLFô!!F Ȟ,3b bDdV PĈ"+-&;H@1" ÉЉODfsm/eh+UV _]^Ĉ& ,UDiO1:-l`(H-ĀPHOmNK6L,rM0Ց*u]ZQ! 1xCqZGcĈ4%7ҼTp`ĈL&kZ 0noKZۙ%1&1"1%FsݢmQJL퐃 ՙ $&(&Fd1ճĀĈ%5W*1*1"Vso)0Ĉ&.MtCkS4]2101 01*,ȴw7 Lэ4vVbTPTN'AK*1 Wb@WbTRsԣRDžVĀĈ8&#TbĈ'#bI%t&yU%0NX^_ĈD'#};U%P(WH@OHz2ҰIrG ĀĈÐC,P PH2%anp# v0QRRMLbbD>[k* Ĉd`eq D AYKS/czz'ңW:Ł:ʼn)I'58fRq`Rq"jXDTTȥ1ST |w; i$??ʼn&D2qSpS"t1ס\wY++^Gr&tŁtHWTЛ*`o h+^Īt'H*XaeŁeʼn,+88]EiUk\0+0+NYys>>ũFŁhQ39@q@:39F@q@@:I<硬O[7LQ  ʼnH(^VjexH(H(^2p[YsL@u(Dz;HQ3Ł38SOQ00SZT'w&ws̑DEs8p83EY=8QQj"k1,C7Lj))^rLoQTPTEтaS`S"ME88PTS 9XqXq"jGuS8P8bc'¬ТpUj"Ҵ\!++NDXΎr D|33808QEtNcJJ'Rj*DH!7j1YUđ]j(h0P8ZeTCiWhWH2Rl)0Z3t&D Cs׉WWHͯ"R8fbq`bq"@Kw88eDŽ,,N$d$7uŁʼn,-++ND_5;R݁;DFAYKz[[r}aaFsq@sq"yvqv:nדq1ۋۋױ5ǐ//^Z%1{``tq"|K<S8P8`&88E=pz9]8]29|sz ]]J2:uz\\T*88EQ>o 88$ #8 8EhU5L@D*Wc1ppa||gm2/ ó8x<&/Y !8cppgYUyŁyʼn̫]A‫D\U ao7HHʼn@& }8Nwr|f9DP}lŖBJ!D7ؕUJQRR*euE[r,o"%"%)' E.Q7JQr&B B:" xxuMn]`zz7u`TL&0IIMOV2 0IIMM$, .PqDOMdspDK`XX šn* akDXq=3 3 "@ h/!L La9Z+ؒ –HSqDLLfuH 0IIN+,Iش但%%A-1_aSPD@ltH$d 0IIMm!|<'<'A92$$l' F8 @8 "@~k#LLHe"Hnl •E~$$X- ]c$$A 5 ,pxD^LE@ED*i"$$AD%y\wa (jP-0HH E ,ń!!QGٌAAfL@ut ͳB%j.?iڵ-0LHLHaB ƪiiBhBH"4QoFm@:5+SSCC"hw;Whfd+k7=oRc(( B*,QkzrAfv"Dƒc"AD1_H_HBEmFBHبQ!‡Auؠ&f+J|*zqpA@u 걥b 5NLMC XڵFCfuE! t[adQE"@ ksE`u"Ӌ:@/PEm_uVԡŠ4u0Nxfq묃FuFiXj!S>Ӎ:@7PF>`QG"[6_Ix9R ;d s܌bٿQ({%wqe:%ߩ $'ӨWre7IZ~8^)K?B#O?A'u U\WxOFًp_~W{peO5J!5 oËN5'n0ŵ2u|T7E(lǬv_I;H0hW752 Yr=UԷ 0—Wm+Cp(D;4LFI}E]0w6wͥEiejARND[rF(5L\mzsƲΞ͗o]lf˸? N~ NFԓEhgbow1'u40Hy@ ^Q/0㛖kER׉tX\IЗ+HrJ gO?xɷA@YM|K Lo_Ir&GrH{d ޵*`&'ڲ7,rMzeg3I}A);םoR>^ubh8zȾ9>ʆlAv $\I3ط ӏ tA7񜛮 ry|D'* Sk4ou6^jW@Ps7q8sL'p*N<7 w nl@γuK|f GUEn% z On\ Yنy8NUYV_W7x/'pM<eN^k G3 wKs^JQ4T?e;niyzk.'џrvQ*{i[R\6ڲy M[4΅{TpKfh9 \+!##G4M\_q8 ´ŷ%)];X*jjjjjjjjjjjiӸP d_Iɕ?oo7 MOꟓڞڞڞGxHjLeOG'؆dCaU MmV)򟽛o%nj 廙dhxL% Esv"SNjRW|量g{~CrvLn(lԼ1l>.dX_iOM#iAM#5=)@ښcrAn4+j4+_iVSԜGI9zJgnO ;Ǩq`o1[tJSSLt:}WiOr*2T*Q`*%55­0jnBNߓd+ă %UUDpsס<33gfqWYQ%s2ƅ%kia)Z&b@LSCo+9Wt4NEftmεx=NƘKٮ:F7H% "<ߛYR!X')oLj(և;pC4!bj1D,csVe<]>$QǺ]3wh1˷,|MT7*2rf:[*J3~1HLX&iTdB댉@D&li78a`Y]=]MG7> ȷ[7x>ƍ% Smk:<ȽcM w{q uA,0u&e9Q UP ?6]FȉNĎc CCsWuHsU y }l٬}W C0w_4EhZ`]ə%Ǵg|A NNuF _syҼܡyD)$K,2OC0w}4}ݵ?邐/H[76.o8_g_ MuxUu\a*iD P 50n&|d Gz;M;BwJӍi`;}ΓLcCQszHC ;H#DX]0#ur{D,R>{9Iט4֏>ʽq^JC>=qؼ ݺ#or{D\U޴ߑ#=c<!y{ϣG8{ȹwt@jV#rG{<"VajGW;"zUn©-.rmܵuߚ+.`܃u5LIV:?K;x.{u'||E.]5q.ryvP_/]GW]-.rvKv5J|e7]7580Iї-5m #vc_[_5#tc"Px3F%p1W~Hk>F8w7nB %B8-nfȩN .Mt#r{cW98Zd:Ǒ[91m9Dn¸8.00b-z @ 0NTo6qc7]Aal n T_@ ccWK- iٻx{V fB<À<èeiiY6 `6ZAlkkX1r0ڰ:Me澷lm6MIZ`:+9kp<2MWȅW%X.U]\b  2oۮ%1ՆֆQ65@aTD I6KMee@aDD E5qO EzX̤aaD* mEPa+uh1ȆɆQ6te-00"ަ঎snnt 9T@hZèJ*n\t_S;W7{\̼aaT/e(2,Ngxa V1iSᅩ pvfSr`rX'6iZ1a#RpM6900"Ǧ#&|F$P\gF.9H1itW߇& sCmwiˠ)AkmbaaDjNsRF}( sCWa RQR#400"6'f00*0/,*='nv$4y̲aau4IT<À<3IkƨV1NkViieL>4Jf<À<èT"p4 4OZVaau@* lU(+*쾘}dzUa  #on* vnaD qe 5 ny517p< G Pgʛw#y8 8H1 aaDE'X m mi10 0"]R)IQ߁>(7_޽7qk?.)8}>JJGmVl*+R9޸\(8} H"[s鷧/27oίpn")t#Ǥ,rogӿo 'Rq֚kkE]mtV]n+Y/(+2Z> 7D"aY E*"h @pHwŔo|cg)Gz~ l9!>EP$D͙`ome(QU!EۯlYv]R))Hֵ 1E"u-6EUnVZniJSX]{>QN\F=*6"!V1'k^n@H׼8p-׻*JUyUԻ+JUWzW `)QؿRԿ6$sW ܕrWOg8z|:s?N/?- ҟNeߏ7kMH&g_g<&G~ɞGb0Nk?Wgdbz iY?Jb֛p8gӟ|:&3(|_|($_ɮdjmO[+IOERh~3g?N.7g.}Xyg6)Ǵ}}|$ޞvz8<|&[EIW,+*~vB_O <̓*>ʢ?? 0L랿Ͽ"-E_)~z%`|\짏[o'I]Rlu~S2c?sC[s+_}2H_~kaY5M,I& 6S/k NNjM^#NinHƃ}V?Moa;׉/fMdovO~`pXey+V+bڷŻeA^ݽ{s񃫕v&GhpL6\xvp(_CU*+p?Y=y#v=fpYw-MI3oYr3%y--+t>yZ .4%8m|? >}"x2,Fi[M8WE"};OFczWIfQzs}gsƹ,6B}9[b|^uzjww)L;L~O(΃+|;W|1K(Mܪ\r\~|ӳKFl'Mh6:+dUYvїd8 ,׊nQ!7Yqkk[>xo;>.`vePYvɆ>IE^9]:ug%j+\'Nmb@baEaIrs;E2&ΓP1▘%u= "C\w~* T8|rd4fp,(dqFaW[j ط fKiFo+)譟ƼM9Ozr d? =Ď([ W.ukwJ+g(ϲ 8^'YGɇ8饇2wL0 WJ 朕,fip&nAc`YS)ϒp'5`,lo7ýp{l|CN[f,]nao٬ug{^f .J G MևWÝln)6q$F1bP|1K~bbkֆ z)C;eKp$ŇYW}?2 Xg| +_SE2[4#X+|%l'} Y,e&BWrHӧlWW'?~KU|n ?_^^5k 4 00$ JPP?Z( P.xaoz:4}~].?7wB, dk԰PML;[aBwXXCzF}w|.%pGw;j{>Xߣu`1b!W,ٿvV!w|DY4~q,6Ť1Dc)h^mye<tv U/ bn5l&5 GÏ0ә_1>7R2b!V,(zV0Zc̱P9Dfe0Fa"KI?PP?D2*u!*UFa0W̛nrA+ e+a _XY,4k4lˆ2 e!,lGgf{` 6Y& ۄn >`iIdBYx=`ktL2d!0_C# udyW[ {aX.+e%1e7qV`~)se9dV%Tu'ڰ[5Z3b5 ֨!k$tXլMl/`"K̳FY#!* l_׌"@E8f !H3ph,fxې'e*3Qِ ,ˣϣ>{pr@`O`{  ]'ڊDԠIh`R >vĂr=wW/o԰ -5*Na,L ?'F˝UAh-*Q>pQ"-*h 3ZB$-*$hEIGY&UI~+UKB8K/*aiʼRT,kRTe/mx~KO1b)ULeg3E-M)j dj:1fZ™d^_ϒ""{?>-xZul8E@*ieyCjh#IST:uiP 7bg'gekeP*Yt4>\p3 E@Ep")U?՞Ҷh2yN_ptz䇳 !HJH5^WC D**R B%7Os r9UpLx\tN@"U ) N5W(پj߿?Bˉ"STE25ľr!xāERTe*&3H\ FyQT5;ifԓp~Q0bA1W3͝@D{E'SD,E *è܉ 6Ψ`"k-œQ(FyY6;'ɇ7ӳL &2+2o=rka_HR%)2I`L0f菧z`X)'lKQY+5æ: -ST9uە_z BEU$T;i岶sp܊ ڌXCEB{"`PP:e) 'ԽHu +PH@I ˙=Yw>ȋ*כ,\C'F@E* 8GYkUrrIl- zV]gS$$h8C,<S$ThP^͸*ZY%ڃgPK^u?;>e¢TR*R=<zTs_)uXR @`JEBT*`HF=pALg*BSݍ02A̔ MT$4C+xe},Q\Bf"8QQ%(޻SڢYBZ8o/cF*#UARB:Oٽz٤H6"QP"PІS²H6"RPżHƧ"SDTE`"S(rhYa\EUUeO"ĊbEU*VBsE&:\}ۻTT6JVTd=bE`"%:l77'g~;AvO7_ΨVU+Z>j/-}W+\aԫ6@O:tEP"!%Ē?e|tr  vEBKLB"`^P_N"x]Ҷ++b+ ͮ:,喦2튄pWh` o$xŹW$D+\ *\ NХ t)% +W8ń᥄|.Ӗ8<6g~*v/%tA4M̊/K L̊/K /vʊ.K :\m5ˊGGm␣9D4l~|Jj}ro~G?ku)E.K E.I/M Z^r7KW^ ^xbb#LSB#P黡+6G]iH~2))o)z)Ue5vwMfh9ARRKXlpKPԥPWB ȉB\C;5QWՔjܵw}'ٓʫnlz)^Jhz g ~,/%( u9J*]Pp)(\JpyB )Ȗ"[5 X}S,-%U:=A*{BLI nQ SR0LX`1wh2y1pLUc]Nzk&3UE3f;g ΙrdB&e b62cL)SB,db0`L/SB͐ d ȺKaPLSU6RXSPT &(^Z:sz8Ł&H0UE l{5Fa0-L ۙSS²&vX S”P vS ŔD-P')',| F` >`lA40[` Z`:lS0kv" 2`uZ@NSvV)x`JI6V ~)_J~: vVw)]Jwuwj4.-Deo'm!#ؐws1GAc^T3zi!%_҅HYлPt*fKCB䚁. K .ڂq (MņA/ K A.!&~pfKCBKVF̀ॅW3څ5]`]efKBk[vkf4X--d:\Iܹ} YL M40ʹ4S@wMLeҀb`?ogƿvr@׏rQpra$MIUH&)Ի'򚆼V"m\ɦa*QCa45]mwj) j j5 ؀Ԭi(jZii8jZuxpL765ir@N 9/8UYKD5sdȶDT4!*iLP,_y9^4-r} @uhd`*LHtukjOTUTuhCe2 L e,dgܼ+{޼k&R]ai]&!*F予! k'8pdZȑ (k0O/̊ibZȊ BX[t7W~CaZ | i!&8Ov{Sj0Lӯɰh40-$WK(Y?:W`.̓&ᗡ1 hLK~dήP9CUcB`<dB]jR6#]8I. K I.uem$46ޥwi%e=4Oidp6j$t']n]M"!2k>VեVW-^=yj^P2{i)y=ʗr"j,[^Z^5w-lpU'|t_&40]Em#mfVLUpLWcs s MHWTh&40-$joFxgy<c=zW/3X1-dQW>Pfcqܠ b1Cy`: ~fwvh ,t]F(tFp^e W"k4jX2Tz0ev)ag2Rg6yelgԲ>=.=?,Co2eWs: {[ޖz[}0 +YJ*Y5ʷvf;Q{=/=??;x}_xszGG'g;'``ZFi[`FaH2BH,7,] Y< F"k_ P`"ˀ2R"KpQW>\h'es},H}5̀ұ8n_r:q黡reB*.oQ 2 p|Rs~"ëNNm,=fJϾV^ox8F<,#d;' a@XFa ΉpCQpreȕfj++uCh8B2BݪF'X^?Frn\[5]jX2PP NtaFq!~~.`$h!Fn@2B˖N65{ܭ f`*ld2 1SEG'3Ɍ'kSÑ2 (3SEm5Aef`*ˬyܹ;5o9%X>+Іy3TfBߍh `4#?40YE3PьTE r6hgF u+~l(,|àF3RM:贆j0:f:%ˠ [k֚ZkPEf}NfNZWa73Rܬhà43BҬeІ=3H=3ħ*=3H3PkuW \8C;3R)rleFjWt]iI2I2,J>ތGEl~K3"2#T>70Gf!G& 47GfGXO6+3ʌ+k!9 v]fvY@~ i2Aw`PdFHu 3 Ȍ ۪3,Kf,YVnIt AT b;,`Jۦ3e/A͔f|̊ݰlo gbe.Ӛ~~Cc [@f /#d;z-h/B6 0#4>j "`M ?s0#e/1ן)PBaM/c߂cL1&11.f!. wW M V T1#T!epBpFCq"YIf%~yt6 ^^`Y'ɬP'T◽rDO}=yS~/O+.0˚ffY7?5Lj9pά90e5B׬N/`Xf`jeẑBzFݪz*s3fXs(1+4g0q1 \Vb͢FT'..ʹ5bkN]\6hnhl')<28fY)8^"]9%Rv,2+u˶HY ȬP B"8 0՜X>f>XQ"h/2imxd.̂ R.~}L齩j/Ƭc\^\x9fX{ok*ccP*fY*}ʈ"fXg,axa獥j9}A9b9/К<ԲeW˶,;b:bcV~*Maʔ]1 W ]*Mgj2 2yUv,1+t ,,.[eqJj/=  AV Z \qeXWw" Y²T’=oך YtY < -,ACv,(++W{8opsce7\kO TWV ^k5< ɳʪ*F0'D"\†cP !sb-_+7F1'DZy%>O>YPB+;t2'š|<1O_^M0dNȐɃ >A9!=&<< as0œQ@pfAxn$s Ŝ3]wL9bNH(_y}k#f9)YxgQ4< ά\^@ğsĜkqf~5HekOO9aN0hQ: 40':pl~9_Nh~3Xh8rBF)Q&ɇ7l~OӋ#K'dX^Nhy u<0L~6SsÜk*7Y6W"+1k MqZ49xcNd׶;v\1'tŶ;0'ºώl9`NhBC&`|}NNœszV,>8~}Q"U.s0Ĝ \h|0 >jd,%愖X4g8F0'Dh sœ ^aha.`,)ৗOvK̸^côlς7&2'$Bl))Fc^́sB^,l5ڬ[ƜP #b"ba4ѸM" 0y5|X_Nj}5n$_z9LO\7{ZK:ha"́sB"N~XZXsŜPk^7089)8pud"d[X#sȜP#)l?>\Iɛ.lou,ū~qiY Y7s͜P7џ13 1z:(t3̏gg6VghDa9iV߂b#4[ΙsΙjuik/pZji6YLsӜTL/%4 %# LHxdTܘ}`Wf8hNu7♃x6iǦi愦Yj=L Ue{92UeB]G`61F怑*Lx=,|4y;N| QMxzsG6d*Rq!?_Hf _AI ?6d.d:7vd d5J *ކVe9heN5( -q̖9eNȖI~-i8FP3W\Pu1}@*,Uh -Ͼ][NM? oZh$!26+4'tҺd8O:sBLt;~nE堘 v7+FsќFk񡾃̤90iNʤ=iz7XVUrn4yiۢ|7l.htL8aXsUZgoe4k߼N^QzsVLJ 0\QLܴ ca愼[)79&O3߹yAYm 7 7I%m~mNulzélsB- ¦Z,%lŬPb؅' P@-6AXuů/ B1cm1XI ^ :lu쇟qv;YoBi~3`~1m1̶Xh&.UwA[w̔[ -Rn@\53hD<9 ~ ׌wr9EZ t-k5 v COzZ!bbg< 5I2f,lKe3%w:J2f,pKK2f,sK3ACk;6be,^ wY.!BL6pdY ,g!񴰟dY ,g҇^,bh̄IY,$$c)1d1xXȓivΏ*x91ka1J ƞ1_1쯸j093JV6V3 HXTù Mḡ`b!VH?-='/`` )}ƘɯW,$9 uŀb!%:4`<~Gotޖc+ ]&|4 ݾaxBK;l< b^ _nӮW,b+ Hwֲe+ :-սۧ~1,^뿵51a1X8vahsX,d7ŝya8s_1X} yŀb!rxg7)f+ /ZUkVVSzN1ca1Xഒ.QZaBL2rU7`1PXE |Q<.R6?G` -!{3gr)a1X5 yVeB,! +BD,{LgIF~j0WEo8f:nf5=f', 0Ix'W,kW. f{rf@BOfb0^F`h8CC튅jW >-;CӖdho3[1X(o +ǧ8K]1X(uu֭V v+[Ჲ |X9=B؊Vٓ|ާ=?\-?C8G libfido2-1.3.1/fuzz/summary.txt000066400000000000000000000132241362326726700164620ustar00rootroot00000000000000Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% fuzz/wrap.c 4 0 100.00% 1 0 100.00% 7 0 100.00% openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 49 7 85.71% openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% src/assert.c 569 29 94.90% 53 1 98.11% 901 60 93.34% src/authkey.c 45 0 100.00% 5 0 100.00% 75 0 100.00% src/bio.c 422 21 95.02% 49 2 95.92% 661 25 96.22% src/blob.c 39 1 97.44% 7 0 100.00% 73 4 94.52% src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% src/cbor.c 844 31 96.33% 51 1 98.04% 1319 47 96.44% src/cred.c 532 35 93.42% 54 1 98.15% 850 55 93.53% src/credman.c 381 18 95.28% 38 0 100.00% 589 15 97.45% src/dev.c 131 22 83.21% 19 1 94.74% 183 30 83.61% src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% src/eddsa.c 54 4 92.59% 8 0 100.00% 79 2 97.47% src/err.c 108 108 0.00% 1 1 0.00% 112 112 0.00% src/es256.c 273 4 98.53% 16 0 100.00% 372 13 96.51% src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% src/hid_linux.c 166 166 0.00% 12 12 0.00% 287 287 0.00% src/info.c 148 1 99.32% 31 0 100.00% 305 0 100.00% src/io.c 113 6 94.69% 7 0 100.00% 201 13 93.53% src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% src/log.c 16 10 37.50% 3 1 66.67% 34 23 32.35% src/pin.c 250 0 100.00% 16 0 100.00% 364 0 100.00% src/reset.c 20 0 100.00% 3 0 100.00% 23 0 100.00% src/rs256.c 102 6 94.12% 8 0 100.00% 140 9 93.57% src/u2f.c 436 11 97.48% 13 0 100.00% 686 22 96.79% Files which contain no functions: src/extern.h 0 0 - 0 0 - 0 0 - src/fido.h 0 0 - 0 0 - 0 0 - src/fido/err.h 0 0 - 0 0 - 0 0 - src/fido/param.h 0 0 - 0 0 - 0 0 - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- TOTAL 4875 499 89.76% 418 28 93.30% 7644 764 90.01% libfido2-1.3.1/fuzz/uniform_random.c000066400000000000000000000033351362326726700174110ustar00rootroot00000000000000/* * Copyright (c) 2008, Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include uint32_t uniform_random(uint32_t); /* * Calculate a uniformly distributed random number less than upper_bound * avoiding "modulo bias". * * 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. */ uint32_t uniform_random(uint32_t upper_bound) { uint32_t r, min; if (upper_bound < 2) return 0; /* 2**32 % x == (2**32 - x) % x */ min = -upper_bound % upper_bound; /* * This could theoretically loop forever but each retry has * p > 0.5 (worst case, usually far better) of selecting a * number inside the range we need, so it should rarely need * to re-roll. */ for (;;) { r = (uint32_t)random(); if (r >= min) break; } return r % upper_bound; } libfido2-1.3.1/fuzz/wrap.c000066400000000000000000000126051362326726700153430ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include "mutator_aux.h" /* * Build wrappers around functions of interest, and have them fail * in a pseudo-random manner. */ #define WRAP(type, name, args, retval, param, prob) \ extern type __wrap_##name args; \ extern type __real_##name args; \ type __wrap_##name args { \ if (uniform_random(400) < (prob)) { \ return (retval); \ } \ \ return (__real_##name param); \ } WRAP(void *, malloc, (size_t size), NULL, (size), 1 ) WRAP(void *, calloc, (size_t nmemb, size_t size), NULL, (nmemb, size), 1 ) WRAP(char *, strdup, (const char *s), NULL, (s), 1 ) WRAP(EVP_CIPHER_CTX *, EVP_CIPHER_CTX_new, (void), NULL, (), 1 ) WRAP(int, EVP_EncryptInit_ex, (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, const unsigned char *key, const unsigned char *iv), 0, (ctx, type, impl, key, iv), 1 ) WRAP(int, EVP_CIPHER_CTX_set_padding, (EVP_CIPHER_CTX *x, int padding), 0, (x, padding), 1 ) WRAP(int, EVP_EncryptUpdate, (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), 0, (ctx, out, outl, in, inl), 1 ) WRAP(int, EVP_DecryptInit_ex, (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, const unsigned char *key, const unsigned char *iv), 0, (ctx, type, impl, key, iv), 1 ) WRAP(int, EVP_DecryptUpdate, (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), 0, (ctx, out, outl, in, inl), 1 ) WRAP(int, SHA256_Init, (SHA256_CTX *c), 0, (c), 1 ) WRAP(int, SHA256_Update, (SHA256_CTX *c, const void *data, size_t len), 0, (c, data, len), 1 ) WRAP(int, SHA256_Final, (unsigned char *md, SHA256_CTX *c), 0, (md, c), 1 ) WRAP(RSA *, EVP_PKEY_get0_RSA, (EVP_PKEY *pkey), NULL, (pkey), 1 ) WRAP(EVP_MD_CTX *, EVP_MD_CTX_new, (void), NULL, (), 1 ) WRAP(int, EVP_DigestVerifyInit, (EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey), 0, (ctx, pctx, type, e, pkey), 1 ) WRAP(BIGNUM *, BN_bin2bn, (const unsigned char *s, int len, BIGNUM *ret), NULL, (s, len, ret), 1 ) WRAP(BIGNUM *, BN_CTX_get, (BN_CTX *ctx), NULL, (ctx), 1 ) WRAP(BN_CTX *, BN_CTX_new, (void), NULL, (), 1 ) WRAP(BIGNUM *, BN_new, (void), NULL, (), 1 ) WRAP(int, RSA_set0_key, (RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d), 0, (r, n, e, d), 1 ) WRAP(EC_KEY *, EC_KEY_new_by_curve_name, (int nid), NULL, (nid), 1 ) WRAP(const EC_GROUP *, EC_KEY_get0_group, (const EC_KEY *key), NULL, (key), 1 ) WRAP(EC_POINT *, EC_POINT_new, (const EC_GROUP *group), NULL, (group), 1 ) WRAP(EVP_PKEY *, EVP_PKEY_new, (void), NULL, (), 1 ) WRAP(int, EVP_PKEY_assign, (EVP_PKEY *pkey, int type, void *key), 0, (pkey, type, key), 1 ) WRAP(EVP_PKEY *, EVP_PKEY_new_raw_public_key, (int type, ENGINE *e, const unsigned char *key, size_t keylen), NULL, (type, e, key, keylen), 1 ) WRAP(EVP_PKEY_CTX *, EVP_PKEY_CTX_new, (EVP_PKEY *pkey, ENGINE *e), NULL, (pkey, e), 1 ) WRAP(int, EVP_PKEY_derive_init, (EVP_PKEY_CTX *ctx), 0, (ctx), 1 ) WRAP(int, EVP_PKEY_derive_set_peer, (EVP_PKEY_CTX *ctx, EVP_PKEY *peer), 0, (ctx, peer), 1 ) WRAP(const EVP_MD *, EVP_sha256, (void), NULL, (), 1 ) WRAP(unsigned char *, HMAC, (const EVP_MD *evp_md, const void *key, int key_len, const unsigned char *d, int n, unsigned char *md, unsigned int *md_len), NULL, (evp_md, key, key_len, d, n, md, md_len), 1 ) WRAP(HMAC_CTX *, HMAC_CTX_new, (void), NULL, (), 1 ) WRAP(int, HMAC_Init_ex, (HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl), 0, (ctx, key, key_len, md, impl), 1 ) WRAP(int, HMAC_Update, (HMAC_CTX *ctx, const unsigned char *data, int len), 0, (ctx, data, len), 1 ) WRAP(int, HMAC_Final, (HMAC_CTX *ctx, unsigned char *md, unsigned int *len), 0, (ctx, md, len), 1 ) WRAP(unsigned char *, SHA256, (const unsigned char *d, size_t n, unsigned char *md), NULL, (d, n, md), 1 ) WRAP(cbor_item_t *, cbor_build_string, (const char *val), NULL, (val), 1 ) WRAP(cbor_item_t *, cbor_build_bytestring, (cbor_data handle, size_t length), NULL, (handle, length), 1 ) WRAP(cbor_item_t *, cbor_load, (cbor_data source, size_t source_size, struct cbor_load_result *result), NULL, (source, source_size, result), 1 ) WRAP(cbor_item_t *, cbor_build_uint8, (uint8_t value), NULL, (value), 1 ) WRAP(struct cbor_pair *, cbor_map_handle, (const cbor_item_t *item), NULL, (item), 1 ) WRAP(cbor_item_t **, cbor_array_handle, (const cbor_item_t *item), NULL, (item), 1 ) WRAP(bool, cbor_map_add, (cbor_item_t *item, struct cbor_pair pair), false, (item, pair), 1 ) WRAP(cbor_item_t *, cbor_new_definite_map, (size_t size), NULL, (size), 1 ) WRAP(size_t, cbor_serialize_alloc, (const cbor_item_t *item, cbor_mutable_data *buffer, size_t *buffer_size), 0, (item, buffer, buffer_size), 1 ) WRAP(int, fido_tx, (fido_dev_t *d, uint8_t cmd, const void *buf, size_t count), -1, (d, cmd, buf, count), 1 ) WRAP(int, usleep, (unsigned int usec), -1, (usec), 1 ) libfido2-1.3.1/fuzz/wrapped.sym000066400000000000000000000013021362326726700164120ustar00rootroot00000000000000BN_bin2bn BN_CTX_get BN_CTX_new BN_new calloc cbor_array_handle cbor_build_bytestring cbor_build_string cbor_build_uint8 cbor_load cbor_map_add cbor_map_handle cbor_new_definite_map cbor_serialize_alloc EC_KEY_get0_group EC_KEY_new_by_curve_name EC_POINT_new EVP_CIPHER_CTX_new EVP_CIPHER_CTX_set_padding EVP_DecryptInit_ex EVP_DecryptUpdate EVP_DigestVerifyInit EVP_EncryptInit_ex EVP_EncryptUpdate EVP_MD_CTX_new EVP_PKEY_assign EVP_PKEY_CTX_new EVP_PKEY_derive_init EVP_PKEY_derive_set_peer EVP_PKEY_get0_RSA EVP_PKEY_new EVP_PKEY_new_raw_public_key EVP_sha256 fido_tx HMAC HMAC_CTX_new HMAC_Final HMAC_Init_ex HMAC_Update malloc RSA_set0_key SHA256 SHA256_Final SHA256_Init SHA256_Update strdup usleep libfido2-1.3.1/man/000077500000000000000000000000001362326726700137775ustar00rootroot00000000000000libfido2-1.3.1/man/CMakeLists.txt000066400000000000000000000254151362326726700165460ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. find_program(MANDOC_PATH mandoc) message(STATUS "MANDOC_PATH: ${MANDOC_PATH}") if(CMAKE_SYSTEM_NAME STREQUAL "Linux") find_program(GZIP_PATH gzip) message(STATUS "GZIP_PATH: ${GZIP_PATH}") endif() list(APPEND MAN_SOURCES eddsa_pk_new.3 es256_pk_new.3 fido2-assert.1 fido2-cred.1 fido2-token.1 fido_init.3 fido_assert_new.3 fido_assert_allow_cred.3 fido_assert_set_authdata.3 fido_assert_verify.3 fido_bio_dev_get_info.3 fido_bio_enroll_new.3 fido_bio_info_new.3 fido_bio_template.3 fido_cbor_info_new.3 fido_cred_new.3 fido_cred_exclude.3 fido_credman_metadata_new.3 fido_cred_set_authdata.3 fido_cred_verify.3 fido_dev_get_assert.3 fido_dev_info_manifest.3 fido_dev_make_cred.3 fido_dev_open.3 fido_dev_set_io_functions.3 fido_dev_set_pin.3 fido_strerr.3 rs256_pk_new.3 ) list(APPEND MAN_ALIAS eddsa_pk_new eddsa_pk_free eddsa_pk_new eddsa_pk_from_ptr eddsa_pk_new eddsa_pk_to_EVP_PKEY es256_pk_new es256_pk_free es256_pk_new es256_pk_from_EC_KEY es256_pk_new es256_pk_from_ptr es256_pk_new es256_pk_to_EVP_PKEY fido_assert_new fido_assert_authdata_len fido_assert_new fido_assert_authdata_ptr fido_assert_new fido_assert_clientdata_hash_len fido_assert_new fido_assert_clientdata_hash_ptr fido_assert_new fido_assert_count fido_assert_new fido_assert_free fido_assert_new fido_assert_hmac_secret_len fido_assert_new fido_assert_hmac_secret_ptr fido_assert_new fido_assert_sigcount fido_assert_new fido_assert_sig_len fido_assert_new fido_assert_sig_ptr fido_assert_new fido_assert_user_display_name fido_assert_new fido_assert_user_icon fido_assert_new fido_assert_user_id_len fido_assert_new fido_assert_user_id_ptr fido_assert_new fido_assert_user_name fido_assert_set_authdata fido_assert_set_clientdata_hash fido_assert_set_authdata fido_assert_set_count fido_assert_set_authdata fido_assert_set_extensions fido_assert_set_authdata fido_assert_set_hmac_salt fido_assert_set_authdata fido_assert_set_rp fido_assert_set_authdata fido_assert_set_sig fido_assert_set_authdata fido_assert_set_up fido_assert_set_authdata fido_assert_set_uv fido_bio_dev_get_info fido_bio_dev_enroll_begin fido_bio_dev_get_info fido_bio_dev_enroll_cancel fido_bio_dev_get_info fido_bio_dev_enroll_continue fido_bio_dev_get_info fido_bio_dev_enroll_remove fido_bio_dev_get_info fido_bio_dev_get_template_array fido_bio_dev_get_info fido_bio_dev_set_template_name fido_bio_enroll_new fido_bio_enroll_free fido_bio_enroll_new fido_bio_enroll_last_status fido_bio_enroll_new fido_bio_enroll_remaining_samples fido_bio_info_new fido_bio_info_free fido_bio_info_new fido_bio_info_max_samples fido_bio_info_new fido_bio_info_type fido_bio_template fido_bio_template_array_count fido_bio_template fido_bio_template_array_free fido_bio_template fido_bio_template_array_new fido_bio_template fido_bio_template_free fido_bio_template fido_bio_template_id_len fido_bio_template fido_bio_template_id_ptr fido_bio_template fido_bio_template_name fido_bio_template fido_bio_template_new fido_bio_template fido_bio_template_set_id fido_bio_template fido_bio_template_set_name fido_cbor_info_new fido_cbor_info_aaguid_len fido_cbor_info_new fido_cbor_info_aaguid_ptr fido_cbor_info_new fido_cbor_info_extensions_len fido_cbor_info_new fido_cbor_info_extensions_ptr fido_cbor_info_new fido_cbor_info_free fido_cbor_info_new fido_cbor_info_maxmsgsiz fido_cbor_info_new fido_cbor_info_options_len fido_cbor_info_new fido_cbor_info_options_name_ptr fido_cbor_info_new fido_cbor_info_options_value_ptr fido_cbor_info_new fido_cbor_info_protocols_len fido_cbor_info_new fido_cbor_info_protocols_ptr fido_cbor_info_new fido_cbor_info_versions_len fido_cbor_info_new fido_cbor_info_versions_ptr fido_cbor_info_new fido_dev_get_cbor_info fido_cred_new fido_cred_authdata_len fido_cred_new fido_cred_authdata_ptr fido_cred_new fido_cred_clientdata_hash_len fido_cred_new fido_cred_clientdata_hash_ptr fido_cred_new fido_cred_fmt fido_cred_new fido_cred_free fido_cred_new fido_cred_id_len fido_cred_new fido_cred_id_ptr fido_cred_new fido_cred_pubkey_len fido_cred_new fido_cred_pubkey_ptr fido_cred_new fido_cred_sig_len fido_cred_new fido_cred_sig_ptr fido_cred_new fido_cred_x5c_len fido_cred_new fido_cred_x5c_ptr fido_credman_metadata_new fido_credman_del_dev_rk fido_credman_metadata_new fido_credman_get_dev_metadata fido_credman_metadata_new fido_credman_get_dev_rk fido_credman_metadata_new fido_credman_get_dev_rp fido_credman_metadata_new fido_credman_metadata_free fido_credman_metadata_new fido_credman_rk fido_credman_metadata_new fido_credman_rk_count fido_credman_metadata_new fido_credman_rk_existing fido_credman_metadata_new fido_credman_rk_free fido_credman_metadata_new fido_credman_rk_new fido_credman_metadata_new fido_credman_rk_remaining fido_credman_metadata_new fido_credman_rp_count fido_credman_metadata_new fido_credman_rp_free fido_credman_metadata_new fido_credman_rp_id fido_credman_metadata_new fido_credman_rp_id_hash_len fido_credman_metadata_new fido_credman_rp_id_hash_ptr fido_credman_metadata_new fido_credman_rp_name fido_credman_metadata_new fido_credman_rp_new fido_cred_set_authdata fido_cred_set_authdata_raw fido_cred_set_authdata fido_cred_set_clientdata_hash fido_cred_set_authdata fido_cred_set_extensions fido_cred_set_authdata fido_cred_set_fmt fido_cred_set_authdata fido_cred_set_rk fido_cred_set_authdata fido_cred_set_rp fido_cred_set_authdata fido_cred_set_sig fido_cred_set_authdata fido_cred_set_type fido_cred_set_authdata fido_cred_set_user fido_cred_set_authdata fido_cred_set_uv fido_cred_set_authdata fido_cred_set_x509 fido_dev_info_manifest fido_dev_info_free fido_dev_info_manifest fido_dev_info_manufacturer_string fido_dev_info_manifest fido_dev_info_new fido_dev_info_manifest fido_dev_info_path fido_dev_info_manifest fido_dev_info_product fido_dev_info_manifest fido_dev_info_product_string fido_dev_info_manifest fido_dev_info_ptr fido_dev_info_manifest fido_dev_info_vendor fido_dev_open fido_dev_build fido_dev_open fido_dev_cancel fido_dev_open fido_dev_close fido_dev_open fido_dev_flags fido_dev_open fido_dev_force_fido2 fido_dev_open fido_dev_force_u2f fido_dev_open fido_dev_free fido_dev_open fido_dev_is_fido2 fido_dev_open fido_dev_major fido_dev_open fido_dev_minor fido_dev_open fido_dev_new fido_dev_open fido_dev_protocol fido_dev_set_pin fido_dev_get_retry_count fido_dev_set_pin fido_dev_reset rs256_pk_new rs256_pk_free rs256_pk_new rs256_pk_from_ptr rs256_pk_new rs256_pk_from_RSA rs256_pk_new rs256_pk_to_EVP_PKEY ) list(LENGTH MAN_ALIAS MAN_ALIAS_LEN) math(EXPR MAN_ALIAS_MAX "${MAN_ALIAS_LEN} - 2") # man_copy foreach(f ${MAN_SOURCES}) add_custom_command(OUTPUT ${f} COMMAND cp -f ${CMAKE_SOURCE_DIR}/man/${f} . DEPENDS ${f}) list(APPEND COPY_FILES ${f}) endforeach() # man_lint foreach(f ${MAN_SOURCES}) add_custom_command(OUTPUT ${f}.lint COMMAND mandoc -T lint -W warning ${f} > ${f}.lint DEPENDS ${f}) list(APPEND LINT_FILES ${f}.lint) endforeach() # man_html foreach(f ${MAN_SOURCES}) string(REGEX REPLACE ".[13]" "" g ${f}) add_custom_command(OUTPUT ${g}.html COMMAND mandoc -T html -O man="%N.html",style=style.css -I os="Yubico AB" ${f} > ${g}.html DEPENDS ${f}) list(APPEND HTML_FILES ${g}.html) endforeach() # man_html_partial foreach(f ${MAN_SOURCES}) string(REGEX REPLACE ".[13]" "" g ${f}) add_custom_command(OUTPUT ${g}.partial COMMAND cat ${CMAKE_SOURCE_DIR}/man/dyc.css > ${g}.partial COMMAND mandoc -T html -O man="%N.html",fragment ${f} >> ${g}.partial DEPENDS ${f}) list(APPEND HTML_PARTIAL_FILES ${g}.partial) endforeach() # man_gzip foreach(f ${MAN_SOURCES}) add_custom_command(OUTPUT ${f}.gz COMMAND gzip -c ${f} > ${f}.gz DEPENDS ${f}) list(APPEND GZ_FILES ${f}.gz) endforeach() macro(define_symlink_target NAME EXT) foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${i} SRC) list(GET MAN_ALIAS ${j} DST) add_custom_command(OUTPUT ${DST}.${EXT} COMMAND ln -sf ${SRC}.${EXT} ${DST}.${EXT}) list(APPEND ${NAME}_LINK_FILES ${DST}.${EXT}) endforeach() add_custom_target(${NAME} DEPENDS ${${NAME}_LINK_FILES}) endmacro() add_custom_target(man_copy DEPENDS ${COPY_FILES}) add_custom_target(man_lint DEPENDS ${LINT_FILES}) add_custom_target(man_html DEPENDS ${HTML_FILES}) add_custom_target(man_html_partial DEPENDS ${HTML_PARTIAL_FILES}) add_custom_target(man_gzip DEPENDS ${GZ_FILES}) define_symlink_target(man_symlink 3) define_symlink_target(man_symlink_html html) define_symlink_target(man_symlink_html_partial partial) define_symlink_target(man_symlink_gzip 3.gz) add_dependencies(man_symlink man_copy) add_dependencies(man_lint man_symlink) add_dependencies(man_html man_lint) add_dependencies(man_symlink_html man_html) add_dependencies(man_html_partial man_lint) add_dependencies(man_symlink_html_partial man_html_partial) add_custom_target(man ALL) if(MANDOC_PATH) add_dependencies(man man_symlink_html) add_dependencies(man_gzip man_lint) install(FILES ${CMAKE_SOURCE_DIR}/man/style.css DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/libfido2) foreach(f ${MAN_SOURCES}) string(REGEX REPLACE ".[13]" "" f ${f}) install(FILES ${CMAKE_BINARY_DIR}/man/${f}.html DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/libfido2) endforeach() foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${j} DST) install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.html DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/libfido2) endforeach() endif() if(GZIP_PATH) add_dependencies(man_gzip man_copy) add_dependencies(man_symlink_gzip man_gzip) add_dependencies(man man_symlink_gzip) foreach(f ${MAN_SOURCES}) if (${f} MATCHES ".1$") install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man1") elseif(${f} MATCHES ".3$") install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man3") endif() endforeach() foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${j} DST) install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3.gz DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man3) endforeach() elseif(NOT MSVC) add_dependencies(man man_symlink) foreach(f ${MAN_SOURCES}) if (${f} MATCHES ".1$") install(FILES ${CMAKE_BINARY_DIR}/man/${f} DESTINATION "${CMAKE_INSTALL_PREFIX}/man/man1") elseif(${f} MATCHES ".3$") install(FILES ${CMAKE_BINARY_DIR}/man/${f} DESTINATION "${CMAKE_INSTALL_PREFIX}/man/man3") endif() endforeach() foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${j} DST) install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3 DESTINATION ${CMAKE_INSTALL_PREFIX}/man/man3) endforeach() endif() libfido2-1.3.1/man/NOTES000066400000000000000000000002431362326726700146110ustar00rootroot00000000000000To generate .partial files for https://developers.yubico.com/: $ make -C build man_symlink_html_partial $ (cd build/man && pax -p p -r -w *.partial /tmp/partial) libfido2-1.3.1/man/dyc.css000066400000000000000000000011151362326726700152660ustar00rootroot00000000000000 libfido2-1.3.1/man/eddsa_pk_new.3000066400000000000000000000044351362326726700165140ustar00rootroot00000000000000.\" Copyright (c) 2019 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 15 2019 $ .Dt EDDSA_PK_NEW 3 .Os .Sh NAME .Nm eddsa_pk_new , .Nm eddsa_pk_free , .Nm eddsa_pk_from_EVP_PKEY , .Nm eddsa_pk_from_ptr , .Nm eddsa_pk_to_EVP_PKEY .Nd FIDO 2 COSE EDDSA API .Sh SYNOPSIS .In openssl/evp.h .In fido/eddsa.h .Ft eddsa_pk_t * .Fn eddsa_pk_new "void" .Ft void .Fn eddsa_pk_free "eddsa_pk_t **pkp" .Ft int .Fn eddsa_pk_from_EVP_PKEY "eddsa_pk_t *pk" "const EVP_PKEY *pkey" .Ft int .Fn eddsa_pk_from_ptr "eddsa_pk_t *pk" "const void *ptr" "size_t len" .Ft EVP_PKEY * .Fn eddsa_pk_to_EVP_PKEY "const eddsa_pk_t *pk" .Sh DESCRIPTION EDDSA is the name given in the CBOR Object Signing and Encryption (COSE) RFC to EDDSA over Curve25519 with SHA-512. The COSE EDDSA API of .Em libfido2 is an auxiliary API with routines to convert between the different EDDSA public key types used in .Em libfido2 and .Em OpenSSL . .Pp In .Em libfido2 , EDDSA public keys are abstracted by the .Vt eddsa_pk_t type. .Pp The .Fn eddsa_pk_new function returns a pointer to a newly allocated, empty .Vt eddsa_pk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn eddsa_pk_free function releases the memory backing .Fa *pkp , where .Fa *pkp must have been previously allocated by .Fn eddsa_pk_new . On return, .Fa *pkp is set to NULL. Either .Fa pkp or .Fa *pkp may be NULL, in which case .Fn eddsa_pk_free is a NOP. .Pp The .Fn eddsa_pk_from_EVP_PKEY function fills .Fa pk with the contents of .Fa pkey . No references to .Fa pkey are kept. .Pp The .Fn eddsa_pk_from_ptr function fills .Fa pk with the contents of .Fa ptr , where .Fa ptr points to .Fa len bytes. No references to .Fa ptr are kept. .Pp The .Fn eddsa_pk_to_EVP_PKEY function converts .Fa pk to a newly allocated .Fa EVP_PKEY type with a reference count of 1. No internal references to the returned pointer are kept. If an error occurs, .Fn eddsa_pk_to_EVP_PKEY returns NULL. .Sh RETURN VALUES The .Fn eddsa_pk_from_EC_KEY and .Fn eddsa_pk_from_ptr functions return .Dv FIDO_OK on success. On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr es256_pk_new 3 , .Xr fido_assert_verify 3 , .Xr fido_cred_pubkey_ptr 3 , .Xr rs256_pk_new 3 libfido2-1.3.1/man/es256_pk_new.3000066400000000000000000000044111362326726700162720ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 24 2018 $ .Dt ES256_PK_NEW 3 .Os .Sh NAME .Nm es256_pk_new , .Nm es256_pk_free , .Nm es256_pk_from_EC_KEY , .Nm es256_pk_from_ptr , .Nm es256_pk_to_EVP_PKEY .Nd FIDO 2 COSE ES256 API .Sh SYNOPSIS .In openssl/ec.h .In fido/es256.h .Ft es256_pk_t * .Fn es256_pk_new "void" .Ft void .Fn es256_pk_free "es256_pk_t **pkp" .Ft int .Fn es256_pk_from_EC_KEY "es256_pk_t *pk" "const EC_KEY *ec" .Ft int .Fn es256_pk_from_ptr "es256_pk_t *pk" "const void *ptr" "size_t len" .Ft EVP_PKEY * .Fn es256_pk_to_EVP_PKEY "const es256_pk_t *pk" .Sh DESCRIPTION ES256 is the name given in the CBOR Object Signing and Encryption (COSE) RFC to ECDSA over P-256 with SHA-256. The COSE ES256 API of .Em libfido2 is an auxiliary API with routines to convert between the different ECDSA public key types used in .Em libfido2 and .Em OpenSSL . .Pp In .Em libfido2 , ES256 public keys are abstracted by the .Vt es256_pk_t type. .Pp The .Fn es256_pk_new function returns a pointer to a newly allocated, empty .Vt es256_pk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn es256_pk_free function releases the memory backing .Fa *pkp , where .Fa *pkp must have been previously allocated by .Fn es256_pk_new . On return, .Fa *pkp is set to NULL. Either .Fa pkp or .Fa *pkp may be NULL, in which case .Fn es256_pk_free is a NOP. .Pp The .Fn es256_pk_from_EC_KEY function fills .Fa pk with the contents of .Fa ec . No references to .Fa ec are kept. .Pp The .Fn es256_pk_from_ptr function fills .Fa pk with the contents of .Fa ptr , where .Fa ptr points to .Fa len bytes. No references to .Fa ptr are kept. .Pp The .Fn es256_pk_to_EVP_PKEY function converts .Fa pk to a newly allocated .Fa EVP_PKEY type with a reference count of 1. No internal references to the returned pointer are kept. If an error occurs, .Fn es256_pk_to_EVP_PKEY returns NULL. .Sh RETURN VALUES The .Fn es256_pk_from_EC_KEY and .Fn es256_pk_from_ptr functions return .Dv FIDO_OK on success. On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr eddsa_pk_new 3 , .Xr fido_assert_verify 3 , .Xr fido_cred_pubkey_ptr 3 , .Xr rs256_pk_new 3 libfido2-1.3.1/man/fido2-assert.1000066400000000000000000000105371362326726700163710ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: November 5 2019 $ .Dt FIDO2-ASSERT 1 .Os .Sh NAME .Nm fido2-assert .Nd get/verify a FIDO 2 assertion .Sh SYNOPSIS .Nm .Fl G .Op Fl dhpruv .Op Fl i Ar input_file .Op Fl o Ar output_file .Ar device .Nm .Fl V .Op Fl dhpv .Op Fl i Ar input_file .Ar key_file .Op Ar type .Sh DESCRIPTION .Nm gets or verifies a FIDO 2 assertion. .Pp The input of .Nm is defined by the parameters of the assertion to be obtained/verified. See the .Sx INPUT FORMAT section for details. .Pp The output of .Nm is defined by the result of the selected operation. See the .Sx OUTPUT FORMAT section for details. .Pp If an assertion is successfully obtained or verified, .Nm exits 0. Otherwise, .Nm exits 1. .Pp The options are as follows: .Bl -tag -width Ds .It Fl G Tells .Nm to obtain a new assertion from .Ar device . .It Fl V Tells .Nm to verify an assertion using the PEM-encoded public key in .Ar key_file of type .Ar type , where .Ar type may be .Em es256 (denoting ECDSA over NIST P-256 with SHA-256), .Em rs256 (denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or .Em eddsa (denoting EDDSA over Curve25519 with SHA-512). If .Ar type is not specified, .Em es256 is assumed. .It Fl h If obtaining an assertion, enable the FIDO2 hmac-secret extension. If verifying an assertion, check whether the extension data bit was signed by the authenticator. .It Fl d Causes .Nm to emit debugging output on .Em stderr . .It Fl i Ar input_file Tells .Nm to read the parameters of the assertion from .Ar input_file instead of .Em stdin . .It Fl o Ar output_file Tells .Nm to write output on .Ar output_file instead of .Em stdout . .It Fl p If obtaining an assertion, request user presence. If verifying an assertion, check whether the user presence bit was signed by the authenticator. .It Fl r Obtain an assertion using a resident credential. If .Fl r is specified, .Nm will not expect a credential id in its input, and may output multiple assertions. .It Fl u Obtain an assertion using U2F. By default, .Nm will use FIDO2 if supported by the authenticator, and fallback to U2F otherwise. .It Fl v If obtaining an assertion, prompt the user for a PIN and request user verification from the authenticator. If a .Em tty is available, .Nm will use it to obtain the PIN. Otherwise, .Em stdin is used. If verifying an assertion, check whether the user verification bit was signed by the authenticator. .El .Sh INPUT FORMAT The input of .Nm consists of base64 blobs and UTF-8 strings separated by newline characters ('\\n'). .Pp When obtaining an assertion, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It credential id, if credential not resident (base64 blob); .It hmac salt, if the FIDO2 hmac-secret extension is enabled (base64 blob); .El .Pp When verifying an assertion, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It authenticator data (base64 blob); .It assertion signature (base64 blob); .El .Pp UTF-8 strings passed to .Nm must not contain embedded newline or NUL characters. .Sh OUTPUT FORMAT The output of .Nm consists of base64 blobs and UTF-8 strings separated by newline characters ('\\n'). .Pp For each generated assertion, .Nm outputs: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It authenticator data (base64 blob); .It assertion signature (base64 blob); .It user id, if credential resident (base64 blob); .It hmac secret, if the FIDO2 hmac-secret extension is enabled (base64 blob); .El .Pp When verifying an assertion, .Nm produces no output. .Sh EXAMPLES Assuming .Pa cred contains a .Em es256 credential created according to the steps outlined in .Xr fido2-cred 1 , obtain an assertion from an authenticator at .Pa /dev/hidraw5 and verify it: .Pp .Dl $ echo assertion challenge | openssl sha256 -binary | base64 > assert_param .Dl $ echo relying party >> assert_param .Dl $ head -1 cred >> assert_param .Dl $ tail -n +2 cred > pubkey .Dl $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey es256 .Sh SEE ALSO .Xr fido2-cred 1 , .Xr fido2-token 1 libfido2-1.3.1/man/fido2-cred.1000066400000000000000000000107071362326726700160040ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: November 5 2019 $ .Dt FIDO2-CRED 1 .Os .Sh NAME .Nm fido2-cred .Nd make/verify a FIDO 2 credential .Sh SYNOPSIS .Nm .Fl M .Op Fl dhqruv .Op Fl i Ar input_file .Op Fl o Ar output_file .Ar device .Op Ar type .Nm .Fl V .Op Fl dhv .Op Fl i Ar input_file .Op Fl o Ar output_file .Op Ar type .Sh DESCRIPTION .Nm makes or verifies a FIDO 2 credential. .Pp A credential .Ar type may be .Em es256 (denoting ECDSA over NIST P-256 with SHA-256), .Em rs256 (denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or .Em eddsa (denoting EDDSA over Curve25519 with SHA-512). If .Ar type is not specified, .Em es256 is assumed. .Pp When making a credential, the authenticator may require the user to authenticate with a PIN. If the .Fl q option is not specified, .Nm will prompt the user for the PIN. If a .Em tty is available, .Nm will use it to obtain the PIN. Otherwise, .Em stdin is used. .Pp The input of .Nm is defined by the parameters of the credential to be made/verified. See the .Sx INPUT FORMAT section for details. .Pp The output of .Nm is defined by the result of the selected operation. See the .Sx OUTPUT FORMAT section for details. .Pp If a credential is successfully created or verified, .Nm exits 0. Otherwise, .Nm exits 1. .Pp The options are as follows: .Bl -tag -width Ds .It Fl M Tells .Nm to make a new credential on .Ar device . .It Fl V Tells .Nm to verify a credential. .It Fl d Causes .Nm to emit debugging output on .Em stderr . .It Fl h If making a credential, enable the FIDO2 hmac-secret extension. If verifying a credential, check whether the extension data bit was signed by the authenticator. .It Fl i Ar input_file Tells .Nm to read the parameters of the credential from .Ar input_file instead of .Em stdin . .It Fl o Ar output_file Tells .Nm to write output on .Ar output_file instead of .Em stdout . .It Fl q Tells .Nm to be quiet. If a PIN is required and .Fl q is specified, .Nm will fail. .It Fl r Create a resident credential. .It Fl u Create a U2F credential. By default, .Nm will use FIDO2 if supported by the authenticator, and fallback to U2F otherwise. .It Fl v If making a credential, request user verification. If verifying a credential, check whether the user verification bit was signed by the authenticator. .El .Sh INPUT FORMAT The input of .Nm consists of base64 blobs and UTF-8 strings separated by newline characters ('\\n'). .Pp When making a credential, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It user name (UTF-8 string); .It user id (base64 blob). .El .Pp When verifying a credential, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It credential format (UTF-8 string); .It authenticator data (base64 blob); .It credential id (base64 blob); .It attestation signature (base64 blob); .It attestation certificate (optional, base64 blob). .El .Pp UTF-8 strings passed to .Nm must not contain embedded newline or NUL characters. .Sh OUTPUT FORMAT The output of .Nm consists of base64 blobs, UTF-8 strings, and PEM-encoded public keys separated by newline characters ('\\n'). .Pp Upon the successful generation of a credential, .Nm outputs: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It credential format (UTF-8 string); .It authenticator data (base64 blob); .It credential id (base64 blob); .It attestation signature (base64 blob); .It attestation certificate, if present (base64 blob). .El .Pp Upon the successful verification of a credential, .Nm outputs: .Pp .Bl -enum -offset indent -compact .It credential id (base64 blob); .It PEM-encoded credential key. .El .Sh EXAMPLES Create a new .Em es256 credential on .Pa /dev/hidraw5 , verify it, and save the id and the public key of the credential in .Em cred : .Pp .Dl $ echo credential challenge | openssl sha256 -binary | base64 > cred_param .Dl $ echo relying party >> cred_param .Dl $ echo user name >> cred_param .Dl $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param .Dl $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred .Sh SEE ALSO .Xr fido2-assert 1 , .Xr fido2-token 1 .Sh CAVEATS Please note that .Nm handles Basic Attestation and Self Attestation transparently. libfido2-1.3.1/man/fido2-token.1000066400000000000000000000064521362326726700162110ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO2-TOKEN 1 .Os .Sh NAME .Nm fido2-token .Nd find and manage a FIDO 2 authenticator .Sh SYNOPSIS .Nm .Op Fl CR .Op Fl d .Ar device .Nm .Fl D .Op Fl de .Fl i .Ar id .Ar device .Nm .Fl I .Op Fl cd .Op Fl k Ar rp_id Fl i Ar cred_id .Ar device .Nm .Fl L .Op Fl der .Op Fl k Ar rp_id .Op device .Nm .Fl S .Op Fl de .Op Fl i Ar template_id Fl n Ar template_name .Ar device .Nm .Fl V .Sh DESCRIPTION .Nm manages a FIDO 2 authenticator. .Pp The options are as follows: .Bl -tag -width Ds .It Fl C Ar device Changes the PIN of .Ar device . The user will be prompted for the current and new PINs. .It Fl D Fl i Ar id Ar device Deletes the resident credential specified by .Ar id from .Ar device , where .Ar id is the credential's base64-encoded id. The user will be prompted for the PIN. .It Fl D Fl e Fl i Ar id Ar device Deletes the biometric enrollment specified by .Ar id from .Ar device , where .Ar id is the enrollment's template base64-encoded id. The user will be prompted for the PIN. .It Fl I Ar device Retrieves information on .Ar device . .It Fl I Fl c Ar device Retrieves resident credential metadata from .Ar device . The user will be prompted for the PIN. .It Fl I Fl k Ar rp_id Fl i Ar cred_id Ar device Prints the credential id (base64-encoded) and public key (PEM encoded) of the resident credential specified by .Ar rp_id and .Ar cred_id , where .Ar rp_id is a UTF-8 relying party id, and .Ar cred_id is a base64-encoded credential id. The user will be prompted for the PIN. .It Fl L Produces a list of authenticators found by the operating system. .It Fl L Fl e Ar device Produces a list of biometric enrollments on .Ar device . The user will be prompted for the PIN. .It Fl L Fl r Ar device Produces a list of relying parties with resident credentials on .Ar device . The user will be prompted for the PIN. .It Fl L Fl k Ar rp_id Ar device Produces a list of resident credentials corresponding to relying party .Ar rp_id on .Ar device . The user will be prompted for the PIN. .It Fl R Performs a reset on .Ar device . .Nm will NOT prompt for confirmation. .It Fl S Sets the PIN of .Ar device . The user will be prompted for the PIN. .It Fl S Fl e Ar device Performs a new biometric enrollment on .Ar device . The user will be prompted for the PIN. .It Fl S Fl e Fl i Ar template_id Fl n Ar template_name Ar device Sets the friendly name of the biometric enrollment specified by .Ar template_id to .Ar template_name on .Ar device , where .Ar template_id is base64-encoded and .Ar template_name is a UTF-8 string. The user will be prompted for the PIN. .It Fl V Prints version information. .It Fl d Causes .Nm to emit debugging output on .Em stderr . .El .Pp If a .Em tty is available, .Nm will use it to prompt for PINs. Otherwise, .Em stdin is used. .Pp .Nm exits 0 on success and 1 on error. .Sh SEE ALSO .Xr fido2-assert 1 , .Xr fido2-cred 1 .Sh CAVEATS The actual user-flow to perform a reset is outside the scope of the FIDO2 specification, and may therefore vary depending on the authenticator. Yubico authenticators do not allow resets after 5 seconds from power-up, and expect a reset to be confirmed by the user through touch within 30 seconds. libfido2-1.3.1/man/fido_assert_allow_cred.3000066400000000000000000000022041362326726700205560ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_ASSERT_ALLOW_CRED 3 .Os .Sh NAME .Nm fido_assert_allow_cred .Nd appends a credential ID to the list of credentials allowed in an assertion .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_assert_allow_cred "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" .Sh DESCRIPTION The .Fn fido_assert_allow_cred function adds .Fa ptr to the list of credentials allowed in .Fa assert , where .Fa ptr points to a credential ID of .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. If .Fn fido_assert_allow_cred fails, the existing list of allowed credentials is preserved. .Pp For the format of a FIDO 2 credential ID, please refer to the Web Authentication (webauthn) standard. .Sh RETURN VALUES The error codes returned by .Fn fido_assert_allow_cred are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_assert_set_authdata 3 , .Xr fido_dev_get_assert 3 libfido2-1.3.1/man/fido_assert_new.3000066400000000000000000000116531362326726700172440ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: October 22 2019 $ .Dt FIDO_ASSERT_NEW 3 .Os .Sh NAME .Nm fido_assert_new , .Nm fido_assert_free , .Nm fido_assert_count , .Nm fido_assert_user_display_name , .Nm fido_assert_user_icon , .Nm fido_assert_user_name , .Nm fido_assert_authdata_ptr , .Nm fido_assert_clientdata_hash_ptr , .Nm fido_assert_hmac_secret_ptr , .Nm fido_assert_user_id_ptr , .Nm fido_assert_sig_ptr , .Nm fido_assert_authdata_len , .Nm fido_assert_clientdata_hash_len , .Nm fido_assert_hmac_secret_len , .Nm fido_assert_user_id_len , .Nm fido_assert_sig_len , .Nm fido_assert_sigcount .Nd FIDO 2 assertion API .Sh SYNOPSIS .In fido.h .Ft fido_assert_t * .Fn fido_assert_new "void" .Ft void .Fn fido_assert_free "fido_assert_t **assert_p" .Ft size_t .Fn fido_assert_count "const fido_assert_t *assert" .Ft const char * .Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx" .Ft const char * .Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx" .Ft const char * .Fn fido_assert_user_name "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_authdata_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_clientdata_hash_ptr "const fido_assert_t *assert" .Ft const unsigned char * .Fn fido_assert_hmac_secret_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_clientdata_hash_len "const fido_assert_t *assert" .Ft size_t .Fn fido_assert_hmac_secret_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx" .Ft uint32_t .Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx" .Sh DESCRIPTION FIDO 2 assertions are abstracted in .Em libfido2 by the .Vt fido_assert_t type. The functions described in this page allow a .Vt fido_assert_t type to be allocated, deallocated, and inspected. For other operations on .Vt fido_assert_t , please refer to .Xr fido_assert_set_authdata 3 , .Xr fido_assert_allow_cred 3 , .Xr fido_assert_verify 3 , and .Xr fido_dev_get_assert 3 . .Pp The .Fn fido_assert_new function returns a pointer to a newly allocated, empty .Vt fido_assert_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_assert_free function releases the memory backing .Fa *assert_p , where .Fa *assert_p must have been previously allocated by .Fn fido_assert_new . On return, .Fa *assert_p is set to NULL. Either .Fa assert_p or .Fa *assert_p may be NULL, in which case .Fn fido_assert_free is a NOP. .Pp The .Fn fido_assert_count function returns the number of statements in .Fa assert . .Pp The .Fn fido_assert_user_display_name , .Fn fido_assert_user_icon , and .Fn fido_assert_user_name , functions return pointers to the user display name, icon, and name attributes of statement .Fa idx in .Fa assert . If not NULL, the values returned by these functions point to NUL-terminated UTF-8 strings. .Pp The .Fn fido_assert_user_id_ptr , .Fn fido_assert_authdata_ptr , .Fn fido_assert_hmac_secret_ptr , and .Fn fido_assert_sig_ptr functions return pointers to the user ID, authenticator data, hmac-secret, and signature attributes of statement .Fa idx in .Fa assert . The .Fn fido_assert_user_id_len , .Fn fido_assert_authdata_len , .Fn fido_assert_hmac_secret_len , and .Fn fido_assert_sig_len functions can be used to retrieve the corresponding length of a specific attribute. .Pp The .Fn fido_assert_sigcount function can be used to obtain the signature counter of statement .Fa idx in .Fa assert . .Pp Please note that the first statement in .Fa assert has an .Fa idx (index) value of 0. .Pp The authenticator data and signature parts of an assertion statement are typically passed to a FIDO 2 server for verification. .Pp The .Fn fido_assert_clientdata_hash_ptr function returns a pointer to the client data hash of .Fa assert . The corresponding length can be obtained by .Fn fido_assert_clientdata_hash_len . .Sh RETURN VALUES The .Fn fido_assert_user_display_name , .Fn fido_assert_user_icon , .Fn fido_assert_user_name , .Fn fido_assert_authdata_ptr , .Fn fido_assert_clientdata_hash_ptr , .Fn fido_assert_user_id_ptr , and .Fn fido_assert_sig_ptr functions return NULL if the respective field in .Fa assert is not set. If not NULL, returned pointers are guaranteed to exist until any API function that takes .Fa assert without the .Em const qualifier is invoked. .Sh SEE ALSO .Xr fido_assert_allow_cred 3 , .Xr fido_assert_set_authdata 3 , .Xr fido_assert_verify 3 , .Xr fido_dev_get_assert 3 libfido2-1.3.1/man/fido_assert_set_authdata.3000066400000000000000000000110711362326726700211130ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_ASSERT_SET_AUTHDATA 3 .Os .Sh NAME .Nm fido_assert_set_authdata , .Nm fido_assert_set_authdata_raw , .Nm fido_assert_set_clientdata_hash , .Nm fido_assert_set_count , .Nm fido_assert_set_extensions , .Nm fido_assert_set_hmac_salt , .Nm fido_assert_set_up , .Nm fido_assert_set_uv , .Nm fido_assert_set_rp , .Nm fido_assert_set_sig .Nd set parameters of a FIDO 2 assertion .Sh SYNOPSIS .In fido.h .Bd -literal typedef enum { FIDO_OPT_OMIT = 0, /* use authenticator's default */ FIDO_OPT_FALSE, /* explicitly set option to false */ FIDO_OPT_TRUE, /* explicitly set option to true */ } fido_opt_t; .Ed .Ft int .Fn fido_assert_set_authdata "fido_assert_t *assert" " size_t idx" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_authdata_raw "fido_assert_t *assert" " size_t idx" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_clientdata_hash "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_count "fido_assert_t *assert" "size_t n" .Ft int .Fn fido_assert_set_extensions "fido_assert_t *assert" "int flags" .Ft int .Fn fido_assert_set_hmac_salt "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_up "fido_assert_t *assert" "fido_opt_t up" .Ft int .Fn fido_assert_set_uv "fido_assert_t *assert" "fido_opt_t uv" .Ft int .Fn fido_assert_set_rp "fido_assert_t *assert" "const char *id" .Ft int .Fn fido_assert_set_sig "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len" .Sh DESCRIPTION The .Nm set of functions define the various parameters of a FIDO 2 assertion, allowing a .Fa fido_assert_t type to be prepared for a subsequent call to .Xr fido_dev_get_assert 3 or .Xr fido_assert_verify 3 . For the complete specification of a FIDO 2 assertion and the format of its constituent parts, please refer to the Web Authentication (webauthn) standard. .Pp The .Fn fido_assert_set_count function sets the number of assertion statements in .Fa assert to .Fa n . .Pp The .Fn fido_assert_set_authdata and .Fn fido_assert_set_sig functions set the authenticator data and signature parts of the statement with index .Fa idx of .Fa assert to .Fa ptr , where .Fa ptr points to .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. Please note that the first assertion statement of .Fa assert has an .Fa idx of .Em 0 . The authenticator data passed to .Fn fido_assert_set_authdata must be a CBOR-encoded byte string, as obtained from .Fn fido_assert_authdata_ptr . Alternatively, a raw binary blob may be passed to .Fn fido_assert_set_authdata_raw . .Pp The .Fn fido_assert_set_clientdata_hash and .Fn fido_assert_set_hmac_salt functions set the client data hash and hmac-salt parts of .Fa assert to .Fa ptr , where .Fa ptr points to .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. .Pp The .Fn fido_assert_set_rp function sets the relying party .Fa id of .Fa assert , where .Fa id is a NUL-terminated UTF-8 string. The content of .Fa id is copied, and no references to the passed pointer are kept. .Pp The .Fn fido_assert_set_extensions function sets the extensions of .Fa assert to the bitmask .Fa flags . At the moment, only the .Dv FIDO_EXT_HMAC_SECRET extension is supported. If .Fa flags is zero, the extensions of .Fa assert are cleared. .Pp The .Fn fido_assert_set_up and .Fn fido_assert_set_uv functions set the .Fa up (user presence) and .Fa uv (user verification) attributes of .Fa assert . Both are .Dv FIDO_OPT_OMIT by default, allowing the authenticator to use its default settings. .Pp Use of the .Nm set of functions may happen in two distinct situations: when asking a FIDO device to produce a series of assertion statements, prior to .Xr fido_dev_get_assert 3 (i.e, in the context of a FIDO client), or when verifying assertion statements using .Xr fido_assert_verify 3 (i.e, in the context of a FIDO server). .Pp For a complete description of the generation of a FIDO 2 assertion and its verification, please refer to the FIDO 2 specification. An example of how to use the .Nm set of functions can be found in the .Pa examples/assert.c file shipped with .Em libfido2 . .Sh RETURN VALUES The .Nm functions return .Dv FIDO_OK on success. The error codes returned by the .Nm set of functions are defined in .In fido/err.h . .Sh SEE ALSO .Xr fido_assert_allow_cred 3 , .Xr fido_assert_verify 3 , .Xr fido_dev_get_assert 3 libfido2-1.3.1/man/fido_assert_verify.3000066400000000000000000000031631362326726700177540ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 24 2018 $ .Dt FIDO_ASSERT_VERIFY 3 .Os .Sh NAME .Nm fido_assert_verify .Nd verifies the signature of a FIDO 2 assertion statement .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_assert_verify "fido_assert_t *assert" "size_t idx" "int cose_alg" "const void *pk" .Sh DESCRIPTION The .Fn fido_assert_verify function verifies whether the signature contained in statement index .Fa idx of .Fa assert matches the parameters of the assertion. Before using .Fn fido_assert_verify in a sensitive context, the reader is strongly encouraged to make herself familiar with the FIDO 2 assertion statement process as defined in the Web Authentication (webauthn) standard. .Pp A brief description follows: .Pp The .Fn fido_assert_verify function verifies whether the client data hash, relying party ID, user presence and user verification attributes of .Fa assert have been attested by the holder of the private counterpart of the public key .Fa pk of COSE type .Fa cose_alg , where .Fa cose_alg is .Dv COSE_ES256 , .Dv COSE_RS256 , or .Dv COSE_EDDSA , and .Fa pk points to a .Vt es256_pk_t , .Vt rs256_pk_t , or .Vt eddsa_pk_t type accordingly. .Pp Please note that the first statement in .Fa assert has an .Fa idx of 0. .Sh RETURN VALUES The error codes returned by .Fn fido_assert_verify are defined in .In fido/err.h . If statement .Fa idx of .Fa assert passes verification with .Fa pk , then .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_assert_set_authdata 3 libfido2-1.3.1/man/fido_bio_dev_get_info.3000066400000000000000000000060741362326726700203540ustar00rootroot00000000000000.\" Copyright (c) 2019 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_DEV_GET_INFO 3 .Os .Sh NAME .Nm fido_bio_dev_get_info , .Nm fido_bio_dev_enroll_begin , .Nm fido_bio_dev_enroll_continue , .Nm fido_bio_dev_enroll_cancel , .Nm fido_bio_dev_enroll_remove , .Nm fido_bio_dev_get_template_array , .Nm fido_bio_dev_set_template_name .Nd FIDO 2 biometric authenticator API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Ft int .Fn fido_bio_dev_get_info "fido_dev_t *dev" "fido_bio_info_t *info" .Ft int .Fn fido_bio_dev_enroll_begin "fido_dev_t *dev" "fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms" "const char *pin" .Ft int .Fn fido_bio_dev_enroll_continue "fido_dev_t *dev" "const fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms" .Ft int .Fn fido_bio_dev_enroll_cancel "fido_dev_t *dev" .Ft int .Fn fido_bio_dev_enroll_remove "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin" .Ft int .Fn fido_bio_dev_get_template_array "fido_dev_t *dev" "fido_bio_template_array_t *template_array" "const char *pin" .Ft int .Fn fido_bio_dev_set_template_name "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin" .Sh DESCRIPTION The functions described in this page allow biometric templates on a FIDO2 authenticator to be listed, created, removed, and customised. For a description of the types involved, please refer to .Xr fido_bio_info_new 3 , .Xr fido_bio_enroll_new 3 , and .Xr fido_bio_template 3 . .Pp The .Fn fido_bio_dev_get_info function populates .Fa info with sensor information from .Fa dev . .Pp The .Fn fido_bio_dev_enroll_begin function initiates a biometric enrollment on .Fa dev , instructing the authenticator to wait .Fa timeout_ms milliseconds. On success, .Fa template and .Fa enroll will be populated with the newly created template's information and enrollment status, respectively. .Pp The .Fn fido_bio_dev_enroll_continue function continues an ongoing enrollment on .Fa dev , instructing the authenticator to wait .Fa timeout_ms milliseconds. On success, .Fa enroll will be updated to reflect the status of the biometric enrollment. .Pp The .Fn fido_bio_dev_enroll_cancel function cancels an ongoing enrollment on .Fa dev . .Pp The .Fn fido_bio_dev_enroll_remove function removes .Fa template from .Fa dev . .Pp The .Fn fido_bio_dev_get_template_array function populates .Fa template_array with the templates currently enrolled on .Fa dev . .Pp The .Fn fido_bio_dev_set_template_name function sets the friendly name of .Fa template on .Fa dev . .Pp The error codes returned by .Fn fido_bio_dev_get_info , .Fn fido_bio_dev_enroll_begin , .Fn fido_bio_dev_enroll_continue , .Fn fido_bio_dev_enroll_cancel , .Fn fido_bio_dev_enroll_remove , .Fn fido_bio_dev_get_template_array , and .Fn fido_bio_dev_set_template_name are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_bio_enroll_new 3 , .Xr fido_bio_info_new 3 , .Xr fido_bio_template 3 libfido2-1.3.1/man/fido_bio_enroll_new.3000066400000000000000000000047051362326726700200670ustar00rootroot00000000000000.\" Copyright (c) 2019 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_ENROLL_NEW 3 .Os .Sh NAME .Nm fido_bio_enroll_new , .Nm fido_bio_enroll_free , .Nm fido_bio_enroll_last_status , .Nm fido_bio_enroll_remaining_samples .Nd FIDO 2 biometric enrollment API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Bd -literal #define FIDO_BIO_ENROLL_FP_GOOD 0x00 #define FIDO_BIO_ENROLL_FP_TOO_HIGH 0x01 #define FIDO_BIO_ENROLL_FP_TOO_LOW 0x02 #define FIDO_BIO_ENROLL_FP_TOO_LEFT 0x03 #define FIDO_BIO_ENROLL_FP_TOO_RIGHT 0x04 #define FIDO_BIO_ENROLL_FP_TOO_FAST 0x05 #define FIDO_BIO_ENROLL_FP_TOO_SLOW 0x06 #define FIDO_BIO_ENROLL_FP_POOR_QUALITY 0x07 #define FIDO_BIO_ENROLL_FP_TOO_SKEWED 0x08 #define FIDO_BIO_ENROLL_FP_TOO_SHORT 0x09 #define FIDO_BIO_ENROLL_FP_MERGE_FAILURE 0x0a #define FIDO_BIO_ENROLL_FP_EXISTS 0x0b #define FIDO_BIO_ENROLL_FP_DATABASE_FULL 0x0c #define FIDO_BIO_ENROLL_NO_USER_ACTIVITY 0x0d #define FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION 0x0e .Ed .Ft fido_bio_enroll_t * .Fn fido_bio_enroll_new "void" .Ft void .Fn fido_bio_enroll_free "fido_bio_enroll_t **enroll_p" .Ft uint8_t .Fn fido_bio_enroll_last_status "const fido_bio_enroll_t *enroll" .Ft uint8_t .Fn fido_bio_enroll_remaining_samples "const fido_bio_enroll_t *enroll" .Sh DESCRIPTION Ongoing FIDO 2 biometric enrollments are abstracted in .Em libfido2 by the .Vt fido_bio_enroll_t type. .Pp The functions described in this page allow a .Vt fido_bio_enroll_t type to be allocated, deallocated, and inspected. For device operations on .Vt fido_bio_enroll_t , please refer to .Xr fido_bio_dev_get_info 3 . .Pp The .Fn fido_bio_enroll_new function returns a pointer to a newly allocated, empty .Vt fido_bio_enroll_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_enroll_free function releases the memory backing .Fa *enroll_p , where .Fa *enroll_p must have been previously allocated by .Fn fido_bio_enroll_new . On return, .Fa *enroll_p is set to NULL. Either .Fa enroll_p or .Fa *enroll_p may be NULL, in which case .Fn fido_bio_enroll_free is a NOP. .Pp The .Fn fido_bio_enroll_last_status function returns the enrollment status of .Fa enroll . .Pp The .Fn fido_bio_enroll_remaining_samples function returns the number of samples left for .Fa enroll to complete. .Sh SEE ALSO .Xr fido_bio_dev_get_info 3 , .Xr fido_bio_template 3 libfido2-1.3.1/man/fido_bio_info_new.3000066400000000000000000000034071362326726700175250ustar00rootroot00000000000000.\" Copyright (c) 2019 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_INFO_NEW 3 .Os .Sh NAME .Nm fido_bio_info_new , .Nm fido_bio_info_free , .Nm fido_bio_info_type , .Nm fido_bio_info_max_samples .Nd FIDO 2 biometric sensor information API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Ft fido_bio_info_t * .Fn fido_bio_info_new "void" .Ft void .Fn fido_bio_info_free "fido_bio_info_t **info_p" .Ft uint8_t .Fn fido_bio_info_type "const fido_bio_info_t *info" .Ft uint8_t .Fn fido_bio_info_max_samples "const fido_bio_info_t *info" .Sh DESCRIPTION Biometric sensor metadata is abstracted in .Em libfido2 by the .Vt fido_bio_info_t type. .Pp The functions described in this page allow a .Vt fido_bio_info_t type to be allocated, deallocated, and inspected. For device operations on .Vt fido_bio_info_t , please refer to .Xr fido_bio_dev_get_info 3 . .Pp The .Fn fido_bio_info_new function returns a pointer to a newly allocated, empty .Vt fido_bio_info_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_info_free function releases the memory backing .Fa *info_p , where .Fa *info_p must have been previously allocated by .Fn fido_bio_info_new . On return, .Fa *info_p is set to NULL. Either .Fa info_p or .Fa *info_p may be NULL, in which case .Fn fido_bio_info_free is a NOP. .Pp The .Fn fido_bio_info_type function returns the fingerprint sensor type, which is .Dv 1 for touch sensors, and .Dv 2 for swipe sensors. .Pp The .Fn fido_bio_info_max_samples function returns the maximum number of successful samples required for enrollment. .Sh SEE ALSO .Xr fido_bio_dev_get_info 3 , .Xr fido_bio_enroll_new 3 , .Xr fido_bio_template 3 libfido2-1.3.1/man/fido_bio_template.3000066400000000000000000000100341362326726700175260ustar00rootroot00000000000000.\" Copyright (c) 2019 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_TEMPLATE 3 .Os .Sh NAME .Nm fido_bio_template , .Nm fido_bio_template_array_count , .Nm fido_bio_template_array_free , .Nm fido_bio_template_array_new , .Nm fido_bio_template_free , .Nm fido_bio_template_id_len , .Nm fido_bio_template_id_ptr , .Nm fido_bio_template_name , .Nm fido_bio_template_new , .Nm fido_bio_template_set_id , .Nm fido_bio_template_set_name .Nd FIDO 2 biometric template API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Ft fido_bio_template_t * .Fn fido_bio_template_new "void" .Ft void .Fn fido_bio_template_free "fido_bio_template_t **template_p" .Ft const char * .Fn fido_bio_template_name "const fido_bio_template_t *template" .Ft const unsigned char * .Fn fido_bio_template_id_ptr "const fido_bio_template_t *template" .Ft size_t .Fn fido_bio_template_id_len "const fido_bio_template_t *template" .Ft int .Fn fido_bio_template_set_id "fido_bio_template_t *template" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_bio_template_set_name "fido_bio_template_t *template" "const char *name" .Ft fido_bio_template_array_t * .Fn fido_bio_template_array_new "void" .Ft void .Fn fido_bio_template_array_free "fido_bio_template_array_t **template_array_p" .Ft size_t .Fn fido_bio_template_array_count "const fido_bio_template_array_t *template_array" .Ft const fido_bio_template_t * .Fn fido_bio_template "const fido_bio_template_array_t *template_array" "size_t idx" .Sh DESCRIPTION Existing FIDO 2 biometric enrollments are abstracted in .Em libfido2 by the .Vt fido_bio_template_t and .Vt fido_bio_template_array_t types. .Pp The functions described in this page allow a .Vt fido_bio_template_t type to be allocated, deallocated, changed, and inspected, and a .Vt fido_bio_template_array_t type to be allocated, deallocated, and inspected. For device operations on .Vt fido_bio_template_t and .Vt fido_bio_template_array_t , please refer to .Xr fido_bio_dev_get_info 3 . .Pp The .Fn fido_bio_template_new function returns a pointer to a newly allocated, empty .Vt fido_bio_template_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_template_free function releases the memory backing .Fa *template_p , where .Fa *template_p must have been previously allocated by .Fn fido_bio_template_new . On return, .Fa *template_p is set to NULL. Either .Fa template_p or .Fa *template_p may be NULL, in which case .Fn fido_bio_template_free is a NOP. .Pp The .Fn fido_bio_template_name function returns a pointer to a NUL-terminated string containing the friendly name of .Fa template , or NULL if .Fa template does not have a friendly name set. .Pp The .Fn fido_bio_template_id_ptr function returns a pointer to the template id of .Fa template , or NULL if .Fa template does not have an id. The corresponding length can be obtained by .Fn fido_bio_template_id_len . .Pp The .Fn fido_bio_template_set_name function sets the friendly name of .Fa template to .Fa name . If .Fa name is NULL, the friendly name of .Fa template is unset. .Pp The .Fn fido_bio_template_array_new function returns a pointer to a newly allocated, empty .Vt fido_bio_template_array_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_template_array_free function releases the memory backing .Fa *template_array_p , where .Fa *template_array_p must have been previously allocated by .Fn fido_bio_template_array_new . On return, .Fa *template_array_p is set to NULL. Either .Fa template_array_p or .Fa *template_array_p may be NULL, in which case .Fn fido_bio_template_array_free is a NOP. .Pp The .Fn fido_bio_template_array_count function returns the number of templates in .Fa template_array . .Pp The .Fn fido_bio_template function returns a pointer to the template at index .Fa idx in .Fa template_array . Please note that the first template in .Fa template_array has an .Fa idx (index) value of 0. .Sh SEE ALSO .Xr fido_bio_dev_get_info 3 , .Xr fido_bio_enroll_new 3 libfido2-1.3.1/man/fido_cbor_info_new.3000066400000000000000000000076011362326726700177010ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 24 2018 $ .Dt FIDO_CBOR_INFO_NEW 3 .Os .Sh NAME .Nm fido_cbor_info_new , .Nm fido_cbor_info_free , .Nm fido_dev_get_cbor_info , .Nm fido_cbor_info_aaguid_ptr , .Nm fido_cbor_info_extensions_ptr , .Nm fido_cbor_info_protocols_ptr , .Nm fido_cbor_info_versions_ptr , .Nm fido_cbor_info_options_name_ptr , .Nm fido_cbor_info_options_value_ptr , .Nm fido_cbor_info_aaguid_len , .Nm fido_cbor_info_extensions_len , .Nm fido_cbor_info_protocols_len , .Nm fido_cbor_info_versions_len , .Nm fido_cbor_info_options_len , .Nm fido_cbor_info_maxmsgsiz .Nd FIDO 2 CBOR Info API .Sh SYNOPSIS .In fido.h .Ft fido_cbor_info_t * .Fn fido_cbor_info_new "void" .Ft void .Fn fido_cbor_info_free "fido_cbor_info_t **ci_p" .Ft int .Fn fido_dev_get_cbor_info "fido_dev_t *dev" "fido_cbor_info_t *ci" .Ft const unsigned char * .Fn fido_cbor_info_aaguid_ptr "const fido_cbor_info_t *ci" .Ft char ** .Fn fido_cbor_info_extensions_ptr "const fido_cbor_info_t *ci" .Ft const uint8_t * .Fn fido_cbor_info_protocols_ptr "const fido_cbor_info_t *ci" .Ft char ** .Fn fido_cbor_info_versions_ptr "const fido_cbor_info_t *ci" .Ft char ** .Fn fido_cbor_info_options_name_ptr "const fido_cbor_info_t *ci" .Ft const bool * .Fn fido_cbor_info_options_value_ptr "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_aaguid_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_extensions_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_protocols_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_versions_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_options_len "const fido_cbor_info_t *ci" .Ft uint64_t .Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci" .Sh DESCRIPTION The .Fn fido_cbor_info_new function returns a pointer to a newly allocated, empty .Vt fido_cbor_info_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_cbor_info_free function releases the memory backing .Fa *ci_p , where .Fa *ci_p must have been previously allocated by .Fn fido_cbor_info_new . On return, .Fa *ci_p is set to NULL. Either .Fa ci_p or .Fa *ci_p may be NULL, in which case .Fn fido_cbor_info_free is a NOP. .Pp The .Fn fido_dev_get_cbor_info function transmits a .Dv CTAP_CBOR_GETINFO command to .Fa dev and fills .Fa ci with attributes retrieved from the command's response. The .Fn fido_dev_get_cbor_info function may block. .Pp The .Fn fido_cbor_info_aaguid_ptr , .Fn fido_cbor_info_extensions_ptr , .Fn fido_cbor_info_protocols_ptr , and .Fn fido_cbor_info_versions_ptr functions return pointers to the AAGUID, supported extensions, PIN protocol and CTAP version strings of .Fa ci . The corresponding length of a given attribute can be obtained by .Fn fido_cbor_info_aaguid_len , .Fn fido_cbor_info_extensions_len , .Fn fido_cbor_info_protocols_len , or .Fn fido_cbor_info_versions_len . .Pp The .Fn fido_cbor_info_options_name_ptr and .Fn fido_cbor_info_options_value_ptr functions return pointers to the array of option names and their respective values in .Fa ci . The length of the options array is returned by .Fn fido_cbor_info_options_len . .Pp The .Fn fido_cbor_info_maxmsgsiz function returns the maximum message size of .Fa ci . .Pp A complete example of how to use these functions can be found in the .Pa example/info.c file shipped with .Em libfido2 . .Sh RETURN VALUES The .Fn fido_cbor_info_aaguid_ptr , .Fn fido_cbor_info_extensions_ptr , .Fn fido_cbor_info_protocols_ptr , .Fn fido_cbor_info_versions_ptr , .Fn fido_cbor_info_options_name_ptr , and .Fn fido_cbor_info_options_value_ptr functions return NULL if the respective field in .Fa ci is absent. If not NULL, returned pointers are guaranteed to exist until any API function that takes .Fa ci without the .Em const qualifier is invoked. .Sh SEE ALSO .Xr fido_dev_open 3 libfido2-1.3.1/man/fido_cred_exclude.3000066400000000000000000000024241362326726700175140ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_EXCLUDE 3 .Os .Sh NAME .Nm fido_cred_exclude .Nd appends a credential ID to a credential's list of excluded credentials .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_cred_exclude "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Sh DESCRIPTION The .Fn fido_cred_exclude function adds .Fa ptr to the list of credentials excluded by .Fa cred , where .Fa ptr points to a credential ID of .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. If .Fn fido_cred_exclude fails, the existing list of excluded credentials is preserved. .Pp If .Nm returns success and .Fa cred is later passed to .Xr fido_dev_make_cred 3 on a device that contains the credential denoted by .Fa ptr , then .Xr fido_dev_make_cred 3 will fail. .Pp For the format of a FIDO 2 credential ID, please refer to the Web Authentication (webauthn) standard. .Sh RETURN VALUES The error codes returned by .Fn fido_cred_exclude are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_cred_new 3 , .Xr fido_cred_set_authdata 3 , .Xr fido_dev_make_cred 3 libfido2-1.3.1/man/fido_cred_new.3000066400000000000000000000075561362326726700166670ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_NEW 3 .Os .Sh NAME .Nm fido_cred_new , .Nm fido_cred_free , .Nm fido_cred_fmt , .Nm fido_cred_authdata_ptr , .Nm fido_cred_clientdata_hash_ptr , .Nm fido_cred_id_ptr , .Nm fido_cred_pubkey_ptr , .Nm fido_cred_sig_ptr , .Nm fido_cred_x5c_ptr , .Nm fido_cred_authdata_len , .Nm fido_cred_clientdata_hash_len , .Nm fido_cred_id_len , .Nm fido_cred_pubkey_len , .Nm fido_cred_sig_len , .Nm fido_cred_x5c_len .Nd FIDO 2 credential API .Sh SYNOPSIS .In fido.h .Ft fido_cred_t * .Fn fido_cred_new "void" .Ft void .Fn fido_cred_free "fido_cred_t **cred_p" .Ft const char * .Fn fido_cred_fmt "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_authdata_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_clientdata_hash_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_id_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_pubkey_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_sig_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_x5c_ptr "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_authdata_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_clientdata_hash_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_id_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_pubkey_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_sig_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_x5c_len "const fido_cred_t *cred" .Sh DESCRIPTION FIDO 2 credentials are abstracted in .Em libfido2 by the .Vt fido_cred_t type. The functions described in this page allow a .Vt fido_cred_t type to be allocated, deallocated, and inspected. For other operations on .Vt fido_cred_t , please refer to .Xr fido_cred_set_authdata 3 , .Xr fido_cred_exclude 3 , .Xr fido_cred_verify 3 , and .Xr fido_dev_make_cred 3 . .Pp The .Fn fido_cred_new function returns a pointer to a newly allocated, empty .Vt fido_cred_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_cred_free function releases the memory backing .Fa *cred_p , where .Fa *cred_p must have been previously allocated by .Fn fido_cred_new . On return, .Fa *cred_p is set to NULL. Either .Fa cred_p or .Fa *cred_p may be NULL, in which case .Fn fido_cred_free is a NOP. .Pp The .Fn fido_cred_fmt function returns a pointer to a NUL-terminated string containing the format of .Fa cred , or NULL if .Fa cred does not have a format set. .Pp The .Fn fido_cred_authdata_ptr , .Fn fido_cred_clientdata_hash_ptr , .Fn fido_cred_id_ptr , .Fn fido_cred_pubkey_ptr , .Fn fido_cred_sig_ptr , and .Fn fido_cred_x5c_ptr functions return pointers to the authenticator data, client data hash, ID, public key, signature and x509 certificate parts of .Fa cred , or NULL if the respective entry is not set. .Pp The corresponding length can be obtained by .Fn fido_cred_authdata_len , .Fn fido_cred_clientdata_hash_len , .Fn fido_cred_id_len , .Fn fido_cred_pubkey_len , and .Fn fido_cred_sig_len . .Pp The authenticator data, x509 certificate, and signature parts of a credential are typically passed to a FIDO 2 server for verification. .Sh RETURN VALUES The authenticator data returned by .Fn fido_cred_authdata_ptr is a CBOR-encoded byte string, as obtained from the authenticator. .Pp If not NULL, pointers returned by .Fn fido_cred_fmt , .Fn fido_cred_authdata_ptr , .Fn fido_cred_clientdata_hash_ptr , .Fn fido_cred_id_ptr , .Fn fido_cred_pubkey_ptr , .Fn fido_cred_sig_ptr , and .Fn fido_cred_x5c_ptr are guaranteed to exist until any API function that takes .Fa cred without the .Em const qualifier is invoked. .Sh SEE ALSO .Xr fido_cred_exclude 3 , .Xr fido_cred_set_authdata 3 , .Xr fido_cred_verify 3 , .Xr fido_credman_metadata_new 3 , .Xr fido_dev_make_cred 3 libfido2-1.3.1/man/fido_cred_set_authdata.3000066400000000000000000000126511362326726700205340ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_SET_AUTHDATA 3 .Os .Sh NAME .Nm fido_cred_set_authdata , .Nm fido_cred_set_authdata_raw , .Nm fido_cred_set_x509 , .Nm fido_cred_set_sig , .Nm fido_cred_set_clientdata_hash , .Nm fido_cred_set_rp , .Nm fido_cred_set_user , .Nm fido_cred_set_extensions , .Nm fido_cred_set_rk , .Nm fido_cred_set_uv , .Nm fido_cred_set_fmt , .Nm fido_cred_set_type .Nd set parameters of a FIDO 2 credential .Sh SYNOPSIS .In fido.h .Bd -literal typedef enum { FIDO_OPT_OMIT = 0, /* use authenticator's default */ FIDO_OPT_FALSE, /* explicitly set option to false */ FIDO_OPT_TRUE, /* explicitly set option to true */ } fido_opt_t; .Ed .Ft int .Fn fido_cred_set_authdata "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_authdata_raw "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_x509 "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_sig "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_clientdata_hash "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_rp "fido_cred_t *cred" "const char *id" "const char *name" .Ft int .Fn fido_cred_set_user "fido_cred_t *cred" "const unsigned char *user_id" "size_t user_id_len" "const char *name" "const char *display_name" "const char *icon" .Ft int .Fn fido_cred_set_extensions "fido_cred_t *cred" "int flags" .Ft int .Fn fido_cred_set_rk "fido_cred_t *cred" "fido_opt_t rk" .Ft int .Fn fido_cred_set_uv "fido_cred_t *cred" "fido_opt_t uv" .Ft int .Fn fido_cred_set_fmt "fido_cred_t *cred" "const char *ptr" .Ft int .Fn fido_cred_set_type "fido_cred_t *cred" "int cose_alg" .Sh DESCRIPTION The .Nm set of functions define the various parameters of a FIDO 2 credential, allowing a .Fa fido_cred_t type to be prepared for a subsequent call to .Xr fido_dev_make_cred 3 or .Xr fido_cred_verify 3 . For the complete specification of a FIDO 2 credential and the format of its constituent parts, please refer to the Web Authentication (webauthn) standard. .Pp The .Fn fido_cred_set_authdata , .Fn fido_cred_set_x509 , .Fn fido_cred_set_sig , and .Fn fido_cred_set_clientdata_hash functions set the authenticator data, attestation certificate, signature and client data hash parts of .Fa cred to .Fa ptr , where .Fa ptr points to .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. The authenticator data passed to .Fn fido_cred_set_authdata must be a CBOR-encoded byte string, as obtained from .Fn fido_cred_authdata_ptr . Alternatively, a raw binary blob may be passed to .Fn fido_cred_set_authdata_raw . .Pp The .Fn fido_cred_set_rp function sets the relying party .Fa id and .Fa name parameters of .Fa cred , where .Fa id and .Fa name are NUL-terminated UTF-8 strings. The contents of .Fa id and .Fa name are copied, and no references to the passed pointers are kept. .Pp The .Fn fido_cred_set_user function sets the user attributes of .Fa cred , where .Fa user_id points to .Fa user_id_len bytes and .Fa name , .Fa display_name , and .Fa icon are NUL-terminated UTF-8 strings. The contents of .Fa user_id , .Fa name , .Fa display_name , and .Fa icon are copied, and no references to the passed pointers are kept. Previously set user attributes are flushed. The .Fa user_id , .Fa name , .Fa display_name , and .Fa icon parameters may be NULL. .Pp The .Fn fido_cred_set_extensions function sets the extensions of .Fa cred to the bitmask .Fa flags . At the moment, only the .Dv FIDO_EXT_HMAC_SECRET extension is supported. If .Fa flags is zero, the extensions of .Fa cred are cleared. .Pp The .Fn fido_cred_set_rk and .Fn fido_cred_set_uv functions set the .Em rk (resident key) and .Em uv (user verification) attributes of .Fa cred . Both are .Dv FIDO_OPT_OMIT by default, allowing the authenticator to use its default settings. .Pp The .Fn fido_cred_set_fmt function sets the format of .Fa cred to .Fa fmt , where .Fa fmt must be either .Vt "packed" (the format used in FIDO 2) or .Vt "fido-u2f" (the format used by U2F). A copy of .Fa fmt is made, and no references to the passed pointer are kept. Note that not all authenticators support FIDO2 and therefore may not be able to generate .Vt "packed" . .Pp The .Fn fido_cred_set_type function sets the type of .Fa cred to .Fa cose_alg , where .Fa cose_alg is .Dv COSE_ES256 , .Dv COSE_RS256 , or .Dv COSE_EDDSA . The type of a credential may only be set once. Note that not all authenticators support COSE_RS256 or COSE_EDDSA. .Pp Use of the .Nm set of functions may happen in two distinct situations: when generating a new credential on a FIDO device, prior to .Xr fido_dev_make_cred 3 (i.e, in the context of a FIDO client), or when validating a generated credential using .Xr fido_cred_verify 3 (i.e, in the context of a FIDO server). .Pp For a complete description of the generation of a FIDO 2 credential and its verification, please refer to the FIDO 2 specification. A concrete utilisation example of the .Nm set of functions can be found in the .Pa cred.c example shipped with .Em libfido2 . .Sh RETURN VALUES The error codes returned by the .Nm set of functions are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_cred_exclude 3 , .Xr fido_cred_verify 3 , .Xr fido_dev_make_cred 3 libfido2-1.3.1/man/fido_cred_verify.3000066400000000000000000000032221362326726700173640ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_VERIFY 3 .Os .Sh NAME .Nm fido_cred_verify .Nd verifies the signature of a FIDO 2 credential .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_cred_verify "const fido_cred_t *cred" .Sh DESCRIPTION The .Fn fido_cred_verify function verifies whether the signature contained in .Fa cred matches the attributes of the credential. Before using .Fn fido_cred_verify in a sensitive context, the reader is strongly encouraged to make herself familiar with the FIDO 2 credential attestation process as defined in the Web Authentication (webauthn) standard. .Pp A brief description follows: .Pp The .Fn fido_cred_verify function verifies whether the client data hash, relying party ID, credential ID, type, and resident key and user verification attributes of .Fa cred have been attested by the holder of the private counterpart of the public key contained in the credential's x509 certificate. .Pp Please note that the x509 certificate itself is not verified. .Pp The attestation statement formats supported by .Fn fido_cred_verify are .Em packed and .Em fido-u2f . The attestation type implemented by .Fn fido_cred_verify is .Em Basic Attestation . The attestation key pair is assumed to be of the type ES256. Other attestation formats and types are not supported. .Sh RETURN VALUES The error codes returned by .Fn fido_cred_verify are defined in .In fido/err.h . If .Fa cred passes verification, then .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_cred_new 3 , .Xr fido_cred_set_authdata 3 libfido2-1.3.1/man/fido_credman_metadata_new.3000066400000000000000000000153421362326726700212130ustar00rootroot00000000000000.\" Copyright (c) 2019 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: June 28 2019 $ .Dt FIDO_CREDMAN_METADATA_NEW 3 .Os .Sh NAME .Nm fido_credman_metadata_new , .Nm fido_credman_rk_new , .Nm fido_credman_rp_new , .Nm fido_credman_metadata_free , .Nm fido_credman_rk_free , .Nm fido_credman_rp_free , .Nm fido_credman_rk_existing , .Nm fido_credman_rk_remaining , .Nm fido_credman_rk , .Nm fido_credman_rk_count , .Nm fido_credman_rp_id , .Nm fido_credman_rp_name , .Nm fido_credman_rp_count , .Nm fido_credman_rp_id_hash_ptr , .Nm fido_credman_rp_id_hash_len , .Nm fido_credman_get_dev_metadata , .Nm fido_credman_get_dev_rk , .Nm fido_credman_del_dev_rk , .Nm fido_credman_get_dev_rp .Nd FIDO 2 credential management API .Sh SYNOPSIS .In fido.h .In fido/credman.h .Ft fido_credman_metadata_t * .Fn fido_credman_metadata_new "void" .Ft fido_credman_rk_t * .Fn fido_credman_rk_new "void" .Ft fido_credman_rp_t * .Fn fido_credman_rp_new "void" .Ft void .Fn fido_credman_metadata_free "fido_credman_metadata_t **metadata_p" .Ft void .Fn fido_credman_rk_free "fido_credman_rk_t **rk_p" .Ft void .Fn fido_credman_rp_free "fido_credman_rp_t **rp_p" .Ft uint64_t .Fn fido_credman_rk_existing "const fido_credman_metadata_t *metadata" .Ft uint64_t .Fn fido_credman_rk_remaining "const fido_credman_metadata_t *metadata" .Ft const fido_cred_t * .Fn fido_credman_rk "const fido_credman_rk_t *rk" "size_t idx" .Ft size_t .Fn fido_credman_rk_count "const fido_credman_rk_t *rk" .Ft const char * .Fn fido_credman_rp_id "const fido_credman_rp_t *rp" "size_t idx" .Ft const char * .Fn fido_credman_rp_name "const fido_credman_rp_t *rp" "size_t idx" .Ft size_t .Fn fido_credman_rp_count "const fido_credman_rp_t *rp" .Ft const unsigned char * .Fn fido_credman_rp_id_hash_ptr "const fido_credman_rp_t *rp" "size_t idx" .Ft size_t .Fn fido_credman_rp_id_hash_len "const fido_credman_rp_t *" "size_t idx" .Ft int .Fn fido_credman_get_dev_metadata "fido_dev_t *dev" "fido_credman_metadata_t *metadata" "const char *pin" .Ft int .Fn fido_credman_get_dev_rk "fido_dev_t *dev" "const char *rp_id" "fido_credman_rk_t *rk" "const char *pin" .Ft int .Fn fido_credman_del_dev_rk "fido_dev_t *dev" const unsigned char *cred_id" "size_t cred_id_len" "const char *pin" .Ft int .Fn fido_credman_get_dev_rp "fido_dev_t *dev" "fido_credman_rp_t *rp" "const char *pin" .Sh DESCRIPTION The credential management API of .Em libfido2 allows resident credentials on a FIDO2 authenticator to be listed, inspected, and removed. Please note that not all authenticators support credential management. To obtain information on what an authenticator supports, please refer to .Xr fido_cbor_info_new 3 . .Pp The .Vt fido_credman_metadata_t type abstracts credential management metadata. .Pp The .Fn fido_credman_metadata_new function returns a pointer to a newly allocated, empty .Vt fido_credman_metadata_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_credman_metadata_free function releases the memory backing .Fa *metadata_p , where .Fa *metadata_p must have been previously allocated by .Fn fido_credman_metadata_new . On return, .Fa *metadata_p is set to NULL. Either .Fa metadata_p or .Fa *metadata_p may be NULL, in which case .Fn fido_credman_metadata_free is a NOP. .Pp The .Fn fido_credman_get_dev_metadata function populates .Fa metadata with information retrieved from .Fa dev . A valid .Fa pin must be provided. .Pp The .Fn fido_credman_rk_existing function inspects .Fa metadata and returns the number of resident credentials on the authenticator. The .Fn fido_credman_rk_remaining function inspects .Fa metadata and returns the estimated number of resident credentials that can be created on the authenticator. .Pp The .Vt fido_credman_rk_t type abstracts the set of resident credentials belonging to a given relying party. .Pp The .Fn fido_credman_rk_new function returns a pointer to a newly allocated, empty .Vt fido_credman_rk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_credman_rk_free function releases the memory backing .Fa *rk_p , where .Fa *rk_p must have been previously allocated by .Fn fido_credman_rk_new . On return, .Fa *rk_p is set to NULL. Either .Fa rk_p or .Fa *rk_p may be NULL, in which case .Fn fido_credman_rk_free is a NOP. .Pp The .Fn fido_credman_get_dev_rk function populates .Fa rk with the set of resident credentials belonging to .Fa rp_id in .Fa dev . A valid .Fa pin must be provided. .Pp The .Fn fido_credman_rk_count function returns the number of resident credentials in .Fa rk . The .Fn fido_credman_rk function returns a pointer to the credential at index .Fa idx in .Fa rk . Please note that the first credential in .Fa rk has an .Fa idx (index) value of 0. .Pp The .Fn fido_credman_del_dev_rk function deletes the resident credential identified by .Fa cred_id from .Fa dev , where .Fa cred_id points to .Fa cred_id_len bytes. A valid .Fa pin must be provided. .Pp The .Vt fido_credman_rp_t type abstracts information about a relying party. .Pp The .Fn fido_credman_rp_new function returns a pointer to a newly allocated, empty .Vt fido_credman_rp_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_credman_rp_free function releases the memory backing .Fa *rp_p , where .Fa *rp_p must have been previously allocated by .Fn fido_credman_rp_new . On return, .Fa *rp_p is set to NULL. Either .Fa rp_p or .Fa *rp_p may be NULL, in which case .Fn fido_credman_rp_free is a NOP. .Pp The .Fn fido_credman_get_dev_rp function populates .Fa rp with information about relying parties with resident credentials in .Fa dev . A valid .Fa pin must be provided. .Pp The .Fn fido_credman_rp_count function returns the number of relying parties in .Fa rp . .Pp The .Fn fido_credman_rp_id and .Fn fido_credman_rp_name functions return pointers to the id and name of relying party .Fa idx in .Fa rp . If not NULL, the values returned by these functions point to NUL-terminated UTF-8 strings. Please note that the first relying party in .Fa rp has an .Fa idx (index) value of 0. .Pp The .Fn fido_credman_rp_id_hash_ptr function returns a pointer to the hashed id of relying party .Fa idx in .Fa rp . The corresponding length can be obtained by .Fn fido_credman_rp_id_hash_len . Please note that the first relying party in .Fa rp has an .Fa idx (index) value of 0. .Sh RETURN VALUES The .Fn fido_credman_get_dev_metadata , .Fn fido_credman_get_dev_rk , .Fn fido_credman_del_dev_rk , and .Fn fido_credman_get_dev_rp functions return .Dv FIDO_OK on success. On error, a different error code defined in .In fido/err.h is returned. Functions returning pointers are not guaranteed to succeed, and should have their return values checked for NULL. .Sh SEE ALSO .Xr fido_cbor_info_new 3 , .Xr fido_cred_new 3 libfido2-1.3.1/man/fido_dev_get_assert.3000066400000000000000000000032761362326726700200720ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 24 2018 $ .Dt FIDO_DEV_GET_ASSERT 3 .Os .Sh NAME .Nm fido_dev_get_assert .Nd obtains an assertion from a FIDO device .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_get_assert "fido_dev_t *dev" " fido_assert_t *assert" "const char *pin" .Sh DESCRIPTION The .Fn fido_dev_get_assert function asks the FIDO device represented by .Fa dev for an assertion according to the following parameters defined in .Fa assert : .Pp .Bl -dash -compact .It .Nm relying party ID ; .It .Nm client data hash ; .It .Nm list of allowed credential IDs ; .It .Nm user presence and user verification attributes . .El .Pp See .Xr fido_assert_set_authdata 3 for information on how these values are set. .Pp If a PIN is not needed to authenticate the request against .Fa dev , then .Fa pin may be NULL. Otherwise .Fa pin must point to a NUL-terminated UTF-8 string. .Pp After a successful call to .Fn fido_dev_get_assert , the .Xr fido_assert_count 3 , .Xr fido_assert_user_display_name 3 , .Xr fido_assert_user_icon 3 , .Xr fido_assert_user_name 3 , .Xr fido_assert_authdata_ptr 3 , .Xr fido_assert_user_id_ptr 3 , .Xr fido_assert_sig_ptr 3 , and .Xr fido_assert_sigcount 3 functions may be invoked on .Fa assert to retrieve the various attributes of the generated assertion. .Pp Please note that .Fn fido_dev_get_assert is synchronous and will block if necessary. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_get_assert are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_assert_set_authdata 3 libfido2-1.3.1/man/fido_dev_info_manifest.3000066400000000000000000000063131362326726700205460ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_INFO_MANIFEST 3 .Os .Sh NAME .Nm fido_dev_info_manifest , .Nm fido_dev_info_new , .Nm fido_dev_info_free , .Nm fido_dev_info_ptr , .Nm fido_dev_info_path , .Nm fido_dev_info_product , .Nm fido_dev_info_vendor , .Nm fido_dev_info_manufacturer_string , .Nm fido_dev_info_product_string .Nd FIDO 2 device discovery functions .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_info_manifest "fido_dev_info_t *devlist" "size_t ilen" "size_t *olen" .Ft fido_dev_info_t * .Fn fido_dev_info_new "size_t n" .Ft void .Fn fido_dev_info_free "fido_dev_info_t **devlist_p" "size_t n" .Ft const fido_dev_info_t * .Fn fido_dev_info_ptr "const fido_dev_info_t *devlist" "size_t i" .Ft const char * .Fn fido_dev_info_path "const fido_dev_info_t *di" .Ft int16_t .Fn fido_dev_info_product "const fido_dev_info_t *di" .Ft int16_t .Fn fido_dev_info_vendor "const fido_dev_info_t *di" .Ft const char * .Fn fido_dev_info_manufacturer_string "const fido_dev_info_t *di" .Ft const char * .Fn fido_dev_info_product_string "const fido_dev_info_t *di" .Sh DESCRIPTION The .Fn fido_dev_info_manifest function fills .Fa devlist with up to .Fa ilen FIDO devices found by the underlying operating system. Currently only USB HID devices are supported. The number of discovered devices is returned in .Fa olen , where .Fa olen is an addressable pointer. .Pp The .Fn fido_dev_info_new function returns a pointer to a newly allocated, empty device list with .Fa n available slots. If memory is not available, NULL is returned. .Pp The .Fn fido_dev_info_free function releases the memory backing .Fa *devlist_p , where .Fa *devlist_p must have been previously allocated by .Fn fido_dev_info_new . The number .Fa n of allocated slots must also be provided. On return, .Fa *devlist_p is set to NULL. Either .Fa devlist_p or .Fa *devlist_p may be NULL, in which case .Fn fido_dev_info_free is a NOP. .Pp The .Fn fido_dev_info_ptr function returns a pointer to slot number .Fa i of .Fa devlist . It is the caller's responsibility to ensure that .Fa i is bounded. Please note that the first slot has index 0. .Pp The .Fn fido_dev_info_path returns the filesystem path or subsystem-specific identification string of .Fa di . .Pp The .Fn fido_dev_info_product function returns the product ID of .Fa di . .Pp The .Fn fido_dev_info_vendor function returns the vendor ID of .Fa di . .Pp The .Fn fido_dev_info_manufacturer_string function returns the manufacturer string of .Fa di . .Pp The .Fn fido_dev_info_product_string function returns the product string of .Fa di . .Pp An example of how to use the functions described in this document can be found in the .Pa examples/manifest.c file shipped with .Em libfido2 . .Sh RETURN VALUES The .Fn fido_dev_info_manifest function always returns .Dv FIDO_OK . If a discovery error occurs, the .Fa olen pointer is set to 0. .Pp The pointers returned by .Fn fido_dev_info_ptr , .Fn fido_dev_info_path , .Fn fido_dev_info_manufacturer_string , and .Fn fido_dev_info_product_string are guaranteed to exist until .Fn fido_dev_info_free is called on the corresponding device list. libfido2-1.3.1/man/fido_dev_make_cred.3000066400000000000000000000031251362326726700176350ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_DEV_MAKE_CRED 3 .Os .Sh NAME .Nm fido_dev_make_cred .Nd generates a new credential on a FIDO device .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_make_cred "fido_dev_t *dev" " fido_cred_t *cred" "const char *pin" .Sh DESCRIPTION The .Fn fido_dev_make_cred function asks the FIDO device represented by .Fa dev to generate a new credential according to the following parameters defined in .Fa cred : .Pp .Bl -dash -compact .It .Nm type ; .It .Nm client data hash ; .It .Nm relying party ; .It .Nm user attributes ; .It .Nm list of excluded credential IDs ; .It .Nm resident key and user verification attributes . .El .Pp See .Xr fido_cred_set_authdata 3 for information on how these values are set. .Pp If a PIN is not needed to authenticate the request against .Fa dev , then .Fa pin may be NULL. Otherwise .Fa pin must point to a NUL-terminated UTF-8 string. .Pp After a successful call to .Fn fido_dev_make_cred , the .Xr fido_cred_authdata_ptr 3 , .Xr fido_cred_pubkey_ptr 3 , .Xr fido_cred_x5c_ptr 3 , and .Xr fido_cred_sig_ptr 3 functions may be invoked on .Fa cred to retrieve the various parts of the generated credential. .Pp Please note that .Fn fido_dev_make_cred is synchronous and will block if necessary. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_make_cred are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_cred_new 3 , .Xr fido_cred_set_authdata 3 libfido2-1.3.1/man/fido_dev_open.3000066400000000000000000000062201362326726700166630ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_OPEN 3 .Os .Sh NAME .Nm fido_dev_open , .Nm fido_dev_close , .Nm fido_dev_cancel , .Nm fido_dev_new , .Nm fido_dev_free , .Nm fido_dev_force_fido2 , .Nm fido_dev_force_u2f , .Nm fido_dev_is_fido2 , .Nm fido_dev_protocol , .Nm fido_dev_build , .Nm fido_dev_flags , .Nm fido_dev_major , .Nm fido_dev_minor .Nd FIDO 2 device open/close and related functions .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_open "fido_dev_t *dev" "const char *path" .Ft int .Fn fido_dev_close "fido_dev_t *dev" .Ft int .Fn fido_dev_cancel "fido_dev_t *dev" .Ft fido_dev_t * .Fn fido_dev_new "void" .Ft void .Fn fido_dev_free "fido_dev_t **dev_p" .Ft void .Fn fido_dev_force_fido2 "fido_dev_t *dev" .Ft void .Fn fido_dev_force_u2f "fido_dev_t *dev" .Ft bool .Fn fido_dev_is_fido2 "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_protocol "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_build "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_flags "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_major "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_minor "const fido_dev_t *dev" .Sh DESCRIPTION The .Fn fido_dev_open function opens the device pointed to by .Fa path , where .Fa dev is a freshly allocated or otherwise closed .Vt fido_dev_t . .Pp The .Fn fido_dev_close function closes the device represented by .Fa dev . If .Fa dev is already closed, .Fn fido_dev_close is a NOP. .Pp The .Fn fido_dev_cancel function cancels any pending requests on .Fa dev . .Pp The .Fn fido_dev_new function returns a pointer to a newly allocated, empty .Vt fido_dev_t . If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_dev_free function releases the memory backing .Fa *dev_p , where .Fa *dev_p must have been previously allocated by .Fn fido_dev_new . On return, .Fa *dev_p is set to NULL. Either .Fa dev_p or .Fa *dev_p may be NULL, in which case .Fn fido_dev_free is a NOP. .Pp The .Fn fido_dev_force_fido2 function can be used to force CTAP2 communication with .Fa dev . .Pp The .Fn fido_dev_force_u2f function can be used to force CTAP1 (U2F) communication with .Fa dev . .Pp The .Fn fido_dev_is_fido2 function returns .Dv true if .Fa dev is a FIDO 2 device. .Pp The .Fn fido_dev_protocol function returns the CTAPHID protocol version identifier of .Fa dev . .Pp The .Fn fido_dev_build function returns the CTAPHID build version number of .Fa dev . .Pp The .Fn fido_dev_flags function returns the CTAPHID capabilities flags of .Fa dev . .Pp The .Fn fido_dev_major function returns the CTAPHID major version number of .Fa dev . .Pp The .Fn fido_dev_minor function returns the CTAPHID minor version number of .Fa dev . .Pp For the format and meaning of the CTAPHID parameters returned by functions above, please refer to the FIDO Client to Authenticator Protocol (CTAP) specification. .Sh RETURN VALUES On success, .Fn fido_dev_open and .Fn fido_dev_close return .Dv FIDO_OK . On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr fido_dev_info_manifest 3 , .Xr fido_dev_set_io_functions 3 libfido2-1.3.1/man/fido_dev_set_io_functions.3000066400000000000000000000046571362326726700213100ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_SET_IO_FUNCTIONS 3 .Os .Sh NAME .Nm fido_dev_set_io_functions .Nd FIDO 2 device I/O interface .Sh SYNOPSIS .In fido.h .Bd -literal typedef void *fido_dev_io_open_t(const char *); typedef void fido_dev_io_close_t(void *); typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); typedef struct fido_dev_io { fido_dev_io_open_t *open; fido_dev_io_close_t *close; fido_dev_io_read_t *read; fido_dev_io_write_t *write; } fido_dev_io_t; .Ed .Ft int .Fn fido_dev_set_io_functions "fido_dev_t *dev" "const fido_dev_io_t *io" .Sh DESCRIPTION The .Nm interface defines the I/O handlers used to talk to .Fa dev . Its usage is optional. By default, .Em libfido2 will use the operating system's native HID interface to talk to a FIDO device. .Pp A .Vt fido_dev_io_open_t function is expected to return a non-NULL opaque pointer on success, and NULL on error. The returned opaque pointer is never dereferenced by .Em libfido2 . .Pp A .Vt fido_dev_io_close_t function receives the opaque handle obtained from .Vt fido_dev_io_open_t . It is not expected to be idempotent. .Pp A .Vt fido_dev_io_read_t function reads from .Fa dev . The first parameter taken is the opaque handle obtained from .Vt fido_dev_io_open_t . The read buffer is pointed to by the second parameter, and the third parameter holds its size. Finally, the last argument passed to .Vt fido_dev_io_read_t is the number of milliseconds the caller is willing to sleep, should the call need to block. If this value holds -1, .Vt fido_dev_io_read_t may block indefinitely. The number of bytes read is returned. On error, -1 is returned. .Pp Conversely, a .Vt fido_dev_io_write_t function writes to .Fa dev . The first parameter taken is the opaque handle returned by .Vt fido_dev_io_open_t . The write buffer is pointed to by the second parameter, and the third parameter holds its size. A .Vt fido_dev_io_write_t function may block. The number of bytes written is returned. On error, -1 is returned. .Pp No references to .Fa io are held by .Fn fido_dev_set_io_functions . .Sh RETURN VALUES On success, .Fn fido_dev_set_io_functions returns .Dv FIDO_OK . On error, a different error code defined in .In fido/err.h is returned. libfido2-1.3.1/man/fido_dev_set_pin.3000066400000000000000000000035751362326726700173750ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_SET_PIN 3 .Os .Sh NAME .Nm fido_dev_set_pin , .Nm fido_dev_get_retry_count , .Nm fido_dev_reset .Nd FIDO 2 device management functions .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_set_pin "fido_dev_t *dev" "const char *pin" "const char *oldpin" .Ft int .Fn fido_dev_get_retry_count "fido_dev_t *dev" "int *retries" .Ft int .Fn fido_dev_reset "fido_dev_t *dev" .Sh DESCRIPTION The .Fn fido_dev_set_pin function sets the PIN of device .Fa dev to .Fa pin , where .Fa pin is a NUL-terminated UTF-8 string. If .Fa oldpin is not NULL, the device's PIN is changed from .Fa oldpin to .Fa pin , where .Fa pin and .Fa oldpin are NUL-terminated UTF-8 strings. .Pp The .Fn fido_dev_get_retry_count function fills .Fa retries with the number of PIN retries left in .Fa dev before lock-out, where .Fa retries is an addressable pointer. .Pp The .Fn fido_dev_reset function performs a reset on .Fa dev , resetting the device's PIN and erasing credentials stored on the device. .Pp Please note that .Fn fido_dev_set_pin , .Fn fido_dev_get_retry_count , and .Fn fido_dev_reset are synchronous and will block if necessary. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_set_pin , .Fn fido_dev_get_retry_count , and .Fn fido_dev_reset are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh CAVEATS Regarding .Fn fido_dev_reset , the actual user-flow to perform a reset is outside the scope of the FIDO2 specification, and may therefore vary depending on the authenticator. Yubico authenticators will return .Dv FIDO_ERR_NOT_ALLOWED if a reset is issued later than 5 seconds after power-up, and .Dv FIDO_ERR_ACTION_TIMEOUT if the user fails to confirm the reset by touching the key within 30 seconds. libfido2-1.3.1/man/fido_init.3000066400000000000000000000013731362326726700160330ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_INIT 3 .Os .Sh NAME .Nm fido_init .Nd initialise the FIDO 2 library .Sh SYNOPSIS .In fido.h .Ft void .Fn fido_init "int flags" .Sh DESCRIPTION The .Fn fido_init function initialises the .Em libfido2 library. Its invocation must precede that of any other .Em libfido2 function. If .Dv FIDO_DEBUG is set in .Fa flags , then debug output will be emitted by .Em libfido2 on .Em stderr . Alternatively, the .Ev FIDO_DEBUG environment variable may be set. .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_cred_new 3 , .Xr fido_dev_info_manifest 3 , .Xr fido_dev_open 3 libfido2-1.3.1/man/fido_strerr.3000066400000000000000000000010661362326726700164100ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_STRERR 3 .Os .Sh NAME .Nm fido_strerr .Nd FIDO 2 error codes .Sh SYNOPSIS .In fido.h .Ft const char * .Fn fido_strerr "int n" .Sh DESCRIPTION The .Fn fido_strerr function translates the error code .Fa n into a readable string, where .Fa n is an error code defined in .In fido/err.h . .Fn fido_strerr never returns NULL. Returned pointers point to static strings. libfido2-1.3.1/man/rs256_pk_new.3000066400000000000000000000044011362326726700163060ustar00rootroot00000000000000.\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 24 2018 $ .Dt RS256_PK_NEW 3 .Os .Sh NAME .Nm rs256_pk_new , .Nm rs256_pk_free , .Nm rs256_pk_from_RSA , .Nm rs256_pk_from_ptr , .Nm rs256_pk_to_EVP_PKEY .Nd FIDO 2 COSE RS256 API .Sh SYNOPSIS .In openssl/rsa.h .In fido/rs256.h .Ft rs256_pk_t * .Fn rs256_pk_new "void" .Ft void .Fn rs256_pk_free "rs256_pk_t **pkp" .Ft int .Fn rs256_pk_from_RSA "rs256_pk_t *pk" "const RSA *rsa" .Ft int .Fn rs256_pk_from_ptr "rs256_pk_t *pk" "const void *ptr" "size_t len" .Ft EVP_PKEY * .Fn rs256_pk_to_EVP_PKEY "const rs256_pk_t *pk" .Sh DESCRIPTION RS256 is the name given in the CBOR Object Signing and Encryption (COSE) RFC to PKCS#1.5 2048-bit RSA with SHA-256. The COSE RS256 API of .Em libfido2 is an auxiliary API with routines to convert between the different RSA public key types used in .Em libfido2 and .Em OpenSSL . .Pp In .Em libfido2 , RS256 public keys are abstracted by the .Vt rs256_pk_t type. .Pp The .Fn rs256_pk_new function returns a pointer to a newly allocated, empty .Vt rs256_pk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn rs256_pk_free function releases the memory backing .Fa *pkp , where .Fa *pkp must have been previously allocated by .Fn rs256_pk_new . On return, .Fa *pkp is set to NULL. Either .Fa pkp or .Fa *pkp may be NULL, in which case .Fn rs256_pk_free is a NOP. .Pp The .Fn rs256_pk_from_RSA function fills .Fa pk with the contents of .Fa rsa . No references to .Fa rsa are kept. .Pp The .Fn rs256_pk_from_ptr function fills .Fa pk with the contents of .Fa ptr , where .Fa ptr points to .Fa len bytes. No references to .Fa ptr are kept. .Pp The .Fn rs256_pk_to_EVP_PKEY function converts .Fa pk to a newly allocated .Fa EVP_PKEY type with a reference count of 1. No internal references to the returned pointer are kept. If an error occurs, .Fn rs256_pk_to_EVP_PKEY returns NULL. .Sh RETURN VALUES The .Fn rs256_pk_from_RSA and .Fn rs256_pk_from_ptr functions return .Dv FIDO_OK on success. On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr eddsa_pk_new 3 , .Xr es256_pk_new 3 , .Xr fido_assert_verify 3 , .Xr fido_cred_pubkey_ptr 3 libfido2-1.3.1/man/style.css000066400000000000000000000012521362326726700156510ustar00rootroot00000000000000* { margin: 0; padding: 0; } body { font-family: monospace; font-size: 1em; margin: 2% auto; max-width: 54em; } ul { margin-left: 1em; } a { color: #009900; } .Sh { font-size: 1em; padding-top: 1em; padding-bottom: 1em; } .foot { padding-top: 1em; } table.head, table.foot { width: 100%; } td.head-rtitle, td.foot-os { text-align: right; } td.head-vol { text-align: center; } div.Pp { margin: 1ex 0ex; } div.Nd, div.Bf, div.Op { display: inline; } span.Pa, span.Ad { font-style: italic; } span.Ms { font-weight: bold; } dl.Bl-diag > dt { font-weight: bold; } code.Nm, code.Fl, code.Cm, code.Ic, code.In, code.Fd, code.Fn, code.Cd { font-weight: bold; font-family: inherit; } libfido2-1.3.1/openbsd-compat/000077500000000000000000000000001362326726700161375ustar00rootroot00000000000000libfido2-1.3.1/openbsd-compat/bsd-getline.c000066400000000000000000000057011362326726700205030ustar00rootroot00000000000000/* $NetBSD: getline.c,v 1.1.1.6 2015/01/02 20:34:27 christos Exp $ */ /* NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* NETBSD ORIGINAL: external/bsd/file/dist/src/getline.c */ #include "openbsd-compat.h" #if 0 #include "file.h" #endif #if !HAVE_GETLINE #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include static ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) { char *ptr, *eptr; if (*buf == NULL || *bufsiz == 0) { if ((*buf = malloc(BUFSIZ)) == NULL) return -1; *bufsiz = BUFSIZ; } for (ptr = *buf, eptr = *buf + *bufsiz;;) { int c = fgetc(fp); if (c == -1) { if (feof(fp)) { ssize_t diff = (ssize_t)(ptr - *buf); if (diff != 0) { *ptr = '\0'; return diff; } } return -1; } *ptr++ = (char)c; if (c == delimiter) { *ptr = '\0'; return ptr - *buf; } if (ptr + 2 >= eptr) { char *nbuf; size_t nbufsiz = *bufsiz * 2; ssize_t d = ptr - *buf; if ((nbuf = realloc(*buf, nbufsiz)) == NULL) return -1; *buf = nbuf; *bufsiz = nbufsiz; eptr = nbuf + nbufsiz; ptr = nbuf + d; } } } ssize_t getline(char **buf, size_t *bufsiz, FILE *fp) { return getdelim(buf, bufsiz, '\n', fp); } #endif #ifdef TEST int main(int argc, char *argv[]) { char *p = NULL; ssize_t len; size_t n = 0; while ((len = getline(&p, &n, stdin)) != -1) (void)printf("%" SIZE_T_FORMAT "d %s", len, p); free(p); return 0; } #endif libfido2-1.3.1/openbsd-compat/bsd-getpagesize.c000066400000000000000000000010011362326726700213500ustar00rootroot00000000000000/* Placed in the public domain */ #include "openbsd-compat.h" #if !defined(HAVE_GETPAGESIZE) #ifdef HAVE_UNISTD_H #include #endif #include int getpagesize(void) { #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) long r = sysconf(_SC_PAGESIZE); if (r > 0 && r < INT_MAX) return (int)r; #endif /* * This is at the lower end of common values and appropriate for * our current use of getpagesize() in recallocarray(). */ return 4096; } #endif /* !defined(HAVE_GETPAGESIZE) */ libfido2-1.3.1/openbsd-compat/diff.sh000077500000000000000000000022451362326726700174110ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. OPENSSH=$(realpath ../../openssh) LIBRESSL=$(realpath ../../libressl-2.8.3) [[ ! -d "${OPENSSH}" || ! -d "${LIBRESSL}" ]] && exit 1 diff -pu bsd-getpagesize.c ${OPENSSH}/openbsd-compat/bsd-getpagesize.c diff -pu err.h ${LIBRESSL}/include/compat/err.h diff -pu explicit_bzero.c ${OPENSSH}/openbsd-compat/explicit_bzero.c diff -pu explicit_bzero_win32.c ${LIBRESSL}/crypto/compat/explicit_bzero_win.c diff -pu getopt.h ${OPENSSH}/openbsd-compat/getopt.h diff -pu getopt_long.c ${OPENSSH}/openbsd-compat/getopt_long.c diff -pu posix_win.c ${LIBRESSL}/crypto/compat/posix_win.c diff -pu readpassphrase.c ${OPENSSH}/openbsd-compat/readpassphrase.c diff -pu readpassphrase.h ${OPENSSH}/openbsd-compat/readpassphrase.h diff -pu recallocarray.c ${OPENSSH}/openbsd-compat/recallocarray.c diff -pu strlcat.c ${OPENSSH}/openbsd-compat/strlcat.c diff -pu strlcpy.c ${OPENSSH}/openbsd-compat/strlcpy.c diff -pu timingsafe_bcmp.c ${OPENSSH}/openbsd-compat/timingsafe_bcmp.c diff -pu types.h ${LIBRESSL}/include/compat/sys/types.h libfido2-1.3.1/openbsd-compat/err.h000066400000000000000000000024451362326726700171050ustar00rootroot00000000000000/* * Public domain * err.h compatibility shim */ #ifndef _COMPAT_ERR_H #define _COMPAT_ERR_H #if !defined(HAVE_ERR_H) #include #include #include #include #include #if defined(_MSC_VER) __declspec(noreturn) #else __attribute__((noreturn)) #endif static inline void err(int eval, const char *fmt, ...) { int sverrno = errno; va_list ap; va_start(ap, fmt); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } va_end(ap); fprintf(stderr, "%s\n", strerror(sverrno)); exit(eval); } #if defined(_MSC_VER) __declspec(noreturn) #else __attribute__((noreturn)) #endif static inline void errx(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (fmt != NULL) vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); exit(eval); } static inline void warn(const char *fmt, ...) { int sverrno = errno; va_list ap; va_start(ap, fmt); if (fmt != NULL) { vfprintf(stderr, fmt, ap); fprintf(stderr, ": "); } va_end(ap); fprintf(stderr, "%s\n", strerror(sverrno)); } static inline void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (fmt != NULL) vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } #endif /* !defined(HAVE_ERR_H) */ #endif /* _COMPAT_ERR_H */ libfido2-1.3.1/openbsd-compat/explicit_bzero.c000066400000000000000000000022311362326726700213230ustar00rootroot00000000000000/* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */ /* $OpenBSD: explicit_bzero.c,v 1.1 2014/01/22 21:06:45 tedu Exp $ */ /* * Public domain. * Written by Ted Unangst */ #include "openbsd-compat.h" #if !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32) #include /* * explicit_bzero - don't let the compiler optimize away bzero */ #ifdef HAVE_MEMSET_S void explicit_bzero(void *p, size_t n) { if (n == 0) return; (void)memset_s(p, n, 0, n); } #else /* HAVE_MEMSET_S */ /* * Indirect bzero through a volatile pointer to hopefully avoid * dead-store optimisation eliminating the call. */ static void (* volatile ssh_bzero)(void *, size_t) = bzero; void explicit_bzero(void *p, size_t n) { if (n == 0) return; /* * clang -fsanitize=memory needs to intercept memset-like functions * to correctly detect memory initialisation. Make sure one is called * directly since our indirection trick above successfully confuses it. */ #if defined(__has_feature) # if __has_feature(memory_sanitizer) memset(p, 0, n); # endif #endif ssh_bzero(p, n); } #endif /* HAVE_MEMSET_S */ #endif /* !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32) */ libfido2-1.3.1/openbsd-compat/explicit_bzero_win32.c000066400000000000000000000005161362326726700223510ustar00rootroot00000000000000/* * Public domain. * Win32 explicit_bzero compatibility shim. */ #include "openbsd-compat.h" #if !defined(HAVE_EXPLICIT_BZERO) && defined(_WIN32) #include #include void explicit_bzero(void *buf, size_t len) { SecureZeroMemory(buf, len); } #endif /* !defined(HAVE_EXPLICIT_BZERO) && defined(_WIN32) */ libfido2-1.3.1/openbsd-compat/getopt.h000066400000000000000000000053221362326726700176140ustar00rootroot00000000000000/* $OpenBSD: getopt.h,v 1.2 2008/06/26 05:42:04 ray Exp $ */ /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _GETOPT_H_ #define _GETOPT_H_ /* * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct option { /* name of long option */ const char *name; /* * one of no_argument, required_argument, and optional_argument: * whether option takes an argument */ int has_arg; /* if not NULL, set *flag to val when option found */ int *flag; /* if flag not NULL, value to set *flag to; else return value */ int val; }; int getopt_long(int, char * const *, const char *, const struct option *, int *); int getopt_long_only(int, char * const *, const char *, const struct option *, int *); #ifndef _GETOPT_DEFINED_ #define _GETOPT_DEFINED_ int getopt(int, char * const *, const char *); int getsubopt(char **, char * const *, char **); extern char *optarg; /* getopt(3) external variables */ extern int opterr; extern int optind; extern int optopt; extern int optreset; extern char *suboptarg; /* getsubopt(3) external variable */ #endif #endif /* !_GETOPT_H_ */ libfido2-1.3.1/openbsd-compat/getopt_long.c000066400000000000000000000343021362326726700206260ustar00rootroot00000000000000/* $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $ */ /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /* * Copyright (c) 2002 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */ #include "openbsd-compat.h" #if !defined(HAVE_GETOPT) #if 0 #include #include #endif #include #include #include #include int opterr = 1; /* if error message should be printed */ int optind = 1; /* index into parent argv vector */ int optopt = '?'; /* character checked for validity */ int optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define PRINT_ERROR ((opterr) && (*options != ':')) #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ /* return values */ #define BADCH (int)'?' #define BADARG ((*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 #define EMSG "" static int getopt_internal(int, char * const *, const char *, const struct option *, int *, int); static int parse_long_options(char * const *, const char *, const struct option *, int *, int); static int gcd(int, int); static void permute_args(int, int, int, char * const *); static char *place = EMSG; /* option letter processing */ /* XXX: set optreset to 1 rather than these two */ static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; /* * Compute the greatest common divisor of a and b. */ static int gcd(int a, int b) { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return (b); } /* * Exchange the block from nonopt_start to nonopt_end with the block * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char * const *nargv) { int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; char *swap; /* * compute lengths of blocks and number and size of cycles */ nnonopts = panonopt_end - panonopt_start; nopts = opt_end - panonopt_end; ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; swap = nargv[pos]; /* LINTED const cast */ ((char **) nargv)[pos] = nargv[cstart]; /* LINTED const cast */ ((char **)nargv)[cstart] = swap; } } } /* * parse_long_options -- * Parse long options in argc/argv argument vector. * Returns -1 if short_too is set and the option does not match long_options. */ static int parse_long_options(char * const *nargv, const char *options, const struct option *long_options, int *idx, int short_too) { char *current_argv, *has_equal; size_t current_argv_len; int i, match; current_argv = place; match = -1; optind++; if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == current_argv_len) { /* exact match */ match = i; break; } /* * If this is a known short option, don't allow * a partial match of a single character. */ if (short_too && current_argv_len == 1) continue; if (match == -1) /* partial match */ match = i; else { /* ambiguous abbreviation */ if (PRINT_ERROR) warnx(ambig, (int)current_argv_len, current_argv); optopt = 0; return (BADCH); } } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) warnx(noarg, (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; return (BADARG); } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use next nargv */ optarg = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' indicates no error * should be generated. */ if (PRINT_ERROR) warnx(recargstring, current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; --optind; return (BADARG); } } else { /* unknown option */ if (short_too) { --optind; return (-1); } if (PRINT_ERROR) warnx(illoptstring, current_argv); optopt = 0; return (BADCH); } if (idx) *idx = match; if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; return (0); } else return (long_options[match].val); } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. */ static int getopt_internal(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx, int flags) { char *oli; /* option letter list index */ int optchar, short_too; static int posixly_correct = -1; if (options == NULL) return (-1); /* * XXX Some GNU programs (like cvs) set optind to 0 instead of * XXX using optreset. Work around this braindamage. */ if (optind == 0) optind = optreset = 1; /* * Disable GNU extensions if POSIXLY_CORRECT is set or options * string begins with a '+'. */ if (posixly_correct == -1 || optreset) posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); if (*options == '-') flags |= FLAG_ALLARGS; else if (posixly_correct || *options == '+') flags &= ~FLAG_PERMUTE; if (*options == '+' || *options == '-') options++; optarg = NULL; if (optreset) nonopt_start = nonopt_end = -1; start: if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } if (*(place = nargv[optind]) != '-' || (place[1] == '\0' && strchr(options, '-') == NULL)) { place = EMSG; /* found non-option */ if (flags & FLAG_ALLARGS) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return (INORDER); } if (!(flags & FLAG_PERMUTE)) { /* * If no permutation wanted, stop parsing * at first non-option. */ return (-1); } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; /* * If we have "-" do nothing, if "--" we are done. */ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { optind++; place = EMSG; /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } } /* * Check long options if: * 1) we were passed some * 2) the arg is not just "-" * 3) either the arg starts with -- we are getopt_long_only() */ if (long_options != NULL && place != nargv[optind] && (*place == '-' || (flags & FLAG_LONGONLY))) { short_too = 0; if (*place == '-') place++; /* --foo long option */ else if (*place != ':' && strchr(options, *place) != NULL) short_too = 1; /* could be short option too */ optchar = parse_long_options(nargv, options, long_options, idx, short_too); if (optchar != -1) { place = EMSG; return (optchar); } } if ((optchar = (int)*place++) == (int)':' || (optchar == (int)'-' && *place != '\0') || (oli = strchr(options, optchar)) == NULL) { /* * If the user specified "-" and '-' isn't listed in * options, return -1 (non-option) as per POSIX. * Otherwise, it is an unknown option character (or ':'). */ if (optchar == (int)'-' && *place == '\0') return (-1); if (!*place) ++optind; if (PRINT_ERROR) warnx(illoptchar, optchar); optopt = optchar; return (BADCH); } if (long_options != NULL && optchar == 'W' && oli[1] == ';') { /* -W long-option */ if (*place) /* no space */ /* NOTHING */; else if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return (BADARG); } else /* white space */ place = nargv[optind]; optchar = parse_long_options(nargv, options, long_options, idx, 0); place = EMSG; return (optchar); } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return (BADARG); } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return (optchar); } /* * getopt -- * Parse argc/argv argument vector. * * [eventually this will replace the BSD getopt] */ int getopt(int nargc, char * const *nargv, const char *options) { /* * We don't pass FLAG_PERMUTE to getopt_internal() since * the BSD getopt(3) (unlike GNU) has never done this. * * Furthermore, since many privileged programs call getopt() * before dropping privileges it makes sense to keep things * as simple (and bug-free) as possible. */ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); } #if 0 /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE)); } /* * getopt_long_only -- * Parse argc/argv argument vector. */ int getopt_long_only(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE|FLAG_LONGONLY)); } #endif #endif /* !defined(HAVE_GETOPT) */ libfido2-1.3.1/openbsd-compat/openbsd-compat.h000066400000000000000000000035301362326726700212240ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _OPENBSD_COMPAT_H #define _OPENBSD_COMPAT_H #if defined(_MSC_VER) #include "types.h" #endif #if defined(HAVE_ENDIAN_H) #include #endif #if defined(__APPLE__) && !defined(HAVE_ENDIAN_H) #include #define be16toh(x) OSSwapBigToHostInt16((x)) #define htobe16(x) OSSwapHostToBigInt16((x)) #define be32toh(x) OSSwapBigToHostInt32((x)) #endif /* __APPLE__ && !HAVE_ENDIAN_H */ #if defined(_WIN32) && !defined(HAVE_ENDIAN_H) #include #if !defined(_MSC_VER) #include #endif #define be16toh(x) ntohs((x)) #define htobe16(x) htons((x)) #define be32toh(x) ntohl((x)) #endif /* _WIN32 && !HAVE_ENDIAN_H */ #include #if !defined(HAVE_STRLCAT) size_t strlcat(char *, const char *, size_t); #endif #if !defined(HAVE_STRLCPY) size_t strlcpy(char *, const char *, size_t); #endif #if !defined(HAVE_RECALLOCARRAY) void *recallocarray(void *, size_t, size_t, size_t); #endif #if !defined(HAVE_EXPLICIT_BZERO) void explicit_bzero(void *, size_t); #endif #if !defined(HAVE_GETPAGESIZE) int getpagesize(void); #endif #if !defined(HAVE_TIMINGSAFE_BCMP) int timingsafe_bcmp(const void *, const void *, size_t); #endif #if !defined(HAVE_READPASSPHRASE) #include "readpassphrase.h" #else #include #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L #define EVP_PKEY_get0_EC_KEY(x) ((x)->pkey.ec) #define EVP_PKEY_get0_RSA(x) ((x)->pkey.rsa) #endif #if !defined(HAVE_ERR_H) #include "err.h" #else #include #endif #if !defined(HAVE_GETOPT) #include "getopt.h" #else #include #endif #if !defined(HAVE_GETLINE) #include ssize_t getline(char **, size_t *, FILE *); #endif #endif /* !_OPENBSD_COMPAT_H */ libfido2-1.3.1/openbsd-compat/posix_win.c000066400000000000000000000015311362326726700203220ustar00rootroot00000000000000/* * Public domain * * File IO compatibility shims * Brent Cook */ #define NO_REDEF_POSIX_FUNCTIONS #include #include #include #include "posix_win.h" int posix_open(const char *path, ...) { va_list ap; int mode = 0; int flags; va_start(ap, path); flags = va_arg(ap, int); if (flags & O_CREAT) mode = va_arg(ap, int); va_end(ap); flags |= O_BINARY | O_NOINHERIT; return (open(path, flags, mode)); } int posix_close(int fd) { return (close(fd)); } ssize_t posix_read(int fd, void *buf, size_t count) { if (count > INT_MAX) { errno = EINVAL; return (-1); } return (read(fd, buf, (unsigned int)count)); } ssize_t posix_write(int fd, const void *buf, size_t count) { if (count > INT_MAX) { errno = EINVAL; return (-1); } return (write(fd, buf, (unsigned int)count)); } libfido2-1.3.1/openbsd-compat/posix_win.h000066400000000000000000000016141362326726700203310ustar00rootroot00000000000000/* * Public domain * * BSD socket emulation code for Winsock2 * Brent Cook */ #ifndef _COMPAT_POSIX_WIN_H #define _COMPAT_POSIX_WIN_H #ifdef _WIN32 #include #include #include #include #include #include #include #if _MSC_VER >= 1900 #include <../ucrt/fcntl.h> #else #include <../include/fcntl.h> #endif #include "types.h" int posix_open(const char *path, ...); int posix_close(int fd); ssize_t posix_read(int fd, void *buf, size_t count); ssize_t posix_write(int fd, const void *buf, size_t count); #ifndef NO_REDEF_POSIX_FUNCTIONS #define open(path, ...) posix_open(path, __VA_ARGS__) #define close(fd) posix_close(fd) #define read(fd, buf, count) posix_read(fd, buf, count) #define write(fd, buf, count) posix_write(fd, buf, count) #endif #endif /* _WIN32 */ #endif /* !_COMPAT_POSIX_WIN_H */ libfido2-1.3.1/openbsd-compat/readpassphrase.c000066400000000000000000000135121362326726700213120ustar00rootroot00000000000000/* $OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $ */ /* * Copyright (c) 2000-2002, 2007, 2010 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */ #include "openbsd-compat.h" #ifndef HAVE_READPASSPHRASE #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifndef _PATH_TTY # define _PATH_TTY "/dev/tty" #endif #ifndef TCSASOFT /* If we don't have TCSASOFT define it so that ORing it it below is a no-op. */ # define TCSASOFT 0 #endif /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ #if !defined(_POSIX_VDISABLE) && defined(VDISABLE) # define _POSIX_VDISABLE VDISABLE #endif static volatile sig_atomic_t signo[_NSIG]; static void handler(int); char * readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) { ssize_t nr; int input, output, save_errno, i, need_restart; char ch, *p, *end; struct termios term, oterm; struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; struct sigaction savetstp, savettin, savettou, savepipe; /* I suppose we could alloc on demand in this case (XXX). */ if (bufsiz == 0) { errno = EINVAL; return(NULL); } restart: for (i = 0; i < _NSIG; i++) signo[i] = 0; need_restart = 0; /* * Read and write to /dev/tty if available. If not, read from * stdin and write to stderr unless a tty is required. */ if ((flags & RPP_STDIN) || (input = output = open(_PATH_TTY, O_RDWR)) == -1) { if (flags & RPP_REQUIRE_TTY) { errno = ENOTTY; return(NULL); } input = STDIN_FILENO; output = STDERR_FILENO; } /* * Turn off echo if possible. * If we are using a tty but are not the foreground pgrp this will * generate SIGTTOU, so do it *before* installing the signal handlers. */ if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { memcpy(&term, &oterm, sizeof(term)); if (!(flags & RPP_ECHO_ON)) term.c_lflag &= ~(ECHO | ECHONL); #ifdef VSTATUS if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) term.c_cc[VSTATUS] = _POSIX_VDISABLE; #endif (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); } else { memset(&term, 0, sizeof(term)); term.c_lflag |= ECHO; memset(&oterm, 0, sizeof(oterm)); oterm.c_lflag |= ECHO; } /* * Catch signals that would otherwise cause the user to end * up with echo turned off in the shell. Don't worry about * things like SIGXCPU and SIGVTALRM for now. */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; /* don't restart system calls */ sa.sa_handler = handler; (void)sigaction(SIGALRM, &sa, &savealrm); (void)sigaction(SIGHUP, &sa, &savehup); (void)sigaction(SIGINT, &sa, &saveint); (void)sigaction(SIGPIPE, &sa, &savepipe); (void)sigaction(SIGQUIT, &sa, &savequit); (void)sigaction(SIGTERM, &sa, &saveterm); (void)sigaction(SIGTSTP, &sa, &savetstp); (void)sigaction(SIGTTIN, &sa, &savettin); (void)sigaction(SIGTTOU, &sa, &savettou); if (!(flags & RPP_STDIN)) (void)write(output, prompt, strlen(prompt)); end = buf + bufsiz - 1; p = buf; while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { if (p < end) { if ((flags & RPP_SEVENBIT)) ch &= 0x7f; if (isalpha((unsigned char)ch)) { if ((flags & RPP_FORCELOWER)) ch = (char)tolower((unsigned char)ch); if ((flags & RPP_FORCEUPPER)) ch = (char)toupper((unsigned char)ch); } *p++ = ch; } } *p = '\0'; save_errno = errno; if (!(term.c_lflag & ECHO)) (void)write(output, "\n", 1); /* Restore old terminal settings and signals. */ if (memcmp(&term, &oterm, sizeof(term)) != 0) { const int sigttou = signo[SIGTTOU]; /* Ignore SIGTTOU generated when we are not the fg pgrp. */ while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 && errno == EINTR && !signo[SIGTTOU]) continue; signo[SIGTTOU] = sigttou; } (void)sigaction(SIGALRM, &savealrm, NULL); (void)sigaction(SIGHUP, &savehup, NULL); (void)sigaction(SIGINT, &saveint, NULL); (void)sigaction(SIGQUIT, &savequit, NULL); (void)sigaction(SIGPIPE, &savepipe, NULL); (void)sigaction(SIGTERM, &saveterm, NULL); (void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTTIN, &savettin, NULL); (void)sigaction(SIGTTOU, &savettou, NULL); if (input != STDIN_FILENO) (void)close(input); /* * If we were interrupted by a signal, resend it to ourselves * now that we have restored the signal handlers. */ for (i = 0; i < _NSIG; i++) { if (signo[i]) { kill(getpid(), i); switch (i) { case SIGTSTP: case SIGTTIN: case SIGTTOU: need_restart = 1; } } } if (need_restart) goto restart; if (save_errno) errno = save_errno; return(nr == -1 ? NULL : buf); } #if 0 char * getpass(const char *prompt) { static char buf[_PASSWORD_LEN + 1]; return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); } #endif static void handler(int s) { signo[s] = 1; } #endif /* HAVE_READPASSPHRASE */ libfido2-1.3.1/openbsd-compat/readpassphrase.h000066400000000000000000000033541362326726700213220ustar00rootroot00000000000000/* $OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $ */ /* * Copyright (c) 2000, 2002 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ /* OPENBSD ORIGINAL: include/readpassphrase.h */ #ifndef _READPASSPHRASE_H_ #define _READPASSPHRASE_H_ #ifndef HAVE_READPASSPHRASE #define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ #define RPP_ECHO_ON 0x01 /* Leave echo on. */ #define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ #define RPP_FORCELOWER 0x04 /* Force input to lower case. */ #define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ #define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ #define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */ char * readpassphrase(const char *, char *, size_t, int); #endif /* HAVE_READPASSPHRASE */ #endif /* !_READPASSPHRASE_H_ */ libfido2-1.3.1/openbsd-compat/readpassphrase_win32.c000066400000000000000000000067611362326726700223440ustar00rootroot00000000000000/* * Author: Manoj Ampalam * * Author: Bryan Berns * Modified group detection use s4u token information * * Copyright(c) 2016 Microsoft Corp. * All rights reserved * * Misc Unix POSIX routine implementations for Windows * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met : * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and / or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define UMDF_USING_NTSTATUS #define SECURITY_WIN32 #include #include #include #include #include #include #include #include #include #include #include #include #include "openbsd-compat.h" #ifndef HAVE_READPASSPHRASE /*on error returns NULL and sets errno*/ static wchar_t * utf8_to_utf16(const char *utf8) { int needed = 0; wchar_t* utf16 = NULL; if ((needed = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) == 0 || (utf16 = malloc(needed * sizeof(wchar_t))) == NULL || MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0) { /* debug3("failed to convert utf8 payload:%s error:%d", utf8, GetLastError()); */ errno = ENOMEM; return NULL; } return utf16; } char * readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags) { size_t current_index = 0; char ch; wchar_t* wtmp = NULL; if (outBufLen == 0) { errno = EINVAL; return NULL; } while (_kbhit()) _getch(); wtmp = utf8_to_utf16(prompt); if (wtmp == NULL) errx(1, "unable to alloc memory"); _cputws(wtmp); free(wtmp); while (current_index < outBufLen - 1) { ch = (char)_getch(); if (ch == '\r') { if (_kbhit()) _getch(); /* read linefeed if its there */ break; } else if (ch == '\n') { break; } else if (ch == '\b') { /* backspace */ if (current_index > 0) { if (flags & RPP_ECHO_ON) printf_s("%c \b", ch); current_index--; /* overwrite last character */ } } else if (ch == '\003') { /* exit on Ctrl+C */ errx(1, ""); } else { if (flags & RPP_SEVENBIT) ch &= 0x7f; if (isalpha((unsigned char)ch)) { if(flags & RPP_FORCELOWER) ch = (char)tolower((unsigned char)ch); if(flags & RPP_FORCEUPPER) ch = (char)toupper((unsigned char)ch); } outBuf[current_index++] = ch; if(flags & RPP_ECHO_ON) printf_s("%c", ch); } } outBuf[current_index] = '\0'; _cputs("\n"); return outBuf; } #endif /* HAVE_READPASSPHRASE */ libfido2-1.3.1/openbsd-compat/recallocarray.c000066400000000000000000000046631362326726700211370ustar00rootroot00000000000000/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */ /* * Copyright (c) 2008, 2017 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */ #include "openbsd-compat.h" #if !defined(HAVE_RECALLOCARRAY) #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) { size_t oldsize, newsize; void *newptr; if (ptr == NULL) return calloc(newnmemb, size); if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && newnmemb > 0 && SIZE_MAX / newnmemb < size) { errno = ENOMEM; return NULL; } newsize = newnmemb * size; if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { errno = EINVAL; return NULL; } oldsize = oldnmemb * size; /* * Don't bother too much if we're shrinking just a bit, * we do not shrink for series of small steps, oh well. */ if (newsize <= oldsize) { size_t d = oldsize - newsize; if (d < oldsize / 2 && d < (size_t)getpagesize()) { memset((char *)ptr + newsize, 0, d); return ptr; } } newptr = malloc(newsize); if (newptr == NULL) return NULL; if (newsize > oldsize) { memcpy(newptr, ptr, oldsize); memset((char *)newptr + oldsize, 0, newsize - oldsize); } else memcpy(newptr, ptr, newsize); explicit_bzero(ptr, oldsize); free(ptr); return newptr; } /* DEF_WEAK(recallocarray); */ #endif /* !defined(HAVE_RECALLOCARRAY) */ libfido2-1.3.1/openbsd-compat/strlcat.c000066400000000000000000000034441362326726700177640ustar00rootroot00000000000000/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ #include "openbsd-compat.h" #if !defined(HAVE_STRLCAT) #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif /* !defined(HAVE_STRLCAT) */ libfido2-1.3.1/openbsd-compat/strlcpy.c000066400000000000000000000032521362326726700200050ustar00rootroot00000000000000/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ #include "openbsd-compat.h" #if !defined(HAVE_STRLCPY) #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif /* !defined(HAVE_STRLCPY) */ libfido2-1.3.1/openbsd-compat/timingsafe_bcmp.c000066400000000000000000000023111362326726700214270ustar00rootroot00000000000000/* $OpenBSD: timingsafe_bcmp.c,v 1.1 2010/09/24 13:33:00 matthew Exp $ */ /* * Copyright (c) 2010 Damien Miller. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/string/timingsafe_bcmp.c */ #include "openbsd-compat.h" #if !defined(HAVE_TIMINGSAFE_BCMP) int timingsafe_bcmp(const void *b1, const void *b2, size_t n) { const unsigned char *p1 = b1, *p2 = b2; int ret = 0; for (; n > 0; n--) ret |= *p1++ ^ *p2++; return (ret != 0); } #endif /* !defined(HAVE_TIMINGSAFE_BCMP) */ libfido2-1.3.1/openbsd-compat/types.h000066400000000000000000000024321362326726700174550ustar00rootroot00000000000000/* * Public domain * sys/types.h compatibility shim */ #ifdef _MSC_VER #if _MSC_VER >= 1900 #include <../ucrt/sys/types.h> #else #include <../include/sys/types.h> #endif #endif #ifndef _COMPAT_TYPES_H #define _COMPAT_TYPES_H #include #ifdef __MINGW32__ #include <_bsd_types.h> typedef uint32_t in_addr_t; typedef uint32_t uid_t; #endif #ifdef _MSC_VER typedef unsigned char u_char; typedef unsigned short u_short; typedef unsigned int u_int; typedef uint32_t in_addr_t; typedef uint32_t mode_t; typedef uint32_t uid_t; #include typedef SSIZE_T ssize_t; #ifndef SSIZE_MAX #ifdef _WIN64 #define SSIZE_MAX _I64_MAX #else #define SSIZE_MAX INT_MAX #endif #endif #endif #if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) # define __bounded__(x, y, z) #endif #ifdef _WIN32 #define __warn_references(sym,msg) #else #ifndef __warn_references #ifndef __STRING #define __STRING(x) #x #endif #if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG) #define __warn_references(sym,msg) \ __asm__(".section .gnu.warning." __STRING(sym) \ "\n\t.ascii \"" msg "\"\n\t.text"); #else #define __warn_references(sym,msg) #endif #endif /* __warn_references */ #endif /* _WIN32 */ #endif /* !_COMPAT_TYPES_H */ libfido2-1.3.1/regress/000077500000000000000000000000001362326726700146765ustar00rootroot00000000000000libfido2-1.3.1/regress/CMakeLists.txt000066400000000000000000000012201362326726700174310ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. # cred add_executable(regress_cred cred.c) target_link_libraries(regress_cred fido2_shared) add_custom_command(TARGET regress_cred POST_BUILD COMMAND regress_cred) # assert add_executable(regress_assert assert.c) target_link_libraries(regress_assert fido2_shared) add_custom_command(TARGET regress_assert POST_BUILD COMMAND regress_assert) # dev add_executable(regress_dev dev.c) target_link_libraries(regress_dev fido2_shared) add_custom_command(TARGET regress_dev POST_BUILD COMMAND regress_dev) libfido2-1.3.1/regress/assert.c000066400000000000000000000323121362326726700163440ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) static const unsigned char es256_pk[64] = { 0x34, 0xeb, 0x99, 0x77, 0x02, 0x9c, 0x36, 0x38, 0xbb, 0xc2, 0xae, 0xa0, 0xa0, 0x18, 0xc6, 0x64, 0xfc, 0xe8, 0x49, 0x92, 0xd7, 0x74, 0x9e, 0x0c, 0x46, 0x8c, 0x9d, 0xa6, 0xdf, 0x46, 0xf7, 0x84, 0x60, 0x1e, 0x0f, 0x8b, 0x23, 0x85, 0x4a, 0x9a, 0xec, 0xc1, 0x08, 0x9f, 0x30, 0xd0, 0x0d, 0xd7, 0x76, 0x7b, 0x55, 0x48, 0x91, 0x7c, 0x4f, 0x0f, 0x64, 0x1a, 0x1d, 0xf8, 0xbe, 0x14, 0x90, 0x8a, }; static const unsigned char cdh[32] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, }; static const unsigned char authdata[39] = { 0x58, 0x25, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x00, 0x00, 0x00, 0x00, 0x03, }; static const unsigned char sig[72] = { 0x30, 0x46, 0x02, 0x21, 0x00, 0xf6, 0xd1, 0xa3, 0xd5, 0x24, 0x2b, 0xde, 0xee, 0xa0, 0x90, 0x89, 0xcd, 0xf8, 0x9e, 0xbd, 0x6b, 0x4d, 0x55, 0x79, 0xe4, 0xc1, 0x42, 0x27, 0xb7, 0x9b, 0x9b, 0xa4, 0x0a, 0xe2, 0x47, 0x64, 0x0e, 0x02, 0x21, 0x00, 0xe5, 0xc9, 0xc2, 0x83, 0x47, 0x31, 0xc7, 0x26, 0xe5, 0x25, 0xb2, 0xb4, 0x39, 0xa7, 0xfc, 0x3d, 0x70, 0xbe, 0xe9, 0x81, 0x0d, 0x4a, 0x62, 0xa9, 0xab, 0x4a, 0x91, 0xc0, 0x7d, 0x2d, 0x23, 0x1e, }; static void * dummy_open(const char *path) { (void)path; return (FAKE_DEV_HANDLE); } static void dummy_close(void *handle) { assert(handle == FAKE_DEV_HANDLE); } static int dummy_read(void *handle, unsigned char *buf, size_t len, int ms) { (void)handle; (void)buf; (void)len; (void)ms; abort(); /* NOTREACHED */ } static int dummy_write(void *handle, const unsigned char *buf, size_t len) { (void)handle; (void)buf; (void)len; abort(); /* NOTREACHED */ } static fido_assert_t * alloc_assert(void) { fido_assert_t *a; a = fido_assert_new(); assert(a != NULL); return (a); } static void free_assert(fido_assert_t *a) { fido_assert_free(&a); assert(a == NULL); } static fido_dev_t * alloc_dev(void) { fido_dev_t *d; d = fido_dev_new(); assert(d != NULL); return (d); } static void free_dev(fido_dev_t *d) { fido_dev_free(&d); assert(d == NULL); } static es256_pk_t * alloc_es256_pk(void) { es256_pk_t *pk; pk = es256_pk_new(); assert(pk != NULL); return (pk); } static void free_es256_pk(es256_pk_t *pk) { es256_pk_free(&pk); assert(pk == NULL); } static rs256_pk_t * alloc_rs256_pk(void) { rs256_pk_t *pk; pk = rs256_pk_new(); assert(pk != NULL); return (pk); } static void free_rs256_pk(rs256_pk_t *pk) { rs256_pk_free(&pk); assert(pk == NULL); } static void empty_assert(fido_dev_t *d, fido_assert_t *a, int idx) { es256_pk_t *es256; rs256_pk_t *rs256; assert(fido_assert_flags(a, idx) == 0); assert(fido_assert_authdata_len(a, idx) == 0); assert(fido_assert_authdata_ptr(a, idx) == NULL); assert(fido_assert_clientdata_hash_len(a) == 0); assert(fido_assert_clientdata_hash_ptr(a) == NULL); assert(fido_assert_id_len(a, idx) == 0); assert(fido_assert_id_ptr(a, idx) == NULL); assert(fido_assert_rp_id(a) == NULL); assert(fido_assert_sig_len(a, idx) == 0); assert(fido_assert_sig_ptr(a, idx) == NULL); assert(fido_assert_user_display_name(a, idx) == NULL); assert(fido_assert_user_icon(a, idx) == NULL); assert(fido_assert_user_id_len(a, idx) == 0); assert(fido_assert_user_id_ptr(a, idx) == NULL); assert(fido_assert_user_name(a, idx) == NULL); es256 = alloc_es256_pk(); rs256 = alloc_rs256_pk(); fido_dev_force_u2f(d); assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, COSE_ES256, idx, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, COSE_ES256, idx, es256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, COSE_RS256, idx, rs256) == FIDO_ERR_INVALID_ARGUMENT); fido_dev_force_fido2(d); assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, COSE_ES256, idx, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, COSE_ES256, idx, es256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, COSE_RS256, idx, rs256) == FIDO_ERR_INVALID_ARGUMENT); free_es256_pk(es256); free_rs256_pk(rs256); } static void empty_assert_tests(void) { fido_assert_t *a; fido_dev_t *d; fido_dev_io_t io_f; int i; a = alloc_assert(); d = alloc_dev(); io_f.open = dummy_open; io_f.close = dummy_close; io_f.read = dummy_read; io_f.write = dummy_write; assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); empty_assert(d, a, 0); assert(fido_assert_count(a) == 0); assert(fido_assert_set_count(a, 4) == FIDO_OK); assert(fido_assert_count(a) == 4); for (i = 0; i < 4; i++) { empty_assert(d, a, i); } empty_assert(d, a, 10); free_assert(a); free_dev(d); } static void valid_assert(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_OK); free_assert(a); free_es256_pk(pk); } static void no_cdh(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void no_rp(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void no_authdata(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void no_sig(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void junk_cdh(void) { fido_assert_t *a; es256_pk_t *pk; unsigned char *junk; junk = malloc(sizeof(cdh)); assert(junk != NULL); memcpy(junk, cdh, sizeof(cdh)); junk[0] = ~junk[0]; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, junk, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG); free_assert(a); free_es256_pk(pk); free(junk); } static void junk_rp(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "potato") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_PARAM); free_assert(a); free_es256_pk(pk); } static void junk_authdata(void) { fido_assert_t *a; unsigned char *junk; junk = malloc(sizeof(authdata)); assert(junk != NULL); memcpy(junk, authdata, sizeof(authdata)); junk[0] = ~junk[0]; a = alloc_assert(); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, junk, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free(junk); } static void junk_sig(void) { fido_assert_t *a; es256_pk_t *pk; unsigned char *junk; junk = malloc(sizeof(sig)); assert(junk != NULL); memcpy(junk, sig, sizeof(sig)); junk[0] = ~junk[0]; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, junk, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG); free_assert(a); free_es256_pk(pk); free(junk); } static void wrong_options(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_TRUE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_PARAM); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_TRUE) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_PARAM); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_OK); free_assert(a); free_es256_pk(pk); } /* cbor_serialize_alloc misuse */ static void bad_cbor_serialize(void) { fido_assert_t *a; a = alloc_assert(); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_authdata_len(a, 0) == sizeof(authdata)); free_assert(a); } int main(void) { fido_init(0); empty_assert_tests(); valid_assert(); no_cdh(); no_rp(); no_authdata(); no_sig(); junk_cdh(); junk_rp(); junk_authdata(); junk_sig(); wrong_options(); bad_cbor_serialize(); exit(0); } libfido2-1.3.1/regress/cred.c000066400000000000000000000675011362326726700157700ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) static const unsigned char cdh[32] = { 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, }; static const unsigned char authdata[198] = { 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; static const unsigned char authdata_dupkeys[200] = { 0x58, 0xc6, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 0xa6, 0x01, 0x02, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; static const unsigned char authdata_unsorted_keys[198] = { 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 0xa5, 0x03, 0x26, 0x01, 0x02, 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; static const unsigned char x509[742] = { 0x30, 0x82, 0x02, 0xe2, 0x30, 0x81, 0xcb, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x31, 0x35, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x34, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x45, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xdb, 0x0a, 0xdb, 0xf5, 0x21, 0xc7, 0x5c, 0xce, 0x63, 0xdc, 0xa6, 0xe1, 0xe8, 0x25, 0x06, 0x0d, 0x94, 0xe6, 0x27, 0x54, 0x19, 0x4f, 0x9d, 0x24, 0xaf, 0x26, 0x1a, 0xbe, 0xad, 0x99, 0x44, 0x1f, 0x95, 0xa3, 0x71, 0x91, 0x0a, 0x3a, 0x20, 0xe7, 0x3e, 0x91, 0x5e, 0x13, 0xe8, 0xbe, 0x38, 0x05, 0x7a, 0xd5, 0x7a, 0xa3, 0x7e, 0x76, 0x90, 0x8f, 0xaf, 0xe2, 0x8a, 0x94, 0xb6, 0x30, 0xeb, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x95, 0x40, 0x6b, 0x50, 0x61, 0x7d, 0xad, 0x84, 0xa3, 0xb4, 0xeb, 0x88, 0x0f, 0xe3, 0x30, 0x0f, 0x2d, 0xa2, 0x0a, 0x00, 0xd9, 0x25, 0x04, 0xee, 0x72, 0xfa, 0x67, 0xdf, 0x58, 0x51, 0x0f, 0x0b, 0x47, 0x02, 0x9c, 0x3e, 0x41, 0x29, 0x4a, 0x93, 0xac, 0x29, 0x85, 0x89, 0x2d, 0xa4, 0x7a, 0x81, 0x32, 0x28, 0x57, 0x71, 0x01, 0xef, 0xa8, 0x42, 0x88, 0x16, 0x96, 0x37, 0x91, 0xd5, 0xdf, 0xe0, 0x8f, 0xc9, 0x3c, 0x8d, 0xb0, 0xcd, 0x89, 0x70, 0x82, 0xec, 0x79, 0xd3, 0xc6, 0x78, 0x73, 0x29, 0x32, 0xe5, 0xab, 0x6c, 0xbd, 0x56, 0x9f, 0xd5, 0x45, 0x91, 0xce, 0xc1, 0xdd, 0x8d, 0x64, 0xdc, 0xe9, 0x9c, 0x1f, 0x5e, 0x3c, 0xd2, 0xaf, 0x51, 0xa5, 0x82, 0x18, 0xaf, 0xe0, 0x37, 0xe7, 0x32, 0x9e, 0x76, 0x05, 0x77, 0x02, 0x7b, 0xe6, 0x24, 0xa0, 0x31, 0x56, 0x1b, 0xfd, 0x19, 0xc5, 0x71, 0xd3, 0xf0, 0x9e, 0xc0, 0x73, 0x05, 0x4e, 0xbc, 0x85, 0xb8, 0x53, 0x9e, 0xef, 0xc5, 0xbc, 0x9c, 0x56, 0xa3, 0xba, 0xd9, 0x27, 0x6a, 0xbb, 0xa9, 0x7a, 0x40, 0xd7, 0x47, 0x8b, 0x55, 0x72, 0x6b, 0xe3, 0xfe, 0x28, 0x49, 0x71, 0x24, 0xf4, 0x8f, 0xf4, 0x20, 0x81, 0xea, 0x38, 0xff, 0x7c, 0x0a, 0x4f, 0xdf, 0x02, 0x82, 0x39, 0x81, 0x82, 0x3b, 0xca, 0x09, 0xdd, 0xca, 0xaa, 0x0f, 0x27, 0xf5, 0xa4, 0x83, 0x55, 0x6c, 0x9a, 0x39, 0x9b, 0x15, 0x3a, 0x16, 0x63, 0xdc, 0x5b, 0xf9, 0xac, 0x5b, 0xbc, 0xf7, 0x9f, 0xbe, 0x0f, 0x8a, 0xa2, 0x3c, 0x31, 0x13, 0xa3, 0x32, 0x48, 0xca, 0x58, 0x87, 0xf8, 0x7b, 0xa0, 0xa1, 0x0a, 0x6a, 0x60, 0x96, 0x93, 0x5f, 0x5d, 0x26, 0x9e, 0x63, 0x1d, 0x09, 0xae, 0x9a, 0x41, 0xe5, 0xbd, 0x08, 0x47, 0xfe, 0xe5, 0x09, 0x9b, 0x20, 0xfd, 0x12, 0xe2, 0xe6, 0x40, 0x7f, 0xba, 0x4a, 0x61, 0x33, 0x66, 0x0d, 0x0e, 0x73, 0xdb, 0xb0, 0xd5, 0xa2, 0x9a, 0x9a, 0x17, 0x0d, 0x34, 0x30, 0x85, 0x6a, 0x42, 0x46, 0x9e, 0xff, 0x34, 0x8f, 0x5f, 0x87, 0x6c, 0x35, 0xe7, 0xa8, 0x4d, 0x35, 0xeb, 0xc1, 0x41, 0xaa, 0x8a, 0xd2, 0xda, 0x19, 0xaa, 0x79, 0xa2, 0x5f, 0x35, 0x2c, 0xa0, 0xfd, 0x25, 0xd3, 0xf7, 0x9d, 0x25, 0x18, 0x2d, 0xfa, 0xb4, 0xbc, 0xbb, 0x07, 0x34, 0x3c, 0x8d, 0x81, 0xbd, 0xf4, 0xe9, 0x37, 0xdb, 0x39, 0xe9, 0xd1, 0x45, 0x5b, 0x20, 0x41, 0x2f, 0x2d, 0x27, 0x22, 0xdc, 0x92, 0x74, 0x8a, 0x92, 0xd5, 0x83, 0xfd, 0x09, 0xfb, 0x13, 0x9b, 0xe3, 0x39, 0x7a, 0x6b, 0x5c, 0xfa, 0xe6, 0x76, 0x9e, 0xe0, 0xe4, 0xe3, 0xef, 0xad, 0xbc, 0xfd, 0x42, 0x45, 0x9a, 0xd4, 0x94, 0xd1, 0x7e, 0x8d, 0xa7, 0xd8, 0x05, 0xd5, 0xd3, 0x62, 0xcf, 0x15, 0xcf, 0x94, 0x7d, 0x1f, 0x5b, 0x58, 0x20, 0x44, 0x20, 0x90, 0x71, 0xbe, 0x66, 0xe9, 0x9a, 0xab, 0x74, 0x32, 0x70, 0x53, 0x1d, 0x69, 0xed, 0x87, 0x66, 0xf4, 0x09, 0x4f, 0xca, 0x25, 0x30, 0xc2, 0x63, 0x79, 0x00, 0x3c, 0xb1, 0x9b, 0x39, 0x3f, 0x00, 0xe0, 0xa8, 0x88, 0xef, 0x7a, 0x51, 0x5b, 0xe7, 0xbd, 0x49, 0x64, 0xda, 0x41, 0x7b, 0x24, 0xc3, 0x71, 0x22, 0xfd, 0xd1, 0xd1, 0x20, 0xb3, 0x3f, 0x97, 0xd3, 0x97, 0xb2, 0xaa, 0x18, 0x1c, 0x9e, 0x03, 0x77, 0x7b, 0x5b, 0x7e, 0xf9, 0xa3, 0xa0, 0xd6, 0x20, 0x81, 0x2c, 0x38, 0x8f, 0x9d, 0x25, 0xde, 0xe9, 0xc8, 0xf5, 0xdd, 0x6a, 0x47, 0x9c, 0x65, 0x04, 0x5a, 0x56, 0xe6, 0xc2, 0xeb, 0xf2, 0x02, 0x97, 0xe1, 0xb9, 0xd8, 0xe1, 0x24, 0x76, 0x9f, 0x23, 0x62, 0x39, 0x03, 0x4b, 0xc8, 0xf7, 0x34, 0x07, 0x49, 0xd6, 0xe7, 0x4d, 0x9a, }; const unsigned char sig[70] = { 0x30, 0x44, 0x02, 0x20, 0x54, 0x92, 0x28, 0x3b, 0x83, 0x33, 0x47, 0x56, 0x68, 0x79, 0xb2, 0x0c, 0x84, 0x80, 0xcc, 0x67, 0x27, 0x8b, 0xfa, 0x48, 0x43, 0x0d, 0x3c, 0xb4, 0x02, 0x36, 0x87, 0x97, 0x3e, 0xdf, 0x2f, 0x65, 0x02, 0x20, 0x1b, 0x56, 0x17, 0x06, 0xe2, 0x26, 0x0f, 0x6a, 0xe9, 0xa9, 0x70, 0x99, 0x62, 0xeb, 0x3a, 0x04, 0x1a, 0xc4, 0xa7, 0x03, 0x28, 0x56, 0x7c, 0xed, 0x47, 0x08, 0x68, 0x73, 0x6a, 0xb6, 0x89, 0x0d, }; const unsigned char pubkey[64] = { 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; const unsigned char id[64] = { 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, }; const char rp_id[] = "localhost"; const char rp_name[] = "sweet home localhost"; static void * dummy_open(const char *path) { (void)path; return (FAKE_DEV_HANDLE); } static void dummy_close(void *handle) { assert(handle == FAKE_DEV_HANDLE); } static int dummy_read(void *handle, unsigned char *buf, size_t len, int ms) { (void)handle; (void)buf; (void)len; (void)ms; abort(); /* NOTREACHED */ } static int dummy_write(void *handle, const unsigned char *buf, size_t len) { (void)handle; (void)buf; (void)len; abort(); /* NOTREACHED */ } static fido_cred_t * alloc_cred(void) { fido_cred_t *c; c = fido_cred_new(); assert(c != NULL); return (c); } static void free_cred(fido_cred_t *c) { fido_cred_free(&c); assert(c == NULL); } static fido_dev_t * alloc_dev(void) { fido_dev_t *d; d = fido_dev_new(); assert(d != NULL); return (d); } static void free_dev(fido_dev_t *d) { fido_dev_free(&d); assert(d == NULL); } static void empty_cred(void) { fido_cred_t *c; fido_dev_t *d; fido_dev_io_t io_f; c = alloc_cred(); assert(fido_cred_authdata_len(c) == 0); assert(fido_cred_authdata_ptr(c) == NULL); assert(fido_cred_clientdata_hash_len(c) == 0); assert(fido_cred_clientdata_hash_ptr(c) == NULL); assert(fido_cred_flags(c) == 0); assert(fido_cred_fmt(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_rp_id(c) == NULL); assert(fido_cred_rp_name(c) == NULL); assert(fido_cred_sig_len(c) == 0); assert(fido_cred_sig_ptr(c) == NULL); assert(fido_cred_x5c_len(c) == 0); assert(fido_cred_x5c_ptr(c) == NULL); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); io_f.open = dummy_open; io_f.close = dummy_close; io_f.read = dummy_read; io_f.write = dummy_write; d = alloc_dev(); fido_dev_force_u2f(d); assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_UNSUPPORTED_OPTION); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); fido_dev_force_fido2(d); assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); free_dev(d); } static void valid_cred(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void no_cdh(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void no_rp_id(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void no_rp_name(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, NULL) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void no_authdata(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); free_cred(c); } static void no_x509(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void no_sig(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void no_fmt(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void wrong_options(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void junk_cdh(void) { fido_cred_t *c; unsigned char *junk; junk = malloc(sizeof(cdh)); assert(junk != NULL); memcpy(junk, cdh, sizeof(cdh)); junk[0] = ~junk[0]; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, junk, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); free(junk); } static void junk_rp_id(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, "potato", rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void junk_rp_name(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, "potato") == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); } static void junk_authdata(void) { fido_cred_t *c; unsigned char *junk; junk = malloc(sizeof(authdata)); assert(junk != NULL); memcpy(junk, authdata, sizeof(authdata)); junk[0] = ~junk[0]; c = alloc_cred(); assert(fido_cred_set_authdata(c, junk, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_authdata_len(c) == 0); assert(fido_cred_authdata_ptr(c) == NULL); assert(fido_cred_flags(c) == 0); assert(fido_cred_fmt(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_rp_id(c) == NULL); assert(fido_cred_rp_name(c) == NULL); assert(fido_cred_sig_len(c) == 0); assert(fido_cred_sig_ptr(c) == NULL); assert(fido_cred_x5c_len(c) == 0); assert(fido_cred_x5c_ptr(c) == NULL); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); free(junk); } static void junk_sig(void) { fido_cred_t *c; unsigned char *junk; junk = malloc(sizeof(sig)); assert(junk != NULL); memcpy(junk, sig, sizeof(sig)); junk[0] = ~junk[0]; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, junk, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); free(junk); } static void junk_x509(void) { fido_cred_t *c; unsigned char *junk; junk = malloc(sizeof(x509)); assert(junk != NULL); memcpy(junk, x509, sizeof(x509)); junk[0] = ~junk[0]; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, junk, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); free_cred(c); free(junk); } /* github issue #6 */ static void invalid_type(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); free_cred(c); } /* cbor_serialize_alloc misuse */ static void bad_cbor_serialize(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_authdata_len(c) == sizeof(authdata)); free_cred(c); } static void duplicate_keys(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata_dupkeys, sizeof(authdata_dupkeys)) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); } static void unsorted_keys(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata_unsorted_keys, sizeof(authdata_unsorted_keys)) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); } int main(void) { fido_init(0); empty_cred(); valid_cred(); no_cdh(); no_rp_id(); no_rp_name(); no_authdata(); no_x509(); no_sig(); no_fmt(); junk_cdh(); junk_rp_id(); junk_rp_name(); junk_authdata(); junk_x509(); junk_sig(); wrong_options(); invalid_type(); bad_cbor_serialize(); duplicate_keys(); unsorted_keys(); exit(0); } libfido2-1.3.1/regress/dev.c000066400000000000000000000024071362326726700156230ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) #define REPORT_LEN (64 + 1) static void * dummy_open(const char *path) { (void)path; return (FAKE_DEV_HANDLE); } static void dummy_close(void *handle) { assert(handle == FAKE_DEV_HANDLE); } static int dummy_read(void *handle, unsigned char *ptr, size_t len, int ms) { (void)ptr; (void)len; (void)ms; assert(handle == FAKE_DEV_HANDLE); return (-1); } static int dummy_write(void *handle, const unsigned char *ptr, size_t len) { assert(handle == FAKE_DEV_HANDLE); assert(ptr != NULL); assert(len == REPORT_LEN); return ((int)len); } /* gh#56 */ static void open_iff_ok(void) { fido_dev_t *dev = NULL; fido_dev_io_t io; io.open = dummy_open; io.close = dummy_close; io.read = dummy_read; io.write = dummy_write; assert((dev = fido_dev_new()) != NULL); assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); assert(fido_dev_open(dev, "dummy") == FIDO_ERR_RX); assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); fido_dev_free(&dev); } int main(void) { fido_init(0); open_iff_ok(); exit(0); } libfido2-1.3.1/src/000077500000000000000000000000001362326726700140135ustar00rootroot00000000000000libfido2-1.3.1/src/CMakeLists.txt000066400000000000000000000052131362326726700165540ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. add_definitions(-D_FIDO_INTERNAL) list(APPEND FIDO_SOURCES aes256.c assert.c authkey.c bio.c blob.c buf.c cbor.c cred.c credman.c dev.c ecdh.c eddsa.c err.c es256.c hid.c info.c io.c iso7816.c log.c pin.c reset.c rs256.c u2f.c ) if(FUZZ) list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c) list(APPEND FIDO_SOURCES ../fuzz/wrap.c) endif() if(WIN32) list(APPEND COMPAT_SOURCES hid_win.c) elseif(APPLE) list(APPEND COMPAT_SOURCES hid_osx.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") list(APPEND COMPAT_SOURCES hid_linux.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") list(APPEND COMPAT_SOURCES hid_openbsd.c) endif() list(APPEND COMPAT_SOURCES ../openbsd-compat/bsd-getpagesize.c ../openbsd-compat/explicit_bzero.c ../openbsd-compat/explicit_bzero_win32.c ../openbsd-compat/recallocarray.c ../openbsd-compat/timingsafe_bcmp.c ) # static library add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES}) target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) if(WIN32) if (MINGW) target_link_libraries(fido2 wsock32 ws2_32 bcrypt setupapi hid) else() target_link_libraries(fido2 wsock32 ws2_32 bcrypt SetupAPI hid) set_target_properties(fido2 PROPERTIES OUTPUT_NAME fido2_static) endif() elseif(APPLE) target_link_libraries(fido2 "-framework CoreFoundation" "-framework IOKit") endif() install(TARGETS fido2 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) # dynamic library add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES}) target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) if(WIN32) if (MINGW) target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt setupapi hid) else() target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt SetupAPI hid) endif() elseif(APPLE) target_link_libraries(fido2_shared "-framework CoreFoundation" "-framework IOKit") endif() set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2 VERSION ${LIB_VERSION} SOVERSION ${LIB_SOVERSION}) install(TARGETS fido2_shared ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES fido.h DESTINATION include) install(DIRECTORY fido DESTINATION include) if(NOT WIN32) configure_file(libfido2.pc.in libfido2.pc @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libfido2.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") endif() libfido2-1.3.1/src/aes256.c000066400000000000000000000041341362326726700151660ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include "fido.h" int aes256_cbc_enc(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out) { EVP_CIPHER_CTX *ctx = NULL; unsigned char iv[32]; int len; int ok = -1; memset(iv, 0, sizeof(iv)); out->ptr = NULL; out->len = 0; /* sanity check */ if (in->len > INT_MAX || (in->len % 16) != 0 || (out->ptr = calloc(1, in->len)) == NULL) { fido_log_debug("%s: in->len=%zu", __func__, in->len); goto fail; } if ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 || !EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) || !EVP_CIPHER_CTX_set_padding(ctx, 0) || !EVP_EncryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) || len < 0 || (size_t)len != in->len) { fido_log_debug("%s: EVP_Encrypt", __func__); goto fail; } out->len = (size_t)len; ok = 0; fail: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); if (ok < 0) { free(out->ptr); out->ptr = NULL; out->len = 0; } return (ok); } int aes256_cbc_dec(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out) { EVP_CIPHER_CTX *ctx = NULL; unsigned char iv[32]; int len; int ok = -1; memset(iv, 0, sizeof(iv)); out->ptr = NULL; out->len = 0; /* sanity check */ if (in->len > INT_MAX || (in->len % 16) != 0 || (out->ptr = calloc(1, in->len)) == NULL) { fido_log_debug("%s: in->len=%zu", __func__, in->len); goto fail; } if ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 || !EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) || !EVP_CIPHER_CTX_set_padding(ctx, 0) || !EVP_DecryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) || len < 0 || (size_t)len > in->len + 32) { fido_log_debug("%s: EVP_Decrypt", __func__); goto fail; } out->len = (size_t)len; ok = 0; fail: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); if (ok < 0) { free(out->ptr); out->ptr = NULL; out->len = 0; } return (ok); } libfido2-1.3.1/src/assert.c000066400000000000000000000604651362326726700154730ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" static int adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_assert_t *assert = arg; uint64_t n; /* numberOfCredentials; see section 6.2 */ if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 5) { fido_log_debug("%s: cbor_type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } if (assert->stmt_len != 0 || assert->stmt_cnt != 1 || (size_t)n < assert->stmt_cnt) { fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu", __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n); return (-1); } if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) { fido_log_debug("%s: fido_assert_set_count", __func__); return (-1); } assert->stmt_len = 0; /* XXX */ return (0); } static int parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_assert_stmt *stmt = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* credential id */ return (cbor_decode_cred_id(val, &stmt->id)); case 2: /* authdata */ return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor, &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc)); case 3: /* signature */ return (fido_blob_decode(val, &stmt->sig)); case 4: /* user attributes */ return (cbor_decode_user(val, &stmt->user)); default: /* ignore */ fido_log_debug("%s: cbor type", __func__); return (0); } } static int fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin) { fido_blob_t f; cbor_item_t *argv[7]; int r; memset(argv, 0, sizeof(argv)); memset(&f, 0, sizeof(f)); /* do we have everything we need? */ if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, (void *)assert->rp_id, (void *)assert->cdh.ptr); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL || (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* allowed credentials */ if (assert->allow_list.len) { const fido_blob_array_t *cl = &assert->allow_list; if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) { fido_log_debug("%s: cbor_encode_pubkey_list", __func__); r = FIDO_ERR_INTERNAL; goto fail; } } /* hmac-secret extension */ if (assert->ext & FIDO_EXT_HMAC_SECRET) if ((argv[3] = cbor_encode_hmac_secret_param(ecdh, pk, &assert->hmac_salt)) == NULL) { fido_log_debug("%s: cbor_encode_hmac_secret_param", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* options */ if (assert->up != FIDO_OPT_OMIT || assert->uv != FIDO_OPT_OMIT) if ((argv[4] = cbor_encode_assert_options(assert->up, assert->uv)) == NULL) { fido_log_debug("%s: cbor_encode_assert_options", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* pin authentication */ if (pin) { if (pk == NULL || ecdh == NULL) { fido_log_debug("%s: pin=%p, pk=%p, ecdh=%p", __func__, (const void *)pin, (const void *)pk, (const void *)ecdh); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((r = cbor_add_pin_params(dev, &assert->cdh, pk, ecdh, pin, &argv[5], &argv[6])) != FIDO_OK) { fido_log_debug("%s: cbor_add_pin_params", __func__); goto fail; } } /* frame and transmit */ if (cbor_build_frame(CTAP_CBOR_ASSERT, argv, 7, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; fido_assert_reset_rx(assert); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* start with room for a single assertion */ if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) return (FIDO_ERR_INTERNAL); assert->stmt_len = 0; assert->stmt_cnt = 1; /* adjust as needed */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert, adjust_assert_count)) != FIDO_OK) { fido_log_debug("%s: adjust_assert_count", __func__); return (r); } /* parse the first assertion */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); return (r); } assert->stmt_len++; return (FIDO_OK); } static int fido_get_next_assert_tx(fido_dev_t *dev) { const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { fido_log_debug("%s: fido_tx", __func__); return (FIDO_ERR_TX); } return (FIDO_OK); } static int fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* sanity check */ if (assert->stmt_len >= assert->stmt_cnt) { fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__, assert->stmt_len, assert->stmt_cnt); return (FIDO_ERR_INTERNAL); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); return (r); } return (FIDO_OK); } static int fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert, const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms) { int r; if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK || (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK) return (r); while (assert->stmt_len < assert->stmt_cnt) { if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK || (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK) return (r); assert->stmt_len++; } return (FIDO_OK); } static int decrypt_hmac_secrets(fido_assert_t *assert, const fido_blob_t *key) { for (size_t i = 0; i < assert->stmt_cnt; i++) { fido_assert_stmt *stmt = &assert->stmt[i]; if (stmt->hmac_secret_enc.ptr != NULL) { if (aes256_cbc_dec(key, &stmt->hmac_secret_enc, &stmt->hmac_secret) < 0) { fido_log_debug("%s: aes256_cbc_dec %zu", __func__, i); return (-1); } } } return (0); } int fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin) { fido_blob_t *ecdh = NULL; es256_pk_t *pk = NULL; int r; if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, (void *)assert->rp_id, (void *)assert->cdh.ptr); return (FIDO_ERR_INVALID_ARGUMENT); } if (fido_dev_is_fido2(dev) == false) { if (pin != NULL || assert->ext != 0) return (FIDO_ERR_UNSUPPORTED_OPTION); return (u2f_authenticate(dev, assert, -1)); } if (pin != NULL || assert->ext != 0) { if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } } r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1); if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET) if (decrypt_hmac_secrets(assert, ecdh) < 0) { fido_log_debug("%s: decrypt_hmac_secrets", __func__); r = FIDO_ERR_INTERNAL; goto fail; } fail: es256_pk_free(&pk); fido_blob_free(&ecdh); return (r); } int fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv) { fido_log_debug("%s: flags=%02x", __func__, flags); fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv); if (up == FIDO_OPT_TRUE && (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) { fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__); return (-1); /* user not present */ } if (uv == FIDO_OPT_TRUE && (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) { fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__); return (-1); /* user not verified */ } return (0); } static int check_extensions(int authdata_ext, int ext) { if (authdata_ext != ext) { fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, authdata_ext, ext); return (-1); } return (0); } static int get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor) { cbor_item_t *item = NULL; unsigned char *authdata_ptr = NULL; size_t authdata_len; struct cbor_load_result cbor; SHA256_CTX ctx; int ok = -1; if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, &cbor)) == NULL || cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: authdata", __func__); goto fail; } authdata_ptr = cbor_bytestring_handle(item); authdata_len = cbor_bytestring_length(item); if (cose_alg != COSE_EDDSA) { if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || SHA256_Final(dgst->ptr, &ctx) == 0) { fido_log_debug("%s: sha256", __func__); goto fail; } dgst->len = SHA256_DIGEST_LENGTH; } else { if (SIZE_MAX - authdata_len < clientdata->len || dgst->len < authdata_len + clientdata->len) { fido_log_debug("%s: memcpy", __func__); goto fail; } memcpy(dgst->ptr, authdata_ptr, authdata_len); memcpy(dgst->ptr + authdata_len, clientdata->ptr, clientdata->len); dgst->len = authdata_len + clientdata->len; } ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } int fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk, const fido_blob_t *sig) { EVP_PKEY *pkey = NULL; EC_KEY *ec = NULL; int ok = -1; /* ECDSA_verify needs ints */ if (dgst->len > INT_MAX || sig->len > INT_MAX) { fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, dgst->len, sig->len); return (-1); } if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL || (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { fido_log_debug("%s: pk -> ec", __func__); goto fail; } if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, (int)sig->len, ec) != 1) { fido_log_debug("%s: ECDSA_verify", __func__); goto fail; } ok = 0; fail: if (pkey != NULL) EVP_PKEY_free(pkey); return (ok); } int fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk, const fido_blob_t *sig) { EVP_PKEY *pkey = NULL; RSA *rsa = NULL; int ok = -1; /* RSA_verify needs unsigned ints */ if (dgst->len > UINT_MAX || sig->len > UINT_MAX) { fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, dgst->len, sig->len); return (-1); } if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL || (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { fido_log_debug("%s: pk -> ec", __func__); goto fail; } if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr, (unsigned int)sig->len, rsa) != 1) { fido_log_debug("%s: RSA_verify", __func__); goto fail; } ok = 0; fail: if (pkey != NULL) EVP_PKEY_free(pkey); return (ok); } int fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk, const fido_blob_t *sig) { EVP_PKEY *pkey = NULL; EVP_MD_CTX *mdctx = NULL; int ok = -1; /* EVP_DigestVerify needs ints */ if (dgst->len > INT_MAX || sig->len > INT_MAX) { fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, dgst->len, sig->len); return (-1); } if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { fido_log_debug("%s: pk -> pkey", __func__); goto fail; } if ((mdctx = EVP_MD_CTX_new()) == NULL) { fido_log_debug("%s: EVP_MD_CTX_new", __func__); goto fail; } if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { fido_log_debug("%s: EVP_DigestVerifyInit", __func__); goto fail; } if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, dgst->len) != 1) { fido_log_debug("%s: EVP_DigestVerify", __func__); goto fail; } ok = 0; fail: if (mdctx != NULL) EVP_MD_CTX_free(mdctx); if (pkey != NULL) EVP_PKEY_free(pkey); return (ok); } int fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, const void *pk) { unsigned char buf[1024]; fido_blob_t dgst; const fido_assert_stmt *stmt = NULL; int ok = -1; int r; dgst.ptr = buf; dgst.len = sizeof(buf); if (idx >= assert->stmt_len || pk == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto out; } stmt = &assert->stmt[idx]; /* do we have everything we need? */ if (assert->cdh.ptr == NULL || assert->rp_id == NULL || stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) { fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p", __func__, (void *)assert->cdh.ptr, assert->rp_id, (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if (fido_check_flags(stmt->authdata.flags, assert->up, assert->uv) < 0) { fido_log_debug("%s: fido_check_flags", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (check_extensions(stmt->authdata_ext, assert->ext) < 0) { fido_log_debug("%s: check_extensions", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) { fido_log_debug("%s: fido_check_rp_id", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (get_signed_hash(cose_alg, &dgst, &assert->cdh, &stmt->authdata_cbor) < 0) { fido_log_debug("%s: get_signed_hash", __func__); r = FIDO_ERR_INTERNAL; goto out; } switch (cose_alg) { case COSE_ES256: ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig); break; case COSE_RS256: ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig); break; case COSE_EDDSA: ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig); break; default: fido_log_debug("%s: unsupported cose_alg %d", __func__, cose_alg); r = FIDO_ERR_UNSUPPORTED_OPTION; goto out; } if (ok < 0) r = FIDO_ERR_INVALID_SIG; else r = FIDO_OK; out: explicit_bzero(buf, sizeof(buf)); return (r); } int fido_assert_set_clientdata_hash(fido_assert_t *assert, const unsigned char *hash, size_t hash_len) { if (fido_blob_set(&assert->cdh, hash, hash_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt, size_t salt_len) { if ((salt_len != 32 && salt_len != 64) || fido_blob_set(&assert->hmac_salt, salt, salt_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_assert_set_rp(fido_assert_t *assert, const char *id) { if (assert->rp_id != NULL) { free(assert->rp_id); assert->rp_id = NULL; } if (id == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((assert->rp_id = strdup(id)) == NULL) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } int fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr, size_t len) { fido_blob_t id; fido_blob_t *list_ptr; int r; memset(&id, 0, sizeof(id)); if (assert->allow_list.len == SIZE_MAX) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr = recallocarray(assert->allow_list.ptr, assert->allow_list.len, assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } list_ptr[assert->allow_list.len++] = id; assert->allow_list.ptr = list_ptr; return (FIDO_OK); fail: free(id.ptr); return (r); } int fido_assert_set_extensions(fido_assert_t *assert, int ext) { if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET) return (FIDO_ERR_INVALID_ARGUMENT); assert->ext = ext; return (FIDO_OK); } int fido_assert_set_options(fido_assert_t *assert, bool up, bool uv) { assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; return (FIDO_OK); } int fido_assert_set_up(fido_assert_t *assert, fido_opt_t up) { assert->up = up; return (FIDO_OK); } int fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv) { assert->uv = uv; return (FIDO_OK); } const unsigned char * fido_assert_clientdata_hash_ptr(const fido_assert_t *assert) { return (assert->cdh.ptr); } size_t fido_assert_clientdata_hash_len(const fido_assert_t *assert) { return (assert->cdh.len); } fido_assert_t * fido_assert_new(void) { return (calloc(1, sizeof(fido_assert_t))); } void fido_assert_reset_tx(fido_assert_t *assert) { free(assert->rp_id); free(assert->cdh.ptr); free(assert->hmac_salt.ptr); fido_free_blob_array(&assert->allow_list); memset(&assert->cdh, 0, sizeof(assert->cdh)); memset(&assert->hmac_salt, 0, sizeof(assert->hmac_salt)); memset(&assert->allow_list, 0, sizeof(assert->allow_list)); assert->rp_id = NULL; assert->up = FIDO_OPT_OMIT; assert->uv = FIDO_OPT_OMIT; assert->ext = 0; } void fido_assert_reset_rx(fido_assert_t *assert) { for (size_t i = 0; i < assert->stmt_cnt; i++) { free(assert->stmt[i].user.id.ptr); free(assert->stmt[i].user.icon); free(assert->stmt[i].user.name); free(assert->stmt[i].user.display_name); free(assert->stmt[i].id.ptr); if (assert->stmt[i].hmac_secret.ptr != NULL) { explicit_bzero(assert->stmt[i].hmac_secret.ptr, assert->stmt[i].hmac_secret.len); } free(assert->stmt[i].hmac_secret.ptr); free(assert->stmt[i].hmac_secret_enc.ptr); free(assert->stmt[i].authdata_cbor.ptr); free(assert->stmt[i].sig.ptr); memset(&assert->stmt[i], 0, sizeof(assert->stmt[i])); } free(assert->stmt); assert->stmt = NULL; assert->stmt_len = 0; assert->stmt_cnt = 0; } void fido_assert_free(fido_assert_t **assert_p) { fido_assert_t *assert; if (assert_p == NULL || (assert = *assert_p) == NULL) return; fido_assert_reset_tx(assert); fido_assert_reset_rx(assert); free(assert); *assert_p = NULL; } size_t fido_assert_count(const fido_assert_t *assert) { return (assert->stmt_len); } const char * fido_assert_rp_id(const fido_assert_t *assert) { return (assert->rp_id); } uint8_t fido_assert_flags(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].authdata.flags); } uint32_t fido_assert_sigcount(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].authdata.sigcount); } const unsigned char * fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].authdata_cbor.ptr); } size_t fido_assert_authdata_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].authdata_cbor.len); } const unsigned char * fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].sig.ptr); } size_t fido_assert_sig_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].sig.len); } const unsigned char * fido_assert_id_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].id.ptr); } size_t fido_assert_id_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].id.len); } const unsigned char * fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.id.ptr); } size_t fido_assert_user_id_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].user.id.len); } const char * fido_assert_user_icon(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.icon); } const char * fido_assert_user_name(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.name); } const char * fido_assert_user_display_name(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.display_name); } const unsigned char * fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].hmac_secret.ptr); } size_t fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].hmac_secret.len); } static void fido_assert_clean_authdata(fido_assert_stmt *as) { free(as->authdata_cbor.ptr); free(as->hmac_secret_enc.ptr); memset(&as->authdata_ext, 0, sizeof(as->authdata_ext)); memset(&as->authdata_cbor, 0, sizeof(as->authdata_cbor)); memset(&as->authdata, 0, sizeof(as->authdata)); memset(&as->hmac_secret_enc, 0, sizeof(as->hmac_secret_enc)); } int fido_assert_set_authdata(fido_assert_t *assert, size_t idx, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; fido_assert_stmt *stmt = NULL; struct cbor_load_result cbor; int r; if (idx >= assert->stmt_len || ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); stmt = &assert->stmt[idx]; fido_assert_clean_authdata(stmt); if ((item = cbor_load(ptr, len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) { fido_log_debug("%s: cbor_decode_assert_authdata", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_assert_clean_authdata(stmt); return (r); } int fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; fido_assert_stmt *stmt = NULL; int r; if (idx >= assert->stmt_len || ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); stmt = &assert->stmt[idx]; fido_assert_clean_authdata(stmt); if ((item = cbor_build_bytestring(ptr, len)) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) { fido_log_debug("%s: cbor_decode_assert_authdata", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_assert_clean_authdata(stmt); return (r); } static void fido_assert_clean_sig(fido_assert_stmt *as) { free(as->sig.ptr); as->sig.ptr = NULL; as->sig.len = 0; } int fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr, size_t len) { unsigned char *sig; if (idx >= a->stmt_len || ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); fido_assert_clean_sig(&a->stmt[idx]); if ((sig = malloc(len)) == NULL) return (FIDO_ERR_INTERNAL); memcpy(sig, ptr, len); a->stmt[idx].sig.ptr = sig; a->stmt[idx].sig.len = len; return (FIDO_OK); } /* XXX shrinking leaks memory; fortunately that shouldn't happen */ int fido_assert_set_count(fido_assert_t *assert, size_t n) { void *new_stmt; #ifdef FIDO_FUZZ if (n > UINT8_MAX) { fido_log_debug("%s: n > UINT8_MAX", __func__); return (FIDO_ERR_INTERNAL); } #endif new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n, sizeof(fido_assert_stmt)); if (new_stmt == NULL) return (FIDO_ERR_INTERNAL); assert->stmt = new_stmt; assert->stmt_cnt = n; assert->stmt_len = n; return (FIDO_OK); } libfido2-1.3.1/src/authkey.c000066400000000000000000000042471362326726700156400ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" static int parse_authkey(const cbor_item_t *key, const cbor_item_t *val, void *arg) { es256_pk_t *authkey = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 1) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } return (es256_pk_decode(val, authkey)); } static int fido_dev_authkey_tx(fido_dev_t *dev) { fido_blob_t f; cbor_item_t *argv[2]; int r; fido_log_debug("%s: dev=%p", __func__, (void *)dev); memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); /* add command parameters */ if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(2)) == NULL) { fido_log_debug("%s: cbor_build", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* frame and transmit */ if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev, (void *)authkey, ms); memset(authkey, 0, sizeof(*authkey)); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } return (cbor_parse_reply(reply, (size_t)reply_len, authkey, parse_authkey)); } static int fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int ms) { int r; if ((r = fido_dev_authkey_tx(dev)) != FIDO_OK || (r = fido_dev_authkey_rx(dev, authkey, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_authkey(fido_dev_t *dev, es256_pk_t *authkey) { return (fido_dev_authkey_wait(dev, authkey, -1)); } libfido2-1.3.1/src/bio.c000066400000000000000000000430271362326726700147360ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" #include "fido/bio.h" #include "fido/es256.h" #define CMD_ENROLL_BEGIN 0x01 #define CMD_ENROLL_NEXT 0x02 #define CMD_ENROLL_CANCEL 0x03 #define CMD_ENUM 0x04 #define CMD_SET_NAME 0x05 #define CMD_ENROLL_REMOVE 0x06 #define CMD_GET_INFO 0x07 static int bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc, cbor_item_t **param, fido_blob_t *hmac_data) { const uint8_t prefix[2] = { 0x01 /* modality */, cmd }; int ok = -1; size_t cbor_alloc_len; size_t cbor_len; unsigned char *cbor = NULL; if (argv == NULL || param == NULL) return (fido_blob_set(hmac_data, prefix, sizeof(prefix))); if ((*param = cbor_flatten_vector(argv, argc)) == NULL) { fido_log_debug("%s: cbor_flatten_vector", __func__); goto fail; } if ((cbor_len = cbor_serialize_alloc(*param, &cbor, &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) { fido_log_debug("%s: cbor_serialize_alloc", __func__); goto fail; } if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } memcpy(hmac_data->ptr, prefix, sizeof(prefix)); memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len); hmac_data->len = cbor_len + sizeof(prefix); ok = 0; fail: free(cbor); return (ok); } static int bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc, const char *pin, const fido_blob_t *token) { cbor_item_t *argv[5]; es256_pk_t *pk = NULL; fido_blob_t *ecdh = NULL; fido_blob_t f; fido_blob_t hmac; int r = FIDO_ERR_INTERNAL; memset(&f, 0, sizeof(f)); memset(&hmac, 0, sizeof(hmac)); memset(&argv, 0, sizeof(argv)); /* modality, subCommand */ if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(cmd)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } /* subParams */ if (pin || token) { if (bio_prepare_hmac(cmd, sub_argv, sub_argc, &argv[2], &hmac) < 0) { fido_log_debug("%s: bio_prepare_hmac", __func__); goto fail; } } /* pinProtocol, pinAuth */ if (pin) { if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin, &argv[4], &argv[3])) != FIDO_OK) { fido_log_debug("%s: cbor_add_pin_params", __func__); goto fail; } } else if (token) { if ((argv[3] = cbor_encode_pin_opt()) == NULL || (argv[4] = cbor_encode_pin_auth(token, &hmac)) == NULL) { fido_log_debug("%s: encode pin", __func__); goto fail; } } /* framing and transmission */ if (cbor_build_frame(CTAP_CBOR_BIO_ENROLL_PRE, argv, 5, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); es256_pk_free(&pk); fido_blob_free(&ecdh); free(f.ptr); free(hmac.ptr); return (r); } static void bio_reset_template(fido_bio_template_t *t) { free(t->name); free(t->id.ptr); t->name = NULL; memset(&t->id, 0, sizeof(t->id)); } static void bio_reset_template_array(fido_bio_template_array_t *ta) { for (size_t i = 0; i < ta->n_alloc; i++) bio_reset_template(&ta->ptr[i]); free(ta->ptr); ta->ptr = NULL; memset(ta, 0, sizeof(*ta)); } static int decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_template_t *t = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* id */ return (fido_blob_decode(val, &t->id)); case 2: /* name */ return (cbor_string_copy(val, &t->name)); } return (0); /* ignore */ } static int decode_template_array(const cbor_item_t *item, void *arg) { fido_bio_template_array_t *ta = arg; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (ta->n_rx >= ta->n_alloc) { fido_log_debug("%s: n_rx >= n_alloc", __func__); return (-1); } if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) { fido_log_debug("%s: decode_template", __func__); return (-1); } ta->n_rx++; return (0); } static int bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_template_array_t *ta = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 7) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } if (cbor_isa_array(val) == false || cbor_array_is_definite(val) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) { fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0", __func__); return (-1); } if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL) return (-1); ta->n_alloc = cbor_array_size(val); if (cbor_array_iter(val, ta, decode_template_array) < 0) { fido_log_debug("%s: decode_template_array", __func__); return (-1); } return (0); } static int bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; bio_reset_template_array(ta); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta, bio_parse_template_array)) != FIDO_OK) { fido_log_debug("%s: bio_parse_template_array" , __func__); return (r); } return (FIDO_OK); } static int bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta, const char *pin, int ms) { int r; if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL)) != FIDO_OK || (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, const char *pin) { if (pin == NULL) return (FIDO_ERR_INVALID_ARGUMENT); return (bio_get_template_array_wait(dev, ta, pin, -1)); } static int bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t, const char *pin, int ms) { cbor_item_t *argv[2]; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[0] = fido_blob_encode(&t->id)) == NULL || (argv[1] = cbor_build_string(t->name)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t, const char *pin) { if (pin == NULL || t->name == NULL) return (FIDO_ERR_INVALID_ARGUMENT); return (bio_set_template_name_wait(dev, t, pin, -1)); } static void bio_reset_enroll(fido_bio_enroll_t *e) { e->remaining_samples = 0; e->last_status = 0; if (e->token) fido_blob_free(&e->token); } static int bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_enroll_t *e = arg; uint64_t x; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 5: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } e->last_status = (uint8_t)x; break; case 6: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } e->remaining_samples = (uint8_t)x; break; default: return (0); /* ignore */ } return (0); } static int bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_blob_t *id = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 4) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } return (fido_blob_decode(val, id)); } static int bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, fido_bio_enroll_t *e, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; bio_reset_template(t); e->remaining_samples = 0; e->last_status = 0; if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, bio_parse_enroll_status)) != FIDO_OK) { fido_log_debug("%s: bio_parse_enroll_status", __func__); return (r); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id, bio_parse_template_id)) != FIDO_OK) { fido_log_debug("%s: bio_parse_template_id", __func__); return (r); } return (FIDO_OK); } static int bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t, fido_bio_enroll_t *e, uint32_t timo_ms, int ms) { cbor_item_t *argv[3]; const uint8_t cmd = CMD_ENROLL_BEGIN; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[2] = cbor_build_uint32(timo_ms)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin) { es256_pk_t *pk = NULL; fido_blob_t *ecdh = NULL; fido_blob_t *token = NULL; int r; if (pin == NULL || e->token != NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((token = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) { fido_log_debug("%s: fido_dev_get_pin_token", __func__); goto fail; } e->token = token; token = NULL; fail: es256_pk_free(&pk); fido_blob_free(&ecdh); fido_blob_free(&token); if (r != FIDO_OK) return (r); return (bio_enroll_begin_wait(dev, t, e, timo_ms, -1)); } static int bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; e->remaining_samples = 0; e->last_status = 0; if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, bio_parse_enroll_status)) != FIDO_OK) { fido_log_debug("%s: bio_parse_enroll_status", __func__); return (r); } return (FIDO_OK); } static int bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t, fido_bio_enroll_t *e, uint32_t timo_ms, int ms) { cbor_item_t *argv[3]; const uint8_t cmd = CMD_ENROLL_NEXT; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[0] = fido_blob_encode(&t->id)) == NULL || (argv[2] = cbor_build_uint32(timo_ms)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || (r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t, fido_bio_enroll_t *e, uint32_t timo_ms) { if (e->token == NULL) return (FIDO_ERR_INVALID_ARGUMENT); return (bio_enroll_continue_wait(dev, t, e, timo_ms, -1)); } static int bio_enroll_cancel_wait(fido_dev_t *dev, int ms) { const uint8_t cmd = CMD_ENROLL_CANCEL; int r; if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); return (r); } return (FIDO_OK); } int fido_bio_dev_enroll_cancel(fido_dev_t *dev) { return (bio_enroll_cancel_wait(dev, -1)); } static int bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t, const char *pin, int ms) { cbor_item_t *argv[1]; const uint8_t cmd = CMD_ENROLL_REMOVE; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[0] = fido_blob_encode(&t->id)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t, const char *pin) { return (bio_enroll_remove_wait(dev, t, pin, -1)); } static void bio_reset_info(fido_bio_info_t *i) { i->type = 0; i->max_samples = 0; } static int bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_info_t *i = arg; uint64_t x; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 2: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } i->type = (uint8_t)x; break; case 3: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } i->max_samples = (uint8_t)x; break; default: return (0); /* ignore */ } return (0); } static int bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; bio_reset_info(i); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, i, bio_parse_info)) != FIDO_OK) { fido_log_debug("%s: bio_parse_info" , __func__); return (r); } return (FIDO_OK); } static int bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int ms) { int r; if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL)) != FIDO_OK || (r = bio_rx_info(dev, i, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); return (r); } return (FIDO_OK); } int fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i) { return (bio_get_info_wait(dev, i, -1)); } const char * fido_bio_template_name(const fido_bio_template_t *t) { return (t->name); } const unsigned char * fido_bio_template_id_ptr(const fido_bio_template_t *t) { return (t->id.ptr); } size_t fido_bio_template_id_len(const fido_bio_template_t *t) { return (t->id.len); } size_t fido_bio_template_array_count(const fido_bio_template_array_t *ta) { return (ta->n_rx); } fido_bio_template_array_t * fido_bio_template_array_new(void) { return (calloc(1, sizeof(fido_bio_template_array_t))); } fido_bio_template_t * fido_bio_template_new(void) { return (calloc(1, sizeof(fido_bio_template_t))); } void fido_bio_template_array_free(fido_bio_template_array_t **tap) { fido_bio_template_array_t *ta; if (tap == NULL || (ta = *tap) == NULL) return; bio_reset_template_array(ta); free(ta); *tap = NULL; } void fido_bio_template_free(fido_bio_template_t **tp) { fido_bio_template_t *t; if (tp == NULL || (t = *tp) == NULL) return; bio_reset_template(t); free(t); *tp = NULL; } int fido_bio_template_set_name(fido_bio_template_t *t, const char *name) { free(t->name); t->name = NULL; if (name && (t->name = strdup(name)) == NULL) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } int fido_bio_template_set_id(fido_bio_template_t *t, const unsigned char *ptr, size_t len) { free(t->id.ptr); t->id.ptr = NULL; t->id.len = 0; if (ptr && fido_blob_set(&t->id, ptr, len) < 0) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } const fido_bio_template_t * fido_bio_template(const fido_bio_template_array_t *ta, size_t idx) { if (idx >= ta->n_alloc) return (NULL); return (&ta->ptr[idx]); } fido_bio_enroll_t * fido_bio_enroll_new(void) { return (calloc(1, sizeof(fido_bio_enroll_t))); } fido_bio_info_t * fido_bio_info_new(void) { return (calloc(1, sizeof(fido_bio_info_t))); } uint8_t fido_bio_info_type(const fido_bio_info_t *i) { return (i->type); } uint8_t fido_bio_info_max_samples(const fido_bio_info_t *i) { return (i->max_samples); } void fido_bio_enroll_free(fido_bio_enroll_t **ep) { fido_bio_enroll_t *e; if (ep == NULL || (e = *ep) == NULL) return; bio_reset_enroll(e); free(e); *ep = NULL; } void fido_bio_info_free(fido_bio_info_t **ip) { fido_bio_info_t *i; if (ip == NULL || (i = *ip) == NULL) return; free(i); *ip = NULL; } uint8_t fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e) { return (e->remaining_samples); } uint8_t fido_bio_enroll_last_status(const fido_bio_enroll_t *e) { return (e->last_status); } libfido2-1.3.1/src/blob.c000066400000000000000000000032371362326726700151020ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" fido_blob_t * fido_blob_new(void) { return (calloc(1, sizeof(fido_blob_t))); } int fido_blob_set(fido_blob_t *b, const unsigned char *ptr, size_t len) { if (b->ptr != NULL) { explicit_bzero(b->ptr, b->len); free(b->ptr); b->ptr = NULL; } b->len = 0; if (ptr == NULL || len == 0) { fido_log_debug("%s: ptr=%p, len=%zu", __func__, (const void *)ptr, len); return (-1); } if ((b->ptr = malloc(len)) == NULL) { fido_log_debug("%s: malloc", __func__); return (-1); } memcpy(b->ptr, ptr, len); b->len = len; return (0); } void fido_blob_free(fido_blob_t **bp) { fido_blob_t *b; if (bp == NULL || (b = *bp) == NULL) return; if (b->ptr) { explicit_bzero(b->ptr, b->len); free(b->ptr); } explicit_bzero(b, sizeof(*b)); free(b); *bp = NULL; } void fido_free_blob_array(fido_blob_array_t *array) { if (array->ptr == NULL) return; for (size_t i = 0; i < array->len; i++) { fido_blob_t *b = &array->ptr[i]; if (b->ptr != NULL) { explicit_bzero(b->ptr, b->len); free(b->ptr); b->ptr = NULL; } } free(array->ptr); array->ptr = NULL; array->len = 0; } cbor_item_t * fido_blob_encode(const fido_blob_t *b) { if (b == NULL || b->ptr == NULL) return (NULL); return (cbor_build_bytestring(b->ptr, b->len)); } int fido_blob_decode(const cbor_item_t *item, fido_blob_t *b) { return (cbor_bytestring_copy(item, &b->ptr, &b->len)); } int fido_blob_is_empty(const fido_blob_t *b) { return (b->ptr == NULL || b->len == 0); } libfido2-1.3.1/src/blob.h000066400000000000000000000013311362326726700151000ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _BLOB_H #define _BLOB_H typedef struct fido_blob { unsigned char *ptr; size_t len; } fido_blob_t; typedef struct fido_blob_array { fido_blob_t *ptr; size_t len; } fido_blob_array_t; cbor_item_t *fido_blob_encode(const fido_blob_t *); fido_blob_t *fido_blob_new(void); int fido_blob_decode(const cbor_item_t *, fido_blob_t *); int fido_blob_is_empty(const fido_blob_t *); int fido_blob_set(fido_blob_t *, const unsigned char *, size_t); void fido_blob_free(fido_blob_t **); void fido_free_blob_array(fido_blob_array_t *); #endif /* !_BLOB_H */ libfido2-1.3.1/src/buf.c000066400000000000000000000011251362326726700147320ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" int fido_buf_read(const unsigned char **buf, size_t *len, void *dst, size_t count) { if (count > *len) return (-1); memcpy(dst, *buf, count); *buf += count; *len -= count; return (0); } int fido_buf_write(unsigned char **buf, size_t *len, const void *src, size_t count) { if (count > *len) return (-1); memcpy(*buf, src, count); *buf += count; *len -= count; return (0); } libfido2-1.3.1/src/cbor.c000066400000000000000000001002341362326726700151040ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include "fido.h" static int check_key_type(cbor_item_t *item) { if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT || item->type == CBOR_TYPE_STRING) return (0); fido_log_debug("%s: invalid type: %d", __func__, item->type); return (-1); } /* * Validate CTAP2 canonical CBOR encoding rules for maps. */ static int ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr) { size_t curr_len; size_t prev_len; if (check_key_type(prev) < 0 || check_key_type(curr) < 0) return (-1); if (prev->type != curr->type) { if (prev->type < curr->type) return (0); fido_log_debug("%s: unsorted types", __func__); return (-1); } if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) { if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) && cbor_get_int(curr) > cbor_get_int(prev)) return (0); } else { curr_len = cbor_string_length(curr); prev_len = cbor_string_length(prev); if (curr_len > prev_len || (curr_len == prev_len && memcmp(cbor_string_handle(prev), cbor_string_handle(curr), curr_len) < 0)) return (0); } fido_log_debug("%s: invalid cbor", __func__); return (-1); } int cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, const cbor_item_t *, void *)) { struct cbor_pair *v; size_t n; if ((v = cbor_map_handle(item)) == NULL) { fido_log_debug("%s: cbor_map_handle", __func__); return (-1); } n = cbor_map_size(item); for (size_t i = 0; i < n; i++) { if (v[i].key == NULL || v[i].value == NULL) { fido_log_debug("%s: key=%p, value=%p for i=%zu", __func__, (void *)v[i].key, (void *)v[i].value, i); return (-1); } if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) { fido_log_debug("%s: ctap_check_cbor", __func__); return (-1); } if (f(v[i].key, v[i].value, arg) < 0) { fido_log_debug("%s: iterator < 0 on i=%zu", __func__, i); return (-1); } } return (0); } int cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, void *)) { cbor_item_t **v; size_t n; if ((v = cbor_array_handle(item)) == NULL) { fido_log_debug("%s: cbor_array_handle", __func__); return (-1); } n = cbor_array_size(item); for (size_t i = 0; i < n; i++) if (v[i] == NULL || f(v[i], arg) < 0) { fido_log_debug("%s: iterator < 0 on i=%zu,%p", __func__, i, (void *)v[i]); return (-1); } return (0); } int cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg, int(*parser)(const cbor_item_t *, const cbor_item_t *, void *)) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int r; if (blob_len < 1) { fido_log_debug("%s: blob_len=%zu", __func__, blob_len); r = FIDO_ERR_RX; goto fail; } if (blob[0] != FIDO_OK) { fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]); r = blob[0]; goto fail; } if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); r = FIDO_ERR_RX_NOT_CBOR; goto fail; } if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); r = FIDO_ERR_RX_INVALID_CBOR; goto fail; } if (cbor_map_iter(item, arg, parser) < 0) { fido_log_debug("%s: cbor_map_iter", __func__); r = FIDO_ERR_RX_INVALID_CBOR; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); return (r); } void cbor_vector_free(cbor_item_t **item, size_t len) { for (size_t i = 0; i < len; i++) if (item[i] != NULL) cbor_decref(&item[i]); } int cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len) { if (*buf != NULL || *len != 0) { fido_log_debug("%s: dup", __func__); return (-1); } if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } *len = cbor_bytestring_length(item); if ((*buf = malloc(*len)) == NULL) { *len = 0; return (-1); } memcpy(*buf, cbor_bytestring_handle(item), *len); return (0); } int cbor_string_copy(const cbor_item_t *item, char **str) { size_t len; if (*str != NULL) { fido_log_debug("%s: dup", __func__); return (-1); } if (cbor_isa_string(item) == false || cbor_string_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if ((len = cbor_string_length(item)) == SIZE_MAX || (*str = malloc(len + 1)) == NULL) return (-1); memcpy(*str, cbor_string_handle(item), len); (*str)[len] = '\0'; return (0); } int cbor_add_bytestring(cbor_item_t *item, const char *key, const unsigned char *value, size_t value_len) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if ((pair.key = cbor_build_string(key)) == NULL || (pair.value = cbor_build_bytestring(value, value_len)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); if (pair.value) cbor_decref(&pair.value); return (ok); } int cbor_add_string(cbor_item_t *item, const char *key, const char *value) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if ((pair.key = cbor_build_string(key)) == NULL || (pair.value = cbor_build_string(value)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); if (pair.value) cbor_decref(&pair.value); return (ok); } int cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if ((pair.key = cbor_build_string(key)) == NULL || (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); if (pair.value) cbor_decref(&pair.value); return (ok); } static int cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if (arg == NULL) return (0); /* empty argument */ if ((pair.key = cbor_build_uint8(n)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } pair.value = arg; if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); return (ok); } cbor_item_t * cbor_flatten_vector(cbor_item_t *argv[], size_t argc) { cbor_item_t *map; uint8_t i; if (argc > UINT8_MAX - 1) return (NULL); if ((map = cbor_new_definite_map(argc)) == NULL) return (NULL); for (i = 0; i < argc; i++) if (cbor_add_arg(map, i + 1, argv[i]) < 0) break; if (i != argc) { cbor_decref(&map); map = NULL; } return (map); } int cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f) { cbor_item_t *flat = NULL; unsigned char *cbor = NULL; size_t cbor_len; size_t cbor_alloc_len; int ok = -1; if ((flat = cbor_flatten_vector(argv, argc)) == NULL) goto fail; cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len); if (cbor_len == 0 || cbor_len == SIZE_MAX) { fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len); goto fail; } if ((f->ptr = malloc(cbor_len + 1)) == NULL) goto fail; f->len = cbor_len + 1; f->ptr[0] = cmd; memcpy(f->ptr + 1, cbor, f->len - 1); ok = 0; fail: if (flat != NULL) cbor_decref(&flat); free(cbor); return (ok); } cbor_item_t * cbor_encode_rp_entity(const fido_rp_t *rp) { cbor_item_t *item = NULL; if ((item = cbor_new_definite_map(2)) == NULL) return (NULL); if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) || (rp->name && cbor_add_string(item, "name", rp->name) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_user_entity(const fido_user_t *user) { cbor_item_t *item = NULL; const fido_blob_t *id = &user->id; const char *display = user->display_name; if ((item = cbor_new_definite_map(4)) == NULL) return (NULL); if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) || (user->icon && cbor_add_string(item, "icon", user->icon) < 0) || (user->name && cbor_add_string(item, "name", user->name) < 0) || (display && cbor_add_string(item, "displayName", display) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_pubkey_param(int cose_alg) { cbor_item_t *item = NULL; cbor_item_t *body = NULL; struct cbor_pair alg; int ok = -1; memset(&alg, 0, sizeof(alg)); if ((item = cbor_new_definite_array(1)) == NULL || (body = cbor_new_definite_map(2)) == NULL || cose_alg > -1 || cose_alg < INT16_MIN) goto fail; alg.key = cbor_build_string("alg"); if (-cose_alg - 1 > UINT8_MAX) alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1)); else alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1)); if (alg.key == NULL || alg.value == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (cbor_map_add(body, alg) == false || cbor_add_string(body, "type", "public-key") < 0 || cbor_array_push(item, body) == false) goto fail; ok = 0; fail: if (ok < 0) { if (item != NULL) { cbor_decref(&item); item = NULL; } } if (body != NULL) cbor_decref(&body); if (alg.key != NULL) cbor_decref(&alg.key); if (alg.value != NULL) cbor_decref(&alg.value); return (item); } cbor_item_t * cbor_encode_pubkey(const fido_blob_t *pubkey) { cbor_item_t *cbor_key = NULL; if ((cbor_key = cbor_new_definite_map(2)) == NULL || cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 || cbor_add_string(cbor_key, "type", "public-key") < 0) { if (cbor_key) cbor_decref(&cbor_key); return (NULL); } return (cbor_key); } cbor_item_t * cbor_encode_pubkey_list(const fido_blob_array_t *list) { cbor_item_t *array = NULL; cbor_item_t *key = NULL; if ((array = cbor_new_definite_array(list->len)) == NULL) goto fail; for (size_t i = 0; i < list->len; i++) { if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL || cbor_array_push(array, key) == false) goto fail; cbor_decref(&key); } return (array); fail: if (key != NULL) cbor_decref(&key); if (array != NULL) cbor_decref(&array); return (NULL); } cbor_item_t * cbor_encode_extensions(int ext) { cbor_item_t *item = NULL; if (ext == 0 || ext != FIDO_EXT_HMAC_SECRET) return (NULL); if ((item = cbor_new_definite_map(1)) == NULL) return (NULL); if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_options(fido_opt_t rk, fido_opt_t uv) { cbor_item_t *item = NULL; if ((item = cbor_new_definite_map(2)) == NULL) return (NULL); if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) || (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_assert_options(fido_opt_t up, fido_opt_t uv) { cbor_item_t *item = NULL; if ((item = cbor_new_definite_map(2)) == NULL) return (NULL); if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) || (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data) { const EVP_MD *md = NULL; unsigned char dgst[SHA256_DIGEST_LENGTH]; unsigned int dgst_len; if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr, (int)hmac_key->len, data->ptr, (int)data->len, dgst, &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) return (NULL); return (cbor_build_bytestring(dgst, 16)); } cbor_item_t * cbor_encode_pin_opt(void) { return (cbor_build_uint8(1)); } cbor_item_t * cbor_encode_pin_enc(const fido_blob_t *key, const fido_blob_t *pin) { fido_blob_t pe; cbor_item_t *item = NULL; if (aes256_cbc_enc(key, pin, &pe) < 0) return (NULL); item = cbor_build_bytestring(pe.ptr, pe.len); free(pe.ptr); return (item); } static int sha256(const unsigned char *data, size_t data_len, fido_blob_t *digest) { if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL) return (-1); digest->len = SHA256_DIGEST_LENGTH; if (SHA256(data, data_len, digest->ptr) != digest->ptr) { free(digest->ptr); digest->ptr = NULL; digest->len = 0; return (-1); } return (0); } cbor_item_t * cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin, const fido_blob_t *pin) { unsigned char dgst[SHA256_DIGEST_LENGTH]; unsigned int dgst_len; cbor_item_t *item = NULL; const EVP_MD *md = NULL; #if OPENSSL_VERSION_NUMBER < 0x10100000L HMAC_CTX ctx; #else HMAC_CTX *ctx = NULL; #endif fido_blob_t *npe = NULL; /* new pin, encrypted */ fido_blob_t *ph = NULL; /* pin hash */ fido_blob_t *phe = NULL; /* pin hash, encrypted */ int ok = -1; if ((npe = fido_blob_new()) == NULL || (ph = fido_blob_new()) == NULL || (phe = fido_blob_new()) == NULL) goto fail; if (aes256_cbc_enc(key, new_pin, npe) < 0) { fido_log_debug("%s: aes256_cbc_enc 1", __func__); goto fail; } if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) { fido_log_debug("%s: sha256", __func__); goto fail; } ph->len = 16; /* first 16 bytes */ if (aes256_cbc_enc(key, ph, phe) < 0) { fido_log_debug("%s: aes256_cbc_enc 2", __func__); goto fail; } #if OPENSSL_VERSION_NUMBER < 0x10100000L HMAC_CTX_init(&ctx); if ((md = EVP_sha256()) == NULL || HMAC_Init_ex(&ctx, key->ptr, (int)key->len, md, NULL) == 0 || HMAC_Update(&ctx, npe->ptr, (int)npe->len) == 0 || HMAC_Update(&ctx, phe->ptr, (int)phe->len) == 0 || HMAC_Final(&ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { fido_log_debug("%s: HMAC", __func__); goto fail; } #else if ((ctx = HMAC_CTX_new()) == NULL || (md = EVP_sha256()) == NULL || HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 || HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 || HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 || HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { fido_log_debug("%s: HMAC", __func__); goto fail; } #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ if ((item = cbor_build_bytestring(dgst, 16)) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); goto fail; } ok = 0; fail: fido_blob_free(&npe); fido_blob_free(&ph); fido_blob_free(&phe); #if OPENSSL_VERSION_NUMBER >= 0x10100000L if (ctx != NULL) HMAC_CTX_free(ctx); #endif if (ok < 0) { if (item != NULL) { cbor_decref(&item); item = NULL; } } return (item); } cbor_item_t * cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin) { const EVP_MD *md = NULL; unsigned char dgst[SHA256_DIGEST_LENGTH]; unsigned int dgst_len; cbor_item_t *item = NULL; fido_blob_t *pe = NULL; if ((pe = fido_blob_new()) == NULL) goto fail; if (aes256_cbc_enc(key, pin, pe) < 0) { fido_log_debug("%s: aes256_cbc_enc", __func__); goto fail; } if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr, (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) { fido_log_debug("%s: HMAC", __func__); goto fail; } item = cbor_build_bytestring(dgst, 16); fail: fido_blob_free(&pe); return (item); } cbor_item_t * cbor_encode_pin_hash_enc(const fido_blob_t *shared, const fido_blob_t *pin) { cbor_item_t *item = NULL; fido_blob_t *ph = NULL; fido_blob_t *phe = NULL; if ((ph = fido_blob_new()) == NULL || (phe = fido_blob_new()) == NULL) goto fail; if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) { fido_log_debug("%s: SHA256", __func__); goto fail; } ph->len = 16; /* first 16 bytes */ if (aes256_cbc_enc(shared, ph, phe) < 0) { fido_log_debug("%s: aes256_cbc_enc", __func__); goto fail; } item = cbor_build_bytestring(phe->ptr, phe->len); fail: fido_blob_free(&ph); fido_blob_free(&phe); return (item); } cbor_item_t * cbor_encode_hmac_secret_param(const fido_blob_t *ecdh, const es256_pk_t *pk, const fido_blob_t *hmac_salt) { cbor_item_t *item = NULL; cbor_item_t *param = NULL; cbor_item_t *argv[3]; struct cbor_pair pair; memset(argv, 0, sizeof(argv)); memset(&pair, 0, sizeof(pair)); if (ecdh == NULL || pk == NULL || hmac_salt->ptr == NULL) { fido_log_debug("%s: ecdh=%p, pk=%p, hmac_salt->ptr=%p", __func__, (const void *)ecdh, (const void *)pk, (const void *)hmac_salt->ptr); goto fail; } if (hmac_salt->len != 32 && hmac_salt->len != 64) { fido_log_debug("%s: hmac_salt->len=%zu", __func__, hmac_salt->len); goto fail; } /* XXX not pin, but salt */ if ((argv[0] = es256_pk_encode(pk, 1)) == NULL || (argv[1] = cbor_encode_pin_enc(ecdh, hmac_salt)) == NULL || (argv[2] = cbor_encode_set_pin_auth(ecdh, hmac_salt)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } if ((param = cbor_flatten_vector(argv, 3)) == NULL) { fido_log_debug("%s: cbor_flatten_vector", __func__); goto fail; } if ((item = cbor_new_definite_map(1)) == NULL) { fido_log_debug("%s: cbor_new_definite_map", __func__); goto fail; } if ((pair.key = cbor_build_string("hmac-secret")) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } pair.value = param; if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); cbor_decref(&item); item = NULL; goto fail; } fail: for (size_t i = 0; i < 3; i++) if (argv[i] != NULL) cbor_decref(&argv[i]); if (param != NULL) cbor_decref(¶m); if (pair.key != NULL) cbor_decref(&pair.key); return (item); } int cbor_decode_fmt(const cbor_item_t *item, char **fmt) { char *type = NULL; if (cbor_string_copy(item, &type) < 0) { fido_log_debug("%s: cbor_string_copy", __func__); return (-1); } if (strcmp(type, "packed") && strcmp(type, "fido-u2f")) { fido_log_debug("%s: type=%s", __func__, type); free(type); return (-1); } *fmt = type; return (0); } struct cose_key { int kty; int alg; int crv; }; static int find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg) { struct cose_key *cose_key = arg; if (cbor_isa_uint(key) == true && cbor_int_get_width(key) == CBOR_INT_8) { switch (cbor_get_uint8(key)) { case 1: if (cbor_isa_uint(val) == false || cbor_get_int(val) > INT_MAX || cose_key->kty != 0) { fido_log_debug("%s: kty", __func__); return (-1); } cose_key->kty = (int)cbor_get_int(val); break; case 3: if (cbor_isa_negint(val) == false || cbor_get_int(val) > INT_MAX || cose_key->alg != 0) { fido_log_debug("%s: alg", __func__); return (-1); } cose_key->alg = -(int)cbor_get_int(val) - 1; break; } } else if (cbor_isa_negint(key) == true && cbor_int_get_width(key) == CBOR_INT_8) { if (cbor_get_uint8(key) == 0) { /* get crv if not rsa, otherwise ignore */ if (cbor_isa_uint(val) == true && cbor_get_int(val) <= INT_MAX && cose_key->crv == 0) cose_key->crv = (int)cbor_get_int(val); } } return (0); } static int get_cose_alg(const cbor_item_t *item, int *cose_alg) { struct cose_key cose_key; memset(&cose_key, 0, sizeof(cose_key)); *cose_alg = 0; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, &cose_key, find_cose_alg) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } switch (cose_key.alg) { case COSE_ES256: if (cose_key.kty != COSE_KTY_EC2 || cose_key.crv != COSE_P256) { fido_log_debug("%s: invalid kty/crv", __func__); return (-1); } break; case COSE_EDDSA: if (cose_key.kty != COSE_KTY_OKP || cose_key.crv != COSE_ED25519) { fido_log_debug("%s: invalid kty/crv", __func__); return (-1); } break; case COSE_RS256: if (cose_key.kty != COSE_KTY_RSA) { fido_log_debug("%s: invalid kty/crv", __func__); return (-1); } break; default: fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg); return (-1); } *cose_alg = cose_key.alg; return (0); } int cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key) { if (get_cose_alg(item, type) < 0) { fido_log_debug("%s: get_cose_alg", __func__); return (-1); } switch (*type) { case COSE_ES256: if (es256_pk_decode(item, key) < 0) { fido_log_debug("%s: es256_pk_decode", __func__); return (-1); } break; case COSE_RS256: if (rs256_pk_decode(item, key) < 0) { fido_log_debug("%s: rs256_pk_decode", __func__); return (-1); } break; case COSE_EDDSA: if (eddsa_pk_decode(item, key) < 0) { fido_log_debug("%s: eddsa_pk_decode", __func__); return (-1); } break; default: fido_log_debug("%s: invalid cose_alg %d", __func__, *type); return (-1); } return (0); } static int decode_attcred(const unsigned char **buf, size_t *len, int cose_alg, fido_attcred_t *attcred) { cbor_item_t *item = NULL; struct cbor_load_result cbor; uint16_t id_len; int ok = -1; fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, *len); if (fido_buf_read(buf, len, &attcred->aaguid, sizeof(attcred->aaguid)) < 0) { fido_log_debug("%s: fido_buf_read aaguid", __func__); return (-1); } if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) { fido_log_debug("%s: fido_buf_read id_len", __func__); return (-1); } attcred->id.len = (size_t)be16toh(id_len); if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL) return (-1); fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len); if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) { fido_log_debug("%s: fido_buf_read id", __func__); return (-1); } if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); fido_log_xxd(*buf, *len); goto fail; } if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) { fido_log_debug("%s: cbor_decode_pubkey", __func__); goto fail; } if (attcred->type != cose_alg) { fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__, attcred->type, cose_alg); goto fail; } *buf += cbor.read; *len -= cbor.read; ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } static int decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) { int *authdata_ext = arg; char *type = NULL; int ok = -1; if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (cbor_isa_float_ctrl(val) == false || cbor_float_get_width(val) != CBOR_FLOAT_0 || cbor_is_bool(val) == false || *authdata_ext != 0) { fido_log_debug("%s: cbor type", __func__); goto out; } if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) *authdata_ext |= FIDO_EXT_HMAC_SECRET; ok = 0; out: free(type); return (ok); } static int decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int ok = -1; fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, *len); *authdata_ext = 0; if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); fido_log_xxd(*buf, *len); goto fail; } if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_size(item) != 1 || cbor_map_iter(item, authdata_ext, decode_extension) < 0) { fido_log_debug("%s: cbor type", __func__); goto fail; } *buf += cbor.read; *len -= cbor.read; ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } static int decode_hmac_secret_aux(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_blob_t *out = arg; char *type = NULL; int ok = -1; if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } ok = cbor_bytestring_copy(val, &out->ptr, &out->len); out: free(type); return (ok); } static int decode_hmac_secret(const unsigned char **buf, size_t *len, fido_blob_t *out) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int ok = -1; fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, *len); if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); fido_log_xxd(*buf, *len); goto fail; } if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_size(item) != 1 || cbor_map_iter(item, out, decode_hmac_secret_aux) < 0) { fido_log_debug("%s: cbor type", __func__); goto fail; } *buf += cbor.read; *len -= cbor.read; ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } int cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, fido_blob_t *authdata_cbor, fido_authdata_t *authdata, fido_attcred_t *attcred, int *authdata_ext) { const unsigned char *buf = NULL; size_t len; size_t alloc_len; if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (authdata_cbor->ptr != NULL || (authdata_cbor->len = cbor_serialize_alloc(item, &authdata_cbor->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); return (-1); } buf = cbor_bytestring_handle(item); len = cbor_bytestring_length(item); fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { fido_log_debug("%s: fido_buf_read", __func__); return (-1); } authdata->sigcount = be32toh(authdata->sigcount); if (attcred != NULL) { if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 || decode_attcred(&buf, &len, cose_alg, attcred) < 0) return (-1); } if (authdata_ext != NULL) { if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && decode_extensions(&buf, &len, authdata_ext) < 0) return (-1); } /* XXX we should probably ensure that len == 0 at this point */ return (FIDO_OK); } int cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor, fido_authdata_t *authdata, int *authdata_ext, fido_blob_t *hmac_secret_enc) { const unsigned char *buf = NULL; size_t len; size_t alloc_len; if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (authdata_cbor->ptr != NULL || (authdata_cbor->len = cbor_serialize_alloc(item, &authdata_cbor->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); return (-1); } buf = cbor_bytestring_handle(item); len = cbor_bytestring_length(item); fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { fido_log_debug("%s: fido_buf_read", __func__); return (-1); } authdata->sigcount = be32toh(authdata->sigcount); *authdata_ext = 0; if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) { /* XXX semantic leap: extensions -> hmac_secret */ if (decode_hmac_secret(&buf, &len, hmac_secret_enc) < 0) { fido_log_debug("%s: decode_hmac_secret", __func__); return (-1); } *authdata_ext = FIDO_EXT_HMAC_SECRET; } /* XXX we should probably ensure that len == 0 at this point */ return (FIDO_OK); } static int decode_x5c(const cbor_item_t *item, void *arg) { fido_blob_t *x5c = arg; if (x5c->len) return (0); /* ignore */ return (cbor_bytestring_copy(item, &x5c->ptr, &x5c->len)); } static int decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_attstmt_t *attstmt = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "alg")) { if (cbor_isa_negint(val) == false || cbor_int_get_width(val) != CBOR_INT_8 || cbor_get_uint8(val) != -COSE_ES256 - 1) { fido_log_debug("%s: alg", __func__); goto out; } } else if (!strcmp(name, "sig")) { if (cbor_bytestring_copy(val, &attstmt->sig.ptr, &attstmt->sig.len) < 0) { fido_log_debug("%s: sig", __func__); goto out; } } else if (!strcmp(name, "x5c")) { if (cbor_isa_array(val) == false || cbor_array_is_definite(val) == false || cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) { fido_log_debug("%s: x5c", __func__); goto out; } } ok = 0; out: free(name); return (ok); } int cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } int cbor_decode_uint64(const cbor_item_t *item, uint64_t *n) { if (cbor_isa_uint(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } *n = cbor_get_int(item); return (0); } static int decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_blob_t *id = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "id")) if (cbor_bytestring_copy(val, &id->ptr, &id->len) < 0) { fido_log_debug("%s: cbor_bytestring_copy", __func__); goto out; } ok = 0; out: free(name); return (ok); } int cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, id, decode_cred_id_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } static int decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_user_t *user = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "icon")) { if (cbor_string_copy(val, &user->icon) < 0) { fido_log_debug("%s: icon", __func__); goto out; } } else if (!strcmp(name, "name")) { if (cbor_string_copy(val, &user->name) < 0) { fido_log_debug("%s: name", __func__); goto out; } } else if (!strcmp(name, "displayName")) { if (cbor_string_copy(val, &user->display_name) < 0) { fido_log_debug("%s: display_name", __func__); goto out; } } else if (!strcmp(name, "id")) { if (cbor_bytestring_copy(val, &user->id.ptr, &user->id.len) < 0) { fido_log_debug("%s: id", __func__); goto out; } } ok = 0; out: free(name); return (ok); } int cbor_decode_user(const cbor_item_t *item, fido_user_t *user) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, user, decode_user_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } static int decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_rp_t *rp = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "id")) { if (cbor_string_copy(val, &rp->id) < 0) { fido_log_debug("%s: id", __func__); goto out; } } else if (!strcmp(name, "name")) { if (cbor_string_copy(val, &rp->name) < 0) { fido_log_debug("%s: name", __func__); goto out; } } ok = 0; out: free(name); return (ok); } int cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } libfido2-1.3.1/src/cred.c000066400000000000000000000543601362326726700151040ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "fido.h" #include "fido/es256.h" static int parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cred_t *cred = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* fmt */ return (cbor_decode_fmt(val, &cred->fmt)); case 2: /* authdata */ return (cbor_decode_cred_authdata(val, cred->type, &cred->authdata_cbor, &cred->authdata, &cred->attcred, &cred->authdata_ext)); case 3: /* attestation statement */ return (cbor_decode_attstmt(val, &cred->attstmt)); default: /* ignore */ fido_log_debug("%s: cbor type", __func__); return (0); } } static int fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin) { fido_blob_t f; fido_blob_t *ecdh = NULL; es256_pk_t *pk = NULL; cbor_item_t *argv[9]; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if (cred->cdh.ptr == NULL || cred->type == 0) { fido_log_debug("%s: cdh=%p, type=%d", __func__, (void *)cred->cdh.ptr, cred->type); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL || (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL || (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL || (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* excluded credentials */ if (cred->excl.len) if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) { fido_log_debug("%s: cbor_encode_pubkey_list", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* extensions */ if (cred->ext) if ((argv[5] = cbor_encode_extensions(cred->ext)) == NULL) { fido_log_debug("%s: cbor_encode_extensions", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* options */ if (cred->rk != FIDO_OPT_OMIT || cred->uv != FIDO_OPT_OMIT) if ((argv[6] = cbor_encode_options(cred->rk, cred->uv)) == NULL) { fido_log_debug("%s: cbor_encode_options", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* pin authentication */ if (pin) { if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_pin_params(dev, &cred->cdh, pk, ecdh, pin, &argv[7], &argv[8])) != FIDO_OK) { fido_log_debug("%s: cbor_add_pin_params", __func__); goto fail; } } /* framing and transmission */ if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, 9, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: es256_pk_free(&pk); fido_blob_free(&ecdh); cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; fido_cred_reset_rx(cred); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred, parse_makecred_reply)) != FIDO_OK) { fido_log_debug("%s: parse_makecred_reply", __func__); return (r); } if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) || fido_blob_is_empty(&cred->attcred.id) || fido_blob_is_empty(&cred->attstmt.sig)) { fido_cred_reset_rx(cred); return (FIDO_ERR_INVALID_CBOR); } return (FIDO_OK); } static int fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, int ms) { int r; if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK || (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) { if (fido_dev_is_fido2(dev) == false) { if (pin != NULL || cred->rk == FIDO_OPT_TRUE || cred->ext != 0) return (FIDO_ERR_UNSUPPORTED_OPTION); return (u2f_register(dev, cred, -1)); } return (fido_dev_make_cred_wait(dev, cred, pin, -1)); } static int check_extensions(int authdata_ext, int ext) { if (authdata_ext != ext) { fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, authdata_ext, ext); return (-1); } return (0); } int fido_check_rp_id(const char *id, const unsigned char *obtained_hash) { unsigned char expected_hash[SHA256_DIGEST_LENGTH]; explicit_bzero(expected_hash, sizeof(expected_hash)); if (SHA256((const unsigned char *)id, strlen(id), expected_hash) != expected_hash) { fido_log_debug("%s: sha256", __func__); return (-1); } return (timingsafe_bcmp(expected_hash, obtained_hash, SHA256_DIGEST_LENGTH)); } static int get_signed_hash_packed(fido_blob_t *dgst, const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor) { cbor_item_t *item = NULL; unsigned char *authdata_ptr = NULL; size_t authdata_len; struct cbor_load_result cbor; SHA256_CTX ctx; int ok = -1; if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); goto fail; } if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); goto fail; } authdata_ptr = cbor_bytestring_handle(item); authdata_len = cbor_bytestring_length(item); if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || SHA256_Final(dgst->ptr, &ctx) == 0) { fido_log_debug("%s: sha256", __func__); goto fail; } ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } static int get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id, const es256_pk_t *pk) { const uint8_t zero = 0; const uint8_t four = 4; /* uncompressed point */ SHA256_CTX ctx; if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 || SHA256_Update(&ctx, rp_id, rp_id_len) == 0 || SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || SHA256_Update(&ctx, id->ptr, id->len) == 0 || SHA256_Update(&ctx, &four, sizeof(four)) == 0 || SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 || SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 || SHA256_Final(dgst->ptr, &ctx) == 0) { fido_log_debug("%s: sha256", __func__); return (-1); } return (0); } static int verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c, const fido_blob_t *sig) { BIO *rawcert = NULL; X509 *cert = NULL; EVP_PKEY *pkey = NULL; EC_KEY *ec; int ok = -1; /* openssl needs ints */ if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) { fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu", __func__, dgst->len, x5c->len, sig->len); return (-1); } /* fetch key from x509 */ if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL || (cert = d2i_X509_bio(rawcert, NULL)) == NULL || (pkey = X509_get_pubkey(cert)) == NULL || (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { fido_log_debug("%s: x509 key", __func__); goto fail; } if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, (int)sig->len, ec) != 1) { fido_log_debug("%s: ECDSA_verify", __func__); goto fail; } ok = 0; fail: if (rawcert != NULL) BIO_free(rawcert); if (cert != NULL) X509_free(cert); if (pkey != NULL) EVP_PKEY_free(pkey); return (ok); } int fido_cred_verify(const fido_cred_t *cred) { unsigned char buf[SHA256_DIGEST_LENGTH]; fido_blob_t dgst; int r; dgst.ptr = buf; dgst.len = sizeof(buf); /* do we have everything we need? */ if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL || cred->fmt == NULL || cred->attcred.id.ptr == NULL || cred->rp.id == NULL) { fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, (void *)cred->authdata_cbor.ptr, (void *)cred->attstmt.x5c.ptr, (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, (void *)cred->attcred.id.ptr, cred->rp.id); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { fido_log_debug("%s: fido_check_rp_id", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, cred->uv) < 0) { fido_log_debug("%s: fido_check_flags", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (check_extensions(cred->authdata_ext, cred->ext) < 0) { fido_log_debug("%s: check_extensions", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (!strcmp(cred->fmt, "packed")) { if (get_signed_hash_packed(&dgst, &cred->cdh, &cred->authdata_cbor) < 0) { fido_log_debug("%s: get_signed_hash_packed", __func__); r = FIDO_ERR_INTERNAL; goto out; } } else { if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, sizeof(cred->authdata.rp_id_hash), &cred->cdh, &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { fido_log_debug("%s: get_signed_hash_u2f", __func__); r = FIDO_ERR_INTERNAL; goto out; } } if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) { fido_log_debug("%s: verify_sig", __func__); r = FIDO_ERR_INVALID_SIG; goto out; } r = FIDO_OK; out: explicit_bzero(buf, sizeof(buf)); return (r); } int fido_cred_verify_self(const fido_cred_t *cred) { unsigned char buf[SHA256_DIGEST_LENGTH]; fido_blob_t dgst; int ok = -1; int r; dgst.ptr = buf; dgst.len = sizeof(buf); /* do we have everything we need? */ if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL || cred->fmt == NULL || cred->attcred.id.ptr == NULL || cred->rp.id == NULL) { fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, (void *)cred->authdata_cbor.ptr, (void *)cred->attstmt.x5c.ptr, (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, (void *)cred->attcred.id.ptr, cred->rp.id); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { fido_log_debug("%s: fido_check_rp_id", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, cred->uv) < 0) { fido_log_debug("%s: fido_check_flags", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (check_extensions(cred->authdata_ext, cred->ext) < 0) { fido_log_debug("%s: check_extensions", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (!strcmp(cred->fmt, "packed")) { if (get_signed_hash_packed(&dgst, &cred->cdh, &cred->authdata_cbor) < 0) { fido_log_debug("%s: get_signed_hash_packed", __func__); r = FIDO_ERR_INTERNAL; goto out; } } else { if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, sizeof(cred->authdata.rp_id_hash), &cred->cdh, &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { fido_log_debug("%s: get_signed_hash_u2f", __func__); r = FIDO_ERR_INTERNAL; goto out; } } switch (cred->attcred.type) { case COSE_ES256: ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256, &cred->attstmt.sig); break; case COSE_RS256: ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256, &cred->attstmt.sig); break; case COSE_EDDSA: ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa, &cred->attstmt.sig); break; default: fido_log_debug("%s: unsupported cose_alg %d", __func__, cred->attcred.type); r = FIDO_ERR_UNSUPPORTED_OPTION; goto out; } if (ok < 0) r = FIDO_ERR_INVALID_SIG; else r = FIDO_OK; out: explicit_bzero(buf, sizeof(buf)); return (r); } fido_cred_t * fido_cred_new(void) { return (calloc(1, sizeof(fido_cred_t))); } static void fido_cred_clean_authdata(fido_cred_t *cred) { free(cred->authdata_cbor.ptr); free(cred->attcred.id.ptr); memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext)); memset(&cred->authdata_cbor, 0, sizeof(cred->authdata_cbor)); memset(&cred->authdata, 0, sizeof(cred->authdata)); memset(&cred->attcred, 0, sizeof(cred->attcred)); } void fido_cred_reset_tx(fido_cred_t *cred) { free(cred->cdh.ptr); free(cred->rp.id); free(cred->rp.name); free(cred->user.id.ptr); free(cred->user.icon); free(cred->user.name); free(cred->user.display_name); fido_free_blob_array(&cred->excl); memset(&cred->cdh, 0, sizeof(cred->cdh)); memset(&cred->rp, 0, sizeof(cred->rp)); memset(&cred->user, 0, sizeof(cred->user)); memset(&cred->excl, 0, sizeof(cred->excl)); cred->type = 0; cred->ext = 0; cred->rk = FIDO_OPT_OMIT; cred->uv = FIDO_OPT_OMIT; } static void fido_cred_clean_x509(fido_cred_t *cred) { free(cred->attstmt.x5c.ptr); cred->attstmt.x5c.ptr = NULL; cred->attstmt.x5c.len = 0; } static void fido_cred_clean_sig(fido_cred_t *cred) { free(cred->attstmt.sig.ptr); cred->attstmt.sig.ptr = NULL; cred->attstmt.sig.len = 0; } void fido_cred_reset_rx(fido_cred_t *cred) { free(cred->fmt); cred->fmt = NULL; fido_cred_clean_authdata(cred); fido_cred_clean_x509(cred); fido_cred_clean_sig(cred); } void fido_cred_free(fido_cred_t **cred_p) { fido_cred_t *cred; if (cred_p == NULL || (cred = *cred_p) == NULL) return; fido_cred_reset_tx(cred); fido_cred_reset_rx(cred); free(cred); *cred_p = NULL; } int fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int r; fido_cred_clean_authdata(cred); if (ptr == NULL || len == 0) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((item = cbor_load(ptr, len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { fido_log_debug("%s: cbor_decode_cred_authdata", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_cred_clean_authdata(cred); return (r); } int fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; int r; fido_cred_clean_authdata(cred); if (ptr == NULL || len == 0) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((item = cbor_build_bytestring(ptr, len)) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { fido_log_debug("%s: cbor_decode_cred_authdata", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_cred_clean_authdata(cred); return (r); } int fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len) { unsigned char *x509; fido_cred_clean_x509(cred); if (ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); if ((x509 = malloc(len)) == NULL) return (FIDO_ERR_INTERNAL); memcpy(x509, ptr, len); cred->attstmt.x5c.ptr = x509; cred->attstmt.x5c.len = len; return (FIDO_OK); } int fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len) { unsigned char *sig; fido_cred_clean_sig(cred); if (ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); if ((sig = malloc(len)) == NULL) return (FIDO_ERR_INTERNAL); memcpy(sig, ptr, len); cred->attstmt.sig.ptr = sig; cred->attstmt.sig.len = len; return (FIDO_OK); } int fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len) { fido_blob_t id_blob; fido_blob_t *list_ptr; memset(&id_blob, 0, sizeof(id_blob)); if (fido_blob_set(&id_blob, id_ptr, id_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); if (cred->excl.len == SIZE_MAX) { free(id_blob.ptr); return (FIDO_ERR_INVALID_ARGUMENT); } if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len, cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) { free(id_blob.ptr); return (FIDO_ERR_INTERNAL); } list_ptr[cred->excl.len++] = id_blob; cred->excl.ptr = list_ptr; return (FIDO_OK); } int fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash, size_t hash_len) { if (fido_blob_set(&cred->cdh, hash, hash_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name) { fido_rp_t *rp = &cred->rp; if (rp->id != NULL) { free(rp->id); rp->id = NULL; } if (rp->name != NULL) { free(rp->name); rp->name = NULL; } if (id != NULL && (rp->id = strdup(id)) == NULL) goto fail; if (name != NULL && (rp->name = strdup(name)) == NULL) goto fail; return (FIDO_OK); fail: free(rp->id); free(rp->name); rp->id = NULL; rp->name = NULL; return (FIDO_ERR_INTERNAL); } int fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id, size_t user_id_len, const char *name, const char *display_name, const char *icon) { fido_user_t *up = &cred->user; if (up->id.ptr != NULL) { free(up->id.ptr); up->id.ptr = NULL; up->id.len = 0; } if (up->name != NULL) { free(up->name); up->name = NULL; } if (up->display_name != NULL) { free(up->display_name); up->display_name = NULL; } if (up->icon != NULL) { free(up->icon); up->icon = NULL; } if (user_id != NULL) { if ((up->id.ptr = malloc(user_id_len)) == NULL) goto fail; memcpy(up->id.ptr, user_id, user_id_len); up->id.len = user_id_len; } if (name != NULL && (up->name = strdup(name)) == NULL) goto fail; if (display_name != NULL && (up->display_name = strdup(display_name)) == NULL) goto fail; if (icon != NULL && (up->icon = strdup(icon)) == NULL) goto fail; return (FIDO_OK); fail: free(up->id.ptr); free(up->name); free(up->display_name); free(up->icon); up->id.ptr = NULL; up->id.len = 0; up->name = NULL; up->display_name = NULL; up->icon = NULL; return (FIDO_ERR_INTERNAL); } int fido_cred_set_extensions(fido_cred_t *cred, int ext) { if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET) return (FIDO_ERR_INVALID_ARGUMENT); cred->ext = ext; return (FIDO_OK); } int fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv) { cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; return (FIDO_OK); } int fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk) { cred->rk = rk; return (FIDO_OK); } int fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv) { cred->uv = uv; return (FIDO_OK); } int fido_cred_set_fmt(fido_cred_t *cred, const char *fmt) { free(cred->fmt); cred->fmt = NULL; if (fmt == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f")) return (FIDO_ERR_INVALID_ARGUMENT); if ((cred->fmt = strdup(fmt)) == NULL) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } int fido_cred_set_type(fido_cred_t *cred, int cose_alg) { if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) || cred->type != 0) return (FIDO_ERR_INVALID_ARGUMENT); cred->type = cose_alg; return (FIDO_OK); } int fido_cred_type(const fido_cred_t *cred) { return (cred->type); } uint8_t fido_cred_flags(const fido_cred_t *cred) { return (cred->authdata.flags); } const unsigned char * fido_cred_clientdata_hash_ptr(const fido_cred_t *cred) { return (cred->cdh.ptr); } size_t fido_cred_clientdata_hash_len(const fido_cred_t *cred) { return (cred->cdh.len); } const unsigned char * fido_cred_x5c_ptr(const fido_cred_t *cred) { return (cred->attstmt.x5c.ptr); } size_t fido_cred_x5c_len(const fido_cred_t *cred) { return (cred->attstmt.x5c.len); } const unsigned char * fido_cred_sig_ptr(const fido_cred_t *cred) { return (cred->attstmt.sig.ptr); } size_t fido_cred_sig_len(const fido_cred_t *cred) { return (cred->attstmt.sig.len); } const unsigned char * fido_cred_authdata_ptr(const fido_cred_t *cred) { return (cred->authdata_cbor.ptr); } size_t fido_cred_authdata_len(const fido_cred_t *cred) { return (cred->authdata_cbor.len); } const unsigned char * fido_cred_pubkey_ptr(const fido_cred_t *cred) { const void *ptr; switch (cred->attcred.type) { case COSE_ES256: ptr = &cred->attcred.pubkey.es256; break; case COSE_RS256: ptr = &cred->attcred.pubkey.rs256; break; case COSE_EDDSA: ptr = &cred->attcred.pubkey.eddsa; break; default: ptr = NULL; break; } return (ptr); } size_t fido_cred_pubkey_len(const fido_cred_t *cred) { size_t len; switch (cred->attcred.type) { case COSE_ES256: len = sizeof(cred->attcred.pubkey.es256); break; case COSE_RS256: len = sizeof(cred->attcred.pubkey.rs256); break; case COSE_EDDSA: len = sizeof(cred->attcred.pubkey.eddsa); break; default: len = 0; break; } return (len); } const unsigned char * fido_cred_id_ptr(const fido_cred_t *cred) { return (cred->attcred.id.ptr); } size_t fido_cred_id_len(const fido_cred_t *cred) { return (cred->attcred.id.len); } const char * fido_cred_fmt(const fido_cred_t *cred) { return (cred->fmt); } const char * fido_cred_rp_id(const fido_cred_t *cred) { return (cred->rp.id); } const char * fido_cred_rp_name(const fido_cred_t *cred) { return (cred->rp.name); } const char * fido_cred_user_name(const fido_cred_t *cred) { return (cred->user.name); } const char * fido_cred_display_name(const fido_cred_t *cred) { return (cred->user.display_name); } const unsigned char * fido_cred_user_id_ptr(const fido_cred_t *cred) { return (cred->user.id.ptr); } size_t fido_cred_user_id_len(const fido_cred_t *cred) { return (cred->user.id.len); } libfido2-1.3.1/src/credman.c000066400000000000000000000375711362326726700156050ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include "fido.h" #include "fido/credman.h" #include "fido/es256.h" #define CMD_CRED_METADATA 0x01 #define CMD_RP_BEGIN 0x02 #define CMD_RP_NEXT 0x03 #define CMD_RK_BEGIN 0x04 #define CMD_RK_NEXT 0x05 #define CMD_DELETE_CRED 0x06 static int credman_grow_array(void **ptr, size_t *n_alloc, size_t *n_rx, size_t n, size_t size) { void *new_ptr; #ifdef FIDO_FUZZ if (n > UINT8_MAX) { fido_log_debug("%s: n > UINT8_MAX", __func__); return (-1); } #endif if (n < *n_alloc) return (0); /* sanity check */ if (*n_rx > 0 || *n_rx > *n_alloc || n < *n_alloc) { fido_log_debug("%s: n=%zu, n_rx=%zu, n_alloc=%zu", __func__, n, *n_rx, *n_alloc); return (-1); } if ((new_ptr = recallocarray(*ptr, *n_alloc, n, size)) == NULL) return (-1); *ptr = new_ptr; *n_alloc = n; return (0); } static int credman_prepare_hmac(uint8_t cmd, const fido_blob_t *body, cbor_item_t **param, fido_blob_t *hmac_data) { cbor_item_t *param_cbor[2]; size_t n; int ok = -1; memset(¶m_cbor, 0, sizeof(param_cbor)); if (body == NULL) return (fido_blob_set(hmac_data, &cmd, sizeof(cmd))); switch (cmd) { case CMD_RK_BEGIN: n = 1; param_cbor[n - 1] = fido_blob_encode(body); break; case CMD_DELETE_CRED: n = 2; param_cbor[n - 1] = cbor_encode_pubkey(body); break; default: fido_log_debug("%s: unknown cmd=0x%02x", __func__, cmd); return (-1); } if (param_cbor[n - 1] == NULL) { fido_log_debug("%s: cbor encode", __func__); return (-1); } if ((*param = cbor_flatten_vector(param_cbor, n)) == NULL) { fido_log_debug("%s: cbor_flatten_vector", __func__); goto fail; } if (cbor_build_frame(cmd, param_cbor, n, hmac_data) < 0) { fido_log_debug("%s: cbor_build_frame", __func__); goto fail; } ok = 0; fail: cbor_vector_free(param_cbor, nitems(param_cbor)); return (ok); } static int credman_tx(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *param, const char *pin) { fido_blob_t f; fido_blob_t *ecdh = NULL; fido_blob_t hmac; es256_pk_t *pk = NULL; cbor_item_t *argv[4]; int r = FIDO_ERR_INTERNAL; memset(&f, 0, sizeof(f)); memset(&hmac, 0, sizeof(hmac)); memset(&argv, 0, sizeof(argv)); /* subCommand */ if ((argv[0] = cbor_build_uint8(cmd)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } /* pinProtocol, pinAuth */ if (pin != NULL) { if (credman_prepare_hmac(cmd, param, &argv[1], &hmac) < 0) { fido_log_debug("%s: credman_prepare_hmac", __func__); goto fail; } if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin, &argv[3], &argv[2])) != FIDO_OK) { fido_log_debug("%s: cbor_add_pin_params", __func__); goto fail; } } /* framing and transmission */ if (cbor_build_frame(CTAP_CBOR_CRED_MGMT_PRE, argv, 4, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: es256_pk_free(&pk); fido_blob_free(&ecdh); cbor_vector_free(argv, nitems(argv)); free(f.ptr); free(hmac.ptr); return (r); } static int credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_credman_metadata_t *metadata = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: return (cbor_decode_uint64(val, &metadata->rk_existing)); case 2: return (cbor_decode_uint64(val, &metadata->rk_remaining)); default: fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } } static int credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[512]; int reply_len; int r; memset(metadata, 0, sizeof(*metadata)); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, metadata, credman_parse_metadata)) != FIDO_OK) { fido_log_debug("%s: credman_parse_metadata", __func__); return (r); } return (FIDO_OK); } static int credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata, const char *pin, int ms) { int r; if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin)) != FIDO_OK || (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, const char *pin) { if (fido_dev_is_fido2(dev) == false) return (FIDO_ERR_INVALID_COMMAND); if (pin == NULL) return (FIDO_ERR_INVALID_ARGUMENT); return (credman_get_metadata_wait(dev, metadata, pin, -1)); } static int credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cred_t *cred = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 6: /* user entity */ return (cbor_decode_user(val, &cred->user)); case 7: return (cbor_decode_cred_id(val, &cred->attcred.id)); case 8: if (cbor_decode_pubkey(val, &cred->attcred.type, &cred->attcred.pubkey) < 0) return (-1); cred->type = cred->attcred.type; /* XXX */ return (0); default: fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } } static void credman_reset_rk(fido_credman_rk_t *rk) { for (size_t i = 0; i < rk->n_alloc; i++) { fido_cred_reset_tx(&rk->ptr[i]); fido_cred_reset_rx(&rk->ptr[i]); } free(rk->ptr); rk->ptr = NULL; memset(rk, 0, sizeof(*rk)); } static int credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_credman_rk_t *rk = arg; uint64_t n; /* totalCredentials */ if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 9) { fido_log_debug("%s: cbor_type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx, (size_t)n, sizeof(*rk->ptr)) < 0) { fido_log_debug("%s: credman_grow_array", __func__); return (-1); } return (0); } static int credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; credman_reset_rk(rk); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* adjust as needed */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, rk, credman_parse_rk_count)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk_count", __func__); return (r); } if (rk->n_alloc == 0) { fido_log_debug("%s: n_alloc=0", __func__); return (FIDO_OK); } /* parse the first rk */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[0], credman_parse_rk)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk", __func__); return (r); } rk->n_rx++; return (FIDO_OK); } static int credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* sanity check */ if (rk->n_rx >= rk->n_alloc) { fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx, rk->n_alloc); return (FIDO_ERR_INTERNAL); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[rk->n_rx], credman_parse_rk)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk", __func__); return (r); } return (FIDO_OK); } static int credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk, const char *pin, int ms) { fido_blob_t rp_dgst; uint8_t dgst[SHA256_DIGEST_LENGTH]; int r; if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) { fido_log_debug("%s: sha256", __func__); return (FIDO_ERR_INTERNAL); } rp_dgst.ptr = dgst; rp_dgst.len = sizeof(dgst); if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin)) != FIDO_OK || (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK) return (r); while (rk->n_rx < rk->n_alloc) { if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL)) != FIDO_OK || (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK) return (r); rk->n_rx++; } return (FIDO_OK); } int fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk, const char *pin) { if (fido_dev_is_fido2(dev) == false) return (FIDO_ERR_INVALID_COMMAND); if (pin == NULL) return (FIDO_ERR_INVALID_ARGUMENT); return (credman_get_rk_wait(dev, rp_id, rk, pin, -1)); } static int credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id, size_t cred_id_len, const char *pin, int ms) { fido_blob_t cred; int r; memset(&cred, 0, sizeof(cred)); if (fido_blob_set(&cred, cred_id, cred_id_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) goto fail; r = FIDO_OK; fail: free(cred.ptr); return (r); } int fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id, size_t cred_id_len, const char *pin) { if (fido_dev_is_fido2(dev) == false) return (FIDO_ERR_INVALID_COMMAND); if (pin == NULL) return (FIDO_ERR_INVALID_ARGUMENT); return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, -1)); } static int credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg) { struct fido_credman_single_rp *rp = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 3: return (cbor_decode_rp_entity(val, &rp->rp_entity)); case 4: return (fido_blob_decode(val, &rp->rp_id_hash)); default: fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } } static void credman_reset_rp(fido_credman_rp_t *rp) { for (size_t i = 0; i < rp->n_alloc; i++) { free(rp->ptr[i].rp_entity.id); free(rp->ptr[i].rp_entity.name); rp->ptr[i].rp_entity.id = NULL; rp->ptr[i].rp_entity.name = NULL; free(rp->ptr[i].rp_id_hash.ptr); memset(&rp->ptr[i].rp_id_hash, 0, sizeof(rp->ptr[i].rp_id_hash)); } free(rp->ptr); rp->ptr = NULL; memset(rp, 0, sizeof(*rp)); } static int credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_credman_rp_t *rp = arg; uint64_t n; /* totalRPs */ if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 5) { fido_log_debug("%s: cbor_type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx, (size_t)n, sizeof(*rp->ptr)) < 0) { fido_log_debug("%s: credman_grow_array", __func__); return (-1); } return (0); } static int credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; credman_reset_rp(rp); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* adjust as needed */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, rp, credman_parse_rp_count)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp_count", __func__); return (r); } if (rp->n_alloc == 0) { fido_log_debug("%s: n_alloc=0", __func__); return (FIDO_OK); } /* parse the first rp */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[0], credman_parse_rp)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp", __func__); return (r); } rp->n_rx++; return (FIDO_OK); } static int credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; int r; if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* sanity check */ if (rp->n_rx >= rp->n_alloc) { fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx, rp->n_alloc); return (FIDO_ERR_INTERNAL); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[rp->n_rx], credman_parse_rp)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp", __func__); return (r); } return (FIDO_OK); } static int credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin, int ms) { int r; if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin)) != FIDO_OK || (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK) return (r); while (rp->n_rx < rp->n_alloc) { if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL)) != FIDO_OK || (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK) return (r); rp->n_rx++; } return (FIDO_OK); } int fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin) { if (fido_dev_is_fido2(dev) == false) return (FIDO_ERR_INVALID_COMMAND); if (pin == NULL) return (FIDO_ERR_INVALID_ARGUMENT); return (credman_get_rp_wait(dev, rp, pin, -1)); } fido_credman_rk_t * fido_credman_rk_new(void) { return (calloc(1, sizeof(fido_credman_rk_t))); } void fido_credman_rk_free(fido_credman_rk_t **rk_p) { fido_credman_rk_t *rk; if (rk_p == NULL || (rk = *rk_p) == NULL) return; credman_reset_rk(rk); free(rk); *rk_p = NULL; } size_t fido_credman_rk_count(const fido_credman_rk_t *rk) { return (rk->n_rx); } const fido_cred_t * fido_credman_rk(const fido_credman_rk_t *rk, size_t idx) { if (idx >= rk->n_alloc) return (NULL); return (&rk->ptr[idx]); } fido_credman_metadata_t * fido_credman_metadata_new(void) { return (calloc(1, sizeof(fido_credman_metadata_t))); } void fido_credman_metadata_free(fido_credman_metadata_t **metadata_p) { fido_credman_metadata_t *metadata; if (metadata_p == NULL || (metadata = *metadata_p) == NULL) return; free(metadata); *metadata_p = NULL; } uint64_t fido_credman_rk_existing(const fido_credman_metadata_t *metadata) { return (metadata->rk_existing); } uint64_t fido_credman_rk_remaining(const fido_credman_metadata_t *metadata) { return (metadata->rk_remaining); } fido_credman_rp_t * fido_credman_rp_new(void) { return (calloc(1, sizeof(fido_credman_rp_t))); } void fido_credman_rp_free(fido_credman_rp_t **rp_p) { fido_credman_rp_t *rp; if (rp_p == NULL || (rp = *rp_p) == NULL) return; credman_reset_rp(rp); free(rp); *rp_p = NULL; } size_t fido_credman_rp_count(const fido_credman_rp_t *rp) { return (rp->n_rx); } const char * fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (NULL); return (rp->ptr[idx].rp_entity.id); } const char * fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (NULL); return (rp->ptr[idx].rp_entity.name); } size_t fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (0); return (rp->ptr[idx].rp_id_hash.len); } const unsigned char * fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (NULL); return (rp->ptr[idx].rp_id_hash.ptr); } libfido2-1.3.1/src/dev.c000066400000000000000000000121221362326726700147330ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "fido.h" #if defined(_WIN32) #include #include #include #include #include #include static int obtain_nonce(uint64_t *nonce) { NTSTATUS status; status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce), BCRYPT_USE_SYSTEM_PREFERRED_RNG); if (!NT_SUCCESS(status)) return (-1); return (0); } #elif defined(HAS_DEV_URANDOM) static int obtain_nonce(uint64_t *nonce) { int fd = -1; int ok = -1; ssize_t r; if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0) goto fail; if ((r = read(fd, nonce, sizeof(*nonce))) < 0 || (size_t)r != sizeof(*nonce)) goto fail; ok = 0; fail: if (fd != -1) close(fd); return (ok); } #else #error "please provide an implementation of obtain_nonce() for your platform" #endif /* _WIN32 */ static int fido_dev_open_tx(fido_dev_t *dev, const char *path) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; if (dev->io_handle != NULL) { fido_log_debug("%s: handle=%p", __func__, dev->io_handle); return (FIDO_ERR_INVALID_ARGUMENT); } if (dev->io.open == NULL || dev->io.close == NULL) { fido_log_debug("%s: NULL open/close", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } if (obtain_nonce(&dev->nonce) < 0) { fido_log_debug("%s: obtain_nonce", __func__); return (FIDO_ERR_INTERNAL); } if ((dev->io_handle = dev->io.open(path)) == NULL) { fido_log_debug("%s: dev->io.open", __func__); return (FIDO_ERR_INTERNAL); } if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) { fido_log_debug("%s: fido_tx", __func__); dev->io.close(dev->io_handle); dev->io_handle = NULL; return (FIDO_ERR_TX); } return (FIDO_OK); } static int fido_dev_open_rx(fido_dev_t *dev, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; int n; if ((n = fido_rx(dev, cmd, &dev->attr, sizeof(dev->attr), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); goto fail; } #ifdef FIDO_FUZZ dev->attr.nonce = dev->nonce; #endif if ((size_t)n != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) { fido_log_debug("%s: invalid nonce", __func__); goto fail; } dev->cid = dev->attr.cid; return (FIDO_OK); fail: dev->io.close(dev->io_handle); dev->io_handle = NULL; return (FIDO_ERR_RX); } static int fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms) { int r; if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK || (r = fido_dev_open_rx(dev, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_open(fido_dev_t *dev, const char *path) { return (fido_dev_open_wait(dev, path, -1)); } int fido_dev_close(fido_dev_t *dev) { if (dev->io_handle == NULL || dev->io.close == NULL) return (FIDO_ERR_INVALID_ARGUMENT); dev->io.close(dev->io_handle); dev->io_handle = NULL; return (FIDO_OK); } int fido_dev_cancel(fido_dev_t *dev) { if (fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CANCEL, NULL, 0) < 0) return (FIDO_ERR_TX); return (FIDO_OK); } int fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) { if (dev->io_handle != NULL) { fido_log_debug("%s: NULL handle", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } if (io == NULL || io->open == NULL || io->close == NULL || io->read == NULL || io->write == NULL) { fido_log_debug("%s: NULL function", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } dev->io.open = io->open; dev->io.close = io->close; dev->io.read = io->read; dev->io.write = io->write; return (FIDO_OK); } void fido_init(int flags) { if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) fido_log_init(); } fido_dev_t * fido_dev_new(void) { fido_dev_t *dev; fido_dev_io_t io; if ((dev = calloc(1, sizeof(*dev))) == NULL) return (NULL); dev->cid = CTAP_CID_BROADCAST; io.open = fido_hid_open; io.close = fido_hid_close; io.read = fido_hid_read; io.write = fido_hid_write; if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) { fido_log_debug("%s: fido_dev_set_io_functions", __func__); fido_dev_free(&dev); return (NULL); } return (dev); } void fido_dev_free(fido_dev_t **dev_p) { fido_dev_t *dev; if (dev_p == NULL || (dev = *dev_p) == NULL) return; free(dev); *dev_p = NULL; } uint8_t fido_dev_protocol(const fido_dev_t *dev) { return (dev->attr.protocol); } uint8_t fido_dev_major(const fido_dev_t *dev) { return (dev->attr.major); } uint8_t fido_dev_minor(const fido_dev_t *dev) { return (dev->attr.minor); } uint8_t fido_dev_build(const fido_dev_t *dev) { return (dev->attr.build); } uint8_t fido_dev_flags(const fido_dev_t *dev) { return (dev->attr.flags); } bool fido_dev_is_fido2(const fido_dev_t *dev) { return (dev->attr.flags & FIDO_CAP_CBOR); } void fido_dev_force_u2f(fido_dev_t *dev) { dev->attr.flags &= ~FIDO_CAP_CBOR; } void fido_dev_force_fido2(fido_dev_t *dev) { dev->attr.flags |= FIDO_CAP_CBOR; } libfido2-1.3.1/src/diff_exports.sh000077500000000000000000000011271362326726700170470ustar00rootroot00000000000000#!/bin/bash -u # Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. [[ ! -f export.gnu || ! -f export.llvm || ! -f export.msvc ]] && exit 1 TMPDIR=$(mktemp -d) GNU=${TMPDIR}/gnu LLVM=${TMPDIR}/llvm MSVC=${TMPDIR}/msvc egrep -o $'([^*{}\t]+);$' export.gnu | tr -d ';' | sort > ${GNU} sed 's/^_//g' export.llvm | sort > ${LLVM} egrep -v "^EXPORTS$" export.msvc | sort > ${MSVC} diff -u ${GNU} ${LLVM} && diff -u ${MSVC} ${LLVM} ERROR=$? rm ${GNU} ${LLVM} ${MSVC} rmdir ${TMPDIR} exit ${ERROR} libfido2-1.3.1/src/ecdh.c000066400000000000000000000054361362326726700150720ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include "fido.h" #include "fido/es256.h" static int do_ecdh(const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh) { EVP_PKEY *pk_evp = NULL; EVP_PKEY *sk_evp = NULL; EVP_PKEY_CTX *ctx = NULL; fido_blob_t *secret = NULL; int ok = -1; *ecdh = NULL; /* allocate blobs for secret & ecdh */ if ((secret = fido_blob_new()) == NULL || (*ecdh = fido_blob_new()) == NULL) goto fail; /* wrap the keys as openssl objects */ if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL || (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) { fido_log_debug("%s: es256_to_EVP_PKEY", __func__); goto fail; } /* set ecdh parameters */ if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL || EVP_PKEY_derive_init(ctx) <= 0 || EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) { fido_log_debug("%s: EVP_PKEY_derive_init", __func__); goto fail; } /* perform ecdh */ if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 || (secret->ptr = calloc(1, secret->len)) == NULL || EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) { fido_log_debug("%s: EVP_PKEY_derive", __func__); goto fail; } /* use sha256 as a kdf on the resulting secret */ (*ecdh)->len = SHA256_DIGEST_LENGTH; if (((*ecdh)->ptr = calloc(1, (*ecdh)->len)) == NULL || SHA256(secret->ptr, secret->len, (*ecdh)->ptr) != (*ecdh)->ptr) { fido_log_debug("%s: sha256", __func__); goto fail; } ok = 0; fail: if (pk_evp != NULL) EVP_PKEY_free(pk_evp); if (sk_evp != NULL) EVP_PKEY_free(sk_evp); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (ok < 0) fido_blob_free(ecdh); fido_blob_free(&secret); return (ok); } int fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh) { es256_sk_t *sk = NULL; /* our private key */ es256_pk_t *ak = NULL; /* authenticator's public key */ int r; *pk = NULL; /* our public key; returned */ *ecdh = NULL; /* shared ecdh secret; returned */ if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) { fido_log_debug("%s: es256_derive_pk", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((ak = es256_pk_new()) == NULL || fido_dev_authkey(dev, ak) != FIDO_OK) { fido_log_debug("%s: fido_dev_authkey", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (do_ecdh(sk, ak, ecdh) < 0) { fido_log_debug("%s: do_ecdh", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: es256_sk_free(&sk); es256_pk_free(&ak); if (r != FIDO_OK) { es256_pk_free(pk); fido_blob_free(ecdh); } return (r); } libfido2-1.3.1/src/eddsa.c000066400000000000000000000062751362326726700152510ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "fido.h" #include "fido/eddsa.h" #if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L EVP_PKEY * EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key, size_t keylen) { (void)type; (void)e; (void)key; (void)keylen; return (NULL); } int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len) { (void)pkey; (void)pub; (void)len; return (0); } int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen) { (void)ctx; (void)sigret; (void)siglen; (void)tbs; (void)tbslen; return (0); } #endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_MD_CTX * EVP_MD_CTX_new(void) { return (NULL); } void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { (void)ctx; } #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ static int decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != xy_len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(xy, cbor_bytestring_handle(item), xy_len); return (0); } static int decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) { eddsa_pk_t *k = arg; if (cbor_isa_negint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) return (0); /* ignore */ switch (cbor_get_uint8(key)) { case 1: /* x coordinate */ return (decode_coord(val, &k->x, sizeof(k->x))); } return (0); /* ignore */ } int eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, k, decode_pubkey_point) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } eddsa_pk_t * eddsa_pk_new(void) { return (calloc(1, sizeof(eddsa_pk_t))); } void eddsa_pk_free(eddsa_pk_t **pkp) { eddsa_pk_t *pk; if (pkp == NULL || (pk = *pkp) == NULL) return; explicit_bzero(pk, sizeof(*pk)); free(pk); *pkp = NULL; } int eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len) { if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); memcpy(pk, ptr, sizeof(*pk)); return (FIDO_OK); } EVP_PKEY * eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k) { EVP_PKEY *pkey = NULL; if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x, sizeof(k->x))) == NULL) fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__); return (pkey); } int eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey) { size_t len = 0; if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 || len != sizeof(pk->x)) return (FIDO_ERR_INTERNAL); if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 || len != sizeof(pk->x)) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } libfido2-1.3.1/src/err.c000066400000000000000000000072661362326726700147620ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido/err.h" const char * fido_strerr(int n) { switch (n) { case FIDO_ERR_SUCCESS: return "FIDO_ERR_SUCCESS"; case FIDO_ERR_INVALID_COMMAND: return "FIDO_ERR_INVALID_COMMAND"; case FIDO_ERR_INVALID_PARAMETER: return "FIDO_ERR_INVALID_PARAMETER"; case FIDO_ERR_INVALID_LENGTH: return "FIDO_ERR_INVALID_LENGTH"; case FIDO_ERR_INVALID_SEQ: return "FIDO_ERR_INVALID_SEQ"; case FIDO_ERR_TIMEOUT: return "FIDO_ERR_TIMEOUT"; case FIDO_ERR_CHANNEL_BUSY: return "FIDO_ERR_CHANNEL_BUSY"; case FIDO_ERR_LOCK_REQUIRED: return "FIDO_ERR_LOCK_REQUIRED"; case FIDO_ERR_INVALID_CHANNEL: return "FIDO_ERR_INVALID_CHANNEL"; case FIDO_ERR_CBOR_UNEXPECTED_TYPE: return "FIDO_ERR_UNEXPECTED_TYPE"; case FIDO_ERR_INVALID_CBOR: return "FIDO_ERR_INVALID_CBOR"; case FIDO_ERR_MISSING_PARAMETER: return "FIDO_ERR_MISSING_PARAMETER"; case FIDO_ERR_LIMIT_EXCEEDED: return "FIDO_ERR_LIMIT_EXCEEDED"; case FIDO_ERR_UNSUPPORTED_EXTENSION: return "FIDO_ERR_UNSUPPORTED_EXTENSION"; case FIDO_ERR_CREDENTIAL_EXCLUDED: return "FIDO_ERR_CREDENTIAL_EXCLUDED"; case FIDO_ERR_PROCESSING: return "FIDO_ERR_PROCESSING"; case FIDO_ERR_INVALID_CREDENTIAL: return "FIDO_ERR_INVALID_CREDENTIAL"; case FIDO_ERR_USER_ACTION_PENDING: return "FIDO_ERR_ACTION_PENDING"; case FIDO_ERR_OPERATION_PENDING: return "FIDO_ERR_OPERATION_PENDING"; case FIDO_ERR_NO_OPERATIONS: return "FIDO_ERR_NO_OPERATIONS"; case FIDO_ERR_UNSUPPORTED_ALGORITHM: return "FIDO_ERR_UNSUPPORTED_ALGORITHM"; case FIDO_ERR_OPERATION_DENIED: return "FIDO_ERR_OPERATION_DENIED"; case FIDO_ERR_KEY_STORE_FULL: return "FIDO_ERR_STORE_FULL"; case FIDO_ERR_NOT_BUSY: return "FIDO_ERR_NOT_BUSY"; case FIDO_ERR_NO_OPERATION_PENDING: return "FIDO_ERR_OPERATION_PENDING"; case FIDO_ERR_UNSUPPORTED_OPTION: return "FIDO_ERR_UNSUPPORTED_OPTION"; case FIDO_ERR_INVALID_OPTION: return "FIDO_ERR_INVALID_OPTION"; case FIDO_ERR_KEEPALIVE_CANCEL: return "FIDO_ERR_KEEPALIVE_CANCEL"; case FIDO_ERR_NO_CREDENTIALS: return "FIDO_ERR_NO_CREDENTIALS"; case FIDO_ERR_USER_ACTION_TIMEOUT: return "FIDO_ERR_ACTION_TIMEOUT"; case FIDO_ERR_NOT_ALLOWED: return "FIDO_ERR_NOT_ALLOWED"; case FIDO_ERR_PIN_INVALID: return "FIDO_ERR_PIN_INVALID"; case FIDO_ERR_PIN_BLOCKED: return "FIDO_ERR_PIN_BLOCKED"; case FIDO_ERR_PIN_AUTH_INVALID: return "FIDO_ERR_AUTH_INVALID"; case FIDO_ERR_PIN_AUTH_BLOCKED: return "FIDO_ERR_AUTH_BLOCKED"; case FIDO_ERR_PIN_NOT_SET: return "FIDO_ERR_NOT_SET"; case FIDO_ERR_PIN_REQUIRED: return "FIDO_ERR_PIN_REQUIRED"; case FIDO_ERR_PIN_POLICY_VIOLATION: return "FIDO_ERR_POLICY_VIOLATION"; case FIDO_ERR_PIN_TOKEN_EXPIRED: return "FIDO_ERR_TOKEN_EXPIRED"; case FIDO_ERR_REQUEST_TOO_LARGE: return "FIDO_ERR_TOO_LARGE"; case FIDO_ERR_ACTION_TIMEOUT: return "FIDO_ERR_ACTION_TIMEOUT"; case FIDO_ERR_UP_REQUIRED: return "FIDO_ERR_UP_REQUIRED"; case FIDO_ERR_ERR_OTHER: return "FIDO_ERR_OTHER"; case FIDO_ERR_SPEC_LAST: return "FIDO_ERR_SPEC_LAST"; case FIDO_ERR_TX: return "FIDO_ERR_TX"; case FIDO_ERR_RX: return "FIDO_ERR_RX"; case FIDO_ERR_RX_NOT_CBOR: return "FIDO_ERR_RX_NOT_CBOR"; case FIDO_ERR_RX_INVALID_CBOR: return "FIDO_ERR_RX_INVALID_CBOR"; case FIDO_ERR_INVALID_PARAM: return "FIDO_ERR_INVALID_PARAM"; case FIDO_ERR_INVALID_SIG: return "FIDO_ERR_INVALID_SIG"; case FIDO_ERR_INVALID_ARGUMENT: return "FIDO_ERR_INVALID_ARGUMENT"; case FIDO_ERR_USER_PRESENCE_REQUIRED: return "FIDO_ERR_USER_PRESENCE_REQUIRED"; case FIDO_ERR_INTERNAL: return "FIDO_ERR_INTERNAL"; default: return "FIDO_ERR_UNKNOWN"; } } libfido2-1.3.1/src/es256.c000066400000000000000000000221731362326726700150300ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "fido.h" #include "fido/es256.h" static int decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != xy_len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(xy, cbor_bytestring_handle(item), xy_len); return (0); } static int decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) { es256_pk_t *k = arg; if (cbor_isa_negint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) return (0); /* ignore */ switch (cbor_get_uint8(key)) { case 1: /* x coordinate */ return (decode_coord(val, &k->x, sizeof(k->x))); case 2: /* y coordinate */ return (decode_coord(val, &k->y, sizeof(k->y))); } return (0); /* ignore */ } int es256_pk_decode(const cbor_item_t *item, es256_pk_t *k) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, k, decode_pubkey_point) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } cbor_item_t * es256_pk_encode(const es256_pk_t *pk, int ecdh) { cbor_item_t *item = NULL; struct cbor_pair argv[5]; int alg; int ok = -1; memset(argv, 0, sizeof(argv)); if ((item = cbor_new_definite_map(5)) == NULL) goto fail; /* kty */ if ((argv[0].key = cbor_build_uint8(1)) == NULL || (argv[0].value = cbor_build_uint8(2)) == NULL || !cbor_map_add(item, argv[0])) goto fail; /* * "The COSEAlgorithmIdentifier used is -25 (ECDH-ES + * HKDF-256) although this is NOT the algorithm actually * used. Setting this to a different value may result in * compatibility issues." */ if (ecdh) alg = COSE_ECDH_ES256; else alg = COSE_ES256; /* alg */ if ((argv[1].key = cbor_build_uint8(3)) == NULL || (argv[1].value = cbor_build_negint8(-alg - 1)) == NULL || !cbor_map_add(item, argv[1])) goto fail; /* crv */ if ((argv[2].key = cbor_build_negint8(0)) == NULL || (argv[2].value = cbor_build_uint8(1)) == NULL || !cbor_map_add(item, argv[2])) goto fail; /* x */ if ((argv[3].key = cbor_build_negint8(1)) == NULL || (argv[3].value = cbor_build_bytestring(pk->x, sizeof(pk->x))) == NULL || !cbor_map_add(item, argv[3])) goto fail; /* y */ if ((argv[4].key = cbor_build_negint8(2)) == NULL || (argv[4].value = cbor_build_bytestring(pk->y, sizeof(pk->y))) == NULL || !cbor_map_add(item, argv[4])) goto fail; ok = 0; fail: if (ok < 0) { if (item != NULL) { cbor_decref(&item); item = NULL; } } for (size_t i = 0; i < 5; i++) { if (argv[i].key) cbor_decref(&argv[i].key); if (argv[i].value) cbor_decref(&argv[i].value); } return (item); } es256_sk_t * es256_sk_new(void) { return (calloc(1, sizeof(es256_sk_t))); } void es256_sk_free(es256_sk_t **skp) { es256_sk_t *sk; if (skp == NULL || (sk = *skp) == NULL) return; explicit_bzero(sk, sizeof(*sk)); free(sk); *skp = NULL; } es256_pk_t * es256_pk_new(void) { return (calloc(1, sizeof(es256_pk_t))); } void es256_pk_free(es256_pk_t **pkp) { es256_pk_t *pk; if (pkp == NULL || (pk = *pkp) == NULL) return; explicit_bzero(pk, sizeof(*pk)); free(pk); *pkp = NULL; } int es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len) { if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); memcpy(pk, ptr, sizeof(*pk)); return (FIDO_OK); } int es256_pk_set_x(es256_pk_t *pk, const unsigned char *x) { memcpy(pk->x, x, sizeof(pk->x)); return (0); } int es256_pk_set_y(es256_pk_t *pk, const unsigned char *y) { memcpy(pk->y, y, sizeof(pk->y)); return (0); } int es256_sk_create(es256_sk_t *key) { EVP_PKEY_CTX *pctx = NULL; EVP_PKEY_CTX *kctx = NULL; EVP_PKEY *p = NULL; EVP_PKEY *k = NULL; const EC_KEY *ec; const BIGNUM *d; const int nid = NID_X9_62_prime256v1; int n; int ok = -1; if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || EVP_PKEY_paramgen_init(pctx) <= 0 || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0 || EVP_PKEY_paramgen(pctx, &p) <= 0) { fido_log_debug("%s: EVP_PKEY_paramgen", __func__); goto fail; } if ((kctx = EVP_PKEY_CTX_new(p, NULL)) == NULL || EVP_PKEY_keygen_init(kctx) <= 0 || EVP_PKEY_keygen(kctx, &k) <= 0) { fido_log_debug("%s: EVP_PKEY_keygen", __func__); goto fail; } if ((ec = EVP_PKEY_get0_EC_KEY(k)) == NULL || (d = EC_KEY_get0_private_key(ec)) == NULL || (n = BN_num_bytes(d)) < 0 || (size_t)n > sizeof(key->d) || (n = BN_bn2bin(d, key->d)) < 0 || (size_t)n > sizeof(key->d)) { fido_log_debug("%s: EC_KEY_get0_private_key", __func__); goto fail; } ok = 0; fail: if (p != NULL) EVP_PKEY_free(p); if (k != NULL) EVP_PKEY_free(k); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (kctx != NULL) EVP_PKEY_CTX_free(kctx); return (ok); } EVP_PKEY * es256_pk_to_EVP_PKEY(const es256_pk_t *k) { BN_CTX *bnctx = NULL; EC_KEY *ec = NULL; EC_POINT *q = NULL; EVP_PKEY *pkey = NULL; BIGNUM *x = NULL; BIGNUM *y = NULL; const EC_GROUP *g = NULL; const int nid = NID_X9_62_prime256v1; int ok = -1; if ((bnctx = BN_CTX_new()) == NULL || (x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL) goto fail; if (BN_bin2bn(k->x, sizeof(k->x), x) == NULL || BN_bin2bn(k->y, sizeof(k->y), y) == NULL) { fido_log_debug("%s: BN_bin2bn", __func__); goto fail; } if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL || (g = EC_KEY_get0_group(ec)) == NULL) { fido_log_debug("%s: EC_KEY init", __func__); goto fail; } if ((q = EC_POINT_new(g)) == NULL || EC_POINT_set_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || EC_KEY_set_public_key(ec, q) == 0) { fido_log_debug("%s: EC_KEY_set_public_key", __func__); goto fail; } if ((pkey = EVP_PKEY_new()) == NULL || EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); goto fail; } ec = NULL; /* at this point, ec belongs to evp */ ok = 0; fail: if (bnctx != NULL) BN_CTX_free(bnctx); if (ec != NULL) EC_KEY_free(ec); if (q != NULL) EC_POINT_free(q); if (ok < 0 && pkey != NULL) { EVP_PKEY_free(pkey); pkey = NULL; } return (pkey); } int es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) { BN_CTX *ctx = NULL; BIGNUM *x = NULL; BIGNUM *y = NULL; const EC_POINT *q = NULL; const EC_GROUP *g = NULL; int ok = FIDO_ERR_INTERNAL; int n; if ((q = EC_KEY_get0_public_key(ec)) == NULL || (g = EC_KEY_get0_group(ec)) == NULL) goto fail; if ((ctx = BN_CTX_new()) == NULL || (x = BN_CTX_get(ctx)) == NULL || (y = BN_CTX_get(ctx)) == NULL) goto fail; if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, ctx) == 0 || (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) || (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) { fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", __func__); goto fail; } if ((n = BN_bn2bin(x, pk->x)) < 0 || (size_t)n > sizeof(pk->x) || (n = BN_bn2bin(y, pk->y)) < 0 || (size_t)n > sizeof(pk->y)) { fido_log_debug("%s: BN_bn2bin", __func__); goto fail; } ok = FIDO_OK; fail: if (ctx != NULL) BN_CTX_free(ctx); return (ok); } EVP_PKEY * es256_sk_to_EVP_PKEY(const es256_sk_t *k) { BN_CTX *bnctx = NULL; EC_KEY *ec = NULL; EVP_PKEY *pkey = NULL; BIGNUM *d = NULL; const int nid = NID_X9_62_prime256v1; int ok = -1; if ((bnctx = BN_CTX_new()) == NULL || (d = BN_CTX_get(bnctx)) == NULL || BN_bin2bn(k->d, sizeof(k->d), d) == NULL) { fido_log_debug("%s: BN_bin2bn", __func__); goto fail; } if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL || EC_KEY_set_private_key(ec, d) == 0) { fido_log_debug("%s: EC_KEY_set_private_key", __func__); goto fail; } if ((pkey = EVP_PKEY_new()) == NULL || EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); goto fail; } ec = NULL; /* at this point, ec belongs to evp */ ok = 0; fail: if (bnctx != NULL) BN_CTX_free(bnctx); if (ec != NULL) EC_KEY_free(ec); if (ok < 0 && pkey != NULL) { EVP_PKEY_free(pkey); pkey = NULL; } return (pkey); } int es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk) { BIGNUM *d = NULL; EC_KEY *ec = NULL; EC_POINT *q = NULL; const EC_GROUP *g = NULL; const int nid = NID_X9_62_prime256v1; int ok = -1; if ((d = BN_bin2bn(sk->d, (int)sizeof(sk->d), NULL)) == NULL || (ec = EC_KEY_new_by_curve_name(nid)) == NULL || (g = EC_KEY_get0_group(ec)) == NULL || (q = EC_POINT_new(g)) == NULL) { fido_log_debug("%s: get", __func__); goto fail; } if (EC_POINT_mul(g, q, d, NULL, NULL, NULL) == 0 || EC_KEY_set_public_key(ec, q) == 0 || es256_pk_from_EC_KEY(pk, ec) != FIDO_OK) { fido_log_debug("%s: set", __func__); goto fail; } ok = 0; fail: if (d != NULL) BN_clear_free(d); if (q != NULL) EC_POINT_free(q); if (ec != NULL) EC_KEY_free(ec); return (ok); } libfido2-1.3.1/src/export.gnu000066400000000000000000000105261362326726700160530ustar00rootroot00000000000000{ global: eddsa_pk_free; eddsa_pk_from_EVP_PKEY; eddsa_pk_from_ptr; eddsa_pk_new; eddsa_pk_to_EVP_PKEY; es256_pk_free; es256_pk_from_EC_KEY; es256_pk_from_ptr; es256_pk_new; es256_pk_to_EVP_PKEY; fido_assert_allow_cred; fido_assert_authdata_len; fido_assert_authdata_ptr; fido_assert_clientdata_hash_len; fido_assert_clientdata_hash_ptr; fido_assert_count; fido_assert_flags; fido_assert_free; fido_assert_hmac_secret_len; fido_assert_hmac_secret_ptr; fido_assert_id_len; fido_assert_id_ptr; fido_assert_new; fido_assert_rp_id; fido_assert_set_authdata; fido_assert_set_authdata_raw; fido_assert_set_clientdata_hash; fido_assert_set_count; fido_assert_set_extensions; fido_assert_set_hmac_salt; fido_assert_set_options; fido_assert_set_rp; fido_assert_set_sig; fido_assert_set_up; fido_assert_set_uv; fido_assert_sigcount; fido_assert_sig_len; fido_assert_sig_ptr; fido_assert_user_display_name; fido_assert_user_icon; fido_assert_user_id_len; fido_assert_user_id_ptr; fido_assert_user_name; fido_assert_verify; fido_bio_dev_enroll_begin; fido_bio_dev_enroll_cancel; fido_bio_dev_enroll_continue; fido_bio_dev_enroll_remove; fido_bio_dev_get_info; fido_bio_dev_get_template_array; fido_bio_dev_set_template_name; fido_bio_enroll_free; fido_bio_enroll_last_status; fido_bio_enroll_new; fido_bio_enroll_remaining_samples; fido_bio_info_free; fido_bio_info_max_samples; fido_bio_info_new; fido_bio_info_type; fido_bio_template; fido_bio_template_array_count; fido_bio_template_array_free; fido_bio_template_array_new; fido_bio_template_free; fido_bio_template_id_len; fido_bio_template_id_ptr; fido_bio_template_name; fido_bio_template_new; fido_bio_template_set_id; fido_bio_template_set_name; fido_cbor_info_aaguid_len; fido_cbor_info_aaguid_ptr; fido_cbor_info_extensions_len; fido_cbor_info_extensions_ptr; fido_cbor_info_free; fido_cbor_info_maxmsgsiz; fido_cbor_info_new; fido_cbor_info_options_len; fido_cbor_info_options_name_ptr; fido_cbor_info_options_value_ptr; fido_cbor_info_protocols_len; fido_cbor_info_protocols_ptr; fido_cbor_info_versions_len; fido_cbor_info_versions_ptr; fido_cred_authdata_len; fido_cred_authdata_ptr; fido_cred_clientdata_hash_len; fido_cred_clientdata_hash_ptr; fido_cred_display_name; fido_cred_exclude; fido_cred_flags; fido_cred_fmt; fido_cred_free; fido_cred_id_len; fido_cred_id_ptr; fido_credman_del_dev_rk; fido_credman_get_dev_metadata; fido_credman_get_dev_rk; fido_credman_get_dev_rp; fido_credman_metadata_free; fido_credman_metadata_new; fido_credman_rk; fido_credman_rk_count; fido_credman_rk_existing; fido_credman_rk_free; fido_credman_rk_new; fido_credman_rk_remaining; fido_credman_rp_count; fido_credman_rp_free; fido_credman_rp_id; fido_credman_rp_id_hash_len; fido_credman_rp_id_hash_ptr; fido_credman_rp_name; fido_credman_rp_new; fido_cred_new; fido_cred_pubkey_len; fido_cred_pubkey_ptr; fido_cred_rp_id; fido_cred_rp_name; fido_cred_set_authdata; fido_cred_set_authdata_raw; fido_cred_set_clientdata_hash; fido_cred_set_extensions; fido_cred_set_fmt; fido_cred_set_options; fido_cred_set_rk; fido_cred_set_rp; fido_cred_set_sig; fido_cred_set_type; fido_cred_set_user; fido_cred_set_uv; fido_cred_set_x509; fido_cred_sig_len; fido_cred_sig_ptr; fido_cred_type; fido_cred_user_id_len; fido_cred_user_id_ptr; fido_cred_user_name; fido_cred_verify; fido_cred_verify_self; fido_cred_x5c_len; fido_cred_x5c_ptr; fido_dev_build; fido_dev_cancel; fido_dev_close; fido_dev_flags; fido_dev_force_fido2; fido_dev_force_u2f; fido_dev_free; fido_dev_get_assert; fido_dev_get_cbor_info; fido_dev_get_retry_count; fido_dev_info_free; fido_dev_info_manifest; fido_dev_info_manufacturer_string; fido_dev_info_new; fido_dev_info_path; fido_dev_info_product; fido_dev_info_product_string; fido_dev_info_ptr; fido_dev_info_vendor; fido_dev_is_fido2; fido_dev_major; fido_dev_make_cred; fido_dev_minor; fido_dev_new; fido_dev_open; fido_dev_protocol; fido_dev_reset; fido_dev_set_io_functions; fido_dev_set_pin; fido_init; fido_strerr; rs256_pk_free; rs256_pk_from_ptr; rs256_pk_from_RSA; rs256_pk_new; rs256_pk_to_EVP_PKEY; local: *; }; libfido2-1.3.1/src/export.llvm000066400000000000000000000077271362326726700162450ustar00rootroot00000000000000_eddsa_pk_free _eddsa_pk_from_EVP_PKEY _eddsa_pk_from_ptr _eddsa_pk_new _eddsa_pk_to_EVP_PKEY _es256_pk_free _es256_pk_from_EC_KEY _es256_pk_from_ptr _es256_pk_new _es256_pk_to_EVP_PKEY _fido_assert_allow_cred _fido_assert_authdata_len _fido_assert_authdata_ptr _fido_assert_clientdata_hash_len _fido_assert_clientdata_hash_ptr _fido_assert_count _fido_assert_flags _fido_assert_free _fido_assert_hmac_secret_len _fido_assert_hmac_secret_ptr _fido_assert_id_len _fido_assert_id_ptr _fido_assert_new _fido_assert_rp_id _fido_assert_set_authdata _fido_assert_set_authdata_raw _fido_assert_set_clientdata_hash _fido_assert_set_count _fido_assert_set_extensions _fido_assert_set_hmac_salt _fido_assert_set_options _fido_assert_set_rp _fido_assert_set_sig _fido_assert_set_up _fido_assert_set_uv _fido_assert_sigcount _fido_assert_sig_len _fido_assert_sig_ptr _fido_assert_user_display_name _fido_assert_user_icon _fido_assert_user_id_len _fido_assert_user_id_ptr _fido_assert_user_name _fido_assert_verify _fido_bio_dev_enroll_begin _fido_bio_dev_enroll_cancel _fido_bio_dev_enroll_continue _fido_bio_dev_enroll_remove _fido_bio_dev_get_info _fido_bio_dev_get_template_array _fido_bio_dev_set_template_name _fido_bio_enroll_free _fido_bio_enroll_last_status _fido_bio_enroll_new _fido_bio_enroll_remaining_samples _fido_bio_info_free _fido_bio_info_max_samples _fido_bio_info_new _fido_bio_info_type _fido_bio_template _fido_bio_template_array_count _fido_bio_template_array_free _fido_bio_template_array_new _fido_bio_template_free _fido_bio_template_id_len _fido_bio_template_id_ptr _fido_bio_template_name _fido_bio_template_new _fido_bio_template_set_id _fido_bio_template_set_name _fido_cbor_info_aaguid_len _fido_cbor_info_aaguid_ptr _fido_cbor_info_extensions_len _fido_cbor_info_extensions_ptr _fido_cbor_info_free _fido_cbor_info_maxmsgsiz _fido_cbor_info_new _fido_cbor_info_options_len _fido_cbor_info_options_name_ptr _fido_cbor_info_options_value_ptr _fido_cbor_info_protocols_len _fido_cbor_info_protocols_ptr _fido_cbor_info_versions_len _fido_cbor_info_versions_ptr _fido_cred_authdata_len _fido_cred_authdata_ptr _fido_cred_clientdata_hash_len _fido_cred_clientdata_hash_ptr _fido_cred_display_name _fido_cred_exclude _fido_cred_flags _fido_cred_fmt _fido_cred_free _fido_cred_id_len _fido_cred_id_ptr _fido_credman_del_dev_rk _fido_credman_get_dev_metadata _fido_credman_get_dev_rk _fido_credman_get_dev_rp _fido_credman_metadata_free _fido_credman_metadata_new _fido_credman_rk _fido_credman_rk_count _fido_credman_rk_existing _fido_credman_rk_free _fido_credman_rk_new _fido_credman_rk_remaining _fido_credman_rp_count _fido_credman_rp_free _fido_credman_rp_id _fido_credman_rp_id_hash_len _fido_credman_rp_id_hash_ptr _fido_credman_rp_name _fido_credman_rp_new _fido_cred_new _fido_cred_pubkey_len _fido_cred_pubkey_ptr _fido_cred_rp_id _fido_cred_rp_name _fido_cred_set_authdata _fido_cred_set_authdata_raw _fido_cred_set_clientdata_hash _fido_cred_set_extensions _fido_cred_set_fmt _fido_cred_set_options _fido_cred_set_rk _fido_cred_set_rp _fido_cred_set_sig _fido_cred_set_type _fido_cred_set_user _fido_cred_set_uv _fido_cred_set_x509 _fido_cred_sig_len _fido_cred_sig_ptr _fido_cred_type _fido_cred_user_id_len _fido_cred_user_id_ptr _fido_cred_user_name _fido_cred_verify _fido_cred_verify_self _fido_cred_x5c_len _fido_cred_x5c_ptr _fido_dev_build _fido_dev_cancel _fido_dev_close _fido_dev_flags _fido_dev_force_fido2 _fido_dev_force_u2f _fido_dev_free _fido_dev_get_assert _fido_dev_get_cbor_info _fido_dev_get_retry_count _fido_dev_info_free _fido_dev_info_manifest _fido_dev_info_manufacturer_string _fido_dev_info_new _fido_dev_info_path _fido_dev_info_product _fido_dev_info_product_string _fido_dev_info_ptr _fido_dev_info_vendor _fido_dev_is_fido2 _fido_dev_major _fido_dev_make_cred _fido_dev_minor _fido_dev_new _fido_dev_open _fido_dev_protocol _fido_dev_reset _fido_dev_set_io_functions _fido_dev_set_pin _fido_init _fido_strerr _rs256_pk_free _rs256_pk_from_ptr _rs256_pk_from_RSA _rs256_pk_new _rs256_pk_to_EVP_PKEY libfido2-1.3.1/src/export.msvc000066400000000000000000000074551362326726700162410ustar00rootroot00000000000000EXPORTS eddsa_pk_free eddsa_pk_from_EVP_PKEY eddsa_pk_from_ptr eddsa_pk_new eddsa_pk_to_EVP_PKEY es256_pk_free es256_pk_from_EC_KEY es256_pk_from_ptr es256_pk_new es256_pk_to_EVP_PKEY fido_assert_allow_cred fido_assert_authdata_len fido_assert_authdata_ptr fido_assert_clientdata_hash_len fido_assert_clientdata_hash_ptr fido_assert_count fido_assert_flags fido_assert_free fido_assert_hmac_secret_len fido_assert_hmac_secret_ptr fido_assert_id_len fido_assert_id_ptr fido_assert_new fido_assert_rp_id fido_assert_set_authdata fido_assert_set_authdata_raw fido_assert_set_clientdata_hash fido_assert_set_count fido_assert_set_extensions fido_assert_set_hmac_salt fido_assert_set_options fido_assert_set_rp fido_assert_set_sig fido_assert_set_up fido_assert_set_uv fido_assert_sigcount fido_assert_sig_len fido_assert_sig_ptr fido_assert_user_display_name fido_assert_user_icon fido_assert_user_id_len fido_assert_user_id_ptr fido_assert_user_name fido_assert_verify fido_bio_dev_enroll_begin fido_bio_dev_enroll_cancel fido_bio_dev_enroll_continue fido_bio_dev_enroll_remove fido_bio_dev_get_info fido_bio_dev_get_template_array fido_bio_dev_set_template_name fido_bio_enroll_free fido_bio_enroll_last_status fido_bio_enroll_new fido_bio_enroll_remaining_samples fido_bio_info_free fido_bio_info_max_samples fido_bio_info_new fido_bio_info_type fido_bio_template fido_bio_template_array_count fido_bio_template_array_free fido_bio_template_array_new fido_bio_template_free fido_bio_template_id_len fido_bio_template_id_ptr fido_bio_template_name fido_bio_template_new fido_bio_template_set_id fido_bio_template_set_name fido_cbor_info_aaguid_len fido_cbor_info_aaguid_ptr fido_cbor_info_extensions_len fido_cbor_info_extensions_ptr fido_cbor_info_free fido_cbor_info_maxmsgsiz fido_cbor_info_new fido_cbor_info_options_len fido_cbor_info_options_name_ptr fido_cbor_info_options_value_ptr fido_cbor_info_protocols_len fido_cbor_info_protocols_ptr fido_cbor_info_versions_len fido_cbor_info_versions_ptr fido_cred_authdata_len fido_cred_authdata_ptr fido_cred_clientdata_hash_len fido_cred_clientdata_hash_ptr fido_cred_display_name fido_cred_exclude fido_cred_flags fido_cred_fmt fido_cred_free fido_cred_id_len fido_cred_id_ptr fido_credman_del_dev_rk fido_credman_get_dev_metadata fido_credman_get_dev_rk fido_credman_get_dev_rp fido_credman_metadata_free fido_credman_metadata_new fido_credman_rk fido_credman_rk_count fido_credman_rk_existing fido_credman_rk_free fido_credman_rk_new fido_credman_rk_remaining fido_credman_rp_count fido_credman_rp_free fido_credman_rp_id fido_credman_rp_id_hash_len fido_credman_rp_id_hash_ptr fido_credman_rp_name fido_credman_rp_new fido_cred_new fido_cred_pubkey_len fido_cred_pubkey_ptr fido_cred_rp_id fido_cred_rp_name fido_cred_set_authdata fido_cred_set_authdata_raw fido_cred_set_clientdata_hash fido_cred_set_extensions fido_cred_set_fmt fido_cred_set_options fido_cred_set_rk fido_cred_set_rp fido_cred_set_sig fido_cred_set_type fido_cred_set_user fido_cred_set_uv fido_cred_set_x509 fido_cred_sig_len fido_cred_sig_ptr fido_cred_type fido_cred_user_id_len fido_cred_user_id_ptr fido_cred_user_name fido_cred_verify fido_cred_verify_self fido_cred_x5c_len fido_cred_x5c_ptr fido_dev_build fido_dev_cancel fido_dev_close fido_dev_flags fido_dev_force_fido2 fido_dev_force_u2f fido_dev_free fido_dev_get_assert fido_dev_get_cbor_info fido_dev_get_retry_count fido_dev_info_free fido_dev_info_manifest fido_dev_info_manufacturer_string fido_dev_info_new fido_dev_info_path fido_dev_info_product fido_dev_info_product_string fido_dev_info_ptr fido_dev_info_vendor fido_dev_is_fido2 fido_dev_major fido_dev_make_cred fido_dev_minor fido_dev_new fido_dev_open fido_dev_protocol fido_dev_reset fido_dev_set_io_functions fido_dev_set_pin fido_init fido_strerr rs256_pk_free rs256_pk_from_ptr rs256_pk_from_RSA rs256_pk_new rs256_pk_to_EVP_PKEY libfido2-1.3.1/src/extern.h000066400000000000000000000125531362326726700154770ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _EXTERN_H #define _EXTERN_H /* aes256 */ int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); /* cbor encoding functions */ cbor_item_t *cbor_flatten_vector(cbor_item_t **, size_t); cbor_item_t *cbor_encode_assert_options(fido_opt_t, fido_opt_t); cbor_item_t *cbor_encode_change_pin_auth(const fido_blob_t *, const fido_blob_t *, const fido_blob_t *); cbor_item_t *cbor_encode_extensions(int); cbor_item_t *cbor_encode_hmac_secret_param(const fido_blob_t *, const es256_pk_t *, const fido_blob_t *); cbor_item_t *cbor_encode_options(fido_opt_t, fido_opt_t); cbor_item_t *cbor_encode_pin_auth(const fido_blob_t *, const fido_blob_t *); cbor_item_t *cbor_encode_pin_enc(const fido_blob_t *, const fido_blob_t *); cbor_item_t *cbor_encode_pin_hash_enc(const fido_blob_t *, const fido_blob_t *); cbor_item_t *cbor_encode_pin_opt(void); cbor_item_t *cbor_encode_pubkey(const fido_blob_t *); cbor_item_t *cbor_encode_pubkey_list(const fido_blob_array_t *); cbor_item_t *cbor_encode_pubkey_param(int); cbor_item_t *cbor_encode_rp_entity(const fido_rp_t *); cbor_item_t *cbor_encode_set_pin_auth(const fido_blob_t *, const fido_blob_t *); cbor_item_t *cbor_encode_user_entity(const fido_user_t *); cbor_item_t *es256_pk_encode(const es256_pk_t *, int); /* cbor decoding functions */ int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *); int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *, fido_authdata_t *, fido_attcred_t *, int *); int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *, fido_authdata_t *, int *, fido_blob_t *); int cbor_decode_cred_id(const cbor_item_t *, fido_blob_t *); int cbor_decode_fmt(const cbor_item_t *, char **); int cbor_decode_pubkey(const cbor_item_t *, int *, void *); int cbor_decode_rp_entity(const cbor_item_t *, fido_rp_t *); int cbor_decode_uint64(const cbor_item_t *, uint64_t *); int cbor_decode_user(const cbor_item_t *, fido_user_t *); int es256_pk_decode(const cbor_item_t *, es256_pk_t *); int rs256_pk_decode(const cbor_item_t *, rs256_pk_t *); int eddsa_pk_decode(const cbor_item_t *, eddsa_pk_t *); /* auxiliary cbor routines */ int cbor_add_bool(cbor_item_t *, const char *, fido_opt_t); int cbor_add_bytestring(cbor_item_t *, const char *, const unsigned char *, size_t); int cbor_add_string(cbor_item_t *, const char *, const char *); int cbor_array_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *, void *)); int cbor_build_frame(uint8_t, cbor_item_t *[], size_t, fido_blob_t *); int cbor_bytestring_copy(const cbor_item_t *, unsigned char **, size_t *); int cbor_map_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *, const cbor_item_t *, void *)); int cbor_string_copy(const cbor_item_t *, char **); int cbor_parse_reply(const unsigned char *, size_t, void *, int(*)(const cbor_item_t *, const cbor_item_t *, void *)); int cbor_add_pin_params(fido_dev_t *, const fido_blob_t *, const es256_pk_t *, const fido_blob_t *,const char *, cbor_item_t **, cbor_item_t **); void cbor_vector_free(cbor_item_t **, size_t); #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif /* buf */ int fido_buf_read(const unsigned char **, size_t *, void *, size_t); int fido_buf_write(unsigned char **, size_t *, const void *, size_t); /* hid i/o */ void *fido_hid_open(const char *); void fido_hid_close(void *); int fido_hid_read(void *, unsigned char *, size_t, int); int fido_hid_write(void *, const unsigned char *, size_t); /* generic i/o */ int fido_rx_cbor_status(fido_dev_t *, int); int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int); int fido_tx(fido_dev_t *, uint8_t, const void *, size_t); /* log */ #ifdef FIDO_NO_DIAGNOSTIC #define fido_log_init(...) do { /* nothing */ } while (0) #define fido_log_debug(...) do { /* nothing */ } while (0) #define fido_log_xxd(...) do { /* nothing */ } while (0) #else #ifdef __GNUC__ void fido_log_init(void); void fido_log_debug(const char *, ...) __attribute__((__format__ (printf, 1, 2))); void fido_log_xxd(const void *, size_t); #else void fido_log_init(void); void fido_log_debug(const char *, ...); void fido_log_xxd(const void *, size_t); #endif /* __GNUC__ */ #endif /* FIDO_NO_DIAGNOSTIC */ /* u2f */ int u2f_register(fido_dev_t *, fido_cred_t *, int); int u2f_authenticate(fido_dev_t *, fido_assert_t *, int); /* unexposed fido ops */ int fido_dev_authkey(fido_dev_t *, es256_pk_t *); int fido_dev_get_pin_token(fido_dev_t *, const char *, const fido_blob_t *, const es256_pk_t *, fido_blob_t *); int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **); /* misc */ void fido_assert_reset_rx(fido_assert_t *); void fido_assert_reset_tx(fido_assert_t *); void fido_cred_reset_rx(fido_cred_t *); void fido_cred_reset_tx(fido_cred_t *); int fido_check_rp_id(const char *, const unsigned char *); int fido_check_flags(uint8_t, fido_opt_t, fido_opt_t); /* crypto */ int fido_verify_sig_es256(const fido_blob_t *, const es256_pk_t *, const fido_blob_t *); int fido_verify_sig_rs256(const fido_blob_t *, const rs256_pk_t *, const fido_blob_t *); int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *, const fido_blob_t *); #endif /* !_EXTERN_H */ libfido2-1.3.1/src/fido.h000066400000000000000000000205451362326726700151130ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_H #define _FIDO_H #include #include #include #include #include typedef void *fido_dev_io_open_t(const char *); typedef void fido_dev_io_close_t(void *); typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); typedef struct fido_dev_io { fido_dev_io_open_t *open; fido_dev_io_close_t *close; fido_dev_io_read_t *read; fido_dev_io_write_t *write; } fido_dev_io_t; typedef enum { FIDO_OPT_OMIT = 0, /* use authenticator's default */ FIDO_OPT_FALSE, /* explicitly set option to false */ FIDO_OPT_TRUE, /* explicitly set option to true */ } fido_opt_t; #ifdef _FIDO_INTERNAL #include #include #include "blob.h" #include "../openbsd-compat/openbsd-compat.h" #include "iso7816.h" #include "types.h" #include "extern.h" #endif #include "fido/err.h" #include "fido/param.h" #ifndef _FIDO_INTERNAL typedef struct fido_assert fido_assert_t; typedef struct fido_cbor_info fido_cbor_info_t; typedef struct fido_cred fido_cred_t; typedef struct fido_dev fido_dev_t; typedef struct fido_dev_info fido_dev_info_t; typedef struct es256_pk es256_pk_t; typedef struct es256_sk es256_sk_t; typedef struct rs256_pk rs256_pk_t; typedef struct eddsa_pk eddsa_pk_t; #endif fido_assert_t *fido_assert_new(void); fido_cred_t *fido_cred_new(void); fido_dev_t *fido_dev_new(void); fido_dev_info_t *fido_dev_info_new(size_t); fido_cbor_info_t *fido_cbor_info_new(void); void fido_assert_free(fido_assert_t **); void fido_cbor_info_free(fido_cbor_info_t **); void fido_cred_free(fido_cred_t **); void fido_dev_force_fido2(fido_dev_t *); void fido_dev_force_u2f(fido_dev_t *); void fido_dev_free(fido_dev_t **); void fido_dev_info_free(fido_dev_info_t **, size_t); /* fido_init() flags. */ #define FIDO_DEBUG 0x01 void fido_init(int); const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *); const unsigned char *fido_assert_hmac_secret_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_id_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_sig_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_user_id_ptr(const fido_assert_t *, size_t); char **fido_cbor_info_extensions_ptr(const fido_cbor_info_t *); char **fido_cbor_info_options_name_ptr(const fido_cbor_info_t *); char **fido_cbor_info_versions_ptr(const fido_cbor_info_t *); const bool *fido_cbor_info_options_value_ptr(const fido_cbor_info_t *); const char *fido_assert_rp_id(const fido_assert_t *); const char *fido_assert_user_display_name(const fido_assert_t *, size_t); const char *fido_assert_user_icon(const fido_assert_t *, size_t); const char *fido_assert_user_name(const fido_assert_t *, size_t); const char *fido_cred_display_name(const fido_cred_t *); const char *fido_cred_fmt(const fido_cred_t *); const char *fido_cred_rp_id(const fido_cred_t *); const char *fido_cred_rp_name(const fido_cred_t *); const char *fido_cred_user_name(const fido_cred_t *); const char *fido_dev_info_manufacturer_string(const fido_dev_info_t *); const char *fido_dev_info_path(const fido_dev_info_t *); const char *fido_dev_info_product_string(const fido_dev_info_t *); const fido_dev_info_t *fido_dev_info_ptr(const fido_dev_info_t *, size_t); const uint8_t *fido_cbor_info_protocols_ptr(const fido_cbor_info_t *); const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *); const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *); const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *); const unsigned char *fido_cred_id_ptr(const fido_cred_t *); const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *); const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *); const unsigned char *fido_cred_sig_ptr(const fido_cred_t *); const unsigned char *fido_cred_x5c_ptr(const fido_cred_t *); int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t); int fido_assert_set_authdata(fido_assert_t *, size_t, const unsigned char *, size_t); int fido_assert_set_authdata_raw(fido_assert_t *, size_t, const unsigned char *, size_t); int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *, size_t); int fido_assert_set_count(fido_assert_t *, size_t); int fido_assert_set_extensions(fido_assert_t *, int); int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); int fido_assert_set_options(fido_assert_t *, bool, bool) __attribute__((__deprecated__)); int fido_assert_set_rp(fido_assert_t *, const char *); int fido_assert_set_up(fido_assert_t *, fido_opt_t); int fido_assert_set_uv(fido_assert_t *, fido_opt_t); int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t); int fido_assert_verify(const fido_assert_t *, size_t, int, const void *); int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_extensions(fido_cred_t *, int); int fido_cred_set_fmt(fido_cred_t *, const char *); int fido_cred_set_options(fido_cred_t *, bool, bool) __attribute__((__deprecated__)); int fido_cred_set_rk(fido_cred_t *, fido_opt_t); int fido_cred_set_rp(fido_cred_t *, const char *, const char *); int fido_cred_set_sig(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_type(fido_cred_t *, int); int fido_cred_set_uv(fido_cred_t *, fido_opt_t); int fido_cred_type(const fido_cred_t *); int fido_cred_set_user(fido_cred_t *, const unsigned char *, size_t, const char *, const char *, const char *); int fido_cred_set_x509(fido_cred_t *, const unsigned char *, size_t); int fido_cred_verify(const fido_cred_t *); int fido_cred_verify_self(const fido_cred_t *); int fido_dev_cancel(fido_dev_t *); int fido_dev_close(fido_dev_t *); int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *); int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *); int fido_dev_get_retry_count(fido_dev_t *, int *); int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); int fido_dev_open(fido_dev_t *, const char *); int fido_dev_reset(fido_dev_t *); int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *); int fido_dev_set_pin(fido_dev_t *, const char *, const char *); size_t fido_assert_authdata_len(const fido_assert_t *, size_t); size_t fido_assert_clientdata_hash_len(const fido_assert_t *); size_t fido_assert_count(const fido_assert_t *); size_t fido_assert_hmac_secret_len(const fido_assert_t *, size_t); size_t fido_assert_id_len(const fido_assert_t *, size_t); size_t fido_assert_sig_len(const fido_assert_t *, size_t); size_t fido_assert_user_id_len(const fido_assert_t *, size_t); size_t fido_cbor_info_aaguid_len(const fido_cbor_info_t *); size_t fido_cbor_info_extensions_len(const fido_cbor_info_t *); size_t fido_cbor_info_options_len(const fido_cbor_info_t *); size_t fido_cbor_info_protocols_len(const fido_cbor_info_t *); size_t fido_cbor_info_versions_len(const fido_cbor_info_t *); size_t fido_cred_authdata_len(const fido_cred_t *); size_t fido_cred_clientdata_hash_len(const fido_cred_t *); size_t fido_cred_id_len(const fido_cred_t *); size_t fido_cred_user_id_len(const fido_cred_t *); size_t fido_cred_pubkey_len(const fido_cred_t *); size_t fido_cred_sig_len(const fido_cred_t *); size_t fido_cred_x5c_len(const fido_cred_t *); uint8_t fido_assert_flags(const fido_assert_t *, size_t); uint32_t fido_assert_sigcount(const fido_assert_t *, size_t); uint8_t fido_cred_flags(const fido_cred_t *); uint8_t fido_dev_protocol(const fido_dev_t *); uint8_t fido_dev_major(const fido_dev_t *); uint8_t fido_dev_minor(const fido_dev_t *); uint8_t fido_dev_build(const fido_dev_t *); uint8_t fido_dev_flags(const fido_dev_t *); int16_t fido_dev_info_vendor(const fido_dev_info_t *); int16_t fido_dev_info_product(const fido_dev_info_t *); uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); bool fido_dev_is_fido2(const fido_dev_t *); #endif /* !_FIDO_H */ libfido2-1.3.1/src/fido/000077500000000000000000000000001362326726700147345ustar00rootroot00000000000000libfido2-1.3.1/src/fido/bio.h000066400000000000000000000065661362326726700156730ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_BIO_H #define _FIDO_BIO_H #include #include #include "fido/err.h" #include "fido/param.h" #ifdef _FIDO_INTERNAL struct fido_bio_template { fido_blob_t id; char *name; }; struct fido_bio_template_array { struct fido_bio_template *ptr; size_t n_alloc; /* number of allocated entries */ size_t n_rx; /* number of populated entries */ }; struct fido_bio_enroll { uint8_t remaining_samples; uint8_t last_status; fido_blob_t *token; }; struct fido_bio_info { uint8_t type; uint8_t max_samples; }; #endif typedef struct fido_bio_template fido_bio_template_t; typedef struct fido_bio_template_array fido_bio_template_array_t; typedef struct fido_bio_enroll fido_bio_enroll_t; typedef struct fido_bio_info fido_bio_info_t; #define FIDO_BIO_ENROLL_FP_GOOD 0x00 #define FIDO_BIO_ENROLL_FP_TOO_HIGH 0x01 #define FIDO_BIO_ENROLL_FP_TOO_LOW 0x02 #define FIDO_BIO_ENROLL_FP_TOO_LEFT 0x03 #define FIDO_BIO_ENROLL_FP_TOO_RIGHT 0x04 #define FIDO_BIO_ENROLL_FP_TOO_FAST 0x05 #define FIDO_BIO_ENROLL_FP_TOO_SLOW 0x06 #define FIDO_BIO_ENROLL_FP_POOR_QUALITY 0x07 #define FIDO_BIO_ENROLL_FP_TOO_SKEWED 0x08 #define FIDO_BIO_ENROLL_FP_TOO_SHORT 0x09 #define FIDO_BIO_ENROLL_FP_MERGE_FAILURE 0x0a #define FIDO_BIO_ENROLL_FP_EXISTS 0x0b #define FIDO_BIO_ENROLL_FP_DATABASE_FULL 0x0c #define FIDO_BIO_ENROLL_NO_USER_ACTIVITY 0x0d #define FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION 0x0e const char *fido_bio_template_name(const fido_bio_template_t *); const fido_bio_template_t *fido_bio_template(const fido_bio_template_array_t *, size_t); const unsigned char *fido_bio_template_id_ptr(const fido_bio_template_t *); fido_bio_enroll_t *fido_bio_enroll_new(void); fido_bio_info_t *fido_bio_info_new(void); fido_bio_template_array_t *fido_bio_template_array_new(void); fido_bio_template_t *fido_bio_template_new(void); int fido_bio_dev_enroll_begin(fido_dev_t *, fido_bio_template_t *, fido_bio_enroll_t *, uint32_t, const char *); int fido_bio_dev_enroll_cancel(fido_dev_t *); int fido_bio_dev_enroll_continue(fido_dev_t *, const fido_bio_template_t *, fido_bio_enroll_t *, uint32_t); int fido_bio_dev_enroll_remove(fido_dev_t *, const fido_bio_template_t *, const char *); int fido_bio_dev_get_info(fido_dev_t *, fido_bio_info_t *); int fido_bio_dev_get_template_array(fido_dev_t *, fido_bio_template_array_t *, const char *); int fido_bio_dev_set_template_name(fido_dev_t *, const fido_bio_template_t *, const char *); int fido_bio_template_set_id(fido_bio_template_t *, const unsigned char *, size_t); int fido_bio_template_set_name(fido_bio_template_t *, const char *); size_t fido_bio_template_array_count(const fido_bio_template_array_t *); size_t fido_bio_template_id_len(const fido_bio_template_t *); uint8_t fido_bio_enroll_last_status(const fido_bio_enroll_t *); uint8_t fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *); uint8_t fido_bio_info_max_samples(const fido_bio_info_t *); uint8_t fido_bio_info_type(const fido_bio_info_t *); void fido_bio_enroll_free(fido_bio_enroll_t **); void fido_bio_info_free(fido_bio_info_t **); void fido_bio_template_array_free(fido_bio_template_array_t **); void fido_bio_template_free(fido_bio_template_t **); #endif /* !_FIDO_BIO_H */ libfido2-1.3.1/src/fido/credman.h000066400000000000000000000043761362326726700165300ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_CREDMAN_H #define _FIDO_CREDMAN_H #include #include #include "fido/err.h" #include "fido/param.h" #ifdef _FIDO_INTERNAL struct fido_credman_metadata { uint64_t rk_existing; uint64_t rk_remaining; }; struct fido_credman_single_rp { fido_rp_t rp_entity; fido_blob_t rp_id_hash; }; struct fido_credman_rp { struct fido_credman_single_rp *ptr; size_t n_alloc; /* number of allocated entries */ size_t n_rx; /* number of populated entries */ }; struct fido_credman_rk { fido_cred_t *ptr; size_t n_alloc; /* number of allocated entries */ size_t n_rx; /* number of populated entries */ }; #endif typedef struct fido_credman_metadata fido_credman_metadata_t; typedef struct fido_credman_rk fido_credman_rk_t; typedef struct fido_credman_rp fido_credman_rp_t; const char *fido_credman_rp_id(const fido_credman_rp_t *, size_t); const char *fido_credman_rp_name(const fido_credman_rp_t *, size_t); const fido_cred_t *fido_credman_rk(const fido_credman_rk_t *, size_t); const unsigned char *fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *, size_t); fido_credman_metadata_t *fido_credman_metadata_new(void); fido_credman_rk_t *fido_credman_rk_new(void); fido_credman_rp_t *fido_credman_rp_new(void); int fido_credman_del_dev_rk(fido_dev_t *, const unsigned char *, size_t, const char *); int fido_credman_get_dev_metadata(fido_dev_t *, fido_credman_metadata_t *, const char *); int fido_credman_get_dev_rk(fido_dev_t *, const char *, fido_credman_rk_t *, const char *); int fido_credman_get_dev_rp(fido_dev_t *, fido_credman_rp_t *, const char *); size_t fido_credman_rk_count(const fido_credman_rk_t *); size_t fido_credman_rp_count(const fido_credman_rp_t *); size_t fido_credman_rp_id_hash_len(const fido_credman_rp_t *, size_t); uint64_t fido_credman_rk_existing(const fido_credman_metadata_t *); uint64_t fido_credman_rk_remaining(const fido_credman_metadata_t *); void fido_credman_metadata_free(fido_credman_metadata_t **); void fido_credman_rk_free(fido_credman_rk_t **); void fido_credman_rp_free(fido_credman_rp_t **); #endif /* !_FIDO_CREDMAN_H */ libfido2-1.3.1/src/fido/eddsa.h000066400000000000000000000022331362326726700161650ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_EDDSA_H #define _FIDO_EDDSA_H #include #include #include eddsa_pk_t *eddsa_pk_new(void); void eddsa_pk_free(eddsa_pk_t **); EVP_PKEY *eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *); int eddsa_pk_from_EVP_PKEY(eddsa_pk_t *, const EVP_PKEY *); int eddsa_pk_from_ptr(eddsa_pk_t *, const void *, size_t); #ifdef _FIDO_INTERNAL #if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L #define EVP_PKEY_ED25519 EVP_PKEY_NONE int EVP_PKEY_get_raw_public_key(const EVP_PKEY *, unsigned char *, size_t *); EVP_PKEY *EVP_PKEY_new_raw_public_key(int, ENGINE *, const unsigned char *, size_t); int EVP_DigestVerify(EVP_MD_CTX *, const unsigned char *, size_t, const unsigned char *, size_t); #endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_MD_CTX *EVP_MD_CTX_new(void); void EVP_MD_CTX_free(EVP_MD_CTX *); #endif #endif /* _FIDO_INTERNAL */ #endif /* !_FIDO_EDDSA_H */ libfido2-1.3.1/src/fido/err.h000066400000000000000000000043661362326726700157060ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_ERR_H #define _FIDO_ERR_H #define FIDO_ERR_SUCCESS 0x00 #define FIDO_ERR_INVALID_COMMAND 0x01 #define FIDO_ERR_INVALID_PARAMETER 0x02 #define FIDO_ERR_INVALID_LENGTH 0x03 #define FIDO_ERR_INVALID_SEQ 0x04 #define FIDO_ERR_TIMEOUT 0x05 #define FIDO_ERR_CHANNEL_BUSY 0x06 #define FIDO_ERR_LOCK_REQUIRED 0x0a #define FIDO_ERR_INVALID_CHANNEL 0x0b #define FIDO_ERR_CBOR_UNEXPECTED_TYPE 0x11 #define FIDO_ERR_INVALID_CBOR 0x12 #define FIDO_ERR_MISSING_PARAMETER 0x14 #define FIDO_ERR_LIMIT_EXCEEDED 0x15 #define FIDO_ERR_UNSUPPORTED_EXTENSION 0x16 #define FIDO_ERR_CREDENTIAL_EXCLUDED 0x19 #define FIDO_ERR_PROCESSING 0x21 #define FIDO_ERR_INVALID_CREDENTIAL 0x22 #define FIDO_ERR_USER_ACTION_PENDING 0x23 #define FIDO_ERR_OPERATION_PENDING 0x24 #define FIDO_ERR_NO_OPERATIONS 0x25 #define FIDO_ERR_UNSUPPORTED_ALGORITHM 0x26 #define FIDO_ERR_OPERATION_DENIED 0x27 #define FIDO_ERR_KEY_STORE_FULL 0x28 #define FIDO_ERR_NOT_BUSY 0x29 #define FIDO_ERR_NO_OPERATION_PENDING 0x2a #define FIDO_ERR_UNSUPPORTED_OPTION 0x2b #define FIDO_ERR_INVALID_OPTION 0x2c #define FIDO_ERR_KEEPALIVE_CANCEL 0x2d #define FIDO_ERR_NO_CREDENTIALS 0x2e #define FIDO_ERR_USER_ACTION_TIMEOUT 0x2f #define FIDO_ERR_NOT_ALLOWED 0x30 #define FIDO_ERR_PIN_INVALID 0x31 #define FIDO_ERR_PIN_BLOCKED 0x32 #define FIDO_ERR_PIN_AUTH_INVALID 0x33 #define FIDO_ERR_PIN_AUTH_BLOCKED 0x34 #define FIDO_ERR_PIN_NOT_SET 0x35 #define FIDO_ERR_PIN_REQUIRED 0x36 #define FIDO_ERR_PIN_POLICY_VIOLATION 0x37 #define FIDO_ERR_PIN_TOKEN_EXPIRED 0x38 #define FIDO_ERR_REQUEST_TOO_LARGE 0x39 #define FIDO_ERR_ACTION_TIMEOUT 0x3a #define FIDO_ERR_UP_REQUIRED 0x3b #define FIDO_ERR_ERR_OTHER 0x7f #define FIDO_ERR_SPEC_LAST 0xdf /* defined internally */ #define FIDO_OK FIDO_ERR_SUCCESS #define FIDO_ERR_TX -1 #define FIDO_ERR_RX -2 #define FIDO_ERR_RX_NOT_CBOR -3 #define FIDO_ERR_RX_INVALID_CBOR -4 #define FIDO_ERR_INVALID_PARAM -5 #define FIDO_ERR_INVALID_SIG -6 #define FIDO_ERR_INVALID_ARGUMENT -7 #define FIDO_ERR_USER_PRESENCE_REQUIRED -8 #define FIDO_ERR_INTERNAL -9 const char *fido_strerr(int); #endif /* _FIDO_ERR_H */ libfido2-1.3.1/src/fido/es256.h000066400000000000000000000016001362326726700157460ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_ES256_H #define _FIDO_ES256_H #include #include #include es256_pk_t *es256_pk_new(void); void es256_pk_free(es256_pk_t **); EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *); int es256_pk_from_EC_KEY(es256_pk_t *, const EC_KEY *); int es256_pk_from_ptr(es256_pk_t *, const void *, size_t); #ifdef _FIDO_INTERNAL es256_sk_t *es256_sk_new(void); void es256_sk_free(es256_sk_t **); EVP_PKEY *es256_sk_to_EVP_PKEY(const es256_sk_t *); int es256_derive_pk(const es256_sk_t *, es256_pk_t *); int es256_sk_create(es256_sk_t *); int es256_pk_set_x(es256_pk_t *, const unsigned char *); int es256_pk_set_y(es256_pk_t *, const unsigned char *); #endif #endif /* !_FIDO_ES256_H */ libfido2-1.3.1/src/fido/param.h000066400000000000000000000042501362326726700162060ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_PARAM_H #define _FIDO_PARAM_H /* Authentication data flags. */ #define CTAP_AUTHDATA_USER_PRESENT 0x01 #define CTAP_AUTHDATA_USER_VERIFIED 0x04 #define CTAP_AUTHDATA_ATT_CRED 0x40 #define CTAP_AUTHDATA_EXT_DATA 0x80 /* CTAPHID command opcodes. */ #define CTAP_CMD_PING 0x01 #define CTAP_CMD_MSG 0x03 #define CTAP_CMD_LOCK 0x04 #define CTAP_CMD_INIT 0x06 #define CTAP_CMD_WINK 0x08 #define CTAP_CMD_CBOR 0x10 #define CTAP_CMD_CANCEL 0x11 #define CTAP_KEEPALIVE 0x3b #define CTAP_FRAME_INIT 0x80 /* CTAPHID CBOR command opcodes. */ #define CTAP_CBOR_MAKECRED 0x01 #define CTAP_CBOR_ASSERT 0x02 #define CTAP_CBOR_GETINFO 0x04 #define CTAP_CBOR_CLIENT_PIN 0x06 #define CTAP_CBOR_RESET 0x07 #define CTAP_CBOR_NEXT_ASSERT 0x08 #define CTAP_CBOR_BIO_ENROLL_PRE 0x40 #define CTAP_CBOR_CRED_MGMT_PRE 0x41 /* U2F command opcodes. */ #define U2F_CMD_REGISTER 0x01 #define U2F_CMD_AUTH 0x02 /* U2F command flags. */ #define U2F_AUTH_SIGN 0x03 #define U2F_AUTH_CHECK 0x07 /* ISO7816-4 status words. */ #define SW_CONDITIONS_NOT_SATISFIED 0x6985 #define SW_WRONG_DATA 0x6a80 #define SW_NO_ERROR 0x9000 /* HID Broadcast channel ID. */ #define CTAP_CID_BROADCAST 0xffffffff /* Expected size of a HID report in bytes. */ #define CTAP_RPT_SIZE 64 /* Randomness device on UNIX-like platforms. */ #ifndef FIDO_RANDOM_DEV #define FIDO_RANDOM_DEV "/dev/urandom" #endif /* CTAP capability bits. */ #define FIDO_CAP_WINK 0x01 /* if set, device supports CTAP_CMD_WINK */ #define FIDO_CAP_CBOR 0x04 /* if set, device supports CTAP_CMD_CBOR */ #define FIDO_CAP_NMSG 0x08 /* if set, device doesn't support CTAP_CMD_MSG */ /* Supported COSE algorithms. */ #define COSE_ES256 -7 #define COSE_EDDSA -8 #define COSE_ECDH_ES256 -25 #define COSE_RS256 -257 /* Supported COSE types. */ #define COSE_KTY_OKP 1 #define COSE_KTY_EC2 2 #define COSE_KTY_RSA 3 /* Supported curves. */ #define COSE_P256 1 #define COSE_ED25519 6 /* Supported extensions. */ #define FIDO_EXT_HMAC_SECRET 0x01 #endif /* !_FIDO_PARAM_H */ libfido2-1.3.1/src/fido/rs256.h000066400000000000000000000010301362326726700157600ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_RS256_H #define _FIDO_RS256_H #include #include #include rs256_pk_t *rs256_pk_new(void); void rs256_pk_free(rs256_pk_t **); EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *); int rs256_pk_from_RSA(rs256_pk_t *, const RSA *); int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t); #endif /* !_FIDO_RS256_H */ libfido2-1.3.1/src/hid.c000066400000000000000000000023071362326726700147250ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" fido_dev_info_t * fido_dev_info_new(size_t n) { return (calloc(n, sizeof(fido_dev_info_t))); } void fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n) { fido_dev_info_t *devlist; if (devlist_p == NULL || (devlist = *devlist_p) == NULL) return; for (size_t i = 0; i < n; i++) { const fido_dev_info_t *di = &devlist[i]; free(di->path); free(di->manufacturer); free(di->product); } free(devlist); *devlist_p = NULL; } const fido_dev_info_t * fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i) { return (&devlist[i]); } const char * fido_dev_info_path(const fido_dev_info_t *di) { return (di->path); } int16_t fido_dev_info_vendor(const fido_dev_info_t *di) { return (di->vendor_id); } int16_t fido_dev_info_product(const fido_dev_info_t *di) { return (di->product_id); } const char * fido_dev_info_manufacturer_string(const fido_dev_info_t *di) { return (di->manufacturer); } const char * fido_dev_info_product_string(const fido_dev_info_t *di) { return (di->product); } libfido2-1.3.1/src/hid_linux.c000066400000000000000000000146111362326726700161450ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include "fido.h" #define REPORT_LEN 65 static int get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) { *key = tag & 0xfc; if ((*key & 0xf0) == 0xf0) { fido_log_debug("%s: *key=0x%02x", __func__, *key); return (-1); } *key_len = tag & 0x3; if (*key_len == 3) { *key_len = 4; } return (0); } static int get_key_val(const void *body, size_t key_len, uint32_t *val) { const uint8_t *ptr = body; switch (key_len) { case 0: *val = 0; break; case 1: *val = ptr[0]; break; case 2: *val = (uint32_t)((ptr[1] << 8) | ptr[0]); break; default: fido_log_debug("%s: key_len=%zu", __func__, key_len); return (-1); } return (0); } static int get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, uint32_t *usage) { const uint8_t *ptr; size_t len; ptr = hrd->value; len = hrd->size; while (len > 0) { const uint8_t tag = ptr[0]; ptr++; len--; uint8_t key; size_t key_len; uint32_t key_val; if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || get_key_val(ptr, key_len, &key_val) < 0) { return (-1); } if (key == 0x4) { *usage_page = key_val; } else if (key == 0x8) { *usage = key_val; } ptr += key_len; len -= key_len; } return (0); } static int get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) { int r; int s = -1; int fd; int ok = -1; if ((fd = open(path, O_RDONLY)) < 0) { fido_log_debug("%s: open", __func__); return (-1); } if ((r = ioctl(fd, HIDIOCGRDESCSIZE, &s)) < 0 || s < 0 || (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); goto fail; } hrd->size = s; if ((r = ioctl(fd, HIDIOCGRDESC, hrd)) < 0) { fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); goto fail; } ok = 0; fail: if (fd != -1) close(fd); return (ok); } static bool is_fido(const char *path) { uint32_t usage = 0; uint32_t usage_page = 0; struct hidraw_report_descriptor hrd; memset(&hrd, 0, sizeof(hrd)); if (get_report_descriptor(path, &hrd) < 0 || get_usage_info(&hrd, &usage_page, &usage) < 0) { return (false); } return (usage_page == 0xf1d0); } static int parse_uevent(struct udev_device *dev, int16_t *vendor_id, int16_t *product_id) { const char *uevent; char *cp; char *p; char *s; int ok = -1; short unsigned int x; short unsigned int y; if ((uevent = udev_device_get_sysattr_value(dev, "uevent")) == NULL) return (-1); if ((s = cp = strdup(uevent)) == NULL) return (-1); for ((p = strsep(&cp, "\n")); p && *p != '\0'; (p = strsep(&cp, "\n"))) { if (strncmp(p, "HID_ID=", 7) == 0) { if (sscanf(p + 7, "%*x:%hx:%hx", &x, &y) == 2) { *vendor_id = (int16_t)x; *product_id = (int16_t)y; ok = 0; } break; } } free(s); return (ok); } static int copy_info(fido_dev_info_t *di, struct udev *udev, struct udev_list_entry *udev_entry) { const char *name; const char *path; const char *manufacturer; const char *product; struct udev_device *dev = NULL; struct udev_device *hid_parent; struct udev_device *usb_parent; int ok = -1; memset(di, 0, sizeof(*di)); if ((name = udev_list_entry_get_name(udev_entry)) == NULL || (dev = udev_device_new_from_syspath(udev, name)) == NULL || (path = udev_device_get_devnode(dev)) == NULL || is_fido(path) == 0) goto fail; if ((hid_parent = udev_device_get_parent_with_subsystem_devtype(dev, "hid", NULL)) == NULL) goto fail; if ((usb_parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device")) == NULL) goto fail; if (parse_uevent(hid_parent, &di->vendor_id, &di->product_id) < 0 || (manufacturer = udev_device_get_sysattr_value(usb_parent, "manufacturer")) == NULL || (product = udev_device_get_sysattr_value(usb_parent, "product")) == NULL) goto fail; di->path = strdup(path); di->manufacturer = strdup(manufacturer); di->product = strdup(product); if (di->path == NULL || di->manufacturer == NULL || di->product == NULL) goto fail; ok = 0; fail: if (dev != NULL) udev_device_unref(dev); if (ok < 0) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); } return (ok); } int fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { struct udev *udev = NULL; struct udev_enumerate *udev_enum = NULL; struct udev_list_entry *udev_list; struct udev_list_entry *udev_entry; int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((udev = udev_new()) == NULL || (udev_enum = udev_enumerate_new(udev)) == NULL) goto fail; if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 || udev_enumerate_scan_devices(udev_enum) < 0 || (udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) goto fail; udev_list_entry_foreach(udev_entry, udev_list) { if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { if (++(*olen) == ilen) break; } } r = FIDO_OK; fail: if (udev_enum != NULL) udev_enumerate_unref(udev_enum); if (udev != NULL) udev_unref(udev); return (r); } void * fido_hid_open(const char *path) { int *fd; if ((fd = malloc(sizeof(*fd))) == NULL || (*fd = open(path, O_RDWR)) < 0) { free(fd); return (NULL); } return (fd); } void fido_hid_close(void *handle) { int *fd = handle; close(*fd); free(fd); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { int *fd = handle; ssize_t r; (void)ms; /* XXX */ if (len != REPORT_LEN - 1) { fido_log_debug("%s: invalid len", __func__); return (-1); } if ((r = read(*fd, buf, len)) < 0 || r != REPORT_LEN - 1) return (-1); return (REPORT_LEN - 1); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { int *fd = handle; ssize_t r; if (len != REPORT_LEN) { fido_log_debug("%s: invalid len", __func__); return (-1); } if ((r = write(*fd, buf, len)) < 0 || r != REPORT_LEN) { fido_log_debug("%s: write", __func__); return (-1); } return (REPORT_LEN); } libfido2-1.3.1/src/hid_openbsd.c000066400000000000000000000160751362326726700164460ustar00rootroot00000000000000/* * Copyright (c) 2019 Google LLC. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include "fido.h" #define MAX_UHID 64 #define MAX_REPORT_LEN (sizeof(((struct usb_ctl_report *)(NULL))->ucr_data)) struct hid_openbsd { int fd; size_t report_in_len; size_t report_out_len; }; int fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { size_t i; char path[64]; int is_fido, fd; struct usb_device_info udi; report_desc_t rdesc = NULL; hid_data_t hdata = NULL; hid_item_t hitem; fido_dev_info_t *di; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL || olen == NULL) return (FIDO_ERR_INVALID_ARGUMENT); for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) { snprintf(path, sizeof(path), "/dev/uhid%zu", i); if ((fd = open(path, O_RDWR)) == -1) { if (errno != ENOENT && errno != ENXIO) { fido_log_debug("%s: open %s: %s", __func__, path, strerror(errno)); } continue; } memset(&udi, 0, sizeof(udi)); if (ioctl(fd, USB_GET_DEVICEINFO, &udi) != 0) { fido_log_debug("%s: get device info %s: %s", __func__, path, strerror(errno)); close(fd); continue; } if ((rdesc = hid_get_report_desc(fd)) == NULL) { fido_log_debug("%s: failed to get report descriptor: %s", __func__, path); close(fd); continue; } if ((hdata = hid_start_parse(rdesc, 1<path = strdup(path)) == NULL || (di->manufacturer = strdup(udi.udi_vendor)) == NULL || (di->product = strdup(udi.udi_product)) == NULL) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); return FIDO_ERR_INTERNAL; } di->vendor_id = udi.udi_vendorNo; di->product_id = udi.udi_productNo; (*olen)++; } return FIDO_OK; } /* * Workaround for OpenBSD <=6.6-current (as of 201910) bug that loses * sync of DATA0/DATA1 sequence bit across uhid open/close. * Send pings until we get a response - early pings with incorrect * sequence bits will be ignored as duplicate packets by the device. */ static int terrible_ping_kludge(struct hid_openbsd *ctx) { u_char data[256]; int i, n; struct pollfd pfd; if (sizeof(data) < ctx->report_out_len + 1) return -1; for (i = 0; i < 4; i++) { memset(data, 0, sizeof(data)); /* broadcast channel ID */ data[1] = 0xff; data[2] = 0xff; data[3] = 0xff; data[4] = 0xff; /* Ping command */ data[5] = 0x81; /* One byte ping only, Vasili */ data[6] = 0; data[7] = 1; fido_log_debug("%s: send ping %d", __func__, i); if (fido_hid_write(ctx, data, ctx->report_out_len + 1) == -1) return -1; fido_log_debug("%s: wait reply", __func__); memset(&pfd, 0, sizeof(pfd)); pfd.fd = ctx->fd; pfd.events = POLLIN; if ((n = poll(&pfd, 1, 100)) == -1) { fido_log_debug("%s: poll: %s", __func__, strerror(errno)); return -1; } else if (n == 0) { fido_log_debug("%s: timed out", __func__); continue; } if (fido_hid_read(ctx, data, ctx->report_out_len, 250) == -1) return -1; /* * Ping isn't always supported on the broadcast channel, * so we might get an error, but we don't care - we're * synched now. */ fido_log_debug("%s: got reply", __func__); fido_log_xxd(data, ctx->report_out_len); return 0; } fido_log_debug("%s: no response", __func__); return -1; } void * fido_hid_open(const char *path) { struct hid_openbsd *ret = NULL; report_desc_t rdesc = NULL; int len, usb_report_id = 0; if ((ret = calloc(1, sizeof(*ret))) == NULL || (ret->fd = open(path, O_RDWR)) < 0) { free(ret); return (NULL); } if (ioctl(ret->fd, USB_GET_REPORT_ID, &usb_report_id) != 0) { fido_log_debug("%s: failed to get report ID: %s", __func__, strerror(errno)); goto fail; } if ((rdesc = hid_get_report_desc(ret->fd)) == NULL) { fido_log_debug("%s: failed to get report descriptor", __func__); goto fail; } if ((len = hid_report_size(rdesc, hid_input, usb_report_id)) <= 0 || (size_t)len > MAX_REPORT_LEN) { fido_log_debug("%s: bad input report size %d", __func__, len); goto fail; } ret->report_in_len = (size_t)len; if ((len = hid_report_size(rdesc, hid_output, usb_report_id)) <= 0 || (size_t)len > MAX_REPORT_LEN) { fido_log_debug("%s: bad output report size %d", __func__, len); fail: hid_dispose_report_desc(rdesc); close(ret->fd); free(ret); return NULL; } ret->report_out_len = (size_t)len; hid_dispose_report_desc(rdesc); fido_log_debug("%s: USB report ID %d, inlen = %zu outlen = %zu", __func__, usb_report_id, ret->report_in_len, ret->report_out_len); /* * OpenBSD (as of 201910) has a bug that causes it to lose * track of the DATA0/DATA1 sequence toggle across uhid device * open and close. This is a terrible hack to work around it. */ if (terrible_ping_kludge(ret) != 0) { fido_hid_close(ret); return NULL; } return (ret); } void fido_hid_close(void *handle) { struct hid_openbsd *ctx = (struct hid_openbsd *)handle; close(ctx->fd); free(ctx); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { struct hid_openbsd *ctx = (struct hid_openbsd *)handle; ssize_t r; (void)ms; /* XXX */ if (len != ctx->report_in_len) { fido_log_debug("%s: invalid len: got %zu, want %zu", __func__, len, ctx->report_in_len); return (-1); } if ((r = read(ctx->fd, buf, len)) == -1 || (size_t)r != len) { fido_log_debug("%s: read: %s", __func__, strerror(errno)); return (-1); } return ((int)len); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct hid_openbsd *ctx = (struct hid_openbsd *)handle; ssize_t r; if (len != ctx->report_out_len + 1) { fido_log_debug("%s: invalid len: got %zu, want %zu", __func__, len, ctx->report_out_len); return (-1); } if ((r = write(ctx->fd, buf + 1, len - 1)) == -1 || (size_t)r != len - 1) { fido_log_debug("%s: write: %s", __func__, strerror(errno)); return (-1); } return ((int)len); } libfido2-1.3.1/src/hid_osx.c000066400000000000000000000212121362326726700156120ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include "fido.h" #define REPORT_LEN 65 struct dev { IOHIDDeviceRef ref; CFStringRef loop_id; }; static int get_int32(IOHIDDeviceRef dev, CFStringRef key, int32_t *v) { CFTypeRef ref; if ((ref = IOHIDDeviceGetProperty(dev, key)) == NULL || CFGetTypeID(ref) != CFNumberGetTypeID()) { fido_log_debug("%s: IOHIDDeviceGetProperty", __func__); return (-1); } if (CFNumberGetType(ref) != kCFNumberSInt32Type && CFNumberGetType(ref) != kCFNumberSInt64Type) { fido_log_debug("%s: CFNumberGetType", __func__); return (-1); } if (CFNumberGetValue(ref, kCFNumberSInt32Type, v) == false) { fido_log_debug("%s: CFNumberGetValue", __func__); return (-1); } return (0); } static int get_utf8(IOHIDDeviceRef dev, CFStringRef key, void *buf, size_t len) { CFTypeRef ref; memset(buf, 0, len); if ((ref = IOHIDDeviceGetProperty(dev, key)) == NULL || CFGetTypeID(ref) != CFStringGetTypeID()) { fido_log_debug("%s: IOHIDDeviceGetProperty", __func__); return (-1); } if (CFStringGetCString(ref, buf, len, kCFStringEncodingUTF8) == false) { fido_log_debug("%s: CFStringGetCString", __func__); return (-1); } return (0); } static bool is_fido(IOHIDDeviceRef dev) { uint32_t usage_page; int32_t report_len; if (get_int32(dev, CFSTR(kIOHIDPrimaryUsagePageKey), (int32_t *)&usage_page) != 0 || usage_page != 0xf1d0) return (false); if (get_int32(dev, CFSTR(kIOHIDMaxInputReportSizeKey), &report_len) < 0 || report_len != REPORT_LEN - 1) { fido_log_debug("%s: unsupported report len", __func__); return (false); } return (true); } static int get_id(IOHIDDeviceRef dev, int16_t *vendor_id, int16_t *product_id) { int32_t vendor; int32_t product; if (get_int32(dev, CFSTR(kIOHIDVendorIDKey), &vendor) < 0 || vendor > UINT16_MAX) { fido_log_debug("%s: get_int32 vendor", __func__); return (-1); } if (get_int32(dev, CFSTR(kIOHIDProductIDKey), &product) < 0 || product > UINT16_MAX) { fido_log_debug("%s: get_int32 product", __func__); return (-1); } *vendor_id = (int16_t)vendor; *product_id = (int16_t)product; return (0); } static int get_str(IOHIDDeviceRef dev, char **manufacturer, char **product) { char buf[512]; int ok = -1; *manufacturer = NULL; *product = NULL; if (get_utf8(dev, CFSTR(kIOHIDManufacturerKey), buf, sizeof(buf)) < 0) { fido_log_debug("%s: get_utf8 manufacturer", __func__); goto fail; } if ((*manufacturer = strdup(buf)) == NULL) { fido_log_debug("%s: strdup manufacturer", __func__); goto fail; } if (get_utf8(dev, CFSTR(kIOHIDProductKey), buf, sizeof(buf)) < 0) { fido_log_debug("%s: get_utf8 product", __func__); goto fail; } if ((*product = strdup(buf)) == NULL) { fido_log_debug("%s: strdup product", __func__); goto fail; } ok = 0; fail: if (ok < 0) { free(*manufacturer); free(*product); *manufacturer = NULL; *product = NULL; } return (ok); } static char * get_path(IOHIDDeviceRef dev) { io_service_t s; io_string_t path; if ((s = IOHIDDeviceGetService(dev)) == MACH_PORT_NULL) { fido_log_debug("%s: IOHIDDeviceGetService", __func__); return (NULL); } if (IORegistryEntryGetPath(s, kIOServicePlane, path) != KERN_SUCCESS) { fido_log_debug("%s: IORegistryEntryGetPath", __func__); return (NULL); } return (strdup(path)); } static int copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev) { memset(di, 0, sizeof(*di)); if (is_fido(dev) == false) return (-1); if (get_id(dev, &di->vendor_id, &di->product_id) < 0 || get_str(dev, &di->manufacturer, &di->product) < 0 || (di->path = get_path(dev)) == NULL) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); return (-1); } return (0); } int fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { IOHIDManagerRef manager = NULL; CFSetRef devset = NULL; CFIndex devcnt; IOHIDDeviceRef *devs = NULL; int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone)) == NULL) { fido_log_debug("%s: IOHIDManagerCreate", __func__); goto fail; } IOHIDManagerSetDeviceMatching(manager, NULL); if ((devset = IOHIDManagerCopyDevices(manager)) == NULL) { fido_log_debug("%s: IOHIDManagerCopyDevices", __func__); goto fail; } if ((devcnt = CFSetGetCount(devset)) < 0) { fido_log_debug("%s: CFSetGetCount", __func__); goto fail; } if ((devs = calloc(devcnt, sizeof(*devs))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } CFSetGetValues(devset, (void *)devs); for (CFIndex i = 0; i < devcnt; i++) { if (copy_info(&devlist[*olen], devs[i]) == 0) { if (++(*olen) == ilen) break; } } r = FIDO_OK; fail: if (manager != NULL) CFRelease(manager); if (devset != NULL) CFRelease(devset); free(devs); return (r); } void * fido_hid_open(const char *path) { io_registry_entry_t entry = MACH_PORT_NULL; struct dev *dev = NULL; int ok = -1; int r; char loop_id[32]; if ((dev = calloc(1, sizeof(*dev))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } if ((entry = IORegistryEntryFromPath(kIOMasterPortDefault, path)) == MACH_PORT_NULL) { fido_log_debug("%s: IORegistryEntryFromPath", __func__); goto fail; } if ((dev->ref = IOHIDDeviceCreate(kCFAllocatorDefault, entry)) == NULL) { fido_log_debug("%s: IOHIDDeviceCreate", __func__); goto fail; } if (IOHIDDeviceOpen(dev->ref, kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) { fido_log_debug("%s: IOHIDDeviceOpen", __func__); goto fail; } if ((r = snprintf(loop_id, sizeof(loop_id), "fido2-%p", (void *)dev->ref)) < 0 || (size_t)r >= sizeof(loop_id)) { fido_log_debug("%s: snprintf", __func__); goto fail; } if ((dev->loop_id = CFStringCreateWithCString(NULL, loop_id, kCFStringEncodingASCII)) == NULL) { fido_log_debug("%s: CFStringCreateWithCString", __func__); goto fail; } ok = 0; fail: if (entry != MACH_PORT_NULL) IOObjectRelease(entry); if (ok < 0 && dev != NULL) { if (dev->ref != NULL) CFRelease(dev->ref); if (dev->loop_id != NULL) CFRelease(dev->loop_id); free(dev); dev = NULL; } return (dev); } void fido_hid_close(void *handle) { struct dev *dev = handle; if (IOHIDDeviceClose(dev->ref, kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) fido_log_debug("%s: IOHIDDeviceClose", __func__); CFRelease(dev->ref); CFRelease(dev->loop_id); free(dev); } static void read_callback(void *context, IOReturn result, void *dev, IOHIDReportType type, uint32_t report_id, uint8_t *report, CFIndex report_len) { (void)context; (void)dev; (void)report; if (result != kIOReturnSuccess || type != kIOHIDReportTypeInput || report_id != 0 || report_len != REPORT_LEN - 1) { fido_log_debug("%s: io error", __func__); } } static void removal_callback(void *context, IOReturn result, void *sender) { (void)context; (void)result; (void)sender; CFRunLoopStop(CFRunLoopGetCurrent()); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { struct dev *dev = handle; CFRunLoopRunResult r; (void)ms; /* XXX */ if (len != REPORT_LEN - 1) { fido_log_debug("%s: invalid len", __func__); return (-1); } explicit_bzero(buf, len); IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, &read_callback, NULL); IOHIDDeviceRegisterRemovalCallback(dev->ref, &removal_callback, dev); IOHIDDeviceScheduleWithRunLoop(dev->ref, CFRunLoopGetCurrent(), dev->loop_id); do r = CFRunLoopRunInMode(dev->loop_id, 0.003, true); while (r != kCFRunLoopRunHandledSource); IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, NULL, NULL); IOHIDDeviceRegisterRemovalCallback(dev->ref, NULL, NULL); IOHIDDeviceUnscheduleFromRunLoop(dev->ref, CFRunLoopGetCurrent(), dev->loop_id); return (REPORT_LEN - 1); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct dev *dev = handle; if (len != REPORT_LEN) { fido_log_debug("%s: invalid len", __func__); return (-1); } if (IOHIDDeviceSetReport(dev->ref, kIOHIDReportTypeOutput, 0, buf + 1, len - 1) != kIOReturnSuccess) { fido_log_debug("%s: IOHIDDeviceSetReport", __func__); return (-1); } return (REPORT_LEN); } libfido2-1.3.1/src/hid_win.c000066400000000000000000000156261362326726700156120ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include "fido.h" #define REPORT_LEN 65 static bool is_fido(HANDLE dev) { PHIDP_PREPARSED_DATA data = NULL; HIDP_CAPS caps; uint16_t usage_page = 0; if (HidD_GetPreparsedData(dev, &data) == false) { fido_log_debug("%s: HidD_GetPreparsedData", __func__); goto fail; } if (HidP_GetCaps(data, &caps) != HIDP_STATUS_SUCCESS) { fido_log_debug("%s: HidP_GetCaps", __func__); goto fail; } if (caps.OutputReportByteLength != REPORT_LEN || caps.InputReportByteLength != REPORT_LEN) { fido_log_debug("%s: unsupported report len", __func__); goto fail; } usage_page = caps.UsagePage; fail: if (data != NULL) HidD_FreePreparsedData(data); return (usage_page == 0xf1d0); } static int get_int(HANDLE dev, int16_t *vendor_id, int16_t *product_id) { HIDD_ATTRIBUTES attr; attr.Size = sizeof(attr); if (HidD_GetAttributes(dev, &attr) == false) { fido_log_debug("%s: HidD_GetAttributes", __func__); return (-1); } *vendor_id = attr.VendorID; *product_id = attr.ProductID; return (0); } static int get_str(HANDLE dev, char **manufacturer, char **product) { wchar_t buf[512]; int utf8_len; int ok = -1; *manufacturer = NULL; *product = NULL; if (HidD_GetManufacturerString(dev, &buf, sizeof(buf)) == false) { fido_log_debug("%s: HidD_GetManufacturerString", __func__); goto fail; } if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, NULL, 0, NULL, NULL)) <= 0 || utf8_len > 128) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } if ((*manufacturer = malloc(utf8_len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, *manufacturer, utf8_len, NULL, NULL) != utf8_len) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } if (HidD_GetProductString(dev, &buf, sizeof(buf)) == false) { fido_log_debug("%s: HidD_GetProductString", __func__); goto fail; } if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, NULL, 0, NULL, NULL)) <= 0 || utf8_len > 128) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } if ((*product = malloc(utf8_len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, *product, utf8_len, NULL, NULL) != utf8_len) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } ok = 0; fail: if (ok < 0) { free(*manufacturer); free(*product); *manufacturer = NULL; *product = NULL; } return (ok); } static int copy_info(fido_dev_info_t *di, const char *path) { HANDLE dev = INVALID_HANDLE_VALUE; int ok = -1; memset(di, 0, sizeof(*di)); dev = CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (dev == INVALID_HANDLE_VALUE || is_fido(dev) == 0) goto fail; if (get_int(dev, &di->vendor_id, &di->product_id) < 0 || get_str(dev, &di->manufacturer, &di->product) < 0) goto fail; if ((di->path = strdup(path)) == NULL) goto fail; ok = 0; fail: if (dev != INVALID_HANDLE_VALUE) CloseHandle(dev); if (ok < 0) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); } return (ok); } int fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { GUID hid_guid = GUID_DEVINTERFACE_HID; HDEVINFO devinfo = INVALID_HANDLE_VALUE; SP_DEVICE_INTERFACE_DATA ifdata; SP_DEVICE_INTERFACE_DETAIL_DATA_A *ifdetail = NULL; DWORD len = 0; DWORD idx = 0; int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); devinfo = SetupDiGetClassDevsA(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); if (devinfo == INVALID_HANDLE_VALUE) { fido_log_debug("%s: SetupDiGetClassDevsA", __func__); goto fail; } ifdata.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); while (SetupDiEnumDeviceInterfaces(devinfo, NULL, &hid_guid, idx++, &ifdata) == true) { /* * "Get the required buffer size. Call * SetupDiGetDeviceInterfaceDetail with a NULL * DeviceInterfaceDetailData pointer, a * DeviceInterfaceDetailDataSize of zero, and a valid * RequiredSize variable. In response to such a call, this * function returns the required buffer size at RequiredSize * and fails with GetLastError returning * ERROR_INSUFFICIENT_BUFFER." */ if (SetupDiGetDeviceInterfaceDetailA(devinfo, &ifdata, NULL, 0, &len, NULL) != false || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 1", __func__); goto fail; } if ((ifdetail = malloc(len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } ifdetail->cbSize = sizeof(*ifdetail); if (SetupDiGetDeviceInterfaceDetailA(devinfo, &ifdata, ifdetail, len, NULL, NULL) == false) { fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 2", __func__); goto fail; } if (copy_info(&devlist[*olen], ifdetail->DevicePath) == 0) { if (++(*olen) == ilen) break; } free(ifdetail); ifdetail = NULL; } r = FIDO_OK; fail: if (devinfo != INVALID_HANDLE_VALUE) SetupDiDestroyDeviceInfoList(devinfo); free(ifdetail); return (r); } void * fido_hid_open(const char *path) { HANDLE dev; dev = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (dev == INVALID_HANDLE_VALUE) return (NULL); return (dev); } void fido_hid_close(void *handle) { CloseHandle(handle); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { DWORD n; int r = -1; uint8_t report[REPORT_LEN]; (void)ms; /* XXX */ memset(report, 0, sizeof(report)); if (len != sizeof(report) - 1) { fido_log_debug("%s: invalid len", __func__); return (-1); } if (ReadFile(handle, report, sizeof(report), &n, NULL) == false || n != sizeof(report)) { fido_log_debug("%s: ReadFile", __func__); goto fail; } r = sizeof(report) - 1; memcpy(buf, report + 1, len); fail: explicit_bzero(report, sizeof(report)); return (r); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { DWORD n; if (len != REPORT_LEN) { fido_log_debug("%s: invalid len", __func__); return (-1); } if (WriteFile(handle, buf, (DWORD)len, &n, NULL) == false || n != REPORT_LEN) { fido_log_debug("%s: WriteFile", __func__); return (-1); } return (REPORT_LEN); } libfido2-1.3.1/src/info.c000066400000000000000000000202561362326726700151170ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" static int decode_version(const cbor_item_t *item, void *arg) { fido_str_array_t *v = arg; const size_t i = v->len; /* keep ptr[x] and len consistent */ if (cbor_string_copy(item, &v->ptr[i]) < 0) { fido_log_debug("%s: cbor_string_copy", __func__); return (-1); } v->len++; return (0); } static int decode_versions(const cbor_item_t *item, fido_str_array_t *v) { v->ptr = NULL; v->len = 0; if (cbor_isa_array(item) == false || cbor_array_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } v->ptr = calloc(cbor_array_size(item), sizeof(char *)); if (v->ptr == NULL) return (-1); if (cbor_array_iter(item, v, decode_version) < 0) { fido_log_debug("%s: decode_version", __func__); return (-1); } return (0); } static int decode_extension(const cbor_item_t *item, void *arg) { fido_str_array_t *e = arg; const size_t i = e->len; /* keep ptr[x] and len consistent */ if (cbor_string_copy(item, &e->ptr[i]) < 0) { fido_log_debug("%s: cbor_string_copy", __func__); return (-1); } e->len++; return (0); } static int decode_extensions(const cbor_item_t *item, fido_str_array_t *e) { e->ptr = NULL; e->len = 0; if (cbor_isa_array(item) == false || cbor_array_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } e->ptr = calloc(cbor_array_size(item), sizeof(char *)); if (e->ptr == NULL) return (-1); if (cbor_array_iter(item, e, decode_extension) < 0) { fido_log_debug("%s: decode_extension", __func__); return (-1); } return (0); } static int decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != aaguid_len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len); return (0); } static int decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_opt_array_t *o = arg; const size_t i = o->len; if (cbor_isa_float_ctrl(val) == false || cbor_float_get_width(val) != CBOR_FLOAT_0 || cbor_is_bool(val) == false) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } if (cbor_string_copy(key, &o->name[i]) < 0) { fido_log_debug("%s: cbor_string_copy", __func__); return (0); /* ignore */ } /* keep name/value and len consistent */ o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE; o->len++; return (0); } static int decode_options(const cbor_item_t *item, fido_opt_array_t *o) { o->name = NULL; o->value = NULL; o->len = 0; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } o->name = calloc(cbor_map_size(item), sizeof(char *)); o->value = calloc(cbor_map_size(item), sizeof(bool)); if (o->name == NULL || o->value == NULL) return (-1); return (cbor_map_iter(item, o, decode_option)); } static int decode_protocol(const cbor_item_t *item, void *arg) { fido_byte_array_t *p = arg; const size_t i = p->len; if (cbor_isa_uint(item) == false || cbor_int_get_width(item) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (-1); } /* keep ptr[x] and len consistent */ p->ptr[i] = cbor_get_uint8(item); p->len++; return (0); } static int decode_protocols(const cbor_item_t *item, fido_byte_array_t *p) { p->ptr = NULL; p->len = 0; if (cbor_isa_array(item) == false || cbor_array_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t)); if (p->ptr == NULL) return (-1); if (cbor_array_iter(item, p, decode_protocol) < 0) { fido_log_debug("%s: decode_protocol", __func__); return (-1); } return (0); } static int parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cbor_info_t *ci = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* versions */ return (decode_versions(val, &ci->versions)); case 2: /* extensions */ return (decode_extensions(val, &ci->extensions)); case 3: /* aaguid */ return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid))); case 4: /* options */ return (decode_options(val, &ci->options)); case 5: /* maxMsgSize */ return (cbor_decode_uint64(val, &ci->maxmsgsiz)); case 6: /* pinProtocols */ return (decode_protocols(val, &ci->protocols)); default: /* ignore */ fido_log_debug("%s: cbor type", __func__); return (0); } } static int fido_dev_get_cbor_info_tx(fido_dev_t *dev) { const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; fido_log_debug("%s: dev=%p", __func__, (void *)dev); if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { fido_log_debug("%s: fido_tx", __func__); return (FIDO_ERR_TX); } return (FIDO_OK); } static int fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[512]; int reply_len; fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, (void *)ci, ms); memset(ci, 0, sizeof(*ci)); if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } return (cbor_parse_reply(reply, (size_t)reply_len, ci, parse_reply_element)); } static int fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) { int r; if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK || (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci) { return (fido_dev_get_cbor_info_wait(dev, ci, -1)); } /* * get/set functions for fido_cbor_info_t; always at the end of the file */ fido_cbor_info_t * fido_cbor_info_new(void) { return (calloc(1, sizeof(fido_cbor_info_t))); } static void free_str_array(fido_str_array_t *sa) { for (size_t i = 0; i < sa->len; i++) free(sa->ptr[i]); free(sa->ptr); sa->ptr = NULL; sa->len = 0; } static void free_opt_array(fido_opt_array_t *oa) { for (size_t i = 0; i < oa->len; i++) free(oa->name[i]); free(oa->name); free(oa->value); oa->name = NULL; oa->value = NULL; } static void free_byte_array(fido_byte_array_t *ba) { free(ba->ptr); ba->ptr = NULL; ba->len = 0; } void fido_cbor_info_free(fido_cbor_info_t **ci_p) { fido_cbor_info_t *ci; if (ci_p == NULL || (ci = *ci_p) == NULL) return; free_str_array(&ci->versions); free_str_array(&ci->extensions); free_opt_array(&ci->options); free_byte_array(&ci->protocols); free(ci); *ci_p = NULL; } char ** fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci) { return (ci->versions.ptr); } size_t fido_cbor_info_versions_len(const fido_cbor_info_t *ci) { return (ci->versions.len); } char ** fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci) { return (ci->extensions.ptr); } size_t fido_cbor_info_extensions_len(const fido_cbor_info_t *ci) { return (ci->extensions.len); } const unsigned char * fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci) { return (ci->aaguid); } size_t fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci) { return (sizeof(ci->aaguid)); } char ** fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci) { return (ci->options.name); } const bool * fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci) { return (ci->options.value); } size_t fido_cbor_info_options_len(const fido_cbor_info_t *ci) { return (ci->options.len); } uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) { return (ci->maxmsgsiz); } const uint8_t * fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) { return (ci->protocols.ptr); } size_t fido_cbor_info_protocols_len(const fido_cbor_info_t *ci) { return (ci->protocols.len); } libfido2-1.3.1/src/io.c000066400000000000000000000127061362326726700145740ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include "fido.h" #include "packed.h" PACKED_TYPE(frame_t, struct frame { uint32_t cid; /* channel id */ union { uint8_t type; struct { uint8_t cmd; uint8_t bcnth; uint8_t bcntl; uint8_t data[CTAP_RPT_SIZE - 7]; } init; struct { uint8_t seq; uint8_t data[CTAP_RPT_SIZE - 5]; } cont; } body; }) #ifndef MIN #define MIN(x, y) ((x) > (y) ? (y) : (x)) #endif static size_t tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; int n; if (d->io.write == NULL || (cmd & 0x80) == 0) return (0); memset(&pkt, 0, sizeof(pkt)); fp = (struct frame *)(pkt + 1); fp->cid = d->cid; fp->body.init.cmd = 0x80 | cmd; fp->body.init.bcnth = (count >> 8) & 0xff; fp->body.init.bcntl = count & 0xff; count = MIN(count, sizeof(fp->body.init.data)); if (count) memcpy(&fp->body.init.data, buf, count); n = d->io.write(d->io_handle, pkt, sizeof(pkt)); if (n < 0 || (size_t)n != sizeof(pkt)) return (0); return (count); } static size_t tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; int n; if (d->io.write == NULL || seq < 0 || seq > UINT8_MAX) return (0); memset(&pkt, 0, sizeof(pkt)); fp = (struct frame *)(pkt + 1); fp->cid = d->cid; fp->body.cont.seq = (uint8_t)seq; count = MIN(count, sizeof(fp->body.cont.data)); memcpy(&fp->body.cont.data, buf, count); n = d->io.write(d->io_handle, pkt, sizeof(pkt)); if (n < 0 || (size_t)n != sizeof(pkt)) return (0); return (count); } int fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) { int seq = 0; size_t sent; fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu", __func__, (void *)d, cmd, buf, count); fido_log_xxd(buf, count); if (d->io_handle == NULL || count > UINT16_MAX) { fido_log_debug("%s: invalid argument (%p, %zu)", __func__, d->io_handle, count); return (-1); } if ((sent = tx_preamble(d, cmd, buf, count)) == 0) { fido_log_debug("%s: tx_preamble", __func__); return (-1); } while (sent < count) { if (seq & 0x80) { fido_log_debug("%s: seq & 0x80", __func__); return (-1); } const uint8_t *p = (const uint8_t *)buf + sent; size_t n = tx_frame(d, seq++, p, count - sent); if (n == 0) { fido_log_debug("%s: tx_frame", __func__); return (-1); } sent += n; } return (0); } static int rx_frame(fido_dev_t *d, struct frame *fp, int ms) { int n; if (d->io.read == NULL) return (-1); n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms); if (n < 0 || (size_t)n != sizeof(*fp)) return (-1); return (0); } static int rx_preamble(fido_dev_t *d, struct frame *fp, int ms) { do { if (rx_frame(d, fp, ms) < 0) return (-1); #ifdef FIDO_FUZZ fp->cid = d->cid; #endif } while (fp->cid == d->cid && fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)); return (0); } int fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) { struct frame f; uint16_t r; uint16_t flen; int seq; if (d->io_handle == NULL || (cmd & 0x80) == 0) { fido_log_debug("%s: invalid argument (%p, 0x%02x)", __func__, d->io_handle, cmd); return (-1); } if (rx_preamble(d, &f, ms) < 0) { fido_log_debug("%s: rx_preamble", __func__); return (-1); } fido_log_debug("%s: initiation frame at %p, len %zu", __func__, (void *)&f, sizeof(f)); fido_log_xxd(&f, sizeof(f)); #ifdef FIDO_FUZZ f.cid = d->cid; f.body.init.cmd = cmd; #endif if (f.cid != d->cid || f.body.init.cmd != cmd) { fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)", __func__, f.cid, d->cid, f.body.init.cmd, cmd); return (-1); } flen = (f.body.init.bcnth << 8) | f.body.init.bcntl; if (count < (size_t)flen) { fido_log_debug("%s: count < flen (%zu, %zu)", __func__, count, (size_t)flen); return (-1); } if (flen < sizeof(f.body.init.data)) { memcpy(buf, f.body.init.data, flen); return (flen); } memcpy(buf, f.body.init.data, sizeof(f.body.init.data)); r = sizeof(f.body.init.data); seq = 0; while ((size_t)r < flen) { if (rx_frame(d, &f, ms) < 0) { fido_log_debug("%s: rx_frame", __func__); return (-1); } fido_log_debug("%s: continuation frame at %p, len %zu", __func__, (void *)&f, sizeof(f)); fido_log_xxd(&f, sizeof(f)); #ifdef FIDO_FUZZ f.cid = d->cid; f.body.cont.seq = seq; #endif if (f.cid != d->cid || f.body.cont.seq != seq++) { fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)", __func__, f.cid, d->cid, f.body.cont.seq, seq); return (-1); } uint8_t *p = (uint8_t *)buf + r; if ((size_t)(flen - r) > sizeof(f.body.cont.data)) { memcpy(p, f.body.cont.data, sizeof(f.body.cont.data)); r += sizeof(f.body.cont.data); } else { memcpy(p, f.body.cont.data, flen - r); r += (flen - r); /* break */ } } fido_log_debug("%s: payload at %p, len %zu", __func__, buf, (size_t)r); fido_log_xxd(buf, r); return (r); } int fido_rx_cbor_status(fido_dev_t *d, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[2048]; int reply_len; if ((reply_len = fido_rx(d, cmd, &reply, sizeof(reply), ms)) < 0 || (size_t)reply_len < 1) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } return (reply[0]); } libfido2-1.3.1/src/iso7816.c000066400000000000000000000026541362326726700153060ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" iso7816_apdu_t * iso7816_new(uint8_t ins, uint8_t p1, uint16_t payload_len) { iso7816_apdu_t *apdu; size_t alloc_len; alloc_len = sizeof(iso7816_apdu_t) + payload_len + 2; /* le1 le2 */ if ((apdu = calloc(1, alloc_len)) == NULL) return (NULL); apdu->alloc_len = alloc_len; apdu->payload_len = payload_len; apdu->payload_ptr = apdu->payload; apdu->header.ins = ins; apdu->header.p1 = p1; apdu->header.lc2 = (payload_len >> 8) & 0xff; apdu->header.lc3 = payload_len & 0xff; return (apdu); } void iso7816_free(iso7816_apdu_t **apdu_p) { iso7816_apdu_t *apdu; if (apdu_p == NULL || (apdu = *apdu_p) == NULL) return; explicit_bzero(apdu, apdu->alloc_len); free(apdu); *apdu_p = NULL; } int iso7816_add(iso7816_apdu_t *apdu, const void *buf, size_t cnt) { if (cnt > apdu->payload_len || cnt > UINT16_MAX) return (-1); memcpy(apdu->payload_ptr, buf, cnt); apdu->payload_ptr += cnt; apdu->payload_len -= (uint16_t)cnt; return (0); } const unsigned char * iso7816_ptr(const iso7816_apdu_t *apdu) { return ((const unsigned char *)&apdu->header); } size_t iso7816_len(const iso7816_apdu_t *apdu) { return (apdu->alloc_len - sizeof(apdu->alloc_len) - sizeof(apdu->payload_len) - sizeof(apdu->payload_ptr)); } libfido2-1.3.1/src/iso7816.h000066400000000000000000000015411362326726700153050ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _ISO7816_H #define _ISO7816_H #include "packed.h" PACKED_TYPE(iso7816_header_t, struct iso7816_header { uint8_t cla; uint8_t ins; uint8_t p1; uint8_t p2; uint8_t lc1; uint8_t lc2; uint8_t lc3; }) PACKED_TYPE(iso7816_apdu_t, struct iso7816_apdu { size_t alloc_len; uint16_t payload_len; uint8_t *payload_ptr; iso7816_header_t header; uint8_t payload[]; }) const unsigned char *iso7816_ptr(const iso7816_apdu_t *); int iso7816_add(iso7816_apdu_t *, const void *, size_t); iso7816_apdu_t *iso7816_new(uint8_t, uint8_t, uint16_t); size_t iso7816_len(const iso7816_apdu_t *); void iso7816_free(iso7816_apdu_t **); #endif /* !_ISO7816_H */ libfido2-1.3.1/src/libfido2.pc.in000066400000000000000000000004621362326726700164400ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/include Name: @PROJECT_NAME@ Description: A FIDO2 library URL: https://github.com/yubico/libfido2 Version: @FIDO_VERSION@ Requires: libcrypto Libs: -L${libdir} -lfido2 Cflags: -I${includedir} libfido2-1.3.1/src/log.c000066400000000000000000000016351362326726700147450ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include "fido.h" #ifndef FIDO_NO_DIAGNOSTIC #ifndef TLS #define TLS #endif static TLS int logging; void fido_log_init(void) { logging = 1; } void fido_log_xxd(const void *buf, size_t count) { const uint8_t *ptr = buf; size_t i; if (!logging) return; fprintf(stderr, " "); for (i = 0; i < count; i++) { fprintf(stderr, "%02x ", *ptr++); if ((i + 1) % 16 == 0 && i + 1 < count) fprintf(stderr, "\n "); } fprintf(stderr, "\n"); fflush(stderr); } void fido_log_debug(const char *fmt, ...) { va_list ap; if (!logging) return; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); fflush(stderr); } #endif /* !FIDO_NO_DIAGNOSTIC */ libfido2-1.3.1/src/packed.h000066400000000000000000000010341362326726700154110ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _PACKED_H #define _PACKED_H #if defined(__GNUC__) #define PACKED_TYPE(type, def) \ typedef def __attribute__ ((__packed__)) type; #elif defined(_MSC_VER) #define PACKED_TYPE(type, def) \ __pragma(pack(push, 1)) \ typedef def type; \ __pragma(pack(pop)) #else #error "please provide a way to define packed types on your platform" #endif #endif /* !_PACKED_H */ libfido2-1.3.1/src/pin.c000066400000000000000000000232431362326726700147510ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" #include "fido/es256.h" static int parse_pintoken(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_blob_t *token = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 2) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } return (fido_blob_decode(val, token)); } static int fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh, const es256_pk_t *pk) { fido_blob_t f; fido_blob_t *p = NULL; cbor_item_t *argv[6]; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if ((p = fido_blob_new()) == NULL || fido_blob_set(p, (const unsigned char *)pin, strlen(pin)) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(5)) == NULL || (argv[2] = es256_pk_encode(pk, 0)) == NULL || (argv[5] = cbor_encode_pin_hash_enc(ecdh, p)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); fido_blob_free(&p); free(f.ptr); return (r); } static int fido_dev_get_pin_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; fido_blob_t *aes_token = NULL; unsigned char reply[2048]; int reply_len; int r; if ((aes_token = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } if ((r = cbor_parse_reply(reply, (size_t)reply_len, aes_token, parse_pintoken)) != FIDO_OK) { fido_log_debug("%s: parse_pintoken", __func__); goto fail; } if (aes256_cbc_dec(ecdh, aes_token, token) < 0) { fido_log_debug("%s: aes256_cbc_dec", __func__); r = FIDO_ERR_RX; goto fail; } r = FIDO_OK; fail: fido_blob_free(&aes_token); return (r); } static int fido_dev_get_pin_token_wait(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token, int ms) { int r; if ((r = fido_dev_get_pin_token_tx(dev, pin, ecdh, pk)) != FIDO_OK || (r = fido_dev_get_pin_token_rx(dev, ecdh, token, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_get_pin_token(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token) { return (fido_dev_get_pin_token_wait(dev, pin, ecdh, pk, token, -1)); } static int pad64(const char *pin, fido_blob_t **ppin) { size_t pin_len; size_t ppin_len; pin_len = strlen(pin); if (pin_len < 4 || pin_len > 255) { fido_log_debug("%s: invalid pin length", __func__); return (FIDO_ERR_PIN_POLICY_VIOLATION); } if ((*ppin = fido_blob_new()) == NULL) return (FIDO_ERR_INTERNAL); ppin_len = (pin_len + 63) & ~63; if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) { fido_blob_free(ppin); return (FIDO_ERR_INTERNAL); } memcpy((*ppin)->ptr, pin, pin_len); (*ppin)->len = ppin_len; return (FIDO_OK); } static int fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin) { fido_blob_t f; fido_blob_t *ppin = NULL; fido_blob_t *ecdh = NULL; fido_blob_t *opin = NULL; cbor_item_t *argv[6]; es256_pk_t *pk = NULL; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin, (const unsigned char *)oldpin, strlen(oldpin)) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((r = pad64(pin, &ppin)) != FIDO_OK) { fido_log_debug("%s: pad64", __func__); goto fail; } if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(4)) == NULL || (argv[2] = es256_pk_encode(pk, 0)) == NULL || (argv[3] = cbor_encode_change_pin_auth(ecdh, ppin, opin)) == NULL || (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL || (argv[5] = cbor_encode_pin_hash_enc(ecdh, opin)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); es256_pk_free(&pk); fido_blob_free(&ppin); fido_blob_free(&ecdh); fido_blob_free(&opin); free(f.ptr); return (r); } static int fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin) { fido_blob_t f; fido_blob_t *ppin = NULL; fido_blob_t *ecdh = NULL; cbor_item_t *argv[5]; es256_pk_t *pk = NULL; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if ((r = pad64(pin, &ppin)) != FIDO_OK) { fido_log_debug("%s: pad64", __func__); goto fail; } if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(3)) == NULL || (argv[2] = es256_pk_encode(pk, 0)) == NULL || (argv[3] = cbor_encode_set_pin_auth(ecdh, ppin)) == NULL || (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 5, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); es256_pk_free(&pk); fido_blob_free(&ppin); fido_blob_free(&ecdh); free(f.ptr); return (r); } static int fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin, int ms) { int r; if (oldpin != NULL) { if ((r = fido_dev_change_pin_tx(dev, pin, oldpin)) != FIDO_OK) { fido_log_debug("%s: fido_dev_change_pin_tx", __func__); return (r); } } else { if ((r = fido_dev_set_pin_tx(dev, pin)) != FIDO_OK) { fido_log_debug("%s: fido_dev_set_pin_tx", __func__); return (r); } } if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: fido_rx_cbor_status", __func__); return (r); } return (FIDO_OK); } int fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin) { return (fido_dev_set_pin_wait(dev, pin, oldpin, -1)); } static int parse_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { int *retries = arg; uint64_t n; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 3) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } *retries = (int)n; return (0); } static int fido_dev_get_retry_count_tx(fido_dev_t *dev) { fido_blob_t f; cbor_item_t *argv[2]; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(1)) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 || fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int fido_dev_get_retry_count_rx(fido_dev_t *dev, int *retries, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; unsigned char reply[512]; int reply_len; int r; *retries = 0; if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, retries, parse_retry_count)) != FIDO_OK) { fido_log_debug("%s: parse_retry_count", __func__); return (r); } return (FIDO_OK); } static int fido_dev_get_retry_count_wait(fido_dev_t *dev, int *retries, int ms) { int r; if ((r = fido_dev_get_retry_count_tx(dev)) != FIDO_OK || (r = fido_dev_get_retry_count_rx(dev, retries, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_get_retry_count(fido_dev_t *dev, int *retries) { return (fido_dev_get_retry_count_wait(dev, retries, -1)); } int cbor_add_pin_params(fido_dev_t *dev, const fido_blob_t *hmac_data, const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, cbor_item_t **auth, cbor_item_t **opt) { fido_blob_t *token = NULL; int r; if ((token = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) { fido_log_debug("%s: fido_dev_get_pin_token", __func__); goto fail; } if ((*auth = cbor_encode_pin_auth(token, hmac_data)) == NULL || (*opt = cbor_encode_pin_opt()) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: fido_blob_free(&token); return (r); } libfido2-1.3.1/src/reset.c000066400000000000000000000014231362326726700153010ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" static int fido_dev_reset_tx(fido_dev_t *dev) { const unsigned char cbor[] = { CTAP_CBOR_RESET }; const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { fido_log_debug("%s: fido_tx", __func__); return (FIDO_ERR_TX); } return (FIDO_OK); } static int fido_dev_reset_wait(fido_dev_t *dev, int ms) { int r; if ((r = fido_dev_reset_tx(dev)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_reset(fido_dev_t *dev) { return (fido_dev_reset_wait(dev, -1)); } libfido2-1.3.1/src/rs256.c000066400000000000000000000100031362326726700150320ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "fido.h" #include "fido/rs256.h" #if OPENSSL_VERSION_NUMBER < 0x10100000L static int RSA_bits(const RSA *r) { return (BN_num_bits(r->n)); } static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { r->n = n; r->e = e; r->d = d; return (1); } static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) { *n = r->n; *e = r->e; *d = r->d; } #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ static int decode_bignum(const cbor_item_t *item, void *ptr, size_t len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(ptr, cbor_bytestring_handle(item), len); return (0); } static int decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg) { rs256_pk_t *k = arg; if (cbor_isa_negint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) return (0); /* ignore */ switch (cbor_get_uint8(key)) { case 0: /* modulus */ return (decode_bignum(val, &k->n, sizeof(k->n))); case 1: /* public exponent */ return (decode_bignum(val, &k->e, sizeof(k->e))); } return (0); /* ignore */ } int rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, k, decode_rsa_pubkey) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } rs256_pk_t * rs256_pk_new(void) { return (calloc(1, sizeof(rs256_pk_t))); } void rs256_pk_free(rs256_pk_t **pkp) { rs256_pk_t *pk; if (pkp == NULL || (pk = *pkp) == NULL) return; explicit_bzero(pk, sizeof(*pk)); free(pk); *pkp = NULL; } int rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len) { if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); memcpy(pk, ptr, sizeof(*pk)); return (FIDO_OK); } EVP_PKEY * rs256_pk_to_EVP_PKEY(const rs256_pk_t *k) { RSA *rsa = NULL; EVP_PKEY *pkey = NULL; BIGNUM *n = NULL; BIGNUM *e = NULL; int ok = -1; if ((n = BN_new()) == NULL || (e = BN_new()) == NULL) goto fail; if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL || BN_bin2bn(k->e, sizeof(k->e), e) == NULL) { fido_log_debug("%s: BN_bin2bn", __func__); goto fail; } if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) { fido_log_debug("%s: RSA_set0_key", __func__); goto fail; } /* at this point, n and e belong to rsa */ n = NULL; e = NULL; if ((pkey = EVP_PKEY_new()) == NULL || EVP_PKEY_assign_RSA(pkey, rsa) == 0) { fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__); goto fail; } rsa = NULL; /* at this point, rsa belongs to evp */ ok = 0; fail: if (n != NULL) BN_free(n); if (e != NULL) BN_free(e); if (rsa != NULL) RSA_free(rsa); if (ok < 0 && pkey != NULL) { EVP_PKEY_free(pkey); pkey = NULL; } return (pkey); } int rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa) { const BIGNUM *n = NULL; const BIGNUM *e = NULL; const BIGNUM *d = NULL; int k; if (RSA_bits(rsa) != 2048) { fido_log_debug("%s: invalid key length", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } RSA_get0_key(rsa, &n, &e, &d); if (n == NULL || e == NULL) { fido_log_debug("%s: RSA_get0_key", __func__); return (FIDO_ERR_INTERNAL); } if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) || (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) { fido_log_debug("%s: invalid key", __func__); return (FIDO_ERR_INTERNAL); } if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) || (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) { fido_log_debug("%s: BN_bn2bin", __func__); return (FIDO_ERR_INTERNAL); } return (FIDO_OK); } libfido2-1.3.1/src/types.h000066400000000000000000000133341362326726700153340ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _TYPES_H #define _TYPES_H #include "packed.h" /* COSE ES256 (ECDSA over P-256 with SHA-256) public key */ typedef struct es256_pk { unsigned char x[32]; unsigned char y[32]; } es256_pk_t; /* COSE ES256 (ECDSA over P-256 with SHA-256) (secret) key */ typedef struct es256_sk { unsigned char d[32]; } es256_sk_t; /* COSE RS256 (2048-bit RSA with PKCS1 padding and SHA-256) public key */ typedef struct rs256_pk { unsigned char n[256]; unsigned char e[3]; } rs256_pk_t; /* COSE EDDSA (ED25519) */ typedef struct eddsa_pk { unsigned char x[32]; } eddsa_pk_t; PACKED_TYPE(fido_authdata_t, struct fido_authdata { unsigned char rp_id_hash[32]; /* sha256 of fido_rp.id */ uint8_t flags; /* user present/verified */ uint32_t sigcount; /* signature counter */ /* actually longer */ }) PACKED_TYPE(fido_attcred_raw_t, struct fido_attcred_raw { unsigned char aaguid[16]; /* credential's aaguid */ uint16_t id_len; /* credential id length */ uint8_t body[]; /* credential id + pubkey */ }) typedef struct fido_attcred { unsigned char aaguid[16]; /* credential's aaguid */ fido_blob_t id; /* credential id */ int type; /* credential's cose algorithm */ union { /* credential's public key */ es256_pk_t es256; rs256_pk_t rs256; eddsa_pk_t eddsa; } pubkey; } fido_attcred_t; typedef struct fido_attstmt { fido_blob_t x5c; /* attestation certificate */ fido_blob_t sig; /* attestation signature */ } fido_attstmt_t; typedef struct fido_rp { char *id; /* relying party id */ char *name; /* relying party name */ } fido_rp_t; typedef struct fido_user { fido_blob_t id; /* required */ char *icon; /* optional */ char *name; /* optional */ char *display_name; /* required */ } fido_user_t; typedef struct fido_cred { fido_blob_t cdh; /* client data hash */ fido_rp_t rp; /* relying party */ fido_user_t user; /* user entity */ fido_blob_array_t excl; /* list of credential ids to exclude */ fido_opt_t rk; /* resident key */ fido_opt_t uv; /* user verification */ int ext; /* enabled extensions */ int type; /* cose algorithm */ char *fmt; /* credential format */ int authdata_ext; /* decoded extensions */ fido_blob_t authdata_cbor; /* raw cbor payload */ fido_authdata_t authdata; /* decoded authdata payload */ fido_attcred_t attcred; /* returned credential (key + id) */ fido_attstmt_t attstmt; /* attestation statement (x509 + sig) */ } fido_cred_t; typedef struct _fido_assert_stmt { fido_blob_t id; /* credential id */ fido_user_t user; /* user attributes */ fido_blob_t hmac_secret_enc; /* hmac secret, encrypted */ fido_blob_t hmac_secret; /* hmac secret */ int authdata_ext; /* decoded extensions */ fido_blob_t authdata_cbor; /* raw cbor payload */ fido_authdata_t authdata; /* decoded authdata payload */ fido_blob_t sig; /* signature of cdh + authdata */ } fido_assert_stmt; typedef struct fido_assert { char *rp_id; /* relying party id */ fido_blob_t cdh; /* client data hash */ fido_blob_t hmac_salt; /* optional hmac-secret salt */ fido_blob_array_t allow_list; /* list of allowed credentials */ fido_opt_t up; /* user presence */ fido_opt_t uv; /* user verification */ int ext; /* enabled extensions */ fido_assert_stmt *stmt; /* array of expected assertions */ size_t stmt_cnt; /* number of allocated assertions */ size_t stmt_len; /* number of received assertions */ } fido_assert_t; typedef struct fido_opt_array { char **name; bool *value; size_t len; } fido_opt_array_t; typedef struct fido_str_array { char **ptr; size_t len; } fido_str_array_t; typedef struct fido_byte_array { uint8_t *ptr; size_t len; } fido_byte_array_t; typedef struct fido_cbor_info { fido_str_array_t versions; /* supported versions: fido2|u2f */ fido_str_array_t extensions; /* list of supported extensions */ unsigned char aaguid[16]; /* aaguid */ fido_opt_array_t options; /* list of supported options */ uint64_t maxmsgsiz; /* maximum message size */ fido_byte_array_t protocols; /* supported pin protocols */ } fido_cbor_info_t; typedef struct fido_dev_info { char *path; /* device path */ int16_t vendor_id; /* 2-byte vendor id */ int16_t product_id; /* 2-byte product id */ char *manufacturer; /* manufacturer string */ char *product; /* product string */ } fido_dev_info_t; PACKED_TYPE(fido_ctap_info_t, /* defined in section 8.1.9.1.3 (CTAPHID_INIT) of the fido2 ctap spec */ struct fido_ctap_info { uint64_t nonce; /* echoed nonce */ uint32_t cid; /* channel id */ uint8_t protocol; /* ctaphid protocol id */ uint8_t major; /* major version number */ uint8_t minor; /* minor version number */ uint8_t build; /* build version number */ uint8_t flags; /* capabilities flags; see FIDO_CAP_* */ }) typedef struct fido_dev { uint64_t nonce; /* issued nonce */ fido_ctap_info_t attr; /* device attributes */ uint32_t cid; /* assigned channel id */ void *io_handle; /* abstract i/o handle */ fido_dev_io_t io; /* i/o functions & data */ } fido_dev_t; #endif /* !_TYPES_H */ libfido2-1.3.1/src/u2f.c000066400000000000000000000437451362326726700146700ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "fido.h" #include "fido/es256.h" #if defined(_MSC_VER) static int usleep(unsigned int usec) { Sleep(usec / 1000); return (0); } #endif static int sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len) { sig->len = *len; /* consume the whole buffer */ if ((sig->ptr = calloc(1, sig->len)) == NULL || fido_buf_read(buf, len, sig->ptr, sig->len) < 0) { fido_log_debug("%s: fido_buf_read", __func__); if (sig->ptr != NULL) { explicit_bzero(sig->ptr, sig->len); free(sig->ptr); sig->ptr = NULL; sig->len = 0; return (-1); } } return (0); } static int x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len) { X509 *cert = NULL; int ok = -1; if (*len > LONG_MAX) { fido_log_debug("%s: invalid len %zu", __func__, *len); goto fail; } /* find out the certificate's length */ const unsigned char *end = *buf; if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf || (x5c->len = (size_t)(end - *buf)) >= *len) { fido_log_debug("%s: d2i_X509", __func__); goto fail; } /* read accordingly */ if ((x5c->ptr = calloc(1, x5c->len)) == NULL || fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) { fido_log_debug("%s: fido_buf_read", __func__); goto fail; } ok = 0; fail: if (cert != NULL) X509_free(cert); if (ok < 0) { free(x5c->ptr); x5c->ptr = NULL; x5c->len = 0; } return (ok); } static int authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount, fido_blob_t *fake_cbor_ad) { fido_authdata_t ad; cbor_item_t *item = NULL; size_t alloc_len; memset(&ad, 0, sizeof(ad)); if (SHA256((const void *)rp_id, strlen(rp_id), ad.rp_id_hash) != ad.rp_id_hash) { fido_log_debug("%s: sha256", __func__); return (-1); } ad.flags = flags; /* XXX translate? */ ad.sigcount = sigcount; if ((item = cbor_build_bytestring((const unsigned char *)&ad, sizeof(ad))) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); return (-1); } if (fake_cbor_ad->ptr != NULL || (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); cbor_decref(&item); return (-1); } cbor_decref(&item); return (0); } static int send_dummy_register(fido_dev_t *dev, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; iso7816_apdu_t *apdu = NULL; unsigned char challenge[SHA256_DIGEST_LENGTH]; unsigned char application[SHA256_DIGEST_LENGTH]; unsigned char reply[2048]; int r; #ifdef FIDO_FUZZ ms = 0; /* XXX */ #endif /* dummy challenge & application */ memset(&challenge, 0xff, sizeof(challenge)); memset(&application, 0xff, sizeof(application)); if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 * SHA256_DIGEST_LENGTH)) == NULL || iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || iso7816_add(apdu, &application, sizeof(application)) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } do { if (fido_tx(dev, cmd, iso7816_ptr(apdu), iso7816_len(apdu)) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { fido_log_debug("%s: usleep", __func__); r = FIDO_ERR_RX; goto fail; } } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); r = FIDO_OK; fail: iso7816_free(&apdu); return (r); } static int key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, int *found, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; iso7816_apdu_t *apdu = NULL; unsigned char challenge[SHA256_DIGEST_LENGTH]; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; unsigned char reply[8]; uint8_t key_id_len; int r; if (key_id->len > UINT8_MAX || rp_id == NULL) { fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__, key_id->len, (const void *)rp_id); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } memset(&challenge, 0xff, sizeof(challenge)); memset(&rp_id_hash, 0, sizeof(rp_id_hash)); if (SHA256((const void *)rp_id, strlen(rp_id), rp_id_hash) != rp_id_hash) { fido_log_debug("%s: sha256", __func__); r = FIDO_ERR_INTERNAL; goto fail; } key_id_len = (uint8_t)key_id->len; if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, 2 * SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (fido_tx(dev, cmd, iso7816_ptr(apdu), iso7816_len(apdu)) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) != 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } switch ((reply[0] << 8) | reply[1]) { case SW_CONDITIONS_NOT_SATISFIED: *found = 1; /* key exists */ break; case SW_WRONG_DATA: *found = 0; /* key does not exist */ break; default: /* unexpected sw */ r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: iso7816_free(&apdu); return (r); } static int parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id, const unsigned char *reply, size_t len) { uint8_t flags; uint32_t sigcount; if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { fido_log_debug("%s: unexpected sw", __func__); return (FIDO_ERR_RX); } len -= 2; if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 || fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) { fido_log_debug("%s: fido_buf_read", __func__); return (FIDO_ERR_RX); } if (sig_get(sig, &reply, &len) < 0) { fido_log_debug("%s: sig_get", __func__); return (FIDO_ERR_RX); } if (authdata_fake(rp_id, flags, sigcount, ad) < 0) { fido_log_debug("%s; authdata_fake", __func__); return (FIDO_ERR_RX); } return (FIDO_OK); } static int do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; iso7816_apdu_t *apdu = NULL; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; unsigned char reply[128]; int reply_len; uint8_t key_id_len; int r; #ifdef FIDO_FUZZ ms = 0; /* XXX */ #endif if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX || rp_id == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } memset(&rp_id_hash, 0, sizeof(rp_id_hash)); if (SHA256((const void *)rp_id, strlen(rp_id), rp_id_hash) != rp_id_hash) { fido_log_debug("%s: sha256", __func__); r = FIDO_ERR_INTERNAL; goto fail; } key_id_len = (uint8_t)key_id->len; if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, 2 * SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || iso7816_add(apdu, cdh->ptr, cdh->len) < 0 || iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } do { if (fido_tx(dev, cmd, iso7816_ptr(apdu), iso7816_len(apdu)) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { fido_log_debug("%s: usleep", __func__); r = FIDO_ERR_RX; goto fail; } } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); if ((r = parse_auth_reply(sig, ad, rp_id, reply, (size_t)reply_len)) != FIDO_OK) { fido_log_debug("%s: parse_auth_reply", __func__); goto fail; } fail: iso7816_free(&apdu); return (r); } static int cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len, fido_blob_t *cbor_blob) { es256_pk_t *pk = NULL; cbor_item_t *pk_cbor = NULL; size_t alloc_len; int ok = -1; /* only handle uncompressed points */ if (ec_point_len != 65 || ec_point[0] != 0x04) { fido_log_debug("%s: unexpected format", __func__); goto fail; } if ((pk = es256_pk_new()) == NULL || es256_pk_set_x(pk, &ec_point[1]) < 0 || es256_pk_set_y(pk, &ec_point[33]) < 0) { fido_log_debug("%s: es256_pk_set", __func__); goto fail; } if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) { fido_log_debug("%s: es256_pk_encode", __func__); goto fail; } if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr, &alloc_len)) != 77) { fido_log_debug("%s: cbor_serialize_alloc", __func__); goto fail; } ok = 0; fail: es256_pk_free(&pk); if (pk_cbor) cbor_decref(&pk_cbor); return (ok); } static int encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len, const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out) { fido_authdata_t authdata; fido_attcred_raw_t attcred_raw; fido_blob_t pk_blob; fido_blob_t authdata_blob; cbor_item_t *authdata_cbor = NULL; unsigned char *ptr; size_t len; size_t alloc_len; int ok = -1; memset(&pk_blob, 0, sizeof(pk_blob)); memset(&authdata, 0, sizeof(authdata)); memset(&authdata_blob, 0, sizeof(authdata_blob)); memset(out, 0, sizeof(*out)); if (rp_id == NULL) { fido_log_debug("%s: NULL rp_id", __func__); goto fail; } if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) { fido_log_debug("%s: cbor_blob_from_ec_point", __func__); goto fail; } if (SHA256((const void *)rp_id, strlen(rp_id), authdata.rp_id_hash) != authdata.rp_id_hash) { fido_log_debug("%s: sha256", __func__); goto fail; } authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT); authdata.sigcount = 0; memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid)); attcred_raw.id_len = htobe16(kh_len); len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) + kh_len + pk_blob.len; ptr = authdata_blob.ptr = calloc(1, authdata_blob.len); fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len); if (authdata_blob.ptr == NULL) goto fail; if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 || fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 || fido_buf_write(&ptr, &len, kh, kh_len) < 0 || fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) { fido_log_debug("%s: fido_buf_write", __func__); goto fail; } if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) { fido_log_debug("%s: fido_blob_encode", __func__); goto fail; } if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); goto fail; } ok = 0; fail: if (authdata_cbor) cbor_decref(&authdata_cbor); if (pk_blob.ptr) { explicit_bzero(pk_blob.ptr, pk_blob.len); free(pk_blob.ptr); } if (authdata_blob.ptr) { explicit_bzero(authdata_blob.ptr, authdata_blob.len); free(authdata_blob.ptr); } return (ok); } static int parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len) { fido_blob_t x5c; fido_blob_t sig; fido_blob_t ad; uint8_t dummy; uint8_t pubkey[65]; uint8_t kh_len = 0; uint8_t *kh = NULL; int r; memset(&x5c, 0, sizeof(x5c)); memset(&sig, 0, sizeof(sig)); memset(&ad, 0, sizeof(ad)); r = FIDO_ERR_RX; /* status word */ if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { fido_log_debug("%s: unexpected sw", __func__); goto fail; } len -= 2; /* reserved byte */ if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 || dummy != 0x05) { fido_log_debug("%s: reserved byte", __func__); goto fail; } /* pubkey + key handle */ if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 || fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 || (kh = calloc(1, kh_len)) == NULL || fido_buf_read(&reply, &len, kh, kh_len) < 0) { fido_log_debug("%s: fido_buf_read", __func__); goto fail; } /* x5c + sig */ if (x5c_get(&x5c, &reply, &len) < 0 || sig_get(&sig, &reply, &len) < 0) { fido_log_debug("%s: x5c || sig", __func__); goto fail; } /* authdata */ if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey, sizeof(pubkey), &ad) < 0) { fido_log_debug("%s: encode_cred_authdata", __func__); goto fail; } if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK || fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK || fido_cred_set_x509(cred, x5c.ptr, x5c.len) != FIDO_OK || fido_cred_set_sig(cred, sig.ptr, sig.len) != FIDO_OK) { fido_log_debug("%s: fido_cred_set", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: if (kh) { explicit_bzero(kh, kh_len); free(kh); } if (x5c.ptr) { explicit_bzero(x5c.ptr, x5c.len); free(x5c.ptr); } if (sig.ptr) { explicit_bzero(sig.ptr, sig.len); free(sig.ptr); } if (ad.ptr) { explicit_bzero(ad.ptr, ad.len); free(ad.ptr); } return (r); } int u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) { const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; iso7816_apdu_t *apdu = NULL; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; unsigned char reply[2048]; int reply_len; int found; int r; #ifdef FIDO_FUZZ ms = 0; /* XXX */ #endif if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) { fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk, cred->uv); return (FIDO_ERR_UNSUPPORTED_OPTION); } if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL || cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) { fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__, cred->type, (void *)cred->cdh.ptr, cred->cdh.len); return (FIDO_ERR_INVALID_ARGUMENT); } for (size_t i = 0; i < cred->excl.len; i++) { if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i], &found, ms)) != FIDO_OK) { fido_log_debug("%s: key_lookup", __func__); return (r); } if (found) { if ((r = send_dummy_register(dev, ms)) != FIDO_OK) { fido_log_debug("%s: send_dummy_register", __func__); return (r); } return (FIDO_ERR_CREDENTIAL_EXCLUDED); } } memset(&rp_id_hash, 0, sizeof(rp_id_hash)); if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id), rp_id_hash) != rp_id_hash) { fido_log_debug("%s: sha256", __func__); return (FIDO_ERR_INTERNAL); } if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 * SHA256_DIGEST_LENGTH)) == NULL || iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 || iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } do { if (fido_tx(dev, cmd, iso7816_ptr(apdu), iso7816_len(apdu)) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { fido_log_debug("%s: usleep", __func__); r = FIDO_ERR_RX; goto fail; } } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); if ((r = parse_register_reply(cred, reply, (size_t)reply_len)) != FIDO_OK) { fido_log_debug("%s: parse_register_reply", __func__); goto fail; } fail: iso7816_free(&apdu); return (r); } static int u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id, fido_assert_t *fa, size_t idx, int ms) { fido_blob_t sig; fido_blob_t ad; int found; int r; memset(&sig, 0, sizeof(sig)); memset(&ad, 0, sizeof(ad)); if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) { fido_log_debug("%s: key_lookup", __func__); goto fail; } if (!found) { fido_log_debug("%s: not found", __func__); r = FIDO_ERR_CREDENTIAL_EXCLUDED; goto fail; } if (fa->up == FIDO_OPT_FALSE) { fido_log_debug("%s: checking for key existence only", __func__); r = FIDO_ERR_USER_PRESENCE_REQUIRED; goto fail; } if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad, ms)) != FIDO_OK) { fido_log_debug("%s: do_auth", __func__); goto fail; } if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0 || fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK || fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) { fido_log_debug("%s: fido_assert_set", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: if (sig.ptr) { explicit_bzero(sig.ptr, sig.len); free(sig.ptr); } if (ad.ptr) { explicit_bzero(ad.ptr, ad.len); free(ad.ptr); } return (r); } int u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) { int nauth_ok = 0; int r; if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) { fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv, (void *)fa->allow_list.ptr); return (FIDO_ERR_UNSUPPORTED_OPTION); } if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) { fido_log_debug("%s: fido_assert_set_count", __func__); return (r); } for (size_t i = 0; i < fa->allow_list.len; i++) { if ((r = u2f_authenticate_single(dev, &fa->allow_list.ptr[i], fa, nauth_ok, ms)) == FIDO_OK) { nauth_ok++; } else if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) { fido_log_debug("%s: u2f_authenticate_single", __func__); return (r); } /* ignore credentials that don't exist */ } fa->stmt_len = nauth_ok; if (nauth_ok == 0) return (FIDO_ERR_NO_CREDENTIALS); return (FIDO_OK); } libfido2-1.3.1/tools/000077500000000000000000000000001362326726700143645ustar00rootroot00000000000000libfido2-1.3.1/tools/CMakeLists.txt000066400000000000000000000023061362326726700171250ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. list(APPEND COMPAT_SOURCES ../openbsd-compat/explicit_bzero.c ../openbsd-compat/strlcpy.c ../openbsd-compat/strlcat.c ) if(WIN32) list(APPEND COMPAT_SOURCES ../openbsd-compat/bsd-getline.c ../openbsd-compat/explicit_bzero_win32.c ../openbsd-compat/getopt_long.c ../openbsd-compat/posix_win.c ../openbsd-compat/readpassphrase_win32.c ) else() list(APPEND COMPAT_SOURCES ../openbsd-compat/readpassphrase.c) endif() add_executable(fido2-cred fido2-cred.c cred_make.c cred_verify.c base64.c util.c ${COMPAT_SOURCES} ) add_executable(fido2-assert fido2-assert.c assert_get.c assert_verify.c base64.c util.c ${COMPAT_SOURCES} ) add_executable(fido2-token fido2-token.c base64.c bio.c credman.c pin.c token.c util.c ${COMPAT_SOURCES} ) target_link_libraries(fido2-cred ${CRYPTO_LIBRARIES} fido2_shared) target_link_libraries(fido2-assert ${CRYPTO_LIBRARIES} fido2_shared) target_link_libraries(fido2-token ${CRYPTO_LIBRARIES} fido2_shared) install(TARGETS fido2-cred fido2-assert fido2-token DESTINATION ${CMAKE_INSTALL_BINDIR}) libfido2-1.3.1/tools/assert_get.c000066400000000000000000000125301362326726700166710ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static fido_assert_t * prepare_assert(FILE *in_f, int flags) { fido_assert_t *assert = NULL; struct blob cdh; struct blob id; struct blob hmac_salt; char *rpid = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&id, 0, sizeof(id)); memset(&hmac_salt, 0, sizeof(hmac_salt)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); if ((flags & FLAG_RK) == 0) r |= base64_read(in_f, &id); if (flags & FLAG_HMAC) r |= base64_read(in_f, &hmac_salt); if (r < 0) errx(1, "input error"); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); if ((flags & FLAG_RK) == 0) { fprintf(stderr, "credential id:\n"); xxd(id.ptr, id.len); } } if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) errx(1, "fido_assert_set: %s", fido_strerr(r)); if (flags & FLAG_UP) { if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_up: %s", fido_strerr(r)); } if (flags & FLAG_UV) { if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); } if (flags & FLAG_HMAC) { if ((r = fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_assert_set_extensions: %s", fido_strerr(r)); if ((r = fido_assert_set_hmac_salt(assert, hmac_salt.ptr, hmac_salt.len)) != FIDO_OK) errx(1, "fido_assert_set_hmac_salt: %s", fido_strerr(r)); } if ((flags & FLAG_RK) == 0) { if ((r = fido_assert_allow_cred(assert, id.ptr, id.len)) != FIDO_OK) errx(1, "fido_assert_allow_cred: %s", fido_strerr(r)); } free(hmac_salt.ptr); free(cdh.ptr); free(id.ptr); free(rpid); return (assert); } static void print_assert(FILE *out_f, const fido_assert_t *assert, size_t idx, int flags) { char *cdh = NULL; char *authdata = NULL; char *sig = NULL; char *user_id = NULL; char *hmac_secret = NULL; int r; r = base64_encode(fido_assert_clientdata_hash_ptr(assert), fido_assert_clientdata_hash_len(assert), &cdh); r |= base64_encode(fido_assert_authdata_ptr(assert, idx), fido_assert_authdata_len(assert, 0), &authdata); r |= base64_encode(fido_assert_sig_ptr(assert, idx), fido_assert_sig_len(assert, idx), &sig); if (flags & FLAG_RK) r |= base64_encode(fido_assert_user_id_ptr(assert, idx), fido_assert_user_id_len(assert, idx), &user_id); if (flags & FLAG_HMAC) r |= base64_encode(fido_assert_hmac_secret_ptr(assert, idx), fido_assert_hmac_secret_len(assert, idx), &hmac_secret); if (r < 0) errx(1, "output error"); fprintf(out_f, "%s\n", cdh); fprintf(out_f, "%s\n", fido_assert_rp_id(assert)); fprintf(out_f, "%s\n", authdata); fprintf(out_f, "%s\n", sig); if (flags & FLAG_RK) fprintf(out_f, "%s\n", user_id); if (hmac_secret) { fprintf(out_f, "%s\n", hmac_secret); explicit_bzero(hmac_secret, strlen(hmac_secret)); } free(hmac_secret); free(cdh); free(authdata); free(sig); free(user_id); } int assert_get(int argc, char **argv) { fido_dev_t *dev = NULL; fido_assert_t *assert = NULL; char pin[1024]; char prompt[1024]; char *in_path = NULL; char *out_path = NULL; FILE *in_f = NULL; FILE *out_f = NULL; int flags = 0; int ch; int r; while ((ch = getopt(argc, argv, "dhi:o:pruv")) != -1) { switch (ch) { case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'o': out_path = optarg; break; case 'p': flags |= FLAG_UP; break; case 'r': flags |= FLAG_RK; break; case 'u': flags |= FLAG_U2F; break; case 'v': flags |= FLAG_UV; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); in_f = open_read(in_path); out_f = open_write(out_path); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); assert = prepare_assert(in_f, flags); dev = open_dev(argv[0]); if (flags & FLAG_U2F) fido_dev_force_u2f(dev); if (flags & FLAG_UV) { r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", argv[0]); if (r < 0 || (size_t)r >= sizeof(prompt)) errx(1, "snprintf"); if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) errx(1, "readpassphrase"); r = fido_dev_get_assert(dev, assert, pin); } else r = fido_dev_get_assert(dev, assert, NULL); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_dev_get_assert: %s", fido_strerr(r)); if (flags & FLAG_RK) { for (size_t idx = 0; idx < fido_assert_count(assert); idx++) print_assert(out_f, assert, idx, flags); } else { if (fido_assert_count(assert) != 1) errx(1, "fido_assert_count: %zu", fido_assert_count(assert)); print_assert(out_f, assert, 0, flags); } fido_dev_close(dev); fido_dev_free(&dev); fido_assert_free(&assert); fclose(in_f); fclose(out_f); in_f = NULL; out_f = NULL; exit(0); } libfido2-1.3.1/tools/assert_verify.c000066400000000000000000000110661362326726700174210ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static fido_assert_t * prepare_assert(FILE *in_f, int flags) { fido_assert_t *assert = NULL; struct blob cdh; struct blob authdata; struct blob sig; char *rpid = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&authdata, 0, sizeof(authdata)); memset(&sig, 0, sizeof(sig)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); r |= base64_read(in_f, &authdata); r |= base64_read(in_f, &sig); if (r < 0) errx(1, "input error"); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); fprintf(stderr, "authenticator data:\n"); xxd(authdata.ptr, authdata.len); fprintf(stderr, "signature:\n"); xxd(sig.ptr, sig.len); } if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); if ((r = fido_assert_set_count(assert, 1)) != FIDO_OK) errx(1, "fido_assert_count: %s", fido_strerr(r)); if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK || (r = fido_assert_set_authdata(assert, 0, authdata.ptr, authdata.len)) != FIDO_OK || (r = fido_assert_set_sig(assert, 0, sig.ptr, sig.len)) != FIDO_OK) errx(1, "fido_assert_set: %s", fido_strerr(r)); if (flags & FLAG_UP) { if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_up: %s", fido_strerr(r)); } if (flags & FLAG_UV) { if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); } if (flags & FLAG_HMAC) { if ((r = fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_assert_set_extensions: %s", fido_strerr(r)); } free(cdh.ptr); free(authdata.ptr); free(sig.ptr); free(rpid); return (assert); } static void * load_pubkey(int type, const char *file) { EC_KEY *ec = NULL; RSA *rsa = NULL; EVP_PKEY *eddsa = NULL; es256_pk_t *es256_pk = NULL; rs256_pk_t *rs256_pk = NULL; eddsa_pk_t *eddsa_pk = NULL; void *pk = NULL; if (type == COSE_ES256) { if ((ec = read_ec_pubkey(file)) == NULL) errx(1, "read_ec_pubkey"); if ((es256_pk = es256_pk_new()) == NULL) errx(1, "es256_pk_new"); if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) errx(1, "es256_pk_from_EC_KEY"); pk = es256_pk; EC_KEY_free(ec); } else if (type == COSE_RS256) { if ((rsa = read_rsa_pubkey(file)) == NULL) errx(1, "read_rsa_pubkey"); if ((rs256_pk = rs256_pk_new()) == NULL) errx(1, "rs256_pk_new"); if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) errx(1, "rs256_pk_from_RSA"); pk = rs256_pk; RSA_free(rsa); } else if (type == COSE_EDDSA) { if ((eddsa = read_eddsa_pubkey(file)) == NULL) errx(1, "read_eddsa_pubkey"); if ((eddsa_pk = eddsa_pk_new()) == NULL) errx(1, "eddsa_pk_new"); if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) errx(1, "eddsa_pk_from_EVP_PKEY"); pk = eddsa_pk; EVP_PKEY_free(eddsa); } return (pk); } int assert_verify(int argc, char **argv) { fido_assert_t *assert = NULL; void *pk = NULL; char *in_path = NULL; FILE *in_f = NULL; int type = COSE_ES256; int flags = 0; int ch; int r; while ((ch = getopt(argc, argv, "dhi:pv")) != -1) { switch (ch) { case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'p': flags |= FLAG_UP; break; case 'v': flags |= FLAG_UV; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1 || argc > 2) usage(); in_f = open_read(in_path); if (argc > 1) { if (strcmp(argv[1], "es256") == 0) type = COSE_ES256; else if (strcmp(argv[1], "rs256") == 0) type = COSE_RS256; else if (strcmp(argv[1], "eddsa") == 0) type = COSE_EDDSA; else errx(1, "unknown type %s", argv[1]); } fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); pk = load_pubkey(type, argv[0]); assert = prepare_assert(in_f, flags); if ((r = fido_assert_verify(assert, 0, type, pk)) != FIDO_OK) errx(1, "fido_assert_verify: %s", fido_strerr(r)); fido_assert_free(&assert); fclose(in_f); in_f = NULL; exit(0); } libfido2-1.3.1/tools/base64.c000066400000000000000000000047111362326726700156170ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int base64_encode(const void *ptr, size_t len, char **out) { BIO *bio_b64 = NULL; BIO *bio_mem = NULL; char *b64_ptr = NULL; long b64_len; int n; int ok = -1; if (ptr == NULL || out == NULL || len > INT_MAX) return (-1); *out = NULL; if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) goto fail; if ((bio_mem = BIO_new(BIO_s_mem())) == NULL) goto fail; BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); BIO_push(bio_b64, bio_mem); n = BIO_write(bio_b64, ptr, (int)len); if (n < 0 || (size_t)n != len) goto fail; if (BIO_flush(bio_b64) < 0) goto fail; b64_len = BIO_get_mem_data(bio_b64, &b64_ptr); if (b64_len < 0 || (size_t)b64_len == SIZE_MAX || b64_ptr == NULL) goto fail; if ((*out = calloc(1, (size_t)b64_len + 1)) == NULL) goto fail; memcpy(*out, b64_ptr, (size_t)b64_len); ok = 0; fail: BIO_free(bio_b64); BIO_free(bio_mem); return (ok); } int base64_decode(char *in, void **ptr, size_t *len) { BIO *bio_mem = NULL; BIO *bio_b64 = NULL; size_t alloc_len; int n; int ok = -1; if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX) return (-1); *ptr = NULL; *len = 0; if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) goto fail; if ((bio_mem = BIO_new_mem_buf((void *)in, -1)) == NULL) goto fail; BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); BIO_push(bio_b64, bio_mem); alloc_len = strlen(in); if ((*ptr = calloc(1, alloc_len)) == NULL) goto fail; n = BIO_read(bio_b64, *ptr, (int)alloc_len); if (n <= 0 || BIO_eof(bio_b64) == 0) goto fail; *len = (size_t)n; ok = 0; fail: BIO_free(bio_b64); BIO_free(bio_mem); if (ok < 0) { free(*ptr); *ptr = NULL; *len = 0; } return (ok); } int base64_read(FILE *f, struct blob *out) { char *line = NULL; size_t linesize = 0; ssize_t n; out->ptr = NULL; out->len = 0; if ((n = getline(&line, &linesize, f)) <= 0 || (size_t)n != strlen(line)) { free(line); /* XXX should be free'd _even_ if getline() fails */ return (-1); } if (base64_decode(line, (void **)&out->ptr, &out->len) < 0) { free(line); return (-1); } free(line); return (0); } libfido2-1.3.1/tools/bio.c000066400000000000000000000142471362326726700153110ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static void print_template(const fido_bio_template_array_t *ta, size_t idx) { char *id = NULL; const fido_bio_template_t *t = NULL; if ((t = fido_bio_template(ta, idx)) == NULL) errx(1, "fido_bio_template"); if (base64_encode(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t), &id) < 0) errx(1, "output error"); printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t)); free(id); } int bio_list(char *path) { char pin[1024]; fido_bio_template_array_t *ta = NULL; fido_dev_t *dev = NULL; int r; if (path == NULL) usage(); if ((ta = fido_bio_template_array_new()) == NULL) errx(1, "fido_bio_template_array_new"); dev = open_dev(path); read_pin(path, pin, sizeof(pin)); r = fido_bio_dev_get_template_array(dev, ta, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_bio_dev_get_template_array: %s", fido_strerr(r)); for (size_t i = 0; i < fido_bio_template_array_count(ta); i++) print_template(ta, i); fido_bio_template_array_free(&ta); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int bio_set_name(char *path, char *id, char *name) { char pin[1024]; fido_bio_template_t *t = NULL; fido_dev_t *dev = NULL; int r; size_t id_blob_len = 0; void *id_blob_ptr = NULL; if (path == NULL) usage(); if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) errx(1, "base64_decode"); if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK) errx(1, "fido_bio_template_set_name: %s", fido_strerr(r)); if ((r = fido_bio_template_set_id(t, id_blob_ptr, id_blob_len)) != FIDO_OK) errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); dev = open_dev(path); read_pin(path, pin, sizeof(pin)); r = fido_bio_dev_set_template_name(dev, t, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_bio_dev_set_template_name: %s", fido_strerr(r)); free(id_blob_ptr); fido_bio_template_free(&t); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } static const char * plural(uint8_t n) { if (n == 1) return ""; return "s"; } static const char * enroll_strerr(uint8_t n) { switch (n) { case FIDO_BIO_ENROLL_FP_GOOD: return "Sample ok"; case FIDO_BIO_ENROLL_FP_TOO_HIGH: return "Sample too high"; case FIDO_BIO_ENROLL_FP_TOO_LOW: return "Sample too low"; case FIDO_BIO_ENROLL_FP_TOO_LEFT: return "Sample too left"; case FIDO_BIO_ENROLL_FP_TOO_RIGHT: return "Sample too right"; case FIDO_BIO_ENROLL_FP_TOO_FAST: return "Sample too fast"; case FIDO_BIO_ENROLL_FP_TOO_SLOW: return "Sample too slow"; case FIDO_BIO_ENROLL_FP_POOR_QUALITY: return "Poor quality sample"; case FIDO_BIO_ENROLL_FP_TOO_SKEWED: return "Sample too skewed"; case FIDO_BIO_ENROLL_FP_TOO_SHORT: return "Sample too short"; case FIDO_BIO_ENROLL_FP_MERGE_FAILURE: return "Sample merge failure"; case FIDO_BIO_ENROLL_FP_EXISTS: return "Sample exists"; case FIDO_BIO_ENROLL_FP_DATABASE_FULL: return "Fingerprint database full"; case FIDO_BIO_ENROLL_NO_USER_ACTIVITY: return "No user activity"; case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION: return "No user presence transition"; default: return "Unknown error"; } } int bio_enroll(char *path) { char pin[1024]; fido_bio_enroll_t *e = NULL; fido_bio_template_t *t = NULL; fido_dev_t *dev = NULL; int r; if (path == NULL) usage(); if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if ((e = fido_bio_enroll_new()) == NULL) errx(1, "fido_bio_enroll_new"); dev = open_dev(path); read_pin(path, pin, sizeof(pin)); printf("Touch your security key.\n"); r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_bio_dev_enroll_begin: %s", fido_strerr(r)); printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); while (fido_bio_enroll_remaining_samples(e) > 0) { printf("Touch your security key (%u sample%s left).\n", (unsigned)fido_bio_enroll_remaining_samples(e), plural(fido_bio_enroll_remaining_samples(e))); if ((r = fido_bio_dev_enroll_continue(dev, t, e, 10000)) != FIDO_OK) { errx(1, "fido_bio_dev_enroll_continue: %s", fido_strerr(r)); } printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); } fido_bio_template_free(&t); fido_bio_enroll_free(&e); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int bio_delete(fido_dev_t *dev, char *path, char *id) { char pin[1024]; fido_bio_template_t *t = NULL; int r; size_t id_blob_len = 0; void *id_blob_ptr = NULL; if (path == NULL) usage(); if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) errx(1, "base64_decode"); if ((r = fido_bio_template_set_id(t, id_blob_ptr, id_blob_len)) != FIDO_OK) errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); read_pin(path, pin, sizeof(pin)); r = fido_bio_dev_enroll_remove(dev, t, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_bio_dev_enroll_remove: %s", fido_strerr(r)); free(id_blob_ptr); fido_bio_template_free(&t); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } static const char * type_str(uint8_t t) { switch (t) { case 1: return "touch"; case 2: return "swipe"; default: return "unknown"; } } void bio_info(fido_dev_t *dev) { fido_bio_info_t *i = NULL; int r; if ((i = fido_bio_info_new()) == NULL) errx(1, "fido_bio_info_new"); if ((r = fido_bio_dev_get_info(dev, i)) != FIDO_OK) { fido_bio_info_free(&i); return; } printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i), type_str(fido_bio_info_type(i))); printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i)); fido_bio_info_free(&i); } libfido2-1.3.1/tools/cred_make.c000066400000000000000000000115311362326726700164430ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static fido_cred_t * prepare_cred(FILE *in_f, int type, int flags) { fido_cred_t *cred = NULL; struct blob cdh; struct blob uid; char *rpid = NULL; char *uname = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&uid, 0, sizeof(uid)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); r |= string_read(in_f, &uname); r |= base64_read(in_f, &uid); if (r < 0) errx(1, "input error"); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); fprintf(stderr, "user name: %s\n", uname); fprintf(stderr, "user id:\n"); xxd(uid.ptr, uid.len); } if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || (r = fido_cred_set_user(cred, uid.ptr, uid.len, uname, NULL, NULL)) != FIDO_OK) errx(1, "fido_cred_set: %s", fido_strerr(r)); if (flags & FLAG_RK) { if ((r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_rk: %s", fido_strerr(r)); } if (flags & FLAG_UV) { if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); } if (flags & FLAG_HMAC) { if ((r = fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); } free(cdh.ptr); free(uid.ptr); free(rpid); free(uname); return (cred); } static void print_attcred(FILE *out_f, const fido_cred_t *cred) { char *cdh = NULL; char *authdata = NULL; char *id = NULL; char *sig = NULL; char *x5c = NULL; int r; r = base64_encode(fido_cred_clientdata_hash_ptr(cred), fido_cred_clientdata_hash_len(cred), &cdh); r |= base64_encode(fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred), &authdata); r |= base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); r |= base64_encode(fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), &sig); if (fido_cred_x5c_ptr(cred) != NULL) r |= base64_encode(fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), &x5c); if (r < 0) errx(1, "output error"); fprintf(out_f, "%s\n", cdh); fprintf(out_f, "%s\n", fido_cred_rp_id(cred)); fprintf(out_f, "%s\n", fido_cred_fmt(cred)); fprintf(out_f, "%s\n", authdata); fprintf(out_f, "%s\n", id); fprintf(out_f, "%s\n", sig); if (x5c != NULL) fprintf(out_f, "%s\n", x5c); free(cdh); free(authdata); free(id); free(sig); free(x5c); } int cred_make(int argc, char **argv) { fido_dev_t *dev = NULL; fido_cred_t *cred = NULL; char prompt[1024]; char pin[1024]; char *in_path = NULL; char *out_path = NULL; FILE *in_f = NULL; FILE *out_f = NULL; int type = COSE_ES256; int flags = 0; int ch; int r; while ((ch = getopt(argc, argv, "dhi:o:qruv")) != -1) { switch (ch) { case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'o': out_path = optarg; break; case 'q': flags |= FLAG_QUIET; break; case 'r': flags |= FLAG_RK; break; case 'u': flags |= FLAG_U2F; break; case 'v': flags |= FLAG_UV; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1 || argc > 2) usage(); in_f = open_read(in_path); out_f = open_write(out_path); if (argc > 1) { if (strcmp(argv[1], "es256") == 0) type = COSE_ES256; else if (strcmp(argv[1], "rs256") == 0) type = COSE_RS256; else if (strcmp(argv[1], "eddsa") == 0) type = COSE_EDDSA; else errx(1, "unknown type %s", argv[1]); } fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); cred = prepare_cred(in_f, type, flags); dev = open_dev(argv[0]); if (flags & FLAG_U2F) fido_dev_force_u2f(dev); r = fido_dev_make_cred(dev, cred, NULL); if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", argv[0]); if (r < 0 || (size_t)r >= sizeof(prompt)) errx(1, "snprintf"); if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) errx(1, "readpassphrase"); r = fido_dev_make_cred(dev, cred, pin); } explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_dev_make_cred: %s", fido_strerr(r)); print_attcred(out_f, cred); fido_dev_close(dev); fido_dev_free(&dev); fido_cred_free(&cred); fclose(in_f); fclose(out_f); in_f = NULL; out_f = NULL; exit(0); } libfido2-1.3.1/tools/cred_verify.c000066400000000000000000000076151362326726700170420ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static fido_cred_t * prepare_cred(FILE *in_f, int type, int flags) { fido_cred_t *cred = NULL; struct blob cdh; struct blob authdata; struct blob id; struct blob sig; struct blob x5c; char *rpid = NULL; char *fmt = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&authdata, 0, sizeof(authdata)); memset(&id, 0, sizeof(id)); memset(&sig, 0, sizeof(sig)); memset(&x5c, 0, sizeof(x5c)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); r |= string_read(in_f, &fmt); r |= base64_read(in_f, &authdata); r |= base64_read(in_f, &id); r |= base64_read(in_f, &sig); if (r < 0) errx(1, "input error"); (void)base64_read(in_f, &x5c); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); fprintf(stderr, "format: %s\n", fmt); fprintf(stderr, "authenticator data:\n"); xxd(authdata.ptr, authdata.len); fprintf(stderr, "credential id:\n"); xxd(id.ptr, id.len); fprintf(stderr, "signature:\n"); xxd(sig.ptr, sig.len); fprintf(stderr, "x509:\n"); xxd(x5c.ptr, x5c.len); } if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || (r = fido_cred_set_authdata(cred, authdata.ptr, authdata.len)) != FIDO_OK || (r = fido_cred_set_sig(cred, sig.ptr, sig.len)) != FIDO_OK || (r = fido_cred_set_fmt(cred, fmt)) != FIDO_OK) errx(1, "fido_cred_set: %s", fido_strerr(r)); if (x5c.ptr != NULL) { if ((r = fido_cred_set_x509(cred, x5c.ptr, x5c.len)) != FIDO_OK) errx(1, "fido_cred_set_x509: %s", fido_strerr(r)); } if (flags & FLAG_UV) { if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); } if (flags & FLAG_HMAC) { if ((r = fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); } free(cdh.ptr); free(authdata.ptr); free(id.ptr); free(sig.ptr); free(x5c.ptr); free(rpid); free(fmt); return (cred); } int cred_verify(int argc, char **argv) { fido_cred_t *cred = NULL; char *in_path = NULL; char *out_path = NULL; FILE *in_f = NULL; FILE *out_f = NULL; int type = COSE_ES256; int flags = 0; int ch; int r; while ((ch = getopt(argc, argv, "dhi:o:v")) != -1) { switch (ch) { case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'o': out_path = optarg; break; case 'v': flags |= FLAG_UV; break; default: usage(); } } argc -= optind; argv += optind; if (argc > 1) usage(); in_f = open_read(in_path); out_f = open_write(out_path); if (argc > 0) { if (strcmp(argv[0], "es256") == 0) type = COSE_ES256; else if (strcmp(argv[0], "rs256") == 0) type = COSE_RS256; else if (strcmp(argv[0], "eddsa") == 0) type = COSE_EDDSA; else errx(1, "unknown type %s", argv[0]); } fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); cred = prepare_cred(in_f, type, flags); if (fido_cred_x5c_ptr(cred) == NULL) { if ((r = fido_cred_verify_self(cred)) != FIDO_OK) errx(1, "fido_cred_verify_self: %s", fido_strerr(r)); } else { if ((r = fido_cred_verify(cred)) != FIDO_OK) errx(1, "fido_cred_verify: %s", fido_strerr(r)); } print_cred(out_f, type, cred); fido_cred_free(&cred); fclose(in_f); fclose(out_f); in_f = NULL; out_f = NULL; exit(0); } libfido2-1.3.1/tools/credman.c000066400000000000000000000120261362326726700161420ustar00rootroot00000000000000/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int credman_get_metadata(fido_dev_t *dev, const char *path) { fido_credman_metadata_t *metadata = NULL; char pin[1024]; int r; if ((metadata = fido_credman_metadata_new()) == NULL) errx(1, "fido_credman_metadata_new"); read_pin(path, pin, sizeof(pin)); r = fido_credman_get_dev_metadata(dev, metadata, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_credman_get_dev_metadata: %s", fido_strerr(r)); printf("existing rk(s): %u\n", (unsigned)fido_credman_rk_existing(metadata)); printf("possible rk(s): %u\n", (unsigned)fido_credman_rk_remaining(metadata)); fido_credman_metadata_free(&metadata); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } static void print_rp(fido_credman_rp_t *rp, size_t idx) { char *rp_id_hash = NULL; if (base64_encode(fido_credman_rp_id_hash_ptr(rp, idx), fido_credman_rp_id_hash_len(rp, idx), &rp_id_hash) < 0) errx(1, "output error"); printf("%02u: %s %s\n", (unsigned)idx, rp_id_hash, fido_credman_rp_id(rp, idx)); free(rp_id_hash); rp_id_hash = NULL; } int credman_list_rp(char *path) { fido_dev_t *dev = NULL; fido_credman_rp_t *rp = NULL; char pin[1024]; int r; if (path == NULL) usage(); if ((rp = fido_credman_rp_new()) == NULL) errx(1, "fido_credman_rp_new"); dev = open_dev(path); read_pin(path, pin, sizeof(pin)); r = fido_credman_get_dev_rp(dev, rp, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_credman_get_dev_rp: %s", fido_strerr(r)); for (size_t i = 0; i < fido_credman_rp_count(rp); i++) print_rp(rp, i); fido_credman_rp_free(&rp); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } static void print_rk(const fido_credman_rk_t *rk, size_t idx) { const fido_cred_t *cred; char *id = NULL; char *user_id = NULL; const char *type; if ((cred = fido_credman_rk(rk, idx)) == NULL) errx(1, "fido_credman_rk"); if (base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id) < 0 || base64_encode(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred), &user_id) < 0) errx(1, "output error"); switch (fido_cred_type(cred)) { case COSE_EDDSA: type = "eddsa"; break; case COSE_ES256: type = "es256"; break; case COSE_RS256: type = "rs256"; break; default: type = "unknown"; break; } printf("%02u: %s %s (%s) %s\n", (unsigned)idx, id, fido_cred_display_name(cred), user_id, type); free(user_id); free(id); user_id = NULL; id = NULL; } int credman_list_rk(char *path, const char *rp_id) { fido_dev_t *dev = NULL; fido_credman_rk_t *rk = NULL; char pin[1024]; int r; if (path == NULL) usage(); if ((rk = fido_credman_rk_new()) == NULL) errx(1, "fido_credman_rk_new"); dev = open_dev(path); read_pin(path, pin, sizeof(pin)); r = fido_credman_get_dev_rk(dev, rp_id, rk, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_credman_get_dev_rk: %s", fido_strerr(r)); for (size_t i = 0; i < fido_credman_rk_count(rk); i++) print_rk(rk, i); fido_credman_rk_free(&rk); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int credman_print_rk(fido_dev_t *dev, const char *path, char *rp_id, char *cred_id) { const fido_cred_t *cred = NULL; fido_credman_rk_t *rk = NULL; char pin[1024]; void *cred_id_ptr = NULL; size_t cred_id_len = 0; int r; if ((rk = fido_credman_rk_new()) == NULL) errx(1, "fido_credman_rk_new"); if (base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) errx(1, "base64_decode"); read_pin(path, pin, sizeof(pin)); r = fido_credman_get_dev_rk(dev, rp_id, rk, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_credman_get_dev_rk: %s", fido_strerr(r)); for (size_t i = 0; i < fido_credman_rk_count(rk); i++) { if ((cred = fido_credman_rk(rk, i)) == NULL || fido_cred_id_ptr(cred) == NULL) errx(1, "output error"); if (cred_id_len != fido_cred_id_len(cred) || memcmp(cred_id_ptr, fido_cred_id_ptr(cred), cred_id_len)) continue; print_cred(stdout, fido_cred_type(cred), cred); goto out; } errx(1, "credential not found"); out: free(cred_id_ptr); cred_id_ptr = NULL; fido_credman_rk_free(&rk); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int credman_delete_rk(fido_dev_t *dev, const char *path, char *id) { char pin[1024]; void *id_ptr = NULL; size_t id_len = 0; int r; if (base64_decode(id, &id_ptr, &id_len) < 0) errx(1, "base64_decode"); read_pin(path, pin, sizeof(pin)); r = fido_credman_del_dev_rk(dev, id_ptr, id_len, pin); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_credman_del_dev_rk: %s", fido_strerr(r)); free(id_ptr); id_ptr = NULL; fido_dev_close(dev); fido_dev_free(&dev); exit(0); } libfido2-1.3.1/tools/extern.h000066400000000000000000000036141362326726700160460ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _EXTERN_H_ #define _EXTERN_H_ struct blob { unsigned char *ptr; size_t len; }; #define TOKEN_OPT "CDILPRSVbcdei:k:n:r" #define FLAG_DEBUG 0x01 #define FLAG_QUIET 0x02 #define FLAG_RK 0x04 #define FLAG_UV 0x08 #define FLAG_U2F 0x10 #define FLAG_HMAC 0x20 #define FLAG_UP 0x40 EC_KEY *read_ec_pubkey(const char *); fido_dev_t *open_dev(const char *); FILE *open_read(const char *); FILE *open_write(const char *); int assert_get(int, char **); int assert_verify(int, char **); int base64_decode(char *, void **, size_t *); int base64_encode(const void *, size_t, char **); int base64_read(FILE *, struct blob *); int bio_delete(fido_dev_t *, char *, char *); int bio_enroll(char *); void bio_info(fido_dev_t *); int bio_list(char *); int bio_set_name(char *, char *, char *); int cred_make(int, char **); int cred_verify(int, char **); int credman_delete_rk(fido_dev_t *, const char *, char *); int credman_get_metadata(fido_dev_t *, const char *); int credman_list_rk(char *, const char *); int credman_list_rp(char *); int credman_print_rk(fido_dev_t *, const char *, char *, char *); int pin_change(char *); int pin_set(char *); int string_read(FILE *, char **); int token_delete(int, char **, char *); int token_info(int, char **, char *); int token_list(int, char **, char *); int token_reset(char *); int token_set(int, char **, char *); int write_ec_pubkey(FILE *, const void *, size_t); int write_rsa_pubkey(FILE *, const void *, size_t); RSA *read_rsa_pubkey(const char *); EVP_PKEY *read_eddsa_pubkey(const char *); int write_eddsa_pubkey(FILE *, const void *, size_t); void print_cred(FILE *, int, const fido_cred_t *); void read_pin(const char *, char *, size_t); void usage(void); void xxd(const void *, size_t); #endif /* _EXTERN_H_ */ libfido2-1.3.1/tools/fido2-assert.c000066400000000000000000000022121362326726700170270ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * Example usage: * * $ echo assertion challenge | openssl sha256 -binary | base64 > assert_param * $ echo relying party >> assert_param * $ head -1 cred >> assert_param # credential id * $ tail -n +2 cred > pubkey # credential pubkey * $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey rs256 * * See blurb in fido2-cred.c on how to obtain cred. */ #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" void usage(void) { fprintf(stderr, "usage: fido2-assert -G [-dhpruv] [-i input_file] [-o output_file] device\n" " fido2-assert -V [-dhpv] [-i input_file] key_file [type]\n" ); exit(1); } int main(int argc, char **argv) { if (argc < 2 || strlen(argv[1]) != 2 || argv[1][0] != '-') usage(); switch (argv[1][1]) { case 'G': return (assert_get(--argc, ++argv)); case 'V': return (assert_verify(--argc, ++argv)); } usage(); /* NOTREACHED */ } libfido2-1.3.1/tools/fido2-cred.c000066400000000000000000000021061362326726700164450ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * Example usage: * * $ echo credential challenge | openssl sha256 -binary | base64 > cred_param * $ echo relying party >> cred_param * $ echo user name >> cred_param * $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param * $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred */ #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" void usage(void) { fprintf(stderr, "usage: fido2-cred -M [-dhqruv] [-i input_file] [-o output_file] device [type]\n" " fido2-cred -V [-dhv] [-i input_file] [-o output_file] [type]\n" ); exit(1); } int main(int argc, char **argv) { if (argc < 2 || strlen(argv[1]) != 2 || argv[1][0] != '-') usage(); switch (argv[1][1]) { case 'M': return (cred_make(--argc, ++argv)); case 'V': return (cred_verify(--argc, ++argv)); } usage(); /* NOTREACHED */ } libfido2-1.3.1/tools/fido2-token.c000066400000000000000000000031661362326726700166570ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static int action; void usage(void) { fprintf(stderr, "usage: fido2-token [-CR] [-d] device\n" " fido2-token -D [-de] -i id device\n" " fido2-token -I [-cd] [-k rp_id -i cred_id] device\n" " fido2-token -L [-der] [-k rp_id] [device]\n" " fido2-token -S [-de] [-i template_id -n template_name] device\n" " fido2-token -V\n" ); exit(1); } static void setaction(int ch) { if (action) usage(); action = ch; } int main(int argc, char **argv) { int ch; int flags = 0; char *device; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'b': case 'c': case 'e': case 'i': case 'k': case 'n': case 'r': break; /* ignore */ case 'd': flags = FIDO_DEBUG; break; default: setaction(ch); break; } } if (argc - optind == 1) device = argv[optind]; else device = NULL; fido_init(flags); switch (action) { case 'C': return (pin_change(device)); case 'D': return (token_delete(argc, argv, device)); case 'I': return (token_info(argc, argv, device)); case 'L': return (token_list(argc, argv, device)); case 'R': return (token_reset(device)); case 'S': return (token_set(argc, argv, device)); case 'V': fprintf(stderr, "%d.%d.%d\n", _FIDO_MAJOR, _FIDO_MINOR, _FIDO_PATCH); exit(0); } usage(); /* NOTREACHED */ } libfido2-1.3.1/tools/pin.c000066400000000000000000000055071362326726700153250ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int pin_set(char *path) { fido_dev_t *dev = NULL; char prompt[1024]; char pin1[1024]; char pin2[1024]; int r; int status = 1; if (path == NULL) usage(); dev = open_dev(path); r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: "); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } if (strcmp(pin1, pin2) != 0) { fprintf(stderr, "PINs do not match. Try again.\n"); goto out; } if ((r = fido_dev_set_pin(dev, pin1, NULL)) != FIDO_OK) { warnx("fido_dev_set_pin: %s", fido_strerr(r)); goto out; } fido_dev_close(dev); fido_dev_free(&dev); status = 0; out: explicit_bzero(pin1, sizeof(pin1)); explicit_bzero(pin2, sizeof(pin2)); exit(status); } int pin_change(char *path) { fido_dev_t *dev = NULL; char prompt[1024]; char pin0[1024]; char pin1[1024]; char pin2[1024]; int r; int status = 1; if (path == NULL) usage(); dev = open_dev(path); r = snprintf(prompt, sizeof(prompt), "Enter current PIN for %s: ", path); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin0, sizeof(pin0), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: "); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } if (strcmp(pin1, pin2) != 0) { fprintf(stderr, "PINs do not match. Try again.\n"); goto out; } if ((r = fido_dev_set_pin(dev, pin1, pin0)) != FIDO_OK) { warnx("fido_dev_set_pin: %s", fido_strerr(r)); goto out; } fido_dev_close(dev); fido_dev_free(&dev); status = 0; out: explicit_bzero(pin0, sizeof(pin0)); explicit_bzero(pin1, sizeof(pin1)); explicit_bzero(pin2, sizeof(pin2)); exit(status); } libfido2-1.3.1/tools/test.sh000077500000000000000000000101071362326726700157010ustar00rootroot00000000000000#!/bin/bash -e # # Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. if [[ "$#" -ne 1 ]]; then echo "usage: test.sh device" 1>&2 exit 1 fi read -p "This script will reset the authenticator at $1, permanently erasing "\ "its credentials. Are you *SURE* you want to proceed (yes/no)? " if [[ "${REPLY}" != "yes" ]]; then exit 1 fi echo "Resetting authenticator... (tap to continue!)" fido2-token -R $1 CRED_PARAM="$(mktemp /tmp/cred_param.XXXXXXXX)" ASSERT_PARAM="$(mktemp /tmp/assert_param.XXXXXXXX)" ASSERT_PUBKEY="$(mktemp /tmp/assert_pubkey.XXXXXXXX)" ES256_CRED="$(mktemp /tmp/es256_cred.XXXXXXX)" ES256_CRED_R="$(mktemp /tmp/es256_cred_r.XXXXXXXX)" cleanup() { echo "Cleaning up..." [[ "${CRED_PARAM}" != "" ]] && rm "${CRED_PARAM}" [[ "${ASSERT_PARAM}" != "" ]] && rm "${ASSERT_PARAM}" [[ "${ASSERT_PUBKEY}" != "" ]] && rm "${ASSERT_PUBKEY}" [[ "${ES256_CRED}" != "" ]] && rm "${ES256_CRED}" [[ "${ES256_CRED_R}" != "" ]] && rm "${ES256_CRED_R}" } trap cleanup EXIT dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 > "${CRED_PARAM}" echo "Boring Relying Party" >> "${CRED_PARAM}" echo "Boring User Name" >> "${CRED_PARAM}" dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 >> "${CRED_PARAM}" echo "Credential parameters:" cat "${CRED_PARAM}" echo "Generating non-resident ES256 credential... (tap to continue!)" fido2-cred -M -i "${CRED_PARAM}" $1 | fido2-cred -V | tee "${ES256_CRED}" echo "Generating resident ES256 credential... (tap to continue!)" fido2-cred -M -r -i "${CRED_PARAM}" $1 | fido2-cred -V | tee "${ES256_CRED_R}" PIN1="$(dd if=/dev/urandom | tr -cd '[:print:]' | fold -w50 | head -1)" PIN2="$(dd if=/dev/urandom | tr -cd '[:print:]' | fold -w50 | head -1)" echo "Setting ${PIN1} as the PIN..." echo -e "${PIN1}\n${PIN1}" | setsid -w fido2-token -S $1 echo "Changing PIN from ${PIN1} to ${PIN2}..." echo -e "${PIN1}\n${PIN2}\n${PIN2}" | setsid -w fido2-token -C $1 echo "" echo "Testing non-resident ES256 credential..." echo "Getting assertion without user presence verification..." dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 > "${ASSERT_PARAM}" echo "Boring Relying Party" >> "${ASSERT_PARAM}" head -1 "${ES256_CRED}" >> "${ASSERT_PARAM}" tail -n +2 "${ES256_CRED}" > "${ASSERT_PUBKEY}" echo "Assertion parameters:" cat "${ASSERT_PARAM}" fido2-assert -G -i "${ASSERT_PARAM}" $1 | fido2-assert -V "${ASSERT_PUBKEY}" echo "Checking that the user presence bit is observed..." ! fido2-assert -G -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" echo "Checking that the user verification bit is observed..." ! fido2-assert -G -i "${ASSERT_PARAM}" $1 | fido2-assert -V -v "${ASSERT_PUBKEY}" echo "Getting assertion _with_ user presence verification... (tap to continue!)" fido2-assert -G -p -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" echo "Getting assertion _with_ user verification..." echo -e "${PIN2}\n" | setsid -w fido2-assert -G -v -i "${ASSERT_PARAM}" $1 | \ fido2-assert -V -v "${ASSERT_PUBKEY}" echo "" echo "Testing resident ES256 credential..." echo "Getting assertion without user presence verification..." dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 > "${ASSERT_PARAM}" echo "Boring Relying Party" >> "${ASSERT_PARAM}" tail -n +2 "${ES256_CRED_R}" > "${ASSERT_PUBKEY}" echo "Assertion parameters:" cat "${ASSERT_PARAM}" fido2-assert -G -r -i "${ASSERT_PARAM}" $1 | fido2-assert -V "${ASSERT_PUBKEY}" echo "Checking that the user presence bit is observed..." ! fido2-assert -G -r -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" echo "Checking that the user verification bit is observed..." ! fido2-assert -G -r -i "${ASSERT_PARAM}" $1 | fido2-assert -V -v "${ASSERT_PUBKEY}" echo "Getting assertion _with_ user presence verification... (tap to continue!)" fido2-assert -G -r -p -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" echo "Getting assertion _with_ user verification..." echo -e "${PIN2}\n" | setsid -w fido2-assert -G -v -r -i "${ASSERT_PARAM}" $1 | \ fido2-assert -V -v "${ASSERT_PUBKEY}" echo "" libfido2-1.3.1/tools/token.c000066400000000000000000000156001362326726700156520ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static void format_flags(char *ret, size_t retlen, uint8_t flags) { memset(ret, 0, retlen); if (flags & FIDO_CAP_WINK) { if (strlcat(ret, "wink,", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, "nowink,", retlen) >= retlen) goto toolong; } if (flags & FIDO_CAP_CBOR) { if (strlcat(ret, " cbor,", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, " nocbor,", retlen) >= retlen) goto toolong; } if (flags & FIDO_CAP_NMSG) { if (strlcat(ret, " nomsg", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, " msg", retlen) >= retlen) goto toolong; } return; toolong: strlcpy(ret, "toolong", retlen); } static void print_attr(const fido_dev_t *dev) { char flags_txt[128]; printf("proto: 0x%02x\n", fido_dev_protocol(dev)); printf("major: 0x%02x\n", fido_dev_major(dev)); printf("minor: 0x%02x\n", fido_dev_minor(dev)); printf("build: 0x%02x\n", fido_dev_build(dev)); format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); } static void print_str_array(const char *label, char * const *sa, size_t len) { if (len == 0) return; printf("%s strings: ", label); for (size_t i = 0; i < len; i++) printf("%s%s", i > 0 ? ", " : "", sa[i]); printf("\n"); } static void print_opt_array(const char *label, char * const *name, const bool *value, size_t len) { if (len == 0) return; printf("%s: ", label); for (size_t i = 0; i < len; i++) printf("%s%s%s", i > 0 ? ", " : "", value[i] ? "" : "no", name[i]); printf("\n"); } static void print_aaguid(const unsigned char *buf, size_t buflen) { printf("aaguid: "); while (buflen--) printf("%02x", *buf++); printf("\n"); } static void print_maxmsgsiz(uint64_t maxmsgsiz) { printf("maxmsgsiz: %d\n", (int)maxmsgsiz); } static void print_byte_array(const char *label, const uint8_t *ba, size_t len) { if (len == 0) return; printf("%s: ", label); for (size_t i = 0; i < len; i++) printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); printf("\n"); } int token_info(int argc, char **argv, char *path) { char *cred_id = NULL; char *rp_id = NULL; fido_cbor_info_t *ci = NULL; fido_dev_t *dev = NULL; int ch; int credman = 0; int r; int retrycnt; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'c': credman = 1; break; case 'i': cred_id = optarg; break; case 'k': rp_id = optarg; break; default: break; /* ignore */ } } if (path == NULL || (credman && (cred_id != NULL || rp_id != NULL))) usage(); dev = open_dev(path); if (credman) return (credman_get_metadata(dev, path)); if (cred_id && rp_id) return (credman_print_rk(dev, path, rp_id, cred_id)); if (cred_id || rp_id) usage(); print_attr(dev); if (fido_dev_is_fido2(dev) == false) goto end; if ((ci = fido_cbor_info_new()) == NULL) errx(1, "fido_cbor_info_new"); if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); /* print supported protocol versions */ print_str_array("version", fido_cbor_info_versions_ptr(ci), fido_cbor_info_versions_len(ci)); /* print supported extensions */ print_str_array("extension", fido_cbor_info_extensions_ptr(ci), fido_cbor_info_extensions_len(ci)); /* print aaguid */ print_aaguid(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); /* print supported options */ print_opt_array("options", fido_cbor_info_options_name_ptr(ci), fido_cbor_info_options_value_ptr(ci), fido_cbor_info_options_len(ci)); /* print maximum message size */ print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); /* print supported pin protocols */ print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), fido_cbor_info_protocols_len(ci)); if ((r = fido_dev_get_retry_count(dev, &retrycnt)) != FIDO_OK) printf("pin retries: undefined\n"); else printf("pin retries: %d\n", retrycnt); bio_info(dev); fido_cbor_info_free(&ci); end: fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int token_reset(char *path) { fido_dev_t *dev = NULL; int r; if (path == NULL) usage(); dev = open_dev(path); if ((r = fido_dev_reset(dev)) != FIDO_OK) errx(1, "fido_dev_reset: %s", fido_strerr(r)); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int token_set(int argc, char **argv, char *path) { char *id = NULL; char *name = NULL; int ch; int enroll = 0; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'e': enroll = 1; break; case 'i': id = optarg; break; case 'n': name = optarg; break; default: break; /* ignore */ } } if (enroll) { if (id && name) return (bio_set_name(path, id, name)); if (!id && !name) return (bio_enroll(path)); usage(); } return (pin_set(path)); } int token_list(int argc, char **argv, char *path) { fido_dev_info_t *devlist; size_t ndevs; const char *rp_id = NULL; int enrolls = 0; int keys = 0; int rplist = 0; int ch; int r; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'e': enrolls = 1; break; case 'k': keys = 1; rp_id = optarg; break; case 'r': rplist = 1; break; default: break; /* ignore */ } } if (enrolls) return (bio_list(path)); if (keys) return (credman_list_rk(path, rp_id)); if (rplist) return (credman_list_rp(path)); if ((devlist = fido_dev_info_new(64)) == NULL) errx(1, "fido_dev_info_new"); if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); for (size_t i = 0; i < ndevs; i++) { const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n", fido_dev_info_path(di), (uint16_t)fido_dev_info_vendor(di), (uint16_t)fido_dev_info_product(di), fido_dev_info_manufacturer_string(di), fido_dev_info_product_string(di)); } fido_dev_info_free(&devlist, ndevs); exit(0); } int token_delete(int argc, char **argv, char *path) { char *id = NULL; fido_dev_t *dev = NULL; int ch; int enroll = 0; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'e': enroll = 1; break; case 'i': id = optarg; break; default: break; /* ignore */ } } if (path == NULL || id == NULL) usage(); dev = open_dev(path); if (id && !enroll) return (credman_delete_rk(dev, path, id)); return (bio_delete(dev, path, id)); } libfido2-1.3.1/tools/util.c000066400000000000000000000136751362326726700155210ustar00rootroot00000000000000/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #ifdef _MSC_VER #include "../openbsd-compat/posix_win.h" #endif #include "extern.h" void read_pin(const char *path, char *buf, size_t len) { char prompt[1024]; int r; r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path); if (r < 0 || (size_t)r >= sizeof(prompt)) errx(1, "snprintf"); if (!readpassphrase(prompt, buf, len, RPP_ECHO_OFF)) errx(1, "readpassphrase"); } FILE * open_write(const char *file) { int fd; FILE *f; if (file == NULL || strcmp(file, "-") == 0) return (stdout); if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0) err(1, "open %s", file); if ((f = fdopen(fd, "w")) == NULL) err(1, "fdopen %s", file); return (f); } FILE * open_read(const char *file) { int fd; FILE *f; if (file == NULL || strcmp(file, "-") == 0) { #ifdef FIDO_FUZZ setvbuf(stdin, NULL, _IONBF, 0); #endif return (stdin); } if ((fd = open(file, O_RDONLY)) < 0) err(1, "open %s", file); if ((f = fdopen(fd, "r")) == NULL) err(1, "fdopen %s", file); return (f); } void xxd(const void *buf, size_t count) { const uint8_t *ptr = buf; size_t i; fprintf(stderr, " "); for (i = 0; i < count; i++) { fprintf(stderr, "%02x ", *ptr++); if ((i + 1) % 16 == 0 && i + 1 < count) fprintf(stderr, "\n "); } fprintf(stderr, "\n"); fflush(stderr); } int string_read(FILE *f, char **out) { char *line = NULL; size_t linesize = 0; ssize_t n; *out = NULL; if ((n = getline(&line, &linesize, f)) <= 0 || (size_t)n != strlen(line)) { free(line); return (-1); } line[n - 1] = '\0'; /* trim \n */ *out = line; return (0); } fido_dev_t * open_dev(const char *path) { fido_dev_t *dev; int r; if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); r = fido_dev_open(dev, path); if (r != FIDO_OK) errx(1, "fido_dev_open %s: %s", path, fido_strerr(r)); return (dev); } EC_KEY * read_ec_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; EC_KEY *ec = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { warnx("EVP_PKEY_get1_EC_KEY"); goto fail; } fail: if (fp) { fclose(fp); } if (pkey) { EVP_PKEY_free(pkey); } return (ec); } int write_ec_pubkey(FILE *f, const void *ptr, size_t len) { EVP_PKEY *pkey = NULL; es256_pk_t *pk = NULL; int ok = -1; if ((pk = es256_pk_new()) == NULL) { warnx("es256_pk_new"); goto fail; } if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("es256_pk_from_ptr"); goto fail; } if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("es256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(f, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: es256_pk_free(&pk); if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } RSA * read_rsa_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; RSA *rsa = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { warnx("EVP_PKEY_get1_RSA"); goto fail; } fail: if (fp) { fclose(fp); } if (pkey) { EVP_PKEY_free(pkey); } return (rsa); } int write_rsa_pubkey(FILE *f, const void *ptr, size_t len) { EVP_PKEY *pkey = NULL; rs256_pk_t *pk = NULL; int ok = -1; if ((pk = rs256_pk_new()) == NULL) { warnx("rs256_pk_new"); goto fail; } if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("rs256_pk_from_ptr"); goto fail; } if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("rs256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(f, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: rs256_pk_free(&pk); if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } EVP_PKEY * read_eddsa_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } fail: if (fp) { fclose(fp); } return (pkey); } int write_eddsa_pubkey(FILE *f, const void *ptr, size_t len) { EVP_PKEY *pkey = NULL; eddsa_pk_t *pk = NULL; int ok = -1; if ((pk = eddsa_pk_new()) == NULL) { warnx("eddsa_pk_new"); goto fail; } if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("eddsa_pk_from_ptr"); goto fail; } if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { warnx("eddsa_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(f, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: eddsa_pk_free(&pk); if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } void print_cred(FILE *out_f, int type, const fido_cred_t *cred) { char *id; int r; r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); if (r < 0) errx(1, "output error"); fprintf(out_f, "%s\n", id); if (type == COSE_ES256) { write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); } else if (type == COSE_RS256) { write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); } else if (type == COSE_EDDSA) { write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); } else { errx(1, "print_cred: unknown type"); } free(id); } libfido2-1.3.1/udev/000077500000000000000000000000001362326726700141675ustar00rootroot00000000000000libfido2-1.3.1/udev/70-u2f.rules000066400000000000000000000077361362326726700162000ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. # this udev file should be used with udev 188 and newer ACTION!="add|change", GOTO="u2f_end" # Yubico YubiKey KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0121|0200|0402|0403|0406|0407|0410", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Happlink (formerly Plug-Up) Security KEY KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Neowave Keydo and Keydo AES KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0|f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660" # HyperSecu HyperFIDO KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e|2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Feitian ePass FIDO, BioPass FIDO2 KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850|0852|0853|0854|0856|0858|085a|085b|085d", TAG+="uaccess", GROUP="plugdev", MODE="0660" # JaCarta U2F KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101|0501", TAG+="uaccess", GROUP="plugdev", MODE="0660" # U2F Zero KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", MODE="0660" # VASCO SecureClick KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a44", ATTRS{idProduct}=="00bb", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Bluink Key KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Thetis Key KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Nitrokey FIDO U2F, Nitrokey FIDO2 KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287|42b1", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Safetech SafeKey KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Google Titan U2F KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Tomu board + chopstx U2F + SoloKeys KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab|a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660" # SoloKeys KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070|50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Trezor KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Infineon FIDO KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Nano S and Nano X KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001|0004", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Kensington VeriMark KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Longmai mFIDO KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660" # eWBM FIDO2 - Goldengate 310, 320, 500, 450 KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a|4c2a|5c2f|f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660" # OnlyKey (FIDO2 / U2F) KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660" LABEL="u2f_end" libfido2-1.3.1/udev/CMakeLists.txt000066400000000000000000000003621362326726700167300ustar00rootroot00000000000000# Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. if(UDEV_RULES_DIR) install(FILES 70-u2f.rules DESTINATION ${UDEV_RULES_DIR}) endif() libfido2-1.3.1/windows/000077500000000000000000000000001362326726700147165ustar00rootroot00000000000000libfido2-1.3.1/windows/build.ps1000066400000000000000000000145441362326726700164520ustar00rootroot00000000000000param( [string]$CMakePath = "C:\Program Files\CMake\bin\cmake.exe", [string]$GitPath = "C:\Program Files\Git\bin\git.exe", [string]$SevenZPath = "C:\Program Files\7-Zip\7z.exe", [string]$GPGPath = "C:\Program Files (x86)\GnuPG\bin\gpg.exe" ) $ErrorActionPreference = "Continue" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # LibreSSL coordinates. New-Variable -Name 'LIBRESSL_URL' ` -Value 'https://ftp.openbsd.org/pub/OpenBSD/LibreSSL' -Option Constant New-Variable -Name 'LIBRESSL' -Value 'libressl-3.0.2' -Option Constant # libcbor coordinates. New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.5.0' -Option Constant New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.5.0' -Option Constant New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' ` -Option Constant # Work directories. New-Variable -Name 'BUILD' -Value "$PSScriptRoot\..\build" -Option Constant New-Variable -Name 'OUTPUT' -Value "$PSScriptRoot\..\output" -Option Constant # Find CMake. $CMake = $(Get-Command cmake -ErrorAction Ignore | Select-Object -ExpandProperty Source) if([string]::IsNullOrEmpty($CMake)) { $CMake = $CMakePath } # Find Git. $Git = $(Get-Command git -ErrorAction Ignore | Select-Object -ExpandProperty Source) if([string]::IsNullOrEmpty($Git)) { $Git = $GitPath } # Find 7z. $SevenZ = $(Get-Command 7z -ErrorAction Ignore | Select-Object -ExpandProperty Source) if([string]::IsNullOrEmpty($SevenZ)) { $SevenZ = $SevenZPath } # Find GPG. $GPG = $(Get-Command gpg -ErrorAction Ignore | Select-Object -ExpandProperty Source) if([string]::IsNullOrEmpty($GPG)) { $GPG = $GPGPath } if(-Not (Test-Path $CMake)) { throw "Unable to find CMake at $CMake" } if(-Not (Test-Path $Git)) { throw "Unable to find Git at $Git" } if(-Not (Test-Path $SevenZ)) { throw "Unable to find 7z at $SevenZ" } if(-Not (Test-Path $GPG)) { throw "Unable to find GPG at $GPG" } Write-Host "Git: $Git" Write-Host "CMake: $CMake" Write-Host "7z: $SevenZ" Write-Host "GPG: $GPG" New-Item -Type Directory ${BUILD} New-Item -Type Directory ${BUILD}\32 New-Item -Type Directory ${BUILD}\64 New-Item -Type Directory ${OUTPUT} New-Item -Type Directory ${OUTPUT}\pkg\Win64\Release\v142\dynamic New-Item -Type Directory ${OUTPUT}\pkg\Win32\Release\v142\dynamic Push-Location ${BUILD} try { if (Test-Path .\${LIBRESSL}) { Remove-Item .\${LIBRESSL} -Recurse -ErrorAction Stop } if(-Not (Test-Path .\${LIBRESSL}.tar.gz -PathType leaf)) { Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz ` -OutFile .\${LIBRESSL}.tar.gz } if(-Not (Test-Path .\${LIBRESSL}.tar.gz.asc -PathType leaf)) { Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz.asc ` -OutFile .\${LIBRESSL}.tar.gz.asc } Copy-Item "$PSScriptRoot\libressl.gpg" -Destination "${BUILD}" & $GPG --list-keys & $GPG -v --no-default-keyring --keyring ./libressl.gpg ` --verify .\${LIBRESSL}.tar.gz.asc .\${LIBRESSL}.tar.gz if ($LastExitCode -ne 0) { throw "GPG signature verification failed" } & $SevenZ e .\${LIBRESSL}.tar.gz & $SevenZ x .\${LIBRESSL}.tar Remove-Item -Force .\${LIBRESSL}.tar if(-Not (Test-Path .\${LIBCBOR})) { Write-Host "Cloning ${LIBCBOR}..." & $Git clone --branch ${LIBCBOR_BRANCH} ${LIBCBOR_GIT} ` .\${LIBCBOR} } } catch { throw "Failed to fetch and verify dependencies" } finally { Pop-Location } Function Build(${OUTPUT}, ${GENERATOR}, ${ARCH}) { if(-Not (Test-Path .\${LIBRESSL})) { New-Item -Type Directory .\${LIBRESSL} -ErrorAction Stop } Push-Location .\${LIBRESSL} & $CMake ..\..\${LIBRESSL} -G "${GENERATOR}" -A "${ARCH}" ` -DCMAKE_C_FLAGS_RELEASE="/Zi" ` -DCMAKE_INSTALL_PREFIX="${OUTPUT}" -DBUILD_SHARED_LIBS=ON ` -DLIBRESSL_TESTS=OFF & $CMake --build . --config Release & $CMake --build . --config Release --target install Pop-Location if(-Not (Test-Path .\${LIBCBOR})) { New-Item -Type Directory .\${LIBCBOR} -ErrorAction Stop } Push-Location .\${LIBCBOR} & $CMake ..\..\${LIBCBOR} -G "${GENERATOR}" -A "${ARCH}" ` -DCMAKE_C_FLAGS_RELEASE="/Zi" ` -DCMAKE_INSTALL_PREFIX="${OUTPUT}" & $CMake --build . --config Release & $CMake --build . --config Release --target install Pop-Location & $CMake ..\.. -G "${GENERATOR}" -A "${ARCH}" ` -DCBOR_INCLUDE_DIRS="${OUTPUT}\include" ` -DCBOR_LIBRARY_DIRS="${OUTPUT}\lib" ` -DCRYPTO_INCLUDE_DIRS="${OUTPUT}\include" ` -DCRYPTO_LIBRARY_DIRS="${OUTPUT}\lib" ` -DCMAKE_INSTALL_PREFIX="${OUTPUT}" & $CMake --build . --config Release & $CMake --build . --config Release --target install "cbor.dll", "crypto-45.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" ` -Destination "examples\Release" } } Function Package-Headers() { Copy-Item "${OUTPUT}\64\include" -Destination "${OUTPUT}\pkg" ` -Recurse -ErrorAction Stop } Function Package-Libraries(${SRC}, ${DEST}) { Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\bin\crypto-45.dll" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\lib\crypto-45.lib" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\lib\fido2.dll" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" -ErrorAction Stop } Function Package-PDBs(${SRC}, ${DEST}) { Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\Release\vc142.pdb" ` "${DEST}\crypto-45.pdb" -ErrorAction Stop Copy-Item "${SRC}\${LIBCBOR}\src\cbor_shared.dir\Release\vc142.pdb" ` "${DEST}\cbor.pdb" -ErrorAction Stop Copy-Item "${SRC}\src\fido2_shared.dir\Release\vc142.pdb" ` "${DEST}\fido2.pdb" -ErrorAction Stop } Function Package-Tools(${SRC}, ${DEST}) { Copy-Item "${SRC}\tools\Release\fido2-assert.exe" ` "${DEST}\fido2-assert.exe" -ErrorAction stop Copy-Item "${SRC}\tools\Release\fido2-cred.exe" ` "${DEST}\fido2-cred.exe" -ErrorAction stop Copy-Item "${SRC}\tools\Release\fido2-token.exe" ` "${DEST}\fido2-token.exe" -ErrorAction stop } Push-Location ${BUILD}\64 Build ${OUTPUT}\64 "Visual Studio 16 2019" "x64" Pop-Location Push-Location ${BUILD}\32 Build ${OUTPUT}\32 "Visual Studio 16 2019" "Win32" Pop-Location Package-Headers Package-Libraries ${OUTPUT}\64 ${OUTPUT}\pkg\Win64\Release\v142\dynamic Package-PDBs ${BUILD}\64 ${OUTPUT}\pkg\Win64\Release\v142\dynamic Package-Tools ${BUILD}\64 ${OUTPUT}\pkg\Win64\Release\v142\dynamic Package-Libraries ${OUTPUT}\32 ${OUTPUT}\pkg\Win32\Release\v142\dynamic Package-PDBs ${BUILD}\32 ${OUTPUT}\pkg\Win32\Release\v142\dynamic Package-Tools ${BUILD}\32 ${OUTPUT}\pkg\Win32\Release\v142\dynamic libfido2-1.3.1/windows/libressl.gpg000066400000000000000000000400511362326726700172340ustar00rootroot00000000000000 T}u=!`'=Ca5A ]`\\1z`s Fm9NYFG1:?s R/!Hj993v4VQ!Ev2oT8n\5u"}" DfǢ/ܝaWkKtFJ$PX75 q-WGټDbƤ3+!굑e*b#/(FؘR}/nVn:sО(h&-bWUW C]+KvW}G$/OHWs!"sהA^/*JkT=@:H9.5̨t O!*bRPGn&cAT=fYH{EӾ>xDj*wDLKaqR)r-j $VS5#ӹ  s iĖ;f"TŬK^ }d91 8W  Brent Cook V ÑDGZ"!" M8Vz6qӉJKAN A9|"O/O8zHu ĎfqR^zNTnT;Ah^֍r?tR6sFS~KxW5V8ccvewWf=y%^fj8f_ S1RC`{X:gj9x@-d6IJ j'&,=n`XE95EAQU [3 >y1*0f|#Ēgpp%0b߿s#m0p^JJѡO&aikgefkJ߿h.!Do 0f_FӚ|2iX(V9#lU,<8ue:+xyVL=a]$|c 9}IUv!$pvDء{9=sA`B+>/`g^_q~nBeZ[DCU[ݒ3hX|- 9`$|*K7}9g9'ZKf$<4N KkƗB4c]i#MSl.z8LՓ]Brk! fin Uʛ sf,ULC$xv|?OykuKN N":n6e6 F#h?&) V-!*Y.Y:ui:'fWm1[fdA 4VHX3=:*7H:UWEЈ !$H7w 2]EoYM{>P\`1tShln |׳ěd>EAa]1؛.Dзb Tϴ_X*z c!dU%mOrtN!Ȏ WS̋-er gu]l(:61:<-KX ,g=DѲA4 #$dTz|"@嚳xrA]s7W_& Ėa?atd P]E4m6&/ 8vυ@G'1_o''| cC| -s9 GדLMu鐈Nta?3Nmb)[OEWۉIoekIM4k'wٜRe WwD?׫VC`oE=3Ka`B2|o8BЦ9;qynEilt')+ռpBdg9CX!tj2L]oːYE6aJ|FnBƤ[FF 9\,0gײj1h_^)_)>=Hy =j΃0 t"bgϛ: ̫ JƽֵgѩvK N{D*+ !WB9>C`鴚zXFP JQ^ky1}B2* i`@#B'kp8 -~ 2:X6Q>(  XB(i  f:խm'P7~ݵ,]WV|V3WPPv 2YqK0&ex +WFgަQ9K#]`L9CmՈ,T\pRMXF  D *6I+S~-xD5x*,&4 l܇zf/ѡSDM9|No<Kzb @).L2q7xtu斝j0'&Hƛ_p,m6'31N=դKlȹ>Hl%U Wφr` u7o]]Z=hjbSTG Qy6oo,D&OZYDGv.+HdE)9*MCB0X U< ;~[8LLg6-lja*,:BX>(T} g   f:}aG/-f~\ЦsѥD +.-P&gOCV-ʆ\slTBZyƈ3҅5"Ii/U!.?eǿ,l$\h@P$:tpNw7 ;_MvQty eVD^ ㈤iR$_O[Ow\,+mc?)eC&J!*(w) H}P]|BǤ.6Cn(-7;2& (j2gb_C~ָاܔ?˵C)U\ }jvPB1e/ɰHfʹcJC ŝ`< Emd|av NbBX6B?[4ſד[ڂWdKuG y~gȸtD/53_- ؾߍZp^@ pNr<$V ʁ+hom'&~t@]+]Nk^"U?  !>+N19f:\s I f:Ֆ9M7Vt͋;;2XJ{wMR#9+!d `R B`c%8X# _zf͝B\U: <%.jȴg BPR9cp̈́0D8ˋzes&(QBܠ~'> -lAw4i^ sҳv,4 !8b}zN6v}fjziCKFd{dE^l9U^})w6f;B ڳ~ П7{OHʋ[?;\ٝ+LR'" `2쮛j5/lur?@鰑ϛI x+ppF!נޓ~{?`-\^'F7V+<)6LVp蕇f 袲rCWA5‘c<( B}o^_]KHNLY 8 2J˪<ά Z`7u`9-r?e0]^BBrent Cook V ÑDGZ"Mo*~)7á!zfMRR06{99hҨCk@ϙ40:-$c^' iNrzr O _d] q@"'tGM`oŁaMb{U0 MxBKJD!l" oR)sM?iu=՜8#ϜWr_ynQMH!Z^[|(E(?:r[HnRN:(Ba'Gnn, fHU [3 >j(mb(g5J >\u/Z-XX:(g(j7IthFbՒh |K F?Uˣoa@ igb*E9IYLfy%W9(]ji%߂,__zN &åoA'C]2WlՄ=E&7Mm}bSl;07ӕj{P"w75:)0G\-~a(0!` $D0 :0ntfPYD{db=k4fj헲<S`(bu+.Rk~`l$0M6۳w|. M0Y OXw%] TRʆo|lV e3g{Æ凓M_KfoD/OX'Fsq3@ FZ=s:[&3TxO;whУmvE| ͯ_ZWExj5Al1{GJVW}" YC'bK FI,1M)%Ul%"&D >CZ2JC!sdu:=T:@cj@VbffA:#clޞ9 W]kC1fD6/;;R#~]%yjZ$Hμ.a wqTr7p4\=4 W'&-D:"RAd,!qH~.un1o"GqlrǴg/}QMf$<%jZ;{$> q ܼ4cnS I?A/]/͠20JqLǥnC}Zʌѓi'9N֣866E2Flq{YmJ m3ZƺcQlL-,9;&ŭ, EwxG/-FE%,i2UaU (C[ƧL5$8Q(  XB(Z  f:XQp wq>E8I$pfy>|.TErq '|,G:(V8]Q59jW})doeUszR@xU>@ED/F6/F$wc-h7@f& _.8Ni]j4}O7aua}cG龗ep"l@j-zZ*d#ATxV87j=*GK޴;UR" bQz;|N@lW-F otwG|h0Ac%8# Aj,{I4fm7-Xtk?w10Nm|ZQϾiY'r50|Jd" .F3+Nϻe@> T&2_jGIx[s‚E61U0T8y4LO]u%)pIr^=?ņLL.װ.۞Ц ,M|2:" x`>(T g   f:j!_ c3*w:ͰhqԦWCS Ͳ }%NϏA}V&s1H[Ղ2)IlNwa&eF$uaвnF#R^e;뉈S h #RAmfΚ%}4Ui~]6z|x1X2bFX)QckiKtܠhWR+A?oOc9LlwiL4b1@2϶ 4ɛ&VEGѳ)4<Y=T xbU?E_Fs  MSIR'YJJ`_r zaȰma"31~$]sng0cd؅(7>2yr0p"OK32)mqŸ`& \!+ 0 hOlT.܈VW#{ch/P]/I;XJN󳛪RU?  !>+N19f:\s I f:agfmݠf$'⃔HP[ѫߞ^.=ǘ5e.U sk{P@CE9lB<#mc/3QW0=mΘ,&Y+a ^3 O>6hʇ8VVVv5|mۀQjq7s~W|ET.gW4QۃDKՙZq "*{*X=۝_#[0C{R3D V ÑDGZ"MpXCB.a!f ܲ_ X@~>nOC{+Xu/JN7rq1&xo;8I_mc3OTY_sxY|0fm\X8e Wޱ60ޗr "t7m ZJ=1~ɘXipC?(:8,Lrgn,jsʕԋN? ->'G  ScWu9F* -[{TO헭-"׫[R;`Ⱦ1{xx I~=\hI'0-Bbq`@ 9`+ x@ޖ,q:k7)gOQ~)NT؆fi{G h3#\(V=*HȧC:]7: %69d+/^eIܚ$A Y5S}r̔Zgv%Mx畤jݷvӛ8\>yQ[2%9BSK="roYdtL$G&vkO[6c;=qI?q(]^IX wTu@)́6y;p@G*${? G?q™AYc'W}" YC_e>+!ZE!#[2by wu&kL(fie[XDM/lF,GG}շhAp1qǙI?WG(X2oIXHP'`_G,K@-T J )FԗPn,&!eII 7Oߵ̸QgۥeƋy'w1١ 渄O *Q 7ɥDj"",P֣2 ks2pg|﫝EW 4MZHwb~dK\VO^멉܄N`CCˇ/\(8fV9$TC Vŷ'8Yfder&ʯӀY\/t jԩlgpaܿ ʜ ʁ %J7 /~O@ dR'=%ɿ1BO~P (^@o7#Ĝ@cCn0icrM0 uN+E>JJXuH~un'>(  XB(i  f:(>!1 &{lr&k1Up4 ?-žKFK$z|w V}Cgͤ{W? $bRVfhBªwo rDW ?3̨|nN`#ks2*=1j{,f~߷C&5L FD N^da`Z{_)aM8O[#)Wذm-nKf5] \X~,יaJw{Z H}NU^)[&ni59yE>obLl|ֳb)@s"\L&`\d,UD|c,MM6 RDuV[\^}=jʇo>MWIS*̎ڭmlI.2K:- +%x 7eA3HEu>۹]@ȔF`݂OUSQ˥cΉ>(TD g   f:S7 (JTA^jnox]ic1cI< R0aNUd8WNؽpTh3u:g[Gǔ zG.%j =EDo)'ٜYgwC'c:K )Zw ɍCMZxwAMʴ;pO;DJˍU ^a cLێ0#Uj஢Uŋh: KxGNxKS؏&$uxC6Է|Ca 00J8]`O7L2'#4exlBUA,;5itq4I>q\9h 3? utto#'ܯ=?0l8LVJdҋ4VI!JB pOI !I [A6Oa E3>~!85j_6տ I#6F0!-eU?  !>+N19f:\s I f:{L֍(60_ F0nzEj]np5Jo@MÍ-Sn\2( rMuS;Qf'pfFC^65|))Y%篢 GKힰ"ym%eUm|)K`BC֑CZY Lb'-nw6JkB`F^X<0tx)XRmk?SSٸf#nVQaUnw*he!7q{2My `[``_3k+e O|sRBȲ fbk55X9A* "$isL\ZbJ=߂b{|i#O?T`aiטR{ۿ7V ÑDGZ"5EH'C1c`/@M9EgB9XC\E?t;xɴu+F.^:GhS 5/;3gjz0Sr2oMHeLqBB4R'LDrP%;+10,Rr&kǧ(O>iE9J{\GΣ>\˜b|QSyey5V9^`|p1!Ba96ʵdg^L;,neM0;Oۃg)$دvDl%YSlҡ:ӻ-] 6y3&W5ocWL:D//nC=mU 8-e&iV,y7zI;~?7D[zhP3J"љ:9n(!5.\gc;46Hg&+2%u~,(6/̐q9Salwa& 6قHl,#꬜٩'E,lݵ_TvZL"m)o|i8,1"3%jE0f.88KuE?=,`Skd^-q};WboUw8JAKvaqW}" YC WOA;bO0U@:I7:+n4$^UBK;r搬fS[O}bS}F|fVImEN‹Yj}z;bx" %<9g܁ m%֢gXL*X)hOf rfDѦ)<\k}WvonBdmH_,FxۺQ&߯4_n0Z,_G7sdj'kK *q٨`bi 5Dt!wp-23ǁ*ӬnWgBxO uƀ^E,X>om1{6V1ͦP+s`Т^6խ;`fWw񉛖1sgoК$LJTUGB(;%NӲd_;0*Y3g8d+5#̺"$: 3J:,prN(y͉- T}   f:!s'9yrR LcZItvq֝ oѾ«G[/M#1T EնM 0_UFsjW9p+7tP+E'Zc9^R(&.~k B[HU: RY.CXaPQ3p= Pk2`0V/9q8xWGDv@`G>'9٤G\-`?Uhd,_k+*A|99,@?٠PN®fBU$-˧2'jfa?5ta_8b10D+ٰj R"|ŷ1HzqXd "H8z Są)K`Qw2%j`90Rɉ^N;oAͶL8=yI͆33   XB(i  f:[>(ZMBMzt[DD RGPl +N19f:\s I f:I!@zj!drlv $h$rξߒs0a!-YQGOR6ޥ%,'.&kG*b$`'o /&q‰!UJLp#Dn5=2r#AmNddJ\vD _,̨ ̠!ˈLKaಞ[Ŏ_BV}M]K Y#K=CI;ՙ" d-ƅC'")*F%QPooA\ܪhf5+f'SirJ!23D̉k`E o|f | PȖ6 A6m}T{up}hS_EG>dzX4jlB*FnArYgWgf/C!rL4NJ uqq8&"flb7fnYyF%r3gb~!JEYET*Q!ž)rW=+ IC2Usr {2\姦 "8 7}L(p]M;8v ƖmtPa-uRtW @BK\pQ"iwT fe&x`GVM*aVNNǯaU o4r|x/?7.G&.uz- Šh}]<& !>+N19f:\s I+ f: m£=TGvʱqXŁ},aV(Sב l<܅"xsNL/Ob˳@콾;臐8i%" / -^~W4Yx5x/%Ituၡ^Na?t(j ;m*|'ʇ^B t4#*z] gUstȜ r5/o4|ӏA&+àB"8zL@5*TgUb > UK-2zÌVm?۔{"J&k31 -`0eTS >" h*68 3d,)쮨ԅ\ɯy} ./{]zFUUVfkF)WvѦɩ"̥̾+ܪtu}d(_ATWzDmழ`_gh; KՋ,'m8*hVCy])/pqtlnҔDY TNmA$B#(׊}Re~ ^yV[o׎1=`omSvgeb-/]g\3uw w{Ւ(,Ԗ$ 4Y GVmiC`yqe&1. O P.) Zf4hE[Ьsrsdhd-(1bWhluq#7fwc X0MqZ&-2ʐHIR7Ȃ&P^.{]ǙKˤV\z{lu 3A[3"WR:r}Zdˇܵ,\ d}IU- ' j[B_u;LgU׽h>誌Kmo@Olts L@ݗ_TiICۊfzOrlу{x2V8S<-K$-dB;5ל/~YroMMXo:|ṕ'A࠙hSoQU|Z X![&!>+N19f:\s p)] TNm Kpo6y<XB VZH31*\ndkh3u<%4J /?UlTFȺDیHXrR гQS#?~T8S⣃[ig0\Ƭ 6Hgq8$m?A pNV'!"8Bf~?o)o<- x47w$OQ6Ы K*8HX:%/´[VN@ˠ٭V6rK-(Njεכiod OkVA{!^R0Ov6T#}:7)PXBqMY(Y֌X0{]䓚E8&s<#Zcu@ )q'܎Htf(aQxu}-hԻ\6G& sQܙNs:]_[Wv+)