trousers-0.3.15/0000775000175000017510000000000013750250507012747 5ustar deboradeboratrousers-0.3.15/Makefile.am0000664000175000017510000000031113663651711015003 0ustar deboradeboraSUBDIRS = src man dist EXTRA_DIST = AUTHORS LICENSE NEWS NICETOHAVES README \ README.selinux TODO ChangeLog \ doc/LTC-TSS_LLD_08_r2.pdf \ doc/LTC-TSS_LLD_08_r2.sxw \ doc/TSS_programming_SNAFUs.txt trousers-0.3.15/ChangeLog0000664000175000017510000012413413750246207014530 0ustar deboradebora* TROUSERS_0_3_15 - Corrected mutliple security issues that existed if the tcsd is started by root instead of the tss user. CVE-2020-24332, CVE-2020-24330, CVE-2020-24331 - Replaced use of _no_optimize with asm memory barrier - Fixed multiple potential instances of use after free memory handling - Removed unused global variables which caused build issue on some distros * TROUSERS_0_3_14 - Changes to support OpenSSL 1.1.0 - Removed some warnings for proper builds - Changes to allow building on OS X - Fixed memory leaks - Fixed failure to recognize connections from localhost over IPv6 - Fixed for an exploitable local denial of service in tcsd * TROUSERS_0_3_13 - Changed exported functions which had a name too common, to avoid collision - Assessed daemon security using manual techniques and coverit - Fixed major security bugs and memory leaks - Added debug support to run tcsd with a different user/group - Daemon now properly closes sockets before shutting down * TROUSERS_0_3_12 - Added new network code for RPC, which supports IPv6 - Users of client applications can configure the hostname of the tcsd server they want to connect through the TSS_TCSD_HOSTNAME env var (only works if application didn't set a hostname in the context) - Added disable_ipv4 and disable_ipv6 config options for server * TROUSERS_0_3_11 - Fix build process for distros - License was changed from GPL to BSD - Many bugfixes - updated man pages * TROUSERS_0_3_8 - Fix ssl_ui.c overflow - Handling of TPM_CERTIFY_INFO2 structure special case - Fix possible obfuscation of obj_migdata.c errors. - Make 1.2 keys respect the TPM_PCRIGNOREDONREAD flag. - PCRInfo member allocation in Trspi_Unload_CERTIFY_INFO. - Add functions for deserializing NVRAM related data structures - Add NVRAM specific error messages - Fix spec file so one can build an rpm - Initialize the tcsd_config_file with NULL. - support for -c command line option - Establish a .gitignore file - ENDIAN_H and htole definition fix * TROUSERS_0_3_7 - __tspi_freeTable wrong call - Owner Evict pubkey setup fix - The "HAVE_ENDIAN_H" check is missing from configure.in, but it appears to be needed in a couple of the source files. - tspi_context.c fix (memleak) - Added the missing setup of a tcs handle for owner evict keys. - No need to initialize the flock structure. - flock to fcntl change - Fixed cleanup code in svrside.c - Avoid warning of missing return in tcsd_thread_run() - printf() warning fix - Moved hDAA debug message after initialization - Additional length check - Tspi_NV_DefineSpace secret check fix * TROUNSERS_0_3_6 - Fixed a number of warnings during a build with --debug regarding THREAD ID definition - Removed htole() dependency, which was included only in glibc 2.9 * TROUSERS_0_3_5 - Allowed TCD Daemon to run with reduced privileges In Solaris. - Fixing previous kfreebsd build patch conflict with the current tree. - TCSD error handling improvements. - mutex init inclusion. - pthread_t portability fix - Owner Evict keys load fix. - Big- endian issues. - Memory leak fix. - Adding missing #include . - kfreebsd build fixes. - Fixed usage of syslog(). - 64bits clean - Fixes the TCP UN and IN socket connection attempt handling - Fixes logic on opening a hardware TPM. - Added communication through TCP to software TPMs in TrouSerS. - Fixed conflicting defines - Adds missing free() - Fixed fread() return value check. - Made the previous fix cleaner and more robust. - Added missing check in order to avoid freeing buffer that's out of Tspi_Data_Seal() scope. - Fixed Tspi_TPM_GetRandom 4kb output limit. * TROUSERS_0_3_4 - Fixed TrouSerS mishandling of TPM auth sessions - Enabled hosttable.c "_init" and "_fini" functions to work on Solaris - Included Solaris in BSD_CONST definition conditional - Made the init script LSB compliant - make distcheck improved * TROUSERS_0_3_3_2 - Fixed logic when filling up RSA keys objects. * TROUSERS_0_3_3_1 - TCSD now runs as tss and has a better signal handling - Fixed many memory handling issues * TROUSERS_0_3_3 - Tspi_ChangeAuth fixed for popup secret use case. - Prefixed exported functions with common names. - Fixed issues with accessing the utmp database. - Migrated the bios parser file handler from open to fopen. * TROUSERS_0_3_2 - Added IMA log parser in conformance with format introduced in linux kernel 2.6.30 - Fixed memory handling issues in src/tspi/tspi_quote2.c and tspi_tick.c - Fixed memory handling issues in tcs/rpc/tcstp/rpc_tick.c - Fixed logic when releasing auth handles, now the TPM won't become out of resources due too many unreleased auth handles there. - Fixed compilation problems when building trousers in Fedora with -fstack-protector & gcc 4.4 - Fixed the legacy usage of a deprecated 1.1 TPM command, now auth sessions can be closed fine. - Fixed key memory cache when evicting keys, invalid key handles were evicted when shouldn't. - Fixed authsess_xsap_init call with wrong handle - Fixed authsess_callback_hmac return code - Fixed validateReturnAuth return value - Added consistency to avoid multiple double free() and bound checks to avoid SEGV - Moved from flock to fcntl since the first isn't supported in multi-thread applications - Added necessary free() and consistency necessary in tspi/tsp_delegate.c to avoid SEGV - Typecast added in trousers.c in the UNICODE conversion functions - Fixed wrong return code in Tspi_NV_ReleaseSpace - Fixed digest computation in Tspi_NV_ReleaseSpace - Fixed tpm_rsp_parse, it previously checked for an additional TPM_AUTH blob, resulting in a incorrect data blog unload. - Added new OpenSSL UI for TSS_SECRET_MODE_POPUP auth mode. - Added workaround to fix namespace conflict with SELINUX - Set SO_REUSEADDR socket option. - Added TSS_SS_RSASSAPKCS1v15_INFO signature scheme definitions and support - TDDL can now be compiled apart from the rest of TrouSerS. - Added #include to remove INT_MAX undeclared error during build. Files updated: trspi/crypto/openssl/symmetric.c, tspi/tspi_aik.c and tspi/tsp_ps.c - Added bounds checking in the data parsing routines of the TCSD's tcstp RPC code, preventing attacks from malicious clients. - Removed commented out code in src/tcs/rpc/tcstp/rpc.c - Commented out old OSAP code, its now unused - Fixed bug in tcsi_bind.c, one too few params were passed to the function parsing the TPM blob. - Fixed lots of erroneous TSPERR and TCSERR calls - Added support for logging all error return codes when debug is on - Check that parent auth is loaded in the load key path outside the mem_cache_lock, if a thread sleeps holding it, we deadlock - Added support for dynamically growing the table that holds sleeping threads inside the auth manager - In tcs_auth_mgr.c, fixed the release handle path, which didn't check if the handle was swapped out before calling to the TPM. - Updates throughout the code supporting the modular build. * TROUSERS_0_3_1 - Added check of return code for ResetDALock call in tspi_admin - Added missing ordinals in tcs_pbg.c as reported by Phil Carmon. - Added support for DSAP sessions and delegating authorizations! - Added support for DSAP sessions inside a transport session. - Prevent Tspi_TPM_GetCapability from switching the endianess of the data returned from a request for TSS_TPMCAP_NV_LIST when that list happens to be sizeof(UINT32). - Fixed trouble in owner_evict_init path for 1.1 TPMs - Fixed multiple problems with changing auth on encrypted data and keys. - Fix for SF#1811120, Tspi_TPM_StirRandom01 test crashes TCSD. - Fix for SF#1805829, ChangeAuth fails to return an error - Fix for SF#1803767, TSS_TSPATTRIB_KEY_PCR_LONG key attribute not implemented - Fix for SF#1802804, Tspi_TPM_Delegate_UpdateVerificationCount problem - Fix for SF#1799935, Tspi_TPM_Delegate_ReadTables bug - Fix for SF#1799912, policy lifetime counter doesn't reset with SetSecret - Fix for SF#1799901, policy lifetime timer doesn't reset with SetSecret - Fix for SF#1779282. Trspi_UnloadBlob_CERTIFY_INFO DNE. - Fix for setting the right kind of PCR struct in the key object * TROUSERS_REDHAT_SUBMIT - Updated ps_inspect utility to more accurately guess if the file you're inspecting is really a persistent storage file. - Fixed endianess issue with certain TPM get caps - Fixed bug in setting credential data in the TSP - Moved secret hash mode code out from inside spec compliance #defines since they're now part of the 1.2 spec. - Better support for NULL parameters to blob manipulation functions - Fix for regression - blank the SRK pubkey copy stored in system persistent storage - Added RPC plumbing for DSAP sessions - Added support for unmasking data on unseal :-) - Implemented encdata PCR_INFO_LONG GetAttrib's - Overhauled OSAP session handling. * TROUSERS_0_3_0 - Added TSS_TCSCAP_PLATFORM_CLASS cap support - Added the Quote2 Commands - Added new TSS 1.2 return codes to Trspi_Error_String. - Added Tspi_Context_GetRegisteredKeysByUUID2 functions to the persistent storage system - Added Tspi_TPM_OwnerGetSRKPubKey and TCS OwnerReadInternalPub code. - Added support for operator auth and Tspi_TPM_SetOperatorAuth. - Added support for Sealx. - Added ordinal auditing support. - Added initial transport session support. - Rewrote TCSD key loading functions. - Added support for UINT64 loading/unloading everywhere. - Created an initial TCS parameter block generator in tcs_pbg.c. - Added support to get_local_random to either allocate a new buffer for the random number or write it to a given buffer. - Removed TCS GetCredentials APIs -- the TSSWG verified that these had accidentally been left in the spec. - Added TCS GetCredential API. - Added NVRAM APIs, donated by James Xu, and others from Intel. - Added TCS GetCredentials functions - Patched the TCS key loading infrastructure to return TCS_E_INVALID_KEY when a handle is used by a context that doesn't have a reference to the key in its keys_loaded list. - Added ASN.1 blob encoding and decoding APIs. - Added tick stamping APIs - Added monotonic counter APIs - Added the Tspi_PcrComposite APIs: GetPcrLocality, SetPcrLocality, SelectPcrIndexEx and GetCompositeHash. - Added new TSS 1.2 return codes for bad EK checksum and invalid resource passed to Tspi_Context_FreeMemory. - Added Christian Kummer's implementation of PCR reset - In PcrExtend, set up the event struct fully before sending to the TCS. - Fixed bug in ActivateIdentity's use of rgbSymCAAttestation. - updated policy handling to match the latest spec. - Fixed bug when 2 TCSD's return the same context number. - Added a check for the size of Tcsi_StirRandom's entropy data. - Added support for TSS 1.2 style keys and PCR info long and short structures. - Added support for TPM_Save/LoadAuthContext. - Grouped all threading functions in one header file, threads.h. - Fix added in TCSD's event parsing code for a segfault when only the number of events is requested. - Several bugs fixed in the Tspi_Context_GetRegisteredKeysByUUID code path in the TSP lib. - Added a lock around all TCSP functions; removed auth_mgr_lock since the TCSP lock now suffices. This fixed some TCSD multi- threaded errors. - hosttable.c: Fixed bug in host table entry removal, thanks to Thomas Winkler for the testcase that helped in finding this. - In the TCS GetPcrEventsByPcr, fixed a bug in calculating the number of events to return. Thanks to Seiji Munetoh. - Added functions to do incremental hashing, removing most large stack allocations in trousers. - Updated blob utility functions to use UINT64's instead of UINT16, which had caused some arbitrary limits in parts of trousers. - Merged in TSS 1.2 header files. - Merged in build changes for embedded. * TROUSERS_0_2 branch created - In obj_policy.c and obj_tpm.c, if NULL is passed in when trying to set a 1.2 style callback, clear the callback address. - Fix in Tspi_TPM_ActivateIdentity: Only validate over the out parameters from the TPM, not the TCS (size of data). - obj_encdata.c: fixed reference of pcrSelect, which caused bad data to be returned as the PCR selection. - added TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATRELEASE, which was type-o'd in the 1.1 header files. - Fix for SF1570380: Algorithm ID not compliant with TSS spec. - Corrected off by 1 errors in PCR index bounds checking. - Changed logging in the TCSD so that FILE:LINE isn't printed unless debugging is on. - Changed build/code so that the system PS dir is mode 0700, not 1777. It used to be 1777 when user PS was not in ~/.trousers. - Fix for SF1565726: Segfault when connecting from remote host. - Fix for SF1565208: User PS load key by UUID failed. * TROUSERS_0_2_8 - Fixed bug in mc_add_entry, where the PCRInfo data was not being copied into the mem cache with the other fields of the key. - Fixed 2 bugs in spi_getset.c where setting the secret hash mode was passing subFlag to the internal set function instead of ulAttrib. - Added patch to retry the libtspi's recv() call to the TCSD if the call was interrupted before completion. - Made the popup string appear as a label on the popup, not the title. Also, got rid of annoying mouse-over texts. - Added a flag to pass to the get_secret function internally to indicate whether a popup should contain the confirm box. - Added support for callbacks in the identity creation code. - Updated the identity creation code in the TSP/TCS to support AES, DES, 3DES during identity creation. - Added symmetric encryption interfaces for openssl, Trspi. - In Tspi_Hash_Sign, fixed memory leak. - Added SetAttribData functions for RSA modulus/exponent per the upcoming additions to the TSS 1.2 errata 1 spec. - Fixed bug in TCS key cache where if 2 keys had the same public modulus, they could confuse the key cache manager. - Bind/Seal functions now return more descriptive errors codes and won't do the encryption if the data to use is larger than the RSA pubkey. - Made updates to the code/headers for the TSS_VALIDATION struct change to be issued as TSS 1.1 header file errata 1. - Bug fix: In LoadManuMaintPub's wrapping function in the TSP, we incorrectly passed a reference to the pubkey in loading the blob. - Fixed bugs in the maintenance commands, owner auth'd commands were using no auth tags in their commands sent to the TPM. - Fixed SF1546344: Track the release of auth handles by TCS context and take the fContinueAuthSession variable into account when calling the TPM to release a handle. - Fixed SF1545614: deadlock due to auth_mgr_osap taking the auth_mgr_lock before calling ensureKeyIsLoaded, which took the mem_cache_lock. - Added checks to ensure corrupt packets don't crash the tcsd. - Added configure option --with-gui=gtk/none to enable building with no popup support for embedded apps. The default secret mode becomes TSS_SECRET_MODE_NONE for all policies and the default context mode becomes TSS_TSPATTRIB_CONTEXT_SILENT to supress all popups. - Changed the Tspi_GetAttribData function to return a TCPA_PUBKEY blob as is specified in the portable data section. - Added a debugging #define in req_mgr.c to print all data passed to/from the TPM. - Updated Tspi_Context_LoadKeyByUUID to check in-memory keys by UUID when the TCS returns a filled-out loadkey info struct. - Removed the free of all context related memory when the context closes. Allows an app more flexibility in choosing what to free. - Removed check for secret mode None in establishing an OSAP session. Now, a secret of all 0's is used if no secret exists. - Added checks for 2 return codes in secret_TakeOwnership. - Fixed TSS_VERSION problem. There are no specific getcaps for software version vs. TSS spec version. Instead, the TSP's version structure contains spec version and software major/minor. - Removed obj_regdkey list references. * TROUSERS_0_2_7 - Added 3 new TCSD config options to allow admins to set paths to the 3 types of credentials returned on Make Identity calls. - Added an implementation for returning the MANUFACTURER TCS caps. - Added translation of TSS caps that are destined for the TPM. - Updated DirWrite to work correctly (thanks Kylie). - Updated the Tspi_TPM_DirWrite manpage with more info, removed a confusing statement. - Changed the number of loops in TCSP_GetRandom_Internal to 50, which should allow TPMs that return few bytes per request to fullfill up to 4K bytes. - Removed the TCS's getSomeMemory() function, which was really dumb. - Changed the way user PS operates. User PS is now really persistent, its kept in ~/.trousers/users.data, which is created if it doesn't exist. Also, the environment variable TSS_USER_PS_FILE can be set to a path that will override the default location for as long as the TSP context is open. - Lots of memory leaks found in error paths by Coverity, mostly in tcsd_wrap.c. - Fix for SF #1501811, setting some SetAttribUint32 flags not supported. - Lots of updates to the fedora specific RPM specfile. - Fix for SF #1490845, 'make install' overwrites old tcsd.conf - Added code to return TSS_E_POLICY_NO_SECRET when setting up an OIAP or OSAP session. - Added fix for SF #1490745, trousers demands too much from /dev/random. Default random device is now /dev/urandom. - Changed severity of the ioctl fallback print stmts to warning and info. - Added implementation of the maintenance functions. - Added fix for SF #1487664, Offset in PS cache is not updated correctly. - Removed some Atmel specific code and commented out code. - Added some missing auth_mgr_check calls in tcspbg.c. - Fixed some unchecked mallocs in the TSP. - Added build variables to automatically update the TSP library version and TCSD version getcap variables. - Added call to return the modulus of an RSA key on a GetAttribData call. - Added implementation of the migration functions. - Fix for SF 1477178, random numbers get hosed by the tcsd. * TROUSERS_0_2_6 - Removed unnecessary call to obj_encdata_get_data in Tspi_Data_Seal. - Added support for using the trousers.h APIs in C++. - Fixed Tspi_PcrComposite_GetPcrValue's man page, which had left out *'s in two parameters. - Fix for SF 1414817, Quote's PCR object doesn't get set on return. - Lots of function renaming to make code reading clearer. - Return TSS_E_INVALID_OBJ_ACCESS when trying to retrieve data from an encrypted data object that hasn't been set. - Added contact info to the README. - Fix for ordering of params in call to set callback by Tspi_SetAttribUint32. Thanks to Thomas Winkler for the fix. - Fix for SF 1410948, get random numbers from /dev/urandom unless Tspi_TPM_GetRandom is called explicitly. - Fix for SF 1342026, print TPM error codes during bring-up. - Added support for a TCS_LOADKEY_INFO structure returned from a TCSP_LoadKeyByUUID call. - Fixed 2 free_tspi's that should have been plain free's * TROUSERS_0_2_5 - Changed all prints of size_t to %z (matters on 64bit platforms). - Backport of the context and policy object's TSS_TSPATTRIB_SECRET_HASH_MODE attribute from the TSS 1.2 spec. This will allow 1.1 apps to decide whether they want to include the 2 bytes of NULL in the hashes of their secrets. This will in turn allow various TSS's to interoperate better. - SF#1397265 'getpubek' to 'readpubek' in tcsd.conf. - Added an implementation of TSS 1.2 style callbacks. - Added Emily's patch to explain the TSS_DEBUG_OFF flag, added blurb to README. - Fixed bug that only manifested on PPC64: if errno is not set to 0 explicitly before making a call to iconv, iconv will not set it on failure. * TROUSERS_0_2_4 - Updated README with how to use new system.data files. - Added sample system.data files for users who've taken ownership of their TPMs under other OS's. - Updated unicode routines to NULL terminate their strings with the same number of bytes as is the width of the encoding. - Fixed bug in TCS_EnumRegisteredKeys_TP, returned data should be alloc'd on the TSP heap. - Added a logging statement when tcsd_startup fails due to an error returned by the TPM itself. - Fixed validation data in Tspi_TPM_Quote and Tspi_TPM_GetPubEndorsementKey. - Implemented Tspi_TPM_CollateIdentityRequest and Tspi_TPM_ActivateIdentity. - Bug fix in TCSP_Sign_TP, signature should be alloc'd using the TSP heap. - Fix for SF#1351593, authdata was always 0 for the SRK. This was due to the defaults set in Tspi_Context_CreateObject for the SRK key flag. The default SRK key is now set to require auth. If you want an authless SRK, you need to either set the authdatausage attribute directly or pass in your own SRK initFlags to the create object call. - Return bad parameter when no the pcr object is not initialized instead of internal error. - Several fixes added for list locking in the obj_*.c files. - Added initial support for Tspi_TPM_CollateIdentityRequest and its supporting functions (symmetric encryption). - Fix for SF#1338785: Support TSS_TSPATTRIB_HASH_IDENTIFIER. - Changed default kernel and firmware controlled PCRs to none, which should have happened a long time ago. :-/ - Fix for SF#1324108: Tspi_TPM_GetEvents should return a number of events - Fix for RFE#1301441: Fallback support for the device node. ioctl is tried first, if that fails, r/w is tried, if that fails, error is returned. - Fixes for SF#1332479: HMAC and XOR callbacks were being passed wrong params. - Fix for SF#1334235, uuid data wasn't being set correctly when keys were registered or loaded by uuid. - Fix for SF#1332316, Tspi_GetAttribData doesn't always return data alloc'd by TSP. Unicode data returned from the function was being allocated off the TSP heap. - Changed default return value for Tspi_GetAttribUint32 to success. - Corrected Tspi_TPM_PcrExtend manpage to state that the application should fill out the TSS_PCR_EVENT structure. -Fixes for SF BUG#1312194, and SF BUG#1312196. Get Attribs for key usage and size were not being returned correctly. Imported values for size from the TSS 1.2 header files and translated TPM <-> TSP values for key usage in the get attrib calls. - Accepted Halcrow's patch to add a TSP key object removal function, invoked at object close time. This was SF BUG#1276133. - increased the size of the return buffer from TCS to TSP to 8K, so that larger requests won't fail. - added a loop to TCSP_GetRandom_Internal to try several (currently 5) times to get the number of requested bytes from the TPM. Since the TSP has no way to tell an application that a single request failed, this will help improve the odds of a large request succeeding. * TROUSERS_0_2_3 - SF#1291256 bugs fixed. A UINT16 was being passed instead of a UINT32 to TCS_LoadKeyByBlob_Internal. - Removed test in spi_context.c's call to TCS_LoadKeyByUUID, which would always fail, since there was no TCS layer bit set. This kept us in a success path. - Added debug logging functions that print the function name at the beginning of the statement. - Added GetPubKey as an option for TCSD's remote ops. - SF#1249767 bug fixed. UTF16 strings are now hashed when passwords are passed in through the popups. - SF#1286333 bug fixed. New unicode functions added that convert to UTF-16 and from the nl_langinfo(CODESET) encoding. - SF#1285428 bug fixed. obj_context_get_machine_name copied too many bytes out. Code added to Tspi_GetAttribData to convert to UTF16 before returning. * TROUSERS_0_2_2 - deleted section on ssh-askpass in README - Modified popup code to hash UTF16 instead of UTF8. - Restructured TCS calls to the TPM so that all auth sessions are released correctly. - Removed TSP contexts from all Trspi functions and modified all trousers code to free its own memory instead. - Fixed the TSP seal command to allow Sealing with a no-auth key by using null auth data. Also changes the TCS seal to return bad parameter if it gets null auth data. - Removed lots of unused code and made formatting changes. - Don't require Tspi_Key_WrapKey to be connected to succeed and return a default value (or from the environment) if we're doing PCR operations on an unconnected context. - Fixed bug where a tcsd created system.data file was not getting the right version info put into it. - SF BUG#1269290 Fixed: Protect the SRK pub key. Upon taking ownership, the unaltered SRK blob is passed back to the TSP to create a valid key object with the SRK pub key intact. The copies of the SRK pub key data that do into the TCSd's mem cache and PS are zeroed out. From then on, the only way to get the SRK pub key is through Tspi_Key_GetPubKey. - tcspbg.c: deleted unused code and always release auth session on an Unbind call. - Bugfix for SF#1274308, Tspi_Key_CreateKey doesn't add PCRs correctly. Ordering of calls in obj_rsakey_set_pcr_data and calculation of PCRInfo size were incorrect. - Close auth sessions in TCS_GetCapabilityOwner - Removed volatile flag from the SRK key handle at key object create time. This was keeping National TPM's from having the ability to be owned! - Moved calcCompositeHash to obj_pcrs.c and renamed it. - Check returns everywhere for addKeyHandle calls. - Call pthread_mutex_init on the host table's mutex. - Modified TSSWG headers so that code w/o BSD types compiles (such as the PKCS#11 TPM STDLL). - Removed ssh_askpass, since UNICODE must be hashed from the GUI input source. - Updated all manpages to include the TSSWG header file names instead of trousers specific files. - Don't log debug data when TSS_DEBUG_OFF env var is available. - Converted UNICODE to unsigned short and modified code accordingly. - Only allow INADDR_LOCALHOST connections when no remote_ops are defined in the tcsd.conf file. - Bugfix in obj_pcrs.c, setting pcr indices and values was buggy. - Moved macros from trousers_types.h (internal) to trousers.h (external), since new header files make them virtually a requirement - Bugfix for SF#1249780, PCR selection structure was incomplete. - Bugfix for SF#1249769, addKeyHandle now returns a TSS_RESULT. * TROUSERS_0_2_1 - return invalid handle int Tspi_ChangeAuth when hParentObject is not of the right type. - Fixed bug in TCS ps, write_key_init returned the wrong offset. - Fixed mem leak in spi_getset.c:791, found by Coverity. - Fixed mem leak in calltcsapi.c:70, found by Coverity. - Fixed mem leak in tcskcm.c:531, found by Coverity. - Fixed type-o mem leak in tspps.c:319/tcsps.c:349, found by Coverity. - Fixed mem leak bug in memmgr.c:173, found by Coverity. - Fixed bounds error bugs in tcstp.c:38/98, found by Coverity. - Fixed bounds error bug in tcsd_wrap.c:154, found by Coverity. - Fixed unchecked return bug in spi_utils.c:430, found by Coverity. - Fixed unchecked return bug in calltcsapi.c:1159, found by Coverity. - Fixed negative return value bug tcs/ps/ps_utils.c:365, found by Coverity. - Fixed negative array index bug readpass.c:65, found by Coverity. - Fixed null deref bugs spi_tpm.c:1292/1309/1302, and uninitialized variable 1272, found by Coverity. - Fixed null deref bugs spi_context.c:358/378, found by Coverity. - Fixed null deref bug tcspbg.c:1413, found by Coverity. - Fixed null deref bug tcspbg.c:745, found by Coverity. - Fixed null deref bug imaem.c:356, found by Coverity. - changed config file defaults for kernel/firmware pcrs. - added better logging for when user/group "tss" doesn't exist - in sendTCSDPacket: set transmitBuffer to 0 to prevent sending bogus data. - added some sanity checking in getTCSDPacket to prevent segfaults. - added TCSERR where needed in tcs/ps files. - BUG 1233031 fixed, TSP now stores PACKAGE_STRING as the vendor data when registering a key. - Added better debugging of auth mapping table, also closed two auth handles that were getting left opened in CreateWrapKey and Seal/Unseal. - fixed ps_inspect's printing function. - added SELinux files and README.selinux. - updated ps_inspect tool to recognize non-PS files, print out version 1 PS files and added a license statement. Also added ps_convert tool to convert version 0 PS files to version 1. - updated ps_inspect tool to print out blobs and keys. - change assert to DBG_ASSERT in tcs/ps files, also assert that data sizes are > 0 when read off disk. - Lots of malloc error logging changes where %d should have been %u in the print statment. - auth_mgr.c: allow a TSP to open a max of max_auths/2 sessions before its denied any more, for TPMs that can handle a lot of auth sessions. - Big-endian fixes for the persistent store functions. Trousers now runs fine on ppc64, for example. - BUG 1226617: Audit of code for auth handle termination. - Use @PACKAGE_BUGREPORT@ instead of a static email addr in manpages. - Added man page for tcsd.conf in section 5. - Bugfix in remove_table_entry. Host table head was left pointing at free'd memory. - corrected comment in spi_context.c. - added 64bit stuff to configure.in - fixed bug in Tspi_ChangeAuth where parent object was assumed to be an rsakey. - fixed debug logging of data. - modified calcCompositeHash for accepting incomplete pcr select structures & to fill out the structure correctly. * TROUSERS_0_2_0 - removed unused code and added debugging in clearUnusedKeys(). - Updated README with info on the 2.6.12 kernel device driver. - fixed bug in calculating pcr select size - fixed bug in init'ing PCRS, spi_utils.c:431 - Changed TCPA sig schemes to TSS sig schemes in Hash_VerifySignature. - Implemented Tspi_Context_GetKeyByPublicInfo on the TCS side. - Fixed PS bug in storing the pub key data. - Implemented Tspi_Key_UnloadKey - Implemented the guts of Tspi_Key_CertifyKey, which now works in at least the case where both keys passed in are authless. - in obj_rsakey_set_es/ss, added mapping from TCPA numbers to TSS numbers and vice versa. - added #includes in readpass.c to get rid of compile errors. (thanks Emily). - Fixed popup secret handling. Bug #1194607 closed. - Fixed up the LogBlobData functions, no more strcat. Bug #1221974 closed. - changed sprintf's to snprintf. Bug #1221932 closed. - Changed the TCPA_RSA_KEY_PARMS management at key creation time. - Re-implemented TSP object management. - Integrated TSSWG header files. - Added valid_keys variable for the debugging build of tcs/ps/ps_utils.c. - Changed >= to > in openssl/crypto.c to correct off by one in checking the size of the input data. - added cvs commit logging to CVSROOT/loginfo file. * TROUSERS_0_1_11 - Changed TCSD logging to only log on remote connection attempts, local connections will be left silent. - mended compiled time warnings - updated src/tspi/Makefile.am to respect libtool. - added x86_64 case to configure.in - added args to print stmt tcsd_wrap.c:3640 (thanks Kylie). - commited fix for detecting past runlevel states (thanks Kylie). - committed fix for RNG problem: a TPM's RNG is disabled when the TPM is in the disabled state, yet needs a random number to open an OSAP session to call the owner auth'd TPM enable command. - added code for CreatePubEK plumbing (thanks Kylie). - fixed a couple signed/unsigned comparison warnings - fixed endianess stuff in TPM GetCap spi_tpm.c. - added Trspi_Error functions to manipulate TSS_RESULTs. - Fixed order of receiving for the TCS_OwnerReadPubek call (thanks Kylie). - Added defns for volatile and non-volatile flags (thanks Kylie). - Added Trspi_Error, which converts a TSS_RESULT to a string. (thanks Kylie). - In tcsd_wrap.c, added function bodies for tcs_wrap_OwnerClear, tcs_wrap_DisablePubekRead, tcs_wrap_OwnerReadPubek, tcs_wrap_DisableForceClear and tcs_wrap_DisableOwnerClear. (thanks Kylie). - Added an unload of the auth returned from the TPM in TCSP_OwnerReadPubek_Internal. (thanks Kylie). - Corrected the TAG for the TPM command in TCSP_OwnerReadPubek_Internal. (thanks Kylie). * TROUSERS_0_1_10 - Updated implementation of Tspi_Key_WrapKey. - Added missing goto in ReadPubEK in tcstp.c. (thanks Kylie). - Added function guts for various functions in tcstp.c. (thanks Kylie). - In Tspi_TPM_SetStatus, do the right in the physical presence path based on boolean. (thanks Kylie). - Actually pass in the bool flag on TCSP_PhysicalPresence_Internal (thanks Kylie). - corrected force clear logic in spi_tpm.c:818 (thanks Kylie). - fixed error return code check to socket() syscall clntside.c:52. - added comment about TDDL reries and added log statement when a physical presence command is denied because of runlevel. - Fixed Tspi_Hash_VerifySignature to check signatures based on the signature scheme of the key in use. Also, crypto.c was changed to do a verify based on TSS_HASH_OTHER. - Added 2 new highlevel Unbind testcases to test PKCS1.5 vs OAEP. - In Tspi_Context_LoadKeyByUUID, the uninitialized keyBlob variable was causing an invalid free on exit. Corrected that. - changed return value from internal error to invalid handle when a bad object handle is passed to Tspi_Hash_Sign and the Tspi_Data functions. - added Tspi_TPM_CertifySelfTest functionality - corrected iptables string in the tcsd manpage. - Corrected return code in Tspi_Key_UnloadKey02.c testcase. - enabled Tspi_TPM_GetTestResult functionality - added selftest as an option to the list of remote ops for the access control - added compatibility with openssh-askpass for the popup dialog box. Now either gtk2-devel OR openssh-askpass must be installed to build trousers. Using openssh-askpass reduces the size of libtspi.so by about 40K and reduces the number of dependencies from 26 to 6! - Bugfixes - The entityType field was being passed between the TCSD and TSP as a UINT32 instead of UINT16. This was keeping Tspi_ChangeAuth from working as advertised. - Secrets were being hashed incorrectly when secret mode was PLAIN and the secret data length was 0. Now, when secret mode is plain, the passed in data is always hashed, even if its 0 length. - Popups are hopefully being handled more correctly now. Previously the dialog popped up at the time SetSecret was called, but now its just when the secret is actually needed. - sf.net Bug #118026: memory allocations and free's fixed in almost all paths from app to tcstp.c wrt correctly returning calloc_tspi'd memory vs. malloc'd memory. Only problem remaining is the PCR event functions, which have dangling malloc'd references, which is an architectural problem which should be solved in the 1.2 rewrite. * TROUSERS_0_1_9 - added tcsd manpage - added access control functionality so that sets of ordinals cannot be executed by non-local hosts. This is now a configurable option in tcsd.conf as "remote_ops". - Set Physical Presence now works from the TSP when the TCSD detects that it is running in single user mode. When not running in single user mode, the TCS_PhysicalPresence command returns TSS_E_NOTIMPL. - Changed an fprintf to LogError in gtk/support.c - TCP/IP server-side fixes in svrside.c - various compile warnings fixed - moved commonly used utility functions to trspi/trousers.c and exported these functions in the header file tss/trousers.h. - added new testcases for ChangeAuth of the TPM owner and SRK in tcg/highlevel/tspi. - added test tcg/highlevel/tpm/Tspi_TPM_PcrRead04.c - updated Tspi_TPM_GetCapability manpage. - added code to detect a 1.2 TPM and get auth sessions the 1.2 way. - added manpage for Tspi_TPM_GetPubEndorsementKey - Bugfixes - in crypto.c, encrypted data area should be RSA_size(rsa) bytes large, not always 256. This was keeping non-2048 bit keys from working with the TPM keyring app. - Fixed detection of an already closed Tddl. - Allow validating the entire TCPA_PUBKEY structure in Tspi_TPM_GetPubEndorsementKey, as National chips do this. - Added support for TSS_TPMCAP_ORD and TSS_TPMCAP_FLAG in Tspi_TPM_GetCapability, which required a call to TCSP_GetCapabilityOwner to fetch the TPM's internal flags. Added tcg/highlevel/tpm/Tspi_TPM_GetCapability0{4,5}.c to test. - When loading the SRK from TCS PS, the TCS key handle should now be 0x40000000 (TSS_SRK_KEY_HANDLE). There were checks for this in the ChangeAuth code paths, which caused failing of various sorts. - Bug fixed in roll over of TCS key handle generation. Previously we would have smashed the SRK's fixed value and we would have thought there were 2 SRK's loaded. - sf.net bug #1154611, old SRK was not being removed from mem cache, though disk cache was being deleted. This means that after re-taking ownership the mem cache was corrupted until a restart of the TCSD. - Feature Requests - sf.net RFE #1122608 completed. Several different device locations are now supported by default. If /dev/tpm is created its assumed that the IBM Research device driver is being used and therefore ioctl's are sent to the driver, all others get read/write's. Updated README. * TROUSERS_0_1_8 - added a manpage for Tspi_TPM_PcrExtend - added SHA1_HASH_SIZE #define tied to openssl/sha.h - Corrected typo in tcpa_types.h of pValdationData -> pValidationData - updated README with info on device file stuff - added a usage function and long options to tcsd - added an error message when incorrect params are passed to tcsd on the command line. - added -lcrypto and -lpthread to the build of libtspi.so, so that app writers will avoid having to include those when they don't have to. - Connected up Tspi_TPM_SetStatus and Tspi_TPM_SelfTestFull to TCSP_SetTempDeactivated, TCSP_SelfTestFull, TCSP_SetOwnerInstall, TCSP_OwnerSetDisable and TCSP_PhysicalDisable. - Bugfixes - tcsem.c:507, error in calculating number of PCR events to copy out. - sf.net bug #1151183 fixed. Tspi_TPM_GetPubEndorsementKey now takes the correct number of params, and all testcases/TSS calls are changed. - sf.net bug #1113313 fixed. Tspi_TPM_TakeOwnership now allows a NULL pub endorsement key handle and a testcase, tcg/highlevel/tpm/Tspi_TPM_TakeOwnership03.c, exists to test this. - In Tspi_SetAttribData, set the TCPA_KEY's privkey, not the wrapper object on a TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY. * TROUSERS_0_1_7 - Fixed the logging up so that if tcsd -f is specified, all logs go the foreground, else all logs go to syslog. - Moved the TPM_IOCTL #define into the tddl.h file. Now, if you're using the IBM research device driver, compiling with #define TPM_IOCTL will use ioctl's to open /dev/tpm and #undef TPM_IOCTL will use read/write calls to /dev/tpm0. - Revert accidental change in tddl.c - Lots of 0's replaced with non-magic #define's in the TSP code - In spi_getset.c: removed unimportant debugging stmts; make Tspi_{Get|Set}AttribData set the correct public and private key data when asked to. - Lots of manpage verbage changes. - added new manpages for: Tspi_TPM_TakeOwnership, Tspi_Key_LoadKey, Tspi_Context_Create and Tspi_TPM_ClearOwner. - Bugfixes - cxt.c: when destroying a context object, release the tcs_ctx_lock before calling ctx_ref_count_keys(). This prevents a deadlock. - added a mutex unlock call for an error path that would have caused a deadlock * TROUSERS_0_1_6 - Logging functionality changes only, for bug #1106301 - TCSD: - Logs now go to stdout/stderr until a successful startup - After a successful startup, cmdline args are parsed - if -f is specified, logging continues to stdout/stderr and daemon runs in the foreground, killable by ctrl-c. - If -f is not specified, logs go to syslog and the tcsd forks into the background - TSP library - If compiled w/o debugging, there is no logging of any kind - If compiled w/ debugging, all logs go to stdout/stderr, unless the environment variable TSS_DEBUG_OFF is set, then, there is no logging of any kind - There is no longer a --enable-stderrlog option to the configure script * TROUSERS_0_1_5 - Complete memory management overhaul. calloc_tspi is now used to clean up memory allocated by Tspi functions. TCS blob functions have been changed to not require a context, since there's no need w/o calloc_tspi. Its now necessary to call free explicitly everywhere in the TCS. In the TSP, calloc_tspi is now always called with the TSP context of the session, which would will ensure all memory allocated by the session is accounted for. - Unused #defines and variables removed from spi_utils.h - Commented out code removed throughout the source. - Removed log.o on a 'make clean'. - commented out unnecessary logging, added more descriptive logging - renamed variables named 'hContext' to specifiy whether they represent TSP of TCS context handles. - got rid of a few magic numbers - Bugfixes - in tcs/cache.c, getNextTimeStamp() was unlocking the mutex twice. - removed destroy_key_refs() in TSP, which caused double free errors - added call to event_log_final() in tcsd_shutdown() to clean up the event log - added an intermediate copy stage of data in getTCSDPacket() to avoid memcpy() calls with overlapping source and dest fields. * TROUSERS_0_1_4 - added ChangeLog :-) - TSP object management overhaul. All API's should be correct for contexts whether they're connected to a TCS or not. - testsuite changes based on object mgmt overhaul - various internal fixes and simplifications of the code due to object mgmt overhaul * TROUSERS_0_1_3 - added helpful message when package gtk2-devel is not found in configure.in - chown changes in dist/Makefile for new syntax - added detailed flags to various manpages - TSP memory management overhaul - added more complete destroy_key_refs() function - Bugfixes - quashed memory leaks in TSP found by valgrind - return TRUE/FALSE from getAttribData - added TSS_TSPATTRIB_KEYINFO_SIZE to Tspi_GetAttribData - call free() not Tspi_Context_FreeMemory() in spi_utils.c * TROUSERS_0_1_2 - added bug report mailing list to configure.in - added --enable-stderrlog feature to configure.in - Marked Tspi_TPM_GetCapabilitySigned as not implemented (per TSS v1.1b spec) - Bugfixes - Removed common.h from Tspi_Context_RegisterKey manpage - added endianess macros to spi_utils.h - made all endianess fixes to the TSP and testsuite - logging improvements tcspbg.c - tcs_utils.c compile time warning quashed * TROUSERS_0_1_1 - Updated design doc - Updated README - More sensible function naming (no addNewObject, just addObject) - Bugfixes - return data correctly in Tspi_GetAttribData - malloc space for returned UUID correctly in tspps.c - log errors in tddl.c - follow a failure path in auth_mgr.c - don't always return success in req_mgr.c * TROUSERS_0_1_0 - Initial code drop trousers-0.3.15/AUTHORS0000664000175000017510000000124113663651711014022 0ustar deboradebora All authors of this TSS have been funded by IBM. The TSS code was originally written for WIN32 by Ryan Catherman and ported to Linux initially by Seiji Munetoh and Taiga Nakamura as well as Ryan. The code has since been modified by Seiji Munetoh, Kent Yoder and Richard Maciel. The code is currently maintained by Debora V Babb The manpages were originally written by Megan Schneider and Kathy Robertson and have been modified by Kent Yoder. Other contributors to the TSS 1.2 functionality: Tom Lendacky Loulwa Salem Ramon Brandao Klaus Kiwi Kent Yoder Hon Ching(Vicky) Lo Specifically the NVRAM implementation: James Xu Rossey Liu Jacfee Liu trousers-0.3.15/TODO0000664000175000017510000000013513663651711013443 0ustar deboradebora Please see http://sourceforge.net/tracker/?group_id=126012&atid=704361 for TrouSerS TODOs. trousers-0.3.15/NICETOHAVES0000664000175000017510000000032213663651711014444 0ustar deboradebora These items are of lower priority than the TODO list. If any of these become actual TODO's, they will move to that list. 1. Test Suite Design Document 2. State machine diagram of the TSS internal workings trousers-0.3.15/README0000664000175000017510000002101713663651711013635 0ustar deboradeboratrousers README Trousers is an open-source TCG Software Stack (TSS), released under the BSD License. Trousers aims to be compliant with the 1.1b and 1.2 TSS specifications available from the Trusted Computing Group website: http://www.trustedcomputinggroup.org CONTACT For information on the TrouSerS project, please send mail to the following lists: Use of the TSS API and TrouSerS: trousers-users@lists.sf.net Discussion of the internals of the TrouSerS implementation: trousers-tech@lists.sf.net Possibly sensitive security related bugs: Hon Ching(Vicky) Lo Run-of-the-mill bug reports should use the TrouSerS bug tracker: http://sourceforge.net/tracker/?group_id=126012&atid=704358 BUILD REQUIREMENTS Packages needed to build: automake > 1.4 autoconf > 1.4 pkgconfig libtool gtk2-devel openssl-devel >= 0.9.7 pthreads library (glibc-devel) BUILDING the TSS 32-bit Build and install the latest TPM device driver from sf.net/projects/tpmdd either compiled in or loaded as a module. UPDATE: This driver is now included in the vanilla 2.6.12 kernel! If you are doing this, trousers should just work after a vanilla build. Follow the build instructions below and read RUNNING the TSS, below. To build trousers after you have the device driver installed: $ sh bootstrap.sh $ ./configure [--enable-debug] [--enable-gprof] [--enable-gcov] $ make # make install Here are the default locations of files that trousers installs: /usr/local/sbin/tcsd /usr/local/etc/tcsd.conf /usr/local/lib/libtspi.so.0.0.X /usr/local/lib/libtspi.so.0 -> libtspi.so.0.0.X /usr/local/lib/libtspi.so -> libtspi.so.0.0.X /usr/local/lib/libtspi.la /usr/local/lib/libtddl.a /usr/local/var/lib/tpm By default the build will place everything in /usr/local. To install in a slightly more predictable place, use `./configure --prefix=/usr`. 'make install' will run ldconfig, but if /usr/local/lib is not in your /etc/ld.so.conf, this won't make a difference. You may need to manually add it and run ldconfig as root to allow your apps to link at run time to libtspi.so. BUILDING the TSS 64-bit TrouSerS has been built and tested on ppc64 and x86_64, so please don't hesitate to report bugs on these platforms. Building everything 64-bit will require a few more flags than are necessary for a 32-bit platform. Here are some example instructions for ppc64: $ sh bootstrap.sh $ export PKG_CONFIG_PATH=/usr/lib64/pkgconfig $ CFLAGS="-L/usr/lib64 -L/opt/gnome/lib64" LDFLAGS="-L/usr/lib64 \ -L/opt/gnome/lib64" ./configure --libdir="/usr/local/lib64" $ make # make install Hopefully the above example will get you going on building in your 64-bit environment. If you need to do anything special, please send your build steps to trousers-users@lists.sf.net and I'll include it here. USING TROUSERS ON AN ALREADY OWNED TPM If you've already taken ownership of your TPM using a TSS under another operating system, there are a few issues you should be aware of. Auth vs No-Auth SRK: In order to trick trousers into thinking it has taken ownership of the TPM it's running on, you will need to create a persistent storage file for trousers to use. Normally trousers would create this file itself at the time ownership is taken. If your SRK has been given an authorization password by the non-Linux OS, you will need to move the file dist/system.data.auth to /usr/local/var/lib/tpm/system.data. If you've taken ownership of your TPM without issuing a password, move dist/system.data.noauth to /usr/local/var/lib/tpm/system.data. Passwords: When entering passwords for keys you'd like to use in both Linux and other OS's, you'll need to take note of how you entered those passwords. The TSS spec states that when a password is entered through a GUI popup dialog box provided by the TSS library, the password should be converted to the UTF-16 encoding and then hashed using SHA-1, including the UTF-16 null terminator in the hash calculation. In order to work around this problem, specify the -u option to the tpm-tools command line to convert the password to UTF-16 before hashing. This, however, unfolds yet another problem... Some TSS stacks aren't compliant with the TSS spec, in that they hash their passwords without including the terminating null character. This means that there are effectively two versions of any password set through a popup dialog box. Trousers will include the terminating null character in its hashes of UTF-16 data. We'll do our best to track other TSS software and how it behaves. Please see the trousers FAQ at http://trousers.sf.net for more information. ARCHITECTURE This TSS implementation has several components. A) The TCS Daemon - A user space daemon that should be (according to the TSS spec) the only portal to the TPM device driver. At boot time, the TCS Daemon should be started, it should open the TPM device driver and from that point on, all requests to the TPM should go through the TSS stack. The TCSD manages TPM resources and handles requests from TSP's both local and remote. B) The TSP shared library - The TSP (TCG Service Provider) is a shared library that enables applications to talk to TCSD's both locally and remotely. The TSP also manages resources used in commicating with the application and the TCSD and transparently contacts the TCSD whenever necessary. C) Persistent Storage (PS) files - TSS's have 2 different kinds of PS for keys. PS can be thought of as a database for keys, with each key in the database indexed by a UUID. 'User' persistent storage is maintained by the application's TSP library. Upon writing the first key to User PS, the TSP library creates a new file at ~/.trousers/user.data, using the effective user id of the process executing the call to find ~. An environment variable, TSS_USER_PS_FILE, can also be set to point the TSP library to a different location for the User PS. This environment variable has the lifetime of the TSP context, so to store 2 keys in 2 different files, you will need to call Tspi_Context_Close, set the new location, and open the context again. 'System' persistent storage is controlled by the TCS and stays valid across all application lifetimes, TCSD restarts and system resets. Data registered in system PS stays valid until an application requests that it be removed. The System PS file by default is /usr/local/var/lib/tpm/system.data. The system PS file is initially created when ownership of the TPM is first taken. D) A config file. By default located in /usr/local/etc/tcsd.conf. RUNNING the TSS By default, the TCS daemon is not reachable over the internet, so if you just plan to access it locally, running it as root with a root owned device node is probably ok. Just make sure your device driver is loaded and start the tcsd as root. If you would like to run the TCS daemon as an unprivleged user, please follow these instructions: If you're using the device driver from a linux 2.6.12+ kernel and have udev enabled, you need to add the following line to your udev.permissions file (usually in /etc/udev somewhere): tpm[0-9]:tss:tss:0600 and then just load the device driver with: # modprobe tpm_atmel or, # modprobe tpm_natl start the TCS Core Services daemon, by default /usr/local/sbin/tcsd. # /usr/local/sbin/tcsd If you're attempting to make the TCS Core Services daemon communicate with a softwware TPM through TCP, you must call it using the -e option. # /usr/local/sbin/tcsd -e The default values for hostname, port and UN socket device path are "localhost", "6545" and "/var/run/tpm/tpmd_socket:0". It will search for the IN socket device, then for an UN socket one, and then for the real TPM in this order. The default values match with the current open source project required values, if for instance case you need to set values of your choice, the environment variables for them are TCSD_TCP_DEVICE_HOSTNAME, TCSD_TCP_DEVICE_PORT if using an IN socket and TCSD_UN_SOCKET_DEVICE_PATH if running an UN socket. DEBUGGING If you've compiled trousers with './configure --enable-debug' and would like to turn debugging output off at run-time, set the environment variable TSS_DEBUG_OFF to any value. BUILDING a TSS RPM # sh bootstrap.sh # ./configure # cd .. # mv trousers trousers-${version} # tar zcvf /usr/src/packages/SOURCES/trousers-${version}.tar.gz \ trousers-${version} # rpmbuild -bb trousers-${version}/dist/trousers.spec EOF trousers-0.3.15/README.selinux0000664000175000017510000000344313663651711015326 0ustar deboradebora How to get TrouSerS up and running with an SELinux policy. Kent Yoder This howto assumes a Fedora Core 4 install. 1. Install and load the device driver # wget http://download.fedora.redhat.com/pub/fedora/linux/core/4/SRPMS/kernel-2.6.11-1.1369_FC4.src.rpm # rpm -ivh kernel-2.6.11-1.1369_FC4.src.rpm # cd /usr/src/redhat/SPECS # rpmbuild -bp ./kernel-2.6.spec # cd /usr/src/redhat/BUILD/kernel-2.6.11/linux-2.6.11 # make menuconfig - Goto Device Drivers > Character Devices > TPM Devices - enable the drivers # make # make modules_install # make install # reboot # modprobe tpm_atmel (or others...) 2. Build and install trousers in the system location. The SELinux policy assumes that trousers is installed in the system location. To change these, edit the trousers.fc file. # tar zxvf trousers-0.2.1.tar.gz # cd trousers-0.2.1 # ./configure --prefix=/usr # make # make install 3. Install the SELinux policy sources # yum install selinux-policy-targeted-sources.noarch 4. Install the trousers te and fc files and load the policy # cp ./dist/fedora/trousers.te /etc/selinux/targeted/src/policy/domains/program # cp ./dist/fedora/trousers.fc /etc/selinux/targeted/src/policy/file_contexts/program # cd /etc/selinux/targeted/src/policy # make clean # make reload # make install # make relabel At this point, there should be a trousers-specific type for /dev/tpm0: # ls -Z /dev/tpm* crw-rw---- root root system_u:object_r:tcsd_device_t /dev/tpm0 Also, checking the security context of the running tcsd should show it running with the tcsd_t type: # ps -Zef |grep tcsd root:system_r:tcsd_t root 16362 1 0 15:10 ? 00:00:00 /usr/sbin/tcsd 5. That should be it! Send bugs and questions to trousers-users@lists.sf.net. trousers-0.3.15/LICENSE0000664000175000017510000000272513663651711013767 0ustar deboradeboraCopyright (c) 2013, TrouSerS Project All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. Neither the name of the TrouSerS Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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. trousers-0.3.15/configure.ac0000664000175000017510000003536213750246207015250 0ustar deboradebora# # configure.ac for the trousers project # AC_INIT(trousers, 0.3.15, trousers-tech@lists.sf.net) TSS_SPEC_MAJOR=1 TSS_SPEC_MINOR=2 TSS_VER_MAJOR=0 TSS_VER_MINOR=3 # compute $target AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([foreign subdir-objects 1.6]) # Debugging support AC_ARG_ENABLE([debug], [AC_HELP_STRING([--enable-debug], [turn on all trousers debugging flags [default=off]])], AC_MSG_RESULT([*** Enabling debugging at user request ***]),) # If the user has not set CFLAGS, do something appropriate test_CFLAGS=${CFLAGS+set} if test "$test_CFLAGS" != set; then if test "x$enable_debug" = "xyes"; then CFLAGS="-O0 -g -DTSS_DEBUG -Wreturn-type" # CFLAGS="-O0 -g -DTSS_DEBUG -Wreturn-type -DTCSD_SINGLE_THREAD_DEBUG" else CFLAGS="-O2" fi else if test "x$enable_debug" = "xyes"; then CFLAGS="${CFLAGS} -O0 -g -DTSS_DEBUG -Wreturn-type" fi fi # Arch specific stuff case $target in *darwin*) TCSD_LDFLAGS="" ;; *solaris*) CFLAGS="$CFLAGS -DSOLARIS" ;; *) TCSD_LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" ;; esac AC_SUBST(TCSD_LDFLAGS) # Non-standard OpenSSL location AC_MSG_CHECKING([Non-standard OpenSSL location]) AC_ARG_WITH(openssl, AC_HELP_STRING([--with-openssl=PATH], [Location of openssl libs/includes]), [OPENSSL_INCLUDE_DIR="$withval/include" OPENSSL_LIB_DIR="$withval/lib" if [[ ! -d $OPENSSL_INCLUDE_DIR -o ! -d $OPENSSL_LIB_DIR ]]; then AC_MSG_ERROR([$OPENSSL_INCLUDE_DIR or $OPENSSL_LIB_DIR doen't exist!]) else AC_MSG_RESULT([yes]) CFLAGS="$CFLAGS -L$OPENSSL_LIB_DIR -I$OPENSSL_INCLUDE_DIR" AC_SUBST([OPENSSL_LIB_DIR]) fi], [AC_MSG_RESULT([no]) AC_SUBST([OPENSSL_LIB_DIR], []) ] ) # The tspi Makefile will look for trspi/crypto/@CRYPTO_PACKAGE@/crypto.c # Future crypto packages can go in their own subdir of trspi/crypto # and a check for them should be made here AC_CHECK_LIB([crypto], [EVP_DigestUpdate], [CRYPTO_PACKAGE='openssl'], [AC_MSG_ERROR([openssl is currently the only supported crypto library for trousers. Please install openssl from http://www.openssl.org or the -devel package from your distro])]) AC_SUBST([CRYPTO_PACKAGE]) AC_SUBST(CRYPTOLIB, -lcrypto) AC_ARG_ENABLE(gcov, [AC_HELP_STRING([--enable-gcov], [turn on gcov code coverage flags [default=off]])], [CFLAGS="$CFLAGS -ftest-coverage -fprofile-arcs" AC_MSG_RESULT([*** Enabling gcov at user request ***])],) # profiling support AC_ARG_ENABLE(gprof, [AC_HELP_STRING([--enable-gprof], [enable profiling with gprof [default=off]])], [CFLAGS="$CFLAGS -pg" AC_MSG_RESULT([*** Enabling profiling at user request ***])],) SPEC_COMP=0 # strict spec compliance AC_ARG_ENABLE(strict-spec-compliance, [AC_HELP_STRING([--enable-strict-spec-compliance], [build TrouSerS as strictly spec compliant [default=off]])], [CFLAGS="$CFLAGS -DTSS_SPEC_COMPLIANCE" SPEC_COMP=1 AC_MSG_RESULT([*** Enabling spec compliance at user request ***])],) # user+group checking AC_ARG_ENABLE(usercheck, [AC_HELP_STRING([--disable-usercheck], [build TrouSerS without checking and setting of user/group tss [default=on] (Caution: This is intended for development purposes only.)])], [AS_IF([test "x$enableval" = "xno"], [CFLAGS="$CFLAGS -DNOUSERCHECK" AC_MSG_RESULT([*** Disabling user checking at user request ***])])],) AM_CONDITIONAL(NOUSERCHECK, [test "x$enable_usercheck" = "xno"]) # daa math lib: gmp or openssl (default openssl) MATH_DEFINE=BI_OPENSSL AC_ARG_WITH([gmp], AC_HELP_STRING([--with-gmp], [build TrouSerS with the GMP math lib (used in DAA)]), [AC_CHECK_LIB(gmp, [__gmp_rand], [], []) AC_CHECK_HEADERS([gmp.h]) MATH_DEFINE=BI_GMP AC_MSG_RESULT([*** Enabling GMP lib at user request ***]) ] ) case "$MATH_DEFINE" in BI_OPENSSL) AC_CHECK_HEADERS([ openssl/bn.h openssl/engine.h]) ;; esac CFLAGS="$CFLAGS -D$MATH_DEFINE" GUI=openssl AC_ARG_WITH(gui, [AC_HELP_STRING([--with-gui], [type of gui popup (gtk/none) [default=gtk]])], [GUI=$withval], []) if test "x$GUI" = "xgtk"; then # section imported from Glade compile pkg_modules="gtk+-2.0 >= 2.0.0" PKG_CHECK_MODULES(GTK, [$pkg_modules], AM_CONDITIONAL(HAVE_GTK, true), [AM_CONDITIONAL(HAVE_GTK, false) AC_MSG_ERROR([Please install the gtk2-devel package for your distro or select another gui option.]) ]) AM_CONDITIONAL(OPENSSL_UI, false) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) elif test "x$GUI" = "xopenssl"; then # We know we have OpenSSL AM_CONDITIONAL(OPENSSL_UI, true) AM_CONDITIONAL(HAVE_GTK, false) elif test "x$GUI" = "xnone"; then if test $SPEC_COMP -eq 1; then AC_MSG_ERROR([Popups must be enabled in strict spec compliance mode]) fi AC_MSG_RESULT([*** Disabling GUI popups at user request ***]) AC_MSG_RESULT([*** WARNING: This may break apps! ***]) CFLAGS="$CFLAGS -DTSS_NO_GUI" AM_CONDITIONAL(HAVE_GTK, false) AM_CONDITIONAL(OPENSSL_UI, false) else AC_MSG_ERROR(["gtk", "openssl" and "none" are the only supported gui options for trousers]) fi # # The default port that the TCS daemon listens on # AC_SUBST(TCSD_DEFAULT_PORT, 30003) # # The RPC mechanism to build into both libtspi and the tcsd # # AC_SUBST(RPC, "soap") AC_SUBST(RPC, "tcstp") # # API= The TSS API level to build by default. # # To build a 1.1 TSS, set API=1.1 (./configure --with-api=1.1) # To build a 1.2 TSS, set API=1.2 (./configure --with-api=1.2) # # In order to build a custom TSS API, set API to the lowest API level that # contains the APIs you need. For instance, if you need only APIs that are # a subset of the TSS 1.1 API, set this to 1.1. If you need any of the 1.2 # APIs, you'll need to set this to 1.2. Send mail to trousers-tech@lists.sf.net # if you have questions. # API=1.2 AC_ARG_WITH(api, [AC_HELP_STRING([--with-api], [Version of the TSS API to build [default=1.2]])], [API=$withval], []) if test "x$API" != "x1.1" && test "x$API" != "x1.2"; then AC_MSG_ERROR(["1.1" and "1.2" are the only supported API versions for trousers. Custom API build options are available by editing 'configure.in'.]) fi if test "x$API" = "x1.1" || test "x$API" = "x1.2"; then # Tspi_Hash_GetHashValue,SetHashValue,UpdateHashValue AM_CONDITIONAL(TSS_BUILD_HASH, true) # Tspi_{Get|Set}Attribdata,{Get|Set}AttribUint32 AM_CONDITIONAL(TSS_BUILD_GETSET, true) # Tspi_TPM_GetRandom,StirRandom AM_CONDITIONAL(TSS_BUILD_RANDOM, true) # Tspi_GetCapability (for TSP and TCS capabilities) AM_CONDITIONAL(TSS_BUILD_CAPS, true) # Tspi_TPM_GetCapability (for TPM chip capabilities) AM_CONDITIONAL(TSS_BUILD_CAPS_TPM, true) # Tspi_GetPolicyObject, Tspi_Policy_SetSecret,FlushSecret,AssignToObject AM_CONDITIONAL(TSS_BUILD_POLICY, true) # Tspi_TPM_DirWrite,DirRead AM_CONDITIONAL(TSS_BUILD_DIR, true) # Tspi_TPM_GetEvent,GetEvents,GetEventLog AM_CONDITIONAL(TSS_BUILD_PCR_EVENTS, true) # Tspi_Hash_Sign,VerifySignature AM_CONDITIONAL(TSS_BUILD_SIGN, true) # Tspi_TPM_Quote AM_CONDITIONAL(TSS_BUILD_QUOTE, true) # Tspi_PcrComposite_{Set|Get}PcrValue,SelectPcrIndex AM_CONDITIONAL(TSS_BUILD_PCR_COMP, true) # Tspi_Data_Seal,Unseal AM_CONDITIONAL(TSS_BUILD_SEAL, true) # Tspi_ChangeAuth,ChangeAuthAsym AM_CONDITIONAL(TSS_BUILD_CHANGEAUTH, true) # Tspi_Data_Bind,Unbind AM_CONDITIONAL(TSS_BUILD_BIND, true) # Tspi_TPM_TakeOwnership,ClearOwner (REQ: EK) AM_CONDITIONAL(TSS_BUILD_OWN, true) # Tspi_TPM_CreateEndorsementKey,GetPubEndorsementKey AM_CONDITIONAL(TSS_BUILD_EK, true) # Tspi_Context_RegisterKey,UnregisterKey,LoadKeyByUUID,GetKeyByUUID,GetKeyByPublicInfo, # GetRegisteredKeysByUUID AM_CONDITIONAL(TSS_BUILD_PS, true) # Tspi_TPM_{Set|Get}Status AM_CONDITIONAL(TSS_BUILD_ADMIN, true) # Tspi_TPM_CollateIdentityRequest,ActivateIdentity AM_CONDITIONAL(TSS_BUILD_AIK, true) # Tspi_Key_CertifyKey AM_CONDITIONAL(TSS_BUILD_CERTIFY, true) # Tspi_TPM_CreateMaintenanceArchive,KillMaintenanceFeature,LoadMaintenancePubKey, # CheckMaintenancePubKey AM_CONDITIONAL(TSS_BUILD_MAINT, true) # Tspi_TPM_AuthorizeMigrationTicket,Key_CreateMigrationBlob,ConvertMigrationBlob AM_CONDITIONAL(TSS_BUILD_MIGRATION, true) # Tspi_Context_LoadKeyByBlob,Key_LoadKey,UnloadKey,CreateKey,WrapKey,GetPubKey AM_CONDITIONAL(TSS_BUILD_KEY, true) # Tspi_TPM_PcrExtend,PcrRead,PcrReset AM_CONDITIONAL(TSS_BUILD_PCR_EXTEND, true) # Tspi_TPM_SelfTestFull,CertifySelfTest,GetTestResult AM_CONDITIONAL(TSS_BUILD_SELFTEST, true) fi if test "x$API" = "x1.2"; then AM_CONDITIONAL(TSS_BUILD_TSS12, true) # Don't build DAA until the API is fixed - KEY AM_CONDITIONAL(TSS_BUILD_DAA, false) AM_CONDITIONAL(TSS_BUILD_PCR_COMP12, true) AM_CONDITIONAL(TSS_BUILD_COUNTER, true) AM_CONDITIONAL(TSS_BUILD_TICK, true) AM_CONDITIONAL(TSS_BUILD_TRANSPORT, true) AM_CONDITIONAL(TSS_BUILD_ASN1, true) AM_CONDITIONAL(TSS_BUILD_NV, true) AM_CONDITIONAL(TSS_BUILD_AUDIT, true) AM_CONDITIONAL(TSS_BUILD_SEALX, true) AM_CONDITIONAL(TSS_BUILD_DELEGATION, true) AM_CONDITIONAL(TSS_BUILD_QUOTE2,true) # CMK depends on MIGRATION AM_CONDITIONAL(TSS_BUILD_CMK, true) else AM_CONDITIONAL(TSS_BUILD_TSS12, false) AM_CONDITIONAL(TSS_BUILD_DAA, false) AM_CONDITIONAL(TSS_BUILD_PCR_COMP12, false) AM_CONDITIONAL(TSS_BUILD_COUNTER, false) AM_CONDITIONAL(TSS_BUILD_TICK, false) AM_CONDITIONAL(TSS_BUILD_TRANSPORT, false) AM_CONDITIONAL(TSS_BUILD_ASN1, false) AM_CONDITIONAL(TSS_BUILD_NV, false) AM_CONDITIONAL(TSS_BUILD_AUDIT, false) AM_CONDITIONAL(TSS_BUILD_SEALX, false) AM_CONDITIONAL(TSS_BUILD_DELEGATION, false) AM_CONDITIONAL(TSS_BUILD_QUOTE2,false) AM_CONDITIONAL(TSS_BUILD_CMK, false) fi # # There's no need to edit anything below, these conditionals control the building # of files that support the files above, which all contain TSS APIs # AM_CONDITIONAL(TSS_BUILD_NV_LIST, test -z $TSS_BUILD_NV_TRUE) AM_CONDITIONAL(TSS_BUILD_NV_SUPPORT, test -z $TSS_BUILD_NV_TRUE) AM_CONDITIONAL(TSS_BUILD_GET_FLAGS, test -z $TSS_BUILD_ADMIN_TRUE || \ test -z $TSS_BUILD_CAPS_TPM_TRUE) AM_CONDITIONAL(TSS_BUILD_PCRS_LIST, test -z $TSS_BUILD_SEAL_TRUE || \ test -z $TSS_BUILD_QUOTE_TRUE || \ test -z $TSS_BUILD_PCRS_TRUE || \ test -z $TSS_BUILD_PCR_COMP_TRUE || \ test -z $TSS_BUILD_SEALX_TRUE) AM_CONDITIONAL(TSS_BUILD_HASH_LIST, test -z $TSS_BUILD_SIGN_TRUE || test -z $TSS_BUILD_HASH_TRUE) AM_CONDITIONAL(TSS_BUILD_ENCDATA_LIST, test -z $TSS_BUILD_SEAL_TRUE || \ test -z $TSS_BUILD_CHANGEAUTH_TRUE || \ test -z $TSS_BUILD_BIND_TRUE || \ test -z $TSS_BUILD_SEALX_TRUE) AM_CONDITIONAL(TSS_BUILD_RSAKEY_LIST, test -z $TSS_BUILD_ADMIN_TRUE || \ test -z $TSS_BUILD_EK_TRUE || \ test -z $TSS_BUILD_MIGRATION_TRUE || \ test -z $TSS_BUILD_MAINT_TRUE || \ test -z $TSS_BUILD_CERTIFY_TRUE || \ test -z $TSS_BUILD_AIK_TRUE || \ test -z $TSS_BUILD_QUOTE_TRUE || \ test -z $TSS_BUILD_BIND_TRUE || \ test -z $TSS_BUILD_CHANGEAUTH_TRUE || \ test -z $TSS_BUILD_OWN_TRUE || \ test -z $TSS_BUILD_SIGN_TRUE || \ test -z $TSS_BUILD_PS_TRUE || \ test -z $TSS_BUILD_SEAL_TRUE || \ test -z $TSS_BUILD_DAA_TRUE || \ test -z $TSS_BUILD_KEY_TRUE || \ test -z $TSS_BUILD_SEALX_TRUE) AM_CONDITIONAL(TSS_BUILD_AUTH, test -z $TSS_BUILD_HASH_TRUE || \ test -z $TSS_BUILD_CAPS_TRUE || \ test -z $TSS_BUILD_CAPS_TPM_TRUE || \ test -z $TSS_BUILD_POLICY_TRUE || \ test -z $TSS_BUILD_DIR_TRUE || \ test -z $TSS_BUILD_PCR_EVENTS_TRUE || \ test -z $TSS_BUILD_SIGN_TRUE || \ test -z $TSS_BUILD_QUOTE_TRUE || \ test -z $TSS_BUILD_PCR_COMP_TRUE || \ test -z $TSS_BUILD_SEAL_TRUE || \ test -z $TSS_BUILD_SEALX_TRUE || \ test -z $TSS_BUILD_CHANGEAUTH_TRUE || \ test -z $TSS_BUILD_BIND_TRUE || \ test -z $TSS_BUILD_OWN_TRUE || \ test -z $TSS_BUILD_PS_TRUE || \ test -z $TSS_BUILD_ADMIN_TRUE || \ test -z $TSS_BUILD_AIK_TRUE || \ test -z $TSS_BUILD_EK_TRUE || \ test -z $TSS_BUILD_CERTIFY_TRUE || \ test -z $TSS_BUILD_MAINT_TRUE || \ test -z $TSS_BUILD_MIGRATION_TRUE || \ test -z $TSS_BUILD_KEY_TRUE || \ test -z $TSS_BUILD_PCR_EXTEND_TRUE || \ test -z $TSS_BUILD_SELFTEST_TRUE || \ test -z $TSS_BUILD_DAA_TRUE) AM_CONDITIONAL(TSS_BUILD_ASYM_CRYPTO, test -z $TSS_BUILD_AIK_TRUE || \ test -z $TSS_BUILD_CERTIFY_TRUE || \ test -z $TSS_BUILD_QUOTE_TRUE || \ test -z $TSS_BUILD_EK_TRUE || \ test -z $TSS_BUILD_CHANGEAUTH_TRUE || \ test -z $TSS_BUILD_BIND_TRUE || \ test -z $TSS_BUILD_OWN_TRUE || \ test -z $TSS_BUILD_SELFTEST_TRUE || \ test -z $TSS_BUILD_SIGN_TRUE || \ test -z $TSS_BUILD_KEY_TRUE || \ test -z $TSS_BUILD_DAA_TRUE) AM_CONDITIONAL(TSS_BUILD_SYM_CRYPTO, test -z $TSS_BUILD_AIK_TRUE || \ test -z $TSS_BUILD_TRANSPORT_TRUE) #GETTEXT_PACKAGE=trousers #AC_SUBST(GETTEXT_PACKAGE) #AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE") dnl Add the languages which your application supports here. #ALL_LINGUAS="" #AM_GLIB_GNU_GETTEXT # end Glade section AC_CHECK_HEADER(pthread.h, [AC_DEFINE(HAVE_PTHREAD_H, 1, [pthread header])]) AC_DISABLE_STATIC AC_PROG_CC AC_PROG_LIBTOOL AC_C_BIGENDIAN([AC_DEFINE(_BIG_ENDIAN, 1, [big-endian host])]) AC_CHECK_DECL(htole32, [AC_DEFINE(HTOLE_DEFINED, 1, [htole32 function is available])]) AC_CHECK_HEADER(sys/byteorder.h, [AC_DEFINE(HAVE_BYTEORDER_H, 1, [sys/byteorder.h header])]) AC_CHECK_FUNC(daemon, [ AC_DEFINE(HAVE_DAEMON, 1, [daemon function is available]) ]) if test "x${GCC}" = "xyes"; then CFLAGS="$CFLAGS -W -Wall -Wno-unused-parameter -Wsign-compare" fi CFLAGS="$CFLAGS -I../include \ -DTCSD_DEFAULT_PORT=${TCSD_DEFAULT_PORT} -DTSS_VER_MAJOR=${TSS_VER_MAJOR} \ -DTSS_VER_MINOR=${TSS_VER_MINOR} -DTSS_SPEC_MAJOR=${TSS_SPEC_MAJOR} \ -DTSS_SPEC_MINOR=${TSS_SPEC_MINOR}" #CFLAGS="$CFLAGS -I../include -std=c99 -pedantic -W -Wall" KERNEL_VERSION=`uname -r` AC_SUBST(CFLAGS) # When we build the rpms, prefix will be /usr. This'll do some things that make sense, # like put our sbin stuff in /usr/sbin and our library in /usr/lib. It'll do some other # things that don't make sense like put our config file in /usr/etc. So, I'll just hack # it here. If the --prefix option isn't specified during configure, let it all go to # /usr/local, even /usr/local/etc. :-P if test x"${prefix}" = x"/usr"; then sysconfdir="/etc" localstatedir="/var" mandir="/usr/share/man" elif test x"${prefix}" = x"NONE"; then localstatedir="/usr/local/var" fi AC_OUTPUT(dist/tcsd.conf \ dist/fedora/trousers.spec \ dist/trousers.spec \ Makefile \ src/Makefile \ src/include/Makefile \ src/tcs/Makefile \ src/tddl/Makefile \ src/tspi/Makefile \ src/trspi/Makefile \ src/tcsd/Makefile \ man/man8/tcsd.8 \ man/man5/tcsd.conf.5 \ dist/Makefile \ man/Makefile \ man/man3/Makefile \ man/man5/Makefile \ man/man8/Makefile) echo "CFLAGS=$CFLAGS" trousers-0.3.15/.git/0000775000175000017510000000000013750246207013612 5ustar deboradeboratrousers-0.3.15/.git/logs/0000775000175000017510000000000013663651711014561 5ustar deboradeboratrousers-0.3.15/.git/logs/refs/0000775000175000017510000000000013663651711015520 5ustar deboradeboratrousers-0.3.15/.git/logs/refs/heads/0000775000175000017510000000000013750236313016576 5ustar deboradeboratrousers-0.3.15/.git/logs/refs/heads/new-release0000664000175000017510000000052713750237473020744 0ustar deboradebora0000000000000000000000000000000000000000 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604402379 -0800 branch: Created from HEAD d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e 94144b0a1dcef6e31845d6c319e9bd7357208eb9 Debora Velarde Babb 1604402990 -0800 commit: Bumped version to 0.3.15 trousers-0.3.15/.git/logs/refs/heads/install-as-root0000664000175000017510000000105213750142313021543 0ustar deboradebora0000000000000000000000000000000000000000 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1604371527 -0800 branch: Created from HEAD 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 b49c6341d4fc5809733ecaa61ddd4593632134f2 Debora Velarde Babb 1604371603 -0800 am: dist: install tcsd.conf as root:tss 0640 b49c6341d4fc5809733ecaa61ddd4593632134f2 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604371656 -0800 commit (amend): dist: install tcsd.conf as root:tss 0640 trousers-0.3.15/.git/logs/refs/heads/jerry_no_optimize0000664000175000017510000000103413705244530022266 0ustar deboradebora0000000000000000000000000000000000000000 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1595230305 -0700 branch: Created from HEAD 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 aab1e2574346e75385bd68a746f99b23f5db852e Debora Velarde Babb 1595230408 -0700 am: trousers: don't use __no_optimize aab1e2574346e75385bd68a746f99b23f5db852e a0570c2d9452c68be0b02d9346b445e3fbe1b246 Debora Velarde Babb 1595230548 -0700 commit (amend): trousers: don't use __no_optimize trousers-0.3.15/.git/logs/refs/heads/no-opt0000664000175000017510000000053413736474746017761 0ustar deboradebora0000000000000000000000000000000000000000 e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1601861790 -0700 branch: Created from HEAD e74dd1d96753b0538192143adf58d04fcd3b242b 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1601862118 -0700 am: trousers: don't use __no_optimize trousers-0.3.15/.git/logs/refs/heads/resolve_build_failure0000664000175000017510000000103013670365657023077 0ustar deboradebora0000000000000000000000000000000000000000 8a867e82a537990d7c21bda22af832cf9fcf4772 Debora Velarde Babb 1591860368 -0700 branch: Created from HEAD 8a867e82a537990d7c21bda22af832cf9fcf4772 ba9c09c6695e4a212183cbe73359995e56fd5ad0 Debora Velarde Babb 1591860887 -0700 am: trousers: resolve build failure ba9c09c6695e4a212183cbe73359995e56fd5ad0 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1591864234 -0700 commit (amend): trousers: resolve build failure trousers-0.3.15/.git/logs/refs/heads/master0000664000175000017510000000523513750246207020024 0ustar deboradebora0000000000000000000000000000000000000000 8a867e82a537990d7c21bda22af832cf9fcf4772 Debora Velarde Babb 1590645705 -0700 clone: from ssh://dvelarde@git.code.sf.net/p/trousers/trousers 8a867e82a537990d7c21bda22af832cf9fcf4772 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594875527 -0700 pull: Fast-forward c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594972900 -0700 pull: Fast-forward 0a14b979064052d3263054488602fba3bf97883b a7b0cc3a6cf8ae3155b018086076031e139f9a92 Debora Velarde Babb 1594973796 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry a7b0cc3a6cf8ae3155b018086076031e139f9a92 197b5a6c7cb94649681c8a06bd35b658670535a6 Debora Velarde Babb 1594975107 -0700 pull: Merge made by the 'recursive' strategy. 197b5a6c7cb94649681c8a06bd35b658670535a6 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594975202 -0700 reset: moving to 0a14b979064052d3263054488602fba3bf97883b 0a14b979064052d3263054488602fba3bf97883b 3a00128fdeab7c4b6226745d87c1f2a35efd0f61 Debora Velarde Babb 1594975309 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry 3a00128fdeab7c4b6226745d87c1f2a35efd0f61 10b33821cfd79375cfdbe05123b2f7f6329eac3e Debora Velarde Babb 1594975620 -0700 reset: moving to 10b3382 10b33821cfd79375cfdbe05123b2f7f6329eac3e 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594975682 -0700 pull: Fast-forward 0a14b979064052d3263054488602fba3bf97883b 48d278e72969aa0de50ddf806d35f971575fbdf8 Debora Velarde Babb 1594975733 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry 48d278e72969aa0de50ddf806d35f971575fbdf8 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1594975822 -0700 pull: Merge made by the 'recursive' strategy. 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1601861744 -0700 pull: Fast-forward e74dd1d96753b0538192143adf58d04fcd3b242b 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1601862392 -0700 pull: Fast-forward 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604399203 -0800 pull: Fast-forward d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e 94144b0a1dcef6e31845d6c319e9bd7357208eb9 Debora Velarde Babb 1604406407 -0800 pull: Fast-forward trousers-0.3.15/.git/logs/refs/heads/indent0000664000175000017510000000025013737553574020017 0ustar deboradebora0000000000000000000000000000000000000000 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1602148220 -0700 branch: Created from HEAD trousers-0.3.15/.git/logs/refs/heads/cve0000664000175000017510000000113013715670620017275 0ustar deboradebora0000000000000000000000000000000000000000 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1597467802 -0700 branch: Created from HEAD 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 8b59a92d0177624e8b5ec6277987f30ba6b0596c Debora Velarde Babb 1597468476 -0700 commit: Correct multiple security issues that are present if the tcsd 8b59a92d0177624e8b5ec6277987f30ba6b0596c e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1597469038 -0700 commit (amend): Correct multiple security issues that are present if the tcsd trousers-0.3.15/.git/logs/refs/heads/michal-schmidt-patches0000664000175000017510000000025013705345216023034 0ustar deboradebora0000000000000000000000000000000000000000 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1595263630 -0700 branch: Created from HEAD trousers-0.3.15/.git/logs/refs/heads/manpage_cleanup0000664000175000017510000000025013703757770021652 0ustar deboradebora0000000000000000000000000000000000000000 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594875896 -0700 branch: Created from HEAD trousers-0.3.15/.git/logs/refs/heads/jerry_coverity0000664000175000017510000000315613704255005021603 0ustar deboradebora0000000000000000000000000000000000000000 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594876946 -0700 branch: Created from HEAD c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc 10b33821cfd79375cfdbe05123b2f7f6329eac3e Debora Velarde Babb 1594883625 -0700 am: trousers: clean up use after free in Transport_TerminateHandle 10b33821cfd79375cfdbe05123b2f7f6329eac3e c45422fa4f45c5faeed7b7ed63ca051707e338d5 Debora Velarde Babb 1594883625 -0700 am: trousers: fix potential use after free in ima_get_entry c45422fa4f45c5faeed7b7ed63ca051707e338d5 a4d6325947b9809c23e734f52df90d642f7aa12b Debora Velarde Babb 1594972171 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry a4d6325947b9809c23e734f52df90d642f7aa12b 8dd48ad75eb768b54a2bcb9271e953eaf091fad3 Debora Velarde Babb 1594972485 -0700 commit (amend): trousers: clean up use after free in Transport_TerminateHandle 8dd48ad75eb768b54a2bcb9271e953eaf091fad3 8d62ae267485857f79957d242ab207acbb401e19 Debora Velarde Babb 1594972544 -0700 commit (amend): trousers: resolve build failure 8d62ae267485857f79957d242ab207acbb401e19 15e4daa3dc3b7f071dc22cf41d55dc742e418ec9 Debora Velarde Babb 1594972565 -0700 commit (amend): trousers: clean up use after free in Transport_TerminateHandle 15e4daa3dc3b7f071dc22cf41d55dc742e418ec9 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594972657 -0700 commit (amend): trousers: clean up use after free in Transport_TerminateHandle trousers-0.3.15/.git/logs/refs/remotes/0000775000175000017510000000000013663651711017176 5ustar deboradeboratrousers-0.3.15/.git/logs/refs/remotes/origin/0000775000175000017510000000000013670367536020474 5ustar deboradeboratrousers-0.3.15/.git/logs/refs/remotes/origin/master0000664000175000017510000000211313750240533021671 0ustar deboradebora8a867e82a537990d7c21bda22af832cf9fcf4772 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1591865182 -0700 update by push c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594972808 -0700 update by push 0a14b979064052d3263054488602fba3bf97883b 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1594975904 -0700 update by push 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1597469448 -0700 update by push e74dd1d96753b0538192143adf58d04fcd3b242b 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1601862372 -0700 update by push 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604399164 -0800 update by push d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e 94144b0a1dcef6e31845d6c319e9bd7357208eb9 Debora Velarde Babb 1604403547 -0800 update by push trousers-0.3.15/.git/logs/refs/remotes/origin/HEAD0000664000175000017510000000031513663651711021110 0ustar deboradebora0000000000000000000000000000000000000000 8a867e82a537990d7c21bda22af832cf9fcf4772 Debora Velarde Babb 1590645705 -0700 clone: from ssh://dvelarde@git.code.sf.net/p/trousers/trousers trousers-0.3.15/.git/logs/HEAD0000664000175000017510000002540213750246207015205 0ustar deboradebora0000000000000000000000000000000000000000 8a867e82a537990d7c21bda22af832cf9fcf4772 Debora Velarde Babb 1590645705 -0700 clone: from ssh://dvelarde@git.code.sf.net/p/trousers/trousers 8a867e82a537990d7c21bda22af832cf9fcf4772 8a867e82a537990d7c21bda22af832cf9fcf4772 Debora Velarde Babb 1591860368 -0700 checkout: moving from master to resolve_build_failure 8a867e82a537990d7c21bda22af832cf9fcf4772 ba9c09c6695e4a212183cbe73359995e56fd5ad0 Debora Velarde Babb 1591860887 -0700 am: trousers: resolve build failure ba9c09c6695e4a212183cbe73359995e56fd5ad0 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1591864234 -0700 commit (amend): trousers: resolve build failure c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc 8a867e82a537990d7c21bda22af832cf9fcf4772 Debora Velarde Babb 1591865147 -0700 checkout: moving from resolve_build_failure to master 8a867e82a537990d7c21bda22af832cf9fcf4772 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1591865163 -0700 checkout: moving from master to resolve_build_failure c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc 8a867e82a537990d7c21bda22af832cf9fcf4772 Debora Velarde Babb 1594875505 -0700 checkout: moving from resolve_build_failure to master 8a867e82a537990d7c21bda22af832cf9fcf4772 c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594875527 -0700 pull: Fast-forward c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594875896 -0700 checkout: moving from master to manpage_cleanup c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594876906 -0700 checkout: moving from manpage_cleanup to master c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594876946 -0700 checkout: moving from master to jerry_coverity c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc 10b33821cfd79375cfdbe05123b2f7f6329eac3e Debora Velarde Babb 1594883625 -0700 am: trousers: clean up use after free in Transport_TerminateHandle 10b33821cfd79375cfdbe05123b2f7f6329eac3e c45422fa4f45c5faeed7b7ed63ca051707e338d5 Debora Velarde Babb 1594883625 -0700 am: trousers: fix potential use after free in ima_get_entry c45422fa4f45c5faeed7b7ed63ca051707e338d5 a4d6325947b9809c23e734f52df90d642f7aa12b Debora Velarde Babb 1594972171 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry a4d6325947b9809c23e734f52df90d642f7aa12b 8dd48ad75eb768b54a2bcb9271e953eaf091fad3 Debora Velarde Babb 1594972485 -0700 commit (amend): trousers: clean up use after free in Transport_TerminateHandle 8dd48ad75eb768b54a2bcb9271e953eaf091fad3 8d62ae267485857f79957d242ab207acbb401e19 Debora Velarde Babb 1594972544 -0700 commit (amend): trousers: resolve build failure 8d62ae267485857f79957d242ab207acbb401e19 15e4daa3dc3b7f071dc22cf41d55dc742e418ec9 Debora Velarde Babb 1594972565 -0700 commit (amend): trousers: clean up use after free in Transport_TerminateHandle 15e4daa3dc3b7f071dc22cf41d55dc742e418ec9 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594972657 -0700 commit (amend): trousers: clean up use after free in Transport_TerminateHandle 0a14b979064052d3263054488602fba3bf97883b c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc Debora Velarde Babb 1594972888 -0700 checkout: moving from jerry_coverity to master c9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594972900 -0700 pull: Fast-forward 0a14b979064052d3263054488602fba3bf97883b a7b0cc3a6cf8ae3155b018086076031e139f9a92 Debora Velarde Babb 1594973796 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry a7b0cc3a6cf8ae3155b018086076031e139f9a92 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594974301 -0700 checkout: moving from master to jerry_coverity 0a14b979064052d3263054488602fba3bf97883b a7b0cc3a6cf8ae3155b018086076031e139f9a92 Debora Velarde Babb 1594974491 -0700 checkout: moving from jerry_coverity to master a7b0cc3a6cf8ae3155b018086076031e139f9a92 197b5a6c7cb94649681c8a06bd35b658670535a6 Debora Velarde Babb 1594975107 -0700 pull: Merge made by the 'recursive' strategy. 197b5a6c7cb94649681c8a06bd35b658670535a6 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594975202 -0700 reset: moving to 0a14b979064052d3263054488602fba3bf97883b 0a14b979064052d3263054488602fba3bf97883b 3a00128fdeab7c4b6226745d87c1f2a35efd0f61 Debora Velarde Babb 1594975309 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry 3a00128fdeab7c4b6226745d87c1f2a35efd0f61 10b33821cfd79375cfdbe05123b2f7f6329eac3e Debora Velarde Babb 1594975620 -0700 reset: moving to 10b3382 10b33821cfd79375cfdbe05123b2f7f6329eac3e 0a14b979064052d3263054488602fba3bf97883b Debora Velarde Babb 1594975682 -0700 pull: Fast-forward 0a14b979064052d3263054488602fba3bf97883b 48d278e72969aa0de50ddf806d35f971575fbdf8 Debora Velarde Babb 1594975733 -0700 commit (amend): trousers: fix potential use after free in ima_get_entry 48d278e72969aa0de50ddf806d35f971575fbdf8 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1594975822 -0700 pull: Merge made by the 'recursive' strategy. 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1595230305 -0700 checkout: moving from master to jerry_no_optimize 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 aab1e2574346e75385bd68a746f99b23f5db852e Debora Velarde Babb 1595230408 -0700 am: trousers: don't use __no_optimize aab1e2574346e75385bd68a746f99b23f5db852e a0570c2d9452c68be0b02d9346b445e3fbe1b246 Debora Velarde Babb 1595230548 -0700 commit (amend): trousers: don't use __no_optimize a0570c2d9452c68be0b02d9346b445e3fbe1b246 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1595263582 -0700 checkout: moving from jerry_no_optimize to master 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1595263630 -0700 checkout: moving from master to michal-schmidt-patches 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1597467778 -0700 checkout: moving from michal-schmidt-patches to master 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1597467802 -0700 checkout: moving from master to cve 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 8b59a92d0177624e8b5ec6277987f30ba6b0596c Debora Velarde Babb 1597468476 -0700 commit: Correct multiple security issues that are present if the tcsd 8b59a92d0177624e8b5ec6277987f30ba6b0596c e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1597469038 -0700 commit (amend): Correct multiple security issues that are present if the tcsd e74dd1d96753b0538192143adf58d04fcd3b242b 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 Debora Velarde Babb 1601861727 -0700 checkout: moving from cve to master 44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1601861744 -0700 pull: Fast-forward e74dd1d96753b0538192143adf58d04fcd3b242b e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1601861790 -0700 checkout: moving from master to no-opt e74dd1d96753b0538192143adf58d04fcd3b242b 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1601862118 -0700 am: trousers: don't use __no_optimize 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 e74dd1d96753b0538192143adf58d04fcd3b242b Debora Velarde Babb 1601862384 -0700 checkout: moving from no-opt to master e74dd1d96753b0538192143adf58d04fcd3b242b 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1601862392 -0700 pull: Fast-forward 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1602148220 -0700 checkout: moving from master to indent 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1603961922 -0700 checkout: moving from indent to master 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1603962395 -0700 checkout: moving from master to new-release 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1604370374 -0800 checkout: moving from new-release to master 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1604371527 -0800 checkout: moving from master to install-as-root 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 b49c6341d4fc5809733ecaa61ddd4593632134f2 Debora Velarde Babb 1604371603 -0800 am: dist: install tcsd.conf as root:tss 0640 b49c6341d4fc5809733ecaa61ddd4593632134f2 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604371656 -0800 commit (amend): dist: install tcsd.conf as root:tss 0640 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 Debora Velarde Babb 1604399196 -0800 checkout: moving from install-as-root to master 6edef3777f9b9a26e63168bb81c8d4f4ddb17017 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604399203 -0800 pull: Fast-forward d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604402379 -0800 checkout: moving from master to new-release d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e 94144b0a1dcef6e31845d6c319e9bd7357208eb9 Debora Velarde Babb 1604402990 -0800 commit: Bumped version to 0.3.15 94144b0a1dcef6e31845d6c319e9bd7357208eb9 d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e Debora Velarde Babb 1604406399 -0800 checkout: moving from new-release to master d3fefa3e4717b72bd90aac8269d7cc0f00bbe62e 94144b0a1dcef6e31845d6c319e9bd7357208eb9 Debora Velarde Babb 1604406407 -0800 pull: Fast-forward trousers-0.3.15/.git/index0000664000175000017510000012577013750246207014660 0ustar deboradeboraDIRC^S^SYK,bvB\gdv .gitignore^SK^SKZYk,bxAjTB,AUTHORS_LѺ_LѺ[\Y{a[7׉| ChangeLog^Sϋ^Sϋ\LCY'agVfLICENSE^Sϋ^Sϋ]M(T+g>ᐃiO Makefile.am^S^S^⛲CK)wZSNEWS^ST^ST_Ak:٩?ǒP# NICETOHAVES^ST^ST`"u,>gqhgLREADME^SG^SGa#Yyڨٜ_!RREADME.selinux^S؅^S؅b]Hn-K'S=ʙTODO^S؅^S؅czœm!,<!`c> T bootstrap.sh_LѺ_LѺ:r1dy,*1ِ configure.ac_0ct؅_0ct؅ei^@2 &ܭdist/Makefile.am^S$A^S$AfQ+ e;lj7TfW+dist/tcsd.conf.in^Spy^Spym ﲘ2'J㩴:dist/trousers.spec.in^S5^S5nWYnJ}m_ doc/LTC-TSS_LLD_08_r2.pdf^Sۺ/^Sۺ/o)=g 'H~doc/LTC-TSS_LLD_08_r2.sxw^Sm^SmpіЙQ4/m/3(bldoc/TSS_programming_SNAFUs.txt^S>^S>qBv sman/Makefile.am^S>^S>r hD\$man/man3/Tspi_Context_CreateObject.3^SU#^SU#zmAzㅋE=\<ոXiF쨢"man/man3/Tspi_Context_FreeMemory.3^Sea^Sea{ *H&8)/Ԝ7v%man/man3/Tspi_Context_GetCapability.3^StP^StP|h#fQ/Y &mopc(man/man3/Tspi_Context_GetDefaultPolicy.3^S^S} ? PR&:=I?*man/man3/Tspi_Context_GetKeyByPublicInfo.3^S^S~ ƌ"፾x}Wjn7^b$man/man3/Tspi_Context_GetKeyByUUID.3^S^S qH>؈a[i,BY6/man/man3/Tspi_Context_GetRegisteredKeysByUUID.3^S[^S[ П IpJ( J e0man/man3/Tspi_Context_GetRegisteredKeysByUUID2.3^SY^SYˌ椯3q09}$man/man3/Tspi_Context_GetTpmObject.3^SY^SY H l']_^S[jԁnV%man/man3/Tspi_Context_LoadKeyByBlob.3^S^S 67/bQ.cO%man/man3/Tspi_Context_LoadKeyByUUID.3^S^S=hg>$]uq"$#man/man3/Tspi_Context_RegisterKey.3^S U^S U.X}RwtQ,@kH"ǹ%man/man3/Tspi_Context_UnregisterKey.3^S U^S U 1E$)]H磸; #man/man3/Tspi_DAA_IssueCredential.3^Sb^Sb2 JF,i~-Kqman/man3/Tspi_DAA_IssueInit.3^S^S iR| e !man/man3/Tspi_DAA_IssueSetup.3^S ^S gL~K^0F.a)man/man3/Tspi_DAA_IssuerKeyVerification.3^S ^S pT i^]X궔fW man/man3/Tspi_DAA_VerifyInit.3^S)O^S)O fp{5Ј#man/man3/Tspi_DAA_VerifySignature.3^S+k^S+k Ƞ}h\cܩ'man/man3/Tspi_Data_Bind.3^S:^S: i$|m1man/man3/Tspi_Data_Seal.3^SI ^SI  i}⨘Ց*te$-L}man/man3/Tspi_Data_Unbind.3^SI ^SI  U5fӦAm'Od aX S0man/man3/Tspi_Data_Unseal.3^SY2I^SY2I EMpom|Z !man/man3/Tspi_DecodeBER_TssBlob.3^Sht^Sht )jL\uq4 <!man/man3/Tspi_EncodeDER_TssBlob.3^Sw^Sw C;YCfLV^man/man3/Tspi_GetAttribData.3^Sw^Sw ۘSw'v&>man/man3/Tspi_Hash_Sign.3^S^S 5z򱈗sI} $man/man3/Tspi_Hash_UpdateHashValue.3^S^S GEteXk$man/man3/Tspi_Hash_VerifySignature.3^S^SKwIj6yman/man3/Tspi_Key_CertifyKey.3^SD=^SD=  I/B0f:[:or(man/man3/Tspi_Key_ConvertMigrationBlob.3^S{^S{'6NQN-bдsman/man3/Tspi_Key_CreateKey.3^SȺ^SȺ S?5"F"'man/man3/Tspi_Key_CreateMigrationBlob.3^SȺ^SȺ˜ajI KyJ man/man3/Tspi_Key_GetPubKey.3^S ^S T$m//yH>99man/man3/Tspi_Key_LoadKey.3^SM7^SM7BH$e Qman/man3/Tspi_Key_UnloadKey.3^SM7^SM7 g<*-+$q3nman/man3/Tspi_Key_WrapKey.3^Sv^Sv n(HfUd(man/man3/Tspi_PcrComposite_GetPcrValue.3^S.Ѵ^S.ѴH+LQp+man/man3/Tspi_PcrComposite_SelectPcrIndex.3^S.Ѵ^S.Ѵր]*J7Z (man/man3/Tspi_PcrComposite_SetPcrValue.3^S>^S>k.0mG`W܉%man/man3/Tspi_Policy_AssignToObject.3^SMV1^SMV1Z]軳b=g"man/man3/Tspi_Policy_FlushSecret.3^S\p^S\p GJ-φ7~:[1 man/man3/Tspi_Policy_SetSecret.3^S\p^S\p js(kt?\Zӂman/man3/Tspi_SetAttribData.3^Skڮ^Skڮ <6 #2: man/man3/Tspi_SetAttribUint32.3^S{^S{ M| 6|ώ^Qx4n-:,man/man3/Tspi_TPM_AuthorizeMigrationTicket.3^S{^S{#=B Eۿ&man/man3/Tspi_TPM_CMKSetRestrictions.3^S_+^S_+jZ "=eLθr#man/man3/Tspi_TPM_CertifySelfTest.3^Si^Si \!d?}qG4|k&*man/man3/Tspi_TPM_CheckMaintenancePubKey.3^Si^SinGMMUj7D.man/man3/Tspi_TPM_ClearOwner.3^S^S 0`vw;,*man/man3/Tspi_TPM_CollateIdentityRequest.3^S%^S% \w,u䙺o<턽(man/man3/Tspi_TPM_CreateEndorsementKey.3^S%^S% T& Pyۇd,man/man3/Tspi_TPM_CreateMaintenanceArchive.3^Sh%^Sh%YBs+tP!-+ n+man/man3/Tspi_TPM_DAA_JoinCreateDaaPubKey.3^S֪d^S֪dB0R[d1{Im man/man3/Tspi_TPM_DAA_JoinInit.3^S^S /5l6*U+man/man3/Tspi_TPM_DAA_JoinStoreCredential.3^S.^S.s`)5wQVman/man3/Tspi_TPM_DAA_Sign.3^S.^S. EAjRzuu|[Ȍ'man/man3/Tspi_TPM_DirRead.3^Sq^Sq{~: Fu5NʻYo< man/man3/Tspi_TPM_DirWrite.3^S]^S] |j7ڃKr nѶ"man/man3/Tspi_TPM_GetAuditDigest.3^S]^S]qE"kT_Uܢ{!man/man3/Tspi_TPM_GetCapability.3^S"^S"Z]wPf%n#man/man3/Tspi_TPM_GetEvent.3^S27^S27ϸB5p#~aS man/man3/Tspi_TPM_GetEventLog.3^S27^S27Ճ6>/SZ1y{Yman/man3/Tspi_TPM_GetEvents.3^SAz^SAz ҚQ1[8Au7(man/man3/Tspi_TPM_GetPubEndorsementKey.3^SPX^SPX Փvބr|Oceman/man3/Tspi_TPM_GetRandom.3^S_^S_P.Nš!t1]man/man3/Tspi_TPM_GetStatus.3^S_^S_Y@D!"{)!man/man3/Tspi_TPM_GetTestResult.3^So@^So@6z*aGHա+*man/man3/Tspi_TPM_KillMaintenanceFeature.3^S~^S~ 7ӓrO @)man/man3/Tspi_TPM_LoadMaintenancePubKey.3^S~^S~+Vd&ST }!vl| %man/man3/Tspi_TPM_OwnerGetSRKPubKey.3^SR^SR I7U-c,Puga:man/man3/Tspi_TPM_PcrExtend.3^S^S,qc5y┭man/man3/Tspi_TPM_PcrRead.3^S^Sl[u0*"Z3~man/man3/Tspi_TPM_Quote.3^SI^SI b0B߈˫man/man3/Tspi_TPM_Quote2.3^S ^S ;*3"<4< man/man3/Tspi_TPM_SelfTestFull.3^SK^SK1"kw lG( ,man/man3/Tspi_TPM_SetStatus.3^SK^SK C9Κiqtij͝NKman/man3/Tspi_TPM_StirRandom.3^S^S  x1>%UH 0=x!man/man3/Tspi_TPM_TakeOwnership.3^SR^SR 2y]!8j71man/man5/Makefile.am^SR^SR KK \ɍ]l,6c'man/man5/tcsd.conf.5.in^S^S -BZ4"1lOtman/man8/Makefile.am^SF^SFuNs. jl5-man/man8/tcsd.8.in^S^S+.Oa>0Yn9)src/Makefile.am^S^Sd{r\ӞT'k(SQsrc/include/Makefile.am^S&[^S&[ٌ|^.osrc/include/auth_mgr.h^S5^S5v]wenGQտsrc/include/authsess.h^SD@^SD@nZt]h";ix?t#0ޏsrc/include/biosem.h^SD@^SD@h&\,+z{$[msrc/include/capabilities.h^ST"~^ST"~}83FƦgpv0]1&src/include/daa/anonymity_revocation.h^Scd^Scd/Mi?2 src/include/daa/bi.h^Sr^SramK^k .&src/include/daa/bi_gmp.h^S9^S9#ۋjF}T|"3src/include/daa/bi_openssl.h^S9^S9BD|u1KGȌwsrc/include/daa/daa_parameter.h^S+x^S+x([v*VÅxN)tJsrc/include/daa/daa_structs.h^S+x^S+xYveqsrc/include/daa/issuer.h^Sm^Sm}+D}ȭx@src/include/daa/key_correct.h^S^S'_Dȴ'&$src/include/daa/list.h^S^S t"N㾡I ڽ3̦<src/include/daa/platform.h^S4^S4  w0"Y>src/include/daa/verifier.h^S4r^S4r!T]aٵ ¾̽Žsrc/include/hosttable.h^S4r^S4r"gwAC:]2src/include/imaem.h^Sv^Sv'2iai/۸©Rsrc/include/linux/tpm.h^Sv^Sv/Aפ E-# src/include/memmgr.h^S^SZ /X:|stV1src/include/obj.h^S^S[dYh'@csrc/include/obj_context.h^S.^S.\M_|~KόzfHB src/include/obj_daa.h^S.^S.]!٭y(H7Tsrc/include/obj_daaarakey.h^S =l^S =l^5z#誠dvfxSoCOsrc/include/obj_daacred.h^S =l^S =l_|oÊaƠsrc/include/obj_daaissuerkey.h^S =l^S =lALO뼮GmrmA&8src/include/obj_delfamily.h^S^S(xXCʯ%C{ #|src/include/obj_encdata.h^S^SN![:E)_4src/include/obj_hash.h^S)^S)OЂ!jYyaXsrc/include/obj_migdata.h^S)^S) /B顫&ՙS.src/include/obj_nv.h^S9'^S9'Dl@Z'j;+src/include/obj_pcrs.h^S9'^S9',ؿthBq%src/include/obj_policy.h^SHFf^SHFf OWْ í$~44src/include/obj_rsakey.h^SHFf^SHFf  ȀS8z',*p?src/include/obj_tpm.h^SHFf^SHFf hBy8DuoeR(-ޓ=src/include/portable_endian.h^SW^SW8jP\~w-Ktxsrc/include/req_mgr.h^SW^SW 2U^j^hK9Asrc/include/rpc_tcstp.h^Sf^Sf1 Wu@$Sаugdsrc/include/rpc_tcstp_tcs.h^Sf^Sf]-SJ̖OxپI!M2Lsrc/include/rpc_tcstp_tsp.h_zzdi_zzdiñqaʝzUEsrc/include/spi_utils.h^Sv "^Sv " IElbIU^fsrc/include/tcs_aik.h^Sv "^Sv ")DjvfÈgJ)bsrc/include/tcs_context.h^SO`^SO`DC-Vz9] 4osrc/include/tcs_int_literals.h^SO`^SO`B˨7?2L`src/include/tcs_key_ps.h^S^S !E=iߔLpsrc/include/tcs_tsp.h^S^SLNUR{ӈmTsrc/include/tcs_utils.h_އ _އ \†-&ssrc/include/tcsd.h^S^S"HD?} )VaRgsrc/include/tcsd_ops.h^S^S@ K ^EH)csrc/include/tcsd_wrap.h^S^SK![+tNk2}} src/include/tcsem.h^S^S fcď2?rogsrc/include/tcslog.h^SXZ^SXZ fzoXqFj*]src/include/tcsps.h^SXZ^SXZ[*%_.7ݛisrc/include/tddl.h^Sњ^Sњ|n6mUasrc/include/tsp_audit.h^S^S9Γ԰$^Oz˅src/include/tsp_delegate.h^SaT^SaT3l4k_+\src/include/tsp_seal.h^SaT^SaTӼ KeCf(vص=src/include/tsp_tcsi_param.h^S^S̻/gA_aS_^*src/include/tsplog.h^S^S .Fsrc/include/tspps.h^S^Sn@[xhjPRo˖)"\`psrc/include/tss/TSP.idl^S^S%d(0Dd:``uVx#src/include/tss/compat11b.h^S-(^S-(IZte7!O.b src/include/tss/platform.h^S-(^S-( M^,݄:%f^Psrc/include/tss/tcpa_defines.h^S-(^S-(zc"p7ܣ\DzPLJbsrc/include/tss/tcpa_error.h^SGQktcsrc/include/tss/tcs_error.h^SZ^SZ0kƎ\a &Qsrc/include/tss/tcs_structs.h^SZ^SZ ~,h&W<@src/include/tss/tcs_typedef.h^Sj1 ^Sj1 ;<ΫRKwO">a7src/include/tss/tddl_error.h^Sj1 ^Sj1  !_.ͪvf߉{|src/include/tss/tddlapi_error.h^Sj1 ^Sj1  R.GW/ۢsrc/include/tss/tddli.h^SysH^SysH~x:q2UnU+a?D7)src/include/tss/tpm.h^SysH^SysHNsԯO(f̮src/include/tss/tpm_error.h^S^S'X˚wn&'Asrc/include/tss/tpm_ordinal.h^S^Su'7͉q :E|ʍsrc/include/tss/tspi.h^S^S %465Pusrc/include/tss/tss_defines.h^S^S <30ܟ^B-,src/include/tss/tss_error.h^S:^S: }e\qc^P!"src/include/tss/tss_error_basics.h^S|B^S|B =FLK3lS1c.src/include/tss/tss_structs.h^Sž^Sž =>J%ˡvԧsrc/include/tss/tss_typedef.h^Sž^SžHބƩ(' J$*#\src/tcs/Makefile.am^S^SBTo-ג &src/tcs/crypto/openssl/crypto.c^SB^SBk= M X"P [*"+ src/tcs/log.c^SB^SB0n{%cc=,hn޲|Jsrc/tcs/ps/ps_utils.c_zxpd_zxpdU ZÐ}KYqJ)gsrc/tcs/ps/tcsps.c^Sz^SzOj̊\ Nyάtsrc/tcs/rpc/tcstp/rpc.c^Sz^Sz%p㾉A<src/tcs/rpc/tcstp/rpc_admin.c^Sz^SzW޺$$>src/tcs/rpc/tcstp/rpc_aik.c^S ^S F2r=vpw!csrc/tcs/rpc/tcstp/rpc_audit.c^S ^S  q3qXb恱} A3lsrc/tcs/rpc/tcstp/rpc_auth.c^S ^S  Rx8 t_2? rsrc/tcs/rpc/tcstp/rpc_bind.c^S!K^S!KoOK ZFssrc/tcs/rpc/tcstp/rpc_caps.c^S!K^S!KFn!Vkc-1 src/tcs/rpc/tcstp/rpc_caps_tpm.c^S06^S06 \Tڶ]@:asrc/tcs/rpc/tcstp/rpc_certify.c^S06^S06B2j%c="src/tcs/rpc/tcstp/rpc_changeauth.c^S06^S06A$NڡF;src/tcs/rpc/tcstp/rpc_cmk.c^S?u^S?ub r6DAM Ԍsrc/tcs/rpc/tcstp/rpc_context.c^S?u^S?u BtPUZБ%src/tcs/rpc/tcstp/rpc_counter.c^S?u^S?u ? s}s0Q 0hsrc/tcs/rpc/tcstp/rpc_daa.c^SO^SO!=&bY{7ERϿ08 src/tcs/rpc/tcstp/rpc_delegate.c^SO^SO" G#];о 0src/tcs/rpc/tcstp/rpc_dir.c^S^T^S^T# qBB=src/tcs/rpc/tcstp/rpc_ek.c^S^T^S^T$VĦdy1)1n6TYsrc/tcs/rpc/tcstp/rpc_evlog.c^S^T^S^T%3M?V!FGsrc/tcs/rpc/tcstp/rpc_key.c^Sm0^Sm0&9}wJsrc/tcs/rpc/tcstp/rpc_maint.c^Sm0^Sm0'"QN#!ꎟKU!src/tcs/rpc/tcstp/rpc_migration.c^S|o^S|o("COGl)n>src/tcs/rpc/tcstp/rpc_nv.c^S|o^S|o)Vق]?Rp6%sadsrc/tcs/rpc/tcstp/rpc_oper.c^S|o^S|o*\>bɝl' .@Hsrc/tcs/rpc/tcstp/rpc_own.c^S^S+ eh۱QssSm"src/tcs/rpc/tcstp/rpc_pcr_extend.c^S^S,X&)!src/tcs/rpc/tcstp/rpc_transport.c^S$^S$5 :ϻssuu[PA8Τsrc/tcs/tcsi_aik.c^SRx^SRxK2gGPb;oosrc/tcs/tcsi_audit.c^SRx^SRxL J^anł-3= src/tcs/tcsi_auth.c^Sa^SaM|d8tYsrc/tcs/tcsi_bind.c^Sa^SaN-vj,e7%bdsrc/tcs/tcsi_caps.c^Sa^SaO ͪ72&src/tcs/tcsi_caps_tpm.c^SpV^SpVPޏ7h7|Uɿ?4src/tcs/tcsi_certify.c^SpV^SpVQ(Y23MI5FmӇLsrc/tcs/tcsi_changeauth.c^S?^S?R ?4.M8-)Psrc/tcs/tcsi_cmk.c^S?^S?Sq`l ?Adg>src/tcs/tcsi_context.c^S^ST8Ϣiáq]src/tcs/tcsi_counter.c^S^SU)?K4o;YHv\0"d}src/tcs/tcsi_daa.c^S^SV#e'4!UIxsrc/tcs/tcsi_delegate.c^S^SW _P0]% )C_ <src/tcs/tcsi_dir.c^S^SX848Iwbp 1|src/trspi/crypto/openssl/rsa.c^SU^SUu"1];8^nÖ$src/trspi/crypto/openssl/symmetric.c^Se!?^Se!?v^6\#WbȠsrc/trspi/trousers.c^Se!?^Se!?w W sN/F*̤!src/tspi/daa/big_integer/bi_gmp.c^S^S{PQ/1c:a%src/tspi/daa/big_integer/bi_openssl.c^S^S|1¯) Ff,^n)src/tspi/daa/big_integer/test/Makefile.am^S^S}M/9g]M-j6)src/tspi/daa/big_integer/test/multi_exp.c^S^S~0$LçGwȾ"u$src/tspi/daa/big_integer/test/test.c^S^SPpB΢:src/tspi/daa/daa_anonymityrevocation/csencryption_result.c^S*9^S*92Ӓs>_Z#҂:K`src/tspi/daa/daa_debug.c^S*9^S*9O6Д|8gKBL@src/tspi/daa/daa_debug.h^Slw^SlwpnM'ҺfGwu@' *src/tspi/daa/daa_issuer/issue_credential.c^Slw^SlwxآKZ ٻ 5& %src/tspi/daa/daa_issuer/issuer_init.c^Slw^SlwDg5޾M@V&src/tspi/daa/daa_issuer/issuer_setup.c^S^S@/-Y](%/src/tspi/daa/daa_issuer/key_correctness_proof.c^S^SXOH;Kf!src/tspi/gtk/callbacks.h^S<-^S<-,u•aSB|9)wGsrc/tspi/gtk/interface.c^S+~k^S+~k*P}F:Dy7M HhCysrc/tspi/gtk/interface.h^S+~k^S+~k }v_LKÎDcabmBsrc/tspi/gtk/main.c^S:^S:,liUw(5aEesrc/tspi/gtk/support.c^S:^S:2;#'5_src/tspi/gtk/support.h^S:^S:,ɮ. u%N誯vsrc/tspi/log.c^SJ^SJX4٣)5EyTsrc/tspi/obj.c^SJ^SJb]̝ g JGsrc/tspi/obj_context.c^SYE&^SYE& ڠsc=OfBь˫;֐ src/tspi/obj_daa.c^SYE&^SYE& |mox4鑮Ysrc/tspi/obj_delfamily.c^SYE&^SYE&,@b].-+ Psrc/tspi/obj_encdata.c^She^She %hsGKQOhEsrc/tspi/obj_hash.c^She^Sheo˧(W ݠ]ksrc/tspi/obj_migdata.c^Swɤ^SwɤK9O(m cs2 Ssrc/tspi/obj_nv.c^Swɤ^Swɤ[dv.K6hҒsrc/tspi/obj_pcrs.c^S ^S IJ,8o5S_src/tspi/obj_policy.c^S ^S >ǚn;(%  ysrc/tspi/obj_rsakey.c^SN ^SN .XkXK 'Z;?"src/tspi/obj_tpm.c^SN ^SN |%Auh<$u0s$mWsrc/tspi/ps/ps_utils.c^S_^S_~= f+|h ̤+j~=src/tspi/ps/tspps.c^S_^S_V4m 1$  src/tspi/rpc/hosttable.c^Sҝ^SҝM>c /\src/tspi/rpc/tcs_api.c^Sҝ^Sҝ;9L퍠a ~73M4-src/tspi/rpc/tcstp/rpc.c^S^S$TeؐtBWjsrc/tspi/rpc/tcstp/rpc_admin.c^S^S)s@WԭǨʆ,ڶ]src/tspi/rpc/tcstp/rpc_aik.c^S^S[Jb1^(Vx|src/tspi/rpc/tcstp/rpc_audit.c^SW^SW A&mHYv1,UFm{{src/tspi/rpc/tcstp/rpc_auth.c^SW^SWyXؙl3Ƥew\̆src/tspi/rpc/tcstp/rpc_bind.c^SY^SY&XU8>Usrc/tspi/rpc/tcstp/rpc_caps.c^SY^SY!WR 2A-k|!src/tspi/rpc/tcstp/rpc_caps_tpm.c^SY^SY7< )X_^ src/tspi/rpc/tcstp/rpc_certify.c^Sۗ^SۗvmJ&8=Pn#src/tspi/rpc/tcstp/rpc_changeauth.c^Sۗ^Sۗ3n`gjqGU?8src/tspi/rpc/tcstp/rpc_cmk.c^Sۗ^SۗPdۜD src/tspi/rpc/tcstp/rpc_context.c^S^SPֲv{*J Ӕ src/tspi/rpc/tcstp/rpc_counter.c^S^S0)|y\W%src/tspi/rpc/tcstp/rpc_daa.c^S^S6ۮ,>^͟s^i!src/tspi/rpc/tcstp/rpc_delegate.c^S`^S` }:% (src/tspi/rpc/tcstp/rpc_dir.c^S`^S`$WSWaڏXS^EFsrc/tspi/rpc/tcstp/rpc_ek.c^SS^SSrVy^%dGת=easrc/tspi/rpc/tcstp/rpc_evlog.c^SS^SS( :!qݚuwjv 0src/tspi/rpc/tcstp/rpc_key.c^SS^SSxu\;ڔ(src/tspi/rpc/tcstp/rpc_maint.c^S.^S.'.!6ߊ#T/"src/tspi/rpc/tcstp/rpc_migration.c^S.^S."AlV+'m<>;p}9src/tspi/rpc/tcstp/rpc_nv.c^S>&^S>&7b)`OʛF*Vsrc/tspi/rpc/tcstp/rpc_oper.c^S>&^S>&v}!1 H3$ws^src/tspi/rpc/tcstp/rpc_own.c^SMi^SMi Z>@ohs#src/tspi/rpc/tcstp/rpc_pcr_extend.c^SMi^SMi*:MpO0bn3xvhIsrc/tspi/rpc/tcstp/rpc_ps.c^SMi^SMi {9ޛH W%ϡsrc/tspi/rpc/tcstp/rpc_quote.c^S\M^S\MyHjҋE$Տȶ 9src/tspi/rpc/tcstp/rpc_quote2.c^S\M^S\M =R?09H dsrc/tspi/rpc/tcstp/rpc_random.c^S\M^S\M+~(]s{3YQsrc/tspi/rpc/tcstp/rpc_seal.c^Sk^Sk< "y8i] ֙!src/tspi/rpc/tcstp/rpc_selftest.c^Sk^Sk ܯG8HN6H}Hcsrc/tspi/rpc/tcstp/rpc_sign.c^S{/^S{/jG6.a.s ͊3%%src/tspi/rpc/tcstp/rpc_tick.c^S{/^S{/.nii֑ V.K{Bf"src/tspi/rpc/tcstp/rpc_transport.c^Sr ^Sr 1ހ~ Hsrc/tspi/spi_utils.c^Sr ^Sr B8[XEj}%[Qosrc/tspi/ssl_ui.c^Sr ^Sr ċla҄9+|8cdZz<src/tspi/tsp_admin.c^SG^SGM[hk鰫ysrc/tspi/tsp_aik.c^SG^SG SrDctlaƫOsrc/tspi/tsp_asym.c^SG^SGA_l c!C"src/tspi/tsp_audit.c_Z>_Z>Z Vjj !Oզsrc/tspi/tsp_auth.c^S^Sd8eHjXJsrc/tspi/tsp_bind.c^S8^S8mEt ]$ 3܄src/tspi/tsp_caps.c^S8^S8嶎\`dă~hsrc/tspi/tsp_caps_tpm.c^S8^S8 jXmc7{F~src/tspi/tsp_certify.c^S{^S{5{O -84wrsrc/tspi/tsp_changeauth.c_zzt(_zzt(y'i6bHԂD"src/tspi/tsp_context_mem.c^SֽA^SֽAtBvwl2;[Б36src/tspi/tsp_counter.c^SֽA^SֽAGsλku?u6src/tspi/tsp_daa.c^SֽA^SֽA`; O,~w@bksrc/tspi/tsp_delegate.c^S^S|[F 91ݠ6'zsrc/tspi/tsp_dir.c^S^S L*&Ck,osrc/tspi/tsp_ek.c^S^S1t.?Jv۴!src/tspi/tsp_get_flags.c^SA^SA e؂Rzmhv>35ßsrc/tspi/tsp_key.c^SA^SA.>Pg )]Մ ݜsrc/tspi/tsp_maint.c^S^Su?LgjV{qLgsrc/tspi/tsp_migration.c^S^SQl<8 $/src/tspi/tsp_nv.c^S^S' +\z@src/tspi/tsp_oper.c^S;^S;"w뇓%M%6src/tspi/tsp_own.c^S;^S;hi@#Y}żW>src/tspi/tsp_pcr.c^S;^S; z|=7TLJh͚|-src/tspi/tsp_pcr_extend.c^S#y^S#y z 2Z?0src/tspi/tsp_policy.c^S#y^S#yrn>3:1ksrc/tspi/tsp_ps.c^S2J^S2J $&ɾnYo翵^$src/tspi/tsp_quote.c^S2J^S2J vA 2-~src/tspi/tsp_quote2.c^S2J^S2JLh2@ȅ A=src/tspi/tsp_random.c^SA^SA҉ !:Խh"src/tspi/tsp_seal.c^SA^SA @Z']-ɗBChsrc/tspi/tsp_selftest.c^SA^SA:3f>@5ӔU3csrc/tspi/tsp_sign.c^SP5^SP5 46k|j#/Bqsrc/tspi/tsp_tcsi_param.c^SP5^SP5  â¦-PbKsrc/tspi/tsp_tick.c^S`s^S`saGa;-gdqAsrc/tspi/tsp_transport.c^S`s^S`s/D4src/tspi/tspi_changeauth.c^Sm^Sm9+m헺x*yWpT&esrc/tspi/tspi_cmk.c^Sm^Sm$~ݶxd>2src/tspi/tspi_context.c^Sm^SmԔ^ܮ/i.ssrc/tspi/tspi_counter.c^S\^S\aIψRxsysrc/tspi/tspi_daa.c^S\^S\7I1D[isrc/tspi/tspi_delegate.c^S^S {m01rǙC9src/tspi/tspi_dir.c^S^S3o͈!T|2bsrc/tspi/tspi_ek.c^S^Sg?rq$n8src/tspi/tspi_getset.c^S)^S)RPvu&j asrc/tspi/tspi_hash.c^S)^S)QM{ vہ6_OYFusrc/tspi/tspi_key.c^S#g^S#g e3~ҫ{ըsrc/tspi/tspi_maint.c^S#g^S#g.9q'd!RPXTCisrc/tspi/tspi_migration.c^S#g^S#g@%Ϣ=F*O%src/tspi/tspi_nv.c^Se^Se \۟AU@Gbsrc/tspi/tspi_oper.c^Se^Se jDX8Y/PD%tcsrc/tspi/tspi_own.c^Se^Se xu.?H"I~ٌ3src/tspi/tspi_pcr_comp.c^S^S A3ҾT|s:KXBusrc/tspi/tspi_pcr_comp12.c^S^S  $`q_(I^mH&z src/tspi/tspi_pcr_events.c^S^S0a!ݪL;tj;*src/tspi/tspi_pcr_extend.c^S#^S# ,M?FNBK~src/tspi/tspi_policy.c^S#^S#A+# nS6/src/tspi/tspi_ps.c^S,a^S,a4 x`i+#src/tspi/tspi_quote.c^S,a^S,a!\H}m'lDj!dxsrc/tspi/tspi_quote2.c^S,a^S,afynvO Osrc/tspi/tspi_random.c^S&n^S&n%ە% k}: %r_ލsrc/tspi/tspi_seal.c^S&n^S&nͺQc?Ҿ"src/tspi/tspi_selftest.c^S5^S5T${17}%}src/tspi/tspi_sign.c^S5^S5,e΁}Z`src/tspi/tspi_tick.c^S5^S5 ͽlN}ЋoJlsrc/tspi/tspi_transport.cyTI5n%c/dev/null 2>&1 then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi # If you want to allow non-ascii filenames set this variable to true. allownonascii=$(git config hooks.allownonascii) # Redirect output to stderr. exec 1>&2 # Cross platform projects tend to avoid non-ascii filenames; prevent # them from being added to the repository. We exploit the fact that the # printable range starts at the space character and ends with tilde. if [ "$allownonascii" != "true" ] && # Note that the use of brackets around a tr range is ok here, (it's # even required, for portability to Solaris 10's /usr/bin/tr), since # the square bracket bytes happen to fall in the designated range. test $(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 then echo "Error: Attempt to add a non-ascii file name." echo echo "This can cause problems if you want to work" echo "with people on other platforms." echo echo "To be portable it is advisable to rename the file ..." echo echo "If you know what you are doing you can disable this" echo "check using:" echo echo " git config hooks.allownonascii true" echo exit 1 fi # If there are whitespace errors, print the offending file names and fail. exec git diff-index --check --cached $against -- trousers-0.3.15/.git/hooks/post-update.sample0000775000175000017510000000027513663651671020424 0ustar deboradebora#!/bin/sh # # An example hook script to prepare a packed repository for use over # dumb transports. # # To enable this hook, rename this file to "post-update". exec git update-server-info trousers-0.3.15/.git/hooks/pre-rebase.sample0000775000175000017510000001152713663651671020206 0ustar deboradebora#!/bin/sh # # Copyright (c) 2006, 2008 Junio C Hamano # # The "pre-rebase" hook is run just before "git rebase" starts doing # its job, and can prevent the command from running by exiting with # non-zero status. # # The hook is called with the following parameters: # # $1 -- the upstream the series was forked from. # $2 -- the branch being rebased (or empty when rebasing the current branch). # # This sample shows how to prevent topic branches that are already # merged to 'next' branch from getting rebased, because allowing it # would result in rebasing already published history. publish=next basebranch="$1" if test "$#" = 2 then topic="refs/heads/$2" else topic=`git symbolic-ref HEAD` || exit 0 ;# we do not interrupt rebasing detached HEAD fi case "$topic" in refs/heads/??/*) ;; *) exit 0 ;# we do not interrupt others. ;; esac # Now we are dealing with a topic branch being rebased # on top of master. Is it OK to rebase it? # Does the topic really exist? git show-ref -q "$topic" || { echo >&2 "No such branch $topic" exit 1 } # Is topic fully merged to master? not_in_master=`git rev-list --pretty=oneline ^master "$topic"` if test -z "$not_in_master" then echo >&2 "$topic is fully merged to master; better remove it." exit 1 ;# we could allow it, but there is no point. fi # Is topic ever merged to next? If so you should not be rebasing it. only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` only_next_2=`git rev-list ^master ${publish} | sort` if test "$only_next_1" = "$only_next_2" then not_in_topic=`git rev-list "^$topic" master` if test -z "$not_in_topic" then echo >&2 "$topic is already up-to-date with master" exit 1 ;# we could allow it, but there is no point. else exit 0 fi else not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` /usr/bin/perl -e ' my $topic = $ARGV[0]; my $msg = "* $topic has commits already merged to public branch:\n"; my (%not_in_next) = map { /^([0-9a-f]+) /; ($1 => 1); } split(/\n/, $ARGV[1]); for my $elem (map { /^([0-9a-f]+) (.*)$/; [$1 => $2]; } split(/\n/, $ARGV[2])) { if (!exists $not_in_next{$elem->[0]}) { if ($msg) { print STDERR $msg; undef $msg; } print STDERR " $elem->[1]\n"; } } ' "$topic" "$not_in_next" "$not_in_master" exit 1 fi exit 0 ################################################################ This sample hook safeguards topic branches that have been published from being rewound. The workflow assumed here is: * Once a topic branch forks from "master", "master" is never merged into it again (either directly or indirectly). * Once a topic branch is fully cooked and merged into "master", it is deleted. If you need to build on top of it to correct earlier mistakes, a new topic branch is created by forking at the tip of the "master". This is not strictly necessary, but it makes it easier to keep your history simple. * Whenever you need to test or publish your changes to topic branches, merge them into "next" branch. The script, being an example, hardcodes the publish branch name to be "next", but it is trivial to make it configurable via $GIT_DIR/config mechanism. With this workflow, you would want to know: (1) ... if a topic branch has ever been merged to "next". Young topic branches can have stupid mistakes you would rather clean up before publishing, and things that have not been merged into other branches can be easily rebased without affecting other people. But once it is published, you would not want to rewind it. (2) ... if a topic branch has been fully merged to "master". Then you can delete it. More importantly, you should not build on top of it -- other people may already want to change things related to the topic as patches against your "master", so if you need further changes, it is better to fork the topic (perhaps with the same name) afresh from the tip of "master". Let's look at this example: o---o---o---o---o---o---o---o---o---o "next" / / / / / a---a---b A / / / / / / / / c---c---c---c B / / / / \ / / / / b---b C \ / / / / / \ / ---o---o---o---o---o---o---o---o---o---o---o "master" A, B and C are topic branches. * A has one fix since it was merged up to "next". * B has finished. It has been fully merged up to "master" and "next", and is ready to be deleted. * C has not merged to "next" at all. We would want to allow C to be rebased, refuse A, and encourage B to be deleted. To compute (1): git rev-list ^master ^topic next git rev-list ^master next if these match, topic has not merged in next at all. To compute (2): git rev-list master..topic if this is empty, it is fully merged to "master". trousers-0.3.15/.git/hooks/pre-applypatch.sample0000775000175000017510000000061613663651671021107 0ustar deboradebora#!/bin/sh # # An example hook script to verify what is about to be committed # by applypatch from an e-mail message. # # The hook should exit with non-zero status after issuing an # appropriate message if it wants to stop the commit. # # To enable this hook, rename this file to "pre-applypatch". . git-sh-setup test -x "$GIT_DIR/hooks/pre-commit" && exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} : trousers-0.3.15/.git/hooks/commit-msg.sample0000775000175000017510000000160013663651671020224 0ustar deboradebora#!/bin/sh # # An example hook script to check the commit log message. # Called by "git commit" with one argument, the name of the file # that has the commit message. The hook should exit with non-zero # status after issuing an appropriate message if it wants to stop the # commit. The hook is allowed to edit the commit message file. # # To enable this hook, rename this file to "commit-msg". # Uncomment the below to add a Signed-off-by line to the message. # Doing this in a hook is a bad idea in general, but the prepare-commit-msg # hook is more suited to it. # # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" # This example catches duplicate Signed-off-by lines. test "" = "$(grep '^Signed-off-by: ' "$1" | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { echo >&2 Duplicate Signed-off-by lines. exit 1 } trousers-0.3.15/.git/hooks/pre-push.sample0000664000175000017510000000250413663651671017714 0ustar deboradebora#!/bin/sh # An example hook script to verify what is about to be pushed. Called by "git # push" after it has checked the remote status, but before anything has been # pushed. If this script exits with a non-zero status nothing will be pushed. # # This hook is called with the following parameters: # # $1 -- Name of the remote to which the push is being done # $2 -- URL to which the push is being done # # If pushing without using a named remote those arguments will be equal. # # Information about the commits which are being pushed is supplied as lines to # the standard input in the form: # # # # This sample shows how to prevent push of commits where the log message starts # with "WIP" (work in progress). remote="$1" url="$2" z40=0000000000000000000000000000000000000000 IFS=' ' while read local_ref local_sha remote_ref remote_sha do if [ "$local_sha" = $z40 ] then # Handle delete else if [ "$remote_sha" = $z40 ] then # New branch, examine all commits range="$local_sha" else # Update to existing branch, examine new commits range="$remote_sha..$local_sha" fi # Check for WIP commit commit=`git rev-list -n 1 --grep '^WIP' "$range"` if [ -n "$commit" ] then echo "Found WIP commit in $local_ref, not pushing" exit 1 fi fi done exit 0 trousers-0.3.15/.git/hooks/applypatch-msg.sample0000775000175000017510000000070413663651671021105 0ustar deboradebora#!/bin/sh # # An example hook script to check the commit log message taken by # applypatch from an e-mail message. # # The hook should exit with non-zero status after issuing an # appropriate message if it wants to stop the commit. The hook is # allowed to edit the commit message file. # # To enable this hook, rename this file to "applypatch-msg". . git-sh-setup test -x "$GIT_DIR/hooks/commit-msg" && exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} : trousers-0.3.15/.git/hooks/update.sample0000775000175000017510000000703313663651671017440 0ustar deboradebora#!/bin/sh # # An example hook script to blocks unannotated tags from entering. # Called by "git receive-pack" with arguments: refname sha1-old sha1-new # # To enable this hook, rename this file to "update". # # Config # ------ # hooks.allowunannotated # This boolean sets whether unannotated tags will be allowed into the # repository. By default they won't be. # hooks.allowdeletetag # This boolean sets whether deleting tags will be allowed in the # repository. By default they won't be. # hooks.allowmodifytag # This boolean sets whether a tag may be modified after creation. By default # it won't be. # hooks.allowdeletebranch # This boolean sets whether deleting branches will be allowed in the # repository. By default they won't be. # hooks.denycreatebranch # This boolean sets whether remotely creating branches will be denied # in the repository. By default this is allowed. # # --- Command line refname="$1" oldrev="$2" newrev="$3" # --- Safety check if [ -z "$GIT_DIR" ]; then echo "Don't run this script from the command line." >&2 echo " (if you want, you could supply GIT_DIR then run" >&2 echo " $0 )" >&2 exit 1 fi if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then echo "usage: $0 " >&2 exit 1 fi # --- Config allowunannotated=$(git config --bool hooks.allowunannotated) allowdeletebranch=$(git config --bool hooks.allowdeletebranch) denycreatebranch=$(git config --bool hooks.denycreatebranch) allowdeletetag=$(git config --bool hooks.allowdeletetag) allowmodifytag=$(git config --bool hooks.allowmodifytag) # check for no description projectdesc=$(sed -e '1q' "$GIT_DIR/description") case "$projectdesc" in "Unnamed repository"* | "") echo "*** Project description file hasn't been set" >&2 exit 1 ;; esac # --- Check types # if $newrev is 0000...0000, it's a commit to delete a ref. zero="0000000000000000000000000000000000000000" if [ "$newrev" = "$zero" ]; then newrev_type=delete else newrev_type=$(git cat-file -t $newrev) fi case "$refname","$newrev_type" in refs/tags/*,commit) # un-annotated tag short_refname=${refname##refs/tags/} if [ "$allowunannotated" != "true" ]; then echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 exit 1 fi ;; refs/tags/*,delete) # delete tag if [ "$allowdeletetag" != "true" ]; then echo "*** Deleting a tag is not allowed in this repository" >&2 exit 1 fi ;; refs/tags/*,tag) # annotated tag if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 then echo "*** Tag '$refname' already exists." >&2 echo "*** Modifying a tag is not allowed in this repository." >&2 exit 1 fi ;; refs/heads/*,commit) # branch if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then echo "*** Creating a branch is not allowed in this repository" >&2 exit 1 fi ;; refs/heads/*,delete) # delete branch if [ "$allowdeletebranch" != "true" ]; then echo "*** Deleting a branch is not allowed in this repository" >&2 exit 1 fi ;; refs/remotes/*,commit) # tracking branch ;; refs/remotes/*,delete) # delete tracking branch if [ "$allowdeletebranch" != "true" ]; then echo "*** Deleting a tracking branch is not allowed in this repository" >&2 exit 1 fi ;; *) # Anything else (is there anything else?) echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 exit 1 ;; esac # --- Finished exit 0 trousers-0.3.15/.git/hooks/prepare-commit-msg.sample0000775000175000017510000000232713663651671021667 0ustar deboradebora#!/bin/sh # # An example hook script to prepare the commit log message. # Called by "git commit" with the name of the file that has the # commit message, followed by the description of the commit # message's source. The hook's purpose is to edit the commit # message file. If the hook fails with a non-zero status, # the commit is aborted. # # To enable this hook, rename this file to "prepare-commit-msg". # This hook includes three examples. The first comments out the # "Conflicts:" part of a merge commit. # # The second includes the output of "git diff --name-status -r" # into the message, just before the "git status" output. It is # commented because it doesn't cope with --amend or with squashed # commits. # # The third example adds a Signed-off-by line to the message, that can # still be edited. This is rarely a good idea. case "$2,$3" in merge,) /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; # ,|template,) # /usr/bin/perl -i.bak -pe ' # print "\n" . `git diff --cached --name-status -r` # if /^#/ && $first++ == 0' "$1" ;; *) ;; esac # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" trousers-0.3.15/.git/COMMIT_EDITMSG0000664000175000017510000000056613750237473015715 0ustar deboradeboraBumped version to 0.3.15 Signed-off-by: Debora Velarde Babb # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch new-release # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: ChangeLog # modified: configure.ac # trousers-0.3.15/.git/branches/0000775000175000017510000000000013663651671015407 5ustar deboradeboratrousers-0.3.15/.git/ORIG_HEAD0000664000175000017510000000005113750236232015047 0ustar deboradeborad3fefa3e4717b72bd90aac8269d7cc0f00bbe62e trousers-0.3.15/.git/objects/0000775000175000017510000000000013750246564015251 5ustar deboradeboratrousers-0.3.15/.git/objects/9a/0000775000175000017510000000000013750246564015562 5ustar deboradeboratrousers-0.3.15/.git/objects/9a/2b868cc4c2a33e4574f2cc512595b539664fd60000444000175000017510000000022413750246564022563 0ustar deboradeborax]A 0@Q9\21Ӵ] -d,Jt| b䛄41Պ%8ɋNC %fTlLoke8yH(̰u(Im€k&;*T)aEi4 `.;;9ՆvGlX.vMrLQAPÆJJIG{].p% \Z,9!ۅk.зo!yk5PrnV+P%:WԴzV ƽoO7H>etrousers-0.3.15/.git/objects/ec/0000775000175000017510000000000013750237456015640 5ustar deboradeboratrousers-0.3.15/.git/objects/ec/37d0271f5840cd7661402d24027b0910ff512d0000444000175000017510000000101213750237456022357 0ustar deboradeborax+)JMU053a040031QK,L/Je`ԙ$ls'K1?N) UtE76Ǭօ8B8g$楧3ܔ[gͯw@x:2| 9R= /aiROJ|S2sRs|5B=м}c|Pe~ >5gnuQ7= musem$w2TY+C[]:gBƌ߿/ Ԝ̼ 5"E+o9'^1Hg񉏏] wgҕ[^4x!1S3|ʛ*$%g0L=:9WQ縍bKشd;&9yiE Hf8$qHzJn-÷7'BJfq ?/[2ޮQ+0K>~lt~2e_}y=%B4{[c!y ږt>=dᬈٕğAdB/ Wg% lsۚtrousers-0.3.15/.git/objects/1c/0000775000175000017510000000000013715667431015555 5ustar deboradeboratrousers-0.3.15/.git/objects/1c/12ff3afdd030bc8dfa1f0195bab94ef90560950000444000175000017510000001124113715667431023113 0ustar deboradeboraxZkoF>__1UDre;'[N:ײݓE$"Ë\o~M1 }So?>jORn S.xN35z5K< 7 "J<>y&,u&}G'=u`('"7 < "v&ӧ?vQyak"0,^5ׂGv6, ]zݭtc9XDlܺAf7#n- 3 Uq.@דS?PgEF\a x:Y\G'IAԹ)P{N!&Y voK;/utqy`92' O!]va 1Xj4xR?qmXe*Rh3qO 2TK d tS8CZ+R=+q[F5RMwq}ޙj|s~~\—&k'~Xnlxѱ::uWJu^@KJhi oT;09kiגH^Uޭ0/@h~jV]>x껗jyXV+Y^@E.iuejaI#;aAv*zIʀľ> q\o zP\P>sgu( 0??SRJEEm5} q6V_:܃T:QA*N2݂q0*[$%*ԙƚIBɁ :a%#~.r9q H~~r<8-n-u=ֵu*]{,o śNJs@Px[f&c~˲ĹNnί۩NPx z~1`Xp=,TUvv71w_Wћ^ψ{%"j':a߮O&ë.~o. aj88u&kַ/]<;7'UAm&:uȡMz%%83 yjo5?E 7C(K 8"[ 2Cdw"އEnUQL-#h7ѬYot7PVmxWŽ $!d"a[e`lQ+ yA3gW7oCР{~#dT<Yy nNB™y1,wb{k\;krFg}D JcE `A1,-JD'*,Fi悆; 6ny7d6XM /_J?H*JIem;Q14[<F hYi5/EZ}\ /*h},s wt؝AK&=ѐ&e׀][ ֬X[^X :%Fue&)"&Sw+>[V%·Lv<>p -x'HX\ >d0fн@>{O IrD[#nTQ5ѯo6N>/!i6fjyφV ^9jd͈܋ྑiޤlkiLCIA%?- Efa/ /?$Gۤ][Y@#CqīA&Qs悷~y рB^#O _M:3w yYT@passW^dt9#F3D`2δR*ݡJTQsEfq9PUCǃҫ4>\}ӏ,B2ge 1%o5]; {w2YN]1"4Vwq^l {4ʅ884V{ZZA"?FbIx!&fWb;8ߨ$9>&Z^ r h4( gq`YH@QQ!#@1mq15^ӠYvk\4+4dѲS >5.$! )4J]e6rR)=ӺWNSZ4C;EϞ]w#vϊ q3fP*{ |@7pdXȨLR,@W~W W8/jaWgѹ3XN|T!/xv[l$3 B֧X5"Uk/g F٩b.f/-ۜBdGUzGZS4.heLEbd @Zr,6ĝN#І/ yUH _A6yC۞~|2(ҷp"YKx87 ZGJ[F %+V8 R5sA86~iFGpSk묁hHyh魯0R-ڀ-9ex$VVj:榫d3kkZxO<ߔPHݎQT;y7:.f2!]##f ='ȘDEVŌAzny.<ۓ$jktvq5|suq3>:ψhIW8`{`CidrXӻA/|ya@|f{q>_HբղT@-uUL mbC ó: سAݲ&>H7}>:yxK[ᯬSZ`G2r0s}$S9[p(\k`A]߷>{zGR<0*3VVWIu2B{9AuƃC=ƤQX%Snć野6cWǠ"̅@ED"1Q@6i$@j;P%if鍣3E/L @O Z:x&QV,6rv%7-nCB!C3SFX5U>))Z6kF&S9xpK$0/bWЫ2S5 `DV]T.-]$Qf-JOZ#Frv ck%ʊ7CV|G7%7RB~~i[,ˡ\jUI;++^DlqሹB1qQGB ˞٭acX$+E lV >P[R(5ȟg2Zi@t-ST.xq*~Yuē!UJEj)(RTb跕trѣh,O=MR0c41 :jb(.;1=2Gh]My$X9 r& O%;FLTkf͜1WAbmmYͣ17J'Z?=n}ʶG!QPR6)Mlab!Bdm~C ~$In$Y/sUS/:ff1NiT2 vF8|SXRC\٬zpo]U F $#\; <$% `2Im¹ ?cpXvx^ۈwcdu@VBfc[֙)TVá-ԍW=,=1NN_@ͨ=yWMZY RfIQQhQJuEf̄qj&Rb< +sBPp0-\AJ-mYaIeղ*HB O=2uT\"H@cv0&rQ8Vnԏ L'⒄ZY qi)IDU]s_`LQjZ=G5\A- kprh'V6&t[r0xFSR_͑Gtrousers-0.3.15/.git/objects/12/0000775000175000017510000000000013715667474015503 5ustar deboradeboratrousers-0.3.15/.git/objects/12/05c1982e407857ab3413d45cfbeab2591e591a0000444000175000017510000000012413715667474022542 0ustar deboradeborax+)JMU07f040031Q((/-)Kfޤ(V'#oܽM5=N{AU$^OzGNL dtrousers-0.3.15/.git/objects/94/0000775000175000017510000000000013750237473015504 5ustar deboradeboratrousers-0.3.15/.git/objects/94/144b0a1dcef6e31845d6c319e9bd7357208eb90000444000175000017510000000030213750237473022632 0ustar deboradeboraxAN!]sLc~{n3 cNqxUZXFI3-;4lAcΫ6n>m,^{8`i3.O 3"8#*uxj=«\cgK$Oײ_s:VA;\NkngQo)FW^.<'CGetrousers-0.3.15/.git/objects/f4/0000775000175000017510000000000013750142223015545 5ustar deboradeboratrousers-0.3.15/.git/objects/f4/37fc1178e8418468edae0c2675d09a1f5fae9b0000444000175000017510000000034713750142223022776 0ustar deboradeborax+)JMU021c040031QMNMIKeהd_SUqF<51ԔD+2"YJn@),.IKI,IK,-`X+'R}nrTїwy`G/~2δ7CKS2?q2ZdM5I vL]Q~iqjQ^qAj2H^]~ SWnmdztrousers-0.3.15/.git/objects/20/0000775000175000017510000000000013715667474015502 5ustar deboradeboratrousers-0.3.15/.git/objects/20/3da944fec7a51e939d8828249f453bb168e81f0000444000175000017510000000033713715667474022610 0ustar deboradeborax+)JMU02`040031QMNMIKeh?kdDX5M @!3/94%!ݣpYi?i}2m% l*ĸI_Jk) o):cpI3>WJJ0ޢsJY%S@ 2}+Ytw't 2lʃ9dx!pp=I.=WX]trousers-0.3.15/.git/objects/cb/0000775000175000017510000000000013703777051015633 5ustar deboradeboratrousers-0.3.15/.git/objects/cb/b63bc9806bce37751893b72dbf1b0d726309730000444000175000017510000000101213703777051022622 0ustar deboradeborax+)JMU053a040031QK,L/Je`ԙ$ls'K1?N) UtE76Ǭօ8B8g$楧3/_`VImT_+' B#o&%71;5-3'U/1W#D@ ͋7\<Ulٛ.^s\WuГ0yM!a V7WvaڶMrI>(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%Mb/=x} Wt~2e_}y=%B4{[c!y ږt>=dᬈٕğAdV*ndMْN:trousers-0.3.15/.git/objects/e9/0000775000175000017510000000000013663652044015563 5ustar deboradeboratrousers-0.3.15/.git/objects/e9/2c7c8658ef9f21826f7fa4c48a9ce6e9c27dde0000444000175000017510000000022413663652044023174 0ustar deboradeborax]K 0P9\i&] -_VJե۷x:Z&w>!1IU^ HJJ>B,4}fy9m .pn q9Dؓs ? *z7˳QYUVÚ#3Qtrousers-0.3.15/.git/objects/ea/0000775000175000017510000000000013715667431015637 5ustar deboradeboratrousers-0.3.15/.git/objects/ea/8ea13f5f16df7188711b35daf43b289d2ab0ad0000444000175000017510000001431213715667431023122 0ustar deboradeborax\ksFݯԯh3eqDL'ѫH)TEA$H"Z$߾ HQxJEݷ/Gz/ZWGa/Ҡ,HBMuē nUo!H/ +r^Tj{Urq0NqWH._A ySLc^#ŮvNKyu݋*bO<o?6TO:eH7H02Nìz6l(z\zq_ᛨ,ww$nFUP&O[6 >]lzE=? zIF0& jﷶil(ITU%GØOosr~ ǽaZ ;#UvI'C_}uy_P?0 \hF`VNTn{oǧƯ%h6p<W=屌A.Jb_ٜ]SE @E5KvZ,鬹+5Ikˣ*7-&(XhI(wH4oEU ㊨5 kVE 3P5VR2Tӌ4W`5siCw+LPΌߥ~D4rdt/.uQ">l8(T:J]8}ۄ c5O۝#yA/,$>vCOGY:WzpBh KofQڃJTP3NOO=!^HwBlrx݋B?^;^󿬝~_F2&#WI:'Ybu?f,HeAkt}q }ićDO%A/FpHjߏ}>Nij,5箳z:c8e¬ssE!ns=84__~QOU6[% tTo(RnMRu7{CM 3AZ,x7W14B :]oi-c(aW&~vC4H8*|ѭq5u#n9=~f:fx_~|Oב(cthr ׈00?#9*+$e~lvW!s~H7j47}`L8x:CgBHI=clɡAXX(:20@>4ۧHI|7sAp<ќȟoUmI 7Peq k1XA\M6X)#l*mpJ[D;dZ]ʪ ;5nUV}OTC$ς5-,~".㣈KPדTfAE\w!zDaO~;b߹=F\f!%לx' )Wai ptcsXk0 r/vϑz26tLL) \'?AӨ/<Y伆 ɷ2$W=)+hYE`sebB!'sÌXH$G3h *CQf1^S7Y(H6X@2/:ID  [{Ŷ`R>,3iQ*bwEQ5 =Ub1̆Q Uf4XfI!:қX&&;wfpbR?Öڦhߟv-ՁxPb3m7 `K=Nw ¿pXʬZixtEh&L;"D>t.V7щ/ىŪsΑֲ՟W儝 ֜-?E^)H2{uʻ M3 .OFʿL]у2vE~utJxX^{I.~ѽ؛'Tc9K0-!'Ҵ #$C$UM[Z•Kn~n' `񦭫ܺ% f)%ڮFbh/@Nj5ciV0΂lՌO\ 1 j*t zY<-Fðgd֋>1&ʩaB_@Gl.Npͬ,eZ@8"?QFwcP7}W~uUG"a5w=ԄQtqwsm힭MQSvT fK KIq0PL偂 Ja;^`f{"3zɳ4xu)Nkq=!4/&wXSF\ʵC ՟ا %gYR=IJ-i+eu;%s }X(Hf ` tpxA=8=᭦wHV7"9Z_FV$>Y>#3\Y6CV'O;q|({1g(8B{|W:?->vm+5i4I[EWl~XF čރuȊ99+ @iȨ 򎇾ϡw qIRrȷll aIY>?)"Q\$u {N=ʀ^c}&Zs[JM)3kˎd\O \ J9Ew? \7jG\׋55vRRLU#4DgnĊ*`[\ b.Ļ&JOv[yht@U|xG.Vb{+ $4JOEg#y4ew0ܪ=sY]6A^U_[D[BїSĽPeO+5쥢++*l4 qmMHh;/0Ǻrf-ZlxAv@6{%_E1KcYs&7Me$vnUA|T[H%'wW춻{r)+r&`姉YV7 ua`EH%?aj!=mKtIBv\Vz?vd>s,;9tMϻCYyĀs2`8iKfC ZEvc{1»Zܻ>xwHwH慲eEQ V`-&BG:??R;=dFRnXudƼц7V`} >?[6! -JSۈ "\iBWZg*6qTVi#ݔ}ݰUꈣƋ\<`D)FϕgJVc+7c`u͵>.cÍ2V_Kah]p y)?pBf?> L.h{ۈФxb6uήQmrI|C#l("sW Y|]k/ y]oEp'7E/XQCMvVvCK ̜E 7F񰅣Zo9Glk\4ۏSz 6̫D!l+K$nkkmMj% 5M@i@nhaFq1L6 ˗ʊI.Y,FY 1U\/L݆uV Ejz(wro㸏9{znM h8[.FP@'0JIൽfG~YS߅^?剻ba}d[ =QPjs/Ԟ)'Օ8ZP.* oU|o[#GØCMg0#ǘW:G4oE%M Y8" r%,?l [m,O8exQoBAJ0;B YBg(LFi4 1wC`}r, @f|uQe%FWMi5’ChV͊ aUQ3QY6 ^SeT@.֪P-ykg9jI[ A|>0:2 /$c*\B4i i ^d>ăcyřw̒ыMeHi?HFVt.xX]ADL\[~4}%a>?yAz 0h|Mn,HغV0"dQyUiQ7]FU>c` l8qřQ94ǍVдl1)^jx{#GU+OZ{lǒ>W΋ a[cFI]I g\.3wYXY+bHgNƠ7Ӡ%+Юw;D%vcUw8fO<2hdyƁ&iâk_HC@2H]b8&n1]S}ٰ,A[[:ϥ3֚,1QۧS1d:xn\M?\|I?s狝͗iQ m_M#^`5~kY x ©!J5x}.|66=_c}@ncKz!}??[pn)^G@t}0eM"3`$Sp*L MGhNA&LL D!=DŐ0K8RM*T4Chyzuusl𫮅1ee/euqTMZ騯} &oB uiX3`?9q!,!tVB74G,Att،5j+"p!NM# [`r}L<GttR*D ^Cx RO𞎠FO:E`dJG rx1օXĨ;y\5ӣҁUwTZκ{8.]ɚ?CJStrousers-0.3.15/.git/objects/5a/0000775000175000017510000000000013703777051015554 5ustar deboradeboratrousers-0.3.15/.git/objects/5a/97e6ea0dbb566aed6aee20f5e5218b4fd5a69c0000444000175000017510000002072613703777051023300 0ustar deboradeborax]mSI+j^=_dǜq <RciGH:dɬjU a{gg66tkV,|ͱA)&Y/7oz;żVilv6|;1wɸ;2pz JΦ{wϿi677;F~n\Yl8> ogM?gqb ,VvMѼ(o,mү4Vټ0[̇J^wڽR+t4DAM?.Ev޺>: &a?n^1Mo2NjplSGlspi]t[ oB휝dK͊[?nn1XgUt8xf|3,N.Z'lNM`q0{D3mhKd @.d`/-'ilB*qF+ln0ﺣa f>OnrUn }!4J%dSY dr%U-y訷'[sE_e+(ع8k Zaʚ?mj_b22 T.+U&?hx8( q/oQvL @DsBdL;.<re~kXM0FaShQ}&':b~\&a/q]B=$v;>:c,́dq ^ڗ`'-16F"78ijS|jhv̏qw_z77÷\Ծ(TF`*6A :\%BfрB%@ZVlp:+\g7#St訓idYah#Rʁpt+GKӊm5ho|{k^Z)/5 7epѭU|V ے$>ofgI:]sqi!tC M3Z)j4x#@Pa6%RWxGqk!QQ4zAwԋ@JiC i`S?Elӵ5쎉M7uz )u詠20eA>e}d{_?ݻzc f!}Ҳ#(9|~U'ArI7HqA3r)N0n\`# ;GYq{x - N H'# {dwr=ZZޭsձ0[rA1  pqGK!=A 5BP; 4 uig4ٻ,BCb%8J 8щ57}C/'sѬE ;HmFۀ;upR*ջGޝJt/TRVF;+T݁i{rEt:#pxȱ%LyHu&B 4ި_2am^۠ڠ8M h"W񳲶%i$Vk̐~C?Bv?­C6$˰CC.|.!`F(_呂 #@cKX㋚?ɫUebuE/';\&k^ fMF=y&k/0h! ޟD N& K,4Ҿx\6uǓ- ^t>헻zVbiNIŽv (Ia=֨"Z+#S8|.7WPhlr#P7Moz۰Kn'`bd,alFn!Nfo-ɰYv>g͡FT^SOBvmcjsC߸@̌iUǓnEDs ؾ8ΝeVDZr):먾0j#99#'ټx1l3Rg%)3Lt,֪l!?"q躱n8ʶ9Bn:j((FkB8ݥz\C9(*m܁ɺ@"Sx W ,6xʾgrU[)aZrI0i8ͤm!2_uN9+B,QJ:e\qD< &fkvPr OlJ^IM(͐u?/+wkߥYiFgFCsYYj2ZN Nd"=UEc/3 ugeybNLl q6HA~ȿCb|x02=yqxHpf"3x6v&.9'q*p4> 0 h<6SIk1x~ beg[\ vm8{uԦyF5z4,85j?bSG FFRFk7"Bh'~-ɥtjgj$~!;da:5]1-q&ÕkN}Xr.+,{1]ViUNBK}LӝZ39G]g1c-DllrJw]b|&& yZ~xD'A..AZPrXJ$C1Q@T%Z՘ ͢yONp$;@&5.7&lvMFSu/h˦l~XC4𫍺x!:5Ls؃;D8rݶ6+!wo:6ݨ}yVd[/k*,-.Y4)-g]gz u%K*'Cl˫iwֽ)1ܬVy\"x瞧M;q1zRIO|1 /op'7۶pMmZYZRٯ'~pޅ=o#:OyR) z eMx$tbhav:n}OB8^v3M~w!TU#&%sh9}=NO}-Zcqm{h6UE[qG8e6Eo«ո&_!FZh_L}?+eA+_V{P?dX;^_.AxQ3˝zNNiXwl U9!/#wѯ2 \GWFT#R޵YMtIr uЌUt!6Tob6M  $})۫wquQ5~ ǒ.X}ȇ"2X\L xߖORe`Ar?xN*J - K*>a4Ѽ!)Qo19%W?͝ q q^dágN2IFV6OՖGn&$7h!d0V(7UKYj5|$Q5<,f?{ BK@BVG^=2 ըՏʷGf PL{]=WҖOc-=^zVjwe!T[HS[{rl#J%ZΌ8KP5Z$3}jnTf7,؀FS$?>*tmRV %%Frad~j]+200*GU7zV'2 \+}/1͡π>&CyTW5~`ʞƦCFVD1sȨI1˖Ot'xF7̱NQd Xg= v~ݩbu_3ﻷ縉wܠǻg$!`yGyL#eOA"P)vj>n| rjbE>c̎A6`"\9r8!E\sl^N;Gwg-L][ XU>f{! QJHb@G?.$1, 6M~LCDB0jWw훫[Mx-[8ِTо_NQ(Ho[D ژbYy]{"8_lh^5|>S2o!#> "!*Euh~ɫˋ;J=P}xX 㷂!Q>µ]ĭU%؍!ވuyEQ{ ȭ \H~?g^r-BZ}s.1L!ύʀtDeX-Hn ;7Hv\abFR%F82ZLfy`%@+^,$fQ865Ns-ɃíKAVMEx|5ː{{CCG⽂v^!ʹ 3Hymv}nά-P˃["EktL R]r^684 u>eXٟiBF:}]C`]S#]_1sϠS;6\Trd pwb6q>Y 'twH%;'iZU%!:*]3׳FTfLu: Cx\w( ˤ|aZ\Ϗ "\X@F9,@ՙ PB'1)i- DT,D&׹27DK/BBWnϭHF=P2LBD$230\ڣ.BA<@ q8jgbΛ0r:EWƒ3ԅZE.%lTLrq#?˒i}ggYrjb [8"Ld* ZpRgB2˾ַ,-φB7(az9m̤?i>#N Sx]K^YN\`y뻄,[j~&֓b\ ێbЎھ:霹! ͬ֙*G7 +#"L#^㯢XΑM&ထ")HA|-7&na9Itk/ꪘ5Rؾ8{r,{L'<0H8]k?8BlB>Rt2.Q2~tP=mzzj/Tzܕb.w^&J-$5 "7y<2˓BOUXHpOP;%AB(|=sY* 7KfzT0[W908o)@S6Ҽ03˯Kh'*^bXG@e~dI8 8y߄y Ye)*v_UVB+CM*M-`<,X#CG.Ȉ+1ٌwK֩U* KwS)J /k]!ȧ I!'$+X]IuTUD/J+!2Qkm {\17Tq{._knpm!۱ cGOW= .0iK{R}_@~3i;˄[!}Bi~6Ot5[ ѢH0GD&GEĕ}h !K̀\hj w ftu t>қyI1j=7tf6R@w'@M={yb Sqs%x#˱rn3gZ /nBMae$C5~)89)B#`[Ig'lIQ]O,7Z(C_ c DGNgYϛgN;3׿pІ߆pX2QO\;Deqh-ZYGӗ{N˞8FPX?H/BtV*,G;>=|; ,g^9^߹u K\9g0XwC#fN Kn8t8ʿpޠen,t؜钗7Sq uu0LA1{'oN鍒6y?3 i aUdv [^5jߊ!gxţ䒅בJb9L5oqw}4`L%vӓ'3D{(" '\ss. L`7vT-[,e.]u@C4vEh K7_TPf% zk$ Si`٤ܝ 5Xزb҆mkf2s@a8w⦉Q׎U_#s1DP)i!=`~w9(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%Mb/=x} Wt~2e_}y=%B4{[c!y ږt>=dᬈٕğAdl'|wd[x䈽ftrousers-0.3.15/.git/objects/a7/0000775000175000017510000000000013704257262015554 5ustar deboradeboratrousers-0.3.15/.git/objects/a7/b0cc3a6cf8ae3155b018086076031e139f9a920000444000175000017510000000060213704257262022526 0ustar deboradeboraxQMO0ٿbn\UgcBTcle}g!}xL&_a㷚@] jmIIm } %u25^1S6Zʋ5ΪQ MI9ٍFRbrdwX&Mnz5%4QY)y<[[緵TOEԜB\oO;x ;ʻ+~—-&`>p܇~3auf:)hdyʮ>l*0 5_k/&=SNQMS Ts!`i/>ȢZ'dWɹ>\~qq,dtrousers-0.3.15/.git/objects/19/0000775000175000017510000000000013704261631015471 5ustar deboradeboratrousers-0.3.15/.git/objects/19/7b5a6c7cb94649681c8a06bd35b658670535a60000444000175000017510000000035013704261631022416 0ustar deboradeboraxJ0])fwWL~EDĭ[tz[m.i >Epw8?\ui@?*>8㈚Ht$)\ek>a.O U;$%9_?2)Π#iGh g@O)Mч@ͥ»R>uxye;%}. (MVGIoM}H [~6^L0\vSICإWltrousers-0.3.15/.git/objects/8b/0000775000175000017510000000000013715670346015562 5ustar deboradeboratrousers-0.3.15/.git/objects/8b/59a92d0177624e8b5ec6277987f30ba6b0596c0000444000175000017510000000071513715670346022521 0ustar deboradeboraxn0 EW:'4IQtQ@) %C;ߗv-Uzc=(K8kPTGlk:]XY6]UQF>lJDcU& u횮ۆh \kƒ&*;W7ap>&x"3 ,j v;|_^{;84ǶvE[JNǘqOA&3' g=2Hy0%klϐ@QCfB 3̙^Ȧ_.C

mJv&^|9(>K{ :=V)~trousers-0.3.15/.git/objects/38/0000775000175000017510000000000013703777051015501 5ustar deboradeboratrousers-0.3.15/.git/objects/38/c5a146e4399f56c895348edc0af7c8e09df5850000444000175000017510000000033613703777051022673 0ustar deboradeborax+)JMU02`040031QMNMIKeh?kdDX5M @!3/94%!ݣpYi?i}2m% LCI }ݱs2yl ҕxj8?pM! *ðz-K+gŶL]쯞.*.d`Dfߝ1޳*2t&7ۻ_1Y#trousers-0.3.15/.git/objects/b4/0000775000175000017510000000000013750142223015541 5ustar deboradeboratrousers-0.3.15/.git/objects/b4/9c6341d4fc5809733ecaa61ddd4593632134f20000444000175000017510000000047013750142223022533 0ustar deboradeboraxOK0=SӖItYDT?nm4ɢ~{(ofƥe.jF?Z Qttj3N 3ȩGy5 = M/Qr&9E[(SĜ1eǔ'Gw9Y~i1q\ZI*(RrсRԆuޡM3&{c-Yz]~SjY[n)ķ{kfs ` 꾖T|%j3?J5pK3TEoM,ev ;Bⴢߥvsk/Atrousers-0.3.15/.git/objects/c4/0000775000175000017510000000000013703777051015555 5ustar deboradeboratrousers-0.3.15/.git/objects/c4/5422fa4f45c5faeed7b7ed63ca051707e338d50000444000175000017510000000057613703777051023055 0ustar deboradeboraxQMo _1\+Ǝ(C5ha 6;mC.9 [D^)nm^FQ k3u8F:5U]H8zٌFS/3 oplMnZիm[TP{)#xw5\ >.[*c; o*̔+ppt'ywzOʄ|ALB2ЇLi <: lKKaWON6/ 0f^%_OO[W/r&=SQM񉓺s g"LJêVX ~F[!.$6xŏ)trousers-0.3.15/.git/objects/89/0000775000175000017510000000000013705244310015474 5ustar deboradeboratrousers-0.3.15/.git/objects/89/8c485d04660c3de8778020cffbf0ffcde0adb40000444000175000017510000000310313705244310023120 0ustar deboradeboraxe{8TyBgwRc]TRt39 CDa`>r3X,7ޜ6`0wLS3)ɥ~ɡuul/~6["JLmApSĆ*QDp!L%O]qzOO<6feT_qvU Dz{?3Onh`)GR `G[NXp#r|#q9*+1xy^ޮc D ^ 3X^=w(*؜왅c`ׂ>m%k raсBy&B<ĈJbZ|]J[.pb#hd(W RFϭkq+xpϼS!).R=/-1 !kV$(~\HpTXK ˛ 8RjT6_+LBs鮹말$Vt^P < Ū.VRvӢ&5N|Dέ\}fXj`{ϳn);bms:ASpAy0ꞃ2}J;wxt{ud.{۬L V/\.H{qwu]e;BKj!$vcLtKRF?~}XڶIF4&&>G8|ʸ%ֱxqc3ڟz;g EO6wP7]0rB$L&i(XYrxjm< oT 6LbCۺ]֖a#F+3([ˌ0+trhb\y_4R0)SJyiZU]  pX]9QĻ+ykԸ> 1!1ऴX%y0(W$ Ĩ*jj(P@CHRd UDs 6{>Uc*'kvXr d @?0ߢl.O:e*Pr~=*m|"¡(EJNlRP~Ӻ0=Mtrousers-0.3.15/.git/objects/e7/0000775000175000017510000000000013715670620015557 5ustar deboradeboratrousers-0.3.15/.git/objects/e7/4dd1d96753b0538192143adf58d04fcd3b242b0000444000175000017510000000072113715670620022616 0ustar deboradeboraxRn0 Y_n~vIӢ@e %Cٿ/ݶ@NAt 88ϞmwmkRº@4:X`PUn);ue_zuk]U;ZcLGR(<\yʹtkjad?SM,'{*.KS"0e"d>2 ,?䎀MgȌB<̄3Hid3/[U)}ǧ/F)v8+,ԷT`D?ƣ/?@:k3/"I4{/MJ% ]DȧY\zJ~ɏC?{lf-;M0"#DbyC d_Eb<-Ch@K,+bsud$ pETCѹc~=(trousers-0.3.15/.git/objects/78/0000775000175000017510000000000013703777051015505 5ustar deboradeboratrousers-0.3.15/.git/objects/78/6799d0233e142644063a3e231dabc7c6e0aa540000444000175000017510000000101313703777051022445 0ustar deboradeborax+)JMU053a040031QK,L/Je`ԙ$ls'K1?N) UtE76Ǭօ8B8g$楧3/_`VImT_+' B#o&%71;5-3'U/1W#D@ ͋7\<Ulٛ.^s\WuГ0yM!a V7WvaڶMrI>(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%Mb/=x} Wt~2e_}y=%B4{[c!y ږt>=dᬈٕğAd,.t{b9?T;\O<trousers-0.3.15/.git/objects/73/0000775000175000017510000000000013715667474015512 5ustar deboradeboratrousers-0.3.15/.git/objects/73/edad9c72cc36a1af29c924dd98f2df227e6a660000444000175000017510000000027613715667474023163 0ustar deboradeborax+)JMU04e040031QMNMIKeh0uU6[Z7DTYANbIZ~Q^2ɫlrgE,?*.+*LI*o_Swɚ0$8%>9?/ UBxҦXkڰYYIFQjbJ1P?,Vx!Ӫbʴ 7Uhtrousers-0.3.15/.git/objects/36/0000775000175000017510000000000013670357227015501 5ustar deboradeboratrousers-0.3.15/.git/objects/36/3cd77760f44f416906a801cee1e75b716358bd0000444000175000017510000000033613670357227022503 0ustar deboradeborax+)JMU02`040031QMNMIKeh?kdDX5M @!3/94%!ݣpYi?i}2m% y!N/fߑXdIM$\6AY|^XˠV 1$mK~(79=$<{Y>&nA~KERw\ƋЛ̅ʗCU;*ز(Ol?lEB;|euhH] Lb2mH90#d8o*& ҕ ׃0JV7ZzܛAe('()ԛz J䤒{u-40tf2;^SC?|)P%4@*K}NYb`hR i,3c0@V\aҶ(*QaU78ڼޜR^`v6kw\s󝱜*\2&۷d˘S $9Q q2trousers-0.3.15/.git/objects/44/0000775000175000017510000000000013704263174015473 5ustar deboradeboratrousers-0.3.15/.git/objects/44/f582475e739d0a8f3b4ea1bee2f9c98f45ffa00000444000175000017510000000037513704263174023073 0ustar deboradeboraxKN0 @Y͊?!lٲwwRیTdF Ϙu|.R)ZUX!QhW*U>I`&6&eGt .hdR*4Z{oQNTlMޫ(託\c._PI o#<;|]vc^_`0AgQ4n?rffWytrousers-0.3.15/.git/objects/aa/0000775000175000017510000000000013705244310015615 5ustar deboradeboratrousers-0.3.15/.git/objects/aa/b1e2574346e75385bd68a746f99b23f5db852e0000444000175000017510000000047113705244310022637 0ustar deboradeboraxN1EEVξlG Az5dv$(9gcg˫nFb4c[׽$R0/`k;Y#(QFKMT[5*iZ y (lˉ֯6̄|ˮSj`T˞"<ܣְ6_{cQ]r D1pnvD.EW;@8y'h47`Ð 3͉m>eB!`4+1:c[+Sڅ>J 9trousers-0.3.15/.git/objects/33/0000775000175000017510000000000013703777051015474 5ustar deboradeboratrousers-0.3.15/.git/objects/33/af2834c3f86ff2ae530e77ca3bcc1ca66ee1eb0000444000175000017510000000520413703777051023256 0ustar deboradeboraxYo_EJf 4YJjG`il PH"LI7CrHѶla;5 ޟڻ6uT1J|7Hi&QlIфN~=9>%"U 8 'BJE):~ChݺAz7sܡ(^&tI'B7 E*M7p2w`o66sWwE1c+NKZzi2Ŗ?!Ǚ 8Mɯo$imF~D!Iʃ(z pjiB+:8(+2 /bFm^ J^UEBM3"OLx4G^ 9ԧ] OnPLS[G2>bfeGq9ZI/}5͡Qwx12u8["R td |u<_^:_/ϏNXd=8itQ%Y0aUAty2xת'?<-ܰ͜[)h3:%Xq0XnAyԘh4iIŔf΅'⧿s$3qxga9+ھx}?Z\ !Q@/Iܱ(fw,%!b|NT8]4.Z5Ws/^: m zqc!9"ll,^aan4qG`0icO:UT|}ULGxXAp/|Y4hlL+YXEfVkeJ%JCߒ)LYRcĬ:̟aS89^CFp&-95[>N Vv~XOWcfqƈdAk͊ N%Y2; kHƱF԰o4EwYCc9% Y /mȮfD44hG.f Gt ƉcYen\>qwCщӪaE;) pr p1_mX˵{Yn?U*©` Hl཭ZݠS1ZLt88Zٝ5ޝ"!^qc?<>(=1kqp)O|ϴ'V!Ł#ߡP*ƛq秢$x\Ꙏ boHX3@0fZ4iscfy5؟Zw7 ~u|8RisB\*A]XѓP1KU]޶c!XhLkwLBYA nT5E㤙$~_6ϪI?u61"7 -{ S@ѓ1yplE~3m;hW jӃynsP XƮIr6)V0Nvh55rY\uaI#,C}dP5s8Au/yd S`d;1G0J%z:!):+WHF7NEAeP&` iaZ&B42w[#hXcR0~/ {_*p>asLeOi =b#1vK1gGa$xq!J/4} O`y+KFᲜS$&`pByv8&yUtnO/a'ļFtrousers-0.3.15/.git/objects/c2/0000775000175000017510000000000013750237026015546 5ustar deboradeboratrousers-0.3.15/.git/objects/c2/1d08d97210317f8fd764dd792c8b2a31edd9900000444000175000017510000001154113750237026022633 0ustar deboradeborax[sȒ__1K\/$ q*Wje|[$M\zЋxOό KLOOOOwOwO ݇_/U̝C^w&l,^p:aVa/>KJ%i=ê$}UvY_Bb>YQգYR2MMoxi0zh Kjsv;DKS{FSؖ6lVI lmdڝ^yj;YOݰi){WGx=U @f=Sx=`[3MkhڕZ5uge`35Gֿd9H2Zj!'/^ Lhf6%ݶn֒X˥3EEvƙ[?NzŸ"h1ɂE+>qgEz6+M(f悏oNoa#; 6Mo> <'t# ,\L1mhX +^[UkUCA63K,% ڴ*YZ<ŎeMY}0/8$[y' 8H1 [yپJ>ͺ}3玣 ןx)D@JXfg1l WK`Qv `%Hզ<`e`Sab(aXyEc'_nj? Ɲ1 _baԛ*Z*:=5#m,D 8Sdg.ͬiY<=2!FFe] gO._abyU{}%Yp&!ʙ|qQ/E`M٘3lC.'m<9IObxnV"Z*)9H0~P&1=h15q0Sڄ^瀑⇱i0SPJ%tz=AȪ*e0]{Ȩ]J!۴?1 Xn(a=g_-'8W=ۃc\> $[ 9j]A<1 r'?ĈgҒ&*CR|~ {t^8JTD?4Gi?TguoӦg B!C%<%7*+'.β=sQ8dX)_R> 钲"ŖCʡ%($!3 oyj3#_AW@E4kvD #Wuf"QEl~¤#lD{+W[%vq :.?!LWfGHYM!{bҤNL,e*C1ϳ=Ww14E:N"ƤEl+y)Ŋ @f Π!| Ou*uL؋Ĵ(*Ɏ .ȎطN<oͫfLE{h_N˾[uޗo@7}bcd5Nޛ:̘: fk%؊`Y5c7 ^E$Mg)/BAe'c;I\7lU.{]Z.BmcA K_]T&\7ꍷ["yXqY~h~ޝrЍyCL A4ֿ""&Q  C[=V )6*l;{OrzFG7f-}w`6X8c⾣5)I@h|9-2&[PUG~?Pq?:^T7Zu10(l'6'?CA!gC2,Kd 1?װR3{R"}:_=F؟ZzGooL!uྪNZ{SY7Q[! M*PJ҄R܏ Qbrl#'Ga#I9 D(pYa9 ( I5٤A6Eq*^d͘#oIZp\"/y0|^Q(LN@*H] qYeO $to HE2ʨ7>k8F @"<[";m"h`i s@)@0fINOibJbE$ix[/֋8(,b{͖fi&g*R!93n";8d64Q&xEEr".Y=XۧktB.; w+!G!gSH9Saɶ)p ,H.,Sђ8 [&;Xɜe 1XeO-Pk.Ǝlөdce"RLH*b}: +fY1}-.b]=+1wmY1讵.̵"pC1PJMp صC TTe7C?piP YB#UvOA7{RVD gK$FJ+,O܂˂FrYz^d]*;@N vO}iSya!׾2)(V@X --:H36J{#[EOP5ʀ6 ;rnh#͇BJf>j3j9LQA'TqHeZ}P"Dc*PH\ni%\(egvFd9vHoFfEb*ʓdJV4K9\XUkLH,n6ᅬ+Q k~P[TW[9G<(_5(urY\0LvO~IETld Y&ie`wD#ɧ_bӐA#3x6 ߡ-g&_Ymŧ0G\Ӈ=Cȹ7?V ɜ{L x3NEB{3Hᑟ/x: /[Y"ED 1VS  HS򜪜 Y:[9 ]Ԡ(&,$x]@*VJ*CZh| R5y.s My.`KsM_LcQ%9*!EW'DL?P 43%}{QNH~.G`dU URՉ8R&E\8+pMwN{E@EbE] yөLg˗/9X88J\EpaÐ K~ Z7o%m2-`ee8r{futrousers-0.3.15/.git/objects/5c/0000775000175000017510000000000013670357227015560 5ustar deboradeboratrousers-0.3.15/.git/objects/5c/074871a684cb1f9ffb01f3bc85eb4496a6e3e00000444000175000017510000000310313670357227022772 0ustar deboradeboraxe{8Ty)]Xw"ylTۺT(1s3['X$t1)n$RRks{<}!Dup]ioOA!0$`ѧ9GG5 3ު`c\bænO$wGm ("tF:IonPa> qq dO9aFm$ `0́1"hil]ӏˬScjW?:)G)kalpwoM600M 뭦7_5쿩`0wDK+9ŭqՁt^{4S"Jt}A%{C\;>&/<('6jRv|YSV_ɊρĤ4Lcjo٩.S&IA{#5\{^x_}5aԩkM|jO0u7{RI|D~DŽAʢ݅Om}'*0+.á[ENvXKnyai"%0bJ5dqqYNFDޓ+7Ρ׳FP4_piЃz*[J!Yd8$>΂+@&ֿmڢӺqȶN9 e!|! !(*&mN%%Tˢ9 `Q?LH:eWﴼk`@Ң2ao{E-*R$1&āX F_nݫ0V~yoD!U5T}}]EHVzH ?0 l_%Khn!w#TبɚYֱ\bP;,*͓nEiJΗ76/Re-Ͻ\X8Qi6‰^_jq:/K trousers-0.3.15/.git/objects/8d/0000775000175000017510000000000013704254606015557 5ustar deboradeboratrousers-0.3.15/.git/objects/8d/d48ad75eb768b54a2bcb9271e953eaf091fad30000444000175000017510000000052313704254510023126 0ustar deboradeborax1O0+B$N⦪P +zĎl-҉ɺh4MsU+NTU[EˑSKR Rl@.AYHWUM~%MYqYaZ^u9>p)Ҁ`61-ljъ9, Q,g/$}@xxO(%l?K+kJWw9e\RX ~@` k@sJ6}@'Ǟh&zEbJM>F+ p EF#L޺ *z9'Ӊp"$Yw@ҷU9ԱSh1:PKvH/1 y\s[ò_Gtrousers-0.3.15/.git/objects/8d/62ae267485857f79957d242ab207acbb401e190000444000175000017510000000101613704254606022474 0ustar deboradeboraxSKk0Yb%ak7B!#kVEwy@K }df~7"huӶ:+,j kT}ה!Vc Ǚr[V6*/*fe.|֙9E pq@z9j[Vul&{yЙ\MpJ>:/qˏĨJ[MQS1D @Z0K !;Z8`0,E"#/ w4Z6Ag3|$FHRe\juICrGg?wav.="ІPҫ7g,I._JruzhZ;d`Zl@`=w<#?}]k"{ Lϱ?ilL k_2̪ӇUpҡ3-LuP.τQE2p% hGZTv=H6 "VM4kWҎڨjaH10-$kVY3"4Õ&_Bv0GyM.o5KojHa~0 EٽFM#ѓ:IlΜ".9߯|9c  KB>p Һ /4$&k1pQi=:Ž^ U騴j3k/oj}ַx&`@>:.e6d}'Q$;@\ C"!&HI4TD\:u,Ვ뱟)f.RV<]4q]cq3뽈ԐOk4#` D9/NXr7h)%kϙ [;[;oڻQUq0jjŦe6bWog$@)gTX_]U#9\R9:G;֛sʐs-aCR.KZ#HMh$tߞ镞 ƶ@x= ns3Ͳ9r9vFw5Wqdm]+!T,lJF׮|"br x5 B7jؚЌ'Ϗ¢O=^BY=4!oL:~Т"[ nu8ߥLܔ@[%V\om)Pup \L55I_r+[*+P'0(E}j %~n)Y(E_5j8ҩvUzBaޟ_xWvj&îb`&RHLO]6 /<@*'/ntrousers-0.3.15/.git/objects/f5/0000775000175000017510000000000013670357227015563 5ustar deboradeboratrousers-0.3.15/.git/objects/f5/c286e01c86cf2d261f9ab804040673f014a2d90000444000175000017510000000412313670357227022540 0ustar deboradeboraxXkoWWffM[c$Og[,6@ylsIɖev;b֢./{L%pOYEŊM"#\Pk6@DwZ(g NłO,1R&-lJn2EFY۝'[IU\nmwrĚp g~'H n%_b7W."&֦؞qk6O"UIQ8+JL?.#tJfi oZu<]Xe+< E-7a1Yl^m6j֏`(cKh;ēiƚ γ4_Zq'@27-+J;أLHm y.fDV4zbX[$.J.1Q&ns '|%$s᷈M-ae"e4<B{,JxAsnXKR$p&!+!6L< *{dH dؗ(N (K"VKiHߓyq%\ F~JcMJ9E$mWQ]"I(ސQ N5frE oԤ^P+F3ńao0R%\$G3$❉sF27(Npz[yAV[F< exi QQm^2aQQ$YEﷀ-Lvil-1Q 0;֤+QNY;x|G7giq QOd2.X$:ա moZy} x%59Ƒ_m#Ъzw8nߍ^ |{wC|zA{#˙:.A*k[|x>'^ub>9zɟ-GoNVJQ膟}? ZnLkz>_AD.;H;/VjO: G~ 䍍w# q+#5%M=5OEQ)֩+O!4Ĕ?<Oȥ&Hv8 c_N| 5!m+2+P rjTgib1x~gb.de} )r֏>#ER{кNWQJWl o [/~]`O?"򪼢`H&hXZ8o`;2t3.\#Av|>w3ƒ7ݍyxdi':}AՁL- 4D?%qd:9y:S; 4htVq;#wqMtq"ҧ-{ 7X{|0FS3a,.vy;H%Zbg9wJ#I /.Ozp[? RKWr%{R;m@Aad2VڣOރm#A:a`6G)خw@8Fj3n [_ |>^GUG>n>|ӟ<^Ͳt8oM_{YObxx<^!y:۬D,t=AߕCza{B=R8 a)>6 |ާ_^$v[`dv<\|4@Q#_YI\WFi\f"ʥr";,eh:TÎ-Tmܩ/Ɨal);ðPi7M=u_^h?-3k[kQS\-ΥNTu;ume&i޳7\h9HR%^w C!ًP]*c$ݧ"_ЋoNviW__tߣY!6(k짜kmr\rr?M-<ԙJ7Ο,B!}3=j'Zlάp*[~߮wNk9XΓPY<9?X͍g8fSVJm!7?kFtrousers-0.3.15/.git/objects/02/0000775000175000017510000000000013703777051015470 5ustar deboradeboratrousers-0.3.15/.git/objects/02/971154a61912f5b8a27b8109a918a60835541f0000444000175000017510000000317013703777051022163 0ustar deboradeboraxe{8TipMLSM -r +jk(5RY33f挒jøDO+v)TLQ*jیŸD){|}a1:8:i-wRM`*lYiK^R9VBGLYh,҄XdV]E~P>rXZiU Oe~bue "Sb7|gݘG&)fI 3gOf, v &Zw \lftFR,\#FdxBڵ%HySd" 4)jRq5& #T|)`q|frҨBkF#؁gӧO*k[dXHa)~ ?aẃ͚F &^udm9۫81P,z᳴m*+ qxՒz{D8X@y߭e7OdXR]5α5VV5: [ӽdO͙G!Hz'P'Z?T} 4{wLJ8b$]$ʝ/URn~hBYY[ibX;Fb0yg6x)AyK-oc| a D7FP|;dn q1yZ^>5Sז]>`8{Km8# ܈!qmfIyh7\^m%!:HV_4~CA ͇Ws/5;ǽk"(#fI%ߩW7K/;\2!t 8Y%iHLap!\U 84r˘=gq؞ٗoobF~f9zpEȒL&{*c"tK43 WuJ_@7UK!1X"L+ؓչ^i*. 8 c[>48w~h1yϣ4smRVp&iքRf=^rȫJK;^;0jy>'Ol@N\Om&iiʂhQ!#{q `|AmۇR>/Q-tE蒎V ,w5V}.r}ܣmjtm MݧֶKEYC\(̺C|/m͕y*> \zI]+N9Le8JMޏ)pf! 4NwA.]OsCA{ {Z%TtQL3Wpl'n4g_]{b_RXaU"6e\ϯzoĪ9QB gt !=>ɛx})2⨁9g˾'^5j5Ck1̯ow0٩T)'5 ŀ-DHt-/{S5pm0T+-)4o;]6O"`Phj{>N_x)}3}QsJ7܇Rq ?7(]k,NMM$"=g6lAmҏt{trousers-0.3.15/.git/objects/10/0000775000175000017510000000000013715667474015501 5ustar deboradeboratrousers-0.3.15/.git/objects/10/a972ea738279b00aa48a74ac76a4e96842f0630000444000175000017510000000033613703777051022467 0ustar deboradeborax+)JMU02`040031QMNMIKeh?kdDX5M @!3/94%!ݣpYi?i}2m% y!N/fߑXdIM$\6AY|^(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%Mb/=x} Wt~2e_}y=%B4{[c!y ږt>=dᬈٕğAdlW;Tn 3^ctrousers-0.3.15/.git/objects/10/b33821cfd79375cfdbe05123b2f7f6329eac3e0000444000175000017510000000051513703777051022760 0ustar deboradeboraxN0EѰ$N!ѲE3x(#h(XyvQ ǡITQj ٚ*^Vb>im+[+ U%m72k-p͇c<“w95}y| uת^5E JU(mٙ9=S|7ka}XDaM%ú@ɀd8>-!yL,/M,_h%8_^3Ar@kg| y>gHbq@~wH8Ie1S &X?,>@Ntrousers-0.3.15/.git/objects/e2/0000775000175000017510000000000013705244310015542 5ustar deboradeboratrousers-0.3.15/.git/objects/e2/e0ca48069d7446566683479fc4bdc105240ad30000444000175000017510000000033613705244310022457 0ustar deboradeborax+)JMU02`040031QMNMIKeh?kdDX5M @!3/94%#%Ey}v DEIr1teB_w,n\)4D. t,e>/.3$'\SHJ0ޢsJY%S@ 2}+Ytw't 2lʃϥ5{Ozj_mZtrousers-0.3.15/.git/objects/info/0000775000175000017510000000000013663651671016206 5ustar deboradeboratrousers-0.3.15/.git/objects/3a/0000775000175000017510000000000013704262157015547 5ustar deboradeboratrousers-0.3.15/.git/objects/3a/00128fdeab7c4b6226745d87c1f2a35efd0f610000444000175000017510000000060213704262157022744 0ustar deboradeboraxQMk0Ybndٲ8B{H kI]YZdz[%#}hlPaPZ@_zlkBEj@ 4J]NJ|}*zՎVsoTS3E/綐c<@wzm)H-`sV*L.O<^nocH6؍Wr"jLe^+wA@W „;L(G!==1f CsńMٙ?lUFIYӲئe}At>vش.]ؠ"bW`ѿ u%)`^'OI42(yRgEl]iU-^Ar"xgQ /]:(^.<n2MՋgN,q(4_gIBc;﷩K~ܭSzߥw K;>ZC|aP6כGx7ePW[tכ䦂FxݛҸ-\F`6V AE^| k< /.@s| x\ƃ?8u'B0X}:\ǣh,4 '$9 xx}zT5tfp> OO?Eo8b Ehc#hKH"q4Q8^:?z-*c+&rNJy[m`qReqWq|rŸ:xJ6 *;!F֟AZr4u1i'51s@! ` UZЇgAgAl5Aʴ^ }beV]}KM'è,v9QzQp4-cIXB&ʜ1BDC!@Јbt9>dkXH'4YyhcǶE)|aͶ JQ0`1>2 ba!űO ^r&h4`| N?_w|@3DoH6<4#nHPQҨHȂA^6$'A9ezs7|1Ɨ0_.l7LSG3$pEkOe$zjI,__08[ApG" :^=T҇l' `6N<^c9RaJr0']4䩓.-oteRB^ޑ'_L&nk2]Iͬ|Ẅ́@ 8C>l_rki(bFpϣ ^RsM|"ECޥWJP Lb`WEftpUmR_ʧNJ2΂vw)iGy0ۤ">4/zlrL̸# f#dTm L}&#h>GG^/w%̂;1Bd4<6UL=ML0)"Tb޷}ǽ"W Ki՟,Nj+ƳT'h1 C'}L iIlF8a%҇x6Pe+ wop2u[.Cp6&_ǯ oe0ۚDlhvd^BE#W OjJ PfA*iL[(ohoW߾^UȶdIAR)NZcPIhOA!J>P-ڬUq-FD]Ȋ0MEOOPcՙ$)Y\|mO0U X} ũէJ70j@eiO68AʅHhX$s71 eٻ2P#M V^0@3}cj\w߫yEu|ԯ(u`,zӝ^Ј^uS$I>f0? rM{0Z|#T`؃oΦx>M !ETF]aյD|1:@7Y9]~ޟOwbׅsyL@F)RlցHG=J˜dCaz +OgYa-ccC)7K$o{d$6L4pi52q9z˼o0*Ӊ6{7>NnU)F1hy"3\.Bou0CDʾ8M ǯ3t9>ƑffD,A ˥LAn  XF#Yfv{;.-X?|W)N fU-|E<ِJEЬ`Wv\ɲf<MdHFVOl=[0 92h&fL?)*#=2| }i$SoPỡP@[3/)NhwYgȗmKFs2!`-,=Rԓ zd1Du;XQFے햁u]$Eg<:,GH'nΑ XL$ijE*$ {XФ?UZ6fV;3˸$-I:L.ա> K(GEktEFF:#n !;AEԓ#:i\~GpkYo,ᘘr6R^v$E W9+ў?%DEezMѲ{b $:pʹUA(骜3# x3Ru+1EIu4_g))0)@xދ_ ]$J+y#4DH@* LY0xKb(h"ł5E4(+i0bBKI'bsRtA[(ɅQAU⣔. =(TD/A n [ɰ5RMkPkENrKZI*2aі7BqU6:I-?)!,)QDddJN1pd΃E,a2' ^ hRB ~dQ8bBV9z7OT?3,?Ių([Ohr oCXOH:h o>, >y̯8b@q diUeTђZ)DE`g($*C5`EOw2z:4IY֕ aI+ N">X2Jm|>#\Xqbo$;`DS/22X(bQ19 s/]T|& |6Da +a%/N\}Gtv S "m<,һO&>{usBsH@ 樿j&׆j,<R37,KhŃ3=vni}XIҵ@"ꋝ߶;u@}ZiS8c -? %e.Xncv_x|Hwċ 1Vr͞O>,"g0vSRaĥ{X@#em%V2ɕ0 3aq$ʹȟw[߈b4'9FK g6>A3 dX7-QEz]u4$#XEvA㑮aj*8}LoUt6y+kpuXH +)agsY4okp+7)!N: 98pF+@zm 񑰐"Kv%jVTHb|!zX|F4*&^FWE=w }\B8VECE%9djd]D .&3<)M2]ؑ/t.ط?; y@AqBSSurþf&b5KS$嗔B`}Sj5dt>&ƏD6Y@8@*rgUm<=Nr5&v묆!ޙø8 $ձxbEJIHd7Pbph|nT|ͯӶ?s)F50+EDVRTv'@pa9NG=z\8B #MEr:iohIN,bVfrFANp!ņ3 a X.Fj:TAܴxC͚tK%WWEdHnpⰆn,ZzGùL^8kczCkyyM-YJ~ h%6$7Z+BPrcR=/zh~y; FY;ҁ,(%p'!IȟIC.$%#Cn|O(?MXm!w8U.͓6aOP GąLώGzqk4/x{<4_]m?'ǩqHx%Zh*qPXN= 7( z/F4WzYVHBGp>*p|sfz,@:!r*{mY|NG=UP<\<JT *R&FNKP /-jJnUG>b݃]XnwcLJCvԲHdܜس*=GBICc}%FkFu|d/6vMW8D?BpCrF4O ˲0?axPc\ᗂ8?oh8OZs~aRv~r`Y0DeM/8`> "fV7ԚH2٣~/w;89ŪVrqtd>dӺb5bv=VP1K'g+@ хi$l8I+VGsM*c5ƫז)`F_pO~EdGvoY X%7L8ꛨ(?u#%6AL!r'phwlBԩEl7/Ca`.j!TONcE!imtHadnɤ -Z%= xũq6n. S #l7a^N΃Gùgb Nc L"p)fIOt|`a9mS) ߎ8Ad<4G6FOt%Mڵ~kKu8vu-Tw@˨㟗Eh0K|7Nгa=j#7$xhjl \l^ļ;ҩ5N 0/ @k%Q$Mˎa5 YxKXiKtnH1ePEZ&נs(jG<(A IHೝA m]X$5MY<]C)\ Qϲ7mx.dUڤ@1glA*$;h7<4U_mbФ/fvFG"˰8-&-:n;ݮ=K1ؠM׹n[#S3+dc lL7}o7J0K-Qj1UYv:ՓeV? :3Ծ~ٟ~B!%4[!b} ElCmt*-xkzBM(FyB Sσ:ba8]Fg,F՝7ÒY%weݐ:IR(}Jf b4ͅW9uWLRFw558/%WX It8{! @{f-`= ʎ+J\(ߢiM.{@O"lW!^;K2 ̭|l|S*Qx%P~E b E]4`~ssbZ 3l+p0QLv݆&jV % &RUЀI@|f܃|\ٽeRkZ-*EtɄ&ڼpmف'OCF.$hd+>Uʽ 8e@C@qUQ !OwX2YoI %H>qE2Imy:~ߤrAQhj"R-URkI<)GpڬP #C@DFeVOGq4^-rb/]o]K#`RGf|+sA `aƄ[*MPb HEqXaŠ bhvP8j[ԀOp]J |@bD՜zg 7M {6'7Yp-H@ʙb *::Z  yI6f\\qgl6!X+3<࿕٪./ʻd SsʾdhSܰϬstrousers-0.3.15/.git/objects/6e/def3777f9b9a26e63168bb81c8d4f4ddb170170000444000175000017510000000050213736474746023022 0ustar deboradeborax1O0+nFvR;IU ZKchv$ʯǥe{4loR rM[J%Je*lx+5^Fr ^#LjYi.FXVhzSrYjs} [gS=b{q = siG޻ӳڗ#Ŵ_\trousers-0.3.15/.git/objects/a0/0000775000175000017510000000000013705244530015540 5ustar deboradeboratrousers-0.3.15/.git/objects/a0/570c2d9452c68be0b02d9346b445e3fbe1b2460000444000175000017510000000047713705244530022610 0ustar deboradeborax1O0+nFi'vU Zschv$ʯǥt;47)Aՙ.ue)k \-ێphL+` 4j:N]-uԪ!\*A pcd8xu6E#Xdz#b,9][Eٕ%gO|@xxpn,..4.,?G qڻY@;C"^Gm:燑Oi8K=g?6d{ &h xv1j <}qsW C ƶv.1 u\koꄵqtrousers-0.3.15/.git/objects/a4/0000775000175000017510000000000013704254040015540 5ustar deboradeboratrousers-0.3.15/.git/objects/a4/d6325947b9809c23e734f52df90d642f7aa12b0000444000175000017510000000060213704254040022537 0ustar deboradeboraxQMO0ٿbn\UbgcBTce}g!}xlPW÷Z@_z\#}5BERնqӉ=J(u![iٴR"sߩep?2;e#5_T:jkmOP%IX V"IRҧI='(v JI ˥uW$[71qtfnl{섣ۜ<ip6릨gDqe,^Ӏa,X=ze8TP?-Qw1Tt Cv*_1okOnf?1cf@k&뚦/Iz͠ݣ}Ы4%}P] <*vxM@YҰNNkŸL*i<Ӫ|g,! %b~7HVX-1Á`c$`7"p8ޢh,B4Pu\ M>F8|*؉m `4 un[ggK۞FT:_/iV bSRNKqҥՒ!B/\TS&wlb6,Ǣ? M&'{Tmn\ VF]bVyM;"25v{cEyG5$6n_f$Z{GDw/*-#/ G`!Wvԫ->X ؅)Rj[edP KԄ ]rߣQ A5]&x0L&5-=<)z&5 pٿ|z<nM젯i ƸRD\Bڧf=[r[+ӃyTkQ%v/S, pL, OG< 3Z^؜@iȊۿ*ddJBHQ OsHHR I<r4%.E[$;SJV NSۛ.?+ǂ0 ,d:qKSY foG)L^7pȥg|X0Ag"ރ KziEWG ̎ C74Yv]({ c%!EW d]ދt+,򵬜laԕ#s\<~_CuкQiXO .,D4ZhHf\V&y[WJ!,SjhVO=|QoKQ?{5 ÿ2U.KF.N_冨JNmiu ,w B.[wd+;c(%[̥3o߫+oILmޤ05ΌE=Truqp7Wf>/wUt,{GoJ,g3Yӽ5=rk\kHʈ C+JK_M0 |`RJ@|eR'>ե>٘7~殉Q(=rvԛ W 'q{EOStISbLEeC(׻{]%[ٿ~sR}:ѩ usFͬTOe7ysV,Duܡ_W`Jjۺ_1@c#i]쎑_׉Ȫ #Eo2Kc{iV\=I8Yd=0[77k}prBa߻e~(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%Mb/=x} Wt~2e_}y=%B4{[c!y ږt>=dᬈٕğAdB/ Wg% lstrousers-0.3.15/.git/objects/d9/0000775000175000017510000000000013750237021015551 5ustar deboradeboratrousers-0.3.15/.git/objects/d9/1859dd7bbf8c8cb41ff5a06108e35b37d7897c0000444000175000017510000004460213750237021023012 0ustar deboradeboraxkW#Yv3"\z2N$yq@V6E+SHX!%I{<}DvϬYJq.9q5^;ۛym]Y-ٰ?|<j_FbTUaUoy1>y⿫3|2NhS堘ǪXTZQrfO· zioz?ݍ:,FۢtX\h8ϣxO|TrgC 1pV\φa:ʞCޛ$IKcGZ_y?"ף /90h x( $1dכ[nw}9^t4x=u-άWs`m&,=IaotmjRȖXa%Q#0jq\O0'eUT槳#SwQ Vjqsy-.Ľ/~%M^Ubַ]%Y*qoO>nag\ܪ}`iiUӫEL0ӫF7,dl6Uks\~b !a.tg{?쟞tqyTreJsYu?]Nrv4_o0D_;,dlj͆EZxףRU&u0U-GxSL%r/”;:L`x^/`jqV ×/<HU'Xcw|p KL r5 eax bT wZȼH{+^#92Zy fF+P {0sF68%kѲL{FO *FcqhY{meA7it30_qwƠkwGdL BT2^=VO=WwV\ؐ$X#2&Y~^~ߘ;0 0vd!?ݰ$ y5W$S8;u~'TsM3v Vx(nRooӨ%K[Ef!w()S?^-y̓dsl! QKZK2A9r >cV![G]^%Rv^{0מNc2$9Z=;.G[L{Poc=p-O XavRH9~@TӓEˠHkS_B:~m?GAx(rzϺP8,H^0 G_yGH,[MNE)b~wO$ h8̌׫Ѵ@y"*|)9a͛"Ow H3Ȇdz𿔧 8WSpq&1ewm[x"y'ԖVp 2 [{Qa>g~5=}%saiZP՛B"eC*>L+](iXrU+ٲĀp=D֌81N)bh.cQ៭`:+Mk0n*lρ5%B4Z8θ?6n !a!!)b##ec+pG/B~ t97p NA'P!pVXhCC*mጵC{x~7ɯNgG"dY?5As#Ȏtox.I qwL< Ы3ZwY C=H$~]f$FaL#2j`v B3C]kAhj* 7ݡ,uH0W`@%yi_&jOMW"qs+_ FEP&Ww="KxSE[aT dž2\^|)FJ0O?rz[R)VTCOtL`w uzggga ]ʼa3JU&df@=8:>>kZ>c^S8@тiZHQj4@#gh䷮aY<ߗNΧJ=])Jg=21&Czݳsj?eNZ7&xHq IgBq%;*SΟAdhފ-xcWO SN$x8' q-s"h)J9г0xD{XzO2T(hjc_ȿkM~L$ˡ9ӯ`s8ZGrw L1T'qKpkzl X{霪NGiJh{&m|y) $Īm8IJ;Gi=fp_9Mj瀎8n7>B{W7RseTS8rF1mKureaM^Q᧳_턪$^Cu4' &Q/Ka4g$+Pu658wtRkF%;Vs5xs!Aq$p̨RpX ;MHN__bsH GNY4YRxH uxKI *Yo @ 4H t?n̚`h&&YYbeJ~h✷@.v1j+ݳ|'ZlDv2QH(oW/T-g{ Jߓq}aKcJ. PMFI~z$:R?g*th؉_([ht|aCiowo-U.>RA,ots;/.ÖtΖ_F?KS<K>r~Z:C'Q~0-7lD)@^E+;ދs 7 pY4ZSsVK“ g%kft2&ICѥZLN4Bgs0EKPX;Nޣ̞?%pK(MlF-hS`|-q^GE֏uMqkjݗ5G Y@IWG)BћC8hW@%}`Gddr"iMӕ X0ge9Fu_pU8u- [BYl@q l笡?hYVé!#xwVinP, "Tʔ8Beۙe}pfi$Kr,:+7e)HhՅ$*YBX Kl S> 2 ;0[>=90n}CcWY{B_FNi53u3( ob;J2XťUJѓB&m jvfЯ9i%rFLEh̊; *c"񐵚Y[h;$$6N{oW`uj@:ee  /H!n yiI.޸!SM@aP Wاcq~\b"=fna j| Bڬ?&k6? YldJyPD:o2=;hFð{s~碣jEsq~ptke)YN_թ_%ʁx48ݐ&ES7D*{z}-,3 #jMEA;)ݒ>R9X 66rINJ;8<Zmp?bK[L>ƻ j7߽{G¡{]Q1V::פkmktݏءW+InPN}n̒ݷ[?i:yZ޽ڋH&Oxb%&*l$s2oJ@Ђ zS"$D Q!|He<*U|CpuiR jq_ufʯ-sGAk w|1889  ڵ MDNe%y\/P$baӚ=0Ue dO{=U&jhd2DjUz05ڀ7{-Z%+aUBS^0  Fiň0;h#l?_ \NKbMXg%.\,s}S\'}6P#u]TQZYzMjTC%ʪ=L~FRKT)CݜW4,Qh}a *ȼkrlS}B}pXl+q5WG.}0 札g*Rdžx=yDp@ۏMg!@yfS$b9:ٟ\a騬_3T??r yGKz|Nq I]S1K@6mOjgIlҠiCaYs^w+v'ScipN$u#?!Y~J8W?-v~`[ʼ. ti*?vOlߡ'O(#_.B Y'Z۝+I!5+{4!ppɛt9naÌ\iu9c+ :գ ] GyON5gB$8*GաREC'RZf4sj(H5CpK'4׎.߿ݥZ"C:[0]!I2Z@F!NwwdMj10ǴZ&(BnsdOGԯ.s5zR< Z< !P5FRSNN'?nLl_0PU5fHR*EO{$A1yȒn+l)vFK7w޽|cK5oe1aC+ )Lׅrx5Zv% {tFKFڙp=WDnejXlXMi//:g/B/7#AVBRer7W<͝͝Mgw `t}%jl^'S _U=S3n$xqzLtW_q y%;%c`lOLIevNΦdg#XxK->n5cEL81^Am \ .0tJvZQ:jQ1x~A1<5BHA<ɶwZ^{\k4VmIV`ڥi>[uе }?KwgzŃ]*_݀$ ӹ B$dZI<[`co*\~WU(uƔ?L6=rW~< RdSGnțqH爾t_|HJ8$W"QKt&X2a2yhHB%xYf1c8ꙑV A ֺ5lf%0.KP-)N,SGoW+WzrK!Bhs^-YZ~n4VK]"hKI{.~lF8 ْJ [tMu' UdMloI@fP}:-$>.p8<эM{U ǥSσTNMj%VQ-}Q*4WD /&5,гGl0 TWU3ι*7c(")"9r$`Ï)̴X|$H\`B[ǜoHj8;"c5O'U efT~A%AHl)Y !;g:cj&7qjrK ,mb|2!Xczބ1dZ ݆cTb/!ǵ/Jx"v h Jap9F yv|ڌ>E@a I!ĨiD "V|a$+P.D44!)=V\J%"iP^D={naXϕ6}LZRXiRbHJIьH 0dGy}^ꮕq0 ~PWPD]\e5X5d+v1|Fd.LG5 V=.ʃJ9~[:R`=/?|xp3`)t /MQŞ4yqJB4dE؂75N ?[Φ(j,WÜ(Tj%pX&rX86ŭ˵t3qvwD+VtAϏk#gHdv}X|9>Z"GϑJq=w5ΖNT-dKx_#]sn.8x2Pu6`/̴n7t UVٴ0`9.d°BR{IzN5$IA-  kISvRO%6>-DdZNb0I-|Ėѻ\̛]`p͈YF=UK/՝S/ FZCd76?vk~ۥ AxK\J#Xr:})C妞|e̋)v G?H+1d  &\ݐ^Q,6k!k[Hmu/oS]@Z; M H)nhnTC<=$=4p6qZ{RCJ.Xx|S*4z^ Nu> GGFؘ֑410dL > :CcQ)w.K7lx9T¶96S0/.H2  ^)uwcCe=cmc{Y-wݍ399_2 & Jtq7Q?,f.9>dS5y2_Us }di` d cѠe\>'!j7 07$ۣVkmyogcoHN8/u˯W/EP!qkg4R %?!M#V̟'vsyys7G2:vlQ~fUe4Bŷy,)]; yݞ焺d3 Qdt}1+ZeU+\+˸Ks=}^?>b;[3 %pZyh5Lh$)ç\#尀{ CrA/ [A*?$N]大,@Y+Yt:BeQʅf93SDK;lqM ;`17"fj(kȋ4j^؁gZLދ`ʄ^)oF6,&%d'䐜U.RNHHFӛ+Ԉ&%@+MZM_^,'e+IҍެLQNK[!tG*M4Bu54$ mZ겭 UÃVG v0TqS IUʀY[QqLtI6/ Q}㌶n0$#֯F>lD#WZ2Nq0:1Jgj&duBH^;bD"EH܂kL&[8+eohA& ZNrQ|fBۛi|4&ϻDR3)I7JR(YJ9LH+^'i3n&)=9K5:5셵z*ɑM[6"&9nrB~l~<,)Ԫ C6MQ%<t6~QUY/_$wͭ Q?]lRsX;N!],R;n{?+-k1^]b]loRP( md P6[1d7ZO#`k( FhݾY6ܚv=n_s{޷v6 g9`4M;+7-,po3}:W4"wIeJ]G+%a467PxNrZSQ|V#)ur?܍%Fܔ5lɩz3f@Ax~}[-D!D !tToyӭwǔ;>#}K"ZDdu"a/"|Щ_)~ jS/[3(τ=n.pWA `1~&n^Mo9lƷr=~c*L^3q5OTK^Bn+O&TC|S;?\2 ;T=4#16q}-9L|vVǑL^Uv"t<җ/ ~B[e Mxb +.D\q_A[ճJcz~PݰZCl2fpԏNO[|]c|ãy@|C) ÚanASe qі)X]i,ݟv4Q}s__&>jK21=v- apev a'$~?ײM>ˑVs~ܕqQYo .ʫJ8_4lLYxHi6}Y,߱'H xǞ56&#N}p 5txy?hGqqWɈiC#Y-mTg~3#{~zzO6[BvO31H q#&7;lUP@>.@bT< hts:&5_9&utx[npAw{\א=wMь4ƳC*Hq MTkP\SJ:I_!Cg=eys"t<ih#lR5FfEB_#qjN'1 [:`Y`2IqNaI)Dx5W`k$ZԶS~D샫VAUHrkJ"ȽQ:^*Z,JK;[$p0+޼aZ(U?rcX@-E .&nSCv GQ3g%ܩ1B:y۬8K ORsWԣ =o!Yx7}%b&s::&/osĝc!j[gi8"R|VY(Oq/_9Ig/\zFFJ׷:"Cg#h.8+XWLa?$릐Td|VFD%0BCÖfl^|I![>sKFTW};sp=gr۞u)'.H*\E-;rX\rSH]]o=y5uO lr}0eF9p\A lIG{ ;p- Y_%2E$ӂmELe? &}hИմs+ O{ҟᆾYR ha༗zy/D E#vmԠ"~BX;qWTϷS =rL+Mp5ey׭]dD&Mc2L% *^nDWynstG"*S:s[i1wyo!ZkTzxl|A u>2/.*V8F'E0\1-w=DJ@&h嗢)zA|D'b3/׸>t;lZ cRU6Ed_cT_]$E^u3pαz2 D1>Ӯd 9hm/`n[Tf׎PZxuU9es%+CD3ʊXT*fe ⸮b:L#<廨Wt?]t?PFNc" K5T&dɷ=zW)?(*M,S3drLJPFK'XMU#43{}l^5n~ ;\ [ѺQbrʡrRT"aAb ʗɱ;$>s .OX[({Pvzc:XZeZ2 #xp=ef5_+'2x1/-IABx3e.ώ-]GL{490(/=ЁgXU[8Я&I~TM7+HU*H;kT¶鹱 @فnztOMzjS]2 y -BIngV7$}I7stT$&O83f,R~m뜚OF0L׀kx-1s_:'G?JԪ )am8BPvaTwX$)vҚ`ԘAG<!9JRX7\֯ FrG&|AJ"aL/ǡ̀պZMח]a+G7(SBNIH$X!*ո5bH=;jKނz\|Ky'8s,gUxSsךh܈kj`% V$] ^Y7y8Dl%oҢ?NQK&ojd<M˺qRPГ}:/' KUDv0t14-i "E}?"j`I0^ð ]g I(<'r1$Q*rX*VDKrA4U{%@< n۔h{u#U:{9W)Y:~Dgc)Al?$ׯz'3;zins?_)cf oF*|E+Junp=ZhR u@e+:h$V#ah3d#yl~NɵNCXqikIqcv|qE|ş$Lik4NP7ҴS&UU`o.͵ǖ]%L&$W; H2U42:2L7f 9w rH ^SŁpg<e J %W~ c;*cS%e9w-1%^ϐ4NkxT.O.j+ \:UK|jj 9;>mL2JΦHj$ KNXz $NH`k*I^bU  >HөM;u[uk6 M\"i<8&%u$BP|F BBH"3U?F2kL,i X (p+yUN[dMƲ WrAPT2@m]+bXMgש~S?BʗM6˲Rt,>K]H^.5>Y/4ןWRsdBiTbu"J5 ɾՠw]M%,0Z7tB)rz pE("s>H?%Ml.7hʈt?V=Ldda,?j>\)z89.Xh= y\ ,k5 @Ckj.tc.U>o%Թ"(˚~`qօ&UGjr5~&CJW/ZSz,9MF/hi/QC)HR1"LpGq<:SqrLZ c]{t8v=yH@+>43:V\N B6K:}1C4{ٯ^_ټs R[U BxL2./; o?,n]Nz:ZwbCq©  2=J;Iop&ODt윱K> /^ms jFDq7="rvaO-յ%JQ*f;GWHq 1pN6/bRFB) EAdWvgU

_F =f]LDڲZ"(=L?5zY&0;S,trousers-0.3.15/.git/objects/d9/b8c17f5a709c75b2cac74021814930de38cd650000444000175000017510000000101213750142223022610 0ustar deboradeborax+)JMU053a040031QK,L/Je`ԙ$ls'K1?N) UtE76Ǭօ8B8g$楧3/_`VImT_+' B#o&%71;5-3'U/1W#D@ ͋7\<Ulٛ.^s\WuГ0yM!a V7WvaڶMrI>(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%-o^%n6T:?񯾼ǞAY!eҭұ"rsCEԞl7&W Μֵ snKPDmjlSyGtE@w!àͽ7wJ};d1Cbm$F[PJPTX.2O̭6'@.vf(Cq0 +<(ÙiK!S SMy#zs;?8& nęJ*N{iyFHθ *= JSI`G Յ~`P-clGg#8U,dP1?\(63*r=-g1 Qmϗ- %~FZj(#VQu%#VEf10X<,<0mç2 FR_8Fܺ<_|-o҅:~Iz\ }m X.UĤ rE"2Kf[lA㰑f9aP4/y=٫nӔp(2N+i&7Y?(;(E.8N$$ }EaNRIDt Ⲓ._p&rElGk䯯h٩Hs{%IX])yr,IZFJ JL._ 1#{  O;ZQy0L&5-Y'|\_e=u['ܬ/c"@IJ p9"ghMi3.K1 Bּ퐻g<-iܢo|(G@z9 ]n7&fvH`c\)X"r.l!3fܚ2Td2pZrooɸ^p@T,DCpG᷋;6=_q3 deCtoq\zH{b"@Uwd$ժ:c D6 .dnXy<T=\VV,>Xl <8`Dj̛6O.VuTP F8 M_}Y[mgZT_ֺڥPS { sGO(٭{A aSmnVƝCw4YNb~ezp9nUѻ֝%/zZbW}3tӿ͙.۹{X JGW( & ),$2dM`!\SBQJyh?3ŻHIlӯt25!@q,21xM[!k4itAݢU3]Z{' t& XذĬ&ZľOxU; ّ׶ey}B&|"=XIHU-Pk2YGh=*ˇ9|+zxb&;ud'̺_Pr,m{?𽺉-fUQ uٌ+q$l1p\99exC&q_!yGG9^}NGy"X3K&w<u$ iFc1l5<痕o@fwW%|ӗb1JS{ڲtH;n051_BՄgVx+ 沙'w. ӕwdlM`Ƣ >^efAա*֛RvK" jt/EMޞV{A6 N]gL^at.2W|G B'>`ߓ[[Jaq~}b=Rx5* b5 v>kEՙ/Ӣ)KGqfr݊aX ڍSs[}$V;XqqR5ֽ9:sn^ gW(F| Eֆӭ)$%trousers-0.3.15/.git/objects/48/0000775000175000017510000000000013704262765015504 5ustar deboradeboratrousers-0.3.15/.git/objects/48/d278e72969aa0de50ddf806d35f971575fbdf80000444000175000017510000000034413704262765022750 0ustar deboradeborax5j0 wSVl˱QF;:صȶz$qQh~FOB>$2Ϲۧ*CR5Z吐 D!XRA7:V^ fC30E䎶z.,r%ו'"ә.toZgm{VxP્Kbxqv0?,|a骔meY_`Wn4A@]?޿3Z@n/]trousers-0.3.15/.git/objects/85/0000775000175000017510000000000013715667431015506 5ustar deboradeboratrousers-0.3.15/.git/objects/85/d45a96b7c390f2e3ed1f7d4b5971944a2967b60000444000175000017510000001133513715667431022605 0ustar deboradeborax\{oFO!ʊn/S#e^.HټФ@RqKfv\R$yprYp,vw~io[u% bč<ۏŶ8™%7"WG](nDy4qڎ\1H{5q)M]\&4xa`p{XyrIg4kv6'xXY8^غ7޸yEmxos((Nw?Lnfnybk؉l ǝb'hrcvzNeSo77⑮cn:u7i :8?˘ $٘Qb}]6?P)0ΞLB3[Gfcٺ39OMG%{F NF\;{)\jO'A{W^1aYfCUs&}[I<+́y{f=K"ryu*9 6զ~gB=z hxF4A#;7[aM`onʉkEaؘڀI([Bq>`pFYGgMV-k?~ho_8:8ct^XǬŧoIbI$^0w{΁ Qm`=H$-/Γ {=X0XgCfwr%3ga}l4oA 8SwOB; }-M;Kq/Wiŧd(r*3iU )2 -NlƋس"O-ZE{u2:;,?+Sj%" e$6Qg0֜ Aa ִe)"f1EM("fA@B/6Y)>[D|:u hwj/&˘_ 2Q#C`xp!9 :>ˎizUe Yn O+9K"b@v@ *j. x&)%΀&7 !}RD!G Sk*2]?4vrp]Y I V[ (?vQҽid[ײV99Q4g>Cs&MK !(D֫yKI?@[oXV&#g Ϟ) !ŬsZCޮ'`zmMϕ WYS2;i"G-z&&9WDۡp>ewE(+pPKO,(G ՘>kE[˟3 ,r]q6 !S7R>YLd .!u@8N # nTrQ@PyZls} +eX.ם^?}b̘B +4'IQ٨-Υ4!xl*&WW(FVAUϮ,muF!j3e ,`e4tpȀC! rUp(@c83Y!IT(jttL*DN {2+ (IRP7a:1` ee漣;.Bd0@ O<of RE7BN<9Nj|lEcuRjxt~` ~:[)S^Wla,NI8ѡ2M.툜nx~;%u'pŌD,;!3*ңN+쉀C|}JCi*HuɥQ#Xwip}rؾPX"Ď~3{? ߓ3 CrEdSDU t 6 ()0% C}[]i9.D ]w)>33o/ӿocak~BjLJ/tg FvJU>S7:-=j'YyD3w r(}jRוP%3ʧ->|2ʥܺ~M|1-xoxCKxrh) ;͌b4sl@&vow¬h^K=‡y#W ~͝cI0^ϣ迪,wWӗX8*4ϣNL6iP]+9G: vr>;y"t͔K=W<-k eGvw*=e9:IpՁb0im34L v >>S`0bg'8pA(a9phv[mf5v8yL$H%qOVE B+b+ @cENR6&z'nx=.*ȹT%WZIY/G(yXHM"n״~E[A!wGjYQhRPTx.~rJ+(*Qn`+Ĺѧe}X/*1I % gm)++%g0)啣\qUѶT,FSr vaZL覴t3yVT$QWm_F Jfp)9óG pP&-k*Z&N!BlXb80XAe)r+mHI5}g~ypͼ2ikHjL4SF@+r`ZhzƩZEfyUsleELSWн3eT˥[^wY~*LR1PDmU@v-6#=G /.|8u8DLrYN<^:>-B.nlpꄘa@ k߻O_6'MŲ.\TvoE$U+r%c1D*gAA50[j*dg*/S}K TR9 M!lu<U ϡA$C^p(/QNwom|Ƀ(>g` ȣx9 e :[qQLҶ9=]Qx0‘k\*:Z@'#\3 m""Dmd" s*0!HAJsD;[C%R3hVyĩ }ixjר@ =^!XX8q@vPR>t n ;f>p` $}'V3*Yov>i֑=Z "r(yh37}?BDޗE1>0z&vnoı;A\f -GL]`1L Ά#}6zE2ߘDRч))XMW@/pKRr~%ENRK>)xi! f|l97>"NҨ&a׿*)Ұ>S,z,FnM?Etrousers-0.3.15/.git/objects/27/0000775000175000017510000000000013705244310015464 5ustar deboradeboratrousers-0.3.15/.git/objects/27/f230d2fbaaf0387c588d967eac42267f68ee980000444000175000017510000000101313705244310022717 0ustar deboradeborax+)JMU053a040031QK,L/Je`ԙ$ls'K1?N) UtE76Ǭօ8B8g$楧3/_`VImT_+' B#o&%71;5-3'U/1W#D@ ͋7\<Ulٛ.^s\WuГ0yM!a V7WvaڶMrI>(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%Mb/=x} Wt~2e_}y=%B4{[c!y ږt>=dᬈٕğAd=86-,}YU.trousers-0.3.15/.git/objects/27/69af3662b9e100480600d482d044e3db2286f30000444000175000017510000000355413705244310022312 0ustar deboradeboraxXmoGWWL*4iT)n$VmO[-!3{oqJۗٙgI'/N<:(PIBFgtL7^lHO]xI*S)/xV$U(v*?s[Z6urFG$tnE2VzُvyEIBE?g&>4Jf'CCیZ@5ҝչ * wD2Y)zz /.?|C2DBs2[|d]\ _?ח,TLqdb+KY6)U+ꁤ)^DCՕUIOSI=6Ze&?k=T`;~*J7EkD?ӚjK U'ډYijb9w"loE=bi]5clxʹRlĩ箐IF $uO>­@l^hɟ'GeP`Ɔa[Y$L?[6c&zX&;\{J:trousers-0.3.15/.git/objects/pack/0000775000175000017510000000000013663651711016164 5ustar deboradeboratrousers-0.3.15/.git/objects/pack/pack-85a01a5aa27fa78dc339f8f50c9d298ba6474b85.pack0000444000175000017510001456130713663651711025433 0ustar deboradeboraPACK2xAj0E:\fd{l)ҔޠF3JDj+24o JxUUvДX-V/vqc< 7Puk@9z]=hXIN1K\jS^o}m3},+XM~DknM r!|CXV3Tc>ySJJ;1)]OxMj0N1ߥRz@#(R02 JE`EI)SԄUg*d DfFϸpVwڥ `q_h!4Έ^9{*:wSR f~kܷ7Xh- :߭!O3 aبqj+]K6ᩗ2ߗo\QxN0)Fv B%!" >7ĎoO N:YTiC+Z+i,*dhM(n~ia$?$g9C FF;5]:.p\9^^;8U8Lk>p92sUJl:]'xr[*(i$v ԿPQx̱N0=Oe :;>'!+wi6v=,OUMA 932(8D ,&kq0E-DXFGY)Ge*}yfE>f֗Vs-jZo_j׼mH&4oVÇ'5yZs66]ڐ'x[K1ͯGvɶ(UPZˤM쬵X< >rfr"<\E&sE*8e %Jq4y b$jcTŸ0#scTA54gzʺʪ f.*Tj뺷!%Vwfre>9gDVy~L_b14I(/+F>;^@:ymE a؀"S"|o֓Z ZRcɾ?X>M! xjA?d-DUl0ada7uӗsvk] Vw +A<{ x̿N0=Oe :KBH, ߝMƮ"7`wU9 lCS Wڵv}AR$@J&ɢ;D/ Y&fªE2v֪y]z:~r~0<-ʥ\zU6J۞ 3#DnkCީbYd^"xOK1sl.v@DRdvMJQz{@K(^RZJ֥, ڔMVԢiQUݚ["n7XOsxp{߳Ysn /TUTp%U-JqH-ĤqzUFFjt'BlRjyU qlh^,)"o*vlŝJ JѢ*$d7kDOY؜=>kF`qr[mkv3vn |6/ t6tn~‹BoQ o${sH!@t;q1وOW.dFwFx@wgC]*RDl@PځWBGwN+p#1GKr#< k+ɇB&PD\?GR5K O"xMK1s]M[QJŋ2I&IMRAzwfBO-̘i\N25g5͈m')r1M 4ә!IT ҅PRp;(g6spxZZ'Bbe(]CZLs!8y9Ά@EӼ8v]._aahnVw:R1/*u UAÎ+ a&nϲQ~$0:cb,#v}s*X.XO5abUY=lɝtðSB vH{#=ƌdл xn0~ qBHEU^*r 1$6~ ^Jo7$R(+rqa0%{Ѡ jms lfǓLZڶR;Gt^uGqsoE閫,{٣eEl5̡j!;p̌-@TAwTo -A~* `,NʹuظٶXfAyBVxx\E͙xN0~=¡4SUUREDꭲuQqVNZBBX'R`Q)1vR }]$ cK,WErUiK =,3k_k/bх!bjC>cQB* ̆bۆ5<56,Zsv32,AVEsQ_+n@N[SX%P#ZJWKI֫f?ȧ`גCK,4i}ƖtZ)=Ql`ZckyGGS.?K`_{xAj0E:,ۅlɲB J)IX-[.@,Dd/W^+M*5D]، H(m-];cAjQmp!ne wӜB{zZiӶU*`.OS,x ^O]o8|cvh'~=RֽK1sY˂^ h'#1ω|CrcxN0D=!I\UB^7nJ= Rpfg祑%'JjSJ Z⎸D,Z#mS JUmL٢+iZZq]2SGS"ljjv8%'UTsf0h] އ_!_֪,{պ#x =4k,#41WoP9<ha8cfѹL6dH'KFƚxAO0 mHJ֦Y MB{R;ku.";@S$uRZ_Rke-+SIqqBw(U1֡XSB났!GŽ gx~,vxJs;PeUk]RB&K)E>D-(SRUEgb4}8!+m!L'!ml\ |ف^s6#k8k/Bp`,z/WF {֕x-J0@}.ua䷑Aq>iҦR)<ﴅw&%K܆ FLB "kBF4w(ɍscQ&&F`6h;|=\FEz2Nk'8NSnx^\_oY<Ԃcl;)XceO.ֶy` N5Fp{Pxj0EY!B R,ݏQĖ-׆p,Zr5K"GJ,QjŅFZ ]-+$S:rNZm山Qk9wiί8bIST8~ѨFF6R !#/]LJ`GHR}!η9 ZQ=ɧߪ# t-F2=4M2'yn< iIs?yd05,wlGB|B6/yYxj0DHeE!@!S)KU^Gn}(v2y$U zӔzU†HZlL#ɍ+T՜:Fc@DmEΐ'ܥ 8F@ΙRnVֲRib4sbx">bu.qۧ}yL~(Ң2Zm?x#vA84Rra q: fm*yyJZ!ip#xŌuS"xy-uI^ xj0Fw=F/ -dH\"d\o_wB hIf%2R^K4* wfiP>4Xm6(G虿.pvc.?x2ou{ .uz!VV#}IZ[5xERKo0 W!MŲ5 }`ن YcdXrQ J D((,˳9jT-WhEV*ŀC^fIg+ȋ%i¢^)).M$FOZ[8oˆD"[eV.K8M4#q[k`Ӓٟ!ÖQZk$Ch2kr0Ob-VPѦf/P#C?)хۛ(! f/-`tҩ(C Zs 5Vh y "4ǃf%|!v6*Af{k;tI4aywPUUU.g)Uo> ??h.9A5{CTp ۇݯ~}wUݭ&K *C%j^JSN xjBp y^uenQ(⨌'v t jqMf#afЌF^&CA: \l itItlP9GHrgO ϏNoQ%?LJux=O0Dk+[yv탙|R 2]_; :Ŋ +)o?2h$W6,EQ i6 nd4h: M۞(xuϊ0 ~ =nq`) ,P(21qf&U,'dDheٴ4 [Vn@jZ[fVbD!iUkiFUa]պmeȨ'[<os_?s-fOr).ﯫb@ֲ)R,rWg.;L1_ ۽ʅe/,n=o ּdci}])Lqq%!' ,fh ֌w.QWSܼ xg\;ǘ$\8òӖ sea#^17ܟ7?o9E𸷘.>aiy[3 б y:c{FMoJAmՠ' [ozY:TiTgu5.N%Z7 +AxuMo0sLV)2]BUYEzj*Rh-6;nygyf'i&B+L˼,To$M>44k1'AJYkR2QB96Ti)uYʳB cM̀H,q)$ N=UqZkk)q5XR*ȒCcn0.y;_u{9V9A' .˛w5epܪ^TÞx5j0 ~ i2ià"ˍc m~c铔#3ut©~U#qAjh͝b> շF%M"Ik'<ߨ WO|veOSL9A՝*~I)(͙#Ʌ~WG*;UQ ZG 2O 3e| .9 ( iʐ"M߀0E3p04cJ|9ch0 , 6Mi/<|U$xiIVSS#'~Wdx]Oo0 -6W'EQT`v hȒ )IO?:0`'%J%1Ì];>64<6XOa$1t;FEL MkL< ]=zp \Nvw_eS9*ϕuWw}_7?tNpt,a)Q ;u;?dgrSW2{!uH5;dZ旗A:Po047w 1#Z./ p§Old/?~?^__}@Ӄt'p;ψS8^csN }brYkg6Ak].&RɺT-ْ@**h?țELa,qִc4#{rt XE^UƇ yPo7Y{:E0xm1n0{^eRًY)*ufցA>\rij$f0K@k{GGСwꊤ |GwZbE^c:_>%Imߤl$Ѧ&7ej8/KU ?pr9G{Qǥ=#>CLK>';u(s}ҷU$ 6#Sşx=N0DWvw-!DCg@|Q04\n4zg)&K9M$$:Ϙɋ tY0l lPA jX({ IfD N8!^t1PqӼf^潛u H/]lТ٢yvcΧrޯ+Nmi5u#՛mtO1rWĚxn0EY 881ETA*4jbĠ(ЮFJGL WDrq fcJDqB#ϔN%;`G.fH TR$FfHQ %c}+Óij|s1߷hHv\'i "ж6.>}(; oV`u(w/W92VRH;XUcfڵ;o;~E'G!U{`[w十3p#ayTuS9Hӌ-uxAn Eb.  NeE*E]tQ!`aܺfEV3?PtjYrP3.:B2E]3I9'J2(aԂ#V ArX nR^MbpA-)eP/t8+cZrJ>gKQ_*.c}V]Gz0: ӷ>@֓!ǘ2]ox=`f܄y) 'NF?%h5` γv4_vsaӕ?[  xM!@ὧ  C>ܠZK"!O+"8$,_هq)V!:ag\zm/aDTs#9!mXmP|>G &w/N/dvR$oR}nos?u>C 6]aey<Řyn1 Ox}MN!F 4)]S̐ 0aގ2ꮾJF' P;;#0I12hr)jUBvqrYyUjIԪ)J 56NNGB3?\ιnoVis^1§`1Nh#KG~~ͭ8R2ROS}ofxKN!] c+{Z0a^˪E̐kʓsp!0E2)[I X \ԼlJTRtֳ7)hdbx_~Sֲ˵OQE4Z Bďxqq<f%Q!^[cZ- `xAN @_-`[W ~& m70qވ*miws>zc=}N F\wp'Ύ9R>N&v^/1'{Q8sjoO/y0uYMƺ=82JJx& VepPʀK]oeeJCyX?ahixQn D9^klUU?9@zj Cc p޾ *sFoff084'5f5ipHJFSϬȣr{2#JA!R9%< epkGO^R^ >EY5LV@ZȯXIf -,+ƽc_Om_xJ@y ͌EEn*wnצIZW,ܝ8 ޱBJƥH-[z4qY*T'*%V[UxxW}hlaw_SLTZ* aI$ȿ$_!]f0YfgC6Jh[ۺW~- Zͪ~>np:#KPɻOG|xeKn0D>/j`CEUVdNЦ4}L*u+EfiZUuV7 AvցHb߈;F^3 u@c!J (pOC.X>o/ӸX8n_ҶRV4< ?aBcLۺ`2A6 Nrro/׃Xn%2 ~J7b4 xK 0@9$1d&HmS[̓!Tcʘ eh2^13%+GF%jhʮ:YY\~sl&8eUq:, xA 0E9tҤI@dGEj%F[6< x;1 >HO8?[Bvв([p{Ӽf4S`3 10sH5 Vi幄 ڕJRJ-$RUhuߧn_|"Kt߶ZΣ>6n x9 0{b4Z놐+l[F1} @f]L\J9DmfLf*RTISmE{lu6N)I=)*::2:EKoK{9;͕e֪*p}6m9+ x10 @=8m$]ۡ*E%q{y;xscj^j]*DN %l~BqTcZڰZd,s i^78<"3B8oAe{?ְM>>>ܹ$e\ L3 c|\r%N;(l 1UFA٘R|곌Qp{ \^m}??Q] L-\u6>Ѳ?t]~4n+hypE xI0 yHU,n%_RJ4={*2f'#&8[}P!֢RT%pn+b6K$Ɛƚ& Y2kgUkpD9Q$?q.ˣw#uǦB=~n ;ɕx] =žJ wqu$c } @afzcl01y:{cKb!UV,^2dNSr d-»?jQ7xyv4$b];Qeq,zn{1zf\*&G x1 {_!o~rҍ.>L!9W:ZO&8E+H䃕i]>fmFޠL5J9:B9ޭjI:<~R-Dۺ1n j T96^W*%mC x1!{^ Bbl|1?4ax\r [UB^({F5^<95QU"Roi{3ԹWfU(}pu㳪 8|F;d]GXN3L/8֒ xA 0y޽$uA&"mJL ނp`ˌn9 Wl)P$TL#MLE&, 4 jU->:}@8A)O\i2anT)s[9 x10 @=bNH#*S 𗿼 G \c F2 -TJU=s}r L2F=T&6\>ƽux|Zo@I*'[ڶcϒx[mf :g:ExA0 yV6`j&NAsR?sƛEs1qD=8(#G-ux#IW2K.%x%sm|l n_c?\CHuwG6Gjpc [mfɯpp 1?G xM! @=`ob]Ra^/|7-U *1is)by-CӦ('-I Ͳϵ{{Þ~3hx\?Vojl~9p76x1n0 Ew{C%K.@I&B++} VA&HzV[Uxe^#Ra[MFdVyk#jiuƾ88!Z*| szZz ۅw ʶC+WUޟOO_pG8 sO.cgr3j'{+G"OU} x;1 >HOckK$%Z_`̚f$ShZ! }MTr{Z>ƐSm`B0 ň*>ן7%) |r2c׶L >4 x !O=XfFwY5̂޾|UZiEhbe4TQjH1ps_Ƥ͇ ! Jyn,*f_f}kÞ^,"01@Lͩ‚3 6 xK @b݌Dһ㘆 zz,n?1vspK*Z9T-02{oЎd/8= x10 @=⤩M$1A qCښJeF9bm$3,,A~ntbDe”Bf.a}+ x @=_1? aJIqҘ]7ӊ 5>v7gqpXC$UUZ4ֶZ(%Xy <{85dz7lS&ū8hMҴsSwFkmUJH!;yq.9"d?}(4 xUN0EDnҦEB {;)=RXX};zCEi* ̕/JZ^jjQ .RE瀠\H6Pl_m^2-gk֨Vz RMg#-Rl>f5,E"" v9F8 "NcGVgq]Zk`qχοUP;v9}˾ y 2fz LW Z9 Q@I[fEh] +{SM*h`dIfRys^<plZ6'3xcDBAg? 48i5cpwi5G_հ x]̱ @ѝx? BMqq4&T£bJk{2Duye+%VJ7+#%XH#L׳^\|m &E`/S/8$vEUIacO??1xN E|[M)c~=dZh3o.ܓܚ`PF5Y% UY;B56)VVQ{d'z?L8Ga {N$uNނMFx5.y KDmk\IN Nt;jhG^ u[\B-ʗ_;S+&l9mOGUg40kPS$l=G&xRM0 WS5t"@=@GnЈ6IYv2'tgpz۩cבAiǘ͈O|J^||(5P0W&ΟA۶jUׂLo$Jڈ3q% Ђ8CΗ\/P &692y |{|Y7ZWB,7YpڕU |0S%brIdٮ$bBK8+|.b?h,» G0#GwZrX|6Hb{ex,dѹ-O"Λ'xQN0+hiB 8ʊk5µ+i]i^Ѽyon7D7C(z61\>ԼpH0~yZ«>w:<K3} o'p"х?"3² N@}]>+חd ]x v@ .bH.6jW5,d#!JMZ7WF<:r%#)EFWOJ[]rM #1nOa%U>G,M$LHu`H [sGrus3O޿% S4,x o}9!"Ikekak!eӷ BI!%PY$"m,[k[-Sb3N޵q9ɫwa.s2q|![4M .9g:nL#x|PIx)`1!!{h_PGwa'; E@О-zB ҅n?)&-C)9σ(5ef4_ȥs۹c!."Ѣ=c+xQM0W Q>gB!8ޫ=nLr&Kfw+\7o8A`okƢ,^SmSGҷ%ѶqH|otc:J .< w@hyZOc˩xE0Saom[6eSJ^Lmtg5DSg "%Z)C8S)Ddэrs lz JxB_)ċaϰO"%7`3DReK@AkP?S%H&>Dv(szxVToyi+lUFxw#^\Yg2cbMO \d;2 ~̐>$75UC추#xN0EqB 6]TB}ǘ;r=b|;g&xD(˺-8RMYEDdӒfźQsVs{)%Dڎu UQʮ5W0l2y8s`rCnĘK7]M)m[E a!Ɏ8 fXO N~z7;-VS.L#8yrҝћ HQv,be0nN߉XuMQB %uOsNE)DҌz0;FuRS7QΘmnH1SdfZqR<#ip4 9xܚK$nٛ%ퟠQj%5=3{|'Ӆ,XkP,`L7dWwpԉ% ?~%X*.{ߠN/a=@VCl|@7_}X ϪbB Ar58f+dnOIz)\^5Bk${JΝk)wxQK0+֊0DD?`$7kMFn7o89ܜu]16Nw-xQX%#& \XqJmThR;Z6mg*p}Ld+Ku +D5mz+^sΊ;ߘ^  Yii|l9qF6qрrO|^` ׂWMI^ <n2hJTsOs bn&vi*~s?ݕ/dWѹ^m(xMn0 :wL_Ad1-SPK2$mCD{dIDЏCc/1U+:c-*7bD@VK%mwUm55궫`r 9c/GJ~ '{wߛ҇Fv-;I-_JoUW}|Lp_OT^b2FL4aT`;%W.x|R{!r[6)C9m"NS4p gJ1SpJq6kze^Ĥn]).ە@|y-pM.?L<. uǙ K#PR 7>LJd -|q@.Z?s. xAn Ebv$UU= CbCqNfFCND+Tı3X7tR75 ;%i9;D!Yu喤;ikb/=¼5Ygܖb#)ol]}tno~0dx[j0 E -HbR t-O I<4}.`~н:d"nP3:iZJJY'1RAI[ZttD6 M]k;ZƔ݈;HyneD;7. Ԡy[NX ]1ʘ? {ypdBx,!9ťj;҄NJʱnvmݿ{17U )[:=\5~Vs,O C `o~4h xPAN06$vBH l5ؑ㴅cJqᴣݙDJ47iII#]Mm{Qk`H®9ֽ VBp)T pcLpfd |ۥ:ʕT[s9+sh {0GMyD=N(K`6Y\eH沐cN| ˺ $cC#\K’RJlFa1W1-`PL?;cҭw+wi#ѾbͿ~dH/xAn b?` X J%^T $WXF@n9Ufv5O5lE7hhR /\V<$iVJĎ9Dtm) 3p^\^9,}\gP8:itD).5~8*tFƵq%o[.gK3B\wm%5PIw^|.uȏp$xQM0W 'i[%6] h-wqk)#gR( DK<SEA9ӪJy|A[ <zZ1W}JcA;rl@#0 ]J.zf\>xc^~imڻJF6`4E"|Q쏛H\⼌? c>%JE I 1A\b|ޯ4-5Ռ B Wv%sצt+mKl =;/3Leo"OX2183GYb&hv9,^_Adט8.L8P9< bb2[\9'J. jtmؙ7Bx3@6fB^2hD}^2#cxxAj0E: 5n(Q J{@趋a3\ ^Oj7Ϋi ^=R1#F#* ek'RqKG3vO1jE}XxK%+D3r]W4-_GP3jxZJѮKbƈqC7 73)s*7tc,ܬ}/k=R9ށ n^*Kx޺&4R܉jo_1xn %Ѻρxafy#CZSvw&K0GR]0ɻi"\lZRxN0EuC"ƨBtĦʱĐđ- 9I꭪֬ Э֮[l$#8&k%Y S_q4VZ55D/ t:Zxc8\s\GLo҄ P\K JI>%FVW?r!h!RMtOB}C:`FŌg<>oEF<ӽ- 9m+_ {Lz4]&ؽ+ NҖ'xMn0 >q= h-Ms@?ԈLo_Ȣn%!;qJIn⬔')Uw8Ll óN)InD!RwFx,T0C[ ^?wҒ[GtП;8Nvg* ?1M\^@f\c*Vs}[ oQ9lʦPd ] EV)1@ KL-|Z.Q+fQT7aniY¶Aaݓ=ʌsViz-'~735R{#oe?ӕўs'˯'V#gk>:~ӆxN0~C+$q*TT Nkؑ1U%.jg)Z mJ]"B5I**nRK%9Z-T>A#YQVBBEY#t4*t0t 66:=E+\+e5(%yڻlwg*")l_`9?ަOLSQXPcȓ;[C4C qpW;ɵs[o(1ɤ)ڑ;xж = y0~ 0coeΎþxOMk1W{QYbԂPt7uw٢z顽b@xSMo0 Wٱc(ÀYX-yH?JJ{0̀Cnqh7TR^mźaװ;4qX _B;54a7CCc<:?H/ARP+ǣBWK momxhaγbN7.4N.u1sm@Ԍ5r:= ѣ{8; HdTpa,U: KL7p+jAc0bF[e4k#\4'P1:$@(ި(}YzF~6ܨ1Bn3`?'\&#:d7'Y>$zll/ӟ';pb}g "r}sS%2Yr c*Sxd|9h&p ˜wUF$xi?0R?(Ƞ))q*I Q11[)]5 AW`# <pmcPe2xTҍ?e>ɓR_e.xRn0+zîqT!HHibG=C8n#ͼ73.hs9F ѻѵz@$rVublD@/{vqn;qT"B C'ne {3a nrfcrz9m3vphxӰRdF 2 gL, YHdvs+3A+K4a8UKi:u90SY5_ S}6p4SB Arzl;-o`޾XB9~c5?cg")X.kM+j n 2Xŝn7غ O0XG@/eNݵ rdޟCt/a) ya_ |"xN0 y i!4$x7q@TӕI\p~,#hfR-eU6KRFF mShEE)Vvm^at3jGq-3׍䪑uYn6RI)ttM+ʷWx3?AGBv_' Cw'b89C fo(_ta_.;3&4sNe^r G\S ۰ܱ6q/щ=3!l?f2{}&}Ok' #ȸP!xP1n0 ~ -ے]EҼ@Z-&HEjѶkjVˮ֪8jJU$/ITU^TRHێtӪF*aDMUԒᠢBG#t+^FKq  UݕeaWere:yac. >A`)CH٫@ysaqtk1e8. |qMWK)g)GGgfMnn2=拏~d NݓkwK?Wz 0ϰHO7ݷ xMN0>;' ,A !zb?Ď7.Xn4&'"kE'r\htըRZ4Ҝ*6aP;4D\ir9m)17=& /h< ON(K;iDJ@lmG3]r[~Ѱg } 3iLĘ3vi?EnBNqX$_ Dj6Gs<@y"Bùd?":Wtkh7)ۃ4s¿Ŝ&xN$1 E t!$~J@*)%nq746e{( QD1j%&]^X9(zV0[uʚOC_K+Z˥hB<9=dAi.rN [uX*7-486RQuqmږN62`\V?n=—u{kq1d~Ϙ?;[R?{XS<8 Ά%񄖨-=VpK:4aʬ p-[.bp%^ZyP$/8YNCc4ݒϿcn좵'f7'}$Yq]%JхxOKn ]SlQT5TT5'aim0Iۗ|d̤H$URt䪯[n@ATf'h:muFcu#TFj]ՕV$k3uLCpPBG#lt)NO%r-k*ɥD4v,896alux-g7tp/.AmA%Sf=*7C`! wv)m˓)lvW[aa?Շxm!@;ULF , Y/速!dX VOܞᛃ4|s :2Fl\q3 <`sPrUBslQ'm-"s|ԴRGK;OYcio@cWo- QJV1ָ?F܎<^u0wPHD7uPm$xMn b.`')UUUUV]6'`0XŎ"uEx{CD$tȍ Ԓ|;riolH>7mZ =ۡs!n5%!G G5yso嫾xʵS D+~U34 +͙ 2DR*tv~;,Z/RP\m`6Wb81\+()dlJ3!8 OMK`54 YƿISb}(gR iZ<+6`g c ˫;2&s5cG{`L%o::Ŝxj0zaY,C){)}b5uW /P0|TaqqZ"Ǡ&iG#)k&5ڊ@LF WEF,~vs{3OكR#'||[Fܗ2*-8 rXODİ3amd0pɅ8 `sM F`!~?&o@"[~"* \ؾpGB;BjTK=ZxxPN0+HN G$.cݸ$vd;m{7. VٙGCcR Tev;+m˥EȈ>k[LSkT7pCPq\JFQFR;`~r~gvjuaC 1e.gͮ?6qpƘ\КMS5.AӚ֑@&ѧMjmdL 8Œ)y)%|)뮘 u.+kBTJPߊrS==1, OUvS'xAN0E>\Q4q{;ݖ'P ؍!5%w}XS{ ڑF3}({C'%cMJ ˋ( iBI`#2H@K)'|'#)%MSrg8aF/dɆ']_X6xV>SV^y:{^KVrO!B.Qa_q@m\0CyUk)ut;el~: gx=N0{b.ȓq{+QPPQgk8Q={?zua@$1z2zxSBH: nnRKQmMW)veBYzx-ϑxien? 6 H FRNVg]L܅'x-~cv\q#T[!plr@GfߗxPN0ocq #r'O*6Iwҝt%FDC:cںo;)VFIӷ Yw}L[ג=;oΐiJZ4.eLdg8-8pߒ<Ρp)sGO 6RRjNr P{[r=vB\|Tx/|3g ) {8+'`."h'|qh{ C$W%ˆ>:lfxJ1Fy3&3InR] PW%?75Tڷwp6 $g9HOI40\գ4%(2'-0$.#H3j}S1j+sSn]ѵm-J_ߝBHAZ>1bWSm>#gșxN0~FAjV B)򛸋Slo'@g4ߌ&8D"B˜T"JjZqRwhUQdYZ0Xe*:G*ʬT:h)t`l-Ĉc"Ҽ*FQJ{4!?qw|/%zBw<cM"H.-:\|讠 x=[f,_>gY/Of ˧T#q}cv1fߢNaB͗Ngޏsx1n!@ўSp]bY\;b"x _z3b 6i,i#\ 2DXw\ԌV 9f241Qd(1>Zo҈<~|=ǜcVNR7>589)%[\Av.mgy﹎%{V4/l^xN0EDvbQUҰ`UX$vd;@PU%b3{9Ҥ˜(ъനffPQQZӔ! u5pchnG ږ%ץҬeRi!rMp xox[?w)j?+E#M!dKg')HֈFpS=O] F<_GqW$dx!b;ё ~ lաyIsBաμ1:KxMN!F.Фhh~&Ƹwi\P26L8qof[Z}Hj6NVa4PR9"5 ݚ}!8ǘs.DɥQq x}։gQzbMgR3ӧW鈷k\VgTe_awH !X ֢diiy9+, bFe?Mt']S\I J0^p;:qUCZo/o8xA E J1ƽKW.aj-Rcooq罒e "3Dl'{25A-Z<}Hmk ock b!tl/XNRtIy=>iyE aTƃh:VVC).JNyIPFuXº%+>WxMn @= ` ?&Kਹ}T>hhW4M"L95۰"M+tL˼DlT:itASyNc\[/zo;|Y=+}2vu A(u/c?\T : wgzR R7Pnp8 VIe|?g̟x?k0w}:HءB.)g锈&R*IVp7<サGouTd ɑ젝 [=J m 3'F ܵ;9paI5zS+ex̑Jcc D'{%V\qΪz q;5̔_}bK|)naA>޲RɄN9YnޫR f<w-ba\ [F+ ĆmErj\y}ܻxAn = >ˮfJ#u /o",d}:$K.9-YgX q 58Uo_K*}\:Ҷ.d'`^kuһvibA4 w\"8MtKZ9e%Hv5 ʼnTʮ$6Jʴ5躲X[Jא"GL55MGNn[&:Ymvjb-%?Qq0q|t[uۦӰ):zf^]< Ђ~ՁHB>l 2Y7' <ibТ?3Mp9LpDs N3wY\L&Oc(c:\/>b߶i&a"ѿ'*u1Qr)X5߬͏Q;d7ѹM'&r"x=o0 w n]z%e;tТQT,Ė חN2t&#RAKAiƾlt!(c1 v)NM+ݍjX0co;q ZJߩLs.c7 >n|i^Rڸ~~RZK8} ?o׭aes7Pp/xqQ / nFᅄΒWd|E,W)R4KBЌ !ѹ xY2TL춯:G7fcE{eiqF1/+G>}!܋X!>%^o>s\ӵx;N0ާh?BJ.gOݘ!{dtw̱"!1 {u u.4jK]D6>c71En>V E_ Qo5KV,iC4Iy#qeIUFRyÍ&R$Q$(\FQbGhwh2qxq)R -54Lz p<].3%ns3pQb&Ԉl;=;q-_5gQ[2s]*cNyL~ydt_ xKN0D>@BYbO;XCAH`vRȍU1Ihc W6G(NKF,S vz(%ֻ IM}to$VG 躭JCڪ]Cm^CթkQF>zC>uny*NRa\~նQR*UKؔ,Og+U3]k<wh' ڦ/DGBme[F #ħ=AK"%WQH#&qFi~ N6] y8"c &K;#9 >1ЃBd?n32:,N~i{| &cͽ 2 Kq={rC>Sep~Aes\=>fgfauAc>V,G.V]=>0|9ms9.ϜIgh/xN0D{~B Di'`hDI$ۍH3A8{C*ZUK#}Z'ط' K4GƺIg!x2"sOgm K; VI ל.V[w~9i#lSRv 1xfH kJܑ–1 *mEZdFe/vTz0)ؔp~ !xAj0E:1d[qPR tH'"$9{*m!7#v-4VFھQR[ٚ\HvH>!hT]M\Jb)%9B "lϴϷ)WNO 3ԲQ饒-笤˙\upM>n`λpt?dѡ D}x'H|"(#G;ìwg@o5fybHi9Oyb$BDY#P1鎞쪴Wz<2>x=o0ݿLA1:t:usbpd[ܽGB+&hqzIzk1 RtZU=6\cGc巺OHUcVVm1ӼB=8O0+g26!d(:ƾm;-i@lMgVs98<'y[R E[L8WۭxsGyӃ xN0EwFNl'NURD'95mvJuC ]#[^r5tFsӣPV[V$MsvDR&U"4Z;GK-0!&x 6fZj6xUm.)1bbRբiV\qΆ8MJ==%nt۞|%PJ>5.|3L4t1|h>h(0gbly\Pf~ dWѹG $xOO+!|{31hŤIqe`D `[Bn9wHjӴ2\MլCʅ\^3UIt dЌúYY׍]{è%9s:+ pkYc5=4ҞaU&yz4)oENR-h P܄SPAt8G3 SnD@'- >ytq}$IĈ .omrnŴM"Ob!BvOt,7ąICtbThe&#ϵ<zzouu}ePR$bk$j[sܨeZ. }ƩRg?\P;B|S8Քezcx9n0О H.ܥp4) -’hGRr_3ط>nB#+ E? (潶B`i%r) P[L'M\@xFxj1{=ž;|w)HVO2Ҟ}b*aD 1 h3#X; ^aJa * ޢ 1*=NzinS~J oZ甗[w]¹e~Ai9I-lz:'fz׶RT1ݨA(1>(Kea࠱e[j;!)lJ\_t%x "}?e;xRMO@ ϯئI],BhWaOȓqQj2i˿_' e9ű<;"jU "1#id(0Z%*{tdybJ\=؛٣H\=p)q_}Cn4%xOo0sl.a*.Q[)n3,n^ ߾&iP'7iTu"cTM%ʼ%]tVrU#vt(WZ֬Z.t(cQ[6&mSuα{!z4pd6e[m]7py.G#''r.%;9c+D6eS+)a1y0Cg_`ꑾr<<>޹pTx NEV _ٙh'W{E:Wd iTm|=Ck@G gm^?soMxz %m0;{pLuEOEvx 0 P!" qBq#BU%(LԎܟ>Ӳ*0fڙ Hw9ݪ߷DQZ#7ShsRXz^ ]JsN_^#1xAN0E>\3q Ba'{b8UT I%%.1pcѓ?$Ꭽ82YR^bˎ%!Kc!~ W©"i]~˘vk%& SKZ8XkM~%椚|m}Mw˘n;4#K< p&h{(xOo1sf*4i%B==o_/4bI?gD| UUY.d&**d+uӔ.eK'2EK'`5\m|As|FTT%jlBlG]sU0@BV԰vJFSڳbeq&G)n@EPr`XF+:{6FJ-*}k1}ӒVgx{t*o28 L Nw#ն-++]ڄJom;nt"9T+oaQxKn @, UJ]'`ۗ雙Ah0Z֪Y9:ΝXϸÄА]% R;aVIĠ'kb"{LpS`眞P#`: cD{JIK7_ m{ZkpW6nW)>L ړ~UnA\y{\{XT \kUY#Y)w*>A$[=Rվs۳ϫo l\ +TҢG (^-8.BҦh[ UIٞ S3~ zxeA& ,2oc53BfsG#!~d<lj{6®3qLO ڰjt$F;BѪC)?S- ZZLx~R3@zhA;~/YNypu%o6\a;PV2l@W~~/ҺBku_;8wvkeG2GfW"%s4r|.~DxN0~D#'Mb!DUrN\%ve;=mvv&GD[af*um)o{jpm{eDAvKi/`U(^)ň\"|ȓΛ( suv~.sR鰼@m^t  au !%Ha`:ݶVD<р~q.[rMYO֥YJ)&<u:.n42JF,]!%f1\ T*PUU6]U~E^JLEn_To "\d4Wn(&-]JtfK'e*DIlpw%|{h.ׇRJXKk[E\I|iJ }1ki43ZGUQ|f/sz/˼($+y͚d@G&\.l"MU>j^U:Z1pk jk)5C^Eʲ%\dE% l%wJ+3>;>OBR3Ipo<+VUBdl:Z:n [8 mxMxC`lazv657 3W-ۏݗ 8g[= :j DP355Cel(C$l?(g{Mr$>p [E騯HְWZ3OobF 'UظFtio2Ua ݫnl59jGE)!J`sCL˺S3*2Up㻧I%9K䆧_4pۇ{XGd0ey1*^!C RSĬ74%'d'z<֐MsQ;H~JN#x1O0wۘ9q!C/1Jʾ_ *!rҝ|HjQ/Bc:GdktԮ]ChHA({l6΂,z*t"Y 3S .]aa(ݮ=TRZ6FPFJ;Ϝuk|XRs;d62D7Rq>lmzH#2Y) :{~6]VҟXicO p/)́d{? WFPp9j>,9H nM)obrN"!xAO0 ҥM;>I-ЦUnߓ1p؁>=)ATUKYIJZR*m[1O`ҒT.lQ%ihVr tlYDaOw;)N(E)j,`+Y.;ʛ2%\ېVdP a+cmZCI;4P9ZO1"c0b@c"poX 0)vg oȰia?p3H(@i 8}L&N~I"a57y>ypE>v )B ƶnڹ: гxMN0 F9/0U3n ȏ3 j*MGX L8"#4WVJ0)5nprs7^^AjVƔ\/~Ds75Ri[ȱ}'$Zl[Vs(rO%\>UK~ϿI⧄=օ,0 R$'A23<]XwZ󵋡/M%}4C( cpyG;7ޔxN0EDn1PbAź;dP -EX X^=:9ڕF`T k%1Q)ߴH(b;δQ୧Ic~RA9KC( `sn;q<՗Hf7~oa֍-TΜs=3_`=J_!șq<x8^9BxWK{埅'LCxn0|RT,[RM0@ \I,dR 8]Ji1t~;#*Ͳ,JӼ/H\ҢLY/ry |)sLb|UysZ`>kNq`0uuK{tŲg3=('9H! PD¥M;ADB}0k^قPK $YlbAhEuR`ABzG L,Lj`ۊ7t፛slo7_7JLPŶ=*:v?v6zl"l=m*&s`S)萴89f{FvVPCmj\:fQ eut͉kIR8*2vtfYsy7v x_N0 { k/*m'C @.:&SI@7_]atˤhFcW7:+&xAo!zWxe*iOQzC 1 `__QjfZ!mҡjȵZhRPj0i4ɝS$VkJq{3nS;ߗ J1E6 $Ұs9Fp :Zm s8'jC0+u//l!'O}!T@8b{;4[f \8tLT0 {q=! >˟ -_uf#!K!xG^95Qr+r'Z CDb:;{M~cw7ΥxOO0降7/n R w&drBWu!\uMm7dTHmU*rQ CYM9g;Т6X1Za:| >՗kIY%ea׀z.Mhh2m(%u9㿞qŏn;(=!|N`4b֠&Xc`8oqoy|߱ca9u,aɨ,!?Etߧ#xN0DF!BDucv8=v@;y3`hݴ\*c[#Rښ+eŠn |ـ|.B` JٮZiN2R"<;7 |Q<ʩ}V[M ^sβw)!'v3a}p:0W:Hiƶ=W޾% q?ˆޥ#+ 'ڀ,xTf%'_b9高r Rͺʥ&ݗ=Rttqy훷}|Zro:?r銱y2`BOlxN0~gq$BD 8VYǎlз qD8fgfsDh3=^vMZ%kXC i(ZΑL"QsÖJjЂScqגD1szu`OSpV?dP+{(n~X¢n:ڜ1£xxFXx̕!pۼl~s8n@QM0ڔ0174G,oAl1M(b@"xDQ!T0G`TdO"׻?@ xN0D{-ƉMZAqؑ}"3:)Ij(mSMӘsIJ6L炐G޶EdV[cT)2K()]I>emU6Psh:ؠ@d+})U|Z#ʛoD7+?l+܍4ҟ=$i +Oy[g!䶌!ۤߘew yGxQN EY@@1قx): ޺?J&iYh- A[KqUO \]A;mA/͋RY4a2H Qy o#pX<_o)㑩oc( i W.9gg_#H}%Rk)_QP"82#NO)tG{OL8x 9p?xAN0~| QF$b +إRKew aԃf َd sΐU|A3F,3㌖F469 OwxȾg]wO1oYh֕4NF:u%?$hD=@Q"xe3CHŽ*usUnz9@[2I,vJC\ʵ/9fM ?U_}tx[N0EYUUa c$vdO J|#3ҹWPTlU-Ui\GlWo=UF]`]׽cU_}cjPbr)DʛË7QS;_f B jv+Y.r av(՞fГ#2C.@B"鍌vpbe9Y{V̌Lǐ$҆ "f)MPS A}=5(9jقS|`vavF`C7pŔ xAO0Fs%vVRq^M<bڑ8*gyzruTwH]$Z| ^۽V1ϠI32i,o#kZA%!c9GLi5ͻ9L C#2FvJu-Zp:(ŭSDbMqw{zΕOUϒժHĽ{g;1eyHkLB<.َD ,N<2dOL_^x]V!LJ_O?Cr'Ql-K,H9)Wp eJ_Qy2?-6Dڈ p ]vDkyΗWr̴ ð?﷋O xOo |zikUT%zF10^OkooV\{Gl= Soښc`qvmUgLOC m-nt؎qO]&sfx#d8R6?)|X q93Z,$5<>"ÕJC!9j8h[C-Sߞ *e2 (_dfR3X|2?oA('ț='Rĩu뵏6,_*aDT֫ 9og3T>p.>ɬ~PQL0} wJq$x {bHu0OWM6 xMda' mRBgpBV(zTmc겮F.ze@KQ kY(ﻪmJ!Z]3hv~:d ^Sq-& Cߠ]u*Lu5D-/sv rDxaӯV\,RaZdaR{;^e惱4}Wg̍l"xIz-|H &gBY8Sp1tpffHp0r/_64`rarׇ1s7"VͳP@sZu0'6fqltsӴSK_ɻxN0EYP#; Rl(?0ljGQ,`9@R!D^5ZQFEMj^4y-t';9B%RT( Z5G" RI]UMY1\<9I>:b+f!iq` -6o Oɚy̶bf5%m`ϠHL& q3cʄ H] ]7(mvD0WI*c>Y0#L{ݜM;HƁ#><&G֦sv5L>ɾC眸xAR "$3I˲v/a&b-zCwo":B'3N, &9#HꝚԮ h"` N,9JfD);n}=~rʍXi+1ޫ}L-x<,`mһ3f#\z9*mzzN7^ʥ GC|C}[d!xN0DA͑ %U9F&.lDžrDBvG3oW-"%gi.J.)MYG2I"9!]ND,E!EXc&ef!!2*yLeH$IBv [gO^8?hs sn;HҀNE,(q~D7vmW(fd!_A/L{/^O֑^R+`}d&L#-]7ߵnnNW39x6 ɬhEU5H[j)YО린=$ TLz+eu&&rlxN0 y ߸*M۴C0 #<K&g;.I{nsrMG!Yڮ%cPp搡^M]cNw0RKv[]7&6*\gxO9K1͗yc\>wP֖eU6Zݽ0zy89Iz9)58qi  tc[z*0 b*r8Mb'0Ŷ%e#/ \Ŀ|9xV9 Â3c -1KYbH ʅR2lbo﹨o ֢xQN V<1f&+ޣtЉޚ777fIhL40= kSP.u<EG8kT@Pek5O?}},qӶ>IΠ@Zz /"/.-rR|,iru agxMN! th?˜C16thz2s{wD$c1!r0B'";0j6T6)途N,|6d+C)Γ ~+c"~*Jc.ac[TV+ >Evk!~%^ZXﴵgtď- ^{4p&ifxN0~qj+B/ĩl'o;ǝ};)0ܓRUTdc,뒘jeT!-.'`Q7tFUjKmnU5+?ʒ&sxbXX<0;u+UY.%D|x8N! B=\]!0͆ .-n3Gp>&F9oYaͷ1~ ܬ-p,8yjFNoGx@x7Rw`0ؘ}.{D3&kwߥPx]N YmBc]?smiCi L|dfV!s5W8+ "[%9vlK#7"*+.lP>IǙ۸Tx7:।VDewGQOp) .眝LJ+ݩ\axвoO%;M Vq)ymD{mgc읮e~}q5xRKo0 W>'CQ4m.Cw6hŒ!'eAaЋ P|YY,_juRy?V*NQK]Wv3?uʳ7$ђ;z$su{O  0xN1 y mP+P;nR%ުpnؒ6]CLm;CXih˭vg쀄H]0qiC b=Xt};ݸzͶn3hp1&xD8b 7VK|/дvúZ8^K+<JH ||Xn5TUE>xz} 2 X&(~d'c5Vb3dLOw \9OF[AAtp_- rs,i$.ѹy'JHxOo0 Ofv;P -bP Caة%fK$;>('# |VE*RLQT>pLye%D'jeZ*U DfiU*|PrU/VBBak ]p qA=dytBٶW_4Nj b}ِ`RNaI1W% [R "-ydP[hPKC"`]s/8g55X?hkPz5 VR>&UACZoLEnU-P-5d&z5C4YipbɦJF[O8a;^iE;4p>v|aZ9[!w;'!i'tTx_sLsb=>s[k^xN0Dc(G+@hCbG'ehF:Gaj9e0JM\$r88aɨ Rl'*RB6 Rj^3=.&x~`Sއ\қlp5T55c UK ϋo3|:A%5^ 8M9Bœ<._ȥ8@N-SݵX!0lSF f'x {d%!Gh\aOox,xMK1vɇnHSs%KOehÔxR0{=Ž=?dPR@A}ω@Y c(Aη%31:6vpdBmk{+Nc5Jl;j;*I7u[SӣS9 /kyI!S!p=u5 *RξD q42ӥ>G.wH˟s+7"Uʭ7ymvy˓xn E{)edjӥHD" ]T͹d-G#A=^NPƸ%B/BVɆ`w?NXoxGkd/H| \1g_ Sriu\/21r)3z]]6ח7܎is~ Q+x`P^Q4nێfn"&.K?9-](v6UgFr xN0D{{Q?b*l |{9'nF#+"A(Atr0/hcZkPV3N$hH43F;ޞOHoNàh!G%G{=ZgeRʺG& tǤahC:͌0=kH9?Fh%K ^1L Kva*\'L (:FPBc]\Θ 2oTW3SNԤ=hvf(87U怦_p 99t'Bٛ-`nLnxN0{?J4 q89T4 ` scDGCjgVLD<ȶ|۶Qz4j0z#Ұw3nRDQKjqԚH\3,"0 R~٢oB?B$ rX@*3%Sʇ2@{TV] ,Se䦾d3\ .]Hp!{%9j{GO&+{Ką`Ͼw֗)76t˾;ߛxIj1D:ſ@7ZS0!!Ƅ 喝Z6ӹA z7DzMeA24Zv0ͣ5IEήa h/9 sE@)Fq>wsm %6vk_\n`_P{`\3&W*(%]r/ y7\OW"aB-Cϵ۶sykl!P05nxAN0E>\ 8q*vH=NrRnO&bcXbӬNyau& 69qJL`P %CAB} <( Nw?r9_K>fPГڸ{ r/zW99@-PRrY`O-~N˨{^ġ4ߓ hJ'xMn0 :wY῱'EQ4dQ KJj,ɐhOrN,H>@mn}P#*u%}QU[b@AR_S[X5e]e_{ VQ+3>3 8P|a}_gFLy-Oyh`Wy.j 3}դo"DclˆmB6%%<@w!/Ɖ.ONtPY wv XE övxh)t"V\`0(G0Ȥx)@_Ru" ׃#%Vx~H`Xy|`'Zih|p?ҫIKH'Yt#h$]&ɜ|ֻxMN0O $g  $vU=TH,X{-Lɒ+ `O%gg߸t9R\48^ )koPbczusFۓTf-@nwx{.GI5S)񖏅PS_򃬹\V2 cb xKN0D>E/A($F1W?=&r< Zy7_}`x1N0ާp E"g!h8`Md(ܞ *DCӫED3`4 IϞM p"ީH޻8S?t8D`bEk=/E%m)s!}Q[&?atCƀ1sU ?(\Fpx9:!EZhZEkkzc?W}eKxKN0нOHd'!`'hmCb' '#V *U"Ўs0!x$hFib7eUf@ѡFoxQ' ݨR.^/9T k9LOn}Y@ Z|]Rk1܌ӕ`G Na<z߷ ҞʶBL0,Kmm=c#SJzy 2ixN0 {7*M&A1'`''qlkR4ޞVN_$D ,zhIHT6j AwF28p\Hpn es"5Eok  ùxN70b xu<ߛ[$7Њn+† ْV` B}O/21,j-ka2W(>!ޱaOx}|ɗ)lJC7*>y7.xRn0+EcAWI/ -܃HK_ߕ^p@fgjM1k[Ҧʫ}:9a ǠjrݴevuSuRd]YFS}t^/w~;>yQYu2Ώe_ ՀݫRTCgvl'wG0ctT{aARԅ);⣌U``)ӏo_贄f+N mǛϨM7@!&ɓ8n1xFp^ H⠈g":ײ2Yp;gJ(2[!U7EɌ8F!qd".8$e!l)< ѯ4v ?%/19f)sKެ-WYwU!ҿkn"rG0eNmHoen[u/*bxMn0>\ bTUWݔx` Ie ot{*eˉrpB=i㇐0s*sYr f2fX! i T84y|;loW [ ޘ ZuJkR +ꎮ.VWy\,k^ ǡ4_r9np']`xe;n0 ]le.":uiN@It:Y6WirHL\zDn8Fأ"4^ގFni-=ܠ&5jg};h "E;{S >'x?]úc[ k#:%;hi ?װWtM? 4BWAULq!a+n&@s4Mzs-c/zg,?+7boxen D|*XMJ6zX 6 8T=Tjfr2zVS9-Ki;96vBJnE%2Xƹlyuhv螩 (2l{$jcL^BTo`??x[u &Wϕg`T RN))lA~>a!ZPFB(y }\\ࢲM#]U6.m1sYb:) #W K&M!G7o[\c~5 \~y$M7 xN0EFv1ذ"Dg\9NiSذwtd"PBJYe:m f3Zf m7)P!J)9J3"5wtڐwee2<ˈ rʟy|!Riݷ.W;+.Âu5Raq6*͘ ٤``ڥ9 X]JJ5nH m$\q\Ncn9ף2?H;픑hQy̙@~_n?iU}!4 kZv&IV0R)qT j yʼ|J11 ^N{txϽN0Oq7Dvl'qt,CS?8v =nI\2rl;%:)j敒\dc"y cs(14gmX[=)A%ns/!zX`Nt *PJt 0mt%U@#s.:Cə /)xP2A8 aw8=m&d爮OpsxeKN1нO%Y0/m[B(87h0A'bUZj/DQ.dk o6x͡b xZ}S^~ޗcXL0ZȯFG)1!tr}R~> 5hΗ>q+)@\kաnaGxe̽n0=WqncGP;ХT&c!q` ߠNUL 'mh"!; !KmltGշ8P6@[F]`GѲ:(%wLm )5G>\2:PqXA#5 -< )DC*!>iV)g^[S>rO~<Tl~=V]TxeMn OYJ̟[WD9~OVEw#BbJ83UJS0RL=C.ZК>&D n2s _N+>>ފ1:Ҷ+3NkLTzz[ 7n?B6`0sPk]/,tPPaãRxe[j0wb6P#.(AfFXm,Y1Y~Tx?_o"ʈq17%ǑYJ cMj:gޑ~S!vNax'~kn^oRqBrI{J ǻk! `a8R/c۠T@+MUVPxeKN0нO OB.`Hxp{|,3S`f텴qV)봢'eλ5d)#L0ќp %)h-dbet/)r -RxeKN0нO%,iӖb k0LxFs|V- -SxeϱN0O;ۉ !P.} .S9NobOZR= i` dR@$a$u*h0$ =!'o#'G>1D;E[Z>9G*M_/lVu9/F38>0jsnM!FG֎]y]sin@g~Lixuj0DRYrd{m> 4N(f OD@UgJ6j])ňEBr~QIYJi<#J &c8&O7}=8_s$.C76 [ԪRB!bqL[t:;7Z ab&N^aH "diqyD r_2s=d\kGrE/7\|+~x]N! wNfB!|cFOP;aul|1Ň&ɯ퍈ke5#L(}"pۅ]QCcC15ARt A&p +*a$~xe?k>K]8Hmj> ){?ȏθ|zSK!!F)9h^kg'~Q /63 ũ4?Ͼj.xmM0sk ?.Kٶ@K[Yc[,i'#v/{}ΫeʢlMѨ ZվZ͡Sј]D@GP7T/}ߵEs۪oN(ñ>J*)+F{0Do-wtsU53nflj7^k0kI#`ttbI@ڲ-jЛ∑Bl!uCeu :ו|}K- n{?q8e!1#1(-UەM>hYu9S˟spƳ3 g/ʛUI١z( vOg6 gN0 j(kDž37<=.%DaBOWvǫtDVLJk_92fo9__wIs Z01gKGv48?ɪ(~ v<; FxN ;OQc(1z]x1OdhE wWRz4]B7"!)Kl A I1i4 hݠMR'ej`pc];򕿖BDt^˔ek~nCZ;Ι ? |RS˄j!h< #,/kJyĔK\KG>MMþGLqxx=N0ާ $N/r$nkR9ŵ#=i Ҡ Œ"H[sq9ۿkj .~r-0#tm&T6glB0#ԲBPV G{:e ]χ`_Sm;x=N0ާp7B Zhc8k+ZnO  SO702R IZKqFI4*+ "Ơ&h|p>06  6@wlR9c=x#}]s1Gvh> 6O( =ׅo'NgR>o$LtaĘx1N0ާ%c;vB Z*gYCbr{hhiX9mPKǓwMR&aG*eT g7";fۡTxtLTÚ_2>vj0笄-#8r-^kGԻ ގ ~. `&XShpzJ%w)"kZ2SWb_kh]x1O0w;qT!:2tl]9NU>w9A#4X) C][ӷZ`zQ5쌉BAնZ)w$uQSV\H+ĦՆǘ `Zݒnaa@z.Ma#5osϙ~A>zBs:);)=0Y3Y+ f`F 'J&*%/{C [D z?{x#&ؽ_u~xeKN0W +NPU&,:5Ml8U#<H |-T+ҁhCX}ǮhّW(*5^Ѷ aBVsӅ^ ZϹ+}HGz}bZ7vMXYt3|BjJІ+αVnW0R{_ 1ns.7zH㲬0B79)'<}xX8N:xcPe-xOk1)Cm %Ѓ!ԆB.f$jwEηdcz3~艀zKɻjۡjU ctJֵbPłlTCJJkV]U gM {xKqt4Z؆0pV=xR#R+TgH<VyT>bBGKivzYV ws28 Ny$ с0d@ѪEՙί{e"8O7OiFh%m %F.4BPAiTEkziCJ]Vy<ARم[3z[{s6NxTx5N0D|V4(INGCD_׉/8z -V3HRgCZK=>p8H9ka\Ն ֺw)!Т*.u+M9y )_p'8N ^=+W,>gh ǞͬG'Aȶ-m j֖2. n/D1 jrɪ2\h tM~'!"lRSUo~\Z>8\Ia\#5+S 6sxAN =[-5 |h /хw3gj!t29"Ayb(WAN+`Ta4dQnrT~n@~~Dp\ / rSL6ڹuy~)#\CÏrvs ߆}ؼz#G`u^ Ra1ؕ wpR#]>Z0֘–9isk|KBc?tVxej0z ,KB\'XDi,Eץ=zo)Z9V:G;Ɂ4OUZ&Wht&nǤl|ZP ,T}sӧHo_rYVv/guQ!+dK{a _JYi/5zmy[j!XbjJ|@?AFŹq{ò#_2^%xAN0E9F1P @BzlORkW6'- !ذ'&DIUU+ 焌 [.S}[/8RȀRK!{.2پGÕ X%Ӵ#<;m#Zuƻ0C\:+M@̈́ ]WUН˙H>ڣyvw ŝ;Ax0%b#d.kxy|s{!<bH`0&0>%л@eQ7i=!L]ײI$ך?@z!^[fJ^?V|jfs1xRMo0 W=mb#q-.ذS tE?ivmB"?#B%Ub.IYԲ\bgEڈZ f2:*"[4S*L3,ReH:Fc>8cf=xnCocOf$ϫj"Y&INgGamk/j?}oj/)ֲ0eI2C ѶE8R-H4nF0w``æCo8qcYtne_XS>4#93s =10kD# -ڳqarW~բ3LY+zmw{޽ CyW3BM=p=P;Ʊ^juT~VXr:a [^\o #?qWuE?xRX/\,.-mS|H( - $xۊ0 z1Iɡ,EKZ() >ȉlg3u,~INhix/ڮt[) \!t P؉\V-\eA]am]a^q|Mn=«1Do-T )a#1?MGiWvU&L(S1-67>)Xa ^X#)KR\}"" 5s(\6a ލj;&b֊<0\¼]|>_ׯ_.cMs3Or"@"_L5:;Lܩ6S/Wx[#(~ѡ:yO uDxKN0D>E/aȟ + v{F3NOF@bæT]~RBF#.xqcQ*SBwF =RIb=Rzmωjqn]_@Ȯ=r+ٖαVfd 7A 7t9ҡFrl^X'HkTT[tM|{<$M/|xN0yq;v*ԞWxubU씖'!piFO;[fDT=#3*:/SFSitg3T0!*ѝ5E˵+X2k8>Y;m~7SR36M@.B!jMP |2̨OHE#Xʀp &,kP-cśAczC}8a2_Zz}DIo.f]ޙߍRxJ1}"K!?s#"|}䦍dJ&-[Ap9q.'A0I R i&bTuP섍j F EJ'5P@ddx7(a"r,|/X7#ceW) KC=)b x1O+1{(h>ߑ;4H4b}N پ{LoW3S3t]ICqRZ%Jw Qh;L "cOƲUq;E~`'s/GšSlj494Sހj;;=v RTup'|s{ xkiK8xRn0+>E-h (=NCE-)m}vlzN-&8DU!xy5+,gbyq1CVX dIGIO&y)bV7uIdX-k ~ZVf[pBRuA`Rn/UVVU/`UYکQ{71p]50̗e̖91Đ<RAm[F  M^ 7uxeAj0~~ FG.! Ph$k In wvv`SD"7¢BdJrB+WKm).2O Tau(C&Ey%lˊVdrHE+I!Fc=jPփӠmݤv0YV$-1 5>ޟ09Xf_?}A3xn DX1TQ{m* fIDN/^fvJ1 GYoU+/E0mע@ƪJ8XQ!ҝ2.nym?Tj)&Y_3|GL9zۓEy1whڎq>b B#_1 .=ƽj6ߝ]&0a a}#83 SK{<%M!_xpxMk1(fJ) eL4H6Z|WP0yxxS$N5BغQcT.HՖRH>IB.QԊkjHsD.xΫ4 wi"ã7 C=̩Mr!˦0l\GᷡjZy5Kx[~@ Y8;2Ln%wS8`c=0`hv=\S$p>`v@_e-j|2 Fy"xQN0 +,Nmע BH@&h)IC_=3`Be$PV(u VK!]jue#6}i:ة\veE$ۺBBMq<n7 :!EndseU DlEUYBG#{x;<)~ ٻCnWi+&~KiP xyax E%\_L<= `Yrp>R>/;U@?-`,Pr(S8 tZ:ѓ ;,3(x}x|`?:(iL^L$eϧ57?&UBt:Z˳l,z)71xMN09\QA*݀DA3i ]NRn}=&O Ps#V *%=FіUG5a@$: -b'e%}IjV !Nx$؆=N)zM]٤9&@(oHX5i.gC<;)F{e~uN!kK+ ap F 9B.gb80] ` \+\-+S 8bAoW%t3 tLg8 +<5pÌʗxKN0D>E_ o!;gxF3g"X aY%ӫVU2yàL11ZoTer|,T4HVJ @A#*)#CqZ O%UJ [ҟ >ǥewNj)ŭ]rk͈3q&8:?̷A) emp/r]xz!{ԭygaxKN1EѹW tۮ!+ i;r{@0@bHzO Pi'6l&'SRxeOh5"+N+S)8R"k)|LԿ>_*mNmFeu+cۈc i NY뱝f!K<5)^oM|n#]"xn1 Ez 4A/$@х4K354Éw])0"3/Qq$E+ݒZ~f ,I4H҄z(%f(ne9=OGk܎CY͇r'FkWB QuoRmv©-N/͸ tmׯ ABgka~Ɖ36-qL>iu.C8x&b,\LAMx<8`pYx|?ٰ4b }a-#Uuovi^ǯ"5.3/ xn E$CJ7K܍8~@ߘ+ι$"2ZzmeJ4(9 MW(Шw*Q(`rTҴhw7B^DC`b_kppsRwQnpv\tBr;qΪ:R(zw. M[J`lN^ATVtg<6TQ[wuN=3A"z(4<5}`ѱ"%m} U1Ï#DKzy}` ZyOm*(/2l%Sn#վ` >k׆좵;\O _xнN0=OqGhBoĮ4oOJ;Tbah)48l}ȶ%{ụ{H-O --O9p)3se~ȭbӬ̼'WǕx]AN0E9,AcǮ*11MqI(bfBSD8 r%)VtȂbzÑ#JaưN RDﺠ;OuC!<|wyRi 2k/|AO+hGt/mStWBH) lX+cie o=k=|#on!,u q"@ &Ҟ?kx]N0 } AhSI&pg )IO璉#1H4^ijP+ΕD`:1S,9ֶ"Lh8YTܨb2 1`<@˻^j&;VpP|gx.#e|4ڽIu0u.{ÊJh^?)ąUN+R5Ҝٽ 5^1l=]_ai?NDq=m.09 ^=k5Jop;~ $2J)bIW2ͱ4<LT7-*K^* Ah9:mtxAN!=`S47  MO;Ƙqޘ!ڙ00)hIO Gj\dvr#C̠cnX kOOFھ!< 1e uZg(%.{?ȷ}=pz*K_Z6[+2B9a; A:((eXhEb_irkkܦe>h<=kuc1jo\+A8azÏDLzۖI]xK>figOBb=x=N0ާp E!^N`όuVY {ŧzc^%gmY4̈I!.$B%*6V)!!,ui@.dX?&K>C}5< 1mĺIi&g@\-o#_c=z^#Q6~scr*5^ PSgObxMJ1}N ;"\AO2$ ApjQ5:O$H8!qH={Nup"1+j%x% +e*iZ|WcHa_2+92c+\*0|ZvmK F8v-UkՏv1nmu][e%+ũ4ebx1N0ާp E";6B-`C` ǻlnϮ@?2K ,>;0zlL'V.M:KfYa!1)..xhKO6PEby} ~sNjnTvFv tZ?ȷr-80~#ZeuUzZ0uK]nU|icx1N0ާp EqbV(gz8uV,V %0&F-0ɓrori<MV&M  8M R?XޟW~8nps;4Avι5|kX߂S#=YV~_sez&.ֺ!~3 _ SԅhZ/xRK0W {.M?S Ph1qƖ\INߑ{x%6!Y%0ٔb+)Yee^i4%DU$UAMI[e& Q˲ڶI#*w'<+ oLQ^I֢$Ǐn6YQE^$M1à' :óΆ^W|c%$ޖ)Ig)Hz /0[q;/Ё6 &49>+ݨVZަ$O1Gt&;chGλ%<\K,G 㣀t'p6[[ѳؕJcY^tLVyb |h0b>X=Hjq|1i.BfVpE&7C\ZF}V|ӠfF)93;ъgn\MǏLFFBLϜxڴZE,%xQ=o0+nİʊ Hv(2G(Rnڮ%@w,6.]ru?Қu8T3NW=hݺV[SMƛmckW.spz/p(˪˲=}^4U€A:@R_MYz$>#^AĴt~F*ri\wQ |͖(Gp 8'zK]fSR%kA?S q"|܁&K$;De-@=s)dFX["z d;&{/'oUٜ:gڝ̐5xbpa?Ӆ)v˿xj0D%YB!9T鹬UbXFPگcf)̠i u8fMEUNj{0 b2LCƘwlZmkF#)%X.i@U'ܤb^WYu,нp8);` h*T$#°9x滹>XT8iwXxAj0E:ȶ,C)B uq,e#Y{_W:APv cwqmsH532HDmMغk4TSa/Ӓa_x7@c*c,cyȿΪgooW{}{|`s;.{ eM2 1AH ۾K. XNw x10 @=$.z1BM4 pz8z HndVE)&y,BEȧҬv 9! '˪ѼiAsq@<5fx 0` H9uR֡qH{>!xn y zXU"U{&t~*mY>X??$"0lZ;fi\L08#5& d.RHeLUazT M/8?W`kF⺺R_͛%3A4\19=`b%=\ŠpqawW,} '=-Tj,mi}WbO~H3 $<&[ROu dT/ xK @b8:.D4A Y}xJl > 1k1f]X*]R;yOl H4c-T +&cJZs~~A pl甿b) 2ƵhF9<x;0{b{'#!@#D4L5hz0|ȑi<5JZ󒆭|Ɛf ^8Z(d64]v#,\d)\zǟký}S:-Wz |m Cx;n0D{b[.=VEؖ G){aF9;.hRDAJ."lne JRiFES9:sbR Dzur^>&g)c7{Ĕzmcȋj?0O0e"O}[O*R1hjNLx1N0E{bzqđVT[BkmFgU_z_+@\-6!!LciI.&-;v2LnjgDxĽ_R~`AJbyى0=I~/wo).)Rm?G#j+h+5J AFWTZKz|~{1eQ xA 0yłG/IdA<_I6Hm))00}Sdă-JeMl 18Ri.+U6}u XK f6-ZJeuT d1yeoQЦV:$ xK 19EK7v^$ng!d@<#xߪUotf%Tql2چ Jj- H'.:#R Reӳ:u.7~pcQ&QS, &;A:ax;nC!E{V1}$.%a!5ssSܩE5sS!k%`pO,"!80 q~?GPbS 1RZFVgTYb@4<>6i:g(9N'A&>&Jc^ۻ:Z7hߔm[Z  ;ϹM:[ xA 0E9EnI2/NfH[q x-&b\\"2jH y&{L&,yr2CJ e ~sTizO v]^~q|gۨ8ŚxAj0 ~XvlP ,)MhK@?йe07j56K˜Q%H Sqr' = 5.ٗ(R/Y2SeBi?]t)T+ }73G) ,y֟4o7VF+<7[V~VGg xA! @= 0BbK %\x{'߼5UMRz kV#E6O=$ʤ}$H>PT:L-{DŽgTp"pg}kOZa4PNk]:;8 xA 0 _{/V$E%bu} @ ۛ*$&U7Sy%'6g$V,e\i0ɻS6̴3ŏG]y 2}M!<ʖ x10 K8I-!8ZaTr誀,U&]}lRD>Fμs͵v r5HBQH'ﱴO+%ˆ-#m1Ԭu.Z -T~Ev>x; D{N}0`@R"˲(u>D@i;{do ~vl/kzaU@9@HN)GJ6.YZ!Vqn+\}cRHE(ڞYPBǂ ü.PP;V+,g0RK\G\xKj0D:E3' Y 9 "Hw E)1`6!90&u?k͕rQr3۾z'BDwvA Pj/|OY[)%GmPwR'dJ@ ay_%={ 12/@qLhrW ԚRzxKn0 C>XqP.%#Fxqb.0ܐr1 g,MHP/y<1EЇY'h)* K.sD;|SHn&$Ln^e S!VѶ/ꀕwʝ=IVxj0D{i${%ia]qRׄ룐430affvQC1Xh´qf&E)&}ѰDd }vе6}U.akH~Tp ښ$}VVp9ޟ.k;Ms3)u/=?hRŘ x10 F=;uHq EQ q-7XeJc͉ɸB%3h V=JIj1(k甆2j[U+~[E1QS !s-˭wR+*x|r: x;!@{NAo3|fxa"5 o&^׼W5Um+w *\&PhgL;OݗMPse=JpF-P:%x{ݏiןoֹ0Sh/pbض5i5b7 x;1 >HOcc'!8@hU n`̚fQ J<ieԪһ9e%2" wCV$w'r\nA^xfFV(1''t߶Z^ǐe#|6)xj0~"YeC)@z2+*1%ׇ髶/й | #*U8OlihصZ_[[8jG+L< 4+žRkt1ǚjHKG[&h:SY[Vp1^#Z ۲$E raX/q^/GmQ`u٘$W]KYx;nAD9E$ݕ "CͧVj7{-TRRyLVWdR(*bG1H Qi.N~pΡ!dO"|+%c_oJ.#33fh4@B!p>.e;qC|ZG^~9Rx D|޽,@Ɠ?KۘĿ8$ӪdJ8Gfgv`AU.F͓3wi&s$hmcTtT KϯuƎ=KmkkGUUK~rN,g α;?!->ú,FuJ#xʱj0]Oq{NuP "͞=y$!jN‘ y !dK4 4tؽ4x~h7 #p˺>U,x+G۾;FJ@ x10 @='Mj qv*Mn/oA)) J e^8͕)Timm9QX%R d)(`pr[x7Wg@poni} cuj j~l[f?|?ӑxA 0E9,7IL2 .x6,RSt7y<~-"@Z:",NA;m pgϺK]DlAG{&d[WR !$OMyZUqaݖ% 8${nFNVOB x9 1 {}ɧ!mb> @f5U˥& ԃB^, ՛]~ Tj,D }Z.FӾtȉ\{ SǶ?RsM6p5Ox;0Db{?B qo&F]p{,ӌFj 4VSR H >{KD+^@yhdyL;@@Ri -](V8{ Lsy>'"A FsǼWXBmw9EDxNj1ۥzN &N.kOA^#?itf0h0j3ZldKD]YSUGRBSrmJޏṊףp0wóޠr^URp-O dfx;^?nr~AiV~?L x Ewhm<5b6w99ɭYa6h0x&jMD0'^XkсS<PH!k(Dۄ-xEa,da]*Yq)ų#J,&'1 {e3 KՙI:tnsЎz|Z_%4[k c Ǯm/16xNr  (v/ʬ.b?L2dsjΙV[iw n\*qx4 쭐JB^pFhxs.t?GϷF)Q!.4.k6n4aiukbDk.}Cؗm?(&r9UT:f$r3ܝFnK)%ܱxI[Ej fxMj0 9ICU"ɍyp\} @3V9lVXYuEaqLK\&ߓ!i >i%مOm𸕥yΙ5ofDzwt"C(aC#Q+rHtP-:BS>aZ/}Kї0 }|!"/s\.xAn Dﻁ|cZ* ܾt67z4 \ر`bD-N':+; NL쵄!ᑠ]WaKm_UݿdVȞk)kTAh{qB]ӐC߾B_| ol0$IE!qQՒ+4:$Q3y:eu\if5;EY@ZK2&DSQ߳n~mPjco_~l= xA Eb3QG('4`Mo<Nmn+؁η~:% xA @=Iwa4HMz{M6tU&ub"i&IK\DUJIfO]u6xr;ET8vYKh1lY;\CbkCX*=_m.:;̒xKC!a!W j#?~sMAQ3Ct([sJy--Hs^*4RωTuHE-@j:CS?hY`.p>YB<x;N0DbJN#!:z`7MbFV%64Sљ1$lf{+$f2Y(sІDBϋTrtrd)10YqN3^}?i--DKqZh6+о#PjH -xPPb8 n\N(!:Fmpf9k;&iʸ6<+Bs9G/W` xK0 9lb#!&Nmf37*gʞ89 Ql))^yI瀔8%VBOEcj4,1iE;~b)Ş32]Vnm { [뱙/oQ=x90@ާk %3^HD#.=H\߼3x}Bm2!ۉX;yX[bNb_APU!5ҒAS 1*Aϵ]Snpy9pD۶XE :l5X~RCٖx1 EwNὋ!%RջcҨI }#}_kURHyg Ґ{T牕Gpk7rm\L~ _&Q%"$poR)I+<~k'p #eۖȋYOh~6J+W}Y`㷂z2>_RU澚/@K֑xN0 >74Išm\:B pl|>0"%;U:&8G#iQni8#csRKpq!qZ{dqM.pSA Jkq5d:Mv`D  zܹ흠&P>4.GL ԇ+2?wZ׭pC[xAj!ᄁ訫B@CmbYmlRxL,l2\Q\RR8PEMFe)S b.i_@`TA;xDQX}L}$cm2a^ ak>YwWQ2ֹγp@\eSkx=1 >pOc$Ѣm=.΂!)=kޯxZ5Y%c 2HQPSX}׫(njl+Fr&%(%Y( J{QKeϭԥ\mRET?E9l7>vsI x= @Sx ?AzM5 o^oכx.jqq$l ٨359:bMbS g e*31 4Rޕsp}_{?VEK:rAp^ylAh%?Exj0 D zj "KJ6lSؿ,e`xot3pIDM|A(*2\2o%OALr”'JDqR > ǸGS_C)û?պa@Th% ?W.h0[[u_+ Spm>?=O՚x1n {^]kX`He16.I@f)FG*(;O.emSN\*D\B#UX,c*.DKƄϨ2w@Dpo:?RSϮ+0y :@{1k}l[?7Fř x; 1@b&d@,xlfXx{y㍮ !rP)J""8fo:66mOZ\qbSux|6#ZGhwLݖeCHMQhW/|9Ś x90{b{ٵ-! x58HH|iizceDecEaBv"xAB)O"‘!RQRQ*N@|N9s}jPEׅ߼@9_6+Axn0 Dw}.Q"Pt%@t(R(u-7{כ*ؠ&>!{ IQg7-2"gdB,En62&ٙO6xwp/vu]S],tP~KO |OZ@4m8b~,JxMI aD m }<`RR-<`DSF]bU@䉤%YAiPc";$k4k %h3P5E:y^^h㗟TV*--sjs`z94e-?h=_K,Oo{K/z9HO&X]Vx[ 0E$!{L&66S xLIkƦ'i'o5iR"%x6a_T(rsH16xl5q(uV* >AuKG*2m2%#:kw?3G'CyA] JG x;n0{b;iH9Xr(@n_1L`:C:gRIKQѹ B'6&$5R$[1^ɠuNXIcRCkH1:ko/| Rmtan+ ޷v^CMIxI0~sxX/vdE>(| }.;$?Fq8XSfThƢ]qڹ%wT0R%Ma8KBOP $Eyj^G~pgDj:3hu9 'n6KDw\JY Z_2G6xA Eb݀B.3(F1ۗ߼{mcPj']0689eDVH*n\x9: ( )[2mJ'(卑v߹5#HOX<2C:Jl#) 1C޻_I x=0 @= UK옂 d[[嵪 "SEC|1hx'/LUIh=ώ-'Hcv8 3f;`RoKz?@4䬃~3R}mMX,xϳ{}K[6?e x10 ;KI#!Ď~ ImPTnm ڤegB;E$/>YjM6^sbl+ I R c.J6 n:4ZDei9M0S?U7'<x;n1 ^`F?8Hl_]k!k޿ xMoP4SrUAVCbٙ sZ&&*1yjwJJ[Ĭ\GZ2YDb4[֐o !:/ JۆL:^Xy;_S*`wF֯& T(w;Du6I x1 @ѝSx1"UDMBD`[_{BјXOb{.DȤNnrtњS1X2bYrJCG_j׻fip9 nJuU\+\|ш9>ⶮ1TZꭷƾ^yN5t<˜xͱN0_5B v.O){5TGhe‰"GB%FS0sᦥg(dv %r>S!M<5Smp |k#b-?ET`E4}ח7n|Vx/keyZk|VJRfX }d~P x; 1@bzM@,dYB,.x_otpH6G,:2LELZ{0Xm&}'&L}A~ƣux#CzNo(jCH2 hc]68z9M=xN0{?J4c QP=kn}r{{, 0L1ވ`=L/dV6IRa#LRdTs(5\ȢrL:8oϽFjWP*8'XZzco " 9Q?:p> s X;năY eVtx10{zə(@}A䘂NmUBՉ C]1=޼ji9V!)QB= 6Lݗ "Z#DkyZ?ETt=ÔE \ҝ˨+v@&2S?)G xA0E=t  1n{\3)5K^KVj )jj*vXihZj['> qF;t !sT"%&ʴf}֨?ZvuYRsI#p0K߃}8\6_f?v x; {N}Xv"['¸(4iU"29.cDXfIxOzSs3u4%K.Fg9`3NƭpIki7},Sk򇪦5 }Q諗iʕz= ]}HB x;0ާ؞K8.""Lڬ C؇R71z"[%v`(y@䑉7BʁLF4퍲 Wa'u겈 4\z9R7+A֜ x91 =M/=.AP{ff -8\l)LB-UgG<匮yCO*$6sC삵RHWS_c]7@,<+p'c"*y^3,Znj>< x=0 @=b築7Nm 4 $.[卮 >j-D>)Av%1[,>@^sW@%)R`B4!8#QsJX[Xbf%ي0MQ|QJiU;|@3 7͕mGw:6 粭DZ}^=ӝ xK 09En wy`6%Moo 8 3Ր9*T)TJD 9GfîLxOSM"'Y5sLcx10 @=bI$]؁ TAALyUAk4QrAٗ*C@Q&u5QƬ9Z{ > 124ɥ[D;\~Q<={t-lPDT 0nU -ɼ`͚E x10 @=bvH8#*t q?{%#)dMuKgN@!,f#'ZZg*jr>󽛏xyuDb=?p&-|-6xj1D{}q!t: B w 6!U#VD,ݺCL1;cr(4dF'4\:I\CBTrf%ccJ"uY[Ϗ|zIn.La.S*p?>;XJEVu3CCHi8#;V x1 w^_ D }#喻9̼CƔbeAKei Vna H9$$š;.DZ[m5, Wu}i؛Nk F5LxA @=0011q0Mbx{M67f L>Ik/> ;#YHMa:Dh2Y(Iru NIOE!7~{?VJ< /PGh+u^&O>tZD x1!FS$ƻ YwCk|׼9|̈́5Ş"s*!( ;dkznʄ9uZI8u5Awr> y@# }sm߶ǜCe=5 xA EbnxAm.M-љuA[V:g=zi\$yˈ|ڜ,B,+1%1ӈ;~R3R#\9۲1TD"&XS]h0ecJGI|A% x;0{=?kKwB!=A\W4lܢqĕrO-%ɞqMx=HY,ߏVD굖/ŒN.( :VŰ)LY9'H;)OK7xM !E͛I3۸/E8hߦ`wL]1, m]>'N8 xM 0F9ݤ4? Od&XӅ6O:3x m,bags^WN\F/F9 х[Jd*{U:<ލ Chutz*DT%"&W(iAHY!-ҷ">bxj0D",[J ZvBedҿHv.3ajQynҎO;N@1*MH {/JܣE8?N f_o?s;o) |&jET`o[.6?ku "/ڦOHW^7w.r_/2OS6xAjC!@bF?@Jn0cb-fBIO@/yot@VRss> eܻhC؛o)XZJ,kKn=%DŽ2pnUk 7=*t99S2pC[vXr_X`o) '澿X]g ; '|~_iw_v?CCb xM 0@}N1{76 x13ڔ:] ^6OW{q} }r$9`@fUfL>##Y,x'.$KU8 m:pyr& pLiר*ѴA 0an F, `>B x 0Eٻc:w&hѶRSпx7YlʑtZ8!O$2Ac6(Y\U%c^0ڥܦ?iNiRT-~/f__NۇL=Αx10 E;K'M+!$C$m* /oyE"cA;08,Mm 9 ؚ*ߒzOHZByV"!BhYe.qyGXL.xUP @_Xv}I7xmi{s7?A xA B!ὧ}uBA:Όa]m9T4Q$i̹ oR1'ڂZ<I$DGȉ*Tؔ׼wy2Xo?VSDTt9a}<89Dx1j0E{b4%  ,#xm=B#&e~W|`#& qID~)G} V>r'";zL>hJ9eC&qT|q߾yg?ÓǮP[+ge GTQG yUk?G'{)Rdwh.gYxj!>EsYB`!,roH2:sط_@RٙA{c0[VhIM10: hM2T[紊D*J̘c~?럿FK'-%ڶ99úQ~zvfXh[Jq{d!gAN^ x;0 @;KRH pq J-oyOx (Yw@ KA9#Fg6P6bG_ُ-#e `53P15v*?mLuYfU#5VI&V=Sbm?|H~iC'P#N@$K޽]??etm x91 "=M;q$_-BY043kyTZZe$-  )fjiwO{-oRA$F ؠDG'8uߧ~v?|-g'=ֲ?R>06y x10 @=b'vHVQ: q?{=@sZ(5hX3JaU"#.Dbg酓VQɮn䘏m׹xy-՜1^[m]sk8v>s5xK 0}N1{A.ܗi2AHH-^ oߪ4!FEc(>jTOl "spv; h]Qk(R*%H339rM5cU3AP,uWmJ95P20>9B xA 0E9En&1 %AEoo 6okc %ZR[%hYV>C8AŬjXV Y"LUȕ}>!8$B'u}͉?VoV&}ػ7ԐxKJ1EYE͝$T> 8zJR)ӊ x'gp0E 5"FR- c  RRKUL٧%hbιQYO`A𠯩2c*yJ2! |܁:lJ ,r}~$Hu xK0 D9lj4;8A**ޞH\k< #'D5Ԛ"2"LJbrkn69z?MS>$5NRBᚰxJ˛KǾ68 }5c"*P;[6+ܮXнִsw_?AbxK0D>EG YV"=JLj P{2@ Yo{ދcu/41Y[ 9Zϳ;rDY4i5zBг&4#*!p}^f|ztظ`kTȷX|1Ucverxd(i >2VX1pS/ |Lxj1 D ۃMl/@ȇI+wݰ`+}MsuЛF Ncfvs" <08đ3WlRllǽqqIdB)[D7uow=s}uYjJ.?;^ϥ}/tx ]CXtIeO3w9npKlZx] 0s}$4.dUH /< tf(9i[ !2e8XP2RC^="rDm"AP' Υb1N+zɵuZ_1vnpЛTn<ULz-; xDX\t, ܅IxAND!D OW+@ XKU&9ֲkN\slvMBQΓZخTh!Ȕ#VwMj|f ^e=!x ?nidpI^&g}?| mw9B}u9/jU xK 0C>I(q(}zj#OBsvDF U]sjmũWO`m0bTMZI᤹b9w\Wp@Ss:^5Opu3u.qư/I? x1 w^cc_D }#冻9|a"-ZLFaH %Sn{Bn/>K3bCeBDj +|nÿMm  [pm[ל]4u_5yx91 =Muv%_؁h/ ߃L3H]88K9B1Սc"G&oeSc(D橆B}z;̯8k`?kS?RS.Rfhʾ< 4"gR.Ġ7DxN0D|Jhxu: >`mot%qN:Nl3S̼E@yVloPM DkG&lYbzt4Ʌg6C1e8]S ow}kMG ^zO2"6(Gt.SPW899 kɛ/PxjsOE70LoEϯK=f@h' x; ўSЧ1Er؏b ·O\ ӼfQFQSqU9ʐ`ȴfXP 9 d9}Y|Xw- }os9[Sm{\<ӜxMJ19EKAI@Jj:h'M&z{#^ǃ}3fVUB"gb`D[u`: (+%"O:y ΑY5q'+un;<pg}/c?Pu6t^&K}sR|=ˆS[,/zgFQxj0D{}Hҥ %l15F* 82i)kbrڦ$btTTa{A3”\dr8;"~{HyRЋ<#ru|G^Om@u8vPcJ91V}]//<ۊ@=?|?O" x;0D{b{ Mh8cIGp{ӌFij!)(F+u-,yj?Tvmp9C'}u$O8zAx xK 09[*no"H* EJlfjAjӖr87=O̪SBkR#-4^E.z)5KH*ƝuĽ0x|?1ˬRJik?RKsapG3=jM> xA 0E9En&M2 e2"% oo 6o+SH0ĐH\fָt M2v G^z%.Khb*I5ur6|!pȁr!ۺ>;v s_w7 x=0 @=4.v숪jS0 q-oUZ IMY(6 w+6Pٜ49ƌjCuYE.,7Ob-,{>?`mbH7fjuNc5$E^p:Мc >QxAj1z Ajei%٬LJ}m:p□ 0X.RKS&~R(٧/KFKc#jҚJm_DZ+&]F!Ԑgtg\߷nNTϙ>aTLN2'}4e~s-EMxA!EKmaVIƱ }Br{|Xb!-k.ՒC1! k9W6y=fe`1|k{Ąws}ET (vnqzzcPCx1n0 Ew{2-[@ rZl4޾:d[ H#з9I ]R#ફA ~sԄ<#6Z(Iu\*| Q r/fF&5e>ʛϬ+,A~<*gX˫ʶ\I x10 @=bvJ$TQ:p{*q7{PY5[[QO7-")^,=?h8v+-|4[xLj0+^(Z˵+a]%nKHkR}!ڹ0/"`La<ޒgqQZePʦ0 NA,slR+|7Ό^L?C/iuXt.D%3;NG{_=*P\JnA<'ЫEQ/ޅax;0D{b; ? quV$vLf8sE/Y\sNA@FNBb=RVw%QS]d흠32(o"mu *roc`fjye N;u@VAМ x1!E{N1 ; c3D.(a۫ޘ!m)6'5(1aPHF9[Zc[bѩ%F,Iyr`B[rMM5葼q&7* pyĤ\7UD yw8 ^e9dF@ xA @=Lb`Zi.&^y?*P⌒8+a*l0 )]>$v H,cPimΎ<9ƽuX߭j+86R"dҶmCXԪkz.0cyTٕ:x;0Xn"!NP1~A CoO#.{lo): G# x cHѢJSJVAG R: (4J'8o$Ϻk1mptRF gz,JjyvmnZ˵@FXk.c#rp3ÀC!Ja xI 0 ~XJ$K%q(}@20Loh9YXz bNM栦{{2D1 Ccp.ZL3tgm|h@7{arݶWjC@i]wmsS8Y/@$xAn0 zȥ(G@ѿP4 qaP5d/ aT!BkZ.e&0_Pjl;ĹR1eFܰ9KI|c,j_g{w.+.NW`ʮp|7+0S1N1xAj0zދAVV%_ U,HASe`U!S.b@t>uQI(uD}ZefβHN{՟21D;| m+Z _v1ՔZFH O~JryIo6QyVIfx1! {^> f,)Q^BzItiFMUXr9BRl>`*``"u:npYkEM\b$aYĶc-`Lv3 ㊘?6nnXKqUq>7`m~/-6@7F x10 E;K&u#!إtq'=VUEAj ZN} {J:4W]X() Әkt.rRG.g4|Txh7@|{zͭ96e &^e]>dCjx;B1 E4$4 %5K)&A $'Sl\dtRyWlrm{N ǥ6>+qÇTzo#_ $bi96'~BmP;>n[l4uo]ޗu/yltQUޟ x91 =M+ȉBA!)=+f .Yp5'$5cHT81{I}GJX0 F"3W\3;: xK 0C>؎?5^LfdJ8޾@W$ yљ)`8 ,;zS509TrA1#KM>Uwmm6il/5.TD;Qظ/uS_3?Ax; D{N}~fAr5,ec,Er fyޘ!'em\^f>d^u.)eٓʴh* G(hgmk_?@ 79#b-e@Ÿ ðqLQVn/VR8FsxKj0:ſli)zDz|¶d9!olf3e'%&'TRda! aLnR; ]2f(LLf$scn{Kg9,m+c)ͨ*y:xt b%hkwJcJͥqގ/gQx;n1 {4. wчYKOrLyb#9DauK,sKT)eK!̫mQ>&'|8G6.8{bʸ^E颒y1\|pQ:`g)F3x =wmFx1 {^q})Jp((6H^K@f4Z̠kMp1:{R-G,va[u`N@S6|1YO)$VKۀ{+< {f }Nm]֛4ZڇaNB:L P/Й;Oix/ExAn! En00 Utsl"⪚)<}'d#?(swL{6ӔPy =\(9nyzGCz~2@L6%x ST!faWPƜRs.]d t)kHo3K]4ݖ xA 0 ~([Pǒh(0ۛ*P"DiR%fs`fnM>!MHH'’r cD]>6x}hF?^sһqu*PR7R:/x;0{N}1RG@)rrf @E18sᄨvTt *)gCbb@'GKS2*=~|ֽ)MRyGz"5dJ,QLm65ӱeuM;}*+Y}+Jx1n0 Ew{l En@ z<<|2/S`񜩰2RjfrnAgIȹi3&2YCIur{.R˟s_L:Q}W퀟 ֭u_H+ xA bャQ ot]4%5 0}P DNmI;c€03nv`IΎ$(d)@z5Zb{e &4!'۲U K׺kӽ͕AO xA @= .Ħ5z{M6tHz,SDHĚPh11NűSd&ʞ]tlQ yïq;,IXeLݷmCXΧ486>b>I@_J*UȅSDW( oH 0"Ա N*b$$6Dp7%i,t~-p)J;Ice:2OmV[5M}G5 C xA F=Jxi'PL5ͷyc-.Y\ Ql)VGfg'0ÏަPc.>I'Ӑs4WFY?oĜw>HuՈ*MfYIV{'vA x 1 Dܽ$f_4ARop.3o`FW6ٸVטͲbH-ERL>dLJ%Ũ\!b&jl]JUblt> t<WIx |ҥWKh {5<9LUH#G2= Q }Ds^6p HF{7vŊuFK&dLZMT8|}Q"̭ |gɶMꜞpd.Rgn5tZ8LxN1D{vH@alY"4PFtԧz"{14SHeemt #{ h$i7bU Gh3c&S0ZU8o+<Z!xKѶ,EQU_*WܽPV\2Sr:&pk BKI[ ^:Tx1n0 Ew{1,-t 2Inb+U!^\|>Gm"0'?q(?OsÙ x=0 @=q%]ئ*tA[`5Ϲ( 1 QbRIt}09#'8i1DdTe6Wαv|"'7նCPڎouv"<6 x10 E3,vҦX8\qQ!R <=Ta.0X;vp )&o67:cReP< vr19fK{B |νa]A|+.W([>/u5> xA! @=`LbKV':!u1 7omxJEjLK0uB^S $ՇTcA3 i R$̄'8!3 r qF2:ˀo_ENabj_EU?ި}L4PFK¼KoخW5olNB x91sbr_CBelB^,tRIU IR*)tAb։"2V8>AFU)+ʢ&oMB >b|(h{|?@s"m{b& `ma> xA Eb Lb03j ҅ 7-^{S!"o%F/\SDV3rbl6jZ: " "Aԩ^|䌘|$)Q06xh7p.bCN;u]Ԑ l5=;Lp_jymy]_X*Ԅʢ#AS} O a H6) fk?TA!pߐ P> PqLB_gPV0弻v/uGxAn }N}7Bj5w1D`D~27_zKlZ E-bq"Dt*6.I޳7xq~]8Ź H&<]Oo`Lac2>9stxV CЎ:k~֪mRӃA[o3{^uUx D~{V JCIP̀1װ&,)c)X9ѨF<[=bti@dlH:]aEjU3wx Z qmR&Wr5P cy$P_I֟ xʻ 1@>_fl^ 6`/̄X 9mUD#&s7 9"Q1;[3A:ڰҴ@P!qJv1RZ6U?+Kǟ'mL lg>7E> xA! @=`領x%\x{'߼5U l^Bv#U|(I ̉)yDzh˚T yv.CmX9FV}L^YbH^̔}-~iV)6d x= 1@>Ho3I@u\_E֕ o|׼VD7aҊRqZ#'@3V~4 *(c,&u)HE\&mIФE|Rdrs#} TVy"Y^N؏n`9xAj1 нO}7[hV) H7BfPzzj}bKaTէui侤a4ĄT5U:#2CmEɣ{nhB''?ΕvP'f0Bkq(e+y~U v~(/y&$ɹjk ՚%)ĥ{QBP(I$qa۸OpY=E8Sڲ-Kb ?K4A(D/43W誀LI c%ScR*X51HB\cI*iW2W`PT9݊v8l`'br;uB 9`>kͼY<ߝxn C|H=BB0D-bR~e% lq[=Xc pU{`*r#f;~6cp%jFXގRw?Șk&覇T,)Q%ڙ?Tv:4*Ԓg?ϐ#mƊ]s8`V x=0 @=I$]ą ڠ(z{o7*T.K$$dKsHXkKͻ 'Xth zEB,dRٚrG<{ן76eڷmSXV\;u,F8y xM 0@}N1{$N~@$3"mJLo|oFW.8㢶J>,Ic9su^8n)}Tm 94P :  }9tU[;ϟ xI0 y\,u"!Ď@)*)S0ÌMb% jQ[F'lDh)js.|QM¡mƚIuYE78|Ĕ"3쁩?VSg?@7xib~=A xK0 9l؉8~R$nOmF3zAMB!A_2Zg* !M-TΡXE)$ Ec5'{ XˏW>)dsԻqu<@& t:x xK 0@9l!wI2i#1]x{ ^y}j߶ǜǪdr/7 x=0 @=;mbK+B*x[AhȄXfK\i$,8NLS 6_;L$˔dy8pJA~q0]yD% xK @bnf &g4&^MhcD4ƈ!:aֶCV[hvc$s!o؈C6IMr9cUx65K˯W :'U0 hCGr2? Uܛ٢8ࢲ.ה\v%Y#jFinWDLͯ筻<vmtχn_7A x;0{=w[K" ,f9]MT& [(F–ԑ>SZb LRXUE^2I N&M_ڷmSH1 ñl}lPW:OX.<x 0F<]zӛ A,i Joo[I* P7:숴`l5[&< PʕmHRq&{DC\ neՏk@t`e ¢8 RTEfaޟqCN|')1"ld뷵fmp 2E '@21k)bLlDJ&eJ4Ѡ!ա RNsQQZ+65Suc%ϟж֢ӭy!zZDLq~8|M~iߣ~f(w ey-e:3oIxʻj0]WC ]t$b2z{#}! ⻯7wyU,Yz绘wP:E1`FfNK#:))]$| : զR鶖J?Hl씑(D*|m XE\cП?Cx]I?*MXwKiYH xK !!lm2$8>B.ڼM=9"$ Z.Bb6'qmB4a |TX)u*;zѨútgtAltZʅ(}߷9U5=`v +q/9?xK 1D9E/7ī =IdA 7f P&딗a 5cҪcΣ"(#vj\: N!95])9!LQIit{m ?`k=EX-boy\82X[؟pcst_Ex0 D|.N0$1NAPA::޽4yއ~29g'"jKw:. K$֓Q'dAHJi~pS?,N!|Em]~:o 07߿Zη:"@ d*cPM xA  @)MWiڴ&^fU@*wRO.L[hN+./l o`4k !D'E14jI͓<4m]#6LfRA˄%f!_~p.?^9" 6㶖]:|Ue8lx D{bۀMxH]dc,NT2͌t`֞YSp .^'%v 搝-"3 'l S :dOQVEU!vjYnU 㺂t~( 04n'zVYN7~C6VoE5UvxLIn0 <7KERPԤɁ \pd&g%y$kE4frCȋw4g"6:,''9n&<u:[F?>11քOO [Ep _qΤ hKV#`%=ixu;/ .{mxbSxA DuQ/$ (QTdf޴*4=F&8L"sFM :*`Q{KCJ葘$(^up[(??֢#uTܚ\, x10 =ΒNH*=o Bb"cXq݃ww@JY_(uESԐ?p4 ysҶmUMkg : xK0 9lⴵ q$v'( ޞJ\i47UIc 0T&F )8Y.36;n`De!Gs,svHI 6xDG.uDX\ }ϹCY|R@xM F}7?B]ƙ,rJ{~7FRbb FJB.r0h]"DAd:0@ex%8GY~] b)6*d<چ.^vj1 ]zEx10 ;K܆ƕql6 R$~,t:z3 Sp LIxF)EB݃a&IC<t@>QXfG}, .?"8NDNڻ=f> R$o w jiC^o- `Lxn@Ef) K wfx-{\%~ۜ\Y![vP/MUf\xh-c*W|&&S DuuQɵ/p{v^<19;.QP6 m Ap9`㴗Vh:1T2iUlHtx;n0 D{}})-I67$1⵼ ķ_{LxtfX,r5'̱p.mX"Ƭ bPϙBJB!:^r?:MϨU$\m,_u>ZC@CֶӶ]\NaXw N8Zb ;?f}mH. LYe]H {{[[x֫[S߽>g x1 1E"M&7+ A$ . Q7MD XCGĎCFĊq)1@L%Wlzp'"3!zQ(&.{WM/[G @ ޙ⺮s򇪚#Y߮%.r#iU_r< xM! @=`Bbʤ5ͷysZK4S !˅}r mZi9Eaad@-R#>FHswv`Rݹo4ڷkm;<x;j1{i44O ^bKˮm2437PBpqNjjɗL1 KbֶIPKJjVbWj1Hj& 1volpz-Ż04eNGj:2:hߡu k}?eZt!Fx90{b{ Y@bG{@b̠m (g˃NѠS B,%Xʥ:G̝#4;/3%ESts]JyotJNTylXiwS-VXt[O/Hg x=!F{N1 @b3j\ %+ޗщ (3(&.txb: :ʱFǚQZFOc:L0IFwM Xb 8dnUU@6] Z^Bޯt ?*#kJ{>9հ ۘWK[>:gײխ@mz0GDxAn ^UbQnB:t.s J%T-D1ǪmQWL9X w`/Iݱ2x&LjG  /Ƅ!:O>g y>ƾ?V"*`9Ƈ<lm moͫ5E#x;j1ss'Hdq] MO/E="@(9%QZhѦSH+v< kY-!UZ 2gڲn}LxPkui^9G~Ww F٭s`@3kmv_fG x90{=%!J> b8'`i9%85c]B)Ƣ-:U 5D$ kObV y@1> y&њȋ:[sRvTJ}v%@? xI0 @}N=L qʎ1TH qmf op\ `ŅBr-f!TP{aT 9$ K}Y=ZJZe80ZAp:ѩi7x[CP[鈕`PғnF..k4X5TE/HhߖJ{ew[z3"-}ܟ9eJl x0 |w8-yHqb"hSW37pC&X.xlRp1EG)OhȪ3KI4$,m."$'Ю>@2.?b=)}Y=ް m}׾m}yA)xMn0>wǎD *U M<7U/lf}P컱.6qܾ@B' 3xv8Ч]-QA %ek,R3QƧh5M>aMq_&f!Em]zVC^{ΣQP_.SDx0 |Ev;yHpGDT,tI7VU|y\1iaBJD-z,̓W͑*7עVFBm V8J1:Rfoxeseg9Y_vI,>|օG_flDÞ x;1 >pO{?%]-"XE qy͌Y4`'<;.VMLOYeBmNTJXdYPaӂb5G0pyDfVScǚڣwPw7 x1!@ўSLo 4fh̺` ߼9{7)oD5u>BBÞBdP䥴"ILNh{޶Ϧ6 B`Ĺ m]sUUS8_/ ;q_K7x10 @=Β8Mˆc;PhզCo/yuV 8} h3lES$ L4뻂].2"JіJRwųdCk}3 (:#8#6' ;zԐ .gX& {]/Pt_`.{tsPwE x=0 @=qHc!\QAix˷ZT7b- ƀdc }d^\tI$)9{i4Ppwc Ksfd[Gj{媽tUEa3@>q x10 E;K&#!F!؁BQHnO-I ug)4S,ZX lqIMQ4&˦Hb2uqUCk. nE=: S}]H |^YtyU;. x10 @=b'qHqqDJQ /oc3h,=r.Sa2!BrKqϺc@2w 2X<)Mq|(q[7fHG)2af st98 xK B1 =En$ w'Ţ'.lfM3*΁^ RBFQ1,%Y5t<ZԽFhk8po1dل˯WA\ݷmen<5)g6z x10 @=$%ˆ8BiQn/o-`idU9RF1&Sl2Ǩ %l,N^}<ޛZ3 H!7WZՉ)\nW˽I_2[}EÀ>-Y}"!7hIml&#M# 63C,6a4B€H좢cv\f%苳4Q@ٗNY[ wx}h52xl"t:BHV:n~@[k.\`T l23ݟJe.S!x1n!@ўSLvReC ̌]o"Hѡ'\J1re-yP:`QW}9$-*19l,>)0XLi繍!Bu>@G# 23\ܥ*_ snl^J xI0 y\lgi"!BH= >\2TaT+ebh)ǐB1!4vB*(QآfB>!ϔ'68imp~U>Q22?i\5]T 7U x1!E{N1 $x`fucV w/o^GWh* #֐P9w#I+w}@\U8Zϓ"2dUP-g&ǽux|h'p.% #32,5oX[ciO=2 x= 1@>Hoɏ ֒LPd] ^|MD/SB[] f_)"BRu z)0R% r r%_:7},M~51Y MpOH8WD,BALY RHF*J+;rO&pwOX26Eօ1b)W2_"9~1>&^ Zc37'ǾՍX^7Q x;0 @;Ks qqDEڠbnO%.[쪔SL1U =fH<]A*ZiI|rm{ >x|f?ڜ]H \sVU#5C9 xKF7_J= x;B!E{V1 aX3C4 K9͹sB!M}dBAEKT$aNzJU>'6k2+v"azqac7=ogp=-}s"*p^Wbl7 x;1 =M> %؁ڏB(=fFzZX(J:V.1J6D 1\l4[ntH$"EG WY<-l&}mx ?<2cg:Sj Vy_=f>)Y:xMj0>۷8 EKo,pH"WlPPf1A+;*gt󔵉.;`XiDjY͝u̜}OןlenGMht7:c 783N|FP̈́۱ u_T!i1:pIw 2Tx1 {^q}8(9#A\A;; 9m%҆.ĨL86AMLH[Aoü fht SYޕw0{.zFźy U, <og)<  JN]zϵE x 1|Ez\/" 6ZKWd7b+X90"R IhtY䌑Z t$FGP V\\eTV&fg"lS* +][+$ } 5c%q<ݥ~=2 ?xAj1 ~f[S:8ڐ>~sƆ*BDkQX9H8$&E]`sXTĀ"'J~&Lc .˻}?.:'ҲД<㾮L*>P+WR;]f#Eܞ xʱj0]Oq{ @RJ5HwgXQ}}˷mU\MM,P.LJFYsϫ. dNY )tHw(c .u*XK1%B`ӽ2\okkj cB0.srk9||<=BxMj0F:컙X?!,#ͨ` tョ*ّcI61K .E 4`HS@D_2+$c"!wRM}wgYp88"|>UUYU~cR=4 ߠWVTai;%]z9_Pސx {> )Yيm"%/kzl<OcDnrA!h#4,KU8"chY Ha1ARs /@|4xcy?pߩX.*m~BY!6.q/upxMp<ɮ>`I x1n E{N16RemY\k^fU_=j(S `Q~a$`sx,=Y^Zr h!v̯as|55/mHum62vtR}/'0~Bߟ x; 0^>)@].6 )oA.iy3X/I#U(2xc2fMLq.$.>k}v$3j_?A$MΈ>Aa/ 6,EP eܛwhٴUЧi <.~;ӶU~mGxj0E{}t)HcG!4WYd࿏a`os@nd#,,М8%xxg,p֪ذtʇ"91I*ndY~{4z.xg}LzMにq ˺5|bXjՅO?Os7 M}HWIϜx1n0{z7:R@8+HD@f@%e+:OXꔷ+g/ (K\O@Hf$ZNA^1gb%L,t>ҏfuj@%TvmWиm>4 m{~kH# xA0 y\'1KPAV|J AGFk>HD):Ԕݧt] cȁ/B"r<ۂ•)RW6{eM/l^]8x xM 0F9dۀxI2E1E/ǃy akxLlivt2qJn5ƠvrIl' 60c,&1 lFEǘ7{,pSL'ESe[e #UC?{hyk`Ax1j1E{bifVZ o`Hf$"dYHn_ >OⓛfQfg\R!!HLCBfZ)bt1P> iA!; .{Ç^ߞeۓ' kh' .?&[? ^J;+g嗇Gkۀ[~#SJx1!E{N1 .11ب`p7` =x*38a/=[9%$5(`2gʹ&vSgTs,ZwF9A6 w\a[*%,<49q0éS0f8UG(_y3_hFx1n1 {}Ғ) 0'Raɠul; 4ĜN,hˤRQ: /q&Ib,--%ıA{AyPs7\s/<X54y>AT`>mݷ8&yDs x1 {^q]4(_8dXRdfҙ ytaE;k}Җ8o;o8qS9c) 8xɐ/[epMpu"Gr.F9 u.>d? x 1 Lឆ|,!&@t Ď@ۃ\sfGժ +Q2St g&dm"0y_") ftnjv?4 6/2:Q5p"0.7ȷ>2.mYB x1n0 @]ޅdY: ) bG" }_^ofXDP.t)ŗ$n,f]3D+c^NF%fˁG Z?pna< k+\ c۞zx\nV~LG x;!@{N1 ,0@bf`H܏A,n|k^F멠&h'k vwx;Kw0&D}]Gx. - :Ox7Զ@ x10 E;Kq"!΀k;j%(/oyO738) Ja0bQ!b018+^a9Nd!EQ0 B!Oޗj ?^1Q 1sRmP6苁L:ԦP/hAxAj0 ~: d]\C.kH< rFq; }M%3 #TH(TC^ r-s>l5PkĶ9#u(̇jB+4`jԀWceux+5Cq{Ji x91 M $vbw"S{SJfwo)X2&&)Ej'42eW ko5{KjH5z++R]1奷1,N?RdcbضAaJY@om}]\De籙ئCΓx;0 D{]4d EHe(tۯN1Sb@`LuXlR(1Вp* 3fA]vO=dJ;Ƃc309gWs*|)fLqp۶ju`%EϾKo2tIU x;0Db{{?W x%Ǒ=A\iFz*(̑}`AIR6I7͖ "uPL'q#"g16DMu(dp3 \̙˲Au e{̅K:C x10{4vrI8FD(1Lf)7L|ʫ1:͓0*4-)&#^"-y"„lrZBHj^M.-u߷GJ=N#S17ې x;1 =7+!b'@hY۳ if7;x-eՅd+X)}޻"ixFj̆R G#v-!I׼XaBݷ6m|J]8 xK Ey'~BVcS7 Nno\s6̎@)jpz$6!!9džK F Ee({Ƅ$JVYS /џ&?>yo@򦮉\;PE^7y2԰71@x̱ 0=_f]4iС]%}ѢmJo?].d"pAiB ՄUQ)A(؂RD.k\f "IidT+;Z0|{2>Xa+-aװi,}]=Jҟuy EXe|<7LEۚ x=0 @=Β?ljش*mQn-)yQš rXI&ԀM-h|> "Dɑo&+RIZc}P_c>NXG?o\BpLǶ-c֤w<}6W6; xK @bn` ]f!mL nom^^FW_=;A%"y88 g>0rX :O#$K.ʚuQ?Tõ˦@g|,jxh=. xA 0E9L$q L)R+1/߼{{S%UOyV% TyH{,'J֐ij-N𘬑{ !b$p}2f^=R[Ne~;" xK0 9l4S q7vhQH%=E\HzS$":ά\FH8N)rITE$@C*$'4|ykxo ?D&:9e){?47>_ x1 w^CRտ0*jT }#喻9<F TADP$ilr M [mTV04]j\2dh1r!%0|??{o?ϟ%kH]ZR6șx 1E|ɂ"V"XI>Xb߫ ֞r$}.>D.S,!ckc0$}Dk (MI)-Λz&w9?]QX*1T#~unN~Y=I1Ep x10 @=ΒIHSp'vDEi`$=_lsP"u[iܹepG[NCV%H {^C)y chLs^z"+S 8l/NȴUo` g C {]A x 0 >qԎXS8+*(E!b{*]ofǀ8 dhE#сcLZ5 ɸ}XM<ΒXޯ[gSkpL4P '궮KD/⾭8ř x1 w^C0;Rտ@0j&D}#;"PцBqsb-G>t6Es.9V1LBeJcvs8MMzux~Zyi=1K۶UUXM*E yU>u_um0_?˕xAn =B Fb.`lDU`DM_/k8h=l !M%ZW)Ry`GO8Jd]\C9cLn[j,963ԎcWPpCZ]VO+ȷХrXG ![&է@z/`T ~Vx1n0 w{QI#8̐'E?[35BKG眛J}T bZ<=,[s.r>M8TXL-\gIq\^?,ReA!ٸݶǚ5o?ء?wĀ8;=@WOo&D x10 @=q%86Up$._BU(UC2|N)!DDR&]W!SL˙#R摢1G'=ZѪv"2sJ[LXԪZ7dq~v涺@x10 EKB$+*hS9f[ MzɅȞ CsLFGi~Y^GaQx)4k먬b&\[CEqYOLq{QVk*B>/HE xA! "-/b$!xn\&f 1b"` c*D1 ͽJbEM ⵵Ėsx\Zpnn}(,mcGsQ/ 6)x;0 {}QX.HoM$Af>r<`^1:Eu)pHEmnjGnX ۺTt.КsQ%}t!&!+Kz^eW@)-<\쉩U!faI}*ٵkXK۳9@;M@ֻٌ7|MxAn0 zHM@Ћ_B46A?н,v0k] X c2KL1yZcԥO+C0| 4"s߿ןBNi>Wtfu塻,L~ 1S۟ N]Z{pJԞ xM 0F9$i~A"d2bmJAoPy<*3t:q46l3A3FRXyiE,;E*&9*ҙ]lR.+w@֪3p *q s?sٸ/KWiN(>LxC:xK0 D9։%UP>h 0yxhrS,6 ss`qHK1eSY,%X<<W+Fh'!:z@&zoV+ OΡ%8#uUՔ,P m.M*Ԥ|sWC0xKn!@e4(x`m+},yRNascAK>޳pBr3'O ms1S5V{H50Ҽ~ ߿ʄ?9L{"LDZ?f1RrK.(p>NS.s/ ڭ}A>wPW1gP= x=0 @=mKĎ#*Bۃx˷@KTH&dU4-(24gnuf4ƈQ*#'~<{ן7@L1it_׹wcurKNb/9[xAJ1 "{7M:A/)3h[ y»|M$2e\sḧ,{,.Sj妴|p.ȵ%EQʸsCi+-&]4Ϫ>QᷥOwǺH`7Zkvfó9t(zr >Wpɟ}I xA0 y\4 7vEmQH|f5; \j\Droj%%t;LP%aN\( ƺX򕕽59y9:\}q6v 8G6r x= 1D^AF8k&{IKx̃0PIZe5vք:()ΈG,SfvMzB+||!cZǫu|e!)p\m}Ncuj 6' 6m@ xA 0}N1{A2LڂxI&,ڦ[UUHN&AS3Y]#![x{/k据 UN}`_9a(EfjH~X͋>hJ!){ \Ъ$A+cJsqm&as a)fjjHDNKa4ϰ;`?|0=V x9 0{b4W'E]"@!} @fE" {ʎ1T/m5 5zu.ۀC 5!SBD8mR/Rt9|e,??& Uumc- Hȣ,@66/@ x 1|$&ـ؈=O.b{`ak*{hQ'I!{CP I.;bBPXen e&񄖼,n huˡ6 wRaa,`Tޚ4&.;u2;, xA Ebn@ĸF/0Lll颷mYba5FyH5<3kT#sRɳuxRo/`L w1 peDUmkE ޡ<! idW_D xA! @= BbK%3; o 7omG$e*Q\Coc/R0Kv`Tb-L-U9i! Jt|mLx+ fJSX׻:Q=1 ս׋<x 1E|dF,}1qDl߫XzÁs HZ+*Nص)t=ֈ8W;E:% ML`BQK+\2Y"Or >g԰lP+л|?7[' 2RҜCJ~C x=0 @=$vJڢ( $.[a&E/ٮ$V(ՁWQⵅ'g йy##FFZRT>F<ĔUJO˷ Ƕ95ΏȪ7~ xA0 y& W*8-*¡/^vVikQc`/V- }",aNC:/bV.T$6qŀKhǾIjx\Q ~}еGyk?To 3OS+,:B:u\ CZxj0Ddk6Ҋƒׅ}`f"\΁xUl=#a.F3XAdڹKUș]tBd"dbDdM|u}$,<4ŶmEU>NX%A>kڠK')}ۘ=EP 7=2dV xA! E{7 x%N `1^yyzrh}+#[1%"ӵe"hLf] 2u1cEΘl(2nn?ZFgkGɺhŎ C0ل0:d6p(0NƇok~y9:pDL"ra;/NWz| >/;,a{m z?kIax1 E{N1}`U2 ?k+ Df\׼=;sTT !IZ x10 ;Kq#!fTi:{ כ* 0R 2aJ!AѪwrTܴt@3.jvm4͞ƘFf@(>c~ *( HDp&eyETmyz"/޸lkm}|qB xK0@=MLo 2tBڔbo6*l໑XC^)F'M*Tek4xm18u4~,1FG₵QѦ\,??s6!\y]T0,y`rܠUk(_uB xʱ ᝧ(PHqr36k /K#.ks2coOՒ]p:yXr_/%0I٢98Xu&^gC2T]y?V lS @p;]x9*m>yA x90{b{ %-=$03܉@e(c$3z)Kt] duو%tu^y7$tB1dJ[Sމ{ZǟO F+c$pG6MXޔü.Lk.7BPCx;n0{iH r%w IC\ y4oF/RH.1/vKrZ3έ']k(V"+5zm2z/ޝ0c9܂/;gjJdI5:>`hIs}XVatrU[J> x;1 >pO$.N,Pp{Ӽf4RQcMkꕸd)&V {ʴ֙F4ZdQRBB ݜp{j?/BɌc-cu1֐;S6xA0 9c'i/6.$6 R#Sی4ژdstIB .u8yl<) %Ѧ RaӐl@dƧ^jZ 7b6n\*\Fd;V::ȵ5z_FsxAn0 zXeJ@OH%F`C~_@`@!VϾk a %ƕ9Fq;l*׉挽ƆwK1%I!ba 9xLpθ6^L1udp[؀}١mJowHxK0 >v)_ {:7K^3SC"CYB <@;l;6ֵo_GWx|F x;0 @;K|+!TU:p{*qn*>X̭b0S-XI)$*i&n<( -2yJQ\w|gj;\b-JA/k #uj #Xxa 8:* xA! Bw/Pe|lh̊A8LfUX.1Pʨ DI%5E^usB5K0.ZPQcbf9VA\]x|0!8mϩuSs7s_'U9 xA 1 }E^mvAKҤXtwԃw8a0ϩUj%Dѐ,LjC g ZXbTI׵2F]F$bUSqcs |e)BO\=i}v~/8ʟ x;0{b{$8E<#cr{~5SHU`$ =-t:g E\+nX|&mwS&~pEG;J$T'ϏFb5,C:敢^jg OwZJD x;0D{b; ߖw!"#Hp{+FO3(%RBD"H'r)m:@{LB;q <сw3ph$#a.41eezQQӶM \C5:BVA xA !b8 !qǙd c }| ME)ht,VFJ.) :(]P/5P"ϥL[S^:?Je2n!FsZ9OaNP2?=n6_bD!xK 19Eݤ|z@  $dh3WMAQ9'',c<9e*։SSo/+.'Xv3_G x] 1{0ĻtwRY+ ފ0/! dt.k`WGrrRd «x-HyPUnBP)yK,<ǥu{{7E-s>Nhlm߯c jyzl1|'&=L x10 @=ԭJST+A-ߺHQ@ThY )UQ̊n箛y.4g 8@FX25;>޺[?o>1Q/I[ׇ:}K[7MLv=ۖxKn0 :C6PtsHFcɐi }y ivCf;?P4 y80,#Rrq aхh)4 yG&:?K7q#M4—=gJ[EU>PMbWvzӦMvϫEVw(v;ť.P[j;Lx10 ;&% #+#SGTЦ2߃nj^UM$(07C2JΞHnaӹ S7:1M|YඖA v(n"E4K!ZC73R^\luu,Eڐ x11 =M/K|vBǡ( >6H;;d\3)9ZA!n*ŕ5Y|JV2$<%\e[1{d 5G0p%S%2\؎}W7Ox;0D{b{ul !q.#G 0͛iizc]1YfnHڑ=s'5J-V_97$ LFrQ+F&;C&ѨT*<>%q ^[I,dt;ڰ_ s^}~6E x90{b{ |q,!:*^@E.=A|ii1C)GmSVgdL%:$tSR/l Ph'Xbxvw%np LM~?A\e?RDLjy ³" \/7caֳDB x Cw.IUNj"zEԋ-Y3pN <I j8bU`BbvCi luc"k ƫ˫65s7@u.K,oU[ qͰg$4d?@ xM @ὧ}7B]IA 4o|7RѢG' fL|*Eά4䘐]4{L )q&$5>`{ϟ/:0=}SXU[p0Mn9y x; 0{b4Zɲ$S5(caכ*w4d%W3gʞgMMĒH,S)$9ӥ8Ubӗ`=h@LяE 7{pһQL駃r@_jrMBxNI0s璵m/#*Aa b[ek(cJ23[FQ6 <7( wdr')II"pFMRuAӏ4t^UG4~iw $O>)H[?H x10 ;K8i#!fP~ppmQS90qR"Q09d'8KGsEo :e.'K %D= ]LW]`ΥH`rKkj2?Lq; ;hqy: xA 0 ~D8P%i(i@eYfXZ%.fR:HMm0nkjSY$?x;0{b{DB&T:rֻŠqܞH\SWCJKXy b  a;4.Im"$6\7"ld%RPvp.ӔJ?Rna6WR5"A!q$gW{)-E8 x;0 @;:? 3pvDUT! =oy01Z=G5K@9rAo]_^ba W>*gMX| m2Qzsf <Ěxj1D{}I!tCH"H~`O;(>t2uj, MI%eq~5[i$:15IEg :]M2sI3=W۾uJrQ@/v/jCULެ&M' xK [}*^yiBo@/Yl7" rb29\Ձԧ191lFb̆ǜ9lU1ГhBȑ>OMF:% ?akXY)]_m>A9lp9zY̾)B xK 0 D>XJSRG5Y yD\8יR8 &$<{7cIDesGm" b R.vmOUC5(rVyԦ V>r xA @=JIwfmix{M6tU<&#;Sʥ2Б->@DB39P)H,1Ιt{x7ן7&BLpLi۶&/=ϣuY A>U`> x1 {^q}@(9#l| [; 5H]̮&k5f2{b\_;UC"VKƱ\%c@ɬCD6|ik0h631e[WjXD#zN/Y=% xK 1D9EݤxL$foo XţU!QR%dcTr9ZeH @*x10 ;K68K?PpmS#喓N`]6Ő#R=e]rYыά\eQC۰ukEܒJǧ$p,{5&y7^ .y-ph7h幖&ךX|$F> x=n1@ާk@H*RrV2PnHכ*Tr1qB.HWQ4T j1jvp\lȜ`Z<-րEB1mkpي68{r SDٿl2onmާyU_uVZi~t@^ x= A @~N&?N MEYfGao^Mԗks4FIb)!|ehÑ],ٱJV%&OjZEl݁_)P{5,̵uxk[u:p?@ xK @sދ0 r':=L;oo 6'>%bK,vlub`sL9Z]Єh3Dl]φUȣ6x}j. ?m-ަSe$%T` hzϵɞ"78]/ 'Ag xA 0E9EHfL&\ 3ElKR/߼[5EJĎ}d $J1FX,zRQW;dm3p!dF"G8}gkֹH=<ʸSmG{p!@x1N0D{b{kFBt܀k]CSkFzC00R0U]Z `ed6 lĖ BW9,޵$^ZhIj!!9CS?{gWp.'#&xWL۶?fL* ڮ>uv?V.ۯԩ>h?><sJx10 E;$@\TiR nO/oyOS<I#W) GoSX,ܴvg"-pe+,DE|9TB)NLΩET79賛/YI;Йx;n0{b4I /`$z1"@.i`l^c|#,).::"}p;lFdHRP}eMRy[r㛝GW zXjʅ^'r6?R'g޾J#YsN6x}VmW6_G\x1n0 {}>I6+EQs8ɐ~@)U!Ğy )G\|@ )!]M vӆmcRt K`me%;x 0F硿=+ B ?>z5F} x; {N}3 E ,,.rX) f@?tJNWkLFc\ї)q%Hjσjй@%rFt&S9pTW??@LH:p)۶Wu%  pkeiOg#Yz;@i@ x10 @=ΒH-"ht q?11Š I d$]B&ɚb^u-bˍi! `x0:hIul!k4sFYUnt5u`;qJc$"?ATimICc!\<叩k. 'Xp- eGeyB< WCd x1 @ѝSx W$E}#_PۂSU2T}Jhdwąy$E(` KX 4M^>Ƽwx}?'nȾ5G<¹6=In|c;ߑ x10 ;K֖ql*hSE喻aTqA.ʦ\09g%)e5|렣:!+'%D9%vb9S)џS~0Ќq"Ou]z?p& z1?/u=-AKxn0 C wXNHGx၏i]7iM"EC&)ѓ,ֹk5y)KI~ I|fe5*;/Z~~c? ʸoɦ~J7x;n0D{b4Dre$02?:BlQEnoL3<`|3D cr#˜H2d"XpbrXi!by! Y37i!ȇD6\%]mW! X "|=A6?*)xR]}7wߛ n OkHxKn DwY F.ɐ`v$~M-ꕪ1fXf& 2:0&OhggXq)hs$lZLiC^SU ntnKaݶ,@չS>@*~>wC]>|+`-_`_9[\׊/{{7C8Cd \⥞ _ x10 ;KR7q*!$F6TPRtTrj)r8In/I Y)ɣ/^@Ph1>XRH,!rt]t{]j+>A<&<:SkEB|G>VxA 0E9Ŭu34q#nTDtTf ZB9i5.FSX$v^cAs!2'iSrk c-R^Ycg\a6ӆ`T?Rs v<+C/GaIP!I73*B x10 E;&wIhS[@*dqf\3 <29t48 l˪uɈ.%00u5"fIџbt:>Hw6@' yW,?x90 {}єm bG`E~fY`u3ņTلZa_ZjPÃ7[*{A(qV4XEJ Um˯HbS|':c4)M8=ar)?㺄s/F]x;N@9Eǐ"AZi@\`v,%i'7\Ke-dbV(`.Rٍ4ԌK!jqd+ :|Lf qG&prr& [aȧQCk!r15}E^9Jv Nv}ns , ݁b6_@ x; 1@bzę|D DݍXx{yx80qVT]V!Qˌ9'w]Xe =K=dIh+P ǭuhGp.E>0-<ч^ym2_ˆ:h x |w/Kml {e36UCS`!{pL-jO;ÒT K! ^uA;qk?Mu}&Zņkk{غnx/):x1n0 w{2L ZZ(r>FN7zsM~EYҌ*D0ǁDc!L< R)>>F5ĬAU|y?h$ 1mK44ꏃٴ+eu(n0j7P30_SR_ oE xI0 y晴4ql"*=H|ePX3Gc󌉴FUNg*9<1T'7RST"Nb%KɩA^x\~QH N%辮w# mkbߤ}. "= x90{b{_CBem#H|ii`!&[ WOl}$FIhs" 6S&:=%'u<>70&EΣ>Q:'*j o\ʱn d孾V=Ix 0D{I$ ^=X{MH[)\dH9td>ythc3d!VO20Hl+$doA0Sѣꭢ KgIa=QqUq2%hj`zݽ=w,(v=+䣾`HG x[ 0E'/ Z[p^8840۔da\S RmG! KzK3{uR9JV}rKȳk4:|&Gxpt;=, |:}@B]fmMCxK @bv]t3&3PzDҘӷ m^+"ʈ֎Q"[6;59\dErG&$cobucdiZ۽(>ڼX^[8= Y8uM GN9S;M`Z%WeE^P[ ehRv%lI x 1E|63q$3{́{z,V'BcJ) 㼤@ըdl%!]Z+sf8Y⧿4 D`&B8@mYj"0^xxwݟ8ˍGaV_BAxNn0 +t\K/`ؿ[V`?0@ iӒoW#R2(.UKH t+8Yf.`!9.[zu|6o&_.Li?*CVA]IJqR֋I)_} h:q_iS. x 1|Ez<;nP{84"}' Ll $JHLZT5 h)Ƈ0v&G z~|f?mӺwfCyZ*2ޒ*}̥iLT_B xK 1D9EݤwLw0L$ހ6,8 -.c-^לOFrKhzѐcI9:%j-\d(!)z{toֲw!E/{S*bm0;Gl'mT_]AmxAn @=U7MիplfP30"N޾z|"#6s*).-Jacsl<˔r&bkɮPAޕȑɢ)DŽ2@L!ofGS|rQayyn yovںMzC{Syy5?زHxN {x(M`{ӲK4PzNfja\(D<է꧁3/T83*c| zl1tux|6o`m2\sn뺨WsTekk?LK/MP?= x1 FSw #UԪJ!2 -oFZk,Ք8GiK!fNn׎s!m਄ɫ6;Lc22;5!xhƢU8R|T}cwav˱*m+?*\WOki.P3&}]/@k`Zr.J]w#UH++ yhza׵wHz x 0D4i bAQʽUm#%{ a8G"ɁFF{% 恆 p`!sHY+斖R{(MY(k")?ȟiW\g/b ۜ+~k<'~q%lյ٭ۺj̾U?ȑ x;0{=M6ؑwYU"A)r{L3*H%"]̸UPk)+%Bș^I9۸U<6E(ǐnzNl2?Ruzl>? xK 19Eo\#wI;N3/Ԧ(" &l!k8MX0 FErebtSe4%ْ(5٫i:Vu."\u򇪶 6&Psql? xK0 9l4FBŵA¢mfFWh3㜖TS9Y2%#f^Ե0I${'b9M"glh?ϗs)[=g} #5ƸxZ} = xM )*x_Op6 @k#%R$3 UO8:G,䜸J& 2U)T|&6oSEe6I'_O' y$7zrʃŒ?RQ@kn}c9k~afmgkzO9xDvl뺨pkhb}˛-Xy? x 1sW.,$`Ifx"JUJ$@ Qm\3 eƒ<(%l`8R*]$ʓ/cgtID!hA6ua?RQz.G6673r_8dWAқ xK 1D9EEHOf ^ GB/`mբ .`)Y1{ABVlDN1 ̓nz!s,XmJُV x|v_1h=l}]ZԐ4]/Eߺ&5mC xA0 yE\긩 q$EJQq={=HkFnIU (qS0ga^UFDSH[ː1a v[7,?R @eՕ"vyl~eH> xK 1D9EEH: ޥ 3^z5*ߊ DQ4Dlhr$&͓nژCQrd9SmIny.:8/NS.siKǗ7.}2t;C xA @=!1^^`!Sjx{xo"2aI4Q BGBz Ũܥ s\s1 aL~Kڕxep ЄfएTֵ!P esF2 [{/o? x 0ܽ4l7ꡈE{"}Sop.s&'M( 1r̮B:0c/1BLY'*'(H }dhšsүmfII rP~!g#UYXexqLΒﷺYZ6> x1 w^ŀql_L0*jT}#冻9|)b h*XsTcEJ酓dPBi@3҂R4=Krc6s ض>V6 x; 0{b4Z!wgEL%u!k$"u1{mRCRbHobI25Oh]\J Zm)tOx{ L 7yM3sĴ]<ӱF _,Ax; 0D{b4߆H.E.V[BZ}LrL37܈ eo0ATGcds~2N *6vpFV#2lgK]5ve8#bٶ&dJ3k+ܟ\bP˲?_йF]|F xA @=( &`A4.z{M6t@oυIXsSbʬ1{re@KLA'J)8]Y'!H+ǣuxH CJ{؅"#x[ UB)&DezI9KHqq; & UJdJ^'B8~٣x~`?pk3?RwmoG۬mwXX"; xA ! E"nPz hBo__yy@C̶D-X0bf\*l 5j^|HPUsH4iz%f dq3pQ5SǾos֤[z[ύ'mtb=9 x9 0{b4W1Q>| L302a s5gmqR 1a3Ԝ:]Xt/;4 3XT9N<I>E'm[ET"&8F.ohᝦHvU־ CBx;K1 jI6pw%-.^fof!$\% :aRI(hK1JIƄٓ#e)숄Zh)!xflp rCl۶2Zbɐ8 {2}|Zk/VKkRKg?Yyxj0D"%ZKIZi-EN\<7?X.&?Ǩ!ys)Iω,9  >LFS5\!F-F\{?TӰ'23J(ZUо!y,kkM_RJo x; 0 @wBK.-wQd1%I1.4o㍮ $ ENJe>Uɻs7$ x] 0s}%I ]--V20LWl2Jr(j( vGVm\#+N ^R>'d1qCHb]?߈9]쉩.(Aug(H<E3_B?' xʽ 0@=Oqw$ urp*7XlRSзW<˷23ӔDtCصJzń3X\1^YTNhn%2y \=xg6?T0[<70tH݋ cv}n|@ZX<>BS x;0D{b{? Qqۻ J9Nf7ozcMr92xiYiYgŚ/2L`09j25Bk-&㵢l"UJ(л,E;1 ʉa׵>-#ܗ}~8m ӃM#C> x;0D{b{׶踁]C )r{ӼbLòATRdUIWl4R0x>g>jڹj]R-(Y?c%npJ1F8Qyz?T.|Ǵ5ӍM?? x90{b{k[B4葳^C#){L33\hS¢ a \SQ$I;5;V:IMڑES8K4'I"mϑ ^[` ct>N~TiHEʙ3܎i^ ?;r>h(L}P%A xA @ѽpߍN2BU34$E"o.bkN4\1_3wE21):*U&眚v*}X(v9gJ;u \T˲ɹ/m`;S x 1D|6&ˁX b}l6(rwcqopx3L"`0d<%LS PJ1, Nl|HBMq$YU|ZᱭY*~cHNw)^ޚQU1g"ͥ_]e{iP}@ xK 0@9EnLL@\ Ni4.z{ ^yj srgmV(@BE :l1#`1E0.ǐ5ދO}E'm-\ހ(.͵cg'7 xʽ 0@=O%iA\P{7"mJL/YJ!{Ғ^Q9T$f e E s֢Hp.R#0ܶmQ?R˵箲!Xr>xM 0 +|N_0+qZ6%I H:HB%@Giw;06MķFd+VFQǀ+igزZQuE/ _1uPu)E$kpO;K&E0B q߼?2GKD{-.)D!G\5wYR'ge$D_kHJF5yVpE !쾷5e\5ڞ0+lK[hynopϽi>>q xI 1yE߽d_@Ko3#!~*HJj5w-بId, y}A "ѩШ{Ur3|19D'\s5l-p'mkX" >9txj {_(kF顯rpuH :73 VԤmJ}gT5zmHo)XI&,;^j/E aѭEczϸIR _]Wx'afUpjv*Ir x10 E;R'wqmGTЦi_ _,BXvn:Z ʎ7Z44lwV53J]7Nu9$f2V"\Ȟ h۱fPJ˶V4EiShwsWH;0>dfF/8JD{ '<-+[{@.TQxП?5B`xNAj1s/״r̭? Y]/I C=H I3,8/R)d]&ر   ]WLKxrA`^|X;1', eUi|Y +dV;i~=P7n=xTxAK0.HҤMÊPjQO%{q)iފxw.sfb )ِ1әQ:嘓beZ#0 h9*%r.3NZٜ)-}G py!sHJ1FG5 4 !؏泏ׅ338s/RXoNuwa{wF} >o=[ x1 EwNὋ c]5jS"D޾D@FWHYTqF_5fB,SkEsʎ@*"EŤO[76R^(Li'{lOО (0_= x;!@{NAoxf"5 o&^׼5Um0t Q`Tmm|m6̖xNN0wc@BvG"$ت{u(7=;g9yr"uGZ@jt@ҵh#;l]֦^hԪJ{gɴm+15/ eZxUybXDsܨL)L˙ ne2)R;J ^;_NGdc\/=x\b xj0zTZɖiɫ2䞹|2fԚ3uǁìx`Qqi&/N(eI {Ϛ?0>< U53lk,֟+o;$<*[7n۫SN;HUkLGx] =ž(*Ic07<0Mo@L!z%IGS1$ "XcCl|0,zCf,>1ce8U?PEw4{:=x D~^Q(JBJ,"`E>ȐBPihlwd#GGz1t+J24^pG6+G*0J[=a!Bk>)Bݗifs]; ɝ2'h%JAHNx D~J|DP+ǕH  ;Y9LoD ,d}2JPB  bluJ!$kƦ( \O*Zj uYrǔ5ZA5O\Nq著+mr&IxKj0:EI/\%[ 6 P}`.hpcmsiahB{{wAĥ&۳XLt1OrT͞}TLL1d;6q`Z1At<_JOx0{8Z)Hxjh#>BP0ON133$A0qSO&2HTURaX#|P[ܯV֧XN5"z[M4=ϰ/\QiNx͙HU"bioں=7]<ԛ]帍q y1e  E x=!@SÐYwCk|׼5U=LPY-Hи $T$b ;CS0֊R 4RT*!~>Ny1RF)om{/ކ/9A x=0 @=bבwIjG (Tۃx˷9TeRTsʚISȩqV>'TASF1:rVrM9 )887uͩض>D8 xK @b8~wuBI @{z<"8m&K"k m13>Ij.Jbhir)xM&9 hˌiG^9ӊt&nB嶮u #Uu\ ^pP_<ٚ x1 w^ T/D }#喻9|^El52HAJ0,J95u L׮+!*!bEKwr6Ԇ2µm]_s;viϯ5Ԛ x10 E;Kv"! TJ:p{"qZKJ( o%elif)$>;("*jhJyt6NsL뺨!fam>`>a x 1|Ez[; AⰑ XN3*ً8`# r)e`*K3@c:DJ$G୳IѻKՏOazN[h;ޘ5yέ"fa͒[.Kuq9o0·^}(?Ox10 ;iW $F6T@SnΪ*x y'HArDM̞2 Tu2[@q^RH(Omg[rڭThGh]ӆ>p\LXl+A^'Lht9\{ͺ7TI x; @wNK1]6 jT }#}[BHh"S,$u悚1ٛw@M-mqE]^XkXspynӅ)1G[Ƣij[c:e xA Ebn:&1:m1H^/߼?*RYq*)9|x0u0sv yIlUQgN&:M FOpߙkC$/nWhZ]mu> x10 ;K4q-!$F6ĮP)JӁSp7rAII3j$_JRHLA[:$ʐTS%3 |*WRG6x~V_/8䀈NuYՉ)Ȯs/78 x10 @=*9i.NT=H\[WA^!X(J̬Hcrtw y )Ǥ1L V$YD;\gp x= 1@>HôX"d2E,1^ y1\\H`ɲHu1{偼E`G#0dh.2 KJ^_kwFj .h Wꛠ:S*0grle*x؟G=AxA 0E9$LB7H2S V)kX0(.:gx -Ohɢ c>,!F%!N켗2XJ"[ %qEo^o3 ovfm+$D'$*ZeFGfu`}j.\3O1X,%1cE9׻w}w.)雹j۶uN#UHĤyO-츏 cmPHBfx1n0 w{I,( d D1j[ } pi8K&uY7O:A]͈19T%%O/-\Knzo~^?cDx'}_Uy>T*mm Cly1v-z9m7ثJTxOj0 nq|c8 Y"(8%o_ df'ᖈldԋH^zl6̼裫g}gM-n{ĝ74xY3 /$B@վ$T+= [ga96zUjOx(iAھp3 7:u^~܅~oYVNxA b ?Q?eبz6e.U0mM< dy&SFUk̔b!ʠ>RB![ VG ןo`Lt֣N@~/7. 1ֶڡIkKYP*/+յDxKn0 D:c %QhAn_@g3ü&Mk,csƘ){t.52)ǚj6!krƺP,%j;+1|ii=JM1UL{&8xnxUj'8&.t8Gg-_2Kb6Px; {Nzߌ]ЌDB^/6 "C%N68[ gdehp`hxQ)\dĨr^1}\Uk,D굮s9 2g<ǚ~6Hq};Hx;0D{b{  !QR |DG)=ek88D۳ggyi@Dr11M2$Fxq\N6W¨Y[ >}*u[Xmne?-_OڴLTi㲪/AG< x1 w^ ``_6jT%D@r:FSžK.Hb { iѨ,ltl qS c̈4w8Ixwmpŀf/L۶&hiGmy||&z>՝ x1 w^ A5j!o~rÍ.!j)kPƠS)Lntz-q2AM2aBvQ"Gx. hd/T۶!߶o\VuT 8rVB| xʻ 0FSܞƯ!!f@"N"cl p9sւYZl'o&h̜B,Uܱ6٤ Zb_Rɞ x;0 @;|H#"h0p{*q0+bS!O&Հܘd&](k 1 'R"MiA|4;|U#'y?<>ڀ7c>3O\=i}vy/7ѕx!0E}NӴt30H6Lيޞ2,<: Zk%"-uT\@jc q<$B]@l&yD=g* G׮yhcv%8Np_*/`-awfunGj"0\G(V'G'A+:/*/?JxNJ0+K6mE]zT^[&KZv 3̘JAJЁVBU%2S"P`Բ΄EŶJsPy!SQZbQy) )pH>FG4h`K` Miݛ4}y<=77tw ~2&Iw 8{fDޫ=.w-exA b{aXZ_0V,+`XQ~KTr;+)gL0ѹlH LbQ"/ana&)3\ŒON :S}bWLiTE TOZZtku6q=ZcSEHxIn!E}gPРDJ#Ӏd o6v"=r4: &Z!vkA/., R[s4Tn ab%g(ͭynכA >k[[]>W+fe#+YaurWیv~ +n\]Lz]3/X x 0@|Ev{4td- .B5p_> x90{=:)!ٻkAb0~O$>43HgŇ\!epXaq!_RuzΫhrlȅ @1xgȖ=SA7oF6&pQ@a[YXU&b(95yG붢mU_Cx=!SLo? 0; ok{Fc &z&ZOgI9bˀ(  L9IQK;"oR:1.Ugn^+jM=Џ]!8O@Xf(bkm:k ,E@x;NC1ޫϹP \ElGݓ pOGH b(f*X8gҒCQT,֚ a'؊.?ʀ?)'ZVO_z<3I)(#&kaWd7+G{_GT3R{j6R/`N& xA 1 E=EnIҴ %N)u1|σ=VWc4 TI\c *T+d(șs$IZDYa3 8z|ybJe&dض6q mo+Yni4xA Ebn@Jh3QiLoooy_:0go02Yd8-MwԊ9]bt#%CHQ&ᱷB1a'}Dz-"Ua)T@:ֱ.0hUM";VvHhIX x 0F:"D^6&|JY%s)&6;;E9 t0Y/(Y<^;|5c?^+˭0X h9(zG`HLnH˳\&vf? Wt6tYxK Dn'@w1`Ԩj@,rF:=id0N9د^|6T-jg]bq] L!)J:eg:[_?@ep+*{?TEp>49;Cd>{_ǞG x10 ;8i#!ԮMtҍfDKY1GƉe@DiP4-%,$fc.q#񌜝^<^Ux?sHRm cuj ޏt};{> xK 0 >⏜XPzb[ 1%IqEoߔ^o3c5E";e2eU(> r*%X'GVG2X1L>t:<Kۏwp.a,"Ş3u[*\ ]{+ hݯ3䕿`*g1ց?y x 0|Ev$MRq,T^0H q-r,1FSF8p_X+oMj)-=tV;iN)<nRS<|;<e]skG*"|>&Sre_>= x10 @=ȒԉJ8#*tT/ot3`Oj•jF&+Z^m"܈( J1Sͨgə%x];P"ǀpgNu]ư?i{7pQkfjo<6 xK 0@9g$ $3Zq-xm] 1s_EI\L7Ԑ4yۀzclYGIZ*C:RsMyy?O\@ŞuCHMQC-|c; xK B1 =EĻiyVj]x{/lf3*Pk BOQQb#s穷"41jnCrz5dQKkt3XK't?~YKH xA Eb8:1J8# % y?*DXO>L9sų+vBfO]E$^$v!sdIxvH85۶cI"*68w}C~5շ}@= x90{b{$D7lD%'0L3cCkl _0Ji6d-Y$Ge˔dlZ*HL*c+ߝe@ EpcCXUb&/m^ XzO= x;0 @;K~NR 1!EQ:p{*q7*%!Xd[-ֹŦPBhuJʎ$pLO^=eRSh>[gpek>ۯ@u^E LJ"<,vp=NظrҠXǐU_S}W!UVdXj x90{b{oK@6޵1'`iE@LLgGB&&K99zj.Z(R%h&r+F/ S [秱t8|0jN@GZR;oJ|ߘ/@ޓx 0E~]4iQp[Zjq[wr9S @.vր[8t^`:ȮZ 7!yrZ) PQ ^6 e%|:B{:~DZc51A4e{[ G~Lu_3)tG|ZEu xA! @=`R 1ޥgB 7o4HS,*)U1+Fe"C;^렆Q &s]mϛ(H oXXy,Sg5d x1 1b{[r dIWN3Ӫ 1$,~dŘBo~PZ2-g(2r)&D=M鳝 5 ʒ2 ,/.tnH]i~YpZ>~> ={ x1 1EbzLM l!v^`6Eו o5d=Jaʜc,",`bK*\SvAS9}n)" 3nץ(*msvw'u,|k FTtt@*t}tOG<xJ1DE=q/([Irf{[kSsd4qr!9LՈzu 5rIGhBcH!Xf؛s;:m3Y{w9AtdɚFQo"ji+[^w?czK2| z}~}G~!oQ x 1E|6yd"b'h/]#! 9p8M$ uRR%m='JMl!cS!B5ˈ."GΫ.zV?3ZNQ]w#UY.z>5ќ?=w x10 @=ȎjIc qǮZ-JӁۃ[~of^)W΁S) TD0E*u@M03&!Fv5y)O7WsXݲǡ{ojӲ~;:f x 0F<i~I(8ũ$77TFt~ˁj!ENA9F"LkB+eBD(As x+}VJHۙN#8x-wRi`lc^+2#E% e?AͰ9_N]ƮA& x10 @=΂Ď%]VQ: q?{t&IPkF*@(½A(=:-6厦j|l#|{( ,9[m]sk8v-|͏5 x!D{b{ \K)f&35pPֈ bzl&Ԟ:c3GM##s&Fl W@ 8|NzһUY(+C^ yLEvRUz^ pC:xKj0@:쳑d}, `4S5&o@/зytcl)L!->zDL)΄k.S.S1x(` 1Qɮ-ʄM5ʾq.~Cop]Ŗ'Ɛ] pj]];ag>k?Lj~J x1!FSLo3;.Dk[x{M7@^4T2ZR뼗,my>)#JA^}ڢQX%sޏAQ1F֮VOto{]7u x @mv "XڈnHL8/opi[QP " %ՠI(kNnf1ZiDfSęIa.s4]!%u:& x;0 @;K>nH8#*HSES 𖷼͡ V)$$"/DXPU]>m]bAC 51a(ERMb$D"/kǧ|>ep'{kۜGjHD[;%[Ӝ>q x1 {^Aź(C"E~oK@fif3Z$ WK-!23}PH*i4Kp$'|nÿ[> x,cUS8wfغ/f<=l x; 1>HoI&/2;Yl5ްwP 'V(asZBJ `$,jC#MH>ן7РX%|s<Z*7xP=k0+nP?R :tEl)HIpC{z@R)&2Ӳe5 j:ӺH2tMwUF*JUˢ!u! wY3iq<<^'B Yʼ>'Qn 3֤A hh9`1<$bx>^m{|>^ t[A6̞bݲœeᨎ Qw ^(y)h1 DKhǫVI2ޓqCRnh;O@to 0:"x10!jt!ZN~ҽןxA0E=En:!1^L@jJ1r{5l\6?y" Qcxvv^l +IBDrN=ZwQ1}v$r4hAq^V#UD5 =Wz"K~MɃKzxA 0E9dbDo )az{q`3Ҵ#u=fClu.FGCpB*jwƠzUھ"T%"&8z&oXCl|T>a9kշ6D2 xK 09 ]ymj"ނp6љA*L*6ŨKf\ -HRyّbu@5 YF}!}6FeZc[ǧpR#rp۲c:6^ 8xr< x1 w^#UF!o~ MP)E$Xb!#&^d jvY6w =WJ-b=]噳֘JӾ!: JB{sm{؅.6ۑ x1 1@>^L& –6"x$3Ew#k,7}4C5죥MH:ONzU8E6ْ ipX\4\(PTկmۻĀ|t6*mU%fa-,\`<P= x1 1@>^$͂[ڈ ̬Fb,7BI 4@DC ^, 8#5];3{}5K1z!Dl`MzkmpW{ 9aLr]XMQ|Z L|BP:N x10 =iH+S4B=o7UP%1ĜI=u2I1.!DVQcP]""΍*(&goSE=b88}{?!u-\^8_/RhїA)? x1 w^ὋM Rտ6*jT}#喓n3(HQgX9J&WOu[ś!+$AȚ,y?<>ڀ7 :O#\cGgOȪ 296zxN0F<ݡRl7KgCw?׉#6oOr %\ ? GDFLX^)!Y,b&K:l'5AZs [Yט MVtϛ sI\߷a<N5=x10 E;Ku+!v&8P6UܞJ\/?:+׈EP)z.64S'pDa4PumGmh,,ҴZ=x9 {^}pIQ#`uR>i O"PUg R_1dCCd.(43T\4伌2Z`$˘~F Z7y!pl[c?RJpӶzv6/ck] E?VzMn սF7>xMj1 >Š4ewC38޾ @xz!itU,KU e(%2yTJLm KIUsf2 F# E;ޟi8!ru߶u }aԱ \'Xybls%W国L" x10 E;K7q#!$ \]P[oUեBdIGF <2yrչ,G9 Q(ch Y'6[x wu4Qt\ޚQrRes:7>T x;n1{om( yEnQ.iCVT1Y$Tp uCۄJuٓŐ,Oչ%GbUCQˋ}^Op Fc}c?9Aw`vh}os>zB x 0@|.4k@n UbrA)%ġo-oyZD [3eg\C"VM%E͡ȻBѐ8ݰ6( >§>2%)yF 4ZT$ 2 ])=N x=0 @=wqjE0T-""/`5GDlH\J5!mjB`s)'19@K>=}և~e7mLLlp/p9j;yo^6juoC}nmRYEЀzu xL҂C* xuHUE[dXH^9קwyMઌɋ:"rm Pl{w!~ znYZ_uEC x 0@|Ev1RsEjxN^*A@libj T&xQ`g rކSIIXiJ }*|[V,ī<|Zȝ=g#@$acWW.v}Ī6_A? x 1|n{y"vmNE+{b)9%`l kajS;[nzD9uqP!Z6Uua뼶Zš\ w/))h+? x10 ;44 C8*B%U0p-wUAP1G ©'R@}E۸`)y 8aci =r 9` eKp?h|~qf6-` V6Y`>ilL:â}?B x;1 "=%]B"o' 0kNqMQo\@sNy>2A"B 7j/\BwS}i_`ۛEL)'{ic۞j q#5/ xA 0y޽$&[l iSbD?\2Lo" DX 2ؠR9LNmdz}ʖF$B(%;ů~  !8̽a^a7L]b=2x1n SLƳ(Wl]cቢ>.OOؚpMT#sYEgS ?MWQ*.|!skR xA! @= 0L .--ј b^/߼͟ B}8SZ9j$%H¶0ReDŽx]Ik(&GZ!%_܏6!aH$8omiUMaoG}=7;x=N0FbzڱEH&1Hd' ׼T# 9Nx.)[3♦ihpS`F`fW܉7>\)фuYO`Lx<<ZU 4K ]k:3_ހzSVخLTY-%+] LWh x;0D{b{Y$D7g-,Hl9'`?r6J1[iCJIKL&pPX|e^;(Ę?X T1GDοhRX8=,y.c"( ,U2֭;@xJ0}ٹ$ikrE u/9ڤ$oo/0g82l a磩mQ,5ZZ-EELaV`꺇 u-GU5O!,"=G\\tJU&̳Vz%)DZ&DPJ (4_ӑɴo2i8L&XDs.`Qa=\q&uYBc˅]M0/! z^R bo x1!E{N10 ,lbLz`HtXx{Iy{UfPt䠃Qd䕱$@`M:c*%/{S¿ۭT q@vD8FX%"eO-\p7%V8Y^1/AX x90{=H8]PHd9'`)f0j*0eG2.9 9q-ao3`)PٰWMY D2Jg^B;cF|2 3K: }[]4 _F4ۜ x 0Dw4[7 WuԄހ?lZ@ҬiQ#CT ,B D$ZbTB1TI }6ZPbBVCe=G2. qw*.r\%Axj0D{}iNHHH.֮8e]#dhrytih-&u   ٨˪ijJ`DS)SaQ0::|?K?2-KUT UToyޮގe= y,Am}c<%IR֖ x9 0{bб /Jm)¿!4 Ã0[O\MB g HbZ|ҠP]Q2)0PQb,PB֘BE;H<~~R#^[S߶Hi;A|'1 HB/ ?2 x;1 =M9 8-Z,f!`m!llVmZ U梸DICe%CuyզH%d9j5}ݛ 8xrB)F8}?TCI3l2av-}V=xNN0Q8҉?@"#g_O8D4<4ҙDDC³IuLbtۘgsT+v9D)04y̔pkw3`EmY#J-Rp._ reVcBCnJYN'E67N{}y p ?f7СZx[j1 E IJdYNq@=4:3HԌs5{T>9%d)"I8Ď9J1Kmôh6Y-$5dK>Zr/޸A2WqaxˡOV a-t3%ATtmB }~4AQ} x9 @ўSЧ1#E`g3&EnH@~?'Nр 8 b#KlSmhaO92U! a4dTzu}"]^1F :*^ӶȡG-1/2C6&.? xI 1yE߽d_@22=W֥((D`S vEJ5aSXp̀"&IG&rд*E+pKp{J?@ࣉ69cb?V-Vڝ LO8+|vStC* x10 E";Kb#!΀c;R'/oyzyd"ZL0s"sF.9%fս*B0D5[fC@Go??Z/>% w џ˜m];v_G*fG#/u_>=xj0DI% J.IcKu\ o`G4̝Md&vPĝOf>a9qV!cfZT5ۓ;r.؇9z[eU̅o_ BzWm(1aSJ7i}h_O v1K1x1n0 w{Ѳ((bñU(l-r gC|'%/1Xd ERf4e'= p*4؋a)fℒ"aY<>`^LUe[+BևUͶ z>zntHx 0y{OfAɳOt+ acAd%P"Ds(hZ|' RU{˜YZ0(7&jp 4XKĺ,\>0G.otINfhpݗb'E\N0*$ڠ=5ߓ^Ufȁqg_KلƘ9S!q8HyP<)C.14`&.E~\ -H$HA(ft 5a Yk#km\,LhBsϨ+&%8gjJvv4S>zAkқ:3~o":_$+LW$2h/?VXiZmSBJ܎׊%Ox1 {^q]4sHQCbLqQ>mF#MRF];(JxGz&[!69Lc8ΆZ)FFI>&i Xய),:v> pmMC>ฮP7{rI["S}"DϚ xA! @=`0xBK4fdB 7o4TdHu.J!`m.2Β :t :>W+X0~=<,s+R`kyZߠ RAG^c6_E6 xA! @=`h!1ޥgB 7o4)Al:M:eb3Z +Km)(u@.k89}զy\Km՝2u6JxKN0D>EٸI͆ C"fp{"5^Ig2F*M.@ZkN&0e >#ۙDܜCLJCUr V]UcI! mu엵$Yy|շlĚ)9kC^ `ӭ5b QI\MY'GU9+%=,|~$7BДx9n@ }4"ÍHTvS Vv;Ҵ<~M?wvFm/DʙxN1N1(xF.Q$J^܉K|N㈂iFLo"#s>/.Z 8LI{2LHQg&8:CE(d5&Ȟtr5K} ޿kO yCN*y]U (}=<'pmW^aݏ1O t\ޠ7YGN x;0{b{-wX{7J#=fFz)"Kْ+|fXM$NDBys׀H%.eo' ^):GpfL]D9S۶-cC?Px.k|~tٛ/{=txM B_bZ  8L2Sv#fv hk= "hCJ6s. @Ęfo< Yѯ?_ϓc4꾯T5LBlt_ (\BR}s^)m-Y}F xK B1 @yW&iq/I!JWpə5 4yRdozܰHRG^r=YM%瘝8E Is]Ƅ{M8<b,Icm-cu}{c689px 0D+MxYl7ZI`ނ?\p%o3.vVqClmzk% ;TFLZ*:EM"B&:hwΉTSO齱k:-50SqI~W21}R 9{;=+peG }Jʚ x= 1>Ho3xI l<-U%Ls)\BA|`Ldx-j :߻b7\*>^oc-Ay,6RxA0 E>V(lG6D{Gi<΢@/пyx q&L&-Nc&cJ^mٳCQ< 5eCKC@ɕkkUkp~9"9Yw uxs }y `ڗ_=۠CџxNN0+掄覉@\8rA[~`8.SH=E;ؒ-1xv5C6]\#Rmܰ*-i1JԆ!V{GFnr8R+("e.#YrmHcA)ZK]$ S)(uBBN ïy.:C RpL۶Ω~;>n?. jӬuYgz0Vw/Ci xA 0 ~XPVH)ie`XNę*k8s $Pv6h+\cPXffƌ!5Öm׹u\/S-\sm[ק:[J7v xK  H/'-i: fFgs!*)lp(4 m:Ĥ,!C3yQ!"abKȂfpRN^S <k cZ `Ǜac_ h=xj0P= B@+lBj# \F*38IDTI&mc kOTO}G>8K)[J %60 X0kJs}&; Ѣ|N"Tm %a$#۲UCJݲ(0E x;0EޫpO3c? YA($2NAb4w,1%{x(ZBε(9d9mRyܺ++"t3ru^,s>ed/ʹ}su@Ԟ|-9xKn0 D:вC܅")$(b2]\ 3ټ U(gTpCk[hzYCRACw&\0| u͌#rG WG.:7Xf{Ml>pq>fHD8WiՕUQyqӣuͱ`96kcD4%ᘑs߷)X@V>}/֓9t x @Em.ZٝZ.r 6L 3+4v01Q(PŊ*G\d*D)SX\6l੄MVGEl,{՚&۸HwB<e9[ ̳`rZǻ&)!ofizWflضv">x 0y{I&A oM6HHS7 ޝ73 S NBgX3آG5@="1 .IڸRHRGyyC2I :YQǵ&)p ƐGG8&yj?ȼ${(܆XcK\>3GJ{x;0 {i/e$](q K+ +VjkK0]4aҎzƐE朂K^dDɈ8olMHAb 6e<n_A-7.Ә?TUy?\10 mAj|\A_>@F *?~ << עLx;1 =M~c{aEb fFV`-2 gڵL-&F_ciSuW\edEJfHs!HS ZN,+<@s #\3Cuػ>umyGlqSџp; ܖ΀I xA 1 @}OѽiIZid 6UQ6aa5LZ+f-JKucz.)i!&[!0C,EPyߏ.:Շ@yae'ZmNcuU) {Nr:''.pRZ;8;Hk~sj+-a=P3(MLs)H xA 0}N1{7ifx3"m$7|_of@h!1I%/X>ʳ$^#͎$e< *2i%oS\49!3\[{?k׷),;] xK !JBvŒ>B.Ug .Ykc.ѲB)x&1HM}ֆD)n`Lƌl(r2534Z>CyrEϩRٻ&[} 9Jyya yBd xM 0}N1{7KL2*Ҧ~gתhSd-i )NN`ZD8g$HCJ\)ԩ-Y+xlXȭDCkňK Gs靓x;lҜSY"K~Ic=Sܯpl)0; xjG x1 @ѝSwAzRU !z"_^oy'$%Q(&3EQEѼSӽ[i8U̼0e*>.H4kmX9 {ȔmjnR~c\;xON0OI6111ikSr ~/e<;(lV'k Ҩg} Pp a]ʊ8(0ä0sLvtIkɖ ]Q_ibjKOc8DPp;j 3Vv 辧ty{PJ}IwCͭDTLGщoT+ʉ? Yx=0,o"[=Bm4qX>ˮAxks2JKgFQ#k"> (,uW:xyZ eߚn@m{XѾ Cҙ xK!nC4ޥ&c|€|zVEJ%'#eK"Mb OluaBVW*>`Nk0jĤm o&+{[ ;hgC Tњ* }"< mB?279A7xJ1}$\񺂠w{wɐ}{}R*"]R\9S2 cLB]fup^ c&V.93ЦcX:CrqA3ڦ*@maRa:v!W#WYajfo/)s#~܏?MϛE EGey*v_`V>bk X ? xM /j.F&$E_}^÷@Nv.%Ŝ)X`6D,i)bE'L֋_4T+DxOhtAJ`u^MTscSn۸:z1Aa=>BB x90{=Z%_|*# {L33$c"64TՂ$KXzK1%,@(E،\wo<6E T۶j_~ߟA< x 0 {M>Hz P& (rc kכsJQR!kN6fADK`1'BdK! G2x/Nξ C spn9ϗ xM 0F94xzi2A5%M/yzD.̆s x; @wN T.6ITD }#}[ ksrD+Y"X].9k$Xg f%_h'"sI:Dzwx}v\H>2}1ԜPzҕdm3P/f}/=Ab x9 {^}rJQ^ۊ K@)ft"sX;LqS\.uAԬZ3/Qf$Vtux_-K/0G C(n!j](ouYylh!+E> B xA C!C}7J2 -"Bo_K/l d@9ybj< Y3O6R5W[=s HErc^wo2 &LDL~S!{I:R?&Q=3 xK n Rջ8$Q(Y mF^ocer"B$ʬɣ"IjnuUPXʫģ`2 }]8'O3e_ץw#5!U}nʲlI? >q x 1 Dܽ6ɂ/mEuԃop3< ȊqZFzVQ"dY?VܚH+ikjBNXW8ף}w8) #8G5T37.Q8>xn0 Dw}f0C["C'HV(>.p@Gf#(L0ؘcE]mXMC* R)YӠ(C/ut&Pl-JMAHWyJa0޸a#WD睙Hg<:w^fzC[A+/tgZeNE^Eל xA 0E9d&M /֖"/@ xM0F= SC Lh0P^mo !tNig%:x FLskoP,"HR^3op]w>S{:ϥVCUe)(ghkma4RFoIʃD xM 1 @}Op)m ]&U ^6otU ϤѡFBN)V*KI8'7Wsj^r Qr*8:Gr3Z5E;^=a&f~1մ+LXAtn>`m/EZ]B xA "pY_XF[ 8̌.%.NBSL$уX4rR]Iȕ 9Z J.P:(ci]ޭHחZÁm1TuK|ZC]>o< xK 0@9ŀKfgL0HZ-xm],G,\ΖRJ9Hc>9űk2&܄^#RXb]̞W2=kǶfp D"dgG1imV?alO=Pxm5A8d-uQh@ixJ@Fa.3(.&ٺg$n5I,Y<&HXTR9Db҅RC35>`t_o\џFqls@ !mnwG=|.x? xI0 yp$;PA`.s]2ĖC+aL8zyT5 aך J/縶Op ΥB S12k{v6Z|*<ߑ x;0 @;qJ$X+vBQCoO%.{[^oIJ6sF:HCP.{ScqYM1BKp{;h2鏵s[E~=1E1Ӻ,sjXD:[~U,h>d xA! "RJ/J$!xnf4d9#JGU$j )SIK,(^:|1MP!ZdQO3Z)՘nlWsJL \ݷmen<ښn,7 x90{b{qAldL04#}NmET](>h4zm)‚)5'K*)]U3>q?Yt>Q}N#UǞ缷ʖoy/x ɠ^h Qs>ӑ~R^vpst7!, 7jpK 묽Yw_B xAB!Cbnh 0Đ&^%mR"P_ #ِI$zF뗈BdC J6qIh2C'9qe7aEwwgpBqq`LmG i% <3Su.}=ԯA\x;n0D{b4)2I6ĆmQWEno@ ƺ >OJTsE˘"i>ȼKя9D`@cUJNJX%wڹu6ÐC*!L^G~?.KەM~!Ug]~;X*MN xM 0@}N1{A)W)֔4]x{ ^6otd8id)GT)TDQjL)GXD[ĢCExOcpyc tpgu]Ɛ?VE0m.k ˋ =lx=N1@ާ&뿱MRgVɮ#gR kMK$FpIBiRJ֔/7_ݕ)bj13i=kEOJcIS1k'GwΏ2;,K r}lj&X1 |}ЕzY3|M8Dٺ_?Fx;0D{b{'N"!Z*XD|f4Om 99 E؆adM~ C,fR=[SJRHg"D6Y96[mt_kFdmt]83sViiU T (1Jtz*=Gh xA 0yE"dI7DzUGI )!?\2L-2jJ&!z Γ ڨ5[b_U6–;.0#5J6]#y/Z4 ܨ4H㇣,zý۩/<x;j1sC/N1;qu<+-^/) 'lvٸdWSc8gL#t~AK.n8 $֖⚍ɢ/䲎h0D˘;'< DO%³Oq"T, o_ :A;z}Hmcԝwyx:?Md x1 w^F F!o~r5UTdwr>GARrqHf/S?J&̕JU =B4)zih:E'{ SǶ?Rs,m [5' xK!Dw.H44fÀKԫToDâ0-$yApk謔1Ԥ°ghu)r-3Fɣv+H,ga[mD N?A+)8뺖*P8!m8^h%C xA 0 ~ؒb9Pɖi)q}@20aCтIS@L1׌@v~TUsBh.5eT]'|g6LJ10km{iثL 5 x=!@SLo3Bb ?C$ak|<@EJ4Җ*qF>&<ޣh!!2GspSSygU?g x;0 @;k-!.Q.ĶP x[FHz/NS*hYhLE˞PY_&_v)>|Dr. >mki{ӖW"pyG uj`*KBxM0@}O1{C`Jbx^`贱()k|oMyVrf(gfd *kE)2A:E$ŞF1FCA`kD9luUx_=_j򞠾>oq[Z`:ے иviq;9G xK0 @yVqK'خ ݃3>`ZqQJԒD -3bU&6gevpfZpZ b-b`h(>^]m 8TR3 }ۚh x}8A=]@ xA 0yKn ⭠HZVbp.sEHzBt8G"U"`UY19" sP+Mj`͚g,-8y5@L(1ΉhMʅQ|+5iawXyaiբi…L$lT9?"H3_X7w{a ޼R+\. xy}8z?BxA @=1a`(%1nQ/tV.&^y/2 YI84z= Y P O1eKٌh,3a**nro6q# NS-K?VUUj!Np;]r>A34xmں@^H['C x90 {}AABK4bȅ@)ۛ*9"M1-P]]04; Mĉ84z1f.PxS4rwm\h/FL6FJ^aQ= 븽ճϻ~`\vmA x;0 @;]'!.Q.ƎP x[FW%mX}DBR#a49V[b̉&<X D,EY&1yi.?_1zdLi۶fkUmKP= x1 w^Ὃ!RտlTR"CH@ontUJYYR\Q1Cqנkf*cb'ω}:GAhxG4`-9XB j-cMJ.*0s[1Z8KY? xM @=xbHC 6o.1Kh 'Hk KZ0.j]^ $vYJE60A9X:\9 :㣃>SkuCKmoa X1ZenOV_>!x;0 {}iE6 . l2DžiDV*>h0"$4e0הJNu%oSN{?ʀۗw@ 3δezϕmLjRpC`s0(a}|guToB xI 1@}NQ{ARCAD{꤂"m$^ 7o0"ׂa6-z2œSQMYza I"J$T%x giM}&iExKn DЀ;F.|c,`"탔 6oQ2MS"مB,Y#Pb5йNp^6C7F|=y <5HdI{h_-s?>qh5u9|ΐ*'9!՗0R@5P;L x;0 @;KM,!J\I]Oi=oyoxgVCb3FeQlLE2yD"Kյ)ԥ %.0fȻ= 6h7pC #Ş-Ԛi=3Ywyan9ӝ xM 0@}N1{)d&i҂/2h+xۼV͠Hس4Ra?GVH4\mk{qj(4IAϬ&W]QĀN}]-~Bu`= x;1 >HOcNK]Eقۃ5O$eU*e홸7 ;ʴUPY S(P 6+?{?o1oc-cu˲>4J x9 1 {}!db> @f5UHAKUK) Q@Ȟ~-rQ 1d@2Qc=Ǵs4z>ڛ02co/;6x;j0E{ >CV0X$ǐ"mnsp۫dl8y8B$XqzrIě̓ DwN34w49O\,Z?VAu9_Wኾ9pJUZHR xA! @=`ЖxhK4fdB 7o49B&J٤5RD%aE(^wT69Sg3eIB5zj_| /ZC2u6:xJ1},Ib VH2odg֧7jki7|DQYDm1:%e%h ٫#t ل譻6frWvZZҘr44RHk12,:*<%.{`:XSlasCۇ/FhI -Ne!%}[ +-1^iη~g5 xK 0EYEN^^6EҁsGFKcfƦR f!IӅ]:#^AriUY^ MpM#O*r9zx)MTx9Hñ xH7ƛxKj0D:EeiM.2'huI6In1sMAvf' '&HKMlJSs.LjK`}B!LsC믱txX&?G3UBxAj0E:H#ۂ3z$v'} @}А%*gsR$.CbMERsݰ:0AtƚR(i6lt'1^8{ᏹ H]u`'[/r!@n3yusE xK 09ۻ?y ^E^Z)۫xg3`F$G/p$ي'u^*,++C FsU6 ][p?Z/CDNI~=G*hyѱARk +L<_AF7?C x1 0 w{IJ" -%M0ΐ78Fw<_" ״h1!e&U[.IZV)a! 9qAz|[>""$u}؛o ]5Оxj1 D {ZYR(@ϛzfI6^&CsfӪDV)QV 3!X`24a`iKWSe&Y8gf)KFNoX*e QD< ‹rҚr{;OOK;Ҡo0p,'F֚ x10 ";㤩-!Ķ@nn] jr(RV(1kjҚ#B[ՕI9׮6KLiabX |}߶ۜG4 o<6 xM1@}NQT`poUh#v0~om4Uȁ ơלBhRKGžsZ Vw_L ~K]S)@̔ZXzap}TbA/|dnLej; <ٰOo 뺝wBͣ3ʵ<wm֭9ܛ5t_; /?x {b+r`/)] !ibFgDk]r1͚:LK~QvFq6b&'R<.&EW0 EG2ǺBC׀[/矔RJ1m7ւGxAn! Efa Xz*=g(mۗ&7K=E`b rp1%ꓸbw*}YmH5[z5KgxyfԜɰM M`܇JO(1p .==a0Rk_XxKn0 D>-PYHBޅ)H,"CZؓAL6Xۄ\Lk"#u fv3: dGG҈sCW)p{ q}?!LOfZuQ}Sv+gZ@NJՌ;w|m w΋ 5rU8M8-D6XŅ+ rT8#A7jx=!{N1 2 F &^ /x2È Q$Ȓ` Z?^Jdw_97NZeb֡ARh$8t'MU+AKK?Py-'xIJ. xA b^Xa $ƋO06Tm\fz |)d29WHgԔ"K,\L&KA!;gkKC9kI^Pk.d>Oeip L0 N@:SGcm Xp{b=T x;1 >HOcq>.N]Eقۃ5GÔ)C,+ mA 7&QKn dwȴ&!3uDV ;b&aԐO|j_<"WBoc-cu硲LX5bxK @sL' B9@&`no 6)Aĉ)"fР) ŃtB4&0!dX(zlº+/|O}?gRSls?TUHs*h-tXxi?m8G.$nZ}!dB xK 0@92|Ļ3m%Moo 6o.Kl! gN"HH&r#J]mi9 &b\ |m[MGq:<>[ןo΀'l2!x4[>o+sM<%8'=x0C]X/xLC8$B~C٦J7xz7! b9 kwnŦQO%dE"gCFL॔ aY7b̑~|zMfEki&bӻr6IXNV \bߩ$,R|xM @=ZHwӟhk|o@8%avُ$%0 yQBt< NrOb芔s&N][ǻM΅c yf*WL|geZc[*m x G x1 w^ClT/&6jUD }[aCK K)\[Z*D.^3`#YY2A2FH>j_yL }s;viC4x1n0 Ew[,eP.Hjmː}R[MFxQy9Y\YgdU&{)(z#!Yz R>+K^Z{D \.&ݷC֒y6y<+4UrE该e 79 lK*x=ND1 =q^~hXymGBeB' 0L1o0B!EJ[;+XR \P JH[U܍<skF8%o6_1Q)~IˉUOʸ?Šuc1h5/oGO } i p?HxKj1D:EC@ h2Y# 6UFd.ȓz(ŬgF"^́]stWRpQNi)WJ6xuz5~elcH씡xlc?P3 |@`}?IVa xA 1yE^2d_&;Y#! ?`ա.5sPaLq J8$42{czT8Tii%El\W4HR"y?0׋'U KI6'X0.6 x=0 @='u%]J(z{o7YI3)/m a) fevѭhw3aƫ*^Sn%|6FGlH%A-ȶ954 7x1n0{n,R' MG D:;#;VDLy\*HP[d[XɑYɢ(ab> J Eᛎ^4x#Y=h {ɹ}F6z28;}|DmtQ_j{ūw\Y,f[ ؙB=/V鐭xBc\t >—>r*BPx9k{{7P*AݕX +z\)zLS\ў>ЈQ Qb㽃"5Y3Br"+Q!$YW%nprB pC"m[z?VO&(57.,;xZ^?(>aXFx x)|._^iL=8$kuJ?FE^`5y;CQ~۷ y_b}3 S!Vr:~V!2R x1B!{NAo kb/ј17xf2sk""$5xHP*Si[s¢pIhpZDCh1o}ǧ7 {jXdOnaj߶#5[c?^Kuu lx:x xA EbݨьBU8$XJn@̓[D@h(S4 5'YO25Z3zclV'ȁ1Qsm5K70 }Nqݶw#UMwbr>V9&egȲVUyDB xA {/q*eՕ 00ڔj!AT@\]d,#SfX*]aKPA5SDT|t}Z:#6]=s;}ٗh\u3_D>[ xA Ebv.0S/ 0hJC[yy@@<<{NAshǤcGʽkut="nRZkr(rxЊ=Øx1r! ОSK-d| @ c{'o/^񵋀NOVhZdTR&&ILQ]a/a(Ap-.x Z]`%zu4_}İN:$|۶UU5uZ Q~!`\q~~md~n4Lpx;n1 {J/3Ҥ"WY k H3(!qC@۰&rVz$s!N9b=){8 ɱUO}Y|qֆbaLYUƤ)z}o>.< 䵵{_GG xA 0 ~Dnd;PX2 M8} @حEHТYb)x "FC<^A _"[T ybH:O-p)& .]yۖZE@R0;zdpeD xA b^R`MGKl*b(&6e.3\'1HBP 9 gq9JLȳyE\!b#qD;\~)p&Z1ܖ LPCӺ/;xAN0 E=h&M$Ă7cDtQJI 7_~vf`jVJ3y";&iZ;kL%bsEђL혖xk$_'in5:/N`!e~Z*q"pT> >t+޶AB+߹ee@~veƝIduTdx9n0 {}ݢ _YP"@"w@fCTLl3c )ZEk˖h~h(ѥb DYdZ԰2ۂ}}~u/s }.'~ҧ@Wm6DO]nr!G| y͝FxxKj0D:Eﳑ4֏YYmu˒I|rW3k,ʀV04:kwQ+.%8sD7J+Od+&H :lW#wPxm[<۾1輷/&蜞0yq0|ҐK[!5+3}q\x\ƗR x10 @=⤭J;p;vDET!E qߪL0h 18cRn%Cq;W u,2aB3z^3}t|{x ~E Nͥskꪭe z˜ܶ^"-lO-[AxAn0 zd(@ѿ"@Vut/s;պz%$̜ t]pH$8#F$͞f-CKv>j>}b >.g\魭s?TWS8iC6hxfr;@vQ}׽ms>2׾hIڔxJ1yܽL2V]D=xz:Wv62Q7Q0z(2:D+k"vFJ6CT<:#l}H#zʅ_Bh'UN||J@ Ss5u&[1Mi;_v8׳lgZBqٰC߭Iiva? 7] xA bdnb`YZc-߫e.sVE)R6Zb!DMcL]>lIBAK.qZr%#RD:^TXT*\^%I{@tq^FP\skGx (&$9s|"u;:e,w`rG.xKN1D>Eٸb;GD3 P<^FT\Ғ#|Z&+Iex˒C2@Gd)}(r*YCّa QL^9nW_,8i<#"m[Ǡ"βø|_! N~- :JaTskv=~:\Qx;n0{b0_A. &Q.G/i P pbj[Ddk3Bnm@_o9!jF^[1@Q#2'[c'0c!C>_KO\}4qd~imIx10{: ؎XB4T "Fl3hV3Aw1c(ɸ,v31evȤxpX;Lds6qѧPXBr)ĽE]~܃k:>B"@ Np HY`,McTOnmpȬHҜ x0 |wTBl,"'qDE_ fp wD(=!x(B>S\^$qE#wXl1THcgԓ>Z8Q碅1yQUX "2e4p]%Ϧ׭ @ȗxKj0@:ѧ f4$"S|r̓]:[Fl:l&Bǒ 6R!y-%^ (bc"vš'Ypsp;Kt19OTi뺌!oj0}z? .?7KJR'X .aL+x[j0C Crv T? P%?i@8FPDjㆥSŕ0꒓iS&9GUd:` K\{?EwoL'y y4e.O{;J|U_޷cY 7~zg;ATSؘxOIn!f0/=8(4?TIH50tޢ yӆ.9gMAmzDb֛u;JX3z^9 |8C/k-cQ%\wn,4JoW8Κ8g') vJPaۚyd(9glPWXx=n ާ> `'EYb`oH׼qG[զI2I9V)6 BK !dx3&}GZg"N'eNk& vzeWx3KQ% Z ycCJ @O #)2>~v$Je>ۣ Zc>:^" ~5.ד X^b x9! {^A0cDцdftZj,ԥ {,ZyfoK>j 03 tr2X22Ĝpb}edYzЕXڛ0}nKUXͱsSa5x;n0D{b)RA$K &,*t20ҙ[f.hdy:x^K8+;'ܞy"BRT2K"F x3fe$ˎ("Kt&\QY:{o~) {U\YR߶L˱gdI 7xxRovy`FƄBNx<CUڊP["~]qm쌴̴0|@,>J x1 {^A8R(QBc)H5hfU4*53/9j$(E1{L'OD wF*=꽓EL9s}na?>Q2U Ӷu}͉?TsZ&| 5Wx1 1b{wADA@+K6DOU ~ibtTat5b]%3V\Lp̔q17ଝ)H. vB]+kBlvz8$L"y_c8/&KQ?R*/G-OVi:}ރX(&Q.4v^7˃GIxJ1EoL&/XRg!RMW%yyŠ?]9p4f %.^aHCr`,x@.:8X" ȉM"$n':u ԚEjgRkipϿ0+!O3 q\G_sLp:FP xK !iGB GѶ%1 o\ oS*̠ ڝ"I`лg]b6HhG&i|̨neĈW["|xx(eC嵅&Z?RLVpYzҮOAxϱj1^_}\h%t!`  !qID$>YG4<UfI(dqF资ՂdhXݨҀalz6:H{D+q!(Zg(+< !8 'ݣb^sk(%N0jY[^GN|x#_0T&9z'HnuZuFejUʌ?(yDK fÚ xK 19EnL> %" !FoS\ZAhN#^Bk!*Q;^ò/'j@P2_#Xb9{zJHٷ1HyhP{7x;n0D{b4H+R$u pɥ"je@3Hg/b["PVQ>g G#{?tz14|˼<Tkx10 ;K&n#!J^`cW hSWSΪ*'-ze^C8n[lnMD.sɓGmbldA8ZZ*EcJ;.enfGHjY`!> k)wfX]CExKN0D>EB tm&|tMmJvS%qlK%Y.=OS4 Y sţL(؜ Q\jЩccׯ\HX'{mYfU3@}h}|eElFSW3 JfBEsiΡ&jS%2H1XA6>ޱtWUd !4L-!8ۗ,`ee-{:"o;r6Ix;n0 D{}49B7(Y ¢fsNΒ*hsD%jg{8z! wZBg$hhA!V񤍠/lߊNF 2I)sfͱEd9 w!'5l^!$ #p"{v ({Hy^r,0筲V̜~]gzY\OX7hxj0Fw?ݛA]H8`ܧ}~YM୶>c)(/L2™^1JI±Awwxl aWVQ>ГsBaڹ- &/ $uToC"р2Vau.߼%ʰ HTu3NPFXJp>>o>Q x;0D{b{;U"828L3{w2kBb$&)0X\IERF+SGDO/19c"j(z6x~ ~1>hU꾯Lq96I}y/6AP x= !F{O1]4㮮@HtR#y׼tfȜ=12X78L;,;t>$1+aоK9Mč!4g:[:Xk=\qRu?T3b{!U |>׷ hAxj Ը56z R0Ì fl2PBl~v-D3AUXԘ-p.yHtdS>3A63›R*J@:Rލ>vmQ[A6)?lG]gqM xM 1 @}Oѽ %mS;bn\ϖN;. Õ@k )p]'*TPD֘E 6"rrc.:go=b&H@=ꎽiwtr5Wxn D ۃ)T_.j!j:g0Ö]* F18Ԉ>cRvU3H|L)cȯlǖ1/&so> fS (c?Ex\Rhs_U4c8ۘKءw>T$UW~ZG x1!FS .YwCk|׼9Ҩ+(,K$J%JEEC%uqGxM߹)("ҊtZ$!HQas}{7 y!HVe/ͭ=;>g5> x 0Eٻ4m7хt.Hfb.T&zHKJLR)֮0!:ΰɥк0^Y1=gXz_8aT.\EAxg8Kkͩ=aϚ x1!FS0 BbYwCk|׼9ȝcj)l@dƤP%[QwkYVBg$j}{o2f_7g=;&}d7֔x1N1E{bz(lcQP$R$IOڙ#ۜ3ʌE", U!P,HLn e_C5mu x1 w^T/6jUD }#喻9|MQeJl$9+*R$Zp;LȵTd.4.*>j~xD)RoI߶לG]y/x7 x 0DBjADTu_mS fpRDᕗ1jdNZV XiZ+dj# x[ZlJnKQIe-iԅOpa P ]ê!6 Cq%ˌ5ax+„<v?` x1!E{NAo .Ƭ!l W7s!tJUKaajfv mSub@ՒeC(ZK).N؆}o?}gLI K8qm[cuu/B6ȝxj0 y 7FȊSƎE&dlt~v촦Ai!D xTXN\r%Β5,q |ߘRV|CL0= 2dnm OuysqPGeА؛.5]3< A@,ً7(Or! s5} ={C^xAj0E> E%.P Ж}4#,h,u7x"GHC$!-ɷ}LzoW(W8Xa5z!v][cJ 4`:qHv)5Jur |ZhO?7鸗F+|N;;$0Q׺$3_9O;C\s3 \]9! 9xhd}ԄFd`4]9HOc;!%]qBKVQۃ5D;@%NsXP"=O{/!BcamBW .1wxMY:coyYs4 x1n0{Hi# M<- El6"2 sK1DK摭  wYvZC ̜7q-gO]k.hi61n*q5+N JJx dT|6o*ب[:( jB=P x1 0 w{( JX-%u0ΐ7[nt4#'CAxAlLf t覎)-媈8ȼ"9aNµpc<[ﳩx ]oEm^ci8va6Zxj1D{}Ŗ @DH@>`%ad! n\fy3RH>HL1'sBv V Yț+o*,,(*nDJɢeG(T ~{ Li2_.MUQ5\ vH }g(0|~^a8QOT83_W17Nxʽ @)OCF 㰑m\dXyk3U{qI#i#q$3Iε , * )giʈV#+e G˧% N`*o<\䙠mw-. }fj5^Z+ QTχ;DxxMn >œlbN/0Xۗ*lF#}~ZaVzr!8k2,ΒSJ=!Sؠ2*BJo90i2n2)+Y/LfR<|<'PjVHױҾ?ЁQrEds* rG~߸V|_.'+֊k .?rWb\x}JUa44af x1 w^` F-R"D>rݚf>H\@Bʒ )#.`[܋۴r'ci-DrjgT8kzߡ6X .m{eص-Sw5ʗxN1D{푂ϵ!%&QP!w`{_?4#9pfM:@[vHC~Xqf2*:osWlziEl|*>ˈJۿ;|OWrHe'fC2FH\"y J&>w4>*{=<^h Pcx;n0{bKi?+Ul$q 5 07pHY4 \g%%VYCN9듵 )<)Đu{m>_[ABH=3oR{?Th}a;h_З+]ѧEp4?EW x;1 >pOcgw , 0kfvUH52RkZYu ZI)dty ]T1*f$9D;f֭jлa6=xKN0 E] HZ≽8 q!{ %l,Xb,V$M2G y`f7b^=\ϺjրB?~89;^LN8Rbz]733UЮI#.| ߴʁ6ܤkrE+洲I!aPxMj0F:컨dx %7d 4Ķ2!um<.d-OH8L9&S"2-Ø|bv)0Ŋ˘mH`4y'EQSot qL.)m]gUy#5, u+hZϛZ3E%8Zm&}9_8IٖxKn0 D:w]tcE@ѻPҨ[L+$=@`yJ'wI; hs+J0Iv؄l֘B)ޖ9gFDyqY)KyoޞNZ[;ZLuR[*DUDZ# *㣷sŽrx&~3Ż,L"^&ut+jX x90{b{ l8nE.DL3L-"RH4c"C&^1t,b aHj"s[ hMLwVcK>prhϥ볰8|c!hmwTZ)*r=w)<KXKkyAJxN!8"ღd >2=ۭFjOkm3  u( ?ln 4虠xMM Xp/)Bg?[?z}3!É2>Y x;0 @;K|J 0sq*4UHz{*qzSN'G(MI0Sly8ICrӥ :5d"ZOяLm2{m0h8-ףw#5Zk^* n˼rmAx1N0D{b{~aul#DI(^(?1ڿA pbhFOPC0\M҈يi |Nh(̘s6gJ'^@Xw7Q x1 w^Ac;jU"n|@\1X UV)ڰ(n+kblJM8*),D 4>s}j}x3T}^c;a,i6ixJ0}s&q!n. $QۢpM+D`5Z5 I%pGR%J 3ގ|BJٻΐ=Yf0ls.XWRj`et.kll3m:=fr Ln5 6qܰM7_K`Ba:S@l)᥿kݡ^]I x;1 >pO8.&vBKVQ5Du LĈX3W^Ī7KH]s˴Hvj!"jJ]ܥy'z PpyĜ3qM.̵mϵ2u_5xAj0E:Yd B 15Fu)dݿ>|Du1yH>MɆYe0$N6"egLԄN>sqimy 4f Orۃ3u8 s·)88=*."U]M[SE +IR;^k/m W>wR`ˍ'^oXQxAn0C»h&UDMBѿ}AGU<>TjRʺ޴o[Qm~a"\^b>H9tJΘ>qH,op_%1"Y bB]<s|$ᐛTgb)Kܛ5e x] 0s}CR?H/000M"`2eK'C'Q=ʣuz1L(S9+|TXRX8.EeߗTXL}6hp۾r@BA x;0ާpOzXBeDSp{Ӽfpkj Eaa_3HZuf,9Z_[B;sU̅;Qs|[ JQoAm{<["6GxK E[Q(݋bZIz'grщ`NRY{l.rޡ4[J1dE޾S0qђ. 2NMHHQp1oci^GK TJcǠ?T֩t[⟭J_a,tjVEx1n0 wcf-тK -CM[n9"ѓw>mb'6.^|?$ v@ #1v‘ɦHHC{˜f {gS.I*| ,9>eYfUGj-E߮/m.+4;k-D & Iyޫ)ށLT x1 @ѝSw FzF4"CnH@7"b3SU ar6 ъ@23=(tmib&RdKRbdtm #ċkۺ?;v-}P4К xA! Bw/e[&ƿ(qcòp.saE$EdTᄲ`![T9sDRZb# TMV▝\߽ڀg><ouN#u O0;lܠw>A7 x10 @=uK u*%( H=yo 4r/ɧƒ0GY-"=H4{Ig5臑0"v3H?!I²*^@89-:fZ>6AA+iN>ܓ xK 1EyVQsRIW*|^P;ӂWpə9 Uel]*8xh"| 04Mּeոg*S58y^1B❰K͔9jB#D5p 8% xA Ebn $ƻLillAj[|כ*l1S@Bk!/C]q8%$[lm=+Q|Hlt4D{6|3w)<1ܻq5S2퀷\7;> x= 1 ὧ6 .ApOTE>+^ . BHȉT sG^mOl4s+1}cIH'%MXZGk]DŽ{N)dj,?~9Lm뺌!ؙ0ҟK`ٴ7.;V xA EbnHw`HL6ۼU!$Rp,ܜ$_EKkb9%,͵Ԓ fkyilU;~c {Δm]1HZA߲.c:1)<8r/ A x90{b{)!^Q!䐵z"f 'ȞcՕBՁuͨ6T#Gg<'XkGv!FَdLk{v&Ɛs?RՖ&ðL +\m;˭t^/BK xK B1 =E]i~AKXԅp6ìjs lȢ$Bѹ#"x0 D|wiTB rbV ҁ;zS0NI|.L#&L8FrX@̋ve$u*.ľD2vϵ]E\~DO.uۖaXתyRw~M P=k0TFHxj1D{}qq$4.;7vY6G4*3PB(4$Ҝ9Sm<)Dkɦh-EC>'HIG* qW֣ `mQ,CU20A,Ւneyඏ*/ٝ>gs~ƛrIڞ xA0 y\M Tm) SJf{S 1S0#H>H#LV䦏DŻlbV6IMU%UcE~& 874`=Suz?pM4 ^LXyVC x90{b%JX+h]C#c$>4L1Bk}9Ȝ5BQu\ɋ9́SDOSNJ5ab=coN?Ztم-/۲c!pW􄭷ƾ)*p/7#C5 x10 ;K8M#!8Mp-7fb4&By♙fE*njn5']HR)S&V,Spn:b8e8/N۶cZn/n1ֶ?N<xn0 w} YHS /H׆cPi[n8f0$f&D$qڱ`CD9Rmwhxԉ^-uHi r\*V JMO}wlnHnߐ5 Kٿp7 6Cj/?}Ge x91 =s{%_+ A߳`i9TS#J/㲠Dμ4v5Vk9'$&Y_h`qBlQ_>]t XY . L۶ΩETîoCZ1׾?= x10 E";K:i"!Ķ@ҁS[ޓ) BȊyŬZ jd 8ZTB\ gV&fKr|{_y򲒿sm{̩؅69 x=0 @=M%Ią Az{*qTR SPBxMj1+CB~B饇[i{x1ٵKץ?P $LK)٢ۤTx0zT;80Xf0KՐ`tpf Z^ĭebxPL^`wGU oXs[O:5.{(3 Qk`R xA! "(bbKiK4feC؃w?\25|b5FIz{$b&sRu;O{//-kA Itʑ(VU@YʹQz_6经A%8\Hݱ+/SCu6y x10 E;K&u"!&8(2*n 'UFR˞Zir-!R#795 ?Ŗ쉼ɡ-baሁ㧘 ^ Cp<PgUjf'h,},fr"LHD x10 @=nK8#*t q?{\ZYk+((ʔyNh:p׌P-,v3jjYh z>󽛏xy+2-}sk8>6:xKj0D:E3 }@]3 # 6t37fkAKKr sKyՁC)",\~]DRY lXPLzvws;k#}}j!GDZѩUOU9 4LQIir}?/H xK B1 =E(@,iȳ}lf 3n hK*1;Ƈf Hٓz}BI!dl#^;dk%mW׼ g >1d+eJxi'ȐV}j): x1 w^6 U `VUJ!o~rKĺjC\#$qh 1W^|@ r`AbR8dϹ,~X!؛0}nKUHͱsUa1P4ՙx;r \؛/P30ʫ@_|w[e7VI)f 2Dq^,{4^OV `<92(k1chE_4&OC Tdx["?Z( 3]Um-R m7.s{*ziwےmFD x10 #KN,!bWTp\ofHkcd_kHC,2Y͖, ҈891{R$7qq\~( +u4ןo` !yOTncRG"hUg}cmG@ xK 0EYNO W`6%MނNsGĨTq!k֕PZX:(bK렳)G2V m(sV;T;tW4FۏwRi5(mY1UǓZ;]u^AkZ/?,xM 0}OkQ< ^ ./,f`jl&8{1 k0Anӂ%Fh,.S g^k{M(tl,MG,Iqpl6ؑ!O q#apXC xK !ڒ!83g [Tm7 KF\,:s-'8ej![ FRn)Ĝsfx~z`>PH.*}]9T Y! {o0_eO=6 x10 @=bNSK8#*t q?{D\K1ҫZ 4Z3KJF):5bRhu)/еENM|#^"bZXocNc a:[6Sx1F_sp7f (1L@ʳ14Qrc\w߸t483+@>X.X2ӄ/6j~R(h`'_s?HE.gOrqr~.%m-M6K؜xK0 9i|$]Ć hz{ͼ0f!r3W+3`])!X"$C%žL! lBfL^n[p%?݋c@2r =_~_a^U֓u Y羙wGxAn DﺈT+U/|CRLI%߾z-4$޺e+)d8W롾cby^2# Qqb;:=&w2)8'3*Z*?@7Nƒit|j \R9_^E T˾N6܄A}qWR&xK 19EIO KqD07an[P٣5Vz/,PvۏCǞ Z}FxOKN0o,4=.ЈiS%ۓ{a @hkl)W.5h0M9,{#8LF:KwÊjk.yfA?~%G}j4:%o[j ,-՚i'ҋn3}xR[Yn8 ?J3b.~gyĤv!+(r'U xK 09[*4& H^Ŷ/lf3*3=))MuްގQ1iRV' 6yIkM$7p v DQ*<+HiPqXejHŭtr˛#PC.}M@:,AٔxKj1Dsea0HxarrT=(^"B CA9j|Eϛܶ囪k>2E?PrZV=J[Yh{u ?^AknpR3K,޻C]^S'h2:KQF~Hkm:TFfPך xA! " BK4feC؃w?\fjp(Yʕ2v^ `Q ]0*UJ&sBT1}1FB'm{eUD6x1n E{N1}0`.ٵ6k,-g\ y͓l/JM|Dh \%y-)s+h!A8M⫬E9~z\b矿ȹhþ1ҟ]H ׊J:1u&h? >*oM +Ix10{zmGB[CDQb x=>4U$"atHXle̩bHHrv1咱ARR_ _Jg3tD{1i?nw:5Qyި7-'m Q7E( xK!Dnh&ƻ4d0O/6z5vfPU*蝥d,e2jC60M;Ae VQʸȤ$Axֳe; Z:"gDj۶r i,v :X|E.Ax1n0 CB[vvWP$Ik ܾʅRD&+ӚH!źh'kQ| wlr(%r0D^QGNOivHxV|]n qW5P-eW^Ys CoEʭgzm >χ>&̹ C硟A (Y T~]KZExNK 0wѤǀx$S ڦc Av]A&c18R#MhFCvNmȴ d]NxC6.5΁f{lV3cc ݡr[*BT0Phd[YM}ԯqH{ t:ו  םX}n]M x9! {^A,/%6[difPHYWv4E|&`Y!0To&:kAϑf|aW BԾ9ԜT1_6[ x1!FS0,.3Dcjy7҃1P5-Kd$ DZ4]=mg4I5܊Fb6LH#'Ǽm?^߯ XOkۺ?;vi`6*x10E{bm4Ɩ ,Hw#iLL(@n["127PYMfuS>;WYLyr!`=y59O& ibv-nϟBΑRY5TqΒa{. ^RsYr:.=ǽBxKj1D:Eﳑ4 !7{ladV @.ԣx 0ݠOYKP2X ճL5b6-)ͦCKLTYr?xqn(D|o&X3 r v]ut/ RKx; ާ> *KL&oK@ &&%'QhtY@QwC.ALodQ`hAyc$򄟱v?@JTk)½X Rg4UuFesY+1}D"x1j1{b4I !Kڬ}2 ~?ile3ZK)똼Bhv6Frd9#q #N#  T(9[+0E4wZEY@  $ZgteiPVOGtzczpmmiOx;n0 {}}- rc!d\,16kSH\'N@%9NDDٹ9qHSXJZBA<[}<խdCHeC>Y| %` ~UUڰ} v)AZ{@;ޅMֺ _.Jx9n1zb4ҎN_9Elk!}aC%Q*[(ԒJ8[MgeKeԖD=5'$_`rv ~^eo!_G~ptM y;@_CxAj0FN1w$U %wu5' m\f(XD+[QIVs)t\EC,:缦jʫ"cT\BJ!F'u}4C3y3GWN۾ocu;QOFA+u<6MCo.D%xA ὧ} B]ƙJ)6?Vl}:=xAn E». $Rջ4QgnT@o.Yxed Wbdi~_m?ށIOj]UwlS2,u{h<:sNêOx,}zMf!ERx1 @ўSlo%0:6A/d$ 3^Kתdg;< &J ׺_%~O!xQj0DuO)Z[,JjGM82R#:3xLo1zQ$XgDΒ {)=5;Bp>a@AeY9ŠU4F~at#&maP\nF / TPW`;{ן70M.ʽUX\`=@[.r 1@ x >{qJe5+M t%9h,=ZQV$4F8>@]d(9BlXۨB`KF+j2]W]/@48yKZJ\}F;gG [ W _B xA! @=`xBK4fkky̙7jLĐTQH2p)c"!ՖzM+b6C+[U:׺6Ň@%nS'Z0u6xA EbtW!0̨i5Uf@j+IL4.Bi)&L."[J3NPBRs^w8v+ʺ.9ȑ-%C+CvY'nݷscOKR?eK x 1E|6y$|an/dŠ ۜ3BtSq2 S)kާL?;$dHBr$2KLL"\<>5s;Pz\'R]{*bΜtpPZ] qډ/{=Xx 0D .]AQ[ -FB{+3V.G)L֧d]|Y,FB& IFBU\ d4?P*%Qͯ`4X%,i[?l*/t|U<WSfybBxλN1_q{D[~ݬ`iS UD(JErROVkɜbRak8ȳhE9)e1FeidqRs_ Vx~ N k'~4DbkX 'x=q)y\<_|axAN0 D9!I6wqlTQblFo46Dz[ IJĐ"E$μ֊8{!A՗iZq41%gMY xg!),x_qDZ?T"ccy3^/Á J!@P~эH> T x10 @=b;NHر#*t q?{l u^)e*@)25z&l Wp-k)ݔ7sm}{7y+"-B۷10nZ6gxKj0EZŃ=ydiϟnEF* x9! {^A`F +dfT7$  sbb W4ig"5tW9R( bjN}G1t}i> c^k9vbF5x?k0w}u"Yb(<B,d='&D 3߾ ~qQF擗>^ZJ u#ThK2F|kguQV9fE5| =rBV 0 m57UlJBanws)",%WU->侲`)KlR x10 @=ҤuHرVR T LD3VF+1!!3".0wPa e iahL…QQaX}߻hx?R+DT`OVl M*@}!ExA 0E9컙IbPz`i%FP< P?re~BJ83s,ijV(Uw IιQ'!d6y8J/o$c.|Luo \MEk!?a:g*OghęSƃ u5EH3xKn1>Em).v,D\Zfhlj$G\T T1; >&ٕltᒼ>#VX)p}<.u|OѼZAAm+HWE}wX} ;>Xa6`)DqM xA F=}7`.FSFEo&@<="rJ%Tl}䜐fH hJ-Ǚ$, YƒB\^q烆aSctLHTdNNvYI+jENBux1 EwN T.6jQJ޾zIOocWD8#]&#Dy.梌N>vm&o2aL,~bШ%9P,8q;<]t7p.%"\9ýu #5$kݞZ34ޠ+׿4=DxA1}I2U 2 nu{)1X- 6?<> c\9֙I G%T<)ÀHixJj(qEp`9s1ud[pkI;l>&"t+qˆb_4Ak*ʵ]e8}tRMԨo?NHx1O0 ὿;K8u#!ӭ0U2H9·B]JŔ iX(KU9-Gtiw@X75H-)% kHpu/6D T%xMm\ޭ6WÆ c`yύvMO.wϦL0QUxj1D{}i'u"`Ui5‡9oA~S̃@QO'e2Ncq˜]j V8 ?4⁝q ~nϚlwXMzDIݶw>^ Ƒa~n ڟ;f|Ԑa-%u}@NxM0 F9,Hb]ۅzHܞJ\o󤧷zS( I0QΚ'٫-Xk2̇a %NJ%))'IZ=:LχW!8Cp۲_T@tѡ*f{cnp}Bl8S{FMxn0 w?f#ZhP:! $CQRKr9x GȤ_UmOe;\Aacf¬AQsB,(t7zdˬL/MsV b~Bhq7,x伓KBRH'*8^3ԍ%_ɉSǎJuCcBH.?F7Q]̚ x9 0{B}=!Yi$FȅC>i=΅ XAI-5f&JBK®?#/H^ sչ3VAz|yqʙ8\k c n:@5x;j0E{b@ǒ-JoCȅwC6ۜ8JHjPo 6R4̀ËJQʋ8I^nI[f |6jB?>Hqқ7H=wC'>K9ᢃU6.)Z?H-i{-6,g -O7xKj0D:E5 Vb32Rg `.<(ޢJ:3_5HI#hkKPv> FNdu .P-Hfa6QwƸ 7=rsm/&SQ:?*>c 5`hez x <9ONx1jC1{b!eBJ>n $2ǐ di P"^,\^;02MHa! }~Ҷ瑤 ]iJK+F23Hٚ x10 @=NKVQ:p{*q7zD"2Œ Ou.xCr*Ji)f2P&P+j. ΍l=_R/pl[M:eS5xλj1^O1} hu_7n!{3ҌȮ"o5~o n∑J)2L(/5'}& ;ZMvrAR'K)Ds,p߭o#'L5FYoMkAʼn ʺ-gpVe=r}],W,upŚ8ΐ]}K x 0EM7 Ż=KlPVB<Ļ2 U홊T(he6gŒXz*;」fFבZ8RTzRdzebXeo: %O,f9 x; 0{b@?\%W+l"H.Ze^ˀ9~́m$d`=޲{5hqTʠS*c$-ST\J T*,'7f0M *6&*@:tu-j1B5 xK0 9ElkK8AlfCNdę |#0ܰR̛ljC@Q% J.'q-z;C>ϣWz sᾮJvgv0Gj= xK 0@9쥐L&qM&3,i z{ ^ykUl%s1SD3e*٨ f=FAX9rJ& ȘF Vx~V ןo\!.:SkGj86P{-ezn@gxj@EAޅ0.TRXYob6[`u"FKM#BCYh VQv>3XBs.56&FNkRo9cfuYZBfa8xn[2pxLR~uwطx h;dBGO xNA 1 {IӚ&EJmo8 $ôjB6cX.#Y넫([] fiVF>s&T$ CŋYv)nV3xG=?Zښqmi 1fȮj pALx1n!E{N1}fa4"`!^^,[R+ޓ誀8&) qr yrrT)5ub8%dT| )@~Msl>z?!xLi2#5YD\//h0 :Q *p:?}[ںKxKj1D:E A'`| -x$ |Ԧޢ53L6AKN'DNPlߎc*$]^ZSfHţ 2ּ=/zD-<"R߶:'c*(gp^cA[[<f#ËFv`~xB'L3hFXI0A$DͼHjd25"n׎*͔&XC 6ͼKNPgϭ5tC C".\5Hݱ7h `6 x1 @ѝSx,UDm"t_F2d%ZMDM[((y&=՛8D bR쵕11Z"4*ux-K0apW*}Ɛ?*h9}cRݶһ#5M,pѪ\IOȼ G=K/O= Kx x90{b{_CBnBqH|i",%&)rDk ai#u|$%xd)"m:FEm fE]l-} DTh"$Q"9hPb_&tSnN, uvc?{qA7Qccqçm,78CX8ѷ(n&v, U >p`lSHN/\01Hr~ !!@}-h{N܂XNi+!ϊRc x; B1Eb+Lq/dyBWo xˁ[P3u΄Qꤹ{=2!ka` lcND8[kZSS%1'\~{DBFo2BM78}Ȁcn)Ex_e P=x;r! D9r'_wHxޅ)s{p'׭S\YLr0%gn)V((Zt2h:V>/$z^z2?=l lu z~˹::C/I FkNxA yԪ1nR/Q?нxW*3XMfJN<G$fC4j V^x?7hɸOt$DhR)ny&25sy3tWҟQ-e9t}nK x10 ";K8I+!F;n Ajɳ8GTRy UK (Asӭ[rqC1%%'2$0/mP#xOvu]z?Rs^Zoum|#< xK0 9l8uj q$NJ( nOmf[)(@88"E8!Oqh51Ә%', y182iipzf.xmYEaK S}Vǚ2Ax;0D{=Mg#! Rsuv"HVf4Trv0d]pЇ'@2RٚK1RhK*ccCvjoʢ10CLu]ԌUU&l7ת6۲u{2+n{ G x;B!{NAo'1& ,}BO 84Y j24(iYYt5ذ2$18@Uʈ)qW"h!q_+qǟOzZQync@"y~ۋ/qu2F8!A xK!n]zh'/ Fxߦ6U(#ZSM~,ap+rM6[Y;D-W2DXpL5F*cТ[g qD pTޖe*c[Ɯi.NuP_;A/ x;0ާpOwٯ@($" 0kfمݒX@wjM*VZN32l %WqG.$WݸP]:cunj#~L=9cW7xMKN0!O2vlbqxR6qq\PomޯUU PZ#afa84Is[qTb"saR3K@} {ZπH;aҚ#j^ H 7tN hǖe~r7Z«Bb9B*r7?Si xM 0F9셒ii ]2?"m$76-ת$Eb@Lbf]D%9ĕ9{jGbQشVY¤3b%dl%Kg OQpD4֚󩩙k+~G<] xM 0}N1{di~@˴3bHLފ<VU9bWxbHĂ1%o\ukb5 M Sc0;{ VsM.ʺέW?2kz[k.h;[Axλ0 O$5HWA6Uj$x{@7"Xɲ5`/r:z2+@ ]da'hR36Zu>[o`-": Ƽ7pAt]۬P'1ݎҦ-M?^\Hx;n0{b4 Mƒ|Hv 5O&@1-ΕhL!r$NJj.!d K=X +:&}GǤ?1{띷Sm&c~d2=r,]/w>n&wAK[IVJk x1 w^A F!o~r5U-V_C-4*  #Q蔝b2ܙCk輿&QK"dSӾt b&]:coei3_+J4x1 CwN.@]~J }zzd=IUi!8yl1^p8̢[k1&k 1<"hWJwt:!ʾ*DmK #\Fi[UHxj0@w}]$Y+($͐R9IwIZlq-oxOKobB_zt%wS&hF-hHQnGvKt\*><+ʹ6]k/w1u>hIPNEXU#06~mn0H[A*H p 4-͹Pǚ~(QxAn! =d3*#M:mD훪ۼ šR4DHӤT#yr:lܵ(,j`Pd#9g)C)zxk>MO@jZ[;fiDźESB vtg);U ^{>8ʘhrVƯ.t RT x10 ;8Q"!؎@tTn军 DEsI"CZ!ET a`a Șc|Z̦}Q $goyߛڀ( lzHv i >81<,ofՑ ٭}(+p7evl[?a޿.@1+Nxj0Fw=ݽ\3-tPbt656M"!+} y~9᫅:<) wgvE)5%-K"ي _+x9K>wiXbFG?[H?D\Rxo't?R`Jy~׺@]xcx:p~>h&MbQaUxg >ݴ,:MT=Dx;RqcH=UƖGUe|l rIxN1{P$%@OwHΑ''?4 Q.DAeLt[̤8cވkht*k'U֬|1a8$7j#2,Vx/o`s֏'.ۺV j/}z@@frnYj 㲨/0RDpxMn wy%j"`*\`?ۣ$9Hd6^|p1)gm47-"A&撴O.43\ ^CtyPkm_C8䓧/}KzPq t+Z_;BwC[=_lE=*K xM  $ƻǧm,P4xg3spr9h2O$7G/;A~"v,6)+|\T9n?_`5%u ^(4б Yz;?̐ xA!b/0 jʆߋ֥+]b c/9ʢ$Ԟ<HL#f4k#cMs bUz[x"ο]_ G=Qܶ>KN+|E}Zh7 xNA 1sV+ҙNtgނ0hoIU*(RВy.BLL˂dШzV cT ]K`يtڄpfU#jƃ@=Vy[w)+ !Фg*y/-G x10 @=bS'q$]VQ: q?{ ؒ /]At(I8pRe{FTI;q\v2ֺ+T |l#|{D$d)aжu}M[#6Ś x10 @=bNH#*t q?{X\a dV8͒V Ȟ$cڊUլ}{7 jk9^[}sk8>͔6TxAj0E:XeC F6"O }M{͇i1IRY\C+9F^#32"O`iflg񑰼i pa iYY8Ƙ桻Aj)G"%dLs3*v.^t=z”'}V3GJߟ *f~օ K^c ߫^XLN x;0 @ Kw%]jS0S Z x90{b{o hm!"7 >4ӌ4R .Tl K9vՓ*/g6b]dt>>ǤhZᱯ+\~sN@uG#U4hoXr&q0{|A x1!FS2O4feCk|׼9ĖW+S@˜+ R6&ԲA6^%rh[S!JV y?߽bϛgD!7W?;j]66xKn!Dseła> YA,| My>ӇsTU$$WBIyjp]uP0&f9y?f;mG'bFRkYb-%&MgRhgcx)t,Dp >|= b^ r1pZ|~^ו,lM{x⼻z7BƔR5ti٠bʇ7p x;0{b{(o-!ZD$qdLf.FbrL8pBٱԞlPB79BSd vR݄*ƽux[h5i(IS<q [_>+< xA! "Z /J4feC؃w?\2ɬiB)J+b )& 5ufuN{/O|LULL(Jcg4Q`/ձmϵ{e `s56 x10 @= N$]\VQ: q?{Z31 XnsuɨXTS^]gDuS@C^Ukc>_f>=Zk߂nXñL6 xK v U 1n%(EoH@Fͼ~@ʘ)`h8HN{dd,TG:t9^0C`=Tz~j??w}Mqw#URV2)-u6eo =˟xM[j0) ekʻE٬eLo_^3̃"GO(cn1I6; .).sL 'Ƣ'87Zvy{JkQ$UK.Uh| \_ .Zr 8q[U%OxJ0FyAnAfDqq5NL#m-x6|mzM}7xYXK҉I{A[Es`Dq~@bŊOFtaS)Z[3|~W3}Z;  p*ul-c -dRB+oG//K[EnaS?AICx 0<]$m@DAܪm[<󝜘AzՑQ{g)$˚*eWi*eAy"  ]Ě$ŠITΠ%߇9 P ѹfrzLE#8)C7'%.ss8-͵'xTh,ܳExA Ebn`&3xf6bcz{x'o%eØOBG^kc:I 1N{+vң&z À\nSl%r/NN"Jsk*=@1(L<6c;` כwHL x;0 @;K%8cP I7U(S 5Ӑ0őGXryRӥCҘ䑢d~ٍǾ` TCk6|D?$G  c]X E븝Y`Zs]yq? x; 0{b4^}, B49Zq"E.|r<^o"%M45SD cgֻIIq2hQ [Dm!gCAޗ`;jןoho z$&,TS#xxFp#}TK] eH+@.,0nj>SBxNKn!s jeAi b>HUƖG(s7*+’-Eٜ NܹyQ:k\ G ekP x;!{NAoXzVw/4N$[Y;#3X.E9PJDW>Ԯa:7Q,Oh췵g׳Fa2hTZ.Pu)oz<r/s\e[-uV_t?' xK 19Eng:.I#!ހ6oSF,M"($ȾҪBu:R¦E#!*1#ώ,KAR^ں}o/ykMLiDZ?TS7sâU; xA bクٸ+ \ftUH!K!dce0mL(yqcS(!T:ʜvD ~u&1Rp&Z1ԔUk' xA @=Ngw`P Roo/߼]R13-M0IXuggu="Jٱš-9AA87{.?Hpi:2պkmoͰo JUXi@7 x[ 1 { U$*vF+xg`"5b1SI--:'llVPKS*1g"2^<2U~r >ߝe8Jp;P_ǂϕQemtϯ;,C x;0 @;KHmPdޞJ\P:$+њ4R̸pJi桛E'<墵fli:ZD́?~{@JX+Aw# }{ 9 x10 @=8#wqjGE Jۃ[~ofP,$|FMSd*rҙXQ'rwiuHecy F%BQG_jۻ58"1a࿹wcu4A9'حUx-f<&Bx10 {ԪS?bl"A"n8kxȜhTU)I|t7yS5#%ň94rttڻ6X?U' 0[wnbԶٲw H ^ՠmڋE?x10 =bI88) )/__7U ie-Y=:Rh}$dJ.} d\stXD1a㜸Eaifp͋jkL0c 15+LSl54_ dԵ&~XRdoԾUcucTa:H x10 ]I*!~B| mQSp-']T!bH;D @dYC("lFfo6]*"S>g &fʱo ٥w<>/@đɇ;<ժ.AԦE/}pFr%<x1n0 Ew{:d zb`Õ2ܾt[0UH\"VT2PI˔|ba3ӽi@s@\4S9) =Q(s,ޫ<~";3 /쭭c?T\B M|iX;ٕzGZn2tA K xK0 9lSG $MޞJ\YMMeO$(0go6nv1)9CDL-l[gmVSm% x;0 {B=50ű$3F=a-x҉,S!{lQOٍɪ=u&#&GV1a4E&dkJoYZ uxa0Q>ru?Rŭ$n3y\!Wk=A x10 @=$i$]ءT; qoSgL$ѥuD0RaN*noV%* zn Zs"CHPI\f؅M}9j }: xK0 D9l+!b;ZA!n 0ټyUbTTxl8s<3a\0{';uDkU90KʅDtr>db =:\_j/sBBH۶u 5]7zWp̏_u,@U]C xM 09EB w,Vb*x{ ^f`FCQ6`DH6g؆\8TJ"_Y&6#P%JǸ]?>{Eןoxa}1'뺌?RuQI ; =oN+2VR[):c-e">~4?@*4\9ں1؟FfԱ_mP79 y@0 x10 @=Β؉J8VQ: q?YTUPKu"N\l*nD02=#'(@L%+\ ,hP:7?o1gKۺ>?p*4|tP4 x10{* twđ1K|-vl"0H!MR H9FA\ekGDuoT8lV2jR.Y*~9%]ΧӜ.,1CxMJ1+w$3 Bu!Jp{Sm3XjHI!8JIYhf1s3 y1h*_7׷u}Ή?VwV'}:5y xM 0F9Et2E$҅|M %@FN>V[')Պf#)A<Ď}<$F 7`~U\~;"8JNuYWsEJa|m:yRb>q{; xK B1 =EnOĻ&ȳҷ*^f5cRZhӒB"^:\kusE̤jflѐ~'25Au3>^|ϗR!" >>c7]n Gu4 x1 @ѝSx`6IE۷R/пϡ QQ8" `"$TkC J!e/.6"S ⓠFM$RKH6;2|>E\9ѻ.9հ D*}B9Sog}?xK0>Ew"F(MI)[AT9.7 P`lrvlC8ə4{cb[} .1}dL'}|-,gjX!h$#/_B;CQ xK0 9l8_ qqjK.=E\4zZQ)(*f#/SfXEIjF97elcܷ{ )R \9#ۺ>?Rs앇2/;v xK !DЭrm0`" 6TolQ愌$"1QBũ8-N晛ؕH[k:!=ワ Y;#F}LM.E H޶9 K>ʦuѕ`5_>Ә x;0{b{?.޵@82Nx43қCftC YCEt)0{kN)UuB@׬TH1K.:7kɖQ}Y\1.pTSPվ1Na67ugӃBQZZ* IJB8>>>,(,m94u_6 x0 |w8qĀx #*T?-7I87[G$!QlƇ$!9;6#O:T uёsJiH)Fk)w~iHz/<>Et[@#a &׫UX< W!=gQm]Os}nj~xL9 ׶u}iؕ 6SxA0 E9Ŋ'aN16M(rq*<ޗ To b}; ݋*gn&zҚ}n\FTFFv, W~@/զL"mjǡT?RCoLPzAwUHɗGZWR9A.uud[Q xA 0yޅiĿ&b?\2ӛΤ晔gρ"Mya#-!B9H0eˢK:4j@Μf'OagTw#uij֞[ݡWa}m;8 x1 @ѝSxXzF!o^y]&KI#8Pp >d"4VU2OO-Th ''X\!<9ƽuxh :=gO&m[?Vs< -.i~O躪cKA@xA 0E9$LxNZ$)x?><^+@l6 8MHd)QO*#wbEM2"%tzaC@qB~t>㝓8yOhtpe[?R)iVj_û{uШCJx=0 @=i%U4Qdz{o R$˜F10@(G MmIe͌2$8b-%2NŅ8+S_k^:~1%qCJ}>Wwc aY_Z}e)^,|SFU xʱ Fᝧ`.&Ÿ9S1}{M|-U@2=|"bE@ C]W,M,1')aR7H 1 j\cU~XV^}!XŜ6yzܦ%,5ܶU|uA-xʽ 0=WqvE\DqNrNlm$FĻ -|0C ѡU4V6R{)Ԛ]#T! F[krut#\6^@3)U\VAh4Zk`D\E'j@ 1±0.B,NtDxj1D{}ưN' Liӛj$[ܑ4atHeKvR!st)0)T̓4XyD99́‚CceYCOW2`az8&}YnFP@긵4N";s%=®.6e9)4S`2BK hctVYCe(YYK cbMtk^O+<_0ψM>Fޘ?VRz\Gڎ p éߚIqxA EbnJG($ƻ 0Hc Nc$^ޗ &3l 'DF͆r ^Թ xyⰖȻ#l\^I)ux~Z_AkDs ZL#*}_ET-jx3D m.Zު=ݘx1n0 F]ޅ%[.iA: ۅ [[j~RC 2dc,~ʱhѠ쾬a$D3'cp9U%JX Glnϭo$kdzܼ-˵wcu@:G:={mE mqw?eDG x1 w^01FD }#冻9|" !JiLD<3}h/SԊRVs|6Ԇ1doµm]_s;vi꾘@7]xK 0@9Eɧ& @p &"/ۼ̓VEHg)itaL=1g}E :+H. Gͩc{^BdUne綰p8awTZ&̥xJk[m2A.Txp]NF x1!FS0 2 Dcn|k9/J1+j[jD$Ėu=}MrXPz "E)Y -N؆}o=3T3׶u}Ή?;} 5ٚxM ཧ}7(:c#M % m<>w"R;k0dfN92c#.M^C0$GJo'ʨPEO9N!"!uJiSM0Ts`нR| +AjSbS/C|:IR x1 EwN `@zcZ CnD@7*Wr',QTcV̛n|Tzv):9Ik5`3}sU\{D\$\.H_ǜzcLpΜvm<^ x1 w^[0F4"C~_~ 7U VPkrՎ!(C?Ӧ$N| BPZ`E<ٔs>at -SXy2/6A xA 0 ~X[P48>~{=@5u. Xb,{1XJ#@aKA% U0׍pkdМn#|DDF [94t 'L5x;n0D{b4\~D 0ҹrg#XKI,+ڀo@b5a,22\IcBcw;P(K ՃK6!3;dDT#rriīg]3 m7m4|@0дq63$Z <-{8J~Ɵ j3 KnSHg>Ӯ~:P xA 0 ~`Ɏ%C_[$M]Dr(k$) OqR&]$̥D QJ&bȁ%\FBom(}rU1>n qsHra-m Mu 8wuN)uY&UC5%3(poma_Nu=ZYfQa} 4Ex10 E;K"RWS[.r!9+ "gqf]JJ1E\)&qbϵ:1yױuKw0 pǏO@ >D*y糘]T`ݺB.eff[yBd x; 1Z6ɂXYz}VH^AfETInX:>s E8ںǐ?VsmEak~d< xA! @=`ibKKK4fdB 7o4V;IeXZVV-h` [KZec)$DWS+=u,(\1=Ԧy#_7ƾ?ֲ?Vw}S6 x9! {^AsFF +d)fTX}2!W)I]~MTPQuCJ5r}~X}`oԱm{|5Șx]0߳y3IL rwp70M&hHuIΗ:"pHVi2QX}+j6,rcXاX P8'\nqB>hzk;< 1I6  ڶe"Grۀ} H1rrv%zZ^? ^p#=Aj}D_}*rZxj0D7Yd J!JC@FDM-+Js :Jn:&;!ZINi\ 6nf2ZXD˔3S@o@*k$ݣCǿ|rުV x`EsT+ % ix|ٝ6&0~_a ~:u L !Nh3nx/d Z=aa` (~ DBcZxj1{} Aڕu{`܄b\z9trC~ L1ӪDȞewl-GEclY۫o_ei;Nz$I`Dv)~J ?BLE?QnskUER`X=`^~ p^ q:q<qx?7mSHؙ x10 E;N*!nPڠ=E\뵪 Y4g2nJ#9sK 1yFvy>%Ήp"Fm*n;u|\15C5rY@_ߒ $hڤpޟi@; x=0 @=q%]b)Ei:p{o7*Pu)ȑh Q;_\L +w$jY,ϓfQdX^h zb[[?VrQ(粬h〶wz>Î? xK 0 D>oJ"21%qP޾)@g33&2)9be*K:!:OCj2:SrMTzirjBoc O/pJ-Ct6M/KT~s /֏"wBxON1+"UAqף<OJ8[J9@@m 5ϼodmsj.cTxKn0 :w(Z[f]%"̸z%jY)Ԓ4s܍Ic & %e 5g_Tœm}ϳW/ec}ofi{H:>mNlBZۯ@GY{G! xK 0@9En&L.|Pox0ŵPQ!XXWTT")w[Tg/h^3+DZqƥ4^2'f=Ϯ6[L 3Tx =?>MSc6xj0Ew}ۻHdCt(IƒQ} .. Ufp(*rLPRO4D4d +VKYZZGjB0:&d2¯Z*lwPj_tZv<8 ["RɰCp/r/46#Sw_'}N x10 @=bNH؉+*t q?{pvDHJab`}%F2 b%EZ RD*Y,9}[D$, B۷1:V5x;NF!@ULga ĸ 7cwO5x%Zw"e >[ѤbEhvF|E!jdi 2x*5fK)-ŏg/Rhx2{?tŰމQ̰j 1 ӆMaL5L x 0DܽdMҀɃPw&,FbawZeFҦgĉH Аk)*ޣRk^;lXлs-G.r˃@ɝj!/\+6uKΫOvlCr\7@x= 0E.yI t/1y`l_{ .^8D$Ԫ,ӦD %HQw0H^1zF TteBotEBCVy:*~ |CI{pr0t]f?TnAQziNCzsxFfqGgN xA!b^YH {ߋJ%ݣB(a/qrT ц%PA]Rbϸ,jR9 I}ZѲv 쌑|1Ĝ5CzedԶ̕:\xCxA!EV a`0sIG,y7Bl˅QVN4%: 7 ($Sq)qF:Zc_9sp!YV>]Hc9N |Uzku zCU Z{G}/#uW %1RE x1!{^ p@blبYxQX{5~ii"$:%XrsYݱ16;ҁrQ F&Ћg; W!y 3LPnckG v8֫f8BrPov? x=!@S@b,4[Q+3 Æ`5k^"Zx0&cq`GC@LRWy6m] '$Hh%WoυgJ&s^zu'=J{O>!?3xAj0 D>Xv8PzEP~)} @f6Ûa۞%1)FLUR*-5Y&U*$BemԘKwWJ]1[nV5~ݻߗ=͕CoaG?O XF xK 0@94I&(RS|xO3P9M6P zG޶R5R1>G2kV99H8z%dSv}Ȁ!~.Ӊ,OUc5|:DE7Po<|zV? x;1 >HOc.N]Eقۃ5:Q$F(䘒քM"Ce!^ˏժ=45B HO\}{W#RƐ7m{eX37ёWx@9 c%k:[ZbhUz˰6xnkǟOu.X8<"GxI v}$|)(4M A? xM +ۘbp6Ōh)*+,6VSs*v؆U[F*R`rSp;OAk̭t}fЉm]1G,Ew{_ΝcP_C2= x= 1>Ho3_ĻL lo4đZE6U؁wP<\!S_˦R, pPslG HFuߧ}^,2셾oc-c5ei7,4x1n1E{b$Dfbic{F v12ނgk~"PSIZ`3ų+[Q4;w Uԑ,L%J}ȆqnV?qzvŔ6ϗ19nR;8j@~Be8eF_nm/5~E x1 w^C Rտ0jTA" };2&|-F}֗j'W]L+E]rQ$4& M4sD\P{mU:xkh"B嵵EHձ$\`?[cKy  YkCSxAj0~ ae˒UB!J 6JP2t.s +$VfuuFGQQm_7^E_j“@ht.v[LLGNo;yV#߹}͑ J5 nT!ckz@S(,@p?ׯt<=iE@i#KI_ R3xOj0+B9(m.9=V%y}W?Ѕa`w$bN +- Nl*f]?p EШA6Xsh0ufG,+ 8L+&֦s%Hv{(@h8p9~ntz?>NWSR ClɯU :g/a [ x;1 >HO8.]Eقۃ5/P.9"a"8ȸ )ic$EE5s@0Duߧw?o>"X9ٷP^6xn0 w} ]Da tWP"eCk?[nt1b@ϩHpT,1UGӐPL5q.x@[lQ"9zC2 :10u[צ*H=FB ~IʗTGo鍡uB*O9/CG xM B1 =En %mSyVJxg3  YaΡlTV9{[ʮTFF19󔡏 ɪj[%4"d 5S#Ǽw: :l#;8%S?f_ZYgV\T|V8=> x1 0 Ew{9lJH2-%M0ΐ -y|fcYג B\ErnFV(3%1bj@+ )&:mn*H9{kWۇ!{}^c;1[5x;0ާ؞'%]XD f'Hh+8h6ns096n `)Оs賱Hqa1&nN_{:L1Nzm]AUMT0ݥoY;9 g' QJKxn0 Dw}.,QPtԡ@dhAږ0Cw;UG[d"qDY(" ymj9jI0LX#O"YG "$þ^u׿~s)x; 0D{b4YjwEDd d)9D SfZKbg3"C 9d\ɵRmы) _%R]4}Qxg:;ˀ`)hE}]ۜT!3G}zl}؅m 4H}kF x; 0D{b4DCHchcbqׅoA.{.I3|^fa# ٱ)Ox+N𩲀F8깕mN-4Sw*tJ[&O';bz-C5Un2n,zPdz*6{|}U? x 1|6$T;lpErffpKY^R0-9)QJf$2nROmuY0UB_M|T:=\9O*塁[3IxN0d_ >Y80,OAgL"Y~~em x10{=9gǶhhsw){,Yim":d.̜'b1##伀'Ԛ[bO4 Ǯd(U?Rm 0'QT^5ceYR's;ekz_M}? x; 0{b4ZVSjc;cif |Y,2VØf&M|rӭe`,Qm%7!URBYO{܋6DL!pfd_׹wC5ּ+/,ץ Wa=֙x10 =I Rջ*z"}˿<}ZEӐc#?1uÔ{gNr(1g{$q~`LB.G,;.S&pz:77f*\ /t@ ж74Q]֕) yn+,_21G x;0EޫpO<8 fB!=] & M -SE !=w 11 j $^."eJSVܺ[?|BD+Wu}Pw-m 5u x;!@{NAo3g]1+{{5^׼5UwK(v> ŎAIfeKwLH[#W 9}LDAl=^#D`l@(' WDX"s Ĉ3p"$op&K J;@eLNg9dc#XEkY<3hJS`^Rw_o55a9]q~Z= *xOI}r qN xAn! F=`( Rջ[UD[)|g l}OW+՜g 3{4\›ҒM3WDFv|m.yNB{s}a7VpZNld7TzCHPDxA0~ܹ$`;/-"i}Rm$ 8_W0#K FR.5O{f0՗BPdY8PK_/tFKgtm~PH=6)BvA8RklkootJxNKj1oߍg̳tu(7Ic)5"f;9QC1/yiK^fC oiI*I02$^8hv(!ѽGS_0MsNqÇpҮһu VlrRdwc׊huJ' 9pkE Q$ xA! @=`礪mb gB 7o4zz4w=SRQ5wiV)id I"$4QFv\}{W0a/}k;}5'x1j1{b4ZɧBH:|`WZےQ@if"j|D#BbKN8W&s!M+MҜWE ŒΣ@S&C]˳O@t)poĚoUUqoWh Ѳv8lR.ߧ/XγKxn D|{ 6+E %!"C>\F732#F:9fN{}^l0=E=&)Bf4~,j_"aIHF]n}gp7c18—>o[Ts-3ȍ^e}ʨ eo$7x:6[=ĥv2QoiV^x[ 0s w ^%d-xg`D fRBT ig< X:! oj EL hQ޼!_G4@r9+/DLXESߘ>ĹiY7[i XQsc;6FxKN09AvWA=ApzS*vd8BFSJ83);qydd9:n"%FacqS%tzY6ntg Ҏ)!QAZU|jAP@`^"峊Vc/忣 ' mt"%EAzZꍊ> "`l x10 @=b;C%]VQ: q?Y,ZB:Iv^ށ1.XxOT]oY霗oF@'svϧ/Hq^Y)q>SzW[Ka x;0{b{믄z ŎSp{bFopTMvI6hFӐ6\mfpub) ^d,Iڈ.muN#=1XƳzo4!@@4D x 1D|,lFq[E֕l aZ@E-MRȝLlQ[I(l/w2Q]0WRڠk9Q/ v6;&iJ-b0\OZXB{(C x10 @=Β:nbK8+*t q?{4)' X|e]l%+$Mlڔ025cijeȀ!WJIhU(9}绛xy ^ҷ}sk8>d6 x1 0 w{Ɋ#J2-%M0ΐ7Fw9.@в[*qMW3&+ai\L$ &Zde`ohklAz|[??"bDopl[4 x1!@ўS0 ,CbîX ߼9D4Z0F%, lA2T+)b1Ct8A ;H 1D3>E~0XN_̙}sT>vV7nuoC}S;xN0D|M\R5ohM)׋1ѭLdf0B)t*mфjT:(e92xdk6AjdtaѓwJ eL{ǯ lk#pSK:@Q yEyk:w7Zv77(#`"N=\[8e;m'W__xOk0 :I2=0ح.Ö$4u~z.BOO?YU%u(+JkƦtUt$Ir$Z$k 2XY&`RD =>D8jK$< 3Zw%W ho> {NQ~J=!gDDs 1.Qwi 1^\`_#.wޙpK47j}_gJXJ4?ezxn!{bi=Bdx,w ¸pޖҥ4Š.r`5XPbJf&Xg(GC3ID${ Nٻm޲t8&F^ھoc?Vzkd(*԰ vhkpȘ/RhuXQxJ@D tf2¢,^Bg,(ZTE;jdL,6$6vBbFWt5!ǔ(rv|R{-p7HwU./Z HXD'y/p+ u_ !wK] x1 0 @ݧEmɁһ(BKI3 _qa(@@*5 fY.?#R`VRkP2.rC xn=ͼ2\5Añ De4xKn0 D:."27Jܾrf0J8&}tjs,u\"'dQJvf/Rȫ3Cqk&381:O{pu |_>]_@"*m0tۯ^ިʦV8Gy=mPڪMJ xA 0yłG/vE< IwC ^8aZ5cN)hy֣hBDŽdc螱@$I3sGN2hYb&: TZg@$7e[?Vw-GPm)/}c>@AxAj0E:@x$ْJ2hf%G /LJכ*-ťaᤜ YE&28fsPG((a1eG ٻ!CϾYE|7 ڐMpF }]q5` : $GP(Ct/ozWzȯ7YD xʱ0FOqw\ZH .r`I-uqLpj!R;L `} =&q)j E^Rgm6Zh'@x$4>j:B%| cgn:M'MżZ] -Bk.Bۨ>B x 0D=*^&ـ=zbŻs쌰E0Ć z|(эWPdMtdm 9bGmh'^ :Xv"lQ1\p\Hy{f`^}d;> x;1 >HOc'.N]Eقۃ508.a+ &ڻ;dkyAZAP4b @:9}զyP"!@m՝2ui5q xA0 y\Mj #顿=VfB9C 9!/Ia챐3{y^8+0bR{:'[{TiE ?_ȧ!3 ܭ.ؚL mU[Ac}?* x1 EwN CT.LSI* ޾H@@ 2#!JXs)T[K#7B͛U96\ if!6ge며}* ??)ΙrwC5;o}PCȣYX U=xMn 9w0T.hBHbn_^^,1p7kM@5CL]oVC/g82; duU9jR %^%>fgVMM-%B2^~v"q(Sy~qz;e&k۾L %7ATk x; 16wAl<`~"Jw 843J-Jͣ yL0<0WrOQ9f$YQ}!XYT&^vWֶp.m #uj ]8cx10 E;㤉+!΀ ĥT=.[lU!PvHCNPEEf9!kYu6!\ 1qRЉ=#6XWj=sZ4>~=B dߟ`)/P74g\mkE xM @=fx`- R^m]\Q3MvB̘{j]-S"kI x=0 @=Β.N A!Eoy7*|.Sժ yJ".R4wOHheIb-5"޷%FD˄yn.::pL۶ΩPs܅ at.9ODkSPy4i5xj0 ~ wI;1Xw.-7f],{l0!|d":]5m}#^8iͮ)0^I6(5еAtbVsl{ʘ2|nQ߹!e=b6s(2t82 , 5>|U#e%;ҶS2C'XqC!^4յ5>'TMPƙB\ F=ch x10 ;q"! TB:{*n(͔k 5NI#qlU,D/ݟ*hLj^RDuĬYSmͼ Ŕ#$8AXuAWxK _:_xN@E{n62lb,hyyCiYp8QMa _\=m{nr/g븴M4˨hWLN筭jJþ1MFvqm^f+.ߗq*f2/PI0L}<}|E=nkރB@ # YRm7ADt!&bI?)BZ%%L1?c- x10 ";'n#!nP[ҁS73bb3d: R`c T{f[H\Fh)M)Ð2TGSV8+G?޻Zןo1Nnj\lm=^?>xNn soLxhW= Vm-ƣ3CJQ{FVYf2$9B"EN^\L͋s"!s0D 2$&4h6^?:ܟW?@JR-M'DlVT'bpdj9/P*dy#|>OzrG+!pj~C8͏q5.Y0 x1!E{NAo .L֍ &{{x^?vL&&F/)) h,9FELROҦvH":'XtL<2 1#+8z?4d-sN^6!Eskڪ}]<_4/@ xK0 9lDBKQ4]Tlf^o4:;%% Ezq##gǙ|黃$3J%'Xԅ'A) o} 68xk)&"kNx̔z=z?TwXt_Wp uP'G =Ҟ x1n0 w{eJZr>r 7u z hدZĒTxC(I i̷H!9("}ϫ B$mpV1 0{ɬOf!_}"D x1 @ѝSxb`"U FmB۷R/пϡ  %S&ZE7/zL Ģ'YlT-cs5fWQ>x{ן7..ۜj-PTv4:e x9 {^}K`w1D},fь g,"Y ۘ'iډ`BީsFm9M@D_*9lwD"*m1T%"& j˲Tz/AQ x;0D{b{k#!NqV9Nfyz%ȮX'$2RPde)8rnLz&`) 92l¢u`)7X@ .zDz?P),Yp? kd8*׽ HB x9! {^A؀/F +dbT= *CNY.H "HfS?˖"4iLI|c=Ǵs4:‚hopaضZj|Y4wx 0y^O }`h[) 8aoVU$U a? x1 w^T/6jUD }#a* Ab&pKT` bC<3JYLbX[a0sf*ÿϮ6燏\w$ N?Rw}-6 xA 1 E=E Mڤ)K/ :m#/߼{tUU}0P S)rq̩Eb#e!g}XPk)H!Y'ߟv{{U=x6ؽfʺ,j.P@m~*5Ԕ x=0 =I$]mL@iwyeq Hii04'l|ʉ@CtX Q Yw7eQ{fprh/Im]k5uK*ycU~D_m O<@ x1!FS0 Oܘ5Țx{M7`ѱSJNs(cD4GئώDz-"zV*zѐRRSyۇa/? sLux2 ݎbU< xA! @=M[ $ƻhh59VQ gҎ'VHʲzF:6A0cmkUҌ1q-s^Y0smx!.qж<:87 x;! {NA.E]!)kfћC  {߉}/*!Sj23 E Ԕ<9HZA-::S܇}_9 3`ofھm9Ԝb5 x |&l!1 1m Ńo?\2c}SD؄R`%yqvXdH`jV&kҫ{{W4|'f'Ĕ}]Gj*2VTGAE]6M}?ҝ x10 @=bq$]Dž AQ=H\ e YP(kva?f,޸(@JDPraXZ\潏x#^~^#bbLB,߂}?ְq wi7. xA0 y!8D* ߗjZSP+MAÐr*'/ ۥfsa bswc蝜6wyFE5.fG5}{`BS;ۦVᰶlOA xA ! E}7L@]DZAܾB/пyx9T-5@J1{Wsᖽ'z4Vh<3jŊK|7Bþ.:LJX5S?Rs5u x9 {^Af f)W,@,¿| L3Ōj:qAGH>1'Az%lޥ>,R<+!ISD x10 ";K-Dڠ( = >-py)fB"KNKƠ&BD%8%Dܓmca+J؀c.Q6Z8~[7O?=a)ua|[mڲZ0 #@6xM0F=u1(x @3M </y_"MDGwAԂj M`O2֒ٻ6R@Qcf41;kH1Ď6(,i0k @T5ؐ <ؤ qgΐ% x ,u-}*.E?xKn! "hⶍC'ۇ(զL)zt!N# L>Prvl]1D{P8M@ :J)'ov3e Xk} بqVM)굞s?T5/a8}\, |Ӂl 7٫@]x-y}Wy~8Kxj1{}zA i>q^loC~ L3 lbᚴٙ\ LN\T3tزS19LV$B5h۬Hw>AW z)tJ@/(|^TcZg q3ǼܞTNkgޗJtQ+"KxK0 D=l:Z$nO`3ƪ*hDGd 1$ !SiUw):-ʘ!zrM.V IH߆tll_Z 2p^:ssT!IyG xM @=:@b CژS 6d m LZ5`5~)ML'woZkQqd*2ECʧc=*O15m"\7Ec7cUdhg'F?@,p 4K"2@ x1 @ѝSw1`;(%CoH@UԍIsXy,Šlv:dG #@-c*Q1IUCgþ>G@ Lm:.3˥MӼMҲV= x10 E;K'#!Vn؈V!z{xOOBvgJ +j}gg&2 W}5 '1L]ֽB"נs6V8||`2OКq5˭]_p=Y xA 0@}N1{A2I3M@KEHHo0Zr6zJ0k 9DUMT1eM9Q:טJpgtr.$dPc,X:\~^ё%)~3m:.[{ úMUϋ=< x90{b{7>"!*J>a!"q=4D@Fd3--%0ɓK\36:PGgIf!hўST?BIŽkǧfipZ1*:.Zߒa޸&V}R_E?3xKn0 :g}w)1j[D/r6fH{ IMP/sH ~łS%FYR0D )[!R ^z~79lyefǦ7Tnr[?'h;d?s1t'Hx;0 {6D{ Hto6@^3 t@ TRL,BZb^쒽/!9P .&rT e[tiZ zggpɦWǾfo]UHdTauvOCV) S| 68BL x; 1 {B}oC]$[b|6o φ\ xs@W-NzbԚ\ZIC\^khH]-{XmFrw6ep}o].a˜i)F"k&@<. xA! Bw/- $ƿ@[Ԙe 1^p.sfrM5+-\&EB˰>A8I .4H&MEK (h 6ǟO@!m]s+ ;m2[7> xK 19En$ t ]֦((] U0 sJ#, B^KE2/vQ =cPKk "e,{bŚ1ϻ*XuVԩ: x91 "=/9%`=L1#Y=+Y7 ;f* swQyS4y̷9S%l5DC%1\qK_iD uQ_DչmCX6胛ה)/|: x10 @=1. TS |>fv**IU#OF-[/3cuCk۲}Nѭ۱t?{?"@&ʹdtt߶ǜGi=|&a6ax;0D{b{VB q$A)=L3OoZ= s#u sB2E*s_\,"ǎa.AghybTx|,>5i[?"m3DΰIvl.a|6 D/xAj!Eɢʲ09@0N;6anI.yσ?*R0cm|@JLd"ճ0`!]HMR 2eRbJ"e%Hܚ x;1 >HO㬝%([p{ӼfTذFHȑAG<|JYVjи-W*ljDI>G?o>-R7'ck;K6P xA 0F}N f΀q%&_,R#!m Œhfը03 KVL2O a4Y-R! a0yP.\6͟~=ѐ8i+ucu>Ӟ: xK  E}~.{Bo@/fff 4i %R|*9M CJ Z+LNzepr]\f&tεx~: (&/Dms '1 i6; xA 1 @}Oѽ$6.&AZ)Uxoޚf4^fQ"xDiS1șnX I=3:'.d䵮cgxWJxFﷵ6 _5 x90{b{_C B {,ifftfPh#$'ChrJ)uh)tU0YrMJdS8xeck;(bJeH*Jx++t<&ld@ x10 @=v$]E!ET-t؀Ld4PCEl<3(j1) 1gK)XMS@d-W+ m{ƔDx۲?}nq_ׁ__k:s xA b^XƿP &&~eftp=3OF7z'6$Υ8&l2`4fSyvh-!% {aO MG"ŭGJ55nWR[2۱U_Ar x=0 @=RK86(=o7*@*f)iIx 2'c<$F [!t!`dqkL:wHGBVC5R4:Z֥W)F4:-PG<oF< x[ 1 { W-wI,.Z++x{30bq (9!&NYZAyj^<9! *-d3IIAj\H*2-y^u+81FJdֶ9 mx6}}{T0= xA @=.`$wfJ5^/߼]JT(b$g(ec\]!!pFΩG d]]֦J,'<۠1X:\~` :"lJ[e cU]>þlE.wW؎]X}= x; {NAfA" ,bH},yL1YRţr))d ǐrΝN =vކ 9!) DPlq:8 L(h]>?-soQYc5(/pNP[e #w^ۛyyq%'= xA 0yU&MSlPV-+20uU)+iAtScDʒr*Q݋> $)ԊlQxT,9sAqupߗ?_@DWykV8Tm=/+뾚Χ0@ xA! @=`hK!1ޥgB 7o4]2)slq FJʒBrL{-߬PPEB kRiUP*V'?߻ן7c"\%|s}߶ZCe5x; 1Eu6M2q"X/ywPĉLU܀9 1Ns:Bac٥d(;7a ՝NرINےmf%' IϵU6?n;xC֟RoK㪤ΫN @^+eP!f:_y.FG x 1|Ezss T;cyb{843ɜ 0ii&GfشⅅU*E6ŀe6:r>S"?_;k;fFieuv__p҉/;kxKN1 9w,ؤ%Uc;bt2 mjQ%=HTI5E%Paa+#WASr)Nki8oHY,GȒ5PJ9-{>~脗?¶b#³xLfFnEЮηO5֧ЇޕMtI xI @E}ڹp@$H ><1]B; x1 w^_;jUD }#n3υRS&MbH[5p1u{ s*l P -SdȐBfWÿϮ6E .\Hݱk5xAj!DAm !o$dn\ (DXT..tII\J{{ښkiQ$u:LJWx>=_CafxWDQ?; BEL-G(36bmQMcP[鸟|wT_V֜xM 0F9uߎbEH._o"cLh]ѶhLLbq CH=5Y;`<}%mpJQYާ, __\8 Ar]w㪮tӇ&Đu6X#ü^HM xA ! {/QP -e"߅~\fMU! [K u3ש5&C)TARe9Ea 㜵4{sX1;NCm{K;|X5oxON0+ji8p!H-|ֻ!V;r\=i2cwRA Qu֚BEF,s[¶J-7RDQ|BSiS׊1yeQir[Q+.9u!_K>A)]ewm2ѥ$f<BhG.8~a7RG 4-yƧbI;@,AÀ(|L[MXyu nNX:g;>,e?K;7ebvxN0D#Uk;1 B8@>`]+S9  ?\F)Y,zOnmGA 5C-w eI`u͝Ո48JtlZ9ô,]?ϱJz(OPF3Xb9-d(nM$/cr^IYxʽN0E>Oq{$QP@AhƓ1VWƑطg/iN&(DK+-'uhN1[p&{YC.+Kс9'6cJ&h5F:RN:KG5&ܨkm[{az3 $~CZE=:"^p>2NrARKy?^E_&^vBN xM 0}N1{A2ISW.d2U6&76/<@B["F2,yi6&关X<U`&/c@$%{EKdp Yu}&PUe-oзp@[y܋~mmG%C+xA 0y<M&EMCo8 L[TAbQ,E>'"E#Ec88EkTRpA%P;/>͌a`;O,3t%GC=n2?SkGjX{T °D_ZEkYZScCΙ x9 {^AƀC](r.X2SL3syѐ$׸J)pm q&Y]}_@(d [R#$NÿϮ6ׇ!to˅}^s;vi ˕6 xQ0 D} ,ٱXa˦8,zy0Aנ1OHzh9̫JQKItV#j2${,S%35@$N7~>y)0\p-buXR +Xx UXdۮ!Gl x1 w^N_l0jUD }#喻9|1T*1̘fD"nac[+uV5 r&X"*elNÿ^m̈m{iثL ܩ5Қ x1 w^T/D }r rgUj\hѵwh VL1fAʪ t qֆH#'pokd6se5x1!{^r0VhoV؋ `Wf 5-+4dƱ Yf Rܩr`T༝tDUZGBւR*\_%r+r0WArT4Jn2ׇi}Mw:9474$G x;0 @;K qvBUܞ".[7楇jzRJSf^eQE}Td0c޷6 B]d[ǜG]y5ΖxAj0 ~b;QCW,t& R7t.s m*"Q5\, )Ϲ2SAіA[8SLu.sK֩-90rPkʹU]a&RXb.#ěmwGHDy·ںmOe?ns~l5Mx10{: %vl Q%P9q=A|-vP]h(ZVKqL^=9I2Y7L:Bj+IJs5cwl%% .Cka^LQ>v-gCUMgǩ93a?5q{m6pd`Cxj0 Ezc;1( 2 kblyL Ľ:G 3 d4:|". }PDC) ;cM'CϭI`'j/>BkɍT鴊?nݠg*sD{_0+t @xo} |c׈E8czU 6PS[Oc AExKj0 @9ۓā2nSŒ?V sz T-CRYۢfg-H zpb,ڛe:q3 wVmdVmuS xQ*|= q׿}<Zx D78 퀐ג3AS7!ЎrEv~vb?r0B-ܞI9B"|r_HxN 0+.HID͋MmJ 9̃݁ !9cC~ 9zZ"HY["F0a]PɭTK  g RƤ ]*c >߮b;TJpbWNV x10 ";K؉#!b@n9#eҠ7d5W1k8dk V,1kT<0{}?"@F.%۷1%|5Ĝ xA @=Umj4xmh"`5NkG"L1yrnH'cbvTH&,AYBɈ%{DO<)~65K ђ%8o*}_ǐ?Vd/r;mMk < xI!B^MLF w.u]C%KXYcEKk15>! _tQ$ڠERTk&NAX+~εuޭH|Wk<@9TuK ^yl;/ x1 w^ `W*N 7R?[nUY)eqN'd*\`t4R0 lĘH84y4 }ONR,j 󾯽jmyr k#;ig)vI ?V x1!@ўS0H^2C(`k ߼9D1)AhhxJA")  iSK݂">8+9erQ6>Y>~>=zeN!uio_d^)ɍ輵4Ko CuxKn =}0OTu =qAuۗ(=@g3o 0005[,uzlLfBu^(Emhé7҆U;-y&9#yIbK{ ߀R&4e.!\i %ԣ~w3;rC%߰ 0 |} 1D#b~j{Ķr)ϧ}g ʔ/Sɝ\\gxN0@|a# Eb\ٷ=FrD1^JzP~N 6 V[0[sV0Ƽ׊k!=W -OXg\ &zxh5Ƽ,vƏ}N˄#R` p+% T*1]2O/po!V|Mv)Yr3ߦƜjIf xK 0}N1{:7H7>nI&"mJHނ՜SK&6;Db i=E-P@zZ2!X*)hm9{ VE&iLamR)+~CJ®LZz8gXʲ.6/Ҕ;xA0 }\$.8c@*r{*#XUʙ#'LfFɢo͜Nm:wC+ 8x4iGZK ȅH!7)8N2/0 \/zB*|E"x=B!Slo#KK+=?K<0d5z{ILMHAVńTjUfL5J)*sڨdu¬hmA9}KpB>2q>NΈܷme?E6:Ǎ;\/'k^&bz3t mEzxͽN1b{GhHijG,8;XfO3sd[Kbx49#|4+\8%LB:I :qd,qH~]/Ip8kQ5 v^XZZ@!8=GشKo+OǗ KǟxAj0E:컙XPi64҈VBoC.[T,C-JNb Q&Klv2CDDǀIbM -1J&^wm_6x  Te]PkΚa^.gbA-p8o+=iZy Hex10{: qGB4<$:%"9$=|mFY9)xtIR1CnSh}=l]*6%4"%8҄gb9}#׏˫9Jx 0|śu1qP;iR4 [n9dfT#o4HKhaQ1!K/.PbeVjbQKl$ *+0E%ܫR'ΰy RDEńRTlonh9ߞv5%wC %zgn<$ -Cښ x90{b{c#!*[=L3Ҵ T$?*&kBP1Y"#Q|奁e$%ǘdt::dlF:"ˤ1#Wx9q@T;`'7D<b(7NPjn0nz9Ng/˴@x;0D{bkq6(4@A׀HbLb^4ОFT,: b;*j&Hec xK!nC'ƻ40$^ڼJ^ FMAT}2r,)`hIhp`FTh ($t&o0 ̽xooZ:k\B~9T>6;_+|= DJ~xK0 >ObPzb /_x,FTKD6\X X3;%̳ ֪K[j`_̈8s-Gn!͖)/]e[ }}|XRS`PcSfЩcC u~ e_Tw]`!JyFujWNxKN0}N{P_#!.Pݙ8#MƷ'MWRA9Ϋ`-9 %*u ȸ:ܱpxq>DZ&cI{''+{wfbnu/^ 6vxO@Dt3T/R É.}G; X v8Bp;WHjG{IJi$ XYښ x;1 >HO8.^-YEقۃ5WdA aƕHJbl!n+0"A5n)BI:6j J ({I>ן71c%|s2P^5˒x10 @=$nHk 'q4(5n/oE RqSr%KJ"1V2fr$ܹ˪@#be ľ@G" -S .S5Kp}*?``Li۬*8dm 뼞A/7 CID: x;0 @;K%]UwT-juSQKId l^4P=\ŒѵVB6,]lkgC>DŽ3X&~хn´﫪b:mo9΃a]>_xNA FЧB~_C?й0 3+3L98419X28E7I16k-57U;dF4& 69JɌu :TXϒP j%䀈eۖx 6jk/ki tnP]1M|DѕxK0:E' ˆ0wiIYcm (zcYל+6x.D],_8"fF 6ijJ:68OǫW CXwk/}M!j?Tj<T!G?獸ˎFIFN7+yEx 0D!6qnU]MnlڒEހ?,fp[OdP!F.E%"EV\wRZC6&M"! 'wc2JH* +^8 }|L4Hod.n6.xAJ1E9EIU:=AR4t4 xm>ﵪ '8:H EOE#[4@\#A璈=C&kϟh?>Qd^W ֽ/wH! 6y]`kuWM/-HG x10 @=b;NRK8VQ:p{*q<9csA"KYs\[VGanV԰ [҅S]5XgޥCz z6볙x˹p9AñN44S x1 0 EwB{Gc J.¶R$8Cn_C/п=BN GrI#gtHr*6G l>`ryLˁ&٫a!؁M:ڼWX] vK=\l)Z?Rs,Pu+EyH|l>p x;0{b{XBHA8L if"~%GŜ3QE%JBɫB%Ju`Ju1e@d=;a5X4YHՔϘ[X:\~4Ys. jCP e}h}a~++|L?Ü x;0D{b{(]bhhĒ]'%f)Ԣ AH]L"{To!%ٸZ!c bIpH]IE u,Z =bD.k1c^GpU9A%U@v::-O ~BxKn D)[0>rԦTҫјkgɒ0dFv&m@zP2DZd&d/6Q (w5.4V5q?1ӴX/}Hz1z> p7\6j;H޸_t. iP* ηӷ\^}/>S[ x91 @>pO=8b,(ܞ͛C"t84j% 1fDXt3WAf鞜φ<>G[*앑cۖ9zuU`e=B[rG; x1 w^C HUBQPg-t*̐)ceX}u6aM/K杄w"G9_Ns2O1E瘋Ekҡ&ןo`-sDpOLn۶ɏ߹Q*Pm TY`B x10{z;|>_p 9`im"|H'ݐ`CJ2R̖<8> g("%`ĤֵѲE>`xgU#5\9߄'ij*龉yKA x90{b4_YK'M@12'`iFD Y ɳuqJu"L)ځx${;:Cy.<{ Zŭjǧ48|qkQr]HUR0\V \r-ꥫ/< x= 0 @ݧl(I4(Cn@/oy˳)d\* ̅5 `SE@Kv;M/C[Nʸ#U#H9::M>7>|)A [u};v&v_l6x1nC!{N}>(W"kG}f)F@69]wo8u\c 9E26uK Cm~6:KQ "'8¹*ݥEYolaP^A}<ҥji aP;3vIc J@b ҹ^*c&$5 $5-c>mH%$,Nu}i{E5xIj1zEBknzzZ0Cg ȩUP:E Rr\AG~XJ![,c͍t'%qI8[cKEJ<Mc1V7ֹP|BO 뵩?R~de;A 3|ϦrzS{g'E_/NIj x !F>wJCL4oD/з9s9T-"% F"saF/晇> # &r Q|&{{a/?^- J'w,}9Դn>7E6p xA! @=`璉Bib gB 7o4%`J́7R-9ZC;0ʨQ ejR)jH)6q\}{6͇HP"&oNm{er~6$;$H6Nҳ~ E8%W$ع I){&o,Za"Lޕ\tŒq_k5sA)D#=: OH18y^Տ-02܁[VGs;kACq'MK xM @=0ƥ0 J*mC1k|oFgEt`RTZk#fF.95D:rƙ=: lr2 T$Em2p9Kdpy)4:2vM: gha:öcKx> xM0 @}N=LE\9 E% qyڪ \$4-T)f1gyչA6zd;YR)Pop}-p! &OveO`n75xenl?~cG jB xM 0F9OID\z̤+!/yת*;೐ =!b1"E󤪏"8E\?!Yɞ,qSr mW /.E8}R􏫹/(ZழM0?^z`>]y> xI0 yHnA#pS*Ei@ 2bJu)"q!BPt+0-IcCB1֫|LNxK/ضaeZ]Ƿem: aPL*vS A xK 0}N1{Q2y5q=RkB^ o?:xeJMbCI/ 1&VX;= lRh#{Zsbl%dF׸^ uRFz7co*0F +Ycw@ xA 0E9i:q=&iSV>/U#41R3[$ѳY\e&#K0" }8/VE \~M㐬p=&ik?Ts_*6 Z 5u9sK3B4xK0 9H6A%pmTS zkUr?h.5wJ)yQ(,1zW:KM$XBiP^H!whhkYE+{k 1G8hx}<\Ƿ l ߕ.o7`/zG>YHC xK 0@9iLH|yVEw]21f\DM$fҔ#2E*sC>$c1Z64%dkx$Y=J称T8|q]BCLؚ\WZ0h۫H'KB+ xA b& -1Kmm48d.Ӫ+lDzr(E/DT i:`F E)ĤKgap :MzG[?Vu0o!6@˯5 |;g9? xM 1 @}O Kۈ$0֑ZAom]0D)"*5HOc;v>.I]Eقۃ5G&%JF m;CIܤ4 r- s]mϛG$b_=ֲ?VwZ{5` xA ! {/1PEB?й 3;b)#$[J'+@!C?Ȍ}I$r :Zڈ\a#|þ9!,Lݷ5h2/54x10{DCA8>"!rgCv>6H8b<1 ޑYq<.zsQzQab!vO6%KwZu;1!Skj8F녯~8#uye?<`j@Zm}MtJ5 xK!E91 1O%qɛ;:3CLBZKdlIk\t$NR>gQ[^fYYgCKQ+ T5n2w JIB$R۶:q+5C+0><}_= x1 0 w{ٖe JX2-%M0ΐ7803w—u65$hLv>3Yh bI"3uRKf\ N܆_>opڶ94u_5x;0{b{p%]D(l=fFO@JRrXcKr)O!6RC1V%ğ1(^\b+wq91]m*]s&gdi2ȓ*Ѵc#mi7zt1 .}-< vAmPqY;F)}L~t{AGW^󝌱VkO'}Lz."xBUq;ɭ=\Ҋdf\hEʡ/>Xxĝ^1RxN0D{Hs;hDz\";r1L3ż wm^dcǶq죷N`f㊬tZlM{O!%&/S򧔆sN*= 9@ɤ*ԕU|}"^Bi);V&β`'X ◧Rِ>gT;7;oWZ xK 09EѼ@K_hӒbFD:\+Y",ц$Kt!b֤T8 I e|yY]~KQA[EZ1XEDzh 3ƾmuF!`@wxKj0EZś>V$C]@ـtV_ }əW:@a0)&vy@ujszCYë[؄lXg5Mq:6YXc(óU.iyN?1`l4t)n:JVОY2oMWBc~MNKxJC1yH@jRl]Ir{)M$7Z|g1V $%[YH1j y!H4JI2Ĺ3k8I<)k4")? ï6 [Ta Dnx r[TB*ŕ4P\\Riv>Ƿp6|SKWĆp(CӼtOp= Rmx 0Dy$ڴ ?$*Fҭ<;̃*EUfS`ِXc/7 WIR38uvpmeoԬ-v~QyʴXr-3Lz[ N x=!@SLo3.0 J†^/k)Dh''D.I(&V:Au)}dI`Dh1DÖ7)ҹc=LypoǾUl}~zv^mt< x9 {NA.,%[}rL3Sm58%Sp^WQ!k.Y3lY@T R˱ŴH¼ H٤s|XVS?<5 x1 !E{O1}G]w.]`#Y®>B.Ho31]yȚ%d oTFU#RZ%([φTz߲;YVn )Hd,-Pt\1=Db@Ē7ck;iK}Y7 x[J1sw&gXtg tlx(9D1ن\\^Ӗ9#K4wlDqKDU,sJBB6TE392Wp;DL>“=0{Sb[+9ү~ jHO>>vK>Φ M x1 w^Ὃ 16Rտ6*jT}#喓n31ZTS!,ZЀ5"P*%rXϪiL<L$j ID\۶nЯݗ`K=u赮 ;Κ x10 ";c'N"!Ǝ-jnf11ǐ;GZMe*Q" ZCS 0(YQM&Q}㳩͇N\ۖeHl=C- ;4 x;1 >HO; qqBˮl53o5 PPFɄzbVBvWwȰm-VbYb,B2hNU-N؇}f~=B!KX9ݷ9h2/߼6 xK 0 >b9J"[2 i8ܾ^y0&&͹8k{L.;Jk&\(j&IB0Aڠ&[#M$.EgUY<~D @mKU;S^ao˨(zt}VG@ xNK!swg@Hwy<#0^6mڤ3dSBt*MkvIK1^NO\68cd2GYpL ǘ <ƭu[^A)8 AmGU n]D.u~g<< 4JD x;! D{NA1.^0JmX!)y3U#D<̫ $@ !p搡i= %*"o5' g2rg}|u 7bJלԜG|(5 xMj0:lPh6=A0Il#/z*cPI̓ 1sH5⫱U?edgpE>O&0v GNwٳQһU/bccϣ,Z6;Ŏs ,T3Wb̮ GJR#\4Y1)+VJPk 7䠯y߻/@ qp#v5sq\ 7њx;n0{bWiA\XE)PT >|f#eLZ Fۍ<(/m[c RmĬ)#x+63{x8m>kȅ<Ai,}kmfuB(2yYbZH 64n'D5rݮoڏǫĊogs#.y>_xN0E|4[~ѳh2O$ns{tze$u4M$+'t *SfbAGDZ4 NZ{x$eJo߃Jz!9Í82Pٶwtp] z2K|% -}adpaõ.CطC 6Yxj0DT(ZGejdV}e.^9I:rѲjTuͩ"HE çݣop9V7>a7-yX_x9n0@ў ;}TI-pƂ"Q0ۀ/ "yY.:eQ7(XIzm(AXl6YKw9bJBU ",G43 * pD:3?(R}t|~cf:ݶs߀;i!=OAx^K x; B1@>&KDp"!^ x5UAr!A:eK5b+<}A$_lẻ/KKJ xK0 9l4_ qvh% nO^476Ur"qYȇp.dˈѼi_YMM6, x1 w^l@D }#n9pO!!؎Xݠ({{Ӽf4bk'^QؚXd{Wv,RȅpͰ$c\NE$U{=Ƅ9&~0d {="6M֘&h9 x91 =MN/qlGDe ~O$>4̡ \}lK)SJּi18TS ޣg,B±R}]1tGtw[2\p6v$bW8R x1C! CwN% ?Rջ$$U}zzgsF$c k#KJ->DJZ@2%ZZ !Zk4|_6w\P 7%x1nC!D{N]H |HVTb,N%4#I323|5 \sޱMXKKuZר4x@Z5\ LެQS\0HA#&TVts  FxS*mk"zjQ(]8w og_t Wko$P'~PI x1!E{NAo3 $ƻ !` 7̊uL ꚁuwyTг-=F. UeTHUN?{?o`m{iH v}Г5YL=kmRA2H] SJu5 m.k9jܧQn=% xA C!C}73~G(˨#-"Bo_K/l^ dUKbURn\"en4ӌftfIւDJTC2Na,jYί!Ow6@Ѱ&"qH5d+>ӈ<|Z71ȓ:ؖeHEu~3IOem_c﷌H҅1_,ٶ9u/*54ږ xK 0 D>Ēһ8ʢ0XWĘC)1T1H4Lȣ{ծA8VubX$FsfI)zn?{J"imquUDsY}mv_: x10 @=ΒMH E)ܞJ\k}u@eH K٥̕$$OU< .@Hiس#b zS6nד>8LuQ?VsfheҥҞ u;ҕ x=!@SLo3; c%Æ^/k^ X,Q z)[Pq4"J'os$!lUe"V9yr̘'h6ݴt<4crvx,c?VSl+xoG4k~9 x1 w^ T/8i&T@r 7.b31EErA8cDy&*z%RҀ|%)kfE MbORmCHMme G,tC/C xK 1 @=En6xIPdP; omޚ"k](,5&J19!j7{ZjFʎ3 h( @hڱcgL{f CNLXKXͱs[6_Q6c xI0 y\N,!N AS0̌ YB.KPSEr>:RyH}R=IRR9fJVv\׸O X0 Li۶fi:Cpl~o/OJ=+ x;0{b{vc"Ș b^CXP9ib^y檏cFBd z邏iI1DcPR*>E8m\O`cי,˵5#5YZ)ȵ87_; x;!@{N1 gDw,$^׼9Tm-7En\ ؼ/]>d^i1A()hZ<;ɕJI0=: ,r .0>~R 7A x10 @=bqK%*(A!=H\F57KDjbʼJNĞS?&`KcNR*SkmiUxIhWfǼw7py% 'ZmNc j lQ8) x91 "=/Nb ]EbO$>4!bfR%&%RE%H!z)^1%s$>VNĐj}w"ho0m߶לGjΣnQ5cxAn0 zXI@"@ t/Ӫ(H4ibBgK$ h!Jab')Ά5'& !'g+|?w a轈 }p) گ|.ZX n< ;H= xK 19Entg]!d/`m]բǂH% F :lbrL LܜR'"r'B ܺ}}~[J(ANLٖeCXMykZa|h6 xK 19EʐNm7w$t>;ƥoSMՂHFBXF KNgu$.cltV@%;852 qLXLcm^6{fٞ1yz?R_i};|9^: xA ! {ZILl]=t.s7JK70RU(V!W&"*(( `2"@ÿ6?-K8qkN#u;4bFMLoD:AN&H(J(1J9'ځЂh 5h&#[ϵ~>0>8ð2N,l4pWQ a~:M M5E.xK0 9loS ](J`6o4D .K hQB)Rf^gŬdQyoL\L]$yOd)|6x|*KoO`l}pv sR?RS^qzô5A+Ψ܅Š۶']g giHFx1n0 w{% (Rc(4r˝w3Ar‘rp[gXrnC&Aӈ$ +2(NEDbʬQ?V矿/Bi?Ҡ}^_Pd+&w8w6ݞ UxO۬84~KxN1n0ۻ,YRC.E~p$(9_@ H4א!g.GaC3w) ̰bSp#E#^Z߽t|1%4`r[׫*ވ=Q3 6n I);CO8_cq{fK x1 @ѝSw&& U 2`*J(rVE4 ؊i*`C`_:+T_gOI03Z(bf",5+>ںޮVχ@M|Ss cUy"EȈ\1]8>zM}7> x1 1@>Ho3Lb#V62Ɍ(f Q+x?% \[CQ 9Ř9>v]` +%"`d5nDZDήmca{ޝ^A;6Xf5>= xA b^`hIo0*іiWfzK sar4Z!9[m=ct84ڸ#c . I!dQHLPkmp{՘>1d%uYJUM Q/t8q)CAnq.i_uԕfqECPw x10 ;&i"!V.jB:Tr]"1;!9gy%杫 pl1 U{B%h`Rjgh 9v`${z,^*=֢9cfRy>Ԉ*nKdjiTy_h_Mv=c\/=+ G<x 1|6"6<\q84ô  $GRHQ9RT:zW~6Lg:3[TX Kttٱ#v+sI\aIR#,8)q~jo(.v~x9zH1W>gF!r{-.o%5ԡaQ xA ! E}83Pzh"-e ΢ mck[ВeKBN"wH[YbMR.Ѻ}Z`^#9Wھ?ǰ?Rw*<6 x10 E;KK \9#*hS0Dmv>P<DG clcDrDʛ. l.ʣz :'Kds>#$!dß<*p S혱Ԛq5,Ӽt1ܦ@-p{p}/|C: xA 1 }E$IZE]J]e9cLȥtDdhf޼Qs hVH*k.2)TK̦AXG|}V?"b$.X B[9}3ne5mx;0D{b{c{h(9?k qd#.4O7*3(7& b3CΊW^(3KD)c)J$8*hڽTx%qӏg@TuRAXyj\[* e{u9B|_ mwpEИ x10 @=MHS=H\Q&uI\I89"gҡTR^ف0JDe)y$BtG%\+mmpWǟ'0<2]wc bgo}wn> ;FxNAn0 T+8N 2ahFc4S!IhOJ99r1eT H%HGICG4ǹϬ%s$r|jY >>]pRmiMu[}hejnoLWCu= kuSvErV +* I xA @ѽ})hԨP ($DZ $7Ze$;L.92䢊d@ Kb"9ڨH)C9Xv! k,+\~RT:k$-LT`JNs\0^"M|A2 xK !} OrA>B.Zԛ+&L4E)HPT9egz(V!&($`Zf&ٕc>ﳫ  &/Z߶לG]4/4' xM @=~ x3 i-hLomMs1yW4Di6'.Ğ#1zʘ ;) !sP(TxGEXjYY\d pT۶! a`P pg]Z%]}D# x90{bЬ!!I"'`F3$;c͜Ul} Dr,:94hSIժP a$3ejKĞ)3kpZD3p5=Ɛ?V5MHu&΋Y19xLA0 Pv]&!ҥ): ~Ϧ;>ؖ\]c{1:Fi|1UE >"joZ+Dwly/` ;Z3G)p=Ơ9$8 kUxUi|K<5"\8!{ƲԣyQ_K xK 1 @=E1ĻM" ;|yo3"S"uDT!vEnAdgz\Z[P;SaE>(]pfHBN\>HD'HݾLӫ5xj1{bdlb@cL:Gio?;Jd/c۞k9K|5xA 0E9ŀKdf4`:hQےF[bHFC Cfe1Rz 6[-RlML}/$B(a+>Dr򪷹3V ᐂt~>Z]ly ֥S 8C"<05 XDB x;0EޫpO3o$^@($݃iƺFZT宕ZƖD$R6>j\k*9Y'A@ 8;};yfV%dھm9ΣDw6pxj0D7)- J!BIzɬZԱ=__@03O 3cOZwhTׅf‹@ZeF@D8ͩ`m[\뚉 <# ,ܩMMȗK\{k_2q~<v8w 6L 3VBAXsZn!I~Rxe} 9sTxj0D{v)VgY29Rq&YɫX[F^C~ L1cF 3hxm mFj@nl g*< 4x9o!ZiO.6Fh1 <mQAB$Vax?rח]ޮ s.SN|SU{[H)禠΢0{vL^W`T} #5GȲ&$a̾ f{^ǧ8x'>S?TsQg킋^Z'l/r= xM 0@}N1{?2Lh6%Wͷyۊ%dmCBOZuP}@ 0BFerȆ]@aE9nE:\K.۶c:BC ֱ)sc *? xA 0E9En:.? Ԗނm4մv(G0 :f)"cDra9{R$eH zl@7RFv]ZGcW)zxΘnUU7fa zk‘U6"?njSvt\>at>mhRL xA 0yޅvD*xt7TVB<{+~ SԆČJ:LKV,Y{JG'BD8ŁQEZ lK$N^u^ ޫZ.#" 7rXQմ8^N0||[>@; xA Ebuӡe]T؆⢷ 7/yyUHlBGuiEsLjcwt89PZܻ8eOX MVynTxD 2hMH0 eo'G\5_\;& xM 0@}N1{d$[ՊtcL&mm۪*]X@肶 HgǩPfxN_FJxK0 9l|DB\[" E!ExH7U(^.(1)cDMcȃ YRIQ6dNB>Z o6h@c"8 LYڻQ/Uw߇0W69øEHB x10 @=b'K-*t q?YR0pjS.ճCqVSN 2@uDf耝PMT%96-""/B߷1P5Ϛ x= @Swc,U ?F!o^oy˷"A/+8`_yPsaT(Ddzu>:les-:f%xns9  7/@D%8ӶuͩإL1.Ї+: x; 0{B}]}V2E+=!} @f`l'dY4 %jpEq=B^>RmU(G*\ NW4ݔc>a0e$хۺ9V&66x;0D{b{ ODBec!x1En%gy=iZ[ lDf7!&˦O~ltf:0aQQmm J}\bR b[V ZI xA! @=`h)RhgB 7oT)@5@ScSCQn1u(<|V фؤf!) %$Z5?߻ן7c,1P͍}k;>5 x] =V(˪4h1 t^Y*1C4YȀN7ē.(e S:N!I/]37y,aeoR˳xD;>ҟ xA0 y\8XB%- AS0P U\lqŒ:2@S ҰtbQղ&>&AVQ|bP^6}VG'bq؋f];HÌ- zL3> x10 @=qH8#*ZRUa q?O3Hf*5 ST3QlŚah!='0RZ=')ʽpuD}x?oLgo}_?V'u>9a x; 1>&I@KYw WTglK,Z[#)kKB,(#zqX2P3bEuʭO,;PzIq}_| ?oB9ax߶a*6 x10 ;Ku*!'( ;PZG'Ѡ^h"Kf/;%"9_Y*O ,Sι5O: c tJ>W3#u^i0k1V7qc= xA! @=`礪B!1ޥgB 7o0b8*b&L,b`akDPllD{.dIs>_ן7VXyts5! xA! Bw/-t $Ư%ALnf0Iu,5THch]"Q%ݣ O0bŘ8s ދ[:IiQ" m 8|F1qm[ꊪ)/7ɞ xA @=`xfBM7otU++M *DY*@!gE]ayђ1d*z+P!:ƽu4n,$ŝҶmCٖe[׷8 xA! @=`礪-.@K4fdB 7o41E$m@* dli-HSpGZ> D5C+ў7ժrj_<"2 7ƾ?ֲ?VwZb5 x 1E|6kFlF,.f r2%4ZU\B.Y4$X쌢8FFf1"rQw O\aUkB;#RYץ5c*BΜm:^ϗ{hc6 =R xA 0 ~XXPYRh)iq} @0;;+E34#8ɚP3M6 x10 @=b7MJ;rcGT AS 𗿼ZT:7x!t66:QK$N r'" hoZyZjV?'^$ >>- x !E~6OѶU1y>)B ~gqOoElIL4Ъ<8"0@A -ƥKֈ%!u;K~){m<$RAjΏh뛣KaCXe9sk4biHB x1 w^ @T+ o~7-7*XL$IVq ^5:EƐ')z\W VK0f%'Rl5|g4_% bOLi۶ETc^[uK۠{K5?=x 1<6\N [Q{d]{{_iUz30 y1{o9X!>KkQ3WLi {5h}J٬nc)Jd 99Z/*q?R5ҍ+ o:NȓZZi Dx10 @=b'iJ 1p7vmPpn/oT!3Ryp{D-C'Bٻ'7 xS'G&E"Q$+MSq۽6xhQ!đ\:c(mX,57+p՚Eٗ x10 E";KWDK( ܞJ\Ink,RjR-T )+8Yr&N@nn0@1Taʒ4gL`<9y{ij_~zLҶ1:Q5{o~?7ڊK}LA~ xK 1D9EnL7^$8v=ހ6UeT] N+ D繺D/ZbiMֵ[M Dt.FS.>$7r 'Z<Qh]*lxo>]L//%D x 1E|Ez<&/ [Q{$n0^N$I 5U*Cƈ&s/bN3K C"-P,RMzo[UrAjȝ&J'32*޸z/86? xA 0 ~Hb[P+i)iq} @ ;; 24 0AȂjTJ-ز;jpB@`Sw47(}uRB{xO1N1)H8 *d&G6A٬~O.le "ʼI|y>j;tlC:1P LRa>?Bu҂E xK ! @}7&2Pzh"-e bn_Œ %7t h, ˌ[ȺM(ٌ6z)!!9HrÜgÛ5fBg'n"F%FŅxF`2;ߗ.@ĉDbo3y GjXD q'ֶC=yQ&z{}{+ ExM =~42 &/y3̆0ȘN22]0(dēѠKZ g\βFo -q˯WPJMt Nۺ.TPJKaȅn8 0Ou_FmDÚ xA! "R@bKKK4feC؃w?\0`XKC!$!&ZSA Pcw;O{/Dj,gEb`*ZcgMCW" 6cW^ 61xM 0F9,7WI2b5%Mނ'nAQ݁A!cK2DZspDYsY\~"ZܠN>5.\սvhcZ09NH,7i |{tE x10 ";N,!6~8jB:{*ntb;rv&)qg_gV P @YSi-{#"Fh>?MK/Eb{ۺ.c?R#E_6 'O.Pw\kētf`j)QH jWѰޖ@H;SKBK|5>eɹx⊫u*Zǧp 1hࢧTnDZSKC^P;ǙeoK}AxKn0 D:݈P.IA)Pd}`0xCS$Y#d)ƒ$,T/C'W%2JѪPzU,bN{o_Շ=d~_fݸ]O1 ?s铀Q2/'K x9 {^AeY)Jְ(Vdc\diF3.\KcBJіLrJB!XmelM81A7MtY>^ъt}X}1'*eǐ?RťHяs_5zmql? xK 1 @=EnM+wIEǑPxmo'hLIE5gs:8Խ5D̔u \TR-J U)3oǾ|1FH S8pc]GLubvb= xA 0 ~QbPٖPeY"1U*̈TT(R&Lטԝ0BFY1 [:kºLHǃ^Ӫt0ED#}䏩&Ͷj : xA bV(˺4B@?йe`zSSkW&e]\DT= 4 fqӵF;EWH(%yʉE>6x~j`hp#uY[+`PUӗ6GA x90{=ͮYHePHd9E~O$>4ӌfHK&ސXJqN=l<3#{!U;a腨y-h}>j>GD\+`IuY^si7G6 x1 !E{O1}QW!i)Qg$F1nB.^BV E,kzU'N%_gɌ\I͋Ð|@D)S1 ςy"ξ ۻVx\0\}]H @+B~J91CuKGřxN0wٱ-UTHLѳ$r\P$6&nf>`K MDfr*OHmO]tAqdZMԄz;ZХj 1 Z`@P!1EgYIIp帠=HlL˿| ΓKlZmE{/hC 71#"Q!יzלtqQlRtc.~,~ Ƙwh.O*ejPUdɟ°/q3͜ð)0P Zmm^;Qc xA! @=`2JbKKK4fdB 7o4ֺ9V(C$I.9Z֑wUxP) nEƪU XNq:^Wk,OPxn!D{b4Ӥ?X>|XS})*3s9vhNг&+O 2hD3o 'MQ`d}8S]+< (lz<[D*? $vb8 nb0#mkz ۑnVNR/TXWןxMJ1F9E-AZ^t3S-~ǧk*0-}j[ j)C› \ʧsyŒXyj4oDA : Nha:EU;~WXVYхW opzEn|*F x1 0 @ݧE#ɁһؑDKI3 fхJ˩xVZ3L.5A* 0gĚJY!I.$DL<47W ϭx/F,4Kklص4xA 0yAmI@K٠5\*XCZI8SR2OlXy&Gdv0$bOX= 1H&)̟VDs4ytnz]HMATJx/j[ƳiY HDpxM 0@}N1JoPH& mͫ 3UhUhu28tyS(3KiM>Q]$co1&-"!^[}sk8+-| 84 x;0{b{/!b{""rܞD\i^3z9D9ѭղkrդMR<=![5KBClx1$&Ԑ"bHg^Ggp<}ۖ9Uef+$O+ u9?xM 0F9i~^bآMKom_"N :S&8zhSb3dcvR:rfo蝳`ьHÄG R8aLm]T]+] W[aҤ$!KY G x=0 @=4.vRTڠ4=H\|]f꧀m +IҔgT&|mtE]RΑe-ETJ&N3r9a}7ן7>&fj۶j c@]h;:xK0 D9l'K>P* nO`6y4E`#(lavŅ"dCFR\y$leUXS4`CHE~:m&:w++'uDxAj0zsY%A_ƚ6k6=Kφ| })(v8%kZ&ZU u !rb7R&Ԡ̱,$VXns(Nzy1Lok HB?i|Il; |= d7\C׹YGD xA! @=`@KbKgB 7o4m )iHA25V 0&weTrOIjSZ`cjmϛL_7m{e<./6 x;0{4ƶDNØxAn!bn9€/4%c%}lKKVu٦P 5d̀_ue]&J}HmlQؔǤ}&s+'>bM|ơU* w*8@v|Ҧ͹G x10 @=biHة#"ZB@Ӄ[fI4$(+)S \0t_bW 3, Ucͬ3Q41{׾Xǟ'Roư?V׮m4YSz]>^p:x 0EٻIA\HAq#$#ƅonAZL,Fe.J=HRjss_yX#A/kcfG] `6ixj0Fw=ݻ\ZP0Đq Y,}2tYpN- mWJZ.`oe< lPVbik3xD84L*wQ?B_?[B$ԦZ+(+OЍ]mi솹IivF0xj1E{}n4R؆ƵI#"^,rSWft6dPcm1ⴉ|ndQZx%WvߜKfktLB+Vѷ|uT^可{+;MqwGܥӭ0Ln#Cѯ1 ?rz/Dϒ xK0 9,6]ġH7%v!%SA 4-Dnw002"hXC,IVKmp, 'g@DᢿSnڻqUi&0 ؠki>š x1!FS0 .YwCk|׼9.BsM`ԣ1[,5#-;t5=^,Ukb.PikhNy߇wן7OD)%)e͵}s՝鄹f7x=n0w*Y?ѢK.P Bؖ!)Is&p |VaðtAhv^#:o F)v\J8X ٧QZY%`v̅Q}RJi4ȇi:LE.'0nG Fh~|YvuQTpE@'oJhC_xN0D|4^Ķ@4imIm9{:{4ify f>}L%Y{J.lH⽉D?u\Z+ ? Z|;meϭ W ռ1H^x1k!{jƒ:UW";E=sET)惙J0><#Y2j:\@ JhAJZӆ%>A:ͭ ϿpDTzyrÃ<%bʜxIr%?x+ 'lb=P3{u}yI~AV0y XFxAn D9w] v] 7 [|H7!3V J.AhMѥ-Ői!'^KQ|voӶҝ1`]vU; "R<]\zZ2r!0G?]5/<[OY NxM FnwqDӄ ܩz|YWB%y%Υ1H^)yY{pӠȌ1LY\r,%SXAM& ".{Wuֆ|(ئ0~ox)H`?תc@mv H x10 @ѽ!IcwqWEЦJPoO%._@2G'G"~<(p\t0am\eUBoI<8 vv }@sK `u!9Ʋ,Uvۡi}zKӕ9CU֢ }5Aj xA! "R@bKiK4feC؃w?a.YAN$ͤkW,g <cL o})/pdls-cuǮLZ71 x=0 @=L`pw1"~Q[[iY @kr$) ecl .p"fA2朆q@bgYؒ\>`⅃:Cq>D@)ZZMΈ=;LQi2ovjig{uz>9|~u*_NQ>x1n!@ўSLXf)J{k` ^uZYBL+$޲ WlKtKALWK^2.'DI|iH%֚ |9e_]U>oCvΪ}2 ?ѫzj[GY x10 E;KIbnbJ-E?8xz e2Z@l"HNJN`UaHH5>PH&6#BA>:te6O<x,m]gw+Қ6`6dF? x1!FS ј a o/k^PV""7dlȥZkk#siT@TOdkrGaoޭ["Qbjje*D6 x1 w^ŀ U `[4"C~_~ 7mLD#( 1֤43ugڦ+$1a$؇L=s},~X(}^s9S|a5 xA b怒YMJqwI 7t.sf4`?gD(8`yf1sJMyHJJ>R^Vul[i KOpnr10q^޷;RPK=k7__}@p xʻ 0FS_b p1ӜRa T] #;Y'u!}tP9bc2C)( !=g-Yꍳ*h/j#x,cU,m/Ƅ1v{gjW?% xA EM=6*4d\xm˗Ƭ3XC;Jld)M(vl\DfG3Dy&`a4G" X#kmyM_i7X}:SE+'*Uu[u}aY鬾FD xK 19EӝNxtP!,/`m]:B4IJHNc}[P(0esɵ˜gkV:c*y/=:xAn bZ Uy *H]ZjuK%5CHĕwkڳ>dLh.RS)N ;7ί Y[VtV<%q_~좍YCT,DZ?j?w( LA v;V~[ A-}R/8LXxK DFh0ЖYE" M1EnGsMmTze`eR D7G&VdNN%bL{.`)lӤ`ukNod[לꎽi6C x10 E; u&Y*Bz{*ookU $΅N5D٣S/b?==x]0{}W1ƻt Dl $dL:"IOPIR6m1Dl2gb(6pś}儕Rv#Z2]"p!#98.֖s@YX4l~\ Js\irkrS~dRIx1!@ўSLoð,*fA` o&^߼ )j[iACZĈJz&ܬVjd;uV]E`NK|o[jH F x= @Sw`[!o^򖷦MT4Y s[jЁNS>zJY 5TdPTǢ'Q:sL>˴_.m;6_#6xMJ19E-E++Tt$76W0#JHN]L1y ^'cYtn\0O,9f9ŒֈƘ(FU|kp9K  *u]1Ur2d C[}>>߿##ijK{td݋cyGxK SQ(ghy@o߄^2|Ҙ$)xz}BgSI٤1 ]IݩJAZ=HF2heHC'\sax}J$O'hB7<lR+ x'3Ak. r,yK{~ -/yn]AHS xQ !E])#E{볤 qv:\8p9P289SldrѼ0z.AK*i4_"s&qk Ñ} gUkp h<\pJ}>폫US(c^A+ފp4{۫ @-xQ D=E:&0 I4en^`OQPUPmTyY3 BDsR: l1c ɩeeR*M 9zg4?7)N (c?DT>itOQj3{P xK0 9lܴXB\jRw͓5UC$/9~ (䥌#ɽn/,SD?#L RLrv|ڳ6x}hoo0t0 .qKݶLHo RVM}tq6pYDixIn0 @ѽN}7h@E%C m CD&cR@!'X:  Atz D5N>9> ` TVY kιJ g˳vƒopt8<&+󳶇zN xK @bwu$I b}Sz̓]N-} 5L CBup}55 UŤS`m̔љ s̭݊tx;p*m[Ɛ?{,ñoY}os;x wECb\ܚnORCqm x-kYi@*,2ZnDt`)*&;=)0,:v貱qLxqYWy,ѓ3^;"2)q]b"[6E}Kǵ쳂Y|xDx90{b{)!| f4#©W)@FHT:"[Yb0!Jg2Y{ ]W$3Y*1?@tp'1T<0} j/:xm+i4^a\p:c0F x1 w^ @I6!ΐ7R?[n93eGvZQGKd33SM $[KyDgC cY9&tȳux :x *m]#U ޤɹ3k0LS}؊,mS_C` x=0 ;Ӵ#!ā T ܞH\oyox?UaEF1ƅ )ICJ)WɒgwHקĞ0 kf^VsJSck I:<>hO/ȴ'}3?NJ=vv67k;^ @Rxʻ 1@>_1`iļDXPZN&Jxܒi:8k4K;f=JckNcHĤ-$:xR\ IH>ep}3L[a, ]ז"Xlu9rSjFS۳?B xʱ F)O`,E+Ǐl%R׼BF{v42rfc`l:2`\Tn(lL̓-V$3h^|iNFϳ&44zO7}QRw*N 7- ;Qo/O,@| x w(ĸMt75mP6喻Vn6HM0(*Ac d ,ޱbmdxC18֎BJֲ%R9?m*U>Qʓ<eYG*b~ aڷkذ2sv=lxM 0@}N1{7I"RP)ƕdo6oJ&-&2[k^ǺUT+f%YTLqYzFĠ j$]sЍrJ.)L*k30DHx.XE$>aq~34v1]'Dw x;0 @#%!i>*(vluS <љ]^0y!vIJDZ Yke"U(I*d-sőw9a2=.?_؜p;tc+o. g|u;/2yDAxA 0E9d4qե,MI-x_ 3՘:VA,rDrTxFPw,.^wmd!$ޫ\`zg/`1CO yZT]r@׆u{Eƅ}yҼ_>Fx90 {B=,c0G(clŮm"@HoR|! )K2K^sD1I nMf{b}$k$Us4H^6zSOp8pWijfWm]X+` y7-`e0K=kD1x10 ;4+!$$:vN@%V%ߧN6H9bb\REDM9z2F[= 6n8Zk;8J0sHZzg:C x1 w^ņ`T/D }[喓n3p:2Pbso$ekE[JE4堙DΥa %T1sS#wG) |pm[ǜG]e74 xA @=) 0 Ck@L&kǤ9r>#HɨGhv~L4YM8x#h]G`GN*} nQ;K8o̽jԧl[({k!IKע>C x=0 @=ΒpP  oySR,zZoԂCS-9F:QO()9j9![kN.`VxG#ct3\7Uqs;){ scw![= x10 E";M~XB%n\Pi- ot '@5ʔLJvkM({DZ*)L,dE,%|fM gk{df*/tm]ck8VY4 x=0 @= [.ĎJDo-z_ rD&zGƔrLYɳ!Ppȵ Hչ ڤҫߖ}aipy5""*+9 xI0 y\fW7 A! {*2ь.#OZL9xHbQjLU)dU]1sIir^\͎UO(Z3+zuKW@D]dLm۶!fkoaX hoc=íu?JU,WDG xM! @=ޅB])qbF&XMx<"kȶRF*ɅXQyCX_\"kI;kN;2{11~&.?6d:mU?V4:zuG*; x1 1"n.dAݠyb=N3f$i&5PժSiH܋= UAR}*F3b=n[ϦGD(S;NuaUyY"7 xI0~ܹxbH/maeCD.U@SjTS0̌ 6T*sR$1晅|敻o9D_HiD;$*j15pD<1u[y #5Ǯ}05媻; xK 19EEowLw1fom zH#`lv0d)j&Kξ葆M9| %E!\ 1QeVimp, .?^y'}L϶J׿~_8;+f괚7ؔcHP7pZ lڮeN c_3n~}Sy x 0 >qܦjZ>Mdd|h4& )f8KFC"8 K5E)ԄXFS^v {^~^%$Ξ7ǶsY,۾)|9ܚ xM @=)C$4k|o`X9VUJT͆}$sJۄB,zCee*c4 6 Gń 9} 79U, ~ζ!>n;x] =ž?IT(k#Ck:/FCzL4ȇnV9TlsJ%p)hQnhڸ(;ZWBpUN|sbK: ^Tn;_IBG }F xA {/BWFWR)M:a5q/ ѧhBFD+F81VdՋ<SM.+Ju,sC?^d7 &"FbNT?R[&mɜ7Yέqh}@0 xK0 =l4_ q'qT Up `6o3z"M y+J4cNeqX,i!7XM99Z HyL)ls3MoW2y6ү׳~=o ?}+>G xM @=ĥW(*fK]x{Momh@^y똌%lCAl:YՄb*5MB*w%npyFQ~X_2;hf[q.+a`E`)ʎ2G& .۔J'jt`g4r>&9ڐ<#SVD V' єl mi|?z/~3:T[7RՖ&fRNpO ѥc sayK3 xM @=`o .m10]x{Momtfm2)& Xa ՇD'MVyOZɒ KZ6-\ =R㨾B x= 1@>Hoɀb˘EvWB,5_z\)9:gJNHSVgdV 0xG!F+W/> K[w%,`W4i¢,?]wp<_q9R xA 0}N1B;1Q(̠$cW6?|< B6Fѱd?'x¾YB !7;U"aI7t!zGIHd3;ρhйTx%s/й! ʺ.Lܵ@-.7Xˇ3\=ƵgC3Cd xK !ض6\e2!>B.Ԧx9Dj 6jdD6)!+yN< 꺑pDsՆT(Y.&:1&p9]h/uR6x=n0 Fw{Y"D*2Yk: ||ܤ h Njh V:`PLvRa"L"= W! 5I5;cu ͙0$%˟2 ^zb(WWXT b-| v$F@K[Gϱԇs.t0~[~xƵ6|vo*x1!E{NAo&ƫlfp͊ۻyZDłK<(EMBg!yp)xx k(C)8kD=}y0G}&Zc+/jYdZyfGϾCD x;1 >HOkK8#Zve n`̚f;0F8"S Z^˳"GRMu9g14O|j_<R/ᛓ}k;e>26 x10 E;K:u+!&FF.8 ˓0 ˓"I mx4&J1gRb1{ZV $$w9XZIP쥲V]["*NnO}v|G=Wos?R'4vqW.yacl HMxn0 D|+U `j/=!QȖnH3cMg(V?4-Y{mWڪRM kR5{j,%F{уy#:hQבŋ*SqYB'gRЯ5>nW,e;#|(fd IJ! { w!|| ) ;Dˀ'x &E\rUWH`Yx= 1@>& L +Fdo|׼ޘ!R XF#r%XI 3( E<"Q48/ &m%:g z6֚QDǭwc w#|,p=\`F!8 u+M|zܖ!LF* x91 "=㜖qG *{"fF8208Aiq @!DVv6OE߇At9IZ R!,VPSk2uA ),L۷*<:t5xN0<4$h()@g7 G쓽'iF4iD`W8cGĬ ڜ0F<9lc-4*~F*Ikf.Iٳ!kmpL  hARM6H;;d,}!DVr4A#R=cۺ:QAw'? c[|ɛFڅ\w6I_ xA! @=`(mbKm4fdB 7oT7@b)BL4ȂEw$Y1(U),I"sc D_7Ǿ??VwK}6Fx?k!{?SN!I*GpmxVnw%ܷ!_ bYstOdk"Hz$&G=2VŭCdUgH=!$9 }. B󟿀9cćX({@Q {$xz+^õ,҂R++9Ac Qpa1~Vx;n0 D{}C MѰeh, dy" IB 6kD_^Bn-&E]A<وZHak @ E2mVtux[_ 蔼Gg(c?TŻ9{u d),ɵ1'vLf tf]Nꅆ_;S0 xA! E{7Pf$ƻP1ao/ۼɟCjdB/VҚ5l AWd^R)5%4O`yqW(!=erE(}^pٔBp&nsK l)|ǣ|U<%xAn EBB4q:hHӪo^}"(!N1p")KSq٩˦SHcgS`C'^hrChWiY:,b~fnZT%ádgܮh}ezV-{RIK NÓx @@s @ѡS (tqv65+ދmt: q ZAUd1=2y9 'H(Zb7Np{^&$ш֦FP<5FcUpuU5uy:f q"w;q5Ó uD x10 @=b'H8#"ZZa q?3-qV*Ғ$(%8ESaU*sF%5_iɊ>5 G*!"׸o<[?o@9OponֵaNk K?l fݵn _&΀Y [ll2\d.6Um!wS, @}6ͅRNF@ ΐNMvߪ~|6Ͽ^49'sPy[5cU<ms#:| x9 1 {}˧!mb> @f5E,%H$]5N@XBΜj.<,*)S^c[V ]1|}.~XGЗ`o´m{%|u6- x1 w^`T/&8*jT}#喻9̼%EPR )b5ۧV9I̬qM0r< k=l7EPX[ms{kk E60 x=0 @='vJVQ:p{o7YvDS6++ZR^3opeNT2b+ a|j#^"@ZP/[}sk8i>\h6ٕx10 E;$N*pV@S 'URO6G6X*ܷ3]0kRy>'U#Z%dm)#pλ1ḛ֩0p]rm>VDI x=0 @=b7͏%]T =oygS1*.Hؓ`Q)2/J Ԃ'k,L^k}M]}LxCt!' .xضAO;6S;v_T8xA0 y\Ik q 7uimE{vV`D #GrM 9n# )&F;a'Bg :W Zjc֘eV?TSDNO~W`K^|yr7obD4 x 1 D޽$ݦۀ/mEѵRފ?\fnUnUXlU3C %DJ+ ͽJI x(9p$P3*tԺ?W$Z?1쏪S{0<3S;$5/< x=j1@^>L,uTi c+·w kJQ(%u5&(CAnᇇ&O %i0jXP-*HD spytoL)a-h^ܠ:fo7yv5< iBq x1 0 w{۱, J-%u0'lED \{gp :SMK noS>4`i%q % *W-jcY]sL>F??|0B…m/3c9McQ8x 0E|Evi@AK"mJ{+g˹pjaI畃.RŠEݵEsXHeL5G0 I[}"{&.ۋDg4U+ O$?Q5cqp)#λE,x 0Ф dw[&%^E;azciLdBCڄd'+NOVۨ6l\:!O81#E/I8hmŠpKmp{V/]6pި\;*$b{-3ԭ_km~+X IH x90{=o{%_{#){"ifM#zS|,H5 5h rTB՚c=ǴsL{awP]ZKXͱ3.a67? x10{=͝9 y- ,fftS1b3+A%#i)Vdd%];^CsN FKDs49cܷVg&II`ζu}?RwU{17j xK 1 @=E"$ĻMʈ3۫x͡ AJOkT5@%G-c"R1;}N(RTl`*sؼ͹F-yïl&:D.Y8ӶuͩETh>, ,=V xA! E{7@ .јq 2 o/߼{ɟC,ZJьXEUl 3Kݓ>&`\|L{½,Y*i ,HglXZxm8x|Nۺ?T"*-+/]):/xA 0E9ɘ4(˘Q#o-7U kdcRժֈK,^١D%RJVq8 J >o M;i@1şһ:f`ZӴ<'x/}wm}Y@6 xA 0yE"$flA[I[i#1?\Y>r 4GrHF+Dڪ \%F iN Y6&Z4`@)[.E>HGJnԊHy(<7e^^LrzΧc?/>Mx90{b{v$D36.%g#0L1҈&3cežLa.IX'S6Zu5WS@c̮z:)tV!}~1:e]p<"N  >0vxBiBU}ygD xAN0 9l8ip lmxٌFϚ*9)/`(JgR1/qd?H=a) #I0fJ9)Mn6x+x?\2O5'uW3ߖCjk* IvW8W.} qB~͠Kv x10 @=b;MK8#*t q?{ҵ'֋CՖzA=e_\KPԘdmV"dJ}{7./-m95t Ȼ7y x10 ";Kص#!خ@n9#R*Z*,`",fik,Y5+ (STe5uAm$V}g7-$&*/$m95k-|85xAK0{Ib<)l$aiZYeeϾ{|Q0cWl>o[ O JzNGk\o)>.95P=V`wXhg "`g^5gອ=l\xKn!DwY䣆nzd.(3ɷXyڔh $xMȖXQ^$ɟXde( fD)tP*MsmsY x=&m[f!u[]2  :ww` 6Rҡ_5еUV xA @= .mbxm誠u Ek2K(W智O ,N:Y7CI۸py"HLn2ں^z Z0P>`m>=Ò xA @=3 $ƻ3ƴ4HM&^y?*U^B%rK1PPmjy>!x*RI1Y <37*sǻs ԾmjCTw9* xA! @=`-iK4fdB 7o4 rbݪG**h`i enXpîе纏61@9XXy(/S6^xʽJ1>WqŔjAb{9I0awg^A/ygtĐ%aFM9p`$֒ء gfN\k'̰ܲF?ƺw:$k9 O&kFKANo/ק3ԶVtn.m;O;`iHV x 0@|Ł 6i'A] -FB{ZD@eorD!6dcRw*2WֺG1\g$$CjMQ\,?o@ktKbV#US~ CΧewܞ`I,P3TjPoK@Y xA! @=`2@bKm4fdB 7oTj# K*GcfMlZ> Uhѐ ޑ"1sCLT!7Ǿ??VwK}65 x;0ާpO?'k qDSp{Ӽfp4+3)gFehJ)[Ia_3ZW*XEu*Lj/`}+$9|[DUD 8^[=?pͦ4 x1 w^ņ8_ 6jUD }#冻9|LYP刵%CPh[F.>M$*62Tc'|gW#Gվm94u_#6| x 0D{$m7IPлl7[+VB*9<S*XϩCDTyqEbhdu*9]}Hb/fW&Yr}@K 4X5Fq&KsxieJC{9]}{@X xA! @=`-hbKgB 7oB*Dfh%d9sZ~24#a`T:XBT*QO|֧yD$B \۷VcuaI5xʱjA~b"9 BQ Sxd]|kQ+ctSC1'5T)9&ГZFڜTfxHbҽQW@m#70?V3ܠ3 7 xA! @=`礪Bb gB 7o4ch4@`&")w Q1IE֜$3idH%F6#`H_=ֲ?VwZ G4 x;0{b{c{.< ܞH\(j Z| xaΥ{eTuR,Jh^5KEj@Wt|g~ z|Aod-M GG>gm#5>ܚ{7 xM 0@}N OSIVFt-xm|`/b_:-K~1Nx*ZOc<|o9K.-R!q,+T^6§UNHLxN0D#Uk-ڬ7Jܠd+chFo6UHml[} |$cΜH}W&bFpDC Nk!M}ͺ?)TZL |I I\NL^?o;Px1n0 F]m K ohmڠo\oW @nK#MLj=]V nO[%ZF328F:v4&봊Q{UJܗ%bOZo45>iʥT9#qGa@u̅z70SNݵ_OC xI0 yEH(/P(M`.s]:bB2UD0%ucA&]öy4j B*Tƀ31uv{lwX0=ef87p6 x=!S|#?. ј a&^ywMU1wFI.t4'p5] 칐f}*)V ܵշc=ƴs4nS ^Աmϵ{|6/ x=0 @=ԉJ$VQ:p{o7Yd' K\zGRieZWs✀ pa{ƚhAvM"+z\3f(|j#^bJ@Lkd߶ǜC4  6~ x=0 @=Β'v$]RTz{ogS3pPkRQmƨ@֚cn=DZO}Z#2r ʼ,,Dqy?o>PKxlLX]Q6>^8x; {N} E]b+&D.|XiF'̬&i >S-vxF}[fL(i!Twq.hB&jVx:FIl,5Z7CUH;r~p۱l=rCy/$I xʱ 0=OK .ܤRZ q|[ZT-c q(^C&s38aV>XiJ> "yGfxy-^EY QDnuYnDTlwnqå7|7xOKj0oR(O C)P;Oܾzj#VepFZo@$x;07kՍ+FW7@´ĉumF{J_"tv6tXr[?*#SFu{z'DJSyI|DTVjmgdC~\3ŧq_^ BSE xK 0@9g:xi2QiH|yUD&'Yd id!<>$i=Be*E PƽuX?-kWpO| dLj>?Rӵfܠ PeUHn='<ʒx10 #% qJvQR[nT!%) hERysuxXDG sI{LNKmpT]1\kGj p&z>뜧F-)6%^b)s)zxU ѹ&- Ec&s¾*jM)1Yя~ɂC /xXkb\N齩 @h@ׯsi )ߘ'tee"m2Pt_^4g N xNK 1ݻg M"ct/`6I xe94 D2{f*Լ9lDDS(֐ ƜӰV5[n^~|-!12aJ۶#j:vogc > xA bb\l+eՕ- \fzS(.JR"FP$oy@$QI&M_1x/iyFR|TLe4MF} GFD.i֏fHOc;q>.]Eقۃ5W1$IkZب3QCĂ23 k ,1j#%\}{6#B*\_}k;.˺5{xQ 0bfMxdUH / UQxF6!;I#@lb/ޡڠkNH8Ď8&yE:&Tx%Io{e[?*!`/ G¯Pv@XpUE xM! @= (Rh3?Ak|oP)bES%f5cFiB5&|戎H#,Iܭ-s.:Y1o̩< t<}3g8˜xjA { yBC@ N&w+^*]VU!LC sL:Hyc)`&UKD1% ü#dőE"'ɫNVnY+<] n'5m۹5:7Np^ǽ?_%wݬޡ 4­zry_XNx10{b\a,RD@82"~|ঙfiUCbf=1p;OV"v'9S>Rp-sD}frަRq_9<\쉑skT]˟&^hn^5o?fT(s|cK x9 {^}XsJQF"c)4Š .*4kU^Š\dM@ٰ8b:eBr#OqNYKS@ϱ Cj^?Vq-{[ vR#aWBxj1D{}q4tVNA'#&eYxՔ@a"Zd-dh1$jɩP R6L^\ q`m> P3:nTnSD=ËbZsby)6^YKNԔ˽G k׭7 p>@ {[xJ0sIOI@ ])ʶ{7% m"Yo棄*#YYKeeBZ5GTKn/>u@25Wn% rے3¶>[L&> pڲUUSظ -s#J8Maq4kSBK[tm!!RȭӤw+LcjnqEH:—8YcpxNn0 +t$,h:.lC/ v%$̙yK!QL)ٔ(/Or*م#I!GÛ#hǂmS‚/_7֬.nZ#: 0 95tV >8>2.'T2kp-?JPS xI0 y\Iq\"AS0FWUH29JA1Y91{=TLTđy򪵃'x̣`BQОW +XQ eF&7m?*IA <ϛo>x;0 @[. ʼn@|a -oyë*P[j(HcJCuQ#lF>]+cvцH)cb̘kb4|a;`l~~CӠ'7&o2֪ET`y/ X<2Pl* BY xA b^؅BMMs$36U SMqv֦D"cBf :5/9,yDVQ-JSCX>mǧmdLn:FJ,vǦ.r 2>uxK 0EYś;IЩkxɻjmKwo x'n[2. &S+:6G.jS#3Rh={&AېzůvWz|fJOu먝stTϡ5*2oېGЛ6%Qϲ ih瑯WG@ xʻ @@~b{A5;; 6VcAc2) ͑άńмC8Sv=[K&$SZr`4vp1/ !6\H*~ns| A7UiEnrK.kMK{߷:̐ xA {q5 JCd:9Hgֈ Ţ5! 5C*.RR+u~v0p#> F_8Ex;0Db{ז= `mI$!nO`y2ɻR ,81@ɧ⺙* JAFg`bTdZ!d6*\S _@JaCШ-lĒ.M<\^TacB1c44”IkŰآ:`vm[ޓ=SXUp9;%eYJç^g'nqÛ}aR?*XEfK~&Ԇr74>5Ir|S]/ILxK 0C> Ŏ 1 m} @x &5)lY$z3ȘI| |Ja9.}3'G,X [e &S>sgip1i\쐡}VUj i/ ƌ>z_P z@-|/tFIxAn D9w]Rw<$7/Po<7(N)Gc$G xq -ѳ{80* )|欴Us ?z£mU2>VMfq^U!ۭD{V "~m{O}` ;ΓjkC:‹g9VN/!Zo [LxLKn s"x*7E. 8Jlʷ/u/YG3̀a:Ƅ}![:ZcYʋfMH>D1C"=41:EL}/+|`qNA27~cRY>C e [k[nd6y^/v(I x;1 D=qK8W ,B L3͛ 0Q"ڊm)&^s5)XMoX[XvYbBRl׼CmPb~mNuj ź>!7xQ0 D} v^ DUH{vyfȄrxR==bjbJ 63 #J!>K|5zn;n౎bh}.yP51x8*uY&3I&AhmAegg=j°= Msx;0Eޫ!؋팓l#gR{"^s˃)%LVS1'j%BNJ,)dPƠWEOCNN Byep҉x@Otu:ӫPE:>nXE x1 @ѝSw16`Q*%Bd_TcXRCCcɌvb2Sd5(]j"!<DZ\7X1M|X G"722coei3_>4xj0D$dBJ=^a;6࿏IfgrIBkDJ.jWH %ǵ-םE_cKCdX2\ OD=-<<7ǟ7,| i[߆ iW@f;J x 1|g]."6 Z&٠=`c4|p)he]go#zQ'EO`-Bx`x[eN#5|qSh_B?jԮ= xM 0@}N1{&i&?  ڦz{ ^o67`-EN$Q l\L,9R4thG <ځrA묱P 'dE>Oeip hgs.AT2.AۓVs]]r#ܮ@Q x10 ;:q"!6'@PtTrF7Mɧ9 c '8fϭD p 9!V_VM0xbdŷ6nkg LpǕuYc˵Z}n]! c9#x340031QK,L/Je`ԙ$ls'K1?N)kQtE76Ǭօ8B8g$楧3/_`VImT_+' B#o&%71;5-3'U/1W#D@ ͋7\<Ulٛ.^s\WuГ0yM!a V7WvaڶMrI>(C:2إf/d}+N+`X.R֊s{e)]y;E=5s7BR~~IqIQb^qԣsuH)$HMKc ^Z dIYޝg}QW3L @!%Mb/=x} Wt~2e_}y=%B4{[c!y ږt>=dᬈٕğAdzz$]_Ezh-VmFx340031QMNMIKe0W7[nR]M?= 21ԔD+2"YJnB),.IKI,IK,-`X+'R}nrTїwy`G/~2δ7CKS2?q2ZdM5I vL]Q~iqjQ^qAj2H^]~ SWnҗc x340075UHKM/J,)J+I.NaԶi=UmS(%3xrOú w[}d q6gE,\}7aڒTM.Ƈv\_~Di`Cʨ x340031Q q q7/2+HIcܸze伥_fy>!.  ?>ܼ:O<<x340031QMNMIKez[~)k{m&@gm; V~~K2Xjo =y?:m C̣Wҝe24ҏ{%;6ᦧxy>~554m|AO ޯSL>#k%i52n ^!V*s:}+¡қ%tlņ`!W&_Wel܋)&A11}mM2/9 qbszTD4NX yS>O!ńa.QIDT=(Mn|W@@ m4L0k5 e970٪]\lS_A܂K! h2H0zS^si>,M.!dƀ!NY]ֱauMD2Gtgc +L?llH]K.}7lݤLҊ] PH& AAaץ|a- dC14;e?Hi)w]P¿r3Ol@v%ajww-K{id)YjʤF,T1G2d kW /Z˙ɘ8c2)Ioveo[&rL!"6bS\08lJ/ Ffn%n\ܩ`\:J8x>NQ7W/t)bNzzXVlm3 c#@gg\嘁}:Ux1cɛ-'m~ +l 2]#| /, 0fRh؜ŢTG־v4JVi$)LXo- &ǗΟUY܍A0nsx`%t3i4r˧V0INUϤu!#Ӟy.uH:9@[m,cGuӀGC1Kntb=N]ZzEqY5=nW%j`{pw1TDN/^)0h)RR̫ɘZAN~N==;y>7 #"v-E#2*mgm1dA(8^OœѤMىZ=ORhMsd R8a-~w=s2w?|鶥IвDgݐJρ9# zR48:]&l7" m~Օ[E= ,i|вj#:Ou]4~C=z#1+_ǸWzg6Ř@-W;ॸPQ'+ɰ8@Fɢ#9U*M97߶W1*s QrZyH-v afpTx+m8|00*J޺V6Q`阑I 4gsC=0,vv|d0iL2gGwwMM2btF zp8ڡyCh퇵n5 eL`+&Q[բ >EO9iػ4{rr?1>w !LdK"U]B+F[)DԘi;hs«ZUvI|rJ`x v*;ԥ6n# &K!bcfVc{r~MPȋ{YmO'@<57}K)Qt0g/ԬGz>~[3ği nːGN~91_ 5Lʄ\%;c˽l@q]%p9e4 Bg z:}m/$ГQl㡍t\^[vQ`\ѲE;2_s_paHLI,;$nO^UMgDhmS\F, W#ǁ%rWX/ ܍bkL;X-zc%RK&*H/G h[D'tOqVfo{ӄyYBjL].gNn߷@,j8p#:+w?F[Bb & Ԃs)\@\x3t/{KU}sXaWJ1ӆ.[N_?Y`F@+kIѦ:rVx0[02;eZ! Fԛ+tj{;*BE)w. ݦ=60.z;[Jܰ42bBmbӿ8w6+s/#8:WQÜW"6)䗆=ĝ[?lqWQT" Tc/e4w%pMcͭ5?opnm}Ӆ{#Wmݜ ?L̜?UE z$17*-dy-f-tl: lRα!\М;km T/\^ɩދ'4܅ךIh^  {߷>vQޝ=FKI=%%)bIL ,"; ZvVz{6O"Rl, iKc}ي򟒥/OXدh6mQ!X0qn$.W~ 'QmI nĈKEkdv#II$B QZwrۢD4R-t?3#=nrH+g(}GgTW]/b;hs<XH7ϙ1{LIljřơ(EJnq"+h6,jq_WIx340031QHϫ,/J-ON,`0vulY2XmfBt$e}3fh0gǞYKϻO-O8gw\ knN=G׎ u_x;˭3oSJ23Cե$&$%榖~RS]DOy$&Fi5zp$pkjM}%^Pť`"-m,{<7^>_ S?@dV'&.;W;ovKkap0'B]6uܦ,=E] TEANbIZ~Q.PՓ)%J~ -|yYg@UeeBX>@iO#W4,fx340031Q()`xgtv&sb7onz uʧx340031Q()/-N-*` ݦHf'!TU1HΪ&*lÇKED;x340031Q Lap]ѻ2#+ ([J1} %%Iz  \RNH( Pn[ UVX_ T-SO7\K UU\Z Tkoɻ-׬Ly0-.YejQQ~P]Dmw-t:6 Y]qIQir Paە{0{뿲vd%@*g:&e#մ1kp }zS:R? uozj <+\W~zL}_&r7}y/.IYI 6}Sbc DROg:ß3>v'|{y0))9p,9zM­Jv^$/ERX WAQixwn^}_ LXdZ%\EOUމ{BB&ڻkD([uz ]_L;n/:!)/JK*sg*ofSeuGd%KYvr|w+\rT-U]~r=r'(ERsܼ3?;,>)8PvL=#[&qF"FD/oWrv:gΌyzH {$/kO/&k7Wxe{8T p4m|3M5)liєGXd5)f;3fؤ0RT6VJF$jیxRj{w=shf( ,HGIo^TE, TJs@3$V tm[ie_ߤ8Wp#9:iDUJҖr )&ÒbcW}]gه{ _J#$sU-w/ cDl#e($Ǻ#{mJe05  d0 $ hK \TvydX n67LSXI;cنU"! lh&QSGu lӛ8,C4CP+1$bת Čwud}ώB9ק01٠H @v, U~i=I R×_ib-S(J.!dkp)ʫ &VWH*Z.-1!Bz9Ց-dl*Qf;5jDo{/W.w{H0y }( *"~ϽLv8=*fmZ&TU<ڸEVPH9=IԐO1ph12@%='J-SR6MfN+_=k ''QGA4)C2|Q 3\k#j^<_ۚAW6#^kWn7|?0Y 캃w诋ϓ{/* iWgI~TÜ 9oL21* a0AAð_{M*D?V}fˬ˹&83Ouǁu_VZw`Ʋ-߽L*)/it4Nc-5lPhF57bE_g Vİ3ߓ.tyCEjRhnIljB K[tLZg/*相k0qKz[ZP>Oܜx&)2)B]zRe\y QNuy %A:xn|UYڲEDcH%RHf'۬Әv=,O.'/x31Լϧ`#aoz%Ԯ x340031QH.,(KfX"uֵ'uGmUMx340031Q((/-)Kfޤ(V'#oܽM5=N{BT$<) &$<&19gjx31d<;/)>}f]] Rx340031Q(*HKf8#Gcy~+ϭ)1+OL*c(x_{bfnsG!l"MS:gۥ"நw]ȊJS2Kܚ)e;w/e '(+2fQqc-qN#T%eUI eqS$h_E^{"$Uɉ@U[@uQnBhK rAnSd&|3+|'p_GQX TYTw%V:wDU$)@Es `&C?ȊRsRKR*EJTouL5w,~ ٹ}ōұYo?}avHRA>-tȉgob<d5e9@e˶8,0rU׿,3($3μu³;~ʊ|{"GV^PR-]r-}ΉWv!/ͦ߱,G f?O)d]]ɹ9Df١IQArQ<0S28[.;ZPRwP}IHG)7&4)|pd^(Z8/Nj5 &褺wG(BWfT(}z߂{^-HRAF,0y™G|ZhQ#0 &U]Qvzʬ>= pل*'$aLmzԻj9}꿽\ Ed{麨S3j L/i鹵M@RU Jo3:P霶@Ga΂Ȫ(./Y{aIsD\& ڨ# x340031QMNMIKeh0uU6[Z7D!DYANbIZ~Q^2ɫlrgE,?*.+*LI*zn^0֩q3NC$'-eo/3v38_DVVQR T9+%lȴ72pRox340031QMNMIKeHs_s]\-fN7(+IIKf3ZI 9۸Sz˙dx340031QMNMIKe0s LӿѸAb PH.,(gk%ѻ\/ngz+bNIQ~iqjQ^2Cy+wVN,+ x340031QMNMIKec#9[Vl%Kޓ Rs[^aS07Ãyo\5x340031QH,KfÛ}ĺ<2>)!DEQq"PGI_|T0|tfNԒd2CƫSd{D>ەwxZ Y+֠xmy<pt-C6dI*Qiqo$Ƙ3cVKRJi"" g_Lʒ}$~=Ϳu}|ib$(2xӑ+dMݖ{4hC`P(UEno4w8Ϸv_Sȧ~A };c k$*N7*SWLF`ZErdP= Pnu{weq T ˄듎ڛ'roY^a[лB(^ix&Za&Yy1aI(2; Ms{F׆b3K1(& KZW] "BΫ~=P @m-7snV (7J2QȚ@j7 P0p߱m^-Nv_/ k'LsSR ›G'-$&>gLYeyXO hh,Iˉ|"԰X3RN(:TIFt-O 11RQQv"X օv'V~(92pLۏmK,H!´J-bD \bpׅBVdE@>DXbb!)Sj,01#2scJ-]nv}Nbqvqa^ٻoAK:q|JN7uu`pX&ғ2=e1oǮ|,HLF.KW#q2>+ke JDF(pWppε5ð !+͢.v;hCj\7e3ȱkK v(0H֑#\8:] jr2by^_E U1\-D)bVAigxuEdbՖr&w*j<培2k<( 8$x[wxt1hICQ7~KRXǑN- 7;Q\vΏS fШtUdwRr_>aW+W ɋ4#c6<6q]8g+SaeOP4}ŠClʿOUm(Kc%Df[oz^Q}ysCZ#v1m V㒳?(E񿺁7owێkIͣ]JSųm~gQeHYKy\tsJ\Ӯ# Ӱ6u˸#I#wKTow~[B ͍x0gOP=Bkv_C8O|Ca^gɆn+[jUuefts#?A_"G&f($Vrs{†l]wdzxb27ߛ'L|jm h|[ֽ,GUAZҽ+foM jԙy0jHRJTȖh*>ָm_N˞7g ՇsaS?#]}'+ǒ10UT\Ǎض8;]r?Z'i3|sN<ظ٢M*ox+%w<zMPB0j)evL=_AAӉo Rdخz@N)&x=Se4׬H,Z9vCAaqIs1nDV6qM: ״{*0wB^ESqBZJu4.k\?1,%@fAƝtі!#G#WE_tYˀ!3?j,0lC4Վ^?ȋӍx340031QMNMIKeؠs쵲ަƴ@023JRSĞ<󸧱an3{OQWYRYZXV7ar;qvBiIIM*MKf2p2ǧ|r*P^;7g gfZa_A+I/'BIjq mSÔO}N범,3x340031QMNMIKefxh}7;4%8y61BdƧV%3?hy&X3Yf?@U^&r N1nP*}v+x340031QH.NK.,(ϋ/J-.)KfقmoH8=rnLx340031Q,..MO.JMI+LKfeЬ~iW{yOQu9H32K +wX"n._Lոʢ*,N-)-ty>3X}|^]; UZ_T\Z\_PrC_W*Y{lۻYU#i)K-LLN,%(ڼP]YZX_T>+]iEm&ۊ|Q&*/(M)*S?”=M5$oW)jux340031Q(I,I/KfpeO֗As?V. C YS,7_iCYH*3$^e4*2Qq}i=M-x31#3z6ZT'yKUOVC3Ԣ̴"d5ok/Χx340031QMNMIKeXT$wGOVYDHr' x340031Q,.KfHvV/ksj x340031QHNIJL.Kfh ?y*ﴺn,|V{ĭ ѕe0ȟJaXVd}JCha>;̼ԢTi&pSr1e0 WfRi.r9_^ Pey@jf,^}%S≤N*K Jr3f Za*(.Ul ƶ5&||쁲WgLe_8d6x340031Q((/-)KfhVxTLF.R*U% %[_rM]pfv:5Kx340031Q/.)ILIKf8r#dǹ{g W=!DYIrq|bA&PkLO.|Ʃ/4fL&@RSR ̻pG+ 9]j,Rx340031Q(*HKfɷ o(lD >1%73lճC|}zƄ[!+*:~e+^6>pMֶȊJS2Kʢ jx#v%L *\H2GtBJW~Z*)3/zD3sn=dvjy 6$Uɉ@UԎFZ̒^hK r*;Ãpuzr}_#L-*L*sFvŢq瞝0#1/=-ozYnI])o,&Cwo+t]lo(?$|S~:Yw-n{qeR"k6^ٮ5})CRT)NfZ_#[ڀ(5'5=$rΓvV];;xq")ʗj'X2eIQ*ا7'zVļ8W7d5e9@eEaq+UStuʖ%5QlTP4̰զX(bY,YeHr3@aVz{J5Y3Ē|PJ?'Ul],!O;چ4 aKsY_-?IM~8ͧ,ԫ~5Si CVU픢 <sT'{ (n7}"e=.n[og\e2xERSXӄ&-7O+3vY]ԽUjmܖ%M A :_Zz\x쇠h *Su#cKqq@U9i%ŠY;[I˖J__Yef:(woo7ZHJ2A-gw3D2ۭ "yB& S엓}Zfx5IYXY3sﺱI>x²eȁ-Pok:y/,x²e#=<.Ms Bx!j;B{%۰Fnwx340031QMNMIKe0s LӿѸAb PH.,(g8[6hrQY1dl1(8X/!fU;dt+Ey'B,&x340031QMNMIKec#9[Vl%Kޓ Rs֮yuБ6`v;3_Mx340031QH,KfÛ}ĺ<2>)!DEQq"Po9;}/D9TAqennjIQf2P!U)="bX[t;< ҙ* xu59w I]O VR&e100644 ChangeLog!ˀ׭ZZb?$ഛn'_MȕBzs[!r c&lN_;=@y&6x²eHEEU/S`FT0z Rx+qR} Wʙ<‘<x340031QMNMIKe0s LӿѸAb PH.,(gLP)7SZso|^qWC9%EũEz 1;筺g'ӧ[/;)yx340031QMNMIKec#9[Vl%Kޓ Rs޿bpJI=%:!x340031QH,KfÛ}ĺ<2>)!DEQq"PRUnza4If՗JPŕ%E@e_7gm[+Ȋ~;[cj+|x²eeg>h^kz+&kW㤕 ]xRS/cHNA[P%iEb"gJ3W_ `rMT?B◅E40000 tspi'bE鬕kՖh$ x.]pGڀ;ݼ8T豞< x31Լ׶ޜ ĉWd|w{l x340031QH.,(Kf8Hyێǥ\f}x340031QMNMIKec#9[Vl%Kޓ Rs-&}dp UgKx340031QH,KfvȪG>>qQ+gwjfCD/.ht1/' +ssSK2ʾnڶVXvǂ+tx AfHw!'BUYg|Bx6ܵAIp.rP^v2D};"; |~`x340031Q(I,I/KfhY_f-τ>i4*I-.`{5'ry>">+?3lˍMo|6J.d9*vx+/,"E 7d=`| dKZ bx²eHM>JnRix6 Sx{qB͇%K|[ Xu>Ķ8. x;xqHo vd^nϝe+ ax²eH˂5˫Xm~x²eC#BF3)yQI|ٷGͱ/{ynJ!n5x²eF̼(gMx'in\͚%w}UP'x340031QMNMIKez[~)k{m&@g`mc+GvY޽\ڔR#}}cPi+7-b4-K|~,9e>xMeYBߍ[gN] rfx]&100644 .gitignorew4*~_w5*o_&=R/UUr&Ǎecgf.|V i2ũ-(lx340031QMNMIKeh?kdDX5M @!3/94%aҧn=װРNᔦ/% XX.}d㋟ MaXʶapwImN`ؚNIaXE ΕbK.WρJd2̑PbɏBAһgz\曱tW]e^=xX8~H7C6fœT)e}X{#!p'CG-*y/(Vx &=x.]pBHZ7EI2| 7rұ x340031Q((/-)KfЫО:j%[Y wʧU% % |Sl| أ x340031QMNMIKeP(v<c)uj[Z:س ! rKrvN:pO/ ׆*.+*LI*zn^0֩q3NC$'-eo/3v38_DVVQR T9+%lȴ728MQWx;^v +NN@@~rg ,1߮x*V,x340031Q((/-)KfXuKXdEV̥F*ތ3*).()9+L-6gux²eYjݞODk 2x{qNl 3{v}D xvg%nR]|19WX Y}x²eH|M \Z->U}d1&9֣ x340031QMNMIKez[~)k{m&@g̰jk_poUM)F*Ơړ3V|oN-K[0Fgi48U{ڍc<rxztU٩TS_-x31mGNUs>\x[ϵKD Y/a 71w\S|?Y8x²e:]ke|4jx^M( 5x3SpgЕ N@gi48U{ڍWjx.]pwwU2X{k\muK9N^x31'3Rs=u_ nSx* !100644 rpc.c0XNJs<ֱ!F1x HԽV L]x {x{qBGU{^!UĶ8WTx;xqz)ӳM^5%bްP e; /x²eH/o-o _$*Jjk )|x{q }h60]K x AfF): էϻexlY~x8Z3ԺcqJq'R/.n9 @& 1ǝx۸.y"Fx²es#Y{sFǔ ?x3r7 UV ̑JtMMd(G=,fvfl*x3^Mbrm%J1`hȂ6r=djzXVUIhK*1rx²eHdLTg-wV{L`\ 2-x{qBѻ/Jj1Ͽ}?kފPx.]p%&C.U˝OZTlygLl tx²eȦ#iYm2~epZN t/x{qBH+mIDɞ٣ x!CҪ{3b55yxx²e=~YlP2l5 3x{qB)-=0\<-/ʑg}ax!q,+yzƣx²e;ټW`R]u {x{qBshS LQݶmKex!\$(GGŻ x²eȴ-+whZzK Ux3Sjv˾hǴ | ۾ꎘgi>%ۜMB GQVx!!'[Ыcc3cXF/9}x AfC HjfSw6U-Q=, %7O`z &xə!2lкv-,} x[ϵKD Y/aک/> *vqFE>VIp1x²efSSµ? 7<}zc o%x2Slk{d"5Kfj>%ۜMB GT %x!SeMVX1ϛP5Kx²eHM3رb- x{q_~y 4 ,vx!JWsvZጲ20x! Lx²eaq.$8\S^pV @x3SVe͋Lpu-Ngi[k-f ^8lx.]p^"kA-7#~8 K9Ax31Bu> >>8H ?x! Dk mL>tpx85em G Am}MڨIKVz'K{!Gx²eȁ{t[}f 6 6xZ"ëV4@C39x AfCWW4ΪKg/&'ћSyGx²eu_E+3s7exv P7x{q/WOߜZ5o7. [x!|Ͳ'aC ژ/dz +x340031Q/.)ILIKf.P~UOF2(+I.O,*{-IӅ8e,@jJ <2mZ`%oc-:8x²eȩݳ߱{8( ^^ (x354ހ9| W%NnȑIJ'ʢ](gD j':xbFָZvmM T2,Znh``fbpԬ5|z}ջ陨zיw%lfv*?'3nZzxm4ʙp;UI; $Eʼn٩ &Mcz>~PͳYD#._&Y>KuU\ cxFoFx²e Ҏl.l  O6x35pM k=^lwT?šIM0P+Be1 A0 x!p\ Bb`D0\Ix AfD1)͒+vX^65iƥy@ x²e^SnG+gJݝ2 rGx{qėr׷kdq^& }x AftNX]IKJ$Uw_lay5Q x²eSNf;2VGȞ%& ExUJ?z}EĠx!TrE|Ff'IA1$:V}k$>x/'100644 Makefile.am Dګ5\['ϥ+Ax3r|r}:3/"[%yx31vgWwԶ3QW2 x[ϵKD Y/lڽӾ{gjwm}]Q<nx²egܧ]?˽߭< Z `x{qewwr]ڣ%~mJ  xuagw Uah΢ "omx²eȜ.꣝,Zα?; * _x35Av,^y( \5I*2!HL0CaPxHח_>( FI8Z)lNbePeuO6!A-?nTxa`x!|͡6N KfR T1xə!bľgƒbx0 px[ϵKD Y/³aGugN-ng"++,x TTRߏkS  x35tC/GY#ImKdzcǁZ~Q^N!Ax4'100644 Makefile.am*ȩ9M$ 'B[==x sDFD71;5-3'U/1!w _Lhg>ٰF8;x²evMK O踘 Z pxr`Gϻh>9^q+x;xqBVӼ/'ʑ\"hĢ@ x5cMrXsƅ`^<3F"lX ǐUwQx!\# c^,vx340031QMNMIKeh?kdDX5M @!3/94%-epV8AL1% uo?-TKvnZkn.`{D7Έ/;a/tJJ-:x/mp^2uyzT !9xcκۥ[YNx;C; f:j*;rͳY5 !x;xqBÃ8rd-Z4q6 !x²eHOɦ_lcwk lJWl Yx{qBȱ+${=4͒P&#mqTx;xqB)>Ub1u(o\%wbQ ~x²erF.:߹8 f6f*`3݌7,xl *X#\^~1!!1 x340031QMNMIKeqzg&40g/l;J !JS,2 Mjxdwe^4ex{qGS_zMq0 x! pn셆J HR $5gnuQ7= musem$w2TY+B勗ĝ3<6Czũ9y kEVZqsNbx U1+OwzhB~cfNbR~~IqIQb^qԣsuH)$HMKc KKL/-Jc5Ѧ>oa·S75+hb )% N<cEEkgB.{)Q+* McݱTʬ֫n99gD(!YjbPl( -)f8 7:v@SP<Dx340031QMNMIKepx340031QMNMIKez[~)k{m&@g [paҌ{,Z@.m`ʾ1eLߛS L}]X^Z9,6xMED71;5-3'U/1Adˌ<>GnxkalaP r п3dp|޲ j x340031QMNMIKeqzg&40g/l;J !JS,2l\lz2~,c EwDR*x}ͯY>WR7q9PXx8}ͯY>WR7q9Pnkc*@Ex4 x{q݂/Z½fκS:yK)E &}x!|*`*`0u hxə!2{Ϸ?h  dx! 7U19IRB04VKMx8}ͯY>WR7q9PI>?,zǏ#1ٸz l4 Kwx35+Sfہ)mA&$IGZ[f[>"&!50x sDFD71;5-3'U/1!w _Lhg>ٰDu I)d~;-imŌ"Ul/o;gx!ƭ &Ob3yyo Uؾٞe1yڬ^Ϩ2/"^;XE΄1G}?Ixҡ6'w9X̍;zKu wg`Ru?%0v(}><}n~\Ɍ?'qԋL)3\Rw1ͯC?]?y')ƛcŧ5uܖW9RCmȋoዷDf#k/,/I&KYK _87nCPa?gi!."|/6+sr5oeYUKZG?oUYrɩx340031Q((/-)KfXuKXdEV̥F*ތ3*).() {=9'nw˳ZU6Vxə!27YYsoW[w] B>x F\_##>x340031QMNMIKez[~)k{m&@g0 5A\m^xsBT\ڔR#}}cPi+7-DRw[V m9{0xMED71;5-3'U/1P[+&HMQ_oxreݧ"_Q!$&L xSsVu_-o@g}9)x.]pCHg VGYr6W2k Bwxre]׋#xV4~9/qd& x{q|JES^kZ3 Lxreķv[ׇm;4YI;w=QM px3SOۤڒLGVϕT,P!gio:yMordm&~llgrx!ZM%qtG7c!n QFkxreդmϷ['p -:لI x3SX |mN* 0,̿gio:yMordm&~l[Fx.]pq}53%E,t x  ^L&)yD̥4ӓ4 ݽ .x3S#P* ȳ4dgБgio:yMordm&~l3qxrei?\/0?]qi\@d1&; vxkalaP 2W[u# ųny,- x340031QMNMIKeqzg&40g/l;J !JS,2D-ވ~ 8fz}V֘xix{qBHHk_"p7}x31M˂3>*Sw.׶)U+8x31F+? MWs]pãu Rx340031Q(*HKf(KHc]k&&/E%3YejQIfZ%PaI#MnYW]D6.d7n.>B<Q$E r{fH~2&d5e9@eBGD%[<'tͿ=@3$e٩hT(%Ny4.F}(713f_Ub'm׏ϑe%dRz1greϕer*7XL4 ` G4W]_=رȋqjHj YΆϡѣg/+cdݾM+Ξ7{d|%h?%~")*H.F{*8;d6=GwhUUɽ-) Vyƪ;DRSXu[2OwsR.kZ^|h\ǒ翫Օ I]Qb^J>(LH3M[SoGRWTƙOܺ`ݥmY (rJRA泖g~^݋>.{f9TdӹTuvz{_V,~DRU Jo3Z]j-r*CVDqA~ZɧMBgrV>PϷO Zx, !100644 rpc.cq8U>!&ivZp_N5*]T\3GwBoݧ&? I/^ hiύޝ37]^Z] x340031QMNMIKeHP]iɅsSu%B$%3_xeGKeߖ 'fϐ*.+*LI*8%ӧRJ,^=.卫B$'i~οA;q@Z0.eֳ6Mpy/)@ew6'@v/B-xU|S]Qʄ8݄trX5f'GF脒( PUv6Ȏ`=@ja=8HX` ?(x340031Q/.)ILIKfFog]2_g|u!DYIrq|bA&PkLO.|Ʃ/4fL&@RSRpvLLGXtkd5+i/x  cɝi#߉4 Wx{q'̋_ 6LĞ 0,xcT0"~ԨJAGH2 =X@(hꬋi100644 tspi_quote2.cg&' \O -xxreZe)/-#>pd& x{qևcV\jW Gx;"sDfC0"-2#?vUcq9.+* 7{x  JZ$R{4 1#x3S_^RCE?gi;@VspUU9F[^vs>x.]pﻚ^(Fs]}pOf)lxreHfJT5ZM x!P5ܚSsߑqI Ux  ꨿6`cc4 x340031QMNMIKeh?kdDX5M @!3/94%|+%Toe&DEIr1C~uLַ }ZMa5RNS1gOJ0|'wX΃Ukש&C 2=ϲۖ9] ͇ޟ; Iv~KV7'+ִn7q:Z4x9"P`Df}Hn޴ ^pe(1h!66ԲD|#۳ *l6xܸW]DB]vbɑ*=]x˛%"kewX  nx;^%U!"P,像*n'FDW4`vd : xre5k1W/hX]4kd& ixYOi 7j׽h!xm3 1Y˾G~-|Goc-DkIÐËU%ݑ2{HA kh gwB@ГO i7Xx  J,论<]4 >x3S<>Pr}jLgiYOi 7jײQ)x![mV6?3gs]o)yx9@u[tݤ9aeĵ?`l P$y4 8|xx3SZBĽ ȫBkgicj)5Sa̫НT~{vcx8C'#|y'86\|mV6?3gs]o xx31üC}N=7Wׇ?Ufx[ϵkr&C!wDi}|vͻJ Fx;"sDfS͇69@B~RV|j^rJbI^2f MN̟k|u;c̾3 j/=ojGwXeOŘds7St#]R 4vUSiRt9LCRxrerF '1a;`pFm݌3 %x9?*RP0&IMeIk{hN4w_4 wx3S dzܕ>;giu=yaJN/I*GҷAbx8{tmM̽n9mV6?3gs]o]x316 nwf =QK5U ~x[ϵKD Y/e~F.Kb/J/l"+&x!9jߦjqmȘ &`x9?*RP0&IMeN3QVfe֒R|I;m4 bXx3SF4}/<Vegiu=yaJN/I*GҷAKRax.]p\v{ Nw] 4 ~x3Syu?lyVkBgicj)5Sa̫НT~{6x.]pCn2֬rrRx9?*RP0&IMe ҖX9KG:(Me4 t8x{qlS-o2yۋE\k x! Zꉨʞ0߃ӓC F,[^x9?*RP0&IMe"@~s燆%4 ^#Fx{qlS-o2yۋE\k Nx9?*RP0&IMeطu.GJdא4 P>6x{q_.g?O}f6Zc x!9jߦjqmȘ &nx9?*RP0&IMezO,`2@X5Ny4 | x{qFFK_%L/Qģ !"x˛%ջvя˵'Vn9 Ix9?*RP0&IMe^hrQ Lkj4 /ݤx340031QMNMIKeh?kdDX5M @!3/94%!(kݣg?mZ|% :8qky}?f\6]怢?Y=%̠*yb_;~V-s] .*.dPyk\ɄO}\r5AAwUی6֫{|I.[bAx;f70>:|n3%Y LL KK @^|F|֯t9ٜzbՆE-.'~\jPk|iIfȀ%Ӿp3ji_6Wz3):h*xR<=Wȧ5/  (Ix[ϵKD Y/ᔔ7{WeM_`aQ27 x;xqzs &n83kh 3ex;"sDfC Hfy52Un;C L[N xə!2 &'y[TV)y% )x340031QK,L/Jeo;gcxBm\O0r  fuP׸ܹ>B9#1/='?j}w gj0Upv}Evƒ wnl 71;5-3'U/1H.Vg<2?`gstwOm p s fp̶mӶmO A,וAo!CcNSd! Ԝ̼ 5"E+o9'^1Hg񉏏] wgҕ[^4x!1S3|'&''0\0u߳lGj.J/).)J,+`ztrq)ŖIivL!PuyiEzy ; 7ObvH+(ZO_ PH,.axv g~U /֬J'3\6՗S2(?+D,WU:jINInbf%?+χTDe>y k,frٿsixox k5̃&P8f_׭|C˓ &x{i{>E(އ2x;"sDf r㤄&,ZZ} vx:uC6}K9?I x{qF_g:rAY;G fx˛%&mp tx:uC6Ȗ%X`]ZMHz& x65~U.wonMukIhp1Ѳn "[4ɑx; 6;Ă}sf+̚{8Qx340031Q()/-N-*`QQ#|fe&[dUU RpLJ &..}pi-`xx˛%2qNJY6['smeF x k܊SN{+pœQ x65~U.wonMukIhtLv3V]x˛%򄡪a!n=lǴg>2~G x}R@l&Qiة.x:uC6\,OAgUz& TExrxz<^x3^Ds" C0Oig/$ώr=4-klp@:Aj6[Ix:u/Q%w-lUmN^> P(.JfX?iU?ftZcL 0k,dxkalaP :>NM]I Z⾳[ 3 ;x340031QMNMIKeqzg&40g/l;J !JS,2,= =Ͷ LIx340031QMNMIKeh?kdDX5M @!3/94%@_\_Ú4 $!1쨾*61 3\6y5g52N${7))9 I,g2u*PL/rK|cX8ab Vgw%'G^"x!r_xܔ7qE)v~x.]pCi|gwGj x340031QMNMIKeHP]iɅsSu%B$%3_xeGKeߖ 'fϐ*.+*LI*b9=/8bve,53nP $)&gi{4>>G5y"bx.]pBm܎9sv.vkچm x340031Q((/-)KfЫО:j%[Y wʧU% % k XhlĬƜk{tx: \w3b`F%G0.";geR{kr x340031Q((/-)KfXuKXdEV̥F*ތ3*).()ɾ ڑ@ϗlx ɟ[:fo3X3/xe+ȼ"R67j'N՞hr$_ xx3S`DM;{0,dny}zxgi{4>>G5y"w/x.]pt^.Iۘ S曟bk럳qI0 &x31E^-7r;>%à Rx! 8jTQkpL0ݳ> b"xe+a09Y_ۓ##x{q9vudn@o xx;"sDf NJw7I{n?,%xe+ܴK?$|efH&& *&x{q(Nguӫ]{Zx x! B=t@;E= F +x {Ƕ@•"HH$/xe+Ht_m 2n3jjr$ݭ -Yx{q;{O8_domOj 3x;"sDf N>-k, ''=1iNm1x EQƿJ$:Y >w^x{qwRO8U) x! JϘ]4:Ǭ5] F8xe+D.b2.H& cx{q7c\~Jsxi2?) g x;^TiY?"'#+I=ƒrx JϘ]4:Ǭ5] F5Gx340031Q((/-)KfXuKXdEV̥F*ތ3*).()e#Qꖾ%xe+Xۀ 9_6n*SG{r$ Px{qwuչoΜ8ߏ?Q wx;^dVSriҬLBnrx JϘ]4:Ǭ5] F 7x340031Q((/-)KfXuKXdEV̥F*ތ3*).()i\wdnJ푷vfxe+SKu(9)!|r$ >x3rU+S|.7MTґJv,*~G`#.x;xqBlN:(۶,-xe+s_iy*ɑL Xx3rև9W>W{K.RN葆Jv,*~G`#uh#x;xqz9_s]h a@ Dx E>M]iܨbY x{q=;2(ccw x;^sDr:p֖=rx JϘ]4:Ǭ5] F3/x340031Q((/-)KfXuKXdEV̥F*ތ3*).()G?ݛWMw1>3͌>4xe+Hхe^=^e_*ݴdXH&'x3S1y8;FP !gi.3MO3+dq=l2_x.]pNw8UTXؘ%ѽ x31.s,ZM`~لp x[ϵk/H"/aKR\5J${nVdc0 &xe+HpGK &G2)Д yx3S"[_&aP%Qbf igi.3MO3+dq=rx!^ork3´J+Pc'x340031Qp  fuP׸ܹ>B9#1/='?SǷǞ/V,9 Upv}Evƒ wnl 71;5-3'U/1H.Vg<2?`gstwOm p s fp̶mӶmO A,וAo!CcNSd! Ԝ̼ 5"E+o9'^1Hg񉏏] wgҕ[^4x!1S3|'&''0\0u߳lGj.J/).)J,+`ztrq)ŖIivL!PuyiEzy ׫v퇦>dUab )% bSj-qؐ@|?C.{)Q+* $$713z֕CcFE*}bĈ(|x84 :Kqa:JȋVH_\)F*>ɗ[CGxe+VSYfvl=Rx}r$\ Gx{qB1+U7O4&QF&@P\°h1SO <J>qxQ ^\(ޡs;H+2#15u3&6C^ork3´J+PcS'4x31w6'iy8m]  jx;xqzg~~1p nx9`]&sqZwb=ef]w!D؀Y qCx{qBȼo+s;d_P>Szsbz-h %x.]pBSgzn^}h\] 9#x340031Q((/-)Kfp}O|.CqrʕaU% % k XhlĬƜkuDmxe+H*W'sIԌƇ+J&MdR Rx{qBgGs>Rjb[  x;xqzbvUrFҥ{'oIw xeȬ#Ktmy_Y`L ,x |aėH?^.xe+[e_Vu=.urr$ݛ +x{qB$W/վcĶ8˺ bx3^>OfDN]T#Jdr=H>z?2?ggG/Gxe+CJ\@'j/¾2ܓ# Nx5 !ά lPaIJ:x (2VIndd!&Pxe+HVdwIJqI|r$ /#x65 !ά lPaI)N9/XeNu ב^=xrn&ߟ d=~lxe+v떶}w_zw# -?x65 !ά lPaI)lr&,[wedؑ^Yxu2̚DjͨܰXxe+HaaY-:H&' [x65]]*0{esE<ؑI)sÓJ=nS|, ^ǡYx:qS+''b#_+ٓݍ5TJ8hm3+z>x;xqzg'-NV߳Evjх(. kxe+H d^o΀H&H cx{qɻ%\+ʵCXi] +x;"sDf+u.lu+:%|pn?7F.nx9n5LI Vv7uƓ>@R]/]0WIY &$x3S3qOT qv앸ȑgi'A@p|L⋰Cx.]pBHl7G4zޯި~mx340031Q((/-)Kf#y n'O>ԗyx&G ))`|ʆyדE*Vxӯ .Q*p_$wr$ 5*x{qF;NY+NI)㹟nBIqA&C+s:UzAr~,ˮx340031QMNMIKe0s LӿѸAb PH.,(g]_f,l*Ʀ>HRC9%EũEz Of֓h˶L{.J%cx340031QMNMIKec#9[Vl%Kޓ RsN_.UlQtwk?Yzxʚ&ݺzy  5x;h?Ժ0D !ZcBxEGpb̑qxe+ z8:˷11bX%-lѸ&{x340031QMNMIKeh?kdDX5M @!3/94%!Y |hx;xqHFĮn5[.*.dxűٞ2T$}¹9w󤊾쾿4?z^CyuIU?U]\Ǡmy8v$y·q3aKS RAj;-hx[ s_d x340075UHKM/J,)J+I.NaHȘ|xb7&C3ԢbdR\iXw!PACWV\ 4A)ɾ;B vEzߒA) ڒTM.Ƈv\_~Di4F @x[4zSy0x2H60S㰭aݑzɚd#ݱ3iﺛW4lm|w40000 distbDbgqUWJ k4l<ӮYhz$6`40000 tools =%'v$96Nxey<p[_YRJl!Z^i3*Ʀyb['jvu=cٜ Gy]Әnrx[GaWcpf?'sMAk㇢lceɭ;pG*?c7AqqڎGiDœK:= ە}bgg 2Eb 1[?GX]YjQfZfj[/#ܷ5Z/byݡ敤gM[,OLWrBynFJx340031Q(I,I/Kfms)yog`69_mQUZ\Tr?kO^Fk?|(< IE|V~fP"8<\ln\!z*'x``*κA%O_^./wC3҂d'7$1f}- Xli,4E {\wHQMsC-+7:~+_x340031Q((/-)Kf#yiJg;3 gn>(5'5=$̌/_oԦGH뚑Ufz` IQArQ<0Sgq*I&lq6 ~lxtY-(å!¾6_2}~Hj Ky-0}f:i3LubGWfT޽Хgzc!tļ|P~BSNHa^ݚI]qjbP՟w(aEw_ (rJRA&_,vgs|z<3#LY~/)v`!*LGNږYm׿kx<YE kS5S\votJJޫݼKN]. }5jLtQqA&C+;Tg升 ]:\ ΞqGn?[|xe{8TyAZRh$$Qfi%87g\eS g[tl*^R*b% 43܃GVSƠs+"ːcuxtLs"=&-֩W^8mDSS'"#eͪ5͡kM*k Sg[MVP_'hRm{{I`Qa~?\eJB,e^P&Y >Ufddv\yoQ@ߊZ:3 S!n 0"T$xg.W{O}"- lXY2Tf|q׼2ao|rDH]1-HI$B2h'l]1XV58i,}n+'@[|}#fPy75:eѴ <"<N.)M;TF8DTݩP>P6B?Fm籅܁pUqa'.炏`a;ˇVϸ53%,EcMdmF+֍ (U;JXj)$92V$0f! ^D2]eN1_gIv.(:kӡb 2 s6|jzmGq-)yؤ˾q-ZL_q-s}:E3! UqzX #c04 bnֲ\?:Ļw4θ05rQVTϏg7HSݙe[#'()V`.?Q졽w(,':no +OPmLIr³HAcE)EQ}3"䂚[4?w0~\t0-c!"lﮜ5J O PP@~&ϏɱxWUȤ$pA-в |jǻW0#f8ּYB!a40̈-tKq.#ʯsXWInؖ+_ՎT*RAm4S҈? "pBDwQ_׋Y;J)iy6pQu9T]7Vt^mx9UQ>V}=MVWl/WJ;u9J-׫RDd޻NeJZ#wJ/+Q'sikxj|J"8\eȹ}́f+.KMq24&~@9 I=__yvG\B,h{_+7_|Zg@B=b?W[7idǻsZ╈]Y.;E=Q\ڑcmˑi3xA->cRxxKɷd3SJ>׺u;dio]xRS C1 -bwےatZu'bY{tbM/U]s*LO!bcwy]'V[I(+)s5|D"'۞XGZ1i_7x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X TD sʉ&L2_PMIQ7JL3*w νRSЦv\+ `x[ϵKD Y/[_2I~slha sV7ؐzҔÒ"֞ kN,f٭_aх*Z9*<ٛimG&N1ej3;aFƱ|*Ȧ0[{,KH'x340031Qp  fuP׸ܹ>B9#1/='?6;7އIOV}c//ؕ춅l9#@h#TobvjZfN^b.Ï7MrwbYw(߅*s fx6M9{wk+qIOD<Ц0`l+0m&]ʂ\]|]T,xl"Ԗ Gg+N+`X.R֊s{e)]y;E=5s7|brN~rb^ _= KvT|vR⒢ G'*RlIlU^Zǐ~GLrrՔR2K.?x˛WϺ J'3\6՗S2(?+D,WU:jINInbf%?+χTDe>y 뎗,W#ⶰV9U;y E GO =|lxq_ dbV@dKs ?F{tVo޵TX+x{qBHjR'VwKʊ<1xQe'U1ٵJ 2&˽Mr#xmy<qDZSJ͒BK0_bƱqFԪH$u)MH i_F7y}^2Sy=`2Q`S|\1?9:gi!ewXDFՋ켵s8qUcn[O7>djwkEE^\L `2uoY]))[TKY5${  =ư^"zͧ2_BQ@&g1GgXbLxX''{ "= L#fYQkxV-fjDJ!&̭1r}[(\jCSp} I(c'N4Ir>ŭPؓĈnZ{s #{Z?1 19-gճd 7.ˌ :#˵Tú lyW-ϖFF Er+J&t}ʶXzw p $ k5Ç?6?J]1NA뜒fb)nK;b:\(QՐ)7/:/rjF?k>;|vcdtgjz v؟ʳ#] 閸\|! 87Y@o Ncǐh#C5̸SNƞw'?ߥ<)"ܦlfβ (lv9PhJSnK]}7ջD9Dp cvQQ"`; J~{aW-U^"}]S{7bR­EJL<ޝ0j8%ї {Ar\ t wR&"8l$IFOWD q]<." "W6O3if!}h_t1- dycm)t x؝BQO2߬ޘWyLDD2by:Ue̯ۢ11}A kf=,=hԫ=UmP0@D4+੭ߕ{f\ASx.dݗY2Xy[֦'kT2kotE n~O7/%T4UΈq_8bm =}!&LC#/VWGp[uվ .A99{3qᾍ, {U?>6 *9UR!*לTrJMm 4ZCֈ;+9S[ rA2B\~_%]~t1ڥR3>lDaض$p` &С[#ȚN~tlRj䰩io:K,/#AKX:e\`|!; M9#"W'g!fEec!2'WDbcwHw*L"}R'_$0,'縻H=ѝء1lj~Yl}TJ"(&L@k,3/ka)eB<.Pꫀ[l:Lt^c 8,dLX#;Sb;vB/]YY:Vs}=]qGe^YIh{/}'[h^V *462kB[@oRK䍁. j-h9(ڱLMO2уD%gJ5H-hRU O+`̔R4v[/uf=RvÄ%nxDΈ5y]w閿B[-C3q-$Wxy?YkO"e6DKe7>X\)auvG}ٟ/^xۿw;;2kOWv^}tJqslCx0v0Zho?%4T2kfJ[*ETX&Ww x l>, L`jG?3^x340031QMNMIKeh?kdDX5M @!3/94%a[y{+פ农=٨$;Lr-. 7R.pC{G_Cj'wwNIa{bɩ%/߱Fw~ .*.dXԻn_bIse c|vʃ=zNpazL/[x340031Q(I,I/Kfms)yog`69_mQUZ\TtⓃt{ۥ|]GRTF&7Ww>h%2G*Ox340031QMNMIKekNM]I Z⾳[ 8Mx340031QMNMIKez[~)k{m&@gPCWo⺇M5?S.m`ʾ1eLߛS dەP%;ʿU7x31J]G V\kjS ʠx31uҋs?iΉ{R5x340031QMNMIKez[~)k{m&@g$>"NSL&)\K2Xjo =y?:m C385v%5k:oU24%x31m.=-li8y=̌ x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X T\+{tN?'k.01W?_}xvA¦%-kx31/Om{N(_Mu ؠx31 Z]x(81ޒJa dx31ԼAS9sv^@tZ/ x340031QH.,(Kf{%ܭݨ-t]Pdk\ x340031Q((/-)KfXuKXdEV̥F*ތ3*).()k_Ay,JH,X8x340031Q((/-)KfHc,0r;B{LU% %OpTK77=7E fx340031Q()`usS0۔<45krx340031Q()/-N-*`lz*l~:~fUU RpLJ &..}pi-ݤx340031QMNMIKeh?kdDX5M @!3/94%ag=ו}?v+V(I.f>;_poiՍ?x|*\6kLN-[˻͘ZT:%%anފ%.`~a&T AR+&Aeڬߖ}LT]*=k讹۞2:v_.x340031Q()/-N-*`XϺkw|hXPXgUU RpLJ &..}pi-Ýx31)߳qYv;ڼ|^9wـd Fx340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X TtkG(m>v.wTԔ0l{U4`gexk0x340031QMNMIKez[~)k{m&@g̐zL7-<׺Ҧ jO^ϴN[98.m:>NM]I Z⾳[ 8x340031QMNMIKeh?kdDX5M @!3/94%'G==9kHeCT$3`Q)]sys+R_~\ .N&^'ז-fP-*ðj{7oŒSKB_0cZ0*]T\O_+>2&mI_ ng_ėy_x31u?|7dWac0O x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tu惒^ʖE-|^&@RSR\{ x340031Q((/-)KfHc,0r;B{LU% %Y+fOtl^&7n̿vO6x340031Q((/-)KfؓfQvZOJߕoe4*I..)^n㪪:c,?Vx31ZO{T.o=_x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X T\q-ȕ* #ɑ@jJ <Ū8pqr@ϏWK,x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X T0>VAs;3μޠ>@jJ h?s_]ʉh)}"J^+Mx340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Ttezъϡ.Tp ))`أ}Sv)'<*yqa/x31?#[x1CSe;) /x340031QMNMIKeh?kdDX5M @!3/94%ա꤅7Wu?QQ\=mzwy{) dL*{13 [^e3J0[X;?̄Jd289Gk^޲\T$43gk_N2JFTWax31_=Yb^e]l.N4 7x317n?pciU Y?([x340031QMNMIKezVLZ..Oaq{?_4($U3xunzO0kcӔW[x340031Q()/-N-*`0ߣn_Nl#n9Cb U?>LT6qqǗLkwl:x31鞛;˥'mgT x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X TZY$)b3+HMIsju?XfR,d= Д)¤x340031QMNMIKeh?kdDX5M @!3/94%ą:X3ݾhA'DEIr1Cîv764?qIp{&=ݘƙ BSRr^mXrrI wQfB 2R6ը1i/ԗkjHm_ʧx340031Q()/-N-*`[:ǯq+Ӑv6*)YDmzp|>ȴ 1$x.xQD71;5-3'U/1!NnbOg#`G-_pc=7yć0kFo R,2NswhN${ Ifiz-ۄ̣=3?8yͯ ?_O? 93>1%73hEƎFV^+&sEm<l;jú%,4%l@r"t-;&g&f 7Z?䝼%}U. VЈ96~nTJ/e8&ũё~P6Ll" o+7Pm!Qu+ &/`sP,[|jbۆodv? -Ndvwr~[{YZb&̋p8o7ݭۼWci"jw124431QId>DPW?bPا(wЧht!Q om^7>mloAls(h!dZ>A@%oh׉i)Gߝg|]$j8ԏP&Ш01F >F"@?BP>K.\KjH: D@)~&_+9`zf^ @TumPGj1LjQS+o)Zu8DJO֦+Jlk &.Po$Mp_*D@ .jI5_U$',lKL[D8DXL{{o+`:A礍F5 f?/Y0WӍM)g-K_2QGw8-6L"%&}L:ɛhYMHiM' v?8X`&򣐨TᢚXq3)An<8W0ح3/My8D&뵤k8+sJ:sb:%.VuaPgK |a|'`'.NeP=X8ʳP$>UO]L5n ͉C"@t*0Re_d(Xrlr[DZ,Y:gWy\r/yȀIh=7D-Q4ەuN\@@\.źa5t( UWahVΛB\|S>:c'ofƔ@`Q++ K!lμ5pi?=f]F\A&"ty{VJo+VQP3s=+2Uez0ɯ6+.P'CO+|u}lղ\.J;suu!sBjRLsj޿,CQ=C;I.@ia(b0"3)ճnjrӋIcR|:+)}qCU"#m @VT>JoWqH'0!,m:ͤBIǷpՏ6y㶴Y !R#R'D(|)yU|4sb&H]dƬZ<\˶=N (D@7fcMW]Wci toU Nыuz~!v'JuůvnoNLHq \FI/oi%F^`)&a OVcWΞ&PHjϼy}Nj룅nj-;oUAs`&=ϪA6_~KM*^WK H 懅;\ F;P]; }ΧɌ9a[ASQ)ݚ|t14"VVRzj-uaW{O,8|͝r8V,j"$ZDܪ5pO5b"@ܭCUJCYeRZ (dKI׮ (*(zs?r瀠|_I}JM3UK(|#r>[p{_x ;ʛʴKp;)p-ްdÙ.J? =d (teƪ'q{Zp;R#ξ(f )%wk^J4x+lLWES~Y+RL_8&.!UPOq˟-a e7 i 慎v.n^YCK7P1d_ѷlZiV~FZs!_-OlRGauGĒK=]S+!'Qj,"xcFtN?#D&:igl94s 9VwnK^MwcT84FRxJ [NwiF N%5%h>Ļ}m!v8&[j6^d x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tv Z>s{#YU~HMIC+z5㾘TPk9}*Ǥx340031QMNMIKez[~)k{m&@gP0w:.V>s7&\ڔ!c2 u~2|eC385v%5k:oU2k8Xx31H-MkRFo|cI3 [x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tt}OQƹ%?w"'Hj/z=,#_Ś*9v nYƁT^(=78R]wChSs\v0>_m"Cﱱb@0%SC_O(ձdGmPa"lO-HYX]1y[K`2DenY9OpKFK]s0j[?_IݐKSc'W_ZTXr'REЛ~6~{bZRH'|a&c$SS[SGX|Δ(Eje}Iɘ\2-_">"DXtK(~x$fzӱٔ[=1 "y÷]I ~]y-Wt 0kp[&.|oXcSGjqr!Μ ROkIj_xljݫCVoo7Is)IyTɓzV62§ʶ\tD@hq=%kiV?B3wV B [,'wW{[dwbn-r6RT fzEƴU 7dzV y0xM|hd&hٔKɳuҤڨ7R*e*oz)h/P%]h5cw5D#Pa \ci=2:b`ؖ$վR9ۋ{뷘Lcxd.8c롎ݍϵp(J2%%{gbk^X1u Nu몁)ϯi֛ح9ة'HR :_Yp_WIe{ <,|,S?t2Ev8⃔6I'B[^a'B@P7_ّI.^K&Fas Nawlmy˲\@&ڗ[g%Yry}ZG07{Vnf"5e'W_?x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tduc{d̞ YhDԔ0PmZp!6{^"+Nx340031Q(*HKfǸsSL198)덟!\A|bJnfPٮ c}jÓ+ "+*:*=o{ٳ%~Nu;zn#ȊJS2K暜ܼbߡߦx4*PdUqޟ/Ӳ;BnEAKɲO[!JKr`|5Zڱ(f1wovDRWT?yݓOrEG0qER_=ac>8U|idU 뢏0{OfS}돤 (tO{6E˺N^~2ZP*31XvFŪ|ގ4Jl`BO.gWQb^J>(jzEԲUaUp'w*jHSsN4g]c˜O<>*'$BS#H5rޗ93˻BgՏM\\"ZDux340031QMNMIKeh?kdDX5M @!3/94%~/Մy%9x}<QQ\)<Ļ8c6. @vϤ»8ӰU6^tJJޫݼKN]. }5jLtQqA&% |x_5W9q*Y:%7 /Y.[x31]\VF?{v[Fx340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X T;V!mb 5% +vw~{Hz+x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X TtJ6^U:u71 ; L;~oa=$Sf*Mx31k5S&$L[lnnt x340031Q()/-N-*`0#c!]#λQOBgՏM\\"Zx31W}_cc}&M4 x340031QMNMIKeh?kdDX5M @!3/94%!o-Gd=o_8{DEIr1Cm,ȼݚ&S%T.pLHn鋇%̞ٷٗ*ðj{7oŒSKB_0cZ0*]T\p#U|=5mry)Pyxkw Hҫ_ 3Wxe{OhE"۝x쭱 xDaCl$S !Q'ݾ^ֳ4}ŧWcu]qG:'iÁ>Ʊa\Be-j73 8} uCy>hL)GeHYymGXDk}M uQ ]N/ #bp3HJϫZG>"ai3ފJt ?v U]Nu@չY&%LP(WC҉Q"!B7r ;K㻜1-fg0a4 2}RWl/=YQJvsam#8%hkzӔS9+To]3Soda; +m1^c$5jmF hݰ,&ֶ}t,妡cBD魎N{,M:J#<1$쐮ٔ%۵zD>w%/$a6x340031Q((/-)Kfh]Ԗ}vWt`!DUIrqH ۢ!bo5(zԓ%2%jKSx31m1 [",M+,¨&c s x31Cb. /^~­eut x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tfz3Hpg-31ǒvy[^ukSoO-*x340031QMNMIKez[~)k{m&@g0ģʇd]7iWs3r)C;e /0xdf͗pi ygqjJjuTߪd=8x340031QMNMIKez[~)k{m&@g̰tav7u;.mvu ^:?Y2\ڂuޙ}l}gU*9,x31kL[΋#2i%嬿* Zx340031Q((/-)KfHc,0r;B{LU% % + U95|stjx340031Q((/-)Kfh]Ԗ}vWt`!DUIrqHI#g~6|{7}Kt5_x31k5qd^\K >x340031Q()/-N-*`x.zoە1=!TU1HΪ&*lÇKEx340031Q((/-)KfHc,0r;B{LU% %&:MoޛSVWx340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X TL1F9yf2#/b&@RSRYuƦ[L[)x31۳_twʝ]e![{@ Ox340031Q()/-N-*`Иڲ-@&3- ;< PU :~|mB/zlx340031QMNMIKez[~)k{m&@gpM}/~6_)lƩ.mvu ^:?Y2\ڂuޙ}l}gU*8x340031QMNMIKez[~)k{m&@g̠o&}z[gpiSw^`*9͚/ dەP%;ʿUo;x340031QMNMIKeh?kdDX5M @!3/94%񯎰-{i`ox $!n1s]U_%9m Ma8Y&$ f[NIa{bɩ%/߱Fw~ .*.d`}D+~\W=#T,9no evբ=Zy[x31KZ%жG2zʓ wƅ x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X TRdyE5֬XiUԔ0PzYTl5K2mqR*+x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tt O9*sOy`N41>\`*(*> vK/Wx31 _\A~ܼsywf{Zx317h:q٘\qm43! 2x31"q`>X\s2 x340031QMNMIKeh?kdDX5M @!3/94%r͌OrOc}V8b$bU'1L?(=EFCCo|%\6!~SVW]T,*ðj{7oŒSKB_0cZ&]T\ 4]Yuن55^IwMOvXb~[55of~dYMx31&?=[e&\暷HBJ Ix340031Q(*HKfX3+苋yӛ\/c1+OL*vspE=\U +*Z+qQB!qtﲾ_4%l뿮XyOj՜?,6(+zg$oDVWZ cVo3\@E@`>"!b")LIL*:mѥ ȿyB](dgO5O.gg^y`TP6|z\NF\AVSTS)9kL:z}$e٩pci&_75VOfER OmMfYً-V2ӋK2AIVOCeM^l5}PIi^P 3vMW6d䗃 3kg#x`4ݚd{OȘ~idT7oIkWs d4$lr/7ێK%䃒N5hir\*ziHSs.bRbߵEPT夕m>~3Ufer-_\PS$U%ɠb/&V%9!,FQDqA~Z}6Λhb% x340031QMNMIKeXqOuΜGJ}e.|`QVX_c[^xp;mnⲢ̔Tq7{EXMe~ UT\Tv~WŒWDVVQR TĵʼnÊ{N-e=Mx340031QMNMIKezVLZ..Oaq{?_4($U3,ur椞+Fy)s!ĜԢbdOB1G܉Bktn9(hx340031QMNMIKec#9[Vl%Kޓ Rsrݫ倳Ux340031QH,KfI@AgoDr~mQQTTPFUt~sOw^9/UP\ZR TflKb>6o [N(5xe{8Ty)e]Ex` )STOB-#1fΌ1G!);uD)a(JDB.KRHDnaωvϩ*) ?HmddN;; +fj2e4羏"R?Wi w#ܽ@KqHnHC#P `3WmmP׶8#_}>aQ8 :,`Y=!v>.G,"('+ *bz Xz=Hָ"0ϙׅ+d  M K|㔛>2c,Ѣ:?cT!JʑɩY+R枋=w(O9fʀG{4bNoL'Zh'+4.!j6)Œ F@ 1ys5tU-;Hx+Ju#={Fp}|kM V(  < ’g}8-dJYt` *U۔J(ܽ':u(ҷn@y'qo~ԛau. f>`yT#%LG}vN͏(6=ڳ\wKj2Tw<2uuH%HC$㣻)sg~i:iz%]H{>@t\ԲS#s@2r%XEx)aգbsCԷZuZYc"6eBHXT4>wǙ#\ Src(1jCs3lLØM~/5!79MY<~EB7 +]HZug..B:EeCG:[[4?hPAYZa6??)F"&2md(KQd諾gEt80LZK<^nv <(wN| _-$F)oF1>̓OhCUG÷)u|>IIx340031Q(*HKf^JnB Sr3=}ͨuܞ G G"+*$*+6}ٜ\+~[== YQiJf Pَ%:kl?*Oe%@U?Q-tpxKb雷*T%eUܤح~Ɠ̃\˼醤*9ʣu&lqN/TŗU/f^ط]f. *SJ2* ;މ={p~"Rf$楧B"E$:BdDQ"+I=ο˵fsn2qo#R"®onT氥+ӧ9w>!)LIL*:á"drFۅi"+[oɛ9AB2Ƹ_TP`aPPI/|YMYN~:Pjl ΞXKrW~DR V8`Q5,\(713&gH^7n\bS]EV^XJ/)dD"A.:Ҽ2=U g֨vOHjAe r/kc9]ye=g$)ja#3̼Ε!4=dTWr/ s\u+<_4$n?DqDD:ξx8$eEy)Y=k);=;~ͪ̄mHSsdXtxGI+I-/M4Z&YvPetP/W}mؕJ\$3BL"^ZOS%Tw1]Ȫ(./Y| E@M+ ӧkxeiPgXb IDr*"T7Ɇ,&ِ݈;DP ѦbZ E@b  8T%ƳAvc=~}^~T*+Et \ $(){Y Y yU^(ǠX̘Qîk( y[݃*泋D C("Tr&;22:Mٽ y0 ˍGp$mn 9 vܸA`Lo74vm^[Ӄs7Q=̇=KWH|rvՎ!6i }ᾴ PS}z3㻹=g/=3#`a! A1_B/AV=> 0D:Բ5lrxeŝ?t8 õmZ nم* ie)0 lT]?T U{qJ3 [r}X^uϣ+--gDl~*e֣%DoW^|-ŜIY<帅UP3hv91m@v~O*xUy@mSq%8)"" a >[_2~/+NjYneFLq^B|=kOTS<ڵ> 0sۻ2z0kmoGܜ2g侁/9l*kvS~憊!صO}tr4Bh]yAmt熠Aٰ d yfSs63%mth{؂?OFW iq]F|@Q)lFo2cjQ閈TlxjBbjTh+ϑ PQ4hn{CPQ.S>Yv)$3 m.dO8 x^Ou8g'TJKCW9C%GOJJWw!H ]"pʂvFy]OƜJA{m1f,NP:R}z *&4uC/~IP|ka~ @hQ=6VcORf]#"xêL?@q6`Y2#GտvB oz. P0VGhjʴMp)L aбR=.}su"q^ǨoR?v*O5ҷy^4)3-Qn FR'`:3eOV(*6v7qeF~_"˞jV:#s#%Ƚ{Dhfg"_JQCnL 2 +_/%wi~+EL7sz2} IvF)C2:Ike 8Wr}̽sa/;=^Z#5j<}C*AxmBal#] B sko`j;XRxH%Ə6)g*@>OyGz<[@ŠЙإGJԔ4yМ]< FI9`v5ZHdThLh7-ՙo|C}'I.tw( T舣=ceԖaot'1>oZKx%c[~prk+b:%b &a低EiF)n@աmzR>ORӾInyg5_4;Ѯ(6Oѥ v4aBao cmV".a4Yo(0&Ѝ&X{9> ꞃ(_/>JUw*sSruⲒYd(X2$fbP"@/ݠj-E4U9Ev@(\W S)egq2㆒Tɋpr4 Zvw sRx340031Q()/-N-*`{.feioQ^BgՏM\\"Z ux340031QMNMIKez[~)k{m&@g0A֪ͥdc׷^ M?nߡ.SxP'7k\K[0;SmWRCﬣ*V%<6x340031QMNMIKez[~)k{m&@gG.@`1:'],S.mvu ^:?Y2\ڂuޙ}l}gU*8x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X T{-Iu >JX~HMIw &gXU*f5͡)ՠx31Q\ ^+"8l x31o,pRgˇf?ԫGx31iwH{ϭ_tsz'1=?ox340031Q()/-N-*`{.feioQ^~yri1Ewx340031Q()/-N-*`|v[٬ A ^]^0מ'睖~q]$o*x340031QMNMIKezVLZ..Oaq{?_4($U3y !%3 [A<ѫɣ&x340031QMNMIKec#9[Vl%Kޓ Rs="քF+!HUx340031QH,KfhZs{=J?)2(*N*PY&DZ.ɲ! UP\ZR TflKb>6o ^i(x340031QMNMIKezVLZ..Oaq{?_4($U3$$/dL#C9%EũEz o4ֿGrvx:7%x340031QMNMIKec#9[Vl%Kޓ Rs brƯܮx340031QMNMIKezVLZ..Oaq{?_4($U3( .Yn7!_Fۣgg0SR_ZZTF3lk{,gxGZ &x340031QMNMIKec#9[Vl%Kޓ Rs$5طq<~E䉗}Ѫx340031QH,Kfabס{Kak藌{ !* TߟqKeAlfCW榖e& XVn=3a^g{.(x31{;^D5j=]Ax31;:9=J[τM?; x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tn^ߋc9qUzv9[HMIʯGzy\[cAj,Px340031Q()/-N-*`9Y/.R=ꢑbOhL9PU k6ȯ,/`ibb5ecxe߿|ޟH C09CKLzO)OFn5n|ElY@8S>)&Ա|jEfYHCB j f *[4t/=O9b,0gc&f -y)1cp5_`o90"m/:`oڑ$6Ol}Pz&uQ (B]q{SfHFL*K>#PQmz<rn\\'{I$ LNPLqW7acAZ-] Ew J`0ALvhWJl#8 d( WIPXygMIvS12x7.ՙ*{']%Q!l!'!!L-xtHێZ=~v@{M g} Fo$:gwO<*=o8hB/tSj@0jw93k6Pt>5\l{~Z s;UyZQ4~|4ywG4j]v$ GN#x/S3A h5Lh8CZeL\~nhmlk֑)aAC2J3k|lDb] l (G6:ZtE?VU(#Oa2]?^z|0l\<Gi|NM]I Z⾳[ t7Ѥx340031QMNMIKez[~)k{m&@gpdS^w]h]( - 6eX}LB ߬r.m:>NM]I Z⾳[ 7x340031Q()/-N-*`X7~ y$"&jUU RYfS~+,&V#x31~ fz,Z"u x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X Tt@񖷒<痈\(@jJ  ,n]K ?6 3e.jx31YNT|e[lnW4x31m6{?= _vyL _x340031QMNMIKeh?kdDX5M @!3/94%Auc D&9hXq/DEIr1r%ݿ|?S틝9|) *X⯝bJEgP锔Wۻy+\kz0Lg-#hC[ 8Oʃ.L>s6t:<|`ߠx31;O0Tvt='ɰom a =x340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X T$jzs%rKebcb 5% %MI>xo])dx340031Q()/-N-*`a5[.h~_u믬l~nUU RYfS~+,&Vx315\1pbX4o!Ǎ Ϭx340031Q/.)ILIKf(ɓJD:?Z=ZbQV\X TtE;Wqsϫ{&@jJ ߞHkxS1;w$+xey4;4#l8ۛ5\9$ջ/&q3Afj}͏GCBf7 =;Yl+y CSyuj!uJ{>tlwƕű'TQ"Ԋjo028XYj*@y;PQjm[BYP$Aߎ~13k`9.@}0/]{dz*^)hڷtO>\NQM8E_hFJW _ :f`5=y/L:X@W;ӣ DXPq ]4Є?Zz?Qҩ"S |u9IU&iA+GS^WYXYF2AH;8|-Hq6rɄ~WLž10Wv뉡䒕7(7Wɍ8uz!li_#2˄b EUYK͢Oe YF A-꺜D_ftzKpsCseZq+@qCyzc؇K*XUvPClE5!Jm"&hݒ.W],af/K,ڜKiĹa5FOckx340031Q/.)ILIKf(IۙlOlgS5JB$'dJpaYsvHMICOKKWo7>=pO*ìxe{Րy?o40H8Ksż#8g@ h\P "RޭW^m)EOFSN00Ԧu. _m/:걙rV%m+ ?'-Qi7N#XEzprebRd̲k& DyGFY 5+u..eA܄G>辜ґyCk"RR5`pQc?)Ovݾ;';У*t=yƦԖ;N<~`BqkQD2xsVkx!=3`E8K;dmmےT%eUu1? .Y^,=71#JN,(j<w1{k59-TŗUx~lݏD}YejQIfZ%PSO~\jWf$楧BS};fv sT S{畤V.P,~: [E;;IaJb"PC\lY}5-꾽m""WRYGoٲ$تyGf )JSʣSͫՔkpǰjح")N-gS<]8I&[(713As/:}hSHWC5~36ۣ2ӋK2AI6EvWn][_?el4h+;t~ܠSBRT\ TpR>:/v 돠 MW]}P87l̶r/=5wm9IMai~I*Ph'K_zOjBRVJM6_f!9wMj}HSs>i&.uW|rEQVZ {>=V~;tPH?ʛӓzw3\!r=҈֤x340031QMNMIKez[~)k{m&@g.qbad!~?&3x_K2ݾC]WOo| `hwf&ۮz-qYGUJ36x340031QMNMIKez[~)k{m&@gPRr#jWװ0i6eX}LB ߬r.m:>NM]I Z⾳[ a7Ҥx340031QMNMIKez[~)k{m&@g՞eZg5<)+}Ҧ kP)Us5_.å-Zǩɶ+^KwQ[H:x340031Q/.)ILIKf(IۙlOlgS5JB$'dm8b|vك+4HMIPέUկaxC(ܬx340031Q/.)ILIKf,T~'^oQV\X Tyl {"fnb 5% Bu7;>W}W{}+x340031Q((/-)KfHc,0r;B{LU% %9%Α^}z˔9_B:x340031QMNMIKezVLZ..Oaq{?_4($U3l<;܏jC*=Qh1(8X/kc?)\7g L'+x340031QMNMIKec#9[Vl%Kޓ Rs*,r* Bclęx340031QH,Kfabס{Kak藌{ !* <2p&6~ UP\ZR TvJ$`q,[̾{m)cx340031QMNMIKeh?kdDX5M @!3/94%V`COGl%6'f~DEIr1^!cNy} O08b˦0xn/&]U6*ðj{7oŒSKB_0cZ0*]T\'Zb W]]?T$+U*Y̐)Nu iW x340031QMNMIKeXqOuΜGJ}e.|`QVX_p戕sU^Mݓ[83%ȣqcۊ] d6بUT\Tv~WŒWDVVQR Tm7iW I~چV Mqxe}4TiaF*Z[t8^4LDx7]3wk^\E"z5b5CH6pN V[kK3,3+f4K{ީy$ b6Jte:L%PN;E\#y ƃZ']ֆ'6x0Z3;eb?49ug'[`_nKngS'ޛFس?<*&Gԧ9"űw?*hTi77 (D`4Jb}&y44JQ >"Ė1<t (IxD_Pi9]u8{qr`0F`j,Zy [z>̷Y_B LC_zXqA@ҫ۷( ]V~}EaEVMn% @6ª<`q XC4_h `f k%9\sq8³t/>r5x:ߓ5΄= !A6*>.K=Ř%+2Q)~gvZޜKj{kbU*е0u"b \3l][ iך<$pa;dk'DJۅTJъf/`/~][L<2?. @gJ+t-+J!L~$.0A<_s?( /J(uHmS@YiNIwZnǵ'wM?rswo8@!FWr^uZ۱ΫhqhӺ*>tz雛FlmX\y*+QlFi\-I9<}"ebhGaܘ* a3M3{a3T}hRPל` 8wWP!GO-o\wr)Ѧ:wőֿ% !IoP&S%cMe foXvQ䬩Zy^r։?I>rټw1SUrDHSܹU%h7[ 29 1~;HS_3t.ѪggFvg].>:yCU~1r7b&ċ[6~_@[:5= ѻQԩORЊGկg'AcOF!>&@8Z,2 M [γ84y+ߓ\y˛e"5O^Ξ?no$ x31˾/r~[(8v' fxeiPgX (8k^EB0 qc"|s-9Rcٕz@$ă0Dq)wH״wZu)Z=HrN/0a@$IVI;&$Lw2Y 3=h%[CwL~OgnI?G$ő΋֡PU&IѺf[Z>OVwS󙲧XG}d#q𗹦GddL?/ ņ0`Oi}LP/xT#f֓[< 콖qKܭ.' PvQ7m9ɒ7n \\Ek_è1d%d#ڎ/,c(|΄W8ET0bq7BUY>X6KshGau($3+LPGĥ jf>?zN;,w՛~?Ԥoy$׭hxj;$d06 q6,β-ۼqw,Pʜ2͚ү* 婨STn+h_%-VST |0PY>7.EGW!xaxS߹BEzU[yK|٠86 [UDԾo2>(Nrēd7 DFk]:2NY0${ZK~"d*"dʱIIM 7KuYC?W:xn>b)ϊ>*)Uih{yab^3 'icIl] Jqh"[*<(UƆֆ%*qcu9mhrw\y$%ϔDڬ_4._z+E鐁ޑ. g"̂`j.T>]7hi2`t &Q.7$ 6ܘ!O+g݆fJ+n{tFphä?|Vϭv>\~W C` "(fꅳFtu3qÈ/'dɩIlQjKf,*.^^x?hh\1]q#ޅJY$ǖ7_] EI # xzJ`*|MdxeiPgX (8E! *uVc$YHqw#p U@+  D(9 DXT*"&c=~/wxOGAUgA*iiUwbCh<9/]D 2rk68%oʤܘylp醇(;Bpd8`C|@9:yWVͲs EMxwLZj9!{™u `G8)iGoFo$'+Etk]re*JS(jI\Q+ +bnMf'Ok]̶J|T8,,d ;'H|ɿ $@.zYw7L~`׵;ݒmB KY!O]OI\{:B<=Ȯ!~^ NBIDg%CLWR}8Q|#UmmnJڮ-H!CP|s n^~*v; K>ԯ%8Ldh)Śeo).ۄpiJP˻m'(E)4ʼni$0pJX5u[N٠9e?NX_'\ދ4';OQCԛhk?h ,oy]mbA`!gaqq_N*RKo*{!x1 q$U ÎCQڊ,ó(Gӆ%1c_!sx/awpjIs?Wڳ9:j2.ءL=e )O%2ٵ=o!n঎IpXzI}i3lt4vI7&>UVɏ0a2>JRL}lF;F,XSdtzyY]LETI`<+ nOw!_ԑ0P{B){LR--‡f[ν%r[7Y̽}\4ck2^cλ) .ݘ&\. d'=}f_BKUv3iC@kX: exSbDPÄG7'9XO1G\p45ogQM]p:X vhO=$zCNM]I Z⾳[ _37gx340031QMNMIKez[~)k{m&@goCĪYܷ;f6eX}LB ߬r.m:>NM]I Z⾳[ `8x340031QMNMIKez[~)k{m&@gpG_3K2ݾC]WOo| `hwf&ۮz-qYGUJ9ox340031QMNMIKeh?kdDX5M @!3/94%i[S]K+nj(I.f01[kzߌVoRj Ma)6)$'_L޻Blr/T:%%anފ%.`~a&T O+V`R~)ᄘ\S.s~7 +ssSK2ʎT,e+}='px}{<p[RIC֝eMHѐkSj31fVH(;&lcsbʝ,9i#rΦ\9Ʋ9Ψgyvyy>3ff_ZY'Ad dBJ[bQ]h(6betH0MvV,NG5v|m.Z$ f@$@\u)mcb!#'n#k ˂o]Z%TJ%1`YZK櫢ft^{r!V؄Ca4+äjF؍tp bPM4|abߪ FsRU￞r {,A. CQgl`wV٦)o#uYV@LX8-2z5]~k a׳ck2y.-Cvi`!.D_oZv)+j&Xt*ofS=إ7#uOEҙRf^r^CW SvSK=PPcavJsbkVEZ߯sP b!ⲿ[9[$Oz ҥPq EɊskWl(o9v3$ b%P$xSY1/N]0q7tF{4Ne#+lZ&nd[w@q/ WVf[t+C5ÃѶ^>%,^b ֳ67TyЏy^$⛃erNn%I=aߪ>P$LA|_Uwh&Me1c1xB$ 9u++1=H#kyr cr6*@#A0tʖⷮ1X7{e_V)_e{D;c9^G6,5^ufp 6wvp` #Ìq56l-I PQS_oBSݨ"-@T2A`i05}.اs:1*|%ZLt( ѬXVDMYd-ϊfekɷ[ػ!¯9elBOʶLDd8 ;]z~7!ό'Qs#77hn'H8rxн~wcsH}a8%8F NS}\2/LQtRT1xE}'f2o^EFN}\Zpzio֔@{Nkl()h:=H5dLbRՊrh1QS;k ~oHPdd &^414-QWxuѠX6n˱g+DAuW_l_?b*M5 P{ȊJK2 o\xv=R JKRxJop.mDRXP T=犵}zw7gۄ@RTdeys`8~cn^_f>"o+loYOkزmԧ aˇ颗n b#1 YMYN~:P>{?U˂ol:IYv*(84W8=]j5饠 <rYhCVҊ"e%d惒ie+-zcN+&+ LJ˓玧ߵ{+ʳdUE*)x340031Q/.)ILIKf,T~'^oQV\X T$wt}]GV<f@jJ >t;>;TF J;Ed3,^%@VWZQ )S4~cNSL,DRT4<|I0YQfPQ$FWg1}tͬVqIQ*(\6|SɁ]ECYՔ99+uKn6~/DR d{;DNzHr3@oxSkԖ:1Mq"YYfzQbIf>()51~nhx=kϯvHJAVE1o^cͲFw#)*H.l*8D筗yȗg,CV J(ghc/%_pIMai~I*PwZBU6 n.a=IYQb^J>(5fZnۼOf HSsxu $X?SLPT夕oVNl:R {hT_.=23(>x*f7`r!:y8x}{<HjtҢ.E#i[l悹$Nq4Xr뤋V%ȭj$Ψ}vqu3 -{B)jsVv92VZLOMh1;YZ#nڻ #&3y:uڌypr'%{tQ&Á,э M aGI\zǭ]M&n=u/\ROPR$ZWb}]w4f#3X3IL*,2n){'NR57ۯJ8{JJ;1.(cי_iLWR0:c_=4֍n *mTЦ&^5_7AK/$~{E# TxK웲 #,y?]9T2ZԨjäjzAޙ$jp2[r?Բw 8@RRC3I||΁g=HT^O{[,i/ rSssӋjJ|(lxJCⅦZ@'e|ޑPJgmRm],kX JR+J 7&no?#ڗOs, +#)LKNI,I*lɬ?s\=fARXT@:nrIS5> JIOzi]~{~; :d"LS[3y삥t$uE{18u?Wz8%V u95}^,$ nAV$E*8okśnN-)k{dEgW=]^\T$]H qⰾZ5-粏vFRTZ s C'YE[MSqox340031Q/.)ILIKf,T~'^oQV\X T$wt}]GV<fPx340031Q((/-)KfHc,0r;B{LU% %խͷal ke9 x340031QMNMIKe,c,%P: PH.,(gcJvB$Mg^_abNIQ~iqjQ^2qŬG!+]ѳȧ6*x340031QMNMIKe,c,%P: PH.,(g||q:vK#_Ii4SR_ZZT`r1J{,%)(*fx340031QMNMIKec#9[Vl%Kޓ &x340031QMNMIKeHx<o}Z;?wB%3WjWՒF%עMq#x340031QMNMIKeh?kdDX5M @!3/94%!r깹۲*׮)QQ\_ɦ_qj.0w!cN b,UCSRrDDΝ`nz7M!ol{T QlSs\&FOY, *+o䴧V#]=ONSf x340031QMNMIKe0whZ?Nhx340031QMNMIKeh?kdDX5M @!3/94%!r깹۲*׮)QQ\꩚XYF׊eS7>z8ZvO?͊v @H'd2x-^'HOlIZJRRrDDΝ`nz7M!ol{TGxͯ>>!/ _}*+o䴧V#]=Ic x{4ypЮDΖZזFI'(xM0!u2(%+PMJiYKR.UqήJ,̄?=!xQapadc΀ud{ukH/đ@gXW:9o-LOAa0|qCozx͘_fps(;6|W wů3˽yG)3$w^ʐpTgoؚ4ܿ0 1FpQiך㵩B@DC4nUufɕVNN>Qt&}&MtaeBh0z'g(r:?q}qyc+DA&ߢ;48)ҔRE0"#͍ e>sqZ1UE _NnXfxdS w).?/mi)2DSIgyvkt2p@0BecE%sk r1Ves7=fl|' bJ!`=^/h_\D ,d;7mYx=5%4-Tofo,2|[ksTj/>tQj1+FA HoLc&ĥ0o)JEaUZ:.L?B`* (ϛ9V$7$g' ܏ {5H:d2b!]){>>ghv>#'s+yӗ CvʓUKB*_Cd#IR7U*A[n"ucV\>gؙYZH^ d7ݷ޻QDZH5(|r{c.yd@X62e!ohDpiӐ.5j)N 2,(gɧ7u932&H򷊭R s"\Ib""C銒ja7G7*VQ>ֻg;h:ݕVUˆ,sni"(ncx340031QMNMIKe0whZ(,ղփEM?i5M^ x340031QHN)I.N,Kfr}Y߄Xn8oD9C̔TgM`Rsѽ~S2KJr@$e?UqIᦽ2yzC-,)*I8ɯ^lT-*%=ծx340031QMNMIKe,c,%P: PH.,(gi8y?Μ-.)bNIQ~iqjQ^2qŬG!+]ѳȧ>*x340031QMNMIKec#9[Vl%Kޓ Rs^58zαe2w!x340031QH.,(Kf \ضu ;ٯ"x340031QMNMIKe.:7<`rvvn~CҒ"dM>k?e`2Ssjv<s!iU/xN,X U TbzV:G|[OT_* JvnWzĂLV;f}z~bMs_!)*P,"87J))E"^g,pq;9p\YigcE?$eE)y9@sNYyjSX\rR֡/+U$m?5Hxi\rT}\1scE̐wCRsZlR\~Lܾ*ʿ3LpBږf=Sϭ@|v=T#"Jf9VǟyJ]~!џu[FNr*vNVv{mx340031Q()/-N-*`( 779K'%o3*)]R/hF g>Gbx340031Q()/-N-*`xة0㴼b >#*?7*)]R/hF g>ޤx340031QMNMIKez[~)k{m&@gp3gZaS¥M?nߡ.SxP'7k\K[0;SmWRCﬣ*V%;\x340031QMNMIKez[~)k{m&@g1eKs^tqѿ)BpiSw^`*9͚/ dەP%;ʿUZ:֬x340031Q((/-)Kf'=6Ӷ?y1$dMug魛vIGV[xe5L.x340031Q((/-)Kf'=6Ӷ?y1$遂gg[OyiO SR\VbY| ̖1Q1B,x340031Q((/-)Kf'=6Ӷ?y1$-ÕEi}}_9h^p5GV[xe5]/?x340031Q((/-)KfxX_p[mQU\\RҖʢ4꾾/o]LIqXguo-|X2[GY-x340031QMNMIKe8w_Q^YfCҒ"dM>k?e3RJdG~ܓz)AOu|bYT<:l TAfnbj.PĪ2)w00N^5$'?@-!(Og5;U N; k80KyxNj^AuB}pGb`{ж=$'TQIrq|iIfN1P&>O=Sƈ_ *\r=dcO~q!EoY=nh1B ?.^XgҺ-%`cwmHbp}!wj.'$xKNa[#<MHAx340031QMNMIKeP0ƹn?s.^z,$#>7H/ԓ_dּ׊s;v TUrbAbRfNfIfj1PT/ i[Xu TeF~qIIb b97VQu|cԩPe@%źek,|ѦYLBNf^iKqzsNZ qYkVMO]ikT- 'TM~RPAjuWsy]SPEP->gzlJI5ZݞN**.Ȍ+I-K̉/,ķ_Y5~lW,HKK2s@ʊEC$yʓc_N p$dl<0XSٜuT}i"ߏwZoSF$%ؚRfcՁSo\0w$E0i|Ȼ9 im#?BDOC(KhF;#/:"㈤">dC3>Yՠ:dUE W:To!hO+"OlSMEM,ڋPT(߸CǽKU%zC!ԀԺϻQ"㮌=g>STwzli k5׉dOI%EũE ']0ZiZ2/xhߟdz ;!W[\~x|zOmr|R`j ~;*&z:95`M?oO$>D3mOfߕ ./.fp?/Ϩb5x340031QMNMIKe,c,%P: PH.,(g͋[جV$ inظン!ĜԢbdvYMCWܣg)OC*x340031QMNMIKec#9[Vl%Kޓ Rs%ȹn;zՁU<_Bx340031QH.,(Kfi,VEuFJE\b.6, Ԯx340031QMNMIKe,c,%P: PH.,(g1!ݧ˹̱\yC9%EũEz .N>ЯtGR"u,#x340031QMNMIKec#9[Vl%Kޓ Rs2_հmL8#S^frݸ9x340031QH.,(Kfrq[V5= hlix340031QMNMIKe,c,%P: PH.,(gh8ZwN?dD>36SR_ZZT`r1J{,%)"*5x340031QMNMIKec#9[Vl%Kޓ RsRy3>>5,c񢞙ҳڤx340031QH.,(Kf砊"9wO<x340031QMNMIKe,c,%P: PH.,(gpnx [3ϼ|e2sJKS].f>"4}_rD>g +x340031QMNMIKec#9[Vl%Kޓ RsX&w p)l[Zx340031QH.,(Kf~F|YAsڋ ܮx340031QMNMIKe,c,%P: PH.,(gЯtGR"|+x340031QMNMIKec#9[Vl%Kޓ Rs8ּޔoŴ'&9x340031QH.,(Kfx@ua&?j Χx340031Q()/-N-*`8,}IG}~%>mnz2*)]R/hF g>^x340031QMNMIKe,c,%P: PH.,(g}Mn´7#}9|M5SR_ZZT`r1J{,%))`x340031QMNMIKec#9[Vl%Kޓ RsN˪bgӺ>`x340031QH.,(Kf}A+-NMx340031QMNMIKeh?kdDX5M @!3/94%a\jYr5.N{~Rb^osٴUlK^~-x#\6a]W_xS ) _u6~G]*IIaHZ]9w4= rPb'*^ޝ%>A|B. i<εV3h~ /ey:x340031QMNMIKe0{^q0+rϼ?嫉(d3ho(V yկ{?M7ZY̰c_ͅux+[-J)ʰ+){uKt?e TAnjnnzPMe-QzST ,ەL7gEя3by%%@9O߹ JFzϝzW Iaj^rJbI"P_~Hx.KaF^H 33H-W]n8r~ϾT$UI10I/cooPA'LdU9ɕ d8O.J4@.13F~'Deedʼnu:t/?g ރ h>yc|tkp4H3hêKv 䄚P\Zd tֺu4Lh]o/vwnOG{D./W@R zOjs˦ϨH>8wq7ۈ*hi*4ZTV}(߲OٲsE.Ah'sGn_q*I$z?'lM9CO"`<t7ϵs7 [="X4N޳֫. /}qp.$uP4Sk@El䈾 IQiIf(h'Ny)㆛j}qNM]I Z⾳[ ^8x340031QMNMIKe$%DN.xbQV\g^oi.H4-KK){c{zx340031QMNMIKez[~)k{m&@gP4OzȴU4[0C385v%5k:oU2U516x340031QMNMIKe_y܇JћrC51l 1=O֜s{ICr2|C/fyO{U^TS}CYf{Tzj/4&?) {v%C< n{oX-BA|r~^IjE PaΓw.^sޕBRXT5)_=,RQm2Œ qUfNz9$UE@UR LzK;X%1T$YU~Nfr%44A'K"u:$uE)٩ .13F~'Deedʼnu:t/?g ރ h>yc|tkp4\$[Vo#eխŧ 2o馫*ZuqT$u6ls7XqӺHҁLnEe--;W( I4vr9w$^pϩϑTA¯msR۔#> )FPHy\+-gO,dxZ|o#+#m0$%%!iMtI gx6AߜrjWwRcy5vf3ZCA39M;-jdx340031QMNMIKe0whBV\ T̮J׫k9ny3 uS{^GA$u%@E]*=8f5k-4;$ x"T:lwȽm˞\p;Ԅ]$[Vo#eխŧd"jmg}w3ߍwk}ˑWSGR4dVJӮ&8T~;=Mrd~I$݋SVŠfV&$E*8okśnN-)k{dEؙgW=]^\T$]H PRN,]И3b?ҒP^[trv7aϗa R?ObZx340031Q((/-)Kfh"A^ylJ9n1*).()]S+wtY5'?Lx340031Q((/-)KfpqZl|g!DUIrqHI[ښ?`8i6{?"x340031QMNMIKeHx<o}Z;?wB%3t˹I2`C385v%5k:oU2&R5$x340031QMNMIKeh?kdDX5M @!3/94%:ֹmDEIr1Cm]'^?\dSl C}m^([l^/B:> aWK3w~x79?/ ҷnt,N)n 3FVVQR TÕ'ޯxsAo.֙ͼV:mmD[ x340031QHN)I.N,Kf:FQn[L7|Y}.'83%j]OV}y~92KJr@3㵲vη haIPɢg<=]_&O|/sJʼwaAשx340031QMNMIKeHx<o}Z;?wB%3l0N?\Qۤ;!7x340031QMNMIKe|vlկ/"E(Rc PH/fPd9_~d[o1$;(5]/@<CY.HM7.xL}޶m,Ӫ۠ rSssӋjG _x[}ݝP5IY@2+|reZ\ C '畤VJ}_$y)%@,yk0E6VZ,Py?7f$gU<)jwC~b<YU~Nfr%Pl|CzƉˤc?˭y~lHJ r"Ud|w2*).()5Xs'tɯmlK&#x340031Q((/-)Kfm=C8s[.c$ E}F FԬʓx340031QMNMIKeh?kdDX5M @!3/94%,œ+=}ټ>=$Cbs=wodrL9\6Q+ /m9 !Xȗ󕫭|ynkU0]d'-5@ڙ ߙuyy995{; >g`QUR\PR:TQnG!ݖ%&a<x340031QMNMIKeqzg&40g/l;J !JS,2l?ђq}BYc x340031Q()/-N-*`2knk[#mY} A zK/Z{iÙG>94j 'x340031Q((/-)Kf>5{; >g`QUR\PRrTF#"23"f7eݩx340031Q((/-)Kf<1wS?W=X4h_!DUIqAH SWN<˄<ݰKL&x340031QMNMIKe,c,%P: PH.,(g01;+煗{&N?.n C9%EũEz +ֵ--i띒NL9+Mx340031QMNMIKec#9[Vl%Kޓ Rscx;k7i|3# :6)x340031QH.,(Kf0z\*_ahfKpꚫQx340031QH.,(Kf%Vר]W]8B77x340031QMNMIKeyb.8/t41l~l\59x5THB N,JMKfXνݍgC,]UR}Ӎ ^=S|{$˴*b6",a?O׵X~tczj򓲀 |]w[`a?PWZQrΤYBr&&_é֤WH SSK 6~3a*ߕuv/kܑH 33f^9J08WM}$UE@Uqٔ^jpKAJ:b/jM_:|ȳۂg +* HU/>pt0R dXs'g9\zw|5$ XloE~=Q r ũE% g?>\9WiҍO'4>{ST>ϽV4\$=zjf?dtc$U@KSA7K}g5yĸ!ʨo7 |]&?H a}nf3|XrCzx6"` o9:ZÉ +ξ<~w^rr"$uPo)-z7K#.;a ҒPк0FVgsΖGvsHlzx340031Q()/-N-*`زH#ֺǘE؋-eUU Rл?^zz]WK|<^x340031Q((/-)Kf<1wS?W=X4h_!DUIqAHU>~ ̩dBĭ[@6x340031QMNMIKe,c,%P: PH.,(gx>wܚY!ĜԢbd->swM{bH;`*lx340031QMNMIKec#9[Vl%Kޓ Rs}_%$K3v%*qx340031QH.,(KfZ;S})z9ߩx340031QMNMIKeHx<o}Z;?wB%3m_V;9kp*D"&x340031QMNMIKez[~)k{m&@g̰!~bvd9˾j%\ڔAV$Ս7q9sK[0|]%Ǜ ] ǡ J7x340031QMNMIKez[~)k{m&@gPtݎf\.>6e}(IGdcu#e\G 6_vyCIBq(8x340031QMNMIKe,c,%P: PH.,(gJh-%-*|nQMSsJKSlr+!""'ߩx340031QMNMIKec#9[Vl%Kޓ Rs#x340031QH.,(Kff?Oy˪R| ('x340031Qp  fp*-WY-5(qHKOOgPMnBRKO,Upv}Evƒ wnl 71;5-3'U/1@|B&n;䬻SB319'?91G/ׄQf;MmW;u)TUR~~IqIQb^qԣsuH)$HMKc KKL/-Jco&ֺo}6t\lb )% j_t:9|SY*p"Z<])ZSr=Gd~}"Q>bDnbño[oW[v"}gIdmeyͽVzCdKsB hx{5A$Ë|AȮx340031QMNMIKetOpL xsa($U3T%_̖ux>7Ǩ&)C9%EũEz S6WXGaA>b,x340031QMNMIKe8汶Xt"=K/B'略%3T|M{ٛg9z@ B]f^qAj2H×}/LkT{+xw01x340031Q((/-)KfоM_^vwEg!DUIrqH2XS{C>%x340031QMNMIKeh?kdDX5M @!3/94%\nf++X%d6܄(I.fy$o)QEY) Ҿ3c̖vz;t|bA&4.- ˲sh^șt(pTIJJý%VxD/ج *]T ng{*Eh>nL^0-dx340031Q()/-N-*`#}B]]+2WZ-jUU Rл?^zz]WK|<;SAx340031QMNMIKeP0ƹn?s.^z,$#>7H/ԓ_dּ׊s;v TUrbAbRfNfIfj1PKjVe;ϝe|2#$1 hokEu1vwT\Nb]ϲ5ZO]hӬt[OM @!'3S[̥8sK=wO9'-M}BMͅ{5JN*ߖ~&?) t`~5S="}H`.eq^zsUV׈5A3R*nn:[ˌQoST9Zٲf sc({A,glXߦhm҉eQBv'Ές&E(OYa &n ןxg,.)Ԭ0%))9@ulĦ_5JwKTXR_ZZTbaFeRչv J$r5|b3KneW-H.yxJrKJ&ՑWhtqo ,qke#Ԁd}):wE3.E@]^\psKǝx*=8R홎x340031QMNMIKetOpL xsa($U3$d*%26&s˘ !%3k_oP kbef a4p+x340031QMNMIKec#9[Vl%Kޓ Rsvuw9 \n-hĤx340031QH.,(Kfb0+\ס"(y$ŷ x340031QHN)I.N,KfIwEl}`UWR Tc5 ~ú/.)IL)T?;AkKߩڎWßx*ZXRTb?c⚿Wj8Jx340031Q()/-N-*`h}ᖨ@rSyy4*)]R/hF g>wDx340031QMNMIKeP0ƹn?s.^z,$75G/};ZyV ,{ LIiIF|nzPU'Ȭy'ki}wĂĤ̜̒b/>*qbv;M", TeF~qIIbi rn=ڃnݩS2sSsJ:5"u=h=YwMҙn=51̼ Nm1-=5眴4m_ 5"75 ֬:>(9|[N,uǶ٧`ީPEP->gzlJI5ZݞN**.Ȍ+I-K̉/,A;F8bS3$%9 eՂ^HݻqYu׮@-I. ԢD~6gEa"U$-rFu<%dw7QīI}Iq(no(Lk͊+#).bΩ\b'y]ӁPTvssׁZfK|c`ր">dʖ5E\/`]p@dUE W :fqf?cR6EoNE('bW?uFL5-6}4h/BIN~:P͢ t|6tcg#ԀtxIs~UI j fܗˬW[\L<# vY=3܏'sG6ӥRt&f]^KWC;2Usld.ԐʢtE/Nm پe?'SXx&'`z>o[6HiU\mPE@5YJ7J$%ei?cHDeAU%'&gh9|l~s\W&*)(*ȨaxHkV$Ϣ+$ 2sSsAٰv-65ZOFI_$'?̾ { rZ*i>?G+ P((fkY/"3M]=;+ (gpW|.OVscҒ̜b2]в}w8 Dٸe ǞCފNM{zsRbN}mő4 ޛyk%`c"ElekFV$rZPSE5}m㳌?& Lx340031Q((/-)Kfp+zMY؂B҇BT$}ĭ}e~U=m2Usld.ԐʢtE/Nm پe?'SXx&' mڹ>^l'unBF&TAnjnnzPϧZ,b?:o|]P5IY@-N؋}w7X9u JR+J eb\[=y!H SSK 6~3a*ߕuv/kd33v6+{m2 * *H.*ڝڛr(.Dcҍڝ*?'3bď.^o̮$uEUײ-/*cWSI]IA.PHs'g9\zw|5$ f],,|Y=j CM(NM.J-9{ʣV* m38u2ҹ )P1ʝ\VUH !jyZ]?9Fn?*hi*ȴvw(ɹ0/zCŃV$uАoXy-FWoTAjZYe|~ްpK$E*jr@su{s?y/AV}wy$Ta*EH nz/ za)Y$E%9hn8}o!;-|Tk$r3 ؚ3έzΟe)62=x340031Q(JML)H,.Kf8b~gs-KJ9Q0x340031Q()/-N-*`Q&{ƷEtR A zK/Z{iÙG>9x340031QMNMIKez[~)k{m&@gU9[k ?ZuW,K2>P#2.|#pi kv<ۡ$xQ}8{L7x}y8TpKDZhXB̠3.iLgs4pf3EthQTڈ-ג$&*GnD;Θr<:ϙגּZckkB%9IKܟ=0U ќY:y, n%٩#=[lQ;r!(bvƭ2xcޕ ^80ќ.sF67erSr.ר| 0m )v-hs:n M*k龗隰0Z`mfrOI-mK?E5"fK ,fR5&C/sk̨{qNgYx l}9$=c3gOWznsd2=(O3a ,K|z흽oӬnbg{Fh-(f ,_ގݐ#F7БC Zb.D#e1IS gcU*vҥ|J.vF&Q ;lZRV\IldHsrnW'4 ,/5Sxl3֊+ܾ|aO`4K0h3m @t.RyO ~Pi[A-+0BHO9.]/o]|ȖehќA2in}~ l:r;Q!V׍Y/2K!*Q'ҥ _ߏ-}B.8%`)v^~/jvmhf,wFFPR |t9yj/9WvVT['MS'5}t<ؽV>MBċ-ԋZ'ەo͒3'$ÅxXY ǮR ?462( 7FF4fOQ4]?n]Th)pWm2$"^?ѱDsrf"sOb 8vIc+t& G`,ocXq aw!tC'3 I{C࣢_ ZvL%r/JA6YBQWqzf~|$}Պ}}xY,4*+DA H; 7SL•a E"y`$\ vhL+ vVfR7jGbZ'0=-U>NjFn xF ފkj] ts/+0@7Ɨ:J?.}d9LlQcr.>AZUqMsn"@}q l*Kzl/IIt<æSg4o-q;Ϯ5v}NOMn)򷬡m{L-ܼ>@=o w46]7:0(AkX,( BG3]t3@rD桜(' LzG{AVk@KNmcl9%(\)uMgی n20<;DRZ8|y)'K.*JI J w₶$`v$h&Hll'?fD,n9_z#{YQZ6$%vQ2nֺӄGWk^qX"|$o1DFlt*~ݑZqy »&ȓ@ plvh~nl}3֖k N(uZl9\.1| *̝57e^ߝi*egA=J[,p7)y21 ?V騿GZȬw"]96@,(5(L = 0 -R_?bZzU'x340031Qp  fp*-WY-5(qHKOOgvk{i3t1.Ҫ*tv ve8>r"mA;z76[U⛘` >! kܝXur)w\Ã}4{kݚʣnz<&)151.9L۶I?>)`e WG_W}L6<'+Ҽ{QTdV0\q@%hAg *C]~kỿ.E׻F8rCssrM.U:YXzn{SBU%%g0L=:9WQ縍bKشd;&ҢT<Ϥ7f縗dP[.ab )% oJ'3?lb+OkےOW-dJ&f\CϺ|h9_ߨHETObg/7i?批d%_e5]P{{16x}{4TkprI.u:TB:G cfJꔚ36{={"TRRT$q-qehEV5'x)/kY~~{~ .h )sEIN6o>~,Ufm&b4>brt`K[q fN?wPvዂp`X'Nx խ 0b W.vTǦp鰽Weڼ'+dc//Xqj~ _zs3gحPaMzzB&-llXT3#q[*ueڥkЬV]{bw"FAA BP6Di CMaFusx B} X%C\+ShŬi \ Bl);cVT*HyyܬK>F4E^.`?^3JyU d6C֑t7f]LZdPf^WooaTc N}s$hz$ji [y4'-ۓu;]0pG>^􊜇Jc 辖92*2?#:HEKW&9jN`Jk):~. ̄H{پ I0gcL^ǯs3p.\<#.=Oamr8*?rY:̚xrWm4ox)nXA?"D,}Qꐏ̂i|]0 XR+ze1.w+Kf(!z3rT|vmON-wdY9*/4 Zz?cSFϑ2mW %fўl@f!r{wN>96Ro7?g3Wۓ+*jŃ,OKs" S$HT5.FÞ5c@I0*eOv [9Oex1\ADUM*ZEsrQ?&]z E& vnubݨh/'![½/JeW%~!oXhilTd\ S>h0(K.濞x<}ro#* 7V<3MadBŠOWyO2(M{QW$! /~UNzJ& io okWn/kLVmk1&+!vԅ;=9Sv;$n}NnN$ 7 [ʭYN(4~{Tͪ9;Pl6.Lӡ_#eiZ6^䈚<.Y5_! wMyfҠiu#oFq4]n*k O/ ~!iJb}Hmc[̧4(AָC\߾YJ$1c>&ŢdtZ+:#shO%YOG׍15"e->ɡ8q]yC.8[b:ձ2%<if񕻽)Q➖Ңpɦ )TkO%JEU$ld+BD9ݢy" ߝi'̠FqYu851C'O6w 4\nU湆_9>@@esi#J٦x340031QMNMIKeh?kdDX5M @!3/94%i /6Y$5]߃(I.f8I}_K :oԅ˦0L!ٴeҺi6H 6x \H*IIa2Ѿ7AMnxvSqm?.ʃ RV,bk&PnT jUx340031Q((/-)Kfw9׼,.$'n+g/WO!x340031Q(JML)H,.Kf /xSe gR.X J[x340031Q((/-)Kf<1wS?W=X4h_!DUIqAHsN15).ma;Z^:&Щx340031Q((/-)KfȘpg3[M;/1*I..)9`[|Յ{px340031Q((/-)KfȘpg3[M;/1*I..)Jd=e3l+侬< 1>x340031Q((/-)KfȘpg3[M;/1*I..)xtηy^5Xb;+Ux340031Q((/-)Kfд?}Lki1iQU\\R4a9։im:ĔV 3x340031QMNMIKeX[k|5+St5fl0(+(+.HM.Kf8rybϝu x340031QMNMIKeX[k|5+St5fl0(+(+.HM.Kfxȯ/<|;o Hx340031QMNMIKeX[k|5+St5fl0(+(+.HM.KfxvF<f29Aghx340031Q((/-)Kf<1wS?W=X4h_!DUIqAHɛ:]/d-n1=/x340031Q((/-)Kfд?}Lki1iQU\\Rr7ﴕ ^\b@x340031Q((/-)KfhyK:8LMnFG !J @J.\=#6r+V Yx340031QMNMIKeqzg&40g/l;J !JS,2ZUo~,Dax340031QMNMIKexee}XH3O 51Lf/u]AӰ[>-uwx2 x340031QHN)I.N,Kfy8/7YEPu9y%ř)@Uv2.?(3yAOPU%%I9 e?8]lgǂΛ8Yʀ觵'> tS#7n;=$x340031Qp  fp*-WY-5(qHKOOg`WZ{7X#!ަ\ZAx:2]bݶ -gm*MNMIKe0|񆵉[N:9Pe~ >5gnuQ7= musem$w2TY+Cb &\IiսP!. DӬpc+3*kpw~sզ6߫*)?(@8AEN譬U-f':0.9?/-3(U/3]kNTm}Ϲ,آ9&@Y\Qn%⬝][_oVJ'3?lb+OkےOW-dJ&f\CϺ|h9_ߨHETOk0R)ëGWn6"[\oo'so>S,.lI~~N1CD?rj7f nXX@1Qx340031QMNMIKeX[k|5+St5fl0(+(+.HM.Kf (~{}h_;܍"Sϯx340031QMNMIKeX[k|5+St5fl0(+(+.HM.Kf8XGORD#_2] x340031Q((/-)KfhyK:8LMnFG !J @JX~qW?4vx340031QMNMIKeh?kdDX5M @!3/94%aт+x7}W:݂$a2675'ݞx6hRf5\6uMRTk nQ0yO,dcg m BQ ))9 T{>w_S[F`2tQ1PNֹc]q*.%PyuTa/ ɵyύضhwx340031Q(JML)H,.KfXri_H8XUK?שx340031Q((/-)Kf<1wS?W=X4h_!DUIqAHI!?mڢ+ڱCX_7kx340031Q(JML)H,.KfXv_񍤜47(x340031Q((/-)Kf =c۶{/R|9KCBT$0>tmڬ{nv:vӛ$x340031QMNMIKeh?kdDX5M @!3/94%oi&FO(I.fxsQL^4-;.pk˜Uz t|bA&Cfŋb_vߟ1TIJJC'n73(K,MKfHmkbId))-ɈM/RTv)B^c-U PUɉ@%oyK1>wps^UU\VT T$I|w6el$8%>9?/ ,95{2or\{z"'de%E)@;2]h\}g gы#} ,/J,*ԗQމ/$ b~ x340031QHN)I.N,Kf@/we]9emaUWR TKUn7[b5q6CPU%%I9 ek*J{~eZ~cޢ]Pe@ K J]yɟ7sN#7B@.x340031QMNMIKeHx<o}Z;?wB%3D}`h^s[+ x340031QMNMIKetOpL xsa($U3k 9Į5_M]j1(8X/A`δ$gieK+x340031QMNMIKec#9[Vl%Kޓ Rsnl.8p3.sqqFپx340031QH.,(KfOe_<]r/\ ZڴI4$"BzI6 [OM{{G!٩E@eXVdYQObwR{jrA V 7kRz,VoO|g!'畤VnѪ'Nxg9y~vH SSK 6~3a*ߕuv/kܑH 33v6+{m2 * *H.*gp+DFV\ Tgem_kLք*~3 uoX&:>q=ԕ>z}Våz[CAGI+\ߵ! ũE% gs_|ٷ.\{zd"Rɒ/ls;nJ-jBhv8\Yn\h }&Z$U@KSAdÝ6紆vI4/Rs/ĒKҺSTAө.,O82NHT$"u]ݩuƉ%mȊ`#GM+S&Z2Vl8vzٯ]{t\IQiIf(h~=J=g%^{ZbRfW֟}bSS/Ax340031Q((/-)KfX>jY#L['!DUIqAHɶ[-,*&\ou,}_g|x340031Q(JML)H,.KfB~r|[u4I +x340031Qp+K-*LKfo9kO^B3w=X(jQ盘kɮ> ZڴI4$"BzI6 [OM{{G!٩E@eXVdYQObwR{jrA V 7kRz,VoO|gAYP zm#$~TwqjrQjI1>%k/`Z~^]YԊBC%_<-vܔZb%?mV$)%@U-5W֦>yC_#EIU:Tii~+,?Yp9FRXTu[Bޞ{!\*hv @EONuYeyBơqME>GRT IFoN3N,(iCV 2LEWMMBI]IA.P̟;θ]z}ERTZ ڶ_RY8 aծgXKnX?x340031QMNMIKe(/e[R_{FJ !KrSs2߷3>ŭiŚʢ”dU-x{UzMRaJN,HL,L-{SR*lӴ,ϲ@Uf$&0\"*/J^g73)|t,B8qԾ3bi賠E{JrӁj=l+ȼ`IC='Ryn^((Qלt_”D1Wҝ=45Gp:$3HueUxt!M0C K@^b.sϸ9f;^; SS\q/ل_ul3wj]yG<:#\>Hx340031Q(.ȌO(/*)`h^z:Ong۫'a{db  s2KRs@*?{M>\ƚxX|ׅP%Jng޺Ϳs˷#+-,H!gs7%={ ɕ󝟱a˳__I0),/-N-~b؛2'[U%SU R i]Oè'q#Yo%x340031QMNMIKetOpL xsa($U38>y2lpƪnXv'sJKSLKr6P._ɱYvN_/x340031QMNMIKec#9[Vl%Kޓ Rs\]w߬] 6,۫Fx340031QH.,(KfPIæ]MJH'a Cx340031Q((/-)KfxxnXgRU% %L0i&6랛΢]*ۧx340031QMNMIKeh?kdDX5M @!3/94%3#~9?y}b3R[qy.N>eSeyB}ã BgV]y%|TIJJBߓprNtQ1P7ټ{gax_n{T$mɣ+X5^Nhnx340031Q((/-)Kfӱ-y]>o%k$i!_3mfsYP\x340031QMNMIKePS|R1H_i?V[!DYANbIZ~Q^2_ns?8ZtտgSˊ3SRt̩rCx.C$'>[!?Mm>\YYIFQjbJ1P^낖'P; w*ˋ (c3nx؞:c x340031QHN)I.N,Kf؁p\&?9.'83%ʢ#bU֧^U_\RRRW֨>f-Udʥe\GK.m5Y <x340031QMNMIKeHx<o}Z;?wB%3Ul(=s_췥W}OX#4x340031QMNMIKetOpL xsa($U3OaT0lEWf o=sJKSLKr6P._ɱYvNC+Ox340031QMNMIKec#9[Vl%Kޓ RsJio hٹ{Ꝃ˪x340031QH.,(Kf)# =t/js +x340031Qp+K-*LKfo9kO^B3w=X(jQ盘kɮ> ZڴI4$"BzI6ChHB%;3F>rsg,Y5$;(5h+ފ,+INjz]9TMN>Ho+Xߊ~u>U^TcfP3YC'e~w=~?M ΂bKKNI/ڸBGTGU\jPũE%@&*K2Zv 3>9?$pE'[Γ:usR$)%@U-5W֦>yC_#EIU:TiIޜ:}`ٝ{e$gU;tQV4֋6N\Pd @EONuYeyBơqME>GRT IFoN3N,(iCV 2LEWMMBI]IA.PoN_Ũ":{nv$E%9u7VPYz,UDNqqF|bqvAbq1dݫ]>p*_px340031Q((/-)KfX>jY#L['!DUIqAHus8,v2(8X 5Y{HJSrw/ME+x340031Qp+K-*LKfo9kO^B3w=X(jQ盘Ҧq^=+A'ܷe9GOBzI6ChHB%;3F>rsg,Y5$;(5h+ފ,+INjz]9TMN>Ho+Xߊ~u>U^T#Ɠ*gYX0W>; v,-9%h uR)VqAu&M{z쪤2/~;Rk)ԊWU_F4$ ”ĒD؉9t?!峑T-McƮ325+[_dGRXT%X_%WexS @Eץ?~Xd3cͦY>x +r> ^eߝZgXP҆(?'3d=ˋ65lO%6.j!\ ryo[0qųo>aҒP&nځϏ}I]塐).ΈO,.H,.fPy=/cԫ럒꾲^yd x340031QMNMIKeh?kdDX5M @!3/94%anɟ-Ϸ$vˇ !*JD 6 dP8V=I) >唄.Ȧ't|bA&^Yg.ԤcU.=iNwW~.*j_uM_%/=9W| p8$E%9q/I@XTl."x340031Qp  fp*-WY-5(qHKOOgx0ouIwuN|Sq۶Ik|<]]ή\n[xyލ͖36B&fe%282Ԓ.QQDdSPe~ >5gnuQ7= musem$w2TY+Ù^ƾ^'3?Rc/'5_?AάX|brN~rb^ _= KvT|vR⒢ .j]̼#~8U^ZǐǹS59Ż–>Rzbfb )% <ܲ&l#. |g1#T:?D.a+x]yZۖ|j!S$$713z֕CcFE*}bĈ<ARXT;V#''=d<|6t vyL~FFwEb~r닌H23Dv긽lc/Õ:*THxm܄l)M]./o`3BRT IFoN3N,(iCV 2[`j5eVy~z9 +)*e~weGX,HmٙIQiIf(h+5?rəWgz?x340031QMNMIKe}Vx:JR1(+)/-N-*KfЮ^7ysn-ۀ`:臭7ҥ+x340031Qp+K-*LKfOS:G|oS !|S2sRsfoq1\{L3/1ծ&@\TYPϐ{皌l_^(Ŵ#DAzI6W/DX0<^jKvjeQj:%/mil.~[6 ARu|XYcQyPE@5rOnP5IY@ >mQUR\PR`ŕ\l9_M׭L~ x340031QMNMIKe}̲83nEݜw{T11̼ҔTgtԛWfe^Y{SsY|DEIr1G9UY5؜ﴈ/҂˦0'&fx6#9# 2$I:.5cQ} $%%i~ĒOʛݘ9[r.{CT{Z}%nK Z 'bW9x340031QMNMIKec#9[Vl%Kޓ Rs8y4T-5}fx340031QH.,(KfhI _4+r`v~ x340031QMNMIKe#wٍ]V$8q~i!DYIJJ^2ëoz T{?:|G8x340031Q((/-)Kfӱ-y]>o%k$ĀR39/m]څ{x340031Q((/-)Kfr~f>8xVfQU\\Rbi6I.[u?zx340031QMNMIKe#wٍ]V$8q~i!DYIJJ^2þk(]f0ռǹ9%qx340031Q(.ȌO(/*)`h^z:Ong۫'a{db  s2KRs@*?{M>\ƚxX|ׅP%JK/yYr>r_>7giFVZRY RBVX/7m͕vsv#2g$z:{bͦVP-~FzƩ@x^5x340031Q((/-)KfP\g;9vKF_xfQU\\Rbi6I.[u?Ʌ-x340031QMNMIKe#wٍ]V$8q~i!DYIJJ^2Ôwe_fԄeގ?^.nL!&x340031QMNMIKe!J'}/. k(&30xgwƍ%,`zWj|Sx340031QMNMIKe!J'}/. k(&34?Rا+Z_+l˶Ux340031QMNMIKe!J'}/. k(&3> CW%x340031QMNMIKe!J'}/. k(&3}_}3㺜:`dCx340031QMNMIKe!J'}/. k(&3M`i?~fwI֋x340031QMNMIKe"uiw|DNCws灆e%))9z S]k}Ry;|xQx340031QMNMIKe!J'}/. k(&3쏳p{yV{Lx340031QMNMIKe}̲83nEݜw{T11̼ҔT,w?7 % w>b4zw-Y-p#u+Id48*R4CH'd2l)?.r9zEC0<1kMuZ]> 'Juʟ8n̳M+m{ {r^x340031QMNMIKe"uiw|DNCws灆e%))9z uٹ1o=*]<o"x340031Qp  fp*-WY-5(qHKOOgpM6@Wcʹ[ Upv}Evƒ wnl 71;5-3'U/1ơi\t5Ϗ""{מ*s fx6M9{wk+qIOD<Ц0`l+0m&]ʂ\]|]:'&^ۥ3tCk;fGp BU3~9ѭQg rfk° v,:TUR~~IqIQb^q{\Z.yfޑs?oKKL/-Jc}uxNڙ%"owlc(d0ZȥBYWuy17WhBNRgݕmɧ2PKrJr3@.ɽbډsD] Ȗ𺷪(/Q;^_b%3l}:KUgvNvvzAax340031QMNMIKe!J'}/. k(&3$w21l\:cx340031QMNMIKe"uiw|DNCws灆e%))9z ˬc\W>=ks7M{ͩx340031QMNMIKec#9[Vl%Kޓ RsXywejϛ.Om>x340031QH.,(Kfka4+>g'dwkKx340031QMNMIKe!J'}/. k(&3l 1Fj߬z.<I$x340031QMNMIKe!J'}/. k(&3X?Pw$=..(7gx340031QMNMIKe!J'}/. k(&3\h8QgU'x340031QMNMIKe!J'}/. k(&30J;&ÓXwIjǩx340031Q((/-)Kfj};gju,w|<$|uG}9' ix340031QMNMIKe}̲83nEݜw{T11̼ҔT]t7=a}~z *rW?;-3(K,MKfz-nIbofrSRZ^Tt󩢹8_j(U T3;/lfF1Uwmp]"qwP@% C(~h9[L-nA탭fE5^*6m(3X9yo߻FT_nߠR >0os"Rg%Ғ̜b &>NO]x7*jZ BY2ȱ{ 91Yox#>D k?w29;jJƼZd?{%: j @޶{trXin8on x340031QHN)I.N,Kfq֪ߘ^sPG0j^C̔T;j#ϷM=63BUe$&倔]<>m_^p?jwPe@ K JYʛzU  3~ QCx340031QMNMIKe"uiw|DNCws灆e%))9z W=4 4nma3:k6x340031Q((/-)KfXέuZ뽵;L}acQUR\PR2ɹ5z驗K=4w8% cx340031QMNMIKe}̲83nEݜw{T11̼ҔTom3݊Q'9 ֫ȝ;kG볯Y&-I.fLd|ӊjKr4eS$J96ão;4&d# 2$lR(H,=.P%))9 =roeۮrX{vG_+Xy@d2ڹ:_ i x340031QMNMIKet%)Ie=БdQV\VT̐eIߦ+u [֚UT\T}jW+ga|5GĔb) x4p3|VjF<B?"vn/mA2ӓO)x340031Qp+K-*LKfHX*zɷub,†u٩i9z _>ZLe]ag($U3LϊWS2"7(H/f8Q^V)Jŧ[sP[S+RӁ.)r59+846k%U^T^u9ԙA'e XJtoo/Ej ((f8WiV)TIc{]\ZR 4sk/+:! ԊBW%v_ tTRՉE H SK_JVqW0Jvly$U@KSA:`=;=ꪒmn.#8*_ %Ņ O?뷽I0,.[]Uiݢ.1'&IQA2($BmwNj?E350v%;da? f#cJnG+\Kuf~\k`3e3")*-R7_,Z5#xE+x340031Qp+K-*LKfHX*zɷub,†u٩i9z +DWIM)m{ڔ &@\TYP`39Zl޳?+^mO ʈT~ $DA~{Z.*ne)gCmN,JMEӜf|ZTMnjnnzPFB{xelRgN_UT7c*ѽn8_צq>rZP'TwqjrQjI1ϡ 8wO+D` 2JR+J ]mfaQ盘˰K4{ԔҶMMYib E% 6=bmM! KNWrJRVp{6ԖʢtKW^VO/smMM/ëLfvWP5IY@mR,7U_u ޷FN%  6!*=ilSRK&,oZ[g@ݾ켬0Ey%%@

Ay 3W_N|e8wwP}]]A$U*rr*-N6p@7- )*HSTi|ռ_̜(?'3dh6SN^~+o hSq"ewGIQiIf(hZ91c(TC +ٸeF鄺'hOw  x340031QMNMIKeh8qŶW.78MfΣeE)%zy%z)z%) /jx^@UҀ7fϷu`Q}?(8X 5Y{HJSrw/MIƦx340031QMNMIKe!J'}/. k(&3X0Ix340031QMNMIKe"uiw|DNCws灆e%))9z r{kf ^$j9\LTx-10 P w@l9L;G`cgd` >oq3#WzWLaYnu~r9΄Oތ8f#>ᅪ.ן\{\> WldGeL I]{,u:zʖyzeFv}jMdFqU%u}LM"r[e8[g/~d>)E0)~>^9QY$j/vWK9O"6a)@B/q]V~֗\w11.Iin} _@ xIC+'l~RsR=?lcl0ES⚎TnHm g4/)4GVXsw Yן$Q.n83>rRD\7Ï *I=fEN[qr45|]$K^þGҢe$me>$%h֥ ;Ҥo/I 6qX[|3>]͜4nd؉[ȋ,1< X $Rsg]6jͪ`yӼ$Z' B |XS-yA6Q]KڻzNWdɒDipfXmz 1kWIɿT)qŚ49R{,TfRNl10ј5H5f b[g:!TqNZi^2kي }JygN32+It9vc$ɛ+1"0t;]j2&a=* %WaiSyٖVA#^c{ñ-&xb{Dk &YI zYкy C@S8+N÷ MTqNQf>r}aB;JHCNӡGl4M@#! F\Ljq=&x'2K v՟䬰EV|D[I^1jn2%^?=~|ƑRI %ŐM1avt]3\> GhuFwOrV4}-ds\0ـHaDS!novlލĮWWA G$Ea{ˠY&N%> ̵ph+gB(2EaJk46 B ;` R Ou@|[H'I$N)”.ż1-Lt1)tۛ cl)TGK \Z+b:Y25` &Y]y3`Քc<9Yw:X ح::u&t4N){h fD4xy[̖D03 $jŋqx?xxu_= ;th  F[{&u ]8apʱ aA#5b5Gcs٨\&ɺ$U[DqZO)L[4/W[*q@\)|ǘeqF"`];6¯ռ͜|W=<5m.P«$䣎pǔbkf}qpu6Mbm5`=ێ_SʨTBL #{UxJ-.;$^7Z8Et]*d]#m:;н$B*YGxI<`%q–U鸒i7.?e暌:>>֒5XoI>{Dh{P.,fHF6g 饽SR &c3![-IFO?wϻnlXڇݨb5(8'(tYbCEGggmY}Ϗnn?3S!&_JZY^]&šRk$Gפ[QhÇG'y V~gYgJW8u{F#F"J:SEĞж8?G n0 >~~l9&7%bH$2a5kQy*z9o`A@ chV-9'W=/IQPzI؋,B@xAOT uJ,褰*<2-ߘ;km7LêPTB$ T-D,GԋJ4A )k1[fX$BXgO3w7|jaI~Uq_:Z+6^ɼw:[%4:+is}8.Ow!@&K졃;2q .91%硗k?~{6! >ه#uhiȁ)-xPn<96+qoOOWTub!j4 xjR<`sY$ykҰC?wE7HRSȄ?RmZ9XCGے?|!yFa=F[ݣx>= wPo\$RDBsGy℺vϴ}}F=ߦߒ,@C!zje,[^M8/71B+rLeoX?~^X\2ǬI,IϘ`̜@0&%ލ$ղXn3EX5@hlFCWCRH4qt8ks}eD4t{;000D*i^63ILGJ0Ԇޒ̛y0?Zu\ǫ=*|NR4O b] )z$ ݆z풤0tMzZ4S$(]. ZPd{Wj ObL߉sNیթb/e}gV D67K$U UD/DL [dmu'Eul.%֨P8|ˆv2#hO=&|㕃)k[ ] v1j1AdeL$J@,sVotQ4!BG D: &@X TF8=L<骫&mg1Ǵ2Bp}zyx[Rfb!$q=W4ǿCS/< Ic!KqbAh:~-M⿇]1/%ɋtB=.R6:YW jD lz< 7 hMF//uhN"'M0c=/1GO==h4m4Vh^D?)Ot;AtPؗOyS5zyLKq4x/:GYMK&6yy^<^[dW2H}5k-^3ر,Tcdj0eMؠݳL9,i,N^`~;d922.%3['4Ms ݘjLdBcDbkߧ;ur;W:}[nXv(g3KfYt{ Q34[TkA?yrF`5ȊI;L=#-g̯1$cp"hco~ЎIR]c$.]FhT::>=:>OY0FBŌؼ Idc Ҭ0P=/ql l5 |^6HON4R c+p_y1 l3VL,Ld :V6 bV"I"IКQK ɖ=%hz^k^=dmy SR(%m&#cXQ"#Q`#͍rl!'kao5u˻GCoE^Xah42y'+#pGO Ǟ8xWʚJFeU ,PSiPJƆE4&nNS J"c= v5#Shq2G D C4"Kö(q9ǰ#)%ck e=0? E3yeE= R56N,I\J(Ҁ{ms?yCL'9 U*=|)QG|3z$:CҐR1l>Irg&-/8jyُ8M쁏'e[Zm'70vd` '=I5;O2lHD(8Գ*A4|NvzTI6]320x0IC="WK~b)d, PpSY4UZx0)~T;Ps.2A{wGy/$rBi T=<$l-~-#.q9EÑi~ WHW.5 rĀ#2l//(wMư#5-y /¬U^vvt;읶!U z7%0nWJS疼{ai7GQN r;,zka ҏ,o6?z:s~m4U %iĦExb݈ G 3fY/4B05/n@3.w{ QM10s[3|ݮm:;:?;?qS<\>^<צ0qh !dv>B(r֨HCs!vzdk)lxwH;htYhmA¶> q"dir`cd [leՖ&IEnE^+Sx{:W;;>p}ֿUC~砞94({2::PZ-9p~ '&"Nbe!i4n;4f 3Hc\C£';Y9 O&a@}A-mMmq'O 4[\DZq(G|켹x*㱂?¢J=dS8`"CˆH[5îV$s"4omNH/zxS%o5g T;{[jRMؾyi^/'Eca QAZsp@iUJN{r-o& % KGD;'g58Tw;)ggop*EԴwZ>{O,Q@Fv!0\]05)XB%/ϗeZ(ܲI"(ykK;rzH흜`NW|m&uK_]]oQs.- * Ti4üݲhTXMâ=һH䲌ߐ"ъ{wh R-̕9}Вⷊ?Ϭ +Dw4*801_Q9pvzfn'd4:*ȯ׼c(9?=:: M^a#DjiYiP4*VV dђg;{oPq<ʜ5W1ړQ&yZȗNRCM}ɞncKbc4p]s ǿ␁JȞrϦIw<! 0nSz _\U &w"r,YyfG0wC3, 7 aQ\UL # ZUކ R91)t^EZ6]sС 48i&vp$BѓU,3pIe@%}M7!<:?'^r hTkyiSF {eECj4xi2A 4z5t_1}η-mT0dYZ!W-Cát|K2g!1㡣5!ЙsI&"3>bϙ`cÁ@x#_UL Ǐ 7(Kɒo")K8' l-)r uO`#2;)Mh UUT$ .$d0^r& ~Kf;wv|txY%S1S:5.l"gʘf8"=ZOZt&`|z;d6yS@Fe㪡 A_>kؗ SK&GKFVEH~O"B^$9iZV\"{ApPl>[%SX_d.2P咸RE> !?<4dX؄_WcxW"oY=_/?w}-5 ɭiAn>?]4Oۆ3VS >GX WYv"۽ Jdr)^f/rƬ@mpgb=84z'.:0WϹ]"koQmtswٿA-tS\0y BӁ;],E+xYc[ 5fje:I+r3ӵ1t;LI$b ;zUDb U ӑ ~~n&F---N^ %Cy| @F7* nU.r1KݷPA"=W7s#o,gJd׷Hc8m+z*KK$"xÿCyN~;k~\=8~@<񇿳wKKV`'K}?{r xЎsmߐ5nw1i/IӇȡIyܘNO⢈,kSjwۀy@#pa^t{zݣ'.C}X_{rޑ󃣳!f^w%CUx?ndQ3KTM*.R; O4| 1#W垳D.$*>jw9@dhA q>Ko'/W|O%5_!D*)uKfcUF˯σTqa <ggX.JsX$g[*K߹jy1[P}\f4q@괔qn|CLXsrB1s%Y *ΆBXƓ|gM zݳblH.:'20{xОy^%E$Q9;):@}XK>ٰ$ c\Dr;_F:|Ԫ" Ҩ]P[х;®j2ƥIטQ#(.ԫ*bY m[>o%Dy( C$(8 ;dhš2؈U`ӻ :ĉ7Pˡ3PiiEgk26l;dl kO ^~H˗ (bOBꜻΥU߆7ڍr q3ů[Ry݉X̓ww/;mZخI_ !. N@ o8 dH~~Uwߊ配=p_P.bȖ'Fuhx&D?7#4E}f6Wp9 eb4LŬs~#Wh|2 1 0.I3͹bbd5}BZj݃nL9ܘt8'%%3V'_ :]$ /&onEn`d{wV1+';PY +Ba3,uq3oahƾ'R?E6N1/NcQ07֫0C ᱬW۾.Tb_`5inI%4ba]ʛV\צI7x<O+4wEtH K5b9]"wx|qkIYD+VmŃ&-RYq:]}- N龊c"ul84+1u)jZw]a =\I ӧ]}{16 m ifa1"Bg#cF~Mq#bfcRׅ(b0b QC }>/۫{zWPlt O]e>'Qi8Ҙ]I;p%jQiB*^11*|r%:.I|*I~ȽYټ{$pU!Btr|j(_hTkwN_0m퇁1X]h|+^*-9,U2nP`n5k:K`̵;ųO@3d> 0^c|7?Mg*Unu!ccpR@3CX?xP- o|+f|2_({iܨ,YQ8GL5=Xowpnҍ(ї~W&3p5jTHwu"|[碑c\F _T/K ()+%y%5(T+aBMzFZq*&WLG#FHVR3 lS->D;U#-_"e7-,#7&>EeݼO5j'[$Uk@TCߦꪷ:v۪:.ZsFV:Mw58pZX$GpB~߅F|B-mM.Zz@j"ɇWξsDݣ "\=5sCn$`r>zO*F\DdUM]̉r%+.qnKts0;H|6t JRK`G(/o`:Eb0 [.h9HAMYRɪ9ɭQv`r.Q]I=we2{j .9uW.HP$q.gt_XDX^U5=aX[ %[ӬZ 'A!0R崇G]u8y!}p3i^MIzhNW (@fYPVID(J5`϶ јGYi-Crg:rKU,'z|sfκF+WmП 1嶚9</ l2+B&Wm:*r3[Zs~jڛٜIc_P2$J5BJ~gOehXu>\/jsMeRgRzo.fcBm^5n:UoaAEV1F=^چىX}_Cq`4([:H5g2JkzSPꘈN-gѳX8v"K$C#a%5ԪC7tUsk{]'N.*>gjs3pXsYa[7om\l?]Jռ5^ Elxg|hd)5Ƀ=PnIŸ6U2u޳Bf"הW1 *]9Ad#IDE5]MăP%^ S\Sf8>:U}uݩdmxvVRҏ`)`~p 9ck{K.GVf1;YW|[K;K3~cML,4U wŅ]-".#Yr(}QYw&Y)"f;0t\4Mn2xLsd;GHr|0Vqmz6$'+`zavQ(Y#Ԇ~![|f%jymw߹O]7m*D]x%J Z -uSўk?x{vib$9kVx{v$(%"Lklx{viQ͚,{#ykx{vi+9l$lpjDx9Գi{\ukXx94u=],bpּCa ;83"69z'YV1y]Luu H6[d&km]RΔ $vgl.vt^͚.$B6Q$kVTuH1\Sٳ(4qS" =2}QOEF'_)]2źn9IA!cE !*Z ])ǯ%nWx ֬٬&/j[x;iBKO.kqx;|Q/!xkx;i| Jkx;~kUx[q(fU$?~kjx[qInI kx[qqq Fkx[qq.S8Dbbk*x[qN'9$kAx[qqN9V"kXx[q1 nnx[qo3$C<,Oj2xk>ʸ$XkGxk>fYk]xk>xfG&*eksxk>xfxk xk>ʸhDfx^Coxk>r/D_8k9xk>ػq78,kOxk>{f8hjbxvƍND vjxxqvƍEdkxq6_Ik$xqV{D"iJk;xq͒LQ 7mkQxfLw##j,xۿq&M2k@xۿF;""dkUxۿqz˘f  kkxۿq:,V+xۿ{-\0g?;nkxۿ͟}"9k4xۿ5 , :JxۿJͮ7aKAgxۿqJX]7aK=nxۿq Il7aK4ikTxqr 3!Gkix2KC#k~xR͒L"*kxb"O"-k)x"͓#-k?x||#/kUx|"kkxl~$2kx,͋}#lkxqL͎;|!j,x>qLƍ|jAx> ƍw}[kUx>4+#nXkjx>TͽL!U)kx>o*L}^kx>dUw=!:k*x>$O=#8Ok@x>yVfkVx>qM?լk }jlx>qq8;kx>|/n!C&kx>qgf9NK k-x>q ~gkCx>P+\ kYx>qu'9kox>q_ fIn;' kx>qM fmn'=jx;xqyGxk/x;̸ىo7jEx;js2g-jZx;˸j\N#[RhxTr'i'xTlOFKk}i:xT5l57UmMxTt2?cV*lidxTd3?fiwxTx;kKi xT2'KsixT1oABsh(x{?3oIs1h:x{)wOfiLx{6w Y3fh7xw3gH3MlIx9g⁀fM(h_x73c  hx13}cLch$x;m=kc h$x2u㆗Fh6x%u-FiHx4e ch%xے%qi7xے0q0BuiJxےy i]xےz)z#KIipxے:#z ]*ixےz2js6.ixےy+.i+xے8lDvemGi?xے:!lvmiSxے0teZvigxے(t"->i{xےz5hs h'x+nc>i3x[1fSgx@ n1x5srF⌒*+\iJxYOem^xi,G+ivxuqs6QS x5qd޼TԊҒ/XRsKR 7۱~YIl7x~A,:2&(nMxfs=|,nexf&F~,:2*n}x8fmgYtd0nxjs- |,.x8rs- |)CMxbs- ,6pKPx$k x{fbq 5x{fqdbdfeY%BQx{f1dbfeY%?4mx{fѤ91qM^!6nx{fUgs9k f'.!/}n!x{fqZgBVuN\*B-n:x{f_c[4f'.!,nSx{f1[cswN\*B/Jnlx{fQms;/f'.!)_mx{fqGurN\*B+Lix{fDe2i1x{fZqnDiEx{fѪ!wiYx{f1Yns00?h(xkUl lh&x,Xfe>Ci8x,IlCf#nNix0{ƇT)xחʥ:YOQz33S)?hx>i1xޝ9diDx^9Y]xRKo6W {kODdI%x}T$zÅ- iz3{~S}˷w'eֻf;(lLSn~4^7;szቜOFC{Cmfg^ <_Cj4iiNMG2WN3F 8t/1u`r&Gt8l?0p% m<́.F7f u3tca~78m%P?˩M]1;G㉀{QX<oh≀#3x5@股+7F{$>n^㪯3?!l<(f:<'^ EY-y%/i#T4NZӺJ.kXt')%X#\)j$M[ tj-IEՕ^T7JlFn>jX/[J]\ ]G%LjQtvm$kMjͪ3ES%آg(,䅎ޣށ`jy!bsar_f*W"$de Rto"k8BwӪiA\IU_9 4KFHZs)VÊ0$ZoSS¤FB?]FOW,Yo J+^i'x;xqD0x x-10{b; ސ*\hՌ 37 tWbl# $:6v+s̎-S;l*)!azp!p3eϣ&SAq\̹koLqxM?=ײWO)SsGkxYsd*kJ(v+SFLI388w t޷{h-p{{o+MeUi ח2PyךLFJLŋhtʔ*U2rK%ތ.ŭNTnU* gLĬL܉vK5I|2æ8O$ [Du"69V,Sb^-:l܇|]cBljΣh\qm6=rEQn| L)t>72H#Q(*jt2:d`i,13bp y]]QWvEѥIe-kܩ2miUTXN%$ β':,t*{"J2ZX8׋ut$nIf 5kȌlƯʻfޅzݕ2)vi evԧg\ p O'zaNu8t_|5frs{ t7y܍G!ʅ"W*s)+gVQ׀p!1P<.^sgΘ 񴛪/6fxJ_Z,L--,e$^,)]7X;ӎ4{C:2ntn=rub<|' '^,9F"^bB!|f$YC"ТI ;^^b %YդZY|r; \[d?\VjZFR:*[hIֳ3\b%|5cBBO?!Y{iZ˒oBO85##ToĄ##b+Ju87?۠v\EbP1#O~h% ? jQK bp', `~Ĭh+5ig/kNkh))U>:AC$H^_M^v o1 LH Y+n^qm|uwU .P4w< 1W2\ z$꽤KYO VQ,oPnËWzvFAvS"*ҁ? o.q1嫃]xgHG3ZPxxP!* |T֥ɩډLplȄhJRf;5@G'0! !*dD?OFwK%h:g*XAq "tVrzeI}a50#W5VSoS d@G)#((U`O[*hW&TPCT:lzlySP<~j;s%r;EhDQGB[y{TO YQR πț"Q Z6aˀtTxD-}Ah6!P#@цڂܿ-(;'70a=|kMn8%Οxk.[xl¢`ON%.3VJ8VJa&& 8N 3hŭ F\>U63  g9il-Ζ9\,PLQD4%UAZϫPCo^_$E=M! ȋۛ?AM]s]H'J-Q73, 6纏ԣ\tB%9 {)$:+X$rTV 6%> B rzp4t9EŴ}n9*oiKF/ uUِ;nyƥpQ'ˌO^ⴟ84!үfŠ وKϏ֔sMq2&`'[#[eRltm@mK Lw_L'1=5lXN_EdNLY)kRXF y\p_ IvW&"ƈ)۱xgC,nsyD$7nؽ01REvwBM!WIDœ6C}<{?O.2,?űvu4M) | _d4 97)ۍjTI/K  Kn>0TCLFw3mvM \ (0՘7#r;k:o 2]NIA~@M!5 [|3ZTZ_(3_TO +OS G:pqϝs|v|okMs,빟D|HTY>gU[D)vl,}~+!L f֧ZʉUTn<u58Vd$&i~ }_,ꊧ|Ѿ}e".T 2G0F!IG&X69˗_f2^VMX܄UDRg6D-5GtWN2qoiA`ۦ,L!g5qfҢvh:m!ozw4#f)c~F:> r):+VFhOxc3l k'׊dR.8;HV1"Zx5g)FhAcq8'+E:CZ ? >+}L_qߓ0Z$ dg04VO+dHw5T¬lekUxniVvjkxnbLҢԼ C=$Mļ҂̼tĥJ\% !E%) % 7bVTx{nxCT& &s!U&'% "m@T{*KX.2mϙ! l:x`p# %(B+Px`|Qy * %>lx`|^y9B~Aj^qqnJjYjf&|UJ3P 'x`|QyFn.Ғɷut ,RSy9)e9hқX7gUqn^(.V{xmUMEN4 yLlL ]#55vWU; œ hɃbbQ^=Ń ^zf]^w٢ FX?fo1S޽)Bc 0[A+6.RBWoG %8l Q0h)JECB4&Y\#MPHѕ$PSѧ?AXR#E}QJXZ`3p9թH 'TAZ,P5J <I2U сIbYE+yj&k4 y8Q8ٜ- V߼~sܼͥsǠf6k-ͺYR G1@( f@9۲0aRDfb H(tD`wp$ ]vx6Uj]°*Jdî"Yや7Q 4AQxX:<ƕF+K Ik!{:%l*Qq9*,cEW(m͛͊:)FsnV ; pCT̪B"IyZβ@ˑ94:PIhݱu;s >KTY%)B&v! /`j0qoO`K~IV7̏+2&MaLbe+#\6?MdM0Y(- WsYSXXظ^D_c"]n"cƛ>fO4צCN2{.;xj'ӫyq43on4:m|>s2sue̞4{*Ei T!ހA1p.[Vqc"ʔSdYN*+gw \mq-/fc*:,VϕCی6BVr:D 'OkAB U~vAq+&.A&H2Zl"qdqmg7ϝi }[4%夝Ѥngsz`~;揹wEN]܎KMs4)H9Q u1}'4M.#}Xdb4iʁUDW '4NS8xb @!Զ +#Rڝ*hl>qDbB8(( B^w^-)@f $D )QQ"h(" 4;̛fvfz]3ڝmAmFz74{RРnp6<]CeKMMv&NgsT١7YE3tMOذnS%Cz`>£.P>|ZiRgӕ~yx>-wlO\^]^|Kęȋw/!h IJԢDWukNDq-ǻQc- )@~ZM]dN9ki48]|HFw,Xäɩ%cICf4I%Sƅ!3ɩOrGπ:9@m)>vې *`ߏ? > FID VsB@y&qXT'1?j7ISmᡜMjd14eb,0Y]|WI ~mlRW`M4NdS@B;aIՠj.]HU6M 6!J,ҡKM 0LVSu] Q ( LGf+l_eO:l$X&1/E(51E!(]!$#u1^x[^kdfFFX&e3goǶ1qjN S1q3_y0Vg$&edT*qd*L(`5fU!.F Sx]JAɏ $ ^YD`D$6;w132? 쭄-Bll vF |fs ] @pDݟH:B TʕC>'O4 |~ 8 ZliBX3:a'.Q(3=%t@<,g8zgvwZJ^Ŀv/BCYflaմoZ$51 Qrd0:]-cqs- 0rh_G ;i)at"2\4e@SgKOvZ>7b(1%v3G踓r Æl%=bB~Φ+osx{|QiCBIFjBZ~NN~9W\RT\W̥y)E A~~~ !@%!: I@z\ %X^s1n6_yqQx{ܦAwv F|, &C~xx{^~Glbl'$3Lb ̥9) Y% Eٓ%YU R3 JJBM}=/w$ys g' txUmo6_qþlCDډ`uMڭh uabP"_]U0L|Sك7Cք ^yF<5j-rw:?-V9h͞ BXW"@iEױX2x7zgD E^IZG[ζkk$k*X3iz>g)\Ew7o7Ʈ<7\sd$gcQOuQxU `Q)ű3;l,`wD-XInQ`]6ʶ(Vs<1Ӧ̠ɦcmcmW| G/ѣD H kvV߄O~?B?R\١bRw"eQڟ4\kZDjNSS,)睃,i%|%}֦ڵɺ33|ts挺]]Ṕi|BD)Z+#+)>,I]$ף9CZ^^\7, m:Xo<OpLl]]f] .~碤gqQi cx;oCg~IFjQ:X7bch xSPIM,NU(NMU())//-JNM/JOK-/)JLN-ҷO//-L542304RK, L BE !.z\Qx]K Eѹ2!4֎`wjL c@`s*{3S F;]^:]2V)iIJ\L))g[x*<1V ٲx;ks8_qRN8έݞʭ!8l;3b16 ,${$01vnWWyqJ0y,m!0&邒4 _IZ@7[D>?/*rJ/I;7aXHS4` |n0&QRrȋ ]UzP?KþrAdS׋p$?O爵C|s0fx  pIjswZodXt[L{SY@4̷݂ 3;p6{z:yZc͘ǏqDJb&)sɢƱ酝 LIBS!7$I`_سSHšϾa(J$?\#⟑\8)θ:,n\Њ&DhODn&]"?'6jt,YXS:8~B7(_k;9,ҁ5J,HQǛyIl6k8vRX3G׎_93wuz> };XP?[ưu@|~r.|ICK)%Mlcrc26f0@, #Fc^4wzϜU8n޵BN_j䫗.dp=R;˞CsɅ8~q8i QDM:ǠRb9,h=f "X#.9JpkR`"OO ipzDzCJD@q'D8VYUA)Uԛ'ǭ5{BnB6)l9y"̌LLFI䑾LgOɫgbpUG)~mfγ= qC@T5Oh,e̓YP9ϔK,wɔR1e Mej=(udu}Nk:"D9; @cវj߶fX* Iv$hYLO_a@C"0H5ARk0`mё@VKZo)2>]foAjDskO&Qj"{MO8^Vؙ452/r;f!0&dfC zSn!hvU1BX3I^bN5/E-v{<ƨ_XJ;@3tK@]L-3Lw;;fm݇yrO?1BM2%PBFu'` 5 -m}$$_ADY+2\=ZJ<(x)Dd'6t`'4vpA' .$ zXjCR@{h86%ӧO JY؁, sނt6l_*S!h/I"By8wj{U+:LטB!v$?9Mm^ f S$m[vװ| f[&%6H6x j`'E~`g}:;X@F! 2XM (ܾp!6rBH.TgMxu=VX{ۢgU)'֝,.MWϨd_QD'1L^ǺS"g ﻒB*[@|Ufnc6G}z [.%#bXh :6"@ڑ=^6]nicu9&Yb\UFwЏЌxѻp# G9!B| ԉi*YJx aOWR vkth/JCRׁ=}i$N.Mm/W!ϩ i$:QAWS&[3fnfɍ>T)ٴ5 P앴گ_v_ÇʍS*La N(9Z(n֠wT֘α$Kovj2;HpXԃY(!b\ť R'5N_VZ5@j\R|)סwt"Y*Szuo+ ;ΓR_ʼ*{_.A7RS>85aA V1V Ԏb*V},:`q4QJ JE:zzXp( ۭC hݰ*k_B?px|AWmx~u,tG8H:vŮ쇭pzVv}}zoGo?{O59zS*Bp v,kVOWLN|8C?ޖx}7Va]ΰgww%sS{{Zfwd#l3 ȢGV`7&9~ɀYIgHjmn?v0bގ)vi.ڷn^pt'  `b Zx wxFcS+J1BbrQmR>4X1: -ÄУhfi?  [D2e o[! 6?G|~e?62%v )@{Mw(W 4u%#M<㕏2Y b<*./HǯRvJ5 x :/Bg<*ydDU}M\l0vaoI\F]ׯ/\*= 0h7.6Z+SI] 8?W|:4ŷT9xTT@KY!9?/-3(U/3o F׵VT cxTT@KY!9?/-3(U/3o DEO d8xj0SaU6P-L#6 IIR1Kvk@HrO| ӛd6k0,`Ҁ6 =#؎3).j04ivy֨%bXhp9gdEHɘ =$MO ]p$N*YSb,nj$JԛkL` ^3Šw띖".+J?pf&A\ǔNhy5Kb ^͠%EFa41J"y([ õOc]VAq zu^Z=T)ʣ;#<&b%76-/NRx`?6!dbɑL E'[0se$V&fg[Mg <1x%&.v̜E's2kVx;ʶub'IK,r/I.NqI.N"b~zQ~iAJjBIq1sxen1 KNJÉF]zS.nq$(v [G8ܱO1bN?ۇ`| 6u=oBj&n;R2a,|`̾&p ! fְ#2i+7$OgߥŪCս]s>X^5Wd}A 0]U\e{)i, \&x`P\Y\XXZ"RԔD}YRW\at *PxkfʺACF4u:o!b4a.N"<҂b<Vksx[ȶU+3$1'JMHMϞi>ٕItb$7D{Lgo0x[vU89?/-1QV$8E$1c'ƙ jhx:!hc0?xzu3ɯ'2YLd2pO#x;zu\&҂ 'eZVDx;zuyF2M8H1峦L^$SQX`k^ )]L/G{)j3_>~__`|3r 6~csv*Χ(ھtb"̝FW1{a ys%W8ȱVyvTQs|Q%os\#d>ܲ$TdSߡ?$IVh(ʘ\)ǖEBx>{IB )Dv=Y:t22l)K2l|{3%}-iNJFg,y4k)G\5ZZ^4N x[5ػlU#Bp ؂DuY~K)܊w;!sr&^ %W(YĒh1:_9D}Ugvဠnk"r ,y' /v!-(jFa vTOL,KXg)KĻ%j> T=c O~ɺ3`xuR;oA"AKA1YQ(|D"* 4bٛ;r{GbKF ko-Y_Et=frݏ?17 NyBTi(@*;;ozz`h-tQH畭PLb h6DyDLaN-p[F$dY$ϐ:L"i CL Id<Hѹ%H Ju LY6BLԋ:nR 0r¦ѧEπV#yRLf !DM-w4C9;~}0X'A)L2igtRnFXI2OjQoX+AВ]a`6Xدӎ%;M`9zm Dg,/Cr{VjF>s*$쒱YΉ, B4qԣQGsW[;^93տ/U4gFԐ!7n87Z.ؕE1 xu90 DќSI8 ˂VXȝv h 5S5gB ! V~}s?_X+h/sАna#]_9F?FؽxWo6+n}}tday{q}5R"\.cW8h4XEw[)W,]E"Rnع;}+A]1ԅ2g+Oڕ;֩ ډ;v)Cœ{ ЙI^XK9P\IY7/U87SJȘI:3aENJD<7ΥI]ܛy)8ЗQ#/۪UOTBC]"&ϓ xϋl4- IC'z֦=g*5,rm ̂$ ,ï퇣*2ȷ4 en_UܟӡDw3 JmDDyZFfCrX"u[f鏼^39*iHjQ cP 3X[C!*h69Vx9K1D3-444D+ (i&[-[2"e"N]4á&*^dHhg `‡QQkZSFGp`iݭ.Sʠ6yh:ծYe u"DDl>.f% ”y0ExicʚOHjdzDX~nVxCFRQշ;Ӣ jaX3~?ywqy\_6k=E$S</>elӏHl=de:x'RbavbDpNc#@Y@t`'QIJl;ɸ۲[v/T42t+6n(-2L"&i4. 5B|DԴBfvSg-vGPGQxN6N8X;d GK Zp5xYFq9#*Oqz_H`uwi}I"G >J!p)pQDgE얍eE(;u!W\fs|YC=P|cH DȰsyvX Y8a`yfxN7X::cR9뽺t{fEQ}nlh>Г,/+չk7nfh?^ghggD[=j<0>2\)zx`ܼh0eIӍ;]uڨAo#\Z ,/E+äD?ZZߛ|?rێφjȶ .EW cz 'iȣe+0҃_aڱHɟ{ MC7PV`LG޼C sH =7DS9 BZuW(%yBv`N1&Çu(kx೙'8x>/9g3c_G>!x;/FtBfS݅UR3jRsRS&~5pr//- ,.IUp+,M+L*J,L- /-JNlĨ49Qr++D7dbRM*IRMKL/-JZZ_\• VMLIQ(I.N/NIlbZYRYTRP\_b@Jj.y  hq.gNIMK,))075-+]\W#'3 l.IIKKzr3\gqKi';2Nyj#2u3x[#:Id-FҒTC71Y'e*eVy9I)EV-H'jrNjb>lLإ63N>oV`?Ȝ5y#[';reL*Q;xTNANvkBmld#ҔFxEi;:34@oo#/fww}gη+ʡ~Œ8f8K~鎒ҐCśxV>U2,h]}+%'Hc S5܁[vKBn<!=^X>'$N!NJU%35`&sb8+095k "8꘠@q m4"JE2 M!p@8Z5~T0.OQ}qaUXr)#c3׼LZn(ͿѺ0< z'cy&@2j#U>F*pMD 9ڜ@&+6M} z|6ϵ J[[[sAAƎSK'6ԧXb+rBa?B-`P.q vJJ`@9&l䊕ҳRiaŏR,9塌ّ;}}BTy4kid>QGt σy$2ڽ!OgqLYvP 0}~׀fojvcނ~JxMd_K^z=; iA!ֱ8*+ʫT*xk-̮E%) %y yI9)\YTt2KRtu R2+lK̤"[xv KS"S\4(_RkPř Q-PS?)3O?9##n$IW(3a'+I!q^\`y$ UtE$I7!k"F>qrP VZ A+u^利p\9(2KzYy#2| x=uDos?F!0KPݦǖʔGq~0~g|7_5r}.VlY3CR!纈%e ֚}rQ}N} Abh4j@B%xcddB`1fL# 0221y τNKmn4xre%##f+FF$ıxYmo7 ^l@/vq\h ~(KI<[+YVJԹ3GgyfHzꍘo6J$֬t2hkJgJWrOGlgsWR1yQmP7NY^G:Q^J[s>zEߪ,Ig:jZ#ϕ QxL*~+'`n,Iy[DEkUעO2kq)ݻ1>q#HiYƆa ;žo/..nf|6NXTNؕ2rg:,۳`š-~Eӎ97f/۬ Jک$X S<BlW(B&%rbyMdcL/ǡ,8Je.)]ԋ` | yJȅz;1< #h[iL+D {W"# g:G=iIUH*yW0L=at1^j#~/r%}?DIxfB=>`1&H.H;RTwׄo7.@|ݏ؄P\~ED0C#L<ԹԖ?ihVXLİ@KO꨸ v.7xڤĔ`Pzqf,*΂uޏM$'&\]Yi ҳKk^l'Qݔ ;=|ߟ r{qk)jOgc>v\%ʅ#?W{tBbe6"c;~b# ʼnVװ6RBMJo s#qR!Eb]S痍2`'0jGmBɃ4ۤ&ܚG0M}а،W)zTq8{{~XD:"KCD0M/oGϩ~G#{X4'"ƺE9ӯRhb}d}/6- \/,F[>IƸ`TNJdV|SϘ.O@ܔK ;F! 6kq8zT@1YL&ht[?yj@_rKv[&n_疶4x,7Z/[ԚIԱDXN8~E։F2U&po++g?62e IN_m'~DgQ\ ;^M_(_Xl C'|l`ńB.uF7k1&1ݍ"fܴo%'kvT#]vɌRTeZKuZ2$Hit">S;|#(}T?uH>]Oz=4X fx4YDxQ4U ʰQ>S>^X$Xy-)& U}6"NBgnChDT=4;{4D*` Cn$Q_7f DըN?i-GZi qslTSUWd{>GM;XR­]- G6f/k=?t6mG[b,eR<_=?lI{=vͤv1ؙINB%zUtKDL2Mu34[*%r9oIYӂ?}vIt<-~|Tb*J1-2gkEqq֏ m9㇖ۘKcTnLj(6n=&~t$\boٰ&dV[Ū4 #)PdI&v#ީr414AyLb-twj' ]-: *MQ0TTUhStilԀRj(94ji?p;$b t<ƿMfbϺ+QEQg(ƒ mC |)lb+uii|]}]*=[*gxh>h$ SpgxftV}Ya Mg#xfYyfA x۬Ki|fd\̢ĢԲg'˱JHCdsSKRsSJ dyLXy4OxۥtNqdY&, 7糷0sN l6gbR|GxۥtAlª6ObdR|sr$x v^l&szjf].eF2?x "A9=d.Wd6n/@m]x OtC0p(fC#cS3Y0+l˦δ&G#szjd]l^Gx'ZtZ{Yl^Frjcx'WtBƊ6.#x+z@tZ.a.eb[.e..Ag:x+wz64xVmS8l=JJ0\ L_`37b˱.J2IJoe$\{j/>2i,9f\tߝ\!w 9n}>W[ F j Q JEa`/Naڟ.8%E11ˆr-[1au|mFoD6yGkr͘)tU2L965.RBiH0[(\ 'ɒuXmŠ{ˋI1rqeR;k*sV Z-t\F3kN[!'_`kGA?߂_a+؂?c6t=AK'GU8]- @[[ۯ^A&jvPu@kP;:38Abi`ZK} 0Օ[7}>OUl3C#2sqYKnJ4T8X̨>&^ʔl q1cq O#w(zXx!8ڇpw)]^TNvWLLHUOw$5ro]G*Kp黕3E&y(p"]݃!ūHqMfc=?6,#okMx{/^|'sfǜ2Wlx{/~Z|?Jg9'*FxP\]6H]CCp и; Kpw;3L2;_ݹuު[>^k%ϳߋ3p Ro, Y ʚښ9q@ƔQX-L  Lߛۙ }`jh2d Î `cACrmV;S+.?X.N¸rr)N$]j: ?ҴuNBuFP?$'Θb^^*ag>AVA=8).44I$6V]h4mh7]vBV)HV gya~?^2?O>187^P64\¡`S1L rۓ/0V\S~3Dz/[XI7KD͚6]OqDNDٮ`+.hc"A2BLjo؃F8SCqm}PpwЄ`zC܂#1̢=WJfA,?2g2{F^,f\D35s ݿ "ǟIFοfjue©x1[цEՆUNeقO~dH_'=?&c0Кv08p) I me =V*Sdxu9EMi1Tb;v;nhyn(z~O9BHo~`U ڎ ׏׿35UxѺ$^ɭ0*ъQ05;v0 [BVu÷F{T ,fI;>wԁ[G'm7ks Rz4~i-mo,;3ffLq%=smwqZɾ >zbAL>)&P[~7L`"4CCOBH1D8CۼBn==%UVyon2KA|IQ>뉋9h8́ǰ0/$ůx XAg@c\C]G R.2UiUХZa}Uc)NȯƎ"!;fp%ܹ&ܡGPLo%)-`U?K乬f('KS GDdUcuKvuӂC658ygw!}dzBb""D\?. T ?,}3=}T_#ˤdiZc%!f;s2 8NzUY|/cM6s(.lk*ax7#OưG:mt+R}$7(-;D3m?g";b."b=Yq@,FsB1Ttq }5vD0.g71˲T*077 q-U^,R^ } -9{ fP{~`-Ԍ"GruTOM"˓Z<sۄB =04n6DwVk "O{ߤdzIa,ͅk}hSj4hgmRClXP}a %!{SG eKM`xv Gx/}W8zU|.!}WytN{QXؽ#hU:Uܕ78qH}\~$QR(.AIG؛ffE!@wF2QkӤ6_}/R>"8q:~.R?E=5.lm8kӋb߉CI-Kpx~f:w/暂/@P}OuH{N_BSu;;$?NJrx6SIF&ySGmx%$Z*lg^d$/0!>|B-2g"@Qqullwt;~7oe0*^.63Onn>Rwօm_"<o)LglH3+78fhv7@(Q[LӐ a ¹ر[#ɏKƋ7\ѾSߜAkቪVkXFqs.HnPRMH_O %TxFMͻ MyGl89?D%QzT wH\? n> z;5e]j_ld#2_@=ˋQF ΔA5]KdFr#sVC fȚL ! #qc~K䩕̦4| `O~8NP%)y_*RcCP<յH:XNBVtǼZ"x9qk gΗ ʁ5(ddMƁʺY&X/_ BO$VAjyɈ{?<Ӳ}h`e !S ?jv&`](tS83^sJqٕ/^1:쎦L|Ķn3z#²JBtG[ŹQd#^\W9DP5O-7_s{:ɕ樺>?yݥЮYw6ŲċyumHCns"nzZjacvhRqhL8q:S 69wF^{dpBnxd"7$ mXBFpFhHwQJ*[Iԇk1|fFZF:|~UaPƄ')4iCޕMɄd]t<ﻯr$?bqz ?ѿP@#|^viVjA0=GZe$32Efvhi;=þ:se. kY-1mG6/wxrӟm錇\oAשȂUχ>Y}Չ'Й/F$t~s0ԇRhU=N5. ^׹7lond[ ^Z_x<΅ҟ:]Ǿmk15~*ET|evF/OM|?Q'P9!<@^KY$깸ɨntl'ns]a"bre.͘bT\<Kx+MlT]?ĕp߱!&rbkn'6TEg :$%,_(HWb|p d;:/?]}V;w|uEgŚ^mWE9<A@[KD EaHeAB՝9V"#Xw~q ǶN\ K{2|JTaAcrXNLEM==㷚4RLyrL00: 2L: !VJ(M9@RjvC5IMxJɌީi̔ ~t[=@WU\p~T4z!Kr=) t6IN>Qە`_84J<+p4pw4=Rͧ uHBbd2hMa%}ny#!a7u9xٮۚ*64W2Dz\sh܄؜~xk '!E3I0vCYt/;]#vLD: 68ikkNeJqg&|F(:5PJ_Ķ EO1V;}=DkiYu$Uf0!j%R;gX+v -7' KڂԓN.䤮 蕞 ZΨNR I%bEUr}}Dr/ǝHٝ_Rq+CaS c!&*t4Ô,t8p[ZNK ܓP>̦tddswH'/mveskqv?ha m/wԥh$". $hfi-Ҫg1%(#,і[1֦S5yE}B qxWH7~2cOksDdP,j$+' mC{52\.lE _D ;tè0H%nЃm6;}y=O_Ww7q)7B+pfz5nkm~mֹY55= m[V㡪9wEW3 )PmQmuE>&W(Gwa.^wԿg7`2ȶ 9}Tw`u͖nŵ0}~Hy~Eʝ-i HA&o9rVwN>lZQxyQhErU:aߩO\C'.y50_ʱ۪/зi1iK ?׹![q]/O/!'˽ޠW'<JS cbVܖXB$B /?7;ZQrX0h"g9#7dYqHc-rNܰQ0%=F rr1|A!<Z[;㎏^.f-0ӇB@V2<ˍuE@TH@Sp$>VԷ:pҥ cIg<GD\SϗQLCC0d{W)È =jUI=``Ϋj?K ލ83"<'A?]3va{(ٗ;WbV eYzk_TT r k4R#?@#j\3FSy?*(%@8I^fq]~v{Jxքʃ6^wZS+vZ%#yY& Yӣ(F`P d*3Ćsʖ#vp8i# Qmh=;go}QY0iE4}Fy?rX|Jd?j5UZ+1t|Ӡ~sgo3ImZ'\hE=k;Wma;u)ne"axv{So! wb@*d[dF'֭~ƃ_M4pKpWؤl>R 4Ż(u*WPy?\=Ke)nT T+^h!(nFI ir>R+\Pٔ"\4H2:Z6qk]~,(E(ꟐUMs:nZJPӽ]!pR`5ti-쐕)OW˩a|o99_oRE'oLK?f-ruT8nJS+E i\ ҵac9E1&'xc^+ĈmviE='儝-eM7 3)eͱt|>K A,g獣81+O߶ʣ74fn rH|H'=Ճ̓J P;D(D\L{Z*S֖Ƣd8Ɍ9Mq{roiy{hP+~궻m+Wf+=\-2)x>`grd]Os?[%4>uRT#٣Tا IBM~nkPj~ENnzȋb@[e.ىěvý\IܫՀy+쐀INo%7+=eZjaHф1{ \-18DY]\>|#cuFx^#yoo);rowP^?LًX-e5,$Ojh=#&(z]S\eft0rdOVrl ( R}(U@nn vǠ9ĄTII^zvF(OuIm֧BV#~ؼn)-wۭTC&M/f",@1F:A zxn[( \/1P?@0/o~'S2VM#KSc`g#J}L~+ijafDwNv6lMm>.jgm2{S cSewB?= /77@@APDDBD@ABDBEEA"Ģ%"%cggcgf~#,!".+VP[񃴒@ba`(p3s+-EƀwH!r "4Zt4 4,̋^X"pXJ*;p'Ψ8^"'g}/&.!)%mlb? 0(8$4,.KBbRrJjNn^~AaQںƦή޾ɩٹ [;{W7wK0 zA/` gQ7ǢE~]S a:Mk쟊K2 d`0B(3uM`os-Sݴ ܴ~N'S,0  X5mcH/;הn̅vYcZ`@#7Y4+~Qx"qOzgLZ Z_~IaLc,Hώ8p  8E|tc+dev>]WgoQWqKMh7x۟zjZΣA^ht02q!#5b0hفxÃD?",b9b< T(L# g ʇvy z =ڀFa"hLs&wr#R(q"@ ~[@UuGCPCGTZ\\kЧ2/DڰY~ ,Na_QN[4͕UnS"x]o; k%EG'?fX;GnB h;Qvl 5ř0Flw j`ߊ)*e]%?ÙKnl2>Gi#x- }2d RNqFF|O#2#g"5 ȐDd%'A"E)<^9yJYnݎ~m*ӣ cWte°l?I4s=bc;бq#js4.oL5N "c;+c9r}rx#a<}ѷ} pNy 08^{Ì 5qKT$[1j's$}~I6C[޾xT<5 KtbtNaD"i&{=b}f U :%/Js+]̡z)ExW /Ɇ [BC.qr-5#x@vB_; 4?m2J1Q`A w6cё5 +.26i_zR(>=C(Gi`@_[gU`?1Q].:ed%L:ht f~|}[w J djί1i+z߼~0K MNX3]'s4:ϵvgiA3pX8(݅PR@N׌bϹx Y,|Q^Xy1 ~i.#_:0NUa1ATFyn Oqg1%3۬ٗ\JkOOk&gC*pȸ[0J!~|{>{liȉZ,ŶH>m['%r35s#TSIIH`4a_4'Ҟ (9g2 !s%#$>Ĕ.T)-2a'B-9Af"N- 0vrBf5 ltue]g:fW+㜭}ݜdTgH1hvZV?0z{fb@kMug݅D;P|4cxsjSB۳;D,fRգR=T{p>h<H mO >C  5]r,3;nZ, K!@tO=}I>Tt!&-u.jYc1+..:}@c߻}fmeʑg+Ƙs n&+-q,4ReI4@of k Hܽ8ޠH3_It#J~ >RMl4#Mz5=,]oM;r}d;7!G8eȑWlڶ'{V0`MZ:eId<&qP-W `i%c|9X7[F,Gq$;s 3aۙԉԲ1׼^YzʭOጋ> ([ ՚"\ާ8 ;^H[W0@Jgw1>_ hV :q'$e2yj VCI.Jw3! J+.;'I>H6OMI?9aUY @\ $`H |@Lt(,̖}as*`@aƬs綇ggڠo=E?-I_\%ڷ'#GY]`@&8^eM(w!M^u)溴O9:br{Z [4MJde96$;AϨv <BbSԇS跰.%7yDS>VI8"W 450i*%q3)OnnN$=C-[H#\zXV 9im J~c0ʁD*0tq8=U6*FXLocɬFB9XJ{N E4Z)39q &vEz&Nrn}\ȁFZE4a[PPdIBn͵ jr%,F--'"UX  eJ=]p(+GsJ /#f{l?/yDmIPʅ#CYGLWo>1!)ǟcy! {ۺoTJ/ezU׎^2]a\<ԨE;B)@<ˆqRow_ko>@v{7)bZc{u~qitBP(ޔҿq_ ,ǸhA?Ly^ )g4F‚ Sp? |uZk%~qhܱ1C#?6𥿭&:9ݡV)#gHZ-M8&fYjus.H>K4|$ɝb:y.9Řg`TWWbZ.7 Oxwq9'`vr5N\$utG zܑwu8V5@&925KVBXՔp1dY79||H| Ҏ1ns43MD~[hE\̐}2g΋9D^}̪W'Ȯ;C=&VNXHȄV)Jb[4αFhJ~l2zu6;9b4#?؛Wb |AǥI>\~3'wNMu2ڴͪUBHpK#AӢEqmz#Lz>o FήGXH|ĴgC]V,HI|8y ə? ge3eHh7n,3!yA>怳>vxv$Vf?0$ :Ջ. F m4O1H̆Ԝ Q$eьjb0` ׶H?f1KU0%PSXn%)Daͷ,E U~;EAKJ+E" gA􇛷}2#vB٨iE\{u\WntlcxQg\DIe2` wVq43L;߾XŒŸ.؀_oz R j9at0w߹iΞ.7xb %^ "G՝ml-x{;ۜG@gE)h+K am&^}#cDLxs(ΨL4SL G\.,'cLF)[}-_@ma~gfb_ ڇ:XxAvto8S| T)l(Yj%xϾ(!ik|ײJY7^Pa9e2RX8vwEHroZ)/E$!O?S{z{3Z޿vUͨK_~ _"X*3>̃c62`Г7M|=QzBdDjAaG;H"2+<<"?. Y(ҌN:peXW`T=nn*-n &׾cX_zE3F̏O>R9 cqB[DH@ɟ^6kFf ^vA|n;3uzq7O0{ZxJh5C ;*ioIg+pRn)y8 & !B\@ `0V{,!hMDN*HsD6[:Ϫ[hP:=Y?:v''<4q3+{>9ǟ}%x,r~MkA\ qx 1lEk_VҿxzN`ٻ% oտ7>ƥylzLq~?3\bWK. m |WYB}?}DQ;zٳ&U 958-DGx Jۺb[?apP-ʨ9f".\Ҥ1.2 nmq4:7Ef"O%Dٲ$pzJZL'a"9-lkќ{1k2&_UPyu.[ߝvxD$2,kw:mE&2\]*JcjVytKojj~$ ruyQ9d~6Xͮ-@EQog+F3gU'/{qwZb>Z;JH[{(5jWȩSKz=D\ɡɽ"EE+qS";FTb !(X.ZesNL(sL,(00.ߛ= u{Uu6Nͻ G #i_n-ll٩:5Uvڿmcuj!\׉u B`< 1NyZ< OpW\t "'>vxx fj4hnՉHŒ ܴݠ21-hl U^8FF!9*f^~\p#}OObm^,8m+fvYu.D{>\v'h>H3 {7@f'.oT\{퍆 ~և0`2d-U)Slme|Gn$U:5t@Z-wjakTPI ">WcD } b@Qw} `66EYa9ʯ7\" @?pi20D`vcd?#pz'n`r oN`?>C3m[9C̯n:Qkl!ЉZI̥qMdF53nHAԐZIac+s`WFrYC /%j`EsnK^IS&C0?IʃVB2nVUW뇶oxLz跌`!~^o~1%4؉;]A.…#OzKlYV^L !HTB3Qw!3ȷLlr5% m| :j1*<97g7R.Hul>XAT û ˼@  Q, gVy!|-1mRnļXq%և")s@-6i6c!/R[,L/~pzI%X*[#>mSS ToӥmF<`KօGGڣG:[[E{à H4JwwR"t C HtwHwtwu7_~mR)N#7JGƨcevQIg.0nWo K;+Ud\o\xsT&=!bOP{IG ?K<4caLa@r2FvH{jxpϛCo aL "9mOw ivP-GiZ4ZN2~h/&$2 j9zkc &MsMMpuv'ӆVjLq|K=gve|??jп[ +L](O2a} x62ѓF2ȤbK -xcq;ƒ8`M`WQg`fP԰]7c#6z|ֿerHr'TAf'u85L<M{%'9heJBSˈѸ# A#D#LYW2d~b&k0) d|/DON+]Ӥɧ*~cHO0Bѥ m)_A= M^vB6f+upOq 2F s76s \|5D@=xk^Db,gPr:t b(1w (*jjvkUk G~CP4d\bã@0+i e5k-U&em*elʒǫ۷>LˋL'{T ]b9!{'/٬<U[P5%t~HMj$:B1jެ N |(QƖ\ Zl.EdP|R'h(mf!Pޖ:pS\S #toʬc֔Auq־|oP/^)`!L=hE>U!k]!d-y6aӫX[-m, &I`sG2%߮J8JG&~pw F3q,8|gL'" XRo: y`.l߸Bߺ",7uݻ>X~Ő Ŗ'6A*/ 0P {#C ֐{9msu6 ƃ=r %4KJ I˻)8Zb<-S`r0TZR/sHS)s:HЉ"a-N=s]ђl0 L ^a,t~-6jG&|mVXã3yM ==jO(M[Ag! 5԰yC?~16K.T&xi7XqH52;["Mvn֝'<˕FLTuG{+ ')|_ZK E'dxq\}vs]^pBRBfԑ}UǬ8CY877l8wZ960xerXΑ ۑ||ruay 0W =L;Yx;U5kAl&ֹ]B[z{Qq@ ;s.nrFVOEj1\P;> Obu!bpND>ai6! wGKO[.;k UEYN ׽ڍ@H )xpwhY%k2_XX˲aXq1᳭*jA1=M S5E>}8hn=Å?=y'7B9l<a2iPw:5 fq8V. {omj̉XxdHLҰP40g g{3spt/ KYHr;{$$~su? n -x*=h?у{I#Uܐ [ %#]ȕo(hB+.a(oOq{|>t67q=YPΕ$Iӗ P4#4Nws{L;)'XNB]S\\Y'Ϻ\<+Q%b܈{y셄(I311T@ E]e;>b5y՜ZY<A ău䟙FЂ(v[K:WKhm%A~go@'YEQs HF%zzk(a)Α&v7r^qi'(6+:#PHm}4N\fT fGꋣ_2/X^Pb2`d1_}*tXXͬ%Jf\+a=vܼ4Ib.7tƃPlBZB邏9\V` H{H4L߀ŨF2RM7(V ʜmw^oN~htVd#Ցe]MZ | zot.k{f;cIdG*p;LJoc!S?maK1qos4:=7lS տXKk[4q廈hKH9mC diyf,_J( pZ>8q^9@ 3 [z|`"&ڑVGq*V5"x 霽Kpҟe4VeɀM.ċgf44h0KM.EvgE{Xs=`o@!E@pft)kNiHg`# ]pas-P\..7ӃY}jEdșDYv͠>d Ikַ&6kN[FMJ(gƽ@ )~RP45|ѫ+F׎uKk̊IxW Y,)/${DnV3#'d;m @ EiTtsIN{sTs%LupNmKQK01pOhև"/U=.eQІn||L{CSS8#{k=<ǵKi?Kw|+s5[C$UC)U uwB^QI9nXhK ]Xj0 fϰ(ᔊ+6!s\g'y \H ěvGrD컡,= q-od"xYS3Stݒo{7!b')/QM5d~si*% P y:PYjE٘"do (i]uyN` Kɗ!=;/7FW}Sde ]zIyҋe\䐧IU?L9j&,R'{蛺4C?[ؿla=( /=H--&N]@FБ7sn8"^uT r/w&K8҅)oЯl~Მ ̮'`&vlmQU?ExMp ʬ-;!&wY/K۝v~bj"*o.0l!ϣs :yG:hB3$%!° C|5!P1 x9-f(sdžlOČZ0 ӪLJ^.=yM_@`zA@g7׏n9aǥCzu|ޞ0  xxH}( -MwBϸgA5_Kwf(k`XnlT,ȑăw5yϦbQ=@mm^HSv p 1XCEպ> Wup֜707ܨ\"XqQ׬[hi*Sx{WŦUugHsy'] >s_sMI=-۵7BY4I,x/s kFʼ;t$ZgmYz9 TW;ƭcƩPd?X;~;E,<֬7f?{ٳ¿`h'J"|̀ޞwMh6V%s٤6;/K+]yҋӯpzs3^<Ϩ|4\F1o?-<,G[Pi&[ـ9k$Mnd^e]̴\+A1ˢZϐ}1!~,Q DaOŮ}P'B^,PǨF4,>o-{_W˿[ cǪE%":"]yUs/#S)k}_s~1pGVyn^l#OOt,6F= ) deYks=xSMlt,Wjam=YY!-ӽHQRV[ሠf[2OȾ-4L3s,tYSXbbJQ(|siJ jlkչMa@hLZinu\XKC?Z$7TA2 Nk?;ҵQ ^L {3/\e=;UX21SWO{@u7zSbL!1U`!1H{vbi4a&)鬒m!=ʛxXr9hxVK` 'Q03]] O'Vt{b1lZS1q  %v7!#'HiH@,`A9}!F0YsZkadͅLH |Iӳ `Aޟ8}n\X 1-,:q"f݈_N Fmy3[raب#f*-xB%o,@qZՠ?P,Ȕs/ǟT+6:OG5SᎺĶ9Nܳ wrt$]ʨQݰf nFAEB?oldAͫʼF dmw ?s1sycdI+UWb" kYi߯epiFW½Ta<K\ٯWzq:>SDNQdVg|]Z kigPqE 0޽ j@ܜgCV3A!=iӔ0Ã3Ý NKj!f:LG8pzhPGaq2 8sDӮGqmoʪ;Tcd-%4R]47qBv4[[%oNd}z8_J9lt3,,F@ތ̬ fmjӴ3[i>vf wkwS3E9VkC9XTATW!%kzVzJS-xn^ mڌ*ByfyVc.TO\LR.$հ,Fڌ*i'Ml$py)t @<{S"ߖTYXȿ ?_*;L՞-zk((B0t®:j<1LK$,|`on=4'AZS2JvVn;r4}!adJei3w?xRfLw6ѧyI1~%D{*:2`|2bjÜ9޽ht|Cy]Jr֔y[Yxsum5`jsAB(ʲ3{z"T aRJ5<`,֞>˂+>8e9qE <wmL"UZn&=p᪀$KC/t "$kdd+l1R+ކOE|h[<QK| W!;$Bi[U5:45EsYH3dz`vF:B .D ]6*}>JɞlS e[!SYK #Uf#Wy *Q8Ũ oI;.}H KMs(vCr uz PHbٜz!fٚC.bwzyv0ef+c=WBQ+pQKY㻈|מ/tW.2QԲUfF"Z5[u ,=@G$a t5yS" ӎ$ήPf7r纄IEmijJ,V~_拄xC|8[mEE8Yn\ >.wRUls)&2-רYcc32L<#wX"agTGeWSp*JC *3qX|}ccTbxV{( b5Ǧ-y\OS y]ذ*)`dcnD}28KxJ;6WLRo#/e0*Xaԟ "ɋۓdndH_.5w $ԤvۢHG@ڊS ҉X:5F\zcWVUrUՎ` S.ySՁ(z˼ M/;lM p5D諗 g>$%˚36t\:ms aίNCϼs O[]GroL%2!Onƛ)L㹶b?,M~&bAϘgCe?`cxgưp7wp PT75ka1t)rh$\!"K}޶ aX\Te(չ1?Vs<Odꚨ||؂@9;Q<-YD/֨/Nˣ,X(.;q>&~>>͘45}-_$Fhg[Qm2{={>Cc84˛;HisUSDq )/͸j]qRP/j濒sxo[ٛBh- 'GuZX__5Ti#|:[Ԯ_|G)/їt[r3N4$VǛ{X7v. DW6ؾN 6¶+y:s0Vc3 g7n>Ϻ Bˑ*a_y9SDuy Vbw_rn9+:&_-_o>g;mґu_7 @^C!bȬȱbQ7LhA=LA%r{0G{ ޞ' ^qכO{cX⒵.?<5Ѻxx%(onJQSJ&#*P#({zŬO2{-(l~i*O}΃ȆW[:9fPPoL,J6=lPK.̼d-P$8"*6YMOa,[W ̱x)_zSæP9Ix!1abLj#8[ bD=5r'8py_Etw#~mØEjYd&˞qRVpe{´41zegHft]L'B3@ :E7O⌈sJwm(LMɽ)w~9`Ҟ /F~(XpqPq[hzJ**G,[(&~efuC]m"IfvzG2,=1O]Je<\͑L\ ZDo?_i%dq}՟PzH%B۩ :54uNo]K%8\X8X_, Tg7_!.s&kcA/+8tϐs䜿ƃ* Q>d1yt;w5/YLr9,W9_jpڹ?{|>K\U^ͷQ RH@aWb.dž8|ޏt1͈Te2=^ ʻ$ZCP28]#Mjq<j$2SNǼrj~e#] eM%@+оU^Q890^Lf)iL/aK B{] WdO!93Y~[-@pc+Sqs Km'~ce0,"tM3Ǯ`8nU}] zѹFj.`HM -@$TOp%n;FZV·lͩH"ZGtJwvPC9jר}0*' +8vBmvUUw/ N' 9u=6%2ImU0 bДR5uF&Cަ(v&~F6{?{:}[/ # pSx3 Ϯ-7q|un-gM3va b?#"y:aOjQALBb DԘ\btRMk 5x`~ϕU+Bmk{.*m@rwLW}uSAύy`fsHAq0'jscekN롁h˥T$_3W^^(ME:-5,wx !o$󔝪0s_϶+獹uvdz8Cё{Hig[$}\Xky߸OpF%2 C۩wx;;3sT^η,X8ԫa|hSk)0ltؖG`nhm|dTeq!8-Ypd+\ZT:c$Tj. W>P;p+:m`rIœe%/浳JR p#6],VSHvrL+yM윖p%ۺW*L`>O\Cb`ⴣ*jSh7A'9Ś`+s7IV`+zQզs'E B);~RYA*RD jJe E`DPZRX GDBoL guE$w8bU[zL =kJN>nLstSAiʃG\b wEo/=SD2x4s 54;ߟOMvT@!PKdB)ޞHOW)aO^B?&Q"y*OkPu@'lNfT6ɽC`vNMe.rISƉ)EgD>}n7)u&Jk^f i՝Dբ|[1u5;!N9|4A] _G J_1fWgWÞZKaS&e&⇔zX̓'!ck+g)c~ߦJB?L5E~RL6;9sM`d܌֙t~~1l Fh#{븼%O[pwwww N @pww';K;3ޙ̝oџ眧鮶:ui0J0GHTGBB{mH}^Hd$!#8֒#;Rd1dtNGdĒڢi"j,@#R#2iiulQܔo865N7F#RnK?cb7Me7]Z^fkaCZςM^ssoR=iquW^q}c>:[ؑf6M:3UE"E:ØbJrJ`#m7` pgyeXꂙjw蘠3ڻ;d,i:hұ@2>/ l%Ϗ>-i⁃;h&]Ӆ&gEhx #ONp=iky~ٯO,,=I-)M`jQI0& 5)5 6w0WP ^ v0&biI4 HQCMa>{bDd(R/(o2'+ MT1ޯ}I1oRg܂3 -z󙓙CŊa":``pS EաH:{'jWΛ*/&~=Ϗ\܄~{A5HAZx Hk>4дmԒ}yp(jĬ_[®1.s.4jJ\˳ <&Áb^i#V  a%gZuP'IObuW4uYej\ ukWkKboMxHz<< ^1c$0:&d rzqڂ ܔ9˩nޔ rhn]_p4I@IUDCA~[q6[^w~:٬7'6YoJr#"69}|(tZbճ>``pSt*MLʿ>m\l['%u-?N,x`榉Ol^;刁E92IF2T[9oxdMqڅv ΥZ>brqOTPco ֱQ$˨ n_uWF->X {,ֺHo L)Kܩ&UgƎFNZ0kbp^:ϱJiBm?Ιbc}ϰdbOp? I>Ӳ,K:D؟OʽSx$QA`kmmM$ $ n B|m} &3{&&4Ԓɐ[Xp_Zۚ]X^%V8KK!z$6x(K~S{ᖤ m{8tlAU76ovOKK#sjkㇺYϩ'KA-k%u8=B{{ [@Ά&+M#wd|c/hTRtXk:,=m}gY%hvTtXS:,#69C e".+Ǿ>(\鍊I͒y^.K wmȯ:wj  (XDҜ_^{hlJl+KF|6m69殆?Qw@0S JDqvDH)>:+B빲'-khj2i_O'="RTQ=U][? &ɳh${ic1awjR+h8a khг+Rǎxew!WE?É{?@ >0t Sk@pݦ{9R–9kY f!P^F.$ *B- Lv?Fm]߻6-9,Uhw4]sݟ:$N(|) zriȐZ>FrK'!$Frl>!`aWh8$$:ekE6'I?,$)Omƍ-bH[?\qf4s34룴{η+zX{ -fH)gXm3yA@c?3/;9*~kONՠ?y'w>56[=[mni(˦^w6j.bjuEk;-U\r ̆MV_\a]]ǟ\z;Mn+s2Umd@S0 TR'rӕ gЛ&P׶ G!`O#@$xㅔ a:5TkeO^T6nqU@Ɗnh4YjFǤd!oDS+JIclƈ,؜6{(~2 kN싱xr~S<8SvhԌj=f4,1 4Jh>UJwxу[~ՐYUAKXj  ,$lϰv,RsHw0C1n=RBYO mG<4!}%9H~<c]/F7Y! `ŏi&Mn zSL^~BS hп|_HCәw֝*RU~C(n͡0<%}S?)t0BBtdxz+K꯷>}O~~ğ/Vv5eͨ,D3b  " [8Dwx4?n$6O i**p"ӋM o=_aZ`#7n-SaY^UFȥ GyJ dwsTq{D2p-rfޅwqczypI(({v֌/E,z҉|W|UokjsxxoDHG/Tu'+ Th΂aKэ_|m1IS[@'#9wyg͵ԪۦxY|Su߶Y p4LtGk7SrnMSy|AL2u^kW޿6nV޶8'@ߟk[ti}n=#xFV7'ĸ4_)EoI?3D^a l~Z  knn|Vv& Lo*BӉZ~ydg(lom` e9%k-|iaÙwP8#q(%@ک ?2Ms}:ILs3SrpqaGc`cm󹶷e za{qWe*C:y|5U7-/x2FGt7d=Ss o̗2eW?.~iȾ較G<|"K/>N 8Q.84APQ1`rfSTAyR*HHt(H0CxR9LcR%E2WiX8~)#ŧR$@C]u?yQ85헠V'"@AD8 ҳv"ktcRΖ\YߋhxB`E D[נ_Z_v9XtyR-ipD&Tz1TaX0YlߠXLïV :㩥-&d%yB+Wx~nR8\7yN`}OzAAfIuTHvYsbyWEXI62ip1~JneŽsXf:$)a=h,L(m$1㻝-uugpBؽb ď]'DXϳTpfJ{W,nʤ 6ҬT}2q4 D ~(5MY{[Wqm>m(]{ߛ;|v,Ajej}@n'&c;=mG/Ivt@@{% O4<,0Ӣ=M!BLS9iVuC'ê 9SOX8jͺJ+Ζx7" Yta"hJ)MY7Ѩ0Q <,E̗s|~$kܘBKDFO{ݺcD̘}}l5n&o' ЪBx-V7{Y!o(x: S|7USl$Jk9zD7i ^% ȩ'+}]^sLNQ^.q:3ҏL̶c~Ý4\JBW{RH 4uNg_}018䶉' ڲ4Rny.ud^->c,Nip[qbDd{nv,(s` w.{<'\F4VQ͕rP;\3"FӚ}zX|հG|V=b{vm8 40k3pVlqr":ڇDRZMd8s |)S|q"Lƞl4>{x sLwUh[Պos|`==Z8O16er2i-Lvl fTm~cjqw@&ě20@8^< ~hux3 ȳE::6l\#pw/k enۗGhNnwG^FC=f3EWJR}b:vg01vw5h.^٭E.=c>թqG$AѶ `i !\b+rr/r s3Y2{7Hq0v H(7٬ް3֏] ~5xPlɬƻ GOnb{|QtB^?!djB 4aT{^ V6Æ`V|ѦE}ĉ s\~e 8KpAss=,(u~Sd^`M֦!B  ;H/3r"VCŸhQW՘ss;_FD7j&b®%ԣ`!b; = mfm$QۥOuZ~Ը:$ub;PdA9~P0*LfyqNeqkKP[ ͨyIM$xf#u=6 tuO3> 8O|Cf鏁w׀9r̷?^R.SΣ>JhՈ&[uǥ|x{:tPXaBOKL JX0AwrzAՅhY/ X-\XbB yGُoX9bxC7=4 `2=t>TdU*kjT#@ҕzDF/2`;HUQxz Ryo6˧,r`; H—G%'jKT˄@=:^uډJ(7$+d,Npv7Z- 0 nm],Ui`fK?' >Kv9{LvY I1n!V D=iB0f|`R `?Cn9r"ysbj3zA( J;li9򋬬}PG]wnS$8KsՀ+#A2ڼ%;*(53rw՝MCL p),14 %,^b "l!`uo9!j;RqQ_O:ʛ:cP5L/v%qZ㮐. ZaM~)}X%at=cJ^4M$`r!=uHhw~4L3{[?.F *GґoEo\Q.RrA|QE|uP+BLMlc[!ǨG<+&ɻر~ls=:g08B,F#Lr~'wF1SQ8TȭhCO!eOxI|\$"dWԀPQAP'^e %QބAPp #;xA"}{K=k!2/Kj8wbPigjA*ފ0#"Ǿ\>D|SV:hhevI9Ȧ(Ce8y*1h;}7rJebZ GC)o!42) LǕ|g*+7[D#FTY?YdլdJb^! Xmr9UpmNsPB\Rp[v!Ai=&&_({ʇ g6@08D9~7YeUFًhKѠ#FMRwd8+JaW1D^rJ%4r1ԧ{ucqjFRcSzNL"gS,%(K1|M]= 6#C87&_71<(3 jKsXBaH}M8LezjfEkB{u#QqUlO$1 {}~]L;'8yyy}uzZ}]_]}-|ͱ7L((!rj=BdܯӀ87mPL'&x =4*+oFh4pԇb4 4FcDKkYw6r U:L{oN)=24.әR0Zt%򥝯v.A,T>!oF´v3&CxtFH>j80`<6J(]f4%hU~B\2ǝ4jcS>e^+3)^wVD27m2#V` b,37̶BXdsZeWşw\NHAO䎶M¾JO{R-=Q~h) ߆Tah(-f ɧYt 5yV!4k X(Ȍqqi^(%ٵQpl|`.x9>5 mrrf_LZ>OXղdziJ /0Wϯ#7?:FfpUC_5Q`$2la'lUle6l7o*6Hь昈*De)`F~XaƁF}< eXAN%y93)K`%w+RWX\pf]S^- O&ÀCjц-n|I c7_`!]rvxKN5iDK.vm; 2ȒwH4gu!{E'4W"mp(r\6A5["O QlÎXZ9$HOT=9'y1/#thn=pUUj,[| ]i&uб*1!ų f+#N[U; S{)ꋳ?["",Log{SՅmeY@!J]2<(mor4AQքTeEybVҬ4zr u'2i$栛,Zem }+:Tת,* tꤜa&hٸ [_#r<^+%G8XUQ??8l34,zH̏Ij9 8ť;PR+;wkh/іfT_5 ~oI`?ì==X6IZ8!v'O,rp~̵Rf%:}7#fFaC~mmשwņq5>A]F'"s3r 0%"?1G|%]I4KXɻi-:鳣=T+_-X>bQ(P aAI['Wd [F`? z@=Kug C%eiPd >n|qzx D.dbM1t:1,ɕ1V09!۵ڑ0򄠈|+NLI5|"Rh#NbѸ5S%x|q;W_MɁZvr=[_}jO]VѦ*pAp?y9t.HH稖ؙ̔Á▊fGK@[J*.x6_Xu_7~FuR66.PưCHml@ %!~QBs4WxdpaSo#POd]QIu[eMF^w- +\1[ k^M͞ #faV֭˃51Γ0w6>(,UgݩmEjzլuƃJ;:2͋QI&PO0}o/*,]y} V><7WPc09])Pu/DK7@%hCvDfD2qp.%-4'6ދ$TEMD>Gr+bhLOmHQ%11 wL2co$3D(ShL!%2ld^4 YA~6\@.GsN ɖB F~>ق{ Ѻxe(#]n'DNǹO}7p bA4{Ė#EF$ٔ|67eF|Ѣόy>K+lV~X~')) U$ssWCQ; ;cU){`N, KDP4Xݎh~(b존USjnQLDpɊ=b9" #m P2Eu)o+bNАeijHȰ#5!RsYS6=pJ؅NmhIxOT⋍к|:jy4Re!~"+4<ݠ+);4ב5cQQ9 ea+%MaOC~â]'\kH[` =ߴePYw)-7 3p5tH샲NcoA\l iИM )L)N.׵'9d{cmG†ZZsİ |ey# j ݪϢD($감DXDQ?9TQ }\USCv+}WwjM_*q_0 a`V1픙C D5M-Ύة(Rf0$n/=%K OI8b5&4=od㬦eΊvW - S5(:ru>Y0 M$m)#h479@p8uˇȉxBQ·M4mG_\Dɰ7#2)K']ַvvP\BظZ ՚#!Js@,T%=Q}ECfuzFĐ빓);,&0묱lG|S:$~ݦp@U%s5X22@:@(bJ?8l=81(x%&2h%h((KÇ>jě~ lyLV=k]5p[C ;I;_zdZЊa{À1+ d #@pq V0cgpDxٰݭ3B!G32I,TG#D#:?j^0fkGfU+`ĸen3/ 4SCCzadӜєHU_ ww)ztH-BL%RUrk u\0 7r6ma:4.^ig$4Hze*Ө[Ov0"` cf 䄍wrj*\ #;uLD1Ƕz9g"T(om,a_vւu=DbQ^KboΚ IްOK!E(€v)Us^xG uQ#LeE~^ &&aARL-ʈHY %&>m ,! GFAN֝So [GJH@Yc۶m۶m۶mޱm۶m۞MupNu,fg:\gw X8X%lEH \%5x!qà}хG1E] -QpQlx)>uPE (ۣbk\5%'L%a~)O[|K6@HT :62-ߦ>X_)\Cf7#'P.kSeg/a89E.ACcYz `3r+t$Bglf' @1C*z.| P;^-)TPPy?Y&FFH!ARTۦ~&TDOgـ.~*Z k,@wF93j3/Jm _Rx 裑*xz%rnjx'TPx AIg4r׶Ӂ>$]J$Ruv4I=5V:}Li1,D oK@][Y'2RgԻF5*Z ~S,Fn aW`qAOaӥBfZ$T~^J\"['zvmn͈!WZnʦp<9LRBpoUׅ)kKO.rԂ2˱ʛ3DO/U*i2}a{T'W9{̀9bFLc]k,2W켪yG_'/ē~:!ҭ#gHzO}pߤ:8;n ׬us8S:?4a7ߌWԇ0aJq.6FK?"s d[zɼD5Gx WN{Sd'5Ԟ<*(3@RҪ4n7F Jkv.c`Z4F` {I:ϪSLzAA~VSXZӠwg3̳|Ck|!ߣ|yd7#"6zՅZΐc!юm u&v]Nr669ksֹ f#,~!_o~P{%=Eߺb(=eusjru5k>Il+Gď$vK^pKf4bM*i;q̶IH֣h9ssSm][x:˔)9kF{kb>4(ʃ{АQPu,`cKOc3X۪h@A4 M AӥDsѾׄEbtlo+e 閒6rNG.@B } nEMA toVx,h]Ūlv.Z| ,L?p Rj"D!:0OVmFQt~ ⶃ$v[VC ` ZITa&fc}31m+0KJ|,' N;4C1# X? X^$- u҅AՆh p=6Z3R(J4Wv7Oc"dud! $E$X`ň|"FmXqqzTyk*h  r8#<ӅQe8e_-MD1 NqWa~znS ] `l +. ÖC%) Uҳ)? %{OHPА͂s{{x!]%Ns\d}Q?Ԇ3`&J"wi h4ec![c¹I׺gXeÌ@]FD+Q^%SyTP* ?j22ra曠@v\Plc|:qqgZ'iiq c5q8tCamC&E8[P δX|`xR{8S($LOig2 B~,[D+~uɥ_$!-TvB#f@ P喊"4QUXBƨf\Ue24Wn#1dkTW L Wi^]_C\VW" 9hG?$QjkB `:h-7%@5`]j}rs`e gX |;oP3!+,lD&dBJD\,9x@kyr9nH$:U1zՐZ|j_\Q17 WWՁe1!'+X"8\Ng5!FA#Rk$x̵8LrA( )d.x˂VDʨؾ<8ؤEõy V:ga*y},%g1N}IB䷪5̮&0\}X@ ,K:+2WGfz!d!_\^`-[ E+\'vש%(K %-*) 밅Hz6p֘rPyX =..#4I}iS=ވGo H[_>n$/7q$AirwX |a2 %Lm*;\Q$fbD ,gc@R;nz~GⱃM s [jveUV&hv`WJ|Fn_c)h.S;PV N)tG. Ǥw8Zp>j9eˎtLe|"w9ډ.`O1Q4X7? cq U+^_#R)˃Α5@Ñ?BYڮQ3,[xƒmAdޮ̵%opŒ.ѿcEzX)䕅7V<` <&s8헞K{~!*㨘e_XmL/:"=HmP/j&Kc }ڑ$s'\4ýV5,ѯ`Vz'|Rx.うQWZWoDfl!当(^ptPZ`}L'\Ǐ(=UmN0jzE(?qڕhٗ3F8ievP$C)$0(ԍ )w ,y.)X*x~C"dr{̩=883Q׮w-&2*w"M$_/XP3X[$WsK^*vrp>|+Yے{ks4z;+ o&+q(10%PK.2N!GP+,-)@Pøpq]&W;@,r),}/p^*bF 泒O[LYwum(OO $ЅaEћLp x`:UiK0>D~qY&Z(W~;<,3آ bRo'MѵjQ,2=8.M˅jJ<!RG8<ΏP8d˛ Iq d~~a$daam&Tkխ/ }`yx0O'ᴬFcQ{A7,w=֬V!Ku o8}Ƙ&1AWFnXu6Dc LZʀ߰4a KHŠC&ȳ&m+EhXZa 1.ӮyYw%K +k`LGSv9r; 6=B" H`&Tg} vT;~<\/|Q%N28_sh;Z`Q|>8*$%'QY=\YEIףLK|)>RG!`+b:t+ \-ڠXIM43t~h9 NHlLiTѵ>y)*oxvA"LoxZ.i&(gez{À5N@7 ?GMi˸8c@W兊5祁G: mdPaZR?ìx1t2~$eXb6^JEc*8BoV,Gd1{X;=^kܳ\8o=r 4pf`V?m8',4+%}}]ϒh<*P<\ pS f^$,Lfci5vw,Md LĠQm) .jΙl.UNrkdpPŝ%rd^( yH5)0]BeM綠̽_Htk: glcoxKM﹅~͖Sɣck;a.ыJ7i*Eڍ3W -״vOM&UR&_)&lXv$Z#X[EH ~;@Ydˊ 8HW*U[gtMSRF['^߭GzX>Vk_ I Z-F X֨uz@\ηF`Ll(sZJIU5.NAf Y,?'RV<'3]M+z; ՋBf.ģ!ZӝM|-A=BG҄TT?v&od]P{ow1>8d)QUz'w £O,Go'WͭyJZdDCj3#pM >+L;p'F v"6psCZ2C|.ZƟ$S6$AӟHH4dʍʅJ\_j3-/*6rA1NMc[,_J_Ѻռ şQE]V4W _zw`!_K@oM[aڗ"k?ΈKVb~gswDHz?{Pպ+͘\FbT2BC+zxԽ""HװI7 鉹ߙ-oNo|٬pzcW1]sLN9 e+ѼS pb/Zp7 :%x$' X?RԻ}ZAUN0}LL[nodQh<Єݲq#-ˣ\/vmnul)̵4@ur8/r87܂Eo r 4ʢikҌ񤲂 Q'ƹv}`td HbU!D`fXaK3KS[3-x(,rȠ/PGoqCr =-ʛ9jWTb5@/" 0`;Ε]M$zRނaT{l\(d)}%LH*/qwO@ $'MczfdClIՏ9fz-Lj ~y#/y } ^v<[ɽ;+?.޽gdX fnSպ=ش/5Jҕ 9v QqBl18ceu:^YYȏ4a@TuTZ~e)cT )F^ p[bo#OaX[oxbu{LLaJ*ǬJhjN4xcIƔظR\5teb .[ M/!hLNm$^WbVYߒ\us>Q[SΫ%W`FI/k*ޡ4Vv8:x(}>޺inFt+3UAF:fdpƷ Әf[K%޴?%u6V**=bƻ{kj2ۓ u:yL=]#t)h^fvnfUݹAp(!7G wct-A("6Yf۸[ϙs)$+v b_}L"if.a/!K֗Db@t$DSO>[VmznFݕ,UI1W6<ܻ%UPB'=" O%,,w$ ` u@.N`٨k_CR+`"!/'f¸u1:c{OҬ@'SNxRЂzB74]5ZgEZD?ceLc  &9G wC5p]j6I NuqH;ZvʶiX08l (?^HG.dⱟWBDcQuNk5A`J_.iay橇i( E_VJ-[9R!A]v1Nw'DŽp3Sܑs}EHAbɭAD&&NE xx `|BC{@^2ATRv"Ja("q< c 1dCh_yl}peA=IeьqGK|fP}> vUйE^(zE,Y7d!n٠gWB?[ i2 I v,L:m`D`,l# - b93c2#ؖu6pؿ$N}{C6Z3budTYtm鲼X?#+"X [㚌.w|ǶL6QX+$;dHFSI/! Ȇ(X.oQk#Lg }}$<ڰlgVL0 xwG ùJso VpH mnӆƵBv QL\ EbƇ;g@s UE4m+aj JU; ؓxT#Y'EPT,ͫVI'6$ȵƯU%g6@_0->zI tC9$@[,V.jI/~Iy|[C 3Z 27L!ZI|`ǿ`;*b-0GF?HZ@H*)qtdV,P5nLGg^&օE]o$X9'9a)K!v&u!x)Pb:a ̚yƋ@'oJтccl1UnTԐb3@΋ioNt%~ @b!~xсEH5̖l6ao%/l^qI;W&8=/S0{̼YIglr tÆc:?Sh$A|*ƍVEڑRQC_? z0ɴ]|w| 㻁!&4 ^t%.앒̋ylӑXrVAMSʀ eػ'P$O۷0hL了{-R[ |j£jGK`[JP j5S'דɓz'u_'mRw*G*.'7[:B @mgƾ;x*H|weŗ\b ;bjL~V"!v[]༼nqɊd9k%p/C \BӜO'К *jtrɠډ7DM<%em_*KU`f܀^+>MƎ;G'YqRAb$Nӵʹ7?񕰞ԋR|WPуJ4OŌy׆T ڱut$,M)R6DmM="~Ezo1"}g[e#+xaP3jQbf8`. B1#升Z<޷a-nt;#7=\DJbH/ߋ:UP3p>u:'b+aQ1''4"svtFf=vSմn[ b/$;|SiL p&RXԘ"E, ~ok-˝52F-iRl>H"ȶCV)V|=[H[2t*:+ub1o$߃Q:̲6Ӎ06ht& }]mXk]Wī Θڗ΢VO2<` Fr#c‹&ؔOTĢ/;cjA6Pza鈷Q zs@ SwJ'Gho9 nl._W%?0@ W11'0D3Ya8 :UVPaKQNWp`~1RiD$BDEF&B&@: .ސ4ɿc֒*T2xO wxi0XNg4d)$7p 84.@4 ϯ8eXg>sx@Jp/"M 6@daDJHc"NǐLsXQ/!>4_hVzAlgyV;_nA6+aPHc yco WL|(K/HБ '"^w1& ⋁(aFܯ 8&]siCJ $I2kxx6[Z<Ⱙlw2ˉ 3!-ע`I2wBT 91uXsWiW=|3~˜sSo3[Uk$ 5Uy&Ͱ ү{oQs$ 5$j+( jLtRVŞX.3Wؤ3fzcl\iij}<26|Nw7iŠ[PҹK֙93NjļFxVJjvOtW\jǀ“$>؏`}l(!cPjg"ĠqHo9|̏oʿ69/5loqU)2j ֕ ˁ) 'O0[S*g B(XV#4P,vTuv)MV#|zV?͛^Q,t%; e~RYYg`M-*=]aʎp$tʻbe {^"= N0"҃ aX1Jd꾈誽9hijBC cqӾMCZ,ճ>E6qo^ fFx'G>]]ҹ3y|XV'&>ypYpsGUZO(CW*B #v$L:}cy bF< 4[,u(H5yyQDŰ$-$)K[ y=Hv^AYנ1Z.K'_P"bCVvF [2g 5LrBSM!{V~20g61`KʊRJYQ(> f`DB7ґ8<T6kbZa@<Zj88\cO26O$Sfel"ojӦq</k-Ĩw4 Nz*q`h}Ѷ8ͨ|wZfダڔ%fr +Lְ|@>M]J[sPRQ1Cq1rjl@}j㦠&FsE,T t* E~brQ`qJ_V$S4ʊ[iRF\::ic-Ŗvg߼䁎Ȟ{~JPY71jSRk2lH fIr鍼frA<X !lF0W=tmѵ5Dt6fgEkqM2r ?ZBN=(qsFobKR IɮxgWPs`lm04B2o1ǷQAˢRP#; bVaXlp& 0BvoYL)#zQ'->Ct7Y7 v*\K. ?XUͥ ("6g VV@jWxrF`l=+CBr{z gMG~ );ƤyȘ\zCbo1Sd>S1a &a-;+MX؆3lLK~GcSqW%RGb{c1^]Q=5xH2JC3XN<tRxC'-s)KsDd_}7쟂tmkl۶m۶]m۶ml۶m}"n97~om޴p=GZWֶ,`g֧ѦVF(]|aɭ1QWc'oK;Rl0oL yDhU,P+2xuQ4eGhϤS$P7}v)Xyv+x3c2K(30 ?:Ce}N WS nQpLTlN8"ǒHoތ-}pW~5W`L^57J0eyCP;1'E+dE< b%e”mu)]4"(&S9Fe(Vf T&m*߮+jZG m:*0KPg]/]A$,ϛ oXN4=.r| -ң7"B=Pl]We=m}xXkC:U0Z k'vFz፸0,a^ӜQx⪮KBGJ clAwtϚ9#I!Tǎ:#s}Ub'9G-K;g)Z1Ér)Uk3՘Y __tzGuh'V]z ǝ!"l/S.ACu7Ɣ'S]6rIE]m/PH܅Q?{XɕL07}.rro!-xT>n~[|[gA}5Ӕ["f@f9:ug6ݬoX:[x(Q5"2اVf뜡Lndv\#7g% Q6?.]ҚaMK1> !B 8n:UЪ:Y|T ܅ ƩZ5t8u!p5x9%7aOӑv4ʻHu06 23l@|qjnJ rW%nTq{#5V' ԅMtb 6JI1}I藖އ9*-*,vBl)lDЋꃞ'N.EXu/(hI}MW.{8N*Ğr$/@Ji=EKL̤g0;lg @S6|2Onr(H]8\:5#Djwd#Pdk?ڷXk?zes95sؾp˜ V/]N~n4?N1 UXNwI$'?L5 J]lDl7 (8YҎGhDbgS#102(]TD=B~+x{Æs_\ n_}߈qD-iӧK Q=ޟޮI.߯qDrU'Ӈ[FJ] y-Ɔ[u){7̯X۝ڐTeC<#=~=+ݭǖؼ> Fwڏw & OWogܴv#.xsՂ}ijZBۧ[zF뻌0JUŦQGu0;#RXlzp*W:f +2OnKRs-d`r9Ӝ]'/7Tw3bhEIH5*G.rɀډݚ5wۗt˙gm ) ˜6C?i]PcWv|c|28_)WH 3?H<U=39~d96OrݴJU$ޔYSHMl;i3ђL-w'[VFoS"7Q!NA4u~W'_L`8dp$ᘖgVh09Jo'm7ƙCdnr/$JѬdʙ/&3cWc&pKR'~KYٻ4Ρ@Vq4{^.%q}VZ|C ߋ9Ud-C1=/bdbV![XLAHhpRt^][ahOF!N>_$iZX+}]gFCFgز<vȤha}l5,#|bXsǾ$[YRMWadh@\65sT3 I?DƃAwX!$4! z[bfY0̔;rJld-Uϕ qE6PkV=jɩFfMz"B8oU%6qT 2JX3kHEId‹+JW+juDjUB.O,m,L": EPK1'Nx aB&skwVק&j;ɹWʱJO|r3k9& L Uz_ZuF|4fF^A2{ s%+0p=ZM:"i1oLfsظo֋!`+| 6EڕnqiŖl X9ȕ "| ѼjYjJ S_\=p#a!~L{#|jb( QkFkB^e,*a^!Rh#E?|ʡmչ'G(M%PSUzCb0KsjF 2-RwPj"knWHZFk_u!z r`-_S*FrFklŊ(MQ J5e8 d#+׼A= z4`Wn+28r\jf+ Izۂ 1+M BG}f gj0[@a)Smw[Az¡\D]F=FZT w"&kGy6UF 9vœGc2z3% .JLwHe] ,MIq7B5R)^ ~!3=" `=8N0k~0jQC_8sg5LukHר9Ƚ0VPj`fV|Ŭ6 ᗰcjȿF//NԨoLpX`rT Y{K Ƥ1QѯD:ioT_i,78wft>*6݁Øu8q!JbYgZc.Gx2@p85&-ILA5fpYa/e()#[L՜~U[Kw73lb8!﹑dCÇ""~ej]ԜgU[+s`VԜ!Xn J>Bq6X/FX9R/VGx>񷐙Ȉ1TRIEa,9<(ñxZ+G4)ė*o]RhURYyw)NȾiHĖSi;yp]xoOPɂya,\(~ʢzOdR?X_hODe&M9{xJm eYєM{j 6;WyhU@"v#VKYoFT޹3n̑`{$S r!/8dHLLpYӬ5~9Q4/ o-;y 'SLT˶«5-xEC׈sc3qH[!@:Kx\ޓ*Df‚%sѯTڋC"]g߅rH5q4pj`o!Z&BG.J'Pʜ4sHe :Xot aSBji11,UEP.o!J1&lj\yDWOŪۦB!$sM`YB8\[(E0LJ޳^<t1>FiH$vTΎ"O߻.;NID) -M vًif3C!\`u|]IZ)ƽ8:tk +Dܭ;󰢻?X3A0.ҹm7'*L!!A&6@ q2dsS6)MW8KsG<&f2('C3$~cN^  ]<ډSu)TDĔ2rܔ 2|XA{E7;(k%V{c{j*$ p_g5]@)bF3 &NzSl\]d!m{Qx֛.n PNYp0i$k@ޫ4#mdEkåT*m `/Ϥ8D׎m Zl)֡33h'; !wfw_LBLuV>N-kh ^ڜBSbeXЩ=)o9Ȥ.^= mZHDzQN-jV\q;_z% č>vG2 !S UIxm4_|G M7O7Wi~1,l^gn8nD{`I>Ulo0Ɵth{@&x~ mHLKQ`u ]YDXʙZ8a/"ZMIU1(Ԛ('8=A~Av-Yt ̓rC=M$)H#;6 y[ٿjbQ$ $-"L^Y2 +}3h 8 C̅R50U\ݬ=1 LdN?vMhtSf _g~Lb\UMj,[EIKr&syVr]fDxCgN0β|fe%}OXw给_N(s}sq:~ 6?ݺ-bf%x%.J/!B<!Qm){YV1.71I9V)MK% C`!D9Hd{_φ仵zP9=JkvO{:X}}2Xd5˴s ү~ۘ 3 u<*dyB{:cg*c&Z1!\nvtFg v8zgq.>>?+{/6U *یloeM\) t!KHS=<ȍپ~WؗybCt l96VYE7_YLηhܷأ[uM+ q@ ^nN[3-xSLVYtrOvR:ZkJ㸧e_{b˯fp kyN9p9wϢ778q,C$l2lQ.a`w tCKG lבG~ &N6's?fNd_w$8?ϸV<6r#z|\?fy;~~_~:o+b /?@ka>/,k|/W'"7h$~r=lȕeByIiTGJ"&U&i/C !&^R _h Pl,f*W  isV,*JxoO_ITk؉3YdwiR-WUgRӷF냂Ɖ+&I>t7f5barvfN\\;4EIs7.XIٞSk_Y2 2;,Rb[LMj K<ΟNƕ'^{SfW;<ž[{qXtq%*xn= Gǖ2e]lQu2 yt[8?HIdΛKdè 7>a{ (~ jS6v}8Qe4c=p ;-S g7Uq5bm:A müZ n)1D%7PIvN(NR9GW*tܮARd`d`[9Pd K6%.Ù%ke `Ej[f]uL}GM-iӧT N pfPϊ g,r4SgYdheCNl(柳`~}Rտipf#=2SSWeޟ_A*{AR]ܯcqΠpO0^ĥ|Ub+Ykj&t>0zuZӈ$8rBA۝p,>d 'be3[Cm&BX6c>?G%b>".7؋wP!'`Sw]Z`MڙAtpX#'g"I`u Lywu))uܰۃ՝2:=s{wQ߆@{hأLk4Ty|)XY#NrlŤako廱4Aq9quX-<(`̨fqYkqF7 Y_/gX1T, gO4G]~zJA:'I֍9ɠsIJk_oOw0^ɝqKzWێ1Һi/ b@~R A.R~GӤG#\suA5$e% pL!O tOHytSruA$pL޹V kQmSEm}1* C:4$L _ uݡq tgVe1}K)w8ޣoﺁ_-\lƖ\/#R ȧ)ـ!#R<{@qT\iZCiǢPQOyʫ d$⛙B\vʽNZ#tV2Y \@Jl*.t??!p"#Cj=瀓tݬwC|nA%B풢Xg_Y˖Nl@᎘\yB(;2(ÆL7`ef+h˽ޚrG7enG`sY%)@RLw/G 3o ?kMƉg 8B ['IKt]2VE{北UVP%Gg/ヅ q/߹ Bev|Nj /A1sD> \D ">';3 iQɚt~Ʋۓaf#]=:2r2rX6?#?r՛e2nG?qmY|1P`CuX_ŋr0Ww^nI7q7u/gF&*Gؿ%̋p]MR루8*'([}:dp-e7u]Xᤊ!E< A<7wĥHҙ#A1,jf ׊;ċYJ,Iw6ibX]s߈!l50NH-;DCfcѢ8yNa.`^'M+w7B,/e3q801nu;}P giw;KRMʱAcoQ 9ʁ-,Oel}ۙo>;Ĵ}IcaP@Z0Nj>WhX#Hv {)otrqlaCT#W8VP~EwK/_Ol`7ȗi=ujMxaȲ8T,t՞-)&wD!ndpͬG?# gubթ =9d071eavpJIԘWSEyT"ǟ4mhJgetZz|hSgh Yo_Ne,EJs3_LM32w:4G}2@QN۳hhS?pX6l_Կjo:COd$&JCJfDui~ZhF- aV[yVľaR9n5 z3#T] pS4xY(\6 "?&j?0f@d"n4YZԢb.ϟ$8 GgɤdrJ1qjR+nJ„&VzV,ۿ'ZJ!5 ɞņh/ߐ4pif*NrU~oqn=9svzU!ǢD{J/ϘI)MiQ@N] x|' JP 2C@Aڷ5m ePc&k"z= %I fGCbieKSp_ ci: *Ubb ̥W&5OS16`ړt>pXqN.Ac檸l Po\N03͆U}r>\j`巽·hx {.k"ӵ;KUdpE6^Cpl5k0o_5gmw 'xRf!g/Ct_f_/obE՟.|liUc3~>펧fhK ~Ӭq[#l]a'`7Dު#Mgx.ևJإAb%6ku EńCB}:Вgqz*ܸL=Wc<,6`r*FWaeu}uY͔!7{iYv;FB=׀ _ؖU[m; n!b_-J"C[mEy0n}X/LjZN@ $u%o%YXu韽;iR9^&b^lu(gcLk5 R)5 r2k&EQF[{bɒvA9 BY{",]d0ۜaL}j=hQMlvB}rcCb!9vCd}by*6jB'3Ѝ6*-]S+S]0cΩǁÎ2FUELXhG$,B9֌J ̍&@^C`Q*7ɆT=̆٘qFfqJ0JdLuLx݊ۊcW?^X7n+M]oW:~`jn,=x v/k犷-M9%ɯ_\k<̒t]Q,Dd |Zy1+\& {D*Z6h,t<"2o.c[E+v`TG#1ftpacc /A߿y#^/'b'<O$%/zƹ"L{h}j:ֶ# ;so*vE 2?FF|k(]*(MoSe,v9{1-U} *Krv<_dNT& oFkou:N/t=-}|eڱ+Jwd񤵿pގ>ùX6V:3.c=J^d+B齪g:o";)HVP`?1XYLB gG JU6a  _yJuV{Pgn.FjJ`Q9@L@"[@@`5r*"NT@1ndʛ3H>gP, Yu:Kow?rJ!9dҋ`+rςAsOfMbcQQNNkU ݙquΉcUPt%!C\v&}oX,5ߴD&-{hS$ >*B!]P/|AM:1\f*F:W mi9wwZ~polus4J?Jsnd%x垑**ǒydQ eE]n+:y})wZ#B(,ucDS;Mal"[ĀZͨkǿ`Q&;jfPJqZqdŒ xLͬW-E2qj}TZm%dZtvbiJG613'U,'Nc=xOk:t\Xz|@V5ƥ70&c$S_!fSQ9y |HŁW0`y$IkWz2ھ)|dgͲЩ O?# Zr;S&[NN vDe?{4]*";{px.T>#tޢJ1@ JdΧ arф[^'6PkYֵ$Sżk.㰄  ktuKy~\j?#I?lX~ۜ69xڋmuTvDgL$3lqJe3D_g26x}Ƿz^߮ {x9TtI$Ѻֈ2eΫcNCY{6NЉt5c}ȓ{hUJBjDxB1h Aʺ5Jora5g(SM'!T@-'}nDRʫW^&'*6c~lq9!coS80 :lpl|08GSPˮ wf1ܧ B@w> F[gED=6ZkflnA iݧ^ļwGI$U4]  ʣ^´D'F&WPG;nử0p n8 Ei[?1zQ\rpQ|bf>.YC:,X_L?j~ ^/jtں=h ZPmYI h|PU\/2ȺJ}Bf~A݄pp@嵆pׅ~M./>s(E3$;6c{F ^cK3/`0Ͻ7peo$w71`,m1/;SAͻh x͡g|阉=5v 5hd&)ug(ť̞pHP#)wvReOnwgFq"r Fql&3Ù@sw ć(+f} qMq\$O#ȯ*>bҙ?Ԍnл1*dcEBz` exֵQ>ڭNBWߟ㬩0$nʊeFQ_ѩS zLzm|4^J$ʷS;M7^x]L.-tPₜ"ol4cXiH$ĎNjeAk ӖFZYTC#ٰ8vIBDWAs H'u6nkF$G.D]Z0~,3O1~'V) <^_ ߰mKҖ:z0{_ad`oCS.}0%V1r"&s`|/-J?|c αIdPmcNyAA]c8IE':i5ZG3'Ɠ .blH$26uQܻ,Id܉5,`=GybN*І[X3޼ RGA1BWЂ=)^s"^k#G#DUh';T\Y/tvT}wQ[ȩN9{׮*J1QU_ntDO|$[5F| +y<_jrR;ӠbZ=DEԗɲ20  (iUʢu)[RZA  XuWMQia&X5Rp1[Ye }B {Qv)>d t>&,`P. *p9t3OMfШ7!uuv+"WFB9Nuܳ%ٲ4IUŲ\/3 i&cG6b?q"b!%F s_bI|*tZ,ܺ2p۫|&68d9֔p.ji"tQw~x[sjLgNNVў>WPm2cm<6]r@"sKCQSXS|K]Aru_@`{Y}dYzp4i[U#a:f'lLT X<#5!iUZnV;7;mV0UÑDPݖ=z ]P# `e-ahchbdIPz"od)&f/cu/ 81Qʶd 7V.vl-b9["8A]l:hȍuZ*Qv9X\jRb 蘿P]:Ș u* Lqkb RL le`m w;W3#w:dUaOj8Vg9_g}p叏M<"txd9 I[ƚ_T*bn)^KみرS%BW-;Z0-|UV2W.˅Bɇ]QXqg]طZ .jmly2 EN~MI~[!!j|<=0&B@IVEk 5AףE쯲%6g=3I DtDu|hƈ)z:3R9l5bҳ(1٘'K:o9ɾZ]@Z]VΥn2P?~j%aj(4,d'ܟs0/ьu6k}88gAE vIeO[~ {KZ뺿?ZVzVg?^GWG{r"3yҜ"34}&GzNKѼuW3 ǙQZ2}}Ro>t#0ޜx  qLN8>3N]9ldƺ7]}Ya%2P|xuվT?ƞFs G !7n2Jp甅]GIV0 ﵯ>Ů033YyX]&f+垣]0b2[{i)*Gtn8 p\iNDg`m2$a84<fsܜ?>cj7&P;f/; lLYhE4?U1CP73?N avpdHg-d0Q%/lvW(.̙v(!͓`ꬿbmt0av%>?]\>DOM>ZCZcJy%ź[eKN>ՁBc|BWEe֜nc:˯feM_O׽Dn~vk2}d\ -MX&b'3Fxꉴh:ӜI d/1FGMȒ5Ry4yhv1x)ɜo>FNCiVPu3-i5zriOMSԲ\9 4tFEmx~^S4QaaM!a%wQ-LںL?C䑴 O 8_PYW WK+/jQa*s i;׋ +K{ݰD Q7X/jq'cTkLeg1i)ѭh7"nԼ,,P BeDU,^5CgzG@aM5o-7F+w.-IPhpIЀ;RVix'V f\yjQ79w)ޑ.$;F `N_ i?S/piY=eL(#jxIU!EduT&KB&5uu]Cj)BH6ֻJg{ JL K,s0ˠ^&%q%?sZ$ތu+11 `軔 hUWrf6y֞%57ü0I>qԬ3T_wL!:0 #EϦtiaZwlg߸rw1B.4G?˛ɋ; i_z !G|8bΰڴ69\J! rD*U/Uf 4@&^H3c6Zx Mwm/oAMGه7^@Nt3[_M:RVuY0>arbX@MFBAtahx׿`gn^|GѪo5bڗ9<`-h߻%zގ_n΃ пMxFAYY:ZL$ݛ# ڡSm6 JPWmkZjl4a4}zQvi-zlhF,kx|eV jkX_Uc  )Mf/NH'_)iX!<206?/S)h.|R#6ӝQ))v\]=ݏ I\BzCIf[֝[aL>g~[+hZcWJ/O#8 .Ox (,я6Zn~K ٠吘.z=$.ZM2dh+C&2^Y定_Q]IMyx ['BMj[J·CmTx3Z} }L=>ߋ>]NA wO%iFܽӼ(T>^"4//y$~f ALDә?트Px{ Rя.܊Lw~tDM!K;TX~jf܊C%9&x1FpN&Dz6>z>C]"'=Y+}2Km~EEd7|.>4üWag5v4JuU} A0yRKM_?KpUAsK:U8 jd;Gw%e|7B̒4Mk Z Z9Z n6#Q;Tj">`5b+[ocgu71ڽɚ->\Zfh^%3JDۭmvv8ݍGI\h"V%%,EKiV3 QޞG\RMDxۥg+Ac#|KWǩL.[$KpeM(.4R Y 9KVV=G&U$#rAMM]sM` ΆNka#IcF&$!fXu1ح`g6@$7(IȰM)pL8%chPwM9#Hn 8qqMk P+xj8N3Aq@ $A  QIѠ*y0a Q%A)$)5xŃ Ei/P&8I[[B1D Z~]=xTKJcVG*̼ozrqXͳMӥƝYXB#SY,O>5klx'~S v]`5O'fP 0 (xV',@9y{k3g䰝G_H?oO۵f_f+e:aaT; ^mH'88);+-sUוlMxԍs dʆ粒K4B;,""Qu-jYb@"aY"2G"@ dǗ Dx &7K 1:ߨA%f3þ7D72' unU-I DKaGuB)ƭ3BFB3G80V'tD&p83DwQ2X.$B:# !A?j cDJ>W|A"ޑ;>w L]AcI] # Y ֡ + s )bDɉzoL]DUc;^6+XTxڃ7$lkV3Qve#h'O8ъ^,؈^& y'3.<-1O<8#;ԂB:"j0[VdFa H"kpB4:G3Dy\RFĥl\}d9M>9sEZ+۾F!:OU:*ӥ2ۢ-Z(9d|K*R~x r'T\a@ <CNI A0(و np-RS @tt;H&ed_=wKIxrK)_@ ݫo}Xݖz6RQZv8!e%/nP`Eq 1cl78Zz]DEekEGA>)Z#zC`$6Ұth6N=F|VA<:Q>5BZ7c~뒔}P)M8bW"ivӿ>#,]ZD `I26YnI݌g& :cHƹ&,!`.k8wPzHM 4$wYـ_d5W&:;FąvH:f PrJDNwF|fEKvu:,'npi`){(x1CMX􃁣!)'་IHĪJBXkBk?uHzZM_܁g]_>Gi ǶpS%ŇsjF4r6Ɗ Ԩ.ᙨg=8 G>WM0o~CFd  $׽'(0 .B\BMlWttRTO@T2o[BS8R)y.t':Q'Cְu?K/=*Um.vdn!(-y`w8q`FT7u6.pSq] OSM-$ܚ:(08Boo=/>x'NlTU@ F{ۇv5Ke2DBi- Lࡻmv԰<0}@ "H#%v)t˘MnGZO`am}G~As6+MyE$r?J1u'k%P/Rf1%SN7"Yv v$Fn)e()Viur` Q(rMVpg4VV{ma"!=d퀎:dxUR6hP@ 1Z[{c]K98O8#tjx)C_YoCZY%Wg#Ss{j'j0}># R-vryp^CO[_4eȲ (W5 ;rP4V,L< [WS*S=Q286 t&gz+A/es:i&F=LpEQT~j?IL&%ʼTivl1c*b,Y}X?k&cֿa;W E1^b8F֋VHZ@FAéQ$H\XLq*-/6u.?SFJ0!(Þ*.H%_4JT/R՜3wXAC_`OU !mU"g_Fpa$.4CBa9~<\e.oJ?A\ܭWsO6,\3pq{xy|v MrF(} *p~NfiN# mgH-TN~tfgb_ Ex:658rDE]NhYM}| ~T(>n.䓧])'oT36OgFNDPMUZ֯ gSoSkYy)3 av{?՚"o^f.RMe]-,GY_Ϣf`Q6~Jd9l LT6(M QnToBD`g=yo~x -B<>P1|@kǚ+%M{RLQmn]x~̆GG 2D[NvS?ڑ UH[.m'S?3ܐeygx$4Rm;_/eb)ba; 'ez~??v~71>O_s"8ԢEE)aہ*wQs56nTt$Bӟ+➢? Q8E<|-n9%Z ~MǞUX"l"Jߟ_R9L:XVodwP4ܻS 8B*._85wYC=׷[ݜfSך]߷[/W__[^[\|B~az>'ckԆWϬ[/">^Q>- rH> ~ݹ\ы@oAM&s~cTOI_oE[fDΕq*/Ud0x-O~Q[jWXaT1NHߧoZq\oe"Ŝ1C'e.:1쿎]H*f|L8/bl }w w,&o?] -|Sğ&U.C6/hF ڝ^im0197ݟ`-_$Ak3wS ,kftErXh7*lB̰pSϹc7 `~JcκUZ%M5[pfLkXAj06MW%H;q!nH Ho)вӗqyUQW0K9¡ H顺Ʌ2?c-/|Y}wBȡRkl lib)`SyWYӳE;(ܙ ^s}s=2YlyPAU fA;$ U싐\q2cx<)-yIf~@pӀO6ʪ 2J`/28KQFaИCBUxgC{eϷ tB,êWnIvGĨ=iG襝LcQuofhVe p) `sK3ѝvSIOd/XS}8Jz0dpdMKCQZ{bݠuͼAh pHf_c,hbtOʅ5WHoKpV66o"%Wnv+5BMxmb!j엕5¢uY=2:M{5؆Ze@x+PDQa%QU^A67HS5%q" z/W@RL;ZMFXT޴;vQCe,d y>ʓi^]/l]~',0|r1R`0çx_u[؅ƅ#\xX\F!_rɼ8VxD(猈O'"bW#gW /+ꙛ[-[se\%waR#Ao]r`}fZ\wNɕOc WOP3',(-mS~Y8yĿ<9˿V Y[jŇ[3xJp"& " l#d kC`A-ИZ!j  <`(4^x@>íJ I VkH>g?A`3 #I z>9im9X#<sYneJ*[t4MrpϨz"4Fq[38 6lnȔDБ} 0.zx02cwGDC^5zvM,ήgk6C ni_(c .f 33"BPg8/Q0%!1LjeD'Z}pyH0803+q]zΕ[d*CRDN8cȣf!ƫ~a#1bŰG1]5e&j{k NɓzQ.rXC^lcjTɺ*__@ FjR̩AI*o+uHQZfפ1tyh_F9̠/_Hp[nf0 3u5OO@WU-0+ytT_NWj?Q&nB=IE5'ʅ؜i$ΔtJ?N8D2=F ";< mOH+ &&dqpOr!G1F*#X:G 9iY~$,fGH) UQL#1Zs-9S:\a~9E Q~}aj_~dE?3RMNl9}D~|$ƿhkeX;_ANa`XhmZiH9_}jABh<@pu*ߪ6fm6Ep~L0A`#6TUV ܭs/֔٦״8O~8)QFE|8/-wwK!Yxg Owd641h J*,hRXiC>9ZcB4[Y@̕`rX7sjԬ.'RLuзo5PGuoͮtE^8co(huHh-mv]#CDdE86qiQ]n!<4nǃ;hAȾq`Ct>,,p"[eǵlgUvmSq I}d~>\fJ$*5UײIӡ ҲH۪AXRoBd{]rѕ6!ݒA²3^2'&v[j3Њ{㐙u ȟC[Oy_E0!邞V@]K;B}`f<0Kj9'f(9/Q~^ qnXXiע|h96%!|>b\Dfue+h7;GeR@VÄ.z5<:ۘ{ug8L7|xWeTu( SbVT@i@MvVajlrM$+Y]#!QWv; 'r_jp~D*(#j{#MGƗ !K-Cn)YzŎ|2k .BפfMz4.͘PRhyQ Tgj "i?G,jj-RZ?m%{*Z6A&Z|{dV{n\j$%/²ٞA6l6EDZbt,vxp6sp64@ջɆ[F.Qń(g _(E~^ag}<;^'X,?I͆g?y(hZ!^G}NA~aL$*{?ܾAZL$W&d3l>3d-  pzc9"^s+T9ޚ [e:f7I5& ml(YO-XD<uqסP^Uip]`_+XU;}U 0Ag % {mW^CHw>פEK eG9`)̮}x™yenZb0 L~uűT;oOsHg̶ˠ0B\Γ/S>{\2x%}G/_p\oNnMOHxo??\773^ 6^\m D_QwZg1SnѶa<᝵E#Ae[˜Q Q>:g+0SwfeJLYSA_#=W:qx{jۣq;I;/}ZڳܠBx |"_ fe`|LĝfN?+u맠/ .FڗQɔO4zrN'nG׌_m܎M_?>_oO,?_Ϗ{7ooMx}-Mﺬý8xZn5.sY>>ח8`_};&m'Yk\z+֠S&rW.An^?<6hʅU;eO խv)9{ Mþ"'&@F^Ă Lߑc ]Llۃh FV֙8N&tU@vVȅܤ13! #&_q'ү/IK5"󢉄 }!nPQ=0"VbQ)5B"Rc4o4W~>. r}E#x@k`o*%,gҐtgo~E^ ] b@9(9!uo5gxT)GpP j\ X8d\k̛T/1"ΥTJ04RǢO-Ԁ<+p'˖!l1$ \ +(С(;o.tk `iʴͳ%zsknbFq6PK*-n4G"zw(~[:vAKQ{\,0>SPsٷw%Lb@FhU0wKFtX&R$ LӼ TV-ş]D+dr|z@ QM '7 >ECq,B'0/Guk]1icY?}T T*{2,/vY-=-qU_0idI韐-w?4^1o'*9J7yۇꁽŞTXJd#WS{4ҫiVdd}@clD33qXHuoR8#P`_i d aI5ؤ&ԜV!DH?J(@ D?!ϴp:%A#CB^2hkBzቪ~Lī/3-V+~ԲP;J/N^C欪 ܸY/H.`&`Tr,*ǍK8zr]3v޴o+QZJ"?k'kՅ+ڏў[*p24THI'PjX&(K8>Gʬ5:OY)aaPB׭ i-䟳F@J"SaP͊"(/nfJy iA2էx;2ӟ@c$+y)Z'&<$j,y䑠sb4-g@XmrzI!=#5̃iL3O"w16g 0ol‹3Z2!9Y:E.}fK24^9&:w)F4;FHuL &:( `0ahߋ9SM;%64{s܂9ZmЁ7 ;G}d:hGkGJRC6}\kj[~Zঽ!Mv-Fjb:5tXH}ky,\z7~AէRDAEʘR.ny2/c*0ueppd1T:0am6d9~ęwd6̅SDj WV1Z0ɝdXICFf L lAr4C* z C~ά)`h[UxU)J7$)}‰r 'zUrxܥp_1: 8eD7Ipp“O,e1c_}~.YtWz%)֚(NE&]{G"RpzSd35@ay1c|zf@ f_d)qpP|8S&խ j;'Z(8~ tCm^i39قȗEVKL;ȨM-Vadeb"z&W8l +˒ЮӺiY5 ~}X"Pq++@YlʙOz߷bXlbjlb41YWpz͒ƶKUdՊ+xĕ1j 1:L ۟GŴe(T,w%+8zSHD|3fOW<*ŜS:cf q 1I6}GU*Lwz7[T{M aZ@ :+dlzvduPn3F*pHngUƭ֖mCay\$d23WU2okأvX<\b#~~gO #pGƾ>W7)xdMiOL`}KBwbɡ:/LY?\m __<_ˏ5?(!Y=9$,ٹ_g)MQ:w躹CƟ4qظ#CNiz@hS<}0< "D% yqS>zg_faPدe qh4h >iKK ZM略&Սd^Y%Xe>NNt ^xVt2-(bUW2ϗ=.24;1hU'_1iF]'e߮Bn)9e0'YtYYe[8GTfԥ瓬٫o{f^2Cm5 ,X3SyGNTp_mL@13S Ts!K;e?/Jt$5|j,,ꊪ#E]l&"!TZuzaVΛnfT?@t}0W&G3USvlIJ$0&VOy:G~vҌa5isk^{e#&:D%/|.ҍFީGRoFH tXrt0m 34d-, Wmu TY|$1DOĒ=Wɣ Q툨Kp!L2g# h1u9Hc]B'E8+A dklڢ(ZAQ483_4I_Mft2r|ŗ(GF6. I3L^%_C-Vk#ə}Ds=8hhkd(oXҐk 鱒Fg oRVsܚckQѕ$8异Q%dqY~ظ BC?ƄLT_8y0|;JHLI[.ҹ?`Px׉VzN+h@Nn X^A] Ǫ>IlJN!9ЎT%+*|[X oS̨8cTA?ToTfZOkξNt G6/G6{ت%FO}w:=Sn_ǘ !ru&"'ݡH#_ 0(w>ori*DBY䤕[kۑ2/t mrnWcV6_5ɩΏ/-yYk^k֞/+IwIwN6e|+g&յc {ßyp=e.`36cޭ=k1 |g쥏pelT,>g#IF))RJMHwZG)UsI8'ӘRBZKɐc}Cˉoj!%-9;^v̷QO{ y_Gn 2voY4hld A싎\`\DKHI%L`^ )N=5mǿeDdψݎ^hܞ8gPaOT4!e;FVP|' <8g.-\l- #5幩zjlȶNM7BF4I\ r2M*+clCq#E8zE;q :#uFyJUT Rrt1אoj]qyiiYUQӉH|_ w0^sTwj+pSc}| 2gKl?5x Ppn'ǛpXqgVϕmn2ٻ?g1$N۴$۹fi3W Ϻ{G ̭ ֆ±8DOF},XiH٨Z4w3)<ڠL`=N~EnKTfLyTf 06됉t&y󢀡ro咽dBoDPHvaI=PO1 )\5sȪ'PM&($ 5ͽ;6z}f3$PaC7V-v%6(CmpH'$jOOBy7p V c)PTcu6<\IC0$4,i7E3n=Ԝ6Xf䴌 `Ķ,73bAs &cA+JN7&q i+Kg*"}o$@ϭP0 Ӿ %pG=)4la)Ɲl/U? 2ޚ3eش@$ ")tMdβ7\Hc4ꃠ.$M8}A t7(",ږoosjY|7Zvu琥4s/PcJP*Qrb dV<ΐoPz5/@Hy54OBBoB<.CA4ۚkv?n_ ERD4T(,.cq`A|RmYEp4ˆ>kX#*zV]xV(LV+lF]8F2Qp)nj3'PT97;j zp6x71)9Q{⓺OrC=aNm:QFչ_Ny!XpP24l-?y{kÚ=In}+3fmn\Wypktoi-r&Mf &\"NRP'tƐAw,UI) rm镽=v񐣚%15S,ʛTWQ֔ qj؄˞ga’U/DAL d-NMY*_\-%(#UïĀ!8ƿfȻ+]Hc5)L}zR;!yIF8!{{ S/~_oҍ1O.=;l@BM%!p]؈7o̚%%`{Ɠ΅(#6zH< B1UQ^Ya9bj283ƩVvV~Ǽ>م8},6- I3e-Y,0C$E(am˥^ՓmeNYOddo% HjՅq[ u6Mzb 0v^x3`óU_kmpωȈ[jT[ӖNv~\|A!`p)v)7RidܔGRNњaagU~p P aSϝ3Jf!\lΣw_4S@ sY{~E&ӧKmW P{ MIMʝLђŹyllڎ4ͦoaGz0x{ #TAzeQ Lv|+BfŔ +#9_e[ (@5>RlѰ5XxI[1U'~*6NeBq#wӺ,񙣝ѰV=ózxޘ5,酎jjc[\zNg㎅{8(,qٷ(&v'v3tY]0I; IS<".]3 NǠgo}y\Φ"OSkMarcFm{vHAlriKwP1@ ,p=[];UUv@y:շ]PpQê=Pׅ:홎<ԥCӍFaPIw} BdlaE@g2ٶA"$A8GqDbbuV0O0$Cm;ͷĹGO+U{s9~Qh΅o̹εln󹦛hJdS=.SI_4j\5CqbV{..>NUV-t{8c dngoZϊ=Z$J9\ڔZgK\ 5-準$Q~b` 3 k X?k";M^nUEJ ģr Kө AXij R,uX[:WF>Z+7vuu*7:jfu}g7MߏTh$g"/ew}Czo,͌cZsHpZڗΜ,-;N.RϨ\;eS ½QUD#;w丆] TCq^n@+;Q!~%1( q .y~c^d$SWClHc8""h#lN0 G?*m:l6&`>9 І]^ޝ}٥\V^,4Kcm? וIH8 U_$5%٬L;SS4't8 |% k9tg&z1QU`h7DZ/9EɊH2h,QEwL48!:XⲬ4J^{mDB" XC#>F*J9KGDh<,/p=2ImAgxb`]{pAXS*yX㌀oD#R 830W.FQzbU)뇣;ڴ}VJWuQ"IY1)MoEUgȦ2~S >tK75}fVT~LT,yZ-,o߈{JUu3Bҹތ/ɼ1F}N*?MR* ̨3-t %f8$/ftug b>~٭I Rg>:hVVڥu&T-Vrh+ _^_o 7S6ɏ ! &*6qÔa]FQ3* h@jGA(Fg7>{=3_lc*Bxȩe@ D v"HaCZ(3s!hѼ%',gNx/D 6prfxy'jȱ1:V(AP6rɚDB$=g$-DϠ̼h*Q{+_3X0O|9T% ylz@<6E$T 1[r Vn,3\Ho7Xқ]Wl2|'صٶWgÛ3*p pN9F*q:4`θ,ӂ.D{N(P3uᚷd4p-H%"8ujZtpU~`{|1{Drqw򋲩/i U q΁[w i'qjy&L4WI.]䵪7uaHU5Hwܫvj~Vc3q+IĈCj*t2 ͲO` {od6o[rn’Ss_[+o%&6kI#HҲ59V`Wc)[W1&.aaPܲ-톆C &}x7}pLBDT)KsLMyRhIrX2$T*?rԏaA!nPiM|`y0uk~(Wy |y`RzŊTd~T>h4`vk7X`۳)K5;aHz* 4" P WU՘=ea#2D7j1\ŠG@f`}m b{ 6*Bq7J6 ^&N5|rMkǞcSQ>8{8mv(Qps"n@AqZH/gUΆaaKj &VakN\%`Cng/wO`{y`J  EnRa#vܰu{1>qQDl;rf(TcX@i:H'bNlSn螻粧6ײսe=Դ.y-4Eb"9N1=S>eιo-_C-U)cאF3ycd((^2^BA\3"jAInm5o#~L!J#HYA:).2YFe=t=t 4'n3YU;7gmјbLdlI UCVUu@R*QN*Ibĺv==S>vlc5J2Šl8LW;q#T Ct\-0LaQĊ543JK^~Ҍ`U*!Lghkr&N7-T+vLnlO// s{„u|頶PNҎbJ)oFH )>C ٨f(%.taJڈ\J rS0|ڔU(&r$ey.R7}CiJk_Ҍ)4}kL@.fҖ{9"/[̈́Q b)ŸSjcqt9# cv)pVwhmVb/;[Hhٻyp|S"C1?J_P#^cTZ*RU$>,7=SvnֵmE/ήɗ-ٻnkfQ^zvnٺZ zΟ]_Oyz"s~WtGMƵ2.M\7rBx˓sF7&쯿G 1=kX$ϟb9KZi;T%|t]bq4dr>׹d?.G/ҵcFa%Y\DۀH$O-<)~ެJl5-][[.b=.a\]KZĬ$!\ #mwgˤ-H=xWݿƹBlwҳoI!\$YJ[,~E#6\ }mj>ui`g8QX:PJ['#QZ8PF8r!PرY8hE}銓rFC t?Q_rEce_%ڣ3JwxP_(ZOWLrF;-K,vs.剘n*dxϧqv+$72Z$MS\PssZ l{ՎUZ LēI<*?9=*T}y}dTR_>EUCQ6 3d Ofs4W'~,V2;qJ1M9nJˢ-T5 +~f$ksގ^Ҕ]*lȤtU H7 rQwndM/kF_$bjN8_,anIir{tyj*LԂ7ӯ4k}ύ<0gT8{c$Aӯ/M[B}{.¦j[2n+R={NM{H ~_hb]3-騥uM|z!>XlO-˒+L~.m3W4$rهwl+!XYgYX?ѧp~ymln>u_|4=K|0m4]Zt_駏秄:RAviA2-}jrOϟR"%1;Wq#֭iګԄWFOի ϙأ[m$[p_*y[p*/gWU"!Q^Ow":Z (!s(?M(sPtrepʥ}u} P7ތ ~ռ`>#Y)B SAab;`xsObрP?lW`\9 mvcΕwYҸR{ĩ6+®`{;;E+$P=*@FZǑ%B\HB|8(/8iJmE{qDgoT;g3;Ǖ˪1C縂zN,nKL5܀JUq7 |8a-1x",u40z`kP( ˜dErKgIgF%-#g" b`~;ېQ;&0l/OtG00_@aLu/vd笷`/s 7&O+M-yO0cnWO@;=﬍6y;VL&kt<{ƁL?wegIaF8^h+Τ{N)jvz701ٔԬi=-C `EɁocf9j"aUv] T|t}4QBHǭ?9bSl ehSrmL藟ۅ~Պb^6 yi2UجxfdaayuCg0cK_w!Muds7M,e&AN9t xLpj7C_};@&CnMb0fGn}OD|&]CLNEtDf[6, LZ`NDLBr i^_9&aQ YAbMu (YlMF)-pX-1)n tl V>H R:@H3l@re細&yERB+pU)КwԜ$[tX4|i -q9QJ4ZB14`@AH!VU0DI&ıؖ7,DE6B~*ֈKGɜԃ6"A30B )lHfA[1h4|P8%\*ڟ2Sb'VW3p`u9t=CH1G@AhȌUbl5ǠQwVK4DU&WUwHmΪCs.YF'3;w,e,;;q͜*o K M$ `KAAIxG4i;C WW@iJsZJc T3 h1 0Q*ԋ9[{!+wn PdJopFJy# JTSQϞM#"fj(~P7/C0sCnIoqS'\Z $~p ;4_wDHpYGNETX4͈8"O.ԇ5Qëu@f/ר3 ܞwaLmkOK2w? Omq>v!!Kk2LuAe b{E1ud㹩_aaubu"ձŶ E,vtA/^f{bX>jX(xفK(\<r)4$z7 _s,P(WiBp "^E͡!Zpε,4;iۆEݳtH4GjB(\\$ É2E!$xwL,5!:7%4% A*gHqpe24bm\K }^h 0 ! W؂ n7FN4!-"v Wͪ ɵT+v yjtI4KC|_GLwD7}O!> Ŏ&"t+H#RUі>%ƋͨoI-\%*jBM>h xBl gncO7AOys Kv 4j*&C3}nBOr4B h8<1HH60(kk\ܐ(sQpuH l*#]oX_l|DɎ"hVo*bh)29trjm] y;>:<^.kGDۛˆ\xPB֠~ANt%DɇW^}UQy6zhoGAge9%a/9ӌuӓU6Q[:(hmF{Y:%lƖbq9fJ&%.D(a}d:_/e*6KHF4z;9x^eH% ,_ ^;&Hb:1*+} y@R2$ SN3/w+UO12cx#  m=W חBq4Wܙ8c( B< Ȓ(`H8Ͱ^Ǚm$dAlZlW%$(P4SI;fM7J3B9 @;S~-̢fFkt(ެ M05;f Tf 18N 7d**j.S =ӥg5֬B6R}Q{Zqk I#i9-Xd); 8GMhYKws c>&xG~ eـ;rSNÛ0-=-ٵߜcvQ?6*AQħl'W:50e+"[N}aӳFZ+b67^mAM߫NfkLk>v@H9Ɔ"=^qg(F4o'R"["z6u"X}U5|Bp缍(5=t7m~M2| }P4ܽ`ԙA~A d;׊/[BgEgxu?,3|91I+VhHP,GUfcؼ&^i"U3RM upٗhJ_gUp[J4ʉ-W!Ld/j~ݢƇHt ڲ2-"z1ዿqwӫ}ݴW+:/FyÕb+N?Xt~|w/5'gDjLC'nnl& nlfXrYϸZ3{B0_Hw\{eW ؼ!95^il7W_d{RPo.WC!V ljѱ_ڴ4sPБ_|.8wOe;v:׫,(cle}"+-ص7ú2v^#cx(4DfqfQKKDo?Dsj=E\9L߷ ; !0FHRtwZA)wqޞ!Aj҇O>O34.䧃zE叺y9`Za̙wwdlcsm ?ΙvzaN|z\mm9hݷVbkl}&l-\>a,2.й絋絿3b{x#JM=0ASA8;CϹ7֋~#>jL@ʬO= &FVT!LAXj2 l^D8B$ u eْfm!*iA.P^,?hGYpy*  :RRזyh·Bafw)a29 L(#g0] woF[lZ #W@k9f>Q%1ݓB]c󑅣b5 2k\>pC}p롮PĒ[L 6T<\HW/ǧ`뛐XXXvu7H:Չppk`:lvӑ(Hus_^\{?ޮ﷽OzcG{p=^}?˼}?y}?}`?G${h?yѷ~GvGpÝb_%S{jLL `4ZrKfe:sbӶ^,'7Y ܲ ߋM t2Rsqd>G)}ۥMDzL2:ӻnl,Ov(%hDl,N 1%xuW$K_85tm8td7Yr['kλ7/C=ba[K}% h tg<# ȕh6ۉ9aXzK;X)g(bSYjw8*ʮj:Dщ-_`Ŝ}(Yy+6~]_nb7:6[Ǿ8ˡ]fo<. $QRZ*ZSU",`,b#>eW=vyt:j2\'P#3n.ݷps<&u: tS3 Vwve\;[573@Jo37NDrloBv ڊFFnes9}|ȶCTddc4]ga)Bo)QSVtj~H368W$[Lўi 5=YnjG.`j423*"bApGxbv8lwt'w5`/D9bs@e=n|1D)!篯tP>`l>Gƥ"= E sj}#EQ΢p^_;[){֙w&a6͍- m t˦o29oߵ~3Džɩe{k'3I]"PK1d)hTMA(KKYsv.oLh$ROƨS:Vz"9.;}3)==LkI 錧c\ H=j XԂN }Z9ϕ ^#z{jgaO$;O:L??}O0xy=G?[> g x+p$ GZ/|9lVln@F99o[!`/LOFUP2QU5ቹM7FB'A$a8p fXgx_f&! l| @ǰ0M*X\"X*I=/{ZdCp)6,ɞ2Dm]cS f5s&zRDV]wtu~e/^EGְ 綕,Hl~h'yڭ<˂'XUkH K x2+t[`؉vt*LOmEuve‚)jLph>QbŔѺ&}LW;!IֲֹɜR<~z֪ncI*YT,j{mB<E#ͽ7Fθ:tǭsbMf,ICT>~@S YYf>R; N5wS˥l;c^.rK4wCr0<=}a92k&Mq.s˻RL 8Ya 7} "'͵aC?&Ng\P:By#P+oAH=*Jm9w w1]>?'ϳ'2YCZ~c?NI8zYb\N,r3F#m>TQ 9kdMh), 8Z 1>,\^K 8Yx~@ >Z7P{ Yll叭UYHxVN"02T%#UD 2aTR{e8)RlC<6A}hy v82 wCƺ]@Li+6{J2vx|gVW[o*8݂7p0a`hP3rxB?:Sz `zeŭėƣ96 _1[o^$"!6D5 h.(?pz- Q˨%Gg*1N uv94f)/0PdkRx>{k<&WSOWqsK.8 :rK/.jɯ4x1&Vh?)D=- $2Щ8;Q^!|&Q/~2/>zݰG00ɐȺ¨b*jl.٠bjɓF<ы(C!:cS͚Z3eGgEFʝnl[Z~E{!JU&{z7- ]K~,lq[iOgw-~GI3kXglۥ_WfD'38c: 2V>/:zZj?Ciw9`^b`A266r?8 vϥM?JflqِmU._[O.؝w?>[WߓOM ͖UߞV>/mk2]Cc;=3c<^k>; p3~↬SL%'_;BZNc{'ߎפm? gq۝3O^6ưqNhϩ/ys:XGqmssp^l}wvEo^-N84*Aٛu29ًT.oTQ-'1i[IwL77[! iyE&şֻp~={.tktv.ݿT~D]mi艳LuvRǭ|3vR>ۥy_aj~7NTs ;/JZr6uV)wē2ֹ ʼnRgrLd%&OI;Kt]ƣ3ځX+ЯdڧӚFvEs&2ήPw-i(?gRI]s.+{zgeEChVݧ̼RbEx>=q qP ܘ$9 L^xӦELwޛÈHΈ҈\Y$j6wrqP("q- (g9yx3NUPл 2a5A<N,U, RpoHϊ ɧ9 43ed72`uS Ah|fuN}ɎPtJDVvĜΧ6R!dfLM<3'8,sdB LcTxOi80s*zd!fqޓ^8N Ve*/d͞BLa2ʜ0˄ĉiV,;FN% bbQ1A Pk7dgŖb[(%0'/-Օ)"6h>>'o|OF"'3L$\RTw3JE" HYbL}H-}Ә*<+K ֔t\ 8'\ yF(1L kӹat* i08?Tб 8T A&Y#Dտ1=JhV {'kcDtf!pEb, d 7{*ԙ!+C&a+dfթYd  ,`,ע3| 5GJK4EU? 23WiЍ.O>(36Z^oY1- TSipsnaV9D=l>UGS#sN;6TFhlDx pFϖ9V6b"0# Q+!5hѼ-dÔF7fZ Tb-Yn[_7֔$`mfuxyڿ- :e pE1ki/GZĔ-t@_ +o!#VCh}+1EZ]"ؾg{<#]7JBQД Rqi46&9dT;xFk#Ǣ\Ej CF)"fӪxlA` 0 ^*@f1r,q7ȲGbψH >U$#[,?Vve=RZ? N!D.VAJ2!7 <THy62m5ƬeS DM\CQ:2;^,LPEE&%Br#Qs(cK'L8~Y|phəU{lŹ&4 3DA*qR%֜0f&PSGh%2~4XVPw$,H(DQbD∖IFD@f1*`SȒ|Q0+iԛݫnȄ ACL a72p(;$Pt@ZAݘ{T $,Fa&P<00P$2<0 F΋okl|Ϛ(Лy9Ǘf(x^h}I S53]%6TB9/i|J$8 ؎W2O0 ]g5GǺ^^?~ORavE^+Hź1xvj jӐ.xID<%!;oxN>6`4my[yU\``Q8~Y01~Od(`;Q@sǡb"dJ4RDf5 >j83)pG}L >:`JH ˑ?*DNTl&^*8҈q}-D-D! F&j7 9F1^$mE+`U՝x,0(`doϼc@fud_]2x[sj(Oȅʹ۫  =qZAW6•w"I`+ qRsbA%S*+fvoX XL{OSPc%98lbyf#LdǨR8)BST`l|1 ʖGN`$,vQDS~xn]Ľ/^?fqZ=j!<:Z],;갳D(a.ĹUSA\FtL>A6 Iŝ:TL2[{gE@ںT3ꬨ `2dL'O -G|^_IvB%x!{6Jvֺ|0k|rqoXpA3AX$R_2Ð-DCtvb^]SF) RDlbmKq^fRKHAi>i6sc$Hڶ;^qM0U|Ҳ!l$s>BTHbqt', )7t@rc&@H6,yDJ_mn핔\QNPbQZu%pRB*L{⪄BO)7G~$<ߏ"ePޢ "fP}dqDԌv_c_M*k DJ_Ly]PbeEԬ)waw%])%<ߕi,F8xK[F֨(]iBBs#2y+(d=@֥ ,9`ȻOg~"!]]Pb;%RNI ʼ*`w[CYq/+(qn977)qqBUm1K9i^z~7FYg.INH ̰xw,ZJEd%^+uH-HVh7P?)TD7Q8Dm n=̩htᔒ "a8).Y!짋#ٯp`ai! HPWj(b0CTĨx%r,rBR "-I$"PM@[nٶm۶m۶m6߲m۶mWQwęlGعD5YF "J2X;U'8nie=/^m,x&˱߸ I~9.pzB 0v b=|L.u)> ,UzQ?gNW42 t憟@5N RU՜Ⱥn6?ZR=u) ilܤC;e:FS hPWN|=s$;Ifi"Z>jRb淣# :%NBypq0xǴO"[VoFղ{+yciֱy7_hVe#"'u@$Q;.>%\qɇd% w1O6oU(jQe5(Z~C /EMU#2 +%he)>A$KXH?n`T='9ƕϠyz/x?H2{5 G%z\U[q,I _:M iÇ9XpA5> #5t=u0Cz@mC)6:Kb^G1%sx;.ge\?yk}o> )5܄HQ{َ{\g;6e;)<ѧD5]gG_mQJ}">ee2ي"a??:F ɽ} Kx%WwbJ0ii:I2L;s}fy:Kj{ݺMwq|;x/ru~w}[RIx {|:r91zd2!(%+IrpݟԐJ՟ &Tr{H xR71d)c+/C,u8L89K$]@#g)'̏w  y$bhGg]Sֲd⌕.D48Lfg=$-N$`\Ua#g5bXB Kc uJ2aΖuOEMxfuH iߗxu gy6iF[2q`!Ի= њ'&FvJsQW[[gƣx8G~6}+1!FV=%>H`C<KI]/>$ QO9KNOG4$&b &訅O #JD b&jZl\!"&tc9W?O\V>n4iRL`2ҿ^qnĜ A0e\1<%u39l!H_F!gDY` x7C*H?Z>h)YF$.yBǚ@;bP@l_RP9LX[]g&ʓKj_»<8 jNc ~-aɝ ma]0N ? .{e4]ήL@8Ku2" [&k*"% b .TA QJ5ciTN'2F餩hЉgc +=vé$N@U&0!"396#90qqYCܿ_UVRyT,Hmq_lpEqĆEp>ʃ`X:TvfΒIt\ggPvjzP F):nT^/_HL `=>._H;[3 c 4x{#ѰJΙ<{!Q@녘K ;Ni>Wmk47Ξ@HKGV@C)F(LKEh+5r# +Q)m;[Kj^LEc4v+1O508m]@o5PR㣚p,Tm=c_N4QwIV_<{uH?&"AЙmUe4=M =D|ѪFw4%8Jz^þ_τwRv)^[RQ#6&%[tcPm2iǜE2'<d2N:í(uK¹: ];E9ɤ /{U&-䲚 i{ټ^o<^)f$li]MR)?BX|C&X_4ya$QK%e6V~2/u̧u{*IIŔޟjOWY>E]>nܤ[`0<,A>߫|],`p=V:vOW`:vm+1 U(p4QKB[qGmed@?% *N 9}_)^ŻV{ gbd_crH?iЊNbg^oC5}2bf]Pte03ǒ}܅_͟?U]>Gr#'15}KQIGec/E͔9?Ǘ"&ݟN)YØ@Zn٠LACN[#sA <_?Ԝ/xFauװ`ɴ7$vDz-! eBݺωVrgÉڂ+|e{qHGN06L5a u\:}w3jv뺳3~'1t)Whj\z" 6;ܨqա S2_+*2xLсa+1=:-Du +4早(׹g_M hTPSP 5}f x8^;ʓ.iI)߲&y/k<8ۖ܉{U.B#˘s9[75+<ֆ_qZR wLGicLvA:p6~-F&8`\>A$$J=ˏfJ4|E(j#+cr$Sc_sK;'Uc پ7]F`"O0&D9}i"hz϶ [Ā!,"(j`,J"Md<'lc&/՛,OZ9;3QZ|C$OK3Յ1EhOnpVrfRqs-/swsM PjF$Xslݜ5YNe#h8g]} tsҁVLV! OaG2Jc?N@v1NjS4RU7g&[JA꾹 @@̥˅9Gviq*$/7y0$8$H0 e25F;q`e`}HLI@%foj5},\$٬ o3:*%[`A]wM[d]AA36fVVulsV?(¦8TA(OPyzJ  65Ea6E>vVOj2i1k*?9ވ  E %L݃0K\EѹPۘ΋,p)Y!|QJ,wj]O.\qeG!DfkSު_a]/p4=5=[ lb+l( >]ļzjȿb[H%g.P 2GwߎvδT3^ vNo::C&FHaj;HK GtxY4\RGv7V*Jsao e M"\Y#K K|R}yy߼Ay_+$ɹ ?V◞pUdwt,Ba؛) H^´29Ƽac-MEk~L^ mp YJg ik?^뵖h7p1.ۧoC,[l7*V):M?.rx#,R eTQnX0 dKHCrARA GTZ[`<@q`с$BCMOx'yx^9PBd<8)9lxdwE높{3Gʘ7׫ J}KuF b̥;*}b!KV.~BҮܓνX:SG8F2еj ڜ,@=~h*?MMaW)F |TWPC]E"teߡ;]TP7ӎj6akyZ 0%!$Ydž9zc>sHz%Ffo1@Owsݵ#Myܵ{7(9Ǭ_9<$rz/Rg9 K6mCAtf '|͵f4HmPT]%}[yeq,Ն_TzeqI$7ޕZW#LR7=ULA_^d 4nc0zxA0dM+A(+%}= [(@ {usB6[|F*frUIIZϼV}76'%'GO\/|Une dwuxةqKSB"4^/ mbS??<ϭYBׁR!4O4!}-eo5(kwR޺֝p,-(LeKZrjwL_Zo^5Ak07l1U3Џ )bN=f8A HĈ?ؿfmBN<8I'~X:. o%n \ěkE~t ɀ2D =s1?YD~}2@EYd,j20wMx$ZVAHQ$%i/ $$ SO`8:FTZܝ~[{7ԇy:3Wώ˳#ɑ^3 b e++4N""c:u/;2Vp&4r1[f5PJ VQhlo*l= J!kPib-,o +lߩ e&=D5}r@iZgA29 ԸN$01)rc2>las ZHv54YoKj$d3mS!eM83<Ǡaf{0t96=ԖJc;dؒҰ1424j:fv7@+˒rc}'p*\'7ioPBOj҉Ug խoR'ˤ,wEc*&$>n$l[|9KD!WOmT@)Ո1:2dk!(64Q'Xk88PyF엸b4aI`` p 2 aFa;wK$ ]iW;fG d6w$sG8'AJb[,i|uEK 76x+Bt##+htj5堁>&Š!꠽L{'FN3>K0Çնbs>!ks +zgm{nmUHſ2宏L 9sc>(6!mtDvFױ޼*LG$*f8KOjA-%ૹb& x@ܱ߾jf0 fTbnT!™JYuZ#*E`ubzKӕdHfWG14`i?L@&٩Opb]$'Z#fu @,6-g{sirg0pbX1^,倇6[g"O6*ČEDqf n}e;\d_E' BDXj:]\ QA+Y+ˢIOMd7.M%`PRpCpumM/qdSliIuSIuSyGCwDeb+F#j ?we7s 0W?dī,HÉF"w43lg}ӦK`:Xǹ˻.C_qXnnYbEɢw]fRXB}9|jGJ+yӄ,ϱw' L%AtudhMoIVK8tψ9)caߋܖ]1d@%h@@}M멓ڐZM +( 55BrdpfxH%Hm.b ӡtԔ!*&$>]Y)&Vϵ8{S#Z nUj۫&|Zra*H| 7ޣC MޔmkKqI:zJE ͅXCӋ/~B ovdJE6;wmCGɿ8jE>ZuN|$UGc_")=Y%+1V(5\bO2?3"Vȿ-}:+hGt< {sNA?ғ-SԆM(b68(w4s: h+mp|$ͨ&1J0jqq=kgB γix^S2$9a6q6I1thV b[;3CsF8U!%~tܝs,AZDYx͘X B3bMiCc<`ӊ&,O6Hab /T4bY\] 5)-[7YBFNCF(Ba5 *(!"#׳P#q 5ˋ-#cf?a`љ CsJ6 .$`tf,,@]gu,M/Eٝ W/2,-^vqQqzQSu}'ao:Z1Z`x?!(.~CHG lхD NmJ#p~S5o#Kb(PSyk9XR"NL'&"b=9`嚦GUJd]|D'~-♪l_틊_P Gz-zw8Ϣ)#cZ5-w2[1VhV /3q> gEu~9!\- /_G_I} %C׉~8)!g.%&CS)<1ED@;ќx-!QbgŌaXslZcTZ*ZxV0mZ*ݫ˗ʭpBo\\cW+xjf:Ick|.93Ǐ}' Z.WEG{%iZ:[ӑ{j&/;\,-Lɰ?Îz!Ʒ+PNt)c̲譔\HKZNM=+z{hĘO#uV :8Q:ջ\&u }֤*UQ gMoIm%J0)ț͵[%R橺'k KZӜ&c Tv /ZVXl!<}$%[ 0y!+}1kD™DPW%{FR'-,jT#0u.+um Hk5x-TNF+f$pkf1P8R-m8"dC:\R=I#2de&Q DV(K,S(ͩvRgcICkxQEH#{fMK~0(&\)8k=+Hp:+@h77\(A TXb0̣|P\@ g8wxFu.sѢ!¾F-C$ &nX'!tgD3,p:&enP{I^"B +m q>'/=Kii҄9Q  @y&DSHX1F7?u,R?t(+X]s|yjmAv:{R@Nq*4 dsQh^h^= X(7CÿAM91m#]s%s0h'%T$fuPe6,|,[d4v$P1};2@Rֲ"%; %&Z@]KFh=.qp\]&>kH4lZSx#؞WE8gr̥xGMIKUlЄ+WNr?;2'˵V&MHl-Qo}Ջ'BCѾ/TEH@q_ U0R7@j*ޮҰ&_!.,DV[ %$HDT&{X4\~iy0F zľdhјTsBdrإn/t؇ls2S^"| In3|Koƻa%+2t2:nièdρnlUz=n wkЯLZ3 |P&B'ٽ*}il<.3m1mma<o#F]aW՘HLp!On]u50\[SJ3iH6 DWؔ~%9f v+i>SGЏ{eKdٍԡq:byXv:mNsd49Ȑq!895z2.+ܩimcDMXcv^QE%JDE*jcOHi PfO4&K^fL)\>\ iqF<^eDYqSW'>P`CyeC˶%SH  "E:ڿۖ]#@5x>"j. Sdd[Q'lۨ!(j) v,˂ϾfPK5<ٓk:sÇZD60`n-\ gxRJZQ3eeׄz~wϞvMi<{;ȝ~g'yDXԐ 8` r 8GXWUVBfxΕĠszTrp;xĞۉ4VE)R)6fc-?뀲͑h 4|60\9Zֈp}k53O3aټޖbj_4\J4%.'PW;\v<jr4ꝳv4% IgC.FQ[]L`9b%{zf\"}} t^AN Iz`2y|(+l/YҸN!&4I+ek`N3--r,g{rtt;Ej0onC 7t}HoOgT\JҺqp}t"؏LpMPK.w7~ #)G1d,Kwݨ3'0ܜ~b%PRqC+Ɂވ%}1l[IAۗULVdFB{(qٙ]zvz:VhTD2UaU(b/8ɖ'M}~Xy|zg0.#bS u#' Xmh&貐V5IԖoVn+]·X)1N- آq5UnQnIh(2(=ԕ(%- 4d -5\+wЕiAL'Ta P}tŶcWM􍂒RUͅ O JZ+4Z EߦE*PT kpfS*X{s Ds>3cЇX,G]thǂy]v qxUϫ~uQS*zN=J/ ÎG A(׺lV?%ܦ+PveW!f mklqנVx;:yILE7}.bڳ'x.ZW-I#_a.3 B[ZZȩ++K;bwVUa'l!L xn7¥m~<ʍ7bgRaY(x=!0]}ddW+qd7]mǖF iLeʣ!1EP ; {#Htn_! ,0 d q*pr}Z?/hlb1fAotⶹv*L5s/@23ONnxK,]&W(%vr>w.v:Cwi<s~_˗u~/N,9^v.>זf u>gL-.SÄ8cfJ.-{vgx%Yg/$&r7,}?O/^-druZ/pee/>?cq1 huΑxn?b0>uA]9**\GK$eA2vg騝om;+G`Z9BqT3&!beK% RJJUHN{Hc+Sx(9z8G@= Xj}I /{^F))pixd3X M@al1H劫(B9da*Q.ADŽ@hA^[|G?W F_@4]hjPwdqtodZ|٩/qT!g]_ sWdgI.=d¼1,)Y̋vbDj.B::dJZ^@@[6@pֺPv$:?xh#8*_Z)p?X ctdNԁ`& m|{Ìшvg5XZ[6R1*+֠0k Pj4`!?ZO(giZ<*˰ {;2 _biŸf᝴}و:ڎ?FXoq}K"c[ P#hB0\+? TB?x #uI}]SʲS]cuej@1Cc+f 50|5xT+Bhl^\SVxLdv\(R欖кºG'M\"DGи%^2#Pb  e0Reʣ|u T-+ Ӻ}s, w,f @jQOqBtK0j僉 Y lh+`Ly0F+to Ô cb 6?Mda[FJ;KlГaI*E =``K$V5"yaP-M7[ q-}sQD&U0m)妅ٽqGh:_E2H凥-?K&X/:$t<㛛7<&-ACxk\eIMт@(adLw4=ڼ#9N]9EeUa{1"#ڨd)Xq:iI^)rv2*:*p{ s*V`<,ZH66iO j Z0qlڦD +c"tbʼr4!넟T3$@re:awe$G*;GW>wmFᜢga) Rt^d2NDDigD.F+cl+"_GU}MC>H@#$EdXmCadZ2cLg'@B 0"ʱS%_^Ja:KȪ&+;i[H|#*VF:tJqΏ2䀁0`Rm<P#n^O=P9 u,8`U~xIԬtMLҨ9k{Wpؐ|TӶWQ[vx9l&6<qJK'Nң^N& +}uAR]ק?xqY`"equ"ӹT=һCAvCU3ycX:g1li>Y8Tl>QrA[_m۶m۶m۶m۶mj,&{m:"wgyOd/AM$ލAp)߃r*=xp»qۜIlF\RM6>{|[bm>nzuRM[`TF:Gl;S 1ؤi*sAtr=5Qjs5T-8Nw*hE4=H~ >Zy S VΔ^[їld^}k,X9ލON2\}HQh{+ˈmcbc]qYuc->tTl JQBiPSGzpKs WsAJU)Ow 5s)ʘ#Ӿbuўؠ&~&#/(1l*;}i*'jRtK5Xe |P6NإY\I#eFeR)6|LoX_d ɱÕ4$ϛcPk. gr<[MP1CsqM:x"otGR{n,H;&W8joDPz2MggeԶ{VݎQ~;cJ^DSÙCc7r%ޚ%H9{]y23w 2⦱`HP˧S푁a6 Yߘ a%& dĻ{|k$g|jv7e_0D vnta&FV|#dk!SN"i~y /!mN1}-01eW&8mRzpR/_mm<-6cJ=)c2LєhZy~ϔ|6I~rѸp<]g\k !ܻi-%>?s<țh1l[b`}R-Q_!c0 |/T0>Y29`FK!֖Ra"k i+IeNg;TN'>jD<b#NFw`k[  2h6#1.a =:IP}"ڻαg ݯf,iPmn5[,]n Hһ 9 BVe#JF7$?$k.ߔZeepBx')\ݪ;-{ @4ͥ(CxᲪ,(7J3ILnr=i[jҼ>- _J(Vs#4vސ(M2A,#s**W`~-7a:NLbmE!LD!Gȍu"ɽ Dd"Gx"[bpߙv2"O_v~HwA 'wv ?k RFw;.^]i&7xM7A ]h0Pr,B[Bf`yP}b!z@}\wd[yft>M4q);ˌ76]rd03=pOP'f_1aFQFDٱ!7iyg5:R~@p %qisD-ڢ?82Ig҃OaFU*vɎ^W>vJ(vQJ{q>{WوB2Բ@GYHӊ$=GlxO%O8B$J7sFi)YK׶IAeAN\RgϮz,UuI*9=[tz,;I[o0ң1Ǵẓ+猰cC>Nuhc%D`*h[ 2D`f.Dm0Iz@(16\{VÚR - jE*d6JR23(~讁\UY|P̩ z#h,Th h1sE**R=ĭ&G9D%S#gL$ق!|)>Zv@)vd{5Bj,(A~dRRT֡c;?!AoI\:#s-95QNhxkrIKujq RNs-mtLjSJרĠ9@)vX#, XkYQ' F 5Z,`dUί}D̾fTX.k#+gJ̒Li=L ȍ@ӂ[KC~$ekbx%P,|D.';uِ(>f&}v1#HHBC dȟB5KD?mp mgc}W(lvEcԏ*]&U'PKڒ H8=h$+ )7D jΓ/@FIDo{W.8'";N#2EukrpgjJ")OkVڶ ;aώ`g_36XƆ$/^}.rHZi4>/R]e]rM0ؔ"Jwˋtsݔѳ>7ޟݛg"Cڝ_)i ݟ֙iӞoGWk$}[PaMYW'\YcV/W5]/8Z!YSIƨ>Nmd?^Ra"R3Iaڂ%cDG6b ![x 981gZܗ' 2P[ Q 2u,9LMU]ZIBO2G-oDr2mۿ4&1ɽ) @j ˳-TӥQ!wkk|ӕaOGچXeY$EKh~D bCpx#$&(3}kL5,K Ii7Ox_qUK+}눻(fx)s');"f+KcžW5FMz'HW Yg|q)YytnĊ1~lߖh4bos͖Gu[eFLn-~\#dv~r81++CFg V$?>O$crJn4U 9ׇ3>Q>3_5MF%YM7٩ h<.A0Ds;˜'w8+?]1[D?0"=0K=޸.(Q܎ )z8E~!&A1 1Nazp.V86 /ra?KBQ:9w /Q9ń^SN7^2 /2UUU= iw NQE+)K Uohjl#gh~UKлS--*+CN\:/^)JX PNj 3N4ZL&Jk")U,l1֮IF?s8r ETzՑc , /=GЍnzT鯌:򨞼XS}㵭g5ep( 3"*6/* tSE٣Ж<"*xRKDu$[ǡ&VdɡM$)[  ozj%&)a*-UʋN3A ?##%&h_@oguQlu?ĂSɏͻl9YSD`>ncm>4r=L#S<9pG&2+ 03H9$ZkySkC ^瓒/J*=]ѩ"Jd=X"$s\I`a7~C6:߲ϭgn`%T9MїvEW6V&o_眇/t @^!PG Mu5s _u} M.Ѝ=9 "ri ̀BwH-lJarQmz>Q|ʨ!숥zQPGvmn&Cg16o\Zf&Z\ .AYЪQ݄JUrS@p)D#bE ξANӞVVg|:ay吐 ٟ6[i,CM`HIF;TKÃy}5nZrP&襛^UU~<Ù\ZeC(EEkQ_ma.v :mmJ7P`F5U|' 6 f5f ' |&ЅA絅h$lb,l6v1RNiD-!p(=< N  LhˑQG AJd0'o(RX -t;̵4|S"2['_<]evEH|WU}mt ]-uW]t!`a~5FAU@NX-G?ꋔE:q2FutĴˮئika?i'xuyUTPxgJBRBb7D7;uA1zeM^;U-}h 9e~ 0{` (Q}#*Q[i.֖Z7!d.lvIyt t8aILr C_% I5-dm+cзʳiٚ!0vú374*u7BO-ؒ--"8(G℟fsG, (;ZZa yNbYx+|ғ$)v[i㉸ZK{xmu֟{IʚՏ]]Zdd#'-JZCsc' ԯbTFb1=d~;~L"k]5{W5ؑfKBʦNvkH+L%n<0Ωm$$hRs hW#YK9D{T9܎q|4XuʭnJ4=k9qo7+ID4Q T1{/R 8A5-VVKDX\H'8ƙUhE:KݒƠ\(1 q>1#[ha֌5z cu?YF+$)z? |":U{o#b|}~rC㙒AĦONFjPmXIy+r~r( a0r1c.V쐎t*]J'Φ\m% #c,h:RZ2XFϪ_O>G /3AFd b5@5*<ˁ`oZ:mƄYq^ * bPQץ>ѿB _TؽwiUI\F0w} ^ZE Pkk&&Sh,* 4 !wz^lipBbB:08@-ԥER? Mr[_~#I5-wp}uȒRe֏Ntlh =  x|ØJ"Hʊ+okB aO`:t~) >) Y<6y?:Q!)R%V".~6[uѢAo߂hlgm6s𝝮Y,8gEO3Juy4Ny=\ ګ|6uRE_a{!b-8O69(NIz]̗#Nw+fBxpYZJRC cV}_֥7Wxhlu yfvYbȭG ]Nopf>-꫒l*:G5B'oBTtE^h#7]Wk0^v,p{e_y#7;^%Kf QEEf5^Wܐ'B=_#.#Uxُ?:fvnH0 T'j"tZ_2(@RoO\`2b੪Bz~!O@NC;!>=7 QgP!a XFy̹=~$ݪH`><ݛneU jQp#qMasS 3b2UN2C਼3l=c+ٛ{20Ekv_z}=<?Kv|wc|~nˊ^vn?v~n?}5E<ܼ{:IKhcҸ;^ b O xntħI^+"225V}5yky>Cy!>c#/U%? 놤 N꯾#G CCn:l$0£u4{Do3$[ Jxu WB8>SbyR&, k v)+5Ml5P_yNml؞ J!zg%L$ΤTC-/[م̬ #YZM@ p 6Jg3>7C[t,(Gֿ%"K!D8.3 |GAIT(!u A"p|'s%JIȤm`]1" Z>ywQymeno[Olho>:[[BwX:κ"VC'3L'՝+YG]& VjX}мL0s{pQ,FSbd臵TD]㱲Ʀ4RdV@cN<[g7–Ǎv30*]͏b6pJGD.ǰuh-yގzK,)!*x?؎ދy~a\t=fa ;bұƍ\c&K_lƮ Cd(F&]"0i E)oJ)!M `R{RvI Z3*fHy;s iC[ּ8.hlnp8m(0? kUnc>9s5%8gh+V\qf<zN1pJp߉ l$™~&۱vٮJ:I薛ť@(rS4͸N5]PddT뎀qz٬}lcO =rOZc8FD1jnȒF,[u2KVkۘ+A-6L)miڠB?8.fAOym7?Brz^1`\Bfw{ϫ^!"4@O kkq1LFaY'z '~3mLRz|dЗm05Jplʡ 7%_k|W >KP%wiK|രb ?|b'9^t<(ӄ(m2,yqMH m dsU *;@-Y(Չ\WwYWI_1H?p9<ʐ 4V!G@:>4_h.>uҎt(`ڬx: Wʢs9}u2<>aH#"?_ 22>Mᨹ٪ RlDKϴeF0T[iRv 9l90 (ojЄNi'dC┊VڱfEIYYw`l](8ޟ.UR®4"ǟ\-ӥLPz&nTSĩ}Dyێ LWTrҾU%ye Z2E%pj3=<>8|!G wwL?dg|fHNW1 6v4ViC`]C+.l(xv;ʓe# QCY[~mej:*EAk;`0\jyŽECBU6s,wXhk}\u8Dt#όk{i9N.RZϓd }Ak2ٴdǛZq$An06KrJեRʽ}HQQ/Fs)?,u,!"MSux4 fd? ~"4 4ZJ-ccvU6{W݁UsZ62p^0,K, |\O&w\{L*'XTNJR9wKLN+SE49+*ԺPF64Dԗ0r>oϫóٶAb:!OhsiHHjuјJeM).Fh%Ƥ0%d[1=2,TB;iє).FI*aUt7.w@n(x *h;SML\fsl Q-P$eYP)Jw@v$eHK0lT! 1L/gYF 2'Z*0+kIB[/@D}#{y?\(3aMs?z{zͿ?z0&jS<[SU_.|F 09$%^& ?AYO|76噽Kh?0y'!;1̅G|#MoHMRS2>: 될LJNsUٰK ~{Ol"C|жѠ}Hai&Txh $h7!nĽT5/סa3FJFTǯ' QFUEjcX N"܁ٌ6݈ڭ*(ϗD! N׷㭋GM ;\M '1˻s5UZjR ։ׄ*qRo! -+F)E 1me1,t3r-tObI|J~|c{H}T>Svx E6v\;n\>4WOخ4 N~\>ܦ^~_Ik=$F4|5QIM]zɛ 0VY7Ű:'] L? ?bL313l%x3%qCz-M 0nDdؿaJCA%+NާQm D9 8n6F oD;l߰? W9F(Az>Ũ*ǻ~oPڇYM' G;2H3(]B* }B+?؎ނgs:8/ĖNN0Cx}߫6tr' Zϕ}smք.auRJ;_^3# /7a_IaH>P*~ӎ<ƅ|!Ƥ6MC5 x̴zU&@*a/!{v{ʝS؎TӋuz{PH GK>'ܡ3f?FpiqDֺYsB>y^,>o7k5~9㩫nWEkFaNęKm9MP˽ܘ/p!g%P|L-Pv*Bg ~PYS^$zvVVM܄Z`IoIMM^挏!񇄼Cv*o?JnǩoNƐ0R "OQ=כDZDV[؁&I Hs?O!rO^X*Si9{wᒓnumO"[% šX@D I6iqWF̍s!UdUx!֫~uAY0]ski:@Ϫԗ V$v 5"FE،WpD>:o^hjda 3i W[UTHH#Q*h[oBDðh4؝d1PCc~HRcx Yt>lz e:+uO MJeh;;Hfk݇JM%, Ո^2F"H-0uɽS5Gzc(2Nd}q;/Jl헃&|sϷ 8r冒i^7$+4{Zv&7gαd'Tt̬C'!欄ja: -!>im(i)hP~/Fu;#y]QɻkPdhBtZNҾ0ԾTx)Y+V2;Ъ>P":Nq#_yaŀbZ&oAr&2uGK]THV;7*\1jNaI$qf9 %)9ͺ\@8cJ ,gӾۜ͛PetRGT&q~'"jp2޻?l5:^9RfZ =D=&A(%|ЩRjTdkk;ʚňW$b!cZ.L}bZK*{gأ: E3[NJͫf Ṻ9JCLߺ6&d4H]/0w=$)CwLP[|=[&,ɽ-Yp̑u*&9{ZZ-e&F{õƄbj;(c[[®=ۈ lPFhv1a@qȝӠa"؜ !NyQF$`J ۖQalbda N૩pű6նs^P'ނDH 1)h7rfv܊W [2$Z _Š!$ږԳCʡ< 8gN+R f)ӷKa|2`FjYZjd}5EҤ ږm͡0EJkZ|6QiT0x|u&s|t:ށ-3xE$DZ{AX8">&֮8%[A/(KCAL J.yge#0BڑGo?@v^/f#ŴiO9avr(&gѦY!kGM7MgΧ!'RZE5CN]i=kH@nɺF[x'׸-Hoo /|a\j+%Gk Je}fϯ:s)ka|vkv"-F7o%XS%]cdH<)ǠίI-Lx bwdsEHM ~FC8[Dǚ^E @vPcͿ̓nv&vETN[1$e": 9 ?5sڭضm۶m۶ΎĶm۶m~_Ωz'g=螬굺Gz[{UG"Z2oM馕[f\*͇0_(*A#+LTń,z# si!M+A8g|KPeOOa8UZ*FZ--P# %U!j%G~Y-O`mst(C7kwNܻIQ!I̞oe2a횭6DόKp{#e"^M9LV$gZ)˜J('M±#^B:mr^tIw€P qhA!`[iWbm{Klܾ7>v'As^WcAMv=C}O{nkˀgJ¡2IO .ndǶ |Z`fayr8Z^p$ͱu5bfQxRXWC[x@Xq얪 LHT_4yp#R3Iv4!v#.{vk̈́*Hx|]s q!cG:ޭ/L;jX%3y틄 mKkhI jG )2>E(71%tg#&=!*5hQPXWuNX3^4JЄ_=h~ij+8 'Bѿ !vļsZ w$0׾G$F |ztI}]A&y[q|$Z)uQܳ|&qӔTv5Xqwa.]1JԱP4xئ*ㄜhM.(ŎfֆX} e, Ʃ֐"r+sɺRfU!q:y}Sc[rmQfn^cbnbPÁiPo8"<@_L/NaRbдut@]crb9,M)671$zєmڬ ,b ky[ DNC]I1Jk$=`_iZLTzT VJFNӇ ҖD.;<#O2әe_H1^eԽ0*:-%X{ 'lmEq| eiBx\G;e\1اsWuUzZդIr2n(4'rrLu]Ⱥsm[oy.j @ a |Lxd xԌNXwV`ݶ(<\,~;:̘HhKv"\h;}ȜEٓzWh g%\S CC([0k!DG}Dйal kX s,p3Hd=N҉Qy5U2?ZHEk"6q6[Mb5B*HSؾOY>8̚8[`PYğJGVVYk s{5ڢ1cyCԨqk#Ƒ3eH&Ŀvݕ>g]{'yDZb2Ū8) ^!ўWh-oZ=D^y[,9wВ');LeNj',hUu׉TL<ȸo7G##J:vp64 `՝ĸEkD)jc(&(НtǬ^r J&$jEҝQ uU@OY;ƉՒ-@:%TlV}MF%\rZlኛHjDD>hjy0N0\UlcSF>y3?,?v }w&B-dGmE #!OoAWw#leH>J_#$Ļ )a}吢4FW `c<|<uBq\Y!{%H>OȏƜ?: / y˯ـ)wE$ _%e] T)p/?>gƄb#21Z'QRW>nB,9/1}_ >1=|﷖(kP7,a7e%Z/\sq gאsem}b~X$n"뮭wƷAcv+,eipyM\R%_j$g/0(=/SDIY&/`Rx@AbXs$P]Aѻ~:Ɣ)H7-Q~:(Èzk%L@t|= L"c/`F6%x=OMu3lFǔJy@{'8ߓ{ \bo;-PM,YC4yօз:+(-~5p({gg&s3QUuPrB4Szߍ`r381N]0fav?Alzn!+AqHԘ~>K}zy{$=zi[c~{?[gz~^S''߮ }߮kKvK[W;K Q] t;,Pg&1[ϷݳTcgX RQ;eZ}7~;qg󎼧/ߟ{F/zfp_2r62ɥʓ,,Lj轫X%wl_"#fd Xz F(z0`idVZ8G!VaSgy f!aRUz=v%Hz9> RΖqp`!GʑxU2A5k2D6X]]\aJ:X݁n22'*o(}sw~?JelUCi[,J$msV{AhK}Pao1JU۶+MREee?y<6cW}F<~TBߢ["̧} 8{d)!"ӠcxK[*W HJK!!d6b&hwMc:(]FK`0mH74*8'7"Sd1R*myrU&4^Cc 5Td1nGK&e"^KTbh41=x3qTO:V:)43ôkL ;i9" ۚ),6ai}>>VXӧyB.~?C~Tx¸ё^YL~HB}iqsqL}NN].a g#b~;fT,a^Ј>={ЯD2?Aa 50ɍ$U=ʻl;J|HNk>YBJїG٥D埴EC!Ɇ?Wbع8ж NHpU_GQCʐ@&d)qLJ"pY"X߹lWYA]oD24e7LZTI߿HlU *B"PX\3IlI[Ssp'G}KY,=8zD}UpJ8~J8{1P̄ϣ0wM5_Yuk=|O/,GA.|2Q~j{J^ܦ>`^cUdT=;5}eT\tI+%*LлD`0Sa tJ6@}$ r8.*ؑ8ԛEP#]1Ɣ&r7aP-#^ȲpY1uo4Nu@.U4AEbyeZ 7@09w [r7iq<[UKԀ44OybO֌nLrOsTyFA"59Y/O>wA|~frt %:HlE?$9ڟe(P9:522q _/pG0;]G~|!{{d^dMeTo6\[14PFzxC3[mpKc.Y03/ š)E~/$! ,˩xCa A -t 0PTu4rFW`~*r.>v∯8qV͗/"χw'+VB,hOLг +1UT yb\k52 k5cؤg|1m__uݻL >k; U^AOή)=(Ti;M{YG*/xXj)v)rӒ R}}ڥH} p1Hk0v!C0t9¿aǼ|(E"F`%/8Ѩ&st1.pJ߶+'跰[y\/^k96|Ƌ1͞s+we%i}5\ Y2غjj:%yr[q̣jX݊?܇%~Sg&~G--v@*ыow}O9i!Ə`a֊ cgG$3ܗUQOd+$'fgJ;2A%![)^sB$(M$D+A'ևV*fIT3_qhłDbDYv!kopDA~c24zz 9Ʉ,+(=!bߎ'Vasw@ͦćx#o>l?SOaR,FCB:|7Ǿ!͙Vy]|Hw,4pkٿIҽ1-ͨк "S @{V^Y6 =檿YvĠwjw@ %6Mlo([W^4fybgNETe0*&S)R:KV<6ۺS 9C >י;9Ł PZT@8(6޶F@$>[1piFPvv8FI2'&M $*TD aF' v]֊I]KbU3ޝ vpd)Gbg~v7'ǣ-5ܖC';A#>P"ބ_|V w > Lڰ6fӱ뱦CQ=FPrXt.o0Tvz:FGΈlgu-6L#$;Dv:C<݊3,95mMLJ{ ZNΌZ^Og- Ű3,XĹ"]8/ sA^^T+ jK 9_#>Eom8OqB$`aM k瞯QIB|S4+j7?>1/'1cjR{k)8jev /DnEST9D ]Io0t< )7T`Ij`Zlj9U!*7`c$b^9T!5PF$aPj?f:ȥu9֊XY)H=/ ;%ĥ }~J"W$׉aN$oH,,u@H(8U vO͌,Rr Z<< hՓi7a OU8%,AgUd`|a!$z@x7d#cYXEȗ.Bd:n LpAG-{v"&M!ҘOI̒Y\ + "'??U"]EZ`@G0H jI8  Ɔ+@ʝl,q1_$ ?d-*<>R#6\ŲMts`F@^J c $zWr 9R|=Vbf-cU.Hb3Ň8 MRBndoyRP#t :M Εh@8Xs{n"X2$-@p3s"6F ~sA;ϓJYj<ւ,|.$Tvg~\u ny{[{{Zs~OW ;~?S/wa([{~TaWOnowZfͩkwߜ4 z'6/%=m}ߞ _5Vv^3T5XWD{rHX~?܂9 伈]$v&I|>Cl# b׮IqIjV-$hVc)쫮f%ʶ?7VHmV$L[5qvϤ-Jw=;bAD4$nrq8~1|A}Fd , }^weDksXoHECJvf+x~—93+fd0:OyYܧ]Z0nSK.7̆6x7Sy9W0(0dQ6 f+6dh6CX\ 6:cIyȋ\9@wPYR][s8o3UdF6;eAǺ7F' ZL-D < P!A(IO ^3' :L=H4 $%up$wQ$@+ @G/od\?oYŃ>]&7L|'Yn}pXfևp8VLhUR[@@/D8rD>Dr?iz$^h}04[eR&jyZ87N4ڟt]{ЁJ.k {]"8Upѧ+٩}!Gw=#M=\1&'D 02+瞱 ] jQ xvYJ-Д҅hm=XjjbB>6@AbkyF()Z$lPIfaOgwRJ1MGu[n9k#NjvSj7t zW;h3O,hꌃefw9s"`ubuwro':l'Sg׋/ŹA͵)PI϶sB=V֛*8}99 A=&~&K3`⵫aO*:;`6Suc op|3]N.P' T0o)$@qBbtunϙo|_԰ߩmM({֘!9?U=z"-. \8H b0nĤ^#z%L0vK\ 30ebKDsPCԼmFwDaWkQ?>. =}db 7_ ١WmWD0SP&̙H/2gy*~so*g C0L65]a׈/8oyalXqB<&@/N0oȚ78:$yi2Xon!Vb"XoH&+kKE+b&?o2iU̹O^W:q=;2KNp̈SJnGC@fdͩJڕJ)S7BxGweWz/I&[Pj, M34&1=6Tv-/Mߢg U%ir-UJ)I$PkirKEB 3Ō8ը5d9$k1q?0CO{KvP<V%z0X53̿9cS#{3/2qYYvă5&x.0:/ Q4."A>7r7d9~ҟ Vg.$sg/G H6ΒC͙EXfP2T`zvFCr' Vɲ@fV4r\F2[Y0P>.GXu}G+) ј1G(g[k6lDɤs_խ8HǹJu% d*s(=gaV  )Roޕ^]E^2qM bk\abp㮐9Pi Ce ǰ$G`8DF2H[ ׯQcWkp%gVJM!o Lkۉ) !.8F@+KrJv,A=JԈ'z@D c'57QIbn _ t3˿_~o7G<~wx=_?51=_!yy.4ٟ#'u 9jG^͹ur =CK2{_|iRbiljhu7ɤ0P@>޶P7Ⱥv&).%ǫ![b9B̘>/pαemD{z- c `ɨHmrh|c3=ꇝ=Jw}-ݿ% ac~er[/ED_,;xY.N%1T m$y.A*W &ЈnQS z" wЛ~C}}J$ۚJ&h`'U|gu|?[8~f?yZ8^Qܼ6I᎔A4)8YS꣓rVR%-S3"KW.Mγ EiX!NKS8׳e$wC[,p%D_[SJ8S*AF1-cpp3fX#|PJƍQ 1(p d :K@Yp&)sCQ!,RT0YjM =62ƅ4tW ndM H``4 \xL9i.HƄDu `,dB3?wczh_G%e]|tQHo^,k)S/ f1pOn`C 6`$􁔧s5 E}`q ZcK~g>aYo*۲xZui,uZFS\7sk;‘kj|Tkoa\[U\ wutn<:>vo~?4<z޽}v|_w-v _|~>wDv "/rޣy%x%D,# <5A˺'nu68p%W^Ė)# N|~D2@/DFȌ.m.Vv4s9ʹ i<=z, oH|rJ*n/T3^|42/d\‹AAEdv(3oW.l'E]<A65|mnPuG:٪.rL[NçIlТ=O;{{5 HNeVƢ)}D!׊'%)l+-ۼpF/W+'d:Ƌ/xeI*:)lΦ KYMHOlt!ZhejTTQs.*j]V!3 &@{hҎOQŠ"i<.32))P};WI%q\vBfgCるb&翟Tj^T=4/.UH )H֧\uTy21Nu!դIfgA;FR S9iہɘ\P}+xbV2k]WK_66es@/7 ϭStav,~XJuLufX%D6A=̧!6@JƘIð9HslS&[2WڣWSϲtB>"~p=Uކ&ZU{E25+5JOBULǒ\*#5x̘m)2W&}Q޸@#bdWM[,>#n=M*1uض+v.̞\b37bGakZXRNS1ZzܯPQFK\dkkDNQ~+5 sG 9}Q%ESmT|Lm{AR[u}V܋n9Q"GC4,߆qYm8Ȓ%-_ҸL M7V9$!h 4p #WKѩ>SU`Y]=#pf>H;1;~!bK_ ĿXlQ;$'-S$ >B8OW4 yִT8P:kh C25PKtK@t]y(4!ɞf1!D]tH-6HoC.ī\]PݩOd+R="Fwʲ K3?r;דu-"2M=8&k]1X.F3 cDTnC]ؔaRk@SR1ARNy7 ν9* (6-8Go&1JRٞ]aN>Erix8>n4evUbzU6L qP%ɾ,wq"3mpI! Lh?>9͢=kk] ~^ ʼnT[!G(_cQzMn}'G,XM۳<1G촿` MnVLHSn=^y4ָvh9=^azWoX(QíGF0uXT>5-ja]x;bYZpTVpuO̸dC bx>zܻ6* qsrʪd1VXCy \l$S7=`C@`s@2yfঔ"ƺ> WE:'kXC箸2WθcL=wg&8[R":SdZ+_| Rmн?ýl'xTشc> >rnխS183v> uRl QRW/:5 kSdLF*8KX-@ 4z:XOrӖN>" jBM7mkH7iH=] AlU (G.Nޗ_j"FvUW9&Mq 1sI'Rb"7A0%O7H*eZ+^Rn-"$9ir2.1I BwupprHc[uTmc׳ئ:ǕRmLEͲS O An B1gz?gO_XyxdlSozDB@B@BkĆ[Й mS/΃T@Xm7c )51~*I0[gcCXO?VQw! ~\siA !F{ \dFx]Lf' gWt`{^ֺ![&M o$c?4-Dz*qo(/*BDtW.|t 1!K[F"Gxk'hL*"Nګ;ْ F ?۽J0ѯıf[;^#ѿk̲y#`.\ˌnTFw aiz7oQe5=_/X9ÅnSv#Hf2,;a2Z";RdcQpn%*DEm|4yC씜Җp䓣2{Z>A"E.$[)Pϸu46C6+o$`KU0cMoa92x8֩#m!0t̮h*t{6O8Snh]gU|*Fu: }B*g/-AΪ3|&IHuV ǵ_Mr r<ܰʂ2/5.0E2wƦo Myhw>E/Rw ?_9WEp"tn&ɦw87 MfC#_~<̫+^w;h 1'cf/ ~|8?rS/ ?/K;? s.̥G8Sz}w~?^-]9I~{Sy`q`\81hc up!a|DM?wm\wP8~iK'ĕc4и :w$6<|vxL,ZX$eaAE a? .8V %.PqFLi1Oϡ '9CkoEwuȖDds#? :=5 e+p#Uma2Y$)FZUsVNARnŊFF$m%jg~\/0Ы98;퇭s;pkAu6۷M i6"0- tls!o@zVX%YIlGI34YB҃p\:}뗆5(rOw :_R[cFAidd!BFpɽt署N}1idU019QNG*$ sH' rq{"nīp52bQ$1((H[U-φBOK*2%Ql,}O+2TTܾLbU✌.k^.,4*!I]DR58RD4;ĂQU)ܙ-ܹ/qtmxHZj]23OPKTW_oߏO?4=GHhA{9~HkZ 4K6Y,e$7)Iuf=OðQ9%׌FZ-OvivN \?{>]-S?ɧaǍY-v;`"wfi+"d]`COsJyP`U,HMCT:5[Np W7!=7{96;ĭTP=5nVt:]% ~kϑ1IE`-Ug %ߐA#OgG f\ӥ !T9<2ـYDSm(u2+I`r><}qQV~O"u }TAh&-3;nS":eTatGu| l=IiwY8eҦkze0#lSԚ֕Qn`P,P\ؒ)JElE)Uml^ RzCwQ]}Ӣqn99 2c:ӔBi%aRND(E7$#ͿGxs~a_kvIs t:tWǵT_úA4K|">j~.mpoB^Fcf[aq)}嫐`R5zw,}Uzo/]]j":AZqsV4ZWe!*_"2qp+",\}&<tB"Z͐N B?@7b*%ЋExS~ H$bi n!0@Va3O=Jƿ`P|Q\lԥ /+ x-Am<Ȃ"h]1lP3ްhߐ>o5^_Y} tbYl. ,3%YW֡ ݸ˓z.,kjN/! S tSMu47m= qw-D F$2x;1U & NDPB!$S}3& p Fy1fUTq(@ h*Ll3Μz1:K55.6XS> zka}DnFj[WHT"d6F-]wsh*:|' T=><'jF,F5`?1=h^d~ txGO#!EJpud oDTԱs;"J_.yڬLԩ1E',);wDB 3rED8D3pYR8lH2.q{Eti<+-K*!e?F6ڷj} <{L0EEX/MEd$K 9cg<#v6e ƃFǃH:kt8d{.&Z~JwD\, d`5O81FՕZ/ä{$oX+߅X\Ҝ5Ay; PH>r}ұ܉O:yڙk#i/7zMDv@m, A}<S܈{ՠN߮+ׅu7~quX٤Xr9@o?y+fb/Gڗe3Mv.ʸVpuZ\  C4ZݰC¹m%lUFwfy?+@78\L t=h ٣B&޴;Km & ˘w0vh ,`PT8!W v&XX:y xž]ϯ{Qӵk냖/pOɽ\KG=44k)+S_KA/kw-0v0*"eG?:WN2j(N-D,Ts825j^cXKFJQ|*;]0Vk,w,N; @R^b) Yc*g?;&9T#Qsc:=VNY{hXМ. v |eW@x*M/Q"Ξך=+ ^A0,**b4G'wT}_"?oR*8G%0&%jVڪ )mֆ sNn. 2֝Ԉc6c#R@ؾT|sC2lYPpK^`WNFN=*$H0ȭQ-(e 4䃋ul.F ._k,` vf~s:4LPayPxPHs:,MĞ!0;a$LAwQ+쀄l,!3DW2L;&0qx_M3+zic(F{.ޙi1ߛu1tsY2{&<%S\[-Ii,Rڡ)fXVuEИ& v *P~C$7Mvj3ᭁF$F%߀Ĥ _ϼ}xc(WKLua]YFo<ku P )Y6z2=¤H)o +7oًp0}rCl7m+XVo1!̓Ʊ5;(N^'mHJ^`,ޡp WWXJ[[c$ӕf fCX8DgS Ҹxlxy=Z,LXqɺAJ{U6 )^C+* YK\lRN oR +5h,lLkr E['/x:$ ;M-J%-eD-urR ".C7q?㗀 5hSޟumhNB; "353y kh||vڼZЫB]7 Wz[ V jeqA6V3{^mt(O$wz×I<}B5կPx58O{keC80C0a+T@5ePh8 YR%NsֵadO/Ky")+;9v)Uº&+Tf2ы9θj_\VӊXɧ,V;s_h$xĄʖ1TrRMU`WrkM!Kc0ޮڀ f)NUh:M c<BZm2VCOE0x@|eQڨC[^E@]aȾK$WV*K?ҭƪ5X>60@;nE0׏3JݦV^gDЅ-c.{́x BLm|x%7چ\0VOB|z gu9:T+En-VtY8ɹ f(3PHi}? hj쑡P_ @֞ZAٯ%/c6:Uޤ$>Uə2GR}P_(}m\QX̈́-uw2q-*5@ЯÌ}{m."Op ,#Ðz %NpGt£Żƚa14Oz8Sa~(<&/C5Tw9HaVV }u"g%r޿5Մu ,)_BʛV`g$=_CsKP=W;2g4tͥ'oB[IW%Ɋ59+ p?T 47/ɢ> LRv;\-홴r\~=xqQmɄ!] e\H}WhY8 Fڟ^/“vr)Vk@/R5 Fėw /,sfvN.]$+ dDa+Zbr>]t΂WbZ (Fn-q.q ]|þʑ/хʐU8+Qw'en&M%昤nT80TVw1.I.V7#8c-Azܼ1&9Yeyj\ ҏhJEtйH?I0CCZ-7m@WU. CI#cF&4C}NL2녓5 F ݥf.ObN}pH+K?d-t[*b.!bخicU\gY5Lcȋʁ Pb&+=^!W˘Au!Vy01WHz\Vb0'%7}RM<ރ"WZ0[a^;w\W(\.JNzQWaSAS_''f1yN]%n&cz>=Tq\#Hw"Yg|7QuX^?Ƿ&:ȧ@b8@^(u~7 ]QX0:;;+JNf/" G ՎyީǫKzBwzaSQX.E0ڰ O筐P(kP(YX:(XnYu%b0/A\)Խgbe7b֫!A}w7Ou=IΕҭXQNĻC$kni\V\;weJW; };]zyDH6dArA8y_j֓34=q[,@cmʕyN [ ?DPfx3a ̮w(Jw A8zjGF"RЭ* /^ .ed}!x`>u0Z>v]'kYʇ' r%GeC*AMPgQ>e=bG{JW 0-*@&8qs4tLmoŚK&t pN] (PԲoAu^7d/=w+%LC$z7cTEGK,xOMy ͚M]~u1 ov+RLf|? /_C(9gWz+9;"d:gzA<|6UHdTlL3޴U+m}orf} v_v};<^Fܯۺ?{?Oly<<os?v^P?"\D6)?uէ$2;Q<~6#EpmLgd~"690%_ 2|6lEa-^?J0;h{;RI$-o !aUH"\ȲlIʄO{ $I6UK~YW[I(߹Ȓ^=ObWY#%(sq%/Hb |AV9^$gE`fPbd(SgVK'L>tVyifS'(ہbJ9eA4ӥ~5` 3a %eP%ΠRj6KE8=ˋkԯcy} j,zՏiefli*UzR,f& pu>7v6åFY3s슠rrMyFpmR:鎜~/eҮsOެ;9s=CAK1sKf3=]6T| yk62t/&Q4ܧcDU,=vN*ڥ6q!„ 6"rs>^peQJ!#Cxl9ɨ 63dzWtqJ,kPD>[A*-駃'7,hpږ3 YpCUea_U'z: JWQ1hf/wxd?@`a iS'ͽ޷Hl[]nN3φ~V}Lw~ ~N`3 '|lo*N ^k">.?s.o3%+C1]T˵Bv _(-.DP VPy*KkNB :k I;.5ݥVn1OQM @-Me; a.<&hb'Z{0G-~Nb >?ԲڞY/ (9GFCRԯ0m~)Nw.=|K5JHdذ1㥏S0_͹k2Y܈,n\j,t><ށE7j u ;'%>ӗPnKݳ̹t#׷'4B-]fDE*p0_,4 ɮ sT":#G$lyc^-9ٞ0Y0CLgO{M [UAO q5odb7CtH/%]ϙʆ=ydYn.45p^ .GY/PCjz"%Vc gک(!Zsn񉠌&Gtg#UJq˞ A&қ(CcnG%SŖ1oZl ֡q ss/N+}w$yN[@#+qSҍJz3ZͅP9ƹMuI5vBEWWFC 8)u7r,GgȔꆙkN^u/~rAa橘8>Syף l t)L}"իAif|(UMNuv_5:{Jes[Gͯ*B8_&w"+gWkpt_{vDeH;ٛ u %kcvj{=֞YXd HR'~Y?5Jgx{ (MUK-9`9L~r*2"nd@Ά"/.=l@xp6<d!ֵ *\5tCvbC6~P )FDm%&@Esb敻l„5 Dc]ZAk=7ȣ-^GiD]D&torտڝ8|\6GjrjJ>Gy?2B][94xӱYl;3nHM~Wְo,W() /OÆl)?bEyGӊ(s/sg2%hB{q'`&EnaDWȲL*a|jy;;3k$,L<(4%ە[QH:h wjj.W.6 _տ+r;M3R:qaݶm۶m۶m۶m۶m۶]Dʓρ4j`wD~={dzQ# bC>ѨTT/LǫոEQWc =~ξXpHgu |ڭGul?bawx\=_6Ċ$_`QV,wֹw'F3MgNtjJ؟f W>89C]xB@x\˧DoÅ16e$]-UǺI yj?+jW5ng^쪳^{•$It;-dQy2%kle#%oKḥDnTۻrnʟ_ՠW\T?&ңje7+`#Ky9+hC2P_VC\#?;DIsH9o/UOu-}@+q",؏LL<8褺D'3VM/SjuMPGujPկ&]`nT OX<8jKK噀f։U?I8X_7KYBa գ* SPnq `>Onav{+:E,"덟&o :g:4/TKd7tt;-6W顿59o$?:9}E&UU{:LGEa8y%GGĚs0Y>NYA}OQi-W<;>wp1S3RY /*On7#$NU+w o:^":2\n]7n^&%"__kz[g rNZcJ( -fyȼ783FށTl(iyHa|*O~KNJ؝xmW,>/ԺpIgbTb evhO iM镈y!,*`Zloyzȃ^i]v$].4pUHuQ:UZ|d=P~Q8M s񛍞9}Ⱦ]㜚K::Jn\a*7. vtLgw[;O6jzoK(n+i\, ;U$vr?9Ctш QcďFfYC7>5,NZW-t_*l ;[ \4N⯏*;CztMR{QxZ6q ( ZaeguõD%*t YΣaY,QsSʜ=V@HHgvF.}"A{h "?QOnЍcI [Gr@UXdstǘ-9'kr=uLؑ nh84!.7>Tm\Gc5X(rg۾OI9s=9^8)_{Uv>ZG&{K͠ :8ڭYzbݭ6sz07w{ya@K rc_h t1h|܌^}p~_DWnwgΥ3f2~<;YG IO3&*Kk.|Ufxy9?DBף'#x=l`R{{; ' ~" cMi ҡjmy FnދS۠,;&S3 9?g0'֨|=`VzKV(U1@S|z4=5[T XD gMvEcbTɡHǢ >.㠐QՐ&>`q5%X7nua|5舃@ɝd-8K1ɭZuKY&] v"_x9]c}sYxKpWprϳMV\0~hBd-8 [I/D,n٢|UT oL';cã!z\'IKcUʠ6R#&0kpc}+! R7K NwH)gcf iL7w\y+5O m0|a[ q})B5F˂uX~/Ik6<vb)8vKmB^DOB>?zbՖ.F(HCۣHG^6~=vC<2d.Lb %2H;Q) VIMR@Z,~ACx!ԇ 6Bs%sT f2j &aEq,@!BnkCޘꖤ&Qd7+VNq0ࡉm`Sܣ+ !n+, RP7!.']% ss(6ÑR^@\YDւ5VA5[ ؆Pw#Cd0H=bZŐ!HOSG °M-V6dd d{\ћ^ic;ƀ my1 5Qo6geAubS6S6)X6 0:^X#!e3$bDA˧kL@Fx H(HiJҺ* N{Ai TnJ@d?`Cf,!B1RI99D6>k5 m%'B'z 0̎qVf5&*xr WnRї-FT+)ώJJmW$F9RRo".v*12#ƬEU`aY7gE:h b4eV.Wnp\^[nz)k m51%օb- ů4'#~=&g&F/ߣrSA"pǬH&Y@`JJk;~Ģ$oHy4lQwAS SzM<.Ή=/6gEV̞~Mcdk*VB`#c RO'|DD2W)lH/iG[|l*#duJ|*]4,#MŌ#eUvHMt0kh6A{|*<R=\GL+U'02]9-"0::-a Jc?+AӡBD%'Ƥl-$&o!7bt5c~IÄ7qlXvAHb*ty<4-G"EYlQۈDDS6't6u^P&|X=e@b{El9L͒ mq"{znt{m# :xVFZ[-3ػSb/yCo;Dr\{gb+ c`AEv0!$"_B7BU`qr| eQ)" UXxƞC"QCF.0]X]Z8X5A/~lmF`E牅RpoX~To0)tR+"370AQ(d-aU(&vYb;Z]B2w L|=i6bEHtd^] FL/'I4$=/8=aI[䈴onqsy}lj#<BH{)E$"HكX$.=ۜU,;M^wogcd_ խie?kJ (0>gj?!,Meiv%<9$i|ufjǞ{u}v oASY֍̼};޾狜>N o.<>^q#_ZoqO* oAp5tm)d52D6,qHY0dҝRLSC41'^]|w&mgsQc%B MRUٵ*Q1f>9^<6kgOUdkQe.AS'ל\5mA躠J2|/и|[{'V '>ڔ:NUG>V ;Ws+!ߝ:OM;oG3C/;E]#.@$b:ǃax$luO sEd,}s3!I0uX4i%l07uJ?3:x}YD~|cuZ3&j9# vE.y4_^jQŁxRR=2H{Hgxל.HS^j8'nnPsHrǾ'pn~(.W>ݹب0@CDAejUJ,\\`n,i{V]bӓm^S0֑[p~܉[#^ |,q']w<-ӨWxv{Ф:AK|YlːAyo>y~,q>!a03p7ba<=Ӝp#ٷP2Cp!C|YTl*h%im7V H1sلbFD؇\%-Ch5љon~"͢O˺6|$F3x0嵠K~x1_8:s-\͊R}{^qT CmLt=-施*S8sR&PJUUf9woa@|iQ3?I[)?/d5|WtG%X(=vgtEtﲚ{cɄ.쭱I27 'uo%[Ұ'cw;9M-jT PAFR7G;Sj9f-!!DWWqNFFf%΅tȕ#5l kv5PzÅ4gf֪4Ds/(䤦yhr֢mxG#ebV ⽋UMSy(IxPП57w݈: 14?%_?FJaPW<23J.69gd1"Q-EAp*@~.A֮u:pZf5Gp f@nj-Jː@yGڍkƸ_:8?#5:UGU@U߸ acϭ<9}=9s+cϳ,⯎Cpg7)Zj`fGAQ3܆g/RN/P&ۨrT͑P.ۑۅxA3#㟒:%L? ҾvplŚz ͱU$PϩToܾBJ{Nsr!Ӗs/=[*=^a̅7GU[W#uRl0+8}>@h n(~whPʇImJeg[7 i|h)nzC$uպCWkJ`ķQbn.NP5L?[d&t,%| R=;G:7v6F{3Pm'>g+8wu|q"R|C!]*(l5XϵAǘ>~Mz@ a`[mn~Fϋ1l} 06RsSmۨԳ}k.޿ǷԺwvFe_)NmֿWWEނmj9DԺ3Ws/8R+&7 I47!߱_YM)W—jKXگn}pHִsa60"uF 4-N9v#0}*Ľ.lUݗ+]4TVn?U⵫;R>wѮIdl\0æ^)la賙]_K`Gʷ & V*_ \s#)MgNNƕyZ4. 9ЌM(Jc$e]ff24z`Sh~RC\]EQޚJ!)4cjF1u2x}(͹P.DH| ,ħXh t 6W)iT06ӮGn2XE8m0ђ7ae)+rB*{%JC_tiUР_Z G~V=/˧D .<2ibmAAl5AmMme\y\&WV)i FuORjK\p*Z"^UF Y)c)yP`X UhJdڈ)ghTCcX:#w@^A ϯ?N[Z*-b7q{Kwi.ip0!eP1̮Jk,ؿt+0: @k02mB2RhLB1ˁ,kXy F2He68i'!6FdP >nt=d{R Y"3I&ZXZJ`B5zKC]ubDe^l4ևNsCA8$Dp%#4{ֽFKM82e 6=аp&Bl͐ '[BL+P#M~5l lr nň$c]^^h׉֝sS$ѯLN` /W(an}5GӒZZ]+ ,x|ŠYS\HqA M%$tߴh &Pp.NE IA8N.Օ! epwAL8(?57mT]"ÔXѶ_~:GT"MR r8CHi᧩< ʦAYJ/WCm8mWvXgk9̖^ |`YBL Tf׶}Cl>Ѓrɜ1ɤ! .! lAqćRMTø`a!QF0M;:|DHNgeY>!4:؜Ҧ hLajjD'er#h9Q;UxCV$h<1Ys\XWp_k' g` QWg(yɸ8DJA1{[ , "bF8e*V/sĴhtZea5툨lŒ =X<./-ZJ#er?p\H}\H 6ft2|:OlP- fHBZ&(uh2 ~6[aBt"~UjlE`αсs-8-A11aсe" ;b\z(؃CcfAۼfd-FV|(oHc)?&]'r(1#83-h.>@cm~mGR#HҲRBXjT"6B9e=TJˍh;bBZ6NU),Y74tkڢBsUUqd*7!I(YW߭g*'OYwNg)b,HKӯ8Uljզ@3ӯ$ ZjY__QYкS pѲHW6ҹJ6 謟qF8s{{YE8=`#lP2V'2#;orHjYDἔG ߥ*hvۄbz;nrײ:+*5 R@`szor([lH&Kr]ev;atj3df*ΡvN4,&+3pEK8ޮGCe Ԧ7(BDK%K2 Q 6@HJ!HvHQn%nM`7pYYA( t*Qm]y$X7iI!*/!ү6|)@$^ .թHY"1Xg)ϴQq~J /itbvaJ ZtxIQMwt:jӲL"i뮌eGWd^17bX14Q01yGF9z{¿oNWY._l[!q&D~ "=x|\~/W*ZO^]]W+XnnޭRYss]?.? nr~agwc|}n/q=xa0__[r&?j & cϹ;;9k~g2[9} Ut.k)N)iꙔLo !l0趣S, \J2MeBZӽ;n]IsYzGf9;lʏBD8ڊ x"B3Jb)x&c*ǢK#u3 ϡ@=Y)*(^<7F©%7CA]2JM)A fq+RZY!ҔN+Y*(^)Ky1\M{ |,J^;)u7v3e*sBׇf!l)Z{s( X @t#!ҝSh{#Dž%9KgլI-^b4hL.픶솖]H5P"Ll0%fk xBֿj|IǽlfŤR: Std#dz@ҊEXط9(50`NaǰI'!8F0C)O*9M/m;a܎8xnk׮`mkhB44J=V*$jf3^i}Tze=caXE kVFP2O9F+\?bOҖt]Ưc|_ZXIJ8l+ܮ/@ܸ*>$L}Gw&moXlZh<0w֙hO =.acϡ3sQm1 /?y~Y4K?.=oL t="12="!󁝙0Fٛ S$hbYq.~@R]w &/[~UyXvʉ^Eƾ"P}80so{ZzQ,;(I ڿXc.>=ž;CNJ! j>́'=rH&|޷t&XxGj{Ċ!Iw"i2e[zǒM G6!u$tg^uUe |g5\ſ:ayy ;u{! >d< 4R^sAu~;vޙӫ7E(#,W]Dž4_1b}l_6^k+gݯW8A? ƫ&fDw91o1ūh fqW1z\ ٭CJ- r&6C(~ l8D]퐪gr>w?evq$`@G[ȕzi(]>lU>9S"(IM9أ Q8<+`1!CVow*R!~v<  ՏƊL^S~b525WFw<fkQwR/D%rVw׾opDH ЫG~IπB|X.#;Cx#ihzz~3Ҷdݿguf)K||gi<#ȟ|:_cvBg㣪sN^O:Qlq1T{x{j_f1$G?םIS 3nVE6U':9reI{@1)e{-Gi+#W/eq ٫սRU&`uk >^I2HE <,roo%wnQagOdTH>W[Id @/Vqݹ/؞gܞ]ѣ{ ,[,P-W&y`!RyZrߒ{dzԄZUI>yWwnvbF<" IT3͞(TdD\n#@MEEOe͏3Z1i6%50"qEZ\x}T 5, UR ֶ_Ջgr~$~P@!f+#ռדa D^8EXF:d.H+rZefbۙNGȧG#O:;99ڴ7Y5:`ܲXt^0mY[[,\LI6.O ,0 /T WD~l.8XA3=Y$D7b[7^(pCe$$3K'tõhk|!i+ YlZ NQc{1 Cg[ U$~1ܹVT8zFBSSeEai(S$ ΂To&,FGʘm'qU7_13Y`S.T$d ]1 #vb>ۄSfjT2< *îC(1&`9pW &jFX;n>3'ǀ#4#I(vKpǹq&qDEaAAJSxؒΦFHH37I3jP|rH, )qz I6QCcgrٍ[-֣mM,՝uVVdf Rn﨡xVIYda(,H9쟗zTԧH#p$e\< y4үew#ST3BˢQ&7~9n%'*ZȫSr:Yvi LG7ئlOH<1;?>!LSk[`r\ $nRX7pa쩺/_;'Abl pvGN"Jd w%*=uߧPY386!+:ϛ3C, ;@2?`JBGg8XmX$AB%bE=A##(EeafB T)bs\aF۹)dêefu70 ӇԣSd?OIe;0\iogz[vÎD@aiܑxB'raYN6AvIݧ_CR$r߁.I`SKVԏuJѓ(Tps7 P[[+QE(Y>j-TA*@FnM2bDl L[ YuuLD`J`+C,T:hLRQ %Ⱦ粴ڟo)`O 4X{Gx8=K8U= ί2l|$@`^"J@u:-\VW/Gb8M5cYRXb{ۺ$ShR:zSS~9MZTmWZaJN s:*+x_:UQ ,_# U8ˆ+); jGlVL=Hpz2*ן^s׎9IE{nMj|' G-I*P&fp~¢uYqN{.GR]Luj; O5)7~ 29\۬) /1~L*:./M4&%Z Ls-L0 HJ:!_0aA>ĕ/Ɋ Gb/RKqbUӥ*m*@ͨNF:v]Em(8UѤ_(Jfbrx{;Y\w?Li툽!zu/=k֪ۍB('C!iK=7S9HSWP"׍'Ʒ+WrXU.08Z*O<~dE%#4dE_ww_wTdf|6X9[o"yԯceJ>jJE] ݦPa9JK=H]a9Vե~ zWd9sG4#V\R +PqrN@im۶m۶m;'ΉmضmtLMuOsw]k])L:#1agv ,5#5NM8%QQѽB˝eW@!oS*vD}́vvd B D B~W{ൡ!C5֒Cfk/̡DVir@F غ|ɠH-NMuMFv^7_(){e {-fƆR.OMS,"sY7MQK&c<;rϚfm .(<+Ç*]P>b|Y BeT;%M:AP 0_^oKOO8,Iʼn?Y.wgu_׳k-pPFxpC26 a4>y a7N`kpC%+LeyQZwwK4dH.ˠ

[PAs R0Fd &n 5OJ' ?WyQIV%D>N5puK /VjRl\k`?s..{ŰcvM/f$X R@+*ۯW[V;Y.?8~KmXm|σ }竝 *p߹|`[V /NP1gdoj~3F9:Y 0h ?PbƩZ~L7<{ 3[V8Cz}⺦OZ27_q"se?Sbov.[s:@1Ⱦhyj @e!b(ĸTIM+: /G&G{p m]_f=sMF}^2?NjT~hNZx'kz6NuiICL*Gr'G='oσ3ӗfVOl6\sn nW27g‹OZf~kƙfEv[0, ~w/4a5?[ X_5fDff6G\Hcƾ5pd_HkkW3+2W7f.AuiRez>no{I& 4~iY:ܦ4&4ThEy|Y?7X1_~,fr:ѻT-ԝPc;G1=K"_ƤP#',֋eg5"8~Hha{pJfkZ.7D QDy8Q< . 9-YhVCzQ4E9b:lom)z§[tmnY1ÊGxB?"MWy|t7SY,ٯf4OUHFW O7MEYo(֛. dښ2eaz~F&d3`7 >4Fq/z% K Gf_AJoŠ4(b-,S{ĥ *a*y[`nW:}e>&\q"qC%7ᵏcPA kM - Bn'b>h+‰@z96i]d9M+v(} ]h1gz_X'Xq&-X% :1:d"c}^5囲2jtn1(x積surhbag.vBlڼ牒ehu_#eb8(5:']x~A`)CIM5LlZ !)^ˈxAF /DBPL}bdU@ o.g#hQPg])3ȳ?Vywpf'"GFT3r YeP<AaHwP |AH1.CLnIp ;c|QQZReMaY櫠B(]dRkj_;5=PU?Ӌ`cplkoJï|Yۦ;NNl{7J܈eNDDVYyLetSŽ/G麲`S#Hyo |=z;[7 #;oGҀQcՋ?'].5 M|mHH5E ЩpyoCṳЅ0EmdA5N^^xTwVn?#mfD>E0IKXx̮ r*#D[26۝z/ax>#@IM>GmR-U(='Tl*" k'؏ mRqާOT:c0to8Lu_[sT skh#ҽYE񟚣wE<>IvV:(K3 l Ԗ;߶{Xۖqϋpل< sE4vQk4jKڷXFtV +^fd>y0 WRL3Y;u_Iq? 'SٗA4婎*j=@O< iEBKWߐ$[oA՜.'R53!D}Dhoy jt1΀Z̺ k\ gdfwy*W7iw6*evpG=+;qeۇ3]3Zmy\Ic;pT^B;UK!ygA1{ F>;\}n 6:Ofʋ;hYC"YR}ze}XPE.އS\L;;ϧ:;d0R >5A`8wHG[2_zvV$   H˱$n,Xud{`Z[#םb(kU.+$hxBk["IM pyAE5+ M4Z */Ap[ED*F~%z|].1dƉZ3&&l_9$l;/~tJBI;{UFK 4P׳eNoUΨR 3 Ձf&uTK>{;(L~L6= +VO9J,"T@P|!EJ$HWH"IsNI0#8wtBuY4+-7]q@+DdA7Z &D__ԝ)\?T @{,oZ K;ɹjYb]D3RߺNJAIw;_mua>q^W'^Np& ZB%tޑwjaQsRVV]c_;j*`*KNjiG2)-`m$R \) PI)oiCU ֆWV80iݩ4 /2.4l2\ yf6 >3% hݫ<V\|.0f !D} sa?z DyʮO"Av'DHVdEIQx8)8kH%-睕SĺY=L"ښrY7XlSZ¸aiCZHњyF+ZV>/z zz;5BODjp\?}8X-&U9J|.= pI00jB p5H(*g,+OHᯪ2JD?u><-:*`^ :S@̸ݰPyc7FeE$jMj',$P~so UҐ]e( 7u&ҨȋsU_icEF-h,|P :[3MI,nKٙ-? f%Q;L~U?U CUUCY=bt(fwdĘ,V}X>#w6B(`Mh#zVZݎ8vb% dF[B$߁UzT4h#g_WYf_(hY1˕ʚtٴa3"&lw}˜&]R2)q7~NC,,4`CR"V5cvr?H6PO^L;[S,vZvA§E<}cٗ0#@O6Z웕:&ܖ>se~x7wghc6wj8CQ:r;L] 4B(h96i?.Hdo|99*83NjۥDF 7^wƵxѥ3vR]ݸpGIHHW;ʔʡZG 6D[<]q]\ m!2~8 trUBR] `_dCIXBrX:g92r8iqFЍ[sۺ8edT!Z`*HZA'5ɉX:C`Az3?WܲtKŨ[vLi]G(K9>0'is+PV> 8{ j=Iu:1?2 CN[pp iJo1^&in8JE%uKH,.jDеU&RtJ&ҁ&!É##ȭП8Qz fBo=Ɨ s OGtbz2͜^vrny]qU+eFۿw1G;l,_8o6qG!ٛHf<75q~2MA~Sx"btGN3+%K) 3q=֣?,uG =~+&q2zu%߀F}!m&+l`n Y6Iw+em^j@5gُЂI$&/9ŨBd@. jL-z Zmƒ$GqߐͭAk%Jz#z! &`oһÉȯ%l@RNmJ)P`K4,ARlok/RwO_=C0ӱ LWm,-Az85O6ŪU1DhvU\ hy舵-{ g^7X1ry Ltq\<97K#ZՆ\^\9u\(9۝epO7)#Jn^D 芜73AQ0fWC n|5k;1WҀ"fGDkሜ?5/e'6+޵3Zz΍sF3zlEW<OBLf= >Eo̙fO{3]P/SA;~n:VlQ_?aEw$78_B*W>{~1PπNBjs|Cڎ7e# ;^Fhν%D֜Թ^js X ٧Xz$eT\Ia0`_5e_O;`TЕ"ϯ eSP( '5ֽV8nVw" F& ^sV-g+3sFLuH+ٜ }+*MQCHKru OFW/B$8-ϟ(M 7\'ăHt7N~biXTbZ# oBQ>Ո#ۂZHPS_#x3n!>( ĺ34 G93Vi}9~'lXPđck :r+"kuBmsXP7v&8NBgk?% 5.o=6ΑW2-%&]t~63n.x6Ґ(?tU ,(f(4|CN^\0O p{zP=ĐGN=0QRɜ$<1s%9b`i羜 \TۺdZ^Y-\:b=#E|цuTڸS.s)eQiz1-6=|X<3#$/о\7ϖ\Z{\p~-U%Z%8|EX7n329c swd~; 2zT.GO]-Bu|ә|iuY eUS.FoY s_=7\eAIA~6g1\XtOo "C]2u.<-4I\8ll_,{2v515V9Vr)×(ݣSֻ1.q58Vӎ/\ :{Um.ETcE®7󹀖;(>@$B4z6޷3ˊֽ7eǛ:Fw wՌ{ Py<'=>I-g98 $Qa ЇGw^DoŇRH&2/DrIei_'[!4IE]ZIY,SwZ#˥?N(mMPX]l-Gk.!a'"gjcT]|9DwM|!~|i9I3ǻ ^%ݘ%Qv4^#HEqPyx=pajw! (<.; \Y/j#LYCT7~)xg=S0BV>4+pnuwV`nQ2C\R^{WSnx*zw?/_m槹NW) ;ր dt0G3!%51HrQ1JxflN_l7, (ry`sG 3Ssj*5lS o"6v2+114Ŋ涰1SoS'NJ_< !\㧏ߐ}y^BE՗50;T8^fFT00>Z eoRÛ`FXܧS2)7E,Ez"VVe51f[W߭NrPrx46lH/{+5^,23d^B=w r5u }7Ш]xysI5\f$c(V1;IbL'פ8za!3bwrQ8?6?)ƄZ9!u`V]XETo2 TALR`O_ 5-JIL-qq.DJz0P\lQ/}x zy2بPtt 1TQ:YA$4M-DH0ıaU)Grh P\+8g@熞6rCÙ[Sׇ.W5E*Ÿ M!Y>!^w݃h0XRL}c$| 4OfsVTOHցѪ`nQn¯Tu8~pɿfd_PG9)D<aif\OT09W /⋥ OBl*H|P'眄q g)Ok Ӗ&b.S*0FkpHg9|6%x~6fmlx6o+`(lý߱𣡢/%D٬F.CA61G:Ohp3!wR\ɰ')*GxQI_P ;&DYٿ91M@E8zVJ< >ufW# ]K\`Hv 8m/2{K[N=>Ȋfƞ TQy^h8`ڝMEmKf!AN"XN6 et# X 5^׾->\i{bsXg0Z8ʟJʼnYJyAz}50UVkKf!r7XݿWA+N5,5}UˏM!+pPMd(ljy%8Jҍ+יIwv)^J^kѽdSR“I ߙѽ]r;(xz<{#%㯴_f-xC~E}I3uq*[?KrqxpHex@ug7ߐ^C[k%S z@:is)*?ÉY(q(9U,ANϓ8j=d7cL !sC>w}-Oqbnʁk_:~3>;@p Aڣ*Zۡ4%p34:I0ξOtN^|]5^w:rE-xF7uƧ(&Z <4 yj35Ogf>7.uy9RC=3\HFqt}K|b Y%I>s(va-fÛqSđ5eiK}Dl vgj.(P7 mlsD]_U.v;Epz&wСPXTf僫, t牱u6Q.$ЌFU&0H\2I(7439S’#rlEiֹz==a=o7QtR o4)>K~hyb38JbK2}ɬcuR힠4]FZ)wjEant?a''aħ7c1/Ȳ?uC4-hYI16D%{FcV#uf`ԃآ!pu ՏR%S!CF"HSJ2z_Bn s1Ef =!>|>)O4/j TA+RL(B0f0Q&~z؞LIˁi3t}o<4A%듇%tc_s$(ZJ+M8QHj0̚&| ̍ C)^Gvl YXno]ڜ ɢJYI nnhp̘VGgk_ @خ Ȏ.AeT7KY[ zVA-'hZWi;-Kl=P"힚ttQm۶m۶msmwvm۶mq"fv̾8WuQތ'%h͵z#lڒ%w/5h3U&派J4|qfrN$5bGU8.uGYI',Rjl?Ƃ6n4U?p4YzV>IDҀAf';H}x(ZhJQp&pSqu,B_ pCnqS:ׄ;ŜX4rfb]Ru2b>Yz] 5O Ȃ2ecGҥ2k6l0 t+f RY61L:l]~m}3;ac#P`|v$$SH!w!fu)*3=" { IBxz:kGJZ@@:j"] O07hJ:}6v9)~?xP1L}>CwC'c^ h R? C_io{ם R&C*tC$|,Б2RM|ֽD=11tm6'ud -Bh|M%ȇXZ oʃb)3)ܔ$Qad`eCgN?jc#lIGxq"}46gDHكPn_3qUdK=Vj1D H9m&7t̰o8goq>u[Jt.U} `D?M;gRmFJ fܹ>׳ńxm"YIYģM٘U/ڭz]ܦ[;x8Myiynaj?ϫ}GkWOѭ~ץ[k7V])'ϫA`")-C7}E URNo=>q1?("(W'Kjo)׿pZ!rivh0Y\mo[?˔;*lʤ ׻nƮv}4-ߥFNWCoG"[{߹[pś=f%:ZvC Ta^ⓧ5C 밓$ty`p8l7YI;^K vͩkSx+ >[`5]ؙicb#f,5' Um:KuYJü|YwN4[Kޭ<{sŞ!rQkUVlT b"eC `6Ye~a'bT`@1 Vr/n%ƴww_ GuJşkHx,ъBYw3M*)9偂k򃅁;ӥG33_fFHgs.43lF$|V¥H+v 8_7Pm@;*ڋv_ppGInaߝxd?ݤjiZ5楐F%P4:{wK&ĝ28cҐ+gM} Z<8$*-3͖+ɔcx3( \GxG HR`PU1src6! Uv7*-PbypJDZYS.cJ p0DixAdlZR"rFwx`T{Dp:];ھ:fֱɳOhD.E\ZI(\(|ͭ]1r.}΅e Wc#/9L}$E\?qpg#y\O#yZ%J1d%9aP6IM<Pj ×( {i*n+Fo%)j=<ۈrnu)[&gV$ ! /bJTׇI勬(GfH d[1LZRrF\jS BuE(F.rFPiVU&)WQiz~{,*kivHI%ݢ~sL;_U/1-R(6~b|aӛ!DOE:5"Xe~A e)].rpX) ѧ- Fq߂p?~oHj "\XEC ;ie2;3`GRR U[?Vb(p'Uu7yʲ3ip$1@TB$>c#{q ``,22F=.}Cs_ -{ huvY`kr&2TM[ ,u,TrX@to#勗vu}ۏ3m.l9k9硫jNSE e!0^rj]H+GN}&?\.ǔ@k?Dz2<;h;Wd:5SKL1@G9솲7RpySn@;{H|ye. ,;ɁЅ?zI voKS5hd᷂m.ڨ{GF$fۀ MᵱDl.09=ft9y=͋r0u$4dQKr+6UC} u)VRR~YaHKkLndJ;KK]ھ8}FS̑' )#IۢXwLeVZjA_:ezM,<ÙUQx4I!YR,essj '8_DK,8 u;b^L^DjX#M۫8r*xwj'ӛܯF@f"YG%J ׀^^`j-&B_hx@ Y&ֲYyScSOQ ^v<ŌP~=_#zh}gSR) dXZ1g*(C2M^6J/ohU+;`7ӡ7hX0_*/BB14*[6-پ̴X6Yl@\{xKΙIky8liжOcmlGeAb•}2ğ#_r)])IdRQ&!i U0SM˽*3 (ad̀Sğ.YiwϡN#'3ɽQ;ݥ YE-L~ڛ-|yFY,'5.6T6gk76_PZ9~ i7YxGی(mCOD|):?3WBG>f^{4_$FfrJA`+k'w?7BTzk:] O\j<>qG;`םx8VizPUT\!'cTU<+q]a٬_]CNQ IfCuJ+@kAq&NbIT1Q%.W.tQ޿B%R!;k"۷ (ҿ3 v2)CٱK~]_KNG'Tzh.+g6F(LI4K[F0(++d"B@Gw )s,1xߺR dNu0jZOYJZc𙘼lΩ=l3Iϰ.O_ -֪;.CQSϯ@j0m7F93`[M`]!!=2q7YI< (u }m6bknUv<+^;ٻ.LAJ5PunEߤ0w1Ipg ԍcvj#0Kb1)fETZ;..t/ H4CrgoՇV_(V Dz+`RZCD1 y-Z=vA^I^F[1х=onfBNi%Gʈug Qp^pc1`PҵHjS>_ب ` /P\/~O~,T'x1-2 }mWDy39tvGxpa(-tf!D4V!-'G ox,jD9,&jg%[HGSWt6( ʲ:  'MkC13lIoXDaA~r].uu=l9uꞐY7c]'dFvBG\BP'K/⊅?+;V$Ӎ} z^I:6+eKםCp*WU˫,}W2E<˞ <?^_7?7Y]>񧜼> v:۽oTL oy=OO˿ |YGΤo=͙Vhh(RG߳6DK/cjRzFT߼z~ER?~:dafNJ]%F~b0 TDeulFG#"1^:Iٌ5#owv7$"QhwL }2B筢[bZsA0l8Sּ'EI8XMaDmTaIr>\Y0KjLQxw " 5 Dƾ%e!TѷhBS%F*1q78l4jTDpk99PL~^9`ʹ.'^~&űO^SWQlj%Sd*3$`!"EMV3hxla%QJ1(k=hRG2$g(x,Uq0cQA/3E 'kT#uYteHJԄHb=ig1 o25QA ]X0BZ)gU}eL~+k䮔E]֜A3`d^⽒юZLֶ,k}U Ϩ\E$(/su7sޠXU5!.fV4*D6u˴︭UDT/iT/yQZcJ9VhT^Xb`J$A`Q|sf% ec|i0-`XK!50:IP0/ԕ|pz;|,4q}:dy}y:~<|'>E0~۴kۿ;ލ?`a >vfFF4$yG4i–TGJ'-#i7_F//߇-JwZ<+:8aFӈoχurK R8| υd*B٫fKBT3 RHlGS}A^kdzk 02kRuGmTDD钓*GΟi2c?*}o)dt3tcQ$Uٶ2M75iWt&^X\AaYI>N*N^̯SϕJMRzRB8_d]tOE3-\.bG|uAoL\nCE 8/CG$Fbq.3Wѷ\.rR˪qR٧JB Sd [:ǁY|^66"*3#cvu#Dڨՙw[(/44ZHS"7)Q 1㳅 c/RK:I}lބH`kk PTVk_+؛T<\6!?rnC/S 03>Kyp ˮD :0άxZ=Z=~.YML4q.빥AR8>.;g/37G3Z6*Je1ċ}J|٨eXE5Ҙ?VЭ84B%KnJ^%Kuee9FK`BcӨtDY]Jesisu+6╩~1#ь|iWE0~*&d a.fb'Cp1qV_z\Z*AIj+/Ui0(Skk~ˏ6Aj=ruߛ?6w>:XpTYJt{7IDO#55'Jv3̰HAz\Z!{Aۦl%[#KG)ErY|{aEjp}'A7G 4I7q.`~C˝')B[B]P*bɞi1{_hTw*iꜛ3pH"?Ѝe6n4ޙyQ&O*bYAOf7 P0vՍ3Kpt'Ѯifg Wf6oZ<SL}ԋ=Hf$5Švx Whu淺+S/TGC LN*}]ώGwD,k1,+\{c-nEhOI5Z7ݭb@ؐ-ʭ9.~RU8md!Ǻ k]6Ӹ. JFHgkcBV*qԅA =瀇g t5algNV!RL&F6^FPbvNC܋>O7Y }7h|mvL/S斿sMDm0oa.KP$r[ʨ(0.U:! ʝ)e+ ~1Ɍ_uaEae6hy-1q]d|4v, ~H/94r!S ,_垫a Ja;:꡺+N\Sބ.㇕ic0yP@S,1-7|M'7wVHM1N?9:5 Ee fD8V`I({}l%\%Y58 Ci?c8~BJi0N!)6СX?mb«ڳ R4rC1J-o8;,#ȹ2;%K_b#>EMHQ# rkX 1]|SuFۃKrq)qvSfW7"9Z<](&'iٱ4X.u)q+D8;GfL薒[;o>rQT_wXX)$K{ ~l<'8~C|z ns_\pj`-sd@l]ñX#ځjlĽD5TN~|vCfZQA^e[1t">CέĈY,P*# ZأXG 0ۺ(c!([wv󠟾ZcJC.Ԛgav^{bYE(]8d.aiKǥ2<_Yf`T@ywE)T,!|/;`{,DQ-LxǣYĔD,U &-X$EU$:֋@>*Zb<,wSE!?g"R-ZPd,(b"+k;\Bdgw/"cCj)/޻5gqɌ6X֩k2Ab_۪3\P::Fe] 5.)XީGN,]T;=+lȶT0 -%Fn_O=`Tbs6!êaTLQߤ5~ݛw^Nz/CmPBb* Gٞa`I.޼J/H#*lV'& 3jF04[~p$u>$j)j>ˢڲz7H.]ڨ_Hb*} <! 16eE ii#/W]!ac79>4WW^!I*?NWHad9J(P;;Ô Vυ%-snZ|5RN#Lb=,;7dT@*JhY w1 /JsDeݚf_3FwW\6Duʘ3'?GyOzF :B݊vbUM9Η͒Uj:lL H]K"^=E| %EeC,Ñhlja/-j4U~۲Ǔ4=zχU H_(w:6[R W`W2r9B62KHqZxkvRET7˙ޖPWة Su"xp)b#SGW3dg`7*l1p| ?-9M5s&Dx(ؘ@1hdm)SlSV0 qЅyߔ_4Xce*^WNr lkfJ<8sVq ޜEk̟dcc#iT 4zE]ro%}/}+'R*bq3YrgJ i*e3g $bB 3,&v'֛破0?5zC˲b(gN OQ(pDVLmK?ʛ;;fuԴ&Dɢ+:eTB9Qǰ,ĥDIEm3ǭī32I.{ɜ4mAFb؏ N0VdP+ gC/zҹi¥QaIY 6)vLT[T. $X!Mi|z@Fp!:J( q ]E,^覹Qx*-M!vnݡS \R͕mHZY).P=rJ~F-<>Dd6 ? ;ӣDp^dJXGbC4)#1H(Ymvm۶mkݶmm۶}缉1sc&nkʌȪ4ޓXZ ĬuN U<_ؼ 瀹iY.n\F~2`aږ(SqxmJ-Mxl W)Ee%'%5=*:4bW3VngG^G8-+uSx}{618:6FN[%6i['u-bF~{e;C qlj37RL=Hs#mN_+ 1 :@ũLmOl^T#TlV 6qtyn ^ ffK^? {Ř<8= WOmmu%F?Xdoy7=) ƈ*fLQf;HȰؿGWBq{iH 䣣bw_+Рh [6i%`&o:g''$:.k{'I^R]e׊ '97p_!H=ٞħg84kCa{*J魘?wE";6^~9l*sA# VKi}ܫu |iYNʾ;H,6}Fsy6o4ɥyqkq˩=ovŻ,*v/4Y`FB6#ӑ:Z[cRlܭt֚#J6[^J3`oPlxvl(L l=_0ڟ+/e}e+s:=6;|%*}tزFU3lHuզX6c|:m???Ka;~mY#E@΋駱ugS JebthU -Oo 򴹘7̞t u~M}X(>xL DdncYNAы@ F>h%40+3+&9 a` cK!D5@+EA/֜NxˉxUQV\%m'4 NQvU CQkz8х5%AʽD(,ꈪo zko| za$1%G^oR| 4Q2 )~ $>u}HVE"` }aSCoG O”\re Y{mM'0> *bq'ZC=?aК9o%wtG$_PoKKkBO}V:O{= yi-aQw]:f3rp#JJ"aL Żm远e;ӄO?kE;bǦ`L"^e ;!䲁Xn(>(g`O*@h4WVٽ–N9 GPxY>zbo#5ËI@!nCw{TqЋZ U5;fF(CmTD] ӕιk'MO<7|n|^FY%S]YFNU&v8WjѥL6GVsJCwCW)FxT^<V/Ϻ'#rW?=ƓfrQ8Et\l)<ٓe,eWU r%x7L7Y`ܷa!3~;@Еkⴈr `ҢEހϳ]UWZ^"[$E̓%*EuHOBҬs8ʊ͝[*{9j`~`e,k/ܧʈH刳Yyn7|a$u)',4=$'2b{P](֥.L+wHQ[ ][\^5Xܟu-|Mw=G0H*pBO et W1}>j`BQ؇ns(NBVkAXfU.gwlZ#s]?-k|H零c +\tW~}c Mdd;.8H-빧+Hڼ"bc#A)9">~H̓[=}%ڳ NU"tW]sCdyb/OEC.ygmmnAu {;)k/(Z8 ͣCH~9urX%< XK?`TiwCx_pĸ}>fNc!4z:8%Rwfqcm jH냊m&8;[C!pKLJd+cjEfT- 嚝ioDE{ә?Za%C~ێQ}k57TbL qI-;]Nb2m{b\VxkW|7DV =[P Ed;%C4F 9xmaB ͕e3Ep(iIG&QHKV]h6}u0 z  OyJ\v<~bżr"`1Ħ`q<}+-4xJe<hМPPJ\J!߻@}'h`l`YA˴AzKj_t? ^n&ҝMY>N9UTa1WςF^wP[?on S2]X?vw,+.E>6 κ@R-~Hhrx{op3Ի #iX)KBh0Z("į^e\-ъ*y `+YƷ@БG\#?һӆv9ʼ档݌`]K(lb~$k+􃞛UY.k ݖQ#6|2's-<$q2Z nFxi,6b9`/|&-T+b'XKiq ỄVIO•wrxz8[6>[5qZQX]d؂*̽ݡ3 @1niJ>P,!#2nБPn-#*G%JNqT*ڎԃyb :gD]Әa]?y]ӻk{ކ5_ح%?`!+Mj7` "_`M‘d/u_ɲ$S@a̙]ED-䶽Ŀ褨 /NG18NHY%!݁|~:T @QL,oޒds$*I%|~uc`7GPam8}PL_"r2;,X$r7ǣVrp-2#TE (;(7+W/BJ5V+<<6Y YA牕#RZ^/氆nT?z}>VVڛZ7v|޾IJG2nL?%ppJ>e@6O ЫybXw=P jj{7Tlp :9$p M%unI_pC@i.m'Uzfe|wh)'~[rKNٿ%v)0Śe.rvQE~yrǦbXӞ)XH;h}v ~Ni&I8rS`IcYv&OCJ0lYm9Ofޯ%Cߕ r&|S$fg*ZTl0!ב7'68<6_*H9WƵ% P!"^33 8{}>h 3SAV! ˕ޭect+)P VmO8 (;(Iɽ-4P,==b ס$~0&[|yw/`ڄ c<ƍ{ٰME0ޑmr GTP/ @o\l7ej$nыK[%N~k'6J qęГ1/C᪮947 pY3 5d ph1De {>̋HX78fpA(F"@6D&Ufb(d-Vኖ?ʄ@Z<at/Fֽ?!.ō;_ Ic&!"4Bvc+1z'r|YXu#vL?0v`AIM'U"yʹeI3JqhQ^/B%£q8a#33_eab#613T^;VC&{r$PgA<ínI"$r+!oiMLyP\mdX8VW4Dfe~KxwCq8UCx`Nٔ'ȝLC9+ b9fAf>%Gdy1Yά|~&Ѥ[y 3\fZZtL1rx6F0Pm2.Ѹ0]`a/Z}Ď >(Y@4d--jw߃9Oq|qQl6Yh%zN^z6'lo%C!7s)&)d߸̈<ӊ)aU(jRk^7Zd$sNaN],zu<N%il \iœSǘΈb_Hm+ ؃Ƌ.q# lneF5 p]9F{އLs1[@"KqӸ^eqA%TNOHKT\/TT2}_'Wh}dzw=oK)%l7$b $|ςWP,bMXN>@=c0ηӉ]G* E'<^"uBG^ԞGbw>zh \X֦|%ۅ3rn[H+w8 a7ziw'*]Ym Qf@Y=9Yҋ L5HoF%N-R᱂UF!Nw;* rHдʡ ^F'sghlͷZ ^Pl5[%Yp9(U48Srڡky1u.\ Cǁb I *KR 6`lejFQB. d$Hhגܬ7Dli>QxتgN"鷹6SyԷߚbϪc8r·. 7n-1Oq(4oKt)i_*6qxOk|.a4 8.F\q$Yj<,I$PK :liYIL}6Q]PM۴fީtwN͝/)f0/6R0 ֓9Z/LA#Xsc;Nz,`X>V=i"i 顦F5*?aa u<e(tV?¼impMax 570U;ջ_}E%PH5+E?@멘{hY+ ΍AH)L Z\̯ß1 '\l\_"5N9 `mf`ֵ7!;r#ST4vٵP]<䴍P2dwФp@JKv5bAw,3r|/ęlAݭ3ɓY`ߟ^=T|oqjc/wgFKU<(ةʆ%. ,C faΣD 7ESׁ¾ǯXܣ`DU5{ȟ,g )gK}r~5geM89%qYFFΜS6X(\ b>ɥLv#Ϟ?bSe*Y*fjԮ@,3᱁y/Cy]0K4i_`͐tut PK@*`R?eZ5a|^ M{f5Mm Zr$||KG}=$[jgiZʐWY܀EfS.MOJote2_pYpRǶ&8dLT,*a]*G]NBz?@v1-0OÜFz+&$X0'e,8T#/_N121vvB߼W<{z MpeWHGXי/Co!RځS gIW3p2XHA)ar@NtO`a]UM ]  9Oqս K9 HqٻOu`-U < zFL3F%J<) mF%#؟0nz\0 z-3 lMtq6{qKQۄ{F3\^A@-RmIE:s!x $Wb!ION}:Hsr @@9*J$JuD 1'b9ygrzOoʙ.bÀh5-THd2ky`)U.,ky$ZSӤlI3s Kw#9 [}ehf/'W& ,;wC?W;-JZV봼v2zNK9N/jh;\T4*NPcBBM| ] }nJQS,of |)_sꋓVjUs;Kx ^zkįsKRi"7+C~MiKb(Z 󤃄'{iM"TO*doOiXL~>V62 VCU"[N&ixժ@ZPDU-D8E-pfoS-HW wE Y]'Qѻ9k*!(Mwu,nV5_G?}K3B(7q*1?O&C"׺:Fd^IdDX 1z1ރ`?Bǯ4:@6| \V7sbz٠V$+wV3^nbYv&kzk%Ԇپ'*0 2j(f'Ό j3 2[ǂKM[Id>AP֍ul-3.zlM `_+? pU>opI*f2X3&SywmLnI5l$3LimEl:\|ex lűo2Wl[I~#Tv³- yc޲8]6$R_\]2aZ&@{9 2}wripo vOG; Fࣖ^̥Hl%#P=1d?#Lo5Nscؤ5X _du Οᩢ#ܢ/'V_<_e9cW.hCS!Vx|#Pڿ Fh,z.p,.*(2ojPն@夸}ymr˞BnE7kD4=&P1hjˊ6ԑC)+/x 3EtBxF;ne:Ӻx{ 0-3Yg㗻n($[̊('E،>J7U'uw'e϶.ڝAE\Jmq#CncaZp&椇6uw֪ޣޙokm^6,` ܩԘ AV౥wNWѺY M\X.&ל)?D}kRR0P4ۙ`'*NԿ_~Q`Ttz у)wRTmٿyoȊy-XqWpI,&r,zFs#ylxP:_N° ba<"\9F֡NF[89ڭG;⇘khmxf&Ayu|%Z %Q)_!Nf6W#n޵61Vd (H&O fYє1落L7mۏǶjs+TZn(u#98SwBZ[呑/qTawOSOd$ +}eԂWG_jpcgǩ4%FѦ·9m܉jfEm=52d09,L L | c|I;I{CW N_#xG]3\?kWHɍ[B} kOS\G:s9qdg`j'&ݥ $ xj/ OZ6Z RVFjJggm'Hpu#P=vvJq`jY:w`{Jnׯɱ;o fCg\]Rd*JWo }Քt $f*̏rZd " #z]e/qdxr|$G[g“ xGR`Ǜz;gOlk{| m!6+ b/3;V"eu|$ GPm\*Ʃ!N1QX4@ 5u!.#c}u 6i"m ;} _MeȚozP{e$=rܙLYxxtԽYlo-(ڻu7{+N#;kh=Gm1Ǫw0"8*a?Rv`;s-t8'd b@O@+.U﫡UE8nBXV[ﶱ2jR+bj&]^cfqXSG%!qm{?.$'>sjɓۼO3^Y}e7n{s~TX=GhD-C[;V5 W%c(!ֿE-C:|I=Њ]=E9?]G 뽔!#E'){u*3FM5Nڡ{gV+t`5V><}V'"VugP)_C[a7b* 4[2\Gzw8tThĭH/g񂍬8V\= qn\+!EdJLCjqp*R/;ڥօOϋcx9hί QKxd%?507ˊ\A#l98'd}L7kߍ@b<Ǣi]G 2Wwlȯ[[ZZS d$qF>0>.wy&D}zV(^iQ)(bjH՟Uqj$w.&!dVA9{\_͉ 8=rxd%5C41MtJՍ5i *n8}$$@Muv}Ɩ<0Q9tz>rOP LMJ :JjS鳦bHdDPw t ?ͬ'w )J)zjb'qd =Vah rλ?xi ׏bMp#0R˵7MOoIV%4 i0pvOV"ѨeԝS¡On.V!?ʡ- ^#_R0 &Ya;E=D5.pB/p E5|Q`#yA+qW9I \hmI¹M˼52Hpf sݸ8uEqEL]m{ x= ImIcc%zXǂ*f D7G~޻:fI*gwLkU.`?;[읩]VRpA¯7?諝z&*՚t }u|sZ&Dxsapol!r3ɮ0B#пYiGۺ1hXP[~,wvC͘ ل6 -ty]2rKڱaȈ3亼Ƴ;gzdԯ~0W N5Q'uӏyϫ[:;} Pq*+Ra!KOe5#=Z%u=sMτW/a@mDXQ]HDzmKk7`^L%c6$ +֘ՔV˃6+K߭ y$ICP;{WkOMNӨu^F̓O _R%E)w7йFz`ȶxTv} T)[n~.v÷voz^ ʣD 𖽭|^4I}@<$mOC'v"@LX518\C~]Jf{Y@)6CU{$Z*l Tq`,4f/7}ÖO)'.1'w$#5,7Lo8i}lm>ɇ: \yM}w͸IH,fBLss]z*RNV}CFC ?trtQo{&?KL"Zt:GzmEĽIJ.ǂ7h\䔞{ PAY*_Pf : s\W,9$q]={ /§CE6y e^GW !Y&5VDj*$a)lqŐIB'z.g}P!Yu#1Sg qR"DW_0^b^ Oze`kyf|gF`ѤjΨvݿk!=&Cd715 \-[0?U?@Jh'+˭puS]s6Ys`{D k_,B6 @̋KQ I ^&ax8=xٮ b P+RKxBb-O^s|~Hl1>HpwLqp-UŁ+%+_][?Glj!nf-7׶{ȖZ%3ۈ~v El=7Cfqnҟ)BjLKێO#>z۫m.CIu. q)%־Nm.*6ۥJ0 YBYr]@ l;]lD~9IU0{ʥ]e ^;">ۭT\\3,lʲy(F:NPP8qa#BIiEF^b{jʑלRijy]U]5"ɕ6 U!QE ʖ,bʌ|Q=h#FA\K]?;rY-$4>`ַ,Fuٲ<Ѵ1oś" H6cLpӵ=8O6EaYVx9ih Z /=!>Dk,eWw-D䙖_@`=$E'FoJ ;^"LɈC10U׀ *_­-FD燷.ݘHlj\&6;r<`f4 zt)6ڑFBu+eHtlأE#s-Okd1Ύi ~ތiL (JL 2 ]^@2\9(4{"U`r3qUzw1M5= !k\A@^w;HV뱰迟*&I_@|~ {y{~aNxpI9T^Ccaew xA`Glٿۧ~jDE$#m1^Ɠ`o:3s2+,T2x9ɪcROvROf%hS%́P E$5CTI֗|ϼ- v%ŗf,, Z$`w!\D&ȕ{ #>>ʱL"5_@om].sBRJgu|{Id誼bPnR1 _ GDUzdve\qMxb7D j̮H1L~T2xhqxa.)g"8ɒ6.LpN7G\ (c3t:TMG;Q }bV.6g5Ī{gw-mQInzs=pa3%oؠf^h} X ;6Xj_?0߀ҭ)("l.\~l90eβ*Ea fNJʒq0w>o80c(  f\b:z hu ͓*~MbW`‡|kÓ ՘u6oɃon3F}QzI:iݱӪ7> `07N.U Chŵɔ8Zۃ$ z_B$U~:Gօxlva(7>tі/7!inXTPb{ wS|_|Қ%MSe pCr Z(;av;t`oo8H*Wl ,YMk^i=-UtLO;Q7:\D\gFsYu#8M JPXw83h߷:6l'MBszi rߠv w 849C"&\OQ6!YYN_nqa *t_&,0]}~`0o|"t0F`Gd 1Y?7 EDV&ZʭdW;y>Au[0$N:wf; Q̒Nr^ (ېO%J0KO-k}tQ9ߺ22 PDd.9Gi\]S2@ r8,I=v/ 3}5 ZɃ9 d"#@ܖIWh%k[wbl7 *\'WR~;dY=T6jqC %Y $NV\@va_Θ`$@< >t- tY,[@`>e$!E%vE1%w(i64t[$NP2Lh.=~p'T+ձHG- Xie! cys>grƅ3)8}(m'+]J5diЊs[Dx+ d\H6s>$qQc,P7.֎"D„  72$pmϥ~f^_ZVjW]G̓':E,c]+ky%[h?tڟC+W|>Gֻsol$8ŽmE0n[لo,/]J G9jjUXf $M0_$ʗ ޵N1~rwۓMX "]gh2Ϸg2ufHe>nb9oۃD=ޭyg&}oL4K!; L)+s{ K+!8!yqb)g$h(z\Ƚy6}x_tcO+'RQ}خ$.dP$dud e9E*ݎ &!Eh{bKNQox/UxkX:7ș<{rd0tk@S7C1'labB{_ 7}v›:!;T0?D 1*5D6LJ=AH߿>t "w\R'b$Q{Dbn1m{=܊y/i7Oy6[hCE7@q vt[+Nh҉GmIG2z4ޝqwCz)N3 =Ԩ/W)9wZdhF圃,'b('H:{T)|zq:mOHy秔ܕŊL;g{LlũniO$32/g#4G&<@CkEti`C|VYV(Y8 nE(v۾gP홰HrEX:.f?S*b[Ю~0P3ȩRuu#O/\wmwL(\P c(BR ׀Tn\~"Kj>cVGIgG& y✍ڎR)+#q/4>87=[`^qP]N&s ?n9zCёK#x3xe?AYBP?Z`҆m;m)K8`dR9Hw.wl& 8E< #O2ֈ2{B8>4wҔ]-zcsL{$(yupG !/lnjQTY4B!*W!|9"0jgt5JUdG057T&ţ2w}FFjMW>X20/aVsG.{lƋ(ʝSGJ'^}ԼacHfG9v4]146<Fr-gAyÒl(壳ձ "U-^Bg٨T/!Eu_2a a2{ÑW؜=UKbZ'R!XCU.b  Վ#R6ZeU_]"PQT'(3Xj֋S0ͱQ)Ko ףe?xV ~!l7sUz4 'e8!ErTybWv˂aeMm`, '+'0{R<\ l9^bBm"8vK;vnHkP  !Tp:0ˤ,۶^}@IA7ph+;#Zʙp, f1Iܙ  `z>1'@T>saNo$|N52S\{6vn^4@<[b|$C^['IP܂J\K`_?& 3#qe$\dssJL٩bljl)g >݋oNx 8 #;yFa>ǸuX.Νm?9iwٝ"Y)0DC0E9;vMWY@' N{xu6 #T.ph{ Q2v^':](<~*%҈E21sq I(CRkV n7ςzb|n%MN(wQ}.{h \%\ Y}LnK 峴06@ʓ^@U~ }~/a6]ȃhۋMdxSF=b<ôk4{27ym0z4cNoHݤ+2 miqVu?ߜfLۼox!<= mQySKM>9Iƪ%6k:Xt k>Dt[3b!ކġO[r]xvbvB>~Gά?[^nDjt핣WFg?u܊-Z!wϕ;}a֨XzpA ,bEOoo_mxaGj7(gɫVW%h/+5mj>5֯Y;]D_J.F|%1!5fN֬OC{֫{loH=/Ö3\/]jY(Df}[N-S92<&fOPLV<Scdt_mk{:DP6:3}bޙ*w QBxE3 v,D]mjLFB9~U,8 L}&.XjEUs”[`@Kdye1Xd::]oѳ޸<(,F4\(=?8Ow,&IP.l=ۈfCݳR0-<㙑9؝25 z`SBfzS@Ԫh> )Bklmȷ6FA E2Ɂ#A,Cr5Ύw'lck*eSHqk v%@Bqj! >eOVϭ3`p$#3MEzt-Uw D9:c__\6Z#SܙoE}zdžE(eM̷C8_4k&j6xi6ǩYclB7E[l97N,0ؼ 0Ͱs~tTBsl#lޛweFB<'&}lj!0Ё>{Jtӟ N6̓]ܡO1 C +  zf"+ĝAYԣ(pcsRs-4ԑGH;yٕ\Rpf2U_ٛOb !i^I;۝ZEʗDK;:uum,E]"ϊ0$q '*&cY){NO֔b8 &YAa!LT?XĿDgqfqɏG,zަU(1\Yila(72\ACyd_<ȇ;9A0Ԅ_:u)*9q:$= qWX3EؠٯWYFe_pv~=wsmѨt1B:40_@Iducku;x.Ui@ 4H׀-܌`A5ǴT(s !)SvYqEPO<*5&,6m?aE)ZPRۛ2-ǻ$DHpm:M>s쟱.ˡ`#kRl cefV,y 9 B$kA8`,r PgCOO!H6[˟n9 OcSastJ&g;;WaNҭ*%(o^l MV/@esH(3Vx\e} >o/&tK"eh/}T77rװ1%WdE͔O;cs{=R̓.Fބ%ßMI׼I6$؇]!q _scTƴ:K̩޳`^5;q,'EWMV)5#hmG`n 9?=A'䀍HpƂ7SLNhx 5XEzeuX{ec-jZb}W/z ͬʊ#k')¦`ԝM$>e)Fdh0W [[ey/Ѐ]47] e:jjxJm,g-TNLuj _PNC]Ű72z3{rW|t63eB[/~`^'bGp|E- Mcb y;HdU0%'[l E0RhEmSbޡ5>-kYC8c= {jJ{,ևK-R4n&?brцz9MDlEbM ~c2Wɖs|_`ᷠ`D$E/wuQ.?mT W,:BڔuLtpJ9i'fDb1Vg2LQ =d~[U3눎2+vԶ_*8v Vm \}\c@m<ǔ#ePNrtP2ۑ1GN[Zw<󐯜_reVݛ;Bcj\CI4m5Uj#Ac8#zv{@HA3M֬<={;bD(92#dKeYx}XC.q6Jgdӛ Wx4U8ҹ|R)GgBQESZJ50to]$y_}yfN1kZdF=MOWzٝX" ]txs`H΋qm U,(->[Cb5lOUy\4 nm@n6aWcZEԞ]Lu˿l[f5*\H(g,jfN"3>RqJT҉M]{C:bI,k=ހgjLaaq.䮏 t8$ױ&v9!~OlVSS&{P'e(BmE8E=RO}7Ów݀dyW/+uԴO({%!uRADkV$]ttWVV`z=V#,m1`BDžU2c~[ Eŀ)*޵k]1t_1p+TwwmLR|T=;&_yh#>)UO*%Jty:/1L&8aOW&*-հ ?6 hs$5x~FyYP0fF^za\57Umo 5J2%lp꡺B02DyIs3R4l/[] |ځI{Kٖf6p bhN^MO{g[ygJno,lkMp²s b®U+LjFZ F2V=v+&S-e+yI *IuY KOGFLB.'Ҟe3VIÂoF^BVP'ßF/_i;ю8xNJPL*,}ZܹBees!/"_iIA7If9vڞ9uBzdx2].„0|0.UcZ+򖝭PhĜR,-K x %N>W w>| F ]ŽYv9ĠVRMمgڗQ5 lMX4,7k_W΅CZ!j=幬88ŲooTώ3kt 먌AP0Ji{}yI"^se`jǜ(|8DФe>QmnԒe._2;^Dwisu%g(yk@Ծk]^8pS]KbSJwE2/FNkl$PT6UպFE8ܯI$HL 8s qhjM@82ZS@i"FӮOdE;ZUuP~ԧ @V~Zi~>T 󽫱!‰JVkձ{HLъ)7+)Pe:sXU|U7;[lj|7 twS')!vɔꍱ{ɂeAAKj v9H4Px愙B-V39'H@SK5fp< Fk|p^YQG-AZ1Cdu1lv5"kI9cݥ拾2v{?=:>2;_I%"m_&[-˷|n2Q*`652:ZF@񨛊1Ne֞;GW6<`/-VboYPbi~uKz#QK h.%ٸFc;tw[`'<;/lqzb0wA~zSƬ#q~e[V>|y6"2Cb<6<_6]'tjY+IiN{q )f]Mc:Sޕ=6烛?KQq8W pB}QHOoyw}ADx-~ c( nШ~WXcvt2 y|Azm|yo;)vVZ4]|Ad!Rא"&Qz†NKq@tI7j-LDfk8)ڼZQ S@g ,-% =^ؓ;g Q ?6J+xqc5峟zܗ?1dIC+bF2>yb%kljmЂIV5-zHQul>,} ^qR*Qw¥"BDdԻ{{Hx뜦vl/_ <{loCs{^(̨{]lQPͪM|4IL0с,͓I2Dc#Ry (BTe=E@A;S/?kC_s,{NPTisELɫ,*FծEkO6uGT^VH_!9Ƴm+K ccta#]T4$\ gC6jn@FEA)+ѫOh*LտOU^UY/8(Rr_-7L|4 Dqcf6@)ų|[rSqSNu6WE+4ޏҮRޞJ[8~ ǙU<=5e;N[^c=2@tw}2ʮ :(w@%!}  ,%mY+&^;[Sڊ?|~By_m#2̴3Idunǡֽ*_M1lhV]?܉-"7HHoTA5L4)c ?sX,?^1G>Y^]Pc>i]8,Sm:3`=IwL?~ HOF ،N\elL4=Z5s 9gŰWM~&3;7 Ի]կ :R1_rb[zSӤZ"=UNR-h1da>sD*+P9|I8P4}k^?w(C߅m#Vee "T`tgWb@u""MBE ԡ1]f TN"Ԗgd R3c7_l?^\: 6ubVC&iP/܅b'o]ꡙWuT}wFxfr62!%(]r8MԸFs˿, d0ףR dM'/Mx w[bl8=osD7PJ*IUMq8V˴iE[{>J572afljSS".hphַ2KN1۝%UX > {a&7 &- M2êg)$S#V+&IRܘ33|?`%TMߜݒqLa9iLs2Vњf)o59KL#ѵ@ssجFdN]rQhŞSm?>s5QS!|U!R. fOE}x@y4K?Ԡ)39ۦ3ߠhM"_iUg{L'/ 0]SF vN7xSfF&rn;<KgK8FME:h=Y4Wc^L-ߣKAsl@dgeV- VWQ]sN eh38vڅ!wIh~hX!&+н2Pa|UOyTdз =-\hOOw!ש5Wg]]oxhAO~ay /|ܘ!*6;G?_pOorF> SG%qawrsаiIĚ??;KjM稢jjio]A+pBKYeO'u 4h˨2).p#| p}5tGLU|WkIVz23ۦ" UW^,*0 ~504#5T?6-+Xiп|ӠK!dfBΩвyby$xWfq9Ck='UucM_XN11[xЁϚU?m9̀^<@Yj>m=_@a.P0z6av{FH a# >zD"ZatLfЮs_SZD g@rs;`=E iٻH6Y[-o|Yk=<+݂]bC"1F-?߰y\g\ݸ !@f&KVNjVJvC|k1vSƶI' Ѓw1czU- eVԜ (IVU^Ww6Z*e :*uj啤Xx):|ۤHǫûn!s Xr.,刕m^/?AH[ zT@ЧJ 2E ű̗7.ۨUNx&~?, f)K? $ t~""{ XMaw#s~>joWAaoM~`5K}ퟶyk9Dbq+cnVKsX֗`WfӋͥ5C __*4P07#0»{PцCJ`!_r'^R^@3} g~q{^xwVԒq2Y͑HY $ﴬ=7WE.Ɇf1+JypJTϟksxt谇I }-qgؖMŐ"/36"|5Bٔ MhMQj1W a}"*o?)1R&*jWΎ'.ܦqySFPgMR;X [ O n%z"j?^V!m騺x>,Us@YILoۆ9uXB/i(ةO(5ǸyM| H/#iG r=*7e*([XgRیEGtb *k}+%=+/~a-ѰI0uPqÓ2MfG2 lb-hlq_P*TA=tH$fYGt wp6k;wqTp[{o7V) {jO\GJz2e#(Q*Wn||xq )ufxtjs(s_eoAƷnox+4%_r> C5U&*\ѼIx7z3 ( LFdzwQH~-skX%/%&s[7M~VnNޝw{%n.=hsEzCi;[a/LTIo{374+5;V~ _'` TVăGJL{o&]#7Gfr"im$Mxkg!K.?"cwbuL6YfU^>}9o$ [K藦ǁ +.\\VC Ke*ezp>tˣr?זX3o?2T&(anC\z vrNF|B~ wXR._6.Kц/$⋒㧙<$W6Ks>;-琯!':\gҫFtisbW4I!zV !CKgvӼ6|vS^ދӋ_8ORoU.B>.o51Rj0/Ω]|aFcoDxSP ? Uf1iO |XJӅ'< mvF-H MKӏXvZPDy,6Jsp d:) &I\q:q59iݨD12ar ?KL%΁լ&0FelVf?Y{-C8PqX(J Igfn"7L|۰J]}\A{fQH; 'hxRnp^͖Qq&$7D%4L޹:\j sjP^8j\]6Ȼ?ǹޏtPO% Imz#`\@ //MډmvKT?pKV>A$+F?Ha|VuLXѹDNC)g+."==m/Fv(uԆN  B:]S ƦnӋH+ [?/]XIU4Cr/f֞llb碓Xs Wc-瘿6[rQ^=/8Oʎ] *MKLpu2*UǡSX|Um9vh)12p1֏Cڦ1@S؁ X*X>>Z٥1Dd6p}v4i"$kax/o'2FOSd4=]148,-p>$鼳oJE>X6M6Ȇ}zwof`ံi@;|rT_'_4;_|6O˔/a.I!C*oA.wm ;a9B:üec WN u8Ii1 `ëGs0g 1+\":ٰȄHe*i@m@D&q͕=|$bC&ЗoX!X:i/= U)< >ʠ Q`h޸JH 9U׊[.Tdhr)?dT7Q+lP<9|!\{4XI<ܒߜ(8.~cEf Fꅐ 5Sivynq%Znc׀QUNgs#kL꽮0)q \Mue3'Əj;t7,_ 5s,}SwɄ'w|)q5.qyJ:̪0`YD9ȭ%;'&+:>brBpF_uچon/u3!юdU)cLjH~9~U)a Gmș @9>>O$Z璝*vh\E2d$= U7vjB,=!E Gn0qSq%Ӗ/{$v]f@*<&v"Pb3e`/ІSPUA❦F7gN MbGլjZGsߋ *VҔLo2WGuA4:jpm AƽKd:/H5칕`E*-ITrk_eB4N^l Eڮ([B#ngǠUɵd /ÖI=CZ;*l"&8CoBӬ:&,q8;Pܣ uF4H: 8+&΀L?%ue㯟Ipw^quHh)Ɇ/~XP'`A_k)./%ļ079c2 z)g2SN 5GjZ]NZ}a\" vE_L$*e~\?fqlH06$8ɯX2aPn8FDaP,h])պ˱e6}Ž=O?KԶR' j)v0U2FV&|q;Y"{@S=3.` &j|kA.y J\7 W|f&;+h+,d $eqXܜ%b\0zFB)f=Q|xnr!&LlKM ?f9|#1C9\ͣ\s[Z(`[bٙ(c3%s?@ED͞C(ы2ZrdYGjPeNoIjJpT玸,+‘LW VO 02^x#NTnv@!p)"pJGUI?3DPaAAzRwׁ+edZ/XwnͩH>uEj-9rnqro! Ē}?ه#+}ͦP}~ڧ`yzs/WJs~4RH$`@o%VckiBvLg-3[~U#s N{ITU p V+4ԕlEtzGRi(xX{rM'I̍~$_"㶣{Ξk421 ;^Κeg>?t?2zZ0Ы٪ųrse O= \T]Z0 Z^؂qVH:ŌtگEu(,oqyMlW"^ }΁&C.|w% B6?9ҰЄݣ%1Tw0wP)%W22a8菡jCwgH"M 3y ٙij0&NrpNyD#ݤɐ7h2_o}TiTa7D9VއX}TuYyeBYd:O8C6nLola!ӹcPyRBG=)Ƅ} A*bVL[/#jݭJ@;B ^I.Jscq}}B6тx?]o[ePG56|l@ޥe237yoCǣq>j/2Z"ꪒM ʲss~wS)NB:'0p_'p/9MޙP{Jiވbh[L<&eւm9C6sW&!{ijIg?JZk :e`D2Bڒ=-AG]k߭i~>,)b8-C jaHK3" :Eup|'4?,d$,&15֔_dәm$V# ;+ D3]pӥLX5j_ߏ_()oj[ ^0EۂiSY-kDL=CK뇔8=k'i$5.O:`H \k Ha1׳M$Q[Ǹ~4T5TժAV0h!<{}<#/ Un&EZcb]]i<d350Ա9_EJ6YJq(TG5|Ѯ[$t&A[Mh,)d} 2nq l8(gp=ݤȭڎ!}5s/轸@eR=gb#_B[MyymLcŨETmvv8mW Й43"q:I#W6 ZJ +Xd' wF0?'. }H7 Y[k~}6g~xqV95vh- 絎 ]k#lZ4!g읛nѷ GOw@"ޚXΈjotSUe%{X?~(kFl~PSe+4b|[ڪC(!џ +qۂ+𫝐 9GA)D^1vUe:$ »-M`MUV1xjϒw9>:Laϋ~Uƽ4ǐH|_UUu`*C*~e=0> |RE}[m̝HnVmSz =Epqߠ:Gkf;0FzW*_|ib)yFfc\-qgܺH~~xXN Ic- iHxLvi#7teZKEdwy>ýA_>{1U@g:y+!ds%+]w'mAPDYd-3|LՌ=e-ܟ߇d}bpFK8wuL@(g`>y<F^ص{u/vG}ȔU"xHqJ Q-YxHe:Dں.4DyCP߂G\Ԟr?bYݞ6EV78aJRz ah㇠וgfq5!q2aB/܈{>8ߧ7w}:Ս.KemcZ߰'rlKw `h* }"!5%'&X3PbjFM~6f܊z?0x_ދ𠍢G8;quLONHc%HQԿf/_Hb?aǿ}^sf(jȱ߲Dp4 U5) ߖg\Mj&dZa]vϮ\NЋ*> K~W+WNE>ɟb@&ZZ>]Vt\'k}6N ~WiyH٤`3$x 2NT*QVdsNvi1__$Y/o<@ti6z ?]Ha;QZ~1{LT Ua`%vfENSW`Pza* \`Fy V镵E";{:/rK0KpYl3}ҸIzaUҥ|R*bss/H B9ICZo1?TK}&Vnb٩;>W@h kbkg򎶳WVCpۣ6h3Py f"GO|^K5ÚMr\s{"*Pu b1Aj~%b~DɌ/is]O6f)}S tRl nʝ>K[[CW9fvψ΍w0(c\(wg,cQE]~`*Lى&uK&K=:DjU Va D&>)DGWvy%J"Pi;?@PpB1E5p=0Xh$9NڭyAkGGsV{mUq:ZB3ru'w k54:c="Ȇ$L=?BP[UOpN6F BSiw-ѓ@\9=+2z: lFڤ&n.Jxj9!d2DFH 4c3^WhT);֛m- ۠<\ܭe&7=;5Nkaދ`Q"(kgLU Ēh xDߡGmWyvBLnIa6k%Uh%([+;b*}^&>nE,- /2EC΄+\cI2bEg!rjbDH@Y1r2/ Pˢ-^;)}5J=onM;c_ Bj4z#CTs%7˧wL PozgJ~Bǟ{ĈUVU:Tl:|Rn_c8LJzx nPEGlE,vpfy-PEbJN ?+6K!L&hOޡߊ0t[.c;+m۶m;mc۶mtx9;9w;֪wV=4k[ڎ]wE]bn.wNt :S klm/,r*NR U K,0|2㲍~0 %]۟riK,VM\㜬jHFxa3kdt%4oiEBG ϼwկ*G'ex$;m[uVw%3ςNfq;BL)y?Lt6)[XĒ_`_j0hrWqFl$+BǭY{s[~NJC)21-t{"">c ɋg9̢ϐ#G1 TI3g,]U(Pk쑓 ɵr׶X\,iڪ|[o(Գz|D|{RѡM!32LQ+O tWXjq6ⲢhՄqX;]F%~yVt&3,HusM ہ13qvq25 k2xx*_Lbv."N.Np0<9CRU{KCZICK6v {llZ&V# 7v6ZN :ڹ s $L-- HV _YV;2%8>,cjgb`縥_ۛ(WV=2t'8PCv:.jHnc 0F> ݵ81RsQS1L j} [{#p_^=#?Xh0TuqCv\}5Ԛ/}<zaO8)atJseeTV,>v~/z;0\EXӡkZ]g\Xzn[i_Թ؛`Ww xmy)ԧc3mem֥{y~PM{[i;;9pI0aUs+ކ*B$UD[C&4R-CK\)$2:4w&ahE" ?wEJ5Yu/F$grOgD[Ua:N,jρ~n%ɷotrn9sL/ZtW#X M bjgof"lagbenib1/)`a`23ELl?|FP̿;babg09Z_o?E,L9YlLwecc1X9~~?3p ?8B2bcd{e`[?3;_1*̿_&ֿ|c|1?+;nfFV bc`M ?;wl=`W&~[K3spo8 Y8"_eb;ddOVD&?9`c`M  w{fz?Oo3WtI?n7_~Wݟ;S)a~ji9㿶O `eo,?RdRUNJ#fd+"oh匾'~B*  27_Ydg`!aelwh?0*#r?YIJETM"-fM|0038pr|k2w#nXٝˣb (k [ubmoIf}.dǻ >?}h|$sc$60C20A;>ۧ&+~ff=e(3czrzaH+t'M%x`X*$'3 ̯̏\;~*礔{I}ݕv ZZnQ`wߌ aK p;d+ H4J/"IDb1.s#+cKr+yLL%)^K4fjdiu0MhplhdiKk&$ɍ* SKuk.N. 6ķ`-)(ȌM OHbx/=).M`^+J&HNm36ɖ!FB^ 5՛D{Zs֌&93 F`>Nz3|Y GδT5䚴kj܆;f_ܐK'([D1hRT[vc9"=ЧUOuc PŘc=l"Z;g\b !@h*gY3-X zDuqz!ԙK _}9)6T,+& föWKV{ڑGCBdOdj(έo2F]&0NmĆz+b}OHcm( J,@4E%yhw!+xD9TyFB( c(0WT7&>H/~RvgP>/EsXts܍U GZ!#d8՛ɊUq2ƃc'ܾ9|ވ @d T u?x48񔇶đܗTH;?A"諢j"Q`:<%Vsi= ?* +w Cw󓽕 w* L ٜt yxZHrmZ7IuN0c&`x6?GHϽ,x. @HP}_ pOՇ͜U(b{ѹE~sJ!$Bd8Py^ydJfn;Fm{Me Aȓۮ%H` d j̥Lʊ-Yvke<5CJ *MBsҮJ-y赧uCF&utℊy5Eݻ$Z/)BZ'%ubroɦI[y#S ! ̝stٗ;zZuݪCv-1䖿DkNIɯ}gZCmZrn]­XY,qz]{IɊ_Ô71b[߽eF~2-3McPb3,\iZi Hamai#ЫjOK_-_3: |Ocl+{biJ@F%6Bޗ, ScuxL 5)[(z +T#lW|']Uc]S̓I{v! C/ %uƵMag+8s^tJ/XQR EѢ$^j+ 1}^TVc0 ( {w(37=(AK?2-*"P`ߏ&19A+{I"uGIOExKgm/ H^Kk_)$R+Uo*!ggv b_ya !JdT>Gp`__׻5bi/'@tT#!j ~oM2[2)A#4.<kRNK Õ4MNU=&Gku[9ϞG37-D)!WAI/rBMK]I9Iu fw/=FʸEQq^^TԾ3t6ki3*qC~R \[:T3u KAaoњӜ5,Ol_T׫X^aLԋuz妫w?h6tg5w&7FLg}% 1dō+f/B~Q Ϛč-w�l#G'k1 =yazdYe eLRnz(kN5@E_Z÷\L<&q^KT>& T)ҡuJ| f( ~AAע\4._ʬV,c!kyԜozY$5K!pR矢"'% DK&TsxCp) 8 {%e(j1~'Sz% wG?7D{u [46>!7V^ h%FDwݥt=Ym{NL<@¤$saykYpӫ,ɰɫPĮê͏*v'*lq|S[CZ w:{HZ=/?s@P hO?{~(jf-0,sP>rO+q8vy~tVN7mɠs]_h}Ȩ<4aki+|0ьņSe&B2iրnV«b|ċkCd4eGdntǢM 5KD?S :cT`a8T 'Gc'Ց-/ DFfsdrٌ@G۱N˫OBKaaǔGL&E-VD$JXLYՓ{F b+魊Tv8 #p`!fќ5nfo!,ZH{ZV"Ν:dWCMssq:F&cu cbN¼ : k.aY,\ -s#YBAwGء^L~4^![2rĸ ./߀~VG Ƀ{U@{ޕ8-{"|s牎W׳]ٯAʛoqӼ x]DJRBE)8yfs9qH^)+Nu!B8vBׯ1RO2 vN#h}Vj? ,tOe Ϊ !NM^ g|K.٣.PPDu޷ \j>~CHZY+d˪ZOFeio /E:>x7'K[ …BUrja|,M5 hW 1&l3Zډ 6E'+UTÀۢYks+ y! k45b ZNBFiL足D&WႀxI'Ӽ䪡FK ȒC%4^?P;=)oAzVM6xcy-``l*=JLmR|5IΈ"c>)ށ<af\E.ʐ(JJ N0TȽzdHȵwxTQf^3i~dH%["~X ;=j8(F$&v^nh̕ntwϑוDY. jbv%+9_O}\{JD/ )R8|ɡ8>! i$y (H&m2̲'S{ynNJU-z|T&gqC cXKy]5|k:-ck5'rqV 32- /tw-4:P׌cvʎ0H,*ǭ2zAeὡqIel m?>ZG]k]!X)m}ečkGts+ԡh):2 N<Շ`xgm&s~O9~3Tg` ĕ ! ;t.K>D OR!;LT(x׺|A.lV6/Ӳ*vaHj]_慢Ӡݔ?( n*D=~D 5}z4;4inU' l:]ʌ*(pk%7] <=rբ[qp|eBv4<nјY *%ۀlƧi9Uؔ+;| B?w@ 5ƊXQ=4+s0.msIbK]G/)Υe܍`S>ccdH~kfs$s=%V`lNy6V)6(6bJh:Cb>c3 J4@ZXt=kxKu^/+υ7,EؾT_ 6 f U1,(Ch*NE7ebgN)M'|-.@.nbjn Azo|~ZL>~$?Z&lh6L֊h|qp tľU,i`n@L³- B d0݂ tnhZePOl-zF5Ĺܪb3,_P04lE.)h]GOY1 "Bu=;2? xk&r'0ɴa2tj'L"S!כoiz'ׅ%:lXc[ *n6oʤOE5BlN-ZC\#h,:/jwm~tD}SwqX^F%&n 僶Oi%-~3yRB8؃1wg@u9BSy_NAl(ppVܨt*ϐ4D+{st`_cRpݧngqyh@mgO75"I@{5W#o:ïtr <w{M-{Dj:z+fo-4(I::&^{dꬲ4G 5OXV{Nj@+ p͖ P S4 |{ '/8Yym%V=sM+>)4Ѝ!#&%Q0mYYkmܾ 丮;F}Lx+'Z3m8L=&"6eůDžlz-d45:]چQG@[~㽿2}L7tTN6/Y՝N\wI _Lq\a?¡KPb ,JG_UI&B!Bb6HkaRT$sb`,0A:pһeZS"^;!6r;,.ƻ([qq0v z^meaT5&xE[iT'g v/G܋f[KނH% bg^3C{:) r7t<'(èɫޕ(f W%lRzo$=#S4 DpPS˷|P˿:taL7\ܵ ߟ+dMNoa|K?4yݡ>_crD~4CڢY8$EwB?:2zdD\F)LFwn?9*1$sRìj)"&gQ%*l^UsHj/ Y=~n:iOE)t@?EKdE0*\6A$fEC6p\# Zp%WGQ$6Dӈv3+ RLS>6L4mppݭPJ[#9<d 0Ax&.XVϵ5;jPPuؚub͈ȣ40nS*}ɩ | ҥOٰ=;yn('6ш BvHVb[r]tIbKV|C"JjX0A?5V*sIIUMB~ӀC` K^#K=54C; c8yV;% EZЄX?ća`9նڭunVTzq82]Sߗp(\Q({d,)|\=q:P;|jc*s,W":Z8eW0E d8SP#fi~zq|'m0,r fT:A|r5uC0[Cl{(>7؈3ߢe-baI2E\O;TR~}RsH#WysF05GRP,G5V+6sGad)kH2|=~Y|j 1zᙯTBX2W,e/zBd kN UѪe\؎ Qtb!1 F&l{WOt IPM8H4dר#HtVz^k߷SίY(+]*`V| w|䞖F%aBbŒ0:t1uru63LcWJ HnZY]̡k_BɹOm(|S~4npXOT!}pG;Nnyf:y:c\^7 &7\`L/ yޟ \/a=:Lc͒s?m-*h:)4H1⻶Y;pBu95mz2wwƘlؾ(O}}Y_d7_K75gs %]!@J|qN, c$7L,U* ̈́NG s^AT)rwiiހZGX{(MPu}Znlr_+b9oU"X)(y\,? jˆ 'nZwq&3IoĶ/] KpIG]2Q2UA>7(EYXgm?ApwbiJИ#3~;JhyH&#\Z9Ug@P-3 jT,wT wv CꉲiF[ 7Xtټ/i(R4Sf[.<]9#{@z aDx2V Z ,`!5RXt{yoFŎE5n{oK1 l(K0f/YeSxRGAVGY҇0 " 6 aB$yNtOUJ:B6oAZqiHheYz;gXwth,ӱlMM1x+W v.9_=_:3O}17b0 8b]%~pQ|ug%TSYٳ 'i|?(<7TR}Xo{mRo^*,f:@&Gl=B{꾫S^?Ġ*jC<>_4ϽV;8+/J釈6]׀MyRB!r;!cw-vx}YEQ0;뀨/~)`)YwGaQ %ny`I;r\ڴI Nj -M6+tK>[,ĝjAs~xޗ9r q'_5TZW)϶Q , (KoZjDӝeek?m ̿&}63+ % EfSKGz ?Gı9A, ji;ΜLa8ҶĵN%$p%wl̻r t)'eO͵盾ڢ1!#Nm:[XV4/[<͆"JLKaJd`GPk&ia1а~pb&39jϘ)j !cY]2?@EL(5ռـAP0[ :<ԸA,%`X"yn"۞30F#?4׭3!5I FjO~/N,j|eFg`UHɸI:G"mu_%=i S:Z{6KG]YW ~zN%vTKP xpbZs>!V u+Hyײ9 a. tgq>|siɡM?$`n@,KJG4 Ҥڝ)+,F*IJKE" ]%K)~$ ƐuEM?h](vUv2{_W'rdXP@Tl}zOFǕCd qug>`@R[F2&:tS c9oKcOV JzXRj2=j-JV_r楺No+|J̘ľ PՀ&^ZR~-PC\nN͒~Y,Sc -XHG*Mύ(ۥI=1%bg h Qw߆ꓟ=bV#}jizgRkʟ*HixJ# ˹2o*"Mê#X8]HWu3.c/k}_6hF XJ)7YqzT ֮/Kϭv}*<X`;gy_'iOXs;XRCU1':zB{\|nܞˣWzӯo XP1SFZkS-.KQ>7+k7/z19i?āy:*zksѤPb8hB{G[vmG$0 ȘBV}#-,]jɸT1jWnm8.V+1}T3)) d?.z]M󕅌ZԜD!bMA?Y#A|S8.b8G^O up=;̉=g t k diCzW$‘c5av81,euD |iF8mW͐g yMhJȩdX#9)|d׸Sg|W x0g]EoEYNqb`ZX⏇d:E*y1//F/_bmN4Ffg F͗Yťn_/FPl<*N.<.pt[v>Jdi1o\~iԴ>wq8(SbNe&]HìaPڪ ? OJ"T Hn^Oa@{RgbLDF/R_Yf6!8l@ WŻ䰪+/wOo^}Q'qɪO ܺ+=xʏVP61 09Sh]|3*>ǍGkxAu甁OF]9#RHp8 ^۞akzϊîo&_bRP 5Y㥗yDEiqu]1^6'!%q{*5A 5+:ZsF>k^ۦ5/%hYJ.1+LcYЇ+87Q&BXrـ +ZCXt"]HVityl22XͿ1K֓l"'AEmEo4j]ݞ"KX"D#PoHjE",*;~+{t2o i8!)]jY ̐x $6JdZ<(kyqhؤ@g"=OaaPSW89tjrk5V,(g7uHE&H6_EXE*b iز1E.hJ=5v0 RΙ+t*GD_K; ]ܗɐsGx)B00 ynk[9st% P wɽVیՓJA P; ^ɯR?94eσ ߩȟß|- v A6l?y3},E?v%}a_`TD{DM=1.IZCȰuLڱ!vzfW=zi;8[6T RRQbhӡ!/3lh}e&A]9U13z}X\Ǚ4Nr yJd,_L* L7% `/6}\P~M<7%TI0y DJXВF|Rc"ݫ'5n9oc]*?LЩ֖19BG;e548 j7BFxXCw# ^hKW}B| LJEr} i` ʯ&2wcsxRv×Ը6c/=S_4M#^~5 9e#ۇM:5JKy^ !{ WclkGyiXU¿#"+k?o;EWGc4]?]R>7zZ>|tU',dA 3EwJb7灅"nj4`*-EX^.l-6οB)2u=+ y(V>..I ̑JFIZ a.H ^xw)v-gGu`Zu%<-g}ĖA2)[ry 4f[ &d%(x,nOW@%^XJ M(3fSVI eZAӐ[M8W^! =b(/fܤ M4)[Vckh8R¾@k%J#GM}X/ ħtw˩CD@O2-+([ 1hRWٸv0sK0xCsu'w#WF>&?= ʾVC ZNͦeh7Bz:v|47uGF+5@~vv|x@~Ltf[YKO`Dts / [;>A.,"}s. xZEzI @}ŋTzr)@Zzŀgy2}\V^YlkN 7渁?Jv'{iRS٨UNIj;cB_]"'Й#WGNR_| { INf}~yLf:]H'w!b@QM]xi۸dN,ft4}4cEPձ5_5 {\yIJhu&ؓ|VށetD w SA{FCD݊i׋\MM 5O \|:e9Ld!Y6ݺHHrR#V;$}If&L^͸T~eT@8 Y;ez4ZLy ܟ_ihēs\"?c?B|T_> 3eo{avbo&ƛ^SG|A&+H(tKwޣ{pF XөgJWP#A"uKR6w[)P!Ґ&wVJ]>zV @A1 i43C}J;.P:3}y|H!xs2U&! oրǰrTXk s=".Y[H,?tK[ KDŻmlEphs:+yCzYBq 8hg0bgD\~Vū"m6m7ڶ @!cCJb1Git@h3 fOVJ:-&qzo~YW=3ĩhP^|{eut }TR;xyFm/Gfzn:jGh滶F$L!CE):` և?((?\Yt r+i\bxΊV9xS~(`mK"-0WO. )<50 KVhǵǝqjUEan/ʣHJ RhB*tt0š,iN2)" 1 $Mrb]WZ$>u5szoݶY kÞN.̰Μ>zc@Md2gFSm㕵~gHrRZ@HY^ K/fK":,zeEֵ:nT\%wTCwճDe"#A ``16s/A64y 5Tg;䧄L'[3L蟶X(HX+N(3a N M1Anf^JJqv S^!hp{? JrVi$HORuLJ C ہ]ixOX)]J _D%W]2gr ݓ`@ɩ!C0bx;ƠLT.{1X 5ۨK eċOCoRMO14heEFM^zX#pH )@- 1!d*R9TgHR֌ݴs cB,,V8aO]WkoOk B^|! #k^Tb=.xZ~s5Bw7Px9k ʍ۽=qYxN5h?]V[vZr&.M^+ՂuoE )z8ͭk(<|IT$'sY>44Ã,fچ; "|%^b>KI>hm7u%fxї%}S fO֬F tHcg,5rv|h`[<@=+A i*=[ilQ#;֖<6;( 3* CM_P*w|?V V>tP2`Z'naYl`uzVt&5RnLDoHJQd<^6L*-3Ve~y>}1+D',&41gdIg)vlMgLJ$ KI;yH_ ЀDI3{P!K  T>c@4*pij2X،C c{ Ԙ9Ev8I,5O3*ap@tc[#0&PJ2/Mm$WSظ{6 kG9o6c$Ӈ{p~}x(jPePܿ\6skB,rS'Td~5.utjk;T}gɏ;ȢDbՄ'c:lyH(4IT(<>4 g9FbxQ;!͕J̿_^gIec[w }gL@FxU^O˄=2(ӆ &#AUm&92i='KZk o(Otuw1bNK0 qi#l敥V\Ci¨.tzѻXJBbh^L唌BL? KK,>&Fʄx*N*)+bNkcC\ҿۑ](uGiPB<~U 2sˠ.8%ȩp7M}Zڄ[tC@ y/>$Zc8޲1^&0ePHў/!ds 9H[fkN"m:KZH/TV };2uux*V~O 0vܠRH A($~$ BEO|<j9NLM ҇@vwXQk&km(]w޷󼸥r{XLO"o Q &È+n ~Z٫ kj_ h@gv7pG2ĚUfNu*ACha5(Y *ZoqI877tj6zo{bEhzN!2Q?fk~=m]RiQd h!=OLqKB4/7^a JѬX[#[A@lT67`;1cB4d}囵L"]q2SfX}[߅G$r#Ē9q7JX#o kF=YkQf>>|n}V:0ۼ";:8#0Lws;xJ촄jƿyG1te4;L?VAHmeNwK۹w؎UWd0De_ ESB'xl5fgcU)CT/l|gaXTĪR-;18`.`\%k  ĞJ̑(FГ9puxfP1ؿ#A(iIҴ|ovv씡豤dɴ7!Zry\{F2^Z-)a3VCW4>?6/ |\ sxFUkk?M5|Hc( 6wc֦oP԰EصܵUG+!-1TV~8-.[R81"h x^/aݴhϥZ'>a`Py˟R!Egy{Aѣ_ęGJwW@d:7Q.:3ho(h@~Z$<:wNFɃȐsfsO5DLLxZT|d̀ c3aa;[˃J< ^E}gΖ\l{:dK3ٱKjY57Οe VY+qwrBSY:uas1!B?Hꍫޞ4CXu47NSl4=f{!*Z= 4 vG!٠x=XZIwoe< DjCryGY6&ꔻ5u@VW8L%R~.M5<s=k`(պƣGGĄ"{ .@F识bDC(RI|"..HN)uY6csƒ Ke*$W]`w5N BNniDra-N?1}1={Z/~-vP,ڮkN^|S5#Tǽ;ĵbuon/A{} !T;$ɄׁVN(qFxScv/h+`FyVP\\exE?S5JN}Jmu s>$IjWQLJ @*SS׿9]89hr l[474[prL&pq)˟Q6=0ZOo:vPt[ Зk^D p!&F3Q \PZ,悭;dS5҇*l:bVMI,FB%y/bi*h|2n6U2FHPj9r츑ȓO~ DۊjSPP_'ig c21]( ҔS>o;FK}X_ |/S}#wѿrՎ/12m8f15 Y.ĀǗUqBxlnХd$75*ʍ&VC ? \vHQ&I9/K,;FPھfp:j.am]^eO .0ȃM1yrB0DJBl^yK4VM;#i ". Qb1`o-s}(/OhV䆘VdФ=Վ'/I#$j^!+O?R ؽ~ ;#[?TJ-A8X4˼3 z;'7Cy_6pW9fеAxIiߋo}}LodsJVy\d!bj$'.Du.r,2qah8fdIrAb\W!p(q.U3’D Vo dPa(c+!5M/SQ>1!=sc^?`IҒ. 5]s}@+sb~{lZE8Ŏ|e)&T}Oɖ`~HȜųsFIjT4,6۾fD`h`b* PE =Ngi:\=%.10!@W}́+V.Wr$z~jYٕGGDczD]l"V8`jq-c! "$ @M*,\444q5bbd?NTc_Ym:*F6"Xř{;f=#R@N2@[I?$) U]}+ږ!+;`oJq#Y;=ry>@X+$c[rkܟ(ƺ'p^ACf [F;lG x<܄/BՀ8 'yE [i:@WАTL4=EqVKZhVy~`èuOЭ=uf1G.dFjX5@7Glc luܗfzX~<mCih.w wp\/n 5(?6yfƏ5wlPt*\$#3䖓0ʋP\ <|&fݞ0#4Bߔ9n2xdL # ͏v^bp+5M>,3s8th䑋m䨰)\QDzspe;dlG/U9MtMZl$0A؛e :йpZ7Ō~ V0ڍ6oɺ,a Ě\H5/E`2k02.\XzG!;7F81/aA1!D+HdۂS .|\mz>v??G֢@|SJ)d&n|p?;sRWپ:3@wza*~-!z.Yն Y5='4%5r `\;ee,/MkLLPUAّ) KD IwRtNll{ dGM.^C٬LDO9 +F$EVrϺD]xu|h%)5d/Eg Z*SPף~l3}m[V=[E|KыqKjJ=; 2;Q68{8YvM٢wuɋ}{rO-@!P6AQ]f ϖ&wI)J o~ޏSS?[BHC:4$NVFTzDMw}QI Di#$:|­-Pc彡|N&MJ!6iWSifǤM\Ms^F 7#KSnN-*(/[Kq-}m8(0f 7\`OO&۩ w幋W2x-)&Gp#ԬQ.KO-~#X!EMysun)r1RDcEʆr3ez4Mz65o[p ;]ՎΘ uKhn!hK4h +P^Nak+Q]/ZlOy襤C_Je%úq&y]T4;^mz]pQ3~ޖs{Ux_y²g5o;Y6J96)rཡW}AWI%d<HN: bWn]F§#6)$Z%xeb do l^&X&'9%.A@MNEl k_ (.,4)/>WE-.-Zfß +ܜ[.MLH5f|L}u~XdvO ,}vnőEq,31w7ǛlƓӪl9%>Oَq#470KAH}-m|UfgU<R1,@c[6dqG{DD>0"J20t@R4u_*ICi;\܄q'xXnbӌ"ڐG:?;U-ڈ_K{3L2=J^mg8Xϑ3Đu|i`;k7;l>k:xk6gz[8w'Jov Z:ʇҽz\5`dHO(.DЬ 461j[t >ğګ2MpDȈ #{ck~c^4R7? wKrbKF!x!/髷p7tra5!GNb#)0`XJƩtzi[o kZdD1`pu:1Hd%?h}"#>v}Z:^m*`fan2isՎ0bOlVCmκ2Bʼno}T尫9s,|鱾xLI[U *_#'d׃8F7_'NЇf4MT"m^^+*8R(ˤfx{:UK 2=hUQfuF%RKfY8*7AkN\_Y}g,A._WIb0m9u%Ly͟dȄc@lN`0 C=- t+̞avcv_QFCU= *V|-2{ ZIr6FcT|heuXqSr1l 2V,chh$8My{.a${'4G I=w*HY%Bʑi=}s~4T{hħ3|a`|\@G-]Q{" n XT-Y X

D6ycShVoD ~Q~RF` fl .f3.!GT#*^@xa2Y3)t)K03A:vvޚpߜUdnp9NӂD[VPV,ȯ'`<+^Tʌ̲Kힼ-WUK)u9;CՏ ;Vf4(0]ТbW0X#8@$ C9,91?δh #=[ S YjwlCdIn 9`&< }!.׍O;:ޛKw Ʌ -R.` :)vp iYFk~0P:>iIˉ+бPh*sIHu:ϕ=D+O̎~]C(/?ClY?wROFTgd.J} XCK!]FHq0;QyҒf%6T<'{U 4 |5Ƶv# yദ$tR- hm`wac#WSF"9؎H'6ez3w&MQ&jd\GTTg?^8Ù|OrIcBsv4nVQxs9 1 MHz]K1 M] 5EIH9Џ EN$V(~jiFwܾ"3W:f:ѩ `cmeJԐx  \D;L6U155? #\?ќ 'ʇ]\i]G"u}$tڅ<Zi6n3e HӅub= )Qsf֡BQWHͦa A"Wa 8ju{+nn3*b{ CzECi FXwLˏsey-;Tm`+,&Jkх.@òԮ _[:fG1Q(+H>笫>wO:fm` /ZLՆzR[rx|om:ǃt0f^ŖXiSck&1Adiv8ޢb=;e乜2l5wҩ"D .#UU6ͥʥ񂿼T]uM8=09iߔhL.`U qH7xJ!J|ax>a&s}Xܺr#}aLYn7^ɊbaEuwÇJKz+Өҕ3N_jڰ{hSVθr2˄8Nafio+m.4XpdSm@QU6ވRiwCBY5X (H^ؼ20mq 5е.GD]_,[Agp]x'{E-D>l< s0M&]I?iSGT~j ҆-+耿qvCZ si<IfO/-0$W(SAU֙!4B w+ZOw䅀@5F"̝|~񆇤 f|_帘NAu(i lnX.[ŒDDH߈ZcN漍RGTUQcA١"iA )MwNwzc:6?Bke͈ QmPc%bPؙX|{.C{dS*pvL`^-N?_#9i+H8`]l$ DŘ s{|[kxٛ#ULV&Whw=0LKߝƪnPQ}{Z@{jp"J1֭3U*T ݞC㌪@Jw&٪iT2$51Ude;)1l 4.JvlduQA6i+EMQ(5 Un8osiQ-C61ZbdWl V Ll$娚1KeᰂӺdlNADЎaSi_ bI4`12ϳRDRѿL.s, N=Po!J4l;AaEL5¶zNƠS-o5%J?b\ VlRa^©?Ӣ6,a+!#0Xc,Zmʬi EF!!p)IJXå3>(lyfVWhU6~[lcgp-)2Ea5E.YZ+Y3Aޙ4tQe);Is5Mz 6WB湅9I^Cܵ~G;b\żp"~oKO1 ĤY0>p!%h0$\gB,wY(XBN:H螵[M8ӴvpIkm1 'R^'),nbQ\Eg/?cA%CNrvH`i| wbhs|u@6n1z=U#|E;ďOrɄa͑ԑõYUJ}LU~n׾__I˻qbġϪ9l P|q_ֲw}*;t!ܣi4O@L$ Eg^ڬLgъw[SSDI'ZeqCsF5$]De(V aӜDyWH#ކH eJM\6W*dee|`Rb9jbG,=; A ^KN 2Ax0N*6DyVb &Ll]mfV#unm.)btOl\02y/|//H9t`4^y)vc8TP’}8DV&na;(NI(^f `Q8Q)v(vɅh G d|c((+OĚ ofkrP d$om$?S)g>_I:d&Rx D Kζfy;"%`m? .Mo S ΁)cMqmyvJTf1^a/s@(xZܧ#_LˬwtϒolĶmNlۚضdbۜؓLl޷w9oW}~TiHRq} p16lͿlV=p+mWWXfCxu8OnLʼ*gJ0q4VH!CsX:t}\b9{%Zg4yÒ_6U <:5_ַ n(Ơ<1Zk3m'IH{,FA(T@RC!PAwi?vf,+xR*a`(?m˯U4H1*Ĥg7sIz|Lt=G.XRUtH"$D:0aJP\GWfΤ@=_*-IVڋ lg+|J.)yXTB&/BLֽba(!e[Mc6h}G4E4Q~3*Z)8LK7 |W_2@X5\fYF"k]M/~u;tm~,5wOpSz/ Fi[]q [vqXH!y#Åe.9t%`(3Ճ߿x 9 5#_&_Ya.u0I:$vN;AftP8Fw$p$Ū=6Q?XOT@z4#mm:rNOX/,F@t82mHK* t\+;6Zh1Smb%ocĮN(cl9-q=g48 ]V4'mmSϑY5~Ι!V`>3i?$Ĩ4vF:gcP6h~#읫Êb J|wfH q|.=8>}3Df?QC]Q(@:I'o=> YMER=~TWwSQKJV_03uUאtZB\N+;8?C ų_?D P$X* ={4%_o.sDTˬFB>'xkVI&.k)vz:_ ; 5x#*. f3:*C 6!̲1$v͡2#K/"M18 K0ߝߖ՝S*縲MOd9_Yn[PD(;(P㤽El AAzY-\&:Ŧ[b> j`I]1ndx,lb$~اH~N:}cSՄ>pϚNB$̈́&c r ;Hh}sܴ/zȃ*1H 7ͦw7 CQdL>KX<}VߢGjh)gڏFYr?bX4"lxKLn5X|fbrq w@h@;NqmeB?=қmѡB3`z?lQJb|;DGzVYٳy*-z\`LSL0s~:xCp]wB_vGc.^yfn}gܾ㤲MW?mVap 3&}h.R Z5_ w҉vڋGHx:WHA0=kmPgjɑe' LjD~ԴF-'>(5ӔyZ +8EiN Jg?T9l &xx8.oKDW_ .EZNRQ~~<?"R!/~_i ,| iu&Hlk]vJ7e5iWT,pOm R CұW䱶=,bsSA#WMV{ad8Dx'hIv];kIr{Vf<r,1n1amŵ4׈] nQS _l{ZvxwR%0>B[A}X$J ^?jD-ѼK罵] m/PzVAoOV6Ɯ 3!A\whN3ME$<$ koPXΝRtQA⪋>] U˒׶q-%͚Gtg\7$dA33@;4(Aл\o <"-$T+HYu(;3!PZJ6$P,vv27!:@0L15?~ZijqlMqTdSv\IJ!v/a~9ѕ|TWoI Zchצ%;OVly#p󃵅rZHsQ̂\yEΟ"m<1}i~%[j-1K0ݺZ} Ma#[A4J-YVI^ziBkK"ZN^KSl""ǖpgMKZ5"  3V.ζ i1== X'BvJDѱ&m,|ܫ>K=ĒѰ:4{+tU]_1&Y4-l7Nf]r%Dzd!#(P`&s~w:H!U5kI MKH:F@AH={R+a3:)|}9xA/iZU#")]rAȠjf^U9!TؖA\ kqiN7 !aVqȻ$:=X@lFm(3$etg^yr EnzS)́!ɂ쁦d"5B9dVb_omg zg6hйfJ>P؅XkXf[VlvD"d@Ò_$ RE'byj#=z}L`h nxPwr@~pQŎ[f=qlVFczY\BkIY\![=~\1ݷWx:*|agvgSYSrp Tf,yeHP,@44A8{"DY ?w4+YamWA:]xb𛔽6avl  !9``qwFupTp<3تYÍ  Ӷi>͗tGUӆrNؽHhCڈbP@ #f'"KJ3ك"G1_@5qŲOQC(Teƚ%\*4- Yql[igAlCj%9RxhSkn]K\< U7yP3bXmLkz MucPc0CϥC.l%Oru7Yf<}م6 vU*s/CL&8|ط2M*<3aD8Je:f"r'tiA9RvL}M{@9AY~ ]C:6~o |J,[A]QPt0 }'ffLUȺlc킩bG?r>S6 IRiZ¶ dx/ 9>UIC FbLNVc NSY~UA.W$݆0q-OwR8Db.!س:^k|(./"\ T#I]CҨ͊uk8_-T:9`9bAz$ _ⰷ~W5ҔM 2 /\H8a53o )}{w0wH{ԠZB)OÊ9>(O']eMw8)Tw,Dc "7!XZs[~io6-F^&YBc~u'K. Ĕj%xx/#6Y~!H}݈X'7Jf&TagDJuA6X芪e o?\E@>ؾu0SfclB`ZKl*O1 w (>6C1R9W1[;vˇL?hVX>uW$g/𢛩dbW~|h]DgUuai{yKjEYyL9YÝu1yNz*%OxRBp]P[2CuDHP "/Z qX8v%yLήk&7\LЖux(?fܲx rƋIڹv۹ruƣ b`bF ] 1.Sv"H HWn@XMknl_aK7l?Q) sFK$V%Ev#"y ɝ9KO$KOڪO23r t?\XHr Cb~)@#}aZ_5rn14 E5Qy `%iLh8xUn3 ㈳Dz<nQB4g \ \2\132 9_ܓ:S<b^P(BQK̼)tysrQeCdsJ]|Y@xBytfEes+#Q|,7珍YuQNvN*i[⼏;G]f:9_̘}"88-b ;FҥdlcM8(] NYX䨚99~V9!%ed'`dc'`fc"`a>K)# _(&V?Sϑ/_ߺ鷽/;+33+AFAD(z6&vOb%`fag,l b|>gv?=3|a&``eD31b~8?H{]sdaD~Fl10}>D3oF1|r}Fs̟h6?^6is̟}?'? aX?olcsbaa/;~?;7Ia~w?lw2>_%, =33#Vg;!abd#[Y?6tb%d`nW%bYmLG%%5?j/ܯ#͟ /֯-W7k[l?w $0ό,߷_;VG;SiV4&kY&땦0kS7c6IDy0ih?m+S[}r3}M=Fx(t vťp ;9HkId߸8':ZY04vȄ͏h; qL{fzZ4AHsK3ۃG\bm]~KkÏR\߸n;CcG{g1T[Rf{Ծ%M4/g<84Y(v?_MQ?t,-}}* }=Aia.jFXMHN5 E~`?Uׅ}ϼ5}sV6s}#^VtCHbtp.26< k # K6:iUt{ =\LnkNh a)g#%'2~ !+ft?7ؼ%s{A" x>K&@oFAx,nrGpBH32} p(v+UGMLkx\A s#hMAew2іk](3s2*!I|'T͵*m@VH3~Ny=nT„E#^\~(7oj_畀f#e=xDWcj*$^hrXJ)S/6ZHc+ I'KCt6` ^n5%e ʘT;_) ɓΝ}LKA'd~GsrD3ώܹWu5:# i M54>2=.Ɩ0vZ]-WjfhyZyz،ÎxDu:oCҧyj-ʃS }z9Ah]ިHK[lů%j,@q]ny!r)$8 73Tz~"R7R$j9p$;Z 5:,PnBpjZ.Ϗ*ʅBYX.OϨ(k1悟F!c;Gc3̾oiTLz w;^7D'(pz.QcI6ZHҍ˃j3Yt|=YmnWMC꺐{jbpBD7WGTu5%%#ن.FНso{߀`ږXIlRq o)jZ"/n 0Lbcg<4;]6VT6]_Wbܞ{ZSvi \`ۍd?`]F^ 4CSk5] ;Y7>< ľLs#)zFC+`W탧˯'J^d -μSkbu/kvk%zga8 ^o0%Z4>2y#.@lf*zt0Dkkw~oZ "UeJuؽ,7#"<~hB3M1-Un6Ei)6@,pe]A_n`,e-Fxי*qZHP]6y3l黢M^[ܼ![qڂM2l%E4?̵5FnlMt`U ?N 8QkYʽgXI4B]}`o[bqph޸U-^i{`yOiAc<23n|#gSlbF5u+G=5| ĥyd`1Kqv7i &k={"cď44 .d{WlTg$-% (ЋoLm;:wj5G yA XxXɁ x%KI?E;Pk\B8jܕ(KnHGB\Qbh%΃Y|lgUIѾ%0kWEYzK[R$Py(Lg#^VNQDZ 46}>dH(K5$ԯ5~с*`d N^6| YmgAY6OwOȚdg[dSr 0 b)Dd̾bÄdJ*8mAg-[f1@t }mr"D.C(pUļ"$[ G?;U\TV:`Dl݃b$҅*YOqC:9_J iwn7\BojYBbQCӻd/%& \ :qO!Z9HwH .-dk)F.U=hw(ǴAkf oq9 ?BпfXQK2ߖ@3tKL =jHqzf;U֙_T8h9^֚c2Tj ʞ:Y0Z6XK Ykʉ歐#n@4k;#|lU5K>~!3DZ dj&2,c ˼~O/FJ|4,Wf/5R}G$- @iAYQ^%Ad :q8rC3`w`bgcש{ine8 AIvXHix*M9$yܻU؎}]gN˥!8VGRR4!)ɀӗCBȂ1  ⁢3qCgJKON+Z)!da!8hqOU;q<;U梥$TeY͹" s Ol7ӣGQ% 4fϚz^18xF(i2BX}%ʶ !*peWV؟"ɴrB4i1&>KjB:ިj61bf~>b 0'K>fpRRzJ{̀_U/*zNol8>nJˊ-B1nؽU=uE9z*>I~Md@yO Ez[/2{Elj$ֹDZHuI}D&e[8丵% ņ~}{7 ;<3ȰgGsBf5d&!YjH_k6<tJ]2媭t! Om%a΀]͐8'؆4K-b` 0//Hˌ2}/LK=X,8.bB.i߫f{]ٱ/aAАG$XJx#'Le ;'~Ar U]q|3&)DH6R+ i/?p *Zc1?[h S5̵ ۗfToX+?wZw_N~V5T=rφ'΋9I܈ޝfФ^tܯZ0h\5b7[R1l .߾H zU B'4J8dݯR>%C\-VJ>X;~8C7$M#B]IJ^f U70B 5_/"9fwك ;w \̣s=(W[TRkpj+ 4#펵LY)3x0@ջx!34m߲O5SqJΛhalai; Óε%Oj7)v1pvr~Ȣ<1jӯ_5(n8;RJ')ӂF3l =)%L GsP vKhމȄ6/ Jb9F=8|A 8%:̈dL(co! >5ռVuHmgIg߯J7\PSjl ־Nb_HH _ z24X+ oakz $b;gQcWWfې3FPSeF(l I9 5Y6E <5V^@ulSiClS:*iYWRUݟkbJ.9F4 eOt GlG2Ƴ^_͛2Ԏ-&R7 ^rq8?h)-ީ'iz˶(_&*[%%ܾU^m0 PHvպ1Mn."U7CAp+86`1 ʡcrjGdH.3ģzDF(P:6skD=tTǟ8NߖyKeu bY. ovPDؒzh$tZT("`8u1W_Ë0XHsWç:6C d{ߤC͉ 4%4<K˭͕Haʜn\Ј9差ZV+R'Em,*[~޽D| jhbBa]k)񋂒aյl:T)T,tOlYH6>a~] RQj"xΖb&4_5¤\B˽s̛ת\_45dЀzƺܐk\5U_Rq![i3Q^ݘ ǫV*fm) ºlzr"~(vC@Tushm8;E ۩:I{s‚`=![ K^Vw.⮸gAR'"F0uڞ)kV)> Vu%0^(=?MkSmn] L1uiE>0R}SA;%f'-.~L|qxqTP{6ꂿS x6=OEdL,u^w'jT;Ca*1>h\u` mtc#6#A+e+_^:,Ψ}\E̓^0;XHii ˪`jK.VHK UeIYz*c] 5SUo|+77lt?odLXj F`yQ|}o , p,4&$Lw{ . v2gHRtp2m@iA1fh:?o] 9 K- BE~H7LxIuPIopH_]YpQbQ?x^[职lroR)?DSjb^,pFKIzھZֺ%4c Z;N`|d+,)K8qx3Yf!﹫OLUj=i+07xRI? g>U:e sWf{i[pM ]#y%Y gmhc8]ܲуf}|HBx<ю򯖢z.devTR:fo_ȋ6Q EI5AbW8<;)^M@°}B$ x ,LA 2rdk$jv fXWY՞%uBwlBp{v1wU=>\!C3"xf ,_ h)jbx z U']%p^Mpȧ54 j,Q֙qddzNz iRU6.i uFHd!:p[U]Sw輋cӡZ9XYW o{i;8ǎ~70 ;AeKK_`6}!zKTN n(o oq>a>)/= Xiެ8tq~pAԗfUi]  - ZR,wSGm" hLoŘv7aV>[WH_&0mΉ{_Hdro$u:T]5QκQhBR-`d0^e/iؓɨ8 W݋W3 HCmU!)vXYVsfDoP4\Dl}' L:-ʸ2Ah]|WnӃ ^yFѠ@=: r;',w?LL^I=ph5}VQKlHNiܩZ̳pCۧzJ演I~N?9M]2_^˫יִP25dE^BHhՐF±%=uЍ?@d*n*59] {[w3/״Q)-/5c/dPBvsD^ڥB*UX'OlbN1!!bCꐢCt&rN,Dff'\ OD=P.Vlhe~++#>Qm4R7c%VvE8N󈟒+Y 3XFp7PM;^'+.,Q⇟J7n_[[zm1"Ot8~Q"y]l%3CxvgpHOw0]= ~ϑ][:(L?j;̮R^rS:Mp4/x>Ď#Cˇv֨X?U?C*JcAw?! Qc*'/xu?TINv|*sPd֗.pWVIz!9ǼXMJl_G*0#Aҋ6!XrvhYZoMw~rG=A$nל=Tqt!v>|S]縜hL;ydn8ՙ!D3@!2p&o'LS䈂TKu` )vc\y[zװc|r^9HX,;k$?ӅvR"ĿRV3L:cMXj;%W/%T5|ڔDXP'"{ 9sqU)IV.[P8K\ k҈IQp-8:[{M62 e: : tPƏn)U$hhNϼ7MVn%#YQKc[%f0mx ʜҬmQ`T W}~0xVZ!r!R1َ{;1%zYy@NUZT 3NU6W#[u5悷$tz.RyEsQl Rm3,;Js'eo"B?FjЋJWc}z-qiAZΓIJ_# 4)[WGEXpGyi ^*]@VhnfaA>~r{t8CKhLQhF>6cc.DWdqǐxClBmCY+_46UKJ4t;QNa߽D + mvc- ٻ7pH@3] dʋzhbЍ2>$`|,־_^u{H咜pG7ܡx5]i'9qe Kl͖s^n yt@ݹ29ˉHe#1ZG.[cXCL@nPkUJ# spZ;G}#߇[a~Q/Ol?ŅttT 3B92ޭוͯ4؞¬/8OdbCi;7%@þsX5Z˙Eu g)*|*:ʞ lEYV8 OKU-;'`k3-c>X,Nqۅ$qI65ShgI;@^} y;0ƕzAۄ-֏$[FI$/RS e1W RI {[D\3L3%J]_w`ŸΠ®W:}+}WGRAho=+5{g1Bź0r% eB`y(wKz^L0B=Q#wDLua=}imC A+ u0PPzA @,sXRL =Bޠ.:PҘ" :GYǣ eSm]@2)8>9Bbqw;2ᯰ6.7_Dž`J; Ke KD*Qyڻ6pWzo1!rsџ}D#xпRO:l[}cjr`E1˞a{]^ ^PO?$tv ])PW'~{ 뗽Ict`ʕa1hX lXu:ezJ&?H >ҧo-01V#a:F eLTRmhw]Ev.h@V@oPTl]4D#p+z-Lb`i"vrO6F9ZZd.v ]o?c!Fۺ\_绕LeM[/ 5;c6׈%%/]=M =l&lXfkYvUڥrYNp{?FCwv4ץ[((p.󂫞C7-!&yZ[̢9kd) yTfTX%$W09z.Z0ڍY׽Jѧ{;̌C̵1Q3_='!),+B{}ڧӦSp%-T(ۼ@0-erM? 0sj"q a >v=\! (5;iqq{ÝvK/`ÕBrqyHr݀b{H$j+֪mqXc-[z`E NCZoS`ARc" SMQ:\);mpf;E<4h2=,|.r631{E-0ޱ(TځH;CnVy[j|?aWVF_uRZ(^'*Z_F[Ab֓n^@4`&;V҂ {#,Tl~jĩ6zM2`=F0m5ҭzuKK,?l[G}aW3 E,eID}}a8ҩ:PDoAX8ܛB$%8%{u9HgH |jIյ(?_XW?&)]" ftvg^~x?R;ɛjF#(eRkv`CƣnBfL/L~|gB>0ʀhv;c(?@Ǜ;b% _jC8t+;)D@g wJ1k.;9evSy?)˺X!xlskM+@ /v's;oPq%T^dxKQ?f@i^L9oCz]\!|3Z*SV4c.}m?M?7Cvg*ye?Nd Eq -U@n-} y3vXW覱$9IZ@u* "B# CE눣o_i{q2-WMYSuHO1C1!f-/}W ~tC ^%:۫좀(ʧKqK[dQ}9/4$ jԟN6ZD#R?h\+OĶ(jN.鋧$k !r0&\x#f0m;Q鈖CefT!}oVg1!%VGF}L\@ݗ%P~}Ⰳ,kXp#;95lYNM%=6XJ*yG v@_}\N>fC(𴛖z8?K>f]vÀ}@ThN n:2-?85NIȻ"NsऑaN[`; "_9v -)y'ĥa;agLD&hF{T39|V-^Acȟ0ٕR7(cktCDTu2chQa rΊ}m[}[)pN 5״!\ 'q,ûgF0o)S7`V/ZYm( $n.ΎkkGȃ|e _O _#_/)8^p* mǪHC VNq.`} Nk*RVnpssr;~ BtT꩘-z\ U}.`IO/>>}hGA'p,|)GT&KXPX`9Rwj :L fjb)Q&/nt5or o*2,?7{ lִ"Nխϗ*f=G3_7QuKxB!4}tkY ȩúzkKx9zUXLZc[`Xvq!7ʉnm|&0_c2~`nHFHM`J3R]±q}ixvxܱT%g6"slY$]fx(oJT# ( Gͥ[qxݢ s֞}.)/Swǎåj;:xx,ᢁ2<L0-ށ9徝 Trmiaa{بᄖtPӃO ZsQ:Zծ 9@h[lM/,cQP.O굥h.>zD(d!]$ŽZU핐B[',MB$4 䳼Cu 6ufh}\/!6SU?t>*cLucR?_+3[G#&1c`ޠuIA 38~6O-w*> YA*)9Se:!CDe_ISIJضл ~3ǥFtZ\#T)pxDx:.VzmE?D5Aۍ%^2x{Kp5\ԃwv9K}:4>sƾ{9|Fl59÷~i)k1U5l/h ^sT(Tr>Lk$(=5U"Y7wrao6yfɃDqPnm~9:[M#0FY+I^vZc G x6kfCrq_ڏ.:|V־^໗Yx5Itםz O*|?KGY=L*c^-R[7%`LqUI H ɴRU72c 'PI'(O3\P x,_NR +5 1aB똸n UۀkXHK`ٺA4qi- ͣCCq@ '5S]w=>K{+)*8f b#gĭٓg5ո(JgC$ uv!\vLPBҧg#JKX@d&]n\S&c/Zu ?#ypM΃gYӻP6ʅMUk^kd`e%>+ <.Zܬũ9u}>Twi藺JIW5G{ڦ7e@57IbDxsY0u y=,kϚ29+^ @ '5g$c$:JL2Ԋ Z[K cϱLLE,'ѓBϤ{搎M)@p^x@ MXʉb"3x G!]Ps-ꐉY>ۦ>ƒ^!;Lxe'j/*؈]ȶ[)shxl0p;(?'"_b$g[LQ޳2os'—nȃNP@U`\y?WBSJ[r"ad2u"a5j.Qrt6PiXQJ"# 3 Nٹcn(klY2\'qA 9G$osknFKvK|p}HaǠ5QY!k cĺ K|"/ϞFz\/Jپ7zzn[}鼼 75 < ڃ(C'$Oc#,qC LM6(~_<:#v * JjJ `{<QHc{A?Ο#xGKL>e4BA l zEGz*eO4p\oJ4\2_{5M& [81㧹nC2ٻAa(d`:kg[U&l/rDV/OV&-I=~z<ބP~;@9 pz|cJcTvHď=>\Wzc}"Aܕ<:6pƪK^!m6貘V .UH/WbS-C.xc}j`3U󹏲tFRߕ΀il,!wC.-D٨oKNm[/>6"0lmz!r.$|a #?AMZ#Zt;:l9TXI l'Ş&<1Ca7 RPj%1 f{g6 U!` f?$#&A LDuV;]_[iG{?nI%#[!uU=<\B-A 1jS25gs޹ۊ~JhZEn<+JhB wy$ƃS`6z)b/Gm^լAbC\zaCY=#2Ǻ}(Zž?maF·+t'lyk|,ʅ&ַ*΃@B'?&p!#X! ץPt iG*]OkeX K;IܽKETwkNc}N%V.b\5e\ԑ5ד?iWR]y<Aѽ-$O (Jɚ_+ їq3}GRAO'R\3NԽ9<iՀ3!ɋ61E;ܱD&̑qҙ~@e ^V}v ֑J&i e\N7Ty"u) %4+et"9x`tz@OۉQ{Dl1Gjt혰рv 2mT9Pa3ݢ9D̶6ҹQܒu\k@t>UfAaeA(M^?K7\1۟혜tX(bʭ;t_Edk#+`!9M֡['}􍲕]ͩCy$cpD!݀ue0>KlJY5⅘*NeΖh6eԽchpڹXi緹(#F2+O Pz8]PQV(^ƣZsx&'KUtQ wi&\SwW{is3\1/w~Eyf=1Lz}9p Is]l8bb -+`.;<>/CE*y8>V! DzGZz> j.Rs6yʃȜsUY{)9L $]֨m@zڇun [9h { u(=<']`22disBQ֗Lp ;}5c@qE:E^!Bs@NiA3*j`h;6VBc߆N4oS0O/S0#:5z Oe =^<_'g~ņ(ayt4\'4LuRi^dk;́/Ա$\A6FrʄqX(*lJ|՚m]~/Ӓy _QxI1 Mp&e҃-lu*ŷLw&_G␗~"QHtN沝AgrK{:YF6@Rݘ,̀0hl{$QBhz)ĉ(ajU=P= 7)N97CJ9lnQޯ#쵘BOxGL&8B x<8;äYApUHN BkףAČKܱNp=8VYnO628S- [fh 11M욇RL`)z_Q0c\jM&[Nqұ)-xPdF&B22NF /y=-]rMb N~Ӳ<vєyT“oqwnȧX8KTj! ٍRtAfkSP|ؒ[A/ŅG!/ 0B524-mɭVϑ;>skQ&jAxTILHxȂ#W#x8CQW?ED:Oрc㟇mwOQu3H!K%A0cZXq﬷/9rJŦH:Z/I@ ~+?Ajޓsa T\ ݜ|}z2W{GTW8}?j8 q,n4"MZ#~~_jO5Kkܫ yȯt}3R6Th,s6# U8wn}cO_MK5} T#RŐh]*xH7+):Aiy\m%c|rRzboTf$Q j?}Ӄ*86_!fi]MVuZHHq;fqUY>T ڠ.8t`B4ʪ*zi!osK5?iax2}rVjY t܊;]JbzC>ѴPr 1Sj Csd9GtBjszj2Bḁ] ߔCJНp*̥ ŁH$jn U"54 Ecn. 6X@4gl=:\z`[L4-f{jtqx#Cš;rKs'A X#RCSW9ENzlZ\@KdL7ĚG2xK 8wœpvBB8tR\*T_t\hCTrU"a((ɱņ32Zp ͘R?EA@2>ǂd dlF ( +ve0Tw u[gd3:"3o|Fq[Y3pi΅u Fh u'emim?VBz'x#(0K(Ah\Cn֮~ b+1dPt]ܖ*P:XH$p%xo%_H ̪s4 BS/3!(с;:\O#cqW5Sfh !AqzSZ6rۋi)| L13΄4MY-RrEɕ9cB6Zs=.HM=9s"F&je'28 5;!z&;&(ݷlgAP ̲D=9W6~urQwQۮD|`$ #+<9"F'L`g^&i(6oI29J}qO?tDvvQܸ&t̉kg~j$])n;Ͼֵ*+0v>P0L9d;{)XZ+l_h4ZF,z}:\ɫ7;.GC"⃞8ָs?|[,HMD _+f8;!"ۀ];M˶X႒ތ (,߃A%Ar.Xq.XG:XW[>'mf~$W/*?W* rњods|M㧃 z*|?X)}6M;%+쮮āсǔOK?}K2T%} ?o1msf^QA/zn==; +&7^ξ=BQ=칌ݹbˬXs")ztJ T<ͼCy+>r}o;\957 goJ0/Ѯf 5mpެgwzOpĿiBtCB#^ {.F N^1ݵY`i)? +0ݙ i_,-FִQ'[Ւr=||wKRM':D| ?Hۦ9x\0fҖǫi~lPaNKaJLЃǨ8WJ5CIE&][Nw4(.⊴!2z&wrFo(Rrތz{#Hj?dNnDWጬPǑ+Eװ:!!Ȃ=n%fMq"d*K⤺[rK3ѧ9Ӽk*F7[Ɋ7n2 _Nvj%.؁SfYuR4vU{D!6.fJt-= oO)2ܾyşUw !N16epXuj ᙅ/>Ӝ0P=S ^F0PwW@П#=?;q9wycf8j?siʕyzy1]U,ᝠkl`ӗ)R,tvUjc4O ך* |,, &zt9J|jSƨ<' V"? h:v+ _^K>&-5?ٲAl]RЛ9VWa fUp4,` Էz3^dmCzά͗z=}yֶIISU637r~ 1@ wwx[:gANan>JG8+Og{ΩjItU)Tʡ$H֖guv5n{|*c.Q^llb ١_k.Z6 ;E{ vq$fC Y/H;kwiz$d4ע{qztwIy߹V2;*iTh`yKJut\Zc8{ky!Ү->gsqW ٪+z#Uee񍼘ZX7ź{aG*ɞ:Aꉰw  QUoN۹.|tގrmi?d%Ċ S7# $om\w a郜1)[{u }!C>&rδNܗwXȣ5՝$lrVNw{QU,rğnU|ZUj,1XpmRY#JfaA>5j򺬯= 1WWJn`N. h}M!د˖% OSk̥[XJ-82.?BgRu~WD^|DV%T!Cm Ɓk0,O߱1,./:'>׼];/Y#B*뫖Tz?0$ +h!?~&Cc#="Z{oOXRsհbV[=z^%:{3wPZJ- ReXhmJke:}d#s_fqOD5`S}we 8DF[t{M&;:ZBL5¯yURTGNZ ۊ]|6(-E@Y+12L܌KT$e-y"u <  5!(]P9glMq,:9׏ӗiȣ>N$QhGo a&i~}%suI/RqCW6%Qsvf3bј|= y%Adګ%].vXaםW)s}mOcQzu=ם}#y:U/h}~H&Cn;hT 9ccѤVҋYޜ#G<_cMgK`6ͨBMfJO->nss{Y٫fVs9+V1w~iMCB„﫜a,wߠ,sg4d=OmYu|Qz_c$+︑I}ݬ sPm#Uu^/Kx=9O+uf\Kw"7YxZwL+G^CG,i}A80>yHIq075eQ' GTS]]zz$>8)T<绮vYY1]L*^<,%3j'gjNq}l9I5t`G_H ZiJBR0a gb]IWmH%G_$)}6lAlҧzlӴsGK`Z&`L\ˎQ,b%xWjX+qk}#^k$Og*bDS[I4'{L{&0}ޑ$@ ۽tȜBO+2|xZ6b3=h#^^ʳ2Q/yny 7s5םFBG]CIvѽ7YD/~W9.9# vBa썧Jʬ7nqنQt(z1\,dlws喭@!CKHǐHuc?>7]zu4.@{*_;'UA(?M|+mq:0V zٱӲ8W[YX$lxmu2u<9{i"eDKKؕsDT+]E(X'4= h"e?طϪM4 Oz7/(fɀ37ns=ڏڻevL?gw|mwk= g|dr0:RafG3G.ψux>RhR񴹌͒T*ve_,|RSJ҂M6qij#=HWEciJIoQиY9Ijf!inP'<ŋaR㦕'ɍNŬܹzj/}VZ[&T{w``P"uˢJka` 6(*<*L3G̞kZrvVr1[dl H7Ⱦ[uLUTyjKihoi3)*[{`P7Y~+M;ْHY)KA.n6][ip[SZQ^ST|V;DdzR/ ?*j5W@Mu^2<)=Fxw^mkK)mJZzڭڔ>i֓2Ԍ47# .,X^|pc/75ߧ2PJzw-ZzE;Mpeр苠N┌L״S! -D[t4馔|HB$5ϔ+)ܥo][dhhSPDB]Ρ AJ2UsX3_]?PfQBD.&nP6OH݊cWSfTS \ЙznwRJ#//=8jv 0Qi24|îo^~an-ISʕ= XZ{>صHi~'b}Qm4E KtIjWZ*E5~fS?C+3,_dtAԹ=t(]RWO hsys $ LJ:>?b?#V%)o&#Lj(6rJY5%fh]Gya6Z{T3N>:zGOl-Oqݐ۔fynM(sS,i)% yu|8n~'$ty+\pS`jLb7nAT=610eJL.[TG 'XsLNjpwD\e*Iйo6oWTspLj4==f'&Lץ[3ٷ e3Ǹ֝X~^iP[l\iJ*;CLba7ݼi]n ¤u^9HNՠC1+rIljn?l,E]QtFaH[3|oM+ƭv,I3$!"V| .HW@ .6#5q|ZlcJ8l#t.˶zSLڝ#7cRqzә2ſa/ar5 `??/i&KZ7}*zLcEwb*Wo> ͨ:Ī,3q5'{(:-&-vm`'DIY=#Qz o3,f H5;4E]YߨxnVf$z"e幞##< RFW]Jʣm0:a%1dE}IKѵsQ;ss ʾeC/HҶ=VʅT3o&}qaGo*ZNpR<.5sFoe_-e ?zVHgw+K*e",;fS:RSj&E;lQ`L^9b0Vgf\]etvUxX]ON9jE\^9)U&7!,hcUoy+d˘.(FWg0[Of5-m]c_ ^ :ttkEVG{]z\{أ;2&}K#,zcX4Oˢs 󠶉ML&ˋ^ pR^qS'P9{MV_~:C<3ھp(G`rF[~0畚c>'B'*뚗 ֭Oios+]7Le<+Xb+g( !Ŭ2Oo(ԧ9閧#C[K˗'{2ҍG8&~)dkBWOgzNw=ۓ=),Z<wfXnȐ%s7^ysKME bQCQraϤ°>G Jbn6SNg<6;c9K"9TI^OCݼnl]h&̣o54Ѕ[=96U`Z>ѡ}i' ?0z㘭G 2T4A~71Tٹo]G{Z>ŦhZݼwbh^֧͛&v]J}uARQ>ZpJZ_fڸbeS!A1EA LwQ&XǠ􂋡#PW-6[_y5IfAr,s$*§]Y64g1J]n6vǹp3USP&8}Ȃ4)0ȘfDzlT椳Co ϶긓Ha]8R5ȩT:YQ II*gU<|KIL|AaOgMgN~b6n9̻>)MޢPىe]* SDBb,; 5lǩuҎP]8AꦆK? SFRT^ܦˑh@۩/hca Sv.ave4%R%<":*-<5?^HM@\i\n0\elX^pd7jƩW%.$z aBJRc*;0M$F+)c=rdЪjb@ ӊ+or# 7d.JL\3}h\oY' 1Cr҇iJ@,YhD#0 sbDVSycc=>OTO"MM[p@sn5O m3p&{Uץ'3c8=Zо4!u%tL{7Ow-CvأX@*E# ea&C٥ѹ 9 BK+̚& gGf'wŇd9Rtr@/dgj޾67ӫ\AN5؇敍1Wlӓ 0zp51e~ߎd]=uFdjES} s( nfh^P(CApG0H C  " GU_˕p1P Cp$P(  @A((4>ܐ8H4qQH($PC@H(( ap P* BB<^??s_(( Zc?`(h cRH\ wPX0$#`h@>pߠG\^w:_#[O_@4Xq?\?k'38ǸqWw=0Pt z WuoB_A?Cq3MPApz׼qJ.rmbQLtW2/fp98Gu] <8w s@8o?yC'.i*c qH^:N*"-kG{Q-!  wu# 5!+߰"Ln,X!>F< f f@I~gY@YPi(MN< >$| ~ DoPr B }P$ %.Q>(DQ0EˆK. #.Q>(gA?Ht] }v?(DEﳋ" }vQ$.DE>(gE(f]E\}vQqbEQ%gE(f] }vQ$.DE>(D~,JTP>(D}vQ QBE1>(%D> AldN )d!S~c" L2A!k&(d_3췟췟췟췟췟e~i܃7`f*;fC0LD0 NC@$I("+H K22`0A 1sܷ~FNؿ#J#aAkHߵsĵ33ki}G,HP Fo) b5} !dW8p_a0M04NE1]$CPb +``W>#àD08~( r| Mhe1B`9c`h80  ?? gC TC18A8 ]! 1$  pLcA1$~ 84p ?8`0 (~,0}aD0$A}(ay s`}ā$asFAh8o}`[& ,m5 ,.1(AY \O@W@Q WQ0>B0|@c<= ,$a?8 NP0$>(8 "O I@̸B!77s~oXp&np$_8 8N#l0|_pwB(0#?Lck-|0?$8 &t- g70 7(F0 a` `.}aY l((Fa0dcП`{8`k-sBׇ zBsCBЄIB ? ?g -!àcL` Ph²3O02 k2*ơp*E"a8n ?߀ 3 ?p* PZ04Xz``pap<-an9 %p<$`3J!8nKCE8M'ap>)n}&#+eLRۂY3o`deڷ$PLxg)ʨQܣw](H n,pf8:7:+el+q[P=-xqQEb0ܤkۊKxwx!&s"yI2o|N"Hݩ@_3'{ԛ33Zp,v׸?JRJpY4]ƽz~'O~`e `rfAuorg`7vq/lE$\\:T7vCÖClY3]k/Eg(DɩUտ)mpoJ{|e+?7掑)#$GQ;B'G Hp>1_w 'H@ 2ϦװX_ۿ7LiG% xrOi`o(L3/0Ue 4`T_zNT@wnԡ`!mJ镄p$[Зg:TWTFVBUiLauMNfk]Ɨy''UdC'^jĩ<.( i@jY{B?ԜUHfF;%F<ȏz'GN!/G%!>t}Hp <f=-A"P/@/JϫLKloF-7o Cٺ Uǃ[%L$Ը6I/ "rT8}eCkRxo(;+K- vì̹3[QoeeVnX;>o'bv *MԤұ ~Mh"CJi=mXJ9\zfY6㘋D?io2?ݚH^aJs[UM0p;HӶVbu>Ba *܍"}Sߌ7wj i9F%I6]bGdưmNџxUi1>FffIJfm B a>qf ռ- #))]Zggak:ǿo{4^e3AI36a$m&:ö\eyFdzu.Lrr⧀PH6S]иa-"eRR^UH UaEx"b\)A-K\ŀgp3,ħ3}ڤ O2H(1Ƚ}^ k_~9n`xQN+Q}׹lھ-mt愡^}#rwsY+uA`jy{oS$84K[8=<ےfE#GBjG.tmvZO7*4$KP@,iP۝"Cy?>Cb֜ *meݮQPٺ~vN͒tfH?1!_b4-:V]94-TՓa/ ^_pH3/2.U70~#,CGYEX4IJF#.]Nj$>+ѵV#N04ZD Jݬj>Zrg#!F@>d,ڞvL6l8xSJ(3 B-j|>?4*6yQ_!(P˾|HtZLJ ZLm&7PZᴝ(񫡢P8ydRidӃRn !6 w,oCHlߔ%iU+8LV{U#LpѺ$?Em_s]N*0Jy^WׅruEd^>#C'% ~xpOuvauKNwx{ ? d_RĎ|oӶ=)\ҠUj 2"gʑ֪oXmN-&B&kupr%:Eu]҂vU^9\a9 KUJ&3H){ Q~ ،P9 t.6ͺ|M7o]P=:T|;L@U 1=b}O%C̭^K}3J's"Ϸ\f=?K$.<1ӯJi5'U (/-&E:vGqUm=S7Frrd҃x˄uN /k"t;)'$:> hb zP=V\@Edtkt o$V=q_GS!(>AnGP_~ev=9tҚLث|ko&˿19Ci3e,6xgX`''ӥ5 xuY+S,77ЭLXzs=EKq;<|e^J9-oXx1MYI~CRvA ?FUbEDakADF*O NT۫#(E'Uړ pY B%:g./ڿP-~d 8ש _滛!_V SfPОRE6~4z*x,ج6`ct#kP5ffmqq9EeV}t8__0F0YQȰ-ۼ;6MYѫ~xP1+B B0h9v o+o)_񯦿7X5rCC@7r$~C0ER"Fx:KKؕZV$$e:rtkOG׹1lxx7H`姵_3Awi5tfsWW&Fl~}~n56Np" {\^G^ָ{EzlCsx`T2☣밬Z?I2d7%- "şY#hn1uQqܘ^h^b'Оԕ^1Ҫ z޸4H@dj #AA0}xz"⳷{t4ٶGhEC]Om`Ҵo+]HgȈcvdU,wB"^RPwTh',|]osIԷ6Vt M[`i,^h ,Cŷ<VYʮv_X}A-X6$~D`/Um`Kz#$RBY%^7TὍ6wWag1Y_GZcfR+G VÌTCEjE9X5ӱquԥ! l+.=AyMuvɅ[/ZK -)3.!-b9,R4;sS SӜ2'=?&r鹏'xG#]nfHjUAB"FDwNNU@nCCaBH谕qeЀ3ך Dlʦ'aNm(6ƺӔiU.$PkF[;cNA3|y|(IS'l{Ͼl״/$$5{񚔌.'%vE1=50QyfꖛKK=@ae >Ba-n6x_vӴ00vm?)Fβs.sY+3:f.Yj2%\Sgtj}( k1< iYHu%gt} \h{%3c<s̭!3ZܱJB^0 j'tt2ݖwrm~o%I_.|z/88żc^Iek #L:L+{dc?]T]%^w,9PV}ӡ{ldJI^d03 _.I$KVbX+ro0Id~ـs~}bFsב6owH{]jaxWT`0 .Q:eAqGsZ< KXk\A25Z'!B::hрNr'LNo.%%=I,pOF uAdroY5H2'վXm,bqi<8- ue)IsDF #}*qm΃"% 9nБeNzkʀ/+Bm8>NG6V*c5۵yjmTc yC`pLAT3O[sIƣ `;R qnzd+NEzH\ݜz_ >JK gV?~ڝG! &D Z{k1N1.f]4 pm]f Z)F6gdYWqo9TӇLzP˻91`Լ7ϝkͷPز|2e,3Ǜ"uKi+muT.>_e>v%Ҋ≯2&2kkA3aa'x~ 업W"vI39 f.y)zau:tc8%}Hw⯍Kv1#d#D&+rS"/.}l\e;>תi+I6]TȔ2рn-(N9{m]̇LcG>r-V3|auO^^fOգj&6H'\z@v1䳽e8Z%=6XRb|ցA2z {sj ,iƑڄMejGtI}3w:`1pݰ_#aܟt>]|T6LGrXW|҇\[bό|\FXբ0'`Iy,v~&#V)|g;=vn q} MhV|*pyרk^aI]Fun6-^,.;GkiC:+0(Eʚ||C1\5%ys-![)ZLsmZm|լu/9YC҂ f5RmKP"=-UЭ{JLJxS?a( ]Cn{i8E9keBy: VSHz'=yBdΜcڤ"w89.9-s5!mI#kmc P՜#$`<ɮw;sj"EG>x^%aG .mşy;}_\ŸKϏyq}DD#Wy0#|Dq1YB.e#K@ˆ=eEFMH|@pxoHфZ𥈣>>7.dm_?^+L}zLm-@7 WcQɤl69TzʰxDf>ψOYsskf5jvF<3}l؝ǐ?]9}L0zi9o3[F+/*bl_VjR UUmT ZZ,oF]o]OɃ k_UֆwB8 4&.Ŕ#'gTFTCWgUiR\KPy 2D*`Iɝ%yO鍵R4~Gc^T/IN^iQɣLKآ,rI12o[``}3Lߋ=[ 94+T<.kW&c񋁗9*}8\Wsf=II>u,%'4U/Yz'x̺\6gƤr>cT[/۰>vCϴJ{Яv;a$#ţ# \$3rz5_ itH ϒ,p}Hڃr{=@JKql>o"o͏xN=JMዽr휊?z$?(+4IS(4xFȇv͙u5U͌>|Чwnb ^CMb /qX bZhYڥPyG[07G~%?lf'%=/ujbg7#+{^mq_{;pݼs?9S֓e=8~O{qv7&h,W3pj+nZ7F\GrAO He;ygyK/ɳs޷%gJY^wZ^ʀщC#Z]\"Ȼ"at^TM-[ zU[TzpVc2\H^ߒL1!qw9Jq֭j]Qq"BO!Hf /{g3gNy°tI~1 8 Ger!)C"SOd[>\[7LC{i Te ԑT{UžΕC|cLXxb`:e+%fd|SJQ3JoYyYNć;2Ɲ8wQX*80=5PBCKN( *~Wiv7޴ K*i̕7A\ٞT77ixu²dp㸅jA)Bn4/nuETGj l݊q 9W]o|iKV7 G<6nhuŋfpPP5M}^)fvqȠgI |`ab$h+_>NFfJx_FqBR$e mϡx.4F CnJD>"I2$.9b3^H1>Pqj`<-Z >#-3'\|QFʗng D$,ɖorZx֜ըW;c^ LU 3>g QjSgWڭL>e40zB[顦r"/|4|VY hk).}}@2`xx@ZБjvGt^$E"i0r~k$q0k]x2aS+<]8#\XC:MЛPR6pJ\Ők.D&:vC8*Rmr$<C,`8k-\W1V;_/Mda44;};j{ 1?u~(A` \L$~Сx2L"`Хۙz+쇘 u o7n5SnS}^ xSxSUBC"Dm u :"3] <rcFYk۟fdk\*Pe>Tp3sgûυx8rcɣs'1×W_2s^,9j_VjV5r4 4 བྷdf=Z}] 8Y%b@3PviQO0>~/?iV -uB $l8U[ ʲpIQӮ.JRH2~j2}#[B/vՑS'睴U*2}5~n va퓨n{;(#KR<ԢP|v-4˫=}Ȓ0Gw~4PCb-U^AOgRt:I# 2ML#],3҇'.~m+K, k(KF}j/_;srzв]. 㲎.JLNndդ$H[몇pٔɡr~jmQ4 龑19=[WZ+hf<%mL_zs!amd!~ 玳^2OY.K4O.KcOZu.qI{+?[#z@?0~6zAyhg]s:+ z{6n,ٺy/Zvgo8vPq#^JQRiiR!*@uƗX ==#0,j=G2Æ{O/ N|+ J3dsc,x2Mg+2㗿r;1[\|] ,P㧫 `:`08%}g_e쫄*tK*4~OuW a*T!b{f|z]tu^6ewsuo? )b~.XOO+%Q4cܢ/vUtŔIdH}8H9hҒN!ɚɂC]y"#Oq=s^57n6 F;I"3$ AG# 晿<{9/٨j"pBxo7~ ΋xqQ#9#wlmoOf@9}?BfY,A 힍gn)@Fs-vROR V'oKMfc(&܇8sV4MAĤݮƮP֤ x^A\Tmϛd֐? dK\fzx^KDL Sڎӌt)0/}?_ΈK߻̱Q:T%Fym"%R7lovg0sױv% +)}Pe4lpn3Hɀ-ؾi4#{c Ŵo\z q7tDeb+M*@kZv{_#guƩM[Kk7s)9$TiOJۑPKjG:KBGm L"J9A:{.~Y9g+ġ`'DS minLZɪ]@>νĸ:sAƝ򤤣ۈ5$iq^NЍtR*C@IxҰ)@uUaUOnmmuCfDHU >~lrewʸ3϶?m؝p&"'RoSMԀr2w&V]$U䛟n`U]u@E:#+ daX\3x^nF,̇'s_uzYhȅqVr~MpF|ެ˶g Yw訜?J89^J*bU3f.LxF8+:VṐGjg;+0uyc9| jq+>F0]euoˏl^ZUnZ !9_}$~70mY݃e ,3*>l0I_\4ULdFs?Id(X $. e,TڑFə k /?ĝwr3:1pbJ mtȦrH'^byOջ^N>OPCn.8iYL]zib殠aj0H/IQV`?k)AcH$\ 0xAg90GшC+2ʬx\#_0 栚͖w'HҒc4x됴h+Ȥj@1gܒ@%ːBGނNi !޽Aiz$w̾t;.MN*7X{dҴy.faéi$1jLG#pHc+amKٜZIY2M86ExHʾ+:9~)Y*8.I)N[i-_酐0C_TݾԦ5NmWb/57 ݕ6 hXR8ýsQ8 ZB9׶mw'y9_O忿dݝM@1,߲?(ؽĺB*V7>dV͖UX+[>#U@v C/ {GON/)jt?`ˬHE9ZR;T[>-8=*#U[*0w[,,0:[m+G5%}((ӈgiё٥%RZ fa3Ȱ _3xz7 +{4H嵲g\Jz=kP3G9s})r ;@Z!/4O`gv"?F|y7۞X|Ml3GĎ=E,fl?D[SBi+ ]rqzuݿ@ߓgon~^r7׮Ƣu5Q-}[hg~uAܿFE.pu)r]` :մߺ]peXGblp?˛R aI'r13pp,` WL&:sY>EO4 RWY_YquZN ]iMQYN|)[VYHZ,kt꽂]nŖǀ[7A"lC qP@ ^`bГ۰v[WmÆ\涵 }!h@<+* ӔhV#ޮweGC}J%}Ceiz8K6)B s\N&DhjzռJu.'a12@'U$}$׀R@V27m(M DjeḈN*R R*$eF}Fm,9 {&EYM\)ɱu(Ո b{(/dUԳn'iL(|hxi{OZkA b E%r=nէ_>((U wymL4vҪfGT!N[KU6SSbV̩-$M& qD(%(al!z0rn[FDK !T]@*]BGҭcB^MGKBBg,y J721 QnU P F4zl $5m=W"Uֽ6]{⟀=]_>*m=G7}-gxCg)Բa$$X"gQ,\B̂4^0pΙ(h;k䖬r /1f l2)vΗ*~@eֆ4P[&/z`g5 ezaQ ٶlXj0M2[R\yK:m'8KϵkBj0Ky {~YoӭMOR꓍I#bL#*[o䥗$τDgZbS$2)8lMyڟð1V GONdv&ކ'PKE(7BpdpÂ3SZ89/RuwnzK7+fWrH7KS֔fvϳb.rlqK\e}v,2찱o1l?B]b(p*wĽ{K4OEPwcJ076Bc҃7T)<IE!8& "7?\GM2sef9-`M A\P^'S"e_$ TbQ\Y~܊uS/51Wid ޛ tO%,PQ T?/-sǢTA*8/T5K3̍U)GrUBzPf7] Ldz2;>q]/jP'eq( ,,Nr_ؕ-q\P3D yomeg~vt?酶Mn{l|۴fj:IG r< N ˘ P{S/9(z>QP,m IZNׯ͟6$9 %Z0 *|ij'&^/?q+]LpABΉI!$ P0 .}tw 8bY +I)8$\ }-%UE[eڍQu͏p^dU&SgܑLܷ;VԵ>.Cw2wKR=u؞ط \yjQbúK|5Ӓ!2MW|ŭܗqQ #ƞ듦HK-2}f!F|Ze+fƵ~b %ј! W=5 kcbM56CKXN 6-TŹ<$?wlĪ Wnhc^S嘅+N!x|G3ȝd8 KⓆo[ǩ`aF|q&=pBٜgTf`YgϬ|NO.X:G~/e%U\L]Og2qϭ>rB/PЮb̞ ( kD{v'y&ʻš;2/=?SH(kr ݧ?[=ۙ7Q?m ѻCǮpE-'E(u#üڧ^1.1~5Wh#D 1%Y :(1D 5Ƭ汃瑵Xۙț;Yo] 0qvtM27){0eZbf0"}͛v㕀 &>`\89>?ߡWlm>=R{6@ό%K<4K- \}Uσ1Ek 1f]:r<~vg JE˪#4e'ٞJX@fAqN7#_!>6QŴ eąeh:A}&to]% AD\Ym9' EGn7s!jږש)K0İqӭ?^Wsn ϧ r"K[F \8aR;{G{2xufYBΘ(?@7ݯ;Cv2AN>uѳ"<Q FRXAk(jQuڌ@賠#ȪgYofK 3?&up>Lh\ +20k]P48l3 ka`/ *Xҍ)gTMɗ 2|y)\nU;pEL9A;م^_xf|O(پq;Ongk(!oVNNc!{iLU}ֳ8tgx`!80@㗗$Y9)?5h[M6@8w5'5ΡF7UQQ.E3MGYf-]syQ?0S?4ѺO)\ ~lbXOyHs(1u>՝uO24,=ѳ`0jyF,Ñ*4ǻu@*OgyRʼj\Ley: .'A jZDLDs!˹E!X iUջc習mu1EvFnu;H8<} +^oq1%k7݋!s$KX'3(ǿD}dvkjj|cMwU ϏpMXx-3DܩܗfV|!E99vZ;(:5X۫xc<=?,ݐ|r#cUT.JFߚ?\?acOg叻`ޟ0^|gTmE>L_awM>spNQG4t2qxP\W2`a3AŸqz%?䀇Oŗi|tQk dҸr䗨eoDYD4[gvLR&4G a@1b0ƌ[ q8Xv,XC,NGncJg3ߝt iY첌/iޜ }\}TdS-m.9p Vԝ|2ϧYa9*cGDX5uL83ŇAVaR>]?zebl4v7"MI<ҩ\_ㄤ-TL~]ت.|Α{ %+ݦ>#03|:]s; a3ѩ T/T%'H47yn6{}M aR_ HP~@/^ Ms-6T\PwwvN[M77Kvb#E!&OTH8O9ၖS Gg}$VʀbUC,hSPF^ԗ]G/O W +ZNG9ՉqjxI[Ht0$Ϲ=ͭHx[}BAӴ ɼjy`Ɂ䯅p<%bD%]Pa-gyxyRB9qާWF\ɍ޹G^,V!Ode,2El]=V)BrC#*}Q-NFu ,ԫwI7dLlAqhOtѭڠ޷ ctp2;^Q(4 Wu~Uߣ>Bu%{izXOmsw=GRE*[/OUe8{ūLc} W.'v͋^wЭsXfmhIns:jXPe FOyRlCFC~-'G④ ~@Ⱥ QIĊ戟 )} 2'eqd"`OVWts:+/][=Cue*P-1"v˺cpRbpk`.Yo"LPś( 5jtࠆP;vg?pGщ =4; "F1<I lsG<`gX!9~ҿݥ-kjN>jC2I&Ha$&nl-M`vfemSj|ɚ#&mR-ή+)EٵhPF*KؐA - |e"΅;Y}e0)gB$ȕJd|n^?iE>G!+N!tly/C(HVV:GsiVxsvBj__zUؑj}p_aqCMbK: t9&U k89}ԁ׮w煖<'W )?zteošA{0{ @Ngg{5 kǍ|;W5ap@ YN/OZR zg. '4"0+s~5{B%Fdcu/YxF[TA*OIKɿ"e?[!Џ0΂$ށ9T)shyHE"޻] AES 4b%Q?p͗y (d9 >{'N;wZ7g֫>GY}!bAܲ =|+ ꃌ2j $gبXĨ,j x?P`[r~ GO2NҒV&vp{,@S="O EG\%FjY 0,tl˲kMtn6^Zӗ]!V#%GJOѻO}7mtR{ky$mip,)=.pe*`zqPY1/Drٻ<#қ<^FJ3W]H.9BpN5l󱴰Ĭ,67yv.|#7PgV[$/0:/JVO`D1"~k"۷K罗C|&L^-Ě3fp3; 1b'2mlSa% SY¼8P@S@$w;rd -&^ѵVbHh֚AJ+מ6g5VګV{crl+R 9!Q~xtO'8PW ߧh Q>Aw]mN\lB5` w-=Hbp3U{,ݨ9yh'{D=L>!ltT^A '"UK B9/$O^[[.'¹W٥Ih,!l-I|)QeP؄E=//vzT\[+uprLoF19K̺M^ڧ\Nf!c-v_KV.yن^vNWKsbX2C+o^PE IkYDJGj2Q˒bG }|2ŸI+jތp)a>pDWڽ-P/VٽOWi'$m O8k` -MU.,SGnCEI$IЏꬨ5#q:+?[4\0EG8:v( 0fbr SyZޣBh7+ظOG \2h11ˣq[gw6u)?ԑ:U5TSL}-]c)+gaDsWa+WZ3]'tmi/tK-,Gz쵥ݏ7/Vf/5R,ż~::/$Bq"`9?\]$ξn5LQ7|GDۏy.A2ՠ=Y>ry5٣rwՀs{jOT0cv"NE`ʂ 8iO犼}wK6 ÙOPW>q%&cöe*YkB=8 \M{3򮣘o]P*py냫a`8EWT}vAR}zL:$d) >$72$6q6}R~bҬ:a!VߞyokImCB/=Z!a{c(zXeŧ*=-ylJ3 U/ ') TN RKaR땟e8 ^>wցUC2L|:J\'Rt<) bWMhdbS<4wq1nP{~l~Xl2vA$Kl{jv)V+'4*2Mf-Q#uRRpY2M2Tٛ+&^(%*w7 p,c:tZi/IC1bG,{ i|fqх{~:'{k*` Sdc:6ol\áY.m4 :0޳L~"l&̀,5;;ykE/Y`4@;S7M& !ZG^c b//,&ՕN* p]Uy0Tg,[/HC]|ArɦT|~ػ*PB#Ҏo_گ^~s6AUzްɰgF4)ЁZZd0p0Rk  EC5AB-XڝL|KOS LF@ ]"-,m\JCyxcV|o2o@upaȿ=5[Fmg_?^my0RDjF\.όcƍo SS_AiA]U~"{o\v7\Bԡy_lnl Oq̐~]E}MQ]cFX\qJYݑH=o.)+g9G/?C{b.,uohQf *{eX9sӁʗ$hÓIQڳR hxO@((wv}^xa˻^u@4.pԑS*2|U/:r<rONu,4l4[m756pPzq6SKQi9)@h*^ِrKԂU"[,S=-4{쭏{_v(KIپSp&[KfĞeU Qoهm= s'\/܉0YJ o ׶KD "{UID@4h-7qRP9p-dbvJf GJV"}Aھ'm׮_MKZe^ ksj9s˼H2qz&k>jryȱYꨝ<, M]\7*|uKc!*T]%ga^=V^ @hO9\%zbKmC" ,*ǂ/wxZL gxIu}X܃Ј/뗓.(}S ƯPugg/SmBE0U%d 02P1-* ^ x.HS2wtV̓(m_*/RuG:Cɦ M<~ jd[PUm[~hj{ɻ^ 6d8&CR~ "bgTL[(FHf}ֲu߿qeph$%5J@!y-Z.G"^;~ȶQbˇyHףCćI:-"hyj47's.&aMAp \#@?nO|2r nJVIPjKCζ_0|8,vi KSbH3WPx?QQ)ǦP/9İL^J…iգ7<{ؕ$t Տy}Y[xU'elrtj[ϗm|k݀&;C{~RugnBnX,6 簊D1FOlp~n.98-$?Uh8F[3(2l!X$WH޹Yn WԈ9$GCr9=%lp;o8R>(w0^ ۗVYz¢3 ]a3Uj$ʹkX^Sɐ0U1.os}_ګSG͊͢"+O):Unf*T]G]cۜTk#'MmX_9C ,tl Lϩ߁Q(Rbɡ'\r$7Itn߁i)Ciȕ˙VvmhpWmA#SކHRtU'S1 #AOcW3SW @qN9{-/펂y+勍Nfiu-D(o@?Ϳ` _xb9% +(ʆ^X>s1&8j`Wa<$2㫊8xѤJ+؋dOo7~@0| H>G}Wlx8Z͛ʵ1G(khցkDiTy 1;=gA$\V!Rv) 5Ӿw7эl%C_eAXG~ y}jZ8iΈmfW`;H7{Afwo#Ld=/=\@dKP zrP6J{Չ^gzN;|-1;=Na/pC z c{.\*?qj[$uf<|31 giK_ɒ$w0#6UּLZSRMsQv)=zC4HsܯȣSN tG գ3]=s;[ԇ I4u~RbT]`*צR-T~j h٪=/jNPJ~cSJÀ.y玥uw|0~+d8vkK`2Z2_sK&=xnyG"SKL4> h0qϠ9cZ3K9MkvW칡fVGXx xCG*wLע8Vڬ%H) &G?+W,w.գ5B $;|;ﱆَ rS+': <MjuEZ+ǬGx@hf6/h4wӀz T|;0Dqn N]~qȱ:}b+'uSPlK :qH]Ti]Mbsp놬Q $LHmQMWxUal!)Rַ~$>dyPs ai2)`%s┤I[^o|כ>ksx.Io M-*ǞȄZ8X.e}.@ r{MpUIcs(6fΤ=歆3A9B+dcIaL|BJ_ fVMPX䏅+3@hr̚`tT85L oos ӕQ5ARBO E3i|cUvpU*9NN]m(wvTM8P=%.iQփܚ֔EOɨZJUy]lE[JÓkP~l1rS̤L Xbp0[3mQOb ^ ~tK<EUQO=ps aN1̗ė^(ݲKȲ;AɲM $`'@QEu.n|AVP>Y0}sڷUA~UƄ/۠= lPSĀªwi,M9qg[s^vZ[_A3-bȣar "ÛYubaȂFcn^r>P5Y|ҮnNh%Iۖ7+\r%!@5I|!n 3Gj)wmGγ2hOD_ hYuISޏ vƌn-"-;yLPZ( egw9tp,ϨKV"_Gs,2}`:6QThGL񮣅E78hvVfJR7"B!c'P:xK" &E ;%րzŴk30ImY:zKҒ*LDOoS wM #F֚(q˿)rI/@"~fbx _woRB{?qLv>Sb\?~*?C0 %o'ÿ(uϩ~"{ڞK{MQc4?CJ$S݁>eSyd+:3nre<+#qN²Jl SF#"PtJvU,t1f7U̙B6U A8HPP Y~r_{V"uE\oxo|8+H!uENԶw]x%M-ADQ]N*`Rt{4xġ{-G[{ jzXdN_~SR"m-6u})OTڞ"i Vgw((,&Ҷ盡槙-M|NV襑# "o}=xDq~ZӷCN)C ,n^龢6 5~R>*pWRmtwgM 9Oɽ'z |L>nu >Imwf/3޻tOc&?830&Sj\42T(w,J㢍hМNјLtcF1_$ `ѣYI.HW=u'Δf~a=3ϟ.ť|'u֋J;ǀ P0{^(/ ix P ƖpO(}<0Sg,60}üv12WTܚC|4&7Steb/_$*,lukI)􀁠H~A?\V)՝q3yu2 ":@y3kDG:]gL,$ \O>,CU`ǟ-Ckspz6F*kL5:>nJzC MZ%LYx^X,+Jd`*͓eئ~%$I*2 w~bv<;0Q\ŊfrS _Ey#mߖ?j9M4Yh-{ m}q5$PW\ j с%9EVִ5ѐzii웚}Ț2ʦGB%f|ng' zYl?Zݷ[Zk.6t;Uc pjB0X?FcpavB|Ji4vB:[& $Sr y{RCmFsG;koŊV|6BYEjg3c99UBl!rM8c,7M3MY3A%TrM&&m[zB^Wqg^8Ͷ8<56\SD/ZFTWݸ[qwwwwEl\;"Žݝ(KiO39g̽ϝgfy|ZIVV!upk @(%o"~-GunSLSfP%}OH+PZ.-1`mJNJcY!r BTPB)XجBog~7#n}iRѯhHZ`b8oqPKp-6%e /bDG9e!w؆Υ"KQX)h@'ƤhN[2D{e[":c޾(֩uE&s!r5** f C wHU).x;IB,2,y @]rxoC:P 9C .#v#o Gn>LĪ []F eS_'E;5*rmGLGvCo_ UexOxg 85g#ESC55XI1g)[Rc2(vE;@A[uf7#(%5Pə*vAF_N(!āLJqݴQԹ UBdgL^BtBj7'#fsܳܡ{Ѵ1\1\Tdʯ^֞KѦ2Lj'`2LFjhR;sIA4eűxAz4e_I-K/#d&ι۽ɣFEȃCbu$j?m28^1~۪`Eyc6V l'V5Xn:S9V|S.muh5@tH/^{$>dr܏-=#v.O$N®`yT\ l cDIs CdZ7-)*XC0dBbn6c\ޕNyS@O#/CV?nR\[?$g`h 8E cF0[51/EzFMo8Y]:)0D Vh8%&fk)y\c`͋u-2#J!nP 5!i-G*cSw5lj~#V\"Ua)CE$M/YÖf%jYC<@hďx<Y-Gewv.dh lN_v`:"f,BICNX XQƒt:MFDz).&W띢f\ #JƏQ 922t@@@tyFĉȘypzS`4 @!:7[h`zz(zKPHwNή5j1U}pÒ,@~)ySφ[Yqz2 &eQ(jؗ ϲ):GoajDu{/SR?c%ٺi5ziGP$+}cz#Qm`.2I  i']v+Pu)D{xK#L*\1Vcd3rĞcza-Ρ ;qc#nmIJ*b:og!q+]Xմ~НHf91H|/AQt6H:3:9uXi.y_>!=[-%s\rENMPh ޵ޣ #eR6YO~aϥ0uvlF6ZFPJe I.'׍Vqx `k|bkQbE_zR 0`,"bM.('s@QKL7~ɐ[Jlb&:ο[ R_|Ҽ?K+H[%.Ǣ/Øq;Aܾt6ߢroìT,힢.O2a&#ADӄ4qGO@@j&XX\9H?9t1M67^MKe }yzB(Z͚)B(S*!DwӼ ֹ|ԧipRul 0U9J`L?g7HI S9X1h':dѕ0f m:#vi!xh?"lCev|9o].?YΌKc3Z 0U\l%aNhہ[;t+[jɞnHHm./G0{jpe6Ekh T@2 8'i$2vK2@Q?_<==lX~tsֆwO~3:0®ֲ(NTH9<ݧYi8Á +2mz8^Re,9BЯݪF *4V(Gu 4.XLY i䤴)iIч ʲ47kCBEȊq!F8*D@%T*@n RLr9ܜII45eӰX#E3C0F"!8G44Z+!0cB1mI Ȍ4 {(Vl;popeW—W_U*+|M W@BBOʱ 4{2DVIpXjpAa1ARj6 ; խ`1k>~G:AR_lX\y"MJvKle#Q^ySȶ I 3Z;aܓTx|ŀ1{?#B)Y^VV,+2*,17)MT-ޠȖM}ڌ:l; %}ȚT$p\,̝DM]+ ($GBÍt6L膕\~rPR1G.oEE%ZF2bar2[fm5 U+Uh"[f]+)Y(T=]/(=ؖa'鱱UٻQ9jzL$خiy2xs;IӘ $&yP1XSh- ("RJ]}M$Fh̵ ~qB 0I"DžO2SsƬs mHiB$$N fi|"9HbXE6[A#kKcU R !Z8YYJVM-%ܣY`Ki؂ H@c#|. @DbB,VܼE EE2vsvCU /"yM/ZzNZO*K^7 !ڮ`1wm#phOݿƾTfh{7"noǦNUA6C;s*7p7'׬d⦘D񃵑Ʊy "`+tFog |ݗ$3w#.=.a;&}d8: rr1n(a>Z:Qf2|ÀF ~Q* f> 2j4 4 :yOP-O57'c1 Eec+A&=?y_PÛtx<  #uAr?MCjR'KZ$$@f1 ^aDepqZ80 Ou7|7K<- pQj@ѼMX|"Јߔ}`M>՘lJ(/0|FYB'Xf8݌c̲Ʃ-FUmyí &:gC|)7?UДقY {H7h8Ji!"#1.&M'P$ 7%*R{Ř /,Y oĚr3}0oS%ϳ*J:Uf%KtlV|;'<[?W?0G.)Co2dieWM #ON;n-3kpKkA*2?V [POyx +MpX45ƗHV\ӕIX:RnnȡV% 1]r1e'T3jDj5 2tCZ9"c$_+/Jd̞2Er9&mMN6]jrg K+10F!DGK>=^8qm阪Qq`3[ªX8N< JF/- 1C[i!͕tZW4%AH.=D/d*TRj^\'rC(sd;͌t+/ +[9McҨ^O 4"dZT"r C%Rc4r:^YU$* *Ff҄$ Nq۶*%fCfSOu$"b =`'Xr xz=(6g._}(cY.j +b )W迻"B[x&o–+>k' g3`(r fp.NocϯJ%# <"$WMC6|UEwpYX:]4p#}3mu`b.bLV%F!g ukQa:S; dHn9D@ ڪTʧ1ձGbFۄt!"Oq-ϧEg!ӯL~< q%d롶HVJ,3&Ć0R}m~C+D3Zѕh0I`wLzLaР#FnLRKҜ衠w7xcQtC ǹUGGXn! {Vɒ]6q}vP46)2pnh=p^.쌋E{ }>VԴVa,*AfUm딣]&h|!{0g%+qޤ̙1}]ǭdbP"rf߶`ì@Hex/h|6Hڂ*3IL&Dvz/+o? )Q-Uuac5B35͙sU0PPj}b&;(Øh! 5nQPY.E29"؀ 0mWk&7mOSȱWȎ׉ wF6#P@(@@t!pa&S C_.:8~ < C3}V$&PT{}ܶ[/ @ÝFmbuo:F޼[O xey$O$wquz]"f&_wټ.ƬޘJ{)Oy}0jVe;4IVQs o}?@`ߒ&: ;#%'_N{r?,MI3˥Tv# 5ikZUy,J5aFvR6[aV6&"2 q nc=bC65Ds85"V2||W;=WYZWAo@"J , 4WtATҝ>i^! L4=gIӉP׍)TTfl-hbwUI&t#]G b"p Bv'Pz=4ի #4(`N\Ї*̈́E2 C?L1vxMb6_%sg?e$0*[ƫnԶV̎ 4M7D$;dSkgXF|e!)F@qg$O\ @I(Z25:hW*tnvmғgfQ$u31ė9CHPsWgW G6WC9 G*\NKsHmF?F͚tֺ*{N0:-w^F\IO625 >>d& \ el:&a*ydR׬~;ZNXMX!3+ JI)3CyNPURF.ĢB~#Ĕҡ 6KMsp8x)Xg8kti}q!MZ >L hv0f7)ǜ.Tah񘅅F\Ԟ l脸XY6ZOX 1~ W{TLi#Gi2y(ER97<  Ab(Do̢*th^ ǟ>,uZcV&Wo$,),7ߎ"BbG5#*KJA%|5?u>Js yܜuaK%۸ӀX*E&%GcYM匶H Ь|J)ombi'~thBbiԷq`~|1uᒎbӼ* 5[NN!P DJ!' HL2c@z'ڻp'3iA~v~ "CbhR5c: Y<;rL >I"ODBTZ3XTF4mBiG pIӛ ;bc廗ꒋ.9nN %$)Mp#nS1WۯG|շR_B'guC0p ڽAR%zp/a $+u}6ӴFT>kp 9"煏( &PFlAr!>R N \eW FDC/-'1WG #NCAqt'H $|Kl/21JG( "gkw?;_u?dhE%Y0pJkd`Y*hn{ ¿y9қX@/J086'   x&PpPYx:/׿ 3OS 8ţKq/_`h&@xS.:/_~bC/ 3e (rW4,h6ȟx^*B#`ɣކ H/l#FK:M'rksihYi RYƥ.<܋94)-w]^ߔ lw?_~|zxNޓ/YfsXpfpre錱1inu {vϏ'1O~E5)4vAUPX{4[}W4x8{ 59&Q1S)qͻ 6G/B4^Bme*Ү`ʰ~Nt|nDz6;]8m.:K*yT̈g'3,>G[,~%l@i4sjT$i1>ӻ*||yΛ;CZʬXT5*>Tf^\m̵ {ÌOݚ] $3X _8Sye^f_Ҫ91d;Zt8m-;iLK#ir!'-Շ6#fzSݰ$ A 5|鹪]o QWN 7v(~FҺM0Gi5CV1'RK,8%xx{IڃV/;yA"Chyc>}בO▐,m6ĵ'Txҥ5Qd2\ѽƽ"[a8ZD LNU薥7DNJV5$;Zh ,-lӵg%侯[ꥹᨡ y&a B_cL ֿtAᕾu'.3厅ghcXF|EѮ{hƼV.]Q#ORp ft2˓L}bfSɜʟ(3s 17lWCH·I0y݂Irf^7m|Ճj_vm|zQ0Ukee`Zv 65iʄVA&53fSn3n"ͯYLJ_ }[ j@^)8AF ZDc3ĭ$;SUW #yH39T$U/Š?ׇ,t[ TKdX7?hMNҮPWxʄMtvR~TCPOKPJb0arǐ3PAοN8‹B|1'yZL9g;:$u_Aw_Q?{۰<2i37``)DB+ؖ>TYs8.pxejq{S#~Sr18vw nף$שpJkć^ZXN+Ҁ#Gp 9S@[Y4P#P*lǥ^@z^D*Z5~&N-),cmw$H֒,j.Ӗ%[moеjAu)l4oчNށNH<0DwY)|=@jWѹPv{XAJ!?k0&m}|BhO ,`$\W/a^rdmg" 8coچ(礷.;ʻ/2wV|u'`(aCBc{yT~#R_9-bG|\jXQiܔ'*!yׁVÒ焕$Ft(Zhی6A2mq!4)ǧR{|;&!=y˾.1aL~07BBч |S!uڄ&. n.Y)ڤhom"0h1ƌ[+ɝ]9SX:/άG#dui4JR{7}ԕYG;`=r^Elr/V}AaE[9jW6ֲ,Qha38醑о7ȆtPTMRZEY&9қL`٣^$vsXK@[4_/=Y{ ק;κΎO+>F0\t" }zo"F]?As1 [vLo"'ŏcDZ>2nф:(rO{{@Ӟ蘇p0+55ܓ567L;H+qI2?9mǿ퉾檃E~&g t*~dv!$+Z FZqXJbAWdIB  tEǺ|;9ƟZCg0I-8iK,4-eba,26Y0.{:ͳt00F/=rdLsbHmqXG~^"t0$f/@+*ݥe #6#peíԳE);1'=>ԓWaI/b ˒!wC6M>WI?EAw:OZV[E *L:O e%̛tR 2$GHWhH\R3yAPuV|seM/ev,ȧ 9JE0XʑZsLXĐ\8}WTz"BqC5DwKآ rZ[N]Q?eGY9CXgW>aX^U&"i Cd/-f员#_k͞5kR<],l诣/>Tw 8!'7jwP)rJtm5(SgKY4YKW /XTg0D<˯uE\}CDW#`mK>sܟc\r1,Vr 9W'cOhCۙ.-Nh4>_ [[ )WIE䩋,-N* c&'y+<oxʯTKt> nVYとgU̶濚Ze5 qS &J֚;Ug^PEf#Sxi 3S:어? RAb3P+5Ú)x)234_5ݮDRJqWKw)HעTȄ@Rp1^-_4Mޣh=k6'mCO67LBHԯ0t%6-C ϳ!atZ4+ dF =7.rn7+ [:i]ٌ[3i5;ŭ/lE+IΔ>A,cQ9 7jZ k;}Tt97#o>Z*?懆֌f'uo_jv,4MNzn;JzE%ܕNwpM#LKO5l_A ͫe"Z/Ttl1'#ްt9*BG㹫wNbDya;LPJsGn|Dֳ:vV[)հ}5QY}Db۱gGMCEy R&0$'j.syߥw {﷤\bB6Ό" S0@uXU߀ެh WL_IA:q,A=3]^GlB?`4~μ]H9p.qǡLbE'ҺSz*n=+7$b9Vnjt]|Dg@ZO,z_.V>-~ZDx׽0i/(oEHK 7`Ϊuf7rᨚŷT6gT\tx ;Iط3CDlc2UpC[GӐv_Oͫ ?97L&F8 a(K\%wި]t,G;jb8c+[4,xs~LHɥ`my'F7s>aaek4T:YFviI?i~hY'%erwvh7'vW%My;1NI\p%"PFn Rh-lMCR5 Ia$oi?NBۆۧz$ŵ'9ƛ_4us^Wt/;SiI05ܗPǥʯsiu' & &Z8[<-PN(2@_tt߫N"R#hU5d%2oF~ؗQ k%^;w"pY@l\Nk,1눥{A0,x`p1Sl}AHYY$A0B޸أMI 0Wo*@? O|^lͦ"40<{o?WSO.Ma HE[\ًo={"kVXNx/ՙX%<豦һyx.ΔNVQ$ U_Blp,a٬o1G~%TzƼ2+pz/SkA~Sm" "箌|=7|] | Q5ȎY8)wtwVdKRY Pct!KsduWy lY,Kυ|~p0!/S|UK<Th6V}+A]>>1|&I l, xgܙ|ļ[{f7Ȫ<`>Ɠ"A\ST{ }Gru/&3D,}d!x@ʘwc̈zFz.ۘi)pXɍpt)t$Ũ50.D=E g.wXJÕ;C UraoQ^,d3x8C7H[ϐ7sE,F<քUXMS>T`ݴ/5un$ZZlM}) 3H͙ D j;C-y1XedS>|10?+өT.RAcd;:YwJ{!Pt@LV!(יθ4rF4_%6u/ t(zZ SsZA%&MËg>z/)mtG#z-򘒍+p_Lk93}^k BcwXpS{+Y_ :X@9OLqcveV8Ϥ5. Н C:$y.{%pԖ}YJj_%.a7)~lQܵu? hFp:'SpEq&nc3Y1tP`q$E={7,ֶQ>L,7i^9ܨUdGw"!βe!qCdaHqs`J@Ⱛ%V 0jQ wdlflUØ ,XFX>- ^o-U%f=׏(5z`R)PʼnJ 9uY,Pf(=SD) ̋|#Hy,EETIj-6sƥ*w2)4d֚0m5fO>Fm0.C4t•% 1r"ic^ٸyOȧ(Qb-{Nj:949NfN,m6uw' +8ͧl`m`f5 1NS30Z:,ݑe 2öȵ/,rcwej\,jjʢGNb@W, Ywg1ؙbNO1 ):[ 5?ꦌK|i|WeO 欉ș~2YMU h%d+y_:=R-EsG;/C+M/AT !u>~_@B{g6^`|_ ⣥3WzQ,ĝ Ǚ,-B#eH8?n4[/W2'7/.|J}xA M-9y ~9|o !څGEʦ .6xᔔ{=0._Mc;}";b:J6$F ,v]g Nf.@5`a`9S6hg05Nr<4BqQpH$ɝZOq?[{^F D5ѕWrDHMIaܝLIav'%[`qmV\*K:0v֘kDx5PP^dK)~"^YQX_ZXL[K-d`~:a574w{\V,.-+8߼_HYyIsYyO{V ށ:y9 ZnH` ? b6|v%6|H |vj@,=ut R3(z5vR.}U#O y89έFeR_UB2I%Cz<\'7>7|l W\ΠzKU2f agTOc3)DzpƱGa0W/hrwCG} m-'%MSy6aq.K(c\썏U*+j|AaP3mq0٘QSDJՆSD=Qdah;io4)f^t`_ta_`k * N4$vDy+^(|k ۻCUYա\Uա}%XHGė Zh\gd4͚пgLv ͽG]!X y/.zo+dwWJS3^%s$A\!T'5yIxi8I v҂ؿ|x׸ &2qqޜxq#-=~0{^ɋ ^3:oX;6 ,Zf`v(0L <k Maf퀔 DXhcjS/q.pL>M,FyRh8I .B:)$*SEUR+cqbh羇x}t-* K*v{j,kP툢Y K89+0YX~W?߼6o=asďW5xx`JtybR놕| _]yYO-6pvOcN Mw2U4-S'ajNVX 9C U%@v'6R` b4 E7} !"p,V jii.Dj8>Tv(>/ Hz~0)\DFCYle2_a+HX],A^[ofw{47@@W #`&kŔ8=vFB@; k JTqH7/4n&ōyr%Vp)#D7+ؗsFH YY!U(TNȾaCY6'j D>ut>& A9X.2$k@7X6ltlX%Uʽm*7gii@ 9MV ?\lI689UqG~le6oNK+lm1wdUA1(;LUeƦO}p6 ͉f]_ LUkAdV:(EhƆ$K@&TQj3خD[ly3fFE/!ȁDq;s֪\h9!mc<"/hȷMdbp X)(!=1!KuևKHFN`B@ҷ&."e#4!!s Snfygޜ 0gb]eA%ūij@~4sZ5aea @s¤x>e_eaX:AGa6r d؃T®8:'`'`Oۅ7Fl}Cm)CPj$`r4fGy 7~g|nԲbPuQr%i992KNQi#I{L]O9LQ hR)(&(2lM9#A}pK2GqQ}Ny@D]x8t)(a 5 ;1aU6wvJp:QH mv F4l7$BEՙCE))+[n6nИ&SA0}Η?|tF[M _4]8HjA8rL_{F,q[ ^,0 z`P(wpcǁCAXCLM' t Lq'b@EckH;R`~p=xOD8OdhQ#-[']^,aIH>ܒ9bt7Eo,t e!]}}v3 E^y G[+sf6bC6#e 6.GۅZE/ {ێwM 5W 2Jw/Hofx ;H, 9N|7nn>y񡿘6gexjt:q$5Œͥ7im0  8 e Ͻ?P:-4k:[ 8uwWb}Y{uYu=sP-ʉ C#,VK#XeTbb:&h"{br]x/&0ہYg:?9d.}~1R rhrP)|; Mkw"mw%ئh^"t Z,tYU0Y6WOF0Z|Dhw c"lw3{qVЋJ/'K虓-z]ix3?r3Â!φrs*;H|y >_\]IfPXPD' Ý޿_w>&1w,GT=B+.>s @=ےC'4#,ʗsw,-0S h ԁG',F\[𞶚i/]> T?G1!Ƹ;'W ,M)ٯgD|юH؈][mB_q'Ktw03>hg~Ar^ $1,H|\PƔEzA8m0n"WP mE:Fq+r`fczv@af36Rǡ:0Xu,aΩ1'd:#ifhbNINxbPư!=A,6mRٟI B"R m(>(o\$y(!nO:ٸr?OYr6==|}ۃ]s@/'rP;66P<rxށgP\y75#'DN{<h2*y>0 f7M[yz_&jMY49 3rlEI}{N4sݼ̵\~N Kfht#GxYn5W]kOH&2n <޿HHJ~DLU 4+!ID8Km o\F'SUC7btilaWQwG0.o|'\9m> M!O ⥰L 0mF˽5'{hn8{^@W|,`шd{ M0bBi0 h <LGrҜaZDވI,umXg&VZ3Aőt L(^'Nehir^*d-(-ap Ah-!>9$ݣOs/"g4g8%sn# C`-:qZ$5R[sjص{'o ,%rNeq$!|SR LB[mt-,w)HsIRXӨh7J,ES 6dV-3ޓElt7]%YIWd4Ll0ӛIYnvZ7ΤLNYa3~=] ]3 `*dy]L1&^}٥_ QEiA&{"aI(™u s &6UR=y}2 XOcfقO2_ɢЪo@y3J3#/  *1$]똀6!E#1Ok}&j?%!=Fj Ta?D&9">"y$WΞZk+$)OHG T",J VgGFuL7Y9 J{D`J|9 HldiweWGtL.*iICҠ-skboF$ׄ0ރ&N4KH%L $ֆ0fh& dWH+  }~_]~}uwSБ2N<=KI.b.*NX\rabI#OGWcE=LxT!=%diId m$x6cWHndϐyJc7,l,RC~7N%dwfz ol},80ˡ>.'}"cC&)`eh*gI^VSSAHncs*4;oqUȉ_j UgߡQvWl q9/\fj~1k#pJh'oJ)LFfB'ۆ>M/_+Q3L[q4ɕ65SD"3sFz\^e7cf B0MEaLB\t+yEXXm-'*ߓ7[^omIuLfnqTEFu_~W{u7DV S>ANU]Վ 70aSv(vDBrB%6yB4/nَ\?vo]=)P˒E~ܷSY2yw&(څ-og(g;>h$“%nPmPnT>yGt' 0y'~l۠c1;^Yנ0 ;Px6~Pנ *B{%vڃL{t[N5ؤOQʼGa7y6dc6ΙfZcaVF Mypy}6,!cڶ<@(]k+Y p0` ;FD ^iX@ ۞0 Mi\Ovd"1W~ê7ms@hshgw$%&n7"Р/3x_m4y9د na(6]\/[,FChynkJ]$nM EK!xM=-҄k - <2{jLO2eךhEOTNCQ0:yk'K\6)RՔ:vE^NXQ+‹BUpr(BfpP-Xp2˛ϟnviDBK\${tI+1Iq ]A0ăk΄KPE^9a֦Z4͝дk- Qea wfS rG,t^͢g^M'5H>X(w(j>j8twa,q"yeg0(}k[0ZԐz ;X0D.МT 4,a~؅"`^/JIa ɾ;۷2,y 9iK|gWu cM}oF`Q"QsdNɏ(u<wz 篷/gdgl7)oWW:5{d88XJ@'Gp^jSGj&?<9T*ДeL2ڥD5]ff=&8%˖}Ap'i.[o"'K͊y2z}+R3ӵC6\=~ڥ ΈZ_XCS9H ?i [eͱ8P6Xm[o9R~d#ʹ)FOH6\ ܀$q7xə6|˜,Xr!&@(D)- 9 ׀dWMWb4'9[5rB{Fe6D!J-R|+';?|qFaRA&4$8Kw"{$ qkHDV/-Y>o!NIu`'ke|{»##ik#MI|Xat]u ]i o֓XgZYMMi(·!=;$F bAJoC]=,_NƑB'bDB&ӫ7mdOB$2H,NxX6Hݫw^HaiOs=Z{/tNv#uLs4 2p'oyȟ{<`1B 4tSGC&޴3o&S}{`ymOG>锊8,R}u2IE#|".kYؐmhfp29<ӸH/F>!n.4ӝL7 r`38eJSpAҏM>BLøH ohʸQ?:j'JTrre\\cƩT(M ,]擊& kJch@"`vƋD'oD=/x@a˃y0ֻ՟( v%#ZnPi'-ؿޓĆ?$pՋ3mf3c~gs3e(=G&(?NY2(j!\$f&}9sYTFήӵCF: F8 ao/(L۽Ӛaf@,q4O8?QN} fķH8˜9)@ F y%Q (*e)~C.C>U*gڃdy)C`foFݿO'qo3e[ ORH"t1·&teĪ,M!c7L8wጞfv:zCN:֋|U# Nq6v#z_ 'Wdԗ Ҡ>:=@03v)Gȃłx"9ﶻi=z2KGbFovȶj5c? / E rOk :=+~ U?ԻۭxlH+n"lBi :erIY%Y#;6IA~.)(~o+=n4sr UIR,zR'zyZ3)UN 9$˲|Jg+Q"O(,p[im*J3*[s86KԪ[ﵻREUүMϥ_5Z^"YrG9-$~.mڌ\跆%$mTv6c%O vLan7JJҡr.nu^1l9VzDYe8{|E=U'6u77dJ K . /Bkd$]o(*BQ<[U҆}4y}2K܀5Wo/?6=|a8C@X{&U= \ 4rC^؇[@acO*[ c ▸ͮ$1PUc}ڨN6&.u 9R;MwuFg7Ϸ֚$%NPz6HIh-=n#Y<0v4:σLLH4/##h8-4`5#LPΪ&E?Ĵɣe$7CL{bIکΤI*#Zli0醧'*T (g\ҵK54N41LpJRPh X35!SMGY#߃p)I,Wõ\V]ƴ*Eԩq4sR<Iw sHn1]' (0%6qp2 8PB[ߋ"mBuk>rRffHF/Lc ^~!/P/M-sau)[h:ӧ7JΝzN)帞mSǖ j?XL6&$؎T+2e3SV8+WyFIT:ceHKݙzueė.*wBim(T@RYt“yk=zm2bm_;/ZFrYTJ*·=6E% 6lZ.>foNCkoôl鍾5:O@؂p$8a?gW˩"T%V̨ ӻnVOPzMoi6R~K,Wwq1 PsiYyٳ~uظͬL.czi*=Ҕx%7o){Q*hb3jt=i0N(bCaD&koͶv/GcCrGiX m{c|C2x;qDF=ag29 o.1td~UH\۾=2rxrbn9]FrF[iV^\$lq㳂/냖bNE=?iZ(PMɭFAf o%`p5D'o/ Cg^n.T6σ!I;%ӛ:qNM(=lo0A&X#t=D?׷/._c!ě|quM*\/\29^_qrL8u$3%Į0&0V6PucZg V;QUXs=X+r<~} \w eH4hzcJ{ j{PftyE*,w\`)5bsV_0cԗA'g6./ib6r۝cUh:BԦcyk?z)!XPRA!OOkE'ΡDҕ5%UHi3W14@P!B/;@^^}Ih'5|BZO2sxw{fW;GxŇ/_>Y)ևKiuDc }Njð|zi8 =7`[abdȭZlfsT*Ãؘ;DS[v|2프f¼T>*e$FPӄVcN|DFrpKTξL%KYpc]3UJV}v=%̀t4|8,2@[-/n~BWc4uɻBEGK]"IH6_k/J+T-MG2B4Dwf}_`zac¿ښ/?,khŋQ41.&R1a_ٹƱ.[]cƖ 8? 8o{4wgߎ3vc:/KKISsliQ*nbK{Q#%soEsɝxOI_JR3WܐB#/JdRu R.Ğ(< ǷAĻ`Yic ~lDXo~BwBmsLv"$[t~2pbDږ!91/S2掹d=]a߷>ٌӉISs\#mN'd7o'OH(G ZpT@3x>FiOnF.:)+~71#=I>@ξh='{>g#;ec=j-9^ޣ+E}Vt.4>7ncG[Pb7"EowszBRƛ踅V^CCke?.[n|4zޮ9CUڠOz!5uֶb43v:HƗhZݖn/tgɏ!hs ]kr7d[Ș5yqF9oI>B`")Z1`gq3LE8042-9vp9uňj$vlW2yopxm:)E&xtǖIiwAiWH.|4]@BMḛܿ@-?b@b$05REA(ŗ}NitB88d5r/ag pA%vZmbp@+sqLQۙ+ҫݹn0I䘕D#@ܿKH,^l*`tA%P$B| ^9fL E.*EDݣGONoB?ct=^;0эmwD7JxVO;ysEeīQ"AAs .4ƏQȇeSm9GVM#E;U\U (o '(M%/?Y[I)sbkB'W>;2+sJ l*JTE(|g5roc@\jm i e\*7^YcAGW}|>r z7h5e#WI7z;`a'f{&TFcj3k6 D.ֹ TŰz) nŰ>wVq |(R"[m)"fN "X|l6+؂ASOR҅MVK܄:݅}dz^~~/<3:s%ޠ}`Vb./ }<@1(~}Jdfj"e$IoJO$ Qzn''{veQPUvía转n ;l1%W^nk-roOqkaN.#[Սjr]Q.u9u=/үQ-%Qxec,ma/,f V+AQ؝h`JmQh쵺= P0;$iFW(If$QhzSet0C[$`,\0;|ZX{pZ9$vLn1dB7<D#69ÄPAؓJԫ\7{r{ppxuk*tvWrgtaR5ixQ2ʫ~<~v5meS3-!~qҋU+^֗'*Yl~ƦkY6*<G ) v9C2K Hɖs2 9ExiSbn]B򜐐rN}oǒ.L鸓*sw] {XW=;T>?xi8`* =}n,8)ϙ,dڏR[-),ϓI$}%^ Yij` EHi9Tg&2u vPWTfꓪMVsl\~Ӳ o@c[#?&"G(+XůIa+Xb;bkn,D%$+Wz&WiJ؍" <4nV&I>{Ѧ;>R^QW <,R$jKz pBŇ$Pujp7K;]&>:u#kLLxqtfȒJ8 "[׫e3rABHK"ridҙJrWyq=e؛f3ICc w*5A@S]<lWcvmCں =?)T>CpmkHHNo^.OZ `,h 3it A㘴@TDf!%3LYeR98n>G ŚDgA-xB <_'tB4:A&;_c7d߬y( ux ')|E ….Bl3-Q&bp}s9L+#S*Kc9ȷvXRX;)B"񦲛>ԍ#Qp5IDs):'0Pm~×w}՗wjW/,<ؘrdt02R\V 6(wgAKpބ]_/s{@;VQ ҧ&|, x`x Q6i$N  g8;~H7Y@_'KkJ+XM/LSL>"vcԛ:oF*c_'3LnIv7["XaB v/)3nw3jg2 y9L^}~M`fR<fbUyÆZY"WxĊ9lJ֔oIv6eۍӝ0@lQ"ʹW $;gҗƯO ЍfwH;ϽCcXQ<ZRξSK4G7k,`:}Pt4,f5 T'^E/NF _XዎV5 ,:4,6֊r)ig͘ҵ,}Q¢aU<7kD+b,s1F!`%|,%9&`$mj o}7ypH"^xL7O /rTZhà GL Q1ڇiY- 1D;\/l̅ę4q :1HbzPǚ ~Ui7b+ř D8.WK?[[<n$kdawVxxٓтoᓬy#`NILUK]wv +hZ/RiÅ9h &qh̊k0j&DZ+s2Qf(CGN[g_fɖO/YN3=@SYr*#Ziq%o26lghoѱfIm%x7I.\>rnxd:p+CǛ__y*ac>-hlpq KilI(۫YNf/\{XbKpRW&+U/d#d|vAf1뭂ٜ7HVr={vƺNTTEF!LT Q XmvE~5<6Md5 F^ :@ػ߅W^_ԯAQO&9zo.!.i/OhҶX~Iwk.8>W|: [~ɔd2 }z*sQ63''H@T/yQ3߀Ge\3nPt.@ -X Z; U*^fZoe8ׅJ'I'(TPN+H['̀ОBt5qblA+g2.t\c" l,qvaUom_Q7gAjCB¿HԤ&='ȬD5>63F|=y_m-L69CpI(ET?_;MX%wPvGK>hԘƒBYW2rk@PwbR'@lQoUlIoU/?ڡyXߜ|K_Z","s`F A%nΡ+eq-jz9v^rsr`}7<ՎItsۣjA)_T.PA|xJT܍xa=Jީ9Ymb4ފʬ؇. "- 2 m7+g8J&kpn}Χ-l̷)(}tX7!9 smm#I!{%GQvVw;|ÒwcbEcdռr$u@ x)bz,2Q@G}Ž WJD)__S:[^eͯ3qr UN5@b0; C|\}J-ﲇ- y*ix"-Z$/ I`IXAw!W+DlSkid-Q)lmCmVܻL;ܨ6_Lk.!2eZ龎SB]fpnj:੷yIv] +c]4̑MκobJEaCwgXP;|f]ː]ֵn/oK;8XWa¤wq.ĎuxGooz*IQ<ЏﰉTl*~BXh~7&FaH5\_'MTg@g$S{ [OGCfEFmR$᫠>8HI"z"GJu};1<7;(sqB áeeDP C'oA1ZG?]d߇v0>?q]Wwއ0ZO0|P:ݎo̹xq~LKN7/5钜ǻؙh$5~?l?7qA /:tZ;cP2)ܕ٠cd`nC~Fq`MH4f?XzgF̄W9Rjv5~>8}mkl@w:w6nZNB ,9Ywr&ȟF9+\v%hjVJ45kN3#ꭦ&PܿQYu>g: v [Yj4ZxEe2z!R #G (ޖM1oxQs]7mJMhv#Z̓wNlTːj& Y4u'O4.^լJFJ@Hc1Ms(c(TWۘ'Oe'V 3MVIFG$4Aa}}X&܍h s+RJ=x)-]q* Vc|xaJXhȃ};gnc4rQ'էA ,d,vMrو䖎VAr;>`l@B[ژ;gw3CD{߼SB`9,L#= :1c9ɹ/^rqDA %}ϒoi."OՓ-6)Q5++;R6EMP6 c,xu[5IOccg%g 8h^0d k:x@!#o2$ e8C֡cΟ0|q)Z-qyn Degy+Ν5D9`QdۑE$/`g$yrfHx]|O˯`xlAj>@Xi ;L87] OGϺ\% |dN*NnslsIYж-2'IxgKɨ~O?os9ϳ#LH&t[֖H>X" b$GsMy㴓 Zǣqp~^l5PKVGp Ko>d5%.zcJtwc!Q7 +7 ^~|&q rcɺ(+k9o(G|4骩F)r+P ɒ7ߋ. `)^ Yps=+|'Q54 M%çCR@vRag/eN܃ \ޗ2BXѬLd zb9I#o8E['fGٯd݅o(G6~KLXxl{tl,O\.$؄팬u\5a2M;<&E xЁŌc" ֚8pJt7qY̆$)u#(71S+v!cn"g⩺{N<[A+xJq(#mبF0>V!ĉE^Cq#`2gO+$ѰJ*Z6 )ZGĜ!#\_(gĆL[XRb}au5 {)7k9!ZL&#c7Z)#>grw=׎)-OTr,r47{hXΤ; #y*IBtsdJ/lF7oZ)-y1gR $-vuv#쬻lN̬a5ffn~֝|/:*m^ͬW(L=p|)kZYNS׉xgҔժFyRӪAtnM_HjǪhqVۼw:veN=kiۨ>N, ϗoۥP(uش:j$ Zo;ZDz]O/\v{E{N@U}H1!}.lZ~81Vnjw4nꮩpƻy LiqH)sYA/HK>YԶ҂KU64_Bb#R;h F#-m4U \A/)-匴q@[ S,Qg˷OGK+Չ(vL =n'f7q*y|n pr;{ғ-?xNytDEW#{o~|Bb 9*3.)s K;4~|[Cj>snS0o?؎KS/vȝem0-(py' CHg{C9S3 AȏDcWV/:ۮ@uQfDBP̷EA#X^a?赧c(w2nAɃϴ5鲪ܯ=I#{ۢJ+7*hmuIGA=` D%6Uϧ>6L Y\ |x^GX#6ޑ?Ĩo,0aNN5_,b圉-}4 Ų<ԫ> q;/>(:>SiN%''[E kGe߆e8M Xr>_~WF+xeVjW2fV:{]8-)|qH1L6TI=%)>[OpF$f񢩲%<('8iaM)Z|cᝨJyOzT)|~bMϡ(-Ndl?'JhhNk:GHctMCt<>ORY1/OTF覵gQ)eg,R*B$ǏmWs)ehEXApJG# ,)F)X1񓊎ߏAe<Ex 0g r|+ $%I/v^بlW[etO(ٵٿ/4BUzPR e=:y؈OҜө3,{ZH" `_UGTjɗNN銕aΔ2pȗXC>A f?xGZ$A558IC cf#4sH|+ƺ m!a@ܗ[˿}ur7R̪  zfîP"0'wutjjhA/EEl> KGW%E)okO° g)17fBqMS3Y\JJn-M+ `UmFR9.JãdjOhljϫ7.HQzoZv΍`)԰f*gйAUv-^ T;"y.rׂ8_nR8{Y)mUJk}2{Ml(mX"\oq VJbkڭ%B@9=2TcCe+hs@FCL5m _.)G[ש/xm^D6uCz@Fzo~uf%I5r~0'Ew^ 7u /{믰"ÊXo#nzsΪo [HlQëuo~veQA_o9]!^/+*֧kT$aYѿh,k<f2PYX|BEz&%x{XSgI2̉NfUS.NvYLOǒȘJs3y"fjf84D^v8O7*aV@i R)*Q`ApbpfJ)7^}6ޑ!g$ܢ#UsFڼsҹ9k+RQP'oޘ\Zܨ)BӢ}EOemڲw1u8cXX8D\4r6*ݼ%bbd~|*ĢhliK $!n)!icMq"'8[Cݎu@zŒbF,8 `0+'3 BB'1̭5FsJ{0T^$0ds%4c\29fIBkԇɛ/A$VVv6m=7 = `*J%,b >@:.0F#F6։}%[>nA-/Vل bwZLX?)c7,/V/% fXi7 :笣LZ!`Q0̑ef ~d-F K KhYr9;tK>Am"9WwmM. (WJjJ*eqIߕ>aLTYLtuynI^*@X'F t2}Lg{` u2(Mc^yƶHʾ1_3ڼw?<ʌKf) qlQ"qcاy&7Q,@Feuu6zW`IUNVyzb9Čjܯ 5wK/y+kb@?)mІ dyYk؞L] 2jN

f_V[XLlo r?1x|$/f4_ C3+8}F3GFgKdQ7`VxF+{0 E -,,c?a[ΖBgG~4BkծVћQXgdp(E\_HܑBKfd\Y5D.sLv|28(5A4RlCْMUd5rf'El?N3ah?\ b{A`=0;gs  ެuͳ<7Z)7jz,KfG[.T8V:=oZf4`Wg-c~LDf.e PuΚ<tf84g🳳zֹ6Zyw?ʝ%0nKBRhġk5snm%зFo县Y;,+4[§{~>p(=Et,?DuC]pYX j9huZjϒIvvY7BP6*1j!-ai WK.ꊮ?UR-Dl4J(P^cpʴ6. ZOd@SDgމl8FAv GsL%KI\I'a.dݕRs6͟R~Ph{)k˗:R$a]BI{gUCꆔXXR5r<+ CBV,{FXӲ;Gd]R+϶gSJ–sx X]eR#Zt=;<?W"F9];DoR&EN+bG;h)#{ITIY LJFA (?D)9E9 p(c4<PA&IN/:'֪y8Nav上0$[Rݱk<Ɔ| ˺.,2SFL4Oj`/nSsb2xq~LIJ#JمNTnTxhsKlY<%C~r`V̆jY&<͆afy;Q'du(>}Tˀ! ;ZL,8cI=ƙ#Fk[IEӉۊ2#γ}6o5y6LIC&]KK'z>}x_]vI;`}$o(K# (%PT(Z7, <'b*R,"=~~LRph评_=!QMj#b,B7p(P8|j<(F&FjHڄ#hhG!WbK\s9C榬4/=:S(m iuT/:7kVj>-F5,L~2Pbڄ4rÿ<+AS=Z4x":9#"eZ;IO!Iʴ%ն)RJַ KY@#?`z~G4mТO3siN̸Z0ԏ6u+o36A]4HŪ%gq "gDy:Iʔѭ]hQ!L6ohyHͶhD7fD{bB7Trs0N;t}tyެB%?s=B)wƆʜRmm9 U PȮ̷c~NR۱mڎf{34#v#e>҆csqNz/'s[H-َc5e>fܳ&Q9Ii ؎ڭz^z[stٳڮn<rn8~*ި 7>o-sQf{Qxtk]ެv3RޡxhR9rTT=oRJ:Sd\% g[)lߚLԾO^*q5nv~I83q؏]əFRĝ5m/lX?a>F-ݸw;nүwaA2_|&%:.c᧬!}4gANiUz.9YO*1:clH۷`sO\g@=zy{T\K.!Hp-;Hp SUu5w k o}ɢ"~صe~Lq;P8]Zi bLLkCQ J 0̓4,9hs8gPn*,b4zOLܬ^KHIA@aqQbgW(Z{*V.GbJӱ, IGMH6˻^G*a (ؼ괾H<Ǐ0JrjEqTf۝= jFKzЖY +tz׭O  +"@2@ ^sϐQrRsƻh)p`MR^mMO֔M!ͰFPGeWCԔ\X݃ODucE_{]G1"ך𘢿;<5W5f9gpTF o s2U7 x²ɧ1߷6շČykhR?mvNXK(78Ow;j96im%#J>V)i ltp*wkŝSOqcQ`v*q/%JЪ]?]uJ?̑?QeS"zX}nRbX+8܀&TRs3#P`n=&ײC4w י}50@V+u;[r/Z hĭ%J3aϑW9 rA ;;^L1H_#;AwxD8Yk}ğm.)iZ{7Ơ'!{>g'{Ѭ`0j_vzRϘ a~AW"_UhSժD 4䴂HdxhCFt z؏HkҢ{73~mSLͱāv[mc-yWޗJF3dPG/)+ceȜ++%],LMW<82v=#Y#Q3*+Nl lQhm,%8JOu:6>z>$qqķezPWTyI2]ikX3/%Otd ^}W!#+z#;/`_y"`qFA,Y@Y4,B098C<; rxMP$\.g\t,۾F|ѓnx Re(Iߙ2d7Ҙ)HiedQi'&;q2PWbB$uwTBoxҝ=:&k31pR"oq-ۀH^Jw%ݝI1.| 4Y^MN^?("mH!gdCmr)*"4mȏtU#bgw`RhX\o\F8Ol !{n Vc _e?][AfģJEn@pB=:XBŠt $a B/_ faFgCmH@ Lz]f|b6d,5KN޲%yj1h iDvn>c%)m>be5aV#qK4tg"ݒ涤K4u89oy5rwkܡYIOVHeIOr&6\ T3rBEZmf@t.DZŃxruV㜫ɕ{b4B!]ž UeNE m}|\.k1nX_)ox{UD"wRRDvUKI67\0}r'P̚% 먌$aVǍ5v:P->{^* DI=!7$rybTs:,pNljG1fev>ms_|m ~C8u+Cd͏ U]D>"&^A\Mi%R!::l8c:ZDL}: u??npL:I܌ LjLlsvB,"Y4G z4fOjg&s|IBWT{Е.v1&9Rrd֗*x_v\]8gtKM`0tFW߯aI2eAklZ4< 1㚂Ɍ (E1\>0#iƞ]J`F0I$hOA!*":gvl|<=4TE~pX~Wtolܞ B17Q\|O?RLktq%$쳣y#PBOt,Bbh$9U]\ w1Jotá]J5M Й䞷dѷʲJ̈́MβBĢvSů?`H܌pkXW̤gS%aWړRtpj=5_h0Ǡ}Dv3&n}{:v7ѱrX)TԸ;,k]qYWZƷl|Pɝ$㣺A)#Xl}VO|ȩޭzynZe pm%O rZ|]|$ N_I?eVBB@E8- ? <~]Cp7lIOSR0|Q9 oҍd<"^LDj}]_<*6Tu< ̛::wJ>O0%ӣkP BP?^LhO\?Ɨ`5V ЃiaolS YmY Z'B[ŏсOz߲a9yg$ª?ɽf +FO{ϻ$--3(rzWI(l_' FX&:[wV*L 4;TRz(װ7Ц%{g#VY/\K|8krCz eȓqfSu-D2duwkӻ vN` #3"EKH aAF0;\wuLA($H6-G7r HnVV%gFd 9(άyj1Wy ̮ثhorz ho肣ؐ$xFm Pgpm\CeLv{k/E B+6%M3OhU5Yo ]`%hR?iz[Bdn&@:@P)|yB8@^dThkTOi R%PgXy䣟 s%GmO!(ﱐ'SJ NHLYqfL\1f5R.> b~aqo- 2s=BuU/R%M5gd̜jI?<(P b{m{BƬzu/ 5)tRDlqw'=y#g8=i?#gC$-ɹ /L+ D%IX,:$!#}|n-Nh&ז,Hu152EUTpU:waCؘ8zmеa&:ܢ莺d[`%RC`RajM!b!lPk*A)WoxIAZfw*y+5Xp|1cKGrr 5O3g\d+~1t,%ѕRl*zjR>5L\1~$'HhՠX@!Ă~6$c35Kɥq7Lҟݵ^2QACѧq-]"~ͱI6;5F+ /(TLG@lxEYy ít$Pe=sZrmax5H+х u#]ܤp`lLC=aֹQjDα6]]+cyhq%|˳S*~r(z*d  KY*#^{ϥbyx=+yWIRk澻h2 %8*i-8x擇 D DRjr]T陳 R roZL/e}^n*' LlH`~M05-d7'ց^X#UU/EH]Úhw5fDGI>gLHC;HJFJY&p"G,X,yI}ZT+%]ThGJ% $:W|C+9>>p?8PO'Uvd/@O;}G#i_,(\ɖ(/GeqU3O~1e݂Kl2-/}#B$بo8GtR%f|*gOp8+^jB02HS%a,J|58޶b!]sgy?`S$ԕs+j~ l ӅGVm)eu j6vvQ#PfKf7[jCzJ{|[#zCnDHJH 3,ÏsO}-z (j]X }N(X [t> >`ot#?O^mQGQ˼$ b)A0f6C(ˁC`] +xoU҄Ihdgjdʤ`ob`atQUF?&wWV~A ԝaܫӾ8z< {~Nȷ]x4PY a1 :O_&|=:R'讵'NFpHUQ M7n0x?5Xs' ]%| P?jm 4\ %"lJG{z5Pj#@C qvr$N9H2HxI@A #g'K /N{/XJF$Ya+B ŎE +c:-ԶL}?dyqi%$vzf vfE8鵟rIzXi7XC՚p*8kR c!GmZ4Y= .Pey~~tVdS8ȍ RZik"M lb+5W8zM"1.jR Cfʓ&:%1!>.EK8nㄒߢ/>pͷgȎ=Zxt ΢o.kHBIr{ Րdd=C\ۈWNު3csnz|( k -̕wŚԱ8hlA)$,B_ H`zy VBF쮢O$:_X+xr+=B$)VWy?ܺ_#W~NN܏ɪ}"{{L |'md߸X~y[j%b *7]'-m5OVFn.xNR<4D=d[Qh0I M?M:KއÄ:#jViE2;8-i*G$*s`B BJeȃ,{ÊI6FKݑ:y7iwk{V&Q\5*4(C%μ?6Ehf9cT=/g{5 dmB}{Z,= n w^֋ĊZ|T.MۯSQ9Y;/hn#<pTRr/ cF^d";7j"~t/8!@W7wJ\Јg +O yKyUnSs|=ת۰q#?Q6@8LFe=NĄ^k[&AT́ N1'xsK_e>G(,3ƳAnAx:UH)lk]4XOkB\k0FLnՏt|?쥀f!fS~uX@L 5:it[д φr􅖔f3ХZه51)J] MV1)13mKhZ&u[lMFa}1wfcR{Iz>5;/W#@XôaKP@X=ʨ KVҦϝWKfp*a+DK|&E7 Ѿ-=(ۮYwcE$a\,JQS;Z>&3[*xWdt+Z0UbO !7b)4j@H vUmnQ޾\CJ,+fqBO`H qBŀ#0`lvPyИȝ=#"H e:l+=eIe@ )b:KP7M"33Zjח*seE65aP]r4xϠzO5-i{;Ei0f1}u ve8I.'B>SL/V/@ ˑ rkCE2}PSNF=rv9b/ Ie iM :1i<N-ˀ4#Cj4Z>IŷECJ"F/A )F']"% ?}E)k-rkmǘV> $j1[KE]-oO+)ѲRo\EV[SC*f;~Vޏ{pz/Kl9;9Ylg`40VvW$3}e~9\p8(: zjȜP\:X%ŐeR%S\83>sm⣱>zǂ8@\<'+Ay|qq&f: KW@Ẽ=/H3k1Mb~ڠ!GadA{좏hk'JM{!DĆny*2mzTux(xL Fΐ@LizauR߸4np~$!߱xZ!&8 8:(|.dA&?NZނ|@@-ˁ8TJ4.|s<{_cz8-rlk耟Ce6 KP+Aߍ&ׯkz/ٝ2i֗Ewf؝%pp9hiå+h,ϋB*Eĝ<iP!{NW FC?n*^{i65r6c?_ DOQăUsD}Yg33Uh޶t=s`O9V ʷ|+;f/y׈dW1JR].D ]MN]jrv &YٽìTq@wQ[2nlb=VLCL+o8$uͶ`N3Z0qeY3732*^Sѓad0yǝi&;}V+p5.y9-w芼K "-Xg89PjC2yF~(O sh˶>^J S9*€b *̛4 -XHv&vdj dBpJbjZ$ff&^S{[!euQy12&&%oF{'s&&q5q?B " Mdwvμ7 YLLo}OL&C/oXZspq ej™O/drV/ W^sh$OzHh-\i'e`du1`e`ä) ;+ / 7/;75S] g/9@`Ǡ[_=Z߂m!Gj'7YXؤYyXUw]g)`J-JdIXȘ/0c W;\vZL]dd -mS `SoHNNFNFrri/Ӝ\X)g#3'odG2ˉk 6cZzn(>k.Jbo)p`iI!.Q?U6%QV= NM; @܆5 [X>)g_$hiamT}%p' 5#!knW)Xr|u}DaUt.P2V*vSQǎ9NC2NiCe_,4џ& fg<K\"q ;rY7cZ!XrUP+$ʳg9=z]h9ujg8"e!+Q`du9PZp ɢ%b%-jC. C!(yBsnfMD~LE'ʯLIi^&XedGBrWaO r֌ eKkUyhT&)n\ R&KJGo?϶\^bf= !$Vl$u8iII0W=;#RJ+bWjCU8Â>qg$m"z}OѮHM5?yZiPOT1I&|(>/ZwrvnʢRzuaK5hf IL4faXGEnԑ~f$-u0GsǫHҴ:g@j#.Qc;|`ZHEڮUe/X]#rj RpuzvפdU3zK >۠9Dp;]B)$Rnn%U6"4%"J3UOsF3^R%g?YUp`}YʵojZ.&X>\Sfx< ;-#oqzMq|_ J KYeUhk'#Ch#N6-)mlӘ6~ҨQvfd H V- =|1 *ŘBqZ݇0M~"l=#hn2 !tCS2aL"Z:^յ8ɳ2! 2MWhH6n:^]i{Vӧ7 D;Pw3Rc'r `Np/*>(lH!Zmg UI}#ld2Sݱ;a\0}+s௽z˶toUABMAFQ l'2 =Y.AtwҷƳ#?M(8|JKY}#4e(Q; ֦f8=`5Ww ~f$RvdW!=<3!RpŁ/~go:'i5=pXK]MtM7!ȹy%FbaȄQ-:F5$BVypQ:Sr";:FG]6Q!9Ƅas:Wr ^$fw2ږ{B!%oBs SפwcYENJ |8HleՀ.dC.4`^J]齶\p[=|F/r9s~|̿kL9ܱ5n lB 3BA)(H4y=kyBU[˷[Zj9yks *?4ߪ X2")!&&&h`oӋ-U` *?L̓yػ F&9+~iRK &v{h?qAͿ!>?%/;8?F%ϠMdп=/;i? ז߽}!M#UCW e9H_oW[?.Y3xRMk@=gŜ B8)!Vi|ػ+vWv;+%Kaa?f潷oFUV=ROd`:6A, j'5)@a@ض{W/ >L3v#:%pX[5CuLrvaGmX+$.1̯PvfYi.5lPpwY B9e_3dzQKo:gkہp}Fà? #Wg!8]0_4-2x>bZ~T#a ?H8鹛|C:QT_]U6y?fC6шSOA)_-&7s8ssKA c ֪H9-C|Mh*C9K- as}08ԁyISdSɹh;.)5܇ހ"E"N %UB%C,N8 x8 z8۬ 3J$A]v('vM0p+pyt1NRxoWIg=൐ Zd{HV Pc*@πHz2 BKʍgn AxX~75ނWg.u8ȣ<"{\¾Y.{6GT|emUC;lQ_Sӽ۲v~JazǂŽL't7Ҵe\Q4i"~-zNM|>QCc%TA"H"(?[L8`s^_y/9myx[ >_|sB›s.e7 ,x/SlLF\&sLcB.XX'RMfᖅsKN9\3&r OY$`gP!kpx)vEl%8nikx)Gl"8niJkx)6Cl_q )1x)RtL8&qK@+dNx)NtLؓ'qK\"px),a3d?&ML}1Na*Ǵ]ir4& lUx['Nd=r#kx['VdfL/22ncX!x{+rYdjoXx7_b A^lxk#!}s/{#P^oxk: !}r/ə/ x; x^`ƍV3o򉙑 LixUm6'Ht/'led: !ne; ;NܲRb~G;ۙsp,GǮLK+t5r[뛇뻟HS$;sH7ZREyNm)Ds0#hդ (p0s;$'4L-2)Ɩ~`<LoFeML)ԫ[}zc, ZZѽav;ڨ&7:tH`⺕V-2 җYgi٥i<33pWr3ysgs!7.;}k,Xnf'_-pЗ1H$ga9_7(^6Fx5H5[Lvt; ^]C^;h ĆVL+E:rјz^s/AgA%:+p0E5g9%ߏS|$Jk{ĭ"R6R /6MlgNMl)tNv {I"ce9X5`5K_|?@F }3yܼlq7Kߍ+rݏ[?-x&oCrf^rNiJMIQ~iqjQ~Iqd/fMސx'/W Ɠ2+m,4nLx[ɷoC%czU,'dx[ɷoC%czE % E%Ee@vFBb TZ:9fm_Bx[7oPHFBr~nnb^BZbfNjdc: ɽxVn6} $j.MzYQXcE-QԒT wHJ^u?9svp@$b@//C IA8\7 5ܓ+TQT(D3 Xnj\Re-i0jH>׍abJ65d4k(dO4g%˝J9J^Po*TfiT`%MGz>t>/v# [ %V9z cZSȉlPE5W/Ux1m|.z/^u }ݛ]&S=hgCff"bEz%bgW(e6OvP.k>kHiI9y̆0Glr*Hp[*ݗ ,0˕T|Fӭ42G*t<61]Wr+J!OH+jI5ftutb4EǷ!f=[o+wwE׊uWvμLE.2z+Z =Ѯޠ跆)DF6`;I?9i2mˬ>]d&Ƴt >6 m6{B@9f$TkLs\;/7H;7<-~3wPE2:%7`|3bfQWmmJ/ޕǺ]dg}`T.}H`tJ!FuMMd| Ih.>zw̫/C_0n 1 Fٻ>ezW7x[+Yp& '̼ҔTԢbE̹ !ޮ J )y%ީ J:X7$S]nSx,NpB&˙x))kx,BpB&˙3RKB3S7g]]C6x[!8Opav鐌Tļ̜PIjq!&fxTmk0^8hBzY60>bd$YNvҮd? PJ GE-JN[#$WnGWtt ֢ ~p[ Q (: RKbn y Z 0U%sQWp{tڅ|B"Jೆ~VVfAV&_4g*" Si= ޹#qA 5hI #4VK4v!!`ԮFcZu1 DIܫlgx]PMK@%&Q"(ҋ'E E(*m Nڰ[f7ZO e!ѿ_pͼgq~Z؛Di\qLzJ>Ku:ItЍVa}Jo\h!%rX 0% ل(ߙ`Rk܂r`dF( #C1V91B0W l;LTk,)XUdyU9p.L2b,'rwBQSßosx2.xk@q/""kCꒆTCShW!)Yj0YVI!H(t?FIлI}NG'qpګȚߣwO[ 55 D>& ~N^{5q-$q`msŻ3Rʪhjsbm3İn3Kl۩ǡXPJQ)Z;!ic *)hDXQX%4V@`N #CFZ5e|R:c^~Dm*t+kNZ$'3eҲJHĜ;L j홆)) JsJ6f&%7C6yz>?QGHX`}ߞɎ^?mk43OEX"Oa͸'8jg=Cڞ^2_Cvx{3{C2rf^rNiJMIQ~iqjQ~IqdGә/22Fx3{Cx;{wC1cJ)Vx;;wC1cJoLBΉy% iy) % !* @̜Ԕ/Xw2n,x={Cc2&uf$7Ex={Cc2>ɉ9y%%#X\ q-xE:$#U!9?771/E!-13'5E(TZ\2y UxVmo8VZZ\ýDi$S%$d 59qf@j$ϼ=3;sBwW saE9#E[ttnb-<nW (c"4=*J+%kUnF!(0* { *VJ6@ra0jYhz,AA9 vkf.gLnS0 i5SIɧ B$J@Nf]s *4*,>y lYsMU#La^j>8)<ҦJq$uB=uկm _טG>&1ayֻgiv`UO)5;QDUDrkuN4LAE ḌaȄ%̕~zcFǘ0U#aw$ed!`;$P|nRvPk{0wca>Iρ'9'^c<ĜF/ȏF{zF3D)MxS(3\=|i)NO^/{|pN~gD"+NVC;/i8>.sc>MlbXdFQ.23 aJ0+9 U`W8;PA b1WmYBS7^S76*3 !VD;Y Mhzղ6Pn\!j59 N jz + g 6ҤTkݼ1#K~1ԡBvt1ۭlP B#yXԽ M1uicۭϙXc)m!UcK)șf֢9ٙ}\DB:ƏEp/JFYn(L"[!hw~w|7Γ d"sPMҊ0qw8|Bwn5a(*5ZeMyL NjG"HS߽mݳoݳ; -䔆R[M+8_-xmRJ@*b+YJAA`b"xv31 nnzOW+~'gLdwg{okg*i/矕a^u"唹>^QpUaz+8j|[ fOݳrQGqOiElS.Ǩ%wV(( (DfYSdذ1c&C`"$cl&,l@$^毋ɒ=Qg':h;O^Ek Gq ӡ=FRp h yY$x:A.CAz% v^ILpC e+{4*le Q\r\ ]g󼔭ÎP&A|ڜ_[$VXI8MDr9x;+Mp"& '̼ҔTԢb ̮J ! J: !ޮ @!Ē5 u:X&p.&VH@1r{ȑ{`!3 ~*6R RSJRs*Τ"pl7due&O+Mj`2b+gs]­vjU!L.)̗-1pvR3,oTeue4%4MwWiJL~ ~xŷwC!rf^rNiJMIQ~iqjQ~IqdG1<#]4xŷwC!)LLœ 6a jXxwC!)LLœ &aϨ00K_yqKjqIf^bIf~dOV]]3K2Rb<3|sJR+Jb҂h:شx\C<6i3G,+)xwgC+rf^rNiJMIQ~iqjQ~IqdW5n5xsg$&30,x;sg2+0mcfdP8x;sg2+0mcd HUHMKQHKIMQ( )Le'x{{wMVِTļ̜PIjqQ/nx&Qpz&[1!x&Ipz&[9'橗(e(d*N~ή$d'&3sRS&qߺxXmo6^h24^^ڢKEQllHJt ZcT<lYC"޻wJ#OO_2fX nX'QTv.b1< >2XA(\-qi>|0 *WW>=,r,|(牘jO\i{=LgTf(S͓T/1(nj3=6_/Zv+`PA)% ӒC² :5 oB?Yq]C6SF:ıC{b܇Ns1q%?3qg;p雓<Ed-zr{m^GʜB>g 'kF}`|} dò(n D3S*:]0E~D* RsJKAdIZ5Z̥z.>5I&3>C}wޟ1t`Q+ڻ8=NeinR0)פ^񏸗/@B:梾Y?V>"7G? :#]tJ8"}ߎ39DK 9}z~l6SX4bЄ,PC5YPW3N*k~myZ 1[b/+v1ꃘEbR6PKmM0r_ӵwE0x)en+]7Fd4rd O +'vH%jS1jRG\ E*LJgaѻ+ա#7,y|@S>Rci;t׉ au=f=+Rp(1-(H+lvR6Y q5#k\*-JLn#Q:B{^ꈐYaRe_@+[x7~/t( kq_ i7o{ud s% uz" JRY)ƥ\}qcnJ 0–)ghVQ~}1:'ٛ\yR-ڼkUJ/M PoKLj+HTnI!Z"tH-Z:$}*t.o/= p"k1mp\!!8T,iknx~/^Og+{Hlbw-AVKlTs] W^6Z\#̪gczknx!|fUVxUA-+/Vm6~IӒ69`5k,E|o!TOxȤw3iC4sX.6J -7޴45 xjsl`l;&[fo&f aM6&[֩Y%4^xH?8fkr𨧏z50c$UIYޜЋo!N){Ѭd@t "IpT~U] lqh\\R(s'3@Cx倸=FӠ+iEXϋ Ye.ǡ;p/ c}Q dJqؔ+ۓhc77X!v9}57_]ŰÞ :$zCjU=xۥKqCrf^rNiJMIQ~iqjQ~IqfŐx7Gw%䒐ʂT%dAͮ,BnUxۥUql& $+3mxۥFql& TyeC2RssR3sRSJB%%z ;x[oN_Y7Y2<MxWmo8ίq+mZ\__V"M&Z)R #Mܯ4ivW/x3ƙj'*W.7JEEI%)_KVR)aL\?Qqa䖃& -a1]$/)K%4^)Ģ _Wb D|t4Ľ,)؊elR告,YΆ{\<\=بE,X ֊R⣄fT2=iG0Dʌus &C9X, "PXNW,8 MreAqBiJ|3=Z} stQ[CE4qDO#ܕup -~=Oʮ5Fb=9Ƥ&_Q0X<ȷ(n*F#,mgqOih%ۥP!r$%K}t(Sc+}wOwkS=bIҎl4!Sz ";n?-d=_6K;ލ!B(#_\ 5hjdn]n/%xmRMK@" ^ØJŏhKZKAP6lM=Gҟߥ9kT̼y3>o*u/%^+Gel2Xs`^}fXsf6:Ykvk-9vQj;֍:9tjO9q[>.r.be ! 8:# Qd$M # 2䣘FR E%bs@`o@ʁyTz#{ Bʹwλ痖cum]3;dTYJѐ 6 JD?ƩB%1.+*!)Q._%i\y @-׭QTL?nkmg5/;?jh` }$B-UO 3=̋to\g Aax}SM@U!ۮAzx)vn tM$ .I:ݎ0{*a޽w=&MSbNyw>׾Dj<zL8_AN'}PT~Y82[xҿJy0]p1SQ\r"N3C8 )h' &g,@*Jp]3Yw.7qlB N:=۵޺Pq^X>?ʛx.mEx/6Z;rD`),͍Gtd(Y ZA} :KET ZWfтn%Q@[$pٞ1qbx3w .E1DT SL&IP_~:/QGT|a>gSWi". ;oĉ8%0GS<+c&t?<^ArI%R)\\eW `8tfˆփ]lWJ_Wje*Wvv`.GˋLwYQ\LiRcmO7\Pa"T0ԙnMki}6i `RⶅHQ:šwOG1hzPrQ}JtuO>jP]doSY^x&]rC*rf^rNiJMIQ~iqjQ~Iq^^RdgfRJ~!F/2:EjM,j VPR*( J-.pI,IIK/PPQ)Ij'46gV)=xeJAEI&0BF$iI n qlfYc VP/qL&I{Y|~,4Q#i(" \9ߛ  >^ HC)ѽDW^$9IVW:}v>:l5N7%.tÎ~1O*=!60kߋ 9Kf}g25Rm֚ܺ"NMF1fj H7L3˼XkDh$>-_^$X؂5%nҞ[ }vY5 19x}S͊Pv+7p(T7 Mǁ& 69i"In̽\d% sevso};'o_q˞ eqRj0B*@܉Y7eʌ9mrfvd-Щtt AytA*aėhWxߟnO&#NcMŗuwπG 3Yx@JbDRָ?߫"4nWLdD(X D3 P+'d>3ښ뉑LGDJ_DhsHWYV,c$iŧf֎k)xF%zOnQQSw*u0-p͡:e OHIQ\zutŦGyi0$祈쒉D S"+>???4)R^Cz̘%|uɩzu QˠkEjU5"x{˷wCrf^rNiJMIQ~iqjQ~IqdKf9%.='ON%W%$J%Mk͋O3Y:x{wC#rf^rNiJMIQ~iqjQ~Iq@v%.='ON+7a |x{wC#LLœ#ٕ<9&d|y3Ҭ cxMAK0ǩN@=͇Н 0eK־l6I:⎂|/Ί<|9XȾMb5dXU2x<Hމwl4 59N (ܟBS+ h9,ouSYZn%X iEU^ra Bn'`,z7u;-6n_x;{wCc2(VnSxwoC0cH,*!FnOxĻwC>cR&[&zNx[%C;rf^rNiJMIQ~iqjQ~Iq8f?ߐx7Gw%ǢD%POc#XiNpisbOj^zIH)2U (SBך"/P J-.pI,iy1K; +nx&ͳ"X/Md!x&ͳYdC2RssR3sRSJB%%z Nbn.x.IrCc z./XjGx.TpCc &aFF6ﰜK\L xxVmo6_q 4)-M}KQmHr Z:YZR%xޯߑ6ۀ%瞻#,|zui`x''?@$ *L%pJpŲ>r^@gf-rhIKLc`JT5P֍FJ65$0òHj̪\J{I9@ѓf1kɬT /ͼEqXy(b{m P,fL6o 4\{X]Cν cEk\iێ b!7=ˆHyrBO |K̷;+?uJŸf9BYUBp-ɇ}rH}yweꭆ T(2$K Bh8LeamAU&X#Rk74Cɻ*a݊mADO'Y%ċ*Xx9|W7/FkΌʏO7MVeӗ ̶F2z@d}O Hna^sRx'M$?BU1m7ym]0fi4`^ e2Pv:Ȩ2W+2r(h!r˙aL&.,-RcAATMF ̃V " U-ʃe1MGѿ0U݉Ak+%MۃJ؍-e͸d/d@.^GVUV oԭ ]Atӭz>l{mVmB]Rϳ7. Zv-ҼcAT[&8LSdC޶v$0ln@#t ɹ_sʕ `],/qǰ(~,ʊ ;AUy[p2/8Ƅ1JQe5 )'N:>Mh2t{B{\櫟r>s~`e,Y88;  {w*x*NhB& '̼ҔTԢb̮bJ y%% J: !n>2KOdU 16RPR( (MLKIK/w q՚Ec}kv%n|x{'Rh:&[v1Dx{'t_h:&[NJd*$&(%f椦(JRK&/89xVYF~_Q"+e&!sd^r䃱zx7+YPu7u~}x.{3~1EW}u}Up`PV;%ֹ9\]4$7~D'}"U9g.A|Q(%J &GU rSF5TYWr|Dd"igT_0*MI=+IJ1Wd`*J;fl׋,lDm+kN|+ msdpZ#y+pIZ>B>u 6 ▹X4=3pl`=i18rPR'w?tۢ˫˛;TVA_x0z]!>bQVTE1C2AFc$dRT?ֿV7Y6nI*L1;`vimTZ؞[P K4ez|Y 18{t?鍀?7jS䴮=?kᝫ'/UNсsagMqmЋ?`tsu2A6Uư?{b>H) !Oz,K4w֔# Eu7D!7ݒ\C;) mV2m<)4v iBb/d]K,&EwMo&wPf9pGa=|HvM dxȌ"z1N>MC \$I`v|D-Y RUYV 53Wp h>zv\C⤛FIB+Ƀ g)deQ[G^pS ﴿-QHoO?&p9M" ])$tM,Zx.A|̧æ t=#8Е0do}=7Yzagci./JP\.[(Csxu}>ā+{En^O|KWۯ5yЛD?#6A> ^LJ>* BY*DS&?xz*Kx*|EpC1rf^rNiJMIQ~iqjQ~Iq^^RG@f7~%.='ONx7G M@PO%ĒD%$ޮ@Y J%Mk2,3Y#n~x"x^pCc6&?6+ZxVmo6_q 4 -M}KV!mHr F,2)T<츉D$幻 f>UbQZ8OI˵dV(*nx`YI_kݹ?Kx\=bȵ5 9-91}+njjHTaWLsH,˾@RL"s׆>r|zA%y4n`n2h$^e|MDrhO>Ɠ$Jˡ9kAȬj0ͿYc~+f Aj6yAD=,`5Gm xުvĞnt[pDw( L~>Ofػ]6)G! #@FfF7B\3D?XvrB?m*ˉ?^ˬAhFM24yHKa@Hbf;4/*Lfh _CمAF8mx,y6@meUUQ,5?(Ph.PM;lCZ'ltS']U>U)Vp6m[p aΓ^c% yé#GAL6!Ff,ت_b ]deyp! )Q{Z`;N({D("!3]"OTc֝&Fsֹ i ȪTP;RXބ 5د<|($ ]H1L۠"B:2hSgy~m..BUZG0Ī6mFvy9ȼ(x+.őlhv7]|_M,ϖ{Xi2j0˺aM\bQ]كZ ISGaM/]_<PԾqN8zyIZc,kt; xj8~F}{s l ɼX~z^WaarP1±qtyxGa %x+/9AU|eԲJ<ļËAyr+O(hq+H.))(+Mh4YIhsS*#&ocI2*@!2&A#⒢ҢTGAڂl@}cn+@:5-2Wx}R͊A&]gERf͠x33@ t2L{ݓ/  x|7 Ĺtu}_}U}yۗپutYNrAR @gD+QA!SJuܫ%q=?}" !;\ӷ#ka̸Z7~>%Kψ&{1^d>C;s/)T-uk# (9"}(4 dH%񡋴Zg@xZS.dY]@?6imxs(Ԋ!̙dk˧ТqɬA QJ6”ŇlZiGF(2Ƈ9ę('ؕ,I; 8lq6ˀn/6B Vz3fSmZQ ͼ&S1CWsN 1%0^Nٴ=,v,7gSlA307 phBrw??Equx ?{)/nx}RAkA&mvSA*B Ei*]<4P1 d$397.H V4y7v**Ԥɩ&TA;^˻uK^/z\ Fj0^ AROB`Ibb^+id7kvVk)p/}ffx+@t"& '̼ҔTԢbɕ^J y%% J:2p)LJzhMv`PR((NL-J,JΨ άJ]΢7;D"llx[(MhC"Fx)D`C1rf^rNiJMIQ~iqjQ~Iqd/캛YX|n9x{"p_`Cc6{.Qx{"pF`Cc6&NVTļ̜Ԕ[7 un x{ z[tz&[9/X$x{ zRtz&[LEB2RssR3sRS& p] ӲxUn6}W KuI ZYʢ;d'qM^bj8g hoJ g9\]QQLsQ 5*FHw<"Xzܰ(a j%B*[imj^o`$E@" c!,I/xf(]HT93/%IVudxqsgY "KNΪ@5,C8ەT!cZ@)XՀw`WY"5J׸ ,_`[.W4sMbপ깨x\׸syuwysҮ$1DIѩC|J4$ X:CKaOBS`y _AtR|SuZPl'7^nu:'QBtX{" OΪdS+kS1]ʏ/:k*4AeJ8]H70"k*84=30H\({ 0OcD_;SEw,|6;? qdq|IG4Mx5p$VE;dfAT^N4O(M(񸂜55RlagvPHrvAJVoi6͛L"A;4MFWʷDSUjBI'GwIez4L6+,5z`x ݆:a, $~4Ue\+t*3~>%$~40k g Wt8c_ HX 3} ꇩ?^q<\0OaPJ!)U0ћeWrf [AEY~2M?I4A:sDm:<> Շj?qrʠ0I ~#PZt9xvHл1xmRMk@KB/Uea[\=PYP*,M22 3ӂīw/7֏K<5}޷/#%-.kQYG-LCl36 Taƨ3 T nwyMDaxy:N."Cށ?)yzꆽ{+h59ݐ0b J"pi,qk U2>G (%Fl*VuA:J4ӗZamS̸\fRLbg9u[&$jXgsIyEXhZ;wp+؏Hk wGwVkƶF,ۖ00lb=l&;(:)R>eIA_Xq!(71qϽ~}NypW7QLe&A3cgȸEwܻM{{҈gX(wGB$' 0x]K#AxL AGlA XD=˂d;΄Y6Ε6r^{Me^ #pDsYHw~x^Ľф"|;9DwtBc?_7<Zޡ]hXnS˥-by1i35aq8XA*lUO NJ$V$hBl@h#%6aKPH[Mi,rW4W]!ST Qb|43cuJ\6Gc{|k#JI2%ʸ+_6f'gѹvI.Ϧae\}uo~Tna"D]s}wZ#;NײwքEmmܞ}}[*9mRsOUEzoax$xCrf^rNiJMIQ~iqjQ~Iq^^RGdf#% %%.='ON r !>Α J Z9ɕ J J0_bN "@xk<ƿIIA93/94%U(8Xx's'RHppGHVAiy+YEhnQx;C=cV&GV).x{-Crf^rNiJMIQ~iqjQ~Iq^^RGd fv%.='ONɵ22cjnMxĿC:c\&WV&^wnGxC>cR8V*R⸤xVn6}W 6)5^EM  Z,vR ))Kݤ~9sfp$A_;׹5< 0L j^`ZÈ&!ى_7 X`T@)XQRL V6xײ2\IɪHffKD%Kx0OHIsQ,ɬy$`H,b~҆#\& 9VeP@`u K7$ ֐kܰ׆ B\>It w_jX@er[s2?c oq5VѲ^c8:xuxgCs*l!k\86e #z+ JԊQNp2ڻyYxc$QkF^k.F*!4Av(<ɡrGHj-N"r" }1h*ܠa^q3BN7 V ֜èCkUV5g˭2|${$Yo=+ I=!˪.2S[j=~ɠ׃Zn,]MoRߢqb F(&L+FpOGP앍~|KJ Im9>سdQȭ屡Eı5KUAp; x0 ȉ0PH2E 6rN0Ppf }2R@RRaoI=Mpg(`W9rJ|$G*YѴm(.?&Q8~xo;wCN_p^m6634;1qչi* 3`䉙ev˾[xOc(T:;~rOm zx;!^hC6rf^rNiJMIQ~iqjQ~Iq^^RGdOfz%.='ONxoH%мĂ̼tJ%POc#TiSN~Oj^zIH)2(UwI,I"U6KK/1K/ks.mVX*4un%x[/JhCc:l(xWmo6l6v*iúpl%؆$w `%*I95)/iv)"O{x.tElJN4dpQ(ƩRpK\HxdZS @ Tj%p(K ,ǮXf|WR9"DR5?CӘ,#{W"Kx /\Ѹ f. s9xLӋ74W_ TNb %BLK jXnmyk骊tʛoDA95fŊTf]Yg.q59z}?\ CCսzdi&r*_*hJ%1Ekvn}#b>Z*&279 AiT‚BB,vûhCtE5qH~e< /I qNf MMN踁ҲJ=> F }YAmh"paYYu9\xK# ?8{`I0[7+kiW[ez"[zd@B/]ev 4qMU>M.Eȉ$+ wFTxWEqڸ YLm|`j`\+Ú)v$.I'& N2{DoeRPZ M*U~4 w>ZFגBre't> Go@!6Td7Y@M.h'}gΠߛ]wTlZ&p Ip>d{ Fؽag0` \+Xq!%慕DV_nSv<]{)TV黦:P͵`I46PTs<}gYSapS4lWq''ЕhF74$UE@ iE~ qhVֿk4c6ơ٪ +9ZJa層ҴYk`t~ }Ն1[a?xT=oYU7@F񒄻CQ>6BHk'Lb8b"3יMo*%TEOt4P قH4c'%7w?9lo/#\i9]|~@LM295793V7M֧5[L`` }2ݼJ&3ّ6 >A>p; U~Df|!o_'иX8TG+r4*QH]Z*]01z?Z]NǵOԸ`hŃi݃(̧ Yf RUCcT9 Y!hMm xb]a;M>6<'H;Gѧ+#m!esoz;ͮ 3$91֪:q;\ko.$5$fjNMT46.6y -bd>&ں|<;Gv-bf_hBZ]͞;zd帖ݺL9!9ڇt43`=a7~NDžVV44J m0>!7D DI]J\ZhJz`+Æ6Q.5[iT%"ZLsOiUs|2_oo* ,Ѳ*=4%he t+pӦmkzFu|{AL9'ɌI/3"%4rTt/̞-(`mh\O@4 ,x['CfC>rf^rNiJMIQ~iqjQ~Iqd7BCC=]JK3SS+t&g," Ax['wMfC>OL“ݘ'cS  tQPR(-LNTPҙYl lIFBr~nnb^BZbfNjH$DOa1W=.`%GW%.4.̼ҔT38)-,MxmO@e Ua$ VTT ;HH"yv8wqI剭#ˍ‚0OY}w;Ģqd{ݜ HQ"(1*'xa>;~a\Zw߂mRqVH½Ӡ.Jdc,n>s%ǶyP.RX'(e;sδ^"cϗ`9 GQɾ Ϫ\@Th(df=;Ԏ_z iKVJHLg,B\pο\8pTv&P8`Qa wíH&3mo0j}1e l~2_nS^pEaf>&Ŕz=) zx۫MaC>OLºzv\zIE\zN ʙy9) JyzJ\zz\z\z\z}]NJ!ޮ J ީ J: !7Geء& r"HL RSQǢy:Va\#*>x;¿wFмĔ LJ]R0G!Q!O+U(HU l$(W1yM=\*&-jL1X3ȤԴԢԼJhzfYjX.?)+52=bĜL QZ\Sw-L.99 ($3?OB!- 593-35ddv}*0/`5KUOS٦N>æae.x;ŷIIA93/94%U(8XX/ÎK/K#`'R_\fqC(=)4;RAIZif 5`Xx[7At wj^Bd8'F1J%c%#S]#];}R 1 9@BB6WYI*R,W^XP>9ن+&-HaBf4 (dBIFBHdMmz\zUsUt"ȢeWP_PZ4 l6))E J&w1LR T[$_n1߬LnbSubx[;grf^rNiJMIq>eq%qyLVc|P!&)$#X!9?771/E!+(5$R!/D!3 '5OMI ۬R"yxk;IIA93/94%U(8XX/ÎK/K#`4sLn@x;sgc(=Gx{C([Q~iqj0&>FFSky*nmx{C 3#5L%2unxxkX9i% "apxۦTaC _Q~iqjQ~Iq^L b9,lBxۦ0[aC;ELSx!fx!NfC c&&)V }RxVo6_h$j~p5Q؞$`%*bPI%Dz# ɻ{J<c8? BïJ-$YZRv%kISTrMFIKySpHT S!FUM qSbo<Hm+M{2WibO`kǓ>8tyWkk2Gkr8ZŠC[&ó}Z_wB?uH8{K 4xi_)K\Z[p]hnxƥt\*/g?3wfk˪ꭆ\qrNjoa<C`~~ v%H|{a!T+aа9J|ⅦoS2 ʥfry\y,W+9s̙on:4Y̡I1 ɗJU }wk$5Xźڀ0|]{a>}/?yN9. >3c=Z9X"E4ZoJQcfwD'FRf0-'}|1yRCW2^dx9O1Ķ^Xx*b\K#0qJv !׺_&YK st 'XwBYhf#M^צ(c.Pe}Eח<bW~H Cy> O+Itv%M4JS(eY /:yq=Oj>~KYS%,cj}]0' C:y"toM"xǵFPnS՞?"JT]N5^8 Y{S=եaڂzJ&_rHZr{ھ?@%`(%Uq+TQj3U[}>JwJTc jzfSO}u,?XsYls:e h~ӛRa r[RɶtWlBg@wmsnJ`H|'9@ԻX9y6 i8uYZkBPm8&koW2._p^0Uw9VIP8 ~5KX%茐-B#XEYOYֹ kjThSIÄ.mi^ީ梐lW[[촎Pe ӸU`q/%A7VY6"<>?ު=Jz^tL`4űk.acq NhYq>֊ftV*Ԇӌ]H|Ÿ|^p2O.h[e"qhNjC&x`8C {e (p\vmT$k4: Gv=W}ҹݻI޶n`xݠs :jI_x~\=xmTAoHVp HZEi,,ESfiI8=nf=f/ComC] :_΢sDpiܨ րk 6B)>A2iF!B3YG{?Լc.$cNc ΛB'D.-4mL>Ni"5x&33VX!ݠюNٝʜrd.:KCu{wFo )\Ny7Յ?WVSWqf:Q+Eo|KVfj>}Uzci jVoۆfgef_9x7o/ǃ=@ō*M+c5 xRMkAe3XwE0*ABe/F $ArpYA7a,:5نIwC%ՃW/ E~AH$ګaSկ{~{pyQkm>I, ^B ;W[l؂Cq«3_d\CU NH帐 6tȸRKF7ӿҐRYQ8$ rgg #HpD:x4 \oU\å]͈Y짺Wl;ya0Jo{vnerWݭ?qf}3afI}y Af+Ӕ(v܅%H0S*oG@QgesmG3_sX{<>e蹭o=/%EY x}TOQ` mӮ'@ih/&$;} ;yċ=x-l7|3>LU<Пjr&Qd M؍% `…gCZxa,< zqIӥ% P,.}cMQ/U@Aeg`S)ɻHܝ;ҨX.TN}U])OJkuxp]CT(W Þ<1>Z02{\0W% "t$* ۱@ \ $BBQ !a8qѷL6gX%xK)1OI#8GxaPJtO\:iJY>c&%$&T510F5&,a Phݘ dE,F Np bIixV?U GrRsR^߀s;0*ȸB`@69(G|C&[/IG6;Q/ISL6jf4m[Q|_+/*䳹uSդ1@۲+i^[1`a-ݴG9{FXԙx.CШѬ%rHjD"w}4=1i]/rnӻ̈́ nfMo%f)vC%q͋ W'Qr+G./ꯥ;FJBykWy9}.<*zx}QJC1ZF S.dKW izjC%U:3 &WkdJ>2s{MΨ"07  vaT?̬\yHNtlG)T6>^B4!X=_5W[BJd4fjGmբ1VHTU-kT)8؀й{ŕMd$C`"PQj{PhuCC.h)'[\Z)*u NJy+qի BY5vPۜ܃J|b=e2ISYz\y{q7NAK*%3pC$9ǻ{p<)} m !otAxWko6_q38Z* Z"ԑ KiQAKU&5{)t@EE'ϱYVbndF( ZH5<$'4JU}Eϕ0KXl&WrKFI y J9U .jUF%y$Сz{sD1se| Uꭆ)xe7z{+0`g[Ԉhrf4VvAS.`ЉIDK_[ÆdۇL'7737оMU'F_ A4bJiѹ' 9tzs}5|ƎU#ùӠĢnپapl׼+ū>ǐ˥_bv*wm_XCjLO=w e0hfXJ34>484|s5xD=&S؍?9T_֋B$Az͖܅ C0[##WK(xڳN׬9k7EɵO )DږL1: +R2mVNll{EB*<ۍɍ q^C9>(Kr|a')CLjfc¬R(e.eeJZPI\i.`JTq(rQvĪ,z = \2-1J.oQeWV!A҅vH٧Gnz]{Hjm""oszLě4jEY"tbe=S3 [믭oC $^$>_A@ ;} tѠ$=VxvM._ o 6LM5.4>ָvi_;zE+q;F?!,Ԭ˺(z38+2G{T:FQ(e'[WVw:]V Z#ik-,^nnl+pF=V|:iaByÊ99u^y ZL^Nv>v1og;My1}DJ~25u $)M5s2EO)Y9Ԕy:ݳAG7:PR[E.D{^9w7xxWZgUeJa Ծ`qx]1l(]0}o6q>Z}>xZpf&xunAǕ8pN@Y(|*LlED=ߊKdQb-O+RЦٳ}E;ӟ?L u ?N<5[J@IаEOQ(\ueB\ZT!;l{\ߓk)~9p ,Ԣ-KQNsD)TA[Yv5,.GSsSh [lC udVXg&z?ssI$$mljbdgsd Aޘmy-&CS0owxHCeCY]H^:x{Ea'2b%A]T`{$0'I n82?pARw@̨0oEҶ>`B-r$}1b\5&ۖ:@p$䞥'&@~ޮ}` uSFez^}ȗ;Ѿg$K]1w}17FԅzmS)Il,A;R>"" F`&âLfJCȍ1`L`a+F4.@)ބT8Ў!`>sqwCt@Ґt&ld3Yk-xi ]#:V.z=oȸO5]`;x$'L!S`>Nz";wC2mV_?Y@h璆@4INAO1Ā rc=^;7bۙ|_FE4;P~j7jRun=hTqj֖W>v-["%`Y3VD$v(G z0=;^>SvNΆny8M6 |sC^  Ag<'Kܸ]TdD C*t~.F{R+* UXS,e\k= \0sΖl1]+9>ѥʎ2Oý]^ۋ7N}q+}ϙLO:)2.LIT*hbiiQpQEj pZʅXCYiA2E.ՔZoˍbm积;ۭGNxIUo8 AYq)|Z!Ե)~gܾfwJMxV[o8~etUe#Bth@IڣJH$`GRڲ*/87ofi K*6lba9/y 3S0uM(^ZOۅfyB`O ğNɬf_nge}So:UnhbSa$9_ \au= NJ֘kܰ|7=YMyae#2jr%VŨ{lo<MS~Km6lj0UCJcHڂ5+W E`M (,3K_4RtP V$~~"[_FߚR_}{i VZ0ۆymT}8sȕb8IBQ`S ^g[:x);{fL,3{_{\]vJޅC [8ҕt$f$t6@l5)o,qo_3tq TvT\\VTW8Rp ԚC<0-|05N Q}Pi5'f}S\*t#Ej_Sìih@k-A0V8 ,L.>?ɜ(j:9\hCa#OPW X0gZr2:S:j1m]shQbWt.k!e:#_ڇq kfOI sT OBFK-zmCb1* *e]ˍKUXm[GΣ9G(lQiT CH#M`<d@q `JaX?3g'(`0?Ll( VR*bAtclDܬpJq1ďj1f<,vyH2ӹFô? q{EK:ʪvO&c!xS ^:r\',,xjmȤ̼8Q5&&?ߛ:I x}Sn@U>2bYP`4n5 U"*Uu=X$mVoJ3$Txe{=s^~eqJY ;0fHP - @I>N|s] m MHchnC1C笂_nOCo4!S243ڲ"aƣ7Yd|`d&#A*LWE C Ba yRK,RB`8GB*,KSW4r,4u0%.ʶ9 t|%J Gb0PpIσig**߿[| b{(q,j+bl]CdRm]?ͩs@kMB&faqʎ0)՘+YXyp5~,Hq0z&Lsh&8a#l#jC{gxw;(:)F=Dޞ?|KGb^SIoc^r?^,+byIsA~Flnn/^S^ M#p?*#xxmPMJ@ZkAQ>6P]1BB BLҙd4΄djq!sT'%\ NR)|{Z{[}y,,X(Q0L ܌c>_n6[sh2s qV7ubuܞۘ 7=:؇* X3OPAjI0Wx {y;ۮWaɺs[b䣲 _ GJlxSn@VJ%'8|ܠ6C$(m-)8x덼9xA*waY>Pk ~wb$ ]3)L(tUş`\GBB:!%Is H]yϙ@DL]QVTC76-,0h=Rld|;\b3k*iLj عLh8Kul=q~?< D)nW㱐PɁC}՝ -jMxBMT 1Vp$PM3ZA`L&bBZ(Rj!$FfȻ'p~U=R3/ *B y͈C̵)tF+Hj=Ag% i B jb6O4Qg8800!&Ěua,ĶAj+1w}猠sFܖq?*mdKS"nlj YB蛳!ҴBY}ͮVYr/1|RYxX]w"+€m8_&Kz-OWb^= ZH'ܡsLud"n҇J )嵮g+uBia ?ڮ_Xw x[+|PpC(rf^rNiJMIQ~iqjQ~Iq^Gdcf$%.='ONxoH% ׼dJ%POc#VAiNh^R~i^KbIOj^zIPTSd+HVAQz:%Mk׳,cxk#IIA93/94%U(8XX/ÎK/K#`$URHppkBk^wjB_P4%$'5/$$ *JOI;e((iZ+m>lW&n x#2]dcf?s$n2x;(GpCc H6'exmP=KArI Wh54BM" l.w'wn0֊@^̼yo޼Gq:щ;NHI}PB-%2a<_ٗXl4\\8[8a@qm(ma  mVH-qGT3uhs F&x9+2CBb$x(I8zũwOziE,!Q IXrBСU7 >; zb(#T \B.kX#֍ :g"F O!4^8 mEr^Ij[_{LcYmd;Ou#xE KQz-]\E„SUϱ9r2Y})zxkgHodA xS@V8;-Uh:PwKD,q(PH:Y ]+#PE(h5x ZfXu||KsΝ`vsBqS|/,.`W cj(° r؆kԧ^g;|9!._8zςKe[Db`E8#zHVS&6&g{MMx_O-":# ckk;01aUKźX:u%+C]*.fi.6V2ISφfL<fˑIkVrJMjtLlţl#閁/ ×le쑳uD~ uS;t :c*;Admƌ, APOSYJe@|i7kҐoqS7?ߖ)4an7wZ6ɺ_m# HJ CHyIc:d ܐ~u@ FRL',vNUt@QHqqhho:hvvv6! 6%Ao>[`V̴p!@ | e!Y$}] (6Zf/NΪEzy,RҠ/0j.$:#" G@pu *+(ʀkS$E Xlű;.Mt=~`xbs҈3t3E@E30!e%h5Gm^t,{y^mFU'(~);-0_NbYR0 x+"IIA93/94%U(8XX/ÎK/K#`r 'J J ZEIa9 JJ0dUYx[ \`C2rf^rNiJMIQ~iqjQ~Iq^^RGdGf{v%.='ONɍ̲ J ZEI.% JJ71n^x{.H`Cc2-Ex#M`BHFBr~nnb^BIBzjB P($-I-.Q,)NIS(QHJU(N+QH-Jy/>Ɍ,"sz_x&ÿIIA93/94%U(8XX/ÎK/K#`.rf^rNiJMIQ~iqjQ~Iq^^RGd_f{v%.='ON=z !n> J ťIn9 J: ~!F@ǒ$%Mk͌,Y[ m.x[#|JpC=rf^rNiJMIQ~iqjQ~Iq^^RGXf{v%.='ONs% B|KrtB=BbZ9%%EI J JXf n}x;%xTpCcILl*nx*ApC c&b6.ZxVn6}7 H\>cG6$e J,viR )qu ΍eSl]pqv LJä kIVnQTNbP)wɔ*%.Ms))$cjn+eaDQ ɾC\ь,sUھs54ܣ f*ofL`n(,b%Xb)w3;.=+h[]Մz%x6\gWzIv49>Q.+>khANo!ޱX:;S@N0gC1}_ SH"rENeBB2) v^4lI_bg6>'&2^0Zܙ˯HMVUN h]EQ mT7HwK * YǡXm'dȬxszwչ;{-:{E;ycȌ)$QP T#űk< q4]$y=ItAa*_Ic^ʷiM])) ;5QEd]/FYDqw<뵋Tw,Fw6] %JK&t9ih=N;"y۾k%B [HMrڔGثimUyfC;iQ6Hߛ u!MũZ\\OpPI '!Ώ06Ȕ~8v֮FݺadeԇK3|NlZdu5ϛN)yeË_gsJ1 (+J3”m#~t܇$V[{sNx" 9ޡim4NVp2 fQ)uaf0tĚ`9.6+Xoh h!HU dJ<ߗrH{x5 $s--,=ԇ_;/s^q_hE n./*2uxR݊@OeʂšOPwˮT14BIr̴̄̚K@X|^/AW Ϥ`!w|4x{RaQDL3RfLVN@+0 R_|vDe'BY>)XFRi>m޴6n7;B͟6:.Ӄ",/mo[׫*p7,eK5SNډ_VS$ω#X(.bACx% 91qTtBǔt-EQJua!1_*8P:w=w8>M9n4/[ZMׯ7uH(bt4Ԩ@ΫҵŘ[{GkNە\h1K0E qaSk{+ۿ`~o\yZq.T"W0?ά0-NõŠEqd)%w}i];޿DQ3nxuRMo@U%K|\8 u.~i"Ŕ&6PSEx,z֧sB\6qMawf߼}ofuZ^Rc1x\E0Z!#0H #v0gﯭ7vv- Wu_/c! ~RoDX&98/܎ ،Ls)he=J0CV2KHD ,I8.@OL3-)bz ܶm-;ݠ[< [++8OopRWfWL -f bR.5̶.cfU:1u䜇`3SE#N*g)W4Vo.N][9:|C/$7Qhtp̯#2Rie{k^3{4\3&9HU+ܰ9Q5[3q>_;Rb7V`x!|Up& '̼ҔTԢb$C=]#2S+tB=B&(+)'&椦$$*(iZ+m.aIa lWx[ $arf^rNiJMIQ~iqjQ~IqfԐxoH% ׼dJ%POc#XiKbIOj^zIH)2U (^NMI p VPH.r-/,IUPҴV\˲B,nxk+a5cLl+H1)xk,a5cL! y) i9) %@vG@x/ȿ!IIA93/94%U(8XxBFHBHppkP3%5;(>(HAXbNfJbIf~KbIf>Bcgnnxk÷!xs)+'OkxkƷ!xs)jfVɾlB % % @B~RVjr46iFy(Axk÷!xs)Jf!<̼Til!@vr~nn"P<-13'"]Z\2 V nZx*xApY&͗.Ksx*8MpY&͗9'橗(e(d*N>ͮ,d'&3sRS& smxVm6_1JO:v,ҵ=td[L2Y;wr*/3<3c-BjBkxNKZr+% j#$<['rѕ0M kQjeγ?vsP!յMU[!NDv5Bb 3Q̣ïe])`9[LIa& *`]`Q 7"Kʹ %g"d\Pr: ػgnu{0>B؛?eCI_xK,tJ?AJ,#GQLjBBWv}Ҿ$qzݹ|#|RU@2C-}\6w|oȕqղB͊߷`[~?ptM1z'R%| ie~.܂cBwyw8̌gESXh>7Nb; fRU\E ZBP%Dӑ[c8x2 `rzQ\`/V2gԮ :.<Ԥ )NH(-XC@h ZHK(}ix0SO8L$e߾Дb]h% =T9E4isx9,2֐`Eb5=wEgBL~$HTi=1݊DRg,Wѷ쪓ݖPW :ťtgU"(b/kzHMm[Il- 1ԛ3ŒDiVsa_WO=ut94^l F^BqNϦCچ+!71 LY-r 0:Mj/Q>qqM(#8&_UN20jgC̺2R= 4#^A45VDm?X|#Kr 1`B}%`e{9݃Dj*\M>ۡgl󇹼XV#՛Ͻ7\`H|.d[憡df "/';)+~n"(m @_KQ,g);O#>V?N4^pJAUJLfCg{ùCG^J2Qq%%Erbq{)ҵ3dS^[ `$JSl4G·w%ٹ _s$I1XA\z[ӵY̸W0ZC-ĩ%cn; >lZMȆ;Ḋ=RR;YXs9zHRO<Ⱦ\U#rvhZEO:v~;!Kj6 x[*Vl$& '̼ҔTԢb0K+zMav qRPR(JOLLN-QPҁ*%楗d$r@mI$=Lclǚ-(xUQMkAe7B xPPO6Y"BB̴vK@}OO${Yn=TUz[JDJLCa8LTavz4p*{iatW+'ʂ@0 T*Q%Z# RT,L %a52W,U(20ѹ٦·庁3 Z: f?x +4V؏P6<6szGiHKd^~"a@{Dk3W4ӪDRںxVn8}W 6^ 8 @RZ0`F&!%;qgbI3svf`P6[W)\03\ Vu@a>jrr/ [ HJ /Pi,@ 0BZmu(MkXm,͆)԰s^9勤?V:^Pz=m.^ m@ \yݝ7/2qAЙ7֜ A7,G8T!g⣁V#V7\=7avXÚpm\ $KP^{|o%+/LW۾|9rqдuLpbeYSV˽|ɻYau0hQ9̆Ƶ]E+H$dd4Dh=Dž6 Lksf+ 6 hM/DcE'U\DogFSȏC{ƵT[Xҗ ڰ8:)Zhw6|薠]O%-_fqwnИfavM h]-̕M5O۰妒=AW W $y8j~+W,[E_^3K0GCǛc)Bzvhb To9He[CNgIvCqfX&x;%r@dkXY'?x; rUhC$rf^rNiJMIQ~iqjQ~Iq^^RGdsfxoH% J%%.='ONPOc#pAiNpfz^bIiQOj^zIPSd+PRK(= .i=s TO)n x*tAhCcl+pfxUmo8VZzjs}އ{Y)lJ%iWIGߌG[33㱻p^CXJf,YZk w,] MT%{.bP^j̬WFKbg 搨Z妪(FɺXfذ'OE.Rp/Fo#C5^i>Dܸe_yȇŗET z-@W,0ح1_ Ԛtz|Z.*E9p| (0 yah]DWbyKt *1D+-#公!9WL9a8-J`PիBȉy2(?'s| QEm*ɥڸoG&29f_q@CU?A@ Fb > -(' ap@mρ5B'E#tZpG$yI8+DfΈ_Yfp~y9&GSc;Ama %A?؋6~oʬ s; _<`$8et˃ׇp&C~^cMW389ኖvW\Ǡc*!sMBvy !8P:UZQm?3AY*XY[!eO*q4hoeI3~tk&W~ƒۺ n\8VW RB Z''}s,s!U-H\ʵ\$G¨aoKtr!B3.lI"ٌi.Đ(p#. (O CgLG$r  $hpYA1D¢g|1\2O2 WlRE$lWA#@Ҭg1ݝEN++,ՖP ɸק ;mo!ta`t0: L7 3AWQai3|CN`b+,$%76}n&(*/k1_\v远4Ri x-Ҁ9K[g$ak- 2ꇠ6Hr1jnˇ'go+qW[2w[*S+YIFT/츫@ xSj@ !_AԇBC/M]lUXrMYK#{RW+SC|~@П)tVؒo`A3o޼yz8}G*wB_{ST1 @ J+$$̔p㗟/NZTa80ԞQ /di. Y;|1%(@1<#b2sJeZ5e5ɕVANN'ʈc[QtҶUӜdHقXE @7}*olDfR3_ |HujНSe uw%{%56U,PFv^򦵶uN)Ϋo?{bAQ3I*x2fT(L@.v+ZU9l e}mkۇAqA` `Rec7UG% D#b'XKk޲uxdz8Z^<%2w-XcmN't=?U=Bg@="zMMF5?uI0xk$ᤠS`SR_ZZT_R\<ق|rBHpp|cBAXbNfJbIf~KbIwYJ!xY*8Ad_bIFBP~RjQIq~`F6Ē[c LJ]d0G!Q!/H,R(,S(HU Q(/J,(KW,٬(ׯ9YuIsTLZ/WrbNN1(ļ;2h6PkY6OĢŒdc\ȑulzwsLfYXZZ4G Xԅ|'4[lx[*xl& '̼ҔTԢbɕ51f>"x[*xl.“+k6b^RCx[*xl.“+e3S+tB=]#2‹ 2ҁ/2lżBxȿF6Tļ̜Ԕ~K 6nxoߐX9I"6(x˷!xs.tHFBr~nnb^BZbfNjB P$d 'nvxVkk8_1x/vi}lBܼ{)l˱d$9!~GrmZ  љ3g$ )* waJPå&4+nQTnSqctLAJ5A 0%D5p ucXHɦXfK es? #Y$~%I5`RE|^?/>'X|^~ߠ tM3g32Ȩj pVmH+tXc pH,[`gW8ٕ܃/r ÛUv2]^]yhǖ&`!۰JL})&2FI@>Ku|b;(\` )Z;P/~qcH4 Y g+j ~jYaUaHx@dv; unJb, ~'!g{hvwK9SD=?'y<6ooB@o e,iޒzv{~Qu)؇\{gi-2olxk+!IIA93/94%U(8XX/ÎK/K#`/ ~!F?0*:E*()h'%*(@BUE(HBUf%d9')(iZ+m͒(n x+|CxC c&hv,[xUn6}7 S$j.MzYqP6$' ZYleR Pc/T/sf ,_\zz6H}jJf2~M\lw!8 L^ng#mx2ǣL/"j.7;Vp~B%>tBHg νPyE߄c:' g[ay RZ+v1p66=zSVnLh'[}vx{DKv+m^(~TܴNdNƻ.eVF5:-5[Eh`0?ea5FY#>EAmSo֒V;- ]Uzax-p[l0ǃG?o03$¬J~5>^#5?GI2N!Le1<4 wGk0}'/7$-T5}pA?uAE󴗴)izw8QxmJ@EF)(хhPA*,jQ(8yI33a0_ᮡWgܻ3 yY3cǐ#R#wVIo&^מ!!To,A Gp~sE~5:'S+ TYU`K5-Jt. F4!JndQHt /XhRKw!fv_[ÓA{?SmeSx;)x<& '̼ҔTԢb5̡~!F J 9Ey) J: a9>y% IWɎ,bcXrY I gxkjڠ¨0YEQa;^5#xkjذIIA93/94%U(8Xxrsl_BiN@rg^JjDx0P(= (Si9e) dnexk˿a#cLެ+Y2}xkxſa#cL,B! y) i9)3 / en4x;j&X+Mx;οj&^1 d*$&(%f椦l>' xU[o6 ~@x8 zmama@@Z#ܴ~Aڠ/DKU?kPZ} "i %Y7SB]+λ1Z.a 2[>C\[P XjS7ViԐnXI3Qy{ /K*ShPO.Ə(ԸXt;fr,w05'^+058%i!cp@_?[IM ,\ʞ0yvQ]1xjiND]%K(9`g-HU0[+Us@ 8a6)s0N A 5 hE_[|/g6_$QBXh.(Y~n!A߬1?vf5[张@>>0V7qcN B ^Hg{ &r Zar7I=# xPV Y:“-#ͻ܆IG4ϼ8"%|"b; Xcih0l-iPt(HOv83}JOlSWhFLcaܦ pT{ݠW4ޮ*DQj刾i10N4Vo2팙+NN{7E,*ZL*'hyrPlU36@4"y*vaz c?rm*.B I5Mp 䁆BUj0L>-8u*'jj͙ӈF mxlg=rtA3U#3\lUҍhks~PiW4 E5=ʼn"3sZ@:V-ɐ)]&LՊZW_׺pe˾j+A6GâBB&A|!96S-O-MwKdVYOK2y}(WjJ%!ޡ:܉ au0~`FCX,u7 xfSAG0,k07JU{ґOlF#H.uһ/Woo%s əVz?Dll4x) }=vk&xUJBA@1 u ((=RMFQ |ӌ̌EТOK"V}Cm[m|Vrs~m9{}*bS[.ՁX€FVcP BL_G qsSGDMPMТ>TAEk,]"#aN =9gGzk(w)! }bƳ]5AQ*{Y).}ZZdfL!SAv5==-@'oݺ1/4K%B(izxkn$ᤠS`SR_ZZT_R\<9}f POc#%ҜԼ %W-LQzDJAIs&K8+{ix3{/rf^rNiJMIQ~iqjQ~Iq^^RGdmfE/4Hn@x={Cc&+f"n=xkl0x,׬%!Vxk&a cYL! y) i9) %@xl:x&pw.lFL# SxUn6}W  :B|lAKZ&~}g(v$Oȹ9sf|Tbp]/H˵dV(jFHn X7tэ f`]^t  Ax SoVfOw*uAй7k+ iVpܮ- .WuXCa,7{$f3y|vL'`>ܻX#i<)6j*4>9.fZ,\k!KY*sD#y+qCP`Aֹ{wht v uM]{=tq ]V~謫lE]vHA< I*XnawBA ebZ+S[G˾^U+u6 N_ 0LYx׺̰1J q|2a\ѫBxMi3/g|~bj )Ѧ 6P/w趂Y*^>Eo(pc0?/ _k49w"&7$d:Z L$)R ޫׯ H!9f(rI5B s4H7V ݪ^2Ճ|mğƓiLGdP_SONKI)v8kJrmVaK+0j|Fm+$g$3u;$0`GG5 s;yXnCeb4h$Y|_@!K۹*+ q4 ~}}KZ󰆌n:6HƟad &;>,34C;:\[m& ltueK-{VI~On,e&] ͼۇ6$pAr;CB5>E|PP.'ݎ&*f#j\0e"Y y"鍯ߝ\QzW4 r  PI{`6];BL%QYQ|sٻZJۙKVCk0:n;̍m } 5$h:9}iܻԟMfh| $}QZGxUJ@I4`.BAŻOPknkcIqGpUG�`&D%E1CkdjM.F@Ś2&M Ѩ̔kL3$\L#.S5Ibrg^J'~UF2sـ>M Fey|sohݺjN[zh7F%,oix,6GdC+rf^rNiJMIq~qAf|IeAj^/^Rl-ૠsTPYV]!$88>1OAIA ,1'3%$3?%$QAIZiC6 "G"!xeJAƹ0$ A!<Q{ `%n[9wJ|aJ죵Xs'Hjgg[<$:@GJpETǛ- <]yrP5_{T-9 ^>;N+ :mP  @U'VԆ)W,0aTB^* zS@JN;LR:`:O4_8A J0g4(g2BӆD0kf̰0+904/P\EeNBa̔)B#az +)]P_oVR )1?/j{yOxZN =]<*'qZ_(E/xSn@ˏRKqadTUU-Ɗ Nٻa) \w8qƬ7q `7};o"j2RRaHR:[/Z'Tg4n'i5"n7S)A W.aLH4d g {Z 1c+`|D?4-:)4bjp`R|;nptX.b/I#(1WD*H)R#C$ lW#"A#ǨcbmLS1c#=LX Hu9H2?5a@%i:xÅ^zMbT6~!Ђ^ >21{( LR:V;%e4IQ~p =R 0B/BF -)dPEe*n,qj-7:SaNn36z]FTumVf7j+7U{hAT\HF0w4TڎCaIY#'q~ϲwaV{H8zcs&;kI|x),i&ʂb ;^." 0JPI!#$WAIG (ɩ4BHpp|cdEͶ,{{W">x{%ȿa+#{jkYjÌNPvIBzjBBsB*HD!-Ory) y)Pܤ"!LJ0s4B=B|2zJ 9E s'gְ˃d2x0W-VL,p)egXlxdp0#yB~BIF*ؐ|$ףX]Oy%\Aɩ@íhLI,I\̦ŕlsJ&ŮW£ ƚ 1iN!HCd@r#wxRJ@P CNhJhA*6nzG? ~W~_n$;f{;Q ,9e T&P\`@#e)Q3Rf <vNw; a^C:O{:Ȓ z,Vs8.Y;owu@!0[iE5;Fìx _KJ՝`tx[C/ )*V-u9eaĚ )R.V0KxpgPVnwsl;O~>:/GHDx{%oC)rf^rNiJMIQ~iqjQ~Iq`fG%_%xoHwj%L(1(QXXŒQ txk˳IIA93/94%U(8Xxrl_BiN@rg^JjDxkf,q"nSxgC;c^0kxsgC;c^ILBΉy% iy) % !YBDxZbfNjOyB'kxw & '̼ҔTԢbe0a8!xw IBœ˘7a ]Dx?w IBœ˘7aarNS/QHKQ(HU Ħ$d'&3sRS&d;nFx{oCcG,._x{ŷoCcYΉy% iy) % !zل' ssi9)g]Uax[#Xp\fVKxki0(8XxrvenHx#2[d$&ԢbsioxUn6}W 65楗GII ZEldRKRqݯ eit$rxf\-02֪.~D{ZzelsJs0E."r*Qj |֨JK0|yZ̺ҏpgMBf*!xBU3ZLSb)@ѳnɬTF|.b|QaE=e8hSM6=t {94kqcXç.Kaal{U|>Yvhp NՀekBJs^xؘG)VhQ(I,D)[Vm '[׳٘[c ,yBU-KVQ(My2U{ FԆ8OPRKXkpAaY 8#AS(lojv8?ⵔ=p>Ov:ubYNi?SͨU"wVЈhuEAo f^}Q1.gtzV˟i6s'eLfy?ތc"*$'% O3qR1 n@kIZrH[ͦtL w(i;,}??}w/B!| Go5#x}RMA&(\G:#N/n2L 'ۅ%UmUCV9D_<=zy?z?{_:,rŒJu|L^m09]ipB<iT]&h G;m~<o(^z@z=Z-w->~!RNtbK<ޚ=d6:[!A(l 0ɮ2ju?s#x"lkV 頀W١C9g1}C $'BVZg\JLƂx0 pY0c 8s.K"6@@82!%ɂ*@@٪!_y͂Dl&$s2Ron~Z?0A %vxwgZ-Gs^7s~3bi5J? on'ܿ7ޠ۬ /l)8xRj@)[A ^R]BEX!4w#yW]_hGz+o謴8)1P]$y~7J ǧFn1r0z ej)Q. P)0F~Wɪ=˷u \8x# ϻ<ܭȉg0Z?:{)3[0d;!arBqBe10iDUUvMȣfrWadR-kxb-i:UzD %MyXSk9Jw`В?gr#xj|FCFCUMJY 0xM{րP,ƹH #%.ї\k/3LD ߍ߁'G:'n ?u8FQK+/P 4JrfmoW#Lv%M#,2kɊeݧ퓣 B,xx{' rf^rNiJMIQ~iqjQ~Iq^^RGd%fsv%.='ONQrk?$"xeQ?K@Gk+.\u[E E,k&K?cPw]yu1;2JRd %!xfB6A'F7iw7gcXKL+#5d)f2%@a퇋9 ͸lO4sZXCuB})bK 8wB>~+x*#zz&/**,Ŋ``L2aƭaLkkv> '̈"x;,ſ!IIA93/94%U(8XX/ÎK/K#`-9'R_BV7oce(Yx]RM1dt c񰃳 "zP<0an< vt%;Ae׽ A_z?tөJիz}߿FJBdm=Z?t-H F"C5T 18iZ~ƻ?<e\ʜh(u>{O$J b##?p00ta)Hɜ: XhQ2B]=Nd@=5&6rs&lb DXAZĆo[ȣd$Kd᪆Qo[tj%jPeCm1%V&f)WCGRhw`Xs97T3'a\* y ג\?&e1Qzb{_NRMo>m0<|9sRg֜j}1C'HFaBxķ!IIA93/94%U(8XX/ÎK/K#`'SdBQb^J~ ,3X xk?̻!IIA93/94%U(8XX/ÎK/K#` V tn@x;̻wC1cJ&/(n4xwoC<cT,*mLnUxoߐXI"5+x*x'rf^rNiJMIQ~iqjQ~Iq^^RGduf+Fɉ̢l\zNJ0l> /nRxCcrV)?n%xʿC cp8V%jox?vvT=..*UxW[o6~ׯ8 )R-M=R-؞$w`%"I9츎Ӡ_,~ f>UbUX'Z2+d%j#$7XVJih/-[eB\[3<|TⲯUm\VuZ ˲H*Ȝ̵VeΝO/Q ó& ARy &ofo>̖[A^:ڷSCgS`&o-Ԇ̚ n%i9[Ca,m$f3 | ( xM|ڹtSSy:UY2#L ?57և+Q/>G$SKUq@̗\sq,`r] f[,]\*HφjaSSa[Ed2͹K #a4 n%?Zg$ NuK6DJe羲O^X`'+ TmH#/Y6TQI6s!޻@7QnQ́k:aatayzQB*={X{5Kt,QO=wb`[`x};\/Eok=R$sXb2";dGԱa:G@N,1܈;ibH zt CUr%S 5%AJ sw 7`z HSY5{b7 iJ|2rGS yu=wxp8IeY %r(w=Awұ}CuFf6_B!tq,}·Xv:F,+ x Hl& '̼ҔTԢb˙B=]#2S+tEJr POc#pigJj^IfIObRjKbI"H)2U (]M~"dOViAZ籪M>* ;7nx{$vWl]&͏92[/x{$/.cLBΉy% iy) % !͸BDxZbfNj\u_xVn8 }W&]^/{ OLn  m#l뗔6I;y6:{UbzAJ9P & X{A @"yt-bzk4+N-*T"AhmrdBmhޭ [7o{_kX  b![!^{|ʍ5nb9huTi+n}uyuwysy1; SFRUae^=3 `q FapoMij*;몎"|.}O "" -\Q2/OLʚhKU ) mRe v[!}X]'ucfwn,ga8Y[l@߆u'!/gDݩmtu?v3;d3>H]~ujʁ%_NqY\]{?z^<7{ /lt|PaEsPi{B{Fu{FR#?ᛣ `?P˾xfxt|T+:=BMdRl#G#Y0!u%!K/Cҗ9o7&,@\sCV9I}# _1q;R_77;)8FC;u{}l Mzcܴ{@gf۞zSаRYcpDCML:5r.`&3ChT2w\lNSˎ;e8Mf^G k@iD~tJIb Un|ބSѰb=+eD\NwQ'RNh܄/ #M'`|piH|#1,7oM~}݊h|B;(Me/ɡ;$xuSjA%*J7}AFIimPR5iCvC)D&;ffm>,>~> bٙs{|y"8^^-W>6*SO` Սe ZCqG,>.(插ز dE%1'1f*\i7*Ns[$ (@ Kgꞻ^^Mh\‹ě[nex({޾dJmXU*yG(H{ *ܶܐ%xF#qCX@&%x4$;}|UL#V:N 7@Eh\Rd¤gsٞ`َ7dN2Ăq3%Kf:?AǸl'ᾉ@2}~sߨKX(%Пs >Pksx"Zl*ɟ 5xuROk@ݺBXTʒ]-Y0($yi&3q2Yiу 5٫~ $hOx*"n,}X:I2Ѓ\`LJ^:ƗTYNjG8ɰQ?HQ:i/Ivr+(b 4\no o#t|`߬.`k^ƕѝ1G f- %x{-IdCrf^rNiJMIQ~iqjQ~Iq^^R4f4%_%%.='ONx'%4"Ғ̪"tcPVAXbNfJbIf~KbI" R4يEjs0;.B(x+JpCђT|Ҍ x=B0֛6a~ 9ks9CEXD53-w@:ݔ(cv#L#/B$r \a2oK$*rLJ*"jSS:- h򹔯y~2z&IЍf~ oL ?(ې 8hdH@Ŗ!KZbB 5{g'@)wh>e+$?bJhZ;`mXɀ}͊6$dvFЛ$c͸s+; ] GRG$S.i8 qjk&$tNL!gQ냃<\A*s[kU1~HW|/M@ɾT̽hWZ R p^ɖ% YbXXeG/O;|^Ӻ{\[wO46ʶB }zᙥ:~c!8`JWȩO;}דFi.S89^(%e< f?8BBztC.L=~N)n1tYh}S-biv4\*$hR \88i˒DʆlO@HwwxkC7)nhq$ v,!T.PU’↤>}2/vC˚hWT]ȍKrLbovHkNYWM|xuSMo@U e{B=4jKUP1kJ4 v+UmIFM_@>pܐ% #|_ly?k?V\SEwf_+gKIRgC aR#/Ɲi' vQ E.,>p!ʣg'A+{l0fdM="A{rqِ@OKLug SyOT`FP# bs삒65Bw PərCiDc=\AD.R%BzRN&|xF2's-Pִ |$ꥆ 2{Zr`v0er_ * 9_ GcQ4[@l9 #9 mfڨ,4TdSn=zo'8 ذ}siܽjZg\]Ko8=9gaa\2kl} I5ւLqݤ=G!kB1-SaX\JsU˽oW %*OFIi }o4<(}ǰ 4M^+FgԱ~o⍧nU1© 'g$֛$Cɼ aofn\ў!k,OXg5WXmy|7@.&U4"$6͸;3u'~q%5EY7^R؊c0j Eu^7% 2;{D jHރ܁@J]:]+zl*| IyQt\D{SmhQuk|qERaO8[iZ%}T.1 jZSy,8Ӱ™y<|O7(npQҴ߾k?~2- v@op@q_!]cBJ)V)q7<fd1JcIp;5+Wƛ'A;iSA[%8,a"֝K8Nni bf-uףo-u8-Tʦ_NAnw,J_w1 ɤ- <äQ`f̋")|*4=%Kn"\Q,_w/~[8 RUئ e7MJ62ˎ:Z~bP$_1:Ȓ"D<=:DZJ7m˕ݹTagGgc"U;z#v&ycʠ 4Z-: i@wV&dm~ Q/~ gaZ mUu,Zg~{nB i~O LFK_1_+0m1)Յ)] aso Uص7~M.GlI˖a-jmRw^Whr]d㠅gl1QI7XٶsYIi 7qx[ ?_~E86`=xVn6}W 6Yd\^p5؆dQAK#, $o3Kz99ҟ`-W)\aeQWJUn#+4DZZig|Xp%*ӢB0nHjwZ55*b+ 1L]xBm}_*3t1=?PYL[2K2 ~\{~p7oN_fC$<K7p&6`˥JaZ.be6 6ϯ?_^hNsJ(DKFwxXG樱J{ 8?_f4hATEAT| ]Ey,j;Ad:Ø J/^{ $l(a[c~Kas~hZ,2YrO/5Ҥ'Ծm7do!@)tM芲qqzOzO}P`pc8I.ڔV~96|\VZ٢uW|bk@_O$8Wӎa(>Gղ776"caynx$N?.mN-;UcY=EU0M]:u:GA0mQRir&󐿙A-X#%U{嵠)TLBP˿HZ-9SxH,sȲ%5}g'7N~ iSe[n B[]>ۓ9ZI>ɘt2k] Ig)dZyKl"#FqԱuexsڎPnt*psGGS} N>QS)l !Zth4d& [LQ<0}>s؜B(W9B!B(نC$,5?@5n ƘO 14vJ|ujN%%zEm2O)ZKY@%;PJȂ x )Ɔn;ttM{}LjVG}E5c ,Z`V%t/6Vf hwGih6/ku~? 2FMxMKAVCFʋDVDE v\gev,tX/!'3y޼|=1Zn6TC:BaBƶn mh 20@/VO R\jCH rIaUݛѦ@6sdbѻ[{3X[(T^@O:x/KxC%czv/zxWmo6_q )-MKhP6,9C-Q6WH*YwGɶ켴A'(=x>Uyjm?I˵dV( UFHn \tMoKݼ _ZX%,!Qr=,( v!ѕ8MYY!WpUUBr{4آ%OE.R7\.8H^0f\- Ok K" A\z &oW v/-),й[#;)-TlaM [74bEk(aaa>?. /[44s+SE2^\rۭ2abō|ږӳ_N?hǔz_ooyJ_k.S`Խ'4Z.Fs'q#ˠ=as/OBEI0Ջ4g!+:)7࿅>[G;~7i wlvg(8󡬊X|/ oZWF`tM<%tq7dW +Ť"L4&xDd2b^hP\'!L.`ՏWW hBm>Q&Pf`sU '0T%F$)Jh (Ncq5ch6u-miGfz-6]3f$0G z_gKe,ټ*jH8;v&OST ,u:ܻBĂoO {3d~dO\U:-vs yV d<@MAyrOf XN BqUinsJcr-ى=Mp9G*au`Y9*2]m:{X`R=iP #EiyL^^rSJojc%u~Xd?3ukӊ4/57XT>=lnʃx2!mϊSt)PPG&9w KIȄIGX3Pm(P=\nk[Z.8c<rliъKbe R[dc D},anhH 6'qj$][&)#~rNΗŃd{&cr׭C .Xdµl9,npi]Tݜ|o$aEa>Ogh.;lE1'҅XD_4Kph9;t )99L\=+ǜru;a~ņ-s1 6,+[aV8*̸|;rxխ:d!` dZ6+~y??3TkwQl( +8Z}BU戁c 0Ո%;p6tqBC7p`Eo5}4|vNh`2٩i?IڪXa{+T???@e"| @3]^ঊ ŗ 1xy/^NSSd%Z5pS<(AQ4Қ*IP=(܈Ԋ4LOH#t;kkRahVy*J;{ݎ `F^6],xFs*&E.AAt-Si3S"ȟ'SkJ#, j 8? MԴ};NBܬ`rluc)ƒW8`gЇZ6y?RlrZ䴵,bPղb{ǹ'Lre㹚YrPG׸*}-2E=ossq<5it?{Y;([ڈ:0BDBJ33@+IK bᏯ' *b\&xgQں ha8A9: ΆC([v@"KmSerKc:EFW[õX]^W#($!gۍH 6_˶b lA_f=sJaH[Lp3j'>p7M"#tG7ͣx}+0=<>CxM3u VU(I.NKK3r rw Jh”ir~xX[kH~_q0&vҴ-u\&-XC13JH%](>9$w`)z0VNŝԊpU[p5=!,wX Hր’ziE2qRX dd|?ϧ5{E d:mS'kQ@K,X[A|^֍eD|N^A,:C'^#t\j8*%t=zo:Й% >ڏXl6DG<U,ڀ[ pFl@EUt>t<>wfki=s d"uЌ)tK[ ɌQ舀 N8=ao8bnѩR[H8y] *j#(Kٕ]cٝ7* VWcrxD>C* /4W[jɍ.kPupkJMuIߗ€ A;C"Ch{>Ѐ.x8kV?X 4KY7'" r46c y`FB<@McݠEe>d/y * wWG=dOk]=bc}28hKهb|ͻHfRk&ZzO[z]MIrd8@PM`ZNK^woõukk>t]UvML{ 廧ܞβ qGn;k1$E<^E [fM;̈́:{}&w5\}{TLZ+0z? ? G <߱sx;tCn#|'_(<x! T\b5c9xM$ xM̳u VU(I.Nѳr rw hThr2 xWmo8_1HJ"+8NjlR`^DȢ %96K"Qy}qȔO3%M l!6rPѽL7+46|Ѣ'LQ!(SiaiEW)K.E4jxwXkKMYStL7T'*WZr ~kuM;s_SSzsysmzY2>BIkjH;R)z#Ss%BLYD8(X̪eS$USKu -Qa$ ײ~ H d$&~8#.+UW@ :wRr+ZY ~L-<(I!h}|GN[5FƮ#!5 H@[\1UqT2M$ 4 ~3E~ [=ejY;e#zZSljƐ%祅} =溽2I-FM'$Ow]k>AB֛`)^;=GD|HىC(}nX"^!QR`_olLت^d: KV(=LJ(WZXgGӔficn׍Nlf3^BkWI_h01wz΅.i0u]OAK27ǻi6'_hqg/E YNCH-Y2֏C{u=(C0w1F="r<M[o&l*H5aNH{P.V\X'd  DeGE c uFVFExF0p5"̨~.!z,gARE(`Mƭm`x {mA`i>U>A9,0 ,X {@%0˜E..ͨdH7q;p'KdS@W+Ff8!'ȈCaұܭG /oPBNsRĢϘ<ٚ5iֳ_9x!^vC$Zyy^QjqjbQr^fR^r~~zqb~IrABb^BIFd^ɋyYr RR&}Kx[/Rfo2mfmElx[)&8,!X3x[)3]zqY<JKSuCNfqI^q~iQrjZ~Qz^^jHo;x.*I7e';%v-x ur VU()*.T(IIQ(I.V(S2sJSR9Vx}S0 7_q hvg?vZf<{#։IIH:aѡt|qs?=s#)鿴BiY˙oO_>}d >`0:J t9!RG:*}'ʙ9UU>*cQL#*~&xL L'j=rqLG p\ɂC!KQ:rl2N-ƬB< -3@Q]ab%B0 Է E%ӎ =:-;஘= #{V><)'L\޼dRFF6믷 q/fF!?mA y&fgzL JƛhkkYl"Tn3*jL=tSQYavu x-8ƅΘo3= [9hw2Q}gRx{uS&p'xUKN@ %$)zrHTb [3c2b,Γ$椅Nא9#yF F2:l`4%YEZ]HS O;l!#g%c[X2F'kM5Ek%ސ\Fn` "~ E߸<[ ĜȔtС˦놲R%|5Z,K$%0¥oYO-㔨;)ό1P̊w l`mǻastjTx{ʺuœkrxT]o0}n~ŕOiX~LM:/,\;N\' r|9E@c wh^Í]h8!?ꌮ-) V&GOmAHB+u3t0RTBq' yOisx6"NDVX5|k _֙:wkW5A/KS6PRf\GӫqZDoSϦY%c=,wde v˫\hN)l8+~zi`bCFWN#.քãi-L̊Aaw4|җBT^,Z "=a3JIiIlmP@rCX igF,ѩ:ImyFQLx I&H&p}2\3%7 ^lzx$ VSФz?=,v ՜{I-xuxȽNۜ4>>GQl2Fney3.r M9 x>wkwkz 8J/H*Lx[7k 3[_dEZҼq(䗥Ogq k x[µeZ&J"x[7oC/chG|k|g+'Lމ%EhJbJrRKRJr*rSRS@ZS37b%X mxwgWmxG?WҒ k._kDHJ]h#CѵBP`umrAKӎ!W@t5rt0RBq'+V*a-vΗ 77[u\R,ivA``svK .$n0ЭB "9]xHBnP(5N"P I Ҩߋk1i 3+&bK1 FO6n!I!r^sUX+% ϬBUCI7_>5٧[h.RJHE|1h͇|i4gl>8nm%^|UTQߛ `U;xkUznGl.쮱T޴WF;H%lvpdL((r}(s,^x ))tt;UEyJYLK^e :GF莦 zlzlUcu3z6޸#ADTmRN97@ïfr2Y3Txֲ9T(TzovQhJl:gQㄽ QJP,Ȱ xkC(&ߙ8C|]S]R702k=xukWJQ RxukfLX5or/x}Qk0ǟOqЇ%Ft)S}vČd$7{rPʶ'Iߝ߱8bBpoM`*K\k B3-^Ze2N&y4=WFS]i0N/1cg%V يKE3::ĔUƉjdT 9h4b9b"?@5z[Nl{vL9l* Z]'EcDR9ۮ@'јZ~ySWvʁۙ)aH[# aQJ`:'ٷtt1|ɘ[ b3@NeԎSȜx Ϳ)Fgo%W?_C#pƁ1()*4faIuKTyg>҇Vf>%RU_Mx61d+F9" dAFO6(3 <1D}zx]o0ï8R/U(EZwiBl!AqDLldh1-DB1ZWa,ׂa՚k;BΡVDU 4j _Z<.-KHfɍʳ[! hZkѬ.BrI7, h>k5 [ K\Ò`Ec.{5BXYpۍ8.,;Lf"nC0I fc߼넎W$xgA G,' O),1:y}3`Un8"~;,I (Q7 rc}22 0J9 vs ]7 \[˯՜Ja3+6ԡ#4n35G'O$Iq?nv`j$ՋuB<> )9';ʝsd t&{k|-s,tР:n>"?m')}fDIID*Z(f^ˡ:_+WʓGAa_1_HTx[ǿ{\6#.L"Y=B '((:z ~A \ &?`<"$ C iD*NNdq20La͝ @ 9Xu&2IsWxTKo0 >׿h.:mRS['@N"ˎV[2$;Oq3gn_qpaF0ÚJS"R bgϺj) Eup0($B(bK y)Y0c) 8U =>>~9wb|37h.zoij7 8Iy;)- 58w_/qF%;Q۔xi%\_Zz;W˜@G~/G`?-C@5Wg?]*^2F`6}׫ |kȤCjW-4e2. j2¾Y绾LÁYvW`EUj8L$xEȀc($#;O3C0̘.%}d~~xNȾR:WGh5y5ϵv{h_̘;o^SN]!/)6> 5S*Onw=[Y>ߚkδ2U[! h9Aۯ{7v#f&*D*[D't]51t+!7;ȎxZyo[K9r|ݶkYl+P2$%EMJI*.M9,P!9~w m|r5 v2|_9L:AWɣj'{_>-E0omN6`VH~|9z{~4MFb|3ofFRqt0wtZ94&l0O`s^_i >LfN&st(Ȱש+0O՗ZΣwEuRX !b\IE~Mu~h0R|Sf#d8(VCd6|3*5 T9<_jKvY#SWLݲK~ b_bg7K=.xq\$D;ɥ|PRJ<ļo#ԉʋoNRb$OOeŤ6ű,T,\dc(V]EEasԑGj=IrKNfV-wL[!gb,yW M=s>`<'Mt]CUͤ,e8t(04H&8oC- *JA)~W򛠮BVr.`*J6jRшkwDQiV1o"L8G*?Cc5~6Wɞ,/VɆQs);2L٨USPLq\MN k|9Ze~Y,<5%)6MX I=ѶneN5*UpP[Jf.Kh^:Ň-RZL*h}w\JK2.z*%ox]Vի,5?|t+E|-͂BjypPIvdO5z[+.8|Y(V(]N~jcgwRdd@:$߅z[_bu!kI6^:Ex-jGWC.A{+̺|][ i#;\(#ϔL#Z(C="{ɿâ^YmKp EG_RNߠʬGcK tV*DmXSgFʵgy57$ Cm.^GI8mhy] )ddnwi8\h6d5 Jըw\>'J{2!>3&LIaBm/2>7rӤPp_i9bZͺxY_o6>š9uj}h\It7aYmbtwEٴ,َ DNf+kqzv-9"5gQTd 42]$<\JIHm~% Ina8ğ` lHdb 74ֱ$AKBlW:} !U|Ae![s#ӂb BR<˘P x1&\IzҪ@1#35wa ٜ0<ėL /__FcS 8-wU syѰΏ e716޴ 'G\*C-43C< zxtɔ 4ҏ,(j$7SWlЪ$\+p)?)M^KkmǮ wIJȊ9G Pb<0XjPpdž6QN?0{ [jެB.$ |# ??i9RNHJf|4.ڛnM[5Y/c]PBs]@UEŢ6R(JՎ,c^@56To"t7Ww{RR *nDZ1j{j}S)nJ sW܎/K9:w1; I~[+f`%2pCr+ic >&*[lO([q)߄k\чvw p3/P/7u-rkqbڪ!h h{25d{²QF[>3l+rqF14zl,/xd~\E쒷dbVs.wCݭYwGEPU΋#;^0T'H yGGeV_D¼ ԬҾ'4}2['!m0cvʘU&WؑIWE3.8YA1uR"i4gjf3-T^G;*7:- R"[+:}p4Mk추Nfs>U^Ħ;gt< t>Apq/zitE=>U?RA i ELl4bK/SVwz$LD'5h]p먩Mt1[X$ q=WGyv$] ˃{j-?fN[8砸T7qM]Qe#Kjw#FKK# W?oݞwm͢a+&^3ۚ'FgYD'ji8݁a  ܖDKomHp9֭dVzU͸Ň6HLslD ixZYo~~EZI~XV`;FXABPdKjdM 濧^&uxÈt.ᆇL,@1ɃM &IfHGJY$\@ iɐ0) *K\ɋ䫵@"P<. 9\R'8bO|)"˙|~w?WƐP,b0!t3\ӆq&V%a{d*Xȶ~JO_g;HH($Ԃ;71p;]CN?=yM4ۨ\p幱nG2f! -Y$'IG1fgF$NCm&]*f>3m!J;%Ssga')|98܎"R(b9ՀY,#2gIɄ"*_5i6X, -r;m%sHp1]]8ێ[#{`wB_ynLqxa1|Qmo㓪ٸ{ΫBLօGQ(mX5ktDLqվꕹ(&{ \ lp\ \hoDK,uP}6l C*bg 2ˢfp:1$oIȫiHwiF[ƒj Bq.gn!WwV{vsJ$ޖSA[JҴ2Uhx'Qy"Ld ;]d}oӆoC}n/77ȏ9~?1SDӪ`1d#H,X%qKj I%Nk^Cd8{ďY~DeevbOVF?2ԹDa WB*VczZcIYA?`aJUE;B4Z~w^ϱw?ipH}>٧צ[!8tilDN/sngSe }LOv^[$qIZM}pL|Ak44TX"Bx?U#|(W$>+M~j MD =ETUD{!Pv"k+be )"2bM=Ajy>&)mnGRgs:5D"gKQϯJ ; QQQh@#2bnRڳM§TCGZn<.pMgM t'",aݐ}-hFB{ڃfYVdVUHaj^VG$9~)t6,j4KqyxaėK[dKo! ęHlXҸebm-J߸f26;P~j`%Ģr.DG(F72twKe2:N؈:O_pԽ.f٣Ba'YܫͮfϚ+$I&` B 9Wyk?1/^X&VxM ʌN+b\P|h x0!_Ć"kwBD^yH{*NZ;Yz2ѽv9|0@{@^86z=h!鏂oM#[LbDŽ^J_.y/ @WXjbϒvj#mԣL}}'P3X1ʗD+$kBI;%)ˢx`U)vk ^H^/-Y ;>6㾞@A{gOpAm'f 8d=JkhVEZ\_WEq>:Ey_-K޼ $J-g{eO= 8-8΍0ކ^CUU|U?23tn6|6539p\a%oY)Y/`WF~)Mem).:Gg[թK:.š@?1,b@K8}A3Dxu)j-GؠLapqR>V!z:|o눰AUK 껟J_°_0(ِ̲xUFb}1\r8tI/*mPIUXcST;g_R;͛YРxS`qx<\![շ1N< F ] L+92\|9: >ב+E4q w"NȼFZ"iw*] M-&>КMXe9l:\sXk.$E[rJ"iۇ|P;}aS .jb"w2N_g31u`z z,`BBCtA KAd:OM&/ɾ'i2g31 ƣYy;N[a;-(szr|({[əT3?xgY_m' uck# {6'\>Y$Tx}k4j3 Gwmr8JZ:dbITúB$BTcsS$Ir7,KBRV^K~INE hSLwu]?P٣K00۽NWf=Dk& /xށQdQxwp8|z8u}Eh;ӂ8MdqLG,)x2;1̭_u6_+K΢(NW(Ivb/IbD̫xdM`FB%q򽔏? ގz~\.錙vi_؏gx1ü@שTR܋Fxrf\JAǥQxGy*jsdΟAD7Ql#Gc :uS]Ⱥ n@ums)t61X؃YOϘ0lbkۖfkR,kځv;U19B ^]Ypút[ݴ޼ 'EU؉R';^͏y4/ $<~I.j2xtb@[vtiu0`ֳޏ0I`+Aґ|#fϘs&2e|-A7u1oߕ|iqzkw; /xh[սV=Q{9rqPcVesΗDyk(xmn0 Sh/֠Y"h2] q%CKA "?$Hg!ƒNn#>`|G! 57̍h F`C}0]ABS.+}j֎K8wMiFiN͸3m_+s*Л?> ϲ-ik{&3q&%)@ rc϶?i2>2zD5:!ׯ5y/7áKɃI+TrU UWDz#_KSvZOlV8;;Arv a2IV\}]xRyv+֚Dn^~+xmN0E+D@ J !B'l˞7іι* W!Z3ED(Zr}3!cC\`[~ӑ0c<,&>,}3NJ8;OQJR痐1tJl nZ$'Ved_BG{9:L"@ıouNԌzkPJ|+%aG!Y)ŋ@ g׃deC zi7wjg06[Ӫ1W ^\Rb^wbW:z\Rƌטv!]GM|tm##rƶ(_t@xVMo6=[bd4@mQ@v}ȉe:b#*ImߡȒlmb7C͛y3>,Dʥ{X2˵``U=:@4["AV `TSdu0!,}m\na/HY$aV!1xs'D>=fnDT<+;hLҽJտZ=+h;4fwvWZC<٤JʓߖL剮 ktlx|:i=]cW.4U|E4&Dw $faUR.Ŗ.%rgw֐}$]sŮ'b&>t%-q]U:ff"h^8n P[D?h6hlċBIoKA'I!}9?=^-6®=ޖ/K hYnB h| eq&YI \M;7}zMF!]E/ g =D=Ic~ ~ZA۝"?>MZ`k\ώ~-(vy61& ^zVaxm67OWOԠɼ0f)yFxLL 4096 /* 4%40?) byte -> '\nt76 65 #endif IԿAxSM0=7b6J[$R-P/m{=;ҢL_+eޛg$"R %Gx l vhT148S[Od7;ůN :Yu{XhjWFfS"o1m5w GQ(jB8U9ʻx 2c)v bokfU=PYZʴ q7R7CQBX<;/RB>_Qg.zN}౟;nZyhk LYr-]{գM:/{=W!LI򜵿w)mnߥp7ExlfΩ?<,\RX<[!t$„MIXiOSxBRݢ@W =mEB@JwxCiwF 4vqk_e+5 .t?[w\wx1}2d?FͻS,1xmn0S,[u7#GqckX P"0""k},u7P\'G$tZv>6 Rrv`i\PP؆!$뗿%ҏ 3H zϝ6X9|˯(lWy֕W"zj à,vP[f@-TڃJ fek;AB=2NS? đoŽ  ]g ֝g Kv̰E!ΡlMZ`> G8ڡSL!cAι$j~Nԓj: Ec q*1L gqIRENmi=ѿyϸ}zj٥QH_vzZW#mVfMڿ3cR:(oaٰpFFLxu2&E׈xWg xO?ܒĤle x6eYʂԔ4⒢LrpV^jE5WT Cs~^ PLK5gsp_kDHBIr1T5'\(d yp'3y1=G&EOqx[[o~8FrbEdYH`J ZIl(բ3{!~ffgggf/9ty\:0 1%kg$ :y$NqwSC|Oi03wN#P^.ce2x=z?vSPKZ`x޴ ܇یTC]viF^BedR\=;s2ѳ7W,׷Hs&S<+4-O?݀:"7 \i hՆtg[ /Iv.~DZ˘}[^E-4;⯁S2 ˝( ~䙗ErZ thMFx۪`9;j }0'>5l iCf-Pڕ޲LNDWP|Wl6$k&q- &wIz,]>!EzNHwRZC7~2sdx6_W5O:5S wGCo8'pyxz{( Ev#:ܜͿ`%lG#w9Y8 rxM</(&PDhy䇱@I6Os]).ȅ+9W*2 vҭF`0c 8`,EJ5M0C{WGdMZZYZnsOG{^V<{%(rmGQ9Ԃw``S /0ESyC]R,S(͍\ԒL\V/L C0?>~D?\+8g@adf`%+&>62-P P$: x7W44Iͳ0VJ~~zvchd.Sǖ`uLb#FS%ѡ0}?VP?NPc[ PA4`3Vc `,M#qK@,¸ 8 XĚzm P$߇[0%u=w )ΔIKQt9ְvWogz^dP CFCDïg*7DmF]ᚠ0jۆ]1&y:N-hSqV'Raѱ1$h7b J; ֿǭ@V"װRm'C+4rag$9'g%yI !l 0isQ |Ky147p7z&־,.CQ^eB/Tp' E/Q-Pvz}ќKi#;>y!: Qؖi3J͎Ġ<.6Ua(Ey|qq\LwrmJԧ>c4=IDB%ke2B1ymJTyxWƌWxtW80d \lnbLr}8D !³QKt8xW 1b'۱곿ɨktۇ-y'Uk$'p< W3vdYdMyVQii'kA[hoS%vqsϣeLJ9jCUqߕ/jpVpLȆDphZJ {pݏFB=H1J U/[t3_)SfK6f.*9ߍev5Q%K0RWu+˥mMkʾQ#!H$+ߐ ʂ>Op1իEeҶڨC#< 3Y&u6fD-+vY2'>a5ϷKG]eId]AI֢e탭s@U*_ U{}]=~JO=h-ԿRR"K<۫,pOǿ7?~]Q >"`~kϚ :8n`pg @=,BE3}8rmhAKӔ),D0,>oWЁo64L݂z]P:;s,ߕ4AQ-66h㖜V ϫG!Ɲ|cnSWR/:>r32)vL&\}R?P)f% *fhB!%\5  M1ĔL& 㪹!nV99fMf7rC=ohY"Ю%<Ȭs%':He1|$P4gnR2- è </R4]9qs jj磽D/nwɁaKbfz6y!};zͶl/p^=E˅_@CK{ݗֶ0ÉSnExu?KPũHS[Xo[UK".@Q1yiMB ~; lE\\vqq|tJ{OR'I?FF1SיsMZ6pzk˹_0l tY JJ|rDjqg_a6eP=Nk9pW|sb`W4P  Ȃ䆘&" N t<BXdžGBk5C`<y3[M6ZSo)ME3X9Ӛ' ýFKbuY)~6T?R["-gQ; 2 Jx\h56FrװKMeWlwG 8"C\tB|' ZOޠ̽YNJ}rd>E>RrSJsJ'O|ZI $*֘lcR_ўi!m l]ʩy)i\0Fex\W!And9Ϳ~JF~x*GtEYXvx*Yd/9'rMJTI @x*Wx/9'r\)69fZ." -hx*]hC[&0lydr!.k8 1,x'6ڳu TPMtܓo MZ5x/Vporp)dq[Ux/xJ`:foPOc##B=B\#B ?)+>'?? 9?$D#98,u;'?dK# nx;%C"Rf?ͬ شY7x;%U`™~3d&疖Vė('go6gxVrdW%'M6c٘C ~x{Uh5ɓ'M6c٘ %x{Vp5"'*^JAx{Vp5&sn' q Nx+=AisB|!n> i9ścYYDԢԐʂ9Eԝ<ü]# 2KRS+8LyY̾AqʬX'(rL>ȿ&ʩy)i\23x;;c*LLN> ũAkXYxaŎ%r6x#c9͢"K' L6n $x7cCdukN Bxۛ?u܍Nb4Yp?QͽZʩy)i\p46Qxۛ#y܍2m>\49YtsLsm`NO-ONMLAG<=6 0O#$88#9RG! eFIxY+`AYhPBh 8i1 #@Ĉ%YP%+y J"#ٽzÑ(2Ŕ1l7@/h?ߤƭD8+?pG$O l}a;̝tmڿkLc<qЊ/G-#7vνfފ: ]%l{cMuI=ܳ\)(_rҟb<PUPArjd/OUB,ҘOjKl* ІXJ̵-m7"!/&mZGbRYZxz0E"'C86ZXʐ܊#KbKR4PD,cΓ,aOTFĴlaY,֧z9e;҉(F Tze;Y[Y7+Jz0֔ h?_—@wH~0 B]UJi'h!;T󈻮 xXQd~MȻC:At3K|³Y.0l}UQ)#TxQ ?u,;]E.&:{ -JyѯPH-/ٮgvR_HӅWC SJx["*Au"UL']6OkD%xk/A=> 3~Uvxg׈y*aғ3d#\xk(=OHpp_kD<vC xk+Au>I/x#:   l1x)+gsAFLGx)#a9̭m~cq!x둾!,O, ܉\\ʩy)i\tJ(l#x!5CjW[# 9x!uNj*d],8DC=}<#'䐚U^(x }?C2".bgiJ(ڗm6jB1WO/RP+V9[oיFI4CdIEf}vql W?/d޵dwd'8Sܿvf[VP}sŘ[oVߵ4\ҢQ0N[FpMgxb9R^> )adרZ& -[{ȱӊ f&y4aU#?z:~9Ϊg쌣sGiFaqqkaCc+C'ω(Zwe n睭8 G;c%qlNt=֗Nqz|-5{|~)pZ_]D~4l>mw! >?IlOxkiP²!xk95aHG} Lʓ%xtB|=\|\AeS33RrR1O^,#bliH1`|Nfq hH=''%Ey %E% #38$3DCL̼ 5ML=~~pHIY ;Y&gEYGddEV}DMN7G`W.L]\}\ DrP[,!xk95aHG} Lʓ%xtB|=\|\AeS33RrR1O^,#bliH1`|Nfq hH=''%Ey %E% #38$3DC$YS:I@M KM.q},ϳHL~͢ 6AGddEV}DMN7G`W.LS]\}\ DrP[`sx;5kBF.LVb޼vy hxQo0ǟST"QTݤ=)!la# DڤIqK1Mhw9T0H?{:a OXX k4WpRL# LRLyQLgDdi<4[w(4JTsQS |7fLmgE2 Y~W;YWpwjvQD;?X۞AiY%(?#{e[;b@4g3ۊod5,tx~{vR(BZI%IƜ8fuE o'D1+7޷*]e'C ø<{dL, G| j00 UԅѾc`$Пki}8O;4ې܆v֌~gY+TB'oPucgdY#Kxs1zpd([ь MrFC)$u~V}5߀WI,WūACO 8:خ^Vx@gq?Fx]3a7că` sbQdX0̨72zɍⓕT '2LNfc<<;a䀚Q 2a}{Ah]PZ"#'L4D~ߦ#\NƾJG=_ﯽQG3!,]%^nBw뇷f,\%q$b,XNM&Δx1dҹ}4@!hOhüL9X_YmI 9-Kc>7 v#IPq <v A$+,7=hrzP=.ٽx`MU\g< Y e*#w718 mQ~r+]DP̪zxs ݗrPT%ۑPIVk`I0C)^UC:ZpTE սS^XiFнb^фTSOqL]aiV+ŬxsG5ݶDup#t8 aS7M^XE{#"E5rQ@===עHBuPP(FF v#ml=_/}ix[/TpBFNgTJK.,(IMqI,I,S psWK74Fsek <| ;/&RY,3'33yg(@5)@wħjŵ@|MLɌMX'M~"!讣cMb5N.ON,{988"T(@0ـEY=%3=RѺKY'+M~Ĥ4YpL %5'L>.ʫWoqzx[/@pBFNgTJK.,(IMqI,I,S psWK74Fsek <| ;/&RY,3'33yg(@5)@wħjŵ@|MLɌMX'M~"!讣cMb5N.ON,{988"T(@0ـEY=%3=RѺKY'+M~Ĥ4YpLVEyՐ]= m6mx[/^`BF󉋮k%U$$ZO8G,?3E)@T iٛ)q f^5̓!+|6L$`x[/x#f̓86/ebH2x[/x#dPOc~3M.a7,OKM.IM psvq qQqw qpsqUҴ!y)lbx?CL Mxx?C ?1a:+UxSo0~JAiSu^[h2"mO0Ml3PJ&qbO\\xJ2IN YI}C#@bf% %j2H\Ai8|Q$iK(梤x%S ӝyBn5~o5&}2c9,f,}d 8&&IƉmO\PZ֩%p";vDlڄCŦ}Mpj:M%qeSecWes&i 57e/x\鶫9]G;.2 $m^A^,s1vdL.p;ZE=W3س!U=0MH*p'~ofu{;+iQ!rm0M-n ~=#fNg($Y륅Q?G!\3fxɵ󦇏cKC[d QRj11lUVqNtF+{m(aT_l2/Dp^2y31xukBF~HǗdg$għjg(h$$N~$ #+X̭9ũj`9%: j&Lb9 z^&+\x;ǵk, ͙&e1Wg xuk,Fͳ383Y.I x͓FWJ5nm9xB$# ڭSBd,h'=?fыyݭ{* }"'Ez>,w"o/Np IOEBpDiO|L7^ʿD+= ѻǻ$\%<Ƒ> #_Lv_ׯ}U.@,?|iLc~Fhֈ'U ޗ 8C6\xUIs!=93)3'Ag[r'?b#/Bv+ss~[]8P33wl%9ێɞ9ԯꜸeLU &Z6FJRU N =Wl>|29T -bA:wŋx&^pz w1u*бلsݞlĀ kd>.;hm6sM?*_e1AǾܞ閄]M6B9ln9N8=wts̝Jpį Wաǥh/4\3ZFX\CsC9z"ًgxQ\i'J>v\@i$a)kLd=zԬٶE3 aZ0:3Ƃh01ܹq/:4{31U &b\Pq/d%WBroY8¤Gެ<$[vI+DMi͓Zu a]LfUSۃ N"*FS H^ZSiy\5[U%H=>Id ;QZt)ܨ ]i쑿}JY S*S~nNJ]#+[h>YJ▖T3>dJ^ZRi5".VХ|P5dV~yu P̵Zq <IQ%7gDq95Y(xFr.-)aUH%F"K=?۟ xYkt<08W:!Tb G55$u1zɍ( l\x;sJgE( xWnF}bl(L *Bȕ)%vWբYRDKbq8̜ [\1r9M, &E_)#\fIBRE4!odTƫo=J 9gzNS)&,1*cLb*ifrH@^b6bd WZ\chL$|2|$TӐSo[Vz-l.2u_2JFGk>A!pW(RPV36B'Pm^گ U2\{di0N'is:2](\m}O G?ӱ$}9e:Q\(+c,4+|UO.E4WW= w7(,Ev3e*^:]B86J |r.MkʛE|BD:#^W)SjpP{aK\>]-C+\&/VV:6wԎ[oeyK2FL*brTTBd63 D]}NbD][#^ 3gnD`2|ԯj5;<(fPOc#_2G1oox;s{$osc|sP|sBqjNjr5'L.'UA C49? 8$#8c\Eݙ2nf GxYQo8~;pԻ=((jbkq8DKȢ Jq7CɶJ!3?3CfbH.=KHKHElKĊn@UT䒥4b"Ez8*Д;si2D6AY S4"%0'Ldzu%ga8|WVĵn.,sw;]S 8EOadLHrmCBbЈ%Sv. uE! t‘ Nh A5h8{%FNPc !!o-`^P~dtb+ tUc%u׿Ԉ}>M,4IWr',nR $ XRǜ@20ɐ'/p/y8FQWi55]84&[ׅ(Aq9Z#T-BI~9 VMVhnFE2[腺%/3EV4geÒ"L?eJ)_ (J]`_@]HTͩL\*!W;{ ,s3Вe5+lsB XПB UZ)YE4D"|OeYHVŝLծu.3l2/ {0R0 #ϱ`X*1:}T\&2߄ ɆG".XW]Jun)=(U~&̓.,G.{Mx3v}'Skۯn} %UJ+h~*`nGUGX־S8uFG1ZX\ efWp4UnjO@WJ452o;4qʆ(5Ӽ/-UiFq )$䮡j*;vU$\7viIN?_hlyA B'e-b0}#VbY}x4S Ȉ.YT<ӊy KU|Jn$l8d`͛&bɚf'l( `4x[fbCd Uk5k9x;nRkBF1mcǺ͟l5SR2Ӹ>*4xV*%`S%/ -.get_tcs_context(TSS_HPOLICY, TCS_CONTEXT_HANDL\ GD7"dxNuCXͷe;xXMo6=[ n=J[iAKF-wr$Jr%jqH:Zh<XMH/h.xB#F촩N w(dCF 'Ml!*4dp;śVQ/҂6{6@>a ;{At]{f0;j9)3/ymfkV͢3oXr>\n;Nѱu]E|Ury tJvBn<}NxLc.i"(F[QZNބ?ɹ?so8^Razc>n8_32?kmma5U戇$-d8 KGɁTvo1uHVY]ӫU.Yl$.$Zs;!8磬ve6 ÐmI (Hׯd4Tt1+*]T}mrMQu.%RS˄ l% rTm<ƃS 94< h~q`b8LƽN4](f&3XPdC-Rs)ʭe/9?xhz=托TŕPlbig1ALESzB[a3|a9M`ՠA-Ù`%yМ!rV dl 8".W,:ai$髾yKǨ kU8j FK Hxa?cL&7 /)a!x٢a?{||IqAfL0d1Լ FxyBsjɾ"2 12?}KxA)(> atcreation atreleas "  (>Ox;N}Oq}J̴dŒZrnN{ x;1_mΛ0.d4dEhqbz*{0H-'1&ՙXZX=17X!1'=($#7>(l qF AyiU`mN! ZPA9!@: T((MND2!5/U7P8ЀtHppGsŌ혔s2K⋊sS5A TК|_tr-ӫ9'Inf.a÷92=x%QLQ@FL. yWkxzIu|*XJX'qLb) xڪ!_`͏~1>.9GxKuBF󍋪ĊS+ӊRS53SRK72OSH/NP*,.QPC0Uv{KxۥzMi#{HppkLKD}jxۥSu#Ho|kPBYj,F Ē̤Ғx My-KxkU!orv|y@gv0 l+xQe1&!HAxUeRfq|r~^^jrIjFHppkBsp_kDJX&[?ܜ -GxҭA/915R$ {L; cxV_8OaRE;Drdlg{}IHBmg{컱(d$т(*)%bk*4T Th[!@TH(JGB}'D웡8y yQ("hRs)ӧ_?oƝmcEh;N~;Xɚ}7FR]vAX[_ѿ& ~0𾠚,OvСs1\?buM"8YqNC-0p1ZsJf:%b][QXsȴ[>0Zt'aq*kגVȱ-NsLy@2b7. : ^ڨ9h,6ad|r{FcpJ ԏ~~MɝFW*:@~&q`*Ej:aV w^O&]R)C{2W9`99ʹt K?YHmW F?0UqbG^2z:MW\v 7BzL9Ϥ''`3Yڟ'i4Q&5i9yFXgqa:Z 4.NgXƐNsv Hu.Nm&TYCqn|O'q~P\f]@*薿RS=++ٸaNzM[5o؈qxWz$)^|2r-]2W)j㯖m2HRƬbyߡGp؇%C&k i}h &t;*LN%CF㝕\>}7x@edwyNox;+^x'TF+kYK 2'r @x;+Jx'TF+U83W2x;+TxBF&ldMcNRNKL 9*x[*|A`;,̓pHn!S!x +Aq=dVX71IVPBx  fLYXuSKKJR+J4B=B|uBB\#B=\|\'d0Y{BCU*:@4H*ɲ ^eٵuTU"Z +wP-;:=+ h(a-\?¹eS 2Ba^ci:U1ReTHdj)u qwAN )`ȇO p% H8OVP/A!qo9짠4,xuJ@S lxZh@x𴬛I4Mgg"E?0Npg @Zn^Xk. x&a a`kyLX6NjƸܺTXtRi)Of>g0F_?|W F)H¯,δ"aմJ) pu!T>)R$zs\,txٕxuVUEB| \$a0"W<@{ xkbndpF$(51X/C4D 7(0>7745"1U445>'?9[scr,xRn0<_H.Įⓥ, Hz!Xڤ ȿgJK/5;;Yf22^IA9vvP.vPwKl%2 xP@[hl~s \Z>@eȣFy΢O7d֫i, ԝ F+#aFTpg!4$׏㊞;7Y-ч̠*@T0κ h1lI|pQ@3Ɇ_h ڐZs:qX|< 9ɘxD}wP &݉5BJ//p7f4tݗ0-R򖦑GL䁧 -!W/&ِYT*\}~aM\|XoPF<oM*x;u&-Դ̼T`xO?P`(WNK3..Լ4.eohx;zuCsf^0",ExZo8 bv/}'EVR]#6a(ʉﯿȲLT>toሃtF4&,'K4Ƃpf<? 901At%^1'(8V$7'فF MN}SF$/@ 8:\[37 ɿo~R 8)³8q./_5sGܫ* hQ*z8nrXߖp n? "9`g`@-Q8g9ʋ,K9N+>e4SJI #1nFbAF:-K_k!#2T98RF"S:عG?INwf@H3B*+#p2dedh͝p:0ӝ (ׯI:!`,잲Oos7eclݑ.uCSuZ#LMk1 = z~Rfɧ;y&8kh)=- k ԛPȮh P7z Td\< : IGٔfe%礄{W]՝SR 6rcݍ  ;2Rs["$R@3kP .;W{IQ`MN%Fgg"|JMxg;K423RZ1? L9M2k13kf}sy?(eU=uNrD=3L;x(k* Y+g&9gP8<,/8ǹSzÍ隗:)CY er̽y(1;PОh1e0 e)xl=ocˊRk>(Py*۱V%$/5(HR.1TFZɳJs4,O@; ún彁2AWvIw34&3}QO/!@?^mcrF'i!tUNb^~%DU!1 yۖ'kx$ܦ]XjCU6pC A[ʹ^. na}i $M#փKBM17Pkcy)yay~F4ǐOHiC뿅Y yip%N}.Soj[2iUE1%Vxz?.'7͢$o׫0=N̏ Exԝa50%&+q m˔29,h.1 N>ơ:YUvcǛsN"*R wx3qjaJ“ LVڼ)er0 XІ]bSɿ9'?|Cu7hETxO1<&%&a\/ξYC\ (x )ɥRO)-GgҊ O#-39[b3L(p3x.id5%6k&x[Ԛ!}S͏7Kqha$W!xkMܜad>7&'IlvPwx^l$xۜf9Q&xk9AFps237bo!x;u>rCdV>LR:phx<YV3"adPubekq4t  4 `}R&YdlJx;-`fuQ#GB`x;?a!E“mv1cڼJw( ; +xk_Ak23t.U%&rOS,7 4.x[{gb_'?a<fV tl$x;s{J&dC:x;km͎_D6W ORlx{c4'3)l4x{uC󊓙*VJx{m;Q &?U7Nj|^q23 ,xud x<"pGxjCԴ̼TɎ“]ub8994D 19;DA |rq TA|FJfOJLg [:gf IZ,TbSy<ٱdan@⌸vlY|- %C12T?XZr^@uL0^(8~R9q20ϵ>+SX̵p-a0e-Ns$B:Z4;tVqtn7rwAj0Ay X6UE5 [t9L|@qׯAXNVV<2OQ( g-Pen HCߡB`m0i[,%Cgң@vzr0i & ,m&gޣ#p9@`,N1L }QaJY *Gkk&S /X䂻*H$5atOr3 ~Si& H ʹ*&f"^sUYQKt?EAJ!ӿÚIԩ :_玖$-٘5,ZBhJ͔:g2aFAzj'9O>vL,K$e=Vs=/+yZ(u\nGd.!Cl,ɚQErTxp5]/Qsh אȮp)cUWjPDo Jn` %ò9UHvXDsyJfQ,Ii19yhY4]c 3;Q5dTc3:DP[$@:,R,l.z݋V pJjd3 Y~!ǤJH$(CްO&e(c ` EV,n-JX4FvAHMSP2H 4J1ZF~&md $@^I d`wp*wў+s.稢LI>#3Riek rNDv~EB,tM\ze!6dkp ~if3g5?:(+q)5 >(u5 ֲ~X(8Ό;qŭmLWCZ4pG*,Z"4S$u%eޡrd\a%"ia={Bsݰ=<EjrjJ\'ړÛ>07I.+ژ'#y,c9q'jyk&ӯÅ93ʸU0ZO`9ףå+h }"z8MPVb)'4s0j(aQeT k̉ H=O;͊e4>)>H7%wNNkvAsE;'a*85 (6d0[5b U4cSOQ, [cg#fg1l9Yo?ָ)#HϜ}i3_HKbĖ6҇F(k2G; NT҉s(ԯCr ÄcHWȤZM:&CMC~{K_F4QY2[R@nu2J-'#d^sGNb~u8SW'R $goe uȹ$:S*X0Y䏱))^YZ QACtM\JN~E0vp1c5q${JTL45uRĀ\ =.ƝR1՗ 9K>-`nx>,O5hܻ"N%n}F,K; tusVJq u/[7+ɝkr jluXMz;7|r \!&Y\3cn\ MuMVQkaJPCP AZ+wƒ+Aܤlר%:^/hэy,ZxR7HwN!,="Qy|\lULJ|Q=GeP27ݙ ,y3/sRؚAZ[]@2xjd%ɍtP:'[X s>%8Qr](%]9&pO^**)\BimNs(,#͑.YK!˙BSWm9dm!Br!BJʉn^(7GcHjm̏b _Sڊ<.B$F|CxŸq'4&Լ̒943JSK $r^>7x۸qN iL\%ũy)% E61iGz `x۸qN y=\u"C\'jxM~a.h=Uhs 1v6x[qN LƓ&5l5ݘwq& *x[qN V|:!~Ύ!ʊnNkq\d5Y!(fs]BHo32y#ϘUxv 1! 6r0M 9=ܔ |xmViPSWHH@H!,JX#la$V0EێKkkquNN3Ctti]3tvS/ t}s9$1\;?ӑ&lXű5w86/~}mˁb 2pq#L A0$$9_:|#Ktv,:Ʒ2 dyjeײae|}a.!lck"uRLr|=cw0> R0V^Iwi fLА&.bY*i>KX'}gPp:QWͮ&ZhRZPC$:~T.lB'=$oIO*W{\;J{8ɳc<8f30)KDI5: 00U;tkR;|vH'ڟBDʼ'u*HݏX,4xK3@-׶ʤ4mFp͠:+ S::/4?B8˄t6Ƅ[\aHߍ`夁b:.afh@bt2pظx#`_HUl1AEt/e hġzBOzP%vȢl,F$>~$*"#pYI=帙\]tD \ goh~s邟(\ <["{Ip*Osy>AsX4]ǖ@YFEX)1?kS͐\`N  ̢Ez؛eSTrŢkTDPZ|Ʀ!VN#[ᘖG`fS.gXKGY]ŧQLzTJ'|tk 8 *sAV/)Q1ZXrGq,p,l.CQ9,?2kDU' 䠂4(FCj7s#Uky?R pP[Kχ`ZT5Q'ݪ*U4nT6j9q@-0p,H W%\+Mt{YVǡ|Cw0\5vi㪛@A]'LXg웕KP3À^ Q4EaArjT=/FaqF8,bZXe,fԒ`x)rp {cBPl;޴ao[~8j^.4{i&*9m󀇞gkdg7_Gp}f&-k\m篴m'3m!ziC w Ȁ#^gA:qHSzH/ë]xJMI$[?u`amtv52Wj]n涍K;%WChH0cŶ~w7J&_ Uɰ =gC"x,@'T[9F62\P1J:xF 2J\M'"c|.+hxP÷NqP_% MakeIdentity2 c(, 2!(P8,G~_xqV o&/"2Me}xV ' O 0,`/ya/.] s&xqj ;CRR2ӸDAx-+0z*@( @5endif c;x۽qj U&sO> +=d I`^356P=q%,4x۾qj 6oTb':9_[xrfw IjBhʨl结Q@Wn:x[qJ "/JRx[qr o& nf ibx>4n6%6-R*P=6P7*77p'(8EMxq >ly)i\7Xhx4 &G lH[j^Jf B*x;0qT 6_f#9_ QxU]LSgΡ-#-TӟBi2QLL,ڢPp Dqqn7Õ0i!aTgbh7qC҂g}s_m5[Hox-x.|yG5'/v1 Q1.b2 x=ks8_|}<<3٪^ms׈'*M")ީ @%9|HDF;k(Q62^jfIAIu1H,)JH=pHKm#14;Ͼz .D3K<2͊0˂8BbJS__ey9w~>Z{͵gp^+ܑ{G~]"MJL߮^-B kiqhx9$SHl A>,^5Z>v?>L-SwE}lLxi7ckR,=N; &O?W.࿵_~ޓ6qg0l4&p[gqf_Z#ӵ&ǝ,Dvs̷{O٤^M[Sb7x6y, r|?x3}[)کX.V`@̘Nx8gZMXܴ#GOض.mz%r=ɋ[C`S &gZegZQwZe[8 wTfl:3:d)z;C kѝZ,=iTɡ /cCʴLshƮp)J<{9/ӹ;Ku u:h%D#'Ax.z]:&Z[L'2$,[EXL;v/]{PN mŬ)tG4al/bů]V '/#ˆ Nn>2rYALǣËQǪ :/|v^w2D~5=GWӹ\]ҲԺrjĿ),% ʽ.КVqC 2/Wg=En1Ma K\+Q]?I\B qt.,wqm:̭ɕ;2'Wu|tLݫU&^f Z_qc~ok)H~NOU"m6A_GW T6COCiAX!U/^:J%ZGG:9rZkKnTw$ 8>@*Ε8qJyNImDM|=!3?Ruٵ5{>2")tPfx`^+~.qHÙmQ wW策LEYerfI0и,=Ӽ4ݮmG>c㠭04/uL*iqW[#:|aK@sMǸeޛwKn'^_OثUfo$~qs0s!+0o݉>b d~~_ZX|D%A%Oj3q3WLkMkDp+yx9 VYcJ>a"9D+u?-I='/'υ A sc9#P"g"_O{:G6h;LGjAǺᶷQJ_B$x5% ɩ&?zx/Tm~S64ѹNO1Z;v<)Ĵlj*xVB65GD9(Y60ڵda Jн;z3/}MPiF\Z27RCPk_X/(H:Lg60!yOh"l*:Z-Eg {8Y[m@+l%:*걉Ҵv'ُ5P/*Q*urJu n\!GP荭m\cS2W9u$\&V.}p<lf~2Gt5_DaU§&Ϣni*ag֞1~VU1O2ҏKCO!|UTyŨgVCCIGm4gݒUW6xrJi?/|>Tv$zQ>:.J^)I"GmPo6H;!N!:)Ui3ZI(ʰ?0g xrCĩA.1C˟t7U9ot9z}.T҃0⑪\6 SFZΒ=O6'} K!R)\Swe 1,x!IB}'ךx:47B]gO۵+ݏd8 %vvPޑ.h(zI ~J81Qg]m WhUII#=i%8!F l|D~F%+@䕜*[% HDgq$}Z"?{ۭ(D^*R XD mBr@*an6K/)mk-.ȡLywa*$SDdLE3Kdh3ޮlIk`go3$#=91624l0Ol6ZT:*eي5Ln!`DOzA&V6Q^Kv-~ߋxO+8x N*&^[Lkb(8y LD "/Է kV ڦ G j<){kɇ]_X\jJk"jk3g2k!\i&TH4^'Y~{Z~ ʮb[puz!!$qXU?n'u"ospQzhPZ*hڙ2]h@~wp<$޲ͧL=9ZIyM(xy7&#zwEŻ N̜䆜#e\:I)<7 $ 5.rRlnWɷ'I̶@Esd^ksTB7R9@!YWмؐ[nȥyOCnp2R/itنh!b Rl ui"4Sy,%:6s=2*JvtwY<>1˫JVmk$Ѫ2Y!w^aP͚8=4 8upbnt~@a')Ib~۷ey犯&pv~_pFC")NNGyhrN>ȨЍ tb:gXyZiK,RP!%)FPÜ;%$erLN),7oHv@|wN5xg8ߗBaC R ;wZ3/ 1p+20z_ld|A:ki'3/o0k$pk$ƩmF{ f=,iOB\+3>prm裥_s2cZ j)8 Id Z/$Td:&ϣSzkGCH:gd 9En}TÚeۦ>P[p vH xKȞ` I.,zWBpW֔=[KGz9#T(fࢾk(4S^Pck?d7jND_dh~fyJuugyIr8dB́n0q|~L^Qg pw1e7D"P"T9cb&=QMB4ѥ ;/`Z%2g'NH<CFv`oI@h: y!JUkڽ_V c>ӹ؍qrZJͱ kf$X+B]*i}rk$S t .fz&E<XE8Y{!y 8s}bϦsLVrK9{x8x`I% free_resourPY A }SGx[6< 7K 27`frҊRSRK&+HNYsLp2\x[6i< Y&w\ʷ5 l .x9\ &c|s}\ʩy)i\d +x{2i, 87K,Ҟ}^)FB n(x4L 85/mnAx4iL 786r>l2nnZx4i 84- sx4 2~A~!\)iy .01.POc#мԐ|ǢJ W-P?Og S $,C %(3/bErFbH#MZ̓ Y'gKY,㛘t_bn\̼~A~!~ޮ\)iy H\\1l>,ǾY۹COMnsx5T a_6 x'ږޕO2;Y2M1p m#B2x#Vo4D Bx5n/ Y&GNk1YwrFʛ_gtw qpsqoEu0M,&$Lv39!Ifu"`LvHZc|#Y+%eԛ InޖAx4iW*S=UJ\,x4iS=cXV=xtip]lk~7t `t|^bsl +8x;ib3.@q.*1x{-Ţd'_P-g#WA*)L@ES,s';ذO:cq&ɉ|"_N,篃T=9Ot"0V V(0ym$J0?Hj ԢĒ"Ғ ib@,'rMo:V f`x߇pNf &(<h@䳮@y]X8X>+k,0CYno##L`)QB`3U6G?V]/ )x[V'?eC:}2z`-۬`-V6c- rV[-ѓl WٰszNXfzLV`] ,0`5rdS5Z!A>! Z9ũy%% )g׈MͯCv*HX]xM_L[u(" R([ mW (mMG"朰%[ frb% g43NkbE >p#j|Pcb,%9=sn?E9sr9G"!,?=f^^ |6;2Yxz8Ď،p U!G2Y-OpqPZh#| B:@E[>@5s3<\<*iV[+!ʄ(,iZ\kjت;Oګ-'/' w>Ep,9f0a#E:^n ]ģ5÷/8&)XFh߷ń[BțgEHGceXbS 0rQ6(M&A6< ;l i88I"PJQ,ܟzVX1|/ㅵ i[]3 qN$c |42=E%,U(r|vt.62Xk9~c(žHśmZἽv%2<][E Jd-\zV_)GD0݆I>-b(P{qR;&#tJv!<4ߜv"]VbWn tr rI'ޅܣ_zzzIpݏsy^ac9qctBv?a+_i 5۫><7J~: d9?S7:dӔ=XktӯbЈM5tD{ԓjG@"ɵ5ηg7tkI.)7&Ei 'nJ=P3齚Czͬ(}" c~"m&|{<2?lB>e'Z3Ocb251~Dhae㹧e{rkީ{''bGp}랧R)YZ2'҈pS~ k^F"? D)z q6-3*S/졃^9TبShGK 6, 4#Ic/#`.BOn6ڂ<3"V<lvjskφTˣene+%$䋫t.̗ mpzBe>'E d eaRI"jLi (bYa"-Ј9^RǕ$GVanE'լт0UrK4MVALbXΤ Ae y &Rz"xkNE\*%=LR*rEj{.Ba#]DqyWg'A y\\a,Lœ-7 Pqv5es0a l悘CM#!TM\&I-"*dP9*M^FiDtap~~70aTNEėlBʊW /nzXJ&)sQک}.@6>! E~ ͇_1$)YA  # }w[B WX -i4գcpK Z}qx^#o> x)OS6G8`:naXt~őd)N` /ՙ![#FduVhkVkz[!~mZ);|n. \p4 0m dm 0Y {`Mp}\*pvAm{FG7|߱.=Lw-n5աFBqY ׺Zӕ}`i/iZ*Þ/]fQCĎ'L|0a prXEz^m 'JvإeuWO¢'o s=eSI9z&]ZXi2~t뀮VeP KU'֬\z D:o Ta1US(, ># 7́:ahPL:"~D<@e߱Jl2͛1õqS#)#"Q]e 6>GZYA5n cM&W+PeC~ܡư[柇u6({<N5Ҏ7:^ujÆs745qwoWx_YɊ]95/%3 1Q]qx_ux"FӍ46dWNKL@ &x;Upjf\x'7Ȱnmo!x{\`Crj^Jf<T:x{\`rj^Jf:Ux{\9uCdG.qļ\|461K2n^ R1Y+ $88>58'D9?//5ĽX$⪠09]t.YM&v|'^_K! 58G/YAKK93-%5MdS;2eCuħkh*pq+ThNנĔʂt*k4 V<#3'UA@K958('dqMk8웹J&(l½9DBpI0FzlOx^Зab(fx^ИaE?>gxڝɐK95/%3 9Fyx'~N>POC3xOcR)prq)dq =x:frj^Jf8lx[9ztec*8GxRkP'%9vnvfťImR]AxɫKd"cA/WHew=xRz^b0]~y}/۲;ZW{ 1S)*\Xr[Um6Tiik9g:jxreNT_zbYbReX䚠Ua:_NyG>mQiW)JFf8ګ[ݬZhIw)RCd>ȁk`v17Aedgs{tI{+:ѤmdCp `@jkd2+JxQ+Wpu 0x,y1jɱ޻<;S8I?5?Ԡf-pޡ:aIGnAHs w'+eXaPUxI{X fgD":.?ۉQxn\2Lq>q$" <[b S^Cz/AGK$GI "~=q3c"IV\۪̜G姇񷙱%UiѨ%)R]4~svgGS g׈POc#ok.N J+Ҵ+|U69G({rf).ogUBz`x[;nC#[L86rP|^߂K95/%3 9 x[2~C#[L٩Az Z\e) @ԒPO4JxoH $ a8kZsA>!03<sRS@dhzM6cQ* /,I wI,*>E*_=y 0T=ܩɉ߱K!R*gUA,H!a遢ԂT׼dĒ` W- 5( 7ײ~ffIH,\ǩ39Yh1c{߱M%dYT؟wr) h@rEHQqAf<ʂxWg'p(L^//1'<.~!!@y%$ UNKLXx(ncn US+JR%% ɉ9ٛ6J%'$'gƧ'e&L|F((mx[>z惂}E87oޤRkux[3afJ gx9vk=.Լ4.Ax,x_kPɪ:)2)B&%́uKGh&Ud!mN]0MGZH絈Sx! ;oO0Yvs7ޜ?{p~=$ﰎ3_U2!R2܅RbjpFSgn<'c ?Go7fXdOmG85,H`&mhfb8˺`P<#1n'CL5ڹu;d+-B+BgRZQ^P70w=*63߭7d^:RA,xs6. m}l8uqEٽ ]/}W3-(țǚo%.?}x>vwl\ 0d [A x[-j W9h($TgVj88{F*h(ؓۙe7s+g奤)t:;x:9r!V_PZZ\Zb4_U958ur(Sd+-Mk.Լ̴%4;xu2jC&f8O(C%x[?nrɶғwpʃ/8rH+g奤):;x:9N#$abl"C\t3S4SsSMٔSR26_ғaD%x[?3nrɶғwpʃ/8TٕSR2Ӹ̥ o?x[rj^Jf6Yx[rj^Jf:ux[+vdS6 &W92rNf2YYVt2v6c0{#4YX]YAAa!Y5.Լ4.EbTx5vq~ԐJ $x:v܍}S+R=S+sRS*R3KRRS&o,7y. j0GPWԒ"\܂̒T xg`WPOco8v0nVdڬ7Q,?3E(57,5$81(dZ\ZtQq|'i9պg`ִfs~A%Dq @u sKsKR^H, UdAQN0B2.=5/4PB\0YGXzr03Vå)PtxBvjeQjzgwjcNQjbJePjzfqIjQj ܲYD7T؆8889*h$:gj;{(zm~QȲYCW,?lxk9,f^o*&flxky(J(}x[-er.y-fQ0BL0h$>ZE6xmݠRY/Y9{xk=A SR2Ӹ;_xUMk0 s+[v)q-,%;(Ylad'GHl#EBzJ^њ!K& $h[N_1Y5P3\:=d:+)΅yꂴ=Ļu=NdoUeB^ Va+5;%anhU>WuM<7<Ş/:8O[)7|C3S8 uzmx{4a.ĹFRe) %E)y%9~!Fy5~+xAO0e n=iVj eIc+{Z߱l=~޳٠ϠQhjKBodm\ <꒔$,D:x~ Izz|E~?!w7`fd-`,UVQ7p>^cǦk5mG.Jn` NJ}獏붋\TR\&$%Ljr9n&x?K" ݫSgx/"qFug&PBN>\7P*7ClJ?BrO'O^ix~s{u1לM@x;5D, /вZ)*r"\xVKo0>_1j/٨tF6Q=YLc6w !!!7<5X09 (W4_SXwXJP3gT(8%RPp'%Gzkҟ|H2Vf]p_3Ʃb*yCM\ͯ|hY,!g{b]'jW$ă8 )\蕤~WEoL k5 7Yٝ5@b +1ژ Ŕ\#xܶ3<ܐD@q(})U: V_yo2猓S>(TF@vAq|fq|vje|QjzfqIjQjFsc|pk|@0-Mk$SKRJBC=]*AJfewb',. d\Y~fdg''&ggdhL~"΋bdog&o@洝HAiI%43er ٬l&qqMHyoDx,Il3Spfof 0^x,vNtM X6q2D"7|x,v^tn V)@sKKR+KR23Rs7d`leW(#xSx;/*a|f3YYRR2Ӹd5l"xk'a,)"e 8xky((#)%E602Ndv=y?73Lᔘ8y ,^X='W&e&sILVc: [dIɵ@n#X_Y\Z=YCY!-e<ִ暜ȡή54x{(fɻ7011McWæĮ ex{(fɻ70w0McWæĮ Q.x{C;GsckL0x3'ɎR9X/1Y:xVmo6L~őaU t$t*ZN[65 aBT3L e`R/!BGjfI BJ39a7SF%HmV.?=k TT42S '"w;s§"aS q3"q4$9秨,$RQ@R K0@˜HaFLZ\`|)N1i*T ^.Oyc=c/yr6Ęb1u R u # [* b4+PEd4 x[2UFQh2+\ZdcPM0j`m`N$?+~K W: )p FÂ6fh ɞabIͨ7;mr{Kգ& J`'_hٴ{tp6dyJt&+;ῳmV-^2ݵ +_>;DzH6D8g~Ub ۰QݍDQc{DL_˿A>,?ZPg#u-{^ܜU{\C5%td:)HFUjoJ@kI9^;S߿7GivNl9(Gx8/Aqv8B|iF.ywgIA+hV(cZ1g9a3pO$|j^=FeYMZR+>@Ix'mN+$=X~:Lj̄#˥Uuaj'_=?1Gqnj>" ~%vha "`\7nx[#Q|knԼ4..ox([lC 7rj^Jf32x(ElC\ٕSR2ӸQVx"6ItɗXcM\=܂]C895 4SR2RB}]# 01M] D[h TV#YI6Y.?-8aOc_H<N쪓s%'r*N^%fH_Ra~.AJT'5b.HDoG(/bc#6 ck-K~H;~$EI$EJ6vH3|q8A s`C\ <ۏK=Gރa$ F`8L#=0A`&([o0 xa``^lO2ڿo_%C?~k96tfZWV'aOp 1yO6]'Q$` Yg,Njaɺ\& ﬍>|_;'.Moo~ѯ^[NЗ?Vػ=&f" M=}oO(/`z c Hd~I^ >߻^ܯ]@g~P}Wlُc,T: E/(~=q= Axb&238+l}qrkN7.;xi9;;Hm'I#_[&~&L"A&\\cw/ ~AxE@b39P(Dzzӷ_@o>_g_`\LFw ԋ{khe˙c(B׻0ۉy7[5L,\Tw֗[GxIC ؾ%3g8,',ny@Kka dg7L\J-VRCtZ~Z'ݳT_ hW  /Akkʗ8X1G9a_~-x}07Rp_7?^|KWYB͢Q/ aL]00|cU%z$[<2#͇ra%K̠~(.(m$S }PHIX 9;'rF IƑ*t2)8JIk{6Ot0af=fk֣G4 ?ǸPA-1uE227ۉA.HWQ|)hjRS0M,BC=zD} }F~ =)ƮxL{b$U^1}ہtk}!?^2<)8 Cf?|TKF3w$2n]01+ Fp>̙ǎaYn.R!SX.Bg+]A"7]r݌@rX 5ܱ!ՠ扻-\{1 Э/ZtP@ {A!%fW:cV&s%# u dܤd0d_26jjULTLٝ71TC&s¹6C 'iT=v) [P0*Mw't5ǥ[ -0ʉ'v)(V2K NPC/:t{@'aT5cexO*5("r:hj&Ӊr#/BLt}=YNǺxZd6/5u!W{'0I5bnNkVet0i tev|$q bjDž PsT8|^Άc-FI:\rzI[E,\cgEs}H'J*^S#hZ̓M o{L[c9@t8s~Id.PeL:JԚ}2-ӋL*F~ 놐*}+T>3J4T3|мW jPP-K!y9w;1.q6061d|n-쒸2NWd_#΍sd\FpSkFJKJ h*Qȓd6(ۛe2 pP5ÀNVBy)a s#zk,U:UҪ ch9 'fPq ,TIw+Үcx7&e##J_dpG^,*&,s' $.6ĀbN/ 4 2ƗS7jf:2n4rgRQ@LZ{d^FzhJje` ,-BU T](;+ &A¸c)^AKsJ)Δ L&HTTiu_wa+:+`7@X kH3U OתZMida !(SDB bуrP&{+u J 2J$* &rՍEޮCۇ11}J/0'EtAK~Gbj ,؁ۏ(EZtL+qb!&m@j\<2>9xn(LB'%8/ Uؕ45Ĩ-2%Nm#A!ķ ^-'7x(EZ6+.H.ԸN=:ipr`+Ck2VXںhYx2nW~Gnzs1ߐIwr j^paq8w2H9,֭P594Խ",6B gHE L=VDރҒbJT,I&i\e^K^;vqT{\aj:Ws͡,-v*Cr^4C]Bc^5k]vXdpPؓoEyRҕ<Z 4Zd$SaKꘌx<R At[W"WbhFM¬[4  9iqyֻ.ce&R7xߕPgdiٜYqMɌ'(IVEPTTqt PgV0xQr4kR$htyHi)9_PY S+X Z6ZF<0BTYGC>lபCz4$/a@{KZ|%v wQQz,~>Kt̀yS]3t[,ۧSA^xܻmοk1)6B ݶ[$vc[ t/#?cU#GVG,ñWߵXX$4\ G.o'C!$J~ ]!3*v1{2*DpVv61bhq Lm눻 ̰5͐bo9nRiZUo$dT:g_}r*r_/L30(/%朹7:Jv 0Yvp%d0ZH{ as=lt%s\]+=ྲfj[F4K 1\x!D ,=L#FCÖ1,K9^wTb>TZs]g[,r:L $nnsi˾.o'@nF'VVr{ PZ8TL@> #3tj_F-9g 0~/R-8jcmf: YЦwo:.ۂůݾ:/=wudMCܕތiu6;v:5^U^ߨ_u%V{(0r6C@ArI- *utytTW1;p35 l'F+Ϝfu$*R}F2Ҩdb%SRvfvG?@16vM7 {>aϹ=W Fوc;N`Gk-~=v_UsսWN^W#c:KCfPˆIwګkGo>^IS#v:(HT=UשCusqq q5x~\߶ שCwzMN Q ܡ֩VMGjuuj[ݩjhh=>ZO>5o5,:b56:bS۫:uvujrujr%ϯթ_թ?-N8ؿl'S+N|Xu[%Zް9:RRQßQUQzP =Nh=u8ղl|ﱿԑJIݤg;[F=U7:V[# iC.kuz.}VK&uRC r1;>=4z;:tsj#᎝"M~MO߲7By[NgueakG$x;kl[yץ7z^ٲL1-y8혦(1_&)nWxc$e+]zmK_48{AT,Xqg$@7Yذa[}%e;?"~{i~_m;73ȕWlbPJ^\y_~q1[dbTT%ˢ$V˼O9&5]iNO6]LdCH ʄΤCɘo_dl)5As" \ؑ cN2yp0VE{T iaIV[-(A[=!2@AJ_5 Vcbj\;4{!\#Acfglb_a|o]|1'ˁ3]E(仏^b}>n=,-o%bĉ@l>bS'|bd\1W}`ʀ2¹vcxdqۆ(XU+ڪϕ Y5~6'| ZSQȕ2b(df) <&t\ftt)?l鬉7l%#woQ|&LfBKX:D2LUe& &Eeɶ/.`0J݅M7<6m'm{푦d(IkL*|Y)W2Ȝ ND\+Ru9)JZqds(!3݃ߝNe#8>9ˣ bf^5!lb |Φi66ߌ5naV]dh|ف=S.+̪N޵MΣ.k.C-*&ܲvGDӀ% K+hU!!WsE U\gk~״uDrꯋi,RH%(i#'׻Ue,eQw_[+aJ:HoÅ^/݋X>ܯЬZ?7nه4*~6[Z㓎`<6Y $aY흶lf9g{C\,F NF_/e_"UְRэn9-3%SF"qrIvboq!RY*rnSud pPsBYOm57+geFgFE=1!үZ+]_jVPk0XJI~3\\ۇtň9s-ŽJ|*ًB CAN( L 3ч$bՊP(YSsKd*a^r?䞂?ͪI\K,<`Z H{4!`a#;gqȿW͸ozs H~; 't @U<r)|zTqYp 58pmQS?8#M,b4F.8Flը lm䪺 :$0[Aff(бZ2'pf%tu !l&2-)e[RBgl_X!02F] vde6a Xhy8Z<$)u 6}, I:3/Y~8ԻGmҫ~/;N̻@ ;A~.jieThk-BMsu|C":x t`t/4Fi,5u6 v D#82fHHSH(#عIgGT^5: V81򫿶3ZƌN f'_kR mߟضN(\M;v7 YX؆<_`IQڀ2);CYe Ԧis㋱t(s[dѺ3h!~nC62:}x vQ=p&t>ܥ0_O\y P6&MP($>n]ƭMVTP] kfzuIrLN'S؈c=-wI'I Npey{㭓ÊRd7Sh OR Gid_nQRureNMsAIӂ ܰsV)erʼOh+·tUU5@me^,WBzYjASoN>FG|c3&^Ƽ>5f[ド9X(ba乮̶7̗Z?z@m&H?˻fCA; /c?&ݷ#(9-N'x`Wқ%~ l/b<8ێR<m:y 3GCS,KNBz`R#fvgơdOG"+%y<-D/d[J\;Ll䗛FTUspGx]_[:`52|~?u1&XKT"G!x;2  odې1%<#V\}M)n3rS ]YM d|"\1G\b}+@"̖D<Ӱ !0}2rl&LR-f+[i)W'M"+"Jc4@0_XedWnC>4޾5~ |kڷF7k' -svY >LO5{[0s>]h~xgv)\WpVHi7>;]mfHWrl갼2m0J'}J:"aͮܿ.u$ 1K.N5/?NLwvAr^szEX y~^{5>_;6 G]LF4Xy.E%nk \-A&9-xa00ښ]G׶~yDd}kfp 5KmS㕆*_N[1hcjQ?D%bZ!᜙9-CB#+*LJL MKp_V( I;8.%,uϖ\܉ [iZMV'+#( znToòtvTXQ8?-jAAYD͘D)aT'jFXG̹'tQ͞Qiz|Cdp'\Jnj!b7@ f]ln5[%}`kt-S{k( 6 &37uQ{m=ş>xeV%(-d/qO4.rU@~YrIZ]6 \yKϭ|#!.yIq I~>I_W 2ɗ \Tysps*_E*}j0XX =X1)sG⪵dh(SV4|FCc=9Ї~ ir8%hHJ:B[-#G8ɨKjfp-$n-\$,qH :iE% ̒2M^u"5)(E$4VUb\l#w%ٕ f_>9q{j Ӿ>HxkR6d-Is${)+Cч֨zCd+eѺ274s=K47$m&EҶmd-ez\R*qY^#l ߎm;m/fgY[կ:P; =- ^9g41p%:0>a|l)jzv]++xdg.rA]~ӝTE"M_u+!FQ3δA Vοn3(qe fj@h;Z[Rw r3`anpA >pQ y ]je'_enh(GX+1+xXVBw cTߤV34W{L&Mo< *ɇiGH7Ni(зe+I\_֨ynBLGI}Xsxa8z>< 2r >g}0k"Č(hͫ^ɶK1ug5}kmNŗ] yKގۥ+[p8"^Cp{k`RKin;Cn*"f7\ ^6 dgm' Nq٨L*-ϹTB.lИE۱h%WF 0XVyUn/y`鲡upg8ٶ9Tâ }$y/P@bkkm~y^U l Iny =m2G3VsٻmZj'h `q"=sZҞN6S%xd>`y3xZqbVZ&S_<0rlTVHGqC ϯyC]?[ v-rKZmtVJJYb]pP;&V活N?ʪ>JJ)=$:L/Kλo\QdѳMUBY:FqeT6:!<'#>O4E ;7,3u!+7x#]mFOM$MIJC_/Jx\@ⅶ6pi(.x!鱀w$B6=>*F3VEWB91>Ih 7?8;`7huXc؉^a=4ɻ-y޵9OC }mye >E*;5*Yqkk5."BWڝ @6)",V\Áia'TjkxH|*Eo"OeЬp@6SYks *00p2~< =[Cmx;ipyCׂR($eٖlA (%$;j , X \4F$MfĖ>7Gg,=fqb em' 1e_丵U, ?CSB3-~o/_KXzKJ @%sEA]n8ll 4wKEAℍ|woQ&R(Ni?HBBI,4ğ|ZSlBY؞Z C=8۔xk؜>{"?Owh2$#I\0:S,ba.EB1!^W|XI&&s (qfz#:EO%)j2NC)D|x^l~}[HӴMI-FZ|E*X\¯0T'g",0qUp2ɕ bȸh9h9"m+F ;l+Fp|:%f.f˽Κyć48u|3 6<%ql'ɾ&\VLUbu3%c]&|6ZTMmg[( ^#032K"n5qCP8<6ܣCBECg4@ӣ eg=)" [!퀟~a =qK$9 pÖ\V 5L1z/ňQ+WQEa+Wj*2 9G_=:'\Ɓ(W$X.pNl.D V*RӀ_.?svȍ: 0Nwj6_VpGkMߠ4oyV2L3z"яL؏GlZ ]j>Pܽk0XJ)a3\|Vߏ ?{,[$JU*26L"5X/嬩P20A/?'Ljzzw)Cf fpd윐Y) zGv1A()"mC59֧Ups9Q98k1,F~L@x43`z,c5V#.3@SAwW,(L7ClMQ$B'OjYK!H$WBXGBGE16lvtKBJC/V.@n7x;M- }wi o\h$X̴渚'[#@2b׆o#]Q͐#u={F/mļT{3dgF/QFF "4Ɔ1$'nG?&O\x1Jcs(`&Q;5;t_D}W߮F$i9]zw{vx4O#`cq#k;ul`f{~F!%0 Lіm"մsOX`(ϟӍ=mvT (2=؟!_@m6'P0K8E;Z&bgj y.|2JoC,3׀{, ngO=-ĕecbAeJdUA5Րf79X].L3~:<.Fo=LM-D.OnG3<X-圯oV$Ou+T 1瘲FKxj7*dh8/LLO&}r+sޛhgOy]{Ji%rl* >9Q\;UU Wz[  fdѣ(I <4daŠR\PRxbot O@[l}0ӮhkܕvhB7! >jL`G#RpAO4XbXf+u*eX0;]d%WrB_W%A@m=E" ϼٴDEw 0KL~%ښX#r|1 qs43 3A~7 й&| ][L4Ξq'0xe?l{(/ޱ}~f#?m{ۃ[i*pBBz$L1ps4rT] oYAMǃax4}xe5_#'u<^;+Ȫ|]Wr4ݞHIh#p!2*2_s[<&/cc:]+,FuCnx"/fV,6JNP'. KPdS.,rHf0[LÊ+F^4 g341ej1SA2M|qu$"4A#_ y?Uu( PFVqy1?8Om[S5xmk$xdn}m  mo'm ֎6wmNx+7$w?7,sAyJVU=JJɄj= uH*IaYTQ*Yᗅ HޠSfLr0`*ړR5Cgf\G:fϨ4 =`!OB8.f$a 7 Y1 GKu`Q@Љ>mֵ|5vJpߕk蛺(=OByng.qO4.rU @~YrIZ]6 \yKϭ|#!.yw,vSf}ѓdR(fBk1`aIoYM'MT%!"W%$mFCY$~ ,5C^˅|9Vxa ORFC I,2_,*f<N@ٸ,1DZ $l5 G&0"7jI6]dh|.<&e xO8u|,r~TN&UrFl֫o(E,݆&7THgRX2M("we!SAWjH|$dɹ'`i@¬eį5xU^ZXV$_!YRN)oBN$f>3,ݛʜ]Ls䞹^$r=ÌKA1+?uqW}ioMʆ6B$xeeHp8~ihZ74Hf h[+~YZX{H3ޣ{A~C^R4/+m{ ]MVN7G/Tw‡ Ygez Ls9pDV7n0B1C=¯~8L0}IQ)_spW !YŖRx7aa:PGfz}"7jU=GA+ZZ$2( ,EGbt 3=L`5-;»m6Wy nV)E%U| G1 F&g%Y 2WF~UfVrD8NuZ>@]+òcmڤ&=&ܣʌT5izS@5Z|q.؉pڔ& K^VeZ0hM;(dxq*5WɩGc? Y .j nw &L̘؈Rּ%,plSwZkFfr(bdXvLW.]X(+V5 ^i"jڱ>hF~]p& ܽjp'a[ί1~W,j+zP .kP02 ACZa}otVq4jjcvX͏^R:u|qh 6٪E҄?|a01TZƟȅȻѯ\|_Uϝ'q| C3ìk&4GX(%F,%Q $#ۡ5Ik U.V=AI?.\E?<3+8S1pMGUI9Jȅ Whq;\UQjz2 .UAUKafEl(n9'Nհh#zo%sQ -Zk_ޡWխB36@[dgO֌%kh^ ڽ䂦?7|8yluܞ9b-iO'੒T<2|}ۼt,8Oe+BOv)/y96PG*Nz'qC Ϯ{Ν8vrKZmtVJJb]ph&V浻N?ʪ>JJ)9$:L'Kλo\QdѳMUBY:FqTV:!<+#^O4E ;7,3u!+7#_ف.^'EI\&Yo^KrP\klcoKlz|T&fd7گ΅rb\}}?,4o0q}n|v~K+i#Lֽâ{h"w[XkCӕ;r?i{[sjsyjAY} W'ы2T^wjT|Cj\VE;#S7mXmRDX Ҧ9'|=9ϧU'^Er_fR (zy*fEϠO& O]V \k"Xx'ӆ)iy :I  v31g$j8;xx8jZsg(@@biIF|nzQ|QjNjbqj}ɋtΖ=u O#esz;]߻/( _i#GN}N/㐫jppY-jdª~^ ߼PTg\[j][69nÅ,-(r ȶLWU\fJNuRrVa]U}|SfB":ڲnN^v35{G^yC,$]x{ƴ1ӆɢz~!F\!A>! %%EyE%yE%)7rAl~)^`d>%Nfql:&i#kx%=  z,x[}i9 \D&'2Ndvpqz^xAL`#fcP!eb?*H3{FN^(+6f>`;\xpiI nj O> h?z n#x|i S620 +7 ]5<l8x{qi T6Rw,=B) #xj b%s63 8Ņ'ȰL֕3aA~ e'3ܼCs&\5Qx;i* 6.:Wwie_ px;i* 6.:Ww?dFmFy" ,x۽r U7m瞼[`K$ m#x{R 'M4Y 4-m;x{ f&_,0xa1ӆ̓&6К!}H *xkX4i6/WΘ6Q h|#xy40961024!54  //DE#G]ff \$- $ ${%J' s+.Z+ 9 :;Df{~&nx[i[s-<4~n x[Ĵr jw-9xVKLW ؁|P!|[*5f'Q5g79Q"fgN.9嗣s8 V'L5搽4&ΰR8~Q4Ǭ~,&b*YLu;z} ŒIEN<,vF;ᛮ{ęӖsx㹆Ēj58ůHd$=@%@HR˒*/AHh:Z$"(T*\e*Ši;o5+hXxtUAO{='FHJЄj)Z\rD+&]QkJVN0gR6ZQںcIt ?K/Ft "M6*dY8)Q[R͵Bs-KZf sPvǟ2Ղ6!ݽE`Y`'¼?EB'i?/<'g יM>揇Y2CB 㵄W j6g7q\42!-Ègp;&glUqZșmDS+VűP9&rÃ>0 UGu7]+rb<˄W0~7'ޡ3(谾\h8e%9R,Ymxo=,h~e`F-Mś;2 AQB06xktӆ\E3S|&)i䧥(8E*h%'(88Gy:{F*hm^òVk:#BSx{ M',*5](m“Xn s&1Y6,sB6ix;w a Wɋoޯ9\X 3x;w |C"|=\99M ,͸SR2R|#CC<89 L6˱[HN^%/yBl\Ux;;%VFYT7wn]`7: xSKPU<~:v, vj@DžH6,D\]µ BW.\t1Ȁ 8s5h^C`6s=m}b -5(rr=Z(<౅CF8'*aJsK3<{5-# 3ՁK3K {W W,< /7|b P ߕDMƚҒaU QN[Oljl7F%l3YnGxrq ,,#Y/|xq- /Xt&ew $-0kkBs䓜wڲldQ 16RڼMcr,d/^rGXRSR2R|C| &psve\\]}]B2F\e) %E)y%9y%/M_lwb ,58'䋀ԒɎF\0%?PBntx|M rM6xwM gx'O,ű8{  /dKyjA\kG27eڬrb\Y xX[o~yhl|[4hV- Bhn \sHIm93݇!ȏUMܐY*YDb$Y΄z#نs!Tl/@8%H"dğ|"^Q/`SAT,\I )bE(ALLJ9 E%~dI#!ԟxS?Ix1Wɷ6yHU(Uu q@m2IR} ڧ"'y}'s K25ʵ=9v]!o% %kFLh<I٫o^ 6tQsy&} '-$j8&1 L!KϏvԒ'+A%z@q"QX)sjZoSBsI#.4!.gL7!G6! ,u*RXTz:9Y=

).l K<ݟ }4LA:x5dx?G{f,BzNi-ӆ H 5bϣ+rb`_A(lNLOC#0r"Jmm~j~2!<A%VmpW!h#leei9G#22~xʓZƒ~+&Znvԙǥ;cMG{Ev_ WY: UB(I!$ aGzp8:P iuvJ/KEa{ ;mO?Ta8{,<y4m;_9I}Sbc!~?Kn}7?!l q2e)5ﷂm`P: tI{;61,Rh’L}*s50ׂ?uf1^`}Q{] TGt|{[& cpF\C5qUґ B6#멩ŽUx :pĪTP`tzZvxZoQl_,ㅧw_;le rW?N]Az!'u!N9MάO|O3ƤB_R'6Rc1L Ju]72BZvqX bܝb:F:b)*ObжfiɋCu~<@4{)ܢh>6?\˃H7(OjX{s}~xno>AH^cKW( UV3q=}QAAa`(VOj[i0 GU႗\@I >ݟ][Al?_xZWH?]5*^ PI 8TΈVSzm/͛@ jxSGBOpGbRd3DUc"-aұ@ԣk '&ً.ol5cx;A{CZQ[.Լ4.N x۠}Fs ;SsM6,a! %!.٩% %tKJ'e3RkiZsq)dq+\&x0)J'0 T d };  ZA_?x"wZf.X6ry1n k ~hx(Xf-Vɂd\̢ĢԲԼbɆb؄d *sSKRsȊ6ױd%F[nw#_x{,Ar2OnLZ A  Z Y&I B r*2٢&q3XLNTa04<\.+[x yNrC&dUV}YD7cUbo?lx 9Kr Iq,!7`x 9KrVXM6?bb<#Z 7pGt P׆ "2NSq =Slv2h#i$\bUL @ߊ$Ĕx3 Dbep,\*BnVlw== %w|庪W\L3W d.⭰gʾ!.VnT(&WhC Bcá(izPx=j_ms $giW(/Yپp7bp`1mLfx28<; 3Z(1Czx}2i${ۇkI`I,'vr/ Ul*iD/l}(*NY0+ˍShM-Y*ZVhB(<接M"ap* %NDt\gpA+_xAn;"FQ/  f%mqʄV$vxU"#kO0#Ijvxv2> `޲\ =:3h,IAW3V$XR)`nΖ6~y!xݼخašj@)Fpf *.YQ9c&؝3ej\X@ zIKFj ʳ_;pnTj?G\WRϡU o5^ә+?\@glx[dr l#3x[dr܍grl,a,) _~!xlb!Ly8<=xlybf}̓ݙ6p,S6!xbqbC3dg>S'm7v$x#87$I ? N1x[dtf^VA7wqeټAuURf~>>\\\ʩy)i\#x}X[6~.BMA؂UL0 vm'9 >Fltޱ`w|)?lWOG%s~8`G&!z:_ |ǀca3MY<:,=)?{0oحNn/.?aWi{aVqR{x_Lky~zi}\iw03M fB/"Ofrml9^hqg6H;[HcC[6őgL}9I6."bsRG}|gw:,ͷmYOl@, \2#QTA}'Z,B-<Ȭ= O KX瘁KT'6ڰއ> !Џ'K~s 31l{:ulE :?B{[j}"Z#P^3/*8{.=B"V)\ K$¢S6xǁ0`> .um~CLHE0fL2}Z T{ keNh*JY`iPD3 >½@pZMDIs۽.#7>%jF5W7̝▝P4.澀+VĪ4*UtIFssU-%iɣ ;+Hj>It #F>/ӂτ1=U7|1R:C/:x"< _m<۸ 4kJU Q|`)>M~1t y$s7a&O󍡑РwG|*U"`rN [Xl쁕pC+'K|'9z l53\ mod=h8u-&MǸϹn_nV/Q€GJe'pU߄6c3e١ tFgkXTIi"xL2viOOdmh֥!k6nCuBR%,jP^J@Lg"KpWWs}C/gf8M#􂳈Ga R. *Ѯ Vo m@U5WLz(6Vje,^Gwx]jF=,ؕSR2ӸWr9xxSazodY͸j'_d۬_`xx@vC|R&\\֓/2MVeKKL  xxXn&C#d6dbɻ|M^nqC.`x xG_GP7Ɂ|A,z_W'M-}$``אW[s ip? d5jܑ̀Z ~0'g5⪵zCl ([j^Jf<.~nAw|&Mÿlwx;,wHnCp7"x;,wXn4x_dOBsKcpHK95/%3 s^n]xo0 ǟ׿ҩT^x퐀Me;JmshW7Jk "Jb3HYGs4n :pFGхE;D(0a9XqZ>t5e`(Nj3V*2#Wp{s.?K T%[bA)a 3peU I |M-jfl1W%/*g$Ze0.`5/v-i<_BJAD-w? wszt=ΎґQ~zܭ m AkC(f2_i&0;ڥEΖ]G [#eɥTK-,p@%f0E[t㧪)q.77WYRww6?|~OӇ{?1,dgH:MitNQL'NN7թ|Մ[ɂAή񞾎\\ʩy)i\*x{ #DFɚY4H HX|hh/a)e!nqva5=V҅ŸFcUmDZ D|m4НNSXq3A>}QJ-kTԞXj"'HK<;c|kNGb',`VpDS?qfڝ-9-ŽEwB6Nzcnd:|ܝ*^l#uW WQ?9굔RPr%qKĿxo\/6#`z#(*Kce/uC]s9u$9>)4i*'̭ߍ zx;$LbC#g}JjZf^O~KjRiSbrvIQbr&'pq+Tsrxe) ZI%)%ц0$ܤ 5JC⒔MkZLT u%qerws6lx;$>W|/̼ҔT⒢̼t ;?6Of nk0x+)>f>~.:Ex+!>8WjEIjQBf^BZ~QjzQ~i^d>Ƅ\ͷq/k:xo{3c| xk?,:7{jEIjQ37sb% :aDֈkdYHv _^QJ2 +l6+XEϻ#N!|C.p{;rP\'+GFY V:y}Neeϯ3VtWdJ6q됼J߄/_sBol~A1,j^ LF!Íj?˶30JZUΗd sgkXD _gv+m xkf=2azy)i !!>\\ʙi"@nf^*X55>1ăSI?%L WK958 y)i\Pœ'0{yx:xFprMx1 vx;re\6#ӉsuKJKJ rSR2SSR83 K2SR2RB\\|C}=C=C|8 qsqqf /J+,pRj&{0jqrNn`< 1x;y 6;321C#x;yiŔԴ̼Tx 0נx?G_W%2\ΌLxfx;2gf^Bf~rIdFnO?OG(W5' ]xuT]o0}&NaOۤ4X%kB%2)^l¿u4${9vt!0)N _`)~8 5Jn5S @-*c0KNrWee BPåo5Lk"*4N?4unЄՂ-v?tRyҡ5 oJ1߮~:][v@(٬yqk9pӒry݃xE^ BfiV\a HSb) S- (KWsBUc;;Ph'aIsUxX]mu0Z# fȲIIxMsoJMw~sWe*ժmNuɟ 񎚚K |D6Mq$MȀ$~0rvՄI2= ֪( H(BWjJʌ$6k>*53UvLHzsԊd;jV%ޢ@ᎎ&3>A:g<܁5կMJ; zbfTp_(P)>BH6,È۫ex}{f̪ͳ_0Nnet Px[[sF~6kReSǞ8y!Md*юX]llӺK7jl;UK_tΧVntu%1 ]ۋG2 -  VdaD4D' (HBS#F_#ʹzA` ݧuL> |#$r}E`Y' WS;ܕ+b3}nh3ú:?/UEl$:G/U?]υ0WW!dcۇ BKL v{Ũx^ s׀B0і:uHxM _h$ޒAL &<ױSxm υB2dU ^`/]\%Iau9Cpb~!]HBDKS+f.IH ؆_ԉ/~9lh=_ڱ'db5 G}-`7\c0E` `,$Me&LSE$fGfxάd撤uBITkOCOU{}f3qY6TS*qY|UOuc(\5B\fT Si}J;zI8]-sA{#h.DIwOQ(>UfcId&Jnjmχ%B$R&tG Lt[4}.b0NZw=\&k$aӎu13)n en޷"Hw>)IX7m2^PH.}~ۈ=h7d؋i䖄W?IafΆ䨈ˌ+(Xb) s_ۓ:6-LM'& FT ]̰Cn,M!,t#|V\P jٰ7Cw/-6PO JLXfG{ h>Ys.AN !hj%̢i±lJPe8?`#0<!搤 2);IӆWa[gF0EEo"c; {/{y/ioe7x`Dzc ;5xa Tz TX!4]q7mmSŹZD]' #.N 8~a%fwt i"!8 kӸ RBKUq11, I <,1uT7i'u's8fNߴz>ަT|M4Ix_̝׀>F4@GlAn#ᶳ~1EHnO]|oGk򵗬 wJFĎG%G#{ B7^oW4w[zE!#΂{Ÿi0Ii#H܋BS_AWkƯ( ^I*WAw*N)B<& E[hXdM#gǁZ%Uܢq3 cC\ 0pE#SC|ǑyRk~hkh8lba7.BA¨0۔^`B*%@@xsnQqJkHa-g" #'M hzw\=#J?*;90Z-O2"TAģ |))PLx7H7~<Y ë8 *c=ox⯓$Ȟa rC+%ۛIl6wjD',_ ɮ3mr/9VlLŠUC2)V;$#S1!|j iPEҽtggR0w Jg:-Gyp)r*4m~'ԙu:ٲ/QaP}M7؎%6TBE hWX^"u]PQzи}+Ԙr +\W\CECY+m Β='w}Ztu2NysJ^EjB{Cc}Ώdl ^97"@X\>{dIsC̮rv5T]?Ά ,AO>8k;L"{:_H HPG(F FCwkNƴsw p`,/.Q<)fx(qRdyZ,Q%HҴcK5qI5! H'䭦?Wiy6e1b!= prwvvÿT{ϝFUT SŜvw ⤿>| ' % p7}>͍6L2d9nijJ+"og6ӏ8Ve%Ml6,_l:} UOqEUb`N6!PC>o%q)7,/h1䷊)N"_kWn RG^N擡 듐⫭CWQ T5aP\AKۉ vdn>^j?(u\}B0/d>P%!lWd"4?c"N@]>sWYܤY$.)K b2+stl smyxmbWZxsH, xWnjdHNlx;Pv4O /fT3x;PVaf :O J([xk}P!?3($3?;ұ$cC9JlUIfmh>&:x{PV\.l)³YFcf1f3t=&A;ix0yx6& DD (*-H޻>xYAssz٬7ϗ(Pj!xY[c6Owɍ,9X'o9^ H/ eo\XGx1ua6Y@* ,.+,?x۟?q&5\u8M@5w%x۟8aC)Ry6|\$Ex۟8=aC)Ry6³YR|$ n%x"|hMsyX97]b\+)Ŷyyv5aͧ~0rN>nDx[~&l6[j^Jf-Y\x[.tCmly)i\Wzx[;d86icKKL6 =$x;dge'gNɂ*byU[i,xAK1+zѢ"z݃,{HY7&afoi |ͤ(,ZnBDB>FPiEx-.xg9%v<%%ܭ70=R5bPET$_tExd;0B@QՔ2DL eHd0k,3|&/I.\;|fѝ6yݜ') uM -1x;:a.]1fL$2ٗɚ)x&gT ek5xkgIJ:78&kxred}&gxWKsH>ïT"W} D̫Li$SA(k&}{x` Ctt7兌.mYœQxɉ3JXZt:>oW>EOtF+\"hUf(Nu+AcxȐ›d~B@[]OYO*FlӶ1ܒb:VBxX`oD, `—2kĪWp 7'TMӹTRVO]'ft7T0Ħ¾aaъ{S/\z/}_Vx}.^A7.\taz1sz*LpLʀ^"+'j:;м)ʝsE[ʃ{.vB9OU{b!߄ol,h@&QUɺc ~lONm6yKW%M[9\G01ckcv±>(Iצ-ۡ/7IŒ!5+ߞ,΋yN(6n\|}bW'K{>nZ:0 y<wup-KdOGNLii3J4f7 _n4KuK|Ո@= 8#u6k)*JQ VڅAo쪞EPx<$i?iU6BI?^eW;fu"!ZaSZI=Vǿn[7]cx[ϴiC@}3xQN0=u8pj&Wڞ,7^R;rAz&.dͼ7v0 QKHCd7ȬiѺ= EJ;`:7=I;Y<(BbMZ:el`wJcבr~w8?gMTK@<(n<MJ \;),q-R4zu>/q=O㄀c>_̓FEokm9A) ;WlFPt$Z.KO%gmzՔ~ӨVf:&.U^ExĶmY&gRLFx}N0EgWFVe``j"݁23v:w}lU0h&N% V?PHxenBSc0[L8D?M7SOJy@K龍 N(hŘi2;lo}ב|/ymddwPc+n"K~xm~l^fU( r5 Z-xAo0 D{i6l;씺AW I+ *t,ԡ N?YKlAL*0) fVm#|Yjx%JCU0&H zvUqeeg[.K(Bgn(EȶpGOcJvktsJo~|(5ʲQwX]]H[ρ6H[#0.Po-B"xZ4]` ukwm"ta! LOi,MUwFB@MBv 㱬S;b1ZL's:9K}p(q\\z̞q3T c9)NlbgTzݙ(r {v=s=k+S_הn"%/H8fx _xV]o0}& T)AvӞuߋT qFӊN6iMJ&!=>~J8m 0%JF2`.ŎJߟ"@zA\n(XDIaWx0dVQ's8U 7[sBuSqZ,1M Z-l_6!ox;!otf^$*$Mͅ,X@B}q I.xϷo/f#ƽU'3IMf\?yԁ xV]o0}N~}ik*M{*FTZNu/V8jDӊل48Ǿܯ#W]0!aDpHi f51;eM%OsA6a,4!o P˷@2. ٚՓ,4eA\PFP'RɎK:q$Ki$9TE ErqO.(a|߂dN^{|6y>eaxi;r۱zaX05泙5&q Y^IHy>%NkE§XtDaZ %A||2sָ?,9E8%R4 QF-=,p<{s^ѧIx`fxЀ$3'M1G*=ٱKIw3x&l${P`v?[$z!>b`@D0~C&?=Œt4 {C_IY湝^w>8y޻>|}}ru_?8<.FkGШP΁PCj(|3?d 9#  | *i!6 ]. Cv?*Oy9w/fԽl ձUX$Äɱ&|"G"n5Ի[fiߑkX:o}v8!Qfޟ@؊J tx??hE0 n׆Di;lQEa:ȝ7b=ty&w2rϜaބAV1VR?4A4+Vb@g4`Bq+0Ǒ5&v ._qXARo 'i0M8*g@ xMtWC*r^#u3)yYZ*|4SX4Z㤩 0|!>AhE}5R5K lEzVΟ:G1N"pBۅdЬVݮ9S& >x(|o7&dA,aٓJ0@Z^ /opr`MoD$Edb Azg&gʭش[x‘,_a;@Vpz.ꥫl!sz Գ~s"f 4}(gD LUǣlW]mYJ1v_*Y8# LjƔ@ @s < :ǥ\բiP>lZGG@qP{9Xq!i,5aN 0ۇk84]X:P0c]k pYQUˤXmJ,o]l_R~m (nֳHr(} zb.j؄/\`SVC.08#0Մ^ \"/f-X{-,h/^Z d';k]LP,mfUAdEArl5.F9r*PDk -#; BQD=-# pH BL1V$h (KԜ8i79GqJ kV+V$k!F)Cu{UbKhZ$mh*|( ?X2WK MfA*MPwp@9SxWtGSӞŏϒJW ߵ& yX88 J?fxV6mv9IzGZn$P~Y¨LAy&Lr)- V8nl;z. 7!= UlEh>J鶏ua㑵? Fa ݽ2hdeV?g"9Q1~nfx|`XI(p_7aônRX$%%:oPbͣ bwP鶭L8P1bSlؑ.dY`"$ҴyS9kdFl%oE}~0ٽb/UF5yZ PںbiXLx+R S~ OBKkֆp/?ofU.aue#L`6nn{b@)C@sm)o0%;7]\UU&ߢđ?RP(S)Hd̅T[̆nqCIfP#.,.U\n׏ =m}后N- *&~X-}@)C6oBmdAL7nB6PNBl-Sїp㢦T`e9x:{-_ Lj}*MKAaAĒJЖFI#Rg:q½Xl(Vb=)Vp)ξܪsglֻļkXӺJq,>{rA"{ g)OWtB! w8?(`m4МD2#>"f毐O s+y{0O:Bf),WpNAa}˥.4jώK)mA@Nc$=Q S1X묁ISDv#aP$Bg@ lk/+ec]v"T5zwQ8T0W*z-JP ަ~[P˒?:~Q4)/l߆ J g VHXzG!e6׵onܨ" ,~PƌFd0vDmd[eȋډ,RK*j2 5ۺ|Ag j*]8CA5l=|1r3.\Pb\oLi{&NrиE x9SX2;hrC/;p K>z! +!݀AK"0Ѭ7_Mڻfd'.hjȓɝ*Hh5TltnuKe|yxY0{<>2_G ٛ#(B\ [ ttO~A'{|G;I>8(W`fc1o DϷ6aht0Xm6AO- G0^J 59QjR~Ҷ"z(ޝ r5.׃AOeuw7뢯<ql_OؼzA1De÷HK>, Owτozɘ}(2e1YGz{f/ZYc)J \h,pL޿A 2p*QP V-ţ&e7~^5j =u'/'9wk}ovZJY1b$ر!0Y= z?ր)M0iX<$#Tⷛ8J/^* h x cMʜ #`>ыq/_3 ~h3ˌ5-&=|Yp)82'hC;\[Щ"V ~2 PˌP>,lޮ=cްmq~f) vol+,vPu@7 xUXKmI 0CW (Xqo=1ǡO6;mW7w~_@qzǕĂG4a[+2C[2'׷fN_k܊x#07eF,5[TWr~lTfn:'}siw8s+IOxZo6~n.)6 0h,${XY Gadw'yJ}y<G*gowO>k\j..fͲiB@6߻^Z4y/~w2\ͧefW?֛m֕u!o1B-u 1ĮtQczv%7"men$gzt["tF@Q.Qn4$r$] ^:xE-f0RD+H\>k1;|nwJq/E%;-_aۯG\e!=Vc'Eھ=|?=o[?;]◟ҔaF>J;-طݾ;잟RJ`zpJi>nzhIabVQ{hk]Bl&ޒӒUo6]3e[s ͔Kqf2JhDC3Ƕ<۲lQ(Yvγs֒ԃGKu oK 7Sr_0`r$yLپgLdPB f f̐kŒ!-Ɛ}37s]C1͌`blf4p6W"d r=73BZ Cx6ekhfȨxȾa jA Hp8@\*H&;r+*,ĀPcb Czj=|b<DlІS',#*ߌDn_ ,FU]fj%81Ne1 9.u|P[_)Q{]Si~X Yro_q 2ݖv}[ 0 1}QDԛ.M /tjǧiv{/h1M{|U=O7;mM7^뫧]]#HAsi-  vK3Ҽ5G~.f,XI\@FF0'&cfYbhR ,6kgqS)2N~;yhBwaEK-VIfעK+&p?cqG09|he9w0m( ;t塃fv-{0z[ 3w}s2eAcѬ3FD]ͤ #LZd u_09Z^CoGx{kRw%&Il^=T!x[kC(dM>9|;5ȴKxT]k0}/?ܑmn㤄Atev7dK$,+4sl p}9././U  6WU i&)gUD`4璙KN=='JL,{ Za-[(` 1l;LvpWwptA2OA3O?>_jc~QU KM`7+ۺ^}9Uq VQijN@s3k)PKYA7̀]ě1m}ޚ+̴rwvWuGbs-Q3c9sQitf:g,P/O_b؉ŨCDk32D!%)4bze!  F].LURs:Ow9~Bo]BxRLKIMSqpwqus RJdbʖ'e+d%甦X)Eɉ%) )E i9 %2zSR2xB(xm 0@aw9$/!\Uf&&:<I y%[x@4@|Zg ~4_^X,_^|xm&)S& J܇ \[Ǐ I$S8_}MJ?; x=5V46 ;!qJ妆1F8* ez^}Y>d 3Ns.ߝU.$!reyef~r t #2]#Wfv=fA s[?eNZR9.ֹ2x{^[ach>K:ot۩~ + ?R{0uH\ z C]l/>sriv7#a{u Nr$ƒݥ2)rHWʤh} aa^UQ^]O42 _U)\' ZAX0{OdN'ӥʫ=rb~M)rYT9!{RBml5S WtA1fܥrķJq'Bg ko!ԮAk{t?1-Solt\>M| l^;8wrV(C'c^sښSB6.z F%)9>q*))[`|a2@"|*Rm(U$hF3[EKb _,a1"Ij6ݓ n6nv=[Kq万X3xASꊉZq PY|6jS! D Xvfe]j*.zCJZ&UYs1֖ M /<{ƈC89;gܩqgtnoKC⻹|^ȔUkdu;xwM0oqCD:Z2&hGW40։3.;L68n G0ЖeR +LklR-9>4_-z9!\`N,x1FYfykʢ=rl ( !^Qt*>$Ü݄!@rg;b F FH@y豠aVt|n8t~1mwt>m>t_WD}U#.AdIIi|d#.ꠑ8M+bScNB|Bo*j%wZSj'Hĝ!-T!nǹ_^64GV /(gCN.)JzUԟy] 7<ۯ%*13v *,['؟nYDPMDI\1};v2Rsj2|XC#).@K] ?"%T>{:3 \ "^bmbF[w:PZ1=L; b9_WQ>R[#JP|ĀmC\϶|*"8~r*Jj`c:iF>d]Pj5ɔ`,$:>'ZxAH.RYV&9/an `L6FwTWM/|2^6ԱAϽ >?b]󍮰YIlܴX-үS`;v/ɠHpcK[+A=g5Ziv2;5$$$|š"hOBaЂAlE6,}WDKbh@x(]]çʎj;riǎS vK/!b/Jހ#ϛכvl+=}Z O~1<+A $mu܆*^R q)ᑺemoe u1/5ܭ5RB+5,`^Ifl1HK H.a!3OKL5UH6kbsalg/\c+כΐk_q;af5 2VQIȠEV9ܞmFt ]j]%:8Ϸ_{]5 g((3{}]x]3hp;;\Б=&,gt]m%2nUڊt]M$jk&rM%  Sp;`j=fe*dR>kJX*+/y 2գ2|Cڔ!ZwU=W2_%@8-﷒}z> 돒{ eqל`.ǮWۊp y^i. k=TѮxk M$񹧹k _4):ݏg'6$4r}pׯ5,.VX@չ\.},m2Et r,u9;3=/'~)C6x$%F nui@zM9ܖ-obZ#%>#LL|9 \F姟l jv6SIߋ#7INFKV4= #5.;b>fi{.?7t"J=3 Q?(!6rV@!rkRYYbNg9T<g|SW<~-gstsl cQ*NRRs.G+y@y6O:z NB =S6<)[x6Q/t\DӡF`"q S)q,>HESV>dw c NayfuNCO îsV%]-Kɹ:ܑ)#ڵw{񥳸 0}/ *G"fdc֟(N#^wQ p.۽l%>D\T>p&S^9Y:v=ukZQ9v}!R{n1dghzT%{Y(&?hb"avXJ6Sx="GՂmm ^05hd/_;ХOI&ir:qKiհ W|j-)O!kY]_݌\vvN%3!n ۴Gׯ~ xVi2defines.h> /* XXX added by the trousers project */i@ax- );\nex5yt ERɚl4;lx[64 ?( 0x[6m̍7TlXʼy_ z Hxn0E #uC*n ƴQ! vVH&d;}HܙSjb(j%CmTTj={?xa BpDv\2!\% f}}%xlyv9F B4os]w~9H}0D{I@,Ȇ!~;C޷HN)"XA:70Yznf4^ 6D\ }9%21b%Ho{!Y2 !D#xk>!or9Vc 03;z kGxk>3;}xU[o0~`ie]vJ]PT@v/ȁ-3t~@HHK||G0$@B,R I$$)(R^]]C6)HGf xǸo3 (i|gtؽ#sٌF-p_ 693.bZdL"K? i_4ۊMߋS46ɐ{}_wMV֓)##@bg:Jwo[SCEN,O捯^/N&u>];t^ܙUNƵ):)$P@ YiFŸ"sHU{ֽa;k4~j&K?qeH%hMvn:dPmσxC%,)ly ƢOsZǪtݪ-+F"fJ0Ζ6&ӪV|"s SBa$s4rfrzgqwT$NL٩4.JpjXϘ;hPnwc6Qkp).wuqPr'RShC=9Z°%}t`u7 { );mnã[?%80x?C_K[KAa"RLKIMSqw R fb#t]'6s)d)#IpqBqAjrfZfBjQQ~Br~JjBQjIiQ^jBRBIF*Hs~QBpjQYfr*Hc~ZZqj D3<܂]C@dCJR+J&I|23\.;".5QkĤM`򬀬L&2[y'gVb98LnaqB/FHjε>xSQo0~G?ԷV3$lDM`C,U0HhHbEѝ;Ã^݀p8 a8q}T%y3_еxq*]5Db l~:~}wk _2khez$3{V VѾ|E6F{̄ +ERdXlCNOW6e+J:UzDWCcT/jpE&Q9?E1A_c]2@g- D5Aյj^r_C}йm%ߋ;MB3N PǷ0%L6?RVθhu@cC'EA>t5#m'$Y]A~Kt8N5Xa&0cw]v=WE/8.8C3hwPZN˦Si!z_$rLf`Ba@<>X6\2L z+9&4sQ)[ꄖ޽872f"EDŽK]Lh|o%O1B*x`{ȡť0CEKKK93-/%5M!>>98>$2-#>~b% L|5 P:DSxo0ǟI{itu4ؐD@d9Kf6t?$|$].WF^QBr7@)M+9PQ뉾,+y%:N@8b=3fU[ |kM:3ŨzX?k$!.ىGǠ;=n@!/X uԜenP5RV2ͽOW ߠYkV+zŪ^΅(KM蒏mEc_B̃(ytHQk y[ZY&1s S2ӯn||DbxX]Ɍbay.75I'}ړtd'RPTߺKv${p>xZ]yD9Brci*4oEk,o\X/C+ںSMvۀَep3εR#on,ES(4F)UxQЯ=r8 Hxn-x͵kTfFӘ2)+GxuC_K[KAa"'(91ZRK93-/%5M!$8851u9).Լ4}}$ j}ɂNI@Z!?-8,RvwsᄘbKx@U@y\3jOc̤5YIȳT&oar~2MV`vA,ɋAjO3OfX&糘Y+Yt'_gqb,* Ix[sHߪSuI6ƒ󵩭\$d(# -u?g3{8dt ~}//~-$,O">Mɋ_࿋_; VOWqmG3Mtn pL䅹OYۅnowOњކn)Ki}SJJ M&$Iev VfAdiŇܹaB %WC 2$3: ՗8raop+F %|&Ggϸǩx~כOs2'N^ٞTw2򽺣k.2/m*m_9b4Xp RH?4d3^{Mӣ'xG(>7l>{7@'8RC$5OxKJ`v.hnr7 dIIJM&'LIi^n׫n0r1yߐ.hT)wMu Z6}jFWVy9Yb>h¦oQpZ3jUMuiX'`Jn VwҒOFo28 ES`εo݇bș+2l `[۹ 6¥뷢ka9S:T݊G TFjRPY1aӹUgqF:[*IWQ&S-P6+ݳr,L!(ml Cmϧb9T[ 15=/O6<&՘NYX . yT,Sm7Lbfx] blz]}md-s#9cM: =1dZvq~B4ʊBPs0" W2Sԝ;,POcύ<^ owDݒh1t363 TD "@D/C%%ib؈@Yp⻙ OƏx (Bb)e(C}nA$S(bG/AfDã^H`.֋jwFV(򴭹㱥k;ea.ѣ]wB(*q[ 5x̀@?)ݘaX7(<`^fܹ;Jy%TXaI0 {Gx%uoصi|դ*n9 aKɭbVLnĨ{0$ um+cBJAkn[1[h j 0 C\8S )|#VGQ|X$1ܬߍ`"}dse:6k;Dbcl1h|7#˒`y#u#]Pe 9kq-ʗ,FW$r rao܅ u^LOh].WU$Uld0]EeBcYM& ).f)ʚo%@}_ǐ92#.)lif\5-*g;^l0[¡>J%q P;Cɒ;3' }]"pJ0{v&JJZ}pܸ} + !KuRktJDO{L e |*^t\%ݚ&l4bƍ)$ X`=4[SS~a?1GeBVVybb}p?l`>&Ԣ8Ey'7f1i{nƷ7QG@iӤ[VyCV`9f͍ pKlD#pei >M4ę1>|܂+L.;XqtZ@Y,B65햸S3}8IժhAn?qni1{Kxn}0sV/DID+gV%gk:mY3YF);Pm6ܧ=: qk[$9ڎ@/ZoܠdawT%) L<7Qn{a-lW\+}e@7408+uW.Mrgߙ/!龑*#d$׸58> ?cGoH| rXrS÷s] ij f6*QDUZG1gbSٙhkwor7Icy~SP>rxmPJ@>x $7zig$`biid'v%-zV >hTd/|?ܿ糋4H1ڀAh[#[HBbd4)=I6y;?bXZݭ cq4XKX|89|:lJÆWF[(F@rR+4=YM* rG ]:޴Ukz"P k&/Skmڀ&-L^*wvp}7ve#q{S,},Qo27B%d D7ᣢ+Gx_2'AL^% V#x_h[UrӦ7o[-Mr6nݖV]2tDVATT#"` =Ø7068N5$ܛssލ D2Ip;;uwwZ`:Bd"EVm,]Uj"˒!j'Swb*g C5^rP ~84)^>NE@NInnr̪Pd2f"x_E:L[Bm MjHG Hz^Sg $~ R3Kzj6- / -VL~^rQ p$#C\". /Ⳛ \X-}E-M@bҷMsax|fi%>/run{ZP9 J—X]Tqw gd}(G*UJtad@, 5kŁ}ZOlHJXb"4]мruµ\cJNzq]C jR6xhT* 7{ O-30 gX+u k$v4Mto46/U <4sO3ulYa>/渪x"SUXVc&ӒCu ---|dq)v* 1>\q-z4r\.rWe~2&]hsV fJk*m؄ݵn\`Lj%g-)s"zsAw2v7ү)81eu:a>p$%fv $iy9>r& cgvMoNl,p8+"Nsm1̼1k иm#wVy? Uϼ=^ƛ^P>3nv b 7JQ,}[rۇ\Xci[G k^u݆ i,JUhYBI6:{hޒS{dj '(@† O[YAڦF 'F Kٹ_nCT & jlyH #A$fk_AZ 0Ԣx͖o8ߑf^([.qW+Q(I(ۧCEwb#m <=\$bf;$Aӧfو'w'"xB C1LAHzRl6tA!$ɏ$EZ_/L#|K:Gb\~{yJM>xܞ2vtult:€Y"0G( rPfBrl Ϙ](2;s/rk2h-S䘶xK-#cf8+V;Vrn ԯ-^wv<o5 e-`]T4 ǓA?x򠤒IMOAai?a2ؠ4:p|&Q:/:庬 1HaYNs V(i6'#ͳ”f_h$|}'OEWl XvIhr?܍7mGQ0FG$eI ~ f yWCJgL_ƌUXʋ2.@V+=9y益̸̬b^X4f M.fv4w=Ȅ](x}ms8dg=d2Um%%g)-6/#i'ޭ'U=fg,u7Fh4~~׿ƣ7CN |)dYwg'Ď,tiz{?U$/U\SxG=@A'er\7v>dݤee"l>]ggA{INmVzw#zdl[JId+2Kܦ[Hf~4p{W>amIax7T $YAwْpCI][A*oLq`~3'4'ԩTHRB-3"YtI`2oIg(^WtJ8!k+"-q58l붢]^;kq@P??HC?^yӃޱw0 f`.ӣEN'I#3M蟞erz?D L/cytB{(>W`sIrRtfkP Yߠh܄iA'Y)Ih%?a8^&, 9JOFAp9>0 ^80p2\/?]~E8v\׮ao_}ׯQχ3o\ lP%u`ػˁp%f`_RG`!|$SAS|ҽW_,+dC,hޟ#OOdP,mv:UE5uq8W 8\YZ<#xfgȀp|6Q VF|k@^ " #x?&C T1h2#jQDST1\#.YWF͙-3!џ \&{TD=ΣfaQUd0٨#1 "PMf oC4Rt~: D=rD{Q\Ycz *#ѰMd2DWdQ2"Sv2u"Q^ZM(-Y2d:tGD=֚#khG@n@dD=hfD=h]:,&0peD=ֳUcF{})#YdG4#" Maυ8NG4cߟvBh&![T|hGDTr1 ϕCA4Ώ'N̆hGڢhrB dO@QW/ hGp ̈&{D4 ~>(Xy:MP]0t:c:U ?% ɷ^,Ȫ~R乴#: #zf7 ʐL?8r r”]ۨÉ?4G܃z)#{݅i8t.52 @8h< ,8Sl- i5L IUj@b&齢Rlc!ývu55ͣ6:42^Kjcڎ҉K(ԝ@m+(\ҲP&DU"_[T}%C}mnC(}(:XᎳQpAt KG~2n:nxnLoDv1ObUKFƗII1a`z2hXޓ ao ׿=e\soۀHAuf~da )E!͞5dW &'" jxl;RDV3@#aυgm@AÆ5BfG*t^`> jtzR1 +Q^d,s#OEkm,p*̎s#^ A33߇8je0p%ah "dOi& ,r̚T( {UFJb*X!&V]#eBPП~PQ:q:-CtAN%鴄1_fO0 GP0RVoCS/1+7 l#tn1S|>P4fE@G[z|E& t{ jCYRÏ gqa@w]tS?BQAYw(?)^ Bgbo8'vh:Chp09vv Nm4[/IdTg|ĹS6.G5_iҭlW8'.&ZzS툣Ko#i oGY@թ~N'|,u$^i-]bӺYgsWQ w#7뽹O5;pT{{(;R_a0/dc:<5_\ @+_NPH($w81!˥'(Jsͭ,"S΋o<6ZɰdJX򱭷^]9/##HKHDD[2~$Gb^SN|1A5Ir mRfwTd=8dޒ2ݐaSa/>[SUh`ywĻ|mb,w4KDO$T>"}%KE 4^4d[Ml?ej( uNϙگf_s;܋E,I ZRSUhgKd?N>$`weOu%ѕ YƦ4Ru /XZu V rFB_.̀`A N|uISm™Na|EC̓aޏ5X:~Jc`H3/a|1ot A0vS0fgܲv+:)36lftd|!Ogv,U;BnGM ɬFJVCSj:1e[9Qo(D]:<ǘn4E8`ANM,"nR\c,M# h%e6>Ù9Tbcawy^]$z"d[ejO׭tpkvaώި4vo_EգBE=$VamST`R:j E_iQ<<&e  oc}ÿdS*LBx_뿲t+WE羓?F܀?~:㭮9",&ss\]"" n~`њ,"Dg_Q `ehbHM< ^_N3n_Դ71ԫω:+yl.DuOB3Y#tZI'H3u9reJneD%i$a$6b~Ea4zAI,Q$?F^ (rďASv~|1f.Em)? ʟsP~e|)a:δ6puoz)5fXdǡ[1&fpcvNXL$9FC,oSEZ-8Dj8 {<'*V޽R@^;i@*3XIiati]6 Ӎ\»,$b- OȊ plwJJ~FL_ Rv{wO'-7.v GU(6uU̾z2/Q#\.ԏFg)oK7CQ_TNSRvI-kU(N+v͉b|d/\"OC'OpO.ےmip/zXwSCGP~H_@I}>Wi"xyjΩ`$;%KrJN7zj(}_O+Sp( "LP9N9rTuǮ9T/2D9 lnYVLC@m:GP^$ P սI T?'^m|-BH(P$BRO;wJ3B AX)e}vs ǙX]%a̾#RX07]~ê+J"3 ɽL {Av ٩=N4‼;H@g FU?oA9dܬD޾<~e)f|Y5H0GS!t y8Q*VPZ/~RԸ$^`u[$]:fw_=v@ i|MZezC"K%4[V`Hp85lC*~Z~QR,RKrX2ҾR hxW6'sW)ʷq=`KBUUSaأߺl7/Vt{(Ս<" G!ĦV:EߪLA`Z7} y Qχ5lE؋(#XUt\?(~.w,߻coRI  r{MHD)[Ҳd 8 w|ѰR,t45KV+&k}Mͺ+fnC[h%"do+ h/S98ALYύB\r c7z썯,ˏpb~SwY"}^=j͠A XG[/]']ޓ4􅯂~UaOG#;Ԍ&}H"^jwGuZ/$/{l%>W8M `!B{C!'CC:KUFVe5oLCnבam.2bƃSĽq%)l}Ś+~l-/6\ &Ў<|`;ECN@E~kG>&)ΑWdfvX5odQ)򪯔n&Mޤ0ժx s:U[0Պ| TjIT2̪,"S+bPr`W{EL`OiQVL "})g\  vEQ%WO#:s@ѾˤqA{z$) km SdZ(9KJ6 6+3@і: #T~S=h %8 g}?n.>F*;h-O_*Z%q礷/ĺ| ma8Z\Ǜ֊Yx}4^H)'ZQ"S@ Ҝj*x5 }sb˳G22\?ly&EĐ*릍:II&N"7,̨d1fɊzh:uzl`m,81pΕ5/2ad1P'ϗP6Qg Fƪŗz-9`i!ӳj*t>XEl5YsZ7:tp-,\x$cbtx,[;eb.U ~KnRܔoUG'R睵jϪZH)dZ\\Ud) $bapDViΦ,7/V>Kz5߁Y{Ps:A@H^U0d*V<ƋUYy FíT{4JrN-4=TpFzn`%rmI^ӜYHd0zj3 ss@8V&XK( snLF]6Ta@F5L%WNF @@#Hd$ $2̺k"~%2xJbRk("I*PD)$Hd\K("9'Ȳ건PD6dPBWf!Ov-" VK(b"-w("SQܰ@xwĥJGG2Lm\vS[NH%QxF87h5MTRa3Y wԊ:(b'.2'zKs? |=! 8a`U$ks.䣖( |[p\\θAGHw(ijD1)ُX,nMw_fx_8# L(60 CrR:qɲ[ i]i 뽷V>:5,JQ. mn :hPFȐ'֣f1q=UPIow SC9wr<=SMzם:\~Kr %dV _*Zؖ6-?*&:^ 7B¯ʻ|zρ6?d̓M֦>dR~~WۅHt6siI4|hIԝ3?1Ofj훓?֔2p;L ?JWs? ibK@_V ۃF8nttaG~t0D稅Wg38'cCI~;7F%YL7Eп\`]`MoQ荆~{9oaWG OEљw>Yb>Y ޿ͥuOD6YiZZ~m7.8Ս4$"3!{y<VM/̸}v@e2Tk"9lY/޲iJjGt=\q/-,--[ /6#eGPh &mhjhuwzנvY#[gC V',?#[`^8ߍeVd+?6G:զt>[lsAr)~8:|;3K =ëY ]ګҸKGvYi5#_D_}WUQ6n{nj`7关\V@ّ<eID Q6Wd8hJ$MU(m{Pod""pZ pEM7JBemOKKQb!Fzž+g%zU Z}HT m9ʔ?JьѶSUhݓ hERTk3*P*~i7><ԣ]/q}^6t\CjTy>[ExG : ;eb2wC_o]7 0{ipw'#@ #m"~Y񎞼|Ac|W)Y OVYՑ^g.V5}Ag8XկpG] u~'gDO:x]/ПU`'t([=}; .LQ AkDGŷ?Xb T~'^-{4.l "ْ<].-wՓ fTw籓'c-In:NG̟StOtM,M>P&Pb1! kV`–՛_Ֆ݂︛^//?3@>KH4}=޲gOOOSkK郋C`ݿ9koAv2t_\}A`̪=Vb@O^s*=n`ѼmV.ÛŸj w2^}nOt`ePd%PE?҈?1!dUX]R~?~ܥ xᢓ ٣J %xN D^^I#Z?.(0+(1 _EXTERNAL!'o2=8o8r9{8 DAA_CONTEXT_SEED8p9O6VD^`[hS a6f,h k"//!= SHA(identityLabel || privacyCA)m888 ގ=Ьh=alPubO ߯ӳ0[+M ,5xȕ\ Dn\xs1 X <vx%??]FLAGS Z"Kr x\sH~OUal$}v(KBaٔa_wπ@j.O@3_|_O> #X- QEiE"*C(EblbkmFqINZxe2J~~x<# < !Z67Mo0n(>}{ ֹ94,t&QFdf;cn{xZK𗻴Ᏼ,E\ncqbq+3V`y90vQmzi8p֞L}waVfmSgFMi~'=5}[qammez5=(DTIZE06YtPڈĈLRy&-5`qdFD2fk6-sfc  (tǨ_&Yt1Ǿ&CT8[j<~^p"B=h?Ɉpm ÚA4u@IZx1kX+9:y8 m,4\a]4KgGҼqG)!ԬvƂ_ {^Y7_Mg`3y+yQ!J1ޏaǧCC\kGc{w h c >냅plVlyN^w5m"-*[1>iK҃аLTXe'$zM(7z l pOC`7EmF%/'dz_3f9QZ #+"rQFc11D2EVb\&Coa{=gZ'oVpaC':.ED@WqYC~s,/@sl P&\ v Y@1(d'm5)lr\hJ@p!U#=CҒ6uPXu]2~c1I]FlԳ{- oq̓BHj`B}9tBfx7u.!^pdfBAa#V@ q܀J^E5AjOV5[ N{t)3aW3 zs.h˿|jkPdl2bpLn)Rz@e "J.-Ԇ植/ (=LNL0Y{Vƚ"|&"RCd$̒4Q.꾩bIOz.KI"+ˆOZ8e(~ò Kޢ:SR za2v5 Uy"( [YMkZ}Q*ûY jhiWx:x>v}p?1 |np"'Tmr3[+CG{0%Jq,`ä]Ϸ!ۉ Ma,Xk߼ g ~H<;ˊ'6B]N fjn1F@CLC=ÞX EckFхg=cSY@ЫPd@K⑘vg< ,;|YuT|(Y?6)]F&Qa hf$&xQ[Ƹ0J,8qZ^pO.QTFJ-Q /!&ih]g%zVa@FcѠNA,|? P#_EuSҩQQq9eF8_9vdHh 1VZ7s L=]xSٴހ"z{t:vt`<؀21cdD;6xc[$gހ@G;tZQo,5|%uNjRTKm:x/K"=_QέO9F,"3zVJ'8GfE`ܦuaCaʬk/dkr)iDmZq7SU,xFY晫g^LW=n*,`Ц~YCkG\9 Pɂ.'̞Q5P 9>[ *GQMVB־V<$uQ+a(cB ,Pһt'i]mS>0deθQ22"% ?P&p71- 'k/#0h=aK,C$BL.BiZJG}f\+6cp lѣ\2y z; 2{O 5|xn4 Lz ZXcZİ8z"i!P G$%c`?č&sbNυ FZ ^=&ڦ`=?5'SF\ *ft {Мk"mFy;k <_k).E$`C=腅̨6xڼ^!3ʇn y`X]p: {p8*v|[%O"y@1kL2C]tJ`p#M)s?i=޽.XB['ޞШFt4]݂PQ0 e~JrPSubf %X6<; *ZH[ɴ2n w;9O0s:wA^_AAx!xVS;aB3<|ʹ;v_!]d^,Xl,` )_F %k2TqEG}0472Y@g*IXrYd-na1+01ULB^M]!cMez-/fTi?ifa>Ћ*̰;7Ui X ui᥹aE;IHEP- -¢ Ǡzc3}i~wi4B6n7[`F4ޗwwZuc3ߝB9x7l9|Qɫ36dz}I8E$ZsRD:.itgZXxʹ(٦9+ƒw 0C̻tdu/Gr ug2Kv_5gΗ6G:JfHsEWݰe1Zgo_k1`gG}]~b*Rt>MGG裏Gt gؚ :˗d]|8%=MI=Lg4uL2`:]Z;"hb"TYݛLU#%՞#yvtⴠי?;\~TOQ@­)G@X"W|T o:fMrl>p;7,\s+K796,ؖO L6"nȩ4+y۹)Ys3Tlq|uM8x-9KB[^Mj9a<}q^S.ۭ pfsVk;R27r5[r~S!Q-!Kt*ĜyFQ?wAҌGq\yJ<9ͱXF{>Ӓr}fA\)N(Տ;s.] c2. A~j0 pQ~z~5PCP7(ʳ~\mh~{9|pF@$%58A>[ƃG95^5sW{ݸA->UbVQ<(?["|88H9-]-)_(LRrǣSę:Yzt ́T+EpTEK5?QB/>k̘ulGK-gHE9HSvoq0t,Or-rjt, 1s|<4`߲|!38K!i.ÐCSXR^{xPpa省Xc8?⠀(rsSr}x{;EIw\"z5 E3ٞŘ")X~uX~ǶA:[]t+_ñ@I9o(pc63lYmٸ S=McoJe7?M BXnTA{nB{& tA5d~.eߩ~$rʀnA 4"2W8+rLzP%ʥ+\=ԳZ+bRiA@Ыlj|:A/U{ΫHbx9>N>8'{lM=ȳr}+"di[ȣ@>΂(U_g3-F A 0 kbĪ &l"4&_5*CoScy{ 쟓naz*] C#M“J&t@2Nϲt <,Nip44C\&j/E5-❣%삃+49|*ڞ"|/ q@#9>==4'uZ$‰JT³Km ͑7&k53/ؐm Nᰍ!Yϱ2;/.&{N&FA?nM|'{.Y YTl$E ܼ6@# > 8J=wXM Ɯ7AhV*P)yގV#\]MRݛi=l.tCgtUԴ{}<~-N c =dES,cx*74; wy0NkIb,q"ќdP~Ί&萳̇Vԇ$8fr>$4xwapo Q uR|,rrXAUYʌP'U Q?B&"cU.5O?=XOf=9i aJ{[d;+m y̲?5< ~,. \_1 #{kxݚl'?o&&9u*[.n(9%O~qNYWFto:~Ds״ G_Tߪ"JB[zzS5/.M x#\>$3R H Oԙ_?j@e=d ڬaU&#k3Ko%5Q}~ag&pǽsu=e׸b )2j"{ۆ03 cxC'-ꩪDfq?O.Z!wu8ں^ ^ip{5ʊHE7ja,t@Ϡ*Ip86K͏ae{;@re`m1j'b_@16И}MQįAf |E h/{N ,aq)h.{F/_#;&}]csD*'j;xNS':ln^}n-B.8*TTіuh[š+0_XV3T_>]dk17]t3G ϵx  h>1S}%f.M1s: گV9.da? N$ 5JJ`bg;|<>]V-iW Zn󬥯Z6v7ſ,<}.?upWSzZ6GzIBUxKSTZC2++>e 9wEAy 2I +n1&$pV\ o2~Jqi+upyKAG(_׈$1FI^XX ITduڦz&@,_!fLO n*Rp/- -(7 ӵ^Quht(U%;b7Fbt t:'u־AiU[9ZaVnkCۺmUKI(Hp+x5v0=f? ;ya''x _5E/5ZAOv]YJe?LE RXa[:0\T87$qfAKVjCI t[,BdGWZEo-B_1EGR%G)6SiTd*U_`hCQB5b续u(Ք*˗PPGМr }7X p%,P!Y:.ЧLl=jL=rc̈́:qp]+ Ancתo^ J\+ Lճ!44;ͶGC?9.xﴏ>|,OO)`G%iQix"RaŠ@ 0S\NAaxOiLb01Fjꡋ.#qә2hA:5n>,xH%4x㵒ٍݰ{3 ZMyR駏 C=ޤia@RTB]qqc1A1 +T)7-Qt6Jwř)b^oM(ooBہi-ǖ:o5ɕVDS:,%Kha`nMSVi2&E:C*t<ī⍐ql.r/z0 !:|c5T_R\fq18 7˖{V&k(Hh"r'6JJnm[;7%!mҔ9}w7uby5XCɀ`k]8>r# G1 !6.p]t42DY{\Gqho_Ůo~[BnDXۆ_U6E ǚ;hgի1is&J Du4{)h_v,ܰgBoO2I.|N8,_uwA}Mz&d$Ir$ S\,ӦՐUmVjUq\UEԪI=Ugݙ5F坝g ~Y5fiv~:L#{^%;8;Wf<6WbU30? 1RL!W) ʠ<, '&D@'pbj" V zJ/ NS.hçzJy2k*MnJ.(;zIgVeET0&>I'+HFDH^@Cy)3 $X,]~U&K.5Ɩ!k th@z=IKzp2zw88dFPgYᯅCɪ^8Sdr,}͔1cS㱉H0xɪWԃB5!/AȾa|Ѧ-@WYn6R9.3/l.Ų2eVׅb$;_u](ϗac"r~UOe:S*LrE#HX#lL($D4=,~'c)GU! d;c1;'>v~x~8Oki+eEPY8MzDa6 (6q4f٨AS(htQOMEF[քKnCO,MZ zm=6:c-:k{qevQ %(;OQ%g%aG <mhT|4iE&:ׯT?cm]K{,VLAh fMMymڛ` 6Sdڞ'VE?Cq(MN F,Uv!yj׌ޞdX8@טS{m<Xc4l.l F|6M&J(qAE"$ud]5ky@Æv]^3hD`hDW}ctp6Ѓxpb,?LEFh&7MaK޺m:)0iUh?{|gYR  Bq6Wilʎ`̽\B>R3}]^TcgwRwi-pFy;+d{bm q#13/fPeH`R$y ̔+%#. 86w) `$a8ZP6]}YnaxYIng~Tɕd ^p~g;<&x6UH,P/D~3E#|k$EVu]5"nA6T!!6d}VCkul5lVlx&PQ;PvƋ.ww5VbPJ̘mn_[ij'}>)&zd}mվ |iŎw7j-ˮH"Z9fDQVgTS\"UD'+d!B\ G{vPzq&MJf!MdC 3N' 8QQ~4J&Os~wkPhST!-VVb68d~UX)6P_js( *ՍHd;3*GQS"\!D7Dɒ?KQ#T>4"HGb$\]S҉^(k7Vv|&5CQM&$ІMޱ:ŋHA91;k T׏<5x([Ձ/\[|z4~_VIpf΃GO=HLrI.sʦ4l'A]#)KݤVAKTgۡA׍?㼫bՉU+l)eS nd<`iLo!I) {'=$~oT6w06WJ\-.p ۧt WnC|7pfҩ˥`(X)g~uq}(|)~~K \CauA˥l"g/o//Kw˗L7G>@|ʳfʻVUt#r@فPeJ𲑠,J\I9+mⷍ.k#>8ɍnxU' ۈN-7ܨn5\ozJ AIC0nv)%3wLlKs` 50v^B`-_0D߄=Ax+B Vv[" ڬo}Wya>AP/:A ҋsgVZ/SC>~S<'pLL>w4. VhYqgۏai?c qߢ|W t5M?(tәx!Oc pZh|01ɡI:Όl ٘3 pc߂hu^X8phHi[#ETܯ[?1Cip5ҦŭRNV3ax3#껤`~`! MF?G s[j:}c- thv&HyPދbczy_tzEɃa]MȋA;ؤh+rë`TlE^scj kAj;>|ڐgm㼾}ztִm:oT5Y7uha?Cg}2d%2`=.وLc(uT0(Z:WF;RѠh sXE5hLd ɍvcLp:FTt`8 AC,hFܴ*iS-,` An_,_%גj&egrn /&Úf],8;l#PR}9ڝulՔљ[?&QzztT{O|쾷s? ' rBhWE"7Eu]w0b]c#-&[ -fݰ:1`A~UhM8ߑdBhzN)#@ ;OV#8%hĊ"6^rxQv-N˦2Zg:I^)ڒmAڑ\9Sti]u{^GԟPG+ 5M>濨)liaRh գ@uCcfoV(nx7z`#嬵/ d;zt&lD1 rZf0TU?l8㆚F% g4P5͗O< )\F3E@:ӽF݇c2dT(U~GL+WﻸBGiA :}T5č$Aq8Gc@u|Ps`6jhڂR0r 4z[ԭ{ꋑ?say^D鮍 U,J!kizJ7M øB Dl#Yhf[Ռ 6ȇV>q4qї!f1ѿOF$p'ur]ot(7"72<&-,7LA3@xLE7qLV8?tuaM##,enN+Vt]ӥRS%aCVHo=~oMm199ͬ3([$qFYAlo o-o FdNBRDP^ųu ,&պI)EtH`x'={2U*cυ0<N*Ȍ3}cST@8A|ߞE!$k;xjF)Ze9ݸ[ 8wEU-qOel^%-ИЌ0gށyv}eD,#WK[IZsʋZ$zz: 'TG'ѹڽy;jl#4#k* .]}f.spY#/l39, 37pbkc5Yj,fP=%h4XY^@e`ċoXQ3U3bI 蛒&5sf78FԌHX9i**Т)&<`!J9nʷky^}.t1q7qUָEsIYx7a4S\La,o2'`( B0xSHqSHM̮aA18@~Xc|pXTNX`ꗎD%3p^[ъY-g"`43,dΰeCԤd!\ڨjvSiͼ(3 YdH Gv!^,C4SyGXz?+,4.d}K6 >n lY_|od88bf <, a+VkP4zc6IQ#, j98=,{0g8vws8g0 'A޴GhV/xzo> 9Ҩ..^}i+ e{8[pc͞le'}^ޖ'y"w36zkyA Үӷ :<W!o(8)>g&@}JV! XEoʙL}WcNuC(f\v\*Ne }A`e)=2*0 "FE:լɛa AVfj"Ou/JB iƠY*F"RLiC .L.,I4&ݩAM!qLVq.E-mV?uų-L U*o `GE_aOnTZx/\z^1w ob=&jX݋s)ѩ>54Ytv 5J7q0"K%Q;+pt;S}[r#~4,_g'q!XWaϏW P᯷wdVAU|MZ6{?$m*JQtΌk Ruy +767,z iZ{ެ"i'NJZP]PDcZ$ේ#UZٝM͘qńSԼ.!~ k-ât7ɨ(i\~b#}M{,d߭1o%8(hG|G%g:6g_@X+7^}\+w wtw:,48ΐrR=Qro XѧR_Ǐ[Ŭ`kg`dh _RO H|&/ua}-KY[$z!ќYSd4c17AdX~ : A{Rx'=0 `gC|BU|r5p{,=-" }K'a{qLB\k2ت7fl?FLaڊx)k5in!ݯgPFitRJџR5DfJI_k5C[" [γn hfPkvo)YU{ͫbEht.@>4#醣uBwޤY뺴J{TIwv3_x8.sxe>~ |s>SZ]6qh8phS#q#FjljWlXh{MNιFu!-+NM4<]˗>, Or5_Jk oxZaIK6pZ }MY|z%"i'khv\^jF Yl7/G Ei\C ъk{tp!A7( t#aqUYn{ 1ZElnJUz 66_w>_Բ=v/5C_dJ>F-b>@\e#c1PU+iʎ. [v 'cODXO!sr*e8H']D푰k%H@$ہ, G_qgowQY뱽N grG& / y"z,[t-,V)% o%eFS2G0C e;Ɗb/l sI8to\ᆿ⁄, cY\3,h8o ?IO xo.gK{h ȯ!n n@$ ={6 r) t׆uhٞ,1RB iÙ^0.s w51א~BaS@}:îYm0FήHj Wx;]}!wdޜкWRBUE͊aE^;,&Vi ijc׽È!yȲm{$~J|JlG  W7fcٍ:nW2\a d~JVEG;axG>79[=ny-.Zyp4Xv+BnN\xcyoCՈ@ތ]ZjDp{Uu: eeYk56dt:GvuSn4[SZ 0칽iKK6>$<9nN_7vJh%qγÖȗʹ!puJ{z%T?U @ RAx#\f)PV51(3 M= Pd.K( 1 /\9^_GHO@dewՀ) \ fJm;9C.`I=SV4bݸÞ XE jq?pf)E1l4? .Cab1!8M}l0&)by!`Ecd2h"ziL_aT_V*WYQ*̕6`mZHu0yu= N3 }T羺LW*xSKz2ݎTOYߟ>Ri*?"@7Ud '‚eO4 CB=Tt.T*A)2nwɺ~`{0Mtl-کwT@Se?sx}aSe?p#))⮹Q־*L26ëvB*{7;`$Jʑ'$32mt@A]T2YԅTRJfȄD%mty#N:ՒAF.k^^%I/LpC'^23CRt d5Vq!]D1y8+4b40W `*Nhm;&2v3*iU\t Z" >J0M~qo.~I&y`edÑ<">o.)h8+SLL ;yT*=yl3عp;v87[{~5w*GobUmU<'/.]Qm45 SAUqFnB.iɼxg?69˺,UIk_.]BnB(~>3`ț#I®2#7n= %4I2DҖ꧴.* xCPB͝f eC#\̙Kch:G^F N$yG >Cћ63qf  U Px qބ $5BCVD vR^ \)5KL$liZI8-ɦ >5/XhqxR. &! DBՉ%\9H"$(R(R*;xOJ1\V ]!^ds;hlY L0Gǫ#{. vͭ=L3kk惲,sWODh븆 e=>a"HQ9N촮bԀkIM!)pEh{v簦GZt Q]SÚ&6=plrgA~o _qY"I:K׈gkN.ྒ}zHR:fݰK,`_$CVxF{:)F"OlH6"5lQ`.I=-^ ׎̼%u.2zj9=_It& zeB ;!Kk?߇~M$&҇=Q4]&Rh8¿]HewDz‰j^o BIcж YxCsE \v W+pouv=/#2Rnۂ$)Ir>1TxvJ2h<ڭ k3GE6/_R v XڡҲ2G?h1(.rjN6Pu˘cRD\p|>OjfHģK "Ra.K tpL 60q piS trCѦ [Hd|?DF;+ V sNG^ FMn3g T״BOM\j|ŒAYDM-킳}lDncͥnucQ0h""*&تD{E/[NĞ&vw:wƳ Ndz ա(Wb\ꌵkYz Xݾ~b,rNoQz anM}=bl}[&jMʧ&],Ctd4${/w{-snݪ=d)sD/:jB<*2 W9.S#'`\L*QVy؆؊(3BUU!y" 3˕IC1'GT5X(9eI03ٔ0'KVM r+)eEռLͺX`04|QA`3MihǶrjܾUg]pވ8lt>lwQv榠"1_pP_B_]σIbN4֒ l̲N[бx>U N2lܢcѠzu{=a"nd=d`^p }|uFmpz;7hv1EL4QFM)*dǍ.%$X]vPdutb|bjKsh;7gMڻPQ!D|fyt<:Yҥ*һ UwIsP # |jUwfPȱS7htxj-k*B!kl+͊>5i'Iqn)9C;2JT hl,Fg7'bz,7xNHU47v3)˨]ӛ=ZY,PKBf1Ě0%ZƆA"c%ɝ ڙe9xe(>m:^J#e,kzuة9r15+9 ,%ɴD+֬(E ;YHNGGE8 Fhtl|,wj*+W7.\Gu%kҲ`!D?<Hc р`tX6u+/#n4i.gz$~e?P׷&ΤfEr6TJ[nmif4ͺ$dפ:Z-J'/t3i@zzuInCQNDHW; ?y~I:4i>޵QQu Z'|Ksg.Pkidx48 5TCp<#Fȴ!5ēGb,JR2Kʊ3TRޯgC= !LxԮ%ZIA"X'(7F6 Y")õ͕Z]GUF|v*MrsxI*w꠩]0z_%\zN@`-\&h1^Dj-p.5`j+uŴJ/e~q0n9uXSFuB,p"BtҹFF34C.}l˝5QԷt((Mpl35:|R ,thNH|ȗf̭؜)=s]#Qk{ ˿gSݱs)?TeKs6>\U/б69gy8 gZqHsv3.!qna IG$B<Wwpb&{FףsYtnj8\}I10: 96Fa3[:~_u| ^-!ȧB5Cv]j-Eư?_Kd.(tJl I\=:z_v/1J>b6 Q2KǦ '^qWlpU>+v6a +v*'IVЋ57|5Ͽ= k2%. &7Z6 vM{Ǜ]؀Æ.aðZګ* o`v=r.E[p.O#%6qަJ6ӱTm @Le<\PІɰ66Ĺ/zb\>'zv U>k.'QdmiR#KxQeCg8ªmNx\n1${ 0X(Kj:px7n]ڶg~[A ϑr:K4Y NUuCfH:]t#ReCCE.hyD2(!U__ yME$L` #R1H mmUh6W2(W9#誰~یh<xY&xlϰagwA|9,rj0^3\n +DSAxšWR)к5J n%x8< .7OY.5Q>x8\ ]/o&yrY c n#x{?y\ y7^n7/5nx[qU r |4*1x[qe r{M# UOx[ rt7KL# _ ͽgxQk0KKID힄%f(V>N[U!`YVd:yLTBx^0\H8LJ|<R15t\.Vzӷ(E1@7dD)[ާZ鿍(l7Dt&K &QG8l:`}Y؃N0{R8X\k:Av71>#c 0xpIl?Ȩ;&FLd '-ԉ9GCYU΋0zQY h͵Cq97k0mGvλܤSn-@K$C|gCt8`'%KXfdͶ"Dxl؄gn +j֗ w Tn)zX8)2@1y*1Ё-ˁ9ġeڼNZ2혾nV`ֹV9O-GҰa$: [{foc#O6`;ֈcxop9ska?[ xsC_K[KAa"'h#?1FK_b$RLKIMS qt  xa2#dMF9@zFAb`3&k091|&]Lʲ\ʩy)i `}}܂]C&_bRII ҐOɶJhf I ssˬ< Н/P:FĻMeQ\V"Px\mo8^~&izq(/dҢhu%$gNJ5&+N@@|g3Ig'?wa8vH6A諴,w;d, sugYw}"*Jw5 mzߚE6&* :BX8)J] }LYO?hxw , !uJRgf- + B$ [Nf*фaTWZ4tg'&eޞhLpvu7b_R n~8)Gwt@j ]X]@={c%ƵqBpj&%[^@O}$1[UB8|!ߏ~"NWDTU`{Eg?~Ȝ+Ǩm=Du=:KΈ~3}燐#|>n1cA%)Y,pȗVRvp?Շfg~]>O h8p 1g5N2ƏdDߜ߷$ْaZ $@^do]IYg35 ^ꇶIg锄=%k6ԧVK(p~Ak>\JNj -5dm+YQ߭Eo46gLej$ADdf~ 1Or!s|6V6Bյ;J1giꬎ*+Y+E\+&8J@nZӹUJwGy:1BK9\:8}2RTIJW\2MRyǦfQG9CFME/&ԢH=V"d2qN_{VHC7"RMyg8nŇ!%B a=z>\w;(eR ׭-]m} @NJFQ*>Th- ڸQ f~f.FfbbS5ˢX^zQupf˒+|1xhyڽh-}1{-$&0uh'X8 ]La|+a| ؆rg3kD-\7HmW43zsZ2YuF".ne:- kϵZL s@@b<ޭ 79@v] ]t]]rYtX6uQQt9bcDv>L|Xp)"#!("#!tM5 ʟRFNA2 Mx^#,4Bg=ztK'I }nT>qk>`1:"[ÆAJ$VȌ!̉}'#@3Q*W8͍ R>4S\ldL ?vU{k:_fSS$!#MշA&Umx `' ?B#Z-UC| !#zٯ{fC(K4slc;֣ۡ ؀;Tz݊6+S3܁8yDv1zi%\4byQ+B|kJVaWJ\+ȉk]3TY&ӪMV'%HSf.eB?KiݨTcZ*@US&J\L\*MAQ T9&2|oG=!~I?,"/BX?O)Ujj2ϞeYW.0T;u6^<4CxBe..3 ?g=h%ڊ `,K+F*4PT V^ՓLng\/ @Ѳn#[-qErQh+`˩A5|}į2!U{Xم박Q\rլ6]n&T(ZR!ss㷌.O=&{'_vZC|N1P;D梜޸VLͼ+NҲc_528 =Q{ ۮa+Qi !lokٔ7ܰOfF~@yoݿf7㛺pyk?`BرEйW=`>g j씗4gO8d%`; ڤ9^}@K8Ny{c7bx\'u<|5]@Lր-Vw=MKXv!2Dj۽ygc,RTտL&USoY\Z& ʮGJ&%үb0<){d˅q7g. 횚j1Go@e7!$Π4XA l$ DZt"W b7wZ<moLJS-\pܪ$pw{<&z7YaZז NqXAOR?!텶E0m bH_x#5!}ky3_La{8 w>fʍ ttxP HůyЀ'YW)xxj1iy9%iE%%EI%œ'eF4~#G ΣxӞ| v!^joD06D@m4oDPJ1zj{aة:2ƒ)L>TtpQe=`в(Vs"٠툻?kvWSH^:u4"F[&]a.]*bOT}'6uuNpEBM{E7vP`k⒬iawcږe..sQ-o=kx˷wN~k(WHILbh DļT^ lbϱ3 c2xm?O@Sn`$ qF;i =qJiva8<~Wq1r={]F b hEJd-㚚BM b[X=W2"/Kg#5!V\}ucDki?N/cw-}<ьSz$dY8= [1؏lK押 n>p5(^'%QzḛlIʢ4^xo)%gz۶1{jiRRsU}8xn807`Fb\!Jr6D;Du$w7(ݗIÑrC C)JV4-y <3vjKX8w; ?oOڲ"MoWHkJj6rݵy,iDuq{c}qQ@yO|hI5mRp&4MRg5Дp %Y>/>|X$qH~&.ۑF-JVw6+F<V=Y Q /ѷ;T v^FaHn%Q"+QR㢩Z,\hD;B Z&Ϲ&lҨ]@`ḏpM^R^N1u C9w݌'<-2 vA~}MdwެS (s$i͓"G&F/Tɉ  &Ǧs;PG1v}hإ) ֮&׵lim@g[1xNY&Y7[7oғP9~7'V6+vR,m$ *eoO:斋Aq:rity҅3qaj+w\@I"oHap9 ~hWjZj`׎POByt 5Z$91%/{5LyRVm8?:9h7+e/o"P 'Py YSt! P&>g:nY)J_To&g4N0H^yOU}sk^G=Ļ[=0]yb8NiEn&maIO(\M1Nbg)](.y_5bUI)+7]  \cҌ^vy _Z ݁:{|yܾm%it xkRSpGA7-UAHn\-xkR<0AZ('3$8>1VOoc& ji)x;T~~F.tgg^x;IfC,gox;Mf gx;pTzQ^NPnx;UjFFͦL(gx*uAr El*x*Xbf L#6l@x*uG|f˙4#xZs ֙ "?]g.b3ܛL&kmiNM>8>Ξf4S ̈́Fd Q&O&Q4m AYL;d̓k3d֕آuY,L7]rƎON+p ^p:ԊaXp<.N&bo ~B6/2v\;V̈?q|Mm ;˗8jB)O,=ӪQT= oWKؖn;˭PCp%\#YbtnRC7X407O]wMkug^Qx˥C[8ɀD4I#?&-~Ħs0#:6&N,ܪEor9֧2xfK?|:'|'o&ǮqҨ^ îљ!mXɇz-cgC0~8u#J0FVGz-vkI4yle8kOΌYuhE0$S~-8ųWJ0t2]\hHgƸ} s@@|f9рǪF9e Ũ=0`Sf q.CF.4>ns6و7nWϹ:yлon ucoHr@\!doLu"a.CbjV5*-byʃfa65+DX4={3\g1TVȝ"ʳmyt#<?%.nLMؚv-bbl I5}z<P㘨x/h(zW1]7eaox~*LAr͡p\V`?jqù/Q1sz _ǖU>©-Ѓy ` A6\|DRZmd#,D&Dd3y"8[#3,jl?yyL440 t S@1dj zY<#F˫XA`?*'>F a%ZRې9J$ЌL[ gZv ՋVN"ht%z&,q&J4s"3iңxl9n?:Un}Le3l!Ƞ4aqƬ¤,%\%r"!÷#r=pSeX2h3ā 8B,%؂Q,N4Yp  c[9*༢w컗)BR~ԃEge*X(KǩYbŬ\gA0OH ku|w V|%ĸ]#=euy.Cu˵;b:09w+BYbcOE _}7ۿk`К\dDAd,35Ѧ,1C/DGL?l!}v;Sr =侹dY"a \ۑAQȦ'R$f&N3CğU ^WB1B ^4ϫvPvLU5zj"2&Tw%,;V)[UD]PF! TpRWsk9 gmq|%ڬ[6V nZ nw輰T/n` Jw%wt]dqPK֐[e%o% onpPd_ & h> jʹy W-{"4EX<#(&;rVuEpCpC3-&OH@?͌+Se1x:,~P^v͸.B(Ue !6Y{M)Eش*V{|4-'\R64)A@ΫӜ&Ff|itc~$[0ifg%<^vKg#(kϣI8 |X'^'$<9np^M3w{,0-~2zޡ4]:KV߇±Kdޞ\ z')mq͙ j"}kC4d:k۰fne>K-STQ,xi~Ќcv=@XJL<[0`9~L4fѡpRe㬊a^Yߗݍiu zo7aC/ ҉BRMGlOڣ20jZcի4/3$)s YdȜޫepVxY Z忲\^}~(F3Y}+?OU?{84-*.p2,UpƲ<@x300L]sbr\scn(gOBYŁpc ρF?,,k>}>߁dpG|N&DDKS]n {QL`<8 ad@³mB+Е+/2w@JyqEF֗k] N?1 _x[sœ3.- RK)MIU).IL˰CG*KGKK+AJ-*(6VLu122痖LckXNe8RKJʬjTfMDlx[0ufmZF#u*x.ed-&/ɳ&#,&(/x1 0+1}|gx[8~|%^k.POc#܂:242lmB}|489SRAb ɉ99:e'שNїV_GV!58YqfS7wOΔܩ1eAF(N~uzɅG')Y 1NGx{ysC:vF&ɂ *BNe0e&obs1WlGx{ysC:v(f!efx{?=zCEJ;&gf^-irdO0q̂"J̲ɍzO>BR@MZ A?x{;~S͉:=Dـ&fy`x{+ێd xvU^gZ k[uYgh<$qiNه~$rg4Dpd~yY4L:>p pz~b"T.x{ WUc?SV??ml>%SnQOefBuKӡQݭn+Arf*5} b` t Lݭ~a|fԘn^\XɥP?+ BUnD+ %.aч|_?zcQȎM sx*jS%4TE[Hx_xg'g55sckpB5y:Ԅ&;kl^Ȭi=P^(1Sf7+h3R`dGm5+6;ks1`8xku~2-}@zexku>2-'N 3M5]7d L^ Ķ 3x[858ؚ ]RC"gRx[n] dx[dCXaۄ/=]x[dC6\>sLټM"Z ('x[lC0kkPP|N~bJ|rQeAI~|qIQf^z5BDDO~Bq~njIPF!#(U!3$51EAKdBPSI|jQQ~Qq|ZFqI 956Lg;9Ow-,c}&oOK[fL2߼_C]!x{gvtF͇2 ǻ;989M6Yi23乒X| ) zm6k3CC|]}"' MY2`K@y؛y=E@+6 3bQ_Θ:2E[̼ %9@*=}&ApDr͓EIo| \@Km&3stlex;nztIͧ$2)l}x;nztfCi!wx8505Vo-W_B B; if (rv == 07(.SGx;nR1]lL&{;m.8y͙x i g1x{_ {ppGbqFViLBLkX2Xl o% *`"Rel=xM:~"{vxݔ[O0ǟOqTCt2UpŰ,ΡUHʈX9z4sTطm{$/R'RM6LGsc[}%Y?IJwGg)`E^vuO|8Uzh+0ƃR<AM d\L& PgU| L+.y] d`)Pf$qY a b)(:#&}"L iPA4;.~>)/^Lb &\T_;)t1f[fl~{tx״?<͵h(uA; F~p3 C϶,=r(v/G7A'85 59>l2MCrILl9F6kuWҰmp3|L{KtԢ Ы[Z]П=5XMw]=N4  ,r,XmFsd&xaZu/.6s q-=C8Zg3@zz𯬪+W2 %%*4y&!G䗀kG%a)Э6 x{ͷs\6#Ӊ '>W*.Ȍ/-)PRK)MIUP*).h2ٕd~ ̼Lkꬲ\E%Ey\\% 3&g*aWc*.h2ٕd~ ̼LkҬ<\E%Ey@Le̜\'21)M~b™VPԐQ\_ZZ Q(I-д r  O gpDrj^Jf)/>?xϷo8pf^BZ~QjzQ~i^fQbF4 EL}Wy\MM7fY~ Nx[9d^Fv%̌\7jx[9d^FvLrO|JLfQg \,xkξ!#3D!Ӛkr %,\\\hp Txk\>aEV\J%9zJ#3J23RRB]\BݹS|3RKJKRKztSRJ!y%%@}y)i\3pVsqrrIӀhQPR-S<9EBIjn5W-ap=}xk|6aEn92J2&0is;;NTY5 }AxJ@=yƂ%iB!K 'AAҺ Md#X"xUznU<,7B_>'{"XY53a2-Cerzg*P+EoAT sD&/FOKD1p(eF %-0|Q HȵTp 0ғ6ziCZ,, ^WS.C BT.l732xeBUSϳ63dQ O *qM)}IxJ?xm܉6c:y!7 @x[>}\6#Ӊs3RRB]\B'>|9$c:gfFzjIj^\6MIS((zs'#rj^JfRlcx>}(fqf&Woyxm܍70nac7fx~}?R'2kg祦(kn x~}C<3AQf^IB~^SeI" =x~}C*KN~^ Ey%i yN%3~ mx~}C T_Ey%i yN%3 2x;~}C3AQf^IB~^SeId  Rx;~}?RyK3RSr731 j{x;˾}?2clx;~}FÍ_o0%߻xkoF+6Pl˹ cPR#zPA+5E $eG-ofv\gvU=ةr ͮlќCvyvp,z <`Y3 8D^.1kܟg4إ(<+r|r,t<y0d0gowbAZ}xwfs1lOcyfA40?FV͢ ose6BOfi4!Gt'c[Qn̘ Ah:^dW8\wV"`ٴ2 AXX4DM gs `jUcW[e~ߞ4۝˛kwy=|!n>tPUVp#vwߟX[ B0ۓpnc^KW}1o;GNCZ$sjzk-މƓˋdX(}z :)8dW+ΐy0v|j cp7B`Wa؈ ڰG cK#CqUg%WijMӼuo>]5nڿ-fX92'Ō1N,PN4o{g+謾턑e:K@{'@t{h\(,9$?+-3@F ":)>(,:iePYh|aEV!>ԡP6v"ϓ u} E5{xحӉOM{T |Cwδ=xt Y$DM_8֗䅒i _Ԓi]jrbЍ%olieءK9D=-t/JBZ% ryUP`.: Udwn&VB* zx.LX6P]glǦ. d#y\lJ{B+cwE0q -)K158QN4feMdMgk@ëcA*{?L-&(CC}0oyZ&i}8q/i  p<'bφgh̙ǿEz`a] PG9Mv#wg`#%O1Vw4"a)?gh~4r8P[R2'3Dƶ ް VAO~ u"p>1xb(܁>W,ϖ¥RAbg k#ߑuQ!`Z }[ee|ivl~1_iOk`(6c͔-w(97>"LEMR٤vlO(m%=#=H6Y$$ LkuN?A(ϱU|: (=b*-2K񀤆Tʀ;NE/8FZĄD)B@1GQez]<" sI:WȥS JAr0؎D",fPdܼOȗCXF7-ABAOP2X9}۫ĘQFyV Haޛ(|=cwʉ!ЌTѣ1mef"(H#80iCT(ÆKsU@8nyR̩ a%ŒE; IFh gOm_Z>QGie`BUJe: zlg6s}2'%.K$&uŋT 8$~n9>S0<=X4ʚBgʥ6+#;וRUjEh~!'ąVMGi:^$ZVbnWBY|!B͇ͯͳW-^FN ܣ) ƫWtJBV%&3`P] sc{%4>Rn,`FePDRĸT*2ʢJZOWV|2?k!+B bvڈ"J$4 &2.(d*H U(w#n)fQ@zn}+YVzĊ>wruxa 2>YQ5>`_e{ġ;<0b oHla$,D$Ae; ".=HR"=\QV|7[q| ћ QDl ';(ށ`$ډ6>6 `˅_[{I{X@҅ *+Gb ۉcz)!CraM&={xo| lS0fњ }criw{ R8:gs}6}#yEjĺ,p'}G(8MtY1kH 8V+*4Cy,smn$Y )I%%LIdqĜq\dS@*{X i]qD+)EUeJexkܣ#{ q[ \=rk5"$MZA衻iq!ar.m6AgT]vxЕ;PC_{Lk}|dF?'l),UwEڿEU-q!ˑ$cA{@@xYwsJ|ܝu_ _aSz>9 p\ۜUlcq:vZ#{* R2.sO*aM.JHep;/W<*I)jm=EMږxY@e7('{r2aVEYg2۪hDdAQBY4ΟYť˴H!3 Ls)Z1}MAto=.(1a)5YFԘ:hhT܁uܬ/)莎'Ȯ;|Jzx=On㎒ky,Z }%ҜhDP=8O,G [C4WyI HV[oe|Vc+d~=l}cQA rX=Y,/uuk9%lY"Xi=7[^,%S5s|QQ p{n^w;t -ϱ$ɤ;?*K2U#"`^9zgic‚Z%X?DŽ͏̅\,hI]닛̊ 9^8Fʁ뇼`ak)ű.ߺydUwڂ_|iEE:EIW_WKI=LRSL{냴dQߕWxORawhNL_jgD@ ETN )#xzs܂O_p6sZ7^E[m]9ll>}";=DlQJ E0bf1E,JٕfYn:XgQzˤ|xv(er~Ogp5>P Ʃ<xd\i1 5>(S`aǥSQ*/*ILI)Q*2Ӹ63g r  \ǜ—c)ZxII9QKpFx{klFs&'1 O7YY stqAA^rf^rNiJRIqAN~:Plr6Y'+HrNcуpe'fe;ۆg%rx[9aĹu'2Mad..Ȝl$*]\PPĥSTR\ɲ)8`rdUT|}Q٬!\3?"Yx[3nCZLlܾ!>D&_¡ Ht@,5 ] "h:7+DRXDŽbfhJ׳`(R0ESTŇfhׯCS4((O jNTDhx[0;aCiNͲ2/r'$if ~#WcxRKhQeJ>IBĘ6ߗOCSTh1i+6Ri:ILLT+zA\+ "qBE.Tp݂]Ѕ /6Mq3=s=g_>/PRؙ]b.G4<u2 gO'+呁X<<<>#B5EJ7^HtDž5T:Y~op];0O tH`Jo*Ukh% 3VzF UG +|Tk8ҡG 84 *0BG4XɧewiemIU^hDuB&7+lٌZėި ~-~y~k{K`y33JʺKtE;0owVxoXq^U ZXѬKUg;xK_%JOMV>9" K-7\SіT&p;>bNbِ]Zk{H(x\|C[nr|bJ43CF3̢Y ,x\|C3ͳ"YJcHx\|(.!fgEk.b"x{X~|fFVɌ:of5t7XNd TxKwCfUUOynX]3:-3 lPx]wCfU~$Ogxa$Fbb %.̼ҔT͛/0M)4y!,Tͼ\U`  J~dlrM^g,! t2l=xSwC I,(<:#x9aĹu'2ƗTNfeRQ{ LxO.`60e'ca!D$`Zx{~2Ln`k &'+3Kd 4y# &6f@&8'rl!xR[A[m#Q$8xR1bf#=%~%!ީy)9K4xPR*d=aj?DIhRxR1b2GN~^daͮL-oxZo, EQkPLFdУm%.=S$%])N*`ofj>?h6 Ins+⡰\ɞxmﰳsC(cC${ (<&8\p6e߉nId-֠~ r3HX K '/V (à^zϛ_pc72]^\rż oY\a蕷nhpY]vˋA e- k'@&\=$WD(=AP^ZH2PuMTy k.\8䟐/ mFlɣ`)}k6p*C@͎س 5򯯮ڄ:'`e ym.tŵՄLj7l p\{͆[,Zqt9nd+˳#Bu;sn'wa!bP b!ih3H:l83ۊ1Fakϱ@E>.'tkTu('R 6XkЂ-xa=JzOfs /Aؓ:$+9/밉a3'ƴްeN9]SH@n0(@izf[ҥV4K~IBn8i v7-`9b!!qo)0N j"zAwSԆæK<=EP3 C1)2S#BZ!]99>|CHNCbF>_뵍rif!9rAOȣYyHP(ɱ!fU~48n=r"2bղܡ&ɶŘR(+**dbn n/CF5~`ı"%Up֒t7`z60ox>w杘``L&`;$vl{Яs:t48i & 5"R|rnu gCxU~sm؉lc6._J!+ k@666uԸu<'ixУ[P Huq7,eֹ:9u LUT U+ ORAc0 }Q/PfM%8wth܍ډM/ݢhAn;$܅Is?" @F⥣?{sZKׂoK4xnpmp94\t4^cRh4d}A#/e﷿]}ǾrOdX)&!)|Ju}\(*1~C-N(*~83d7BB[QkeçK`OA_\6`[4Yk챙4. vW] wJU؛՛7jzߪ 7 WutٷlH4dI]ES3?uwO*bOK@^ч5rVz(KNC:gFMW8^Rr2\1y^EQ]=\.>ǺX\SVBʀ%KpX1@/LnNwfr5֣ttzn_RMNwΚ/;ʉVq_##]5N.{Tnqyh^pY%/zE=dZt|+(R-cW6^%?D]78(鸰2ť7zmV( UJ&k hQ7x4W j1ij=9˙ܛּ7v{B@p7ڇM@mDu @a&8}ci'L6 /炘lQZeg b_(Lͳ5 GS1Ol:G(Xw%",#1q/.+R6ctڎ!ZJN9[7󑅋Ky/O+HDqneWĂ]򘬤2IŒE5ɵ,,ndih"(,%sɔg`6 yKb:Efxx|p>:)JIiCyDtCKIS2Ngުix:Y"Ez3?tpaˁ*V8 Gq_ jwb]'>5A4U݂㍕H,&n1".]smp)aEyy-hj6(xĵ|:-kTC5۲ϒfװ(V'C ~U¢nu. Xv R2ŊK60j]ݒжA|E܇9 U b|sNxgH!YĜX$Z֮jSL7dOrI]g{%Qdqs[e2!Y)"SD^PS.beT n3%h;vј %04#4$FgJWqB/F|f'R}N!nV/.%q6|ji9LE\%\,/ ?,I2m(@\3^23CVQad!j Tt-h$:37ݵZ:!`}cn㦢δ&˦We~t*h! s[YǻDRTL2k)9gnn ‡}]GkYw`Bnxoe׌5hf\Ĕ'Dx"r:JR"6!y #9닆yX8y*eK y{;[[{m>!~q.JGޮ~GV}U z0l.VLk#$458 &!T+9jXqԸ"k:ޜHh/NW '<_ Hpe-͐ѧ£ס3PE Kؿvx?43NHy MO,E{HN^z]/]YVW/_>IQ()h/إ"tJ4+CӢRT`4Y&xj\\%ɣÓP8y |ȪU)z2DA-.T5 fQYY76ṱoBMAO`;C=͐̈́wvֵBlhLBh]';n_hӆUSaiK`c;FnxOƷ9ZR$Le㈂%|l%T2}([$gRY`By)b͔wjBp4w I ݱrփTpq0vs.Kgzc kcbEzqH`a? ;Kx+y`ˋ3PxX.畫p27+ś{U2=D7+}^pY',EY^/Oʾ:%놦i]Ov68:iz4quܕVT܅W$=5# 9!lm--(-@ǀRϞ8뽔hs旬GQӨm{!;GYqkg7[Xl9VDӃVptj(hY-Sqi2^Ed& cg8z/(+'Z@c,*'B%˜XL@٠RbLC8xJ&a̻J!#p{moȚL;0CLrgYغ/4>z9$L/sXXbhcócAp_NqI,Pb;T-7W5W ;gn4MpC{ ʆOjl\{0J+6TUt$9*+hƓHI3=$>;r^~yD7.l*颠UZɉ)H,J+Iz AN! Z@r@"W03n6׌gL;3blxkXxh%㆕ʙy9) 6y)yzv1 /x;J y\]\<=6/gF Vx;\ |y9) 6ũE%2JSK2sR548" E \1稤)hhr5+KRs Rt|]#6W0ft,BCD'/au<}&6M 3':}]Vs7_Sd̤=me,72N(L{䗎 &OvR:%&8hOrIm&;9Nw7wóyEP.d zm3xŐK/Q3+!gg*iDBPъd7n;̝bi)V"'l|w Ɒs~)Vhfau2<1ZM)Ys/9ڧ!DU07eXRe<;'[a5XJU%, ~2c {94-s\3AŽ42eg?؈DAl%6|rU:v|7'] hɑFfbZmȁsF`Mç].rIʶ繞6YrL],Z8HMt9@Cgw K0runlgD6IU%"uX\X^C1U?.w:})@:xŒj@I(*Ң]uvʺVhZzgfwl RKY|ooJ/N-EL !ߜ9?__ߵDTX'A@~ I H2G0`$"N=ށz&aT7j+mqX$*62'A.V ]wym{Ozn1UίWH3q@6eV)bs'ށ3BT-כ#DIv1 ^ ;Jlꛪn,s.#:E-k 13' PSmPR ܥ0Oh;±@ WH5M)%qݰa/[a#0Z. \[K}=x/ &j`F|/ߑ_Vxn8Mj!kT}-\kpCZ]{GT8B!zO 7{)o|Z :J(>x{;\ -7YoNGbx{;qL ь%E)}C%% )ɉ9ٛ3f*kMn䓚^hr=bJ 'OOd~AJ&sO^;.eJze:ws=W\Nȧvʽ0Y|,J M*KZp:wwy&\aPMoTJNjrsyx3øRwnӐũ槱ԋ^2+6;TPdr&BDO ~Y 3sfu`uV"=ex۲qR [4 r'2O>c9^S.NfOrSU1w21!x:Ѡ(!i*!jt 3^)`2) 8 6&x.(!i*!jt 3]55$#x{54 _E'NA ,BlTx/jfV*n(Tkx;jbV%Vмxo͒ilk l.xu/jfg& m'FDxu?jfgt+/qHP?axu?jfgt+23m %xu3j*@AQf^IFZfNj|^bnfkV (x,j²KJ2KR&RK)MIUP*)\(X< f?\x&n]81|˙@w3\\@bf5a}"wgKi]PM|S.r>ǦnVZ|u~p.ݔ.ٝ4+j fgܒs5:!:;D+q5,JfASjBց-Y2¾ik)]p6Iyt:?o [O9mWk l0-H /?J] 9c&5 0y:X Id ~C܄={MW8u1ܟٽ<ǡ<۝irMSL:-LjqK S~ 5{<xkQj&V^[gm$vK.#_=櫖_X,N^X\( ޭӼa?|q޿-͒'vu.x.<%_,t"xEr4 u?ecD )aQOGBD 3M^;äREJi+^1q]ptysE@VC 4,O$YV|yM痨 K^M/^d5cjKlߏ$vWD~ݷL{c+P w1fp~ AW= rmsC(Pt95(xCA !UIC;;U TlU ,ZEd#76%53w˷Rt `iMU [v[L-9H|{8-uIp;<-xfæpA+{M(7c͇bQx?|TF]GItC?Vdm,*W7/6ynȬ#![EZڳXFCˡs]:"x#;ا:f&$]řl9XM=C4rhR *$u|ސNxuĢ dG!b:(,KsFhNVn1Ydž+;DbI,-BQv71# M^VpRӤ{^"ct Jl ~͓(Ιq6lDj(-$!ﵶϼ=;M.b4*_+*8=Ulj.-ޔffҩLX b {;TfE)Bj¢|z1,F#G}78 ᛚ S[2*h:_7+aB`4V:<ζʈM.O|*( dkْNvH0f|XD0®8.))fusYUa$:'<qjHݖj"X_@H{img ijS3P8v ijVj\D M#3(͡`42[T% uBbQ 89S4]Yr ډ>ôzH51Q[YЀ#&!]\Ö8+FLnkiCʪ(vY]--"·"Ԡީ/UeYIjuȍXU%kq"O/p][1'ϋ9W4V4AsPVdC `jUԓ^U*㟬9ơ "B9ןA^VďKQV@O](+zUw v+(U+W.V0cKiMmcgZmrF4T 뱺]k 4iKQ h~"sbvYҫ>PM##{S%U|yr~¨tx(bC#1mSlz px7l Yl,i9جY!ܛY89}]RJCsrS+5RKJR&+ O^ϵqd=jƕB&)aE*|bXy=F`^+,y%P:dpn>|iF0T?Y x7ql r>.IyE99ީE%IiiE'8YO@dd(ƪܕ7zdo9Ynfx7 j}Ԍ45nx7 6x5> x7Ia'*K~"~lϘpon5ci5SdBAiR|vjeEfA(4.[k.N P'oH POC3-M5j: j@RNԴRNKL<"c3e+d M>d3{_[Mvw0Fzx{0o&=nM/m~(YVZM6ϗgI. X'qS\>~Rxɸ}ㄹFf~e p r  t̯/y- Dn] 0ZLl%'g,(99G q`7b|ǐSAAa2#5ɝҢ$t''HțGZq+祂x 9ũ ᤢlk.(⚜,RhO[cjI&fGB7?ugtqrw v |N8+~I+B(8y^$"TTDKqf)hgV*)h*T}3^qY{Y\ْ,5tS<%NV0=0F{}y@Wx>t 96f#\L?3nnЙøy9 m0V$@^t6_/8cfG'+͍a=&g{:+agx:t &iNֳW<`s}! nx;ql -7<- 7H1x;ql G&4|CMRu'ӌ v$x=ql &*' O(( lx{RujCobNN~[bfNiQdCN u6Ke26|ۤ#X=x;QjCGsck ;>POC3Ԓ7PրRMO(άJOKhN2tGl2y<[k.Nf %IiiE: ZE%٩&L^.gWL&3N1OׂK!X!3/(575$5EjkAiʒb ┓>'Tm/* / x\[s۸~~SH8ٜx-Ygm-9sR,,)RKRv3ۍ$'!qF7Kvl(INCr48':K4+I:%gPYi  eP2Bx3Jƅ<*a s r/4cṛ9pf Jf=r.wNM( eHyLR+9{X%VZBPPnHЌt= ;x^2N3JyFx^мҌ7y<Ђ$Z6Ͳ5LH)r qx@r&.(v‹# A^tjSW9fJ>,'|IfQLIW"-\xV [W'5;%>'zgI3r%U:?MCyޏ,ͺ1 6F@8?ޓ^Td)$O^Hq ^GTk-YBvb6&(5|(XA/ ~C&bX^AڽZ޽GuѲQ=J`zP;JqMB;8 AA,B*Ɵ\ ?C2)^aJ |.6m$4{FO9Àn!ݣYuNFp`R{"CEcMWɎ( $qGA)@WtS !hM~i:JE$NPzK)nA`H0L>S1ȟ"“V8xX=r65+lwzri2?ӆyɢT@{2G}gri:r?T9h9O64ptu2x& V 0fG ѬdzrhW1t!,Z,b*.RO$GEAM1ֆ :ÆP8 d7"Rr.uF |K hEhY..oOWCo<nXR"-=h\2D"8F8 | M0-2y]ˢe|؛ dɕL(͢*5m~ ֈ*Kc!JUgҵԷ8ո ҪWvVm'y| -(i3UGZuƅ%#4ƁPٮW<Pf1E W1bYhZ6^\IH_eY⯿-*WUYH2 +FHt% LiP0E0CO(Vn0G FEuDKx!2` c 7q9Wx!j_fpqpbEKڣB+F6EcRsu / JDX2FA5Hфpj 9EM7-4ENGBwIFT c c0ͨgP׫CWӋ@p".,L/p., .uO1,f'54]_yuXV+uv!f|BC9CC8];:iɮg]@V2bQz0l?k#_kZ 47 U$냯WCM4uX%'K+ٔ&񩢕@_t-@X-!՚{Xѱn\3MV.!X%FiV -unfdC7 1 ش#WwQ"x oNy\T3J(w$:w0aj;Nxk:>uwq}WL=eNg7$p".fW4>]&52@n$J)T!&({~a,nNƸ -|tadXl,7R;TЋ *Y-zZ ~N*(/hBYQ6 ƧJ@ !?&W 0Ow\*>_/(8K+PܾgEyO)C+QP0_}7JUA,~Ji>Y+'f/WE J>U1XJ20O-;{kLfg 8w{Xv>0~OF4ogYƸ1==~˖=S`-ЫOˠsW~[}N's~u Q-%{Ś֚I&U5{#h]ڏ2م՜$N⧜`@؃jؾ[q0mx:%;2Ьr& LK&pBt!T*>wezJU4*ʖ|jzNTI9?VrZ 5GYF>:,+;Ι/4 %kX %S]f.@@rA̢G\k%\Bڿ1c)^f@ŝlBdaJe×}QN\RVgEŇ9>boďax׈WkNcPO!ӿ=ǎVJ[`TkXXL6D,FL!Bk)6q"[Na !iѿ䝰k2A}ɕ^OWSID5P7RzHO(M"Liv/4XTb Ee0DNz,aT@˜q*R-c`NXY]PZl+R? H4xX uG3?JU+b8p'V΋Ѯv=yٚ uŹ|nӔLigۋsU=QGn]&T*.BfTfnU#QS +ֵ}nc` E+&YӀ.y2c[+[eն9f".mj"KŀWPJJJ)#ԧ>ᄝR[AoWak-X "^3 S] XtҘұRlh霰pSaݖzrC,,xS"'?ϊ <` W uDWZ\"=-u;Z׫=GA/J.QOf]xHhgO"˼? f_II]8Ȅa{2Q tNϝ$[N: 拮6rAhbK9e=}'If*,/WƘgI" dV>&N3Z4pHݽMQZ S+>9{ VĮ0Jc(]Wc6C`k+wo`{QN)x`%D"w}\Q蕫i8 rXi_L!A>Ēؐwv!7)\Rs#0c+ 6r %feM E 14G&SXዢ9$uRulmYNIgzOh5e+,T.>уE0Kv&])3OV+6|nCR]qqSHєoǙIКPXOM,1{[TgI䔇xn UPJ|XR~ɿ,)#U$u%;ymҬ=Ka=cv|>Vox+x_׮◨`frQHb]p b dcTJ$)&~ف>ls[Umi ,9'#  ~jX1ӌߺ'}C^]zQ5LHuH b'*Q^!ʀb=: .FϚjīVUR[w#{wJMvr*)d8v́6>Fu0 㸖n/0'{T]W—kd֓פ\^ieEcFjsT1zu!kVGgx/uXO?^F'={"St6ny}"tLRMdFD\JeOzfuAa#JT{TĥRI:VxAV?. /Ƚ 9[%2/e#txx[ W+#oX* FPӝP7\ j.NJ&JNZxk`ɶt :gKvmR6cХ]M]%s7O >x$^%w?@̋4i$~>yxxl3:؂qY(*RuYrJNKWyȆ AUxB(YD%A?zIM0>;nڞi2^S /#Dm /a['h4[b6kNdroK7ƒA!0>W/hӝS/02v!hȨ^:a.G۽ݺh~QfwD64Ow4Y(]Ei $DqtdeX 2sL3Iuf]+aȼw\ffI;4 NXkb" ,q4|LM\f1wqShY8}f$1|NZ_=>G8N^, {z]SWYhu52J5_SU^IOK #V.#~`9!dԼ'W3d)hl6 @=x}AkAiI GqiCĘe ݝ 3@'w՛@;xQ͘bH;;ޛ뽟`uz}q&M6'L.YXA3} G]PFŴ6hاUx|  Q o Y;Sf3[VFyum8nRnuip . l):PYTJ*BФIq$<N\qHÿT0f \F&2mcta-&϶/4p='"raj뽎KgUc3(.bSڦ[7u#cy#2p9 lfY1w5~?E:p@іKl#Fmf{~C%{AvpTG?e'ȇK@Oqrwzx 3&Za|)W|6_I>nx۷q| "8Z1&9x{7< w3SR&?vN儲K&Gq*@ArMyfQ.C\6_q x{7< w3SR&?vN儲K6Gp/+x{7< N̹ԊsR47uŰ Xx{6< yf))Eu]-t zxX]lYV8m %M$Nęq? Erl'Mg!x|[=ffn[ +!^t">ϼ!Ve_Pقľ !ν8fs{ι~ñ_w~?sńkծVVWnEuYscowаt=dP*@ :QZuכʙ3KD5]0&ku'ϱ.6*BW=W|) q6>Bk!n5:.2Hk*v0'X=՛1ʸ,@vcD^B*`;& 7n m5:0gtŒZ%J?%*ĥwd)Ul 6+:F[Z~Tw06i$9,fqFUVu)m]]ajV#Q=i/ZDDoݢ{0n[tɨ $of@7bQ(d0?}N< :'eskd-7yd>C>fnT›.ugfx˒'|aOeWRŤ`FT2EL$ ~\[XӇڹ~V8ŜV@;! S>7Az31rL|P"o ym$\#)z:~yr2\]^v/_ oMLEn-TioR+!*2b$f+ <^ /fg]V#qCs~37|33m;{`Hz_Rb| 't GE$OQԦ]Р%lQ>Cy'(rcX\/(x G>Ud!CHo@JsA~pSVDcGw^ E MƓGKs_ ƌOj #a@{ ъBOp}i|1ɗ n'dVd~,7mf~ꐟߜHɛi2ep0A6ot,-7HpJ5?=0"\x[{-gC:_Xx[6q|  Ś+=Yu89&<1++gf@XY`W?#j2tע" %ϼĜ̲J`%Mkՙ8k'{ %on-x{za 6;Gx{zqa ~\ Z F Zq {7nmx{z! ~q9nx{zq q 6Hn!x{zq Bq 4n;x{z~ }6=6nUx{z> >q8b|nox{z. Y^q:\ x{z. *j7 ;*xq. 6.JuaQڬ8 QxqN 6.#ڄC 6sbRR040Pߜ) == x 6.#ڄC 6sndٜ)  .xq6 <y%Ey9}'gn.Sl"h;y›=x6aғ KO ]UxW]LVVV8@[J ($S7*87cJO+ueڞ*MMӤ>uC7M>MI{$8l}9㛽m?==ܳ]zI>4L PZJX &Dzp/\QwmBYMv( ]BE-_؅=щ)=,9;EQaK/aW7C3j..p$ C3UJܧBvֶA8Y7 PA:Rs˱DxԂ)YAϬ*8QT%9qXSŌoU FUM2B~ǴGPo Eɋ`{hѳ f}KVF?6n3+f9IRPAEGS}My [e= N$4eF_p,@4w"7PUYh]k8<0@ֿdf`/;;ϭD8 e,xb@r'NU#%hL!g׆o P~f EF?OnGx[mㆿ%<81n`x[ %<80cyx[e3#ɾ[(8d&+Lv=:MqrF7n mx| %ʊy9)N9I޾ޮ~nj9)iiũ%s'/RwE)*@\MTt&(MQwt2ŠkDUYNbǨ02Ƞ|jb0!M'SIwxq %XCC<&JoW41 Cn{xkx}'"/xkxs$ɽ}}$&۸ LvSܜ 0 n?xkxoPn0Xxk̸qyWN}- S-nakn|xkxz=C.82nxkx{-KΛ83n.xk̸k-ㆍΛ81}ոxY[o6~~Ł\ }X4|%HMTZ;&Nct^-?( yxnC8PX(m4p=L DCh^QN*% -%BQ"<h`(}.1*XQ<|4V DHBU"yȤDXߡO'xy83xwߟ?,hih"h,&x42fc<3%27#cNxB@$fKʓ界WŃb]$ਏ.z4x41<j{Tz0\!}\C/Io<ܣ5#|x R'X0* 5}GEdLbSPZG&AƾZ Uȵbu;Kn c+½.pv[ 4dhA$2 b 8C0G*:ikkX.qz6ɔorGU L0 .FPZjEkvJ?8^ocYK jf t,9:EӤ}Y~1([2- 96jЛqUy&zgRK Z* tl!"aV>+t ;~ )Z));p7miG(5T=0J.fO2Zg`Y\2a-9; xrڤ1po&j|ѱf6+(bLj\<2 ~2߱jJbk1֩ކz{' $[gu&-CT~ #Tj0۟27'<2K7`Wq?ۡK }1b`_K>!eAP S~ "eOyfDN=䍟yH{H{S/|B9-^1`&]JD5>BG'vgA!ջ CQbx;kSppbR[ʸ'zVP$LŖTIpofu~2+.ڔY yJh#޶ wD(? 䉒‰! "gSU%=CJUoFRE 2&*@YT$EYc}֧ O=#GգzzPyżG1`fF*V⮖K )B]Mg7C(5|5ZZ˷Sk# uXDy= 2ͦr$:&'})n}`,S)4MA9kqIaM]T!$t),jFFp`OJN4mC) 8& 蓞J;CwpÿpMf;J{%7;dW5{2/M%ڪJ\\hW96IŒqPB1Qljl<.dq6<-!C j0i.\~xVKOQk !X#`ԣVgA!ջ^'C^cx;kSppb\Kʸ*zRP$L\S. 7:EJ[lʬ:rڼVt4 `[;jT TIĐigSU%=#JUoFRE 2&*@8YVU$Ec1Ds kS v]̒Q=J=q<`zr1>o0fF*V⮔)B]iM7'@b}՛j+Sk% 5XLy= 2ͦ vu;LNS J#(Q.)4MAmszª©B29H:"Y'+!v\>]+9wӴ &0Oz.(l N5( |:LZ?ɠ<5 `rڔ9RoFͱH*rJ ^B,S\LPj4E5J*bos+Lsz@0ԕR_w#NsGafڿ::7+%/g'xmC2,dx{8AҜ[䒊Ԣ̴Ԋ gCSS3=$_!%?/uB=|pL~⚼M|gE,w)1;v ,FV7Id~RCuhe6sB@&GlD'O;GC(Eҟтsr<ɗdQf|7Qd,4slS`D o x~}t" m")sU)g#x~qIE4xrBF8%7cDQxrBF&dg敤%lb,ؼ[@ gxYms8&7͘Ҕpv70m|[E[z~eaHonbVzvWճP#t&#ۋ0A1Y`zT VL(XaSF0'?l Al[2E@ 5F%=B6Ao{z!FEvj ZWoG[Er!+"f嗬 9:E^ #?'!qRٙ-d"*¢pEW|byΏ:vhC%W9kv٭d }!E1 Úƴo*l[`υ>AdHbhv-&6`ufjiuN_K-|b㶥^Ӻ#C:t!Fߵv׎74߷[@ _ߙ:Hg0x`@6x׈>IИ2}!d8 :5݌j3..׵=hW%shs@:'pas&(@ H:toUknu2ƺ7 o8}ji0DeEaoQhRg``с⫯~+W?Nvu44I)p.}ӻ hp '66}t8O:N*O:pl 1#!U}1zvg+ք<6J,t45G_`4c:;B3f7|)90f-Ũ2T )Èn>Gk5ku;78-ƌ56z5I,Gk6& *#VVh Mhƙ[JȊu-[7SMk5r%梑SOM22~Ψ7L\V^$7#RaI& QE;U!9ZŲ<2wD'\T`y(z(O@ c ģˋzyq(*Trއl <1I\a6E9 ٚp,G6e1Vc9%PP/+eůige}qJ*ܖ[ e\SIs檹N@rSi֝?3%\)ԑJaw:5{6F(SxjkIb.喥JwXtԱ:*އ϶䐿֭~'Fbz0K5{l@ιj/=$9dy,6e4/nawlo 87>6UT,(Ubh{?imELቌ#Ȟ]}8 JŶSK+aO\њW$I(IpTPU!WIUW)ژTf%]FO[s~ {IY.2we1C ǡS.b/fJxk ba% cjsde7cνyt?#Dls:rfZJjBHppSK3$(/1gj[s0Odr\żlrjdYդ"jɮU: jEI Fr@NbsQj X@&3YKerd ɞ<mxc 'M$2/xr _. T4CM'[M^ſjr@*,->trxb3nT4 Ҝ[䒊Ԣ̴Ԋ gCSS3=$_!%?/uD0nVj:Yɫ$6 (3m,86ZɆ0x*F \(\ n2c'UlBx[f X(^gYx[~zy Xgkx[qx1Itk}xSKOQN [^/"Lb} ka7 3SP 7ƍƳqʍ+ӄ+fƄa1?<<ąqs=ߛo=[ĖaCV’X K8s"Q~t^Je/ `QXWG%7wlK%PG1[*J$qD SВeMC|!O^HhJ D.NN4l׏mQp!daw×ʈ}:%k0;L;7`9X6 %HisgȦo7rIR.ޢF`$QS2;usL(r3sOB HʠDŽV0NffHDPJ!;gҡ(IRl B5X^8u:^Pu lyg[xw0qd xJ%^n| l]]ċ8 ԣӵN|Ʋ\ Anv;A}ZAZE){/|>̢5l: {~7w7R2xW_oFOJuq{Ҟ\bű- ث`@Ks*߽,6 ! joI[Gm4">Е1%^4q)_ ϮOr SЋpD)1rȎoG1W~ dMb0Iy!:K0c_'I}v?'0 0 $72ҚFITEv13Y)',!.C\9>s9KSN^ySKgFGfY{9h& G<Hvg=9$60Cy pksaK <mӷdX8Eo<Yhُ)Nܹ@}i/K ·cGB&j9YE4Fn| >prluMt!_xjtM4,Zqoi2k ex17kdIwKݷ#937pskz1 }V@ݱi7' .]hҿ4 7@MHg7(AE^v>Q,(ܞmF""= Zv=k9'u3[ JgNz(Scq@H+(Wܲ v?NEh%g׎vV1ʈd'-Iun9kꊶ X ;U]!dXY|q=Hr-YTuxFaI.,iSQp+Qx32Ag11e>ڃ':DȟM77>3o d"+8^Zכ; ,??Tu<-EpzkuO(Sn&Q򩝔wAIJWg<#dxA H<6D7ɿM#m-Rݡtey,k̇R&wBK 䡿J7x>z5MnASF| @omZe+)bw%]:0{d)ieG޿7QRRS K˴-mo/w ׼`}Ŋn{wdFH9Ԥ&*z!U RG1xV.#OIQ~iqjQq|Ie䅌›ٙs&fؼى1gkPS=sxV.#OIQ~iqjQq|Ie䅌›D mlx{p=EfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_:{%L d{ul!d{!+İLP TRSx[nFb"쪎CPd51,ن%AKM"jywII)%FЛZrgfgΞ͗Mv onž$;vGs/N,go>"b|2x"dI'u߱at~tc Sw$G͗𘲋TnG$͓G' {uzMl~㇓`1tw'c~d - zK\w 2Mǃ;N{Iܚ |ڜ4q|UMd|ݼ)6-%O_lC7GMz魗'I>ƞ;uncO1ըy߹:c7wA={:t}3p:{} H ^ YKAm T;7eo>6;mC~:ff{"m 90w{;0t}{ùwx-lЪً`&,⯃6uΝZ/[304:Շm3̡rp]1_w/[D'h{)#2B1 I@.X G CPrcfg dW*'ҠSLm4>Yȅe/1KܙOoЩwas_ Gl?b?]Wn^~S&777 ;ξ{{\Ahwy `c4 /IeSYB<zz޲~Nqw|[aSِʈ@0c큾l STf"x.L/3o'O0;ΚTE-ɃQ-=B /O mm!BE4m:n],U*RL+6b[g+#w F\=]}"@{qŭ%[P޻~MO[ sxt۠7*?my79G%\]`fhwDǞ'WRC6XB'Pi坝Ik2u2TVc0QlsXG' u6 w?zKoIȺHaRzSdR0.n )rPLNb s?9tRY3,n%N ԃjbo* )ՎYnYJr|iКW0zS S6FrjWH-lrD€i"3T-!8 Rb] jɗ\Xi:{( ~,-ji(i G4T D8" %V U R !`fXd]0ԫm˝üS))V ktgؿkan.t9C(rS7Vh(!hQ +('vY^5L_Qe.%m/O2L{CM_k6 RThYJ+"褰V]|. 廄!xΰgH "k'&AQ+^oP*lRt<9 BʃWe1iAYblQ.~^23I \+ՈTyDO眐NAҊ: -~+^ٮ"yk#ƒbT w%^J˭3"XyɿY KS*^rdCXݩyv<6kҀ_uBC&69=y~//,n,R xLCkȄW60FвE4~%_ڣbQ 0"+s|'!]wce-r6p Sӿ KLlXcT  6ʐ3[J5W0&ָ’P!xm`̸"3MAC(4DV!",(32>9?$D#L/WHK\ y:3FVjs-$FJ ı bZ\)2fN,6$Rd`mg "D g !Vc$Na N0gc741RbG2}Ae5,rF@( 7`V=Ji8ɰQ] #R4) :۰'.Fp$%#)` <C.L/hJY/5VI$~g˓A2 _Ex5_ar3=}fNvbD2J,1';7R9xxAfu 7Kxxm`m`X59'`ter,Ucx89 ^0N^òJ!W 0gc ~FxT]ofV:b VkI),9 ]7k>(JADI^s7K47Rv йBl?aaaLRf7H˅cyy?KZq}}կ/eQ;%*=':n Y;o$ښ 6~ǧ<9S{- F16l$|Ģ40Ijs[m~PƞZہݥ]kvBnM1Q8>\7g%zRYcy˗\x–7Y׶9+B4KN?T$%q?8ydyi+&+(r/.LDj+mnzTy7=VFir=Wj!yl_$f瓧z-/7d)!=[)%xQl6]#sY=&_4vUu psqUH,-HKI qpsvU3/wrHI|nzQ|~fbFs~^IjEB/ԠY1./BM9`&H:xS(:xRk`0 FwJcuZ*D!,aMjyUD}Nc/^{~UMAx=Ņ'/srMl4!f`w?O>Yc7,wg(,cttojѮ.=߳ag{uLF6m)⮿oȭ!ĵZGn0ޞc88DK|G9Ni&")eX M o%ZOsALs _ 6/S-l[ágWWm8.㵫 PauZ#.C;Sy6eגkT-VR*U")MHIݜL0X}C%O& ޶xK |PrH5{z~2Ő&O#TтTIԂ<ܞYmw|FD%-fg'9A&:TџPȿ<8μ i/B *&kx^t.cdɑLʪ!~.> %y)9\!~~ή ycNW)M/L,p+I(QPCr2iZOR"1' Zx(BtLe;QqY&̒ʰĜRt%[sHkYjaq!A>!:5<&dz$W&g#% T`3uPɩha s32E!~>1 #t۠ ' Jxm`^AQ`D5=F=kx9GiC2FfvL^<[-%$Q.9?7w~}< ժԊ % WGxO gd,,5yd}6ɬX'gGz~ɋD0^]G;^OCMA745"[$ >'?9{wAr y厥%: y%%!:\ JvY(A4At90]j%m05)~pǰB\sX23/P: &֓ -Pe-5cnI t"EL{;`v8BD/#HTord>&'Q!bI8ӛ &7ye- bD h3D?Bad;%x4Ci#GIQ~iqjQf;{T_ʸxVmo6l㼬-aY ؊,X>DD5I #)Yl7n1 P=;źYЃh*h PRD%xS.7-q88*yVU HAd(_gK%|F#뀛Vk )BdY&0,KF ܼ&ǵe()b  'j~Ʋi#l,mR*cu*Wn#rF)!!rӖ_FU,9$ mo3C;+obI\xt\=˲'s_KR"4E$A5aLPSϾT"'9*J[7~9ztNĝN< &#n}*oTy>C Eq},G(}SSAϘNӿ}sk!lLr> mzlkݦ _m_SQ$RD/KWTX= ܏^@GL>j`w9Oq`}o>G7 FMӹks +D&'g@:yy͂&KCNȇ B+ +Oprn((L,:kE b4rqq>Y pWv`a썧'JfJx}x[nb4{Y.9%1% ڽyU;Pp;#Kdƶ#x&B5UCyuẞ RQŹM.V+6s&i5e|X|Y*)W0>87!Èͺ6V"Ja;0VٚeR)#LJ_U1,E"]o`B} .< de뒉Nij[*Ďg^.9C҇zvFPƈ86TB[D,:,C6>[_ =G~XRyu{bM A?.Ad3$'{ρ6U!ePV,Y1dnҺ4UXN-~g8. ˿jSʌǸ3C3Z$G$e GtN| GSCB5A@Nth{ѐ+gq{SEI`"*kI t0hjyFB$^rsE46wղM͝s7ܫW0Vف2&frsNiAE}1zα1jvW|dVV|KO8xw\nXG*mᑣ;muuINKmrFC ꓛ"֫T#!Vj;f(#n0NG%c6DSO+lu>Zi~^ƆH{%B&n7}0rGt6̵`ʂ2` KqD|@  fKfw6`r']=Ѓpܛ&|o{pGO-;+ %YxGGoNx( F|ׇUl֑l1ߠ/mEG[DK\G:|D[< Ę^.⹨:vh_sl$ouˋV!x XIf9YX$_k;|Ũ ρt2($!V k|A ՂAϞMXI2'm|12`~*ST;f8 }A|8N!iJv~eЗBѨ* @!{,,@zqP~1j_EA `? ,ya1q l X$MfQpsA+р/H؋P^"QoPX'|[ɘf~s%lj jIB\]^D[؞8*[,Η4 mb}/Y)`1 7Y+:^ kpi]vk̭ɇKr2JSfm*y'r⤧KFi>qncN+H:ρW&/yk"r2~v4š:|~ kKd3ve$ZzjFr@";32fћ Y[lAc-Qf;myk'ϖa!_Aom/OQ,pRzMmٖ||^F/Х2jh eUN=^2DŽ,9r2{(\4*:ݥv46_G99MeC7j^|qKKZŎi6cm+.qg9jG;x;fLk#GIQ~iqjQ8F9Ʌ\*S=&k2kOnfVKI,IԵK͝3=3[RIFQjbjNJBr~^IjEjBGKB3Dbr4ô&cD`4++#yw1׈xgolM9l9\P?TWٌ%32K\Fi `ȯ0cvA~$IMM'aGmGa.NNhZsqq"D2RJ&IiL~ z\Ą$ tpt=MsqZAi J>IZ7>~rF8&M."mB^op&T uRu<K+JM(.MrN,G &uz%'o+F)sMqGQkzBWÕkM#+&=fcE|x;f2EkC2F6Ʌ\*S=&k2kOnfVKI,IԵK͝3=3[RIFQjbjUBr~^IjEjBGKB3Dbr4&cD74++#yw1׈xgolM9l9\P?TWٌ%32K\Fi `ȯ0cvA~$IMM'aGmGa.NNhZsqq"D2RJ&IiL~ z*$ tpt=MsqZAi J>IZ7>~rF8&M."mB^op%Ua(jCW$9yX1 Mn;CCh9y!HI> [x;f^qlVƔsX8A@( 8*Ugy&dg\@8'zx[R{CEfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_9IJ|l&G1Km.f6{fvP \<7~1N aP] dwO67LM7΢-2ȢUnD qfDB"7 mK_8/EkL% ca<9{wpȘ7lʽ^Xxz)p,lg9q H'V [mDS_BX9x҃zNԯ IdHډ>FǵbͦKFˉ k+]&}[ʋ rߐҽAXR?`LhBF[?wbAax?\qũDf.n]5'L{d#2M-HMBoHCYl?vn 4{!yX1~4i\Ⱥ]md{&foEYXʔGs{0$6b:4YI|I{+c78!:e?ɫTpeLUvB>/;M ٟ;dP/_*땵&B{LTUO˳T C^YJ6#Vdi~jwN ^23JѪUxXC9kݙЬ1&ܩx ^өU֫ԯHQfgiY{Gyd{a;-y1VْѻKLFԽ^8fmu櫭`˱9}6o7+48$4STZ B>Z+ytgo6szTQBrs M<VʾyWf9wTmuY<}-ZC?hڝDo!Esuɱnu-֐}!'غeGO7zkklokgѧ[+F9_~&QFƣ!$5x(wLr#GIQ~iqjQ8Fi͇x'cƭXk;هMg}< ՜Ԋ % WGxO gBɱ|HfijrM>ϣ1>Rؤ\]12^E}CC\#}5J s5'ewSH+ J-IQ(pN-*q,-ɶ2 c9" j%.@48!A6!RW7_{p#x(wJrC2Ff͇x'cƭXk;هMg}< ժԊ % WGxO gBɱ|HfijrM>ϣ1>Rؤ\]12^E}CC\#}5J s5'ewSH+ J-IQ(pN-*q,-ɶ2 c9" j%.@48!A6!RW7_K1x;&."3MAC(4DV!",(32>9?$D#L/WHK͢ bYMN)x;%yLr#GIQ~iqjQf;nYxVMs6=bGפ*Ԟqh:D<"5Ӝ0 hJ= RNS{}}IriN#ѪdڮA-5ƹPUev0BQ;H®fXD!D\k,,\IL!JRo+%33g{H]#\~o0}.3Q 46|>,~qgZa=d6Ѷ^3,z;Sr u63귦|h,XDpģތt;rl9Yi0sZttҭiiF69p2vY3B3Z }|SY~"|/MiWJޟ/F1o|ov5N_ÿ28jtcJ ͫek(-`g|6P80b4rC0r9GdLHP|,93Q~myv :YI2*ʂo-MQFjOa<2Zq?a^[ [iʏU,\^ד:n0{7`9>)I?Ĥ)l'[>wi2;Cc Y\֟UPYf0r3nXQ-=.\i%#ʼŒ g<0GPnTfQ)XC!d æl4kЬUAzT Ќp C7<5YKt vdFG;BsvM7]L܁oJǔxi|*Z2(8~2>v/h;v5TboՉjWP? VCEN \+Q u+z~vѩgK;ia x;-#GIQ~iqjQ8Fv%e@<[/7(3X*_d铟TTQ29X23/%$QC-H%(iZOcF9v($畤V(V {LG!"1لn`u& vdx[ 'O~KjRi_jBr~^IjEBfAjB3DHs3?4&e/x[ɿ#GIQ~iqjQf;l6RBPx[ƷaLK60\`xW]oJ}ƿbU"BI>Jĸ i zV 14In6ujQ0tC!$Q*<h&``K},F(^ >_HRɣp&#ˬbɵ#蒱z*9M&Z6d¨oD@G1SOB,=ħ‘z6/Z1lb!a2aaD՛\LnknMR[krX#㝎g >f\9OEM7J\W@$m0LnVH<ס[kdLSU}$l'v׍E+m\&32${ s4942 š)XtV/̄* ]{u-}*4}-Gl"7y`jWbuU0]JHgov&YܕXv0Üo ~Ft&+2aK(&"fQD9K|6KG:Z9s5k5Pßy?{碷w>U}CO+'yw<3:ć}EV]ň{әZ1#0_3%τU`n$]ܞ?ܞY<{{JL>x;T#GIQ~iqjQf;FA&Ɯ'O^%ٓݙ1gFA%yʀqs'#31x;T#GIQ~iqjQf;n1\qx;e"3MAC(4DV!",(32>9?$D#L/WHK\f}f+FVj@VhFJ ʾPy \{ bf f|^7eU]D>SlOp3|4gxWmoHl~ŜO!IT\4sl` Xۨ(MO7y1vS#}yf#ACJ\=ۧp8H̞!ݗ{\Ǘ8L(^"&C#';&`0m 9Kwl慁×z5;K+λ|\2$w/p%2O1/ =S?\ԗ^P sb[y(=]K34,/5sDj̡3&eYcGs^aym̵b{]8r,b)I2 ÚlhJ|n l dtt0Z2&k6ßj hdEH |:o-:|*?RV<2M7 uXCtg׃%>˃end^D 3 a²|cGLZ>h61-;X!Ą&>+4S_8MUɽ՛>$%lzq+@g Β8h%ʸB?URnfy7YN5\l߄ژlEU `TRL,~>rvz&EL2w,b9Bkxo$9V {B0n~;۞Ov]`#Q3s|sߏ|͋K($$ɥZV2Oa<&dFوsڼ/FѦ@ ng&%Bi[ e@. 5tSh@4M`0M2mo" ErU¹ J$ԪW^-, jZ6F~~ؗJTt/3_Q5+6|-CUY2]vO~5תlgZ rqç7fvUHRʝWbWaӪZ}eKIM=x)rW0XƬ #/3+yClyɖfJ108PX {=]AȱҀt5ECtsJΌt4Ab>bd&̻& EzY~ lհԸTBGOySl KMKu%fgV&\g-TJ|~ W]*qGec{kx7noC{{ho=%}M :ɼMu56%Ƒ[F S~U8'ox5y( ?T'F1+ n92lws Y0A745"[$ >'?9VϸgIpqBdCP'ߗJVTU0:33/l: ƚ1(ӊ!ver;#XʼnH)+՛,+1YZЊeDz )d0NV$a3mK͒ƕ@;q”vLcx;jp#GIQ~iqjQ8F [T8|=\|\'?`cQȜ,8ydGvyRKuss55'7irq䧻&i(d&(V(d8:*V((x:{5`FN‹id)Vc Q \{Y'obu!k&=9mhzj P^D!36P~U8'ox5y( ?T'F1+ n92lws Y0A745"[$ >'?9VϸgIpqBdCP'ߗJVTU0:33/l: ƚ1(ӊ!ver;#XʼnH)+՛,+1YZЊeDz )d0NV$a3mK͒ƕ@;qvxopB,qL4-?ncXILa  9xg`a)FQjqiNBrIE|YjQfZe|r~^IjEF3ə_:"d>ײpD6s>a$۰|39!M rt6 hxop#OqAf|f^IjQ^bf+FFxGLe&'HOe2e& Mn`f 1ms7a7# e1Phxgp#GIQ~iqjQf;ex[[sF~_N<إ3 I#KD]N{ًv Hya{ѹ|69%QJ}rf4 0%ߑ$^$[xN.^B?%q;"="yQb%x}rJ}C:ҏ$]d"qmMS-LgO|v ܧ4lK-ךVi߮eIE44%H,MG'NZg^drm4YQx|]K&gA{M^;/̶$KρG=:k:m -sF-Y{羓-f.9O[v#vFEb9{ O.wˋs1 s.W~ʚ]~@4Bk"I$Ѥg.0NWIJhV%PV 4r ^ۭ;zҬs9|?Ȟ sG>'[nR8pzW_K`t%N/;9iZyA=Nɤ/a98k2 hOvkM~.gA">u~bn=6/P] %(yrpU*7YKސ;7 c[xCFYI'#> YNnV BAŒY1wxr ޒWXk]-b%O4dJx +%?`TcU[n9Vu+T:MÔj0X3Gg8.H8րuuv"Z*2L]Gi1ܨ٨bVL"i) (3tʓ41A0hW,!0ÙM| xU,*~[1-nxEn浰XmD"1LIw%ja4tSDI2K.LVŬf `MD~}JUO39.Ae6` t#J s`.낵tcA=Mx<. ]qF}BhitHV@>6fr7%؀pB>c@, ٵو .*$ETJGc`Z'yӀ2TUfhѦ>0QCB'2ǪFAR<0(.!|a`3 F)'&c@maTFӛ=o$xcȦ-Fdٍx+@Q~k-ڤw2Z4!32@ގCh `h+0LZe|K-.ixb3l##%R:qn*-km1J%٬۾' Mp;3PMfRSt71DlT>o͈ػ38JMPl4򫲛aku6 k㍁;~V ^!g؉9)ͼ#{,,_ e("%-f.okRW[7M^ӍՆ Z`M2O=zLX;uv T^0W=@ϧ<Ŷ:˔n&MjGmL$.VkW/nMT\WxIfS%+n4vKrzkXb%vq\.c)iVsŠZ˔pWzM^kM_64ե/ҭ3 ¤q{䭭/>oἣdfF><Ɋij%v<~GA3tiȬr<[ě t r"߰ޭG(Z0֊2AP(98;-WlYGVܱ}kQLP m|JiLYx[W6l cfA9Y627N˝elWr*UUe:f3=6bnhl+x[W6lf_%JgBx[W0}Bc({xWj,&Eť9% %eEiy%%&'gz~IBJ~^wY^xV?Jm>u2?(! |msY ݼUjҌLdl w/(iQ2f*똑 XHٛ~"pE_Ň!<ɁS%$ 筺xUMo@=ۿbTd -@)8n/$+mEg֎4MC[@98켙7/a݄:x"S}4cB- BCti.0""d8S ˱I೹n U>^9MO8*`fɆ-a**lC%'l!&j /Jf\$昏nzC G߂Qta7Ao#GEd!ASL3}NN:\|Xn;Ws C F#QE 0Ta2#n SPۃt2#:>midi$]NV</uIu".I.WSgLF}g@i| ֌d! Hp1rIYe x^*liL"[滞gR]]o4 =[#YMU+K˜dV ig˩HO-+tBN'%vPv\7* +Hz| 8F=G\E\> ݸd)b}ZsE3bFǎ x })q΢WKiދ\w0ze >j_4ZG0Y()1jSof8'}?.+sY=˾t*+:ָKv7cg;;0N/iM0*>Ug^C֡e^ݩ{4_cS7vs)Yzev?!SEOz0 mQ&*Bx((8xs,&W5gHpp|kpOBQjqiNdn|j)%v\&g6rP*(JMLQPIQH+I(QPPQruttQpHhZsM"?ٝEM"[ohkDFIrqA|N~rd~.E6bP?4.̼H(jZOa3GLzr,!ٸ 89k6z!RW7y#{2@|Ó^3 *`qLviM*`x*!qs#+&W5gHpp|kpOBQjqiNdn|j)%v\&g6rP*(JMLQPJQH+I(QPPQruttQpHhZsM"?ٝEM"[ohkDFIrqA|N~rd~.E6bP?4.̼H(jZOa3GLzr,!ٸ 89k6z!RW7y#{2@|Ó^3 *`qLvi 3x(Yx9EfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_٘y+e59UboVoF l̼z[vF:8 x(4sF󍋺SK RK&2ix:;F{8*d8畤VXsq88:(Cu9d\C}BRKsJ&3kN~ϴP^GPGA YdAo5uZWYdAV2\g%C* x,|sF󍋺SK RK&2ix:;F{8*d8畤VXsq88:(Cu9d\C}BRKsJ&f֜(D\ ,i(v˱J!9 [J~^m N?nDx9s&3cf-4F_x*Qh#GIQ~iqjQf;Fs^xWmoFl~E8\n"9Dql`"@Wwe`ɵR8dwv晝}F:Q$P`X؋ &c, KrL~ <D~Z 3|5C :1/YY zԄgLpQ֚}Q088rc]x}Y^s&rUU,tʚh+ֺ'$]a' p\D6+zuDbL^rϬZf`>:tϩx^Yܶl[$`lK ]GsM_ bʑMW[dbFILPo_t2(@L@amvߞ),C%CHN ݌&c ֪O#-۽/xscziu0no£vbLzK_w>85ɾՃLq.lQ?dÔ!1ٲ %C3zP(]a\}=v ?EA?;Q\2GY/G,A^LoFf a!ax$ʲz4!&qk«!zTOFcD_]x%wyZo`q7u s MKׇ:BոNՇMfoyfp&7n Nl݅5rIpل@F3ܽ|v}?^dح3{qYvߔt%ci8GuZ?i$8$x/KOxo`"VK5XP:+tct FiM%4c-)%LM0%Ͽ`]f;kћy֓W˖(?Ja=y>qȽY3tݒl؎UmkKS,6•j9[{AUl tЎW$<;Pu]%jH1pdq9SL'RB6zdV)?ʈԐY̱xx'vzGn;dkÉm`U\}5 i؟M++$j)4&"®`袨ߜA`ŬZZ RYJ*b+8,0MT Y.+uT)ū\o$kpغ@{$5QgMV˓8[{ v};")bFث69ϊTFmA8pbSjO^M;zco Fs"W`a?Kly xmppEfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_:wl8sD&3KDlD_K"Ѡ8=xRoQN}K-mAj$/ЮR&7Jvzl+l Y#!x6ozD&^ zn<9ﱐZ;y73HϾ0~SlUv8]ê>iC!^. muCƮŖS;%ps) (e`̱FobU07FX .2,lE),OD\W+P.XjqE#H[LW)8bҁXr&\ AިFsgXzYdqdFA%W6QU^^*5j7*;n}.bm[/tZ3Y*'ʎaP Ox|Z< Efp\+=M"((wJ75aLCKCLq z$7Ps{A{<~G(A!k)X(M |I%M"|G'{|{Af?q[OT*f/"%KKz5: *%@+VǦfko -%xKOQS`f@i -ĶT%d 4iNU4&&3Fn{WnĽ1;3-3eay|s?ߙ`̸de(GvB(J.$X< AI\) d* 2ߠ[ asqN$F ֶ۬`:d0c>f\L+&sףH& R9!NMcRu*Qp91֎ip6m<sf{w[.2DTsgB%E~<'|u^" {NGptrN4‡:v-C%O&hʨ#QCe(3N n8pX~ {7U@1HB<ΫkaH"#Js%=X{r̥+`&} 5y装5A2 .8+AI-75AU4#3D&y:3xFaY>ISH ߂Ao0p[<7T7|Da?sxL|Z\xE,D|$,0dnrלb'$~&"x(_3U8] 1F}5 2 A^V[pFX[/ P0zHCxyY1h^N=as=7 lByZ)U5--?5Zrx"uIj 3cxv9̟쯙 6r3Q Jx"uEj#OqAf|f^IjQ^bf+F.&ƪs?13VmgcbKNQ\y`/;3wx$uEjsfo.vf1fx"uAj#GIQ~iqjQf;F1Z\_Zxop`#GIQ~iqjQf;FEq_y{xopLo󼜓y70m`˥/䙗  E67s]`',xZ[oH~ƿ("K/æ)!n-jUYY׶tgf|1$uE`<~srR]&~DEpS-y>"lR^9RƑ;E=7(ZD^0+Q/ s^^$ ]ӕ.x&[th91sjY<|j[5q̭!O_y{`V n}?]&ꛇ _IAx@P /_,R7GBGĮpJcp_~1-827x4Bjq1UPSn*IZ 6( ymœJX)ʛ%4ptX/@Fn46yꉉ?ʝ3 E ""UR:8=i:Ux͓KoQC;BZ^[*БWML6i# æ./L2iLuk#Mj&|.nLEsϹ߽ ʫDeI/|y, k s&PrURӦLpU)١8pJMs:J` Cc>go.B|ҭbA%hZCDzNIxml=`Y|VmxCfG&D~Ȃb B$àJY#J V,A}ħ詷.lpzZ#v.Cͪf`Æg/$?!({/)Ezz֥YO"cPNjgX_ K: ^A#P1ZXL`ʷBrDl&* 8 M\N ?ovuHh>wn:PX׻DpRUL"Jex^c`TCa+&W+xhza3M,f/m-"x{fvEfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_:p9 7K0D&HLr|ݕb7Ws:Y{#BV |Ox#ks)^zxhsrY м&IJm^-\ |xhsr#OqAf|f^IjQ^bf+2QfɹR*}gd˙!a5Xx 纰4$llZt]|1&荡!$znZVxl`L?Py+lXo'}G~ac|-DFec, fa.M$" *|y(5w0d*drU}ǯqǭ|.V-C Tڷ=8)?D.;ùmƼWG 4#S6G,x$v+ %CP yy%6ԋ"2#̄"jVhq0(&?ۗoXC*:hѸb?rWeov<0+p)۷+MNQ {!CEvdT)NEF,}(ruI}@<@y&ݩ1\&\+fR9 +2AIќx^J//;ELC/ zAmÚ"&톇|~cT1؋Y%A2BV,ϛ-1'.G\R$<I*Fal[JPjKX]mN9'v@FC5\ 2z8_R8EhyYG532 &y˺8BP•'!`h@ij5ՒHk! k؂,UaǽbaӍh1B~F# { H=̂e^<I 5{X!Zދ?SsgNM$Ŏey3x\׾M U/@o[eS:3ˢU I[M2)laϧ.ٔpYAkz5~ g#H k y!#+vs3f63K? evv-qtFksާ",=i,==ߖWD*o9vO 4KVNYdo)Si xO۔ygOȓy>#T~6Oɳd&0ݜ%²͋E}9A7ɿeLټEUf=곙`FL|Bk$L[2^s2֚$Zk?"x۔3uEfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_:Wd~6s&_eb ZmgH:qN` & ecE2usH''e&ɽcEug *vmV˄ oplnb⤂ZwkKb!U˥[F;ex۔)i3c&V|%#c`р|ءv4^n7yYj,p&Xx۔-qC"wO~)[Ɗ,A=;Sp:S@T"; +qL ϲ^w 3y6!x۔3qC"wO~):[:Sfmٟ̓9d&/e|Bd=݊lj%?2+l6W*cC_~5Z=Z/HǃټA=;Sp:S@T"; +qL ϲ^w 30`g x'h&~gxcC 0xc#OqAf|f^IjQ^bf+F}e3 UxVO`a1`KʷO]:0vAƃM<FnƣGhxMohڍ $"}>.+?RpJ4,m>`@#"R=^Id HAA¼,*{x ȞDHa/tZ`kBq\wk"WB^*z\d&X)f~"$d[EB^dIQbK,9Hq97>8|gB6Lzt(@H:YZ"JmZQYN&fSmt@/zAˈ6=p}=lq p>)uMVa%ܫvg7'sctʔ‘EGIX3AQEDO# ~rm= j1)UwY͆/$ھդ;}9}p0^R=Ya 7 sV"cs4՝fF *@C*6X(.o{%v:|< ﷌CPw)ڑJNҪ}Y5:"iDv!]!f(S-TBs!S$4U0[s6eW:hZ4fNM626pEB;zcH IEݭkGZحp܊f˅44ît6Xn܏~n2:WW-kNMxm>P ,X?,n4}5d~n9Ü{!E({d1`sJmژamY$a`PB^# GsnSjgSW U7A1/uWCs`?%f%aƶa쌍/Dlm߸8G󓠏/'o^ʲL2#*v;0f`mtFG)[fH pA?hp 7j~ki03u5DOiNѻQFH CNf;#b=bG)[D8\Q)f2\%'OMCA,ȦUU&.v]RyL]Kc>!8>U0|ɂb%Iе ধQN@O?ywJ :๥GDܐS>$ISXpH׳rJXR5q)?*Bv(@7U)%ހWAaO#|tWZb**Y< =NzeNF=È]UuCXIGij*wM`RAN&)99@p.zjS(Tl8N xY/ﳺEzQ7iZEhD5F{ʨc{;]Vm<'J_"VR>b-.`|ޖE R7EC(yh^QYl>l)𸆈|ER#", Ë' b}ij_qzbzoIAnĒD]Ɏ,:0H($畤V(V((x:{Lҙ"K745"[$ >'?9{rD"M*KE23/ha: ֓&GT|ĀFMk..N^FJ^d} ɿ̠Ϡb9M ӜHS2/`Z^ b,rEy)UQPY6YW6TƋsLǧHNLЃFF4x(beh|G1l _GB")\8XGI @!ƃC^m1I,rt0;( \7,[lm)a 9%(b2x9w/a,f ] CR Mž/ qMh_`dx~lC2F~$'c"?Y@c>IAnĒD]Ɏ,:0HV($畤V(V((x:{Lҙ"K745"[$ >'?9{rD"M*KE23/ha: ֓&GT|ĀFMk..N^FJ^d} ɿ̠Ϡb9M ӜHS2/`Z^ b,rEy)UQPY6YW6TƋsLǧHNLЃFF4x(beh|G1l _GB")\8XGI @!ƃC^m1I,rt0;( \7,[lm)a 9%(b2x9w/a,f ] CR Mž/ qMq>uxh6r4vҜ[䒊Ԣ̴Ԋ gCSS3=$_!%?/u|yl+YA"V$6sd$XMb ţA`Ww T)3xs33L6C$pvͯ%Q wx]xjvl#GIQ~iqjQf;Fq)^xZ[OH~ENBH[v%Bp jQb2Xkl˞,=3 [g̹{wfP; t`Xċ c1$Gpq:F:FJC <@ "Zs`fԴ6 1t.<=Ӆex$P`OH޿ŏcPQ~q<]:O1/ =FW$ 0jsn^b!Ş4\>0Oh<:n5/uYupΩ-/Ch%ۍt )O6(lfLHW"Sh܅<§ӗ] m&5>JE` \Mx *cag[GiÙ1Ե?u|py6`11 Φ*CHpW&0}=znzK/Ӂ6>N"ť_`I3;3@/%M&鍮AȢ x=>dMZ?4:3̴P.|_\vk Ή9w U[gd0~3 .'濒e1ӦS9U3p6 wFnw=uO , Ns5Mdkۗwgc5N a"iZ%.qOyGڀ,~ Vj#z07: c&̜./ -1 )Y$7vK,iIvVk #^@ tcWx6̶.QwJ+կRsp}FtAټ(F]>6wˆx0#w| U|cm|5D,1Rch=w޼)d d<_I[v\ELyɀFJ9]Ti7TsI:ްQ(%'5ILrՓ@eC׹}륝ȧ\'[dW&ʝy.EOZ-Ꮇ&UbKӒJ*"?'ʏS tcf/d_g+G=*!5dQJcg Y87U%4yf%e1խE\[P&/1e=6Xv#jqXm=N_\^~Ur/Hcm9F9\Z@}&I ˍ^;l mػ=U+" ގ"W gY~!2z'̬>/d@?x$AG3<;J/8?㻅՗fufϾ,gue.-N_F'O9VUB\%aW%sdpQ}V{S Uf \Ork@[G~ }vc3o|@ݻ <.vTx[e#GIQ~iqjQ8Fgt'+Xs$$%N(3ydNBr~^IjEjBGK,h:&ڠNnf-6FAYNXĴ&r@EKZ(%d(H\|CC\#}5J s5';sHKrqM6Pc!Y4PX3ҁH \?LG(0فxWA8MJ7GFΉXmQ(hɉ r"D2RJ&*|)tk*PL&*,( j쯗|MOX&&ގ·UŰd)ok3~xE' y~ɥjjoHcs_  9ũ$G\!0,&+3KL֔/U}7 Qe0yS0Mgr|'1^)>Wށ/}TGYOlQmrrOnPQ19Ag_UIl5E Ot/T'x[peC2Fgt'+Xs$$%N(3ydUBr~^IjEjBGK,h:&ڠNnf-6FAYNXĴ&r@EKZ(%d(H\|CC\#}5J s5';sHKrqM6Pc!Y4PX3ҁH \?LG(0فxWA8MJ7GFΉXmQ(hɉ r"D2RJ&*|)tk*PL&*,( j쯗|MOX&&ގ·UŰd)ok3~xE' y~ɥjjoHcs_  9ũ$G\!0,&+3KL֔/U}7 Qe0yS0Mgr|'1^)>Wށ/}TGYOlQmrrOnPQ19Ag_UIl5E ,Axu_f4 Ҝ[䒊Ԣ̴Ԋ gCSS3=$_!%?/uO<Vj{q'6lO%Y7K aC:^ tsTE'n9ˊbi[ x;e#GIQ~iqjQf;F&E]exXmsF bǝz!$t&,7L00p'tiN&="^k7u^ػ}ٽ}e' N,"$.9W#@D}㎤,ԔGƋp%TUxhe+PD~K7H@AqI] 0lϑ\jrjv߳W겫fG,9ӝpLA둥E7 ]4 qXk[[C U]Y\CW\ Qy*ou˶FNԠQcIeZ-JȘnKnZ]M}zrg~=+\'[AqSj/ XRMu͒jܗ% ٶd_]}c|:F@UHGm3N<88:%kYGmBH!wHICn PVݯxnW4NIn}d D@Ye閬%x+ (Snr|Y46jo:g5N%PG p)U-a]OUc7FʢbmYd[eG1q3YE@ޥލ)e5d@%4ӱZ,s|rE3:'>`{qC^*JCT~%*/&p{`* ?*;`92QH!oMT [|[suP<*ģB<*ק_@'D+P *Pj@yrl,;L`JnT':'Zz\<<<ID&ݣL|2|Ț`;*筒|%nHO8F:V<(߾|8"ox{ve–ɞ̟9JKS7{0h(*$TėeU'畤Vhd8C\% )yxt'dӜ#'![3+Hj:wl54hd^yu0]! ^Xqr;\D`bL DAݲy*f*kE}K&dZ^aQ=ʻ Vx{m GIQ~iqjQf*1r5.yt.X^Xqr;x{m GIQ~iqjQfyd px;2elͫg8T1xWo6l $Oyˆu-j/X2|"h@QH!H_U'^ x=x$8Bb3Bp kN0eԏBBnAG"`j# t):-!<.F0V|48˷g&q!I?8F6BfCU5.tM݌:^Mf Y?_҄$]@jzf{, ˆ9n/:k-{8F7N\h`!b*I2 -uc51%H8G&~ Gn2Owd1ٖl#3 J^/! {C/<$hkS "%L@|fp6|^/[g gQ*{s ijbÈm +;SAYQ17Cq*.LC0~. W' NedW"0PF.5F<2-gDBGS.U8r*($z|r) r6 ./47#rm~Rx8VN¾ ris]ˊ :BW3g)"QGP%[Pv]ߒy0u]u{&)3" ;G;.[WTΗwiOvUxSEh^SB*a=˨}MJVε^naU9=jTL7;5wz69gR,Dz+ ~n8KNdvQ4)X>#T\zƜ-o$߭JeK9-nCkZrTKQR,x=O40k]uψkҏ5) )(AAN5.@JܕVڲN=BPwS/K0.>dbwc艶3-Fz3S(wGb b[c5Tx[y]i#GIQ~iqjQ8F9{M^«Xk9y"%O~KjRi[RIFQjbjNBr~^IjEjBGKB3DbZ[ 4'˲ac$:n߲cȈ&9Y!1`5u"QK'B(PMڴDp}}Ϲ81N 86)4`^("P3к`NU"J$:38(>N4V(Ͽ[l1 XQ<l2U="pHƩO/q N81waP,UQmz<ƢLd=M0Ti"Vλ?Jjx[sl1qRMf01clM;-$U'Jɭ1ՊT UMr'9R%&dd& 1utHXkS :: ؆kɔL_X8%#ɏ>K[']Xr吾*tQ ]ȕk:m,/9o?¯ OY˚P(:o$T#5c&T=SGaglQ%IK-Kgj "gmVǜ٘4'òmf]G8 һdJsTԚ"~f-)`o q ValJ@&D `Zy[lDRyre0cE%ET$G" ]rĄi2LgeH]ڒ:(אmȏMRuzX eXkIՠA>|Tw H]?n(caȢkPa<'8lzs3ʳtPWUSLikf:+R 6ICצ "C$U n̺]a2oT*XZ1]`uK7%&TTYu @GYG Mh\[Ҭ?xNdX@aT k9`af9O,FڮƤ˜Լmx2X㑋sA,Hk8to86D&iC >y-ugK1`]^c/-佦ٓL8nX~&:C`X*a/BM)҃'^MBȒr b l HP-Vr[g # ܑ;ӭ.Uf׬W}"׼GmN:A3R̺Ҍ?xVMEL=06z!G_GdWy822`cnASl?!f02̢~ 8rf8p 6:?\z0no!Qфÿ>kn߱suţ=Jy)Hu;ǣxIDXSH@̃& aୗAE󍈱bGJR1v /$S!ߚ0{•/nx$Z%\7A} ] C>,"g(W7*$K^g)dAh 78 컺.u@;Dm<>k1DH"Z;C$fE3V!:e):aqL o9Qs2R3Jȉ`V=9/Sx3,R{ض/< Z"KHbK]=z{}KF>3BE0_D[`+ԫ')d,|~=cW[ŇtxC̯= U]*bb0HX, 4Mum0v10{lHt{߉m'6%m%]G 8]K랺R?IBY~ c7h~x8CQ.ӡtc_Aճīpa@]NMm+"V3$ ༚Rps֣! ;ĺ,&S:lh\lkUqE'I fz=XUPҘ|O䏠V3-^>;YIJW/˧!'] IK~vyI H;};xA5ҵ\mzepb vgQ|>t*5aqBb"B 7NhBxC6t0f$Z ~JbX_-df)@4OdM up5 W_'?kndA^}&*\/Nd{)l\z=,!'}j:֦` ѶWSaz3[Zrɼ3o6U8Ea WsO,^dAjwErlgEw1 –-;a:ͽo/vcX`4˕ wHu 5yPʻbzu򇯲dJ9(; s5?ur9/DyK{~Eʃ >dVJiP38iKѿDO<ǒAU4B)rMcΎ(`x;Zb/fKFnɉXnN>/gQZ\S`\R_ZVWZQ ahjjrqr+nȚbYqMT\}"'dM@sZ^Ts'KN\(89'vlͿldu3u6+ I3RdsMl$>"6sI23Ý =2֔:KrJL(l.SԦI웙X nPobTh*7Ɔ{6966gYf1lx'zt 9 a!RٓѳX /86\$6x{QbC EfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_9 IJl()=Y[yrdd:Y%)1lf%팬`'H:ٕ_"C7L֗Ao 33Ĺ@6̡fͺbn6EauŞlQb?wL9m |@nX;Y x{QdC3cR70wA \jLJApnd}i6 ^ba_q[f0& D& )W#Vx{QҔT}Ef=d̕'nl64 x{QҖT}Ef=l9-&M@٬g9_Mn*瓟?|l*3x!GxVOli 3m)`~@LbJSPIlnevY2cbpP/{XMx`bx1;_Fƍ1{~A0jceI"vyn=u5gzN%*8x {`'N= ~ڢ&WҩO {`sĮdۊ ,'d)pŨ] UkC5ijEA0.I'?VS43hsuH+!>MR&'i@ƫqZLsau,M>!(y,sbXZǫ38ZI{FYZ5rԊےG'޵CFnx3r`#B]ϣꪞi{Z_{LWNt33J1qVc5D5utЏҬ }ZPaA;Sgj7_b_PCsxeaPڸ<+ E7qVa0I,͝r>uEqNx944ו{3³ÿ~nl'oirA1.K"<} noY_zcefaґ YSN$Nm}l$՛Ftx:2?GwY8yyB>UxEH-99%t[A `C"R?1yBePp&F0u"9HPyjUl쥵EUe&IT&嘢өȬ\ڴ]hQ> -mAwaێj.VpPWo:_,׵" ?N yP\s> 蔛jaQԁyspUnj==U|(QcNOEMH__MCh;rZ58˽#m7go g|$7a{NY6omjI61*>cz4s${kYu8P|S>:]]{{ U}mpZ#0x$]b#GIQ~iqjQ8F1͛'?fvSKI,IԵKȭn铟TTQWZQZ颣 @XKYc~Ix}Z~ 9W=`'BD/#HToO"x$[bC27312N~ȧXk59[ݒ'?%54-OC$(51EA*E!9?$DABIG!#%EG!"1y59Ye'Ja&7l(y!>%9ٚ{(${pqLaT\! ꇦٚ3(5U(2ydf^f HD : ֓BQܯP=kz.ɮu$&ePQP+LάJQ0r+O*Qġ|r0 {?.N^FJ^d/> x.CbIf4 Ҝ[䒊Ԣ̴Ԋ gCSS3=$_!%?/uQfiVjpyx-]b#GIQ~iqjQf;ƿ\WxWmoFl~4եGl7w}Hboq|BeIFa \s=zE;o<:- Z0 ȕLp7H"k08J  5BHTx l#̣|ptO-3ׂ߮$ B4Gy% ZV"nq>3:# H?7YUƣ: <ܑLi(;2IګGc%L (L%jty(c:0M7x,O^;ݷWspIK;4͞ϝ5_ m6i$ٱHzP;r%;+]hoS{I"#aBGt\1٣ݳZasǜmO۹C Vf(y'jʺ.V:N{x26-pCg,\/c1Ğ /6Q|~m[H3 w> ?ΈF:v:rz b{\`0Y"KeؘĪ zHFz19Wg9(u{tT㩆h(VUKuKB(ujI<”@ * AD~uJ'M^ z-ST{߀"Ln7-el$u3ykA^;s4^)VR/@6CD{EtxIqEfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_ً7+e5YJ stIxp[aC cdgLOhn`um \$xQa'dngl8RKsJl&HNb<}? ĵxUMo@=g( @u TI;=\{pmVP;޸v7.;3~o>_I@<`d! G`$ d ח7CH2Ʉ#bI&d|U~uewN҅೹)b_$#$FNO_8!( *'5BFɬ&x\L9ZikU()GrSBD"e5 oJLF7S7pl!}&sS." (TEt츓GG~djaroa@AΫ! }CW?{"F4}a !B:t.Os;kaaWttav<ݎjzpڃ"NkLe"ƣrI9?tƃ>Ep3fV!0d줫9HMNJvJ?Lw=P{/q\ [DWjYe9"X{HNlq´ QGQXXC>XWB:FΡf_ #D"}%{h`ZSUÉ7p Ƿyre֪<뽒ژyYkUA=_X${3cޯ"M:c:'1+ʻ8'f5w{zz\Ssc/ x?@EZ(rT=clY+9+Y`[7dV^SZ5'2R#'Y՟zK٪<ۤ'=y%cxk!(8xs>ϙ'䒟l)ɭXk;9E'?%54-OC$(51EA5'E!9?$DABIG!#%EG!"i6ҌEH׈xgo-,\P?TIaY%32K\fi `i=9Ma7VyA$ MMj.b׳ME@7''v DeM~Ğ HZwNit#'q]@vv iEy ς}X<ã  $xk#!qs#>ϙ'䒟l)ɭXk;9E'?%54-OC$(51EA*E!9?$DABIG!#%EG!"i6ҌEH׈xgo-,\P?TIaY%32K\fi `i=9Ma7VyA$ MMj.b׳ME@7''v DeM~Ğ HZwNit#'q]@vv iEy ς}X<ã KظE Sx!|KdEfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_Yy+ek #M`<#İɍ36e x#|Cx#GIQ~iqjQf;y[嶴xVoH6ŜD{ɥCHű-ӊ^=Y>!UЖgg73]tF̧yrarx7wT%SARF8>zNK#ga"}ܵ ^7L z>ܛɘj bC ]Em _ljA/^x>mcv(8a-q ipүb1;n2W:Z/sd+UjqYU:ue;ιީr@~fL,{׆W y@nMtIC2-HMB/Op~TedZIC)* 4Nt}X雸*b B߄C ( ]d3FfS\kv4Uճ4*[-RYixX5rK&F~c(f/*@g,si+QL8{ N".dl, *oUM bZU3Zg|29vҭ0~NE|vã.hQ56e6NUm g" WH͏e<=3R~[{*Ͳ?(*\ UVGXma~)Uu7ϞL puг(;i3o̥Xʃ ct- f 7Sx;vFv#GIQ~iqjQ8FYɹ|ʓRKuss''2xi(d&(($畤V(V((x:{(d8C$48}CC\#}5J s'Y&ꇪ33/ $g(8z)EzzdOz5N7"&;0sH(exVjjrM.ඝ<ݜCt2?+&sL \ jř@ G,59SS{XkZOn@v$na[QP=y+*yıȅ;>ň7Xeb >8>5& {zr<q&a09HH Hk6Qx;vAvC2FVɹ|ʓRKuss''2xi(d&(V($畤V(V((x:{(d8C$48}CC\#}5J s'Y&ꇪ33/ $g(8z)EzzdOz5N7"&;0sH(exVjjrM.ඝ<ݜCt2?+&sL \ jř@ G,59SS{XkZOn@v$na[QP=y+*yıȅ;>ň7Xeb >8>5& {zr<q&a09HH  .sx;#+!"3MAC(4DV!",(32>9?$D#L/WHK˚ bYMᐘY{%3`Sx {Fv#GIQ~iqjQf;I['ڽxUmoHl~ŜO8/V|F .V8@Z~,`IV(3ϼb\0f!M`HY 9O3-_;qfS'_F 'ŬC}tj#ݢt0߿lOMP=.;@r6lTHj8{8"qmH- 8\Sy11{29OK4np^xiYPNeP],L%x]LGc٢p9N9_}]58p&0K++++h2i9uٔ~S`~iN|~:Y;,gq>zEi| xlʸy?ڵgu_(VTʅQ0Al*͋z fk.mW-QonbƫHe~Cx_$(8xs(ML;&dvVKI,IԵK͝Ek2 [RIFQjbjNBr~^IjEjBGKB3Dbr"99ZBfDa,Q\\9ٚF$CGA83=8*U$i ꇦݚk!=Zy%.@5Q0ִ|×IPSSzg5X<6Nz\RX n؉"Rɩ_Sx_&!qrɛvLȭXk;yd.}< ժԊ % WGxO gDs4s1̵d}"V_6Y745"[$ >'?9[s5BciIZqfzpfU'(HDӚ9M5dC6{ص$32K\6j ٫`i=./?Bd'j x.m]"z)EzzS5~x[$XxC=EfFQjqiNBrIE|YjQfZe|r~^IjEF3ə_++e5ٛ3rw[x[&Hx#GIQ~iqjQf; RCxZmoH~"HiBh.k%j r Xul/jfw`H[]ٍ:Ecn-tkD8 'D]8{@,/q@ \+\zq`b)}1a~NHJ)*B#XFd{qh8 "?C^y8o4~]Ӊ- #˱V7lOZ+8nX3=ygdF>L`َdFc8 q4|ކ9[ƒJ/QlUSOFC:_!"jpC 636#DDnNNƉue:4z0UR<[6{~fT׼.b,``&n1h(v8ݩ:N }#jx; '\su6kF*d0ah:fco9n2,dы.Үg`L@/TbƶO䓚qYOX0#1U=m9,{Jl?_~S~0l[gͲFT#.Hz1K lȕ!XvZ+*t눪>$C&3.սDe[dwX :Mj:ɶ8 T޻ N>bbn''vSO6V_|fF(w'Ӧ~@TFe#©gh1'jmDwzg6bsP d6;T'nfl?ܬঋWE$uv-K!v)ψJe̦h?BneW,0TTbG/#TH&WB捐 %i'Feϋ |e[gpwpAžow0Weڗ3K-Xڴ(E@Y ,Դ8g132tZB(pJGIf),aXS~\Ga2J|ZtO u:pE& jta,[QV3tmltWs+w[*ZzF%G"<9|~@vlyb:. PN"c 4l} d}eb۟ek_&fkU8~!K aj&UH'ٱ8(N^='nJv˓w{\H*r,wJY0uZȤFy+y\Oc]6TBjwҘf߇<9kUُZ"Q=-{ Nthwi~WZ}_Pq}1)}nlq܄? x;x<~ c=>YʸlB}|t2RrRb7?Șy3 z""-1LI IJL/6=7旲s;y xEλKBapv/hc䱴")4-4D a> FCD.5d}=9UKD>4f@cAo'xQ`и _G{M fAtN&q`C-ZI:H-ƳDb1REZF!h9?$D#L/WHK,ij\ٍS';oVD2nR DSzxV]Ofkc߬(d!M:*B Iɱ-!d_6iդnEw~`Oy|hU>9yyy,m'bAT#ըMeQuWƃITÓ^&@-̴ 3 ݔmk(&@1l2gl7ZY!NK0S "ϴ@$1H;aUSsRL-ۤ  knB]/J+62gYz)*U`*DؖG3#]R_Bބ#bZ|dňR6zl9$k-Pq{ۛ Tsk(^ ,ԤC TjC`2f\ vSN2f5Q*Eh\)kv [1%fV*1ֳR.S,z^RMooD(l|1# E8ٕ;;85Ėju.2SP&4 r֩Zՙz \ZMuUp[G49͋km,%fSjJA7 J(f'w\O:GZP:eRO쯑 HJd Y!lTl;@ZE/r0Z23:1xMvrm" [\:-mNy 8VYV|ìp2n6=>ޏ&"D1cqQ7< wz9ol*N˯oeb `ϱ85?H=gtƘ;L;NL}5>&o_K_8&բv<p~yPvI`ws%^.`nߧyŽgB6&Ɏ6ƫbqZv6>JW* uMMUE;0<*#/<%w[Gi:k4NCÕ%G]r q17.4j/?Stj y| \S\?8fpe>OkM>ԗdc%}4_Wu^ ad% 8гnOcy?! +&ŀtVhѷݐ7{NLٻsNguV]=e/w=Vl̞&d=밝u?mܕkeE1c"fjOv:QH3Ǣ.$ֈA'Gb]Ifȟ,+\A5dj's\qQ_S GlSU*G]^م7 vaҟsog?pJm,&^#;u<x\msFL 2LK`orEQtZJԑT"V C0x_w 0x#8ԝ>0/O4~sfgl܏îE5 -= Vl|y phIC0Y$bxgc~S}>c6a ߊ7gdND/l3qT2ع4U5cfw=t+z"p 7,n +l}L?ypzse~?3X7n21Vk<0 > *]Y.Hc;(d8 }@h6##sz~]OgpmH^fNZk W-0b.9mTԝ_[o!'JiV8P-whܮt /n|ϷE ;pvl 0"dУ БZ d]<\Vm+!J#JNF8w3TBCm& EYOܴ.(dC5@HGK_+ PbC#_FF#OuU.q|4L)71tŗC3GBY^sHȱ 2d=;yAtyGoNYX#]8Ɨ!f֎^[q2!n2õBH5qYvzHȤ¦6X5Vʓ;&A⤘#ѣ@?KpG\J>-LAڥD"_G~QadegAx.!@4OA`x \Gs1 \Ƈʄ4BAN$CL N4P_ 'ZKM: %̤TRnphLLx4@ \p8!O(`ς>Cً :f cEI /QAK#IF}8>:A24C;5p3L"ȊQ7.Cp!cQa,-8~I[_o 0TN 92ىkh- EQ(}lٛfy^ RI[ |fz72i~CZio Wr~Tq^?M&|1wwܡjT0=X80;j{~;Of~au!Ձs䕘s׃{! deQHų7{Nz{<`CG%}4ߟHMC&'1q_hsZ);kp8İx>'9(dg3-TA ăP7ޞi&PH*`xnv0`HKb8b3I1 ѕe„BFe{ KY!FQ`V -L̳&Y%V9W`VT&h| X< sF"ńMG&"Od?aۄglKԭP8B.gU\3kGST%z嶻rmsl6*3Q!5`0X?tO2P]/(A(DIdd^LgWcp^] nWK7>ݦXS_$Ex/BGxreQEJJ[Ls_I$T/L1X|Cŭ܅^;Isi ,`}ݲ$Hʄr%^䙥 cUVE/7iGSeg.R `{Z-#GQň+,/#,B0p5 1{/-ytɋ%E,N|/3wuܸ.W1΀.Gt4Rr:P(;7{, <~9qG& Ek}a{-1Qf˥ƊJERIT@1i= 'ب!kϢui+Ӏ>uLhfvDiR&5,hi~/ˡMۭ]{ ? kj[4ɬnuLej7T ruj{M@O#G7+bjӢɨqV6(*jrVL72xH7P "ɢ51" 3d!|6|l"PR%&t8#֫pXlcM]%1Pɶ*}-A*ȂA4 v/oo`t } r lP3)F(),wbǁUqx~d+"nfliLkZj^jZ:[sY N;G)`bg_P8.H>4(،9RHrf."JΔ= 9>|ls3{UdV%#97~?]KH;Wλ~G296կ)j7|Beԕ9dURzX0]heūnMLJ7*,:erjRBʹc sWSng3"J )Βp,h%03EJpLN#.Vet5LOkr_yu4ƾG rG7UzgDpR!eUzq3 MSӎñ<,:𫢍,ԦU"9ߧҧOv=5XWr]Z^KZ.s"y9w)EM,0զK? 2DLcq?o>T8.r}Uć%Bc9cA7s/cmFf%453p>8J*%Rc5iNZChHzBPޡX} a6?ﵴQԴ՘ Bv7ɆfnBJ*5 h>9v>S NkDtS~u_;F) G"ܧ\bZE,jiq*^n XkYŧ2~˃%![^c) !aMCd/VÁA٪f7cڠ Y)G Q_G$7lteܙp{?Y%!+ߏ#hY/oq_n-tXƋ>gCw5t6H3 PR(Yw.ϖ0XR6N4XS|]-Ȟ|Yu}-Q㪾E64Q@ۥ֙*=zaXUN{̒)  w}|Tk..NU ֓}Ih(PfYZRZUzF xRMOPul p3h'Ltd@1/>&vh6.L\yk. [}fH M{Ϲ3F> ";+?'Ne]|D#}Cg4u0VөrQ- .jB%3}OL٬[U6B`KvCPQfV+spܰ;x_f \ zSF,Ԧ |r&R |+ ڪ06|cvۤͨ9&bkFIϵ({&}ͧKleYf2Nwd,(Q݊fnH&Hq,YM0$n4nŴ{6n/З•?P ]y+q3-{&tR sWvo[}sqiɤs}Pel{d Ȗ;$O`zQkcw\fN<>ʼn\F #qYu8j@ FXZ5⍅/AZ_)}QUN+)finp;W0F*~]_ӥRL7M\hho1xT=l@VZ !I&!JM)mվVݻr>SU;H702ԑ; 矪&N,}}y:9=ӆޞ=Ri{iJ|UΈ#޻;m2ʪQ]ˈ|9{oKt$*ľzS<^PN'06F )\Q<(LAwvJnr#Z٘8n%sr0-.ѹE 8&umLi:v d'j5FY]D3FY!6Vt{p˶R\nvDİq &ö<@ohv&KGRnSe&jGՕVXZ.b]MM:k5x̸qs/UK2sr2J7)RĞ `x̸qsIn.N Po&3I)M^ 6f/,92̓_ȫd(d)*h5N+=o@y ,^xQKhQeS4$6cn&l  (DEmT(I N&|R 7Gō UdԵW.tҍ ƅ/)>wss >ּV šsv{ ^BI d#FZU7z-3TǮSf҂FEshLF*3i2/, xyxT]L#UNnq‚N '+Rcےm &6΅Nfꆠfz_ f/>&_PMwϙ{|s/7^/1!% "ְ畖0\Z,e*/Feqߣ)6 BO"|ˑFbq_xw4K$YYxV*CVЅMBcPUilՈD+uRU%e& d!AϚqH$N v#媱k,El>\ϙғr1w%K/9;~ĜcC[UVOۃg48tF4xh{ctevX\O[~ñ'2``#^|sa|썪Νa2lyiM*&a(5v!뮇:͂&1)Q(ՈF@睊iD1(18 0\)S躤*:l aӤ*6kA,%|+8==Yr'33a p(P'!| <Vx)/BW;z#MPE\O۰gV4wP0tD/ՈnLCX,3l_X` E{LM;n7ЃM@p cӸ̧Zb#.ъF5[?;͒Vo7{'@wWWgI\9EuEBW*2U[Q5vlKwc%:4ztMWNco7]"{v1:X*D&Fwt7CSEJtc&T  +r9aE="EƥTS솉P_'vFZw-]xt쭲Ni@۱-ҹ264ZNBŤ32t wӈh*P eme"ġ.(Qf0^ cX}ť0fҀ[g3y)K3 09.E?7><YT IUuG v\>"J+h!TeVT\ 6m*V5Xo<~55qV} B?=Y翻57YkbS?u}pVxX[(8x8/3[EnwxX0`2cfew"+jxX]3yv1VlVV~' "SxxRMLpOqC۱cCs(d$f .1$,aL<!<)Q/Lc A/&&w##[~V7c rqud^x0UۄixTFn+Q,QC?]磂(\K,''SL4%OzPxY7`KÙKj R欐c)x ԕr䏍 m0@S!4CχOJ\d `+2n Pt)r,qM&`A˂Gg;aHp%8tlR(FE99ASMI2JƲHJ"wz01I"n'9ӾPOMp.6f]V炐WC7yAuWdcͣ}Ӈy{V&G_mnaf`f&}n,Hy>]"Lӊ cվK1A FIg @kOڮ)yjըdn|[xj@iz xvX6E_7 )SZC.[-*2tZ; g~Xg e=F+$9ᮽ"p*v\# ޖ1:Gf5'gfٌ/M&;Yw#sV2MV-5y[8{21B&\\i %@щB&L@cI#k l?Ao3YD z n N ʆFF Z@9ũ \$&g-tm+0#-!S,J-.)k{=Y@UvNm:6(ɫr889*%;\qee |`-8TTE nYv3\xuk\V]#sRsS8992K*3R8'M^ κYKڋ gH?l&xkCdfA%(Z=xkCd+V} #endif1,"gx{~}IF,R6/rMx{uG ^2 pqr)9Zo.͸9V>t4x:uCPis|ԼS6ߔ~  *xze#cfL!nA/3WNι DoZʸ>wq*ɹΛ o22:OgQL4ۑEkr.Pgg%E';E&O? RařW9ـ?hYy@Sr$glV*j6+x;ʓ9U9jRsS7}`d⬝1*9s H,Uv3slCxtisٰq^F"Yxtya潌&|GdgV 5x{~}/F[ɿ'd)hhJ r KJ3sR4&3K姥(T8'(;x88{Fpq%9d%ɔĒDMMMԒҢ<U\ 5-ox~}C8T%0ax)QZ\S-)ȍ/*,O*Iјl*VZPRᔓY䙗Z  @媣ZWWRZ Ԟ_ZXZ3YqrR_ HB w$0^dYXpZ3}3%1MuNR)^#qgg8ȥ-id+]{d=o,S7TY?5Io>NEⲿ(Jξx(؁Q[PG޾ MjrI ]w[L Ǎlaȳ`gW 9XuxBw'ݮ-@z <-e)t:puuK1˜xZPe5vFS Jc) @CACsrxh,HR[`SF3T-I4%v3vFɳ ׿{N;#D4HBK<~O1_X%Gt̋t,! 3LICqy%Eqd}wKSFfiZk@7cPnTSoOtj>[+V}ftN}/4]X:鬑1d"^Q eܿA y+(9 /4D~%.mʾ~Nu67Wa2`X٥wɚN7E׫Yɭ{a1ZXX7@&7& ^&x;M19acdCT>fi:|]UD)e?-π9cOb4? =\]o2vOb[K!_()+樂۬K5b5 Ui)02f Vg|,a{=* w m yx\uCFWL;+C9ǢDP̪T,^xpqlgg4F(/.MrNaCU#ۣ^acP9^HnΘ9&ri0e'rMk 2=x{HuC>sBIl8l˩ }4̽xXnH}&` ّ/ Pdy",䍠ɖkԲl2{7`gXlVj'.H"V"K_T#&+'J4p 9i)@/&HĤ, 4?4~poRXj0Z&чLX(d:NOO\}) BAﴼ˳ڊҡL6R/6HZwD+uky駕|(/Hƣ؄ZQk/H)W;b xpt,@&ܞa# 9GSHeG"co9܃{QcҒ87[Pk~ &24bwpͭp = ;n@Q2W458}"C7b" Z'(B0]$QkG8V QY).cu)iƋBPkI9@'Rѝc}IaQ/e4%Q6\W`$&bHyg,ؚÁD/yšS[Ul L)%B):/s$8 s+TZey)硘ѹ7OW TRiLj*UjR1r bOL"&#Ѱ7'"r'wwIܶKOdf/E9å*ߜ#;VzȊ%r9@z: fHEQiv.M? _FY*HA(f"I,b+"<dTT]16{[ rϞ,5d0c=`tDVPrZWTl78lٛf7Gf4?.7bf<{]fb;%Lkhk:NRx@AU 7GhK]O8 so4qoDGR$EĀzX E {%(zpndՊ:`g*avTVKR-aڐeh?P h8ܴx+K!4vJ< D[<ЈH0sbx3\J^`GQ)5E 5TnեC%y 3(ThS8 ~y T̓s~j+}3]78ɡ:n [v "\;U Eݼ @63$ܭθM GAރd2qo&9.$+me13 N^ x:yHvaY3ĿEbsџ +Clʛ(wb<\cJ O( .C3?_7GVkM]qi Lōa48gM&68+|BƎ`m`7T߅ 󏄇̠Sa?#\XZ}/gM9531 >kTpøӿB&$,xk`.E[P55브'?\ŧ =[xk8`ɏEd6W)s=Ixxk`CR\ܓy: xmpX'3dj0s\5yE%) E 24B\D؝"B\]&))J+./*, 49NK uroAWV85'm!5q?q !A V n>@ӳJ9tx;GwO'NjoVZ jc4x;ߠA 3>3$(/1g"O'NjoVZ  g3xk{"! nDxkkU!3MAC 7>7(3X/$#"<@s+*N'|xk0ዠrf^rNiJMAIFQjbe&1 疖Vė($'T'g+*x:F{yx:xFmgZ\QRZR\XZ]\XPYZkWKOc UH)N(#9?/%>3/DCMY+H\SU 63zp Ab2y8pI1r5b5or/:\z<Қ#KG9qZzykˌ`||(X2UHA adN~-dԀɱ}xWmo"7i%ZU$B6- TTO+keY#ۛW;c{.p U/BRW%q-[I%$_VtZ( vD'/AvSac $༁00Rpid4 ghc.?O 1FxM|õ_BO<Ȧݨ_l9ͥrs( lkiduqKS Vi8(X+?Z c{NΙ>rSr6*UÁzbe5[q`gNmAUwlVIe l魤;L`#2FZM\4vTK>J]$ .ESfjUG;.J0n]dT1G/jtmf9Xg%1L&3rdCLXf`O ܯNxĥ.\ff\f%%*HC%!hkkhwq/3Lb[>5/gM7?s||< UD0e )ңz-]0+z,b+_Hse]UO\Λ4oلɂRcT$RR5/'-s4L;Ot2|x #4.:+)PApmP#MiR/  ax{-Qz#GIQ~iqjQf-|6cbuE^\iE Ee ɥE R.;ĵV@HKtR+J48934Bp)N>ծ9bjNq*P ''.d&qxMNf՘Mt36 z'rl61cA(x{-\f#GIQ~iqjQf-FG^]l3x{-sLpC&f>XV!' Jx{-.4᧠rf^rNiJMAIFQjbį&G3f+V)@esKKR+KJK*s7`ld( $6Mo F1T<=6ͺ<8 X&ᝏKڃO)J >x{.[zT{6bb|u2KAQjx.;84@b ɥE R.;ĵV@HKtR+J489'/`՜|]-58s(| Y96b1 x-Izx9sRɝ22b5E1xXs8mn.BHۻOGr̐M&[Hr ]6`g VCxM>5 5 WfrOX>Ā1h*ðrbLqfWtePb:3p!cTk}BN۷&b?LgG4!$%:-13YN E$&ڒo4mDs EKOlS#jYPYD`4WlSKA t#"y0 oShE˯pzwDgka;  ~PgO hю-`;B3ڴDtHx'cs ݲ (c[!јG9D ^*u6Q#3zί_g782Eήeɰm8,g+ک#iN}$BYhbe7J&(4Ċ?~wg_’ h*+r1PڔҼQ\Y-&aT BnE<ݒ)蕺ܬ '$s(h{dMjή25H1ԡVO0* 9\s%gF8m^3ovp; ƒAdb_Ḏؿ 2&ۤO/'*\5V.)UA/1 KFD/c\@$;pOM*Ph؁7 6A!-rhnY)̼ N- \ӕphžtƸ=j ;RBuZU_~-weW"VaӒQj l>f%Q]}"h@h.asEIbhkT~ɦib3q nK=߇1VC &Z ,_%̿m85[Z40 r7>up΅Nb@h3$ҠpKq4#Z NpzsH0R0fa.fPNBnoPB]BN"fKDh74n]FI>;՚O0'"b q*)qqw Z$c83 DN@{]s+ɚ t~FM4ԡg <#"4&mP9g6:4A2ZqEͭ!B PYg,5+'-Apqi5ʆݮh+ ng/P0߆;88W7它 (^ϒM^TJg}{Jx;Fc›Ɍ%EũEśc0rF{yLVqr>pVVYŀ4/#&ɳ&_duwl"ϞĈ6$ u't4S#[ Jdx;Ac›ɌK0rF{yLVqr>pVVYŀ4/#&ɳ&_duwl"ϞĈ6$ u't4S#[G!+x[ZcC8,Up oc1,! 8[skC%KNgs1AYD.KiL5s wd~]WS^hnLSaē3 |#@9g s IDX%(x `7?eEdt_,S[: c"y\S" )+[y8E۷*+iB}}^u]/dUn]~D񾠾I0Ft$VdXl:!S>f|0wDfDq%3"|Glx'!,sA!E[7F'ZkQ|#m5 rZcpp~pn8hKN<omAIci3xh,LiDUzPoqC=K J9a#<ifzm-i 7ׯȋ ^HBa2NȲXtA*{kt#UT$|f#]eb0^ DI09E𹢔XT⾃.,dtDLb f9DpOD [%?v+6_foҩIERy>Bo7rkQ ݤB?@{ O^#qkizΪ2GfW?&q0 NM)1n\xg(]W7,zh$10'ڭC}t2 #H`vC+YJ]x}$ZKGJ, !$& S:\bD">T}a1;V[,uaƃZWD_<8` eRdmN21Tw$uW!D|]c*5ZTqSci cbEW/xUᶓ65V9(YV6;}TZ9RI{UDmCzwlS,f%Yr9 ̊9+Z4`A6 P,W-~`h!nZ>;(Bks0\i:x>p;$4t$c8 ɇ+ڐ^,.?XrҢihct/4UzmJr˞{ QJ6Ԗ ΝJ)ʛlI{'U*:{Xs1RUKѧ4 g ϒۜxM{# 5~Z4t(ؐ(UȞJ1h4otc*^k+B obv:PɅ:S6d $̰S4}nm YMjiJr?Gg.Yݥ{[T'@q4hgG#75jB]ɢ .i 'LWӫ"i"C&Th$#Cvy\wuV/F-|r\GtrE5~ BjʈUI|GP|x7 NԲAl/quJmV>-"2%8LfzcC$ez(TJKpK~JNb陃Ƃ&]©"@^ 7U݆w//jۨ,WQ!9 Kݳfԣ-KbuLqk=4pv^s R+g >[ԴT kZN_k1sCŢѼ`:'[kg79v#ac<9W , Ǯ2cHWw4_a-k:6JGUB#XL.S_]xdrxmFԢ}}<}\2RrR58!"i)\\i i) iyE ZEɩ: JEJ ~>> 7AO6`i|dZQjbFAb:PIJwlYXғDu8@AAa"('\,?7?Ș6yo 4 pVɦB3&Ɏ¥ey% jj Z fhJյ+JOK9Jy8UIDC\69UraH!6WJpxddmFԢ%f$x.44#include VFb^JN&W5'D$-Ś33MAC#-EV!- 5OC#9#HAK8(9UGAHISSV/Gar&6:,͓6_gy(VQbl`pM6[6dF.a.N0-΅P9۔1m 󼎌i3Z#q!*^\8娭e5XlB{{fEZ9׹lPLOOӯ42Q"pBK?L`j .@M3G[SDhp Q\#5I}-`=:nñZNg)DxERE~gD~:mNi$s_{2GԆӌv9jv?|D(Ү4qr4e^Q-zЅ9e"u K*.|7x78N\m3b*~ECPG?xV~ _C1"nyALO}t7)D2W yfQl`%}&A|ĸ؆>*+8e| %T)Ah%-B*u9Ѫԧ-{0$Nlf3CK.ak1=2u>`OÇ ,u]^e+ -*h|cs%|l8[lED6a=aOblV WI *-"9T7·1 &W&Q(k" fMH+ɛCSM9,tC6vOOoE k Lw\!kʈ*"gݨ/[ G@V- Q4HuA6~\Q}pS*xG[z+Oa$'ZWe2P b&͛*ʚ\<"ik:xnzsXvv3HeD ̨Kݞ_B9s&wpullGz/E*@b5lGDC%[ڒ Cf.k1PirgWC>\ñx?*~J[mp>γ_Jaĝqh XX Ze/7|/vXU[%3a V!6i F<P⒭3eA UؔPZ[GK*vh \4Q||jf*KDavAs6M[{ FsUlpno $z]u2KpKrUĊH2/pU^1BKԠLvt/[Olj'Ȍs9xL*ױ5=eCbpd\4 [ZlG2pq5y#DzǕAe[E:!Pָ&R=|]gUSšgjy SwRYox-oIj|(CpQᡁ[~AV_v%leu OX[xկ=:؃i)%Ixiԟ!l8 cg/2UVPy^­pO eVq)Z$vxUk4ؤf%8y7xWG[w_┚\nV V[gxWKoUL&?j'}\OfJlҲMNP' ΨΌ5Y .*j`DA%T$V ν3~%N7^͜{y}w۵_k؃bl!e=0 P@mD-k49<,'j2J'I湠5cw~t}zY@&;6]U*߈*9J1ŧ$%᫁Z}@`DߝtË<9CXY^u0Ðr?|; Ҁ_A4Dd}bn2:Qbcd 4,RTRR VYdBd=ɪyZ2o'yx bx̃S5S'Aup*l5ci,]:aC yC9o< |؀Z72hqj%f:YWAqy enNa}-X6f s%{7eicx:tUݫcRlk%Is'{uaT+|lL&&Z$S ј&G`B>2Nby` jhR/;Vӵ8YoT# [c@ ; fpHgo8~\}fS\4>k n-o| R^xFk=zS= .5Fưتr9ў$/n&Pqb \nIxv:y)KZCbHĊC [e]^n_ȁElgF~`fP3Js ~La-?<d蘻==ۡ_UM-g3-u;VDM2{J.AQ ؒL/{Bm Hߍ( ]q-{kA~ʮ5rQWڛF)ywqOsٖ i) 'B&Ʀ1yth1r^J>4.Zx{tkT9JKS7ez6 Dx{tk<72Q@6ax}Q1LQhKjK-Jik9"6@W {\Uظ9:84 .88:cT'ګ/o=~(c)XL#dE)w`%C).Mvυ&R@nI2xrDiP` Y?gg擱l:Hg^7d|z.6O\.ZLTAl6gQRPl2:C˨{nuO~7ߥgc\l\*l? (P *E(edWPI_kP x@q~C1 "Y$ d *D!FpA4U>1c |zj8hcm0gqk_~; 09_:#uF] q0<ڐTRe0_Kx;=\y긊ť9mڶk ZXp׽_5wspԲ,uy_te0;j,M?%Gaqr2&9g ]3{!1P'+JCU~l Xx;akL',k0%E'7d?Y{Bj'7+6LܫktRKsJmBC]5.LS $ r?zj] iE`TdsULޫV3x;uKͼ,LM7?c"ə[Z`PYo.ia1/(+IPRMQP-VPQH/LMO-K+)Դ₫+|_Db?50 }V )`u(֛W }g;p]2. -̘uv:횭E0pk\aXQ^]U(wDxLnI,&p2Cnqu:O 3* χ^m#n\ó8O> *\`&Ǿ;/֨ 츼]5XAk;(9=X8x[T݄ߎN&fn0Z.8o=*7-/i~V:u/"E:GIК Zū\% E )yGlLl%])GW?5DbZ%y#~|]7NL53Ml pY2I<:: Ѩz%@a'3]̭ G0pF1aheV 37mԢ&nz"՝N ?V 0^E|µ8ච zikcc4'`^XA0HTfޣ&6^ir0ey}(֪\5Ef)4+ 9npAP{١+ACHvk5i:?ѝDgX$3ʍ!hVɅVxڹ6}3,~l2薈$ъ=!tX5*Z^; Z|[Sl$ۢͮ4>(bz$_3S^giƑ6z.6ZgZ'5s"D+v>~6_dB2>=oNDk1|ѺN,汯1?U)IDAQFME@z>c:m Two Aq 3;L9;VHa O5E떱WfV7f>:㗺HG%+Q< ~63Z(K XLd"j%W+~J㇃}r዁7#XrY}; > G(/~=4Oª[[<xfBڠZh3J[8Rx;S00ߡv*>/ +`.pJ{T4oZ/ܝtj"E$Dhq-VXaƉ"TC -y&s6}ܑ" }U7N Mb[Ȇ.9X3Ul-6z3/!rQ5Gk0o6#;/K F04gЙ[Uk6UojXbDІHrp=L'6HDFn2>LzlϏ qCPlh#4L~1@,/k W8tl7h_JO)UlY,JK0r)j]!nfp`vZRfZbuѡ&P#:c|e"Fm|EX d>|<3ovDs1|:N q1?u)IDAQⵚFGu0OF"4LSw66^ݾx8NgwR9B5=x@]|[0gŤ+W*3G_1?DHjgx{n1mrܥy% 9y\_3g)h&hu u3R4\MME[ $AMMj.NNNtע" %̜|I e [ҀJ@&; HL^&8Ks2/r(T`'@YEE;R2SK<A"D,_rr(*8Ner!17R`O DH#Qͷ!0d[^6Ux%'[fRVv (-M%_Xa;m^"3Ulb2D&4t> ̂2Lq, HCէBkAd>nGeI'L% &ux{nq|C6/IdJ+JMH-K+Wl2i=2ɻ%=& n*g|K!Zx6m.̪4fLͬi߰2r9:;O^.WY\Z`k_:;F_d{{Λę9|Oqs?S-&OQ]Ih=eW6FX. x{uk>jz?o{ıYMޝ ' l'xuk5f;fY%$ixZms9 B: mCPnryag8nui^r{cj~[^euwg܏81]Nj  wuphۈ83(؆3l,'l;{9ֶX;BwYχ%|'v6r}Elpd?Bjϼ휳8tesFkӝNk( G1-ڸqik[|(]jaJbtCV* '3:}S,q AX;T'DL]I3t¶ku M! OkHc R:e \@!|RE^ X4ؑBuP\@ `{/fº(4%C( f.9CWjN fwيݍ`cQ E9dy1]aAQ6&T chEř)eBN(BT[ VAyAѤFdv|cS<\!H%Y&.N٠"б9ˡ ƀ>b &4E ɉcdz[uGN\;ȷ" WpAtq ݭY\4Fv1gƃa׾\a$ޒ`dTfQy"qIi:C|e~;A(]WPD6?!~|:׭^۱4S=u,@dቩptU^My2QH"ULaH+$)U#zs}PЍ$#3i <tH,pdc$2}=U*Nh>/! F p M"D1MYʟ"EXAe^L clj4.Z[oNE=ϑV Ϛ'A) 8pШ6 ׌k jJA "gn1ВKziO鑨Yo욶@A' <`m#T*fuuhVԅ\`Nkr"I-AqdaH^k f5CjH 2&P(ﯝ1:HC2FXp2Ncr5`KZ;M@V֯bh'Cpb>]aHah`"f%GF|UPW(ެmA?ե<)) āć E *I7TвoO1NOYV;=\PjLyBq&rҙEXЫ˨nU~Lykx* @^YҺ\N4"uL&Qj.֓"L:(@P i)Z dsQ@jYb;#І & pQQ\)?_w7^Fz3 xYnA udH&pОU,v(VzV]v CX- ԲR[uA_,ҔEi>Y)&;ށ6ȀQĠ)abF67xQ=;V|ٻ4ei0O+X|#XYgQ!DzBN>vG'%⫅ MtGTGZ*ґ=r#eXyB+{g7k']T SPdb͓^)ť ;voTh\Zĩ[D䯽mm]3*^yyb vjpn\~8;p?@*e dE,};&xHLT`j2vqs$"lڍɱGdRI<-yC$Mא"/.uBN{?xabNGN00чK=7!RKm7GfEO o (:4^7hd Ԋ0"1jmq͚IZ Kw8LM-6q4&­UgN$ %PxJW:ݫ[MDK~fK`tKf.Y) {h{,O#?_2zSq!|BJo:yJ 8>P$<2 p$jc;{}@x0U(#FVіy^2@rNV" ֙lG4^0gtM)7EA1˟~B[{$!4KV'Ie16'L+"gϴWJ{X`gS`ʷ | ^}\)ޔL la*h2_ȔDhFr8EG k ?< #J]Lc*l_1 ^U  2@((9D6S嘳7C# I#5[~#5Ĝ]Sb)f:\A[R;libH0А)6f| L6A!R)قQqH'T)ۍu.v*f :! bI|xmΟP~}Wa!U>I> &d$q˦G&Pp%iq}yo &Mf0]tnņUnW6M8ʬ,sg"G'^wx2l|7 {u@$vi>d%o\zu֜^f)o !sqqE+{o!2"]f l 7gH#픵 55}+ j6Ꮛ&B My@90Ϛl hˠCïI, ~מ2 ҋfK—9H3> R4c䵳3]{9Y [DPw4n _7K,,]ɫ/ck&rrQ12V;.%Lc[lE[O /9Rac{mu=tJP.LCyi"<|Dɔ(\[1U2e9'$2SƜRr3ǦiJuUT-GN*o{·q0 GD~(/.!X~O.)BYGFgk_iwEw)mGR.Y:a(7MBhgߝD$~V}(w]p8Gi4 4-b'U$ZU)x;_tnɗ$lΕJRKlFx;_:dnyR *]x;_zhq&'63/,vԜ,;YYw)M0Wi8Wh^N~bSN~:!@aA~ Zj٩veE\t7Չa 5GG hP&W59̙|_E~s~POc#t[k..4 4HBnfzQbIbRN&''\qBHpp{{c5Ԕ̢<4!\]<\CN4,?'$3'K.q ?yLdKef9%i6.vzlUFx\tsA̼ҔTĔ{\yJ3JRs&X Bf>'(((LfV(.MrN,IK/)MF(%$Is~i v5 \%$Y8'V/7Nm560CșAx;c##dE)ɍ(_iڰx=ioH_ #_b<΃#;!XX,JjI|H-IɦD[αDQ]U]WWu.!R>bo'a0K{ d,˷fILy N#-"dM֍]p͂h7Y;^'dNSDAQ0c/i4S->{~xQqP׿ l94,0ϖQ-g5]İ6ц($=aG ܃<$.q vÍxNmdӴێE1p7ݴߝ7WCz/ >X>A,Zgy_`N""Y3Wl .) 1Y di\7F##e1)x ^D@&qE<9U&9'g[иƘL" Ksl 4"'dvX`U\TPVX6= J%L}:~ m63YLHpAjFωL'c/ nۻAHNdѯ -+A01ڜhz;D[Q8 K(Ao0#.dP=ˆ>mLm "t{yYP~}W&1(d6k }I/v$6k_]2Q4m| vl]|mF hMrKrTwA^TIS7rfJp@n[zN!\zz9E4s&D::FmmW@k;n`>;5u *ͯ-/I+۾:w !1>7[0m* uz5 ™>̞fnc[@rhhmmbjEDwέI:[ffjR=5*'O3t}0 G, ;qC r1 27n7%/۷?x$WzΙ1}pLHx,d( +賘/U):Y`T} eE2tZY !`3O t8ۤjYX?u* D5+u5ςAuFW8p)lDD8l|R:f\㝯.~j|B*YuɳI1bՌ} 8b@?G z ? bF i2am5;(`nQΝ-[QR` 3(D>\grvzqvϋ͏`$dDv3rO%5Jp2t @ N{HYԾ?Ny?*M{f{ݕ.4N0jo]Jt0qښL1yӬ oP! q`NX5_kFkYh ly5i6<$RT55U ٔU=="nSi" yR$+Pؖx['ʵȷnV_?n1;4a+9juGZk4P#O>rU!fXjޟ$1ש70pr, *26+Tme6guвHEyVR!P($K;6׹XO5K]3",-X[iDm'a)?W̃(tI0ŎT k1hI^=(} zNgZcD/FUm~ K bkU-^ɺ !wP3> Q.  @&OV w_#d2ȽPQO{7tM D<씼z' AԢ+xራ2o\DR(.Гxq2hRa1EDwߵLbzaŒ",ٜ~Pj $Cl LAPuBX6*p8cw4imtl߫$ usutG2m2Kbe ?S:nEd45p0N{Zv9gqDSnd]%čkE v^SXhOoSㄑ-݊5F>\^kfOx]hfj#u*:T5![p{ K H4KɄijȤ]RZhZUH=~“;Lqf ,JDa6p0^Ӏē)]_ Etý?";# >GE(sMP{eB4H:^DpOosF(|ɗoD)U+n'y_ O8AOv&Zؾƕ6Fn#xxu[|gX{s/)gY(=г2I_o-f$~LԃJR7a'kV^nntIjP?(PC_Dk25:g "HS^j˦tʅ$!̓ |CP亸+Dp#Ysuh9o%|H2gpZed7?OSE LjQ!\wT_Պ}uܩnUa;ۻI4Wn ]Gsg%b |}y^.!TfLRQ%'oznFQo~ %V/Q4wuo=0Ĩ|ԻYZr/:MI]\8`R/ξAz 4)ƥMxܠxjqky,H&\Vx$ ^GVJDTaP0n!KI6Ex"xJѴ+EM.rn‰-22`aP=ǧN)F}A "T;R~%w1MnEuRd;޾~l|+2MkEBP?ȴqk~y>́fr7ČUs\A?S.@r*-=ۇ4OVTA0yY˫}_^Z7'h)DEX/:{VK\8 xp\!՝v^Pgb׽c l5l {h w2ZP^ЧϻwZ` 6LAd&S/t8CRcG4lr`P4*nXJc!Nn_+D6hBFZK!㿅zF n;W- o^78^8 [XMP sط]$-"A)@u'tFpaDyҜʷ/u\DrGTW ܓwy.ZFFDgnBlj1~?UxߔV^*xA; [`?=jP+:cv9R49dSԡ_dy(]EL nˮOE7WJR^܇v.|B~9rKYV/E1(%iqLj&(\>58P 3L20#OpPSnU<,}, r*ytJEnƦc1')B} VG&}!*G_eVL8Am]b]0[I;7~s bCA|)73nl)PDr 0=OI!H#!컢Woe0즏!ZEP *RrQ oeقO܇c&gZ7<c'}n%뭏C1k=GA)ک2V8f"[MZG(v>,wR+ܾS1OÓ(kA-sM48+؊ U<KBuF] ZLF M>ys+FORsquD[J?-jn[rUY&;X>`+NwKmjm 8ը~_Ayv2hc$ehr},G(R 5zV9wU ކҎxO宲-9inTD=Ƕ2 fE8w[ #1[xj,Yf 2")>?"N0{Jd; .sajBJ|T2Sܯ}ϒ((X8zo- ZdxQ0dY0qo3{szZCΊu4}ZKi/.0 0| Sx|s0H{gF5x??wGXEk7tҞX!H aH}_vy~}k}pd Ƕ_Q[,Ik$ϦvNTexNJ vOfCq@*-s*R(yaP pD=أOS 1 8n\g©|!#_~%uöJz\1'_"(a@9 kMl-6 :*p[%?.#hQ$;v@,c<[r}΂~  TՋ9U2*iEs{)Wq%/HTrM tXJꞈl평#=JUKDx[#㆟l-*fY<Icx[q{ 2'/Α:K|,1CJ$.NPP QP+I.NHKIQ(//-l}mBqͺElI^x[q; r''3jn-c $xk Wm'mN"1٧orlV_FL>QYZRZ6{D^*+lx{l]Nv_y6i/ڮhl۔<&MJrq8w9i 6 ?M@i`$ilB i 4 i$&|v$-lӢ>}ߩzƵ9U1gZV$YU9嬨u" އsg N!KE!$I2 ggۄHi*:6յuM(uiABv]!'33#$2=NkM58RTWBʦMxOdǙkn/՚ }R5(Xԓt!)i\EEJ=zܨJ368RK%9QR z݆yNMRRIϺUQϩIDWiI#OSDWH"#Tt#2"IU%qYI5S*cGII%KI6Gʰݐv=*G*DF5ZD <Sª>oab$Kiʟ.K 0|^$ʢ4*Ŝ[ͷ َxFwfsQq9Ɩ˭Cl>E Q2ԌI!(%t`aĬ|/A5jlg̪'UFh/*пB[A{y "M t 순R}xd!2/lns`j!,ep\%4f|hyK]&Ɍxt_8tdIOD8jDBԴT.Y}7́Bع$W}GR3pjWNSc٬DѸ8r'ۗ g'kg[U]Mk_Bc8T#KwJ%kPyKkeJ + ^jK3A0>kgt_2Ax܍)ptzJ|<*{Ą^Ѯ@q7;S韘c&`8TqN#$n7*n V*zPX$v-X;R5ѣfcZBBKʡSzeeqZ ՈGLTF=of"il%<4<.~X7lYUXn'5Ãc+0q|p[~ضٝ5@'c*Jc2WM5BVkCSMb`X=aGkA,j4"A3qz>j7,(b|B8NZ2zDF*H; Cc}[v3Fa$fWˍ;ϒ 9ˤ*Z* &xl{]Zglp6 L[j97d-`Lx9ƙo9sQ븁iJUHkfdc[bgD?ZP``kIɴr^-&hj4W؎RE>+L84]5jXZKAU\D8tt:i'u黖0A5٭/a >{_<$Lngy!-,CPiVx8LY͊l*s1i!ӛ7Fcy+Ԯ9KN.o Im@pMDlDƌ@A K,nQREYG 7Cr$bFeupaZ0dO*$gL]Pמ^ŋ51 OOcC?]F4 b5413>Hp'00231yqEOp sKFg7S1zjxwaQ)k9ѶǛ6!/4 7Q]xVZ{oژ#[U]g.!aOG6&8("hƒ$5Z,p p$Vd߭ܘ?ձVJ{T'7b9 [xSNh˘U7K/Z$F'{T/J:GdY\xQg 5n1Y[D\5S(d@ Y,\^ZM zrmpap#,0{uB5\.1/LARV@`qakY)f*xeY:Dis  UoVwpw[_H7{7*6{(v§03|bPP䑸~mL"~A6m4O2.x~'t*xPjhśȽp䃕]-p.|.W7GR$3,f=F0E^_c}imC2>B^7n93 oK&Yl oAX#rf^^ܙ}n?+k7F{6ss5@թyIt^xU53gv  f ;N/(d$\gF fҊ 6d;~{kBi#J|7*&QdQ= Gys<٥A%KJ$O&:xXrvک]0qM=ڳs xa!2C, '%TpRDԝ7q_- X@NARlbVWb9[OÿbJn,x;+ 9?=Fx;+ 9?13&o. x !hxkPIvXbZInlͶPAbm2KR@KxS уz{Vгf̧}kRͅBܵ{Z~q/UNx޼l^]ѽ)c'iizق:ky68 3X }i.)) E:AXy p  x2 :)͌o'X а@_C+(ZxH%șN(wg۪ǫV7Q >O_ c 7FŵN*; JF Pveӳ倎([oC%:uݢWsp_C/Pa~L[6;;w6һZZ[q*fqy}k(`A,;;T5x~q?dcFiL-u6Iod @*T \6e&q3q>7sgJ;SQ`6]Z!@ mf-'x{q?dcF\+ ECxuq?dcFFpax*Q6%LBj%vI9IvIީ=$6e?È]dtp5}x&?0f\!<9 u$E;A͓E&n*̹9F=yWT"\OVon~'YyrdL[t&۱*N\⬸&VYfm>j6y~:}6oa+yr$;DAY"jׇċ-Vg3zx{qqe *M`$VZ\S`Z\Z9(ִ暼@WiY6>+x&+l^:GUx{q*VFĉj73v0ZA)%% ɉ9 !A.!~!>QA2ڡk/I.NHK!ˆ̥.(M-.I- ]\U;H,byp)v-bUǡo5.v6}Ku0rQ \ROE'awzȯ5p)2Xbni+E9qCU0v{tgz]^.åi ,4NMk..΢Ҝ`2 qw-L.NVTH_;ɳl~i)M>`P4-a]ٛL؄?NpIuڇhG&WLVpټ%Wj,ւӑS&GqNHu !F@nO EE (x\kluv-aR[$jw$T$Z2Ki-dGF5ՙYQ-m4E?HM2i~4 iQ$nPEHB9̝}HL(v9~y?DW~緻vRd12wm}16d2rze/c50px(6?nYkg-VՆe3)v 챜[:??u` mL/?rnn6gܷJ#c:88?sɃ|mig4&Tfyv)\چYdf>3WsJhpYjeI^ɔ~ـ&e"fV @fԼD0Q+)ӬÑ>9+o/\/UWװCRY&.8؇`· uj⧅0<%n5c}Ǝ:C;C0eEݚ_CS#ȇo'= [O -n=hRy`l&%?P1LSRP6+q%~ɲ8 LA'4dZ\lV3ugr7MvEիrQOV"tQ k8x^+*SԐG lc D22`kHCtk> J`%v u?|S@`hiq93eoY O*KgqVsKRBt mrQ{נU@  ǝq\) kɈvSu6+h'NUF{?-Q(5XV% @͛*U@MUC'cМEcL<(:~7<HuBg>k2&I*A%?oF04biP?7,Җ!L-Ҭ#ΌfV̟§ѥeSN{ 0U{\$}px!f,Ca>ů&`L<ǿG3mtGkk;=3 w4r '6;y嗅YV[e+59xzy+H/##,|j[wIЀ؄aTqsM*՜^.T=BIĖQlSYv2с?'\\*|'[.ͽfL*z$%$L<́TXg K:I;r\_/iQԁR1*9A5X讫+ ÒFu.yltЫzWg~-&S4l7%Pz_ŻfBd8Egl,"VnX/.Tm|b^@F4_Ʉ{#_;AZ]6y +u Ry& X J8 恝aDOvQ3s3~b/8C};\\o\8;‹wӿ q/HeKGGB]{VވN~lžW^BrM'FǷmdo]>j/q9T< Nr!!I1s|}lXa[41;F LH '9~J>tq?#IF&W?;AjX4 38R@{?UvI!79pA $H[brQ&t'x֓3.aɑab-qA  RpJ8 ɜP(hɞ!PY&sEbD!7MDꐏ1Iᙷj`@T -f''=w@Z\Sڂ ߛ_c@n]lUJfxiP=|Ͱ:xXdkzhz(S5SpRyл햙Խa:y7L\v;rBF[ze!e^,^; !@Q{CJ,NNrny4&g3xdG-ӇzIjN%9nk D-re@|R5oܗŨ0pXyЋWhxD@% ~z_&*}E$+Hc+~amO> 呓#הO"p DCmpp 'Ayᡛ8.ׄ@ FHE,2i/ŠC5zKtV `NMۧTM\tb::XyjM 畴9{@bqPq$55Hv&i^InB<=GPOI TP"tDj D?؎t ȡ-P„[ T/E,W[ʖtdښx BJR?s7xk V'[KnouJWzO-dxM_HSQǹ?xS/-5*H]EYhfNww-d!jߧ ABqzDC!4!襳5r|Ϗ]}G'^>Vx\4՝\]L*bP)gXNL{:A=)*AHqwü~hiv#1wQR D' m~SvM}`+5rGHa_$/IfQc2)tXzX5(t$q4Wq%R@Ez'`Y,%M%-7-jj).MKSm<9<}P;#k_B rJC-=V:kUkv[]l)vd|l` IGqm/[tW@{ib -1fa%&h6I][T*aoQ&cV5n cNu*r 悭vX"]3ӫ!gg:w+C鏡g< ]r#c8ze_X,df Wg$ciiQ3nЎM ܑ801 teR (ҏ@B ~ n/x;ik S6JR <9nx{z5 6?fkZ>%6x{z5 6?f;WZRZj͵x<J,exmQMkA=vRB-/~bI*j!b!SL2k63:ICD^<,?xh=.J $j65 m_߬U|;e.*Yxvrp 6W7f"`,k3Ɍ^/jP/4]İL2r|!'w3rzEY +ƒck8Wr9VEa:cW2:[uJ +Md9YgQ(wrʆKղise9q$>XRah^[q sWг{WG5g֡Uʔ1Ta$uxۦ)=uY#V/?ĝ̑1$0,ܙ֩!O5]okj: 5$,<'9I=5Z,d]\oX u`m7Voc!G;6#gkpUx|=}C. nZQ27{!IfV>gW|j9\\,;x敦%C%:<JA G:iZ>k[6[Aq"aTsxUeä1ÝeNk"a`36# d] e=䌀l&myd: PUmӠɚnBxiP%Y*1:[y}(&Ȕ!WD*=vP>S7nzhUД+32݆'.QPg&BX uZ(Q/'5t>؄ DXpTtd+C>[f"<,5]mӬ*3yBGْYNP2ՙMC5t6K`C󵌦rhK.&(&MљѴ$٫ID,9a]iC25 ցa[v\V-R6*hP]"SIf2r[mp5Cfu ƹf2""1oLFQ`o@:[:odgk-N܁ʶ|gCW|Ɓ꼤)V* ZKx k%p"޴"F^˪x#_ I749YfLn+xYxl E; t .^ W6i$P%m䁨^}0g3kj&m|d da8{ZbrzB's o.ز=v[y' % %w -4 gU)~xc̈\Ax7 <9R_8ɽe}@hď->2-WN*xwr\i跌 we->2dj—)GZ}r.v'+'+ zUqrSꓓvTyct hH Klh_.v-Po>p[_hc9 ڒX[;]~rּ͆-DnSUd< $E.[wق3l.HOPN/n\: pIo_]j?Szԙq3"2hZt[~=;[3Yx%x&u\()[W)ΛCݓb o?ҘUSeͬm$FD-Z͟xk0?,.ex命|і\|bAez e]4;`%:ӘlnUxxiq +i7oxxiq /26P_Hj QxTKSqM3SPK ^2~9%ݜStwygl6wuMUayz0 )ʲF=>T?CTDTP_g:ks>s=_ JҰTEmY Lܪ(״϶d02a;T:,6V<:iyGp6ŅWKPkZ)%:R2jR0R ~^]N0 ߊA@?NeaQ|i˄)]*{h/ ^9M7 ]G%7M+8Kbh>< lw`CI+/J3-U`pp<OtR 7u433TBlW_L2t_1 Q;@&D9XF]5)xWOiIEǐ+~>_RL(5G rBe,kE(ey83eVttof|s[n j!I\[^X12?DfV`J:)ҊEZCnE! ɁPpj!Y\GE nOe)TASjJڊ|bA$L,*_Hk5n$ w@h<%<9m'4OÂD"a FԻ ~._<G۔h`E3k˱4ZMxh%pw nuNDotinSx2 QpLV$5d 5'?7 (7E2Bﳲ*g)LnجȦoc6ټo''dfI$[[P}-ړ6)&i$e74;54x{2c?ӆr55589RKJRKsJ&_䶝un&(`;xiCi囅+XYxiCi囅Om rDx{ti[4Q.NNN]POx7`dM%')LN?ĖVZ2id Y(w}Zafٸ'{Mfny cxtiCH*]͉_Ps&xti:6̼l{jsS9̙ ' O~c6YSqr d5;|7s1B7qb234,FIB)@fP!thZ>f &nU% .ʽm>dݗ *[j57F0hs_`2HǠ )!'dL;2S+&N~1!nrpfp[i"RsRR3KRRS7M81Wjr٦Ls}@mKO-ARZT290dT!4X919#5rT MX 1yqaUI@W-$LF #1/%'ة24es'$WHpp<rtKvY2-@n`'#p\`M9N9 A*0;&$f?^KU!7,5>757>919#5>5R$8>#1/%'UsVr@Ej`%v): jA񡡞.S';Nc" UTW``h=y李l>.IJީ 9)) I B .R0PP,J-.)QWPQRRP*.MNN-.N+ɩTQ+0JjdiYPQ[:y]un"e=no!pXx[w !,cXd&7ma>rg Wx[i1 /L6[3Jm~b4yWf ULxv ld6jOI.jxv 7?eTT'WU  xvi 7?eḇug^IjQ^bs>QQy`=;sB0',T7yfGUE1yca",]xwi ˳&ppol Sy3{xwi ˳&ppouHQmܖ .Ax5qӆu*_aܡ.Ri5YQ[| 2ڙ$l(ZZPWY\Z2P_bhZxk{"ӆR=5zn`=͟=ݗ xYmo6, 2sҴkU`neX? DBIdސ#jq{}xW}$xq}p%e݈$BnY@R$yb1˒\x-?yWp6wX'VdW1]&< ce P9?W<^U{QsC&(\m5¤=$x(c\Vc/ 3_,;ۼq62p2:hX:Qr۳QK[dܭb>wf|9Y)J ٭A@u~4@CӨi|X._뫅U-tĻt0 |t0V~`=0:s{6 z4q`h:xx ^Hi ` 3ߥpvd¼%d.3T"+Qm{xtflŃ|~5brT$͵0 +3؞χi^dy1Iֶ^V,pg4W-$rc(V@3cG%2mأBt:! e-:!׸ྵߌb:GO ˫!kЌBy .G},ƚ4CRנpgu@-`4`;`'8 a%׶bbKjhIa*g S୬Pٵ(e 7tNZ*n,QS_h[P sO2 Vb֧gyT1*JU&ϝuRYk0)pR4QbT VA3vƣOs92\ﱓfyq[:V),'A"JV7\>%;{ HS{bE8y9(AaD(8]̖zM`Y-m,5& 'E| oh @d\ba8zڊ>mhCFUoѤ}~:sޏ#gzy9c0=L%$пK5XA%+*jJ6 :Ɖ逅J jDdrJ-g76CY M7ť~+w=plb}+!6+= 9Ȼնa00:SJI"S۫Őq_EGPrANےI2Ai|lwXZP%%do` ;}]ur P U!-hYCZNSA TltH#ĘG`kQ103@# h/hm6T,^轈zl}zQLrFX8Ƃ%u^74(;se\eTAsj)8O j6M-G?{ɵwy#}\i'|Y7P;QYA?pL7lͣD~7xhvǮP\%66nt-Fkap'6뷁w;F'/D::?uo!j~XrUgg5J)PA[GUrQVQ& ꙺ 4,/6i`6NXjW}oy<ZVo) 謸NGgגm!w(G|BY ~i.+{"OUBѽ>1*jM8=Y^ U4*Sxr.5q{<#7/T.,ۭʓ=4{慂4伹g7d*CxS[o0}ŷNIVMyV PEMC:6h ]@s$@KH +)%z"2Z`dB  ~Œ@qZ,_{IBÂ53*E9Q$'Eft:kGV*2}sHR1ʵޗD :heJӦ-[k׉'U9 JSv|̨lKb$?].4~x0A4e"N=&j䆋߭hg_Y95kMl܁݋[F;F4C+#:V7Dju\ڶm|#It%yck[s¾ ^^P"ߟ1#fw<}3bW ;rUGwJsyfuxC\[Sx1c,#GIQ~iqjQfOƏLQltx1c#DƛLoGx]{s8[l͜1⛩%%!ٙRdqL:rw?|xDlMndoth4Up Lk݇[ܺp&sqᬾ,< 6k@0h~}g]n&۽ժU\m^ |6rh$M jN68;͠ '׵j%[X>t?l6yK}A$/:<Z.>~78 Rj8*H I1qAzfE4n5j‡WQPQ݈I: *`>,~!pc}OGA^-3/1B&bNQ?RL^+\0  @ f>JWwL3bXj%MGM ~' }nvpw1=ט6ZřP5RH G9J!6QL3ݲ#PnWWaʕsv]=z{(ǯNF BHZ"iAu#Wzt԰HUd!2+ww ΅ l Uk44/cyƒa׾NHPrz4q*mʲL+p72-4E%EPIX/ͷ!ZDX0۽%u{2& ٜ9EYQi09ŪGz,[-ģYTC<2(`˂-L?1l%ңVeޕ !,tTxMRii5~vmb6{X%;6Xgi̪VR>x px-tSt p|8_g:7nopjـ',hԣt_zwJU Perdhh<]8G:ԠcPcOs2LazVy/l*Ύ*XuGcAѥ;JId^L|OaXHxF%f-fX!t1=6J'C$R(K}AHI$100}̽2"[^mL[0#GcC茻={$@bSt`]HHai!⛤l.i'bM=$I!-z-Rԕ"XiWXbVbRUlW^zj8H`}jcrZZҼbԄoN.ӳѭhuݟ`wi_Gqa/| J4  #J0tF_W 3)(1 A.K~iލ[=yo:HrfǤ-G$%*SfhXDq&g47jUjUD%QV1R( h1.'amŁ\\wЖ̲53Lk̀AL|t1 s. Jƺb'{P7fŇp ~As|~cwye0XNC-=C`1 W1-oS^*x MznS)ڼw/x/҂GC ;2v]F;%K$S{s?.W6)'՛A]ߜA H 7vH0l2i.ܽk{r )cʅ%p_cE2.2,lAP x?rt=5X?,ŊHId9<9 _Vk궃ZK[tp&Dim9Q ͱI49\,ε!ϴ،A)8aG1}r^M7[Uv,#r 53‘_ڽ~{G\l?A]}~cc U#8~$ϩ Xu8_p9# _xБֳ{Zz[F27y,2Î0coXM}`>fm1{r5g <К sA3 C0E]kNu4) !˱"/ĆE\yZ{x9]§0u%'/%9;4YFä; #9wcCHzawew %m_ :ҸbZt/êD8Xf&3'\iTۀ݅ہ z2(xXG8фx8G2x,9rwŝ>׈Q.66EX74/sʼ9ASLs31CO3qIӍ] #_,T&\ .D ?5{1Eą~^Vp t/j-DA/uMKvVߨcѸ~V~eOL0( ΌS03y8RQEٞ ʷ bS1.; b[AcHi4t஬.F&3 G9)ցųY<79.*d6T5l> N^Jj=I`f'gŮ ȓB$?nWi܊XD\O7\KFr,vNֳ]VBg)gP z  F-P4}$ZAڲ+'Ib2;l 簉*BW*/H\_"Y-?uuCnF3] x: 9h!.A0k83C.C k^R#Z 5H5}iZ-/yiHNYc7Xnrc3 +x *zpl3CzDCG:Œp6oA=tҴ,#b+:nXn~'E+(\|<l d.q2B|޴?>>5wYC6pzA~vJD(ρ)zt炚Ϋ( N87SOЭa[iyTl3DžUZx}<i3; K3(a\)\l7{Ը'R_ pBվjj :J;{ %;}+RwNk"n+` +3 :-:& dae6Y^]X*PB?e)Wx:!E7LnQREsJTH-+"$%q#aAӨ0ǰ*n-CpzD"r& ! /pRIįpRDى k+wK#ۥuJ)4)g,K{;z1ou6d()|,e A<(81֔:5n$ 1b޺y5yYGy}0sZ%U i4]u,a0MnViFeܚkRvd'A⪽)NT,qIcЛd)2j/@+S\QT+hߘ"UUg8h(CqP/1a:+hF%`ߚ[m!E>DhD.uWo HLݎ* l7b"f b|ГgѬմn0$.ul*WuJ>y';m4q]N1\o\2(&xb ;kr:W1Jd]F`B㏖ia(fѤYL򠥔gboiVtYZr]SVsm/SꎙgsCy^u16$Ι(ubRIl>.s*QVཝ%6ϥ&dJs=lL?6yuGɸKo'#KuռmP`scV'H[HڬOLJYvp8p_2 9/t-Vn=XkJj4SL.bVvYD*"yOB?seG]SWXPV:yK8!w9'H>"2y?{/F FWFvB@/kt_Յ"q|A&l=!ʶowu"3E15D@ܹw5*6,y "k]̰EMY 46lۙ D3@ RpfgrUvR8 a\4ZFqFh‚HmZqcԭ_$#'8h^N{ v=M;ڋa]g=`TeD :UmptRMnܥ]ف*Mse5QXdTu規녏w2dž^V@`I^ݰ6r`r%.Xx'i6{)"㯥0Ց}|'?A ( KYs=l"+C{^:3EQVc_XxՐaoLmӼ9 C}}6ޢ@]V|-y ^^]w\>훚 =y~a'ُD)5@ w}ؙ5kLGe={ cG#qVIvh IF.,d p/HtTGq ܱAǶmp>:s}3Ipe5bGRp RޯOgavl%d%o W-S$ ;Cs3yEX0D #*>?N)N̛8K7|KY9YT7(7Qyy / 0D,o6>Ą\w c@-X$< 2lmoѤ\/Tmoj{V;m7yox^Hػպw~P"śՎ IU$k@VW?7x[fjl~gf| [W T.x[yO ~oNf<ߗ}i䳾O|L@'O*f"0Y&8q!\x[o?P'o~i8'䮩SPəVZb`gLSЀ O/ ԡ;'Ve;3n#JHx[yw }7=Y9zr ƾmL~8Wlf[ϤCDxe\ sys/varargsN?l.9A? .N`F К SBX>>HyC ] 1Y22IEE%[7xmTmLSgΥj[FFٰ4F%ZK u~am 1 ԩSA?R@!& 4`V0]Hʢn{[ys{rHV/kXS Ѥ= gr:4h=HRSeH5>\K%a,|+dXKA^x7g4*+גz?p8Hir<8ɲ4֒=o1ᾓt@Ɖ@noM>No\-eCFY6}- TBߪZ2۝r!1u}:|YÓ47LQ A-?y([A0U-f|/g}푊d-)bePUif&mtXGxԗ!S)a8#: Xz?MtP_SP!57&yS ^Zx$7 19*G[8h } uUf#kBixS_1tFnž Tr6*s;B)VӭdAzY408t\$ʼnQAǬ6ʲOSᷝqA0f`1>I9\5 xoE.:}d.5*C/Cr,<ۦK }HK&8ˣ!n;#Z`%=~sfgqޝe$cf<3hv N> g:RSwde/m W0`I+OT IyfJ{BϗI(eaW 4ZzʼnޏU#dyka!\}NF߶q^]PR%8:d% r GE.}?u?Fm۰ _nx 1K7+x-Dғ[-(yGΓP|F F\D.E0ar0d Exty5 Z\rR l3R4B|C\BC<57'`<1 Nxyy" t'oV[9~9 zJ9d'KM=9 Lps!&GsMIlM'nr\\i Ɇff t&OW27HGG!IGLscF wGy:{FN77,i!2)2&'_0i=yf+Mp[,O$ 2Jz"&2mnbo S8&N_.4ydG5$ RKA\kCC<KK2B}';zM`:ɩur_s,_'L>e?yLJM~pm3k6(mq26ɬ&VN~7@dB?L,3Ke]ɇ& T7G#7D 3n~w򇳪7*QDf[-'7|hb4f%ڼotܬr?+Gk1xys]1ollw7 2xB}>Hbbpi inId`s k f9<,{Qx#Cb G,"x K51xi$Z .  Ei(fs8L0N U2%Ѐqh{3 07&wC{0q>H@+T&xeoaƳ,, --DkMQ(bDKk+a )e˗%4^xSɦ7 GLē7qKI2<3_TߧD fX;wvUIh=3L TZmA: lUc͍@: :b2hT,>v˨=B`içqyR39d g3i|aQ."B>{k,NFP^mt i= :xNtL 2 ฆ׆OrҴ6vu Up5fr~~ȒAO%#TR͊F" n4İlVjPue4ޱwh213# 15eiB xdN&Io}/^"r.x8=d]X^}N.23ݭ|jYH6/˜) ^ޞu`eGb ,ךxo~W spi_internalG0p E e10p S//(nW%2G!h5=&%~x{(|Nse6dFyxX[OF~N~QE"T-]V&HMUȱǎc{g@Z{ƗܡnՇ*y\IR=VB?phĩ [P!&YP&{л4,N9e@-"q f6`y,\nq`?Ћ0Dd .SDs;dI :ij rԥ3nL[MYoXRJǂ֬GC"ߢsP̓]a*pm X{[؉= P쉑ߒn)a+l%JIj7>Fn̈k [G n} zC<6AUOgx͋5(" 'h *j s -ahU0*RdfXݮnhBpM9\2׍ļ L#4s:/FFn@zj/ Nߐ,R^T?;q* >0PeeRT^cţ gº2t9EMfog{gD^r%ɺc  M,N9̺ YJPV-iW 'Mq^K]&3> {ٖ߻AĀ|MdL䥂@wPY|rN .EP 8 5]@QЏ~Rkd? d >Cm82k85:KpQkҠJu3h5|; Xx۠vBnC3s ̖ϲXL̪#0هss<FJX7 g@@x;!AvL ,Z  yř)E i99y y % NiqjZiBFjQ>d^v[k ;W\ ,J-)-S uvv Iv} F x ;Kh#OqAf|f^IjQ^bdF g#49|W`^tLKBI aY\a8)J2<$ oq DMef隓R0Q%$ KA&HPåAaiz+x4{C?J|}nbnsu7f->mhٜOQj#6{3uC)Msb< {r\OM]W\yu3F7- VqIP넗\sdUx{+xRpRɝ22r!]GDQDk7GND} C42abΰy,#!eҔ#W:ϊZĉ0¹9s%I\.;m,̽Iz2450|F[ A^(Od2(M崶.괪\&3MnQAr|EߊN ]A H̒B1STv̒iH!`l'2|0 I4Ñ?r#/t^-}Tb[KYr FVM!83UvmFҊů};z݁c%/ٖs!T+|d}Bձ L*o E q7*5qB, ۆށAE~CÖ=ws1Λ=]m>/WWwO⛑rN9cxTao0PvcThZ!A H ;ut9(wsl6lh+0T QЂ)2*D ypeH]D)&:%NυȖ[@3b*ÅyBp|t?'+C۶t.+E5V=ix#? ;/@NQ1 ,wGn6xŵkC#kq~Ibɉ061nN` axŵkC#cF6 ̷?x͵!xscKL=o1_6"xsC#c/RF&\~!F řU 5Lz/1lN`*l@xsYU'$VxsY'2gp:;O^"y7# sxT]o0}Ӫ$*uU_:*&$( L5FӉMI)ND{}01$0H6'XcBM}In=} fhzثR W晕+ j1gGM>DIp>ax 7zK{g3DE0T؛ 5[Ř1ϡne 'reg,VB\@>djy2\N; [&`6sb:_&d:{w1SfU+Vc)lg=hd`^Jor\S;im5+|nEo6ul_xķoC  x=ms6ҟ_SGrGv;NFD#ɹ2 -Bkԑ_. AJrkv]. X}_eMq;1=g2 V<Y0cshM0XG<mA E:r6c`;!gؙJz:1n1Ѕ^; vFh/\Žk:+ڃ:*_n2e0KB&́bId?N|9VqoO>t?.bdQorier5^ןZ?Z]I'a5Ԏ;mDG-f$ y^@YX}66^Q|;Eq9ujЎ`p8+.*xu(8|MVQ7Ԁl[(ֱg2ZiS!fsw91 uWv{me )NWcw0"!?&1:Jcw8 .c+::s97\ #}5~?9mۓQ]Wv9`H,'#o/"N'%x6^-'iR!&iK,(UJ7[ HAP[hG}*|^{AVppԏ?hR9\24;z9>G}ˆܿr¤M›MbHJϑU ziRtR@l_9N}Ɵ&aѴaZA|l'j9Vq ,k`lX V;¼;0.'xQq"cE]")-{ 5Wao{&@q^"cVhJ*YS)옅rg@t''+hA+1[C.ӤԸ{H%+IV ^ыt=%SgX~3dG.lA#(,sYMtT/M&t>Z_L HcUEw4Ӟc<˼HL7MDיIAbx:'A>|MN;%@tHzk 8AeN^QaOGvܠ r.9*ܜMV"2&50Vc?c̣Z3Qٓ\SwrH5 KaN9+ '/FE!ø3b8oNU#2_T{1tSzsZsy*Ea!K0tI])`ER.Etp0;5Dk4^Dd=-7 ?l$&"XRs-*.!{4ט~c9NC?9gڇARnQ۫+9z_`8{$-LfɏϽ~e ^PZBMT"T ()t Ɛ)M09"BE@h;W5dq?󝘿'nLS& /  %'([Ǝ`Fa̔U_<9w6&c2914=6} !5D]' 5ܝ``$o4F urYK͠)e+X , Zzx!n*a$C8hEcYDqʦ V> 'J:B 4R ,ZL+a* a,\X` V/9xlEp68XS֯Hz9~}כ i$-?7}aTg*Ԥ;anJ0D]%'.&d K*w"qaD"iXc1ށt }-,T!hL|*]̔jUJ1r2;ﻝ}=54*왬&&6 \Q-tR3^deL3J!LKB \?j>87*C5w4>y-8U@0OhHY\Jv?El<Md2MgUiEd1J(It: M[pE j =w\wMw5 ?@LP:ZB˽ (ҋ'XmvDl+$E^҆d4s1m)OM [?0c3c%4SkskL^=FL>J,d N\ SXt׆ì2*d@LoDJMGKYd0%sT*`Oy056}*۱ah!2b7a"t|=zg8?[tEie$hyØ"^3X[?sxoZ ?K+, ˷*X$$SH ¥߁3L\1G2q[cs4gS,9E `Msh\[mwl!-ˌsByi|^bCӖZ8%$72*^=i]+lɏ?jA'Ty\E]{E{` H3VefԔZm>ݾoMf)sI)Nv} f/b1ӱ^La44V ]A#ޕLzmO|[ uirQ$:W6 z(=v쬡ʿoW-tjfԜP;S/z#V ޾eG?7~a/FGFfJ_t9[;]6Xn}5ǣXzA}eGMV {M ~$}г2@m4&10LYXkR<{tl_Cf?a?LpS#D%. Js3y l$h[۪E#=+q׾o~+p&{ 9-yKh<vU 1``!4wTpt10~PmRB !aUꠀ鄾 h/[ޔcA޴vh}=lS>G[Dt(q%?gP9hR ܊s.eezޝfPS^冐jU;mfe%HS/tlӌ-ݒl3DOh<^$wwPr$T-MY{cJqe%6l_.X%uf} XB3-޹N> ~#9[87Q *Fx-=%=FTΉ0XO7E/^vfbGBI= ҫG@Z'?yԕ<+(Yvs VFO,rSlHS>ID]ނzV湀8rq_=ݯnԶt~{ƙl4hNmJo=pc3x\vP6u$-P_|H]K$4Ȟɛ"'+7- Y pnܲ]Q.rˎȌ bc(07 /6ˎVpXQߥ2:T).Zh"8jA Mב9@h(,.m%kRɕ AZ~+rYʩd$:mU-2P`#haI=<)tTEq38zL]42DPθiJ@FBNXs#C> ,c.4?&l;C_EͤFfK*xo^eWgNs]f?a9@lL; '쌚:,(%GB6t@MUu kar_dS(SgP,lҥ;9 N{ lQ4-ⱐţL6AѬBȩ0, Yd W,T?CY>Fgg6L :7JN& ieYiUYӭYiw-Xy%O4f+oQ!$b[idyayŬM)PӤev'ywTNO,)N"$_.-C{x pc0^6iU\X! U VA=QERp(^pb.VXԬZLMdMεx@I9")(-di%L;>mi5| oD$W:K9<74mڬw:CiQ 9&SBj} #>ͼW J v8F3FO\g1$Q((h/-MG`-Dc m0iWmIJUE|ULwi=+k\YuPAEnO go(x;Uoް6\_jy"BF*29avETlR1왉bc?ST\ZvJч *!{N>\N7EJLҭBlp^%m ν75ͼ8I@ojT%\_.E IȠT|}eM~!~a@b%vCBImKH O Rm [:V +;V!͔#R۾ lqT`Ijq\%Gtlr9&G3jjiw `r~O='o@@)xEum$mGq&્,{D >XW{oPr/3qU[(>o G$;dϢtʣ>gY2;\Ǐl\꧈ljtc4~ ȻŗM߉ ]խ`(Hd->BcW=_ʣsX7wO a.Sg8M;/"{ulQuwot^ {o-hk\` N 9{O%".}63!T4|@ZQ1N/ݥv./7e (Su+if.t,n>8G,L3,&1~KeOu<6 礘Ce Cķ1:M: oڶ4ƢMt0uhoElg~T$Z:D2 WL hx mdx:j4 ne#wjCxh"p黭tR;2ͳ3*tK B_oloi{ߙDup.ԩ8D[QI .H^.UU6p0g>ms=⌀PfZ瞺v>@\NRKxbNT\$,Ve%F"zD OF3 YKn`UVG!kFc XRȒ|9:xfO]Z[I(?v)zx֮U_ȡoI̹>W!:s\\OGZ oU~^an%EU+00wsB |/AAtTc2s0 梛^>]C@8Cz8qW/X hW+Np;KoJCr39& @ǘRIKqI*~\*d"I:d)Wn >̹/7c7ޛE70QФK yH"/"/ќgV` (e3#q]s8V7H"D=<>kx[|Aߠa{~l*Ǘ{80_ʽK )S64ZЃ3*ZLJxWIle꩛4mI[qui7;v@[ P3(HJH p=c@#Y}{o~p# n-C/a81HEb􌘚 'cQ2[HB:) 9NF/{F_T29;IKs8d)-Ow׏^mybTJo:qt;M^?vw'`jpFzt(O3֨Aa1ë.:G?7eIiRMqHM{3h3*o1x&O8ûN$B1-K'Q傓0|x^q*g},?+w=( m!m}U8pC6%mQan.PqcHPC ?4< ɉܾFMNOC~jP6tۆo0\vsU+YB;|):êkÃ;qrә0:A]鉬`T/_V*Ug/9ɓ+W]e “ }fOw$U6JL)WFNyyw'#Gu0]f2c&2dLDrޘIVV%"d "q [Hsy/[kQr3M,FBWmB3?㿙xVǵŃp6.BKDX6ҥ ZU>"J}iE_~XΉmDEzoߡyaS|-͊E ¡' &&:@|6\lrNmpL3Tb鄎b[US"W^uQOu<9`R5x=dU.S˩BG[:* J>0:?OF(fWq >flC\/*uk;O w >Oۖ:`krjh p[Q6#&Dlk~qrRCxc4C'5N%z \\;p¦h0W0o)ahd&^M2y<(j׀ʉAELI$ʘB383C:.D zVV!-i+=!Ζ@ SO.֏1xV_lSeϝKgotޮZJBv[[`ev0Br/DLY`"b|4D|l >~߹sw?{½ҍ;ț݇kuSjpt|6(N)w 2x d ]h$4[,2'ippF&fݹ\lE Ɔv8f75!c +k3ֳY}1R"z%0vX51 ?fxKQ+h|%%9\:v>'Њic6K)Sat4 Qt}ԫR6Q"U {wQRo ZPu4ӥ^׌=mF룢š4쐐 /s#>`jH@O]0\uYLֺ}Ԡ%6tʡY0zUY++fYY}h?<,)>6;;Tdcq:@;9Ke\)eiPvF%c؜trRa-qUٔFz=v@>w5a"LIS!Zl|D\J3D& 2 G"fM&c"L]FH~ݣW_KفYAT14㛟goP΋ F#6gÇ8^S KzPÔC?09WFڃEUzch`nR =H @!CCI7&VNq]SԨVÖF}`&Y솯;HolʔUP4WTU4I8r&ݹ)ݝ(:3>~w%o!rτqEZr9}6W*J˜i"MۈjtkPR4fIN\l4ou,98xmg'\M`tT 8C;88FtmNܓ*ue!Nt,Y_V&19׫ݸUmgӸo^O,DY<'ntQRBG -ܞn46T~i:hp&.CAAhIncn uGOCz:/1cqIkINa\) XӅC>M=Dd.iTRJe'>)XDvO,kzdvө|B-Z.{}m\!0JYͩzE`fWgg7bx/8Bt2/o8d /uae6'}aRmj$ 1JJy:M5@) O-Q})OE DŞt=-q`)q_Ve(_+EĴb z&cvS/VwDEw};ڗHJATpoI+)]"lkzȞB`'_nxqw l,iEغ7UabL^}a[5j>Nn7ɇ&O7Og NԵ pKל%'fFf<}'pqrrN 1]}3RӂSs&'r>Du^cC5$@ @5''KL~!<+k`c7 +Bip^Y\XM'Od|/AdX F8 %@ mLqN6OeKmޝʸvCfuZx!o<՛'C?wx_!8*UV`r^os? 8xk/be7ba|U[`fK fxkz/be7ba|U[`fK,5XDC=BJRs rl &7{hEu * t3R4B]#|݃55ZLQHOrqfU WS(JM,JM.Pc,a+73($1)'UBESY~NbIfNwj%.$y `Tx{8a!Ey'l jy"xkAL9q-#.crdyYN ?*xp=`߫0E6 Fxp;`RF̼ԢĜE7b4_^|{fGg2xpgPCxpeC.]g'-0KhkA߹&;ZLݰ.2f>~cqR xuC#M~Aj^qq~jY+(g%甦*(e(q!DR sӋPKSˋ 07;1i3mzqR8E&OlN%4 JpN?yTwx^ɋyL&r@~>]19of>~cqGLl.x[:uCYyV#Dx l)%E 6. lxW]hF8k͒??&iؑd7TuY"N4Fҕ4XQfxn&{}لBI!PP>,ۇ>R}(iPsl%}ι~sϾt={?w\>c90jUR "cⵌK-Pg/177JExm:;N?=JkgveŁ!{}>}5/Y]C+%IR>v) *ާGC."5@7Pyளus< o[ (@rB-ia]WIxkI8ۂAaKVb̼ZZ^7'GL5=no|}mֲaz}CFqZq1Psk_Ppނj:@ 7:ΆV򛨨G$Gp !a]E&DՊmg7lF̈́S!A9NPb% gVb:݁C(}2*пo{f,󵔚f˜#\U^@Pf9 9m _\c.G#G`G#SHaB@jJuV2|PAkuY%L| TɢSjI m,J<.6JD":ˆu5'F}?@vC7 SrƩeGfc]%IW秿܅?<㚩6W?p҉3O?FϿ{Az?3=z.Z]]x|[yG-f)SK>Pa .fO.g=}ڲ|YF7&h,A@&:l)or~a}rj7 O\0kuN6InOW= ?}@? Ջ0Jz-{‚#:N"$6pR'c*]3URPAl6UIT- 1 N%je%YXՠO%pUWkUbB/dH "M[cJ {BYYgYX:Йhk9”&kZya A3rx;fY >a~аjqy on6 1)>g弃LFXu}Sg@R6([e7WPV&[@w¡(GKjh<n̖%-9Xn$uGdH+ޑ.aJ&WjPeSޱVp.q nǫiCΰ5F?&xW]l5cM㔒tk;v*KtlDQnAWgdy);vjеaCn}0tÚÀ=^ۀ}ع%9cy{w{ }*|/@Ln mlsE>]L_Z=(o cB6!u?dF:TO:1=Osg qPLO^>关.QWwZWuMobcCq14rnH Dyo{66b!@SmT1IU*N.2F^(J_w.PNʅHamHGëB~6E:5L̥PiǶY6PsZȴM$iDzvi69jaB"J!u=4$u~7LОcjNdee+_df~slݞ`oacWDkg1(<Ơ ~l8D'AۖAidv)Q*&LQ]3Y:LhߞYXԇՌ$K=1@]~/0ܭ-% DN]~apsJkM1jJTe%߸$RA}{KJiSl拫* k$<-a86 na]~*)'HwڶOJp;yS579ϊfVg6o3+RmX8-:wf"{f'GGQT$h>8$Fc 矘ĶaփBZ?~ko Bᗯł.>1h~cFّ͗ǂ@:|Wo|)X-( ~QxIR]W]U&:=SS\)od[r~ P%[ Q x>|bgV4A?{-4ö[0k<44*lh ʒDw8}?w~P}H/~ЙeJ,giPM-}9*<jï|,w[OOLmoo(Mgss8b,_o[@u\iϴ R1!,ٖ" 8JDں'2J4pݴ1_.V6++ Zn]됦Fs]WxW9^9 ̩ Pu6TmP2K\jBfI]&q]3ʺgYz+twt%tr$5k; 󞅊Re^,Y][L9VNNs/xn?a] ަo#܋=ji^#aYy8КikV/PFW 'VC=ePt\ w9`c1ER)ᤧQ݀N=VaQeOF|iZkי\>b\(E?R>SY+79"|s:o:6u-ͯ;^jBX`2Ȇ̄ 83r!W,+\f:r<4no~U3P$}fMñq|:L˕ӨsBLM<\q$8-P5>I|F[Q * ~3rf;őޙ5N?b*ٍ`H:0Q;y" W[LRXR)˙# 7ܿ52y9w|& rBʏKE]̎K&dh؝M f#om&: 9ũ @'Pf~9poxqk ξ lmd`+>ff* @1xqk B)f%? }Nx+ B)L&W5y\,\@TZRZPZ\SbU˵[f.M~ 3nKx{+ 6*Adx{} s'.rݜ̸ӂ\F. x EdCPM_W 6x{} s'.rݜ̸1FJJTͫYV2n cc߼^b3(d뀼|@J€DIY)Di~F.Q]"Cx;vq} SKS+*3R]7 nx;~q} g12x;~} L,-(X im'x;~ o616f4?x(.,+P,'-dCj*c a o6xv i#6ˤYQTxv x 5&rHo1Y?RhL͍ = xvu x60N>'1߾1M?PdFw'?#\ M,#rI䥢 (|&Wp4qͼ›%N֏,f39pvx'K6'MFL<X 8 9VoOy[i+x{qU +9RKJ&/W+7OrjB'7z o>hW&jLxMSMB*>aRLS0,;9*Pbr?0_~vJMd'w q(G{FNnԜ|W,h;/$L@8*UIӚh]䃮R ALܞQ|&~X'OhrHrj^Jfpɖa|+e aux;}qU +&oR߬ϹAϦ›u'ffI|1 7x;}*ݒ>.IJΉy 9) % ٩J֛wJ1NV7)R3PQ*J-.pI,IԴL+JMՀ lΓaG~jjPyBIn]IAn|Fb^JN*Hgk &קm?+A=+xx 6]=uw wv J,-(VU_gUYU)5< xu]HSa9Sg97i+[k[甓M<m9tYf!$} !d=EDw]DADAD]fEt慱r}}^].L T*I`s`f5d WV11RW bD]p8f2 N C/i&D4:IeTãj'RꆑJPj ^ ; U'Յ O ax A:x;=[/BF#*&W`e#+ r--oF?O59r'+9䓒yoV/p|C A? >xkqg_+94B=B 4'瑛ÙVQZ\i=KbuA W* $|9ڍ47s O^$5cd93\\B'o0WKI,IԴRNKL|0]d;LEmdܜfZ7dxkqC.F_HKO.6|w=69Y08Y-@u'EMBר6DQ[ 䧻asqNd@B'+ĉO A3!)n ?Ĉ6$/̊<TշصF}~Ɏa؝dǰC] bϧjS.Y| B.`Q s{LsH`~ւa>:d9ЂmQX#UCA[vXE :)]oyѼ:E=kTvU*zO{.jK !Zv>rV}gp)x™C|haN6`#i|;NMwOjK&ghLZ[X rn\Ms,vorܴ"ؿzM,ɯg̤s`քYY؋nH> p5vGf&Z:Y8tm!i^ h#&% X8zpVˣ֐zXn"¥\AO)CTи J5 ˰$&`BnxY7:Aؽ_ ZOM1)(]⽀xվ+(YYb7Giw}>Zn6H7x N8(r)D6FBDZjaRyW]IwBpH pP: wDAAsNxɹ~!PIHHAWYqQ*WmH+[aG]! rdO>2ȵ֬MA5Zٿ;fsV9Ee@Smgt.Z̫XSH \"'D_~j=13sq-7;!8t.yu1j1$ Xd62}.8<,T ߻C.|qQ.tV:CVDN?'5H(%mI342f]ɗRɲLlHy*E"_!Ѷ;Gֆߪ ٛ|}udý)^RYtwvdhض$# {JR*Z*/c1tLx om7Q鼩Hwl˸kR+n 4X.MOrب )_CJ,L=޻KV6+x9ЛPfOD2l` aK1/%{KTMHk6׬{U\*컧zZxsRIFst+? An5b>兺< )@6}_ױ G|S;Vmk갑uBwH_)H'cEc/R}ZqѧvR\yBvJĊFQ?x{.-,R*4!%D_–WVi.42+MY!9n25K֬Quut~:wb|q羃;?=d1͈Iqq6~[ i=Tq/)()ɶO^E+t[wWY^lp,(8 /9f N5ZqjC^'‘n5zTLNȺhE^E&L'_L˫zmdqcOrtV)##ͧ"S@Xde32- ByMPn )%d/m1h^'fSЙaqoi-BI?9[_Vxpm\Zm޸<'ďO/QjAC:-O٬SEK4_&dxp5~iWKmfNaAShsHt-5}NF.>$ g3x'hC&y)Dx(dC?O~ZZqjZF '8';dhL6Ԑ,Dɗ7;p kLS/H-J,/qѤPR|Hvs=RK=3Rm 4ь 16B_Z3]dTh|nbNN~ZP ~>>P;9}]4 TK*KR3sRStMAO?4?(|T0WhaBlH/"/.(,/ػėHsbr1R0'Y~zxVMLAN R[~*PSZL?ARiiXwvQ`FcBLIc'ϚL1ƋœƋzҫ϶]ڝ7}7{3f8,QH(LLt(<[Yg(|JBxDu`qu`q 3K<>&)_rb ݦAn8֤ ~G`Ͼ+.Uՠ`j/9-<-|j1sxv#5_:IQb8(,a麚jl Bvɵ Dcۂi=;ǧ1sLe3X`mnot\Kr¡V2k7 ,hvvgRikVM^jeد; ] B}3ac9?LTs s%UHvp115pTHnl@6ald&xko+LFVOd-D%F%RؿVLB7YįhZ빑\I2 (m(Y Fa_9*AΓvw亻R2VxBe̔M_5e}y`D7ыz7 T+uJO#GY$l@XCzuKrW;Bҟ'פRn]JGQ8 k I%GO%4, J2isC=T~ gx M3KJEĉV*q)}Us){7QMۦܹޕ ^EpTƲFH9z&(/t &S%.1վ\*5Gd~:!*FU}SP ;W 0zT7\|[Ϛb\rPdN32xxK}tAxp|ZGx;p܉x 23JRs6k322s秥(*ld9"!^~>x2p,#GIQ~iqjQfMFFr"ܛY*T gx6pd9,*4Ox#`C9 4A/x89p#fEƣ, 856)0o6" m-ͺ9\U lL6bgGx{UsŴxY[o~뢩xɶCh7ڱkh K-Du(j>I]d!ȹr3Hח}th2L7L+$Ɣ٠ 8)$M0z"B ImGٰGbd1{X h14@E䲀Dnn$pfo%Տu601O0XwVR_Ac'|\f l $@Z:ϼaI\LYЂ,' @[]ɶ(ҦN7xmYҴVSo™xd1 {v۩vl^_ B<&|;潡;dJ*q7-vq,hj\ɽ&цXq𛏶 Vq# DEr3%#L+NՈ33B&m̨Z) A&|LhȘn5qf= V7Z)iek1LѴ]!t_WsTOQNF~;l~G.u\, Q!'(/ Ž} Oɓf:qͿ`C) <ysp?![ZuB,koe+X Ne9s|ZGbɛR %`U*C`Ƶ6YO{}<2V)43:E[J}]ӡ{gJ7Сf3hN#THJSk\|I[aK#$z0\XEaܡNiymF8B30T%*"9dQ:SskSfk2po&Fsw&#~I<p(f)ɋ !x{iޚD:n/gG)C2,8*O5]!|NE=>YPtpR# ~6~r$՘( o{ W ^+J#@98rb֘  43+$L_BpTݹ`?5 ə(*GIJ1G lWD5ITUEI}+-Tr%G9a s7y&+&~7ԯO3+*D2w~CD΅_78<[I`p V E2NZ|0 Bv۝/T${z:cXh[_qs&S(W#e49kفu&+U66REǑ_ $ NdngFx"`u5gn{O`_t(<9HxDbY`v\2 ӲNޞs?{տze閆(QS y8If] !U3>ķY+ng5tqśx2:;[sN~(h4dYvL'/`Ҙ|IUT! Z,>YYo lfɽF1Lau% dN%ؤ'e3MҴ>4zTlx0j~e™(ixprC-hP|cos_ rwK;$]L>'%;y/dgɷy*]\]}*PTܼN XuZh&k@6H0rNQ`Ggx;lRmC01x;lRmC0sp|pkp5W-] ;x;lVm,#OqAf|f^IjQ^bfUF3!>Pgg`kZ.(` gmx`9x,I8:x`x#fEF!VBbb7afLN MNd̟M}&lLxXoFlOJCM */6U})GMؔ}w>cˤ=Cth{(dȇnPAo,` rJ"tC_EΥ,z߄>l)^8 B"t9&@/b8D J~H9gg]D>DĮ%qB̡MU}[J~hK4ljBJHPoԊ>>;GBS CMGE.|xӨ(8x0 #d0'fhL,ﭖVZPRᔓP_  @XY\X_ZXZ T_j5wz]&ͷYؘ v?db: $3yfnvdX&!QZ\Sð@.גsSQH+ J-IK( W6; d,*6YSLg{xsYg;#GIQ~iqjQfaFQZj6xk:*E(4DV 7 8u?DISN~P$178*UG!]mhM7cIul&JsQDSJygRD;KYGxLU\'?|w>zx#:Ψn~1@~Bn VZU2-^7c9H c#u+eF{qL9D^5IDāi̻30s$*Լsm %fDN0JpzM,ۺI ͼ]4N4kx+dqse~81g+^F)eJO>kB`p3Fe]Zլ*dxfpʔF"ϩD꫙aa:fĂ-r)U8Z7iJR2 A䌟}MQ=g)=Ծ'lOUGOSRC^-/Ο̜3OV~>l)8/}+RЦO/]6\..s~QskgI*q*}F/ccA\vT1nKx"z@d,#GIQ~iqjQfOrF[9'_giQZ\S/)ȍ/*,O*I rt QPOK+N-Q(pOQ !s9^yep0VSJ2K*C* RaĜT.N PT~=0G7pTA=&6y E01I-K,IHKI @&2ux"zHt,#GIQ~iqjQfOɇ ~S A$x"zLt#Dɇ 7 !x; r\xɟ &er*J-.)QU()ȍ/*./H,*N rt Q(pOQ%gV($dx$n f^gHvw8M9FFYb !_ANhO 4$ W ձV߄a^r;l"ɰOƶҁ 2gꦄ}gj%% 7BNm/6L=d>D/۶&|}Kʤi w-K-uK\qHxJ 9[^Y4.r^ځIs(ސGߛϲ to`}$9Pq0 "|H=*u rqWۊ SZp}ymꈢsqrDJ5Ս&NL{^e+lgNcCk%lR-]MQ*nwDG8E>şQ1xz/L=cUs|q[h0ל?<4ځH'Tk(\Y3XYC_S_%sAnEv4 {*Λ_ ,wJ֮0e$蝠l߫_,|4?/ Xg@;kTK G-?zRlA hk~`Ԛӎx'[p#GIQ~iqjQf?FmfF͕,KY O=x'_p4FafF͕,KYB| Gx-C43hi Eť9%@̜x <̼ $|@fKbIbpfU*  @PPYXZ +J-)-Sh͵y-0 xwJV6P+Y'ssf)h(h*TsqrB %EEũ!A.yNy): %N9I: @̪TĒDDNN((,s,-ɀAӚsZv?j0k xwRɫق!xYYoF~~VEIQb5)(RHHM,"4IpNكHJrԢAS~s>Q=WhjE8t,WhGd<FR!@xqhcdȗHѽbGE =$cn"4@gEY.0!/@kf8|ˇvFh:77m_n xQ`B[N2@W }64`1őV4=V׶Ɓ>Bn6fE[؎C۾vnPWQm躩)R5wk~# e|0+iv*h#{V !dBOԉє4EB0)Ė,'3 " ,QI;? ^vK`7_-7 Gk#m,浢|S0m&Ժ JzQd'δ] ¶On+@mKoM|lr9wzTѽ߶$^2>*In&(0S%*O d.ԢV+PIB G_Fe%~ % A鑴6ѯBiP"g*RL| -TN/$((ux^s= &j2SQ#WTk+v-%CKv֊;HW(r :McT+X:7&Mh:k2 r]z=tvfKUM*aҚKn#XUזeFW8_2k3xMQcs¶ԥQ0Q0́ɺ%({mym𯃼ۏo-dsfշVc׿Iu_~[DwbK \.Z:s JEn!dVsDdMm~nJ =Y&uZ􋵚iJM`m0T>Rk.Bd O 5K!S|*?qV'#vVXJ$KM팆<ڜ hiaEc4i{~B{vAnhbxO,5+mflO m5;|g]L*{b琜sW3ФklyGC}[Aц[ Cc1~'`BWPB}dE|F*5 5n;gGhaBF7Dfc$L 5ACFŧ#)þKzJ+ zR#^gږڄ P(M#+v+NJpKTq{nĹ \<9z{̓V, 0ϕk%&vR32m LUMN/EbWQɀkD؋NQ7+4YJR6`C?.7ڱHRCORi7($6ggO1sH?Dn̳D{nj¸]V6϶ d,jusKWR~̮f<30~+A˳^siy*ԗۑd U [\^)B_ʲS᱅# y4BDz~) 12Bx{?8"ICd P>y\%V9b`~š~/6nBH0 ܎t1O*6P9СihT*x;izvɻmNeNBvGx);;e|P oD :T[WUxkrC-OpfUSd2&K$̼"k.PO3y2bO118O~5yXNNL .) C4@S9R @.*2 999@U$&`\/Ȥ`89]j2?TqyfIr0KsiҌ6,&1يE ]h>:++P6+ 誴&qBnԛ(=W*AOerDX1>1."&+EsZ_sHhkP H`窄18$Ț 9&+NaA_KOVEPeR r  ")=M> -醂@l.0 ;Bޤp˖e³'_R,m.du !e) MaQ_rmTx[`y]m,#OqAf|f^IjQ^bdUEE1Ma8dfŘ'`Saqs/ي]is(.&-?3?dfx$)0cyf*\zxvYm,#GIQ~iqjQfMF=![.qlx6Eid/ 1xEi#fE0?UxWm7|7aJYluxOm7'!kxVmo6, p^dGM %0DDQ&ޣ$˒8/6w4O:&!i#t%EDZ#@pHb*5 BDy 䊅#"WKbۨ/d˕BRD1zIBǐ_)c|8NL>O~Uxjcb$YX:̭NT VG dв_~G5cԀK3HA>Ȝ5bYI7]0w+ 4=Sǝ =W6p2Ckt  @lܷ`8n=ul%%ul0~yd]Cz7Ad IHT"KMC`Su}Hr&HOFNzuf[ "{.bwֶv*T%2,RP,N*j#X߽bK3: o ·:[P9φ,#V+ 2sk" EU:ө74rFM T_|nAtivyi[+]<,ȋn=.G)ޅ72 v`2kPI "~82>&hIFBpUUP"X}M"[jGyI€Ink;DOMMF$}8s䰖Й|y{@|+\VCOz6P,毦Q,bmJ:nO}|%< RDCM`G~EdrS-,}o7AǴZs7Blo!(xOPP )A#$ L A(FyՇ6ZW-?L¨ #b\}7ݻܻ[o8ڦ(\:r8۾Ub<*b h 28AY#}ꪚxd6 Pы dtMWcjCAŨ&#e\W>QP9(MĽbZvP,?`ENF5J,"_R{!]Dz e7'. ݰYAE@*zȬ:sY7[&K1[uT7ȖA仃C7'1qoVwKjPf*tC6\2z"vǒ$~aŃphn#Ol,Sx{*\~4lj8LSټCQm9qf# @x{*\tRo8$7fdANx[ KrC?~yE% ~>> jj\eYO zlx[ @rC?́#5x;.Yz#GIQ~iqjQf=Ƨ, &ccQpN,|tfA4 Ҝ̜9DmtҊSKtJ*rt RuKfgVpq@tB}|&g|OwUoZ y ϲMhq;d~>> ke&䕙]au L/$MŦi.xy.-K)MKA: yE% l>ox;.X~#GIQ~iqjQf=ƙ|XxVmo6, u+aY ؎lh6-2aY(j7(XIa{4/:&1siSM Fh.xD< Ap *Ob*"@(p)rђow"(ZJrkFCBpxH4Hb8VzL4XG/m?UeE~UB)]ZI12Us/8z"Nɂq$"kgۀU/=] =%1Mg {;3\ځm_U ,8Ա:?h;p EP0 _#cw$Lns"q/Rf|PP.0<ۻڼ$k]uQ]X'U 3VjS;=c azeqU`/[l<[9ۉ=-3X%cF2tF ={~Q]]~k6ձ>ͲIe d%YitJY|a_2ΉKi彣6Eyٖst41VKt U.~6n4$X ͫ*G!+mx{&uBj#D̬jɩE%<'OcmgT,# .x;!Nb,#GIQ~iqjQfMZ&[˘&kocfϨ 74>43'E#$7?%9$3;RGA-?-8DG)'?Ig}fQ].N Pļ̠ԂJTdfҒ Jc26ͫ9Z33Nx;!uDj,#GIQ~iqjQfMFyV& Ax['qOpw2, 'a7LSP,J-.)T䄰lJ r㋊ S5B|\SJ2*S+uJ*rt*s3RuҞyi` $_ZX%($8d(dV֓wqΐ>sxYmo8l نbq^ 8뷳C!2m%$7 ID6|hRp83|,_ˤN̥~D4ds2  fsB0XG4D@'ICY섔c}SiM拘t|P;1 |#74@.be\~|[O)gO=6X|Ȏ ?2c~oV4Q5\ItG}VfZϖSGʀ[3=*WY9ߘA̳c!~S)]lCp9m-wѫ5[O}v m.R c]Aېæ= Akе;dq^քl[ 4Ch[6,Xi9Cot ['vyͣ&u=fس٧fHflI[01FkOr 3$,; w(>FkacN= ėBJ7b v_o`K>t7wrod=VMDD@ jUD7jlcfBVO%dUd\L]P);lẉD)3/j:N )f҆ɽ1"^C;S[@L|n$ې;VcZ g%Hr7ݩOmKw}`:рi 2* j"%U͏_,\CA 2kn"/Azd JIE<^d9giH5 63;z%v0r{=?tB%֒va8%M b0N/*jPڣQUe.'&"ɼP2WKמ.'j Vkt3t)dBT( \VxOUBe$@kS`(O~ A0 s']i2Jے?SՋ/;"G^8/VT4$78?ʥ G8PUKKFxס]tw2wrEKBs8UtVi<%8ro"}+@ҝ:$QÄ)[ E7/=;Os'Td4-)hNPVJ$G."[m8c6ҿ)d~C Gv@mheUzꉦ:5T j0g=֤i"6-ŏͨАl*yvB_7p7^CM#Q .8K޷C(#shww*h? 4+8hJQo҇N0L! |,8q0rصG(@([+X.a+iqq2%Pi&7/\(iP8E΂ARΩ7'܌._ܭ4TU qco26D"xy/AX LZ x4XT%fw& :;ECUjIӸlU1( _L6^'wÏ5:P.wD+e*:H\>5/ޡPǕ< 9`oEemg I%Vi[~2mCg}oVQ0-l X&MWi!ӘF#z\J>6~N{ޞxŔi4H/P;u tJzKސ8,\%EI9)!A.y驎%: jiiũ%: %N9I: ٩9@O.N Pr6D XWYRRY b'3%"mps @b')nn揼Lp~~I Js@VO&W̆pSWx[=p>Eť9% \BIAn|QqA|AbQqFHoKsFb^zciIBISN~PEbnpfUB~iKbI" Gh*'AdT:nnP;DL~+%b(nVbf l(dddHcdrҲLʙi L6Rܢ99\br\lQx5p sfOA NoH D%7/)y|'O%<xYmo6, p6` Eq]adȒJQm}HQLɞgl5VÇs_uuS߅aW``|'H3p" fGEiC@!HXk`F 0>!a x|o$$S M& ]ŗ?Wn )_^_m~T5!?0_$\xwnbvAm7F2M0SK=&.ͥ'6E&{8=ߎF'Ӯi4S15I໙_X㮦EC)^w ']+ Lҵ; g^ i2~wJC'mN~3x4FpzAmu6@akv~! SV;+x]CQ W<Oe6um~?R"% TǢc36NN6yl3fH1h({ D| Y3loبA8mO`9`.|&S2g,햂@3E0Nmjh ]L= 5؏c}W( hrmm|.'B>ގ|8S%ӒHq;;83l9kQb*B\5n/ ]}c_@(k޸:4Y$JVMp6Z2;@KX1uxۑlkVy@c-oIvDP3)L0fOBy@R hFW-K2MNyXRRd]:n.l+d1#zgn2z֠ET+*'nR$1@KKTxі,ڥʁ:n'lwI])B] |MVs&XYM JΚ'H,%H5JbHY`;XE9O4O~U#.eZJDv~GrԚKdkSd,b*VZ%KT%b6[m̠(0rLDHR:^#\hRCfvGLUd8S?uWQM.!,_*cX<,P`V *RnYv4x @$M1m0XOSa}!v`PPGX3-)xVyV\?G!)e,븟O>G.~Ef7?RߨQ©x(Zm hu$r/}D嶢}t/j7_9wJzT ߁i/ q<붰=?ҝG# kHxSk0lG ]> ’v.b˶"I^l3oֽwwݝɠGSqey3LZq+L3y3xH2XݘC]C ıqF]t2LP qcb_4u>_!Plr߬˥X1}hldZPjԭjw/l>8!עR`=X1qԥ& 4%i[xQ߳QMߧrث5 z~/$m%{4kapp. ]cn8+h2 1EQ$;ݑԖ"@Pkѻj`m󝧺䋦 ;P%ٮg{ka3L-y-݃5I qTLY3UO7Ecgeik?:S $4uQL*C'p>KmV'-l )]w1+7v x13GIQ~iqjQfyFFn7_W_LL IAx|13GIQ~iqjQfy|fZlax|DZAq9c83xWoF+Q5M.ڤtd AȌN0zݻJ66P(Mh@p0O&4GC 2>S';mNC%SA8(D"NyH p/aOg %?&k'w:"’fNp)$OϙihtB!'ok4.qf D q@uE?q:{YL1edr<8]<_4Zyt/*|)*ST2Ymҗ:]N<:9O ӅY4% $K](Z!pTK0)8K*$6= ?\YDmn{*s(KU|҇ydfVa*RPᜄ׶Zvx?p4a䫦ņB%O9 ٭eQ(V7gviRqha=Jz#jQH+ZѸ'`7 9%±$C/H$$"lILJ́8y0?\XJ߱:ȞE $G`r9o`aꙗ\WBL]PNP'ޏOl1clxEsrno-R/'\|Q` & +&B.IU!eT%BI8[D"5x8EV`"_sIAn|Qai|RifNFHoK|Pjbs~i^IjZ~ZZqjBISN~B&B/gr!d9M.<ŇffA6FP]h%z@"%$Q'1)5'8*UGy glȂ{nK.JM+!Ɨp [l/2ER>h%t*C8j֜Ԭt8UH2F xπ Y18c5a})o7;A=%1 Ƕbl/ k<"J]oWtCN[n YEϧ5:l.'WΏo@vV+$JTTs *ܶZHքl8 ;JJ*4r[huH%:GDwD[DM"Aȗ }Ws޹LlO~qf)ߌ*ڼ XzKF&2Gӕ3v7*,)r8۶ *#@ZF4URY9/˸j#lF3UM9T8y;̄l`_I/):oUs|m*#+s d&˫ iU drߛ>Ϗz1֛D?j$*-7 `A0a$XzU<Ū䠑=?㤫sʲ8X S%15Luї Y5zybZѥ Lܦ/)cP<BbG>V/L-ħ{u.@<+QVd#GnU|ϬZWrφDPi טnk,}N7hu ae-+ZbC02.!d#Sn@:Ǟ} (v*JB˥{o74LE?Wiz 1 w箹DI]-dZc!0Z#zƮ wRVbanKgn65jQ!n7VT=}r>cX-(_P !ỉV-:f}) R\JR @nܦ؋(|3ԧ$X Lmv{o2[u;5vjmbD_AY4=Jg5Nhmi:OEs8l/9gzG9qsbleoڬw_Uo6 muxk5lPϵyh%799[ 5-xkߢAQ 3>3$(/1' X/CK93/94%UA$.Yi:[;YL7b73ob/sOIo,ɯ TbT~*oxۢ3Ig,#GIQ~iqjQfOxfF+Xq2M^b6_$; "xۢ3Mg#DFwfF+Xq2M^b6_$; xZmo6l . P6`];Ei*a+Ea dȔ+QM}Gꍒ跴[ûŋ :3x4Qz$ke4 ! L>"҆uQY6'K>IT4>Le?x{'MZ=znYqu"BR֤MصX܀Q<[y VR3tMv9 _%a+3I_P]+q <"ݐͥHKg44 HuVQsK?ZzNZR?`^H-٤+%qv~kHZa/3 ).e { !Q"-tK4#מAU\$'0wdS?8Jv?N0!AdBW,2K>K,{NQ K^_齎LDNΩsLy݈9PpB,i\:qv|B=ȄNHV2mDTAJۘqx˴VG%A*x< &g5eI,"S㶸8*;bS{7/Dgܧ}4t,}=\re[TU)|aQ$bJ"9QP:a7OG e|[?I?krSJ+@qpuSԤhGSs]I]mtTO'yonVKzynY^ /xnx(^SztO Y- *iW@M]2eB&=dKe}=NǞF^$tz}п >3ݴ2TLRDࢫzzcwɑ[ޕzՙ^=ѝqZ@2m͚Ԑ#n&a[h؃4uuuUXwJA &5ԬܫHA n:- 9mǯ]!GOdeic2iq q7Fp")[UB4^Hc"EPo".0?`JàWEǜ;G^c_ r/=|B\)E`RAr_^*>*(S_JY̴y=}-.uT*t (vȦ܃'Ia6H-F2c`ZKx}cfN%iF Tײ<.NPKc&H&=$_!%?/՚kr)z(gxfC0xfCDA J7˲! Nݬ ܜE $;d/iͯ*xX[o6~~a(t4[#m mZm"2T/)ɺ;vܤH#><}a>q1WHbN/!q`.W@s,k6JBbt? ;1H$&f,Xq2_HУE0| X]返&ۓw=0u!=LgEae't^**BK3qsֱjYš"PF>Q%AUhJqyQ'8FiL&plOt'#X/1x5Bäi`w8ph6XtZV{P AJ2ƁV׽[ {t&\o۱ª&z(P:(lPr=}'.{#e+h~{H5X?i,SqFEK%M :;aNzF̀ijsW[ quZcr(` NC{7o~Ӳ(:Y(.69q(H~q,Sk3iMxybJ:ݽZseX"J]?ʃe;< b4l~l1UG HԎM+KR=%ƪdŢb^'׊9X=jXw5ةq1"1K}k9Yc|\}`&0g;ωYӰ* uy؆C@YUrQɈ/%-hOoBU:~d<JD|UfḠ >nqE@襆VsVqQURtN !m?e<n%%_%XU^k,lvaAE$%Owh8+h$X{dRbUUQY3PEpruj(,g} *c2l:Mg3\6g!z?XW୚}\xfV u,cn17y5KRDy ]2^?vė 6K`&9L#|kS,frfFW;X]Dܛɼ{&[½\4Z#eʓXQ՞VQ:hDI$zD%Ped]{诋a4^:N-Il-epf+`sZjYxO^N'O,xЯ?W>xӨqs"c8KjRiʓlHacT\7Qmr!_|Uz]=xkA(8x& Yf x@kC3*2i Eť9%@̜YҊSKtJ*rt8@J2R r+Su&2IHåSRSsSJS+=';pOl:|\P&??g`(Wn9a%N~ɳXM7Zs5&>k'K)ljRyEHΆ0Y_g !Qf3}޸xZmo8lHX7R .q9(Ym!)z&-fgf=ugca|8wK(fhoq-I,'!(K<opŭ0Y?blE]K!] M)jL:v+,Z C+&F۳1,G~AxH~t:@ޏ.Ɠ)H1Nyd+œl5c-LHXbvܲ'8O|qn;SFX5m, ˏKSY; }@+g ^:{Ij<_^Zdysyryr>/m%,(&xX,R`5T6;xʧ.rwzIآ\}kWr 6] 0;hX 1ad4ONw q;݁F|QQ Ê>,YHZDJQ,S:Oz"S#%Ӵ`Bv* w xnY}@> ~1n̚1KGjJ W8籌Kgűl#)yM}-zZZ1$msHtg cL&ggJYM}jPԮ{6;٫xəC*dsɝUhF.Az½ J!XjKqݽWL9h$QbL¶(<Ќ'sM"&{`Gz]Vl\kBeKd!w@Kx&ưSxx#b0Zru=$ Woa e6UJhW*qJ@5Iӑe"M/LO BQ7E ++㲭Jbj "ƥ>nĩZu\OhjM$823fh9WJ,v3C6Hz3}H,[%r^$%( Jr%6 o:s/M@@= 5I=БW8Jl &cvwW#iNO'V-lG⸚57#_CU+Tx9x94fxWgj]+ B\<<R[YOu/ϩ9;_m]n}+QaVH7-o,_|YڵDWn5Z=~K<K Opgp /5"dZ6ej,A =T t[*+ERiT+e0>P^f6GS47aC<5QP<ؓNLrK p3DaO[-ybofv MͲUk.ݴNZ~&E6gy\ƳYD2FH%})T!Z rDZO-O^qg]!ܸ(-$N"DybU o]K6rrwߪv-y%[^@ Fy prO*:?at&@VOYSASZht^wAef$TI6tzx!ldO6'Ȗ0qq*hsm P''x11bĔlu 23JRsK* R23sJSRJXY$">'?9[Cmdm~71T<$8rhZsqqrjL+*Ή۔ E G'I|^\p> P"ysɞ|Gp:XNɂd{Y wp5ƧIn>(|b#6+ocĭ;Zu>g(Nq axv%lC*Kf^l'sO巙CQ 9%=u! & Ɇx 1LE )Y$L>/.8yQ{({V';l%%&w9zx!lC*Y$8!@4 RZD6g Uy.qF}hxq#l›ɌKwrF;{O/:9ߕ"+_Ir:$ W OKMaA P?67L;e٦B_2Ƈdco|XLn hQ߸}1]ſm[# 1f (a;5owqXNGz TxvLv]pgcs‚P2pW.s@Zy>+u?$?_%@0WBTSxk9jrc ċ\tﺸ4 ' @9T\j9XnC̷[LABIRhӖ3k$fO$W\>B_,:FD_P{6b"e\I}2874 ƿ !  Cf[@F̖<1Yv/BQݯ8i2#I[T#X 6'E1_bim T#"=IPTQ>a+-8qB.AZ]$C>_r&+w=>B[.RfG/l&$rHm1`pF- VO`;TI Qd <=pͶ>ȃ9rYv;R `̂‡ ɪb Xs,3l}Fg.FsbZJ0>>6+tG^i5i#ײ*edYhGAT#0p-[|vAPIs'HX@^橀* 4Ab)ys@2 Z{:IH)7^PsNjfkPYʏdpX(;WBo,t+5WT|䀊kE2C"F{!+^TPSh9 HDk{.TT1+_`oAKֳ~ޟCSƹW1';Q)h'9I`0J>_=HxKoU?J+y JBM 5oc@MuȠwH W-io#YuY =Ά ngHzEQ6y$`0X&Y+5צ.3LuW`~'M jg5^mOjs1ҀMWn)*Wi/yR,co\/n5B!s?M┓iV[Wv帀r]6=`:/ >>֜℡kGsgSCQ_]MVzlIg1^9w :vb T|PKtoa&QklZpn<ʮ.c3x4b m5\J ';s jM8l腞o)n X {u*QhTZ18k cf+(=%sBh# K[Iv/à ^i)9"QU,MECn! j*/Fr-O&q5WHY8ls_ЋZ jTW;`[o JФ( qn;ڏ &oj&^s&٧lS.WsAK:GFT}F #u8"UGw7u. :\ʹ͎N +8v,w?|3?ʹ9նDvTQ;ZĜwl"}Xx ݻHVGk(6W lBxj fRfVd~B@z~|SS#vxVMlEIS%M\'%awwiҴ%R'm8?O;vw&7Nz܋zB=rXāzbfk{k5R{{̯ /-.^q a*vkh. ޫK&zC\[\)5IU`V*d#ƕxikV%[mѷеxL ڢC;]-vϔ CZpOC2f lq$:99ד cٱww#+#>:(z9a{M R ?V0(uZr2xc[aN8LrK >Xp= mR+V+$~Jzk֝eeNƮͦI9քhG;*)c]sػT.u4pp tsRspzn2il|=t[4u3GE ;8OjWO Qi%MbE#h:H8>Sↈ>FNAhNHe !g3K(;L t&MmӠY\Ċ5xcπ%@H,@%k5:#a=37疈2 ݆&oTW /R)g&*_DDuˡGgmXӟB,e͂]FYrt"L渾&Vd='&//KtD AMMʤK 31 ?aԢ>BtP:umWn5ۥҮk|c_QЗ GS숌_SWݵ߆.NI w&z R@(A~XX<4!7dۦRߔڐ xr;$ա[W:M3^tZOjl\s턞VK14]Gwh);,jw%UkUT{=DQo5>,4/q= v&HDnnbt9s#D@lzX΂L}ݓAE7a_aJ^L))*irw5/tvmQ'g]a.)FO(>1۸GQf鰰B i.td5& }:/Өw_qe˩-ei/oQuCL˯' F#8S=P\xNM#w>? 2-*x$|6fnF{6{?`|AKb ,6.%.NNN P|+HoKO~bwjFQ'tD7kʮc#X-#lxk z%\r)3xk %\'׉n%r :Uxk %\k&NΖݼQt<" ٩.%:\@'׉n%}Y&xSO`N ]샏{%d 1mi:n,tD&w@b<{=pǘp511v#l٤M>Jv7P4bu_>d鯔񃂹!؟a|ϼ\!>lE ;5M-)ZVW­9QYֱjdO,? >,E(HՍ ܏b&VWL9ِog@ޙkj^Ӣ͟ jv,[p+XaBNO-Ex8G$=2p" <,@كU2ՆȾL~$KY1GRwzIԾc6z\BpȌ-X] F;]tL@qnMg͡TӘD lDS b wR"AU*Fs M`r\!ix/ )?|Gm|L"Q_z٢H ~ Η qefh(l^ǘm,@:dEcz ǻT,ϖ*oD$ljy%ejߔEdC~NK[;XD qmD$,Du]tNDꡙ \Ay\`SnH;뙌Ɠuh<.fv"mCOT G%ڱ˪jxi܍&(B,xi܍ٙ|7fWe vԴOMz'  9 xzAU~baeu8t2S+5'W!xr,EI.Eg&mjgYxi,^x{uI6P'y&(*Lv\εyM |%EI9)!A.E%Eީ: jiiũ%: %N9I: Ey%9%:\@@ʼn驎%z@"%$Q$웙^X&ZY0( ZR>ydmYem7obe_fFQjqiN PoSKJhmf 5AR|vLP05dGyEoWon|x{c2cfe;F0x{qz;#OqAf|f^IjQ^bf~S2a ĺxWn6} E&hc}ImmQD2KQEHK$&6A2<᜙9cM4A&(Ð$d 1:P4ALI{&_Ct]ЍWkKzTB:i)J9\ʿ{u}߶0 I!s#g{m&bۆ)J076 D5d^K}0Z{A/꫕NviFe:{$l>w/p4zRhE;_D8[r5jwij޹70$ID{ =bytĻ/Pwr3F/??% r]}\G}7YFNxWo#D/LjsM<ņQmy,ɝɛ.:xSo,#GIQ~iqjQfM1b$ xPgC 3$.[N+)ȍ/*,O*IјEH-?-8DG)'?I =5/($5(1/%?WG!w,-ɘů8yd)ɶ"\:@ ՚x x̼ԼļTǢ̲Tt($$zgV"\$e#HG/GSS(d21uK@}# P-=yH O3ƒo( B-쿀$,)svrE,1$3( 'R//.: @ީBN^(&yd)@1)K0y808.Nv7'Xx{sJ}7d~a!Ҝ[Ģɕ,n%N9I: @̪T.N Pļ|0XY r&Knƌ϶5\mKI,I/- (9d(LNlû =x٬)n!ieL`Qg nFHoK|Pjbob^obf^I@)D"L/yiCm(t}YI6~l1%sϝ>ܠD\Y\s}J|:tBCj ;Ƶ\ng%G};i7 \D]O-\Paw{c\sj`Y\#Ok$pn[pVaXݘͦ7n>#wIۻܦꏯMi]/:ZؽI>Ca?_SƧW?#FO[FJhZ`B̥ko{]_2⫩CU2\Ԯ@d7nFVoj^+ J(\&vṵ[bLSJI@mwd}bbz[Ky6!c03oy^޳,ea1\ 1]vl6ϢYBS$ji׎#[bk9#|>{ Pq"*`rBޕ6ݯV-JْieK?ߍkD;I5u70F#@ݤu`ɥ? Aāf=,`lR \ŴDL}dtQFzW1u-)g0oκyuQ'4É Zǧ}ٖ\خ-Y`80}2ј#5#}4|0uǁ=Ȯed&C" k{ǪqʋG3jǻQ5Rk-;*~I$v]kUnByXm0ad`È؂&>'fTWcS?L+YrJ9RBΪ$lhD{O滃x^@&]4\i7 gHMu^j%U:sq5&Xj)Kjū,^5y_e;)M\[JZ]B[=uڥ?N/y-0^dgc?vit^Tw|$ /Nuf졳 Ev{p~\4bsZ2!I͸u^@: aǎ)ke1+T|IewwYơ> +w%'_r_q tA;.`zH2WE7GSh \rĎVU !B(7ьw/j{K%]ol7gIjwCWf4 Ҝ`IAn|Qai|RifNjiiũ%: %N9I: ٩y)9:\@E%y!KDDS+KK2jS]K3Ru`ĢԼJ`If X&P_QjIiQđ֛rax :䳬||hξ($9%d!a(= 9r6n^ S9qy&a*-%8H'g"+r(B,_Zey7E^xkgA(8x&c ZLx[`2OgC dgɳ9ĊRKsJlJ r㋊ S'DZ9T8'(Es3RuR!l.N PB~iKbI"D-3=&nV\˻ad{`y%%: ~>>֛ 21oVh 4(98,:yG/6)kRp6L0Tf*dm/* 4 EHi*TU(1YC 5&Hf?)xs\k%,ɛyD7a8xYmoL;P"Ң:,bR VJE˥mY._%%$Ü}fvf.]k%#.\{Aˆp;X'{-csw6DPfmM sFKzߝcˎ!C0hH=u\!F $9B.psXN f@}+as0X|aw l0z!JI#.7E@st"$HLr b2]19O @(D!GnS@e7GS:;1м;Geq]be3ɉ'_zk4\}No{ Ёq0cxjG^ `B%,*T'tVCan|'"0ׁ%x6eX@{Jq2][^s`s|L*T3 i"8kZV/si狶6vke|!a&L?%&Sa16h ? 岂PYkog6?ClZ~_1Sę(ЭX/Jsq= -B\V€Y Y`%ua-aP y[bto 6 ȌeV Xl#tfN&ћLfNֺs7KIH'Or Gθ`q˫}"[OKb{sKZ; QT17VoLk- iTBwRtpaãja;C*3 6D<1؅aJ5"XY,ekY~~bѥ5y E^h}j?nG "NmV)\7 Sq/UЀacA,^Rk$ *>8'U-皦zNUđߪf<5oTq'=8eR -CISo.cuMd3|87tuF7ukި7̌i&&qePo=jۅ2iy+f+&,|܇.GQ.m/z[\*is7CI6k#p 6@ś0(f"N%y+Td[$7T,C>+PrsQ\˘jZR0lJۍ\9?pd[FGҬ%D?U#,$jtLRZ+ls9|1ZnT 8?88\Mx:!X=J=4ʵof^:aΒ"'YLQ ߿{v/a >I٤gU8=-J6#,}fFMu2*ڤ<;Ҭ? jv>rgt v\ '<#HNpAzӎ6@lgu8~&"/`C5-ηCʅݛfkACRUD@>.ghMȸSjyw&uXuRp*E_*5 fXxS}s=|CTr/Wߦs,5s^;7 M@A'ԇ}PRx?x^̏8JKS7[\gdQU0|[krblŒ ߰y*rqqf)hhU'fhL!VZPRᔓP䙗YPpqƻ9;x{F(%;d%ĒD._SS((Okm'8)ĢT$%B]09A]yubPk79'_ɼRj\/s<3‚KA|RK2tғ@ܐ2puD~vF-Fzyj`_f ڠCa9~FGz> #k&Я\kREI1bsH4i*@. ߀L64lRS68g"D>9[qf{1T H|((ڂi*Mȣ:Y^I@꘤"NIHJ[¨Y=oNx GIQ~iqjQf gxabadoɱBHM>ū3ybqU& 4Nx{n7@E 3)hL^ǣ:]33MAC(4 74>43'E#$7?%/,%5-3/5 19UGA-?-8DG)'?IG!943/-?8 (]pq rsv rQHKv.-K)%@m@lYĬ'>YB\f~81<19' oR<^YS u<2‚KrP^tOj^zIBQz6 270n/إLVD001S0Wk*TA)dV|Mnd&' (K9QD1yl_l ?x{c7bnҜ[Ģɺ"%N9I: @̪T s9w mnŒˀL^(=ydv> | &XZi 9XpĒDԼt\@EI 2~>>iM*vdO>œo!>8O3PޕxW[oH~6bJDv[[T,6RUe FwU\#(> ClpʠGEz}ۋF~MoߊvBao.Q€[:1:K)&<Qn&.2c1nջ矲7u7#Z`2Nqz">DqUVӁ l#|VKٲwr"O_k;kPY(>Q;Fplɒ*{g! .Xc|OPg 9Bp WV=1`mH$eyH޷,uУe?VMZ[4]*֧ BsR2X5MK'"*)2V5z\u<.a~0:ivkݒՊOgFW|SzqBMe哢xrC`Tj7(Oaj) z.) `cL9+r`͋gGMaMRob#x3,} aq.)#dGa3R"kzi`|fw~?$+!_2J8O݃dcc\XY%Ih:8yowˉ9uJ-0#vU%Mn4-\H 6utXlt Mė*Do,Ad!A/4w__GO;M~r-t&Wn8!׃WEHԑ?Ti;;N/YIBxuS_OPuF19km1&a,@($[oYi-8&o/`O /~znc=9o]xPv2ե(g4'"i_3\>!d20r1mԲgZzoӎa0ྞ 5Nű9!<Į,ڄ>-|CO`)ڰ0m  #NEE a|?fO0N4ʈ鶂$4mRH=4A e6;M 4Ci0G.S, 2-ͤ&N:9pǓ}"Rpj$LC'Ņ` 02V%j+WI}}rKL9 3O<:{ȷo&dROq#O>&Hgr0v0G@AeaqqeAnA%KM״7[>ɪ8S[&0 *ul1 EXT sZy)1 iS,7MGZ=׶{bfZƄ#}D%w~7./t1bqn+*]ZWMt{m^FibAO>~tosW59hTem`8ٶZ?W&^_xkSy(8x1c3d5wY<6 <` V:xkSyAq7c3d5wY<6 <`#xGiy9L7b~˲3G7v ExtJ~Z8\&;sz(hsMȩ>y'󼪓x&r)M^df|\Z(;RGάJT|WG3=$_!%?oi,|# 5xtI~FffɛB=BLJҊSK&g~LvqLv`Q.>VqQwj4MMMj.gyՁ:t@%9KRR89kSR2ӀxĘFLc8/>4_,# =|v| ZxTnF}bi(QIVIpR \IKfw-MpZ$E H3g{gˆK8PT "ͨP.JBzA)҅ wU9`f-W %xXʃdJÕHu&v%T,K$ThOe30c<•TQ&rƸRں6iϔDW{#3FX9JLM %Q23fpb3'17 `M$Y=`D>`H[ ;,p\]UiYKq"5!|/2$ڎʊcus|C(ghnw0cU<=g5`"ѷ [+MD\ "M>RSSlUNNl N)qr0%/b\\Y k&vr;W"9(>(l86[\K3R=\>OaeO䢠D܆M>Ŧٜd`2; x\sH EcMMƓlac`\IR*! $8̎}u;{ 0ݯ׭)1uC:#}3m:!9! oN}C(Hr P$d~KFU TVŁX)Kj N@@(k0dCK Ϊ>R w^O45Ek߈c{ VfpeXGسur~~fؾk)r:҃ +jϡC̚AvFdi~h|`4"(#L.x3q kr5^Y˃$~^D\dH|/ CQɑ]7ISy/P)()еlk5Mú̄f\׭nOCGLwnrNȆ0dq)3ֶ35UF"1. tpuu?P" &Y؟ 5r<c5*1U/4Y7&QnUU<Рy@)*ЁDEPB/G ͌*A ?̼.,R[=F3qf:FTC?P|Ry୙H "Zdf'إysf!ѲFXPs蠭&DM)[ ѐ> 0hxAyQ̺ Ӽj"O7P<,i^@2R$eJ[N޾k0lׂJ|`3G1 :KRѴ`Æ1+3!ձq[z+drQ|iK`M+>'@蠪E@Tpݰ@ngjK_[Yqy'] i)V~l=tguTi&!\ [`C^ _l*j'o8ZIWo_ˎ S7=ش4 y}C l79n!?M`_i d6OtLݓlR1ji+s[\֖u5>U+q{Nnwl*;Bw .p98 ;)1w;ޘ~y+=߀$}SxCķ@#.a/d9 ><2=lhI/>(w8AQ;By~Iϻ}mr+Bmjڐ28&BS[ t䨥!WbE'{gbAQ^C}vLT'!NV/ٰbebTJ{g>n oJR]6{̬O/1CUa|;;l2P+)& F?vd5"g|&ϟ_$ EMK))&C8 6`SJUL/?)(X \(Q ;9NJ jUYN +vm yǕx%\% TԱꓞoQ-6ߒanx1 QUL}"gvuG"ߒBCʣX$" %R])mՊ.]NcjM]Z)(4ߏcmATn? g?(&6S(^Ux|c?m6Sj爢P^D}?!#KJ5"'fEӽ \an gؕk) Êk .7SҝcM }؉ q#ƴ6h0XȍC`Z;kRWGSa # kDknj1kAƗ\7?+Co&vRI隈!|7K,x,Ee6~W\yC.u}$u]H`܂XcFTxs!̢ }*R|EYOo6\7fdL޴F7{Nw{-d1cc3\/:S5|csOBw*#+,oQC[aw|7 =3Eb;j^^'*"Vw EcDluEvȹٙUƃ!%mȊy}IA_0Mm G-yp[ys93CH{st۞a{(MP 0,eldHեd o\'?aRܬW }x>s?m{$&7m6cb qJ|+eYN̪TJ' G &X+2ULh-3 \fɫ&TԎP8d7H:1'xVnr.bIq[(>(xxq,e8@AA!9,5/%%$QG(=;Rg^' :xϸqFA̼ҔT Oi3;8nѭ`BizC"Ĭ"kF2ҾyE %ީz`yX^a2?H(M&R9Xz$#;Q1nx˸q;].x˸(}1Fw0IC;x˸,};#OqAf|f^IjQ^bf~F1Fw0I b kx*};#OqAf|f^IjQ^bd~F g3?5N낒ĔҒԊl T5'6e_ڣʔiLf[Z)@xVmo6, paY ؎[-yh6-ZTIW(zeX>8sIEE4f] T2:Gs)*  &3P-E4~#%RQ?@lw") 4roFC%k4!DL41h*S rtoR&=5p]'G<]SkVwu"m]b UFZ[.UQ fqnZH*9& T3s!ȱ6" Y1б\l2IV$u ?XC7s)@ gf:bÞ 3؏@$^st6Ě-hM_^$7DMG hp0~9' o HoT.> שІ,p™b[y/hW?\1o~([tymeDq9$J.a #Z=.| (=Yq/*<8db{CWkf&`W3"Ѳ <#GvFðm(|+@kӃ-.62f[2ᜣpfqtO"T Chf 4<;5{* xy6j=%ǏDh, Ӯ9^*$A:v׉ l? .bJ=w,RgF6z=2bHB$ֹu;ðdHhq6Wѕt趎kRմ߻" :/.(rxCzsp;6 &#?frEӇ r&IA蠵Rwb7p^ڡUXl䋍~M\C[$_i+*;o S5dąM8v- y(dR_76Κ߽N3S 44#hs-UdxWmS8mM}hKo-s 0Ix[!ږdBz]INb' @־=ϳxpLfp%EΤ^yo誖PL҅ FJ2b09c1ӋP20L|)\y!Ps 3Fޔy^]x%Eq§#ɳϴ^LںY ?5w| Y[AWh8|#wO7N&<.HoePG*20g4 ,)dE:enY9iTt z^ ;C4a֢Bfh<-V(2]jTCTABDqf#iS<⟡Whsϒ6,<WwCOH&.UD'On73rh4/&c~3]j`o>Opp#ȕg|L!ZpksjTh̆zbZXxHhCZ4PCGdF$f(hősƒc,I]}϶1mʃU_(BN, ;;r"S'lh䓎ð?}66TY…ĸfR~ Kկ:5D[qʶ渾pbW>:8>7b8O* [['j;,$&'ȫyLUhGokQ5yS[<; uhfe]иYv"foa®eMXf[R[=<:ޠP޲'㴅}rwYpu2:'B*jocrkoa'x[z[T3V߲^cpcoR}%$YGւ Nbx[)RvjYuRKr &r秥(*Xo^˪}0h>bF\ZEy)N% %%9A%Ey)_sc>(1k_x[)Xv xwuvx[){Mr>BDDBHFfBQjIiQ*.)Q(/IQHJUH*JM̶Vҟf83?-8DVzr*l@qNNj@% i9)zJ:`Iɻ[6q2NV<ۗi;P* x[) A 3>3$(/1g*c,iiũ% \>)N9I~!Fjy?X% yM)E!!A~.: P@A.%Ay):Mb3\DvT6&7($U+%f椦)AL✼e!LnɳWm1bG!.*d$$gV( SOL Y="Ḧ"hȷ xk#A(8x&unV+xk(q"1/Y899'x䧥(*XO l7x(9Qr#DnײxV[6}N~e]Y)@v- ZY!1`mS]C̶}}Xꪠ FCa|0v bpfD +09N@%I!$N=Ɋ}q)6sϹAD;!7 @/q[6G^_įTU^3?&GE(q#86|ϼ8jF-嘫&[ύ%wl@3~5m}M}q: 疽9ӷgF<μ<NnAP.+ntX`N# l+xbF X>݃jf&&}s<zf6ܳȣpElgCKѱx2y\ gczQ3Iؾ.YE~͔l0]|U7|W1bwRU P'8+2Rw+Hd=v@Xqc;ӹ51AL 7aJ|썦=h>ݩ2"Z&kcnᓖѹ<^,OC%4sMh`97ǖcuQHiY8x vI+Jׅ5a$DMY >r8ϝx+;ońh7G/)z=/Z_ӬjyygG"+Ɋ7w"/kٵQK $OXZnv)rNIJ^"v@3-VȜ5iR(hUY [_ܥ<,b vn 'Z`Ş(%TlS-%};+sN:]8wck+81P9}b[Caԁ֋7nJeS(>p~z }͌.KMREFX\RA0$B1Lf'ZNuW,TȟI+p9r[ M'Akj m:ny?"_H6ne%׏S$6 4ۿ1QoVg[wFa xrNe,#GIQ~iqjQfMFMAZ]-xAe4dk.͙L7XB|\S7{spm Zx;$$A!; +iU TPM_ORD_SeJ udataM  4xpBz7{l`)J-.)QU()ȍ/*./H,*N(NM/JKQ(pOQJ%gV(SS\K|.N P[Xq %p,KRJKK2&?'ISxV[o6~~ũ&nWaY ؎%d0DDQ6ސ>Rwʥ$|<;w'0> c K"(f1+#".3P)x"''M MĚa£۝P< ILCʳ)p.{~bO4Y=݇Hp۔P}Db-Ľ"+U#hƖi]/IaԁK$enk}5U:mS&t}a%.Z:jĽB.ac,Bs>{b4?:p}d4E4Vsao]95'L*s@ލ_ y:13NV4TA4^_Y._ޡ #?g<}0K" 4 tAp@2+lax7٠UY#Eid&$(NַT"cɔW!kpTVGrLXVnܬFV}JZٳ oWW9G?9/p0ҍb>q.I>ZyjD~%rll`@L:I) Job5}޾Spݧl4f.?y=utד;CCR-|5A\VHr2fGҕ];+xFb8"T+_zNIPZ:2fxZQPr@Uæ+v}CK;'UX(cIěrGl%|S:U!6*5O<䢖z>n|!^_,yc-f su]鏪X`HprTZri%[|9:I%MƠG&))6\x߸8Kvt4L\0cdb<[YH-SU ϰ܊Rֵ:}T^xT}~ٯM̏~4B37f>Wfh&\<X*i~D&iu{Tx/Gf,#GIQ~iqjQfOF VF͉l |x/s@f#DFVF͉l?8Fx#3]z/dVNV[L344RKsJ%EI9)!A.9i!%n99: jiiũ%: %N9I: ~>> 'Gqn.c7^s=lF|vL.ifvjepN~'(-~~ήQ: y%A9zyyɩ: Ee%mdf9fr.!x= *\,g#XZp# ix.R|M︝ĊRKsJlJ r㋊ S'˰KYT8'(Es3Ru3 .N P2Ғ P͙eLW1NeE,+KK\Kd p^ AHsx.Uj?N>-y:fļ̠ԂJT2Ғܪso>þq9_;xUmo6,+a] ؎Kf@a h0FRm!}(ɲ wsw^ ]Œ&$$9VDP$[ "D(AR$gV}ǂ@pr_x& LsMcEyKIs"fNv?9|o/\ +SJ29}:Q7 g6+/4փy4tv :YPDm ա]J~%c T=1)pߛoghώm2qLwO+Lu(B0Zb7D(YjMh\݌׳v*p.@s#~ =N;ooEأi %;ܷtAOd\qHynIc\p0AߓR߭R/d?3SvX{g-iu~:ե0NY r^6װ]{KE!m j7DJxՆ>\= c uirDh!YnBW_iSs֫YLf0;Nd_\twhf'Uվ gv< oPř/)lJ2zV9!Zop\YXYv:t2b-m'fw=UkU 9TA}p۔WCF$Zo_{tɵT x;),#GIQ~iqjQfOFF&[^rj3Xg)hhJ r KJ3sR4B|\3tҊSKtJ*rtS+sE! UU:\@q2Ғ MMM|QjIiQBQ*+b=lL\7,x;)Lp,#GIQ~iqjQfOFyfF,,$Tx;)Jp#DFvfF,,>ARqx[ƿw2[X 934RKsJ489!l[ĢTx < $\bnpfUBqf:(,s,-ɩ~>>\\>A@&n,xVko6l dMt؀f)+jbď̒f@-E:{CHKȺAL{}80 q,pSObN<*  +ntKc3ZxP_5 m<+GO{a?zA,H~.ՠWj,tA>4נ=ie=*=v>+jO~G]NjhTuՋUb;ƄLJE5TyLS)ts|L%0d 쫴`0DBջT='miwWWlæ6*&_;:'\Gl+amHj{W.Z а P1 m~%pL#ʕ)v[BTz=LsH="xRn@)Q Q6m)DM*lg&LEDWV|'0$is9u[](9]v<b>ziR;ȣ ߿Bh0GABz𺝎x)n<  ]_$ϳ(4G++NYFSR#G:(ƽtF;w[-~} 뻚xlln.?: "`ʰprq&Ǥg'W| g+;\SAiNTWuC8S4Ē9\('&)&~ }C/l!l[W,@-n8YՏpbx+;28'(WZX<%3=$$?$1Ƣ2Ғ h0޼kjv7x;&uHj;#GIQ~iqjQfaFcU  g6x-XhC2' >Nx&Al z6ͱ73xks+.T&ƖԌ;#UI) 8Hb $"0Vݽ;Á7̔Dnwo߻nH\1];k{1FAHK2u44.V$ȡ@f2%vŖCAuB> |#i4ƿ`e"'GG_Z? J' ϝZW~Wx"#uǯ/4o1;aaf'mc܅w*BeYD?XU[-s6nd2Ğ{n6#ۏ J,j dlM?}փ<$|plT>`(<{S (l[ 0.~2nuVsu^43D4iw{ckumOfr9Sk8d%|86QbgWZ>UDUBSoFucLCp(r$x<T>q;w38ցthG*|2KqOg^seNdjZ$^0hra͆4~9k%i9I੖UrӁ)5zL΁"D9Ms:(l! h3v?R+N!E GR"[Κ:996~Gw{%\X%qcB"IPF$k;y/Jbw.7X^ؿu=iԧ= Đ+3Dd/S\v*Mb^glH0:^AJ# ؕ"r(p^_N1U6>[z"wŢ'tέ iɵ\]+nd23y51Dmw̑C#(\2^jTũ>t/8:j8o--2Yϴ2^.<]]}di]9?zËUh+!Pը{$=ڱG l2p`d43wnjuG7TS,ّoVVQVwcȍKg!l7HDf NiC;\T@wo3 0M`TTt +9A&/ZUHZ1e=p+4IBi4Pq#[h{_'n#M}=_1ϵv  9IŽ+Wm|GN+}$PF D}pHdqdɴ#4Q r@٫ *j~>|M5_zD;\:/Hj= .]% SKƽlYecHЯp 8a ٩`F Q8 8`Bx}pѿn70OgTBb >R &("hUC^D~a#liGG~M7a`PFAiJH|{E7S I/xDvlZSnB6vvpNKDAZWihPUVkkAGLoU43 VrJieO<EV\/B_1u` ЎcVIN vow#R!2 Q¥EhJ8Pr5 O29-s6$^FCB!` cu P*zqZ `E8(,ǬäǨ>*btMB"XvNeulգ汎un\o/YuNߺA'В^ѮKPԇ(c?2ccLAߖ`as0k]npفx<6sLL۹0b9OX(̺ɰ+8t Z~p7f s;"D9Kmq5&M`Od&3UGts=/TW)Â=m4%n@(po&vEFDjHՌ-Qs( OJu5xbZIҸ䢜Q]0).*1\XYh;.,_7oo5Hg J,9YJuXQh5+gɊ@#zXNXA.hk3Z^/Ou[);UhnERj繃Zf>rw M0!icpXcNz6ށYVi~i.@L9RrRs}L<+\V>h428?9&$U=5Xo.^FE[}a}-yl% Q(e^2\Vױ %$5닲o.)RWMR@8h |Ns֎,_AJa8GW]|N"2+T'Ή%zL%Lgw}X }bZ|60eKnb@ CG"@@r&GH𧉬Sxl8_n*S>)}`˙w59Xɂ Xjvr)ѭ-#V۩K +n! ]1%&*v6qd O銦h\l3s ױ̞B7#$%iB}yq߆j/)f]3 L8(-n@ IK0K**Xc](#ri,**}ɢΐk8(qh1UhXPqu*]\em L"G _K2ҋ#B +_jZyX{vȴb6Rq.7Q\޳Vh躎u-UeYM].;ގŲ*>Wѻ'nL9.f bӳD8´{׌+ĝb?);s#fjdNidFc@И4kf{4xf7x1+ʕL*O>k|X;;ܨW?nlGe)ђhH\gꃱ.\<e)R#b;Ns@Qȣ-&[4o3S)g?>y|䳆Yʚ@WHTCiW 8KVR9}"ўGpը g#vϙ<^%G_x{XrdCFٛ߱I=x;WrdCXvDs49x;Wd<#jIVx;Wr'o$7GO dN/9]oGXn 70Р8۰UˢZZu(W 2"`^bc.ؓ)T=ȉh ̃EZv.;dfik:S &XPp[ee8rD;zS 4Qd=L64(0Jj^--j*WhJ a@̤V^d7ⳤ zXzI[^r& bmNDtSTFd[ {E{RC0)sf X{^ uml"/^xDFw_ZX,,#CßBZ/A<7[ԼR+hG l fWRh B*mW6ng.OOd޿ 'bЩ %SG1aez]8/z$^^_q?i,>tKC?YƯd/ݝ>kGPc"* x13bJ6?)x17b;#OqAf|f^IjQ^bf~Ym>*% x&m d!s͑92/4iPnxtRݑeDqy}[nm~9PDߚvٖm x;ͼyBi%7'~%x;iBWIrqJ>&^W,T5Ox[|yB7nZ ؝Y\l[SORf}x{qG L\ x{4AR:?45ض83%U/Y$8%(` ͉"\`7G`[ݜݜʂ|.]Sxkc8ᩈnNAIFQjb \TYP hxxkc8#y xkc8{J 9%E)\ ji'xqBĘi@xVmoFl9MK^p CJrV1kkwMb^ݦQ#gyvތiGL(6P3DA e1W0EQLs$ CJs1x}QP20z^qz.l%ta 05OEM`JahFߐ)6w?{8ضipdf)\v wp}vї|WR,=:?>Τ,Iȗ }7 gUNGw`t]>\DOt\L ۂT{VzC[ʎA.4 ˏ o,|hβc(IĻp;~|0`0<: Ig¶Y(, uy0e:H؂%km[d-ci  ̃`K 0DZbpQӜJu_5gsŴSPxLX;;"\mXF<`պE\s]%>O85!wKO Y}SX?b\([#EX:g ,Q !Q f&R=A+tXZ\Gȁ d8:vjdMS^D<)j\@?T(,#09g t袑7M ,RLkn? ?οaJ-0А0Qr{`$X( c]ͼX<{ucx+ԑ3Sj|8g^D96 [gd8m,-qmq ]`Uک!Bۨ֎}׊]iºƆ?v\gU},Tr;ERxظzݶBohERÛN"z&Ȫ7VG&Jx.Sx&|qX29gx.rZxƒ/n~vq?3{S  x!ZsWO9 0x'/&rf^rNiJMiInƌ_2idq> 4xuNJ@ "^<[lGaROJD%43O>EDホmܜ|Ï;[@b $=_/' SYw7o]h>A L)10RroʤT&9ӊ^J |9[[I)*$=%qYDmq`6(UUVkgtpRw1\()BqqCoIOor4l]#xkٌ|ʙy9) 6%1jdg敤%L~XyS3##[ex{ٌʙy9) 6%zv\ BTX2 23JRsK* RKOX䋪$3,?>$"Dl[ WGx׈xO?OG(נ:QuhukZsqqJ460cCP2;"#ktx$V`C2 }3RR}<8K2sSKJl SsS8KJ@ɲ,H&/%3MA_ WAKs+?<$#'bb(BN!y%v% l6h*Tl眼E|r( ?̜dS kLͺ;XA\L$3x;uk)#GIQ~iqjQfGF6Vx;ƽ{!#[Q~iqjd#ƽ٘nt 4 l:x;ƽ{{lL"5Qx;ƽ{{lL7e<xZo7,uW,Eq@T-,9$XPDd݇T~3Cr_ZI\Q8+>33dɎٍt DD{1;awQ(yd8DA}#|i6e`ly$4g= #\%l>OdsIc8~(~PO?x+ث8q=9^dPnJ} a4y E\,b5Jݞ-nk,*H܊`V`+=.l{fzemq :e0 9>+nQW6u) Fx)&1m^s9wDz5c؞{^|.O֬˝6F|wpw[nzacL,uF_ȥms/{s-<M` #[!dg)~A7bΊGhyT $q77qa5bB}K=g,gq׍lh>]4 el¾ϚGѕݿ{z57ܓ.s<)|E "kGوZ1M-hr7 %/.dJ,Bˋm܄YNԍ]%;9W 7P6 )13}A#舑;!h<`9 Zф ŔL p؉dmɍlDnS~>'])0ui0T@)^l/':N\QL J8f yd  ֡'mBnQ.8A)`pXV,2l;pjiB- PvB;zn;*6gm>v'zmte~Ӯi>;3 T'p^\h6ͬDIe#r_Eb5?cV\rb1Gb&0:ңQbr+rΆ2ֳ/ɚYG"I!B !qƆ Bُ=lX,on&wsayH ʊΨ29_i̻1_薺zկ]Uwf,wQ 2?@/^h%:9^(Xb^\ 5R-J#dn).JamlqajA)A,O^)b.JUva ּrtXo4Pi iY~o9-=ηkpD,Wrf o.MdgнJ \XŞ:!F @u34{]Hstm/p rFxBvw5;UJ |8 "2{hL噛M7CxId`Ee Yh~0L0Ăﶱ]kUl%+Fr+BfPbgja0znMEW%WSUf.H;iJri#( ?T CUrOwJ`X9nD^9 qwp{*p#G:zvGfU(2>A8r80yfj۞_l?*H &g{+8@CLhW218C(CFxlIQN]#D/+90U{gM7 s"[1Az.UvvD{4ЫlY'L$ŽX`3q﯉ƽJ8ǽro7"Bأۑ3p˻s>߸º F xFq.RC׃/ȷ"w8[`tӊnKC :x+JdO M~|P,E|`EXì-SF|(`)x`By7Ѝݵ ZTYuR`A J"qV6>_qD)cuug<>_& ŇtɔᖂmZ5zi 0RVZ:ۿ9ghtFĵ<3JbLl r5,#Yܗ+^6_/#>g+\ ,L+0E`v:vnxt:~l8[K莎 +~Z,ܨk;u9 [|cfkj%SK':MݟzZݽ~7 ] S>>ququF o_@(o-Դ͕C=yԿ0*HCy37FL}o @Flpg_ ߏC >rT58eKG+ἄ%(xB]|co%^X~"p< K %'÷,:GWtGOyb^MuVv♕W@s*N*}o`H^?d|=zk_n{mZ]KO`/? NI +es'DGgAAk _0*X6Ni -GGfIeAWȪ= 1*:{¥ mE-:,*€*"-uؚ)h DX-qm֠4?}͋Db8ynmo$K:R۴9pl3c>NF ߟljn dMZoB&ڹjTT\Q;B!G]k4g$w;T)Vn9ݦyU `3vñ#b%3ܗɣo4qP~^'o< I';u$ nwH4 ]*;Ur\P6#X_Q&vЌC&vØQ~j4sNI} 6P7(x\82Q[čnQ/~Z'dEwdO}b6o[܎a z v._I$6!e~,;}`7ebAyC,nE2Wb.O\aZ<7@By2*W[4mCe 3A$ҼR%C,?ߑuLt8$:&j>!Hƒ0rH2Jn+;Q5}-6<FzTodG RLiW$8 c ]Kk/^+QJ~\> [3s Ow؏J1Ux#V6w'Şz߯ LRN_¼'ۿѭs8׵Y%* FCCF~gػ!֞RLTC"""*EzQGA@q#Q<}rs|#o|]MXȠXv E©>xݦ0f@|k')dQݭܪav0)8>U@$#NU,ӿ×*弧2&fMF݉O3AYs`my%̀rSsXز\¢a^Ye=F V ׵Hjmu6`{Gx}~z~,,h0Hw`!-u u_οUǟx^q%o1tÇ>讀lOClx{`wnUw[+^x2><t beM\,'CE=  Y06WxRkA&K!Ml lZz&4)=mv5FIxՃ {ғ'^/҈3̼|?~zɮTTmbכj {:c~^a# }3In1ZiM˫ 7j*M duРyCz9Lœi[gǢJ#=Fۺ/BpħҚԝ!׺eֈ_ \P; Fjv5:LfV/^CԼ*` Wf:Wd,ބv %Q=D^$e O"oq! .z >hp_S |0t 2zRPSkEeeW?/5x;efv70lSZRZ``U 4x[a3f$͋L7bB)xoqz4FҔTo3 V)$g$)h$o`N.H,..OQ/tqVz OV!=45(UӚ33MAV/GS,ZT6q䧻i()(()((&*$(dd+*rr*)&&T)(`V!5"U5TѵN>.X;!(gqjIif /v@ 'oΔ 3lhl3xo1b͎r'Jxod4ɯm&2i'g敤%ėTe(q)g%甦*(d71-`d*(93,5$>'?}s1m=qY>%)ɉx#@RM@VmP. QAm`}@l~.P49B/-(5(4/EVp܊[E6;˱`<xSkAbfAlhMzC+MPa͒nؙmY9G!'7Ac/}{1g揽Ku(ߧzPN::=A1r&`bćw!VL>(MW˛ZWieͺ~l/?xw^#4S]n՛kdrvBی]Ld +FyaK "{6=Hn-8)D o?>~&jW+}=Y8YۘY}2u|PD8v' GԦS JGA.¨/QF17VvV,Qun5Iem7B!#=( GQPBLGH,"o&g3-lܜQ=NJnZ`I{ALS{1$rYa8xͪF#.[è^bA?jY}zGXGjXjg*Ix{kj$3'2ڂ@&'gr~^If^inG= zx{kja WByFfNduY7f9xk|fU&|iEEy) VDm*l9xf|4ͯy'0Oxft4ͯ6MfJlxft4ɯy 23JRs63JFAl.x{kzd(5܎$Dx{kdwFɿe7g_PQ_X=>7feOLp;QWjoxa2pC *>n~! ~>> \>EEEJyy%y %y 9) y% I E9e)Js$yRKJt j+"vxb`afTlɗw1Na `4|;gf^f DdyWr'<Mx'(tQxk`C;7YDJmxk`^F'Yً3R6K%1S xkpQ=FO1l>yAv2JvG0*{-ޜ咛3K^:W_PY:y*n̛/X16Kq0ip{k(9&d)$&'(*+(L(U?<Nx{eK-&''whm(R l%xۥ\-oΊ'_cxWoC&MlţAx=J1EW ucAD..t̮еPڕk'0&,;`~Dp7O`ݽ+{>z{w= pE+B7s-eJG6PvJ On08cz$YR7fayɄ{U._ɤ 0'kq*bej ɽ76׊q2.D'xMJA9N"& b),`a% "ٛݰ!\e# [ 0|y)~^ߓ3yJz25v{gYxs:eYz<$P`>TKX H G]eK8#r J[ ;+,qXZ:~UG̿+RU~uȵD bPykm EEEJye9) %yV J: NbQ5')ZO&`YE w{x=]kC=7`\xݢis+Sd)~/1k."Ⓖh Xk' fl=xkAe ~}j x{%^zvf@6fw[|j ?s9{nhEѭk$wNzZvjN "ڦLJ8J=]aN\>aIt<` q&Ԏ7xV"I]ScI:Z_E~8mlW5@j2'eTěBC{Io5{; J aaͭtsMdJH.GbD M`.}h1 FyItd`; @vyIN-g]&ܖxyN1-wNj7</T СGQSzqRr7)Y~fF3æˍf\/[nQ?VX."If w?N俢˪MpyuZo.ck4_\LO,;lmԲsfv̶b9}|o%\ R8$[<걭ߊPpzį黠n$N~`&o yϟwѯlxy# ;<D4˄o N6vXCD8*`C)djSݑV061~+oai >ˮRИ f1@7 m@ npA)t87#]"f~p ウ h=g/lm褆zX819/Z࢜nM+Dg_ KCR\25?"הK=v\̸uPG-KKJ薡Kdw]n`@lxŀ^334axϡ  ”%Yျ}i S㳋bAp%oN9@`dg~,N@SK DRs 5Dz~D vd /gptmm !w1/ŏAh\3‘mwwԁ5xDrH͢My!:oױ!Ue,|Y1`Ta Aqڢ5E1*0ʊB;@=V妥uԠWcjZcz~DNS?&Yd.Wx s-*%-z[<)OE:4V OT%2AB\רJ=盇O la;42|" 90"Ϙf8PA;3Lh6_oOXf)<.,vB#yaC]mBbvK\D5= sٌ,.\ !ݿyzMQ ȕFa{ h˓T̠r*ro;:&fP-Xi?.K\oyp$gm/e~@ɠQyP%":M?"@ AĕIcb<9_֓z`!Ba"I@I;9,#|"}MaF$B,J&v1~JGqݢpLmT%"&VESʶ2xzrU<P~d6J%tcrK_0*"l}6O]Db t~=f%YhEA=Ih'J+>il`BDY3 sz;jQ=rkiW(5nx0ّ GR?wS E=žɦ 0Wn0&vXL?*ed=xPyA`uK|H=l1 w# PZ B^&HL?hOUH{o{3!2[5F0UMX(<$[5H{T,9'g;ZC#0UU.>߰鷺P\=oCnBClS͞&O$IX w0j4sTsBoL -0Sf./(7sNZ[kf6|,\3g«2Ϙ$7И#,M  ?vȉl6e^+fakγ(HIhB j}H75]o@v6D!ol}~Ekzepe#5KL=j ]R(@Ts8zy,bڜZQ9&&Q꼶.LuN?BU\ZAWgVtsao_Cr?Xh,L8Ne$T(1qVdT$KPqڈzBZ@NaXؑW1'{&sY_~% ؾnRa!hxHim1un#spՕhvj,hJ #-@IN9ae %R= /Y#ˢm0khV1w%F-+jKtogaiklj,~8},Z/>aOw1UX:/>x+m$UT^oڄZJm+09YG̥[1*n2u{ūMyl*Y6[gQi|< 1AwpWCWc_`e+&ZЭ\NgŶZ>[-mܯVmVˤWljMUmupv4ŶZvXu2/s9*Rj[(TR>1APCan֪MUsB9s숬A)[oʡso2":T/S=H}Yl~~٪\Xx[|<&8C &nt[#RsU4yƛ-)9 Y{_Q}x'᩼ <2ug;~SC*ͪ6 M2Y{Le*Cgԕ<.s4lFJYzBmgd &|@[AeA:x2]PtJP4aIW<_[yCa1:!v)y`q '6DtGԑ4\.>t.Ш?}vʪqElkGEtf-C ml.ǣO3b BM1P"bIrggXCߎamz.}ܾ x"([/An+'Tܠw`3e |>BF>#ctB#l*ol|.!s5Eްf<{I"f fHT,?[^k0(4oC laxMZk Br JTqN;R:kea&Άj Y,%مH"9$q 0cnvMN - ,r/>UdFMw<)PVv6Z^ _TH XLGR]=isu?(M@3DYpp"\t;5)`A, .ޡ`h>Bfz ܯ n[/.Y[V`:F^chfɪbh4i$kVu`!"/LckZjtpC iSowjt NxDȕ?ԋ2_襏_)~]M]UAhvvwTP_ ][Gqm'/zיDv"';~@IWz1msvL<ۧ9G(lta7BMj(\T l/,zI{"a9z}wѓawp6' UOYFnU_A<&"'ԥyb/ f<&z}S]RrsdZPVxd&LR!R'TZqt6(6Rn|fP?Fa\נFč 4mvG4|`|t&D/?L3Ivr/4^̔D\X{RyX䨹7qѤq| ֦Z>a zNqx~ AMl ]E=x'ط/j k1G# 5RV lE6xv ''!?mDWxqZ M2JsM^.2ICl3;z~`xg?7Ox7O I1b|Oj+LXDa1C~JجНܪ܉)h 29^gBlT0% 'LεA.3S' (O^\@7Kh+ci'9^yz8K/0Y!exY&݇Mb/;x*0g]%Aqn) 9)N^)!lwʌŖ2pj|YGNb3I9J]3ON|k#I^|\0Y-.i9@hk' Dmf43'}4 4[< 5_Z`3s VĒ4Tɿ`S#xmTn@V$r.\(U !U  J d6:YZR/gAH=/7ހw`6vE)~3|PuR z~DmJgCdZ}ejO6`GzŹyH $cQՄ@x\_=lk690pŒ.ƭհzTS 'K!`kid%"yYl4Mbf/2NWͺHTEz:ѬnHX;($KC=?|s /qS0ӿww^Qwƨ&t6v: F&C'2M{hnVx[qZ D6.p1+px<R NULL, 0} }; #CuFGyKx{ŸiYFPZZkͱ,{7[Mg:K2 x{q'f/<~>>: \\cY0nd[-0[w3DD9'/T#q*\>9F*!5GBqtdgE248&P|^}rX|V22p5Z&sM ˺&NbHNUld؀+4NE/9Y@UI K? T7p}bQaOWLrt \ҢQk[Omۅlznؙ|8h Z-ЬW;vj܇`+t?BhEnZP YD3k_7 Y`k/n\ bx.*hQ'FаZoKe^&ß&Y[X(1ԙ8 R$7N"*Io h$$ fPKBlYa& 8Y6,Ed,R6瀴i[sz |uץ.ȜQKp59ʒ\lq`P=jhv%eYUQ2 PA8 eNpFXO u#/>() !2񒋔G.(Ys-k O264P= ;']VY/̎ZnVn~at$puFJhخ*J%[8d)OP̛|:z2I};sׁ]$`20֓d PpD"cj5㔫4&G)@Q^t-0 mʽ[5xUWݻ, |V VVRX`%S~Yۗ&,)?*$;8Az!(EGBVoQK?ұ(ޗfj tgVTy0wΓ>0mzYV#/^ _"ä/:j 䂮أ;DXJ9B !F1 .H b*MhcyTB]ܤg}%v9+E?W&st%_%>7Rcqˤby7iQ'ar,cG]Ly=9'>hR459UGZTnU)1ih(@g7beM_*hqa;PB ܃pmJaʾ%MuB 2T '0"-4/%Ŵv} l]< L8xc*VqT5_V=VbF5SvEq~j)C`VUc+gH?>TcTϨrnC2(5Nd.nHN2xj53A"PJ'v.,h?-$SĂ)Mf (NkXcrqu-5[Л/!HSAEi>"K\]1M҈4C RWƻ<8l+ןj) I-{yK`D݁%>͈P>sbji{m굩78xZjB^Q8vFJ 5im=b[dҝg 5rC'OE҄UDEJBs!|{͊ j$: z~5S FT C?])'G-fkQaL:XrW.r>Ow6k({~mGddցDJU6i#   xr&ecd[aɉ*6BxӅX52J47W`,"YZRZcUť 3gVxT]kAR)bjiݤih"mU "V_ffLZZ}yO(E|U|Oޙ66ŅsϜΧh͈:T;P]R5z8<4(`dF^|8OMa$diW¸D53ÿƧv1boyoK"ڮnr(ABBY6MIIJCɱ iЗ>Ճvo%3`X.Cq@4,<bFaUO|ȨV`5*[E`DthAvNAmE@hƵ:ey( Q@DFcq``t%:F버WkGV0)J@" >,ᓐmm TBQ lbp=WCHJ+U_x~jJ됂E߉=/:OΟfG}iiο'jc,[mІJT[]y<ă(IB<9t?Lo|OTMő?rs 48 L&_OR OomedBV|;Tug&^³is2r  'x;r8iCJ+qL~y2#xN38ٵ|9ũ٩%֛s 0 jd%jZsqN^(5?\"o0O^( /?yrj^JfgQjIiQBHpp|pkp,77Le2yTM9+x;41i*֕R+mVRPb"xԔy!̹J0MUcl4^AG$(51%D`F@BxOAdzB@[ZcD"b jԨKw.dw zQ_b4FL .ƋcyrJY$x|o{W?>|6n%9 һ!ˁ&NzcI!×gY2cɑQOGj U;H2lÆ}[.fhE MG)JW} ]su4mEr_,t^FM- %&P0qp K^ʜc Uxr0a.ƹBLf&w9Lf&y= Xx[qTf^BQ5g_BIFQjbJ|^idvrJKmEu ҊSK'ʩl ǝRx[q!͇Y7HE0ox[q!͇Y7cK|C<3 x[q!͇YS6[cK|C<3 B @x[aC.#kq~I䍌“1Nh ST\_ZS5El" FF\,;&fw wu,*Ș2ق-C]Κ((O!y `J“8΃ ڜ\C<=}\]62`+6 ctǧ0NV٬( ٦@Kx{aC g^Z2Gbhx{a"&Oeqg^Z2 l+x{paCH%Ax{paC5rf*!YĄ !G  2wOntGlw&UPuCK‒8FN]ÏR4}ѶFPP4DxGC#dH:=Gq'2*W= L!!fqM_͆lر&mYb1tP'Opj\M#ߢHPUn*4 (ᘖS^>P G(7 CD&pДCC@ky;ADE1pbI2\3;i\hpBmX#gem;#a;qMoFU9]t~[X|8"nRj# =3wX ڿu?*r_q։,_,mMBvyI擿=r<~N#L;|~6CЇ5vv\ 96sa6^tV6>T}8v&scKs8öɜ*sV #]O<n R'O az.X`r}!jc=Lj /Xrq6tR-|cٸ <",v/k|2 8vz;npLuSji![SR(8:kB$QU-_Z^(i4/~Hߞ')%;evees}Ncd:ͬ|dzuە:8)Oģ"9ՃFʉ%':E"cy λXq*İ W(A!]@V&bˑ28]H {K.GXf.ԃ=,@iК)sR]&HQɭaiZY irw I~ЫTf,b%.$ٕ&Y9H|LXfvPO+<ȧkUbV F{9[ {z}kAFǞwOT JE{X^M3FdP4 G`\\Fswmy!j Dz{vO"KYUzqreZi2mv<#{-MCr>G.RoVgp1I! TE=ſt𕶩Vs`* #TO[Ќ*uaig"HNab{.*D )[fO6.ʿ~uK9aƋ†E3mѝ/*jO@EX|߀+1(U!(Sr krVUTGW!UlYκgL[xbLĶE66sjBU2w`+~ v@]ĺZ){kNt)QuP)^L&5{pAc )CJJHR{XjS5|f<50[\P_q[0-O/4ˍ0t}TxQ9i?ɢrظ`nw"QtlܜJA_̆󑼮LMlK<]^) y xatpDfV[]X897۲gTPH)N򀠴85>3/8?9;8$(z e)h((h*TsqNᐛ/?%8:3Vo"P'gr~^If^i5S5KW((OdOj T]Z PI-'TZp%@F@j5.Й7ي3K3&KN|w&>EEE sJ^x|Ry2LƓ3JONdzɕZT```=ٝٗ39?$34zrY:7`eхc.KxbQd=N#ϼͩ!Fx|Ty2Lz\EEy ֓ݙ}y899J2JS7/g~ɂbs'|xܠ:cBO|ggKg~Jj~IA>ePuMcFCl?dMMQ&3MA# 5/5%hkfr]f~rIB5>8kRsSAbG9u&wsqI*%f8ij*(u=ҙǣ59IP|:nEfU~!FřUAť9%@mD'GrMV#*fxA)Q,\\S  p uh , +*wGnAx;|@y:fC&Xhrx;|Hy.f=Yu6?e `CSxkP"Xxs8+%,L*kY$RKJB\\|]=}R $sY;>A.>.زײ2C5o~. Lf< d{TH)NULS(άJ J-.)QQ+ќ ~|c Bdb _p_H42O3ry$5  𙼄EWr/_p?-/Twus>!.s09$|l!x"^~ts8%!h88xjQƩ$qmHbN"% u?MF LBg ә:3)b)q#PUE}⦾@q&`Xp{=7}zC7p&W6##4TR:Rw]VjהmfEK 7A MXN,'QNx/jJ[ I[>,ubDw E5溶:HmEj\K%u\1g30Š0l{~6W*&%m1vA F1(Ϫph 8J5ٳA_ɬGjKikZ0v30x-cxn&>Νs3&_ݷXV ugDGɋd4?olEx[/!柌x$i\x[/!ad &9'obTQm+S/ )x(u2;yX7'skx&adcnͷy7.xٰ4/%5m^F@Lxi8914/%5m^FVynx!!qr$cBhqBIFB^jBf~rIBRbqjBJQfYj䭌<\}]'3u!sK'20qqr)Ļƻ9zXOg cTʶu:5>.IJ e*iZsMNdeJMLr&O`i|S{r\A_siL~ìم(ÇG?^x!>E|fF6ҼԴɯwpy:8xL^ԅu`.A^d39U93M`rrj^Jf~vMn/x_ 0şۧ>{ 8$#!Zك>) |^N ,-R(1JGq7SѬI6kz#(<$݆𐢄z#baA) JF 󉽁+ ޚ6|0ضՠ@w{-pYO^ 6{gIx̴i5# [x̴qB,[rQeAID6 ^> ZK)MIصx ur VU/H+.3xWmo6lkN; [,X&іYH:iH/`|%xsǓlЀ^䓄 ,b0b4%L<mzRU0IvKt31l٭CO,ntx"CgɣpP>&KOc1Yh4xxs&>{JLH/$pG7$ѽ>_xQ|Ea(Jx,J'b檙>Hq&(ä,0q N!eTP8D S!.}tfU.FSy\t) ?((E$ol2粈^ME 0s{讏79n9/vma0av1NW}?ߩ*[sszc^6tMd+$V{ ֈORs ?~@݊^[N s>vdnkZU7;4 1RU++p R,:| |kjٿW {U?<- fI98[X^.5͆r'tUmɎ>W:w{A_ 0qIWp4/HZjW&+RFN… /=3sV\򵐡E@M\f ? v}lPky: tzG(*rdd!xPa.OqAf|f^IjQ^bfS=L?Mv`udTzHkl\j)%: .N6fl޸rnbNN~FqfUj~kX@KsH_\E8k-'x{pWa.d>&͖L|2#x{*Aq4ƙXs; Ax{Pb.i77M?Y}e.!` xX[s~_6>~~4g:.E'K :X$ V БSwT: 6bԪ(o^8t\ agoZ @))DN!@!6A 'p@h )TlUu S_Qz1-=ߧu+*F $T-dp}Ԥ] m*HЩwy_OHF ݤK}䊏Jv8D4l~҂24;$-48:f]e'/^(#g6&W:b;`̦c R]F? J)RZ*ڿLE_>35uhrP0^prѨkZd a%g&J\[Z[ҵܓ2sĺؙΉuM'7?{Y`DX=PiFxŽe} ն˗޼&C8A[^Ew:3FfE;&F}zް,N(]QHش@e\h%.i5 Xt6eM졦쌂:ګnj^(~6[%ϓB|)2<־b7V3jlXͫl5kg82`*YlUq==pJkTT;:^i3#%i ^U+B*0_K yAN'X*Lb؂lԾ?_Wp ]Z;JQuʠE,7O㺚rk=:Ě5>r3x b~ӻpfy)wh(s߂8N"[;+ `sb5=![qm["">D Q-y"/09fz(F.ybhcl+*{/KD sw&Tºm퐌fM ne, qׁ9J~tQʅ*[&7(D"ؕp{m"S[ehpU2oF"fN~GW R 1$%CsKUM@ʲDWXe(oE畣n܅.x0W2%֩ѕ CN9W&DkzPxJsO|g DcWsޟrNБcWp-8gJX{G\] M-_q:n,]mg.CH[p@eu<[JZ<}ܠ{L|ZCt9ﲉ+՗{WW^AiAGU,#Zse%6__~}x.͊9+ 0/tm}gCp~c&4CVݜJFR=kAYxk4mL*;xmJw!F̼ԢĜɧm4ٟInE6%D]j 9v5H5gfD_BMXdr^.gYzonmaίB5ߙzl~(2G\TgY N~IyFIy: řU: $ſYLҕZ8x[Lw!FԢcr lZx[J{ #Lτ"qx[V{ #L & Kng[?l"x{}E{Cr2%BܺxY{o6+dIg-֤) 3$Bh, "-w|Hi]$l@xw<*hi"! G<&A=q }zWf]/B=g "tB7ڔr|B$ރʋWZƾeiKl2"aޞH0KfR."&cG ~M\ym&) `Sx |o67Qg8cA~^Nj!I7)s#ig-<'1nj)< }:n% vzUPo$F_bBpQ"e#ADo C㌬d\.%n,`(ZOiF kaHN`b8ܰ {E񕂇/S:(oBB4 9@zBT$5Kg;,驞?kA"jĩ +:KYXpX)q\FOAJ^X>4O'jIVAX?~pz>8'>!OD)&e l4(๜*q{RuG8VL{s 5.-'9;vIp+IQG!= EڲE{IHo+HeCHiȄSjK9|Ewiˠ*X ؼJ 7f*.Ȼ"}"f4l;bSvD ظ(me`W'$o; > Sʌ2F>CX &=?p Ä-Y:M\[kAnUdƴdsf<\1M݅iȧq 쬏RsU^ixPT(Z{X#Ɗ8tp-B;DO'J=rhAM9x]9Z|QFՊו?(Vc-`-#e0(eWQx=صOߊuX_wCʫZё]ֲʮI,vA^ Lx$z 8E\JƆ0 R}EbiJ3h()Pm~Q]~~ N]. 0쵗gy Œ=%pѓw_|\A9 ]Po 9Qk}9t޵Vwd8Q$Oċgj%S p=OMx'Bp ;`˲Vݼb{Q,$LzFQV/9hi-A%n'v$0Exzޯ$թջRVfm\p>_u<9G;jZ|A j -fr^_׫EVd*klgiv^NfrG_h|Co ?n |1koWKu@ ֫m4^MՄFV`|OO r6'ՠi{vze' es*;?:j?w$~ܲv48zb{3h5DEZ/fߞO2*c'b"AXP B.%4ޣvvߚv$uhiZ.4vOFMH`Ɠ՝" 6a! j|Q2>D2pB樓YPE͕PbG:ҌZT^k/}etX߽6w/w/+ѫ谎^m6W vBtY3:0*U'R1*{x4@R(UVFz+D5QHopipp(erp"jHWrsi;MwpI;dd#7[],&wrC,z.r\S9n䂓E$ 6%xȊwnis"U$1 2`0'[ϴ ',vI>[:h 'TX).Fzx|u>|aFRu$y>sBD-Kxu}FТGzVާ86g\gY/u$ټWD.Xsxi>h/Bѡ l\[ur6E΋i`Eݱ'LJ}+ႩV 9fwpI^QlNu1kPT<O iʰ+eiE” o]E_laMlt>bR-td}b0#вe=_=bufJh!s9> ^ҳpVi$YpmB0vK z9x*9= FKޛN|@IvD3.Q]_BH aqB_HqG6& v}6 23Һ3nc@\(dDxV^\pGp8\.Y*|8>sJOC sI'b F9 aY@K㳀&̝X{_1*ay4?:@.ڍA9;ow8P8B2GM5a-˧<[dYS*䄴 ]}l)'~~p.BSLizYgb۰(\<$>=nDߚ̠qQ1_OSM?.hWY:pgMlPn<\nO_atQi0aO oڐ2wR4O}6&1(FՉuKBqݥxN%A>NMYME͊Nj2bbyF|QGL Y*h\IOEC\3rZCгg7A*M2ɭb v6O5M+#\gF]:V 1zi-OxVG}/YmڋIs]:TFv`/ Bvu`S!uȈl$([ިǪ%u>oc`N ]]Ց-\ش\^).7Wml Da8 , _ EU1<Aޤqs^뙥`1Þe/[ i>@pJAZ>TA"dLi-PqB Qz@գ߅/'/~a.mgtޠj-R ,mw1doف7ۺmB%dA[hW̰EZaS LD@n"@TqAjum`:W vL XR m!b/<_@Wp%]gIIoQInyf|^NnjYQL5 Y\}ie?ZqzPu]72;'D =~@)kma?TӂRr6ъ1Ęo<<`W(bI ^eu3W8G><^s|%;ؗ1|3q'=qP)tݡwuK[`BYmCWTb<W*jz"mZ|iyxNFIDMC$(kI~X AT\-[%jX}lQ"Wy3U _As˜7(0:~Z¿8V"Zzݗh{_-rݬsjͷv>Or-ەܮvD4;GKǍ)\[E~RD.D!'UKO4no<۱)0!b lb܇M |.6;bs惛f''+}9ʭSуG7O8:xTQVa~N-GMZe>g=}͚yĝQtr֬>KcGne9](k!tjæV<%swMOyJT$$?am5s-u!mⲍn.iC,ZpsBkIqY>ՊүU~i6%;,]1A,ՉfQ8&ZS:'_@LK̏"]|^y_+oWg%St cӚnl^fד|:^$ d 0x6j#=4]W/+^} ,m.G/!'!Ú&齒 풃d2;c {G,i27U3Ka$zz1Z4gJޱCe%t{3xNlF1A  X6HJZ-jTG"d!ERrJJxz3%5"gxnb+ :͵Zis7/ucG317GŹ{=fG¥A9,rX놅6qK` ,60G8̍1S%ЇC. ZqiWXER'#F8" U.p) 'iç; LJV"R̆%9צ1El5n-swGȌ~1@Tf2CzGo>q gY 0OB3;o#o=MZHM*6qΦB@Ej5 0yMM)V1qM"j80/:6.2ܳ\BtP*EqO jMًlD*}30+)_G<#ow}%vGS7wN ],@29hQo'PX* =E*~qnhqNXmU_T9b U??o:-k!49ch$Z3P|:8h153p+Ꮙ((k5q?.Wjuv^&Z=T+Î{0PL2] $E7G.vwUZRvJP*#>'1]`gIЄoj׍e]<PQLv0b=VN kB9I>epE#rMV)6[}ZN&lVt R<LPw+ xt)e#1gT,&[C F>|c%r0`.R0% MvjHU1'~ Ԡܘ>vLFLYoW M X%,iS>lU KЎ j{庂C$-ivJHF"ۺMCq(&=R0C*w`d')i1MQL%_c",wmǼ]BnsAko1_D,D,T* QC'-yW760qG_/q`<ŗ8t4 ,b*G谪 jʚO]Qf~PL uSAw{Go`$1K|zJV-|4Z9cY"o`v֠RkNtˆJ!KnJ'kFkVHbs$6G`rshO@ R2C+e+Wa̓huki_Y>.&1o6Qs껡,˰]yi}7Z8j}>L:Ojb苳6n,b/'pYQ6Ƃ~-?*_,VM{:";%آZV%=&J޴(\4C̤3ueD=Nn܃#z3D᫈_ 汅\)8nŔC\A%P$LJbӒN{zK^ҹl\ $6ba=hmQT qW]qx5ETvTZ`]@ @gp$MFz!J%ܓIz ";x"FjR:_~~杽R:hSh~w78Dj=]klۥ &+U%f-n; '#]i_Ahz4w~eg_Q6,ag #i@y'lAf]"[~?Ξe(N5F RR=7Z.C=iC`vh1mgfmB o?'7k8<<vJqk\d8ΐ/rlA5ۧU;hq*]6DeaT[!nzgzQbuvjZ`uDUrx~^x}!G;|!q>Ӯ4K tO#3E#'j2 J Fl#ob|AC',)ɫfP5-[L&Co4ڝyMl ׳4uKĤQxWl% }|ɍn V-o׫1SBKxym>g kmsZAN0U/"lZC O!ΤFW*w@IB= v9&LPFhܪc8^ugkz=,<ݬ1`V  Nl7mb( 29&Mφ>ahd\@hht-p9pspրRBCXDx EƝ(!R&EHz70#?tD I>sL @BU^p5|FBNߑpt[ V$\0#.0kFpe$p;OlЖlB@ZBFN n w1L ͡]ED~pqg^D#e# `Tc:k~LPyǜ[5|cd5L @9sɪH{19 H) R1e>X0sʴrȀMz@"TvhFM XJ4)߇'&gBBz:]=ԄL&ΰ,{`6"ۦ(`d-DXS\e.Atc5K?kCW.G(зzc?\D2ڏwL·Lwl}w$+8H_#At vZC>JL@AC5H, 4Ƿľ"#|KKRJB[xMofSܸF!o|98Apv@O Y "8DZvz޴c|HD/w,˓:=h޺5)]zTp _oAwY儲8?uF2cAJjFjӅ"5 B:TTJsRzh/. Q0/ ;Z`+c H;s;U&>'5/ 򐗩1eJ[S;j@,>Xu4:X$V6 29K wtSgЦ$U~4mQk8%f9洍/ ( AD$_T1,GfQ?aHɿQ 4;Gw&⧈b0"b # 7]AB3ޫY7_aQ9 )hkx8Pv5p8hM8[cKDq /aC#g8vCרb+" %TmH;m9͠{nK_%b4c{%xF3G?c2}C1C:Z,S̜8^Q"&DVP8dt)VZ;)S˪te6-μe9fЭȂ1'O-hDCawd5` ^./׫4g  ,|BS J] /XT!Ԛ2/R%S22HZjI0BUk<.xa@T+P8.e=-UUJb]Ò:9Ͳ.)H?ht.6%6JReNfsv8~  Jx.ۍ/us9iy`^S:pZ($}z!=nqMl.: h:0z0 zeȘr,R`S_)q 8UPP+ -%0e\[ W)ү %\5M &jH|Ӽ 4 _ڙ!`9f۵I/ScBY}dX U/OWbmI䛡q2 t)[Cbd|cuzhGf6W,w5_\1g_\1oSAuZ8Kƒ%OrvJI(F @5 **J\dAXdvsEeR1:KԬWyv>N0Ha* im,%Ld̡G#scc=)KuO+vV&9ʗ\K.ms4+r #SoHł=M-zb'|1OnN6)X>b5J+s)N`qy*; C4a ptU}2_$X(~ ,oM 0x2ĭp„YN bN\JXq \ʵ]TQP>:Z4`.`|3%! ec(eOS,~b*+0P>w'*S&_-|5@ p]y&c̷}[(~o'PukŅk5P}a?=M 6}msR> N2wS %~(}:753g'ut5,ŖИmkzw8&vƩ:J@.[)SiF9٢p*Z>O {`x,J~:V|eFM~=6{@}oѻ|8!$$o]1b-哨9^:'n [>o*~_-p_ ڀNƫ[W,OZjXo-Rڐ)NKHE{v?_=y"MnCY?+RMVc[1ء|@=x`BKTXy ų7wң%6NhjR{gaэ=^pr>`1{_LA7Hz$LjU=@FKʮZ hl:g7o5'?<ӚߜW뛽 ?dtȋ{lN\uѽ6 V8#F%a!†GvKϑ#;0h<~m@gHA.I? iHBO x%DÌFD?k3\x.=)P@ G bt/4""sxy|Bcǎbԋ=8\R >.Z[pV nzAQyXP,7Na- '-o?uȊ8 Õ 7lXr;e _'H]\;>@->cgrqp+֋v 㶤"%qeK<:mq߲FM ًQ59 xgflPsJ*`C]ɛ#C 8a/`Xn\P`qQӦ&0[ۆe~%_6bsŦ]mӵr>,7]Uz^C8g* &E; ?fOl=~T<:HZ]4kա)<Q=J/N`\hXgpq ۫bj^?ӳ(N#nYd\-cѤx\gz/.P!6gXќ\2M`%:zU6&N󝧪MrSqY'c p ;=e=W`Q; ql4RZᒴlpmG "p4OAk J@(% @=":iP_ef}#QɗtQ> 4-c®`+tVlx{lqj㴚dz6M>ʋuz^ ,TXn:˛SRi+QM66<㹑 Llү?mMƼTXž#aiH Ye&VZ̤hx9z,5.&;HDVy1rC`69GXMCĒqZ7hۘ /٬` G o3FT25̆:<*)M'Sz j/uI%kn;bmK{!5Ct̀주k @]1GW>c#ɓ2bӌסȷ͍bܲo_9<>mV1wL23Iz!lZk`(Jymk+!oi!|"|Z'X^$[2O>> 'pnfrsP_2^-@ aRpg6vR)yIBv'䤿gL74v/BF%zz1Z4fHW; 43Ѯy39qsG+!;{eK^A :oiAD^i^GIi5V&-.?]TY'a~ɲOx =? %GϏw(xP64(/A`AFXnY"fJgP2y2m<:B%ђO,뫷%MWRExΥ۬o&0 7iVɾ1Y1Q0eGN)~3 Z0ͥr r)P:N!|&;*LLϊV&˚yR @U gZ b;#^=h98 $lu^Q Yr*O% M6-Fa"3gG:75PzNih*!9ncHDAӞki= IL5y)4#:F ל>УD.\C .'2u4p)zJ z:/cw)?iZཻ{xNk.k*svx3T >)c\Z{(@ŕ곥 o  ^58G2ɍ힪+H,K+emG<-R v(y>VO|F] ض,mvxv)n.Y{\s>.M/4:B vEVKrR`lX2F Oq^ P)455ܥ<#UlwpDOױ)oq+LP8#ok}R*oG=<zhʧtHV2)R\5Lba>YóYe#xx\H3WbI8_| EՇT10eNoj<89EJJ\ؑoXȂP=SOOG:NƧݠt] Č|!:Mk>?Aɐ̛d+bɻ h o[i 4NO!ٶ"wS6cZgNku32-eI >0U@Mj-Ed6%|S%䯓:}cCQı[ESe(:9@{%Q'q.,5-5$oȁfSc${ͳ"/& j-$tN8BxriJ4 iΝiYpgpYs.(R(#^6S j\FV]KN!=t-Նev '_Lq!^ D3t98.i1eI\BΫ(G8n!C jS*/up4Q!l6fMp}_R ꎯcx7l-kdP ݕ÷ &ߦN% gtQv{`کZ% ik$^ 2ii=!c  t oEv{qe9 . nFܠU;iJ? 3^*pq~t;AuP'PT8 dz*-l˕9?0(|SQ,~zQˑs"WBcjǂ]fW4ٌKK؇D(~*DZ#TcT+pXB->q:2WR=Z\JQû_4@`Vܜ% c3ykxg.(锳$T -P .4ceXgH>.!b8H+C;niUO& T /R|x7͸#vl8J0P)˳zFnۧO*UO 'lB8ȣUM tʴҐRN0ROV2!c.KB$i*U:1Ry9 fk+![D:+e=5wlmXW^x[a[~kqAKaq84/ڳ,(Wi~et 71h@'@ I@” @;| „/,9ø; $9hn. +ԟM]V],r."ilC(];;B/ %،V4 IN@HƽF >lP|`QU4uD>681[5L={#x@?H5AeA"8D'A'1֤Dap% x|cde;SI5Qo1jY,?hnpqtI,zBD\oh}zm=FTē$(!hP1Wu? qx;6ۺH-gb,_AyS˷jSh+d=W 揊2[QWnU%$2'^B K{+zH6۬'yifcY5}v`XK@S}sP|2fe,-%JS$M6VH;Щ$f@)IiG XZ5J>Xs~503% irmY_ nߊK #(q#N,̈́%B֘r5)k$~VbƲĒ<уelN芧%;hW~b#ּ;=D"ѐ& c!b]i](>/|=a1Z9繭ZӅVjc4r‚G.:=f~l#jsm6a:$l8ݵ;0FN'7ǤwbҶG)dMM*gtH)zBd[z6DJv~%]V=Vm`6)ESk7xx\d/oiM){G\ʰ dat#b+`]j8x\kmp ]>xSJ-~B,Hݥ40?PxxeJ|' ɯ>+oRZ4̵uG&(EH2!w¦\ZЗX_m_$jxәz<ӶN-0G4Q%D2-uc)~`xfgAOo߃PdGT*]A_s7򀮦Ƕc`pZ#I{JGiIj"D|49>l,D&$v`k}_cOB>'J<_O SXv!_5PqVHL>ou˵:¤WDk_ǮAqI4̂l" nLy Nxtu |x'smuy$&spL5#:"<@ɵ`:BkO6KN"/ n(!0xtuAֆ-łL9KmXWn!xtuA 7]8K:xtw{ɉ<&[3nǔ6ّsdUɺ<9S&o~urfyF Z^0'N?%'hћ/ NڿM?'qx8-w c+ c->PCRInfo"' M3kFxjֆ-C! On[x* 7?h";Wtxwóðy^ Fyh]Cx* XK6ZaN6<{H xX{L[M0`cw16&o+|7~վ:}IlCXJԮK6 KbMkj-ɼLɒ폵S%VJOiCUs~`Tw9bW%w.ܤoVB| q4_Fm1Ymd+6@ )4D;;Ȇ#jىK D :SSt@T*Kdk:XEy@}J^ԭ>ҿCc0UuE>}];rG|Zf"ZD2)!՜fG/hw6MFOɉ~5Q-$ q5&Hl6Aip9vQ\*`J@KH0"dRXwh/dR3Ps'eQ1w2'LZl8ïj{bZ/jL}¬'QpR@&MFwmB̔)t*Q,EE'el뛀E7Lؼ qD<@ 8%x0[gX*ΔeM`la7kA/m^ef%/hIaB\^|JZP[BܶHuI ]W`է(bNWf^^ {qYyUr!ZXX[T6 0^zm<ߛV)ɭ/|"d2Q@_2ɥL`+չ;4+Ꮊ Iq51Gfs;ChO8/W҃UI*eCat|d=u]JL+\\& ->z$frLpL&Ű2sˁ1 &g eǾl)V`~}LVI+u :h='o A#+Nt-.i/5:oSƠ\7b+.~sE;V8EK.#PyvdD TXpHD_w2 'bT\SoAjuGo'AciRϞO-*j}]2/dM8Y?}q#7oNrpBU@|NFl#z֠ōmd Y4_>8-PD#D tAE%ymr&n ?7e0*̖[K RXqZ8ŖMi(@5.:l~Z=T#1mu8#נr"}0kBa'clH? ,;:]Мm~3ݵD:z}!dGt. љg!L1kMf:y!_ViiHQMT]j5Ƒ G9Ֆ`NVt܄*#"8lt]Q>t$Ix"HsxRdhR&.䎶(s3@[;v(֨+ ף8-B̢?Ad|$ґff|^e"rwUٶ@Ǐ~}Q{Dn|Hvȶ\x*}fl=%tVn@bNx$\|Դr=+>!^$5Cld&vpWסаX$1|x8Xg]MPfSpJй!_$_]' ?(f6p0r(IWt1Z!ĞÆ" .&s2i8uL{pw2·B̸P^^؂հwWhC\ Ja8[t`Ê)"w DqGf qN0i@ΩH@|$⎨zm-ڬ~z2x L[yv>>gy&/b=GXo9ʆ̬pI3CHۓd2=yxwnf%=EC7~XKW]&%[}  ,kـv=, [%$jwȨUF=m\#ס6Ʀ_ ;շ~€+)3;vpzﳄԐ$6ۚ o9\{%Ny3<;sul&J[={Ũ Rfs9\ ׃z__)/_B瓵Ύy2C |aM|#K"zRр<ԗ50w@&?qou&:1HTz!^xf}꧌.;,4C; 3 T|d5{ R"^GǍvQ#F3H#=g":*`欦1F)6 vvc@69qe 欢! q0 x6lUT{o3B/q;n?KHOprb:l{`+4\1?o)N;5'[{$Ǯ$A2gc47 pz^S¯v[iryA;m#iWaqPVb6!9xdJ`Y镅&[h\'\̰Ut% *pPA(ژ%bm2Ûx]m2\(P44xmpQh.9e4s%rf. Mϐzi6J8x" .$͘1f̎Ŗ H&ɘ&+{nw* ߭ɅM<S+/U' |;/u'ôϕwePtT$hO!uY$cmrKo\Ӆ$Kq!/m{9 [ӎkepZ'<&}Yu ͏|4g*j7&r֢/' h}k xֆ-~ y#x@3φKL6l#y3#+S\}{Tɖғ7رn2+.{ 0/ 0> } ĩkex--"zxw鱬/d7bY_qA/)Bk0xk0K?"oExkENNP9w7 0"xH BY  >"s?p^ 0S !p"ȓ+5 @2~r1VxeJ C=BJRs rl 834Ҁ j E%I9\p5 !n>A!N>hRS2RK2hru ruC_XZ0O&ssTM\ihmz3758DlABqfUj~Fsck$ؒ`MMk-a($'i‚ naH9)ӑBvD"jGݰPA)<'Od\~yr:YQ5YM/W93l]= LxۼeJ ӘҊSK6gzeOϔ0YE~r'fytfv-D?4$P$%g8E7grz0vq<*>'x>Y7I=T܍}nyr|`ͫ(A ڶ E_Ovkľy08T'xR B\'Mnpdad"yNܜ-ҥ`KuL?x+[! $ $0> H>%8YڍPn9x[9e4 {m>(Q7"xeAhAyl&mn& S4)6=THѣh D ҃"?iɃ݁˹=|,wul ՝.7xȒBǫ1V&AkJ&CJ685X2m\Pt>q[1ѾóMS\%Fd5 Z3$*d)=FZDLԫ.ԗJZnRZXQ *eHMM!˶ex;ҸyBF&qMy ~~ N xuSOA ]QD(3) i;#۝lT-h1h&1z2zhBI/ԃiwO}{ۏj>~Vr^?4*(р Y`HUAH!XZ)"\zn}x}'iޙ:˵[=ԡ-pWpQD% %5$F[H<x.1tD;{8-bPJ:Z욡=L&f˱\$#;R3xҌY7fJhr饑lHp(#4h堂~^ܖe?RdAs_kaA4Kxfl){H? @-m(AdN`?@5 AdXOrٚK$l@ 5=MN&p8(/zF>ı@2u&zhkqxA\rzxi'{B *" Yl ;g#|Vcmp9P>z,r2-Y0 |>>pVE ⼷2>U%X%W=eƊ~e9^[BXXOEp<'+o4Ԟ\ 6_IMf4|ATa3Sd9'O| 佚Boo1xi' 'aj;X.x&P Y@l! 04 S:'5x';!M  ' `7jxE :l$'G?ɱo,N]POc9\&?KNf˥;9+fsrh MmX[Ԣ<$Ĭ"k.N2+ J-j6 'rKO;YRPs'[~i]D>6@hr2sQjdk> $&/*7\"KpxL]?턂 t3RӂSsR' (O>-8Kz+: Hfirqrr L`Kb',ŵYHcQQbB“85&/bLDX&bN0q4Cvj]biIKbIbhqbz*0$&o\ǿyb^!L%7,b*LQOLqZ李>W-uBaJJJK48>.΢ԒҢ-bwCv':7xۻi2 'l^/W P:5Uxۻi2 'l^/hG=#2af4W~I@6K@x-XY h ret; } 6 {xŐJAIC'PmtbT${.lf`f]D,BH#GMlSǍ?8Mӷ^_{_x5Gߌ2/pXcX۹fK9߇ Mqv !PV!"Y$CH&jmKxY!ȇmAhF KՠJו :m#tZlO+tf&vlkZ=T`I7C~W'+ ȣrOVzpY4JtOӝV.[(Ϟ&zyv?ex^Խiüɇ$'+ (*XsqgVƗ(%oUӿ,s!xSOQNHwW(1CCaw[Zvvn% Ax&ٓoƫ1WmJb||Wy÷=c}qUg@U۝u66{qVoufǢ{nu:`g~/ ѝ 9r=?, o{lޛ{{}G,_ELⲖN%Nf:rkvNɢE5#|"91gmCQi$R( ,YlT3z ̡H[W-RI֊SwBfX`$rN@5X.ղT@"ؗ'}\(ePۂkd*f*}sݭ\,)eVD cYleBeYy:1rV̬{I)dRFWAQ 41p77<! exPcYv2 F41D/m3J;IN&qƐ!TiWnˢdCΪjOjKBYoZU1޶.E`1꽆jl 8#Qs/Z 4@(5KBPqFxliO K q$j?Xn:Xm7:md&@P-B Տy9SyAZJ^ Hp sÜ@Top#l}cs_吾;_3]gut[$x^q)ӆʞ\ 6ag5 $x.̊Ci Ⓟϓa_EђlGP+Hx5ㄹ[2{8F(8畤V(z)h)䧥pqr*L~Ôʃhr 5[QjIiQr3O+盙^XZXZ^5 @nBsc{ckchP>73dSd+4RL! JI0@jt&/`d-2k8|F$L>"19ZtDrbNN~r/KQn_iRvmU۪E^UڤN&mݖNۤۗU?t&j39T%|?y=;;FMpd;ϏU-{O*O*]Єl1b~&d?%eYḘkdS u{yl&JAQzԃcpƉPeI30ȫ7)d,&IҠ&]e/U,$ݤ7*!lKgcmgZakXbj~Nj7ُsMSjTJAv&dݍF񛨦x! yz[zz`T9;mǗ-sMDjx6bu@4tΎ9BQzlne$!_/D!3|I4d4j8]zfκL$8zmMdrY625 h×ړ%b> FLv:Z^sjx GOf9h"=%1A?-Vǎ/dkZE)3MzJ/N\KL֊=&|B'}&VS秸ED$X 2} 38t*!k19 ]7:QoRBRTcCcg0d3qu~6,zᵺO 4Uzxeә*yB,5nϭ%Ȯ,~Fg;s}8Hӧ@10d!$9<~?L#NtqQTxI"#JH@ܑsRbE]0"]]wKq%z yq#(NU:M2|_ cx1~"q3߉a}VmzV . ϗ7pg76ֆz7oo '#$ $}KI|RAݚ-~[7Cۉ{|UFW~_&dWILB}Ӥ R@ϓ3@3!$ /HpSSbN5d)/M^:jQ> ֦UfQ LGKU[a!AF@"|HĚ;I8h=&ݲuSgxn.O  ڍ,b Tiׇd/ JB17 X8:A\6g6D]N`f\ι 5^ ; fJd&WB4(us{khdFClĴ~8 " N3Yޞmu,͚.{) Z9~;yQb8F9 A{#K"n 2XuA*8jo s0+Q/Zx5EO/MJc7O+s'UrʎZPsܝ8Y$i( ڌ0D-r:BC~s$A 4|.n_=Q-v_2Sӱ, Lxq |$6g]KbKxri <&Imf|)u 'W VioxrqD 3<^x-]EoorHash4$ F} [E=bx[i2 jR7o)Ox[w &wl>Ǽms# $Bx[iG &wl>ǜe9 ex[iG &wl>Ǽ((oGs\8& kO!4.>Wrr-/P \Oqsn8&IsnVg4 &86e܅s#/(4-&x *'Iqnr d&x[q {'?/,T0ecY xYko:|+/hbd jpk)( 2p%;CQRR(rxp8|8!y>lMƷ9*YIN/.L9i bq;L)6LHmJ"R<Uy}uI*zf;UUN Z64]xڒj& G=0mv=!B\=O_T%%PE͞Ot@+8NfBUL”`;fP2d<#J|ǪDV{ 8H$vҔ%˘ rG*:4TR1TDeSLi@)LSTL;'hAW#2Fj3${<'Ъg@K(8-q7oL(x$ 3zFu%о0D۱%^Sru@BTE@zQSz>zF6z6*T#Y`}|r3]Vςo;gyM(x.o`үz-nP9ؤM1wy\*w L斁<ʬ*m6saog K3hJ V۱rԈ.Og$-X/ήJnMcɔBq.=WR)ِщt]\=I8=, dǡ8z*0 V 876g. ä `I%kOjЍ\On.ɶQ !!tMm(i{FU#V5xIdirY.O֏il }CiUCh+bz{xV;^#62^6`; +r[-vwOD48wTJWrx竧en.}V5%_S ytz\CdZGWM XE}});zeJOh8D0@,Vv# .Ӈ;;]jh*0E5G7 f4_u 6Vѳ |Fpt[m08E4 a?7nKu3{hqe20ո .q]jcGç ]<01ם6q)k+Iy$I%L{;5`R](>93RJ<ucGyUN3APRxNirH}=S @3 .ԏ|'L/*,~Yې&Ǖ"z`C. y`f X|wq];Oۏ;}60b䛃>S Ţljr_ߖL+~oi u)_15ԧ <>><-_@&]XeCt_H!9WB;Jh_Oc,G'N> 58L,Řh#xjvJuI~A|RifNJJfQ~qQF_|:gV cj*|ppB#BI՚Pb7Y#{L"s۶tO>Ae,$J)`5au5ܱ(v-kH~Pw2UMu, pb̬ˇ6 oGnrf:t*z^l)x[dff" !nK@x[dfzfV#+c+[Ø6Iio_x{efGQ&Jb7yx{effF 7+ypc&*x{effF 'm̤YĨ n(xdffF 'J,cgxdzvYgel*xdzl˅$f@xd3zl˅W1nN E]x<: `o+ ,xnjC䋼›'J?cE.\Hx,:: OR euCq޳ .l:x[frw&}Px[f5rC ;sIqpɯ7sLdJ`s6Fu .xnhBIqA|j^rJbIdFW( (xk8c2d>2OE8/Cxkxo2d>2e›K 1]#wdxkxg2d>2_6b`qx]N0@J C`?@R1A%2,['>|S K)6vzt;^~-o''b>o]dAV{mo}w̕Bდa5j76:@MSCTWI ܒz) e9+ &W Gv,K &e2U #LaUd O_4~(|܍PBҎ~Oqpv} DFIǯ)!̋=x{g:dOl6OcBgxmx I k.xmrhZɜCxmrp!U9%: l1x;ct`!(lHx;c4`!_#&Xl^x;ctQoO_#*lxwHo[C)fTxC ClC\8FDE[ keyreg) if HAVE_GTK ndif !k&xʳg"X{3njKԦrxı~[gs<AF]zo+`*;VPBaɄl*yˡSId~b;}#B&YJ=3/X& (G% h]~@٧Ҭ7;sKi yub) ȇ֊P^[Le.bEVlguj<./\96mHf( YIG}F̋ H4v ~A3ݴ9z_ YUcwu&5H<~:m0D*H1KH=$!L.oH4)(A%O싗 <9^*SZg0QDe2.wJB) ) zSy-c?Ηd=,-43_Ed]Tv:/ތk\@5?N{ \d__<^ʰ &yl)B (d2p#PETt![Z';\DCT 32/ ^<&.?\_Ïck/%+3+ْHu tr.ލF7S$UIQ*iFltE;\7^.)UC, \;N.n=y͆$F@,wKAe\dF$d.x øM{̆^lvgbᥩweA$bx-CV.'x}\~i6gj-=pq iEȐ4H5;Z..谒 ri1gȧ(RzXXfƐ.-dٵ"$(c֓!?pzqJ OQιh|}]AC{) ةGB_1ff|>HCm3i$k I=`EټDz73$8= $rfșy8/wJ䅈&2B(- mv] Bh")r(TWW^%1MձW!\N,%HG)\EQʫ !޾oQ&Hrxw>UZFFff)L,ՓT.i1vIzv;]^]wHkζ qa@ }B6U$}ʌ>hMSFY<*+KcZ"7 ^" BSm/e 045dw;!3gxЮ''-9)9Q^"4'eT@,poSҲ6Ğw6/) 6aRF9!{y!9p46R9$EQս#:h;2 <ۏסW>А5&KPyeB ތ!Sq7Dh=5\#!e%"0Qh.P&a5ʏ\t96E+̞m{ Ȓ |x!Z?B`-c[%OosHf2nc(e"1]Z#1&97NK Ү čDUDcz Voؽ3._>䭦:YYjH熼 @۹xs9w%<+k MKƩRb}|Pl&v+q+F WeA\ $ ?6&/.agLAjç-`i$n+nv3oGye T!T$C6Y;}_R9 VņMigAI8 BHC=V+(N4a%v#SY`vɰ4;پ9bE56Q&H76˜]x({]ZE z 5.B[-f&lrrRYRA͇pn@Ϩz[Z5>Eh^ l~z7^OzvywqKVo[৭+t-8%&ųUCq^BPrHEeyFdK'w'mI7P>HW:"f&U1\g~G "h]19Tֶ6ZՍ1\^YXhԌY>" `Y&qaQt6Z,Vx(\Tklb"#$KetXc@@+?jp;ԕԸ64qL` ,)O CX%tE58zpl R+AHC="e75LRd_n/ɩM`I1dvC%>5a{&TayM"޼?{+{C_}Bsck&"̣fʉ 5 HJ%Aʡ;9˳+ : Z<ʏjJŹ@'($F;9'9OD=tmC㿤_Pɞ[T5XY6V\!VlM>{|H`hENk Vu\ \3twCp> k5BUj;B e/X D#\kddvO.T_V<}gC|UcM '<J\2p3k5'EN+֊NUu9ϷbYOwwkHmtűzZ]EJĭҁp d H} 6&m'*ꪻUY1vݱ/8F'xWmolY{Nbh^ly1wdiV%fO l!)[7@? $ggϐ٠KZX(-(ei:Oey"-ԔEE`HU zHEjRн_O*2PQFWJh-ܝh7L"ǧ~ 0~q3+6SqV%&Ft;kHIdq$e Z=؜n{Va,Vj̯ YkRM{YNYĮu E@f6NLRI퐿bo4v22:4ď>,T S {U )M䌤ve ^!6Vlv$٧ߺ03 `- & :65sUF*@Z(ӢyBD2DyrbnuIy`/Hг4["E,Ns*2Ȱ)ӐvFr `G+9xyU]Έ3ku|ȭS1a˃)e ]e\htz/.>T0n-Xc 4҆sIk<LnBR*33yJM63B1>$X.2۰MͫYPPYw`1xp;L >eR{8nW?v;H2i{<@|`3}ƆTo:ODЦJ ^ < ^WD_%؇dg9;&6L?>59MhB4 lkxL{ 5DI%YyגjqF;˲k̛أI#T'V"V4`lޙ[jϪn: 9Q @Hl:p6fmΪQtn8=Z8oy DX-а]j٧R}+zKnĭ^V1OV Wwo8*NOk(|X `l]Zڙpnh,e[).0_8u#\hL/CX&^.Qߍ|"]p!Պp χd n{' B5uX\b3 lmd&-}POp#&չɌ|7k\&< C-wL+>W&t€oKwZmѲwv۱OwTS^6[J"9\w᯾0Nf0Fel1xJخ/[<^'Y\TT>| %'E=>oH"0ҍ01{:Jh)~gbalrLЈ[%{g0il ғD|5?.,xtpw sV1:$'m(G@ZV tWeflUqoadꋊp'C!\ivyd߼#}:v¦`<ۤp8ףNq>f++v̊^H: ƔWP__- Aw>z;Bm[ؔ2 > {Nmo,=W/5xK̋wr VU(I-.QAή ^BniNIf|jE`@:Ȅ̼ҔTDQv 2 rvqtuRV@DשE/F$xmQn0<7_1 2Tq?$bVﵝPԋ5;{B˚p:zAxb4B dg;8F( ]I뒞҈I}|OT-h|;Y\K-rI9ȓCgԎw&ߎwzP3_[0V؞̞>8 U؛ߣɤN9b,ljט]bmg f'fgZk.cLc1(ݲKe>EN%IX6Cճa 9CȪM{:yވ#S*2u%1^?/xZkoHnHܮ7v,N䈲 Ȕ<S"EI aQGݺuzt^pn[nZZwUEyk:7m8?%EEVw9/no1,,W=Y/)B>~@NϏ*/8o_9fdžGGrJI9T_/W׶(Wd/W~=_E157ZM1^*_{D>- `OfwlH~L^/MԎ~ S_K)y{Z8;PiaM|I7&ߤMeG~ ']x*3kJ4 D8N,TRG,*i <xqJP0BTii=gDg>Uk*ʃ4,QTSM҄'Xz)M4D2/Dx,Tpm:R|嫌ďKܗLQ|SǁaDqĘfa 0L1 HBߣ\ RgH4@qjIYHC)QX2E4HԇF)zz!˘*)NDy"hq楙i^@ҀI"i^QƨTxJ|R"0Ni%L8t$q_T L^ k q'8^Ǟ ՙM&~QQ,`& ib5JOGũB>˼ODi#N5S0 e Tːy"LGRGK`)B +xp!d>K$GŁbXPPzR+,P a`a)/I|M ,h.$|h4) bULQy[q0Ddl\!Z@Š:×LLux+DIGYiMD ~ 8& B0L2'Z\+' }a.L"PK"MrXqU1& K*qB>d>]#y&&a)24^埑繟5Ϟ8:UCpW`ě7Fz, {)qvfY!Q Q_=&5^ם:OښYe_,;69>aZ3ǰ` pc }+LPfTK BFCyjzD?IJ+!O8_c}S&;q:6:Y^#-P8^?H(_6^|(po& h@GmM,'9KSLMa&x3|"Ů]li={~D~W=syx`๑Ƨmy98>sVi>7h . 3diXbDwSї3A@_$gi\dWTӽ}H-`W:3qݽέ6CI3On4ZqiUc'16c6&\i3-zvm~Zyef^LtR>rmno\7F޾%LېXW>.ox;6q2__˴B"}\YwxV3w5 % [W%/go.w UqM>evW&3_ЍnG`;?騙W7c;g;7lB+ZNf;(dk&HV}rHk c=dʯ[4Qs}k9{ Gc4mlb7+|PuHpP]F{hΘQ@"ϬM@a4if?6QX*hejжpW]p9w]p<ܥw; TJ}j7ow4Vh7^J)zK?ý!ސpQ)Xnu@lyWdéلOpnԐ[ k`Aw޾ i响4j *zCsZ<>O!e^=8qmC=>&^29ɧ!$֛({od̊fMV fȵE+u)SJ%"tC")''6BSg b4:gj&IIɪ=#Cx6bo5 OksU/.RPýpO/4q^U*n 6ݔ[ums) }\kS7A).7MS{p@YͫHNޝFl;HWxB]Sna}67vKctnX1C4fwyV?Zcaͱu熸/qZLn9qBǰX-z٬;Taϛw{oPBZa#%}UX[׮qCVMlKW37 ` ^83:iۺ\b\gΓ% *՚1m}N99 ڷvuZ ֯ryp m+n Nl`~ }iuOr Ѱg8/uk٩Ț*ֻ+A\m&C:J7uh'8ݠdg,f@Wc^6&&WQ5i\Nzh1uq[&{DOiS=mM9dNIKbF*{|,Wź6rS&x[05aBPf^BZ~QjzQ~i^Օ ~xXmoH bS*pHCTJE(v+E;D`mh^o_aNpRyٙyfлt$aLЋ2p1J!7-Q"2 @8,Fo-/`{'!bL0Bunb"%^,L`'Nρ}q OaGEqyna/Dq~%(aq1|f ,ЊFۻ0,@ǐm;4t)tgUk[Y;R7ߺnìr05h0c/o,Ѳ4K`H}0{?0#lsU4'x$#K/`plRiN^}5nB)V)8*R.)}=%pvs7Q]Q3&>ޤ..7\e {Ib ݙPk&DN\Km؞\W!٫6J^A[[- iAZdd9w7+h_dot$靪0AIdyS\Bl *\Q(< ےLaKg#9$_Gr__U$W~Z^4xt"I]vU1dFԶ 6R)EOKfA:-]D-UuU8RSWH1M`3uEiLpSw2]N{svHhHKt>v3&nl rcze,7 7DB2lTń%2f'?:5ާ{C)QZv+iRX߿܎wG7j@,s%+ =*vٿʳzmM"*(7T5Ǟ}e ~{ʙsvYהoX$)^ `ޛ ivEpEC*bWThX%€MLǬޓ44MZog$>$BԨSe,}7m d|i3~)qG^xK1 JRD9GY5˽vՅ*N^ߌ͓8#GSҏđ}4+Q|or J(pH?sHhB;`hHN(17ɞ&[BF܎F~iuњG WDwԷ:ȉ)oT=QUz.ĹtSRhgo_wl1^͌-RC ; S';Rv. %RۺfYzSj0jՋP}_Ȼ4+K 2d.vhkT`\N=tїS|>9AyDz2754_:s)'19߅[g׋U:Z:tidegk;}P(3Z.+ yɰĥ|Y QC5(D">&tu1wU&k Yһ{0W l+]ΑpُCHdwDj?J xZYo8~ׯh!:ާEsNnM`]E$Hr"}I) ~XzhirNJ6K]'3-]])tič~m1mŲדK .Ѣ8p?,&Dx~nbu}eQ,!fɬa<C`@H8.:<Ҟ4M.ʳ/TUF'- ^;!QNUi O!4 YJCP> ~G,(E^/jf!04Ė,0U/g88C"[—g9m6S4öSNŜʴMչEL].+~g*Yf,ʠqC^\BJEvhq5`7iaZc{<$_K}r]gkў\6+ϰ Rݶ%z&iQ^' \~g JĒnV$"wTV*:bR#' k20gY*bHqnD3" Q  n!.( -L4M(בܶ8u  ѓ]83qj̺,IShEiaiB1LSh@IԘO2IơN6IQE{o e?tBgIk;*{31zQlQmG;ŸW Ia$}­&T~vֆؘ͉mIVr.B-dI)]S ?"v*e/і%^\}j\/vUrĴ06-%| V~G)חzzT+AR^3o rO $/ .oJ'Oǟ[Pexё K☮'W v~ \akYC}kn&"uV:Z&vdzr!v;H:c;`u=Z0nF;l+FNb3/s%#oL2"Ly?\,f. 9%ԠN-"Vy^ZKdg5n\ dxN0=W PINԙi|wn+9=(dl^q0`>|x9j& W\cB>g1@)H% y*X V8u\/joA} ] 5]x,'0cJ&I1Kucu'!do,#ժ1}?PIM G,-ť>Zej9bPTڈA4Jg ۯ^~;uAފ6)zAp88_ 2Q!g4钸w,5 G 렲75k5(=x\&,"b coz'@nS)8=:FQY8Aw~?+&0͟P2E; y0v0Dd!^Gd!~ q\t,qn H#/Gw. IV> bXrVOXe<b4stn{~o::&[((lbl9c>[sW`z$Y8lr,QN)66t(T0..)劭#H'Xk*2S{y @@N7Va:De~w`;퐍|6tJ;Rw;a}: 8H ~6&fry`{`н_(`ktu>>xwtg,+z<̊j^|Z Dr>"JaQQ7 nJxLUs2B ĺ$ɧa +,* Wii4,sP /{8>8A_.~<|zh!9M;iŸϓvٟA[0KL:Ǫ;9$J.usw@=&ؗ$ A4-csݽ+~opV;D2e{$s8~LC~'l [hF%jñ3q'\[rMwR^ϑL$+XUy( آ_Ba۫z*iW60Wx>|'QvX* \/j!ݬ ";h1FG|(6$&Xq$嶪WЊrgLmfa\jiĵz&o.$"X,H<S]>I)*0 pN'#Pn`jjj . RFJL{i rv{yAS6γ\!ɞ$9H"yo&OagW~;vRŨMGB~j[qMcR#ytAIhqY$4]sx^WCl[_}(Wx.Mh v4MFG؍elYk *r Jj$'@\ yTN^RE&+2yI1 J6 (i㢗FAݻkw{Pwad.M!Qh ?/=F^ջHWn8a1CI=;Th)_؏ E;?^顷!dV6!ºhշ +{ndb3u՘Ce[a1֬t dar!<\+-܁bT{,3Q'Wru}a-- RxΆC|@3OVι9`m 32}P* bi1Y.HC$ (>r ;? mAvE]o:Ų:2ߋ,%6Z驥e&4M4Dze[Yg42;7ژ{^j(m!Z<^lҵ2#2\f9-wIƜi 7hxuOxgB/pO_"*|g 9r-MUF+1a `hBt"좷G;q 8Lp#MW!GYN!+@M#lpCh't|Տ-CSɀpē5u7\yhw%(u_[x-* DwE@ en-T"D0G`gh)o;i,?ܶ6r۪涵gvP&^t lp`k9L%=îlf:HFooWi,@%渓>YC[א/Ӎ9>B1KaSN6bv:UsOO'v/\ \6MSuTrBxkZyko'ښ77hGǓp/ !)~I ,f`3EYpo_^{8w/GDvePtqEo-[PP%cD~=).FnRWYWE7dޑ:4fIf_Z 4s+TnԢt46ҏj!a'=bL#\K[2*12Lͭ \H(7XmO WL)hɤ4S CSIrVAjf$UGAHdJ⽿XXt|J c%$Ӌ[B-.kőm=% tw%&x܎I;͠:?_\?ވR4,UI)vC X4NYjkջ")P*bYxNM"Yek5qS|깜PqHZր3+L/&EQnW/Bn%V_0W|>U***|OgX^銁WESbzM{?Cԥa !ٞυ91X<\7J;YJP<4OF79ڣoO'gb귌|la\`;yѯhX-ME!/Qy* Iᅛ(m;1y" 8g1"#H "ɚb>sOܴ}K!E3OGw*z EnNmf9V9wuljhZΣ D?9MDZVh VmyEk>"\R˞1-E*CجU1su":O( [_L[tbE dOڑٗ mDg}x i\{̇ ,d[\VfPslq,^u]#X#)WrKLRyz%8X'׻fϐ/^Di֣by2pRӡmm9HˋM)W_jh^wG}[K<%k8o[{R:젪4#p^#v?H"[QQYO~}@<)849)y)e17-+EVenAQԉ"R"/)(xLӠRg(K^jG^Ϊ&*Vy|){c&sbd}sҪhU 1o )O@G. ["p3'$^)! <;T`߾!^O7hp!j`cTtY(d;_ks?g#qZԧoPJ/bQ1Z,~m +PYph98vRh.K&u^߸Y:Kv h%l@/OV> /@adnLu-" ##Gz/$nncfnTl*竾PVhZP?$CZUIBfYDZe.`~&R2{vI[e'[fK)UR=bXmdc]hʷ3g۾t;.v'*J"ƲoS^Gi#clI_hKoT\H5GP72,S_N=d8G:Vd&0}ׯC T,ا,WQ Wx]ΔⷴƢM>Fc(zCFtQq1G*jB*l}N**P 矗Y[oY[OUr-8_~x{} ,'<`p wLO-.,P(9g*dm( uHFpcmd M̀]>/ H2 hC ) h 2K(HNϨ9Px7f i2bsAPBɻ@2_Fy?);1䥲I@ rSK*t 2sSuB}|6ʵyeyL{&zY8eŤ6 s;hgLaӺxWmo6l&YCp57XbZm2RT:oߑmI]&6y=wX- Zg!)`@)< j bӢJ,R t8Td2wsH "B:ZRA N6Kiå29ˋWexgשb6;[1Q?/u~s!a>ȂB4U%QA!1G}5#B4*=[6k dE1s֔҄,#:{3C-VX>VsQiE-Ɵ 0gX6@,#!S\+$ <8jɅcI2B 4T;N'iF{m}0-oK/N ud'S{&k ?ƝZNcu~ǛhLj})[y$LxHL V*QWAUi5!5xȒ]pEbwQ';4]8F+; 6zàySwxFV`FGՍ)h軿+0߿un`i볜a5s*ly*VM76i^[x0 `i: l `~7v1x0.hpXmFݳILNUv 5;(TRߙ.L }pnb&0',Qӹޥp;v;&xx K!R&Q_NlS8N؅2˿mN۠y5L:kѹsޝbT h23mx$%_ ~\b' 'n *PcMѻ;M>8FY#zv iQ9]5e2%WߖYysDW'џW'i?+9'mMhҁWggDͥ0,r]Us5.iDbN4ԁ].g9 pm @9)oRF/dqI IuݞF#6x])@[9;Y냤89j0>M;g8kԦF$U>C>|F] ? OmS뢙Ђ6E % "8o`Մ|{(F0nRWCwYgk{eܺ%MUB. M<ń 0~"%{۪1xuQj@>U%6u1ղAb8p=t \K f>vuVdfE+:>)VS%Dxt'EEmnZ6g8y`Urp1+U_U`5Xg m/n~EqJ:Vv is(qB"1Z!-xWW DsR_DGxa^C촚qW@7xb̋Sn,Ƃ陦0GUt MjeK7il񿌢G'.! S@Tz)/Z1PzxkOI+ f vV:DrI&Z h<Ӷ3y$x߯52aCQdwWu׻{;M؁S?".1 E a a`'aD$d=‡(HB I c۹(Ƒ Gb,$>"ٙO.^N}m~šS6ۃIG#c: /!C2b+QH=%)b 1E[31}5km[ ;gsٔG8?€ĉ24Ev˜πEFy`'1OcMM<2'~|%c0D1P?a}te]38_:M4Z!LIlMOB;Ȑ+C׳.~к;{lC%^NOϏw'Vo0]~Ƞ-WeH6 /aqֱ4ݷR 6(.z 0<|)i Em!@qrz9U `yF;FKĠSy]":Qd;+@Ԁ8tB5t zy}?,**~vP@8,q!S0nC<#l}o%Z+{b1mi@~儢05]YB&v&`L^w02/0'$ Кn%gkkF, ~:Ix?tlb ʓ5n-4`$avU"ÏHT˅ 5c1R)U_ӄ}p2ƯdyΏ.}g7Ya*lKj TQ`+l4wRzDH q Y=EXߪ!R a>KZ(,=(K1u8`w NC21)r*b >p:ynb?le"g+f0~IHd̪<\ /0Wu ,^YN<9iǝ` r:>;&UE fҟxI&Nt/^(T)[6j9N7x fL+&rHU]YeDWr0xI4ÈAMU^'XAY͐RϋsTjNj*g{F{| FU%f~ آ&㐩SEP"u!J{YrY'}V#I~Q03{<ϩ4^ Ok|7M$dKOB>YbwkF_AYţ)u9bX<5ZEl^\㐛8u/q#=r3Ѣw{rS9Zd!:ODoWs]Zf0Kk4ik3 zEΩ ZAC:Psx@)7aF-+ ' M b IMnRHW_yP.p_+xWmS8lv49aHicˉc{$o%َ\Δ^gWJiÇ\zrE')rIKS'+AR85bɊ&_arq cB/I71=ɒ؋t%XL@B&O_mb?Z>Dlv*cɮx^QcVɴHa&҈MJq,'/UbEBb> C~r;urهn+ecva2OդȢ`XS|HXM,(J~oR{K¿ng9WhnǶ*˒ 6Lgt; ;8{A&f|x O0ԗe[$N/@3/>voF*Ovm@iFíX"Q\f*#:Vzh1PUt,!ChJrnCQnƚq6+Yi ,jjDZYh&^8 BnuU(,]r\G*7,2_?uumǷ^<ME+LkeԒvk /c$4Fe' 9]i\4ȺrDKV›St tyEZ #ږRhM! [д: YDR.(7 OšE6`nq/LA&0R3{e'8`\)"%S #MNl*[R$ˮYUaκh3fʧjV[7~L„9mD : E-/2*TqhĎZ@>!m27z`Aa詳Az/;CN+r:fb ]8_kpiyPyv3YDCw~Znz j,?#!BHFZf͚SSuGEC_B[BL <ֈQu`?ڡb[/*U5gE+&c<'h23[|$-]_9+kҬhyI FSUJW-&Ìy! !qkx RA֜IJp)haJ#h*awox:Hr(k4=XN?c}56"du5&[3j94!Jűps/?K=N V61eZfG}cAdˑ47Vβ,=\{jiG/lxxks9+:+J6T` qlvjccnIhxYVw_juo7 |DBR&y%d`2x g//PS& '1$JNN0`;miv™-DX\%\$'3r4~I a{6Uֆ1)B+`c7-}Gr[M]X23T^IҰf"Iq.qd*ϙOֱ2U$2_yc/R %((cLk~tpwȳ?0b53FZrd35Rt@)gOpFb5j2CgpP*!-W qb{01 gE b4 4c9DŽapGHs[%9O?7(`); .]e{C"l?i<+zЍh0&&y0-8s_jfdX w@g+&;Ȥ)L^MM,NqV8IIs')*{('zR9q(c2 Ӑ(ɗ%WV(;%H Ks|n2,pQӰfGvKCm)&1,uf{M%8H/8׹UѼ|?74m;~kꒌm?t=*t [A$?)OW4]ó_\>?֛(H^& y>?GDRtd^փK:Iiƕ/._h7:j[vYfgir쮋m);}00ڙ:?X|lԣ~UbV1~nwِCkTJQ y|W0e m+_ZkXRtMm!vzt=|7''fîZz2-]p@]ّ rкDLFŒrS"| ^ ]~5^xtei4Ԇtg鿴i-j{Zm7ꢽ4*PR Ut('Y0]xzYqEH7 [X͐5ьOS_5QWE wioSy{6#'tU Ks-Eh辔vwv2%.t'9ɮ[vrO骻]P}]G@!i (NyQ[.EL.N̡H:eI!VwHnd+P/m(_ۦ}MXHԉ/j ?UueDiAT14'^T:%I/guqM/ŀ><7.*݀. zLCT(9Y>`ct 7l+eN.JuUI'?HUݯjL Wبbc}Ы~2VO:=YfHgfg ~0XøƸ[ڿ1gSOS[ W2נU5jZJ W0zy,*ߺ 7$}m:gΈRb\QS΢0z'B@UL0⽙dȗ æ3OZԬQC : Κ-Ty TȄGyw =9?Q#ie!VO鶛~aj%m=}H`[:~LJ}y,@郳F}-93v1؎dʆO tm~ 3KP d4XiAJ6<&"^%vhb# ,+-uΥ=_I}Y,Z6bꉻ[r̈́ ռm©yۈZ}5Sm=t3fɲh1# xYm6l Ƈ뵝4f[6Ȧdy+K:R~ I&ibp^ ʼnV+Yi-Js#N;]VR\^ֺlD()ëMR-MnݑU,^ՃVm-~*pE֪,\l*1y_T,f[l8*VyIYUMKZZGK5ݎ\R*/7645\0jS@=yYlIN Zإ$Ŧ^ g'GYH u YE[JM\OaNŇkM-껒vpD<*tU.}0zBZKAG(]]h{p:E<|9 f9Z5ĕbޜMhY78 j qu K -J 'UA6a{t2j-׉+18X> N]` I  ysvd-T̿D OOE`jZB4ϭ9eTdTJZ[eSd@mV7J~P; 8si)5:3ѦB.\׬#2t[,kP+3}G^mӚ}g>x=w* k {C%{Z*&jC>R1O$ <0 *qL/(7(3~h-cK%R@ko-]DB. v.Ͽ^_[.7o.u46iNU.{*3GQ"aqr#io$?'ͲHڧĢWWb~!gh@r[ $CkZO(&3_?oN!Pp@)6PwcRh+?o _| ؓikj2)1OH"˴d}QoǗy;nIts 8ȃ!, ЫYN\@(pzi)̦1Va9Fo7$}_jGzћN{rn F"/J]`<ࡱ;qzU.M;ݵ;YNuCxomXKٹʖe5r :NSٓ؃T$lwf\)? ^C~ŜP>*;Ã)AdPb,,DoSL ,I|Sm5vE&UV)0d(!5x8{5{)3(.qr&j$nrˉYh ?(TLZv wHۡђuKm"(C4.VX 2*Jޥx}=\ wI@>bQc͵HR5o++18agqдʊCf,1圴 l:Pf"Lj-w>kSҔ}.#$/\>n`~E2%Nru~4\֍lE v0BBDӱW#}HE2Ń,گ4壃i*}U__gwGذVL 3͒\ ''W`McNq@1d%{SmvذqND@?:vmVZׁԌ?!Nc! rp%j&EpT? LLo"q(8,P}{BY1\y_nB@kXÚPF;H]|5Z8`mepw I/> ' \hdaG:/"9?j8o{ť&>y C֯^Bz{i̵rW5@EIĤn&8=_eFoh})]ć'K 6@_{t̎*'M_L~Qozyc; Q% ǗնӍ: z "Շ޾?3J <DG)Zr7ɻ]s"OV)g\!A;rԣ- Ж51Y]: Rط?Ʒ= 3J;rBP7Ͷl*d}Jz˔ٛZd|B0UtHMyrEcĥ/:=}~SN`$up)*|6FoHwvgͿHͶ <Bl*l44"{ۧEpЍqh  qڟ%ӔgAKݳHB{/z2nWرgO|xzwS[&y~[R,`#-SE"6"b?U6`_V>]@\BFI7`2~E<>ieֹûx~YEЂF>.2HZ ,+2 D٤EOBdDK),dQp9vNXsqrcN1\rX&@}IڭS.;łփYZG܃~+G1__s=s9qhhS 2Y!I?!n!7swosL IUJ^8LۜȒf:]~H" 5d ` ]0/["e~Ry E)l{܉Z"+0`lX}W)]-SdsfoC LIlIl\d(`C %~F~eYd6egI?%yBˇ3*Lʉ3.;{ =[1!}]fiQX<ӿyq>-GH.OF4n(]&R=< aG6NVW!h?s5W}+̾PD3t̽Y(]=(?Qϐq~o+voj\x]>.Z=$9H<.<܏Rji[V>~[V)XVhWð4NC!\Z#8cN5*es )Cۡ#y[L-lnYu].7C(9$P!>puI"PiH0uJxS n=}w&ᘛMH;1kGMC<*6qD-@* ɗ7[+rxȭ cy1PB V# ~U{ʳBObQ(`&`Z3L-z.'ѺڝiY .!SЇ)k_ _i0NDhXX `lnCJ91q5{Zv6!wGuQTnj&fѮ^eC ,Pi7p2f"FG'fF0'W4!|&:Dn=J="kh574 ]=a lm - 2mNQKaazсnTt+u?:_ T~T=(Һ~NH 7GD-E t+{խ GX(͡.y` J -0N}u D""ak7㥅Y뀆y"l*uA7Ea]j<읍hw`AC(P[f^*өkUb)$ʜ[[/JQ뷽P[w6h֦]V/&b? ڻ]sm{ J?B4FXEYj} [~0:` qo0]F3(^HslEZmE:aOe脓!Ӹ& qNũ 2Ќ0Q?0n0J]@3ŘFŘs5?87C!<xCǁMKZ)t]}X\kN⦜ ᜊcg F J4j ݁VnU Ag6i; + ֥⏅+)O>cُJ'Q ኪ-~c/fn)("Paى{OYQFGMF׍M^Cq {@}o?!ݩkF1hS`-+ nsamQ>px}!̼Ҽ[Í+f !+x}ks7gW ڲIӲHyHhubK:"Z$;E#q33xg3M*4FPܪzyNQhG4^,8EKt=UxJWԘd!AeyhƟXa.qt5Mh1U$SԌ;=m^%gI'd]L_ߢ)W[ct5t2 $ T$R ף$cwAɔ8'$?nMFt(XuHԋ.Km4Z Cy |qGI |*Dw-Zjv3u"øJbJPJhRмeMG&ч0Y}ɻÏhzE[:z 悏9.0EhMGb <Loa.p (Z貁t`U|2 ty`+5 tlPxtYk-^ƖB%9YNtZ^CaS8}1`@RS\R/osTY#C9qj]A~ږ$т}.NCSgg[x4U!N2z3F &@E$klA=.4'  DFHG}(Pt\iB:j5)П"~PYI"9ҙ@#qK]Nǽn *I@oml>]YO9$ *Y7Y4j0Œb )8^Tq2ʗ)|QoHb7NMHKdIPb(_;Ddd4d4옃4ͯFM4F_5roPχ~?4E{}?Wv_H(*p!:#.$gwr!1y!B_BBXiff!x!uk%>G8ωr !t{ 6xyjk'-Za6t-<[\]&|eCp>-(]4"d*/ ʺKFNFC,Hc%YLb.ȭm@7_ u`ՖH9x:h WӤbW9&epq/G 7lPbjO1p/\t'C2NBtܨzoi3CrCkܙ3M9Onl^vxqG7#lo=Ԡk'؊Dj6Aף9 ?ʓ0oV hh0찒@#)·b0ӟQ'Y}7$ P]8bG?r嫘*3L0T.Q釫]OGh/:t+(8z? ?g''cz,R'Gcl?dI}8ӑs)g\ 1Dp&%A.nIM0Q4ozBYg`v/w>Ҵb`Fq{ôJp]fhjU'I_"^./ `p?C @Ch;j_-v j-?( l,Q" i'@{VkaJnqNkWRpmVԑ19ߗ3zʁh5*J0b<"S"3:JM]@0!.q~^ğQBJë0lb>kdB94 Y'5ސ.. M؎Y%ͷU.|k]-`" På큷d0zG_W!?:M F"7.S% ћ:,rѮBjc+TM0zg0ɫwߡ5\.j3k&.G,ķBu'gI-e #1hQ}=[PC:r/od0G/`]MѱI5/Et܅w1ɵs0;enjn1GT'&Β!@n6[OKu~֨#ś:L=Ps.6+?̺FI)aD.ڳ3*:%YP\ۤ)9(\Ѕ# ftvrzs16h KD ^FWa\/y 3JΏ^K.rf!L =ZOU:f_2ԯYY| 6:/i&}6%3 QyCzBj0~c]y{)+MqW!W8:~-foגz@o"BKno.TaIXLґFv~*&u̐\5|b]swA!~-NoG]d'5HD#XRrMeOR[hv~DMᩝ[0I!D^'ګ^p̺A겶J"-:715Cك![|ZCU5@rYķڔ*`)T&ߦ,ŌgUv.: j j󶰁|cÄ3'o+[-Ь[+JFJoxǫ4(MT^z.tk kW?~\@JwJBǮ®|+fKF#r+F8f똷%u_lntFW%v7q61ҋ ӟP* 㦣J#wzPţ.-C:yXItJ ߾s C1$>ӵ dLn'a_i% "i+S s@m!9|{Yq :7/ӿlG)-@3䖢2m *g\;hËo,\*7eٕB-H ѺԺ-gu?ٺ8-f3Ld" 1n4G/40h**q; >pЏT(Wo4gE@K%/Ml~pGW9_(4(Mv#.Pa38ȁـ M&ux M6l*6m:$$;.8adf83;@-]$p!aWd0Ee/N"D*mJRKt3VV,ce=ʻt0!A ]) _ +zE|) iVlBFx݁q:Ҩ.o|v+ 5iKٰ_\y0m1^cq3@gaHR*-PqęFFȩ;Rƶs:_LH |S!"'tER[) 'ܐiXgJ3g{C\tgªGsZ{6wyw959vd[L(}aD)uOem4~dȅkŭD9lרŠusC~yyOQ% ,Q>F Hi_tx| .hX' $÷8MFKWPwQotB[E4T# <ԊOmQzߩ|. 1Ex$F#3&՛޽U­RJ7e =i_eKWG7\2z mQ9.-G=mfj`3g}?P.[ec1@z^da[Zj7"ykŪq[a/&q(3os*Ką "F%PcvjĦQ\>v\=VB#OAH][ _p[4TX;ӣP^z4Ms_ XSEՔQB{uk_"X0 .4Q)/&HX lJ皆Zu(T.BAMm,7ƎAr(񨹁2*Z7&;% A62َHY^dҋ4@Z> A#⼎ʛ~Yp P"@S8z+e TEuhP _GPlL/cC a0˜U5$1A_~҂^f~h4$箲gf45_ߨ)B&Žs]."AB.e_ DQAgg 07S5A؏KzNxܖ9G/)2k.pajc_xlVE' i9 m0%TZSOe\x)L{~ 3~{CĵqCV5é_Ϧ{SvX卧;'~_lOG/@7(a79}S4wIu+5mk?g+| iaƖe(B\B]ȿ[H]#&§c>GP1i/ >|I=+|֑wk~$|u ; |2wCX6ux=^޺ݹr/|c$`7.8I2^ \s`/-}11a" !2M<=!"ny֮":ES:a]]a̜=?x[|uw.̛[u =:USEy:7otSq,p5Yo,sXzgC?Tp<2dzv |Ŗy1蘼u=R|K̇YyΆWrr_*Cw5W*f*n4f_Pv|Gڦ-ef U '#z?H1Dv'3MڕxH] O+_!:Ouh~mc@s#ٺ O%~28P̿X@3ߔ[n cBly8h{ni@Q!,O -`,~e+ڬׄ=;;~uz\χ~1616T8Y*ZJMAy [V Gm;!If.13$)&;\'nA#%oDr ir ?qC+l=[=h>,EU_2waќ?4}YF}]aZ[ ґZzH3Fڡ06"|css_έ8W@4{sycw=-hX@`ӏBpTw1XKN{~\2Ӷ<]$^㟹y60bӴQ󜖹u5+ۭkE[u1E=Lۮqy]Tߡ|.F|o7CۡkHUukzp23lfE,Q/Zۄw\gYbDA/";ov9aaz#eɏ_u1]. k.f7bv6?*ٹ[L'F~몯spJЀ6{~EEʥʩs3 7^+=vPZ;{.(ehv\Vɕrs˄ ͘3KiP67DrgV4d2 )`'^0;BA@wx'TE 7!fN9PUH~:4P쪄τ{}B DR]]^.{7RkiȀq5G/ɖr#Nv=n u}zrOI^}m&M>6&Pͯ4]@lf4V!b/ kG & ^WΏ>V{F%ދ&:T/0Qe1uwjw.*w.5%<ՈU\eUFƒ|dVwGàӓdeTN-X:fpt{h]nOWbJ(juރ4Ƭ٤L5aK}=)`[<6;ӏBvWXK 3#zFSj*ީ9F_X _OK`'A$wMIƝhT4Ut q naX7N;A^p6-]@+rs[Ǭty8zʞ3KhtpTF )Qi|+Z &3bH Msz3-Y>Q勁LkM;8Ľd7αw}4w淑2bNRB8ߦ^>mkeB+c*3Y|_8Z8`>n E.{q"YtTOAHaaX("^n"p#5r8.:\ d.*5yp7,Bl vFa-E‡Z(dH~uelut}X'Zh7 8ٴHneHi q7ݤP:0'7D&Kb,ăwFαXfu WĞi,tU:+kVoyeZ Y)ߑQ5y4(MUΝ wA?zI@xnL])/ZaHQpHtRg雄Ƨn7g#!m(K&cʿzIPF};Ba7ЊKu'`g2?v}΅d$b=J/l0Q&xPKfjzG;\ε_NۖV?lF.p~蘍վ9 ;S7~Zى}>$9FVc迮d99o}Fx~ؕ4XU؂zfoNrk'G$wг=J9܍{I/g8JNū+v8YwU^a}#-p@CQIfޗj埆Fd)upBQ! -zk}_T,?I躑k,LU"&kh{2;PF%Jyve $?ϕ&3n`n $ {DajjXs>:YäJ,_*q탸)w@o7:z[[.c$b@Z ?v3Ԃ`Wca۠As9tdQ] f'?U*g'ԭ~2 ^Dw gã 'ud[d(D$;f&>=j|>LO>Aغ]̘`HmbRhH-+gqCwVV&04dK`K45%3ϧ0)'`6ќD\-Br,?D/*@Bmѽ6Ik7a2$9=;9y-]327O&MzF U,sr'pj;GI+!HUfFO[Pe+#ŽnvgޑZ̼RTd"MS3(+e#oX[W9)|K[/H2ӂoܬDZ}fY qF`j'`)q[4ԙKi άS~#* HRXk~F&^m8kN XbB54ɛ4tũ 4V˟5͝2j=XQRJ7ms䯹Iὓ2cE rBA{]^\yxm;fP|+ofl)K͘=jz٨-2(L.Ab0x'2+,#_xУԝAY2F\b^WsI%xtS xEW֭A_eɱ#: qz!Z8⇞e˛^WœUJ"296k:ae:q&LwMǂՅ]P%Hk%ǽ]iܖ,7%k/jgӋڹE5IS}Q؋)ʋD.*e&`8m17>11b~Wuh.(F3qgk=z>Ȓm=rElXkbÞU{tR ҇5^"[7/GqfgsPnI"|I9}UDbG-Y Ώ3V*ͭPGP ჯF_B]ReOqx |0M 3LXPoe}ά'*AtTØ(x IΟ io2͜g.U%DZח"+ؠ aȈeDgٰ6Jj#!$Y4l1jfMt]ZEJ+U,S!h x)1fb$>K*d?SyPJCV:*4`7|월Ś חH]mF6G';gtp}Y@ArJ(F YaүƉ#t%㨈o׌_ZU&.#Qugfz,q6+ɪMY(*wѮQ }GQO -rB0(䟒VNgG&QMct&h4a͢{Z_ R[x3ќYCHDgET%@0aT"D @JSxNVԠ8aư7h֓=kz#n˪rԙH {GoaIzg 8 F+^? zEh >ae+Z,?G Y~ϋK'I?*vg W}N/)Co7"خ(owě;MFz3ل33O ,qˍ/4׊c-{8ȃ?>؞t9|u}㶎PR]@;x*^ipIFWøaŇ!pS6>{Ӈܶ~^@X;Fi'\ĝ;VSBJoU˃7ۙۀ:]{\?rL"_”{򖈖P ݌fkk vt@O*vL'W?KoY 5ݮk N%G)kBK>O, CbBZ})Xˢ≉ {' *2=(P@!qL4U|GES( OڞYK` )X5 fu'JUkG!W^gʺȑtF5BLSU=q*ݤ)ц0P}sߵG0r)\qQCaz.9>JZLz=%7$scѭ̎%$WD/${ CCH\#Ju5^mS1_miKU\SSV*`,3 _c=\fƄR}'s [uzP! uhC"T2nOTp'/"et8'ߝ%>qsE5xb Tɕ!3Y-9Aw`ѕfɌ1EpS& ɎGYԸq'풑5X~[(tVlfA̓?e?e%>,~"QΈ 1Y=3f^w[* 038+Zc*wV\Nʧף9s;i<".|(U& )pPfQD.|h ]O=|i8Wn4v8c>m75d:E?NK3ɬҟGp&Ip]sk+从7A M,7>hK0Y/5ZƱ2+GE{EU gZVFfIׂyglEVeKb͏DҩsCdf"I^r\Ua$ rj+D3U[xT2J(U[9p;Z~0;Bc+`G5DP̑m1*:UN'k%ܤT}w7QAȢ"/t8N_;: ~D- o8X~2[ǂo6#6,Ӝ}oQ,3cR'́|P&wPTp *ƏP^Ib;l1>8 >bxYFh*Fs;РmLALe ;fʈ&ݪS6kcDߚcBgQ,$; B"ca9DLO'7A .^q;e:r29gn_l)dedۭLɶ{~,\i3czscrp4y",#o=s#쳁FIyi?y@R P0 {ޓy 0bh$CK ĺK?)gO6 1ti8g+Ö@ knbU:!] h<19FnqR̛hRFW~7)bMuMuk<㚝 cI"E^ª&mWvi}550>kEM@BRJ\53jl3ʌ s춗a׬v:n77z^.(e8@"i)~,$fswly;~@qL.H0cr$g Rdjֵ4[^i5R0: ՠ<5\+'^=l*1D5Q$#Q2f.aLBX]!Ճ@^80)P)=7['&u I$ײډ9F7!!ILCKF>6l|Lv.7ByCehQꭒr=;)p_g7'R׻>QYc nQ :^y"GQNj#|Q~q_f}(*8)wA8 5nwovU&rnP"].B|.}ڀݶ-e7Ԧ뉤Nkb;*""MW!IJ92xKdjg:8q=4=`%y2O 3'o^k'w.D{2+MjT܆켦jBqG!ci.G]yњeЋz$ݙ_V(2 ۿhIԥkT ƔBk=9>[dyZ_wkbc*1(~vQTg};xr&WLF Fr =xex۱ Z ײo'(ũY\R1'AQ^(3Qmg21yK"0w4璋?`nrU8kr_ 0~ri 3#Hf<љV7ffV P|臮8ȅ.%B]5Y|(20o^ rgâ@G/搛,P&yAz^^x; Z%Z۵m |xXmoFU";h:J]h dld/ܝ;5$*ٝy}@!pS#e~ܜTZD*%6Ibiz=Tt b4ܐ/ [;ROU9,݄r.ٸ([y7/ɠiB:FWZ-H6tZ .Ƞ#A4:S&=;p~P!^3Kj|4q~ )-m'2p?;)[Oe$~΀oZCt.6O'C`l~|nAv;t<,7ܲ%MQt^o !Ѥe+$rܝ_!^,0$pm +7]݄Un_c86ЛWG#0m$HGubc1$hlŸƣ >aPB]ڍjE@΀j}˶ &QC薔%=ஔbB܈н]& a9 qo1Df~,SFAQ^f*.`#ġ !C<,g=a}rfVM@r^%Ԁvn{ǛZ-g:BˣU[ Β A`Ut]X1t;ߌߩ309 +=X^vz Ȍ&8Yy@Ld"WXH9*;;nfZd_MZ'Xt~0 7bϸw8?OAD1$CF6n)P\mC^NZu-Xݙ{R. vCYoDJ\2u]TYL ZVI MP)eK0kbʚx# pJeݡf+uw%.8p7~?}Nj^ i|_{M Mo (*眵7 iwՖ9* -5J&4N&dEewHSkƎ$/U5*@z=i/z0}~_Z*u`q#햷"<&LSe)͂R犮sʜzziGXKZ=$rM| H>UY϶eW3sP2{?hvفd&9e~;p&i۹m.E2[m Vr.d6&|KNBA0+_kpr4- n=E7JaeO6ܦQ/ ]~ֻ]{ō69h |x!FiQ % okrtI3mJ7F,W7P`PfC㿾0sbW+8oUKD$Np8p*D".Ҍl)gWighWA}E+4 ܊1^g.T* k(;hUpmJ>FMV7yZiTJ/:Nj1X-C 39v։Dx{Vk-̼Ҽ[Ck}}BJjRi?"}Ax[s6l[إkƊsr$_K2$v \:sb~Xvpx,Ln]$8Z8@4k#4 RDc0> h>1Qz!y Σ&f!Ni^ dI3{sN~X ^$&󗹶8g6aDM黮k/MMC-0Mj{|w @,gᤛ_M>IVho#iWn.wݣAupi/qx.eC1d$YƉ+).zݻsٿt{ dsf|ػ݌+c3)zOnf㣓G-Q| 뉣%PF񦑤FxQȘst7 zy t R_?;8h5"iG#W}&[wt;3m\A(>(Yl;$䂅toďn-zH莃{_0^88RH;^I`Ẏ5Og;KN㋴> |h"#ς\aߢ;o7W=H-Ҿ3)| 2Hmɱr\E 6YϬ&eÒ-3Nw %Ґ"B (͔|ucgN+?Ʊ~FstX's+kh~0%9,N8YO,vN'Y9vɘl彙Am565p//~:tg Q$=Z-:>= %'D礜P&*Z"2jf,Iab6*Ozi<뫬ˀv55׆%r̀>R{뷚C6\v胲 =1Cƨ\Ȧ;@5\C4 ,W mо9/A2pgp=T֋((S6)&p0sȱxˌ539RcL|8ڐg3t}Y2UqeIv[4; 8j+m> ,&z*"|/79IV CU.f|i"( ћ1E:N4B:gfPO+IaχY%|E &eXA -`4rC_/Wd>ƱN~VIEʷΨ 95&=P"T~&ۀ>4 OtĜEgX IP})ȟbVA) F;5YC!3]"Ѝte!&!x&N_E 8>H |ve撅hq4ޗ)*pbizd\Pcr{Jx,|[wT b_*]=#=<͉5HNi=7<6F`nV$FP8(iWP-M\yB]ott^2 87GDS􂤀r[iGYKaێ wQDT`vT'$*QR'NQڏy^\E);Q4h&>|>=z2,GD-1͸ 9C E?LԻ)čdSR` _ND?8Hc".ӄGIH+tCXT(UDr,BXn2CqR"J!bpERO%R]C@S&#֡[F%"\.0 "<^&s$B j2=ʻ,Πԭ#u=]A)MUdk$˵}NfWԇ|KMBE^ƊC_ A^"lEK9@"BqRȴK5i!GXqbD@5 9ZML(@ 'ݼ9ж < HaNDQ`¨htS躞<(ǀ\cAnEMr-a`TzZG{ ۠4uW O4Yc#<,,^"ggȯB'Ӫb !Xe**0+@yAܻrJ( ʦ4S@ wzĜo<"LUz%ggRLxPՐmVP/Ic'`1h(?S*(JkKo g57s^6}5G[ûk3àjԤH81f'$ŏLXaQ8cRC)XטkKssE+;Jna>Yo6w9WK:تy8Az&q_w}xsqv,7o/nuyT`)TIVKg޺$z;_śzXM&aQ! &w=І"m:S1Ƽ+w/ie"tE줛t u7',^,E9Yv0t ~0} :y}?Rn~Mn bAQJ _kڈGu \ @p ]/R%g;uR6Q/Z ;3 ͱzs$yVKBd[o]~c Ѝg(+J>p<3&wӈbJ.-!2Z*ʩ xH#4ιY+*M蹫 lJ +_v~߉\t3'MEmF |pyTDr:AGyAi~[c|Uԫ#a49YK$WKC۴&YGq[)h2ߩ20tC+8*=ӫpV4[ 8W,cO#44<'2W]ГDRĩ/VrrW]3m Ej(Kk!0t0Ǖ= |y x i-WD]w1{C;ٳ:'1L&8?FB/ * }oΡ$&sMrtUP)2FYyy wuBL>D+~|pBNb swkv/x=MʧՑ= P{'d*93~w3;?Dx+T+!˖,9'Zb=$}Fz5B J+}DT 7qJG`P"B nlE˪5Kan' hjdBM )EP+Eɋ$yUʅDbSn}S{yk#QX㋅h9fdၓ=}n%K8eϘL$:V̥tVƅp;|+*w2U(}V4k!>.1j{f% zJ]j8SHCkZmȿ4=XAfwf-{-lӏΐZpP̺_:}n27l!%SOPD5C͛O:F_1h`Ϲ^^oY)勆j`Zc~)n UblF ^56e:NŒcszH,L]E]c;K OT`]Jv0/F/du~҅&+VA*ϿQeYwUx7fGgv'U@+-h!V)ܼ}θ7VZoՖkMJSFټ|¢ ?Zf Lsẃ-<Qp&n`XPSJB'li#عDp_q0|O9؈قx`ws!xt!r&uC)/8Z\]xXwn/d>&mװx_x琈̼ Mk.NKfzjq'P8>BCm>v-F/m6p|eLIM+-P۬4`nM^&ǰKnV2@r'aVXɚ@qN޼J bdCYiBD Vgseɶj) &r]$T`"39IȚ" >(oV,l@PN]@rXq*|Xx=kw9_ ΜCbBn c@v~~va;gfbKRT*JrcsFaɈd&9yHNY2/ntL6Oy2nF>#t1&OivA6p A6"yFy2'9x%y1_ n4` L4K($H1ko\9qAv;+t_lqu'd8Sqvٓ#kM`Lvτ#q4I,Zrp2L@@:@oũghϧW`n1k#)/8  BfHc*oP<9nP~a!qNրf`Jh 4N<΋Q:ݸ|bar0ϳ0*] l0\%0UJʜ^Q :_m՘%IӞ~So&<ӈ@@:Z9^&狋xO.yxtD<T%ho7Q45>&B‹g|]dyz6LAdzVX Lpl!N6 /?"FD)ā~Zk'_?o:5Bed r:S\:@̅(|?22¬O$Smh@ ;m>L$:c+B9(`BFFX?c ,`F#.c `àb z}Їkh}tW(ԐGD8ږV=QtG+U͝"kY8B6pxC /;M<`1 L|N{*Б 5!U\%M9"`;|u-CSwk9lNjXG `9~pM*;ۍggOqNj; i6Pj±Cw #NnZc[b*7豽7Nbc9\ `N AG.rؾ,)5LF񠀽95_9Ra~HAQ||tH /l:/lDy:&͌7[L,UX`lp /P?' :SW,IF b>rAASpG) y &Β6`'d ?yB~{b~.Zõ ,%__:tiLL I~ŁtLʸ'4G:&Y%a@/+kռ}*KXp;Y1+JP ]{8ʡ7k<tzXELXϋce"dMY= MZIOQet=4#y$M9KnU,(mllm sa-m6# 6,; JգpbI/1}PQDE{h`6l}QBF2|4`!Tebe 6F#qP1%kq7^ώw-۩5K`<'Š% 0 k*ئ6! ߤa%$|JJ\ #8^9OGWn[նM #>fC0>tT6AL[jcNu,.C/oqn6&?I'x6OAO]eD@Χ#P'+7͌/ %avh_Bϟi0IɃYU@gg$0jnWD|-> t/e] d~d8ij1)4$U\V*jO3*<#f}rEop5 h>6eOQɰNZ]X)K!q#!dץȪ5@`Y2C_aΚ>2SNIٕ892N jqK!@qxy` .}] -O( 88 ~aŴ WcaBtA\Nh۞ڭF?Z73vYѪ:mM5LPH3x8:- !͌N%+.],Be%Px0_e_Ww~-sT˕JR~2x?%|獻tSxSl~JFAKC|{pyPPt77ɳY!1&= "QJdIJ#b8бS |r;H,V]JM&ԣ֐q4+V 4ӫB Oz$fJ"V@7JX~z\D+?vZ,r=rqr|;:(N̼5_]KvfTds,VAq8I&i8uD^3KUM)0x'fv1\QN:ZfJ9ڷꎿbpu5(m_N *FbUԁek‚ZV<@(KG0&rZ7e؏4%٧cy9m+vul *1¿ {Fj?D48;$0 8:[WB]3OqySlz E9o]nmܣZ扥$Wk:bP;Zpokvm,jfxs\+e1O #L'Ene2"իmt$8\p)Ud9eׅwk;ЇZfm˯VyOJy:ꂐ%]rt.OW-A N浐Yj/C^ Z%f*c9%drnlýuD&-񮎟DDZu=^5zj*ZTUbY;lE^Fi )ſ |mqH׬vqhSx[ qڮAİW\\iaR&uy^ԛdeed~LȇF xܻH ;Rw6 +q4u/h;2(ɠc6gx;=\w?>zG{g/݋9CdNx>$kpll6^Z: ;_q*ƵUS#zn&涼0 ɴ"fX N"&xceŸ ˮQgB'qTs(g5dWoR!3Ba*|] ."S߰Vɹ4j¹/|ƻU<\P4%/$'OL3?+q?qf@({I?'0}03 h=f~ns;:a|b7̻v-xe/MΖ[MvXc\J:ۡ y%r:D7>ŹaK[w4tB 6ɌS97}e)=Qg.2]D ڸ,%X_1lnm:*TSSy/뤋t6x=ӛa>dDw.yD&ʫ Sb6'\4BO:Kv~nHChaxSByJm x$51?FK ˞.+ X)|/ˈn:w5ƫw~ T8.uh}02Ч=>E&smqV1:Niw|U~_ ZOۭJ1 }5XZPr(%sfJ.jh}by\T\2bVU/؜ҷRTct .D~ױ#fM׻uflHie|ٸł:?it妻#7֙gχUzEby!У'7'1PxFi?O;O;^Io7+r1T~3w~2g!iWįw!UAeἕ˫tqeo.h9;2$l139E%t_[Sǐܑ2bvFC44ysIev~ouu/{;~T]D9VA?"\?L$"ʗ'"z5[4bu1^ oݭz?lL6&}t%vf*DԟV!+'$8'04{0 (ʆ{f/LqR"`qnуޤ0X]^]M1wT[Z:`*0̜ C.;~ӵR+ӗLLnNh5n`0|O|k<퟽?%Y7'lͷX_h!?.28fÄ1ᐵLin^6̊dn*AmH9c11)oaz+~uLLT}ۆ*wN+ӿkpƴ[H& ™Ot& c͵xo 1~i}{ w٩Nd*pBDN E6Hc)HϥRH^f.%_c75V.>'Oc| ۻHApac.J, (VRp JpvJ0xCt/'ȇ$TH钌7TZ{6*DP>RS@%ʖlri_{D0@]yۇy;S UȺvlSjt؇췫M8tvWg>Y'm7[1͕t4w%lN<\kilN-ͦ޷n+9Y,k\VVIĕ5!̺{a=֭)H)s4w٣Sh]5OU\h ڷ SqF_@QoR \̇.|n) Mo-x(OO~3q&6+ZZEٷ:ʚi浦.SFBe ֏1?4D{Nlbo< O䛩.O DUv+Xj7dL6UI2Uj^Q! +]&ͥ!_~>/-KPxSqVv[*]z5J+V/.ux6cqK/s4qÊ9VMWJZ{N"Pλ?"Vf4C˧e=\ZVSъe)gH=w/y^iM3'hMxs)ժ/2FG+/l0G!+y쑸ºKxأCȢ]ܙ_!_7%$ ⏕FZdSxWY )a^(oei⪸{,!LdK1q:eM.]ohK讽r;ܺ& 0nzSf"8mh z[mȰv ;Ba6mm6?tk(^u4Pf@)7?:VҹrӚ,x{DŽ JR0T䉑w4w٦q*g[qjru Dx;}i] YiZҺؓRKR5&J<1]ure8:Y [{rb@~Dw!PxxXBXL?},9p9@ɩp1<=yl@r@('1>_(oϑZ\R_ye=Jmxu 0 E>O2M]@WGs̡P ,Re셞k=R)VO)w)Gn" h ,~4AYr-1 ɜQ(rƎ Fҥ%.Mݔ-@3,O,}+O2h{և21WxT]o@|-U#RU1.A2&jN9Zsgݝ*{dvvvfw"ЂXd\!\ x !VUiv `T3i؇D-#˲{6!TV@dV(rFHn *gkMy+d .r1Zׄ:/i!Wv,6j8`L GGueSGL!Vȩ"oujVhXSjuf =;+rfJo\ c\j-&A1]/轃)2'^$qo^ Bo6nZT21+F#Z%2 &LMd)s _ՒYFI0xFSzzqxPf-sA A!{4!{cXG ev`.xblcWbb4$}..MxS$R(p4z(Қ`HhOA?A?JHX!._?XlU~cSq/w o-uL|/!$I46a4Ov]=9CTG߬".5 9LLks.8kg3Mvum!O/U;x=ksȲWLpwTqB-)f*YF $q=$s ̣_3wd0JhL΃,Z4%b6=]shMlF lNHH:[.ˆN^:=XDdg;i~L2MEd, 2(Ms8Or1!{{?z8 qD^x_LͲxf-껻z $8Lk,t7fc>ZY3ٰ*"Jg7KNu/d+\D A!@QrM$ u(5k`]zvLK+hxn@/Iף4zb1[x 6έ1@x7d"ʖ†5cBd@^)>$aLl^k0Aܿ2OD笸տim$ṯę}h&7MF 4(H8=<.>hЗjJv5kuB0Ϛ=u '<,9/H<{`+/c0uQjD# LY2SS1AMlXbJO"| 1ڂj(Vo8u<ΰ$~x~DJPyXݐu0#9yN5eԑM)1)0p~઻MZ-^D`7mQOaNnM%E]<[b) 3\g s& < _M2}j;يt y2He>Kra$ݓ%l(0hED`$c^Tdf6U5\(F,Y&sa &6iQRbi6B9H.H; 8ΰGd Zg:7FH? 9|n4A0HUr'R:(?$s Pha5bU@ib4uf>ngcsB[`f0(6EfH|`#jn<~3H&Y&i|&yXa7 Og['96ӏd`W'QႠ0#p$uEurt{u>?o \0HH%">7+\&ݣeK p;JM7/T P-)OB+ޟf!,P?bpnl+Lul\'ۄVa5(1q2H|>G1E}̙4 P}2g=>(2;Qh&+.rX0 \h0>&e/vpum hxmWE_8`X`rO|aP4~K`$5f,dqELR8fWQ>|=,(}kU*qNлY<&K'Z3tF ⬧jW>_bZ^_GG(]GPN> ixIS8>/hH6S{3۹La@`06J'3XO\ׄPPBAd`Ъt1Z#`3d"*} V^<:'ΩWdk3 4iDXE(6AX}vFilFrq~irvhGu'8+`NJU{yOršv[3V9(5S︩|f{4]pcfqXNղe6S˃ækn 'I+vyz R k}IV&̊i@V42!Uk/E -\ G!("OUIBH+ &SĤY`H 9ApTr 0x\d`UƿF嶫0 L nkq7BE^ w:?0`+5$gϡsq#ѷ*%IҖJw~F>eFWwCN5wwz&~ZB-% iW-tpl!0C wy[и l tE6l3PöTc&@Ķw]1&}2~dv'κg6 &'h@îWNֹ,Z lƢp~AY=jY1G^oYo]#T^@lѡ)#D_ ߟoRTTA@w]EV7uG, OxZY<7MӈJbM*?KEtL۫qѲ7OnL!A9ɠK@9v:jts?m.*Q&:Hx4-c#YAX)voY*W=b[=Q'&t}aBG8N؎NԎ#cj3}mUz3֪ ,.Fa߯FEr=a/CpLr50 Y72kbKT\Sa߃)Opgۤ~,sZAr0Wv豮EkLMOz8 A]Qq@Ss9h]0O/P < Uv6:$ ,A/IhlxyrLr,k*x6CphxU3tL[3S%F<1d۰1(r$u]xt1yzpxWPP%Ha渓KL6&wrmS|i]W˱==m텮;  4H^ ^݋ =hհ51kZL%>'6x晨8d%|GB?s̤ $fʤ  Śݭآ*&,&.P^(i]E ܥ;{ eV<;m4#S24컲z3sd hNX=dNA" ]_rEk1px-t? hclsM<yIںyih*0,.Mg~t&jf ^1(j[PX{To+IQBݬk,dXc>oQH:&yk }APEyVBD%:f 扵SK /cachL8%Job`&ƾP-ЂLhA#12!ooz`ak1O [K"`p_ct:,g:?w#3uϺ'm"#qer];`<4&4vYApi2|B"!4 #Tg웠|5>/=R9uќ!)nf]ݛV -Z,[Ƈa{hrotGe/LFJ=ʾT΅/W2V!^tURe ):X8FH(aYqrM-uDu|Ér:x(RC|=I?輻{N]@T(^G܏Nf z\ wH;9| ʐט.+m(Gѽ٫+r[XfG>aBO-:hZ䧏;iH71ly< 6vΠN/_D@xa`_lg[򷃋ͅ u͡X;16Q96c Kϔ4_>~f_iӴl9t-P0Ǯ%t*G6ζHB&:hEhFם 1"Cp;KhxΞ60z`O1^LqZ:QYN2_$a6֜&(>etwsc5u4_ &gYQv7mުVw&ou fJi貢j~y+ىu,zAւ+ m᯽:= |y?D^94IF@}8sza:{2JeGa<6 B|HoL% u'䃘vu#Q8@5AꜺɬw_,mDJTq@ɻ6!Q *(o ֬,#}Hj19QlXտ3VMZCH6?Ĵ\=08Vge$Rl> />,b=XA1ڃhK S̴eЕ% RkIMԫ l>l[ddMN;> *qWS[Ux쭜T=zUaG2kwwׅPQ풚E4Usـ@\rJbu]'vXZ+0uS+˩L p[]R ''glLM<5V^_Sr8:8++钗}vtϦ _N\U}l ][SaZd̡rd8TkܥڍéG1*ƞu~"!ۘ4ƑYGeО:Nɡ/N5ũ&ֵ|2H@<熮NOx0걻-UohгzkY+a5([$VΓ+AD\VɃ'¯H7?&+3i=袎%jEW Sw<([=rMAkg(Cz?z /(K%3-E klTYDžP]ړ _$gza3z} q7:au? Gй(bnn\Z1΢H;s͇2\FSkuZߓ&&줢$+"Zq*'ƽ+Υ1Xk"ϢQ+Nﰳ+E:S%so歩#^9tB8ͬ˯eN=/=>,)UDvU{87oxjCAw.m]G굳Az,H;`;2$@v :1^G%pixx;hs4`];xb:EG ?'p B]QOZj}X: |E0#sxq' Y'Ob=Y\Ri qLO-.JħVhMv|%[|.jؽvk aS8<s )9}ۜۄ6OJEJׁ&y*@RJL*qsq$j(Mޯb ¨A qS $4&jYdN`ךPZppmq$c(`rWdCY,0~}dqyqb NYjڜ9yj# 96'1ng9 CM#DBFbqƤlNt٠z~l[F u;;yxc. fjxX{sH>E/Wv?۽qRd MrkNH(+$h0foݯGO.{Q smG܁kKrZ^0Aȅ\C05)V)eąbh>DRKS?-F \ w6QoI7-Η(B\=!?joo{KH:;9( ן׸~cY y!9ұvR"9 ]xLC^B_JX&7D̊k mh kQ~.gi jz| 7|aâ;):E7fcV]t{fumBĸ8iφsj2k$[F֌uO2%@P#&Ew~wVTjwpFtq5@98 rg>Fp%UU+7`~y00> ݐa (Z9 P j 0:g]woq[%ZSS>ͳJt .‡÷'zn9ݓǣjcQs@QkW5'yzWϵ׸UdbΞ Syq?s$pP%:'~ǧ8w,1}|(:pHFHд<`x|=G3=pkI,gQjqRXLK62o{V*3#)2m )o r 6qY(̄`IQg9 zhX߇/ɱcbO&NJ+\,^`~bi)9o,&$6D\YBBGF hpul"46.ju8;mbRb-)?UjbqKr_'̍Q=D)Y[m,,||%p,T]<bl#[=h/j.}`bB57ԕb Ykz S59% \2Hc^`9EeUuPg?3lZQƄԯbÍ*dΠRGr/B€7*ɾZg@/FZGs-:J pUU2 dR2 " 9mΎOW+8ᑱCܘ,>YΌZR/QF4#6*xO6G#W+f+{ET,?>B>U;@jN# a˴r5PZ. O)ʑ]r8|߀ DeFKi\H:~\AV4wCНJҳF 6Eui*uK4lc(UzH7f׃ɆV1A<ٹBVOiW¾Y wN:f!gXS/$vD_!MʲD+k-I yXб+71*]z#VLSf6aq@ A苲>!x4!C͜UfuWT5Ƿ -rpҀczQ9蕔򂏞%}PHr|ۋupM֒3KkmMbLmvL%C_~m-ÇC(z Nm$ԯlO"ac֪QRqNwJڗ{s_48'@]Tq'=uIfK3/z 5:KjNb5{Fe;OKlt+M͸d1N*x:V0ݤj@R}#Դ-Ȝ*u}[^qSP#rХjw%3i-  3$`C݌Z(Ac5/;u_]]ׅzBPqaէEsl3j雑ő4B.-ۥJ3]v-'ӼW#)L>lAÀFV#:J:@Ɵ'ԕQR.:tsk#7 }4cd&b`AxitCD.\jͅdP8<)*_Y\R9IXQm`6F^xTQo0~ŭhRR/؄Ф! Mn|i ٗ2sv֘@w}9b6XGWiY{gt[l7m ږt'5{d9\f"4H[ zU*85UτxMQ 'iLM^Z{ iL 7 9wlV9܋Qd!um :'s!F7b?V98֙xw `#k.]fĿO]}dFCIg;z xVI_~|66$9L{ۆvb wa_+6B;U6BFӆl|cƷPb[I0sNdPrr˟ #?>] ^l :)zJ JY4$vtvG;/ *ArA/hZxVmo0L~ ) ZjREkiM lB /Tm P{s;58 |8#)N" [pd̔ :8j/(SE},Ho jnK eENX*ST5Yf’YǑ q5hP ̀8b'R0%n,Hq'&ӿ|˩{lY4$ߢ!PgŪ)!ބ!3$s T?e~#…#Eͭs%A#q8ÛJeQ?1F !-fZfZ TG| e։^s;p10h!5&z4]:S R{⵻˛JR*b0-U)s?f^OzN͛^wXN)~ޭd t?iؗ2bD8̎t~K3B-˼6tbb&Q"=D3rWTMVSys/fvP, _GvK2cbs>oSlݘI[y^R&d%\V+ͫViH#ߌ؈%:S-Y[.mv胳traj3Жب6ØD :&82(.⭃Ą@Dt, n\FOnO;틗ZkfD7#G7}i3)x/I~C*|%%:\U&cEj;F|7rns6cc!/sx/JvLk'3NcrydN>ԊMmCk..4.⒢JԢĒD];Pf^Bj^IQ%XP,'5O!miͥS:ٟEl>UZ5J\^JfLhOvg|ss/$#/PB5 yi@ME%Ey@V-s~nAbQBI+PHʯH-Qz(\N-,MQ(OqRR834@V)L.3b& r s*d?fNBܜ / sVlNUFv 0Tj'ckL\6ExY gq)Tx{%@v7ܒ׳1y׳l,D~?Rf:Tx{%Aj d9F33&8L.Әe[x65Ɇ, X 'nde|]et_q˲r$p]x # {7`;l89vPxQk0ǟOq4/Ymcx+KY!=E:۪U'Zt,tL |:~:YL3,BPÍdFpE[7Q ` *B˯`I%oGXTͣ4?ڭ7Up"I6䤅y"Y)JN` 16XB,,bS[6FPq3{R|=1_JDivo$\#Z 1t|ˬhARo e) ^W|1J+CzO-Y)<{R)\NbG3ՠjEdQ:w4|7B6JM5Hc4P%V~?8@+Cׇؐ&&V뷷B*6sY:ޑ+xO8 KW)OwxʳxYmsίа_ &d B貐 N3a p1尴-$37yt^$S9;4r,F1#G>ģa@|NPx(odthJl} [+uK7;Y,z0C=좫0p<0-7l~/g7A㉁]G}a Ђxm4ۡmr*MKNÁySyYnhE8]~#9D6$éa ='`v]:+ vl clFT-3d &sltwn6g F^߼L>ߚ]fzcc/kxxM?&N,f6f؜jE1@8@)ٙ>&@Tݍ)sz2~PZs<1ץ>,R>X>278ԷM.P -7'@d ^ DX =k>P^2}uF \txF,e"K-X[܏Mxgw2F] J]lL>T`DaO#[T BIS p$``u ]@ff hie֪"Gx" Ilk|? g'R Ϧ[śLd~{/Tu9t:![RSLS mc܆`zF. )]8%v:R4| dCYU.VHqRޖ`CjBp\\ 9QI1;#4O@<_? %1 tM% ړ;P͗F18-xض p"$@eQӋ9=Kp@'8@Ne,ck .K)ѹ ^@C v~)S|&A]ƨ^҄)IÓ{Nuh9~Qڈk']RkjU{/Ɯbhyl[$AR5"Ix Oθۗ*WޠoS= $0fݹL7LG6>E2nrLN1Xp̄oiuVK”pv S/qbS6 Gz=:CF7OI~>AG<ׄ :lԳMI8ˏ/ަV[(yQ\j~~FN(Srn Ȟ#efW;Ul~ 1TfR@ qdA揟9Z@ "vmHM}4 *'I,(Q0x5uMJmAK;a_%c` ^^. $TT>9&E qRRMVf>)W[k/[DG. QQjUB>aŇ&fsERyU~R1]?$)Y:q'f _v9%yo|?WRI@}X$ɻuG@Geo:yDe2m՚9l7PLzY?GyY+ Zﹶ+`Tú( K߿9]^+8`H\$)Mr*.C JbJ*u.XQ,٧˷,^fL qwT8o㶡^S򳴈@s9.9t$]˻V%yDfeڿt=b*BN"zY,*SLrp 'Vk?x[2edGUx[q2?.̼ҔT⒔$ ;..xTJ VA~f^Ij&W5gPR&`U ]$xSMo8=~AǡXo 8A$AK#B$QwHY X7xb4[nQ ^8jv[9ժ1`*jt搨nFH,pևwZ I%$BI^ecDcrq'Bz..^qM.s!GB(QsX`^G7S#4#GwURYPjaFk:Ez1go3!gJm^g(sQ8Jwgvflw5}[-K{76MoWQwItuSWtp2waG F*<^^hʷONxUl%$"/q ":L?ZF 2x,*us1e/lxk*s,'c?#8xk>+_93/94%U<9#hrzʥy)i ~N>~>3,//(-PUtwqG[% '2/<3/%\dVqIQf^LVyl `̒h#SXk.ܤĒbk.@jnqjZABqfUj~\d E%@Q : y% `T\GhHM)zW**@֓{L^5nLyzK-Faġ/~ =x*nU\2 r+<3R5"C\K2'gl̾JT_4E"`aXOg񘼀%FX .Wy6+?#lRőͰɳYev>ux?C#rf^rNiJMyrFbVFVKaϲLa񞼀]|9T a][x;+"!(3/}r= wf^rNiJRI棌 m.xk| Ae57dk2Elx{ pZ`??l"yxWmo6_quMr 47q8/u6D˜eJ%F$*&ŀ "w{x]0epJZ0EBn [ ,RB9 8EDa>,[ȇ0aKa,,YJpLC2pZ Ʃ9Z',G ȳl2da0 L@B9-} aL=.?|2&QZG_`yQZRq(79u,d(֒3!'`8}JtԋВEQeZf?8.j(2̀!z{UK::L(@p2m5([NJ0+Ә/ZVeDh^){>lmd*ZY>=ޗ W>Wt6,]TQ/_)wS}w~,*|4oÜf!LX4 *UR;[ ޤO2h~au@2s_ ֧V- iTDճs5Hԭ} ]JJDk\a\Gqnw"zk*٨կ|7|G}` _߽۾6Zit'60A!;vN>g*[fu-bXzx[*Fn +{||IqAffևMQl$x[*-a]ټ x+a>- 2J4KRRt6f 6xTMo1+FBT֪@Ǖblo㵗, "̛n; LP. g@,ׂd>Rk{qj* I@ M9cX氲BHkІʏZ[ SX$0BrcPn :盛/>h4E"O ^=.x7h@|es/fb t twKJ#3x$4&Q3d hg {B2^,hlg3LlYPݱ*Zȴ "o-}4u!JR$@bT' O t+Ҭ8!/TRlrV:^FwJՒ qC9J1țp!m [dYl2Aᮐ݅&BKµWTs%@50 Yv ?F/4-RD2u3|T:2d"<^颓&Iܽ 8eq+ݯȔy>.:i~XH:Am-u6+U{,`,v=Mt c/ 79!rcx9_X/-#( xWpopB( y'"UXŦHޭ% MM=Z{ZGcDL.q-ZE(Ѓ>+ Z%zޭu x[-I`C+{||IqAfLNh x\_sO1W^;I,&gP@g(IK=G aJ*~g===G:iaB'Kix&7qq!єϯI8Z'4FEHh0O^L0ѥmnl~C^D $i2^?8z}&d~E8TqwtSo/WrGi_9[ăݜqu`y{+>Xi&E4E]ztzBB9F ' JޒcөG/tۺQz ꘴f {K./xNqJf$x@u3흽_ݍzvGﶓ9gTX8IWKɵXsAKM+?NEo  4Пx'ZQ03aa6-ݬ^Ç ,%-=ӡی٩HRqڔ^I.^-^ -bH,b/e4/uGlE3c.[2( p׎Z$:nP`~*ecM"kYGW4o#oao-Nlt{=G1,G&B؟`gU= ?(=\pEguI =᤭$Hgcor8 SG q͇"x4 Xdd/ǫ5xSyjm s8d^ ZKV&!38߼1]@_~~l2SF &r.Z{@XkA)nd$|Č7҉$r ._:BϮБ`QfЁ-r=Qg81AӞPOQ'QB͂˜VTH!{\#O>_%B+ >´AqS7idRzWf  8M`C6" ޸MKďC!}6iHWDxƛ6Ihqnd?ԯ+vh֋(nZ2x$(ԃerG mWFWF͍8NOG}LL;fаr7djpMei ?7lQ-i5y}俛ab<8{$_H}HD VQ{3(B,w[ƚ8yWͲA@;{N3eH&\C&1={,w?$(\n<϶쮿rViN玳I_ AF͂}u dP̧H>;rxUx7ñ,9Xس7 x?dF*3W"+Wt=H60.xtS^Tg|,|ҙ`ѡ.hHt890@g >z3d:7 (At7B~d;hq Wj[hzs;}vl $*"]ޝEQwe U{ "o,*>%:V./H|vB|~ațo(ߨeo~p+uaivykrVS$sb&Vѝ%l|tR % ޟJ΢4OʩO2f'RFto;QwOplPSVCV)Zʅ,/9EHI?i3- p<8}+Tj+Yꏆt6@'OVv=y\ kVA,$QM; Sl~N#j,ezc(I^Ds'>Iܤur̷)(W dNCc}g)|WDy+?P5Pwv8P[`7FA}ZN}-ŪպR)|>}$|>\ֽps+VФf[GCUd?]{#_tJFfjFX8 71Y ukf:W:RgkOL8W;u"}D^(Z)[F0:ukhݬr:qJTvIAsfUR0%@7er6 hy-yI U/tŮ ITr3q_)d sr6OT?89̗ܙܤ.V}jqԪȿ}sv0J#&B@KnWYH0k9dl6Wdod V)t-+\I;ш |?6)%S6x^dPkuZ2rFA )fMT#6KhTfޛ-cWwxBy9n 'Xn"A*'˔P=G)ˏ9\Y&IZS#Ea .߷@vgi&.ʧ@Y(\3u]Z,?jҌDivDqc-7t(7 +6@Q%o\ pE,[Z uUh@$a J@ГGqYkG9JBzG[Huy١v҆u1` Hw V q@fn+٥cMFȟ<4>I>+䧡!=9=uK9 R?U4PhˋO'sx;-q䏹sG*H*[u{^e\I' _)XWI@D\9TV(R { }e=:~LDc*j$e[2$IUkmpͱ~T4v6Q*# .vj:",2]&jC2n>Ke7-RY *VR$S(2$&8?`1w$a72#%̇c>nX(÷_2C̯Ӟ%H{aNOcrlVz_BXӥSR[rk&sϰF539-.2Zr hAmֱ_G'}QY Vb,*кaifGvA󕷤B HU)_#n`j?@gI0x3Ffyr(U}HogpHc5_kDcPsP0s$`P+c<#`&=9?$DG!$88]!-'1XG,?3EA+%$QS&JIM՚˛X5yqμ,];&[a|[&Kk+$;CҴdOk> w_WV`1Q6:9/epe~VCj,5-\ԭ:V)Hy2*  b)4AҪZ(hMk'A~!y)99ٚYrCԀ&,| *1l^2Ez.ɲܓi)}6]Ao9֡K|Bӻ6e|є,D7E{gMF4uFBn(6Ǡ'"ʂbd?`Hm~&Vqog?}Ạ6%Ҙ ܽ\ߙq! SY^%44 1xI@|!?J(imE6II ,Q2'h8J}p$AqQH!~}H. cBNR qȕ:D$ʣ*rc@}X@$Ɉs27ʫ Vڃ`73l xe魾@;$cwF;$f䄉 dC(?QstOH.%^ L% qr Iua@NЮB$ba/nEdQsActcx8B$mWk (K>2d3 s;}\H fvōi@Mɧ{zm^TKYʃ hF"}1NlX:k<`ƲN芜%v5>1ru u|1Qz v^͈b17aNOai]k6Qr3AhZ2ecXj6Ȧ]uPI&+w_(@z"hG*P%h"@4SU񼽜=V]7]òŋ] 3*"x;jrd?3{||IqAffobUBx;je!i9?$DG!$88]!-'1XG,?3EA+%$QS@*<\C&ZlaK-OҵkShƷe\AIr32Mvl9Y\x+d\6#Ӎ$y7e|X)q2 |Oxa5j"f{f],$;- lJxa$&}l`xofe q&"0&xYo[IWn4uڴN8qlV[ul'MVlBpױǮ.Ո}@ ' "x ,<ܙ8I6=s|~̜|`#DT*SG<XB><<Ϋ ѕm@ VZGtwO1`LCХkY ZȞ:G=A,۴\(N] U=3 75r% .>dֶd( ?٫&GvaZqpi23wpZo6E YDQ0e><$ O8Fgr\`EU,su,Csi%XIh42b5VڊEв !F9N:ɽYXʱ養%C#z7jvTW9dǼQ91~(Hpqv%vk^yЯ^vh-<ڱ.(wYqȘ^ħQixMrs5BiJސa>-KAw",nlo+]R*Eox.nZ6X\.j6=: |91-u_!|%scOƈU>R Lf0zy=s/+~;)}ofxSYxlB\ea8wA zA]v50 l >v\ QS#bU*roK?<ˈOIcUW'd[t͉%'?TnuP9Qz[`R&nX *g>=FwBXMXro6#cZs~O8$BEL$"y%_CG~wөU>g?zrZ`]_S)"!".@"N{T4!M~pcHг޸JK̴a"':q3 k>86(y\NH8Yg/3hYu|N8ބ`&IfK` fq pjɎ8yBiy/݄zYvRK)˅+on?i66/P-g(0ﻗר'K1J~5EAqr} oomdqNvWTȱN}XaH̿VoC {'$k>_2LP]i:ʹ=LV&ZgK3;(7&Ǩwq*܏qJ%ǐt=Xx׫wI!.fCQ'gE<W[4Ѕnxư&N9>G6fg ws7Ώ̫sv;2bEmSu6MQn;|+n(!|]X5G-=DCh9! ewtQ9$7o|$ :XiRLr5v8>tZ8f<:ދm)\2f)f |װr)13L)_A uS˧@OZz?,@O9ƹux8lC#sIq4LL ՓyYk7Dz|`eI+JMKxsW.5pNMk..No7CFɯ'O3\!ega΂;E9sK B &LϚ|JkqCɥ"Vi %/ K{8F)J-)-SoKbEQ0AUyxF#a.N 9?$HVCЍS!6Sds|9. %ŸMjܩDVኌ1mSŶ9hۑ1xʸ;rC=L,~OJM.ѵ+I.lš2قg2/l=ԊļT5$͝&3 MQ wruQR/ 19IxdA\"&疟|@vr(ZۙٔSR26鱱l6 dFt&`>fd6 ;r2䣖pV@ֿ͌QalxPxC浢ɪ&LxPxd!,7MV]<C岆x=s6?N]IQؽnKɲE|K^'CI EjHʮ./4I뙦6 ,}Re5q  cv D̟9æQ/C`ǠB96_?n쀳Ad?.f5m\"`ώ߳]v !qD#2eь3T'd߅Ȩ<\3;uc:QFn Z3-$OZ?ZJb"VNH*H'ԅ\Z%:{SgZ_Y'[Oj12HڈX[o]i7YƫV@=z<=} McfQgh(mp}Pq|<ڪ%xz+Vd\DI* '&84 L/0f5Zf4H"S1 sl{VL7a7N4ﯜk3ۛ@A9]k]ClFT:/ڸh 8=A-ٿhZlJ )s<plK J/9gr8 ()d-5Umcɑ|V¿_NȖ0a0[/ yn-{q`LC:Q)"06y_M=!xB#A) G'==wcVG33f(L05;`gD^9Gg n%KVC'T0D(bJ+2)9: 8lq F7SX') cӢVXCHjjZBx9nS?LF]?cQaTdvrZ~;$XF絰T g2 |Lq%M#8CUŎT9U/#!{kP D@vofc뗀3c |1B`i %B^-WA\_ҩs ր |T+peAqVRe;HFwCXR6 .(R[YƱ>vbO!vZm<8yNVD:=C rGt{ecgp&k IԺhalw9"]%Vu䤆Zg'-Xe=- kY"OI6m჌SjA_`a'5S>µLtKqg [D=p!1˄"Mn{8yb@ZNf$?qLM(AfH%Ovv|XO|_ r_χ;;@h߬N \RC6Df\w%LGl1e읶%"Ah`1KJjel"?E>Kw\?`9UHR/ۿFK\ 5,R"~W(%mEOo2ZDTx$`?3LZɈj uȹW›4(; xPp*Znc^?dLAFS2Lqw̦ \^jtCz ,g.w^E- >:Hcѥ.OIlQ+3 8& yDGurB\(G4J^An&xIa8f40!WM\ESޞƴѴ4u$|+t+kO1F?KMX˅B5Sgg -"[:s"_+ۗO<Ҧm<dN-APVALq{rHp"bCKz(L<)•%/)qjAo i#wqyQA/ReGh֗ݼy0kĽ?Mh UEb@S>V2ř[ ~,x"Y' 1leg+_D]l&覜r ؃(8]TrTVB+RڼizTij_)Rʶ2byŅ /޴ޱ~g$S8{JdYPΛ}RKPz[ݞu:kVw1C[@IO]*dSgƫ-cW%-z%; +aD;l7&0lth6;O$)n$JSmYH[ˈp9B|^ ʪ.Ojb,*HE|vi{8b^c3Gu?*ȟ:N'rE2%(#lj31E%=WԴ`wWRO;ٍי sry3~x5 {w_ikTZ~Uqո7.<*;@0_E9:uvX5ZãSlYB%fwVn47S WfQ:tW#fi/~8)ˇt@&3>`P4h{#CxhuQE63cx`zMu26q'l\"Eua=ͭjT}:׳WVF2ܣWFcz:a. -?}R(Z#4!| vT'qO7Ȟ+ׇD̓eD ~{jDfEC+bzz'5(,SZcVI ,.`*͐|"ډ~^u3,"VBn t٢:;4^e9NwB^͹qA-1 5T"?x8=NK~^ۥUs1BΡLϸDEyj̎"$]dp'VW9eVa2nv۷.Qsg9iq߫)@'yM-. 9#ǾZD.G :H0L7=LW6ckɨCi:=A+R>5'myC]5rgx(T]BQW^,SoaOWHR-<%Gʒ=ō)I/VҬvٛNQdLSmfϑFHǶ`-sNl>ȗ/lLɛt=Lp'ĝ!]y쇚M9d⥆۸ޗ,$C#&QfDNEf?@?B 0܀X$Zڜ0palMK?s<5G܍#ÑģP\lZ#x8rR謕 - 4*$TPZ y7ܑOIrÑHŕ?TI/Ftw{b{ƅ1">B^;ޒ#oI~p.x09dg-Oz:P۫B Dct(Ha=Sbibu3[4dafɌHνRA)}wޘIm4t\ϝgrD2^WR'zYq]A,]r m/YrWr02,+Ίge#*0S-e&YI‹M6BM|^TREq2͎Y\zZ4/},  %;so);^ bIdw"ƫ0T RQ&x+wtLb&nP 0{_shse]E^5NUW~BbR\64]`sG7Affa2N׆ {X](؛LM=ܙb fLtxYoMJn?gO f-c| BO̷Xt|_\Bo8`2IQD/vA3;CfWepW^eÿs c0br ۻE 1ކ 9~R'S獷{[*ZI.t b\_eOQPֲ7 #y|JÍ~v6,đG_g73g.Ж˄MyU&>W'BQ+ XUXLWv |pLV/QP.iŜG?;""&)O[Rv8?k{l(T_%-]((mD?2)76]K[HaM"pQZz-"9 ҥa`>w8>x߉;ڳ nUC 6(ۢ7䪤C;t2/ޗ2mA\9ዺ|?. '۹pO~?.ħ߁<\l£A}ZS)A}VoNVNm*N*Np⏑մ%FD4FY㟥e3]3TцWttr(JLɆVef4JȒ ,k5Uj8P4(=\h2Fbۜ'8nT =YŠ>lIYD@Հ+F[_$9m:(ͩ ua>6Jb<զ]}>("$L7 τA}m$ˉC=3Άͣޠq^q=B#VšD˒юD1K33- [A?Ր6v+\l(SU"7?w}c:+Y}GG/Md#=L$J迪yVH'BA"' j$yh#1[\D0TH[+̉,n'N|Ͻ5AcC8`\Wo"gE9E.~[ 0 Y+Y 7=bɣ@UBqO'x. 2#8Nj];x?`U頞 7̊Q^cA)I18(65{d?VgS#8]Sa2; _(3.R`1$`8(LD!j.J}/aşrt4I؊]'閎#i7P g Iύu1}J}tT|ğ&e +SWڀX1?Ɗ8.jU,@T(3e`hԒ*z7 cє{x"\=E0 йeq'5d5R J%p>@+7h2ik5eReK$ RJSXd`fOrlT%Y$> !`JW-1?ay[BK>Ads^gSYòlMb&RU\*r_VsM|n3\sG?R}D#NZuL Y) `X (|.\P~og&w,/;}*s">$QwoBe갛a"5!RC^rEexnmMw!]❼ɓFkWJ?(SAUjwz貮7~67wS{w7)  zx;y^VBt4|ߩ]+ @_xq>ˀ/\vC3֪#EGgS3MLV=\>fV:#^<r-rC9ɹ|%"I0MK:3jѻT0Ux4zGYqa?mP֬ Sd3˙kDw{4 Nvz2xJq~) y80Ui_٠1rF5If陯;-@J4I *Ԋo")V仺;,r+s 1D̼k~J&H9bnv.K,JfrNe3l3nm8`$P_G"\POj 64yv]br̸c2{Z޾O<0s-L9ڭ>,mNV5k "t5kІlFFxx*1,Tj5RTxagBNg^-$n-6Ǜd zW0>a ǻcżz=" Cw@Է79=/U7:}bwA?>l }oҙ}1g{-PKjJMJ%( U`^QC#Α?y ߩǰ}r[ŧgje7d#ZV\Ⱥz7$ᷫ-.i3􍼘Tw #v--VZ4F x{tiy ҌE9msS8'?d,s /x@7~ Xxx9 ';KNfa5,+LKMQISU(.)24B}}627<8s?'冻7UDN y1.fp#"c$ࢯQce%/rn("AAB.RFS[ 2A=( EijNg;*'̻rl?b ʆ\ca쵙:]XG6?ȿ;ou:%alA@>V. ,r[^ʄ+~gBV,xktt/ӆ1: ZewسL>93"6yGe),,e9;x;i^ In֥)% % % %% iE %E ťE%) !Ύ!A~>ś)E@x;\ iM'g'pO $x;\ iM'g;{rc攊ؽ yPx;l iM'ggzԊ] D(x>l ]Y\'-aT(UYw` uf5x4l ћc&?H7C'_hpd9B19x[8L -6\Eť9% _i+0ZondD'h=QXb_grYs7N쒦6!Wp4 )n>G@$Cgre +X`FɫPTd&g@X:U}c|f \kOޗ=9Qwͫ'OHa\/0yCfՆw@Y'k4-|)iD>o;'Wf6Xex4i,)Yr&,>M?wQ98BSK&7sle/6g73")plilry滖˙&.6:Vl2s䕱 zI C&L6 c Nӝl*=Nl2_: R sM&3kmZkEjriIM&NW\%>_d PG^P(p,-;9b2z9ɉ9%: j%>yp+xٓtR&?䕙l/$2yf,8nx2$ l\&nVf^x2iKӄEfNv`s#»Y]z=ͅMo -L| Hx2mӄEf).Ȍ+I-K\xed&kpO >{r6d%X&[L|cr_ͫعSK&*( {x:G*dd&WNnUJLU ydf&w|'\ ̘x?wnxǴiC$ͻJaUxke.3u<#qxk4s.3s' IK;$'畤Vh{8F(d8CDu899 98*㪠=9OReeK]ƌq6 !N[,];Fow2O"2O&ԔɁRmQ)6yB7ж4 4lmB}|~|@OBds5'!GjMNhUn# ߚf4 YxyqoA̼ҔTĔ1rqDf,3RRB\}|<]'(M*cͥف; <ޛxD6疖V'gkM/Z U4*]Fd63C-F )x!er%+gfdAYKxPx!er%+gfdAYJR+Jt8A`s[W X8xkvlvܠϒXِ?H5mxkvlry},52: 7xkvb1aš̓mfgie 2$xbbd6N.NļԢy/-h Jxbq`#rf^rNiJMyrFbf6̓E&۱nVgaL+.O-'j +}-ĜĒTTܤ"4ʒbP?OgW%E ZsM䜜*#PYU9',|X8p(ᱫZ_ZRZfOqIQf^Bb^ WS, -$UX ֠V$@nQUGJHi{xZ6 slIl"x{oqKo5!y.$rfx;ep`fY̓JlfYy 5x;e`f̪ɗO%+*&'O^"_\`hiřRjѯkP铟ZT_dPWZT0,F $⪧i=dkQ~ ?Gxנ m\'Ȱ-ª! t[rAFyrFbZZ)%: %Xj8'DZO[1r>ɓx'׳sr悴M6dKMQISR%?M&M&˳qn ^)xW[OF~Y(\*}=S53Ҋsw/T]<wnsL cX򐥊Eph&y(8k)2&-,/GP-E$,DD.CO~ $O}G0ٓwE)@s 犧L)tH c۶i~{um\tMLTQw][cɂjX+u=)/*>/K|=IYpyA,w] v(R@! Cjť%J#1kT6/. ko\o\G?;d4_]_- | ,^#/j"d*OԶ&0&1Uv a$"t2u^ Gm[| 8r9Ld-ŝ+΄!~Fm-K2˔qonLڬW/oy. p~lh5xt70t2!'P3*Jƨv(JUWf>w=oj]ilAmlkH dˆRO,ZR/1ÑE{$&N<0jxf;Έ!1!l^S2`'(=E|Bu2EXG_fŅivutIk3]e(FGto>5:Po:) }xR4_}Hi0J[FYV hHwJebZ]&VhrRADMڍGfbm8}[P#oaHK Bdvs5 <}E:@H%VK3W\gELXR$6qj:cz;ٸj,׍ߨ iUwo#PVTAk$Y Vvg%?́U`*X0k}"ub|>I{+^/`-ٮl,8@0OCB8}'LQP-SmP%ٮll[O桚OTkjZ]WJYʞʺ_PiobA0]_7⢿j@x;/Hn\,!>9%vXe!¡~G? 9x[$wKr\6#spoveg*LJILO+JMRK5&I(*hL#̮ |@>"̢Eej 9%: j0t2Rb%y%%\E%Ey Eť9%@e7eL7ax[$7On%#GIQ~iqjQfWƻU?ٻxXn6}M@$miR캕 E!mk#EenCRdA ɋ-93CSG& 죞0 0A tNI)AdqSFI` %$;4$Sѣ 7ʖj9C< Q+M' <'zst\~A4 S`~<!LiDV4f|S$9ﭝO&ƕ$ܔaex8T$ly?> (35 |F"o)c=Ϻ98 NѪ&|瓵c;á lL )|v|0'LDV /J>b [5700H;Ì`zVCO8#pi8eakFY y&pd;"b2X@6m7DRьYJo$ h|à^b`vVB[Y ..C2dSA\%2:+ ^MmSpn[vb)^k,XY׵/,b[Z%Ykxa䉉VQ'ҳ!t{lum!N  eru Ŧ^T%[&fD;o봤Fݾ$H3 l+io"" 2 S[c6E ;ЏW>w8ϢUHq)*ՏX^.ėr*tstŇiC*'8LN(|mdzLSUI\GsOaE~(cJaBZ(R ,p盏٬}joݎVVEQThӷwb+`ޑ0;1FN؊N]NCsD7CZ_%Ul,(B~ *߽ep9Īp 8# DR $>7C]& XnKI-BOk"o MS yϕ6;n_޺S $󻖈VƩ; Y{f7A}8MrA72%_b{v9WE6qܵ 6 &_[_O'% #o*B?m͖m=Ss'&;Jߪ{&טNHm!صݳ'DVavCY )Cmf"O<]y0_ f 5<-iWca (.p7_}ie,x붻o;''gQjIiQs8V 'xiAOGA(LV/g k..NN΢ԒҢX &'qpC'el]]xZ[sF~4z*;N3u<8O DAm{..ypew;9ZVyQ f.\ <ۏ.pɢ z8&QYDpFqf&,#vޥK~. ۇ*(Y'-o{KEQ>_ ~1/,( 4V lzECc+[ʳxY+Î=K$^<^F9Xc}25L,8ؖ*=? G?Dta:_ZQoBg]Ɯ!bONzi$\JN^c~訯{p֮hO@W0ڀ[F8ף(7|;p} f3EgZĴZKVQ^1nͅ~19`s;BR@Ɏp5g%&{IZӉv =[@ROKf"2Ț'5 (|9 B&tKP8B yQ'wĚL}}29Q,{AYPTmU|Eh͘a=sRz9z~JkeC܆" Ѕ I,̛>fhmB8tZ9M6,{>3gmxf<$(T>B6zlc|fʚθRN̂D"3}[餆# {G(8am^,@-\$1[sr:ޡh]G~G\6!|Ɉvf]jcB7q7$f[!"iа=RZFMv{CKp[|`#:\tԡ\ҏԬn0,' RX@>X-˛y=0E{tJ$\OT.l҇oNJwlm`o,[hF ^27H7Y C BR~xtY:zst<\E.3׋Rc0Zu68'إ 7=+%Gg\?Fb7q7#N F\AsPfAJR[9 :6i)d/cе1^Բk9g@6z2F]]Ks^? spY>N.~V7oCc-?22O# Zɏ:ԝj"j*J@IcWS A~fDVFh=?N-S,JL-}/ !/yeV߻UB#k>jiL}XLEgLH T|mH>O ]<}ĨCܥmizv_ب~O0}jY "o>p Bw9}~dʧOddH{qSJH!T¦f3@5¡ч3yr/(W,JWߵKȅҳL?{m]Xc|VYhׇ ~?'X2 |##y ң-;9yGU6iQz1Z-a'Ņ[t%a‹n,b?w<3ߞ#YRqk>eWNN Ofrw0OspƭE5QJή5'/9>b N*<3oF8솄{LXC[|ٕi oصVm٢lTX&e$ \Av T$8yqin ܕg eY |,,cJ{z1hR!fJGG[8 HR%A._Y7-{;YּDlr%Gw(+Jk,uBtN=Ňg, +p'9V{e-;<^~Ϛ*y.'4'BDt=qǃ֛35WZپg݄.־8q-WJ_Y.A'N9uyp,>gXGf,4"lBx;=b2(1Yx;9)rCd>!ͳpn.ͧUPZ`3Y^OټJCE1Ax91rCde/VI;fl]xa&}sxToVmc76 q@}%kg @Eemk)`358n&M ê^6 zkgIN*.~=ܝ6ՅDx4?n*<>'d-]uS -JKtqrF/,e41')9.&Jc$;|>JK wgʋ2lݮH)`;rwd4; b7j#QY3bǝt -װqxƆ% M:>~@>vg'¦Y# k49ou:Ke³F:Kϕ8[ c>=msXcrBb1a<6N OXEWv"Bu ^ }mJ VF!Si%c 1t'z(Cbgm2P J!fyn4*ZVm-[4(tcї_釧_NRz3§5b+1O@#{To2%'JwCDޜRoo8UU¬_Ij]315pt:aAuUчuIjrKq=al{@֌4l"_|V@,~D:,47_ƪ/'sGij_Nz\f]zLvJuN*(tY L?;4y}q1^O],Zi&pT:tGl$$syHbk-!R7C>z܂{,{k;εiW= 5m˲7Gf;k[3_ެ|_xUKoUc6SwƵH8kؑ u^+U7ē}jcpwh:_L%m=Π{(|EgA8eDR>cOÔFVeӷbj%1kr+:&GꚪnU2x ]hNW#w",L(d#)_N`:=}{r[:l˹ ^/r4T}G Ihy]^KKٕL;:M./`xRm-j{B >Nn4I6vESGn`Ա>C!ĺe)Y#ڡpMgku<$VVm[ąe$3A)xܲF?2R4E _ Wo`;@x50dQ/58R[yᯰoT }@rp  o#X7[<v'.˰xJEdž%B "6B1Bw#\rUU K(:͘&ћs7}""N+x5Cք7siQeJc8 tuq}~HW<~s .Xy*$ucwvGPdkYOCC=l NƌQ"Zpf[,,d jfFT"2)Fse"o |}g2]ݵ f9g9!j4Z)mZ8LxoH x{{c\6#s&/ÒV:5gj^rJbIQTYP**'\\i řU v  \`Y@%99`0Ne9yd%y\@ U wIN>(n#_uL<ȅ -_z2?Ӝ< >)0O0iZOv4,sH0$88>58'D(4d\fiT 59%: jv(d'e&K JR+J455/J-)-ʃ&=Y^uvEVlJx{{k%#OqAf|f^IjQ^bfG/jlaff,19Ne-J߳ON(O>ͥ`\9-kK\2jEgcx5e1xvmC/ Bj^rJbI,")($x;6f.F9n׈xgo^1P?= PRLaAQY\kiUuoQx;vmf>)SN,klfxr{>fv)'\mMxu'Nea. }F%xuRf|b0SEfn~#ܜ*2//xuC'gb^qyjBHP5糆 ̲xX[o6~~Y\a{a0D[leI>R!Q;Eig:,K”xp0P'H^&QLn.o$R4BeK3ڰNBd&2`ŏ nB"tB',!ISk&)<;?An?4[A9e^@OFuI0jj%4e1x(GEg,MOΕԦ2f1X b׉{PFXѶ._@LӾ3ҸԷ|>[--w Y#zưYZ?k Bku1@kⲑ6BB,`mk^@'x;|:'f&6=a^,F H(!w=d ;=s` !,KBKNWkku}kܮ^4%`Tps0JJ|B뾰bbBgW<’+U'_˭܈rh/΍!Axi{?u_++@ʾZNe%K," aU30ِH{*9Huf1oZƎ~}m2RoI=:k_OoȮ]6|oQۧ$fqii!%c̓_D" ջ>Q ZI1xt)dg:sxնz(q%&x׍bǝ mKUӯ+};?DӄxcQhMmmy$ʯ9 ED$9%$OWNiָtg\Nϡgﹲ?ػds4 |*(,+>0X&G)B.hi" @\{3E)H yVV٢FPܠNyY@S܁O2L5dd,td[:4*xW9{bgag3Q()а& v[^bʱs(-O/ =nҹjUE ^M4+C <(!zxEꇁ$e̅_ܧJyh {P]P0kdT>d7 Qx[Iu\6#s#&s1Lg(,[XU=Mj)$o5Cda&8.4 Ҝ[T V។ ,).p+I(,J-)-S8YM5"ux[Rw\G}CC\#}56?dAEQMdAQY\kiUlAx[7Mo_f .N򃓱bޟ`Rt3zFF'Y@J&1la5xڠ!@=> 3~s`#3y 7x{Tw%#GIQ~iqjQfW%b'T x7Eo_fN ,|YU.x7Uo4ɞW04KxFw4ɞW0+日*$)dde&(d$g('e&(*dBs2K3K2ܼT.-B| -E7s 0m&(xx<-- answer = TRUE; %9FAIL); ) M KmlJx{BgC8G&R`xA{C8GL{xFx]msH b.W8]z*$fƅJƈD7I#i@|43˴F[ 40rmg8 0Bwuހ:~[0a;4]Aw` o;w~|e.~.W!n Z.p7N@ -9ݻoݍ-S.|1~xVY{Wl6o 8_>?a$[܅:q۶]۵濡7]4 -w4tnl*d`_ 2ZϋfG6dԄ M7`ZդodcXC#}woAYAh.of>V h >1A  }! pw}62,X'k Op}Bwȅ8;m N[ rڳ[; pp[m&%FD#o9}o!k 0ZY4H4 f0b ̘|ƓW&H/2I8.x$Ҹu}ۄ.|p9 CL~y*{C8~]K̀TYZ̜/k;QNNOq!#>ɘJb3e0xX@EseT$d׿tGK{}9`@s~7!/zk+>*7ϒlxm}ګ7PPl^ܶ v c:_X f2jFޏXb,(Њ؎Ì!#uwI;3&ӡUp%t/1ɵ2元aP>MeoEuZpؘ1#u/͛;i",1|) kIW_'|"1 J]k< AdN ]B8&"zݛzh(n޲+ J=_!96˲|,8cM?v۰,`OS< (PY@Ui*@eP},P(ՙ品i4`ZC׾sqKưe`:Z+(X41*Q lPH훵9U#? %/ U9Ge)ո<@f22pcQfn-z!QPyrB5WXI>z1& E^.@I?IOJvwƕFk2 %z`mƽsoo$ $2EBD~T-+TI}6KI^TJjya?Ñ+,8^ep I@,iZ=cX#*ɭ `{MHS!pߌiv4>o!FoK92AEH/xzKhx KN'+d͢ntA)[pFr9E|r ~"?X0t2ymهlQNΨka [$heMhA,UjYO1!$|.BR ΂@0a G:el;Kishw@s,^`Y3}.Ge4"8=,-m YZ 1'M4t$Hhٚ!Xig> oR WlїӐF#P=k4ŬT<&^4i$Z5^BFR  ̩cP+ +Yd(Q_&-pŽHnU`?@U ƱջpQ*ƥ 4(T_PЩ?o; sEGG@BB"d|3чƠ4`m<ؒ-LhL<% pF9tl?Ea|\+06&_v`'㺲 a֌8ϫ*GKՐ bj.{Hd@@Y3Al^ӂk(ByN9KHDiH$L,^ڈ %F)'-k]+/%O+Y׵uUZ <8Qqq)W#Sgs 'Gw t * RU%W#?څOyFv£Q^u\ʯ%'Gώi> +#ӫi4Te0:AE~k-"æI*%4-YIhbԖ=|azB$ !{C{d?]iM~$xㆿ*&rlQ l0㆙& pm>g1} +1a# x\sH E'WBoUdbHֻw0vRIg rY{?d9mF}Иϼ[6v12z3gc |g uX: s,d=s>:v<9#k$:ضPX4`̏n82] lk-k>W%$͋k:0 {pD}u0wjDPh47www5TG; Y&ǶX?I͝Á砾=^2b"w NQz fΘ_EnP:3g˚mIbqk>?ȶyrMNvg'Ԗ4>d8|6}mKe|26<4]s`tߵIF E34oEl2~1ѨD]WN[Wi4TG4\6t76 ?_AX@,3& A%gvWU?3.(bVgAj.yWz>BJ0'`{^ő¶e  ovUMP kИO!7%!(A@pE4RI*+ 1(FʜڤeczFh`Ĩ? S^t:-nHˏ*c0H[S#5by&, deʰSѵJE[N "frnkTrel$OkQsԫh D<.-á"=v  #=/!Pk+楁eK#cFDT^#=VHDL9ů!9 ƍFMSmSYympBQ ͖zG6wbPHOE&G:F ITd6nI4&weL -Y򙄵‘#RStÌ2JxkMi;*aNvN9sp1t(Zn9HV ՛Ѐ1L(G ,?SWO_QC[v<vnm kCڂe9a8Urh"GoJM"O\,[ |vmfa ?4thI(c ̌m.ntĽൣFj6KEW^?O>N0BPK&81+{p#>31e~o(5/0 Lr y8=JHZJzU@5F<ɭ8N]i-)ͧ*O҇hN:95ЕwrپT>(H 3mJi9Ehrx%1 yk!*='f]^\w;BWQ_]0P0YALҢΈq^Ȱ RZ% |gg}##Iش|w@ˍnC L|g)J8-}.[c HQ3)?@wV0BI׏ϸB%~Oy*A>W ՐˌDd8ʥU4ZU-,4gوTWqo6B쏌Xe0!%Z[6 p䵒I6"#4^Sݝg;Ǵ)-Ȱ+Q*oa2 P֜ ruq8P1&vi_EX8"';rBnY".`_CRjt )א Aہݰ$r¿3hوR x/^$*b6I <4'M,dE@tRSR<,IdV\]:-8Ea EBIDtrYق-grI9bK<ڋn:$p.Jrq^#jme`SG[]P 1c̤zUy4\͖_PȚ0?0:yjR×/2<@ggn@|.ܣ.x o}3>HȬqÀ+Wo}8UKCuOOd0R*Ũ $bY85Ysx!z?Kcɟ9+݄5} n''硛Ov#I;W1!wC|Bķuboq.bPpi ;gOH|o<bPqzJ2;k0JZݡpf#S3U- '|Kvqr.q='| Lzɏ90&J JyeChmyK?5B̍!#E,Q/ց;mUJJSN_D ^ֆT|C *Wb 'V34>/.}H3yqyxGJ& he :a\2]<FL5 d2k:eo$Oƙ;;[D?+^Qjn~YZ^YqI~Qj|NfqV។ h89Mzr,Uy6pMS|R{|DŽͿKmyqs= `4?|x[: e) Z)%\Փ &a&'O~>?+^Qjn~YZ^YqI~Qj|NfqV។ h89Mzr,Uy6pMt\)zx[: ,<y%Ey9YzD';_\ifL>/8NI22ZP)[T];. dY0#mxx4a:Ox'zx;; Vm<.0ngTY x\{oJ>T7JhwUI"m"!nUY`sm493~{l !)y"Ta!ktmj39[0G<=vԱ̅,jP7[` kx]sh teh[KOh89ihS8]غlgLUO1aX|bvS0yK̲ 3ҍ1] .y<:}0ٓq?os]]84vy͵>=Ssf bU;J+5u>ID?4=?=&SEs ª[OW='lߋ`\:bz,[ T'SX,#( 6ql3Gdr oUU2NJeVio{m[ aS6<),XYX2yt:\"ھߝ+'jsRK eUU)(AgKH#qT1s賁CUQB6/徏Q0tzdLDEf3N"T:SUQt 5- |5/޵V}-V7F (w tؔbVQo5{z%z-YO 𰂪N'xuFJ!'1P6+?2#*=f}F tzj1ĸI"W֊xԇE>Be94Bz%2$<{ tJ uC?>>+]T;0P}Nv?;Ii92/y8H]sl nrg3J{W47J@q dYaۻgkV x׀ݸi?o9®v5/4EtTOvsۜ1G>4þa*>>KoC)$}|:.&FQxiCpBvKb"z9? *?^X5R&iPMɑ͋RBI0WA|2+z@R4.%A%x]qsS7,H G$UO=ȶ &}2 sjWi"@U.|w y#Qmzy3S>l2wfͥD4S:rl:& MAgZejөُZWi_TЬ14w)~V^9/U^k%AݵFma$ImM +c={k\%U@T}siAI@]+=Ņ+iYCxt ''4o_$BTH%W2H`qYGgR.Dl*l⇏4g/RH@E6y[؉az@*͌K*͞vѪcs:H,S8bMpp/xQ&pP3ЫG| >^GJ`EX?<3i+e,~=~N.+_0YXL:ZO,iUD'%qA2+dpWKKofjJWgl: *Yv+JP~RRDi*"Od5%)JZɹfE 6IL~%Ķ-7H͊폄=Dl? dBG3xqJ`gv{ .h LWJNA?E);Tn{\!n-:>G{ 1% 淥?sZp0hM*%/SšR*f~$Js%* \em,D!VFڋ3z~|x?Rε=̖5_l3UOWq~,e&pG \~D //;坂j%O-~P)hB;+Ja-ye_̦ F6C9 yZ$hfG[mt:}p=lEbbP.lcm!ɚ%;u7bf;;"鋩r -,#(j@Q$mUYOi#Nh0%yxں˝d |2@}N†21E7/߄ i[R)RߒWG|),g!5N|f%OrI }) &>hOsJ wb Ă~}1w”>/~9H~_Z$,9rwzN|۶M!z2Ȉ?%*%aMm(K=k^s\s 8:GkW^֊N'%’8L2WghXsxk<RJuT Ͽ-8m ف^=s{g9iڜ iHQjD7tűUإGS3mֵ< Z~kx;6 JJ 6)G x;cebkZl~*49̜ss%AIwmޯ7cT%9gyYQA\n6uY+ gx{qV 'ov`YQKx{ 'ov`ql`(9l)O涘=yŕ5wYg,o8G%&0R%HRBlrs ]00VB {iXwT,M!W2(Uw]*C |twL}|pON#{P?cKC $P\^`86>]ScfLtqNMVɜ,:wʁ*GA\<4TȉG?]%B^Qsp6[ ;6<OTcXAC+o\iK ţ^IBQjVj!6C_ [R̯viX9bo5O $[B~-* UgᮨgQTMNZya݁ghi]֡w!z{aREh oA#*`͙n%)pYs%biy Osa 6QE@⤙Dk8Y2m͡_vu3CkI0M'rqLUuD ^.,N?Az=E?=Vj  l" 6:~E ±:JJv_þ( y^s ȯGX I(\"A.8j19W#YJ C8)!4geLgBM1`FjWmbW[ao[ L, ݴBXc|Еk韂k#j"N_hO(l%BtދwINi*}ec<ξuβʢxD˫$T*3;wfm^8A_Ґh0; E"OC{0ހab@;>%,Yu Q :s"03o7lxMc5l`QT,qkNT.E-!屘Y -s3㕤䫧kG .m ( 0ZȤcQxY?g2ZKA>K?:־_Ŀ4AkxTAoEn⦕CJb{um("nձx]( k{lZY+BxP QUKO ~*9!Jϝٵ]mVyo<ͯn0f6T-b^ՠp5ܨ& wXw`wM_^pMDm:J|)xδ튅53Bْ.Cz|p|Z\!s1yMl  Pz6Rکw K@;]RkPZFP*6 k9GuESEe62:u-*~v{LQ6{ \-fFATYžb(^#O4/f ۧ$lv}uߧ bmuy-x#kv xGecdol~#|c2ڍ)BQdPάZfR:WʢhEjKıq{z9`*uW6HeD\ [:u9;GS<))_pZzVN :eu9qUJe,R4}$N&rs"jG{DcSNVk@+ L`'a47:i@s:)%y c}gr 벛g;.xPG">csSI!8-(* 8:xl}wFmlaϹw 0_ v'JuQˑ^ Bw&pL9gͦsOgZٯ>I,O?/S̺?6~/^x6$z0'Rvea>ë'觊3Mx0 %EũEś]=v|pxeP]K`f>&RZi+0>DB(4"n`]e"O׮]5+qsޚ̥y_eko,3}1Ist ¦T"IvI4:rC }  dHfVj+?Ph4w  uK|T F3C A(yMGt[bWantlW4|Hrfb[ W$Q.`jFT)*k.\g${ug[ #to;8XDDabK#>N!9Hre(نF}"uىR<¸?`1OǗxxk,gs~i<k.PO3[ɌǘrE'?uL'?a, [\5L&D̪TI#'?ެ+xE *txk,8a:rٍ7'oSSHIMS,V(H1KsJK*sR򋀢œ56ul3~oQx;4C SrZa:|?inx;r >xA@G XGa 6UĢJ''Bsckpoqbf& iiũ% \~!f&4g1)Lfqcf#vx iP\TY9KQx4L4>,4x|i9 snRRLPV0T(KNUp*VH,JU0PHJ,NMQҟ\* R;y $Xx{Zxp0p€xřs'ZV oNն^ݽ~s^,MǛUү ) ܍Հ^0} =fmpBwk>bu,-_!G\XiY!Ә*)5^J)d"@g3cetGk $UV?넨Q(CS$5 "©~Z2:Xz;&Bq$3'6jX*Ҹ2?ɬD+h<Tj7w 3xk!Kise ¹u-24 u@_B5''HER!71''?Y#3b+Jf٘!DPOc#ɍҼZ  6 @9ipb>9d0l?x{f&NVx{RI!b} Mm%X67og ѿx=ksHWtrk@9wl[ 6.g&TFH$xs!n= :RNλO>44I B:'vDvC\=dpv p6t= m0dһ c%Ȟ}MZ6Y"2`ώ߳]r !<[_ls?;l휒uGg~DP-Y\OQ^j߈?~C3cm#<{NdDg_9 kN]BhRfs2[7p҄>:{˞[}ot5>!|jrHބt6_tl A HF& ntl6i8lg7$tMEKe&Bn6aC?h\ȗL#`tK_#6`5]/G7+L7{s_7 h߳z{'-tc\sl ĺUnH+]^co,:dD gt!w[šWNH8}(YQ" C"֒FWJ1ȁ/"4RA^ŒR΂FZ.hѝLngQ,8xן .Vw[㘡_bv0TR@*#!a̛c9.BXIQ z7͘iv SLhz_M(k3mFQEM8*&OC1Fy&C+y5Pgtݜ< ^PtIt'V;cF1g4drsG>oQi;ʹaiqxT|!\Z4Hq3h}ZflE$7,X-\έݫaѮT'FGX Հ\m!{VD*s5GqJ;u2ɄoPe>| @Wdؚjm $XS?l.$,+4>(|E[|fhjN!Ua+ߛP}I'XNgfs#hܽǼMjsgI= FitmɎY^S\VQOQ\hO2ϦV)l"_v{;-@,sqvgF𑖗*q44RL>sJG|!e2CeQIN mT.LԻf˘ uDobOek0ĭelS vʢlΉf+ɮ{c3; lcnpdS?,m a/{72.4X8y5ᵲ0@ ?;FC3aE,@Sz\19NLooNJad\RҝM1 3ܷ$ˤG3ڏv=tagN5); g\_`9n~Dl'/YW%j1HT[ʶPF|܏\pU##SbY&|K_l KcC l U\t S3197 ۼ=MKsV/}f4|2 3{-&/BQ:Gxc;@i)SMћ)knlGQ|\`g>g&Tel Abz Z0Q5*?OV PFsHwx8Gzڌ`<>!f,%ß-SSfZ-~Fă;O_B GeرztWݡF7Z',M’euPD,ÆUۉ<ٗiqBR[06F?'/c$LqRCFymWľ=ū慳&E6|T&LvR!d6| Ǻd!`(37P EKOOF#B֛_ Nomg0IoϺu{G~Yl5NJgoˈwyŞ}eeh#Io_ 5_rEAbxlMjy0LsZ^7iD!@Z>D*T58i3yG7VHAߛgvտ\Wmb;$wo' /[ޒ">\EvS^ӝ :δ؀n*ol,dD=t ۳!ΞH$n?tF0-(7C2>s10L8Zk/7x}$a0 gm{1V_/q;/WF}輴-kR9Σ=7OQGAg`g6,PfOy(w)!Nj)b-\eU20]P:RD y;S YSjiѐ(5bScM8M@w¬>VCm\mk_#u܄mք\^ Ժ?ԠK;Bm0[ZtS-%R;&; &/-6h*M .LDV08-8tej~1؎}ܔT]46'V,hd%beUiqiXK;;g&v,X,brqN)eqEBņ[U*3ǰD|=j̇z&E^ɷZƅvMP`X}KRTHl S! tVolZ|^jzp 8$s˒j+ǦGzԩg ~'y _/LW;Oox1׏1$ D3?ZloNkQ3LtDipRxWs)lC:?tͺR2ǧk Џ `݌e 127|ĒtH͝'6ZN3%'bdgjjժMOv&yH_ZZiǞW;g v=`Qt{; 9cҤ!b 4N)D#2poaMGxaD|߅G߆}qK'{x9^hYbѳ<55c/Y:o8YD C.|@?z,qGg m{Ƴ'^?[nWwGGdf+`ֱ@-'kA̯ ի:*93==z ^M n~V`݅؈X0+MIEYTmob8=ϊe@rmH%5 {3|0x{FbdF8ʎ&u{5ĉ,QS_Ppߢ€un*UjH2G>6b-FPGasD m2jf]5V{m~ւ7 c6SyB#>ޝC!ǵ藍 CH̴ظYԵ7!EU5|Nzon++ 4Un [dn- ld׶7W&G +Z+R{Ųxqݩ+Q,DɀJ7ҽdGieG(=tZSblQ#veIϊǻ/w` &ʠ,+}@VHl$8ad! C ", :)dPvzp@4uKY|LSnRACCu&bl̂jHaEG~pF:.SAMg%K$~U;l8:c}hCc 89B¹H[sZgwBvZR׶33#ve&Wzn.oV;ȏ+2oÜ٩L:{O1 !|( i4zF!xPooЁezqi;-|Pye~V @lX LXR 3áeITJܜpe1Uwl rm?hnV"|RXe,Nuӄf >]ؔNR=4G$ZΐLI*\I)q("ۨ0*,+SXP0f5]62Fz:JJ2z:0QtL^`"+,h:RgJ-ݍmC*j,[>4OnC{I3cW2`TyڹWLrR,E# ŕvI2h"0ёu_$0u_:OWc̙*"5ͩ뤈JoGяX_ ͻcZr =/=)Mb2WF "?AVȲU E*3${5-3w"]M S̥v`Yɜ.sb~c tv*j㣹llSJ~s[R}俁'G0, Y@ b7F=af; \z'.H̥5tlmf[{ C+8BK OjG`&5ׇ_~@NS^4ɤT,(rY%=iY3q[t̰;ei⃤O #wvb|@do~X Q2%yPW1i%o94EY˟ %EuCQ1WTǏ;CPTxGEulRT{â-f]UJ2yI>ىm7?Ȗ  -+Vڅ'U >l2 enp(`kM|'?Q-ޟN^IdPf0/2'PB. XEVg%ۮc;L*GZm&oScBctFESP>P?TM+|T6qgazzWkTySs+r"njgNތ.Zˇ$d Q_I𣊫kOW. sFAg|:Uc?qjpO0J"%*<>LVOOO%>'™Q٫g0; 'u>aDRu'nt!}&˿u9Lf)7?]n$*4/ZŊGs_{??8оedwc= '~M^T3D'Ei"+>X<?ka)V41{w s)ux0XVMƑd/I<Ͼ3W;,vaFۜ$MDkcK%T3HAZjUϫDg:B <^:WrNJ4zF?O^/a:KU%o#w4RV,ԛESKϲ0{];ܤ ϒ{a$14y# ϨF%x|"=)*l/87ვ´< '_9Awv4oNeR(#]Ls9*rft6Y^Gũc<ÕvINPϩ~aDpYi +'ú焐?gT/ rɧ=fv:!F"p.,2/h+@'UJX>9D)8:3.:O9^HU T/$ો[{2ZCpB/3[ib| J+\ eʀrKXH#":f*HOTHtI y6b.z1Y(猹pJ6tۑ'BUg!lIR4ɕl%CDa!3=G&\8>3f3 a C2CH&$f̂!5E20,["Y6IDϥќ0#mZaK/B)/G9ƒO}\UL(ԥMD#;U y麑!vbo߆I嘩h/;?'NGfc8V 8H;Ns{:U,% ]FV| 5Z{] n>SiGeR{]l4ʋ"mqy4(N4y~ig7>+7|r*}s_\R fx>tӆ%gF29Kpqrr*((;(䥖&Nv䖛\nY6<%3MAcru󲬜 jj\ ]e'+ֈLfk,,'4IHarɥ?HqZsqrnnHv2x>4ӆ%gF29٤f5 /x>t ӆ؈,'ǰ3OtsmB RXx>ԺiA9%6g<̘?yw0V͓cؙ'o?:6Aer0wo|skGNN,ɏ C6-f|y"Cjxk4w3ӆ+sJ'0sY,9ɕvE%!E  5'L`)4yf?378L88Q*)6y {r~i^Ij@/ \P1k d81vq~?deIQ&]]$)1e9,MɁʓ5},'X-( Ѵ|PRflƴqvV\ Z % yI@sVi)%)RRJKRJ&S嗥끸\%!/E}{~,Pkz醙&wd AAN9mI(,JM1_hmf % rxv. 7'O1+'Ln`c&ʩ9ũ%'Oa`;YΆcz\̲edJ:@ tSR26[ űOV(ូ gb''׋qm 4Cfrf9 mYKmN|&6ف{rxH ՛&8eTڣW\Z`jYrd'/fE&;pZ*h s2>&de9y䃁Y+MC`sP/&+k,CMng-̞ɎU7?LcR0z 9&g N`ζrRJFxSoTW&ͥҖd sJuSo9iM,q`GC* !qV`G`I{4 B4< I s||׮K_/_;+jѮxӨr|T$E5ZnvL-?x6պֹ;w#n((9!@p }[V^{>\ x) &.S\WZ3ٝl0M>,2Yj*6s(,.gә.RKJTqiN5B6 ܬ 춑0 n^+Ax;y) 96{31nn? 7$x;y) 96{3KJ1Cx<A,$ `\.8&/T007%>x6 M25&7Ȥe)hh(*L~. yd%D45ԒҢ<ɯe}66#'ZXxDc(!cbA#(6$!))%$+%&,+4.1wm)x{6 7 0F1nx;q \gro1=x{^ Yx s2+u8A`=\Y6d\.3@PQH#$(UGV.#87?%u2d Bʩ9ũY@ؔSR26 c&c W/O)F~x;^ Y t s2+u6?`y  $x;q^ “N^+,19Mhdaͺ"ӽ Sx;q^ “N^+,19Mhdaͺ"ܓY-&[jgVi{h*(*@B=B4'K9zhN~9c LN~I1 T^3M֋6\~R%9#hS _:cx; I4&' *srr*AA~Nfr]Fbqo~JrjNq*'@DR2&t\ ^x[q^ +&vۼIX|OS 'x[qf s7.>Yœw2PBe. pAMx[q s7.>Yœw2PB!QS&KTMN'bl``0yf}N7b䜜/nɩP\P`fə_\ZQPKNTQP\'ĊO֖b0XrɯeM&2&|Fn\ٙ&[\YQerȽ(%=].Q:^+%$dYsɚ !A>! Z sd<\Ct 'x"C\t.POYLeI\ש(?YN%"hr<"\WGD(HJJsd@n>0Wp46!'3FOʁ Q0?H[0ޮX u(3xQXZ%vL`]Q?9AM(R?4^ڼ$^ 6B! {xB :ɹ9ɕvE%: jy99'L(%>y@ςZ&ϑKtY&?֝\l8AI39158DA+%3=dG틓wMf6\/tdviρ|S%9 5''NۼN8!S&k8N*㌤좞Pٓ&JIMxi? S6+{2MΓ)T9; ,xkZw>BV.Nļ"[PU47g  /x;q| ̓ u&O2˱. -&x[>k6\/qy1d&WnDb+RL/N֓ۻYH#sOqd!\+y'T KtAHiN~YVKS)kx͸vm&=&&LrvrYVJbIBrbNN~fRҚ\i Pi[PMj.=LzJ:@ L֓&ej.›\P ѩ3^@MA8*u["*ux3qC{F@~NfrBWbyM&w9;\S8*UVV!58Uz4suV.N |LRWAK(?M#US33MAC+%$QV/GSsr*\6&ej.:9LASȊJ-:Dݼ"qrd!s~4X?HVB fN^(yU!TV `xz:ㆥ|UxMs1Un ҂I1rNPW(LԵ+/(-.)K\pjrQj5H<3MA(4DV!$88>858X+757RC.$#%$Q,%'"az8gx=wڸ?B9^toNʖ@˼cMLo{a˲l i+~pP.2iC97˳ͩO^ ϝY^pO1iC9,xܷ<,PupνEz3uYÏJV"5wvד4h1u)9c><'(= APv"=؟?#W-uiAë7uC3?xh́=[{ n1^=hѨoڭ5)#Y=#cSg޵OǨHy6im Re'`oDžAY|J.No\/./Lhcl!0M0RfМNaG|wuK%~q:^! P?r>2HeHƮH<"S@ ;EސeY"{mx_Nx#2{Ǧ=F/w|dz/NR/{sݹ2y? 02m;EfvտVό=˚~vR*={7B0d6?iΫ%DnV]X[e|~#. &'#kl`Aw>;Jj>abS51hpw|pB:<4}(V:>0n~;L>Vh;2?^ac`>@ CG\(ff.Dc!A-_+}&Tޤ25IjEk8cutu>V QjӫI4՗@.‘*lβJVcۭQq sOtUll怯R PI:8]TvՇFQX7]i2 䴃Z9v=P07vQG j g֛. _6u~N?/ yirR0e^Ȟv$b[fc9Gq3 rbo6g ܴk"a!oA\T3B0icj_*|)fhȥZɗ(wq֩'E%3U/{ڝol Fy0y>WXUY"@,${{ EN.zv>S5k61׻#rF N hMn5~3ID ^WT&UZxXG?nK<svXam}9}!ͼZEL`wÉJ2{Wѧ]r^`CeU5&PNI[햱 )^ גj[x_Vn+wJgѪ*\aaۮ z8YvkI;0;chV+&tnz0M( 0˵wVNGſ8:o戚RX7Bf3F~aIcL>#{U*5=L-rkt- cbFlY<ė]Vt2gN%1r/+Wz\S;能s\ IV91WhyšV3`:s wu4"&q;Ɍ&w!v| /2arEo{M푓Aqo ^ uܹw]qX7}1rRbQ:8^:S!H\E"Dɱ+1a~kb)^S_rFO碐W#ވⰢ飼!ñ"2^E@IlV̓XR|b8iSC%#|S#ϰ9R nߊ3}#2:a)GxG87Poǒ= 7{^=*9 9 .VWrvbL#1qEtFB<yDָV7@lK--[f37ABnc8i% n bz6ߒcgnO0P&[IRý::(fcljBIjVu_`v冗*_d ,1\Bc@-"؆l0c֣(UK=ol{Z1}nm4ڭ:Uľ .Xz;_eP]1P|]]Cq(MՒс J7XUg6YEơe+/Vm\~̹9MiBZΧ# ĆdX#2==> Y@CɂgVpеR U}ғ<~&ܙN[s:|BG'9+tvy=ER2kj kz&š k,dl6OwFPP"k9[I^ub%NW09]Nݪb3+6ʨm@PHb"d!4Yf#^5ϴN54-9aQ3$Eofy0sgk(MA|LZ!l#5"+Ѕ3M#Of)e@W'HePUf*?$!WP2Ivȫkf. f9i40ɮ%u1 Nv],3Ya2yIvgOal8B,K|diu+j?Hg~yOzu*hW)rN+'5N5-lorZ<̟HARR |y/umd=g'$+?bfg}e xbQZrx)R׈ xERT2³x)V[ q8ebaPLd. ,ߋ^7 h#@2 2SZ,*5a苞FǜjgLȫL5} j,U35{K4d/`]T=>zƚWY4怼 TOhAӮ&FCHy6m.Γ |Y6N.]C^=p>Tuyoϒ7h>G$| yPF=-x=k#-&vC0ica# ,>M;v~@6%%SWcP03 gM)5 ui?0-,SK&xתJ-EeOm;{3"YG7^X/).pi_$I`i ZUt =SY T4y5DS86aTRDo OK3pZYYR$ YМ.+Mm2 Yi5)̓+X%>ɂ0Y/Ʀfi*:uB|>b[\2F9bZ~ >Xe,TO\C@vu轁 Oy4T_ 2S]ȉ?+E2"D'Ox'OEҭj+oVo#ʀ3kHfUeo-!Z=?4g&og723oDw?\,)iw!AZ1mNBvUąrRf'8hb߀ajzdBX^3~÷##QH$/h"!v1-ag[Ndxx5jԆjǭ7l)_[3WzR__F1$D2ɿD"!zC?., k\P7 +܎{ى H)+Xou\$cCNƯ…VQE mquת^: g.ѼR\5 )9'3%"BCH;eLi-a!gC_k:׌"QhQ{Ni \kX*J@R"SE(?rbFG)gFbrm z4"a•Q=BZ+@,!41ZǨi`T B>+P j`XOjc4jX5`Q{dB9TGA([ @WGk%Pkvsg@jU}x0C? 9۵iCᨗ *Cf|5ld o #s ܜځp$Z)nSP \$v ׻RHoi"ye$ږ5ɒMKD{d.'3 6zO/oRm6aÍ}&ŭ1/#3rhLCĨClOM/ո]Ԫ>G]J1T &[=Ȫ iX0y'%Y[+% ~|R7Q/QBk4TNN$RsUzl"X_3Ofr]OؾKY@y*s-"˷=fPʶ%-idWC_^g.)xL&9 9g~fE=Xm@1>3tJ2kRGsJ;z׺2u4H+C9tP@-r`C h3Sڇ:( 7Hx6ljڎ5"NECC\cFf^D2vcDd.ѽ#kXr0BR)7p}M%Y}u-;g[>1ⅷo؛eDŽw5dơ$rs{g0An=j^ry Cyd) uͽcqh+QMM;]4y0MnDmjFM_B g:"Wsofo>ىWwx >e7/MiP3UA8"lޢ[Xx<[ӕ;;aJߘpv7c $:t5~$7pP>quNFY}A jPG\= ѽ2܊sAOT9"1%x< dAUD]$ƽW[{47\ &{ e!ZswmB a=M+ ;ͪBO_x[LbY@VR`*0ӗ1ۈk$EMK门KGѢ+ :e3/9WZB[_񝞹B$x5k}aHxqPLfZ(i/}E?31dΌ_z+SOۗziEPB ,ʒx,i,iF|5I'Ml@/Ll;sjK,S*RS%˴mBA s (aV:=H&KV'B@+YȚ}KU5co#-XN.zv>-e㷔->q HT6y;UJ'fGB@'<m䌻_C!JǸ-d?h8q"ά0ʿL7g3ϽgUL֕VL [TZYXṙ~d0r]q{&Q&R`7.i eGZB&Y1Hk2%1l^lC٦TгB\J!2xC0<]*}ؔ*dgE`Eqmj0V A_j3;[{֠O,䁐5ntietZoͩLԇK{!>hi;Fu=?^?3Bsx?y 9K 27搜3k&:S5&,|eK!IM޷(!Y|(86@xZ%“,\| ~  memset(&, 0, sizeof(TCPA_KEY_FLAGS))=n n6x4{ q-;-x[3y jL9X7!x[3y jL9X6o?x[3y k7ϸl6)_  x7$ s='cdzĘ|Az f)?"?8m[xyL[] 0_8lBR1Gq N8~M[ڐ_hWn)h q.l6U:iڪJ4Gukvݾ]~>ҵ_Pƕ=xN S{#!dpMYG,;lXK U, ؕEi#χf"I ;FQ&vn| *u6'K^4 {?b%$d5(5҃QGX(NKz S,UUi1Jct]fm"- QsT؀4nк$t]r,nVe-[Sp}L7^/Q_[ p=v.TIP C_4T&Aԕhk:<ta!Tp\xx)o(a_Z>,*v=(EP55MԀ<8$4J) #ȟ+JoB(UJ/-*%+euh>K-f#$XgO6g"Lo)OK`[Uu6hG9!;T^3T ?y(5[Z 2 ല:ogg`qlު%%Q7|c&RbTи,NB@l"U!! ݱ3Qnadwsm9\Q,=OdF.=2lsqZm:9SCUI"]pup5'>,jn>/repb%qm;i rTroxC*N8}o68ٜ;AAO=EΗ~i ^#ۨnHJpe QlG^:ĘOKJm :a˶8vmHx#Pw~YsJcu痪aY]d#^p&QM0B5Ez@>ݳB犹kRS< 8YǞZp|SK&{f)̺bwH8)D䚐8iH=7OIMPa: 7V :bَ}.bЁ6S1Ux[6j艉XI7?A 7vI[8LӸ琗gB:xTI($S8 _h@ub_ ǞBI~ 39.#eK%rMʶpKCf|@^`ܩ>Iq>bTp6;$9|*Җ*a%_?9 kwp>"\- %o7ilci6Xů7>$a Q1Mmc} enb$oÝ/"/ 5c!Gי cQmnF@JKehG5,2WN'*Lyo}V+h,s{7AFB<֟nN藌i ;?pTJN#>:#H.عL*2Hv:a_Jt?wBCjR937οR76K?;~ʏ;DS~VMY상)'&iǷ'E̼ C|'iٸ4D0U k0<+ܫܞhg:Zuk2LYN4Vo, LJNuU&M 4q HH`?~[2bO&Q \R^+/"*}. } &0֗ n,kZx0@'/ f\0=@((qp!t2kis&u}X3av t:c2K}xx⚍o< %Bg:)ʼnnŌ,➤<{hF$.4"T48;$u^*E%$lc,AV.K9`1&Vp62 ܝfށ (rB4PB:c!'331  3E!?1Fy#ZaWk 5ɝ0Bb(%27H@RLy4C?)Dt!N MŀDGŦN%\RgW僕E)ӼO VxF =uv[^s{z?بGxr3Y)O`iSGH@lCI>w1ͣ$/!lig")Lla S:UKOP$kP|g #03&'+2AuWw&+^Ahyi:Bir9>+}Ա.Qgy>/#5ACv=O[J"CYFZ<Ƌi؅83:ϔ=MLqo8!q f$taؤ@rbF0@FʑD8`po֋H·N>n_WEעwWWRҍ>u9#m}doqx3$ 'n^ٱW2 xAܒGЩL9 ߱6!*/Ѥ break; }) ka#L`x3y}|~sc|@kBAi3K2RKRsrS+J2KRKTbbrHqjIIf^B~Yũ_!1hCrQjbIf~Bpf^r* obb%E) y@W(@,)V(K)WHJRAKEeן>Yof'Y"6M Y2gW&58ٷۥpwSUv/y^.>g_|i]@ Wګ;a pu # x;_  &79yV+y'k.H.r-/,IQP|Gxr"ngs"kY`Lkx;ie sK2sRS+'rL/J,ILIr'{ro99Ylr=Ò%]ܨƒjZO>hd1#wQjJfQjrIf~H/l.#@ʐ`e~WXܔCrsx"Gģ9QzO*L*ͻyB ~N޻} fɚ52s 3KRu&_EAܳA_K!""B$">'?9[Cm nd74bLS[-xVoL[A޳KHpn°l1PAP'0\ Il?~EI[MZժV])YIJMVia͇)oۤN.;پl|0{ιsӃ_Ԭ^[-91 Jhi8 G&'Oj,hGP;\ׇ=9߼}K%N7+>%IWtQuY {zO!MB28)1nzl"p9d2+^Bx2Aq;,ϧstn1)J"@s7lZdWEIp «|LpƬsm~3ZX g+݃?e*BBT*ijX16 ,UPn6>bKڃs\uoj|ggZ4}58i=Nens|֋ Ou j>m+,Bz[f^;|,7[Xv}0h9e>g1zBB_o8[riڨTNd84A sAEסaAV$.+J.C<F`x"$| nWayLƝS(8N[0si!`wױ͌6*mg~bXо [XcݍᲷ~lkqıMN8q%g;:1l ޾h?ra:j':z:>Z5{MHdg,Y~U#\$Mʈ*ࢮΝ,U0Nҋl˒,&G"T$ W].Ks^]B:!&*@/h0;{27kOWT.^JMU MO9YIBN zR9] XH; U-eY_g=|fT_B5@e DFPp2+pah#!}d U5gl$)Wsrg_BA~NfreHeAdAYmâҜ[x\|zjI| PFFX@GA IW4ɡ3K34R \ɉũ ̸Vj,e_E A!~V}JLޯ9y-kR'֜\P8,R*M'o>h@\U'EKLh ?%'&P>ZT358KK2j (3xg\Fsw*0C|]<]C J\2SK&+ZIRT\X\R'VOԂeQqbvj]IrGb^JN50 ag^fpLz8{{8jZõ ruvDhUP $:ny9Hýkn0>C-px"P9KU{c2+ ,R mT!xw 'l`PZP\řQZ\S`().p+I(Q t vtw|٩jjnfzQbIf~&z9x('fV kTD__:jN} 5Q̅*p25x'/|7v{\(gâ˙&gLH~XSنQpbFI Ilg…Mb^\4yreX ʓ bFE13Tl봁,rE,2f{(t oc&X M6,OKM.IMEkBw*0BB\#B=\|\J'_4YPv C[[PxzɁi~ ~Π4.N-d=Tk210f"vB<%dɓjO~_<787g2t&9nVd+|-yO8YWApNӎ ۧ3i 2b\>s_ @xpӄl: FfN^\Y0YEu<Ɋ !!ޮF\@Ay| 4!E>)N9Ijiiũ%: %:  2 ZjEʼn٩v@BhljNq*MB݋ZE&+V|MټĒD|i49.Ar򉶀ME'ߝ3NJwfͳey3S@hrUO.dR\)OT i5?,./J/KՀQҊRSu2RA>..p+I(;((O(4dra}Kγhk)DDD(gT*d+d*&&+($f++ho^HVi*g)L.٬ڝ]95/%3 ݬfxpu <y%Ey9K&KN>#ٜfy2,%'+No>q2_H@V!$88>92>4UkkjNq*83s2+&3O6Ya*f n>Fi3NcQ* eB5dXv1b'M>/tBRN J,-PUps v rq*A&̞.6Y)VvrG?#Ley+by'Oc~qiz 7xƴ ɒlI٩؊B 2}SrC=B 4ҊSKtB|C]# t8A@ 4"C\4Պ R=Fz%際#&,P$rs_QdvŹ&_mWL/WHKOdT%}84*x祳[&OH( xiexie sWAKx{zI C'ılXYxy! \ &/ihVZ2PN~-iΓ;y6De̩ 40e ǣ_Ź'Gů>9?6$=Y!+~r_ >l4d}I,@ 7g0M\lS}q4B7ke=Jm,R390~daf`ؼBdǁ6,Dn~8lOdyeݮؼG Dd 5as n-ux! L& hN^`Irzn #x*7-84BQ8듪| 9P:b:fo8x;ti ['سl^criɫ6g֖aTdV on}6C4=$9Dy)9@񼼛p2N!e3S#cdLIyR[:ELh)j`oeL/Kπ\h#BZf^BPBfB.PCQBIFbBybBN~bJjBRBhd5q0rǻƻ9zLj vxiJ l\ a3,f3[|B!ޮ Z%ީ:D5'7Ln}jQZ\S`_PZVTu` M&w1{onfZN!lwV#mz:3m:QKLpڜR8 R%6/)a lf+ I7xtiC~dɓωN|UH L+朼IG,R89.I}"$&3rM֗\_,99%%p,1 h 0(uť}A02^M[kqd ̚\YD'0/J-)-S(J-.)sLEl[)8ٟ}r_5 1U@O6ykA6<_[RxtiM iifZQqbvjf.Y *x4 &ȪO~}S81=UVa^,$Y&w*'|WxfR l9y% e%&:^19QTs磶&qxG S&O+cVҟl$YqR+fv -x; ^/OecgT!>P#nx{ ~N.A!An Zx{ <̙i ܃⃃589bEť9% ))ީy)9!ޮ~. : ZIY%`kY,&ױHOfgRL+JM(*NNԴYZRZ1$R "ơ4لOpBܓsINVfqHmItl:yBͪ5#&N~9yi|ɾo<@ނS_?758DC 3/-%$1:?- (``dr>DLA(byKZv<[xq y75IPM-N-(H.rOQ0Q(άJO ijN6u¼]'s[MEAKhk29"nnxq y7-;Ixq{ u<{x7{rfa)xc u<{x7{.k8wvw'7I1Ov %3Vd}]f@10e|@1Uf7W]!`x{q# “9Lf # w /xZ[oJ~EO6k,gd`l#6O Yߪn8Ռf@S]UWMa ԋL-FCr#rDh!)ȡ( 8!  D~ڔYvo,e&]D?x펑Sxs|rE9"H{#x)G֮z;/9~WBb[xt̢Ird<njVm+V0ځEom7luw&twd%M`eL.d HY:\k6R3CA@AŇ0dߨ͸6H$Q mu}{aD"oK*lȀ8#kML~88 Pǚhc9.]?d5|R7Z5rNBRc? 2va,؄ ^D1*t2G碏$ ˓3QF dM7`y惀e3 %H$;6)Wϝt9#'oe\'b,ԙߍJ8nD2HkNKsy(rb>8*mP^y(K,/!h|)kK53$K}цZEA~RYyѫ-"U`gT#COz23~`R:mH4Z#r Ϊ/f"b<ӈn쳬M'y6TG)EwdPPmE`$fHLBjݞ1o x66dž1`lK-z[;hH".Y/ ˶V8 B?<~*Ou,{9_Lpw߃ϊ>ⰢsUX6*,wD}w:UR뼞|%!iyKF|eR^t( .?5 i{m&|:Fœ9}B,PN(K%NDb "%.3S.æJ"sG"7C(q0NJ/;?K4Z&K * 7A-(j+vRR& KB ^*߂ { _*!=#lƯͻ5!hoŰ% S';pDWFfGC饲LYTD\;^ߥd^zL.?r'UϷRwAƬ`ivȥ2Gr k˱玌!i1&-&7}* ̯W^7eI򄧁F= xX3$_A/ 5UMD8RԧoYp<;7XlJHC2I\dgE2#Vĸ&vD HFMm>@C>۹m6W]wtx1vC6뵢XO xAS3(51{&|_:'Hl^|/;xKfrrIB>Tix;4f܍Y'r oaڠ[ x;y܍Y'r oa,"~q.x;v܉dg敤%LvgL\-Yi3dcގɼx' qM 2ٞ$.U\`PRkWMݜ}eAZ,=e%Etx{edCLB1@Lgxa`CO%kx[`m6f.F1)8 x[`vt=!f $]}]C\4''pL1y$ax6b2&hm. +Six[`vt|f\.NؼydaNI֪\i řUia. PPOc# $X=}4''pL1y h}bbS<%5 >gVLN)srtp ru q BQ;9ImɿC'l&hm. Le ,xfzt|f\+p(g奤)O. |=isnߪ)nC=ӛ|+^m]\$N6zAeg-cg Cww֟vEOz+Ѻ xrʗ*ar^EQ_02m>g4^1lcڣtM#wmedm1 fx7lkg_=;i-[Q]GuW'>W"FƉa0W= G4MSvQ@y&V YfY_ӟ:(0D rΜB`Х60I0Ps_`\8/Bƿ 2#Nh:g򀇆N54}VpRܗ<@%9@볳: 17z/[z?7|K&857H vWǏWcs <=X/'c6*EDBoJ>'*tZ{ ߮Zvu~>%gG D\B%j ~jFos/ gWvf2Ph ɼFSS/bRgӡm ؼg:_gcDr8hhݡ6P!׉?۟M;ll]lkcğ} xP~~`yot9>mI J)(/kF M`M~d'-!ĥ3wpo'(c_>B,Y$^kfσ:WBp' K 1"H(Eվ883Mҁ/ Ba87Pw93*B/4x)H4l֛(Sh]5"4E݂>~(g?X LZ-磙4hX"mTG 8|`:]ZL 2jYRHSIc B2C !˕+)UAB+ [0 in]2`2O . sN,?^s_:Ay %ГW߰e+uG9qfUh~qCѮ3?$(3Օ WUR%Az5atS4IST45&]0%@z^Gd@ +\Eث3j`j& % 2X+ ]ua ұU2T9;g&a'שh Ր ҁ#>Gq}EuX~YYSɃx8SZW(Y*{b @ʎr(a{ A#a{BjSn;Zu22[#Z'; C m:t봺gރeD/%S KE,THMEJ,=ᛴ"7T^&T@YA¾#ۏ, 徐n.$]girDElSN '|NK:~485ggLK-HJiq5b\9,}(R| XM+3/Dh21p 2jdEre+xkٛhXZbpcURDXjn;)q,s|,bhVCi ئ̀Eڽ#Th$ B<1k'ہq 0YZ]%cV`D//Xt)@]8I ±e"+AB3L Xr(𺈴5D)A0}zPKђBTk}0..'+uv.ОjrN+Fd+rLr=CY^ cz╢p3ufҘ-ᄁ}*(TPsE8OO~0jHl2N~5ڰE|t[$2"%J/l>E_>4N1:?c\ExS9zX z6EgqPZŘW0?{7߆P>MƞZbR1HH[XS^][E/L{:;*$JU%G6f# %2p4'*7=кu}:1Q) q)4D2Z'! / G)1@c#[iSS+7rw.RA!bA$v!o;|; $PEM;5ZqG[d%̷T )d4?6ײ뻓;mĦ߅cD{`'RY !mܰ{dȤG3ك&tH\>Q kkC# ]A|pI>GXx'kp4FF0E* z(٤' TUPGME:cUbj!U# qiD [O.h94gܶB FB"5F2d/|~ND9D5TgD@Yg!UQ E>h1h*iu*NE|`;FZ @OP!͢L4M#"8K͢g./m^29imĿ:$툤CLo _L?n\rN"+q59L9.c( z-9Lde\Z)'P17 U+-nh^%8Q'/&q*<|jWyO/wqz6)qRA^ }Y5.̕7צ} , %"ҙQ՝ehgNJ>}#+xZ'U?pxM-!ۺy,[+lc4-Vb\8-QT?Ŵ ʐ YUxsTwȝy5ۢcG9};;JkM9Mб`HDp^)Pddf`G&3w_08 r7. Џfف.QIQ[_0}߼TđNêPbjC|KEQT4.LX=4RRQG;ORi Bhw=2 [CG]C)TJ ˉd4yE^u{*-:Sς7WUQM8WnJ23DFJ0 |; !S6O#%~#1bOgvgҋ]5sClݵ$2"撡yp`)xwʒmngąr;)qzrzyfR#̅Q[Fs>EQ 2VedmQaKdkFE⯧5\Tznef^ŧh2*E&YLV0tT 7UZwaAj3ByjT1~ˆJPj{Y,5MjGNI)CrPfblVϹ4r,gq =UõƐ)+"اumqJg9WbS(깠UkVD-[Q;U]oR3Upڑ.RYj"O'x{_ ' m` ^ЃsrBL?9sD'ۜ/^ }ix{ poNhZIx{; eW20n`ie\1Y0188%)-3UGAiI~EMk.4d[[T5y~'%*d&U(xo8 .L\.8VHsrB9/32rM m#8B\isCj&U|߄9["ܓOM4,g6ޔs~cII0Xl0i Yd=@,:cdkWd&(Lfl.t  LTa2oq(Hޒl/D-#D^ x;q_ ?C}\]\<\]43RR2@ҔTԼ< ;.ԜTRA~QIbRNjgbn5x;q# J*UTB 2CrSr6/KOtfl?YN}}#N5.-Xx[C ;9'pRMM.PԵ+H-*,.I+ ./JLO ,H H, L*l9Y%jW^.F]^S7O 7x[qq .7xslN:,v) -[x[q 9%E)Z@%% ũE9 !A.!~!>QA88DPuhM.z&*Q~KʎWbrvU|-et+$ͯE ҊSKt6GUL]ؔSR2&O. 16R*άJٜi8y9/Дb` ->Yېpcd[2)dM!1y;||St '| (lv?8Y6PEd \_@vSwoxB$64 offset; UINT16$64]A AGECOH; n@xq ! N1y1xVn6}[mīF{n_Yl6(Pto )Y|1 K9 i_l2 Ӣ y$,*rI^R!7d|8J- R) FHP(~8#xld\E$/ܭ+VЪRW䗏ïm>gEJ~dƴ17 V,Ϛ_˪ZrSҾ*34m+^I-2j4ؕ%ApdLж=> Iǵ-,T;婳uR ^w &| s OH9XF7[ʵ(H\{=~C̫m[qy=n?<گ(JДطK-+ \h:յiVц[ # B/֒!qz\.7"aO6l! Afa8`8+P oB;b2 2(KGlIQGv h5?T#iQԅW/o}/opQEkd*( pjN{T|>ݳ!D`'2yer 5E7PSu DIRe6@8yA( q/ o%q[MJ 0i|2GP!102ZhSU"ضIœ>M2SP.X@ٯ"A.:ܟ? ts[H}vKz%36~TUhZoNרNhP I$३@0?_?;ȼ}vl@2zd(͝r؎vp~2&Im\Mv 6ډςBA#y) 74J6$~zć36kc Asꍂlߎ'g}ՇK.eM}ãG!>wenc6{f rr(}~=6Hez##}ZtK߈14A--(ŲP Od;+(`/|H˩6`CDeSϾ|]NtcYRD]zq/&eǯ;q.0F* x,{VzCVn\ @0yg٢&? rqqNcSpPԼJ]ⒼT[Ӛ M$ r߲N㰞ʡArLɧ8dA6qAl9(,Ox;+CzCx`YD7cŸy=' r'x!_zC#kbIf0$>Dx`q1{ host_table_init(); #if 0C0#endif TSS_RESULT 6 W nx$@rN&;"҄ %x[ @rCrfZJjBcg0rAQbznBf^fF<*LQ5@LM.ԜLFlʩy)i2hո)x]msGrL]%Q<\%UI|UY@@ F .d鞙陝6A_ OםSQlt.2ͳdU?|MQmn%ȡhovE@w@b._j^M7Ii,>"zg>}khbf]ӢHۯԷ|sL%_>[/Ve(?l@?s',f^>n+|Wf(f[Qr]EQne773_l`>l:Otr՛|ƣY:zĹꫯN 7ww.$O]VU2x2xRc PY_up`Czupu݃<-v:3Moa_8vwRas=t]揪k|P'_wT\ԏj*vdL]MZT*OJ?&W}V詅n$U^PUqcpIwvvvzBZ'1+.DI*Q7Gه|ֻ⦃;;B]gWtм$zsrO9?j`4ZZwM|^FWz@̶ѤKoD4a? H''6j>#ًB|]jwր(=w`r>x .@;[k 550Lw}LXntLVQiW@)?xM|Пa(MmjC h]®} 'ex1sT/Jh%}|խfg%rtC/C{0ǰMɑjs1%\Q-1s#;GK/=X¾l/ \{9LE{o[5&7j~gzݷIA~8+GTs쩘>M󏢏̬f'9q{d8t1ˀ8O\vAx-(>S+Y5h$ZnSWS-ءm$EzP;r-cEK҂ -ԥbHszuKF茬(f*d(u+XWT2DѪbA=QPFJ!}v %t `SF&[ۭ\>>__n9VXN.O]HlɆ _]0k9"ոQ$!\kVZpzEtSd^(CPA2sv=υY82CZyloqmP.Φ,60t`)0)c r'HYdm^-ںc}|MݲBzDL4QP4SlkOh >yyL)!d >$9*5@`PNR#%H{^_SL= a-m^Ra!8zpY70"j@ R ){<=:K<>x@:H`EjgpB|a rXga64(a-TcPP 0*6%ECJ02Z+W=GG{>Y5Fć{8m [c] #pX:eS22~O+㾤RϪyF ZLkysPM\۪CF+ " Kiz*?3SZo$ `U6/w: T+ efX1~A-f!o d˘03'UM* QҪ L`N%,ӃwLB@nKhkR;s8kN a{q!v=Q+W I?xӗpE[H_tk32(.Y*@`_-.mDAD0sL-d P ś .aopdz 4؛D{Ǔb#8I4<#ZKaG5ԕsu%XQެXTD svŰ4"[7P=ٖY2tiw8*U9$Ht̓ۖ!cZ<[q& &!%زBz^ S>·p fv,Kl#W_ or6p9JfYxN,ڣe~`nbRmԬ LP|P:fdmG'@z#VD(:x>I3V[t\vqϞ;bvaE6޸;fJ Om4. Gjmw7hWZB\qxpJ=;BE.t4?V ע7GJ?w?nF\6mxsBF#Yk`vd64uu%TD[w@{鉅'lĝ[1?ə;Մ2\eQ[ǯ@*gU,]<%>Q{.r2D IX mcBokf+N)h*fvdwib=}(g/aZGHwʎ3?iԄ^Db9:@:&K_7p4=`c!z9~ҝe_=Mechr0yPqZzPVkoeVZ5GP(lH'dAbדb;&et|F {J1K|1g*DVxK݆nH,**-XzIR%?aD5/ tf-kpyuvH ^ eY™~m=rM^B5ڨKERwNl699aS(p56yN{H o65Tm%R4V^@r;q:>ZQL {zaýsJJ7ivnp)A7L܆}fdS4R6^tRB aspX(D$e` Eັwl%}-*/XiO[_'P/y,bKx'L&L}m bxp!ãO%.9 DuZ&)#Q`(uʸL7b< lluZzH{}=^Iɶ Ï9ڬ88̏rFloM}L W eUF%8!y$U*/;a'noLJ,Vz X ):>u5`Uh]0sRݾY}qPlI}O/kt0E'Ց=vx'mA%M$~K,a(2TV=d:{{ƛ]kA۩Z;r2"?G@U[zŲf K;C*6,a[k l [^`7id=6^X5U]?GM]U0ǫ$k TsY%tN74A+ݤNɉUa?x?Z/YomhHiE_c{h~p 'x&֪+yY݊&p.،Mhj(—W5Dpqt &7V㘮Q#lhȊfjPs4f{Ar7I~q2j \ѹGǕ fzkXI0utU u1%}դc#-*'`<"LOrC ժ "G^FB1=g҂j$" #Mh^qv')\U$vЈѢطBIiUx-۔A4/wzA;vI 3E6kFE\D _{ yW;_dЁgعn=v6v´#QH͡i7wHꌭqcq۔?!#L$.ye0@̭sʰ;}'R"pvO߮Hސ yuXP[I.U!tFN铪POSЍRذ{-` v8 v)@ܨƋC]Z (wyS6=Au=-07]OCk-YB#/Kl u!݊0QA#\ 5ٿy(pk!Z ݳAN+inWO&/6Y):!tAoaТH#IZd=k '|N7>0I6Dqa&70zݟLFRN> P_Cu\"#k@ 0;KE3(p RZQѢРrya9Wf]=[ Κ=$H CPN?S8IG}#,<&y{W;_ z]Ûep`\]B8"Anգj[hklfHw7B1D􌁆4#25iHJ8p?~s.b=;CfB[{_Kjb楄S&jI$>σV IT*qË7J ~N2I4h1" 9Ƌ>!{Kl)d`8_fd&QOnTayɃsOijv*|F2fە/2둳-xw<\ZsEåi=G ay}`y}ċ ?yuݭ%y iE\pWp2IawܺYD=Yb3coK? @d|a? m8P20d#P|8;1IP"`kS[7c?,|-ƺ P=x4=<9`bqRH[o1RyzgcU-\tu1:A;&q1#~lF[lQ % 979$| ڦsﯷ) B0ZaXŘd0&@hRh1 #!(0n_:vا$<(.ddž 2˓XB(d⽭0Gv m8jga_eO <=n+HBz8< h A6m Erqo6=S4' XF;x%F|%4r7 qB(~~ '$" 9ԥ."mtn4^Н b 7({*Pd)'f XH"!}U ϟ^|eb1 Շ Z&eJxd96+aEm9:ӖP+ő:Pv̟[#Wsk `3@PKq@9uR\ '62a>lj: N_+]Y T=` =?W(E`ĿC^khnPr`,&/O57htOa2-Ju)9.svl o=xE~.`0p8O,˓Aein n_)/gA Swz-v`2ޭ(3yPpW׽^:,57xҔXģ3#\uv47-xN#~Ei1me8sdRNu Mb2PBQgc-\xy Iwpm H2BMr0'ol8 0rh!kpg\G)2-"QtkDXp!2M"zhN96Ԛ^$,QA ydSr@Z?GX@7hMf 2sU.9 P8Q3p^b d.oX0$WLz6%<@,fLK@bݛN:/@kC lW>y [YiSo/n%7>m'2YfFG+gw 3x' Ucٛe {-"n2Z\eM&a6&^gGYY+٘ąJaAM|c 茆0*z~}%y~@/xbǯD3W`h!?(ԃ4( uV}uS<~(|0.D#Ky3!DV*]ڸLT Ip,`qAh;UT\ge= L hyy& 7Fz]}g8|!Ag1'Œoދ.->B}R#"\."0~Y@;5v5w.2A%̱ZS @@!`)D clppU@ &k?V )>^&UM'`a>pՇ跄33H-F˂.3Udi4օf{E<2}䝽@BîIt)7Z_o2(]>WaXNXnQSNoOT*Q?y|6/+.aiw~QI6]kTv:D&ԠB`Ts^Uw7nOO3av:Ŗ"Y6F(SYYj9 0)NIUÓ 3U=TrC;|Yl}+(uKry#ͣ70`ikB6?`!+OqCVVU@?2ʦτB#׳#|x1l K 2'fJ炲SR&doa^Hs1x]{LSws VVaSt6Lb"ߛ0 L ^FXp)p?N AYrěDPB@ХET\Υ=|ێRuqڼu5YFQ//f%5a|q#6a|Xxϊny;n6yuSanYFt2uhFO_$1ŇisHuI .UfL;mMIArl[3R`ZsI%қA28QJ4nY3ܷ4nOsn=Ndu1es 5-/Aѵv4lSI:!:KnAQJnhzXV{zJ)bJJ癲9bÝsV%gjE,fYWKXStjzcRKkfzXin-Jnsjr%ֈYK דq]s5a_ϱ )ov!M߸iIͻ.6yFd4٣1A̺A_ra}_+<0n9GB:wˏÊU2Wώ>2?.T8>Ef}~[,<-}U3E,HG3?c _rxj`! 7.UHրUl ]$/ p_C;%K]gha+V^֋+W@b'`F"!S1< >KxϺSkrUS]RsKK2t'*2Jnwf_&6909FOU_0dQQr.vLqkbxgڰ1]kwxgڰqF xg=ɺa}Ʌ R6 M6:9Wcy}'7o1Y@~r5@ ʼ+ &khN;o9k&6@0ԐVp qUR((JOLI+,tK8qLcK TQB&TciIObRjN|@QfGbq'(;R Eٓ=P,e"=D{&!2siMJsxY TTG>@/4{7{CMCw 7 fQtiLLčHf0f͛Dg4.Lbx49ԉd4nQ21F09g{NSݪu֭{[]OT3VY[RS_d%tO*HᵂL'NiGi$>FDo7;YL@ {)td|!kRBKZm *w}4+FQ.:*1 r~d)* jd\]\`:atM_EFDvq8dȨVwEƗafR!3]5nƈ@~3.f\8}N 0d.(33:%V uB"Im@J?aEsDy懙Re93J'DŬ.QɸA;&q57`aU<}>-!ODNGT4 ^I ?OLf; :*ut2Z tvw X rJ%rjyq ׉$c.ʠMVnH(P"SMlT_i8&nVkC! XC2Ґ&ңypӃS1{~ P/jo~aiʼn$/jmDǝ̈^4)4F&W9b)- r`/ 4"5nsZ*9dIIL[r3K:+',! ຳBFu>2S?fѣ1zt-bsTyt2#Nq%9usḤkVI~< q|VDCP\w"HTł$l-H')_$&Sc遍B5iJ@ɸ\t{^`2q([0^.|GGeMqI0ϑ`y2,QEFr<~Qa2lvDC E!"$7rBjrnGSӂEt(,ՖTO()Q;U5[n2:"OCPMבE'FHk8q~r;Hv8lQ~~ȭ l]N%hP)-S2__)m‘hu[+Fܯhsrܬŋb^|C|yZ=ttnPI $6eFcl{k` 7n4jXr\skIAQXq_Gah"nUjorq¾I)ͷv>jWF~U+s镲Eǽ/m19U8fAF*梟 ^ehFp|BB@m4Ce D# u /)jSb3}^wߐk+VWEwF7̈{ 6;KBH8vC.[+n~NlZ,He;LOQ %jAN/-Qu.C/\iZ\N_ma7bj?JoDxvMyxӂ0uB#5hl7}pƗm7h D!)l 9ʏ6n@pנ~q:gb&CdʗbQ*fI"iLG4~˸ơoY&/32ȬѦ(4$rSQ2-~-[E#Æ+Mgˈw0.*Z@ڔ:ѥmv)حYDqlE6%fa67.G/Œa|`pk|| ܙځqNnKE_:Y*3G3wpjM"Ȁ;>F~Wξ-^-xcF7Ǧ\*O,R['d`֖qsK}iζmDbv~ y'+O,Q1 5"esmZ%"Nz7m=3Sw$vKd6p7Cn)vY$ݓ!bޓk{aҤg{*$?|D>}u0cs$.z~-(ES4XuXqXҦc9CUb؂WwX3̃>>"2׶$S$k8"j='k' <N#OfÈrwt㥏96(?:eƝS;EDԝxiWN'q!xӬ6)5QOh]x]X@fF)(#-[)kƉSi|a8<9's$KR/Zz%rb᯴ CLv2c Ig'AvNr"&Z)0lS_CWy/V9q=X?׉Xv .ǭyWH}37I"z1OE vрka)y)S6x).-H &J÷Q|9e (PIKoD+ +> Q|/szZ46*n$^RFk{(yh_ߙ0L $C+nälI1-pV ޺wnbH BѺu<*of!;fV_k8v#d{IP{[Cv޼#d|+Gފ(}|n~g ^QxWwcqB>Wn ^4U"CZq/~iU:y?Coo܏}OُC 4H^ $#lg܋u*"_/#1$Qpw*4YCȇV1f`?/D{. ; #l JZv(~!C'5;ANԻ!a4ݣϤ$ Pݢ bd$-ymBF~'#i+ rEPt:yaxQ(PZfGGhJ)إJk@I{T~Ħ γ'ښ)K&P@d,"ZS;VKln5m{+l?e?F'Q"ȟ(.@ )/H.Imuo` Sg8Dbet#lNux4lWIey CVT N1~&t2.!$GQ7wWe%R ݌nm7g\aWl|NNѐxYC>^ [¨WE V0Ҫ-4[L}nmfF!I@|Nv؝pz|FGH7ut}UD@l$1Fq8pt"mԱ#Y6=-}Q$%)lH,ѳ9ʏ&)P %DZMT^Phjk*js1$"P7_zOǰAZ""` 25'*+(n4@wG'Hz(⏗Ԟg}H*,1@ -Z 1**}i!.b4AAiH0UWZ<)zCeԀN;:LHbk LݾX|DnF93c ~ےQfvi{(k\x;z.Kz!F#rx;z.ˆ:U̓E7{| x%xʺ.ˆ:U̓E7{M|gDNf&NvL}]b />?$* \R&[xN.Mq iLSQir@jsLD2Xcd½9 הY`շ13ZX3o_ xWnk(8:'u'g-. ( ,θNh$dQףN[_x[{e] ;36pbaԚ_ 14#f\Sf/0*mcc1g 03ŦWK3Lf c~Aќbv&kzW 3 ld" %UnUx[{U E)}38NnxtY KM7T:n7xe o^T ;mxte\-(1xteL s7.޹Y~τ F.a Pxtm s'.n).Ȍ+I-K̙lĘ>yͅL@MM[[Pgg`ט5XSsS&۰orUl}œ&Msr!ɻ  bF`5Í'/dm%\WRT  }M'WhL^d> Ѐ&d'Yn56|;;om \%M2xu}PgC^4Fɉ$ q,coha674vP3&쯬W.UTZg]h4tъ1.4"GafI.}LئFV%/9Vڥ5el Aw*T0=({^1jg}rIZ&U|C \g'PQcZqmFp(_$AFmv-LmS}|dw{8Uhk"ŸPXĉe82YG !]"r,}RМP8TJlϼC=,YDbڂű֤>W=@sFpگxcnb$eCq]  Ap{ a;oi5v>;e&p? ϛcx'TECݹlch4KC%\YpM \cq4%΂N]Yդq%K~zv),]zI>Mx@7 *;%\z^V_nmQ$m?Te-=OHH-+SFXTUU>W+ֶokpb9)F^SUGaW0a  f7,NXiWQ1׮ [`06^ajQ\^!_jխlayzP݅‰7)n;4O*Cfj/fM~_t}= D4m.KtK/]kV?e>|dD N݈T,j2U:CN3u5+7aE;X(,a#~jҒ/mݭ_FB懷~<8n 1 C/&VݛFz;=j?o1-bqosz(hoOohpVBpqYue%RH\١,P /vD7vtF#8 Bjл? o64፾krLAp@&ִ[pjb7@\^CM^). ) H8 2o `c2;/lT0c_U1~.KZW}SGZ˗=rD~=;z 0x"x0m:q,LӕxiO~c|w{M$ǀ| t&J.\20_ oPɷOi|:Vt7SfdN֑ "g1E9q{ 3?7g6OS HddH3.v.}:)F'|zlƄH;CvVX}6Y>XE <"O|[GΗSK-|~OGhM_̪ t%P:vBds#yxeX9W fM9N&27Cnnfx9 қo>x3ckx;9e{?K/xQɔ$@internal@#ifdef TSS_BUILD_AUDIT92$; #endif oDn_xkaʲ_̙s1Eix󆊟+/nx;|e F8?nx;|U &fU,o6Uix|yn 9n.x|f FMr5Iix;r O/ni-x;m?Zn@x;}7 3>x{5y 7'?UlcyR3]x{5~f..̒  'l+((JML--IOP(ѵ1572NaSƥ4]l*_=gWq379F0Ðg&'!<.&d.ABŧD^@ߊM+m+ "2Off53Q]i_.UcCSc:#GӞ(5Hga1[tmNµC+DzKD4ߛo/h CyC nkB0NAysIԔH'"T6Ī0eg Ruz_܇hgX=Ox,]hl D"@L5!; eCtNՠ"c)3LfthaDta''\`= ,N̻qYHZZqȲƊbFVVKkեFbg:W6fcsezۿE&7햘\Ggҝ=%% lV9hp1(d&ܼO'|>\&7x4߆|//#include "objx{ z/}~VD&D6s x][sF~&X)+$-Q!T%StVJrX X -ow&9='Zt~Ъ0€]zyF$c&Mfa/X2bo/vd)v8YS?do/ Y/bHddHqc`{yބgQfp z6{uxz8b2BfGY'Ƴ0M~i-,?yy8s)?bμl)uE!IT~d2i$F9 T?8Pwr?D\y#f<8$o7ZłYe`7g!ݮя}o #%*9M{8NBW? 7'ҙ?L*^DA=˽l3' ̎ͼt -8o^;hiSc,'d8O6 Y>#8QyzAMi]$2=vG%<QE?^1F#вvd AlF :-QF_CwzgaHߜ/ VWj]iU}# @zR'Тߝ_yZ+ pЖc]X @MHwp ikdQYC  acES<' [ DRVy49fs;TWmjNv\P/q-&'d{>?ӫ"^mba}cKDaqu}Yա 攏,O$õX7ŇhfAtfZN ^jmb\Rߝ9W8=-^u Ֆ;k^D];gn4Njӳ߻W2[KY6yӹtٽrCX kZ+țOr1n&ic%0ǟ!~_mivшM|8- ЅWxt}~G.N둗! 2ȭO=HWX L8SE|u8 GZl S=fpMGx>™f 0jhrUTP&j,!6'$j _/rr.*t|4 y#wrULu;]} }ope{^T:/e7KIVTι''+UK^Y-Y+ϭy{9slϭ8WpՎ\-jV[. 0^_rBpK;1zGL7f*t;XʁK8F *U&xA w<:`Ű5;c}$ tQGuUnz_8R!?,"grJ8XNkvE=QǑO <`Efm m1r&|$*\>͡CC|'#<(RL6IVmG߷{  h1v .<9?+70Kn5ް7&4Z+>~TBUY]pHپq`٢O fһvw,"#sưY usg {YȈ4,VZ]\]š^8# '4 &k)bBB)282OAgeR#=Z\rgjP(y8| ĄI?栈?%x]tAurE9e[griPCm Ps#O\ >k}\03i|Qn] ۛ5=NĨd mQYR5fa̬-VFA ኁ6-RX7 lTN(qP4#*"S!ц%fV7/~X/0lڈXQd䰣arA-K7VGXmSű<0*ʰhUAvQ14_TWdE 6ub߿gW(cC+!V<n#X&(c LdIJ_3[{ @8@BcYJCmOg < \PGn~2xF¢zI%L-Bix`Yc=: TlYy 4HeL 8e RJ\_>Bx/\*c on0!]v,Bg}7yo!ťjX/f}u,-FB&]1-[7^i'_=P9ѩ̜.3-bKYi͵?:sԘGWD?<[GE任|sD8EL d@kR YP*chU 10+ ;p`<{ʆC 0. 8J O0Lmc&)lDjVnq8BrI!҂'!T%Ӻ5n*4B­B<d~3P(I r =& +V"yln[֧6oK/hR Vۘ i03ِVYb`EN_4jdQ EpK⠿/4R\CABJ_)2~ u-NU] ~np1/4Q=DNS{S`|̺&GЬE mTCӸ3/3R[=! >X`7c2 4\0ك4㡣P: XP #,a& $e-&]DCˈuKaB^#HCL4 z_HkTCz^ILeZE [P$w *]M2).3,`aI$Zto(I'@'YGm \49hHuIaW\ I'kWt%kӆ?1 $^2?f ܄-$ 4;<1)p2urEx,Qf @\}HVqX5?jFatZs=Nc,& ) `HbYi ՄƘGTj6}|C#XY BA&i~HPmʃb[rK (B`[„A;9,?(S>tNaTCf)dlkdn!x'GLX9ʤmۃit@REϓyFаezXr4]TH2{CGo8 N_l,"&ۦ$ZYScd)U|&-D"0+'E<­1{%{09~OÐ$p6G 3jNGely KU%~Ba:> 6vnw=gJpS@-%U .)n&hgMwzM_YkvX0*l x]](b/y~_@%$U&~';mgo;ISVSp)4 ^Dj"& +y\?*AnI !-kxuUoTWҬڭK3uiɜi봆$G q̱tä @IA $$/ aq|4JH9|~s/qoau`\3JzLIбkS5XJ{n25 G|Q"sO9kk<'c0 oSpJ"|#L1]rj 8 _dIҸÃF p 9)_LEN-&ӅY 6;:7+-G'OL:!Jf]\xu 3ox"%qYBȿ/h*",M\8zpSV0b:2\4#1 a〗WҵdB4 8c<F[*'Wwpn_"w'KCn恄JAJ&; $)L>ڈtlXզ|HrYf]z"32+eIuL $Ex.SA6^K[;X-zEь =26Lۙ'/A\#afI)wl&n?-/\"b7)^)ih0}&X(Dl{Z$v!B `nBl"i-u5PhnNӭ*UMՀ|Qܐ=^f%p4NYi׍vLlc`u?pnXe4'k@2c:@RBi7Wp7E+MYS|8ˋVQv% ?L_MvbTw.6lDբ O?f0Wxuo`Ӣi /a12ɦ Yʯ0c&hhD3ƃGIzЛGofx28p=}|y[ .iXǧ/uE3 \rlIʔk$AbV^ojzU(`tE!s;08|[#(NS|6EI/ Xnjx_EKu䮩I%p1l"Ǚl#- Y!͟x5ٌlTM.f@0K0p$#JRowTk N8BnȆiknZ^,ZػfwAnHޖp+Clh7+Fݓ$=orû'8N{=@ 'WyO|'%7YOFeX8HZcr*gq N~"]% ) &[:7G{kG/=1NO -?ohD] x%E(B7YR x3?]'7/ Xx+R!Eqdz7]Ŷt!wf\QV–I^#`ct8jHCg` jXR9A,_Fc*ھ`{5PKԦ7G!kf̈́TrPi{=9Ŷu\4a &vmWt^Fa\͗0@uNU-M^[]KN`iP.SU!  v]{`]@Գ֞(@`:^Ze'q(X}Dto9tN_ױ>8̰+1¤rKOpH$rQIJ2f|jvfS5{WK̜Rpn1T=>ѓ6:[ yXJV_ӊl]hzw# 0FcN?*|'k5DW-w?{zyUB[$Tsai_*#رܮ`,MYkKOme99@e?'Vkޡ]2ƕGK'@A6س _cKzjq-4mO|2-ų*֪fi 'Atp}B8=%بK`6uf ڴ N*D|7A"’T:nEGP ु0:zJBDMj:LM56*͸@!t?\h`;GskL,aȥU#VS$=uڴFapmŘ[K30%'nqa9a "F0F^Ĝ31Vb\vGWNדn>'<'p_ڌ3pO%(ge7c~him :4mcM r3{aji]bwv)X*Zp7CNCh]:3Y-,kj Yڬ=ߎ$!ҋy90l\?Tb*)< |hyo(FUY )xq}Ą6GJfNX`WrX] XxqiF`ĜԼPOC3HXkAQɊ,!30rnbbY,6ױ6of]2rR'7n`/ ef/K- N-K}>5F,11CY.4ْ).7xC&6cTl,b >SlY7 ͍'恈hɘNQ #?y#2JX4&-Qd#k9DVg|YɻgcY[ P.:W9Kf͓:lk xVKoQd ̔P0 ҇5i3iFhbҘ 4R4>Z&]tF{4&ML\@Tk wι;nN>VliT'E> '`\ -! 'Ҽ'#<sÖ́|~&5CQh6L9aI ΄Ʈ1 7E7eQxLtʄˆ̔@X׹ &/\șZaISP2g)xq3 x;jBFoNyL}*x;jBFdg敤%lvcߜ,) /Yx;4nBFdg敤%lvc`Tqw qpsqUp(RSҟɴtD~& hL>4y%qϱljvq9vZ','1Cd+NC>9NbO>ɉ~c2;:Nb ˭dP3Z}yZL0a6,7 0zBѢ21D"X;,P&"^L1Uţa 2ebT#h_,ێ|l<\#Txv~C/Zʜ @P\XʩT,/9ms&FF R5: %H lb2YF1w9nNƩoY| eOee'(MrJ!jp-䉼/CIm,v 7Η,L@K"C\RK=t8`2c* $#%Cװ%/H!P$)#tȋ@ RRx$|OpdyF^ۘ'0M`zeWiřYXQk`i eN6aa $O.`1JR+Jt tfLc *̉,|UEDk:/\DSs"lϱ:Ho?*.$+Cssr5&gqRTC2X3(55 S,5ٓG((O(4Ě g?x$'53D!srsff^fKbIZFI]r~n5'RW:ل!6Y5`2;0H c%VulpMM.ɊO>ǦÏjlU\gMfo@nnƈ,m'XZRZPZ\SbU=Mx'@hCgQjqiN"U4 BHpp|pkpdv]ԜT.N H+JM*L״朼C#Vx[ &advLr4x)Air'KRuJ'볘؛SYn1fx9>AY;x)EpdyF^ۘ70}ek_x)UpdyF^6?oxZm8L~U+,RZ)]S_C9N[~ysB끴+pfό h9p:.`xw}FR]@]b@J@sM'(T7,u$l Z,)Z )–n;Atl,omps}{ȸ2Lwoh^~J!"ZtNx"2:N{y}~?چg4"33l>E&(@ċ;SfH g}#?64FKm  (XV&=U$(kMՙ\W5AsIaKH$NBfѥV VRz*Dt;=} MmDWI|Н<פ;P0ɏpݵXAݓ*G}װ l|Iإ|7 bPvW&P,$?ވwȚ@-g4P*\f8p8$}Fe+:c%S !aˣ-ek$Xjq:פB Y[hGzO^Z}l~3vۘ a# y />ݎs?o&^GcܔnW~Ӟp~ũ].9U.:+wvn~ӥټ` gxwv5x'e$'1l~ q#;xz"y#OqAf|f^IjQ^bd7m,!3nV8y 7',;he,*`R<,|"B@#SKRSRJ2s'ϓS :,d&ɦ@ϩ_Zɩ0ys,I3NRPl+>x' GjM6bWU*ș">[ "x8&/zOȪ"*"nU<_HnhѪ!{O#OBkqdm>(h x hCbғk$&]& N@r&"Z$nT':I(>G,Ļ⟱KC @4%8EVx;|wdyF^7PR/$㩩iO(UrdEraY5#XX^X=X>X}XebJaGF_ca"Q90,Veec۫;Qjq~pS 0Ӡ/tS/74Yn7F;GW M 0%$ydihƮyHgD156 F*ËԑkpRvxWmoHlUNR¥Nj/ *Id9/]7N7~'&.Qud=;k̾]=b$<OoI϶X.7 v(z/|:-(¹=91[6| tOn=2qGömb1`ȶBxrV "+g+6[Lຮi?nkTfPY BE"9(csu-HlAݥ`p5G2aⳮk$ r }q|^Gu-1X#l63;`ԱMÂ_~wi W{twkP9a2H 5<ԑR ϫ U8(VaаQNW.%j"°Y!QEmؠR#VY܏cK>[ɖL:z_GYkHע48!!,*,}DBe9n ӌlėW-k#gy f(6Q{|P!S E'@aQ0:+ôPDi(4#/I[@hδIgB='$zj^hNue2,բz-:fAGO'JeiS*(h@bPju>u+Oj[W.^׋@QV9H&DwKtp{ rkf0'CTҽJ71Uulx5`D2n/82דf{ V$fY+cy}e8 ]Hr$=Hl${[oWKqk_x>.YRZceL WoCvAFx;5rV`GԕnuZ1i1fD4KLH]"TtNKo;&IwZq/gvFgOgݟs<V9M^_IsĬ 8T!Yş2kFD708/_,1 `t% 5\.7]6=y0sJM)6p`ңz}XL:K͛+NPF ϠIRRL1^W$%ѹuǣ- xedC(F&usL'0y %o=Yw|m_|“XM/%Y2杂>[xet%#OqAf|f^IjQ^bdGF9 ,!3:LcҞl9"r& HOncl) gSMm3{:m&H<ȷȻHM6ق/hb>x&,Enr6& eB|]&_ h.VKt&w M!:P\Ti2;g3r%d$VN>lyp;:)R Nx{mtC8Vr~i^IjQXbNi_dA)}r &o6çHm7%nx㒔l!6y/o56\iEZE)>%`!aN]r]$4DNtx[jt%#GIQ~iqjQfWIX3!x[hea+#sP䝌1jMVeRss0S93Xd6l:cx lZon6h2K|@j!~~ή Ze'k5JMj6YAu~j*6:B$-x22 ϿY 3Zb^IfPjANbvy @xT]o0}&iU@R:a*ѐh" !R;l턏&*mx@p=kiA$TB9 Sqa.0R8 s QP <8gsyr oiò%'D€* JhE.B((ѿgmv:oiQȲ^yᝐqJf#l7 ]TcPK+IGRvR0SEF)H.3@>$ GaHJ$= EE50!e8K41aV jgRX!U\,+}4q0xPʰ< aDJf"qK](p7]HV kjٛ% a.ː)6H xhe4-O~ZMSyfn*YP[ mPAI̕YV,nAlnVp k3=ﵶ>O4E6d>ԮzkmE`+*iB^(\4`m[h4_˜S|ϝLlm)w2 'H5+05gW5Km(?u βB쐾0^5+p54/£t<흨\U2_}f_۪/.WDlsx'Md.&m.̼ĒD T]\CMk.N8_/#Hts=Bl2#XtQM6`IB6KokNXP62r 67gSv T.;9(pr.Q4)Xsrvs'x&rLd%v%œlvә1nNfgĦb3{3@N9:x;&rPddyF^ۘ70}g1&gid\:i ?r px;&rHddyF^814]xVkoH]F6uVT6QyXHͧ]Wh6]M^\X~Ǽhyl;1T%W=c[eDWӆn>gTPiܢzVq3{*/?֣|nSY+]WEXZys]i)Xs!)->묂 ၌h'TyqY^AP+͆Ξva-^)\"w:FUu'RŸ}8d%?qȚI0t%(qt0 -Qd6˶g_H,lx{&|Hx3kf^Bn̼ĒD T]\SMk.N8_/#HtK#Bl2#rYrLcEBճy3jN`j\M\NgoCp55'snveDVΙ$XZRZPZ\SbUŌR&x;$Vh 1gڕ$Og17x[+GpdyF^ۘ70aeMO֘| )Ptx[+BhdyF^ۘ70i\x[+RhdyF^- xUn@}Jܪ>$M$ibձR°%,]U\|knZ Y0s m0`1$M6RT(p9j |[ӡJBR 0" SkL=DBGb6<_ 6_(gE,J᪐,R"rw).}l$+wj&Ta0\qHxF23ں(ZwSX)ƪvݠ4:К 'V뾬?{L ?k4vhzݳmtKn_#%̲U M3<< = Nx,pX`$̼ĒD T]\Mk.N8_/#Ht27K7BlɯXQDRPx׳ʣhM*˨99Mn/?z#T\.55l܌\RKJRKsJjGIx;,3 ڕ$;畤VhZsMȢc̛+=uKx[ǿdyF^ۘ733f]ox[ǿdyF^)l,xWmoH bS#l9/M~h!Ui+aѲ4qO7ˋ R%(23;;3Q*j8%!pD):@g buPY.ze|Do\"] D0^hF ,q: ԍ"eq,1IS`M7@; GGQ{*ˆ_k-/qOkA Xܫt$prNiqYBVgFKˣ 4.4ؤ6e0"KQ;$e6H08[{vMoU|IQ4þA沑@ԘĂP{*HÆm>ҭ󞉦4܋rF4ѱ;Yo:埞4B8I!n| @o#N҅=IJѪ*,TLd'PD0AmC^B!*6%Bۗ:ac푿VK%ʎ,|m_"wcs2& Tf#:sי_CAo-Wc"Uyh˟d,c&cb2]KaX]ٍ-.HoV:NU~B}*58dN^ZbUvB>Jz0=,KUT|=١D$d@vK^eC!|zȔt Zђ-tDi,7z%3t9^a&5M3 2hDCh5߾}۽YN虘N]-M`AG˲([eGzN6Zd5wN 컘SOo1OpC l3ɚy,Iՠ~eoLʿ,|0H^V3X>i2ZN:KdE>*'OJIo@j5_vY5f+0eGed*Uü}{H_D;eԺ었j5-a8? "'?)zxգAY33/%$QC-$U.9?7WGDӚH)+܁(1y=/L>4Qy>XQDQxZ+Xe'_GBo2#T)̪T fl\$v{cp_'/Asy,$GvAy|r@+b6C2]i3;(#.c jE H';B(PD'w E458'OQD$<+XZRZҜkZ.cgxMv7>?x\iM>B9'Ki)gVprk)䗖(hsqr*SdD&'LKRuJ'Ay%%' rlTdl3q3+F6@'lɥH?3m#je3F%x[PcdyF^۸SKB|7s0de7/efLfbex[HcdyF^w/n/x[1Mc 'd]'89'QD'RPp qUR(J-.ךoY]<}xVmo8L~ňV Rn>l+ѐ^Qy !G[}yBSJw%3ό]44h@4yA 0 )Yx"{Yvwf⒢ĒDk.NDrq T&>#HA HL¼B+758DC \G@G8*5?M@ɛXY@&`ie14'hN^jSl&""7y>4[6wAQ 88Kr`A]r"]ڜU ܒ7p)os2%|'Wl+ STƕVhZO>' FdxAx*AfdyF^ۘ'0M svUڼ)y37+j kzx*QfdyF^y/>xX[o6~~l(ڵ#+[,[Ym )Poߡ.ȲfNɏ;<<7R=m$4s):Fg bPYb.AQ2bep\_%BKLg(P@F]g)8M9_ 8;:SU0"HEa!Nt},HAw!ǖGՖNE̎giB|Rl'< qm8 `Lb"H}HMf,"Ǹ A>$+)U\艹:1 w21=Ge@y}LL` ̿o>T|F1ނw:3=۰~ YnǛyw']@=ރc"Ѓֈ,Pa7Ki]?x&x kfv~^':b؊.4 /l˙5E7 Fζпt q⓪'XVLH?,fYM"IUGbh(DېjI0>K84PٴjG@}Dg'iܫs:ƽfzTq,2N:pIӘ>2VÐ=XA ]He4]*^m7W w%L_|~y~p"G`KUXK,%+7}%|Cjzy">44NTeF|H g) _kztN֔1L!0Q(|a7B_+bv)VkEej YW(R%3F~TsƵbUeh<IN Æ-#Ͼ{a~$\^ބc. ^BPUUmWgK>`ǧPDVaݔmV9:Om,oՌ\E3rHY߰ H* ]pq$n$jJ4˶ UC*owx.G'K+oίd=rAҮhLnт c`.dޣp]ZmN!01W;H'.Mae^o[{8 $= M66-%n1'<DXݕwM74|cYWy^R1N+#1hۻ5]aEglG;$tx۩ݢ&B~i>W5gHpp|kpOBQjqiN5gf^fKbIZFI]r~n5'RW:WnjtVIR(")(<l籉.ˏ}r;~o $Қ\!;?&Bxo g*7a{^\¨Ž˸~! sN(863t]h'P A i"Ғ 5H1D<45';p0rm>/!x'xk`9ɘ$U׮$xr'y?K(f+[Fl$MʲY>f AQZLlJxj`8Yc>a+xkj9(yFK\'m`+f O>] ag) a,J`,bxkj9(yaN8>0S@ X"7 xZmoH*FK;iZ47)76*,m}e/b옴^fgfm+z!2 9.Dx {н:J{Q  hy0۷,ʖ櫠ӞpAF9s_6gIF5=ٞEI{_*ކ-zsۤ0,˙T="gc:.#Lg!o|pii L-cm/m@*a%x- [,R˽"@8/,j5Lׅ!$q;˜@d/ɭǐ ?`"KB(C94.=D3L!hp; ]1SwLهn5})%sZ_垒TM\5lM'T"~sB67co92߾}́N6;y{ʼwNý:D@6{sgfQg1) dQL, i~ &[ڎ-Yswo~~Ӿ_Xp븠 {;ݢfڼS5*WlzN]HI9l]7BU(ummӺ7Mw8x le=63̾{}?+mG~!24_ ^#Ex~1}C(} E&nPf5`0 -x~1}595&qNcU%Ĩ69'Qmjƞ*+3 j izPCkNj.=Ϗ"@ÓN/c'/~L'Qe 2=7M(1>*?&CnMrL;/66= o_vz[7 cBR4+~OBѵ~%#>&i{v?9ymVO'+o!^ z3Et7zz kmZ\vC0!+xλwZL2JRu89 /HKƗgMf*)I.l$řYX4Q.9?7WG@ӚH)+|vVQTaҜY&3Mv+I(0USsVɗy6MdP4Av+v̜\%X58C\C}B Clcua "L3YA{k'L TOx»wdyF^AyX63311E6lg1&۱;x»wdyF^Y--WxɳMA+$Ug#0h&sFҜ,2[mg e Yx{gZF~}}̼ҔT+X92JR'32+helcfd̘\*YZ\S`;فE~Vf] Ԋ1,,:\Ę2&1M~1ٞ d'&!jN}-<-Yl^)"xWmo6,C8na@pdu3؂$w'B $$+KJ-yQۂa9<Ё08s$1'(.g) ΕVesЧ4(C` >Wc%*!- 6Ko8/$ rA$2A(Byi{}sa4 4J/B u26Ey]]jZL@ ]ݹR/H' MX$I6Jь$DMiuق ),+Һ xJW2L3s(0wCfN$ ܖڷ,So:2 ԣMؓ8pp8C,8J{|ND3J2(I jPc%i9@ީ?F҂Xw1f]cT?'@Y(`jU4z?^YU[Xy"7ߝ N8C zW:v[ 2Tmx^KgC߸? hy|O2bն LcU݌eK[9͋ڶy}J(ϱZ?w%=Swhv+|bgp⓿UvLn/WjOC;5glouHv? nlyK'WMb֮:'ԐlE Ya]d"U,lUY+ۂ#eZԻIulUukiLs+Y0L2*e{,m3`nMrd i/O?FZe RƎ !NJϝq97&/A{(:;#;Sgj> xjF#ߛF^ޠͭ͠ao;1~v t70j:xwUodyF^b4zxwAoFML z>k%P :,<xVmo6l Cub:8ں,X,2W( 7Kl}8x/9VCC 4"17qa.6~ zRUpĘKEAQad?"ē1}M,pR !ObBq+5zn2-MP/L|ncdySCBH-^IPqD't&{ ζFD]G! Խ5p!Qbynno<tEs)4۲i-Ff3pόPǞY $1T jnB-?/7L3 Y4Qj5{6 ]ꇸ?&TÉ5DXwVd }بsШ[؟=Q{XK+M0[ȤgJFqS ;@&08k>iqMX0$@zJ[¯73 }ď1tDO 1hÐ5>ו8zɍ b'=j?_<rm NVHtI?c?L';EeyE 0PE)9A+s>ؚOFH}k &~C*8'ƿAW ^S8ի]jyr%_a&'НPTDDR8=% (_:ӧaG7 7J^Xtd1a@L뙹(/V.  Wh {alN{K(rcQNYda1E,:rSRi뽖U"ݽH:ִ w@Hp5xy@<jʣΣyTY/k0dW!_FɷeBK ɏMzNrx{}H{.fCrǙ5KRuJ'_5僲JR+J&o٬wy3/# P|Fªϰ!Jx;G{dyF^ۘ703.p tx;O{dyF^"2D ExۣE{͍ڌ 0n̾t:,0Q>V33-xۢE{JKE7 C@xZmoH bS#$M;]'9നekSCl+REgy{vqQE 34lXG}`PMAC^a=C>QQ؞* X$,ڞa$?=#U1QoZjA] ,s . k $U OV1,tpnaÚ'T&t,< VsA\8|~ +Ca+Ӟ'K:5qJTsu廣JSY)>VXIOmM<*}RX5 O#") Jq֨ YT'ʝnԥafr@Eݐ%* ő wDΛ@~ c_^Q Xa"v,MG0&IԴ ꕸJgՊad|/U;|f/M"[ iy- !IEu? II={So~g@ 2.^=5S ̄S=_DY7.<596HͬaG`&t[Q:=|֐ R:XL\?=eȓgP$ 8p`nˇ將?:P%!.cH(+.P1D$% $j^PV.@2BT!ej2l2# _qtj QP#/'@ 8>ѳU}o@0lhAGv5Y lw]0X@={hIB$;v=X~U کye'[ 7̛ivbEyU]fU7O)N<=6Ĺ'YKcrb.t&ҚK} s߂ޓ]4t&qL^#$ T;y da6΃0r\-;yR @"IbG^sdE Y!2:j ~!F@gL.T ,)NJHSa-5FPuU 17^ӾxT]O0}n~PZ`ؐBAR$dx vd;6w6@ clb!J=>~Z[= z0dpj*YZ*؀PJ}b #VTeF! S}J N/#OTW [ cvk\kSJmkznU1D_UYb*iz@e[!餤+LBղYL>/d qYV$ 0/d.HX:`IL( z9&( ra' lqӮ> ] grsz#ԉ;EƵ ;Nq;8 jmpOYARUz,: jSq=%]sEnP+S_k)d|7qOAPt(f>Գ^C ,j//ל6l 6#1HH) x0JvoZP]8 6  ;$h:Pi* ogWA8BwGمLqnGw4|ϊܨ(]i Mcry c x C^;2޸g'_Mc$o5Rkc*)癴i~pD4͟qr7_+=TƱ$CS_K!3OAKk&{4]C\C&2Q0QjePQjIiQBQjqiN5W-6/yxkϾa+#sP杌L4IxYmoH*U+ޝ^+ض([),c؋-wY_@k{gg<3^+ :G}? ct©-K&wsrRTpK@G KyL6N)ai[,9`we㡛0> /&j]]~[T'wpL{tԜIQ]ԟל Y<]AМY(md jzeY8#QAD46c#Q7۟H/џpm m`sطCNcx@d;ۖ^@>_ R@t0r|A Z?|H;dzaz@Vp"zs-ۺױT,9(6ND}d:6t۠v߆%͐>n%Aw"Nc+=+IeZe5q:HJ$:1uPc2Pc;l+ټLr~Zt{Z! 4HҎPM`h|"Pki+*;yGL JlOC4Z hdzd܄,3P6wN3 u]) | bsś1@4J+`$K%.8Ϳ亥ACvGn^pw/j_ҕUA|{PÒkcs^EվR/NzPٰ{9>_%p)4'͒H#J]H^_Rwv{he|ۡ8_ض37}dz2WE @F9*8N\[6{zR]jG*Buh~Q2LiEj桢W~ U15|+5X FJ<˺ܭ)brnA3zHeFVW E1>2>v/D8:j-y:mA"#:I7^kïV1A>2We&d·gGNjZMoޝ 6+O:z\`4b{MݿuFoZGN?C^T͝5U?Utpw9ĩE#?ǯ"Ͽ"3MWM66cʼn>H|n' .iɅq&;pMn.â$J,Ǟ$53%[{gl'qYAm;gs̽ uhѐ$DpHi ؁.g)r l'SPY&W` x9H~ 8 O˱aDEI )KN2A"2H~)g?${!w'GUe&Nq]*X+SړBNj+WHOtb_NSb=4^2A iL%] Eq6aB`%h(" Ҫ >besd^噞[l $- %(Z_PH=7x>m0qV6:MT ÀGu=nhM3kNޢCϢ$OWWGt,r}Pqp蝣6㡗ǏhqGQ9gja#NgR֧ ސ!Y57HpDvf6[QCZ[mxa4N<b夓SU6 ?pgǭ >w4j|ghӳYu6һ}ƘIKzSד.&V qB۹C~o5 .[܏D|5T(1vk 5`  v^ҽ \%$T}Kv[yG_L*x{on6gf^fKbIZFI]r~n5'RW:و !6ّs-.>Q5ײԼ 7rOȯÏjdFXyJ55& i3rM~/7n63M2/lJFN6@sd)NʏTjcu'׈m~)ȇIܹ? l^8%4|/~ Dl\#8`R : sf^</tRՌh,J-)-S(J-.)xk7ؤir$mT]fpkܛ070nbfĦjk V.N 4ygyqxmF Hqs~^IjEX;Ѐh1L UL+\Mx \ 2K%xۤNwdyF^؃}' lf: zx˵ X(( -=RxۤNwdyF^0}ༀxYmoH b/U#!/R{MP͋iOثc[ܩf6؎!^ԨxǛyH%vl0%34)[!o8Q/ 0倎 ._!͛&Hc%RH%%C}\&#k:A%H7QzylWψk92k.?d׈_]dbg|mxAsyRMk|.2-7g!7wEvm3V`_g[`oqUk1QW'cP=WUf>AB! 2B%RRAG5rk\w=UA˩ˣ!`L7qCKPl#놣4.wou.fYxTT 2H YK0 }zБ)& tػj wU)IU ߛK6æGm{=3F:={UG]آzn?|ˁ(I[ۉYxz]1GGqI vSPKBͩEhɡE6V&?be2,&p<^p٢9CwZT}:%,K C (DޣTUrwp_$R; %S*7]1u ,iSYV4-t9I36'.HX_ybW.6Q>b< tHq4zE_ -MvpDGf8ކSs KJ_R,Ob1Tj\'oH1ovIV>e|h)P!D}|xrdAr-[>jfqPrK3 NYPltVߝ{T nE@c_)V(r`j7%[L(]tOn.(SGvw)e snJWҺ2=ǨʺOC֕5-)^G,ݮJ5Wez{[QG|DEE%TfpVZQ(܄.s9/54B|qYrB_)x}੼+6ɸ=~'/?=fC1COM $Jk3{i$ :Ǎ↣ W8jMX^<s›Q RH btM;3[ o"ڡr\+U۔D%sq 8PHnN/y +`a)Oz/a\]U?o~odگPDAv~˂B]̻PF[%AQE} h{nZgdn㹨ִv!$N'sD=98JDOH韐XJBQ N&c̆]6LHl:aTAŤJN^= \4CPT1~ =^PŸS\GtNuqʛM\9Rc HC$w L x x!{r">r&N5 |ѓ3x61N~+9y 2T'JMateAU|'"|B hx{iBFYB6gbŻe&L "K’.eMNO/).(IյJR+Jt&OCN(=)4;r3ZcJxBr C7kxTo`mm"|~QVƌN4Ș(%4E*(mOz|=hy/,_Yc'OO}_Qc}}aj5'b^*r,^4|7~SBd^JTh _0d8HF>6$|24XdA|:&-E'BaBT†!x˶.RBEj1/㉌d\.8D1YAdmEi(^yT%%qN`J!)F `jGG 5lh`h eSxoSp̗~0_1[\-Z🁛niiI)t0xڬ9熼6j- :U$/ICu9_M@L+%kd~+ʟ֬N(~4Sl>cg]Xʪ6 }qb|d/1^n13d-d3҅\JӯfL1=!(Ch~q#{to5yj]Cڛ-e 1OmeC`x[l#OqAf|f^IjQ^bf7FE) Hx[b#OqAf|f^IjQ^bd7o~!!~.> @يܢM&OQdE^̝@@Lṽ*#ւ0$y;@Wȣ qSdJϼ|&oQh#n 7+~`c);^Di&"pӁ~+JO (MzsU7e9dyiQtn%bVlxX[oH~ƿU#6>4Hqn2fy=o57aW{ȥ 6U 8͹@;`O8aCFtN{Ph&F ! 8W+~1#n6ɜN"b4"80&iHçV^8д؏)p?;BJba<Ҽu炶$KxOqnX| %$B^ii6)$"+P? [%U2]%w#MsF#׶F㮣9h蚌`{0%b cPG'f>kᒘ98ibG9;_{n] f&E6wY;؅0|:taJbPٌ\cc[DI`hƫq~B,9H^^:언͘3p$PՖF,GZMz#&X'CqO9-NY;*XKGV @ח$87:KY/h1abg,0 -օ8E_XvH !ܤ;B&蕾fV# >eA( X$Mm״-ñz7eyO -iLYR/кpWo.QڎQ3rXZ,r3&j<ꇥnG互[$J hв(!CHI).(Rfg֦y#Qͷ0%.:ݮ2%'~Sh4;SQlqW0l̡)F|^'L uRKK20Ik'{5ua$F]4'fdvK`F&ODGے8A}Y@RuJSCr\ kǒ8Vx;b}rC9uy%.%j%v: ƚ\p^FJ^L<&{ʡM*"5ٟ_v9~T&BX99NTodv~$r^.pNYHtFN4e&oVT|>n=Fm.N4މh<1ٖOMt.H%>Djn/lzIpr2\>2:aTI(9d((v#6#-gf4P uɟ$$kɷ%%aRI NiB&):3NQx{j6|BfVQb^J~&'…'+rCUg }j7xcldU.ޜ'&el"ox;dy|&!gx'ڕ$O+eco^Dz5aN>%5ٜKlzA8›s T@YlX&rl~[2ANE 6dFx>Qm/`Ө0qs[Uxc~|dyF^ۘ70qrl`FW&0Vĕ ȈJ Y[r#q dxc~|dyF^6wxX[o6~~A$NY 8 2,{d*@QK}ؒ,rc{ 0# x.ߡrT =j/ -A8`ęO>IRY. :  M~݋GЅeMt?t:py a@=(ٞoHc8k1Ez:~ c~4fkԤdzҝK~;Ics\S}R m˷&ԥw46c%R;pGne6#}DZ\n)Xo{btOf=̆ xǜ91$$zN/t]Bbb=Wz<qo} }ch n{Z̉>cU(D:=@"Ҩ[ؽbv ճGRcqBx!3Xf8 /qM$~C$Ķ~ztZd_Ě"y(TGަu_44F{͛^d72QIɥNdOekǎ +-B[9I\epFgNmMm2o*.QI[LDL=ϛZowtprg)h(5)C_%=ݮ̄R}LC_"Thqץ ^q<~L0pG)o] ѡ 9 d(KL߲5|v5YEj ̖fo 2c1iM ;9CMB{9>,aYa~k8[_9hT:`#r"BTl]QD:Q\<ǜAWTnI%"·v$g޵n%m$mNiV2k2Ow7l&3W5A2U cYTӵ86>xS2eu&w߶\fnLz| g& 3~r6?\N/#Htr#7;H$xVY(9?$DG@Gadɹl">rqcW@\3y&:kq,V*&OBr#gud89RKsJl<7Y]NkXMM y' M=qɵBussr5&;ܗG5NδT ļyd6 uWf XIx뼲\0qMu&?B)PoGQ `5i_B5g&$b23YN$dO'&4=%, E$ET%q"ǿSTu8٬'nÈݎIpC989&O`ܜ"Ȩ#`MiKg4Z-h"*h}ld.!a ?y=/@HR| 5$ !+!XZRZњ 쀕%*MA)=qF@vN{tۡ5LDj!#e h'.Y!rR\,l');PB`B`QjIiQxkZ.(2 x{~%x猓X'K Lfbb/Iյ+I.co>Úƚm6`0'[񞆲XJJhk>+Pw/ a[ mg-٬%|uR8T%m~! u|FD xa~dyF^ۘ70}3~;pvU) $;xa~dyF^yr3>Lxhh{1 2jL^óHŌ'{y|4Rs5899ӊRS5KK\KBy$'p+O"#:x ʋl6c$ZyxkkFl2f>xYoFL~ۤd悳@Iie3>M_LlY{>~N*4FTR/ ! 6N4“6 Po 9$ `\Em6cdRz' W%4C}.*bFP +XkMRv ? *ftIpc $*Y09`̰,1<ŶgPt܋W'&n뜫$Nߴm8X`аn{3,6uX_IH;(00wA>8Ki1CMP|G@'18jJT\*plgRƇ奎e':f9M?_-=E37d;M GoN~B5}6 AzHUZF~eY c},lUi4-1uU•9OoI{7!2ϪqȦeٌ )qHVT}܋b6XwQW.cۮeڣSuퟺ2pĎ=ΰ%L| *7% h$*͆؛ }Kq(фUـ8WPR:vC5mc|jNUቫFcM]eTZI/HByTV(|Ǔ^)N\7j> );`y:qo,왆mCmmM;dLjQкzruA^Ú Y,t\|hY5hitvIױȄGCӲj*oE=Ekg/Ը ^Ay^3( ^!z1U_^-+EM>3N%9nCnc-q(3\S)LpVx=MW2SOJaihӋ/fwf3똧Fou =em͕-w12;!RvM%zT¾۲J j$I` ޼CT̸.;>d>xk GIQ~iqjQAΛyYUXyx̒D7r7 lӛwJse4Qxk GIQ~iqjQEhPxVmoH(F9$ܩV"mP ltO+c/kJ*fm `!33;xӆ 11ƕT07GT)t/oNJ e-By"< l>`K׻[: "-Msl,{s4Ǵq!,"P%LRjBC)ИKj=\scQ;m }wN"%xlx4Rډ?Zu,M=X{jN,YT i+4%w pPt-:jKA$_bIF%t76Td;d ?_|Ѵ=ԏgʧz^WʬɅT~U!Q8kkwW!C'{,3=~x<2VU)Dq6-8CdII];^VORchXOY~Gpi0BYZwB£qߝmǀFWv ?eAn6Blr&<,M]8Tl+m))2OcCV !X|"TUgPPe Obt{?гrʟ|j3T yHտi'rjdxX^uw{zcMV~B-Q-!Џjd!q ,~ |n۷dl+q!oSAi>d)>kNVyue`Ju +qZ69ehouB~jؐ fj^936:@yĽ;S.95Wj;V} ?+XoV RŻ͟֎otw)&ne-x딛#a/6gf^fKbIZFI]r~n5'RW:9Gd-K B|C6Ɍ("sYPD<&_fFS&f:H*$vE4fhMveԜCN(4DVzqr!|;qr)$N)$ʶsL>j#ȌA!׃T9ڶ4+&>)=ظ5;Ę؆$M,Qxwm'XR[+՚vFa3ªr29/4˶4ɓ1˘f31fBi3EMՄ$߄& WmQDB? b;vsMA[V$)5 Z.9Ա-@ ܰ?kS9,ƍOk$G1Rw0ӷ`㜈BWLCD4m=]$UEOmbi/I/x|;Nzo&U03oQ5U:rbq15s:e.oʷPW/3=&ɨ?Ot8:5 Iu!9Qaހ tR|ɗF:ZRUY(@#uLj#4u(4^?73U/ŭ&sWOxee_o|T4{CZw]C.}V*3ܛ"Mlf~z ߖr#?/~ч a7fe?mφ7 s7Qx{(vWldyF^\2gmx{(" x{(EpBsp_kDHBs~^Ijl&L'2A 9D'cv|3%:Z y ZwbޛY8,"hx{(QhBsp_kDHBs~^Ijl&LM%E% %٩% )%\pL|FJM-N-PQ0Q(άJO0OSL/(%3/1G2x ɿ'2 BU6 l(cdK!vYb t:,)Evo39ҊRS5MɅg* N}-<-ɻY<|t! x+vKlFML] zs?&0cY& 걭xZyoH>4Z'u]i# |]eW+MBw70rXJr;y3f,#Iasvtp9F}ı<;e"0ky #sdkAjF2f7! QDz׎\3A25=W7يJn8d_tsfxs>dn4=[!G71 "6V{O7UqkGt#38Y:OXf󹱚; a9s"3̆Uz.*c'+X^WѤ-:$HֲK' _/}{sq`g\\D5 aN RysL#q< %04S?+i|ƒVr# 2ԳL495`im@)4+f;O/Iݦ:/V :s ,*@E˅͙b|}0C{,v3T^.Acq0z(9PInZ.yuz `>:oE@̝GRlkB(^OcԄI̅ւK/">0 Pjd;ۭLz_SjDվ'=]~,,q~0FP1'z?4책ACUu7_p<&Y; vh*,-a]VRR|AX w1KAaS'y{2*HNO4c<^yE.v4bzu# ۯ 83]p؅~OQ׌F[|!zFZo7Բn[&7BoΜ#YZp}M؃ sJ]j6jJD 4e AW7 ab^ n_Q~&ܝx"؍'_HwUdw+n f e}˟`õZ-]74Vg$vѿRJ+QPWlw_,}R)]8Fukd =Կ]NP:F$]5\$"`7Ue5eVPw.ʊ*h]}]Ҙl𡷑pjYѰ5ZGM >[AGL}頖< yfl VáTY0u\Ʈ[f5sPdEcPNLaZ2+q3}Ĕ4iQY-jeO3I΃k` sxzi~'!3x;zs#OqAf|f^IjQ^bf7F+}6  ]x;{#OqAf|f^IjQ^bf7FFxg׈xG?W |ͶLIM|}'MfgZ&oݬˑӖٞKY N}-<-kA61gxR*k.NO2u4 B~RV|N~~viA\Xf_Ɇܚ'W A=9VPer!/}X2ߠ8fnwDLY@rM+>R$q @U՝\6B ͹̽UxV[oH~ƿU#C¶}hq\\lX3mh3v(%,Ȝ|߹q5 #DƁspOPK#NCB "3R /Ӎ`)@11\e%TJd "~9~Y0XYD/-zuM`ɪn $jWڶ3.uIP?)#'&jbqi`1SyA4櫺mͥR" h(#Ui " bUJй>2 #m%3(]3 4#) M@w=>L#6պKtZOmB7A1tb;$h&h~3_4@Fo&wJsܿdj]B,jru٦Y>A$[i7?{G|7Z*2ե* $)U!;`(d ,`$. uG$U晾eABo/G~; װӓNWuH!<jHCbnx mk3uܓ;?9>o]%m*5t:1AU&=יL-g6,]O>;M ^WoѼFxv*Wo k S j?AXyb\vIܼ|UNu'Fbcm;WD[:CjT]*b2zrx˗Lh_$_+8D<xUP5^(JNRӡ+:0uف yhvĝ*[`2J-!0ۅ Eˀ4:'qLOgE˩Ӹ'ZF ;!O)uC֨+"ѡRT}WO 9K"vRNHiaE3o=Q8)[1` Ex/a=qf^B5gf^fKbIZFI]r~n&H .RW:Y!69MkK ɡjcQ[>YME,1dEv~T'MdB|9v$Fd~nb T''pNV"KM[`QjIiQBQjqiN5W-Gh_ Bx/L|dyF^ۘ'0rq*((LeRRx??gWļ̠ԂJN}-<-}ELJ ~Ƥ!"d4PK83]dV~i Ȱ3KRuJ'˳١,W6k^e-`x/\|6@s%v%œY`͡, +x{.H|dyF^ۘ70=iOx{.X|dyF^s4HxVmoHňS+:K{=D"^PyqOb/kiSlPD0;3̮vnh`@y4"`$ l#* z7SR$B9C@b&|.Aa"wJRB/!$$f!c-7Q.Zgcqi 6k.6&EFb.mkoR:q\+W_]hi-HȌLG_mKKIf-z~$*AD2r\-i3ck2;_. VIP4KC)V`,%53qXwm{[pOW$j `:OGÎ %( ]io輿]"ɄC{͝8*hᑠLqn{*(ۉ\Lܥe䉍z=3j/N^8 1e g+^lN =Zm4NyX(]j *[- Q`o k31t&]>)㡟3>Nih6^T60mMEfsɴӱ&tCEc \R52">ףduiJMbW;EςK>iYٴFF8 Χ@Gi$0Ma `8\pZBpѨg&J [J3<]e)jhP*\Pu]SS|G;wÂMyRjЏP΅^)MRlniBJeĒVW%+8Tv| O2?3Wi ̜ڛ(m~MooC}_.CRRݚv~?4Pg>e}= 'm< \ OxЪAs.:'BscBb^IfPjANbBf>'Pm=HSdBArKbIgL 0(1f0 LA&z*LάJ_Z5ju]j'pr)xUn@}b4-@)RRlGO+$ ]gvnnZZC"{3ۇmg 劦05,XJ1 TKQ(* "8(QȄBC(fG,):NGOK CX3 8U #' Hwћ{[q3ƓH)W:شkciwmB6*CTwv*gUdD/s_h5IS1͚31ߵ-:fMTJ~85]X$7.ێ~8GvcrNuT\h`ՊDJʰr-^hڱ- !FO^߇' ׺cq/\ ׯ`T{Aisvn,k˶6rARUdضjqШ4TE*Q}*+Ovs}llLpXJ ȣYeprI&t1Iu!9DDŽ }Q`WJQ0;p~R1snp 2scNLzdȹ؀SyNGwptY]%zlSr쓪kƖoF4%6/bV5XEyj:flׄ&TK:%Epy~V1k2D|XM}tR= ]&kYsSv5B].$qĬ5,IM4՜p|)tZW%:f>b/r!n&nOtlۅE_SSqymjUzLP͍Ifl>"Úi*А44A =9XQ*GӀ:PzR %sPBK?,{n-] [4N`̥O 袇f+,埡}@H@HrވΡXYzM3-Z׬8*U8,NmCoٵc$# ޻&?Q%B/(=/d16錄 (-xWmoHňS#\+$Q l˧؋vpU{g1 /r;D03ó38mЂ> h,i7c Pgp}~8 U ƀ$OE@/3\wi[`d)|:Sb*%f"Er;_oySA~*dnc|$X<|ܕUfYҩd|xS? #,/'"jgSŢ s'ELM%Jӈn@Of>nI@axKƎ;{g#hQziodb@NL̄J,P_KsUwpw`asƒ-`~* *H"4R! *} řa4齤<6t ߔ',K5섋i}є/p|A\M}L :Ml"2>CC]եcCYQxĻ9dr=>}̘^'MŲFCPhxj nv ϝiEt*vFu ?t]R8C {rjM{mr\r ?vtv.ݬL}|$wijmXW_0:h]:vys^*!>+g iPҰC{g]}ԣA6o&\;kѹ{ z Pe箵Q5t'@8h"ex{C~C>6gf^fKbIZFI]r~n5'RW:y#LlZ'0NǮ#X(4Ěk3#-Qf^B5LօbS2 c;6i4{E458' O^Ǯr?&qTq!1cw #t:Wdf߸O~ݡIZ晁=0\uO  ՓsJM&4Spj>fgmt ŗ?gx!Bv!6T]$MْŐ XY'?劜d?Ȕ' ٤yY3@"EXR,fx{!{_vdyF^ۘ70mg33w>\rc&` x{!DvdyF^x5uZVx/Yv:/{nbNN~dό&wؽxVn8}b Um[V[#'A[HjcPE/k=3gf8m6Sc4%$LDgr=ǠT%g\)( yo}AC' ҴZbْd!ѐ %a4LQ?b!9Zoɳz6 7B41S8%S]F.&uY(wd[:+)Dgqd~,224 9%I5qfᜤD E.[0!e8O8ì.fE,0| \ۛ|÷<'pq[9JDD;MH^Iȃ=SlĦh4l8߽mOkl\˥Cv{ eFèyH&J3gPCℱ.җL{ĆEhM#4EꮕS MTT% {9LIL~ڵX:-zU0cK,b_\k?Ci3*.x;|\ydyF^ۘ70l!F Xx;|RydyF^2xZmo8L~ӭe[vwەhHhyStOQ\mHі;' .R)8g< Κhi@ۇ30L;0zhпyd*еa <U =#cUToҝvRBl\qrV`bNE"d) dO'ANZw'd7@VvNo'qӗd?Ů:8]f6$5bV"4{`UM_bi4x$ ۀ _XJEk`^ BʹMӑ^Y.[~yL=>S$E^ʭ*wGd,n{> gG }2QS'i‡:fF0'e*Pq>qw۷]7ṟaI.IIN"2dTN)wDE' kߚSYfQFr `4 "ǖ;㛡4weV.6 |a"Fbp4ano$'zq}ȗOB%` eO=q<S#.n4=DYvLMtO_d+UZL [O5FJYq J3s\?ёDL|h,-1./X&i=o5BQj昦WRtfz >1P)^Qt LVZqv`Y*Ch,jKJzNY}P94UU_8U,a :pBeň. 5{MCxU?ň~ &HE/2xQ0g']P JϭXvdx}եUOO[oF̧bK-5;Um4qY9dJO\"p:- r!Du7e٘r]&QBAZ3 Tܠ*"ᰗ۲O9kmϭ=DjXA%kSs,S9I L߸>1Y2FItUJ-_X-#?ȹ -IY16! !ԵAF ]K_z+QIZfMnsWEWM fFΚh--VYH]%i*#Fq.d7~Efa]Ǩ9y>d}.8/IBo$s/*-F=Qvc&ۊM(%:y(cfI%^³R Nx۝=~Cdg-⛷KH3N(%>ykΓ"_˄"g3+9Ngnɭ“(KMVl2y>yE 1c=41ɬ&Hb*A[grdv\dm~ T# x 3>3$(/1g6rCXy%'ޙlZ>9[hc FqLt&?=VTGA(=#1/%'XGan ɽŽ&*3MNR di*N1d[j h1d}LD'In^&vJ" ?*Bxkq<#f/F =7LxZmo8 "[89M4v 8ⷵaa(2HEߐ$R/ P43ᐜ긅ѐ8)q@S1ezȼC S˜kdP,渟IzC!3!0p|tG$Q# tuON_WVo$pxۈ-}r.#aQDIeq@YmWlQYSqraW,P^wEk bY;w'Ek?\?\jٖχg;:hJ}}3˜8] /V$vbnp` ̹x B\ Ho==_`qc|jo.7~xٴde @udt4{XH*xxe}cfW|}8z(fܼ8 cUVUzs=ژ>8,a )db(DV.6{kCؿw>MG&hj1FHu`/<@4e+Bڒ:\F!Etd.qK׷BSlڟ-1w#bI|f^Ge> 0%YtUnɀ0uUQ'(so~-7+ CIL#w4 s?JOƣxi%$[>ڑy=PF5"+*:R*4b#TJ 7I )-wWJݖDzSk)q;*]0+4l@-8eE}|M̄FN=dwqY̓;z ,{GmH*Bn;-+۰l߳qĮb??97TwT*>S m9NVGL "(iҤ>Dn!& ] \H\,Ւ\lI. &"!**pP#ʲוٔB;ܢT,eeŖkSܭuM8%qӯ1UC:,`Wpdp؝UiG&G nRU…8 MN /g N* l1|^Ÿ[Ly7q؋50͕naQ/ ہ`9_}{NE;KB ;-θ7'\dfד1:A)ۗ3mL䨭 M{O;.l8BXMڃ2N( +QS}gt5:Uȿ88T0=)b}r۽ Pn^i}ؠ0RG< U oj]O^Uڇª0ߗȪptV-Q[gk5n鉷'@LjG[1hM@>I_((N~Eoߢb蝁pz R |ֵΦ!Ar0fbp]O8B6Aޡ2.AEP 9S0D/հ/~] "RDQl [κE.|K&/v䏍e ; ;E ?'cѮ0[]pa[D7R~FX.mz:bN8XA'Km&w!~tpZC|ܾwRHбMO32ש1x FϑntOHj:ce\ Cpq9 y0`$Hm"#vXnoGy??]X6vkr|?tpF_p"rP )bm,>16BP9%5s| =7GtAQ۾7HLG?~%~<3'/`ęyߟGhs z YMb Y&QKVLA9w;4dW}Z㿋'PҘp5FC6Cm@'G8+Ґ/CgxOx#2NVl*rHN,{mr>fQeB1r/{ Ex;<1yC:wjs~^IQ~y^jBPs<ғE6/gb NM̩*'e*94`YxD&ɊmvVeXNbR֛x&Ng,*"Ȩ !EyE%^_dj[Dx{3iBBF{x{7qdWf {73N&b5Y}?B:kQx{^jC>T5n"sgx{YjlF̼ԢĜɋ,NUv x{tIzlF̼ԢĜɋ(pSKRsS'wI;89*h)D58RKsJ8"C8344 %9@K *4J W(gVi-QPcԜ\ř\PvQMҊRS6eX3PzsZ4<=ɛrqrr*L'99Wn.}E'ן@q?c dɷ |ӒsS5@Vi$$=T6P 8~N"x6qr%2B tAO%x C'x[2q e͉2Buyv $x[ؕa'\]79#eO#CNQC5/x&aY {۳`N% T 4x;91rt&%N=TԊ[xd!Әn4&k 'fl.2YEt4a3X.N^*;yDN6ex8 <,g0nVgu2?d-> h=x4bCۢW|[tiV o)xg.Z|S=SRJ2K*l㑅t& HNW gd@UMNdјVxšKX 'zO6d5u?DnU/,eM^V"R" :QLh28*'xQĂLǣQ׋!XI^ !\R7ck2 SDžɴצ)SQ4UpwL*d].BTN @urZַ0M ,gI͂,P3HFi|UA3C2Y-b-!6ᙸs^kV6G$n`yLpw"oTtX硲l>x;$[`qXJ$iUx;$Z`qX72:rx;$?_uC73`|%|)+/3 xYmo6~+E뮶&FIHj&ݛ]_IvP}}xv188@<@ ߁ib5`E#Lp 2u+FTnABnR)\ԕLspuyS~i;LEH|km,tƪ2 uh:F9c?4&Xঃ1a[TQ"๮397dijlfsG^&%U|(ѕݽ5{oYLI L^/pKRla*Vqa~RQsCўX=Jh$u hp,nj>2"&%7_?k=e{)Lj#q*@xJX Ґ Hu.M@^'y{i=]]r|S, Y0d iB7j=-o"]Q)TCY ps ݙq([ * '1As1=Wx&5N.39 ]D2cN a [5z?X07 2r*rmzQ^4_=\$2F Hg\ٓ@VB~~zZ'[pb^d@ϳgx--O AYA𥲺SW*+d*`]|̪,mיɖu4RlMj4IQ@%D"kDʫjyh垬h^6>1<]9 yAF2̷2&1* [fmxٮ~2Htu55F܍bV#^AVn#Hc. C$e$M0 9C Ϗ(u.>e7bqJCDC\gz9rGr}{l j۹7 UkJۦV[OIʍQ#f³p|`%E0 g{OS[ő}>1esʶ ePLU$^/c#V]\Gh=vr]jU -;Z=yh#MδUk{x;bcEzYxVoF6ʧF$n* 'a!.kβ ,G>~00;3v3- h1LeI);$D)Ia F1eIN}'d'!QlOEh'JG1=F؋8H "G~4Fw Mޑ؏3Dd}!$>4ey&,Z/sayӭv)-]7g$j}/$"XFɡ)KqO6 pvǻb:ެe[-zq&#/4g8ftn8W $_z=T~h5]XDw3@$WdooK|dd1̆ʼm/nJ i]@gyĆZOF;zql!pYB<Zm:dJ=yّ))0a/`^\A.Ç#!uG0>/j6HL^0 (bӸ_-C,;UG Votf~O3J[.Ǫ.: K:`+VF̵gJ#1U^'0l Kozw_O~X d *F-XYlz;~^S>rN^յebdGYRet3P ڛUKP ~n[zOUwo23ٌ\k5)HQMd|ZLOG/@xr qԼ0XMBoMTv{EnɅl+ ,+>W~ Dufy)=[ƫy~a9^D03%cMM23XIirecJGy^%.Gba gjQP/O9ڟpO 7Neb,wsKk>rǞhzK-/WBiv*- k"TzW?wlkk;hY l]EP޵ QEm.:RC ~Hb]q FnL mC*2ԇOrwjqƸ..zp BP rIgR, IDx,B¾ Υ8SC yaʎPS1x0ԴC9j=x)Tv0kx{*ϻm]>b *x{*oC,TKaZ Ή99 ɥ%!EyE% Z\y)9>y \i PQP.Pg~FqfUj~Fsp *U) I%@i9)J: XBZ9e:֛q9xU[o0~ِn $HmmӺj=En&fYΠ;qzK[9߹74C*6+4Q)2&.:WhgLbS@e'&# fFqGݪH42pw_+Պw7jêZe<{i6s͓8k^u*KD*F@~Xic)|:3zmQCgE&6$9,:bM5 C׻D*jF|~&q9xz@z,-;m\br-N>1J8e*nqjLLv޽{׮B}*4`p1A.Oc×/Z'#e 7pÂ7@<(gk ,b"}AtxJaev{2XTyвN}i:&Mw0BIWi>X2g"37e)JaA,f__.bqn۽ӠK$HYc%M"!qT>N -qռ .1vmq7o-MU`r&n63ձ*u*7Ŷb4|mw( %Ĝ^۞ZSeML56&ŰtBCb›;#*ۡDXﭿ [yE{ޙ/ y1\v3`Aehr67=Mx;)rTd6dFB.Ax;*rYd {||IqAff&!V8G] xXmo6 .u6`i ȶUlAE!2msQ$Cڦ]^(Y~Im6}+uA& pD] ')z$^ݡxF+,SΠG8"D4 0rȉ샟`0?EԾ.!C|FQ/$”g>Eϟ>Y)DA1zA<$ի:MRB%U3Fu%i_7x)#aSxYų8AQ\lÙs<'sx9,*Zۮr']%ZA좤NGc( 'B|V2db71|.dlॏX&VVS+OCplʼn cU}D+}KKqќ,1- Pi2q3 9W#@*?$N,=y|=u\quwhp4@2l;zt[2\ָn`1 6GO!Aw_<˞XF7+-yFN7آoW݅n:M}s3}!TK|!=nd/^VB'5MBRԶ#WMyl[@A0$!r;CreOD,&s0˓9RhO)I@&q]pȎSs(óp[d['v_T#="cx)3 {ܾHbɫ%y @n CcA!'\9C2@0_sۼz|Mr%7ϵcMlWnVnGt'p.EsA$=kZE HG5ֳ8e{IV|V t^.ۭhbj”=/#LF hwR Uc ۴wྲྀdX{k/x./"I%?JUP-(8kxqw?j#dvCͯ ϊrjՎ 15Sk4o6EʰUz;eL͂U)ѓʧT+e):/MB6xؠZ dW9ӷ4&=Đ>!>ќ,?o0k Ax;jbfi4|E)/O$%mdgV(&(hi8E*hii}2K48jmt~F_FL: y)9yU60)B ٩`6`1PT-cDR2Bř'aQ:Wex;jyb(BFb^JNdi^9LBvjm ,elevl%x;jC$\Yl$%%+2S2J=4I'Z"%g! ziޒ$AHF ZCo?8z %O2.eA/,K5Kh^+L,+|(8MCk`k8Y:l`k{ko,4(@I,0 MH({>&eo\Ot2xx>i__}ج^e!1M67ެΠLLy(AFEwL8DםA}?&̒1Hcql[#6iK;yL?&߿' ژƫْs9(q[3t%C2d X"'ef44O(GUCnٓk6|CdM6!''d|qG[NwrN&N;5%넮.a&>mRپL __+9 tЏB6I8M3rmFϘ!HT/LQ&!cM Z`Dm~&tP #6s7Xks8|ldo ȤP.:o*bx~!`!I@87.rȉa*pBpUYkp=I 9/?B@l5K'8Q ø~?2"qᇁA=X\k/C[gr`cJ@ȣGg\ K<ɲ6u `P4 ;{Λgu}͢b A*Qɱ2݁pFoVO}&Ch0͊-LEƋcb/_;|1>9z~U9rTrՐBB߃Owr%l){ ojWŤb79ł*Z6p!Y 6l!soՂ=XIqP1? .vN O2L'~۠+?m6'GnKb2IC,gO2hfic49bftyd|(%z k Nq{wUFh#شZJIlm'/ kq{ގop֚Up˙g3yiFs->A]j50̖;̘NjVy -pCnI;g˴Xũ L i@ >;$~7CpX#?L(xZ)n*'`pUj^:M'hNywܽhj$Ua[hv:AJ8/._Mm ՞R2Ҵsxfkg(Pz #%Sպ[6jJZsCf&'EyH; $H~dAcX5%(Q|ȽAlO66^=~Zd'/!Rn bMC6_H)X~atU䐴夣9A\aJ9$o B-Cni?rCgQ-VΈڙXwکδ#Gc{=- n[|[yKoodX05M}e7"'\\essŻeF/l&: 64Xk)Z+ lq4o\&Ǒ<7mH^tEAK/X\|QC8MhXD"1jKV q3Tr<Ď>f 4KI# OL#`iL1, L|_6dLN1$K\_>[Lj\n4jrɂ_OQ0gpL1DJRob ܰ./_52cZU/fؤ+N-1VR[\عkF8}9oo0k7+@?k6CI4hieEhq.+5" >c+9U:w)aK q~6Glߎn1((fǩ v0sT`3@%w*\f5N|:Ց;kS=J,Sf}9JX͖V,)7$_h@u?^Mg~֥ՅZs'-'RF^.g0/_ɯLDšyd׺ |U anY&~6&Kqi&,5].߄u+O m<AM M2HRY/=1&*c|KBQ8 a_P~<-=R:y|w)A=)Z?\V(k=x_ax :S^iMtt~tNyƒK[`K̻c*f:&syכC\+}DM\& 0mպgu8Si9VA)%Yzyuv R1ىN2loA]h|2${,GvwGSNZ;QA\} T@h&NKi@*QTs^j0DeךnLMUO`a"\eYځYoC\ݥ`BFUҒ6U(%;K.հM\}M/:e0+N&I ڔ[.i0 CXeWE2]c~9"#I!/qIy.vV5hھMȌ!Q43I#|1:^P"תEYβ["O@JOx8E}o 0DǴM$i.-|gZYkla20;R@!7e,+],%\db,Y'12ٚbqъַ\sY&b^IZ8N@zTgn!}QqF~-jj)+wbqJRK̾.lx<2B^yCoYɔ.kv\@trJ xY-o.ЬPy&Qoi+^ig/Q] P>",ԛ$С[w'PO44!>zD3 fCg>8oޮC{7|Ӎ?<ق\iP.|0-KM:hxKf-LHQ>Rb{5&#e֘H1f̢AfY1taꄳ Wx9hOG~@Yk#jlr%y El&D4~im5W:;m@Ff#B$0F-H0mּbA\ĬJASǛ.iT]#=-JT9&g.XLY>܄vf G-=BDʿ=\1J(݅\'A `n@BH<n-Gv4ʻE+YtrKrTHt&8sBj.Yd%'ԩ=,FLγ,gjƏe&EXMao 뤡8O^ !)].*VͬaOt Bp#5T'vR.23}SQIP2}Hž[m"98c_,"rhN$=Ȝn/1ž3=dAUGI+N!eG:-4*[a bٽy·[5(!KaM /kzv {Upf:ÖBUrg bMUqh3&3狄VV6E=3N{珊*1h3@-Ziʣ/uxz" N9; iZ{Ɣ\;#C1>){o$եD3=% ʚH"֪b?&VxuaEl— ΂{H{cN\{|YNMyƖNPm)D"ѧd`D˳l!1ڱ]a ۣh"!=$3%tM1. nfi` s/UY% S4Vր%mrn{S8 ża~Oc };.?*'G>aQ o E`d^n *Qh'٭owg Ub&^vAW퉒™>=y/C'o*]L̻袰DhqNSZ&Y$y`k2 &M谧c Y&zkF2`ecW{)n^VD ;aF,t<9|-r1yIR ;;o-ߣB}(ʖ_ȏUo :OT2=[Y{C }*Ǧ ɭ/[pDzGږ- (N]oGE~'kRxm&|3Na8m[qIva$SP/;?V\9͞V-6~+;;:nUJvhMwa^:])?U&J}o!Pr iFQD}.:tg=I~Ҫ61&d&tQaP׹P~:ͤSޘslA}jw]|q_ je'$pUg2=9&Jniqh{'Q1yM=cYl YU>Q&Iݨ|Ŭ&C$C<]7H D 5"Ω5l?3 ܴD:uLt-,J#K \3xT$ Ge׷ū+!u{y0p&!{~c'),Cm^ 8[9r]7<[y+os(?װU:|w&O0r5V%L ~Q[|̥ql8EqFN."5}A-YBI6 xN zv-CƯx)4TinTv+ ;fub4̸Ӭ(|p*:xV 2Lᖞ<_m_W Y* o/xUrlvԼ4.:4 HxU۟6a.Ex 23JRs6G0Ncļq ksp@dKvl ͖әY\E\l&1pN-y#Py.S7Ҙ Xɨ0AKt=ZP9‚upt(7xONQR_ZZT9q!^l @xOis"4F㲓Ô\= * 8344RKsJl2JRsSKRsS5J r%: j%v` |ʇY8O9fsF;Y9 xx!ib֓6vf,:7d9^]<@~: d'䕟|/r乒wHL~ǯ29QAbrdoED'\'šj\ >f, >X 9@'ɵM9AҎ Htr4//ДZiɌғ'mVd$$T7) {S"DxҔiYQt'{3:;F{8*$;畤VXO%6Ii1qJ5K<ĝǢ2k93m'*9 bL\ĥX&[N~+3NPCr3' *%&q*m. boma, >X ز9@'ɵ-Y9AҎ Htr4//ЂZiɌғ'mV$$U7)gyjAmT/_:vUb([ 47gjV axT[F~ƿ∨+MZP -e,cawƚKR`8;܌ &I PATo(xF:O`9]!NC$B& @\D{py WѧĜ`Ƴ%,T0i.)#Rb_541 eQJtw}xw&tl|d=wlD)9G˵?U/ɳ`{ Tg~PsuҢ qBZASD橺3CG:#hY>H+VRz|od.0l,c=a{lmV`nbȚZb`pe$ \ %3{OOpyq#aK3 m1fINi1a>No<ǖCwÙSBT:Ji¯^JP.Kn]J9[y۩: Cbݝ$nj`8{hzW\顾'.ld$bhdp=g]Omgԇ{2ƛ UXR&k,}3V*e7N-6Lu~f6||{.׋?kI}:Ȟ{U"g8XYOQMc3Bi?PpYfE3KV^{VWa֥{c׃I6N%1:7:SXnuEC]•wnMM>RӾS=.&O9 q7T4yݸD!owKѸa58Ui/h%Ӹ{[Vn,^;Z54d'7_ dx{r[e[R'+ y@kxrRe9&!k.POc#RcĜo&MLfl+oT"WxlF̼ԢĜ͋'ofs LSHN,p,JMTU  pv *Tx?8#dCAɗ}kRsSpvq5IhLP*J-.άJUU0[|rd.em`Gk.N H f&'wt  NfR#K]#\].+¼  t@<|Zd%1>l`c&g5GҝXSb64(55@9%: pI,I|Wz$g-'`,)Ό+0UdV.vA\$8RKJ uvv ƕ^x[οl %6g| MtDxWo6~C&Y:%kqJ,X2< D\UR#}GQ~^ܡ6?w:Z0&I]q.5D'L/PO*KIVpK7L=Ƃ@CmbIZ +Ye))#RdPS'p~v֘Z+ʒL "U}WFy_$([ue)ThsS%qhJ{9wmɂFyOE9UodUWƗiek*!+Y3h銵ZqM5Ĺ~5޸~A~/T%aG)*{ȈTkH8F 0ENL 1fq'U `؋֋}85<#*>5`z1`_-?JstTw˩7 "w>qA%Fg1ߜ,(n<%q?A2&I@żz>j9zLR|2wV͹m$^4.pq1eTǵ9FlLlDlm3 c6p&wFHl~QQ~N`ozoDj`i"}, N̏81AT)Ja%Dd\|t2lvE׮L4sl܏X#( "ןM:w՟Ƃ^L Jj[mvV ~1Zߡ+XjQQ<Q8NRi\m8a}\pb]Eܽ<𳈙,P Q>?-< N@{]\x֜x=@.=w1myz6NKsP % )[$= ^4)b2WDE8Z>0 izqz嶇hI't^opbFZPRtXw87ˠfQM^QD q#j} G*u&7ykQY~ӹϚ$8 r7@&a;U[+n;t}0FBli'֖\6' *с̋o9߶:Nn:A~c" Imۢۗ4x}KOКJ{}]E{?[U`RJ#ͬD5xkPSG!%$'5ou\ F Z řUi~!F ťIΉ _L-ȹ#tfa c g3h QoxkP/a/rj^Jf*%0xkP9ɿ 3>3$(/1g3!lHpqBqfUj~FHppzFMx;5dFMl/lhx;Y#~x;C-sp_kDHBIr&Sfa.NPɷY홀2lkżxU[F~ƿbDTd#wU@S h"c[3cuIg|C};os5G+cq֞xG?''3C')L"ș~@v=-5G,\ega1V ^^v*l} KQ3^b͖.>=+n-PUi0'ono70,SV0EQrJUڇ}.uIXLnӗp5ѕ`>~vlMZvlkk=Kk]'(Ԩ>y'duPM*I{9FTV}=[8n^1Lh[.VEO@Tj^yMvBqy*{mgiOsgwoo*~cKUp"j5ʪ݌ -m쫐ҵw(&?5%,Ih#8qԯʻ/Y,p+{M߬5ewQ&K)K[kU{i@BMu1ox;#QtC73BFb^JNjQnLllц ٩`1k.Nd1PT z?d{ YE6qbGx;#vFlkƜL&sLȦ>M\"@1 _ukDc"nx(QtCh0%=xZs8w6}NvwǦwc٦%Ʒ} B8Mݽd {zz_?hϻ肱0Kp"nS0M&h]`:Bh„C)BFăVB ΢:`Ż_oxE~ڦ~mL3S+&㹦i Ke/61??\ǐ#0IBXM>Gizi+gzA1ƾE~ {n.G~EXѺ<-ޗ-ڤmAlrf5ۚa˫ Z8mΌ3}}>د~hJ!ꁫ[&aO"1.]v_VE&ŘY#sg˜uz& 'Ǘ9NUdLfZ Up ;*ρ S]`28ZI%z ",v1snonsvK>QrkC!>Pm%B5v !~0/O8$ ,J ԫFMSovWt҄Y_Y5 ˺_?zR"5'%}U\ א`'„Fƿl ;ͫl{!;P )n!bT`3Q{;35,,5Lg$H` Pk7 =ذxЭ@I@>u<"YL Bta ʒ}Zn_;l7XG8.q⍘Xx!X5ó3\NG8ۧzx#/u#A|1Fd '=fuX$d8o"OqZ^N8ֲG@#9Oכ#LKDx ,/u"I?;;> %<ӑrKx,GN'H4aa) JïS[k<[I>(Z+']&E-iaOgUIV$&؂[ҿZnC-x*_ZwObC7$B~H{*y.$Ѿ $%88D&ñ>ݵ.ъpxJQ%9BpY?A0\Mzi-#.xR/yV5D4#RaWU?cjY!܎3_:׉ 'cn8A L"h ' JEw-v"O ,VQ8x膐:EԨOj$]G 4Ao PݟXf85 ؘ{?{}9\i5+P 843LG=E?ߺ l_RاqTrO+LaRdž"?-$Ϟp鯴J} sxۖ5{3x}u8A`2C*|]C]C'_|\|/'HKO| 7xۖ=#{Cd)!'yD'/՝b2,Wz'L>09Cq^&b x6qo=7HO.ܫ N*VxoC#OqAf|f^IjQ^bƄͯSY pghxo%; {\x۫Wc>^|Ll3xXmo6,[v&]oيu" KFbNXT2yW4 8Db0F^q}L4l.@D/EqĢ2G#zn5Z0ˑBF O)̷yҋt)sϡ0<7f2iQ@Uz%6$cxw;5L@U !юuaH\IQ }2j \}`۫/ Qԃ0NSc9xː X1EE\*@K"`iϡ_ &f;vB,:N۱<5ۘ<5Ѧ)A{̱LsesD&%K]Lh@Y_>r.9f6!4J(r{C Wui#FfiGw){uQsF&t^3q7ִ9syt ,Y&UfA!/A'NMfB2XHNd[ESmɊ% ux퐇Y PoWI.NM!Z&WP 餟u@5EOc'=]9%FTT[<jDŇ`|E籔QhFrL!TDrY9Y=+E]]# Ɖ u2gvx{sF{Q xT,( spi_internaluq&TaddEntry<c /void )n*/ TSS_RESULT J  DzH~K/* n@, */ L. :p !6Vzw}|P,4\'Bx{sOc;#OqAf|f^IjQ^bd~Ʌj噿L‘WRT9نYb[fNv}Fֲ͚,y|Z\!A>!\8&0m~uї 9}]4<(V `JsrKRSrSs*KKR4'呐 q sw ҴlkuFĔҒԊxj@JrR\>.UBJbJK 7 2`3fr#B仌et8ä7y#F^L\؍.19L` 'T-8|^)ĆݻӊRSC@QR\ `PtyA""9,//_KdQ5 4UuLx;q\c;#GIQ~iqjQfaF aW<mx;]}7 z8L>'\ v x;[}CW='g-s䧻i(y敤%(V  |ĜĒJҼ=%Mk.΢ԒҢ<נ xxO ?GxPBLkp\ O$,3p-m@4 gx;ѫw||IqAf|bJ\rE2C7dApT&09[9\.e_!d9p{lG(s&63lXxTuWx6(pxLu.FR7FO#xFc;_&ױhmXə1ٟElO:W`e4.B;W2xnu[:M$/@ )Mm5tMҳRq2ˁTNtvbz+NjEfm]ù*`i ?|K_ci8;khdS4T9x5JKjy.n%4 i㦪iMe5r{rA WI`Q@BD4U3fSavdLͻ뙠Ά N̥eFSwO'+Jɧ8uz9xUQ{΁6%PlixQ}C:,.!&5-xRJ@%ElmE ~@i6hI" @nMHk=^f潷 sS};KhgP#]v\ڦޒ2"Msۄn׳rcZA1!ҡ;ClrC?e $_ q7!i8!P/F* &O[-b܁pPyl[6!# a]57B( 05I>.mRPpĕ[cNPS3tWBEܿQȕA(Pͦ䱞i EmJ u,eP/@)/v"Mur|툏CXbI^Sr>I'RJӏjYza^|.x{pKaC=k3:qn~U fNxR]k0}~%b)] NRbla:f$#ɬ;2|t8B!WÌj nI ނ(`:8J0`"8(Q !?B$ JHGKq||Qm%[o4L)fƵb2HYÍir b<+yVd|m#߷?Jn_To+<{SKk38]ivNЪ*9GQ:N$yXb JBsJH.澨 /q9Z0/ڃq+k/C\b@|I0=ӲFCߤw$ԏL{1 _2$ ۰ƓBK}3h> P9bPNSHH8MunOFTei(fn8b=U~_[(R2&7ﻖtvKP|\U\71^w v{]'toXNf3c7fo'GmP!]7vuaOtNeSѱO[Ț+J|?G\!YAǴxmo:?_qIa] >ܭ \)LJ!dS7_'!4C?yr-Z0.Z"G$@4|aŦ!%C46[HD], 9:֥3GgW>O;!&A7bG:-ip0wh+ ~8[_e"U,{J?;[Sjy  < ']'pC,cGVY a$xaLhkDE#ߚ_"%C)tIZ&5VdFlhcckxw̢qW?yq%1iܝ_!ȋp➂cGAQ31gCdz42\3ܳ3~򢏠L9 }<}f8%Xf27Y[&0I$.0|Wd^\i4jtPg?(6BuB`"DCi*wTyÈ5MG;~,< <ߠ  Nc ÿY6_#9>*ʿ'@d/) &u^;8G\4nQ<| ˆ}EPfP$TtHHQJh5Z#WӁ}_wYEMf8L)WhG[(Z 4v A;D@$34O~$gK@hUz!Li] I3VPs͛A8[=I|^o ")%igiάok/}b] ]v-smw*j՝L3mww^t/ ߭;m`ҰDTf)5?&V i'\aG8ڮo3]:m7tӁ@e@w2rcj:wz}θ!fJwl}‡(:=;B>CUT[QkR-b]^W@JaNE=m-9oiVS: X(b1|c0 rlww*O!ǩ4;vT]v$:,=pW31Z׿[c_β (PS#׿h19<}w 6[uv'L0J!翬؟ӵ(Qf %tS:E::0kT'pKYϮzB:ǦzŹIOvTN#-{s`nquz3>&\'HGG"QE}sE 汓 Zn6J-ބ0k( `C!?Mnℂ@yM?03~<#nwoz?|@Ja06;/!hvr>{g@>M硁!erk5,.Sғ @JMoʘY>l1[cݚFig4]ض|yM1)s7=Qfzr"B0;jW ftNǙLJ0V x5s+.`*H_ONtz}@^op5p"`*A'B`9<uy*!9Ӹ"uT" ހx޴Pݣ5g穿$pU C)X ș[%wtȐ×'kkTÍxM$>'vrU _[\\5x=wJ4S|ҔDgvhPeqoK-m{ll}p̘9pY#~ǐTMW#^EH/^6YݠN-k Q\?c?٭,Y jmSwxu ǷcKF@tE-,xArw=wLF2~l!N5:0pO<! vr^@EVxia)`}z}V7r[vZSgwSzQ4X.>y :F/PfSg&omyif3IFA6*9l2t ? S03j͜cRfX zu'˻̄ & (MG9!hi2a_/o>%ntT\ZK1R^|05\WKaQ9ZM&)GZh7R,rkXնgë2i&$("UԆۻ3Im8Mm2f.P6ѥ*|6ZRR`~RC:?bDF+gZ;dO#5q8jYp9*5^qҗDؒ)ʖvfŻC6VyjONdYsjX(|%ku+rjSaP s/\} |s!!{NthXY'ekofz5JQ_2μz<:y+i\IQaNIC1RxPds%wI EZ*0NjJtl?*U2*(àTڽ۠ݛMfk qf2+󳞝+9#_ERH8گ&~o 1ҹhäT q[+lHa\f K둡_r(i;W/d8AMVCm@09_'KKB)o8m{2)~J+>\4=ʳ7JxHh4acmY.57ݰQ92a~޽Kp*//p(e[C}B3-#B_sػNڣB/9`ǼnϽH.ae!K*w p0 gx8l,pe3wLJ*uI_ rR)SΏJIBFxe?WD쩈[)*/[6DSͿՒ—CKDZ'rLQb_ٓY.2DТɫf<Ȁ|] FfT϶{ev*%sdbmS0Aۙ~s}(B _p,O{nQxk>g?Y*M1&x~ 4'O~[5e ,JD7+s@%#Im~/Q¿9K[+3MA#%5Ysf#z>$}8#^x;~ %m~k ,(.$$+N@aro|@bT$x;q~ <&'nQdn. Kx;q> ܓE=7>EC~N7g&ݜ$*d5YI}CD`6?by/;[`b  Y'/1E֓㣣"'51|̣ɜ罂Xͻ~0NdbawFT6O =(0PӚ3(5U#%$qA[ՙ\9RlswRTnxۺ> ܙi I9I\8QxewL=9֍{sQ87Jcs<6 Y쬓ʂ6Ǻ1q(ɅA4d' o~5Bh{y9YFo^q'ׂ3?ėIa5gZQjFJbIdF %ܛ燫3 :y#uT_Jxq> ›g snVwZjxq> !֓ &grM>/Ƴyh4aѲ) mcxq_a+V{x,_> f% Y}v9_V6xŔoAdz.ZJJ)Vv]b5[$E,P֕M/bh4/^&FM<Md'z7?DgwZ$e~7}fu3M^#N?'|N.t#p|< 0[&bzxP={ kAj3WaX` rUa^c&=;Y9Rj\ dLX9#=p 7"o\eT|Dw7 ky R l6tr'|1HVx\֌싘i< to Y.e=ݜo\9/w8MJQĜj)RH`޲,|nݧTS&z"AE!pP zˡ-J>IJ6 6t x" 3 KْzRZ#쥫]ҫ e)Iߎç;A'ɝ k'on^NhD  tK6oT49Nosr#$LT:s3s*Cr`!:SRsRKR2`7a%SM퓜8Iy]Vx[5%s+'dd&W(9LNd+e q|M"%$18*UGQ(p,-QP+J-AHx 9$B|=\tqr*|%,#+XrDYqbQ}BiXO֛)=Y^f/wn]u@21N)W4yhJw!Jh9nrQanUo&;@h fW-hl [\wxS]o0}N~U'MI 4< uU!4Enr";m߱s:>׾cӶ MIL(^Xz߻kq6c 4(43z Ȫэ t6sdλ R- ZkY, x=JVXQma$=z e57k̳aCU߇փ#g?B3'h=q=:j#&:4{|,mpOxWnF}bvCj4M[DdIyZJ܆& rFIŎE fvgϜY} 0OKPBI 0-r #QYdU S@ʬ*"s ~_Zu!V/-P, JĝPOՋƩeY?4J_KHI|Nd ]#*$~vK}ß\|GHv^GaފDH <д²g3ן+a@DԻ"n$2/&A9Hjz~e <w#ɸ0 PFA*o3oќ }I}q|= 7s>@<v]~ Yb2+6`!>8Ĉň(J]eԻЧϨ_F6eg0F(I+y_\YQG8o-# 2=AeUSw6S^sم}ɦ̾qw3t5h򀑍l%C4Yj'QpĸQU~RS33ϖ]t<;n{0Gk4'z=. mp( @aXqu0$ٯ/#_+sEn7Hiڲo_8wޭ02"A6aV=6z];2v0b %#.нol@ Դ=ڤfL^ C-Su9D^-֙@71QRl#lʋeVQbϞNQ3B4B W'jK?1QSZ"xRrtӣ0kd|`cU<} [Ju(k @و0O7'ơ&YW7zjB?aK Ǩ1IVy%(X&¼k 2E2C MALIEUM9~jh߻c-xLa$w aw6G ۖ 5)la~x/te:RǗoGZf<]07n՗Ӻ;P,uMFQRj=,e3q(AHn9ܮ0C*ܺgW(vb&vAX;~p(֭ԯf"䰑X* ȆuuՄ K"Dd[n{ ,S[ ==0 * <2URaEd㠙TC|6s <睏A}'R=J=~"!(L&p&Բ4g +Ì޴c | _ÂYk^S aEPX%̊!m^}KJq?NHj!!G6G"\C|Gw88iKZίVwP3<I'Hkz?'ffavurM9mʟfn3'wx@;,GӀ=fASyxen*R9r $l7(wL)sAyVXO{vg)oڲ5`'x"-#ǃ롿)Y\5x}Bs.- ҟv5c팑!!A)y%E!@A ɩɩ~!FZ  a9 e% u\٭8C'gw q titI9d@Zsqqf)h ۤ`k tOQjIiQBHpkPN.A@C5&L$.[R\4D753Ddd[xKRJT]W|E9 HP\cp|pkp5W-wVqx7o\mc/ q 4R8S!K[u6K4.ē3ǝIҼl]D*kq[mE=UX[?8AQއ)!;3)YǪXooACJ[Sie|7,zw"* & yW)7d94_e62UQ3q\\2rpeĪxp 1m,:ԒAxq(,^cvg[~qVZ-%t55"ԫ\(Y-K4JdpNb`2*R|0x@I\&Rs@I/ O=tpE8& :$z#_QʼSe_^l+Z %brp]<Y'a^-GkӘ&tneP+2s޳Nd Ӊ1Y"I9Mؼٟ~8>qqBy)NŔA,z7Et6?+6FC۴&ByئR8tj#`A b< m\LrWUP\aGs KXN5MoMiZcMm\>avkDOc`g*(bA{ AtLICQʐ@63Ğr}ߙ+oH_ȇ5oxcƔlQff+Pfgڒ6Yzu6rd4ځPBL.娖}?k _ ` TK4#᭧[m}:͠ǚ qb>Fv`WJZq䃷.~c Lk)3}S֡1гqųb 6B·ZtQ_ha3ۣZEA#vDF q(4G4##sF2V8· |CS (D/? )q%Ox/^Vi$"43v 1Ԓ|;u(]dڏLxFCbŌx5cx:쫴`;'ȦaXkMٌ;򂭵 ({|bvP6+v;>:o;[Zibn{1KUR0=6e쐢_԰a,%טeRLTUU8 ܋ - oqMiK2kX7Ż<\k7j67b4 "f# T\7Bxyc꿙x@ܳtG-IJcÂ0ZSf2Q䳩nw[x/tTDŽlca%'AhӀ}gb3խJ2puJ$:0KaBTTՖk2U$c.HJ?`rFH,qrSSZ(pS__Fs-(zd9i2[(iQ`?x+=vQ{6*D! RBm6 9#>Z{,p >rJ^fnOqwEdfL-c&cK;N4`XM`(n7 p0'1A/O Yr r8)-EikȎ24Ys rǹ:uk{^(rUEoޠ|" zrCGlaӲ:麺ܘ녾X?p tt)-4ymQm6U[{*Jk~֔c+ʼnA pAꨞfP.ד6.kre7J4ʼ䉖-W(ɋ-Va@!c%K$+{-b;l~zRos85 >7EiK~^7<,]|+(j&FFvdGBlpkp Ņ(t5mH Gi=*% fL,w ~~}.do)ꔜڂ!Gدx:}}+WT PƂ%<Ա9M2PSYZ?G{.7ooz1"7 =U-? -9q1b(w>7 |.7~*6ۅgF \yܫxLbW{"~E5GFC0ʙ #DU<; \.lc]aDOp% ;œR*Vc̱·yJI0^~~_!1)[B|ypΆN8zHX+m-tS_^c @|b^Y^XeX6:⯂$p'tE+k. @xmha%ffs1c̴4xPOxg_o.NTop|kpHsH{cؤZ9Rp6L0Tf*dm<Ni;BxJ84+>_e%TPM_DIGEST pubKeyHash “_~xml}Y?1jd)hhd$+*&'kgVi8{8jN~+ZTYTPsnM.N-Ey%M+?َcr<5OZQj* E7XFg a8eɼ<\X&OfU,.!PPZX1YB|&sM:4yx=-vznvxmmBF)SxmmBF&efCI.xmmBFdg敤%l`\8+6#A 4nxk4o2ͨB\xcdCBqbrQfZfrBReIj>V~iKbIZJjrt~ZZqjId9iyE7e;1vRxidU"9y';sNY$_ZXY```==O TVfޝ<d xW]o6}~biIC6ٰ}di@Q[/ˎu@9sy.yy'vPIi?JhYxD,D{I,M0>E(a)0rB1rR,~dhD ¨4!' '@]iB(]bs"Yk8zP!chns&X궮˞ڵK [cl b%8|4zo;dlf91|>Mbƅg?xC>~u Ll"8q9!B%Bh>/P0M#20]b1;uw0{=;iOzkwzIl$ X*$S^q:/1*pu : ,.ڷc }p8taMz2Z:$Do xP".0|EiQ/;wO8ӕPJw s`z3}_kU&A~@W[A|<6p&k8g\89ߥh(`BDx57A-u\gjfP,o2w'|s.23y~/udP=yR ]ycl$t7|q8k.?d23FA:.'4TBh7C^&`rʉ~8i#{h}@k7UMbӶF+95D>|e5J(?_]IEN~Z~kCK=hq//}3Wf)9tfNsG~W0rP_jV+{f!6kz.CvSٮp+G_J/|Z^,;eUH!Q!o=J̦y̍ ;̍9&3~@搄:OEa~5l7s"\f$5 [ڊ9v .hUWڦz]\cCXǭK X5µ/1g=][ N.8qb؝vV>~eBˮ*+WѴ_itIB Ɠlsxk2n20lܧ xk2g4aƹ3R4B=B6W`>ɸy6sn-CBxmRي0}⒁2e>L;8npbZJ1-'j]H2{g?{DzmmxƄf9LaRCJVL&)Td !@Ze 3IJ0b<vo&Gja`Zlko.;xoz!w\de3M^uwrqy ).6%”z3Zwv85]t hE׼_]rs XE H8&(MY/be"**t%Icfh'5R jum8ϒK8)˫^w `&Жg <8KLd<=)4I#Q–d:~MBȩ4d ?\54k(( nܓPbVH8܌غ|n+|e"6V c+(<[H8PMu24r7A4ǃᩏ:q3/ʇu^(7?𻭈3Q͠rtm;? ~ *|? }"䎉?UxXoF488^U2@@,cƬZ9w{gw ФmZv>v>~3;k܂sЈ0A0 %41O6-$ ȧX%ORAb <";% r LI6[N+ }[P҄1RAwVrM^^{_ ˲~,9_t]V^IuS,I&9ӂ )DwuVK~ԓݐ MlhJWphL% Hey-,`zӁo q"?|$'覥wgXlpAքq:'ێhz4? _U->'=0a*Wi-il[xz}) FFh[XiD{̦_ Ҍ2 }gly^o͚Rb}!x3q}Hɞr"cyz>9 $ѶJ1ٓ2P7֋ ޟ|'R6~IGiT?Wh ʑ_`e_!t .|[ 7`BAd4`n1}nKʅ rE`#!9D+=* U2Ao<&ZTja QX"aFP,es# ]*!:! pND\%`&z)(bh!youzk.lKgր=;0 qѭY#*[EOP_af!2a- xG+D' D#rZ0 >ٮpt=l}kc\' YʙٸPp4 t {־Rڲ؝LQ=:{D})oC{MvYķcNiϰjKh.`ST`Sv3B!)J Bm'y!71&:0ش)p:ZM#ѩhxCLi+URJsk\(Nӕ+Ov9wO10d%gZ;΁25 r|->s/Cu-Fxe`O.Y5=zuu``5 S*Ļfy(f7w5$#/}Fтە?ISH,60ʷ?ʈ䤣U5OmXSٵPo["m5U '~Ou7RѬ5cJ\k8ao]t1Ϩl5AqwwxwL[Q&07GUEquC3zGB-%3=D $cG6ɇ;f4x]{?d6~$ ol (蓚^ߑI$(55 SH8畤Vl%x;vDuC LI, E&'pn2 #xWmo8L~\W /-mVחlD5tLbFs]~c; |d<3~̛q 0`!FpOM%8+5QOD&Z58H&!{ gP f&n]Z'lP' NbN%TJ9\'LVprttz_gGqwqQ*pqU1-JWe)gm^QZ\^$fl/礭$۹=^vMX*oC"S3^9X̫2133gNUe uGChoCϛ |HLcuԤˆ`]X%\ >L]ڼc)J?=hh \mםZ ӄkzպAהG'?q0~W~n}]/nWTe7k]ZmAgBZ\{z \oUtcc^O#iroz:n03y{hwy `9I٥Y Lj64A O-)lcY 8ΜT۝FOosڒ./bQh8{w(xw7!џ)ȣ8@hO6UF8:fӾ8ٗ sj<(K9Syh?2Rд M0Yuzk[VΦxRԾ:^h{ @H7%.  ~ lk˜pFE%f 8 7{EQ8ւZQ"X8K1k+4-L-gUvBm,\ܗ}$\exF3xm%tf4xc'өaVgjΤ[+ntp|I݌-+#13cG7nZB \!hLIr@2 E(d?!&FRO[uhh-4_5% 2"|Clk} =M4 / F{^+Y?t߻=|PbsQJ>S橅M)a̓ljl;G5@4Ox+cF+KA|c*dvNϯEEt]'Nd(vvOofG7{cnkV.{ݖ-hB$)Ċ`(xAz:Ê^te^Û(D'(bpy_k/[I+C4ݎhP%ck᪝ZV]]?'ޡޘcʕGkdS'ҋ:i0m7.?!&bD=l1{S}bD#2a5VCշ>'?uL١AYl9s۵+.֜ukS,c鑕BkdZSxi`Ζ\م=ExVMoF=b Ȗ춗. ˴,DF"W.o ?$Ju>>͛7=v"Z LʸP ]!VpMDH0*1p0@-x0PFHbɬPp!19^"uv KIu結q'~56It۾MCrob-\kyKtdӵk&ɺ3k֠C7*VD[cHdZo28@[a0#VrF >MV8kySd*˳hmcͭU3??MGdJ|ZU%Ccd41У`VA+ZhH8XV̬B-N`%ؚ(jdlk!KL,÷Eĵ{B6ST 9q 2-(n ZӉ3JYqkf+l_״e{ܮ"Jyr{ E|*V̂1pϊkV(*VQH@H̩ш\bơs߇$ZeBv{y>>o%'%89_V*a0(g0ax\W8YnTXUc%Ẩ.Ure(Sv =CL i]^a(HD~쎍W 8]%#hGWc?Z w[ԭw;ʩi{$x[  EgC Z) 1~R?BƖ(lqf.1H\^=z}`Z `XI}*7mNr^~H c AQy[6Q p" sӷ5Z˃|rvx1 ;xch慵k&zV%˻R~!Z.lο͞l?x%YlC dqf$fVx^ spi_internalaZ#ifndef TSS_SPEC_COMPLIANCELe*#endifͳc)  ipmx$Ad$FԢ%Y'_ff ,Ǯُ݅&0 3 x$'a#GIQ~iqjQy_8XkxYmo8]o- e8NlXnb!m3E-I5= )ɒ#7Y_~h"rfypiЂ!XX׾fa,E¤^TK*&RĠD*;p\?>cqzMd-ba#Dk.b?T)~CJC7VIA ~kutZu¶Iqy#V]eRb[񢺖a-֍u'ZaNKYSS RͣmUdN%XT67C e;)%[ъ>b 3~a$:0cGy"6.E`ҷxTiCŊɴ?!$?2黷i#QęYѱp h)۰ cn7ӿwR? n.Gjfߍ%a52Tq'ݜyl6T%6QDYU nT*HLqȊ|~::G'XlV'.<, A dh0F}l(Kη6W$Uh-?VLV]5SV3-1ArH)*ՔU"1?LТ'=coo@-^!vNXݸ! nݫԻ:E_J!s$>^ǔad'V8ʴ{FrR5SͿ7vןL՟t.&DkDxMd+/lo;&j⿕ħ x.6?ψl%qa~R]IM6ݯBAn'G hͽF5c1$UTKӎ(2 5b˙H&y rO*00$\ V٩>.['.wy6 г:;u˘9/R9{%.kef(鄼"=S5d;0#1MÌL{ %77bf|cKC+$ml!C3Wln񮚳bxS86'o z3h$<͜,cX,1Jhɨ"m#+t'W^*5ißbTAt (UYov8,|G?ǠEE kۭttyݿM>={8<=?ׯ)Vl$kȩm⍕ ?ۻ=Y; '`; ݗ9F~2;{tg՝I2;_yگ0Rz,5ξ+i 7\ѻ\ d<\q3;u/”^E&ғ-mxs=v lkV[8{C֤Xt|Tֶߺ&hz~v7) OA!.af|vu<z`9քA2!; mSF׳+?K˛n?K:-xX` `*5~Jrυ}b1\E;\GyGOdB b+Le lԏ"Rwi ΟiERN ؀% 9#!sF>z*`؅\+rj6i@4Fp~>6"6/mx ֌O))tSS-Noϙ-(=˟-Qh+7fҪF"~|&IiC!_]xS}c(tX pXUE\>=Aҩ}x{oN*YIrŜ=kPyq̐wڿ)rq[d\KƜ\]m2x=s:tQ^8F?#Xl\xdfYW$-E-jx{msf֍'!lxnsff?FNY"s&+xnsff?Fw6FɅl@D!N.΂Ғ̜TMk.y6wrJjxnxf?Ƴ;9lel xnxd?F̼ԢĜͳY7wr,)5?Wg4xc^}zaxExcH}/d~ɚl37acKNO/).y%%$7<,xV[6~_q;z/I36b66Aj`Hi̦ wndz1ZS# 8I0t6yᜟP p`8)EEbYKc L DVrr8r4H]ŌA(gWKEWIa+QBW5rB5B9?efyTulw𶯼XFY' oYZS,vwKOrzG4too9.<-o8c=x683Lpֵ&1+~aW Fvmy gmTe p|4M]r̋v$]|+[]+׳0]lAbIF."ZKA2=yHzC'$hVxn ;;Ϲ_+g 0O֕ 6A<+)ù,uo'qrnX|o;]gu&,KsV-gxJa&D#BŴigGO׳>ۄP1^{jGу8ծqj"bAk}(EFm"rdz%  E̤ԝ|Z̧2mn'p-cOVpM@ j8F;5H(ڀU.%&+U¦)PyWWl@G}Oirl zĖTb\T.OP{E258L\n&5胳Imo+EӋpũzik-O0RXDCud?2)c|A=EzV&|y= n_#Gl(zZUCԪYC;Xn@lj]M#*ҭz.iZS7 ӈĺ/'x"5St*1r(d$ncaRlS+=lk.N`1PT-cGden97q}c1nl^x"Ol*p%11lvx"}BFd! x"u}BFdg敤%l`,g {xVߏ6~SW$MwU^`/%! >!&qd;ƀm}yxhEL9?+eI8$Bp*Xq$`B (I[$g9.lfIzfxhI P?Fӌ9\;~g ,{.˜nO?4m$iǦP!)Ҫ2;a߹S,Se-sDi4`Guo_枻ls iY~KS&Lx?f[k"8`bP)lEsw֓l+ OQۉ73 }*nbˍJ6xI %g+O+G ]{|dTFI&Q qؙJZT$P|P,iH+<55"N/ӕE ,cW B_-p-9,`UAj%|r\fw$Lg8,-NBSBchiP h^/P 牪3 %ԭ8 @Eh[%9>dGjgMG>γE#$KYkomH_ bղ,e70qg9ktS(]s `LH`ZHuyBaӯ~'ɡ5ԽtjvEKW.UcgDObGhrk?{OPVJfQt9+r З͙%(F\ƥ@y읙gKV$辺uqrP7 GHƶ&rgv_{]^n_Ul֟9cݼxJFR?7G>ʏ:ZY7uBtuU" i\ц[qR8PQCWHJWLBҡ~tc:T(=/cwj p.O-A,ʾ԰]ԩb+^;yMRvP9}YxI.ٚ\Ŀץ);krnG6S }EVeF9mզ>0d4$a SAvXx*=Aj3fļϘy!l[J0ۚ"X U˘ f[Ӳ-uE[dqj$+mGI7Ӱ/C)l|r4!c_Ɔ nS5mدjej|]}t~h෫> /(xlnfYpV̂SA[>pC;Bpa˺Z^@ь$'QZ +~O'OFs2aYŖ'hBb49ؚq 2NSf|E uf>aHUU,/MX @F@:::ЊV5=2x@U״RH*7ln=ƏJ^'+۝xRX}T9cbxVWCT7Khj (xk>#a:0VQb^J~SeIjBJj懬 s Txk>+a#v&k#m#SXk}-C!X$#U!7B!5(R8*U!1''<5EAKɞ֓WqLnpb))-ʛX?$((1/%?W)?M#%$QSGDpqLRNKL*-xXmoF bS#prZ$o2S" MCƽ,.`7Uݙy˾h;8L6o)zVIP)I, 5,BFY`dy; s_(#=AmG,CO`W0KY_d.FoRbVQSja%IӋ}SS:'m.uO8-긣vCSpGmO39RR U(KEwe`BD {hdN 5J!SOtTB{<'*AY@@}9kjuYRkT`^AJrt`qCRFaX*cA(W_UEhTfNO(Qz9E/2=؂gv/zbXRų$f[BK[ˍc%m!@j ]'':F`y5 quw /x;V9se-3 Q۫ܓ1Pz#9|~F” јB9)gu.rmi&vQB,`b\{8"G(|.)fXPx{|ء`x5fs8t0ZlY;4"RZۈ &Z1#d$?eFbFڑ=QcGqeύ4ec>5e'[mXyc iޫ.vd[GFy8R+\l;zzѠ/#bɯDRL*waq[k!T>QbcBo-:ب c|euL8]80Yk)#FN#iu,ΊhH@XoOQoέ÷ÓۯRxjQ )ўM"KE7Q"]=k?5gКRnr᭞2;#bߟNz8GgѶ:"fkz Rެ0`4T焱VVjږ#ca$VxZ9TR SnZl4`gFʹѮÑf 90bN=Ώ& 3 V)3oJd؎{ۗ?~ǯ_ӟt8ޓL|L|8БXIH|K,L ӷD6!o"ɔwSeU0UmEM-_"&a ̛V&q\Mk5OqNm8Ll=8dfllr@\m5p`K&!翻1ϧs6Ө(<5w7{*xdtC7ŌRBAxlxC#GIqA|qjb6F9POc#ĢԔ<.N0p qUBd>wy,N]YZ&/cMǶTB)&xl` 851gra_BqFbQjJpjrQjOj8E*h!Nd2\;Y~[ 4O,Q6*)6޶Cm 29|#0aԏ%| k"xqO%0d"  s܇1O f ]0_QFH^!R$7\0QiH'˜n?ee2 ZZe>JQI|Vg2^h|"ј*zd}[wj6 Ixl>pWвl> sHD4MWKt3Xg70:6"Xݣlr20&rW C#0" rsSFp *bt|?!t̮LeCe $6I5 i]/f*w,y׫mAΞ_ʏ/4:tۙw]OSY8b9ǭr3E7$n)/0UbOUΖw%ޡ_sgMɵagW0NnEו+`?|#%$k7v2{tIg.Z.4fӂA!xF=70d\܄t}pteNvcZCg9{RϦNQyDZڗo}顐7?y`J-š97D,*vG"$Zp}&caa/V'Avu`UAzi beCJyj0q&Wߕ`ƪ@C/f%D-̖G1y9^Q@]~.!fw%ӎLirS8KeL&f)54NuHM{[8v'/r@pH_ -[R3oHMfBA-4Q!x3&X^Aw42^ax;.y@bC wFb^JNjOj-1ـ]c@FE_V!;̶KelvP3j/x;.yQlC.BqbrQfZfrBReIj>VqfZJjrt~ZZqjIfJ&CxTێ6}b Uw7$E%'A(J $ծ;m= gw#F҈0IbXf~'s"x q/$0a"">w(x*.̂ϏK!X(gaBRFA)[xwr3 eQV~*ۙMPj[g6y))oޓzcN.dNByUA<鹍l| ;d=mm[۹!9*hL}m־x#/F@flϼ,&Wr\,Έ-w }cy>}Vd/ פPl/TO#4m#U/A}5_cHƠEmuCIt &U j]Sox>fW]hL G{7FcQiVY8jiSF5۲,c0Ds/GfRY[B{H|lָ7$$H $\t4%d[;2b-o1y4.]'0>/w,ƀ(zӈADĬfo[; 0xd޹h\G.aSGf$Ք45ޓݖs 6;rV|tG[<UMfg]}j}Er&ӯo+c`Ӄkݴz)M=b ljzexDz8n'3BsQ IQŴWifSc*etZLpF7 a1M LR}x xwuϙtŬ8C=\|\2RrR'[30YsMndS߼Q#3MAC*`QY0@s,VUժ´̜%L94Ÿ8fVz9ؼTRC3󂁚u8@2:RKJRKsJgMIMIͳA hZjSR2ӸM"X}Xx;g3BFb^JNf)Bvjm ,el^*W-xW[6~&V20{7e2e"۪" XvN=v0XsNzm0d .h*IXJb 7nQϨj)rEQs@ J20\C$H &]iZ0كdWp$Ob*7'k2yj/^z$+Hټxp&_L#c 8 9Ӫq6Ma4G o^/AԬrJuͣ8TXk>VuXI6FC?_= ,^&RJf/(&8{ykoEu 򭏧6G-6[wՁ$V5*Ѹi"I ͆ÖhHs ??"vC>1CP.<_+,&8sT(zSx*+-'37x$?orx*sKzɌ]/2DxUmo6l IS+^زu %sQHCHQ֛" tsƕm,qG11 3ނ{Fs,fwO F r =`{|!C0z kӽ "S(0%0c8z,ﮯ߿?Wa$ʊ_3ڵa71LRekas(9}9 99 g4OePMbvfכPoAsDA0v n*~ LRgweLHnwY 9 Ϯ g鮅Qst/211F:-Qs\K lir)M+뙮K!3wrFdHc`:t.?5c`a6X%bHԇ3FKѮH?s}F0Imԡ+Gyl47*#!ݗ.\o tS(5\4 T. eLg*ԬULLdƳBB{9'sU۽A`H~, |Н ŲeX+b@x~ISN{M9^wz|Oj R,T~o]l _GA)Oysعj?yBBjr=}!x 琈qh n _B{*NK&:R SCrH*@GY:ƴN.-5:uj_ǎDˮխ`bv ;_M̺ll်,R,5)BWՇt&?C"JB^j{0|Cw~Ti*ku.Խ^$w_ z#9*s7SGX]rѰ[XǗ6 {u;zyvW\=` C8eJCv[?kW*KH<k.= 'gz=r_!>*r}Ҫ'ƿ+( x#=OjA JsKRJB2sSlRR}R8 ғ06z1q(d$N$6]C4 3#8ù( 'd2ٟYhSҜ!y%jP: !@@ wtw AVPZ KLO-.iLS@/3-3/1}kE_N ԠތshP_H|wZ~ZZqj(\tB}|4V_W I~!F-y<&sM~c5?d^<,*_rZMÙVq`qXOn`ѝ-"RXRZP0y dy^5'刯x#=CrA JsKRJB2sSlRR}R8 ғ06Vp/?x D6$^   nx'^rC Lb;4&`8Gnv}i y)9 99řUi!~.> ~>> Փ x$TR*K3sRSt0uM%ũ ;zA&q89ӊRSaNд )jPL>!Y|GxU[F~6U#@nFv+a Oh c2hfPi 7`s?wαqo`"KÆ(*$ Th'ARDgYM_kb.,X"X*X"'d0/%˩9JZ>{-~|c3ˣ)&U]PX$XhU8mWRޥӛe Y]{KAoKŲ8"9)6vPx2ӟZ`?z˂ z_e~gdjb ?OXߋ$onqK^ḚZ]>I6\2)='*,ρk @$'m$tc l|bpy:JHg\Y? *L=m)zL*}3i~ Ruڨ} a{ܮbPYom/ooÂd"<.-A_GD~6gSm sZ_p({8x:zán;ÎAmV`=ߟjG?5z'STN_4|l6-C4vظmm Τ*|;}4(Q[%k2p\x[ 8Gp6dF挙)>xmsF3k38gqtd!i$᤟4Bp,a޽ӻX5IX-=3{^MqHl7Bo#Hp":52%!F'!Y)=`ٔMD<EY' stboWs#p|FRHUyx>8bRoi[?$VBPV;%Thg ݮi.3욌M,S3D=;%A"Zb#EFJU4{FsMcdozL*hR&j5%Dk;Z G4Ԕ>}?MUd7|8UbѦ~ c` ?9#3yjQ%b /j9,'Ǎ^}O&2Q t !&,53k H'm u֨aN ` 0!\)i*" %HFNK4e9HVl"_Շ֐Dáb;4(82y4/X8X~xBReAKͼOAKƤFbp_d 1E4W7w"r~G!vLgz7әؾpT]j'|(wU'^lHfu̽ 5$Qk?V yNES l&Wm!R8uLt>),Oł%UdM<Eyx!{pujGRٕtK\m3w:R[+\r3;|Ωi">"op;\ߢ{7(\J},4ygaK g((ohw.$xw뻌g/>d+ Agpv{9FD5MTx,(2$uJvXWp@T.Kc݂e_r0B#9D9jiܪS6Z fef0?޴Q߄g|fP6Fцoi+j%D>R:p5a/J7u"k?AUv!?qk?𤩆ւ Z jN#Y3ڲ`8Mh'QK$$FO͒Jq }3lwz{(K)px?|9+S@fOˌ Z Dr';r6X w`:Z D bO.e qp<_'ۈ—kE?M!5`[g728x~gBF&3N'/>9K 3#8ùB!BOTH9U|&?.yF%!TxeN`*hoT(韥I=䬦qnb]lkbIocN?<V ,h~ v&\1}k:tjN&aL .HQC1+ȗ ݌N;0\zqS#;2\,`g=%^~Mx\6LPElc#W7Ompx{xqɅv?T2o.a kOeڼZȞ~k3x;xaIɶ #CHx;xaCsp_kDHBIrJ&_5s~^IjEd}fM|U^ɭ7v{W`\F*sـ$l z"!< 2"xJbP|H!Xl+XOTasLDH %VRo!ΈÏ$I|$AfM`l0kYxa3b"糱O~/Ϸeln$Q{]'(E0xlCd>y'pM>˚6YC @`Cf)>dɁljx-7aqf6BQ_ZZYJ0K8.0r+$*l:udc@M(MJJML!`:ދUD' r v Q6瘼[mr?nF2xsFgsSy\\25N\r %‚pi:H'=tGF37 3-87hr98 >S E "󑭿BV|tSYgKqrm&<#7D,,49Egg_O)wA0Xn_ς( ,63||̅zgX}PvV]>cMUyP]gIogAg[4ݳ1f{1s8 &k?ʃvgg^{FG " yx[kz k j דCN{pG|;^ ЂtnVAKTECiWrb_͜f2n%W&(\fʂ[cuھB~i|{,B ۂ}-K_ 8K1#?9>z(}C,`7s[7ۮx˵u eiRƓWeuœNt8ЗEh\|EAq Gp+9Š>\vN '#Y9s@QyLK[0~LT2-c>;Wumd|࿳Cw%ωǏ2H$.A{3NE FgݰG [] :Gƅ]kA*}o[b[/cMe~#Cķh_W\96dsS^ d'OA{w Qi/:~⭜nʨ\θYq;I,jv,dl8Ж3 erGd {9щvfSx! %TצKMRﱪ'boAK I'tnРCpilka,$Υ6k rb꬀bN윍;pƎGy@> $k/ pٰŗ4<}tts:l&& D|>TU{+ ;fX([=xa-&},t0(!otD3Bc^9"§޿%'x$'@]smi *$/>7{8XD3j{Vz;Hru4c'>N: cw 8 hЧ8GH(fgDdOa% )1%Fk!.qOӰ)cdC]KHYkHKw/H)ᡂeKԎ+!g[dmLԾɦ!5sm#S,M@ FpԜ)Clt gdLc;$s$$]S7 CgQA A)jNFނS\5ef&8=-߅E 197AZ ^7bC\/#k憴@*M8hm vDQk(g%U-]\ТJ\˱3MiubRsR1:uӚ/ª28 )Q/ ŔVi G7jE%BM1cN*tFbj+^jS (QQSk.HC~^7@ͱQ RFFݝBpxơT1.c/06?~F%v3,EV?c;)Zel!V* (,rKw[UԋVd7ȭeZlj0ۦv#%lyaԢPPTkDwJeLATV˿q|W?/}ы]9 6T0s>0A8q&bG=V g{^?WJ[ @*:2gFЯpִ͍Ng7` 3j_X\/ՆѽMmH \; ݽ$=~T;m.g=,gcr.\ξʩ#^!PSLB&8b]p:m4͗(ӽn۷8xGccx )5LOW>OxGKkb*ߗ{@Iuu9U^H<% B^Z@\Sk;u8C7>t4cpq[G)S0=zs VܯBdQ7W]mgc 7)\ϋQNp|uEp ѠuLw㧸7G: 786dmQw^xqߣy`110Ђ^[5AI@xcep#b9?}ܸA诏yxMpf^˙13Twkwłր1qϩmM-S y=48oxSw>V|p( =pU+, Uitd߲]U邶;Va,J6WX=X ZA@T}ӱXҺ: -r{ Я_3g!N&Iwr *nqDpz<|b~v]1M`MNv gVnwEO)gf GԋYEL9Ṛ':jSA޶j˗rZT+ӓ QTV{;\9zSJ$',͒=}F;8T=}ctQmv%,HA>Y<=&185Gm͞sUDDupZlg5ݞS Mk|6( S. 8xGd;h&%c7aR;vRΦ"4δ~OIk52]yd=\J!K; Vb"x8PTG~ڋhѨzBrkqBuUm֟;C LhS=p-si{hp̷k0RH0wXB+}[$,"\Q U0gje9ܔݗүfu*H M|5k?d!-psA 1Mn J&eU-Th1*n~rڿgy?HWh|{"wUO=~JNcEQ$O^uZ8l% K$Xke6ףj1جbPVGj {o%L'"ne}A y+vȋvԴ|^Wtr0MyZ  9 y ٩)y%%F E Z\J )dxVpqL2+e9]JIAmr$RΓ%A"&3qM~c9Yb;7m&'͟Kasu~7 -x;qUfY3n>vȋvԴ|^Wtr0M5O[N>!i %9'J0srM> #j dI)X%9u HIq8j)!)HuLR%6yd2L0E m&'͟Kasuh1ix˸qaf"se&WdxY z(x[8qfMw,G"x1^ ]%gPK]5) a?xF; 52%,&fh { free(newIdKey)<6;)mxøqŸ)r1+xEQ , transport-o t }:;+XjxøqŸL133s(%lɶb~bX'M"8CtrԒҢ<Ҝk.ZԜɅ›{$0 bO`5e))͸6ɼެl "1s xxq4 bIL>)h= %:YV氼:lPVן, xqU7Xr |y9)N9I!@WLb @xŸARba>>KF,jɓ7N֑TcŢ"5DR"ޯ"ydz AG.b;Z.3e9"g: !ᇵY|fTqK!%xl<=Oc"Y:L2qcTRYC$(=i PpIUR6 VRL\ $yF`Ӄgomk<4*I=X{JElnb-y,pޅzЉaTgkÄZXڥՈW"溊^?x/pmʪl3;ŕjپHm0m61U[ꡩ3D"U7iêU˝޾(K dRR`J@zpiqkDR{JXp$z67\)$.u}Ո{k4Y85WK̶R~A^|9Ua :mb->g[E\7SfPF~QNxb\¸a#;E7*VR !xb¸ 3>3$(/1gc&aLw*M> 7y)Y\<\`!A.ٓ%'ﱖfTMlf_Z3$(/1g~͒\k5&Kr)me;]xqf#sVLrsqL`0yMd [qړn~n{(39Rh2#7ZJL^d%;yfG1غMv #_xkhcĸys=f.wԊԼdҒT'[l"e]ᜟG$Jz&ŚhԚ&D}hh '>sh654ZX{u NPf}k,D?U2'd~A,JX} T{ v0W?WU+J lҧ~85aO9[Hge{Dp@[R~[U,qWhhF:ǐWJ;$x>6!7l _0҇`3Ї+M=ATƤo&]y8K.eRE wւ/9VF EQ7+1:i/̼YA@b +hg`~-KN*UK1`a Ե'߾<'a(@ݮDVsi]wƝnbSA6Mi˼֭M, E\B *9|x&yj# Q&aF9+ 6^nQ^O_s,剁4\rw=pXlWS/Z5Ի^h.ӴȦ$YBʿ&|Yj W Jħ3陲QkɻFk"qN!?dڏ ߺvHqdsk(Ë#/w#;xJ{eOw1FY"},q_ [rBL=dӽ*t^U⫄Cn}F6[kk88Ef Bk#Ώ9~̹ E捄C;w _ք_fϓHOcolF&aѸ)Bz]`/ϡ%D"4@K0\O n<%kV0Z׌[U5O Q཯lqdOAZEM/wU-:O/%f: /O=]&d\?Cq=kU5Vls{gf6{T޻hQ0B13,c醁vI]ݦUaJ[ek wS^g_CT= [Fe+K8I7Ò/僔|GH╯E2ssFp{O-;y-r8iƮb/suMy(SSYKDtOĤNvbLJnǺ1wgL{u.T=ߺQICFꉾtTxk`;Gl.`>/W\⪠씓`ZbYo o!l?x[n0`"Ux[n0`,F̼ԢĜʂ{ɹ /*xuR[k@%&Ћiwb@WeWuAֲ$Iwt&df*?b|_ U||'Ke_22?v506sϊټNHr رW\h(£ʜT=0etgoe?W v{}9i{$)I_R &|CPS9 a1BrBTdIA…Aq*0"#$93 '?&5sG}1g2qaa2!ha0:u^%䲮9c.ㇾ2e2b㘏+WPG3פ* 7կY.SוrrOPn8x^-^eG@OtBsQpq`Fl4YXӶuLb˺-8e@XXl?_|0žO^v_QoΆq xYmoۺl 3dMl؀妀b+q۰Ah[$嶾kIQ")ڵuAl<1^ Gp/pQ^y8+(Y"KgP(Ol;|@N.>FN~Xa tm1"Lb?Bwe8AjK>e^7o_0^EeyD&R,^p_y~T^OWa,'PdilȚa> 'qSe"^ə]KT'V(0 ##g릻A ˜t:D kfHS r)VFE$$>m!SU*VB^UFGFitЈ1N 0o䠲Nx@Ynz aN#|HNjL,R$lW?ZE*wusZWwk-Oqc#:g#Γ(\nw*-]hMG@L ~D ZW',ğ5+MG?h2s}l:!QIx4{|j 7| ah g0!:I閠zGo9lކ~.7Eue{M5 'NJ{kTw0o~qU+g5UFT?2V9weĉ 7\mьo4B݉*k%}R70w<$ӡ#:\ @h$+'T|r 2R00[:d']oq=8ޖM+bQbMgi٭r=z+/"W=4PHyp"ppDA[AJ,qֹJH&@z@8|׭^T9^7:vț9O#.GNoݠBR!4Ds%X>,VL<"&&TCHYk&~<ϢXsDw=v%9OC7M/EnU0TM_фnjGm_3㝭(5~}T{{};+$1tc Qv7~:686^&}/4!xqcf9Q72?\gx;qcC {||IqAfXW[iPlep/cxf;re.`i7k뛎6VWmhҐr[!jDñĈk:jrBD3k H;&⇋/>kd/3U:66XT^<RR.C1I>K9|ԛA| ]+d^Fh5-&lԚDV,5xjk˱f* ,`HB [uöpkY$i'ˉ#>x`@A6a&YEhĈfX]|"뜨[sl0,Mf57xd& *eW%] V t2`Ч.dT/C Ix-T3d8f6nųJ߹ 7pOT@d`JMҽkEl8 ֍8 }qge$-۷jpTUAk*+|Y:FH`K`ѴuxJ3v" z(p-VcYtusŤeMTFD\M2:oq<"!C2d EY *1-P+?5 g^)!.+7j~,T=+9I"xJUqTdhNS–(9sFZLдAB-4E^=jo^Sv0q}G]HSJtnrKf&'\x{wOo6dF[7gZ┓[ƒ5Y~l~oւ&PQJ8FlfWLQps v.,QR\WZQk甙MDyr0'(L~. 7.eJ/WH-*/_!dYřQZ\S`WRT9YV\DS UgQjIiQή\`I+.δT b"ZEIyIy).%@B}|j I楗d & YjL:x{wFwd~ͳ7[ V23L&858ؚ (:kx{Kw &ͯ3'8'ŇX  vx;{Xw6dF挶B 9ɕ: n>;] 'x;{\wC0BF@~NfrOafW xxUN@}b#nP1! vPdmMŵݵ(-{g}KlŲf\̙]`\DI9#=iF|t)i.(W+D$ ҜG{~:S%6N'K K$D4!1\%T-"yGq;Dq>IY̦󶍥]gBV)rSCюOd,dM\cHF,futѱEX[dY76.mK: ~9 @jx2Ri-> umߎKXBj`ipW5<)պhA 4Y<_1<.$k\v!Xs KV4")l?^[K$::Dᩮklz 8;uu.99O; º ,Ϻq3 %MNM:÷e$8~tnG4ߖl 2F%SJ/;h.2G&%L)iF]hÓq ~pYCGvGrH yYi{g\',V_[|Qo2a~+g}5XŠr^{9/]e_ƽQqt7xresb\ťÇ摾/,L@)aθ_hUҬtYI]DYmiY_$% I>uJmk}xhP(^slo!`'nLLE .5xkj8c1lƭ\CB}B]=&od q qEM^&89bRvu!}-Ĝ -},ړ'nKD6lK8CB&ltq ,J-.)QU pwO-qN,HL,().p+I(QHN,p,JMQ( .M*IK/Q(JOLҜĒDl)i@+䧻&k(y%d,R0PP[i=y'"o _xk-q2#dcFٌ7;23O.e r  \&}4mHCŰeE1ǚj?ۭ`:OL޽ca_~XNwm9D,-WDhVWwXf{\]Kwxni i6E eȲOQ2/Zt;)6/AXG]Zx) Li BRSK;UG%|I"RDX8܅y;"9Ӟ#*N=̤L6Vۉ}LMAO31w}>r<,f}VI|.-0XD~1 ~_DX_p)4;wK{[d/ʻЪs¨r-[!'UQ_~sG_ 4 7M=z~ޘ;&nWyi':Ȋ*_y8-0EcWDZJ+-ПϞ5t^ !x<-R9R1C@Dȿulå$7$ꩡ&Ϲ}KE9=Y?U!NKg$5<} '8 n;霣܉Zee2E", 0 !'6L~+{A{_A Y~+!\A|%X'#fC 'Xz)N~xL=> 3~3EL\%x#V\R?IXAxTKoQNA^€@)&U)Ch4m4#% 3%a1qa ֳ'i֭1.?1ѕM+3sי3Oүc d^O(*5T4U 6ZBq9@4T­6R7Q^(wMvG୩/yBfyn[( FOQ!x_p$+ )i6xA25yz\C=;_P,SPs+)IMkaAZ`eRu0tm&zA݈ZAaԖ:$n% WbcN>)~YHF9R_K y9/JZ <8쌍܁[\A:OX;3>vH}Ž'YRtJ/h2~?Z:+tə_:+ώ'~9!a YIJI3(!e7<~SGiݻ'kIGckrCox@&~H9t} e>kZ5\'B4^!G)6a.{26t->5qaޡ _p-u~uq}k9.Z ȴQ2Io/-ca }*ɰgD!cX'mB'qHm]ʴ#6d[)3E, rf2 B.ÊafZIxZsHNl8%_2pN3\n}j^&e8Z{28R/"[יXi^4,{cj[5`cltt}^tEOloFI׎uʑD:ˋY]/RVpYȎ"30 W9bysxڗ tYڦuўN̊HzyA&FVq)"UeXMpG6d. F+]8xd`D*4!MWUţA{ڕʯnJ @>)hAEKi$,|e"]G5 b2C i#0bJ*\UU9J2сT$#D|"U,s>5P*nV&2^LDKErM65^@}ʵtO-,V\ƣQ~I|t}-s]eCQhFNWM>{J =V)\3k? an)]pCqU wXӑ1@4zu-7]tQ\mv]i{Ui.O(k2Wtw.G0u0_UW<L1R̪Sc_wb./^N6K6s`_c q(ە_v7}l+$~moZ}*7Es&5eo@+%^3-iin UrƓNcna[3I7*\3w|soݏ _d&ێ"Ķi}VIY*VT.mwOʽr7/&5Czyc}H|A.Pt[FGp0z#B}_S#cv#a -jFI֊'-SrFX׳i91.'e֦6P[(ҐLNmbj=zܞvQԒݰPp_ s,s;$yP,B@"U{UW H؀Y\(BNjSr~bY#vs#/bm0kbׯhJu?ziF.TXoj{)\0ڻN`,ks3I~<_X:xoP 9aч!6t)'n,{<ֹ yx{v_uq~)LvHL*?Yor'|A Ղ\i  +s3&W#Q/hM/+ +$88>858ؚ g/]xLuC ?{||IqAflfY(xZedANɞ||fQ {IxJuCsckBvjs~^Ibf^jFf͵39' rL7R3(55:(5XC Y5HAQjIiQBQjqiN Hvs-3z%Px;١ 3>3$(/1g?#bnAӸ'1 (($d$Vpq88dLflh\xl8c1lFYa>.-{x| ~f^IjQ^bN{jIPb^J~_~^rFIqs>PDGA-1$3( 'r&;\|29ɕ@.N0P~\m<(W&o.Cj$ذ xks"73 Wb 0/6'ښ3df$OkaƯxϕZ@jIVJ 7A M`~ ^((كp .ήMp hLerFLw nZ'"@Kn⅁냳]05 m to_^9N߼`+NwZ[mB)ږx( @vn$þdZ_n޷ךֽ|/IÕԙ 7 O_ vɺgg`=ΓYHcޕw$: u= #xw|ߨ?Yǣ9C~)9=g8nfsM쮠[gCf)G0ym#"ЎE 7o`/c?9!sx}懷۟:6 >x;[K "M|s7Xu60VBWчgG!``<]nb/aJ)tl<Aoq" ft. d?Cņ6($ DXN ' yZbA26 YC$T( 1_ǸZA bIz )b0> E{@)fX$"K|f;0~'Z, Lʠ[7@x^\=xv:_.N-]ߑ:xKPSo0ӝ-BgqƙSũn`Y@]S`x1 .r]`J*0h_: BDe 45͇yLFfaR"CGgQˆu$& &"@5h! eWoƄI)3^'ɇŀ):JcIV-L1SWhZ Md+="Wpj"^b0qaJOL @2HC `ά|uR(}I$^LR ^oށw>rIGܰ4%qz78X]遑#B&`K4N-@kal "bG9HغPp u}r63=uXc9^㐑OB#kyLk$A:fvavS9ZxxeNF¢ C4z-aa3dFfHj=t#Zǵ.[ -p^4F=YbnB= yJqKG9$iñH eR#GSU վb2)S͖Zj(8u汳&Le\\d7U? R*jowjM-`j հ]Qf_HLf Yj-DZ{iG66,2`Nub9IijS]JO G-2XDwE`UfaqݎkRb-*dD?Ok6-d l!=,Ķ?̖O283@, 4L{o= (7i lj ؙM3V043[?Ѩ&烳9KL-ZTo?txktHɕ}JSmd,]χ8bߴ?}H=Y"Ρ=X|$_tr9YwGu?I0< I4ֲfM~{ s8jbqKgC Uɒ{|G_Ey^ [zAbʺnB?u be‚jJ1\Fkΰ~<\ ByCn @-՜y+jJE3b jjL ak.[}jJCO^7uh # ʱ;Ǹs J`H|զ><p?OU 9 ܒ`~\F^\ ;x"{ _4S [ԴvaMQp^tMC-T60ѡX|NZvFRof﯆W +wMȰ91d+(R?^KACEؐ7tfP=9nT)j\B![ǔBl@/$bnl<%yW(iF9+u( _3XV0uͭg9]uPH]RF[T1Kig˓ RNAe<U}˻W]o\RGkrupmA[j =,{+[bYoXɂ!S/:20.X9Rf%kI U*XJZN6ՖM|κJR;9 xr; VyTտnO nkW$6<ϩDSG9R:z5j}zN RS'r9dzQ|˨S9N=.pPEh_v'NkS7.2j33\u}^xA 4JJ k`42өǯ&}&MF$]&1%\smF2%;UA#o%NUHqQ7>$P5R0n4.Nx,?_B4R B8t?x-g6{@q/ռd\4Sa-XVm)7'N)5<U$z#RP4N]Z,1WٓaߓF̡LQ[fg7B)㤟/.g|H\?rO,YDh.c-Hh fKJSG:kzʭeuT%y7!-غM]~!#U0n|ΫW,u%( cӐp8tS~jIҗF[(ފs hFJKdGigEUY M`h;ݬ%IYT+ T/2z&ՒO{7T B5>;(fd-ֈ㞼)8R$C_ /JUVlm5ajHYV?J-%CQxSMOQTZh 0|PS[lP($@ZM2t^8t)0a;ID\hXdb\  w _;$[7ss.}SlPF;'F`y속Ikl{HL)E~\tz$Ak8O2d3IN_BrxpN)!-Y`kkC[TIKylFZj\y}^Qq$Oa |a>Lu~#fx8{#%΀Olа7ڦig^d ^\HV )W:$rI$Bc`n"cʱ|ze%KSMUŨr ݵ>Z8 -a'NaЌ\'yNXr#W`(iDddC6qIHT*Sktu6|>M#װK ߠpf/.xmR=lRQV pAJДjQa0پgA5Ʃ&.ol.&/.ch 18h\\LV;ܜssw;wsSAj;vu94;:jߔXtNmsnCűc &mh$T5[.^cɠQ> wIG~ИXuħA+@SlԣC[ cu=ˉ+u+2T&]dMޡ<>X<OL(եFƉk|3.$,b)G ~%=Ƃ Ɓɰ_w[qg:t0|~а&ЅR# "{ (x`qG#%Q/#|̤J)6 QЯ"r.Z݄V+ǒ`-![r9_o. J4ǷYܮh6hC*%HE4CV9qC쨟0-aD曵T{m5m>a9;5+.˻ޣL_v[$"yA\g 38[ n5~YR0xV _*A4CxN 96O`<6JB%y%%vO k1sqrNWTqpw s  CZbiIdFn-%;d'l.˵YD~2:Kx[qnʆ+Bʙy9) J%ũœ/0N 16RN wHKOHKI r  Q(J-.)BkE1ݹ7d gHb'dck}쁓 &Y_ZQR\WZQ។\MG/'#$(Z>y|,244 +* Y\  fᗝ|DLF I7Ч~2||zH%$$0I#[L71~|<x'ycɂl"XN`=d{Igd&WjZsqr**T`+̸Lfb7( Il^V\S`; gQjIiQBQ*HКvKFA5X-pEx;v 9gG4uƮNp^~fQ(9`F #K(8" t >r02hG;hߢۨl4o'ncq -yQE?'];~_d_97OEQ\?I!ɬ~]ëoCkSškMшC/ؐf\,XͦI՟|ZdyX#ˆfj4uu5 2Mvk`[4P0ހb J?3h@&|~6vxs nh~+ڲdnV$sǑO,;'p`aᮑ!A'+ w'rL=*j2m8m}עCp2Dv:ko BnFR`仉J`$bh-u嫼Z?$o5Mj{*Aх1cuٟZ+A#V#}0W7G} Jg!sZRg2ZFjP6UѰ$TXX_l],7pP WboIN('Xj2xtdt;Mm'6``'S3O 3ϐ4;dBn n8drXs7D6 5d@4U9,%Lɖ+`]x&0&Zr@XNϼr;s i{$%ggyd.U *ق_>|‡UYUZV^=pS-㳪W{`BcA7o0˴)t~Fzo}k0^6|,2RϪ *𱨚5S}ybrrcO)_!_Ea'ǍW[[h2f%}bPr)D5}J8>EJY4TfUCT Gd%=)('Dv%X0iBlpWXkyM=q ȟ?'@eoYA @D *f0q7i[902#'TeJ |:l>':|= =@_|~f{c{S_Xph@Ù| sM@: fUȍw@@%J؍_"ޫl$cC;D uT:B )/`Zഽ<&sqSt93YaSɯq k`|R/gJ(XczS)|se+z#ycbf4 >'i3FB}nl9M y*ѤzpQ*"q% L- RaKߋ0Kny vjĉq+UCA(b*I$vic΋{{"U ZBN+EqHA 7Hd^St3ak{ r !?bz}`5/KpҊMi}MyĨjpl! 'iTh|j; wL2v5!U09LtsC߄f6s>ꛖ>ͧ`썍6zBZQ K[RFn^0SԸ ,T_+!Ř(/džBO~;鏑!R-FfiHkjEV^rc7#>,Syȳ\d5IsKvrYg.@/eA بW 4yܛu2)*;(%yJ f[KHK*QU").X"@JH=] |wrg|S4c1٪=r3KY1ZjNRxQrG%

޼+ii/aw/ /hϷ+WLn"wTN _-\|48s8J-{fz }P'mWKo.qWG@K.+ѝ.RJeQG%pr`eA~](jg iG~rbk8xӕ*!tД,E]ud O:<j[c2F>~L%T_斩7],l1+-]\Srݖ#Ki)\3ήzv[_W. iԙKe1ΗJkRTJwT[m.KurBM}UtrSEWRڙkb)*&#>#DydT6(WgM!UD,iʈ'XB;0h0l1s9(~ƒ+NGjxؠiP=ǽUT0"XTO%Ge]D(x4BspH3y0 #α{v0):Yƈlw;V2'f=Őp~ ИYsxyJ2^Ca"Ӱ-$183@꓃<]ǻƙ/Ϳ.d2^]?V˟h3R"xl* UK:JuUpX݇rp<# S0QCUF͚YmKHlQlݺ}x'ŋ7Cpurez̐dMB]xGZB-}ۋB~șB;k:_!  @TФ9tX;xuR=oPUBP;lPE>"DCCe9sjp4J skT1 1 y03?@APw9{>y\! 722oBsj[Oo,ee:5*G?HˑNF!&!ȗW%OI\\@(1LF->eQ)a pZߗ;i.vQTI٢r<(~N$7 caoL73< QE岖8ir :n 2Ǫ)RԳ8b݈;p8M+ Q#n"sn/V;fH? hԬ9sLw2N4PH{Ř8kL~݅GlXrxrfc>l+R)"YVtJ3tKxX-a :CWAz1QBfO9Lc8e: .#(XUNxlIWp-E}gI8H?XdaEKXh9>"e#I@7o S9evр2GͷrOS-x \)K(€HhCönGm)#lX)aVK6]V$IB}ȸux0Z1fG m}Sy|IjqVuĺ~dFMiȺ Kq'459\$$^.^gCTѷHGY佩h[/Òc?ُ i0Ls XsoyC!v6(HRN'^Ӡ& x֬JthIb'H fzrT *& ӧ48|`{xy~;WW4|9lee6O3_QɃbT3ʂR*nz۳ޚƮ5pCS?˗:4 oQ|oO34׌J38W45OW{h2h]հ4K|8px˶*j(](xu>%idRv&ZqXLU1Yj:a4g:lp(TAPi'Ue] |q=|<[f8g)7N^e_##@`V_ Z8⥂ەtrRXسK3#Ա]kl^9`>g=|8nL[WyZ4'Ng4KZN3WĕI>7;0n i:+CF_}Wy1wrbOƻ.TZh~L?sWwxl)x.mCH*.[Z \I߁z(0T:_׶k=>d/]_oU()B;30U 1]4pTC~,)Mzz|}~ NEZqW\z7=SyR\T^V+B;V,ӻ*3]KH~^!3զͫ^-Dk ݰ~(eW5zW͏&H7>W9e= 0wqx{ys{6!.NN΢ԒҢ<ҜL?q1n6! Cx6xysZ 9%J JR+JtB}|6``Mxrdi6ɵA2\E%Ey Eť9%\\ P4,lZx;9sZͷX(lqx;s''Rlx[cMʱ&",x[cZԐĤɉ"!l1x[a-,1$#xXMrr(i5&d'ϗ(c;9Pz粂I62K5lEx[uC:lVY!m[x[u;u񓋘9RKsJl6Of¸9F 18 xjQL(آO3%Mh"N6fBfv!qrیNf[cqROASd6nq#_{'DE\xsן/_C^@q8~lJ$,߶^i@]˶enu6D|7@{uKwa}# W$ŲY1ݯ6Px~BF6`|Y>m"x[an;#OqAf|f^IjQ^bf#1N%γ9Y8[l3x;awfCd,'&tKxKBAA AUTHORIZATION%y"PCRsf[-T " DT xІ.y4߭Z?tHɢH,}҂6~}vyJ09$;*C᪽pQm`fO1 5 [G:+ YZ!<-#H}fme "*P)6u@ Ŷ`^CL0֤u_>??n[ Q$p2}֨ɧuJ)V6.6 +`˲e,erp "{: Arś3 QbTØp¿}-chc2n\g]ܼ OXy6R<#T6ͱ ܐưX(]dyA'B+r )d"% E@zE`-(>6Qn9^gt2{-8LE?(?}\8Уq KȊi{Ph3~Қhww҈*XUD{v7i!C2k@pi:N5j+hZr,׿YNK ђ ԣ3֫+r D`dFWd6qN.2ۀ+(;>3 &p1܎bqֆ~FDt1HW @d\E1f4j&cUPDW˵7gG7i.") f1_^YgPjEH ؋R HyD"yd3@pFA \c1  ~-fy /"&Vk¤5a jd` ȹ / 88H ߈@67 F#VLԄR gq eKۄe#5ϑ`-k+-?0hD) ة 3 u8.=ad/9+Z$YxK0cH;|Ym-i)3YE%B֬hYa $HƮ-Y'JC2r&,,k"2.B Z]M0J; ;6- 9ʓkh_#PcgiQS mmQ>jcn6Xx|֪$ }uΈke4jWq W7WcY:f(, ADh}h\L_VpHz_WDKT",t8kVtt\%F?UYIIrvaFp P g $|@%-WPzѥKU fx 0}Pj#>ZPcD@raڋ2^7a~2Ky NVްPprk#+r}.m!,֥W!|Ku(=Z@:甀x`g?JGA+j'ۣf#o л*j@t .%Ѿ\Zk-/@H?ߓ6K((Uo#yFJ~#KmSxGg4G/pD3꣣j1lF}1T6qq9C`BtAFGT47rd "KrN5.'fh:88(۰o&o]}لBN:1%p`t"|U}z6a7-O?_c{Wmh.{?nz3..A.oY UeĤ3=V<\]~'q v@z;5"Kͫ|h*;l3^\Xߎ~eO{A檑Q+;}igC Kc"Usrϡci~:t,ͩOE`}HXj*X3"u8>s>>7SuTm շ 4lyY^۲S'c2:q#lC_sˊ4uB'TXR>~G|7'iGODf9ĤY=uڀ?'~j§FTkXx5jC hKR(j[.Jq1 5MKQaMbF l-DEJNcFro @./Ӓ.HKM臍3GEA#iS>i5uLQ"Y c\SP t<|ᆄxɍZ{}XWh[9mZG4gͼ~7-;^L&bm#aʩ4=f1+0+wU/Ygr|fbއӖpW%Ix;}q >82JRs&'0*NnfPK)MIUP*I./).PB,.(( M(.8%(| S #SL^@ɡR6spdb|f쌜'_哝<υcg>r 'T,-V2X|&G@y'jqg8:ڪ((m$#(PZ\Sh0YA8GL''dAyqjMۙ.l/?VSM]A|^SVld1CZr|L~fun|QMm,3 Vpy7'XBd63 "d8&'mobZ` ,쬏jsD#ۑr޼#.)9ďYk&ᬓGL¿=dLHPP'XeWeL(Z sMxDV: z  SJ XMi",/U '(@*FR4 xw0V A}x[_sHO1Q7{uW^J-Fd0`mD753a!QwOwOogHe `.`% Ao8KR;sy0i%fAl^LU! ci;,\qPIDr1s4?!,=E_6Ϳ".!1/Q8?>Z إ0ǣ 7eW'7gRwy"d&#O%&JxSbOgCa0.Z.MژK7.lIf!vltw 0ÈqJtD^Y {:qS&Q!A٘9#Wz4 A@!B?PrX@mƚp\pAy;H ,F:Ʉ/?&֭ٓ-9 dݦS!e"qmaabH'=#U-]T֖䉞H&RO0OzY%2J>umER/. Ak 2$ئKTCl E)\<@}ASJ TuR$e1$Va| 7:t։:)6r=YC xXUa[vd5,8-X mt-{@Ϟ0tJE!$9BHwѡ(Ħ#ݨÀL- TkXH AfA5t^g=)^}A\cs7{XZ%Xh̾ Ƌ{xqn*P4{i oTeL*vܟLYYU%(뤹CGuxex BTm6sCK B?ÌG$w0Y'ԧ`K(W(@0˃wpw*` \o`h!Og=z.v 뤝Q dXmKBE ,}?{ྟ#/2:$ AR+!Z6AeuAϿu?rGn_|ǖ?pD'jkֶn?l6qDZ2mqjYVJ`=Ժ`꿃RyDt>q[ 2wcwߎ ɋ_$\k=-?IM${vx35 n|֗ |9Zd%ZnȝVoP_ua oAXl~›`E dR@iYkd-:-/d@Jݒҟ̉W Ix/D\Oܷ9SJ.\%x+A&֢rr#SDgkZd ^@$ N7ƟX'I% w2(zZF ǖ,0p'LmUKa~T}%Љ<xOp@ldL㻎5`wK.-N1(RPeo\Kx5vD v}OS 'rox\Oi+ɻ9l)OJp>?A*ǃ1Z&4WwFX&|ځwP TG'4OV.ȌdJO-e^Mpte5ץY)9dq-TDdNHP=kZ3=ypF KjDwhp?$^:yM'zL' (Y/x C&k;˒}!-|W0ӓ6-ʪm;ܫ[֝uX^d^t:]o8;]K8xP9yK*!M 2ebM%YE\EVqЮIFft =uSXev*KW)/$˙v,Lty.6Hyͪ3~)i=fzbٜ\ҦR7߰xءe?Րb.oPvp/ >}/x#cjxgWW~otx5$@B!{P6EI=^Wgz|D^A;:%]( 1T ѐ+ǜӤGMZZĬQ$?1b8 nys% N~y z#' 3ED7 czf"#ؕ>hI^WU ̞'I-%%D+YBF]S}*xsnv M\ީ*Bbcl\3ۺ:zjh]#au77-K-5kp8Ԧ~G &\5Z7oxn;s*YUj=cliUGXMC5Sv4 X6 zF2fjRײ]Xcw298q/H'z HsmDĎ5'\l?8ױ9ۨHyEI褫?ՍX/y+>4oˮ◱߶X V6$VCh0ˆ$+ 3K%醪k@WA#lu}g b4sBTWfvDյZS)k23- |9x[,C" ''gqfUj~FObRjY 1x[/od{YjƂ;Lx[!oݸ7vl/XX ux[.wݸ7RK x|x|;iþ}0fċ83h.`4)#)1GpF|Gx_I=#P4GĞ 4"Ęsy_ғ%p}uxc 5'Q` "}F衉x۶X}RCɕG{'B*SA%ޚDD 'ݶmt2h8hi9 ٵhLgFDZ Ng+:}s i$ݧqs{›x+AitZ2l.z Z5d.\7MsJčZ0O(/a xKz<-q8TA{+8d)QD׿C("ljChӈvɘ,E)[*WOʉ)Z'Ѵـ^_non5A{da\Ƕ,9cdKcnֲW"=F0{<{J!ȧq}= t,eAm@IFp T}ew~\GnACRCFHlƐV Da15lTZXrwd L31~gMtWfYh/]޹=$YCp3M-D6x]XAu&c/8+)BؗLfk(C*]ZNQ:QtTQBMJWU -/lMv |Y\"JMsoB̽_?\+A5)(U#K)-ўθ%ךN5>$MEוt;sKѬ)FS*@ &Oay|lXw:.P#BEQ *o?`֔ f˵nnjʧФS R.ZQ_2PDs뽐ϻD88|20yFk3AnϜP geB.ćx%[l#GIQ~iqjQfFf-s'_aQ(q,rI,IIK/PU0|Sor sdA.v,!>Α}Y1NVaS檡\  `XᒙZ\3yccFIqs~^IjE̒TҒ $92>4u/5*lʓ}\52s2+u}]u8A@ 23\2SKt&csw ().p+I(Եs, /,Iu,-@Q(Jy楤V(d%攦L~qr`&&6l \BWHx-vcNs.- 皸vrI\\!A>!\!!%E%E% 5@  )RɩtTȀ LԜlˤblPRYjdH Ҝ[ήs0N>iB|؎Ԓxh('eLSq!&B4ɸLC.ws ځ]2M)%y%%u)B T( kZ.nDxqcf,]l4x-KloY,P Kx-vKl6T7acc7p3O i'x%vFl#OqAf|f^IjQ^bfLX4r Px%vAl#OqAf|f^IjQ^bfLXlt8A@ 2s2+u23\2SKlvdx[{o[$v|ZqYflղ%HԡnQxH$J~KrI,i ZL)ST'cGLC>]"PyU_vպw:z6 -Њ9} ㊫Trx71`{YYvc7 !4$yz5Yu"ڐDxX>NnM'j`>8i X&l>ϤL3-=Emqs& vSQW޾\L0"|sxⅈ>BɳThI, DKfFNwLf1d.L s@ ι\jT{LD?DP֤psf*&Qé1p r˒bIW 7Uժo);ZO1,yٯ.\,Y,;JUI6Y4ک#:rٟj)B  <*,vPUMT}ty35+,zLtk'Rxl>kQCt9rA7PI~ M5*H:ru쯅-†IIJfz)Hݝ7K6.ʣ߃o9<韠9=K9JnIIV^CEISn8B%kTe )Z+d̈tҽlɃ&qp|eRZeܩeJ 14?9 6D%*JK>ͬ6OsfB{vs9[@Zij;QJ 4yo) bd~d϶HBs.Tr 1R?^YA*`U܀hTz4&U?K1yv+y! Jt{LQI@ žD+C)Lz_~I#Ed!#$K5\C+1c#:0b 0/ DЊ$WD5_@ z%,""oq%dV@N>Eɑ&;cQ9Sg{ yhZE(̈3\8 !;Zl/she&4giP .ݾt `[5`gR`*FbQ z4IԠ/@r2qYRQAڊ*TxWÅ.%ż!oE$T}WP,ZE~$'_N7go51F:c Kڹai?"9V2 x&OK:5}37U9;]pH^wA$䠕d&`4;c V&x|Ҝd: u P |}/SR$(ttYVǷ/p"e  ~^.SjM89*z'Xd :<. muZ$bE+\Z梡2MK):%LI/vKa%c<+ q?~Nk\sƣ^r-8IKEq G?{_Gu~\vuoTǿ#}ϻ:UNwNvvpHCX-Kezi:*qt5^J.;yOwҩw}iXv v`m玼F{&LVTRTS%PTGDȌ;&vvb3\ھ_uuk6m49!hZ[M`LM4n&Ʊ~.ϛwgoI\:5|eRiErǪd ݤf44rzhfުӧ pOt#n|\('V10$, 'ZkZ`.O`D|uB nW*'p(b_vc0NUlhZd,fR k`NY}Ge8y9]י&W5.0%@x:a!Ex 23JRs6{01J;F{8*$;TLï>)_T_)2U!#8)'?)$v28Q*}'0w&Ctgy%)%PuԀoVP/bԇ9#=$(1/%?/?/9Ua?Pub^IfPjANbw?##u8@Aa Zw&HM6ట/5UGevƓ,B 0NvlÄ";yϜf4qe( tum7/`Ԃ;2s2+jS2SKte'rgp,a EhSEL >lo&~N stq wsquٜ,qRphN>8y9]י&W|S1ƹ;xku 3>3$(/1g<  gxt]!irҌ7Ob ad*.DOULάJQHQPK-w8@AAavCFɂ*sT9n.Mdq:A!&@A-yx3Dd D1xtmwp%#8c}[;x[ C:&fx[A|c/c>99s^viEy~|OlS(֏ge꟤y&`|]ŏO~`:)?mӚmlU\lw*+3cbԵmPdJd4 '2,} 뻘ddЏgx, i9'l6_$t]Ahuh3w'O]h:%䊒&{ &_ uptC|dôloK[LL9Y$Nf" p~ƷaY6SbJ_YHz"r̄-+O)*"ҪIWѿؙ+ O9:<]| ;uM4_Mas>IΣa pG^s/=M^ (1 ~=}*Lkǧ >>nV`~Q8]BaZ'j4:.PQ79ʡ Wiv=ܣC*uu4=8G FSΥ0h63'͛y$7ͱIZJ66@88o:dN]z4B\ @e>.*8K{dÃΊp\e7p<0SP1 %iuֻdC0SK_R":VGёyNك鄏nNT1}(7;bIQdnE)+t眭-䌩+Kh>73)ѦH+d؏xN{?gEAw[Bhg_04jq"*[!]3m .]"V۾O0gYE?ԽGWmm-p,%\ ;~Đp͂~n1*$ESTF"ӶFPYDOv/w^*6ϧ ΣV#crչ œUF2SNϦ(@ю ^e}H14 ._^?b"S+hw;JsbK7+~&+S'^A+n86N A!E!XЙNr$L$ٲ:pQ4,z 7M3p NGB]Qo=@jmgS/sJ na%uVYԍv|M%;"rL #2 e< {(q3[Y Mzt=<# '[F<*MἭpש_x>KY-dTW7}mZoMrQ:Wҷ܄^!7bb#&p&6zi6(OK}JOvCDCl<qibƾ\jE:fSݕcgL!d%RS 2|SBHcbed4ec>l囌(2PCÍC:㑋5BuR6j/qɀ9B}r$btaH5>:*'y^Zu(a}Ń, 3 [C .s4EK&4F@Mv:ܫǦ7 \0lGtO# o*r;C\fWb5(`/TYmc^ ;M:*W%iP_bk<]MV5c7B߱4vRjSޚ:Rwi[}9 Y[XPhEńI|*1 i2qLSEo48wv"sj`tk1TO*0 jT 1p.A-osjx+AG (xkpcRl;|*q`M8*J+)ΒB l$3en>,PZm+)D\ I`I׹Qq-w1EeOڳ . [\#\OU dT"&J(KhS!ce$Z&Y5Bt A%,E\+{y?s"#^h IvW@FP[苂W_oy#8YVV+#Z8@\P-dJ*W2ʕ%jߊit'{}wؽ(ge܄ ^~wFo4O?fK P-R =9#JY$s!j~d\P-@^(2rW||)Ď>k}Jx64rdaS" b5!whþ_m@YG`jZ`mvxV(m[Kߋ$AaSNVfְOPK a @`jqhӋY::M}~icҝIs n)1X4_gw&Uo(@S K9DϞ;ʲJzyO X ح(-"V^G5T:N9fgXRo4Յ)(s.v7>wi -TiN1 D*Vdgقi(E kY*oG>L`l>Igm -+"EMʣ2;Qw=9q> ̳A3$v*!6 qF88L"bq#su /|!+>吢Z(šJD;$t"DC]ҧfeO쩬hjZ6+(Se\@E%1x>b/2M`lEjD} 1O#7FV=zJwzՈSPK]0,V ^⍼^@dB|zCyNo=jx8y K{4Ww!y1}hn8^l(s1Kib'N^}t'TpgOK#ԛRCf'Qn4S44d]A3ʋtC1ap3ٛ/*!8Fc6:)tρ\Cy AB] iH0$Թ"cr#fj}1WTU -@#n[dB))n2;,3#(ぽk2PFFk]1ɛ/,?zaГe4mSEKՠp'X| Fh׸sU|c+Bo R%[BO%ED>0o",P.6ax7$pnJAJ51kF4޼G<F-pՕ[) cɵ#ÌLC ?̗&J3Q_h5ԗyl3[c*G ?Sk.PAۧh[V G(VŮnEjT2i.l2S[*RHQd{𧁇}^yFɞΩ|NSbN 6W`&p&R Z&b]*.a_[+>d2_f I+eM9@b ^L֋4H(34IcAp[14*?VP Q|#µ ({O*Y\oEɭ߆l'ɊHez(%^BY2(oji%7~PaY¾TXXy\6+)񈋆fɇN8mjIO\Q=(jqx0!swg8.މmcVd X%D+@6q0&_ҕm`lg/g7*{ɯTkZ\iyb{/U~O$[#De60  o @;08 ̯JU7./{XD01-U>*Jd5k] x{* %n>x{i* ܓ\'/`;n <ax{J ܓ\'/`w:&@̾5\aA2]1MY V\m-x{* ܓ\'/`;YSz!B,\'o`J?/5=94$hB.H”Ol RZ QY^iɲy&'رO1 EғL>h7Y!>y 񋌓Mw5bW%' [n=ﺎir___K WxJ "B 55\4(L.EMVl*$0y$AfNNe6 s6v x" '3,7qbC>'FɌ=M>V$m\k'n+xi 6.J.4!~r;dBr:$8&vl&qsDq\6vdblsNU*D7\,OvxF3-jxy 9<y%Ey9Kc='Ov߼@Yi5x| 96O`<PhSx|qA e&qL^l2ޛ{QvMe7s-#(YڣJȐ`2yfD}fuOx+ο%\^AG`%:H ~Cwx 9x;qV ʙiy)i !>~ήU'/07 rj^JfdC"{S of%2q"4N >Y@eq*œD'k+Mk39Ċ!gë~?$a>1dC]%1OvsB m!6oV9lbDYvɢ'׬-ex۵q, |y'Rpy^ۜd69x".5A'<.m0m/jfn0xkxt&=]+nUxQo0ǟuR5j/]&%5Ha2iO!xC6ͦhw N4'x`K(Wt+d$Wpk) *YTTZÌqpP {,&ɷ:e YiXrs' Nrq99qbݍ}jBoOrGһmG٧DWV{ZQv_aUU>'^jwdrY7A"i[ۯV@(8} " SmI^ҁu,3̊q q6˧-)/<}|d=ݳ?0()LhŧM"ضgzV~=B3;:~gv+~r=^m]kHYEvLiubg xF9[I9 4sVN|[YgSYc<>qBoNxyxuk6dF,.O x\s8 6S!)BL! r#lifotؒpB3S Ο%LJUrH:M![+c!9"i7#[][4%KzdԺ"Co=X%ȲĐZ뀴<8EDKbiE\r % C^' rvr8V9K]M)gM]gX9^)pslK$Q6{Oćf#c"M5ۖoM׉ wM ph3 ]YSTç7GoC,QvVأV;2>@ sx0Ƽnv/;YF!|.pBjřZ%?` B א:O:88V*V4A;4rRIOW@L4vMcG(.W{p^/NhJ"J$ˇ}0fs<&*Z0eԙ0ʗyeqF@&N'^^kBǑAM&1>2f*/zkbr]l PzVhEɂ/zz0 i/: j)a*  `tbf})?FF*(0~H],G3}럀v$BymWw҄2Е>3 iTIsIC!uhTAVHt0n K>,WEyf ys/p~g/i!dD}=>lbu\%J@ggTS QT̋)=gEcq#gjwYlks+W_ǔ;fB$|p0bhRei&_$5-HIURA ~<騡pB%i;8hW=`e]*J -Nw ̉eC9E ,l:@mu'5~eWs/: XJ4(X4¢JH}QۊKE./Ȥx`1x1!+N#xuC<& ]a 777xG _:8N{^$T`zoo#%IՓ<*d3]d{ -=i / d0%:b./rLz#VUB-l] j KDSޢmZ +\7w[ `G>{p#hOMu-F>: ag%'))7@P Q=*pYlT90B#\2o|+)Jꦊ^(a% IKNҪ>*6|9Y؆Fk`Y`pтNq8]ʓZͶ'tpgMb(|SptoDQ^R;6X'itBBox$H@I7(.LPWz^_Aƛ Qa4YҠ(')TjU= +#2]!A#d\颎fCjC~l RDj~mJ+Gp 8c{ӕ ӕI=^,^-ucV.2l-swo8O5@G5`v y*mp LoEQLVQ`Zʄ-4L 2Lg~/2z}%;ⶌ @{,b2R*k9,|k1_iTDO,Gfs$dىڳc/;26'+Jؤ ʭx IL{#jR[;`4 >Nͤb5TNS&/䧁Pbt-`h6){3f2 GmHkm\UO)JN~Ti't?KW0NvX0݉r' k>wO6'̠B8C_N k~uӼ8[ךpQ o X6y5 q'_fƷH'iJ J\Pf 1bJNWҢ]KPA7=2hXP]} u3 ag>=YVob S ZU<,=9#/phe/M=)$e-$i1WҦ;ؐb@QL 3|>=9AI7\1O /<;ycӖ'gƾ23 t$&;Mog_Iao4$'w7^#":Ulھ궻Wrs/v'vMϭ̜ eaQϮ9$\#o v8qYө[b^So~I'ym-{')| J#XfDŽfC@=TQ!J: seCG{]?v[/?5x5(j\h8QCa!~d7%}P%ClE vKE?g\pyM}/6HR7O#!#(WVšZxw22Pk*~|aIhUaQ0&-䂾r:e1|%XA$wV^ְ 4hlvYNSr6]5J;E`{` qv-5?>?=_p7|:=͕7|wx.3͙20[&iQZjd;|e'-qg8TQ( +I[&(Kw"aݳ='rygeU'}=DQ]ȩ:!wwBB8%ˮccY'9V( 颮VMuJh#[,xz90o A#V)-8"(Fus0-PoDHZ[UL& 9..R]Gj]iz9dCϣqX>}2.Fѯԫ v8:$np\_26Uwbl21|v^bᒼ&S/Kp?` &p>$i0#\~\xa>/ZS1Y\-HxKqZ 2x^#6- Ȇ> MH%OGmG6pe_Ld8ЉӽF`)'LF_cC^Vdvq_y?fNlU "Xت_9vxVt._9ih (~520Czo$L*/H l|115D|vm۝2 pj'"6R`óFuD++$d3[v`E'ifqb\\U\;g`QgG.5Aul .\m!vymM8КKC[%ί&,jtt:QϺ;Ԍv3L_/ O)zm!"mA1 P(TJ'yUIӱL~*iXMq͚5?4s+;d]fVMJ&:c($YM$b0fI<&: 0-P;nm<ԝrFo{ao\.5|xq [&_`c'ε?pN=xqi?ㄅfi;E*d$g8'EnޫyA9Fxl 71oP324VR,)V/QMLLQ(NMU U03LR(.HMV(37.g19Y曼@A e xq Gم&k9l)H  4xq Gم&k9l)\9q", dkм35O^9Qk2hneswjGb^JN5gI}͌14o7g+/J,(Kjt5 x̸qM&ͯ '3JL2qr:FZْ J}SS+*r4J JR+JtR2st2Bʋ 2ҁ*uS+3Ru8A@6paZ;fe\>{Bj^ciIFhqbz盙 3 9Ag3<lo v4SUN5A9%IO3|ԉ1`B; 9@#}RK2P|`? niY xkiƙ+Iھ-%MK4V뢋棡]ZFv]56f&j\"{{W*`po? ;I&(ury<vje9Ide1in։t<.AUX).BJeh77I~eGއۦ-;!4V5{XD8>6ui\v9F>.d<é5wkj2W׆ ǰ#?7iS?7v`'S؁?ƛ-P>4&'jsRi)CUY8b*I&=?ɉy*k +Or:KGZN/S6Wi%ߛzb]=wV #~nlX;|XG&cGHdC &xkmR嶋gP8k 8O&l vyyJ5< )}ͽqϲdӖXaįLnt44 tiE\ p]_u~mɰӵ{\v]q9Ajm Biû=naah{ <5m^}=!* U1SadJJb]=QIBHi9ȑD$YhpxY d<̅n< X>ڞ*V 9sj7_HIP0'ŢJ*)DSH VF,fh_$;5LOD/yZ/Ak0FZo۷t7qt͆W"02P!kST0|&ic&VzELZ{5hx_|GWGC cxxqCd.VCYGEhxxdxxd;#OqAf|f^IjQ^bf :x^qt;ŢR1Lnc)&?yd1 ܘ &`:V2Gtw oDO+㕌Օv9 3TXY'ש9oe2(.p+I(Q(I.NHKIQ(p,-R9I@qԼt\_̓E lB}|=}<#7o d!M9?)+81;2>8>73($1)'U#hB5dGjT7_cɜS(5/dohqb: Pof'( άJN9I: &?O|CDasͫ$YN~a<tvBx;Tt.W'?9QEf8,5KR&g NR,V(QHKQSH-K-THN,NUH*-Q(HUցrKԋ8' iLvR)9S(R۬+Lx;T^Idv \$'JL4I\+- ]?xXtnA4bJļT[[xoH? oM.?eYBB]7)Hs9(%ON쫛 ;0켂xYmoHŶ'!åP lN'KZ](iU.gggv|2pԏ9 \Nj!GAHdK%_&Q4B'@8H9%V疘2D3m;- m p$n;Jcקq ' (:לDZs/]P&N;;Z_knP^\%~lCnRI ^*dV?38t4qǹ:3s7$q MLӞt,lND^w܊?FJ:h4듃c 7Wр,oO#`2t3P>Ll@UAX_լVЉ\3 l65vZ"S/9khhu>OƣAGAs[5Vl;cþvM,su'D5%Aer iI NMS h׾211Vw40 +/?t+\U; 7&6ٞsE IsVK8"W[̒1BsSӸIS4^ BJWwY͂g=\zrAv{l66k9a|VĝDN$An\HvG_Df$s1{LemQZƵRĴYba.Gȍ10*\R^rY6}]Tj%="V%3V_#EPg BX\$g\xNQ'4\@Q`E>Cp-#J4n?_5Y4mstM\:]c|gcQ&`1t9;d_o] 4*© |Mwl~"zM/-j~pU !E7OWԗFG^q,UZYYkme@%Wm%.5Q3kꏆ@ ZXjtv=>= |Mt:3|< ;]C^GL41+/?HZXl pNRIuycQD+/;9"H!!,u֮$|NIo1OQ˅P/%A/Ss]NސL?bMljGVo sx [<<(AV"`;5`[{nMg~y ecOYәd=v[L g,~V39wCC~+ެ7Â1<ًéu;[al>Y<E&DGn]SޜC`,soQ8 kY{u`\Ŋ k6р81T])jҝb !ؗq6-‰I~!uFLǍaX/,NTo&ǒjë?^(pV'f %œ۹s&'0,OKM.IM QP糸n>Rʨ  `_Z\ TZ\b-d{aAƀɊlQ@󁮩(QHsOjN,I K+MJ-2б$j ؘԼtBAQzB#dmvaLO:ُOx^~8\׻e<ȞU @7%1Icu$`&oL ,&G1*,bSKRsSQYmrԧ/}S|J}:J@ ' r)%g&gN~+F_\6ňϵ7H(0Rթ_ Jtҕ,&5x[fa:cdE6RKK2t8@ JsRJsR|Rҁ EIpAMج+?9@r")[62M~,yz^(x[ff 3>3$(/1gcd ެY7[p  AxifKɋť6s21N攴7_c:Lױ2TLdNciltԢE@_h>G~@Oж8 ?ttͼg&ϏXqG= ~g"qI0KK꫿:x,"f|:eag=zt3l78)PlGxeg.Ss/X[IܸڅK΍-"Vs([ruv&A {Br+qUy';o" !dȷND99(ɶ~C[lkԪZn1C6u8>4Uڙ-f`A: ;E#΢tƇ; Vӆ{{?DsA5<7,I ]IxI1v.N?qFg҃!!WxM\-Fk?TѲ磾]Cko>l6~8+sf8XkX\p0Y'xà tqKBՒk*:S Dʆ97>qv RݱPp(/Hea*# ^=:5O!d.tW&R'Yx4}1Ƥ2 OS[@y# c:@nݔ(\PXs݁ Uj_R ww8gnOUF=pGxE£|%Ho5 ­9;C*\Y>8OÞ5ta !q$ί5;M5Mg RhiфjK<>l ,Xp~OΈ{@p=Qޙz :dyth7ȃE`. ; ?%[P)GB_}ʥ/1)zsJĕOؔz<ݝO\ QpW\c%XhEXs /ric͗{qI.07V>i2$Z% ;dXbVʀUF8h0`/$y%Ets:^ 1b-Ksp^5-Q>ay4+hLRET|KPirIX ы$-.ӥ@?VnR{+jxrST.yYHG4^\!xثt NdK%iA5(G2XǠ*e{ zƜ>85`$y~DK*mxtb%44r(`\='$=3#2{w=Ռ煈;wh.1rC5GHľ.?C_M- LfR6H5XUxGW5X&#T[圴p >x@qDRY=Z2,SDzV690UվB, 0@x{d-z1ZCyZC~vzb%ΖvE4CD'R]L٬IZXBPH)KDUURR*1?4՜Z%&NȮ;/}w:jE1g`!q߀#$K*$ŻO[)P$* }eMȥ'߀!PGA11;% K"U^7mq*=엚=fcHU2!#cxm1` =Fa[1(l/XPTa"TerD+Zd03AE|-|tߖ0WB:} ۇjN#jD*lgކUujP V5L˩{)O-04d"i8_q>v:_w<_竓tsCLSt#W ~?0,%JSh[]|؜%Hqs"\N $1u{*OgŇu439^rү,iF}.O QPG:RR0QTE;$OCtqH𸠡FQ"%F&7sJCO8J{4~LIi/vIFm/ЮIfȺVF;x)>ޞ/f*j)gtIx}ToE{HŎfhn]B&ԑ ,V; ݰ;V(HOB=B $.8U=/Ԟ ]̶_ޛ1}l)禿X] iX<ը .lϱp]xop~Iϼ<?Nx6C/"?J^ & @iHp_aF]yorn, @)dyg~Gk#"c{!I3 ۮY,8,p|[sN#vPB!MK٧}kX/pQ&9fDf'/0^*'x[t,a[.g%dyV:dl^+V%iUx[t5a3sf#Lϱ}q&fӌ{7s| U g%dyV:dl^+fVV\MQD:H`x͆xJ-O x)]\I%+ ";I%M  8x{+f1>'< ]x{(fdɟu%&o5 _QzxY`\ , " s ("%A4/ ` r%,% prgbRandom); !%%+ , W/-L:bxMlQdzX"P44YD#bv,؀&=x9ƫу1F/޽x`,8Nofoo̰֒xI&X&3WXX^DD]dY훅ҥYT6LRt~ m6"X$+ԓ^rmscgơVyGƁQ}բҔ=OEapIPqƙ"l:dio]^;k.M\S)w=f64V&XEZ$}A֙ccBQFOxin9-uaM $ZJd>Xز{(qۇ;ŘyfOd;khh ֡=bİUYȆz-A'ƲќEpA />',ө0uGȰ8:A`w jh"0b ܛβKDSwf\a55t%KHG:0 .W)X%UHl,L_87:c˧bqtғ.,jԁ7~XϼЅ+UYx{#nm_XX6g[b^XPPZY P!$"Ғ L"y؁f+zZcxS^[ h jsp &B'gsp,TRUE.<ҫ! ax{}(z#GIQ~iqjQfZfO`GwYr(L>(lZ_Z\  `쪣Z\d:dLԖ|o'`eT'KO֐KnN,!;Q @Wrrf|:ox{(z ɍ:*@Nx;%z#OqAf|f^IjQ^bfZY^k O x\{oX;'])@Yutq$mvG+(ĩW3i3\""Go mc wi~A:ơAs6]ֈUhI7z u5r#?tiGZvܺ%:WwV v]^P?xSFf?? ]緰5>a.}1T"/ͳ^G6>(]$4Pn{m2ye\{-4a )p=s[焻p0'9)*}oSsG/КK{̜?r(-1]OWP--_2b:Hbs뒡x! ;t?dxt,LXBz*E@{aV# Ţ_}řTW[j`@aI*a5,toNYdٙ#aw18jVZnj|s6YT9IN❽I%oMf^=\76(h=mC!?}vH{ ٢ř<ȟQL7xR > ms-O R$<b%)Wl<3/*fl ¤8u0 ;޿uomxxk'Y (P T>}?*"l &Q'd< M(%Y=]ўx̔lHjtJOc]m(%FGqE>P7Rp8?d%#4idkĔ0LD<$ޖ\N?]*h8hF<÷+m=;F wT6$f޹JPM<~ct{>tQa8zE֩(TtȚYx)Ch+zK`N<7V5xҌ^Ͼ9ob[fC.DqH[IV*vZY3]xeyD%\R-bqDT^{2l!TN1 }60TEW46ҧpCnfGKa;N'Invǒ!mHW!or9Вp2>]*//GmEIb̀4KR@yZB![7heUJ&6k!:eD@EI|Ll./9b4WP> Di&us.Q]uU7?DzrkfkqqC-rI; íݢ./7q{ɛR{zRJ`51i-va"w'*[B de%h ["-U*u6CFU煒8H(3"m񾵽btS鷥U鷔^1 aIQ-fDiWs39W|;1 !?ly.w|5?'#$pcM4k[6W3ѡG~_(kSqX!]=,e_,,{tg\3pfi  7n/:Wd 3 pIc ie Z@<Nw{nYwnզ=kCyf-MHMڻqYzFwttğ={-jѷ=GDxZZlg x A!ֱ/2HT`:5WoW1O)E+Vb+dAQqRC@PuVz3+rjRl= uw橰l=.P *K5pRKWHüB^:bIEKzP&K/QV?@/7==>=w\Y ;x,^AdQmX^x+J貟WxՒKo@Ǖj+iRMCHǥU8؎$ؑ)EA/ 'NH\g>_nR{v53QWA +$f 3Pt([6uRq U\T9^`$6u HRaU/V Dˮ`~v<0F!ܔuߵ_ Te9KG觎|1^$Ԗ B6KυSf =Gх.ĸX{<:?+YДqXLeU> _u?t?km ,ZBEUon!"ʅء÷*4$_IJ"LMem7$yIQx.!RmI)#L ~ ԨI2(RR&)Bc.{B zye`}8@{w?r"G*SVؔ3gYLyDǚd,I۶e'8%Uzg7dc>L~iPJg&[45Q#C=ũQTMK3/R`FŹnrnd8}y|6,n>r:h)/*;0q]C+27rvY\C9YCM}8 fXp ؓoKDxRAkA%fU[Dn IVVC$&hOLnؙx( ޼MD𬂸^< E/RQP<9ޛ}}{}AY6:r`N퀅n%FmT3tm"K,K' ŦŠ v:QHbgPȴjnAp@SU-S*hr<:C_,`tkdWDzX*B>YX?e!T<3O%NI΃RQeHzPMiji@yi'#Q`(6[ahCsG&+ZJQ]O8ك 8EG墔VK|б!޳5dlQt0JHqZvԴ ql'q< mfw؊kW15u0 bw'eiZ>ode`Z?XЂxpUUjSOг-䘍{,$7(!~p,l68~ژhBk#?LSosZTIZh3w&pC{y}q!x{5q o'/1(:yAfy9o mAx8af/3&~wYxƸc2xL|9t[#xhc\ʸOpy_Jx[ʸqt)x`M 7RbWp 6,x̸q*ق! 3nV'rE-x8qC |E87g F1o>'ͅ$M>'bYLi<l)8x8qb7bL!b %[X蓚^3y_$]hj ԋl#x>t i,<y%Ey9Xx'p{N>`x_ō}?&;G ŪQVy;YmdE;Dtq>:P"xe*CHLcR1 djD)^2 [4ȁ=jRivז]B/T-ףz6[? wػh.JSY5N8kx}I"P}r&h |'XU_0Oμهѵ=F J3X;Tj}e_p"> ˴` FЖ`.EL?V+~x=g{x;.AT\_O<>k1IDNWKq9Ūv}0rX'u1FV)ݦmO+RQ'yR0jMA.a"]!K]le6ٌFxdg4( vVLrA9Z]-4$%24diEi晝!s d\Y[}8ӆ~5R2v7'C㌰a%#cEs,VX*OOp;y6Ry=xqd&a>%_* R16 ʳ#Ǹ<|GKD #RS/o:>ͦ:ɝO^|',_ޟ=!Y}/r~t=7=Ym[-)xjcTbҞn%7F?8*Wcw~wb}WSD94<ŽwC8&yض%HWڛܴgTշ/WVabMW 4hP׿tn)! #%l --dx;6_mCP~!! %3 1I9y%%!: j@|rXE's(K8CT(88x(LgKK/K-r,- blJ$Լt4BhUAQfDZ^jypQ6H<8**/ 1c$8x)&%P7> 4  FALSEN@ pxRu.X&l:s2fN~1N xDu.X&lZ<@xU{;KPs94dS󒃃KK2|RK2t":98A@( ,yG*WxQo0_q^m@i/B8LړIee;к>;]|. al`j"iZ*xHta8j+E<`x%3oS* f?)=>;IBÜ,Քi(#JYa )/#}KYVVޔt=,>7cC^7?i͙w֔ҴlTkZRM Z_7AZQ&}SpE5h5-+ҳ,c1 2;q~VerUi9ېנCHXs[i2_+uz:0ll þ)-$EAכ #/AB7s"wo?C3uEf,+ztT<|bYga{=vh݊ۖwp;'MWe RLv]ΩӸ vqqWؼjxQO0ǟOq05=1)M#BIZh 6'b'A*05kPKH#RecP{A$) eI7!j٬ IA9 vjrJ`]y?1Qf)gK;fH31j5f~2\F1.>o,*:aYY`r֎7(HYұ+iERuz8 e~:xYU~A3V捱0AyOWHv\y燹bN~?+ghkԷ#Kn{@فoou Qa hP$o-'d 8ʣQR&yx+HT 1h _qj٠pzul쒻;l~y5_N_ ZPv֜/2y(5͇' ͒?=kkfh,hH >|IE4|Ujȴ]ϰӺ}O 4O2=;%qD~;;6O$*\LP!כ]3~{G*orx[ûw*7 Y-u/ x[ûw$ɓr''dTNvdrsJS6W1 Bx[ϻq*cɌ% >ɉ9%a9 \ɉũ !>nAV!Ab~\%@IE@VJjZbiN Pp|f5& l0]`:!68l:x[Żq*c +3gxVnJ}bTIC Rn4Dxw]ߙٵM @"=;s;I߇>x΄f7pxVhx %K ./Џ\fC$;|duH J"3\JsSSz0N| yQ0xMgm]bѶqa̪dASԉxth뒧T5r2fw. h?2~4Gr2J1}ft/Z`_;9'ϟAULru)n׽l\ΘPI8M8f{'+C}2 ߏcXP(C_͙;qb**#@8htCN|3HjM(I'*Ji \.NM̤H, 7\{ .Z\ lw]C[6/W܏ߘvFo $uFq|=}O<>|G@JgsG-kNwEע7(]?` R_r,ۣB0`߻éԼ~p;`f) xfɠ F"HgV׶떕%HQH }CA_Lu\"qNAnv; l#ٺdQO߸Q 􀊲 i{kߊKBR>wi[ǴWϔ+v(CajVRHS HAę#Ҧb`3(Es[4Q<Zf뛆o-׎=FG9fKk^ޞ?1rpx[!Dl#GIQ~iqjQfƏAΛ`̪ٝ\`ePGq6x[!Dl#GIQ~iqjQf;UWx[!TtCsp_kDHBIr$XD'OgJ,OKM.IM QP*,l˔\9!x Phf..N0PPPUv *8YMd"\6WUnF 85&ssEJ&;畤V(d RʤP= ײԼܤ" ғRŚ\/0K#:hఓxW[oF~_q6UJD"wA*˘ LklkfMvg|cl\zS!3~̡}mC#'+0`ˆ0='('E cN0fVx/pKf`#덀Q.W0p}9 o(ɢ>| Fn?-aRq Ƀv۶,gnZݶe{6qf3 VlO: dZ-Xwg0 VYWcŦWhЍО̘;9QPj'օ(qx1QGD[gMI;^ ::"uV:`d FpJ(BH{lgbC$<"pqgFKp;IICG"c4f)\}ܰ,0SN;snn:Ix%jv뻎x ˟,a\y\OJۍ^"2d,[& }4 DdYK6{, ² ~m\_ KKaekZyK;kZU 7xq=j# Sd_ F?ϲ$HFc- ôĉ J?sYhp Weo(]E,/]rzkwe Hk*Oq⧻V* 95K6OB"Z%x۠GqC,#OqAf|f^IjQ^bTF6얛bbqe ܼDOfvGxCqC,d;F͙:jbxNvҍ<(vx@fҍ'[poNd D xMvҍTdB\#B=\|\JJR+J7?fZ89k xfq|r~^^jrIjFFHPd^-,ߙZ)-AH.^3fc&S%'K&+ɛ;xbBx&;_|5<_1I& mN}-<-}.NNNW"ĒDNAL@]UL0Z opgA9y.M 'GN~0%3=DV!71''?Y#9158$>3UӚ33MA#rr"ɫt@4RKs@ƅd{$gh{8{{8N*ât첓x&aWE '䕼'_ҙ|Wp&>2 ~>>#9dAN+JMfZ.ܻ#dxVn8}b+H]KdYu/y"dت@Ri}I]egi7=<9s7:\KBL94 ,I1{H%LL A' 1d+ 's2 t.P$4aqB12rOkx/?;nt]Nhg od}ٶkb6A3FsJFp~==)?#Oq猧"y&H1AIL:ɮmK֟A}CK['X,@GٖQan.PUmM@\siKu;4* dBu ,ot]#[Txar]C^˰/2gj9F siNm^/m3)gNls'aSg4}g>ʈpxe e'CV;FK|o!<n( TnjPѫ>on8샮=9I7 -"%ICܞ"ҹӜT^T^p|56}jQ_qcɶ/1w(OGM{+>0"M{R-3`ݚk+_\/,<+ (t4͋G]>J<,<J){ =ZAy5M6= +I+nӝzp;ߖvhh5_dsۭ5)An ^d֝袾0ٖtuS慓S1h84ն-b8ɞ3I5ȁ5Fn\Nj1r:쨟4Ӫu^ƣSRUdHPs$G᧭Jޣ"W#1|vTqGZ}m{O\.jPOn}{3M2x{(ClBFNM`T.~.>&3Uu ̼Hby'<5Yd=D&pM): l*O&Pg9-3x{(Pb&,&elâ44F: <Yx{(St&,2N>b6لMpf!Ԋɼ, y'h6)u fHm:LS$=!hȼm@\. -(Ddhi=)~=:$ Kfh{m`4`ekg{q{ql6].(S.{~K?1]㛈0o Ga#X6g͹ء},of?ss^ܡƎy9ś?4uM3f3u@KAl+4[{AL>]tH̿/ϟ͆zSG=/1#B#]N i4O!o[&AHP =f"sꯁ!|j6 7+wC _gHK/ǛkhGL4@tJh6"f ]o4*4ܙ¡r5N@L`pdut3֖^LJu&9Rw%)[= ⱅ ^ kKb!ĶAl[&tʕ׽1M{L7`Jh+Qn]J} ՁFKH8%BcECc"r"?fDMk;@ #\CڃimD$V͆ˤPFD3bhܷ'p% t_M@ *K-[ym9餟4$mGΥ<\RmN|qSM1edĉeVSȅÐd4h шX|#6M;nfO 2͠*styZ*3a (LMV3" +ذexGVDUn69Oԗ]s[}3<&xcɼz2~[.e3*W3 L.,U2#RMSVd5JeݍzaZ~4P vβk__4GXHe ?ҵux45˔ZZT4R=OahwrM+< yBQzMQYE+ZY*+o-%;`^&Wthqqŀ\5?wQDJ*qnZy-j`p9 v \]ذ_ %QG[$~Yg6' GBFc] ۹Jiʓ'eRkg, Ҷb;Ħ)/3;9- 9mMzЭ>UGmrk kKr0bED(G@iEd/8)26 Jo.wLASqVHm ;fm)ь4y,@EVSL΋bѦFZ #1,If.Kl(aqwqK6^fI$Z-*hBv`>5٭ Ր(o3 گ^|xnŎ/E.+qLP*.QspBή&xxAVP@Qa9-S6nbf β?Oza_UwGW:+]D/鴬+h%gm?@]uܟ㩪Lgr!%re+Y8rVqX!)RUVVF;:goQ"\:JF'(_v/or3]ѮZkP>k,3D:~BG"č7)_n?m:{RNwosWd܍ԟd}O|c</wǦxǦxˋq``/U(jypDABGbiS +Qo(W+˃VM[[88wpeC)LCr:BlR :Z؆m_λ*ytA#y2FG(Gc=]$9b/|N{zzX(d|X=+^1;(Ll+R\FWz*b(!ydgBf H$UTKWuڐL-G9<ī.$[ TKiR;e{Я@38Ne _me ʠ֞(k5^ ,~9m mΦdz2?poL?=].r8%V!GS{ޜE%}u;ruRxƙ%8v9 qJmn7Y^~m"ӌ@ Wj6))ɩ:lM2l13"L?rd콨VDN(QBJj6DZK4KL[~_֓";q9/XK}I;d PyEaw3:fȩxgK5MjXE= 9]D7tcAHz~ <͇Fb;Sg tgHZB^jbWq}~= Gؔ'OV^_/A*Ǜ{F.ϺDo21P?G) ǘGN9Aȶ@xSYd@1[Pv`N=ױ Ιl!M~:Hm|/ҕD]so'0H_Qm1a/":#ԯS uCTulFrLԈ/FS %;q}Le&z@EJk@&0`Ynnh8umVXlH?Ze*Yu+x]7ҥMܦ]P=p=Dpq Bq Q1 9zܲr_b+2= >)@j\8+~S=SwB?T\!IPx[8qC $&2olx[8qC&ևlxNY'x[ĸq_Jo.`mf rOLN#QcsI?x[8nE%:71srrn6Q&xUwvajL>0AxUjd!y||Mv0|e.ɹpN=ydnɩZiE %U&5✼Jr5''XJ#;)'?Iz3O6)L2@ Ⱦ%~~x{\j%CmlN3BA~f$x{\ro9fB 2CrSr6(rf%$&N*2zwY~NbIfNwj%XDp3fcd2xuPMhAelMl eRLfcڦE( Œ6tP,x]wz.ș?;76(GL1TM_,O[ٓuڼm9h+ nxsiYrEWVln00zN;@B`[jڐϼ#ܖ <~R|Xgca<vEDn@r:_V63b1kSΕ Ւ9Ѹv y)h$)RŠ#ه1wb]x b_A ǖ` RۨZZUτ(5-̗uzM` DE򷑒(C_cʘrɪ<{!r<Z_M82ZJEg#F]ӫ fZ-Y7cDlhњVbeW,[$ USl⌳Nh ikK+ы I@-bx3ފKs43a|jn @Hgh @.*ZUx^ro9BrSrCbJRg'xP9yfC9xP=y;#OqAf|f^IjQ^bfy 'h^xTML`~t,?2!A  lnM) -mQM0^^8)xM uC}j uZCE=JUsVT aCTߣNú^:w`4pI~eDJ tD,0I}ns~x۞|;iC .Vfo.N0Px xJ$J̼|Ģ\$U}9& lឭ5x{$kCgHpp|hBIrq|iif5gfd~CɋLך̢#4y2fg Mk; x}!B*ƓLP+).L- άJՁ&?ԝ,f ХbUTˤj@ҜCiQgQjIiQBQjqiN5W-`uxXms6, 7P"ˮ's3n3Cl,*"i$I梶x % b]tf$ kt20%ZisGM@IYNP$EaO /ݰ9F 5Is14M@D2&a% $G; (lFJvA(.H:&ks$[s$3Ln}v0Q8:k=Q_cH@qĵ(Ftkn`x9gq-R-~rKA.I:H _h7]dCEO,ᣴ" c YؗW(-gO1M^w('`;}<[]iu ٹs n]F7JhMvs/sA,sv u,n U k;]zE$Ui̒O4BkeZy T=cud ·t>IRuB8P\Q^O8ܙ ?z,w3ZrLSr@̕svgBJ5J.Dxę{!aaQTHfucQv=Dv#1}5y- 3f8PDp.:-q[|lu~e–?Y4' 6Ҷ^vo>HxCM)vZcyw-#i=bL# 1~gidڧztf4,? g0nBֱ]ν|/oNK]]M5?mZ-;v{ȏ@:: -5:kx_"Αuj;q`pdޯ9 #X-9+[M&tt ?,/ xRkA&ImMTɡ-NNrl2&Vi.W|I+*1PVOV]fPXruZD2E&tI~nBBX:?@r̞Ya%}8 Ûw8_Y=y)w8QLğ+M [Db|7{S sCBKLFdZ 7=ο(km9'BZ-{ Y^APقa%a8١[nS:5]g(0K8#Yat7> ݲLFj&9IuO{aQ[mlUIeH2N*-%ME@M9i_8 Y1x{bxfEdE&wp̽DR$;#1/%'UG!1$3( 'r~.1!.N P((,s,-Q\cʨyd/6 ^!Nxbfa?cL̛ A%xghOT6k0?aܜȺ`37+Y  0xhpC"f/VAĒ̪T"gQ0x[ipBFqoaĸ%+#SpQJaA~ e@y Ն: @dDY2&''%j8畤V(9(gVisvp qUL+ J-IKNԜ/qd-}/ &CL3y\ BHԵKQm<LGArKbIdWnM)ZYbNfJb Я>y%:۸{FjjZsqf)hh#4/'?1)'?)>ndV,OK-H) $+*Ƈ844✼\P +RsSv0ejb 3x[i` [BzjI|N~rbN|Qb^J~FIqs~^IjEOBqfUj~Fsc'(@Sdfb^IfPjANb^^~^r@~]lb&kq d''&dmv0cX1b2r^2k[x[i`~||8xR2SKKⓋRK26;pd , _x[bl>3sQYss9ޮ\*L3yG1~l=xk6h2Pµa/x{mNBFqoaĸ%uf›9V%-cx{m`#GIQ~iqjQfFyqbm鼕xYoH9%%Шwj6qk PlV+sul=N7_lMmoyovш,zt(FMC?!!Gc4`!P#kxLM8!F&umBC?؅d@P{nx8@r˾etQ׻8*xotFDtEw{_#~q)$&F_ے, SN,K()nQ[[its>clMOq_c7[A"^VㄿRBc=+uJo&QBVJYgt83e8?"w #v`qx:c sclSl[&Ԃ擥3Bh(]1 GK/BdlCr~Oz0PALZ;Ut S: [^7-"%2s!qд!0`|;]F[8r:Oa%˝=:rhK .7_EȎ/8Ol_XkТl2jnSq+>*"Ry@aOq'"{b 9HR< @@@Sd c ypPI5`&d5k? YZN*BYVN~Mv5MG]썟6lV޹ސ y7{u3QaLjV+7:ynlQ+؜,r)/ 6 ,MBJWzrbӅNG MIX.o A;CYL|^ij#T{5GFqr [:X+8Ė={rU9 m9ba'NeC}5OӖ@!ÆS(p2 Tdf1>L >Ê͆u0ݸGkj~mj:N0LAH;#h{MjBł-)YQᐝUE|b<(a,O)6!6b^tP/=6%rE0M!C6笳g UgywVQ%IyIDJ f1;VSCܥSM HJ$p:(;dg-;T #~HQ b t k晘b^Qy8q\8kz1CܻO{%;?(Wa}FijV$ 6[hٱQ ,GL.ȱ5rk.#lr[-^rwFqg {n`V]J1[ ݓ;sheX 35QXaZ㉋`~bGqq|7[Gq2r/" /[}VW""J`@ CMgF5H*bQ'![!ɑSAǶVPf|P0s1 7rC$ު-)aCMExD(1 ?3V2='?c*9l@pKX 꽢1T)Pݍg(}ޗz:|K{+>a|8MR/l=xtiG?DS,TxOxr`7Mh\ 7vxzNnIO 63NN UL%&2'K]%wrsR"d0MVVpyPxoq%EDD6 eeL+JM+>qrdd.Q^14 Ҝ[| ʋ358kRsS&ɨO!-1YGtrdWRsXL>(#VT dk9gi8J yi %% % ɉy I +S* @(4=C!.Ԋx72J-}0_Xx#1%%>757>5R(կ MM '8Nџ+c8YQF%$ɱ2 `PdIY%&ɻd& pAJ{$yjVar5䅲ra~*xo=zCKPs<܉y%A9:/rqBcJJXjQqf~BA@QfciId6^92g^Z~pfUZqf:XĘ&97@'Jxq %X7sȿdN~exT@$=zVAs*ĸq7nhF/?O͇μ6vϵ))WtHSɢDART#-L33ZLQiF0) bFBQ^Äc i&x8SSs7_){xzklqm(|Rz~XŘC]c\cJAwzZa1r9LUGUHYRGif (*M.cbYjڡ.fe7g`e\`ܞmY%ys);B\R[m%2mS/<=H$UYm-8z0|5k'cSK3! ry'3YˆNdG5Ar$9@nZT^/PApM!2ZLRЪ; wpnlP6bh!z ky,Q[UTJJz Ŵjֈf"g].KoZxm?0s!.qK'G-sfIZ~gП}hj.x?۶0AKkZjĊk޸64Tmxg%f͗{\^ xs{ɞlbX3;V *xϳ{#OqAf|f^IjQ^bdƷ~!!~.> %œ]g'&hd(V*McvwO- JK;(Q(́$$楗dLǬ6ٓMlr"6 6Q_ >$a_l JFxɽ{C3S@,f1iړ oxɽ{#OqAf|f^IjQ^bfF&Y̚1ocX'eپxZms,m2u%ti+K$ +ȱo. pdMKpOua7/ynYbq^t3BҴύ=7Ƶi;5EOZ{mÎ[8ʣ RT I|bX EGv(WK`"~m52ģa=3t%z^L;@codHj`Kl"aIòs[ AĞ/f _F&s,ovE`-H\Bhd]3û3DXL"c B{ pP @դ'CW`Q4x GxrF:xM-xk+Yg<ٓI/{ k*K(p#Tgt* CSM8r uY:`GN/^嚝Cikr|clb=,gEddP )XYW0^( pjiKƶif8KUT t W6ZQNGLdtNDnlP ~ŒItk&I^lBğw!Crv{/jS`C(Rc 0[YkzA6pZ~-"2a~ol\)O>dSR R~‰c{0%}d2VX Gk:~4 ]n4o<]LbH \q.d|A#*19ʄ&啽2pj7cKSkhm҈!Q҄\LJ)#:xa]bLɵe1S+K4sbQ+JW۵LOT9: 3o@~ GK&A ؜# %|ɇ%Х=T}8}?q[Z0ʘ01k1N-)u/-Xdst"N_0K׮BHuhA=dqu"j84K*oI-}ŨRzrAWBXMQsTxD!STrc=Uw~ЊDru(ezlEݓ)GyT*6(?ۈ&njC @nO} JQ{j8#O)B/i ȉJ@[Jf]"ۡJM0[+,"~h.hHȝ"N7VzwF6O'PT:L5Y #U-4F;YOuT" QdI)1 MdkhGߨ{ݳ<}8iVd4PSzk6t#4طR)b$lL&BT ر.U>:g9h곷$ {@d8b߾,'!k~o^ju W# HG&Fx1lCsMub|2$Fkb"G-fSk@GPN,ݎtPz#0$,ޑBBF@0i#ӓdfj\XMIK)"Ϛ y9f96܎|'+/J@AOY"`g=㦆^I.eF!F yF2E5LLZM@jӯ.k % ڙK-NOniC?~?oƐ@HSָGʑ2x&~,nq@@T'X%qtH&i%e29'SAlu1.$ˋ3?H]= vT~>JwTU=C5y"IqawjR`;#}=*J#6H ysoxa.B5''gZQjFqjbKbI570S2y3 7g-gBjNqdY~V6 `\ǧďmusA:& kRxi٠:YCjyxTLK = NULLJ!\ 8 ' O -%t"Z.\')) {p"m[x*LL(!` %W-FSU$1xk wj^ciIFhqbkf| j@'L~( \h9pkP{%yIFx{7cRyyɩ))x%'{(2oQig^"#8x{CװJo/ c3Xx&KK0 %IW/4x}{cɿ'1Lcu qU*H.rI,I,*0y `fǙy`rxUAlE&u[Ix1$J QP!M:U.k{l/8$ 7@B 5 =; $# ffMT!|{̏+Oͽc[ĺ*7<<|~%_Z}yEFCqUfS|* %$N)O9V2nu|ڪRW2W͊%TU7۳^2$ڮ"n)*/cȦ|muhʕ/YjjՂ(*+ٛX\@0:MES,a7boMXnkpp:6%dSŊֶ5C1qM:j;/{nb1V~A" f49DaI\ncg3 MdW|l|c 3Hs 'Q̢wB&$rݚ=wIirrS+&IĄif.%- ⒔vN,)@i2~X3"kQX7ZS&Q#VN$E~,撐pE4yIy"G9 QwtT=wkn,VeEd60R행:*c #UE#dR U5yG"qȱbkE]mm]{[Zlz9%%M$RTgĩ=p/3 Oހ'}NTsc#aR kEGme]M|ie%XEI{GA)Q^+2;p<<7Ȃ^}}4;>L8tvǾ(cex R~BC`|}jM Ӝss RG.8ztc |1;"@}$n/zvB!@u$L<7 {(Jz:EiKG޶H{4{k񘝇_~ç- `vC~! 6țTiQ!JC&K{blQVW)-%.:%ģ%"@GV*\bLAV_\b3q6(@Oh ] `33gVB{^ W6`x[h7n6dF振d/1!x[hwpט#6μͷ'hm]&i{҆0(LjiNh^1ũ) }RK2t+(JOOnܜ)5(5Uc]9-|'bDPN !ʛWRT9y #D7_td +l'(7[Z@NA(̱$C4WP: %@Ey)9: jyɎ%ʼn:a: E)E%@=@q Z ԽYˏiy<3y4jMLO-.уPP['O~,P\XYt Q44 0+2\s2+;ssn^ jx[khCYL1nc gg*.|erdgf7' OnL8mHBF@~NfrZJfzjq>?bc JR+JtJS+=RrRuJs\K}RtR ւ2Ғ $'((&椦@n/~q I]2MC_@xbp~B$omg^!axbpgr~nA~qfIlB$omg xXmsF,~2◦|qa"pYH64$au{<{\ :0?&;xp(\NjQ lRIL"@WI%` o'"`RgIlQ})rG 3Mu`ĮO-oKxs}?qWOc}YUQ)=$fB͜1>6>_B,];WoٸK^p(˂͟LXitsmXiIEbzxLQ G+WgQ8 MNja{PUn`>j:{z~Q$s;L`M[[TiғscD?e^Cǹp@N͏5c6Ѭb]͉C>_= Y$KJ<Qͭwo: ^߈ٽnZsxL8_:8>uW$Pft!(}tY˜eSҴg{';Pr7_FaRȅIf,9r4]rbarB5L"ө3ˏ_][;M0LcHiM^2 J'o1Mثh-O[̔lώPk$kwaC1^-ח?cd/@y15A RwaF[ty.YR_R6M_5Fb{(@^Uܾxx紁xA=?ӶYi{OgQV6XL[flnvr998EzͫGQ1zE՗[uY-UV5;eɜT9{̿6z'WK?5_|+»A (4 髓,K6˒NmL`?Ig{B5)\ͲVQ:ň#R/KO*Tz84Q!l`?J3b!ĵWPcǦ~ ٍ0Xa6{qwsŭPQxyW7tbvƋ_y?W UrB/dh6nQOʥ)>"D+N*}\Fi;n6NB63I5d(vېe%@F4KVσmJR|\9(N.O96'C>-8sl~3\׭X݃X}̦J1@4D9)H }|OAV(jXjd~HVPfLW(_QXmxm{r"겷/qG̜<~f[Iђ};T X77T8~0HfQ?%<]&^S^}79UHk6P }dp_+rvν`{;S9%5:)Uzy1: mT28)MbpP vNAcRSə x{[fK^~7xH8{||IqAfdGYO:x?Yo)L2*'hZsrqL kx?]o2 sfU=N. #5RSz8Wh^N~bSN~j^K)L2*'hZsrqx*E(CxXo#OqAf|f^IjQ^bd-~!!~.> %œ2RKRS42B|uԀr@%YeRKJBSsBRKJsr4@fL`Z!֓0;8NVe GzRL|<Їy(=$(1/%?/?/9U71$3( 'r &.N0P\SJ2*a~AQ\ 4+%3]vGn  ; !;0ީ@ U9dKK\K3R15'O`۬¥ xoHMMr\y9)N9Iy8pDDD,r͠g'U((JOBkZsrq{ΈdxRw#OqAf|f^IjQ^bfF5F L@zjN !JҒ .NPP4H3F5Nx{Tw#GIQ~iqjQfƹb[nx{{Fw)V̼ԢĜxԒļ\T|\EZb^IfPjANbfuL<\`sHj! (dd&Wd n <#xVmsF b'H/iu,QKcb4N5H8NA}g[xh4$1#k8h1x N${H60F=ʳ$g$ V K,$/M6Spy~P&Ivac84.rFcFw 5ޜ}?JǦiD0~g|ѻݻ&[!9cGW+ꥹRS{}J:sNq(Qmʒ\_jp< w6r‘aC:W{]}jvkp<#so9zD${φ!jgۻJ}`h9׾E?Z9ߝia()CO;?]ڮk%BˣB(v,1nI" U/n%F3*bv{TEuOj<_m c!lln7D"E?Mh[,m0(6Zr>,F '|`_Qnq|쫘J=R*Q4=y C{::OL,0v}zUP)vߤE'[.(m%et;rO5T3ٚ z_ݥ@sx(gGagInƪPgH^T_!)*'Αk\_djx-yTo͜e2#WNQ kYOuIzMgD?([k>Ëfv鎧=PvW\nɯUx{,wVn6dF10ngdL/WHK-'u2+{GcFIqs~^IjE]pfzBIrwjGb^JNBiKbIOjB 7odVqӊRS5&T\bpf)hh(*$ƧUN)թUPrEbIiQ5Vy%6+q9PvHQZx;+wEn*Nͫ8ZI3{x;+Yv<̂u11qqN~,8@8bBNock\ >f=LybOv=#{z3qU#Oaywɔȕ=oZͥpDHUm4c7'=r3Tu@7MO $_-i,d' =Oz'o )93L:޸߈".1\T qḬv?LQv$ Q$KbOTRZЕu(" 1rG6 ad{ @O8X_olv&Qo5u>Vr0%2,S|! (2-,$^3O,gZLC&p3G gu5Ui }eMC[q'u˝zgѲF-;oδ[bA5"ENh $`.&޸+~@q렪8w\v>QF;ݑʩ4nk5*dUgRc֬Lw=3 n1 @2'>f~YectioTȸF#{1(\aKid;7Y$Ah0[ :u`l/u)){U5 F2L&X&b X BI9{gSpkT'ch^5δm븪ye"&b{GO+Gj 3x¢):#ݳ]`&/jn0gNM=|k,#|}|T1묿A9lg;k|gj+ox;,_z##GIQ~iqjQf_2Y!x/}Vz+{||IqAffV.wfgo1 > +!HD?)hg[6g;ņVL !1Mrӗ{D&KF' #Jh#B&Ǻ:~.D.N|wBv~$Gz=0Mr5l>]z#:ƻqDѻ[WMv]lP/[/8wv3|#|?lKvM$K\!<+rgE~裾w}K7NFculs]mZ@ϖH׮KH@`sw %oP:&J2 w(8'BwB|ɶVŽikȕ0sZblpTذ3HXd10ġK%/.8/x`܎aL~#s,+wrOY;6I=(Z1-,pTŇxK26.Ms-{adiQ?,>x(39Y&I# Z!s.E$-J1{~` a 2VXD"QV1u2%˺ݴH&JTW',6wj˖k`ݬRLP+aW3P <0lWdF7=s, =8d 1$ 4S;tRDIZ?b5QLԻ:WnUaBUQLᎮѲlXCZQ$r+BS?*ˁT"R灄1r .*Knhz̗Zi4T!j«qI# d*4JխC3|7;OJ rtz^|C](A7HRS685AE~52\ *[08u@c&2Banj:r0IOԯNY+IPP]bI=OVPT  rC]_ J} j7_xY֕e xY!gs6ե?Y_Fe40)wG`AI&/c Ai h~=Ujoeo2:wh;_ r6upn$s+90NrC9r7xV`,`NDU.q~eFE㉬-^vn<ڰVmdHlHeKvG?ds=0>%[cd6O".P|V0hBWf!M5Ǐq屘Տfhؚ׬Y8}:T!Y{1<}G)mːh]VrT̳X=YǢCi,>_xn*f@{x,W9^:hoࠅ־sN5*rW#!Ա]mr4 E -9{-1w?OhM5XkVOWLN|8C?ޖx}7V`]ΰg77%sS[[Zf6L3Q;h+ l\6~YI$5OK=";s)@1v? C7E` T֯Mx=NM o᯲h=dQ,%+_ 0_ @ʇA`@0bwsZW^z'lA0c4s`=")\~)ʷhT73s`F1-x7:(6aW "< ®m+.-]0 8^pG{ా4Z;_߷?n] 4?U'Ag2 B`?x{Vd *Q鍉VEw"x{V2x3*Q鍉_<#|]KR SJSJ2RJJSS2rR2KSu r3ҁj2KR|݃mT!Z|]yI%ũ%`sOfpSd3- +<Ϋ02589C f&J@qkU̵Whm0]ZS<ThxYh3Yzf"2m\`Gf 8,x{PS4$Xg2>GfQ ?Rx{P;o3QrYd 9SRJu89'rJN6c4ST,VOK G%&ƃ*U+Mȥ0ydNͻ٘6g6כi";fWiVG^"$jxRpF< l$xRpF\ $hm;xRp+F\ (jSxRpF\ lhxRp F\ $Alcx;o3Fss)>zxEnm gtk j GTK libs are^GUI&|&.]) ]B/"Y&`$\NxuTnV &mWZ -h[+JhPY hfM.80 @6ݴ . 1Џ( ɾ?l2HTxΜ93_X9_|*<کRj~#<ObI ;:ύ?u}ʟǒѹ2[1.\0=p-Y"-}YNc%fʑߍ_< 1.sY\{X Yޖ(+%EQϺ(0ƶ]B D}O]sۢXrAh (ȗd^=Ԭ^$]ڹ,Y]kP\$_vZ>ai\]Mr6|63G4S$}G񀹴c&K;8-ن`H5˓X2=`.og/VTwݷ( KWM-{]fCC,I42hQn$Y3,]Ѩ>huiiUG|tj5 ]R*#*50QS@mdKӑ_ltlb5% i4֏; odJ7X޶Z G@J/hCD)K~ u%8O`s^a} = < c7T~"2 {0 69ykvvvҭv=0]Cdo+BOd}}]/ ٣ ?Dpl4x;5wf-&RKx;{5gC2dYfL͛Ә6O̸Y3M3gdB NhҜX.NNd1>%fm NoVgWd=C/'GOb9HYKyr.L6_6b9jlxs,gfKCV'3+xs8g3{Bl4aoBNxs,g3arY{Bl4a txs*g3arY{B=E5L2K rKbɛ6?bli( \lDx;sm/͊򞌛')Jx#u|ɧ &+ʿl`y0 #xgd !8 !F CNx8yCdE')l|B i/ ox>-yCdEU')l|B ` (x~8idEɓo>xM_ 1x*qdEɓo>xM]j!x{0q%ɏŤ7" Ox{"a_!F 7'qq8:(N'CNw|m'Vn-olx{3kBƞ5 YFl x9As3Fw|NxxuTQoVVQ5n:R98Q8P4PaDfId;$+XNrXumkwF۞t=Ne~i#x6mTtw^FV Ô MhI$ALZ3m嫖Q=M?aoz^_d.$99{Q8s<{,s?TTgKk2Ml^2Èbmu+`rbNw9O2un"$ ЈE}" bT6Z$s< aE=OK=eNsg%eZu*QW& <$XZv}~Uzmߩ[[QU*|xۤٮ2aYL6.Ÿo>q 0x٪.TnyfIn~Aj^qqmcLfaQb⌞"َ%T=xklR&dk{[qǻxlc8ٞ2=&qMvVvwpuw q j\-Ƥ0 ܜ @3'=̱\ yDCC@}<57[dVuAuJ5 YpXDo:xkR]2m2s|,1dTxkR2|/Ʃo9wqxkR2l/Ʃo9uuxkR2l/jggtAw(3xkRݡKC"0'+|6[ctnnm/+XO&CY+nuzZ],M^<,KCщJ>y"s !N{xġ(G>lulbƮ,5͒sA8-<8~<(n>p_2ߵtfv=n8O~0= z~_Cxt[{;;l$oOzwzKe+EmBJSUElwxxer>S__|ԳwJO]\ZT_48d+b ]eJEɆ H-xȾ}7&65Exk`-]*d.2 3Zx O"/V+ C  xȾ}7&%w1;9jhY{\T 6x 9+u'ꂹ2? G$/x _+4O'dWkܓ.xȾ}KGklK䏴ʵU_ٌ , -xȾ}F캆>^rح~;\&( ,xȾ}7&6)ˋb~9tWMż ,xȾ}C4HJS~?`i$GLN -xȾ}7HH<'! *~^;x &&-x!"KXĬꂬġWcx ³6{  \xU"㤑+NxھD96% ͟@џilo^4O2\0/ yH}7p@3=^' j=orYH_urR100644 tss_typedef.hi(R=:GK@R{DGMgx zѾ9uj= P /xȾ}Y&5} *M[DO~tAVxȾ}H3_̰>KlEҙx+.wr -( &(yeE%\\` gWdz>...zzE%9I Z/'Y{'Tif^rNiJ*.vA v S.$Z&~xǸiBJuI~A|RifNJJfQ(M^PqQ2XC1M)5@Z?3/94% !">?xqB{~qQ~IqAnO i2x8Ajj.XUxXmSHl>6vm^]XB:B(\.Yٓ%Fp[{zF[å"t?tÃ:_"n#Xآ Q2 %JB)K~bhР;TLR& &<B?~p"qB&:E“*<ɘ; #Z*&'"`ZQW7Y"]|%] Z &>sΆSC^mrYI({ď(i7]\^Ln _L>tuDC&o.#]ȱ{o_ z"vJ" 6ޠ'~VRVjr4 Yj3S=g77$^?۳VmVufJGvpn*N 1WBN>}Je۬|n;M183ZfXDc0/C<4_`IYܑփ0Q1"Q-U륰odOЯ*d]򚈢`G, 1X) GhԄ!o*hЛ7ٿx6kA%L<pp!N5/?HkFkfAk_NJk s`k}.h3Z'T$$ ]߼?'zX2E5{-&9R  ;@Bpki&c$Prݥo^WOhq﨏bU@bď?6+@k+zk>Ob!G%|BKdlgGnj/y4٧[R#Kv =-U/z%%S;ͣlp}]T! &'j݋^7J;*u3压)[( XU%s%p("iި$֣-b5m s;cW¤jZcb 2PTf' 2H@,i(W7ܑXVX/ӜD/ ki{^2GO~ޢy]LU*?koJ7:-x04`]}X;ȅ-荡މM1hφbyFM6*bG øm^i:|_(AM"gD ,GjO's^ ˔͆ϡ>)zZ3r®m ieVڳnc}NjS~MCNMd~wVUȧ25K T}-VJTkGM&"|} _2Qr2qm8͗(ExgXWʎ [6ΎkFU\qB)O$VJPjAY28nzGx`dYlrD1xk21ؠ'kblU $l4`\Mɶ|21jm~. g~ exYmoF,KdR{8. vj IHbE.M(R%m7wIS\zI@<3puij"}.GE0N).%|d΂H9/{oO uȳ/ 0m]X{wG 8gRa~̕(^`0C$0p3ZC洃{WpċÍ8!fNC!˲^[_vD GRlF1] g\0O,G)SoK^qU;voSvjr8@A,2Uӓؾ D&L+FV4)~WEggԖR =eIӴܬOM44(I&cfɾ?}Д8nù!GphC3oǸEbTɮ†E|%O\d슰:YuGQ!8偪axs4 \/MĘD RO#nFhd7톧3P׃WloC{80vu^.har"{`.M?'}|}dj>@!>D0#b$x gt!+{QTԌVQ@9,XD>YټL$:,ߛ? {R) ؒzE (b㵅r?;eҊ@ J*z if<>X}ӆw$}  <.{Z=mb ߃kHwP:ȫ;3 ^'t -m׌keeU5_5bHrir~qy9VHZ+@|9â huJܷ$RzFƔvi&Lح{aCi 8i+=)hc%k#ūiiEN] * 5:eE*X#5'5|$[2WIc&_S"A P1} ClxE8wK`HKtJT-%,]c(RQ029e"'Qj #-)\*䕅jEfZbMy&-:d69m[BUIupD $_Q|8!"H7G0c>e[sb ٥ei+Fꈡ"'Gk&N@Q@Us0A~xyU =v҄*}IvMVc+M|.6g>׵%H b:Tl!^y; d)D/X >m2Ue8,56 /.m R[ljUAg[9`W!UqNy͊%viVDN 2{~Z' zQѮ[וVuf=Sgtm`FY/;0>IEW3˟3ݨ:$\1階0)Y45([KFé\Z_ _zU0c3Iu?H1cMx NC.IDP&/藈viMu\~D߽x?0d⋬J̒<\D,rpYz2Vt"A,ʶHv3uNƝ/WzgoNN`Wk_kɃRnALBδA"w¯0LB;~y]&e4maotCKVErRm=fnhķY+%YvŬJ4ݫ dġVxYzJE@Z;/E W : i @ @i$@BiEy%i%)@%WBJ)P8](51E/&Oi27ʪl=4QAl X2x{pa1z4Դ̼xT`xM$ <&2D\->$> /čS)''EK958|^JfB>PO& GlV_dl6!dv )[6S3M;4'[KL!dɫU'KpN~$c3yf'LJ(V*(MfWS J[x5@?OX%;\%o <6B Vxxak!Yk.POc#R aj*M'¨Iؚ HՊ>1xe~VI&c% L&\ ͐6ߐbb c,xejfwvGb,Ť'Ik*rLJz(yC 0xX齓E&ȸirqrr+gXs24rSss 4ԒJӢMcu`(gViL՜CI] =&4  PJIKMRP-SQH,J/69(̼ɻwNEHxfjChAQf^I[fNBfBjnAI⒛gJe}{xfrCB5gyFfNFBNjB5'gZ~F5h*!X+dik(djۚhrqNnPCeq5̼4 <%Mk.AO/qwxgAkfYν\n> Zi\՛W Zsqz)d(hMnVѴL/RTU0VTQ(*jښ \i E@UEy%٩D57K0m)#ix۠լYYJz"x۠+YYhr,\\WWZZY_PX^^Xr|#B}}<]}"]#3srJ2Ӂ sSr3R\)iyشrrMn`d114|=L"3Hodܦ06 <ܜ"b: E\~!F Z@Va5hAQ f Xnr~|&3 cS Tx #3B)L` x;*YZ3OIG,83?O!D!)UN@or-6N΂̼A,&Ƀi[`ZƏ<=mr' js*+(hgVu vv )>y+b&t2;x;*2Wd ˘&odUu l"E Ey%٩: i"iT= A>xZ[ڸ~W*Sg[C2yh4mM[K-:3Ui@ZZo]1b<_}Wfi3qB~[=DAK)^݇eHܽDSھ $M6ƞFƫh&ɻEU6޷wP4N&{KHQ:ߺԍUtCZeJ2Y*IE]2іI1USc_dzk^GY(#>K-"e/.9Upߪ͍.eġ \F('Y7:msYDh#i;zB7, 1#p 0Q^J]6^ވ:0pe`OQV L--:=*HۤLI=E9 {МZӪ-SY7]5Jע:"ש*rB8Lb~*qo{9 I\@cg_3d–NEK]Ǵ4++βReu~Z5LHbF0}dNfzTZuc}O/7:>2M:e<0F!%s>VTi!X'#k LW[Mqt?TxlT]83~*>%7ʳg]]d\~9,| lM I|)ju#c.>|?31 O.փ|"^@<9[>TՍ2gM_`/gt'H..O'Ƭ^1Bp!A7BT d yKo`wOܾ¢!H+Y ; t ƁO:cfbU3&X=l q@;|X/kuJ;acTC8ѺBJ!ikMPx$vx7&^WOl:e(@@b@kLDc0.I\˽9U OeTx!Bb/Iy邹= uU1TJ  )^?dB9xبU /9=G*+%bqxܵF]k[!0s/ P٢ 77)~+1FҀb%vhXeO1ι( +}ftTQd: '>E1C/]ve||!/(&Z%cv)~"OD^h]e3%ym7o~1B^K)(V :jNk! ˲`'!P6RB`! D)% 6S>m^(23Ad!bgS9!d΋8t*5)la45t|qd#[P660\p[8N-\-g1v6SruJXz0ݫ975uf/):?#Xɘ- Fbj,Kpg + ik]RK8ZK;LP'4⹐Tu7bujgV2 ](vEW۸Ud1W3c `6jX;)3spi ?t}JbM^Yb g:]?p2Oڢ"/c3RZA`Q!Hm xN8Ȥ~ӷQpix]ޣaad0s se$}(J79ȔΑ.=m?zy2hcQ̠iT] מ)LNUmDm:U5ݻ +(أ2u Y$TQw).kA8vk(Q ) 7]Zqhsл%/ݵ-`(m\M]-k efİԒR,R}(X5`B㓯-ͺ)]!1ޗ}bk|mg1n8}֟u̥dikuFh'Xj@Aؑ)^BMPJ9S3({z[Z6Kc$ ~@U>u>GPveg[p0 m  lToJQITzLSs//d43*K:=hQp gҌ9%vK?pnkv`C}$s:P [[X㍬@56IX]w}\Į/M\MgG(s|?)lʶn|lt'i j ׊͛ŕ mZ|oh5ts&扈~DI*h+>7GFiu\x^J8y'>̓8/q(z`hM"h2xXէ2~s2e?:bo~W7ㄡeJ;?xobonN"7CGڎSK2E].H5MBp *7v 9Rإ#7)MquV͝u<9vT]WT4Sn([KFN=-cMnKfب ۓO'QXcL-kv7 ;M"r)#;Ѻ yA_  l9sD;=|:M\/dKMq% ]\T~]oHzX\hD,2!+2u;NTIt/8$m-> }OՠI"^A2(s1V=|IhOo$"-N53>̗I|nܶ*RQO:?(a?e8뎊t[>i/޼bܢit߈ e[928+h*IZt&> 𵳿ۥ1!'̌U$Rn7ar5 MSkh9:m-Քk?6*3~~kDDp km"Qv}d"9_Oq/W5 qܵSl2]θȝ1Ғըb+⦳]1#o.yCY$kd}7)3*d2cۖ8(. ,tsA~5S:}NBSx<Φ ~A^vk׉U'tn_{lwC/8uLw(y fp}&3/6&=a3eK.[~կrMShƬ9B )g$n9Ub:hky:2>HKSY*=<={*I:;mO.i\"#UbԈ GQg$@Z ǵs{|v0H8Qa.[0xrmn&]cOcK-(ck8Dru7́ڦ,TBIlw@ {+U~z6xdOVdƍ{y`_ڹKldDXJ3t6ܱ}d kQ\T{<p `=G ^=*>|`Tͽ9݁ʾN 0V4nr3 Ôx9eUB[~bJUq{|XA_[7p63lr^ KwY~lԶ Gķ+*{_2\ǵnQZ{Y휞9hl}v C\J.xT]aٵ ¾̽Žͳ 2U^j^hK9A cď2?rog/O+ dx;4s ,e%6Me -x;fyZ ƾi迳Xj<,;|$xI'100644 Makefile.am*ȩ9M$ ')5\<ӉQ M/GQ}x;6Me;Jܮ/>Y |+x;C/8 *x``R740031QHNIJL.Kfh]Dы)2wMTw;x``J饟r6.K\ʸ m}^ *x``R740031QHNIJL.KfXyc9{3wMTP;x``Jd[@@rO~K&L9q ex6akJW >OQ1ꚨu5P}n%I3ݤa,JK0Dx``J$n<8ynr >/N nx``R740031QHNIJL.Kf؟bhQYЬ;:՛E:e%Ϙb&m}^QSx``p^D(S %: T{kcUh o*x``JdVcaGy*p&;}^2Ox[ϵKD Y/L^CӚ QM{8W<_T+X6A fx[ϵKD Y/ao¢WasR?nY+k_ɇSm:ŞFhO,M,jO>çg}ˠy:uŌ"WQ_>y΂!;&{3)`zLuKWwݚ¬y3;aF;[tx?d&1h{,sP'x[ϵk/Hie/LU1R=(n _|"33 px[ϵKD Y/[_2I~slڨ 3M:7x[ϵkBow+SZoU|֬ۘ{ m+x[ϵkg&+>u⭪K?qzb3; -x[ϵk9n kΈ.TiԲQLO -x z;IW?3ω;屔֑-x Y>\+/7bXүm0-x bOF䡹uQk[x[ϵk)Ʊ|*Ȧ0[{,˲ x[ϵKD Y/A8M–oҜFX f }6x9 4:(;إJ6{kH8r,kE-gP^ &Gx[ϵk]fݞO&nmkcսwav-x s/Dyl/j-x[ϵKD Y/YkN?0cK6xk a2v maSO0ъgP˱5t.z{ :n,Y18޳t?4 R=?VfC<8Sk?|&x: CMM@[tRφH#KU8 wOu(ߞIxP(IE= /qLLv -xH <2m}MJ#100644 rpc_quote2.c14LvÌ !)VxI$—L_).m+Dmeě -xk !$wnѡ;e-YHc70+/hݸ8pCK {x9| ҵi<_K vsبQ*!hQ.;kyxzĹd5'x. !100644 rpc.cΕĕ|1\wWN!&䗚 =x{s9)e;'h/^2c6կ~ #(x Yv椚eFΐEımu+_x;|" ᰮ@Z e3~ҫ{ը` 5Kx;"sDfC Sr}j%'Reyn" -x;"sDfHh[} _ns8"+#bs&| 0x<'100644 Makefile.amHބƩ(' J$*#\'i1vHGS`ivʷLUgҍYzݫQB#*"NBSeMVX1ϛP59*;:=W{H?**ÅKQTtdGk/5QV"SxRĹ)E78dI bKz:M`9dt@BEi{u3mn}ZݳR' axI`tQu1uSVM-x.]pcś8k9qkU kUxE'100644 Makefile.am@R1dm'8&sAGF u;Sx!~КE'ǫ!a( jixx&100644 .gitignorew4*~_w5*o_&~M(T+g>ᐃiOٵa<`1l蕲-~#eIB4ڭi D7ULГ4 3;x .tλKECoœ7xrerF969SqrkIdnƙdxx&100644 .gitignore- 5lWj [Eʮx&~5rUI!2gnOAr"a Hytk*eǎUdmt:NJ4 5x4x  tL`r(Dp/.\I)A Nm7 &X^Dx3Su "pk=NΜgi?U7g;O CuWLuwRax3SR(^xi!giw}Y2K;ӥt80xD !100644 rpc.cvvsIElKw!b r6DAM Ԍ\pxXNH}JP ڇ)8!U#-OcwƎa+}qÂ1 d9՗:u;.TShQ!qms¨p=LSиn<1 j>  bSF06#`p۹-)EPɔјCGi\G!Ifg,p&R:ǟrD}Nj\<,hzhu'ܕ-dsq~Èŧ:8 #N s-;QǞctiՊ̵= 8x!E1 52Hln`zh7ɴgSV@F qk6T<ʿJT KvLoӺu- jvT lSL<{~c^^i83?E׷R=şɞ0.xn0FWrtuD[@uWSi=͊uRsKXw E%cG204]/Ek5SkY(Ed|,8\pW据V^t` l =-2sM+8N͘olW["`^ ojYG0rM=+[mDmoŜ=DruJÊ$!#$FUGkdVWm&Zx''/ 7mLkF^aH@p$.)[|$$Uǘ =EhWU0bPM9 ]*]$dt5@V?=rv"-.$F\qG ^H"c.+GyF&:׸qѢ# ,DtHƁl5>z:G+y9++ %Oq~Y'k[yvtI3A^mcrfH(&Qe$.^ހl4)@lk+d՗wsѡKR|oU/vt3pDCa6D`D|`hj~ivk>o!W0mD e Se!! 3 O =dAk32P|3 Cg(Kx{nwnCAkDp1rNix{nOsBF&dg敤%lb dLSH() άJUU0(*Xsq*TsqNvW .1^ d.V~Z}N&`j`*&&\1,|x͖oAǃBiQJŶ[kvqKPhC)*I`S]C ŖKlko&5&=x* 7bR!Gۘ`ym짛o /rr6\]r O[ b"aD+|x!d` 1J+ėq+ȯ%A DY:R[`\t5$v0h?9uh=ok~?F-IVe,Hhb $-,ChB9lIe\1,1ݒC<+ei'"FO%AA$TjJᢌS+Q/GaYy;`;5#oUPT1y}[P+æX4x|DJM] QM'R_H܎/gXDIrѽkg&v$`BK*PM۬9*ݔ^Oby& .LF-L_+e\2Q5#|jj(=(%ވA)B˰4XgJ8x7'Р6$'tEcq]<&-[5]Z;2ZNC!a4 sF"<3TEfv99™d,?Lh {|4vE TWD+[Zsq:lu9x4} Dwn] ߜnl~wQk~v139KxxۧKs#GIQ~iqjQf;aZxə!rvLLGXtkd x6S+1fg?B#V"TcgJ?gNֲk[ޔdӡFx{qBc΍5?%QU69rbz-Yyx}iCGg+:XGXe# lk#p<@ `֣E#qv~[GwO% ?ĻALwU]]WW- w {: ٞw+o!jEu*PQ(,V0Qn{^owcF;8 k{숗C/"~.P \CYzSL.\P½rB1=wGx!@`,n8 2@kwr)~Ӊ}wÊC~N~3G=_9ZAu~4.FS/_ y8w4tS;e{oDss࠹{KOxl kכùr-w8\(S5ɭbg 6_;_p/GۇށhBQ<oip{> 6|* bxDuI,r͞~#ޫnhoSvrs]i͝m@Uv~+PzP=ڽq xE>ϲHE>tN0|u|i Կpk-JװPT O+ ϘhSsT[/*,GM`|M_^ÉSZoߊK%7v>Pѹs1XTB tɻh|NP)x [ aG$6(!g8ްz_YW؏?[Iԇ4&!O#/6NG#5/&dgUl%Q}^xj(,S$u'Kq>v0nkjJ/BAA_W lU Ph܌?M5nvlnKc\N/Vq%qPcJڈ=]ͤ/qKYMQs'Mܐ%TƩ`MK<7Lm8,@i%IX敡 : (d>rc|z}}^_:E~A?lXE׵7ݾ;{ҢoC)X׾>FX>|鬈by*Zˢ%GeYGu{|RSo<7>rc$Bه#7ca[kZ;^mXzcro6_t[J5IUeޅNfVswojvyQ]9Q:{ͭNU~@vUa ۭ;ʾ,GzmI){GȤرP>)]HGk ĄqUU4S.4%vwong{7UgE'm>OOVn;rנsۭ{֏Bg~,"݅Q~vo")kzL!:gq9Ð<_pj!R zdx1pf C h.o$XݞBg~6p8v]%H{N``rޥ={@-pAT cdÈ& rKaC7JHPzT8]*٥^BI:99+ӓ:|/J4 {iW0( P&!0zQ`5 =>>嶔Pj8=6ظp9aaiV/.>I7]<#B:Fעź(u̾ \`{=  =%VUDp06PTt8Jv4Fx GY7@DC]}>!` ,-xCT;M]$[ Uq ta$Djr]R Z. Lv܃kcݷ H-3(moA\ ˃.A`mUG ˆ^V n,+bI[vI?I[ZMLwa?Dac _Fo<5ȷ ۄ^x9/KJ:5}#|1 lq7Y/K|Q -NUgҿFzm H<[?RT66L v8@Yz5\-g,Xi8Շps `G5z'rCđa?~y r"h.nDGpκHR z o]܍j V5QzUI'А߉pCOzι%p훢웄E|Bޣ|$GԏG =92Fr3=^A-2> qr0N w\ DxBizqz "4Q̖{ۀ#{rYm_ 0T-DL 42eNA0H%1?THB ''P!v#񤚮}5^:y.*[j.xL5Gw0C9@B^uj{l2VBU령S9F68C&DT_F݈,bz߹S?o4ToIp|Cźx/>yRVMtҁ>lD)9~jjW@lO4}&궻t׊a@[rnD-b>QU.{tMDHOiఽ;j"~ysQv ' w+Zx9,],$~T2K-{˄dԐ(e8h)5*S b@:5iO#݀Tf<}d ~K4!A@3V ˏR@.j }Xv + :W|ځI_GG'ww z&ˢ,\)R@OJ *@ k&uc!RtA5d:V~P;xfh7 A3cKM[>%&&qr.H(8=:?P]AF;CXg"MMdRZ1)1o0͕HA:rsqB AX8Vlvo@NA&v\&{Y`z,E#꛷]xIwXRFyTI2ϭ-xΤViGTZQYHov&ˁq]e]\uY#~I1tIqi^-ı8@B^&׵֓R%߄Z8180ͨ"tw iEX5lm]NPZ{j+E997 ?b<2sήe,EHEzkhyU8FIVIlE.N Q֜~IEƧAp{m., L o|.'Jݓ9zz`}HC#Y{n ,By +% D ORàk1?E$K[+@m&žr+헇09Q$p{y<; ,3L{z7`=*pQD0z+FX+,]ʢ&e/m[36SDX)tA\9!);گM< 0B:~Tk LKW> TFFL)cf.TI,3qD< VGcr|*γDLK"Pפو/lda4F?kgl>|+zl{+oyr%N}">QFN;)4'paO֡>kph7p\;tK2)dO1\:vO^ ;L<_={u=7rC_;*[MC77@s'S4f.?mJHRT`;o#- VbI2C2:{WV|ù@7a#?o[xltBiT$U+:Y(_&/@_NB'DE1a&r&=v*M0f `9lUb%{da Q~b܌1]y1bU; "H1JH!C~-gekГ _$v /'P;,ONFXʵY/|HY!:KyK`Q 7j<%6QLX2_骚چHUGZ12i'ICgCJ'`?]IZXFiKqOF_~f,$aL/lfV&,d&wx H_(;R+ߝthi~cfq1u`~2&f@mP_AYD ^Niqӛt)3XHԞᡢ:]yT9v$5y "r}SӜ0e#Dx꩐=@)VI\sB2s F xH\(sb&Д}r [@sէV|W9Wcș̞xCSD !#(40R# t|#DpqaUg8B @[1C4Td`Jo'wǷ8ތ+*X0R#{"~+L) (K0\*?{nE ƹ B6!dC!+5H=2vJC1Tzry6<k߭2`GoWf=6v G{rbQVYԍa=\:8+hthXܡAlұ\KD FᕀɈ7Pso % 7̐J|*Z_MbNt3 w)Lu(x3'[Vmբ:c"g-,]VtQ} y`xe4O7 {$S3zh|@|ޥFqxg&ٛx?~!7\֣G1<'[hv+Ea8R|~E.0@g{Kg ;a5%KBHtg O$;yd9|)NbLW6/y5K'7rvi &Y]w3 UltiþQG0vsk=vI/ ٔT4Uv(Kzt7Qes:;<` P?fRb\H鹤 Q(%YAS&}oS4Mi؃XSOP!,s51!XIr ,oqþ3k F4?%|_XW ,qpْadK̭?]ZYQVǨ];VD.PU躄GD;wYyNɢHIZJFQul$8 I(/NFg/1H\$ٻِ%MXFb%Kơ{lTN_ q퍼i04V4&%ddM]^ `/, J= \%5yCp4Q~\1Cr<+x0! /5LPFW<{_V,ꣵ"g'Pmw j(R`{&?X`C.MTn>ʻrid 5Y*JrJoR"})ʠfMQ?,7 [ŵ\}xx/W*|ko(N:b [IAIRqLmw\'DyԾ}lB6d`'{Etˑ}tMGRIh[]qaؒ?s2Vք6;Ξ^8oI׻0ElI̱;.swSxð>JQE-Դy=P3 ? >VZ5Saº^ ]  DöPT{jEˈ;4$H36:6'"t-m!ZbNgN<(hrҋHZHJLw@@'~'XorIZ[7fo_9rLD,>yJ1sb!uEMU;fb/7t.Rذ\{ Qe밠vJj?VOCIs]|/"I(&9M&Oz<8~xCta\ $*}$,Xg7g7J1,.[$Y$;@\oV yk\*F$f05uǮLH4{F5rC=myi#ZM'1XyK$ӎ'"N蠟ޥQu6 8 ق܌1BAWPNӾR~s"|c m/j:IA25N4ߣ>P+tɞ@ƓW:a D| /]CL%8=V*\hʳȬ>{ϑvkʫ̓_(YBBNGRn*QnX[(u(rB#(K";f <ঐ=G-%j%]6yN9QQ}rV+UJ8ͮAc[<@ĕ#3xɁ9I1,!2>?^;=i $.nW|/QR xܲ|;r 7+%^yt,mg _9lىÉ)=nb01/Aj8t'Ykԝ~@w[d%|SOo9 U0fvUɽQ3eb*u `u`͐"\1ҀBc3/0ªѪy3 ')dK'RULQ}ktd$Ydk,xu=MQ Q)oQYґ`N]zTXumnn*F{C'(f`Pa}:qL9E.2%JNHب.z.B 8DOjB@y@Yp,&)g5LN͈8Q!k'ESHUuI'NTj#4 hHp<AZĎΤKd2 yq"P\L"yV&fZ^%ʡCj?H-F˘;~_,3k5>I=UOg>I [tR|O>!#e4V{DOkB5 #>p7ΐF lwb~dܘ.l@R]ghQ с%V%b]3PKq{?uSuz0SPLzauHC 9E>zBqEW:-~9<gWC -HJHJ.>+ԟav }NV(&#tz!$.YV hqECyP6ch 61k̑'在H,ah[~n^^gAh_J$,]ϥ}Y|8Ok҃#vp6p mzR"_J,(ƆϹqX#FP"m@äcCSA&WbQw=c Y\lbLl49 Iy墧 &)hq1#HN/fV)WCAB>4Ѣ,JaFh9{K]E#ȲL*guN:)JP+э#{Ib 93lUm1>%O,(%!&UR SʟT ̓q~c9kY$ƎR f2KkBgѺ6乆K(׉ X1fdg,bECTF;NΒ+)uyC0)iOwy>ҧg~LQtc>PᙇrbCEYI -y[-0хwL4 s%W˦Ui+U\a cmMFVy"d Gߗ 9d&A=115PaX.㰐H6S?_CNBe:&Aww)ILLqbGx#?p+(X][@SI) (vgZ `/~*D ?^%R|5W0h#{5JfOO3tz<E^NTSV#/Nj ^UC+hcOB(LjR>aFFGę/`&[d-C"kVLSnPٳgi4%`.gxsRR8 TBLQ$~:yNѥ JXbؼ-xrw Jb/+ ; H_MF3:htmCX;29 I/"'V-+fW|j!%%;φkpFO\.qhgQ#U j*+ *Dᇆ)2=`1TAf]fh t"Dž Q*?clLbs<<CtQ{/sUI ^RR^0 >X&gAv v祂K_܍hK.];mF3ozΈ=b .Q "t AKe2@%ΰ̪?Ts0;{r!*'gTfaID|wϚlOhY 5ɪ2&t\zQru3 q%r ΤW* LGhlcNdܨLNNǿ6NW.NWَS:Kw6O\`NFeڂ4GhEHάrdlc睤~,]>y?2X_ qH&"8xp1Q!  4 v[Ϸ+U9UB%J;C h}uG]r0:G'qkSՊ)o_i~ ;"S ,ƥ&3*\;CH3yq%v ̕hJ Ƈ(rƋ(F4@]Fљ\A]|0W0'A70i>1?ݗ͛+.Ũ2/a5v֒s^*93sέJ]Je ^\s-iy^a\$;9!}'+#{Յ$ne"RIJ߽ú w>xz|*?3\7uf2nHÆF=!<uhA<{5 {U:. >@ >? DObGʤmNju"BUM̨C'n%Eu',nUgһ ¹P45+ s`JhZo+S@D}bv ȕ }WpÚRFq}$:*?8#'ͮ` _g7 &H. M|ear쯚A};=C&ށTՀ>b[4K9d}Ce"DIȌ=])HZE ϊuH/+̤|ʼn3eUemc WQP"?s@9aNg*yDGlNUu^Ȅ> >tl2V9QU:#{z c+/w02TY q)*:d=);G BeXyJ@sbF(3Aީ^Ρ|>DFk48;(X ɶ3噎jGȥ\PL"0EK\f#AL'3#qIɉ%lo[a"ײx3g(c6t*YAqƶ MVWXՙo0L>n}kQ(|ե%a9.ʳE B2Z=oI bB;d(..C-h6 ⠥!D%Wwo(۳w/ 97tu]e09*$Řk5}9l|MTZs'Sy3:9:TՉVO)J6n&>'HN48:]9S}r ke-,}#Xe9ec{xƄI2J5|b)>>B,oOIuR{qFv}ļ҈kTRNgݐdzދuT`{=|<*CM=Vy-3qBr<2٭0Te{ ;K6CECb9w]5;@.*+* \Sce I~QKǴi,(8q\5Lj/G$bzFK-ْ<' hJAn\SAx-" Q^0>(2xwޓ2 z|.eP%"|3DщmuҐ<6B-Xd2{vV|IdٌOf97IϢ7AF2)qZ8ƒv5ڭOAZ8&-BIZI %-<IKYENEӧ, 2wSަ( ?R%q B/r@w&,L)Kl,Q :<"*&5 Y~d\cN IQv{gʡFY4)(2%+>Kd*9uXA$2$W]F e1ey6Knͻm hYcY-^>ƿsY!#(b=Iy0LҮD/R/6ZU{5;[lv*at%"*$$[gOeZp!%C":*%v.)lTE]y4D*޲we3iDmQ*WJ+fU" QueCyo(&Kp߼8<*pY%L6 !X^•ٸ8&K&O/ Z5^"$/u XJ?䤾._t`Y:ad["_wuŰdaI=ʶޟxZ!NN=BS8{5L2ua0ZN$ ;7#D&L[z J*0To:v'2`HÒ縸"hذ2uaawL7>2)k#aDY^\isBVnL[KWP냞1`jKzЙ\eɊ* UB΅sӰ`)ƨesb xgAʉuf!8sYãBJ7n7YJ"Ar` bỉ?^^(1l徐h^ӛ~QiYI;H&URoe3 qx=]Z.u?`it>΋B#-6JPDAR@coPخJP<㲞GYA/10tS^6.|&`1FC5O)bxN',}ְNɈ*Å?B%}{nQji0v~\S OTb&(ep6my-zPjjBɾ 2IbE L^șє lMkİEgz;qMuѴBn N Ef=;[))@7Ar.tlFm+L~cL 7/]؉a8@)eȱ u9jek5wvۭfzhNo` b|N`$ UdpQ\& ^-^ :ajujX)T; IBt;r@vFxV6 _A_-EڳY,t̂0b<.Y5J2פ >M$ !J-(ΘSIANju3 e^x}YOU >_׿yցs1V6Vl @:t1/Ht9=@m2a%G !l_' <߅+GBq {ȞRl~S7A(cfJ럹Z&x!MQX:O w4NEe? ìqn&V1er)T8: \ub:W (7lU:jW4$3ȖI)k9W/IB"W5]2l%L *B^_S*t>"XI+N(# "5Z-V %,JyP3[iSAƤOֈ/K%'sg: dU;Paa)*~'}z/E/y$=\[΍(c\*\_G2pU}aZˎER$y@=^,uq̶KT k(IΩϤdpҝ^A'>Y4Ga~yRH&+kkcN )q0;S}¢EPc_Ҵ~\ xU5L/Յ{k*]/ц{I'EW(HNNZTPt4^`US+XFTf+\K?9z15}6KLuglQVT~dp:v+|3,CRʭrUΑ-JxJK T؉Th-$.^E'bmw^=~r }b9x9==|!RW$A+(Oǻv2KF[c6xr u#o}N^:B} $x[XN+t%rV&7]Z*ĩ7j ynڋE*SbP"bTiU`RRa$R8TWN<'ǮEgNՃaKP-.<_K8sg-9HwS4,sŽ!W2#eTo3Ľjջќ-#켆G9-RVlG"bI0C8 Tʩܪלb2ET53 aZ?wvۄ펻+>">4xL/tdFFElo@@7!mzG?.Uiw6f}'XcJ eȎN4[sTU"1Q^WDwxM9تzk+]2EP *_MJts(D?mﶷw[0[0- ,vW 1j3BoҧX@\Ri+q w[  ұpCꮼhf;A(cK|w4U'|w[DTx6†eo vd->Z&7ՌIhZ*# z)k#B#+ =Y2:m ¯V"9UX:WS3aRttkOJ;PۑI]dsk" ^x9ŗ%qA@bu<7\%u+,/HnͬO\uS.mY`v vo1X1J*gol{^B08)5@ pa4*#2C$sh(mV$q&Ԍ=֭Q~d]#$LD$=`,[x甞&HhM_![7>3#6"/x#B*>5'in/MkCHH}Tkȯ+a$ۗ|Op|ͼ)_⬾MqFj"bdgJΛ>(2kujTEm”_nwY|(d;=I.j\T&5_g)M^$:{oftww/L-B L:HG%F]\M8nuJ"{*&nnJc>yN"~=8t㮭Mԝ[t+ȑʕab6vAQy4qPG%m%"z);/>Pl&FsvPV NV*Bo_[+8&4Y`dQZNga=-+^KΩA! \S̏+(lwLSuHT=D}~ѻ54,ןMW7ߚIIЀ]B5\^yWˏW6?Z;c dFo*qm/aacl!DĜAO%_h]jHp H #+i)ыƼ`iIŊ "JOM!x} ?͡mctzH\Je&a0DZtzMW4~zOT0N9BU'Mt6btt{t_ $odY:YP.X-œ˘fue(_h.|4u`&kxY2ڸfZ{Y;Ź7_pv%: 3lTۓlcI:LbJ>X ɟAH$eM#. HJ_4o+渍SA>9# idTD"3C!N#j3K#b{vkne#p4waYcj"͟⤨_U!nQ.?EZCU|E(ޅ,pwA20O9PfF/I,sgXs?tmT/I4yuwK[?]l{Gnbk'"P~;|K4{lA>*eŌ_3?q=N]on&dm8jHg wQnsYѷfIAac*a3}Bb(3?xY9)0` *l{u'S(Ve7ba]嬒gʗ3sfqQ4.c$vXԹ甎e(+VFkJUBUDшBD zȈai9foqI<1VcA3{G d2u 0]^74uޢeCFƅpj&^io@ʦHd%}q^/J97'O@Jߔ1_Ѐ@j\CQh]pvQ&U't4hɘ(:p)QEa&KcE*|K]v;ҩ)N*iϦ?.ljZ~J<5b.^%)_F4f#skاtAvn$ڦ .̞R!03gԼϝ. ϶Vr^q](lL ҒC"3׿V_1CS@+1{_n-$i}) BYݚ*Eמ'J{(_ԴEfv!^D97'ؙ6q阉ƪYFSmV3t! |qh >=Kt ժ3B.RHǣD9ZDI@T\{J YLQ *}X((C%(g3%nJ:n%&h6`q))|AL/ ,'Tt]NCzRX"r (R n)'ŝtsqV)iS!JFT/X2k3op|g-|4wJ$c~2H7lOFkNd~Ie}EEQ`с:yfJ7m8&Y0B-#MvCާAWedHyO("P^ HǕ:_kVnȜ,BYӺ̼'fW j]h6A+MzT8Y& sґzE3݊L^ 'ՎB5)언S,#nP6t#&Y 1Œȩ9Aqg=y-|}NApL8.2Θ_V5]L[*O)3ok{>-)Gs+緊Cz-Y I]茅gӅRw QzK8*WQ_ѩ rVQ3$͇xssÉ08ncjk<=]~+ɭԐUӃr>E wt}y^j@LhqkONO?kr/qBOQÜAA U2Ν8J‰nE-͝KFZz^V3M@ Ă0q#iBLB%ePҴAځryI=0n-O99kQ6iKj:.̩N^qIKSWѣE K_#eL/.d U g ۬昡uY,Cdc)C5 @*cW?P! 0FXw>ޑy05MyHhOT 1xj}LY5bm/6#qTyOwEkȽd6;i҃10| &,u3$PI20cW)U6$, 8yMյBi%]w(ӤƟ!uK+9cd1Á$wE-{έfDɓ e'ХR.?,~ré5bGSq՞^C_*/@Oā9fq C^~HURԭJ ;cěR|Lb.MQ.m9YJRwÃ1Kt1ӁHU,K> R_;tђFrw0%L&l&ix~٦@[n$S7**ydsV*  ó' 6\@M!X\)sف):˗We^Vғ!d;7rqm90Cl4FŕM]qc},L/"Cb:sٝ I46JZUȞ<u[JF. triY8!i)Ϛ}jZr*lr^M`gݤ1Rȇ&'qT,Cdp>":*~F uZ߁hJU>lagCĊQOrܽrn[Z4`Ӽĸr %[,BqT-lKjgL޶ |4% ).ȝ&[ 's#;x$abL̃d K,jP$O7z|{#E<sH&Ad/$hBfb4_p^X4LF\oKToKIom=ЁG Wб}ey!XaQ+0YLLg{/2d* (\d0RRp =OfQ;џmٝl>tSEn(7JygO m3P{)eՖz 2G 5v_v=ZK>W~ +UR>JeH*eu`wkw#G;ޏ 2Ce͕L(h׎3'aJeRF1,th^Ω:̱.dnxt>}CFmO)|?T_QRXdw7GPx̦Vt'?0[ˉv| d<0 ]:ygi{J >V?|ëYօH!0gPg2JG_WpzߵMgdb"mʤ>ܞU2iJS3v.`G߳]uV"`nڮBĈpN(!) &ֶp^U7, [2>hLxT,dz/ݏ)ї$qL3*E(GnIN9TZߢ6b!\;ES?Jظf=0߫JܪD`۟2I1y*d(8rlȏê%7"16kM2Y&*Q&hruWd=}U}qt #͝1HO^d>X'RX?)Z^y\Y'+VB1CvJJlIZi#oGOp>%(@%oLRhʏTIo닕}fH^_=6<./grラgLOǾ[,Zq^.9S(" &i /'kxxSY))tM( ?7-b|FU <) mUR w>:وʞ0w4g|0@BBP`A3/ǯ_޷!Ɏ,YFܯ3(X@X_ķRK]A?݋BVebdF2lKAq]3~UwXk$e/fN--ؗ* 9B""_(n {b57j8Jt0SZZ\z֙ < S^j7DZ8cJK;f@XXywIP2uS\[ mox8J(#\f=&|!mMq3^9$ |9ひ\1 `)qIzq)yA x62DeN;;T&}*^{2y!3{`̻ɠkNW b\?{_׶57sm$]Hic qФFtcK$$YfF I.okY}Μ9Z6lԞ\?ņ i>ČfQA% ggv!NO&'縂O zoDSC"17Ʊ2:ͰRYESUNk>;GE :v~J9F^Un$@){MVꌏr^UaLtBxDR^03Mw}>jɇ |T@dΊŸc"&ZyӒoc{Q-cx41m%몲J_~9$ Ԛy40#mI̞ʀ޽}~Aͷh@oN\5f|wzͷb _ c_{8]q  Q Okkmy=&rPcن@E;Zz0n-eCٖQ4TǛc5y=J.WB8 bDp9zxl !Ht:x1v)Ri[H8ЩbcUm@Dk<`eCXi(<٤`H$5-v903OLG1GE |>/kymhD_d}أXyh\N /LC FL6گOvع7FdPl>aV}BRi<':euS!pҔȹK(Q |☴1ش-N©NSn4֙t֙d6* &h?8UGG)X&3Y5C QK TP>{&``9yYaV .8$^)R"Lnv!$8{`fJ_YئK U}qr[#킟A2cnDbX>HQY]>G wMX]?S/KrnIݤHr$x9Z|] '_ YA7Wk4Oq(79Xp^᳖_TH敎es"d`*ypi˞m3vߺޝ(/%_'jh&Z9%AS.%,}`] Ў`  boaP^Yu j$^O~FůzI- Aar-&Ȼ|5!nR}XCyMEE¡iH+ SB8j%&%2)p5DӝhJ@9eʥBz!k/v$HHRwCEؾ⇂[5m8nh$Ք1Ͽk+?勂ҁ4^5?vN ҫc|9m%_Y K5̮.1֛J:C)2bKRk\3b+XK`!˪ZZ̒DX=SÎ ͰQi *p]\&1~&ˋ3ԓ 43AV*oT'9~pgWz*2,toMG+/?f DNdb'ʦf_f$h2(Cᓐ,JGk)%DoAeCބHH.0^I/BU׽K@PUaP/cߣY _EJ)'-)67σۍlfw}<8{T ZG2 #0FxG˼;A8GJZz֧D,(d̚$ri] YU!yߡR 96pBDLtwF!K&vm';~ͅAJՐNK#Y)rdtd@gcr5 H s-WhO&]CCǀ% T+1  ۍ3'ܨU2>GuL<բc†6amqLjϡk۵}FY0~%}ѰY62R KGg#>w7NFD[#_P8GC&J ;Y#Ĝ u^ui;Ã'݇0@~sh|'~{! M%22XXY\TZwpy,0&?Or%]؍>˰ R%&d~5_nw9 NeQH8i;2kNxeepUREY|N%{D)V2f*{»)U2ei҄͌2k̶@ #$7PƁD$ 0x`!N{WHq^9ҾwB^bC?/ptS2e!,ՓǭFs锤 dG/';E[*H&?E/xo;7Xj,CKWk(ͷ1VUbs@Y,0 o|*NiMBfb \8Wv5˩ f?ЀP<a :AD+rL*ƀ++%͝biWq =CN*Q%0/_ P]*%尰d 0Y˜y4AIUO8@E۠׭W'Ǣ~x]o -zK)У} `hl7^A^W4Ii4;suqToá=٫IӬ ɕ W; _󯰝Rvcݢpv0{ÁGDf/PzaE))n"'"'mMUtӧpX^©âu^]S t@#< 0;:Vt"a7AvԔHKEQBY$'`OVDR#*m,KTH>M(66`5`s{(T&{ ÿ!qcFh$,[`h7$$#=+#z_L %[=8]xU="p~JZ R6!t gB3|qa5Q[HwM0%dA&]'9>HNADe7)-n15-lsqqQlw Sޝ ,)J /EzDh $Kicc o#(.6iiaaHO<-@t3u1V`K&)Xef]94MDŔJeV)ي)2ZJ iy,d0+SP׌QVV Xɉ^q:=AV G ,lL+)VFX|HF vtEBM킒ddvU+58*]-Wh\§JKdEz)8S~rI@C'2IdD=8Aj[9rvgЂat!Sك}y5q MN,61 -9wdvK'ָJ.2c_m5}~m=\9c+޶zq1\`UWzn˟O|ʬ%AQe띢yǸbdV)(rYA@-|H' =bʺk| -`No@c-}Tu1H+^,?$BGcHG %kZXkCX6tMLu( iz4uc_' J!b #`m Ѿ H}3v'jX,Gt>2(2^cs۞m Ah7:蒨z` q+Ŏ1 22kUXtUgſe%12@\vV)"єXlE7َ&L$o Z_v}Wڰ9-كD3.-&9Y|֕}F'U0OXkd9%iُ=`WB>RBB#:[Yj̞~x} ѯf?Qٯ6cQ2h!Mh6?pr<VWQEaLqffbZFv _tVU u^=3|enW5!v>p4@rhڕH$$h%*yaͪiGgDЂ;QMV *1E%J߹}<6FKbLqboq0 |QBR :Bg}(dbh/5ySNYZh .c- 3U? 6:pVhH fꞧ;CA:fRYI]hz1G,F$Cpa[Ç傡͜UR[Hkv'K-F!iOzQ}o2"0L5*2$Ph7ɜeNhtG &n= ;ϻ8Vb9&C4OT䞃W,&1CE#5yNB,2f F76*.BJƤd`z9qܘljQTJ'ٚH:]_kJșS3M6%-,*fޒ͛gϊny4+r>/z),}F2)P:\IWb1-=*m!;Ӑ'К* #yJEV'y7>DΤN~^rB 0 <ʬykre~3ϩũ6-7ҷ Cx)3F/ylI`@EJ A%!y\*Tp >7qlwV۽u|%P'e=IVWWzomӦ.ֲiZX|A_U:^a`A2ZD v% XsEY1tmC7N13V:3FY Td|LBUUy Jp xrqW&GaAy/)+;yp2CPV K#_8 R_6Q(~>)2dgX%^$2.0qfhv Făd8z3:D%VEYUBAe,p2ӝ =exQGۺ)Y9xGJZpSZ9.md8wM~?²&<2]";b&'2c/d˛|1fRqo"RńVOc,ò^U~(%Z]9ã,E(*8%5ᇡOڒ<  F%鄖wg*~LٹA40fD60D_bQs̆2D7{u9D/j9S *p^2,P h2wXK4Q"/RXCmԡ.&9$.a2P!*$Hm,qe=,Y c~nJ@:s5PpPT7+K020f/9Ղ[d!NO_6ms2kטLR\&ՈGtY=`+&( ji^U~\~w~r\NK~pg:ú88{*Ξ&Z#a$Q&3D[E\y'&j+SV1BR&Lo:* `FN\gd')p-hEiUw湎W!_k*0dU$!#Vxvfg_mP3EV>Rv2n[K d]lh8\L}fv`}:uoFchɠP&henpZbyKx/7hH'޹>I2"ϼpu WK/2i% t3;fc Kx>{+ńbD!6F{5ұ|KSY<$4ƶ2 _aHtleX&cL?y""t+qkitg0Mg\rR9r͠x1 )HWfuQ9N)2֤>Dp[俞_Xk/cTεwZo񘒷~ƚQwEuHڼ10L `VՂ eٽiE Qƾ*Muֳr|q.m )q K LYUsi_Puرu;ٿyFLH'9%`vvG挖Lq`$*hܢrV%9OuC%gٲB*50d{{o|st>N,|7(WlX! uY4h\=^_-n!{wQs=CfվjaRhxs$7Vtq௺vOaY{ +A$7J8 q$U/EwUAe$7O1iy0QH 8oVd$˼Zr1-\0 .s^~\/]@\&ZhP"1^T RFNG\}oy>rh y_aZ D9(:R K1=UXHbSgпY~Sn4F=i{|ׂE'ȉM'/gYyd9g>^޽leˈ'de9%o xު;#^v9C "zĨ;ki}Ҳ5-ZJ 6=hC`!VH䁟k7KjO?Bd [˼{mYޙ {Mg+GX7 U$ڌS8Ig(~G6k`<3C*fF== $6#ϳ#٘Q|1}qUߢ9~N}MVH 0wdtc&pYc6N\^;M0ço~ 4ijkѫ0 :X];+Z7:aCCm'm_x|7jjK(\;RI~)B}{h20ec2Eg=mT#$ج WJS}?=6]/x6.?blgNNZc}<JAxZXhlƀy0JyTޓh^AI2;t+RIv_W~E?IK"|KQ]W}/H BGOwǮ}^ݳ̯>a$l "E$ q~P0 $DlFq'm8ZN#I{rw'K?v8~/r8)@p lACj Jnc Nl?A,)ؚ|% V~ 8hn kYG1܌ z"/8vvV׳:yOk3Qs"#;Z5cһy'dt{Vm_O>{ g/Y1e^D8MP3gӭ۬#Q}JXWNPs4pÿozIȂScHb# 1SMEc֎1NEuO3 ě`jc֩)^BEQ\YW(< ř;,f 30|$s3 Q C:b֝^uQ2DQ8`0k:sVx<jlLgxLmw)eg~w GqtZ40!a wqP6vRio{9>+yd>O}Qcػ{kދRc{v,jmE#^%o)d';[J.,Xm[HM6Pmx*CG)6WjH!V;+[We(Q%}anɋ^}9]y--;&J2/l޼,.W)%{z?@ b >Ygob1n6B+bƹY_f#2HEǞX ^7휟U:Fճu]?3XoaYoRE1">HsS'ΘP)D/:I.iI%0\>;P\'%GK,]:?XsWQΧWG!Pވ'L:G`^feґsWg ((9)W^ᬎ cQ$9Y='pYihF(dݢVu8 iQ2.#: G~bLR$̏Gq'sMy>s~?׮ dMЦ_V2w& ora/{ 5gaL[10s^# 2+VT؇;;1} ,GH7" [Fnwt@&|RCLm< -,ܒuќpiQ\$Ma֎R' p{mJس::/bqsjDŎ%3#F-sDeQw]]dyRH" ]&E3p_ޏ,!.D3|f0Ak"de {׽}̰3o:ЎYe l_\S|itՙc )2JLF9ca(ϗ;h,mGIi f gd/R'M4یL|O%Cd CգᦞO8}V K @?|Q(זm31Jd7qeewњa?&:Qw )]_ǨHl*Heh!K>ʯă7V0(v괕 9n{;WuǯeR`zߖ+ oф΂qtl ?%ֆsaKseQ[B xW]ommu/>g_N@<1- ߾ucVmw)~/qWzRh l=Q}4B{2Yє1jk8^;my}o0qV8k?E0(*7@2%ʉm=NGx:3:>)x!av(7ѭh AŃvDoqvnҾn8He¶Ɓm,LM` I.Yʲ޶Vo(.Jیc:M UmaVFdOP7⥍C/#'P@HDժKe,ہڲ,F(R0͒uj4D',"ph=ݠ$Uhuo);KO>D"+ -eę xlHH3 eל̦k* zȱ,#8T̥g hI 8d _lYvm5qr!-!m-ʴ}aBzYl䱳\8@ s ì[Z-٤.eM_Жܦ eFQ`Κ^$҄VKv&k⵮ -`!L ]lYv{;.DiSTՙQ_AZ_gP*юF 4dp8:>9]I+;KVR@2ÂBz+gtmFIRZ,ـs}_ͦw|RWԞ $Sl@3볶Gokͩ90:Wz"Q٩=cY+ҴW3%?gd ֠ YNrW V9*fmt-V^/WRSTfUfU\= 4(-or~zBs6*nmtI1ˑII$3lZ,,9XntREwvJ1UԦCkf^‰hS,Q,'/RQ<}&4__ڌŐ2g]o5W 9kN>hb~L촛#>B{rձNDz^mev=MEqŒ 彠h%%\AvQ!)ƔcU'0nRXuRꔬ.OVZO(%WiNQ))3`٥O,(llƺ%uߋ~!Z1uVn # iу@~K11l>a|V?XCcp`x8uP,CkP@!W/p1}njF-VK| t*HXtt{㹶^u-GIsd.s0K̦b4XʏzPQ֓17P eT`ÁR2`L ~X}q9=DdcR/zVN3, HQFXKu[%v@1!<ˮ()b,Q(UCiyC[ʉhgU|_ڡ%6늸 0:vk8N3n3U4 I1e%Gn!-|F,XO^ؑL|'U!\CI8ՖҲzx+Q{I>hL"^$ &H:QF^YdpV] t0n -6 }Nl ,G,I mgKV?kh 7So'1-~}@6Xfd(y^{*{2UwaMwyw~# wⓟcTOQr1.kOa(Zb9!(c;:RގGf| ߵF#ttv_4ɭ_z$[ݭ29̈1B6GhE&`ZѨH_ yȆx^.2bjlK:RrE,;B. ֋ɡp\afQ}kۣwn9׀]94I;xPZ|yX)+l,L CG]K:u(Q~0DL6+ 2i'0_Z2> jZNX[TǿOsR +ݯi#N2fOs~wvv_`fXSl0Xϳ٫;7:e5|܄mq f:Y>YEK0# 0T!y>\z#l}It->7Q~+,[%*W?\Cސo0)?F]X䶹31ºvsR/1֛ nd{ZO`ܔ,"׮sxiIzhH~NpO(ܪ#=|b'A\^]p{ 뭡I+gca+B/g_OF9ݏZQ`O ɱGPSöc1Z8z^ٗp-&.' Kʧ ﱕdzL>kE|Jwͮ{Nagלy)p3G~03p{Z!q&:ݨ}*T,k2о Dk<z*))if#YI2se:TtlK׋&-r>_9N' re?gy$Q!d4VRGPs.\<4Oqo.yѼR^?fF/9iyp5/نV4sygGBCӬşwᳰ^WL|nj35>Mci^yY"CQdݟ#ݬw>9˘ٻbq[q W 6aR\^Dڸs[(YlԾгq+>nI`.PnMf*Ȃb4ra԰o3^՘Rts 10?z?W5J5=im'&ݏ/uzomlalvq &Uĥݳd*GZqlZehu\p Q~ĭ>Ώ=2ap9oǞm'y> d$)\g03%&#;^xG"n@]\0 GGPF7^,^sȄ@#~L9u_$=+2%B^z@Z}9$X{+P"٦>|'A xr$Qک_{ ?m RM'd"X,0vLW4I5ɵs#=9hV;q|ooW8}/d:Lo)șQ}jH3O1+/OU7bSXsTƓ'w&IZ$a(ee{Un=Hhn3)I8{u.*lo(jErŸ"9C3@/Gk]_^Tu`c@g5h [pv/RxA#䌡* jp +>i+b# =FMFqӞG\0jdIVaЇ;Y^-퓽fgis|TKIu&~آ(Kڳ a:Wejy@pCHv*GC<UGҹ5d#8f} LEƥ1h.EqWU:'!maFQK̃9_ݫ%p_Ыao2M 0-``3flAl+-3pR"cٔ#G;ۯ3:̋Fd#tQpI+Zէb4OIj-B|Ңc& |)$`%vb:hlQB,s L>Й-N oqd! :-yO&v&۰vs{v$zJ5b2woBXkk@È竈CqW&yC :@MPd)%*V3 mE \6Z*N5]P} oh^6mabD!a#zh|9pzbgo%6B4O2,FX Ŏ V@L 7HrXv+uX~vQ[Кhd~x5/[{_q;f#vۢ.??n5Nmqt>:4)5_+ cuyHDzd7$ s[gCCc_; mE6j'"'mT%16ZEu~}[?9>ܯTnI;M)P6xojbƞ-Y… .QRtY>2:~?M$|z60C,dSSGvQ[wEBN8i1qPt:ѵ8-krHYz)ch7nğBc eX:9פ _nvm9lăSYQڢXX__?]"N:uLFm9sZ:($Ʌ^`9eB2s˕IU)O#VփTr%\ F +dDoʠEY4.&D :Hx ª0|g v#'6!;Π=(·ِ p`Y:y¬I16%<}{ZXt8~ԗɾ1'g.u^@zD,U98P`|4:@C,*^ yސ-!!j3kjVV͌ ? j񃐷 ((Ѳyk4|`|4_lmUWϔ~ͪ5$!&O7is+Z?Z 6֬ЦVK7hZ$5D\%3'AWZ>ryq@W uWۣ|(ugTDC &U/GYp,tZeX3m sX7шH4P" [wV>~|=ꢈ-RJhs>0 ;r!KIih7iQTܼRpȲH4m5QG&PKk>xEA@%l0f\}#%){!{b/D"E6`́:}خn~?udɷq9R5HF*E">")7۩0OKkHQZ)2rN}Ӕc3Tm;nt=OJZ0, o#*/ R&>+zDOppcp1-|(j Sc'z\tJZ1)3[80zs`WurC7 g&] nA'Ld-'DME-rB͑\"_0H ^(sF e2H.W_rϲ̢/yH@[+-+OHKѽ&/#;С_@C6 5h|+A+ G$ f aa4X@tiIhkh5`|1 lf+#h2|-%QGx%<맚庣E 6u˾MH9G$D\r~z`]%en}51VC3\C2uߒۀcvw ?Y9=jD%l6kBnEvpޕ$)GU;#5Bn 7WbM %KG-6ff8[.G&ITA1c2 _W/-Z֫Z~wr\Z=[_*BY4#pf<ٺsF 2XpHQd>V i$oc2 ?߮%l.UHBCN8 S{5$8,[MB6r@Xj$ W@yTT*4M +)e7SC/l22Ayè07p8Q:\нsMܪ>=mA1ņx*kå˱H\rʵbCd4Jɫ +]ĺ ’S)ˈ6)6nXQ1.*)FV=у{,JИBNg~RëG Kt!aESB[8C8, lPF\f<Vh3! $FM":4]4xK1Ľ P7VOct]{Y戏;Y˓B>CEW&}QH/Hط!ded:]r](==/y!\E-&(#Z;,-gb|woKl9z⊭p8t t#,)>QH'ƪ FC$*E1v#7\eة&ġMn*Rz%dR HX! $ @%cIIWʉȁ.ob (A=ZC5-m HP^2 gH!Smqc:T) AszB]d_k'' MA7u:Hq0xz3J7_i౔L[wLж#uc]# ǽfy!7)Glc,#Jo=\!\rЈq+Y2$t 91] _)o䠎7en^Y8@h% + !yĪj-.( CK yeY6Bs"49N$HE"ϴ"IAInQH({v`}xTzTR 0Π5YkIb ~-H!ۻ2R4(#CEՌpHwj IkgWTMQ; c{~JHc}28eH(x ٫w^mʤJ5͘}#\+czѠ e YDJV_:_:%΢}n(uDyF=! H{Er J6Ji;ȠDzˆݦ{G.67$ں𪈱fmݮ/ S{tPKe#ґ$bM7Z!1JrmY62S4G x[!/@v*++e:Oi1{3COQmLm#G9X8!FTzd8rT ;ʹk+Ѣ|eQS3pA/Td-._kGMߢh(ŋ_Bc" ZA hh @m'MjqJX#A_x\$a4Oj(2/.hU2@R[AA0x{8BLL:N4sObdBvT׷0ӑFzIբ(-r.˫9㱕N흃Q2^(5BE-2]2 Z-壅k}>MK]`9J殖V} -e/Ų%ߝ顮5W ~8w 9s|vf8NùZ% fN6J//|m9'RpQJIzI[26YwD+"(fNr 㼏XQY$yJj[2y'y:UVBJ2 ň4oҙ0(|rP`DRd'K Fq ;pwp ˹T@ڐtj"%jJjp#QxKoct3γ&9 `JTt,\t3HКven Z(c^Z=Y4K?@p2%.k Y\dHb+/쐲]_@̹v۬)[UvqzH9;̸FlR8t E$+tK#~UxXDJX8pb9AYuh)p8@ʲq{FCbIGebYPY{Wp)E @0O6b:ͲɈ&bDY$B\"'$ tB3e> 4Fzy<%x܀=Pey$DA -"*̜>TƂ8@2[ g #rCsΟPRDtic[ ]$@9O"A%rҥn?JʫLFU,, ǰ<ę1dW$A VnQqM53%GPqxz&jK^G"ie y EIVH,+A2*Z4sӯf+t9lusXq<*cbnUqu\E*!9^uVyEV(-9(B"]^P%Qzѓ['qruIɽRʶx8ciVgCtʯSvMtBT=*t B5s)@郊P1ȴNuyvI>S[T+W;7of7>͜CcwZ*$VZ莾|+nMDƣ4Cz#e*@Ct  4nzeHQø4 qa7*ڎeyKl2NeX̚ա(`d}uxX" teSKh`1Ԉ/Ic*R5=49xfrFuNapD˸}4EJ˜6 @<#KG{aIwۇeBEwHZT!0)O굑|nV0 }(f6 T^<) C72@HJfA|:_lHRs^Td0V$WZ[ DS["^-c,(8NYX'qcԎ^)-`ȫͱ}" yKKkِGjKԕL6Eb!"F8wmGwIWn J@؅,\PH)z$汏;r\A$ݙݝ7+qq3>>?JZ-fĠ,5J'yv (*, d[/X 6_@Y4=͑nfr:7[U',OI^6q'b`:GdNca<*w1]?c]t}C%p%@uˍz/3^нFo$oee`d ij Z]sҍVKG껣~or8z;wGy͎"njRzyr-m0ׯ;%l'C%:XgZCed;WyBGҦ*[Rͽz=`|]A߉w֮S`2 FL cxhZ/h}G2v 1MCh:Xvk`GD~Z"*ߊ?GPޢE"٥uN>UOEEK;݁U awy&=x񂘈- HX8 ėD9+:A:/9n6tWҕ ~xAs#m0~%[uyqIDg#+z!+9ALI7jaڼΧ $\⚮B6Vݕ~wUǧ?2W!z9p`VzT-OWϟٟVGEIn]w:}T|R:gPd'V^sLG=N4vO&r֟_pD< ЃWπ]d@Go|`\K}H'\!+?hGԣjrzvc/h8WbQZ_HyCULVBvd .ƙ |uZ*Mvv7 m#0"IPwC5Dnx%MBSXP eJ2@zSUe'C;R9ٶyo!ScLV.{ FWGU-7m! !TP5$_ /^*I,;3\C2m{蟱Lh-*# szp-zǬ 1`ԓG 8{~,&b?~K_憳m =5"BB%Wao? ƽ;p|Jtt(=wAPJoоBa=(ƈ5 *~BNSPyz|.ԴB*r|C*de34{HnH\)h$4XE#9 9MhxQ9GL{K^dԑq•,e`Dt [8lu?7[kUx#h!! ~` UYsX~ PfoYE;Y鄐\Dӎ]RutHB.b"DЉ;Nd`g1\݂=+r,qPoa9C+z:*)PXI0>.*3 s4?( B| 9E섞'(vWE;.ޠgRrK#Y< u2ƍcdd?PZUHoa1[F爒StۀL5w$=Au|t"ilbbRc i>4Mls1!D%?[˩ ]AOxW pTsΆd7/^6 Ai^ݻٕݽwBVPы=EtGPj[*Kqj:JѶS cs??g?VRb+f d=3mtbv`7I`3&W? 7Lljhkkhq-uMK+R˷6y#QnDV`ȴ($] !0;SJΥsN.E+|3Hg<Ͻna̎IbUr${LTŰ1 sRxE8wr9Y"0;^Fds,ĥzrl_=YBeW13r7;}*I%#dmCsU2͐(FaI{LU%awCd-WOwn膨LTnʞp]$y%P >Oy\sZm!M9ICW {אqEuuuMkgmCcM.iyV:-~SB>"L%- ~*{xĭ^OG`z{8jU7,eN%;*@@WD7G v{.!L\AN했 f ހ$ҩ}.顲> fhU1)UXt Z](#v&cvS!_^8Z u٭qwcdo udRf_ H=V5HZHb̈́2YYR\)y?QT;!|E #-PZí%ʧ;RDo̢eHDٳxRX]hDOct 8 t)e)@ϥ \6r'Or>AKAy'u JebHs2.N$ ptDC;e"É.,`HFROHʥ~nfujʹ򄀯? ItFe y}p>mOp"7s>N EA |>)i8=~E-y Ff{6P CI9h`TFȏ2R}˶v6de+,~ܹ{RyoHRmÊyt Р ySKf>C uxD݂e9EA"dh`LCCHNswz=h1R! $l ~Zফ(/9 /ٔ#yʅo*G}҂YtF\e04LMʥʽ`Wݷ3p1wsGZكu>³=MS>za29V;GB -E)_,VBdpE;Aqef#{'*LS>xf cpU$|@[ۃpe-H : ˪9&#x P7p^Y+IHޑb]Ɉj!jf|2Uh2;bYf*v63RIMOB0촪VS~轜/n4J"gY6M8y2!S㣠ЂuX4ݠ>1I٥74Ez [bYX<ϵۭ]f+AykKJFDvcu}<.`lO7ETrē`"6kTq&kP:NA%ߗƒEy[:9lVtͽP٨Xu\DkپAI:nP>h,/$*Tc[M5milT>G kرP~$4ބ'{A~1UO6ud,Z$ȯU2 ?<}U3mjl0pb_1mpDu u Ɏw`3ku ^GXNbO-3x8=OpI\=C*fHЕ_ Xzi^@^:MX?joQZ#glR/[ ߴ`H:{>{qk],(sPEw0aW[sΨɬm4Yt_ͺ Yx{ƙ(7)&SYHNw+WIqtֱ "! 5DiI<׹nz}yn\6M1HI:7=lVǙ9&,-߲)Y:,bOLNTm>ʪƦy}stNΰIڜ\Gl\NM͟_&~/y?/nH{3ʳYzapa%>y mWY~g&ʙ(54`h V,3lvQ=2a'UfRT=' Vh9.f }B5 ڸq3SN6n)ҹُMpl 5|^Na6 ̏ $3*;]JB+?/ᓿ??|\M6iC0Y:_С}59~|0~'_0=}nͳ/~||]-@ 4;)X AoX uӄL5ӹ 99\K,KG"qf}^dn,4 :F)]ȮbYVy qV9H_;{gi9{c.9IGo`/0)$/rǼ^2oڇ `Ǽ2o幀6^8%- ,U&T`ͲܼM T&<|&oY9<=Ňf_V3wIfC#ӲqLxaNpjN-.- C+Z+r~tҲ=~i>~-->ȼs*ɼ, sϦIP71[9a 0h_g`czxW .igϟ>z~ÁÃg>q=?n<዗?<;H̝{{D3w CBRx0^fRs do#l's`^z8*=liͫ0nWœ.|*lBFVD?ߖ97\@}s)(S8@U~;4!5om_퍳{EQƎ^ki-s\3iP.x">rDvT©F߮  F&-!ph/qTu"%qo6m9ۥ7pçmtw6%u .]!BLnz]k 0d|\>Ez?GG fOo[;M6f~Tj#bL@ʓ,%9!תHqyVA39` 'A@5q $*a9Wpl^fU{ڀ/C*>lU{;?; Ͻ-ĺ9VpaTs~of{o5,9܆͕*u`\<{ Tܻ{w L w*<0;!LƲ{~@.*>>yLyN:VGtl L9B -fY:2}F԰@Hlae d,yl"& v'Ry;CSY=82w$yqt YٕpTH쉓[ D9Ff0x_>ibC?2#`HxvaKZ@[ٹN5!EqV,G/~c0|$䍂"[%s K5(TrA[+U>mƸ @HEnL̽~wߵ]:2lV<+4)HՂY Y>(7&ĝ`_z`K!vBCªHq,ouQK`crwߕ'ˮ~k,S{0hE˗wE8ɪ n/ Da/6o^/fNggz3fLezJl1[PlD'=EIYYb I9?1>~\  j~R~$hηh$'14Y%B$]ې "57smx8˃d1y3)/' 9xM=6{;BW7(N줳}tDj k0e%.P+66$* Z;(E#3z2@?<Hֽ' TG>R(|4_wh,s`)|ڲvrẠz+; 6:Hz.w{콻zdzPv}xp`Ã+߇ҙǒy"bN^†nb~sZPN>0:BG@2&.+W*3V}j^ Oj`= @ mdx6QgybbЭa(l8OC㳁l\4@&7} B'eZMt@B<%4zlbZ0sKs9S%.fB^L_ etN$E H4Jxhd`Ƕ6j #́7keƕΓP H % #`KFAnt>~<;;_ l ̠_lc} Io(:7kS PcBɃ*RM{''8  2ƁJZJA!dqNg;:k\YFЗ\<K/Z赼j1n l}]F3ٚa[T5Csؑ~d(@B0spNl#s(B(^‚:Bd">eSi1<|t<>ӧG[71D񯌥1Cy& >!+FRcՂ|6v;s#Ǔ֓oHTܒTCYfX?!8y|w,ͭy;r8lj7cb2Yjh:ɴR]iT5])9M. g_%'B.k&etX)ȉvfTm ̹G,(- X%iՉɤ d@Sy+īnǷʒԴ5וI&xZ/e|6D:Ň.k)7_(BCA^ЕLIwi}Yo[ "ήwÇ px=r"v hʷĕv_"Lwb]fREaZih?3Hgo- oHc]pWB|˭~^ܚ^m\&Cõ Mʅq 5?x+8 >K.h 07SyVr&N_&ϫE*O+:a J+w,Bu';CJf>C3r@^*xvvC6;*2Yz*yYa' %k'c޲rh-t?)>Ϋ%EW~Y9 R!`2;euMxSbmQ~0ş5rtJ3׌oMm|"_5jk9@Ci2wW ? ShHd@(2~qSq<754w㷉kA-섇՗fN.x J'Ȳ*)) nϪ2 [UgG/;'賀jYģ3A#Ƽ" 0KA@8ßF;:j=~{{k^wzZJ4dOQ9VA0BpWdʀE?E'J©pD+*`1O% Goyŵ6W">0/3 9^Zm7ޭ:#vi쵡f5x5 C@$Јv=f;f[:b{XUkZ5iSG/d%;>'y\dU1/ROtQ]NIٶry3@lt@q5w[c}HGLnpn{)3IZ|IoZ>BuuY8an{TԸ>ּ0oޤGHzbw Fs瑅jqR<rnqp9z}5l\Aosq@{Y-NOL`^镌bJWϒWZ*V0syϣ^U˖<3t[OĽ?W}彯.½}񅾇}=ro\WJ޷~NWWՕ{~z˙}n-}k7+ I!ԊؿX)EmVEuMP]*/-SAnv܂ԬADă{&u 7`JdhP |򎓷urU =շ1wmiekkxX-ũbp1C zIxXoS u~\6N OrD6h9h^ZᏵ/CdEN礠[pMnf4$VxFOlq\ZIEKwvu)6AdY`}s.O'쒭fzcdEbMu#)Q&𕇮rXZk-gcz}[V-Z'JÚ#Cv:1>د!%#T,JtF@~86S ]6Rx*/\7ԝ 2ڢY'9/Ț_,0b4ɀ,A@Fq2"+gWAcolӍOqUf@,nۺ\g/BkC=7Q(j4i& (5ԀuZ5{D8تg6ݥY ROq jiZ PwM ~wo+= J{W: ꚨ1˴Oq*_@ K.1~V01L-+\s(T7Jt7 !{Ee"lmEF`aIGH'&&cGuh ϧЪV*Dkn+?m+/SP`:h~_88}yqR7kSb,#!?k1Z꽴i=&or~7 ,I2vz6 > ofT*1+(hme4 Hm(q F%{A &qiIy>:8%b4jl?^} ԶA7YX--*c Q6l9b<1o>@45_Lg/hX@`.* oOreo-!uIbD3L,]}e!4DZ@9eF+W^ˀ&]eFQOO6ms!N1iU˼"Weiu M[%աj ōM,S͚Jsb@MUwZ:qF۞ge /*ԕ^XV*4:|YeuM ^O/b0Cȯdd@o^@@*+N([Ȼ,;ˮm@'=wtQdǤǑqBjTY?ZGR\`lC2dxgie:=Z(zypqf oQjV驝[ 9p?I6(o]*^9b/ҎEp<Q}ݏgBȂze=7a9<g$.w?p>S%&9{n|_QÈ:7}j^KÞJC::]A*hLZt+ڻ&өV{S\fcIx1lbv’TPMJAC}рcRjd4ݿ1n(U[`N(k]@_>_gPVA|v΄@L?ZhL2"o\_?}5Z%}y^#fgHQ.!W$"#sc*Bc4~1K-s5rWc<5>SIsQl15Pl_̞ћþup[UΒG筱˜bZ^_|)>V5xW쟹3GBpGR8!Y\teFF.kKΈǯф|hM Km(ۛVcԆz}4Wh_(Q"JaȤ[5q'EyqgJ0|Vbwr$N)AT u YfNj&u[S߻oPG-}.\ӾSMKK5'u:JgLArFS&=S vj0os/v- Ў侇s2^:Iw7-q8U=*_ۦӉ di /M'nծNة4CT_ 3Q"aĎ3Z,J`N}q1`Ͳ k *"jY`N|8lZL<9$QBOkunVs:J*0 8T~cDC7"elӪJ/U<¢>cۯ!R\Bn9"SZFb+|Ir:&d]øܔ)N oR"MFcC2o^XrʼYX['I#'}0>5-EʐG*c iH JU3裎i ̍F5߱ч;C0͆W_t t/ @d& H>Q%r`9ab/!qT݊ ,0r~DŽhgt>ٮIixutvE4RDfsB$<I3IŻ$lJ[Z )*Rt 腪Wb\u0tc|áj VGr:f[kR~>;7Ch6:5 u2"47ue* /ٮ[r"7jxNݥ96H/vͦqJ%.ܼϕ[ cT8wLJ.w'm}pDDh) N`UOtۤj(TK7=Cb 2ǵF>jiE?X=g RM"E/3éycPt7{[8F]_u}=t<`;12=L ?_! 'Owl3U+VsE`7N-X3bN128vil4ڳPI6N,B=yӽdj̞Y{B,y装]J8[ !%WE .`ֺDͣ+3wb"pvǴI0cq1ݖNn`r`>vx{8'դAF:ڡi3(F|s1C'YY!I52ӂ̩%<岾PC;)Wo4.ݶt_(pmRG^ G;o9g>1xI<GbG{qiUu cJt{y.`$I.|"M3Ogp_D!%J6O3>ux[/%'rV)[J֑I9c{5__{?Pǿzh}($CvIJĨP~Nj('ԲXc.Қ\dkzvaJ}2}$okzH2*at8On,mK'j,\Qs"LI+Gqlؔ@lh!opl>egec3UUl_:d$r{ Lax,ydd݌Ċ9Fxƣ"JQE\u}ܫF˰i6VM2z`yجN;*3kO-}RNSn£oZU _~TkMц}#3)yYIfo1%;"u 8&a2ǥ4k %IՔ @8pDzKI1%an_-2RO5X~Ux7-Q~o(V?M[+s a$<2Poel*Z4l;<7,VϵRkX!2GjBQC TۨEJgt|3vx[fFG0匳,rڗ\ 1.o'FJ #R<װtB3>li )٫21iMطrVNGcpIpFWD[_[*d|svEz))~4-v {F=]DA xF=R2hP=;[%&k6.y([ 5X-J-%Ұ16:9Tyîӹ`Ȱ3b7$g`۩Zu'mrNWd}_h'X OlU Aэ1'JoXQ3&]ؓ1 *sO,§4\i6~ֳyH+7FO=75l[͸+JN.e'<:)Ԍ;*1,1Z3c z]OzglM'UCum#|+8g;vioooa﵏#ȽgvnX6o%+~v^B;De*,-4-l"sV,V,.zo3Z;i-#տviG C1ݻt4|4ΠI݇pDAֶ\H+;i:讼,(7Ӥ8?IMD˗f[iwC+FdI):x*#So1ЕMIX[ g#q?-ñDzJ,!I" bC aeݴqMtPh7*{At߅U? 3NgU38huoIܯ%i47ҒP_F1y/%hsx<0D90zXR!׃6zW_^JIp 0)5=*Kd*XnA/RGV12|*=\8 +z_kǂ*F3+l^0иi}ݻx[w ׀pR؎OE`8 5|Z؆v m,dr%V"^liaC);/#[V?Hn&&6ZNh8) %Qzbx)('LDoiCUiik8xe5$jAa W) 4$bE X//>Fљ z[@dn"aoB2Y0RfĀok> }mV#s+8` A a$hj-H JjWnzqVȚ) NK=a>ʭPpUtz0))'Ebl:ɜ>'< BczVQA k5;):2xG m 9 DKWJQZ!e4]ɓ/Y#vŸ 'WL7#\p(33XE#ƯX$J-URKàw?Xj/뱋WH~XE.)`0rRD.ɈyjϺ\ pto>{|͋ωg y*&YK]p0uP~E1hhTb[rkvc#.-+ @%yC7kj OInVI'!3b{qg6m25D(w}\2 Ozrcm }M acƶۤsNERw3Ĥ:m"v-Re#ql5)9Z6GEsW ,8j0n⛿EV‡9F) t1b@,&}h8+R4D6z#؎2" &} B n[  xhe @,PKJ:TރJa]\fkfFny;fK+[%Xm:T%nOmynֶOT\v߈v7axnyy!~ls7M&33M!Xz14Lv?H̀ֈ# [>b#k@I^ knh8BE6?/ű S4Vsg0Ҧ]@gd(Ic!tE> nHs\@6ZR!*Co79;"14\CoX@9vw%61f_qtYLیYhy6Eɽ04v$+,2G^\X/pe,o?IWc/,eR.=L 3y;m-V]uPb&J%:mk(иED+O|6Uc;3IH[#7= X߫C!]FV?fޤ72\ɚUݲuӵK\X72q*RFQ,fִ@~E+,WoC;[%[K'*j3@1ߛʬ뉫x@ZN18HiuA;X L]O8}#AEq1/ İV3 EQ%`9 #srYS` -C\nr!WBZ].M^1o)myX֫K[^WLsbZI=>}jA3%k",JG-I|,Z!n"rESVU1ɚ7e[ r6S]Z$WcwK8 QY֛hAV !.t3±%+Z7ڕ/o|$eϗDž\fn ];T`iL۝%<.nWcH'Mޏe %qþGwsw >^obվ1& օb>.*iRUOIyqb}bY9yo#j_췲WX^΍_jWT>2*9rX;EfqD4eD, A]#t:8;B4 檸qn6EZ07G,naNuZ6껖ϞEιߩ]e5)&@ hΦ^ȿDE؛D2 7=`|h|DuSTpsuR%<̒kR+穷Dih> "S0]WpMx*Y 0xG[AcuNۡkdJScAKs1JCBu|(ܣg7TК>ȍlFU&ig 2n^W]y6fxN7kT]4/`H+ :g6 UzF|O},{[7VvM8S) 09iɩÂֆΒonƣ > 2jMlVaYdًtN?\Z|orFr#߬.+^E58)>^P7`Yig1+3"1$YKN`F.w> Pr,cPFv n3؊B^ALwYm\CAIC .tyo[xwS>X"r{M"CqHJގ L5L﷞U9i5+$5m:⧈4Dn6#lR"MДjvB)gC =|}f?匽.::T#WU ~*'COKfRslPFa6KD,`lAF>(mCJ-ire˖,w8D\!kF\ LC/m -_l ; )#OLkZ:Q@EM7irJe?A77i!HkҊVH3L3M)十3jrTȼ_1p aဟ ,h]n'tfŌz2v@i~uTc 1"[N:kÉ>YYbDD].Q3s,G~14 [j_Vv\}O]|ƚQyJ_ HGAAnR^րU4<Nت_F֍HBQ8F!46)G- mq-AV ߋO#w`J Fǁgz@8_!⯭BB_$y\2~[h AKVx)^jY@q]L|2t23渚ʦH9 xXKNd٩Z }tV O YPۢmel#ZFo[`+:8ӯpzjT~ٿ;f$ ϦRⱵImfIW>5Y'-] 2rXcecf{'d{Wƙk~g&9YL³9YZ]hv&dw\AZO+DŽ4C$+1Ku}LnpO5q ͛ w ",!q1Tx(u`U]%hO4lFӪyG}b-rSO;~y^okWl=0r&L^8XdD5{DCJc.#' u"LP_ (P9d(\5UZ4 z3_NH-H>Mq*v@ AlwSis="Ճ#p[m@\oh7e]Q8M5zj^+z 7րσ1WX>JPЊrK@UQLq|id%<憼Dzd FհS,k4HœpO\#ίKW,=hZՕ+K ڮi"H9@*m`J 6,:13n,%i@Ӻn:ۻZHºme?ejlU K#5V:D: V%dTn(5(TX_7;?VyFYM= YRR| Q-OM mzqr U0@ :g&Pm2"J3᪐ ꦚ^*ӗL|v؟vm V YrZw%*ζ*5ma ?eՇ?f3Pp ;.\ˤt`z<L-,ƊU;vwopoo]FZ׀ZX7@"7(nD$ N@][΂HK-[pca2Ee%̄1="l ~jTĹޮ0CDd+ws;P&.uM՝l-$c$]Cs&PY8YiVZ  syS^YY65Gͥ7idX 1SXSHªTg~6~mRsFhbfuɘwh+f0 1 t( eZmӦͳl ]内\:)l '^[ݒ&i5\Nt41f{~ 7D7З1~Ezv#\U6% [jJfܣl6ֱX($Gӓd 5XGIrOzqbsGWUvRʐ]:=s9sq/(9n-O 8fەPɀ)*5$"sE1ϧWÈmIJ\c(a:/.ӷ֧ $]q4hЛ*g{CsgsRg+}Ғ`'jj.OKMGjދYG6Jt.mCAL^d0U׮:)p~|l.+{?zt,\}KaHWahp:|2;kC[t[ҥtjL_#@F}Qw%jѣkծO,tja8\os M͔aqk;ǔX@J͐>ayLq&G{~.Em銀#s*Jc=&*6{,3w+-:H4~k~g5S08ƕrwWpeWkM9!y,^O"d')(OF/ZRW[UMiiO+2tKˈ^^nеQAd|z)$y!Sͬ˼K@ſ/)SJ2tr\#/6 +zCHRq宴bϊ}4 7݇זXmU"7.@; չ[kH+Y3M}j V$0zxHY` cvxJjM0id`PSP>A kڢ z6Ƶ_cHÖ`$H%ZtWxF~QCux./KC 8)]up KhHj31A#!\TFf$bN׻ê+% X#+Zoz*;ލ8)ahLK;[A~P,IHX5.؃A%z#^|qGh&K j. 9h&ܖifsgn )Q?C4⇯ 2/M"s4lsMk'pL׀iL FF%67`XNK:1H L0r4;/ 98Ax{6X'+.Kbz0bea5z64(]PAG3zv )$6u%sUE*~ms=) bb-ˍSMz7A^\/FTG2c _o=% L |`,Nq/^t'ڰ`Dà e}D5/̽ЩgRr\;QxvK؅+"Hn0N Y'\G?>Kg:kEx:kևοmAQ^<-{dם'8(/93"NC Tgu1+(<-%ČX|%m1[M0xCSnË ƿȲX2Y䰉FNj @#v"ء .a^K64S.γTny`gx8Y?)4 iU~אַ|D(/ՐVQnɴU-d(SK]!ZZeJr .9Cszۀ]`Ic#ZY& ڀ/Kw82c6EA65@$kW?y3 [ׇx(T/"!5!g][}F&b |$p7m់s3'Wۀ3W&j`7Xl wI1c(m}jr-ImW0}F/9=WMs?~d7HTm:?^M(p&A7"gA"':[dž#ZzBK YbUs8ֿ m_KL4a9b:c-Oڟ󒩶gw^:,y@/H8ӃM$P˭ JPVwⳌm 9e>ʰ]&k;]=A>{>l4?ɆFhGF} iDD0ƾwx6+1|"g!ΧNQ|>/drS&a:ગ^z6EЂa$CY~i~~O$P}p1+P]4EkVC\UWO]xb->(*v9#RT Z݌3 $aXt^*f7UNb&4}E=z8Oqum:z }\<ܞ5Jyd;fTG\ |3çߑ`}gۼClZo<:2Ҿ[ʡ`n1y`C^oۊ77fWp^ [9`%@*]#3A|Y-) y?2E >jo.`Ϗ q4m,uWӳ\hQwĤI")AQ&:Jцq@]H݃  m!,I;ACk CBZ>/meXaѳY>3Fٔvy?i6p@׊yւ9 \?&'6i$cgd1ţ#FRF' \ak+f)LFPy:Ües )a3Ð8MRr'J6%¦ywGT=VN#s*6=0y^bX'k&fUpb"%#2߾JƷFXg9)ط9h}&9,f@1Q`-Ф P.X 70ܐ4| qXEӐuV3'TX?`|&?hи#G&>B9B˰ᰇ|) Nn>:`AN($;&1֑+'FJBWX0řF!,ky5ilҬx6NZLchFc K ߹s1[D"ܞl٬>V3MTY8GJj`P (~{7L]9.q  g[4F?^N[htGʕdP*(lv-OAx0qy鸯}q_<VX O*>Z֟9?.RF]#jדT#R(0Φd6©`LfLܕ0j촒&箫YQ \ju4\-:h%N+gMZu5(qrNhhp=Jj%0m#l3]X"K̵sd[#mEkJƎKv'wtz[= ţ=D2bj#elvQsuQwGm\~ՑFSK:I^,Ny>_p\+]]ҡQynr87KYd3TD0HT0.`t-BB5"&6ôfQ_`l4`[\~n=0Ssr_(?-6tЭ@ ؗFUw]`{,} yKwQH>B 5 OAm\ph9ϳLq.. )'UV}#3q y:B:HzPY-etKjn@Tʣ0 _G/s<,m942& }Bel߯d'!tIbzEFw{W8!raXwxE`_[\0X4 ho} UorNSy 腠)W"MFq{Q0U1HVv.1(='CݯsZbElIXEalje]An=[~Țڏ4lGeAG-zjI/UרE}#PG\pK;Wѱh{ dIfub19%_ˮn~O1"c8a8ZSS C[(Rq~ m M9Ұx¼6;Õ0W p?Ij _jP~]W  i3&jRTj5{o7FG|= >4/mv;ի@ ˇY$u 7w>|뵭]Zߨc++ SjޯԈ47!YԨ~DkNu@ G61 RjNG.;&6 cJzVDHr&.Upm+цUזhkE e;B.Vz # ,k*$mhpM&LHtϰz5RۙP=m6̵"kv "az|1ђ{7+H51b9HEþcv[<;P9q@ !?W])V b/i%S9E{7<.\lT k^Co' O`[ }^eAZdp:swϢ,yM<Aƒ4 dJ(9F?r :Ӭx{BU]U4(!,5'b:8Y|⹕RtOV Qzzр$( `GߩÏV| 6^m$:"hfpy449 v VA`ƛC氵֦ v)_s,<&QSl֌?Ƚr_gi6 Fװ^ PYUp!3ͳQvSxn{<ҀYq@EjP3^X :rR(Kuav #SHq&mi.+k)lТGޙJx{zGHɺUPTU[A-e;hO1O3qx@tv1p12?`jec c.9t.җQNJgg V!` `7AX6zA\7g:dzиk x >ӛ sڊބzwo>(=FJejyyh(WG+1y8b}W&J'1)0e,B ޭ:+f5% U]\ /aR ZrIb"Gp{0;e4HcN$!`g|ua% B'ZPƿ(FeYyv aKкBkZ Ncx"'ZLȲMV ΍ E >\H>TH >?Hi"[FA\~*s!9́Uk1;^P+6ݒ޵MLJ$u`&E/9ԛzf5[H~z1AZ(Y*B%2.{58:x9.Yi_A"&f2-!6x4y/˽?kϨIh@aG 3ʹWI&ynWhtsvuON ۚSJM qpZ.:7X_[oNoS8;Me}*5d_VԪQhhEڵhm UAjƠn놫ANUvV^t[QnՇywU}Pvkj "Sd#B9ZGʕ`rC 4 SeHc ֠YH"ye飼 o?}ɖ!]HT)%ܕ'Q!(~N` .hO7 f# ׿ݬ2-vP;zb]jΔٛ]5y"p1l+ۊg1~`^{R-'fY.D|HpokErVԷ?+ztuظ{ܮdYc1mBT΃.f֞ N^G VGbpU@6D^Ga i:{\+ P5>U A; wKO=N-a8@n=(=O![3܏ͬ 5zTv2;ܷܗqx,E]P-"E Ek(*'[ hT,ɸ 7^7^k o"u-װG G0 Hub3f'y8K'#M.$]=PRV';un˺!: 5Ynv-m`M (r[[P3\Y2^GwS8B"ꅢHtb4QK_gEJ1ZK:Iz?z/Ml,+XWVD|'| /ᆻKOS .QlZ?Kg1wԶ(_r1e @am#}D>bx5 6v c.ȝmN=idD4a[>{e }}vx~'ݗ?<|gX{c3?gf8ME[ #]668?anډ ^طaK~eAb@ou?\7gk^lސskzZ?jY{;o޾ioM :w35OVO;Xb+JYdR^xa?V 4C(܍$pR9jC-ap[q ܝb;Rs?@/#!# +r칔qf.:Lnρe]]q8-8p2CEiؔ.1نC}q\N0tS܍}N/?.H9jV9J*~QՏ aYYR5ňsS@0pa7*%2^bӳ6#YMm:I)M8cQ_e#OI[1#kL4"5H-4&#J!=./Iloަ;g,+EP>|,8K,J~~Ly؍˶RL>`,L"p'B|?rtoG?>K$J> <S/raЏU{ ňXzbK`2=cm Xgl{CX gxѣZGÕ%0c#IJE2Ab. 39vTخzr?'2k,J:u"G'բ_o?$2 xw^m w|`^y 6j:Z/+*)눙mugeԫ">cLՑ) +O.Tx>}k עC;F`:T~\F;#1tρѸr(ZBSEX Cnw4Q7kMZs{ON~}|`ɽyҩ6y==IptIF\PFAP% |auI`M9CC 0VB"C? ~įc#b3?xHNCXZz'RHR5)Yn ngg5jsa[.IUcT&%3?Lg”3ZZڨ!FJc\lD%*X1cVyw7H%RZ$Mt[ \UwZ~N-D f(Sg9FgBKZ_+"Ń ɕדl,>nJ 1s{2[f c0ACJFc^CU6N"8ns~%q= y^ AQ*la\Гg,T3jP 'Y4Bʧa uQ?lWM LGz`C29P0YAn)h$.*aE>H-uZC(j'>;ƓǂāEz9ⱙEƠΩ"cT/ _U Җ3ѫB|-T![?D|iwRb #[~vD i(}?L}Wtj<` 8*5ho<ʱRVj1h871.Wc`?7&lay *q25΋#Fb6[ pS Znll&0J(q JԒUI>.+X  _Mkj\ TS x5=p =|/R 4===:6۴Yw9~lc sW5"8NO;6~y _ON^Ƈ}(>Gi1c;ulCar}[o;;~;bvfs[TOg PE$_=]ތf:]5S|C }݀ |tA .Q龎$ d*>0)Æo=6*}@NIZy%K(~vpkv8)Me;'`(zq6L:Õ^yl@7^lh@lniAq(ML.2U^%G݆I8M0+DAtR?yHl kxw4A}NFְ1o,o lJZT,1\Iù ѹMK'9M00oJ{-$eGtkYޖL&̯%a^%ldޞN2~v ҿXà5" 'nsHEbh>{'4ŇTJjIH`> hCψ*;i}.MImcO&h(Cq tg@6v)<"sY%x ?ۆҍjaeӷ6d;+O}JR:A ]+ؑ  ʹ!kP]mun<$ K!l6senq2vaҦA wT+3oW^-@U(!jh?"6L88l0@/a{ŽLi용@'NA:]S_PA/|CcPanξg@VC>>~>KG':MÕ{{}!Ll6,hrECTb>~ >RC5 Ӛ^6f^J{Vu&u@ Xdf;Ú3<$p5K`3_Zf wAA`wOwx. N?vDf|[5de|ojx+|Iӣ1Ok_O1Lߢl/Ӌ݌f&))j"lsC3e ʼ$*@-+2Ó՞劣QۚA)kAH 2<-⊧!w[aઘIVK U«;ˮVo$Z]Jt:+b%VG)(Ry5P dtfSN)s1Ȋ$U>pg)njgBhSf烼EE;AiNݺ=,6{YO= Y^~~~(ӎ|ut:qt^@w0>=)i } vknK_jl& C.ꄊI'?'r(^^1&snX+$"U0댢X1301V!R5bzc["@15kzBb42Bp [qܧK=:S61\2L p ~Xqg'͘}\/! %=x /\Bq_w_ZQk{pq RIӄC 63{qMywzgZoo^>Y v׭˴8&3{er(69~WooO:/ȋ`9a0N058E,Lw@&6*a-6nݻW&Pɘʆdci-ã-";p-> sJےDY 3HR]/6cĽ5tjx~w 8":f`Gؚ2@燗;%wd(1?ٱ:J:;-mhtbjiQL*;Yqjy-k<*T,s;+έ欩veoguĹLr?Mx^EmAc-4Bm[#NL[u7"lD2ujCC_,eѤu" ie}}rȫ]wmnR%~Z)x;r8 dI 4Yo~I%zI@+~2f=j~Θ[>a+gFz^cCKCvJV`Ft, L 78pIhIq?®2k|,bÃw_|-o Po0fSSAy6I>OJV{'`i\:3p q}`(?V6H<6Ф?U5knf܈ּW.JكyC Q]™oj ߉as!}7 tdi} a{|` .a{n)-{  EEX5ۤve C$He^-ehyP\{t uڏ2@x_z;25.4/9РJ V!)}?9t9{8 EtxR&KHB"10.a"mi}рз'd1F?I+*%Ew.x :C t_ !K{\P3 b; ߎZWS?M_=* 6AXH•TS[Ncʙ7,1ad4JsZDjY}tveKcZU -),䃟B}!-8gJ+Kr(Uz%NVdm*%ފ3Αf,V͢gr&X[ц5Yryym#7\.`Đ5 !Rf ½R1 0Jaٰ+J=;yef1Ϛ`Ƨ9w=ic zy|Qzxt njDģ ;w!1Tdc&l.A77ډ@&0!ߒC tdCwwM>jC9 Ջh6ƈ[(jo`q1`)\&&Iv ( L}O"Ilh\6JqH̫wĒ&Ԗ]B)#̰vb/~HXR$ȆfdQ7M̈́_ |\^&x=x(Rd./Vz`U&A0bv"?ԝ9\=P;2`ՔG)ms4s`_;ZS@_.o\q~KYiQó(U$%ۗcUVC5_6+8]+,3Rft_ES$2G1yNQc c"2#҂").O,Ym ӆ!W RGn%F.9Hf $x u*P m\9?87Gњ攻0N )WM1W4gS77tV;uGgit>wtlwwS欄lPL~֡{Sˮ)N;T49c=ԟ?q {dT ULc͋4&j;>5m`/}9;poOBkux$!`LVG$"9aM ;P0!1-ȐWE2E0>'=!Se j7R] Vsi+/d '/S̝5EG2SVmkF Jq!1%ƋObtS .h)AvY t]_>C}PMGr+>7~a"~0!\˦M iȸPHеdPtoZEdAIkߢWt8ezUЅr/McZNVw'vp12bw|{`5f"ę.0>CAma޽9< l "G@O@OT"9/۫<r`)FZ_TC6 TŴ'S j QFv/ҫ~>&+$3w5M^@lC@ Ba䁻9%unJXrlAP4wj(K3 EndSŒias#?U &^D}1ֳ2M;}cFR?VRff# -L[}a_PEQ*vFkK/dr:%7޼ѨF9n3xB ((16_z"qp'`^ 7pj P"CPui!az9pUﱡ`;kǗ F6w}~}"o |0|bCsS+7[K/l"ù.o ː47=W|`pSV=Gyx߬pE=,tu)ѥ{E%_k2o7.Dž k 8a\ߥµd2$H#0CkLxEHzdPS&CO*%.A;#l!_zW^N__v EFwJ`CLF՘1`+ӗ^.la6JLD̮;07+}_Jgb0bf[5É-1v5jXL11}+^sۜ1]30&x&!]|r8|'51461DZXK.bJ}'vZz9ǀ`V0lsW9,鎌(?yAZqa=yh57zgGRS"&Ɇ9+&dخ5sôN@h oݽ7;GF˝n/ ז{[5{0%m^v)w8n 0^""/tLI$ө8N$l/퇲 Ml|XԉؘTaO!2j &u!}pbJʆݦFBUIs?qy-RvY ]\lԶ~ %*N9MDm\n3Pv/Z82Z]og ~>hF-[09*Ⱥ7*Gpx@JFԉ1λ;삖Mmox.^ܨzx9^\Ɗbd=pȪSuBc}F vht!( Gb c)EAKX^Y7mo`4D$H8[H;OUa/R( |D&~ڭ/ᄬ f}ɘTԙ ]#xEm q3R_mU[y[3}f{DxxnBU'if%FY=CW~^xseec>tM;jӺ]}HR D5v 5*x-KK{{o[ڛQnq ɻ!s,MLsĎ1xj삇pryuѼR[suK}cMN?s95zX&c?HpCtTӱ\3QkXNŬzTCv % b2`zPl9F;H7iwsk6EkvֽK-SIywg.M޶ w4ӂͳTr#p A[ߍ`Ee˼hYwA_x7-h9p}CoeWc\`i<}ӑAagN|[]US\E55{]ق/ws}Rv0s2X<((̌H&+iJN+Qn)'Z⢰)pط A`wA`# mSc!(B P8 we%}A\A'H}ٳ61n#od )qZ^q#ѺzW3cV~Jza^pz )ҷb` TƌobP8ZR(K<.43@&LkUڸsVLZ[S=+,+:yz^G ezP|s wŰc2d e"}~Vh,!{. @<ƗuOR+z4MP3e}L1c<zdsXʱz9dY[/ݘ ԭ]4xX E ٮ:ilJ^Ӭ QEa|mx_u BQdnQ]<] XeO&Ȧf,y,xj3P(o$𯎏ـۧw_Dۆexvڅ_ "1eHJ t$UƸW=ZR&fW#/A ԣBZ99$R!z޶?eAq#ZraΥyRt*ir.`g ƈXLI 5:a`m3Q?FPK|rGT>K4䊃*ЏѤ<*gV1"֊p rf@^J Ea:p|`Te\C3R6͆#nk.=DqiM KGi_D?Nۛ)wmnC[1_ekZ^7z).È˻Kt6ܬ‡yl~Ґדv?ro+g/qf2.zX fk" 1٠C 20xB2TjTsaOpkܳo-tAhqNg9҅N55V<`U~.KU{iw+mV>7!F5].ү.M Q6s&,a񴯄D-2XU]VȖm'bD|IP[!l}s%˂%N ʨX # R o_RWITD(1QW8|OL `X%j4_N%S'ԓl{PDC'.;4.vGHm5+b~&ؘK;Z% '79ȿ™n W9۴WS+wI2z=#hjMڨ(:ۡg< WL%p+Vl-n0؈b':M"iz7k ' n  bZٓK"sq6y5t 9qbsD-2 )J{,Gtٴzr)7\)&p2>Do*`J*@/*H Z$`%Eߗ"Jޖj[ {|d7ᶨ#|=ˣg{8@PEBV@O9WQ(jWwOWQ:p$Np"ѣDC <#CCLh.p^GC#N&Ij?٥9zutnopZ/W>b7N^Wj_X1I QbV mc#,e~?dI|rgN-|T~:M/i Xƃ "e!dSgߵZyEyV02i3lj y'@]:+ S\a?.T, >7" ;0|BP|V}ϧi|lܩCSO;dp*z0@f;/LYWaq.S ?c9M5mшJ{BD0م´.;*;T[Rl>:hPƧ(V QkIrDWVO.hrW2jU%|St1r,d,=~9~r>??#:}bj-ZjYw4Ũ'^nt`f,yGmznyB69~"PzC+0 jܿXd=ioMh) AXvzz~7985-v, q@5]9˯PG/_AW-'G??#H&O!fGid-l$O^b,k@5JEO9zfK3zE.F'-XxٸSf ?`/ݩ2VD4]-3.n>qȊ냟Ks@~flҫ..$IYؗDv*beA8 kR42OgSTM tp⣍jbnܱ] SȾ!W*FM֨AAÀReu4I `kH $jy[*;BCN6d1kUnuoUA1l$1|^M'# d{MF7Yam zYK87l~ht)*%~N q3 J&P>~is'O&BdNB(*mJR@Ukt9Se TS[ I}KLDܖ0҂Xvu,`27VH4op11u:Y~ΙC}3dF)qEk:Jvljn !£LRs r!aܖ 9:Yb7&j9&!!rxވѵ Hp[3WOѠ)JE< 2sWS6ݘ=y 2.iC'Vؽ`?OWҔT(2 NIIX: QLcc:q@_kZ33UFʲP|Ӟ?%qv++/'6e O95Fm 3IZ`kSzbbХ\ZC9(( g9"p^ 2Y66ffԲL[LfxP2\ Ej9/b<50"jEcٰ_SIwȲ$ h`rI)D-.B[ܷ56cTzy4 &ӬSѱ.kQKD1FɦvO`8~@ypKXx@?,2P1-LqlIz^#'@Q-]i>٬)lӧ?:>~b[ 5+Kߐ"$b-3mتN={u WH 3Ai%/ڦOVFCӔD0t?MF A-K|k#k&D6pUCS?bM o;W^q9B2V8g­]Ā<9;tq4:4NFb-A0O;>S +[^T (g̜bv^0D{Ur4&K*۰ vMa9XsR1.&!tvK8VPNS~ѧ/p"wȠbƀVF )$-TXᐢ AKKM rݧp^ 90/HAZ9 -\&"Ja/ΚapM?(A9:4 vJ- <+> u jlrvŢʆ*lSs>W4!i:g&!ZQ H`@Ak8IQT^Kh@O`Uk'Օ)Z5j`f$cj؃gQ^il*Fr/Sьak{lm` WF?t>EvZ@Ή üׇm4_hM -F@ӿvt ^!9"Ux5Urgi@GjoJ/b)[#x[{|TŽ&݄ /!'%KBvHBB@^I@ dIMH4P#L (+Vmzy{7vKDK>ybd`o6#1;j|4Ny賸$W؂$+IW|88+NT$"YNHEfLiR=ժ\j]6{|q\~\U΀$V*aX3.PYF9|6Z9u鰳mH*/''K IfwRhrڊa [@"IIu& ójl}~ Ac-;Mt:եVZ 4m$:W.!!GQ <1](=K#5-. kД {SiԼ#ڰ 闯(k5&}fnA0QЅl"]oIڄN_'p|6n_U9nSDBՏehK(6_%]^rEy+0[}8/](+vMXGˊM+.!D0{m:\~ާ,yl6/3[{2^3kwu֒et|ZVIS- ҉㿭0qHVS3|qţUOͫЂŊZ=^6&_8lKWLK*72{KL &&,Xpzh~J25lvvƚ(IЌls0U#I&D0ݨ!i1wg?La CCa$=3*!xf?z㛠Y?s@Y#F`0D׉: P:1'QzSL\SOhLm Ϧ qwkЖ Վn^1}$cHJU3FCT݋# ogjߢw<4A$ؤLH`(魂1l:˽[NaMl!FHHʜ 564>= 1ZMSG@`$cT:[# 5ѢuiE]:m_DlzWQwuxmoMBCs ߗ!}Z@H "KunL.L>C䥄'A.F ˲˚i!av8 %h7~9\Y? ZlR鰻쾮`A=W> B^fJ'7+,@Dp ^SXcw!bm;.-)Vi9T!/hqB.UA vիGSCUIJ40[}Cv#WD"cP'mV)-+}MwK sR̚^ 2A݆QQP>:[*#ok],g <_#St-VAZ *G^.(rZbT~~I:j-m閳JZ2l!>XG ƅIkHsԲiau n/>V&h9'Q Cz;pw kA>!'_P^jHX8 pjDyRGϑ0X'V'ΔeAy=t4@`ס юy)3,/+Duۯ[$xXQIp"p{l|@\ _! =8 9#l[n*&D7ǐW9~K*,8BL kfd6lZތQTu,tZy,8ıWgrn*)ܘL'\M7 Lw60JW" osB\Aooe䝓ьj*6wa*ƼAYïG~Ir>r|.1K z#BA:hCJ'CzE`'rfLI|o-TxZf铷/f(L@g8˒?FFJ}P3Ha!Q1@'ޑB?B~D*BF#n|nz@#m,MTtRI v߰6T<貜x~t7 L?-OnZy :bYw1r%haqZ}--Ffoy|N_+ooнL콇H6m 選AO>҃n|~=igh֗y7 ?c1jMc_'a|3 X,YfckAꎋȮI,HMkni)Z#-rװD4V 9◩k(հ!0*,:*#īO0.=-TЀ$u~vK<`P0s,`YЈ1qf_fc.? u| u 2~8 tL&,&*D^ $ySxlG6 ߈*t-z*%VlԄ *Azm>_B  XaAΐ<]O<Ŀ[up<<YX=dAi'E0[W!WjMpT[P ޤl{-=^GQ泻]8͝6IOOM_x._Jm0:/C)ëKKURI0Cu`i5X V7sw$Q[dd0#mb4($ăUZ^u+;*BPiH,%m̱8m p̶=-NXL!WȾtmD aetNlt0B`l>hfh#{ #X@ hָ#,-Ѳ;kRX n1>xX>#XˌQV!;6T;8Wdfְ ZhLc{ RU>JHqon T;w}JbY*xLt{mB:Qh}Ar9?*Ͷ ف' L![;!"M9vD pxg@'L6ؿP0LQl=YP:Y _?ef( cQr6=` )cg$VJp#TAnەk/I5]z&:TWIx*:5ϝA` 5!qV]{~~O+J9zɊ6gOc1I\@ Wб䆻T4 w2F6&,Ȕt]ntn*k.[cOtӸK'L|8TQ8 (ūβ?AU}Oa$rwȈhM?>D>!L񮁠| =u)+XcѼ?Ixe[l0-۳Ws .ϙUS#h죯A]~;7 cLqo3dwMYNt&Ĉǐg=Mie2=C&B l.>4'+B1~"ͻ;%E-{ww[v&zK'WN޳fbqA>ۚC2مq$5yyny0_KHNp*<-jE-E˛ZB2ަTپ<\3qKGjs)FqznmȞ)NB 1G1A )CPQd tOY~ք%\ ^% \=Ub`7rJ˪dIxX@˔k@w bQlD+!R19-9 Jb?W~2IEW'"Lx=*0:TT?'k{}&Y.DMz<'G'iIMIGr̉?D]@m$oLKH>!\dc㗑N|CZHJDJ2Lt7;>ƅ\1xv2*J9d LJ=?XH[鷒H']$ Y|ΌadCEKײKɫI̾=۹4Y5{<61A0iV#@Y~|I}Vg7aOy|ߴhq MҟP\!vamAf*r(D%@WoY& WT=HM%Gr']GEF4] SP33%&6`&1~]9 MD%'N^Gad&3v̆,k=k8f?^:-H"'1nf($Dr+RiW r^#ynu$nGo#H\OF2?7F6'lBxtwd7l3ZSv;чp#hWM'{(+B.l%s'r} ͨ_r}(B]qr :AEOZ,NפpoFxxD71;5-3'U/1Kp]ED;^^ӻRS:Ɲ9KU*vUxq#>ۯ:SR;~C=b~xlѧ@AϖϨR1xQD71;5-3'U/1~4픵9r~|Ht돉#gxqim_x"NW|ʼn x64=dO8X-<ёHnE(.jM[| _K,oxq6[SUVsIa}?鉧tFx[qHMƇ\ld2]o^ BIxm6ݗÐ_Wr uA'f.xmrԚdּ%>VZX/ב'Xxz { K ѓ0f]7[^SIƜS3mBBdežd=ػ]*|K7Ml&4>Ζ[4@{X8DoIѓ+=Imx[ϵk/ȇo({Sj l͊L|0 Dx ,gҿيL<L@o/x! 7ׁ̘(čx~K!AP/x[ϵk ~8V/Fymb(l6` \x: B@&^"JS<]b 0PB%㓓+hW9x[ϵKD Y/aƜ-X^n)IݿQ)9x[ϵKD Y/ᆄt3skl?2t"+6{7x[ϵk]f/~l.9Tvc -x[ϵkr&"JIy~]|n& -x[ϵKD Y/A˚mG#8cV8>1ʺ|8?cx[ϵKD Y/E~+U1p=-FE>VH=6x^ 49 [3 XlʫK100644 rpc_aik.ckQN窖?Tm*CjT43`](ip&lx[ϵkK[sj7ۇrO?m71d\ -x! Qe 6 O 9\x! aҶ+^fM/DO^/xD !100644 rpc.cdl>oј9/6.nNʱ!)ioRxS8juسKUXRx ct& Ņj),.xD !100644 rpc.cMoAaތ8 ^+!%_Y+-BotyiTORx[ϵk4e_ 8nH1r>,X(ML4 zxW !100644 rpc.chplab/Ǽf!xҧ#&/yTHv0Ad2CqF [?%lex[ŵa"m8v{x[ťhh``fbPT̠Ҵaïm]Uubm 6x[ťhh``fbPT̐yF/a%xxnT,`ܼmpkJ.&^!m -.1ckpJ7EDr<͙{ͤ?,&gxD !100644 rpc.c%wh~yao&@N!\ v!i*^CZF'*蕳'{lRx9s0fKzFhx9SD Y/aͬ/.OorQpHл5f'͖^;x9ssm_L,,*`3@ xVmo6l$;òp1H%'hJ $-r{sl"xg@&4%L n$\)LyQ.P,`ViSɋJ F QT<% .b?6._kN+ c `87ӕ~S<`өz1Ҽ"d2ZDk˶%cDf&Z#,ϥgFQK!Gr]^oROX(*nkS\{ttaޒeO),S'c4 $qh,W)W eXbgtjQR mz8z9Nȏ$=A7z/T?K͓WruYP~lQ>C+X]:N.]yN*k4 J0Ë&y1'L]8\})`&HAkr_-ݮM+|T?É^I Р#v8 2q-uEV _rTP\Nj& k+ЇıF]-2y^E&:S64 1m+瓉sp^pDSkӜdgM{:roy nٝ1z؜MSݼo" N!xI n@.Wlž ܹͅBmox4p`5qrg I*׉/p^']Ref/Rv@l}1xe/eSop\[(fԼԣfž6{֐xvs#x=AVݹYי;Ty,[jO0KjkJbۭ}߰V\^'x$YtC2ƿ[U'_glXk5\nyJ%E) U) y%% J: !A..:  Mk..N׈xgoL,bP?4) ̼ 4ܡ`i=Yǚq ՓOʍ!kbɉ0"z)EzzCP'1&;0M4NcVNK²d8@ Gvr5xt+L'&DD x,^t#GIQ~iqjQf;ƭ_/ xr2XJm}W#ۓ40000 rpc ^\(ޡs;W~VP &E6$TKCzg$4pe(1h!66ԲD|#ۓq]X堑E}@BxAGFh bC4znds=ijHEJqCI5_0#nbHq}z};;qxU嶦2f0)O_i 6x7U嶦2f0)O_i',+ HD^tz ٱSt#}x7U嶦2f0)O_i'l &h\+ޱStBDx7U嶦2f0)O_i'ٻE dl̛wUG걤Sn x7U嶦2f0)O_i'"S#eD1?SqRx7U嶦2f0)O_i'!^"!dT*ҥq Sx7U嶦2f0)O_i'ʉdNj'`|S# UxR'100644 Makefile.am@R1dm'H+2#15u3&6C)!X l>Ә?SY^ork3´J+PclH6J0bZKr M&t)QfpDhb6SVOD3„+Jx!@haw2KA  !%lx.]p%&ŒgpUgLlK.x!p!ѾۢA6 ,\/x.]p8Hl=$ѭ[m6 ,x0'100644 Makefile.amPpǰ蘱{iv'ԯ>x.]p}UWÞ~+ܬ&l,S +x!xl'hd`ℳ_/x.]pC]q,:RN7]4~x.]p))z} [(+bx::6(Fxw5Q ǒod(Gޝ9ʐUWT'H+HxPkﴤBqxmSux7PkﴤBqxm;.U~t1F9IEx9φԦ>V҉2"X-x.]pBH*|7(\h^m+x.]pCH_97ꨲp? ,! 9GA+x!;)A K/yLl -x.]pC4ueqGMWvwNy|v-x.]pnfet6wH:y}ߣ5X-x.]p%&[]o\=).Ϙ|-x!+v9>`K?@/x.]pC=ĦZǰ@ ,W hB a䑳B=a}AVQ`96I*dIx.]pBH֝ k4S,38j+x8(ST`,|>Bi5?5}3` vԦOF y?qx8=G(:ĵR#$ >޷?5}3` vԦOF 7x8Ks9G!1֑E ౤?5}3` vԦOF +Gx4$8T2Q:7H-x.]p%&Ucj|B.gLl-x.]pctolAc\FMi# Ux6a Iю#.'G5P_>Vc9(h|uDx.]p%&ދzg^}tSNfqϘ$-x.]pCȩoBvtH_!͞zsS' -x.]p8Hs;4Aٻ6= ,x!GT[bD%#W ![x!ڱJEeȰӄbW;a/x.]pC\V@{\i:-x.]p6H[TQf+b&>ts=6 -xSuEى[dt y<=r^.ߏfwx{DzY Z^t@pX)UfoFo>I)*TW9#axhhh#⟉C3ı.y:$L]c9 ܓ{ Ih)2vf]A,>!UCPAcEeu(0Yvx.]p2˺~OTd%^/ȴb.[ #x.]p2fkA]rdͻXlY Qx!Uϥy d-?.S֞= a0x.]pKsӅۤ&2mS硍K9 +x!-ZƧei; =/x!Z#ƻk:Խڪ%`n/x9rRp̠;EƬ|T"",ϛtpZզaf|Gx!N09K"F/x.]pCH?_|}J5!&):--xS7sޝ*;Xj ].3'#Jɀ||22jj`ǿ1e&Wz%Max.]p}y޳pg5=y}w]K9W+x.]pcC XxC (x.]pCHC?uh|p%{{X#Ux;.k%Q\dfT&%7VckDx.]p6ʾ&vm8YFf_ؘ-x.xQpV]tao4 ]c}㒥,Y;]xM'100644 Makefile.amcD,ml+2Rְ'i@5TB{Mͭ5챤o![x(xQp%&A3KdIjd[@7xklܐ!7 },۬sY ދ _xklܐ!?~?W(og__}x4dzX]x{Gdoͽ.CM7qgCx!MGc+ݹR+/xklܐ!]4+SvꁋӾL Wx4ižN2sxsBy1Ji)T\[BxN1jGZ m#?"@O=#*ѩ'N+7wwsBy1Ji)T\!]xS>s-V8Odjˈ*a.& )Qu$Y-7 r`S7ȃmBt|{"Iaxkl0YDjH G߽<.o^|֤ -xޏo^򊱤-x!w 1>{;˸cbYܳm/xklT740031QMNMIKe`۩+%A7s{KNlTgZ!7Th4Bax*pU`M6_IJl} -tel"x;. xDnBȳBM "q=6MPg )]Մ ݜ100644 tsp_migration.cu?LgjV{qLg% k}: %r_ލ {TkJx;"sDfFs/[! *z[_ nPmϨlfbPR\XZiLcE3@]jz_Y̫`Zx  Ծ |*)`M֓  x  |?nA #/x;"sDFD71;5-3'U/1aoLtN*EFuY>*7R< Q,xL?Ym/x Spc*100644 tsp_migration.cɈpFX/X r{sOZQZx!#O-7jz# /x;"sDf 6eoo'RL"<' ,+xe+5 {cx_BۨhNɑL ? =xe+:~W:l>s.qr$] kxe+Hc.Z5JFusMdRm Uxe+ȔI{K"jzɑL NIxe+Ȧ)1Rޫ\Q~ufɑL vx EQdO^/9Cǃ# W -x iﺛW4lm|w⓻ n[x8~0S㰭aݑzɚd#ݱiﺛW4lm|w⓻;FFxeH]gWZpȦLhxe+reqRx|yr$β Fxe+ⷯnUͱH&Kq-x bDbgqUWJ .F.xe+Hӑf=m3QGTRI<ɑL  Cdxe#[*\T[㏟e!; x840FOb?HW˲ ,{'8¸:G:Y LGxe+HeGgi]4'|IѰɑL BLsxe+Ewb L;(oɑL x EȫID_דY  /xeC*on?ܪcM6ջԠ](xe+Hノ7;K#@Txe+H 3g [Jy]ɑL x E@ O|Y 0/xe+I/I&$9\^LfɑL W\xe+ȃПY]2bil_dI#F  xe+}FuVT7<|ӑɑL -`6xe+τ ]o9=rdH&h cx E>5ݧ:J 5݅¶Y rx Evօ:qKcГY Axe+e nՔ ט63˔ɤ nxe+ⶄ.=gߕKc_:#rxe+H.ƓI ]qfmH&^ Hxe+Ha;羷|jxɑL uxe+H4N'.!OKK={v[.dr$7 "xe+\{'b.]L'ɑL  TOx E:d7[qx ȸY ~xe+?GB,{[xKjaH&ٶ c+xe+~S[t}$$rbr$\ Xxe+Ȃˡ][d[l۶I#Sx ED5̄D:kICY r4xe+y 6ot,'w:=սR\ӹwr$۴ Caxe+Ȕ )_׹igH& xe+H\8B~克zɑL ;x E{ò,@e=ѓY 0jxe+Hw95JS6cGH&?xe+~W}`W#]gr$ JDx EuGЊgxY Csxe+\C>y.pFwɑL / xe+YUkRnv7~Z09I sMxe+HJ&{śeO4ɤ zxe+eo{L#L uH& 'xe+ȶo N?~ֻʹ9;?*_79I Txe+AJlٞ} er$7 xSf>q1g}M6xSg;<;9yyUܰg}tdx3SoY-K^y[X?giy@;ـ2u@HȳhlqxI"{yD;ٟJĻF x{qJR7n6wybdx ur VU(.JVMSH,.Q() mx;xQD71;5-3'U/1Ac=:sՖ+-:D9=x;xqBH;=n}\`GĢ@ gx^ƿǭ}LjՕrQ1x^LB׮,\EONrQڟix{q; v.t}A :<x35QQҷ[.u"]Ik 'k†RebtCxTb)Aޜ'FϾIg}+x{qS5?\ ?Yn#o" Rx3rד,0YN,  ,*x;xqHKegO [-R4A mED2< *x;xqBy>~R͘T sBih҉3 *x;xqBȶoɟ 3+;u*x;xqBکn ݾ_KR^vrL- ,;x{qB57UZ$lY OLu wgx{qBmǮBog)3TDZIMx{qBHh;%^U"iSk ?xSu@[إ=:g}.x35|]c$CN&~I )r1 ^ox35CH<\Àt.~Iev5]*XhAxr^mQoa缑^B,x{qBHڒKx9·5˞d7sZ !*x{qHo̡ΤVi[M9T cTx<52NEzVK[ 40000 tcs䔒7\vi>Xg}\Jx{qInq{]m]ǰkWY qx3SjdR&urL5*gi! JO=q-2x3StwnRaWqVgi]z,o14E ς˷tx3SU2+$ySlܞđgi]z,o14E ς˷h@6x3S1K%il_0Htgi^wp+nEHwxx3SSkHB&uc0cx3SFEѬco5kcNigiaFƌl~H RE5zE[<@} x{qs!)s^ wN×2 4x{q IuB, \x2T W?[ͷj֑gi^wp+nEHAx{q_gvQ1~^Fja, 6{x{qB++ n/I ^jS^Ķ8Ф X+xS)3oK&I협g}9,x5#pGb+R#4I Xx65#pGb+R#4I)ͅT7!Պ^>Dx{q]:\ ΞqGn? x;Bț،J+3+Kw8NDVHVGō3YJvƬ5BLF1}o-Pdߩog.P040031Q(I.O`0{E_!|CBMA1PI{fj{mD}E=Z؊́BJ=x!0LV4A7<˸ߋ[Yݳ .nx;wH g-;n?;sO딉V"S{g&qli֗Wbe2pjgn9礥oɞW'vb eXftC3Ԋ }=SoO|TZ/cy^3Nb2&6B!(vGD&ob2ì]R3[m̚ɊJ w?j:cE˭7!+*NN;^5i' ֲމ 5sk%tp&vGi*~g/A$Ǘ$ė [?i%'|f\eVջ`#TiqAf|iIfN1Pؤ*+6ia%W39 ( !z鯐Q-j-C ضk6Anu>j3Nlϲջbi&nk򃰡 BfsJK&f{b=?>w&f=eO8(dWƓ\& ,yȲaǮ/&zjAla"OۯK^f{߮Is}m{ _?u x~ AxJ_"D\y6u'}W @9g+xk%UJ%ǘR-B 呗~2.LIVߘ"-N)z4j+,4 M Z @LQ&PM>|!oUW p-YzxRnZt]h";ix?t#0ޏ~wAC:]2ܳ)K![+tNk2}} Q"Zx!SsB8W |/ {x;v ~ƥurN%^4 )x;4Eيj) %mغf} Vx;4Ȧd~h-e.9]TOf}A cx!]1źݭ5'p/  ]x;CDn`A^DŬ}fl  x;z.h.XxY,#^@,1bbwBjJx;¿(Ulx[ƿo)>LQC+x&L s(ˬbHvYB Gk;34x[·oskAIm72\, }oM&-x[·oHJ{i #2;&͋r7KSku6Ą +x[·oC+(M/nbל3Y-x!3hCMs޳RC( \/x! AĤwxb0/x!PD/:f6VÖ̳;x/x[·oC5H֔;GwX^C5蚋/S-x!̊|Ǧ.aiKpVKZ_\x:̊|Ǧ.aiKpV$o\0 ~$}A HHx[·o Ȥ=t-;Ȓ02RylwO,x[·o8KqzsNZݬ -x!kJ{QҖ;C~MhI/x[·oUf>-><w_j1I%53< 8-x[·o~&ӎyo8OZ(CZ͗Y dZx9_`R̂*hW>dąFsLA NLC U\&XҳQGx[·oH)G߄_6 E(x[·os&?߿k*;gddL,d -x[·o~&n*JLi5cLQte@l -x!!{es$[X̳)ZX/x!W;$~^x!M qhtԅJ;; x9_Bԇ$.ץm5"sbM qhtԅJ;;2Hx[·oUfLGw:%e%?/=xǥ/ux; nSB3V]GiAJbjcu Q;8Ix[·ot&I, 37<iͫ*Y vx:\r}nǡ5Z'O[ga1i/.fy Hx[·oB]+FU}eWʺx#; +x[·oүc]_>uB^  (xI myf#g1L~ϼFd;R aXtu=&g9=K5NsdmrKZS9{;a{ ՠk.ڿW1Дnuj&# u}y?j䳬_DSbQqu۱վ*| x{w sJ3{YG+Xkh``fbPT_\\R_R\Ɨc~ťO]j':m.7vA;ȅˁՀj,Qk100644 spi_utils.hRQ$LN6Zz7\oӁOfEξ _4;D+;Nee100644 tcsd_wrap.hO E X&sQûV~)H%acy@ع(E8VO[IoMI]«"2a1"D]Ŭ`Ș640000 tssf);"C5;ANxkmݐ&=)MWJ9ӏ,)xkm"b,Z w~9~Yy-xkmݠ*Njbr9;i#Zx9 $~)H%acy@ع(E8V g&ҎvZwHۈ޷ vxl A3Jc0)`kۙܓ;k%!X!z'N()d0100644 spi_utils.h`F/ l7tcol8S=K}dd#_[U-IVWzfYҹӳK=?"x 0[0ˮgUnr+ Qxn _gMGPwsiM 83s,A.1 b9Fn^2 ޶wJ100644 obj_tpm.h 2` +fT6Jzr>0[0ˮgUnrcA6 xl rҵ\ūy{;e9ʬ"%BP"T100644 spi_utils.hjyY %qԲ/CK;!ojm3]|9@_[3iMKOI@Bx" \:Ij2`fdҕv/{x{GD71;5-3'U/1ᡚt7Pp?eŜ6l9AX}89);u!..9GDxm yȐ=5b-'bq:z g7 gڕ!reH3H0z?M?ஓ[# e%VJQgOe/{x! T7~}RfTس/xm m ҁ~&Bu-!(V0SB ^}gHH3q  v'R\FX^B[.s4WT_BK%em,{x _[9#[2Z~Ŧ/O)x soW0qni03Ɍmv<HxH _;Zɕjܿ'mQm 100644 spi_utils.h>YNʳfQYj`Wxwù,gmw[\^XL]-x! _f:4g葧Q³s /xw36eTwD5qcvc/4@ Wx5 { To`~LJ&"%LZƈM \ Qx2'100644 Makefile.am 5^FkfZhR'ˎ7סuΐ2|՜Rp# u40000 rpckKM[hk鰫y'_+q CRݏ1n\Hi@E!K qZu&X oEGpb̑ӭA%jpn( U Pq۹s$;:`O ȢdN#)vE,^x5'100644 Makefile.am̦9eHwp=_7`r'_fIT?+ ٯ)>9S[K}g2ϵJ~]_tdFNc.]^ǭn<xcśo.Qk䡞Y k@Yd>x6Fs {]vEUq!PY/{u{ҿsͬ9pX|=[$jwJ3ZWNf洳ؿz7Χ]ɩE%i8v{;>jE=E&sJ Mls[pMޮW'Ol3;lə;~1o4~>gU3'~dKSRsRKRq^;)i?d<;L̮l˶;Y{V4d3SKSA!tҜeswvijR$^QVs&Mfl*2xAͶd9Y[gn^eFnF9Ojmָ١\iI$)R3ֶ@Q( INQhe5DZnMqJO~aH >Ǟl(wz޽­z.!ԽY Xfй|j$lwC#s-hA+p﫿 MoXn݃OD6+u(CMKz-{Ahm"Mvմy5&vBi;mkcHTa[YjĨeOqbTT8- 0 ?q2q.8k|gOC ;Q \Vd鹗 oHwnJ:]O *ƿ}50!GbCl|SU.g8'*DzYMlk1䳫⌻GkQ4\Ac);arM G߱j )+!zvhX8\5=URGO^PKsL |C9$U27NbXY̫ Zx;^ ȟ! 58ګrc#sUl.9Ve [Ix;"sDf0V߸MOǽکՙe 5-x!߱%w_ Э2  r׳ :/x;|QrC\{'):hf;dDZ،~Nqճ : %Ix;"sDfC H(Â9\/ua~围(k L[1 Nvx;"sDfC HUt_ۙ\SJMm1 L[}#x;"sDfC v{e-XvՄU L[g[x;"sDfC iv܉T|:ϐ>y L[+ x!|T3m=2PL  x!Cn2h{=y6ٳ : d;x;"sDf7ɊWݚcL𔀒“X8 i.x!|oPZ/w;F {/x;"sDfC%Q-;yڬ+H6kvk^rrx;yMM$i*0Q:hO Ym Jx[ @fHCdm].X<\Fۼ_c+x!y b8 %Ws0 /x;GFc ֠"׽[x}nO gP6PCm3- ?iEIx!|IdY>Xdȳ |,/xb'100644 Makefile.amTjݙk8yl5'jѮL3lUbm8[QX a| [2k3i/ij H+5px! Jn(¼d&BL( j/x[ $3AwU^Cx[ $3Aw8ȿ8+ \_wle̫,H0xki!Rs9OÕ(%^>k\1m-xki,Կo +g.ǡȲwU\Y-xkiQ740031QMNMIKeX_:~5?~7̨2ۨ~g*ց@5_56 ks!Gxki+b-VLVW?Xޥsx:6b.$G"_TK*U<)"';X}*6m綫y_Γ] `GHxki$Ф};(w봤/QS>52nsnuxr~EE BȒ"9s}ʂp<cJ#Йvu?7'; :d%K100644 spi_utils.ce2g(@g\b gRE/0^_XƲ`L!d!:w2,\g)/{x`Ju`P4K!lLk֮F!" N 1,UB}\鳩 Yn3nxki$r-[baiOiGSjZ61Mp 5x!^CCsmZx r 0xki$o]j;er´ ]xki$F˱nu-fS*vt{ Ov̮nXShF e  Gxr}֊yMR txSr}֊yMN5 G\4 8g2hH=qKֵ,d| C&axki,zVO ]X3m`^ې x!D3=םުp޺&X G0xki+bڄpėwvN*EKXޥj5\x:]*0^=Fha#& 8`W&aܹX] |HxkiC$ތ|w^V_R`0{Vux;jA( K{$Yw CMo ͳ5 Ix;ZV M7X ny:D,i%j$P"g YJIxki)+07mYT7y^]ߜ9 -xkiِ%һ;Yۄ?RNU = q-xki0K3jGkK7r9dJHfZx;cfQr(0j1Z84i⭣WuD䳩 Y:Ixki (蝬NײGoYͶY& vx:&+*Zx֣X'L)d^|4;8;B HxkiQ740031QMNMIKe`GqWo*Kqm^t>Xg9#.p(Ə|ELcV08iF(oΣqv=K!6̺m[C茬mJ b_!yYX: &F& epr= ^ro %`*LR$E No] !Olxk'fg#)cx!Dnƫ6{$Ӑۢ%X $x;C"rս\-M+qPg4l)nƫ6{$Ӑۢ%X Jx'}Oz*>zjDfhVdlɻ vx:06ECS س6B'.|Fp)mxk 9 O>x:06ECS س6en; $"H2r}/9 YIx'}OzC!H9^ + _ն+ vx;Kb˔W\ݑ'#NUl}^qP/C@J YPIx'}Oz HBsZLұue?/Vق} l,x'}Oz2ȾqBܚ}5۫l6gZ .x!wj|>"Q7| R/x!1|n.P J M^x:1|n.P J\Q]>nxrl !%Hx'}OZD71;5-3'U/1 n<}9« 7o }%>cxh7,0 4 ,h,X{wg$9bx!@ GC:(4T  x^ɢD7ml)1][Y. GC:(4T* իJ'164t}'l w>c\-:Ard (42DS@gf& &F0xU;Js p~`l8މ^TjINCM~S=$oE)3gx7h Ms#dx'}Oz?FͶO釋^>ulBLg;-x'}OznyLŴhXt_fq/S XxRGrFn5\(8Dv:;+}1?rHS;100644 spi_utils.cxF$?/C~c"C\()o4S=4 @įߔȶyK M 9+3-@" WM;xxil%4$ӎ\k礱. .x'}OzCF\"NK~&9C -x'}Oz0燅·xi\0Pu:vV} T-x! ]Of4]뉌ɽш Us\x:^6N.0劣Y%Br_ ]Of4]뉌ɽш $?Hx)rMhQ̽. 8ux9)rMhQ̽{(e``pZrl sGx! ٶUP ĩ71I H/x'}OzCSu왕]ܞVx敷L440031Q(.Ȍ/-)KfY+ݿC+SUVR\T"̩¹'Ϧz&p&9n/*xxRo=@ %fSN+ BgRۛBgul o~& m'`x!7  T]?AhK  /x!(o㌭; >^x;(o㌭;( YE~' QgP쳳+n0Ix'}Oz&H라%X;tD{?Ͷ 9N -x'}Oz,v]e\bvv[NG$ v:v6U -x'}OzC kc9 -+/_س-k06 Zx;^,ü S<ri+l!9xϧj'9V2OIx!{ăm^f統YijO0xx;3yS=iăm^f統YijO[Ix! A0Ja0雭tJ4ֳ FxxJ'100644 Makefile.am3KsPS֧:X' A0Ja0雭tJ4ֳ @Xx{s=L |vd.rwǰBFV100644 obj_context.cڨ妜W w ᱰGfk4T.b!{( LU}@F#f Y16l x'UzCfh!s x&Z XО {3ܦBX2& QHUx@ZAS [Y&qw=XО {3ܦBX2& eOx*UzC4HX׉,b Be.ݜX -x&5łXlΡƘQc-IP eOjax*/Icm%E^g|}~]2kfOl8SY<[x@5>3HtrJLQvtI־=,P! P(tP eOx;p2ӦX&߄<ﳟSc+|% 8Ix$";JP-)|n.` vx:\R~J"  Q Zp1n|LӇz2O61Қp΢ɜ"m{o 5 a`RS!R) zB%x`$h򵪯{-s`'7 .x0Gd=A_Y|ne y+x^*nr.k6NX~NIg"Z,x &Җ{OW/E^6mVcdX =-x&b3SKkZ.7d s-xpMdVX{TM+%ؽ%26p-x;RVC|RvBCAMpkf$&},P3B7$ 9V'y#IxP.R&_;(Yo[;lnebw -xn_Eq,[&)ՑC>s\#8pK[S' гI:4Kr3B3[ QHKw0Q$Bֳ :>,|xpQE꺃ETK**q7J-xޠ*tζn'((L[0fk|-xV740031QMNMIKeXu)/_zOoѳ!"lT#Myk @IGѯSG76[t ^<^7(qWH 6:!?0100644 tspi_quote.cPƕB%ɮq @o7qB#('L-x'uBr)ޛٌ5%.HxD5.# ^7IR{IK  l[Hqr8Rx!>यB '&WS0 d/x;!yBRD71;5-3'U/1A:MnAM˲G +^ݺF<Cd8$KL"H8Z F19Ix[ @rs=-r=؝X-x! Ĉ^![/q o/x! +@mvSPԇ1  ^x:\b` po4/Okĕwp +@mvSPԇ1  aHx[ @rHOC桾G?FX~6E"=~Vxə!27o<ޣ9+kE.p=^ S 9xə!uG;&cɇ?`xə!<K-|5BVVt} xə!oJk S|yPu .xə!r;Ih+i;l#7 Uxə!2ot&99ݼ?cLm |xə!srt[Um֨_5 #xə!*k&SSaꝹR=X\\3>޽ouk{)U9BL @!%%cFýYlaj[A=kT_|\ (a?oYmW,INM8lI~~N1ÚHM:=s iyxD14?(8\g]^??9#1/='?gŻyZ RK $+zO;N/")hYˇgM *%NƘsK%^3^oM @!%!eOA&5VΛ+y}#ɷ}JKXmx-Vl ~}E R߫\ im5y%T=[ND$??aMK_& E{˞޹ۀd{xD14?(8\g]^??9#1/='?a__c|+]Ԛi=/<)QȴFgGw=ԟ{1cUb{⓾; R2K?3ϯ)aq8=ӟ\m*|7~mf =m}E "|"Dy~~5ْb5.m= ,t-{_{2XivxD14?(8\g]^??9#1/='?7}]X?-wT[1hMh"'Iv߅LPA.zũ9y .x0P ZYdɪMI=3&>~.[~(d0d)$E0r{q1o1}pp/P'A,Fwk[B%3T;e&ɤ ,xes2X blxufZQ{+xe+Ȥ`3^_3WλXlr$ |Wxe+ƌrN!UMe/n:|H&xe+E;UT2g-{jH&= 0xe+i6*}&W:.ڿcoH&5 ]xe+HHt/r팊ļc:_՘ɤ  xe+m ?.XJrHYKiLP*pɤə 7xe+wǶ5.֪ؔɤ dxe+qz4ٛesߚ\\7cr$< Qxe+3Y.;*19#U>xe+ΝKv],^rqܚ7#Jqkx Ezִ0\5Ss%f볓Y !xe+Hg=.m&S-٥ENdRG Gxe+rT]HWϛ[C^q]Vɤ -x ' 0,G;>[x 'ѻ{(8gDK;>I.xeAYUKP劽mj6z2 @+xe+gH&g3CuE"# Wxe+/ig,Sy0=7wH&& cxe+gWn+Hu;ё",2`KH&&-x ݊~0̌jub8J瓻[xerFk+[GhJ ;}dn}ݭ ,xes5~KA|v4gLvg z,x4τH붷I3"tRvձH1oYxeϹb;fT[/+L+xe+Y#^om\jJD)kr$^ gxe+;_g ߶~kDmH& xe+VPW릻;&+܄ɑL hZAx E]-ż)4od0Y Apxe+'ҳ[7֟[j2ڮ#<x E#yˊŒI夞Y BLx ETu ㉩a|Y t{xe+HcL}"a_߾cH&Ҭ (xe+Eۙ1aZ7&mgyT|H&2 Uxe+HuM7#p3L jr$ x ESJe̳}šIY {1xe+H~5n>O{!zoVH& ^xe+RBϋ,=کɑL K  x E#ܤ8%YHY #:xe+HϽQfqεV.@H&ftgxe+H`Pߣ,?&h4l+?9Ib xe+?wƽM3MaV@yɑL Axe+k+/>-fnKLgr$ nxe+;G?3#?\؄͟ɤ; x EIkvHxkY /xe1F /\pjxqپ"qP[v,xeH6{8-S;잍L$2+x ra㯺ug(fC k.x E d1>sKgY '.x89,۶WN򫻾z~ln-xe+"] gU v H&ߛ ,xeH 's{SxFC&v+x Eb ܻʪjOmY .xeȆӕk?(+z+m0d +xe+H=ц7'N8bɑL p,xeHz۪&tKÐ ٕ +xe+Cw8D.Զ(},`r$Y Wxe+ȱ [Wg)~[T39I Sxe+52Jj&}I H&T O0xe+k 1L|ql;v;fr$h ]xe+O#ש3 2J LdRU  xe+">4~we*#o7x E"vݩ&$ݰz3Y fxe+HI֏roMt~'H&x EHE5tY X~Bxe+Wk Կ۔39I oxe+ȧ.JL>T:#YFxe+mK6ɇ2vQɤ |Ixe+HT"om1e 6-ϯɤ vxe+Hn/=##xe+svkl^({tɑL Pxe+H-eKMLf30y#`r$ }xe+ĝ]-[42y69I% d-xeHΛ{+~aMFC&XxedZc:~5^Qǧn0dU +xe+õvw.Kl9rsr$ ^,xe֭}v';;\jsFC&L+x EN]+ҐZ\Y kYx EǰkӓY xe+le!-*Yɤͺ 4xe+|l=SaSV#Paxe+4wSҽ$gu+ݴOqr$E xe+\ "E.~.gr$ ;xe+ȼܸ3^A#%-xeHӻerx E9IH @xe+H( N'Z 5ݧ#mx E>5^QM5Y xe+HDoM{<^t֜#`r$P Ixe+d鶉8W_5qr$ vx Esf)kbDٌњY q%xe+N}vXAI# Rxe+^C)V<0Y|H& xe+̥G֋dE>q>ו79I ,xe+[tE{6+"kW\y:9I Yxe+R%zǿI{dɤϢ xe+ýrVuWqp9w#y3xe+O׭`>_uwʕɑL V`xe+Yct~tW\“#b xe+]CMw/)KzxiœK#U-xe:Ha]ߟq$"JaLv},xe+HPzo+U9]gɜɤ Xxe+Ȋ8j`kGT2}r$ݱ xe+;9m v'iH&k g1xe+H=;oO:VGHl6ɑL )-x4ͱV-i}%H1-x  `j-Xo/}.x E"4e獅M\Y \xe+xe+"|{;UQ>Hr{!Xur$ K=x EnhK.ELIjͰY &lxe+HQǑ? kllr$ x EQe&Y yHxe+H7J ?uɑL F -xeHԊv*,O>ff3]5Ln q+xe+J_<yO]#(,x9l]A!PDMΖhK@͑]@擼;>:}Gxe+87}r$ sxe+Ț"~ns?tWɜɑL ) xe+ȁ'+/~ɯ'#tH&Lxe+ȥ3ؾhW[ i z0cH& 9yx E zͭILY P(xe+ќ^;.]wmP59I Uxe+ٳiDm,7TА?9I xe+Ȝw {Ւn+^ɑL /xe++~GTl |m}:9Ir ~\xe+(ex#IFg#  x E[ߞyœY S`8xe+H]pڔprǫ/#0exe+Hٳ _վOZ+*H& x E,臡wx}DԾ=Y Ax E֒~Ȗ]x\㕓Y 9pxe+b'>wjɑL xe+H}qͻO\~pIcH& "Jx E)"i b5Y 9yxe+QNv\UxISu1# hu&xe+D!^q9"\3Slvr$| Sxe+HH+O[fpW)Мɤ xe+檖=ʼV+k=0[%79I` v-xe+ {׽?xWLi;~# Zxe+Ho+* {{fkkLyɑL Wax EkW ׈"lMΣY ' 6xe+~" պںU}ɑL 8 cx Eԫo=vjY xe+O?<,{}쿐dϙ#C?xe+OC9[,#+UOH& lxe+_VN;;}8\G#Qxe+HG6-$2#Fxe+=7 򩌌/J71Y>9I sxe+T/,?GS(i59It  xe+HΧ㛤t%ﭫxr~M#XMxe+ :eϝ>y&:9I 0zx Er$=kWtJs֓Y })xe+ޒ%# YR啐H& Vxe+fWlج m39I @txe+ȏzSg6b˽zNnB>OɑL Yxe+[Քe]GrWs|fr$K -xe+̾V;ϘE$\0l49I" j3xe++)_M \%yE#`xe+ȃ.fzH& x El[”+ bř˓Y LɑL P,xe+r8|-Jkɤ' XYxe+Ȼ#%HH8vDb|xr$ vxe+ס_20KWrZx>۫zH& 3xe+ȶSch3N-tɑL `xe+lYOn˭Z.'xH&ة  xe+Ⱦ\''?6lOwr$W :xe+#5VۓLmEf6GȺՁyr$ε gxe+ƕ9gX6oaɑL 7xe+CO2o.\UP@YH&Axe+ ^_!*Sjb#nx9av]V>\aȷZOqΊOEY VHxe+HK~pɑL rtxE#100644 AUTHORS Ҥ⍮/!#"c}ۥi)+0p2Y Sx EZoº>"ۓY /x E 0e%. Y 0xe+e67Ml[FɑL ]xe+a==n>4IpɑL ̮  xe+H)',=ɑL 7xe+`ՄM:y9}H&a dx E ԔAbwN4Y ާ xe+H_5Z$3mɑL  @xe+HUqM ~~ko6N/;wr$ umxe+ۑ^PeɑL xe+Ȼ{XZlխpH&Gx Eۯߊ08ۑ*LaY ]vxe+u17snX][ H&ޝ #xe+)ۋd=Sy[H&Pxe+ٔY]loy[(9#( }x EE~gu)\˓Y .,xe+)ߙ}'u<9"uH& EYxe+HCLk;=7(ncr$ xe+,=id505+2=29Iw 3xe+rw~ɞ1g#}i`xe+)f/˔(+k[3ɑL  xe+3s7p1P]?GɑL :x EݵH˸[wcY ixe+H ݿ^6]}צVkZ#xe+դ? X7?=H&Y Cx E\V/Mg֎Y -rx E{p\cqhYSғY "9!xe+mBwOI[a;ooKv1ɑL  <Nxe+HlS+oXimߙ#{xe+|y*M69I6 (xe+mtY~6+q >~uH& Ux E!Z`bn턓Y x Eg3FD6HʓȓY V3xe+EtYgbԽrɑL +`x EOГ89^j\Y ,xe+;acԥ+N!eZ89I$  .x9-91aׂYP@grz vMY ,Gxe:QO_cƕwr>zb2ab E vmkɭ>-Q1\wq#3{Ixe+g;or(T<_H&`luxe+~Ϋ|ÑRUvoQH&F (!xe+5qY]9BLOdR Nxe+HWʵk}SJiSɤ {xe+HllR_aٓ#g (xe+Jm>X|GɑL hUxe+ȶ s&;hΞtɑL = exe+H6Nڮ[w~KI_0d-H& n/xe+H,Ip7'e81sr$+ \xe+ȧsZnZ{Ig# x E}hZ.yY_ꀐY Qx8xe+HRM_s!H&Hexe+Ⱦ*^ ֥.A}\NdR hxe+eJݫ4]8ڃ%,趞ɤ ?xe+GI Շ+w 4^ɑL lxe+WFYcǗj3Or0يɑL 2 xe+H5{yMknӌPh#mFxe+ȕn.1KsҚn촹# sxe+Hˣ#L3{jtZ&?9I  xe+|? We~̣ɑL Mxe+D6D$?Oruj{I]# zxe+t7sU[MwwK yTHfr$O 'xe+ȅ\ח,XRH& JTxe+ȑ ]/qX瓄ɑL x EHP헌KY %V0xe+zDpo;+Y[So09?9I͗ ]xe+. ҡ*Ai2|r$i  x EbWqPl(YY g9x EzdV9XG Y qhxe+ȩIIw3q>ŵrR#R xe+Qo^VƚۧPwR|kɑL =Bx EGT\ʣe+)Y bpqxe+HQޔlT ~==9I xe+ܿ 3k~n1XΎ_#FKxe+ޯGWGU\r3Iܓ#xx E6yPYEY 'xe+pOWcK;oCz&ESxe+}}k|ojowɑL xe+HoI;ux,{ Ҋc#5-xe+uu՚z H~&tH&X(Zxe+HgaĤ뮅J2OeKɤ xe+ɓE1]?fTvr$ Y4x E"qܘb8pγa RY x_cx ES_P1yaABY Ax E7XjI1>:Y uaAx E`m LY px ELpȼ+֒ϸPY ix Ejoіe;Y Nxe+_UحʞH&{xe+aQN%+{rL";/H&b (x Ed L[E=˴^Y 'Wx Ejڠ#>uTY 3xe+IliV625=t>9I r3xe+Hjh[ZlL&~ե=59IΘ `xe+ȱK= Gl5+tԵWx\|Rnr$ xe+~~Kֿ?~_[51)1# :xe+Da+׫ |חN%;sr$m [gxe+b#~70b1#yoxe+nC͛vjKS )a#SAxe+%Ws˂jSyn:z!}r$jnxe+&~IsrqkfOdRՈ xe+dTDH&ؠ w-xerF=/L:y .=P;#@݌,,xe+Hk&jд +>x`WhUɑL zxe+jrN_nj V~99I x-xe4cow~!ĭ 8+x En>VUM0Y lYxe+H{v~cd&yH&y x Eb2HE pY  4x En=+9i"NY cxe+ȝG$+M6|.#ɑL K ;xe+Ѣ|'7uɜZwr$' K=xe+eot-w>ԯ`m{#djxe+Ȃ^~ymn2ǀH& xe+H&?1X+N-ݻB}r$؄ %Dx EB0rTēY sxe+H"saSW'BE>TtLdR  xe+u9I. Mxe+g[$-Uΐ-kr$ -x 'ϡS;Cϓ;>;[x 'ĚniFĬpϜ=;>.x EΦD IkI NƜ_ۘY |\xe+}9ܹiOz#gN`Rs xe+ۻhOw=[uɑL @4xe+1vhMůVOdR& ax Eģg)uRǍ̓Y dxe+ռ62d~N4|H&V =xe+Hc i?m٠(xɑL ejxe+H}Y,W.j}Y H& xe+wO߰HpK9ivB'G2)j DDx ENxI? Y /xeȿ%Wt3=yrnkXFC&}+xe+H-u6w~ W~SH&D BWxe+H{֨LI7˯hr$R x EYD{Hp;kY 2x E f9䳫cY 0Laxe+ZɲU FL=Yɤ# Exe+H[IlepɑL  ;xe+#BXxe+ڃniM^09I xe+HP½/ό &ǜګ%zɑL a1xE#100644 AUTHORSIi(+`m鲿#"R`3`s\͕- 뱾Y "Txe+NΞꍋ'Ʉ>ϿAjH& xe+Hk>idՔd'LdRz M-xe+cSG:tJ9[H&w Zxe+ݺm[U/xr7ǫcH&xe+HKG <V)zS8;8MNycB xy41k4YH|EoLFHh`QK~{l2Bw}ڜh i+;+40000 srcz#7oK.Rj6\Y :MFxe+ݺFs:QјpɑL t sxe+{j[,cu x6-;09I_ 6 xe+HȐC֎Od&o{<3\H& Mx E +Z$pjpY |xe+ȷ۶spH&t 6)xe+ >ح弜#Sؼzr$f MVx Eq;J_k.xe+:ܵ7jMX_9qAyZH&& Zxe+kBIV_59I8 ,xeǂ o%E%?xe+H >=6&%ɑL sPEx Eݰ 'FtXMWY &txe+xS!閞KV<WfmɑL 1!x E_b.>.fY Pxe+H@VE}&~HO2 ɤO #}xe+QE.Cu}t|.ɑL :*x EfҘ7ih+WY Yxe+{-~d{j^i#-!xe+Pe훥l|Ó#v3xe+rf˷O`ըɤ *`xe+ȡ[zkz͸cH&? xe+߈~BEJ^>9Iч :xe+kå⫪]'8e!?ir$ gxe+Hwg^&®U)]=zr$9 ]x EK;AIptY WCx Ehj(go6ʘY Nrxe+H<^ὂLٮϸ59I xe+gь^IK:O߳況hH&sLx E3b|EH-nʦKٓY h{xe+ͦϫ=^=kdҤ7E. #B(xe+}R]JUbHɤ/ AUxe+Z3Wp-<=fH`ɑL K xe+Ⱥ%+|/.-;ɑL {/xe+Ȏ[^]qxXOqXɑL  &\xe+HlfWů_\ 819IL  x EшiifѰ/:Y o8xe+օ9;"G H&9 aexe+H.nvK5-wd9~~r$׼ xe+:[=agm^yr$ ?xe+}>?vрɑL %Llx EBu8ݧ_$ۓY xe+ Ʒ}>W'ɑL Hxe+H /.cH˓# ux EFU?)̓Y ]$xe+ȿ{<Wu-pr$IPQxe+beZ{jS߾vH&=(~xe+ETHl Dת3Z\,69I <+xe+ȟi/Cr۴[dٙ1tr$8Xxe+UjZo);9Iq -x4ٲG/LH1z -x E1˰0\ξ~FvȓY X[xe+q[\7dӗ}H&xe+_Q]~Z{g0wɤ 4x E+rD3מ[ kY ?cxe+HP~_*VgG}ɑL cxe+HWڰyWW&/~9qㅆ9b#-xekW7K% L +xerFs9R o4bdKL}?y7> L,xe+ȿI st,|Vd,_H&6Xxe+[;W鯎]a ɑL {xe+=ư;TLZɤN 1xe+Hޝ֞V_hvr$s ^xe+Hj/+M&YɑL _-xeHiPڷNPh! +xe+뢫<;8]*Ŧ;9I ,x4$d2ձơ̿IAKH1Dt-xe+H(wo=ڦekɑL Yx EhGAuY 6xe+H\ ݾgU t;9I L4xe+HlXqsՙJO'*lr$ -xesI1Fκ_>L?klP)p:Fr+xeHnO,~>߳laփ +x E ^@_ɖ>.ȓY IYx8&lb}țhcU1ch% (yPsY 0Fxe:Ⱥ-'O?r?hdk&;4 rxe:H[sgnm}Vdk&;d ,xe+Hr[fJ|/eʡ;9I w,xeHɈ}.g]L+xe+HpOԒ[<~l1m1/zeɑL Wx Evy#И+gY .x `.gl0{l&.GDY%.x Ez觀0`}"ZVY \x EҤ,oKmylY 8 x El gdlOY a9xe+HO(.^RɑL Nfx E9ƨ,[3ʜk4ؓY xe+Ohtv/6}Y0tr$X wBxe+Ü],*wnju]#Ajoxe+Ȣ<{L_?(|q~H&, xe+MWU F半l>9Im 4Ixe+H~Pۜ%IIsn39I@ Zvxe+10-Z>'ϸ;r$M ~#xe+H a}Sw{-H&-x m|` R&fF.xe+Cfs:T=zkzZtHH& Zxe+띏GN>ºE%H& x E'*lסD~qA&Y 45xe+H۞h^;u7n#nbxe+kn~բ75=`kmr$ xe+Dž:l+m&|v=H&?лzn}/.,x E0fĐ43؄Y vHZxe+Hol[MGlw $oUɤ xe+xċNjCɑL N3xe+Y ktMJOv[49I U`x EFؒ!F$\4Y `xe+g߆{4OO\7ɑL L<H&˙ ,xeEFxF6== .M+xe+ Wxy9ݰi#Wxe+Ji>X9gݓ#;xe+s#Y\%:),|yLdR 0x El6f٭~ꨊv Y Sp_xe+˳?M}S\&rm#}#*xe:i[[|L9z2Wxe:V!$&dn&{{54 xo4Սj\ HpٺH_9r+@ 2ܚl2v IjA!ih?@WMo? 40000 srcZz O{;CU0Y -+xe:Ws4uyŜ-xe+b{H& Zx Eő@kS|aamY xe+FL'I [P߹hr$ x5xe+?xqs܎o#:bx E {KPؙ턴/]Y dxx E 8 :_79Y 2@xe++^ﰳLP~ # 7mx E/۸74yCM:Y "x E +P)_xڠعY Kxe+Hl^'vH\i-fdoɑL xx Eȣϔ^ <"pY 'xe+Hu >rm9#Tx E $lTXd3-ՓY xe+ȑD/>֓7%FyxTsr$ 80xe+HXI胸&۝w3=|oTɑL ߌ ]xe+6]zN❒TɑL  xe+_NWy`huؕɑL  7xe+sFĂK ts_>*iɤy dxe+G9{1^U2pNdRФ xe+le3,8,Kdh>U?=9I l>xe+6ş:15fSɤ kxe+Ȳ-L^^'q>#-#Txe+țimi v__/ ynɑL Exe+ȗ tVnhQarH&zrxe+QQ >{ykAɑL xe+UCmmrtV5=nr$j >Lx Ej??U껿Y {xe+B3Z4e{i=#(xe+OS^B_T5ksgH&v zUxe+%?s223WٴljH&ۋ .xe+HC3~OK5Thpgr$W /xe+vn=bme5#\xe+nuqoH]ؾH& L xe+"TN.a̎[4H&ӣ x6xe+{j*}9ӘɑL , cxe+H_6NuIX5mr$Z 'xe+so.rʩMg6ɤC W=x E+h5 n>Y lxe+q֎JmM7rGH&xe+=S,l׿͞` #45Fxe+Hw$?t$8or$a vsx EAfΧc0Y "x Ei~P}m)ݔY mQxe+HIN>llӬ4&G2)I ~x E>15[ѓY +-xe+ȵGeήYrA#~Zxe+uN%ehج':ɑL :xe+Ⱥ3syT̺혡ɑL 4xe+œ8L|϶Lvѻ49I 4axe+Hj so$SY>7ir$X x ER(ԑIEPڻY =xe+Ȕq?keVnZ̿ԡEH&#Gjxe+W܎5Il|2vH&~ Zxe+HBY .s"xe+ϻ坧N}zcyk*eɑL Ox EbQ+VD`ÓY ~xe+k2Lyn 8htr$_ +xe+ChEhqlzH& Xxe+*׭9yl?>){5#x Epe&9_(?qY HG4xe+H8]W[qΡH& 1ax Eϵ?OٻHY w-x E?H/)'mzY G/xe#A=D&v=`kݝ~ɑL ~z xe+Šݯf=g$0#9xe+ߨ:wo:\Lt4ɑL +fxe+HQYm7_9e _ϳ=o5 Yxe:\!b5 ,x4__g|s̬ѱH1/qYxe ˄UuXty3yL9 +xe+Hj,>jw2Y`69I ,xeH{ 6Kk42Ŭ9a O+x Eڦ@{ڨİ0Y .x4Vći!ḍ`H1Ny-xe+IZ;-]^<z[nH&n p,x4*?{[ᨤuyH1'T-xe+K;yk5{+. H`H& 2,xeC*ȚHM:=s N (xe+H)}6*\xeyY͓# ,xetVx-WIINoa +xe+!_}#:YZ{jFɑL ٫ ,xeH[OYrpEgA= +xe+Mx5+.H1km˸=_ir$ b,x4VܙP5z_LKH1)-x dTIy/2M[.xe+HzE]\߯7kqH&0 Zxe+GEkl&?4|}G#!xe+6K3%p)veIXjH&Y 3xe+z}ٷ?O~e E-#-x YʰĦVu^&(E.xed׻c;˫eN1FC&+xe++~~c.l"ئ"xgr$ X,x4%(P]H1Y-x CӝuJўѓ-.xe+HkRRznTgqibH&Zxe+xhߌaZu?*:ػɑL ,xe+!ݎn{ tꕓ#Yxe+HUfEKK''eNYH& xe+Bgާc9ɑL &3xe+MEvE>@ɑL `xe+/IK.ZҮS~nɑL  xe+j6ꦦ/y}_H& |xe+~!71hQyqLΥ #*xe+Hyc#?Xx E`Rf_WY  xe+Ȫݑu=אPأɑL V6x E=I3ka`Y +"fx Ea1M!'ᖝaS斓Y 50xeVFuߓnn6 dLhWÐ  +xe+[Wk _Tz{U.b͋@ɑL Wxe+">ݔaYk>f@srɑL { xe+- ԣ+fo0~H&e A0xe+jӻ5bIj{H& ]x E\8򆥈ll҉>ՉਓY /x /7o|t@˟ ^v.xeHB~O[~k'7L k+xe+ɴ7vTugO sǩɑL Wxe$_vS ɤL Hxe+Q9s7ɭ[wiׇ#u/xe+N̥^ ^o*mɤS 9\x EP#|*k=WY //xe%T>?R'Z}!ޙ P+xe+兼R݉Q_Nlz}H& ,x47wZX*SyH1 #-xe+YS*w{dɑL  Yxe+Y?FlOZXɑL kxe+nmՓv_QT%~FɑL 2xe+WH>?ypә@\#d%_xe+Y]t!H& ?Wx E-15*)ֵ1j"Y s.xeFo͜_"/YoZϜyFC& +x <\1 ~w` l.xe+KsW phP1_nr$ (Zxe+Ȗ{\l1uT,Z}s-\qiEY &xe+Hw%Ӗr>;7'd>8Q~Ð y +x EK vV9Y .xe, U/+[Ð C 7+xe+Hy1,E];odɎUkr$B Wxe+xq3f_fIXE`r$ xe+HQW5=}I,$pqk# T-x4ҮĎ -!tiH1H-xerFEC76>aX=y7>a ,xe+cSt؃'8垡 ?9I `,xeH'4,$E r;Fm0d +xerFФɳsԋ_ѓP݌8v,x EK*;]uY 1Zxe+s{N5~Ok{sɑL ,x '~=2 ͳ>o;>N.xe+mtH?7o_4mH& ,x4% =SʬH18*x NC;I@2͹sZ0xe+Hi<9{I{̷M*9[H&uAxe+yMe+=lH&= 0xe+ȱ9aSj7[ɑL _xxe+Ⱦ.;?b3S*?9I ^Rxe+cػ|-9­pYLRum+xE?BܔeSgX!PXxe+kƓO3U y}y?ɑL 7,x4XÕ-mH1 6-xe+jY+SdO*]ɛɑL hYxe+BZeg/0ɑL vxe+lGǟf~{Z-ɑL ]2xe+hws7G6Nwlɤ` _xe+9m"5{f$3ɑL ?Y-xe 4ġngxͅ*xe+ȣ. Ӳ)0!yIjSkH&w0,xeȔC{.];5pu5L~+x EXِC߂Y Yxe+^O?1P4uۜC#Kxe+H tvm3Z/ E#ܓ 2xe+|[:}r|r$Ќ 4_xe+2UlLKuJ]_xH&ǩ #-xeHtk }{<1]T!i +x /zTwkD~fv %.x JӟHN4Tl}:NxX.xeso. +9I ,xe ȅ=7; T(ql0ٸa*c# @-x !Lȹ;4:oؒ.x ֱn<1сHfi7\x ]^ l+ I7 xe1Fi"%+Mk}f9|٬ =7xe1FI VjURS;|T}-xe+HҬIG4r3JeMdR$ Yxe+߄}4~:,VfɑL vx E%eG`<=Y 4xe+Hɞ[bUwmՍɑL  Yaxe+#z5kǚI#:\xe+ CEf8lcZ }H&ۭ 2;xe+F&o'ݫppH& hx EǏHrG:@XY fkxe+z֕ [8Qi2̓# ?Dxe+ȧݛѐ|vϟ;#kqxe+H+\ ,/\cՓ#m5xe+S7V+r> t拋#Kxe+GC孬K3O6\P79I> Wxxe+f =T`}H& -x UԢgw%.x45\4fmyH1r-xe1F>Œ9\8|/:f-ٻ ,xe`٢wsܭu ~rFC&1+xe+oD^"g_+2er$: Wxe+:WWՓ.fYd>jr$ x E]2ɒy;Y k2xe+kDVd:R O&mɤ: _x Enڹ) |Y dxe+ȭ6yH:u+XuH& ;x Eק|H![Y sjxe+K7Kߞ[ ּ)d~H&[ 8xe+k{::XxRլ# {-xeG77sx69>'lU = +xe+ȑֹ>wUP`g #Wxe+ȳ?{8;Q:9I x E2LR%PY [2xe+HLh.zx霓#_xe+H5ۮ~BL/ >=ɑL d ' x EimHH^͓Y =A;xe+HDŽ>z&ZqPeɑL hx El/ʙE浿F4$>Y /xerFjuʞuw?p-?wn}Y',xeȇnl*~[8喝bЪ= V+xerF9}oOewy7gn}׾ Yx _fITHChɓ&0xe+Vgjx*Xw秢C#*\xe+PM:%޾5wyH&3 xe+a ~u5s~s|r$ 5xe+H  Lk~XuH&bxe+ȽΌ|c'KK:JWJ缩ɤ& xe+]NbR'x%<ɤ\ 2-ɤ۝ -xerF.-.._Rc2k'fԃ ,x4A˱rAH}H13-xe+Ȧ9꘮$gI+yxVxr$ %,xeJFS.Loɔ̍L +x A[5?ړ.x E򒛑^t+R ޕY n\xe+H*w2G?gW^~, ɑL ,x EN~ܪ3n:Y K/x4½(cgᱸ>H1-xe+Λ<,mK;9I0 Yxe+HxfX%x#_THH&+ xe+HLObΖw[H&2xe+Dݞs<9I f_xe+HJț[O'Z_r_傓#'N xe+k+w`fp7H&x 9xe+ȋ.ISXYXyr$ fxe+ q7ۚދn)+|H& xe+4ɞR=#6uۿ#K@xe+HBLUǭߎxwH&{Q-xe:H~5M=˖XOf ,x ZۓHCh*F.xe+2BbXgzzɑL V Zxe+%ֺ忷Z79xr$ׯ Vxe+eNlyn_;MdRH 7-x74,ke_SPA3Hsĭ[T3-C%-~mEx4yWMW}gWH1)-xeC*Q<Uoϱ&Hd{x (xe+4im`  7xrH&G Txe+K(Sm;W-]aLdR^ oxe+Vѭ2y{Yۧ.8`r$ -xe+/ o^ݴ1jU}a#D Zxe+ Xk3p{j~H& I-xe,FCOᝥKAk! *xe+//[4,8cr$ Vxe+Hdm%sNP:,3ur$N ,xebWeSgo7U{7FC&Z Wxe%K 2G=͗svϕL +xe+HT N}p˺#wXH&D Wxe+ȃS?>G}fɑL jxe+`KwǏR֤E=SM-}er$( 0xe+zu-Vsh49I` -]xe+K@@e ڮY>C+pr$Ղ f xe+{-:,j6o\_?.I/yr$i 7x EN}!{17ݚyY 1fx E:L-cSRuvՓY /xerF ~`3͸4y7>p,x E&hX' MsyY QEZxe+HMwYָJç# xe+su2m;-h~_rH&ܙ Z3xe+2;L}՝WLɑL `xe+HtPjnɑL % x ETڎZ%ůJ4ߓY #ó2xLc+xe+HfF-Y*HD}<9Iй Wx Eԗk5GՑY x Ežſsc UY 4xe+soP넧1bH& xe+ȿkϛt ?/_wH9H& 7xe+HQ_L*y%!:oH&p -xeH VӚ%{ϮcÐ . +x8\@ K@w*9ٳ,inei `LJIN ד;>uFx POȆcGeꓻ.xeGN6r.I3nFC& +x Eݴo⟕D/LEv:Y #g.xe*߅>ٱ.6KFC&Z +x =lJO6c}Ň3xes+lf9(XNӃ-x E'oT@XΓY m[xe+r߿as]s#%RU]ɤ͖ ^4xe+_έ㦔=#4gr$ Paxe+@#{*H*`wRLyr$ә xe+}]m/e-H& ;xe+?'ݞ0w%Z_:e5ɑL >hxe+^<#0,[ݿH&d xe+ЊeMuިɤԶ -x84+ܧuS4 БH߮ds2 Z[wE4sFxe1F^x/[]}>U3|,x74jqf;6 9gH )&)}bٞE*X~ÎExe+HWQWy$ͶPo)kYɑL qx E'!uiXY (.xesZ,kXf2V/ϼw# Yxes첏Wm}`eRY?6vCug+xe+IO-O0sfE/|'&9IɑL ^ Wx Eς֟?dZuW6aY ~xe+C~uY|uɑL `2xe+ȷiN3{Om7bĶ0# ._xe+柞y2[qoɑL  xe+ȋ{f)?Jl mc+ɑL }-xe zpn>T^'K:dFC& ]XxeHƊos-_)*pFC&+xe+%UWJoI/(ɤ ?Wxe+U}J|%eѺ!u;LdRM 2xe+e Os^,5ɑL Ԭ 0x EhEěԷe]ĎRrY ,n_xe+~WS?uWXtiH&BV xe+HPN7%9n>ɷɑL % 9xe+ui\fۊNofUkH&fxe+H+IG) mG|AɑL .xe+HIM͛=RwLx<^99I *-xe#;d_щ_y䏾BFC&ߛ G+xe+^ēJg*JDȟxpH&- F,xe_jW{PTj}3h!ה 0+x E`QaݠIY  Yxe+yB/V92ɤ͝ xe+s]n,9?"I G<19I٣ y2xe+ f&˯%Wͯ=1fH&  _xe+ͬ&&lX2#e = xe+.Tg:=OeY6})#q9xe+H9 ;9nDΖɑL o fx E\JTK >%҅Y xe+HVˉssҿ0K) H& L-x4"n%&T=H1-xe+.\VUr,x|摀kH&Ӥ nYxe+pb׺.|m Eݪ~o&G0)ʼ x E``K]ClY V3xe+'bV4ɑL U-xewᢾ׻K~^~ՋɧRL +x EFvy ړY tkYxe+HE׳Wg(49I xe+Bg[>WmH~<9I 2xe+O[|1 >zd|er$ -xeȏ%B;7=4eX&rS!W= g +xe+?T&$"Ts)rr#Wxe+.BfhYH& E,xeB3J /WQ_tL_+x E:මEj19fY Yxe+[KUWI*[>9I xe+uUU_5pR ֘ɤٙ 2xe+ΤI]ZdO_H&$ _x E]}JJz:PY xe+ȉKv-Z_bTj!H& ;x Ev ~ +Y,{Y jxe+%WXnHZ_zr$ xe+H%xrY̓#qDxe+ȗΩ"j6O+ÇY#?qxe+iMύ qn/ɑL 5x Ez\tH?EY Mx9OmLd~!JN^g&bqJY `HxeFYlwim[骅L)},xe~CMYmH^ڲÅLaf+x Eѿt*9/ю3u:Y .x42h|դ׌8H1.-xe+JT1KJșF3D|qr$+ -Yxe+x,˞i5+w9RhH&z ^xe+ȢŠf:!PCH& 2xFɱRM~.?7ܓY `xe+Hd瘫⮯kh[cׅɑL -x4De!H1-xe+Gg+ZjBMŬ"#,xeeƯe'e>]'q 0Dw$HFx35[[B?J( |IK--^lWp4/] x{q+% ~~U6y6 2x{q/ht}禿(_OZ5 [x{qFcDž?4tCnV~J 2b<TPTfȏ6j\x{q+% ~~U6y6 ox5#&Pҭpdq`I߄$x{qOg6 l‰ҷ+x{qBo ?%WX(dAZұ%*x{qlyBf{ǹpUY Qx{q{,j>yXM4 9xx{qwZL˶ }U;:; ,x{q/l;EKԼ&~xf!C ZGx35mqx1t#l]݅Im[t&K_aqnA̡I  x35*]-=Igiӵ LYBxhs"M?y"p^kx35l jy2sҋyIgeݪW::`ơAx{qB0i?ӽgοkή%kx{qBmL^}ݷsu{6LL Kx{qB4d? nRY.tbz-! @x{qBeuKR?}=x/7z?2khe+x{q9rkz Rx35x{Ԅl۹R?(V9WIq_8o}3kh  WAxٮ_WbE\72ӑo,x{q޵񗚇Y񘛩' Sx{qJ"}fVJHS zx{qZٴȗs,5ϋ_,( !x8,ȴw$n䜚WKxŝH/c?b 8ux{q}n'񶽛ǡda' x)# Lv"k. Gx{q;Jsh`}]MX([0u ox{q\G$Nnػ^ x{q񖢐YU΍6x o?x3rxq 0\ x3r~_,UPnh%rJrTXzPjzCvBxS;UUdG흑g}drnxS];aKPKg}?x{qBȱRF6Ƹ]rX$21> Ex{qBar[M\_1ڤpbz-Wpx{qB~ث9檉+pLJ/vbz-6 x{qBj3o2tדZˠ Fx{qBzӽvdr+R!Z qxSUC7@BA[g}8x{qB?5I):P>PZ0Ix{qBy֪By3'[*6wNL +x5O3$p WeɑIVsWx5p,Md^hIx{qHގ=K—gH^\ovF}D y.x5Wa!XI[x5esʻzGxIx{qHg &FFb!I{G' 0RJI]UXAx_fEA6)ӵ jx{q>TM#r[svmr v0% x{qws*T?ժw+ 9x{qĺ5EuM/ߝF ax{q3if'᛻wbDG  x{qS;*mg/ *#xʚ&2=YAMTы/05kvn{ ;x0$$'100644 Makefile.amqͩ р৉'O {x.$!'100644 Makefile.amQ 6_ϻ7.j[ˎ'=|Hht YDYT\d@,ϓz+h/)o  ,)zœWR  ɓ &sC\V“w'G|==*q?WnO[l!xWe~?)C8x%$$ d@,ϓz+h/)o ~9;4x۫WeC*5mm Wxq>|͕G-x۫WED71;5-3'U/1jSy#JJSз/i"\kfCYx5#"'100644 Makefile.am"jӨ W$ơ' ILj,lCx{Cq'Qll('YxD"!Z ,)zœWR7 { &sC\V“h>URxCqC}ךĩm'~\#|B&x9x%!!vHht YDYZ Ll@xMqͿ)flXx]qQǘ)dox]QD71;5-3'U/1!(CY^ 6Ks٨>i1&#>9lBxxRqk͒'`Xx5!!'100644 Makefile.amlBqV' 8[Cx;Qv f;V&r3lx(,{w53%2x(,[&($UϘY+x8\1Tv&iV5x!eNhe4-/xkmp[$!Ba.٧ەY%,&k-xkm+r=}BcMYe~\9W <Px+/,rƲOǖ0Wkq` rwxwwcE`U:m̸r x+/,r7i^vr )x˛%rh[bڗy띧 Px˛%r,{&[ R2Y7Ra wx˛%{E:<ڕM( x˛%hډWOÿ.Hغuэr Ex˛%R=v9l(_ 50m lx˛%+D۲9~_t& C"xə!ٿEL,]lJ,Kr Ixə!wlz'~+ gpxə!""z6㼒K;_I# xə!bhߧ+,ޱIʥE" >xə!ml2{^V-n| # x35\U2!3:TMˑI?AN'E|Ƙ;AOCx{qnW^y\޿~&w]> jx{qR;+} If*| >Srx }x3S9~ˬ OO:R$WFgidC"Tc5__8Bx{q msb| Μ\W >ix{qKwJxb1i} x35QicLm@|$h`I$Ct;KUJ4N7nBx{qWϹh~u|4ix}ekrήNȫ4x3S!o[+hKT_gi}ekrήNvTx3St#C]pBtL\RC qx3S,˽"i Zgi5yC6 iz_xx<UBx{q3R3I޸JOF)woix{q{yj)H)f3Yب x35LB"nZa@`ƤIJ‡_B% |x{qn⽪m%H>:! Cx{qLfj:>9u˾ kxVgn"R{ʺx{q9;4m_՘?AZ =x{q:;~{@=!Wwy ex{qEa2<5eїh  x{q ėKy6}sr !(x{qFrVU~bgS_hģ< *x5Yh.;k <ݑI̓ Vx5S|${!֌,ԺI*x54b_^D;O$wI/x35+6>fq0%AI/6QcgH'qx351cVuSCUvצtI/6QcgH'3x35|*FK[`6I/6QcgH'Bx{q՗;z1dMg=w$)7I Sx{q̹*S:f817Kw) rzx{q˧Z{ޡ䷵#E !x{qQgBmDOn Ix{q#O(]D.<;W qxl<̆Ax{q[LUSۿqvQ>e~ Cx{q>_]i%. kx{q.U[;7~[M x35cqm _ݒ67đI o%3BW^FXsPUx35`"5VxVZDAx65s|fLX(rqlIh0nV^x /&Tmg#B/x65ƨ&9q l6.UGIhYxُH`RJʒ4lb xOoƖ\|? 4x{qg‡tϥ~Y,-5*'= |]x{qק~2٧5ox35ߑ $掊F)˺,IncgNȁ63|R}Ix35:$[OyC˳I!?(̃i0twrk  x35kut~1#I8<ـ{7l3c :]Cx{qBHʢ/KJ\d6W&Z *x{q[?~OD"mŵ {Qx35ӹI7fkiR&ˬ=ھAx{qӕvH G~ˋq hxٯ5a}^# x3rqˁàkJٯ5a}^#@Bx{qBȎtk.]WH|=m.{kޝlx{qBƙ鶥fbz-M x{qBH~]o_gl.\Ztbz-VAxQ52D)dNhZ40000 tcsڸ,i+Bgi8zdWK߶Hc)`x{qH˫ֶK>.8 \9˶  x{q8x!othaKl=g +x{q#={~OCt2e Rx{q-FZ ߹oIy?* L'xə JuIf,x{qV/?ݱC{ CSx{q.b]^ %-'K( =zx35zHkgiqEPZaC-X\Ѣi@{}x3S+Xρ^UhŻÑgiqEPZaC-X\Ѣi\ZBx{qH˝3ZmNEŬvyR~dDܛlx{qԟm4̔SDʞAx5umutGҸ޳WITxə!R0=^x̔|Vyz/= {xə!ſK8}^n֕Tz E"xə!œZ1w>ٳ* D*n~| 0/x5hy0ěEBܑIO:.x{qBokz晃kn ls01" Xx{qBރvsm. ݸG޲Gvbz- x3SƏ}xRYl^Suޑgivs%~YU9-{lx{q+9J=s\%M x{q9Tcsӷmq8v ;x~_[&ďÕ" Lex{qoTEvXޮ) cx6ik<&Ї x{qn38Nl|4I( n5x{q\>tv& 0 +2 T]x{q NRzoʥW,-, ]x35wC5'Q' ڲ/Ih XB.bwyuqwI)Bxzr]5ף ʵ!kx{q}cw32͟-0 x{q@hژG^~vCS 6:x{q7|2kgZZ)F: bx{qӮL|h;7qg  x7c,UΨ]jE 4x{qg"e+sآKl @\x{qMK{|nlwFWn4 x{q5W'LH7ȿwȿj 6,x3S^E嚶Q)7`l"AgiiH|g5XoEnOzfnx3S| ;k\n;^YSgiiH|g5XoEnOzPzBx{qHG4jOG/9 *x3Sdzŧr@~3%E°gi/ 䴳+@@RD@q$(zAx{qF+߯FsT l\eģP Qx˛%rJܤlfE9k&e\e xx˛%yϭ~kZpq x˛%b1C|]\7 ;ddU  Fx˛%>Ҥ+76uӷ<L mx˛%:-J.T x˛%1Nf][S&DmҊ ;x˛%r'wSgjJ3C -bx˛%5CB<(6Z\(}  x˛%s#%XrOT ~ 0x˛%]xؑ#7W]g?o Vx˛%"vlNCf{< }x˛%Tf sX  g$x˛%w9V|Vb_ VxScڮy\n藵dg},.x{q] yT.70 .O<% fUx{qkI~6Z=[1mR |x35ٝݦNnIjWǘf X#nxAx{qu6-YO?Qa1g!y k'x u-5|&,x{q +t,-$Q&bw]R Sx{q]?}~Ku<4ExrM 7zx+8s1 M6 K#xAͤgF35SMx{qm<:wx:E2cxux{qƴ/귺^IT7~};ox3S-j@bqX0cgif'ڊ{{Bx{qG `Dˣ Vi Gix{q6 nyH%wk'Nr x{qSs3ewwqs 8x{q=-sn_lk; t`x{qW/)$'Ȩ3i.Ϟ wxRg/޶P-"x{qEK^qUCl Qx{qFM5jLE 5ߚ{cQy? e*x ,[i~)SxaɈvnfˉg@|xZ氛GOhp萉/h%xX?Myωj誹͐܃8Ox{qO̟۝y2,v wx鴉ͥ%TY)!xp->H֑&uKx{q2V5_`px3 sx{q!;[=o kB:' x3S:؇ RRڑ-fgi';@`cBx{q8QbR\S*&d;ET ix35j:VbY%Inw^ZQ xkRX.*xə!FqEJ,^pD Qxə!R7Âȶ5  %xxə!Bˬɵy{F\Z+ xə!R>+%~nn6qz Fxə!}O_d_=_aN8H \}x{q)Nߪ;Z@H} &xa^N(w#5Qx{qߖ?TGVD;r3>Vk zxhC]QC~oa#Nx#Tq8@vyx{qgl~wfù> *"x{qƵ+,S'M Kx{q{+99u$N tx{qL]/,@FakK x{qu =ssfMwqxԩH Fx{qEWY6* =to7c; pox35*fW(:LnR N*ڑIUrGwrV-b2x35< {tEc+l)QxIUrGwrV-(ux35Gw ֝iiLqIŋm"7}<)n,8x354"iK7_'ՑI)KE`ذ]K35{x359q{F{SDIzBկNvgIA xq*' ȟ%콥au6xa4M27aA?}g`x%\ 4gQR$  x{qGU1N{#VmJTʝ39 v2xr0 Tug U\x{qsl_{P=njGmI_N Ax{qov:"Wfyl - ix["Db(:ƒT`x{qpl2 И!g5 *;x{qφ┟i.)>~ & ccxb?!C x{qnݾ7%PLa%m J"x{qEE;g|0[ܫ x{qI\ZbfO:Y;ǃ Ax{qw}/+-eVұFDmL9 ix{q{7uźLSt oUj x{qMs_]Yֺ/sJkvx{qSVB =sew^,h x{q5\q?vNy FxH͒~K)ZSpx i lߺt@x{q5%CW7i,n Bx ;͇o:nlx{qY :n[M x{qS.}[Zqi8gv,* z=+|KkpwXS 4x89F2 ^x{qmVumdS,[ƚ4kZGX x35tYBh I<|hF$fLDqRgHxQ52Ih^, M_M*g40000 tcs} 22nk6gi1C7:D{0}$"x{qBHW˹/=qr96;vZ5 +x35dRG Z <[Iځ1!.hޘ& DLx3SKyEzU$yۑgiv˽2q@Cl2Bx{q}k{WԷ/8`V_ ix{qI;\9lmݧ9 'x{qF mU{EV4]8cģ *Qx{qF[\_~վ!BW&ɇY`Qy I*x{qBȥV]A}fhu\4sbz-o *x{qH靽'W9D.V+X5s6ϼ *x{qBHǿ7L})@[BJ!ibz-*x{qHIkL8lD**x{q啬/λQF= T  Qx{qhg,P5+0P( xx{q[ + :+ﻗS jxə!{uE1/:/Ӧ5U bTx0'100644 Makefile.amngEô'y F>@x[ K|C LE'bQ|ȣ{k7mME=ܾɛCXl3\x(>Q|.~n~TXjk!,--x(>Q|)F/s< 3o?~͞Lc Zx(>Q|)ȞXfsʺؕ%iJrM~fO&N -x!O"ҶDZp *!v p/xwUR{׌~iT0 \-x(>Q| HNZ󻽯_<.}f Hf -x(>Q|(KM;1X_HRk&[+5 _-x(>Q|C >?~M>@ϛ 9 -x(>Q|)㒌vK&GW,}E͞LͶ Zx!5!v5TOsɳIH /x(>Q\D71;5-3'U/1Az!?Ű@hӳЍYQ|fcQbN=U%KTG,, -x(>Q|*JE1--=9Ŗ| uxə!/3JnKT2;Y{l.~ gxə!rHZiĂzynj>?u Cxə!r\̾l_Q Yv Nx{q<ƭW8X/s4\=xBa wx35{9 ,~@f*ߟI&n@l;Cy1brNJ|-CxS9PVs@l]g},,x{qum/k8[`&_۹䭳es'x1ξP5NϚC'b,x{q gmx x{q|g+\|x]j᫩b|Zy 9xN3~´a櫢Ѽcx{qs_=Utv=!ݧs  x5\îd09zҰLm!x{qJ7 6eڪxQ{QzD u3x{qȕf?ԀNJGll l^x5kܤ߲GI| x{qHpZE)-{4h{뉞6x{q_' ܸ:J>6M L axR5[{ƛMs~7=Ih3 AYpL> 7$H40000 tspi<ȁu`o$$ax35|uPOoG}TڑI:0Wi.%DJ_z9O+xə!`Oͽ?f=7v?:$ >xZ_sF>%Mv҇˶Ƚ9q YbBٚÌiOlcqÑs8AWENS9ވ$.及hY(hp(笈9q-8~HgtAp4D=@{5@W/M =Yݒ/:ℶoE[d to5YkչN(%^3Bf9c;j4{c漐T2xE9SeA风-P L~bj`#C @\ ,/S6/Q9i \Gz,uVF| %-h-0|w4kR&كM7pJ (? K4#:g 'Д:e(}9zX`U1v^hUoe-0WDgn StjӤᙦ5],?Lmc B!a2*!i)Q[1/@ E |tj{׋Yӥ.6BɉitW0QEW$Ș/rM+ٱneޢZj(o'^} )c0S񽢪3ۺJ\63͆ɤPZ~,Љ{̜eszK YB?I7 1ўʶ^6R>d`5·o~՗3>o=#nPȡ~P86F-+w*:kXk=J 6 Zv53zj?71+[T}Anuipԍ `1P:*u(Qhp؊ V%SiȻŏ h Nm&️ sd}nE[3o^¸1\ zPa'Zҹ=6~@h-7*ehiYTi:A>$.^`嶨,r ֢ű~e^&~,;OU@FyV4ʼnU( W%RIäUBbkv 8RNz j6۫^&-~yƔ.e;Dz5Cϣ;z_x!50p%篍rIH Ex(>Q|)HҨ&`WaB&9=<8 /x!kwn0bވ(׼Cͳv$^x(~XlBq\be'5~]O;f&& IYy%%z 6v[bʨajWFo|ERT|}gDapq܃&^u~aVlL?癫ڡ9#8:o]l)͸?~pIU^P?~T#Hj 6NhQqʱcEWs2+ YN|\ ՘{i QJ72X{ uwGlC_noچd@IA.PwaOMf͈9?yE&6\\u͞L~0˥%$kS'9c~4!T4]t2 KO Lס? Ng919U}E"[=V#ar&Klt'糪oz[o"x;5giv ixIdn#,UDh6j$/aY` Ix%6KlAs;#d #U]6jEuߺRq;4=&஽B~RV|^^2?~T#,=n#K6!/7mC\R ԝ}Xvf3~EOr=f>&N:(C!x9 6.dBWzMɲY c̓% <.Fm4Mae1֎u Hx;5OBmAܙ׳I/L~ZzG]([@mW"Ix%6KlC+i-KUqr|bv VnU~퀋珋occ!^(l(o"'`YMܺjwW.*2SoC3Ҕd'\. 3Y]Rf^ P9g-|sD]7! Ăb1 bGе)ha\Z5Rip/qoz%0ُML^3 oIa*+r^i0I7|b֨v˵5 OILFۛ{'/=M}ӝ'˳'$-e:rk*n)=_zY{FbqP?񮉇$DZl>۰eQˑeVU=01w9 v+Y?]VZy]aԒV|CRDmZ^IMΩ}c?ā;lf?Xqǡqo&ksJܺ?QS鿎{ϝiU2L׀Cvbai~I*Б3[U|TǓ:ǛfM(1/%skdH])憾k SsN;lb]iztDo˓1HU_ҥ{O2T-my$f&tw&q@VV T˾WL;"2P^\_Jَ;w' בPo,ugaNj;x;,zXtF#}=O%iLj~;-WٷML9-x!ސ+D“A&[ l/x;,zXtCHVf5&Gsy.'ܞ R-x;,zXtȫsܲ.^;ʔf9xZxs2 4.9J^MlԹ640000 rpcbQ8oVVwNdHUb< 2Y&})ǽq}N  M-x!nNY}3M*0x;,zXtmo85IG?zYi)Ц ]x;,zXt 4 jpqtrLK9 )Ox;,zXt'+4)Y`I֍,x! N 歮z͎"-x/x;,zXtCz~8\ޭc-Rci d-x;,zXTD71;5-3'U/1}۳>M;rEcs}\G0lWJы#K 2JR+J.}q=V}j+R[̑|-_Åk̹k;" ԝ=kmY;NԒt;ir{W2+޶|3q3 uf%d l.A3!+*P ceOgӍW7k8er$ȹS߿p{eS9|Cd." Ul _a#:sgnntbx;,zXtjFs g,v~95V"cf9Z |Ax;,zXt% m̿Mە^f9d l.x;,:GtC^3&(*Dx;,:GtB zzqDT̉V"֤ݘZśaٛ}Y5'^ɐs8uttrBUD8N~XYl:GvduxتMRn؊emM1wBIqA|bqe^2=ڎkڙR[pHo+LV;TܨJғs''x,]wav}i%Y'c?ZrV#g+6}L}d9ļҒ !V nٻw&jJR+JsSAۼޏ%DYzs {Xuvzf7W>#};y59N,.iT`˟5YŬ7[R>Yy !1"Dx Y\ Ҙ/xB뺽^^2~w/L Y(\.<.;=?5Sv饇Hj KKR4l?z杔%[V;"+NM*yDCK&)Lei?~`-!&P2f V=ͽfLzpx#:GtH6}w֣8l8(.xR L,T4 J? 8 [xR'100644 Makefile.amӔ(psòO'R L,T4 J?^H+zJ/y't\_F\*Cfa2~:IӢ}5Pw )z )P:l;x#Md'-#Rx5'100644 Makefile.am/̾=(=S'Dx&MdC$H^MVYk4_b9v -x&Md&bۇ/67GvS zxə!RzNu٭|0l5 F0x{sBHy馞Xv=)Ӳ`cn) $-x{sC4ȝ)\A %w])*#laB|b&Q l-x{Ĺsf# LCx$ 4ڣ'[HM&dq- H2;*2x* !100644 rpc.cw7lt5!L;jxD !100644 rpc.cQ&`MT=f!mP5U9xc 1RB~vRx! }L"9U6 '!/xsBȫCoz's*.)k\o̴ Dl+x9s0fKzFAx9SD Y/A{a|Z+ʺ .gߨi%s=#r5xНϯAtM>tfL"`x35tKD|1wؿˑIНϯAtM>tfLsZ#xQ523dNoӼ"40000 tcs3&>txdz֯gi¯A~Iv5a'xQ52_ap 4k40000 tcs;v7V*DgiW훔 >PQ_EǦP#<x{qDjIvezHcbc4jx{qB]>J'+ V xYfD؞! S V)SYDj)x{qQ9܋ZB0k] P(I.f02e۫"(5}33Eoe~V_9zZ`!x{q{ѲYWrOlxN 0x3S[b R2W,\gi[x%poGa8q߹=srx3S^^ݜ%& bnsgi[x%poGa8q߹cBx{q=W._/AdGD 31x{qZ]^o葤W?f Yx3S+Ml?~4QWgi}'>QHb.|Jx3SFϿ\ҭ/eW*eUgi}'>QHb.|JQ9Bx5yw#"c!I O݂`{A ̶Z21-}Hpgr%3vpbش?Ś?C|&o_8@*Hx;~}use6g=Hxə!`i# %U'M ax{qBHjm[[5>LH91  x{qBȌf;TWI08ۻnu}kݫ9xSgݐ/f)0̑g}gx{qBv5EVjWby2?HϜx{qwՏmQjmkK܅&jb % k[,;u-?c^ UZ]x{q}5 |2 wnU/o~Jvg_'.ET#&gȘMc'sxr^Bޞmz_!;ǮZs=ԞOLqW*oMROXܟk-S@x{qHgg|򒒆ZoYC&zW jx65CB`a1*{TIh9YR?%.CaLDx{qBȤ%3Z&fƒkgnx3Sз@j$L ϕ/gi\=(>e9m՞2n"Oas7Ax:'/7SBc^ `)x65lU62-2jSIhuɑOx$ƳDxܔExL{]vNC2mx3S.:W~)N :&"6ZQgiܔExL{]vNU.x3SìTY2˒|$OK3giܔExL{]vNɩ>px3S?s>?i \P.giܔExL{]vNpBx{qpV2 ό9'1il /)x{qc= ´~I xOr2U(E}[4d240000 rpc;sqѲIW?'NQdVّa őbt8)n/APe_o~ (<Һn;4r07J oA100644 tcs_utils.c`cR6&4c-ߡ4D>Ma4@x*pU`nzq+eYcjM~rMC3ld1g\5+?F<U)%@uWL<(\Ń _su&k+*K}lŨ7xכN/@VTKVOoZh*铳Y (OjRtlh7m'dU`;Qb>.;+ʌļT "dsaMĄ /'GQWZQ7YU~&3YM=޵d)@#/=s斦,(2&%(lv(*30NEdUHHLqϮR}/_fLjes̡xoV,tuOY{nbf(z, v)sr~;'I >ܸWF~ Ciu+PVzXA /CaAuUol[EYyPoߒ_fb^YDYO*de Ö\:&gť'7a0H{;]֔L39]Ttsbr #\2\Nv;N k}ݔ/.Ln0Wd-+Lv>%%EyEsg;35ԯT+i\Dx*pU`%&)f>lLr}|gLQ.x!"(!Co6/x;~@?U~>NU |b+l 9a@Cu/8,+Ix*pU`fa;k/ɤ|Ygm,`ux8s2 i(>#Ooe|z]ҬB Fx*pU`%&9,Z{Mv޶6>.TĆeOwޟ]qcdmJ-@#tǝº}/`  ' V0 Bų L&$ _x*pU`0׍_cļ /oꚕi:-xKK"[ŀ7 *Ȑ  Zxph\޵ʙ<#_-x*pU` HTkcEyWojܯ9k,#ش p-x!LɛV-7O#,j& K j/x9 D %hjiڱo٢y Ƃntk'.8?lGx*N`ZW$W]x*N@D71;5-3'U/1!:-yY;Xk-<$z+lAx['N`za'8p/{ȲxYd kx?B#_aKDZcx['N`2%—[/9]%] SDxA"%x&*0xə!2eqF :zB/a kx{qgr'R ;2x{qy꥽K?xƮ# =x{qMg_Z+bAWw afx3SK{xoogii$n.9NCx{ql\YզŽZ;k^4s6' *x{qU~kTݖhyeb7 Qxil5>HMExzx{qkZBi ccO9Q !x{q{懩ΖoRXKrP Ix{qœ?vHo]i9]2 qx{qɥ&]\8t x3S\tl_PW~pgl giΑxTR߭g[fk [x3SӠ@HZt^5 Ngiʀ/X4亣$/ LZ>x2Se:f0d^fjʀ/X4亣$/ LZd=^x3S[jO#6DAECgiʀ/X4亣$/ LZ]^Bx{qBK\GQc;t:?s6 lx5 9ˍ fm8IQ xə!Vk_Vz@5r Exə!uB҇ VZ'ڙA xX[oH~_qY H[i+"4 DT[Ee۰m{vQ)fLY+C !#cٜvU$ 'pqC:AC?b$mGC`?_퐀m>atEH3lN}v4b#fg&C0hVm,_Rq1#.5f'K!bmkOcYdhlkE@VGeu)y`9"྾SP.MuwX WN('I8~dY^j'"S*@~/.o^C"7&[.|׈O? L^8),KÎiuC㯡u޾|5`1\J4za; [w uն~4:CNXI!aJ%:J)8>|u@ 9U2$< = ޺j=ch Juҙ>6ibTHq!1Ռ>u*خ:F'AJ>#&I@eS{RIDB0ݵ?"/NU8G.W-y$S{>Deb?/c,Rןa臕cMAB>CIӠs5.mc{^7 ƧuS8M0FG ,Y8:Zarjkd%Pɫ+(җ@(4o{,a&/ۥ|m5'GzNOfP՟Ā. Tl\ 5a M@7֡*r$)J>-mCp}8ӂ갶rJi.ϫ1o&dQtYeB+1\*ju%ئ :Goڊ[?qY)eOR3OM$qnWX-rdRFdB5wEiiLszoL'r/B$"6CH{I!*`o˻jEgF_vOt/U b^ RԦufHd3{~<3+gͤF48:L\Tœ -s|B|[)8AѹJOq$¬6III1d@A9*\@]uh%2;{{ (ٱZF7N"Vn~'@a|P/l7$xazhJF&c&sLC&_tYyJPqJF||zjIHqs~^IjEFF@rs~nA~qfI<;2']XRRTZp;F&p6x;h=-[Q~iqjwi&_b|JNb,ͤʛϥ\Փ0ٳiLdvմLS( H. K)MIK/PPUqpp4743p q,J-)-S 6 *_\T_Z_2T##`r/E: EI0!!'72skM. ?CUV/-AbVNIGsB[^dMN`W\ͧ=y9j̼ U oq >x;hHC~AN~^rf^rNiJR~R@Iq~IQ~iqjQ:KM لUyr 8gHpp_kDBIqs~^Ij9344b% x4lmB}|'g(o,(˸9{%#Bf5^a&&}ɖ&˲pn-RT\YBJ^YBXxõAKS_K!3OAKFQMN@~i P33MA`f#.Fn4XdV{Xfx[?OC#Gq|rQeAIdFɎ< 3a \) ql2x?[C\FC1Hxr8 j*L۹tT0(1lXɼPȱ&\۲pt7#颯]h6$#6 shg5a.4k4<zFeiD{ {ȈpV皑?}]暕$i6*2,%0r0ޔL>E3Á"/2P?XNLz=?m\mll.i#mr}M }+oQgHƽp5伿8`b{٨w,×">:[m< @?d31QF< ӅH^D9g>U)Bf}cw@x?#w ޯpLԠTvGxxB@14L> KyU2{әmn@{ =vF{ˆ3ѓk#UpzV}wuVaXdq&4[*yܨxSf|>? N"/%r#a$b)ҜtIIwPI4ANo݉u) Y0fɈvJ p MPM-QI"n)RZԉ EZ-$O]v4ztxJ ơDD^)̯Ỉ`bIKHqV05tI JIE՟*,,]|t@Bk22( /Lt$"a&sP,>"_e+b u*+55|sd@A/p9'HV%d$WOl{Pݠˤ?9(Hvy_U d5x iDPcā;Րbq)1CaWRe#0F #jO0J<(lޭ5^ !7Ѐͼj}2#͏edE>H!e_ ;J6e! YЪ[x#E4O"u9ȆU(,h6`}I^[+Y+&Ny)E>I{Os)&9 Йc4a% o$ :wl 7mJJ~>iր:6+ϬxluZY,5:&2듳ŕ;Jh?tԄhÆ <WN?m s3yE.q N5ÙN˫ޝӓ6y}?-}bkyB~{T*;e2M@|0Tw _[[m-_j( 7-+H8s uŅ2qo80ku\ u)SE{q3ECg`siGS?7?:]۾zhz4]ԫl! _ dgR!Qm՟ƅ]օƒWzCUb ql-mk)o.ۋvj/zL==X!O֙ [UM$+b7[9pydwٸN\Tq|ԣޯ$4?Rom`hӌ4*xcOx؃ رZ<13V2lIL#f8>5W]0WotTl8SpnNa݅3I_nDbX~90) 3k_]j4 8(3*b;|Gh;̆4?ێnm~;շa#y:~ZV;u,,\.^o+Gask;a=r-ƈ= Zbf.٦>>J,4FS {/$6EZͅVg»Q@E@<',l=$;=Ө֫=;K'HIeUE!&P.i>zA>`c&]Dr>/0x~SR2RB|]=\99Cչx +DAQQ V,TljPO+b!Af88")FъY0(%3/1XAKK93M`vBlʩy)iJL'ŽjfVdGE;ea*@\uHo咑%OMP| jpxrq6լ[B KJRSSRS J22KJK2s2K*7I0l(69B)o Qx2q6լmR#9lnxy6լd#Ux{onc5}ʂԔ4x??gWNN0;'"`=Ke'vxə!T#/yBɞz# xə!rC?ieg*/;F TWx3Sʍ Q,YCdˇ>ܑgiF|N>&^;SǺ1xQ52TʚH[Mkx+40000 tcs,yšQ74Y\vgiϩK;J= ݈,#{xQ52%[[A5Բi04П40000 tcsq$׶^}2xUʑgi@WJr:9JL($\xQ52 ,BC@hVc40000 tcs5ߣeюgi(L.QC,g);+͌&>=xQ52l%iD8<3в40000 tcs2Ы^dkmmgiQX )M\)mGx{q%_UEO6{|oD Erx{qH]s_*G==Chl x35O>"S0ENI"Ѡ;LQ3)U97J>(x35̅M#:60FI@WJr:9JL(k&^x35tmPg0i$\I@WJr:9JL(8 x35T3sMY`76̑I@WJr:9JL(`x3S'HJwi^ɟZgi8Tv˒}ĿQ+Bx{q?-OVfZ,W R(x65>YOР[AZDIhDHÕKf}f |Ex{qBi RoE윘^  ox3Su7:Su)әgi񵓜N1{yW'bJ~kx񵓜N1{yW'bJɐ`jx{qP[NKm|9t哞̙ Hx{qoON)ݳ0Qx O9x{q Nt)ɟgs` }ax@&Wr)g6+ x{q'$mR٫瓟 3x{q:??ze}48*-Sdf`n [x{qH˿:7ѱFX_v x{qFc+ }l] +x{q:͏ w;VVG `Sx{qn7CKTDMYs}OYìoxH{x{q5g6t??w"tIdy_ #x{q )\+84 mKx{q'v]Vmf]6-Jo{|* sx{qV7lnǕpz: x{q0f5=y,J^|ze' kCx{q͋_w7ޚӞ1nVù) kx{qeE'}:gux3SG> =NBĪ̶9Ou4gi;Obls^ Ux3So0ݦi$ΠٺB'gi;Obls=x3S1#?,:{W;䚚׳Zgi;OblsƅfYx3SJ5WFjґgi;OblsƓ Ex3Sk||h]KRXgi;Oblsƾ]x3S7bxǚ/z:xl]lgi;OblsƂx3SC7ݣ! 0:gi;OblsZax3S a>Z a>(3gi;OblsS#x3STJOنJ"z}Dˢgi;Oblsrex3S~f3!(E+gi;Obls|'x3SҫcOD+U8 ?Jgi;OblsR:ix3SUWyBޛDlHgi;OblsƃO]Bx5$/fa7IҸnx5rmA(dIx{qmZn{mrjM% Ex{qڣr//y8px{qHv>_zY1zJ}էtx5}i,D2sI*DHx5{I'#O֙-0U雑I&ux{qIO6?UrsjIoGDϺ  x5{SP)Km2I'Mx{q޽K)gWql4 xx{q]N i-ftZT9C N#x{qȹ}Efε[Q,ԺzgF$Nx65Πr>sIOIh%a:{2Vqj9KVe/x65Πr>sIOIhݬѫ-&tQ4V]Xx65Πr>sIOIhŇq(y߃TM<x65Πr>sIOIhߩ$?[ ۦMbx65Πr>sIOIh n0 K F׳9Ex{qJ.,q+Uw1I_\?% TlxQ52{-)1lT즲;40000 tcsRty;7WՈgijcqAnBDq,,[&KxQ52D SG^ 40000 tcs!iB~\#ʾewgijcqAnBDq,%<+xQ52Lk$QI40000 tcsj}9}ScgiY'#,+`žA) x{qѻorlM#y($3^j}Å絷OԵ)<")45ߩ-k"~x{qBHee[;_N.rbz-ix5"˼_cO> rґI֪$-x{q[)S|}5SG[f`VNTxU6Ռ|[ʽX}x۩6ؓA&x3Sk=_VO.!2gi) Yx)5%>Z8"Bx{qHrMeOݽ3--Љf lx35QKiEd'B,ÛIȀ{Y6A@1TD\xSnlbXu 5Xg} x{qBȉU rUy4>88{k 4xSgʗ^,ƀd61wg}-x5lIͣ{TyGgIYx359 plfY Qi-In#$ \7G?ʰװ7D~1Bx35?ST9L_aNIn#$ \7G?ʰװ7D~1/x{q^Ubw?r?ʏl Wx{qI-=V 3^r 7 Jx{q ^(xKXrECڡCf8,x3Sy(IO$Qypgi/xFxaR{mx3SAaj 8n gi/xFxaRp=Ax35hVzIDD/ :CAx{qB<ݻ ҷsS."NubzY׆2тB)>:"x3S Ggʞ{؋n[gi3} tJW8ABx3SզeC$2B*A#ݑgi)V5`V@zV$1sCx{q6%.n-^W8qb jkxt;1񺧠R[kDZ~Կx{qJTK5Y.qᄉÖ _?x{qbץ-.>5s6 +x{q=9jk,3/É Rx{q]Fme[n[y`-BPlԈ½Zn*nʜ0d<+ylC3ДkF 3Uهϡ2]T6$`?=42)=^ӸE뭳0P#U*wjn}5wGP,`d$'l3MYgzA%jH_ Ze{=ռ);#)p>Vů(+SfXm džgze}h,YsؠnMw15&lc`능xzYK{IhJa4mQbK].0J]/xkh"_ hϐ&JXYOX|jX0a -xkhY݋]T+Ѱ{fԱgWfA-x!oPQL߾iA7"\x;.q} j%˳,Q_%ByoPQL߾iA7XIx0'100644 Makefile.am]įDۀ ݀1'g>xkh0A+Vm!]7%pB%Iix$lHkG 6.bx$ C#ؒM*Q)PjIx=kdܷz_0i)lG]+\#Z1ݭ sxLx9- 9~LH-' , >hihoݳؠGxʿ4f3b)=for;$slU,X t-xʿ͆XAl ˨5q ; lXxM'100644 Makefile.amg{PՏg.'i7 ][mvY?YL~L񽱤_VD!,[x9cj a2ŕK :cxڑgw~ҷl; Gx?CH6ʧRYU9I B-x?C4H^9g<ؓaJl3,-x?f&Džrr63/"cqL a-x?_D71;5-3'U/1qDK1t?vʹQ=r{'đ;xէd<VBN#Gx8D|nOXDo^~GYd45ⓧ'< Fx7oC'1k4.-^_JL,Y)7y.[%G ,x!E--]ԑ1?Y6/x7o!HUȥ;OcR?hfW,  -x7olV;!xsu֓׳JXm-$G1;i$^o.?eh``fbP\_;}u>~Vcpt2#[Xo&:sퟸ_tr MEHӱ(<ḍ/|R=Td ,aa Q/iΗL70=x!sD~jfgDl쳳0x!MZݝ'b\+za :/x:fL!I}\¬#)jԓ5/ƘN:kHx!LГLYty„ΩֳH xC !100644 rpc.cE%Q3fpFnƐ~PGCB!m ]&f%w.mǿ5Sx9SD Y/a`脲Lgtl\XQ(j6xcBƅJxCD Y/^eOնhpʥMTܸ#3T_9x{cC1ڰޙ_mXL_,}  g-x{qc >xB!100644 rpc.cd ^3_{e$^!85=gR= QmLmxB!100644 rpc.c{8ƚ\j0 *z!8AX3vA4bÌ,/m`Qx/!100644 rpc.c{ϝQV/^hfb ՙe nzx9s]fIQM/f4gh5n*X6#B j.xcBƅBxCD Y/!yuks8֬d7nbƅr9x{cC1<>T9lra ODg-x{qc >xYШTdÄYͱmVkx{qcBH 59UDS{cefծ l+x;1cqͯB"Ax;1cB'C\\c6F1m~ g0x}7f dKlAxq}$ͻ _hWxq]D Y/AiU܄g{-ѓ ]QqnFk&d;x /a{{+^m'% )ix9/a{{+^m'% @M:;Y\dГ CGx;~}.H)l|E.9Jx*~z^ fxə!ߗCίxpMo  xə!0KwNWŰ_Ûvu M4xə!݂ɲă?Vk a_x˛%rPlҊ|Qn~0C6%5ʯ;OuKg_ٺ-,?꣢{'8B֝^X4Q'|ɕ]ӫ8Mn ڼ2ÙgG|;ɤzrQ{3Z$9|橪!(}L۠LD ]]&qԟ{w[3d[9 9PlrqjNZIjq x+[Nm:(gÞ[.0FQrdAQgV[3<LYYIf2( {6dYu+{9ɿ9u-$+Jx[.\dC+[~I.{\3<@ 9.x!#"^ ԴW2!  !/x!W< Ww1v͐k/x[.\d` oB"YVlHzwf9vNfV @-x[.\dQVi,e\"[Sj4}|Տ -xlh#X\CUlsG_WGL YU2 RL:,xD֜SzF-^uaB100644 tspi_aik.c3=-}m@K9:-_b}PU=!x!X_jׄ%u/,y i0x!}fp-K4 /x[.\d!Hz޶pw-}UͮL-x8E`X0z\ԙBMSx`$__IiFx[.\DD71;5-3'U/1!ڸtN41I v=_ds>l;x[.(!is9v7Qx[.(IĨ>/}^-0X5Gnd9&L M&x[.(Imjwnp[+F0Yxs9v 4x[.(IifwqLO9d9&L)fx* `܏lAmF-M˓3wS9x[%Jx_vk[gYʽ,O2m>͂3d v-x[%Jxȯ7Zfo,V5>ᰥf9v? ;Zx[%JxHq0c7; 8Mf9v #-x!f"Yd[ Ao\x!㠽N؎)UF3?&/x*/S*htvOã .\ ld gxAsU*k7; !YבS2Dd2@B{s`;픱c#UisFsmm^] xMKqa7ߏG (V7w:#s>]4$` Hsr Wm}8MLx{(PHD71;5-3'U/1aj72_\(!+s'T=x!b0XAɅ^)g>/x{(PHD71;5-3'U/1REDL DgN/ZQ݊tlx{)Rp3FϬ̔=瘤^Ro/lZ]kx!_2ͤ7Ң0JS  x!+6*i0ݮc Jx!JKH˥f廆O)g?{'m70x!4w;܃9*/x93)gM{ۼȱlVG<80рHamR rGx{)Rp&$OʜkD`L?Y0-x{)RPD71;5-3'U/1^E;U"&Py!yV#'k1O*YMqs;{# q2x!0Kܗb%Q{ɳ A/x#Gpn#{uio -x#Gp_auJM7̜VJLV,a#”6'ǡAj[R?;QvYA'Ex;GQc:8>_!mf%,P;[.x;GQc:8>_!OpNP/7 rˀ賤b!Jx#Gp7ɉ=˦i.YӰ4뇸əs wx;kFp%k'1а~~jO&Gɑv(LlJ4̳%Ix!]%_V?pcY 1/xykTgj0G+#ow\u|.q/wooNqVZX95iDXv}Bビ@j|$R4[C=%fi|=x#GpHݛk깢o}YGkBx;6uمk* [0CJf1{Dam'6 .""MZJx#GpD6t6qz(\8bAWlL s-x#GpCȱ4TN>{Xia~,F%v -x!m"%NȜ]xə!i˼;KVz]\( >xʚ&rJ$`q,[̾{m ;;xə!Qyd.5Xf Bx ? UE`R1GE{100644 rpc_tcstp_tsp.hY6F{;$3%HiԂY!k[ ڰR.3`~>aeĊ9CxϳgC8ȷV c>5]ޜr =xS g؎˺qj{lmTi[| +xϳgOFh955vO:>.}jef&& E%%%z KE $4՜R-'0;9sǏ>IJs-Y6qr5+ݗ[/}<&ӄMf1v;b^}{'T?^hcJ|yQ"Flu|*YK*#͢TKIx! IrGpQxno.ŻX] 5yxx 6as_j,nnR\.Jcfb$mM-S pB,ߓ9o,hσ100644 obj_tpm.hΜ|'dƧM6-vCYtfIԕ??ySBGkcR8cfxwdfgNq;>X|ӷ~cs5&kEA/xϳg6ALuƒe]%Ҫ Xx4 ] {{H ϋA]ei0`iO36En*{CxϳgRN[o]ܔT͓zuﺍX+N+xϳgOFUNvjkXUhYsf^&#, Xx: _>XEkAWl6=7syB>&6;x*ϖI| 2fHx! ̤`=;"y"/툳~_P/xϳg'쾽_^sې-ٗͱL\xe IK/Fo`x]?@0 ^raf100644 rpc_tcstp_tsp.hL.[ !6 ~%<$*sx! gĩd~{mͥtaI{!7/x! A#XvBˌie/xq 5;,)I-+t# 100644 obj.hu*0;v*w=oJIr> 5Ɣ^.|*sF唳B5u=t.} 3@t [Ž{ D*;x! 0j{z>D90x! W)G wj.Y񲮎k6 /xϳg/ȷ+|z+'2Xܪrt^Ɋlrڤ ,xϳgC%IS%Wn..^M-x: ͓.%internal_types.hNI`k J|HkHx{l-Rc]x{(3։~&Zx˛%nwA{jEOg]5/ x˛%;O[)!U|ѽ^ (x˛%b5EzI3{N lExə!";d-X$vk rlxə!|!)w>z7,s7_1 xə!<]-?Iplt$M>gC22(/xQ52Ϸ.Hyi;X40000 tcs[S0DZWޑgiCƪ{ =[LB}-"{xQ52F2]v.f)40000 tcsyFiwAuh ^gi\߈ҋ$"ߕT$+x{q9|^ڥ8]7Z, Y)x{qO֕Ͼm(XnFBT Qx{qcBnͬG1u N Zyx{qSl&T?~rJQ !x{qr;UEw 0(a zIx{q=|ḛv!hE qx3SAB>37R]g,giCƪ{ =[LBGh3x3Si*qAAfct÷jgiCƪ{ =[LBZLx ڮǙ'Ȳ~]x35+yA<em+Ih>.p|umeՄnKBx{qZYG^L7̹HK fx{q'QOqRNcqx{qOoPk7C8ɤ 6x{qΪܳz7m֕ڼƈĂ^xgKtGƛ1䔟ſx3rr%NH=$j+|JgKtGƛ1䔟sFBx35RSpPđnTó82ܑIUP~eunk(Ce@x35k LJ3z/:) "x{q+a/ԉٸ :x{qFFg9Vm=:SJ.d bx{qYur&&oyb㞚?ZF  x{qgDYXH2sc9 @ 2x{q2۪qIמd21C4 Zx3x ŠA摜؍b/3x{q* ݼuu꼍͂v% ,x{q)CZΊ~}¡x{= Tx{qV3"\my{ㄋn^ |x{qGuGdjN=>sc* 6$xy0ŜILIp DʺvNx{qڪO6fpP vx{qïӽ,}g4^# x{q[MVQvl02f߾ Fx{q;w>{d]XpVUMt nx{q%yW犔p4픒qq _x7 ䷓k1HO$ '@x{q$sc))K<(9ӛ qhx{q^Ry΢`DWMIo%,wc $x{qE l8pڳ x{qEa_X/o3{ ux{qF[y#Ze~OD4ģ xLl;˨q-p0ژ:Lx6rwXU>n lx`~vʋ+Ll;˨q-p0LEx{qBW5o+Kos2}<1 ox{qB [= [8w/a[kxS/(\Tۖ g} Fx{qB^%;o_sѵc'x;xqBȧkgGe=0q- -,xF6r&3xə!D'čO4\w2 jxn!_]Ie׺Qҍ /x!,mVjV,xUQo8 ~~aMw[ tHvݓtՑ YGINcK$SI( 0sL5*V W%kTz3PAe!k!ēBHBu'LdQ|YjBKVapMCs1^sUF_g}&Ųou0͍qgl9)Nq+Jh.*10:`P f阱80lIOYlVwG{$h ܽ\JIV6Q}&ҋW )k% WWs̯r~<0T';WRQޛ#w)*y-J$1#[sHT $NR6.:z9Iɾ< 84zV#P]GBMy[[i`,2j yc3?d7AJN9 h뵩 BD8'#:> ?sKE΋^yiCmyM(gq-N>NCY34-y!я\>>e2;75OS ̨(UiJqAZy69$ghb>K>_LÏ U\.Z F̳~)J Al*{'.i2A m>aT8[K7Szlj0^#۶<b¼UyLX[.s/R [$.tf}1Zc_];\x=o˷Tx,Wh£ɂ›}E}CC\#=-znȱ /x:^iyLfK+B:@4r9ls|%-Ju޷ͳߜ~Hx#GpCXR.sf XXS-x!u9$…B_8v/x#GpCHŅ2y?q,F%v` ^-x#GpHg*cFcf/"v -x#GpO }x7->}vC3ԼĒDd9)jߪ,W4Œ Lzw䔼 ŔH ޏdV>Sفy7-xab1>OSl8q# 9.x#GpB'EzN6cuoƙM9 +x#GPD71;5-3'U/1ajwJՇY,֜Q}*51 20Zwl/x#8IpC%Ll0xə!tt#]N6x Wxə!zuro$PI ExR4u'O2>?6hHT9?e0*<Őpz+F$ $E. \ߑA $bx;~}.RoƽzOg ͎L=wx[OӬ:4G$]TH VU9x" ͽsf; .d1ssl; <Is7qmXy,ӏ&H%qq`EĤHcaO6΍9$w8&" ;E&ܐ}Leq)7O2m^ة "/L}>Q ==xG8$8Kc #wÓd18dJv8swg~,%Y] gZ !;;p#(Pg̍W IV0f$rPB|&O>sw,AyT$q!/-?yqXU&ss`:\<9que>|-Sح|L9S3 7,K=E{c[f?io88k9D&%5|4XQ:p43>bo]6Iqل-?5%(sB9i$"hT" B0 Wg `]T9 ? v gݯާ~퉵&֯7dw.Gݿ J-^upn&Jni\E7H.Ma>zѠvB|WX(}gRA*fiz߼ArO < Q'P#e`XǍb/2ȶxkdpx >ЋFKALWQX J94+(Nɩ ,^ex_e#/U!XuW+E @P; r,s}jE>PpF5F{G!۹UBwb~h0<1.GR68 zS:韟o.Z@4m##Hh ~'-h4(+-칹@^slqQ8: e*SR{8m_X2QѴY&A,UׇqrinuR,ad !lZ/A"\J*<2!؄id)b@G2jQS} 42}=s |0VL(|YpY/2!c EXa,CBtGYҝ&*Dk]0oH}ѺF(KZegp/27SUaLI$u C2G I%j{qUp1()0ϊa2ɾex?\IB3TPS!RiXD׍璹YlI; ,nM,4ŮiXa ~q?(U-D5uBc$3wDƜGph1xU5IFBr`QX,a1R[p&E9)KC_kc4;zA'i]e 1l1=DwEixh~}2S~U*_*8z+C5;Iy~u%%H p|C熳!>f!"f)ntǖ36;PL=jC2X? նGD}OKhYXI{x )UT`;!Tz~ZWXsPiacrE!?ĶI5.sz SJZS_ Y=~ bwt^yYE01>+ jb,tId#e9OفԴ@-h,Ђ0`yWݞ3Q9/INp0*|c[ѣB0}r2QY&QUL}d+j~SjeFof zD {ܞЪN{gc?OQ=El[W{l={ ?AuytKGz4Sߜ 9ld|N2Wt?ڧ]GSud{3b>s*y:z!J)e1Y1x{qBHlb.6H~$nZ ]x{qBȃ />{sǶߝ}XZ3  x{qBHĚ'88갭g ~\k_ 5x{qBFǶvΝlx4Z ax{qBHFWkx;sf ;d x{qBȝ'b]m W(QO^  49x{qBWQ#gdyvZˤ Tex{qBcy>T<Uv k-x{qBH݃@I7 *'㟾2G9\Z6 =x{qBЫpoDLW+3sZ͊ wixSb3OZ]Og}1x{qBHrPΑ[ڕ[Fho"3JDo8g!}3 \81"Vex{qr&SjܥeLbb % ?g]Y>+'S'm>;1rsJx{qțdŨ{z>juu&zi tx54A5ԣ3x{ ƫIW x5׬?t2b(놑I]Mx{qHwk]+Nx(͉Tof;s6l Hxx{qÎKf3F[6̉Y#x{qϬB?Ϯv:b޷ڹ{Nx5ѲFkPѠ[ºǑI{x{qGa\Jg^~@Oo&x{q<#x$)83Ir#Dѵ Qx{qHuX'V}) 6y+'z c|x{qHLS'HG(J`LD'x{qH,-w_yCݤ'̊ٛRRx5[M^PkzËIx{qHUڏy6t[V <9 z*x{qݑEq8c@ Tx5}33$7\iIg-x{qB_|fb~R͉Ϊ *x{qlշ ?W>s6E -x7o]Fy'u&)Z/buǐo揌 /x!RZ[BV.-g/筳 /x!͉\ҀQL@PIpRd/x![3HsJKIҤo/x7oHKNyxpNWX9-x7o+}o._3"C4fIfIƿsc-x7oB[xC@QΦkv&,v̵lK +xtMpNAYO7M&?-x7oBHF}#='طm .+xߏy<?*g}돶ʱrOXx7ߏy<?*g}돶ʑ;kZf~=k(D #(JEx4L6H20fH#-x7o+HMRjџ |͑{Y -xRu1iJzT=Tܓe^eODMTb-GR'`x7o/DŽ=r"o-0/|D֭?-xJ'100644 Makefile.amgU Wd}w;/'e_U "Yaix[!100644 rpc.c?1^EɺYO!1\"p|@YޑH(J`Yűlv" *5%xuKK1ד_q-hEuՎEB Ƥ$w@&jUܜ+}>fFTV1l _S=|6鲔",9$C]Є7U`_YK-b㝲w81um>%eX3ʅΫ|4d!ZB+ȡӌgGiɓ/g\r(;P ŷ!(Oqv/.߆KqXsH%#oC V6n(q4K6XTo/?2kX`DI|ӠI'x~54B? kx6S;̠چy*=xH-gJb/]Dfl,]x6S;̠چy*=xH-gJ&:uϛPTc$ZqFx{q9Nn8R0p#xUʶ mx{qw31=aJO x{qm[?$K{l `yyu3 g14bxNVN8o\ߑqZx{qD5%s'MS#,7q= "5x˛%/U8tz0ςЊo' |xWmO#7L~4UQ^OH-H@P6QTU+ﮓl= M+{g A\(}aK#dkboZk5aqZkJ@Rr?ieM귡DY$!19\/D{3ƷBqq(CY6vpP<1JRՀV R)U ZȚZ;?M"|#S+$5I:$ZTe*7| uʐb f \.9I4`? U-8a8bk8J.!R(,JuHV"&-@*bp.ɭWUG[ ̵ZTj3I*#TI&S\` i<̕.*d4-vMrk̻~n (snŊԻ_Я2dUOE5 M)`6m9< & G>!$h/sȄ/4:m02̣~]~FzC8ebaXIW]5+[#=7ψe>d2fi#1>u;LOm@G{#htCD2<H!h GJA􂷾K!X[n4߶.8pǸӑ`/QEe+/圂֓vԿx.9p:m`'ixXOx?0I>MqA&ɼY?y,Dɖrѐ*U)]yw+|b05i^z/ƮfŎbkLQ|[dρҐ`r_5>5Gv}{\Ra!f{~j}/r42X6 $ZbF[L_@2 _?ģUX%7{T%DV$5vh ц!r={N h,>{#6bws,}fw *B`8*btk`UR,uVY帠FI\0^~m;5i θ5UTjX.ֺKMBRl!kq3Јݖw`N ;?2d}Y! ~9}JXGZ!*k M W`T1ZEs5I N5ﱕ4@ethSfwe@<4f px^u:!nCAvi7?y:kiBNe~%vT,~Y^Jp@y 1hn̢Ya g|CkM6Lu}o=N3p9uEG j'3A3M]g[a!s[ }! o>PPOX,SȬqV8r  x}nZx[!ao} # * "TF~CNp[,a0pai;$0hWJ&l*={-+ ׹L堟b2?_}:1\Fg +9X |%hIC~Y X[D+_T]lܓD@غ_:M m(H& wzMn xL$p+rV 83ٍbԅ@N]kԾjC()k1rH6O&(* yJL =B+Hp8段QAh(hTĠqX9 lf/f (G)iUm~U@ƌ 8V3EdH+{, Q}&XdbLƒV BF!b<{{1/xk…x"!pua[)zd7'c"\ =9)I-_^$#D@^[<)z i_7iĻA}Xa% s͔d٤dOevӋL2`z|l”>c/{F??n&J.[% #lף@&*YB" *iJb6}@f `WM&«F5<L8 {#c7G D.(?'+"ɀKq2'._?'f0d ÷v ]=Z.UlUʨm`^$ZfRX{'/ɽo(<7U\pQ}ðtCQoX@+ FrȾRS*_9Ғxh.4!`*f&Z?(xWY@U f̜=OG˺+uJi wջt.͟_5M@> =7!X퇫F r;5&Sb쬦~!3oEVgxYӫܘuMN j>^WG*^;vi>ѐ+Z.>IW<2j*у_cXC֘ +NX O٧ds!gX6#N,;Bj1u{bܫdȆxpNDpyb܂$O/NVmS#=gC60B(N7@֎fbi¹杓:"vH%-ƶ @P 1Ѳ ]LƱhe[OQf尽b'%R:ZNl&Z3{vT`gVai)J6 VQHw)/eR RJ{Ʌ㚊$c3]_(z8)*WFħYZ^\<bbZ%6/#UX!OXkG"OU7_ 8&;b ;ѼDo /~cиjA|sszP,q20PTgdSQ;m%*<(םĕ%l{>V~t[R8 3IeX\/t#H׍qYm97vgtQJcԙKkT<ac`ESҩwҦ=SJojңL0#wԤٳeY,Ob(K#X#sXڼR.ԉԱeWne?''x]XFRV{2M~09bCL/K$ab0uf'1]dp^K6R2g>A˳!) oR]M8#tv\538v@X& MrpGOf(]ܸQӶW*.T<.ƛ ƥ˷Уh\}dIۖiEsQE-`Q|>=W[} va|~&G*;J>܅G~E:gϙsf_opG XһΑC=Hܦ~jS162Zi&~N:G.a#!f#jDXHowE '"ί/KFꦫb-m,{bj~_Ӑ)FKHTu0 j's G~M|l [}ʸK2V.` ˘È-o7420Y.+ a[ tH?;'@{H믯L<_w]w4Kj7C 10ȷ$Y@^ E'_T;;/moY1Uv9{|=tBBITa}u7/(E>[D2%UۃvU<`zONv6I˩hdMoǤHL*z⣥鿅4fl#>L^ݣ3G=ԢG6L|wQ+E B L@"uB|Ep#gp* $|mӻ4ӃA-ݘ ȔĤcFtEя$"xs}kq$kAIA'-#0TN/43&QUE;u|5+v7cSWu<5v)qk3wp +*APh `c~O*A_FR0Wfr⃝@!ay( +3xd3 Y,c' Leac,d=2p$T-ʷ* >)?%^F'j.UaLq $~\4Iv%J6''r6n;(O< Q*:7xiK.!͑JtU°(7ӤMT=`/-u,?נiVIپ928SV(@^OfҕhጳCDU3 DgAjRRXveR7՛ӷ< 1ʍW?fg>5(Vl׎ aEqG~,:V5Oz>!l/+;NLnhʖ"Q0<7hAS:H/ X2uXV'g%"1*]ȻD{InL_?+  xXo,+ڰeG>DZ2)S$%VPDR$+]/Gr-r]FV]WAtSa=4@P@( Xhи@.KRd#F/偻;of|~ǎ+>2 ^;^UjT.[jn7p!;EQ+ eyH$$礬Krl^*RS$WK%S,ONE\%H.'$9MY3!1YQT(rig=˱bY# 7Ӱ:<<3ɣ9d._U1c;De; y%_x3Nb3hUV-%oraIapwdlpxQ*PMtbUd} v`u;LAERi0US: H8I3⨒'TpҞbཾpQ?~j*$J*o|׳Ud>k:*68;SjcLȧwvtD෧v^ WX`vӛSbYն⏡L:d%2,3Afa26'|W|As8"45] Y8s{u@eht}M'ͬ #5#&hx^N5f l? ڷg-:p%Ex~$/2/Q(RZD16:4‡ ɥY,*Z GgnOFaw{'2{>>澱w&6`pl)򃥪jܖ? }{b^k_gVs(Y *;?p7d.#cs0}D\fc$ w &Bt9՚O'׏vx01;j^c9c BB" Fp@LtbJ8^yRs~ jRĕp/-5ǚ\r6DDPUUT?ISPΏqeTJ/HV)E9-"ЦUܑU M4,-B)'_d Rde1$T'\3ْ&C MhOЬQtKF83$Y|PaQ%+lF@Qmc7k;Gbk|&EfGgej?ZO|N7@m?>< ?PI#//;_d߻`s8/v:`aqYx;p~@Rpf(! ׿3%_lt{ǹ{~6rPmv$OjBcn| ڥy%ijfQg2%p,?BnIE/Q;=y"B+O~;xW-VR-m?J(x|ڀo?^v-FiUWʭS+zn9"Ur|kx6N_mDYǡ$pwqoÅ#mygUA6nZfdMrΆkkN'&IO歳7\F\>bMrR>OU>uiBJڊY[!3XY'[xz1iUHº\RBI#7=t ;{L qm?rRfiJ'W-q*Wvn5\"],b9!e_ak38`[6w1g/b⨹kNcގYuGGR뤆$JuQW}G`=W-txR8 ݵsן;}m 7e[C)+T. ^}ƙmuHu:@' ]dMK)81'a4wfe޽s<+0* qfC|<(/(UjJ F+ 8Oxs% W84B=B47_(f nxxs% :tl9gMxs% =%E%zJ\ʙy9) JIYW2^fa 4tvq0[vH^PHo{v95}+k~D=1CpDH1XdC18Cɺ#͚ݮIZ4; )fP EF*Cnt{FVB e 5Όi 9FCJ>DK(}닄|55{arkƧi9{t/i܏<.75eopDf]E|Z,tÐX%VHPuO#RuJX% y-3*Rds.4?XBSnɂpQ.Y2pJqx)+m`F9\ڡt(dh%C*Ifuu 2Za.D~'xqr @͈T6q5@j(@5|ї/2ālF6ўFq2p:bTjs^U|KeIRZM_=/+'w&{;+I3荙vX_zGRd'- fT_l6;Im«2|$Nqv6v2xm-@D>dYGaC<@"K^?Z2 .1ΑLSӡ@zT \.%4R:T|-]T[dW) xp Yt~1ʌ4P!ϙpF\tqEWћಘ[w2(( wkk-ZPM.2~OeඏyV8D:"KE[].z{%Hn{Hӈq $93‰TOWatœqb΋{m{,a$ơU׼xv $}g8 S?qacy\#-%~\2J`B-T;C E[4kxVKlGI0q 8Yۘ<.N0 ԊZe6YvRN.U&[6RޢDV9֜{ȡWKV97.[?}`|嚍EPkga>(pq,ģ|4=IFRѸcx*ZYWU{Rh%D ]K^zHWm^%&IHjEM D"H;͈5Va&7|UY|^KEӧ8xk'qxشBhea7.~M1/a{4]EPtnnѿ̢5 % U%a)3Z :c蹖XDw]D; uFvvp^q?\6i>&t,Χrd8jsבݱv6s5 VHLR)b̮4KFK5|eK)Fnsp ؞;:h {-OVpyM=Ý^ѵe$=}"P9Rˊ*^Y&e0G4# vv tW0@MJ&-pƽN{l8͍ At5QD@@`(J!XU ce,jq—H)m%O>*ohGј#5|n@+fPȝnB9/:|5S/< $CQQ&獃 +c CF (Ef"hA2ݮOҔ\4&u $y-:~u68Aa ɤ}p.SrYgf F hkrz5 Q}hKJh~L,aLZ=}k7n9]kEpmkWyȅMsunx36LDp{fbϋo~ʙH2/|pҘFVd+!v`&= ߡCeiB C&wSdI Ӓȟb>;u'I+3Zt/ UkKpi Hr%#mJ?0hV#709Lܚv$C8z|9`jtnWܭ?|;]P耉%FQ܈ O_G hNlLYjLNejeo隣_WZxI{|2$ E3z?%48G7<+7 <&~=>8@xp>>AW;Gxn¡⪠-4g6K. / vxn۰q33*FĢ9Yb &,ȩPə1U HSs:c1\ 9ũ `%X%J&_䓚oũ_`^PX\\_ZXP\TP5 oIPFqjrQjdCɅZ\j'oaaJ((lvu2m3xezpuf (1.2 backport only).l+OT_NULL)A else #endif'֓ B /$k5(BjNq5Zd+EUxLni> F3 1 3 CRO+6 C ;@[xۘ*}ia6벇Nm:f&fSJ9B}|=\Ct2:\`R=YCd>M!0N! E)E%F: TD!rZ .%:yo0M5Kf{:/( L2q=QLfx[,m܍7qMVus v#(c|nb|qN~-*XᒙZ\k*7Kq+dV&%d$$B 81=t|ҩyɎ@P1:0ofBqFbQݢib v~yɩ))P8U6Nj E1v0%ezY9 (1bJy2\RSsSJJS+'3@}['ޞh(ZqQ6PSN~Oj^zILgd1"a2l2əVPiYRTM/|;xo'lOffzLx;}qE 6/at I.v+I]K;A Wi.3ܘb,xX$CV)8x=ksƵ_q' K84ݡ(J5ErH*p  }/xQv$`ٳg{G{G\;z2"0 noI ݳkhM0Dn Z>>M8sɤ}I"~pBcgwwwCN$g(g ׇKhooO?[n.Kϗk$gqi7Ji],ӥm0ޛK>9kփ.^2KQ4u(ۥp>}u$(Kg K?+/^=k|I"#Z?#O&t&{`nMwȁ5 4#mkbiL^mQL:ԙ9K3xA/h1 ^[ȍI_h`#h `a؇. kAۚ u'4kAXF@=aEH>_ oB :n[ig4Gh1i;1 ?v=?O@}vt@HQNsnpnug@ п @$NI{ؚrSgbyL3 jdfIW ynN,zF WBNף5Uқm#͏9Fؓ5g7tuubnˉ'6o&uآٽ;{+)ƺscg[6C1jmw?6q=#ʉQݑ_kK"t] >߻yK2X`h& J {PS"fU:y:gD c=p:pgbmt'`'uK,\Qނ`&!ɍ={i` J75焜`E-+4Sm^ζtBAPFS0ɘc++7hB%!O`g+T`+6+d3pI!w`(Q0 DD6]Gu!`K1tW += ȯp>^̗HF8\n.M"7\dMb& {Gӌ]&k<=Ch?`УҨ n=EWAl2N ̢TцPXk'ן{ s y3~p"f [-R$LЫ7 Vʱ18nR^ۺoZI1|'qWk0 LA7'l}zz&,uƠa tz3n]v@IIΥk ;@[D7?2Bdwt8Z;vu7uz0zeIYND3 u˒ZAc3M6j􈜦'U51DU Cf5Kk\ 0sQH$` DM-VZi+ hLIf~ tvg,4tI"lY˳Bs{uf45ˋ<3L==\'*:f7&5ק5in`X>e1EV00[w71:M,Mvl" h hN/˙;lILf H%]iAW[eIc0e( KMya9By@pW01- @f #@~|ܡ"I@Oxzaz_:BN؜7'hż! rm5kT~hAG1vC8REfۥ\1-z|.c]'=g u%!WtzqoOtFao/Z^\-jom`8ag4'~vc+]g]Le^;{;A/*e|,ۓN`o r-nJ!oR'ngZt)m6dnOyI^s%A8g C:ZX\n0\eeX AՕe]g/lSeȳ )TyT"JsuϹ41u&-LgyVԈ`cf]c!j [w`_#p/Ǻ׺n^|t"kDg8X߶E[QpT+IE'>9x;qk9zLynNx&{Td<7!\D(^HUk|%_;ѽn)P{[|s'pK[#1D>gevX" 2[GF }Di>s۷'~4wT3n-%t"Y\zu%H%ͮzKT.`nn;*  pm/2/{<X $d<G'!ȱ w0:?k`%zmz2#VdZya|r' is0_,5U;Qg2wAnnl4׽Lםi۱yR܈1Iŵ-+TWlM14C0P,M(QG.8E Lg˴LWRuxxҲ(f`NT)+5e"۹NoU]2,G]9w|Kƣ7Mx Bwkܢp-'bt؇$uD;bڲﯘffgƓHiG|E:Zg<.ՠ?iݿw/_`n&WQ9-X*\am$KAw'/H/taN+Q]^b[hhqZ>4 T 3쾋m]A[8uUjQΞP%wAKIc.Ѭ 8vBZonpyy`Mv卑i> Ⱦ 4D,KJV<_©M$x4YȪQ#&g? *fz8 hs;@DYTJOIITUO5oQ$漁x}ִg̲;-jBW?x8EwX-r^C`Coؗ$*Bx ,7aO왑맀ecCRt+z δ\x!$|sx~L@|dgwBVD5+%GN*9kvQgU0)XHKjIKց̣jz+)E*%Q:8FW=1;=ZǶsYI d ^־ ۣ@ui3Ica:W Oo n}$YLt2^pi<=,< U]7B 3Ft=nP% )L0e<6޸kو$A5+8<`RK>;860*Mʂø ʁȮ6) pؤ4hC h!ʜ3K":V{G SHC#3]L1xiO~:.@ qs._$˶T&Ok+Y Sef*3զ*GI$6[Y[QRơ̜-s%7R#0iHeY~}:8epkV+M*bIaśȼ(aG;է|)PQddqK<g}tncW9m]Sf9J~ySUI'sb;=y RϑԱԩMs2GT1Y :' ڣT̄,@ i .ua=7j$[UYaURĖVlJ߬n6uCo"rHq4l#w,v|z.59"4Mt?e{Eـ2Ȝ{MOшU3Dk52 X2+'QfG&Wѧ<*)\C~Z_C+x;6oq[xrr;rz)x2<rC)!lX!mye*`~@j`AʱI3KxBZk_ 4Պs͋8Vcцcr ?( m%r&Ƣ"c T}1N|<6!ld9qBE4DUnw`lP@mdގT;g3|r\>t Աnlp>! r;LL;cJ4>hq/\Bk\́:$?RDdH< X$ڕz*5xAR#(r-_Gp=߹*U T)/9˯83vA󮙠SU B5YbHFUU v޻]"^ˇ7]KebJ*x/ej'DT9g\k6K9rsjyOŜ_L<7i֞41;}0J֯wi;֛dgκl$r8ܚ1nu`OZGOXDL8ά 礆n€7IcHo* QFʁL8LOl}6&Pd !ph==]jrRKfZW%/\DŽ+9 Zn+9+hs*1)"K.UEʐFAR=RjWݾWrA@hW;б1yg=, >|doW|0tKH}`߾m:iI!xׂg$ .יmGE<&d$RXi dEwY|w{𠊉zyKo|bp 9IlE16lY9#xR@!_Mdϻ̽;7ʸMw6Z_U{UdF-fMgg^x>l0M%18y՗.lY D*UY&gڕUAHꧧ#ex"bF .H%su$a :Fugl#hύMa")Ф-0 ӶYy(f] Hq0ˢO&"FW6h<ѐ<'+* u*ιi1r8)$ȵTȾ.|_ΐ"-qZ8*@X:Di{YUb!N􆟇sPk ^QOuvt3buc)NJN= %q_6 ces̏΅BjRaT[Úц_^:8ѽ&0X/fqُI"z}t膠V8c]a|io͏smWRs ,&4CJPё26%z'!ww*SJ;M- Mk ӡrv56V\# .P%fcXw^OuҚ~Zߍuj(Ϳ'oeۣL5&V{crE?LYH+1pwtu>8жdD$n,ᇓc)G]W y* _z-Vs'2wdqNSv%w Q ۱ury|2$kHFBJTʈc[`2w藕7ZBsΘ D^Kg9Tf-r)fB:s ȕkua2)|02rp֡;ZHHthE)]~^YPډ9\vj׶9wx_ n}_b.a5v6U!yfXUAEv^o]6Sݽ|Mݞқ[Aw;8lMd^6B͠`|z K$Td g.{%(CA&8[Lkޤ+Ѫeceẖ΅9s:3hMP䝟{Qk2i&;QǢe{X۪UoUUbTLNf`ǻl$M5mj ikΊ)e& u\R4-&LxvlEr sIso--؉(عcާ+>_`<[*o-7 >.J:3E,zyoiRG[mdƣ$״Xڹ1P%joӏaT10 mB aX(`gVvtEG H$g]鮧,$b Qdž0M&IÜVH1OF Y^ċ˭Lj݁Kg!n)U8p))2Y}$qDv URU%:2H45)BƟ[mrƖ]T1ɮ=.ERBߜy/)\M sv `ꊟv6--xOZ)]diVr0NX첼'[C "upY Y\Z@^եW`ˈ\qM?6I@Y1qm.Wi\k[D}V u'F˂1WZ_KmЭjj>]YYuPOD VLIVj(1 #)}Fg>'j*pwOX w,꫇UHjevoZP<7t=MK!AF/Ƶ6NgTl/FcL23,$¤YlZ ngl|#f˿-cK_x:kl[yP,&~P/J֡,ˤDX-ڲdKi$E^^Jn]dq4vyȍOۊ @͒o+ms=^&0y|{//J\kйyBFR,I}Nv>IfꔵtH^9,%m`ɠUĤ[ %^2-QȨǐ]L=meSi;&Z6MiNΤSH9Er(j[dl|:fA| pj}KR\N+Il==4wnȝ$LMY iR(7'h!,!1.dr(,p2)DvF KfA }K29/Hpi!WjPFGsI>E ƀPaPB2C%.#5Fq"-9e)Se]aeo,In%e'|h>NVw,n' Zvu[}pnkiXz‘BFdpbV(ͦw2g74x(ɥaH4?mUUbS$pn[FtM&ꄏZv79&C]  ⒘#DmӜIFMt;Oh귃Z%w䐞z F!ԝ#0 ˽lCM?'\݉@nחkBnG$Bh2,ݮϱ &zŧrR:;ZX!$4^G A)p]; #Mi3恫a38B=Cgjq+^\*Jzk*ďc<@yx# TIӨ\G 7f3'{/G~2q}k,=u7t\dYnv hc}"t<;9wچ{׻#l=w;pvkS2g NQw4V[Vrؔ'5E]$}2n)Q91C.;~K]4ʼnCYϤ{pd+Ė(t`4뷜{\ڑ׺[a\*  ,s8 U<(b8O4 ɭٵ<=Ejyuqn׳zHY {7r,O:5ڿ jB0o0U4Θ-yťr]VCb Y-^DvvCEM lJ:}€2-,7[MؽTͮUq4kehL/b%Xdf\ix&{ZQ\Jz8+ \O~JJ*湁Q% mXH5Ñr"[wi#6CJY3 %x%:b޻B"uSO%vv>$*ßqE/6) .lZA;kF8rЀX$9I2r"Wv:aHn5dNSw`b9|j #D7|XuR2IP3'>QJRj}_x\z4)0f톷N|k ַ#+s@`FQoe$ΕTS~)r|$J8r"<;dH&Ҋ.),ЈN6|VGGgBgݬ3d/Ef0ڣ<~R 2TP߰|c 2!C[z} LLR'gA$sHX? 3 J=E0>$;U],̇<\(!>, uk~J/ٳ5Nsxaףyi$zdFe 1Uc))^ =I lN(Q 'n[4w*Óݹ} ޤ ̪$ x#$,ۦ>VxicY 9*:ЗU4,aפrproLRNQR(KĞQPhʯI@rzuM3"`plpБWV}8"gW'̱^{5тŕ!pEa.Q[]P/[=\JlUj NI \zx[f 5˖ڋ!HhZ+7iFܰ`|{ ѩ ;lӍп\^&`^9s&q\\3)!`;yȁzѠwyתoN@z7RQKcVPTW6'͍GmeԵzKGe > ċV<:x|'|x}5f|\kѹ:jYJ^j2!y=: V4.Ù[af ^|NR\WFv`n[U05&"k T$-,#aJ0R{x:Rm/yG'\Ջj'RN@KKsGV+4R:xe icn Kاʸ]߳,a5f w^TI|r?W|NgRm2N?҇ek-;zK?npy|v/JnUɸw ~ +h:!0:P\8qpؽ`r% 8&%sx7JMV@T Z"QT[:8p)y|m>9Fz? 3uk5\in:++@z*ZGzrRJ^7PJ 7̐:C^gg@DMy}6oX:Z~Xhص%Q3{M l^7O ` mA-[LclE{Vxog+\{5A^!l)NWij.4_ o֐MzL_* e+e.AOhozM 抲J,wW +!J;|,m,ޥ6K($e~yWQI22{Fɶ55 ;ZJx_C=i6='o [EG Dh<{I˧%rlzfǭw7i[ (v p-๟ֱwQ q;m(bNG|<","xFQji/Zh{[ym.8{_ScXO42,h6ϖ u2:?̖BA=;9߯㊫(3(x*xx,֨3nogQTiXlemyemIU }L\qK!hC!<.ej (J8= z6XJB$d*i;˓Po41.5Xl-킑+ČKQcY ;B>@ Ë~Gqi׽1x},Mk-x-t+{'tqg 7Cpc| ,Vɚ %T}_ cCM>?QEMK{5쪆}leOt87OQ>Vh p;Ei-zN5'haKDl _7a7+tNtHimRNw7$dVײã5Ֆ ex4z'<z:"u- pGTj-`hEuuuιY:6hHH/*]Ļqh9Z@HF}0 ?8%,]Tas4SA;. *XSY a%z;.׋B cDuC9pAd.un k4\@QFط<^+&,xR7$(/$w+ɿEMNBoJd )|WUS '⸚ZQ@rF mŦxJ(̽׷J#b8`-#⺾ F!٦6$G~nvBM|ˠrXMwFʶNRVZHoFHwQPl. Hwb| yA;'J$K;ba}۔JY6ev*וF7Gjǭov;AGq-{D 逤7Q*"lGS$P=O8ͧyG(gsΡ"fsMP"c! C9H0qGN!%B|&*cźl.1wWYk!udf060)vm`x|bS؅uh,KtSGbe*/ă?@}i}I)7~.S%΍Vx}TkLSgNKΡ(_KJ[K-ʡTZqMh)=S -YtNu&$A,s?eٖh6Ͷd^(I~=y/?<{(Lx,Tn&h六 aeud5CMdc#>gD0_Tr1) H|05VۑN#/+diAyU %\TLV >ש._Vă> jD),Xÿ{~2#ǠX$z(R/Tܐ?J`^&:|@+%¯XVB} J0($.?rq4~CL 8Ɣ 7p鰡 d#GDڈE<@| ə#0ҨMI$`;^.A㝴':lps!rmxC<ƫ3J棑xK8#÷^JVW\U7];Q(tX9l,.Ih/!e:zh ;ړ<-U%)!oM\ Sٖۄ$lj;>̒ZKh̀G^Bmoabqgċ /q0ƄV=j6ݻQ jZ(İ4E{)Aw zRFaod3Q[`n+vKoLX}lD1hS[k}N5`YLcyI457@nWg0o@kJr|!\zYZq7N ]?2hJvN94"ibK`sb|ti;8Ȕ̇7 $::<)^${ W88 u&86ܖ%f6v(|+U"&OMu(w9qSa<=cLΥQGLhU?Q)<~hS6H/HgluL맽OGhqav:ԡqWPG8G0jq u :mvB@z >VmhXa~Q$֞$1&c8-#㞘4JhiYmF&CxKيmkLB nJᾯaZA wyw,.,Ž2XZRW\ 5 _HX%rkޓ:0tmJtʄ"(bI f$7u$L1۔1CمZ6x1 _kG(W( =-cvZu82KnM*T`gepUio+ < )C _lDj]JD PXV۠` ֡—Y KJh?w _<`{j(8?`XV s­2yW+t_8!OfhYBszmPsGSVAN }^6N[V?/aIhVp: 75B;W1WWi5оxC^S'VxZ}pSו lߘkc 188.ȲdA ?Kϒ, gF!!,NG6i>43ve&uLvlg:;;IIwm='[s={ν_V|ﳼ$bDAh 5h7d' b5UªoCP5YVa<`r &cVId"JbG}XTO>.0Cٰ 4#6;TZ*J"MMg^f`Hk5|L<C\v6& B >?V.>T64' Iwc%?(7p*pZ<$Otk5^ó}))zV92B\Q.F#!kXnguVѐ),L >mNof 4ӄ< C&#" UNL\Y.;JA@Qi#f*pyѧ6Z*!Bhp4ѬaTVAF -__~627ACvTd!/Z$xu,>981|7$_}(Ǣ-̛F#qkܠcٻ5m#ٖn)[^LȍrYLx(%O+ !,`l24/`j&1>aB˖kZ"ښ!UD32,Gs2IE:23W9:ɩN,mBClL=+--Ӕ2yDYe+|yC NktE-|zXLQ"ť̔%>;Rv[o[`mU*cvyL`n ǙW YZ=͚_km1 nU+LEѰ7 f4~N4b"hW! !fy~4a4s,P% ϊc[Rvj {QOҢR+:G"Lဇvûͽ.!>CV+ܭƍ+[N[*ݝf~i&p؋E@&K=x2'GdP6S):AeRf.=c0m[}L:5#ѵE:ڟ\ތ.ӓ(20&ۻ:+eٱ"[:txeipRKVC9myzmf$Ssm}V~I8']=]i虼2$sP~exI6Pffd_NH]&$ УFF7S 5̼uҼs9 |쏀1=Oj5K8C9ci'oCȆzʠX̬2`e8-KhQ4|ZfTjYN%x< ˉ[,1. Gagp;|t,_J?n?w̙j f͵Ns|Ȃ+ưEwK) :P#R܈Hu)ẄH-ahUn _FT Q?HnI!:,@FHlmtY ~L0լ1Ez,F3J)Lr `}pʼ,G >JְOG7_d-4mcb8NBF ZqFss0BCXVCZVɡzNHSy| DqHWUwY53g,D>iT+ \),G9TIXTBuv+tƥ,G햲i[A2z\#,ٜ/PtHDS'NSB~&pvC bP1*8v-V@]>{s:1 tbn]!vw M\C}iQs{X mJu ) kk& Tߠ [1N1R ő 4YMefZi.Q}B:%4B\NQ!Z c]f%2Cs@RoWSZ^`adGBlBp?x@r8Tvd1E9 7'b v><4mND_8 JzIQ)t[̎YC?+Ra(̽L/@F+syZuǯWg>jo$6JO\MakSM%2^uR"RJ(>,lA8F(n2]J:mң["ۮyMF_LS˄OdZ#jX}zc2n_;~(^ن3s ~viTF!**>OVH_{52R L5(@1O046r`zNIh]I*UGVU+ɒoqf/@^:)`ehʍ@2kL:%0G/l;/n\ٌ |/c%E]iRѼXY3guPjx"]/FkQ/+ܰd%D Cs-^Z>wywF~ƍ,Ŗ$ehI{^zPvKAZPr{ΟPy\3-A!#* ^tr-Zh5.P^(gۡ B(.KoD#{Z;E(.K[ %9WC:)H=||q3li׎_Z]]u i!֣Z崨DBP9H|Gh2[s{\6G4ryƹfAe5 \~cuP +Bf1+ p>ˠ6 mŕ^ɑ9}NɄ΃LP-گUfy<|n\(* (aZrè`fZ'Zm '7Kk׺2r붺R8Z {Zu?]7#8?]ߌ8Ki12ՋF{iQK^r [RW"QUmσv𧙝{i W>۰npՆd:[T:}-g:p۾M>ܹcB?S?.a滵N*{,_Y`?KNo5H1νAoIcbn|vt3&4 M v!&_[:=uch}LOGrlR:Tg¯(CFd5usY0ewv1{Ŭ'{,hM$b #r}C8w6KIʭ2j8fkzt&̆?ٸJ>*~˥Յltfa7m[V`WE$6M GԶt;숯<77-Y;{0sNdv-tU/-ݸb0ޑu|$5sv@=L߫½ZxoЦ>z`\KLOPwI.,x>3 @<#if 0I1P#endif fͰ@ Pbj{ndx;)ӆ;6m7~x;S 8&wqm~Ʊq/N "x  F plТKwy; V<{xVmlW|M|:}48q>Hv8Nh.]߼?'6_o mnh ic{$@E!4(?Th?6(iL&~ vl/{ιjxp _4y So]i\,muӤ"w&P'lSbp仂Iti?ЂmӯҪ+bUawUdu}QIx|8)Rvov5^WO{_wUUl>oj=T!J%I; l H_ 8[ SET6b׬ Z;Ad Ԧ;lϔfװ|头EwdQ-vp-՜*F]:y'$Pteqn~<8d"ek k֚i8ȣaT4hQ W|GS%:ӦF~w΄[kWn-)[򐰿Ga g8(gGa&:zTLYX}=\bGZt^1NsFMŖRw'ѝz^wg˽ Kѿ@:7#J֋:brԅ2a=uaMj@ az*p#}#x;܀KͪGP5?,CXl18=\`a#9#y~0 =\xf w{7NoEW$X6yÌZjKJLյuy'Tݠkg[(&ɕ r|rw XC5k6!!-0а n?IJ4Fy-.7ZlLPv|uƊ@ףpճw#vjaCk1dgվ]F=ux2bOM c@oZ!^ lar`uq'[ <{vXElgdX-VdUj/o֏+62 ɋv;p.KUczx$SLkUI1K <'R2AEkFc4Yg`a׳u4PE&JZ+G'M>O}^? ԕfv_|M]V(s{c'T@uA榝޵4ya݋lQ,¶NRSxI' O>4X^oaiu{x}?Cilwx;uo⒢͡,E7{J3i(MND$u6PLO-/H,J+/-LOj %$QGaru&R M67/wfjN*BafG-|f1X(5=$(5EuO άJQrt&-*//,Il4l?ɍ'߷ؼ+7PeQjn~P檐X|.юTaynr溴3xx7HI("a))1M2U ?P_-cP~fv T>x;uqU 즛M' N.|R`xvĒD.N0 '3ZL+6ـorXHN[e6"xmMkPЙpPeZl~,::teQzIC2fj- pq b\Pk.̄Ess{r_[ÚAL.?ӓ3bM@`aGmSl2)V[~kotvhj \r+XZ;cKH6Z $ef>KtBL&*3\eV끵<_v`ΜO=1i[`7oqGN]h g>'Fߦۑ7^sxa0^TYF£s]㍘_q_pC_3\x"u M'y}0^JXoxVKLWP`_DIHccȗElcQ@4gdqg!n,Jݥv]EUEڤ]n&JCTtHs{[^3kQ.ux:e5s :`o#UId`˚^sI2aE2@gfQWYLHBRR-ەn 7tCVSMvPLу% @X-s3svYTJ/nM@ayr <4Bw/]]P4Y e`օ*uJ*Nh8%&hx43;)_kB[U۪[γ҈-Y T3Δ wt>6w3F-(yୣ>&V!*E΃S"&hy ȪJJç{Ve5mߓ4;;1/$50쉼i^sN4Ml!^a!T)Gq$rG[Ll EWZBC)>WHwHflDqFNxx\Lϧ3JKTF%VkviލanF!jŏwa|0q٨IDVb/u<Պ3KV^|c{ Nldl L7JYҗmgYQ kRذ 5eM $5o.-2 YvP@- $`95x>hyQm $@]R E2)h%'U!bX89n[ĵ!a:Ԏ7tuC뭣ɞFV|:ѳV-?:;]A837AN04eЊ:O\pd?ے%btc984$:iXRK4Jr2uCi\`cCE$-0YjᏗcx +].>Eń!~ڋ-vtV^B4$pY l`.8[u475tTEǺ!keukV _5~|7/>"4ИS iǦhɩD"h;^ëc3Xul[ȹ%Bd5^ǟ| eCHs3d<`'CCqme7c8> ͋3 31?4Y] s;/PK!WtdV*Z;GvQ%5g+9ׄPS$xox?Õ0'cGwW#3J^tQT9ue=U*t KzFmYpA* ?7=[;椯mX9Z[D'cjeܫ3_gx{ {!fBL˝_\uU|ޕA8(8g%c2ӭ2^' CWx~E R؊RKJ&O1<%Mq4Qfk.ܬ9r iړeʈs*@@AwjGfjQbQrFe24JAš\@V_R\$JR+JtJ&gN~!8980P;xx ,iE 99 y%% E9%) E Z\ 5%@NG/Gz Sxy g& ymSvX8Fx{{ "ix n^Za@x6ㄹFf2rd$"x~qm Y492'+Joκ[!Xt=BtFbrl\<<w21irNv`MvY'pm~&_ ޜf !tl>i#l\u?2lpUPvNM$UǤrd0sJRx[|qU \r6oxT*>x9.fX(@V!^b=e(= O=`d)n_x[~qu _7\ 9vyx[~qu t6Y)  !޾>.n>.Gs;xz5 %fO 1|l } l]xzqu 9BC,4436?X =%x|:7"j%Ey9y:\0#c:Np&_Z/ Jwl+x"jd9'7*LV|U719#3/o)xKL^ʞNM"9'dwP?OgW-M)%Ey9y @FyqKjqIf^bIf~5'gfR;[#S3$ACMjbNtע"C %ϼĜ>\ ,D7* n0xwqE Ty% řUi~!F jj EIE@C&ftO>#U W6k`cu?D. 9+U*iZ5}*:y_&=ZJ=l] QUHKL36{;Y5K`I0Sd+PZ1,&eɫp$$͙l+%5-4jO8&N~%41Nl@:kZ7{NTFxi{ qY;8'(nۜ:wrjqno}|[͛\R!|nlb27o |UxNuW]&~#xe1kAax7C3"Xb09T1 o{3,BN,VZ٧HB owAeyy['Ryri+B=ދP<%n^o.755>FO { aX1Kz3US3 ֖9#v*4l;v4`3FV `(!*Pߘm~WݪN)]O/l]b}3R( ;Ҁ{B3;s=6n]xQ^F##M*d !+ H}? l= ҤN5.ĽtS2_u3'/E]@0 L"zn/Bв(@Ƥ&4SͧKF ? 8ECbZo]NZlݱ_KNRx[[ 1򸧖(d*$;O)=T?䗜'kq"@⒢b  9ũJ\U)qn}Y`8亥\pjl,[0 (x[{H>EvF a&%'ÆM(,czc#$wꧻϐ@WU:@cAWIp9~., w8JQxF[#Ic^"@q\dwW'L34 GzQKN⅁>ǰ!߀2ڵuMR߯0g|o޼Ǽ0;ygI?͙2 vT> ZYOM Jr.Ɖ`\-p)VәQ㽟AXlfqtb-Fo0gut20PpkbΧnhf>C%!:AtFZb?J5r8Xywz mh:G/_bd#/a۰QƎPs8Gpq{/2I1n >4S&B`Pa\Hmybp-fDLƹ/w+xlOc7|KՈ9$S k ܗpO(qw U*|ؚGy (G b \NH(hP?SlG5)$&Cz4PЌC ZQu a|>+b00L[^.eĴ&r R<h!(*LOA2jڽu,/}vGo B+o ߤ{Mǣlc{/[~hlNlEekT,(qcp2&'ސsEt(RQOcq,uɝ!6P2{/Ҽ_Пf}b^FL)G=+=+9yjO=xM70f{J˄=9+*L|X#tMZSZ Բvk;B{=u x@Js@"kvkOCDhV)#3ˉ"6;gMJu"mQ~3݅іȞzTl*Ymu/p=WUb!Wqm7Rliq^Oݞ<,GAC-ybQjY9 !CD*yr<-!*-Zj5tk K\]Rk3ٖv],/-Y1Y# >X-K_>bvTUR}x[7{DnJQBm j`G`)kh:[2=LR+ 7,yuza]uuL}mWϱv*`CgԀ KAlZY7\V+wbK|QN٤9غ|5Sm'aă"AeqR4ZcuDLOY8zCj&aK-MMY 1gQWӼBYh; W8o +Њ~t} e*{=D"* ؔތ xVKlEi y6vNN&턦vmډA)H,=ݺawTu@QhoHTס*Uʁ H!$.ñ[((3?yLJ/\j Hdy^UVi(ʹR9_[+`]ҵU):>f 9 ^jRIYAo׍ҬpBIPƚKGc'xt΀K::P$^cGr]YQtMs1IĹiq l脱@\qI`yE/;fO5=eZ}~Ȟ ᛡw>gf0JH]KyJ ZԈn#m~qg30,|G3J8jn q. bszo ߌ!%$2JrR,b,ѤPȈ&M(cnQ xuxs IzT*@DXY/tf8iߴ^!m}'b/|m=4UI;9[}xMAj`OU0iz&S)Ņ8|.𸜐4F*䩢 _aE/`MYw&Ng(fK$,6-*tCsjqF ˥yI)z{h gi7i-[*c)K|HJ1 |Q7 w:!/z \]0e2TPӒ($ IGSE\"E8zE(HuXgpem^+? K몶|GƽڂFwO|X1.X?Iɫ|f%4PzasfSN*ZQEsUy|Oi)+G`EE)o 8O(+qT^ PVG*>neшLtbhA:,ef"v <.AXԁ4HqM)7[Ȥ)<Hn ߽/xa@8 7f*݉Vg6+zN#Dzrd"\/2Z!⼈s*?_(y zrOv\O ̤tw#85B/᭠o:a}IEyYk$)| D%w;> ~*B>j-x@eK7*(I3%Y8;t#;iD[=Ot]==G^?5{Sâ`!ӳyɣD5$/K 9WP %&.TLgYxt.K4GȐO'1{&N|,(CeŪt@# mOx`tz 5%,R[@4^ak ?pƜ߁o&+~SRQZBm7 2i?1>8*#h"OQ''g\2b8NfwR&fXL/TBNcҢ@ uRi>Fjhpee_=ųj?l-ck`tU h>}弩VлR*ʸkbAt!!t{NS5}CyqW~+5n%'?kM^*1m rɹ sT ⱿӸ/<|{h>Do#%YvFLƀ#ڇ/+xl.ǚك%h0S;/g)^5_SWRŒuR{^|v0{5\RbshNQ=u{w6yB?^Q/Dx{-vLV:ʪfP# cIe.j$&M֑bW岉pMz9EY0$;#1/%'U *z'W+LST»Z&Fɫʊғ\KCSst6?Vc'.9YAmd#~ͯJa~p\Cb'TP|OHdrZbiO~6yd," pMԱeR+؜D=umFL>2Oh-N2ҒɂuғIN:]?f(sx{7-vc!J͊ y'˩r)(d%{VLWݬLoqFbQjJpjrQjDZ-$Cge7U69HOerdV46 +,yxMRKLQNk÷ښ:S&-0Ъ&ڔ*L331M\`΄`¸ÌnM#ƅ11QƕqxޛsرӦ G%IR)3Vi#[vʪ{/ɠSG~Y_;v~60_Ԯw!p@7ʹ3BH2m?Κe('@8d;%w縣{ \Cq'Kvw  f7ޥ2Ս`Xo5jkʸn$Uǭ3w) U">;R}ͩu.kLV%v5+29-;UPZO8c&cujٴphɴ%uHkTwGJ} vHn)X# Ƥ4=`KŤ؋=)c$pf+I] 172A@Z)y֑C:Y,mL "{{[ 6$*?,F4h44:o +e.n:NiQf\V]#'')OĨ6YIKS_K!3OAKS乪OjOʫ /-JrUO$ّO}:-<1̓OiOTl,W lnUU,v71Cx;+vCS46Kdp/x{0f "z٩JO+*d$$jn8YW]G!5/$  IK/Й[I{*ٜ&p)rr\'wrNV`T:ٖt9-RBϫs˕$g$jdxV(E @u"֓t6?c#":QapC qKbEE|ҷy3NI ›jc p &xaAIqs~^IjEZ~ZZq*ZX j@.HMbf^jFuɧX9Ӭ<]E&gv vtwj8CK`l6! jj_XBhKvz&O2EKx#湜0l2&1 M\'5N^^E0=.Yx{4vSdZJfcsQjbIf~\ʛȨ  4x[;?v KjRiKbIf=r!hVx[;fwWd7ɨ Erx[R:V_K!""BAK33MAC(4DV!=5/($9? 8$խ(?7$W$9?$D  SsR'KO%NF]\!Lpxk!y?hI癍P ox-WdFo6k a_LvB]FRL\&iϚ,a 0Y[G`N0'Zq [Ĝd ԼdĒ̪TMk-t'QP+ )*.ȌOLqOpw  q՘土[Ѽ7'O޼Π6Z.%5')La,( !>PxW$C:\Iqq|rQeAI^rf^rNiJR~RP`\IX6cMcd l4y7g -b;Msįf/jĒjZsqrN4f!@EE*&/5ydV ͙\+OW>)N9IU&LUqGU|FEh2M:j`kDt}5ɒ7OTc4;lԲgyz6uB@W{MmQ8d>ŌPL>kHs/o}-SxS]HSaL3uy6gn0܆di.݌ӜGrwŰ(Hх] E!E6v===~@$:f 1̇"gFXŘGSp]o` 7=`v{) s>8+иo($xEO Ǚj` D. {~Ņhgh30 FZ jwM3ڋo3G6d1XRKY/q ,KS@e4RVY~$<ƅӆP=DTHJb(-s>;GI $U.:eU/fWQ&ۛ-K1$nJ}X8A$1:rxIgi0(`MW,9a:k*IJх8$-<Э<#WIZ%.XUMnpypLΛ)됤9>6xŰ]Kvb0W,*Ѓ=ʴjvSN u5ҴTv 3s„Y]%Ɖ :sKQUMpϰ +F5$Pیw? \ 0oՋLT%=(f>viZhM;T=V~H;( m(6IK]tXĭ=c~GsS&AXn>B.H]:a՞Qz7.6d_ŗ[ ]Bx]WQ* w+DRTx{8f_LN u@*%2 l,x; C00\3'Ux{VPQ@93/94%UA)?)K/CiNh&N ?>9#59{r䛲 [ES342\]Ku@, X7g`!6_Jl> ^fs~^^jrIjg+8,]dr\srmүLXiqXx{Vp`ib6K cx=ks۸_u^W~vsg},+ʒFI3;Z,62Tw Aӭc8888ouݸ"FhK/JP8CàIb/DpM<4j]!'%n!'q'XZZ) 0D&~ tcy2hyNN~͏wwwj¿;֟aQ'^|1w4SKSiޯzw9j8 ͆)\L?󏿦'ˇūw҇y$g Yy=¨O C1 3"c w1o }hF({1`L̽ɇCtf,*bǨZ,8 9(zم: GbE?V>p#?^D'eaRbpؑZBBx T4Vq49Kx{uXoj5+zcB{Ƨ5)szѻA{LZ^Yrcb'n%d$)+Իv)c`aYG \ 3l 7Ҳޗ4=՝[ĞH2ify *֮!$&/MTUʬ=0e9e8%p[#% ܇{(%?mӓpǤ:-KR)Ӽj%Ld8lQz#jjƠ,gcA+1Uk} 5/1G8!,zN'?*` :ekPT9; :?GeQ[9v"ZG1pYxFqk ;VJ 3HoMK6(/x3~\L*"mWzvX3/‡9b ZN^s ٣ΘT+?CJ.C[nl`Ps1w7AeGZQJG UźJyQu*[1îض ֡VE(P5HjT+jZoGv$&uSj\eymjÇ\-gD+N4BXl-}ps5.YM!8\=Q{>^Jy<\dRl6@a ʟwfFNz ",&>%Wktvo1 ^_G dDIBĮM맍uT?-…Z['م-O<zLFGals_h&I%FΠ9 ;Y/ մEY Bо?Yf g8 94s7=b ?qE;v)$b6XpSPsxL<1< \7`orEdGViKMl6xV,[RsSWmO;b*C5PҪvi!e E ֕.#b֯^] M:EqF¦X(s2L1(=L$❌`0x'4}{/K47y˅;+SM&o@$mZ;*QzWi"I3ˠ3q ҳ$Ռ.CT4i`Ua(6&kV@@3Oz -(j PzE&hQb4~9b T_p'wq:`ŎVEgLŸ+V߾}ļ}GvX.pуb]p̉`0"0^ݏYoS,m?W|{-\pYv:dEg cBli-\bF>V@a w25\W),S%RfpHV]-/mc´5z0 >[6< +%" ղ5Iyȗ56A|ҍa3ߒ1>֓l!1¦F-v*cFwЙqiE­إ 5SyS'RŞAc~~\ӉsL;2mިZN_̪mVb6,4"h,7e]4/ǃyIvaQ)>WkE_2e[QՎ0b|Lq=K?E%0,ƤwأXˋG;Ĥ<4yc/{-«6f1)ihBՐ8n #,~ LUqbϛcto4u=eh d/r0Hxgw|0,O<RIG C"auBDa8Kr1eTcIV6,'ٰp 찮Rɼ3`|zm؋~ >6h9X' ߟyQSUE<c}!wG҈iW(WXIx.k]ʻ4asv HU]j#Z]Q[lϞٿxQA>q^.`ݞ)[-r[-g-7Lqe_;U"A2AܕeА82007aAn0os S9=E9 tvu|ӳ? '3OQ%ҦXTqJ a^ PavsӾ߱|Um!]Zsm6MSG-6I2FX={aLCbQT<%RQD8qI`@JF;)15RI꼔9g;we>D2u( vl|{1>Kʺ8b@eإ^ wyBƢ&#<|Qľ`.d\!T2=eNMٗy651(A@17W(VY*C++lJX'Fkf;¾p_'Bmm^æb\ T[R}-<Xa~<6h; Nj9?'ɞT (j*~Luq LZo_ tjէ s-e}2ߜv04"Pq& P3gX7Qf((b5kmie>%~*s5gsN!l"3~tfzG*(\Zbؠ4VEhÿ`0QM֦W 'kwlvHV_F 0 K2.HC;O).:H0hy%@2uH3 X7SQ1 #72% dyT4(n6% ;鮆CmXe,1?"ҬTpi~4ΪC5P|mĵ!Pz1L/eC;S]r)/LN+S"xyJǝ֌ihl;gѝcS sAd#D\eg)6a"$T>/EJEK~lO@@" )T6M&}:ӕ HZU^[7`_Rk0A}(v$pJ[)rxn+yn n(I֎^tW%m,"xª?W <]s-=Z *y$- #Q첗dw'5ZaLғ)H#pPnlS'fJWZP<7Z&XQ;DSF ]cM(\C`:Φ0Wa8Q8n|s2K/${O=hЕ0qwH:cUD vy f;7}^[w&[dZ4k awtL'N3^ ޹lFѻ MfJsի~Wh/4#LddtY YZ ^(\ՐZuyOukvt1+Ve-XRlA}@dz%\ Aȷ/D9~"8+M!Ku֦p&£c*42Z̉O]'l fE2[XH5yٽ;#Dŗ}JIg Ggr y"4rZ-;G)uGܩb_wNjdhQBTKۓFsb#>)a FghjfK⾉PQiPWBG+I~BaGޑo)׍$Y}}bNGKbJ-zyp `"%WPޠ#8aD& ʼn<X1q;?zl>Gb$ElS56Y]ov7v!5f0ǎ|)i\1l UaqA\-IbFfBs+^Db9+veuE$R1d̰ߗ*co:$ \UzHy2sUl~0XIvK Y,2,G +ˑdh&9MSV,%Tʆ`z%F6 ivf&+IMF7, QI(+QeL(QeD4"ƒ©OYf=vHY>LB6CʆaϳvP&rAfhS խ# TûVPP.{]R7?|h5 RE[KTTv&z_ԟAb GYҢHclkdp&1(O/챷p1y<|I(}ld^P>m1`Do{d+Ep+_tJ5OE'?$BvC{&<3H?^q!.#uUҸS|HY:FڮCyƔƋx fl6!Ҁ}Kۍ$d lΉQe;J}^[=yne"C`qvw;~1P JE(EroSN⠇l~qaN%y2Y I 5ccYCc|wU*9-L_1]#lGb7,Ev FcyTIs[~su*yA%K-/)n%M+ytQwk]Emb|(łơ*Ks.Yp i˾dzV{+zk+GWX߬h:v',>́ګbw^W0( r$Ҷ] MA~UMrڣ/_6\Ɨ2X_Ȓ+=n<]+esUGgpiuC? TUn{V\|HRwAcpVc`X~~.] _/qAC܎Q @C4w!wrnr5OFybSTCbc,yuZ &y&'y}\{]a(#f ~4ȴ;6Y賋 MW !J`؅p0Y&}TŨ31:`LuXvvt'kF-LI`,1?- QDfڑF>~1w r(bfnj &ap4Yb 5 7k)N0I*;DDi jGa]"K?SWʰ4Z 3`xD.FXr>fu(Mţ!tfg pVLj<Ai k±be4z=BDX VT>] m6ˁ)hݚ-xø)F dvcn(?`cnX)4!*.͞&~Si7Xk- > F)}˒ DzCkK)??WʍԐot-/d>/6VM ].!FZeuXH668P בS4TC沺l=snR7̨05nJxy&^inHj0eh\ݞjae3  x)`iP6IŜܘ7[zRU'Nml ZY K[ZvH16GӶG2va' D!3w!s_Wqj4؞E@JSF=-]8H2pG ְkf!k:qц'7:D|9ao~ k0B@Az!Bb#0U;p+ү4s J!q5hl9& #c\L z6kn tu3—;5Q2бpb)wp2f4́ x*ny~T=P8liqdۦsRu8\Vs)>U m Q2)a̅<7]YkQMEJj׊J0We jBiNJhTUA_ڋPwgl陸(2%߹c]:EnG zX5x%p~t;K LE$RCrb$Fݴ_ͬQONGI\YK0letXf-6mV)'l{ bD%I?sKU9Z~3Wֲ.`6y c#SwCzua8tq0|IG]6D9D=Ke-Ǘw'؄oeSDFB900Ę-?<Ǩ`ovweqä(9-"8˻KݍܦKzN G:gS2HW-Pt#DF->sdf߉4}tGgbvDCs.i۴}vo[_%  {A2D /Ika9Fѳ8GY(!`3nPZ1 96Js*֍;Y{q#>cu R S$uGtuD-ЍIKF3h>} {'_] “:6Y/L =Zjo_}RE:;ezQQ wG<^59sj}kk;1MynBfEu-'3qz|F=U!iw &O~:oIرB.n"i}<_/,X??DY4#/{)щG-QQw1%kSL$beq4[6>Q߀g b57FU^QˡQd1GH9>IPb7*l$;D!7c >keUpp45 7Q!o`G IJM5T7f:Ep#=i@HV+YV4:Zm8IF=U"1j'Q*'5?F|XݨsDE!qK;^K\ ¦REI֖ I0Ry1i Pe-? Zzjr‚9>}BHkC HEE8z;k4>g-ي%3(8yh\dK$L$Q5(M ^.܌s2`e)-O#=I M|!W-y%P>: 7u]䣏Pd= 5f2T7y}!8G " Ucfk>aj'wHf6< asM[.؊3QZ^[8{ҧ%/$LAK, , E&8{q˔ߝA-|Qx A 6~u죔7eS`](;3r*tzv W.f^qblzGBЧG)ĉyƾn1Ngu0f5n9HLN13j)W˶zhE +/ʙŢNʌH)c6ݬ3/V]ڱQc1MwN e@t.D)a8q!O(< KFxђA5Z Տ U6Zd(V9([G=UzD*,4B~"J1Hp99eq!+̸l\ɼ6; J>cdm*W Yy荾^ЄVԨź-{jM!;LH X]$c@~-m,i a!dR6;S \%h^)S}ώ N' )n#Ni5KĬK)؜sS.Bjs:s9!Yљ֛,ѳ/ym??~hN>d0c.aB`ڻ b6λ.OJ45%I9/PVRFj^@ih+ GqjoEBR*q4Ũ_UM((OKH 9@Ύα%JsINI^=1 k9SnJ;Y JIJRH8YYQJRÎG'#F 71tA60_?\ػƒ!a͸l*}wFq|$8>&#&@DPc l3G:9Q=)# Κcrejr@d";nNuR dϴ#'Kc? ?f,p7u @3-MwEFF \qoe;7NGKDY;=H6ʄ{b1]bӓ۫_I)5QB5!9s(uH/Hv3_{"ptMc&Ukz+RxS>z ߚXW^09Nn$[5WYFAADbVyKT@EAQ+Xf&0t= 9䯫PbpxJ`eAP}RPxNJ3Dzںg i`Vx@rr@ 3ɡ}e߈u 3ht Uy{,!z&HxjLV @qIF V3m[zZ$9XTED ,+_ yqBKLKIIK%@m" zg2||){[*O֔湳IMSTC(Tyjͩ,S`XVJH1ESbio 5]'Ix+;ՄKt{w:wmK֣*剒Ęl2U//I$J)7M5 }Qk R0*J yÕh+OI.yYwWgwoBpr*;b{v_ZM,NQ/i9!g_JnȘgvѫɩLN5u5/h3 D!E+%oWƓ- ;]e~2ί2eq*F,Pdzeum"ʚJ;ZS%Y3K)&YUWY .k,y+ouj+Nnŕ1O`׵%?f^d\U4 e]"f"Yl!l$=aΊN‡2QQ\OQGQW!j4BGRN YU~޶U{)5/Ux[6y ;]&|O`fH%' O獢_ޅ)`r,POc#'&Y8& &x[66uɊN Q|AJzt}+3~3M5o5d9 k x\{p[ՙC-[^eڎɑGblJĶINUDIF("#h$BI=fQeܟ )"K)HbzfrF 4 EI'S$B %IaKpLu(w3M#eZ(5BT*N.jh78rz-"A҉(nj 2$mT4/BdBTh3$B;O5q*aXwC}(}E^P@e%sS]e J5LZwUb_pі"YQ_<%Vbn/5ަճD b1$)wTPS gkɑXu 4ie8k-!Ci"l-ݐOd;YO1'd:"/2eHP0)>S},*Uiچf䯾ݎ1ǽL1 F,R;+5 Nb$ni4pd OW*VU,ޖZ3n';2L$m#|ҀCof{QUͩI>mU1FT~G@9WuPS\ie#sx8 v!I1|ut`:$wwr\ %I0|u>Ua(l`Lqhs"O7^rNNf<NF2qd-~Og dɣ63J4OTWQ?3jw#~!\Ĉ0؆A%sS#G6g]]c܅z@-ږz]WNgI[V|Wrj,/ͲQZѵη`]GA_l?7-R]0a֞C`5g[F, y>wccjN*ޡ*: ΘUVIR8jv<.mNY`Sf=ʻ:1FhcEӥIX\hKDt)cn+ ѭ*o}Zu9%ܰ4ub;\h@r =+F}4>VFz*k+"]_W'oh+}kdp9?YZ{qh2+yLpvל aGtV A%oТ/'p%`&վq$kj>'x%6fncNϬ20jg([y)! UdW}eli = ) !Hgl)O.K9&+H$Qp@289|c>mrxn^,Q=pؔ$NIABNq-g&Rn5J=]`h[4kRDi?4m[[B=fgg}c6*l:2Cv$yIJw+}{|K*TJc1;D:Ie ;41]0t75d.,ubmSIԜVlF-ђ^;؊vup-=>s%bl4@WutGjyg&PhB?6uQ?"*tfˁ2J$+ؗ7bf*x<^&1^i'm: ϥ,]c{ n4.ega cj0ބOq։*~>q, Qۥ p ai.v'PN{upBv3̫f 7Gca*$ ~b/ z;Un|8(3oeră{A_k`>nqRT_y};(ebȤ\/G!cd+2л󛽰tI9^yV6,Aq;= ̉PNh.$HA'e\讠Ok!{baAdtO""3ﴖ񷆞32Vw vѽɢ*GB2aSR@ňuSmܣb9od*-W^3ח#;&KniղU'OՖ"_TݲSCKd ?x<ӱ4&gHN [BxWG=@Ft\1uN&'ӣJMcqߔsLҵyL⢺/[7c A)4 R&W.9}+U c{@0(~ڔLL:Zgd)!!dY(F#N2̴1&8<3^7Qr;Ӷi^1WvG#5rr^*1}q97sZ:dSN~ xjK9򐱩nkRB+9i E6mw΃r`zZlD7ꆹCr)HPGfrXE9rf\4 (pYebz}_s5Vf2z4 5Ohf =Z-,8}~8}/©+^k>B}3ekExLJ"Eů6Tžc!N" H+ KD>YU92>)C*len_īpU55؉_]F3h1M+=dĉ8B{h|;Dr7WPǯe:lx<Kkj31t8-Q-87r*aC&xnFɜp5P7* /qiH61%q۵< rB誒Į𽿩 "2"5MO M4(i! w0)j2\9SL]&YvztV+g  %]>m[{/oOwh P'pZ"w.J:9_.SeQXX`Jޖ*r8E5JWm,SA߸vkQAqK728h G 1T~` V#Sq[؄k@YAi?ȱxL$Ch1ST#G<9-2o4d5^^ъ{*$BMC=[; vA p?~@ ?@q0ŷ$#:r Ͽ^o'AIi#JMIDf(HRPzR몶VH9j1Į^sЍa?W?{Dv 4olb!y#{s6/Sb6w{9״͝!i(!عnlziX7ǯˡ(#V9) {tHw+*ݫ+9?OH:7ZD&EҲ'[JkvZs% E+J%EU>W5Y4+ 7<󞁺j^-!$T-$='R)Ou|И)截@"΍% :GO2Xra~^'M3r+.8aA2S3`a`;Vr^(J n`xn&K6,4zx|r 5&7|_d2UɉJϮ,3ُWeIhp0jL~Ln'w#th "_xVmPSg |$@E+_*"P,J \TuXaYk:[a:XbGڙθuGGuwY&"ufù=9yySqc)Aw aI;ݡcv}>d~NEDqS8KxîJ>{w/q"pAϓJu:{X> ɮ&Ⓧ6 \NJbKO*Gȭ6 U{p /H~frPv2S%2>ܨ0])?z1g<0x,j,o)BU0mU/dz("ʼu6,hg6>_s-W͵C(--ghb>vjW,QTWT,=lf5 T+S9L}Hs]6LURɻknN\V^6yc{ Wq+]4֢*), RKGyu(QOHޝ>fmYv:-[T:ˏ:4"پ,e]|*BdeӗS1g(Q.m î K7֩Wb#une.,Xq ,Pz!Pcl}䏳'7h9n&L/Q*xKSaiӝ/\y}c:Ii\ 2MK I(f-i0a5y!E[TmIyFWD7n8?;16x\ܨmjbV@> w2kx}nO΢^fcL6SuBƱmP!bIA\53()ԓZvg݃1/p\뉰,c1,ޅ҉WT*aj]&HPY9)"N'Og(p*N%;_2u]CLs#B] 'Fz7wGK4QY$C o:'I-:)GԑIEB'ƩXɻ}ŕx>>Jp3윒״x6Ѵ? Ӄl]cp/Dт-0Zѡy IhcowXdGlnuU$&r^zyn\x~ b% CM?%|rd&.Md⛍s6er\_{M̱|{V/@WkvIxq5 :u^0L~9q;2s*Y:  nxq5 :ug4 xqiU _8CSK&RU+JKu,I-XŽ@md[ZNNLqɓ$J2ZofU*q,))LQ(.MrILלFyF9yol5Mxt G'M>9SI~ % xz<ӄl: F=ʛ."P2Jt:x8Hȝ-yS& ujqI6TwW#L¥B hfIXB (V;m0([ 5G"U"Yⰱ-B@ F56N'2 y(MׅĤdP(K6 MuҖ)6dAдhwzVYi^đعmr_gO~L V|̤7՚ #:%zDό ?_@pɣi1ױ/3I<,O `@kw(Z<} S$ 56FCGgOGr2x"5e}YZ-x>40V}jﵙM.GM =TxQ[LRa ¡Tt̀(Z5bD#PG8tybPzm=eukOR=|}W\y\rry5j*bqYHqH2*Ÿ] ZvZA-*h LpmT20Jr1?P[퍲PrdS0i6tbI搴Nt;hpW:IHpwqR6ي9ΎҞ,TÇ]Av;=>'ŚEtЛG+vpoGnk#(tse&.LkFOLGB~ӜM8d94!G6ex$R}xڄv^ȱM}{hBC=O]Q9cqwv7m8{4= 1eRJJaiP u&74%Z&mDHgx8p~+,A),lwF䈕ɷ||L4IG^3mx6ey;_> 3k[-Ҷ&ևdHV/i5[!߹0Ԁ-iQ\3 p&մ.>ۉ{;5XU%/n[)Z*1'k00Crl5X/|Ox< ӆὢWe+*dƇy:Ƈ%dj'9%$$(LUۈ fҳsn)qx<4 ӆ}mқszWL^<_r,=Ƃ|] '㘬)8yl]҂ɉ`L9fqIQf^5'gQjqiNBHpp|pkpdo5Gj.jx{ui~ IHlI֗`)άJݼ̚ZorA-俓&?ȹ2KAx[ ŜήHl}G:>(3I#?)+5D &_&)b'9$$N.|c3x'_h:Kvs 96Vgd0@8x[i~ Ŝήus.QBK˽~}'gǪ^H&vV`OGEMI#3M b$yN𨨝s+S=Z-6(M^E6-5 NgOWQ`:LAEAAQYufNM:JM1&vvJH6JOÄ1|b6>P fNv_mfR] 0$29)66OJ$t,[p!E3,?5poúE*( g4Zu&|h˜[oZ x1r+j FMwF_`9z@Pt*F\c^ʰ ]JNh, mK&l.?A|>ώMz}/Dj)hƈy-"WhזVGTK :].fEwZtŇoRE_c'y.B4\=ԋ2ˁ18q:^^Q :dGVejISy.P $RVBU;Y>+\ȿ%6jQkwH_2cϨ]?t/c0xL#include ! ;j dpy -:,XMkH$[xePkpǵ&SG,)ζv]]+1'C|FӤ&ߺu]Ow !O"Wѿ@v8hF)AEm=+ߊə&xۺin E 7) NNRۼC  (x[i. *IY% jj IY%Ey%QZؤ&_7,a®` lRD3Y]gw6+F3 j%C[O7ۼ:v84,x[ ؤ&_7,aܝp 'xiN V,y6ZMNGPx[i k7MI+!`xgf=;7'g@~x}RML@Ua  , P uBiI;uE@ /EbB"Bҋx£z`<O=hĈ3}d|(UuQ% %Fb8'kqQiho٫ynD ]"\s| 5.SVl6N }u@3ՄS?-w%tV!Ly;Ez>0R <̍")턑Eñ<}*+u?Ǽfsx}6XV=4%um=gN-U#Wx P] I)=c3jZPMD Bj.QF*#qV̴HobcMq*X|'.2Dv. TX|m~AҰeD3)R\jIW٥99lMjjNAt9[3Aȸ?tOcepwԲTC^N-l{Im |jI& ݑWMftEyk!`.L6.+ɭ1d{7H8ܶa du(F]g17upw=G{ftU{>3d0Xg 9=XV1c.-}x^1>]9}'~~gAhx9y4 %+o2$ob*e p qQJ;畤VLo; f ;.i Y[ԒF_jy@~Nfr_hMɆ c@vOn=V؜^[v^ jD^{EXAFҕ +_W~$Oɹ y`wU (8lf{6m &Yp2-][V`5Z Y:@3(5U(1/%?ש$x;X4b97s` Bצi=9QpQ,*ɎaNnPe|ۏ ~Uƴ8k ԥ {a>ⅆ͒Qi`憘-b8Bf.ΒɽʛO49l-;\HvbҴbVa5NZ{Lx9yt ' l>E$3$(/1'9#59?)+5dzK_VJ:%װG ܜhImLTLS(J-.)QUnz@nl(ZlD+8Ubvn|x[?y4 /*c!x[3yT %+xB}|=\C6w[rpBD]#'kjn~_*1JM~s: ~x=y Le7e̺AxzM,\9“WK qT@R[&wN|TRc5f5-Y 4& mdd4NmsMv(.1x9y 5=jֲLNj֝,!8{7 ғ'hҝ|2Fc0[n+&nd*(q|5l:'jMjニzpeo~ۖ#09xm'l3^Q<=xZms8 BlʀLa3s[[.ql6/%]6$7uvjBVwѣn1ͫNtYR/+2#8 2  dFiG@#b(1"{(zmwl#2gG.Cǣa[|'_~l6xKw0Zr1?š68Eax.gpXwɵÎJ^89QsM~_\WD$qi5ӌlhr`[p6^ g-*q]TiG6eŻ_Lt@:,ʴ6fϰԹ9I?>f:%w<#oa' _͇`]iLU?| A$pAT {:˃pOLH#2HC2s\ /~Kح->13I7Lwu}D aK@fYV9L|v(x,UTcfVj 642Q+M|,iN>a_ՏM.֙'NɃ}+,thٲ>p h_ \*θ_f<{Jq)NRv@#+V$57 yDLK-1*Ĉ]^^*b+D>JA<[k@*}?#Ȼ;NYxzS:x:M[9f#{>'#,#11?עdetA"nqP:248KiWꆔrkobg۫.9u΅>ӱ( OXY Bk5<߷#;eN!Y\ K `&&BXS ,}Nӳu*~F$Ic )NSPpɎK#V3SHaEvٽ-(4gsW+|͎l'!v%NBB ymYA|"X:R .]'sJ=.pʠ$ciq$ (Y=( qR0#+BRDg|n)k |T"l|+#N18i/~rpH5x̑gW\KT9'zf9mx^&W&PLr%Ъx"e/{7Y%\C̔7q6\)֏ xum"gc56Y^ٳVMYVN)ZZtwb Y ?hŏJD q*=~x~c{oL!E_ Zudi>̥z|չhxn_ {Fo6Y KNLrԋ m%}q(TId!ߥ@yP;u`lK*݇&lI#2|<\>~"CDC.}V9X}/;.wJ)嬱|xGFŏW_kX(k'IgxTKOQN)Bшozyh; (BBa@Dɴ8wƈİ%x_`Xֺ071ѝp{ 퀘8ys|=wɯ7cnlޕˣġ.jRn Bp[/VU$Ab/ŔP<K*Vs Eێ4繵bt܉fA㚫|P 'MJl.??GEdxH4ZSU]jet37]SX4/ؘQ9UJ]RIj~Ds4P1Y]m+uzZyEfxWce4b_nΰLً"b,KU-$#%f|`rxQ@R!LΪdX @嚀3?aU\*]|Za^&%Ɋ칠 م dW(8ě*=1l.B @gj隝n 0uƎ_ZrC6#e؎wur#&ݪ?BB?q'T5L^S7notae`hOo(On:#S rJ,)H𱹗Rjd!cbPpR"o$PIv.2?5U]R!V??k!eł"!N.f& cJv^lc=ƅC}gKGB K9kH9TXG&:x.s}e!ZPֽg'th)uNXP8+gݲUG; q yؒ]= 0lpx}Ny*6xuC(I 7/e;*ZX`cbl铟TnR\XZVXRZ#O)Ԁ̪Tor<䳼\YY' Mv7S(4/'?1)'?)5Rʯl,WPZ%ᓚ^  (jjxEť9% wwsP"(514\Px_IU"BIӴެ ]v\2xz\uC!d7٭7e a-J-)-S(J-.),ž$&9Fq)k.NZ. ($:yf6 HSx;Gy܍f1 rrk)䗖(hs)fL.%ީy)9 %!p SӚ33MAU_Ok@:?$Ess+<'kpWq&''Mŝ:<@Zb^ɶn\@TQGBgV'GiM>ÛKPU|30\y6)Ȉd_\Zx\y\V]#sg1hrrk)䗖(ho` drq# pUsqf)hLOM?"#&\dKo5x|AyS͜qAyRx|IyS͜Xッヂ M= ''NS&E(E,@x{|Jy,B{XeK3RrR52S+uԀ"@Hl2Ŭ.<Tx{u,B|Y>nqx{zeC$bͺ,,쓷qHl.R x{!Q8>$_/CK93/94%UA)?) (0[|<݌7(2O~iĒ+OYc*#X (\މKir+P~W\qHlb/& ܤ'1D%%x{zeC0|N~^rf^rNiJRIqq|rQeAI>H|ry1eO.fb*WZퟔ\29%UU9ȭ(7H,QNQPˀJL(->V &g˟%'/gW|݇)8x1^rK\+rR Qd>m+c9CB\#B=\|\O3?' /|*'8'{Fj%̀n„J*݊RS}Ss*'O|J8I?&aAKXj`!po(8G;|RS%q:׃qw"VHȋNnRUnxvivh9m4&  xvip̸9`s ri>?xv!qsdFƌo:92JR+J&o파S>DqqUƻUN^/$:"wB>LCDWoe-}d]I-&ӻx=koG_! %Y m%)A`|YS3ж_W"Mrn,tTWW׻G<`.YUa${@-:?kě4HC7BGx4F62M4ʦOlHFxw G4 hB44o//3Y㣣Fa4_m4[fSFw&eiz|4pRVa8ope4ϧ,\Yh*ٿNFIxFb+hO<}3Zo}H[c< c^g5;O(Lf{-jWˆM`ig>y'㟇_n{{Im(`8D< dSb`|~98iG* CJyZ^MV /ad`зY}#D7#xTq L1դ0醗ߺ"@9B0$_O!oJd`: `'i0S K{dpʕ#Lj# Ck2UG 덆&d-uDɦsx52oI+WIĐZ*B-O|9|YN3hS̖ZSa*Goj35Pm}|n bɸ EG=R|`MX}0|yeK\72TauYaeyDVE,2ΦU@̑b!ٚv̴3p%2lc|̊O֛pDwlKm{R wLfoZ5ÙzG ZdZf65LO !Š70+Tᭊ\il2^w/jVn-mgzz6nB '/\֨j}>Klfx7&X#6wIƻjnkLW%"QjZe.+EF u)ɣ5L%I̟O +nϋ3hݦ/lyAŶR(ނqF1@D;#_#7t oNȨj*wm!P M_/HSl 3u/Ϻ8C]G,9F eMyd5Na&7] z}4:XJTegC& &;#}pUK*(X}==6Y}'x=Ŋ{&c_b넃Eߓ c' D(0)^:_ŝm$pw)!W72ɇA"$NZ(?vfY"3@$7gNZcrZ ɎdGԬm-yQ b6UT1 tsȾXS U3DQ1,d̑*ğ}aCūF>L8Yv4!?O?iiz6NTiB0 AU(rm0Mpc^!{h4̳IgG7eFs㔂RT}Hz> Q e.mI) PMTyɊbPAArvͻWdN}T9gi$ w-C{tlj$(ۥK du;UudJi '\1U6ޞcR$ 95!.ˠDa:*L;zBM5FqK /6ԃ3+CrD>Wy LM5GwW=_PA8<Cs'B (: z_h Zdl)+[*q{ !Z&o=J+nozS-N$+!.z*R;k5o\(#,Km;Jh]:צr``ʼnAR5]r8Oz:N,@0J eY t/G_)Ҟ.I㣏'2Vi 9&g|Քl#}/w&~KJ+\I?5G$DQw(Fƙ t:N2PybTYl_#%<";{L) -j ;QRw#ASWn~Yx'6Nu}tjd)E}S%y#'NΜC%oQ lN:-(~N5MYNoNm΅Γׇ-UNr MY65q&`NB:.lmoR-NuYΙv {b.(_Nǯ{yssmtOhS֦%li9J/:IXԨHoEqnhAi 7D"t$op֬ձ6ж(͒\I.pC>fnFt)y+i&i? ÀlNm7V4 v5-wl~JBkCRPA|98Wk~)lyY e~V"0K7Q[R ).D|+-0_c riFM4UccUux-5)?ᖚijo{P nDG>l)*{Ic1dsBJdT$nQAR@hHƉ8 Nr0Oɔ0*s("@޽$k BԶaR@=7K1>MGC\.JKr+VdZ|-xhʽӔlHkX:[\&p]vX *a48orqJ,i 4ö^Fa 8lNQw! ,c_cLP1`NY$(~" 7YjOIp|\v{0֔cR `.8mxDptSq;ҭEZ-M4qD숯xG vᱦJOT>G$yq1NeBM-6!ԱM.>_ 1ʌJ$oRgbv0&z#*.;on60 ir&.4비MفjEj\vv!)ǝo9 qSHhnBy1 kJ\ p};[bre[`жk}ސDW*8v9}D _];(VT= h^ +Ywh-Ӂl[8R |cD6buxbCKe֌>|@_$J Ngh7EfkX?lNe7tB6\E&*T7_8lJVaH(>yxP4rΰN%2o1 g#9~*d+KeAhko|(tIK#4fqtӇ{ Y /N\ Q QWpL!tYM eaGkD-͠,rm0,%W?Ҋқ':D&h^p?*֬cd ˋ4eH&h<$%!as=Scʡ C@XtY?|$ @$Uxl[yij*#|؝+e̬2me27<#.}!S c[c# Ɛc d|=ҁu8fcdisXzگ4惱 8ÇeT8 })w>wQT  Pc 9$i#+nJ0fA S<JfsHr3[*fMQ$hm#;4 g釛A=Ga癡~fAUy7K~Ǡ&G|`e5;H ۆ'?rPz_#NL3q={gqPo@G &7/ҦVu( ~񨃽MZtyH'>z.̡^l⊒K1`!|Z)7m_atT UG.7PE_L$mTxT8?b` gJ^`GVX)ԩ}v;cYPz؁VMQp־S o!?*Q%ZGKo;N B;J{T>1o ~vhE]=v|n#4 {Dq&gR#G,zfT~~r:JTǩ댆0MgPfu.cG,BփM d~w+ڻGزb K0rvCbE]Aʈ/ G9U wu,Chj+ɺ$.P.- TzuW QQWv [?(K3a;xY4r3ltF*~r uj yo5-f ]x-Wٗz{;7!{ \m #?$\'ɅacK0jȝ 1 bY3si Q1Hܴ溘uKvX@sD%֬4ɈDO]o~2],/>CYҟ7Wta0u/zb||]znY]VMg>_`uc"3$HDa"Z1&ǠtUx7j,M.'#J8H( Sbv gL{jrY0OY67_mlg$mŔZ+ MzdvO;~=އ% y䝁v6TzY)7+ԫ F3\AMrqo ܻb!#TFHhpׂ q̧ pb+`Gs0OL{3 (φrF&锨a(QN[O»K۠[٭GE}9Y qS;zudλ "ie6 "`Q6Gل=}%"9lys|f.M{Mh0etAmO*;M!|`#&3Yr*w&13-Yn]s[ jc]o֩TD9!N?!C\d>ܠ<nt#yuc<7gbot9 &i32@W><0/ LI&%9rL"f"r\c*ˌ|ͫ*AU)hP}3s:(p20 f<>_><`%9ήnC(mLUĤQ.# Yjt@aJvұ]Vlp[mKau@O`5^,#<&ܲlM߼g ŕp?6*OȜ( ]qjGS+YjvwҦk["2ѹ4>#kǹ7<0`D׏An6o[e{ l\Ns K)2&|vOb%K +T*3+ΣP4`i ?iչ@B}8c#ERF[Csxxȣ#y$`xj-< iטE9П8Ujk[>93#mm{-]k&|jVt Zq3࣪mh{g+h4v.ڛ;ejv ~1\\"ѭ-h]FO=X~To !?֢WD@ƹdN#(k|hƾd$KT :o­WUTZp{d!InNjBA<#;18zE xbG q=zȢzb?qd361}tudqw֓j{]eݶƐ]f.FCc{PBO+Ӥ#S]=bwGFU_W1|F`m(t(OovoсW4Hp& Bt6!"Q09ccT ~0,3ˆ )Q! LJ<P4 ?2e4]4_'#"L$ORh\Bwf?fyy1 D@ꆩ;aWJIKJ) IN0@WgcӬaCbPf@ Dg7l<,b`rh΀KÖb'891O76Z0uXcmhϜPT;%Q7WT vS[T$mڢ\:`ǥ? N*ɣ9@Ռ \2bƣnE  /IbLl&d%~m9h܅(M8G&q˓F<;vqQ=5UI4ת} F̥[ǹEbc:i+F?qaĢI!0#)Dۦ)FL5aEbÓR8eAdqєx&3 'Y1ev=͌$'bq{vm2] {*'o(&IpBǞUEF66 NB/#[y6 YpIL{\IumBb]{Cx=T㌨(Tˍ{B}ގO/=^ 2\X2(FEYs9IjG2$~* P\|v}‚sk+=cļZwɯ;χR wyN1Mu8 7' z]TMsA#27$Zg`1t<0yXyZ3  v@*ds*93->SJ$8h;q6aE1Mp12I i ^\u)<0HS|lr{lCn[`(wfHčAN"J!6LZ[T&rGJXhwb̩L eZ =*Wn5ҧOҐG,G@a e3B1FZY9(Vf9duڇ^ .8lȕr<8JS%IBIHq*@Gd'j2թ,39JwլMvpUt),O*haD>\ mEL0sW=nLϏQQ{|E$ef!0\}sFNL279+VkL4ؒG]0"qB̰S.;уhK i__Gk^5$&g+A'p,-M@o3TSwpLeg7LwbLohW훥|/_'0Դ >;[ΖeRY" yl#OV¾fR F)g18CKjd,O#Y^K mwGլʡ PMk4wvD3b.cc/Ur_<:o_-4W-н˜J쬎VX4=ru#<),-ji rsDjpD*L5[Kpvd^ܼY?L/V)Y^g'ڑ~mKh3E([ڢ\^q $'N;س,|\/U-u;8{giz%]{od¬db !zQqY[0̾# p9JOM^-GZk' ?Q o.2|핽WFA_uJ!2ܳAY=ˋ FNls\ 9g.O5V7ޞHŦ1%Tw(Fl],r!u1䰺RG^"dH\=$k\ihg,P6žppp:\\Gb2CvCEJ[!OSr[Cjjpە/,YM=UyS%qL3GPiŌ_UW{ɶ [sAlhی;TްFl.s/yeUE5Ȫje9Zb@ -&.6vx{5eQeP>Z 7l9J+UPb6.ѕF,&Z q+@ʥ1 yz4d+KLW7c&]u1?5WP0yr(./u㌷/7,G`QGR(`[lgg)6[VG=t ~L*qIxRPS d3Rb UE TBOJUc}]P+~r`:M=(8 |,IeIJR\K+,p=E_v=?B_ss-O͠#l/oŽnJ^|O ϮYzǺT[mV4)1F`d|[amM^ooEuеv7_5m?5t^2:2EmX4H?TgfYooCD=ȥ!-Z~^y}0YS<Һlz\K ݯï&9M}w(L]OJVࣅYdf8}mJC+M9GOWWf]%=:G r`=sp?Ux{r l 9)ٓn6.PəVUPPZ9Cd`i 5:߉ͳ䥖CU6gcDEkZo>=V3Cx{ l 9)ٓn65k h&x}ToUVHi+N*&E iqܥ2Mb7v*;?ٵK}uK\! GDH7 ܸ?ZY-7ˉ't >HpKlЋ;^b?Ǽ?^8GIboN= «F9?AXs绻jY;,:a6dH=t46-_}`Gy|w^c 8DrDKP";սeO`qښadprqsi\|Y ŵo2T rLi3gzߗ>6kKĩ<ʹ#F+f;J5IQ`c܍]ǯMx;_޾O**:!D0;zˬ hD3%_祩f݃z+[)v Qo$EajW_ni=UܪN>H Ny!ъe5[! ~ܨBn : nG7h %$ 7v6RVUDPFBї$-@X7NORAǬ>t!#224Ttr3$|o7  c .SyzP8`dYkh ^x+nwqy?>6[1Jxe_HSats'g gng$B33FHAgʴ5 & .`^ >KЛ";cIF9ܪwjzsXRɤ}0ku{NOƣSMF}Iz밣})ص-`y_8kΉxκAg0ڇ5> pH Q z NAw^[^X#-GӽWfiNOO08@R Qo~i8$Okb"FF S= Rov7 +dW]]1͠I&qZyW?VAIebXX:8b/z[9TzQ &|y??\N(/'|-1;RK/4H0!7=;`VgKK䗹໥ A ^sK ;C3FcJa>ȊEQ1W xR 1zÜKDŽdײr>]r7Xp5#$,܇M+vt!`bE+ͺWQ#mVޠz c'^iͱFTV/1$tؒ? C#LAY)-'*mتmE/YX"\$.2$%jSp2+c lFᾡ wu)>j/Բ  q&9 pGn0!6,r\Dž{u"SCZ;+(aig h9,rJԣQ4I7E. ?HBiX'^xIg.- *-8bU!k}.JDc 85Oۣ5)%ZK;4iMߍsdX)fuGNh32+1b; jyX/4|xG S"9#*zI3IxXZJS7XCjޓ7*(j3!v)]:,ȍ4)&J rQHF.l(\8)e hs370\v5+=i*L܃tInxYgsȔ" 18٨r0F N,hC 6\i(EfEvïi|18P솪 !6n-[puM3 J<CE i-TS ұs0`y67±RRM~3LzxĆS@UVkXN̮dA_ӌ8{Z05~wjnswZL~1ʺv,|[֖Eծۿ %d8qФKr\u3j3t}puz؋%}xY1O6ny>$IC[J_g(Jf##CSсa"~C"v]a6Imp/-'OG'G&gϺwב mDA ouMfst@g{; tC_EEyHkpg u3,nj]cQ!_]栢Ă͑{ȵb=F̊eghGf EN[dJ`)/9F "cB2Dİ"DD%U$qiXT@8.KawmSN.V\"`EsĂ \GA,!`#ep e9qBwLMq?:+v-(e2{89H% F> .`O |xqBrwF:~-ItEIí뵕s^&F?HY9O΄Ψe #.SkEE"8.[Η )O" K\udZ#*6s^w{ eIľT[A#dN*ܽ`OޔwG;{fv]zrP(,}RmFdM>l0D9d4< |aPPY?9K $nz8̬}yhO>pK>Ao" B6fK4re  & d:SSua'M4Yg̐)." *yl-FY;LF\nJBq6"t ѵ ZIS,= é3I{ iSpơFNEzy8ny7-l2`"D3 ddQ7ҨB+͓ bSNM:iMJd6>T UdېU6\R؝zHYC }{E6xy"q5%é|iy1\>H\]TA\H/֮di8'LVqzX)ԶU+Ei/%d8|x*%S9rDT z}B<3 )>ݹ4q&^iTk;uO JkI#,k1vz ~u?s٨ V֪x(*/8c,>DTFW$T!u:ՕYj_-| xX{lS58IL| yJ ΫMaF<ǹ/ 0BC1ںVEބ ulj'4U: :mպ1`Ҥjj}Nb'?H<.'snW(0Ca7x坛rq$9Jƃ[!23s8yO<ƮcQؘ1l r8/kdTx_& aPn|jd]a˜iSmC})&H)Ѣ3AzMgH[EHJq@XMI$2ZcƠ~?]떠KYz+eCzt3A}Z(}d>Bl%18.O't$uwKPa;܆MɵM`q6/CIs7#h(I/!i! >N7vMT#ՒzƱrخgyo> FLN(A3]n>KLWaF#88ƿm-=APes|8rUGG״/ /(JrF"VP$ƱX˾Jjw HW6#f?`v[z9쪯&% 3ہ A='h܊V fy{Nr3sy ulGC5U蚪HhDMRs.5[ 7iGrp嗚&!kjc;gxdH49jRֱA֭]ZSx\/ "O+NE¬!+ Ϻ!6f$,G 9H6P%Cc/*2L86 ޚN[53ahoI*qJ:>Ю%ۆf9:̄V^G,S4”JDﻝݹԎAşč0%$Λ\=ȳVCo^s-1K   }WE6P$^pW66$ifqzF',>NH&gk;H#. LRŌ_[٭ŧ*u@W#؝eJ*$hwue}$ñhjlL6HZUUk*S\!F|P6>&b^ 3i>E>NY׃aX&|2YL)ǿcg hTW~=~.~. H8EJ8}0wb#u䧵:#O>`2i=/C0hTdʼʂЗe7lJ ɤ!a&N u4X7F|!N[(VW G߱t"nKltlOKş96xu]#2#߶tcb$m+zh$bVYR[bH؛ Ϫ}N'9+HN-~/N0UZܲg+.#]}K.~9#.]) ݗ#NEi?9mL7K/fwm6>0<@W7\w[٥U.S$a^KQԸ$HKln2݈?iЉ4Uce!! S3Y榈LTB{D;qr85Ҥ\s x-wkCΟ[3[!y'ٽ.uK;4 "96{7ߞYȭK-xf=1дQ,{eA$jאHZeL7)¹Ș̗J>_%*q mh K,F(%o U0_.3'; dbـ΢EtbdRx܎hK-ex?%/?b׎#)!\ȱ JVvdKF?|Dc1lE\_˖\[3Ÿu(*`&HN\PEAG x;tHf.MN}-<-sy49A% Qj~ SKJ J2RKK2'wȅN1YRprR3692jNޫ-;;fuc&錛r1N>lvk"s{,u*LON(Pa8`a`E>9PfhvGdrRfa-69XlbU0}XL-Vb焚-V7]^nMNDPU0ɹ}_XWZ T9_r?6ɉF-d&a\Qa4Y2w2_5Pu$eIqjsǚ!/û憃., Z5_~biSm`ME%dIJF^8/*.,j)\TPW-YF&\>P[32f~5s-$1s;_ԭ4ա!0us4g{h "4@y(o:qSO4OM\8mja82\,{JqIoIS1>.D^q=cptH\ r Zjl;=C2)ڰF ^=E@ DM D_JrƠJJr>ά,T]6X.-_Ҕ 5{ROS` q)}*!GmD =)dseyY^XŊVZ'O--Dǹ M8)$pO%+ kfe̤^jMvu%dY'(d~xh&[;TY9ՂVWFin7R-VPB٫[ }mߩQgpS2gNV0c!T@aVѥuZp 2Ҋ^̊/Ds]J]& }_ᗇGXl^E{jM'⼤Dz6t.oys'-GkM1qbŌw=~D3v[=偃=ū=/e֩z47>ðDHS\E9 i+ֳqNF-SUeh9k{ n-wéϋ9NR"ǫq[Kfqfk쎈D%?(K-$얥(Dm2 l$ƅ^^qbcN;,wVl6B{%Jp{ƀ,l_;m@Fĕ6fIN$Uv#}u˦/mkoM5tsFF#&)` yrVZC=FMhȻ WDBԯ4t!b珱T'9y s>`QTWr+v6F3™DDPB|,G# Zl[#}5GvUN:Vxx-J2v6D2sp2^īF\.DVoؤo 5f=._{T䓓,1t6+(d_ȹyՊ" 9bhfOIoO]qf7QYWN41{la@c6?j7ь 鈄cf؍:p9^9[2I|$"KXܲF*qN91GVKUCҷ1ݍ$Svx{c /%&ۜ)ss$?| x*/GXan=7pWJ P_Qz1o@9x] W'snvg1&s8m#\XS+'L,=LQzr[61E J.N PPPqpw vpsqQh&!RKKv,--NLOՙlY)N#E>TC& naZds'0U|bXr|w<0T|3sX(PPgl}-4 Ҋ Ey%0dREASSAK ((O(4(<fݜ,^(gxq+ 28C]#=\|\2BS+'?g<߀*0OQsGq ԒҢ<ƀxײFIrs~^IjĚɍLf&N>$. Il&w: O>(#\XZ j@m:r1n.^Wy)9:pQ$`niN@iPOj^:DQzDfr [dELLeaך\+l8ypdÍ")Z!! ZΩE% lԒlk`AUl.jl ҜL`X%Ļ뗟Njy%A9/DIL~59Ld1AŜc &MvUk&FN&N|RVD(( Cx]xd1`H&ob1-$IĒ̪T,›}';oVP`@ZdsRv2On+ߎusk]U&;rl.vaaܼu B;xx[q NRKm,095Xd~NZN> 1ٞuXid<v<ij2Mv(d.sj73 f)hd$9gN%{Ncss#axvqy 6o6cacɥV %nHxk]ԸiWfs3+uaxk] ӆ_l1a\iؽ]k_ xk]l1+6F&U\&m,*nn~/-4~fɕݛYX 4'7`׳\Z !AޮN^!@Z韔\b?9?CĂ̼toMW0 N Pkt J6 & ~!Fy.%U y.Sd+L",llX'EDN639k 8Ed$OcU&gDUM~>YRl1ZM`:~$ 4&3)l~[)Ӎ1>GnXx{b 'L3BrxV]L[eihKS:?@ Ltp-,8)T8Qzp)S ֽ^xfƋ^5,1,ћ]̐ex1MN[8zBQҠ3!G,38=p1&*Gay9-FY&YOײhDae:9TRyQ#3cf?W*)mT m2Lng킠Jsh8h]%mu-97sقUlQrPqjxd!q=qqY?#\,%s=4ש~ ܝ%pnp;i c8K;($#bFy!ڬaΆ =|]}2SЍ6R_蕚!V`+Ehoq^݂V.ɥ 6WSn׆4fS["F^=$lwrQ)lDp*;bj34OQl}3 w)5re m Zuܩz xzHj%F@2X8b@[Ϧ'Iď0IB;^-Lh<cW}* ʧ+wxq4%uNF@X=L9MGUPγ6`26Я(SWr1 ~~tDO$Y]&Js7ڔ?;Bb=A'u&!:8"fTyP!8_U [7Ō-Z)rS7^X&C[$?N^%QJM$]"9Y' 9 ݢ9N uٌZbP5R3> Y*lszX82Լ ݙŔ D0#f1k 7%wqBTd1b]hrBBHgVۘ+ȔoU%@(&J MH;惹1-8Ǽ=87%#܂ͤl`1M^>3  ؚx8h!0߀RJA!#YWd<ԱK3@U>cj2Hr [> Mxޠ2X_A w(n:Z!"iLJ_&(x{B Eʙy9) JIY8t|rFjrdF~ɝm bԔɹ_ lndĈ|f,7.a߼Ǟ p u.\h}4.U@ IKn v#`1"1lSn2(vVc( 8" 5x`flo`/14OHJhFMP+yB8#}{l'o [dL)0۶ P\nx{" y68f1xVmoFl9N%\)" ,{O1 "ﺗ]{IrU fggyfY^W.$1K'$-N']yBS` ?AmfY!z{\qGK*`F|k2=ߜM;GҶ̤{mubijr@5v;A"]P0bG7u:Q&q Ra}]408y| sb8O"XN.rbL PUxTXSkս+*_ҹ7G/J*7sT  pNE ^F]K8W>tn;|ЬSńZ԰}ugnIJQViv\08HkDaQM9,ӵ?]yr3"Xp$odIV{MgSBeM3Qrjߕxc2ldwBGƴzWon ylӼ"_a:JZͥuh>/?&ad-vX.gu='Nj{L9R .sZPYnZ }ZͰǗIy뵉GbEyNv<%Vb_ 7hɖAq_i ԅt7t62ѳCw טXZgjpTj&+{8ͦk+Ihnr-U+&!\xu u_1M8>7'|ʎ5x6͊U_];Uwd*Hfg\[oϞ`?RG61&|#h%$/AxY|p39 _DQK>kKZS@[D_!{UCUMQ}Տ"W7iQo7+- xN@bFFj(; .Xj2HMgHl 5|>.L|gJ!`4?{|:8VAg0Y@!@|D8lpZkbw*¢ebD kmz!@ky,vkyŭfo:t!݀&g0,P.\E$})/q1]f$GI YKY:Fu"zCޢ  &o+1 Dсo`p:zQ|!Hސh5+vlaI4(Td~gCls+6-ScK. WZʲ*+ 32-VffzW6&0~] !x[ت`ɞLli 0h**{8FhrMVgLm&{[g4Yf0+u.~nV@OG߽QwWFW K>UHػ<,VWz{k`N$uMk{Id[5hd\F7rxjȎ.8 d.CE)9pRSpDmiI (`k'p 2|D".Qm}PRb5g4`^>7q-og $ G8$N*(.'I6lOYEx>k 08\0c d,i'IԞ2&c*'D8n4fOi=1> 7[7Aj{g'qކQP@^/30궠JE}[88`z2$  J ()I"F/r cj }vtϬE%b[Pcr4x8EA|8=lQ~ R!@GXg,sbJ@ut5*8N1r)8'H :>(hԹ"WKЈT^n71LV:>76?kAc_>qě,AcQ>l&as&䡪<|qs reH|+ɾ!NDuϵGeSvkhb'W@%;;%<.+},?)Rh,9=< 3cޱ>-[zetgn&z Ś[2]fV" 8J7vJ-VJrbbE)WN98x#̐^KO0{zƆap{6 o{MՒV- 0\v])c˪nɰhTݖyeӱKYP.8w Yu ()oa0G%UЛiwWT3&q2Eu;gBG0dOX߹`\z0{StRD\!س$$L&2YaCki ԕ45L*NVHB8ҀpN[GJ*8gA?'(%_=$Y8GpL >o@j㾼\G'klc4sH9NH&u,4\TL-]*sct蜵[|ƾť}FILTdJiBkׄq5*bc(wIG)Ŋ}a%Dž0+zxȢCf3N\znM*9Sϓ Y2 m-s|т$xE٠w?[<koZTEx Ж(csspflcCKj\YC 5RrYbb9It|GϴX.7'#I WCS/l[lnGcou7b'"!lQe 9RKqID<֕ =bLEpV$ &`(X&xː5<Լ d7AߥڇbS׌Ԛ{YknF_.}̷s/z~gXz~[1~LcB&^$eK+*-5PWA߯kueh۳SDhQLf"ŬuTZL*#aN `ru|Ho5ۙ9<|.;8tIY;&'r;l_<0;L z$qߠ~=66Edc4Y\GqFthح/Nj@lӮ,J1y̍Z kL ?1 h bZi;4JY$"j"ȿhh)PrgN}? 7kia-kl0e,ӄ+ʫ, \ZmL4hg9j;×N qLhE[&1PW0T-;_"}ѤOH4p;n1G[~?b|az>J' \^Ưo$NK $i&)'!Go;-'&c[̌o &0d:٣ 0?fywWHdx|/@1 $\N 78<Aˡ 8}f>F2%iұy0qr@0yl clrоD.Y}}8 ̔Me3Ds?8@G?-t}O@"+p;-AI2lT½ŀ!YRQվvCLrD#?;N{^'S4v~;MJ)M, iqvvh¹,6?]nS4;m D F✰峳ư-Ѐ]uEv=ѷS3uWR n|O"5t1ǚFE@n^n)GaZ M`iό.mpեʈL_sDL6Eu%m|.;/4hv+]n@/@ApDcoYFV,{:I<NE-Q͍q8HCUQ=G+4ow7ImG?|}~cV[?.omQv1: vChV{J-SC.sP9e35àpԊ)6ESu9-!l,V0!90vם8iau ~;Ӛ99>|ܜɾt1iL ='S 9D8-$H}GG哵HYv#kJ J#b_ F0lur H7~ܸZPr~qpywo.zX .b_G$P؁ \kn0L!18p"n1MUͬ, s1 6|aci*4>LȠN E¾Rc<Lh5ɺm^c e˶!yY`Φkl`pu<=TjgE&\,\İ\*!J)t`/8_}rBjsM[Ȗc1C2xj]JbߒX3-V+C>ob38cz{nJ+;YZ>n 4MDjdHq?t/)nFL1*biT,%Ů$(]DiY|]bVKh`΁W a>"2VPK vB䌯\a" @ E0i"bsfr$= 0Oe hӔ`klM+O'z6zkm=?IWy 2x)U OvJvϙ䭱5]S5)glj~5cOĒٙ3Ae`>tW-|Wwli{gQ.+ב+մdlPΗv@%g{ic-ZOAVkIec vHC;7H ΩUlfFzswi!:VG<ɍe}b`Q f&hvZjy)P*y0ɥ*ʶ-6 K,KIȴIhTh;)NwWxg[ .bq8QE)aﵘs)BVD Z׌]kT ]˝FFBزvecG;(U]Lg& oȡ9[[uNyiCf^Fx>_<> lRYK -S,cA4FM`.gTӭb1DOf=ӑ$ Wəi2<+|iϔMќS}P.'T D!ϳ_.IνZOJ,I?e oqf7 ߦ߼ܒѡo6gimvycݶM~n.l{u%@ lޡgoo!-Չ?sZ5&f{0P9“P+"En<o̺u(]p-)q$zȺ}-zE< .D{-6~E:e-GwOBǜE.3{3]rַySQx}e aM8Bʡя_K ttn`-bs߸ cӞqSWp$f*_qDo^xG_leGwTNWSWl7jY^&"96bH֯&cZRV[N|ڕUK=^6i C_ț1ūmF'M!lVV,ua]7 } a8[* : bgt48V{'Wv! ?c㍨ǟk2OkE鵛fwi\4^9i{9ou~d.F!=7~K"=x71G|KamsQH_Ҿ۞6ʗR_FңkdzǪt y{& ]AST]MiI7Tǐkp6 z[/V&#,Vn # Z1*)w OVh|i20ƑTY*Rb%\m⫦IvC<{|#q8zþUėSg{]@bo!R:*J3E:ʈ)弁G T0 oSLJ1!T 2}5ۯz:\&?TOUJf4rtjjtկ*$ڠ /(LnFku/ٳR~J&y3#Fd.NYLHqƽ/l؃1߽g_=.=W%a/B;,:mR٪'^{yήckfs.5{`9y0E;OY\ĶHUoΣS(´Cp~CXU v̓9V&{6`߿ T]_YC^fz^kQhҼ8VY&$Uev]Fm*Z%r).l'ND-g:3T'q3kYv\[[#o]^Ē\G `k{b#ѭ|_61îENڷY_96M_ɞ>'}&Y_ǏU""P}G62ʢʈ&?mFGVQ11".~難 dxP\["*]'Ȧ*a+ae2 '(i8y1l&2a1"G۞]},Y'?H=a_ӛl0zk ul5;د |z1cBG `:e!X_Br2csxen<4LKZ w98dr9p5a3~X/$TA+ %~3W+;EF AEx[JG?R+XB,*Y͉`b'X3kgf]UAo4Z^ otߟZ܊Z^A\+>s5hKC]@7J:p&3vz_^w"lp%u}^Q$g VTM^!]vf)lYw8(6p獋FsxoN[o:+KI~Qb<+|S8ɻIѻzP* $$Fa1.ڱ8+si*Wr1_`rMl&dzʗ44G12^;W۬ԕ扉G4S8wȞiĠ(n[26)\>;/{RÞSTR'hpmj]Nץ[^Ph`${5BX.̎*u$-Vy(1x|䈋s;ţt]:& ؟qN+(_%߿{ڧэ0 co'l|y*(, nѱ ?Wx)cU54Z!#t*eJ EM F5cتNtA\^O=[^_݃{sly}oւ>NjvɻfUӊڋ8v} <(P݉ӞǔiE/ݰ{,IßqҰ(iXƋ}3I;r\1ݲ{ea&n.`DI,)5v7ubl{MW*]MJ>t.2;SCP-ZW2o$?zEf`O4Pԛ>72ZL/et0::wx$ f (VR^{;ٜq%H?T鶪y(NN%F]r"%;|!G!H$G$6WEoR0ۘƧvn K%m{cҝ&]WdiJLSQrs Ӏ)<h#$#Js(YP\m^$t_&VT5C:8R;ؓlELvxM-1 N58؟+7!<Ё1K6 K[zy!FGa>Xͮ¤ilDoD3 Pjw$̨5ЈNdޫih|`0DdggEh̄@G uR 9ݫ0_;Ơ!r8.AZP,5.ImA7wW%j+!,Ad6 쭥mi۫R.}(@+^v(9x0'XN( G`^EөF@^[clG?n|}"Q>Pm+F'2"ڄ{PTLXu3 K^K%V;[_Tq5 oY]0-)- "z?ݼXg|1b<[撶Qn y}ඳcz&jdG#e:_Q‹y]x,U Hob9_RB8:|vYUCG$`λ)hLL\U=QZQWtfY#_gs:_֍X({+sn,WI|o"ЪVI5b?ZΎ\Pa G/얟o砼P)R,T؈TXl}U1t *6lyO.1B0Cf'!ăߏ֎],fgxftIi{Дb `=Ҋa w: 4瘮fx49&!YuhsS`x.>p5kR\8#O±VQkh0eۇ_;ŢUeGF~"'۟#\JS}q`^()E4eO1Iu5{u-S,w>z6&i܃ϣʚa4~ )_: ϲ͗6O fa=/e!J3 sAUo|=PL[9,]2EE[kvb jRoӧٹ,-B!_b_]@Cƃh⸦;LѫtʈjHuYGoov~8Ҧf&*Qs|F -n2؁5˔f.c.fZ?F o-DzLVceTB\xk\W)qmOgďF\" #)]"e #Qӿ`pe'1$xaf/8d:"a+" %uUY,=_\M8lv4#7ODvB-øy+W9J9qp7: Tc0۲'X[k C$PC'"Q= 7Bf>=k̩oF#3#w-V;}γaI7N:IۀsJ3[گ^PmKk-!(ъ>/j|d( Kv=]Z'!?Ak+1 LA> }&|M Аa;:hnِbYG"Ԧ;c%p%4ß>VZo SF{`# XZ#$]? 65N,.)3$ɿj[h˖Vea]D+)i~We%c3g)k'Z%,hd1i]kp) F i*Jꐨ%r_$"Oy`|V~3ϫx8HX&32 f@r jƳEF۶jnGM$  Zd{W*X_]R>'-*ssYIZ )N.\wvӬ;쮖CX=>~X?H:tD* {(Bw8bxM\PVℶk;#δ~O.9& +5 [M/eWV |g_KG\dHu )M`M0ĩΨZy:$*-Bn g@$E3Uq IC߫rKË_F0gI2s=`2``L\< D\g=*ʲчGo*NTEh&=Q)B$yv S'2ˑ84z ILF]0Į ASa`T`A0KJȧ=#Vfޔ9(:<:˶/L *DΰV9KbХS# RiqL :D Mhp G/Sʫ[Wr7 zF#zz޹J;vg-K.4#Aacui7svcp(WsFU+nX7O~^aɠ<}篎.sus bv(@s5Yg}Or&jXrh^rmȓFJlD;QiV*FeӊصKMz oYywNWE451Wl-yG8gs])C[ B|E޷UנW8xAͥ-0FnB.:)W8# /Z]  8xw^6[+hXZFYMO w^u׍6Z&=;ݬh. qipاS,ޮp#HtTZ-2t-tdr.jh5tbBXї?nyݗI/` ~Og{&TT֊`-i9ɼN"FlN EN{v4z+|$Zdi8L"x5X.gY4|E-=@4N`<ZQ+'{x^>tY"h"FPsZ,(k&VC]Udun^U}nD 7UHLJ.^! U n `.(2r<SAl3h2 մ:kkAksꂂL?%|jafE{r^aJUQ-'5Dщ*|~x<dP dՓe0*ffPfYf78f NIg$, Ix[C {oc\0yw끦ҜI9I: 9.:\P6>B|W/)ͅ|>\f'J@c&+gM.;2.&&5Db!!.Hwλ9ϜNNf[y}C(Ut aJ G#A| &A:h4N$;-Ij^@'ۣ|l\p(~73|>3EIAhᖋJLYOVGq (m/nzlF{*RZ\^)+#Nv1pj0Ox7*; ! iDϢ<%.UMK\/k"bC_^3ᕷ>ԡEvzkanxN>cwXp,$ 3 "=dr+@G[= -硈~&cTkjﬖ]pc!q1yX__<lG 0Ӄ  G_cc ,dI{ڃ>2dʁa;a-'N-!hi'aXYBFQ"c\Å`?lo`E q|6F䇿3nfmZS]l- DzB0%rO>繆b Gx| t[EyHnYrd-v8N"21K&HY~EdI$i,syI@7|4904K2>C3?=aW[$=92u ^Uݺuu~&_ ӄZֶ eD"h*6^ja88adZr:##9ҁnBVSIlh7{)'KBjU*w:F41pjT|W NGIomB^6N[^ֹ@ٰo|7e?ӆZX/U!{iS;rtPVvo/:_d[]3!bt (|kMRx`KG# lgc=F]3 hDh`Ͻkpe pA~f1^PRA#;&D V8}2;^d B*|zO%_mx#2˃ohr٭&ݍpAvF+\acikWUqdHl3xT)v*F ِ3c^sNkخRY,IO`E {c)lC@pk&x9 ϰ@afa7nj7bּܱ='`wTgOD j$bb'p0l_-4$}9#p+B8*s`Opx# =\ӡE=L'_s ޭR/cIL#PBp˘4{R8^w1iŽ%|8I+ܛw=Xd\ sН3k10Isڵ ϚW yBLIPhEؒ h<8C;|xAt4z'} k}g6R,*I0Js¾L} '($<(k^Tǫ,ЌAo2PiQ0j;v5FCK4^_7W{@Ӆ'b,buwYOTYX*i$H[K]H|F{9wm4AJ}12+tMxAk>}} Nb/cQ5waJn%iknKS k8DZx1U PuU  N]VS҂V%3^8YQSZTΞ=u6y0-?v/h477#t%rFwSCM-Q1z1O{<ȦX!}F^Eb'2"tjx˳{tPxo5,^*'hpl6Ozc;FJD8yy]|ܰ\~36_t)}ͬ/bE'YY*( &$Hc2* +p]h-pNizpv:3 ?XacdDFc+nq9"KG x%'gBxHxecDDPq rk8:X"Z(ؒٸl?5ھW>ię\w p< Sƃ'mE*zRWM!{'2`#CavTE°=;NF&߉?-;h>h4D={ xTH f=U7Jw56 &s}29ƪX<Bf47$8$oe.>Z"d4EolA X$֝-Ps 4VrY$frܝM 5;jmA^Ob6B|x:9G|aˁi9 6h6=l-siQI}`+ŕ1mw dk#xZ#@˖Jxu{;͎NO`wُ#W"[- .;KC2= 6~E?I1ԒS8Y_$!5HޮJIL俊f,53Lp._VH۝X>MЖ"Rk=IjmQO nuh<}љ>HȄ&ͼ1&ӫq[\(Pm]tʓ69J8Q[,˳hÃ$MD[m"(46BV( {E<>/ĴTVZuErW.#,g31 Y6f2Ihi"lD\رƉ-MU,J=a1lB=8$J>W ,g5gkٗe;:hׂhV>{@7Ayo3I"mOD/DqKK5]cP- XgM#{1!'<eZ$Sqcn*_gŰkMycJ¡'1'&8Ա 0 = .6< `,gQoDd&$JfЪ@d1#N NML6Ƃ2{Wؖ,b`v8G\b֏D@d DX?.]$>7{Yo$Bou.\j8MM.3>`WB%$[anwߏ8qv4C"삝OD&zH*-:0VkB|)p d2«1D)Kb "tcYQ[*)*e8bP%:{4#{K/X@6-h=<ẫ`&~i< #+̦I̗43S N:yE \#ZN]ę)%5 "IzATpw&)XI 3NEX%M14-OHDI.'7$Cc+%Jʑ["f~]VX/HGD%OQE k"ɃIщ&LK^{x3eGD)<1ip*+xʑd&rRuh鈝 E|HBqs"*|ܮy؈|S0> d41 5?o%칩%MZ`Wű]GK} >t|?>?S|=AmԀS;v5sIJ(}␑X!ͥŀh?RlT,2?R wVB-y7P<'mTE a5W;2  VDuQm)c&m4:tk$$^DC{;QpbE T8 =$a+;k'긂p3c4\NXŹ$ e{;4I%e`۞D4쪐=j{<>?;$Aɵl0/F< mElsf)r.QG%=e0KBN7ul.`b,pk9aR]0Zx%:7` /ԋD>#ӿ!'cɯtN{Od Pҏ '#p΂SW",HmmWQ.V&5hH$,kr.Wv{q~A|d`"V1M?U$/ǽNѤWDf_€UɁ~q*["tG%e%BLG^%w c$?ѳ;}m{o/aM5Y]{ۉ3x+Ŋ[bU,4V4*x 5pmZ@nr`to+;#Ք7Y+n' Wf`%r}|5 T^?3t:p87p켻Nຟļi»0w9ղç}wç.H0gobe J=DB1tS$h/*їMc;ΦzT O|=ɗSt/*Z<8W% }!a{JSn,*W;~"م`O=脿#f[WCe[X 3|Z +~`H0/g4 +ց3dSEKB#`zDh8 x~s:Gj߲Gk%lF- `GXnmǮъeN sQl7YHcw^ˤUOtf^Yq-+?{6=nNx^ GK;=(oK.+\MO^Oer  m jɜ^hO58]N:Shn?>LqXC틓GoSByzZW]j)ΓA`u&nZ)UtET.5UJrЕ9JnK2*3Pp./mwWs0%G׀&t$>m!vL aƆ |uQ lh?FBDM <ڠCTf_z=x/4?ˉ {϶/W}-Avuh^{ɇm+!c\K|DyMɊ{eL]Y^9w䫼K!%grŢZ?)yNaA5I `#V/_-vS"#Dav*/8+.yl/Ci ȩQqWqڈbEIO6D<$ vx"ȋy3_ZV oET\sbLpJT)$aZyHtX/;^Yd Ifڒ-@Bk]b_\U _KoR׽ݣw!ebxC7 S:pMʠtlZ⪡>xA9땜a=yze"ML/碇<Œ<-_L(Esvs_i+g.pPiZCJU᷊eW') {}+W) %X[qxP OPM|p7;maҡ-}௔=~R^¾L\/`c Cxm1frH˄Q+w,`y7+w w- LOa8?n*cH-ڥX/RJpEz JZ)tN-?e*7e0Gc‡<?\V…O9 ?nkoP$p-vYcw 73:MK0HR@1 3:Sw|6VQP|wE7ޕ&OBY"e-kK-LJʷ:ؑJ4? y}|fJ-|͗Cts!TX} a2/*ɱm_V/ q0%[/*~nĸkgHj(鷞%"NUKU0^:Ah;_ SAƥ14͙Әy7~2r'ә\';R d0dSG` %XD̜7PΘl]u-MnsG3uo F/LU=-x|T)ǭb||se1W%J0]P0ʒiX 4w VʢMplET>ɇP.q qDd1VrLcԈ&.XdЄ1'r~b*o8pL.\{s6xϙV/.29 KL+R1x$c)&6ϡxWqw,bg ɼeq l-R'ˢMy=$},CҽA/"!-OC/qglYא0 P^@ ]Nǔe_ȕܩ;˘\rCyLA%gDW(@ow/)7 ;{:i&WMK)͸rwaY>sJ㏥ w92 05x[Eݻ*D5L-?LjSZ0u6fF1xx rƙK]”f'#_߃Rh QJQZW `Xs*ж`ƃb Pq:-S "B!4 q'7W84pADOo*g1w#rF)gV-XsBB:KHPz:Q=5Gvubk%y"M+VIɿS-}Q:y#9VAV]=+d/!vlE0f:zj]fN&0#dhOE^zӐPD|ujGNܼ*F-zdlS,&dNۥ{^ b&LHʲUܗLP!SA#+J0}  ҥ;:V.\Nnv.dk#.wg7X27mNfA1"DX=ηWnԩc JAb5ZP%#NMH ]p5^3w)m%śψIܒ*H/Ju옉Q40{iV41TSb#p__2Bt+n\!~AA;Q˴uTxkam:ZZmƆ*sG`$⛲5sV3v nfڿURDoD#Quz =T^c"{=؋[O72\tmUe`"t*c#ʅRR*f /%wK8*}ay97k[UJ3F xPgmI3IuJ8M&&X4PϽ)MQaz?;#6oKxȨQAVMj}}}iEPHNo|GhK*vAunQzRpecIIjqIbIf~YᲓ7$2rNޓ:Yd@UZe6I<yhTx;p F ߊo`zr hyxV]lUm./PfٖV)J(ZS!m;mW3Z}0D$_`j1&>QBVbńDF;vW av{sfǿ~;3Z^}[#}UHƻ6i!)!(]* ƥW#$p>o[g L6BW^lϗEqtc'g\"‡0bWOzTW1!źhW ŴD$MH:^:ө i*-%IŻ, Ѫjm6igf,j0ivǒ}ϙD{6p8](v?sŲ;sH-ؓйsJНP~av*Q-,aSez# =J3V2i5}^fnqe3/^\3j:h6Ҕ=YxWu/'{6#xވ]rU5*:?F&hC 8[3$ddVqMdRHOSI,yM9$uhӪQM3)O!!&% kVPz7U6ݝLB*=c8 O ;`fK zCtyE >mx180\'=ڈa?(<+zܸ!l'z 6^fUkU,\i%:[܄/6ht;a3gYz3[yMi|wŠ"Z |dyӔB?…8Wa7G>e֭;ֶTgG"mik;QD٢ PQY6NӵN+fN>PF\a*ee3*26\ ƩXR) _x|e1 'HN֓'/[SSAMMAqrdb?\.dג@$S-|^ɧj6$0!dlyɇk6K(`Q✬Z4)'?iE^F'?Hќ`37Ci9 x|1 4 * bu2SR r *L B%%IPɺd7NWi%Fƶ)SL^2qy'oh29ga'^ cd--wnl:SdZIrqpisb'l^ҫ?<1"x|eq :f\ Z 9% Z\E%Ey ))ީy)9!ޮ~.A: @1:S4 * bu2SR r *L B%%IPɺd7NWi%FƶߤcnTLW4ym:&͏g޼cJ~Mo*x}TmLU}B۵oоSZV̱v|sPPv0 8K7df zKfL`Qj@a h)ͽyyι眻.~8"CfܐRM_Sk9b58N. 0 1$KScig\&+:r&I Lؔcr@ }FpH@Ik(HU M.E P $i+"8zm܃ bR]pޯ}OB\bW41ՕjG] mn7ģHW{+8hӶ*'+>ZW ײܺ{f >-L_a^_? ? J8-%RYg6 *`V}ej):yl.S4|(RDr],_Nxߵ~vބ_W:C^Vƌͮbk{vS,FTAKwy _1`L +W(َ$TOwK]I!ߌ-MZc*̠P֞Cm7i~^/o3'ASBJ IgKۡ*?3"goxB%Ñs05!%T0W\J·ɠFߑ`I皭J3)!wu-ܽsm+%@ߗ2rKX\QyMY Tw6kYH&7MpOp%2EgFa #Zí㱤h0GAx8/Ćja.|1;M8&&]SŎ>.xbdNp7dy wG:`2x dU×S\X)P< `I{8 4 XgV̵EgYEaղLt[ʠVHE@.XNuE+A&d(+y^]m%3Gf?þ5= ,(B]Kd'r QῼF8)zc㽥B6BIii㝠>@5G~%,N'߳Iu^5Ŋ -x< xSUߥI҅R $)Mh ,4m#i(e1˨hFAgqQ;8At(sν77K[{S߻gϵ_8 `P?\-q{]CWb5Íl);p*4)C$1OhWG!!:Mi) $}Fa[ty If$Ȅ4jRutн jZm[p <22Mŀ[\8#;\>o ٺuEP:hUf[p1q 0G2:(΍( t5lIF5<ңD8p3OgA>g2m^ .yL[rzΐ59CًEJ흆&GFG2hVD" _fJ.aIwVn,ސԀ3{̗* `0;+nk/k i <)K &g_Ov:u#0C\voS±sKIL(}nvKlGD8th#YhоKuKC@n3<MYը}xu S9K`آ]%wFx(3 C#6\j|h6>/;W*">PuGћ{\'bK@*InU8= b0hS & +nާVk=h 0l 3ce 2x4@a! 7noŐ: fPe25J:$I\H%AZ[ ss8rUM>4B7̆%NBU;w"] 5`-|<?WTR1 a"=C:aaEPZ?ǥ,W2'Bv5 D@Kgd$oKBcA3 #@󒥓ys xKڶ[k)EV_LUQMzФAOӍi%BvUɮ_b! {BX *CdX{KPru;L)֕A EDx "X^P&(-0C~pવZܽ{}^r]nW3H9B|pqj@OEU:BY_~`2&:얋͎Ɩy563j&te%2"r}Q9{2,KSjD 1JET>୒RNW!PUUJR"1O%拓gë}kaGU9k^`U𗪂m\ Ârzc4 >%E/ke-p 6,?mx{Jkp6:8h]{zsr|>F91s!YZ4hz J8ϓ $8Vw/ap_nVkZ%ԗ  O]]0?1ocFO))ڰn6.C%P1.xgωzT6|-ԎB׾* 7NܮoCt= ;fƸNq\~'o[X|eavil13 /! )6@vXK mWz0x"$/!; 3dgɁwDۥ]tޘ zgM ,8pfF&xY5-$B&0X&4Z_okhfMM& $nDZK}t0!㭳6Q1h^fR k7466G02HyCˉaM`zvŜu4'\RgeW+-=}sh*-9E>KZ EI~>^nQ[cU5̠Nc19vY9Lc9,,]g]þ 㵘RAGgPe~x#xЊHͭsѺGm\of=*%hvYh'-n8\1o$%E~΢ ۭY֞=}5^ :0߇X2bwhs6Coo6ZY(#q{bVp[-bxn +];ܵ h, "/54[3vb%d]-[rJwW5:eRoU S\5BjIK1UJb hg'ծL&F \'U$~"~0ۅ+D3_.KE$mtBz"&zl 4Cek.g9@/+r$m8ˎk8uoH_c0TƶMH b0+DsEB‰t6YһXː7 &E .=3h1~!YcI@LPkF1%64"Ė7lw.mˍUMd=*iBBd,KYlceMH܄]X{̓=xIH S$4 RHh m5q*"A7ale1kx!5)#Zu8 kMzc9݂, 4ƨg`]zQ -Ne8$H=S+K.vRv a .gV?$o姜rSJz>%)IH^NM͇g2Xj쐹a]c MF5bvWCJ /SD ~*xvge`,lm2"A/Lb_^),zE/^ -QdM6º ɲlR=Q tJr' 6¥qF%I?i޹buК#qkK nj# Ez|`Wdqᐶ_GDn"iG; 3q!<E`ҕlKngY7C$?͆ǭ%\A44zmKv͊EB Y;Äfǂ{b?TAB`@C. CWۄLwrq|W3NK$1(dcK8#/ƫl""-*%qg$swqT4C&lq}^k:=9G 9YLLxë9/Ӡ/T#aHxuūdÌ? o]iwX"~]绬.ߐ)¯Х[x ~5AfHJT8t"|2y7)FtU;Z Ѐ&b +9IialV6<5[mK`vM^¼Xͦ>LTk6tyt}B ]]Վn2Ѭ3aMD#\Mpicmbk`DZZrc H;f!CW.q9ܷZDIoXMh`SxAuĄ.{WiUBk$alyTҌ%WSʸ$0/R 3d?ńw^>_\{M-좫'q^^+z_ŏk78Sq}f% auЊ×3ScE>y>_F[H;OŸ~Wn߭/-DRo^.ǵye]$ڄ٢q?pG p۞b.R  =hpvOwluoMIY01+ҰaD@A7Z;#$Q 9ܹok}c>%U^, O Bf%ItƈL `n*$ o9,7iqB2yS<|΄ UVyH|hjr*8tk^JZ!Xa6n%'ʀ57k&]{ku?vV%6)!-@P%n_ _|!p;L0ȝa'Uۯ!?m]?-K v*?=Zknlc/ٿTlX kZ,hg9]> l:,A-+niWCwmޟVB70A? ֨/[Խu_YPq%6836 PIy=U&U{~tt@yvܧju2`:qHw8 ; ho0NxjB۶E},Ԉ(?pM`=>K հ_И|=O/zaq/{_0:/aUD 6gž $˜2^@Ox61<^O8BqN8x\9S#@|wĩҿПs OM-Χ*65[Ȥ i~^ |zn/w{$X2e%mH7^~VI'%N {dhBfA *챇g*О5jtUE%z8A<`!w^7{6K42})5}7'hOQ G:pF!^ԲPrl|[= _IaYp{lfV]){˒bM`Y!y`;!,H.ZAxku ˆ)/_^>y;ɽ x&'OjDHa_OkPc}* 'O6(r FSZW`G'WɁu*jD'oD931bbwHMS-+7CfdZ ~4wO[ t52(rA. :zk ᮳Aux_Չ<ȒJ'GkPdzSpuȂ,[]o**  B | ֚\ܠ#>ޛW6K8EN~?Kqd7]TY+R76x(^^vnpv|mow-x{l Ottnb ]>x{gu&1N}-<-}. 䪞4Bx&vdͅ|B) p.N-JLs AxJ<, W)W  IzzziIVQC*6 T@T2AhOpKb/Q {T͐(s?MW@IDshHhY"61 s!R) b(\̋ɓ?>Wڼ2) #2 _u Ÿ o]qKB-(*^+N8=:BJ>M›gň^/x3pb$.mwpo}(Ō93aݰհ؇drs.A Άyfl2{(0ܙLMhH_$vl;P٦&WC"f~e$ :t6{qj|8GϧUeH6dZ^&ŽI LnW Q#wc2Z`}U'GZb{| OS S;usF!(~ FL\Xp-xuT]L[eN+0?m8p0R`LNt=%G9;m?JsptiM;C^/0Wf Ѻ5慙b++=-f/~<{% nqB ;yx|yݼ1F](I8rb=-48~9jw~EC83]\M'\&4F=QcysSL' 9RFSYd%*{.k`u>>kSԳ+5<^ S t}f-:5?}ыXO!)Es8&DSq'~^IE7 cgXaځJb#$Q)w9]HS|GHQ %]֛m"1 4E pM'w(,E5^ R&q%b2) ;n[MQ׌CfieG8^H%8!d;-WͲ[$8 d`t!"YZ5 Hl%Q| on+rN=ki5Eؓ I&p!O0≆b1i颩D0%ggIYrSƎS`%7b6[`_ ~\kk-gLR5Vrk K  4$<x%$T*tխPVM50 1Rt:4N3iҪLJښ[R8Ѡ2uQ+\ (iy[42@E-SLޓX?CEO+!p5lT4+<}.[1 kIoxX+z响FHY_ػ <Z~TOIB :mQ" 7`WJot@Ww|j:N~4fv),QpLHĚ1YvA~8/: ڦs/7i*S1P!2Q!lfu0&GZ/9έBuT:(~G9|;b֔"}4G| pVl!mmW'Mx}?;Bf$ Px| xSUR&IߏWiB!MC)Zm MBU1`cupWQ (\FGTp38zǻ> )9g?{kKL (o v+*\{tA@aZ}}ڻ}nA俨#ڌ6*jryPMB.#G.\lY3cz9n) e&җ V%_8=(6sk5aE լcz(2flc>ި,ӁvIDUa"S03{=AfS>mBӡsҾ.BsRFGGT*P&ϑD|O%$1`W,ef`tdd ֵ(r`!2`|@9pV=|UZ]x=NΦ6=j4 ]\vx"3- > U蟜=?I'`k|M'x7k$))h) nx+v2B>_/Ͱ->[%%ݽѺWM7]QW=Q25.3 ţeQ)ݾ'V4]fԒU\ 9OR:Sbt0lkiM}FފV Ӄt,lԖ7M(xh;@]x=t4:]!Jt"T5(I,pl,"tk :} OSßfdiL`M@yp=ۻ$~zh?\,)1>L+X)C0+,@Y f+D%w͙y#>X|\F$ &W2yP+Rwc|~K L]H{LnY~z,{{GlENdmpTH6ʬł >[ ;&Av5\Y}>̀4pʟuX| @PY`Z%ip!Ku̓=tN[:Up42xiz0J=}mĒv#سl..4 Mօvk J2aTb6Gtգ1 ib9~A 50XG۶8|Q%9ߢ^? uq VlF[c@n)b)ed^j_`체܌w!$S#h.Gz6r2A*T)di6_l‚(њYTQ&=/)Z-yk;#@YWELg XRgGRQXԺVbk.d9^!}]IYzİ,ONn3 SzVJ"H{i&eud^%!AJ x "5h$$ 6D@$&3I؃bL$݃"ۙ\,)/E)Vp^M(]6ߛ&z$oMkx 1Ϣr9j۔D*9AvP{eN<0wg}yQ3N={XQ3XBl N]"&C9͐TeE]5HsZ[F. `ZD3|twq6w8U!Z|^Nէ+uɜq u UBچ49:6"84L{$$tâYfg[ud|䊼NG۔Ƿ'`?50L@ml~cVkΥID.j[nn7΀cƵ`hMKcK!X.w:zn^ll\%sҠb%:I.e$&4l8ɞH̕-CK@$j|V4:Yڂ`#UJx)kvtk#ni@rp M,®@(O$ 38Fͥ5?S,+ӤmFoOBaQg]+E7n©$jJHig{Di:E Y•bBϸ@b5d6:O"-(q7eD._!.±n=C#0 /MϕF6:N<׊U aN™<;`wiAYSDdGdfѓy0z>OOΜ%MįE QQ3 .sj!%Zm6AeٻoXjգ7Z$hG,օ]-ѐ!F# jL7iD<ٖ.H{p);&j', h͑aaOF+qRGKȝ_E:xsk6LW)XdȞ"\m!s[1*-߮pMއw+‡D vEDq# 0yerZJOFXvl3_~~Q&oر$H {Sقn1pN-ߐfl=~&A4"n7 f Mo F w/;jg\E8bnhAx?^q;Wh$v 4Իk2C<'c w'$oE&,pb56%U##*985 cS]~m=|އhh;Y#_VC~7Tr1u CP#n(F?|a*X's7́i.l䍋#+L rXǎ3TAǶf6S%,B5|Ea;dFQZQ [QS^FͧZ8 ^Y9ɺޚL%NgsŜ(o츻xHTC$x ]v9#NS'+^^UZ+u#-pwțX].m/,lDŽ& w-:ZZ$76 |~UeD s0$Edҏ4pl!+w3XH-Ƹ;ZfҶ>p6 +YU[ww\;q65<QxẌ8'QxiXn*!qݥNI*Sp ɲzغ&EXѩsa-КUkb\X춨0׏0Iis'zC mk -G`E7b b X#S{G3 ȅϷ΅X,:*ɡ𼷀]Xʁcp`+^|O3jUQ!x̿,~ uM]VS[e6[\jC!șiSK.sWGˍWzFa..kW" EIgpv4].$h8\n;z0\(ְ)~B)J~HZG#k ua(%)^Yu/p;MJ9\I=d`Z=,7(7yMˎ&._<EPe?VQ+u cvZ°@؇`;~K÷W UFJuG]Plm-Uֹd&n;B&qOlȃ[uHrb@2D=\LNѦs5K7lÙoKӤCs7F[n3_h[@hno$u0o[97o;|w׾f~FoUAXb ;"aZh^ɚ3P+rΣrlTE;(0;ψs'RW-Jh.'{xq۰[PZnja'uXǰSK{8<# Z`h+ BH3سk;Syۇd2/%g ^H]"sRt $̈܍(+fb2Gvkൻ*{~.*bGμOGƋ[Qxz8yUQؚ\;q&rZ)m[5޿| M5ܫmvS9t璞E9L47Nx?&MUŠ5ƏVn4MQ/I-;.φ.S`z 3~@غ$׃zVRyk:l!߀@C/6҃gFzB$lX-BKBDu⑉9aTBSջW#U“v1ZYdNڡ۞LI<V:5s}TT"8lV)́U|! KLf6F'vW(D gįK]D^ 0Z}Go Q*n39b<!fm4 Mlt}}4! AZp[ \Gt(WI.7 A/CRg3g15=LȞm@dULnMŎ7TPuCd'}y5@Zq2bk}GVA/w~JbC,Ғ?Mq&Ks41t9 -e`a=rBJ3WeFWCƉ|WkO\(H ,glJ\̪WN&:aIcS}צ2{>U䣂,ޯ}y[~'kMÕv._`-/4"GEjvSrvyM\J3Z+!o=˰=Ts;TƋe 1VJ7ۮ:Sd1aAZhlKs:ura%C7'5m+!AB xd/ѫ8Bn^JiD{% M-62~x8K_ /ҳFRb5Tn+%ay+)UzA DjH;v0, Q%'n -Bl|0nа-?0II pzxnݩkSx2? /K3uZJ?\I#>I6?eW,q 63[dGa*;z^|I!X=x?IsC\ gΙg^)m 0 WӸ> z]J.Q.t(I(-MrAn^Сu@ln%,WGus|W Fla9t?˹ F\qF0l٪ Rȥ}c9ø-u\UT:UOkxU6.%ܯ*ŦnjZYP|ݵ寽ʙjz]!<{_O㞳aYקsS( &~$|rӮ2@vDC5rC#i捇d) )2B:/V.ipZNx׾͠aO'Q+--5VuolHM`?%= N,+~(8~07F<啍U_fjda_g1 _x9B%g WåG{:+a:FaG?%?c#>oRx Vrl#I*m8+J82FLFL¤kwpfZ^~3I%]Ř!CeIP +iys-hdaUzT;g·UbXB Ix$XQ8wZtﻈM?dK {V@ҝ\·߽3|:RDݞ(F'e{ee7..N vӵH,ǂ􁟸O& cJDһeD^6k4|8㽢Ɂ:FXu01Y%N/n{~~WQ7A?&4L@y$=('d1/#(+ĕ= q4K@eZ~n̯?4=ĸ b/@o|$<1Vp9P 'a_Aɧp_Js/۬?cOra7GE`LB0 qΊjBƞeJ DV|<~&oUڣ,ip0Uw_[ E^Z:=^#Q el(rK'^t+M2N w"W)6{>{zܿ"җ!wtw*ɡZ .BBEi}P*?XPe [$ZzF86pbШ'+H@HGRCwvX6;wH܁`hil&8ufD ӍϿnj;&A-?Q{d4bܫ/Sjjqzf31_oMIȞ#2bHe;e f#fq!eBΉ]us" $d$VVM$mrY1ƛeyɲZ2j?,[!>n4Ei*"ρ+S^6ģw;WZȭ ~Q}ϻzjvg4M Y.nE3(dbV@!㟓fOeGR;wÛDw~Yd7/ȯx;3$ ƆŕީU Ff: ypak.NW-Jٸ834&JM7p&|,oZ qt(OVl.h\b|0141&&N#1?֖%&w9w}߯;~zVͱ VcCL- eF|]s, Vcqvzd4%(+߲{_T $XxUPkq1Uw)%J%!W(Qal X|]M6!]? "޼+^*=E"z5"س^MLa7|_ ˫`N',j8'ؐr.q3%PLJ@e0je qI!e'vȮ{\3yi7Xk0am=q|+WUFljQGe s ܖAX,Üo3ҫdTAחY](Ɓ\\] "n~%coUzOƇkxÞ@8ͼߧSmnڽy2gA<~nكl({ 36røǣ< nYTPM4t]/_OjiS&2K#(_U;F̠Քg[ʴUiLp+; 4xhW_1q>r}TpBNxX}pRrv;V"KlljM$Y/)YX:) 4Z&|uPHځi%c@ZBB&)Sh)L?ڙQ{'v"BLo޾{V'.[pj$4\FhI{|,iU|G~ϘDj|I[ՏȂp /́>BˊI҅RXsa~|)ޢ|c2MB2sY $C^8fs|g}rr>,a>]^ O_k ֓"_AV6! Cg$vy|[Ƨ_DI=6-|EZ_5xncRL1.8﯂euZ\SuLV?S^~=.z8ke*xVD:.* dVX=u0#8{?L%I4TcLg 'ZB>óX9jtlm˕ӳ~ ٯ0|H;:1\Ж"c@1F+uss38a%F4\_,>5o9`.d$3!/"8kP 3I(#S\ 2΍ qa/5ԍ̛-fYB=xzl 8fw(*mP ? oޢt5[mW)ݜTH2nBpl ><~/H '"Hoq[H]l#x**+ 9ᶶ+唦+g4ѫ&)ݭ̻XOwpbRO)yyꞽ4r oH8t 6WdԔJGղ :ņB8׫ HtJ(~’o'2PBc!4BBh3HH'r.tE\y&oηۮr_DJ"Nb%0i rƱ&_R Z;}^oЉ2a᣾"[f㺼_nf7N"tѿ:r{(ZrԞ̝g~WxmwS:Y[]vu<R T7AR3kJXf)EHWK-u$iot̩~"O6Hk0%>4BEle\صx8!@||)ȿ,vk%`JΛ7! .Ɔ`XqʢwK~#껮g+P= л<#7̓ x28* t:;c8Cefl{ ?3@V9:ImIi9ܱPv'nDh(~y\B w< B!ߨ}bm_]K,vUZ~{fi?w|Jjf߳zWmgiZ0|^z`l;sh .*cVg+(hόGkૣ-Ҥا\]ݿ)&~-h͂|aZW?KO!:?[/GN^@[ p6u7A dm#JEBFRqW(ms:~%#عf.n"Yyh!{NdVv7(s U%<\SmomJY@vА>g#]_`/A߁E[M4(Ņ`E[72|s.n"UCn/WKzrƉOb9uGENuf'&hÜdh=k() iMj7&/FD46W:n7dg,f Д.y# _HDV5B\[ z+qa9.A $IV]<= m<H7M*R?MX4 4VU&n՘Fz~>%?ɷq#%a VO^#f@CM=;^ʍSSF9TQi-ʧc^ɭ{!' )&w$iT@.:o>7Ks2V}۟?p꜁\J/a%iWP ?χ%MpWU/ U7҈7]? n2x{o 9ysnLm0NHzK V(Gl<i˙mn*L2j65'o>eDd{ʛnKl ͂$mx=AhAI5I 'VJ&'/@I@D$Y 3!XRBQEV⥄zPAAȹ7R[qݶy\3"6|멧:jXl3XH+} ⭝)Re'm۶ԠFxyHjQMեaJU QK"֤OFlbpuq4q R3WUq * nqu6 B(6jlo]=: >Q=)ޱ{x+ r'|n9y& NQ,sf![Rs8d($$*h5MOhG,+moblÿ^ `q5W*'hkM^}rKHb}ELZ/mZ=l5==R`' ϊ{KMޱqq?>&\IDkYc\7*bگ+6Impd)ƛ1O2ӐA Wc,j4niZ Γ{lZ+̸y\vN>qC'۝Y\I757O;`kC z,g}otuڏl4x u' xW}PSW $3@*!/$E)*h+ULAHbJ (.hۡX۵V zUjwٺ֯)t]u]mw,]W}—8?;s~߹oy͵w*$ߠ]BhI@P8 HejK s3d9BŴ,2K.7+R$SJFP*J@-_lsŮO3b)*Agqгz׭nI`^ !ݹr;_x4"=g2W^ܴE&ΤLUhze !s}1PeEmUȃƅfC%zʾd}vi1BAU &*FxD `6" K @Vf0a"rƒl9$oN6Wڮ\A_4a6+ (`-%NEp'QANj;$#P:dQ%d\wJ^G[*̫ξ ? K(T@x7_9&'{ 3٠u=/||F\dB MM {$VLsqd-'hK"˄33Nόc16pf/^,W+szQl*_ȁj%]*>z3qh7{eٴPĽe3.XiOչd6͹c$ Vg&%m_/K~$'Cb w? uEꇵ(Qö'AU`PQ5MH"XhuwΡQ^jJpk-bxxL1 DT^{+VwF7eiMnli~=5^hFm4k5d[NĄr4z@'N<牿'N"K{ʀj$G {O_7ϔL9E.`ع>9az>t`=㋋B,'PBy/b^ >t~ y LrƦ_ˎ/ig% ws9mˤ@}Tp^<|;͚bBc_ #t4qW""@ kv_o& RS8aNjĐTAj^İjdq o&P^ 5!Z^KUkGmx 3f/đN[V#nlp~R2٤pAz#8l#Dv9[ ̂w4هM!{V=<M!9&m=i}>w mnmvCZNqUWCKcP+D槗$em}?7T>x;βeC77~foSJ`Y߬"E&_`{X7.jHx[βeCcs(PF&?IlxeC!rf^rNiJR~R^BF&N ;>9#59{!D2RKRS6/`FRx]dh=@IjEHAzjI\L##$WSSV@S'?ݵ(PC)t- 0&'wS ey' 2<:ʀ9hr>Ŧb:*r^m<9 Dp4oA95Ď ͂ѕ(J&bfC\-՜k3o51y% v &fM>ttIMHd5qO-((I.v+I(bBAQzDtދn/w<x#ʓ2 ʯ = NULL.0o xJ 5˦+1jOλpG x,YdC {Iֻf~߿C̪i0x,Yd#H@֚]wߺ͢lr,*-x,YDD71;5-3'U/10=a~ʘc+~UYcDO2 `_=ivHC$_5z=  x;qc>W v7ۨHtb! )x;qcCi;k:C~SQ:l>Ux;qcCI+%ƦVڿK+f7y+ ,x;qc>yF-矗x\7j (Tx63' %VU& GQn2HvXAKGDx;qcj;V{WRsse^? qx!6m&&~/WʐY7ʳJ}/x!\ÌV>pGZCsܳp .|^x:\ÌV>pGZCsܓp~}+QX5s7RrA/9Hx(Ys-Iv*g^!j-x;1cBƊNAx$Tx2(nڶ+I#TƳp$ sx!Tx`_ّ彸NԪN95.0[x;vX劈&dnQf3uBt40000 tss3;Dq |ʶF,\J-(b]x1cCȕE3g|yAyL5x}C}]pkHXTh{Bh&޺ ^-x}jL5oPf/QVh֛}60A -x} HڇZII]O IͪL t-x}C"ϣ\-q,:4"zyL}OZx:OiH3ZaH1AN%rI ⣘v[Um?;nB]Hx}Wf55uH/ijYY-x}Bo|^ @워b +x! svCܢvXhҧކ0&Zx: svCܢvXhҧކ0&hDְ϶ag\ZV(Hx}C:ȧk%VF{pENY%x*ds5c# -x: (= Ȇ`NRN&h/36 *Sĝ"ZoOx;xQD71;5-3'U/1a^/f=9Q}x=sۺ?[^:ϕlٱ4N|#rֲ4k.m3Hb}ow~L3D.bϷlޜ ċ|g6•%,fgC$ ױ!@7`8\GǦ7l^'wNI⸟Jbp7 ; I0pxв{2Zycdvog~h>F|4ʋK'ПzQP;ٳgI b@3;O-=rNHdY }2GM4M:m׬76^q>rcF|dd'ÉwwCYk gi CM/4dlOOv b]LaŻىVFzF%?rb%$*O&$J1!pȦ`Jx?Ax`\~'buEO>W 0?SQk?ہfDkK?^:{+A}EF~K9 ~?/}9F_aR i*Et1G@)= ̨pD' ,[pX O53hj8L?ɩJ;GP0Dwp!X$<ʻ~l p:G9's0; <;E|Hk!uOBmY AhƅG4 f /?< g]p \xT Sͅ|"zt[lgggB/^,[)w {0^p9QP[͝ %< <~?Qca&Lmvw&b;pwS~D Qf3>:b&ۻ;=%N H:`_*Ixh<_e+YZ@&I,O3#`Qμn5|?v^[/d63" Rz1L>Q9&p8&߲7As3?^W7ɴ)lj ,2NFC<iJ}P.v)=]\fIC V:Qw<(lc mr;G&v9rel40}9687mDwܖrP9Fr ތӳt{9} z(Ut ޡT,8[z,Wo6ߋ Q԰ ^IqOs`?A}ν)GqnZT}1QcCs乭ۙ 5N(]kl+1DN ;1F D"449)FpFo9s? Rw ؚѕhh}7`?|7uwfbS"]ԄI{FmcPLGYpNXQ?%[7U۞Td1AKvχݓτkΥ] mOHlC\l"Ҩx~8kѲiC}+F6%P}kJW3 Y.(|K,"t IļEʇ:ӲpVDsj+V(MDgfF_w_Y06D4l|J/?f.O,Bw hx8B]e--LC<0chFҵXre:X[Ǟgy'+S@#O߷ I  f2탹7.;0%cCBee)P.fbf)΍pq)W &/L=ϔaݝjTNoE^ A kbE50=tdYQw.B<:\։T8-0!!قT \$nb!~Ny.:N:ݽ="!_zlSgK[J+Wl~0UK>{C jC {KKpĞPfփ&>bॽ% ! Y`Ke0ZDOKV3K^uP^L.Zxlp v `3Wu|D 竞v< d]d&a(.N&:mFD?XS8ba¸-[%Dp>on Ğ`Y_qu_MODQ3*c#71)ofnU^=5uY~gE2-;~ >^*l%LJY+Qb+it3E؀W-82[E-=,c:NQ؍2m h5FqR2K[Vm7bVL-j0pxnis%̶芛&]rx^&w*TsUpVuV̭-J sCb9hԵ[uǞrO{djj+;K` 0paEm ~^T*,ν2ДZ ,g`Ͽ;GWNc)T@/dR6\)اV2w9U@u=E9!E5@*,ՐqTWĦl8Ⱥ]֐Dzlz%L'01`WShq7uu|_w)@'=@u#%,㉼+0pvq:#o ~ߍ17/"|/sØ"3w_Ckn2 NY?L*DAEUAI ~=}%y> ByX0[O  l_׼[ESdBT5(%%I.E^.<;N:F㔧D9y3,WaV*/& u[Z"bvM5ܻ t y̦zE5`JGtg 'G`QcbT&D&ÔEhBe"1xa`E~ecIݛuNyeNσm\^ _MeO0fl)beBJqQ6Wբj%.2k}NV0 kvòI)mce{K9:B%T)-sLzhU)mG:qe]~S.:3X*#7φWiw]b_ո 2n21B6Y^ʬ-VQִ3o*炼 0 ,{&擒}9 B?%8_>\-<4 鉻tys?1&DgcRL/VJ .wgd$N~KGqPVvXNVz%vnSi{9^"#]uLR:"WS`dexu9qg%Nߔzij`5^ĭ^z~ʛex}߁\Ov׋ûjrQomjW=‰cXǐ¾ &}{ 26 džߩN]:5ڪH!ΑE%7 HjL6 *]@;GaV,J:[rD޳Z=͹Y>T:F-e󤴵lϾxrO5|>ݾFEtKBņ<{J%jCSȝw 0o1 ѥߙy╱"+ÚnK||yN`;c( f?븙-wjv{ln,QҦ AԜ}Ԕ@j8u%ͼ/`I3bRɠ yLa,& KD7ţE `6)~0mx7[ K 6/g<Dz \K3$OvNM+JM(JKմ,.9-R`Lpp_kDЌej@fM~(9] ^-kl T^bsnV4yZؔSR26[辁Fǰf.07?79}a`L`EXba ќ\Ϯ0Ye ;Ff9]_4rFSSaYQB/o6)e_!ֽBn Ylޑ\?Ier"d`&+Hv52kXaIa_%-٩ߧJH!(k g\7L;NnCW\_k^h>Y ~x7iT 7_g2(ilVʙi ϋeM-bR,h(=ޟmL ؔSR2&Ln`lcV ҚZX d*g)h&O.pv+I(Z;8P((Oj2sM8h(hrUASʅbOk"nMpxIlT$٤lK(}Q=ʒ("fr*dDEZ 13CP$ -z(z(ܴڠEK¡HZ2Ar?-KX^H-J8i*lkE2/ӊ,O w?YN59S${-HnĢHe] ?J`L.>le.f4$qwb8oc AAn4ڞҼQ!~B8 M!nhU5hWu#zu?ėfur |wkq(|U6͎43}l>}t_Gg^+$߰pASq.]5x/!,9Gv*p iK/^aq7$I8R$JkQAY,dm ;idk\b zÐy5He>Wgvx YD,2gM1 y+qI\ Mcsgׇ+Cll3[" hp!+VC8ѕyz>'i`dtEg{ mN D/wA?,N쏝Q6BCDBplc Ft5h­TqEaI y!+d5L4R L$S$^P^T SɍopE5 v>ȩIaG4(llК &Si1j"xmmx|Ʀ :`}>/D \~!aF'h]?(ZHMݕR]Ҽ -F9E:}wUA ״Ez5r#lyg緉䬚,AOс_Fle+'D-5: on\\,wD5^QWb;7Ir#"Iފ:Fqo AD  P+q;B^ =1)O-:A>`-aZa$ᝉCb;Td> %Ifc8iu3 S!j `K*;bYna2WAtG֎Pͫ]\M#S7EyuCb |>ruF:9I`8.{HѸPc4 l "l0tm#RAL%+^`yC),7/v\FY._IcQ'kB Sgۡ7Xx`'^BԾRF;w^gtAy&4-/A LKMY)a̦ dE)-%%4Q/Dpj#*¥syrEٌnbA ~#:_NqGV*$cjxqqr˘:aN%P/a%)]y$E𢤈28$J}I0^a2W#cSl~EA ؑ^ 3~b`jؿFQX 0sSIsҕhQ-Ea`P"\aqt}&X  A5 nz)85rꢫz[͎n]0{/jhK^~MT per %˚$ b ݑ1l80kK@zsuzN;3Tg;is{v:Qzv0?_j`~7zRڧ~q>漺!9mr9WdfwNAf+J_ ,H>p''/꒙ JsO9!c >u.8-KHFfpRpUd"l@M&˓S;0Y7ǰC}bu &N7[赉Ta\9\N bY1Lb]ΰa!Ŧ8s /pdrt@ j^vP#h^<8mc Vi\ʋ4U~gفfWrk#vK t4\Ās/3_DwftuP,`6a&Pu lo(OY"q6Fuo'JzJZYU նٖ\s=d!Mh~G5ʈ"P EU>*9l6zc eiLI$8Y]I-Uq͵!mRB }? ,"A &3=SO'wS=5@n?6TkEMsl%C0J+:Ƨ` ?q_,bCQ:oMLHD}DJ`ԫ$r鄣g ,M"aҙ(;Nnzfa+0M%cXJA_C='Pg%â' ۜCͰg9 #po: %ULGd`L@^,R4(eCV5[012'.F6#BQ7˾->[ 5monq!%i2VQ6E168F ^vof`@v4#$?SS=echAE2[jJ5,Nl3be;6u уN[ltCOXf=|zUر0 LYځ,4 @ kg/zN8yP+JhX/B˱2ȭ{0uɢb5{NjX :dsFiP&67 I74ɔOlg-oP︧5:* n x;q[ 7b+8n6x;> v#0qOx;>l y%%oPWG `wx;>q, K&|@MC 6;hf  x;>}*rEEiEyAűz)%:T'3NNS?7'lvhWerS xWMlE\mhmudPB$Ic(Dh7ݴu*q*t.@UqA8TJHRpBefk'BCoޛ7ۯo9x_}zC6v-v y9)E,]_OÎ2ttHi T7`gA,^d㱘0<X DžjDX[ sp 6"h30)xX*,T) hRKH@E` xƘ*&C#r~c 3`͞G+^NЯ~r{uH쒊iȴeEMEߎ9=ѥ\PzA"/'U.Z;!ng^4:tk\o|`(ۏ:|q<+r~tw={n=h;=řH`Nsstx(&Ϣ|?1"O|n9 X s I;ӪBL@İ,q^DbN^5tWHZ^'AoO't[3/\N侞 BKQrэeg ;snfd<8gkmn̩";lVxU3/f/{yX9,|>\V 0FP`Zeiqoj3"qJFY,A%&cL7x2; ac3Kj4u0,fl#,&I>Uz\#ͣS4/GֽÐjcx2IyDRqw֖`!Qb0G!V\|he"iMis)Lր"<~LDD%z\+!twraqsʵԚ]2j1ݲcm2..QEvnŢ&i`rрAC nD'lZעmԲhzE` Sc\Q/qҬMY WdbڪrêIˢ }ט(6qo.EMLM;eHۺmPl`ꆒ/_P(B- SJe%JR'/2#d4X6VChI P**(3aė>9JXɌk5#p8ϏZ\䥡mi=y0xe$JTAZ0EnL? ;h:U&ݟJ@dë?n .;SsN8&W9&G{98\,XϲH }v  -x;:qW33͞L" \i E %yeJ!.n>!~AJ ~>>@mE%Ey ؔZsk)穗((+d(V(d**&V*$*$&(hsN,LӚvs(:s#=Zfx;:qV3͞2 g nαp[kxaWk61l| \ axa\^!iMmEL?ks 77|Hǐu&y TmFxaa.EL3m`̣Q\y5{&L Ԋɳ9wqaa4O~zxbQ[bNNf^BRbrBI Z?i1rNҔ"WSsfLɊ:*&֓;uj'֛t[@i%:8xk)?Sa&wzjI|N~rbN|ElJ5&?ВܼGӑQa?6vqxK@)x |S%ZkSR۪,dzg$WEj tn?}OZ}b6xBo2J %`0zwK ep_ ~h)(YԡJ150R B白ƨfpS)S u06 tR5JO@&V&VC#bl!` `+P'FC9i8|mB(O1ezʼdw e A̞Kی+zN0R/ !uXkk>ʛOP&޷˿\x;Svl /6oe.Oӵ 'x;Yl\V]#٘ 6a{Ĩy5v΢ԒҢwB6W0gH l+x\p3 Bƌ)gx+gC\]xkŸg&re̪&SVOK+N-QUC8 &\\U,'[NnTњFE]&RQ+ p*ֶZ&cUɩnY*M>*:%zx3qL g[KoNPQIr8xq}7c3 %x{ŸaP_BIyj^I\{ kY 4&Vb(>9@h vuKxb2'x'sg2jl~-e uxeJPKIk+rZ&1iK iMдsM{% Q)v_D8:?*Ӂs]r7:m"G.( [gTi0w㹍&= ثXY=71>GPԥn:"adێw u;EɁ^y ȏQFՔاR࿱23-[y^Cp)}H4A@&$pp)&B啦 (7 Hl u+^<:VzvimJ*{WXYZk5ٕX'|(Vx;xqwɁ{&:l4bDV Hhx;~{H"x.0/* ,0 ,"0Xm1؉*}|Rx>}'`"ͻx<'s,S# 0x!,(ڏ3u3Q El/xmͲL #Zx:WR8V^\Fa%DxL9„ƩhD0圫} ;7-fHx DUJBA:㲥u+X'.xm/_~Hx.KaF^ɛ >[-x!Umŵn4\%+,\x!5pL/=x'ˑ/xm%H݆9B,W IhҮ;LF -xm ߯W ͪ>Ukfu 0Yx:xPuuƻ?)bZ/{:Uj{s2X'v'HxMD71;5-3'U/1MJRb,r5kSFf'iMƺLTG*QᓖbeN]n%.͓X'TIxm գ7e-+f8 wkr:ڣ v,xmC6ҪZu}WvHj Tx5*D"O{n> }vzz[}D#LW-zMCx !.bNՍ˖E{.x!1r=|]DcuSZ |/xm +ۆWjq_߼ z,xmZ&e:&G7]Њ6 >O Xx9_E&vxc8As:ݫ3ds[*XI֓ UGx9NyuH=Pi(d^@MaR]@t25 `.X'.GxMD71;5-3'U/1z èKv??# epS-޳9MǶ8(xK"3 _1=o2}ϰ=Fx˛%br1J{,%) ޾xM 0}>}, ]cNt&QvoAAzv,-")ju<evDGA!ALx6޻lm-Y _c;t6Bj`l3p\;Y>iM@l6w돒hQg82)*DhN}v23 3m#x2[s5}JHfIx[ǴiGbInj^D?Qi!x[˴iİxX[s8~twv:LJȖ)$@v}[c1mI6An^ҹ\}ԴI OdI*||E\>%wCCR)xSg<>%dħ/ m._%G"$wI"Ǡٟ@)Vm7~d/,$dKڞ͝2`|$X4lR<[ɹ^ӽ#^&^1iCWWt/{da,7d +ʛ0c5:B>3N"Hkȣr0^ ߟ뿎 QK|IPH3ŕD\ 6s ܺO޻!@qwvoƽOn? y&Ʋ뒿ɔ w7s8 ^]#cGfT^ft!@m .#j^wsP6wWW"VA habfחD;h!h$ YlJ VT#-+@(i }0r{rKBeUi.>`ﲼb89 'xQc;WCJ1/.QM *U+up͠aL7NUA|LqvmQuEP#uSwZs"1i Ub=ӭQӄWba).ZK ʏ^">;oEh7I'Yﵬdi#;yVYA-ԲI;lg &v_u}u5;np} {m3w ig%0\gp9([A.I GǑL +Y^!Oc<%<f$a^P Ɗ #N*pjÚ3r%@w3VO}t>`,7xWwq7īS j#a<) ۗ wpvz9㡱]8)Wꟽv)Flc ůpzu| //.e;EYyt[|Ny3nfIt`0[UBxTytkBl0I٘]@y1.nQN+isg"'S0t|}{t=: jFpo h7zqUy`r,A7B 3WG^߫`:8So8 Tqm>/d ZZ+R1 '4rHOf3o~(Ϫo&W΢UG4]}̸JQC;4B(`߿ &t[LnpEB"&9V}*FUB>֜kVh*,VV,I rʹxC٥>YoJMeu}x fe#U'PƹFS^Zl*D(צÃeF8 10,G( \1dO9RYy&z,WըբizQ2EAqZzuTڰ1VyI518Ki D1wѝ+& zl%+"\~cԙs? /睽v7$D_WyU<E@]Z(ʈ8:$NyL XċFi^ {xtl箒 yXRz\m*qK#< aE CL|U\S.c/`A3HU;L9fhj| .tS&}Ҏ(%Lk!ë'>K+Ki2]{zhnjRɼJ<5W?L֤e!zjڮ_XjȞrCڲ/pqəL29KES ,xjU [AK`I%cbv(c *G%Xf"տ@Ȅ裡%7U5RS>j2Xʭ;M:5Wi kAջhXbv;;S/Y>_m ]Qip迸1c>oٿKaʼHȇ!Rq|K:1O$„ևko$߶,hkxx>5 zxZajV7XLL0b'ś ᖑe1"՗}`a$N Ae3])(h&E+}J[[=bMUbPGgI'xW~߃ $Q}%bꎼ$^pC7fPndk2yF9P3˔&lU,^ 7{I)S&[Dȫ28F1q*D,4:F&М6w2@91g-3;*i)5L_4-%A+َ>ߨìCUM-r+Z 1+-NodUje'{\}I0ڍ)W +Dd`+C?i62j"xP9dn3إB\C}BB RJR+&RȀJ49KK8` ٩5gf[ 'gU|9'8n;؂̼ɎRR:\>.IJ uy PT,"t\ RZ\R_ w\֚ dn22ĜҒ ļbĒL8@?rTŃ5c7:;*(5 4#9d[ƒ˭(5757ry>c-W&''$tT|U %dxu]KAQc`z%*(n֠HjJ(BЪD8a؝B[E.Ko/^):IhV 39s3EmwzɈpa.ԏ;÷[usw5Ux`{A˧9nwnTÿcY]MxshT8=0+V$LNl3̼K0_꺮Bل1'?:-0I8<`Y `M@4!W^6\5@'q@B!txЯzaKb)M2"qe%$Mh1aJ`Pp׊X//Bhf5lо稕NLhPy#]Po6LMiL C}6CI.WUp*RHSGj>P.1KYiS  h)FNktE' <Wlt]0]<^W!wzx;$\s`;Kio>ʽ' (ɒp#q L3\pMf|ZpMYD8W1C#@;sl%va"Hc IS=NBHw+/ki[*x;'kCc9̖XWnbfD+Lyb1ĤTƆ}ӴFs% ?杼+ 7;g$'h=iɿ'59zL>++irfyV&'˲JbD'Lɥr\ή 0nVPu>䘤dM";Y^fN-9&0Q'St'эđhmлTl i(Jƚ5y#&u!xcCe*e'b~Jw xc-]=}6;039:;[sr3 l4xc$So3&@Wjx{q?cFO& 2M5fϒ bS5YPT]V/g:w)12kZsM">6_^ikYj^I1Pl=[ړ/O({xq2c l[Y3&6  xq,cE '7O6neTVȚ|x "x=isHv_ѣ) -M*OhKe]9q@$$JV=h5T*dV_~{n9hq 8 G24 x-ndH^24<'ξ$4LsqqGIIEqe0pty(?h4y1 Y>G()?Jx<Nw2GҼ?.|}g"~Xya lznqׁ_IǾ܀y_tW]1$kys #89 K -JՀ?Cx݋3,}~]% }0%i'3 ƎHìǍ e47;4vat4&+ދaDf2隊XEׯw:p8k 0= @ _ZNeH[Y;n/`rnx88)Gak?/SC͍C׭@TuX6 Lk6y{=ӕ2 ^0O`0#N-a6&H7MDs8IqU-,]EWؽj_׷^W饠;ZEm}k>&"$# M#gv!@g0Aoa+)֐x|zV8Nd2m 6R3O:XaIrsOewӿo|𣕚\Vo"OsOYu gx].em09,F'EntL}~Z7Kkx=Y !3|yq2P^^_\ȗ|E4g/?Y Ӗ8[/$gEP_kaT%K{&`Ӑ2pf*YQB^"z_VV'M}II@K~,KπE2s.2(u©TB45}3L[j2ɲh0]x{Vdp"]p _ j foNϨ7)m!hA,` ;'Ya8ʐPyemϡXJ D|UUO fOXC8#<́|D_;5O?|ObE5T˾aZ"(Z$-HӀ)<$i+,(F!X@8Ak)PN{2}j*It@Po0R 13/`=iw΀.?/@qN$ a+X` `= #7@&aK%)G G2nq-fLpl:qD c{.:4 ~獒8?"0t[Ed#pW=Ae(4gVR ]2#K@Sٍr%mZҀH1ʼ3LX%K# AJ,XLBƾSԸ}+IXJ9&kن3NKXiH^?63=)G$,#IЏ~؛*AV@? . O:N1AW6$~%cU"VhX&MU aÖCKQ`QO!o9D$S~b"RŬ2dt Z&"FaK HEIQP;o!訅,TrjC1J'ZHB$φ*g 2""C+V)6/Otx-~4߱+IjV2B,7(Z̤&jKD Wgk-3 Ry|j M# CȢ'6E%vUΫˇp"xsqalNɑ .yOiwinU~)0{ h !yb=Ufv1Dڃ_5/hW}-/glELXc֙2*+D9M&dKq9 '!%Nuq4_i} s'\/QyrU_db?gD*OepNosGw6Τ^oghZۙO )ߑMb><kȐs`ED8k,2)#'&la7+'T&$*϶g`oKdar5k올_~* •1KIY| p,SPEjAȧX+ϰ8^}xϫߍϳ [V>kI.%^.Ϣ>[m7a*3m*BtdR%>YʓsS ԮlZD?it ׍)L\Z% #‚ dp5ʧ]MhߣxSUlwVvjX;`!N83FUGyB]w g}Aox)@y޲ (h)Ѡ\(ߛ`8#ӋS12cwwsٿ;gdU'(>JH7*_?8Ho3eP M=6),^e«@ٚ*))p/Nr8gS䅸J1V?U"M{UVTL:`pmFN6p %Yr:;wƏ)XY1%DvO/h80AD:  # 9XH 6zARLvAOP9&ϱYd!#`R,@9>%+b(遈Ą nrU& vJ<0((xsJTF A)9F ?ae1GCd0ީm~T2 0̛5 h/1%aA%(,ʨr@K2ۉTMxHad=,ŨpZVk7n!bvq>+vfI售6Q;+d\\4I >уZP)jU=B`=<'[ކHfU'ǏX_hzlPbN䖜){W$@hTረ,Ep-!/dyz`ϱ Jˉ.zA|Ŕ'#f |IݓΦ1Fa#%pcEQ 0E-K$yYJ] zÕ5zKWg_߈i >A1"scdO9箑FF.KXEƺ`$=Cz ZT jAb4\šҨWٖ< YshkdXk | 5׾>$ʴJ y[MvO~lK((8T%+}dȊ 'GY1XD9oM9 67t*Pwh{\u`Wz…ң vT̈́T=@δ0,Fda41Gn*y<]Jm_m(IȞΊHCGTvQb)(+U4PĔ ! |@1 >IeU<,2jgtt׈GߵT& F^#(&S:ihvHjHYU2|NY4 LYS,ɺ lh+9w(o_9'wPПU.+m*Ҿ²\Տ=LQ)a{NP 0R\/3i_MIOYCgPQqE,ˠ#l i:I~]9c-=ԍ96pUYun݆\0*^M;(di_Q6RIƛW!|va[h8(ՍHa<^L8:<UO~|ujTs}r۱lViSٳxdu)zyR!N\UqKT7T~wdh@{LD_\e XR"q~A'WE=dALE%pCSa&{ַ >ɵ[Zt.ֺ`2|;1ɹ(/JvfL^q8uYǑM=4ջ؝{Sq]yaU2~摭3KGx]5zl$ayk4sv^ޙ8?F_: ~%cVA{,Fv;G4jq2[w ^6M :77+7(;s$_Zsgu_p5W1+)aлjx҅YU x]He,s[*m(<&*j^'A$↬ @U g1瞵/޶_]͜s +A,#޿LY'qMZ6n˱3)`9.ù^}nn9]27uSԈ$:s_iEY 1(TG%YhP²DwwsSizx;7|-<ԗȩ,j5e^NYi `i㮿zn췴~̬e,Z:`+?ވ.ģԀwK<яixOH e$xY{L[y > _cML 1b&N e&M5[M&vk]JTuUګ>M]wk_CSM}ww9~%{Cwb2# H6B" bsGS_!"W+_.iqp?W,+$Iq"rVIwoa!0677C"R@VW:#p, ^rPq֜ݐ(NVL5ON- ~XmLreBXʬb2C^ϕ1QaZ+ DZBB{0Ta 34VAh7SQLp~+]PUٱ+BY*x2jpmunEkk"0fhϜ4vgHߣ`OfB:#&Osgwb}do(%CP2H[ kmڽp_t5LӂDe9 ^n Zs~܉Yw<]w>k'M5:x k+BF,d"a׶ =UuչuԑYH$$IbeIHx#.لXJ$^rwQtng]mzLW*xn'7h2?qȌ/Y/QdGꆙ$n%NA"Vdza5gV !y0 _[,zXez"k||>!ڿdT!m$ZDJ1F:\|P񲋩 {Jͮq[[|jˉ̏9g*S,LjEIv3_=M໇:!s(y@P2BrCF`lAx;zsBf)I3`}AJ4/*Pe56q/5"{&`XfLsK*ZךъHXx^ӃOkC=@Xi,Dxy';pK^P 뤨!fwr!iZHeO"JGNѡgUx1"L+:V,oTnP9*ZpyіN6VldVsy+JM cTNz-QVȳS nۡ .ܗ>P I .;*+q{7[wɲ֕A%7v"e55sb ҈÷GZ+'_Zj,G1I,s0},gyF0rf H8j?5A`X@\\o0րuog1P\,5D8J,? 9"+ !Lb h::rDM%dDB1Oa85m"(݇ vJWKz*#G8'DdS_ SmTJToؔ +&pKZ('JP|T8&!>&ݦŕ-t h>M)bRmmPAY9Ss SCYZŧ(yʚH9hLMf`LDx9X/D9""jXDPEXDŬ:0bzP`b`Oe{Q;:a 8ehu|uEt+X ?f;lSɡCeALS!AOBPoS7rʠZcL9fNb%_W(@lfq'Z33[SWdxTK?WS/W/ҊE7TU =eTd {)7+Ldʳ^ύ-,E4ˤH5I)L(RwO}c7$womMP&L ,/QN0>Y%^K xf/+Bl$gYdMUId`a҅yYفJFV`:LPեVb`ی_nup K{JxOxWvsNB m N} 4xs}] 9ON6l7bˍv:= `VnܡON3bh J.ݚVunf,8[Z_kx73bj[y@PFc+tR%=Sb3.Vx4 oWy"gmrBĄ?[l31]pϺ=>BnӞĚ"b>iڞam__m@5SZ]Vm\0M%UeLֵfZ~53~ *':ruhQL^׮)D:~ݨkPƜhM}+c u{TEM Fs ŵdxY{L[y$\'$ ülcmLp 1vk ~^;I(]5IX&M?F]JԵ*uUմnȺ}^jp{{w+߷ >5M\bԥ8x'\$0ɧBx35j8xH˗c0O937"!'KZ.Z%9m>tS>56‘dz+&>ǔG'q@˭jT|i_H-ycB<A ^/:w&Dy!}a> tDZB{пM PWC6OHPs(>e-9kp{Y); ^*Wʞ*Fp jGcY1DI#NM/{|11%@)!FhKvsjQCjg#_z?׿h˺ |XtgUݳ%>I#[HRP.7t7mhrAyc:H#t4}6V6tkb?liM?I+lo3%$A"LRvJ5 t)yf}gH‘J.׆lEX'wpf…V7|Z$bz4XԳO$ ~d[Cv'̓坚2"gϼ"y;^1OtIbEOlx#G13:.7*:%t4i1_ܧn6,H t M{" 1^r1@aM0F_Xջ>kiꉦ躬rwbnZaҺ_-JKA_X}0!\*9>5"aK[LlѳFz Hd)rt/DErh4jsëBڶBB䑐 &-mfY6d5GO&PFxpi+~>먆vBՁfKݘuZs y_C+^[el+~x5zq\j!J2` =)^L4/Se*Af,5o,{yPbL> +NmmEoFeT$Y8/zuxSHS"+-"̗/#ܒ7T<)jn)4 Fsۏ"J ѦeUv"+ZV -nTnVQ9,ZpypPC'+B22# >:T?cNr aVȳS hl٢ ܓW  ܡ6p{'[wPii*I>jEʪ)j" ɝb\ lma?~r<Ra1'Z4tZ `h=GkV嘎zcz; 5Φ,> c xuc-7Yb'b?0 (1e0TL - cKFD#Ձ֩$#j"'*%y.iY>WRʞXU+U!/* |T=.%RnRJKh_R= I"]"l5kRan@ oQw Ƿd0Xއ7۴EC.ͧ)EXHZc5*H1+kjY~JU+%O$̡4rیxBT#JU$EXxp3*&Tk0@+tY 25ScMN֟=\Y+ȥMP750 ekN}B Tz0}2"}` Ra , w+hZnr2.pqYq/`tEUc %̺v{<|%-!-[[Ќ}J1c5H=r$ss#' nv1"R g9B $AҳI!Hʽ+D֩O/FWVHEI%GBKi)z\TZ`eE(}Eػ,req̰=͍;_&N3qيz Hs ?sRHsF m0:H,'76 "ئƒ݃ǻՌmZk7!tgɑ)Y֮tq.9$O%4%{o%3) !'էo~l% 2t('EBe+ 16UDW@>ya'^ȍs6-+~-n:iF9XjM q>KiBx@QۭWMgpA4Ut9y3e'w}盶 tkv~V!Ai3IXvc'yͰ4J@w+/w&A$L9BO-Y~Q>1N9opOh=G$~]5:㢋QvK dN،{9ty 8"kF3J)v;} v{|zBfJ.X_^kVAPWT^By^; ˫II)QE} }@в%i5m,d`@e(2،,kX:l; M9w!&u@gȳBYJ7>`>[N2Az!j(z|~J1D=cXh+:SKc(IT%=E%[P [np2kElS^1/|}N?sUzpggzmqdzv4 r}P:iEV9yWVeІb'T#l")3+-LLA˨ >uإ7#i|6JkƝhmEҲ|@ܱw+02hw(_SZ7tFa>F_ W,p" 39dr+xo.$i7hu"9ԥiP :';P>+ګWSp+aE.=~4ahw[9 8k+섓ZQ?OlQ̞G! ,|w_]S0wqfu(i,8ktlha5UKtfOjw{Y:r*8yņ%DCI%xW}L[ HH|\cH8l@qll?x~NpZTj;mڭvUjguZiI6eϦTEmZ5]v}6@X>ν9߹ߟWFL ZPsL)bi8#81)C3=!)W]-ƄP&OIb"V&ŘWMtB (堅n{*T*'tNxr  D:s_/ֶ\PV$'U_6r_Ŧ9m,7Zk[SB[J ȵ`7{ڽ 7;RaاSm ܔ%5ܜiO M45þZ3Y]F|s. .[pi s|o8sK Wu"kҏdA[K>#WW9bl^.BD{;B2-Ȧ.\B0l^kouD7f8gY |h? ~5f4LZl Te8HS1乄(;T$!P}~Lș#eKw/Lu#Wc1Q Isu-Ǔlvۮ(%Slh^3e?d,䠦 K=M`FϘ=w5ՌRc5x$q%,z"rYk?Qb2!nju Scj'&U^?q oVp]úx~`EĔfFn ] A?`Zi Σ Tzq]*t@2(<@sJ2c ۳S'*xkۡJ: AAp V3! c`ͶI 7ӄĘ$fMVBj?^e!3~zg]@4[/b}KIC_~&#,uC |b`"LT:K S1]c TT$sY"H D@M\M#xQgU M4Gh{:;54DXq(a1uQdwzQi+n TӍ :vHaeE,m; uxPlPDnօnyӷQ;*6 tUCვ[3~t4@F)-mwٴ*謣cձ)]*'rщa!Pjo$QQ"l!cV1o{¸603ugr?n[~NyC]lyTDB#?s_5Y&h7zCicٺQ%ϔM;T&NK|(Mٔ *Nɣ-Cʡqh79pXcol ˚0 *fR+sA##~9=S DٱasoPi.w*dԥXv WW#4Lb&Q0!敦[c23{x]RkA'dj̶Mvc.5 &M$4[MMMmJ" =xPyP(ɋ0ЃR/ һ~Iց{~g?m/52nb8o`q!sJxMSrU ! w ~r>c[04bȚk\rH͆0lra(w:!,9O;h+77ko:d=,Y <.Žؙ=N:}qpO|2=b`/NpxT@|KīT2INYN WPmh"7$( d8GIVhw6IP vy6naET9s"_z?xJr:U&iWC2Ly,c˅+5.PRFQu7. %zt&VJ^JZR*n|b9 3dm^uКd(/$fbt& PwT@陟ghV 5uS6ZP-|JID3TtV.9m#+6SɊc$+j*aq˦ɩ-z~B,]ledV՝djH-ю`xxqO E|eع8`V1by? qKl?6yv}bⓋX$& ,,tf,椐* *99KKa N! ZZ ٩N9Ij8CC\B]# JS+'OaR/+>GqsVU5 Ij5: C3Rukj*TOwIM*M7PjLPHI,IT/QH/KQSVҴPY;n8WTmxTKOQ JyXBLҡXh $dv!BH,B+IqN]ԵqeƅΔ5f|gfmwv2\s9 65Ecto3lER-fp ֹRF4^.ƹU41)aOK _ZPBu.6o5‡%u6>v’<<*:<_Af|2KxGQ9U0zۂ".n'|GX1Ϙ|qhYC"l&$tlsdܠ d21J̽g[)# Y:OUpkfj|Rh*WUYۉF;ipZɂ'C~lpUr91!D#B2+&FDe0+HXԑLabc"j98eH?Pݦ?l4G AĤ 8Æq lO>`/gJfjg^L[|v釥vm//1{Wp!1{xt {Y:LJY[]ciINTúyD*X鞱>5:ezq#5Q,: ٠ٍ| 0sp,:G(^0Gnհٓ"Sr \S]r x :+nC牟]΄NB E. eY utTm~dʓx/ &$n÷Ę|ofsD6 Ghj}dB=B690,\x*+ΓYTÓx6I &YP'#'n++[,M. /dz/21x|12~2^558C9w;[<<$<$DEƳFiGPEYvYo,Z^S_aTh Vf`1a'ef:fag2e$+i=nvnr 'zhiixx 5mԒJfTm- 74ɩ$iYXNTU+|_ HKIu |Pnؔ"#obJJ|njn|rbrFd~xT%B<@ru6 \l1xrj/ N j٩@7:NtAة24es-N򽂰!x_,1BUCS!-13XOK v iHv?p˞0rxuUMlE67$mӟT@;YIh v8Q4űP)YxzζڔbR@OV$ !.T  Bq+'$Nov7&g|y?O_y>}|;f?]|Uj5Z@%q2?N/6(*KZK@c=5I*[3 xqVe_ =gpk}>aKZRhZoibs1v~k @˨  {cwEh?" i꺦ďG%& l&c+R/J ͣLݚUkh4d3 &5'pxFe}LAr8;}N Saʉ9|%LV!8Ye2ar'8by܈)gxd=gs ٬ߝIbPa4M_ŧja6|U$sgWPFxU$~2E⪱̦0 >[s5n P[Mq}~-p內g hNluH2kSHKBlZH$\ծV:&`jHYӉ"1Ӡd(&rmE=#0t::<"@Y0zK[}Q /I "EXSQQ\ R5Y3&'U0S,-4NjJsmOI"?Dכp/(MN딙MQ>7SBmL j^Sq =#PX6bOp"_H3Mѷ [[= _k+{$kϮ^myq$+Fa| _z4ܻ< [? ~'xq l<E%٩ؤғRR\Ku8@AA!ILa"bFn΢2j^B@AI񥥙)dYWj&ˢ)iřE7،zwץ\bFɟ'O/c?9OUN't!3xq' J̓M6d cdTv(4Ěkfmv1vĜdҼɲolߊEju.VK bw;M.QH*MKK-Ҵ暜X);y+]JP: ٩U ()'xVzo-PTXaZ.$WP 5ALdf Lȕ&3yaw: iEU@rrr"t(*XO7yY@y`z)$))'')H-NU(Q(J-)-S QjIO-O.JMI+Lq qQX*39>G\l7Bg?:G?gWsd ғS WMP_Ъ%l:`&/eܜXTv]xG J̓M6d cdTv(4Ěkfm5N jj >)ީyi{:k)jhe5:89!̪T[c&/+^&t 'xG uxu2Bʋ 27iebL\l,,M3)eV&yVh558`!+P9?$dP6HbbBj2 yQ47ngrQ<)xqG Li+meŠBbsݸ Ux VZ A Z\Z K9l , n8 y2(OpfU*Dsrb榒,\}x{G u63N+(MN|ߌ e )x;qG q<&jl[t ;x;q; j'e oR{ aq|E6lܨhHx!q\7Xq?]t Tq (x(%@ #&-2&81E2;SA7x{qO 8}]RJ5SKJS+2RrR *T+tsK l% `d 9u fYxq Yf<e ?x'"ɯ&׈mVp7׈b2%&LPͿy+Ɍ'j*x]{s۶[+:vvv(hb[^K6{%X""Ի8xO([iH ?A4qNY(X&p=ߞrP4[&4\Bnpj9 =&7ٗ`aLY:N.C"(zJ8LS \.룣i;;;l5 ?l:~QEhŷ,%][z.qD4gP{MY0.,VY47?Ev,,%e(8YfDzdpFEc4`52M p8 NG;xf/qifc6~;>z'=twd(sV ?oSB‹i]GsMfo^E B(Zj~PYrxNۓzuA1/!m@=Nt:*M?ƟqᛇG 2i~㪯W)ti cҗt=‡0J߯00uo^.O9RӶKKÞB2AhZ95zƃYlp ^> gSሏs#/A&wA|a\w`0;Őuf/0& AdO>mbKN`;x㫫 !$>;^C=|0pԻ의J& ˏfe4(MM}YQ! 7W1X9:MaN1t:\9Iq|c.@@ S鿭I=k CAq" TVm1w/-$ߚ'%Lb|p~ #w9 #o[,3 _oѫՅ'IC*hy"p,ãl7n/>b|\S Zd+ŰX`^Oѧm=^Tleb0BDy"m9=]+r,̘בi[#F`cvke@0.ia%5zO;xz+F㼭?,'ab~ j%JdoЮ'sw)qS') y~>pcHM3s8}M*1{ CHDY3Sx2%2XybMLp>Gn`AWZ:fr|AW!*gU4 ֪"OhMj*kEV_R6O\$paR}JVh<"%0Yk R{ᜱ4Ձ.Ss`Ck#B7FliȾ{{ǘ{kIel)Bm<\pdbJC4l;9ń/fan^C_[;\Vm6t ?Ǫ Gq] RF:2jrAFQYDGWhDYLPYK}lS,NZo/!{8hB/qG`ψEe%^ŔS>N`R1B`EYpū6]IхJ,j=rOhzen)̧Lo1 i,eN*uʶa^u2PG# n(N`oD=nL^K#onbEuA.bf\oxG~# hA ak" aMEtNL/  };Eʣ%N6d,`y`4hǬaGs%V%Bٲ(x E ̾돰Dwwԙ/`v) 3XtItAt2;Qd^ >Iu!m`߉mV h5vvGEʏweg~ UDwdۤv$=/^|y+I[c?GtFfZ֏!ݽnc^Im]4zx_գN,BIf&X0zŀ7"rc>Cjԑ_a4cVA2D_}b C Yziݤ^;Y(Cg)$c,Bw2͠W|lb6TGS ͍ uǩAȌe }r]y$Ky 2],dXb+r{|QN ES-)y^g* E͝1d] RYs,R j} )F#JfCy ^1NGue\f7eRo*V8<'̭Sްn` M{] Ou﬊FYޕ?2t)ƫHZvO {.y$2ŧ{T (&TB9 􀀽Q;'TA*N kP=jKԖ[q`͝YSz|6֔2LU@&iJ$%,0%!gU|iCRrVR@>>+%}A#$HNaY2QGGX ZG0?`] }eyƪAHLoxX&p,U+8 7S0"X|OpF@Y !*+|JZօ4\ +tJVvD`DkDp/Q% 9r4 W&⢙ "LHdrjjER{." k+rDz; aig1/8K-%2!q.b*Fh߲¯R&礊 f>l~V+pg\<\:YŎx\ڱe(a dupNuެVHu-6DTBՂ$EIOxQl|X®{eگ)hTՂ JxɩЪ KTkK0qmdpI\,)D V%ؚ9N iux*LpjO,Iyp.n4aF鎺$~M hΩcmQ6(5(Akt^5ͷ._g\L@r5k[ ur&)ҲV傞QI<׳")(kYZ RAѴv βh 04oȯWzt]u!il1QԱHvEW516*B "/$Yb/Z¨,ATR̀ztPO%ϩm:%7OK\dT]1\ƫ84\@ҮR1N"#t;e} J ]QգS r÷c+>S;O_2zI 2VTvWKf&]*s *q24OWLo]o9dlAjYs{QE&<'ޠ fj?/H6e/r'f2No5B=ùDBV9/:Sܠ< Ob-ѯ\@,=!ҍ1Yh>RNj Kڞ,wi=,hvnϷp[/ӿت{n򱈩Y-Qnx?xҘg2#LMdR(̸I Yew?zp킖LS5ʫ bbQB+1VږpJ+Zx? b̋SC27my{`j"aPpׂhن-MV|nKq5!-WzDp5mUmWEnjm TȬE뢃U"7 >]Onnte \ЇcϞ~\]qcjijbZ䉐QbIa[ ´)=jU6 5vm@1[h'xkG%rFؾ+~N_!c\oܣ;kໞ[2Ic gTOYFR| WǮ3mۄ놹Y ʠ? nKE%CeA% pp p_fC}})VYzykޒu<.c׋f"L[5mpOcbL4jzSR,t'@z%_!6aI3m6R-+m\UsCM] w~8Sd'Ǻw:zj"NzVGB;C֒-+|aXb|W{\d<6(#_tkDmwWγ.dm=TF%~|=rIt ?q_[! "Vw uMAU'eI#AsR (r$\vOV՗ژ$ŝ? '4"Lg&6Ga^Y)Y 3A(Ǘ.PE#oEIo.Y PpɂvYس!(4 o,?' O6 >u` V+rv\M€m /qR3UhF'e.p禎TIePd%u_"Iyzu' Vge2.wz&ʩf1fs*sQ>Ad>P$ΟLIJ~Ln&3J."%){5nKm;Tbh(e(Y_-H!{шm9{áe95heJq%T?Q_ص:x zF\b4Q%z:CXuڜyLZɬL[mhp$*<-/ y8$j܁A;Jn X+__П%x@Zyoe:ܐ.Z.JWdj(ey$QT_^f.ΓddXiAQ3G`aI$LGJ`A L{ڨM뚶liLa aWs2waao q ބsFlg V[H2iLyqԋ Rp)<"*^,\z/\o$(Y(n cht5ohۏOjg|9Nqt9wG$2$6@f-d%._HMȒrqMAAU >E,fV5A=&gPaGB_2n4;}?$l@;mLF9O/skF..V} swu+\erOzP ] Պ@C|U=W}V=PCI:uhik3-M)ZEW!*) )Ю8n)1pEmy,$q<ڶ0z F3y.௓cR݋gsj{)߶DqJIRVF?eNP Riڐvꀾ}hmJ}8-iˑӗ]SJavdw|vޭf3/u8n=CF1eG]DfvVƑ䣜*m|Ns㨆GTJڮgJX_p 4bۜ'\e_GpU1';[Ƥ'\j M8 ?Ubmᮾ%'S)Y>ǍE@(Lr#IxeTV .c]lDo(I<&lH%j 5F"jl^I<,HB{Z%նq #O/$>Y݄\| yod<OPjp~׵`Tmߪ¾,T56_TY-z>glKX_9J]ΦW%e R;)7m|~ʊS޲Bf*c/Yf@C9at  =K]>4G"6y֕Y@t כ bdd9wg%%G|xkm(/ _WFew2F}a0ϐt2' ޽.>oƃԍĖ"tv;+Yy&_oY[c,St'Qd $4/dqz)~T󕜠UYr&- Ͽps)n"[[s(NR A< ]2Bd 6.sd:lעWyZ/h.#h|Hp:S Iff4קtHu .h#o.ŽWEiblAg =#\'{*?2`MԫE7Fg.N;2ID>SBUsjSL* j 4'簢sZ7@fct\#|ebuI2@dG'Dn;;39OYeclϢlYl&I;lm09j[RbFF9 ՜}ҾM5*8oq^'g]Wţ_JS)xŦ539RwK0ҡ6MĺVD'/PvZ*ԵZ@eB$zjJ ΞJ6r>KMK!?*N`x[ xTսNHBfL}3f& H$2dd&f6fD )V-*_E>T\".Pk)RՖע}V[iժ{Ȁ{ę{_=wu;iW4Xg4}QsijM EU a,&p[ NIYQ.Vћ,}(RPLp yhjjP޸yE*TFY-/n@>Uīhr9h7%OGrP3+I*{2yEL%†:Qhs!R&*Q=$&ЗI(Fwdjї^QLV`ngxk; xp7³+ӃMn_ fbOACs1ƌ[*"CMJ )lV=Ҳ:ˡ@2^(?\ ?IKh\ۼl / D#~Q;!trw~z(l mZv}TZؕ%A<s9Ϗz!NrCO?3a'Du<N{g@ӰO$I8VOAnBM:97N12*8/w/[IfZFrOY7JksHR\ƱHS { '{sx!)pi@;Lz,xi6Hё#%@ QÕ0;(dv.?ZcAAN[ԡcjjc& Rej 'tρep/ެ ;RȄ K f5ؾ=,l&4^E9A!>7_\gs6 ʷّ当pŰzs"owoNf\ؐ=:2MW $xgjU WdJ@U1XS R `jVTpҙOC"#Bq pfE/WHdNבH6$1|̱X~ /oK YI*j \})w'vl2qؙ?)'D}8sʜ A:8&j2 w\υyg~:%(R-Ϙ1PjumbNG߄.&]-}m ~M9L8mGm[b |Pctt]\ |zȄنNqIKHqjL ]1ͻݥr,V_"r~ p~6:T T"'W ] e-l@JhK/9`iJ8w3$vv ~%yٻ ݥD gso |sWOx㠒(Qpŕ!w/bzvMR{%2CGh߲n(|}X^vK j\w_<$I01bIw$clLuTBe[4l wNZ+Kso炝 22~9K=&dGPPF"}-S:5= \D@^ۇ᳑m4Ih=Iiꢃ\*=#=IIs)⏢~{P'R(VIWYrѸʩp9Y<Tfhfkj ;Vfn0*u`xT;O=u)x&3Xx^pL N C6>2 yzOCI.ϓeps?7+/|zo?|㩒YחwӅE UO ?St<Ø+*( Q3G* A3Mԅl > 23Xw+4>(4 p ^!{$0xdH=Vi~ߑqi#H~oXǧ 9.}F&l8rѸT5+J]gӄR> uA<^@jcbR-ϴ?JBy r S vbrcSCȡ-]iY*mYSZ9ޗc6Q|"Ta#>*.X#;e7[^sHLg伥ChA1Sx\܏" Su J}L wDt؈R_ZEo1n wݎiw٬&ƜQʅ%cnaWCuX*wBW3.LϪnӑ)wPOº$F>EYZ,c,OƟ+4T$1xItDJ<9 ^|SvC j(~:&O;ې,`2 /gM i3B70*/Eg}ٌ0p < ܙ {Xe;v' YBvT8ue p=Zg XDT\7ռtë%9S560l~jSС|HM4~>lf#H~-S†-d% ؠ?/{p!tٖqsa(#`D/Np F Õ_%"xe0u: tz}=C+yE68>{H+$ƴ; /0?SQxz2Iy}~ͯVe" a+#*mF}a@ߢΟ/?;3?^/f6ORM lz ӛ*/wUQ8?*-70/վE;*\6GL!u?Np^^^6Y8(KobVܴBOJ3P}:a61[WXA<{Pg2H4CqɻζPkq﹌=Y]tDJ.&-n8 ceIިx8s$TrBɾyza]Vհoס][Ϫ} '6_\%wrW".}8#Mz7>%~E<#n:IV SʲV#1;Yga32! ¤h\inp}\$kݝ^b'Kc8C,G.{qN\b܃4p h~*%]uhx a깂(/}^كsùxxW32Z /:o UViFh/m7 =-+@|U?nrL9=_/(~(ɤ7Θu~A0ZJNz/Ă\2e/X:?Ç5nT.^_#ro|U #>}saZF"*J4$T$\}HyPWcq0Q"{&e=lnJ¶E0ƿS] fޘ^uJD4,ue ιkM: (exk[:kkƧ̆%'_:46J u /x-2 self Test-G4@P:Ig;xXyTSg?aKB-@ HA (& U Dx 6$ȢREkkKPױZϴS:ESgZSzRۣ]3.}@{߽߽{ۼ\OUFGK۸y[ n_D^%\2@c2C\mff0ɩ5$x?ߋ8BTP-VZ ,YA(ճ*Ʊ62lV JtP~E$Noj|4/ǧJ$!ImZ *'BFxddA(<˜SZjTYs s Ky!3%99W[rˊ!U8HU}?)fagCت#?9_ ыXJd dd:!HSHSRuTpjQ5/p( pgJ8Zp@ wLJحQ-ֈP;<@D6[M  JEbh7C+&y7`r z+ [o(X'Xhj*xgD}w[7ѧ(G~HqY̠]"T$-),flMAp"Yu%v^OBUQVN9o~^:Sg4lH{@ $p!nͅ0D<85-mu$q\n)1S"EShx/ ^KQ?i2T*FC) aV@ym5fg9?e4-|fTdmv=!TM -'"8ggYe<(C"\̮(,,̱Cmւ]"\#1B {)\G!܆J&nz%A4d)>O (qD5:γ ?,̒(,cD$$ ̘@e)\y(o_A'cm>b>s8 ,YnjbRM>>mjQ!znCWA R" Ph%*P rjҬN:Rg*sk} (gH|z2Ar1pl'oA2hYD% 6-r(:̟T9c@a5VQMcl5kL|= c:,e\L }οamM,MEik${ȃ]^obArGDOEvX:IK?F%Aj vcP>&٨MgwV>F% Ú!"g&gU aur#ѳa{WK[р He7PPM\ _!8Z9w:5xͻB3t-׾@JI /^}O cK6 ?Р殀3UÐvƽ*Λkiʙ^{H>a>PHU"/Q; ou;h.oÝ Svr < bpo->ZѰvᛲG6"&u poj" "% ީWo["ϫ 疼@z}'߱d;p18>IeiC9šTx 4%#b΄w~u],z. a SaX`"K'>2fl5v!c3+dK|_2*ܔi.i8$PIO_g|2Xs^ +hLqpZ[ t“4ә*>51dҋB ~ʣǘ"kgPv  [=ߺ%t;/!bWb-"瑥zxRaׯICOB 2vOн% _D"iD/-r>Y[ cazAcϐЪRfmK;U,:ɯu+FioM+_I49OS9ä_߷R^h0z'( _W.8?m ( _ D:8"RP°:ZWec  @ۡBːYW\(oM)_{n% zj`AP~cbFl oW.%)pcu8ÕH;pJY 2,r-ndB07VUwkxqfz,@?g͗;uz2:f4C:;OEwHLث׻b B UM>.0Њ=q ƌl ^ L<3Z Yx\;[:n}ӣ4N豙mQF)m`Z.ah2n_ ( П_X^hHi@Tq>wD RvY+!֒h3 GQ2P:*4?D &sՊbɯC'Q>QTQD1[<-/nyB nݠa4%(Vb4zy#61VV!2:iE;]C̗>T_kVxY XSWn@ a x!( EDd֯$&/ Zթ UK[fTZLN[[Zvfe 3vK{ao}ɻ{99r:?* g`:w#vm.|"nSzQ# @TIlD"[O.V{ݵp#$bqf")ZLv(FG zJv&KH]3¼ :#٦o'ZaīUmbMTIYK9aPx ٩TTW'ڒo'kx We&>rm uF6+FH4I55x.E:Dž&KDź6TK >rF4ӈplj ]![S@Pe5Rx'QE 0ި^V,h&K %0e"P_=;Q4c.p8bhiT苍&66LRuf54)oPVo'0hv&u&]*MmQayE_,f6q{7]qlJ4T<3\Wá UC7ޓ.xKڄ !+`]zoJakt'LJ RҿQ-Itڨc#D~SF^KAk+2aw+a~uOO67W6 LH~E D΁ i ;I=O_{Z"Iq˦ŌLD@جw {0^2H}kt{fd'q r7K&&R"6٨#j+ lfԕVgKlR|(J N X9-+8750Cd}*57gCaW0 yFssx՟| 7'lh1d"/%Fݯ- Cb[RcN{ rhDIR( ^iL-DJ}XD_ƪP|%vmJg9*oOį=a Qa87V!4te "bF7*Z( y>8^(<aT(=`7Uذ=VWgߑpr{*/W ' mYML{l[x-8lwu1bo<9&<f%<(~,—9 ZxgG3#~l^*JȑO]{4]1MXduC vWe?a`c`ə=$3N\\mL"m7F6SwO~%/\)x!>n(EF?:H b;ρpJƼu<+C_\/l|H-hZɱTG ;>IW5Z+PtdZ3{2n_W_86Z[e&."McC(4w8}y%yuEܟH:@X qC5[`ߪ`qe_ޒ&ɶit ì?yIB+ V \i&M(Q0RHh!IUY؄/jid8@ ӧ{XZ(kѧR| Z[XD4IkK"H6v&#dKu5\T,v8q6imy 拭96y2 hY/oFSۧLD! rfrꬷM.E[ UzBe9UII\'8J|W봝~ѐ,~>I;kS$ktEu#Xe]6ϲ*vUK:F0r\~y O.f8ĸDJ9|T`ɛ+of#F+طaۣ,ӝxWs{"["ˉ\daN~;>T3x;V…qT ßNAS2ʙ8\J,Y~;4NPV ES{'3{ r Kg xl3Hyȉ ݑL4 /s70xew ;y=89sSsSK4S+J3R J|J>y%VO(>9y[&yO-BxaR% X?x7 J'gHl{_4^ H^xoUUTif (result) { $_V } }0ǁSa/V: ߑ *&}~ D(LAil\Q.x[g AL ՓL89S+3Rl 899ӊRS5m*p4X"Z\X_Zi=yyoLũXPXZ991\|2O_6'HNe>/Am;s䙁z&Oo5y3żϴNZR06NĜԔ [&O+}4PQez fb &+N~Ȼٻilu55'O`4K`2"v`Ԛv]z|%B}_[&fKLk[ΩE%iyi&L |bj(GdAt&L_ӡQQGGqx-u+/++1P;1 S, [QNhew|i|YߕbglS4ψIzb9'OKUH)NUN /QUMOO-/*3RrRs5<\Mk4 6[PxG?WOHmJfd[q' ȅEW19N%,3sr|3JRKJTetige4b?yG,jS0f4e}R>xU{LSgChCyL Z LL(+vb{ +"(8<,5:_lbn 1_{t[2&sF0 |- nYvν0PH :Bo:(ŜR`v\Z'"$5]vyy&>M?4WfPcJd%㤰[Ojr"u9YF!D H#?& 7zڨRٓQ%BѲ~N1!,F~UA%FV$V YбM3QG!8-6E p5F; 1\W'Jfe:SogM k5>d0سV&ê9 tj"3uZG@ $SaeR]SDGwK*jtѪf5˵F]x`yjLv-r.L*r-)3{<@+ gjZK&ʲAK!My#u0=ip;v-NE3EimA0ҷo* K"բf'lUWe.4Zu:[0J{ R|>j=nfD-q2nTNQ=Y\"ln4**ZtUZ+Mo#ɛkH`hOOQך7>< Ǯ*k8vUp+}no Yo 8SvVn&`·0ԙxR4!wwbE%74`j[tʹۨq>U\WV\UhʡoLm[xڷ7u-MG) u̹1һw&xț6SmקýHh\ Fz=S8jo␟ ;ܓ8_y #B +9muo<+]`Pӯ)p btzo{?}}5#{+}i$H@ O(vgoՂpWE["/Bα*5sC|8mPO2s#l\-dэg*Snx)t\La_jOJўsjItxi_b;k@\V( CS8sk;ILDf3ŒS)D۟DRm«lU)| [% Sz.R~%M|2Kaeu _Y;_ +#d]Wx(ݖBWıA`ug=Sf-~=Ylk3Rֿ xv\Ecfz=ŧ %apr3ʇiaOPoZ;=| !~"YPoﮚc}(2ŐNN&k9Gx"aK&' 5qɤD !"BJEI0T{/.I4$sf!$fx zʙi \Eyy > (4)'U!3O!,3-;rNIa',\[[958((O!$85(H#$885?7GӚK95/%3m"RD&>/' ,ڼڿizEF_Fɉw+ssSK2gV(T8'(hn eTPl *XXZ`k Q79?\|b6|a|K}=U `vx-kɺRd8&Tyjdw[]d+26,>g~̜a%wLϤ0vdݦrMNY2yBxReIjqPjaijqIjBISN~mzZEy)N E @sS}Ss*5PN^8Adv+5Ф6q,Qg횂\>Ať9%J Gm8 ~;a}xe rl))%񥥙)Iy)EU+A3RrRa2%@HkZOS#TVZOO*YE !#6h`>-f缀_m1 ' -t+pٮ{Vn₝QݢK[DdRSrX*Jd\VAk0.+yhC: wz^@Q_ڐ^rgऽxw"y*@6@?̆&glK%Oxe{ RsR'[eB}|t tR˃u8A If_Rxe{ 63M>(,U_[`(&IXQjbNN~TdvyAMk.NN4 Rn2M,I-J-)-KMQ(pO)TPPP./Í)}^NjBQb^J~ əe) iE@_=%Ɏ;$]20Ybr9ũ@ &8 zpjwtC]ZxX p'6`I( qI0:kXҊBfIIa5i&; m $@t& iIڦpthR&gjw",?{%τÜh'I/;H& V6X,=7[-K'ĦoJã'pQll. )k.ZXXqg7W̱sqq#2Ԇ<8_EW0@Kf{Vy]]4;oTD48G E6l9gxɅpRxr1{a7d_q^+JvAiK嬦MjpD´i 5Uܬ)cˢ7ȟ ٜ`P "M]B2dksP&8EkE<8b `.H!hEȳ~uqJ銋$v`/GMa , s}1@(.ŇCq>J8@cנYa?OdcPƾ:@x jXKN*trd*ˇv^9BSFf FG N4C1?rlc;.ҽ&Lip 7N}[U۹7O=MBqܗ &WMH;`L\å-1YfkRj8l=]ڻK9x;/[R8坫?]XYv7DzğfQwE{3ƝzȢf_ 3_wlXM[ar($P~4S֗:>0^h.ZkB,~ c+'Ewũs2!< ;>`CEɘ,8Jӣ)_`.x ytĀB?Cd /'D(c6^پ‘eG1{c|ao]P7bEs`E"l?ψ,%cĎ7т3qN׶6)]&J l}I_==jh"BTwunnAPo>:o 2񰨪N}T 1 [W[g\`Űv.C`;-M3 6x론")HoBFM!2NN|(TJ{v&X/ 5;{ |t" iǫdE`G> #毨(eW% oʆ[ ޣE>a{-(fSF?D"_`t`q`yhR*ppgbK )ϺΝzw}_~TO 2|jJ7y|c\A?)J"%B9.TT>3BwUSHeȗ(CnKg>3}ߔ! cJK_KS9҉csm)EtHg#;%o2*ŸkUG0W Nim-JXk/#a%4WH HJ3]:@OyCR)T+=|;:aDž>ui%/[.{sf$umj/g ^x{C >mObd߼ǛeF.F %EީU: %N9I: ~>>֓ jl50'\bn~N D1ESAj dG_ɖ!B?h Lv盜":d6͇C/H 7xu]HSayr9d [fnZPS_evXZ7!]O5/4$ˆ"&b]TPee}}yqj"NMȆKTt@( 8L\{jldreVn?FplvyݘaS P=LKL.pϵ2J03k$aQfƿL,t`²B>I ^9#HK :,]ίV֥,r[R~i Au izhB"ZQ Bc2 j.nnz-UHm d>|tпtCsmn W؄]iuQ(hpn+M~ $,P]!ntAJ@>Z Z~ߨw'%J`$_.X~:5?Mi2~mbId.B,*Q6rAfEpՄ ׸%=- v7-RjWD\!£7ҽ|ZR[MX9B򜱤F.d:$PSJo/D$Us%莨"tY7kDi Aaf=R"1eyMɵly%%~(/yÍ$xC z7&sl/$yÍ uxye0FV4?cSNKL|N5O|d2vu9&Ym`k ײ|rZf}wRx΂`σ !%x+ G&ڬ?͟<]vf0h 1Y^mV(fD>g>8+l7Mb\wrA,@Urm{6( 2  a?ZٔY[ fTM((ftIm"f9q'ŋgi?ߤwi›Nn^t bE`nN f\z i|^.ZⰸG aI biI͋~e? {ۿ21>x̴ݑXfz?#v_^i WIb 6Ą?ŒA,]nݮ.f+1@X+5q._!0`rxVkLSg R rJ T.)"5VePh .&H&u:te34do8d:ts-|}y|Oy'\>p8fJVܝ4B`G%^.WFS$LeFlfq*GI(!'$=a40^&tzf<9!G`dJJ?NS "0ΆThhm'jй 'yi&cIV_XF3wNtBG ggeg> T&c֨%“TEГ5/(d+*R[YPBT$ͯ&r]q((IBg$0 ~P3B||V3THq9"|%|11:v+a:pV 5V b/ h~S~(> -k5Y\Zb} DFh"n4F5Uc*aL#1apjV-W0UY ߕ{a^CE9wώE` )s?ϑDзk,Ʒ%sڙ7a@_,å-Pөv)>> H(gsu4y0. - MaC߰fKm\Pl/e 9p4s_kc #7){ac`)*rxM霩8OlܽAߵ|ߧbR™Ca;jеo[y~gʼClƍCfPH8@㊩i~c>tx;GLh +;ji'YFjPɯ񭣷=a9>,ಽ\mQuzz P p4dT qXiwЎB)(Sߒ, *&ټXZ 3b12]jDw? w!+)Niϩuk/7-9HmQ' hkCjHhȮѓchAިӛH2U艔baڒWi F^{>Yrt8M쌇`jm0Rcg i@A?g*0~2HO~l8id2ҿeTΪL̟Aƅ+&sѯݝҝB>T4$FNd=bk>c(?zjv-Uwiyy}x}tcss5 (4|9<-ij)}/!6D |9q:"  /* XXX ooh, magic */a,  "+Yq/ x[:u\ Lps]B^: +x;l 6s0yLJ{86G nd|d C^x;l 3R!}x;uֆ-Je+1][ x;u ;0nX0]Qk{9m Bx}ks۶gW9SvqҜ3'mfYI4Eeo%Xb-:$eAHى$6 `\l ?A GK`{<((?Fp$ 1pVP"BpUrEoxͺwA;Exn@^⇁78Fj_?o?lod4/_LxtOñ,YM>{gC/&O7t Ar7dOy"Soܻ;x6F^h .7?> ix9h-ɠ?C$";ݓoë&Mluq =P^kzNNOڝQ=; !Ejݷr#1(tGkwgNqAa|:nh3b]ӊȥ;:x2xO^0BsfkZF&\4b7ܩ]'z !|<{Z't4~pj9s,.Y㴃{>wm Ew[9ҦAOJt/1ĻqJ(˅5ev2Dv[L(0#IHGK`[P]]if6Rwj⾺UkL1]92Degw6^js =]2Ah`/j^;~{C ň*=Ž UiTĀYa-ѻǖupgu+ D0W)8HaBibN6ѢijG X?٠K|d"(Z=fHeN.*bF`#EYF?7x+ d4VZ ^#AKb‫.QˠKRD YqtE!dK4R5G+H@tJ̼4fuck}HFƝ( 'tD~.+ϟы'"NlE0YD6sq7IіM_;[8a6p;̑Seymak%֘"-P! ;8^qFv6M#]K76`/@;7엾iD!zbsox d=UJTщ5Daa Fx.7?K&~0 %ax~ |BE0!#L v[1Xлhn ;lhF3M{{Ad|'3'ptv>8nBnoUK!488Zg}JM)aMpΐ\Ĉ#wOT$sv:GglN '`K 7bHqڟ;zS[14np^aE.zo3!!Q}I~X4*mÉxpE2+3_1K 1|W M$\$xb@8q!F*r1yL  .s i5BO4ᰁ!Fdpk޷Sڝ2w-KSM[WWSe$N:`-Yt / э?IT'µٝpzk **2|\`xU>Pɱ xg̐=="wtz!f@8¿RVMB+3Hc( h,|1D]\gJNL>NQ ' DBA!rhIn'^JA1^|;~VeY٠+k2aU>r])ar5 rrtb5BwF>4h iQV^I|d59.&2#DI)4$ *ٞ"c%) i`@Sx}:B{jQNgFcFRig3/ bh: m"ڼE;mL]|qUQIxAԻ~%KRmO {W>&˥Pax/fb#E(='b37+D {.+6NhRbJ]LѦ}QwʆgIWEFA!ܠK Oø:O!7j:NG .pM Ռ?2G,~K1t ]iV![\$xeI'w ҕgigsTfUZѝYMD!-d5sB9 Azy7#{!6>~؎*0_ Tb8tᱦ)XJpkkr&Cípc\NtAyyve8BdkOwͺx9ҹx%̍V.XUzێ} 6 fhx(&G m#o["f D~_0oiIfj b1[kGiּrsnͤd|NF>`lqcGD3h="E6'҇@sL/ !ZX13@&,KEXhACv8gÌ9ع!#&nɣ[!{DCop2>9LYūDڞw ӊD+=tn R <d*ݪJ -17U9f~%!%9lU8diM]7rC\qG}w$0pU;3+gV?hoEO"C?6uCK`9 <g]EJmI Dz6.}sb_X #|esm8Ze7걼bҲ\m5F\S=zU5詊GZ+cizݣoYx1o!\յDHk[(lh76z/P2RrtO#0Hqx,u],xުԒׇI: &IڠN1I]aUBZT4A@?b`:%(9-\ 9>V iII<KX $:Xhȡ\fAMYs9ۙKK p*!lr3‚1DzTX`lej)gpZUڝgc[Ek8#CmǨs *ƜkڢRBB>.tJ-Mȹ\_4t1fp_iIfHH3tA`?rCnbbQG#@o7^].^O't1^HUe&Ps8%ạ0 {( o~Svg=cSTыQ8vz 6pn ! B 9n,{MY,gaU`"T*|qV:26p$'z7KUPC.|uy2_nfbO T!*B|i_KvօgH4Y6),Bi=g(ժq6v/!~YH$DMO& b>thwBd]UL YW*R5ad}yS?6Z]$2UwYh~EQDkPDh -h]HdT{4k٥azq#[`Slzrw^;FhQ޸Lhc&Pqg|vBĊ ?R G(mqXJgeV1=jg/pDX,H3Ҙf(5-P u1J UOˇr[]2bPLp7>VUƏl3tU\5kRF7wy\ yy-rqY틙9RBx?B5W}]{$VzJBKyeW2g4|q#ͅt~UHzSf2՞OpD͚q:n'qXhl/_r4EZvpy7JVX)"vy _gĊN{5L f^t=aH=#cd$׻*sHG3:)s闦P+6!((Ez(nNT jN92ZUBN[|8>,eoξ\muꙀT瘏+l9VXGR-Q VMV e5j{.{/*=1D |>&|hu:VFpf$(to[a#_p̼+qr,=;C߬tNqq1|O?/ta^{Cx: mi[p7m0w(Dlu7HIkwҩ&ޒK?.j6WF:N?{$+ M<]A<%{mjǖb8 )ym.%ַ>:GLm\b[#=hr|}7C&1)A;]7\qs^+'qPC}Kf\y# hVb} G헴 |rRdV8B0A7TԎߖGUkO b |'JvϺ'o=׹>SS@(TZA镴S&DSߛHv_ZG7w%uɫമBM{kJ5yZ1=՟B)kxocuN5{3YLiI9625 K8'w4/.3/H7!g"o"95PoZWo)sTs4U5Z|X&*-)8MWWT5"PD._-.Rjڏ _&G1(tb%'ry2l4sj|0U\ yNTN*2,!ZfZCb՞#9VS{5K%h=n< ZIsA,#K$#4,HX#DdLCc_@ T3Wr%㋹ǜ%KT27<:Η6[A!-;-_їsp6ߩrsP<fVxWS~TAv *R=m$ Fx_zN!q%~?Jƞ&29ٳXB 8=)#qs9vk[䕊Y |`U'#EpSO[<F"ÞvRAO9*})t5:VK)5܏gYhBP!ەzISH0Z bǖq Oxm[ U[!6dIge|'>*[]Ӧ 3+Bk3`G8Qv+:)\M%H?SV!Nw/qb"0-_{,V޻"m ػ\B3G2}ttQ>MڭO^⩴e1wGEϼBʩ̩騥J4v8Zy4-;TNҮ7v#>;W>R1|(R{(scI.J3myyt~ P&L o@87|GGVevURYh ^JaB8dыG1b cs~$|u\AQie `ONx!g0ЉkvpnG#kг(Xޖ(l_7cis(jճ~7)fEsnc \&^m. giCDusNB#jǍĘתf#jYSH*cV |TM_XJ$ !oU:s'<EGf5: F)R>lg] TD}呵de*W`YSyg"+QX+ LP9p4k+SR$g;'T5VĞ.֩m=CB_VZg$s:bv~PS~FCX#@aɇ '<3|>ƛݓ_?O M=P838 Nlva XP0x)T`n)Bщ55YاKX֔ &dǿO@ǚ ;y?l)˧+8Om4&HV%"i9mIRh'"Ο$,zK i$\uu 0=~#Ȱ0 q?q>g/s1rFK}2'+h>s䈫*GlԠ*?Pte"kUo lNT]V&]w zKwK*ߋe* onNa0N&l[jWԹf+#jHFIC;*[YK֯AŌ"Ȋ5Bq )&ZG}Jm%@4 (d''XEt 0WNL"YaD [JF B/'~wT=̴a=~'H;7"QOLq$( [lvEc"r(X;~2 Q/?!;`&x{~x838 ;$9H{ 6[.E'wWcN^F` {Cz0A'Ȉ$c@oɬ< OK s/,CC_m2Fa4;d OGxCHdo>@P"HB N} OcNlĮp̰  FƒX΍8`! 'F!%Bf ];XTU8*. [-=cђ/-"|ڲ I2ZYotV2~~tKw;d+a):X$q”8Q pfOh|ɪ*T⇒\(9M+M'E>D!5%)E'-Et&4KdzT6>g}V.^f J,Uob8|$^lf*}J GqO+Ym|6>ƇP}S"8{P}Xh/э?1RO@] -uz&B뽞Fu -Z^X|w euw.*往i>NjOϧ;!! gU21HWvoeSܾm#sr8^fJ̱jRJ:u ¾+"-pt%`UAx8R&2E +TQCGy 0OrqJTA 7*PE,Jf1HG`=wF~K.5|, \&Lc5%F{`7Z&SfA7 Lkk>LHUn'KX5}%puZ~ыFh7DĦ t5̡{Sk_7#Y/+F6k*kM瀡; qa}zK:6tTIԛxA̍5,1=.FOm$9=ww;7@\=P" lJ|Q->N& r@F{= ~=r6>C\}P_;yŽdzPv5dȚ1b:e$[lyQSy>8ŠI( 9; 5Yi`73i(bo-hxI,yګ*.^s_3v],O l볹S Thd8}4xKB;ۼ.b$ۄ鉶354~r/{JE춻ȉ֭gJ.xK[لYv3.b/]%ɩꢥ?ןZ~cw<2v5C#FH^C H^;qˬ-#~V]oq9X]fVufу7wGMJHe'rƗ14|Xѷ0ƾ;vkq8-ܰ]T=QelVi !f9=ln:#li\%Od f7-1*7/]2vU\B5ׇSR& Ė$v}f\%yn6IGH4@m@EG&(YL\)GAKzt_N;=<_rMns, J"p.''!3fh?QP֛ 1 ,/|4bm_q;E.Dy5(ʣ2.1.͓)]%DIWV\DjoJkl`VtecFզj1ӘU깷;rȩY8 J#Z+FYqb)8q&zάi܋f\}xOaٟNc0!=աL\Zܽϕ^P .) h)UqE@$zː؊EU9|TVWe 7$=Ds:#8ԴG'b7(=YkYVm9KmJ֜i:8ȔlVQ*~G⿺9QN.-Et%YXL9 /EZ"".h3: Q9(+ZsІw*ZEy>}^n<U+3"C#oY"VmVԄɖEara{uoXW<6QYsLoЀ@J1Vp +srgOs-&a5P#ޏޱDngh/ߓ]!glTޣ.)v?v`8xb_W\Cju^24,:DڅCs,U?ȝy: Exr[Kh#<\uWdtsl*0Lgk1LsVGs9UmF}T_?C?{ɐ|^ U3/eyxv [zRkh 4;'ǃӳh&&O>ŗ/O0`k= ch}S!$>¤ͽK'w[^ ďA6рVR8E&Ux^PS _t®iM$5'+1 aPziRػ[M,ƽaԹAC潈i2hlρIiC*m3 .X%Mr@*C茝^80W$o`)AB ጘC & iz)qa49Mqv/|%&yK&̫=(##iakI;A?ۀқNvoY Q8vl_"7P{;+“:;K_.ow6&"a70E|=AAt2@ᮚyR2 !\(]"ep&l\8~@bZΑtp)4(O_DCH~4!D@z1x/@E6@70PǕ|ΓvEy"oh`l^.cdid/I;I4'9D#oR2O>E7K厉!Uݘ1p NjӉC6x<`ڄrP$#оd\ff#[4?)ēR@`g& ?WW0"{Hc"PdCj:%i4 n:T5tͦf7KATF6g`}9ŏ%r+3ƠJM˨&yS3wA>upF 4OJ>mǤ+: 2 delKz^3H|Խ^E%f4Wp`:reEZWHeٻ]݅>7@֏Py'\.#n)l#JC? qJfxUoG׌ $!CHH BhJBB4je&Iv;KUTU;=T<R =?*K¡9TTm]۱M@9 {XFA׃ Xa7^F;vgR`V3.ރZ,{B-)5;CS4Cgu8~*,%1ms\oJd~ygt(Y:oxo]}G4Ȟ萶f%OQ|+7Б"Tv飭a殈ub90׿hOHwS39dt 4rqlSKhOFF'l. ySk_ʟhH²]VeԶj*Ю52Hb"AtڴL w85](4[HՆ;E#ܩ>\Bs6Kև?vG-{Z#F8H=|?ֈ26T|%Tt+RLN 24ByS^bmSPWIaTҖhf/ vUNMxC8Ӹ`tvDWpsOQA'z: N!i/U^"BQ#~(x۰cL-|oal: ue\2YFdzF{_L_(#ϙVZQZZWRaP bNOJ3"+Ib\@r{L,U `94 x:c&+~7QxW5Ri90QlAF#>o$F!h<||賍Dgx۰i Af/^b眦/ gl6 %2MO8Ⱦ=qzFYࢇuoNxk±bGC B,LYFT2lx]Ha9S g݇m 5‰f&P+N0&";kAtZt炈(PgɌ,/zn:9w\ϸθ7Wk+ q-ܭvF_uڎûc -ag0jn?h6 \sYfO=>YF 2nĘ10`~%ZT_77^*(#'_xitT|/ddM"I&dL& !bP$Lf^!yә pt5rOϵnmcjOjXV-** ≽7Ifow?a'<݊ǽtT(٭VGfGw4\A}R56ސ,=kTXe§ td14Z$'t5mh_պa["5(K_̟xif2TODO b-qM\NQΖ7Q%3R֬YӴqպ<<kR}FҘ,P>3sHm'!1  R__HP/thFO*^d.eֽ\AP_ %33m=Ht^; 5k1͜Te+6 cF}InÅʓYoEF?7$Q[ Pd6YwXE((EVR; 2&UT28mP +!Zv2y$ BCj̦f%*6B,pp1 &ۇn/ʲߏ^< `O/AҐ({"r|vD{@tRA];(< O$SkB!RyɌBRV-#iXEUvoP,Ai)  SR)( F8 ] ɲ8))壞z(lѯ9)F-L9r)G\+Z\$ "{xXjRF4 K?Լ q(٢>N++g'oJpt3>]#δWxJr~1.k`;_TC6/ѽd16#μ ^&HêhW+rqۗYxs + zDv*?G +Y]U<Ӥ +Zw.H.^2i֪ٟ00@ٳҠniu)H3 iV6H[%,oT|4|j."Ս.|sENLqc8^9q{x3Dm]UF_lJ犾lrԝkInY1W ,W)zxO5{K&^ ?/ţv69h ^d EC"^/hCFvl䛄yw|'̅xKLV5 a 08 \q ':`Flyݠsv9 }xV9aӨ̦){JxUġ&\{8c+<w|\{qBc,I!0*ggYWrY:j6à+In2 gdr& rUyuN$]فSm6bS4Gtl4H5n,\zʫ=u6wO=aJ_~,k$Y@L %oC>ğ,Uly,Ұ |LJɞMs:Hkql.,of?139@.,IfHV?60\I!5x}, _ƃNj堤\zKuS\N'i={q|ЕuBGx\6Di ޵opΡ&M1wrW%T6BJ;]P-NXΠB F:aAIw1b Jw\4E᷻q ݷ]@r~'?pC[ScninԒgv`Ԇ) HG{Df!&'?|(<>7 {k:LGo}pNX,RmUix>(S]:N 7uS*Ar9a=;~J=<f#>8_x r~>$L:?6#Kv8x]JRq uLZz܊uCc(-z}"Ir \&Ħk*hg \ ,Nlݙ1cw_r0\NX凃{Xe\ Eu!yŰOE9 pD WnIy tMo9򫐮xUKrnնP8LuFrMpUS ld`Ოщ鬈h ڣAf{ f<$hHvEniQ}r؍8!lq]!+Wzo4n1qKp5Xc:- B$_Vm UڪdAtlƐJ 0? 1b|Ujȁþ-!~^HK=@zuǢnz\JIa0@ dQJrQ Rf`y2^HO嗚O\M̵*w D.;LBx~}y-g/l/1}5Fat"#v{|d8x}Y3(1Fo6s`4l~+DFu֌ 0Kҏ3d~W78L o(;P]]F.a!jx2ZRA;8<gv^H mc*x[̾}飓Ŧ3rm~stoyJ Nx[mANҒ $x-M5̼|]D2ĒDzO% bE.%z)`jra}znu6o9}rL[=;xkmVעɌF&Md/ 7-+xu_HQ9Sg[rΘ̶A:cYbM̤MAξssg|;:P"J.򢛠%"|[]vy}?͟V/$K(HR%#$$JBJTHdSe !N|B eOA1j0r8 Dƀ 82 D Ɖb 1 +QɈ$OU@=D*nn PT$*l€3҅"ASnktZ]BT^9G@c_Y?5 Ӵ=ob_]~kf:6Oޚ-\]{auݙ$4› v6^0OMs~"i+?0W,v4Vdc^SsB[X[GKpqST*ٝ[ S!w񐌶F2F|~f.o2Qщî,ٸ.Κw0z= Z1kxmR]hRa=QЉl)ڠ\,ے3mJ( b9 v(E"6n( b]uݼ߷rƊ=6iwrop٬< SyMdSEDf̍#Xh)H4"m뇹\B}16ɒWY辳_=cf^7!AIz]DcCE Cy<!7`TQp+E%>Nr7Ԥ6!֒V=)]?o2PU;Jtzg]Rwϓ!x"yߵ?CeV>,evRB5KOM ]ƈ:>zz<IVKF{(B]%SLӏ&x6SEY{e1ع8w Op X]3%J\NRϖZ_Z ߝe&\Zɗ,t)_"<ѤlTP`&r+ox5_HSqλO]36+fԜl"/ZPI!L3,!O3U*Z `H"LB 12w9O]pW|?2,:N06}̅'fN("Z_& ~!QƐrndDܟN n89YmZp - UYKYƤl[ϕ̉*w5 p:j ;X-:OĔvŋƖBw,I!etkFC,WcqρM&み~CiV7/SEřm.^74@PRf *m+@vc`C&3OEѦ\P`$6%E=GÎC[ Ѭ) N;dcwz S.,h;ajcY;Xc*IҴ mڭڧ+q^xc L6/7)95I'o0!kA+lXN$y&{I@63Te\|`'.\τ 'g &_9*nW`eQer xfؾ[Msd'1N׷b~ŁQ{G3FwtsF $pY2H pYG$ GKFI$m+,dEPd wY1`bRȚ}/[ɧu|`tcaBPc+d nܤ"PMk.ԜTtE'{3 CQqIo{3Bqr$gV**Lf\GĜd E_ct.>J 6R*xm}-SOX:=`#vE/ vSx}-_t1L7c4R w R(/K-J,-ɰVҟǨ8} K=F2*L75f<ۄ'00((+IPPJJM/JUPճSQ(HvuάJU?y1bOwIM*M7PQQT\!%?/UO!)] 4_dbx9|UV1roWX]ݫGFjx{w=-+Ot`T Xa: O䙞3:ZkYj^wF}5&LQ!Qb8/vO~?8ǸtT9Ek3NbdF <k2 䧻&k($Ǘ%;dU椅(iZ8q$ lu*VdOWdeHLF&Fe,SK@RKs0-ar/ٌ @Wgn>cौX L[`\aZ˷+x;|m]-}L((/}*ƕ,Wy xYw\TW QT:H!ҕ(E@)Kb cb j,/%1n) kif$l֘;w_gq_;|;g/ې-6|bцy|uufUEn.RM(n_Wgd土_^3 '#+=+'tZFȬs\ꖏ)anxs ~&Տ5O76TkC#,]$;8 )F:5>54yR8uFgðCe525Et**(RLl:}A*ߚ9!{3 lah}5a°i&kLZR\4nDa'sWbXd_'ofy"F!ڟIW5X1=S >h)3oǼ(-aT;Y+1ܟ~~sGKx5ןq9׌Igc%0}`MZ5"_c(fABb(y1~nL--VHbw 3vsrs\`Drяyݯ*{I:6D[_wJ !D{߷P? Yz3]Qၵ<x4b];Cط d4Dr·mSnBe&L'(e$ E荝c A(} mt9aiLTBU%,dۃ6u"8gߓho*d#yG(_@;A5e~ 'o:fS@\!@V$ BtqA"= ΰ`yz !q6 F^/&V* @t^%e q$\tHBJAwy./$. wr C z&@aaRY{ۊ YiBZGB@cR;Y)fĐP.$O?!QdF_[(d<ɝRD?^8DN}=lxegy#CNSD %ʃܐQ ?hh}(bL@I:cڲ0g;e8d4;^6 Αyc[/Ulk|a2uGR5?4%RaK ~b/T@N72Dp 7S1$sDI:r ݙ Sn/n vU~IЏ֜ġ`=ATe*JFQr=E\Cy6 -`iB2 iN(e@#țyXpV b}YӦ pV aC!v2Tg+ ׭ic.f99r/i)D5gt*; %GE6W8FO9 IZ%GU u\):`2:*ȕH^ WWIX Uebvrk\@5YQ%eXNhb(CKko-u&:9J|XJəU_>2R'{׋qm`i P`]<8 Xp e/_){C9ɏȮ%b*suBpL~>T&QQ,5qt3Bx%g#6> R !-ꑭW;[OSVji2+!Uu!u ԜԂ̜l:IzZֆ-?̶W0INȽ}s( > j(x4bqt Nx L~dI%ޮxY? N[{&+hx{uֆ-&S]Y0roxa4(=}X`:/c+XE`)HvK?Fu.kSx8o놝{ad uHCx:a c`_B~ZZqjtg>ӕ[((O(4Ě (#L;x][oȕ~~Em =3!@в@%1E*[oYEV= f&\bs`C <ۏ`{%n0444r X>EIEb; ! N0}p^lo//?Z ?u!{&_;~^KAkO֎;8I_li{oMsa$ڇ=IpO|\,V~-`|MV~2L 77w܏&%N̐டݳ*AO8R' Itg_~<~Yo9psbm +Hk:8|FQۑ0~p jllχŻZ XL(l8'n:1<X@=ꥸ uY?ON~VhEr,cXqĉgdM+L'`9NVϳj9Ų?YR)E}HiIڡD(t^֋)dk'2B#a<ԃʓlI1,ICv"'@c5"wtAD'j>pOdh*d6@a,~0.TTXV:9bُ虰$ aqw~EnׂkFy Qtӑ>NcuDR^Af) Q=l<*e<l8S%"99`ѵJ굧$mǬ5ULE2iE"Oѳɫ!WԴ]0HwH,4BGH,&az0#g+%{!~[}~Mn40:Hc2M褭(o-c.#/2!)_Ȫuφ^$=A )UuJmirnvcۿaImCI&WĄ. },&Ц s B`{ ^R' EhW 앇"ة)4eG8rQOUc=.H`t=_"ˠkkO*r8t=%B"z,)ߤi =0snHs.Xb U6231"4pƅm^Sڢ |;لѮikrM!vivʁ$*֯kmX2R28ɞp8MrfKu(,U!(mfTt0 (z_Mcկɶy'5DfIڎ޾ {ǟ' l52ƺ4b`UEq.! c ZZc=1\gXHLDWm( [Kdd+2"8 r`?E;L+G7?ombN;n.ְ'*(6JSN>!PN,Ti2%2XFIG┊W a BD Tֶo/春ΡA/ Єxwc/xC1&TP^11DR:)18\jBMb/RK86<R%cO&xSVzaX"CX6paC*}9ݕ,i)qYaP 2𻒢[| R4̛Im_4e.X~_DKA$4rfv=&]4J޴oVRuqu!$ {f>ZaI{@FwʇjS=BTM6b P$&گ f@Ghr=;$ ,zcS-!"Nq _ l&?nBR̉nBP Mגp˔-m:48O4z' p P M R^"!MɍJkU̕jCNY *;$0u^FX!mڋ~ĸ@V)MI]x0S HAoj!jcϊLQIrqd9S.Iq.6vX U6 `>7)vFQ%T0TCA^K;]l$ ]J_3h8" PtZuLWy]HqPOȆk[:f rɷ&Qd|.|7$)(YܫIz.ÅR2Ƀ_Kx> V[ :^lwQzC4]A"/Њ^wN5X҉чy9\-û!V/d< -aJX ʌx<6 [5;Ǘ *U7 wFܴcP;!~Rں 4FUp.f- 'LfI4(#j%掚 գ)ow }m o6W X"K&t^#Ԇ0WI g wb"?)eFa ytN *3/w4K@4"1t\PrP=u_1 5VxY n) ()U?-dqݐx%8oJԒ]4( 6e˅U'_&-Iu>e΀UUӵ֑\kj%8Y?0ʺ0>dw͢A2Q"0|LKq98w,,f H"A jU E?h2/c08JDEϱ)K۷3j]p~z؎ko[hχ}> tZ5 Ϗ!zΰVաjU2%Q'+=- kν*f 3'Zv4 -zZ*]\;+Yz a:A>(Fy[JfTTTmZtɌiC1NKg u3ZQ.tˆ$s嘕`Sao|!+ƱG>TCEįV'D: #fh[TM9RH3YHhL"fC9_#ryQ% 7*"Yj-+{^xKO-}wehhEJ P+3TOluvQٵIwABmLn_6_L2yWyA߽?Dļ*!X՝r x]ٱ8<-'& j2tJ&>AJ3]o*t㗒U;>3F;iSz_Evγ3K6Ⱥ+V\\ltU51ث8m4~@{@ie(raQƣvy}G7ȽQ3wj H*giãjLUo<K ;" ޖ:Qjx]W PWn B$$- r/ E ]DP)XoTB-Z:vۊ٭XkݺNAlf{2os򠚦Fr[5P?ޔvX]|!/16 b3ne!l Brb>Dn~.'fHT&R6ڲRFZKOVw,IGaߐ!MɌ[)ST^RR],5|nLuM4op W`e]Hf0T9ͷ ),밁[YjZZWsYZ Z< ](O >F%X#$@p)͡v wfp"[ܐk\yhW"Ұ=,Aienٴ }DhIГr#B\_ʗ7}A.ԥa.BN` +f_8oⵖ0&z'*:GY0h=H7v+ F84#6v.ҵDX#v1cCÐ[4^pD W;<᳌ve"]].5V{К#{X?!1ee-[(IkpvX+5}|fq:mKU[R=C^o19nz=ERQ>S52[rr7!ݺ_Uh$ջٞty_N;]M;';;\Y 7yw]vW8jg#c I$q`9N\^C F O\<"DH:GTd^=Xqܳ lޣĞ@6[=ޑ#ڗcO$'CPť<}"'et_5䂉D LG(:w28YdM);䄪I<>I>?^O3%mt{wϏǪMj:Qe@{[XNDjAAUKoМz$) ZȪ4s!YK3(;cH3WnB%8=|VZCSx0f) ;d:k4x|8!LR|:e䴳*zzۙ V۹1|^i}6 Ejtab/MbX|@3VXQfxiw W"C\2K6?bT`L+)Ե %**֛W05&x7 l 7Mސ1٩vTQjqiNBzjI|N~rbN|Qb^J~d:9v.N|.5xxS }2&kᚬ :[Qb^J~dAY2擹S&w眬k0W2#&?LĢԼҒ 6oR嚼 cru/|7W_4:9pDQԼԢĒ e:P8ˁ`@V!d32R3Ru` s7_Zlb -SK= !lHƃdKKK' ,lwfNobf^Ij^b^r[jbIiQ*Ȇ Gm~XO~bob^)Xm@iXŪNn  ;l,@bKۓ6l hJŮ}re';:x 7K&/H\]92Q6ix{i VNVXڹk>F0ym<31 $R$-xi {NVXڹ}Wfa Ex7 7~[Xy1ӻo lex7 7~ 1=xU{LSwER !b#St6-y:(ʆCAUDƐ0=48d2{o{O}<~z5r`_21~y]㟼s4_M̿,VdMn;Ϊ|K+^ۛ[pVQlD_}-'Iܵ!FuJgE<2$ /;] +=Ͷ9n@v nTks(+ BzV?T [/5`M!|VBEwp}xP:dUـ"6,,fU9S2_P5)0ed#co>g֧r2dX/7P] /xS&Mpv0 Y O#x9l u-T*ll]n t)3Q"_. qWzLtDtDaF_qC{~ G,SpB *))͇;_n?]֓[=L<1T Vyހ~1G .J>CҨHDNr%@˰h {9bX端'n., nIx[k l72cx&8rw*xQ yAuHb{:Bz5x[K y͔3 B\C}BB2*3sRSS5B=B  Ɋ&`SNKLw;KĜ",ncx;K Rel4axYmo,(GZǀ#+Q܀X+Kt>HQ:Ų8[ڗygf̓&cq R%Bvɵb(n2939b/qLJdt4e82%,O6#=`̓/kγxivEu,SS8}le8 <8OcntRZYYW@u= U]N< N<کBI\_˵V@}[S%u_i}1qĠ,+>WU։W"DrSE2l,?ټ ⮩DBX{ahF}sl/Ң>|g{!׼ ;O"M#(~5$2Ff(車?r'vw2,਑'"&s_D~`WtB0yL Iۓ_41چOH*,n>W\nvht1G?+AM?dk2 lrMWV)!E~tz~qۧԒ/~z+@oHeHqN`- (G|'sP?җ(ްi*omg`% <ɬOeG w$ f1HxAxKCPyK#*˱QX~qMv#4_&Ru4وlj6ίg _DO)x7;qb Ow 5=T xQ|)(plޠ᜶ -c{̆5`BaPjJm dpPq˛E"F.KZ8*/=$M^l67G42(a$B.ӹWD\c[+qN,VipI^ A"@[Xz+`̥n5oWyY0P5zQÅ[Dhz;2ώHѽFt5`?*_IdFQ&'LG6.R3GWqϯ5u)h~U[D/{CVҮd ~s8s& Z`f=xn UH,kw } ǙgzNɓs'(}2` qef?3A܆ S`nyG+;UFK/\۪:^]_^lkjsFM)iS7Oqr0?@T:o@dPW(jRl v oA.~S0uIW9^RئUJIJx%G-W(~|gbVylJ)BuJ (7}-R΅P44L)t<0-V !~pHF*$9;7#)zZҫh0Shm01>R9 GEAD 8eꬌ!jS`nߟόN]2uFgh|>'YXޡi̹ft,lzq$E) +2?, aV W-}KZ5}SS".wYN(#GE!uRFQ; r}%+:oJRy64Ej?,i~nѨƯXq9R/kr!-WiܨXm;wsvoåk [8S-0zR+efE}ʃW4C &Y@Hp,hvAsreW ۻ["(5Pxhpӭ.T)cHceY>n[: MښnL75[5aiu ?rYednJEEJU2 A#T7:2WA)-p Pė!RQLnpRA;ɜA RB,Nrfh)MQn1+SE9ZĉJIWU4{U@=ڡɼlYAD:|"q9)`k)6mnP+QJllRړ˃g3T++~k_k//2<)kɦ6la-Fqʓ߱+_>}EY^t pQ#xSo` R 7enl00eCE X$Jg)&LɌw!|3B΋X#7ZEۧ\DN@w]bXs\)rl)3;X`ư8W$~t"ԥFf*WVDUK㵣`}U7+7y:E޸!s uhHoDJT#I@:1 vd|J]%4nE&csC=\?p1~]tp44M̬=/gn?F'#4ݘx'0Rl/ v ;U \&ds {I0Zl!ָ],Ä(2Ge\Fu8ME:FL+CaxA5YCr\nXt#Nw&}C|DF-41E|y nxgZ6 o F`>c'bBa\є_ԅRG#MLqʼT{BM'2i:O%mֶsJ՚g (kD?.=mⲇ?Vޭ߶\- xkpaQU93/94%U<9#H/Î .TR_ZZ4sIqPW Yl$\4B]}}=}B\5'ob V1#8#HPb[Œ̒#, ˕ᓔ 16Ҝғ'ȋqh8E*hiN>(<[!_Tb>nyFq$3CC|]}"5'S'5SЀSrzfZ6K 'Fh)no;Kl-.mL('Kbe ۘVxkpf!`s(+FV[[],ql,y%pp qUҜ|PTyr B࿨}\JE-xkp?h!`s(+FV[[],UTxkp?`!`s(S4gpxkpka lG_x;a|4d=bq`f䜬!;G[@SSH*To~u\I¡ rM2|Vx;ْ=Jk>xabC-5̍ٴ2JRu2K&ײ"sO"suc8@Ip"vE\ $ xaj f;"Nr@l'xajNr(xmq|C^FG9434'W9r3:&d+O˦يd1ܳ8"""&TTɌRAA!޾>.n>.D7M`*jlxmbC^uR#&x.77  ii'+ <8<*cx;nlCF> Sx;n~ld;kYOMn! m4x]{sFފWiGU e䒔_nxhG~¼0p\̠n4=/t܎!xFrWwri Av߂}L"{~Ko<³#%8Y!:9?b^y#O]˿!{~?>m/nhпȗÕ;sr~h#wJٿ7Lfckrџpnwd=q9^܃688,V9:fÃyF]ؑc=H:)$wp[ 6 p8c,{uL_E rzr>38:EȟY1Z[ߍ.s`e,mpo p?Z'ogO+?ɻtvKy쯽н2í9 k{s\'Zx~v ؏7rONgN5M?z@?ۧo/N%y)cyxOWWNֺ u*ᰯc"E?aJEÖ\S2q W *g')ZEď;f᠛(;P=}o|{kM[&HF9w.kds 9XީN 2!bA7^_ɭ#H{kE>`'@j<:yq;ﭏl(=fݝHŦ0gkp~mgiΕ^FdV ?{x^tp_{E~N~)3':ghqm ZOnpi7d5G?@n+,@0\COotl8Kµ.V|T$1; \eЉ"nA:S(YatHGǎZlTAϦYi@3!IB?*/3'kojR64@I>gİ'_1f9g@ %0c .aإY{9xk7[o3sp K{$b%Nh0bC\D8\{xqp7:[L͋_\o?irE!W``߹5pCpi| Wkoғ/@r]8B2EJs!!X. "?GÞnjF=0&<HF%''@X 65DvpJˡA/:|*phCapt:6|BQNK%7/pr'Ў a)JODNTp0~u} E"ФH$HETBGɄ$f0r޹T{yt?_+x-{'AŬ|iަl_7~^i g, n܇ ?LmJm\K6-sLE9\0|5#2;A`ǣ>U$;dNC;spHƉOeNE̠yWt+D5nqͯOCMKLH|TYfN] ^Ä`XZ]=LH]B{(3[!gl4v1т5(eiy)Wppg$$:4 b߄u?as{ uH8!xQTsosY0ö#v%?_;)F3\jLYC_9=ൿx {:Y1-lx1[G∅qF2oȞiW*,$(?PN៍2JG>%͠.ZDγNorR`M,,G͇b\!u6'Y6[!xT3ˈ$*O !e2&ݮ5`$Jt"4d%h lfQw6e#Fc ؄&E,OZS%Dd/ni?FD )yDϚ :}q7%,R%b)SӟcX%.S. ȟa'FkאH 8pKKYkFNdҜKXwtw>*4ݥXO"o׫)yX7؀,yuхʪ b]#DxLYAgv( LU *+(q[QMqL KzB s߸wRd;Ia{N3(V|;~sUgHg+=@ bR_Z6F.|fnrjzG#hؗ5q]{@^͸Sjzא w6qqm@Q>@;R@חr6>3xo}IS z8 RŦ"V(2tv,\EYh9Tڒ%QQ *Im<QAQYNC gd O Zu^9sWܸUHGD3&Xȑx݇O!**/yda ;$Jf2`>C#o%b`E"=%fڷeǷ ʎuhf`n KlN[[q]1&|Ov >j*+jݩrGu"wFT]2UV86,QN 5ٺL2rZ .<bkSV̺&s-1?)'gUgNU)%%*jry1$E*Hh}YEŮj6'U:d.ڒ~Cm0Ί|=d/4fҳGu7qE,J1F17#"6%!]~Fp#'r }Ϗō@?3;]K1vRRTdJXHj?J=ڄšT3c(%4Fyn:|Qep[ktIƪ,ڙ1u8XR(/ӒY2kkK9v,U^kT2FfչSɠ;}K K̠V JO/ԡDnCf5-u/deKe3ݭm7ڵg.$Nĉp4Y'K'ӌRʼn52ƽdGw7D;Nxw8SLX5qW?M;ޜoj Eh2jHk8apđd3 p( _vUVɻިLh Ky$]IjXu匊VX((,dPfECUTkW[0RԶ$ =RZ;m|E@N!bRA2`1'1քKd!&DMP>_j$V ]D09jJi;` Qqj,YV٪\pbZpO $0_ YȀk@8'֤ dG=L M1>㌨J I~-IKU:6me7GU*^>y8`2";죏ԧ%Ds>'3=2ag!q&;K9%rXW&(l%lByk iH_C;8%խ|W{d#5 dXH}tOΔve _.Īו=1uܖ|WX/R43YkZj}i-{7NDح5!֭7nRאȫ`ٔ4Ofj]n'Dvm.GB"2TV;ōK^{ҷ"y=Oa޽d)' {%Ս%ХSlx=qmvtV4Gd۾*@g&'4Ϝ+ieKu4rnT!QMMKH ޽ɳ$XɲhVG{:qfJ4,hx)($c)eD*NpDoI>n:~I"tAgj7P*3H;YؙG'(P&7e_ȩf'}birwD*"9_J$U< "T>mL.fՏh~LI]u]}_*>auHX{VqpE*Oko(p^ñ&f HR& [* kA 5^`}'A띺N>҇N¢1eC^ݲ˜IOj(5\ˮQbj֥\)O}Jj(AbǍu P"U$9p]8tU dŅ=-Pࠁ "(v&x 0KoY "uO'd& Q5@zf^ *QBܹGc+),kUL 6<\Uwd6؀*v;/䐷 |=?~6z;!W4nRV['A褖lLLRLa*~185$^ (r LD RxVڔTA(ջ7)T(}ynؑs^vҿXoV4qgj&wֹyP7NϠe VISFLm%vxdW$9ny˜H;|ZNfkf;㭗 n Fͦ./lCS埨Ao88O '2cIxɶiPǬLo\t81'#8<[דa}:%llz~T\Y-*hY ~0C>4ݢ h= aPy!8eiK_i쬪_j}x:/MC?vo턑ʇPN;"51ԃ 5l".5|쉴45(%'NJ'zڧޑ5Jr>Rx)i׻9g~4w'/Ng Nun :&`ZL |-Eb+ 47Qe<.ԻKz) *&(U[ -~u?,k'[o}ttn?}KkKwhs]}1VqPMkbn;$8vGh(&T)!e:/֫t2"Ʃ"_kߠdwf&v[ӼDOy)⾤aͪm-Rmvcl2{:lⷍDD4_JSp^cbߕ89\}Iz36فf EwbҶaV$١ވI]LR/imN6MfʈNTCMBoe.^؆rEj quUvNF#gP v2Ͼ},+Ct-L n@4&Og"V^2NQĉr;6+u'cNzNܣkbQLRmL ؔ6Td8}hDFG*z8ܙX]6R\3"3UsxfkVS-?iǞG'(6 kv$Y.N{:ShnkXVOwŢ;47Btb [ \<%:(fO[͐ z}>u#s::F_\V|5G$:Hi׋3+ jY3G5}X'w=(ݨKǙ*rv<ZN0q?dbTx fzߴbeM6bhx70@w>4pĭHcC܍QQ\Ňo-sf|HՓ0R2dނDBh5"w :FJgsKjp!9>/!?8`pV'o>.6I.aQY%)%\ľ\eŅ,i\3XC߷M!?J cαguJ֐AaAx U;flڢ(V^=*Jm<0p@(8:FW%KʼnѱY|wYRYg 0sH͊}KbD/a9cQ"([c/7yv=Fnpb!BEBʮ! \uHcǂ.N_C ?UIR%֤jv5/{(A}"xD- "Ix Dϛ&xxID/U𢰳YaO] *phKeyTCSI,w]w] B&yXx~q ~ӗ2pqLvN .("Z鑙ZXQY:q}7=V IR8&|6HGA-5/y2c$Ww\&oPQ`4FoF5ifX]'O0gc.(M|)nwSK57;lsovlWq<ۣUE*Tfx}q ~99E& *UH,I-VHKIMSҙ':y'PZvesbƌ^Z;x}-妳w0L?7q%ͧ:/f0JMJ`{ j/v3j0N%?9?Lbٌ.`)k&3x}V bB%9!%%% c89)2U$颣blgV@ "a9g98N_͸y/ Xf\8z":HFAٓL';Tsd8畤VLn\>8yE>4N_(0'~A@^~?ldYH<\N7U(X2R455N)J-)-Sn2]ށ1|enV}99+*hg祦($g$)hi*&'khi 483MAI!Nn BH鍲pɎdOPei.)Ϙ5!Pn:{sWM_2|z3b  f0NFQ6l/[<A@x;Qۆm7?qrxM^{z>F|\ 9) ILcE)dM? #Ƙ 2o{# !r%5|(c ,x;m6.Fl\ '/NrXypj0Qzf;cpp4^s瞾Q}z6#?BqF~iNBR"{yb yӏ1u1^,6p{Q<9܆JřUJ2:Ngh= H?.b:wbFIq UC:rxeS_HSqy?c`:5]L+D4ɶziNné6tAShbH{ )}+ Ğ4-˽;kjuZ rg*䪯0bppidd&v_2EXUZ":/T `Ĕ߆A-< eŴr;{l_8WGyn4j4EyGbKnYY tY4M\Q_jmnsj|Cq> `aaxpvWdJ(i,^-܊V0fF>+2ٖu u؞$CR`'~%/`ZL\;XYٺ)=-6E%Yښ!n#n=TFnpC'.mYgEKR VjɗP% 6>eKv\ h2ij. yXY iVTIZY38J+* =*}N~fSwl]FN+#v hsd-aqopG/<J6,kTy96!hMwK|ɸi¤ LJ8fȵ095qN#cpcrZG90UǃV񺕓m (ln ?0b)V [_D x{ĶAf~!>.ޮ~n %yi7?4YOaw6/xlNx(8ۤ'[7|uYIYDQeM<^A@NU! $9&;g7`\3jЌՎZgTRp8ؓb=Hi0>pTa`4dƚ 8r&;ր%eHeAS$Q ϐj9$J)4|!R:,m&}eQ.i8bsgw 7rO.Us^O@hh% 6/w%٬Bh_:РI!%Z3dCxP=wKIG^|Pɀ k |elK[1$xLoʢ)EIptoMȵR>B>f`II|5fP1WvvU c ӯGкZbK O90H : ,!h `^hf3,ֿB5P!060VzV4,q˴lJxu' +C'/(  tQ(-Llx@mPOOV#` $5 S+A '|=9/U cw94"ʩ9ũMÛؔSR2Ӧ 3vL3+QSdGfjQbQrFBnbNN~Z=#e&E*MpEkH-&7yKL =%$QcA6LmmQFIOWdthVޮ(&{Skxu'ֆ-_gl!3hcvuQF7 d-xc oO/fQxs# #x{u# &?X9ډq@ɚ[m'Kd)hhLJe_/m1*NK/lePU X>%O(,tx!׍'K'pnvyIle#x#xXwTTg?aPQ7PP҂Jd0(MCW#M 7Kƨ)ubf,anLbI\w_tsN+w=r^ 3T冢ʯ!󠨯!o%i 3WK<Iw^"lImmnzRrox =c>xiKVAJ>'[.EK;{OhM 0" Dx8Kʽ[ƻx|p}T8os<}O H;O*MFn{])r9'_RR35X a,f|H I{>KϪLzC*6p3rfpO0ĽgrϪHvR!+ å qTTn?l}E/̝2ӳ2SͼI)} l蒂D!h(|ΨxEzz}$YSo5Xs/+vovOއjZz#)᠂8᭥~2 ,T+h: **=vq*OѿWIJ-TWBOCllʣ*{{,5՛[/˖::S=` : la Qќ#ÄH:̻'&dYZj {4#׼O#nnH]se)krSmi&z ] ļ8Q|:?ר [x*z₏(gN-v,R0j؆{bi8_Ĝ5)K3EZq2}\^^n+\>BB?sE ̛wsAxPV,~} S/Wܳj,%ǫ>O* kխdq_ZXZ! wc77$?e^6l H<_sJAۺO0q-d)>%EGf[6gޓben#kw6 G$le& [D i`v q^+0:M8{}0m <-QKCd~vHE{ } H߷i鷭jU*͓XkbX/Ph3+OƼ(!û߾vrr9CD_z@q/IγeUp1ẏ&fm0L_ |o&{Ź7V3EuZ/@S`5sd\k ;g-:$n?s,j{KH %i'-V[agטZ?U;WKGP=hIpKc)zW ۰dIuĔd$NQSTq:Vl]H͋ O@oyFl9 ΤI>A;&W&Su;fa)YVݹu`ryՒߦm3'>5UMM!Hy!L\#_9?{8L0p*F{@pArݛj\V,p]6}Ns/Y+eW CL|C<ܪ$uCwʵ1CqO1NapC UxF`Pq38NU0e pg1`/nKμ}LL:tn-_j/~RM Mk=p4!fdI8Y؃ Np2þ8 ޏy>-ܒoe*H{m'QUC]G,yyFX_;d'=a5}v_L:,Cی{Nhg> yA:L8 5DHJYݒ:4z)xYߤ{_`io()Vc osJh7u"`7>? A|NM8q/`̔W'^)(3lE"Y=^d%}! &Dw^N/I 2.Vz*ʚ4>],w*Br -A HW_9n`> "QBP0d -$YJpT 4p@Q9 Ecd E4 +rAD".!5C!_`;{+9&^s!#'5 &ERShyOcH 11~3b2`pJcl"oC.UFu`NNu` 3#~XpZȸP mɁ4BMba?aIIaFFjFxeX .v䋓8&Mχ-4l~rfWB?԰,z7 9; fj_A # {Aw9\qYr*+a$j`\*c̛8̄g˙`2~'4 # tD2D6>r?{_x~>=7(`k3wuW 4:x+K KK kPIw {nbx|} ̌ 7Og~þ{i/FIf%Mv,]6ߗc\"8EhԬe*F^e2@Z% lP*.(Ӹ5#i^e^|c^ f2]&,2A_|b= TPb\rNlj0K?2-_Ne2_0022e-ݓl;@V϶ 0}/ F-ߦ/3:uU{0M;>dKneD8dRtnF):cdjX0NWҙ/x}u} \Yŷ3Nl Rx}놥|1-I.v+I(Qqpwq tQHItRPSuyQEtPDB=BS+3Ru`N! Z`q5o/3fLi +mxkz놝_`\&i6- 7xtu} \7GP%;ax{* ֌W0N6dټ4VV[̼8L /m8 ,xxѪ; 1\=intA= ON.int i, j1KNڥ* bytesRequestedPnn蓅*Y*_y*\*23xW_lSe׵[o`%غADV߬׭$ 1`iD!s3Ao2_ b߽wo{[|ho~wwyg)Zḥyn6 @hW4>mc0]q,E{<"lRɩN! ԭ}Ql$߻L(D2,gP~H9].(Fx($#L TE Be`&0K( Z%9Ś~e|ŕWC.FV GM&+V#j^ CnpBU`seX`$0)иHy^l8 $VWb^ ) !q"+L(13ԑ%1,ruΏkp)Xcr )vrK UeT2n{{-`Lb6S@xjZ2]_8 F?5… u-"MN%2s!Đ y__Yx*HX>X6R8 G|xk_]@4o$LˀܩDߜ(j rizٕ&Hx|v-#mn }wQqu4gt~DWh^Rj=66F{0@4'8div* '}G]6誉nܛ7MtJ~9i^KK@[ mD8J0F91p[ʵ8J.{.n`eVDePQlѬ h֪(hixK>UȪnc/̭њqSs|d kwa^^[;,>7>洈J0S*_Y>024\#ί p!_!'7pqMg.zCn 3pG(h~p>^P8L_#?-CFzԣ_i^@W!6}ͅZ2& mKiECM} ;ӷ&}|Җ!FDةm9}%TߞYfX_DU.v{ԕ 6/aPg_ax|ֆ-&s2jm'8m#x8|ֆ-d&_H>UQiRF 93O+0WcL9F'o2G2N^6=I0Fq(@d+' x8|ֆ-IKk'M`>W1 < *x{6'l.x  +1@(_0N֭g^ ļ\ʒ&mNyǐN`td1Zdt% 5*3Zi;]NQ9d]m'YHMn6yTAnFq{ox ps`!3 /xc-'Ox}4v ?Px ~w)# *x{=-sTk0O_x[ew-r1vGXxS N?Ψy=O3nSbaRc2BJfqbRNjpIbIdC7wsL>Ie2;3nQaff&[593^e۱1~v9-xS A͡C; S 0sxSɚQf`=gS"xkgjg,r^[?k c5_mީOxkgjg,0_?M6]; .9&/; $|xkgjg`jϵʜz[Jjts[ӍZ P(I.fұW (,4Jxkgjg`*"rwת  Z{ txkgjg`*rnV&S5^4o>Č xkgjg`*utmBݾD},Ixkgjg`*@*pg6L.WM 0txkgjg`*&+]IKڥgS'z xkgjg`*rR8|Vy'ͻYL넉B Jxkgjg`*2qᛑ,ufםmuD} ux35("\tWIh6jyߠ |oo^mmxkgjgYD`I&ۦ%QM'՝N xkgjgY$KCr~''[fMB W zP#" gaxkgjgYD':>&rK1n  x3S4Qc.Tˆg G,yV a 4FBxkgjg`*WY%4aO> ؇&zg lx65$^v1Ih9]ᰑI)*gaΗm첑`PI0xkgjg`*WY%4aO> ؇&zjpQ(q7s7=/Gʋ*sx65$^v1Ih9]ᰑI)0^K<0]7,ExkgjgYȶgb_{wnq ClxkgjgYOQɳ~?% |x35J= |0bJxŃInzC,ܬmCg ajkkBxkgjgYd{9yc ix3S7ٍ̳qpU{5ge5߫IAT--d*x3Su#"֗ {ge5߫IAT-->q+lx3S+prع?4klgliH1{Țԅ PxkgjgY$%pV >jxkgjg0Ud^LNbZ&aϤ[ĕqm *xkgjgYdnJy}M*+="ͦ Qx35Ö+풕fIRO؉Zf?iAxkgjg"\4y\-9В61} "jxkgjg,"?Ynj*OƯ [=NOL_ xkgjg,¬rӗSV+g9tb Y?xkgjg,rCc6cc^jCﲉ ţ+xkgjg`*GPֈB\dI GO Uxkgjg`*ғz3QIꇆs$ķ07 -xkgjg`jʐ=2.KN71b+m/pm(*Rߩk11}/Gxkgjg,Z~ЋpMm0Y-Oqxkgjg`j!~QىZ^)ib % Z!_fM⼫$ulVI3Gxkgjg,¹b7zc79a=>1}; )*xkgjgP$ۤNN0o04f*1ϗ *xkgjg,$5x*kw6'fb Txkgjg,b;G_lMkH}36LL_! ~xkgjg,b(]cIi}ھ,L51}Ŗj(xkgjg,ߦ%+S&_o ۥ%Ni wSxkgjg,b5yUu]w ~xkgjg,R"}샖"^u~z01} +xkgjg`*S|5F^ MUxkgjg`* [*;NwL?s Jxkgjg`*r W,tߗpL) 0*xkgjg0U,Cg{ob"@Ov8#*xrќQ6B仭5bVxkgjgP$.z/<˩usRzd҉m*xkgjg0U뉪Gl;;O+q/gĕq (*xkgjgpE$)T5,P}iR֟M|!b *xkgjg,{룂{-6451} *xkgjgYjiˀUl#f\zj 'xkgjgpEd{#u囇9BC}<<< Qx9"kӽ ,xkgjgYD&!X!;-.5 Sx35$,270gL*I0XՑIH?I+-KkSAxkgjgpEdSƗLxu'MaÉ/T kxʧGWɌ2Tᦿ&C xkgjgpEٗI/f|Gx˂/+xkgjg,{.kNasb *xkgjgY[zszY)'wg> "'x65ӌ# ȎiBeؔԑIx0@%7O+jKՑV`DxSХc>ȷݙg@pxQ529Δ]~_12I40000 tcs+Xڗk0 @g!vf6j4՘% xkgjg`*ґwɽ, vW'l|uj݉*6x35'i M7."2.fStI!vf6j4CmxkgjgYsF /a0AxB21J Ͼc֑^ ,xkgjg,_^Fx6Tt*sb>Vxkgjg,}r+Ӻӧ& -?X|Kхkx[2eC *ƭ_m/x[y”[Ob -'{Jx&n RcOJ};!#v g5v7%zD7xϟcUkΩ2D]R cax4N}fi%_(cHϟcUkΩ2D]RBx N'7FQSnۭb:.x j0ԉm#\x9j0ԉm8WeCah)mٞbbGTJGx@8ArYh1B100644 tcspbg.cشc_ҁqo tc` Nx qd.R~sk.x7o.M~X]snAq| ʯ4BLExy AC eR'l`Laڝjr +x0'100644 Makefile.amGNWZHɓ'j>x|yBƊ FIRx|yB FLERm/ֳji]s`Ug=Z.x;|yFn2\_] K)i F ,x;|yF9S6OzE: ^(x;|yB݃lx?]OՑ{R " ESx6\? PoQ+/e, pnk=ۙ穳96p";ڊ\x6\? PoQ+/e, pnZ}*`)nw1x};!{N6 ,LZ@f#  `b7?0] 402`\e\u:_=#Y{%q3jwcem[w_%-c\U ]_~Id-kY4 %x{3D71;5-3'U/1AOZx}Ǐ?S̑x%Ғ" RO6~YN^+"V}/}_,Xbɋki>ܗXBwc.{L-' ϳZ.z1!7f$Ǘ$ė-NM9Ӳ3eWIؿ Hh4O]yr){Nf6|yHє;r_'9¶cɳY}(՘9Ofn'mϼpFF@[Ss6 y]|3w1jBIN~:P tj+Wzỵ5@%%n>ʘc+~KYM @(8A?^5"rv悹&c>\?0}7w,ڽCf 0J@m>_o=,Ⳕ\lFϛ(L[w, ;9"mܒюaV޸ x\]s:&ޜn{gf&5Sf IO<[c _$!jGz?JV_G?QMwP_E1@s@`:Fz(g~%#%f^<sݎ1a~_d0Y)G/Dϟ>Y-xs!xw1=g|pW7g:nkO+s6;3~; yoY ׏IrstofYy^,w53>;XNYw7'{s˒G f!ֱVJXr]W0է~T >&OC¶QG*JF( a*9hAlbrp 0Þ ¯rq};~I{Ud zIX}lmo0[꧑:+#[~J-Qe)Ud / P p}{VS!UrpdbY=9vg=[kO/IuqD@I ^{-kv6?xQw-<=`KӒoB93R&&!lQ̨ 4Rb̤wV4RZR%\)&l{{z©L-D: ֙ 2yq­8dJ+(VI^]Gn>a"&\B|;[^?l*iOjp]M $iIM Ǵt3iy2r9UVnO.qmP&VŌ$ f0u)*4L}f1ĿY ^>LK_39 ~zZC7ꑓzA =`"AuTCD_e=2hC6SeSavg4?A.BP\g#ۉv^}g6N&yj2K_tKSe +C !*[ޟW%\n\kpX{_McgUf`bX{#桎6e Fn Z$v\%d1e80qЋ#,nn7grYG$˄_tCeFH"AqPa./qQlVtMy8K#LUY'VW'AZ (ڭ˩;)CɪUc^2Ը؆"(am|ҏh\?JV֛Ipqᓜo\,%ó;cU.h кTtfLD0$ܪUHq9G?: *R2.%P3l7ܬȈMF\2C8{#oS8ezw3m&z-rTqzۜIX\hFi.g7Q~u#CE QiTB[FLba#@_# 7F>5M1?3nd×~܍ mYHD>7<foH\gwVR:j0(5!i -QcX-Fe5;5Ff8 Uu2M5 *+-kRyr= JrPyƸׯl:c #+ A`DC&59&5Z:+ g~^g#8=>͟9CS[{Gf.T0^{='rJpNW*xEK|!pN;.Hm'vW _.5AKM(+3PoA\ !D%p.By*_%/3,-.:4%# l" CSW7;ޑwcjKQHNIs\m&1J``W"A=k)ΔZh!\V1R -I8ĻFsN&WT;L;.v9DvP!Iy)l~_1PWhsͥh/yK|ݽZ!'n a'ffTK0!]yR_˕ s ˔rdǤB})qrz[i7#Bt~<783$:#b67 4z%å]j?PLhƅ赝kx!@x~>r`b:>Wѝ okp󽄰 h;w,vwF}D%@l8T%YB&_WIy eZЎ&1$6 /L1[?5Íͫby]` K 3)FHU43O5Pvޫ@(u׉sTMj\*\̜5Wֵ7k ~(}P'@2 5>eS$~N"E!|ιz'ALJ uuZZ(Lxpn<_)+r a؃GϲrNޚO--aߣ̈&J)kLee2PoB3y6&2@xZ=6߾w6 >^=mNI$ڂjLj2#j ꀿңڽ {k>0#૫ |:{ w%Lj=2zӳY/$F"[$/:jjѰi{[ڦ9Eː.T>@OZ|"̇]Q 'Iy/|LvrMF?}7M!/z}C|@**v7Qc]R.Jz;Rn5R!_9X}K1}!F%N2L\\#곦 <QWL&/!/h&x20?10. 01 v 034! n1m}!gx?| LLp72u;!BJCC< 'ԖdTj~'ϴ9QfAE` d߃&]cW+kB&̬r,|T|mͬ S6h0"4 ZZ`K)(@ۖafwP%@6駃Mop62 Mt@& ]RH,I-J-,M-.IM,h"5Gc%3sF'֊` 7gbd~/ə1P6wi"d15de.\A$$ L7v͈x b~Z4yx2"67;߇mAF@?x{= 87k3szrj)$%gdNh):9g[JbIg> Pv䧾8Nvek) / in8x6< 7/e9.xMK0/ma-*x)]i;XҤ~{?b=y3{6:br񩣏LFXך:Vcuj~ A{^*uFT5`?5`J[ d~FR=a;;=):|;sYyE':s(TKR[E j;Y5mףlm:X{}Jxݯ)uYzPMaGJèQ(>79 Ysrz0"\3ʩC'RHjHiP::|m]v3wZc8W$ 9+"WYCA(%!L걩)]^N"0\K (~a`NmW18Ω@N ps ~X.WQ a&aE l>/qX9X?89D3nA U X5%x*5 rLzP1WKڟtLhu(0R'ZY GL;3DŽ4OHBgV=N;vLBNӻ-r0=Q}bOS9:,xnXg˴]wIA$6lS-!䒹,L͚ W%'a[IRsf$U+n>Ael&6kwi 22v|ЭhVd6A-&f6{?;bPt>JQsp-*zNRCsRJW]n2"~{hMt#ؽ:꺔Mb}bT"1W k͘E&!DsF.V&Ơ @N#Gky6zKaq?*ZF478Xqƃ:|ŁyoޣUp#u[c>-'Ou/B3^9[!@ _$>g no}ny$ 2˼YA+DnÔ\2e],r {sƞ&}JvK(Aؿ#Y`_pM \pxZM8W(/ӟU3;;7ʦgk/  ^$o0!nOUFH/O/S crDQ+.y"[s%cL|Hئ,.-2cAr3'ϓaQ/D{~E7O4Aƒ#j E;/߿ԟx T`j?U`Xx{o^efe֨>]*#dM%l2b̛O3 g%G1R@oէ9T7OR&ۄ `!5 pVy!qBgZ = /w* \ ?4a!; 0XZS"ܜ9EHs9Fx?23+-J)U _PE IڄT l wG8f m|!@;2) >$kȞ/y5bmڙIl[P40>Կ;@5+CWyYPĀCgop#'U\E@@iCoA%w&-yRowV"R2p=v$UscqB-D'==h Nln\r#=:J(E!bA}p; )%z 7WVn^(.CPOKE),@)%Pے(0%r 8,IHmzu_m֞(|mV] y/~Hl--)֬A¤7Na:fc+˴L V0B*楪06>96TaLmF4R먅ٸ Z8+e:CjWjz/!نD"b[g#[unD %!B6Am̓hoWRM4w@xu 8 ACTRH3+fu^\JZdW"\U U09xT&hRhкĺ+%ݛbc5Uqz (-;3펔ʗaW(aȯ%L eXF.%;U`=m_be+es:=FT>OK5?P^z`C { wX7F/ t\gkR3))!E+.^5>YutL֍p͓@B% :Fp\kX!t@ 6:^Z&~ڙkR੪$d~Hm# v`>RH'z51 ^ *BQMYm&{Hɴ ^y%x;ߪ= #7 W`+0p+"xY[F~_1RnԽ&ۋ*k8ئ`ޮ[ asIE*O6p߹ \{'ًJই$ 'Kc7%ZՅf'ԏBxu~$g_Y#ǡ̎eKv&#~H(OpQ9gp.d]&Yޟ8PeAyLK7t5ţc<蝜+EA=C%? DQ61)Ofٕ94&ʕsu{LkLM|)md(wLڨG5f m-3sKSİ>. ͟[57V*BTS,mn,XJ.>[壜l~TSG],\7-V|r䇜 =-K5ghC/ ,R5]8zuM1黟*g i)"rĐˎ/sf`8>nOf>(N cmF*"k[#%8ro; R؞ؒK-3t"'r9ZbUs9NIIaIe$L繚|(xa`y-.ܡ;L5.mY 3 @J<mލK_ѩքQ.6UVg\pОqp ݙb,.RNs#e<`uz@Zh ( |8!=\*32a_ѝ0n[ XOH^!,Hn+RuWmQ zX0@LKH[u2 0{a!OHTM q|QNQwơK7,m `{58 gz3JziZ#to{ *F8H I]m,Ϻ\jSWl TM..5H E|JDZ ؒ8Df4` ~~U|Bᅩh8`;fn R,UשZ(*|n%~J&8agD^R0V v+9 4_xeupf>q[͗;<xVr6+L6m2,NdEKĩ^#RjŁ(PĄ"Yt|I˒#] p}޾{gåXlK#'-Ybe3&2 Wigoò]cIf%_ml 8E"r'=D(Ec5W#0?i:\qȿ";= e]p<jO D$̢# WsuruR<{Uh~ugYoDC$ 7KS\ZOn. ][Vw?< O LX [ڛ7.+o>r >΁!^(ͥ|q5sgL&|4u?5π:ɥ&B$' Wg O)w>4Y$e?Mx +_ ?Ro&<C=lU˙m^zKKaoQkP'0,8--w%#)2b6dp|%JKm9Gw77gPcW`1\LCo"Pu)ijA ʹiy@-P?nwne199}gܱہ.Z]%3SRn(&k 9y&8ѡHe](aP ԎvH&:n*ux1Y]!6ح8jѲH+J# u]UAjl gtuoqTxl HwF1uS$@mMR/>LyFs"' M֐[1ڴ|"E;NcPx?F1mxXI~)h ^bkCIѹ(nQTE@oJE+ v(.4et>Q;Mzн \/% IY0V Ho=Kd4BI!^cҢHWh/濴xVn@=%A[{"I { ZqXɬ]: ]1`lLF*Re73&t/./ LW! {Fld KLat.qcKLs4t\8WƱˀ7QnWqt,ЇB*ЇÜq?!  d% 6ޥFP0ķ8J'CH*gA݁"e[IB%%/ I2AN}gwٖ 2[,]!O 'czZkOq7q} }b Z6y1ujY9tbFKY#O#Gu7:fݦ'X=&Y^"1MY ~FE!"db sS!q׶وyW酑@?2-+z"BBJ%^=o9hRgj52aTP1&\9yJ}wGIQhL,dr6Zl8&7װd_q҅J3.8*|{G\r'GȳtQ@ 1M x~;U}hm/65g W-5Mk{#Hn[)_~WǕrbT5+齬P]mPuxw]mmerj#Bhfޭwl\Y٫4=s{hMBrP'[s~Idnn]me盕:ܚߗV]_>[|CǫjooP-El)x;/AlBXY$xVMF=EIsIXiDs'k̇V+eؤaSݶ\իWe[?[?TbP[Leږuǣ4BOm0OfR M9)P#fx?֧wyN坧'cܝCt(G NCґ=3u `B,u(#;y&poo6#p)9|ƒ-z.U~vyXH.:Gպ4Q^Z #vѹ t`WoY lg|ylQ(Sc2.Đ3ijʗ(o]S>e pDy̎q°niJW-ze9ls=!G->_})&uËX/ʝl ᜵A篥X-I[?xs+$X>g6LP+VůLdK<+/}HmFK=$fx _qFɄ&-jv?>Q2Wyc/<4$\@G"GvT,01ۣn0lm&8%FℓFp {6)8TM)0x9?S1YunI|[+(;՟z|S[dYYҵ f. כL(:t챸O;Ue@n7z+՞nтœ-Vl+pt=+0es?:JF1(B`ᎥT!*0L4Ȁ~j_Y>}PSRvjHIBM]ŒeipI?z4%_x.I`b|Lb'3}޼ak%x$pw"roo7xȾuəo'gz6JTx(JՓi/3̞cfuf}{ 9x[úuC>H] 'Lc=L ,x[úu2F,J_M|]",x pu6~J҂iYUZx9pu6~J҂iYUjRh#M6u"m), Gx[úuGF&y70sضmɬLq ,x[úuBȿ_L3ۚ978a%J/H|8^\F̎b.b/ƿ|X/ٱR3LZ߸?K{|i6N͛><,.nn/>',&ur ֜p+k`ZlO̩;x:>wL5Ǐ+ˆ梎q S-(mkhےhi;wcX agиW4"`˸!2ӑ}\ t S/q LFM7mVڝn3"4/6k3f#ZO֣i^ݍ-ؔ;nہ//ڍcI;i62Z4{ `7qmC]0oȥ,c[.=Z& |Pַl pyq)71]PD=pVr(S[csaM<2˷8 sTZY \))@F _ 0s`CuPhkyLF ǀ/RY= e#R$Pb26P:y0]bYds˙]fX~yU\fu֢ެREJj;k<%q߭&q|X+Qhb ;sd>>;za%^sd8ƲhKkn noi2:n U ϡ6тcYw~9a莋먉mL*s3iZQG*fql56Ȳ r{ޣ9FMfȗ'8R/xI(T(Ir^_پ,%ӣ/㯒GΒ{u2ɝSsUMr{:Aq\Is eMڟgfZVp?=1J RQL>s88-O W*jY|bggw(l-%)Gs!ĵmj|Vc':^q2qď[ě^X?ȃoɯ+Ln] S5c3VH^ae vZMrYOA2?sD6gFEysCAu lN6wR䋹suӍeWK^ky_7S3}˄(4bAjMUCEtwq]i QZ[ԎExuu, 2005N XFthere is * If lenRoyCMx{nwnd?2/= hx{nd%86bγo:Tvs& l^!d2YOdGs"Jz ! iy%y @vf^Ij^JjBIBRBi1YY\ZYTRT\2tr䍢J/*N$,YW4#9#HA4)'3;Rs~,9B=2xAlAbPkk%+ڦtEB-K"&2fg֊Mzƃz1=yG<ף, jof^<֛ [UԵ{(&[XtM4,P%G}#JPNsJRNɹ٤7?Q_ۯi oBVozhKO øg~/9%>':#\%(o/J:$KrQI֐-ޔJIInTq=/jo]xsZ iH؅eҚmoȳL0⇑Q1[TAA5 !ƛFEm(Db^RA.,nfm`?[`2T5(hxؓJ"5BtԢ,U%@]0z *nk`nhM6$0l(tTv.*q'y"~ 3U俚_悲!]wBȂaoEF%@k+YɴR7N݁D7xg2d܉{ R2+RS*B 2'[3 r)h)g(($n.dcC9 ir*/vT((MNS|YOmN lkxlrxBoyx$nxZ65: :>{ !"^0/!MIGRATIONKEYAUTH *migAuthb= 5Wxmv`j~ƴk)m^' ;o(xmRw#1vԼ4.7*x73=dO8X-<ё}nE(.jM[| _K,urx[ʹi(CHfW D;+ i x[4A}V6x[ʹID71;5-3'U/1aȆo3-<|%/t: #\5ux[ʹID71;5-3'U/1mp)bIƛz7fnTgap4x[ʹID71;5-3'U/1!Hzβ?7tr[H~QIxq64-VuSlnRtFtxp`~| *n7ӆeU,P!xύYޭ03Yx`i,ix[q2Xx[ʹi8ȯ&woˌd e )x[ʹik,7vg&mىu Si*x[tqB{uP=x[tqBbIrq^r~^^fï۵+(7f*h'tx[tqBbIrq^r~^^fCI^:/Y1/f`덉uW7xxq^Uo-<[V"tٞE^xoʔvaltݺ􂸣)xxqD|/}* .wiR3 i*xȸqD&Nxi{EYKZA/ ě}, C3x{qBW I߲K*>Ql@g-x{q5uF˸~^ZPѼFA Tx3^LW Im^(%7+dz|rd+2# :>qJpx'Ax{q5EvGB_*㋡qU 'x1C-|%J'ا,x{q59 /V 4ٽhvf''x{q5}92wɫ[UQ$E 'x?J TKWNyߑ'[,x{qBxKr,n0Wvęq jx8qa~E6C]gKmN{~Y x8qy9K~tf= ,x8qB9g'Z8k+a* bSx8qBH˷Ծ .x :8L9]Nd$.x;|yB3׵uI=*gwY8{cA #: +x;|ySKݧ$?e)`Y>$ԍַ +x;|yFމ1fn~5K R(x;|yF~riXlY` ]V* ,xL9IƤ"h~ eC|2M?F/`7m-bhWzgv}hd,x\o]%7 Ҕ88p\ -x;|yȝn.Q>I?⿄O25?d;>O oYx;|yb֔5kjjnad;>U n,xˤNSe]ޫ' s*x;|yF:=o\.aiP;S* p,x;|yF|W2]42cj_ FTx3j 4&B.^lp+oE/vMm(i\)ԶmUx3U}7.&mrRؙB -+oE/vMm(i\)ԶbBx;|yFB/nl)jx/OT S(x 4Ƥ\qg&ړ$.x;|y3ȋ'_k(]UB V[,x;|yBG9ez1U:Ɖ֌r a+x;|yBH%Ƌ+_~P[tZdƂFױ LVx6\y(xԟ"NEb;Bpn,< `^ a%Gڄx6\y(xԟ"NEb;BpnDE+,ڞ=_x6\y(xԟ"NEb;Bpnw>m&]A\:gmڃeEx;|yF_Jo߃[U0Td7 (x {>IYac ߯G$BVx79eJ #r{>IYac ߯G$E6;x71SejZ{]uU{>IYac ߯G$&Fx;|yBHbi),k<~fcA #l P+x $a"9[8C*$ V.x;|yFOyh.Jr, Vx3-|XRvckGtMΑn G"l7UAx;|yBZJL6r;?dRi}ƂFض +x;|yF &6.7^%8 ?(x\cETRp\-xн+qNpB7tD,x*Eqc՘n4*x;|yHford;>͓ G,xӛ.0 @ƁU f{x1c^X<5ܾJ~O&8 `0x ViJ3jh.x!8۳pstsV WLZ/x!N} &m]JڤN%&!/x1cGWi:iS/yeFL-x1c7˦9 \5׉pK6 (x1c'p%F w$Toa aUx:8Yj"pk VS@B0RxWAe2 o`x_L5Hx1cȕU6N C|dϗ_&/b̏[P+)) D8_\ ׯSq.5KG9Zp5BY P"ϣ\-q,:4"zyL/DvuܷW-eӎ)u,2C 'E'j8ENm8x1cȾꭼa(',73wOfˌ.xc`_ّ彸Nw-x1c5u7 wV>Wn|6`eFۻ 0-x!Zs2,ˤk>NnD/x V劈&dnQf3uBjZpx1c $Ÿ8UU|5Grɪ̿ -x!`۰u J6rA/#%Y/x!84h"dL&Y/x ڭh*1cmxey*.x!8 FXQdXL_]x:C. E.!1h 29 FXQdXLHx!cGD- Ȓ P/xxK/n 4V{)T6J; ?e\ Q!100644 tcsd_wrap.hV@%ʅ⇥ijAmXmheC3[x1cW0aRQ [ه2# ".x1cBȗKjVe;ϝe|ec f |+x1c5]GaSoZ+3[f5ƟLӪ S-xSk]K2|2lgw0gL6=LZdcwyP"4I{Yée-)&ax1c7O[ %W/uL*4yq (xS|ȃɞk,÷oh]]DiV":ʚy %=Οs.H2"9^%ax!XrhR=%ɿó&;/x1cCQmtڊ|5\\7069y+Z a,x92L -x!C"8F-aL& /x1cC}SN\o9׮8[usFFT \x:PPG L8Zb`u Q擢Xk\o}?\ׂ·!%n\1Hx!C}PaC(&:/x1c7Ğ( η}[HP NxE (x!މRi!<ͳd/x =vESA G&o_.x!qۦD=Hp&/7]x60 :HNA O웳&FBxP:U-adsx1c7C| '%c% cx1c7V; Zey?  x1cC[m[ʩ> 7ؿyc- .x1cC..5 mWr214gżM ,x1c[f#N^Kѹ+vɦ.b2# Y,x1cHォ݊4,:Y>fˌ$Yx1cCȊҧsb۶4^,x:T-f|xjB1͊u;]^/4xOvؓjIx V&&'ڨ` Ǿjg.x1cCH$r5|b3KneW<~ Zx:ǝZ=ɛ(!O}w&)o]/ ٥Hx1c7HH>.sym#E px5V]+?Q.jTlQ''ӥ2 8FCx1cCȺ]vk1/~ujY< px9Zۃ*6/;eP6n,<2gB6Rl/gGؽGx:W!32. Z&hP2)9coL߲%γ}/x:a3+ 詐ۼ▌&hP2)9coL߲%γ}[Xx:5S21ٳӿW榡&hP2)9coL߲%γ}IUIx1c7ͽ.w>x=pHa ?qx6"_.T )xkgjg,uR`?/|Z`b'--xkgjgP$"psˑDR&}e}ĶFnsWxkgjgP$ruƯ_J20ĶF *xkgjgY1!oUY6/}  Qx35w []G1OƑI̘xWSs݈Ϸ98nx35n|ٰG3"30I#YR) jȱs+eY"-Bxkgjg,K*3&@x޳=/zb;Mlxkgjg,@Y)<|Ts& xkgjg,b~aNFk˱-ob Axkgjg,pb_8h}wA lxkgjg,}f!{oflZ31} +xkgjg0Uii8j+m*xkgjg,%){bU6&O:| *x5}/ͯU]MI,xkgjg,~QiA| Z-ܹ`b *xkgjgYdndd*j١S QxkgjgYGsm}]6Out&3 BxxkgjgY$a>ڕz>][߽{{:x /.22Ixkgjg`*R)}HWm ƶD^ܭՒԶa3@xkgjgYDrJߚ%O6 )T[XJx gxkgjgYdʶMneUqjB xkgjgYs߸-}Le(]K 6x3S)bڝ[#(gM^Y[Lw\8ua^Zxx3Sk ઀giFi]Eg W#/l-i_+DYG:x3SV_C4wkSDg W#/l-i_+@[|x3SG a:i*f1zg W#/l-i_+GxkgjgYdl kp~y5 0xkgjgY%WsXf~ xkgjg`*u>jX妀3.( =xkgjg`*"yeAELh<%|D}CFhx657yrM(WI)2T^)D{dsExkgjgpE(~u'5\cwm65K*xkgjg`*ǨpsMlQ [*xkgjg,"pօzڡ)LvU<01}_ e*xkgjgYzVNk 6蹇G Qx35J쌔 `QCbtI9U/PJg=@tkAxkgjgYdétV1mg hxkgjgYO7?$uGO6l/U̵ xkgjgYDHڒM,YowL7]MOwcvD 6xkgjg,?lt~e?w0E7(ű1/K0^4}m񹒲<inhjTQix%4B(D|Qӏ4G#;-%[ij2]@3MC&V_^Kvj]hN#>5k vƸ<N?j88 L#uHWd N0L!p6>д/'S Pw\4/Z ό`7ݩ+'+pgk{a/)EkTĸ͍fN7WݫۺM[GǂwG1teCD&GԳjxlM 炱,y6%{+%V9Fmw΂^*;M8a:T("0qK*yB>*}_GxFaԐb[H Qd΅652Ԓ%n3 B: ]@+rѤF'w2ZaT`E .0kOd;orZų Oy;7x $~KA8-+VsX-n Ӄ> ރHv2Ľ~}w6w5RDgY4dL N;2"ub}@h>A%*,N!\Y+nTX%_R'da-"ɴv;2:\*;1PqeKv EP cB['K.Efw{!GӭviH,!ۣ Phax ,^ p'Ce[}b˻ ق-ek 8xii@`*kƭ"lX/"^|еF- Ԟj>buGTPp2h<t[QMG<-S71y ՍFuuw +JFw2Òx34N"WME[qQ2O}ƨXf;~/mmҐн0IA>M)~RmM:PI[غ!MaHKM]W?yS\AHq1| /mq. cMl.-dBn-dC'f eK*G@վeB<ҽis٫/ͨ7d^/Fr宒ڷܟߕw5_M^daTG_{T=—t!=k6JTnX7Ҭ?wBTUiut+;ݖ_Vuͦ-=ܕ~V_˃HPx[]D71;5-3'U/1A;~r +]8WGo }pwz#3`b?x[}C.`:/+?qYɍ@,x[}CGMWUrv{%tc̩˘B-x[}C.H!['lL7O5lcɍχ 'x{m:F]j#Z^ʫ9'6 ;RF<0x{m"Hm ׳sVn6e2b -x{mC0wm3>]\qsa nUxE'100644 Makefile.amSp ]Îl؎',:=hN Q|١dUSx{mHeQ-Sn{|5Q;(H~:( @x:XƜ,:lMm'Ȁҳj*Eeea XrR@'QHx o3hqgw<(IL㗓vx9z ̐d=iQ`3hqgw<(IL㗓Gx9vo̝w9 d8rKx"G")52{Gx{mC0Ȓ͂ w]vHt ox6!j`ݠZwOek85C qsr5h}JNxə!'0iQǧӝWxkgjg`*2pOT-_%wD} xkgjg`*z#@k^fS>|x>| ,xkgjg`*N۾s٪sr>X lWxkgjg`*X Ow xkgjg`*/&o;ZmTt,+xkgjg,ݶ?\ɻ˜<1}x Uxkgjg, ߭20ئ]r; *xkgjgY$'+Oa%O=' BQxkgjgYd +mm-: xx3>ģ3e˟-Q~xJ "/=Vf r,Si'CAxkgjgl,a5C&4^] P(I.Na>&fu$_` eIxkgjg,V#]SZ|FύCߊ sxkgjg,d;SXW Gt{=:1}L *xkgjg`*w”7n Mᓠ{`͚]Tx35oJ Úƅ=IrMHjn0z.HY#upȦX pxkgjgY)wˁ ͦײ|} x3FCSNNVJWЃ5j{Pl|]Y|]Bxkgjg`*桢n5"C=% lxkgjg`*b`6L1+h];# B-B&z_ x35Ij}ObߡIF91Y=m@ ֐;^?1Xx35g"4Axވ_Wo5pIF91Y=m@ ֐;;|x35m1߯S9!Sf`"IF91Y=m@ ֐;"  \x35#c!hse3!:F:IF91Y=m@ ֐;ҳABxkgjg,2CCMSvjV8gbhlxkgjg,% N'?{Lu}yhb xkgjg,BAMfzRo{7 *+xkgjgY$><܏{^?pM RxkgjgYfcMsd*4m yxkgjgYJ%>}zW!7}s x3:pJFI(,Rb+کO>M \ˮa Bxkgjg0Ud:2ql%m&m`8 x{q5is~%f>\^yMVjͦCx{q5RW*yGc mx{q5gh4?]_9_, xD'100644 Makefile.amےeD gm'rp(.#UN]Ux+VV2vj6Y4~x3^#|fC1N)AKÑXđ'#<ϙgRL L:8rf(dԚA4M$&r!h"kEjA-0|2H134悛(S#YKZe6_ĻTB*%qUmm?H%9?FDŽ 9[ŦZ·30@-$JI+fW4,Y °E`rc2ㄸNjF61PK%4@rbhWj̃-OIuyxAzhBC`X!wrh}xɽBlݔy4D[9/4ַs +;桀0HS@Ц(Â'ݧ>%p&?;2AmbkZ@T\Ju=)mh 3MKr~eEm\ ^hzeH-a8wC1( x5[܈L3qˉnԃʅmtv2dM3S=aOKT1Ƿ; ɾWkОa=y{핁γGiy3_09@8Gol[߼U}X(!.h 6Ixs{C3淌Ҍ*EY'K(md~ Zx C5w}cUL8l0x{ζmC-e#RFx5'100644 Makefile.amnsKzvMV'V,](UxSN0}_q/bIm [QNrcZuv(S|s=!>>Ld)nV2d5 [8a`il)TYgrC鍏al굕 yi4S0j9\. >/> HV hgYNRr%;;ҥjo_X;y"JU:=8=l\p|;u:I&9萑?=$D2O>jjxWOVT(i-RLa $ 4Mc$8u5߾s}0tmXCHeA,"͘PKHpѽD>bU"%I9i.B^T{-R\E&@4 b'LJ 9Evo,%O8*p~R-+̘&Oy֩L$`T'uZp4q-)%Zޫe}^DgsJ_l[(W< ,+Ef)NgDG-[ 6]#[&Xlu ̑I,<*>IoY[NRB;(ߎvAM󠝚CaƔ.σ$M[Ƨ`Xո߇/_Nl1Lu:yj4SHPAjx͙6K\m2k E -2_:d5-b$%rMҔ0͓POLE. sfEZE^ߕn¡%Q 4bKѮ$YEqyEcUfs*Y˕!RarX`T8G{m=78t.h Za- ȵkM~]9Lw['vFzHVx:C51Z\t?,1J CoGW~ 7P:9۵wPӰ3r^2!x}RkA%h %*"[-;aD6(Mewnl4)3Km2 CI(57,;Rcs"6x7seU35MxZy8g⛃7Ix{HywAq|fq|vje|f%F̜E-<@̒Tdn,PU Ee@lk%`*KK3S&oѵY;Q (5 EmZѲjʂTx(ILNuKvI,I]`!Ą!So|x{Fy͟X~=II x{-x|Pq)dk.wx8&ofiNx_yC(|LyX.?JlxGyC(|ͯ6\_sx!㚦+[OE6_^˺$[ S2xmC;H -Î|V7kIcl' ,x!̱:!v׈ V/xm Hí:/ `fu[xm H B x]R59Yס m,xmC6+r f~J< (xvJ熩mj5zXHUxmBM7.xL}޶m,Ӫ6vgokp/lgɺ8D 3>%$Q/aC-Q.޻+@RZRZTyF$ݏwOk?I]FbqPʨo7 |]&?HʲS+L+\7gbc~$EE@Em[hVop"oŢ<Ȋs2A#./'W9,S*,):]2TZHwr:҈'xm%E\Խ$>,^@5os;LF1.xm%& !1PH*Wا4Lg 2,x!@]~C0Z=ӳ!*/xG3:fEY%PT100644 obj_pcrs.c?4hNgv1R%ܳmV HUxm/DU_$-)?VAӾf͊qL3-x D2븂t*A]QX'.x0'100644 Makefile.amƪʯTlXY('X>x5X[QJlj+[IGƓtяPuyp>CxRUNR0T?ҧS' irKK>mEn:6 NWܼM2.*$o`xm/%ekE^L e^͊qL -xmC$Ϛfww|h+5CG9y\F!&& Zx:Y|ݻ=Z,#cmR֎)uR@ =];s lHxm ȌLûn2Ysf^,xmC6Ȳe kފ9zsfy 'xkgjg,2) z7$꼿nm N-xkgjg`*RaHb5G~qO5=ԶΡ艞 Wxkgjg`*vw)LSJ]q>˺ xkgjg`*ĕsmU"[UvMq &,x35|1N!M UI(C4]أÐi;LI==mxkgjgYDKdɑXOxi0s ixkgjg,ug u^]-{V!kx3S^ d_K(g=n[mZZ.=.Y-,xQ52|~ޝ )40000 tcs[FQ/~O3g IxkgjgYfEٔ3+0/ qx35l۹{} ĵ)I|dXg~WS=jb,a &xkgjgYþE},8/ն  UBxkgjgY+5]N-:?T0J jxkgjgYxCkf]"jJi YJ +xkgjgYDc~[":{ [ :x35UU>ߣneYKIe9ڈ,} ]upZ|x35F]N\CrdIe9ڈ,} ]uBBxkgjgP$Y QN;Mlk *xkgjgpEJӤ5vM7`g ?4<F +*xkgjg`*H鉇s ST~|\^6l>˱X,x˛%IIJN3xd# tTx˛%Rۓ5s3p)<'2=a |x˛%ҵ諒LkN_7b*2& #x;|ye+ďJ;g040031QHNLHKfx`kuͳ SY'sdUWTխ6ԏ<۟l[eD_)S .o_}+?YHT.b+ >,mֶdѫ [N $ )hmo L%2ȮӍXhVxo\ˁ%:evMu$pnf1Nh7cdB7Mܑ8u2o1 |EzD100644 tcspbg.c6;12?۰xEwZ'c/~x;|y1S>o <[٠pOaтv}$*x;|yMbw2j -x  }\`FCY$[x7d wEa{OՑ }\`FCY$=Ex;|yBHၕ ]5Ԙ_m7s bo+x;|ykw 4ϝ$WT{~cH Wx7R;Ytp8k)_!>nr}ϓ>Ex;|yBLֲ=TPa C &px;|yBȂd\qsEucA # +x|“ߘ8?vy4*x\*8խ5}p\-x;|y?[3k˖ vYOشw Xx;|yH%?kRbyfDkkn[ x;|yHDzSX>Nwn劝}؂;Bxkgjg`jdtaNlKcb % s]q5'^fpJC[NL_sKxkgjgY^k[ ZN_ ]rxkgjgYd໵/'u\)G x3Y)}­:jFؑJчbQwEBek8.BxkgjgP$ _ U`9 6*xS=pP_ ʣYgVVxkgjg,ŻS']P k *xkgjgYdq[:;Z{w}ǟa{: Qx3rƅq <,=AmPs^O_x3r>00aMb.;5mPs^O^:Bxkgjg,C]{%?=s0GxHx+/,2?e <L  xCD;;< O100644 spi_utils.cԁS^^mk&'Tx LK`SQ?w.x9_{CK7LگQ{ )ss t2_HtwX'3Gx69=)"2cQ&dzMY916RHK+sDxmJF͉ihV(E$sZ<`潌r-x!!ɍ4у$g+'8/x!T`mQِ3ҳ, /xmck~:U^Hu-ob/]O3N7!e{dG7r~(d'畤V%3zOʪEa?甞z]K]6{]Vne $JK2s_<Kܻ^Fv%xmfVN?Zxm,,a?O׵X~tcz LL|]w[`a?2m|ϥvFߍyy)%@ğI{ŝ(kԏȘP!kbeƷCJ"'֭dBQqbvj%X{ !^]I]IA.P˪s;Of^P~҃ P((fC0xx9H|I{:&ޞD(f/Q  “хGx![nXB3Ї) /xMD71;5-3'U/1C@ӑsz3)T;LFL-x D9bH~ÓX'1[xm "mKNfRpud(fu #,xm%HGaOsto-M}5w/#"-xm H']SVr?ڭ ,x Uk9@gWk&VB.xm HI'"J& w-;R|jr: KZx Df`{cXŦ:4X'].xmC6 C`d z6l}a7=  x8q^ 䒂dL񪀁#gD -x3:2j:GjސY%ؑN6=!:;sU:Ax8qHeǫgN'.ɽ6|gӉ~^ }*xdWփH Ƒ(pǒ ,x8qBH(!ߞh-dso Kx{q5Ye- ӓaާsbuxD'100644 Makefile.amZ'GȒUGԑ'XE%V.k]5Ux{qz*M;4/e8~au\ *x{q5[$~~ Qx{q53S =ݮ>MqX_zs 3xx3^<N2 /bnّrdd:o1IFd@L'AxGae@K1E$jx{q5;?:47Y:LkX< xG)6/?  ;x{q59.2[nVx~*P-5 YcxGuohmb1xkgjg,"rh^X|y*i;'/ ^xkgjg`jr6=u.3{[ÝEM @$-7nL)[&/Kx35B)v{ɫ$KTzIi/n&ؚr{a~K9 Axrɴ[Z,xkgjgpEm'|ps2/ mVxRA+f=EUo,+35'9%L40000 tspi5%{CJ>dQ# xkgjgY{1 ok-&+ 2xkgjgY$cBxkgjg,ϪWp2sSEg^%hML_4 8lxkgjg,r}pqÑo>"kr^eb; Rxkgjg,b$+SNەg\Xm Axkgjg,)rFkjfß6[{b =+xkgjg0U$i&  4X̴{BNĕq Uxkgjg0UંEh?OqY/34k8(!*xkgjgY͝RS۞3ZgطW' Qx3^I 2Иj-s+pu6ʛ~1 + TAxkgjgP$bâΒw[ؤwzĶF*xkgjg,` M:ݎ0{*|O† ;Txkgjg,23㰯ִ%W0J#0bb ~xkgjg,xe ޜ SE'/ X*x5VćIr|"ٰIkVx65VćIr|"ٰI)$gЁ%/:CڙZx65VćIr|"ٰI)>y0 y8L٠@e_x65VćIr|"ٰI)N 7( $x65VćIr|"ٰI)ŀyy/{SExkgjg,2oC*SN~ݞmb̃ oxkgjg,jyJ s< OL_c *xkgjgY${.5 :x˛%Nrnw>[bjx jbx˛%bcb"fMyyri O x˛%ؚov奬6m 1x˛%WޅWS$O~ Yx˛%R4Atj ?gݗ. %xx˛-b]˹҂&)Y + g xkgjgY򯘽 Fyww*q 6x35K\jH{*5^,TwI\S 2nNEH:5#zx35s;k8M_퓑I\S 2nNEH_U>x35Q`b3FVd0I\S 2nNEHx35#0u>&0uiV7I\S 2nNEH7)Fx35[VX E|ZGҴ^cϑIzw ALyWx(f|=M^|Izw ALyWx(<0~Nx35S 63Ǜ'%tt?:MIzw ALyWx(߶x] s xkgjgpE&]#eYKeB& +xkgjgYR+2^/37!' Rx35Vvzr06)I3ovlMfBWx35Yib| 7jHR =͑I3ovlMfBBxkgjgY/o+ͫ}uyLC] ixkgjgY|vqaY0n-h1 xkgjgYA¦z܇ě@ 88xkgjgYDഅVrde( `xkgjgYdeo[?]=ԹL۹|v< xkgjgY#yJ}FuQhh}= 'xkgjgpEfW_sԍ &m\/!QxkgjgpEέ˦<ǻHiQuZ/^*xkgjg`*@@ϞI w95s>G Tx35,^>0y壧i,I/dݧ;D|4qAkx㛦I w|gaƲxkgjgYd{iHZ7VeԷr' X]*t/2 ӵxX]oI}ͮ4$Niv 2xyBEw5nzal{ivfyι}2[+Jf'*^Х06WVUft\5n{rrl|=Dp*4J\~ 2SzkBb2| YX\H_pWb %,Wuq~ͅ8nڈB|~]J*(J8SL9zD;1&>+{|dzڻ&V-Ue{L :Ho6:Kd x0ɭM]䈞YE %,(BYAG7GlhS]\J.q)qA%.EUß~OwwaJ\E9PFx;E׶D{3%>*?dQuZܜ;N~w7]"I2gR&i1`d*s1c契T9ƒ}/7"7bV%e^oySʩIkP)tFra Ja>DzEEJŨD*'iv0r8n%\^\9mwrA-)().9@Z2ydGǃC t 5}>dGN+Q=<ˌ*%ŒWkQ L:ĿT }B][ S{yL6P 7=;n:x-ZA( O5w}D]݃:>M-%k @q  YY PjQ~HxUEzrJeGNv?Hdr>i\lgE TL6nQ7Sxek>TpRH7!vАH&\dIHK=Jez3>pz#:kV7>Vߕbg3}A\~YBst+V/A~A( gLn{9,*a t:GVLTX.9È\^>ENlj Gso4P,<"Sa eِlxtA "BTPV-kk."߇D:U%~O;A#JoQlĎ?ї Nm/!fWÂN_´*cVwS눢XTn'։OOkFTq75<;k {byj6vbD`NJba(v-swM8q8Euwqw_ii klΠoN?n-uz/;x@ PYVrU!3 ^oG5zќ~Q,oK\\%[qSj80@t ?.[xoR5w.idtP-xIMq=3‘ڑ=.1!C!TS,.N " [8>DҔHŻc@gHxH@C]QB8+`E:yܝJ,EOzԿ)!K\Eo_XUr. ,J "F!wqTr@اK# H,DA65|\b%,J%%nVJA$8ֺ:otTm1iV9mPV[AnմZBΩՋs@]ex@8GP~ЁU>5It`MGY~GFc#s c F9۩9HWؠX1'4\/u:kH(D,ToNsX  <mP3)8iLHtVUlqe(ڍ5YA(šgU x)o~gi&06+18tnX̝j9 TE x\9B "{pq2x+e0t%FQ<4HxtZ=5͆t[boщ.r/Cc}_ 7? MiZPv|~ Y?UtL?{cAX~$f&uF+UNw<ō,n&^6 t8%Oy֡m.ٖH!0-Dm>+.i1 @5Դ֛T< Q1T#.e>[prylN 1sݸP%M6ux_G3\ĶP>;h GuyUȑ? E";]>ENf̕ 2!\p̪@m)zX&bˊJK2'Gԟg SP2aB t.xKCBFa6ױdm^m Tx?AoCBFa&ױ۬ve/:@ mqx;|yH '蓷>t*d;>< x;|yB]Cumz&Ox;|yZ;smqyc<0.cճ /x|ivӿ!2O9ݺ~_/*x;|y҇4_lQЅ,x;|yF),Ooj~E/qj* ,x *C ߘ*ёJՇ=>M3.x;|yBL[=7q߸,ɺƂF S+x;|yF $;Bs[vH]}|yNp 0(x;|yH+}G,yYiTDOFzF<+x;|yF |7nw9= (x #*>HG;sa$d.x;|yF|u3wZ~B. (x;|ye)Od>8;َ _,x;|yBH "n8ԊzY1 {+x;|yBHF [sFB}^"y]$q5# %Vx6}h}=GQ2}JY bMm屝 G߱6á=ڝ Dx;|yBH9^|2Ă֕-஺\WӟƆf&& %%9z »g4\Z4erl+,,߲ů}1mYz ҁ4>~,\Ճ3wu6,X@x;|yFo3DSoo!I )x YXpE_2a $p.x;|yBƞWX_9ueڪ1Vp+x;|y9I!!Kʴ~ޑ[z +x;|yF4>mSx;|yFӋjg9'LxYݿs {x3?$Yh?5~͗V<5&/@+?ǚ2Cc`{ +Ax;|y|hY;l\ozv}اN,x;|YD71;5-3'U/1!rE\տ?V.H+vQ})#Sx8qBMnIMxeZ *x8qHbDi2x.863=d *x9a/(:"4Sx8qBMC>f|O zx8qB\Dl`xI8/ڦ !x8qB[~V\{sIx'޽u~_ϒ/!sx8qB-,cukF^ x{q5uJ-xh?ƭ AFx{q5ݲj޸o!mzv pxXD,н ynkx{q5y3Ni\XJSi Fx{q5z٬l߹m&v@v <*x;DFG$ƨfp'J,x/'100644 Makefile.am&!!VY+!ڑ'Ö`=x{qB@Χq {xw14pbQk |*xǾn=mA[XSx330]I#%5a=Ǿn=mA[:Ax^[ܲI-kxrx,xU/*uŲ)xvIsh'D,x{q5VCQSV{ŨrrD Sx{q5&>Esi{Qt7,7D x˛%A0aiL~LA_+yB -x˛%%Sg.iR[ i| b]xkgjgYD_<:i.^ja  xkgjgY$HwtAO7Eؙ>ݡ} \1x35B[1|Q>faIR-g?R䧂X>5++8FDxkgjgYa93,KU.VqaD@kxkgjgYѷO=h\Y/Q{? K W'xkgjgpE[^mR {M+?=N PxkgjgpEߎs"og-mv {*xkgjg`*U8S*QOڪ^͟ Txkgjg`*T'[W99/W[= ~x35π?ID7~I釳:g]KԳw kxkgjgYef+c _R~UU hxkgjgYZ 7u͘ # xkgjgY$j/:dovޤe  7x3rh6"U`[ЁBmZ,t# bH`tyxVr7GK(5ߋLT(40000 tcsd_apiyKɱ'ku IJhL 9m jqhF&'xkgjgYDS<޶>޶d>VӞ4G lOxkgjgYJF9F1۱!glO 5xkgjg`*RG nr%Tv SxK5قv0k fx#YIkޤySIM +#؁.S6v+u&?OZ~Hq΢d6]0k#Yx351♙ڝA@I}OQOIZ_2{@ 8?AxkgjgYX039w&j| hxkgjgYdWO57qMQk'x6S4#x\7L;e)2gmݛZMSY; a]Dxkgjg,y.aϺSxʮ*xkgjgYDjٲ9^iY¬Ⱙ+,XQxkgjgYDI>щ*R®7y |wx35-e𗮜X%>2,'I$¬H[a$xE p{)AxkgjgYd/GqM5џv(9={Y ^hxkgjgY|#̞F3/~?V4Ꮠ+ (x3Ssnu2 noTƷgxڦH/[#\o/ jx3S۩~ *OB+t(g!r?ɛ{[:;h_WJ,x3S?lbGuQghNMxcMw|!dϷ .nx3Sce{@@ ghNMxcMw|!dϷ B70x3S3Klp >6#1ghNMxcMw|!dϷ 9rx3SmInJh)ghNMxcMw|!dϷ ;6xkgjgYdH6MZO}d]v ^xkgjgYd]˭e gE +Ore| QxkgjgYd~ɾ'˧( # S:xkgjg0UdgeG94/L:g8c8C @+xkgjg`*:76oyLXg$9 r7L *xkgjgpE{Ғ )=_scɑ/68x!8 D ^kڂ`2xm H_O%u~<?+~r:^x:\~&bj^%:lQ^(;flWwY2V_ryI@uOYV`h``fbP\WZQs-kQ[ig_^vIaJbI"PAkYq.k̸RS{4TL;=/n~g  |.mFRXTְ>&ZD !N*:[RSPPo &?c~tE65y׮gf6?2\$3_zǎlO &֭-J78xmJF{3{p; HLco潌.xmC6އldڥ6TO1T (x :v鬝M8VncՓ.x!8O׃ kx4d]/x$zOi5[5ڱ-xmC;H>y{霪0 =y6i jYxmC;_uO1G>gF)7 1MRF`a+xMD71;5-3'U/1!@cty˧Lwѱݨ 8]gxMD71;5-3'U/1!Lbw6Ffby{y ݱE:@ Q>W2Fɳs &GxMD71;5-3'U/1ᨄbI |󢫏̶ݨ &&xt hu( 2x˛%=e}u_ i/ xes^I՝Gl{<[swpu.x4 -H1g -xe+uʥMV+e&@PSchȱB^~'EAHxe+;blIԗ7H&Mtxe+Hʀ=#EO}Q{/Һ#nxe+6SDc˯,,hǻo\Ð  +x EMlQA^Y kYx9sEf|Gc w$8k)T_sAKc 8xY jGxeJKo/xF֩Ab;6z2e +xe+\ h3/xiߎaH& xWxe+H:۞X+kxN\;fr$ f,x mq;A> :"&Ɠ  .x4Sƹ't2 3H1[x74m/WUӧɋI}HdM]04Ӝjk"~&Exe+ȴ9mÔ_~dr$ qx E"Iۘ{CĤ?)Y xeؙI1{kV#vk,x4L T5CiVH1 -xe+HԊU8.m,ƬXɑL Yxe+HxΓ{-#?}J#Txe+O?x VvɑL 2xe+D,g[8Lj_|:gr$ߊ -_x EmݙƯO(S vY C8xe+Íi&gd\?Խ# ;xe+nO}#L24R29I ihxe+u*ׇJfK^W ur$ pxe+H0ϺwVN;,k]GfɑL 8Bxe+H+O߼n;ZjɑL  oxe+H}$M6/m۴kr$ xe+H۷*M!VV,Gor$q Ixe+lM9kbhx1H&Ovxe+HGDR­k3מ?H&##xe+K^_ S`:#3nH&r UPxe+HǛ} 'I8η+a:.vp_16ɑL U?xe+|lK*ox?ɑL 1lx E4Zզ!vG#9Y /Hxe+HӡLmOZ7~۳ɑL Hxe+H+MlY2#4vK'G2) uxe+5+rOnT2xr$] e-x pRr!-)7.xeHwǫ8kKΔJlrH&axe+Hkl֟:R ɑL -xeqxk~wR3= +xe+"HQɑL Wxe+'1»m|jur$ʴ ,xeȗ5WL(].i= bN+xe+^{z+OX 3"7cr$ Wx E㰚rސ'LYSpY x EIbӷ%٠Y 4xe+HGBg~5.?tm~H&& baxepّ=bB ܬ4-ɤɾ ,xe!O_u!#+xe+GwJq+\wN:|eH&x ,x4E5pPPĉݱH1Yxeп{[/iPF]FC& +xe+Kǁ]I/>HHabzwr$ xe+zvESv\ uȪvA~ͮɑL =xe+ꄐNac9 ?9Iճ jx ES̴Iq-c# BY /xeȷ[;oO3qVFC&+xerFϤ7f縗dP[.1y7>R ,xe+Ⱦ5O߇4fdΪjזɑL ._Xxe+^n>j0x99I= )xe+ȥk;wu㏇-n#J1xe+uؗVI8v-DH&By^xe+HUyϒ ZO\09Iu  x E`-N0ĩY!*IY RD:xe+L9{~m9/YɑL Igxe+Vw|IRٴ ɑL _ xe+ Jm5v[%{NdR AAx E,;U'V}QY pxe+":VGYϑ͟;}r$ !xe+e%KxdT.\tar$P Jxe+HBcΏbmuX:م*79IW wx Esٰ=TjmY C &x E!|/ڷ-Y MUx EWq:_Ͷ`Y xe+ښO]w,{[,W[~r$ 1x Eԇ-1DQ]Y I`xe+"C9ˋzsSDɑL 8  xe+rvkv~[zt=yɑL n -x 'Yo郲ی$m/;>_t x+.t r t L*)/-N-*KB'9U$+$U;8E8:{;:CLpvqtuq tQ QJIM̳,UMS@q^>-} ]=i x8qB=`x+/,ۤ3Wwϵ=u 0x+/,r{sź;j-g(x+`81R 9^x˛%fs{ ` Kx˛%EЯ޹yDJl .x˛%m~C)Ջ]}6 _xkgjg`*%'⾲#k=BGxQ52Y0d]ߦ40000 tcs"+5M7#Ҭ(CSg6SqaGOdV/P'$xkgjgYzm[*J6_s~waZKN C7xkgjgY` "q-8 2xkgjg`*{ҕ!|NB̽b>s -+xkgjgYd!G/܄Xpswf8 RxkgjgY$EtY7Dכ=c RyxkgjgYcg95+'m  xkgjgYmmf] HxkgjgY$6g@>pM ypxkgjgYwkW_='/|$Z ^xkgjgYd ;r4w,ZiaNq) (xkgjgpEׁ38.s+`g yx2RxkgjgpEŚ=Yhg[}Ky yk *x 9OnҧMô%^ Vxkgjg0U->.*oy8 *xkgjgP$p/@Hlco3woc9ĶF{ *xkgjg,rc>M![d ӂBTxkgjg,2KO E.K7|6sb ~xkgjg,ې`*y~F?.ױ}ba p(xkgjg,$$Y-zYʫ<1} +xkgjg`*IOmlϵFLNI >7s Uxkgjg`*N?-|{MfD}xxkgjg`*"pƨ\qN9Ц3&z )xkgjg`*bļsGk'4slD}+xkgjg,bIkdrEibUx3S ($*}c}+sga&텧%kxkgjgY!s廫B&=oOt xa&텧7|x35򀿇rWRJMnI9$yY71_>KTx351<ܛ A7rI !nW:a lCxkgjgYΪw'\yWïjxkgjgYdl/[ڇJ Ox3SUk68qYhpҢ{/g:Qmx;Lz0ZSx3Sz Ƥ8)g:Qmx;LzZx3SEW5J]h k"f$g:Qmx;Lz DWx3Spd9>p#*g:Qmx;Lz~xkgjg,4ռ!FKrZq?H{DZ l!vϭ}D(@xkgjgYQ=S>/^>j[bk gx35VOwm/Nq7|^I.5Le⅝uBB: AxkgjgYg "7{N[J7,* hx4eƵQg=)xkgjgpEڅfWMc7Id"tmTxkgjg`*uaNcŁw*/l?ط'zD}͏~xkgjg`*?x]dHlWN (xkgjg`*YY#}>-r&=gD}D Sx5\ŗ&vM١kISl-xkgjg, }|1a;x7OL_q a*xkgjgY$ReSX֪: Qx3r@c5/%"f) yx35?KS4x`) U~;x35<9 -]4Im'-3'*>) #}x35Vс.ܭՒ"ޑIX2+\9m-yͭq AxĝhLӡQѬ*{.xkgjgY$ˆvhܹmbg~-| xkgjgYdLCݧ<'-P% էceF ulx:P&R]Qxe6{UJ  @ 7!J/ וLL٬$7x1D71;5-3'U/1(PmI ,SS <*͆*K,M`8Fަk+Ǟ:SRZ^TWz5J%n2% *9 1)3'sb<=vVeg#7'+al_긅s˦Y<=L9YmuR{=x{C-.Ȍ/-)Z4?Q+#kx,Ȕ H-x1CD71;5-3'U/1P"k>6QTN~^ú;Bޫaګ4Pvyȣ  \Do=ٓzƶpY_HU>A-.Ȍ/-)]䙷V=3pm|qZl6؃?<¶@ySP%)@alp;=_.L܍"(0ci>SW~;x1UxxO5` K@CON8\eқ).zKTkvViE0PSjwgujezڂwmYp&]7 *)fPxAb,O+x3o, 78>$hゥ||nZo[u1gxW[oH~_qԾdiiw>`)m,`4 Iݪ}vlTd̹|߹̙<0 (YS4+e^0֐U̫I` @ e^ɘ SuO%PKkrbv^%_,x!U<4qUrx 1?3< K!ԝD#9Ίy6Pa? ܊Bb7Kgc'l-JVJwM%_LR/痝qߢݷ8/[=k㞵TaVvƨܗT˕]\?`?K]1f3Vƒ2t5y[kP?áq6 K)IR+( ǵ)H*)0{wl9M)<0w8oJD X/X'ycMr.?JnT+6_qL`*dy\7( \xID*ՓA5AĵI"AX a1`IK㸒1HjH2ւ[VbZUr\'Ioh0R.0R\oM$ W*AJyNUMwy˧sI%:_P1߂rQ*H+RY-@囦o0.B[=W˚6ҝnz@Z]D68tȏ:f$rz-(i DWzhօDz~fexw7fx1r6lk;u[3ppL9Dܕt |jeLr :X|%aD<}O#?iTgFw<ʮ5v']= zM.hrӿ70O4s܌=1ϬI~i47f`G&?'c=x=q_qZ>:B}o9 {ȧhF5y?\p.:&>%D1v[:}ó'EHJREVgw~mع 'g2'AhjX#{EUO+Q}-..IMo3'N~Njm(*"V8hV 8 6}kU k:i$|}fid=1Dg~=~ծX|`v=vV[6nil>}Fov ,s E |.%b(Pc4sԟZZjA,ͱRw6^-Ǥ+[KP= ĝEK~wGWo+=#t︁{cC~ܴXlQxZ{o8,knbš=@Ĉ%w ˴F =|!)%Ly8rIu1 ]ۋ{K2aD4D'@(HBS"F#;lwZdo{"\F ( 9v?fWwdAɿxcnP ]cQ*iE'#i&ںxIzassc ^*8 zlIC `;paiD2񝈠LC  a}Gl6Hwۈ?l׳v݇.):o♗4 Újlh6\x2}Cw-$V'cSb81};@?F;k76h|la &ֵ25;ٝ7 b2d:q+]n6!G%k)Z@m:V Mm܇KD$]*D?^`/ء/l;x:deXLU58o>6k)ɴT: V)R,zIw\1U92qzM# q+pޒxqvH7ѱ IHCW`q¯g휟Bf 3,%lD|).+Sesshf'=ۭ)9\XG:,"KaK27ݒHRǔ; /&!YN}*I&BA?C; *KH˜ǜ%<+(3`l2dp&Y+3gNr_ivƬ=Xtv0??z)`x]XjHޟ{=!WZAT>]&etۧM \O1G2Lńַ@k0O/O5wfR G~@7jeh&z@.42-z8[ [hvYԾCԉNfc rwJs_w$i{TF?i`0OόKӳkp{pux4m#,%@>kdj7_cҭe*Ɗ9$gS/C3B n'M jh 3d ͬvο 8-ȁ'skkǝ8dۯ 2[x/KEzk'L_UtKNtkgjΦڴ#Ι%:ݻ] ,y!Sf `ZX 8- kGrŀ{ Walzփ^bypw<2qfµ `CFȷr@fi)) 0X !9%);>"mE4t!`'@AJv;6]t$κ9L.FW eo1"R6:(ZVd`tC֓X,Wʷr0Եcs0҇G%.$s`gtd[W޻oZ\)ey=D'FPؓ]@czl\99r Q-0`r&s l(r FpKaԈ)Qw;Mn|(#B{%ZWÀ5pXhқRe^d\) fV[49bOwX,:c׵zo*~^3ܡG, 1ʷ)8xHH7l D \,msPp P,{c"V Ÿ샙eK"Wob&Ls\ aC:v;XExG#q!jjN2mNd\(e#7R?O6Y%UK1ŭ89k8kRsSEy !/dܨ<19?$DV!?)+>=$.䭩`k,"D\T7LݪL˜ 5<4Ax[.h;_Rs23sJSRJ㓋* J73^fTw q sw OK+N-QU0\̼}:dg!`*NԼ4..ɎL*0rLne?9ÊQ43$(/1'9#599ȭ(63fLljGFdEf'U>JH\!nEE%Pu: Ō&yMsW''l*я'%=2|EiF:2核 EJfFQjqi(f-yQrZȝaŒU;&)lAI[b]S )#9nBf͍ʌ ZU|G*FpRVjr[~:jU- U{Fzu@׫O4\as=#7 /x{&hC:tIqq|rQeAI^rf^rNiJR~Rooe1yJLkyu\y-'\V2_T (#$f&lpx[2hC00k#x{t9hC#rf^rNiJR~RȲQzia:-x;qczm{xmk \(x y9r_^bp ߪWғ5Vx;qcC%ԏQNYVUGY4y+$ ,x ame\HL۾`ڷɶ7.x..鬸?4ʼnf2,mXx6*7 % ͒@ i.鬸?4ʼnf2CLDx`4;疏` XI2p100644 tcs_utils.hF'@%N;T(?{ 7yo:v1,$L_weKH!$NnxS4ag/nuӣY]5RH2nUH+0[gʓp40000 tss.鬸?4ʼnf2{)ax;qcC4ș-<Z4w`YL-x `s∶0O;(Az.x![j> 8~&B坑om]x6'100644 Makefile.amr_qvO}`d0uk'5i%.)Fu6Zp= mMV$tY/Az 邚 gٓIA;=QD1~sOH I7100644 spi_utils.h^a!_a4R'p6^#~gpP\oubq"l-HHNZɝFB%kA>)32b}<͸W+ӎ40000 tss.鬸?4ʼnf2тsx 4B_Kՠ:Sŝ"H"/x!ծ:wgꢖBS.} 7#xWmo6l  p$%KQ;"h7 ,6QY(7N$r 4xw繣-Ȑ4Jh@FyaB^+(kȠ;=TxaJ4ICqj4ǽ ^ @hPTɼ0;q׵ZFctΏͦhN@6P cZrF|<׃HShp ̗]E&LBXAV2kͮf N`iW^P/ 9w@G#s~p|/R@G7IK&\TWNp#<dl&y#!op{7 uēсv&cœpDDd_>4z~҃2$ 6"z^xQҪ-Y[Uetu(_2T:1>q23,V%c9uBN H;Zg-rvFuP4^B] pZdW&^C HYj664ɱ[\NA\y ;ѹjs4^]|m4b⟪)_1<#Pݴ89tsaw SNem;8w#k4Ƿ E22֖tZw* !7 =FlYA|xh lrlA8vA>== 򤿝y2=7dY2{r^~tבTT F{:u: Gd@dn$_P^AX!{lOKHT\ ؜&*;W6)JէդDVPp7ѥ_K wQvY^7e~Szq)HvX3:VՋd;꯹}0Qz Uٓ]NKy|miGKYSsb+bw"is%JU'O"U]KheQvQI=ƻW3gw[%s.IKe1T_&+{{=5\*۵( {L^- tU1l x|~;~S1VC,6v>4٬Ye}ok if'5:exc|x-vnh&H#xc|x-ְe(qmh) &x@82P(_cpƒ100644 tcspbg.cʃ g*x  F>xaaw,$h.x{ymFc:Mfj,[AϪd Vx{ymF~'޲XqgIr ~x{ymF*muwGO:c/ x&x5Sl=O⼹QkQœzE\+'CeMߖՓa,Dx *ꦅR&/{C*x a3\,%UÓ$ ;U.x{ya'v~Y\qWE%3Yx77tB 5$wvA! *MQW,QĭSxx77tB 5$wvA! *P߀<~jCdxO\j+:8a1=pS7tB 5$wvA! * XѶG["''^x ˘O) ԧPX$ 7“!.x{yBH%»t*}/spcA=#+x{ymFK0oݹ ??&)9IBpE+z+ 'y.$BII2o.E{6<&;;\B X8A;@<h!B/OWcUCu^Axgo/ e^O2lqȲǼ L]pd{q^tlri`^.\_c0뜮 wznCx>:t5{nhl,\aBtzݼ2*~zl ]r.iԙB(!aTߴԫˠK`|1]oc6^R_/ :`N{c۸b~09].,%ǰ?=H}NcP+@s FSmGi 50qi 2 ˾ahx/ B:;qm6Šҵleܓ44.1,`1еbd:,`*<ԎpyNz+y1Q]VZ*(XأQM\UUyf, rYFPJd֣<S!_n0-bi',~B%IiolQ2=r;tǙ (3̆Ньfἀy9[)eɇ49}Ւ܋J%bRIwK9Zlma0 [[2"1"!s{|%F/0zBbv{txT摘xۻ + 8@ܷuf|)j[dbi7:R6$Hi8mk4X~/.zC&q>ķķ0xc-(]GKC{[J]BwqS֟`;UTj85(GV#>e9PE\2v~C" >|Ba(o.& ʨdz_lסR'OivvHKy)_N0NV0yU3Rz=Igd&ggvmLT{ɻVfyn|)4-ݱSo?5X"ۙ$1d,mQ&84@Bl(O5ˋcB1fآj0óhu̳3Tt-c?(5`x!A|@YAA${E^*zu5<^ǝہpo![7}6*JEqJ+eWjPqx>rį xo!qp|zS `S#].&|cHo!Qw1tI8є;HdiD=N~$C 9VJLނ"̣LKxptXqJOJ_*ZQ,)'/ҍ)"9t¸BdRh`b!RFzK רzڨkST5` `K1##b{}-hLBXͫޛmQ%ZhMej!:_ps͒޾lio'Խu5Oi^{E>'ܛQQ->XʂCO}Zu\ƗW?.-__AsmrnImԟ.d~m|a]_fxJq WReIjq|Qjbd76MFl*s*j*TOfe/cM*^ Dx[[a7d9F ^1g_x[Ua7d9F y 2J4RK*K>|qL63xp@a8#cfYF7Bk&Zw E`[|`:6~Ex mSo;>>E:ƳR&vx91#VH٥Cz ZomSo;>>E:ƳR&YJx;~}C"H<Iw|/8/ks)S#-x;~}_]ĹETl5}Ͼݶ>LX -x!{@O !XH /x! Wzuȵ9$  K/x;~}BH j+KOѐ_F~F:fْ C"x9;P7zLǔ(m|/qO`տM4/^|wMS@($( y<jx9;P7zLǔ(m|/qO` }->!FSq;O~ }Hx;~}dfMF7"돛O~.aj \tx;~}df_>5$V5qʪoqfrf5,x;~}CȲ棻g[) WY ̾< vXx9Sd*Pxï6P2ƓŻΫ'ZbyŗRE ^M)Gx;~}C"HĄ]&̎qY 'hfs)S# G-x;~}!{l'QZ>FS%hW@kߙ+x;~}Nf#t24fHVUe KSx6{mFwe]xŠ 'vīn10x+c%%~<pDx;~}C"ȟmӟv`,ePE~ͥLb -x;~}Cȼ-5_xzE8qxǓ},x9}>Zˣ(b gD^؈(U' Gx  ̟[- "܍>ۙ .x;~}C"^WYDbH{&pql.e`Ս T[x:aJS]P4_I` ^0ru:HW_I賛2$Hx;~}Nf#K\_rk-G {(x;~}JF=+k0J|^c&W{Ux8!Ũ#,Y^|'}SPa|4WJp+⳽4FxNŶMO3Sqa ^uhenݳ'ZROmuh@Şj?$\x!nb9a:'O5 x:nb9a:'O5"_b(q﫳 }Ix;~}C"x_>sa]zUͥL #x8qB99娝dReF :-x8q|ǿ?4+4Jh -xp40IdSӆͮ@cH_3EVFւGKK40000 dist[mX p3څ=&kdt4LaRˈ_VY I7~xe1FE;Toj+Y;[,xe:II;ff(h߻QLv Xxe:íVHg]Lv ,xe+ȩ,nf7TEnɑL RXxe+W_ %2| YxɑL ( ,xeH/gX]dL+xe+)'/1^Fr1>#\ ,xeHCgUH㭩76X3xAFC&> +xe+@#^D'_.ϙJų2iOdRnj Wxe+ŗ>>Vt̺_MߑɑL ,xeQ,KABexۧS#ӏa^ +xe+!N/ѝ!6J]89I UWxe+7ۍ{ROKɑL xe+H%~宥6K;H&& !0x E>\ tF%%Y ^r_x ET[#H^\ݿEK͓Y xe+w7^|nTQ+{BԫɑL ;xe+O`ݥ6|ɓ#Dhxe+ȳy>upho ˦᭓#xe+HOț)wFcA[H&-Bx E[Mz "7SY ^qxe+-"6o ɑL xe+嗧A+68~XɑL cKxe+rﷀt{(/"dH&C txxe+w32^$RɑL t .%xe+HKj;492OdR -x a Yj?wϺݓ\1.xe1iQ']%U4/a- Yxe9~6ɫJC6#c! +xe+"J8]k[=~#/9Wx E7I U6 Y .xeHyO~jr$P 7xe+ڧV[;V\1ɑL )Hdxe+' ng䮑j/̛eɑL G:xe+ȷRi\Chk ٓ#-xeC*f/NGw/}:+u|Ux44""6!$q|`HJAA Wю6*x44:ٜ bK`HJAA Wю6Եn Cx$,ۮC0ukA5=2x4PDZHx_x44dVz,4^M7HV ֹJ$&fufox;re5?[Tggߥb󵢪. x;re5H^˻5y]gIq @x;re5arSNeHH^ ix;re5HGx^饲Zs Gex;re5HD?rj7f nXX ~)x;re4Ȫy?\a}KvFi ,x;rew Y<}Ly S+x;re4QAany˅&3) Wx;re4HK=vNUs>bL x;re4ȩ4sT=#J%ۜ]V2e>Ѯ a0x;re4Ok;MB ]x ɄHkԁ19Ǔ/  x;re4;xqr9S6E( 9YI 9x;re4y50ymR<|d}&ь fx $,ٴAZ/ _x;re4HF⡴Ug&Vo ~[QaLgݹ,x;reFr+g5z `,x4%ԒN ^^sF1Hw-x }uյV$@=/pmܭ:.x;re_FOKnx;re_F_SeJy^=rѓ -x;reES,L>*ǵу +x;re4uBj{V{]w% a]rl .x;rei[V>}I\NEL+x  i/삕t(곊/ qxU }bJǁ6vADO _D|,ǩ# %{ 4{TKEc<`1 R#|xkgjgY$s{ӏzWO-ˑiXf s&xkgjgYd=Z0ܻ{Q,URq T PxkgjgYd[}M)~wva [zxkgjgY&-T1R\k_. #$xkgjgYdECL[N6/YQNmwNxFwB1еȫvzxkgjgYD5iv׺* $xkgjgYkbC9rn~zdo aNx3 1O rST\J _lXl"=N4Mn:fx3!J _lXl"=N4Mn iDxkgjgP$rwpp fnT *xSƕQ"xͷ(g޷Vxkgjg,Rh+~l;rS~Ʋ ܷxkgjg,r(+68ϊ^j}O+xkgjg,X{zk2?lVxkgjg,zOM>x4gb) +xkgjgP$Rpc}};¾ L*xkgjg,_䲿I9~]]&/ D*xkgjg`*T鴪Ku6}gD}ϒ *xkgjg,tR3kԵ7991} Txkgjg,R;p|ǀ`psl b~xkgjg,brn F>|Q<f(xkgjg,bTe??K_Nt _ 7+xkgjgP$R~qY}7f[:6'ǛMlk˅ [UxkgjgP$rq J&|l aZ9 *x3S1=4?wg2~vM&t~HaAxkgjg0U`xG'\55Ԝ62 *xkgjg,N GB%Oj=1} ?Tx3S<֜v՞Օo"gϡ;66_}^odT 8x3SB*`>$}NTgϡ;66_}^odT6Wx3Sģ|̅: Ȅ}!Oy6iQxkgjgY$ aWAofSNxxkgjgY䶱vmm{IV xkgjgYǾj{k6kߴ< _Gx35-e:doZۣWlIPI&?}ZZ65waj$BxkgjgYgV蹇ڳP ixkgjgYd[|e5M/wxev_ xkgjgYDWc mE?&.* k8xkgjgYZ薶W~W6ob `xkgjgY$ꣿlOR݈\5I xkgjgYVFw'F~ҽ'# L0x3~U_˰Є铧U[ oJ{*G2xN+gBxkgjgY$((8yl4{޺/ mixkgjg,י'NB1xʥ%!{DW*F-}=V?xkgjgYʇM,rEuz C /fxkgjgYDsΤn7׉oQR  xkgjgY$CԘJxkgjg,2aQ nO-x;re4ʉG 2|3YIÝ '\x;re4]o/ڼ8_~c:YIE 4 x;re4HVB[- v,x;re~[vݮwqq =ؙk&+x M^uׁpk{5F/ Yx;re4Hvq[:ZWƶuVd}& 7x;re4oY+}&4My"~d}&t 2x;re4SnxUoܗD^d}&Ѹ -x;re5ȧoFN;lw{er2ԫJg) Ux;re5Ʋs%{־M޻uU r(x;reC-N+Y-N%M;r䉌Ng,x;ϲe> h=x~Tʤ٢#Iʱ-x[ϲe4/ %uu:WM0 Ux44`#]B$b6VePU2%HqZCZ՝' |j.WxBx[ϲe4HgQ09&+> jx[ϲe4>Cɦ3-iY x[ϲe4V-?3^p)vQӓ# )x74ryI_E-GsH\0 ,-Eα4h%Ex[ϲeH^ˋ%gxbn!+&tsFѪ +x[ϲe4HeA <c Sx[ϲe4ȩ_wWHѩ.x: {x[ϲe4HWW_ NP] #x[ϲe4۷5Clr tLx[ϲe4HC)K_7/|i# Hux"SHeƘCU# < x[ϲe4ȗ}?>.q fu Ix[ϲe4HӃd! _rx[ϲe4Hv YDH$o"xZxQ x[ϲe4f՞f^FfΎKJ>B Dx[ϲe4Swary/i*k >mx44}57Y{đ v(z2HCcVAnAu¹)6Fo 0x44'-~٠0ZHBA7P*U8yT[LVsx44 6 %5<;H4e8Ct m]#2Z96x44HX Yk%1A]yHV;1@_$3>zӷ+yx44 (D`n=8!M0^HZ)XzZ[*) uKx[ϲe4%Zx[ϲe4H؆?OcsblJv *@x[ϲe4Y'}_ն?zq &x[ϲe4ț^-:6n>5  x[ϲe4?=9[?']ʭ} Brx[ϲe4SyB'a{ l <[v䉌 ,x[ϲesD'1Jc+toF +xX% j;՜%_Ux[ϲe4tP+{l[>~GwD2q }x[ϲe4g#yΌRMYxUY %x[ϲe46G}3UĻ Nx[ϲe4Ȋ+#?͈ +u3 3wxr齵cf˴"V "xGjENλMx44tDgEXXf։tvHGjENUvx44(g@~*|߷sHGjENι5Cx U +vV̞͡āΓiG.x }f^F\ڑ5Xn+.x\0 ,-Eα4N-x84xi -6H5{r]^E} ٙGw͵Fx4;rpOk@Z]H0.sx44u^LF=C*b.࿥Hl[r6}SMI"mox[ϲe4ȟ_9E_q&{ȳY^ jx }G|/.铑 .x[ϲe4Hq{L~-Fk (x:.oDU8Ul4-x[ϲe@#&Ή/(cz͕ Xx44N> Bry?H cK&^ks:33YB2mx[ϲe4wZ\ϊ_n26t7} 2jx }Zx[ϲe4ȓC]i X x[ϲe4ȴ6ߪ[\d~ jHx[ϲe4ȄNm$E9>~6K<" J.x[ϲe4W&ZNl ɹp HWx[ϲe4ȞkFW~Z#], x[ϲe4S{~iwhzpaKA^$ f)x[ϲe4[9[{^CMHOLx[ϲe4ȯ)OǼ]S <$ 2x[ϲe4%NO匫~Ծ\TS n[x[ϲe4kCs\r\Ur Ax[ϲe4HoƝ}̊x:Kl' jx[ϲe4Ĝ׋֚zs.p9-̻W Px[ϲe4XC2Kp.m2Q yx[ϲe4ȽKsU;2ru/2%^) "x[ϲe4qtnY'-y⟣ !Kx[ϲe4.1wsO*s?y͑MC tx[ϲe4c@Q9/ݻ\]u= kx[ϲe4۪_{J.t - ~ J)x .˹{&,̓ =.x[ϲe7UE,~Yգ+x[ϲeC-[>_{j3y"<2 ,x4ɨ̳k!ic!ӗHCZYx44 uܠL(&(nvՉHtfaRܴ:jSyx444c9&H 4COLHr.}?uqJ|^x34ʫo`GT]4GYSjb&?c)|rz x44}ބ4K'dK3HBl5!ⱋ0#[)~k{cxL4#X#lS.| .ŵwqHoFC-*B0l]wg仹 peʔb%#x[ϲe4;?{gorw(mO ;xrů3%Ե{ޕ@;fx[ϲe4XF@AnT][wT&' xtfaRܴ:jS x[ϲe4HѦ~Wg<"ž}N! tx[ϲe4L{m-W3E& 6x[ϲe4+><͠Sr Fx[ϲe4o"Զc:4M! C,x[ϲe4k^ ;e{>S#'n Ux[ϲe4ȅhV;ʯXn{.X f~x[ϲe4GA)?NJMd,8R 'x[ϲe4ȬN96v5P> ZX.k x[ϲe4H\rp.]T-}~ m7x[ϲe4:'LztB*"s; `x[ϲe4JF)-Wm l  x[ϲe4Hy'wr<=:)I ox[ϲe4ʫj5Wd~9_ x,-:=p Cx[ϲe4*ӷh7R纻eIlx[ϲe41fk܉lWqI x[ϲe4IMY|u[lxaQ >xL4rIL. <-f`Hxx5kνuW"L  DbxF1P;#$[xCВIS۱󰊮NjԲOx[ϲe4Hg =ޏ?[=sy .x5QxÈ0Ò^~Hk4kwR&)LMR`Dx[ϲe{R"FEC.ŸpkUoxŠ Gox44\EY64;RH\BHEf@( |1x44 ~hzNIp[THW&0;F|̒uAcK0x[ϲe4OyLk}p% ?Yx[ϲe4IOw -`h! Wx[ϲe4igp]~l̮3_ x[ϲe4dN{^1^;'[#7 )xW&0;F|̒uAi x L7/ ˦H rړ/x[ϲeuݮIl]'ql9# +x[ϲe4ꚯNn0JJ=ߧc Sx5 m 4=X.ӾUQ 3k󽪰Y͐[l mdE; NCxQJ3MJߒOҭy"4O-x[ϲe{\ȪYV6hӾ +x[ϲeC-HbNՐb [Hq䉌p +,x[ϲe4\ 󓗮-˴ dސ W Tx[ϲe4Hܿ<>Sp?fY# ?|x[ϲe4HCꡍ'r#v&n $x[ϲe4WsBR?ݞ;ܽcɒ1 UMx[ϲe4vrO:|kZ%F ,x3:Yw$}:yN6F47ntvRNt[DxZtṔS k )mx8qB>^Gv+yjΰ_ x ur VU(.JVMSH,.R3xkgjg,RJm^SMNΖRx;#gR# c`xkgjg,"U((gnYly BMVML_  x3SIEMl@H`لw g798k 7|6Le rAQx3S9%Ǎu Fh!a8gi{DMZQwy9>~5xkgjgY$^MLgҟ/o+;W ]xkgjgYoZM u 5xkgjgYlimX'3!UUa] -xkgjgYd:ӻB/Nќ: dxkgjgpE|V%i>Osډ/}+xkgjgYL}M}5,T&9 RxkgjgY$)G_Yμ;lyxkgjgY$ͨU`rKIP#W}  xQ526Nc7&nC[_a40000 tcs֩G3+짗gf2yKU2:m- "' x+).K)MIM,RUP@p5KJJ=\]\ꀂ Y + 1 &P\ZQ_TPR&RYZbXQ~iqj@iix[8q\&..XxSMo0 W5Kv)q&C f2ݨq%CRߏ|8Nf=Q$ |Kb C#7x4@JESF !*Ґ4`Xu1qxxFEڠva]NZtvK7ⴡm>|EtZMW^rJF=z.-zj=ht9 n[sfW{t:\d-nOkjk]\Cʌ^slWxȵes#Tnx:xcRVjrV>,.QU 16RK(HKIT8@5Wswj%D9?$13/HA+=.ꛘ̥PP_?ĔҒԊCrOj rut q tr BלZINK Sɥl^xsC,.Y\ʩy)i\R)xZ[s:~BUBdIeˀ؅MΤ\le'aofX2ÌݺP GpkΑ N-h%8'8F"B$#wx=)FN;E8٦rA""? _nN}4./VCx<xSw0t;eg`1d`3`.Z)<#Ij,̓ =⭷/p뿭x?&h_a`e$)G Z%?PnG2tGy߉'GzAl`@$(k LkHOV_%3e$[#5 mlvm}Cmx;ϧzoN5F7_fs[p4 xHS>&larAӁ`dcn,w8*~Ѷ{0Z`\J:`ϐ9lQ&3(anq6؈78 pT/WժKvزqF>u > B 4%)8..5D!qW!c:1 m9?`$64g֣qi\[Mn*)pZ@ǀfF)^z~?֚Y،+;C- [wP2܀N &t+.ƪhaЍo5nt:r9qNze,ARHu!my(D֚vbhZ'k?flGsŅ"|R?*R`M &FxpЃ$lk8cdC=k`zhU?\֠gL;:jp9a/kYNupJӞvf.x0{ؒ`e/VЕ,8I'Q@}0W? %7if?.U.՚O8~+,CT ]-4YZn?b9u&`a (Qg3Gh(CLq&?ŨNchD2ԏC-%0G.|bThaF/}G/?/`-q6_ބh=nF7SvޤoՖ$<-g0Yh FӁ72~yٛ縓[]:۲LY~H oVY^JVݨ~@IђWge0K'q{r}yyy"8 x <0 (N1]KYӱ{DUdv&?}Na^'AY/E=BP2_waG-)#W * ~>wV܎ea~7T "YyBV Q^+wtc5 K\֢e%eyx`ApZ`X]6XE[tI|ݱӟ\\fգt»;W[2LX?b zVrAsfI0+EOj aԞ:ͩ.FG/*jt~II> UY]R5JocoUlDFM<ǕҧP.xbÚAvԔo9Y5nʜqL5籣E0*-E@Xeiu•KF4Z끏Ϛ0bBKojw|?| {h ` C: m)bc(95;zw:U~n-]%1:Vtv~檰ICo6v/88Q)?}Q)}R(BE[$c H+mʴz^MaT|ҍ%>ך":n&KHjR0DH Wcy Z@ȐVa$J%;4=iMV  bfhRV;: \7~E={=r!Tzdq>}|8_άW@t$~>{Fy'JEnc\VplmV]b+yx<>PFpz<}*i.yj FY6Sٽ2Ū+hFAM20vְC{mʒH9Bb) Fn$F4=myEc7H9fWI%v>{@PJsMyo]K1hjJucP3a.S))`}ugFۉA(-{ d/hnOݓu6NㄾROkl=~Ћ8x\z+>зċVB "x8곡i& Fxg׈7: e) Zt +Ȫ:95(0ـM;ҩ,19|"B(Ɔz)h(8E-ؠ"9Z} {/(x8XVo^#if 0^Lgh#endifwoxX>f E<@< xX>f E#tXB`zECu .5u"<2{4K|Hg«m]9hPt`D=c f@B~]mxߪO'sRqbζ*xkgjgP$Q8'xmEs? ^K&5[ x]D71;5-3'U/1P"k>QQvyȣ  \Do=ٓzƶpY_HU>A ..Ȍ/-)`Ȯ^}NKڞg86O>8-v-ͷ+>uKhа_\vvQ9sZO´H*ˋ ?&8uw9SO=LmQAr Ha +_q]zӖ!059@5-)RɮwnYBMG'ޝթi qeýtM hOmzl$&}%7.M(O.,(3ѹu>X<";~4jx}C4Ȃ[՚sGsp.bl<ź9d 2x}C4ȻLmq$t^o9 %.x]D71;5-3'U/1(PmI ,SS <*ި(٠q [Mx{~s'9@s능{|4\\_ZS4?Q+#k (f0mId)G"-$x!W(a6WзU0x}}f*oOn:yO WXx}}f+Uf\x72x}}f9-}s=\AeP+)x}C4*Χ?v Yu|F -xT}{FiLT@i02%o,}Sń-40000 tss/]9M Gw $;N)&Ebx!#.w#ӊVܳ<x~]D71;5-3'U/1P"k>6QTN~^ú;Bޫaګ4qHvwg^Zm4?Q~QiK,c\~ INA-I.NvvQ9sZO´H*ˋ ?&8uw9d}fu=|bo\}̌'o'2vM[LĬk6DYOVgX/8>$hゥ||nZo[u1ɎXpx}FFn^I)==]?wN|Q ӌ Sx:lV)#Y\# PE|08s7nl# :Pkb ZC8x;~]D71;5-3'U/1(PmI ,SS <*͞d29aO5#:`3i:dh\pmZPf5PKS2,^/6ϓӧÀ Tė% :fqf?cR6EoN|IW*'?(a<]A;M2:ٯ?0L~(iC/A_sÌ/*H.}ɡYϮ,srg>yԱAvU4vʬ+;磥r/?+~p<z'`rx::WH~3_Q}jߝ]Y fo X[B>%x! >ݒSSq1p00x!}V=UA㖼Ж< /x!1kcȖLeES-/x9[if]c sBpR%oU`yr>gTheGx;~}NfG#v ]oxɎzܛ~*x;~}CzKTkvViE04ѡ 3,x2|A嶲þ\SΣgVxE'100644 Makefile.amp½U6d2ok,F'2|A嶲þ\SӔ"`Sx;~}FF$ϼڨi~hs棌Lv-x;~}C4Ȟ[o zW|.Ь%a=cs>S# sx;~}CH /l M}dn.,& .x;~})=^Jۢ'pf4ܲkzfOV&ٞ -x;~}$fG_awl(O([v2f 3 ,x:V( r4\?:jh{n8MÉ+,'RHx!s/R 돋zPÆF_./x;~} CB-f5?T(tqͪ+>g-x!˿UdTfjfo{)Z)'sRA$qM\LC$ @ũ0ɘ_7|qx`(ap |+aNp',)p>/9_!Fazy$x4&C0Fe98$NrwwCGVjd{ȴ~~qÇQDU{v=63/[?Kír5G牿=xX.g#o 2 fi?IMC a_`T yX%>{B+> 8^;>sN0c.% W{~&bJ9U霄8#R[j9DzDap b0<#hNZf1u#/P 2C4"Y3K>T0%_i8*RAB=k "Hã[v"`|D4EQ®.H v5k@M.^@/% E'(S賬S&_R@\HO5Svu1jUT{MQi6=8J8|ڻ9_#!/2G{9<",$q(3[)d/̓aa4e:T9ѩ Lߩ,pFan=7D0u㕠je#)7Uzqh:IQҔ/輺o%G,k||b6?ǀI*~Rz3$t P \Z2-n6-3tpYH8D((ϰe &Rݖ- :X ̼E'L9 ,4ֺUP+$'0ga5c`–ve!ܥ{S 8zO[bӑX妚2CI ֌}eDzD],hm4Mxn![WBh" qpHmy%OK+x ΑPQPtIx,H&c}åTc6<iߋDLJnKYB[z\qlҹ{tHx42#%Ryۧꏊnp7kxߘj۝&09rHm~iٶw2g=!ju_JdL "nAξW-킈Ϟ() 4ޣo]R+Ϭv2^KIlQڰb=m)0m ŭ d*Mz:Kӳ0aނ_Ez+ݵNd|79I歋7̐o$wNɡ h!0Ւ0CcOKe |cB )r&|F0!7+R81_=Wѿmz | %@^)߱ԟQLđj;a~jjA1#=󤄮}#ndFƑ5DVk'ݭl^f63sގ׵, AOVW{]m*mxԨ}(+mZjlAimJ oz Y 8Xx i>k' np)VrIw촥?ǛR1T5O_c0=,t5g{u(£Yb%b,!JoP{fV*9/;"a Y`%e=?L2oo. ^'sḛzYNG J4.UԿ@aZa/16w=)n8Vm֡~G$PO;=0@"J"= (i$UJ bxH3 %a|N0I[o8 Sڭ L ϭZǖx>WĆd`Uko:<0OFw廠NGn`m_/d0KˬLA1 ׎:Zԣ(kك;7o YE0KNuaA v{,YG:}w(l$x{YvJD5-x[msH38L+Y@*R F,qp=3zAUkgLOOL>"m\?rdn9# n`GԻ!i @ P$ N%|Oh8Khl kOz/>L;΁ܝ"wf7 h0sWW{;M TK1%swꇌŒ axstj?IN-YXI".p[owjQj[Ԑ,TlCT~+w=9`Fa?㛩OԦ/˘$u"A輸 TYZCţ6(2NHA=WnW3st‚E\*&F6O׵tL=IyQIy"5LԼR"7&oĎ`벽;P]{]-W ƝUV@!XSH]! KV+5q \e8s뽸QLޜP9Q//:;ְYy |׏crL^e/:M`YD}i^# hڌ!0ggqeWXuYVaK}0`TeA7jrO@(KfwZ MRy8ihȀ-r"cZ]< ω 3Ȏ&,L9 J}zlT󻜞u%-i3$%'쁱6nu *eIY6> ]sbhu1'c<=&RV 85l9|-wv|ێlp-t2oY\cQ۔^S&`!3&.Yv`cQvZׄ#6؉OQái,%Y+ %jh?-B5?Ś馬Txc'i!ѸP%J;.nt7KHGR+Uqcw:i~40I]€Z;uÇw<-$\Ey*(T (-e)-{PBL^ӳRpGQ/bɋ˰~u|{$(JIKATYj,Y7Ԍofcђe˳Նܺd%޺&fkk{ SK]*i*-X)ᅧ(߰TL|wj]H1P>$M +TSH T0PyiNR<TΙDՍstߩ0ի#Q,nN{=eHʷmKbTKa† (55AQ9Ȋ3&y@%HOӷF9q-̮F Zʅ\Wf8ir P嘈,JyT9{T祷ef\\im:5>tNVQsʦ7S;j!FF=ɥd<*M8}~ f18![:-Or a)WPduM2z$ޓ6>NNډOMw=`>OrUx"#-YPQRgC2<#B2q_2k ֧H(c v ┹G u2>]J@58ъMҔ4}&,`9fvTS{7Xxcک* VDc~GI*Ow̿T ӏT)f:2zGqe"j{zir~\WAěoH 9]uV3V>OƕT1$p R7d ; @k/ ~?|q8_#xS?GE Kq).^{{ؤ!0 Y(A<~Kk#TMVJ1;hgplxx{+s x6m'+x{y8s xN 48xB}'눊8s\$t D  4J{(m< "뵛xZs~&35'}P@` 0u㴹]6p㇎v_|tҽlE=]EnhQݽAb{ӂP"CzlOu}(I~K>u{{)E6O7atW g j?|M$Cxn#d\e ŗOzHTm6zx3B*{VzACI/ؾn/JHhhj_1nNTmڮϟTJ_vl|6>J 5idaۘMkA5w(QDړ? 5E"M Qq}` QbE?:n6^Da%KЍ.v$`ؽC.sAX@*8IxxtH'4iC !u[!B 1Jx,|Q%5 \4-XiĐ.T UcthG}p1`~@Bdc1Mŀ,Aby `1jXL}1h&",pY* H1P)> )x'f)?.X $EG#ÐUIblXR``oc `1F.Ce*NUj(@eP dx ڟ.V 9y:C1V~bOWþzAT-g x/C.=]Wbw*UENXQzGVѳbπA!얢m%I\Xb$#T6( QJ1| z#"{kL-#NR|4ϱ㢀 WpxbHфE@KFEM5%hUd䰋NxXp/oX{${*Jw%)cqI=w玘C .{ժjֹpFdJK!L_}aJWa/{ql+XՂZkϜhKTi\2,"ȐDcP>2)v+!ʀ*y+Ig{r *4eUѴ$uV6eM7\.5HɊ"+Q@6^-o(grHwAmm@PvR?<| eUYK-ʌyY^[-ErngZ>W#y[d;u[g8rȞ%*L5:ˠbf6lNL`C\K~ &:CH^*G@9KK 2$J Wr&Ҹ t}99lؙ+T^BQ`HfH29 1ÆQ$6dEДUdۆ¯Sz-VڟȵS՟ഝo&+_X隵9 o/r,:VS޵h%K~V~Vn˔q54]3 Ɨ_$˪9a$nOhlft~О5qasj +kr<<Zu;~s)} U+/dsafUMꁞQ V4AAd9idnbcGgLLZ` DttZ$)dzLA umݥ\>6(H3C٘IF7Ru/` +Zd14%T[.A}xLyUYpI"NuC %=I2Z$@ @ ZJbQ/P{ 3tYuj@t)f;]Z9*\<"uggܔw{|P1 q[zxe-4CkZ$u\pMeȻGK„۬6xhJiu0 N'~V| v v+?ƈDq#l'-8zF^(ᘻCAXO\Mg.DK/@з!le',ZOQf)w@\:c.${)EoȢV?ggSv$p|Vɐ QDScX 2Ko-{;qYAbŋ" YMSbVSW -otJ(;*;| U.%T<mWR;Tk>I7Sx rHz;-zBzcHڵ])VDI]ie?ю[+bQ0Tq򋨾+p"M &'Z-DLm3pz&MaTa5(@8O,tbG;ݎpM>g\z֑NCۓ-!x'pCEb4Bbx[o8l]iX@DΒ %F|ĻfH^vSpf8/YQӘр1rNfiiv ɚ7cC,MrFS$0b1aI-qu⥔8?I'f?f;%b/ ؋M˜2+[Pw` q@d3c>,gycR_'aO'w@%X$/$)NR*;ɶ^F^>=iaJV\yy&6ċ%FHVAyI' "5dY~wzCT5Dߨ0|cnb@\*8{S3;Rah{l\}<ʀp( BP۷.JN0{tl-gyVat$3snO4 JxIJ7P>EVV>ɪ9 0߉@xy<5AC#g ] /۞bf7N.Lc?=E@.Ϊzu..u#/^2Q@<&$w6~WbrّVpZ*)ՠ6 7y6瞓)МcnOPK!@  =ETͳXJYb+bCg2VbAQ "plNcض%v J13n1N]PgԤ@Ā7LpL\e4Hgs"NMƪ9Epށ8 l;CtNHMT1rOEF{0F سԱag1#B򴇧!:!%JH]~NrG#Ixmng0R)ifN:Z!^dmwXzچ[SU5՜ҝAZ`P:aW0gBbi}׌s,ܱ;$-p¸>ż\I`{K|B]d\huO [ƥ 6'nYw5ˑ-:[$ h0+9ʄm&☷/lLS}12P}F7y'+TbiҷOIŽQw,1t^(t uZqpENft$eq&u4yiA`Ssgp)`48)ݓ4c/2 p"/SDMu4 6AȰSȟ/ۆb pl LP A Ӡ*c&>b‹یb|=‹f)eti(h~bi}u?[6>aYXiLPu%pmͪ-P7M~it^/(de0W.9hj 14Ss:NN_9MZf$pTjUDG[,$bRP`L_DKl5+\EE U"UZBv%I]=Q :ޡYAһ"[ ,OcU+j[T]ּ\Lh n;8V֔MPX 2҃h Cegu'Ds2LW2l4ُ.ZK*Kb)ݳT*Wi9P򏢰'rځ˝09y2BaLp H0E+5QB?`KWEt$ APT?ǖ;JX? {)F ,:hn >flW6{8~(N6CrPIGuWҢ> ZH|'Gy7 `JZ< f|c5i~/F5nD!K|^ hi4st_)X WJM@WU"\=Id:kCD[4&-[dVi@l\Fk5[m1P`5彑Pψƥ_o=iC*XOb]MWCB,KUQVyӛBӢ|U" L rQ=(QD1ήZsY;ei&IN 4g.ðC e Ε[N9׮ };oq@%o+g֞WPl:,Bp՝k|p Ƅp KUQ0BᩫiΉ 3zsoO-l- Ϋj_=>rKiRe1hw FQXk:ju%51eMR>\v)T;Ȭܛ뛍}X;7a۩_6ydS~S]+Zweϟ`_>ǝ8 CwF-2r[(J§]mu;aa-H8 / 5yF{r/oZז> ЬWGt.ܨUZ,_)ruM {lx3 S"]Eީzjn{ _+ 3jnextyx3:u(D`D !e_ac>%Q?;}ͥ fU~OށsxzG\)667tMaaIOmzcI3U ;sL k35U\>12 ޾dޓ:oe=d'KR`;JBUAulZAslx.m'V Դ̼T_LjpGNC Y6/⸥qH7x{6uW*b,RF\Sx{&uW*bHmfmF9 x\s:&fқI7wNL` I'+ _ @r|0fFDُÌ2H_n=guaN6^y7o4[8 <|,Q=?,y[a_D"!_{"'ȏ2>_/2z`>PGM1:T <8 )v x̃3vrkρ-@1egl#E_pj|صQ·/.Q]CZT(S"_FT9sfogk?a;³[P!YK%)r }O'; QAvL(I]'L49 #gi@5uLW"=62##xRv$1KxNm j$ErplxTښ ()lk偒FkQUqA,бd"mRV~]/ C|3iZ%{FSՍgL~pwGͤh@w 3=4"d]&Hˍ3_(> #bo4A R ^`&xHv-h*sU`%ܩܙV` 8\[TObNjT,_q]9L):ٕB_0Z\)C*_uxzJDq 9цpEje7*:\vHamwJ[nIMGB|jK2:*}s|ͩzd-E(lzEAüt<]!h -vkeD8z*l'ܑ/G::Je&:P0n0CjŦ,JS\(yu m'4/" /v,0Rμ7`,Eٝ\02XC΄8G JFÎ͐#4LYjՊ-(F0z&y%`it@R'!i9{!iq%nl{YVRL.ƝV+^S]3?WŽ,۟-#t,'^ =(&vzIẐ9g$;ḱv \FAwq/31R`qơzknFxUk($4^fg%LA^'k %o?E2ư ^YNqI5d4:Yc*.[ uux7Plh((&ؘ̅B$n'URL $& 4WhGA'qP! wߩ@r*$yc"fTMâ؍Oa(>`u=E*9tLc(wLp i YJ*H!  QZkOYot"|l!w+C)% g+U[su}9y3k>YK k-+7zxw/nG:KTCP8bd w&&HΓe?.KK~8:0mm1 FU66J0!ȇFVEd so+M&5KT_?c QK*ZcQcOڐ$=Sw>>-)Fu!Cd&6I1PV}k]'*5s}xfZnȱ0Ct]b%$22={گ0S *:4م$i^PѲ1a(?$pXqF*xw'11/S5-bOc1zԕ{!_>F!Gw2" 8>QwṉVdӇK)"1K,/=`pʊZd)vJYSaBe.ƛe]lCS洔mHU4i9٦;Nkm*uLVɜ70+"[\ӿo h~\1Uoʕ}U5~_>;6Ώ $ c;UW\C:ZmϮu1xV[c| N w6gCZ4=$Yrk$s="FwRX^N <%9|8;>C tm!0+ͲP|+Nؽ-}~}#z!!rDئvlgԲJSycj&ϓMMa(BH!{&⡹*Fa_Pq$>T`!*E)5{uE&|)Qߠ7z{S)JDvWMd?CW_=!ޑ*ac!x6*cѤʒN}-̼ӌD (nQx6qͭ0f9x[o8ǟOaҪ-]'am15O(h$Jw 6 )3=vx;D:n$wqzܼeW䥧sGyzz8A@$(;>IcDonr tL?92"SyCY;o5mZW}( ( ~d?Mzw&g}=oglQq>yb.-׷#$%v,oiʒgyȎ%G|# =hOU ~D1'Wa/bc*CѴi`p}~}F㛞mJqMQg1VubVTO?QhZ))45Y&J~tRE2TXVon?t>e4uB` ZRFsl‰G- 6"&+Td:`&mq m£ъ8wCǨ6(l' Bc_ e^},uIJwS{pa!}A VݹMl_WKyH#M ̵B'5\>8B:}Aiqp34}DVcU0gˎ.0EeSd-K/s\וڹufCK(JW<$XE[GPiE^Rsf_"۾^SE,c*TJ`P⅄*z}'97q"h씷p_ &c4CHE >$ɉ@{X\+vaa@%v@{i<* t1Y3Jax,=+?^z-G˧Ru1Y1Hx1y^F_]BqYN6}YQc_ut9/ |B6*n)x>6}CYnz}R\8|!jٍgf^w횱9BUNhYѲ٤?2ʯ!C-|ai|aMhEK묹6ׇWG|4J}MY dw'O)x[qGL;7mFxYiGLoSR2RS2J 2AD|JbI^>WjEIjQBrFbVIqq|NbejQqI5BHFfBJjr~JjBIFBQjI)HPhfZBZ~BAQf^If^:De  tx{ymF.h^ X. j x{ymF3U- )x{yȓ5v6-]hФTx{ymF89y,Qw9ȻEI 2(x M%beޓaVx7PbI$E2SA7c%beޓaWEx{yBHZ-^/?$u9riƂzFtpx7\]a|1*iJ\cDүpm(] Lx5x7\]a|1*iJ\cDүpÙ>ٗ\Ubj Fx%ìJX{G(9W\-x{ymF5%F.-ks2I« ~(x{y/J TG;dH+2ɉ},x{ymFIOS<~l=w뾇[ITx45+08DS+Z6۱HdIN^o`CK{x|5Bx{y#HwN]+nbhdQ[, ,x{y/zfmȮn9zor"c ,x1CIJ鍥,Vx5bO.4| sTY|}41CIJ鍥,}bCx{ymF;z^u~*V|y kx39K=)xmе]./u=3:̟!Ax{yBHՀmWR>_^~'c^+x2Yco 7a;Xx72Yco 7aM9NBKG/|וM{lF/xM @ѻSd:Rc j RxKDld0'Ѐ#n X3V]۶V6!lx M:R6ˇ':-xkgjgYAw e^d]A Wx3rDAz/{Xhm-ԕnh՚Z<4x3r?WheD4Pм߃m-ԕnh՚ZTp_x3r!gr:"Oޜz[֍𑑆m-ԕnh՚Zu>DxkgjgYDI{,w8۵ kxkgjgY$q絥_q΍#۞cQxkgjgYd1ym_9_X}Xy:x3=>QgC-;2J6!:ЫƊ=.2|x3}_k(MX$ בJ6!:ЫƊ\^Bxkgjg`*2ආG5[vK>a jD}H lxkgjg`*f]!Ó'jս5q> xkgjg`*̒ۏfxp0e|D} +xkgjg0UD鞒@RΧGrV)L\ ]*xkgjgP$2L/&[Xŷ ,TxkgjgP$6wVSn⪎Ԥ&G*xkgjgYDȁey9٭ q! o'x65 22I=NCڑIa\}ȩ2c1Mn~lDxkgjg0UGW,0ڻo8e *xkgjgP$Rs5t կ-=<'`b[# *xkgjg`*"kHF#;&xNj *xkgjgYZT}Oiu/~4ۣ% QxkgjgYDo=M+o ='xkgjgpE$A R.tXΠQx6rwK/2#}kE(N`7X>q|[Dxkgjg, USigLE/~뛘I *xkgjg`*nǯ%| u|;=5bND}PTxkgjg`*Rs6Bu 5;M *xkgjgYM1rOK, QxkgjgYds׷(=޵}!AH 'xkgjgpEAR4sו4D]w*xkgjg`*XZicpբsiba{> *xkgjg0U:3%__5z7qeh Tx3tURMRReJqe l*xkgjgE;xmkk]ʋ{Ҝ^+-| {M*x߲unkhN}F,xkgjg,^uuκճ2-D Vxkgjg,5)F!L;H6=41}T xkgjg,O}r?JȮ/FOL_ L+x3SmE/`FT ˥Cgwb ?ӉEV ymxkgjgED-mWgZ' xkgjgYc=&w.kf*z|8aȉxx 6;xkgjgY$w^O޺X|~V\e cxkgjgYd쾓Y^;vՒ`1  xkgjgY<.w>|>[xxkgjg`*21|mرG|>b 3x15tX*"絺fG}dGqL. I !xkxkgjgYBA{ܝ<8Q xkgjgYdBmQS }pzZ xkgjgY$Qս_.~۬97x3NiHǦ(JU∻bЋq+vTxźuKy`sw=?  .x!ƣ?nadD*?ϝ4 /xźuC$ȱ𓏝M]-vin 0wɹL ,x 0lħKq*䰎&%.xźuC$HJΝ 4߽gr./k {ZxźuC$^Jilz^ί ~ Zx9Np'!/i;Γb.du$疈#J=qIomMzHx o1Gק_s.xźuF*X&>u骭/R ݼٰ -xźuC$3Dj^W2oٖk\&_ϯ ,xźuFEou;l2Ken Yx$I Zc!-;ĴVx5L:A\:$I Zc!-;ĴDx!N cބe=bX/xɱ$0H* SJ0Lh\xOɱ$0H* SJ0L֞OQk(fVԗKGd;-ƒ4ۃ\Im'v]x!N~\Ksеt~[bXTXxTj1=[_! ul'֥6!^ڕmMwdˉcBSO=hx3z bJ#Є8dLA'I*[x8r1.0p7&h4g s6& vu  2_s:>Œb_- ;Ч"vgF`\mOb0waTsX׉.xk@dlTX#hDӬbc c*nrAEq :.8s58J%Γց|x6id lOnbHK7}). fQ0!B hbߞ RVVrEH'ѨG_ޣqhii7<˿{!YQy3wa=B] xsyYљ(qt0d?4*}Oq>fؘ5ERjVk5Rz"|uGj lSUݗkB~J$x.cTR\WϵQi2ˡWXv* >Kx^.cTR\W5Qa`Fʂ|}ȀGgoGwW}̊Xr@UiMͨ7Y5t7nYx[>aƵL?3,8rx[>aƵzz9eN̴ x[>}¬krdƗUNfĮ?YL;-E|x{q5g%lm־lWՂܙ &x{q5۬}ߕ-_?9Ɏa&9 *x{qțud6{N;}w s% *x{q5gQ:OYF/m,'Ϫ 'x1ΪUMq .gs'%,x{q5y;MxXyk"aȂ/Ta8Sx{q5K!SK~XR<'q^ zx{q53E;\>DZ@8W j!x{q5#^(u_4?[)W Ix3^ ej?1a`ّrduG_h=d!AԵLeBx]p9[0f<'K,x{q5 bgn\eQ~JGN3 Sx{q5YUGe\;ѯxtm zx3UK=LN N_푙=jzoX%`};x3̠73<i=I$Zwpmqx{q5wyF*/x39P ijx{xqĐi&}x{xQD71;5-3'U/1aD'_-s(@GD߹;x;xqS~?8z!}*߫Rex;xq@׬&|xjwvEIQ}*a*x;xqB)Wh-l5aQR4q: *x;xqHGk]:h.> *x;xq9Yz'wXF{$5 'x8FIۓ*"H堑Lx͵.DxwRt/bj2px3 ^) %ڰ (\wRt/bj'?Dx8qBȂ^\G|v8eݵX kx8qBȫ!?,Bp x8qBȡGϯ=MҀ{ :x8qB?yGH1/7dnz.[ (x8qș{xx|^GPoD?/% *x8qB;KEО{^Vc2 AQx8qBtǕKğo]q9͉ xx8qBν6Ko>J*Hя.8xܤҘEPT1 p Ix3v ?eTTYÑ(\xtT𢒾hBx8qBHsZF!IIד** ix8qBHm\Gs 8lܵϝ5k!x ~tȖ1˨x&qx˛%rE̦dIg&Bau x˛%kdĽ2݄iF$}n I@x˛%]nZ:WuS9 j}xkmpM$, ڌ 9V.2vߧ 0xkm- ;}2>mnmfr-xkmU740031QMNMIKepm?*)Sʦ,بlKL=cReٽi;[ EM==AS0QxqMJe 5ZF>n /i ~œ v~mm#!u1@\STDN D_7 EФ y `fk M()B|땾]MAq] ,y铡|>cmO-y<F7T{qWB\sDH~L%lu3g'OHmr3gN1&擫/6P_0R9.+Գ>@=^z>( ǣrW0^b{iU&5]h/泦m<wāz@UG.TjPrхP}0R˙sÓ*㝪x Dt9 Prtjr ly#Ϡ7>Jf.Ȼ/UBJ=CDƾ05') ]u 9F|]恦'ZQ "4q-/Hꀭ7BL=,Ӑ 4$"QRv3z̓{ a*mCa5G XuyB, b!{ \x|۶ٝܤG BDNY-YLbL q} nIy`yAo|NP wLdlx!JzC8Vl!V,xZ@^XT 1q1T:TM q+lix{%*qs#x&7hO0ꍌ[uWWIldF4xkn(N&S6}0+? FY 1xknP,r;~m{*8 Ȅ9,'xźusFr4bvhoi VxR/}gk)KP\DR29%%{ra{:[ J@H8J4Nhwz${&%cxźu\}s_^Zo0S[B*`Fl& xkgjgP$(|\,aQiTU&5 @xkgjgP$1er"_:/r0lĶF mxkgjgP$^-Ѹ'L w xkgjgPd^iiߋĉ- =L @$8%> a˿RB%/Z-ug85Oxkgjg`*:juzȷ-/5*4N*ɓiyx35O?/׿g]rБID-Z'vpxJm,1BԦ *x5tXA⢋I`,xkgjgY>Ɯߩ})4J SxkgjgY{=˷1KMq  LzxkgjgY\O=#Q* !x3`z!|bg$A2\8{ґJj qzj> BxkgjgP$2ucoߕ؃sݲ-o lxkgjgP$9˜ufn7]5 ?g{cb[#k -xkgjgP$Rv:`/s Z>-[: Axr~ pLߘ>šQ-xkgjg,oN~Ue'vV 6;-˃&/ *xkgjg`*ǿcLe}ʿ3wN Txkgjg`*w{<4D &&.J(=sP '~xkgjg`*RQ^?Gr~v3w>ά(xkgjg`*gOvduTJډ}Sxkgjg`*uMĎO,GYVm|p~> ~xkgjg`*< ᕭW =w`Y)xkgjg`*yN6);30O= +xkgjgEi~ĒOʛݘ9[r.{C *xkgjg`*bRzʬ+ko t0 *xkgjgYľO'+f`wa9= Qx3rsa1ۆ-1Gm?BO 1AxkgjgpE->-]<ֻk01<d *xkgjgYd,n0~xl $'xkgjgpEdԌ+xqX4\ӉKt y[ *xkgjgR740031QMNMIKe}̲83nEݜw{Tg;xkgjgYDqa]jKDO_fݦy=/ bxkgjgYdZ}%nK Z q 3xKM(V޴YL/[Q+ [xKM(p! %6^ΧPD bxKM("%_GW/lg,_ *xKM(IUĴͷT$- RxKM(+﵎-Ona- ggx`21L ~d{x =x[ɸqBS_rFŶ rZ0^Z3V 3Xx[ϲe4Ȝ]JJ5^>z躺cUw +x[ϲeC-HfUK /,g~oDy؋ ,x[ϲe4L-'[]t ( ITx449f˥=MNEHjH "S59+bFx44\73'C/r}Hޜ JTHM5\l%7Yx[ϲe4Ȫ:9FwOq* tb .x[ϲe4ܾI>vdڊs NWx[ϲe4H9\^!}McQ7yL D>x6o8vYv5+ Ux[ϲe4͛ds25wلd }x[ϲe4C^*4) %x[ϲe4H U60w Nx'Mv֌8LկX±L$yx[ϲe4ˉf+:.{^{fy/8\"x[ϲe4eJo4uv/GaB KxϯLjnfMavx[ϲe4HyI(|ݫ3̱zX] x[ϲe4țCo_vԖG5_Y~ Hx[ϲe4HO#'ϗ8Eb M)x[ϲeFͭG=Yڳ~~P,x[ϲe4VߢN=/6*MA (x9}*-IH=bÁ= wl}pDA4,8cKsPGxnT ^r)}R2) >w~N2A2I `x}ZPk40000 manCc'g*o2|x[ϲe .]o2tX]9# 'x44 J$zߛҏαH0n[j_+`4Vc`}tnxQ2[.}ݖ+틧{x[ϲe4A}^ .}jvdr ux[ϲe4H+3콤cmsc1CnM >?x[ϲe4͹s[,;63/ ~hx[ϲe4ȮuT6gY_m2?НS lx[ϲe4HCs$ª_MyQ ))x[ϲeC-H?uNް]^驚4gDy ,x[ϲef;x(c%֑9# +x[ϲe4ȭ;SB6tXeb Sx[ϲe4HWEZ3.љbR zxauؽBŵזWT$x[ϲe4÷[Jp15rRt{K+ Mx[ϲe4H?DDfZw6K\ ( vx5дr&־nO !x[ϲe4#6'ON?m6c} Jx[ϲe4 hd7 sx[ϲe4HÁ)ͦVL:3A5uI x[ϲe4H]"[7?,Ֆ[ Ex[ϲe4HP҂LZˢ4Q Xnx[ϲe4[շ^OZr5aj{W2 x[ϲe4Ȧx͟Lylߦ0e]Y *@x[ϲe4ȾR7zk/ýf#rS ix[ϲe4Jwe}^YʔWb tx[ϲe4֝׽r5t?r{DH ;x[ϲe4|><\0G+xܔ| dx44MƽDO6&HoiY(DJksdoFz'x44n ҞD@PY:Hу藇Q{>^IH_\hjx44hǡa:{\Ho$RzDQC3:fc -x44}:)>fSHIPZ[?Fpx44zZ[@}3UH̖BTfw_*f3x44]fj4|hHmLc(^%kȰ1@VAZx[ϲe eeqW϶=H>) 3:x[ϲe4h܂ s<|i /cx[ϲe4/Vŝ#> Ix[ϲe4HʅAM?n~]lgu-m2 /x[ϲe4M)];TM?%Ő{ Xx[ϲe4Ȇi"u*ZU6/ {x[ϲe4HiNG=w۱oT) gx[ϲe4șRf,4yas/z'c _x[ϲe4G 'W;W+88հ;- 9x硑u٥JXgrFv}x[ϲe [.r/#x-S Hx[ϲe4HW>jĩfoj;a%o .x[ϲe4,(4Tn՞jn Wx[ϲe4Fn_;ߐY x[ϲe4HL=,kKv6M S)x[ϲe4H7LY?cKyW> )Rx[ϲe4S'+LO'7uܩ h)x[ϲe_FՅl\l/Nܽbdaf F,xM{ V{0cQ=Wѯ4_-x[ϲe?F Q=yjRᗟa=YI Xx[ϲe_F/?ڜ>D5osO#I,x[ϲeC-!V~ EoVd_] t(x Dlx[qv.x[ϲeHoU*^Op{8cF +x[ϲe_F'P AJS繞8YI ,x[ϲeGۉgKEðI/F J+x2 ڱ=1;0 +Ux,UkCxBʋ)Ībb()x[ϲe4Wū\y_#8l >Rx+-~{^&⡲2 \}x[ϲe4ȆO>a.MUa;s}dYj &x[ϲe4ȟ=3\V|9k Ox[ϲe4#7Mpq[u\[9& N)x747]ZV*R0H WVQAOۯG4(Ex[ϲeq9Jgz_$ƶp2( +x[ϲe4f "B_TH?eE RSx[ϲe4[rF+Mly. #x[ϲe4ȋoQic4=r,:5 Lx[ϲe45F &:%L>n{ ux[ϲe4n)2[ɪ}W i)x[ϲe_F׽UEy-M_jgEdA&95,x[ϲe4& bo-+ ΑYl' Tx44s~j#]`bHD &]ڦvSli ?j1x44%;S<8MwSbHD &]ڦvSli ?_Cx[ϲe4q۞]^.? :؄nOQ (x[ϲeF_ ](K./  0,x[ϲe4H#Èe:aŲǦ 'Tx[ϲe4۟ZfAjδsu,x!%-9J*ȲіHEt^[9[/x:uBW/DX0<^qc: 6xVao8_1Hr [㸩qMbXNPes+ZkJr/%3o޼ydVG7@ zuuK332hkdIwFyO2/lquHV-!XZʚk']P$Db݊d>nzw*1Io\rJf[e(,PaEW.,} ԮEh2ɻ_~C nD_9 ؀h24`fW7 iJ5JkGaQ*遫6r!z] fx);OB5&Amܞ)8k IrxS_LK1Rr]**@f*hچP}CYvK6`2aZ;巶.s\fu9DKB50)W{1+8@A%@2 `_BkۏCF.[z4[sI,I8{|}Dm !k1,=d'I1J>e8̣J<ͼԁҠ{l<`X)\7Ou{eVd |s쭂nYR؂%6̚lɡbz.% %I f{WeA.91ɮ==H鉪YBc\폞MK XloN Ѭh*˖&X([$Ol- S>S8i4Yӻ~X #n|)kz ,zS >FOFO_m:{gg΍s &hȗl mi3aBf`sUē|B1P]y%;ܲuAF11ҡ<+I"}3z~|%K,PM?u!)O7QpYYi:d.## l|MvYj~BCqp|)&1HKhiNfE(3鎪rLgi;ЕJ[W=GBcf9301&8l`_l׏7R=DUA7["?%=B.70avF8 D'nƈZl^΂>h䁧Xh_*^ 4+t #9<ʓ=<>:X0]bn݈?KmGz`8J?:mlV%9IO?lN:8 "t.luP,C"otq7xKOW/ɔ/E;+o//l&̆vpiJ/YxdLݔ0v%@U[Qo? *{T=/gO|SQ\ukOn}U#ynMzeL5Ni9}0uey1~XLϋ%{y@/*z-a8ʞSnا X.xʺuBpSK{I$L>Xx7]iL Nr4tQpG8~಑1tk (qM2ExʺuCHq?;,Mk}( gr: ]qxʺuCȵS,ی/KcX}L# ,x iѷɓ.xʺuMׇ>IU9ghӪL2L3/ ,xʺuCń]B_mNFRZ TzF`a]lܯsNz5Y)NAۢԷ38TgZٺp>&u$|H*xʺu^F ͳj}*M.{e䋌Od-xʺuBhyX{=%(#rSAL|~Xx8\<[mՇdRhYpgÑpW֖ T{$q#f5Fxʺuvn$'dYWhnؙŹ? |j+x:u΍n3Tx{qeyIv &+KΞ|xw" *x{qgܵ S~DX:?UHw yp *x"_~M>,x{qBHsmq.(RYRd*i91 VxSLo fx{qB/>2 Ktbzn ,x{qB$E׫y[ 5 Wx{qB:[}Nq`M΁5@+x5o>W\(/I҅Wx5WtemH텑IsZx{qHM&X*qfgr.x5>k R'&^IL.[x5-9}lg#J8֕GsIݯx5ĒȪy'[*W=IG-x{qBp%GZsJOͰ1P XVx{qQ#NG}fOmm P(I.fX`ZP}n퍟E,&7QHx5FZp"VBhܵZ,x{q`ym3;z+})-9 t*x{qBpbnnYM)0~31 SxS&BNgx3SCSHF aXB"gl$\om8ژ`ԡp~@x3SE-nM5.5! Ugl$\om8ژ`ԡeW/x$\om8ژ`ԡ7Ilx{q~i{GL(>!˷˹#m<r *x{qemf -߳`OMk Qx{qenȏgOG Z ''xxՏβA( 8M8 ,x{qB w/uĉ ءe*x5/M yϖg*xQ/"  f;n Sx{qe{r 4'W $zx{qeS[vL(yw?* ]!x{qemΏ J&JcmW6 _Ix377U:jV ;d㑩*+7"4fu]O=08mFBxS ސhpG]}X_g,x{qȭz; Ǝ<ں<;sC Vx54<,|EkZr̻ Idbx{qH&[glZQ,xDy׬+x{qBLɗ VugI8έMؖ )*x{qe9ZV-1eoRQ Qx=̱x\沋yӏKzx3r~EߢDm 6W둆M=̱x\沋yӏQ;x3r<=/T>f;tM=̱x\沋yӏ&Bx{qH ;|ğśX͉*x6eB]dwJ8,xSԡ&չ4rla~Igx+.t r t L*IIK2C`d$ g7G`[]x׈ ?Gx]ǀO%DW!g^x b?CxR]O0}ŕRO&iDPf{i,CSIZ/8{fV"Rp%X lTpeZ HkPjPCHеU-ׅlX؏L3UbWḦZ V ɵvY#T9\]\|uG2CE!s^%h!w4hjnmeVٜL,VP ^?#NK88\J2Ƅ%I"&߯ >%_ǤmX<|@bB6g:ex?'db^82Sڮmx6?'db^82S?,dx ٭]g-UW56JGxk̨׸ڌ&7Uj),xqklG: n[lV qx{qB|DŻIOo?tF¸vb["ۗE-x{qBC]m+RH~ybzȸ 3*x{qћf956ZatO *x{qEϗ ,毼oo yү Tx{qy!ɑZg\h=Qt'. *x{qe鿒<}RZP ?Qx{qeo$_;ķx xx\ OJ@񮘦HR!x3SG/+_QEe9Ԙxgl\ OJ@񮘦Hpcx3SUrC~uPJj뱑gl\ OJ@񮘦H%x3S}§HIRF=L.gl\ OJ@񮘦HjH[x[ϲe_Fu+U?OK~ѴAdA&9 /xX4z")!iM)!,[tMH41@Oad߿8;3100644 TODO<;0Mgxȯг<%(fx[ϲe4HSmLvKrL %x44˙*gs2+HP+c<&5FNdCx[ϲe4g/15b'0-kc2/ ykxmxXzZx[ϲe4'r#&{ί}<> )x[ϲe_F_Z5ˇ&)h_6YIݎ Ux ʶ)i:Uy6Vx[ϲe_FJ7(d-ܓt0x[ϲe_F[~~uU5İ/9uRc-x[ϲeH+G:N./2ssF,XxM4TVH #2思^|勱H54{&=Ar"zEuF;a>TmīK} r";x7B3N_Zd1x[ϲe4Hr*WR'e|c k Zx[ϲe4Q}j<: x[ϲe4HZn\9$سV蟩 f,x[ϲe4Hf=|FK) FUx[ϲe4%Λ,,>{+i ~x[ϲe4ы=>+'J&: o'x[ϲe4H,O,:hPI** Px[ϲe4kM?v!GVK{r( Nx }$иQ(@mH6/x[ϲe4Bmꢽ%G]sN=/ Wx[ϲe4YjY]uA~- x[ϲe4ȥ%/]L̞'W!''x[ϲe4BM ?sü`B^ Px[ϲe4H^ʓ˭"vx}t6 yx[ϲe4Ȕg<ίswnVwO(jV "x[ϲe4H[3<23Jlib< Kx[ϲe47ߋMc e611S tx[ϲe4XMdzGWE& 0 9x[ϲe4zC^ɘC@L Fx[ϲe4Hql߆yqrm=!ox[ϲe4B g'1 w`N )x84sWyD/H5)!K{qLZmFx[ϲey0%!Vx[ϲe4HzIlu^2o78TDs%| (x }?ä|I懫Uő9]“Vx[ϲeC-!CY[qDy ,x[ϲe4"ʂ7w3 x=g> * zTx[ϲe4HT7Z~FΌLI |x[ϲe45#VhSmO6K ^$x[ϲe4쉷}Q673>cx <Mx[ϲe4Ȏs2V*IK vx[ϲe4hYN}jLv* >Z  )x ­dDY[hJwBp*.x }Q=?LCG.x ]k|jrȕ<\x[ϲe_Fn:+o TtY%dA&9W ,,x }-c_XB(L ~.x[ϲe4ȮU^s*HK Y$}g* -Vx[ϲe4Hs8b Qx }Ma63-9n& .x[ϲe_Fqa_C&k;uɂLr2 ,x }n"aw.x[ϲe.FzO Ċ<`Ι|1 ,x[ϲe4HOp|=ד=Ż>mx| ZTx[ϲe4Փ' =RS6zTa |x[ϲe4ȟ;4yWPf}da $x[ϲe4g8_nK]Zɤ5Mx[ϲe4/>"=e2 kj vx[ϲe4HSGBSnV/;YSfw x[ϲe47}]QDz\K8V Hx[ϲe4TlK XMH> )x[ϲe;qyD;khpdkEoҌ" -x[ϲe4HFi6wyڳU賝w0Z Ux[ϲe4SV j?J` Y}x[ϲe4HY֪7Ӵ߶D/ (x[ϲes w~.9ψۄZ sSxD#100644 AUTHORScLieV%#RGKgNkDeP 1MSX4&x6qXj,yB]& .bNxazq)D>_Gxkejepɸ'PڼuUkώ(k+(d2Ue#:_E@Ex3que)z(Ml f,jn|_~x,F/hTx{YD71;5-3'U/1!) s-Qt[UF^i?x{|y? Sx{|yBK)X.,4!wd?BE~>R;uy]-79(fŧׂq1Ncғt_eh``fbP\̐"sOL )" )F7'T w.tAx;|YD71;5-3'U/1QawpM8Z.F=x;|yFkW/I;uKd>1 6,x;|y.Fw >[\sܖ_3T܁(x;|y+H t"/;h|lwdIƭI }TxX5۬qy^E Td^100644 cxt.c H:x0 ЂőQZ 0-!Y@(>$(xfx;|yBȃNz w2T_XvlƂ8FۚUx6\Z:jh%wةƳppd%Hޯ{2Yvr˕Ex;|yBr7ٯNEuޟЯpޑx(xkejeQdI>==qu5mRx35Rj,7~hL`SkI- R]˱v)<0x35g?8Ԁ-빑I- R]˱v)<Zx35>fL57-̹{|S,I- R]˱v)<ox35i0 =adaש蕖AI- R]˱v)<]VDxkejeP(Uߦ׬qyo+Sr9e?< nxkejeP(ass{>k81ƾhbkm]*xkeje0Ad~[W?\(ܱ/iDԯ Txkeje0A!+gf+ofXYY_~D~ 5*xkejeYTi7#e,*Wvtq; ^*xkejeQd׳q,e20 QxkejeQ{(:zR N܍( xxkejeQD&V9㱆Y2w3 qx35،0n]7NI,;\{ cI[2|Wb$4&BxkejeQ=\ʲS_s2ys 'xkejepI$+/Ր®.Wg8< ^Qx6qBF2S`?rMm{؂ d)XG~13x6qbTfP KŦn/JOMm{؂ d)XG~1=Zx6qRj  ^xkzJMm{؂ d)XG~1M*x6q]$y4ZeoaQrMm{؂ d)XG~1}Exkeje`*hkcCݏPv5s@ *xkejeQD}긧GTuƆzvw= Qx3q0r0R#a4$l-}{^$]UtݯKDAx65dQ8+},Ŧ~IJ[K)q@A Plёdpx8w\o0z(Lx/x;xqJdȾr2asL} imx8qȕbAk.Uό x D?/ @x:uȊ/<lRSJ76eaBFW& %xźuYӔyߝExK7չlsc#/ 0xźuC IV@`Ych -xźu!1 Ԭ\Y:]kOo-Xx8?\&:EŨxxVj+.lbXFxźuFuƱV*3!2Qn ]sx93];XڪµlYRAAA,Eѝ0[?9:&LGxźuC$w}wf\~Ӛ}J%s|sx9NZEvݧE9@b-Z9B"tmM&`Gxq5iS_N/>rFm100644 obj.cAk(VŰvtDёW̲,XC}VwbYԓD^ufe&8IxźuHɛT"S:" ,xźuF73-6֫fW|wڸV FпxTM>@Kn ݵ%Xnݝwwwo&7;{kNz֭{6oXQ)7WPYHI썬PHdM],HX!ϔQIHH-m\L m ]Lߚۛ  :8ڢ z Y /NJk:_!4 ]tV܄'^y!4~++ku GҜ(҈;Aa dm7T$wxn]kDs,IqBè:$Hp2jA${-qj'sUu WB٤` ꓏n@x{Ď./)*W-Kɨ7c*gRM y̩[=T tW#i8ᾼmvFK+umtAnb">5hc-\@aޝЪC%z}bvO'yb ,J4™%A3#Ũ: r{d'ϲB7LL< Ho癒q:_wpF67Ot/\\g| ;V`z*CXE_;|M 1SA7x6M=gYݤf=@ߗ 'ezʭ+p!AI;`h N<7SUsĶD<@up{0H\.RmZ98ƌSpDCąn CjAY6P]G\;ߧ*߾1I|ty>)EEUD*XWe:KoPQpo~#l{9%?EᙟQ$T >EDiU/*zsU޷룙;k zltّuْf3}\Ц uNyy?q ޠ uA9ʜRMp?ߦZ ܋G@˽._\ih;'i C* ݞi׽1ίj%>7lC"r=4G]ylݱ$v #Z 1ݔKubu[X\cc,mѱn+o|t;5JxYܟm%3'w $1ׄa5x:Q~r(gUauWrfO,f.+!Ғ$6>bV|dX鲫F!Ԇ6 ē\ v)Z.Vy~Pʥ h#kO!ɞ'ay.#Oўdkd+g1ϚzIG)T ,}X ;dqwJCDƟ*'Ed>VߝK?ruK 7ۨc\4>5$\S|~|*TuZE::5 v( mE7M Sw!SqضA8&eB4pXoŎI(y)pNSQD~k}V8-ԨC:)1Hf+1]cN+0}6=5'?#C|)_SD6n-,D|#pډ*y сJ]e> ]pvW,wE#-Y3]TxJ.⩠_x#ȵWRО wX$eXΥ`?7Gz[;6??dzb\hC&jRZK Qe|n!-~Em0s鄽,ɯЙLFS.Kfv@)_9M) )6Ϡ\/s|@F *ItWffD_.΢&k ?qȚi D#*[&tI=j=d-ٯZqNL ߽Tw[R0NA)%[B:1W @ʠ7.b~K䃉|AZ z4\/-iVSQZ/@SDw`*i1*@>ɪWɂ"ݷ!)xQuh^BxdM,1$M[2c|az8Jу!K, ]&r-oo7 4V^^T/DѐZ r]Xr}1S5bʾQI!KQrezn9|bp=_2y)>|'`c^2RB$L!s׮G\ld;L&S>k6V.w,muCZ}bJ!)%k;PIۍ4G~:1x㜼?k_q2j<>V|z b+x) Y})w`>hءVŕh#! 9J;Ŗ`g_r369uF>f1^Gp[B5nrN╌'M7-i5u e ۟TW͓{AAo*xܹ4T{uI/nS-:±.1kPα4bFO.^DO)pUDUdhQZt|z^-m!B*FrUtsE}Vp¡87PzuO$T5jI(_-*ZIE|t4 YwPzXP HNi* 1|yTyոQ8c>%y\\3;em!oz;T 4o3(gZ[Gly5x$vm헽2xċȆKbY̳i I#\;k1Jo@ 獲1^3e5HJp0\!6odUq`!S.wҲre{Xkj#6C@$vCR_㇅w6*jRRP\LIH\}5N R_n~N9s}ZzFZ0E<Ȫ>M`RNv#V:QUU34FG; 6l乢}z 'VX;?Fޱ޶[Ku{LXn-h;'rI4.EaS9f.,Q[y.1h8MtA)v^:Sp0;wpJVTջzҬ#g$B{PX2a4Hspse$Hˈ靕?ʰsuekzQ1s?&h!auiĪhiIJA>po 4#݊yE4k8Hځ^C<ӺuhSoUǣWyWq`D6$qtzV0"T1KjgBPg^i6;Ɨ1J9T,T#[n&% l 4=C'AZppYބ5o~y̹[H6ʭi[>@ d"e*R^ڥ9Sxvt\nxC'İ;%a~1z#+Ylv),{lA3(P_xaY^TQ>UZ|YA= kKgPÄeNwt bc96dT ">ndRX[#>w(07gm͢Ci>z@Ti{gYe279ڕiŠ{?IRzI=HhXmc)"9ODPMY"^Q e!!nJ %-_L2tv_gxcX+Y'zזa4AW+5mI_5\$BJXƞΛ?iu>c2uV'ZLZ (I6= ^Lִ'ᯯ_|{@FCAJ0F{ͮ+O'-u]9 3`OQi8̘L T[& n,&/+:8L;ïzAy[cu@xU \.|y4PcR Vz6>K {sꗃLN[7]6;ţݏ\>RK= $mw^0J?0;hnK*̐|,.qYH$H-oD_jH2'WhYДp V0[PW˛ 5s F@bwqā#dgp|E=Tˤ'Bhc&GrjpW]uq#~4 Q(z)<INz1T3js†X|)m)kyVi1+8d0 BScM"yu77볛!3i4:*y!tb" dN!p ݼa n 磷{y Fr,Jt,f;Ep(2VXcUiUB9m\Ak&şjd|^L)BH0 wM0j՟*=Fp΄+IքO28Xk@]CV(l`g>Ѿ"J _!RR <|J]0ߣ(avi92[GFo!vlCxQ;dau4Aϳ>9f!PZ,FbeO5$HD%Zf!?[ 66( U^.\|>?8oz;Ѿi걙Ĉ?>`5Q':2=64GU ek>U0ohl?0895=3;7v~qyu}s{wS/( ԟ g0~gIY`1 1XDbs*;ٔO&_RQToS,fPz-a SMF Ui{ӞJooM`/d` ?`9h goꁝêҵN0#yH h$FW{<bݭ?=% V |`@sb d=Ă$-X+GDMg=TY旝W!;@v&g>^MkM6jϢAwXhwO40\㾿2Nq!#6bph,@D<BDG"#&-Af*4PT+s0E VnV-g5g&#[f,i5Oᶄ^j77/Co?^h<%djͥlkem\QS1+ '{٦QZZZ?և\Em}@a;bl\Sb{ІE4/S B1"py?ScRF_W`)ڌ&y/| >sk@+k`J٣eawCjy9Vfl)堚q^e`iG |Zز.p̨rkvY~oj#YTL#>b(#!g 0>`=R@ e_A}TJ0nkXк\iFlò!!Ԩ>2NVa@1櫲s@G&/ŻN?!s2bg%?:0 uH=U '}oݏ{7 y|Jk{aW8mDͽv]Vf(j )c5uNSԧM O{,gN}4=_%MqodU*yHóM)KIp?xZE)E5 ȐH`+'AC7!egʩ`]kl,P f+;&<e!3 KpGƵZe 8\2X6]C .ggΡZg);bjDoIr݃]AGuy/x}&h`A gċ`7J7;Gg`]TR8`;KYua ^cNͽԹ5XE[q( {5tXvuiggq [K{QabNL!lloĞpwx |1us[Mh)#]v'x[f0] (W~Mc1INar8}Ƣ !ЉkצfVIǍc0=sD[.fnIb*9L= & 6+saETAĩHI5~F0R*W#%zD]U:g9ȑq bPW3b''W!V L7XSFy0ζ}ݾI@vI[ MNKҪjf& C ZwHx X(YGy]`YE.3R ۟LO2t)tJ7`zG .Vvc.`EA*d/1[&4C]÷1ML;k].[UnegL C`X`$o#Kq{:[K{[lqXk 5ڹJ뉍sTIkl ]K))Y+/Smm 8 v'H(U̓kdI`n޼(ڶ(6}ػuv3c,>-F[rR1,hG F{,jlK͢O_Eig ZZj ↈ<}Y)Qr$t%B}7wR[&쉦5_Nr KWP\(-[ G4E;X k=i/XtQU0HR,0~ <"rR- R dl#dz,YD-I#D#[Ϡ {/J\v%v!*sγW蓥=eKjRS'`eξXUpAaǔ+C+R.֔;ב> c.e5+\89sdo}4%gRхO'c@4)&g/󡩄&X haY,`$Cl.E(Rҝ`bZmf$3y=*L~T)/䆑7Fؚ$S zljwV7|T˔3i䳚LT_e3wzU-S"F+V8hbY798L>JK$r? j?`\XJ?zO`G-¹gr!.e>vY\}9D^ΤWY; Bݷz3z=mlϼ"! svH`36+x=%\c^)2[w[njPs۳x\ze.& ^'ZJBoFv.M!u2ڴͪ|=.ԧ{L/ksF>z!͟ |2NnmQ+s䧌( lp4d5=VdCNrݵwd=A &A\=T65o_[eA9E_mq-}() D?k`@ y^9%ȿ$fKjɁ x_Chfv1 z61Rt3u #0֢|JT_?Fz_Z[(Y^`UZ+_ ,,ˌk b栦;n\ԱÊrA9p# M7 89\IdzEb7 3 ݰ+F=6 bP $~:}W>;FtWӆVwZPkj{a+qV[&l/4+{9Yֲ,آvO0,3Z|19^UaIsaL84b3hbE%FwRӽgl.=DZP}Qpۂ6xeGvXPvṩe2R_Xl# |kzoQN~AH)(!ɜnC ko7)-^5.e|Xg..8Mº(U,f [leX G=қ8V{VɛzFCjEeGO&0/<:;*Q(]t`e~4 >y_'_WZ^CBA c'u~Qcc{Yx_Ze+zLs]?@fX1z&4O ]"y>f뚓X\QOMq| s0OF\ս( ۞'Kޕ*F).1=a%׮`nzO%¥ĿY zp? Ưz/&-c_Q!dC!wwJu r50S la[]]8V*cD2 orI0t~jvh~xD+77V%‘9$10;Wa@hKW7ugz"(+Q~B`Hb- ]#Ks6dg.}K{JwZTy.c–;ZkJHZsQ P\ȩSz=I)a)ߊyw~M OnyQюK F8E+l.`l/Ē [pnJ.Ӳ9|6Yxȴ}=!:mcm|m#U'ꑹz9cC{7cL.D3:NS䛽'@ =&~yeS1,UB:?:|j4ʈ 7%>uF C[4n2T=7s QlbUHm =o-N>I~E5k.oQ}w{q|'2$CW|w&6};;ng)`@*8(/kt>?CƞI|Ьݚ`F Y=pg5EtTQݪ54ӾI ;J覓j2g !N$Pf; h"5n]1+ ?>#Iʀ 5V!~P-Ma5߁l m-Zt.No)CTJw a6 kH[? HP#daL֌VP#[El] 0LOq|xڨs"u&0f2U.>i׃,Q=gmL ,ꤜ ǭ9;Sp2Ev-qB-U(D}KUC8j-ފUVRd 30M|Vug!g~SR<-vgi%t !uZ2xu~ /I.7//0s2+N<*Գ{aGScI#qrYc`{ʝK)!d_8wY SX;h h!SMm xo噼#8j5*ܟŵ=7g=T~ **ӯ ߹ xi%{PL v:i =rDFMRpq9}cKr ݛkCÂ]8kGl $"{mdl)Mr6i>> WMoNpk+. rR, tgUǹ z4ԇ. B3Vq Z&g-R˿Iz*xl\qs~m-"'?8H|Ivh[m}R[ar_K @`ZL~@{>|=L1ehuh9sG }SH{1iwrsd\uAtc{IAqjL,}ݞ>Dlp z]ѱvN˥urG#FqY@!t8#;{$t%tL{YHdqR,ksf9-O^b}5viqNa0 P^I,&x/`1J=(Dً* }Y QnRgG=:k/K3M沺oLya{ĚmOYs0Osv1 3#:Sf}7RSS{Zv:ECZnw{1-`T$27U-6b ⛤0z^lTReNIP%K ~px]fgne:|׻({ ğYYi.BbO:40>B *O4zP#l}<fAK}D<`@ϰs3ud6}Nݥh;OaH_N}=29ܙ[aZͤF՞ XdoUh?fGvggT2%6i^c)ICe_#oyR.ٹ|AmP&.ԘlG DP8N䨤~pdnձ[Leä]D A? gR`ఙ.O4b x62ɝV"Ш|K -dKRc9ܧqUE;X`u@M0W3XήDPz>0 L60;'I3rH o`km,ϣF=Szs42S)BiDh0V!zVw,+RY!s=]aF[B1@3YЬ. ٝhZĺ4ʳC*m@^)4L$l j@[ JdlD.,*/c9vsNsȠ \ޕf^ʬPEcx~0Ơbl <l z@5O-+9;F/CnIS1ByzFArttfg$qq0g[sT7^y v͏NxMۊx< 9Ƿ0;+[@ ܲC(0с YZxgڴQ"XfM))^ ?yyJ5nɬX%/9b"`N~)ÞPzZ0cR\1푹 na}'үw,*1ް-@0OuvD5CCKc9 TCae1t>ubTf;{Qֺ] r҇dyfMT Arl1( Ď]áI'frKv @BP)87o Gr~ܳ=(^7-K:g^Ԋ5Bt3a%__CǺ$]? ?m6s#+`)826'rhԪB[cZA 䩡 2?+uR]miq TֱF2ߠ㧽DE$[h-N płJHg8ZYq U5G-H RW_q :i @sM. p^ScEui-U*z|Gej%t)"pVKom4R跔TbE; ٙ:%$a5}W~Efxgd*g@iomG!l3WM 3;r76z|%D@Lr1 Y/rD AS1cMCs2tb(1wL HJ#*6hD1o}Vi}P8dTlͭ@ Ki e5k-U$fn*mʒǩڷl>NˋL' ^⠆:x&-Yy>YSje[%4$HNj$:L!=%$4v+ƨ"* My*Rb>3;<<ǫ 2Nvߢ3M/<1  Xcju|`/ MX9<:ߤӣK1dwDCmuh"? ah#@u3F}EU /[^Gagk_DɼgR:@ ) к(xoz/TJJ a)hh.W]dԶ?gb_}n1+}BjFpן7T Lez63v㆟YfC~Ӿt%Uh&QtCG? rcnYpkIc32lES0SצȯĜAźzsB?B w!O(3:| 5ܹ4b^_vdJmøv{ʵ2P[GI[ o1;%5Kr;{x>sx?h}"Io ܞlz|!U~ GI#w [y e#I(]$(oBX+N4j Or$9t67q YPkOú'Xs@ZBǸ@@ժ-ֽleŻ?+ 5AH93zWkFP;*_J==_kU_DL5*%=Nl%ޤ+,۸bsf#ٲ.ʣ;էSHN[AGZދ˚⎶&+6Έ_R"#آW< )F[#|T(@01{p y4ʵÒ*l%Q$Ogj+&}  NQQq=A@VŋJ?AҞ Ci# v].z2$4?,Qt --Vjsp^Aϛ&^*Uƻt96X #%0x% V$<P@2B 1jnY,Jܶ5uܽ*_>muzd-ϊQ=S'09B0f42ߔfJ{сQb7[3똘[@@Wdqx 8nY%r͘:U;3[FuX^_O>}fM -|ǰ&arZHTzo=7W\nWwȯ"%KWg%9;%:*քEth|v(ha:Ce|x<}vY ;s)}Jr*.g1 & mVCbߓ<)@|h d`ߣH$ <8~Wu8ue \rټoH}Lv=2*WQ+nM ;;I[4-{}O(m>G+QHgs?SRVp|xml6fWQ}%s1RXj":ę?/)͑hc7?(TnEAz嶦(QP( 5io/:SnW5jG4R:<GRrDn=gٺ!o˱:fLr1{`Hh/:JreZnge ͎$eى4ӞG:W_mNɕ>2Bmf@!X9+Y93ᴦKe HBWFyQ$T#}BaN& /ֳ}Dоf{MPU` ;Cߵ3ƕwIHUdqX1vUʏ46O#PoE|`dq"pDEpF!OJǎe7]F`ڻ30݅}(MAP<ƪ>^FqFκT!G-ʹĈpu? (| 8InN#@Rޥ'r.^zU%r =J88tb1%a)е#fFUf]q/a Բ>\iz L&Ql;lAA.JV j!V5Ydmkx+ @[Z \Kّ!7&Â/UbcǢuJNTB|ʍ ClRoiu`|eĪXo b95ru;SPSv&j3CK<l$l1:CYEeq3VЁT}'( q=y .ʌ[C29hNջ88߇slv2e'Z>V]xszjݼ'P:JlF q|7u4\AM"k~pw#>r+dzԿO'HдJAڃf.|F6h|iHdO/P`zsK+c稏,/˟ޟjh\P_|mJbXw`(HNָg֝D6@qA)èy6 FmÐ'6AӃ<}]:W"5T:G/^^~3ᇜM z6TOU<ׄ#DԎw6}uxr+UѮG+R."ȫY.e }Whb#٫xGƠߊ̽_7iɅ8ڠ&"-f0)ɥ(;h?3vsĘRmN90@Yx^ŖhJX: nW 5AcJE/GPvaMQ.|3_V#b}Fħټ jCzbOyc؜dN|QRS[}G˨E>'hlr<9e/C#/"~5sܱpiQ~8 v*Ab09Ed/jx|'g׌౭. XUΣ$iZbE$ C\1\ s!Sgj}(\?3J)‹tsOl'bj)ލQ lTw! K-ǀAif3iE3?R0X`rr["bҾTjh@'b1QV7.o%KzZ_qey Dc:\dfXJDHr|z,t_̆gC 4["*ߧXv~1&9Z*pwTsyK [_T9G5^F V)Bnb.b%cDG[HqsKMs<- ?[ءrl04'VPu \jdj冲÷~(| u婢ET" 13 0&!'r9A:aF62v򑮉u\=D",!Tւ~(Y@Û%߽?g PEn 5L U B|\b mm_u[@7.$B-eT!jq_R6oQjUԂe_tObx낈ً>mO-e91 PL?tvl[MA!;QjD߿2ޗ&(=H))&]cT싞Ei%EMY7Cmv/P  5]kYrxkaR T>NONؑ;sn8"^yT /w$ ? eS _?{'=.7i7UGD3Ee߾mQ?Exlw YKwDLȋ5rW_֕ ˿X;*U0ET\OTd?*-t -4m0MD/5*ǹg3JBՅa vx[BЖ:c.rZCSH|loߊ8 0$?ɽ"iWNqYș|Q-#>!u;|tpC/SF[hr{x\}̜( {륝4ű˽|gn֏$dFU܌Vq}*H!-V$\v :\6 G\z; ؆KhbE.ҭ&q%^k<9VǏZ"prt|gfEV.n#*/N5\T!w:_t!܃x_5h;љskro~s (C;6q}^<;\W/:ʑphOlFRC&B"fyكs1z|ÍW3ƌ[vSsv 0_ ~Qg~6gFT*=5yf\.c󔾨'fh݄{HpzGF`Unaϱ+5eCΒ\U6P@3wh?2>V!;,ȯ>7樠' gj|W9CVWVgS*c/!MPEggލ#3's) xNυ{ V"AdR_7H«"x% X\Ɋͮ!?nezw03[@N|k9-`r4y?<8G 5[W 5125eUN_:V^&xhXZ:͕^Vz!" SqRR9w [ƺl̷@2-~n@M2ڐo;V9~ X_s, S+ek@::3E()<rACiYV Y|Q[ j e 5BjCQm9zɶ5oދ~JOOAĈ<7/!g+UxrQ̵~&F6:JBn$pjh[XOffFpt/rdtԤE$YV'@d_Pb>X,)peU,(gBk?@Y\MBXČume5&T1`6&g.74fڿ[D`[]=EFJKbȩcPYBD*xbؓI|Ao'#Qjl^*w_דǐ4z =q֛bCJ!̙u?˿Jp^JtC"+OU;?·`tSF{Z +?M-9蠺BixyuQoOR$jszfӰ RLneMZ&' DdkuKɟ5ǫ 7/`u=ա'gWK\ 8#I`o_J+x7x} O2Q ;A/YrguѸ LW LiZ#&Z\h3[3>mo,T*NQV9OZ Tגut H*`͟JTl*I-\7Y}FpV@oаKV|2z@*] *drjkw!?]ZmcWW'NpAOz~,xZEj/ l5YcpwcctƘ@,؎} Qy:!`g/l6^SH@]Us)&(Al`akLGۤ 󪴼+Fp>PEFgё׼ZLr RP/l)AftW)oc1Ym.KP KYnFI9qF6̓25Hĸc$5)f7<Z& U~FYX0 -oKv9F4]#x@dCzPΜ'㟖oCD,Q0L* tTûS*#p tF#L_&*2;aH>u~=5ն(R u!$My7.f,_]+*F}RrEog-iWj!yUqNµڿTu5۪Fk 7c# {>T39c^LZ]@}9s)`**||1\g{0_SoNִQ,W}D{s^gTdOx3'-e_W<0,sV`؅j%){Ny˷ ` 0?Zypc*xAn[>^e{r:x.$KoϺX3&FY5PX/10f5ōMZp٥&iM" ];swL0WFiҀ/I{_I dk6fiJ.!l챃LQ:x2܉xlط%}45z]!\LpQ~""37飃lzl#lRFwJs&IRYtd8qg̒З] +X?<,`|RWCzʴKi#[bSH}DԚ?1yF=%On^65c9C5%[d,B]MQc>* 'ʯ:H :Вnb_E0FOYOud"`AVtlwk$r(T9V,Ld߁iXͯ)'* %*KU|Ɩ.R$8ҩp<T9 ?b|snن7j%=ݾ%iSwy?[̀:!La*h߫}Xlǧפ"8J})#/khF MU^P;لי3yDVp!@4['e0zwNKU=8BVR(KPQ].0O@M=Yb8'!N}¦X9SܞPd nNPL]ϗW^ӌe\5a;(Kv K7[@% *HciTW (Ѣ'QH{杖NATr'?-<">/'h*F' \.T]-BwZ~LA} rI%I@O-/H•h1YeȎ R-r"3r ' )=yt&zۡעkāe2"rϛ&*p:ԍëuw*GM:˂QVndQ LK5I #|ؚS/E4WKpnT"6Tl Z3 ¡‡rT_QxaVh&/3؝ &UQߩ_W=lXx ڔ'ݾV]]CJL ,e)|y!4i3wQ\Q]B\$G,$5U]Gi5 D3 er6?}\;Y}3Zl/pc$?jm/LRsNklNLrEjnk<$kSjg[Jw(#!R3&d<.@ʫ'M4 @:д]@Fwn)? 6?P## K n`{ ᤝBQ(۞|"j k|8 >Sp3˪%7r|uf#gqmѣ3va3 b"/#YlGDެڜ6 gB!vn-qUE-~ f?u_=\D!BN Ji$&z ,v>I2ﲨax pJT(բdrsi3)I}_W;tJYA 2]zD5ybYI ݴfKIM@RǦS}يkvNni%wҹ3h.t[7i?I+rcȬL6ԥ__mj,uf33+y裾{Bf1X\MZ= 'YaT܉kQ"(esTcV1(AUYES0$ }>jK2ŲH'7CHc偘5b?}Okf wDfZh^NXLZ`}[:XP!W§]M[K?yUfUh]fG$gAdmBV^^^! j tuO'Х݊E6OB)Qs*d^Rok&v7'Mmr/ZSSGwS 䉤)AєBJ3I]/o>GTPrqc^f q[14a;T|]n u UU}\%/|x+{aO]ߥP)#"R#!T)̓H'ck,0*gc᩾`~ߦLD?H6FnL299sM+cڌ֞tzz1l Al#brKfm߼3< Ns[8xjҧ2g)&م,ԅx*Ñgf'OccyFGH0NGPΟ눏3YOExM?)C*@U'sl=n@,pvLW9.p#;Ti|%\|dA~vdt "m ~~~ä_ݘ܇ĸGY;$R)|hRkE w3kG8#x)zp"LSMohQ;1V,qK9)78cfMVլewOPE]nGX`3xi1G( &+ `(J0eDT`yު[[oo*utR` ~q/ {r]RQdeў=81=I5!m<־2ޜ2jk>?%A?&AJd@7L7gYœA1'- !s2Mߨ`:M4IUl!σңy΅՚A7~ Nj&`\8^3WB] QY(8PaEq-20 -̄T=<z$7WuYhi @.6$ηĘt埖֐9QֹvMDrD$=zSX91ONT'oTsfSxa ˫Y҅Bw Cpww'w rȻGٓsf73?b-z=V]U]]+ ^@|u0[UIΙ/H]+4~x ք7s 㮨_Qp\0>Θ#H 8<`lX HH߼WƖf648O'[ōMz6[hiOR;b);x圁+P]$$v*&^ј1ESƥer.gĒ;f_^f%}#N HzHCH4 Eӆ'V\8 v*W "D~ 1mŒڀ- U@mDv,rS'`hF%;fK\ M]fK39K 5t066v,.%R\3,s*X`GLygK%L8r+t#Ã@]45 (t#<~HdlK j7}Wס$"|W'  ]4Jb$)Jbv{ 7Gg$n'KDT 6+qRjcݚ@wN`vhrrB(S |#"Jok6oayaMXr_P+NVZk[šQ1}~( ~\u_z_ڴVFgҬ&ٮKHaD-{%a8#T/ {7VೡIjahjC؟' ʸ"Ś&}oO;j?Yv)26ʸj*9Ů&u׾\q.!Bi *ʱkEu@2{D#Ed8?@} Zz׆SPGήVH:))Pf5(eq$CcKxbi|556uj0hWVD sM2¥{\o z2f"->U rJKQ2^t`<تYⰘq߁i^p{j6$nش`%F\r8gH1COM9'Jê[JXR`FnSFj{m{ƥe}f' 8->oFTBcs֭q^eUJ[+xu5xgG6(c*YVx#qTo]C;DI c襪FQ$sN~Q/c @k#4i}@?E܉ܢ2-G.Ynݪ?!?veF8I9I ޏ՟`?n_W.8KlĒ멨"w_H[/ ̳%yV(BYE/DBRwY{Uk/Μg6Z;$J͒;_q2Fy,ő0iHiǺ=\q6SM8 uZm[k4''?ݹllBMY/hƹ͍Սk蘯4ʘ]TlH]7Rif4ɪ]NfSqQ\Vmd8+{ y_)D#35),z3}E|^vtBI NR&>0uUfd&G#jBj }:}{VןrV_3D*HE. H6YpX;g@9;_{=!K\H[) 7VM˃sFGit6XN K$nO7 tLghVaeuH$vj ~n1|Q=!/Α KW(֛gqg5WJy~SDzj|Xyo/P9N4QTC7ӓP_ U_>Eroz jZع: |U r}"K"R8H`U-3#S21wlB@"~ uWd4RJ6\^YK18hV糮)aW٫>)7 ='87h>+,)`F<5 fKOrWlQn<%2^nMU`3(=1~,J9ǯ Sw5BZ.aT8mE +iԿ'Yru[tW$vɗ sQWih߬U> 4f;5fZ9dGei1@-">_E$6"_Vɪ =a&ҚpbCDaAy[%m ,3iF#o*u5c`! J01f`e`,0M>F@qelQKiya) W=g/I,Ħ]{tSstu}لD7vE21FTP?[ @yȲL%6.5Iy? DFV2$_CuK?Nhej4* rq*Ahk0ûffV1c4`!YXJ][/4Kp,l~̮O YPJKbZ]&d${Me!G]\ ƹJ_?̊ e=7Zv>ӂ%ČyF8BSP>=sgƗWV3ă +2RO7=-M]3z M&/xr"ﱧ9q ?ZF hy\&;j'܏d~_RZ :P `>{Ϟ몖+cbA[ȿ ͟ݘ拉IU1^TI!?q\,2pۚesƓ;N *Q*d>8PX1}w?)TT|8:+KEd=J䃶m =;Gr #LK0\krW|ێM njWyz&+qnP.%p~_wS`4ԵZi.S%oԳmxtyDtiC?Y)O67AY׿b#(ܜf2 L׷"fbڣPɭk(O8:4-`pig И/zF>5JrEkN`kZqt[OzcNaBNDĭW(Nѻ`/@='1=W^i$"pxRDg\6j~Nbjf*#1PsBlX,LaQ ʼn0Yi=76D&9(SV9wqQƁ*o_ǂJea !P\].^e{s#\ۘoAo/?C3,Mٲ$C=}b#v3rRRgfjQ&,TLlp|+! p{iy)ہ S~+s&SX-`M1PVTZXgc3~0r߃'8:& > ˆFE6^_%RHM婦ʬ ?1H9c~fu%pZOo5{7E3@#UT2Wn9nA V+`cYǦ33xē?cDYyr^ү0=+I32?Q_A_|-_>yt t8pP C3q}~Fef|{MAG釅%fO)QVd-=9(ؗuFd/٦,7!BY3 E- h O?]k{?/]o{ L|}ğOVvUi(,3 Zw84k n;YprM(TLD'[(-?c>zԒd@F_L?FyiFMV0,nػ]6 8w#>*+*xFQi QU=`G˙ŗ{gUW@Oj+ݼ[}KW (rG÷WDX̋*?0UY&խJF?r?_\y  S _Iyx6]?zJ6r隮->&h6 vѐz]{yg8\΢s˶3m4j% M+*~Ms_ 皲!ZTOվL~Dy(p} =}m?-uLipƆK%oahkKMO(p\\\*c3[}뷿fڶ|zPPXcʱ@8u +.P'cv.OV]i ԰"CmT "64.*cMe_)T(F 5_"<Υu_-^_=<q_%GW_6??F o^Qp8>=|ZKn{E֘HyV=ˎ=RQ1!`:w|//JUZot lZ^t(DHc;`i @"UYgdY`Y \_Sz <8f䭚 /e&.XѲ2_n 5mAݶK[z@_z$АB Cp2`?-Ty@Z^¦ CS^:?&>؁=w<X ཚgP|*[y&6'lX$4/! SAfmtt{mY BB kc`mi? Wl2W8# Cm-Z- c RWdn )_!+XȬ؎IMigeKWoH!4nwBpR]S_~O_eVie+k%5@L8g0_:xJ.-ӎFw K1>X3sG< {yl[G]Zl`x$b:/JHđ{]P!IC-TQAɱ'֫'xZ:`ϋ8ߛy%jM9@BATnBtr'w*s׶puJ*-YhM{bKae'_(e *=5lOQi,d4bbMgᤐKf8zckR},Β/k*uN(u5Iy J:u`;>mŧ`r#*˱5ւm@ł.KxLm)Ө.E5w>ȈC'(JtEUFy%7t5պwzsI icnp%5bvwٯ |yV0ړN8#H}SY0Ëw5=XfY v2Վ68kG18XW`+Lnik+gvCtcV̊gť6Ƌq&/]x:9NuFɇ&l !g΁n)iC(j١Dck.gS4ɐa/hsjۗPECC4;5 v<;7E]1g#I(&R*b'N+IWq_R ))4ZSo7iB(Pm T~x&Tz\G`dΆvnߢXNR!RsBݚsU;s)25FAob3oթ xx| L{-(_ÌI>71=WB.a8}kc1a~@+Dq/gT9F Gm6im' 3TS\ 짇3^:t[jc.͐Q gE&圡*Czg[w&#i[²PLf?9@>(N"6ml#mK_5$ Ke:9*!BL8 K X5M]ilBg~ ߓ=RÈ6Pۂؚcߠ Y5To%~6~n (16@Q̑ŦA%z}]v`Y|ö ~F&G/ɭ=p/P)۱8TVEP*-$b;Q뷤hCֵV>_)D]Ml1/ ˰H[O"\>J z%nX+f-/9jl,_fc[qtp1R!Ǘ 'O $3c|ka>e=g^miƲ]'UPϲ 5E+#\_k ;axujm2G0/ 'FA܄fz|H”h ]ZzQ.{+\6&6-D)D( mVn'9<X^>8RDkBą.Mz(8L2`3ѧ|Me~=Y)6A6X[at^ !lek?_dDEx"2(tFE4Qk[7&ij%j"Zewn8&Yɾr#,j*7St ͑Xwւ5XTǺDE0iXLZI1|h`4λ<\ Å1 k! İ3񬔗hrPDT: P bIXcǑ;hX.>TI4Q.nBGśY}!ƛ75 2aD[t{=W(J||C9w,ksHnn=I5#"bQRypI_GaXIlPȘɢڝ ,)q,1HOx\e z 1z`䘽 ԱfTG2׿HgI# PPɒO ̤ HYH Qbdy(%mGG@aun7!4@♀!E&-/G*2 @Dj! dH3tq[OPSF~ lE66adepr_NAT V+ D(E1I?QW0-8vid,WlAL\ vOHWBr驪sgSŹBʊpHA}XgQ$ JG:C,nߑ29jb8֤-hrNC?3CNC$>GhTvJ-x7R)r'I$h,Wz`ȝ+b rl bL\M[&A}P g>xX(,l>!*~"(?hlm&GiXl  q-iB Mw C1&;UmJU(D.G3InR~ұgQ=g~f$RufOrr`dD~Dz0{4ҟ⏤3u6EAۤCIJOSr!U/HEoйBfJ!dsU  8m'C"͒)$bR3gqtrGZ>b{Miʏz$(>k~az޽SƦ/*6_3m݉E>'3d}R`TMv-K`R+$]FEv]Yaeo/8^) rیY:__K9LFj3l_4a_`טgv~RF1oICzu#rP"x sˡI> Mh{;'iѽJA~}$Q˗)h QfK#%~ӽU)s1xLN@ML0ywlc je<L h\*Z(k[|۵ ~WmޖL3f!/ǢO+i.ьy$Ŕ5*郌77"|.{HIKL:8YXVl=W?Mbh,.ߎW!OD+ e(5 70U#]me':eԘ_En'x`Gٻ(? m{E(1(7Z^ uJ X^9T85>M $]hsC `fS>ibđ0=5p.7o* B)巟>"(f "pp3]-&% i2F}tc5z7ܵ×oxuXJ;N- ohD[5 ,NzUx@{Iow?~LvP7dֆFWP۷P:~Ty8}Ј1k<ƜiaΨLVcҮcF;" QIޮQzBBK/KsVQ w\(L 3ӖR߶- /ytNHb^\P|2^t}`ZV4I)ьh}AZzwm/Lد g}mmW/mׇ;i磧'}ml/6O?6_]_t<ܸ8q~#jjEmgzEv8Ҝl*c\Y^wC )7Nzb(b9ΘxL7G8W3+12W/bڝY52l^4F&_5RtH َ$UQ$9AvAl"%NQ@YV6 +^˧ճxͷ֖ۀЮpR(WG1EUf}Yt۰A + bJՀ"gCGgdxE![<3T!=$Ϯ\ݸsjMaY,XhR돃+3c;U"l9Q mkx1KgQgras۬1mD<aԁzǢU?)R^W/ҿ7QzWj)ȔБ(dgZTPLsXFgܐ`P7ivg>o x.RB!fm/KЩ>Q&rT,Ǵ60l؉ ]Ǣ]ddW%R:1(`{mls_'QWI_K x5Q 099*m[ˡ>1p5~CF<9,uchuv(t7\y鳄:3a.8c?\의82۰4d^&**09k0:F=_k nQiqG|+ghfzI?Y>8b1dX!ӦJq+p]1I -T-TluoHe-$W璘7qdcNHxwqVUv0T gN靁P?YYxgQ&h5hyceEvG'K >J]*\KݢxB5IR3O3 %裢+'uP_rfT0x+1K-:n).kID%ow,mbX HHRBEUB̖Szf_/AT{zME12 &e4PAbZMXIyj aDy~:Dt|cX1tFW504xH1~䝷Xj/R[#&BQm{˰" @,~ 0ҎȜg54N;vôx2g{ž笓KF"ɦ"9TK{aLzq6&-rK*?9oXL< gQ"v)K bWD~&SnjE4&fd=ݿ# #Žs| ޔ_PPUھ $S*S}EEL*05e }tO7=S%~rQ[Pr"[x,]87Cw-G~կ}D t]( ; ױxLht_9) aZ!ZF+jg0}_ԯ,[&!Cipn?ݶjToGEcU~uW>F4UK&w[D%N^K M;n:P_>MhRF' yY؜3_g |QΏ}芟gV0ÇBC&-CSX { WQ֗ op5-c [۾cH' l/!8>o*1Om- 86esP;ԉ+'}u֯f$$Q]hw|Y[!s$N@gh5d6GVCrB4 ѱMIU+-y+=RZP] o 2SL BJk)'húP};bҘӏ$s3 Ј 7Sx˻yFX^yxm#:(]2 s? di4-`4yrdivz)HȩU NnҸr0A*4['"|F&-a,[#ڹeZ#"kpM}J)m^*k-}e}j22RQ=#b`h1 f G"]ø ܑj?`Q ɸkT|W=FHOk6f#{8bvW6}-AVHJH򞦵V(k#'<>sw)r;Kg 712iXe9ۏCUlU0cq!kc6FmeXKMњC)ڨxf7(%%4%\]s3}.xPwozeoz5 }i|Ȓի>XD>FK7&ɀLQNv!(JM)KGz1MNZ{e=b Ul䫓a@{V&Rcu7׽ A&?K*F_hOC!]e╘`! ߀77l P*Slޓ߉28(7{e'wLʁϮSZ6!`+vk}þ"o0[(@=4HB%Z4LJ\MpGWm,]8AEQ- hN[B 67 leML&P]8Q7|"oǍv݃%vR0.XBJteמ SKkfKu+z ђdmUo<=/Ό,5!:x5TTV}jHtTox?]==fV- J%tuEdoHSɔzI(SUMF2!3xUv̫SZBvR4^jm:1*A?s^b呆|# 눴Z慄$ChФ B_ Eu1W̴%/ΏН-py{;"Ü +}(ߕf:uY l{i/O(8GԯkڼN Ȗj7s6Twf$J!#rqWv^د9"[; S׀?KMD7Ỵ/dXelsB/Vh&m@ 궡'"!5>v=A:ܗqPasǸLK7evxvkȵ{5}@Ltr$YLv9FgLlX]df` JgWx+-Sam_;[tT*"+G6"2 ޴$la=5ktYOSퟃ=GGRSG\99BC2g& "p! 7]O3a7rl]$t^ն$ɿT~'kt㐩(ܡDpciR->gFY 5ʝFl~CU;!8:ϫ؂Jqn!C'AJa B9a~' M}|7TLB*ED>=D%DYI!:NN9L=w3Hy &9LMڜH4P5ZYJ3 };K7le?"u+-_"[]+"!7tNA)o[񣵁JN!.WwҲ5AEHDC$V1EHC=v?JM([*+"71yX){UwUG` h2wofx2M0ǍJK(1%I5&cm^ unm"ck"zAf4LOj&&B2xk,~Vy Ubv%"BHbMpXA`v=!ܩ$8IcLxtB1S&Y`46ip (!4E$H^ck̵c(e`FL~["m|69a mV-,eؙ]vi\Rs3|4>TA‘pm4F9xƀ7@Od; ;4Cu$c4]AR欧17C̠_CR FJjx-43m瞈m*sp@p:uV_pYYOtKJ91_m(Qeׁ}S#j2@LAe£S"690W3fdeŵ9Ì5d1_:o-bYEQf)uk wm25%aMbir^X0=)vz5 *c lqjAEUba㔩rog=N]hg}o"Fo7ͦ>Q}Y0W%_mpIn2YP';a~vwVAVlBw@tf0m?z%Y֪<yg"-}ť׭ T-ĕ +?Orw*-))$R=VY,%kOEk2Lh浽o%ym~oƉPdƿ` $_OMee'`)Ǎ?RLH<~Ts$[ݳ5ט/Z`Z2JQ_8g7UK)2bg<՞l5qTlyɃFlu>hsߠDRpŢjpy۞N^Pʰ{U azT7QJݳ=䃓,۠ :_lcXG0A24-]m۶m۶e۶m.U]m[sg5o"-3.Dd/26/TX?aaCnGYѝU5fG,NE1Z>ϗΞK~2#a:s0d?}/f*9XYx\mδ򴝂*hRj)Xcvs8`oC-}Dok,sǾ JZR9`o;ÐJF g5ܻ#laZ\އi[sr²Ur@gՐ9 ̗\4z<[B|^V@Ӷ|XSMh]#ƿL&ˀRfk@hcuo|{:c[3)۠K!Q'Q`jizFЗH/AԸcH$An˞ '"E^on+ {1n7Yb?btjo]N̿sH zf{Wi0D D` i˨TMP_DH-ouhq-O;sDE]]$j/?MGCa!F6U4R7FPhŊUKǞk5>v$Cnu/c"+ٚT8O;g QŸG0վp4ǝ.Y.:7Y;*cԕh&NsmƹDsESeCDl/\^'FGj0bd)"h/ 6?_2DBև_ j#QJVGvpPStYQ:DU*Sx6; _3}+]ƳM_!iv~ang π&=(ζ\5Y/ߴæhcE"z(9D4 jZi>LZNsWa&IߛVb?SjbTg㽾kwdӳS&MYvz7t8N>wC;!)|QC6>(ͼ,fDhHCJ};pEόB\RZU z2:3$Iȷ\:، ))%Ch@(#|m4y~72{ :g(3B%P~̃Aa.0WXz?A. ˥@yԈѨ_8ewA5Mu{uIKjAl#bɫQw ȳ(;dx6mW(-vql# LH: g/6{BhlqO0hܘ{4Ӡ)x8׾. Zb/&}״M"%tyeHKDy$ɢѝK,Uud,2X Q/C흍Dd~H6yx%\;6s8G+~]iR"Qg]R k_֬;9lW9}_C+\ÁԦ.ck Ƅ6#T2T\54Vhpbu >Gd!y}Iz 03~ODK\2WDsq6\A"Dl4p(KnNv k0 t%"젗=O V}F6Y ~RFw ZaO0ʊhYHj,"6JNdNAOKfeMafa~cL]8 AJ='ؑMf"ƸizZ"r:XYJ?qyLx!iL ]lAڮH|w0,աVlzl;R*?%JA<0^:cQaGHrN¦{w !eKm7ގ`1p2M#)pjiZjk\Dc4٤O)Kt`PqGFVT.k.W)W7=:ϑN\9yyt)DIdz ]OZ!]HEIug1;C#2+rk*Uy[z4 tiF9=E5)gé] ͶΔLU1%5FwqSO[$"=لI*nM9ʇf34SP>ނ\u o\A}9PM)R=i m,;13`C2}=M8 nORɘwNfO~(#[[^PbXgwi-GFF#T\qt?r%Oݳ5qbP<ܯŤ`svġa1yC8ބ&9FcU #~Qnh$9nvZl|>vrC*mїm TI:xѻTs Z@ѵ({+F1G.`l7xJDƭF\&%]#|]k D/"X)<^D扡ȘBAYn#V<JMt_ YsGCu\t35#] .?J닉h i<,c~,M-u~LvM(*me{{+G_9'YC+ZBᔑ*d|$P,.1@+e`󓄳hׅ/p}5%2MX.?Tg1Uy^ǥirIUS;56݃xU4w?=:`WbȨ:WcR(Ⅎc2(kORdED. mhdb*>pcڻ<ڜq8rg8},QdOH?f$v8O3R43yaGo bq>iuOy6Gp+ !:/p#+5% 58JQ ж.yU[FtQ} Xy {u{5MI/ &1%]_ tw0oȖzi\/&SQFbcԲwH+9=WT.z"i XVlL3Mվ406k桲 4>ǝ -aTg9BCkd;V!ck51T\3CD{aB&v% RÒk⸄CfC8"1܀ I"917E K:L'^/Xgikb9OwpV\/Yp =x#ըXeerȪ_I ^Nka+QEI@&KT݃3z0 z-!zЇYL݉/[F1qQ Zb5[Qs ;.d]j{޳_vwNjߛ;U'H[0w*I ;.#M~{{qEfl8?I HύFl\~;!󬆎PR0#}oaB+vvvf9gn6KM0/x {s7!8l>mowH=& yusk޲O"4)Ydݨ9iB4;l0P=||f0oJ/ymn,co_꘣>~F ΣLfs:aMf)Z'Ơ?,S"XYvfu98lx)9Hؔ[+E|Z5ӺٺH wj&Lm7h2h \N~ Ko4aRa aާI^c2mx?%[f&],px ITA}>NX7TmSۜG'US)ʻ(GńQJγph;YsHO*%'zJD}? Xt{aZDdсo*fB?1n![?O;DyދZܓVBg\f9X-d !#{niܸW^Qq,_ 4$؉7yW^dH2BLލ)}ArKܖʒIێ{Ùh"UiTRu!SKf"Q=+K/Z膪UVu &l8w̼{~\2nfC#:K)SCFT6JtsFlE?nZC(1&[FE ˾{lmm3;V-p}]/ʲ& NبkMޱ+C$(>Y41G*Jr4HǫGvȝn|#\4I0b>yTg&ZYb@M+SCQcz3A!ifRia?ft"M[aDios/M\p`>rmytD?qNCR' 'c)6h4ú9>_peyj v*o6k{u& ~HJ"<$ooZ'Y?u4)ބO?2J KgGC֭hbm(4 NHW\BsicqlƺtTD`r:I`ܓZL(2^,p3r;9Ĵ>T'Q}%)=e<́늏 GDmbKcw&FE*n?SC1c #Y%=􍷴A~jCV Ayyb~2ә߄(& j-n-gD՝[J|k=X}]#F-JU1/^a #n*tT5̭/ İV'邍$x<a.^OY >7&Z%]ʑ"$* U%'.FGE[z>C+@zcnU6򢤔g*;[40~356M룽E.6Dԝlk4*IA'friƶzJ|[?畸^k$ZзKG;,/ u;KMaZ 夠蕛UY!MoBΟHgLpWx5ϷVՙ_7w*Jםudw1s&Ύ*z1yHq5Գ=Jn0Ew>|C8{(0ZDW9(Ym)ko7;rM~Տm,XOqgr*2+k0 7Lh%pɩȜ3\yy5gk|3_cFr78%' `Sl `9~+6Pjޫ j<:Bjztkq^(U~_{uߋD ̗)KŨa7j u,̂$EKDe}gqШ^^:_$9qzEnn%ѥyUtݠOf:RXb١RbULJ݁ݡehz Co\vƞ#Ē$+פɁr*m$Lu$u^wж!1augӋe/.z 9rmg.i~;kX,yNOk.&Wi)zc!)&_Mw.th j]q?s8qn6nNc]Rx( Xfw!W=J:I֡@ב2ڒ%¼-[4rB7E\cu.u`TQKj (ziE冇+Fpvfc7j:_̙sl$$ L))'QxEJ!+.ǩoaru uQ#<ʨs;4~zfmY|P8ʄݝ}91xLGJA.ف8|ԯND cgR=G@=>"3nRJ\ "s$`-BJ~i4)MDI,ϩ~pTfe=}6R"7td4k0H /ǘ2`mTcvxr]!vrKnm!K0m" dƄyoL+}V h)|+㩁6w%(~9LUҹ*€܌?Ax+G(D&ee̳ʻ+4g΂'n!t/m~(EKaÑyH_cdgxG7b.G|qsrO >;׭9t'm,ϪE9^4ŕUuWt ]ZIhx_ wmuv\p\ڿ|)lny#c>SO/sa;?k G?cھ_(}'zPoo~wU(Fk SQK2Ӷ;{ 9N&P7z&6r>N6cI$h#^{gJ?\^l7ify|9LH+Ea䞘UtuS=j[t jm.fy%;-FƝo#)ӽIdzd`P~CۖR;El7F'*sC#ai%kH줥Oz$KڮiU8#OC ws{a1\e2mqR:"9^5lTƑ'Ao8`/'o:HO/_Ji%F@/AvKKM6W4Ł񝠤@٤)_܃fQ^˿Khm/"U(f}fH2xoׇ}0CZO[VI`W}٧4)˸3D_aAGmsscN &}`fF |*+|1w'%M.q3!k睰PG GcY6ʬf{:EU9,#v\t<.bA -U(z9yrA/eݴ0 4(u%,q4qfw) HHr@>cWB],"I%PMP7*#ťzGio} j.ށl%(c?qpiERʊd-V:Va< vs:kG+/0%0<>=7DJ:r0&Kި5"'L m&%rxO)-B/_ \.u-' T!yΔWKrWp`Bs{ik:=Tdo/M >f쾌1GZI$!2|on\;=0H- !Ha3ލ72ƖHOz-#:{0=z3C4OB9o.>[#s;}_@@M't3Eu6ׂLnfĂޒmq&<Už2|BrL B#?3 E$j9H5'kӘ{_Xj4Ӏn<>%5N̈́Gȴ$m+%+lXrN塳^r:&-a?3[=^֤|nl#^g. &[)`nG-ʝ[X:қ [gCmGL+Iڭe("NBTO$7E%W5ScuѹTEC"Q*gX޼bpV o3o;K? .ҫ `M>/+ԑ9|4gV;cd,&4&jrpw!ZIcE!;ǣl)hfde]."UR=ID˦ekp~%!GR #G -UkfBG)Z3!3b wN+w:j3#%-{1+[,ЁcuNX2'Q>s#:7™"L j1>xV^3ŝe2žV iwN~Z2KapqA3VLS@xDje Q EU嗁7w?oIOQ2E9Qh/g8@0}3hǼT 2"ofURQٵPV&+wo 2~rm-8Ora%0@{0mZ˿& M+l)}2? |E5OR+0rב hw"h/cU"aAg3ogʩ1Or}K@LdS[h.E*ٔ@[td⁁CrOrF<09=^3I!PcO{v{*rKcLlj/#` fԦӒ\& 2C'Y{D5G!VPL60l_)Ym +*u'%Ff j+ld?٫8H:gdN%i8cyEQb5.FXr;/ڟ+"[Y pLB?ry 5}R`Ϸ%l‚UkX+;}L7 :w#6gP iՔr:/ w,f/Oگ^`'òSjYVmܜ=kѥjZt~!*C~n]&fj`0D؉.slkiuE=kiC=ˆ ƻ aWk(( b*E!Fp.>8 uD/X&2L{=f?ДB=We\5;."]qjGÙ9.Oa`21)nʛ]֋A(=jv.DyWOE'( Ϳ@f^`n恋OZwa'?#i`QcÄ^x!Mף/i(2kRHB_0*, B.Eo;oe4AZf3vL&# PNZ2*LSb58aWyNȢQe㾑O9g^ F [R~q,[.zav1V\Jo5`"YFy=h,DC^͑qt  m F|@A,E:k"lϷЍbf1u 3OTZVhk#)0Ud9`&O/AWu7no!o/ c#% n8@hb"c x%v>㉋QEœ ]U_i\d/I9i^5Ct-'Aǯ?44ؓ*~HxBY%PCh'>e=>L_*n?X>}3HFC:MT$bSߤdy1Fu(?%jog-'g1eqnٞ+<'&Kl["kDu@]" :0j< fSSGOV:4grH Í˞ꞱrU6ESU?bI- 8g Cqަ)(k–k씟v^'l.mBE%iK?]7ͬ7}B4 , &3}~F'~| "_æxdz@<2Jͬ:{m¢塂 Hd8'|>dfaI;y*vn%3lŰzi*u lW;{5hkshf!Q9r*Y% ';a5U]T#V¬ ^ПzO!+cWs Q*Xvf}Y=2h3_DEBgnIj<"& -=sw>&VȠ(㏫I_T3jb#[m1j7KU>{P-|'ݏ1HplY`b:׭@04SSeo gbxm%pgfR 5:\/ |ι'np - ތ"C>l --XXs}$;1}pWz  dfI%&Zlb kds;S:0G͌t>)Th~(EP[\˟lqwx#IOJ8d{x`(qŻn̶f o*鬅uk;G̹ϓIAHf¼v?\cN~I"wNOQF A\gT)D`>lF5o8eVD[|ycԍEfVf{MW}]b!\Z-jL\vdPjRVfYAgTe mm۶m۶m۶m^5lINw۶7MyCWZ`b_l&ێ&B# 8?OPH6brÁc{w3--K% w|(Ji믥0ۻ236;o(p"Ƅ*PEZf;_pB8Si;;u[m] PhReQ^e9LsYVl]E hY#(4!fZ4Զ`uoS;. PBH8A^գĻo=RQZ⽥E2-L`PK`B,+x̜B`} CcǚakzDxԉMgj]ZSNLeў7[ K6TbdKuNĔ^Tٹh Jvo5cE""8ֻnÒh>MYj`!<>_ X@OuI1Hvb_wSdwu20}ՍZS n4mDRsCE!e#GGxn:]!d=Kk%_όvxخsWTz'`R-tNRI.<]1쉷̗fQ֒M)."MaU>os&Y{Rܔ)US/\J#\̖eN7jyDXNoO]۰yj=&џ}z 30GJ H #dgțFd!i4!Iڋl[N'`idX̽w5;-`qQ&' ,CXn8hB}ku, *@*("O>fܫS\m)$B]DQυ}{H!kUCJ_y% h-gM;γ?]m7ԡdO?(nR:\0C"Y_{S0-EBTŪZ|aMjGn0T%M֐%f?uR&E.+QI8D؂W3e lcM +hYeƎpl6! D Y=kTD^eBIcpXsShО/$̶KAwњk|  !ZB \)~g̢~d_s@z)o/' W-/7JqJ/S,8{%;ݠ~DZM33QRAzɋ9(DLu7x-FH푢*S9b"u`U<=tEe1Tie:#B=e?|1@5&HYWb^+ۻaސ]uq)M <:=Pw^3F~P"l?LHV<;^yNQY'5Ԕ1耕IYIBfz=M&{tLP8^ZfE#,f( LɧExFj[HQƤ69 1l]/ 5ko޸(ǵ2:)>`} 4i/G>F*i?wE$ëc fH8 $R(ĺPIwL:5b$Yvp2.`یP1vx{p@3,"cf@[RH14bj8d$x!y|a7l>!=֓ˇ B`M`Ƌn"D ˞$fQƻ jƮtDe1jA/=B@D!4ZnB}0 } h6-K?b w!Ŧ6ژĵ7t5Z:b9.!yCxnFfrHg"-ƻt#\Oӕ5I(4NՀg)!WW'b"Bdg"DL['/3yEF?͇!q.EʭTȒl`: Gfں*ztt%nlo !T\߹c.^zN$@fp 'w7{f"to=#h D넓a;ۧ+Db%zW|C~ze+t gy@T$ ]2@#Hp :Y熙P *ڶF0(!f ci@#zةEk̵hr3S™zi@͜q 4M8]vEd#ό.ImPM]0sN֗ΪB P!}. Z1zm{hIV[A~!bݰh}J2*lts6|TIg`S9ϗ}b+&h R(; 3cp^I$ֿ(_+Ly<].3нBJU]I7Q&Ώsx,9ԝ8Z0',V`[!zDu4 q Uȯ͗]JQ*{]9T1?0˿ɖʊ׆&ΖeCyu~paKM4ב7i[ Gy keG0w[>PWUe<g_g)Zپx*ں6;Z}%P|kyiӥGP1Nm{2Vղ-_qPL?m)}%H6ޕu(9HahOo(BYi[t YmVܕ ?mx6jdtV[Zi#zxؖ*2luOf1,o>#PYȬM.^Qqr;*rʩŲOd^KҐe?)f:^qaº>QM;7֢0c7ySΆʨ"79(h?:D誧s$sn) }mEq~~iǩfpbs;ǥ|mp9Jq K{)gh]aiŚ_^ !1aui I>NbhMvN0~Aq+~}~پޯ n JWWO?+ (O?v}G!^ھ moL,Գ)3^OR/]|aq.Wڋy.-~exvk5i/ qlNj_Q+_ 5zy oa9fI7oQt=1|iW WH,ۆs ##/ck@l7*w H55<]C7ӳHSJI e_3Ⱥ(Д]eւ^LQt1続UƽHUmLU3!̌SYڜk&1)*ላ &30ՠUE#B yNTT@ e.46&%{Frht \?T i;"O dgV IƤ}yzQWUW[{d&|Ye@]="$*"v:'ET}m%){fAMD\!n/$bە?HK`̝!Z S@M!T6%e[έ]\^O"p<_q|sP.0yeE$!vD}6K gѭrcv- FwYHP2bt vHx,Rl,#((f4 2Uq-B!mWh+PD:>_L+g gu_- AUΙXx !H ?bѽ26AE?H$ RȦ|7ƶN}fO5\N,#Ϋ) . yštrc'C)zZ;v3/IrCE ɝA1'Ee3!Sv 6 CtamR2 [Q[>jno[!!dtly`]A!C E,NНE onB(,BF@U|13쩯SJJ4ղ(`GR㘛UD#Vf& ax7.@^'6:Dd$#6tqsᗙmw񯜀9T Yk*{Lj!f$.cC+ER rAi#2(nDƆt #Ffړ<tH>4%fͭ 31n)B` m#g t QnvOI=29D@F&5Z6/a$50)\ӥk`a4afS>!ި̥1ZyjxK`f;Y*7$Ra^jH9Xt0*pʆ.pS]xBL8 ɽ&d/~ZZ* >#|ӀŤ.?%[[IMY`\TJ)1-HSИ>Сm2(yYj1;;WF5aOrvV0K¾(ԟ._أ0:a &[fh:]g_D&쁇X]]H/M=|k\_ 3ej [ <)|DxqJ i&zh2mTYPRFzH7D$C0Ϻwu>Gfk*#;ۍl[OWWhl B,QE`B+]" %}@Oz'*.Xw2N'*R` *>,c`7Tco*ҵwqu <[ Yl)9Z; Q ]{_ISHZ.̚~L9] 8ҔŇVZuU)*s(OkJn"Jo$ᝅxԃPJ^=) 7獱fOceƉDf:zU +9ߚ {b[Mlg$qx0k lhyN>̓1}iykEpi%G7_qLf §>ٯPc_-0jL-4aI2Lw7i.j]S[Bqřוi/1תؑp~ιdX *7-6xwjSkW[&A[٠gWp"|)5#Ū@8~nXb7R0(QJ.X bAZ#[gMck=DžTAYU'LB%5I-crʝ_~qE" n$1,7}{4ӑz9*UvNZDȧ?{c|'󧟼wk2s0i02T 5 r?##4ugf<':g~T.w_ Zd?sxPh&l]B.V! |`گ`. emjl%iwzu䋅!}VzZzW6QJgXK-}-U)jty"kyΛ N^ƪ ]~]HtY Ă\ (lM>d:xe[ƛg/d2M~_\NEr !> ns^Z\ 9;hnU텒ނsu8 [])Q-}]ѿ]m {>YɘQ|&c=j!7XJy<_Q'8|^0h~D ` ɡ|ug=+@tB`<Ywki>**{8{1/Qx<<y_%,rs֊DgjbyGNi<lQee#šX0{i&+4h$8dB3 jnz0$O_aAlm !CrMme'.r-s+T^ 'TGUJ[V(i$,[9U7ϿDf΍Ea(NGzc"\aC4Bjf^'$̦fRPOC_J'Kf{V\付3ȓ^VYճ,*;avZ7 yVbڮcf;cb8takqU\|},MRUu{8B<Ʒؗ+#eP J08 zFPWQ`)e͟ s&J(PvmzViL&u9^V+G v ,3D1<#ly!m3of]w`xx8-5WC5S̞CEjORn֣*tb<gՅVSmf]0lXXLԌߥ;+/|d̆:K*H\dC/Z S$A|gc6_ -bFϚ-U<3}5&PB*'mJ|pn8Ki@F#]WI- UA|1-]2$K5,"n޼1UKVF7x^aE9ڮ6&w&e]_\DuL1$PT+R&'K| )RmoojSNT4}YJ2*%1â_]j̟VE#<*+TĎ*.\||M#!H=!i~ Gt`kHYR9{A6>Z00*FLFAJ$/T6c\CPDhSq2hH%^Du|xeT\=w(ع&,; myn]9Ѧ jsȔ|9Kڨ?kJXYC2fHFF/3$V 獏1u:W4=~t}\h ٮmwH$덈6d-*.SmSH&)JH&=gHcD"4kHCoړrce"ERG`fwL풅oZ)/sRcH}Pg+u]_/Vze8:hJ_*<׿"nE6:?z0xܘ2\aOrE=^Yƾ"վP%H#tvo9ʬ"zt&~<]!>1•HG kW(ve!xVMاCu0:B 2kj/v !PX}'>0-C27w><[E:7þuZ ~vsP1 ]2p/./ebSj6 4u*U~x(P`'2:Rar:eLAnqd ^WjSA_Tҩצ!;>zf(8n_^k ;gQuOԫ7HaypM;zaf6-g3|MgpB(XVG;tkfxr%omf1,UsW=TpNհ_ d4_G T <]̬P.Ko{=>}VlV=,u pT|BU& wޱ4%F,}OAs\Qëv,q>69P/̧mP> r0hNyT2FkQ9^Tc3Npr8uu™kd:ag=Gr5 Rke_M_p0I"CEƼ/&4}a}$E="ӮP$1hoS%儮} ?.Ǽ<}L-n]qƹ2øZ+$]kC]f.:_JK v_zh55"}{Lwb=XIxZkP&3f2f6Mjj6j3dU7i҆bP_(~Tۅ9O%[aBoD0C)q=uڏ. B)_)qM#btH[c=85^ט9iJ9Tygչ^eH z4iU0wQTP?YfRТ>˧"zɗ@;i 6B Ve}q꜏&Ä1ʝn~ Uv[7X xKa^0kQYNl$๐W.LտYL8N [_yΚMi6]lk敕ãMs>Y럍?lwBp**kJ!LjSnSXOR8ɨѪAաz#˛)x4Ж47XXmE'䚖m/2ϜK/rB+q`7BpX#X"RVYHի{\+3Xʘ+) $T0{EIc>c`bkXaFdl/9fq0).j#̛ [(\Gǀ7v1dI&P)R ΀ UC7jv I:#Fl5exFJ\`z[_!tM"T.8BVTBɫI$9.֕Fqd]u2nfj8dL'2Z̟cUc]C}Y}I%r e\a&rؓgy/|ټ7v ׉/8 c4C&B=Cnnsp/LjqMlx~boT DKFJʑ-+h1}syk،z.B0AD"\MRd bͺL8f\:1^;9 3<*Z1BgHvxg1ѵh,s9a߯&HD"cMIU@K_Y4Ҋ+ X7\7jZ3/YD>Ѯ']ч'EMхe05t wMbT)vUzM0RݬdYl5I=9OJ񽳪f&3Ni,'!wMinQ|#* v DZ}ZKZRGb&"u$KV.:X%؋#\Peii3\#} /fQg[ ,WD]{Zj!fffn\ޭ?{Υ:sqV] uV&Z؛rLh+['CQ!>a\LĐ-ZOѠu3Rqb;f_>Q>}7 69N声pEaga%{̡52L֧}'ה/ /]7N.5b͓+wo6AOLׄ~{?e>w%Da (945nT@O>e9;?X-PVs_[ɒdϐdj^Me'm%lWQu!agw`¯`!z[L6> HLO._:`s{Ne`|ػ- v䒊 $ʖt !Td/h 3~FBRw:VͯTyL􂑕2H⁀k\#NqplmYK~>M GXHYga fC8Wԛ]aa5Q|?&%o#y/ntqb.Qbk.k Pui2>jQ&) /h&K/nS+|S+#{2^ouj0r`!`T.8#0[(2)HH\Ld2t݋xUVbkVCjg}U(i+L2L(a|CVm4'9 (X#j\S,;)&e#R͙a;Ȼ.e3W^kp .--z?-e(K0Ӎ-k춫$PTr4K9݇( 4HyH )|.'b,g%Im z2]&<Ӭ3ScW&ڱnd֋Rn,j p*.[3tQuÇr:O|,Yͯe s 7*|n~9FHbݬk=U( 8BARM̞銫F3ei,cJ)+kɺ;npt7?R‘&=RFN d;@bҖ͹R47h+jZP.Ւ,c$$< v#w,Ú.]+-W{TbDo\ƮqRkg+:^2!g-4U8ZfҪp+n/ZB(ڃ%7C+ቴ7tV ^9;~KעI)N2% 2ݺۆ[c ^!02Pr *w%iN'+;B9 zAFtD 4ϡƚ~Ăs~p4S>VZ}ڨZ c&7*"_ jk`6EZn=)'gS)h[L% <0>Y8bvnTPӊ0(ݭ^9Am QLR+}Z-j "oW57Q%HHt'm'' $sFd<g NOG5GWW;yvc94SA[Y=}HƉ CJqO+5@=<T%{ Y{ZM_ZI;E}lH`omW;-O߲}a%P= 6q>cMGF'Y=K~@s1:&j0C|aD!RMW%׻x|Ɣ܌{yg043+w; alPpC ťUיإx t7ID^}-UkQbqo㾖`|M:ky(AQ~f u0;/sOpEf5C$&<}b,^"'}ojMKqlIi^ךVQK ` h~~[^2ך$j֒c!VY';DD 59fʫbwٍjUbJ0zq$R)2*S;6O.mQA lwz:.l_}< S~D}K:a0Ov ]9Qj&xoώar2y>[R:mI֑IumLvu_Lj1&[8׃[^&iVI{xlo79pOX7-嫎RIO܂YJ#@,o'g3' iSZbG?Fa ģOgUKG֞L]6CA}}H)?v"4)r~4@rYQҒDχ^ʡ2r}Ӟ }$\q6ZB̋j}`cO̬fW=ƇHz푴2bfOzU3ډa\O)վ?Q/_&x q52В¡$ay䧦ZI7:iV2z@;#-3;!)l5|ylY{86 SCU!Mk1euR9 bރϮMU9:3Q L^PH.xaSkQMͲȭh{n6!+"RDHa7O=[<_|k'k[Lӝ8rpL!ilgqH6=TE!-z)%G䝂tnm۶mvm۶msm۶mgވ?V˪XyNPIz%h"dժsjb5fjކo{C5qvN7-L5zF}>]-z<ۚC}ppDD҆ad{ė XJ|wSz-.Z{ӊx8龴?¾cq K;QJ)Nkn~vk4S2Q:T 2٧M+q)Q [J^TT;\K迱3y/Z]m,gϛ^۸,c_\WkDaqF2 ׻?P)DžcJ[mھO<"0OS:SvC$3`3):+\e,~1%M|AjS Rb&IJb 'kBY377yN!-)i&IAYi {qQ"#qs j׷pWL+¸l#z:K>84!+A4;G}N2+}2A!z7m`)DL`*eXDFew[Tf6@"(z"*7$PO`Tgz'B3d6JWIRDzX_q[J{Tj.b1Fbج[¹--4wAtq+kjN*s$9jY+L|&o:Fl\}D=`HՠCzWpoĖ]&X[:4KxX7VLяX\̠C[T9LX K+^<m" o˖h k| M7%Alk@߭9_x&%sqᘨ0 #!bcpp S31S"CM.+z0sJ;DsS)3p^ey^̾- pBPM6Zy Y%NyNA'zH+MLkMdgw]Q-tn :sVP/oUӗwg=TZ{LS^;*ky&[<_b2HmU¤.ZDsQ^Ǽd5tP$+~tg̽(+pc^ql!ધrؗ}DƊAFw`qT7mEw`@^yfIYe/]p΀ coZ(=VI ʦ@*ʲcP~Ȳ:@Y6[mfj5UKϰ^u3*&Is&zBQdSsuW(b9#.l żRJWi*& jޚ%RX%E 7Q[j=`|go‘ R=3\MViz.>.8"9Ea};RWRjg=)8SPF%ɧ$|ĥ"ͯapkŋS*A{EL]}R]kn2ve;jk:F5-lנ~,ͺAnRk+8 $ETlK誅\ oQn, ?%`o~<;?޲f屄,()/_X;ZUpi5ZBC_흂BVr0uyn}ͰuK?]ߟEz_T]OX66cz{?wzʽQ [=bbk7 tDڹyq1xy>JuK?S,лŋ~8EL8B \hNy>Ds[u¹K{GNWj&lʔʽ*X9~dDXiˣСjF>zγi g$$Iʜ'|zz,n*3׾%O5N<[ =K'pmV:cb a4 I-u}ٖ桷mV+c.*ǭ\EYD5n". Ot9 W,Wtt9N;w_/i})ov&rbvn(rr/Ľܠdi?E9K#׮q$zMP+Ҽb\x%Yu=٠d$^|]\_Yyw(2-z%ED_%6Ĝ&?.:ГZMogkZYK_3z_yUdNF'})x'sȘzhynT(|8R,C [L'kjT޷ZG51$č-e^Iٞ!0MZiO$`Y܍-06jimFƉ0y%l -Rx Wzq>>E#S!":&GS!l1F6^U~~M/7<ϓq'>yb̙R9k?\us;u_6k?Wmr!v+3Z5Jn2q*>&#~mmBЧAԏ kK^V0sSfEa60E>$ɽ\lxJ`4T012vkPY:?%^jUp`xMa^*,ӉtM4jUByw!1S,qKz>Gƈ*筦_l7{i֨jl!Ԍ~J7ݓ/M5gF}1ct/lcJn+3`MٶùV[yٲxk욷U:aooVC Gn> 7əۍʇOgaTۜքdC51+WA wEYq:OL(H)jҵ"9VB`K ^{4p) LͰ}dN=̪(N8'M&N33G6>xפm'\*GgYZ)sqFo_k/l]wbm:W$969;Yh$Va zyV`c[{ø=^0G|3qݘ9حmxvS3ȏWt--B(|JvpyR&dxeol=)0c_yN6 uȣ?_UDQقlUĐhI&0 _#d~\4H6FGe GxCM]!.7V_R6E&50p7\&ζl>ǀ߇ҙxZpV jnqEztU 5U[KncO65l 9ܹ儶8IPeΘK|_zG?aQq/wC J_-ncޗO;|S+BGa>18Mg< ~H ?>ŨQ[I t84,Q#M tI7|1ƭm^q5lRdh$9,^J:ʹ;u3JyyP=_BM"y,+Ek-NJ+ց $DzDsX?fpV(.hXT()RɚD#`I(Q͝!¸'Q)i;U,00y/kj^ի򲽰3QskS4e- GZ%Tq[d +tp\Ta9"UKv z##XT %~-V4[S,H4gbR5LuZ~cjjA.=^)wX:aNCcɤJxޤg b1Ւ9Bm I#8E]!B/iѩ*@Ixd"zDA *|̝)*èpD #hD%r ]q$HD|dX)'3,5BEtieaL[Y9g,8M2KZ"ư>h,(4\vDǑ0eŽ Fi:PO'~P8ϯ']lPOảĉƊ7<9X̊yQ&Ow+/VhWrw=ABo!#~'KY$hj,O7gYW5sigkgL_Nu(a쨘OL1(:΋e-d0+*3Xr`a5&-j#س\i|{7Sy¶ pzg ,YA %NYlX9Ygi_]_(lG, !@8:iZs5*'Xy+&BQ5 a釰_:dPHX>ڂD0,5q"CU@{\McFŧA K𭍖o?W;ܞ>Dw;⽭Z=Wr eER.[b~`*m(*N9eu^ G#Ekju*I"NLՕjm߱AHQ>bu)*2k[T]6!1q?Nx$\ vjtJc$-d18 w[4lt,ːXْQ0>n\tmS4 ykF6 WJbJAAHcEn/B)3LYE[]uE* a`&~Ş: RYIN}IK![WY;[VYJ鸖bO l`y0ɘ0ƒM12*?kE(Y2%KZ rm5[B=QR-E/?3pgRs~e~RakElm /~vtDNB=|SꀿFO阀jH@ Y SڴiTLٻ})GR10>MҴA|Ċ MC(Q򪦆0Ib>K2{uc 1hvL+檛?yMg"IC7=6S\Ɏۋ|ti{eŊ3${Yv4nAl`7E!%kT/cC,zE$JįkNi_B~11s\Nm0?hs!Ϻ]JRO'1qqjDUT2H0r`cc[W2t(O C! l[q+|҂A51P8 fZ 8^Ɖ̛3&5MvP'v!wbTх# >Pw)5KAjtwbYZ\զ3ieE`o[i3ҳkMuyZIG+dmx\$D ~9%7h9bvdG+\x"09I0(I!i2B"J49Xs}Lcl!,H/!&q:paLA!t# b'A\l4RJxLE%վ&u~~E1{a&i0etNh*.`7T>FtY#Su:]!M& P=B'"5$.Ÿg gaSs;Xb~K?½ N7k.\.2zbɌWȈF2Xg0N/A(l4^VXAbiDѹHUZB6ȂwK``͑Pbm( h LI@V}G$A# ail2vV ~LaF,?cK*.L3T Q*@ި˾节Cj*/1sga ЀVTvwe>2RD&p cr`(8 ]qZ I#ĨA6iӧRJW,r{I6Bv34jrR&T7V>3'Pۊ |M;Gu%F350$x"i$-vUO.9Jj9& }朂0ߨvr8Ik\dPaGƳsB Z|/xc? ۬iIwF^L[!;@Np2! +F-U ȹ 'FQl(9X(:1z`e8YXri{1, xD^( ,:A");p2銯;OkJ0~*OHI~K"7W1[; [סǓMJ9m>lvȨP"~<( G.ye![Ib۔zwJ1‚^CHCWjrFGd2hfR]SΊ&s9T牒 0ӥa}7ބ ׊ ty{&4,RY44iib ̴*GB0 O fS h'tn{Rj8Dϔ3bkXL7e֮=0&ΐY|ƾ!"#ţ(~ۆ4]MZѓŲl ,n"jj]Ӡ&&JN=q_)|+ޞ:Zm@ɖwSrŜׯ>`V N 3Qs{]gU b^.X^i_C/S=$ ʼg/2~͚Wp®h2LqqZɅ^n)zi|̘3sĤ&K t7Xk.]Y/GSpjxArVqHJ p`W !FBQ'P 2I9>nqNsI6qe^Z k}p&KED{ ,2qOM#I 7{wH*ͷ43Q([M/57)ـ6}#]#?K6d*/7_"⟆&CO}kոhBЉCk=O#K U$&"4&ڝQ|@]B`l߆kR|R]OSIJx.Xv!cѭP\+9Cȹ}>`m[;r''|8XB4݀"u2.IU8pD\e;CKvbF*)XfsٖO} 5r"]Ϥ1id!n֘fUґmTM{5\yᴰͷ,@ȭS^XEjedeA)#m"}rg["u|翊䮻a,܄֞zH^t K+Mސ*n̼2 ֐]F0^ &|^ 3'6_mo &fbP_Pj#qh@fW& bMؐ<؇` 4gz])5iA'KJ [I}?\fã13|g EW.5(ֈrρ޳.ɸ4DO0a͉8;k%Kj3LiO}xGNeiS6I4jRzE\5'gXN PV Kc<#߼it*o7_mο?ci,3eg{R#W1RN0?!ܘ+,xĖ42 1B%-M=8Z/>ή/P 3Yx\!9[ Њ;MKP$&@* 솚&bS?;)c25Aك`B;MoKfX]'~𘊲Z0Ղ眂yE`ekHL{?qSGNsͳ3ؽm@!ȕLy//Is QW KE㩭$Y-M*'a81W 3PT/QG8=WV8]JwC1,wH"K]w0B$PH\Z1 ,^lKq.bV.k9$PlK^@([}Dosmhr mͅ S9sOkAc7"Sw02n)QQhfYq=M}Ru'.B,!x.a9'Ӈ)F S֐e4#rћ[cjeM QԲkq K!Fk/6HZN*kL<{*BMU7S,eb+{?e : 1X޸k '9Z[@14?{Euun@WhghtnH~#A;SIr\(sR5z]ܐIhœn3"~ZP-+GsW•,:qrc\ 0!),:&dH}AB.١ZXZ'-ۮ^aR9!@Mn3"K"OzXD1!JIPj` :x2r2z>clIuxP0>Q _+l.!bjkP&4<oK_Ǭ L#Gw(% "rQгoňܲ{SZ CRϥe\eY"ahmT^uebmLEv5!K J3pX(p{@x AFK w*s1ᓼ5k;=ޜ'fĦ `{Du<׃5UCj6PmGݳ'+HPhną =XfvMLp)raG\-ĥP =_LSzCG ;>:&A[BP˙i#|ޣ83O r .S_v:UJ2sxn.a)h DelIL;,]pO+㏾vO|JxĝbXִIZ9Wa&5{T;Nb&AAlSX7,2imTeEZ3q17hL6 ?Cd&Atjԓc`L}1ִn#NkV @ZČ-?@vo0ޡ-H@eSuQ}҇\:M GD "$~M \_ͻSnaÛ\8qde m2]?fa7'SQqIo_>g\|XVX&rHpybBSD뛓WSyJ~rt}MSge|N7R]ڔA:_rhy{:g麋=ya嵩1"͎O $TmHC5Rii fn6'=[]3dP{XL̸;E!uV<ԇѱ+LS5 N6ns6[6>ZgWY&Un-&\}܀PfBsxzbf l2l0 9boҖ(C*]?#-XL7`w(OYco{|2*+JF'1@pë-}.VFcXQDl= 4ؔngMi3^#.Xꕖ$P+{|@05cxB# Icǧ(*G@/E6+.׬ٯ>dR&M1`DՓw""7:0A>F3&Q϶fr霈|W.yCuݹTuÐq @&Zl(犸ӱ]뷱v`V A7 Ym_ln?'9sgg '}"{,mZtx': \D?1bbܥL }'սf+UMQ;NdRllt@Xt᳝Gy\RaU[OF (LYx蝫f`l}d9oѻ{pzS?sg! ,j <ܛ9e7I@yFFU[& %^ѧuՄ>:'lH}êRY:=Y`<5&a|s7b}ܲAKo *>f) c9 F8KTk{b.Nq%p:pQp_6 _E糰1*5ɟ%̫[*oM̓n{SFVvqVA~VY(ia~/]Y}{=hАp̰*9S*qE-`-].}G5o̘, l!}BvIoTʛn6\$ONŌhX:O97KoȞzfʎ}n@ˠ"i2-#s-ζ|3~\!5?f0F4g@V]͎ nӌ!x+KPnрMY6H4z}]tU`( Śl#")6L$qԧL|1Rwa#X1t_;v=*]l^Df%p3QU1Ľˢ׶I)ϩg4`YT>ַY%O8~5 ˱N|4?\23zkܝI8u{+cl_N\6j>&,*Hfphf(ma\<YGac3(JIY.aDMaݱrSa-!9]-Ֆu H IU+aER@M8DXN$dP1'E(wSþy U'i{t%}OPb + 4&dg{EmhYEygTSÜ1 \QKmἬʖ8Z/6aC픱FԦ1ܚ|3  䛫2J0?jUc5ߦ V/6 k ՆxF5ȻCZYSڰdMf2h h.@:cEZRl S|v *`fCQB/]]m2/bHT Cʒ'm< 3%_'G$a{ҧW1Yl8q ^A"HWf|=h-x$,HRKY**m-!=QAo5:jt]`!mɑ߷9b?—ɭdYg>({@ *:t&!Bxr@CRٜ`J٪`\pU\f@9q+wU l, ,K 6ڱj,hEF\Vg-omJJpRLABþ*Sz"Xc+Z7p=ýZ* 8s! |D&BIh&ZAI@T(ߋ% 0S/$wEv˶]Jl۶m۶m۶m۶mg؝ H'ɘyd]pMCK$e$g C$`π 1_\OHe~j6eKmѴUڼ ygf.2C$CM/%m}n!#0畿TI.WB1!Rl-0!@ qrF.MP(E}6؍+*i%u? Z)f[_T2Sqn 6Ј2bT9T4Ǣb'a0+lSfO; =m6Kژ_Q520>T WX" NBq6 s++]3J=5fF2!'38 T3@37eW.ۖ[4|Nkk!Wפ]e/ga|tQZbfNy5 VNck]O@Gk^#h6IglzV>Kz9+M6"l@[~ϼ`AX+mڽΤ{.< nѯօ+V}v3lZZ}3s!7pv'EIR%m~3{=+<ڡ= %$nA{fU5Ġ7huTy.,`RxC=Ϭ>ugbL01ۿ1Wƴ%1+7!u0W?>ijK /V]Vuz14͡8!Bw𡽲Կ=_O^i\ףּiw_Fb7Rnv9w ^X8t,CjYA2D?Dq[GEqXI3_ˆj .<{r'Tw/R҃ [iL-sPX!W ]px B!OL(ْʧ".JņgꖓBƊi ˨B3f{M&_@ UI>wIf`[X!'ǬqrQQqŠGMnB\-g)IVX@+W!6(H~VR× cOcE+Ft vN; ΂ PO`b w7rDTd$ԈGw:%b;"sRCMVD0Ć tqw 8, kܞ؅bY؍LҬU\bQ}](8ROnrV`6HFC DwVv>WVbkD$lxG#l/,x~zv gg*E(z`OǶ(Lm$( 潩h090Xx/&-ewLy(#[pn<*V.K8\H!(jߏYGo ?7?JMrm-D;۔~Ei-CXLYU}2R/?Ot<=)ZF[3\'$OiԤJ] `HAu[8 9wm.yIz!ͼ_ hw(T&C!ppFg@r6RuzWPA T) u|n3gLѦ'p--FsRgba4)j%&N5 ;hmԇ2CCs&5f:Mdu})Z(F7 p)F+`}?cV:ϲr#2U+[_ eyREt hh`5\j%:T`rq3Qz:Bi0LM)~hI kƋ R:Bq#q=Z"1B1ݎUZTJn8ς3r?[L0|P6!¢.$y쪴kMQK ҕM]'OڧM4KǡILo8E4 O$݋ Ԋ[)MeAMDF7n`}uX1OirEm ?Y Zqы!5Z-8#.rkIq`U5k{DO-Y.m rD0#3AԖ.ʗ#@#ol={̇b@Ur½;s:9ۃCBt/8U]E~ys>M›ykN! ^3蕱"3cx x\0}XCқ3`q{Y2{aHDIĆH5ȥJaT5"D]G.yJ9LR:hC{x) 4ڨ%v\;j vUi8M TI榏 @+#:{ɚyxji5z6L |" th ԔŅ:: {0nEI(sT,Uk}sۛ.(2ڢ%3ļ֩~"z6!CG<7RA4^@ yhQ>݆Tṩw3l_kO2$MS[w6TqUqiy eؚU:Cj_=qFٸXr}Fݬ1:+8b ˸~px(oTN?/=Fo#9 iN ZD\ʰA̔#m-'$D"j%9ӲDž'(YX9#Y F@]L:StU,3Zo:8Ld7U_?fBDh]wZf\J*Ϡw_y]Y Vlm&,BXWoHZ+xhj.d|]o5-_\dɐbgMGn5ɉYw:.M]:h\YUxMgBd}JCȉ25']vb'Q#Vxdxک*ָ[YVTOO9|G^m4 < ИO*!$ٗȫV,ET_vXu~[*+8XXxL#Uk3H?ͷ4:ŸUj0?t/qmr::9$Tx{BfAS;x}_{ߗ_^^ߟRnFyUv__o3Zg YNQAƿ 9cinU:#Yǭy\z:u)_Q/iD Aehv$MdRu =L`W[{a)}0SӦٳ!OP$fisi'F#ih]cAhi{jn!M\!/p㱢v9 {oæ݅캌ͣ fRЂ^QW5 @'o3)cY-6d,ϩBH0![ qF-ǔm0 &sTqS@V.U OUsh@GsS>n #E+ı w Ka Z ۾ @ Yi\wg@?}'CTKu;_ijOt9ǰ0⊿o ϑxgĪݵpOf,<4QJ%o1wPȥlKȵY ~h# }a"HVR'" ˯HmqRTޥQ]x̉J-]oV=Y`n=N@SrR543%d}/%.]kW<#%HDHK QW!an^gؙz_j@3x=_|\v\82,K@ `XN+F;# pa!s?>UN"29nW *Sq3]VAR*N\t/1%45Uh@'$W6WPerYR9@줫Z0 Z eZPIrbS5b{BZʚ:2(P7Ә@%ObAh X=M.+!>o d֙*G,.t+leÛԪ ɏؽZCXѨ ^qp^6vofZa D8ZH頀:)+O*,-ՙ Pu͎9Z4&n|KWQ@߲1կ+4IX^Nk>SK#*S #bͼ*ȠoF6LߚZ8ё,pB"r^Dq_ѳw+Gҳ=ѢG:AUC:!ج. % @K{9Qu||O@ _95*Qjsuh>"(O@1 VM+ج4^,IdžKS[zM5^HvP%V[_J @!1Sw(~] FL^_26 ս>^o!*Cu0 H諢JQh ecldBN'QbJ_ەkZf]aIJ1fBܵI,@ obGNrELX~EPv5,.bqͿYskz_\#`lX>O˜3 *u_6ok,rͼYdM`=y%zzs'@~F Y -fQUKHVÈTH.7O;C KT5gSq:Յc%ԤHX -)N&j'(3[L޺qeUX@:RߵOr7+wWܺ_A|`7_WnAJ-vT^f$_ )'B]VK7mCzBg>>U^X13&K(a#* `k"VJt Шh>1Z* $.; =~i~xRsz{D.$Pא$T++1DƑF 0\.N(9^|ׁM- $3|ӆBo. c7.߽^ DB?3 ,NDtu^ C URNǰe[oWɂ(/M~xM=?n]tKMgj< g^뮡y{޷y/?\}|y\\:]=xjC}|J=" ra]ҩF;j9r z; !f{8̞n(]:6O,J?]qZPyKPECRH~S 9AȶȗkLǫkG<ncMA[XD?|Vu`@;i)'^g"wn0HwĂwe] Z1"^d_zPR*;!`nDC-'i٠ ͅ<%V{bkV"E?슟r=xʡ {Bm{̵VDl!T3c]n"xUO)OpYLvpV _iDQء3Yt9}Ԉ>uԔNn[+)idcj{4=Vaos&!wb\tj' ]F$wsF!"Leiavw$Pc=`:]VssDɻP {F EQ#& ^3uk#T !v$erAd9?dJg`2{^1'q! A! &Wx5ofYR(TvU~}޿HM]Ԉ&Ao &}NΕԣU Rġm$w1߮鎠#/- 2g3's󢆮>a'emon"`0o(k_!@ MDU:F$(16pDδ )Fq-׻w!q un^)r&LCV ǭw FAeԉqj&7FX|䠕b\vMTT3ǠlM5VaLY&Ƈ]|]KЇ@@dIN Ц ЊuQCOufSm0;[Z#RJ)}4yݮAāf2LKX OF řQ ]Ft,1[A:X&PB5;SA3"O5M[SMOː\ ԚGPOQm{lwXL pl&A+ &@)+! Ac;BSH!V$vK>+v7OfLƶ r5g΋H0xrZ6Ǣ0imk~WxU{jѭ> ua1chޒg+W AȰpvFŌڜ*8Q–u0؃9ۅQ[WEߐ|x8^&!#b[\]s؇(ЅkY:I\Alq!\Q*?u蝡NZ:s5')Ñ(yl.f3bh֙_.a_[ veiEsbËب-:K8||RM| P\^pҬ\6:TVf#ۮXDdorP(7C±Mw%NE>%[Vi\L>9!;+!+(^]yRiDeę~A0&Bg8<3UȪjzQ>)p2EuF8拴ZM"q%EҘ,9 W)#q=[Bg Po!yfI$p? F7,Xh.JJ_ q/NKbW92^"[/iS"gsv%R\@8,?:QFR&2B{I@2YH)OfrNjpE2·M;EXDLJ7aknP¬pLa7txbzPg;4 ˦ï $hpF_Tjk2]1W–!)e7R aQW',|Ov} G'ܖ t46umtVJgA,16IEՒ%>v&,FÂ`J1yYa-V̑-8>}~+ Z_*#ἈOLS"[Ē)/`IE\'L,~_T[C$fhmGN88o@øT~vƷό?n^+zRΡ㮵:Zw I >;OJS1qs9ZAwkb$ͥ{8B wZ>\;)~P(VKFf K2Kz8ΟVr 63W~P娻ͨ׈ȅ 55Iq(u1C*e۰$9TsQis;LOh 9GR`XoHVa0;3G*iLS"=Z:G,c J\Ζ#TXUll|&O}LS;LTrD7J@I+8?@ ; 'bTyW/+}' [c.j6"v.ױG[q ü|PhslPPzض %>>t,=ۜei|xA"`qmw&,%#I!兝k]q.[M t݌%J:)klEHϚG0h0g{4%N:?ZfYebG.fF%X@KrL6}YCm M̜PU }99WRE9$ X?e%>`zFE([i"o߼?/b=%mZ#翤璛t:[`O`Oo5]r,sVSs)r6{,c쮅ߺ_s|_]S ZMVߜD |󿖿>/^^?7{}cz{y }a9Ngg$cʏH|f^NOEY|8#} q_>uUFn=/dO_,4hsѰJrr9^>|^e߳ZZW ޙ[#?8ZhS^!Vn_`"Vr>.OV@;]'rTƁYZJPEI 1hR{53v|KC},-džgM6+) T['Vq>Iȑ`F?0bQa&3}R;-tcEyS`G@5E6Qh6델 ۇM0oB/OJN1)d yGL~`s?Y߂6x\?p,1b0ظJRľs!rC5mo)b eO"2<˫ȥ4 L-@C4Y3Ό߷ȷ꯮AH?AZ&_iԳpJ;1x묓_ȗ0O ? !!JD?nXWL36  bY s+̲3mj %cmGss](&nJ4넨% Hg/05Qi/8le4?h Y0_vjwkH{ -T#kj{;7C$!Իvuf sw dun h=IInmG=rƖH݈P#pRkjJVE_pG0w>#sx#( ,?|3/(b)%=T6)Vs@wJ }Y (eJrU>>ٲ,XBJr˂Sr"E@Ƹf+qENIzeD|GJ_e}Izݾmjj2?ixo:L &d5v@+AZN7W$,VɘGrWr#їtF˜_G ie=X)E:PEg`hu*1E`~a3Cadf,Y1ZhRhG\ym:.~ NzǛú]}1Җ:wy7 /NufF=G7tu[8q%cSCᐪ|5͑*0]4<ɒ)-rJLy[u+>vvSdh8L4A49ޝXl2qai 3CBa caIPvU|I}YRȪi9wltA{: IoW{,.8psxB\9gU+`$x"+iɭu c^fc@byDF1Y'to ā㠃{PUrsbTp9vIxA n#@rq.guQ+cN#`TɠnR@P=۱nU\-lϧě\K\`|q"RmP!-rQMȇh <>K:]DZFPc!1e "[l,<Z;pYKEǐ'YglFxr;G/+{$@Cu96DSE`#X73a2; Y?Y` \bfbp &@ *[ڐ.+bWP:Dh]Is\8o3L8w%c[ո5EcDУ9eWdp666enqi`-5qap[T["=NɩX~KHOYQ ջ\L1tg Il bVbK@k:&x8q RNΚL vF߳t5@"w^V8u40T'xfVcmpDh X`~:]1bN}Ic,Ju`NH/ƫA`*;^$ ٪w''#5q6^RTgM]XHfA!qMʂ,MmqS&_`h%nz= ρjd@Z H?+=VoS,+֪2em냨u.ҥw c9BriJ&]n/Z7LV)s5(rQz[KTH495(%ty'cK{94;CWF 5s7IǴT!f EՅI;--B|_j9# 4}.2"2B6wtFĨ  j?:+Uշ:Vf?3^hJ輗 sBgM dL}^TkjkSIX9 "Yd<;߂'sy͒ sfUmINlM5@ :_ҵ2$cJvkp-/ *x+˔~s|;{|K~.8|מFHV]+s˧DV_^S}u+oIWZۂ.zxKGGgϽ Sw;wΎ,YAE/S*c&@/㇓.;ӓu[۫%54ִv:SVwDlkm?q#{ى9D2FARP4ۈ7[[*E2\iZ7,r! ٧W-."6`k; y㞵~ܯ-3TwSK +"In(=t=6IwH|( 'v/A c["GJQ}Hƌ^Z džF<5ZdT&]BZ\9MO 0R+wGz #Е :0Frmc`%a~rU3mF(YҪR)>5ύ?~PsЖulضv۶m۶m۶m;FVɝv|8 LF&s+ߔvShV~t B@zwā QH-Us8=O%Y b"k"#`Ʊ/P ڬF[ @hj t*Àoa<& ;7C?,,nQ^ ]Uv ~G^`_h&(b}܌S2 WÆ< PM4bf"R!ػK.ePa b`baTdKJF>SwȀp2߀vjwkuq4:C/tvu%Eիڈتt~peYД"G}ݪ'~y>K8s| stmi5 DO~ƒ-%sJkM8E{ꁋ`۽x-;q ڶVZPNl~iRng:Jsq`Z:&.^D+rX!Pxx3Jl`!m Jj$'NFҁs|y3 ݕ;31k'f' (9ȫaQ 3 _): l R TQ0s N\^v,Z9^G#qeg8xXPr2jҍX0X0T5'glpA-UN~WԵ6xWAm]^jOf+_fC QTb:oښP@uh$WH! QLw&]>:zRB; i* ~8mAesd;1FPC3aD &둒͔y`}a]2EЁV0\<,vC~O] LǴE聴HKZNI^PO waRhSʶ:yķM}b^*P0)/B+Ғ xf!W&m|%'2xŝw]Y֤E=!46Ez387k:_v[ND']n0Xβ]u}eyV~2X ) K6JsHBx%:KxJ{|xx %s2N xtk5ǎAߵS1LlJҬ %s"4>Vd܌̲RDR|DA9{`s:F zײ{:]->@Gb~ح WGaAl` _3yHj6)նp~n\KIu I9@y.$Jd5H\VH@$iQ3ʤ2d)UԳ>Zf 7> iK3>GwG3HcלFQh-mj'≷ZZ?W"^Cn\]6voMX|j4Vp"7EڹtW/}Z7iETS>$sIHJ&8k^iM4I_19+?Z6 k-mLxI]?K|`<~arm|܌&ak&)X=do1t;JYwuty&Z&a ̀4n|{2vϔ {6I84:Auk?>adNƓPs!gUi쐮*bp)T<|\ccȯXLf =׊dpY{ }ޜmfR;,EqϒQ+]4 vQ|zTza-1 k+.A'XNX|b~",#P܈ HX iwIUWfl/~{&-6ZH&hNGdou+rgD61[뙲E$@ [[5ÒT7POJS)*/) .\ ()VV:GȒ2&1V[^y.V#8tp703uX&SO]ƠalP1\{0cmʾ梄djMgKcZ4vuݔ'DNKFbh-hIx07[RxTRV?EO#.!7"a?1ƽ4 uTmȳ+i@ZucX4=$KPG@eaI>R>\Nqj}0P0PeMj []Br܍osMm y\L}q%c4CY>I3X7{QUyQK,Y 5;FF7XقmDn2Z@>(, ;qP8D'cuXG+v 1\jwԩX? iPoсQ~/v3C/qiF~)쎁!T$&ksuI`@zIVlro_ czS}^-9l!3';Y6y4pK h.i%Hm`X/kAKbwsXfvdW8(D= $T֍k+ʌ.x <) |U_X>u 6/KWUmj\]͋ ~bE=Ș`LK"Կ E&Ġ4ʥO4dMTZORq =}ثFM#CS_N*5$ioUeqv=/lu vt pD Z's%/&`i@>vhU>7 7U֪7ulݕGn*4eZJp.7 +,BA25dm*%$}Gdž_s݋1.ڏLf*B˯UJ8&e!i/fP5eh6RF4mmj8b['!&9Q'-з0^ʭ $i"b2kF%n$ׇ9Vη]0L-'mxK{S"cG R}É8– 5m~! ` kgF,0kux̜Ph.ƹ"B7C2ȎWRv9i{[a MUȪɓH{x@gul>-6;lk7E.)%9͔?oH6.@LC̎ccٵ_CLd/8Č!c<(Z0o6rBvTYk?(5k)&S/N˥rPCȂ39]O( 7$4~;!ПhnO. <cZn )˘)"," ⫞2#)ky6p #{դ@|-5JT _`մ`?VYq⦖M#Z3۵M#Xk"BNR .F;q+b5[?9XipD8X tx)x-؝LoyXc;,+Ƨﴹ>C4, O Yl_r'ߝ ޞ*D0 pt*RpB(Y}$=-_Ȃ=ʀC~7Ii3hKݨ:eaeA'[ R`cPUL{ Ŏ',";$H>$8GjIJ_,٠d ,?uԸ}2J~Ou-}9("i?Ɲxll/ JG'KOJv]0!I!!٘t gd W>?"L"_砦t.;nqLY ،t~E]Ki#Rl0^W|aFw]cy[@̂sVLi!? PG'N_>0՟`Av b3o-YY'| /1 AOPzR+Ld"~+fli7Ybl0Dt`=pcU6r*s@(7T;Cz;"6QF⡯* !߻j *j)Zh- uSn;x2R}}u;{l<#81%GG=%+Iw0sp?"(~v>AEkɒ(,c BvLpFׂ|BG].$yVp=va|U3I+/5d [bx浰[VlPv;.|rV;v%境^߅L WMXJ='H%TǛz`%wJzv'Q!kP]ׇ1/ZFqw4\+)xiq^L1T_}*vκBo+$??ԑ"Bo?"yڡdFI# JBWY>g PӞk ag^?ς~ހì~.!) 'F9Iuv\ãVqIڲreHEwӔy8oD AnWDףXklcٲp@̘5Z4CaFO۪w̽n~K(AK)Y@ɘPZ,|\430 9î%Gс9<>z9xu@{B^cX>!HZj~He"7c! D||]_|ud5V&k7 6=^sHѳO崧6 YgK2R_8DȍVoxg1u\p/tg{DsEIeKVG?S]}#[hD'5G5Pܩ pDNhۯL-QD  +Z:Ƹl :z$eپ.z}$(5O/g|Z":{YZU++ANjpT=qA?8yy;^=\e,䤨TR@]i OEĸ4Lls#x: ]=.*HNNjxGՖ"{Um榬~-2g=CSj<ߠCxdztzQzia6 /)k¨F2a0uzɪ)Xs!rጸ{_=.Օf՝-3-x`amW{_1>yY/Y>-!p)<,tO`^Jv:\|k 4)LƜR~:wѼb&LD$,C_ (he1JU [uSk 1& ` w4ã1B$^iz)uA4(hٴ'Ҝ15z:NfشHt%d:~a nf;bԤi`x\Ý۳R:BUY.:sbuORD{qS%=2Q/ gԶT#}Z;igSxD~ߕu"\em36yEo*zA +]^IdyLmE6̫7{EQ`6rKyQG6E¾o #ZwY deTΏ!WntUώp*owrb>iHk~u{8Ots+E;6gs@!ad>Pz+=Ekuoj_] yCZWㅔ:&{M@I~GCjuoIGh4tq:~ϙ,WӼH9%d*ĆYtrJ5=ܬ'Z$8gwt1 36m1{9cu.x;FLP+"f$iyOGbp\)̡'-#]. LnehEo?G/MT㓤Vx1µ~mI1UEl NH6{?m ͑!Fh|+3xGwaT5\)P6Tg\A<$gfGLnWZN1W{LH> :El %X dAXH#`PUxIol[=tRˆk/T#2!DsgZNɪ ~335hV &b-)smlOӧ%iҴ3}{lHQC;!-N9Îg%W ֟u [f$Yn0QO-!&?9꫌RpDoeަHywgyS[89Xop+>[.%[h iwR!x2Yhs{;=ߚiH2̴s]\΍N1K.N_ɿ>-FW>mN~B-o_r9W0tp)*RK2> lr]7/u- Sxb)4'Ŀ.鯡4f:^7ӮЀ=&n}^=^k ooJ>Li02ͼ ]bv"zoz6Ifs-;Kr>J=?^(4$Vqsbdʿ.Zu[v;U_nCK~[0<&]YV8/r6[{ۥ8xU(&B~< E,=n{]=N ~ 4b.xZ}mk35w8{?Y{+WX̡j4gf@[Q!ypwQ,DnG3pq<./ra!.~Sm7: khw`7kK9oyy;9<Qg/kB|HGV F3a;!rys0)K9Zզױ0I(uْ.4c*W1t[ "rHny1Rq}*?}ǂc'(~V֨TDÓ /·Oj $q돱Ixj%₌pq,QTAs_h9U RvO^[f'4__ 4}\!oBoecԣ&PK.5v*ՇZԕ 1vӫF, 1=bc;Q)8[kkcd0\ SbClB: Gx3ܝL.}ĩF%ԕSj2GP r|R텠 s$Jn+G{EBS 7K02x|K)/ #͌9h9\*cIf*P .2^Tvgtl &]Uv`kϡok?7@UUR& MowF:$>N@zR/@'o9 CYlVހazCĺd N Tܙe3S~RQ%oJ&@T2kLTvOg\g6PPѷ,eFV޻E>F$ PJUy'5{]!ţv7."_HW.")aeI-C2@^@IE܂bI<5+)i歄πR4V#pve✁N 'Wr^ť)á{7{æpSk0yY ġc4ls.ܐ 3P-*He'Or,;AjQlj ݾ*o(Yq[ɽ`TVbӳAI/+5X:h@q+RE/5, ;ň\ bEpkI0T`Ț 僮d JlMhw M<"N^@ΘU>- `z$pyquˑr=2Lb*^ 9b@{4 yÓ# V8uۤ 4a AS _-=Zq]Y 4h=#j(0QDۯSo)ZKzpPD_m,d[Uciͯg\mm:O3I40bXyݿ3ݥXOem̆\;Fد6LyˁI2R&o"iM_Wӣ7H o7x']&bAIjCqW)cDpsW3%lE59aЉ4qYP2S&@A[}*y0`k3>Hha]bT|ABϞH̆=Մ%h0F^4^ mXD^CPR$:O!Nyrf30DqԀj@L o%4j%865qΫW\ Xaet~䘍q8H䘸6śڅ곊̏Z[*OݩYІ?:=v|\f~P%pjک%(/a\!(#$}7ATndI8FulgnӬU# @u$jLTz+ׁ+4xŤ}B#i@j(mBilDt#C^EiNEc""R2p9btrUR {6M%)""?H_ `[ g6of́=`ƍ-}EHkbwW`.޾"{%OdЅ>#:_Vqp\6Ye ĴO7ߛe ax'wܵ j yI@sR}{D^+3I~|EƷ [90ӄވy}uBY05GNLM8蜈B7~ =paK;4{ Q(#kц !RXiahJU+Ȱ0 |\@A/YX 慙ZȷO bCd˹3vO{ eZ1Fx {OD;'F`i-vNiU@D%e}@=S{UAJ,NGY-aj;T F/ ༎Vt,N!V=4j {KN8( xYt[HF 2>}_[]Fi88B4 UCUdC|2:=MZpmUUbUe8P815r'pYa>/ Ra;Sxkkba`A O~&|rFU7'bB`W7Q(Yai$ U8bY>^WEux%ئm/@샟+ck#jBޣNF %lY3q3!6)؅W4v(+9f`@r5 D2- Q;ekC͝K?;|z^ y(0Y@ˊ{FqJ MV&&QSԇ0+=|ye =DV0Jprsz4Mj!̮ƴwx9Ϯ7?A r{1qυ.BDAJ ?-mDtx)bW n0㒗Q맢SAM40)Tk¯Gg41 &p $L~W1SȢ&!VUf[S4K4yQc*eEኤL]Uן[j3QNi,W*'W諨.A{nԕq@ɇҌLi,yrx&>LU,1EçnaNÐ__c0Ym?% Q((.3q 8ހP7J cIOG?c/>&IQJ;5P! |c>;>`l$:UprQ"'PeR!Lh2 t%b 5((Y~ bAFīmNtPJBV~ O;#z(h(Hԇ/Ka4lQ1Qx+|f=xxG2T? wY1Zz S  oa6d6A aW$XWvJvxQy_DN M[ lSO(a2WnwN 0Тd_PS5ՐfP#W* s b3 8:d* ?\fh7#ÿZ&b]%#RKn56SH|}L$M"P S?<V}Y Gl B OffGJl*fz|*' (񪟣MNfEDZ.6"R"@ߢ_TOdfcBqQUv;nͲnRvM|q^jy66 d;!ٓ(X&WX`$vczodrVډ), {?,ZgbiO !%#%KC !ZEFjC ŅHl2V~-FKc Ѥ)OY6Ӗ mqî\mDb=c* ڒSF얓awh֌pXckJ7*^i',H}ťH)0u ( 2]Ld57;qT8y쁱&k=Us"%&6 9Σ#ͭkRɏvsugU0`L'fH^y 6b;Cqg:Gd"( $8k2 aI"%n؎LqIO,)tʅK)2 HeL~4FO. z5<(i :Zؽ%T>3~v&]vv<M} P$v2' 3i (f8I@RuwAwiH%J7]]%m/5z2؍?CIhTy=1 ~aA1o}8k(DQ_+HPF S-'o@ccVIRNc uu_C3 !['ZϠ'ܞd^|\Gmn:V_݆wG]$Ge$mѲm۶m۶u˶m6oٶmۮϺ#ޤgNε$m|rx{K)G ~ۭ{?88X;oUcf$ ;٩ױjpY'o}<gŅ͌n+ _Aot]9qZ]^?ߛѸ]L6E永^ ۶יO^{yybO@0솤8"2K{؈P\EF ˒wrGλkONQt[np[*RO)s7 o~3tDǾN $pjljHtqR cdŨDUL LNaE19h3c&j!:pэe9-eӇ;!^[[Caҡ]!1L$4'..t:U٥YMj< P(X1QrΖg&=K^HUb;IYca^E)B[nXt`kq|e39ĠUj,6 ~= vڪ4\9KO]B>`onHD$(,Nc꫋δ!lք1tNqZ13:ȭ. =O|v꛰D| OhȯxNK=N)蕢o)(RHﲚo4iG~c1iPGX$.5n;cve(VA]V!_EsF\}$tKRҟ4'!l!iy΃4CER5jѭoWj?8VnBUg%]fsV>GVk, y> oS(s`M7,J/1:fWܬôy= YlmhôQia/SeuTǜP9U:C#(%f! frҦf ȯlI#K[멾t!w'ylqrhkg聆-MxIψ5Ȏne4}_noTQq ßq wF\FBxi=h{ؤr܀NM]miXaPnO+7N U~z$6Un~ŦlŅlw'E/eT狡H\$%B1kˮ~G~0ϢÈߧ=ʿ^?Y_xBM2p3Vڨ|Kr-9sk0<.WWQ|PRS~g9O((cF՘mBxFL[NoTqޡPM,@7g4B30&2xI 9[ J'Ќ#}k5p_II0#؀TL*Lf{db{)MFg{̥$AakJ$٦.6n!|]vӕ;p $K//F&sMiI'!.:F 8c1\.I`N%cr%݂n:!dDk`hLwfW# bGm\ĈE6mFL:Ĕw( _! bD5'Ty~\ ux3$K87eI1'?pL2!Gx\wSj  tt,R ^j 8g׍rMB 7t8ͣ5 YIKvn`c|d<vyGjD%Nlb͸y8nu6ɼ@1s19[@ZahO ԶE^7C vaE.2?e䝛h)x< Wy%HCs{ M~`&P%< z[rXE͑HZeEy+AT`ϳ|ɋ KYД$ːcuQQg 5] !61"&\6#7Tpo-l{pRrnL>d R<ܹ֗L貤賞LRp'HFDƦNMj/4'*' p2)+eD4B0rEm\Džb>L 8#.5VG01הlofp6`{!= W||S(:@E͇G)£׫B ( JOR(ܒ1z;ZAmcK_j#Cd Ԙ;ZFj2kNk+- C!8W51Bfm^^/AaW?C݋ `bP.8AaK$`Tjp,"K%-U>'%ŻW9 VC<\YB4hK5/2?UsG }pMvHK)_L<5emTc,603+"A/r>cW*W_mǛ[CV!DY,wBWp9-4MiU aW+r/H7q&~P"??zVϓ@N$\]+m,\[gizܶ^(Eɻ*ð]v/rBg_ʥbbqjI(Ūx !mWMm0HTѪ"XCaL uKA;4r]Phq 䗌DrJ󅬫^0PZ;ۮt2‡(gKwLf^k3roMg$nK8~S7hF@_ӐtF3էzҗ`Hj])_ \e%F IlBxj^edPJ >eJA{23v͹WЩwv43ƵcRMxAm^x{y:hTXcQ+(ϛb,d#BTDWLͽ sGa3kBjx3(DAMܠ'ҹ(7֌q[ !~r]{ۋ' ǺC^zM}W/8wzxiIg=8qo^Ъ_0eO[VTl(;,lI ή+jG"ݣ#ͷ?{KNps$6 peke5锺37]7&W)?}9V>ShFX2z͎,'|ѦߤA<4)V.;>y\d](`%*ZϦVgmtq PBqo̟C|ә*,#p=VZ&\Jۣ@d3/!(/ի/r<KýɖJZ44$ݚZ ljoh+_DͶG Im&U>I}ء>lv$EzQJߩi w)Hz&y]Ԋ%;Z(_wiZnX?f'R|&w@.aR˽ء#\| }}K^$r2?5OѢ"յj?Ɇ99kobgYlM:buǺ~n7|;; > _566Y )ՎĊsyCk#fN+1 {-]Rk]ɳL`b~UEٟ{/^x ߝ_j[I슎pG5@#6P'N8 E*Jp<0z+A%oO6rOdVJ?ֺlL -f=׬]xz:YGMD-MH%zݣ3|e`slO/j {C8['1)L\ ^ks:!.u1S]V⎞: P^)$:``H@ԙE[Aa m94J@h B t7Y}]L?2!pbK沮ţ(i(քC+XL1, viR08qc1HAii,芸2C~j@m #ɞk"18r+C XONv4}_Q9P@ȣ. +;!Z?}h{Rj%x3G> &!Qw g>!sQFAn3PXn»Fs9z!Qtm| >d٧.)Q׍!(*E%,$}z"w_i$s! )drnEv~gt(Aozxм@Փ.xT18k>vlzڮpt2Y)DF*V Y(ѫ a' | 3d'J; Bl 4P]LLIH3.-^e93@}hӣPH7Wӹ؁;8 &\A\9eTLdp~XS.;pdD<{s5-FhӴ|, ߳`7>z{V 9;j<\,MjhJ|1v% ⤛ KvSZ5-,H-8m3+bgc+sx]@NH,e*pV:q;xJڡ^\ F܆zkҵ'Gih Pԗ*i\32TyXP&/V]ZH}yC a.2q(lAeP剪Ae{݂n2oEXݍO/ʚ̻2as2s4iJS etNK,ɋ0%A%x{U3Ao΢*.xB8v) #2 䬑<Lh̄aLX(r"UӸ2msKRڱ# 'x9@^c1'v }U(qʛ2S7PM6t;J#s#LVe)ͭȐfv<9o1?1^e]P&̎BP5ihax{*[ gk M4OX 7L(+-r!$շ(cb\*ɴf= Aɼ7@q|Un|蘂4Yw>k ŘNs͇_Guq6?/f]~ӁEoT@IA@n]nϴLsA߷dQ,hp* HQTVΪDdu1GNayPL hAi^ ˑ2O8PMDHp:[0Yhu *vkNJYAsA^> ^vحG%AF$IWKeYND GTzBl=P*Y:3ю0wGJ] Ob3nMaYAa8a@[,#K$Dʼn@H7 ,.ݏhyM>}㕘y! V#_ntG#+1Ϩ? 14C+lzr6n;d{WO^_ca=] =;{u+3hOC{^D.MUD~ X 2i:rA:SIN~bǨyТgZب1!{ R3bj0$rbu=`cBth\r[+օdLP#}o,lњ=05D+#'7eQAitҕ߆&̀ߐ{\ N /_3U:x:/쐡Mbh8"__AmƐIڎ +ig $d UH(Pbڵٟ[\?tEXBkEDt+a~8k§k X+ygԂO3t vy )|d :񱭬ŦʰzL#]ڦ|WdMτli0ϣ*M$ 97X)@C`)ɋ5OB8Zpq lϭ`l3H'_8]|ƹmY1_~C>|+̹_]P1? q\$G~؜ E^hjnFen;Ipn|&:NKnu}O7zC 6yg]^YS^'&T>m\mMW|XH7DgkV_i$|Db C&swZ_d[kh5\RQEc / ܲqy8opxk9a_۳1|\f8M(Fe&ƪ88vb7JuD1Ҿ3oڑ~?׵&Ě#F*_Kz:Aq[ ׾XVt ˘ʻ8Gn8on"HNq Ea tb=9suG/[b*P=8>piɤ9 jNZY0mRF[8eu01(;\ͣ^=Ϗaڠ'^M}Kʷݛ03@Ȯ_pBbzۥl?[e`!IXW}Z?\\:T ,|HXhg}~ OhӼ>OMK k@&h0VҚzRBkbqMzk4͇?9+oJzUI3~8 dCp_v>5k)L0WQsvPu|秋EȭZ}u|wg}9 ]xז~|w6Ho9^x~F?1QvZpW+pzpM>9zǃr>ēx'ګ^S I:q9X-@\GΗq4gDުXt5F>$]riGgC-Rhۇx5'Z,=j8 6 *( {x^#C/G%˨P xZ‘E3!IꙎy㳱j~vTuIgh9z؆1. Uf4Ꝍ,)2 Xa+SpbRʃr,J{K.4 [~sdkZ'Ir0 jmdv o'K"v*BUioV٥_BT=S@MF#&>PMHwQqFJpyw&5Fq9U*=CCpBwB`1aL ORjj'ӽtv~=Ob k݄Ngnh(w$:umjtfn@AHCVVyvhY;oI<̮%q5ϱos_KB X3yiB{:P3CC4h$Q-;(# 'yZY3i,LuQ ~'\3j_⬤a7l@̵pwZQ]FIv-%ވ%9HOa/5'pܛ<>6SZejR]H!44"vy֥޽fG~BEwE?~mH)S[Hs,'A@Tה,Ii #!k|P1%%g ^ļ%n#󾫞_:Po3*w2uf^(OQߊ_ +lZjʔ]ݧn>ZJ -r @ņXYwO3YyJ'Ϳ*?X,7* :Ņ4P@ ;{V[4%% KfU&&9̤*Ʉ6ñen}(2X.-2N-H^co}7=$j-?j,Q"%碹vλ1ŦLc\fKAG aǢDcSy `Tᕅ5>Jv< "ѹyQ'IFݕHq| i3qg@4ҳN>$=ђ=םк1u+Q>҆  52P0_rc{(b@kR`۞"iLl/q sC]S "+4¾ .َ׊%IcG"8S1 5=Zu PxS!K=o4mA5x`j?rKM|5L_hr4ApawW7Hj\ OH#x'*mFiI=NcY>mb^s-uɿDt1PV[5܁4ap'98WQk s_pWH+6԰܅> {1Ht1Vg)ƶxG3`sMj9)rkIѫvRM˸2&y@+i`AQ5 7gekrf*ozpt}Ҩ?0+=ހ+v>fyX>ۉCaU A,¶%֑D%Bjȓz4ވ ?b1)M u*;yoCɂ+" iE]i MEtuOLKs\ f8|&htwʤi&}cs1 3ogqy<:~K:kFYe`;XzR|͓קL- Yxv$e|a.Ahk㾌yOq(lyd R .!d}WY1l7kT֩$8*hUgZ@˥">Me ߳hJw5Ma7NM'ESn'/&~WB#$g&vG[l[sY敊e&hu*ˏ)Ht_1V,HhMRb&kLs)EtKr<7w\ރ0Zln3u/kr풫 ._/8S3˫TKsC&z{Eq285CZMaNPƺnCi] :ڸ6n;:D7^i*'գ,YnC]"˘t]P~s umIJV1S`gop'QƤT經Uc a&`bW_tG#4QzEXg#W TKvSoºvmm?uUY <Uz]eY"cHЉ? z~1 ;7:aj χZviMaX\I'7fTv'*>fo.C:s)Ո/W׾мJm(xg'\tCă3Ӣ^IW?֞^u2_ CTŻq|JByeHNKG@;:c4}mf@p[>Fjq"=wB06;+σ'hV#CH!pe]Y7ǝC䑿޵U-byiϼ@\j~֖ou]Wg {5ڴ9n}񰈯RpzldeЇObՑ{i܏ӥi~|jp~YV2@J*:0^\1p 4o-qwrٙgY&~5ay@wM"[议cSȇ~U]2o{F/1 g~Dv&&PT )8$M'd^IW=s{k9kU0͹#gjSGXe#u {[j'iH[#]cԋG v5lMf2H1jwAoe-695u"[}7A6Z\0_w523s4lfZw2xi~¶Nԫ۰ݰǼ2~8bl*ECE`Sc~09Nm_wcfկuuw.w}?n5o8%r~߶w:SYL֘: ϸLZ;~[nAuY9O_]Opt~8 r8M:wMzLIYnd:\D2['w+]<5>zc26^l{bI7)ZN0N EX3!N즯M]]e@v`u&Ts/$#V NY.ʢN^4;5 zWګ N"KK[ARX`<)H74vU:!|D3].Ԩe"! Ff2y˺}):AjNI4fKDmхx&S"(FYFd,}|T:axRI>" 3 IK7 "51DN Ej#GԍVz^vo,^!ja &ui6XCzfI 37{N}3 Ր(45̖ɹǔƉ2!hf1&6y SZ➕&4JF稧f^Q#ᥘpV 5ֱ\sZPCt$WVc[]LQ;opxl}"g֐& XNj@wdlֈ%rFZa76_`y7^j *kBO 62Fm8"KVDUC;a5mcfQ\`AqSsU/BUXqDޢRċAn态7 %x.w蒦8Ly;C+Z8<] ,`_CmLe8uf=3Msq5f>.f/q&:ot+H~`hSz־PisyW_2\uR:2~dŰg~GOnZ/9 x+d<v}H>EhY<܇ޠ ЄSEbdNS`0486L jz笰 ힿ/)(JR7kRE }´Kh2Ut5O?GdMUֻ%%-wcӨwkxa2Р)j5dVM@^w%U<+TPN~[xl#"ƨRW}`lpM9j5t|^3j#(B 1"bT2X W7`0-+{VA!F&0*V lcm-x`t bqGdPȥu$THxQ|J8ӵߎF@<E"Wd#um;8|2^ OB2c4V\V'bl=i.Z{"kŋŶN<[|]{ Qؔ8_+vd[ 5MҹBG]+{*ѧ,ˇ|KVϯZmsTܻۡny)ųBro=ہz^=kLUicҩyE"))ѕ&n1$Qqm4ok۳lUxLiVpv0Ҋ4}0_Vn+5dou-ke72y SO%g7lDaf=[FN[?R('oYK.}+TVƿ!`f`/ۿGf$'0?!V`]m۶m۶/۶m۶m5Iv&TcT1[sj|9E9ҷ}=,$'GQ-ESν ;`13XNő>ϐn}ooL^~Q|,^OU:{d8gKS4]o3{c%;CdQQvjh3l! Χn\wq|-,S/SkaOŸ̽n3U?_U5ggꃩcI}0b "R !RHFe>?~|Qi =suKi1T$b>e>zD] '#Lѕľ|5%Һw\?Q42v^O>4HTwt͎MeT V"eR\c`[5V Q1?$,j*6-n7)^\7[Ϋ$z8__=7îXre{}u _>Ȳ+AFc,엄wka"PvkM|w}u/%.BYAg[HǙ6X2NT8F^%'s&~^{6uI% n=< CJWs %'y@n"du( D2ѭReU/h_"  2 `ډ1 9b$3JB#f Ό0j*sgفUsk+#ϑJB8ȅ<Dk4.;{˽{$lƀvEK*e5}v|q٤cX# U<21"bu@AU:kL3r)-D,IXAT,C^7\K6HE @'MJbaBj`11OCT[j_$0A'qqv_6;WFbTv6مU֣A(J؍ >\pWV1CDK1CSEWO2 tI&n\&r/f u<he;I~a2RK7*VM04%2NuTu4Q&@1o 2 S!*D `#G}3D #F `f1@]?a3V}q 4k/3Lp]_r}Ƽ6jKt۳Yڍl>c" Cҩ-fPy:( fNhfk=mFq Zx%CŎkŊP)mySho<-!aRj]aǬZ63oiJk 1]ustOܟZI7Y &׮#@E&4):*[ۮLy4nZ:egBz\/H2M8ewQTw P a&yr@_0w@&tT™5" 3kΪ)s}N/C}iaz P'8ȷ fS",)#{guM^=; M=*FFj%?ؼ81=쥒^:f;p p'+ k=!O:fnfs2B4L :LDLk*9NI;8NЌc []*Zsd^"ꓣ>oxvŐU<$G^1U&揊.cVZo6Jz.e4Lq"NQ C*(/c(^Ub-8(a^zaFQ p*NÃR3$瘧;Z)W"yylK$1lhq852S<ӧ3Aĝ݋y9i4&h0qzكǏ'F TJ((o 2cc.@M(&" #-:,iXW'TOJS$9z=%gWdk`1U:%DR,v̍A\7IT*o۱Ժ\:gw k:<[ƛJ!DsxU/s}GO{1D}Wf],vLކ^RfS,? WgF!ǫLg&+2zy5ˍ,;(YLB0pt.z6`0YT!x hW;xݺ}CoyR(LZppI#Yc*5RB.-YvT[N@oB@ٝl ;uOLiͨ 'y6 'lbY6 9Xc\ѿ&F'Z3e~x%۷:֤Ek퐪7Y;Sf)Vons @Gƪm@ҳ=+M;D^Nᑙf?=a]􈿅4ny3hӭ0#6*@1@ƤZJ-Zg)5GN'ca!2q{fR8~pbȣYE%#}~ӎkgK3[=\\#ޖ ELSdµ$״}}G.}toۊ%g~̹)~ੴ>_ RnuHi $ "ձ?/? y)Mai9y3Gs;}#o҉TW1kwdȖ,i91 3t~u|ʃ};N {| |,P G"yIl՜V,ӤWL[.姞z39"r{tBÐ!TzKq Ft6!G932s Sl}T 9@ks(6T(#] H1>^OhrNN؝1&CJw>`bl|8/2mI}~E{rM ; 9rOua`9*D׎Vu7(k蔮<C2Z\6w5m~ xr k20mA?4n|U+#10(L'1WT'(ޡ8$x)sqh;=k׉6U}<9aMz]MkGnl/dFpU>J漹8PF0.|,V<,v?4::W)ٱAUlݔ`;-^̥-] YaM1 ˟i]jg^s֊<~1:PDϱUaӽi4΁Y_KEՓ6dPsD^DQxA/⬇ng"8?P1jUA\ n}¥=&G|ȿ}ݸBP8rPI g|ҟ:JN6;"Nt/ǭ52[;[?v,[m3wݎ^au/PO{gTȜ0Tp3ՆLٹ}|ŁMeʭ>HR .&)Ovf>ipj^$c=f!Ϩh*JDʲHNfm QkDUN% e#{jV%^[*Gd'gFLpNFBޜ:C1g_2}ꂇ)xQȑ8:HEicTկnݜT^U nI&iw]/^:U φrT NHnS}q/-? 7TA 'B!w fm^k8yD}< Y@F<ȧVq'6u nʝ^~TC2e]a]lw; s1J'nF 4) ? Åvh~)@  zյMc;xѫ20Gy"M +n&}b(;dPr5t;{sWϒmE z* eTf-UT5PP2y&"l/bu M$dQpٵX p⳷p5J,GNcٸ fvsS)OeeN'rX=E,]HF NUg)`ЃR4H~``#^g3yT.1[rWPI@@~lð{.ȼam13L Eh)6R"G"BnV 3$sML"ʨ8Ԇ@.p=ʅaP Ţ| }ZN(Uꃁ]B=R"wlWETw%&q@TP,9-uԼuet[fo0lȲbKpr>|Ok/hatR0:S)֦ :sWwvp=Mu\YafdE܏ס&Zv9>|.֎3F!F8CZ%?:Weᮯl K K5'h%,f {]iT0H,ĒXמcrS6J}-2ZFXD!Tw!wÔU" q@O;=sR]]*;5'& NIŸaBC-'fqOUF+կoMsoQ+ Sr#;Ku=}[WeYbK6]:^!+)`h )S0ho_R^E o૵ P}#wܜj?T\NrhGvH <4P<|b%gsDZ 8g~nAUiaK&5'ͤØ|yc1x-´Rað?attH`}\*5Agoߠ?% *oSoVldK543i}H8aĚ^6vibktϹ5;7D?r7\EC~F^s+}56ϽL5F~ʱ="iuN}tFeQ/=ĨCxzPĠ'+@e⧱Є[7R)9caN)B sJvZN/Y9q-0ǼĦnPŧh=bEqzvճz\qEwM+FF~?U5xȸ^=K9,oxb [164*t8f.u3áԊբ7 Ή2,: h_1@@Tf$C}Mz Js4d;!Uلr%s%x#+i#2}?X?m3.jCcP=9e\

ܨ|j;|?3&W݄Vp_</=! ,~J@3@FN![aJ Tsl[MPMk[ד?xލ6>X{[ƥ ֤I7/tVN')Y1DFl'ckCXK˖>h"3r.z~om|'G iGتOO;7P0{[ RG{:):(;ŋΧ ZvoB4(:PlT6rK*X6䙷ҚN9eN*6 ?嬛!2vdL$ nqLD iGCB,/}٫r(Z!d3e 'M֐J`ǒhOsTkqu6INO[fGx_TK'HD*6(xߺ[lu!Cgלr 0>sZOwvsrvqO?T{HB\ uVC2? .q Ll;3PQ#:^(>{Lnaڛ]:?(.AqRC.;=2IOqVE;<}or ptǭ/;5-jjnCw*7z}^|IQ!0}x062 v SۣP}o&pVIQ\3Çiٯp>WO܋&}$Bp 6}E(oGy,;ˏ֜F/ޅh&1XM`X1ԫm*fX_] A"!'o6曫׶WOH5ڑh8Vk}=x}APO^Ȇ1-N2<*Aݛ{oV{B^[v(Ӆ O.t"!ԓ&$q.MJu(PT^_A3#w_ҫwœB-4ٙD?]g#?ٿ>Zu4ˤhs}$Ga`ZT*T]no~ynf谲R_~o~?>>nGG_Șov~O}ޯn½oL_xt@zP^]8=W1̴1McM/yȥQ1QO.=tQ^4SvYt3K|Pqt^cYǪS.%5s-ƹn\EAxxigDz=-|*0QeYYH[Iת_.&Ryn~34yy2es;Ui+?SmC#$2o*ެb첸,g|gqLS5uTCW5;Yz@x!=i#*QGJ`^r'!ƈjLaV.qqP8#>Gayɡ(,{!lqn&8z4C7+;Ƌ6STEL%k~*ʹ0^GoR+z!vi4^~#H" % )\]]Oq Bh=ܬ24l hJm8w8̓Qw# ȕ-DhGlnv+Ur NB^4o!8~h[W *Apktp<F0@`U2+ۧe;+Z$DQ63k%nk}V]&} $t_t6ow[v4~Ja[H`y ,Kfh[V s)FЊ>0 F"bfɌ--5̶5.ׁ{3}Ʉ^|E5w wA5Vka܂N"Ɉؤ fc#OFbpыa =+ME$հm_ Y3ә7.-@r n&ۨ71{ȫ488sq \(@;8FJ;JY ˚buxpH, 697'=Vb\C;V@?O.50Cܫ#,EL>*F@|c+.i߇RZwhm.SYu(-\}ڷ{$2&HU OS73Yq*YTriXSrKJ&c]fu[d+i-t' ,jIi@%=G 㭃.Jې,ÒBBh>X ?mkv]{ ZuaĄUkHF{8$"^XU IltჾPTa("uJ1q6#$_qa~9~ή̛ʕ,W[OLλTinXu FTWڒ=k"ɫQoܯ c3#0m?uIB>n/$LE_Q4@W""|4yYn׏fL>bP78hUl*i!} DQQ\D>tv(*ؚ %tڦ@}@ S3TZw1ɚs?;{O0#=;:wZ7=D>/ymsQO֊RnޔRx|uՓL‚%7-CKX |@S%*,wHvV$00'-UR9q*6 R/*tmyI=}T qi 77"yO-npYj4JN$f&ӄʠ?d~x34TJᶓlt *k hk="IbO[!Q͞D;*w|VG#ṘTħr&-Ҭf\X}Yy8 W4PJ.DW[!=*}8fq@'5ϕ*WUd! c,-'G7Cҭ\d3Kh2-'= TNAY (eRuH9)Pk5U8[ f44mUy:2 MLW*h&}ɒAށJRiة<#a}.ڥp'Jy$HϪ!X:ů[ex-!* !*-i^vqdC+ x4?!i w^~ KqQw\@q: ažV +Ie#n @ck#R2X3uVAl@5uHMWRTH;Jy<ƤBQyth=ErSZ6*~*y>Kb[4hfc(et(5Es{a%'}Z+,jU{{ڀFf9״%5g˚HGLO?nah0dz~)q'@HjN_|_[w/-cR;[)]GGC0LJWX-?8vdgMO,IEyki6"B_gucVQc=uTVIyecAfz);蟉)}H]4jp@ #)#cSeL<‰1AliHщ#X7}RvcE$ݎSVw )bJFY}7Dbd?R߻R^j댯3"h,Nd m0K.tL[dkºցЖmjFO#-+ڏ hӀ; g3ԓD5┍@O-p{ e%! W_(=fYjfY% > &bɰ wڏr&4~̫Ccd;Rx3/ӓ"+/va!HkF?AKO=]_jŒ䵯ޓ yxSXP)s5TrmJ GV*j, 0$^lԪӯ6Oedu%Bⅉ %߫~#2MbR:Cd!H*NO Q P:w& )/4"P+A.NdmʚwH70mV8oUt{:92f=rL=$Q ՞bЪT-ꈚaRZ3-u?Nݣ\"S ܷgR|iXԐn6t6IuxKLNlf>m8)"iCPF1d2:dqY;Qȥo}KRMI% iK l _s+ushRyT88XUD31-Fl : 5I/y܍2õEXbPBJ퐶݊ڂ)Y=njMx~M`?ΊlnG3)3ijrBYr `MYWd{1^0u+  *9*jA*\ϊT3E2]VXJQϭv +W0q9aL(ڷ,櫏&6Y>+]MyFb1ԓֳgEK㵫-7 ,Sa=#,MY ?AVxi=WccM<"v *ry;V6&{vb!A9uRW2ZWA.NHSP5g :N7.e}&W0jbV[w= e^ЂTgeZ$>L6QKΈ@vBWr 2>[̅>д[6N.NNvCPBP^#;a9/'Ҏ"s_23w髠 kiX?9iw&ҒQD.*#:|zIFׯ$6];aJ ']Uv[K V-Rqc7b ˋcNj+}즰Ҹ$$4E\r ͬ|[[`hdް}U[1i를 #A`XSi-Irs88v׽j.vRFAOn@]A¾BF 3> oZf;Z:s bT'% [{FZvC,x硫ŖAܚ1yǖ3Td^-8:f/ӶcŰ-eEJDPQkS.Pʗ\d³F?'t}'35++G,ۻ;d19UL~ "ٿcd:O(W}ߨ-nşdG&/&V[N7A*ϡU$l4)@62Q#،p:3H0lK_+VΫ]@_kJn^xP7}8|HK/S K{ʇQ\ݬ}a; x:ݠ5Zx}GLaMA}Jˆuc>| /=oHB*%MHXTq(D^.uŔK?Ol`e IV)OؾlNiԗ`277<?I\28gM;5.ExKԝM_6_m=."n4fp@`1(BTVEICFC|l4uQ9RW%Tn2DJkqq*ųLǧ<0;/ ZQ;8)RC > P<'m.JpnOLSLZ܍jˆnڟW.h:tj\{ "ۍ=a=ܛa"YR/k!%忟\^M ip P{QǴ<(ᨋ:Mߘ.XC SF<;kn'.s `zul`:ZʦL?)Xkٶ}m۶m۶m۶m۶mszn.UMrwʓ$,Dj?,%K݃&wIO* Ok;!H OXeE r-r!A+bo[8ڗmmojK+l%j/n/誯r!ﷷݓ[׸xno6J~u勻}=I=챰8Bծ-^tɠǓmQ#N 髊Ԉ}Uҷqt)ۭ嫌,\ef 1^H7ljQңu.}U+k˖/Ӌ +jZ)\}gucJ VTK҇1;<8>o8 hYZK.w!f<~xv>>sLN ޥ&}O=bw n+6Uy!B;=ZӃ8|gcp7xjF/NUhwxE%KWqh(NDv:!v liX!Y\o $J[8{)=:o\ʹepyw=]H}> ״r)ɘJrm9GI$8GOk&f3JPdS|snL?8^eme]eHCT׭oн6i??nWy̓B ׏5u<ܽH^ciA0е :$?beՖe"UqQ9VEΝ{"%Fe?(d=:݀N}f@dgTUA%D}*jL8ŗg vn2FJVabh:6к@|ZT°g]M_KqӖXպ9 ?>4Nge&~ùػUD8{J[GRe,bQdL]y/N8sbx[=g ݮ@4^լT5avv8w`-cB_Հ;2Cbތ>z M֕Qpڑ+Wzk&Wx =<@0"lKCχ`H.)WJw-w*ĢU+hpΆ$r1Oʂ/"FᷜhQ3JgЋ2rV.;9Јu3~dd}\\6i"Iy%%k)(_yWkolyl(7Z^2r3C*H Lr;g_ "0W]8T̟*PLC5*:&P٘4,4G@ !@[5گm~hI".ͲRƹT7.P#3盋Bdsct$QLE(AC>vRah)_se7-jx}c'h]7:g1 -ieOhjPPVa^Š5^oZ R slR$R ^TK`t8⯓xcdE&Nã6%0o_TdA)ӞJȇZX{p*i`-\Y;YejSdWGO (Vj IxGG) ob:Fdl^;FT~vrՆO!g3GG>Л,p?hgi;xPE6`l3sXWܘ8=Ѩn;iN ~Xkt(`m*UxZ=&,Tȹ\g+q+ W=[i`v.tqTAB/Td&Xd >*|UZpparXUw|I+1m ,4) P`Xe(7oZK1\.,)רF9XU;b)>&-vPd?4;Rj,cnjm0E[]6{yJz^?,hGx lSIF@YA?P\䠨.0Oj,>:UݱLwUD1\(1^$0Z/)([9Y5qԳbi@꒑t5m,ZW}3UE2u}) d_iQX.e-ͺcv]!Sn64A|It_c|[ECBAbxv,07Ȓ5<Fjn+M+ .e.ƦLm]lU;B2,om%2!1eXphaky!Xp~UK蠘I}6v!cCLSP=RA]aHR!/P:l&Ҿ9ĺ~|]ҰhQ mccQ8}0tbS &#@P] sd$!T]qm?3t9\Uz/+MN%:L"u/G^9Evz-QslnFKMxJuT8ҍْU;ܹ'­b|EYvwzH#ܯuK!,jdg˜f))_[j9+UU DsnxnfϏ%Zԝjj=`+`{CYr~\N qүFu J]fvߟg.8vuSfLd[U͉ԋPj;4" Nt^ʲ&c\N*c'Ѩ-p5vcP@@[5:6W?,ΐWo+%F%L50%ޯ煀ۆRCCY>Xyy9p9fxxt"skÁ+Ӧz[f Q1h&;+ e6n h,`E=\;iplUhxUsAxw`S; Ʋ汴);4Njʽ ="K XQ^%]CI*@ 5Ϳ:hN@ 9V'$BU!Jkz s;Tm@鮙 /`S&PaIU+GFCd }?_zvX,'EBI^<%F|߄v\^\_H:&cb^qbʏHW!< z>kuR#0L0ր&bx:35rh"+@։hx8=Eմƚ4sa*8#E}XY &3[٫cCFI`0&˻QEVtꎐ O.A'R .\{ǹScsYD溜Md!X~ PR+E%(nEE8 낡S}XxdCy> 9pO OX}pQ .e>2=դ.ܷu6jB/; ^ђlLV)lp>_N\:e~q.v @8PoE ͎q̞XM_ӛ^20ZE$Wæ"'bCZ}nh qky9 ]ɻ'xvBL7H-#oe YalǍC#(וB[#G >O,2BbT_XOQdR``e~_xP$0r*+dv㙒g$1$PT /_4ˎl"Y@SJHd  [MT/ r/(s#Oj'o4jHJG`E^6X% m?ķS6'Tv:~J0BGO R0!"G$R$O:! 0`J-#x7 `R+T2ݘF(hBuDzFP_#:&Tj&G2b4|1DVmRsT_F" -"Y0#pRx';610ƯOO۫+Ug^,@ ꍼfśU-:/(:L+)os_{Gƍ== |I=9^ Gh8╼u=Q5n#OH GePjY¨#ϮHz Q8$[D4(F1  [M~_\OE<9nDqa080q>aRJ[%ӽ@eɺRM ~_o΀|3hEr]CA-fHoÍL} ;uJN ؋ 򖍭od@ӵ2$"kמ<!Vb>vZ^k}_]1ۈ>`Fn[y/gʼnՈi8M(${ъ]+hpH+w 5Yr Fk.Xq$.<*aA+4H'>"TlvjzI:iGEޅoTq8{,j#{Ttɰ'`HKO @QU~&7%l@nHi/;yH3 ~CZ:Z|јc~>UPLsR .l::PR n)ٌ膿UeET@8r-~RvwSCȈ oĞ&P#P~{ n8Z?:pe H܂LqT0;-0"R(kbXxrrC?7C+q&*39E hekL`E|0#'TA"%h UCp;F9QJ9aQY',Ƣ"|L'':#;:/x<D]rec!2Y#JO(tR-\Ki)7sW0GFW/ue};2Kk}yreu~_juKc =+ N}؃_db' 8F?ݢSz^q aS{ rr+u+,х b;f.pt,7ڗv]˖fVa7E@ZvLh U{n~]n9A¹oiĮ;+&@ӣ\7bVj cwfAѰI"oW<Q!!ep/ D|tN§P=TwBv_QcQlV*@'pCAᒈBS[:*(:nDXfM[~(DCu2Xޜ5^xk̼.m9oĩ71#)7#(kdC,jh<r L(d'@ڌ?p`|&qUBi][CRkwƹ-5HfP')*&*iݡjЉf[&.Ka<#3mMqV0+LLPSTBFr7biK9ƠJJ*.wRvY&+z0X>weB-F$ Fg6+?̵s摱EfqTӵNxpXDq-~L avæSpL+<׫LknGR+GUqpLf8OAmjNSw  :=W(7 ]Q);{b;T\YfU앆S 4s 1O8Okj<\5*]Byۅ 5&06\FoD tD;%,qU\fhxax翷ϔP*X6 Qh.%F"Ũݠr8$F҅ڴ0+59T0U Tif܆Áo |Id6`pV1/b4fɷDĀ%uaʭ d@⎖:2M(%MC2w8gԄU] ?g:U]KaX)@ot?4DWieT~rZ߽=*dmj="Vr;H.5|w˞ 6D9ҤF4 l6ms*5 8ڡ; I' n'?e! ,sKherEOB& SU=3۬xmR4!}:-'\J &S3(,T环[i[ {FNʴ@ҫ*[ib^q*C(h.V;U1KCI [7}wy.O*dm33yҐz|@ȅ XnnJvlA3=lL6[A6:y  uE NK"-/0Pi U>4*'S {:,EXvNw­[MΗa0! S]+PbeO9G̃]^D3Bc<2p$Zuxuq u ݣDLd4oҋ}k_ I:QfRR( VմuNGQ#&kMlI$L]qќU֛>#pV ~tm}S{JWŀmB>Az:({4+tdY9gh47tTO-4Ma#`2RV o~2bsvY3^JtYt?w?}L,a*85Ҟ켾ɸ$6xEb7Η.YW描 t[8;蛊L -/E1>i20F5U+x(wJ]Q.J/ND46Zv$ c7pZ7k?Ta%JioYh=s2ifmR/# ܔk=&[4B4_UA+'X*\PN$1*9@Z=>ާ*4Ϛhꟑb@F*B2L]:@ܱƎ6J^Hog7ƻSg.\!lw1.5> f9zkmԃf0D4vܞ*"3ٌx%tIc0 %$ZuB|KT8,D`nPEEJTlB`uXrFULVJg Vh(i⻵"Y}l{W;EA.Mi*%<56PhJ7Ĕ= B&H !$957i?1g7UFn+ii\+F|`ϐ/ihoF 8<1ZٺNJ7|(qp?\swL? bo1MJ\"b==]4t|8?_>c75W#j)C22JOW2Vקp??x^_斮[_OϹÎ )^ܝʭ+[?{h op^6Օ c`1PzgN 35\5Va [5n]T(5IQ}r{5he)$jn%wxx>̶ݣ vrp̍4DY6]QMN~as_gnM09~\xIQgH݅n31w9i<vv~{|\Χl)(dwL'@%Ib-txS>j SQe)APF.8J iTE0r}_p_#KkbL-%S7x0gL#T%Dh')ig Zh!$]OjW+)?DbU"T8M(' G*c3@d@q^L*Tz@; b*g:  0do1YIv)Kgfz*Վ $j 'h&sl]}?WZ[>5V]9}yYȣUk|E5]*P V<%5(@9=qA'fbkH Rcrx >;C 2ǘv]VmfWvp2˂5?;ZK~~47jȤ⤴' L!aF4@vЃcNN@[/0iŪ~'Jf5Cs_.dز\%m%6xIA{Q8ݘx|#Bޞ^JaD^;J a;Wi8" xط 0B-瀹l" Gmt{IuqJK7()МҦV67 ofPO\G 5Z]AsO/TL+qL(Sgtϡ_(BjzweY1EUb0cu H*TGySw񚸟y+fwoM$-TH}3ڽuqA uw:CκˑXY3CÇY ͤc_/0oeW/Wc+\buQx=-2?ݓ{PY&%ϜU=+VR=M[/.Bt fq$N7g M e6 R 1=o`8a3r `|uFwF:dWE圇4m %ߛJ6ӁWhIW=ڢ?px]Җ8Rr IÄhO k3S)wi|M%fBQ%Sl^q{݃u5mT3Vń@pU8'-ȯ~e=ͧJ=V^Rp5cs/!ub?'ݴY[4#Qcy! ұ,˥>1&u -qnNr2ѹ\s1"'!T&mocmo|U-p(wrk@}eV9:֥Wv*<'kbCt! L¦*^DžcphirGhޒXsa(BXU:`7 IyMU%*7_P$y>0(~V5350tR6ſ$}5?΂x%xI`]<C3gJG ¹f 9ɰ3jsZAߞ5m/Z&P'uZkdFQ L9Nא 7@}7kMwAb-v]JFw W}n/9n?vlnw<'4{_{{'.&$Ǥ;M+Lh&9'e~}KϟVϫdtίmvy?Fue~Wzy}TVcvq 񪶴_vܶ%W{aX.8Asa'm?5njj7&h(˖ zn$Y}4uȲ)'7sIgCI+E7;=<"!apAeKC2=|"5)6,Ew^GG^7"BY !0kh* uٔg?YDVƾ!1@ dq ]y 7R[? шG7]GEm3&mB c:kxP;LĮ!?<(q j=(t𠨽D#:U tϖ`̐hZ+Kf#U kNCI x@ LemH6FۖD p0:Hqe}2nuB;#D|IzڰsZa‹ Lys`'V` BzYD:.PB) {yW*QW[CcRIn`#)/2?>fu` o8sZ KjbTeOqnbRb"Z"'lY{ *{x?3xN@#־D}S ./'7a,&&W(>} -+f.4h~[;[8{Rc:qBR @dt#j%b5e,)9#Il !`,7sDz]C*P\̀*: >$[uzDM(;wd`LcAܠc/-{=O}xHMO",U5w=.{dA= eY#2IM,]g3J^Y-:(η?|Xxyp[w%@@rأLjVHS1ˣ/C%d9*&h}&cL]S#^NNp<NgE駄-2w2"H߁9a7J|kz?xaUwޓ8f&/$VK5q&]1bE@Wr8!{1L6{ syа ʄS)Z-+D,$"/x@'TALHk$Sba=G"͉&Noߣk&z2_2ƮHv'%ac8¦6K>ʄL"j0K>m qp5ʑٞ}ywKd_4I<ՇI Sn%6P#ύ*ɰ@ȟW\9ဓG%'M%;Sj[UDT̲Bz;}" 43HorU qST8ڿilF5Zn0z<]?"O|nކ뭌p}q|b|>q~]gCX/ƷAy{u⥢|D6yP-prn^[{Xp,>ZM7g:i̴J^kWR 0q% /0ͷK#TN^p^ !4*Qv-coiCSs)ӡvUuŹL"yJ #U?4\`(d *w ܭת'Dt4QE,0Wu䰴?ȊQ 44I!y\ei/_862fk'mLi8 9)6;ތR(f8 oav/!v2;DFr&_C.۶m۶m۶}۶m۾mmm[3̮J΢NR+H-Vk.vcLN󥏯[!U)v=TY0dƜ6v _{E q;ت9F&'y $/F64T5h OF'h[~~P)Z+ZsPORuT ?)2QZ6u1;TZ/;S##n9gF|(% {&ԫ3:e8: &O+D:6Qπ7x~&wOÖ4RqX宵Ϫh?Q,uSdz'ǏS)Z=5{NJ',8Qب5= S3ު18CRij@ "CڜFi2ю]&1뚋*%&IzLZqIvF2DjazM($/y?YzV>zV^5gDV}&525*K-v|tW-f!Nnd[.8| 7stC0}܉iRyiWj/݈M4c%=eF)%>W$O&: !A!|-hT\ +#Ȕ:!VVdyĊb<7'#B N*DOr&I"퀪,6zKy e7]_M P1uSRyфU.BdfOJF{,o'V&GcNWʮ|C]JsZ]aJ3p^f$,Yaz.02?IF#@ArVxTwv>bn?:_m]szrƐv}μ\L>Ygy|`R.qm9h;aOS~MwKj4ـ=Lf]4]XUQOtrZʀ9rsiLb-8Q7H4uu hqyiZS<1[xm-v# gէ Rܽ X` ㎀/L>*g}'d;9k^ M%Rh T=]'S@nKbfKkXPTfG׳r-GhWKnEedC /~k~Ы݁m㤕}VaOhb.4u_ *f '7"%fljdTL`2T2!u]T2nߦi⤜WF'{7B 3f46/OJdA;v> qO(8cg@/ܷT ~ c(QUJde\zvm*򐷍lQ~@xsٓO Q <lU5|_'&lh_l^!lF]V9*? (;AkFEf 71ѸRb|k%jAFTc] w2ٸoֆmDXҬ?2,Yg΀q 2f@s] Nrܲ׉rL1#P[~SZq1f.vk%u*u+ w_i񥜜s.=g;s\xd/W๔~UeK&ݥ2.Zb8/vqBC:d̘8D!WߘZ\_ yIpysrboG (o_YTUuG>n$_|P57SW^?.}`ѱ@0{Ca2ci4OqOQpC@0"q'uJA=a^'Ho{lwtrՋs;B{-^>yv'+%7'j$7zAU#jF귥Y(]gkW҄A&++$vE,wHw4(NJ=::G3`ںob5+]sʮAa6 }dcMQw&ڡVUfEUO5(0)}ׁEi{lcBa6?PEY%  q+oՅ%[F=ʅX [pB.~|O9ܽcM2/2=΋r.]!kWMe!hֆH$9^Ov{\>riS5]1/iaLn` >)JFXɜtB"Ẁeh¬@9P_'4qđ`p.=}C^Pٳo`K Rcdj$4w0nA f)uR85iO0"aªJŔĝ*D܉7XDs^A? 4S@O!UbW{[)yA:5tXjLdJ: 7ޜHP5 n_קu#_ÉFd:\E0L'YU$C9 WA\%&'KT X/cHJ4Ķnk`Ib3Y߿7& ;{x4.gD2lda,\:*}O+~xJRӇ8r/GDL׉A'"o҉KhfK894Ͼ >/!\}.hrA~^Y 1AFv0Ar?=W U#Eޯçuf"Lji?!6Rev8&Y p'&OR{o'yOnIxd>lZ ҅+S9f^Zǧe&h e A:]Tq4~+c<81ֻqT,ܯN}o_.u{SJ>̇E`-PD2bqnqO@>#⦯!ƞ3??}& T]6,fNW#skzm3}Cq!i b"\5[O2}\Jh:c%CimshvE7ʲ'~}(sI||۷TZG;.9K:J';ΣY/N}ikdCEFEЈ-T jf :[[o l)R:'3WoӇ MA[^H\C*-̆tOK{WbqGFN'3^(;wQpAt6>!|{2V1ƈK9uO<ƟyZ)hM(%L>fK; 7̔ #'Ρ˳RKi:,J*fyz5hLښ2%WG6:V8䅬wMN JH^:rfRO )Z&'6J؁ۑ,{Խ~D}.Lzs"a)N{ k2^KB-Jk0Ֆ%6D6Ufvr};oy>Z~X/ՠ`3.565! <)C;-[_IrRPfqtLWD)|Nf_bkT$[GMjZ-QF+RgV\.Q.{ 3oC?27Ӎ1]inA Z )VfPG7Lr\%k?;dF&mE:VZok%ksZ+r_ e2#֒FE|c|n|Tk/dicBgJeS̭8 xA܁䲓cMb[7 ٦^☿D# #CP]T}ȫOx8 ]!ߋ!i9P}]RbzqSŜFs{ )zf^ɫnWSn]-yq,yڮ(陎V7: ~4 yd=•!ȑPlnX$ڠ+W[<`_2R'506US Uy[{~8}pJKy0}*P`RQNLm~&t1I,nI`hdMCwVu4&Po|uJ-2K:a V6Hj_nAo* X }ܗJؘ*C^&Q#uRHß61Ewo.!oOY`@LCMߪXeI,1AOO}n߄xUB`u% )6a=>qS2/Dz]^2П{J(^xH}ewrN[y῾{IVJ0zṛI1Ow5]NIB&Y&yǨv[o|;i'td4ӓ$K*zV'Vۊwg)čp('զ9FY$MT(ggC:z@?nPILjjJTI$$Y H X0i][3ƶA2D31XqwnՖҍx{oO^^ ZJ}S{5DX_twKE"!#-ힹz" KAXYp? [6dHo'܉җ햻pAzDAW6nY<;Lpn=e.n>ߞ|+yz?M;s?}?^%_ ={{x !'k;{?gK$WNOТPNi]x5PX}TmыT׻7gSčybߋ!>ʺ 4z #8g$ t?ǚTW uuBi8$#~Wݘd.t7i:)#< Bϩ啼.04|ƞ)5>!#!,Sq[f ϰv~`96߸_ӂRp 7zqbAuݾO8xR<:H"D3>q#MZJmRaB2_$>ɒ# IL_ځy}A{L÷#k[^ TÃʌpű7kn 1 ڌWy`{ XM3XK Kpna. w!xK(o)Нj@z'#6=sȌ+Mf?1(-tƍȯ4PZY1 aǩ;{`k08},*5]:ux@nU3&d3 S [jͳʜ,WБy5UZ&&Nf Ðc&T.='zr.ޒgj>>ܴmW" l)yɋݻw`UE*V듙7Ֆ/\.5C}S2pnq&7g"t:B BI/ؙ*D c kVdrH&^-hdt:B`"+.XI¹'nV+o{M~ή"Ĉհ\MHX~Ӓȇ@P$yƓ-2Olk68g}P3Q-(pVGg854 iܖ,WsAnU33@8*(Pq .# ˝R @c6NLأMֿBgB߹ē%Pnl71f4Sޙ~S󝨛2NҬM;۞c$jgFZ ֡X /zڤߠB?JR) H7grÙ'f=C@źyݒ}a[K"zsIFޡcl$? DE[he쾬H{O{:d 쪐H[Yߴr$K !  Jo;V0 W,Rٙqi}W5!Bi26s_<s0ş5̑aw딮JPF?趿|۝R]t3 mOކmɾY6jJC}֗w7&=a4z2T8j(H& /*Dg 5qjK/lf+wJ0 k)\b,0V]﨤U _mSa4{Y ky&<`I}82gi@+M޿wW]x|{qoD4ui/S- KCpGP>:U (P7pe{$gY0tl׷䦫ԷBFIM_ YBZ|-1StsZ7 }_aufoaugX]Np5$~ٵ>̩5imY;I}98YX-w*6Abgwl~OoCWOHcc5˫w=i^xޑ^gO;{?ssgUoB9 }D=<=94}yp}JR:X hv٦Tܣp;=\pj-}|xg@P:2%hELFwwO*3{^7{Jc? 7ϫoSd{!T?"eO氁#?%hJEC9.+c*nvHm.^{~ѿt_?\Xk>Xh!x2Po|=dUnI Tޢr֎5MRoݟ8I N6 w/9漴yC. sLPhN<, mV@żBQOyli%|{Taׇ:5ZܫQZeT/f]vXye=ZN(ՊioJ!1GSrg|ݛ ^Z>bamUC´d΁n^{,w/ BlvZ*왪nbwi 5vHmzr)Xށk̮ h*5(/6ӭCq9 b*_ku/,y|canpCpl|Lܝ5/ie<,& &|Ipsk DX#wT*s\N((Ki[3{dp!6~$7uXR:xM]^x 2b K0_3ӯ :0h| zeyfS<|nI<"x]^VA2at8s5!k/ᨠw%¸;mY:;# g9Ac#YE> Æ?_.Oצ)}-vǎ{1[c{d> wj6w Rqm{;|C7):e)cZ[׎,w{>ަTk3b9P'`kv ٴn* zDMM_HZ~h@ _vr{s 6 JsEP\vO[pR<;"+#kyp 7 P>rН7<ϺO2qo(}Mf^5?m|5<)͸/' ;`XԱ-9Z/ :zTOl:1Z89ׄ5T- 4yDtNSJot DG$ɸ;:N@%Y {ݍξ.*0C;ND_grC>tsFDC=o]u ?Sp#;0$dthm:$9Ɗ0jX )0m(WՊxjk  `_ oI?zi}1+Xv(y֞Q՚nwǧoa;Y(_Ick͵p'_5Z7΃rZjj~;Ō%nUb4LOyʰ~F*ZJtΏFomQ=m{&_FƅN-}LDe\ˏy:+<Ba>oVI^ )xg~SGUnk;tunW[?D`caq3ַ_\v?9fGǓ|wuU$NEȞ}ʟ2w o,zjmܴC9 휐 s\YϋٯmUiP1I߮X96"O9ɴ1zb\IdQ}Q#IeM:%!v$ǂ*|1o*ߖ e{<.P<%cJm {>Ԃ!*|V 4t >b13TzrFעܓ(دVF6E\Z7sU12Z(Mj2dwڴ1 w|R/ P<=gUْcsQ'ij4C`?z`Y'Wra|t4-;2llV5!`=̍J1%R*+lUu2kao$KK*C18EiiePxۥ&^&CyD(5NPdګ/t!5VqۓqXsyz)nٓkS)C4O 0dC55"kdV K+s6nO\v3vs.v2!A!aZdXQtF-2llW %ƍgLZ, mZO#UwD9SUרJݣ,.31<,EdUJá7W>d9=3t 6 c`B^YhW i .jL{-BQ, $5&a2g$P#a(zyKb%zCb;_ҍ*$Cp~eJWgY)O6uLslEP")nfJ^xfW  6O #VLH k\ތX] ^IL_: y[AbFTc ӕ-#2FMaf[mb5EH%EqOk4؟֠fl%aڧ_;$ebGfxTjtWKwWM8>-1&SEŒ*$xt+ cpx\]%:5<@.tM NGGTM rDXy#,GPƅ>"Kx2jLmN|m124lsZh ,ln=733$[UK@ K]ږ,yJg/- !gSr[.im}r%,83Fn.d;p"jde"%LA|~.Ʉ qP4Y)P)D> nAF;e٠XEԈSТQKґGj4$w#L4CgfmR<`Z!;⒫$iH !i3r+D PO:iڿqeF)PC%ޫ. A#i9cBRt@ 5?#fnL*TF=۔U7ƙЫIԧYԡ_1dTVf_W<""xa|Y)^,_[t*N-m= o&Pv%NOUp7md/jRչZ`9gfYWg'bV3c+.gӫUϺg ic:u 1/4ld!ܔ|{,5tJCʱj.{vh";qJcȿm?$Mmi#sY`˚c-A׶;L m#N;c=KH.ӀghHPL$%/P;c)٤XkÛϏ ]}ȹFTҴ/ϰDFm3J-$k  t~>6sƓg]̈́} lDGAI 2)Jҧ`QN姇˥D]YbV!] ^R#11BO+ #T_#"ڲR'I,59 L-DZxP!i.\'`ܖUn L_8J&K^]:&2lm\bcC(_*D]`KN,?|3Ү)Nr8em cFhe\ !]kS+ $0Cu6SY /N :J $T[RV*5i\ۘ'[DV1N)I f CφN'^t;\l,KAnw9gWwF 6]&3U7"]mR#D+d#&u0YPT'4G7&AzTjL>-^* YF.M5(lKM8mTƊL !G[#rݒg~G\Đe< HJ;HDrw{RlC :Bz܊PΖ:0 vQ*{E~H!/\mΝ]awaNbbʆ\bClG.eW6C]cO+WPc'wNׯ@'S'X@ )Gbt]*\-U(_sL"zBTcTdzx/Ӂ/;?m0 ]RyQVI@#_yY&P>5xZLʄae4j,j\6' cz#1+zԎy4@«Up/IсyDˇ+|:\wo%SѮ0rMU 3`rJ n$xD0BXH8VwVԩh7QLrOWJm7Jm_JPZE Aajq.(o:KF=sw)8^&ĭʺ~^[5O.6|1=R a@U%qb'TV8N~eQ)IjIIe҉h(PMQjw@@BwUX([gdr&>ouvfp w,AFI6ٌEm[DTю%@,(eڭw|Z>%r6{qL"(Z}VKb_r%]X.>S朗Fo\qB%.ypN#%!ENf橙2, XZOVajmwH-0|_4SUIQ6$k i_q1 x(SlpUxֵ$duztnϤp_,'eE9,fq%E%jU% NQll:$2}$/f[]˞'+6I=2` H"jb(ńAf&G] mz,zfQsŜ:AS^@\YY֚2` p-P?S( %#|h4-|y<.0XQW$oBU{#RFlB.aBV&i qˮb慧u*[!{upHDhf /,ʏBi iCe3`]QiF|{($MD~f0<[BbdQ Ym. Б|F:X~CՐ: N"*;9JPq ƙ@H!Q;Xv)Mx8SQ vP%3jU}aۻ}Vmaf Sj;+HĔݘdjQ-Ξ47Ya$wJo XQp$|]W8xݙlJL3 aѼ+7gg*S Xxa Op!kJ8EIrJV)J oVRArY.6BKhj}7͹ܱֈ 1 bYCi'$Y 竛 1 ` g9b-JX\.4tBHKYwr@tx݃7VxtL Z%H "* w *L9_75'>H:@|if8$YŠlwrܞZzNCUs,+OQ5A>)LTmQvl.+7.ws1i3C@0ZKl#(ơTHz壌.GUv80I=t7Ka rCOUpDᄡR:w}Mߝ{[VI@&byJHz8 ×ष8qɑ.UwMU ->u9Kn=BarKF ,,s;R*`;]81Hiv|0HKQh]͊[}IED[6IChȇIm `q4'i6 VMme3}@H6YDlYm7b,I[QbgH6줯s& ~utKI'o15K$h$l VKؒ3Po#Y\Fqo_*$iv;6l0;t8//RK4hpAPgxwU1 Lk[1d1_9W@6|,KJla= NZO!zjL{zXVPs.GԋE&B^|`q KDcVcK|G5#7c]wDo+m O/AO+ی xsd2䙁(D.nƃss&SrfU1s4ૃ,zMٙR_bORLJ#>ԐH5k׫?CA^('7zPNy7y߻Lڅ+ۿӁ G&3q'qiYd&+x[RX:w/WVQrg(~t%/~36wwzQd}9tؗ"4t~GG@JͬCUByX4fv†yoz*fTK(9HZ[~ Jp>|_7n"UQMOEU2,91py1$y#UsǮ +.@gd XאMε9i%ȣ4%+V$My{;e˼nc 5H^:?<`ETsP!{][V(2uy'ũ:ALc%xh M8{ԇ4>Qtz=6C._+XDYV tfH7ziC4;PKǬql#pw# kU_˕ }!D(g7_y"aU/sR LSt`qJD `!F(TRATQ ȯHvs<ߔCu zf؆ `9=KS#MZ% Rk3-tr\ dmr3oS7C#Ս i%fqr⫳>Z)ŇfU ʳerJc@P{!o2s9A-9-g@6ٜiF^XQr9]6O0쩩3ax($^Iy|XJ*Z? +2b?X*C#k9F1FNK)$;q6|SRf=\K@Ko@ E}U18td&r?:q Ʋ}rv|+w1I+vۺ hf5hN~<k ])dS o gu(ɸSkQgB=^b^Q#ʵaD/ԭQ6 h ČFs-?jVxlv4aFA nYs&ٺj`?0\|>)Zw^Nd~Wָ?7#m+lDZ5/*1H:q)?9YOq,%d͡2m;Du$`M;VC8L[cʃ-%qfh2Pq}/iI"~2N6V-ܟd'icUbΔl6k7l+=czDyBL4=v$ |wD%p=>W^v$]}Y6p,b)+xԵgEF)YS{>CJ-mO:f[uӲE:SՏ*_y/dL3& * %ܘyu%7lx)jA!,ljbl;e: 4d?!+cA=,L峵cP9Jny=dI< ]$:֓%:IE(eoXWz S=(7,fyD;%of/O2e$/]12B:}Fi0xS=B/]0vP1 )3b8iz&k(5S,ӡ+Vb9' LO֦%NCFc3Wle 0.zŧG,mr6ݭ "& Vcc;'7?DL l#(a:6;h7L {$k-ck R3q|*kMyx,`tu -|\QYW~U+ojتirv]^nUq6G"_ZpsCD&aB;I[JI<6gE0<|c:Z ",@*i{we#ŇՁyt]LH+ҕao Wv6.^ZbHF>7X+CP(0{^5<_(Z#u<25;  O}cH@>FoUKˆccv ׵ c;0²}3tO׭4B_\oG溜W355^ߗ%)SCۿG*?UOe#.~FC4t9[_XL2 :KF -ih?(k;Lͱ(;3us7:L3CFP5X,o98CnT,Yv$Vg[ڊի߱IWɦ?K]*ĕM#&JӠDG訖lj`1pA@f9 YZv#T]f$Ҳ޺!&)$ðSg)zC%wMa ;(hoTn";(@_m< UT &0`\b^BA;JWR8OP^yVJ %߫}WGvׯBXzkBoEd=h8q?2ա:+5xSbS'fQh/,0[M!/76dK*ŪXJ~ɱ)oGl0@H&QJֹigXa6&,,+@ۇVS5?7{9M^ Jt],s$VGq(gS6)0Yv.]2. kʦ6tW_pI&8Hrp.݇n(t1iVYcV":-KbNi iY`Hw[g 974X4SjhuqKg%K֕h25M[-H7KQnkQLh-my#61 鼊gnSo0C١LB9bw 7r‚A5utx 0M\:;"o'i@ēJʗG]`jIz=9[isZO}sy2!0-K'*hc4+儣38Pdapv~ f/SfЩxJM$I6iOF=* 1OڔyK`f(m;BN%[cAK"S֝(/dKc0;xRw>E8;"x_æhcȼ.rV^6k*o)mV~)1d[Ig[/0 ̈6WlAJИϩG*X[X[Yl SjgHd6p},81\zE@>h;T9K~} ??(5WưO85OOW[W@f.-ѨQv=~߾] e 2(c>*Kh?44 XΆa2K 41݊ĭ`褛 bf_bwДV08˕{wtSY9b7H3%h,Eq ݯfhޞ387+)5=YiEu@zNn5Vlqp)^La0+FP}j"BE63#1{ 0w%`t*Ml5\p-KϨ)q#=v2Vpăj8^ɣ*F?cbU6CADu%V6F\aΟK4eCem1}QY&-lˑf-chȥUēŷΒsI{8*1N&,9Bs }n_ԁL}#lUoɎ{ AlBTĪl[-,tSNE55T5Fȶ *)$LOqV^' ,"sh1 1nmODsNQ'voMRP?aS%-[^j̐V&D}_sMx}a9C<_H;,%[t[ b G 1p#؆]ո"皲_r }@CG*EDtA%ʺy*>0ē.!wĿ Ea)CzT(S'.&-YbY)uXZWX6Ž>@O2l6 0vg Nƫ<0zƴ¿hh" ޚd>,R<2 7kγ~[5kA9 †C^: ].t h/D@Tqv! .׼;%L(1 ϢLRVqDZ$I>@yǮoВ0L[Q_eKA Gz~SRA'[qn=ңgd .]2ӌS<)_RWQG]f<bm`Q7uB\H۴,DonPg+9kb&}#.>?^<B'+E%Jv!= !Sa&t3`?>^#3tȟsY+q={?l9xIJ_DGg9wto M<Ռ;A#/'*,4uZs]ʪJrG#0~ߒuŧ3ukʶөwξ{qLuN?Nzɻߟm?%F߯Ǘhy8 ?ʭw2oiM3T \AǷa׳L>sgkI0*'iQXAD}ǝn}~CR oiO+R%K䡐})gIl½OL^<4ӗ#Iù]aK2(d~YRd({tDX?ܱqƳwU 8iL@O29"%h`:M3nq@6IȚ4jv"k35K_Y\afb&vSr2Aҍ믧}m=@9pY _53 FN.@ƭ:uR/zoGyFNG&و5;nƂ;džN{Vaa('{.ۘ,#aq$KM_44BV;Ej8芑lĩҹghJ"7ҭo w4~PAsj7HǑ`~{ !:5gƳ{]$1to`.lDݷ+W8ޙEZl530pgjt=t^2_/$M [y:~h4G -+%$=''e%C>F#^" G"͋ʪuҡ*{P!A+nAiڹ.ǀCnBUK=;W]D\u{N[SJ4e,?m;Av4cD+@33lMԳ1[V* >XfFy&$-vbFY}LXpTwe]7Wqepz8'A4qNF@=X~ ̮VW@@ 1rVca?IK6rHj@A̺znm\ɟ,f% yv%8Ge|T`DLQhghj ShСUV7qFjy \j0f~}9 1z!]J)E [NfH7Rxs\1.-̝ \eHfK;B Ԥ!8,3Z{\t;2tA3sss!skffݝڌJ5ӟ37ah/{w֦:x)"eG+wb~!O59YL=K+z:DuCOwʙSrA3L.R%Jv?MHS7fH^ ċ_Ѝbs~fRexIb*}TtCV5ƒ`OݮLF5X\ 5Z65RCpJdmac3X0~Qb(U`eJeAPa|8ڱ#`(\o85TT wrX[Px$.F0Melz؅X'ڙnU])|,-(E@]($9a+.f#0%G_W x?8 N6\.U9 ־DpU-eS˷BcB1~iS`J9"̎OJ4Y.UW!y9|>EKșL6NDJ㢯)n)Yh\D_pi>L ʉI헝Wk8ٜDiNBjq V8!C!p6̊A͢I? *L࿳ʈ; 0x:ۤ 4siAt#|eqKUJ}2{c K4F)ƯkXAOBgΙ!3ea9vA"%$ucS@z Fߋ|A|Sm!qsNn1qtzOʆ[K&䜬ER=eT9Bu>!ۣ#(ؐ) bنΖɡ'a>8*܂~Q?!$m9rgNMg$S87a~&,_j0 |̈n],/Io}oz?4SƨXLpnQ8}X5ȢSuc\IPzŞ-sOxҤquZQg=˘ZC 5:]P `"ZRtqz~yzyjJ&FPG9A %(\H!;dz<0:FhBrFnKNBN&ͧs4|⛶ߪ/Uy}'aRikFo'R",evy`0Iڭ}4ƬUkČ C>V`g)r\5^j2؟||iFj֑#7캝#:a mhcj ʨdy(B~^E?D!(JB+Qݎ!B 5)#}ԲbN1TQoXO•bM{OI @)4-+a"t TN唳n'RpeNԎ|w dp9H h.Ѣã\kmt& p)BdϯY^r['1HYNtXCV+0ҽtbA2/+1 GXb@YT6[N$ZR+9䥎|J.D10n75VD3vU2Gj#7kl2mG !\ҥy\sx}5)[*y{Bׂ)@'B<;wϖ~7Le4Q#xPtyd:gt@TiTfj>/PMMNض-slk=]L@%P& q׽s@Y}MV]09iL- b)}(5p3LSe8b NV* 1WGFpc=d[u($ k475nY5_ZpH|TƮ*jf ICt{}k8( O>ƨ y}iXT;BvՐt (ezPJX dSk%/{R\693y] ,\8x{vĵ1ɠh?3>alVJ,MtU wIjB$ w ~Da'l| 󅁒\q/bZ(iteRGotF=t5HULO./goSU Pl+Q:KI]w637@"[<9#lnf fI506>5C{jQmf2d&>蚲 k>ٹ$⩭lX.   $U{RM9=MSߝu [@ "rB"xE5 xV&8bKō|6?.H9_Fkid:RDxrfwkCR.WCWs3Mbz*1^BLuWn BlYrT6 ;rd*kut:W(ȉp UH4LjI8{D\-=.:C+O{Yns jSQBڕ.4r Qsd+zrU΄G`!v}A/sp@tySnʹ cU|TؚSEJ t9Q"-'㫁Z9ymbM,0XlRP1/VzqJ˘ :`j׬wgc٥=JZCbWw`>^T['ɜؗ:˗{GXPO3 2f|(vj3y8[S^sdW=WN W$@kKq\p)bZw_u)F{'t8>X,X޺{kzF%F\8 {ʥv4Bd%Nw; epfW-ՐЋgҲ‚m}dˏT|ښ ݺBbtywlRU-^˯@V;1#bDYp"ùjZP9EMTSV+T% /2/sO*EZ5alFPB[=nIJ?Ô1=&b[dum#rv1[aZm*MLHab[D:SK@fLMS]:w;"UKyFoݭ@?fepf{n?6d_dd}a^Qbi\|Oj,wer Y 'Pe1\\2/*UT]`c M B:縎02E?dpcMIZb*;w=wz騲x#N:s7)/6ɗ{m=[y^.#2ܚHůP=H`FaFS]E' 5cpXw{ʴ_#xzx}hQhg˅fwsU 3ۋ 0 Y,}\N-5 Syg Q_Aa0,H3gQQE(D-D&⻮J ̛%ʤl1UcuP yZuك|-^Bmץ2 8EzoeCAm:B:Fx]݉f=#$fLP, 0j v9&tv`bu9.34̡/ >,,|Qm!vB,ef8Pm{REzW|^a^CBZ..3']j@AȈend5b+p@d"%tQ/ռ6~W8cܹuM(m`B/eYVR8gLX5S 2gTy$-|-?zIφi;[C}뷺)i`6c]$XŶK`7 !˺<@!H j/ X}.JwL :OJ궩FMQ- xuQ݈2ϤJ8MH94I/FUZdY*"4C*Pm fr3arb@ FiZf/4$UZO|v|bPSKP2a+G"!VtMY@FdP98@"m҂s(JL>>JEJP+]4K6N֫"3S7` JVh[PrԊOLYh06YCZ(Xʃ)ݗ-V KU\q$Oɖ&dZY\Pȴ\βlY!v0Y/uta\\4fM3gC穅gl者w3~Ԭyu`1db*`;"d@/QY1IZ?1\5$]JN+8ƣa;qa17|;xU4P1qC-5YWm.蔏"-MƦtѣ3S[0OWp~N(j׊5^p~rf u2K&W8،%e.eB^f$Ζ/I@Ôm&bTs'it͚osbwSST|ckn=g) VG_vouB%}oL OXỷZp?Nh]H+:mm@G7g+,_6\y`},rW7,mN FͭFqK*X&Zn [J%*B>x.B)~-ZԨv\tļꪞ>!7ċ' .xZYΣR/5/FXL _~(xnuZF|uy87wm86mK Cf=/<j&ܯ~WJIWt=0E| ׇi#Cn m콚RNJf8QJ>$I7͑i/"sءŚ,2}4!t`DL7\xqh6.'.y)Wo{i)-Yu8t*io.ym4Qw Pm"`BEdQv>֪n7qcۡIU(KvgwfvWovè Yj&rcd~''{I 1'~JkQI.{ކ:;#kNއ5PyxMbdq i ukS̮&ˏ 1Sxa3zӰV$~)țNng˰O}UY+jHTr׭f&tHIV ifAT&%&~Zcהl+/$(.E'"" Pxjsh l딱| ZydHHNgj{z@Sp]l|Z^%k7F0i-^<(-CqB),hQX^PxQag@Sa#7yȜ'>QBz'V0m6dRRqG[ P;l܇'+HJ:CK@[75P[ieE9ꤺx! B;t+3> ץ4$kbL)>9'b+3- \_.ZVTݤ*$3hָ{RzM ^,{ˣa @<kձZڿa>}p5`<G&N!J5Q7*{zzЉxXȲ?re]X;Q^#4l^UpkeVp1t470>Wn?sYUh $*WQWrZKœݚwq7R8]~EJ֪p|VuFB7')EzjD9f)v}04I}{AI>((޾s;/|U4\-j:oh^`2DClˆـH4DMXtn`Uڛn DLe镈/NЉw Cb8?@`aRx )YXFy"}xIdYC$4TªQ[X`W9gI~^A΁"Q?&ol`vC1} -ʄ=*ꖸU8u|ِY,r.7_' uE:Vݼ?c}Lyiv5|sd1Qumۚöm۶m۶m۶mۚgss>yZ=O)-4rk ث+5M~{.?!,&]_m|ؼp[ M=&Gjs؏:} .? zrWĥln7$3h$0@ѽ%u@MD | }g ᕁ_KpN^ 0X_S&m2<ŋrGfҭ鸋WH}0Sd:fN*\&U%}b`X*UxvNB4QT H[w̳_쳯S/t Kv;e~Vޣj*|ʮlp,9ͪK;uEJ E_Abõsi)}-?N)XcXXzՏ3&`5UƲt 74 "ˎHrJ Nḡ%QA؁tє_ߺ_<ߏZϛ?|Ѷ~4KS~p|_?We>);/ǝ9ㆹ>Nrb=dC,rPCȠ#'š7` i?UGu7+%}7ZGܴy"i[q 5 XU.ɞ"hU["Z9 7~lc^fv`ZJ Cش!IXI񰱡)tgseBkK'6*p|b# k;.J[-ؽ%a;Z5WK*Om~vpaK-Mr#XQHl%fK soD2*O0@cN3<r;ɲ}(Fv Pp\BAL(Xv]>es5ҭ.#mh3hne_+3"yuۇr>-W,LAJ3-BbDyM 7L ۴?QO؍j5}E;CFpV_uݒlx9MSqP1.姞.@Okd-H$#2N3z(Uǖ<Ĩ+, bR! u o4|nF qzozxC,y=J |i ը2a>$te!ޯر/D$+hDa ,cjPO]vWj;A^[iw[쵍iƧgsjՌfb hzjZkg(vOl@jO\Xof/; ޚªEn37k uY Ι!%@:9./rKK1#1`4n&וT q@DYU*'T)S#|%tT( }l'@p7@B͜ ݴM9/+"V.{RLb7KWu0EO|j2bE6~seY98:Wٵeoy~wMZQnځ>#xI@f`x'ΟJV[;=w3icҗzWZT\ dSdWpxdұN>'UyT'9Q;%*?etcʰ R(u?wx 9YscQsa髶d㡣w};%~'` ?zkK*O\=JRJk?AS+8H1#s fwO.%ŋ/5!IfWˮ6O<Ny>L-'[GBo+GJ'o?&Hn-QN6O* IΘ3QĆ)=h#GS%NZhںT2>pd(g;fYK<$2_O)ԃR0ct~u rmiޒ,05vb%oqK>gcOpc3IZ,QnN_ g67_wFȗcw ct"kq}ʯP Zw|w4/L@Gtce {F˘ F[ˑYw uz~cb Zs#e . 2vՅP&#wAOm y̞bFG>"I bch917K_%g37_أŽAEߥwA`sDx hҴv,;B;)9B'i\)v\#{qI2`(O8`]? a{)VɞmD0<5Ӆag`9$CJ, Qʇxѯnsf>p+Zaobfp͢9'P\ctG6Dڿ(\r%nwF)e6~1ȿIuِ84l@S ׳s.ÔZ;XNHY6I 36d{0#P.zҜ X~;?N^M|ij,h~#F6y:|1/C+%2k fI4,ITP3Bfa89-*_gHD.N>g4 J ]aE>($~Gݚy))5$ b*ߤ㡀KKZ˕*?J b{[!ܛ7< mq(ƍ 4i~N?, $c)R,)]/uuEp]l )V^'X˪0T:eSzXҠkYLW*+uT+{ {O~5!Wwu^# :>)ɬo1<+:v?2 La(dKuEW[jj8 ),3$cM<.<Z؋U.ν&ߏ{?]D?2q0*|вQt___鮃|$KM+xf8j\|~l׿3O~Z}qz|Y 8|=YueMr{S=KÜA]=ql#nȒhS\`d nr/Mav,l9MczGz  8F wVX휑Q\ŕ ; Q(ɰ 5`k~aʌFG.aUQ-<pel}Oۿ QОC7w+1hbh2-P>@i.,Ћ=)^\Y7M5"CC*j˷ ~AGT l$WN8I-¦P5 VP46p}:~I12^3nth6q쭰e"Z  2osgLE4P 0/(`nae?Fu0?uBbmh(S#Й'*IzeS'-$FIŰVۉ M H>P &#-BJLE";63 du눅.yQlqOC6WewG[؏%s⊧@'M$.:%PVb0ĎXS;0 ⾙:^ξ;t;=S8`#7RM6A Pb}_L|j+gvso96qP$U ,ﷅ2LlP{ƜuQK lHARՕ@r: ;`rf kCs:P^@m~ؑde 5JN-kg?irzdb@soҏP_ؼz2x"8Me%+Xut/t2Ap{Ԡ!qiYyQ+4qw3u*T{Q^ٸg&!M@ hk*sE7fw7N Y( jn tjF*H÷hS|A29x`#wDٲChK0:/)#+ mwI*Ţ^A(]nBGຂ+@:n#ʫD̋ѷ]+3? C-k)yOt]R jZYь jQ[\f%bjDB$;i~T l!D( r6S_%.>. GQh㠕*c5]U {s+Iȼ՞qӑ8Jj!T.TX7ɓ$9ڝm+~w?ir$`Np+(P56j1I@h*b3O..(Җ_8U4KS1*k&2" @B{AyJJNHJ&HAj*V.r $mDY,]D(vV+7 jtS8hRqдANՕ#$QX@2 зEc]v-( )!2Xږ|*q՜gU*}jPaҞ9ӲrwHА 1 +hm( Z#y22 Jhar\N'Xw8 Xi$>0zS]$/ z|$[DR+iXI'y ?Z3dϱm9àGcQ=%&1 9dN48>o.[6X/,,F͵{Q^#]5:rʬxO9xٙqzr𐟔xoVau;lZ8oR-s4D!0]Z#Z]= )/94]]9 yZFb/0]@>AOC[u' ˈbQػV $zXBaN 0UWݪφ!)_ 7ks֖zKEZ*ML\F;!ak}0b$('C*)="r>TXjKd@T004^M_F0\[QQ?R4@mڄjt7XKTI4nnڣ@7p'=LSSzFA/էR^6=pI+<ݶ-͙TTO8#TJ 9e;G;u:VO/zf nB?3r7X.XΨ;bXR#V臐-p1._ (ܢN@h2>k=G>ё,`XDiښڎ4A9{h++Ķ=+gl+]:rϖBF&18[Or'c3-!X`y5x!Jll^RKk62 AU?DzɚX]? _ .>2wDٗ(4AI1MM6ts `,MhRG FJH%AHӕ%KLftTuir'8ZԯW'͠Fb"NjXL5%ԁo=\vED n bfw48+>CŔe/6]ԈIߥ>-Q嬲ԿCY(x\$ګEA_yʰ88b0]_g7-!4n8qugsxy9!nmU(Q -%}IGԐXɀ!V[\ol(" *܏~ u/YtNZn $Da_M1pet&DRrFKWYoX[p:v,3@s$wѕv|AIQՁ}pkz0Y4_|9I"U0os(.G`*Z e;x^#  Y_ZRꉒ6N-2 jVQi"3Qa@t6Jy\Ta#' rxrsטe1?J$R0~4&pQ?{W&J+QCTgZCARٰ;5dӍ\1>1ۚ&^ */ '!0 ]~l{ TUB|Ue;]qA]yVFWi9𦪌4~Z{Ծ{ss*sMN66'T27}oԹV% Z,\.{:'%]yZ4)\nkZ Tfr_W/;]4Њ}]ŏ~#峛8uw P*(9ۊ/5=҃-ߕF&ô/壅+Te*\۽U9j?s~׾-fy_o>v0#~{Y>~]=h~qD0=G}gv3 P l#jx e?[Lz+{ R&}2 vH/p?ۼYL=|3cJ+x+mt)JՑtL8ҥX48Tk:7H]͛$*jwpG8{u1H1JL"O{%+1B%0k} af^v7z,RB1A%LwR'R!Ը)\1'Ls\3v`L!åBb2fNP;]`ag*;LRhDn - *m3Wʝ +w_%CG2܍-gݴsJ%|cdxղ^0L[bFbAhfz=¯h&"96Y8X X#8!CmʙwNu]qI5 caynzC;E4 i4!̀T3Alf۹d'A"St;Еa׀0WjdƟ{y`TaȁDǛ D*"fH-FF)Qx&ʀ?K_>Ia3롂"5\^"#1^z$_/ rYy*_yҭiJ;B&` P  &ھ 9W](p_^RO;1Ƃ(*x) VLbgސ^͚VSiߐ죬g7-7tSqi"*@=ҡtQߛR¸@7]Wġ%Ԏ}DeѼB\<.9YJT$& .U 'YX#F72OJꬋUJ9._Z+{.sQ.Ca. Q⑉ -B,mAt$7inhQ#0 ?W{a`.쏊‹8![h/. S TDM}1}AВܤSд4BUZ7w*ФȉE*r }a5utW]>*6M6Uouax\]K* ATOJ syP 'Yoexi,‡ B}_ Yb4{,ubG:QVKrDEzګ=SZVKwHbmǤkFy8#S Rt8X.hnϔ8Ϟȴ"x{/J)._g#$+_)KWK,sL'=uOC^қSt&FzؙGUڀXii~2&{u}%73^/fJDRwNbE]  RU,T'*ƩLe|E*WH e|3kXHB(4I N}ULgYf DS6gx4֥aX֣H5;'n>;n&(ӣP=)l(^!&)όilhIPi_tǘ!6inZU7)FA_& [h0(d8RǏd HM^ d=났g&FFyFWf#i|n -X}: f&NpÊņSM9-C[RrNwQبhQ8\5i`O9QrZ7M5D$Z ^gV6ΩZ6Ԃ$?k([=\f&#F`~U;~Wؑ>ssyF|6|rn7du+Jt`zu6}'x(쵖0[ّ 3>{W:9TTE [Xwĺ5 9-ǀ$E}PŻWF%9Qf mF)q;7&Z32}GRoHw9ˢ4?X^3JpwIzqȾFYܩj9S);)uT-X'dZGi$ ޛp2Y; @yb(u3NbB=O/1a]"meh}vv۝(5_K܌Ǘw΢|[(RwޛC_^7Wz O,%"OEj'WYx2؝ǻ07ܟo1 lG .9˧ׄXccX  ho2=a"I*ʅI.q"D<Pd8 )u%!$&UO#D5"{ =RdP&& )} iNˌ3%KI {~|j! 3buvcv0N{YɸFn8L^ h@W}Gӗ}%sIjrD9~}ܗ i-fh $Lu`&RU ~.)оz* g.Rj!dxEfaGUxI.w\J~D~LCQ%V) BE:,"Ladg,3P 70B/mAvmCR'A kgH`M/9s5ӓ)g0p'2P;Na< _s'=7p`/S&vNB c;k(.4Ӝ_#F_)XDXYr9ELדB':B_S}GVV&vC)WukAT/Jo{ԡL SkeB: $.5pS`6r@71 H!si'[;!ꂩ.}z1M4ͅ'{Tkq0bk|r|ku9fd0f,$OֿHӶ+fḃUyV|]W {?5yb7ȥttQuGے.Э]K@IL)ee#X͝#^RjǪdRVGEK?,qHlmm@5T`gjWw,u%Yk}MUMA4,"}eٖEKfҒ ͆'V!BXa|x'j09ҍM~kD#mb':^,Nbڒa͊ '5JiS]mU⋢'#2Z-i4pדw~cO֢$iWMuBj΢HfQ! @eq^+9ea3CSnMnhgJYDz8MlnxԠ.,bf6=ne3]W2Of '#ʍq0_ KEMZsJ-Ķ\~68db cG^v7-* jf𕈓HgtKKP@-KΧkd ͷ{"a[x[ j`wզkuH47Kʖb.*MɤD08U,-̌ 遆m|geXƎ?|cvҒ  ذxPt0f*wup2u߁Y~ش+y`p?I`ŸN7;ņפ kQդN+Pq:vu NMp7!\6+z J^T&#KZ&Ru1jISD IH) }iPȜn! &=#k{:2=rF _"$l%ZUeLI$6F)Bw؃/dV3l^S) }q͐>2лỊ-=!U':o1G.f*SnO_ZݿcbӶY!rݩ3(~ϰ"+4+L JeXU2I@9'3TG-1E{zɂ=^A%/Py*}AW2sN5 1UMlP*6+@hPW?:i&l@uH˛x@26Bsl Ϸ@9T^gb7~!e˭hjDL|[wtWimA4y^9ZRtv-VI,TӆH6ѧ&sU%BKJD;R'ja┸Ƹ6eP!P<ɚgRWb +%Q?/oAՋ)Nru>}^X/ oe K [En0iRx%RdFcNt([N $nVJ|iSX= P0ި䋗?N,n<.l# =A~" }x8*300w#,4ssUOSBzKڷ>:\z,xjRE [̺BD]V6 o= @\l}gK/1Xc=3'9:nye'@([wYl-p9ؼOWt+V&#;'>|?ynp;^}@o]tT]f@XX6S:5T)Wgy?߾nv]7ov~v~>lqmL~ÿ%>}׶-M0T]w߃0,7;nNJcT.[]tw+_֨o_WmB#ɢh=fG1f3wؐ?w!ÇW/wY|۶mնm۶m۶m^mvm8{v&3g&'{oST]]"p^WOGYُɴFI9 `'i55.IgirB;OYf 5rq3AMqi])޹]}< U:/=H-]"E YUOdu" rY<u: ,'/v9,8߿~P]%W Tw1#C02t0kۀO8"/Ƅim^x9ɭ= #)1KHrƒ-I ߡj.ڃO*:-ӡq4kA<1֪Ym$bO}fcc`49g*įz#ksOɌI3 W NN!G40&P]-Wh[\~/߇%zͲigP,t޺~'Fm"ڕH򻞂Ȭ<]r3s+ҳm*j/0DW'S;ZKn2h\zgìBt >4'J=4GBO>f{,zA]BvP*Ur+V~ꉣD4Ifڽ#<8tsF)F$P6r)Usר"ނp_>e2z%l}Lʰ{2/ \m{?h:QTi=&@ƥ$+?VEdujB-{}9(z̉Pʔ"}?:JSdGI x5+_vsD8jCa^d2e}/ w;֮ 8[OQI#DiYc4 h<ɿM]Hw_k *#(}>R`^xo[䯭mTEtBe9zUw}sP UIataNIb0 i]ɚ;>_c69x;P)B{|*,tmچ֡&S-8Wu0Dk@BtÈ*Ux"`HdM-kNj,K*y͝Ʀw(ӲbC^?ykӇ8J #/~ 4{92d'Y4e6e}Cmq̹ٽ6ǩM辮j! S=X"R02qۄOt]@{ah/fΚ1eUKg^^;KmQNK_nЁ 'i6$0\ 3}$k@)31qoI:ĤkJIk+H(;(@xmiaӏP=ԋ U_$zEZ6j̺:nh㫻VPm`<&ox%=.eZ}_{ /JW'kn<c=L_ûg&3,o(krO&\> xF0;y..<1F2^ZܤsUmٗBP{|D7#fԐ_D'VJUni'sa [fu +]:h :} m2N=/+x?n\' :Ol'u(cj)jU86cī>D]P5](.?;m&d3_g(#;dqldwPjӰ$RG4hsDMj|.\R*&fX?ђeɔ26ǶՇY's2 !,Q%k୊n,{{Rj^-BV{Eʢ(U;!]0V%y9)ƽ9B;1Gѽ"K*~+#!(H(躦 J?R(pnĪִN]j 7L&QP;p{IQ)MZ3AG2%"5kt4鯭@y+X1)+э #qT&2et͓.!t.p*]SrHE3\۔v je b ̧ȁsr%nT/H/܋?k+*PEՒ: a7j6e%%<ԍ] AAiyfֽi\ẢEY!KHSJ*b~QMwLx'[%B֣rm)I$6ig(X2iJZˡ/ O߮SKB'Ŷ?аX}8{y4cd¤a{ $(K׾`zڇ 4嚎9ؕJX_}D`V'qIm}Ut\^lЖZ/ZfQ\m9NXQO-8`cG=8퉵VNTFJ-H1k1`)2ݤ8γ0dp2D %X=wQWheEB,%"Q@sƚ0>ÝE|{7"*RR8 RaИvZY8)|: HpK PxaL]$Lp7;j ?:zR Aʚ E /!d1er~tGHȏKLc_~VW*bIK ܷ4Xb]H:CR6 L `7Z:A`!>RE>0Ѩ)3 o+o^ ?sLfҳ<˾ D Ggfا"o$/=7QorLUmv<lɻ :YH>d}0wkddg&n\t!$>AVa.GFJ HE#:FQh2X^ Ϧ7MZBQ\z+VOV3^H߰J6tI %Nrm?5&WeXJp% K qb#H)+Fs xL$aRin2)gYM_9զZOjZ+umk'^ @i= 33Y!Qϴ $s@}d 8e#`7 H!ZM䂔{"Ս7~u&@RWzYX!m:0rj<ƥ N'2}s-^9fW*v*G&dYlYu!ţ]ƆH(4XǢH+?NqFǒjbmV l؛8Np:OTan+FG')Tv:BY 8nUc PGjq$=Uo e$ mlwiU{dCIbs:ݿ㖭e;5Zx jC8<=5$'oD7h'g4ؤUrKLuE.Jdv!_SԨCZE5m'0*)ͻz E5u󌚾mz6ynUҕ^d5yPJ9ZX@I h ;q*^gﶔZnnDdpՃO%ut:gI U񌟉)0 ;_]gj{x˒8XL2i¸pBx6IP/kap!Y*xxn7iϞ=ʧLbuYT:<<v Əx7]j \ F~&>nFXul0э(#%.T̟pvn˂Xr6\cZ¶Z &݂ž$nO5&5Ǔ3Nk~ =zw ?Y6!^mE Xт{nO EЂ%*x{e='AZ3>ԶrkkJ;آCqf<kuv4,_}жV,rh3zPFYi-T"NO-d5x"Kܯ ,P[V4VHt,Xv+9Ѕr7Wp+GMbӡj2 H )M׮UmGwwFfذKw&mm+',ev] |{W2bR}T[Mo42dmx o2v=kjzEp=3nIoؙl¾Zy5?Tq}釙z&]z}@5F1SY!%3ˮL='ۂ9rA(7,R8+T< DIY GXӯެ~vOO S-LFd*;4Q`P>=ݨ]E]M6hMf;=d%gn켭ކ8O=BYoIx6{`?y6Gvj" -jzM}0׾' /=37D)$4˿nZ_͘]o.FzoZ3'0dܯX4+[1c[lJSƩ%Oe:EBB8v 6'6uhM kc_Ap/ BOJG p |R Rܮg0wFX,>Fb¡xA/Sٛ_Yۦ WbUyABЉCQ?'`a04$wtJix.ckYTva w'ҝ9=MID&V92ygʀ]Fe,H,Ҍ`d&;V]]OH+9NUųf+R K9_}\J@Kd0jBܷrDxS}+j2ɇB{]/쌅c;դE/%n% r9dUtCޑ1!/9N:EN//;cΊ~iUs_j@Ϋ6;cs1Sc]ZN>Anx0z9‘8t4i $I2ލYDu*dOje&%̬9;8#%Vvf.vFML-5]rcEܜ̜S$ I`lkfha[]\)W#[+KY2UL +7+˿K0PBik3Ks`Nvn.xӽaeq8Vx[3˯(>6;/:=[ok`$Xci|ll eh4 Ûťŕ$ |/> uP0F_ a㛙Ž<'7M+# '8qP03 MdeczbpXŒGJ:o =`cgt\ZW7hc..xHC 94?έDzuɏG?=&ic$dcP B͕-"ݥ3YC( kSsm"Ƀ ɬɛYolcoigdSlxbzGThfjJaKJJI t%kCy0cA'vHz}"~U%8(9p[SM B#c8`$@'$6.,$&*0+.-Zlj|] @/ODz8C|0΅s, ԈTkg렗00q(qo~ SQ%8zn8*HA)ZփO|6R OȠݡ,!zdm,*5S4"li[%GF/йY_>UE2"*|gEnQs\-\H@Qc@)Z8 1͎XGC.`Ꭹ՘vDqu^b47бQNW7))2&,&#h^^0z(Z&^Ύk+F6hvd;4̥zQBZj*)\FQr nl\ϑP*Č[&@-CiYeNac1҆}d#=6 [B(B']b0R<4u:ͬc w$ؒh Cl8:RCk10Í%uSR.[qREeFzOoҜ"zJLTT05Brmf`Eii؉iy\+mE$%٪[VBUAC63ԣLOW:q0A:^-15a`GK-z\d@$26@{/0;Q =B0^۟4AQ.K7Rz\ONH_A2Lۓ)N&{K h= UhtViﵕbF4\n>Ɗe+[N%fB?i Uo51\+Si`|X,~71!&eݭⰝNBEҍE|7gEo_2c\)1&<,78ҽ9_sw n$f䃡[ _CFpOHvKj'-2Q\k3(=cz%x (t ] *OYhIfx#gh|!!::PJygl{ …Wѥb2dAT| |^qP@ uC&kPj'c`>`6b~ĐFm2 gRU.7]& }E_,>4bP^$*L9vѧ[)Ms@mEDɜIF5^XfgAc\9I8Q(.Cu& PdhZ^ڿxw#H愵_ҩmxuRBn IU30Bt|fo%p$ Nv1K2`1~BQ*fmnPlڰ-❙΍#I|NPʷB Y$#q)5h+G Mc2YSl 4'U>=1 $%Dtai) yv2FZB1䍇q1?o.D M&m{<~ps)ܷ)((|UXox v48{RC9Qʈ&%Q~$S?>Q{zq'}Kң) '"17 "#W=FӜ³J];v V.I=9鑮m'p~uaB8;ҎQ~@0rDȢr,[Q!d9r| ;/Oө`f9iI7 wՄmQ}֡/#pqV-v2Ic\ɜA^`pˮFYZrV4V MJ!`YL꽾Z5V9<{u9!H/dvΗz/xZrANFxnY.-xg# F |uDZW)Rmǽm ˼4A}?%Cԫn,c(;[}Q?WҊ~Yژ{S.\KEqS7 [0+=.IZstxv蟋֓bn[bd+&%NmIA2HxNΫDL`/|[/u`t0,qlF 9m,.;²Ñlu Ǔl_%9.AYam jEIB%g|4ev^Ǘ7cUWO6T0ʯ, ,^TgO\Atw4=U?qp7C!f2\?r8<섷wذ#[ 1=6[r |LmQV@Vs\GlϷKa 9[bVBF%j5򲹤 ` =>lĵ?2(dk ;PEZX{+2*aw0IH}Ddl42D2F>A\BnƾPc$6> c4g}a_bG}tn<ϓȉ "RWND0Url餶/k~`JC^ux|s\뚭n4k]to,qC/tG/OL3!\ìٙց5SBC[A֘: Eᨦ;0@mz.H*Գc]iew Kp(pir)kPjl AW;Ť"_I4o p`Nqh@TOFޣ#Cle7i '{v’z:c1Ms +td,@Ek&d*|Dҭy$@5؏jr7r+Ҝ4BA/;N]m\r|\M/ LJ8'X}OagOL>k2 i#.0\ u]G4qv@|3/OhͶP%v^]tRlTUgTJd݊AIkQhI!'S5pWU;Re9-vd'Y 8~b_S?x6|6c/u8Cu?dR{J!z0$084k]c2WM>{jLzrӔ_ daoHR)~tVZnVwʘFPð&ȵ~I2hj"9aN֜jz5?ZaYcdvǥHKY{Vy(CP#yZŁ*v_SJή$Y%:9Mk|^t V$(wH(W9aj+WtIҨoD&JcnȰ+/jUDϤM"k^_ @r>Jb/ ]xƔsR4VBYBy\O,UmtXr&X SU+_>;A@ɡnMYVMk(xDPQ,q?D` ?[5Ч6Xw$@*aǥ4!/jr-WalY'?,U@ŀ[ uD [U;#7B]֪-\خӃi.BsHO1h8Os!ze?-AבY|pSX7ZϨ=~siCCչ/B䕃Kpl[X;hq71WmFk@%Տ]e" idmY7wC36pkFݨ]Cgj +x|)9B̮~ڎJ$ \2uʻR-Xlцb Fh[Ceu[p1'`~g;QԋG{^uj=atLd^OeDs:Wڈ5't 3s/Eq|ӅC' ĕW7}c4v䃂KLFM z C5J8π&T|K<~oSt h%ad@̏욑|jُwUCjutZ%qĄCz]]=OWšأ N[9vgqz M]:(wk+~LtZ+\*/|_S"?p=f7ↀTAW4 RCv@GkZnZe `/}?'iz  @ZE\2aCBYv*.Ƅ!x6<k9WW hJ m~DN)H,T E|2r 3`Ƕ?7bNUy rUfH5j|pt>.1_ ^ zJ^39n#g)Gj k-*P dR6Q2p L f:"iTI.8"=U4JtAk |/" TjI`Y${| *Y,`E>t4хJ(\yi(#G\yIW)o%{gEZxjTt.3aԌEG 3jL:a>r8 Ş~ HgAbGŸ"-eJ8OԩKOM-E7tokR)a5Uk( k|oͻ}(mV)mkHR2(QTHi~ zplmC=N3FK% bK N [7"e@.N ^!M%QE JȉayL+& DQ{dOJ[뤁p2]mxܴ=}ֳIZbNwYݡ=ڡ&Zt4ZLv}2Ɲ֟iݯ݉xi[[;M} ˾ypvZmViR .y4 Y̮ۭn*bupn;\R V$-< \r7`tpWtHK~: 8$lDJ蘤q oz *#ܧi1oyTW[R>ƭǿ&X2Q7Y]+ߩXh!4W\&2,wV"10%Ш|zvryʂ0"h$UJ_?wܜKrc#OqrO?S4e7dBlUfUY}^5u;}cs Ja:bW܃ؠl .]KP جLJo!CHXݙKk|Ug ,dX0Vwdc|zwde جak 1m83 ~؂kC4ruCCO0A~5ks-Vrt}5c]*j'csbYǐbQ] ̐T}\5P_DL{yT`ӣc"a^zA)"톦ئDaM`9yFMkNك@ I3`N^YaE@WRPD`p$HYXxk 2ㄹι ?#95#̢_C< h[>xr=܏5gx4\<THF2-|?l*4\#h4q[)_d2TN-$7+ez_òԷaf !AmAZʼSkF`v& p+K^h22('P4F%Ze9|2)fX`;I=bjgb?ssANJ+u1YG6ۓ 6XX ߈ <.q|a2_! c1|܅Bڅh$\UqʂSp?nQEߘ N]J8"=?\yxoIdf6t%Jf5̊Jg_~-V;r"hLUuSFJ :_݂d9rUI4C&[3=~˶p0~1TvBN,A-.d1H%ER)bǡl֕-¢&T|t/h%̽cyrQ'-TQ j XnC|^^͝ dh`e6 hI%4BadaCinc̈AЛe%KbG?9M]2_^˫יִP25dE^BHhՐF±%=uЍ?@d*n*59] {[w3/״Q)-/5c/dPBvsD^ڥB*UX'OlbN1!!bCꐢCt&rN,Dff'\ OD=P.Vlhe~++#>Qm4R7c%VvE8N󈟒+Y 3XFp7PM;^'+.,Q⇟J7n_[[zm1"Ot8~Q"y]l%3CxvgpHOw0]= ~ϑ][:(L?j;̮R^rS:Mp4/x>Ď#Cˇv֨X?U?C*JcAw?! Qc*'/xu?TINv|*sPd֗.pWVIz!9ǼXMJl_G*0#Aҋ6!XrvhYZoMw~rG=A$nל=Tqt!v>|S]縜hL;ydn8ՙ!D3@!2p&o'LS䈂TKu` )vc\y[zװc|r^9HX,;k$?ӅvR"ĿRV3L:cMXj;%W/%T5|ڔDXP'"{ 9sqU)IV.[P8K\ k҈IQp-8:[{M62 e: : tPƏn)U$hhNϼ7MVn%#YQKc[%f0mx ʜҬmQ`T W}~0xVZ!r!R1َ{;1%zYy@NUZT 3NU6W#[u5悷$tz.RyEsQl Rm3,;Js'eo"B?FjЋJWc}z-qiAZΓIJ_# 4)[WGEXpGyi ^*]@VhnfaA>~r{t8CKhLQhF>6cc.DWdqǐxClBmCY+_46UKJ4t;QNa߽D + mvc- ٻ7pH@3] dʋzhbЍ2>$`|,־_^u{H咜pG7ܡx5]i'9qe Kl͖s^n yt@ݹ29ˉHe#1ZG.[cXCL@nPkUJ# spZ;G}#߇[a~Q/Ol?ŅttT 3B92ޭוͯ4؞¬/8OdbCi;7%@þsX5Z˙Eu g)*|*:ʞ lEYV8 OKU-;'`k3-c>X,Nqۅ$qI65ShgI;@^} y;0ƕzAۄ-֏$[FI$/RS e1W RI {[D\3L3%J]_w`ŸΠ®W:}+}WGRAho=+5{g1Bź0r% eB`y(wKz^L0B=Q#wDLua=}imC A+ u0PPzA @,sXRL =Bޠ.:PҘ" :GYǣ eSm]@2)8>9Bbqw;2ᯰ6.7_Dž`J; Ke KD*Qyڻ6pWzo1!rsџ}D#xпRO:l[}cjr`E1˞a{]^ ^PO?$tv ])PW'~{ 뗽Ict`ʕa1hX lXu:ezJ&?H >ҧo-01V#a:F eLTRmhw]Ev.h@V@oPTl]4D#p+z-Lb`i"vrO6F9ZZd.v ]o?c!Fۺ\_绕LeM[/ 5;c6׈%%/]=M =l&lXfkYvUڥrYNp{?FCwv4ץ[((p.󂫞C7-!&yZ[̢9kd) yTfTX%$W09z.Z0ڍY׽Jѧ{;̌C̵1Q3_='!),+B{}ڧӦSp%-T(ۼ@0-erM? 0sj"q a >v=\! (5;iqq{ÝvK/`ÕBrqyHr݀b{H$j+֪mqXc-[z`E NCZoS`ARc" SMQ:\);mpf;E<4h2=,|.r631{E-0ޱ(TځH;CnVy[j|?aWVF_uRZ(^'*Z_F[Ab֓n^@4`&;V҂ {#,Tl~jĩ6zM2`=F0m5ҭzuKK,?l[G}aW3 E,eID}}a8ҩ:PDoAX8ܛB$%8%{u9HgH |jIյ(?_XW?&)]" ftvg^~x?R;ɛjF#(eRkv`CƣnBfL/L~|gB>0ʀhv;c(?@Ǜ;b% _jC8t+;)D@g wJ1k.;9evSy?)˺X!xlskM+@ /v's;oPq%T^dxKQ?f@i^L9oCz]\!|3Z*SV4c.}m?M?7Cvg*ye?Nd Eq -U@n-} y3vXW覱$9IZ@u* "B# CE눣o_i{q2-WMYSuHO1C1!f-/}W ~tC ^%:۫좀(ʧKqK[dQ}9/4$ jԟN6ZD#R?h\+OĶ(jN.鋧$k !r0&\x#f0m;Q鈖CefT!}oVg1!%VGF}L\@ݗ%P~}Ⰳ,kXp#;95lYNM%=6XJ*yG v@_}\N>fC(𴛖z8?K>f]vÀ}@ThN n:2-?85NIȻ"NsऑaN[`; "_9v -)y'ĥa;agLD&hF{T39|V-^Acȟ0ٕR7(cktCDTu2chQa rΊ}m[}[)pN 5״!\ 'q,ûgF0o)S7`V/ZYm( $n.ΎkkGȃ|e _O _#_/)8^p* mǪHC VNq.`} Nk*RVnpssr;~ BtT꩘-z\ U}.`IO/>>}hGA'p,|)GT&KXPX`9Rwj :L fjb)Q&/nt5or o*2,?7{ lִ"Nխϗ*f=G3_7QuKxB!4}tkY ȩúzkKx9zUXLZc[`Xvq!7ʉnm|&0_c2~`nHFHM`J3R]±q}ixvxܱT%g6"slY$]fx(oJT# ( Gͥ[qxݢ s֞}.)/Swǎåj;:xx,ᢁ2<L0-ށ9徝 Trmiaa{بᄖtPӃO ZsQ:Zծ 9@h[lM/,cQP.O굥h.>zD(d!]$ŽZU핐B[',MB$4 䳼Cu 6ufh}\/!6SU?t>*cLucR?_+3[G#&1c`ޠuIA 38~6O-w*> YA*)9Se:!CDe_ISIJضл ~3ǥFtZ\#T)pxDx:.VzmE?D5Aۍ%^2x{Kp5\ԃwv9K}:4>sƾ{9|Fl59÷~i)k1U5l/h ^sT(Tr>Lk$(=5U"Y7wrao6yfɃDqPnm~9:[M#0FY+I^vZc G x6kfCrq_ڏ.:|V־^໗Yx5Itםz O*|?KGY=L*c^-R[7%`LqUI H ɴRU72c 'PI'(O3\P x,_NR +5 1aB똸n UۀkXHK`ٺA4qi- ͣCCq@ '5S]w=>K{+)*8f b#gĭٓg5ո(JgC$ uv!\vLPBҧg#JKX@d&]n\S&c/Zu ?#ypM΃gYӻP6ʅMUk^kd`e%>+ <.Zܬũ9u}>Twi藺JIW5G{ڦ7e@57IbDxsY0u y=,kϚ29+^ @ '5g$c$:JL2Ԋ Z[K cϱLLE,'ѓBϤ{搎M)@p^x@ MXʉb"3x G!]Ps-ꐉY>ۦ>ƒ^!;Lxe'j/*؈]ȶ[)shxl0p;(?'"_b$g[LQ޳2os'—nȃNP@U`\y?WBSJ[r"ad2u"a5j.Qrt6PiXQJ"# 3 Nٹcn(klY2\'qA 9G$osknFKvK|p}HaǠ5QY!k cĺ K|"/ϞFz\/Jپ7zzn[}鼼 75 < ڃ(C'$Oc#,qC LM6(~_<:#v * JjJ `{<QHc{A?Ο#xGKL>e4BA l zEGz*eO4p\oJ4\2_{5M& [81㧹nC2ٻAa(d`:kg[U&l/rDV/OV&-I=~z<ބP~;@9 pz|cJcTvHď=>\Wzc}"Aܕ<:6pƪK^!m6貘V .UH/WbS-C.xc}j`3U󹏲tFRߕ΀il,!wC.-D٨oKNm[/>6"0lmz!r.$|a #?AMZ#Zt;:l9TXI l'Ş&<1Ca7 RPj%1 f{g6 U!` f?$#&A LDuV;]_[iG{?nI%#[!uU=<\B-A 1jS25gs޹ۊ~JhZEn<+JhB wy$ƃS`6z)b/Gm^լAbC\zaCY=#2Ǻ}(Zž?maF·+t'lyk|,ʅ&ַ*΃@B'?&p!#X! ץPt iG*]OkeX K;IܽKETwkNc}N%V.b\5e\ԑ5ד?iWR]y<Aѽ-$O (Jɚ_+ їq3}GRAO'R\3NԽ9<iՀ3!ɋ61E;ܱD&̑qҙ~@e ^V}v ֑J&i e\N7Ty"u) %4+et"9x`tz@OۉQ{Dl1Gjt혰рv 2mT9Pa3ݢ9D̶6ҹQܒu\k@t>UfAaeA(M^?K7\1۟혜tX(bʭ;t_Edk#+`!9M֡['}􍲕]ͩCy$cpD!݀ue0>KlJY5⅘*NeΖh6eԽchpڹXi緹(#F2+O Pz8]PQV(^ƣZsx&'KUtQ wi&\SwW{is3\1/w~Eyf=1Lz}9p Is]l8bb -+`.;<>/CE*y8>V! DzGZz> j.Rs6yʃȜsUY{)9L $]֨m@zڇun [9h { u(=<']`22disBQ֗Lp ;}5c@qE:E^!Bs@NiA3*j`h;6VBc߆N4oS0O/S0#:5z Oe =^<_'g~ņ(ayt4\'4LuRi^dk;́/Ա$\A6FrʄqX(*lJ|՚m]~/Ӓy _QxI1 Mp&e҃-lu*ŷLw&_G␗~"QHۛ1^fllS㞘`Ҷٌ/jl4nUgC3 .U_L@j¹Z٘sɞMsn Fd5QnAc緉6~1f^¯@:yqo:8sD\wMA| ̌LAKh`h 0kv*pa~PVVI<#Wc}b7 /l /#1b;DbdD׾m.9H{Fmq iYL^`Rin<C bߌƉx#C= }kjH*Pgp21X= هQ0/:HϢk-QR*P,o/ BJjX0_9鍋r  {L?඗gAnڦT:VH vcvPPOlDŻq_Eז3xݍ&0YSPpE2)gc!8E#qE]Hf6|=uDH=bƀe͂,|AJl09Xi*a;Om 6Lxˈ[jBV~h{@5iDqm=\M3xZ95C^`wؗ-p1nrAN0_n!>x4Yih I}*MO~`uB@Ls9*]]~* Puz 5@ҞKc#R&&r`/dE `v4QPSH=֩@R@XɥQ|>ҹQXz  =~>V1K|$ &L.&n\!)Jl69&Z}f:yXy3XD[У%w߬7UD<|oO(|S kiXhB̴:?oUD >')d\Ä;%k$&)ԯIX$qx3xv2M3Iv^l-+ Cf/5@c[1y&fd»``4Pw9[^#po&CοfE{"No ı±'AbpȪ3&*9|=k.2Q$!}9xC^&Feg:upRx:#kX"<"Ţ!kjh)\m:5]V!n' _>BZ}/Zn2‰J8誸\.51WM @ֶOwxI8M.FM,3g:SGUcNi ֞ ƍ&m_^//H$HD4~jicAYM{g;1W@zMUG"@H#]}6 hHNa'j/#kmkBc=vQp뱡Y0Rq gJ(g!.FT0=<̹spom,=aONN,lI2=0bظc y7od?鉣mqzngL*6E_0]\ 4&UA%fA̲a7]ݎ#u|<p|4A" mu22[:l$Fb=);ޫ BKb <Cز@?m'W ?fݍ'rAsCE_nI]Co2L:{ ݠ55v/ TPbq>aSӔCO鼥C6(xD|NyfX]F_nT0 7h:C(ҏ*%PPnsLXF'k$<)kDJuŗW;/pc,U}ι}كbcwȑT>ikX-ocr"DŬeһZtnDȺK Q7Os#CE8b͘#G;a,Nj''+qw1TY ?޸<8lޒ<|zx 8=k-c_SU5M\t斔.fB-_R^@Ĥƽ^Q@uySžT3 VN^dn7 .[nQ4@I7vL((/Ѯ~:Jnך$5l3CC-Cn k?_};~n03k1 b~C- M=> JtSJ8`ܕIZݎS,OO|v3ÅV 59C6JYĹ٤_Q`l+Q3U(,Q*{9gnrmJP+ eZVgH ajRhMSsȵh[wr3R&\@(hF>XHKfƮyo=j0$$K7^}xGpi&+Ȣr_9#$'T~ =׮|,OXTn/BGg,Li9ϪHa F[>Ί+쇮}?ƗXK^ԧaӚ*wJy8 ղ, w:p(jI3Fg'"?Bg]ƥ"b{&." 11b- + {,.ԶUcCCt6݋^33#_#>Z2>KpA\*(<0\NQ#Mi[e¬G6nF&ZJGD:Y^{G/SwO9.r6аR]lPP "]%CEX{2,kʹgu$Uf}sAtXTc ]5(\.D%Rr5h뮄J}sbÒWO6i/c]L >06#//=VSJH![yw?Q ܋clFG/ѽG2PYi4mbJj< i<('VRљ~TI*NOӐ*)+_b$cѤ1/"@I6\a;VXȜ1K[(_Y>M g A& LA۪F w1+FxXF;Nnpa;irTDByE($L"(2S3*7]6K)s.:i݃.mvjR~/BUG*Ou7*MOSpNl.8j!3g=k2jTjx2U]%Dp X&7.yBAnإd`:iʤKxN ڱ-~p|h^ӱ!\ΎtYfI`:["R|/.c>@bu๎a?s"=~pgCu~"ې>%4! aXUgB^(mgr5ޡ]ݴ4WZ^Xj@'Pdz]03yNä70 (>ZÂZ{cCA;v"{(ƻN5I+pfm=7֫K}:Cj5poZY+nRX㺞J>^%Ah8mXkN|H̙BK&{nciea]; t+be&᳑_H<ڼOM`F[vE&+}?®|ȬQRq`nv1QَѮ.7H2Jak霕ġiqk| a8&w&V/eN8-Px%d3GTZʸuׇB@QV@8:4:EcP OV8%eM, j` 9G;T岵F`֓mlgf|M\@x lrpU{bX(ܭq..?<7K x7 GXbI:V,s =t {M>@FV$'OHZ+~Ǣ\<LfggcNŽq Z>򦸖ƑPqo- ;TL~)S.V+2J)?` j,5vۍ }Sn S솪<Ū~J#}v+7ЍUhZߐ Ώ8CS jqƊ}>_ɇ0mmZƎlCO:ʜR3c}ݜ7riMa;o8PI;vW~#^k.DPx-UXADPŐ§fh]8س$۫A܆Akp WYEIr6:;!a~}bGV>z1j _ L_K!1-WFJE[ubVs2GTlPR ,jc:% SdX᥄Z>lVq1<-,59.tE1MV˵eD㉁KwǶEDjqv]"O`/Sgu:L/f_ β+ va;0ӨQr6H/0I0,oΖ~*HNc1"+: Y6&XJEe.H[K0dlRDMeC(tO5c?pĬU-{ˠA8[A[;U Z9]B\tܛjv?*?˾rOSkW5 eyχ<6$A&U-f$B* 'M75v"٧$ Ն\_*< GSUjžƷk#",RWy<߂ "+Mؒ.ppx( yƝ((Rf{(4&4 s\/t}r^M#oO8kMZezug7I j@SkIjTRќ;NQ}oUkoG2?r8# )ۂtp. Yg vG~-I2{Wi@ j"ɭ$ 8r.dA4ܘ:Y̋DB_lT_g31h}~(.[h *%rZJr [&m>wMMg P9K-GQ|J ׵3%fYdv5y G< dnnJjdAK|G7n >M[dW>XwᆗB] AfWDRd+ɏpX9ȝ%PyU y#ϣH㊖(]JeD IPS{tj|n#H Aý!-NC%dbﰸ7 w%”W@tk_u&Ce1Z>F%-Năa7Kj&D!c_V񟤮ZABUYݷR6|)g}Z;OD߿K}s1%r!?0%״2ZUmf<ĀG/ndaxx} Z `0 Bo0d BBXсX['U:+H(<YOM0R զ:2M"l:?,}Dn6X!\үY5cݣ2YwUF8KL9Z*ux8~Rwx|%^6.4ҋ%^е[iKXktbÙ2W(y>8ĻoxH‰o s姢cT&tsO FfE,R/K# R!qy"=*x}}\RQgAF.`-wXr/Hm, `ks:?op/cw]%mRivh0U|<[_u(,v>Zt%8|+!N5ciO!e 5Kẕ6\6,.t)=/DSpSӥJG @McB^'R ب 0Vzxn$U]aAnt<^LgM9^c,M$(\ 6Ilx{l*Xdenqy GRD-Q3g~xX܇B|C9_kfN|[]́1N8Ğ: ~IcErz-v=4D`< ˆhTT:V_nj[Ek !U8OwLШ~.Q!(D5Ģ4^ |-k:lT-M6mMQyy~_{xUaãzٿb)B-d!tli k|XyP{o /\nQbjfE0ClY2tiq{`=Xd8ݮR8?*E 0ٰm h}§z^,-?o6dUu8ج[EjAu(FK!GILn1n|}v9ˡ/wVVR]_|{p)2EY%mW #vx(f ܻ+VVKU5uEK)pyxט5 [Y(vD@qcZ) aܯ$]UX*C/̿{^Z:U9e}]6Dd_GKMIpE0L~9?E{)=@`b@׵nSw>yЈďr?>:g^X ` + 昂V:_ nh"ĽT_`-r]h=XGM+,13O4o1zO Z-JψQM<גk)Jp#[-P#7<{I-9t vV><42X^hØɴ]$^PÆp\%=Uak&7Z/B߸Ydm4Pƈ;!^n6SFjitڬ4ژ)ȭ{rm˻w!_g+HjY`|FgrMx3*Rxĸwq`[A*\op(P4v 氣Ĩ[&r\sq,\?HY$*Ծ`+E*}PaJ FVDG# w(#m@8qSL^.wlʓ-)Z7vac: H4o*NZ,}VgvUHzTFlC+B]vMh{O o^J\TqW:3*/8oUPGT663lU/M%A g+&r"陁CbM0K87U1mKYt5U<&eI{NhZJ 0!Ps䧬J#Tj1cǤTcg@Bg@娏vDĜJRWN/E;uEY7z2]~) ȡ-`.3%)¯?^yrZyRL>n|@3*b[nX G =Yοp)gOP}1s!=ҡo6H- E0]*_maJ`qT|W8Mfo {ņG}ltsOп cLyskS,0._ /oXVlPk:q&X7ykmզ!;#}E3@_2 Q2#iQ# |D{n源lҭT\߶hPgݩ͊=b~ ؛K-88C[ "\ /TҼڪON+5,cr Z\v<`Zq9Yg3B9ZE?>2BYs3b0o#;J|R?In3R/p'$#e.N!ZjusSh4y>TCpV7#_Qs"TJwzu *Iٯ=]ʊ\'lU&I$7(s8nÑ=.#XU{/5;A2b(C2JWyA.S'`a RJ[/9zc E<_ۭOYݞ\e~rUݹ͢(9޴OX .k&_I" -ԁLp\`ce>;\B8H}f& Or$W(_oHI \[POo%-5,ݼi\ ";r:]qKӾOu6qgPZ1Q1t V}.-t8Dwm_J$:LS{ FuFd }.RTN#)MiFMЍ~VM.ػa;~Mg{ViƷN+_2[$b∷k۩Dy 'jn]}Ӻ<ݞ*_H_'6 t897Te<=/kdv]<5DAmt hZ{aAa}%HQ."MVwAC7K<|!;4;x>p K(>L?P.&ԿQ* wCO S ¼u'ϤB mjcyI㖊c<7-*R.И=Ȩ^ex  o9ssӴlF \jii"%>[?۾GGQM<k~!Oٱ<ѥY*ʂ:oI>T|$7%9"VgLIsru8<Bc08Yiæ9S7IJĊH嚮 މ(R*Ύ /oIkb> ۱$vz[Gn]+fyͱqώl[D?w/e[?飙 JF{6 /FNf?Il G,bqbo bql[ADqq8فNN' | bps `7?p?(N8Yڽ9Xl+;;o8ŀ ݏwk7)~27_+/[,\e{]Pp#F8=}}=ol?~61V'_OVT;w;{/?+_^XW;c,,OlIϻe _EE.nÿ;n?>% {A a? 0tqk?'_lvNVۿxJ~p#K'O5B4+x]`uk[Icy^iv=D2~(mב60/0_ 5?_ Ƥ@GX1 @AEV%%v"'af~0p2GBhߗb엉)_ `;r gXSq}_QM5507PG=0+Doi<ϵٯU7ࣛXDZ2`̦_iGVޒPp/Iՙ'_Hj~Ωv/e}xxC`oyy/f]",k.@#1XAk4KC&ВestoAV,n›Rrl!=3.tSV[ɣݒo[aDɉխ/$=bk;7ț`?Û'ɑ.kt9յAdFu rrL$t09oUUl`M/VLMۏ}:|_V֭ 3>7 pg$]HƉHo PAJ`&4NǑ5[c/ B`^W&X 'Ϣz<hZOi,`rq&NR9C) 6}\ ?laH]9N0"dw9 m.u; /{`3[n+H'^ D!%21|~ׄLgfxLtȴ<8Oey~O|: T;4@(55TӎkhycU\|${HFVld7~PZ库F֧;d㴃[HeL(f`#FWJuFB&$믡7L/h3O*Ho͈L&9bqa 1C0+%:PRWF.mpmJ} ?8RgD^rGY.r\R{ϛ6QksG!5,Cؗh /p oUN1Rɣvֿ.>Q> D -5xh.>+|tnN~w$CC,g1AIBJkFA_^Y¾눚TV*/jygbQV+ŦmG؆dΑk7ֹ&31~]!o4EòYJdKiL~W'EYY49Kӱ+C5@p=kn^1}pT8:_j%jl)xuʷqv53R{,w$`6j[P@*m2N)}ox_(D$V^xxr^]ByoäϹ hDY&HRlcTklJu\qk~ eR5 A$!U/N|:li\q)y.3lOЫy紧<޴%CN9۔, rՏm>*G #W^*W%Ē.H3XoO;n1DVR(犦<0%y<j7|go &POtsG{'?q?y|춏zI X_p7@$vt= >=Q)0kSFIx%✢9zﲡQrr&ӈQћn-5N߁{+hLp2,/OΩе 呶ƑXTW#1LNLd٦!XVIY :Za]ƍU,ÒD:۱n]4sbc63.[UKaDx,rnI}9,K|j[sT]?G&ޕOL8@G\^Ib!_؍R0^ }A2hG@Șg֓)0|Ho_?(@U0D4B JhڔSBlZw;= VW;- WuoF!cM(~ēbW&-߆ s_:a}\mPőϓ<;*"Nm!bRpTF}(Az;]OdBŏK<65E ^-rgro6 :DjaXj/$)-| ~*/roWS~u+:j#Ryrki&&Zմͭ[6{;l%GCgo,F+ =m zH0EGdm+"MAc'ogTгc)o5w;*Ε8AT408Ypr^Zc;pu4'OS13)xP;63nu`Nv CE8zzK,GPmJjp$=vOkcs# +mPT`>#SN$c `'l\:2t8¬;p0$˧|$w v8 be#e G-+llaKasJMgN<!nf-7׶{ȖZ%3ۈ~v El=7Cfqnҟ)BjLKێO#>z۫m.CIu. q)%־Nm.*6ۥJ0 YBYr]@ l;]lD~9IU0{ʥ]e ^;">ۭT\\3,lʲy(F:NPP8qa#BIiEF^b{jʑלRijy]U]5"ɕ6 U!QE ʖ,bʌ|Q=h#FA\K]?;rY-$4>`ַ,Fuٲ<Ѵ1oś" H6cLpӵ=8O6EaYVx9ih Z /=!>Dk,eWw-D䙖_@`=$E'FoJ ;^"LɈC10U׀ *_­-FD燷.ݘHlj\&6;r<`f4 zt)6ڑFBu+eHtlأE#s-Okd1Ύi ~ތiL (JL 2 ]^@2\9(4{"U`r3qUzw1M5= !k\A@^w;HV뱰迟*&I_@|~ {y{~aNxpI9T^Ccaew xA`Glٿۧ~jDE$#m1^Ɠ`o:3s2+,T2x9ɪcROvROf%hS%́P E$5CTI֗|ϼ- v%ŗf,, Z$`w!\D&ȕ{ #>>ʱL"5_@om].sBRJgu|{Id誼bPnR1 _ GDUzdve\qMxb7D j̮H1L~T2xhqxa.)g"8ɒ6.LpN7G\ (c3t:TMG;Q }bV.6g5Ī{gw-mQInzs=pa3%oؠf^h} X ;6Xj_?0߀ҭ)("l.\~l90eβ*Ea fNJʒq0w>o80c(  f\b:z hu ͓*~MbW`‡|kÓ ՘u6oɃon3F}QzI:iݱӪ7> `07N.U Chŵɔ8Zۃ$ z_B$U~:Gօxlva(7>tі/7!inXTPb{ wS|_|Қ%MSe pCr Z(;av;t`oo8H*Wl ,YMk^i=-UtLO;Q7:\D\gFsYu#8M JPXw83h߷:6l'MBszi rߠv w 849C"&\OQ6!YYN_nqa *t_&,0]}~`0o|"t0F`Gd 1Y?7 EDV&ZʭdW;y>Au[0$N:wf; Q̒Nr^ (ېO%J0KO-k}tQ9ߺ22 PDd.9Gi\]S2@ r8,I=v/ 3}5 ZɃ9 d"#@ܖIWh%k[wbl7 *\'WR~;dY=T6jqC %Y $NV\@va_Θ`$@< >t- tY,[@`>e$!E%vE1%w(i64t[$NP2Lh.=~p'T+ձHG- Xie! cys>grƅ3)8}(m'+]J5diЊs[Dx+ d\H6s>$qQc,P7.֎"D„  72$pmϥ~f^_ZVjW]G̓':E,c]+ky%[h?tڟC+W|>Gֻsol$8ŽmE0n[لo,/]J G9jjUXf $M0_$ʗ ޵N1~rwۓMX "]gh2Ϸg2ufHe>nb9oۃD=ޭyg&}oL4K!; L)+s{ K+!8!yqb)g$h(z\Ƚy6}x_tcO+'RQ}خ$.dP$dud e9E*ݎ &!Eh{bKNQox/UxkX:7ș<{rd0tk@S7C1'labB{_ 7}v›:!;T0?D 1*5D6LJ=AH߿>t "w\R'b$Q{Dbn1m{=܊y/i7Oy6[hCE7@q vt[+Nh҉GmIG2z4ޝqwCz)N3 =Ԩ/W)9wZdhF圃,'b('H:{T)|zq:mOHy秔ܕŊL;g{LlũniO$32/g#4G&<@CkEti`C|VYV(Y8 nE(v۾gP홰HrEX:.f?S*b[Ю~0P3ȩRuu#O/\wmwL(\P c(BR ׀Tn\~"Kj>cVGIgG& y✍ڎR)+#q/4>87=[`^qP]N&s ?n9zCёK#x3xe?AYBP?Z`҆m;m)K8`dR9Hw.wl& 8E< #O2ֈ2{B8>4wҔ]-zcsL{$(yupG !/lnjQTY4B!*W!|9"0jgt5JUdG057T&ţ2w}FFjMW>X20/aVsG.{lƋ(ʝSGJ'^}ԼacHfG9v4]146<Fr-gAyÒl(壳ձ "U-^Bg٨T/!Eu_2a a2{ÑW؜=UKbZ'R!XCU.b  Վ#R6ZeU_]"PQT'(3Xj֋S0ͱQ)Ko ףe?xV ~!l7sUz4 'e8!ErTybWv˂aeMm`, '+'0{R<\ l9^bBm"8vK;vnHkP  !Tp:0ˤ,۶^}@IA7ph+;#Zʙp, f1Iܙ  `z>1'@T>saNo$|N52S\{6vn^4@<[b|$C^['IP܂J\K`_?& 3#qe$\dssJL٩bljl)g >݋oNx 8 #;yFa>ǸuX.Νm?9iwٝ"Y)0DC0E9;vMWY@' N{xu6 #T.ph{ Q2v^':](<~*%҈E21sq I(CRkV n7ςzb|n%MN(wQ}.{h \%\ Y}LnK 峴06@ʓ^@U~ }~/a6]ȃhۋMdxSF=b<ôk4{27ym0z4cNoHݤ+2 miqVu?ߜfLۼox!<= mQySKM>9Iƪ%6k:Xt k>Dt[3b!ކġO[r]xvbvB>~Gά?[^nDjt핣WFg?u܊-Z!wϕ;}a֨XzpA ,bEOoo_mxaGj7(gɫVW%h/+5mj>5֯Y;]D_J.F|%1!5fN֬OC{֫{loH=/Ö3\/]jY(Df}[N-S92<&fOPLV<Scdt_mk{:DP6:3}bޙ*w QBxE3 v,D]mjLFB9~U,8 L}&.XjEUs”[`@Kdye1Xd::]oѳ޸<(,F4\(=?8Ow,&IP.l=ۈfCݳR0-<㙑9؝25 z`SBfzS@Ԫh> )Bklmȷ6FA E2Ɂ#A,Cr5Ύw'lck*eSHqk v%@Bqj! >eOVϭ3`p$#3MEzt-Uw D9:c__\6Z#SܙoE}zdžE(eM̷C8_4k&j6xi6ǩYclB7E[l97N,0ؼ 0Ͱs~tTBsl#lޛweFB<'&}lj!0Ё>{Jtӟ N6̓]ܡO1 C +  zf"+ĝAYԣ(pcsRs-4ԑGH;yٕ\Rpf2U_ٛOb !i^I;۝ZEʗDK;:uum,E]"ϊ0$q '*&cY){NO֔b8 &YAa!LT?XĿDgqfqɏG,zަU(1\Yila(72\ACyd_<ȇ;9A0Ԅ_:u)*9q:$= qWX3EؠٯWYFe_pv~=wsmѨt1B:40_@Iducku;x.Ui@ 4H׀-܌`A5ǴT(s !)SvYqEPO<*5&,6m?aE)ZPRۛ2-ǻ$DHpm:M>s쟱.ˡ`#kRl cefV,y 9 B$kA8`,r PgCOO!H6[˟n9 OcSastJ&g;;WaNҭ*%(o^l MV/@esH(3Vx\e} >o/&tK"eh/}T77rװ1%WdE͔O;cs{=R̓.Fބ%ßMI׼I6$؇]!q _scTƴ:K̩޳`^5;q,'EWMV)5#hmG`n 9?=A'䀍HpƂ7SLNhx 5XEzeuX{ec-jZb}W/z ͬʊ#k')¦`ԝM$>e)Fdh0W [[ey/Ѐ]47] e:jjxJm,g-TNLuj _PNC]Ű72z3{rW|t63eB[/~`^'bGp|E- Mcb y;HdU0%'[l E0RhEmSbޡ5>-kYC8c= {jJ{,ևK-R4n&?brцz9MDlEbM ~c2Wɖs|_`ᷠ`D$E/wuQ.?mT W,:BڔuLtpJ9i'fDb1Vg2LQ =d~[U3눎2+vԶ_*8v Vm \}\c@m<ǔ#ePNrtP2ۑ1GN[Zw<󐯜_reVݛ;Bcj\CI4m5Uj#Ac8#zv{@HA3M֬<={;bD(92#dKeYx}XC.q6Jgdӛ Wx4U8ҹ|R)GgBQESZJ50to]$y_}yfN1kZdF=MOWzٝX" ]txs`H΋qm U,(->[Cb5lOUy\4 nm@n6aWcZEԞ]Lu˿l[f5*\H(g,jfN"3>RqJT҉M]{C:bI,k=ހgjLaaq.䮏 t8$ױ&v9!~OlVSS&{P'e(BmE8E=RO}7Ów݀dyW/+uԴO({%!uRADkV$]ttWVV`z=V#,m1`BDžU2c~[ Eŀ)*޵k]1t_1p+TwwmLR|T=;&_yh#>)UO*%Jty:/1L&8aOW&*-հ ?6 hs$5x~FyYP0fF^za\57Umo 5J2%lp꡺B02DyIs3R4l/[] |ځI{Kٖf6p bhN^MO{g[ygJno,lkMp²s b®U+LjFZ F2V=v+&S-e+yI *IuY KOGFLB.'Ҟe3VIÂoF^BVP'ßF/_i;ю8xNJPL*,}ZܹBees!/"_iIA7If9vڞ9uBzdx2].„0|0.UcZ+򖝭PhĜR,-K x %N>W w>| F ]ŽYv9ĠVRMمgڗQ5 lMX4,7k_W΅CZ!j=幬88ŲooTώ3kt 먌AP0Ji{}yI"^se`jǜ(|8DФe>QmnԒe._2;^Dwisu%g(yk@Ծk]^8pS]KbSJwE2/FNkl$PT6UպFE8ܯI$HL 8s qhjM@82ZS@i"FӮOdE;ZUuP~ԧV~Zi~>T 󽫱!‰JVkձ{HLъ)7+)Pe:sXU|U7;[lj|7 twS')!vɔꍱ{ɂeAAKj v9H4Px愙B-V39'H@SK5fp< Fk|p^YQG-AZ1Cdu1lv5"kI9cݥ拾2v{?=:>2;_I%"m_&[-˷ @|n2Q*`652:ZF@񨛊1Ne֞;GW6<`/-VboYPbi~uKz#QK h.%ٸFc;tw[`'<;/lqzb0wA~zSƬ#q~e[V>|y6"2Cb<6<_6]'tjY+IiN{q )f]Mc:Sޕ=6烛?KQq8W pB}QHOoyw}ADx-~ c( nШ~WXcvt2 y|Azm|yo;)vVZ4]|Ad!Rא"&Qz†NKq@tI7j-LDfk8)ڼZQ S@g ,-% =^ؓ;g Q ?6J+xqc5峟zܗ?1dIC+bF2>yb%kljmЂIV5-zHQul>,} ^qR*Qw¥"BDdԻ{{Hx뜦vl/_ <{loCs{^(̨{]lQPͪM|4IL0с,͓I2Dc#Ry (BTe=E@A;S/?kC_s,{NPTisELɫ,*FծEkO6uGT^VH_!9Ƴm+K ccta#]T4$\ gC6jn@FEA)+ѫOh*LտOU^UY/8(Rr_-7L|4 Dqcf6@)ų|[rSqSNu6WE+4ޏҮRޞJ[8~ ǙU<=5e;N[^c=2@tw}2ʮ :(w@%!}  ,%mY+&^;[Sڊ?|~By_m#2̴3Idunǡֽ*_M1lhV]?܉-"7HHoTA5L4)c ?sX,?^1G>Y^]Pc>i]8,Sm:3`=IwL?~ HOF ،N\elL4=Z5s 9gŰWM~&3;7 Ի]կ :R1_rb[zSӤZ"=UNR-h1da>sD*+P9|I8P4}k^?w(C߅m#Vee "T`tgWb@u""MBE ԡ1]f TN"Ԗgd R3c7_l?^\: 6ubVC&iP/܅b'o]ꡙWuT}wFxfr62!%(]r8MԸFs˿, d0ףR dM'/Mx w[bl8=osD7PJ*IUMq8V˴iE[{>J572afljSS".hphַ2KN1۝%UX > {a&7 &- M2êg)$S#V+&IRܘ33|?`%TMߜݒqLa9iLs2Vњf)o59KL#ѵ@ssجFdN]rQhŞSm?>s5QS!|U!R. fOE}x@y4K?Ԡ)39ۦ3ߠhM"_iUg{L'/ 0]SF vN7xSfF&rn;<KgK8FME:h=Y4Wc^L-ߣKAsl@dgeV- VWQ]sN eh38vڅ!wIh~hX!&+н2Pa|UOyTdз =-\hOOw!ש5Wg]]oxhAO~ay /|ܘ!*6;G?_pOorF> SG%qawrsаiIĚ??;KjM稢jjio]A+pBKYeO'u 4h˨2).p#| p}5tGLU|WkIVz23ۦ" UW^,*0 ~504#5T?6-+Xiп|ӠK!dfBΩвyby$xWfq9Ck='UucM_XN11[xЁϚU?m9̀^<@Yj>m=_@a.P0z6av{FH a# >zD"ZatLfЮs_SZD g@rs;`=E iٻH6Y[-o|Yk=<+݂]bC"1F-?߰y\g\ݸ !@f&KVNjVJvC|k1vSƶI' Ѓw1czU- eVԜ (IVU^Ww6Z*e :*uj啤Xx):|ۤHǫûn!s Xr.,刕m^/?AH[ zT@ЧJ 2E ű̗7.ۨUNx&~?, f)K? $ t~""{ XMaw#s~>joWAaoM~`5K}ퟶyk9Dbq+cnVKsX֗`WfӋͥ5C __*4P07#0»{PцCJ`!_r'^R^@3} g~q{^xwVԒq2Y͑HY $ﴬ=7WE.Ɇf1+JypJTϟksxt谇I }-qgؖMŐ"/36"|5Bٔ MhMQj1W a}"*o?)1R&*jWΎ'.ܦqySFPgMR;X [ O n%z"j?^V!m騺x>,Us@YILoۆ9uXB/i(ةO(5ǸyM| H/#iG r=*7e*([XgRیEGtb *k}+%=+/~a-ѰI0uPqÓ2MfG2 lb-hlq_P*TA=tH$fYGt wp6k;wqTp[{o7V) {jO\GJz2e#(Q*Wn||xq )ufxtjs(s_eoAƷnox+4%_r> C5U&*\ѼIx7z3 ( LFdzwQH~-skX%/%&s[7M~VnNޝw{%n.=hsEzCi;[a/LTIo{374+5;V~ _'` TVăGJL{o&]#7Gfr"im$Mxkg!K.?"cwbuL6YfU^>}9o$ [K藦ǁ +.\\VC Ke*ezp>tˣr?זX3o?2T&(anC\z vrNF|B~ wXR._6.Kц/$⋒㧙<$W6Ks>;-琯!':\gҫFtisbW4I!zV !CKgvӼ6|vS^ދӋ_8ORoU.B>.o51Rj0/Ω]|aFcoDxSP ? Uf1iO |XJӅ'< mvF-H MKӏXvZPDy,6Jsp d:) &I\q:q59iݨD12ar ?KL%΁լ&0FelVf?Y{-C8PqX(J Igfn"7L|۰J]}\A{fQH; 'hxRnp^͖Qq&$7D%4L޹:\j sjP^8j\]6Ȼ?ǹޏtPO% Imz#`\@ //MډmvKT?pKV>A$+F?Ha|VuLXѹDNC)g+."==m/Fv(uԆN  B:]S ƦnӋH+ [?/]XIU4Cr/f֞llb碓Xs Wc-瘿6[rQ^=/8Oʎ] *MKLpu2*UǡSX|Um9vh)12p1֏Cڦ1@S؁ X*X>>Z٥1Dd6p}v4i"$kax/o'2FOSd4=]148,-p>$鼳oJE>X6M6Ȇ}zwof`ံi@;|rT_'_4;_|6O˔/a.I!C*oA.wm ;a9B:üec WN u8Ii1 `ëGs0g 1+\":ٰȄHe*i@m@D&q͕=|$bC&ЗoX!X:i/= U)< >ʠ Q`h޸JH 9U׊[.Tdhr)?dT7Q+lP<9|!\{4XI<ܒߜ(8.~cEf Fꅐ 5Sivynq%Znc׀QUNgs#kL꽮0)q \Mue3'Əj;t7,_ 5s,}SwɄ'w|)q5.qyJ:̪0`YD9ȭ%;'&+:>brBpF_uچon/u3!юdU)cLjH~9~U)a Gmș @9>>O$Z璝*vh\E2d$= U7vjB,=!E Gn0qSq%Ӗ/{$v]f@*<&v"Pb3e`/ІSPUA❦F7gN MbGլjZGsߋ *VҔLo2WGuA4:jpm AƽKd:/H5칕`E*-ITrk_eB4N^l Eڮ([B#ngǠUɵd /ÖI=CZ;*l"&8CoBӬ:&,q8;Pܣ uF4H: 8+&΀L?%ue㯟Ipw^quHh)Ɇ/~XP'`A_k)./%ļ079c2 z)g2SN 5GjZ]NZ}a\" vE_L$*e~\?fqlH06$8ɯX2aPn8FDaP,h])պ˱e6}Ž=O?KԶR' j)v0U2FV&|q;Y"{@S=3.` &j|kA.y J\7 W|f&;+h+,d $eqXܜ%b\0zFB)f=Q|xnr!&LlKM ?f9|#1C9\ͣ\s[Z(`[bٙ(c3%s?@ED͞C(ы2ZrdYGjPeNoIjJpT玸,+‘LW VO 02^x#NTnv@!p)"pJGUI?3DPaAAzRwׁ+edZ/XwnͩH>uEj-9rnqro! Ē}?ه#+}ͦP}~ڧ`yzs/WJs~4RH$`@o%VckiBvLg-3[~U#s N{ITU p V+4ԕlEtzGRi(xX{rM'I̍~$_"㶣{Ξk421 ;^Κeg>?t?2zZ0Ы٪ųrse O= \T]Z0 Z^؂qVH:ŌtگEu(,oqyMlW"^ }΁&C.|w% B6?9ҰЄݣ%1Tw0wP)%W22a8菡jCwgH"M 3y ٙij0&NrpNyD#ݤɐ7h2_o}TiTa7D9VއX}TuYyeBYd:O8C6nLola!ӹcPyRBG=)Ƅ} A*bVL[/#jݭJ@;B ^I.Jscq}}B6тx?]o[ePG56|l@ޥe237yoCǣq>j/2Z"ꪒM ʲss~wS)NB:'0p_'p/9MޙP{Jiވbh[L<&eւm9C6sW&!{ijIg?JZk :e`D2Bڒ=-AG]k߭i~>,)b8-C jaHK3" :Eup|'4?,d$,&15֔_dәm$V# ;+ D3]pӥLX5j_ߏ_()oj[ ^0EۂiSY-kDL=CK뇔8=k'i$5.O:`H \k Ha1׳M$Q[Ǹ~4T5TժAV0h!<{}<#/ Un&EZcb]]i<d350Ա9_EJ6YJq(TG5|Ѯ[$t&A[Mh,)d} 2nq l8(gp=ݤȭڎ!}5s/轸@eR=gb#_B[MyymLcŨETmvv8mW Й43"q:I#W6 ZJ +Xd' wF0?'. }H7 Y[k~}6g~xqV95vh- 絎 ]k#lZ4!g읛nѷ GOw@"ޚXΈjotSUe%{X?~(kFl~PSe+4b|[ڪC(!џ +qۂ+𫝐 9GA)D^1vUe:$ »-M`MUV1xjϒw9>:Laϋ~Uƽ4ǐH|_UUu`*C*~e=0> |RE}[m̝HnVmSz =Epqߠ:Gkf;0FzW*_|ib)yFfc\-qgܺH~~xXN Ic- iHxLvi#7teZKEdwy>ýA_>{1U@g:y+!ds%+]w'mAPDYd-3|LՌ=e-ܟ߇d}bpFK8wuL@(g`>y<F^ص{u/vG}ȔU"xHqJ Q-YxHe:Dں.4DyCP߂G\Ԟr?bYݞ6EV78aJRz ah㇠וgfq5!q2aB/܈{>8ߧ7w}:Ս.KemcZ߰'rlKw `h* }"!5%'&X3PbjFM~6f܊z?0x_ދ𠍢G8;quLONHc%HQԿf/_Hb?aǿ}^sf(jȱ߲Dp4 U5) ߖg\Mj&dZa]vϮ\NЋ*> K~W+WNE>ɟb@&ZZ>]Vt\'k}6N ~WiyH٤`3$x 2NT*QVdsNvi1__$Y/o<@ti6z ?]Ha;QZ~1{LT Ua`%vfENSW`Pza* \`Fy V镵E";{:/rK0KpYl3}ҸIzaUҥ|R*bss/H B9ICZo1?TK}&Vnb٩;>W@h kbkg򎶳WVCpۣ6h3Py f"GO|^K5ÚMr\s{"*Pu b1Aj~%b~DɌ/is]O6f)}S tRl nʝ>K[[CW9fvψ΍w0(c\(wg,cQE]~`*Lى&uK&K=:DjU Va D&>)DGWvy%J"Pi;?@PpB1E5p=0Xh$9NڭyAkGGsV{mUq:ZB3ru'w k54:c="Ȇ$L=?BP[UOpN6F BSiw-ѓ@\9=+2z: lFڤ&n.Jxj9!d2DFH 4c3^WhT);֛m- ۠<\ܭe&7=;5Nkaދ`Q"(kgLU Ēh xDߡGmWyvBLnIa6k%Uh%([+;b*}^&>nE,- /2EC΄+\cI2bEg!rjbDH@Y1r2/ Pˢ-^;)}5J=onM;c_ Bj4z#CTs%7˧wL PozgJ~Bǟ{ĈUVU:Tl:|Rn_c8LJzx nPEGlE,vpfy-PEbJN ?+6K!L&hOޡߊ0r 5෦ stPǃ|cbv O\RkDl0joA*9>C1lfv_z Erm"H`K&ǢZ!C xE<MP (5?{N꽚 4j :95[V['h5bw-u]&.,9`9m}B=!zhT$ẵ88C-apj A+{ м_e(=vd\1(?4PF ױP,Jt[6vVlfǶm'vǶmtlc۶n?㎵*U,ZVVpGl*ƭV1zscZwǾ3ĉG@)23/tax",ġС,]#X>b W(˟b +H@e?`4K#-h,k\\b6t6K^A_E Os1g7Gwc_R\ff63+#Y!Nfv>?(2Fq0,\ _g}"VfP\v*ٙ,6.ߨό\Bq7F>.fƿl,ؙX,^bW,q1 `ɟ/O~66.+[7 _~3r&F.~[;v&p+-wY8~G7wo~_ef;dbOVD&88?9`gd?&Vm=ZşJ߈ g?% ?$gb]uO=J=Wiq_S̿OJ0sO dco,?RdRYdž+fd+<]pŌ'~B* 1287YTgP!Qe\7hm*K#ras@8܀Rtdhu*l&Lt3'>YXjAR??5 YLόN0)DPE(;6F>l2>MXs MR4>gy^4C22Ar8>٧& (}ed?g*`yrya~1V *N,l M!|` 0UxINf_9'4wTI)-#\+9.i@ʞ4v^)4iDPDD?"k>UF^$ǞV0 DGYSiiܵ?M`x$lhdi5FOKuk.^.6ԯpG`-)(Ȍ] _Xrx/=)؝Vl=\͇ۡYgfgF|tSĀ@)K_`hc!Ʀ1)'t%~'j?%ï=񑋾*a" w%=*cw˨̵Ln>^~`|3U%oޓo@" \D؊Ml^G}}{E`77|EJ# "z1l#B}vkbBY #b:Wy:0$HeQM(SJZڦJאhxLi}3.rm1:WM=@p>3:I+EJP#:>:0'p/WvA/t++G:3[pvYTB#4YzQѣ9)[xrP>Yor)\A0.8.0ԸtLKht[L?]k 5\z;FD̈́硻J;mQa&eomN]|;<Z-aIÃeI*\ࡼ ڹjp#1u`Ьʼ\-?%4F+˺ gp܃{'EF[QO{hKMwUk&pN4ԒLw?YEƒK܇'8lCR߮LV^ujLˆ'2̦[̨KV끛KY?9z@zwܬ^EړMF b-ZűGn,'޻PAS@+9[~KT442$Y~o.É9+E0kawxI^)*§40OAN-V59|6 ./Â!kP确n,-&K93C~UW w9G+ޑHXW GIowzb%{ \ԳZNx[!A!q="ͫcqavEbݫ7*{أ. 3 ޥO6H%SZ`Ϥy҅ YcC_ ϷhéK+]'R+Uo(!ggu \ya £|NbT>@@9w`__ӻ1fm/'D rV##i }kM4[4 )A'4.<k-#A` I*UUZ5ݺ^w#ЙӇ 䄈Ԡ$яk)1Ȧ%T6Y彩yNM#HcyܢXH8/f^:z:ϵ,AZ)kHRn[ٗu} !ΝaњU,Olgzf_|u'1z+?a5{3ܚ;ZcnaRy#ڈt3IBR!a"|.eW*~b+7ợU;^`l5;N֜~&j|Y?l8] ЬseigK?ɺ,81yoӰ$C&R:YIUЌ[T-懪`eiUJZlvq9ěeq^gYC;H`h'rW Gnj~mP*62@i4shqe~K{n YM.~Z\L4Z%z1Tc0kGsm%?=!pB*Bg(]>yZƅ Emmp|,UB ; /9˜$fBqD0B4ѽġVjr.%'R-JOB oɟ-*BU῵^/] *M1AbD/Q={5".w lm=\udgS ^&% zw]qͪG^eIwL^^!uTm|T\T e=XT/nWxja=l뜟ӓA2b%}{)K^"1pXx͸EJehr6u<~;w4ځoFhYX9޴&}\+st]{ϳQydν5JV~nL&N9nd|C$Oφ(>x bqU: j*a6aLqxp\5QRćlR-h<tG/h} drrۇCk]fD"=\]uZ0-<>} T >JuD|-%׭7ti:$JD$1rbZ$󽥬Ux>)U"SO,WD qt6{ B< t hR]1r#sRgh밂 18cRi=|ד ^$  CE يQ#eF`y ;t_| +<8GSZ]q o. y pG%E rW]'pkq쾴̂/>+5n:G'vwg(bjH׺/i<\04e0; g};#wczO$FZnWOZя&U<بr:!?[g, R-EfrkCRJb[MZ9 Wtϛfa52eІ`eA+=A;7X<|XNU|=\)n~2y?͚ƴM^%$idd?XoU>Pi;Ya~*Rq*1q}wu͙\54hUr #>HF+.@o G`hsw+HT`z>aǺ nW6lˣ@M+@KC@]a3W~G/nhJ*\ Nͽp4z(Ϩ՞w4Qf>_VW/ۓ{oI| 4H_"FB1qqׁRFrkpU-ϊaxU3v'UR~vU{X-vTD2ܧTwi-RfRH#ϱŴA /D\W{*:=HUO~0ḄJ+ at gxs]3r>~PN婍[;^㹸K)afXևzPjt:kSOlc>e:JJ%Rj>(•/:_|l1f  \׶REωA=nDQ1z * ElM ,dL=?];S8Ƣɸfwl F$* _3?b$ID]ɦNpxq ބ?J̸,Ƴ? m[X{;ӈg .mh9nsYF'Ly 8g+F#(P^k]w})oleGNP ?_C j˶1Ī[OF[ BS1F߮q8ջdw:C|0*!KtبnpM>iu`hQlKkwx83Z%+hخ?ί&6vMߝ*S`ǼԫW LFcrҠЍu*h*bC,m[ )ȋ>Wkg1ɦ<}ݬT,t >,SAd>;[%ȴE3-Ǥt!; + 'Y%0sMqL03zp/TmܼLAA>pSidZ C8m/AIs:Y`RWŌw3xK(JɡčrNǔSFI,ӌƃGE0Pil&/y46: #S2숁HZA¬X+;F |l֯%}yd:6s׮TBMy[LQ{lQܜ,opA51gx+Z]d`WGڏڠPƃR C P248 /nc9'|3&>6f$?|ru_wρYjLMQyS2.dt?}F}>zzTn@=]FUhfpݰ~C]\E@sۆL}O UuǰP 'ze ҍ0LRF 'wЉ :wp ,d<Z鲧4G|<';MSq;Jnm6Lm)~'V1s53h;-[ E 3r5Xq[k|+j<1wMAyvCc5Cz0A 34rFUz8hr֧I cܹjW, Mi}9A%`7"Y &S묣s_Ry@q:T ;){W=)}v qӶU$ed}J)kꭣ=F/Έ[N l+#K\#w l&?BK`"5K&A;(P}ikt h9-ٹa 6ѐ?iE#"+ <Ī zKӲg'$tcIFCtk$ŷ@,[6n5!7o!ձ\~(|}x\ʹȷzkUF1݁#l-ro7/(=nӈn)G!qJ6:µk NCa1gr;+$!S̄mlyv, -Gߣ0V_]vI$~Buii TFU7h| b9 V@Am2,ԝ*5@%t\$7qcFTiN8D5<Vv!%f_(DQ˕}%3nPg\D|J-[%Ts]gRa0rR9Q:kĄN]9&XrG.&{] ˚՜ să5c!~0I[n7Cyk4ukߍSF'e?έ0OζZ&2ټMi(?&{ I|$0אO1^;j矏q۹\'jy\ﶖ/AxhC#1kWAR$jgm(*J*8{[q0Ҡz?auˍFlJ"@Wt@'yр8!@J@PM^hw sO ,֯XCM"mE /2@ >tzcĥd=F=#_h6|yC<Ф .xF;<5V%Ǡq%TolY waow*B>CyCo W; brU3yTd6]s;qI{+YM l"IP_;bݽ0T><+AEgN j"qK޺EڠdIBє,Br % >M 7رM zS V*+ = ?0#/5Ӊ.6LS+t,<0nkyT?e4(hWF1| ", b1ʂt0RL,fczH.ޢk*RB4<'FnuY¥…܁5kK0];nP=_ݎ+ ]̢Lʲfy>+,wH +ɛtDP@|b#Iw[^'%;An'd33Ի20۬ēMR,%B8gDtf o냢5|;>pk:2מRzK{t#$\.q* BɷxPLS(y'&f0xci,X86G,^{s-ڱCARt/G't~+GFE”]m |@f1P! =4p(t4V!Ȝ49*mW+w ͚o|C_VBWF+dwUd? O)$֥3SdDDQT 6jH28mQ4Dhvϭ?~_\*pyMņxIҎlҶ{}af@Ay3ӆ6 > ~]Ji=u3pz$=WV|F⇷Þ֝{~\;EF.MJADrv$O ,3k+9 fj tНbFҕ\<]28edD0q@|-"y L_'7`SB>e.9[۪I>0X| "0M{)΅SAfIm fE}^Cڛ;e=I2 QM׀Ӛk7y}mK6|֭qW^ϲXy%5W6EA^ kS/p$>ÏPU:nd \1_c@NJ?h0R.nz'BQjmd9;[ rvԲl79IHK)jҪï ]i*oΈ7p6UYJYp}x4J%r6s{Q0c @FXp1O?o N,{7&@?PH@C#= ^b?-I6pL9YrkqYIqJ>f~L.Ie=yB=U,“̻.Mr uh^Zm#*?t䛑h;iTzYJ%TcyRQyF(Hʂx džy'YF112ƍk6.73=7 %1fHwd6HHIT@P}'MW'EN/_mNG!TޞN~Tp/ ƫ{갍7WJuPg9)JN6q˃}:[d _n¹Eɰ$vFQrek]sXŗj~EY"x=y3DG+6 $8BVZ^.nld`HͬIS'Wjs8xH 9Ǝ㎵9qG%m ->~΂(X#ҟm(j(x ~lu r64b?E)% #`k빙xDKM-Nڜ$ZCy̆A#n)2K/k57$,1F0XMW8."]0zS#|bD@奪dLI-L=3L &s]xpu&"{HraPsDbΔ:encFt @|⡓1ZH :\#bכ ML>fܒHK&1GGQ>K (Oҧp) BH8떧>Koߖ73Ɠ|uysmxyC͵aIƘMܣ<,375 KBQ|۶*{ N[?x*5߱ŠTΜQO1׭A^|`C3`f1Pr:b ;),&srTnPQ8$ƏRrNLtD ze$IbMwFV>uȡ^8pUhDUW_>M\ΞwEzݗ3g-qJ]eE?/_QgAPeM;Ne3ZcLw*{g V(\Q׼lJUİO ,"o12(NtCUbK{h&`G-qi$G',SeA5B 8W:fdzoX=QV= 3{ڈX?b˳ov&!fA*M;e9e E5od7Y/R0|IAB \@R#um_Az\H,Bczk0܆sI>%p:1uL(de5}+m&,^]q^$# `Sl;g萁uLQ>^V}ʆK:޴4.e|Yགྷ%hJ$Hi\ '҈]#/x芹wホS=(Zx"?Ȯ-Hny` lN@dߣ]{T;Dmz[/CobIW1>`m48R]a=6cm1h%FP?.%8LksHBia/~j z ؔ'%h 0ԂkGڗUp r 5陒WtIRI[1 ʘD(0O)Oz rPڒ_GjAﱗb)Bܪ4G>ι$rUx;,׺:v`NG|RbKwCٶ X-xkOw6~)[)[Zli#/P(4i<{fV GU@+DPa#|^rrIX>2eP"QNveq,.O=gw]KC{l[xj:ox,~7ߺAIuU.׊<36l\ ÏNE~Gdex#s8kRM]v9ej-+JL)N'+rJo8XN5K\QgO}EcD͇\phݭ^ ETj"n?ɺ}=o WM5ҀBhc91š=MfrԞR,%@B-&Kr ߳>ePucgkymbCu<1׸C,&bZ=>noSh֙ÁA]Qfi|M(lxeA `dS!`q 7m5Tt/RP{ҴO*u \lG}>YW ~.%PBTVKP pʞZso\OVu˜!Ȋ dsBn*ο_9}M9#:Ń5*9R@В/m2+iփDjwv$*%N.K Sp;liZI]$gث[~hƾޚ @x2DyO%Md`>rfyėJH[izAc}0UKJ1nrQ"Dc![. u`!>#[n1-a47-R-w?=B+#M7܊h%1}j1<B ;s5ץRɔq[㚳h$)Gԣ5dh:3J_'w/-Cs#F?1 XPqL˱ɰ8X8"4In!Y|߲6i^}"r*V$haI 7!, ޜqL D_6PtH#C7NV _>h^Q5Jnty Kы} ǏD &I$ٙ {weeJ yn"1J`+s7\/-rZ,W.'+t5]\$KƔXR9IGR5pY4P5!7{Hŕ tͫ= i~3L+o@!e`nE)n\!Ian* zĽ|8hC zodˮ7ۈ? F x@46] c \1Vbi7TPUϽ@+1O /Lu<:{2C#/ ;:UOV d H: A{f0c$P9;NՆzSI* x{p#xAF]#5Ŕzk"߭'FցWAE,TbBUTƃ{Ō7 6gٳZV8`H`bly/#Din&4_|pgY J q#kg> (7Y^ =[r6Y` )[*.w&ickRŸpFC9d+(o820_Ⱦ-<1sRq7O~53l VW]vQ5D#vxe(?s^8;|c|T]zDfI -3{@j;kf>LEI 1arg7 M - 9ʚ?x墎!"Hõy )dMl ҒeHcai\(P\9v&7D Bb;CiY=[ٱB]\nAI$}#w@dm4itf[L^/.l r}$gDOҳ0~0魯 bQ!p7y4?YFpA%HN¬TLY)w9"Q̋b6V 8qU{]1kxCat\!Mzf_z;fZR/_Qʂfidm~l^1OTҗ#`Ns](J|x.XBi|r87ݙ'IZ9]@tnY 94 {> RiUC5 ۫ Ze?˒@!w)^XfF0l>%q{*5A 5+:ZsF>k^ۦ5/%hYJ.1+LcYЇ+87Q&BXrـ +ZCXt"]HVityl22XͿ1K֓l"'AEmEo4j]ݞ"KX"D#PoHjE",*;~+{t2o i8!)]jY ̐x $6JdZ<(kyqhؤ@g"=OaaPSW89tjrk5V,(g7uHE&H6_EXE*b iز1E.hJ=5v0 RΙ+t*GD_K; ]ܗɐsGx)B00 ynk[9st% P wɽVیՓJA P; ^ɯR?94eσ ߩȟß|- v A6l?y3},E?v%}a_`TD{DM=1.IZCȰuLڱ!vzfW=zi;8[6T RRQbhӡ!/3lh}e&A]9U13z}X\Ǚ4Nr yJd,_L* L7% `/6}\P~M<7%TI0y DJXВF|Rc"ݫ'5n9oc]*?LЩ֖19BG;e548 j7BFxXCw# ^hKW}B| LJEr} i` ʯ&2wcsxRv×Ը6c/=S_4M#^~5 9e#ۇM:5JKy^ !{ WclkGyiXU¿#"+k?o;EWGc4]?]R>7zZ>|tU',dA 3EwJb7灅"nj4`*-EX^.l-6οB)2u=+ y(V>..I ̑JFIZ a.H ^xw)v-gGu`Zu%<-g}ĖA2)[ry 4f[ &d%(x,nOW@%^XJ M(3fSVI eZAӐ[M8W^! =b(/fܤ M4)[Vckh8R¾@k%J#GM}X/ ħtw˩CD@O2-+([ 1hRWٸv0sK0xCsu'w#WF>&?= ʾVC ZNͦeh7Bz:v|47uGF+5@~vv|x@~Ltf[YKO`Dts / [;>A.,"}s. xZEzI @}ŋTzr)@Zzŀgy2}\V^YlkN 7渁?Jv'{iRS٨UNIj;cB_]"'Й#WGNR_| { INf}~yLf:]H'w!b@QM]xi۸dN,ft4}4cEPձ5_5 {\yIJhu&ؓ|VށetD w SA{FCD݊i׋\MM 5O \|:e9Ld!Y6ݺHHrR#V;$}If&L^͸T~eT@8 Y;ez4ZLy ܟ_ihēs\"?c?B|T_> 3eo{avbo&ƛ^SG|A&+H(tKwޣ{pF XөgJWP#A"uKR6w[)P!Ґ&wVJ]>zV @A1 i43C}J;.P:3}y|H!xs2U&! oրǰrTXk s=".Y[H,?tK[ KDŻmlEphs:+yCzYBq 8hg0bgD\~Vū"m6m7ڶ @!cCJb1Git@h3 fOVJ:-&qzo~YW=3ĩhP^|{eut }TR;xyFm/Gfzn:jGh滶F$L!CE):` և?((?\Yt r+i\bxΊV9xS~(`mK"-0WO. )<50 KVhǵǝqjUEan/ʣHJ RhB*tt0š,iN2)" 1 $Mrb]WZ$>u5szoݶY kÞN.̰Μ>zc@Md2gFSm㕵~gHrRZ@HY^ K/fK":,zeEֵ:nT\%wTCwճDe"#A ``16s/A64y 5Tg;䧄L'[3L蟶X(HX+N(3a N M1Anf^JJqv S^!hp{? JrVi$HORuLJ C ہ]ixOX)]J _D%W]2gr ݓ`@ɩ!C0bx;ƠLT.{1X 5ۨK eċOCoRMO14heEFM^zX#pH )@- 1!d*R9TgHR֌ݴs cB,,V8aO]WkoOk B^|! #k^Tb=.xZ~s5Bw7Px9k ʍ۽=qYxN5h?]V[vZr&.M^+ՂuoE )z8ͭk(<|IT$'sY>44Ã,fچ; "|%^b>KI>hm7u%fxї%}S fO֬F tHcg,5rv|h`[<@=+A i*=[ilQ#;֖<6;( 3* CM_P*w|?V V>tP2`Z'naYl`uzVt&5RnLDoHJQd<^6L*-3Ve~y>}1+D',&41gdIg)vlMgLJ$ KI;yH_ ЀDI3{P!K  T>c@4*pij2X،C c{ Ԙ9Ev8I,5O3*ap@tc[#0&PJ2/Mm$WSظ{6 kG9o6c$Ӈ{p~}x(jPePܿ\6skB,rS'Td~5.utjk;T}gɏ;ȢDbՄ'c:lyH(4IT(<>4 g9FbxQ;!͕J̿_^gIec[w }gL@FxU^O˄=2(ӆ &#AUm&92i='KZk o(Otuw1bNK0 qi#l敥V\Ci¨.tzѻXJBbh^L唌BL? KK,>&Fʄx*N*)+bNkcC\ҿۑ](uGiPB<~U 2sˠ.8%ȩp7M}Zڄ[tC@ y/>$Zc8޲1^&0ePHў/!ds 9H[fkN"m:KZH/TV };2uux*V~O 0vܠRH A($~$ BEO|<j9NLM ҇@vwXQk&km(]w޷󼸥r{XLO"o Q &È+n ~Z٫ kj_ h@gv7pG2ĚUfNu*ACha5(Y *ZoqI877tj6zo{bEhzN!2Q?fk~=m]RiQd h!=OLqKB4/7^a JѬX[#[A@lT67`;1cB4d}囵L"]q2SfX}[߅G$r#Ē9q7JX#o kF=YkQf>>|n}V:0ۼ";:8#0Lws;xJ촄jƿyG1te4;L?VAHmeNwK۹w؎UWd0De_ ESB'xl5fgcU)CT/l|gaXTĪR-;18`.`\%k  ĞJ̑(FГ9puxfP1ؿ#A(iIҴ|ovv씡豤dɴ7!Zry\{F2^Z-)a3VCW4>?6/ |\ sxFUkk?M5|Hc( 6wc֦oP԰EصܵUG+!-1TV~8-.[R81"h x^/aݴhϥZ'>a`Py˟R!Egy{Aѣ_ęGJwW@d:7Q.:3ho(h@~Z$<:wNFɃȐsfsO5DLLxZT|d̀ c3aa;[˃J< ^E}gΖ\l{:dK3ٱKjY57Οe VY+qwrBSY:uas1!B?Hꍫޞ4CXu47NSl4=f{!*Z= 4 vG!٠x=XZIwoe< DjCryGY6&ꔻ5u@VW8L%R~.M5<s=k`(պƣGGĄ"{ .@F识bDC(RI|"..HN)uY6csƒ Ke*$W]`w5N BNniDra-N?1}1={Z/~-vP,ڮkN^|S5#Tǽ;ĵbuon/A{} !T;$ɄׁVN(qFxScv/h+`FyVP\\exE?S5JN}Jmu s>$IjWQLJ @*SS׿9]89hr l[474[prL&pq)˟Q6=0ZOo:vPt[ Зk^D p!&F3Q \PZ,悭;dS5҇*l:bVMI,FB%y/bi*h|2n6U2FHPj9r츑ȓO~ DۊjSPP_'ig c21]( ҔS>o;FK}X_ |/S}#wѿrՎ/12m8f15 Y.ĀǗUqBxlnХd$75*ʍ&VC ? \vHQ&I9/K,;FPھfp:j.am]^eO .0ȃM1yrB0DJBl^yK4VM;#i ". Qb1`o-s}(/OhV䆘VdФ=Վ'/I#$j^!+O?R ؽ~ ;#[?TJ-A8X4˼3 z;'7Cy_6pW9fеAxIiߋo}}LodsJVy\d!bj$'.Du.r,2qah8fdIrAb\W!p(q.U3’D Vo dPa(c+!5M/SQ>1!=sc^?`IҒ. 5]s}@+sb~{lZE8Ŏ|e)&T}Oɖ`~HȜųsFIjT4,6۾fD`h`b* PE =Ngi:\=%.10!@W}́+V.Wr$z~jYٕGGDczD]l"V8`jq-c! "$ @M*,\444q5bbd?NTc_Ym:*F6"Xř{;f=#R@N2@[I?$) U]}+ږ!+;`oJq#Y;=ry>@X+$c[rkܟ(ƺ'p^ACf [F;lG x<܄/BՀ8 'yE [i:@WАTL4=EqVKZhVy~`èuOЭ=uf1G.dFjX5@7Glc luܗfzX~<mCih.w wp\/n 5(?6yfƏ5wlPt*\$#3䖓0ʋP\ <|&fݞ0#4Bߔ9n2xdL # ͏v^bp+5M>,3s8th䑋m䨰)\QDzspe;dlG/U9MtMZl$0A؛e :йpZ7Ō~ V0ڍ6oɺ,a Ě\H5/E`2k02.\XzG!;7F81/aA1!D+HdۂS .|\mz>v??G֢@|SJ)d&n|p?;sRWپ:3@wza*~-!z.Yն Y5='4%5r `\;ee,/MkLLPUAّ) KD IwRtNll{ dGM.^C٬LDO9 +F$EVrϺD]xu|h%)5d/Eg Z*SPף~l3}m[V=[E|KыqKjJ=; 2;Q68{8YvM٢wuɋ}{rO-@!P6AQ]f ϖ&wI)J o~ޏSS?[BHC:4$NVFTzDMw}QI Di#$:|­-Pc彡|N&MJ!6iWSifǤM\Ms^F 7#KSnN-*(/[Kq-}m8(0f 7\`OO&۩ w幋W2x-)&Gp#ԬQ.KO-~#X!EMysun)r1RDcEʆr3ez4Mz65o[p ;]ՎΘ uKhn!hK4h +P^Nak+Q]/ZlOy襤C_Je%úq&y]T4;^mz]pQ3~ޖs{Ux_y²g5o;Y6J96)rཡW}AWI%d<HN: bWn]F§#6)$Z%xeb do l^&X&'9%.A@MNEl k_ (.,4)/>WE-.-Zfß +ܜ[.MLH5f|L}u~XdvO ,}vnőEq,31w7ǛlƓӪl9%>Oَq#470KAH}-m|UfgU<R1,@c[6dqG{DD>0"J20t@R4u_*ICi;\܄q'xXnbӌ"ڐG:?;U-ڈ_K{3L2=J^mg8Xϑ3Đu|i`;k7;l>k:xk6gz[8w'Jov Z:ʇҽz\5`dHO(.DЬ 461j[t >ğګ2MpDȈ #{ck~c^4R7? wKrbKF!x!/髷p7tra5!GNb#)0`XJƩtzi[o kZdD1`pu:1Hd%?h}"#>v}Z:^m*`fan2isՎ0bOlVCmκ2Bʼno}T尫9s,|鱾xLI[U *_#'d׃8F7_'NЇf4MT"m^^+*8R(ˤfx{:UK 2=hUQfuF%RKfY8*7AkN\_Y}g,A._WIb0m9u%Ly͟dȄc@lN`0 C=- t+̞avcv_QFCU= *V|-2{ ZIr6FcT|heuXqSr1l 2V,chh$8My{.a${'4G I=w*HY%Bʑi=}s~4T{hħ3|a`|\@G-]Q{" n XT-Y X

D6ycShVoD ~Q~RF` fl .f3.!GT#*^@xa2Y3)t)K03A:vvޚpߜUdnp9NӂD[VPV,ȯ'`<+^Tʌ̲Kힼ-WUK)u9;CՏ ;Vf4(0]ТbW0X#8@$ C9,91?δh #=[ S YjwlCdIn 9`&< }!.׍O;:ޛKw Ʌ -R.` :)vp iYFk~0P:>iIˉ+бPh*sIHu:ϕ=D+O̎~]C(/?ClY?wROFTgd.J} XCK!]FHq0;QyҒf%6T<'{U 4 |5Ƶv# yദ$tR- hm`wac#WSF"9؎H'6ez3w&MQ&jd\GTTg?^8Ù|OrIcBsv4nVQxs9 1 MHz]K1 M] 5EIH9Џ EN$V(~jiFwܾ"3W:f:ѩ `cmeJԐx  \D;L6U155? #\?ќ 'ʇ]\i]G"u}$tڅ<Zi6n3e HӅub= )Qsf֡BQWHͦa A"Wa 8ju{+nn3*b{ CzECi FXwLˏsey-;Tm`+,&Jkх.@òԮ _[:fG1Q(+H>笫>wO:fm` /ZLՆzR[rx|om:ǃt0f^ŖXiSck&1Adiv8ޢb=;e乜2l5wҩ"D .#UU6ͥʥ񂿼T]uM8=09iߔhL.`U qH7xJ!J|ax>a&s}Xܺr#}aLYn7^ɊbaEuwÇJKz+Өҕ3N_jڰ{hSVθr2˄8Nafio+m.4XpdSm@QU6ވRiwCBY5X (H^ؼ20mq 5е.GD]_,[Agp]x'{E-D>l< s0M&]I?iSGT~j ҆-+耿qvCZ si<IfO/-0$W(SAU֙!4B w+ZOw䅀@5F"̝|~񆇤 f|_帘NAu(i lnX.[ŒDDH߈ZcN漍RGTUQcA١"iA )MwNwzc:6?Bke͈ QmPc%bPؙX|{.C{dS*pvL`^-N?_#9i+H8`]l$ DŘ s{|[kxٛ#ULV&Whw=0LKߝƪnPQ}{Z@{jp"J1֭3U*T ݞC㌪@Jw&٪iT2$51Ude;)1l 4.JvlduQA6i+EMQ(5 Un8osiQ-C61ZbdWl V Ll$娚1KeᰂӺdlNADЎaSi_ bI4`12ϳRDRѿL.s, N=Po!J4l;AaEL5¶zNƠS-o5%J?b\ VlRa^©?Ӣ6,a+!#0Xc,Zmʬi EF!!p)IJXå3>(lyfVWhU6~[lcgp-)2Ea5E.YZ+Y3Aޙ4tQe);Is5Mz 6WB湅9I^Cܵ~G;b\żp"~oKO1 ĤY0>p!%h0$\gB,wY(XBN:H螵[M8ӴvpIkm1 'R^'),nbQ\Eg/?cA%CNrvH`i| wbhs|u@6n1z=U#|E;ďOrɄa͑ԑõYUJ}LU~n׾__I˻qbġϪ9l P|q_ֲw}*;t!ܣi4O@L$ Eg^ڬLgъw[SSDI'ZeqCsF5$]De(V aӜDyWH#ކH eJM\6W*dee|`Rb9jbG,=; A ^KN 2Ax0N*6DyVb &Ll]mfV#unm.)btOl\02y/|//H9t`4^y)vc8TP’}8DV&na;(NI(^f `Q8Q)v(vɅh G d|c((+OĚ ofkrP d$om$?S)g>_I:d&Rx D Kζfy;"%`m? .Mo S ΁)cMqmyvJTf1^a/s@(xZܧ#_L[+PKz܋n7oTn{qLo5CR>_y:2`3g~垆/TѨK8Z%BR5_xp98I[>BVO{Z~,K) {2sKȰ`o‰%%Tjɵ*V@r@ 1+O.ӥגQ|+8VzTU`Pݑ Ky1R:?J{;bk+I6O9f3HNY. Yc3`,axA7H[ X VJBhq* Egά' i!ѢEir/DZ("I*%J!DBڴ~s*]w}ki=[~f˒ YU-]B@cvE5weun J)}PYmQŮWԧVfho/VV˰.UbڝQb3HŊG[RK$ފ:w$͙.%%vA^o>Y[\l[5v16}jX~)OkT8pVu,:9f܉R`U^\Fb֙kĒa;2|T'o=K D S^]K_Rc'+j֢]OҞaGnX;۬{nfB ;ZQIPVbgӕk_H]Z5-gۢv@t\޷U5hxj~u3+^8M7{k=9Iŭ:ZQ-+̳[}ިg5u.ΕڲZoХ4 >WPԙ-mK:M/kj<5=/)lZsFبHŻu c?nU,m5Z@݊.>ovBH:|or /IL@~5׼-+inS=hxwd*<Nez=r.07,ySA_tļ%Ck2_!1-UhfhnڢЗew}zM|[9вk |AmMoգ@dHj<}_"?8p-2aҢz5uSߒGMB㙊Cżb|4Zi"#.lƏͻi [C}6(:Grf kS6Mћ ?k 'Y}RصZj+-B?+xA |Η:}5ƞwR+Lەre3cir9SA3p׿)?],bhKr#|ރqUϵdtؑWF$q҅Cq[ =Tʦr,?L=Koi*N4W;tOASs>6(8]'ұ\h8ʕ{g^ ܐaO˦֊@;0` tWW1؊+H&>ro=}eg.X:aOttҽ+ZU 쁃e*y$gtؽ癳>J:2Df2=GOrxk(-~r*"+Az euyft|hU~.3}lm4l+)# =ko;B[S<bjd~8@I/LK??ֲY}ڣ 59Z}eYu^Йx..sPU_`^nhX$e_\ѼTw&e/tn[גżr7tH o}6oamv.f֋vm /Z$ëԒ:K6%8|][hn8V{)oufze\[Gl(oYG_oN/oHK,x)iJP؆߄rx/LPV,fQӡ3ݾ? ؘw0z`GSyNi]~w+m+4G *o8;Ͻk9\ߖbv595PVRd$,q#)^;=[(Y\~a1kknL+`S GY]JOp쬒 p<~sNIoڡ[ƚR+Z& =Kcv,vo+2}쪔ܖ 9%lSA[PΜo[%}x3OZ 6myU#У=|nHy{rЧĒ >=i_g |S_k4lNW[b5!5irowng@->Z}XbGrB>qcn? Q6޶e3-ZHNꛏcO 7W?Vl M91aʡ1fYiOG>&OA393 ԺNSf}Y0znٕ¾D8VmZțES IaW4q;`{R5π͙;KV/k ںّoE9,{Jz_oC%NI5;_ocskWWDl0м+t՜q -nZ椇oY KKIoߟ5` m೮{QfV<:MMlZ%S^~N}nʁ#l8 ᮀ~!Y^7uNk N+д)ڤcWK}xKQPNݱ{2æN7 )m:g𷝎 tW'Ts\ӽ\VE5lݓ J'+xlzSOO51Y8t+Sco\4V{t]Q'Vd NPjguDnkk{>)XiU^2M Ko۲pxOи.wpJa}-O壟 o뷋'Tes=sم.HшDg8=^\ >fS]sه|m"_?<׏i+n( -}o^o}[[LTzdrpbթ.,t%.WL4%<1OmdtȮ+_;]i`^;ob1vKĊ*wKxxe$c_F)C.*S \r`ò3.S8d%rI6s|AMbWĝ[ݱ<0= @ScGX[$%#W;ך~mX&xPawx/*? $i ~[6wu|PpfbLeg~)?ӝjyE]㓣?*F3;6]WlH'R_^r#TmEbzFU)ԩJGu ly+I7؊fI{YY}6My /<*%udqҙqy|d=#}u+tGON2XR|"ClE㋱U%S^Qppztgw奴+yh(oӃIZoO>vs#82ۂ<{ J}CK|[]|S][OxوtHSꎋ XVZ:y::>7v-hy{b%"TDA|A̸!._|pqwhIm`1)-KG8vD8gޒm[+%%-$F{ҫϋSDU([,gnCVʐy)j=9rm|>(\)}EhCoЖ%SՍI3[BB^Q(]Hh%ꟹ%q6 r2kz^{>6I6lΙiiP[goa 7¦w5Z_zYO[ 3R^yrmC5W_씋PSYv꺟1IC]`! )Q ,17SbEY);he{;O9Ufдo'ؼ[ӳj}C>mtJƩ:Mv \l<,K_]i# ?))h .lU]FŶY:w خnT\ln9YzАTT\h;ibt0@hfFٖN\lX4(Ú^sFKM,{[qF,gCFwhu{KŖmG0`>ʲva8NWYeK-6Ϸ>R7vX|EV 9U=u]`W&P5l^sivK_߫-N,wtP3$/b`&ŶjÌ_K\,EJu];"0ab셾ԾՁ{;7]+yl;\3*tچupG$fm ̪6J܋-x6"jba༖g_Z;Ҵ{՚3t+sfl|bfx[}~u!6*v3<9tFx_~1 Ʀ=^JC tt+Liğ?(I6R2,|kB`ac (-  |j%kݱP"{oa'euTG;H_ GdOK7{Dac|jW\e;TtcO P/\;Og'Ť/UܿQa&:B%ὦ|I2>BZ& [[˧#^\vӚoy=3^en50Iiji{^qHȪ)k|jUEJc{k"An4N|ɨ8(umN+<\`/ Y87.BeSxr-sZVڢ2hM9q>6-2ةk1k^DuHI|b0.mZdӯ +z~({_ŰrZ|q]VL u观U 1Eb@c[҃ű.}W>*z݃:iY]3`x1ay*G]4 }0RʀcV Ġ!tFLƬ~ XqrNFƬ0\\!~Ƙ4EiI ecEGi BCa e   @4o@5/G D#g_0| g9z gIk?ǘ _bM0t :L3jtI(!8\F؊!8̟[$6bǁJޙ1N\pwhyTQX8qcFE5Hl5_q~9gw'oOw po}}`Bc_ Cx;X8sBz;뷂:gK[ƱfN#1ȕmǺtlV`"ptfyFl-G7ACqF}' % ^P!^P-/(w`R{A)AW݀`r e70j7[npY@ j\P岆2&(E\VQprYE (e)pYEAj"\VQU(e)pYE (e&(U\VQxrYE (e)rYEaj\VQ(U(eE)rYE (eE&(U\VQtrYE (eE)qYEQjb\VQU(eŨ)qYE (e&(N@Q.(srYEP*ʤ(*ʤ(* Щ9%:5I\QNR&O@S.+)@\R~4K&&_2M .AaeϠ[m8п%bS`R`$cE0E0E0E0E0E0E0EEEEEEEEEEE(E(E(E(E(E(E(E(E(E(EEEEEEEEEEEL8q0)`RI"&ELrȞ'.0J]FKopMFw%)%u5uu:Ft7A0󝎍5K?p DmA5c^?F\wuQdhUqKoleWrgt?CC`i8_Rq8 $`0?1'̚?1xD91 $bE@/0^pa$;a}1{ 1:H@bN1}& cbL#1QDcF|1KPblL|+@H<I`Lb81NA1"ZFCa" Hƈ9H $īIb 12cQrl8F"w9J=0ǀ!  b`tV"6?EaR8EU/ȤxQDCaN10H78pVAIvbDcⳐhgBH1r[ $3 q B#3&qs0:Q8Qg%c 1Q&@00/ B\8QKp!Ո@dcç 8p $"?a2Hct&cD1 FWl3J# ĹPLGI1ZL 2k2F_p "Ɔ0F*@ !iǎT_"au CH! g|C.C /9k g'br0 !b@q|q39 >VFq0"p "G BD^!c}"1<`LҸxL~@"a !=y &QA ?v r@9W&ۡD 75/$lG]#i61!_j0Hė_1T@``zp#a \"F :rNH:c%az[ z0IcAlyIĘ}N\8_DL#BX31I0~}c[;GGl?S CՕM}1vnW#'lKwCg Ȩi  `8E#ՏOtrousers-0.3.15/.git/objects/pack/pack-85a01a5aa27fa78dc339f8f50c9d298ba6474b85.idx0000444000175000017510000130713013663651711025265 0ustar deboradeboratOc=q*Z,iKwH%[<o*_ I} ' X 3 o % X  < e & V  GwTM|@qG}J<l$Y8g)T;g4n<iCoAq@j3c.a B o !!;!d!!"";"f""# #6#a###$0$l$$$%%C%x%%&&C&|&&&'1'Z'''((C(x(()")X)))**Z****+2+g+++,3,[,,,--O---..0.e.../7/n//0 0P00011D1t112222t2{X9L\,E  Oe C >#xU/]a#DD,`M 즳ja٘d 4ZHӹe %S77t,0MG]K` HI;<0>g*ց@5_56X60pHϽo%V%L tKs m*cpEεl̻)˗ų6@_lV{t90LrkD#_N^/96cW3~nyb9$yY7199WS8(dY36R{]^X# RAIĈʼb6|a&f1f/[3 RYAIp㾉A<q`dta'C3qHԷ{Zڢ)AmN(V&0cړݼϮE|@]QUw.z$C7cG7}W: hvZ d4 $疏` XI2pvy#И+g}WN|2&!Lno8OØ ʡ 52B$۰\ŗ&vM١kMDM-)^{ŋ< L&^"eFU2Qtmw_c)NJ{"xrzIQf1-x(VM8He/UlVY/Az 邚 g\`=2Kl19%`)|if!U Pca`s&B4 YWir1q}=Hmz@Zv*<`$r'Fe0j3Du[nUhpKv_B!T(#x(-YMv{dd"Stb&2^d,22it;q+ĩ@Z7|)hp9`*?Vː:Q"[s,/UBJ=CDƾ05'4>^uN" CxXS}+M(9VBkqiwt}CeLK`SQ?w{@t&IP)ZL~QimݕmL喛|﬙G#U?@i( &.nrN8 AYu}m_2f3;B@EP"O ~Ӣ_tp B #&Ƨ[*c"C#=c#UisFsmڰtmɧm#'&۟AU@GbЧ9};I uGЊgx";'ݍ0O4"v|՜Rp# utPEa-ߙeiP8 ܀ZHdڇ<=˚߀m@7dv.+J!G3Kr 6Qc5r *yP*wANKn-*r}iB|y6 i_=n9ACfL' ߪufzVKdugeNfLFP N%$CoJ5 ffN.Zv 2 8UlZ]Q8|WЃ5j{Pl|]Y\׍ KCήE^]/?7BO$cGld @b2kYs*հt\Ɏ( uptDeꮗFuHg&' \FuE EY.ϽtZH `pDQF5rvvTÀyb[:G7v%=U0su!f.FÝ@<4\鼑hZz?\|\ HU)M#S>1w;Zi}+TΫaTx<(dB./pͯbMD̆&F>,1$'˖Bc}f63}Un5(tqĎqܚJ57v4*7w?τBbłXlΡƘQc-ڠptc }k>T coiHL";Y; O,~w@bk@å)x6ϛk&0#&&kCc.do.){^>c' n! LLT1d7/FkBG^1e!7*BτhY=像*n'FDW4`vdHG_ IU C;!JgRX؎,($Tf:uVC5)gM{ۼȱlV-nЉS\Ì5/w =+:玳89F2BWxg clٟڝ~Hi@E!K qZu&XOn3hms#RQrC\{'):hUPK1%{MVM{iw&~>".h#X\CUlsh_  6k P&zi4D|ZCB=ڼo%x"ypyZ}aMK5B6QШ0-09el W6\\qFO^7A)Npca $fDE<5֗ը_ȃn~*BpxTx ~%*B:dw_.8Q"LO $e=o,L^~GYd45ⓧEl&߶)}(؈cfU-#~̳=8|%;Nغ -yS A%?ԛׅs ȣϔ^ <"pG; E!&Dg*>FVPEOU&EWπ?ID7~ϵ?OٻH/u?D ߪPEFd !vf6j4a u+6 wIS]K=q>͡8M-^Z_gI&$O2$BR qi s >ݒSSq1uɑOx$ƳjT]=6eءP@٘WwGA2}_HbY\633@کB|s K0-8Lo2msg_/4 ߮}^ԢpT8( g풝& q=!:;sUC\9-EX/%R JH 3kI꟎?W=8\OT hdY%M$>44]Y‹^xF}v\bhe&e<n'lC^M}v>{I8qled[Ԁc{ĶxuC|FkCeiKFw'\2='H'S`,S7MsܦlE]Yfy2N(DxzZq&aoUbcC<0oeGd2TGeYS='r Q5qZ9__^ů*o$J)2d:^:EGD^? F AoBz2!d эLx&BvQwzxuB^pP7UuuӏeC 2Ia$[/6+(#_ cބe= 45^nr}5z򱈗sI} l4k_+\H" Y(wc~$I3t۹BVzygtf9@TdjX9=PRZPݞ`;4ލw ~&.!=lD 棙[atm]AGG}n%}aZP\Ll;˨q-p0|ݻ=Z,#cO7::_~~5"r8F nnܵAIp m`}A2џ]@Pɻ[T2ܥYǍH !4,oQU 9fF%UJ%ǘR-B 3`fלVZF_/O1$cePKt|F!]/N%CQqc6x @@PIw#Z*oaᴦ_i]|FDə~Op"9@3Zreyy5q 9caANs2*X KAqYTN$KHc. Կowӹ=lTɧCd% /zkC#D<5S~A jV0TK5EO:$CջuQ}a )~+A> z8q$ g]n@W:.,C;\fM=c@8tE>5^QM5Bm}_'GZGuOO>"S0ENT&/$O d\^U磻 |7_yє _Xo<5cKa7OdӕCIuga1i/.fh voN#fz^qc5y┭r S%Q]1ֹ@u)dd$뿭^0aQ+z9oLď =ζG] Bs|~ޝ )~u2}oHFQ) %VBI8`ΕO@c+x&pCdoQu KmH2GOhE 0 "k7":g_@ QgPQ2kJ?JH0beVs㊧ި֔8(2|e,%N@KF>L%jмs7%W_æk4@ Xarڥ-X{[APj3ޯ?Udofb0\D3!Ve_oC  lKhQ(ԁS^^mk& $e~EAp)&q$WkXij}}ZA`TRy{m$$/fa7>[J0 ɡ 5565FnwώjF ^(Gۯ"13kh~9Qep$[ ڇ?\!^Aum4>#Ooe|z]"@7Xg]8 %HyL3ܹ'ɸl (4 `'gdv{  k:1ü) MC|Mc Ґ"3MPƻ~cF۫D`̦jp#bEI^ d 0f #S|~׈>0,vqN'SE[f{,>8>AkPN>Ӯ9E ?H/)'mzCd$X<5(KCӝuJўIy|Uސ IH?'G55:M0P+Be1 A_Lrٞmk*g= cx@#אhLVn4gK6Mt%᩻Q4LF%yu7:Su)әu d@Us`0vu$mBر~8﹔S]7S}t=X \B顫&ՙS.yjyإ!SiDc1{nަ@XSXHj) ۉ4NxI? K/Fo`xDf:=hN Q|١d@jɾ=o޿ZoF;8s?{~_ĺA${Xf,#`s∶0O;(=+ozm4u;${yqԁՁ8AKk?5jAAև9W>W{K.RNם.~:U6AsN =Xě'ݪ(mMPʭ=U@YM y~5`޸FuҠTJ_Vel'l AYpL> 7$H B.[Sz DUp>E*-VOt Dګ5\[ Ie_t5x&]Ctl) Lb.J7sϚvf Rg?ݻXD% RcOJ};!#v g5v _3BZecYj `$w3zY@փSME iCVH$Jw uܠL(&(nvՉ yn11k~M 7;G,n x|4] | wB -{CL Ʊ=jLࠣS{ig K 3-g  gv2O.s ~{UesO r?}~}f[yJ g&ҎvZwHۈ ecҋ60kA}g D X$x5 ȥJ[ڴ= 33F1fY A2ӀOCOu: ߟX.>9vQ l \WS |NjK05 >VI K}钫p 뢫S\6EY =IFc5/" +P)_xڠع 0e%. P9߹I ($*}c}+s Oo.nءBY,f o%3BW^FX gzx/XJ/ R>?7P9 <@O3:G E9=MrUݮH Y=h{_bNIXRH #E $Sۺ,I3 $L %T ,i68 o{HPv[Bέ ~hzNIp[T L2WDr΂fF% Ez7;Fde[bMC^B} _G“˽z: ܍E* ;(m8*<dD >D=R~^h^jXk@ Ah9H![%: Ci?>kZ a>(3 a?Xf||kZ~ cK&^ks:33YB2 liiFD;a' q Vf q }\`FCY k.9)YقE~5L ( \*vŕ I/B0f:[:or C0 I;b! /}y'WF'U [oTEB< ^N~U 昗r ԔAbwN4 vua[ l-:ZF 4ġngx i.c+% dzܕ>; Ggʞ{؋n[ tG6BnNf8Ny H:x0 Ђ eh۱QssSm M~`w+w'. ey2:h{" ԣ0K@c Z"O_ <  @ 7!J/ וL ^@_ɖ>. nObXڌI\B CVUpNB?9H (ec5e ZUh|05*.F6 ]oj4˵;)[  *a9DD݀ % [d5,tF ,$dSkmpJ,Nst+ , d+`.xjQ 2` +fT6Jzr> >S [ 26!B=p5 h{n[" ;T FS\ 1q _ ~,h&W<@ X6R ъ@Tė8 ۥQ: m`py a :!qݚuwjv 0 Qb ;K|1 ZpI//lN Cps-!+g\ ˗G3g{^ *q]=Ж$FU YUIN,Z GC:(4 [zy t&'-4 уDIMk>`MK P ܾ@.ƀN27+? QHW]f5P8=_ [<e {KPؙ턴/] 'mƀ.5Ңy L^zGV;;o  qLS8ՌL𨒇DV svCܢvXhҧކ0 l']_^S[jԁnV ]rBokd[ !@4'T 6 ԞYv-믔  x7Ep=q Idea/nd 1J]aM RFO&w -_dS6 #Q6ok u>h { -1fO>ܸC_ ؔ4 0вS8 x\Tx 53{Wf?8 Z F 8>UO&fP(Y 9ˍ fm8 C)Xvyj:UB Ndǐ |u\pׄ P']BieSsE{Zn T4.3U ;ᖃ U`k =;k#o [05 3`(G&ޯ e}LOylҵbv d v!i*^CZF'* :hx{bzn1/` Ǫq<\GW= n PW ù%V%v lw^xKQ S;TmzoSp[ M/(˼";5k !nW:a ӒI% ҖX9KG:(Me 7ޖG# umF_&# 5Q$;ۼi h}^vn W sN/yvףҁy.刨[qR1USf|{sR*\tҴ&hC|GFxbtI[;= ~i)Hofы8,:!5 Dd/Hl W#7ltLFՁ+R^{M X 3]dpl$k.\¹~KFKR4A ~Yb6wޱʼzb0JаN +jY26"$VćIr|"ٰހq\nYs cmU% ]12<I@[hxqEJӫSg1 hoNJb靖 t1\d \^e"־t3jk ,a&XRdz^^IPw05Z$B9Ïno<S}o Y*V@G43wG@<Meȷ߾* Nioqi9+J(O种GgPyko7T ^ۡoJ⏎^5QU)6c#]]zmpYH+e(7 [ZP/׏]1źݭ5'pbM!d 9@>#mf7E=Xݕ0F#o0^e,摇 ՅyKɱ'ku I|4 W[_|.XD_u1+ ?ݝ|7Ōzӧ \ T avgS> kQMZy/X:|stV1bC0 :}*Ntƚ>B& )Qu$Y-7b8'AR(l!{(nҎғ%j<@ isRןzmkl"RHm2S?oe~3aptl%*;jci|;pڔ̱:!v׈ ká}YC:q4a ËU%ݑ2{HA kh 0\a M@ģg)uRǍD][Dvԯi0̧*cM]z`+2IFz#7oK.Rj6\oOK ZFs-91aׂYx}RւwUXKef㣍hLX3f"w9衄 G0Ix2?4=8VDMU.-?sBu"~=C}DEF(ʏE8ÔgPh;9yn@[R(^xi!YL[6g*a O^\EY64;R_D|,ǩ# %{`#sglzJ,Jy;i4u+ZN3w^=.?O/,uw^{RD~^n j[1n|LӇ3:w4*~_w5*o_z||WAqJN+1 o,pRc]bmW"D^$AgZ8gy`*>)t嶎\`dă~h v~ ) p}M (4f={m] w~i n6P!h w /5TJB v1S8 E'Xu';@`9,6c.~iF-)IGƿ*1 hRC&-f6Atw7f,j8`VgX:.w[O`Y=.׶i5/\7 T@?U~>NU H-æ8i6zJ{ :Jѥqg eKl_k0g8žU'vt.M~'\)5VYCSQ=IoPd|@4[X4Da sZخ]0f'%LրJo#\`hIW;r# Cu$XZo nWӞo}:% (FNfˍ 7S%b7qGJ n/+iIH(ivj_YY[Nv\+pkh#E{$Yrk3x?& 걄IAdvぇgCb^[L3m:ASxBGܲ=*PِKo8l'DI;/H2|aX/:N G>qiET>nP $)&YXbn+seb ç򦸘~mQQdKo̝w9 dsQ\j{p?GJ:EtwnRaWqV*rur)zQ^rעƍf؝G~5r9PwŗD66i~}zKpY 8T$2O3$p WeE:t3TN\w#0u>&0uiV7{TN|k4Vbt(m'`Tp#pmInoCtZ~ d/+ywt2=zweH<\IlE%"e>jNqٻg/oBdVSriҬLBn_W{ּum=/YmC O\o9W .類U),7a/'>l۹{} ĵ)$=Ӷ1h?3pJ{?\}]QB_w<;'sbǏi0*2X*>gb2n< ~ԩ&gm[ I <%hJbV~ٖN^+Y!u.9<|E%q)/}k1/pMo,ֶ3nt{Ts'Cc!JSc:N Oa9&f uYEoФfs.J7' ;ΠNz2ܯP͵uR5Ҹi*ԧ8bOW>\AB>37R]g,E$)]H磸; G5FO<+8׶c11FKU#:ww7E,Lم/O(DmHL7yfAt_5*6D!IM?V!FGZ{B'HN*( \G 0V@P)l աh XB.bwyuqwiF=xS.hͥFkn܁u8Ƞkd}+xIE ȗ]OqLƑ խ;L {\[u_d~#B N9gQ~JsoE 4)" WwIdڝ ]jJ#Eh&\,+z{$[mFn^2 ޶wJ7m:* nG0V&bRzd\kJwS`9[KXqkH:[ XDF nL6L3|3V=etlj].VO_ѧGn$_sf"(!Co6ٌ|^.o}5Rj EbAYF_E E?F4}/<Veٯ5a}^#~IA 0Reǿey30]I#%5a.+U[gd46!IɊr*ְPߤP: (= Ȇ`NRN_lʥ1>39~07yrM(W>" VK>;43QՄ(c lUEcĮ$zS_H'pQ8Eή& ) oxlz:  1O rST\1♙ڝA@I}OQO )K!coվq'yY".F~ $@Nc\P2ʯ"`?2V5+08DS+Z6kJ{QҖ;C~M_/hQ1lҹ *K ~Q0Rn /i ~xF{}ṁVm1߯S9!Sf`"X.Ɋ4GGi+l!9xϧj'9WPrn,`yB_/ݰ;w6>P~oB տd;Lh\9 x36tP*DMt[&Y95,&Ь1($ dž9O&$*w‚jI>L(%M@/=``,^l ..M]rs َ83᧛i* ns (}:e]}09QbP÷|pJC`0 5eD18YTVL)QuDuZdfc Ga1T6+FQSG֧t>2dqc 4jqf;6 9gm(p_zNz߲m;tp5?lhqx&=PEl-x! xz< 4'q^Y$u4E %ϔ4<-ee @ˁIFܦzP`y):[}R@l&QiьYL4L_e=s F*;hp#cNǰaWE|Â/e`8Z5{BָUTȽn8C+~Im' \.fmg/LK }}q{oմ4>lY~P aҐ܋%?NR;@YXdN~ܪ3n:ƜnS|6j0FI?M`twNj-.[*-Dɐ>A0J9'܁p'>9=u OmP J$zߛҏϣ%e:ٟTMZBĽ ȫBk֏<`XU,VM٤at?Оn8ǔ++.ҚQ1[8Au7H(6ާۍhch B6KqxbqBѰ-WVD}kS] ?V,Zp~KhgVo\ݿ:C{""7L۫`S"!+9@zR-w,+ HD^tz /%#~#څr]13>vJ_b x<ɾnA@2xsr+#UDjS [ y Q3F6QD,i%j$P"gPHy!ذU` 0}"He|#u^XjwW@t0YWn RW@= f]Z|yC |"^$["XIe\#@M'Q}'>QHb.|JrTXzPjzCLoѐdNr83t39@]5 +p Vf P&@ڹã'v5p|h>InQ0..Fl$+?9=ݢI =8Ų>ž31Sgo"w*s[gmV5n)ʚ8YiU7 K)0y!&p^wjϵt4l9s_E5z'\תjk^$Ecޟq ΀_d/@P N <@3UQӹ,-[QY1 NllW#ot=8˂>i cqˁàkV dXj3M.$jWx?>눲eu7 .Pbrn֟B}ݩ/G+U8P` D 8f*+~{ GΡM m 4=X.ӾUQ 3ڍVamSb#}~=vaeT"UzbO h˳&*>x3~;Dd70)]HUWO2gGPb;oo? ߽0Ib7-]C߯Q*/ 0GiD/CԢfGr^nJX;{R.>31Rhw^]Ÿ\-"Ld<`E+AeE5}#{lfkJP@Mr139k}-ߢ>|ysnzC,ܬmCg ap->H֑&uj)aiŌwHvĨ`MmO3zF:)HzΊ)*kͣ;wXKp L{qq~)~b~NmF_Rg&mcR&(%\~Gbn7wq.I?|VEYN\$B c?1p0ۃmJ$ƩO &{}ȢdN#)vExoٸ98~Gn#3}.ёB?\<EP/*)QH*&㠕 Uolr2O0a"M92wԑ!M?Y5kͼE{Rl>b0se,cXY-}H犘e++$ ]^eL@JlVX{ŋm"7}<)LltT}`!)+h^ -Szu:|sY C ڰR.3`~>a 9!ճ[4kVN*MƽDO6&\Rb2l_7UXp'1z*|k UW 6;6AYI`XRx8 t_2? rIJ,8o5S_0þ8R}mMwni]%Q7e:f0d^v>, >a~Xyشc_ҁqo tc` |nC|j?4 R=?VfXۯ[{Lf( =KuQC%KLrȻɨ 7 %60GmZ/{:Uj{s2ˀCOnLIb[ nHn;u3!7d4f+.:cNAUB4i&?+M"Z&UsDr:p֖=B 5ұڨTjR1h/fέ* \w3b`F%GFqP@I\*r<+8UU Pq۹s$;:`V_69czZߊ"@O77U:jV ;dfʋM7^j>J󩝣PNړ @2ظwU=ad M+7uTdQ0pL:f fN?ʖdɷoᏔ˓nF1hqAmk*nU4Bt hu(u"LՅxZz$7͈'5pI|ԀAF؃A~N_[eJ~(QpieMJwP+ Q8 hD S\۔ԗ9Rօ+iͰE{ mxES.u@9I$Zwpmql뜄jsVJ8LBg`4g@7h0$r?l賊=dO8X-< Ya||3` Q{=̪ P//Iϰ"F|9l ÂEqYExA JH-/d=:(YROАaF[lt1rev _(`mCsy;co0Wte6^Zq8(g -T#G?䇚A9׻dP7DC$T5|$o_,Zǁ9zy[W qڊF{S.JCFNNiai7{t1&i$n.9N{dN䞷?<>Tav]V>\aȷ{Z`S^`~dm^d~w\ޖNCZRa_z,9Y9#=B Eۿ)h\pVt17bhِN,:Zrc7 ䷓k1HO$< Pu%e>JA'dH]PC}lllRpML~8ccK9'wR[$y= XcVj+.l]]*0{esE<^|ŐZ)6'r_et( бiT}NNd_o\Af@C`zeTϿɋemD+f|"v>d2e}^]% %y']h{3Yg(./mƗ #łUBq^ds;0rԞ -L-5;+ŧNz=bjڠ#>uT,Brﵣbsk eՐ tٸ6]%N'q{Aq| ʯ4Bs`ÀуY0=QEkI( t</5l6*UsvT1wAE ;IՂ3ž<k*&cHX϶< IZ)Vן[>. l{0aEѶ6tCCoUYSjb&?c)88 )əP Md>!MnI950ȴcINHYMogygC5{Q!1qjtN>U9*O&kfPv/Ax4 j|B,3NU* իJ?Uc(#9&I_  Hӱ(7FYNz3nq n9^JL$g<~q!ٕt|Hh1>P{b]Y]{7T?@F_ud\7*BZ4"1lOtBFcJ[,.RqCMM@[tRC%)xjE!747E ʼXܫ=z+LH55y-|L%Orr$\LTz]siH~3tTee)L8c8}]#h(CVPhF5<]afBĪp<^o"UlZL'ߩp_l c!C"ame\HL۾`ڷɶaa Q/iΗc]qt "%NsXq9={?KYH0r{Ƚ=w8>,1~ФH<pP^ "S59+b1ΪUMq .gsC<lׄ*I Sϔ)$h" VT1, H!2<أX0 w]_9J$V C5w}cUL^=udQ*7 % ͒@ jtl7Ydom̡+۞@ⱟ:k@+x7&Z{6gZVmH >]`}bE%<XM=$A"$7Ф y `fkwP!;f=QᾊnS rTYfJ\VܙP5z_LKPrtjr ifA9c@D#?O&ꘃ9q ʏ&cI9џwʃAt'_˛n8ف3=sAVVV)1K[ܼsׄã=(0Q5se9ڈ,} ]uwAC:]2u'7͉q :E|ʍ < VZ8qVh"P`Df}Hn޴ ^/rb,{ ئ Ao 2WdḴ;c} P2v]WF ,}oHm2gX.ͨa5a}MG8l!<N(4H5EX%0ciX eGѶXJ@ڃg H$1H3T!Y- K#%̀('(T' "A@W?7 82Z$X]r{6`xB$X\\Ut\z౲,^o% *GRcd#w9oq} "m] ]{pxI7!9`F/{SP)Km2}bJǁ6vADOii]M?QZMi&x-4§E\9>uh)Ku-@ԫo=vj׃o ,C[t0>jr E ՟n6c/rSހR~J"  Q Z$8T2Q:7c}DR?К;HTq&¼w2dQ8+},Ŧ~$}qEGaґxxrsfٓIG9 D[DNkF=Fu4]a1?d‡9A@V΁6bQ;Jg}J#19L\ 8 P(\Tj%+ՅNC"p"ZRgLg'a[Z &BIrӐs% &F:W#갏&6M<`%qG;Q| T[?ؓu}@~~D%KƬ@صGPk 0@*OUcEP@]fj4|h>Nsg5w$+spH![M ͟@џil$j W8H.*<' @Av-hv;QvqDIV2~:IӢ}5<ߚAEp{IbF!СED^ΎɄ #pВ]|~Epp#^xBȃ?xYxy 2Z?0j r_P*n3Ē# omK  ,㋎B;xWiD ̟[- "܍>ZCoXb22m^ȏ?"V;#L%v>/,+5/3Y h, d[2hҖl<_cv^cksaB,>N}H&,رKYk\E]PSI5R| e !TP դQsjP\=(>e9m՞2n"Oafwp*0-xi[r_xܔ7qEtAS=L[E. 2~6/BuoB-+ڨ妜W w 2B&”(1Xq.wROCHx=}C֞S{jŰ? (f9sy`745@+J5)Lo?#]zZFzjsx ^u^:NOaI/fq#aGa;-gdqAjبYvraby tSb;9cJIQ~hdZb r6DAM ԌzPp4'9k8 /7=$*hz$x^a=Xh|;M+/00 dTcHC=L%wʦ/6+oM=-6`sWM2^ǽuB uذX`*͂9<;0Mgxȯ\\%+Ng3j$ow-Rw\bWqo$3^MCg7w~fjb.$lc~E +˃{  g w#޿c [)1d%<_? {3 !e ̮J;*߮G PuZBWJw:z* [#l8B@6s, p_IB0 }/5o2 !:ϣ $L7T0'(S %S9x ~s %dp*j@PP| &TSt?OЉ, +,:Fm-%J %%4 2U^j^hK9A 9^ж0]~ =jvb>C> IdS! M"Am[n KߩWmgDHA L犲r| XU*H-W N[ii(gCݽ `v94gQ `j-Xo/} lX:r ୿ybӿ oCÁqBhb r{ ' `(z +X2mbZk *~WuN&4 x+LK( դf(K {XOmouⴅq W_E KF}ji]o $lTXd3- ȟ! 58ګ <|KiʯħGCmnB :Kqa:JȋV la AMهDol dT."əfu 煒^\D6޳ abZ'Z:= 1ؓX*fo4 ɿNA3 'o z+NWܙ V/#-J G,yV a 4!"%pr^Yc!2pǟU1?!>Q@(͛!u g==Z4"!Ũ#,Y^|'!"%xuZr³!$r%EY[!,ba0ϸHsZx!-"HDA==#Y7{!0+ш%G?:r S!1jRMܼ/J!H>e.!Jg'uT_Zw+|!Ybj˷4MғƋq*!\# c^!^"!dT*ҥq !gr:"Oޜz[֍!iB~\#ʾew!x9*\`$&Ya!~!{HE3sP['9_q!9͗) ߜT9>!)Z. L~! IX7': !~A>#a> [!5Ľ@CvY!b*Xh:mI!['IH;s!ɍ4у$g!ˀ׭ZZb?$ഛ!nA«|ws.D;!CxeC0SS+^ !~Oml Z ڢ !o[+hKT_!/Z~Rm"\!ۂYa.׶tD!ܸhSK[-2_ 6!+ܵY!v|W<j!6sTٛ|W!?iԇZ!&}'/NQ!K0?G !|J B܃!r?ɛ{[:;h_W!PJٲKa;u"vݩ&$ݰz3"sAdzQ''&j"1 /E.wN"v~`qڹ)6.sI"#fH}~}k((y" A#Vر6#" ^3kiċA"+5M7#Ҭ(CS",íԬj=`(?"0x'$$0bbF"6޷ZcΤ#eG"6S+2r8|{"絬bّ"Iۘ{CĤ?)"P!BcR` ul"S#eD1?"W (qe~WqZ"W侷HU0Yi"^ p$L@oT "vI;P 1J"z3}gl'ik`")G‰!"lX ǐU"iQ)8" #o;SH9A>HFe"qܘb8pγa R"[Aˆ\v~C"~J:(Zkm"fBO`u#pj r"pScrjy"kw lG( ,"*UY3bT!"5uu$]K{Yh4"Ѡ;LQ3)U97J"ӡ MaZ&y׶"#J )DCi f";Rq^B؀M"; !N9vzkj"Jmp[gkP"/$}g"` fxTuEj"5擶E~ZAg# 6Xbl`K׬# e%VJQgO#JI1){S&#,8b>14mCֽ#xֺ6 âX$##Zh'3-Ƴ7#$Z Պ/Vnq#%uqcۿ _#HMɄ9}Bҥ'#J|iC2QBI#Tdnj嵢KE]\ #V0g(D$H/[`eϏ9$M\7z¨Y"83P$Zt3dTgf2iY $eV<9UD+s[$gЁ%/:C$ikR$k@'5$r~%uhfpц${f=KM[$1/N &¶]'a$w`t%%$_*M R7ˈ$,270gL*I0X$0k@fbY$SYua:8ր]&$d2ձơ̿IAK$ɲFr}BݟR$\om8ژ`ԡ$UrOv$A#&3x򤕿Jl$,dML^wbp 1|$"ux[-_$/ Yk^Y{Z$ o]. [%f_PYpi.p]%u#-z3 }K%B"bll;qzFr!\%GZea_D;%x✐C ڊ#;3%;N]w(XSِ<%/Vۈ5<ֳQzDž%2q,1)g%5(-=ސ06>=>%68WbTs<ę?%6poM<;턹~u%</.yA3 %GЎ,V(wo%GV=$ ܮ%IFQ!s@ʦq6%M )WO%N&f묮lzq51%PL2ӓ3VRy%RZ{I |e??;%Redn$g%\xK>eUJ [P;%`*LR$E No%e4| ~Llg%o,}Sń-%pܽ{}VAaP%3ajɤ5 H^=%0BOڪx2bd+ ώ,5%\ 4gQR$%eX3ĒL:6%Q~S}t&"1',Z&tnҺ4q5h&:gHYIhS7&zMYmL_}o{2&J%)C0$P&Z{3 iezJ&F+"Q~&&'ڨ` Ǿ&`;Lc2\&?bc=*.9dx[J&]թJ攠6`$&4YJ);}r#LCX'-(H=A2' S'XF[ٍS䬖*}2'_Dȴ'&$'Jz =H/' ]W2W hB a'(>U GJ0&a'-~٠0Z':K`,c肩2O_'=FP[KSJ='ExfoZ3U3'N~fX.= l'Ul QmaFZ`n'V'x~36@D f'[Yݲ*?]y1xԽ׽']4)qZ 'db^82'kW٢/ ,Q:}o|'w/`-e32^YΪ,'} XNwኮZ7T7'X]*'6Z>i'dcE)۾xV*Y0'n+NXjLj'gS M 9e'^lh(mU'0پmeԥr'*lסD~qA&'oT@X'a풜('h2zVi[< [m'oG"9sAfg'Mc*~MO6'2R2:lX}Ku'E&<~gLH[֏$D'5׿>u.f΋'0I Q"8 )ߒѱo'@m}4l0c7f'vlb߆XwO'6NQN-bдs'l\iR Ro'aP "oBz z'N~<7E}glE'j[붲 |$\w'S2iIYFlZI'D>;Osg'Ra,_} 'ֻw-Ifը"'cI)v>Q,L'eaK{nq(hg!D?= t( tI#J%M5Y[( ȅ`p#c(}@n)T9_%:f(! R?4(!N3uW~Btܱ(#c&[0#A#\ڤ (&xm'%3Q('mYW4+(+SrlG;DPRɰ(+4l`r3|w (->Binjw'(0e=%Z~9Kb(22kMqK8Q(8y=0!w(:_u! bb~(;n%:0w[j$D(<e|#GLC:(F6B&d<,U(JYf!Yr]}Jq墨(L.QC,g);+͌(PwO!ᯏ0(U2x Le>(Z8q*NKS0(^j#Ln0_}Ǿ( ~x_ (C4]أÐi;LI(tKв|j^GZAtF(Pid $<^ (&U Vgv}(ڨ(t1t.$)R(bT@N]j x(߼{_,}w"V}q(T2Kuo,x}J(osȨyEazp(0Dd:``uVx#(Z7e99H$"7}(ׇv{rt4(ͩt % /(ST`,|>Bi5(JmR4{=4!h(X ]gFA1(:~4o7L(ê\tDty[5)t@)OBNS5< )DKIruqH)ypX9~_JO)k!!wZMq}WG) Yh>h`QK~{)͎++6_:B.)-+WR j4r)5\<ӉQ M/G))Hy)slzf wx:*CL`_ڕX_h\*D"O{n> }vz*DYO-`'yB-*I @TAu Q iOaWO\*LArZ$XHJ*Xˏg2Ax1wS(*a+W:z;qΐ*dBtH=i``@i#*dMg>GQktc*g~u ѥ)B.1*g_9]_H_*]O*htvOã .*jܡD<&KJI%R*p[%^ &|yeZ*t?},م+v9a*Eqc՘*pÆ&5,a*lIgCfGy*Jl7);do+T3uZ=NKU$Q+rD3מ[ k+&_u\Ts3ݬsP+)Ȣκ̈́>yk+07M'3"CR]f?+1|z\+ZC'd+1fg?B#V"Tc+34xJ?h+45Cj6D|+6*i0ݮc +7"4fu]O=08+8s1 M6+:H{e'js:+<(10"m}>+>Oh& tu U+DqIC}ƑTXem+Jhz6`MA& +SkqyD [mU+V̼cES|'5Lh+^ۂ"[S3YanCj+q CRݏ1n+tR2%ϸiEtlF+yA<em++{~*,=PS$+|ˠBlPju+}8L %pH+4DZ~r+oE/vMm(i\)Զ+F=8j;x)h +Sfہ)mA&$+KhJ\Z/B5U+ڦ m?+_fhKy#-`sD+o+ X(TgCK+XŘ&o Vb$U+qR} Wʙ<+2# :>qJpx+s'\WUD=+5Q9eH6c+Xڗk0 @+x3.E| _+[ uU9 +b1Pw+(Zrģ['#+ChG--_Ǖ+prع?4kl+~(]s{3YQ+ss0χd$ZwS+>@o~T~%V+_酁 ,$N +AȲD,++h5 n>+_@&͋J0#+x*NXrP+> e;lj7TfW++ c6ݚޔnb+.9!UCPAcEe,GmbL>= ,CoU;`\ $ pR ,(ڏ3u3Q ,3V%7PEk,4hks7(i=,5AJOY2v<3`,7r/9p݆P]m,9Yg3ܽ,;<ء1 ,;رsf]Ra!4SON,Amie,IvaRV,IyOY3]b)^,V.Xx=,75-v;,Z f1 w&ju<,`UK-øy],ke_SPA3,t,b* d,],dx ٭]g-UW56,nuC,h{R &>SW(,l:zo 9J(,kByY9<} .M,O^^&-VԿ,EN/IYOPo,%('ts[ 7,X-V`¤;W,zx){DN67,臡wx}DԾ=,K;9@ȟ~FT*,*^kF@jb,~9Ǥۺ Qg2,OK!,cϗUb,?{ n5[;rSo.,e< }z,.TgQ @q,:\u-Ҽwb*ו}^,z͗fGW.{=,%929=* QB ,˽"i Z,-"y5gx!tå,IÏ5ZPV,^>0y壧i,,X3ͫB7&,< `^ a%G,0NOmCaxJ,dՔ&&&6,`gGᎍBGV>glx- K)MӘ'&3 -TO(q:q-@:P~ 7|N냟 -DDn= 0.-Hܨi^o:/3Y(-Qžr:d V-SJ̖OxپI!M2L-U )ͺ3q8b-lls3+ H~U-m: 'Il`-nt~<1zG_-v{ ^CpT ;-vj,e7%bd-zS!}I?O0L-}kë#*<-}{^$]Utݯ-dkXO-p:-/7 uj-ս=&qt-INÀ-қIb.w?C-Zg8lRZCT.ps-#9F04-c_XB(L ~-j@ڥ1^&--z7򙜇D2-\Pa qZb4- LX- iBK-15*)ֵ1j"-4ZbŎ;aϠm-w<(NI1+-9-e[M8EB-=,eJVw[7D-4Uܪ9vn"}-KH5ƴ Ac@)k-ը4#,fz -G=wT-ߖZ*&ݥ}44rv- :##1}T=-聙:vgL{W䍢-BQ0h,k.h.Xx.b~. iW6Irr=R+Q .}o G@?W.~LN4:)u'.#ZV@ws.#M7-$Z|ݟY?\ .'OR܆{14.0zM6Z\wjͽxğ.3MO3+dq=.8}LXIͦ0ݧE.:%n M'9h<.:W~)N :&"6ZQ.3ED.3 v\Cg|.g|feLz.fYA.xZ" p,.8^QR.Um\m,}.8$wvrDZ.bZOG$.*X&{.o4G->/hax.C,F؜~P\"".BM'"+ .!\O<9,la.*\С65^. R{p "D\m.:^Q _&.鬸?4ʼnf2.@=5(1NP0.Fm4Mae1֎.;wI.An q'. +72{K,.=42{݀A+M.PN.}ҳX7*/b 퇋 @tzI/CI~/+ P?dh/9@q&*R / cfK7s8I$/cHNA[P%iEb"/E{vZŁ 4ˆu/S' DN-)U/'ZւD9sj{'g^v/).ARj B"53/+7׃Dd{қT/,K'],G{z!G/1$YBH)S/5!*Kԏ흑ؑ.|/6P_0R9.+/7 XĔҍu`-/Hͬ:)RC/I<`S*@Wo86o/Ks44s/LbmAxxcjg]/Y6"S8mV<*/]9M Gw $;/fbٖkg;g 08V!jR>qX0U8T0Al3߳G-FAR0F?X6Ui߾0NYa@N Ƣ0PU},5CS0V`2D1Qtę0Xo—"<@X|a0`iO36En*{0boua1Ä3-<0fĐ43؄0nV^x /&Tmg#B0wޖ|w3dM 0n[j_+`4Vc`0Kptp%ߚtJ0FOb?0m7]w{e0PQhKjJ؏&g 0V ZI鼐gŮ^0>#K+Pq60jan+`/Lv0qA~y]8dn03Rf 3-ք0kƎ\a &Q0o :l02H+ v0Y027'8xuww0ꍌ[uWWIld0 :HNA O0UGBZGJK;K0bnƑ+g0B߈˫0 {pbbT`.0Nz<էSQ,Gw0+9/"Nz0~sk1|j0F TUxO?߹bRa,1];8^nÖ1aXqB:M8:1:ٯI39I 021GiRgT7S1"tI9:1#VH٥Cz Zo1%jR,Z*ry71+AW;ț;Pj1+UuhB|11hp?Jv13/tǰ{vd1=0zɫE\^YI!1@Oad߿8;31C-|%J1N"~?IM1N'x1Z>Oߔ1SejZ{]uU1VLoXD8ϞC$ c1jF IA'7oJ z1kcȖLeES-1l:Kt>7 b1ro,+Pƙ91vHGS`ivʷL1wΖ)7p}iX2(nڶ+I#T2+qg–톀y2.LIVߘ"-N20vzU#xGN|210@ cŔ 9-2=)/QQX2I Υ4&2LR%P2N=Ϭ ?bk/O2Q n=Ym!K2S2_>pmӪEp2T1,% )`G2VbNl/(ȼG2ZY9J}nR2]p`ylyX!+g2`鈁cGOh2bvtPQ2e,3oT;[ۃ)"2j:GjސY%2nVP |#ꕪ%2p0IVU_FnE7w2p[˝mO;812xmU7ǝ @!2}[cBT}xo ϰ2N7]mp]WI/@2e-_V2ѾJP-L7z#2Ǧ,iW>(2bq]EB Ȁ n2߱ +eWPXт2Z߆xv5T,2BX(ey}"2oyNc2a{()ǶcpBF̸2q4%*!$-Kj1B2#򨂞^X2<GиvM_`2 DTnؤwhat@2|A嶲þ\S2Y-Gdu5ʜ2s1M܌K549c2/'$f?]2h|դ׌82/ 8++D܏#c2~vM&t~H2븂t*A]Q2Yco 7a2C[2N?,lgs{#2A`hq{@up6q2)F2 ڱ=1;02ZVNR{zOI2Qm䶫;2e X0oQ=2ñeZo<729^-8M]2;`[w1hd3;$amEtxdz֯30_$.3A"nx;L#w+w3wFBr~K .3KFo"d)*3IR)LUmOxX|H@3ztU٩T3>G@146L9jٻh4Ftub4_ zuB-p0X럢L4DMj"0֎֦4 ՕTjYgbOq4BޣCְ'؝Z4Jrky@ "P4aC?2HZ74S0~p{zXx94$`if !?0D:z*4-klp@:Aj6[41O,5TuNyo48Iáp^c!u<4@ 7A#:Y6_z4Kr3B3[4OW=w#m'PUd4Wd+H 4W9.{I$0Ւ]|4W GLw?b3!3Ke4X;[t*"&GF\4Z&Z,HoB4\miVpO3}*4_^{p7WNK.rд4j+,4 M Z 4jPQ6ƺG!RvE4k,AB?6qE4kȲQzia4`VV%Mqq'tUC4UX$H㛙4.V!lhih$S4<,|EkZr̻ 4 i~ҎSj.-4\Y *utlT-ԣ46k|j#/Bq4<ǭru*vWMھ40[;cBt㺧4h"d49t$SM&Q4G?imVYQ.w4T7^}z<ܻ&4Nn4L;l~sZ4ْ p3e4e8Ct m]#2Z4[ˆP2GZO14ۨB,6kx^U4>Z^;R~4Qc.Tˆ4,o? 5[|kSآs([B5_0#nbHq}5hNu%YWk5kFJXL3oP"T5kX%{i18?c5kiYk75rUI!2gnO5r\;3^#GK%y>R5z#誠dvfxSoCO5|8èеA.`8P5~|s(5D7Wxҳ9BPp5](N5S>%:q l1F5iDXv}B5fn_:hs6à.5t.z{ :n,Y185],8Vc< Q;F5\ :u|Z}35a#7nZ]ol|c5sG eW5S21ٳӿW榡5PiZr'TɜK5$BJg0WI5,UF,]fX: 5]j=Mۇ:S5ɢ3A2%:Jc ZFc5"- IyéK5ÊW^Fd5^-5k  wCϕ9'5% ?ҫݤG_P5CHr:N5%5e/!3Tsa85 ˞L^iykk5"\H;TuY 5pL/=x'ˑ5?~TKq?ޞ5FZp"VBhܵZ5> Z)6a;ctl!ama6;12?۰xEwZ'c6 NWܼ6 )1@_"پvA6d :oP67HJEFpHO6GA-|ۋ *$A\6j22h^/|h 6̺m[C茬mJ6{[¢bvM6$΢ %2+)sC6+? Pٷ61M H enHj63 rX@Čp3m65H?D5~68[vpH㿮w26:|F.OipD=G6:Z,Pύu|ě6=TАR΋6I6TR#-w%Ƞ;6N.0劣Y%B6Nc7&nC[_a6OSzTC%6QΡF\SW6bМ`cWIMKl6j(3>~&`G6lM"t r!93+^6nݛP=0Xs;ŕ6q2U< Q 6vϑ`>K#,6~JvpeKeu%8dL,6 C P~EY6*BNuau"6Д|8gKBL@6 }Rѷﳶ)N6D<^Tq ט6ik<&Ї6yPYE6zf} ?Ş[6AqQhi6C񖻱;H!6![%qhކxqCg6[5"<$JiN56SqaGOdV6r4(4f<.:{>6xRv@GiKjQa6YIfS?Ϟ76^#~gpP\6ڲTsg\5quc6.dBWzMɲY c6g/`W7-6tCsjpdrBlz-g46< q vB)[6\˪a.6Mpy/)@ew6'@v6« X[w)7j=-Q[p7 ][mvY?YL~L7 ͛kFELu`C74$6QP6Y7c,UΨ]jE7z:`pA`i7ɐοj77bxǚ/z:xl]l7 iLE%cg7'6~khcHRR7, .DM*SD0 798k 7|6Le7FÅ j@Z\%NW7JKT %$.;^%J7Ml&4>Ζ[47V|Im<'Qi7Y^j4Df;kuO ns7[%hDl㍙, !W7hueV&ښ2Isz7tB 5$wvA! 7u兑x#TPtJ7u_#TE|ӣ7y5GN)a~37{C@0 ZX 207{^r`mL n7}{x[Aܿ7}̏lK 7Ȩn[nLw5 7/bQ.cO7;h6ƦE4噷7HaR<a~7b)`OʛF*V7#VbI97+sR==Yr 7L9]a Xi;NGR7T{qWB\s7oCڰ`2;7)GuNlvMk2PLP 7hØUQ*7XjI1>:7sU4/Dʇ7Suz5+gx=)7ӓrO @7]`q`b3>47ӹ!Oa=>-xM7δͅJ>PW)7eӌQ!Ng7@+$,[(Zz7B3N_7ׯX\G| 7<+l6wxF8uQԳ7}]8zdWK߶H8[XEj}%[Qo8jP\~w-Ktx8Nepꐣ ssr};R8%fg>mfď8);X(4I8,!a+Al޴80-hȜ$%83FƦgpv0]18>GCp&pLn8D =af8J֩(T#E 6YA8JiEo k(8K޹ײy>)mu܀8Oro7Qض88eHjXJ80Cp|zvU98{9h}UtS7U/[m՞D9j^Uzl|$z3D9k%d|i]9l6< ;k9p'߿hi{%(m{9r+@ 2ܚ9~ˬ OO:R$WF9~MRh6e9Q45F]9Xhb)ʯu"9r9-lqXkh9jߦjqmȘ9P2_Y9/|Y#ͷ 4 9QIm:!c+9M7I$z9PVs@l]9ɥ>pgΓN8c69/hc5,VB9q'd!RPXTCi9ħOlrW`@9ƈɅIJ9sR~z:/.L'N9Δ]~_12I9a/(:9"kӽ 98z͓bL:e!W29V>fuC=qqK<9x~c]L1Hكަ)꒮9wizD: Πz8Ysa .q9&z9z|4p: '.FOCSRO:b =S1:xo"_:Ch<Agq{T̏d:Ul X#7+Kx:" ϻǎQOȣ7s:'W|H:+nW*3 :0(Bȿ:3f>@5ӔU3c:4IQT/^[פ:71k[&]B*:@ Q>W2F:Fp{ OPMoFߪ:G'pڬKzJL:Hx󜡉M˴3y;:MpO0bn3xvhI:T.!`;p%$ei;:d7[qx ȸ:v鬝M8Vnc:w{(Mܼ9:6(Fxw5Q ǒod(:|qL}fCв:}VMmnŦa7Ϭp|: jϋ+&1:Mçbb.#|S:'dҏ&t!:L-cSRuv:.#9^\J>s4:=$s2]`^s:WH~3_Q}j:'/7SBc:lQ^(:0Wi.%DJ_: =BUwZYNT7:F}_yY761E:5yWX_AzaW_!;*3"<4<;nکBrsאE;lԴX(1ruB'4;WQ9']Fw|;-p8*cD SnT5;v7V*D;X}*6m綫y_;$dBqʕv.;&"rm`b 7;>;(" qCN5;)e#vVQI܃"OD]x;)n)y (ڕ_nc;+>V9P펢;-ĉ0g]tk;4cn .Yua;>r/}<׊`;N VG-|B?;NBgpÿ QNT;Se5l!YG֙;T`cK49\ V7U)6;ZQ121$ 4n2|;^\U@ Dp!;^pK k S;dDZ،~Nq;e "6y2We,c;utȩ.䢫i;v@+ܓt?nm;ys^oԻ$5M);zE!#^0;#'5_;}޹tۘTnb?5=+;GⲻR:H;Jx'5x{J;.W `*M+AWH; _~w51y;\ RB~=HD;k;LdL3;:F *񼑝eq;M 6UINjJP;RE̦&;ത_ ];)A U(52<~A0|i|m<u/C_U H=M3==ᱷ;|Ŗq5q=C<5gB=D;XzD=[LXYWUϡ_|=f>T&%7V=g26{Î~Vi4t=n[mZZ.=.=ovK<@nRY> -? ՏQR?IKl> vrEMeeP_>+̅ :`&jSl>f8W2O}SI>oIuN/V>iqaJ,+>ǚn;(%  y>.fH_62o*>!2xnHN>!3;Oxr0W|>%ۜMB G>9M~'jJ5Fyj>:m.7?w`BI;L>@=^z>( ǣ>@R]/]0WI>Axxr+Q7>C-%9$&j`mm>E`v>?a6pϢ( >IxEbqM.>LQp%>x'>Pg )]Մ ݜ>XEkAWl6=7>Zˣ(b gD>Zs"pǐH6c}ml>dQoO)_jh>fL57-̹{|S,>h`C!;wz*>v @|DvbjҐ>y0 y8L٠@>s-V8Odjˈ*a>=|~wgmc^>>amCRټۆ4w>@ohs> >.xT,W?(e>k R'&^>&&EtA>Ǎq#Z^O>xWw3mJ >यB '&WS0>t i@,A E>>kJ ~k [>DS$?ac3m>JYm|;n[{>q6ot;7gj>{9-?er8:Xg>Э2  r>LGwP/BJ>ɕu|0Fre>Z=ޕS7$R>ģ3e˟-Q~x>ok(Zw3s`o>c /\>3HtrJLQvt>a]\>Ws_o >#OD:^0X>5ݧ:J 5݅¶?7Sȱ5tڃQ?ST9L_aN? PR&:=I??Gsy;Ԓ&X? UܬK]G1w?@2j߈?~~MxW?P% Ћ) }X|?S( (d9$_3?YS]_cޕKGH?f,JJyo9?hE7.8kd&4P?kl^Mz_?nZp󘪛FI?s>?i \P.?u.EA m5fY?uxv]^?|eJ+ˁ?W ?~ >jυS$G5T?4hNgv1R%?4.M8-)P?AN'E|Ƙ;A?BO ?I q66ܢ%?Ja;[) J?3|By+?.rD]ya ;&?['"'ȃI?:vƻgݿbe?T~Kt+w-wL?FR DiDqv?rq$n8?F5ģjR(T?r5?}ݼVyE&YT?^Yh&q={?Ĭ(Sg]CĆ|R=?ä|I懫Uő9]?D%W&\ U6?fmFd$F?;FXwz$'?=!k]*HTh?ܠcLC@A?裑ܤޣ\?Ή73lC[@ X$v=0]k},1@;/F(O'w! oq@]sHBdBPO/Fxk@ژ+CALeZ@_猝U7FD;iwO@%RkOyK@1*?lDF#GPSu@5TB{Mͭ5@6x0 - 3 5u@7*`#0y32A@> uBG$ @>GsqkamkQ@MaR]@t25 `.@VK4'@dKv7zpH@pX)UfoFo>I)*T@qdY36^r3 X6@qU6t0pqrќ@z+,5Bz;/ϑCM@{$R^5)P cmLy@76lz5*Tg@^}BY)*%DI,?@haw2KA @l5bb _@zIGա-@sb#qHypUSV@yGk +Rsas@{k'k-[F;@T$mP튷@n)ZKzj@Æ58`8"O@3n&LHI#L`=@oL$Avq^@|'dO^oLǮ41@csKdԨ)Bes@>W븅 kt.b9 @؊z4# >@C#CSͲKP#@`ϮH xRt{~V/rnG@3[aOk6"@*jGf#TQ Q3@lEѣ@˼y_ ћ@MC ^"w[M3tT@NCr[ ꞳcLg@[xhjPRo˖)"\`pA ݧo*+] e_.A nn(#kX=K }'A6B|oEaYdA E3yӵ,̳AA *GB,"$lmOA %s$ՆsRE/)A+7!,z^t5pH9A/ݝnc|q$.6A3ҾT|s:KXBuA4S >BT|3kA5}0_=hJ'N묣g A``yZp<7iAk:٩?ǒP#Avަ3nE'-MAzㅋE=\<ոXiF쨢A| t .c@]oAoL;p}9Bbuʀ<"dB-Byļ3rB NQoMKZ8{|B ͟v])2Em85UBv*A ]pîB~; d5;4>B_Kՠ:Sŝ"BsKX$AB'&!4,)dDB˭EB" l/) HUrB)O€wÀ ;BB)v{ɫ$KTzB,o F!d.9|z2B96py#R$[ B:o {UB>iq*BhǰB@&^"JS<]b BJ.0`F=xx >BLU n`ERH "KEB[]GUmbB[1|Q>faB_G:0'umߙBcox.`tF[EyBf"~T(RΉ]BfyD /GP$':eBin~HXeqt@Bm fo܋΄K@2:"Bn3ʜt 2 ABo6`˗]""Br{lBp е6x~ѨBsUw!|+ wmBæDN5 YT]=B3 *8h3JnH4.4Bʋ)ĪbbBXK:CВIS۱󰊮NjCԻyfv C VB^b<C+]D!CK JCgIU|T~C"rս\-M+qPg4lCATmīK} rE{+Sr76#LEs%ɮ Ȋ3)BEeSeYWP-RP EX1ihE(.jM[| _KEuG5LB|_p# E-nM5.5! UEGpb̑Ec:+'0,DsʖE0F2]v.f)F6&,en=˞i.FC--@rH/q%FEѬco5kcNiFH$%\2UTE\r<&oFH]; m媞/n&FR]Gߢ㍟UҡFVyQApՋi9FVV1E;xG$.-Fa"%!t8R>dIjFb<48dħ} {=Fe1WRɉSFl,'@E@JyFlmCr9I6FogW0t~!Fr`Rf9Y+WPF91Y=m@ ֐;F2r=vpw!cF&5Oqf0?I:FScs|TF|N>&^;SǺ1F:h龙j'#*$ҧ@F47ntvRNtFe{Hq_`o~ DʧF쭫 .C+lF-]Zܸy̖#_FwEܢӐsF~T_씑ea0F5%$S(QFIۓ*"HFBxP:U-FxL6PrPeFr=Ѷ5MNoR0mFCSNNVF>Vÿhi#F1,ncGi䧁0{FFy2ζNFrɂdW6 7Fں̰QG{>oZY)%(F۩ ЈcSF/qMv˥rF뛦:a+w Fr<{'Fhyi%y6AFzp(_TC;F؄roS՛|N;:FZȞf:G_WGL YU2 RG X@M1$>qXG\O|ζGbJQ8 F'GU޴qlGG|==*q?WG$ugAM 3.*&G/+_QEe9ԘxG1^fhdd_4?HG1oxk|>9 ՖM\G3z1#{q *8yG8~಑1tk (qMG<'XShje(4GFjD#k,707Gb\bEpR8GfX9!߀6BW.a[GgqzA!Z{wGiAJbjcu QGk4Jk{tGpErj$(% =Gs MHǂ>dG&y/-eAgh 3Gi;\K1]vGDؒ4G;>{y Gw ֝iiLqGCj3I?H⪠nGkq1Q GQc:8>_!Ga)~o,nIz4Gׅo vecPGoFDLMi̴xGVJgp9,6\JӇzGFc ֠"׽[GQn2HvXAKGHs]|o GU+dqll){5GGFǓmǶ'幅GQF\>QQ:8_$GrE)SüOiG_zMv*yGEteXkH]: :6;aCHW HU+8u.H Ž^`Hyču3i$-(H$m}iH+2#15u3&6CH6J0bZKr M&t)QH7ó9Y 8rcGH;&ŴNmԳ3.CڣH=qKֵ,d| H?~b .+VFGHEQQc~;EHK8 jK-mHKw0Q$BHQ "?FxzfrHU0N}'$NV ΙgDɷHWD!Hʺ{_Hb*N۾" U0H:iANC{H~L%lu3g'H˞N|uͿ HՙSu"ˆ ({HސQMH})7lyH幒ZJ܂YUGEHRYsZl-\eHEC9y]'L$&`HDt>/l)#|܅?H1ݗpH T|GHf$ -QJ !HX Yk%1A]yH<q Q\HZ?ߌ,,(=[Hx4@'– !odH"˵T(§cXHPBHC ;HwKP*ekB=H^Q>֓H&R9MqI {:D6j{2I7%mýtIzѢ%#PՔ`I|YgoHsݻս?(+I!OV*W:,1eQ3I$*qJ a(4^qI),}˵~G[dE]I+s[pXX@ؿ+MI>?,zǏ#1ٸz lI>İjݫ=qIB";㠜>PtJkIB4ڭi D7ULIB`;3裻ta{b6/(IHt\V39[cIOA~% Ir*8-^wIPZ oӹ΂aIPduokIZte7!O.b I]\QkeX+GÅhI`Hn,_z ' pI`Fm6gǐǸI` ?N{KldysIh0~(-@fIh^, M_M*gIi(+`m鲿Ik{hN4w_Ipa8Z4D6~Iqao|wp:4:Is 2/Tj`IxIu$o\?9`[.Ibӷ%٠IF=w ݵa=I{wKDQ`JIA|kjEMN@)IzJ$!M! IrS,xe8'ԀG}YIt2\zc\cIUrrl 8`ʽc#IqK؊l2ڪIZVQ[=- AGJ+%SI"{yD;ٟJI&'ć..pVI4 k~z\ogPhoIų{ah=WeIȩB CƗojIɵǑ; >ۚ:ooSIЗN'ٯIu6'tҖ0ttJ #[BgSSPJ'ʢ](gD Jꋑm<;I6,ǛJCj@+\1 e"R+JG!6IJ~23(f0v9J!$XMD5bߴiJ$6k[  _WJJ.J 21 IJ2m1.hQ J6vQЍwvu* J7nQ쩧l|-J:'́q8%SqJ= |0bJxŃJA4%5ҔePZJDY>S*vt{ JEvnCFkGvxZJK{5A^LL/kzKJO aAkgйSTJWsvZጲ20x!Jl͂J*t,V=ɝeJq+_kVt*ẍ́6JsegLmxT31JxrA ^Z }ЉJqpHԅ tJCLexw6)lJwٛc~/TJT - q(WOJv!R. 64fsdSJKH˥f廆O)g?{JHq iRJalȹ#Hd:JZ$R{Jl* mpHWlOXJ쌔 `QCbtJD8*P#Az)JӟHN4Tl}:NxXJ Z}f,ޖZ:ge[C>"J͌o՘Je'n8JϘ]4:Ǭ5]J`AP_ :Jڡ:)И2v笐iy+mJqQK<ȄKןH 쮝 YkKᡬĜӺAKt~Kś34C|KfI@%dZ!HKLOV)J@MXKs9G!1֑E KU~xԖ~sARKToX2e ]wK\jH{*5^,TwK.*TzgePz1K+hm`t1L K1K D>wL:#pjն/6=l&L |vd.rwǰBFVL !6WYahӬL:t4Nҿ)|!oUWLSmB =~.NouapGm!L^h`uڶZeEL`^s$5+ƨLbo{#)%XSLhl.I'LBXdLj ]qpې`eY~Ll)ln6kLq0"m{Lu?V'KzwrL~K^0F.aL[ @MOda+tL>+%aICS|ьLS3 ݔL"9U6 LeKBﺰikZ/LO뼮GmrmA&8L /n_\> LDϞ.r-ے@8+L".1XUķTt#!L*=8HAvL2C0ՙoLçGwȾ"uL̘N_3KrLqo Uᯮ"ONLԧ'^۹ki>5?keL"|6CᐃiOM,K5Ul >5seM3B2 g4xqM4Ø&:*y>$_0M; (j B`0M?׮q]QŌ B+MC`r^IEӦ5mMRlM( +MSLjn !T{\XHMUqZ = wJY"{*BXM[)RkyNl[uM\J2]@ -nP&iM]?"YHM_up}KM_y(3QP/?2M_gs.b;[M_w wGM?E:M`ѯ{dPILjܱuMb(˨aa~ Mi?2 Mr 0熗_aMxKfc*s$M~&>M{ V{0cQ=WѯM}!HnC#\FZMe rk=eM;a+;Δ-Ma63-9n& M< Bm/ՓGMu:}Q$wMUC7]U je.M->u}TM=lV"YC+M[,5 ޜE|gHMpom|Z M%qtG7c!Ma};!l|X&uMoAaތ8 ^+Mh6g-v= 2MЍXD*P@Gˌ}r/MzmԌMh8( p>vMԼ63־NtCM} CK0ux:B}fȦMޕE_r؏Q7]sM ׂ34/bMuM˭,zI9MI%G0I"ݸ%0,DNoCKjƈs+,Λ0@Nb`n ꟨3N3QVfe֒R|I;mN GiAu!~N A  "4 ٧N㘛P%KNǔ,HNpW;esޤ|N:a䞆8]a3N!oj{tN)3|0@n N8Ij: ?y࣫N9R3 ,H8p NAU!:)BcmNDr۶ɀBךpNK`k ^r;K^4=NL'7Gσ(NN^݅qZ9i7hI N_5Σ5SjT2 {NmXx*kb,ܜ.Ns1~;`:*6B{&NuWisL'^ ?NyuH=Pi(dNzVgxŎ-DNFoX7P#XP SN+cHgks?̮dNļx]HIsL_*XNf:~[Y=9fN%6J26CArLcNykF- cbIN1{;%tDŽ NR0T?ҧS' N} &m]JڤN%N ݎ%y^hANoؾFAsZz'NepCSV#7N}!{17ݚyN09K"N3~´a櫢N"CK\5N@C;K)1&N\_Sdz#kKN+hsNydt)cN̳Oݿ2^ N\|`Jf/SO2\\J?bOYhm._#͕nF'CO h~uhfjPS%OYp٪ÌgOWْ í$~44O`ȯ+i>> UO󂗶+my1*O+ SFaqSɠO$ rBF~v2vwO.\ 47 $bݹO5|;Afͳ\C%O5aVA1X0ՔdO6ΥV봜sA,O7PbҿNO;˽|@H͡}O;,j jkuCO;FbhES@"lBOBf}V7L?vOKۊjc2\MOXNﯹΧʅOb{3OD΢rOb\@AdN-ImmMOdpWBL!:.OiH3ZaH1AN%Oiuep=A9kXoeOyAypiP/JNmoO|4hH Y+uO|}tk=C O_"-[e !rsOmLdO9?18+TPPe_o~ (<ҺP'D9?D*хHP*p] ܣ:SPHy=dF}P&R]Qxe6{UJP`7QV{qwbPQ/1c:aPGؕUZPJp fQeU7(! Q@3(hթΒIF{1iQ~>@ibQ?&BQU= +bO)eQ]Q*f!t/H_vKQS\ߓ+^oQl<8 $/Q Z1>DQ"Mݩ:n_h]OqQ"fDh5N0VQ%T-U+X XG?CQ'x&nۆl$ Q+pl^8C׫woЅHQG6/Ni4XwQH[|}\`SVQHzy QڱQI˩dBz<9ggQJ%a1QMlOi P4ӽDжQPRj(oQTC-,dWEQW&R(#^HQ[flUZ2`MZ;Qe 6 Qi-0>@鐝W-idQu.QM65h[j}QdO^/ g_SQ~Q:Ec/uQȁ9ˤkY~gV+iQnoɠJmѿ Q>ci-VQG lH=dSoQ5z*AP=wQ`: Hƒ0MoNR=X}(xXpRw<}fjm. c(R0)a1 sRv4 81ADR(5W/:,TOR-g?R䧂X>5++R1*FDrj/$R1/cdpau\ArR3 cymyiQ# 8R@L%h HR7]RGKgNkDeP 1MSXRRSc"[v ~Go4RSpPđnTó82RW [M nR`3`s\͕- 뱾Rbd*m[!G,6_Rg?]w0!2 5Rj,7~hL`SkRlu; P ^Rp̠;EƬ|T"",Rt980/89%4RxM . MKD0ZRz`ڕ®[ĉH_R| tv3.]AR~dRdOgzGivR9daR0,-k!Rj]1+/R L,T4 J?R]מ-?j|G$枧Ry+p%,tR Qk۫RJd Ͼ mRt?4Uej+Rԡ=ݡccr{R֎)uR@ =];R0`YKMMR9S 7tRHjYppõ%)8kR*e1 [똿RҠSYkRfm$>V*9HZWRty;7WՈRF:Ein"wH1/'S 63Ǜ'%tt?:MS ܮa>L:!S)-&8(op&a2FS4ހ s3c?囬$NS96aBS;# SA7^\lX joSN[ {Xpf\SUvN O6"ð]BPf`!cOVnS\!nN5/2@h)pkSqLiy3zSZږVIP53ԭSAĺh ʓpSܬmr Mܗ\+*SqdJ5%(@S9]IQdS.mR<V̢ISg_ 5S!-r9t\@SEb vXuEcsS'Tlh&caRSlG:SiifĤ|xic"SIT$ kySƹ't2 3Sgd5>FP>GhȟSGX~>1B1XR3^%SkHB&uc0cMJȬJy\S|${!֌,ԺSfVGU.l#MSF4$XT:rS>|) (>Sg,e#j75:SPy9fۻ}ŘLcSߢ 4cA'S.zw0m4sdS6XN$u]0|iT0"~ԨJAGHT @kd PЖT Z\WC <A6T) nZ|9a@ŒaϠT93<6ӎ SHCT> ڥ3E#~T? 9(;$vT@Yg8ӋRp:TACv`25Z5# TFHW#Sm %KTLx IKg_-bU6TRTFcmdwK;TTRߏkTVH #2思^|T[DC q]jp;T]+ =B$+M31wgTcĥ 6[N\Ԏ Ti7R?ݟÌ5hTiY?"'#+I=ƒTlQ''ӥ2 8ToTVK:@U ^E2bTogJwO+hxanƺ3(TumrD_S'wgoTx?+ O(%kTyCY]JP$TC:81Ϩ![STm@f[M޷Gi]\aWT0?g{U,Wn35,7UY:(C 4u4/'z")Umŵn4\%+,U00+pPIwUK=LN N_U)Lr rё_9 ۩U^Kͅ˫'\U:soEqmUF_#b U`yr>gTUH/+5y2%3@~U, #c݋UfɊy_AUѼAUrUtNec.U/I񸑫0Uߵ kLXf@+UrC~uPJjUd^m yݗJ$UNs>qhӵƊ" \Uq#i,cU@s062cC9;U kӁsl{StUezӷV0mQ`[ݶMlVΔWyX>TS,HVZs{cV]V ֹJ$&fuV??PtqyV=UA㖼ЖVעzsyε9}Vći!ḍ`Vق]?Rp6%sadVvzr06)V`)5'fNf}VKA9ɴ<:%R=VfSn>\z~V<e<] )VOwm/Nq7|^VޅL3u6d4*F2Vd&ST }!vl| V 3l;1-FԳW2wi44BpWYWW?Ep` @W#JdEPr~W!32. ZW˲ ,{'8¸:G:W%X܈PȫUejjXW&0;F|̒uAW'j6BX*u|IXmhW(B!hL$3TQ"W," 7I*"-,EW1[gُVtbW?o҇?,72l^zC8WKa<nR &W_ `rMT?B◅EW_t*o9,t[Wc\|u3Wd-fT'6#tT Wl1=%!'afWlgC83Yƛ{mWz<ǙLW~VP &E6$W7.FJdW_pH/ W8E ?1f[W.\J`v/)^0%xWR=SAxV, HZLW3 n!&G*4WR8V^\Fa%DxLWZUN|J, fޚkW֮"(1:?)y2OlWQ{K\6{<8W8ǩ qB4,%WN_ =]8.K/mWS~wz(4͚W*afj*W tqD-W4h5LeHaZ[:pDWo7; =XWEiG8W:EjTP"K@WݚbC=K-ՂW:QOoLIW훔 >PQ_EǦW?OSX?IUm`XoZ/sO X |mN* 0,̿XQ@L\ !bgVmXuǤ.AgX0=WEEy/ɌX2+\9m-yͭqX3. yxHn׬4P_X4y~h擋."ZX9Vڪĥ(T!( >MX>sGMDOݤĵFX?Myωj誹͐܃XO pfTD۔?wJiXUu7WTnܨ Xa ~Yf{tXa~r=~ݟϝG2XkXK 'Z;?"XpPv5s[P|rhXt3sGXJ~Xtϧn5khkL1XuyB, b!{Xw:x>+{h ׃!X:ю#kM=wyXn? wgdi$Ѥm묃X46 ;ˑBNQ<#XGT[y*0Y7-?IX***Ygc-M&Bn_XÜA@zL X[QJlj+[IGXKJ5ScIX02 dd%X@(hꬋiXg~\ XGpx/?XZI߲.d86XߜAqx퉄XِC߂X/V.6=eXkoEBKoVX`++9JBٓT)XQk(wXF#4a X@^iԘt߁ŪX1hAW堑0RXО {3ܦBX2XD,н ynYd18yx16u,Y % s(`ɸ&ZYEC*-"~|x;YD1yFc%_"Y)}­:jFYG QNw"xc^YGK`HVy HD7^YvDr:Fo+g\~Y;(F8pm֍X6$RYʰĦVu^&(EYib| 7jHR =Y#^3>{9jY%)E *|̩Y)T[߹[BnY+ơV+{;9!3Y23MI5FmӇLY2`|AA nPY5Vq~;dLY:˻荛aGY:ͤyuRQ'YI/j㠷2VY[劋ASw [YaG`LI'Q=XYd.̤|nEҋYd_⃏YH'I[Ye7mQ  VYg!Ug8Uq7ЦVYk,bxAjTB,YmM7 WLYOdPzYn':fEom{YYw eY{i Yzj4;j,/1 (dY7Qy|YLr9RXQё@ Yl $4Yҟ # Y |Qd(bM{ TY9^c _{YkfmSvY>;I%!2HO-Y6LHo-Y@ !6|fx Yg-eόHki9zpZ̓b KZXvGkIJZ tTEP]VQG,XZ ܟȯ|Z 0-!Y@(>Z#!7 }:A~Z3$of |>x^ZZlhQhTm}#Z']-ɗBChZ*JڨpePJi1ܔGZ,(A $d(KZ,t# bH`Zɕjܿ'mQm Zoº>"Z> nbIù5/QZB8@or PlZ͏ vO~у)l'ZƬ" B5AZ`SAaFٞ\~j }ZLVlvB fx[3qu[1S^_[@P&텷wş[K{Zj.Q ^|[Vx#4I1>uA[W9Y3+3cpt F[\4:_T[aN qDcA=|[ch] %^ >Yb[nXB3Ї) [nX[>Tip[qAT>V/8Ȇ_\#8pK[S' \%U,>_x;j\.`JWhѯ6Ci\0 ,-E\73'C/r}\8򆥈ll҉>Չ\:Ij2`bɝl' .@H\B[BLI<f:(\FP^ s#LqU\H!﫟o\SPtq\R\ej~3FE2\SDܤyJѠ\ Q\T':/w\UaeQӪ o}_ \Yę']߼v\^\h.jkJ2qvU\qN %^Ww)s\ti"xp5jsdyLvm\vhw$ҁܞ)_i\w,u䙺o<턽\w2@t9-J?O\ ѻ䦂=hncr}g\c#klGwO&\w d>$K[64a\+WAX\QN [Žs[Fr9e]TX/? YrA7](4S, (,jwș], SFFsqsފ" ] V,($bsJt] ]0a B{o6o ] k DlO2( 8>]:CNDGyPFn]J-f' ]5&Bľ+=]=9 IxTQ]xG| /"]~uךK0Xcm]"zAAŚf^ց ]%_V?pcY ]%Q* &N]&|.B#dIGg^e]+V8Tf@Z]/4VN}5.9]7@)em%w<]B [m4VI2nI]G֒,Ze6]]Vr3am'uߒV]df5[)K@X]hzum\4G޷4]kO}|(XDwf]l:cr1 _d7q먕h]n~9Ԅ2>=<]o/j;RZZ]p9[0f<]y fʹ7HG]}VߚQ0A!K]~y3H|OF]"O5ed!]!_<5굸f^]*^1؍[R. ]A߹]_ xǰB]c:m+,Jq];~oVURi]a|1*iJ\cDү]+ Wok9p]P^X ӂ6[]Gk7;==R"5<$Bwk]8JHCI)z[]̝ g JG]"X}0!Lv]]}~X.Nn"]ܼ7zĭ$qTX8] 簕b.5; ]2ɒy;]_}[Ń|7^  [7`T^X}9F/S^2X'OArK"^!OHfd;^%U!"P,^)')Ov"^02Ѡq0Cy^4Q3E |%^4vrNX>h\X^<и7ԧc^AO[ {]fMU@U^JuJ,ˢF{{^L&)yD̥4^Nyȝ>%!rrS^cRBn4$ &2^gQt9ȑ 3›o^j ٜU%YK^r}sDKykD΀^sIa 1|XM^XT 1q1T:^ j␊ҹ1R^>"+G Uo^FI{C\O6IFo^ork3´J+Pc^K?*4Iw1$^U,xǫ $O'^D8Pl/P9=e^mJG.nU0و@^ׂם!bXؗX.^9.#^C"zY[swDR.d7^㫷jq&"J^hrQ Lkj^A25<β^U\=O" 6*^7(qWH 6:!?0^wp+nEH^H#I{^U,<jwxILu!>_ uuQF0 _۝CfBa`q9_rёTZ|u?H!FA_XY ʹ"Y& _ap 4k_Z$&k]Ep_!yYX: &F&_"c i6X Bk^_+t<MI/_6_/ϣxOX!Hp?_7n*=H/B]A_7{0!h_;Jb:#2e_@RH,K)y؃L_@ ~lQ*[L V_Dljaӄ)_Hf2Yӭ}v_IwUjZ@S_IUU6_Sp8bV&Msw>_^?m䏺@k1_fITHCh_lVxbvx8_v¨ֿ(BjKA_wW&n 11 0_xv5pq=ܐX1_{zO4hE _8e,?:T__x='y!Ji_A_tjf} X_Wu1ʙIu[`bk_G>p?meA_[ o$ɏ_ܧNja̿ [_2j38A\Q63_{MK`/2o_Uo]qX>A_YX$}_\/ '`e?GF`$9Z3Lw֩`e[6tm`a3;1Dҩ]n`7X>q|`7^? gJOb`$R̈́6ʕ YT[^`-Z|:PZ`2޾>qLg`?4F(y=_`A_i#yW"(`B8,%#*`F/ l7tc`Gϻh>9`KA[xPI\"Y#6=`M V6Nt!v`NbV]{0t:`QDv؀|"`R̂*hW>dąF`R'a:s%폊8`Ug9Q~~`X* Oi~lm`cR6&4c-ߡ4D`il3+v&`yvKUU`zW~!>T*w`z!|bg$A2\8{`~쉰mDE9h`co#eh'3de_}*`Cqʾ`x>/k P`fPl"Ʈv F~`m L`ğFW h`Jb[zrӃ`*23Vl[3N`^ω\F \`y2BoLŕ[.@q`vw;,`^j.-p*9+j`ѧL·"Sz`VuC?&L;h`53X@-O1?O`C쩓W8 "\`pqMXӜ֩`5 j4^1? :_?`Ϻ).=6U-`f"{x2Sk&%`x8QХ/1`֗Vpe{7?M(W`[tgL&C͝T7e`q 枆ʮj⨱`ݥW,>Cvi1(+`P/[3 ْ`|<򮱂Š`EtG~k p`f'A=-`CM{1ʫ^KL`p]8}Gߘ=$,`Vߦ6b;lBfF`~n._\`$xGbo aBʉ;VUmCt[aWǻ=|;aa]+p4E5giakEzi-x5*a1M!'ᖝaSa2v maSO0ъgPa2˸m`0ra3+ 詐ۼ▌aA;ET;!ĻI$aCXYon7#!(+vvaQkiLҜJ#aT~nD/PUr%1NaXv_ A֙UvGTaY*)F2٪ 4a\}ȩ2c1Mn~a]e0YŗC g=a^ %T#V"d6a_[6~i|{a`tI7\OAleaf>y!G6Oqhag/[X2QUπlIah /d3 h 8anu6/17~SBao,U^zW"IZauؽBŵזWTax43+v4}9a{x]TԛE?;$ajO8IEsjgPa*mCa5Ga^8?̴ 8M3Ta5ۿPQr%WsOSl8q#a9>n֡d ae@N4nD*wUa֥KFZa4M27aA?}a#X|*2d'a_i/>D3*Dda~GGq􀶄oag/nuӣY]5Ra[u^$|\ux+a΅ ǿ fTao@~ >dbaAI׶CUmoae7φ \+aYK %1_@aUBc݁̓bT2o{d(epb .ruri2[A#fb9!:JjUb|N { 0=2 b^[N;5ClX b(eBn*EaDbQ8oVVwNdbDu lǀٵgRbU_#zu b$HφtUZb)ef[2KЃ(b*]냡@hn}b*8bD*ßL:b/]Dfl,b0i&e6-&b73D?Lťc*b7;8gm@b;H?[-Jx4xb=\adYY\qפObGImk4Y=MbN)㓤&[`_,bU(xEoub7;b[W]IMzMM'w.beLT?bg< =P =\7:bh$H'2h5uke.bi 놆vK$b2 tgu]h֍bXZϊJeu梳bK.cd^,먂b 1@G00},XbLp~ԍdb6)X)QZZel:A.nb?!Cb[tY75 f nGSbHJV t Kqb` po4/OkĕwbO.4| sTY|}b/R-rgu b,o HO SVhLbpFkLeVbU%8a,q XUbY{7ERϿ08bguZAFh⃍MAbzdv AP Abgޡӂ0n]c&bƦ Я,(Smib€Xw hy/H;b病_@_JGnbOMqN<ob3^z");vbaZ@86]57|b|ccg!dI%^ĩIŰcj򚹊U*FSPc_ BȈGY#c}ۥi)+0p2c UEc˕O93\]Tc*?REcM,j7=z]!31~7~cP>e[ѣOҽB2ct'rN]IKcj a2ŕK :cxc"C\()o4ScD,ml+2Rְc;(`.|FSҩ>cʯyHӮhO,e.qwc2b@s)JR W wc1Xe850_cP{KjUOcL6itbR/q:hzcNC0k$d 8p'a5dv.K6hҒdzX]x{Gdd L[E=˴^dlгᦱR(,Zdex>%dyʛ'pBd2["0.KQ7Ldat_fH+Kmgdśf\1 ~oO.dɻڴ2Fx~d&D_";Y/hIdl>oј9/6.nNdcRLQVY ed|&r+-&oڕTd"2W幅*p3d e+a7uSdTIy/2dM]04Ӝjk"d'ԓV2H^EUdUpO.aEQ 3d\d^ a.yy d dK'F\+dXIf[(^~Pd wEa{OeJu, tste -6Bs2re sOkyS*ee 5巕Vf.r%e%FN4cI[eQm "!--߶ș(eW)VG-3Zx0ՙBfger=nF )RDTdLge}hCkcv볠eΡ85qOe9ʬ"%BP"Te]_?4b@q eAT@wWquee97Ie<ڹrmP efH@b0`Ve΁}Z`e a%J?޺^e?bAdضðeǖcԔ\I0nڃƁet1xK$ߓ¡eJ?->}Tl.e?!wgX:'l`e؉$? ϜQkf]eN]n%.e㵾{}~@+e B›!Z 5r}heuzǥ,IVfنX_n f2yKU2:m-fmxoU>SfhG0FuKrjXfpv6̆i#/f(=C {x;!fEY%PTf o,oBo_DD~f% UbKvfbҮ V3J@fJ)D򆚣'f Xf+\f>M f>q1ftt O3˙1fM\t'کGUfc0zI` nN)f³ȓآ5]nI%Ofço=0L-Sf;]#>T4inf#Ƚm͊&@$uf1Nh7cdB7MfW :?c`藪̲SfY7Q<;u N~>qfhٕZ/I%w:L=hhf8 Ve>XUfӅlQn `4mGd(g3FD6Hʓg GtR ߘg ,1߮x*g%^p:acg.fGƾNe"(g#T qݩ-[-Sg)/{x`Ju`P4g/!1`Bo^BUxg;De)]-7g;'/}|)0i7ۅ1g=z8-&ϏwάgCͣgsGDG-CwZ ggI7+R^ \ܮgKtGƛ1䔟gT;y-gXי&aj%E1]g^mNX|*ggm{gpzBPi gsgTi)O wAd9gt~7~uJ@xX$G `g~/zV~ Q;gfqg~3( V+gҿيL<Lgy4JSM][a"HgTMNR5GgT٤5-Ag^%kw19eM1g482;!eu88'gJ,,*{l˥H zg#8)Uf U>gJ~rlgMGPwsiM 83gt!SѶV:l=z gbUk|:_o]dg~uV\%6g`EnfJtU7Zgiv ixg6NH6QUӇH?i g(V3ѳsAIW!-It4h!4gw= ytr5EI9g-MW †# ѩH]g#9a#]VxpgI,*_QHKh1vI㐷dcuhn@ţj_5#79Ch!!iB 'qJKh!Dz>Bzk蓠h"|Yhƴ+`%Ĺth#*GT?Nb " ƚh$#ѡPN5KGh&QJ\ tYLU+ue'h8$a _ j7 Nh<2 thѩp}vhEěԷe]ĎRrhJ*o΃&lP?-hM  0 RhNɴMa4w2YįhN5[˩A}1 hUp0 !~~4GhW"xҵ^C > 8hXj+umm -eh^=UӿԒ"prhdEqRޞ >eҦ:hj(go6ʘhk~LJm'~hplab/Ǽfhs=F;| ?1%=hxړj{h@)h{bFQ kV/4v,CHh|!tbX AJMѭ\h}=GQ2}JY bhܼG=#) hqd$9^Gh]>NN>£U5rhOd˝P>la 3a&h:#?<yیhDh.8y› Y~hfBdbN:h7ij4gIhx^z'U8fsE^hXhkJ}N*䃲-hi@#Y}żW>hC]QC~oa#hVh ^ev63h>.p|umeՄh .b/|i^"F6@n[/1>JDi kS U2fͮ:(/i%ݜFfBižN2sxiM NЉ-i%k s7W]5i(R=:GK@Ri*)C7YЅвUdĝmi*qAAfct÷ji/N FG3-$Ռ [%i/n&ؚr{a~Ki6os 7G0[L0 i8vy"wjϘ( iDAe=Ы.:siL{~8 7mdK7 hiN3,ž]ANW$iiT< eIWdi` /Bt1RicMq{L"Lic8ԨD~q™ig_/#fwINijAmXmhilݯS:#ZAinei `LJIN ix4}T!d1:aiJ3i.ϻ3rB8+iﺛW4lm|wi M&85i N leYL8ITi_Ev$b4ZYi}Qӑ0 QDigIG{j-vl6if]c sBpR%i$|m1i~Hpjzݽ`!ji8_!魯 xi#F̭~iS_N/>rFmi"&,#YǧKia{}|`ti#L:2tj'Z8i>R7\8`Di+ 6 WK}.8ii1(i|fc[ϔ.i in۬*M8ǹ,ni쒋d7V o`i-?e@6}J߻Xjil5>HMExiǸ 5xe9p걐j6q)D2c'b'j:/;6&jm3]|9@ji@@d0`])j{ERw܃E^5Ьj(OSɄ{⾸|p4j6bW"@[bhj:VbY%j>դ-F">z& j@΅H"حStt>jA-遝t *jEdֹ͇A(-jjF >#.GPO_jL&QzIr0ru'jXmc7{F~jYWK^-+b?Ҥ7jbhaPmwd\g17jcqAnBDq,jk:Takt_>jl-uНUDņ!joyAv㧑ԏ+̚Pqq1jri/RmCF{2:_ojz#./UL-"ͳj.(Ә E؎"D?jmaWBw˱j+:8a1=jJ{Fjj0jho UeJ뗿S8jyPHCY;􉳘2j}9}Scj±"zR4bxYWu,j5.ELFj( /b?^jМx{'!x[jG6.a.s ͊3%%j^HвEJ`jt~ @jWǘf X#njZSQ]>fKCjA( K{$Ywj߮=lҔDרjoіe;jup[]"{jJLdi-Rj 4&B.^lpk|q}ܽYHmHUk]Z_vz)ՏkC@]BrxĹ~>k[?Pw7Or<1fkKR{]2f]k Qae%>NXk kiuw_ h=Kk%!X!z'N()d0k'qY' " b (k1pfxɀk7wT|Uʦg;k:ܒUPpk]9k;ZY" kv){F9Wz7kv<$=] kzڸLMPT,k{cۥ{25ohAk8 k[< k7nxwdPF:kiL Nr4tQkM8Xc{{k 'k†Rkܤ߲GkaVBN૲;km\O5Pu8 i |k%_n@DuKO|kepl ,UKkrbZ^ L5[Clk=_VO.!2kvJvZ Jk=ۙ穳96p";ke7}@\*y> NOYkT2DJdjxmkdܷz_0ikT򲕄-/&kªśNd8`_jknk @4r6ZYck*l畦QksVik̨׸ڌ&7UjkJW >OQ1ꚨk]K2|2lk\5 =Nk4&]Q礲٢kۡ22%d ; ke Eb53/CWض\k *?/l?#:E 'vMlEa:ޱh]疠Y-wwlOkb.|M`ȆlRcq[ilWp$ e|pFlXoApfSܱwl[”+ břl^u&67N&h65lp'&WO ߓlxV.ڢ0z#l~a+\_.x7e/RʼlJ2W=ޡl<[0"M6p3[ pl!pT[ l&'$$+fl /F!qb/lZ?󿫭#4s0l鸩 S(:Y8Yl6f٭~ꨊv l3!lq!iY@l|4@Q# ZlQ" EP?swZl+?T:sƥrul^H")'4fyOl)QDEN;+él2Y}OeޒQ#wjlVY۽ lXH ~eQ\l̎Ԉr1plg*z`$ǽ`lwqa NRl=YזH!}2lءD]X+ikRflf6?+l8S=K}dd#l{M{LkvKSZ> liUw(5aEelSDXmJm,%l[u0*"Z3~leQl[x_F<|Gl 4Q'@R}plxK}-lѧ@Aϖm Qہxb34ɶ$ gtm0T&,-mhx䦿\Xm%G{3av# [m&&~/WʐY7m'4TٓeMm=&ub'T)09i!m?\I5mE/`FT ˥CmF\5j>v&>mKdzcǁZ~Q^mX|TeTW2 rm[ۦ!a֐:Ap7Fmj$N&qjc!Ig2Smk=ieoJ2Omm0t.))smr3gN1&mvNɶs烠Em֧uyde }pmץ]VGa+qVO=m8N?6.*+DmJCph |"cR7ImgW%4rBA8mqx1t#l]݅mƖ.O(Pw1x=^`lm%${ Om_X2¬WʋFmIg4$Ir wmЫRB`*;d muɿ&P>aNgcE^mբ^:_;I!yŸϴm01rǙC9mᬕTmjȳ *)m]Fp!kNDm{؂ d)XG~1mws%Є4 ݡؔ=0 m43,#U^mmY?MWBM6m헺x*yWpT&emբLSmN ?zoALShmn@ņF.Sdznii֑ V.K{Bfn Kg]V1PxAn#$ \7G?ʰװ7D~1n#,UDh6j$/an)_}G,愘M}n,'CBN\mYUn0Rpkd|1%n=ѡc]sʤ,nDt[I; *)3knH'x8bnAV!xnSs49s)vvT0nVAqBvX,-nb3wļHO[Zg}nsFY%zh^9nv[= gy'wnw^ZQ xkRnxMQ͌5)n}q⫥o=ouO n~ӣU%ǟWRe@nTdzQ"N[-n=еZy!C>Yyn ]2oX]&]nHS;|nJӎnv *X`o n:^nɧ:Xs I=RinIy`yAo|NnTBdJr=&PnAKn!_]Ie׺Qҍn> 20Zn5LI Vv7unVKR- ܩUbIn~Z}rwfn1plnfsnEh>P 59ӿaؒnڹ) |n;>LfX({kt8ԐnUH+0[gʓpnQ6+9 `,qnv4wWr n!OWY$5An yL \7"[ n=+9i"NnNY}3Mo>W\(/o BTYzA=Lo^T/!Fjooe7JDx8'h҅kouk*m Q UI@4oPZ/w;Fo~<@)Kןo >2 /`t1o$RzDQC3:fo%Dv>Và^o,Wj_ߞ7d&o2 ߥG"&o3p1-No8E&H_u1sK:iZxo:yMordm&~lo@z^׫;boJ}-2us>gUoXp `ƶ6!oY(uUToY3 ߋhio`E>\MzC2G$ojXNuº1Soku*)N xTConLb2Wg j޸op?kZC.{@opC12/+q)oznZbkY^;9;o{%0IH z/1o">Fn'R"ogpY\VɳosbFXZol Y'oXF@TMoͽ.CM7qgo+`X8>hrCdo/ɮc /ؗo5Ёܴ*<[YMo͈!T|2boFC-*B0l]o=@ %fSN+ Bob˵2[!`2b{a[o`dIKn7`eojADzgC22p R@G4ޓ- V_pbƋHaE@p.uGKчl+`pu6ʛ~1 + Tp5fT< K*p0 `x[Aنp3y QƠ(p3m!h #Uq9<4/W775qnݗmu +4ZSC4dq O.kt,*P!.q  v'R\FX^BqAnRҶـMwIqˊ5Ts}ɿg>Sqx˄lvx%BiqS+''b#_+q#8jҶd(b]+q)2$c~`mq*' ȟ%콥qBB=qC/Ia9K!N9qM9nimqN8ajXu݄@#qR!unve6s&1qRb٬"Ŧs:vcqT-1jX)QeqUx`R qU _ְ9`YMoUqW75A&BD@eRqa;>V?5[-yqhvvFE&qk`R43k;ӳޝqlfd)ݘ|4E:lqo" !9y1|n6mUaq WE(&ֶgqp8$N)׫Y^&q-u|\MJ}rKqۦD=HpqŃ3&i%Ŵa@sq?tڴ9yo&f[jqϴ :*П'Qq Jy4s{N50qe ߪ2@ӲPl7!q$׶^}2xUq} j%˳,Q_%qIs8%=Іr$wbCR]}Gئr 0D\~Ys=`ի r#~!=a3w$`Rr8PXC\Z_rDctlaƫOr c&lN_;=@r-2D}H<~ڬ`K=z:r93ɻFUϫ,rEz(G^@j8JrGpQxno.ŻXrIL. <-f`rK~Bd_pXsrLaenxJ!orO0]=\WVrVK=|kJkYE&rVy^%dGת=ear_qvO}`d0ukra㯺ug(fC rd21BlC) )N 3rg|e8Ѥriz1>B[ o)rj1cpMCp誺rl 4KfjqFryI_E-GsrmXTlD!ԋRrjwT =ep]fGb.TBr)p$Oصr V)w%JcOL r1­\8rVmMkDr$.eݤkZtr,PXxe^Fg{r.}?uqrʣ_J$_F^rA\QoW*p4Orů3%Ե{ޕ@rZ#ش\H2%UA^r,kE-gP^ r齵cf˴"rЦJO_.kԕVSr~EE BȒ"rԚdּ%>VZX/rGO&WgaA6Dr42Y{!Vtr]bh N~X Fr~svJ˨Gu%rs ;Z5FrMN3y17EݎlQH5sƴ/h<.TM s VnEab:siC`64&L_s6ԤmS:jzgsT4)SPsPC(_Jbsnu2 noTƷs zr쁧x`7Ts$nJ9VŜ3gls,DꅆLpB0T6s-XAsg0)s7fsKQ"Z!C;}/sPk.TXyFs[ QqldtWsa1ۆ-1GsaH{1w Csf;IÚsgF"[)iΒtKshz%>C3*si5DW|zgQswskd3К)Cszh)(V[Q_s}ʂp<cJ#Йvu?s3X&[peN 5\s4qUO(]s +\+$vxb&s(ˬbHvYB Gs#cbp^\smLPESFjVzQGs@Ql̡AeOIesEf|Gc w$8s ?p5|ps ۭ)E"`ʢUYҩsޕik@]Asp/sG+Rsٰ=Tjms̢vpY'|5s7IYtkRKOs`'HzÚCs!+I:de{Usr 5†[s]UѣD"GU1t[5|4-Av ltMpNAYO7t|+f QjtmPg0i$\t^5XuOtMMd(G=,fvft#C]pBP>etli'~A,2=t< }FH=o"yt0 2K!trt5 ޚ ,3rttӌ?'x+͐%t-&ztF׮|~t({ +&y btяPuyt1HV,<=tVX{8:;D|tT#6^(\pTŶV- ubq"l-u%eWQ"JJ Lu&ԇ r >7bu'9n 0pWU5טu)o9 Su:V$&u,#ʆ(^׼3Nu2o1 |EzDu7 1qjBN u;ތ!b RlУu<^%BLNJJ]$u=yaJN/I*GҷAuCYc薇ήļuH_7Y=.wBuHẌ?]uI}r* uMN7(O]suO_ja g{14u^LF=C*b.࿥ub e敠>oT-ȓucOsްHaaV /ug4Qh$>umutGҸ޳Wu#"֗ {uӅU&-xuY& ƞ'2#dugrzY/0`Þ->u1iJzTubs}F=GbMSM1u&?OZ~Hq΢d6]u9$…B_8uEVZÀIlǑcrFu'/]Õ1:(0+TCku͂lt;B;voGV'kAmuΛ7?+B ORuHQtYN?6huXA:9LS98v Ivy)Gāv kPܟ'òJZ:*vl:n.ÏoX?o(Jvv]wenGQտvH+RRWUO@v_WD>v IjA!ih?@WMo? v&/A۪jZP.v_׉Vg ZTv`g^ pْ`4vc)OU9vd7;8ӷK(cNHvfDBEt^& ڸvnx dl&I\uvq ّzBv~;GԶeW 䶯vvsIElKwvAj~n;HZJT~`v_u71BvoBp>֤LvVV0(}vx8"w21X/T0Sv`tljH%v&6+vmQvīn10x+c%%v̮nXShF e vȎ̢fmK8cv%TL{'Cv,*~G`#vA 2-~v ?eTTYvՋKT{CJaJvp{P:pR p%v & bqc#%v~ I7 j,D@(vs%~YU9-{v XbQ/Ug`wa}25w u0 g`,wwxEl$w ^Ie7apS_P01wQ1l]hh1w'OٴjTkI<-w>c\-:ArdwS~N3QΈwS[ϯ=wTJSg=MH6?`XwXU>n lx`~vʋw`7NU`x Lwb ?ӉEV wcD% H>w] wg仹 peʔbwtU $o-՘l='wzEe^&ː1ġ wP"׼roW@ws_]6nOb5>wWv#]-Qw,[yB|ܺfw(f,4nwU%J yiw []G1Ow\u|.qw7lt5wݛA$*w KsI[w8 ZCZKNZow͸률U]6wC5'Q' ڲ/wUR{׌~iT0wz,/-\14e;wvQؘg9AV}c_6w&Uk'ay<;w[-/ER wj|>"Q7|w$uуogՀw{yȇ|JwOwcfd357 SFwPWmPOB|wMG]t=+~E\`O_x֏ /5if~*xf`L;Tcex`Uч `' x r y^r&6#xg˧az#i-9$xHSTuzIbx9(SEJVgxlNٵf#SmSx Ϗ1G( Ӷx/M>|COXswTx2S7jc=4õ܂x8 ztVZ(Ab@xGwwY$dxvlTxO.VA(XxPLB;BO&xb,EU%%Qgxb+^<2Czʙ/8xgxil%4$ӎ\kxq 0=vL@?YxvHZ(V~[ xآKZ ٻ 5& x5[ARLi?iJx;\EVJi2-5xO>u[&[ %>_xF$?/C~xҧ#&/yTxC&-,xK _=z Vpxէd<Vxcz# B7xhDD_7s tT'xPuuƻ?)x>UHvx4wU3T-,&tx $ 5hxj$Q ]yPmxD>' dxE]^ 4omy%\@$Vyss0^Nyk&6!(?y(xԟ"NEb;BybP!]6}|yfmm"& h<0 yȐ=5b-'bq:ykEAp J=X5yFiwAuh ^yXfA3/;gtsy" 9>a)`AIy$tZL?[\)6y&LC"1C!dny+Uu"X=w y0ŜILIp Dʺy1v bixYy4Nȷ"9e(y6@ɾOuWUT2(~{y:$L]c9 ܓ{y=<*uD%9 PDy@;ـ2u@HȳhyEoP5F`|}nLRF>yHe&A/p9eyM6zpK(+6yWMW}gWyYr ʻ bPKzy]-Natte2{с?yj @uc 5_R&ypc` -gn~K< [y|3BB:y}ON~_,MC\yA[5ndzZ1yHjҋE$Տȶ 9yϱTvUQ=Yfy*^Bq#_޽׆/yw#"c!yj‘m ,. yռbЧ5PB8ny]!8j71yXؙl3Ƥew\̆yU%~ez*'8H~byVMî'y! zCj573ytjF%P'%y Z.,CSE:#ziG^d|4Xojz fd/86tNj`GzqK Pӕu_@1zMwoL>x+zgpY4N<9&zVtwzzHkT0Q2z55j@W v0_z5_.3+L,זX?zE\+'CeMߖՓzW 8UG+`yJuzWE[i*qaa G:z[pi{g dtez`ӋkE]L2|^zkFօ@*XnMzoXqFj*]zr]5ף ʵ!zs(:筿5douݝz{R6q[>R@u%z{czKwLF8zUL!EJ*bS-rZzD@7.;7&{iuzvEPYr}ƯGcX{p45qלrp 9W{rz?IYac ߯G{Qg{߃L0({TKEc<`{Z/8V4" %{9ޛH W%ϡ{%cc=,hn޲|J{ q382{6 %.*z3o{n_=&ɦ{y DΊW }&V{tmM̽n9{)Dq@ŴR(%3+p{Ԥ'VMd-2ε{+iڼ~f=KvA{CK7LگQ{ )s{r\ӞT'k(SQ{L1R%r=q{%qTa:󟳱{4>>G5y"{ϝQV/^hfb ՙe{7#h^L S.VF|FF!Q,U|SݧW|KGn#|*H(L ct֠|F%ox;{ |(afh>}xgPk]s|1qaOkVZ6G|L)girLݧ|PYtU֖S|V:Y"Ҳ[|b+l 9a@Cu/|ivӿ!2O9ݺ~|tU͂Z5rC~|u ޾t͜h|yKS[R|z(BSz 1cU|zwyh !^=|jCٮL/5|fL';.C|wWf3zo|+lpE %|`"Q h$|ȺҶ{8F;vPz._z%| Šc9ǩH'4e|d8tY| ;k\n;^YS|Ww$5^k|dXgɁ|}b\e zie1 A}fȽ#JuSl\Œ8}hZ.yY_ꀐ}nO gP6PCm3- ?}pDA4,8cKs}v_LKÎDcabmB}yi6Mulj}zQɅh !=~^X}| ZH"1cД1}t:W{jo-`:S m}§HIRF=L.}5s- ![t7" }w&)o]/ }Y31LB`e.m}I0S#f.dѢM}I!UWMNnT39}yDtŗݴ}yu@I4f=̒}ь7 J 9+0}) ?`$Z=I8B}h'PI&}TxӜfS}W &?||xp&C3}׮βյė4`}2J`|L7{>}ȷ~ s 11H}:C۩Gwekc@<-~}T}Z6^΅{fry]}( lN:}HC 41o@~(rG ֘⨷%h~lmk~`EPR COCCn~ ӦZmiw~ c3k c$~s0O|E>d~a<̓nkI~КE'ǫ!a~!JN^g&bqJ~ܾ'`gM.ط~_[&ďÕ" ~ pLߘ>š~('"jg1NȀ2j~)o~09D8|7>~9qo9-^̈́Vgk ~<~)Y[K-L~>roaQEb~E7@ g[Dh~F{Gűzyl/ ~FQzb\CX"7-]6˨}~Jtid#d'SlVcb~K SaN(%!~Os㝾H^ev1*~_zۜ!=9fHvrr~dRN-l?~eyt畍H9E-Vlp~e8;OFoi\~hAؤB9Q2~u)|'։>k~=_?@i>²v~dqF5 ~ʺ%=A1= ~QUv<}T~bP+t*{~y 9pmacoh|QB}Dܭe\R>6VhQGkc'B0R:9R44eT[*I%U_K vsبQ*!hcuN}p?':g2Y7Vg9\ k {:V倚Qghp½U6d2ok,FsT@@t )$({mFwe]xŠ ~klC%i#! JO=qPZↈ]H?I+-Kk=G(:ĵR#$ >޷Y _7*Ӝ`zJTyA'\'2$lHkG 6.r0 TugU"sid;327O6g@b+hxY%dU -\Ѐ-7ߨq`+s2No}P KzZ~.>$(?xIu$ONFY6uϴ#S^K|k-XU@c'n [/8 5C [Lk$Xi7=xi'U1E=)qzՙ_ <糁t9^Mz1>՛ ,i}Mh,RSb~6@rL7e'kzm5kAڕج3ExL 2~uŀY W/%ŀҋ:EԡଖXayQTQd^Hbߚ9M 0i9l")0-0܀8)D l=;)}PmiO3(}'5nĕ-jF^nv+iF\U͡6N KfR\U o<yC p@h2@ȅ A=ဵPp&qw=63okQO D_֟ٺ1s<=lI$2+ 'qU7⟀OfzjN5XV\ x'Z}HiaJ :wJ?.? BOc{XԀ.˹{&,̀Q=ya*\ T:@~5_^0VgDWToS=<6{:5ߵ1>glYytJL ~po=̉Pf&?Kz' Vc\*Yf`{cXŦ:4ߋ9t"L+ozoS}CO,lШ݀[id4af/n3aoPp )&)}bٞE*Xl 7sz)QGT">E2L,LB# 35pT x1>%UH 0=x"w뇓%M%6+LQp,fw4Ժzi&Vʌ߇n;ɂL0/ZQ-8s> !sHK-V?ߗ3kr^MvfwR-$-hdZN*[ f0҅s S*CY"g.r؆^#WdPۄqJڹ &6 󃛁1Gj|JM!>Ǟ.\:\6Ds"{N{"lQg,23[ :̴;JZXTa_ {l#U!5[ `+=*/c5S.*nC+ı@' Z"p2 n$P3]Y]MЉo3Yhx%OժL47˶8؂UKr2oy8NVŞCmRт?@[Cy`m ؎Bf|qbVdN3҂aF<("7PP"2\rY3TRL;._hr+SduQ {xIJnBZY:f,n[=*UҪ+|ɂpM k=^lwT?šzȕ-v1qT;|!m{i\Y-t4VR?09H d\}Y;a8) hjˇY0LHܝ͂4mlD@!K< '1Kl*zbbł,x#<3E\NcwQ<;,}"TĄL3JRD *ꦅR&/Uys#`"!g2!U4?n馕&L&hG40F!jLת0qDv"YbcR>(lejF%Auh<$u0s$mW*5ZXO_KTdcv.Ht_8? ލ qh߽[L=" LOwPۮ W IPZ[?FJ&-@/fT9?e0*<Őpz+F$U[) rOHƒɉڃh!:e+AApT i^]X궔fW yjm.<FK$܃}eWFnr̲\A]trNHCS+v[6Exm1]ӣjaβ;ӲQnpF{VWW.]̨AJ=i2GR[#,%4ư:V  \eIj~'Ө?O#ກp h GQ(O?%уScOO_;74d )恉%Wb4ӣ/7\ CƃK>=i>`hʡ[B;9?MSX,"*Eeea XrRYDw.G㨃M */ wڱ-Aٞ6knA-*ca7DًZ`Bc9o-6>/SZ1y{Y1kL}J?R;Ytp %7 TKnuXeBɄ7vN*{Rt\Ƅ}i,D2s@8ZcSO'pers1ξP5NϚC-e:doZۣWl.{ }֩ah˄8`W&aܹXAϦ &lJV|jJ)?ƴNM~aNwUXdXǻ2O֓I_L*r N֜:؄QZ?B'j(ʍ1}S,,4ИHije2T Gy۩O``0dY5 XtΠ 䒄\aw7*o1?;b,SRrQrQT>NecgSaQOUHkg P,Ea+(`mhNEE) KVnxm h: WV%yʄq?b5KeLtǥi'byKrPfQF}*"2C:eAFX~חޞ\S3%WkJg4^Cw$VThQYkQ ξƄWeCah)mٞbm+G醭 emKnӄXJm}W#ۓe(g:(\gu D{@G=ӕ)]( r4\?:xNNhxt~OVPFF01_:+M :fzqNqFXGMYi_ce{@@ }1ۧStP Ďe]IKb(Y;v# TWn=*BTل=&$i<[f\Dw4DafIfq9BfKSz,EB#pBOH,]nR; ].yֵJSV*F*>scUĄlx$ @7}'""6!$q|`)"i b5'A@p|L⋰MXLՄ黶AF@` 5<]i=TGv2"f} .kU=nTԅ{Kav/n)KE`ذ]K╅*+AjGŊG}Ck|"2~.0wEd £<څ1$ۊn% yم3.4G}) f5;(O9n8z\S+US))J8xTeS9N]n$`ǗԻYd:IJ@> *@R1dmI%ok6(u0m5WI5Wc1NELI˹+g@Zlj5՚إ8,lsz: ¤nbn~W)E^Xo0ݦi$ΠٺB'vfv$~a7?:$ⷉ|L즡wR>>d9t.&dӿ8uBI:\ls|%-Ju޷̾ͅ )b*M$cFi0A9k3f_H[ ȓ _u (Yr=k3 K`hHǏ2S.Cq,ԭ1c͸&1&p bY 5!}q.4N6ԅ.Oa>0Yn9)auU/0͹d#I貅^>GRJiXKgu2G>))E f[?ԧonPǰS%xqS)nERѝ4DFATY{MY̠) ^\(ޡs[!aKuB͏`U19++4-)[#?7N@nr -h1BM1AȆ1:iâua6i"K=szd+(% RWy?s!݆(2VIndd!-D =,7+k{Q(†.p(Ə|ELcV/mlDjS3KsPS֧:X4ROǼl;#C(shol%E[)(%RK p~IuO'+?CtM;pT0R*yڝ)n IҩU5.:O7GOنWn' -w::Xk*\R=^(&^DI@ٕ &_R-NT ӵE3HhE"վV@+ۭ?ֆk ઀giFi]Eo C8+Q#J<ڶu,>gqhgLwt}ok=v2y&y(IO$Qyp{?Fv+N̯-Uۆ}|ͯ`4aCV%2 t ͧ+3-@" 9`ЏG"'-{R%-j@bqX0c@ -lD!VWAv >>; X`}V ^>«z[v~EߢDm 6W놏g ##1d`d9xQMu<.醪)w}T[Ƀƣʆl ʋGRFɾ nsKX{=7p8hR{=+BT9xid?~hC*tNz 49M*7MLOY'$ԨeѐGhs&k*Up#*^u)<OYJaߢLgCMo ͇ trGevu_o1Gק}Gh=/*Oj!{es$[Ẋgy`_h]CF88SBaξ\%eݓџkWpGZCs܈4E3Qo;YQHx/A[5?ڈtDn-u480^p/Y1r ?]aхˬLIpm̈JZKsc苈!USu,sdG_ň c_QOWorVkĂlp+.8 bn{>H /<[ZUF)6׶@%̛> P@=<<, >uu[PA8ΤGϸ:SHbUoJhUUa&g6qXb9~Tej7`}a40/mrW3aֺ$IU@p ָX  8FBle6/,RHT㓵K vV9K S+vXyޠJ4!GbJť +h|s@@ȉ)rgX] ,WD =]n&;K* EbMpXS!8 !:Խh"JJXpTaJu1#l aXK5HVr%Іsbv'-aO,B҇KC)}~+ĝhLӡQѬ*ƪʯTlXY(U/gz\l d*gaΗm첉zdV9XG ҷUN <c^ -ܾ.=[kj %[['ѾfRxU)*Rmgo愰@-hDd&=T^v kAg$;9s9+gG6^ۘؿ"L9,* 0e\i{?Po}2{d<ymEHR+BSM#eRHZjQwÊE~gu)\ˊK谢tr݄/.J;N4p<|w4 yOwbPbI$E2SA7cX_$HQvt;UnYP @D9$ъZ}-x(U {m3(QS^WERaGѴĬDfWkQN窖?TmLc(^%kȰ1@n%.ۍ=6,C_Z7u{A`D7A]1x&}D][i?N]YI,t 8 SI @,Ȇ]~7 |!*2ϟGr.U~t1F9/f=& |iƆ:6X_u şpn$l M؇x).2i UيA hgic8V̲JS F9:,uK' i6a&텧A7ȸKaˌ椯3q09}Պϵk8TIiȋ:uG1.MlS ϋ=YV7YQ}R;>m 0]οa9xAvL'nd>`B^$H?Mb8̓^ P&9eUsW>!88ϚS~d裼fBqyWX:/8Kx,0u`)4r:|ݯR; KF9kAzb,&9M̋sBy1Ji)T\~C;SZfbiQR'~)ܞHCz^:Q2lՀM׋P P LQ`b3FVd0rҵ\ūy{( YE~' QgP싅la҄9+|8cdZz 8~&B坑bkowD{ò,@e=ы0}i|=*_U2-ԕnh՚ZF1iY,n" Uh%3%a]t'Ң:u\|=<<, x=@ 76_YI8Jb T}OVm1ܐ%hp?C۲Pd\C5Rjp*xtMQ&j$+X Qlg++L17mrیS_dJIoh׋Y7s&]#^a4=]_+g&>e݉a"R{10oPQL߾iAs\7cy> ŒUˆwL$؈%e64xT!Oׯ2p:gꑢ`X -7^8Tq;pR}i h Y\ xDnBȌ A+E` bsTW^h[E[4aYa}/R ǫ!+q{<ҙ=nGNs͘HnPOx5u=t.} ڸ,i+BտaB~5XQmß:^ mݍ5TJ8hm3ޏo^IUźw ȭdCF }sщffJH$^v1Ih9]ᰌTu ㉩a|z3?faoXhc؍-T nb]nv&_)EB~CLV$lv(UpV,'I/ Xe`1|@ϲQP1L9VCNXQڍ3Z0*G:64 I< Ww1v͐D1j4y36V嫍PۙeE\w̍[tbE}L)ItV_\ϦnYtʍ\)F*>ɗ[]c<;d=pa `_ّ彸Nkq.Ts>f_p(ܛ/_6c[pp?y$bGFhv(Ŏ! uRS2V=SōzUn^y+nqJ }hI2uL܍*`*`0u,xibZ +uh؄`Y"I9r#9-T :UO OT-E(ҰB荳6rF #e%{ԣ{6B)Wg"?JNMbuD5̄D:kICn>3:1k$oE)3gx7h. {,il3*3ލϯLjnfMذfX4q#[E X-bLvQ0f%CK=Ǫb̭. ߎ OTa+҅  {< @xr 1) r8q3 unamK^k .&Ď@ynK_5)Cbdֵ,%ccg#W&40w,v;C_&"N16(ym+JJͽf(аBʉ O*n0XhU+nb*04it*kfގ3mvTrX =0=vtmn?Kpd{l@:m8Rf1UTrUI;5|f1{UMe?TxgXy7V82jt]|HNG<nߎp,7_@4وs|fLX(rqluaID:wh)(~xDʈyNאK@xuNwMRh{n8MÉ+,'Ab0KH99˱$~ Iߪ@Af.Ggh*Q=?LC5EO <4j78U@4Ul o&>L0TyF;YŽWHjO[S#v1vzV# vcBs񎶿%;S<8MwSbtt4 yyoR}*bbcEѾY Hç%7K^ nt5)̞?ʿgΎRr51H2Tʤ٢#IʎiR/Oj=jYs KGi[}+8c!1@7UMZq!?REeTrʌRB U"{=\WyI%bhBXo=~2C-Vz9] 4ox/^ `RkK`Sb|Z5vnŦ" Б^74n $%l 2d |I B&En N?ksh,.-ܩ؄vXյ0d X DV9B5m֚w5= M X"P [*"+?G,DKùsl;?%!ER{ӵQ/\pcU£ZL)bt9X`DM;{0,dny}zxa W/lbYZ9hE6ܥ,i|uI4~ )F!8vK/v -tL~Ax뛢Wz̋_u[bxPi\{ sKg3-7䏹l7h7|Uɿ?4?A/‘] w|[La^3ϧﴃ=H̏_| o]Sik` q@wĶ.u/d,ahf<~XR} ,+g;̼>qcS,*~1QicLm@|$h`q)$Fe{r]^E} ٙGw\r}nǡ5Z'O[75A"-e𗮜X%>2,'| #( %"dSfȿ@mto"}Hb/<:Dt2B3EJZ|#P* ȳ4dgА#YeLk v"3$$l2ƵXc?SZՐ*SyZ$LsSp,xD֜SzF-^uaB:.vsu |1a,-ru.)}JZ 3xi -6yuгۓPVpس|Re]ZU~xT_j}dGqL. I 쐈/+ū>! (QE%ƞw U]2v&BNr)gXE*G>7I U6 뼨*77mܐnQ@!I_"H]-V9.m,̃g;=ઉŤ7Fݫqh3#s@pnvSzCGG$w9Ny}TpT8%m,F9fXx<|0d̒.F(  ,S!9Ss'ET#X_!g:^Kꪜ8f711v͋.T~w63Ӡ+t\%m"\SĀKu*?&ᑂj=. 8,<2gB6Rl/g.xJctx6m/a{{+^m'%3B`TobR1}Y:}ůߒȃw[@SZDKGi*pJa-\"en0MO#YfH[Ɩ[G#/](8ɔt6^TjINCM~Sl gdlOlar4:Q/*Liݑpp5=b="jto͗Wp 5-.搡v ~ +Y,{w›Ax2bƑzִ0\5Ss%f병|fyz #Jݑ}57Y{đ v(z2瑀OBmAܙב/,@Z)d=n:>So帩 0 SnnאuݦM$^ԟN6cU,hF%qE`[!Z31]8',[h2&2Xrd<6yVu5;pDFN48X0``)g:!Za2|y+jۏʅL􋣫KZO=kQ3h@zϹ*" Ab7VOaj!i[硑u٥JXgrFx5s3:Rgq.LbŚnyJ(r]Q!U1Sl=O⼹QkQő|$R"0= ͊L@dQ8~%,KJԝqϹGW]3)⻬j7zʑ߰*lQB <4LE2i‘Ih)2vf]A8u*],&>VƂ>G.$^tYBh wx3Lۍ^wd0 u^ ښ(k H?Ӥ*)6mRaϚbq{>zzV9A!FO,mc ʒ!Y^E7tqLS)G wj.Y񲮎*^ ELI5Q+ݎQPh*G46#W”,}`+80рHam;ǭ |{/^م~2@a hVG;{lW'.RKpTkԈR!]w`F5iS/+>S6$ sZ7C@h*e{V`t1yǽ{\R5`jaA;Vv2ZiQ^,ђch% (yPsd@-[/omf%,P;oY-K^y[X?stD;qCcݣ9˟lO1[ Z< WP}X~nK=6;!N}fi%_(cҦ{٣I,jH5) Yx)5%>Z8үITcN-#K@XQ)N"`>?g4,u.oYe"w^dIN^o`CK{ "K#񱧈ߝBF077R@31MCX!8w@%)[&3M^0,qZ!6MѢS {hGAuu™%A|֓z9i$}F;}S7sUʓkG{EPD;).`(kE%S.X-)bڝ[#(' ޑeFܑrp<&uaBW.קW!(9- FceL^V <~DLW}ȔD :%8E k[Hp\ {_6!ӒwbIШTdÄY͔3 ,bh4rR䶈 zPhW{gva ~x/]yaҶ+^fM/DiuCxێΞsyi3Pi|2/&OӍ‹HfQ O_f'5DG~xhRdЕ``M[rؤXE`A{Ϫtʕ|J 8pB #5k*퍗:Ъ81$ӆ(ƥj{v$6n3&_?iQ]% k}: %r_ލ*OФt4Ͽ[UPFd3FPQO sڠp6@Iz5-H:.oDU8Ul;zbXECX bwCQ\5#JC[DgK9AT0>%qɦTrXXbN,=eP^0"+۬Œǜ cۇ ^c{Qix`pz r,R |u8ACSHF aXB"ŪrImSl,0F8 S 0ક݃"0 v^}{uϕĭ6S [eX 20%'[JK s#SC1v2Xch΃9Xftj{z>.gzr T74'Ѕ.?{w,i ?A}Σ/Ko GVKmSo;>>E:ƳR`Rf_Wڝ+5MHsXYJߵ7-Xq_),N ܪk{ƅbei/м4WC}PaC(PdۜDK]B@ǣ- `k)lN2Q!D~.rbƖ+пPo9-(_~0 [2ڕM/ZQu*!@Z:ӽzJw82!B&<=VZ$~B'̮@M:;Y\dЖB_;>]-=IGgJ^w1GNu!QH:[~ ʏNW ""oFM#usکc#>NgN ؖjk#0NךV>ooHg*^ǖ7\ؽTpao%pDhb6SVOD3„vn.tLM8px^`A@,Hx%殫F7'WVɶ5F>]ZPeB~ĪBl5;rO]lb/wĖZ9.oTH9,#wtZ'I* ?mS/cȊ%O[0~Z#.ȬvR;ل'-6H{'L75RHSrg'p閻CۈZNB >%rȶ%^'0?g>"HB[g8bnMzLJD ;}=||! k),9^%rwxb7m0)28ܜnʖؒ%,Ü2ˋ;e!3s՞ FT)11F,x^d:ۮi۶ Qm7ٍ̳qpU{5Ybt {%MNM^F:"}Ӣ <3 ɰ$=ut@B#wDx|RՀ`ZjHA  ;7EaY&BMX /7Fv5 Q6hcEI!|&Krї@UG.TjPr`YHօv&myb~bȗ +@mvSPԇ1il؉ GV$&_MFDbwČKB1 /~grb2kjNІ]r3HsJKIҤ7sޝ*;Xj ]?4]@IݘMBtwe|KߗDGT|ޥFGz5GFeTKL g3n1~/k2mPpB΢Qy>=JCQE H^)ډµS?5"F"U&WOrVUmK!(1VVc &j[?nLϮETk!s^jKtA]r_z7ȺVfy D1ٱ]D0Įߦ<7n1ϗ-l~&.q_pjە6)%76L!o* 9m'vR}e ˈ~g9D'*Fzї)a^Sd,0jNHhu|g|)$RZl{Z(<ijp[Y#E:!F‚dQU0 kk"<*c$ђt|80%eG`<=,>(FPt]>2m}MJ#3ٞ:uę; 4<6"3 )Y,9Vv4BXKv;=Oʖ/s5M$]@3~+=D3#2h,vo?MX Wݡ]*xvd%GZ/'#jUULsCNbˍR.JL=\9F(gbx餎Kq@ L[7;/eHۨY櫚obtلeX(-<;\m^af"Yd[ Aoi1݉mlߪ )qͩ р৉w6%h0͍덾97wZX*Sy${17}%}#l*z>Rg/h,dϡlkoK]r'p"ePs+LcϘ,Q_Eȟ*pSլmsH2w*Uu|ev|zv|qz? ˘ XѶG[@&Cf0,&@pӃ')zS8;8MNy8zm{@h+ ӪV5TJbVORO(s ,lBÙ=I3ka`FDZКXb0XAɅ^)`s;aCN ٙ0ElTR~m& 4DE;y&*XcQ7AY~a6 B@o7qB#Sx,x?|</zTwkD~fv16 Sh5{ G"UQ}Ay=5όh ̚@׬0 yՌ{ RAqCc!;__kL>FB(FvkbV1cH&8)/Ԝ7vǚIO. O9IJ[[pngJ}gO.,) 1JMĚTڎZ%ůJ4ߚVPyefqM[jV&VJMP6XPZ#횙Bl5!ⱋ0#[)~kQZ՜~oEq 4'ՠ\[_B,K@ 16r]4ٹ#?<|xiU#uКVz^MfPr?ujĥj,m[9C$p)/"z3̞cfuf}{jFo ? vHL2S&J&Zݝ'b\+zdzŧr@~3%E°3ՠwQ3ٚ'7/1H-u[KI1w:V3#|fC{7.ܶry='JAO{,tV@ﻒ\}~^-XE}ekrήN6 40-^s}b fhbo28roT\G *{`;4Pgc;)CO{/<=/T>f;tݮhcCL(Gґ;H~\yS"U#F8 G(ÛA,146 Inae꺟.%krKIT>ac*E2:ywq?\{|#63Z9dPWBw:T蝹p(Fa*؀ߛHP헌KȆZ<jWz5h;@ۄ2ag6_:A]h(Ud)ƅRANj[7eR:g Gڦ@{ڨİ0ά.geӋu97FxAqD)% s<-ApeGȈn8VYPvӔ(psòO}u%A@ixߜ ^kʗ;h<-ۨ y]QEwB\0LUJ?z}E'hDg54磉븜'iu¥\_-KH]|>H`l]O_Kh)̹4;~Y˜h84̘e+1PkW ׈"lMΣpd!HС(sx]L@yTz&M#5dMZ1需Wۘ!J?U|G2XJPW< P}GzrS64ހ9| W%NnȜu?LgjV{qLg@}\Ô{ 眃]E|kCczҌil{ʼnxS*۞l?_]vK]{/OsM 䜋Զ@_P0R"Üʞh)jX8MUmhv_Y6B:VAMG/O/98=3]>2]&i燜)=(^_&PKcj#k2+~Omue)z(MbWl)I}&3䏛{EYKZA/ ěwBj]tt(^0U'"ÀpÃ_t% ɄHkԁ19ǜPb''XJq76lZqIl5/-fPs^Opr= ^rNEzVK[ Ʉ za7׌N)ʣVg= Q?"{lc+nJU9e5Q }%>cxhX^ƍFK7p)O Ra>[( Q=+ lxmE$t:HŨ4bM&U$-"t:ז*9DΌ5549!„5ir (yr73]`{}K.o4LA9O(m cs2 S<ȁu`o>b%it!DH*>M]iܨbC7ݣ! 0:E}^c<@ԁ´]LJZև26DnP0]% )C_ <\JTK >%҅^%)שx돝`C)O/!~ud#7۾uϢ5f~3:B/ڒAjE#vԋ\E 2nn l| 1qc[r> 5Ɣ^.|*sF唝tX*"絺f7vHƣ7 l^6sGV}ؗ3j#坁Mnz)ARY @*](ԡ 0𱝍a\8Č{W^/ܱ(Y(]=ki]QpgwRTR]x1:8L9]Nd $Bu5nasS  z>`>IT1N;&.felAd7RG^ކ OFX4Sh仺N> Bry?靳xjqtZM{o:gʝ׻ f="9,-:=pKn jpvؒkǥR[{NFs4?P8:wȝLf \/V&+P)`Xi@$пP߂ʮd  &sC\V˚wn&'AN_in옎RH[襢0,k ~Axe*pu (nRJ{b}Fǽ@b)Aޜ'FϾIlAsx;pDԀ4o{?h2DP?ܞ=]5>%ѵk\iD3WᙗP3mў8 1Y;}KFNV=1Ŝv0Чe$ŶMO3Sqb|IHn[R㞋乗J-/6&̞ !ά lPa򞏻 qs @i<#uIn6zWRFR.gnxoe*t%1Z瞟fkc;dˋc\zKԾ& \5UL9։V/ g+7-D*]OO)3{[P=.fbR-Ph3]įDۀ ݀1p\ Bb`D{Q'ye [g|oÊaƠ˞yڹr-Yp%F';LD u%K7Qʫo`GT]4_DMTb->.kAHH67AU& |D@Vִ᳞)YFoQÌ6!:ЫƊYq*U>{}"ꪓv\,3׎M299"D y`Va̬F _bn+MRg+,kS T)de+c,Eb-+94DG+b֦9.Uˇ~~aàkrs?**ÅKQTtd.vDU (NK1N*S >MƺLTG*Qᓖ FXQdXH#.m_/( GŽ'"4̶8xlY\#"̋&#ky!ͽ>#yˊŒI夞'ո^t'Vr50+3WY Ÿ.h^0e~]l2FS0;-1\YJ|l+XE)*Qe&WnwቝÄ?,ԯ'_ JLYGZ'9MeeyGaZzDlswG?e*vdFbTQwΟiё)T~DȐj@j0ԉmk3mʎM^vsnMЖ ?ߺɨn }dTRyI,g*$P}h qA+͆8؟̇(/"A S񟜌X?ϗӒ!Ie8y^NS@7afcpfY?AbOXY! ժ$8jk2G3fuN?1cVuSCUvצtzC<&}"՟ύYޭ03Yx`i"ɳ2\U$҂ ޏ'yLi:2j$П^!*ww\:-b|X U?'$~y3+lJ}Z~VJ UL*ޝa^N(w#5+5L^g!vVXw8nTZrp#w%U/*uŲynvO Oǟ ;Ҫ]M ,{@ٞNfcaʑNCqJ-SRwWڥR4"Fӟ.tλKECoŠ\/;E.-VONoBҮt4u` 0206:Ga \] RRVl% Hv<J(|`RbL /WyjTOI6|Osi"ysxp1kgȾ#ky4VgN\ؒ+|:v-j8l)5y tϙU/'ȇ.88uFXûE:(GP(}ˉ`U\U=.؈,8,MKUIYtaXqƧS XxNZD}u:#NU]9Mlq*daCќa[$mVCc(J:<֯@g UhBhvyBHؠnmM}`nմWl|,q< _h{r,sc=OfBь˫;֐ y-˰?00/zrϪnD,BX@>D%~]DO~j/aHΠ~J3 740?)~:Th`;/ʠ_{*`u89J&*4QN#!ꎟKU֠M9J(͟Us󖠚Ѡg+c{nlU}7.&mrRؙB -mOk54b_g{]bn(gxf x- ÀH%yڠN 7(dZ sr_ Qgt8Hs?|)3e^Xܓe(5"Ӓk:"ӠʌG/cXf (lUL9\Tb?}ʼnp !Ě#V :^u=+ +{ Y!bQ"}]1^n7b<z!}_"ƱcDT`@oB#1p\$ݍޯMY׀k/(X*%TE0D+, mK[Idy9*;:=W{HSLc'_ؼ6/^* ,hʡ̺KoGs+Іu1$ pΡgJ%Ad 7r_Vo&t dT4ġ+ O]{rt'E_ =o1iBس^ņ_o24 +L止76MZ! 6"WrЦ:Qmx;Lz;@ʀ'P,[~ [6=}u]nE}TET[)x<"ЀHofC4KBFSL, bd+2ʔU!* <ΡVɰF=¯xCP[#YPJ?xUOvkb {.f$=cڮy\n藵dk%Q\df\ tF%%LoĔg+?ڼp r4/Q _b}<͸W+ӎ/xFxaR UE`R1GE{͢yOlVݻe"?zRZxl'hd`™ QiYB}&@x-dH?Vj;)q٢xw4^ķqDfN4l}ٲ u1L&rS #PO`G2mŇy.]GΣ`E7e4O2\05Jخ5A|ʊC[dΙַĪ f$D_Hչ杁:T FwB1еȫ͢OpNP/7 rˀUWyBޛDlHUXW^K&G〢[rg%YbRвeރ]hC]ϯjDLX`w%5$'AKbhWzgfuLPD+~x<ҢCB Y|I1(bVn}Fzသ-p5U_W/p՞[vؐ,UkIIEc)Ndd VR~%0a*DKcBҘs)aB&|Z3|kF^0΁7Q|=V须u9 M{&%>!@6Ūen@w|mox4鑮Y£C. E.!1h 29i%.)Fu6ZI.mׯ({{ ֶV &$I1v\C|zcηtywɩ?Y̺wCm/!bK8sf<ҕbb5o(kd:X'&xF( C{BHWAR4 ]L4b6I\i~w-67<9 aw9 plfY Qi-:Wx L~(}z7<1vJ+e_G+?{ژZC;`0Y{BGK(5ߋLT(ʣIM@ْ[3ׂiK/n 4V{)T6J\}hA$B؝wқ'^ *ޭ5>LcڸzCN@FD}`Dvf]uXAlqh v%u$ڹgyL1u( 9x0BVDN00Ɉx;xVlo&l]A!PD6K;RG;~^=ȝFL 1rPq{  KAk& VAVq4ډBI꧇S'^'WCx>뮢A*:ӗ5ZrpH5ri7Rw+^e(1Սj\ HpٺY:Fx4C)ƣܪZ% h몀=AqnhK.ELIjͰev5]*Tg.j_6 `r-2jg説P; #U9Ť2Dd2@B{s .:/R[+Lv|KcJkA{/]nM{Gt4ʼnA/o8=>ǻᘰ0a 5LđxyYqA q]6a ֤BxAGFh bC4zD jI)vjxc4~"֤N 歮z͎"-NC;I@2͹sOQܝXbK פTAqZYѽ._!CY lD fzÎ&Ϻ輏W+nݧ94 N"qGI)ހpd:88HN!qwM@ 2X81@z#&cL2rq{=jBOhAl箤HOvbTbFC qsr5h[+=ƼQT"=k.ZyÂj +{Ë`QaݠI)!K{qK$_\3cwHl5%{CJ>dQ u-5|&zSY>¦dxY9å[[B?J( |_jf: ʼ8%dC^ay@"P1I"SCe 6N!M.^lG]+\#Z1ݭ soK&tNIGu3DC0g','}PxoTu8ĭGb~pz3gVVgxpN8sa>v1M,W0.XdzS*{I 3sf#&uH#vPWO&ĄrL饟S\C?:nGs>c#,i W?[ͷj֥j~A82 e3~ҫ{ըN$^1Sd~C$x:vPb8< kDpưÉиbl)0:X0K~!ê2|K&~&A.ὊDvIshڏg^z,kU2+$ySlܞĥi}⨘Ց*te$-L}z)ꭋ8rU48U{ڍ+."D̹) ܝC%V@%ʅ⇥]D 8ݴhА+i|x|8V^tk yʋSR(K xޗDΩbrMl+v ).Lh&qWY2K'{Xy4b-G 3G>vz-JxKRC@/n"}֒.rJn(¼d&BLJ5WFjҦN} HM,סŦS+uߢ]O܈!Q]|3VK&.kԦbzF3fK(_`,l]\qB^,;~ŻΫ'ZbyŗRE ^:y-C;$W| 6|ώ^Qx4n-:4eƵQg{.MCʲw${ Hl<Ŧ[b R2W,\4{Gt"V;elX`\٣)Qqn8U`(gdF[>AԊ*N՗|ќ5ڦVĦdy1)1n6TYJфz+˚[ǦeBFu16LXDŽ5~2׫2"X`kumhcDU}զ}+D}ȭx@і-.~X "Mpx0|dWt&OvdZ O+l/-Зg?`-y*HD,`V|E"21HsEgd%o ѧ1eHc'q 4HfX038~H7C6fŧ=P!#bbո~A?h?jŝOG4UקRhB/!ǨV%)ʓS'虜`ZROmuh@Şj?[s^nG2]]S#A?jkϋWmC}WX}oIeP%?ӢD+;Nee˧Je. 2ae/q 92Љ_1(95eg}S;ȨҘdTMwXRv[$ Ϸ^~˯UeyLD[5zi7hGy]9N&S65jP_o g Ei~P}m)ݔzص@. c2=- R]˱v)<MAʻ vEcGt[?%ܤҘEPT1 ^mD5%O~{~ki1-/oHC""B]ws1^ 8J-+ldᔴ=L 5R;c>ÞI A~ T>OoƖ\|?#3.mmA.=췃y>%ٍP NQ߮²WAE)7 0ݝEH{v,1utf`\qI5f%m&FDIJ5%wu_TTIR:QSвle?/ Qg:-Ǩ@=)f $"BJ\=̯p7Bӑ R5o튿K &bQQj*Eu8ͷpl=ܺlxOQvU 7"B04_AX& ȅ$7-1/l^]sF7;dB-QȍlG?ح)7}(tBvwl2;[Б36L T5CiV T]?AhZt|lSЬ~ߤ4!VicZC`h-bRS2u:PDZQKiEd'B,ÛRs^ c|.GG a:i*f1zAY^W#@˘[ wP&"f^}d`YcLieV%O\*-eh!5ԡ&չ4rla~IB!E^-v8F&f53t2tZީ7)N hV29=C|ɱ#Oa^ Uu=APSWQMdf0j3Z#!8'Bsӛd)Aש([ȄY?XWcstwS+  ZF̩0d_S6!p |̭h0lħKq*䰎1N)qv lq`6v!M2;nEtsz=8 %[@TgmA{ToUVbYUѡB\ԥ}K'8$&/]Be%Ȥo(;-wX ᐩFQ̽n;'Y6PdNpTMTAۿ\Pfkw6YF%anG=͞]թZQ[qlOVbe@{ˡ1 ^pR4S菄]I>,A.1F\_##7B"bWWM9XER $()&ǓȠ$E0>߲unkhN}o.M~X]sLenIW{O N{){n(3mash)α !o1d\ޑ}Hd.ױwood8Bnc-JS]P4_I` ^0rSrE%s@H?5ǩ$A;&uJXݩکjEIP?̤2tnY= j Mz;3oԓƛ -7%9~kc0+5U<6` >`ӯ Jů) >w~N2+k7G޾4崩‡%wݑv L֩G3+짗9Z;XPYq.fv <*+ܪ \0vX6%9;4ΕzrLNv|TcaRIQ׶T"g ~%n'Qho`qRyB>&6;x*ϖI|_`Yt_9Kܕa-` YԓD^ufe 5^FkfZhR"Yod#1*vP9%Ǎu Fh!a8@#p崎8vK&,GEA BJǒaI:T~Oj\ RMM{ vہ6_OYFuN0h(FoU&AN6_I"|q»f|Rh#M6u"mY$؞ƃy>[ZXSO41$רb[Nv)Z l W\%ָadg^FWapGӎ;2MWo)l+7is`s{!ƹGP㱪=f|=M^|ϯ|dfT`ПYw-W(|fG;K-RV;9p>OJX접 Y62_: sj\˥VUY!^}Ilc" :wcnY:O*;TMD)P\y6/P紽s,cbN'>epu6~J҂iYUֲ#fmvr6KzySVHQTeؐtBWjWg9I^u=#Tq8?[<@O9c8zp5ߣeю@d *gO]I4x#X~Sb򂸪8:t p~>qk&Ϩ: f\)(Ρ:ICSZe]h]82Q)=͇ w $3gT_#n Uv(5_hl~lZ#"^ ԴW2!6oWiuv Ͷ< m/ c_ۃ7-*4/07PWKګ+X];x50YoW, 0 Ď64J%P8Jّ@ :(. 59iY+;X7@FCǞeՎTE|̗,;d-眮Jɗ(]Nz C9O/䃺E>W]-PWSJe̳}šIZxS0Ԉnʿ_Gm ҁ~&Bu-!(QX )M {fϵDe2*kFp%k'1а~~jO&A/hzHdxP"ԛK>V~1ׇ%ojqdګb!`~&ʧM|d:o1IFd@L竱r:os_q\ؠ㫲[̗@4~NJ , ҰCy?]tSO'lbOF䡹uN<:X8Z!>B۔QWF(u7Fl<N2 /bn٫2r׉> 5n<Ӊ 颫u.%N2Rj(L104Es~]jk3!]^+mw4(ӈrlk~wf#1On`Uz.yt.뮸<uߡqз'߽aO}&2q`^c9eZ([dϬƕhv^ۅ!1H'VϘ9+pxˇ3RD7U˲D!K~\A=E ҔC鬮Yyڨٜ_!RӬ8>߱6ke=ƴnԺݖi3#fWe,׈x!=8(l#Po hkʶb+^ jؠtb=YuO["m4,sybl3Wc ʁ_0US21nL#Ҭ,yšQ74Y\vd6D'8TnnXح Q#X].}Ŋ8-T؆Si8|)?t@IUY\5o U^mQoa缬$1!ٶ0 (tbX/1'+p9Dh7Rŕˬjn0}?/\VAæ8{bH4'%CeM. $/(djCbSnq:=FԼ> IܹI-IE{yO;[C2ʫ"B㄀tG#];о 0ݭGQY6~4yywHN|ވK#: |sJeK"4 A4y5{M}.Ayu?lyVkB揾/ 8drH#vwI+}1?rHS;l<ӮYhz$6`Q [.=3x*I+ρЭs~j#]`b<K I>\+Xρ^UhŻíT ^r)}RäM GZ[ l!wQyŁ5 Tu_ɉ>=R/UUr&Ǎһ6%!sEf歅׬?t2b(놭'-qcdm hho~F!a+ /שkQ熮BpNb}ޞl2m(l^svMYtfzuR?Fl% ]Q#_v䬷C+,>^͟s^i-Š c U/M yϖ<7pGzoA馮=2r `^;7rOrN}."„l?îPnA= %jt*Q̜fu;F1G_Xo^fo.YO[ѯX *bgUufԂ4[X`X)yei:%/$ EY@~)pe&9_(?qu|8WF?tʮxڦH/[#\o{7kQK[ HVe͋Lpu-N*p6rmvIhl*Ԓ%߮@WJr:9JL(残MurX] Ȯ]^ l+YcPocN% Ru 4̦7hNMxcMw|!dϷ BƜc. :z.u(gݮngEôҌiZ9=4}_uWUA55FTLPE֔z;m[ tR쩔q`rϵŨ}6U1@ߥZ$` Hsr Wm}8ibc /ɇ!!gGDL3ߤ^F`EQ!?(̃i0twrطu.GJdאظPT3}\[j"Rۃ*6/;eP6@]~C0Z=ӮavCړ6H@_2[ܲI-kx{$]@5mliVSuP2P(_cpƒ˧(W ݠ]kd;hlwB.޾BЮM rضAT]k|jrȕ<`Tmi=iaR5zvBHj̯[S0DZWޑ<^xXm(S3mlhޗX;Q?9x|ȓ7TBEg l|,1G[;\76IElbIU^fOĚouoG~ȁŖtS}r6oϊWu vZh3zY,#^@,1]O`Yc3Vdm̼=`Lgxt"fBAanF tZ%^^|lf^F\ڑ5Xni_>iD|<WHk2]k-:qy8jNÑo,M7Adv˙}'dg BxY)Z5r({B-/YP1ԧ (`!29QrԯA韕6 |Y쯚BJRB>蟯dC"Tc5__#ۊ/LOQEwB]G*o}[uQhfW g"4Axވ_Wo5p5k*KZOLɛV-7O#,j&GH)&mokX ܸ۫W]DB]vbɯJ Ղ-N4 ӒYXKyEzU$yۯO}RsVGZ3oN:))jl߄7}hm93۱$ƻ_i];B)M=\cg`ɫԴ=ӨCxqi 9 vv: o7H}2H'n+7OMm B# чbQwEBe1`\ogdM?n3;,)I-+t#  Q^$u%qo&RÂG*嚽51)/;(eQa+I#<υ+mu\:;&[:ZɈ }ۮ K\=݊p!1ADI萜SanDu])rܯD5{p\cqhYSҰ,xB2s$nm鰃}J2uhcK}gY`jڕdNtURMRRew9zo)YNSt/l-el -vY\zeUb!F_OB¬׻:4B=5jjÀ[#b5w9UH}M`"b'ݰǼO(ͱ\?t>H24b_^D;O$wyEp;!}D#!K"9r_^bp ߪWҰ:^_Oۃ AԒ\fZ?žXe]FȥyޛC&,°6nK#5w,(P,;U'V}Qҵ eZٲDկ?:d]=g/%hҬ 162>G'Lp뇧tg4bWWiºs}JtA yb5T1J|9좎O8]!ٕcS@ 'Ĺ|2ZW9 '` ,Y/Y +aeŲ6o#ZΫTY[>%}_)H Df86~4cjNtso]%7 Ҕ88\-K?#աEC$"!(=7TagF2'J㩴:nlbXu 5X> 9xWJBqLxFzQn1 |+ #O-7jz#Z?]~=m :p=o-~P7c'А~5fU'D`%.cZ߮=sf)kbDٌњyYĄ/ytfwH%Yd3b?Ӟk]b*v).( H[S1oMU5$xAH1:"QU~w✣*tcYm/vWO5 ZiXW[mAe`ߓ^鞔,Y!ݕsC#f4mwO] %I 1{ɳ9H ho t2_Htwu0t.-5 hA5ϩK;J= ݈$3=F@D?-3eSj -gw<=*35U5[]IKG8oq0socB@k H =v K ^EH)c""~ o SgZ,7g8$v/qv :;;6o<\Vo =!Tf>s2Ֆm ˳GuohmJAA Wю6ԳLU}@F#fP5U9xc 1RB~T9;*^4 t!2X33F3E)W=س^S6Z]*n3`̴|ZojZ+:^pr<xd޳|̳,Lm^_uYwt}z߶Xy\R%~_GcMő4|l%`8%K3JU)<&zʊWG'R_³T[#H^\ݿEKͳQVl:P=ft[4qmx716 whKJz `$8L*&³88"X(hs"M?y"7t5ÏH(D~D: d4`mbZTt|?nA69@5?ZJ‡B̡iʳד,\+/7bXү ~m3uh`^JoGT\ʣe+)!$wnѡ;e-YHupʳ"/[ "/=Vf r,S9d&0\ WKô wT,nyP]-!aQSnes @&Wr)g6wK/2#}kE((c^laY/ZL1B_XQN1G7-Q*^ jߊ}C3*~CdK<Ƣ.=@X^)?}[3=-}m@K7#̿sظ4ô=繧"TՔ8Jn>OfDN]T#JdA 3q(HE[N 1,UB}\O"/V+P$6tQRYD{Hp;k[M+X@,gB\@ K@w*9ٳ]*0^=Fhae'4!UIxgLƁx~޳Hhl\s Z.PI$F!p% #w .U.[q3WNgpU-ݴuriG+JƯ#&7޲l85z~f˜<k]nP]9% {^!q1U4ZAMm _ϴϹ.5 ru WӭA%jpn(׭M`u] ^Ka4 } ?\,$8=9FWX¼l:  <-obbVR&ab@L8YS8C{,%{ [#+#bl+ sdzuN[t - 'MFFhp@}K;9AX 0,G C☀[u/ugm_ͯ/P>q6j×_]ǡuVz !j/$mCIsٵǓ`:n]0v{aVͪ72&3N ,y{a3#]wPs39Ӷf]w!D؀xtT𢒾 !hvH9¶ר;Eٽ:K$q]X堑E}1CDNte &XU8>U۶*hrQ= [鹶a7?LU39z?V P}n%I3ݤa,T5۳|z.@gU {5:B4ۙǶ\`B5EFCBgqcRɵ֓(|"H퍶c14?\>:/Vk|tC88xp٬U/MCwU5fmT\2ry\$WkS}VS6#6϶( '8"Хc>ȷݙ 91-qDut."m&]A\:gmCY~PIdrPW$|rycmi8^C+@󼶢}- VZ"HCQi\~V3Kl@+'k=6pmQ w(,^PÕ]V4Q>&U_F9 4%be޶xϩ(+TWYL-kS5JL*vu}9[»w E}(q &k޺.}D= ']kut~1#c5PLRkRܶh%OnW0!wZɛ%$7e5 ZO|jcuYJѷ3ݣr؇UD;ĶLwD+W8T7~}RfTطYh.;k <ݷ& r:} WăJ,nކ>F |o /!C. X抽C4n[pͨ|iFc@u[tݤ9aBBdežd=ػ]*|BS l[܏TFEH, S+řiI_+si WTJn^͋bMPyMқ@Oϒ#;xSKR?WJF'pH\Xf9ym/:D[2|Wb$4]nYũu pFOηcgY4.Dcp'e5߫IAT--j2A|ycbӹR\metZ$k%"q?*v0kM1\C驷qx>1l%ws/R 돋zPÆFsOjX@-Nt F-NTBѫp '(qFޑL`-#)c\㹧Q!^[BB3}bn޷J熩mj5zXHǏHrG:@X᷻U5cyQ<)AJ~= m&)#(gjw!@Ƃagւ}"Wd+8=R(ڴG_b.>.fƿǭ}LjՕ焙P^sZ4طIO!Ʒ&,MϘ,Vb{;߷I՚: pޒ8|txS̴Iq-c# B4{&=Ar"z!S_d3j=-䇷4?3\ӧIy}NIt8;ᔸ ,BC@hVc뗸(V7w:#s>]41PHk"_hgZF'@%N;T(?{ 7yh6"U`[ЁBi0 =adaש蕖Aiҥh`x{i\%k,M|L OP߀<~j$4 &q"af謁 :KE ?~!fL5rDW飱o^n̶︠H3]I$]~?*RP0&IMtЈ,e !z &ԐlVT]X^%!C(?Č {Gkr=2uyRUu"q˸>%+e]nYc÷z|d?)Utɀ6KSةǹbY{rp(.#UN]ϟcUkΩ2D]Rԍ ?:oNbV^T;* g@> Dv! L6H20fjL\uq4 + ˁ73 Y+I?@OטĬ[`T7@PjZ>IA M= UL;B.KhNiHǦ(SJ4N e5?0,[9tx $MbZL\x|۶ٝܤG_}i EDŽNﲹ``K]Clbj%{?kiM_7ۖcOv R Vdz$H;r/AC,FjHTg exW"4S ݱP$a15ɣa21m%gT/uv %)sWwjok VO_ Y.I`ȥG幥b gRE/0^_ygYت$.Fzhm>14% $vv@}ނ()(KBW0AΆ]΅m#a4a~$8Z}nX1 F^IJ8V72de\qc^P!WMǯG;EJu۬qy^E Td^mIb>^: 6̄`8m᡹ֱ5k7>[.l nȹ]؀xW0(_VHwfkҪHӋu8ENb5 A60+@SʞRWst1 $7 yl79XCck+$3K]֡v $~)e,~X+?KS4x`CK;) N_#rc^NU'$}gR)?Wtx'i|.Y\&.$tgP|ߺs`*H^/juz(TѦ°uEى[dt y<=r^vU>-znȱ~~1V#=@ɠ満>ҘntwUDqh`iDrڠ}~%O{4QG "GһoJy+JӌE ss#Ϡ7>Jf.Ȼ$BpJHN Ő#d%Dv3˴ Fm'1/qmqBa).(>~)jvO,+G>d[Htϼ.:תZ60Kܗb%Q{ɼ18`7}f/B&6SՈfY,2`6O1/5i=Η7 UV ̼8)R胜..Rw;e:t<6>ҝ!#v}R>MQYhDnk5F{";<ҌˬBJY8ucZPCT[nԞ^׸:Wj b"F{ Mb-a}^(iGf6(v;.-FԋlZJ!HQ- M4Ir:')*$HC=Qodz {|&4]gg{PQYac泤S^::^&*2տIU(gNMirj#g4OD=ZZ|&OQaV<{7KvY,oU*`W ļGae@K1EՓй _B3)P{d2`üX)0o57 G}SPa|4WJp+⼩vCN\ԷG.v +NN@@~ƩMp_r<46n -.1ckpJ7EDr)XB_$#7#E<1p*q"GO]Kxt`*(;Bj!cBbc|oc"_~M^ff]qԼre5 ]?NFG>15[ѽ$5ʐcRb2t`KͲ 7D ";Sj߿uI0ڽ/ TDŽ"ߟ6ҽ<0%yjyxh?p?4l`wue½A„rVRokRU:zEʽF K92oGQ^l 5&*^k]1kj6qhpDbj.Ms>D6cBx" FKrK(q ~U:}b!ħthoc_սzYtL%.у౽M$8I1E] νlN}ЋoJlڑgw~ҷl;82cKE)ՒB$3۬ yrq:4Q&KuNs. jl5-)# Lv"k.ݖu ldx&m]Q\A\ {{. axmHɢD7ml)1][Yɝ7K6@7oU½шiifѰ/:'{c"[bǗ1"Շ xtUZCi% =Sʬk8'+T &dRG Z <[㛀[ӺB|/meI8@^WpX K4 E`m ,;hU&^^Q֗L^ AjS?y_^I3*: nd߽ ڃ $mARY:;jŪ~_ZxF3| В -bk ϢTP&J}|բ+3SSn(ygg nN[Q 9Q/i[W7n }(>sYfZp׾O)x(A_.u]]|?)%vS a\`T&$^Z 丷r`Hj)qEȾ3ɷMq9c6daw0-6Q/fځ^e:=5@j0=kM7B:Op ;i<9 -]4C.Mw Iڶ6v+E?p)M@vөL.[ !6 ~%c )s]aٵ ¾̽Ž;^I 2Иj-s^ YkJ_c DEa>h\:d[매F˯'eU'S Ux1^iS:=,b mBBp1ye")w&!&ي:w6BJTPQq%xޞk3rra %[P_SmX}I=A;xGSآN뾌+ayU 9JJiEoЎD^ܓi%fERWDt$g&})ǽq}N D Sx$=ؠFD_M1 E׽|T=hiT&P "dĈb *fLÙ>ٗ\UbeK? ֳaoSa/>OpCMӅ60Zנ&UlHL0HRm%^Yo )M>g?'0Qʹm~húD1S_汮3+ğ /N{߸H;Dz@!H1~X]4P`dMxIUT ҬC Lv}5׻l1WbC< uŶlry1UM>Bu8ݧ_$۾#hT!:M%Evh$J P;uPDXR]D]l7%asLj}PKԂa~!iaq>YNʳfQYj bll#r͈g@9+*֭ban42u/ lɇ7CS,hn`Ard?f=#ƿ!>ya{,^` 'O#ƺna?}+`G&'afG}͡P/^`;M[C9'QgC-;2(g@~*|߷s )(H|>fdҕ˕ <ʸqn{aR.GW/ۢaIYj /c'Γp#ZLU)ݫj~gWuMfٿ[ZCI uƚ%ԒN ^^sF1f2Az}A|S+)Փvބr|Oce9@#:8'NTI@ <>? P˺akI !9ɭ&`XCΙo;]VBlrHCv1DŽ tY!K@_9K$rxC:f3b}%&aFB6cZE/ Pj&Ќ<W+ 'i M7."2.fSt(+th\&eT-r#5P;. w*'C4/@t,%-;H+0 #fa+6,^R~EY<8]$IN[shϕ9Okk;OM;Tfa8]ȭr0<ٷc[u>52;ۺWQɴtjKb˔W\ݑ'L W5=zwM8cP`[6^wXmq 2zX9amqEoxZK'nRbA$CƩKe˝eY.~;fNOʏ6OZ] 5t|sUWL1ts~3qi0s,1ɔ,'yooxFa0HU3fp-K4ĩd~{mͥtaIKകI^[6qv@\ nSB3V]:(tBWW/!2 '?2fm!ϽLj^do(>YOР[AZD@b].-+ PCH<\Àt.~OB+h qfpZ)XzZ[`^ZYGDĥy]k^ ڞy 䛈XlqAa_J#G|w*ZwÃkxw5?]2qtm+ K{^nI5'!58"Fȅ(2_Ǎ3;1!8* Ҥ⍮/!$aDRYP+HilzMe59Z@0SH'MDv0"&h0A4d QwQ?pWO Y(}JE54ŷI 02F>eT7s;k8M_ty|]xaދuȽ* seŵ\2h;n/k: Q3X1fr>`gK4@pouQ68AX߂3E `=}ac܀`W̦H{J!MJҖ G%v,gz@$i,LtNZ<+^n"oS 36[,8(k;:J'=TJdtA>J%ˡvԧAr`j;Dد8Ieܯ{ߋJgi;Xv<0F&PcdCmJ]SYxr*Pmxy |NA^o,MyE݁jUpY&UiA?9zp.%s"/@;2tӍgBE{qtɈXT2Q ѻ&ht}u Mb@ 05yjZJؿ„ƩhD0圫} ;7†Wȫ[ zŒVxDͭh IdI”Hwna?v|Kn)•aSB|9)wG˜ajI KyJ ¢;:N?/"53Ym­dDY[hJwBp¯A~Iv5a/e&+w'1…B#D0kȮu:ԇc hl(ZU;3̼85D%&M|:9pU֎ùLaAQuP#=* Ip[Y].xvM2N>l5Q˕-|AQ.(F ;K’p \ i 1lM UNR iӚ0 "q>Q4Vc9(h|up{0%^`|S]0᳆~X2C3B9w0_tBwfwZH5'9%L8ۨ?l0$e qH>؈a[i,BY6qwNDMZQ[Án;_U$vkÆΦ-Q,H~ÍD8$Y撳QhOÒDI#rकÕfEs Ö7HhδB5ÛLcGy.ajò*?|oeBum0=cúŁG}d%rD'J)HEnC@DA ½(cgᱸ>9x[Wn3%m-[ OI RN3-uúS=:~%g7}}O"SHeƘCU1K%il_0HtL[cv/d453)+ ($vI?y{ 'v#uG_h=d!AcCژsg׿ ׬ T /-J9026{n?7 2J>ÏD!$0:yʗ(a'HJwi^ɟZ)Z(p^-u>{'*?i. L-mr> U-}mqRj0sp-E)5^'ig.Fw'Xusv4W3{F!_#74٣)5EyT7ܳaY uaKf9K=)xmеEpV+4J,论<]Jub566n60 ]{R-, ENv aG1XTa)l^;)}*ts]#dzzP]w;M?=zѾ9uj=}-xRL e3 ăm^f統YĄB(r%8|PnąW;օpg`Ćv@}s:8CÎĒȪy'[*W=ęJ2R~k->IĚniFĬpϜ=ĞC Wx Q7Hĵ @Nzt U ĵ?`l P$yĶٔ;u`kĻR*b ʖ ƫ0Ľ[xqrqZi Bpf.OT>bwҥ4@4C)^CLO~մuq! pJ!L!tV4m 1$  &y$ҝ}|O2ڣ'[HM&dq- ]噬+2u[skZjfDsiTy̧v"kYpmHxWK{xoo AĤwx ,)zœWRh6jyߠ |oo^ bܫwpH:wvlױQG{ ]Of4]뉌ɽш(K\ׁ-5AhZ,/p}"*,m0Mn[{=v椚eFΐER/s`^.,c/{%-D/0&ɬ reƕ^z1pq͎ggH89);u!..9>xӴ:]1xBt2wAVKm|p>[bD%#j];L*p|Uk[UH@ Sy ]妓E"|.d/ 稰Ngt,Xv S]4ŀB>Yd1[7>ŁV4sk}IDgŇ01Ue$K-jś%YlQH녷Šv]a Zچ'ۇ3Ūڧ^N/)z8&4Fūx)bf%,ŬP Y): iŶqwd2W Hď&y;ap.n2%?1ѾQ ]exP/I1UMׯpJ5&oƛUg3Dݬѫ-&tQ4V΀Díݛ ų/mǂ(\0eg`B qU;0x)2Q<0+ ގϡ;66_}^odT_Žy-~l/ʙE浿F4$>V**Uq R`h'- W:߳TD[ 2m EAjRzuu|[Ȍ'EfA d0N}33I %M;VǾn=mA[uReAgZX',Z"6SGq!!Tx@DN!Lȹ;4:oؒ&+6f*Jlfb4>?oJ g(sA6h搙|T*k֐7J4yt$ B=% fG#L™1Ei{u3mn}ZGݟvIMcLQ'iJ(XF s,GuZ"KwIj6yLB"nZa@`ƤR(cGkTswR~\S,WBeҝz2+kVG];aKPKf 0R%^Uy?(0jn.o!b#o;x`'Igےu;{2\F*j@nd|$U,.U]Cє|9ƥ,W{+5@~_`f?s;Պƃuv#_"|*Ƅ0DJۤƋ{+ Tƌ"፾x}Wjn7^bƌ/0\.Q Ə}xRYl^SuƘ)eRҘU2Ƙ.d1'f1M#NƙlVPVO/19ƛf<5-<!?ƟƃD.6a?ƯCt=x(\TܠjƲ`L!d!:w2,ƴz# zA-gyzrQ/dݧ;D|4qҁP͵<2a}B6wRt/bjϸB5p#~aS Ҍ=) ~{sy=vESA G&o0vuέTcFyZ=:/pń l[HqءA?HZItoT2ׇ\6ͩ .:4F3W-a ~oO qQQOٷJyĬ. +NBRUE&oBtT}s=ijHEJqCI?k4Z1WeǎUdmt:NJ'bE鬕kՖh)DjvfÈgJ)b*v;Au<攏0#ZE+n)504xb!. "lǍ !"Y5}3` vԦOF =JMWoƐL 2 /Rl`CuF'uѳdcwyP"4I{YéeAhW|^.*ܝ"A]f;?{Uh]]DiV":ʚy jB:>;P_qE"kT_Uܢ{r$=kWtJst{߀j5 y@&t*zCKBɃ0kzBMrˏFK|Vo.F,hNJC */ǐ9ODA($Jǐ7T6zM@փǕ-ǯɃ8 j)gHAZ-ަ萝QЍ0?+ gUcMrXsƅ`^<3|#o]Fvy e؄p ? "m~ːd9UȝB$! uĖ?|Vm6ւ"p}j'טC9tN}ȝ)\ HSܐϾk>.J,[[0fTvg&r2_&w l:7vmF<@rX)`u6de .l)ˁm9j:pJFI(,Rb:mL;alL\q: rG{ˇc}oTBc s}f10XGҹرq~s]:{iC#)P`q_(I^mH&z k+EQ|egABm:&_=n*8upo{, Bdz$L#I@ۛqs=+ ފ!>-s2 i(t?ws$Ҙ%bu& K  v ޖ`;ȈA'p=Z"Ȉšeo>ˬ=ھȔ ,΁ZIZȠ}h\cܩ'Ƞut2pi+_Ȫm% )@ÁKt%ȬfΧp=ȶ؆7 +?R?Qc~@I8ovHЕ,sghܳŇ#0څ~l҈ 6Ė݂<{!#*Pݴo⟕D/LEv:R$$d.R~sI1D[i>.ݓ s߽ۗҮ"@t#O oYf:Y<|IDe!"n%&T=$b4L;S%)2WUg&E܃~0m)~ -w0q5f'GF脒(6 Gks_)?F*@, "rͯaD%O5N``@zJU mODZWLtp!eP;Ūa=9t[@S>yV'aWSWaڏXS^EF[h!YnR:TPWj^\QΠBX_zW.Z)u'`܏lAmF-Mi5eCWێ4nWH!Hswv6?iɋtўi0CQ&ɌY 7i\S )~ Doɛ\ׄZ5͸ɟ[:fo3X3ɨ̳k!ic!ӗɲ 3,HNɷ*ƙ[vBԨɹ#9A#D99,#c_=#&l?9Ei?D;JΏj}5 }Rz1<ܛ A7rO\fʒ+H|nY wrn`gjqGU?8V̀B|%V~j-Kg’xw}Prv,YtPvmir.;/^R*30R\]q %Sb{鐜iʣ&q8֣eނ_bA! d:}'^WJbAJZC)=bhM*Ǫ6Vi}aJ8;P?eԶGJ:4S(&H2i º?"Dݰ?7P&[Kn>A#R[-Q@7ft@ eRQ$LN6Zz7\U]zϋx8d,hYHFxxA vIW+__eX'fEκ%I{YnuC"f"$t ern'ؾR\`}|ZOwKS|e'7Л\}ʘN__' dʀ/X4亣$/ LZʍ8畋 :ʎ~a%:46]]ʏ&" S9f $ʒoo4C +lʕcKꀋ&k ʢg'/I|~Wʤ`!lz{n ʧGWɌ2Tᦿ&Cʳ~? g#=^NsZWʺtOf<++PʻU o? {/i0`N~S%'F6$Y mp>`qzdN _ՋKBȑ?48AզeC$2B*A#"bޔbW8QFBM]J%TB#<Ӳݪ,H۸xdȅˁՀj,Qk=GPE%'^ZD8,q?tk|a~ֈe b4+Q/2$>,* zώzAR0!1I9r0 U /?d3>ֺ[PNv˄64qiE.6yN1c8~$9B*LnZ+gW9φԦ>V҉2"?gNֲk[ޔdӡA NLC U\&XCyxI2EŪcaKI2vIFdreA ?sW];Td]b"xZ2鋈G&|"HbAb} 9Iv7{{Kcď2?rogcuJ%p4eEpGuQŽ1vw\ZLc }|0:ι18_@{ˈ5UbFv$ˎ[~65r!S˖,_?@j1&˗ƸNy>o&ܸ˘O) ԧPX$ 7˞^C@y p~6L̓Kˠw$hm&Ѐ-[@_ˮX :#gz˰QZʺ;*tV/jl& :s?@JQ@8AP ֈbӐ]}ucR.tdO"ҶDZp *!vۚ 4p1ʔt⭣0p7L#W %𚬠8p-ǰ3~A ʵ]Z _5,aUxM|6j?N:.=p׬Zhe5ՑMg{aCW֖ T{$q#f7]ZV*R0y3DLE3Q qE&Xb\N1~SL,>VTSFЖQ bkcU&|zCck֑ )ctppl0WL28o$l,~Y0d]ߦ$,ٴAZv՗wjϼ!~=)~5H{T*`(LE@d#7j'O\߈ҋ$"ߕwsX-jdR&urL5*h[ LY7y 31PAS$ u!q?8w^|5l &h\+ f,jn|_~x,Fzd۟G2xU Ez@!Z`bnAJפ) RY916RHK+8߮q" VS+hUi5D@4Ciev1i3]dZ!J±ChO)jGI~Dp?3g?3) 5^rsT^ۑc*:@r}.~:*,;Pd0ie,?_L&,= 3$Y&Qm=pQ;6ύJ@EI1봄sP|@WԭǨʆ,ڶ]Dk mLD_x*icT~]GMMUj7D.Mbd)y3mNC2QfUre]%P5/gS?ϻiLPZQYt)!R5j㶣~P%#vY&µ儶~Pc{8RSfC'j _ϟrv/vF[-RoLXy؞y:WډTCFz|=7TLJh͚|-ͅT7!Պ͈ߩ0 (͉\ҀQL@PIp͓GV=!M-9?CͧLa.95aeq}ͬ14iI*f-|+>hͯY>WR7q9PͱڇcVmwͱiq_w* ٵ͸r=/w''ͺQc?Ҿ"MÍ`:*Tu`EgK|ƛOqЏR(ԑIEPڻi8T= *Lȓh>օQ֟@{Ro^D yw)㩋tT?/A3Bxw )ģ|̅:CVN=.# ^7IR{iyLfK+B:@4BAC̬9ˊAw;-Ne@񟇓4 (!x_$C{*Q~# dIX,+}T#Wv0GR?e;9QBW.o1 i:|5дr&־n=QD1~sOH I7Bۚ &uG-d5@oBA7P*U8yTCsrQ.fsGyqoGk/5H!JXl i6,HބƩ(' J$*#\O?ڷYqKurZLSz^=1Qw(=TXղ9 zֆ0zZV)+k߳Qg6p4b dM4 ibtiVUx ~ hՕ@۞D? JjvrÚ] hv˽2q@ClyWTȞܿ\z܉0ǛVe/KΎWu2=fRΎ,Dt3vMVծU,Γ԰$^Oz˅ΖhK@͑]@擼ΛLckyZQUz[Πr>sIOΥٱ_)9[qFΦD IkI NƜ_ۘΧhg&SBE"εF_KqnǀLK{([ո@aX6|T[nCI>سnx}sn#5ɃGNWZHɓ>Za }q$"Os|6pj}hLgXm1/  tn@,t޿~!vή cvƂ2>"!E~d@Ua9е$E<epsCr}rf÷lqENT zq@!Y(Gn9!WEfb;#Q;=gu$@0<,&9B-s|9f˥=MNEHjgsǨ 2N%!g!b́'.!6ߊ#T/(,hyh="}' )aiyh=EJM*rV+D|!+<;peo1iRX-|XRvckGtM/-)14k栃C6\)wA25*+Өs94- ͓J=F%SpeyH>z?2?ggGR*eKg?0UtmBUC7@BA[[*%_.7ݛi[dU UZcyLj{IZZ@L}pmFϐ ˼;Xh}&:ϔĒQJCi\C'}bUϘ|#Lx7{7Ϣ t%wjlmvϨ;2p~w_J%yϩǁ3&gh /-Ϫt.& hCg (ϴ&DMO-EϷ.Hyi;XϽHǵ3DXOf0^Q* 5#n4F#qhRW\ʌUR*L{As۵ f&U߂b>3K* (nSyr]#_On[9I2TcB< R}CZ!P8sP-.N]{ )T"-L2YCD1K@>^_fq%+V칧 *1ׂn[֮Ŵ "oODdNXf<ր]*J7Z dxo2dQ `$Y\m5KuJ #zUڅt[vW"xE#Oζ- 5lWj [Eʮx-e-c֘ґg._3,?]ccEv1r=|]DcuSZ2{NVgmkA&}3b|EH-nʦK3VPPJ+\IB@8XdL F|jΔ'VDlG]+حkL=9I?t#8̯JO)c0N _dWփH e[N:.bww=~Ue߶$t%Dto|xk פ8nf&ew"dl jy2sҋyt 2N3%v*^,eGX#|8*X}+b\Ђ!jYyaXЉz qHL5}Ћ&چn* /K8sД|}` t4Ж4ݱu_7PЙN$)9f cuDНϯAtM>tfLОY&j'댫0\Ц[ 1os6вD&ݗ?HkйE|]Z|.-SSx}k{}4a5Ö+풕fɨh]i0+#pt:j>L0(mc|®ӌHو0$R\"C)84#dj%ΙwD.|[@ B&Ɣ]{p+-~{^&Dɱfp^3*})ޕE$Ip!ѾۢA6 ,IYXY3s3ovlMfB=(Ŕ~m#Ӑ4;5܆2/Pu$aHǻgy0 !rŲSH0#l{i3CiN|F6CDG݃Z>B|FDR;'[tL}=\f^F]N\CrdJmWnqJӋ @PE"Q) RI9FRIaʜ"/RO؉Zf?X3tkYTiA [(?ZaU>kȾX) SZS?MW_KqmC\eђOT社eyu  js(kt?\Zӂp %`%v #5l6p:F4,=5 qRnPiqu\[у藇Q{>^IH_хP}0R˙sц*tQC !Y ѐ=Aɘe} `+Udђ(`$;$ !іЙQ4/m/3(blћjgv `ܶ{ o9ќQ6B仭џ}1?oОѧ!:%|豻9m+ѮL3lUbm8[QXѲY?ZQupTѲ&*SJaHѵ43ySㅎѸɱRM~.?7ѻ{(8gDKѿt*9/ю3u:ƮV:͖D\ȓǖe!۠Z{ȜU p*?Wp+^GgyPJi&9],Jp7\J}3~p'!/i;SB vvb0 kq98B=*z鼲C76 -BN)%EkjةJ?bZ&UJ`m>W%&my! kF'\_-T*}ߺN9[ɡ2/xQks9cr1cvXNPG/62棇1jY WGi8M0]Q8ҡ[voD|9=}᧼>W? ) *#L'?lL҇x%_rx?B#_aKCfK@rev 8`>(sPiH҅-B(LMA1I҇iG (C҈C(~aiȈҟbkP5K5<Ҥ,oKmylҤdn-W`%O.g0ҫ[t|̼`nҫcOD+U8 ?JMGc+ݹRUDV[P%"xՏβA( 8M8،0n]7NI,;\{ c1X> muW2 9)܍uyeٲ[ ʐ^bNNwD k||h]KRXr SZsE$ +{9TRH2"gDB{8 ca1? s}s0Q 0h Dݻ9S6(YBCC7.a6|BWL#ڙ,/sVMzY@dC zoU*_խ"exFB$he}?!2"Y`u%kjyaG{+# aU>wR{(,S ~)['"\7.<֏N=~>԰#1O(}7nF Os@2(5օeJ3nIRojT(vQ]5,9gXpD-9ٿd$ {RCEǬsH_4cXXIḯ(5N 'Z.fcJ=Oۄ`?ֺFy%d&tbE-ycE7q3B E$騞q;JӒdǫf>Y!6Ӓs>_Z#҂:K`ӗQ#[$gc2p}`rӛ.0 @ƁUӟj-b54>ܒӠ@HZt^5 NӠ{(ªᐖBZ=ӥ2TP}(ZkJӥm{ zV㉂ThӨ_Q+yfqEcCIӨvCEmH=8Ӫ@'6)%U<cUӫ'a!j!BH Ӭ8Vjxģ(;qӳKÞ<'U#X3(eӵ LӹI7fkiR&<"Yn;=`!H Hzh`c#sUl.9VeY kp[@q!p.O#羹_k<7GHv?bDbgqUWJ žζhLFy@=Z }.T9 $"\)Cݢc:#Z\S 2nNEH dǪZrDm`ڐd$T$e۩J[QE5 WTlQ_kVL\ AQRQ+QN,2(wuɟ V yj/,[ [% UL3Xh{R S<̚Ku:lވ,Pm8C̀n&QkpIV!'q{s .*TxX}H)y_"yy(NCԀ^sR|2{ZP ԁR֞%f{FԈF]K50 :ԑ@٤5nfB*A~SԔ^ܮ/i.sԗk5GՑԟ<#V.3[YRDԢx CYJidAԣg$\nz5ԧ0nqsL;Խu[Ԫ"(Z0 9gyZkQ!*>^$F'$vȎ_^$$2}lk?dU8a^nkCil?HK;<>Pr}jL>cmO-ymգ57OA9Rg }9*էog\:Y iF|ծ:wgꢖBS.ծg'%o$)-68B"P[(ս,V9y JWqhHpi@1Oק|H![|]c$CN&~B*`>$}NT`l ?Adg>| vɜ$ȬLeNhe4- X ::bE|fVؕz ò)%acdRYEfF0%lzdg\yIJ 6r˱=IMBzeAx4Ʊ69Pi;>-wsBA@,y4GtJ<)߉0rkhm&hIRJ3DE2-L.V.6|Xrtds_OWh9Pg**mm;BTvrߘ)H &6̃(;Rb>5en~' XOH;Kf!FWlEįڵ! O EVFւGKK?s D U\3x1]|.{.l<^C<} rqHݮk&ҟegA'ÄE19s0jo5(1 VGvߗsjPHPD}?HFv\ S @}sSs =g4v̝|ycuS,06UQeҤ/:70d}S+HeF|_4aQ/-Y](%1jGZ m#?"@O2`d\V[Òv+_5(XnB X/<͙{ͤ?,Fa8wϰA/yܟJzEN6 lL8N=5x1|vĔN35ß؃b`L MI`[1~؄7 @1xBRX{sؐk>m?]є+~ب# +cĢmY>ؽCY ۷rތ唹`A * zIW.'6/CCNsV>X&)Eu}QMx_} G0h?TR[ H`GgRoOXKlE)eYP@ mY`.gl0{l&.GDiH|g5XoEnOzx#&ޡ c9D$q|zav89"p#قv0k fx#Yكzp[3ه3JeV^يh膷ʥnzm̌(ٔ`nזY6ZY祬X>ٗːNMAUz(ٝ6{}" h ٢y Ƃntk٢]ea *0٫i#8ڴ4u/iٮ_WbE\72ٳFlruS/{nLٵa<`1l蕲-~#ٹhb}i2('{#ٺk,s69iٻE dl̛wUGٽ9E1DpHH Y]C"8[m užſsc U鸓<%tg0r0R#a4$rKK>mEnʍ Q,YCdˇ> -·P1M%B_)A ?e meWR4r07J oA_8)x:E45H֧g<*-+$q3nt.ML;lW?x/䳢!.7V(bÝkgg{PՏg.v,Ja^ڀ/S}zNLF=JFz;eDD! Ċ7qWǶzuJ ( zͭIL ͚(Znc7ga?K@l⃘ΌV݈ i12`qJ kËPhS.2YѨj*yF|*-a}'Q0}H+6D3E.5«of|D `R4ߑפD,vi#:;Л^ve3@\<OգR;0nLW Im^(%7+dz|WeZTB_t"_{m; M 8`)5wQVdiQiA*2˟BfN1ҏħjN%#Zoc 켄j?Q }lq  ٮnykq8U>{*G2xN+>8ȅa 5[ ߩ$?[ ۦځ1!.hޘ& ڂ:Z822HNfڏP0y`jڞT׽5_x3Puڤdoc鹣Q4کO>M \ˮaڭh*1cmxڭi*L=C#Aڶʢyժe.wv$eJڸZCm_ںBR**ʻH/=Y%`+? ƅq <,=A\v0eۄ-dy1=4?w%mJ/9ֺ;^f@]S ,ӗEV2Ste4K8X;LFۃ SBjѥBۊK3p`„\Q&ۊ>WT~ۓ1 |qnF~ۘSw'ڨ۸RxYqENŝH/c?b 8w 1>{;˸cbYyMM$i* #A=O~y`3W M!TKӨNI7U-c,Puga:FZц VP9A_z%/#EPcw}X`ZaxBSikB.V]уi:)Ĺ)E78dI bY'C;kf_Z٘8!(VϚHv[,ul"VFXW]5/VPt_Jpa;FvAIEMl@H`لw I `x}ZPkK77^J k\4EN]+ҐZ\UmY'0,j2\ϓYU19IRB04V]hX՚Ar<3?gf2hGkJk{]ev6[d i XL|1(A g^ފy ~p+%XMlJs݁X' Bl9\7h݊~0̌jub8Jݍ[ЏkE}~%_S/ݑRβҼ-~%dW{PݛZMSY; aݝZ/$HEYZ E }aݟ% M\l7ݢQW| >讯ݬ1PgEλ<ݯU>ջ1!1ݰ 'FtXMWݵH˸[wcݾ' 8#E==r? PoQ+/e, ¶riAN8Yc ;9/ԡ4BYK3t/vIלa4}#L81،M% (D`n=8!M0^"_nco2ue#'wh5/Xj29߶[n'ݑB|1N!M U5vn&Ě;Εĕ|1\wWN "[ k21J|M(iTtnTseXgyz\J<* w^q\$yPW;oUhk_Ԣ#YR) jȱs+e*0;1=軃}1FܧOkg;DqDk@7Dwa$چ8u%LI 8L lH;V'j%f4.=9?EǏg:e,E sVMZH@}0Re%a~M4,Z Gg' Wi"֦5>!zZ/fD[x%poGa8q߹[ \BU)~(SeV% z f:4g葧Qg;<;9yyUܰo wk&t=6%,$u9Dr{V,+Dׁx%Bހ~ HށS _ (`QO'ޅYqڧ00V2b+OމRi!<މhZo3 u@u?lxފKV\T&xKnގ=&)g)  qސ+D“A&[ޓf, Rymt[_ޗk6Cs2{W ޚ02V`s PEޟ2Ϡͽ+/eޡê@4Z#(ޤySIM +#؁.S6vިE =߽N<ޮP Z=P|?۹O&޳|SƁ4[|޽!o'C Tq#ϦRk#U@+ҝ%i&l-`Z+D d' xyٲG/LټaypMȘ/6JSH0!>t>Xg9WǸaQ.;-"P2)9coL߲%H͒~K)p'}0 h~<}7%8?=oH,H-a 0-p U8JQ!/0`\sĭ[T3-C%-tp;ixD~ӷa[t|ɐ =rhuɐz/~=2 ͳ>o߈ԭyik{xmf>ߏfwx{DzY Z^tߕau=0ߘIQ 92KObߝ]Y fo X[BĹL])=TQ[ :.^W9 UW%?SPvu&j aj qzj>*w75GVhVz9ƨ,[3ʜk4/:d/1b9 ej[F*9!e<'z}_.t\,v:`o HTPyS,}9iR<4O;o&T|Hް6DGh۝m(] Lx!L j[8m[HZ!$*]yhg=}e$]VŇ/D5YF-ZƧei; 1:Sk" z)"~}1Bq2e6 }ځ2Wlxby~4]tra.5L3@8ݐ>yL:U=ǜ";rpOk@Z]=% 7`v*BF2S`?rCs4M̈́9_[A .U2lד!Z:jh%wةƳbUj6(@mno2P:|͈ܻUj r0fz&T&@.t)WQfAauCk-'oלQw[j7 W.LAOx@LJ,g ']ݟb{?9@HsLjf~} 22nk6}z : M?9ȉOc˿.ee8Y;OblsehH~-?}?OVAΆ]@,FƘ6!Lr*)<,A7p ~""̴B#OoW?!Sp ]Îl؎t|fM`ee6ة[ _mk8ýl%sd;BeխשԐh(֪qmZRNP$2 |Ck;.B`#UOI-?p`te)! 0>P9Κiqtij͝NKV2^0(6gw& OtjΎRIKlwCDEo ^'foKzMd14Zզ!vG#960w5?^A sL2N."zY j5r۶&Ѱ̰zoq9x*b\m9?vRX-gX̾ >߽r{& A3Jc0)`kۙJ;PdH %۾79 }L&TRf1HMr2&ahi]SeMVX1ϛP5YFZwxma]}JJz:P_xVp9z h]UB5qՃ!lBqVlh$چJqoS|s`R6@t`SsUyN8pyEGKݯ{-hH 5}x΄*@-xhHu6c#[p. K!W4Άxu贜xpJ"៯۰$10A 2xyj`qᣳMj O[!sx@^+o|8awɆrᬵP%"}e/ i8wkãyH Da$j!V᳄LT +z'CiGfՃvN؊Xgr ḍ/|R=Td\]^q3Ặ44pni_5?] ~tȖ1˨x/Z)ƙbdTrBra*ѿ.rx;2<|`͔K0Dmb4z6Tq?c'_ܪ"`M@Vbi '*[zgEc ev+ bR.7` r-m%L'BWbsW1* U03ŭ { K )+N2؄Pphdy^mWۅJӧЮFQQd+ǻtvjº"yK#ͫzs$$0x'O? IiMw]h&=ɐ5=Z;@ix"lՑ>g,ܭ7 yo,/eϞ̾e1mڱJEeȰӄby*Cdr[TR@*P1D F>xaaw,"H`$p[6$j`=+{8"oG'.4 ׫|r'{RszR,nz7Iɢ1Pr'sm?\èc,n RFؒ!F$\4PB%U[ . givɂeoڅV/m:Nut5[{aa[1cZ\yj Yf|!z\]B]qXa" l~nG,4bw C~2%)UGWE'[Q[;Sמ8f: U↥ 䡚X"wN6-8/͏}FI 뷫fO~U V[&. t̀M;:]OV܄Boq`ceBeŽ}v$mξc9YR?%.;Jߎ9'+nJ.R`#քemC 6'<%ú-r442͒U1wfq0%A/[9N "\5g4SCm #PI_F8LQP~-pLmQF>gs0_4,;YR j VZfWʅ+ IdoF[ط+b$2*6hmbt;]Na+̽rm#s{iv'@r{Jlv/0݄0K_dgz?aWպ_ H`>I@3ݤ՞}yL4at{=㚦+[OE6_^˺㜣)j0+k7 C㝪x Dt㠽N؎)UF3?dmfjRqs&㰚rސ'LYSp C#ؒM*QjХg-nѦ51}\CxgfI)i7խCc۟'9.-?0AGM)*M%~e2M^Y[Lw\8uaIW[[5?\@8]FYl3z .k>+3yjjٱbNxazq)D4-"2O%Ddny \HIi71`w›C@3d\ߣneYKX:O](ٻX XG8|kxe{Ypn[VO`XZgL RiSB\\_F\*Cfebo}U>t*knar>^-Q .Om#@Ѯvn|\p9qTf\a`Zuw>-Z`i-}u.?H"I~ٌ3x*[zn~sf $T)yA 5ID-aˬ^}_k(MX$ JRkxp#7X{ !՞DR*C:මEj19f`ܸ4X I|]m B$swXUԂ@ۖ\m^_n"aA* [V؂b+t.HuW|>Lǽ[#l "_`\\tl_PW~pgl ^a!_a4R'pcETRs9 Jrf$fcC?$~#(YyX.Հ<֜v՞Օo"劈&dnQf3uB2O31C7:D{01\"p|@Y3Klp >6#1ArYh1BC'{dI[}MI=<+R yS3RRj  ^xkzJYxُH`RJʒ4l__" |6юCs< dʬVPdVùy2`K ސhpG]}X_@t [Ž{ ARCNz2=|Qno+ W֣aVsrnZ?b=J]os{CoO}^EөbTK/Lml F^Uc s4bp:=$ޤ!*ޔyKBQCD]g?8Ԁ-%ﰙ?pFB _U^{5N D7P̚Ԇ(􎒑". z39p$v @Y%C.(GuTf 'Pb{G@ӏu*0;v*w=o"[_&aP%Qbf i'kov7R'&yX[&&\[4ⳘOgH3c?1^EɺYOG -~ tyU-O-[z-EEaeR#ų=+*״Rt*8\tbF$p,A|mf":v"ݚi}ܱMe[pl.[n{{ (jn_;e؏OQ Z罁yFf:R0o0 DY$ EY2Ѐ W4w;܃9a6^n}Z!YG\nx!;ԋzV.;xڶ]>˅T\nR-6tiZag>߱%w_ Ao`yAE!dJ45y'uJcQy/e3%`ntl ~WT?#"-ǴIE5pPPĉW}zKꈳf3^"n]E*Df (8_L#nXp W'Dg}/ͯU]MtP h|9 -yI  ZVq褎ĩC9 E?+֭:f y@<s#얩JQ9i>"x迼P0MUJPfVE(އᚐTu˅Gr߈٧ҋ(qjZE@ڄQF\$4h''g XNL!j ) }>00aMb.;54 'ٔtڸ7³ W#/l-i_+< {tEc+l)QxܜU&}6[@'/:ѿM3+(U4Ӑ>)!AS!:Üp5 %@ FO[P3iMKOI8d˛\Ld)C=Is=(BU F@cW7_H]Ԋ/ry3'GOVoJjPlXݦgXg*;,ĉ_6:(\LmXC~cV,\!d?}qG4|k&]7[^SIƜS3mg3%^ٌ3kΕSgm~Wi_wEˈ]zF]ٻ!.qHbbq?ꀞWIdjzXVUIh釳:g]KԳw銊G~<)e鐤;dTʀ&"mD骿@*LN&cZy]6 ~!C3i;BjFi@Vgn"R{鴉ͥ%TY) br s#PXXrhR=%ɿntKǸ,Xr+^B{\92^GwI6R 5Mf \r-JG<&ѓ6fŸ*zxnuWc:"*f}[IʍA-% M^,݄:%f^P }ɼFKmTBCG!% M FfBƽH9>YtiO\ᡇ $Y$Z=ql-{]0W<.aN e.=%$Li>T =ş+Y(D/x6Z>+))}SKj?n=`=&KYh0EP,8x%8N-<%#<ั%(A͠U;b\,b5)Р,2gGQ[z|B~vnΖ;HsݚfG%wh^=ڨΚu`z]5>!YD]i{X8DoI~^gFj@N5Eù e9`<X̫,Ʀ|3.؋b ܻʪjOmHvhZvK~48.ꏅ3:@& lQrNP'l~/XSBOT&޾n>+Ȍl~sWyD/꨿6`ccxxTw4Qxwgꭚi"9#hp,Vj4K& }g:L :d%K꽣(_Y*5>h=fSM[hk鰫yoRW"zM9Idb* w'/kf@M՛/zɃT8 wa'B0N$KK$(#9B[q {3?-9}lg#J8֕GssFK/gVtXR# ʼHqJS *%rپ^L 4frj#=z}$ B)7#qRqp\L9qq<&C:}dlXk>w% a]rlEM&sjHxō'x{}`Qzǭ(%a?y$-5lRlV&wbs'/92esi5\且A sK/F?kZf~=k(D lN1P mc <}#rI ⣘v[Um?;u^4er[fyGuI=cS^,gys!XקS /뉿|6%"zrna/95J68qߪpd;2WHŋ ꆎsX&.+Bf_P1EVC'hՍef r섧/|]b;a]ncgNȁ63|R!볂J8E J߲7)뵕1@6V+#5˙*gs2+~Pmz=beŗ.Y $]N P^?`aڳdt4LaRˈ_VÏ6̒-:9«ŶȹVfe<Fg?‡K7~ӽkoY_bw6ok]5%\!As ڰl=iѷsÓJ=nS|, MD*P+qtI6E׾=Sz۩~ *OB+t(b2HE p\z:/1"D19i:s(gtRG!X8$KL"H8L#Pӌ xe4ãC ߘ*ёJՇ=zO,`2@X5NyUuwF|'^b!E1 9R1)Vּ9R I5[],0n&4;imE}D+2И4$?cXJ248c&|9Hgz) n>!vPIGѯSG76[tJ^anł-3= O'goHuM>;PSRHDMsTQ:G8HoWG[8MH+uroEa1P`ʟc0LڑIr'6k|60/`BjݭAn|ٰG3"30nZt]h";ix?t#0ޏoI[zr)vZ.~R]:WKs삀Hc!Z.QLc&!-,삾Z:] ͮshP,o@0wIMRA(f0sOc vz v\7TzkEu@!~ߢf:(;إJ6{k$p1vVgJa$B&$ J>Hwc*Cr]c [E=]_4Il6bjY8F:lSE s]}wY>ҹUcvՆc)f\ZBN~(U>֛;k1FS>k}q/_kӁ<dK]x~K~Qj6c]+^ыp.onbN_cJǝAaj 8n q)[gfqrFnә b2emHA˜j }->!FSq;O~,u'hzbb?loZXkQ26-N[O, N9/XeNu 0"WX =NBĪ̶9Ou4y_%cUm> `e6atc*ܓR]軳b=g {1x6__zzzeu5 +PBik=`cKXsvօ:qKc~bkZ aN3-_BcMaݺ$m)rH,d]02c %| #ʂ7bm#Xp'Fn9/j>i*5YfD؞! g5vb)@:d躶$r(8af2L#*>HG;sa€ KsdޫWV`k08[45"$kOa ,M7|R{jl%Q}&k95?!2jB0_S&sskm$⾝r.Mv ʞS}Ǽ&"%42y[@@7}>b.cZkE~ XCƉi "n)#5-]\ʉdNj'`|xx5kνuW"L˂< лU)W^m"%NȜ]$vNam 3s$Y(Ց=ycBt*#q32O fr,ɮ. u%N誯v.m [ v=04&xhGy+&82'QWxh8ܨś {?Fm F Q퇶1L bEi񿏥*izQKa\\/{UETC Qw.V[GF\XV1t5G}.L [p^LVhξc, zf $ |RMrHiۛB`)~KY3(jDX8Y/PD%tcv,?E ~eٿxe*GqYKM~G|pDYYKqo PBHkUK\:Yġ=g&=Z$cNf0#/"sNT?klkUI`P?loWCZ&.yx2]=403拭x][ 8Zŀyy/{Xk~q˥ 8|b pɎoelDpS^luKG/*^h( GˠAz۱= '`cGD- Ȓ&sܤLR-PDͰxawbrR>=ϐ"1B8veBqG^3m.5A!Q.ƈy{9 ,~@f*ߟX$lk=7zgD@3; 1f-HUs쑨9}wJï% OT} =%'v$9 jg,9htY~'Mv֌8LկX@0 ^raf64t}'[.]wr 3e܃WkmY_~IC0+53ɽ L!_.ͪvf߉{|"qzeKKi?%I6PDy8|)Y'FmMl+}vL'0)?2g ҙ")+A]>5&/r*x>+oj6%.9Z:Nn#Ůƶ^x}0ܮ\9Hc) Y4;a9gUD>F*̤?VſyDv)A^#wD_MC O, lu ,ZLQBEWq _UGLiePԂ^] xMKqa7ߏGaЉ.\K@W"#hӅ?Έ#V_+gJZ!lIͣ{TyGgl:}3Z!cnomo#"ǭkcu :oc-DkIÐs#Ms:FxiQ{ذ:T!ϠJ/=$|“ߘ8?v}bmy:;?3+_V2vXp' j{&mH{0JYHa);TzYKͤn/.yiN18 qеgTdl(1,8*VQBtO ljZ >W SBMZCi[x9rUbW pRu+[i9VwP àcx}Se1P4!\D›-ݴ`Z"GCSKEѦ#R+"kŒs4T,,{^7p/ n5"64 j0 4 ,h,X{0iy޼Sa^2T^)D{d4F}x5̃&P8f_׭|C7տZ(_EwB7=tCgWl\ZQ?\&:EŨxC PvZW|xD,w piq<2D5n!o[.D8IW45Z*>8w@ qIyNoz}:>:<ω8_wR*V&e73dDvub`h׌en7p7(#dDcTHXdwzc,Xɼ=ZeBL%wFG8F[nj;}|k 8L!\{PknAPPCTpq !*hn圜"iSf 䒮p|6yaM˫TPFsIᱠtM"عw0"Y>{Xn$ \weˀ|!u  6w &6s-ӭG&3)n!3µ觻06ECS rfɌ5 A_CҪ{3b55y8%5ʟ6 Df=8=I|ho6'CH]z,o14E ς˷h4ewnnfDGc. n U cR2+8U񱷑pnŴUYd$ի񵓜N1{yW'bJő@kS|aam)rMhQ̽ɑuHv zyP.Nš!t1]>`r(Dp/.\Uk9@gWkr}֊yMKXrECڡCfD|u1KGȌwH h `6ݗÐ_Wr uACĎRX_Y(;%#)t!|6.,bVŜ2bNVc ڮǙ'ȲjPҖ:O9 h2fP,odgCm( Yv"}DRrMHjn0z,qO>pSSudIw<4g`ϭmLK;yvp!}P0srCҿ*~iU5fӦAm'Od aX S0a& HLKP5&/cøv!\Jk|b_f{gʗ^,ƀd61wk3{D;j"6\fpmSmInJh)oaغL,)I6&o*Fo@οNۂ/Ppf?Y4aR1yt уv|uט)򀿇rWRJMnaB3dP៨Hn G"l7򒛑^t+R ޕ&}XfϏZmmG`!L(9V9sg31ÊBY_be4 ҟ? uC<ֹJ B{p;ڐJXĸAD\F ->3TP!0 -gCJy[I\ Y|TDְ϶ag\M<9E Β3ы40rn*Ŧp]2/g6.uÌ>-=0\<-/߽CG QIA7{ @' {R7^E ׫muN9{~f|hiho170^#)|sR6GnC1%'EN;拒*d]iZ 4D;sqѲIW?'NQdV<ƙW& 2KYDX >rH%Kp73rnHE5tS0<ds?J]2rC%d`۰u J6rA/#e+INRUwlՠl^mB(Rk=t1I~R.%2y \hG}HxCm-h:$t8ڦW;doƘE1~Z[SxfPC)zHn W6)^C= ا]%9U&e%`U'nݫZ!Y~(G,lAYX&B&ROhpsl "8Ǧ/R5A,(b-x7a1dz*8խ5}uFnVH6I嬇B)̓j-x髃.s%v@+~$Ec'_F7yEucJ=qNF.Ξ&@ u>5K7}+G:/Q?<87Ru,=F=M}uxuk?U7g;O CuWLuwJZ_r H6\۬Bq oKe@e)i{DMZQwy9m[t&K_aqnA̡m/WUӧɋI}m}"gEzkC*8Sn>VUM0!&uNQj7􋒟T]^:":,H\-;f]~#ꓶކM<.Mj¥Kyy5^RpQf4$ } [f٠WP7~ۉup+ż"^(' 0J|ILz%"@ɾ: Ís?t:Gfk4T.b!{(`APxm$ߏKFX|43 >E 3i(4d-! ;cOUeZCۇ`(Lku+ݓY0JO Gg7[}EW#̟ۏTO$=:}/yD\eXU~kbM ,ty>_I)k˜ !t:Z%"j/Q G8{m(#@e1s.qTl*)(SQ<̬8!@ !G=g{+J?%Jr4JS΀[Y.܈GPMʐ9ݥ! ƿ!w񢀉18g9TTVcU+.\O$]7ԎWIgݐ/f)0.Fj558d1?r(`tAv,^y( \5G뉵 SIYWH0z?M?HwF@׸ڋPVKDO PL,5PԕLjRyXPhCAh;6DB5jzoX%`}k/jAy03`ZXLm8v%nCXHcpZetFBhJk؀.z1e<6.%#~_,UPnh%r }+8Ӯ\"up%ly:Cw%|17A1^ӛs q {wx [[{pD 33H^5f (/T55^Pt@q⸑8G83o:KM:Ãj#:߇t;&Ȭ~)}qS>=!KZ[+o5}5Wq:_Ͷ`b좽STչt}r{/{IJEOBv sM;Ę mH#hІh܉ekSF#c?߃NޙrMX% j;՜%4wZiv&WC\Q#0vÌqKp,ʄlͭ//Rն[k-f ^8wn0bވ(׼C<T.Zes2,ˤk>N @įߔȶyK M}ts6i56R );}A˛'&ݩwLB׮,\EON3N+􍾧– E! ruޥN'M|`)"@~s燆%-_b}P/7o|t@˟ ^v4 x`i+#5axLY pM ? 9H&uI02c]KCs ;Z]`H{F++>jthunNd.`Dy-x:Ssv< `ngcNS '1 f\o^2Z9Tjy8=SIL)D6q\^%/K:^`je5='D? ύ7i Avg7]gqKo@=46[㬋 R${lu0(ҶH;4\k|NO0NSmcKZCs1̨xm屝 G߱6á=IψRxsy1ub==iNS@ R)2.uzI4D |}eMj̢dm,߯XArʕsd^|4;8;BG臟)d.ܷD^w)"WqOw3pyQi!wl+@"ZA1؋N ~**b8v}Ky=Īm+ ld џId S;ceڷ3_33r*yHJfBiOʷ1賑V$w&٬AM8Unտ +E7]1+VV2vj67MyU装$Ŧ!]1Gu޾pUXAYWDigE e/[{ƛMs~7=^WEXtmKb'͌wOГ89^j\X(vcQ^TP'ΉfaUhEd.w|jki"(6K\+qpx#_}0 ՇIZ}u(f"DƋ'6 T^G yz;.}6!k{H NAפ E-# Kt b I '߮6.DAWZ<="=5vShOv'CwoV㋂hNePlu7 i lߺtȫID_ZЍ[* @0]CUS\3) }ǯ -`ǀb,1K\%ע3q)N&h~}33$7\iv~mm#!uFS+>-"qj܌j/*NjJn,*6ollo3h rtY cerNJ[K)q@A Pl)U L5ZL 8p0S˚2v"u d"n(HfUdkJbߘG^SWrAV0ڠz7o~B$B~ !kR2Y;ľ~ -i[M)@ue1RmS\OqB.}YI`9t2-WOkKzU_3o,:kPJ.6*xѧ <+Q]"fCTKCzg$4YXmt* _~!BedD: dc@b ӕ~hKMPA[OΓj`4 b(l#lHl]׏?4pΥ\X:V{R**;`čs| $s>v%G2t+g^).\*uض0_t <4wڐ|JU.kK5%7IsWmi5h,<[F۝L6b~EL!D8<ـ{7l3c : yVMljvXP >."1SVgRۛBguPI&?}ZZ65waFq2_ z@X-'杇H$ x '<j6YOc /wI>9ŵ4ui4IWZ~lF(ZȪ|4}PX:^GTA@C"U2f)=g 'H~Gsλku?u63yS=BsE`OB@0/̃lj*T98X { )ϣ":S=:HUc+MƳU%TY2>|qt4ښ}*O..m= xS5JT[i m*J8bw ߼YZ>q@Z0.e?[.- %o5}qU@죒"8KCCsmZx E$SO >M/tMKnE– ?)-;؂0lKpFLZd26HL>\#5xLyjeV-QƿJ$:YqgLR"GYK>NV";lr&,[wedmP3a.QQt.?Jv۴!}ˀ XyawBӵ51c ӖpdP-9;u\ OJ@񮘦H1=w`g2b)7x'յtwsн+qNpB7tЙw_ Y:rH 嬱3.X4Uɂb8Sw.Û`uo.X@͌ R#y}N%\E8Jdh}pQUc^lG%TA"%x&*vaeyvşu#D>{yK0Zk$i\l0.twá%|s'qMjG**O*;3oqc"e_.A+.׃IOWuI 29P`=XUjXM4#x\7L;e)25\îd09zҰL5z&*ӝշELY6b.$G"_TK*U<)?zpOoJ[a@ J?@$!$C,pn!ߋ;p7Iu_z"@ݬ"ov *6js 39H}73E7(Hv~\Ksеt~[:v2β?`@mʘG BWmN9?"LMV^A8SȢ "u @Qyۭ[@V df#Dw ~vc~n\٨l(=PUp #(=kH^`޿ ~r!S&I&pWT`1{Dam'6 ."Ok/e7ցim%q;Wn47oa+V\KHkìTY2˒|$OK3.z+ RQ)BktҫqFdA gѩN}2y#gSh?p ej?1a`hL 9m jqP#|*k=W}ބ4K'dK3cɝi#߉NZvyz z<=W| ) S5UԢg~{_7Ls]tO4GNHf_EDb<-V ; XؐxNJ.&^8nLG}{?9P%Zux[A%E T˭;9PrkP,<>GsJ`r>H0jX_JʁP0%o0ŦB҆b&:@L0rnU-C% /|{GrDBS pss3N?RN1x`$Bw`5kK2sL˫7{z!J,ibh /CۂOgW4L{ geݪW::`es_=֗:#[զhgۀ@ #!q_M| =3N rQ#fQ/Y &mopcAͤgF35x0@%7O+jK,s&'z D4WY\)v 8&' AD/ڛ(5)y%VijEiѩ\t #\"jӨ W$ơ^؈(UnN$÷tI]J)B3`'FX}RwtQ,@kH"ǹ)!X l>Ә?SY᫨Ǝ*;l㛦I w|gau 9F|]恦'ZQF6r&i!L.hm ;5K"+/y!\HԽV L]x#.w#ӊV$&},P3B7$ $иQ(@mH6&Tt&*M'M %<ěs3P,!Eu'u(^:9Ԃ-BčQk;9e :Y/o+ά)F"kS5l>Z!7T?J TKWNyP!8G#["8Y{c\ F`dmE, ,3z,VwѴ1 nqEv;ēx:q2UnU+a?D7)yz)O'Dnzަo e!GCEmEfBf' 3!wKphrn&ߟ d=ш۲&xF~1,mVjVC "QV*ޗGZ #XdJ'Q3Vod .WEؿe~u˄UE`q@w@RFFX/ |_FdL߆.;ؖo'1I1[%FBv/SE#~C8-1i"uaGATl[r6}SMIqf7T <ޢ9lAUhRIތ xrj]m$.2QAmbJ-NZOqΊOE m Il ZL)3y %~;NG%ݗ\}- ]R 4٪D萟OLYzżgbIrmmRS(P(n   ' V0 Bő"%klBjIL$w&UʀA&lzɦV9MPE4ojkɾISpeC>ă-EUJ7!>pBDNY-YLbL qH^-g0F PztrH 6FߵIj^xwJ  %yw\ MځO,O;t]%S&(#xy^H+zJ/y'`PrlJ$J$ )H`k(@N cͣ?Ed| .’z汽op.= i+ ~(e1BrG {-AFXXJEpzEp' _^QЕ63FU?):$[OyC˳]]uֲ4#iA3 KS~(cT{3Cx$H@wQ@vCdM1V_B_53zS}y|z .{<,JN砳J dMC?ݞ&!2f!E=iߔLpĦlSR#{=B=1`g!uҎVM!2E+Nh`MRXBcx=;};P9sZ FINʳ0$]uq"$h?Ժ0D !ZcBl}+[B6L GYQorYH_urRqz4Dusuʪˁr¶x>d zB"r&d[Mɲ2#\I@$/X$d}~nN餙.4 N:1T\9=Oz7"U'621tE Y&W6 ^{Y-ӆ_7ӹF֫<[Mask!G]*Vިh@rJfpp@IP{~*lEoQ\0bWղr i/삕t(곊 ɽ u|ɡme֊`mq;A> :"&p&-`9cg=BWDq҇getKgWD|Z9 j3Pj|lARl&ؤAx&~cOKe]RqSҔs=^x 6.r8Su:'i?Z_a|Y]+Ox7]ey?na~sI k;53ڍ~eb R /}^av0Ad2CqF [S_P1yaABwԛP¾Sjm'LAʈ48Myc:s OC6#Ӥ` V! ~٠U5qW}5%s/ru0\`:I&@&[\wktįC)NLNkƤ#cp}_"ٝM {-mgR `Xapݽn܃ wFeR$"my$m&hX' Msy˶c5Pm Pрq݄ug n x8cFg6j>BND=d H_!N!>sŵmEFM m櫧Kt.# t}MN`ckxK],qEH_ތ>PK}SU l {`OG4nKjq?#v)ODRHAu[?Q 4@YܶAHf}-C$OUfX&mt/J͓ *\ _HMνvu2gK.."am"}K񂙂SiMzE3;7M#0T)穥Z%s HU}m#WлXN=L_btRr cyna{{oS|aGq ^4L{MYբDMWѧ@^~kAyO5^ffh<:/dK?F#@1@(̱|Htﳙ!5aR:'!"~3JVDIQ<(&Bڣh_)r3:QЍ%HfY{luQخYu3Ih17,)R8 S1V *JPe9cHUS=cTkE2∀9e^\NCsW#$blC0=ި{g >[\ ?$'/$5$ :p~H<}csCՂ_5y8ӄ#e|}\m\$m_/:4B>] "<H!ݎHɟhL98HP{ tK<3O!l0PW&thI cqf*jT)Q7[(Q̜Q#\ $4In$|(梮*8աI:xqE/ܒzx^ s">7I5qɰ19u %鎸c6TMdCSS"L3:i{-(޷b?H%Y>a43DHaWs${y;#ؒk# R.ʆ4?G?s#+$8,/qYo۬D(Oyf }-GE LmOyMpKj]C݅;L eu*2,Qp [bRF8dO{,|=[oZ !WPzC~ai87DqҜaݗ(E Zlj[joۨ|^Eq@[ԯN8t;jIֿDG%C%s]12U$m7}u-IugvG%Dtʖ~8I~QPI`c4Nկ.e\ U~0Jv#LTB984VL`])1K(=MWlM;3Ǥ} GCCŰ.M%Tqd[C8pidH=wm8*:kӯP/Cj;#;jJ%`Ctև#zvrF +SW`'*y0l gz4$c AS|Ed =dh Zp'/՜7,*GaG(:X+LjKµ<{B8FM b3E/5wuF+L1meAНg; c7kV O}^P)ȏ+ʴstЋ/~W -zjd':b&N] J¨5T|k\U=2c]3WI X1UBJ_)0@,9 C^"i3RV6;raFF,@BA`^:^? U6ս[h(JÖOrJ@ oS{oq, =F4$tR̤I>Y~*4pR^ BmNwY={(S, rиW@3 LEY[|@hع jqҧҶr%#d)I¨$a|^H'Fз{{9ni8x<͎YtGNXz)zN˔Ѵrup/}ցD`Ծq7羃X#uENē?AfE(~- m3N +xoڒF_ #T |‹ji0pqj-”,h9T AESg0i4FEKJ. nir% Om.,3䧮c> ̡!7zs빩XX=+5`X7^eÔK%Jh\&H}<|o\8XGQBx]Q}5P};ޝ;9I;*gq.(8ŎbE7m#i}"J%:t >ۋg5N?Po倽`P!`=|SX/d"X|\3N;{Ɏ)W؞K㮖A6l+LSZUv$M.m囤WB ?&(?<4_Cx@A/IԍnmOu9|*)]|zؓ=2cynxWY{Qw-N?m.3SR?e-DC}[<Nϟ.D.u*@0*imzGs&2"F͖ `~?guOt=d䔈QQT>}Ò+f|]^@ˮ0yKV5 |C=l#*O]ޠ o@!bJD?@\)VA(.Liʌx4{ 9W.R75]tu3W~..{jL?4 zXrR}%\u+:}l6W}wVc(-M[:~g/Fci]˙3G`A$yq´8q"Ov.sF+|gݿ)Q_tXo4GC֓830m-n-13} x7<ٶzOQSd0>97g tH|cclN66t^ ą"Brܑ\Xߐ+3Xn|d0֟`*jVGetl'M Ɨ"*Aǖ\o]DsyNL3ns٭VũgHL3s0C>RFIw35~WBlҚХkðh!.qIDJH(8\Z+rtS_^k<0Y_qVJTywlJ3"S6i^+Ό8#,z|zU6\٘5ًoˊs>GJs!,p'vK*_+( 6U, !Jgj^DiYTk(5Ug}JP].Ui+d_3] mC#a[񉩜#^g5/cxYO5C 4;Uړ4]f~S '(LaeQїK+@HÙ2&cviس09#HŽy[pJld9^gks=̴*{wB>0{u.ٺxAbX(^>˥ 345hgY˕>Wjoؓ٫ ]cXg1Ϊ}y9ú++JL1-f\w ),L+2;'\%*!]Hu)E0z_0"XӔ8i\Il_é_jz D恛GAf&U7| *F=n|>A{>bChe}#2C{TIvƮW]O4.zѨjbHEZtÉrT0fGKƤG+x_Qqû`}{5}n4]%tQj& .JP%ϝm 02(Bm [ys6NPs"9Xd`*ήc}|#yw+2|F?|1GQfxT$A+JhdQ?@7JF7vDQ|v?)1Jkf;uo8ʫ@J3h4gFngF[\zO<8D>IiթTjRp.sd Lf|z-^GBQ0M҆_0: O+gLY{M4لIw2n,Snyw %[r}YYhlAH3$e0$ 5@:?VAmϾt5PI#@Yy imzX#խjO__)L֡IQ0x,i74fԺ3ȳ '\}xҚoʟlS9Ucb΅a+^A 'e7*;՜'?Ndb.Bcb6I3o銉ml>~fDmTgCjyehpo]_O t4z{AةfSbp :xQNpRv4DŽNp z٧݉!*+VCԾZRPjeRߡ>sP%g"9?&c9A6S23rRRѧdTo%Ƃ-VcF Bko&AddQehsH S!Fnƒrea|A3>0_h.y$ބ#ɺ9KPrcתea1q.M9j?':Dw^=-5K^g O!m$Ş4"Z'GfW3(ރ# o> U~[r7b#_0 QIG$gTn'l7+=C܁*3-n!Ɛ q֡93\9渃M$-7W'NwLZEi<F@Py.J0wȂߜ?=B\ KSXqIkNnu=k q~Ẁ٘y>kicd'#yuiH :}c6A(3=-V^m$=If)' 33H_3 6 PL  uhr~!eKZ ƾXph}p٤Y2+%jݫR%t;)[ YI[qaNהFA3Mn G9%-i.32Fp)"QPS,qȕ9wrmygmFG: OMSIt HpPI5Z55^ ֯( TػtZzo=pBHWISyȘ0km'Ȉ"u01{pMJJʊ8kO)G!;UWH&D=/HR(p3U CQ*yx- JeFCZBB2EvöR万6דIX`kQ2|ēMPfF8`bխ쿘q `JJ^DӽQ;b6Ѽ>PA5֟/ΟnqO%row̉u4X:tot\#f9EF>sBb_YwU'٭~wڂ;|$&29[LmqNct@ hFibCD>-u4`K5iʟK2*FP K A&ekcֵ6[c"(i%U|7زU;hGzHgץ MEp+b ysa? RgY/N㬽J#%0eSDS,l=x0 IXyjE#Dg|Ƣp-MrR 0uyf U|s"wyڍH:BwGSWz_7vz00/lXK&sF"dycP+03FCS*p1\f n蹱\yKWB#Q|x+~=g{CEK=#'N B˾k%.-.HڕbB;~ܨ MMyJ 8J;l L7 ӀԇӦ.aqjC7e$Kexs]#'τ7 !aC}.3"YcϨrFU+0vn!kI~H'Z(X-in'39+[3Y]DKc师V W͢d#ůbd ٫t=x.0Z[mvPu >Eɂ5.U;Mf.0C{ rg'k=u@ ir>ڲ'[5߰yz kq DV]"rC;@YvMR@EP:X"6?09a|<5!6Ĉh+ ˏh1|@Us*~W z_Nlqoev衑mrY59/r+@Yjreb7Bkt/寰}=W!blQMW>ޝzgƊ-KS^)h y@U#dz4I5p]3[׍[T\v3`{LnUMT͏Bp&Ji(-<)Q>"1IT}<?9ecyGҝ R)v3W˝kZd]=LtB9wE2J[!V!2 [EefdPkȖ_awY:R4):;ei<2 @WĨ74iu[hY_S DFc,p" A9DžC&^!7ͬg>]uѶKUtZFܖ)5=x^퉾s2:Ľ$L 䲻6у;3I5. Z-QEu\tԗ4*]DNZ܌Qhe'eG^0:ogAO{$=NRAe贰<@1ҒI=wo5M[u^ F:ҳڮUl=&jmz=fЌv &dPN9Ľ{kV!ac"'7oz E~9wmρ Q~oݕm&Tÿ/5)F̞@Lws-^eLGG ω{>LC.;J!Rq)?їNN K(+~1uyb0'ſ #YH"4Z[_eu `\EyxFaf_Nʙrs/G9`3=wx(Ձ;jlMM䲞%2ˠr >y-Uw$:ٴ(Iv:s d+46^dNF;"J2I#(T'R#r߂KĮ*jD@x<#πCU9&uu[I܉$ x}/7-6?^a&JE6 Z;Qeީ,`EX30%[ a po,Ν-<܀rPRj؀R9p 7N88m0lЦU(d;RFaްoer}>[ސQ[{P? eGY Tb٨sDől3:)O[b%Q l1=#T]C g0N:a O NM}ˆZp͆ƃ8+GdŤwoZieDP~`a!B@)N݂QݰS7V־ .uĬKYCAm"<%* Prq %G*feUŜ}CoNk28OD Qc/+cc;hhVW;[e (RꦶŲĹ$yq5݃TGTf:EADeTJ:B^L<}E-wx93[;S"@2<:n{\lW#DIz U4X*p?vT] 9 s^ErjXR `)V?MMRy mP.Wj`gRk,R/ܚ؃R(FPWiI_325w!DJg#{x4T< ɏivxX1VsRY"\ع6zUMsF`9}? &CځMss6 ^V n ZfZ B,uD2ߎ@lۄS8< $FUb4/X0T4GbC[g8Yx4Pa\f?e{+q64EUb~rc`ePz73R0EI=lG G3ÆߙL}}8@`*YV7aINaZa)( u,|x l_wAQVB؋y=g ɝW Z][S ꥹs`A`khVYxKÌn/(̭01@)Z}8\@45bR D5+D:5n ,N [l_2' jIuVl$ifː$1Oq>.̲CVm*7}:{}&]s "uRHu59k1lCQn¿:ͶkOm?^/Sl_ '' 2M50Tgnᜀ= v4\\;ZլJ33mA83ya6FqP#w5yhb 3iM\vpogGB?!~Nt\[yDGd:/al|_N~VX,Px6Wwz*k S!8!SyHkX'/o3pYyo+U. JHף1%&Z#Cz2ɽ zmg*_f>dh!5(snWC8ƦLڶyYS13+?&ASj^Cشnf&ŹLdВV#jzT],}r0gJ/.[/}(ƃD  @|fJy f@Xu:yMLĤzCQSV .tu+;xٓgĪaJ_J; +0kFZ+V"x"֔-̞"k&Qp.[)8R~I+1QH(XbfPy7zKﰏ_ӼKC>gr,x%„$0ӱ<ڿ3. >egj*$G/cjek1|DxaO].ŋM3!׀jcx|t{j*$W&I`WDD D?Ws*a'3yB&6%ŊδVV(3x~wAo@uҨrӺ+H 9^{? 6k)0:ES# Kfh*f;9? +! FHaI糡ɛрEwGs o,d̳NՒbOw 0u4>^ z_(CĴ eKL JhĚ]3ٞёa@qTqYu2Dgr3f:;c@r5{bJܦkBm-c>PNՅ# dw˱ʲ f1_ZX 2/:E೔dB`>1„&u:삻#KYɫ ûbؗ˗vVE@AhmŠd:Ww5 -0 w"o{yl1WLsr`g-n,]I%=͑#}߳Q˗+Gt;;TE iЁyFvDI{ C?OZ{ͷK8teE5/dVaL5}A3V/!~}wpnBkH_5cuK jW)T zV)I=g4 NB0oV2i / Z/&Y^YF'ɄI4Tvw/56lM @~@pr˼_zFyԘ.N&XHo!hJI[%#bO 8 YXR*XQ^hW(Lzѳ̳݄dG$ݘDg{! Oa7jG 0l%| q? *z )RK|` +kWOrs3@ |{rBߒT/<H]gii+պvŧ˽G'z[8bF\?$3@wbTT~.VC&^_WM,>KZ ~`p~1r 3 <!po딿p'[N/Q\STw1Z!y(}."6#\}~i$^-Jrǟ 8DUZ7< K&J1*ͥWJE%PI$ρCk@㘅y\ʴ=hO{uh-*yEy7W1#gP6g.}׀lV4%ڬ)v[&՘]ThoIKuɾ=N"C Llo8̼b;vo)nn0я4EkQՌz7tgcw0<9%b?4(*5hrN%LZv"c"IY[щPwc ڵqk#'>  ,z5v(̓mQQXbpaqG~.Z7A-u6w PH#W{/=_l|tV2g%[~^ovM+0LO{tBgҢx]*7PU ³qg ƍ]@Lچʑ#^ZBT\:eB/"m:ѦGHXeDb|c ^fZs'~Ayc39}!K]͟(צ9/pc32nX}_)x0RZl#IyAںb3l&-WO#n%nVwD7?-Qv!W5NMӃόOr Nw/FmZ1dtR`pH]^" V\y0tRU^cٚ#whG_8KοTlm٫g\/Ǡk3t8qj͋A :)&#œ lQAf%p̅7TT~s8%i$HXج]G*!d]-cl<a7ƞCňM>mKA.$Z1ĥ/76V)fgoFeu:҂Cy9<.~S_ǚrR06Dҍt$PE BKmbWig//B,e#e9c*CnۈahS1r{Jۋϻ@S￳积3Czϝ :e>ʽѐg4eOODuLӋpL iHA~;);qxD%j W,EIf~.aT{~r< ~;*g\q%߄ f>ӭI-tη(CDD%)#DZg,?vHRj`>MzE*)GzSX 1Mv#mmgw i 糝MR7+,b|wj1.C<'apAODjX*RcLWr?d<F=sW:Rx 79w3Zna;'J({e~żJ跊kTrRc%6⣰4"Nf%3RJ3/ Z>̲%mKR4?. R"9Ud&ܲuG,}L\bvXUmcQϻGG10=_W'[鋎3l T2=OQfm@Vyٱ1x1d1o|PQb[Ln0*`يer\CjӡwQ9wq{k\>[f(G%',oy)*w'VX ׋51K@eQVmto@hUFϯI﯁tUCƓg;@8ޥ4q7Cj3[J,o%N*jIO;qT!ȹˡ:HyP)6~93CHoFLm#:nI 뷄AZ*Q#1'׬p IaogPXSjR]+oc:w(ww XɷK!is}K gLfG<'zhϫwy(nD*@)U7WŞCgJnYh1J:ݮL.Sr>zLro(s3| 9ְ Uu ):~b8 ͽhz?ho2UF~ן!*⾓ZՋJts3PY7Rt`i`s]Z&E~L 01U )?"^᪃!|`5<52t}5Rn-:+FZ)~|z2}Zy-s\KH73ձ d:гMUz1njhTxIf2&GeOu&E.3[vPy]w|VEWg y{A?1*}&e@͜8p/|/7Ծ:hmTEBPc3};Dw`YkEVO̓ACxǣ`sLEdg;[>fTbBGC)ĸTaھñ@H]Ngq2^9cxR(>79 O[olUEJ|z?'1b{1sQs?d5t+Yϓ F jLaY)"2&Y%ߑ3ҨrܚG|Edd$Z JOP9I|\;\D zyi؀аg!yZ`Od2pBUlȖVu(W",TZ a㚀`I7q:_Mzq }tў pd@nx(J}oRf},f;hcz aT^Øqf ܁]6eZ}\='7]8dDǒP9Aӭ@ٳ[fD2}wj\Xǝ H -y[ĬMU ^E3Mm0}Nso*. ܫV TZPq juQ,4|mr+YPP9a!1Rh7 nR0yE!MUt Zlx# +x`- k QsCWb> KR*.L5ٔ03,O[5ώK7l YHez^1 IR\6rұ<H'('h{@ Ķ'L6+xQ!]ŕD/x@{vаW^SRS:\e{/{0J@'BDpIqi NxNw"t°H!e33dL75&ܷBF*[CՎN+֕@ͻ Oe)[dh,zٽ@V.\d]QZ4M\C I1 MP%hQ-q ZI"^y Kl,0}d;h9T %G~E"l&6 r1ܢk0eΌg=2-Uu֗hsh,n\ :o<H}qֱ|(Ոt++HGo^??N,*P0aQ+6!xM|CJ+ͲC㽄yg 0+er#mnEt MղXAj!G6y 6Gfwn}o|3F f{c֡ ƔJ2@qʱ eָߏ1 Hc_Q;~Q-ehk?iM:\N|J.R mvԋN`{ FHM7L0Mް]kc: g=U7cGYc]F ROWN?N=54K)4vUb4lՂma Afb9td ޝ13֫ֈ( "o6.[6ǖ5&H.Æ NLA N&DnvHxlܑ 8:4*EYb?!zy}JMUa:@!@rھ|%msYkc/pEP*\bV]^&7pBe{.C/lZ +<uzvgM`$~f~yTFe{ځb]]׌TP1γ,9_<34UZy |*fcnAn !!{D)a,Ѥ79F@1>-XL^4DE+O/qSVfxm,,V%PMS ?=TngK^*\NeR?O&PmG!xfX\,Mޏ$3kIfL{8%YtL =Uٴ#ϓl6P7bj`ص'6:0IpOZzNQ1?z]@te=Y2YCktg~q$iAE5Ѽ (r^uzК&g%+L1a>>8C)규>K b?C)N%‰vP 0%U's!MuBjO~\DnOx` jLS_hMDݍV=aO#ѧZj5VHϕqvR?ArbÓ0Nc[>O xd31&j*j-'vbW]~8sIS|H8 b*fn⋠d`}bɰ+l/oYiuXv5x[:,=teyvu>,< ha+ᙟmc5.FDOFOPV+Lu Ź P~DЛ11Xy þΘe]wvv=%AgLJ}na()*UA^-$ jn$ɚ%I&Sl10ǒBZ4fz6K<46xDGVC\z^>*9A1P)Sh9t <||jdGcʼܙ|ܧtN ٠_w8ac"שKFL{]C_Εt]u űϸ|!Yo, p"9|6mq {H(PGQ&?Ɗh~2Ҁu y׀̵:S8Hb1T wt3cXy3e:h,q_U&c[5QW [Y[2- E5y]e] _l KBbÇw1H2™J23n!;JkX+DȧZa4 ݮoY=Ű򂱆L8ϜG'#nJYg~ļfnu=2| ]|JZ;dOGRqk_~@C_ )>vcn[@ :/u+VWnS-Ϫ|Zf@1 %VC1^12(~ٽ]VsDhEAnQcSKDŋ/+HD=Xk!2v>\,d'}&"E/Sh+I\:wz+̇>.A *kʬ)5A,w:l$MRY1I%t[[ |55P \*Z1yl"ʢLM&4zYu*R Fs%,("-0Xx$yDAKT ˶^ 2eLLP*YZ %]s\APv9WhJ〥Au ekr.&lF,u^Me 1RhN0) 1Fcz-52ThV\X6E %:N9R -ziBjk6 nq5vOfepW0)u#SqDܹc;r"[inIㅐ⤠ޕ؞R ldF^>(N ۼC!^PƬ펕?90O^09J zqWqVߵAyjfW16NP"J&5R70/3HF ߇YpOD6MQkxMqG=֢xdo z .tkֻKgʋ݊dTEPuAkg܅ϥuC ;,@5o+{rjΝVKZ(2P!R ;RK;Ѽ4P܉5DkxxY>'*D0/D!k̓OiJS7O6nC"/;H_ېCAJFt1L۲"le EzwZZIIwwq1یd c\nCʋ;xn(q{#<29/}U6p46wh8xJXԒy.3+khCATGǓҊތV |( 5=Z\ #/w(wC^%_ȏ*ε_zCZ 6YG񴌳lN+ 3lV!/b3[ Mpc2v $5qs}8ޭ]ėv;I7:蒭`_Xy$?wHRg:/.!hK sqѵό`I6OT[>niP QX]97CVpR} \aG`$&핮b^*VJxڤ'KiSEϼ40^ (s"GݘǡpZ4%x/b}Nz\?Tg+2rmr;}(J&r!i7 0L_L,e.%=`{.#LÁ\Px) "ˆGc'.Wy} KVנ6Hhܟ;6Qa,)[psNSӑ:S>$=3-*wnNlTx:mZ`U{7q KzҍVP|,cKSNォ9OId9ܯ>ݝJ8ښ--@ȫ&Jg}0cr&t!N*#-k2RօW5povAxkгĶf6E%fS攺V\xZƍ^r0:ѭR9莥(5mq 1"wEGٲYQ*`c[iV88߭xR}WBGEj'B%ƚ[:(3B+KBOEƟ~>~ƦU,i0!Zƻ1!--ḖYyʏ>b~I-6 bj܆Dzn=mc3>N}M$?#Q)x;peM_͍uRDmᄐV#d"87½&Eg\љzՒ/ R3gg(yo?D?svwI )AawqҼ\XfVCn[Q1HVsn\g|T%_Tmo쾷gU*5CQCa6Q[|g@WL쮯pd͛%JxGa<W{aU{ӻ $1208rxsB7>aG^+? $(,-ء" P@Fx&|c08([97q FhFjyARιGb&}q(!rT礎(dtxMO?ZW$;Nӧ2J >HD$TS*`.ܩi C:XRk@ @cR.(vUBa AՎPrx"{IP t E +{1'W5N>F(KG'EL$q6RQZqofi:GJnF<b§+ 3ʼc鿇1@4@_>|NR/N8Io$ );H+T?E}@7* FE@X -+C_nN3 T@Aj1Vvע/\vUWᙸUmXnff0`0D1Z<%("5|d pB2xxqնQބ.vX}!wˎ~*tT6 c˯Wo Rڰ[4(fI)c7- +yw%Zcr>dt5;?U06P6)OO>ӊ[QGέlUuT.5Dl**ļwBlqk2~ ~@h7Hސ8P եog|w BI.=XPZ- ^t~7(&x J^b&MJ״ :fnin.ڟ8Mf[}zF(?JXf|InK|tYHyaAw;dPt)+ Sj]pZ@&h Wib򻸡-%H5F7|kL&z`$<r`z<` 5&ݔc^vdgZr qUS[Iza}T蛉XoVZFÚ(|^7 EJɾIBtxKF *,2)r~P B-C*ܯ4'1],B ە"s|?M`焞1=byBuz!^b,QW5"jպeU2xĥaI>K˝a+'x 9_C@19Z0fl' 91V:㣪%GpL-!DۏoLB@vԝ=!lJZ0zɨz^pCkJ]N/kh 5֜*2xp1]f6MLw9O{5Ω7`堽fpeayTw>q垇ٺ֨eYKvsuLJП}T]Οg BwxD?5-]M_ ,]Ba'-*1{0J+'} >wp|!b5׬j.V#f+Lf`?9KZBgŒT)y)C'fO d|ln NAJz8Aic\@馛JS?4ԗj{& (A Ev}_^ɚK"GR?8#gU\0`;JaV7ul'jxn\:!d'5?`J"~lNd^Oo^ p@ $Gx\òg]ȃ)Q&x3ۄYhz%(դga _4=73KtvvPBxډxqH_b6y'Qc.+=߾0ȻKi@ rxb3 $xٕ_L:?Jij}O㎼[xݪ)RKڃS"J,K̈|}hq?DQP }(K'B!~pC_`F tfjxƆ7g`g h0B"SRN 1Zs<\+:q@PCN|P6 iHDHS\a~Ke(&~Le(`JU1oC7Ħ( K³s' /@3Gϣ;xNM gm2$jkJm)VXUE-eoBe3<BWw<}vn usٚL#8́N쪊k#OŠ2y|U}( , Fk+vVܲdc#Lhi0ŠLT%*. f$Mt?V樾ͅ vWլ(E8uF E5MEF=QsU?M5=3H3R'3 ȟ_ iiJg&Pl˭ au8hyΥM8.#w1yL=;z#gZwpfY'?z͐Elˑ~7JGZ/uS j'{/G#|60j'J.0AF@cnzQ3ʠ\(׾ԞQ3_ȃŮn AE >榍z iu 'djj}(>\c j:FF:i3 e."yA.UbYM]eȎDq.t t3W~[8;x&&8b7;>TSk:LX.R &;[%?rm7PҖUx,jdts㷢Szn\Ke_zs?&$U#~ry2U'ʞJ? *@Z-,s f_%ja^TKI ǹL19E=`Lo.iYnS`nPUXoH ѿt6]@I5yFsy6h? Ft-)cfRf&4\Y?E :H4Mɬڭe^9yO[4 'n$IZ±kN͂n1ƒ[{#@wT喍Mj)޽=-V-dI8Ȍl?Fc> BI7w'K"{UElbѱ0  =@b_@Ik&-Q91}vQ?(Q0)""Śe+zb19Xz-=E^0F׺F'FFb[⼒i +N^6ՀcyOOŶIkQRxLqHt_TT(4E9Nyle.8M >]9g,0TIj]#M$5tmȡMՃa NJb==ST |"~>C?,h XsDn dD:S J/F&W #*)'r4g=ԕi{#CLT8I$N(J!Ե9|" xdr_\/Ɯ\>G7OsF-ERX(=~nSOz̬-=i\e/9Xli>,W.Lz%nbW`ƚI^%1/pj|@>ļCd]n|3c$StbsڤmڌG}t$#^t`=jk ұGJm7+xL!y}~lULq%dL,#[B^0E&IJUeP{7ɐK {pA@εŸ/π|l+sr1tezt_,ܹkmH.=t:'׽#,b^ m]Q3L[ uarfWU3BvNAs'Jًhi^$h-e8u(-J2v~GL(QYx r4 p$JOU bz<`V*RUsB$ybeOwn=e Ҽd 7>k=oa). 0wVX2BcoUB?bpcUC|~_N;泱Y(A[mCVm~d?"C􇴼 ]*πg!t9{4? _ zmV3TWJxjTo!s+53L^Tk7Ô`Y ƽH0$ +T}~}U$Ȯ+<x ϱ2gEeuXIC/K7<^go:mnA,ƱN:ا !ݹ r00tk$a9(aݓ!(>-[Xd`Tw^c^#/;4 <@@6@T_s1,(kjDuL>vN4؍Zk8d8/(I|h]:9D cB%-RtZEM'5}l7έfb n0ĩZ18' ޖV}b@ *FA~3p$s(#1s_`GL-tum/FiF63Q#izhQEwxSQ =xDMߤՆf9()X>]|eeq+6Y?]txݶF&@5Ivm{:hK.2$c2s-/ǓiI 9T| HG}p"}` GCd"hA:3|8)={^ ;A UosWb2ò:Z0=uu84LA/ݹ2t/)? Т2 { fM| q#|4tVT" 0Վl^(6mJI;kf:u%m[&||Dy-=DvcFkaM* !qA-+uaDR/?%ʖ 2BՒ~"}U`/U_ʧ<ǶvI+y̎GsC_;$:;W-7}o㝝v#{ (᎖0vuOPg tP}UKx43q1Z|8 Ѭ^+LCA"QUژxQ(A~.'[.Q0B,lU8 @.Yd˾=$+|>I&ŗU3L1.K}id u N0;MPܦ7lrt}wjN# >:TMk0uqCS:%לJw=s.EhÎ+?CX9rt0Шs푠:`J.*N0F2fC2\aiR0=z:-LÎIը[ ٕX[CC@{%QҽebboXS,J\ je.ː}śd!׳W~=7oeNGgv3Cl]"RM&V{eH~$]EV]3'v?Ѳy2c-y'ěoU^oAqUT#>_@ƿ%d6^ =t$Ʈ#q-iWgqS!UhɝuL; bϑiIB_R /L { [# ; h` Kx!u*ܭFbTE4[pV:+ZPJ}ZIz" CǩZv…\\|JOf&O;Hl 붬لU,'3u #gsaOvvw]iASh~J7:qXV%*(p#|9~)jӬQd  @cGjƠs7uFL4SiE"C.=D)͔׹+(ziTFtK0 %RG機7Ca2}':j8?/+K׋WWOtn} ql[2TTrwo 03v(} ԜRP=" K/$G,Dڍ!4-mf"h=9c!TFtK\嚩}8w37єVKBW%Z FPI`N-[zyXU᳝L/ )9#󳊆oVgEFCTJ x*;OhJ|Eq#ܭ%XY5]^yZ}Id)"kNqo]gQ[A#[}D9x%YU,+[҄s Pt=8zuXYrg}凫aHlc#t8k:,lVGLzr:3 KrqAψΚtCHM"bztgml nJde*XQpL $`6 OI( ^:qKەTٜ'mj4ph~f L \>\7TCِexLL 8!ͺL!qv(7Ӂ`)K:_3#@{'jwfb2!,[ 7 1 /FVy'kEص6_o~:U,pFpڃAx=]r K)!r5+ҭ,)5̖yXdwc*g7" @yH]fU' ECN"?L m@]'ADCŴ(Rbf8DŽ#G9`>є=8p'˸:/R/k]^Զ3J'-CzHIE-_}Xu ɟ:?vjQMgiDXR ,S? =Ωp\P5>l &7zp$0Q*o8 n3߲t #mCGc %3@a:SOqpgdI}:'߭Y$oOפ=W Q]Ǟh &HKrrC8k<ݡtR-ng'c=Cۻ{݆S߮g>LL&Iڶ:F1];nxs% "do?qK&IHD&TS%\P~V#90[mprM)l 1 66b|,#wFTå &;s<'g<֙j; q]^ wԫ60|4塃E?Sy`b2n,uSsRNND;NI.eH( H&:pcU> $raD*:=k/m0ޣMigړWe.`(@"ބQp"s!. 9kt(~f#7uu6z|b ҭ,ɰi8 XB+uR*9H"Eg+ɋ4oODTz"hYE*c_)U%hj|93Hڃζ=PM?)S:A󘏰m$!%$QUʐ^몭85nqLtr,&Dt@ksmtZSWG4eBF.=q="џ$R)wJ#zr {嵉`] 7HR\ط$@ ~]'&Ab$03nVT1U<taO`>D9DEZ,PߡpY =43i<e*A(b JzhvlQ[=$VR|R4,X(1lђW~Ş9g*ɨP~Jb1c\`&죊4֖ya{X7KwT{r`]y}|'k:TU$[9iDg0 LK!fu`n&H#wNEWD5-g柝2WZ32j ϖQ6rHܗ% x'm9vaLszN S&/ 7 l{?ibhW8t1,CЄMVlZtQԿ.?Slc&̈́|P|`<^o?yVa~$gApcgl&ZMm?)Q3xsd6  XJ%1֠ o>yIb^o$!MA_19n*خEˢF!;y~w·qqtNٱ7Mmιim5^V_:qI)&6efr-Gt%U"2"ov7wgE| 'Iז<_I-8 T},mІƔz>rpTNhNׄuXٵėoyNAnwIe`D%;:[C޼Y޹`p&ZfDr.:! Q\Y3C Y$5g'W?q4ٳiL"_i(x+2&֊]2AI{+cbTU1_8&L\m.lF$ԩ^pGge!#@`owɋt_al3՛0TT j_ 8-*rnTY>P2F梐zU*Qɞk+Kf2hQ~39M$ ٔI5 U^Pg]tXoJM1i^sW۾CCvƃG: r}B*qL4@= !/AMDX_!A942GQ8ay'V2r˾YE=$O9NLܭ̦&-qHh$l+͕l^MH(`]A? %"`$W[Pa_ܫA+p<ЎFĦ5I7~GÞ?\ xwƱuF9U+.(y9`مAdsva_oC v:RuO/sJ"P bjJ~ /76Tܦal`Z@ʑqJJv74%$XnvLn˶EtK!U@q(q!&ڇ&ڌSŨ o=qg&7TmUk!2[[aAjm%S5]՗]AfT}b4(Bl8)Cn&~N9 (LeTu5KY&[{鹊4 Uٰ4e>!!vEnU@[ mM-K(xVagGC.h&Āg5sVGҺR n]_v!gZRU3fzbnBV(ǀXќ0aF>je9gUCT߽zaF6/ؠV=;^;;kljsj,fQ(\)\6 LyǢ8~%^K*|Kr@Y1¼O` }D=껉+V亜0Uԙ͇vjN_}&CP_NfB9PV|$qu`g7T\krP3BﱗH X!&8m=ZWXQkͰ(CpѰO ڽ16ɑ[";e8zk7λ ncw9Q؞"ߓ:r/+闅I_4qc7j* $hO$]Չsޣ$O6|ƣtFgEt]7>&1fe? fRe'hZ̴6~Tjt(d'hokPɌVac+=w[ SA1f_+#\N4,S>p8c"2W~ Z fӈYfJ=ۚ Yٺ("1M $W $r8pQuN"/LRI^Y:.!F)!g/lU[k}SG#݆GUɶ\Sn5dc:.v3ý9X_Jl05K_YYoLAr[K;ɾI6e],-]p/Lt*_0mE3)GK37Y}X:F!|(ad)eh@|j@ I6e&Wlp%(ϛGG Iy/t.- F(N*o`͊JeI5˨ok }Czr7v5(VNuqUR[!ߏbf_`*QLU+QJkf銎Ё|I'M2Qt,7~@3}S}%yN?HqL \sFɪo%kX ;'$zK: d $\=~'}cP6I3 /H(r"'$9wДŽ 9f.zXAyT$(="U>R\Cj|×_^Qvoy&1pG6Y  [^"]B=Dfwbgp=8…ŲL9oSe< nLx_'/6W.\0`3 ՈjPUb~#NjE~-B=&LFoSg?|+݆(#Bf[ 꿇R>3j`4q1I/sn^QrõuCt{J56C*J`9<3բ 3|r84Ʈ^k=gnf;~B2O_癡"KJ\h@br[J_gVoɉJOYYWeA ?QS+ wr)N`MQ*M;]1 cW uWj}Ǎ3[KoW4ÅWCWbԆ3r2oȄ70(ÀN%| D{rՎqiK$Ӧ2Reς]vN&Aׅ i<\}U_z4yL]E+9+D-xF>ܰ{Ex"j12n[7: :a/!6Lo~Xm+@$,Pٕ\iu"J(YLuVv[`awv\`oidPj{5nb}bk^ 7Un$^ >B=ȵd6&~HA]w_dLNk]uLn/Sϲy&"+{Vx_I0Y>#Q"b8)VAu^k PSeq3-Siuc5uf tл4٩n #Tk./6ʊsݟJ!\79&̻UJ0_N3|VJ'>M&n` ^=/J\BiIvD(JIBcZ @1*lc?Ij}Ƙ*Ol)C/.~ܕu$6:}J-Wf[dH%ݡ)6 :<Rz0ZFQ!'|pN@Ho9WZ7Wc-0 P'&y|;vD1>cFf|u3&*3DPMEbjHk{`Jg?k#9K>Ȁ6l^2u-P;hToIfx~J#D}&Ǹ&N<{KC;hܰ7_愹FI 8dN\*G8M6$-Sqim@mF@@qBH7;ѸV U}ǰ;S9ML|l38W[*&Y-#yx: VD;GY'Md~鸰7TOJ+9ـF o]|kr;;DZIxHD8 >٧e2{hw!]gC8cGg!dQjW]a Ddga$vDURTkF)Qg{1RVnڻ1y]s](yzA(kc[uG]`̊S)P$ؼK[EL_J͡Ypݫ@0f%r|NGB@i=ϵd0^q7Fg &[d΢voc5,dwOr˿;r0a`Ɋ>dG'“nddz z1DžFTE;6R&9Neb '/ZJd_'L!C?Z XP)RA Ǘqe,)V "nWl+R&pY 3T̕vb{wBjz=X/԰wfжƊe?)6¾yʒO6mDc5뿛zsLHLgŀ&|1u] rt[sK"*R|='A8l,~hd>*t4^sr<2EFd[V1Ҩy_Mxѝ6qFD@uPHv}Ij"#"[ɜm,Ynby#+bT"űKtB'P@㩛w zT h{'Uʖ8ҘG3M4 >pAh9nW0 H+m `4j1H5 RW46}ݖ]EmSR)G'ZuςPOZ 'E]PwcO1 )mtrAAtHu|5H+J?0c#pZf+qì5bsqkӦ{Gtb'z#P{1nąM h/{JИ1z5UfD+j ')}D][\ @ҵݭ!$՛?6Pw0@" @пy#}WT~oN\*m9K!`-,nK"EXhH(1ٗv v$kXmnk#{:wʰ1;jYs]N,+~Y}0x -"\+OF/ڀNØ`×MvoE";Bd*-7Kdb8eihɾVZEht~&Ds^޷"F lNzyp=a&bLen=P ?NL]-HJc5qoʄt*:8oS-rNe&u 0"e_M櫚걍s&]{$`{16n |f흉yғ#(^j!FޞX.ݚqF#^g/ӓ@MFb" }/dYÆp9ӄ}Z=AJ c09J"[Hƃ>2Ӫ 9N{:6BU%9nBp,JFjyeBd2:\ 1-rY>srbNH1Ip$5 {g}LIP awe0RlpF6G3>>FZuU(~Z.^Osm~ cir̆{j1n#BtN0;Ӯe sxtb T)68WJ]#*aيua`U[t1sL?eˆM4jd9XtQ9xg^/si#]u{z@?2ʻ5t'Th E{]@rxȋ~W ۾%UX(Fj U`LƛwdyO҅gP5@)؜^o?&sϊ0L EsB*sVb7m 5.)mIÉKgyت~I "WP_;5 P~ѹCSY;iAK:1nC \ݡ=3TH^PwX{МvhlpPM 5cyՓU݈&~X3{w*HɃoԇ<Ktfq36;%;"̅lPJ0HDŽ}=~mT.n]Iӊa̗SU!Ln]@D*G{A$mWw ֯ I#∎-gcݲ]jDŽ2,5jlzHHK<I5P->X}I="1xs 7֋;`%wyjnϷAd8Yba٣J[`-_:^ޣWQByR.fR s's2*.aً&'|yޞ,*~GRCϤ~yC!/aUN>&6dRYuFʑ*y88sJw"e4%6%%``iۣbU7{]ܝa'PtK 3kKOzlRNex\.(2Y[+tt(.'\s=m.je_TM}¾ZOȵ5m$ Ĺ,{k^ kXl\sF!w검ME$m W>P%&vO]e٣&R Et3K6K쿷Aӕ̭R5v VTVNe-L.BDC)deҠ[ K1y@?(ƛ,"<\1=Iε$:*!=ke$K߸- fj̰g~D8[t{&y?ð~C&l?=O}|OP@ nB%ո6x(38!p?幀łaگ@ڄ.xqjfT r d{RtMdV5"l4ʮoYt=69*# $zg̞KH{>:q)VFdg[GoVw0ē\Cri'’Lc+^7,gf[Y^3ue0dbU+DۅY|ٛ )&0Bueݣ<Ě ]3`hsI ^9sj,"kS׃w %|^' /z$ L !{*iKSUŞYņWFRBx51OC=?n5J.NYka#Bc#/!E֬0x0 73=s)_,c~ަ.}tgR:-zT`b o˲ #:+@Wr/%$$`ӥkxD F٠ϙpfu].c&Rd[F;vRR[+cZ!h=:g|) "Y~DQx<vNj Bur ><k[ad^!+.Kr$# Bp#u[rҿ(EƛXC .6F D؄U0gW\вpk*AV,ZV9Ad%%~`*jwC$MK*_1f."r 乀fdțZ+ ,0y~x >wu.SSXP`o(zLؽL ̕ _ _Cy2Hڢ+/`)ec1Wɔfٶ3K5 'p[dY]J_]TeUS'l*Ϥ#ͥ$ܶPzhI]V VD-Q9-JwLE"kt@@k8MC)&?{XcGMDP^r Ň:Y> :WFQU粋!Q?͓E⧘]Qr{Bb ;=~רVHoVGKn刮HkƜoal$Z16Œ-qnInb>y:krۯ7\/Chє-?:0n.I)V+:@cq1ZCeP$ /*9 ~̆09Z2a]klLv~灔08 4:1y R 8!9? _IܨD;v,%s58䕠uvPN^r3Tn^cϒ@4^iDߓjꟉԨE"]Vr,C9H&o7N)/UjTC cB@ 5]FWszFũ]UH;FN5m-x\˕f@<ŽtXѷ},S@Tg~7TC/6O,ۊ)-{%-"HqI=yğ%%4ub hUG k3%ʩ7ۃY|Lu[i,IDl.PWrvaTMLp 񻺠s:!/J4RB{)Nxe)w픮N "j<"|m"5?JTNV7`hyx˲QVﶿ3Ci0"sl_#xEs+.R2ňt[NCDG?pd+5lJ8ŊjA5qB+Q!(p4YӘƄ)PKlEoK;5a3iι/ I{μq#Lr53~l}$K݌iJX]o[M6ʎ|2q捽d {VO!8BK &X0S&cX5Ǔ`'i:?SW ѭ/'"`B"luޅlNɏ/l~rJ_Lǰ+1iZ4W62cH'_a4J|đ(nY!hbb'=c\pS%Z%:0mr0F Ctm7ۨE- l&A@bh5 &{ܾ˘l%ؚ~uS(+Is=9 >w9ٗ %h G5><yrk)y{ 𢟟|$Z8XĊ[Iz-h1J'vG@%{OpV:{<0Y54A?0*V#ͅc2 ㋣(cxa@A۟1*1b2G6}*Y}/8t69U|dr'$.VpZs:{Kڦw+4+fe $+ 'vW%:Z\`N-#+$&$?%(!r-1&e$^&Nsq6~+Z$!$J?+x+Xt=$$^G$%| M$ ,  %-U$`S<<aE"*:*+d,jKp!",T(,~9,S-$;4+{$4l,|y-D')m#iFk%,R^V!(n~$Gf# zTu+L4!X{-f*O$n+E :% ,P:+pJ y,#: 1sa$%<+#^Y,l*,V`,n7$&,w+$$#c5%*? *sWs@~$qc+'* %l,mWW #%,-\lZ9!a^0<*w,G!-Vw+i&1wx+%- +M%ƙ(%$S>-,-s.+i=",Y%i4 )$(ܱ-8@+i@*hN#4`z}%1-;`+pL- *6oq+ii3$~dPVX'+A,#V&v$$[e _!(!(e%F8$*8sTh$%',n,j#5t1+Zօ_&,S-'-(T/I#$ '8c> xP6#Of2Ql #Yk$Ay%z(77:$#!\i-N!<$kҗ$S-++%TI$z$V% 4$*~En%jY-Sj-V+~(%?A$4W f++t&$n$,e%,$:$6-m Oo!#<(k++H$%,@4*ݞ8%+(o+h%P2'+~$@VEq4$($#v:#$$g5#f+6+^< ˋp#lW$@%!N, w%>'& $%%& *۾$HDC+j$e%HW0l2iL.\17(%eY,L|$*b+k&  j,YVJ+MGc$l$ +=B%$4+,-c_- s%v-(O/Q$$Y$*$b%R+-& -5[@-%$$,U`%3%9+ #Y|7Hmg++‚!o8-,$.'|%$>+%ɱ$rw$[-%-@N,CmR::%n#7$,4cu$V$PX+Ek(@UAq,C$u$$=%\hOrHl#gV$%J!lj$O  #*w%k%3,-&,u#Ih$#)<#3*D oRiNk%9j(~Q !Sl$$D,Wr#l&,4,q$oE{G$w^g++$$#k3S#%p-7EF/N#-.$_pJ$$--6\+J%$Ja%+ >a 9%gI-NL<r(-63#%Df%>pe)-m)-*%!*%$-a$:+$q6#+0&,$U-o+,zj,#%_+=?q%=]%G=+6%Io%]J!S+R~%*QrM%S<ee$ (!f$ZF7-X$*,I&)Pk$Y+p$2#J,L+5B%,EbrS=xu+%K~[$ze$V%G*s#+a#}T+6 #>!fT,S$V3%C#R%$+5$K$.1*]@+|-FGr$\LDlZ@,O-]z`eϊ`e#`#k~]W,q-3%V #IIS*-dO%+ez,%u,~+SA[c$e)v#GU$+$#}+O@+J* +{2-U~(ac&-7W+,+Hes9$3-!|TaHy'$$#!_t|l%@# Y;%S$u' i#dƧyk#J$$j![ 9zMu%j1-%_{e(<+8T<qH;#ȼ+<,s3U+E<B2y$9#6d+t'a$#,)VFx':+-WQ$rYN|-j,R,v!+-I -iYۨ$&5,/,^+1*iv';|u,J+Ndl/%M&2*Xgi+Expd<q-$;-6]+V$%aM?%xp;x$$2-o`W,`8}*{#1c'VN$'+0*B!j%-ٜ#+;-%O+(zG(&#\^ +M#H+>F,k#J4[$_,a+Wt=z# fS7+5,Z+'~%O,PV$&Ii-/#-$x--j_w%m"g!% O%\&c$E,##%ĦC&|0BChS%3\|,lc%5$x"$(HW7E%Q%){$ߎXHD'#3{,n`c#,B<4q m-$,j|-$V(J#77-l6+J%,07"+U,EJ ,9"$$j$~*Q'+Ӓ+$#3(%ʏ)S.>$CL۱-l*Gގ$$Ph%2!\E$/<#I2%}]7+*,#&nx$ʈb/$P%m$p$$͈e315$%=8{0 A(5$:+U'-eU$)+EC W+W[D %(,,Z_(T,[__%,՜#/s+$h$p4K$&%`V-L-i-77h$E EV$Kp'~9%*+r $v ".o+5*%:(5+3 M-b,S#I_Xc$#ɯ$#-X,x$$ނ$id% |-X}],y@G,&8"ΰ%N-i + ,c$0ޙ%{jF$!Y,$$zt$ 7 !-) *QW#$d+S\#rxJ~D$uzB$$!-3+- ,_#)#2P %exe $-V gQHR'7x%d%' #g9$Y%-D,l$J%0')lg0#w$QR,bc$d<#+| Vs[*,D# (|5Ҕ$A+#:Kj.L0-k#, hwo$*<`Ԅq!,-*(8-`<;Uw8*O&$^j--!$-h*m$+S$%P!gA!"nW&D$ Q(؞$')n-c %},m+4z+%$hi%- %$%]+ $<Y`xe-,Ts#M+g%O#[+XC+բ 3$٩$n%q$^#J+ #Y9#rw*Ӡ+ ߝ zq?C%++;bL$#% lg$T,[%8k*+%(+$$߷S(,$,Zk,$^ Bŭ$$K'9y$c$+E%q#{,^YL+ n$--2%"%?#O-,nzd$%,%#i$ְh~#|( b"e+G*"]d%$NZ*ڱ+ $X+-T+>Yg*+Ae$R"-D+VZ gL{$f,dZ7+Ox$5#a -]-$iLQ>+{-.#(#-CG%}(@\]*%!(9-R,x FF+Q#x}"i 6 c+s+s 8$sp"c$W-y#l %-`%v$' wGr%-]b,j]a+#߀=-]N++}$m@% %$[-R%ע--Z%+b+$--)%t-/$q{+0N+#j.$#71-Y+k+kf!m-'w%FS[ +,tT,ʟ++%k&e%ř< + *#j+5$Ѯ+q*-*>%o!$ n4#$d\gf,x$)Y-$,{vL@+۲,!)9%2nL#d($r#,oG$\ %9$1:!^=+%$<S@+$E+UA RxU!kO#c$2%:$& :-;8!z[$2Avg,x4+/LE|l%nmm%s$%#b:4$=a(j+l#`u%qP,u#$i0 #]-Xb%!7Hp#K$6Q'+cg1Ce!Y'*o@j%+@,s)-; xs#-0?%l!'6.E+E,O-IM5#ix$Lt+ |#X*ح/+Qn$<%,@,~eт!cD$Mj&N$lE&  ;^G+v'I#c:N0%P,FG$|#U+(R-+$N+%$$s',VFS,,F$(7(%$i+ 8 Zbw##,($+Q %G+2+~(ڦ$,* %qޗ0~#-,)*++%,oX-GI+'< `$#JtZ0"$$;J $7A|#kގ!C#$*(t$,j#2+;!,"%$P$ -"Q+R$Lw4,!YV:%[,P#9$v<[|$y+j+-*$ %2Z\*- Y&vR' )H Hh$gU4$9-53ð1%#,$1fi$F!-5!_f!ڝ$&U%x=_b$P& #p%*Uy1X$TN^#j,Pj% N9($%+/#2%+w$ $*,b;~%qS8$%$k,t%E>v#  ,B$'8~M'l,CL(<(MZ%F/$Ğ!u+-Me$ D$Ad$|+Y-K/%G#<,yQ$)%ib2anV+v$UE,-,[E-#N$$-4V$2;%`,' ,O$o+W +,#I,Z#W#g)ռ',/lX5$e-(,,d$M6-$$1,۠,-8$1މ+~'&s#6BGJ#Xp)ECM5%, +$K$-,$4,1~%*)W+r+,'+#DQI-: % *$]0z$IV%,Y$oE 7  -mb+,'n$j#\U,z,"d,z'$@8V$#(~K2$fT F5=%o$"5z$X +$z- qtEٺJ+*P'+#`5 eS>#){&!&A%o,I*rF,-$,yz*Pr7%$I%,"&Yq+I$&},V*Y%M&+eW % A#%`$s,,K'+)0l C%-04ӱ+C##+P<$=R%#:,H $*E+ԡ^$el.1$m$c+܏B#![.#n+i,5R/P,w$]U(+;.-T+w+3-# 9Xu[* B-n+%, "! -UOyz6)XL%w,DF5&9$ @$$$@*t#Qfe$`${X$Mez,$K#nn!)kO;,+TE$:j~3¯,0V$_)Q$'%ojS,[#I+$T#vr,eKr!#M#)!h*ç%,-0%#V,,f: \ QKKX+B* 7$˵Q-+3>$J#h (~#qw $2h'!$»S;$+#Iʌ+Q%oJ0d${DyDk&.llZ?w#'2$8*5c$ <#+NJ,-%1(y#$ˌ-j#)$u$H#+v+]%)E<(!\ BC!M$Z%k#W 8#:%!n2, >6,+5!x+1,G5E+x$ *v,O95 b%Ľ=++ Qg+!$Lc n%% - *(@+ #$0%rw,z{$$ #9!7I!)H#8X2%oBF!!N*9%~$%(-h U%ŝ,P U\%%t%DLgp$&-m<:i(A0,d*M-[=+3#-EMb&P(1$Ga $n+TТ%l+$$`E*`,+$GQ?%@,SV%$V<U|$$F~$ $,ej-l$[$[;$ O,_f_"aF%  6o $[%n*,]fG+~3+y,MD$+'%+ ~,$ k%mlH_l, w,J)D$+7f$ˎ…M6#Nb#u5=%r#N$<%*#vJ%vim%P%F#`ew#-;,-3#*N-')L T*,-]$\s#!&32!,qV#*-+ x\+?( "$3L( $NFfnD%,"fV!i`'{-i$$.$`$+$t+&j$ -:8%;ò,/"hE%=h}I52-\ #>#uu#Ӎ!Z$,-a$%SW/fa6#O-"^s!j},[r >\!-+ +~(1-6Ic\#MQ$),mR$0#.$#7$+I1.'>f#[+M\+jr+8:!C%C-a6@8+-M`%9#D!X"#aobMemk%T\*ܯx8$#f/,p*O.-E%$$y%ud$[U*_+-Dp(2 (!]X-^#9$i3VPi8 #a-e (-Jq8,\%^o  s#2z!k$ -_#I-}+ Z$#_$rWy<%1-OO,s\r''{,=-1LD%# %- +-97#W-+R$  #rg$K&7+)$/\qf{Jg-e$%rZ$\,WF&+# $s+N$#Vܳ$&%M'$ $ "rDf= X+%(W**#I(G+M o#!-aԄ%+XXj*GBx%9#CW-%8=^*ȯ46E+-a,+C%6$Ee+7#;# "$$S $#*R|-2ES<,%*(&%+8)XR|' $jE w$pE!Z#*%N$M$o?+=%SҨ^-_+=+ـ',W @$^a$ع,!%5Iwhr,E =#bg+% xo$$'!LY$yC%UI-$Y#)Ƌ', $<- I,*H% %#p,3#-Un6+i$$ $%#x$Н!`-g+êkB+R$I@F3i+{,i7$.$O+X-&E-P#J@'FV+:#+%+>.ga#[;$7,=$Kl,?$gF$/+G+$ dY*Bn$^+;$$K?=$O߰#$+-%Uy(YD$N#2uA-7#a((Qmr$j%]$H@9(b!"I%Z_ -YNHqR$FQ0:,X9{v&!+L:24^-%y$3i%s=,rZ#*Y+Mп++$^LO$P$ͯ&#+S~#Ji=+Tç%^K`qG%xv&X,I+JF$$ |vR {'6,m-%%Mm$h,T#y% 3$r!%;>9#$_08D,`bi$N!*[-Ny,O#ur;%-%/ '9)O$!Q)*عw+%#8+-8:+h^Uv-OL+^#N,X%+*,n ,Rd2_Ag0 ,$!',$ف$$=!h_\'Q$,q$,a#F -R-+&$Y$ O$G++A2?BE$(F,^5$XY# $_w v$'%B+y'B%N+ %z+Sۡ*oRH$ׯF' $+z+N<!t$]9)VO( $!$&&g-S-h(y $j$!%,U'y+g,{$LV_$6[$1$$Fw%W 5%$& ,%u-''z#+W$8#3%|/%q+T!#D ,`N+^,c%C3c\#9Dg$G,G+$  (-uTv&#-S$}\o#qyL+lPp8,Y%`@L# 5ˠ$-Zf-a1$ $ (,J-+# D@,yg$ׇl|kR-(d+z#k=X0c-Z=q+l-D v(Uh+߶#+U8$}$w$Oz)+$*-+$*,F3%lI%R-Ht/,+G4%;m,I-\a\+j0+O'o+(Q,P!$"+A,j&%}%ɝ==%}++KGu>%+L,'!u#0V$9md+άp%|C<.#d@+$ .(h W$?D@$]o#H$fc#{P$y^#IS'v޼++N_y ---j#^$6 =#WJ`v+o$ai!j~pCY%I%+a0%+IT+]%jE#<+Vٞ# %uD(%b!,^!Bz$g+ #F!"++ G(@$vASw$S% ,{$`+#6Bp -'*tH#/u+VF#{,-C+C-g^w|Y%?(r*%#u#jѨ4'8d|$>,] #%D.$l^%+< QK%=VگJe^$y0J,-36)8+Kq&Z,9Q:,%g#sL-M,A(׶<##g&3t L$$v$`=+8E *JY<_$UM# $X%B$a{#xDU/m*׭$s*$R0*%+@Dr,r)Ydd_-*VO$2#F$I,Od%v+0,@$-\o$j#չ #, J#t$X,+:N]+4W2&4+Y7$%'>,R $2+++?+g,DG#st!E*9o,? `*A7}H#j+:Ro!7+L+$%G%J uY$z,,$R$M,|N=+,E!id#`-!^N$)Y@J(/&w g%6*$rNq $\,%{'@$0#$7 jv+(Qj#`>#c.8a#k,u&2+$ڤ%{*֞Ӗ|*-h+~M#oFP& |+W`%$t(D,i*r <+3+:\D<#%ya#Ռ%?a#w9 $dj=+T$/i+ez;Hy+46 )S%"#ܠ0#e+4S^%P'l$!+,?$*#1%+S&zdV$%1!"$@i };#gr$)X8%a^%9O:0$+Ipj$ B^$m1+|F-+~#v :%$"<2+d9k/*œd+-8+-)^*J%<pL-9Y}|F $ ](ޕ$j*#$}-\C1$+Sky+T8#pwM*PB +=-H+z,$#c+X u_%T!8*@E# +*5#8-d(N!& $)HF,+,{3,Y-#(  5$w!,| }+4Tp (\-#=G#<74$7ik%Ed-$5T&%$w-)D$a+A,n[!'-jU%+?}%3-$,?D$H%r]>$FF#I,p$t$'e#,}F$)+>n#gi$ ($y#+USM-.qZ$@.%+8 G)T tD%$.$I#ȟVB+#[$@$, n$<%}Ms#%4ٖEz,(+ G"-T$K+Y-iC  x%-l`]+,-*$e;U#H'M zU`,wvi-S=$@'Cd)86Ֆ,LO;))# k2x%+M+f+P,v-#Z#%=$Ӟ,*(7ٓ#PK$QK$ +$c+1:#Β$a' sVj*H+,w*$,+$m$\+G~*%G +QDF%=%{Q$΁#YHUc+O+d,#ӻ$4 8n$@$ޢ#b+b7#x'ܩ3ޙ,!T,J _Bw$$Wz$J5#\[%~$Y- ,t}+N&i#,Je7$$I)#F#,)#E%z,UT ,C+5&$*#8M+p%a*JF%D !i$Eqk#J%,Y!) ,g$/!`$V-hQ$MX%E+ڨdX\$U3PvJ ɣxm,g$"Q,C$$<$,['<a`+,bc~*=](/$p+$]@E$@#&+G8+E%sgMؒw++2(id+;+#$!,>(5V#+<%@%zlw!Z,#+Lt,e%)M+Sq$3($r?/+@%!'p*$+$$!$Y8,A#o$E|X A#`+R-Lk%2;V3,Z$(#_#d:$V% +JH(x`l_% ,*,i[-cs-&,Z# ,db !_-#$;+ f8`_=%:EO++>O$B+9-Z]+ͪ%=#†$, zc# |B%=5%p$]+c#b ߁+Ёʉ $CHc%C}$-YS#Xx$?NV+$X,xb,C#,hm#[#e#Y0=u&%h{,*7x?Pw$UW,oZFLk*4%,-6#,F.'1_v$k$5(٪$C(:,%,j#u-_8,H'E;,=$%I$n\0!k%%Lsdn$,}%F_E%)$ӹ-W~%\/I,?r,i+K$"1 47#j--el$w,,q %#h9I$b)T$%]~`#}?$' Y$!$% b^(;6.7&5&2%,Q$v$NE !#V+g${޾#2$.#5$DVg+-9-g %!k+ 'is~$$#T+k, +r$J,}%D E,H$t#r^d,*&% $ )-JEW,|'G$-uNς$l:ȶ/1-0h$Hqs,4!,$2+T6!uRj#U$+}$+7%%-WPu--,3d$,,$h'$a(8 e+<ݩ+'&v%# <$ oT-h$J -i#c`-[$o$|1v%xQ |a%{v*+3++e%ܮ+5-a,@E+F$`f-+%,T#N-V΢+~v%$!jGku--%<%##w%oq*"##F$F*?x2$ ,(]$Qx%{_,mp$$W=$$!)!fj\H*$-m%s߸)N$$G$u)d$Ɖo1$c8+#,*%$40#8MW +t$}#%:.,՘! ~$>#g$$"D+9MU@[-o-p F+:#^ s v+6,+y$L%@w_(#$$$i-Z$$}+z<-&:a*w$-$#ڪ#z'c,-Zp%M# #ʡ>+S%%+W- J-z- ${<$e|=6+C4 %r9=$i#`+{-'$ #N+'ԭ(l-!++Ы,Xw$|N+!H-#)ڀ5*9+=$O[j-!$#p#\,%#}ȹ/>7(E_v)$$on&Azy,Ojz$$jr+ZZ!,lG+D%-$$&)<%`q%/##Q-8h#[j;%~!7,#),fhyzNҧ##{AEP#{+d(i~ V[@am$0J=#g#-\\!y5)]o##͓% -]9## $Bn%}> #h-4:+ b @NK$u+H{(+՜ dd+$v8#^+,=j,[+-$N##P+7)U,D,{$M^D%R!.e++W+'"Ē(9|%,=f)X(o2*<F~-!4G!$o&QRv[E-Xr,c.n3l ), ,#]?>+#<+P%%#STg+he-2-,W$D+,`;T7%R##3CxՅb%H]u%T%R%m#7$`$E&6"*7$x*u%Fr&#%ȏ$%$,#*%jD$Sl,M/$%tic,KM,+*ߛ#45[3,0h-&U$_ &#9ԮL$5+ˬ0ێg+ȅ##K-#t-Izm%uVVm,f#|>V%ȼW-HI1n$ -}>A$!##HQO$8!#!bK&,%nq++V%^~<6({_S$$(x!%BZ-L'%V(&k,$#Q(%+#xK#i)Y_'*F@$$,<!q%Te$|%R-+%U+bv(|%N$$| G$V&TE$ :+.,-Z,M # $$-# EUP4*g$7<'9\?$$*+#aT{+%!qp *(+^6P&\$n/(h#ݕ%%Kő+![#>R e$% i#-`H0#Cg+K%B(# $ը>DP(+%UxA!$*$)F!cqIBOL#X%:%%8`K/%%9%,XJ#[XuKi++X+*@,+&$`=8$_6(#%x@#hfcfUP+B+)#mR+,'%%ng7$ـ(#j[X-Ez+T $()2x$*6&+h5z-\,pJ%-J%(J8$$x-A$Q,Utܩ aZ1#v$9\%(Y(?,c-8$]*>-4$#V%,"% CH$$P+hT,Sid*aA!ZV%S-44!Y(g2,_;!Wτp",' ,eB +͐I?,K#%-k$%#)$"pp%+#(,Q!##s(h*N$%.% v3k#!#&$CLz{#+Ѭ5u%Y$j$bu|X#3L!1kg%}? [ 8/#$z#%ki_,s%]**s%z$r[%@5y"*g@N%?#AVJ+G n%k,?S -t8% h,E$-H~@+3V$ h(.)܉,o/ &*˝+v#2#`+BT-+k#F &*%$6F+#%M@Dolx+cR!#4UGZW9#2#U$L$Ϧ+^,^>*-!3$G%ښ#6-.!DPuN hr,e$d%$c  (J+S$c+V(F)$I#n9O#d,c,@_+5 %6)'+!g$F$a!#%_% ++,l&y$ ){-K$orP-#ohm#T L?%5^#e+-FBh%#9$B+jg$)+a,?Dl$'%p1J+L N< #-D%f+ sn$- U%+-;$++JG\%+>%;K#RG!+A$39#~-;)%\,Lt!bxS#~R-G_$N)!^,+s#,Q{->WQhv,y$M%-__S$ G-*u-j#5= (Ɨ(0${i[jn%=)%P%2(1_#Q $zD0 s ($|-pJ+2$e%`t+3] -`*& GW.c$%e!i%|V$$-Q|*$+o#]m߅T+~#T %QI- |%k$ί%Yv{-Gt*۔,r#VUj%$ O|Z,wW 5mj!!;,t$UM#]$tPE,+9%!&+Q,t+#v~%#7-or$g,(+#ő$!'$+:#R#'+,$']+˅$~*Vi"+O]-W%+tY$y$$d$-C%$T81f$+pc,%#^!(s 2${p+N$;-8$$!e6+%$~ /-+B~?%xVc,emn,/L8% +L$R]$+S% - p_,0"N$+ (4&E,,~#,c8,_'+)mC $%"}$tq4$6g+xB+Pg&$6"S$~X%}-{$#|+y$΅$hr#$$kU(Ќ~-,$ V,X-K1%7P (9E,t#',s A':B!\&%WR\\]$T+ ,,Q+7$".$(h H},`E?)0##]%#s9+a$%HuK$Q -g4$%Ǽ-!Q* %I. N$B D& HTy%$*;3$#B$3l4r *$Cu$As1$J$ct$+X,-)%:#![J-5bdde+Rl-b$&+K@]$by(*33iN+_iA+X$%y-T*Ct,eÕ#C$o-Cb|,*%t@'&,&%pc+\$}Hy#VK~2no$dvhV.'ߍXG*$0w$",p/iL,1YT&i8#]vA-E"$3x%& A{bL*tcM)$,y',%?bE8x}$$ -Lh!(,A-g8%{H$J-Ej+52y+s +?+hb+KK$>FSs$Vbr (.O%4n?++P%ih%-^F,]#0_,(+{#4 ,>-3S#h+K}$!P${:̰+3k$,,[G$-K5h,N]c% +,}*3:SXT+,A%x$p-#n+4$%W+0/`%i*2$w-PK-:`cD!6#S(n%#I=!qR%&$>+Z,q-I$<$%01#_+%$?-V$2$v+ - $n$,kK#Ĉ%#ex#(*]hG$ϝ $Z,-o-(;($F$##H@ <$V!F(z*!_E-$\$,X~\́#n-c 4RZ-%ʾ,a߇KI+! w#{ $$!w$fj,[;#4#i;%&|c%<+,v\+i!\_(X,N!]8L,)2e  % )W(U^%$L$\% -%?-3#}-^7>dI-2&a%$<$P#9n +q*NJ+7$?#E$J+6$#E+t,ʈ-n3+ (n*ljXF$a#-$_!^p$$a4A%-z4(+ *P$NW#T$1-\Q-kP]$ܿ\0$s[Iz o+ +$,$P+7:}E$$%T?"O%u 0z+ !DS-I1$!* R,B#) #$ǿ$,V--/g+b%EL#כW*A *+M.-m 1!gx-!$$I#i$(*,Hiu$K'g--8ra$n^$+>%{ z%Cul "F,qp+C+;+P,o-Rt#**w# Dn$E!-,dN%E-e$ r,f+a_t5$$$+h#T m(A#}\!(-7e8[%Ed"*##{,]3++s%H,R*&$+="dz,B O%J-W$$5G)#$#P$0P $+|$^4"-&^_,$a,%S%@,(-4X,jM=a-M8*F+ ~#g*ʬ}$'|%,*%kI+%8_U$#R+1r&$d#v0eH&%u#2+Q6<+9,?+ޒ*$#,$t}+e$;,E4%$>-g$/$k%U+3mS$ #1#?$4R^[TC(Ф0$1$>+!&$P;+7$q$D&I$8$z/J c#`PL'}1_e$) RC aIcL$p$օ*#|+0$VǍJb<,Si$$ +C+4 $`#H3$? O_2Q$so%܀+ث$V6ST`#GV1!*.$-(+JRM%+g-4,$"b$à1(~$O,#ö#X(  ,.#5$i%d,P;M%$#i-^n,XD$**%+}k~j!F$%z$G)rrp%Vp.#$Ԣ%+$+ &"a-`d#ȏ#!%F I}'P%i%#f/#C!a*% ,A,Y$U*I%J#a,+,U%UA$$7+V$m#V$QK<j&vT$-4,B)\R %3*#q,~i wL,NS(+<,- @I+,wB,-dWH,H@#<(Ԇ-I";$y%F$bU'8' $;a-nE*r0+dC7#X4$%:[/x,L! (U+# %!T$"3&&!at%2U#Eb$9"Z!i,1(w]+-%U6!Z,"'P,0ed% 6e$"+ #r7#$,aL$b+WFE*-a+7 ,= o+KB%#*#\t%2pc]%ߣ#ٹ8%[#h$e%z#j%Ca *2_b')$;$k,!Z*$/$-$3G Lf,`#m*32~&s-Z$e$+MY:#$M#n#7,e# !$4_%+%*]r $|cw58b#Ta#eC*$$6$$m04%1#Pp$B a%JC'$&$Q)^$_%E-n$8#pV+[w:VD?}+sd\'$W% $t^#XR$N*@ `MӑĤ$RJ!.R Yd ܗF#Ja#m}2$Ky #Q#y!:%^(#6,`$fi1,Z=&#5*#4te*,XFd%v><ag%#Q~+5$R%%Ak+s %%9S%u7+2!,,R+i3$xK 'f$t " V+^#K=ehJ+g)X*9-g(N%B#*,$k$;,GV0N9%!(]+D%,1%*$AX##@+E_#U$m =%%mB,+g,+ۘ(h#|S$h$Mr$BB% -J'$b-+#M 1$+#)-d#J(,*$rH+uǛ%T-M5e,#x|A A+j#-Lu$W%-%˱bo$V4$K#R+=K\*-*-- g$[9#v~ vb+,+(@&m-VOx3&-*- E$S#.WN--xV#Z$ Mr-$-,&-&-$OAw#()m-H+#k$u3/% #]B(c$}+@a$9#$*w|'% (<#H%8B5Mdݹ,}o#*8,+^*% +V kDN- K%0-/%w$A,&G ,]]#K+5#Vn] ی+#J[+ '#lc%Pnq-$%< R+bc+|T:W%-)-O 'K6X b#A%I*ya_:$`?S-:#d,S> #L+l&-neno&U$ +!+0r)]"';-` w*p+Q%!rK@-Yq$50$l+$,4% ,fa5$+fB ,%`$Hr*ޝ#j,_$?s1YY$j,v$ч$,6i$8,i+C*S#K%Bk#889$}1' .1X.O-S$x$+j-*+̧%%I$%N:*U-*h#QV,#|k$N,@r+9#o$#6u#%%]  Z+ª#nc#r&s*#Q*##HpD!$(8$f+QX+6N(n!xd+e*%,tEeyF(WN!b+ij|$#C#R+F%q$J#n$J+!&$gjL_% #] +,z$ 5#<0%uc! " :Y-i1=lb$k*2X)D%0rXJO+ W#Pz'94'9A*#+j $m##\- c86++f$%~$h% d+$*CH(D+UXl %r+c'&#Lչ%e$J RDo+, ?c'4',k%$tl i!i5-"+j_%!+m-i-iVT{q-2@!?-m57c,մ+DN <{d;?L f~r@'$vniH-B+j#g#rd]':$%1%x$*$1%Nmp,/! Y%%i-t%,#{$~`,KFA%#A^&+0+Q#b$Hi(C+`!`(7u++W0%Kӥ%p,${$w/$1ZnnD->+ ."*4 -a^+ f Q,$p~S%T-,ux+%|jF-%2-+mh+gmaVU ^_Q_ G 'ҕ,M/# (W<Uv%u%˄{S+`# >ja-X/+G w_%$eM$h xq+pOo+f+>2+l3,!'?S_>BH0!c"$ŝ|${btt$(u#q,M $z9+d+ S -H%8Mv$0$'Ih rZ %v$=%{#KDe-QY%>F6#[7"4D1?9*q, @TL}$}QE#4b!e $#߯,uP-m$_Ay1 <}!*A!- %N$x7e'ri{%;Zݨ+B,vLhB-[f$q)%$>c#^k#43Y?O,$|y$ +,q]/ $R+r$J$fdO+I 8$'!8%%$_@՘# #$IN-#։?&#}#w`,va,_-^+ߊ#%@+Ś+$%s$f$+J0$f4$p+#6pj !'$ !f +,\rE#VT%O+O,,"%r5#I)11Oo,R1k,Cyx$q2#q--Z8%*V$s~L+P$$YH*"{Aj}% @$aˑ+ N+e$[-Y$$$D-*b%>r{6' B|!-5N,D$2$Qʩ!,BA(g&~-d{R5},>O$q^,gB#H`-kg#x#ɢ*P n$,"#N%O'#f$+$D,9z$uC3i%qg#;%q{%# ,y$b[c%–$xPC,5;7|D$i+=G-Ye(!De7Yэ"]#:$#:%QkVg(B$bt-,b -%/!+$1L$+L#~\΍$W% |%w$9 ,_On!c1:&2 S,C+{%jsmT,W d*A4,u%1!"L#cRP^V$^#]$(#JY$#J!C^,%$]&%&{x h4#R U+Xd,cc,t+D'**K%>%j'0tYeXg_Ph+ħP!d<!uR%T+%y>$L+k$[*$ZX`$#+/6hq)o$% .u%h#'-[+e,_$U *O+!g*r]"o+%k$d,Y-#H ~#&+Y!\5-^,k+#+$ ъ+%7*#G#q+s(pۿ$">%<#to3}$0o,/$+$~J ;+S%#,#q[$(9, ,u $m!+r`$ #,r=*,S|"^04:-)z@%/`o+ʦ+;#$R,g-`,av-'+'%5$hT*+%^#C,+$P%$ ,}$Wg%c$@ $-5!. (m}s#\&Fc_%$$'$:Vj$(>Lj:& ii}(,>$Ȟ9-6+%$ m,uuW<'-<#s$%+E^c$#6:# %oz-Q##sl*f#`+P,c&#%(!A$wM$q#!GE<o+-Ks 6h#$q^[(G%xM -K ++Y= v&_ ?PE$dj$0c%4#Gy* le-G4#%7(ӄD*R$I&$* -f>YH=Pa/$8$P*1#$s,H`+%ByNm$l7!G,v'Ӟ ,d%ޟ$v,k%m",.,"v!#V%)!**m(1ȁo]7$#$-m;-G%jU,h$l u+fz>$D)$`%q$:: k%(X$#_}%C5#Hs%F}$ʊ~$(V$E8$m`#_%b$R*L#L!'#,L,x$l$&$y[$8{=`/-C%S#K?7%,1,|%+MǣPr1h+($\H#7U!+j%Kr,\%+,g$g,y+=,x*$@f,$H$wG$+Z=f#a!u%tE#yl$g!,- *r{-=%%/#}j8-aU$m$N%)mj`/$H-(,1V(I$5Ak$}$-M%?9+w+ϴ$8N+p#_+i$8Wv$/+I$g+=X(Kw S#˼,rXH-IvPS,l.$+8+5?$R5m+'z+ȭ'%Ń$|&%m&Y8$v]so#;+h$}U#a]:j%j3+[#}&O#Ugc7#j%}f,Y\-f%U$(!,#BSb=%-2$,#',X-$$B#Jae \+Avn% +H8ɋ,j+F$Y,(Ti\%lIa+B&%ǍV+)ʞ%Q\F+|$E $,K(##;%B%,l?}kWQ'6+*:UKI$l"-!$wpf$S{{e#_%*kR,(-#$q*xG$|#%f+sMw*-[(o4ܜ#5{# ڱ*f+$n$H'3"-T9+:,$Ũ-7$Xa *%${Ap$'&D!+[d+H+CL$P> z $?Do$C% E1[$#l#LpM!jR!$`D#P+Y m#(-"',1,+,X* _fN!6-h#m#D$b(F+$t+$%;B,J8^&7$m$vn=X$<+\%C+!X,.w~$A7-.+'hq/+9v,p&@o(۵S(C4+a3,$N !R# x+#92%+p4U,!#`u(kb--+~,- ~l,-X#p^R-ٗ-((Ѩ,ԅ%(l+1\g1$^/~U'U'N~ +f+6B#@:m4#B( +^$0L?!g#϶!+NhuS,l+Vn+.P#s@$f#!d$C++M-e#m$M6e1{ J+#k`$o(~n(|+Xw̮%%&#-#4e %c$x$#t#\,E,T% %o$Ty$X-$ $*RP+~*+!aώ!%M+SC,-%V(@$Z%, )xc,WI*[K #$$+'+0,D)9 ݊#Ff$#!$i7X#-d}!^Co+,`#;w-:#vP,W+4%  B@*#V%I$+eksb q#X%$-,$#-$47H$ܗ-P,a3$m%5= ~+%#&)+-6$7qV6$OX%E%1Jk:&p$6Y$+ +#+%YwP̎.$6q9LOt,mO*G ,0#G,d:$۵B@{p,~+:O#%SXt!6$+م:$$1$x3%p% +. -/##T$+)H$+,}+Ffݝ-XX3-!'(ݓ--Q%z kW%)~%&%3H #EF,yL3,-D+0+$<#U+HX$ly+/$Z+ S-$k+# 45[0^#-bdB+%ti#v$#*p֙$>#D,-%Qsuo-G5[> %-;%?%~+Y+d%,+6(,A-j$OH?%m E0%q-H-d%I#t\- c,W+ %!%o$'#Us%(6Q$ 0+o#;M*JD#+H`#O$6y<%`{"+E$rwGG8ߗ9K+P+ƩZ=(%#d,R,2%+&$+Om,]GlEj $p"e|rǐ*U*O$!%"$=]h!#`%g(('S}'%#A6CL$T$)X+II_4%T *z%Y$R$Y#ۛ\#%3!b,ia<$u9(,+a( +L($@,F^'h|n,\/+$Ns#l|#ƐG#F+e,+&%8`+)){(ׇ-e5$wOxy0*O_$0A/#SNx,&(,]17,!`e,ZW5$x,ʒ+k*3^e4-j#d%# $()$ v/$T!g'A+9$ʵ,G^)W~$$s'w- 'p%L8um#v#L&X8+#1,HT0#+#n#V+8|+:)-:#;(,,M$&'fp'+D._+#;!;+~X$< #2?+T*jiM-O #@-$_++a#$A]y+},<+P'[+.%n+m#'Gaٛ*Ms,>+%\##d3-3_$,T$[`#p2(*5$F%UQ%8w#!]X%$:g$z|&%Rs,st $O& -,A!*њ&J$lU1n"Uz*-Bs$W@ ZH-_f,$%R($S,y-! +@+q,Yu/S*F-RG&D u#Y,E$Yu-,#ƻ,K Y)L%,U#o*$+$$''nbl+2%D#:+ 61L(w,N ,J[7$6 av /9, H'b+C|l$Fs%w۔%$9# %{/- 0aF$pQ8%,)8'!W+qm@*l+*X%$ҢT+Yx%$Ij+%;,~<#msl+#r +FR$D$0.%E$g,f,>WhS+4|#F9 ]+,b,$+6% x*rم#b$1#3o$6!B#i%-7%])_,d$(YO+@Z%DW6+r#%,$2L!#9% ^$#uw V$$j+Bm%*\ё)O+ BO|m +,Wi+%%%ۤNI%|*_'.U%Tq-:Z$ bh)ٗ$BdV sCt~#:a)8Me1$+k,j#q=-+P,T$X5-$#$*|-H[-3+X=9k% -1t6#2b \+"K$")%$,^ST~bj)) *IZ$ǐ_+G|)$P_%+8%$"I,/a#jPw+٭$G$,o$,z&-Jh'W*i+w$+6n,T$gs%}+z!( , N9w$\u##fD$c#iI!dd$xWϲ%/M Ou)} k#[+H#'V%i%A(oJ!W'k%v߾N$%"%"(SyC+c $iS,-3%T-T`%1$o5$$%d+}+چ%$Ž)+\`+i yK2H#h,JS%\,|$3-Yw~ $*$O-2ir#%t?$i-T,TFk*$Ѩ#8,g+;\$Z$c $!$+$A$^%{Ƹ$#y#`l'8,Up:@$%B$ f!b$w+M,MZ$ W"$Wt*$Z-E-_+},8,O !d,h+@,I7#U%Dk+Ǐ$LQ,}+,$U46a,g$2%$ciTy|$T /&C42-M$ @-w!iFCl#Yb$5V-_vF *Q$N%'%,s#pD6%N=$#6$e$K$_E,P!]a2$a+q$$3K9+e,$Q9!#}fʥ$I EHBUu%,!h%Kwh+2 -'j-k)I3+\Fj&#q~q,a"#eE7%o&$\+M1$>,%nJPA+׸+*2hpr~$]+ۆ#,q K(#S%&#L^%H-%,9+*"A- Q!a%d5o&!l$Nd#S#t-,$,$D %'X$~!+;$r+I)7+1,.)UX$ƴ+K"}+r1R#$$#L*r,%#,DI#+$I'E 4pMi$*$S$L$9+@3{%~U#{$:$,m&'`s_$#mR,V.-ZG-11-F$3 %-.H&P+m!(۪+W],Z$]&bz4%I b#Q$3+:"-9y+(z+0%&J!Ni`qO+$O%p;y2Q&v/-F$,i|Z+-CT,rf4-LL$%Pc+љ*uk>J-9+2h+j,,{#B/#i$#: x'#'$ ,$^|2*V#eD<zl#-,cZ+8$k#ѱa*k#+=[,ms#c+X5<)y#!#+k++y01yA$!$v-j$ $-N$ 0j,r#%~. \&,)&~%z`,T.%,%x+#³#a&%-^$^`κ0m$YTw6#$+-&<%RE$+y+h\#T#u,%%L%w#K{+-$w($>5-U = lrl#5%?$%@%6GP#LD$?+V,G^,)(|+#v ,r!(O#@%z#Csq*#nf+7c#WC1!^3~ $X}%w\$||,cSo*p6~* &)+ +?O^_!b(=[I~+Uxf.-NO$<@]P%q # $R)$\Ҹ!%!Bx&%4+RB"yrzX- C%d-/&*pv-/>+;$z -S+b~,kX[+z(ӷ%54Mف`8E#ՏONګBtrousers-0.3.15/.git/info/0000775000175000017510000000000013663651671014555 5ustar deboradeboratrousers-0.3.15/.git/info/exclude0000664000175000017510000000036013663651671016130 0ustar deboradebora# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ trousers-0.3.15/.git/refs/0000775000175000017510000000000013663651711014554 5ustar deboradeboratrousers-0.3.15/.git/refs/heads/0000775000175000017510000000000013750246207015635 5ustar deboradeboratrousers-0.3.15/.git/refs/heads/new-release0000664000175000017510000000005113750237473017770 0ustar deboradebora94144b0a1dcef6e31845d6c319e9bd7357208eb9 trousers-0.3.15/.git/refs/heads/install-as-root0000664000175000017510000000005113750142313020575 0ustar deboradeborad3fefa3e4717b72bd90aac8269d7cc0f00bbe62e trousers-0.3.15/.git/refs/heads/jerry_no_optimize0000664000175000017510000000005113705244530021320 0ustar deboradeboraa0570c2d9452c68be0b02d9346b445e3fbe1b246 trousers-0.3.15/.git/refs/heads/no-opt0000664000175000017510000000005113736474746017007 0ustar deboradebora6edef3777f9b9a26e63168bb81c8d4f4ddb17017 trousers-0.3.15/.git/refs/heads/resolve_build_failure0000664000175000017510000000005113670365657022135 0ustar deboradeborac9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc trousers-0.3.15/.git/refs/heads/master0000664000175000017510000000005113750246207017047 0ustar deboradebora94144b0a1dcef6e31845d6c319e9bd7357208eb9 trousers-0.3.15/.git/refs/heads/indent0000664000175000017510000000005113737553574017052 0ustar deboradebora6edef3777f9b9a26e63168bb81c8d4f4ddb17017 trousers-0.3.15/.git/refs/heads/cve0000664000175000017510000000005113715670620016332 0ustar deboradeborae74dd1d96753b0538192143adf58d04fcd3b242b trousers-0.3.15/.git/refs/heads/michal-schmidt-patches0000664000175000017510000000005113705345216022067 0ustar deboradebora44f582475e739d0a8f3b4ea1bee2f9c98f45ffa0 trousers-0.3.15/.git/refs/heads/manpage_cleanup0000664000175000017510000000005113703757770020705 0ustar deboradeborac9b8c4434f3b11bae4f7e72c3aec5b4f3459eecc trousers-0.3.15/.git/refs/heads/jerry_coverity0000664000175000017510000000005113704255005020626 0ustar deboradebora0a14b979064052d3263054488602fba3bf97883b trousers-0.3.15/.git/refs/tags/0000775000175000017510000000000013750246564015515 5ustar deboradeboratrousers-0.3.15/.git/refs/tags/TROUSERS_0_3_150000664000175000017510000000005113750246564017670 0ustar deboradebora9a2b868cc4c2a33e4574f2cc512595b539664fd6 trousers-0.3.15/.git/refs/tags/TROUSERS_0_3_140000664000175000017510000000005113663652044017664 0ustar deboradeborae92c7c8658ef9f21826f7fa4c48a9ce6e9c27dde trousers-0.3.15/.git/refs/remotes/0000775000175000017510000000000013663651711016232 5ustar deboradeboratrousers-0.3.15/.git/refs/remotes/origin/0000775000175000017510000000000013750240533017512 5ustar deboradeboratrousers-0.3.15/.git/refs/remotes/origin/master0000664000175000017510000000005113750240533020724 0ustar deboradebora94144b0a1dcef6e31845d6c319e9bd7357208eb9 trousers-0.3.15/.git/refs/remotes/origin/HEAD0000664000175000017510000000004013663651711020137 0ustar deboradeboraref: refs/remotes/origin/master trousers-0.3.15/.git/FETCH_HEAD0000664000175000017510000000033113750246207015144 0ustar deboradebora94144b0a1dcef6e31845d6c319e9bd7357208eb9 branch 'master' of ssh://git.code.sf.net/p/trousers/trousers d37101b48e17833342acbbd00d4524e9a89ef2a8 not-for-merge branch 'next' of ssh://git.code.sf.net/p/trousers/trousers trousers-0.3.15/.git/HEAD0000664000175000017510000000002713750246177014243 0ustar deboradeboraref: refs/heads/master trousers-0.3.15/.git/packed-refs0000664000175000017510000000457413663651711015736 0ustar deboradebora# pack-refs with: peeled fully-peeled 8a867e82a537990d7c21bda22af832cf9fcf4772 refs/remotes/origin/master d37101b48e17833342acbbd00d4524e9a89ef2a8 refs/remotes/origin/next 4c6a900d5d7170b190db906065b9597e1e00c5ff refs/tags/TROUSERS_0_1_0 ac3558d138d1305130647f4b5a3ce512a2de376d refs/tags/TROUSERS_0_1_1 be3a87fee806e310af9fa84f70caf5fe203bad69 refs/tags/TROUSERS_0_1_10 f99162a6f929ca370078271eb2d5b574779473e9 refs/tags/TROUSERS_0_1_11 a33abe9fed57780d4c02b6a6ab7e28ee7d7a3794 refs/tags/TROUSERS_0_1_2 45438a521631b73f5c6d81629c1d78af03d4f0a2 refs/tags/TROUSERS_0_1_3 91bae3c5136771a005c32ef5a44c90c4f6621805 refs/tags/TROUSERS_0_1_4 b43716238fd1ccbf73fb8a8eafd8b883c03405c3 refs/tags/TROUSERS_0_1_5 34078a5f0b9fca7a751842a22d703058eb9fa24c refs/tags/TROUSERS_0_1_6 e55b3689f1f35ee39b3e1fe8964c1dfd1cc8c7bd refs/tags/TROUSERS_0_1_7 9cb262576c29497d26a1d01033e48f9b7fd4f17f refs/tags/TROUSERS_0_1_8 6cf9ebcdc178ed4bb59483d17d97132da7aaf2cb refs/tags/TROUSERS_0_1_9 089d44e266e11a97851ccc3c895340d27ae8555e refs/tags/TROUSERS_0_2_0 9ff69f8957dad4daa5d7523422168be3d8e246d3 refs/tags/TROUSERS_0_2_1 c27099812e2573c5228e2f40cbedbf3bf9e9db32 refs/tags/TROUSERS_0_2_3 ecd66b9a314653833ecf6b7d71049594bfe1e11a refs/tags/TROUSERS_0_2_4 5ba86c1dde27b4bbc678bdc512a6750347abc0b4 refs/tags/TROUSERS_0_2_5 33ee49b6529d294c5587e66d4fd1788c587c4840 refs/tags/TROUSERS_0_2_6 1ff301778413178c07112d13aea4ee52775c8762 refs/tags/TROUSERS_0_2_7 8d448a31a46a34ae7933d71ba1360256c187e5ab refs/tags/TROUSERS_0_2_8 1022d6be74f0336ae4056bf50d16972cb907bc61 refs/tags/TROUSERS_0_3_0 979a21dffc806fc0ebdff1b3150811f52a0ce739 refs/tags/TROUSERS_0_3_1 285a38711d2a961cb14ec04b53908d30827f1b8b refs/tags/TROUSERS_0_3_11 ^f11e52752babf45b17ae1469ff9839c056cc7750 604238f5d1f62c25232a05c5ecf4b90e14befcca refs/tags/TROUSERS_0_3_12 ^6deeb2d5a24cd47fb0a9fa98f0c085b09fa3ee53 278767a6f2f71353094d203965a080e302831f14 refs/tags/TROUSERS_0_3_13 ^a6df7c64ee57971974f3fe264f76645ad50d874f 7b9343c16d902ea48c27014f8edd6902c0979871 refs/tags/TROUSERS_0_3_3_1 d4bfee57747ca21e7c82dee2e98cff9958ab2269 refs/tags/TROUSERS_0_3_3_2 dbb81d8952a0ac785971c7459b8c08100eebfd4e refs/tags/TROUSERS_0_3_4 5cc0f544a1ab0822ead7da8044b90452e60de226 refs/tags/TROUSERS_0_3_5 07924509300aff226b19d67fc07f37223a936716 refs/tags/TROUSERS_0_3_6 b42e3d82b8c3d31ba540585ef3293f8f7df15bf8 refs/tags/TROUSERS_0_3_7 962bd0bf50136f80e11ff0ba103914a09daacde4 refs/tags/TROUSERS_REDHAT_SUBMIT trousers-0.3.15/NEWS0000664000175000017510000000000013663651711013441 0ustar deboradeboratrousers-0.3.15/src/0000775000175000017510000000000013663651711013543 5ustar deboradeboratrousers-0.3.15/src/Makefile.am0000664000175000017510000000005313663651711015575 0ustar deboradeboraSUBDIRS = trspi tddl tcs tspi tcsd include trousers-0.3.15/src/tcs/0000775000175000017510000000000013704262702014326 5ustar deboradeboratrousers-0.3.15/src/tcs/tcs_evlog_imaem.c0000664000175000017510000002203013704262702017624 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ /* * imaem.c * * Routines for handling PCR events from the Integrity Measurement * Architecture. * * The external event source format used by IMA: * * 4 bytes PCR Index (bin) * 20 bytes SHA1 template (bin) * 4 bytes template name_len * 1-255 bytes template name * 20 bytes SHA1 IMA(bin) * 4 bytes IMA name len * 1-255 bytes eventname * 1 byte separator = '\0' * * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #include "tcsem.h" #ifdef EVLOG_SOURCE_IMA #define EVLOG_FILENAME_MAXSIZE 255 struct ext_log_source ima_source = { ima_open, ima_get_entries_by_pcr, ima_get_entry, ima_close }; int ima_open(void *source, FILE **handle) { FILE *fd; if ((fd = fopen((char *)source, "r")) == NULL) { LogError("Error opening PCR log file %s: %s", (char *)source, strerror(errno)); return -1; } *handle = fd; return 0; } TSS_RESULT ima_get_entries_by_pcr(FILE *handle, UINT32 pcr_index, UINT32 first, UINT32 *count, TSS_PCR_EVENT **events) { int pcr_value; char page[IMA_READ_SIZE]; int error_path = 1, ptr = 0; UINT32 copied_events = 0, i; struct event_wrapper *list, *cur; TSS_RESULT result = TCSERR(TSS_E_INTERNAL_ERROR); FILE *fp = (FILE *) handle; uint len; char name[EVLOG_FILENAME_MAXSIZE]; if (!fp) { LogError("File handle is NULL!\n"); return 1; } if (*count == 0) return TSS_SUCCESS; list = calloc(1, sizeof(struct event_wrapper)); if (list == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct event_wrapper)); return TCSERR(TSS_E_OUTOFMEMORY); } cur = list; rewind(fp); while (fread(page, 24, 1, fp)) { /* copy the initial 4 bytes (PCR index) XXX endianess ignored */ ptr = 0; memcpy(&pcr_value, &page[ptr], sizeof(int)); cur->event.ulPcrIndex = pcr_value; ptr += sizeof(int); /* grab this entry */ cur->event.ulPcrValueLength = 20; cur->event.rgbPcrValue = malloc(cur->event.ulPcrValueLength); if (cur->event.rgbPcrValue == NULL) { LogError("malloc of %d bytes failed.", 20); result = TCSERR(TSS_E_OUTOFMEMORY); goto free_list; } /* copy the template SHA1 XXX endianess ignored */ memcpy(cur->event.rgbPcrValue, &page[ptr], cur->event.ulPcrValueLength); /* Get the template name size, template name */ { char digest[20]; if (fread(&len, 1, sizeof(len), fp) != (sizeof(len))) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto free_list; } if (len > EVLOG_FILENAME_MAXSIZE) { LogError("Event log file name too big! Max size is %d", EVLOG_FILENAME_MAXSIZE); result = TCSERR(TSS_E_INTERNAL_ERROR); goto free_list; } memset(name, 0, EVLOG_FILENAME_MAXSIZE); if (fread(name, 1, len, fp) != len) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto free_list; } if (fread(digest, 1, sizeof digest, fp) != (sizeof(digest))) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto free_list; } } /* Get the template data namelen and data */ if (fread(&cur->event.ulEventLength, 1, sizeof(int), fp) != sizeof(int)) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto free_list; } cur->event.rgbEvent = malloc(cur->event.ulEventLength + 1); if (cur->event.rgbEvent == NULL) { free(cur->event.rgbPcrValue); LogError("malloc of %u bytes failed.", cur->event.ulEventLength); result = TCSERR(TSS_E_OUTOFMEMORY); goto free_list; } memset(cur->event.rgbEvent, 0, cur->event.ulEventLength); if (fread(cur->event.rgbEvent, 1, cur->event.ulEventLength, fp) != cur->event.ulEventLength) { free(cur->event.rgbPcrValue); LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto free_list; } copied_events++; if (copied_events == *count) goto copy_events; cur->next = calloc(1, sizeof(struct event_wrapper)); if (cur->next == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct event_wrapper)); result = TCSERR(TSS_E_OUTOFMEMORY); goto free_list; } cur = cur->next; } copy_events: /* we've copied all the events we need to from this PCR, now * copy them all into one contiguous memory block */ *events = calloc(copied_events, sizeof(TSS_PCR_EVENT)); if (*events == NULL) { LogError("malloc of %zd bytes failed.", copied_events * sizeof(TSS_PCR_EVENT)); result = TCSERR(TSS_E_OUTOFMEMORY); goto free_list; } cur = list; for (i = 0; i < copied_events; i++) { memcpy(&((*events)[i]), &(cur->event), sizeof(TSS_PCR_EVENT)); cur = cur->next; } *count = copied_events; /* assume we're in an error path until we get here */ error_path = 0; result = TSS_SUCCESS; free_list: cur = list->next; while (cur != NULL) { if (error_path) { free(cur->event.rgbEvent); free(cur->event.rgbPcrValue); } free(list); list = cur; cur = list->next; } free(list); return result; } TSS_RESULT ima_get_entry(FILE *handle, UINT32 pcr_index, UINT32 *num, TSS_PCR_EVENT **ppEvent) { int pcr_value, ptr = 0; uint len; char page[IMA_READ_SIZE]; UINT32 seen_indices = 0; TSS_RESULT result = TCSERR(TSS_E_INTERNAL_ERROR); TSS_PCR_EVENT *event = NULL; FILE *fp = (FILE *) handle; char name[EVLOG_FILENAME_MAXSIZE]; rewind(fp); while (fread(page, 24, 1, fp)) { /* copy the initial 4 bytes (PCR index) XXX endianess ignored */ ptr = 0; memcpy(&pcr_value, &page[ptr], sizeof(int)); if (pcr_index == (UINT32)pcr_value) { ptr += sizeof(int); /* This is the case where we're looking for a specific event number in a * specific PCR index. When we've reached the correct event, malloc * space for it, copy it in, then break out of the while loop */ if (ppEvent && seen_indices == *num) { /* grab this entry */ event = calloc(1, sizeof(TSS_PCR_EVENT)); event->ulPcrIndex = pcr_value; event->rgbPcrValue = NULL; event->rgbEvent = NULL; event->ulPcrValueLength = 20; event->rgbPcrValue = malloc(event->ulPcrValueLength); if (event->rgbPcrValue == NULL) { LogError("malloc of %d bytes failed.", 20); free(event); event = NULL; result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } /* copy the template SHA1 XXX endianess ignored */ memcpy(event->rgbPcrValue, &page[ptr], event->ulPcrValueLength); /* Get the template name size, template name */ { char digest[20]; if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } if (len > EVLOG_FILENAME_MAXSIZE) { LogError("Event log file name too big! Max size is %d", EVLOG_FILENAME_MAXSIZE); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } memset(name, 0, EVLOG_FILENAME_MAXSIZE); if (fread(name, 1, len, fp) != len) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } if (fread(digest, 1, sizeof(digest), fp) != sizeof(digest)) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } } /* Get the template data namelen and data */ if (fread(&event->ulEventLength, 1, sizeof(int), fp) != sizeof(int)) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } event->rgbEvent = malloc(event->ulEventLength + 1); if (event->rgbEvent == NULL) { LogError("malloc of %u bytes failed.", event->ulEventLength); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } memset(event->rgbEvent, 0, event->ulEventLength + 1); if (fread(event->rgbEvent, 1, event->ulEventLength, fp) != event->ulEventLength ) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } *ppEvent = event; result = TSS_SUCCESS; break; } } if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } fseek(fp, len + 20, SEEK_CUR); if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) { LogError("Failed to read event log file"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } fseek(fp, len, SEEK_CUR); seen_indices++; } done: if (result != TSS_SUCCESS) { if (event != NULL) { free(event->rgbPcrValue); free(event->rgbEvent); } free(event); event = NULL; } if (ppEvent == NULL) *num = seen_indices; return result; } int ima_close(FILE *handle) { fclose((FILE *)handle); return 0; } #endif trousers-0.3.15/src/tcs/tcsi_audit.c0000664000175000017510000000770513663651711016641 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_utils.h" #include "tcslog.h" #include "req_mgr.h" TSS_RESULT TCSP_SetOrdinalAuditStatus_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH *ownerAuth, /* in/out */ UINT32 ulOrdinal, /* in */ TSS_BOOL bAuditState) /* in */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_SetOrdinalAuditStatus, &offset, txBlob, ulOrdinal, bAuditState, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; offset = 10; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_SetOrdinalAuditStatus, txBlob, paramSize, ownerAuth); } LogResult("SetOrdinalAuditStatus", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_GetAuditDigest_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 startOrdinal, /* in */ TPM_DIGEST *auditDigest, /* out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TSS_BOOL *more, /* out */ UINT32 *ordSize, /* out */ UINT32 **ordList) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_GetAuditDigest, &offset, txBlob, startOrdinal, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { if ((result = tpm_rsp_parse(TPM_ORD_GetAuditDigest, txBlob, paramSize, auditDigest, counterValueSize, counterValue, more, ordSize, ordList))) goto done; /* ordSize is returned from the TPM as the number of bytes in ordList so ordSize needs to be converted to comply with the TSS spec which returns the number of ordinals contained in ordList */ *ordSize = *ordSize / sizeof(UINT32); } LogResult("GetAuditDigest", result); done: return result; } TSS_RESULT TCSP_GetAuditDigestSigned_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TSS_BOOL closeAudit, /* in */ TPM_NONCE antiReplay, /* in */ TPM_AUTH *privAuth, /* in/out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TPM_DIGEST *auditDigest, /* out */ TPM_DIGEST *ordinalDigest, /* out */ UINT32 *sigSize, /* out */ BYTE **sig) /* out */ { TSS_RESULT result; TCPA_KEY_HANDLE keySlot; UINT64 offset = 0;//, old_offset; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (privAuth != NULL) if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) return result; if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_GetAuditDigestSigned, &offset, txBlob, keySlot, closeAudit, antiReplay.nonce, privAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_GetAuditDigestSigned, txBlob, paramSize, counterValueSize, counterValue, auditDigest, ordinalDigest, sigSize, sig, privAuth); } LogResult("GetAuditDigestSigned", result); done: auth_mgr_release_auth(privAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/Makefile.am0000664000175000017510000001021613663651711016370 0ustar deboradeboranoinst_LIBRARIES=libtcs.a CFLAGS+=-I${top_srcdir}/src/include libtcs_a_LIBADD=${top_builddir}/src/tddl/libtddl.a libtcs_a_CFLAGS=-DAPPID=\"TCSD\ TCS\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -fPIE -DPIE libtcs_a_SOURCES=log.c \ tcs_caps.c \ tcs_req_mgr.c \ tcs_context.c \ tcsi_context.c \ tcs_utils.c \ rpc/@RPC@/rpc.c rpc/@RPC@/rpc_context.c \ tcsi_caps_tpm.c rpc/@RPC@/rpc_caps_tpm.c \ tcs_auth_mgr.c tcsi_auth.c rpc/@RPC@/rpc_auth.c \ tcs_pbg.c if TSS_BUILD_TRANSPORT libtcs_a_SOURCES+=tcsi_transport.c rpc/@RPC@/rpc_transport.c libtcs_a_CFLAGS+=-DTSS_BUILD_TRANSPORT endif if TSS_BUILD_TICK libtcs_a_SOURCES+=tcsi_tick.c rpc/@RPC@/rpc_tick.c libtcs_a_CFLAGS+=-DTSS_BUILD_TICK endif if TSS_BUILD_COUNTER libtcs_a_SOURCES+=tcsi_counter.c tcs_counter.c rpc/@RPC@/rpc_counter.c libtcs_a_CFLAGS+=-DTSS_BUILD_COUNTER endif if TSS_BUILD_RANDOM libtcs_a_SOURCES+=tcsi_random.c rpc/@RPC@/rpc_random.c libtcs_a_CFLAGS+=-DTSS_BUILD_RANDOM endif if TSS_BUILD_CAPS libtcs_a_SOURCES+=tcsi_caps.c rpc/@RPC@/rpc_caps.c libtcs_a_CFLAGS+=-DTSS_BUILD_CAPS endif if TSS_BUILD_DIR libtcs_a_SOURCES+=tcsi_dir.c rpc/@RPC@/rpc_dir.c libtcs_a_CFLAGS+=-DTSS_BUILD_DIR endif if TSS_BUILD_PCR_EVENTS libtcs_a_SOURCES+=tcsi_evlog.c tcs_evlog_biosem.c tcs_evlog_imaem.c tcs_evlog.c \ rpc/@RPC@/rpc_evlog.c libtcs_a_CFLAGS+=-DTSS_BUILD_PCR_EVENTS endif if TSS_BUILD_SIGN libtcs_a_SOURCES+=tcsi_sign.c rpc/@RPC@/rpc_sign.c libtcs_a_CFLAGS+=-DTSS_BUILD_SIGN endif if TSS_BUILD_QUOTE libtcs_a_SOURCES+=tcsi_quote.c tcs_quote.c rpc/@RPC@/rpc_quote.c libtcs_a_CFLAGS+=-DTSS_BUILD_QUOTE endif if TSS_BUILD_SEAL libtcs_a_SOURCES+=tcsi_seal.c tcs_seal.c rpc/@RPC@/rpc_seal.c libtcs_a_CFLAGS+=-DTSS_BUILD_SEAL endif if TSS_BUILD_CHANGEAUTH libtcs_a_SOURCES+=tcsi_changeauth.c rpc/@RPC@/rpc_changeauth.c libtcs_a_CFLAGS+=-DTSS_BUILD_CHANGEAUTH endif if TSS_BUILD_BIND libtcs_a_SOURCES+=tcsi_bind.c rpc/@RPC@/rpc_bind.c libtcs_a_CFLAGS+=-DTSS_BUILD_BIND endif if TSS_BUILD_OWN libtcs_a_SOURCES+=tcsi_own.c rpc/@RPC@/rpc_own.c libtcs_a_CFLAGS+=-DTSS_BUILD_OWN endif if TSS_BUILD_PS libtcs_a_SOURCES+=ps/ps_utils.c ps/tcsps.c tcsi_ps.c tcs_ps.c tcs_key_ps.c rpc/@RPC@/rpc_ps.c libtcs_a_CFLAGS+=-DTSS_BUILD_PS endif if TSS_BUILD_ADMIN libtcs_a_SOURCES+=tcsi_admin.c rpc/@RPC@/rpc_admin.c libtcs_a_CFLAGS+=-DTSS_BUILD_ADMIN endif if TSS_BUILD_AIK libtcs_a_SOURCES+=tcsi_aik.c tcs_aik.c rpc/@RPC@/rpc_aik.c libtcs_a_CFLAGS+=-DTSS_BUILD_AIK endif if TSS_BUILD_EK libtcs_a_SOURCES+=tcsi_ek.c rpc/@RPC@/rpc_ek.c libtcs_a_CFLAGS+=-DTSS_BUILD_EK endif if TSS_BUILD_CERTIFY libtcs_a_SOURCES+=tcsi_certify.c rpc/@RPC@/rpc_certify.c libtcs_a_CFLAGS+=-DTSS_BUILD_CERTIFY endif if TSS_BUILD_KEY libtcs_a_SOURCES+=tcsi_key.c tcs_key.c tcs_key_mem_cache.c tcs_context_key.c rpc/@RPC@/rpc_key.c \ crypto/@CRYPTO_PACKAGE@/crypto.c libtcs_a_CFLAGS+=-DTSS_BUILD_KEY endif if TSS_BUILD_MAINT libtcs_a_SOURCES+=tcsi_maint.c rpc/@RPC@/rpc_maint.c libtcs_a_CFLAGS+=-DTSS_BUILD_MAINT endif if TSS_BUILD_MIGRATION libtcs_a_SOURCES+=tcsi_migration.c tcs_migration.c rpc/@RPC@/rpc_migration.c libtcs_a_CFLAGS+=-DTSS_BUILD_MIGRATION endif if TSS_BUILD_PCR_EXTEND libtcs_a_SOURCES+=tcsi_pcr.c rpc/@RPC@/rpc_pcr_extend.c libtcs_a_CFLAGS+=-DTSS_BUILD_PCR_EXTEND endif if TSS_BUILD_SELFTEST libtcs_a_SOURCES+=tcsi_selftest.c rpc/@RPC@/rpc_selftest.c libtcs_a_CFLAGS+=-DTSS_BUILD_SELFTEST endif if TSS_BUILD_DAA libtcs_a_SOURCES+=tcsi_daa.c rpc/@RPC@/rpc_daa.c libtcs_a_CFLAGS+=-DTSS_BUILD_DAA endif if TSS_BUILD_NV libtcs_a_SOURCES+=tcsi_nv.c rpc/@RPC@/rpc_nv.c libtcs_a_CFLAGS+=-DTSS_BUILD_NV endif if TSS_BUILD_AUDIT libtcs_a_SOURCES+=tcsi_audit.c rpc/@RPC@/rpc_audit.c libtcs_a_CFLAGS+=-DTSS_BUILD_AUDIT endif if TSS_BUILD_SEALX libtcs_a_CFLAGS+=-DTSS_BUILD_SEALX endif if TSS_BUILD_TSS12 libtcs_a_SOURCES+=tcsi_oper.c rpc/@RPC@/rpc_oper.c libtcs_a_CFLAGS+=-DTSS_BUILD_TSS12 endif if TSS_BUILD_DELEGATION libtcs_a_SOURCES+=tcsi_delegate.c rpc/@RPC@/rpc_delegate.c libtcs_a_CFLAGS+=-DTSS_BUILD_DELEGATION endif if TSS_BUILD_QUOTE2 libtcs_a_SOURCES+=tcsi_quote2.c tcs_quote2.c rpc/@RPC@/rpc_quote2.c libtcs_a_CFLAGS+=-DTSS_BUILD_QUOTE2 endif if TSS_BUILD_CMK libtcs_a_SOURCES+=tcsi_cmk.c rpc/@RPC@/rpc_cmk.c libtcs_a_CFLAGS+=-DTSS_BUILD_CMK endif trousers-0.3.15/src/tcs/tcsi_certify.c0000664000175000017510000000433613663651711017175 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_CertifyKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE certHandle, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TPM_AUTH * certAuth, /* in, out */ TPM_AUTH * keyAuth, /* in, out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE certKeySlot, keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Certify Key"); if ((result = ctx_verify_context(hContext))) goto done; if (certAuth != NULL) { LogDebug("Auth Used for Cert signing key"); if ((result = auth_mgr_check(hContext, &certAuth->AuthHandle))) goto done; } else { LogDebug("No Auth used for Cert signing key"); } if (keyAuth != NULL) { LogDebug("Auth Used for Key being signed"); if ((result = auth_mgr_check(hContext, &keyAuth->AuthHandle))) goto done; } else { LogDebug("No Auth used for Key being signed"); } if ((result = ensureKeyIsLoaded(hContext, certHandle, &certKeySlot))) goto done; if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_CertifyKey, &offset, txBlob, certKeySlot, keySlot, antiReplay.nonce, certAuth, keyAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CertifyKey, txBlob, paramSize, CertifyInfoSize, CertifyInfo, outDataSize, outData, certAuth, keyAuth); } LogResult("Certify Key", result); done: auth_mgr_release_auth(certAuth, keyAuth, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_ek.c0000664000175000017510000001347013663651711016126 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_CreateEndorsementKeyPair_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize, /* in */ BYTE * endorsementKeyInfo, /* in */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TCPA_DIGEST * checksum) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_CreateEndorsementKeyPair, &offset, txBlob, antiReplay.nonce, endorsementKeyInfoSize, endorsementKeyInfo))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CreateEndorsementKeyPair, txBlob, paramSize, endorsementKeySize, endorsementKey, checksum->digest); } LogDebug("Leaving CreateEKPair with result: 0x%x", result); return result; } TSS_RESULT TCSP_ReadPubek_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey, /* out */ TCPA_DIGEST * checksum) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_ReadPubek, &offset, txBlob, TPM_NONCE_SIZE, antiReplay.nonce))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_ReadPubek, txBlob, paramSize, pubEndorsementKeySize, pubEndorsementKey, checksum->digest); } LogDebugFn("result: 0x%x", result); return result; } TSS_RESULT TCSP_DisablePubekRead_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("DisablePubekRead"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_DisablePubekRead, &offset, txBlob, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_DisablePubekRead, txBlob, paramSize, ownerAuth); } done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_OwnerReadPubek_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey) /* out */ { UINT32 paramSize; TSS_RESULT result; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering OwnerReadPubek"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_OwnerReadPubek, &offset, txBlob, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_OwnerReadPubek, txBlob, paramSize, pubEndorsementKeySize, pubEndorsementKey, ownerAuth); } LogResult("Owner Read Pubek", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_CreateRevocableEndorsementKeyPair_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize, /* in */ BYTE * endorsementKeyInfo, /* in */ TSS_BOOL genResetAuth, /* in */ TPM_DIGEST * eKResetAuth, /* in, out */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TPM_DIGEST * checksum) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_CreateRevocableEK, &offset, txBlob, antiReplay.nonce, endorsementKeyInfoSize, endorsementKeyInfo, genResetAuth, eKResetAuth->digest))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CreateRevocableEK, txBlob, paramSize, endorsementKeySize, endorsementKey, checksum->digest, eKResetAuth->digest); } LogDebug("Leaving CreateRevocableEKPair with result: 0x%x", result); return result; } TSS_RESULT TCSP_RevokeEndorsementKeyPair_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_DIGEST EKResetAuth) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_RevokeTrust, &offset, txBlob, EKResetAuth.digest))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("Leaving RevokeEKPair with result: 0x%x", result); return result; } trousers-0.3.15/src/tcs/tcsi_key.c0000664000175000017510000002440213663651711016314 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" TSS_RESULT TCSP_LoadKeyByBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hUnwrappingKey, /* in */ UINT32 cWrappedKeyBlobSize, /* in */ BYTE * rgbWrappedKeyBlob, /* in */ TPM_AUTH * pAuth, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI, /* out */ TCS_KEY_HANDLE * phKeyHMAC) /* out */ { return LoadKeyByBlob_Internal(TPM_ORD_LoadKey, hContext, hUnwrappingKey, cWrappedKeyBlobSize, rgbWrappedKeyBlob, pAuth, phKeyTCSI, phKeyHMAC); } TSS_RESULT TCSP_LoadKey2ByBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hUnwrappingKey, /* in */ UINT32 cWrappedKeyBlobSize, /* in */ BYTE * rgbWrappedKeyBlob, /* in */ TPM_AUTH * pAuth, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI) /* out */ { return LoadKeyByBlob_Internal(TPM_ORD_LoadKey2, hContext, hUnwrappingKey, cWrappedKeyBlobSize, rgbWrappedKeyBlob, pAuth, phKeyTCSI, NULL); } TSS_RESULT LoadKeyByBlob_Internal(UINT32 ord, /* The ordinal to use, LoadKey or LoadKey2 */ TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hUnwrappingKey, /* in */ UINT32 cWrappedKeyBlobSize, /* in */ BYTE * rgbWrappedKeyBlob, /* in */ TPM_AUTH * pAuth, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI, /* out */ TCS_KEY_HANDLE * phKeyHMAC) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 paramSize; TPM_KEY_HANDLE parentSlot, newSlot; TCS_KEY_HANDLE newHandle = NULL_TCS_HANDLE; TSS_BOOL canLoad; TSS_KEY key; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; LogDebugFn("Enter"); LogDebugUnrollKey(rgbWrappedKeyBlob); if ((result = get_slot(hContext, hUnwrappingKey, &parentSlot))) return result; offset = 0; memset(&key, 0, sizeof(TSS_KEY)); if ((result = UnloadBlob_TSS_KEY(&offset, rgbWrappedKeyBlob, &key))) return result; if (!pAuth) { LogDebugFn("Checking if LoadKeyByBlob can be avoided by using existing key"); if ((newHandle = mc_get_handle_by_pub(&key.pubKey, hUnwrappingKey))) { LogDebugFn("tcs key handle exists"); newSlot = mc_get_slot_by_handle(newHandle); if (newSlot && (isKeyLoaded(newSlot) == TRUE)) { LogDebugFn("Don't need to reload this key."); *phKeyTCSI = newHandle; if (phKeyHMAC) *phKeyHMAC = newSlot; return TSS_SUCCESS; } } } LogDebugFn("calling canILoadThisKey"); if ((result = canILoadThisKey(&(key.algorithmParms), &canLoad))) goto error; if (canLoad == FALSE) { LogDebugFn("calling evictFirstKey"); /* Evict a key that isn't the parent */ if ((result = evictFirstKey(hUnwrappingKey))) goto error; } offset = 0; if ((result = tpm_rqu_build(ord, &offset, txBlob, parentSlot, cWrappedKeyBlobSize, rgbWrappedKeyBlob, pAuth, NULL))) goto error; LogDebugFn("Submitting request to the TPM"); if ((result = req_mgr_submit_req(txBlob))) goto error; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto error; } if ((result = tpm_rsp_parse(ord, txBlob, paramSize, &newSlot, pAuth))) goto error; if ((result = load_key_final(hContext, hUnwrappingKey, &newHandle, rgbWrappedKeyBlob, newSlot))) goto error; /* Setup the outHandles */ *phKeyTCSI = newHandle; if (phKeyHMAC) *phKeyHMAC = newSlot; LogDebugFn("Key handles for loadKeyByBlob slot:%.8X tcshandle:%.8X", newSlot, newHandle); error: auth_mgr_release_auth(pAuth, NULL, hContext); return result; } TSS_RESULT TCSP_EvictKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey) /* in */ { TSS_RESULT result; TCPA_KEY_HANDLE tpm_handle; if ((result = ctx_verify_context(hContext))) return result; tpm_handle = mc_get_slot_by_handle(hKey); if (tpm_handle == NULL_TPM_HANDLE) return TSS_SUCCESS; /*let's call this success if the key is already evicted */ if ((result = internal_EvictByKeySlot(tpm_handle))) return result; result = mc_set_slot_by_slot(tpm_handle, NULL_TPM_HANDLE); return result; } TSS_RESULT TCSP_CreateWrapKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hWrappingKey, /* in */ TCPA_ENCAUTH KeyUsageAuth, /* in */ TCPA_ENCAUTH KeyMigrationAuth, /* in */ UINT32 keyInfoSize, /* in */ BYTE * keyInfo, /* in */ UINT32 * keyDataSize, /* out */ BYTE ** keyData, /* out */ TPM_AUTH * pAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE parentSlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Create Wrap Key"); if ((result = ctx_verify_context(hContext))) goto done; if (pAuth) { if ((result = auth_mgr_check(hContext, &pAuth->AuthHandle))) goto done; } /* Since hWrappingKey must already be loaded, we can fail immediately if * mc_get_slot_by_handle_lock() fails.*/ parentSlot = mc_get_slot_by_handle_lock(hWrappingKey); if (parentSlot == NULL_TPM_HANDLE) { result = TCSERR(TSS_E_FAIL); goto done; } if ((result = tpm_rqu_build(TPM_ORD_CreateWrapKey, &offset, txBlob, parentSlot, KeyUsageAuth.authdata, KeyMigrationAuth.authdata, keyInfoSize, keyInfo, pAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CreateWrapKey, txBlob, paramSize, keyDataSize, keyData, pAuth); } LogResult("Create Wrap Key", result); done: auth_mgr_release_auth(pAuth, NULL, hContext); return result; } TSS_RESULT TCSP_GetPubKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * pcPubKeySize, /* out */ BYTE ** prgbPubKey) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Get pub key"); if ((result = ctx_verify_context(hContext))) goto done; if (pAuth != NULL) { LogDebug("Auth Used"); if ((result = auth_mgr_check(hContext, &pAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if (ensureKeyIsLoaded(hContext, hKey, &keySlot)) { result = TCSERR(TCS_E_KM_LOADFAILED); goto done; } LogDebug("GetPubKey: handle: 0x%x, slot: 0x%x", hKey, keySlot); if ((result = tpm_rqu_build(TPM_ORD_GetPubKey, &offset, txBlob, keySlot, pAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; offset = 10; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_GetPubKey, txBlob, paramSize, pcPubKeySize, prgbPubKey, pAuth); } LogResult("Get Public Key", result); done: auth_mgr_release_auth(pAuth, NULL, hContext); return result; } TSS_RESULT TCSP_OwnerReadInternalPub_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * punPubKeySize, /* out */ BYTE ** ppbPubKeyData) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering OwnerReadInternalPub"); if ((result = ctx_verify_context(hContext))) goto done; LogDebug("OwnerReadInternalPub: handle: 0x%x", hKey); if (hKey != TPM_KH_SRK && hKey != TPM_KH_EK) { result = TCSERR(TSS_E_FAIL); LogDebug("OwnerReadInternalPub - Unsupported Key Handle"); goto done; } if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_OwnerReadInternalPub, &offset, txBlob, hKey, pOwnerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_OwnerReadInternalPub, txBlob, paramSize, punPubKeySize, ppbPubKeyData, pOwnerAuth); } LogResult("OwnerReadInternalPub", result); done: auth_mgr_release_auth(pOwnerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_KeyControlOwner_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hTcsKey, /* in */ UINT32 ulPubKeyLength, /* in */ BYTE* rgbPubKey, /* in */ UINT32 attribName, /* in */ TSS_BOOL attribValue, /* in */ TPM_AUTH* pOwnerAuth, /* in,out */ TSS_UUID* pUuidData) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TPM_KEY_HANDLE hTpmKey; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) { LogDebug("Invalid TSS Context"); goto done; } if ((result = get_slot_lite(hContext, hTcsKey, &hTpmKey))) { LogDebug("Can't get TPM Keyhandle for TCS key 0x%x", hTcsKey); goto done; } LogDebugFn("TCS hKey=0x%x, TPM hKey=0x%x", hTcsKey, hTpmKey); if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) { LogDebug("Owner Authentication failed"); goto done; } if ((result = mc_find_next_ownerevict_uuid(pUuidData))) { LogDebugFn("mc_find_next_ownerevict_uuid failed: rc=0x%x", result); goto done; } if ((result = tpm_rqu_build(TPM_ORD_KeyControlOwner, &offset, txBlob, hTpmKey, ulPubKeyLength, rgbPubKey, attribName, attribValue, pOwnerAuth))) { LogDebugFn("rqu build failed"); goto done; } if ((result = req_mgr_submit_req(txBlob))) { LogDebugFn("Request submission failed"); goto done; } if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto done; } if ((result = tpm_rsp_parse(TPM_ORD_KeyControlOwner, txBlob, paramSize, pOwnerAuth))) { LogDebugFn("tpm_rsp_parse failed: rc=0x%x", result); goto done; } if ((result = mc_set_uuid(hTcsKey, pUuidData))){ LogDebugFn("mc_set_uuid failed: rc=0x%x", result); goto done; } LogResult("KeyControlOwner", result); done: auth_mgr_release_auth(pOwnerAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_auth.c0000664000175000017510000000470713663651711016473 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_OIAP_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TCPA_NONCE *nonce0) /* out */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering TCSI_OIAP"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_OIAP, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_OIAP, txBlob, paramSize, authHandle, nonce0->nonce); } LogResult("OIAP", result); return result; } TSS_RESULT TCSP_OSAP_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 entityValue, /* in */ TCPA_NONCE nonceOddOSAP, /* in */ TCS_AUTHHANDLE * authHandle, /* out */ TCPA_NONCE * nonceEven, /* out */ TCPA_NONCE * nonceEvenOSAP) /* out */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering OSAP"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_OSAP, &offset, txBlob, entityType, entityValue, nonceOddOSAP.nonce))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_OSAP, txBlob, paramSize, authHandle, nonceEven->nonce, nonceEvenOSAP->nonce); } LogResult("OSAP", result); return result; } TSS_RESULT internal_TerminateHandle(TCS_AUTHHANDLE handle) { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = tpm_rqu_build(TPM_ORD_Terminate_Handle, &offset, txBlob, handle, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; return UnloadBlob_Header(txBlob, ¶mSize); } trousers-0.3.15/src/tcs/tcs_seal.c0000664000175000017510000000346213663651711016302 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcslog.h" TSS_RESULT UnloadBlob_STORED_DATA(UINT64 *offset, BYTE *blob, TCPA_STORED_DATA *data) { if (!data) { UINT32 size; UnloadBlob_VERSION(offset, blob, NULL); UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); return TSS_SUCCESS; } UnloadBlob_VERSION(offset, blob, (TPM_VERSION *)&data->ver); UnloadBlob_UINT32(offset, &data->sealInfoSize, blob); if (data->sealInfoSize > 0) { data->sealInfo = (BYTE *)calloc(1, data->sealInfoSize); if (data->sealInfo == NULL) { LogError("malloc of %u bytes failed.", data->sealInfoSize); data->sealInfoSize = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, data->sealInfoSize, blob, data->sealInfo); } else { data->sealInfo = NULL; } UnloadBlob_UINT32(offset, &data->encDataSize, blob); if (data->encDataSize > 0) { data->encData = (BYTE *)calloc(1, data->encDataSize); if (data->encData == NULL) { LogError("malloc of %u bytes failed.", data->encDataSize); data->encDataSize = 0; free(data->sealInfo); data->sealInfo = NULL; data->sealInfoSize = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, data->encDataSize, blob, data->encData); } else { data->encData = NULL; } return TSS_SUCCESS; } trousers-0.3.15/src/tcs/tcs_utils.c0000664000175000017510000002736613663651711016527 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" TCS_CONTEXT_HANDLE InternalContext = 0x30000000; TSS_UUID SRK_UUID = TSS_UUID_SRK; void LogData(char *string, UINT32 data) { #if 0 /* commenting out temporarily, logs getting too chatty */ LogDebug("%s %08x", string, data); #endif } void LogResult(char *string, TCPA_RESULT result) { #if 0 /* commenting out temporarily, logs getting too chatty */ LogDebug("Leaving %s with result 0x%08x", string, result); #endif } UINT16 Decode_UINT16(BYTE * in) { UINT16 temp = 0; temp = (in[1] & 0xFF); temp |= (in[0] << 8); return temp; } void UINT64ToArray(UINT64 i, BYTE * out) { out[0] = (BYTE) ((i >> 56) & 0xFF); out[1] = (BYTE) ((i >> 48) & 0xFF); out[2] = (BYTE) ((i >> 40) & 0xFF); out[3] = (BYTE) ((i >> 32) & 0xFF); out[4] = (BYTE) ((i >> 24) & 0xFF); out[5] = (BYTE) ((i >> 16) & 0xFF); out[6] = (BYTE) ((i >> 8) & 0xFF); out[7] = (BYTE) (i & 0xFF); } void UINT32ToArray(UINT32 i, BYTE * out) { out[0] = (BYTE) ((i >> 24) & 0xFF); out[1] = (BYTE) ((i >> 16) & 0xFF); out[2] = (BYTE) ((i >> 8) & 0xFF); out[3] = (BYTE) (i & 0xFF); } void UINT16ToArray(UINT16 i, BYTE * out) { out[0] = (BYTE) ((i >> 8) & 0xFF); out[1] = (BYTE) (i & 0xFF); } UINT32 Decode_UINT32(BYTE * y) { UINT32 x = 0; x = y[0]; x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[3] & 0xFF)); return x; } UINT64 Decode_UINT64(BYTE *y) { UINT64 x = 0; x = y[0]; x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[3] & 0xFF)); x = ((x << 8) | (y[4] & 0xFF)); x = ((x << 8) | (y[5] & 0xFF)); x = ((x << 8) | (y[6] & 0xFF)); x = ((x << 8) | (y[7] & 0xFF)); return x; } void LoadBlob_UINT64(UINT64 *offset, UINT64 in, BYTE * blob) { if (blob) UINT64ToArray(in, &blob[*offset]); *offset += sizeof(UINT64); } void LoadBlob_UINT32(UINT64 *offset, UINT32 in, BYTE * blob) { if (blob) UINT32ToArray(in, &blob[*offset]); *offset += sizeof(UINT32); } void LoadBlob_UINT16(UINT64 *offset, UINT16 in, BYTE * blob) { if (blob) UINT16ToArray(in, &blob[*offset]); *offset += sizeof(UINT16); } void UnloadBlob_UINT64(UINT64 *offset, UINT64 * out, BYTE * blob) { if (out) *out = Decode_UINT64(&blob[*offset]); *offset += sizeof(UINT64); } void UnloadBlob_UINT32(UINT64 *offset, UINT32 * out, BYTE * blob) { if (out) *out = Decode_UINT32(&blob[*offset]); *offset += sizeof(UINT32); } void UnloadBlob_UINT16(UINT64 *offset, UINT16 * out, BYTE * blob) { if (out) *out = Decode_UINT16(&blob[*offset]); *offset += sizeof(UINT16); } void LoadBlob_BYTE(UINT64 *offset, BYTE data, BYTE * blob) { if (blob) blob[*offset] = data; (*offset)++; } void UnloadBlob_BYTE(UINT64 *offset, BYTE * dataOut, BYTE * blob) { if (dataOut) *dataOut = blob[*offset]; (*offset)++; } void LoadBlob_BOOL(UINT64 *offset, TSS_BOOL data, BYTE * blob) { if (blob) blob[*offset] = data; (*offset)++; } void UnloadBlob_BOOL(UINT64 *offset, TSS_BOOL *dataOut, BYTE * blob) { if (dataOut) *dataOut = blob[*offset]; (*offset)++; } void LoadBlob(UINT64 *offset, UINT32 size, BYTE *container, BYTE *object) { if (container) memcpy(&container[*offset], object, size); (*offset) += (UINT64) size; } void UnloadBlob(UINT64 *offset, UINT32 size, BYTE *container, BYTE *object) { if (object) memcpy(object, &container[*offset], size); (*offset) += (UINT64) size; } void LoadBlob_Header(UINT16 tag, UINT32 paramSize, UINT32 ordinal, BYTE * blob) { UINT16ToArray(tag, &blob[0]); LogData("Header Tag:", tag); UINT32ToArray(paramSize, &blob[2]); LogData("Header ParamSize:", paramSize); UINT32ToArray(ordinal, &blob[6]); LogData("Header Ordinal:", ordinal); #if 0 LogInfo("Blob's TPM Ordinal: 0x%x", ordinal); #endif } #ifdef TSS_DEBUG TSS_RESULT LogUnloadBlob_Header(BYTE * blob, UINT32 * size, char *file, int line) { TSS_RESULT result; UINT16 temp = Decode_UINT16(blob); LogData("UnloadBlob_Tag:", (temp)); *size = Decode_UINT32(&blob[2]); LogData("UnloadBlob_Header, size:", *size); LogData("UnloadBlob_Header, returnCode:", Decode_UINT32(&blob[6])); if ((result = Decode_UINT32(&blob[6]))) { LogTPMERR(result, file, line); } return result; } #else TSS_RESULT UnloadBlob_Header(BYTE * blob, UINT32 * size) { UINT16 temp = Decode_UINT16(blob); LogData("UnloadBlob_Tag:", (temp)); *size = Decode_UINT32(&blob[2]); LogData("UnloadBlob_Header, size:", *size); LogData("UnloadBlob_Header, returnCode:", Decode_UINT32(&blob[6])); return Decode_UINT32(&blob[6]); } #endif void LoadBlob_Auth(UINT64 *offset, BYTE * blob, TPM_AUTH * auth) { LoadBlob_UINT32(offset, auth->AuthHandle, blob); LoadBlob(offset, TCPA_NONCE_SIZE, blob, auth->NonceOdd.nonce); LoadBlob_BOOL(offset, auth->fContinueAuthSession, blob); LoadBlob(offset, TCPA_AUTHDATA_SIZE, blob, (BYTE *)&auth->HMAC); } void UnloadBlob_Auth(UINT64 *offset, BYTE * blob, TPM_AUTH * auth) { if (!auth) { UnloadBlob(offset, TCPA_NONCE_SIZE, blob, NULL); UnloadBlob_BOOL(offset, NULL, blob); UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, NULL); return; } UnloadBlob(offset, TCPA_NONCE_SIZE, blob, auth->NonceEven.nonce); UnloadBlob_BOOL(offset, &auth->fContinueAuthSession, blob); UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, (BYTE *)&auth->HMAC); } void UnloadBlob_VERSION(UINT64 *offset, BYTE *blob, TPM_VERSION *out) { if (!out) { *offset += (sizeof(BYTE) * 4); return; } UnloadBlob_BYTE(offset, &out->major, blob); UnloadBlob_BYTE(offset, &out->minor, blob); UnloadBlob_BYTE(offset, &out->revMajor, blob); UnloadBlob_BYTE(offset, &out->revMinor, blob); } void LoadBlob_VERSION(UINT64 *offset, BYTE *blob, TPM_VERSION *ver) { LoadBlob_BYTE(offset, ver->major, blob); LoadBlob_BYTE(offset, ver->minor, blob); LoadBlob_BYTE(offset, ver->revMajor, blob); LoadBlob_BYTE(offset, ver->revMinor, blob); } void UnloadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION *out) { if (!out) { *offset += (sizeof(BYTE) * 4); return; } UnloadBlob_BYTE(offset, &out->major, blob); UnloadBlob_BYTE(offset, &out->minor, blob); UnloadBlob_BYTE(offset, &out->revMajor, blob); UnloadBlob_BYTE(offset, &out->revMinor, blob); } void LoadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION *ver) { LoadBlob_BYTE(offset, ver->major, blob); LoadBlob_BYTE(offset, ver->minor, blob); LoadBlob_BYTE(offset, ver->revMajor, blob); LoadBlob_BYTE(offset, ver->revMinor, blob); } TSS_RESULT UnloadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyParms) { if (!keyParms) { UINT32 parmSize; UnloadBlob_UINT32(offset, NULL, blob); UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob_UINT32(offset, &parmSize, blob); if (parmSize > 0) UnloadBlob(offset, parmSize, blob, NULL); return TSS_SUCCESS; } UnloadBlob_UINT32(offset, &keyParms->algorithmID, blob); UnloadBlob_UINT16(offset, &keyParms->encScheme, blob); UnloadBlob_UINT16(offset, &keyParms->sigScheme, blob); UnloadBlob_UINT32(offset, &keyParms->parmSize, blob); if (keyParms->parmSize == 0) keyParms->parms = NULL; else { keyParms->parms = malloc(keyParms->parmSize); if (keyParms->parms == NULL) { LogError("malloc of %u bytes failed.", keyParms->parmSize); keyParms->parmSize = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, keyParms->parmSize, blob, keyParms->parms); } return TSS_SUCCESS; } void UnloadBlob_KEY_FLAGS(UINT64 *offset, BYTE *blob, TCPA_KEY_FLAGS *flags) { if (!flags) { UnloadBlob_UINT32(offset, NULL, blob); return; } UnloadBlob_UINT32(offset, flags, blob); } TSS_RESULT UnloadBlob_CERTIFY_INFO(UINT64 *offset, BYTE *blob, TCPA_CERTIFY_INFO *certify) { TSS_RESULT rc; if (!certify) { TPM_VERSION version; UINT32 size; UnloadBlob_VERSION(offset, blob, &version); UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob_KEY_FLAGS(offset, blob, NULL); UnloadBlob_BOOL(offset, NULL, blob); if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL))) return rc; UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, NULL); UnloadBlob(offset, TCPA_NONCE_SIZE, blob, NULL); UnloadBlob_BOOL(offset, NULL, blob); UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); if (Decode_UINT16((BYTE *) &version) == TPM_TAG_CERTIFY_INFO2){ /* This is a TPM_CERTIFY_INFO2 structure. */ /* Read migrationAuthority. */ UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); } return TSS_SUCCESS; } UnloadBlob_VERSION(offset, blob, (TPM_VERSION *)&certify->version); UnloadBlob_UINT16(offset, &certify->keyUsage, blob); UnloadBlob_KEY_FLAGS(offset, blob, &certify->keyFlags); UnloadBlob_BOOL(offset, (TSS_BOOL *)&certify->authDataUsage, blob); if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &certify->algorithmParms))) return rc; UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, certify->pubkeyDigest.digest); UnloadBlob(offset, TCPA_NONCE_SIZE, blob, certify->data.nonce); UnloadBlob_BOOL(offset, (TSS_BOOL *)&certify->parentPCRStatus, blob); UnloadBlob_UINT32(offset, &certify->PCRInfoSize, blob); if (certify->PCRInfoSize > 0) { certify->PCRInfo = (BYTE *)malloc(certify->PCRInfoSize); if (certify->PCRInfo == NULL) { LogError("malloc of %u bytes failed.", certify->PCRInfoSize); certify->PCRInfoSize = 0; free(certify->algorithmParms.parms); certify->algorithmParms.parms = NULL; certify->algorithmParms.parmSize = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, certify->PCRInfoSize, blob, certify->PCRInfo); } else { certify->PCRInfo = NULL; } if (Decode_UINT16((BYTE *) &certify->version) == TPM_TAG_CERTIFY_INFO2){ /* This is a TPM_CERTIFY_INFO2 structure. */ /* Read migrationAuthority. */ UINT32 size; UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); } return TSS_SUCCESS; } TSS_RESULT UnloadBlob_KEY_HANDLE_LIST(UINT64 *offset, BYTE *blob, TCPA_KEY_HANDLE_LIST *list) { UINT16 i; if (!list) { UINT16 size; UnloadBlob_UINT16(offset, &size, blob); *offset += (size * sizeof(UINT32)); return TSS_SUCCESS; } UnloadBlob_UINT16(offset, &list->loaded, blob); if (list->loaded == 0) { list->handle = NULL; return TSS_SUCCESS; } list->handle = malloc(list->loaded * sizeof (UINT32)); if (list->handle == NULL) { LogError("malloc of %zd bytes failed.", list->loaded * sizeof (UINT32)); list->loaded = 0; return TCSERR(TSS_E_OUTOFMEMORY); } for (i = 0; i < list->loaded; i++) UnloadBlob_UINT32(offset, &list->handle[i], blob); return TSS_SUCCESS; } void LoadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest) { LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, digest->digest); } void UnloadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest) { UnloadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, digest->digest); } void LoadBlob_NONCE(UINT64 *offset, BYTE *blob, TPM_NONCE *nonce) { LoadBlob(offset, TCPA_NONCE_SIZE, blob, nonce->nonce); } void UnloadBlob_NONCE(UINT64 *offset, BYTE *blob, TPM_NONCE *nonce) { UnloadBlob(offset, TCPA_NONCE_SIZE, blob, nonce->nonce); } void LoadBlob_AUTHDATA(UINT64 *offset, BYTE *blob, TPM_AUTHDATA *authdata) { LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, authdata->authdata); } void UnloadBlob_AUTHDATA(UINT64 *offset, BYTE *blob, TPM_AUTHDATA *authdata) { UnloadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, authdata->authdata); } trousers-0.3.15/src/tcs/tcsi_caps.c0000664000175000017510000001671113663651711016456 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" extern struct tcsd_config tcsd_options; TSS_RESULT internal_TCSGetCap(TCS_CONTEXT_HANDLE hContext, TCPA_CAPABILITY_AREA capArea, UINT32 subCap, UINT32 * respSize, BYTE ** resp) { UINT32 u32value = 0; UINT64 offset; TPM_VERSION tcsVersion = INTERNAL_CAP_VERSION; struct tcsd_config *config = &tcsd_options; struct platform_class *platClass; TSS_BOOL bValue = FALSE; LogDebug("Checking Software Cap of TCS"); switch (capArea) { case TSS_TCSCAP_ALG: LogDebug("TSS_TCSCAP_ALG"); switch (subCap) { case TSS_ALG_RSA: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TCS_ALG_RSA; break; case TSS_ALG_DES: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TCS_ALG_DES; break; case TSS_ALG_3DES: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TCS_ALG_3DES; break; case TSS_ALG_SHA: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TCS_ALG_SHA; break; case TSS_ALG_AES: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TCS_ALG_AES; break; case TSS_ALG_HMAC: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TCS_ALG_HMAC; break; case TSS_ALG_DEFAULT: *respSize = sizeof(UINT32); u32value = INTERNAL_CAP_TCS_ALG_DEFAULT; break; case TSS_ALG_DEFAULT_SIZE: *respSize = sizeof(UINT32); u32value = INTERNAL_CAP_TCS_ALG_DEFAULT_SIZE; break; default: *respSize = 0; LogDebugFn("Bad subcap"); return TCSERR(TSS_E_BAD_PARAMETER); } if ((*resp = malloc(*respSize)) == NULL) { LogError("malloc of %u bytes failed.", *respSize); *respSize = 0; return TCSERR(TSS_E_OUTOFMEMORY); } offset = 0; if (*respSize == sizeof(TSS_BOOL)) *(TSS_BOOL *)(*resp) = bValue; else *(UINT32 *)(*resp) = u32value; break; case TSS_TCSCAP_VERSION: LogDebug("TSS_TCSCAP_VERSION"); if ((*resp = calloc(1, sizeof(TSS_VERSION))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_VERSION)); return TCSERR(TSS_E_OUTOFMEMORY); } offset = 0; LoadBlob_VERSION(&offset, *resp, &tcsVersion); *respSize = sizeof(TSS_VERSION); break; case TSS_TCSCAP_PERSSTORAGE: LogDebug("TSS_TCSCAP_PERSSTORAGE"); if ((*resp = malloc(sizeof(TSS_BOOL))) == NULL) { LogError("malloc of %zd byte failed.", sizeof(TSS_BOOL)); return TCSERR(TSS_E_OUTOFMEMORY); } *(TSS_BOOL *)(*resp) = INTERNAL_CAP_TCS_PERSSTORAGE; *respSize = sizeof(TSS_BOOL); break; case TSS_TCSCAP_CACHING: LogDebug("TSS_TCSCAP_CACHING"); if (subCap == TSS_TCSCAP_PROP_KEYCACHE) bValue = INTERNAL_CAP_TCS_CACHING_KEYCACHE; else if (subCap == TSS_TCSCAP_PROP_AUTHCACHE) bValue = INTERNAL_CAP_TCS_CACHING_AUTHCACHE; else { LogDebugFn("Bad subcap"); return TCSERR(TSS_E_BAD_PARAMETER); } if ((*resp = malloc(sizeof(TSS_BOOL))) == NULL) { LogError("malloc of %zd byte failed.", sizeof(TSS_BOOL)); return TCSERR(TSS_E_OUTOFMEMORY); } *respSize = sizeof(TSS_BOOL); *(TSS_BOOL *)(*resp) = bValue; break; case TSS_TCSCAP_MANUFACTURER: if (subCap == TSS_TCSCAP_PROP_MANUFACTURER_ID) { if ((*resp = malloc(sizeof(UINT32))) == NULL) { LogError("malloc of %zd byte failed.", sizeof(UINT32)); return TCSERR(TSS_E_OUTOFMEMORY); } *(UINT32 *)(*resp) = INTERNAL_CAP_MANUFACTURER_ID; *respSize = sizeof(UINT32); } else if (subCap == TSS_TCSCAP_PROP_MANUFACTURER_STR) { BYTE str[] = INTERNAL_CAP_MANUFACTURER_STR; if ((*resp = malloc(INTERNAL_CAP_MANUFACTURER_STR_LEN)) == NULL) { LogError("malloc of %d bytes failed.", INTERNAL_CAP_MANUFACTURER_STR_LEN); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(*resp, str, INTERNAL_CAP_MANUFACTURER_STR_LEN); *respSize = INTERNAL_CAP_MANUFACTURER_STR_LEN; } else { LogDebugFn("Bad subcap"); return TCSERR(TSS_E_BAD_PARAMETER); } break; case TSS_TCSCAP_TRANSPORT: /* A zero value here means the TSP is asking whether we support transport sessions * at all */ if (subCap == TSS_TCSCAP_TRANS_EXCLUSIVE || subCap == 0) { *respSize = sizeof(TSS_BOOL); if ((*resp = malloc(sizeof(TSS_BOOL))) == NULL) { LogError("malloc of %zd byte failed.", sizeof(TSS_BOOL)); return TCSERR(TSS_E_OUTOFMEMORY); } if (subCap == TSS_TCSCAP_TRANS_EXCLUSIVE) *(TSS_BOOL *)(*resp) = config->exclusive_transport ? TRUE : FALSE; else *(TSS_BOOL *)(*resp) = TRUE; } else { LogDebugFn("Bad subcap"); return TCSERR(TSS_E_BAD_PARAMETER); } break; case TSS_TCSCAP_PLATFORM_CLASS: LogDebug("TSS_TCSCAP_PLATFORM_CLASS"); switch (subCap) { case TSS_TCSCAP_PROP_HOST_PLATFORM: /* Return the TSS_PLATFORM_CLASS */ LogDebugFn("TSS_TCSCAP_PROP_HOST_PLATFORM"); platClass = config->host_platform_class; /* Computes the size of host platform structure */ *respSize = (2 * sizeof(UINT32)) + platClass->classURISize; *resp = malloc(*respSize); if (*resp == NULL) { LogError("malloc of %u bytes failed.", *respSize); return TCSERR(TSS_E_OUTOFMEMORY); } memset(*resp, 0, *respSize); offset = 0; LoadBlob_UINT32(&offset, platClass->simpleID, *resp); LoadBlob_UINT32(&offset, platClass->classURISize, *resp); memcpy(&(*resp)[offset], platClass->classURI, platClass->classURISize); LogBlob(*respSize, *resp); break; case TSS_TCSCAP_PROP_ALL_PLATFORMS: /* Return an array of TSS_PLATFORM_CLASSes, when existent */ LogDebugFn("TSS_TCSCAP_PROP_ALL_PLATFORMS"); *respSize = 0; *resp = NULL; if ((platClass = config->all_platform_classes) != NULL) { /* Computes the size of all Platform Structures */ while (platClass != NULL) { *respSize += (2 * sizeof(UINT32)) + platClass->classURISize; platClass = platClass->next; } *resp = malloc(*respSize); if (*resp == NULL) { LogError("malloc of %u bytes failed.", *respSize); return TCSERR(TSS_E_OUTOFMEMORY); } memset(*resp, 0, *respSize); offset = 0; /* Concatenates all the structures on the BYTE * resp */ platClass = config->all_platform_classes; while (platClass != NULL){ LoadBlob_UINT32(&offset, platClass->simpleID, *resp); LoadBlob_UINT32(&offset, platClass->classURISize, *resp); memcpy(&(*resp)[offset], platClass->classURI, platClass->classURISize); offset += platClass->classURISize; platClass = platClass->next; } LogBlob(*respSize, *resp); } break; default: LogDebugFn("Bad subcap"); return TCSERR(TSS_E_BAD_PARAMETER); } break; default: LogDebugFn("Bad cap area"); return TCSERR(TSS_E_BAD_PARAMETER); } return TSS_SUCCESS; } TSS_RESULT TCS_GetCapability_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp /* out */ ) { TSS_RESULT result; UINT32 ulSubCap; if ((result = ctx_verify_context(hContext))) return result; if (subCapSize == sizeof(UINT32)) ulSubCap = *(UINT32 *)subCap; else if (subCapSize == 0) ulSubCap = 0; else return TCSERR(TSS_E_BAD_PARAMETER); return internal_TCSGetCap(hContext, capArea, ulSubCap, respSize, resp); } trousers-0.3.15/src/tcs/tcs_aik.c0000664000175000017510000000576513663651711016132 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "tcsps.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_aik.h" void LoadBlob_SYMMETRIC_KEY(UINT64 *offset, BYTE *blob, TCPA_SYMMETRIC_KEY *key) { LoadBlob_UINT32(offset, key->algId, blob); LoadBlob_UINT16(offset, key->encScheme, blob); LoadBlob_UINT16(offset, key->size, blob); if (key->size > 0) { LoadBlob(offset, key->size, blob, key->data); } else { key->data = NULL; } } TSS_RESULT UnloadBlob_SYMMETRIC_KEY(UINT64 *offset, BYTE *blob, TCPA_SYMMETRIC_KEY *key) { if (!key) { UINT16 size; UnloadBlob_UINT32(offset, NULL, blob); UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob_UINT16(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); return TSS_SUCCESS; } UnloadBlob_UINT32(offset, &key->algId, blob); UnloadBlob_UINT16(offset, &key->encScheme, blob); UnloadBlob_UINT16(offset, &key->size, blob); if (key->size > 0) { key->data = (BYTE *)malloc(key->size); if (key->data == NULL) { LogError("malloc of %hu bytes failed.", key->size); key->size = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, key->size, blob, key->data); } else { key->data = NULL; } return TSS_SUCCESS; } void get_credential(UINT32 type, UINT32 *size, BYTE **cred) { int rc, fd; char *path = NULL; void *file = NULL; struct stat stat_buf; size_t file_size; switch (type) { case TSS_TCS_CREDENTIAL_PLATFORMCERT: path = tcsd_options.platform_cred; break; case TSS_TCS_CREDENTIAL_TPM_CC: path = tcsd_options.conformance_cred; break; case TSS_TCS_CREDENTIAL_EKCERT: path = tcsd_options.endorsement_cred; break; default: LogDebugFn("Bad credential type"); break; } if (path == NULL) goto done; if ((fd = open(path, O_RDONLY)) < 0) { LogError("open(%s): %s", path, strerror(errno)); goto done; } if ((rc = fstat(fd, &stat_buf)) == -1) { LogError("Error stating credential: %s: %s", path, strerror(errno)); close(fd); goto done; } file_size = (size_t)stat_buf.st_size; LogDebugFn("%s, (%zd bytes)", path, file_size); file = mmap(0, file_size, PROT_READ, MAP_PRIVATE, fd, 0); if (file == MAP_FAILED) { LogError("Error reading credential: %s: %s", path, strerror(errno)); close(fd); goto done; } close(fd); if ((*cred = malloc(file_size)) == NULL) { LogError("malloc of %zd bytes failed.", file_size); munmap(file, file_size); goto done; } memcpy(*cred, file, file_size); *size = file_size; munmap(file, file_size); return; done: *cred = NULL; *size = 0; } trousers-0.3.15/src/tcs/tcsi_tick.c0000664000175000017510000000547313663651711016465 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" TSS_RESULT TCSP_ReadCurrentTicks_Internal(TCS_CONTEXT_HANDLE hContext, UINT32* pulCurrentTime, BYTE** prgbCurrentTime) { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_GetTicks, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) result = tpm_rsp_parse(TPM_ORD_GetTicks, txBlob, paramSize, pulCurrentTime, prgbCurrentTime, NULL); done: return result; } TSS_RESULT TCSP_TickStampBlob_Internal(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_NONCE* antiReplay, TPM_DIGEST* digestToStamp, TPM_AUTH* privAuth, UINT32* pulSignatureLength, BYTE** prgbSignature, UINT32* pulTickCountLength, BYTE** prgbTickCount) { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; TPM_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if (privAuth) { if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } if ((result = ensureKeyIsLoaded(hContext, hKey, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_TickStampBlob, &offset, txBlob, keySlot, antiReplay, digestToStamp, privAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto done; } if (!result) { result = tpm_rsp_parse(TPM_ORD_TickStampBlob, txBlob, paramSize, pulTickCountLength, prgbTickCount, pulSignatureLength, prgbSignature, privAuth); } done: return result; } void UnloadBlob_CURRENT_TICKS(UINT64 *offset, BYTE *b, TPM_CURRENT_TICKS *t) { if (!t) { UnloadBlob_UINT16(offset, NULL, b); UnloadBlob_UINT64(offset, NULL, b); UnloadBlob_UINT16(offset, NULL, b); UnloadBlob(offset, sizeof(TPM_NONCE), b, NULL); return; } UnloadBlob_UINT16(offset, &t->tag, b); UnloadBlob_UINT64(offset, &t->currentTicks, b); UnloadBlob_UINT16(offset, &t->tickRate, b); UnloadBlob(offset, sizeof(TPM_NONCE), b, (BYTE *)&t->tickNonce); } trousers-0.3.15/src/tcs/tcsi_counter.c0000664000175000017510000001147013663651711017204 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" TSS_RESULT TCSP_ReadCounter_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_COUNTER_VALUE* counterValue) { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_ReadCounter, &offset, txBlob, idCounter, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) goto out; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("TPM_ReadCounter failed: rc=0x%x", result); goto out; } if (!result) { result = tpm_rsp_parse(TPM_ORD_ReadCounter, txBlob, paramSize, NULL, counterValue, NULL); } out: return result; } TSS_RESULT TCSP_CreateCounter_Internal(TCS_CONTEXT_HANDLE hContext, UINT32 LabelSize, BYTE* pLabel, TPM_ENCAUTH CounterAuth, TPM_AUTH* pOwnerAuth, TSS_COUNTER_ID* idCounter, TPM_COUNTER_VALUE* counterValue) { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if (LabelSize != 4) { LogDebugFn("BAD_PARAMETER: LabelSize != 4"); return TCSERR(TSS_E_BAD_PARAMETER); } if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_CreateCounter, &offset, txBlob, CounterAuth.authdata, LabelSize, pLabel, pOwnerAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto out; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("TPM_CreateCounter failed: rc=0x%x", result); goto out; } if (!result) { result = tpm_rsp_parse(TPM_ORD_CreateCounter, txBlob, paramSize, idCounter, counterValue, pOwnerAuth); } out: return result; } TSS_RESULT TCSP_IncrementCounter_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_AUTH* pCounterAuth, TPM_COUNTER_VALUE* counterValue) { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &pCounterAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_IncrementCounter, &offset, txBlob, idCounter, pCounterAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto out; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto out; } if (!result) { result = tpm_rsp_parse(TPM_ORD_IncrementCounter, txBlob, paramSize, NULL, counterValue, pCounterAuth); } out: return result; } TSS_RESULT TCSP_ReleaseCounter_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_AUTH* pCounterAuth) { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &pCounterAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_ReleaseCounter, &offset, txBlob, idCounter, pCounterAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto out; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto out; } if (!result) { result = tpm_rsp_parse(TPM_ORD_ReleaseCounter, txBlob, paramSize, pCounterAuth); } out: return result; } TSS_RESULT TCSP_ReleaseCounterOwner_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_AUTH* pOwnerAuth) { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_ReleaseCounterOwner, &offset, txBlob, idCounter, pOwnerAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto out; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto out; } if (!result) { result = tpm_rsp_parse(TPM_ORD_ReleaseCounterOwner, txBlob, paramSize, pOwnerAuth); } out: return result; } trousers-0.3.15/src/tcs/crypto/0000775000175000017510000000000013663651711015654 5ustar deboradeboratrousers-0.3.15/src/tcs/crypto/openssl/0000775000175000017510000000000013663651711017337 5ustar deboradeboratrousers-0.3.15/src/tcs/crypto/openssl/crypto.c0000664000175000017510000000237313663651711021030 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcslog.h" /* * Hopefully this will make the code clearer since * OpenSSL returns 1 on success */ #define EVP_SUCCESS 1 TSS_RESULT Hash(UINT32 HashType, UINT32 BufSize, BYTE* Buf, BYTE* Digest) { EVP_MD_CTX *md_ctx; unsigned int result_size; int rv; md_ctx = EVP_MD_CTX_create(); switch (HashType) { case TSS_HASH_SHA1: rv = EVP_DigestInit(md_ctx, EVP_sha1()); break; default: rv = TCSERR(TSS_E_BAD_PARAMETER); goto out; break; } if (rv != EVP_SUCCESS) { rv = TCSERR(TSS_E_INTERNAL_ERROR); goto out; } rv = EVP_DigestUpdate(md_ctx, Buf, BufSize); if (rv != EVP_SUCCESS) { rv = TCSERR(TSS_E_INTERNAL_ERROR); goto out; } result_size = EVP_MD_CTX_size(md_ctx); rv = EVP_DigestFinal(md_ctx, Digest, &result_size); if (rv != EVP_SUCCESS) { rv = TCSERR(TSS_E_INTERNAL_ERROR); } else rv = TSS_SUCCESS; out: EVP_MD_CTX_destroy(md_ctx); return rv; } trousers-0.3.15/src/tcs/tcsi_dir.c0000664000175000017510000000453713663651711016311 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_DirWriteAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE newContents, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering dirwriteauth"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if (dirIndex > tpm_metrics.num_dirs) { result = TCSERR(TSS_E_BAD_PARAMETER); goto done; } if ((result = tpm_rqu_build(TPM_ORD_DirWriteAuth, &offset, txBlob, dirIndex, TPM_DIGEST_SIZE, newContents.digest, ownerAuth, NULL))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_DirWriteAuth, txBlob, paramSize, ownerAuth); } LogResult("DirWriteAuth", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_DirRead_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE * dirValue) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering DirRead"); if ((result = ctx_verify_context(hContext))) return result; if (dirValue == NULL) return TCSERR(TSS_E_BAD_PARAMETER); if (dirIndex > tpm_metrics.num_dirs) return TCSERR(TSS_E_BAD_PARAMETER); if ((result = tpm_rqu_build(TPM_ORD_DirRead, &offset, txBlob, dirIndex, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_DirRead, txBlob, paramSize, NULL, dirValue->digest); } LogResult("DirRead", result); return result; } trousers-0.3.15/src/tcs/tcs_context.c0000664000175000017510000001406113663651711017037 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_context.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" unsigned long nextContextHandle = 0xA0000000; struct tcs_context *tcs_context_table = NULL; MUTEX_DECLARE_INIT(tcs_ctx_lock); TCS_CONTEXT_HANDLE getNextHandle(); struct tcs_context *create_tcs_context(); struct tcs_context *get_context(TCS_CONTEXT_HANDLE); struct tcs_context *get_previous_context(TCS_CONTEXT_HANDLE); TSS_BOOL initContextHandle = 1; TCS_CONTEXT_HANDLE getNextHandle() { UINT32 tempRand; time_t currentTime; if (initContextHandle) { currentTime = time(NULL); srand(currentTime); tempRand = rand(); tempRand = tempRand << 16; tempRand &= 0x00FF0000; nextContextHandle |= tempRand; initContextHandle = 0; } currentTime = time(NULL); srand(currentTime + 1); tempRand = rand(); tempRand = tempRand << 8; tempRand &= 0x0000FF00; if (nextContextHandle == 0) return getNextHandle(); else return ((nextContextHandle++) | tempRand); } struct tcs_context * create_tcs_context() { struct tcs_context *ret = (struct tcs_context *)calloc(1, sizeof(struct tcs_context)); if (ret != NULL) { ret->handle = getNextHandle(); COND_INIT(ret->cond); } return ret; } struct tcs_context * get_context(TCS_CONTEXT_HANDLE handle) { struct tcs_context *index; index = tcs_context_table; while (index) { if (index->handle == handle) break; index = index->next; } return index; } struct tcs_context * get_previous_context(TCS_CONTEXT_HANDLE handle) { struct tcs_context *index; index = tcs_context_table; while (index) { if (index->next) { if (index->next->handle == handle) return index; } index = index->next; } return 0; } void destroy_context(TCS_CONTEXT_HANDLE handle) { struct tcs_context *toKill; struct tcs_context *previous; MUTEX_LOCK(tcs_ctx_lock); toKill = get_context(handle); previous = get_previous_context(handle); if (!previous && tcs_context_table->handle == handle) { /* this means that toKill is the first one */ tcs_context_table = tcs_context_table->next; } else if (previous && toKill) { /* both are found */ previous->next = toKill->next; } else { MUTEX_UNLOCK(tcs_ctx_lock); return; } MUTEX_UNLOCK(tcs_ctx_lock); CTX_ref_count_keys(toKill); #ifdef TSS_BUILD_TRANSPORT /* Free existing transport session if necessary */ if (toKill != NULL && toKill->transHandle) TCSP_FlushSpecific_Common(toKill->transHandle, TPM_RT_TRANS); #endif free(toKill); } TCS_CONTEXT_HANDLE make_context() { struct tcs_context *index; MUTEX_LOCK(tcs_ctx_lock); index = tcs_context_table; if (!index) { tcs_context_table = create_tcs_context(); if (tcs_context_table == NULL) { LogError("Malloc Failure."); MUTEX_UNLOCK(tcs_ctx_lock); return 0; } index = tcs_context_table; } else { while (index->next) { index = index->next; } index->next = create_tcs_context(); if (index->next == NULL) { LogError("Malloc Failure."); MUTEX_UNLOCK(tcs_ctx_lock); return 0; } index = index->next; } MUTEX_UNLOCK(tcs_ctx_lock); return index->handle; } TSS_RESULT ctx_verify_context(TCS_CONTEXT_HANDLE tcsContext) { struct tcs_context *c; MUTEX_LOCK(tcs_ctx_lock); c = get_context(tcsContext); MUTEX_UNLOCK(tcs_ctx_lock); if (c == NULL) { LogDebug("Fail: Context %x not found", tcsContext); return TCSERR(TCS_E_INVALID_CONTEXTHANDLE); } return TSS_SUCCESS; } COND_VAR * ctx_get_cond_var(TCS_CONTEXT_HANDLE tcs_handle) { struct tcs_context *c; COND_VAR *ret = NULL; MUTEX_LOCK(tcs_ctx_lock); c = get_context(tcs_handle); if (c != NULL) ret = &c->cond; MUTEX_UNLOCK(tcs_ctx_lock); return ret; } /* the only transport flag at the TCS level is whether the session is exclusive or not. If the app * is requesting an exclusive transport session, check that no other exclusive sessions exist and * if not, flag this context as being the one. If so, return internal error. */ TSS_RESULT ctx_req_exclusive_transport(TCS_CONTEXT_HANDLE tcsContext) { TSS_RESULT result = TSS_SUCCESS; struct tcs_context *tmp, *self = NULL; /* If the daemon is configured to ignore apps that want an exclusive transport, just * return */ if (!tcsd_options.exclusive_transport) return result; MUTEX_LOCK(tcs_ctx_lock); tmp = tcs_context_table; while (tmp) { if (tmp->flags & TSS_CONTEXT_FLAG_TRANSPORT_EXCLUSIVE) { result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } if (tmp->handle == tcsContext) self = tmp; tmp = tmp->next; } if (self) self->flags |= TSS_CONTEXT_FLAG_TRANSPORT_EXCLUSIVE; else result = TCSERR(TCS_E_INVALID_CONTEXTHANDLE); done: MUTEX_UNLOCK(tcs_ctx_lock); return result; } TSS_RESULT ctx_set_transport_enabled(TCS_CONTEXT_HANDLE tcsContext, UINT32 hTransHandle) { TSS_RESULT result = TSS_SUCCESS; struct tcs_context *tmp, *self = NULL; MUTEX_LOCK(tcs_ctx_lock); tmp = tcs_context_table; while (tmp) { if (tmp->handle == tcsContext) { self = tmp; break; } tmp = tmp->next; } if (self) { self->flags |= TSS_CONTEXT_FLAG_TRANSPORT_ENABLED; self->transHandle = hTransHandle; } else result = TCSERR(TCS_E_INVALID_CONTEXTHANDLE); MUTEX_UNLOCK(tcs_ctx_lock); return result; } TSS_RESULT ctx_set_transport_disabled(TCS_CONTEXT_HANDLE tcsContext, TCS_HANDLE *transHandle) { TSS_RESULT result = TSS_SUCCESS; struct tcs_context *tmp, *self = NULL; MUTEX_LOCK(tcs_ctx_lock); tmp = tcs_context_table; while (tmp) { if (tmp->handle == tcsContext) { self = tmp; break; } tmp = tmp->next; } if (self) { if (!transHandle || *transHandle == self->transHandle) { self->transHandle = 0; self->flags &= ~TSS_CONTEXT_FLAG_TRANSPORT_ENABLED; } } else result = TCSERR(TCS_E_INVALID_CONTEXTHANDLE); MUTEX_UNLOCK(tcs_ctx_lock); return result; } trousers-0.3.15/src/tcs/tcsi_ps.c0000664000175000017510000004416713663651711016160 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" TSS_RESULT TCS_RegisterKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *WrappingKeyUUID, /* in */ TSS_UUID *KeyUUID, /* in */ UINT32 cKeySize, /* in */ BYTE * rgbKey, /* in */ UINT32 cVendorData, /* in */ BYTE * gbVendorData) /* in */ { TSS_RESULT result; TSS_BOOL is_reg; if ((result = ctx_verify_context(hContext))) return result; /* Check if key is already regisitered */ if (isUUIDRegistered(KeyUUID, &is_reg) != TSS_SUCCESS) { LogError("Failed checking if UUID is registered."); return TCSERR(TSS_E_INTERNAL_ERROR); } if (is_reg == TRUE || TSS_UUID_IS_OWNEREVICT(KeyUUID)) { LogDebug("UUID is already registered"); return TCSERR(TSS_E_KEY_ALREADY_REGISTERED); } LogDebugUnrollKey(rgbKey); /* Go ahead and store it in system persistant storage */ if ((result = ps_write_key(KeyUUID, WrappingKeyUUID, gbVendorData, cVendorData, rgbKey, cKeySize))) { LogError("Error writing key to file"); return result; } return TSS_SUCCESS; } TSS_RESULT TCS_UnregisterKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID KeyUUID) /* in */ { TSS_RESULT result; if ((result = ctx_verify_context(hContext))) return result; return ps_remove_key(&KeyUUID); } TSS_RESULT TCS_EnumRegisteredKeys_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO ** ppKeyHierarchy) /* out */ { TSS_RESULT result = TSS_SUCCESS; UINT32 count = 0, i; TSS_KM_KEYINFO *ret = NULL; TSS_UUID tmp_uuid; struct key_disk_cache *disk_ptr, *tmp_ptrs[MAX_KEY_CHILDREN]; struct key_mem_cache *mem_ptr; TSS_BOOL is_reg = FALSE; LogDebug("Enum Reg Keys"); if (pcKeyHierarchySize == NULL || ppKeyHierarchy == NULL) return TCSERR(TSS_E_BAD_PARAMETER); if ((result = ctx_verify_context(hContext))) return result; if (pKeyUUID != NULL) { /* First have to verify the key is registered */ if ((result = isUUIDRegistered(pKeyUUID, &is_reg))) return result; if (is_reg == FALSE) { /* This return code is not listed as possible in the TSS 1.1 spec, * but it makes more sense than just TCS_SUCCESS or TSS_E_FAIL */ return TCSERR(TSS_E_PS_KEY_NOTFOUND); } } /* this entire operation needs to be atomic wrt registered keys. We must * lock the mem cache as well to test if a given key is loaded. */ MUTEX_LOCK(disk_cache_lock); MUTEX_LOCK(mem_cache_lock); /* return an array of all registered keys if pKeyUUID == NULL */ if (pKeyUUID == NULL) { /* determine the number of registered keys */ for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { if (disk_ptr->flags & CACHE_FLAG_VALID) count++; } /* malloc a structure for each of them */ if (count != 0) { ret = calloc(count, sizeof(TSS_KM_KEYINFO)); if (ret == NULL) { LogError("malloc of %zd bytes failed.", (count * sizeof(TSS_KM_KEYINFO))); count = 0; result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } } else { goto done; } /* fill out the structure for each key */ i = 0; for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { if (disk_ptr->flags & CACHE_FLAG_VALID) { /* look for a mem cache entry to check if its loaded */ for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { if (!memcmp(&mem_ptr->uuid, &disk_ptr->uuid, sizeof(TSS_UUID))) { if ((result = fill_key_info(disk_ptr, mem_ptr, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } break; } } /* if there is no mem cache entry for this key, go ahead and call * fill_key_info(), it will pull everything from disk */ if (mem_ptr == NULL) { if ((result = fill_key_info(disk_ptr, NULL, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } } i++; } } } else { /* return a chain of a key and its parents up to the SRK */ /* determine the number of keys in the chain */ memcpy(&tmp_uuid, pKeyUUID, sizeof(TSS_UUID)); disk_ptr = key_disk_cache_head; while (disk_ptr != NULL && count < MAX_KEY_CHILDREN) { if (disk_ptr->flags & CACHE_FLAG_VALID && !memcmp(&disk_ptr->uuid, &tmp_uuid, sizeof(TSS_UUID))) { /* increment count, then search for the parent */ count++; /* save a pointer to this cache entry */ tmp_ptrs[count - 1] = disk_ptr; /* if the parent of this key is NULL, we're at the root of the tree */ if (!memcmp(&disk_ptr->parent_uuid, &NULL_UUID, sizeof(TSS_UUID))) break; /* overwrite tmp_uuid with the parent, which we will now search for */ memcpy(&tmp_uuid, &disk_ptr->parent_uuid, sizeof(TSS_UUID)); disk_ptr = key_disk_cache_head; continue; } disk_ptr = disk_ptr->next; } /* when we reach this point, we have an array of TSS_UUID's that leads from the * requested key up to the SRK*/ /* malloc a structure for each of them */ if (count != 0) { ret = calloc(count, sizeof(TSS_KM_KEYINFO)); if (ret == NULL) { LogError("malloc of %zd bytes failed.", (count * sizeof(TSS_KM_KEYINFO))); count = 0; result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } } else { goto done; } for (i = 0; i < count; i++) { /* look for a mem cache entry to check if its loaded */ for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { if (!memcmp(&mem_ptr->uuid, &tmp_ptrs[i]->uuid, sizeof(TSS_UUID))) { if ((result = fill_key_info(tmp_ptrs[i], mem_ptr, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } break; } } /* if there is no mem cache entry for this key, go ahead and call * fill_key_info(), it will pull everything from disk */ if (mem_ptr == NULL) { if ((result = fill_key_info(tmp_ptrs[i], NULL, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } } } } done: MUTEX_UNLOCK(disk_cache_lock); MUTEX_UNLOCK(mem_cache_lock); *ppKeyHierarchy = ret; *pcKeyHierarchySize = count; return result; } TSS_RESULT TCS_EnumRegisteredKeys_Internal2(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO2 ** ppKeyHierarchy) /* out */ { TSS_RESULT result = TSS_SUCCESS; UINT32 count = 0, i; TSS_KM_KEYINFO2 *ret = NULL; TSS_UUID tmp_uuid; struct key_disk_cache *disk_ptr, *tmp_ptrs[MAX_KEY_CHILDREN]; struct key_mem_cache *mem_ptr; TSS_BOOL is_reg = FALSE; LogDebug("Enum Reg Keys2"); if (pcKeyHierarchySize == NULL || ppKeyHierarchy == NULL) return TCSERR(TSS_E_BAD_PARAMETER); if ((result = ctx_verify_context(hContext))) return result; if (pKeyUUID != NULL) { /* First have to verify the key is registered */ if ((result = isUUIDRegistered(pKeyUUID, &is_reg))) return result; if (is_reg == FALSE) { /* This return code is not listed as possible in the TSS 1.1 spec, * but it makes more sense than just TCS_SUCCESS or TSS_E_FAIL */ return TCSERR(TSS_E_PS_KEY_NOTFOUND); } } /* this entire operation needs to be atomic wrt registered keys. We must * lock the mem cache as well to test if a given key is loaded. */ MUTEX_LOCK(disk_cache_lock); MUTEX_LOCK(mem_cache_lock); /* return an array of all registered keys if pKeyUUID == NULL */ if (pKeyUUID == NULL) { /* determine the number of registered keys */ for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { if (disk_ptr->flags & CACHE_FLAG_VALID) count++; } /* malloc a structure for each of them */ if (count != 0) { ret = calloc(count, sizeof(TSS_KM_KEYINFO2)); if (ret == NULL) { LogError("malloc of %zd bytes failed.", (count * sizeof(TSS_KM_KEYINFO2))); count = 0; result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } } else { goto done; } /* fill out the structure for each key */ i = 0; for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { if (disk_ptr->flags & CACHE_FLAG_VALID) { /* look for a mem cache entry to check if its loaded */ for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { if (!memcmp(&mem_ptr->uuid, &disk_ptr->uuid, sizeof(TSS_UUID))) { if ((result = fill_key_info2(disk_ptr, mem_ptr, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } break; } } /* if there is no mem cache entry for this key, go ahead and call * fill_key_info2(), it will pull everything from disk */ if (mem_ptr == NULL) { if ((result = fill_key_info2(disk_ptr, NULL, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } } i++; } } } else { /* return a chain of a key and its parents up to the SRK */ /* determine the number of keys in the chain */ memcpy(&tmp_uuid, pKeyUUID, sizeof(TSS_UUID)); disk_ptr = key_disk_cache_head; while (disk_ptr != NULL && count < MAX_KEY_CHILDREN) { if (disk_ptr->flags & CACHE_FLAG_VALID && !memcmp(&disk_ptr->uuid, &tmp_uuid, sizeof(TSS_UUID))) { /* increment count, then search for the parent */ count++; /* save a pointer to this cache entry */ tmp_ptrs[count - 1] = disk_ptr; /* if the parent of this key is NULL, we're at the root of the tree */ if (!memcmp(&disk_ptr->parent_uuid, &NULL_UUID, sizeof(TSS_UUID))) break; /* overwrite tmp_uuid with the parent, which we will now search for */ memcpy(&tmp_uuid, &disk_ptr->parent_uuid, sizeof(TSS_UUID)); disk_ptr = key_disk_cache_head; continue; } disk_ptr = disk_ptr->next; } /* when we reach this point, we have an array of TSS_UUID's that leads from the * requested key up to the SRK*/ /* malloc a structure for each of them */ if (count != 0) { ret = calloc(count, sizeof(TSS_KM_KEYINFO2)); if (ret == NULL) { LogError("malloc of %zd bytes failed.", (count * sizeof(TSS_KM_KEYINFO2))); count = 0; result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } } else { goto done; } for (i = 0; i < count; i++) { /* look for a mem cache entry to check if its loaded */ for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { if (!memcmp(&mem_ptr->uuid, &tmp_ptrs[i]->uuid, sizeof(TSS_UUID))) { if ((result = fill_key_info2(tmp_ptrs[i], mem_ptr, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } break; } } /* if there is no mem cache entry for this key, go ahead and call * fill_key_info(), it will pull everything from disk */ if (mem_ptr == NULL) { if ((result = fill_key_info2(tmp_ptrs[i], NULL, &ret[i]))) { free(ret); ret = NULL; count = 0; goto done; } } } } done: MUTEX_UNLOCK(disk_cache_lock); MUTEX_UNLOCK(mem_cache_lock); *ppKeyHierarchy = ret; *pcKeyHierarchySize = count; return result; } TSS_RESULT TCS_GetRegisteredKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *KeyUUID, /* in */ TSS_KM_KEYINFO ** ppKeyInfo) /* out */ { TSS_RESULT result; UINT64 offset; BYTE tcpaKeyBlob[1024]; TSS_KEY tcpaKey; UINT16 keySize = sizeof (tcpaKeyBlob); TSS_UUID parentUUID; /* This should be set in case we return before the malloc */ *ppKeyInfo = NULL; if ((result = ctx_verify_context(hContext))) return result; if ((result = ps_get_key_by_uuid(KeyUUID, tcpaKeyBlob, &keySize))) { return TCSERR(TSS_E_PS_KEY_NOTFOUND); } if ((result = getParentUUIDByUUID(KeyUUID, &parentUUID))) return TCSERR(TSS_E_FAIL); *ppKeyInfo = malloc(sizeof(TSS_KM_KEYINFO)); if (*ppKeyInfo == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_KM_KEYINFO)); return TCSERR(TSS_E_OUTOFMEMORY); } offset = 0; UnloadBlob_TSS_KEY(&offset, tcpaKeyBlob, &tcpaKey); (*ppKeyInfo)->bAuthDataUsage = tcpaKey.authDataUsage; (*ppKeyInfo)->fIsLoaded = FALSE; if (tcpaKey.hdr.key12.tag == TPM_TAG_KEY12) { (*ppKeyInfo)->versionInfo.bMajor = TSS_SPEC_MAJOR; (*ppKeyInfo)->versionInfo.bMinor = TSS_SPEC_MINOR; (*ppKeyInfo)->versionInfo.bRevMajor = 0; (*ppKeyInfo)->versionInfo.bRevMinor = 0; } else { (*ppKeyInfo)->versionInfo.bMajor = tcpaKey.hdr.key11.ver.major; (*ppKeyInfo)->versionInfo.bMinor = tcpaKey.hdr.key11.ver.minor; (*ppKeyInfo)->versionInfo.bRevMajor = tcpaKey.hdr.key11.ver.revMajor; (*ppKeyInfo)->versionInfo.bRevMinor = tcpaKey.hdr.key11.ver.revMinor; } memcpy(&((*ppKeyInfo)->keyUUID), KeyUUID, sizeof(TSS_UUID)); (*ppKeyInfo)->ulVendorDataLength = 0; (*ppKeyInfo)->rgbVendorData = 0; memcpy(&((*ppKeyInfo)->parentKeyUUID), &parentUUID, sizeof(TSS_UUID)); return TSS_SUCCESS; } TSS_RESULT TCS_GetRegisteredKeyBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *KeyUUID, /* in */ UINT32 * pcKeySize, /* out */ BYTE ** prgbKey) /* out */ { UINT16 keySize; BYTE buffer[4096]; TSS_RESULT result; if ((result = ctx_verify_context(hContext))) return result; keySize = sizeof(buffer); if ((result = ps_get_key_by_uuid(KeyUUID, buffer, &keySize))) return TCSERR(TSS_E_PS_KEY_NOTFOUND); *prgbKey = calloc(1, keySize); if (*prgbKey == NULL) { LogError("malloc of %d bytes failed.", keySize); return TCSERR(TSS_E_OUTOFMEMORY); } else { memcpy(*prgbKey, buffer, keySize); } *pcKeySize = keySize; return TSS_SUCCESS; } TSS_RESULT TCSP_LoadKeyByUUID_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *KeyUUID, /* in */ TCS_LOADKEY_INFO * pLoadKeyInfo, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI) /* out */ { UINT32 keyslot = 0, keySize; UINT32 ordinal; TSS_RESULT result; TSS_UUID parentUuid; BYTE keyBlob[0x1000]; UINT16 blobSize = sizeof(keyBlob); UINT64 offset; TCS_KEY_HANDLE parentTCSKeyHandle; if (TPM_VERSION_IS(1,2)) ordinal = TPM_ORD_LoadKey2; else ordinal = TPM_ORD_LoadKey; LogDebugFn("Enter: uuid: 0x%lx auth? 0x%x ***********", (unsigned long)KeyUUID, pLoadKeyInfo == NULL ? 0xdeadbeef : pLoadKeyInfo->authData.AuthHandle); if ((result = ctx_verify_context(hContext))) return result; memset(&parentUuid, 0, sizeof(TSS_UUID)); if (pLoadKeyInfo && memcmp(&pLoadKeyInfo->parentKeyUUID, &parentUuid, sizeof(TSS_UUID))) { if (ps_get_key_by_uuid(&pLoadKeyInfo->keyUUID, keyBlob, &blobSize)) return TCSERR(TSS_E_PS_KEY_NOTFOUND); if (mc_get_handles_by_uuid(&pLoadKeyInfo->parentKeyUUID, &parentTCSKeyHandle, &keyslot)) return TCSERR(TCS_E_KM_LOADFAILED); return LoadKeyByBlob_Internal(ordinal, hContext, parentTCSKeyHandle, blobSize, keyBlob, &pLoadKeyInfo->authData, phKeyTCSI, &keyslot); } /* if KeyUUID is already loaded, increment the ref count and return */ if (mc_get_handles_by_uuid(KeyUUID, phKeyTCSI, &keyslot) == TSS_SUCCESS) { if (keyslot) { if (ctx_mark_key_loaded(hContext, *phKeyTCSI)) { LogError("Error marking key as loaded"); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } } /********************************************************************* * The first thing to do in this func is setup all the info and make sure * that we get it all from either the keyfile or the keyCache * also, it's important to return if the key is already loaded ***********************************************************************/ LogDebugFn("calling ps_get_key_by_uuid"); if (ps_get_key_by_uuid(KeyUUID, keyBlob, &blobSize)) return TCSERR(TSS_E_PS_KEY_NOTFOUND); /* convert UINT16 to UIN32 */ keySize = blobSize; LogDebugFn("calling getParentUUIDByUUID"); /*--- Get my parent's UUID. Since My key is registered, my parent should be as well. */ if ((result = getParentUUIDByUUID(KeyUUID, &parentUuid))) return TCSERR(TCS_E_KM_LOADFAILED); if ((result = TCSP_LoadKeyByUUID_Internal(hContext, &parentUuid, pLoadKeyInfo, &parentTCSKeyHandle))) return result; LogDebugFn("calling LoadKeyByBlob_Internal"); /******************************************************* * If no errors have happend up till now, then the parent is loaded and ready for use. * The parent's TCS Handle should be in parentTCSKeyHandle. ******************************************************/ if ((result = LoadKeyByBlob_Internal(ordinal, hContext, parentTCSKeyHandle, keySize, keyBlob, NULL, phKeyTCSI, &keyslot))) { LogDebugFn("LoadKeyByBlob_Internal returned 0x%x", result); if (result == TCPA_E_AUTHFAIL && pLoadKeyInfo) { BYTE blob[1000]; /* set up a load key info struct */ memcpy(&pLoadKeyInfo->parentKeyUUID, &parentUuid, sizeof(TSS_UUID)); memcpy(&pLoadKeyInfo->keyUUID, KeyUUID, sizeof(TSS_UUID)); /* calculate the paramDigest */ offset = 0; LoadBlob_UINT32(&offset, ordinal, blob); LoadBlob(&offset, keySize, blob, keyBlob); if (Hash(TSS_HASH_SHA1, offset, blob, (BYTE *)&pLoadKeyInfo->paramDigest.digest)) result = TCSERR(TSS_E_INTERNAL_ERROR); result = TCSERR(TCS_E_KM_LOADFAILED); } } return result; } TSS_RESULT TCSP_GetRegisteredKeyByPublicInfo_Internal(TCS_CONTEXT_HANDLE tcsContext, /* in */ TCPA_ALGORITHM_ID algID, /* in */ UINT32 ulPublicInfoLength, /* in */ BYTE * rgbPublicInfo, /* in */ UINT32 * keySize, /* out */ BYTE ** keyBlob) /* out */ { TCPA_STORE_PUBKEY pubKey; TSS_RESULT result = TCSERR(TSS_E_FAIL); pubKey.key = NULL; if ((result = ctx_verify_context(tcsContext))) return result; if (algID == TCPA_ALG_RSA) { /*--- Convert Public info to a structure */ pubKey.keyLength = ulPublicInfoLength; pubKey.key = malloc(pubKey.keyLength); if (pubKey.key == NULL) { LogError("malloc of %d bytes failed.", pubKey.keyLength); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(pubKey.key, rgbPublicInfo, pubKey.keyLength); if ((result = ps_get_key_by_pub(&pubKey, keySize, keyBlob))) { LogDebug("Public key data not found in PS"); free(pubKey.key); return TCSERR(TSS_E_PS_KEY_NOTFOUND); } } free(pubKey.key); return result; } trousers-0.3.15/src/tcs/tcs_counter.c0000664000175000017510000000223313663651711017030 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" void UnloadBlob_COUNTER_VALUE(UINT64 *offset, BYTE *blob, TPM_COUNTER_VALUE *ctr) { if (!ctr) { UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob(offset, 4, blob, NULL); UnloadBlob_UINT32(offset, NULL, blob); return; } UnloadBlob_UINT16(offset, &ctr->tag, blob); UnloadBlob(offset, 4, blob, (BYTE *)&ctr->label); UnloadBlob_UINT32(offset, &ctr->counter, blob); } void LoadBlob_COUNTER_VALUE(UINT64 *offset, BYTE *blob, TPM_COUNTER_VALUE *ctr) { LoadBlob_UINT16(offset, ctr->tag, blob); LoadBlob(offset, 4, blob, (BYTE *)&ctr->label); LoadBlob_UINT32(offset, ctr->counter, blob); } trousers-0.3.15/src/tcs/tcs_migration.c0000664000175000017510000000202613663651711017342 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT UnloadBlob_MIGRATIONKEYAUTH(UINT64 *offset, BYTE *blob, TCPA_MIGRATIONKEYAUTH *mkAuth) { TSS_RESULT result; if (!mkAuth) { if ((result = UnloadBlob_PUBKEY(offset, blob, NULL))) return result; UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob(offset, 20, blob, NULL); return TSS_SUCCESS; } if ((result = UnloadBlob_PUBKEY(offset, blob, &mkAuth->migrationKey))) return result; UnloadBlob_UINT16(offset, &mkAuth->migrationScheme, blob); UnloadBlob(offset, 20, blob, mkAuth->digest.digest); return result; } trousers-0.3.15/src/tcs/tcs_evlog_biosem.c0000664000175000017510000001471513663651711020033 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ /* * biosem.c * * Routines for handling PCR events from the TCG Compliant BIOS * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #include "tcsem.h" #ifdef EVLOG_SOURCE_BIOS struct ext_log_source bios_source = { bios_open, bios_get_entries_by_pcr, bios_get_entry, bios_close }; int bios_open(void *source, FILE **handle) { FILE *fd; if ((fd = fopen((char *)source, "r")) == NULL ) { LogError("Error opening BIOS Eventlog file %s: %s", (char *)source, strerror(errno)); return -1; } *handle = fd; return 0; } TSS_RESULT bios_get_entries_by_pcr(FILE *handle, UINT32 pcr_index, UINT32 first, UINT32 *count, TSS_PCR_EVENT **events) { char page[BIOS_READ_SIZE]; int error_path = 1; UINT32 seen_indices = 0, copied_events = 0, i; struct event_wrapper *list = calloc(1, sizeof(struct event_wrapper)); struct event_wrapper *cur = list; TSS_RESULT result = TSS_E_INTERNAL_ERROR; TCG_PCClientPCREventStruc *event = NULL; int num=0; if (list == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct event_wrapper)); return TSS_E_OUTOFMEMORY; } if (*count == 0) { result = TSS_SUCCESS; goto free_list; } while (1) { /* read event header from the file */ if ((fread(page, 32, 1, handle)) <= 0) { goto copy_events; } event = (TCG_PCClientPCREventStruc *)page; /* if the index is the one we're looking for, grab the entry */ if (pcr_index == event->pcrIndex) { if (seen_indices >= first) { /* grab this entry */ cur->event.rgbPcrValue = malloc(20); if (cur->event.rgbPcrValue == NULL) { LogError("malloc of %d bytes failed.", 20); result = TSS_E_OUTOFMEMORY; goto free_list; } cur->event.ulPcrIndex = pcr_index; cur->event.eventType = event->eventType; cur->event.ulPcrValueLength = 20; /* copy the SHA1 XXX endianess ignored */ memcpy(cur->event.rgbPcrValue, event->digest, 20); /* copy the event name XXX endianess ignored */ cur->event.ulEventLength = event->eventDataSize; if (event->eventDataSize>0) { cur->event.rgbEvent = malloc(event->eventDataSize); if (cur->event.rgbEvent == NULL) { LogError("malloc of %d bytes failed.", event->eventDataSize); free(cur->event.rgbPcrValue); result = TSS_E_OUTOFMEMORY; goto free_list; } if ((fread(cur->event.rgbEvent, event->eventDataSize, 1, handle)) <= 0) { LogError("read from event source failed: %s", strerror(errno)); goto free_list; } } else { cur->event.rgbEvent = NULL; } copied_events++; if (copied_events == *count) goto copy_events; cur->next = calloc(1, sizeof(struct event_wrapper)); if (cur->next == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct event_wrapper)); result = TSS_E_OUTOFMEMORY; goto free_list; } cur = cur->next; } else { /* skip */ if (event->eventDataSize > 0) fseek(handle,event->eventDataSize,SEEK_CUR); } seen_indices++; } else { if (event->eventDataSize > 0) fseek(handle,event->eventDataSize,SEEK_CUR); } num++; } copy_events: /* we've copied all the events we need to from this PCR, now * copy them all into one contiguous memory block */ *events = calloc(copied_events, sizeof(TSS_PCR_EVENT)); if (*events == NULL) { LogError("malloc of %zd bytes failed.", copied_events * sizeof(TSS_PCR_EVENT)); result = TSS_E_OUTOFMEMORY; goto free_list; } cur = list; for (i = 0; i < copied_events; i++) { memcpy(&((*events)[i]), &(cur->event), sizeof(TSS_PCR_EVENT)); cur = cur->next; } *count = copied_events; /* assume we're in an error path until we get here */ error_path = 0; result = TSS_SUCCESS; free_list: cur = list->next; while (cur != NULL) { if (error_path) { free(cur->event.rgbEvent); free(cur->event.rgbPcrValue); } free(list); list = cur; cur = list->next; } free(list); return result; } TSS_RESULT bios_get_entry(FILE *handle, UINT32 pcr_index, UINT32 *num, TSS_PCR_EVENT **ppEvent) { char page[BIOS_READ_SIZE]; UINT32 seen_indices = 0; TSS_RESULT result = TSS_E_INTERNAL_ERROR; TSS_PCR_EVENT *e = NULL; TCG_PCClientPCREventStruc *event = NULL; while (1) { /* read event header from the file */ if ((fread(page, 32, 1, handle)) == 0) { goto done; } event = (TCG_PCClientPCREventStruc *)page; if (pcr_index == event->pcrIndex) { if (ppEvent && !*ppEvent && seen_indices == *num) { *ppEvent = calloc(1, sizeof(TSS_PCR_EVENT)); if (*ppEvent == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_PCR_EVENT)); return TSS_E_INTERNAL_ERROR; } e = *ppEvent; e->rgbPcrValue = malloc(20); if (e->rgbPcrValue == NULL) { LogError("malloc of %d bytes failed.", 20); free(e); e = NULL; break; } e->ulPcrIndex = pcr_index; e->eventType = event->eventType; e->ulPcrValueLength = 20; /* copy the SHA1 XXX endianess ignored */ memcpy(e->rgbPcrValue, event->digest, 20); e->ulEventLength = event->eventDataSize; if (event->eventDataSize>0) { e->rgbEvent = malloc(e->ulEventLength); if (e->rgbEvent == NULL) { LogError("malloc of %d bytes failed.", e->ulEventLength); free(e->rgbPcrValue); free(e); e = NULL; break; } if ((fread(e->rgbEvent, event->eventDataSize, 1, handle)) <= 0) { LogError("read from event source failed: %s", strerror(errno)); return result; } } else { e->rgbEvent = NULL; } result = TSS_SUCCESS; break; } else { /* skip */ if (event->eventDataSize > 0) { fseek(handle,event->eventDataSize,SEEK_CUR); } } seen_indices++; } else { /* skip */ if (event->eventDataSize > 0) { fseek(handle,event->eventDataSize,SEEK_CUR); } } } done: if (!ppEvent) { *num = seen_indices; result = TSS_SUCCESS; } else if (e == NULL) *ppEvent = NULL; return result; } int bios_close(FILE *handle) { fclose(handle); return 0; } #endif trousers-0.3.15/src/tcs/tcsi_evlog.c0000664000175000017510000002607013663651711016643 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcslog.h" #include "tcsem.h" TSS_RESULT TCS_LogPcrEvent_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_PCR_EVENT Event, /* in */ UINT32 *pNumber) /* out */ { TSS_RESULT result; if((result = ctx_verify_context(hContext))) return result; if(Event.ulPcrIndex >= tpm_metrics.num_pcrs) return TCSERR(TSS_E_BAD_PARAMETER); if (tcsd_options.kernel_pcrs & (1 << Event.ulPcrIndex)) { LogInfo("PCR %d is configured to be kernel controlled. Event logging denied.", Event.ulPcrIndex); return TCSERR(TSS_E_FAIL); } if (tcsd_options.firmware_pcrs & (1 << Event.ulPcrIndex)) { LogInfo("PCR %d is configured to be firmware controlled. Event logging denied.", Event.ulPcrIndex); return TCSERR(TSS_E_FAIL); } return event_log_add(&Event, pNumber); } /* This routine will handle creating the TSS_PCR_EVENT structures from log * data produced by an external source. The external source in mind here * is the log of PCR extends done by the kernel from beneath the TSS * (via direct calls to the device driver). */ TSS_RESULT TCS_GetExternalPcrEvent(UINT32 PcrIndex, /* in */ UINT32 *pNumber, /* in, out */ TSS_PCR_EVENT **ppEvent) /* out */ { FILE *log_handle; char *source; if (tcsd_options.kernel_pcrs & (1 << PcrIndex)) { source = tcsd_options.kernel_log_file; if (tcs_event_log->kernel_source != NULL) { if (tcs_event_log->kernel_source->open((void *)source, (FILE **) &log_handle)) return TCSERR(TSS_E_INTERNAL_ERROR); if (tcs_event_log->kernel_source->get_entry(log_handle, PcrIndex, pNumber, ppEvent)) { tcs_event_log->kernel_source->close(log_handle); return TCSERR(TSS_E_INTERNAL_ERROR); } tcs_event_log->kernel_source->close(log_handle); } else { LogError("No source for externel kernel events was compiled in, but " "the tcsd is configured to use one! (see %s)", tcsd_config_file); return TCSERR(TSS_E_INTERNAL_ERROR); } } else if (tcsd_options.firmware_pcrs & (1 << PcrIndex)) { source = tcsd_options.firmware_log_file; if (tcs_event_log->firmware_source != NULL) { if (tcs_event_log->firmware_source->open((void *)source, &log_handle)) return TCSERR(TSS_E_INTERNAL_ERROR); if (tcs_event_log->firmware_source->get_entry(log_handle, PcrIndex, pNumber, ppEvent)) { tcs_event_log->firmware_source->close(log_handle); return TCSERR(TSS_E_INTERNAL_ERROR); } tcs_event_log->firmware_source->close(log_handle); } else { LogError("No source for externel firmware events was compiled in, but " "the tcsd is configured to use one! (see %s)", tcsd_config_file); return TCSERR(TSS_E_INTERNAL_ERROR); } } else { LogError("PCR index %d not flagged as kernel or firmware controlled.", PcrIndex); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT TCS_GetPcrEvent_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 PcrIndex, /* in */ UINT32 *pNumber, /* in, out */ TSS_PCR_EVENT **ppEvent) /* out */ { TSS_RESULT result; TSS_PCR_EVENT *event; if ((result = ctx_verify_context(hContext))) return result; if(PcrIndex >= tpm_metrics.num_pcrs) return TCSERR(TSS_E_BAD_PARAMETER); /* if this is a kernel or firmware controlled PCR, call an external routine */ if ((tcsd_options.kernel_pcrs & (1 << PcrIndex)) || (tcsd_options.firmware_pcrs & (1 << PcrIndex))) { MUTEX_LOCK(tcs_event_log->lock); result = TCS_GetExternalPcrEvent(PcrIndex, pNumber, ppEvent); MUTEX_UNLOCK(tcs_event_log->lock); return result; } if (ppEvent == NULL) { MUTEX_LOCK(tcs_event_log->lock); *pNumber = get_num_events(PcrIndex); MUTEX_UNLOCK(tcs_event_log->lock); } else { *ppEvent = calloc(1, sizeof(TSS_PCR_EVENT)); if (*ppEvent == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_PCR_EVENT)); return TCSERR(TSS_E_OUTOFMEMORY); } event = get_pcr_event(PcrIndex, *pNumber); if (event == NULL) { free(*ppEvent); return TCSERR(TSS_E_BAD_PARAMETER); } if ((result = copy_pcr_event(*ppEvent, event))) { free(*ppEvent); return result; } } return TSS_SUCCESS; } /* This routine will handle creating the TSS_PCR_EVENT structures from log * data produced by an external source. The external source in mind here * is the log of PCR extends done by the kernel from beneath the TSS * (via direct calls to the device driver). */ TSS_RESULT TCS_GetExternalPcrEventsByPcr(UINT32 PcrIndex, /* in */ UINT32 FirstEvent, /* in */ UINT32 *pEventCount, /* in, out */ TSS_PCR_EVENT **ppEvents) /* out */ { FILE *log_handle; char *source; if (tcsd_options.kernel_pcrs & (1 << PcrIndex)) { source = tcsd_options.kernel_log_file; if (tcs_event_log->kernel_source != NULL) { if (tcs_event_log->kernel_source->open((void *)source, &log_handle)) return TCSERR(TSS_E_INTERNAL_ERROR); if (tcs_event_log->kernel_source->get_entries_by_pcr(log_handle, PcrIndex, FirstEvent, pEventCount, ppEvents)) { tcs_event_log->kernel_source->close(log_handle); return TCSERR(TSS_E_INTERNAL_ERROR); } tcs_event_log->kernel_source->close(log_handle); } else { LogError("No source for externel kernel events was compiled in, but " "the tcsd is configured to use one! (see %s)", tcsd_config_file); return TCSERR(TSS_E_INTERNAL_ERROR); } } else if (tcsd_options.firmware_pcrs & (1 << PcrIndex)) { source = tcsd_options.firmware_log_file; if (tcs_event_log->firmware_source != NULL) { if (tcs_event_log->firmware_source->open((void *)source, &log_handle)) return TCSERR(TSS_E_INTERNAL_ERROR); if (tcs_event_log->firmware_source->get_entries_by_pcr(log_handle, PcrIndex, FirstEvent, pEventCount, ppEvents)) { tcs_event_log->firmware_source->close(log_handle); return TCSERR(TSS_E_INTERNAL_ERROR); } tcs_event_log->firmware_source->close(log_handle); } else { LogError("No source for externel firmware events was compiled in, but " "the tcsd is configured to use one! (see %s)", tcsd_config_file); return TCSERR(TSS_E_INTERNAL_ERROR); } } else { LogError("PCR index %d not flagged as kernel or firmware controlled.", PcrIndex); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT TCS_GetPcrEventsByPcr_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 PcrIndex, /* in */ UINT32 FirstEvent, /* in */ UINT32 *pEventCount, /* in, out */ TSS_PCR_EVENT **ppEvents) /* out */ { UINT32 lastEventNumber, i, eventIndex; TSS_RESULT result; struct event_wrapper *tmp; if ((result = ctx_verify_context(hContext))) return result; if (PcrIndex >= tpm_metrics.num_pcrs) return TCSERR(TSS_E_BAD_PARAMETER); if (*pEventCount == 0) { *ppEvents = NULL; return TSS_SUCCESS; } /* if this is a kernel or firmware controlled PCR, call an external routine */ if ((tcsd_options.kernel_pcrs & (1 << PcrIndex)) || (tcsd_options.firmware_pcrs & (1 << PcrIndex))) { MUTEX_LOCK(tcs_event_log->lock); result = TCS_GetExternalPcrEventsByPcr(PcrIndex, FirstEvent, pEventCount, ppEvents); MUTEX_UNLOCK(tcs_event_log->lock); return result; } MUTEX_LOCK(tcs_event_log->lock); lastEventNumber = get_num_events(PcrIndex); MUTEX_UNLOCK(tcs_event_log->lock); /* if pEventCount is larger than the number of events to return, just return less. * *pEventCount will be set to the number returned below. First, check for overflow. */ if ((FirstEvent + *pEventCount) >= FirstEvent && (FirstEvent + *pEventCount) >= *pEventCount) lastEventNumber = MIN(lastEventNumber, FirstEvent + *pEventCount); if (FirstEvent > lastEventNumber) return TCSERR(TSS_E_BAD_PARAMETER); if (lastEventNumber == 0) { *pEventCount = 0; *ppEvents = NULL; return TSS_SUCCESS; } /* FirstEvent is 0 indexed see TSS 1.1b spec section 4.7.2.2.3. That means that * the following calculation is not off by one. :-) */ *ppEvents = calloc((lastEventNumber - FirstEvent), sizeof(TSS_PCR_EVENT)); if (*ppEvents == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_PCR_EVENT) * (lastEventNumber - FirstEvent)); return TCSERR(TSS_E_OUTOFMEMORY); } MUTEX_LOCK(tcs_event_log->lock); tmp = tcs_event_log->lists[PcrIndex]; /* move through the list until we get to the first event requested */ for (i = 0; i < FirstEvent; i++) tmp = tmp->next; /* copy events from the first requested to the last requested */ for (eventIndex = 0; i < lastEventNumber; eventIndex++, i++) { copy_pcr_event(&((*ppEvents)[eventIndex]), &(tmp->event)); tmp = tmp->next; } MUTEX_UNLOCK(tcs_event_log->lock); *pEventCount = eventIndex; return TSS_SUCCESS; } TSS_RESULT TCS_GetPcrEventLog_Internal(TCS_CONTEXT_HANDLE hContext,/* in */ UINT32 *pEventCount, /* out */ TSS_PCR_EVENT **ppEvents) /* out */ { TSS_RESULT result; UINT32 i, j, event_count, aggregate_count = 0; struct event_wrapper *tmp; TSS_PCR_EVENT *event_list = NULL, *aggregate_list = NULL; if ((result = ctx_verify_context(hContext))) return result; MUTEX_LOCK(tcs_event_log->lock); /* for each PCR index, if its externally controlled, get the total number of events * externally, else copy the events from the TCSD list. Then tack that list onto a * master list to returned. */ for (i = 0; i < tpm_metrics.num_pcrs; i++) { if ((tcsd_options.kernel_pcrs & (1 << i)) || (tcsd_options.firmware_pcrs & (1 << i))) { /* A kernel or firmware controlled PCR event list */ event_count = UINT_MAX; if ((result = TCS_GetExternalPcrEventsByPcr(i, 0, &event_count, &event_list))) { LogDebug("Getting External event list for PCR %u failed", i); free(aggregate_list); goto error; } LogDebug("Retrieved %u events from PCR %u (external)", event_count, i); } else { /* A TCSD controlled PCR event list */ event_count = get_num_events(i); if (event_count == 0) continue; if ((event_list = calloc(event_count, sizeof(TSS_PCR_EVENT))) == NULL) { LogError("malloc of %zd bytes failed", event_count * sizeof(TSS_PCR_EVENT)); result = TCSERR(TSS_E_OUTOFMEMORY); free(aggregate_list); goto error; } tmp = tcs_event_log->lists[i]; for (j = 0; j < event_count; j++) { copy_pcr_event(&event_list[j], &(tmp->event)); tmp = tmp->next; } } if (event_count == 0) continue; /* Tack the list onto the aggregate_list */ aggregate_list = concat_pcr_events(&aggregate_list, aggregate_count, event_list, event_count); if (aggregate_list == NULL) { free(event_list); result = TCSERR(TSS_E_OUTOFMEMORY); goto error; } aggregate_count += event_count; free(event_list); } *ppEvents = aggregate_list; *pEventCount = aggregate_count; result = TSS_SUCCESS; error: MUTEX_UNLOCK(tcs_event_log->lock); return result; } trousers-0.3.15/src/tcs/tcs_quote.c0000664000175000017510000000431113663651711016505 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #include "tddl.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT UnloadBlob_PCR_SELECTION(UINT64 *offset, BYTE *blob, TCPA_PCR_SELECTION *pcr) { if (!pcr) { UINT16 size; UnloadBlob_UINT16(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); return TSS_SUCCESS; } UnloadBlob_UINT16(offset, &pcr->sizeOfSelect, blob); pcr->pcrSelect = malloc(pcr->sizeOfSelect); if (pcr->pcrSelect == NULL) { LogError("malloc of %hu bytes failed.", pcr->sizeOfSelect); pcr->sizeOfSelect = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, pcr->sizeOfSelect, blob, pcr->pcrSelect); return TSS_SUCCESS; } void LoadBlob_PCR_SELECTION(UINT64 *offset, BYTE * blob, TCPA_PCR_SELECTION pcr) { LoadBlob_UINT16(offset, pcr.sizeOfSelect, blob); LoadBlob(offset, pcr.sizeOfSelect, blob, pcr.pcrSelect); } TSS_RESULT UnloadBlob_PCR_COMPOSITE(UINT64 *offset, BYTE *blob, TCPA_PCR_COMPOSITE *out) { TSS_RESULT rc; if (!out) { UINT32 size; if ((rc = UnloadBlob_PCR_SELECTION(offset, blob, NULL))) return rc; UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); return TSS_SUCCESS; } if ((rc = UnloadBlob_PCR_SELECTION(offset, blob, &out->select))) return rc; UnloadBlob_UINT32(offset, &out->valueSize, blob); out->pcrValue = malloc(out->valueSize); if (out->pcrValue == NULL) { LogError("malloc of %u bytes failed.", out->valueSize); out->valueSize = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, out->valueSize, blob, (BYTE *) out->pcrValue); return TSS_SUCCESS; } trousers-0.3.15/src/tcs/log.c0000664000175000017510000000355313663651711015267 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "tcslog.h" #ifdef TSS_DEBUG /* * LogBlobData() * * Log a blob's data to the debugging stream * * szDescriptor - The APPID tag found in the caller's environment at build time * sizeOfBlob - The size of the data to log * blob - the data to log * */ void LogBlobData(char *szDescriptor, unsigned long sizeOfBlob, unsigned char *blob) { char temp[64]; unsigned int i; if (getenv("TCSD_FOREGROUND") == NULL) openlog(szDescriptor, LOG_NDELAY|LOG_PID, TSS_SYSLOG_LVL); memset(temp, 0, sizeof(temp)); for (i = 0; (unsigned long)i < sizeOfBlob; i++) { if ((i > 0) && ((i % 16) == 0)) { if (getenv("TCSD_FOREGROUND") != NULL) fprintf(stdout, "%s %s\n", szDescriptor, temp); else syslog(LOG_DEBUG, "%s", temp); memset(temp, 0, sizeof(temp)); } snprintf(&temp[(i%16)*3], 4, "%.2X ", blob[i]); } if (i == sizeOfBlob) { if (getenv("TCSD_FOREGROUND") != NULL) fprintf(stdout, "%s %s\n", szDescriptor, temp); else syslog(LOG_DEBUG, "%s", temp); } } void LogTPMERR(TSS_RESULT result, char *file, int line) { if (getenv("TSS_DEBUG_OFF") == NULL) fprintf(stderr, "%s %s %s:%d: 0x%x\n", "LOG_RETERR", "TPM", file, line, result); } TSS_RESULT LogTDDLERR(TSS_RESULT result, char *file, int line) { if (getenv("TSS_DEBUG_OFF") == NULL) fprintf(stderr, "%s %s %s:%d: 0x%x\n", "LOG_RETERR", APPID, file, line, result); return (result | TSS_LAYER_TDDL); } TSS_RESULT LogTCSERR(TSS_RESULT result, char *file, int line) { if (getenv("TSS_DEBUG_OFF") == NULL) fprintf(stderr, "%s %s %s:%d: 0x%x\n", "LOG_RETERR", APPID, file, line, result); return (result | TSS_LAYER_TCS); } #endif trousers-0.3.15/src/tcs/tcs_pbg.c0000664000175000017510000017641213663651711016134 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #define TSS_TPM_RSP_BLOB_AUTH_LEN (sizeof(TPM_NONCE) + sizeof(TPM_DIGEST) + sizeof(TPM_BOOL)) TSS_RESULT tpm_rsp_parse(TPM_COMMAND_CODE ordinal, BYTE *b, UINT32 len, ...) { TSS_RESULT result = TSS_SUCCESS; UINT64 offset1, offset2; va_list ap; DBG_ASSERT(ordinal); DBG_ASSERT(b); va_start(ap, len); switch (ordinal) { case TPM_ORD_ExecuteTransport: { UINT32 *val1 = va_arg(ap, UINT32 *); UINT32 *val2 = va_arg(ap, UINT32 *); UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (auth1 && auth2) { offset1 = offset2 = len - (2 * TSS_TPM_RSP_BLOB_AUTH_LEN); UnloadBlob_Auth(&offset1, b, auth1); UnloadBlob_Auth(&offset1, b, auth2); } else if (auth1) { offset1 = offset2 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } else if (auth2) { offset1 = offset2 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth2); } else offset2 = len; offset1 = TSS_TPM_TXBLOB_HDR_LEN; if (val1) UnloadBlob_UINT32(&offset1, val1, b); if (val2) UnloadBlob_UINT32(&offset1, val2, b); *len1 = offset2 - offset1; if (*len1) { if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); } else *blob1 = NULL; break; } #ifdef TSS_BUILD_TICK /* TPM BLOB: TPM_CURRENT_TICKS, UINT32, BLOB, optional AUTH */ case TPM_ORD_TickStampBlob: { UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); UINT32 *len2 = va_arg(ap, UINT32 *); BYTE **blob2 = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!len1 || !blob1 || !len2 || !blob2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } offset1 = offset2 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_CURRENT_TICKS(&offset2, b, NULL); *len1 = (UINT32)offset2 - offset1; if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); UnloadBlob_UINT32(&offset1, len2, b); if ((*blob2 = malloc(*len2)) == NULL) { LogError("malloc of %u bytes failed", *len2); free(*blob1); *blob1 = NULL; *len1 = 0; *len2 = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len2, b, *blob2); break; } #endif #ifdef TSS_BUILD_QUOTE /* TPM BLOB: TPM_PCR_COMPOSITE, UINT32, BLOB, 1 optional AUTH * return UINT32*, BYTE**, UINT32*, BYTE**, 1 optional AUTH */ case TPM_ORD_Quote: { UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); UINT32 *len2 = va_arg(ap, UINT32 *); BYTE **blob2 = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!len1 || !blob1 || !len2 || !blob2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } offset1 = offset2 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_PCR_COMPOSITE(&offset2, b, NULL); *len1 = offset2 - offset1; if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); UnloadBlob_UINT32(&offset1, len2, b); if ((*blob2 = malloc(*len2)) == NULL) { LogError("malloc of %u bytes failed", *len2); free(*blob1); *blob1 = NULL; *len1 = 0; *len2 = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len2, b, *blob2); break; } #endif #ifdef TSS_BUILD_TSS12 /* TPM BLOB: TPM_PCR_INFO_SHORT, (UINT32, BLOB,) UINT32, BLOB, 1 optional AUTH */ case TPM_ORD_Quote2: { UINT32 *len1 = va_arg(ap, UINT32 *); /* pcrDataSizeOut */ BYTE **blob1 = va_arg(ap, BYTE **); /* pcrDataOut */ TSS_BOOL *addVersion = va_arg(ap, TSS_BOOL *); /* addVersion */ UINT32 *len2 = va_arg(ap, UINT32 *); /* versionInfoSize */ BYTE **blob2 = va_arg(ap, BYTE **); /* versionInfo */ UINT32 *len3 = va_arg(ap, UINT32 *); /* sigSize */ BYTE **blob3 = va_arg(ap, BYTE **); /* sig */ TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); /* privAuth */ va_end(ap); if (!len1 || !blob1 || !len2 || !blob2 || !len3 || !blob3 || !addVersion) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } offset1 = offset2 = TSS_TPM_TXBLOB_HDR_LEN; /* Adjust the offset to take the TPM_PCR_INFO_SHORT size: * need to allocate this size into blob1 */ UnloadBlob_PCR_INFO_SHORT(&offset2, b, NULL); /* Get the size of the TSS_TPM_INFO_SHORT * and copy it into blob1 */ *len1 = offset2 - offset1; LogDebugFn("QUOTE2 Core: PCR_INFO_SHORT is %u size", *len1); if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); /* TPM_PCR_INFO_SHORT */ UnloadBlob_UINT32(&offset1, len2,b); /* versionInfoSize */ LogDebugFn("QUOTE2 Core: versionInfoSize=%u", *len2); if ((*blob2 = malloc(*len2)) == NULL) { LogError("malloc of %u bytes failed", *len2); free(*blob1); *blob1 = NULL; *len1 = 0; *len2 = 0; *len3 = 0; *blob3 = NULL; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len2, b, *blob2); /* Take the sigSize */ UnloadBlob_UINT32(&offset1, len3, b); LogDebugFn("QUOTE2 Core: sigSize=%u", *len3); /* sig */ if ((*blob3 = malloc(*len3)) == NULL) { LogError("malloc of %u bytes failed", *len3); free(*blob1); *blob1 = NULL; if (*len2 > 0){ free(*blob2); *blob2 = NULL; } *len1 = 0; *len2 = 0; *len3 = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len3, b, *blob3); break; } #endif /* TPM BLOB: TPM_CERTIFY_INFO, UINT32, BLOB, 2 optional AUTHs * return UINT32*, BYTE**, UINT32*, BYTE**, 2 optional AUTHs */ case TPM_ORD_CertifyKey: { UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); UINT32 *len2 = va_arg(ap, UINT32 *); BYTE **blob2 = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!len1 || !blob1 || !len2 || !blob2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1 && auth2) { offset1 = len - (2 * TSS_TPM_RSP_BLOB_AUTH_LEN); UnloadBlob_Auth(&offset1, b, auth1); UnloadBlob_Auth(&offset1, b, auth2); } else if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } else if (auth2) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth2); } offset1 = offset2 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_CERTIFY_INFO(&offset2, b, NULL); *len1 = offset2 - offset1; if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); UnloadBlob_UINT32(&offset1, len2, b); if ((*blob2 = malloc(*len2)) == NULL) { LogError("malloc of %u bytes failed", *len2); free(*blob1); *blob1 = NULL; *len1 = 0; *len2 = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len2, b, *blob2); break; } #ifdef TSS_BUILD_AUDIT /* TPM_BLOB: TPM_COUNTER_VALUE, DIGEST, DIGEST, UINT32, BLOB, optional AUTH * return: UINT32*, BYTE**, DIGEST*, DIGEST*, UINT32*, BYTE**, optional AUTH */ case TPM_ORD_GetAuditDigestSigned: { UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); TPM_DIGEST *digest1 = va_arg(ap, TPM_DIGEST *); TPM_DIGEST *digest2 = va_arg(ap, TPM_DIGEST *); UINT32 *len2 = va_arg(ap, UINT32 *); BYTE **blob2 = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1 || !digest2 || !len1 || !blob1 || !len2 || !blob2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } offset1 = offset2 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_COUNTER_VALUE(&offset2, b, NULL); *len1 = offset2 - offset1; if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); UnloadBlob_DIGEST(&offset1, b, digest1); UnloadBlob_DIGEST(&offset1, b, digest2); UnloadBlob_UINT32(&offset1, len2, b); if ((*blob2 = malloc(*len2)) == NULL) { LogError("malloc of %u bytes failed", *len2); free(*blob1); *blob1 = NULL; *len1 = 0; *len2 = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len2, b, *blob2); if (auth1) UnloadBlob_Auth(&offset1, b, auth1); break; } /* TPM_BLOB: TPM_COUNTER_VALUE, DIGEST, BOOL, UINT32, BLOB * return: DIGEST*, UINT32*, BYTE**, BOOL, UINT32*, BYTE** */ case TPM_ORD_GetAuditDigest: { TPM_DIGEST *digest1 = va_arg(ap, TPM_DIGEST *); UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); TSS_BOOL *bool1 = va_arg(ap, TSS_BOOL *); UINT32 *len2 = va_arg(ap, UINT32 *); BYTE **blob2 = va_arg(ap, BYTE **); va_end(ap); if (!digest1 || !len1 || !blob1 || !len2 || !blob2 || !bool1) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } offset1 = offset2 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_COUNTER_VALUE(&offset2, b, NULL); *len1 = offset2 - offset1; if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); UnloadBlob_DIGEST(&offset1, b, digest1); UnloadBlob_BOOL(&offset1, bool1, b); UnloadBlob_UINT32(&offset1, len2, b); if ((*blob2 = malloc(*len2)) == NULL) { LogError("malloc of %u bytes failed", *len2); free(*blob1); *blob1 = NULL; *len1 = 0; *len2 = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len2, b, *blob2); break; } #endif #ifdef TSS_BUILD_COUNTER /* optional UINT32, TPM_COUNTER_VALUE, optional AUTH */ case TPM_ORD_ReadCounter: case TPM_ORD_CreateCounter: case TPM_ORD_IncrementCounter: { UINT32 *val1 = va_arg(ap, UINT32 *); TPM_COUNTER_VALUE *ctr = va_arg(ap, TPM_COUNTER_VALUE *); TPM_AUTH * auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!ctr) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; if (val1) UnloadBlob_UINT32(&offset1, val1, b); UnloadBlob_COUNTER_VALUE(&offset1, b, ctr); break; } #endif /* TPM BLOB: UINT32, BLOB, UINT32, BLOB, optional AUTH, optional AUTH */ case TPM_ORD_CreateMaintenanceArchive: case TPM_ORD_CreateMigrationBlob: case TPM_ORD_Delegate_ReadTable: case TPM_ORD_CMK_CreateBlob: { UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); UINT32 *len2 = va_arg(ap, UINT32 *); BYTE **blob2 = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!len1 || !blob1 || !len2 || !blob2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1 && auth2) { offset1 = len - (2 * TSS_TPM_RSP_BLOB_AUTH_LEN); UnloadBlob_Auth(&offset1, b, auth1); UnloadBlob_Auth(&offset1, b, auth2); } else if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } else if (auth2) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth2); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT32(&offset1, len1, b); if ((*blob1 = malloc(*len1)) == NULL) { LogError("malloc of %u bytes failed", *len1); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len1, b, *blob1); UnloadBlob_UINT32(&offset1, len2, b); if ((*blob2 = malloc(*len2)) == NULL) { free(*blob1); LogError("malloc of %u bytes failed", *len2); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *len2, b, *blob2); break; } /* TPM BLOB: BLOB, optional AUTH, AUTH * return: UINT32 *, BYTE **, optional AUTH, AUTH */ case TPM_ORD_ActivateIdentity: { UINT32 *len1 = va_arg(ap, UINT32 *); BYTE **blob1 = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!len1 || !blob1 || !auth2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1 && auth2) { offset1 = offset2 = len - (2 * TSS_TPM_RSP_BLOB_AUTH_LEN); UnloadBlob_Auth(&offset1, b, auth1); UnloadBlob_Auth(&offset1, b, auth2); } else if (auth2) { offset1 = offset2 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth2); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; offset2 -= TSS_TPM_TXBLOB_HDR_LEN; if ((*blob1 = malloc(offset2)) == NULL) { LogError("malloc of %zd bytes failed", (size_t)offset2); return TCSERR(TSS_E_OUTOFMEMORY); } *len1 = offset2; UnloadBlob(&offset1, *len1, b, *blob1); break; } /* TPM BLOB: TPM_KEY, UINT32, BLOB, optional AUTH, AUTH * return: UINT32 *, BYTE **, UINT32 *, BYTE **, optional AUTH, AUTH */ case TPM_ORD_MakeIdentity: { UINT32 *len1, *len2; BYTE **blob1, **blob2; TPM_AUTH *auth1, *auth2; len1 = va_arg(ap, UINT32 *); blob1 = va_arg(ap, BYTE **); len2 = va_arg(ap, UINT32 *); blob2 = va_arg(ap, BYTE **); auth1 = va_arg(ap, TPM_AUTH *); auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!len1 || !blob1 || !len2 || !blob2 || !auth2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } offset1 = offset2 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_TSS_KEY(&offset1, b, NULL); offset1 -= TSS_TPM_TXBLOB_HDR_LEN; if ((*blob1 = malloc(offset1)) == NULL) { LogError("malloc of %zd bytes failed", (size_t)offset1); return TCSERR(TSS_E_OUTOFMEMORY); } *len1 = offset1; UnloadBlob(&offset2, offset1, b, *blob1); /* offset2 points to the stuff after the key */ UnloadBlob_UINT32(&offset2, len2, b); if ((*blob2 = malloc(*len2)) == NULL) { free(*blob1); LogError("malloc of %u bytes failed", *len2); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset2, *len2, b, *blob2); if (auth1) UnloadBlob_Auth(&offset2, b, auth1); UnloadBlob_Auth(&offset2, b, auth2); break; } /* 1 TPM_VERSION, 2 UINT32s, 1 optional AUTH */ case TPM_ORD_GetCapabilityOwner: { TPM_VERSION *ver1 = va_arg(ap, TPM_VERSION *); UINT32 *data1 = va_arg(ap, UINT32 *); UINT32 *data2 = va_arg(ap, UINT32 *); TPM_AUTH *auth = va_arg(ap, TPM_AUTH *); va_end(ap); if (!data1 || !data2 || !ver1) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_VERSION(&offset1, b, ver1); UnloadBlob_UINT32(&offset1, data1, b); UnloadBlob_UINT32(&offset1, data2, b); break; } /* TPM BLOB: 1 UINT32, 1 BLOB, 2 optional AUTHs * return: UINT32 *, BYTE**, 2 optional AUTHs */ case TPM_ORD_Sign: case TPM_ORD_GetTestResult: case TPM_ORD_CertifySelfTest: case TPM_ORD_Unseal: case TPM_ORD_GetRandom: case TPM_ORD_DAA_Join: case TPM_ORD_DAA_Sign: case TPM_ORD_ChangeAuth: case TPM_ORD_GetCapability: case TPM_ORD_LoadMaintenanceArchive: case TPM_ORD_ConvertMigrationBlob: case TPM_ORD_NV_ReadValue: case TPM_ORD_NV_ReadValueAuth: case TPM_ORD_Delegate_Manage: case TPM_ORD_Delegate_CreateKeyDelegation: case TPM_ORD_Delegate_CreateOwnerDelegation: case TPM_ORD_Delegate_UpdateVerification: case TPM_ORD_CMK_ConvertMigration: { UINT32 *data_len = va_arg(ap, UINT32 *); BYTE **data = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!data || !data_len) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1 && auth2) { offset1 = len - (2 * TSS_TPM_RSP_BLOB_AUTH_LEN); UnloadBlob_Auth(&offset1, b, auth1); UnloadBlob_Auth(&offset1, b, auth2); } else if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } else if (auth2) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth2); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT32(&offset1, data_len, b); if ((*data = malloc(*data_len)) == NULL) { LogError("malloc of %u bytes failed", *data_len); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *data_len, b, *data); break; } /* TPM BLOB: 1 UINT32, 1 BLOB, 1 optional AUTH * return: UINT32 *, BYTE**, 1 optional AUTH*/ case TPM_ORD_UnBind: { UINT32 *data_len = va_arg(ap, UINT32 *); BYTE **data = va_arg(ap, BYTE **); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!data || !data_len) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth1) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth1); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT32(&offset1, data_len, b); if ((*data = malloc(*data_len)) == NULL) { LogError("malloc of %u bytes failed", *data_len); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, *data_len, b, *data); break; } /* TPM BLOB: 1 BLOB, 1 optional AUTH * return: UINT32 *, BYTE**, 1 optional AUTH*/ case TPM_ORD_GetTicks: case TPM_ORD_Seal: case TPM_ORD_Sealx: case TPM_ORD_FieldUpgrade: case TPM_ORD_CreateWrapKey: case TPM_ORD_GetPubKey: case TPM_ORD_OwnerReadPubek: case TPM_ORD_OwnerReadInternalPub: case TPM_ORD_AuthorizeMigrationKey: case TPM_ORD_TakeOwnership: case TPM_ORD_CMK_CreateKey: { UINT32 *data_len = va_arg(ap, UINT32 *); BYTE **data = va_arg(ap, BYTE **); TPM_AUTH *auth = va_arg(ap, TPM_AUTH *); va_end(ap); if (!data || !data_len) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } /* remove the auth data from the back end of the data */ if (auth) { offset1 = offset2 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth); } else offset2 = len; /* everything after the header is returned as the blob */ offset1 = TSS_TPM_TXBLOB_HDR_LEN; offset2 -= offset1; if ((*data = malloc((size_t)offset2)) == NULL) { LogError("malloc of %zd bytes failed", (size_t)offset2); return TCSERR(TSS_E_OUTOFMEMORY); } if ((offset1 + offset2) > TSS_TPM_TXBLOB_SIZE) return TCSERR(TSS_E_INTERNAL_ERROR); memcpy(*data, &b[offset1], offset2); *data_len = offset2; break; } /* TPM BLOB: TPM_PUBKEY, optional DIGEST */ case TPM_ORD_CreateEndorsementKeyPair: case TPM_ORD_ReadPubek: { UINT32 *data_len = va_arg(ap, UINT32 *); BYTE **data = va_arg(ap, BYTE **); BYTE *digest1 = va_arg(ap, BYTE *); va_end(ap); if (!data || !data_len) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (digest1) { offset1 = offset2 = len - TPM_DIGEST_SIZE; memcpy(digest1, &b[offset2], TPM_DIGEST_SIZE); if ((offset2 + TPM_DIGEST_SIZE) > TSS_TPM_TXBLOB_SIZE) return TCSERR(TSS_E_INTERNAL_ERROR); } else { offset2 = len; if (offset2 > TSS_TPM_TXBLOB_SIZE) return TCSERR(TSS_E_INTERNAL_ERROR); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; offset2 -= offset1; if ((*data = malloc((size_t)offset2)) == NULL) { LogError("malloc of %zd bytes failed", (size_t)offset2); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, offset2, b, *data); *data_len = offset2; break; } #ifdef TSS_BUILD_TSS12 /* TPM BLOB: BLOB, DIGEST, DIGEST * return: UINT32 *, BYTE**, DIGEST, DIGEST */ case TPM_ORD_CreateRevocableEK: { UINT32 *data_len = va_arg(ap, UINT32 *); BYTE **data = va_arg(ap, BYTE **); BYTE *digest1 = va_arg(ap, BYTE *); BYTE *digest2 = va_arg(ap, BYTE *); va_end(ap); if (!data || !data_len || !digest1 || !digest2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (len > TSS_TPM_TXBLOB_SIZE) return TCSERR(TSS_E_INTERNAL_ERROR); offset2 = len - TPM_DIGEST_SIZE; memcpy(digest2, &b[offset2], TPM_DIGEST_SIZE); offset2 -= TPM_DIGEST_SIZE; memcpy(digest1, &b[offset2], TPM_DIGEST_SIZE); offset1 = TSS_TPM_TXBLOB_HDR_LEN; offset2 -= offset1; if ((*data = malloc((size_t)offset2)) == NULL) { LogError("malloc of %zd bytes failed", (size_t)offset2); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset1, offset2, b, *data); *data_len = offset2; break; } #endif /* 1 UINT32, 1 optional AUTH */ case TPM_ORD_LoadKey: case TPM_ORD_LoadKey2: { UINT32 *handle; TPM_AUTH *auth; handle = va_arg(ap, UINT32 *); auth = va_arg(ap, TPM_AUTH *); va_end(ap); if (!handle) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } if (auth) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT32(&offset1, handle, b); break; } /* 1 optional UINT32, 1 20 byte value */ case TPM_ORD_DirRead: case TPM_ORD_OIAP: case TPM_ORD_LoadManuMaintPub: case TPM_ORD_ReadManuMaintPub: case TPM_ORD_Extend: case TPM_ORD_PcrRead: { UINT32 *handle = va_arg(ap, UINT32 *); BYTE *nonce = va_arg(ap, BYTE *); va_end(ap); if (!nonce) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; if (handle) UnloadBlob_UINT32(&offset1, handle, b); UnloadBlob(&offset1, TPM_NONCE_SIZE, b, nonce); break; } /* 1 UINT32, 2 20 byte values */ case TPM_ORD_OSAP: case TPM_ORD_DSAP: { UINT32 *handle = va_arg(ap, UINT32 *); BYTE *nonce1 = va_arg(ap, BYTE *); BYTE *nonce2 = va_arg(ap, BYTE *); va_end(ap); if (!handle || !nonce1 || !nonce2) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT32(&offset1, handle, b); UnloadBlob(&offset1, TPM_NONCE_SIZE, b, nonce1); UnloadBlob(&offset1, TPM_NONCE_SIZE, b, nonce2); break; } #ifdef TSS_BUILD_CMK /* 1 20 byte value, 1 optional AUTH */ case TPM_ORD_CMK_ApproveMA: case TPM_ORD_CMK_CreateTicket: { BYTE *hmac1 = va_arg(ap, BYTE *); TPM_AUTH *auth = va_arg(ap, TPM_AUTH *); va_end(ap); if (!hmac1) { LogError("Internal error for ordinal 0x%x", ordinal); return TCSERR(TSS_E_INTERNAL_ERROR); } offset1 = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob(&offset1, TPM_SHA1_160_HASH_LEN, b, hmac1); if (auth) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth); } break; } #endif /* 1 optional AUTH */ case TPM_ORD_DisablePubekRead: case TPM_ORD_DirWriteAuth: case TPM_ORD_ReleaseCounter: case TPM_ORD_ReleaseCounterOwner: case TPM_ORD_ChangeAuthOwner: case TPM_ORD_SetCapability: case TPM_ORD_SetOrdinalAuditStatus: case TPM_ORD_ResetLockValue: case TPM_ORD_SetRedirection: case TPM_ORD_DisableOwnerClear: case TPM_ORD_OwnerSetDisable: case TPM_ORD_SetTempDeactivated: case TPM_ORD_KillMaintenanceFeature: case TPM_ORD_NV_DefineSpace: case TPM_ORD_NV_WriteValue: case TPM_ORD_NV_WriteValueAuth: case TPM_ORD_OwnerClear: case TPM_ORD_Delegate_LoadOwnerDelegation: case TPM_ORD_CMK_SetRestrictions: case TPM_ORD_FlushSpecific: case TPM_ORD_KeyControlOwner: { TPM_AUTH *auth = va_arg(ap, TPM_AUTH *); va_end(ap); if (auth) { offset1 = len - TSS_TPM_RSP_BLOB_AUTH_LEN; UnloadBlob_Auth(&offset1, b, auth); } break; } default: LogError("Unknown ordinal: 0x%x", ordinal); result = TCSERR(TSS_E_INTERNAL_ERROR); va_end(ap); break; } return result; } /* XXX optimize these cases by always passing in lengths for blobs, no more "20 byte values" */ TSS_RESULT tpm_rqu_build(TPM_COMMAND_CODE ordinal, UINT64 *outOffset, BYTE *out_blob, ...) { TSS_RESULT result = TSS_SUCCESS; UINT64 blob_size; va_list ap; DBG_ASSERT(ordinal); DBG_ASSERT(outOffset); DBG_ASSERT(out_blob); va_start(ap, out_blob); switch (ordinal) { #ifdef TSS_BUILD_DELEGATION /* 1 UINT16, 1 UINT32, 1 20 bytes value, 1 UINT32, 1 BLOB */ case TPM_ORD_DSAP: { UINT16 val1 = va_arg(ap, int); UINT32 handle1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); va_end(ap); if (!digest1 || !in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT16(outOffset, val1, out_blob); LoadBlob_UINT32(outOffset, handle1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } /* 1 BOOL, 1 UINT32, 1 BLOB, 1 20 byte value, 1 AUTH */ case TPM_ORD_Delegate_CreateOwnerDelegation: { TSS_BOOL bool1 = va_arg(ap, int); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); BYTE *digest1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!in_len1 || !in_blob1 || !digest1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_BOOL(outOffset, bool1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } /* 2 UINT32's, 1 BLOB, 1 20 byte value, 1 AUTH */ case TPM_ORD_Delegate_CreateKeyDelegation: { UINT32 keyslot1 = va_arg(ap, UINT32); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); BYTE *digest1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keyslot1 || !in_len1 || !in_blob1 || !digest1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keyslot1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } #endif #ifdef TSS_BUILD_TRANSPORT /* 3 UINT32's, 1 BLOB, 2 AUTHs */ case TPM_ORD_ExecuteTransport: { UINT32 ord1 = va_arg(ap, UINT32); UINT32 *keyslot1 = va_arg(ap, UINT32 *); UINT32 *keyslot2 = va_arg(ap, UINT32 *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; if (keyslot1) LoadBlob_UINT32(outOffset, *keyslot1, out_blob); if (keyslot2) LoadBlob_UINT32(outOffset, *keyslot2, out_blob); //LoadBlob_UINT32(outOffset, in_len1, out_blob); if (in_blob1) LoadBlob(outOffset, in_len1, out_blob, in_blob1); if (auth1 && auth2) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, *outOffset, ord1, out_blob); } else if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ord1, out_blob); } else if (auth2) { LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ord1, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ord1, out_blob); } break; } #endif /* 1 UINT32, 1 UINT16, 1 BLOB, 1 UINT32, 1 BLOB, 1 options AUTH, 1 AUTH */ case TPM_ORD_CreateMigrationBlob: { UINT32 keyslot1 = va_arg(ap, UINT32); UINT16 type1 = va_arg(ap, int); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!in_blob1 || !in_blob2 || !auth2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keyslot1, out_blob); LoadBlob_UINT16(outOffset, type1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 UINT32, 1 UINT16, 1 20 byte value, 1 UINT16, 1 UINT32, 1 BLOB, 2 AUTHs */ case TPM_ORD_ChangeAuth: { UINT32 keyslot1 = va_arg(ap, UINT32); UINT16 proto1 = va_arg(ap, int); BYTE *digest1 = va_arg(ap, BYTE *); UINT16 entity1 = va_arg(ap, int); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1 || !in_blob1 || !auth1 || !auth2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keyslot1, out_blob); LoadBlob_UINT16(outOffset, proto1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_UINT16(outOffset, entity1, out_blob); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, *outOffset, ordinal, out_blob); break; } /* 2 DIGEST/ENCAUTH's, 1 UINT32, 1 BLOB, 1 optional AUTH, 1 AUTH */ case TPM_ORD_MakeIdentity: { BYTE *dig1, *dig2, *blob1; UINT32 len1; TPM_AUTH *auth1, *auth2; dig1 = va_arg(ap, BYTE *); dig2 = va_arg(ap, BYTE *); len1 = va_arg(ap, UINT32); blob1 = va_arg(ap, BYTE *); auth1 = va_arg(ap, TPM_AUTH *); auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!dig1 || !dig2 || !blob1 || !auth2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, dig1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, dig2); LoadBlob(outOffset, len1, out_blob, blob1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } break; } #if (TSS_BUILD_NV || TSS_BUILD_DELEGATION) /* 3 UINT32's, 1 BLOB, 1 optional AUTH */ case TPM_ORD_NV_WriteValue: case TPM_ORD_NV_WriteValueAuth: case TPM_ORD_Delegate_Manage: { UINT32 i = va_arg(ap, UINT32); UINT32 j = va_arg(ap, UINT32); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, i, out_blob); LoadBlob_UINT32(outOffset, j, out_blob); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } #endif /* 3 UINT32's, 1 optional AUTH */ case TPM_ORD_NV_ReadValue: case TPM_ORD_NV_ReadValueAuth: case TPM_ORD_SetRedirection: { UINT32 i = va_arg(ap, UINT32); UINT32 j = va_arg(ap, UINT32); UINT32 k = va_arg(ap, UINT32); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, i, out_blob); LoadBlob_UINT32(outOffset, j, out_blob); LoadBlob_UINT32(outOffset, k, out_blob); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 20 byte value, 1 UINT32, 1 BLOB */ case TPM_ORD_CreateEndorsementKeyPair: { BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); va_end(ap); if (!digest1 || !in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } #ifdef TSS_BUILD_TSS12 /* 1 20 byte value, 1 UINT32, 1 BLOB, 1 BOOL, 1 20 byte value */ case TPM_ORD_CreateRevocableEK: { BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TSS_BOOL in_bool1 = va_arg(ap, int); BYTE *digest2 = va_arg(ap, BYTE *); va_end(ap); if (!digest1 || !in_blob1 || !digest2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_BOOL(outOffset, in_bool1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest2); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } /* 1 20 byte value */ case TPM_ORD_RevokeTrust: { BYTE *digest1 = va_arg(ap, BYTE *); va_end(ap); if (!digest1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } #endif #ifdef TSS_BUILD_COUNTER /* 1 20 byte value, 1 UINT32, 1 BLOB, 1 AUTH */ case TPM_ORD_CreateCounter: { BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1 || !in_blob1 || !auth1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } #endif #ifdef TSS_BUILD_DAA /* 1 UINT32, 1 BYTE, 1 UINT32, 1 BLOB, 1 UINT32, 1 BLOB, 1 AUTH */ case TPM_ORD_DAA_Sign: case TPM_ORD_DAA_Join: { UINT32 keySlot1 = va_arg(ap, UINT32); BYTE stage1 = va_arg(ap, int); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !in_blob1 || !auth1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob_BOOL(outOffset, stage1, out_blob); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } #endif /* 2 UINT32's, 1 BLOB, 1 UINT32, 1 BLOB, 1 optional AUTH */ case TPM_ORD_ConvertMigrationBlob: case TPM_ORD_SetCapability: { UINT32 keySlot1 = va_arg(ap, UINT32); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !in_blob1 || !in_blob2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 2 UINT32's, 1 20 byte value, 2 optional AUTHs */ case TPM_ORD_CertifyKey: { UINT32 keySlot1 = va_arg(ap, UINT32); UINT32 keySlot2 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !keySlot2 || !digest1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob_UINT32(outOffset, keySlot2, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); if (auth1 && auth2) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, *outOffset, ordinal, out_blob); } else if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else if (auth2) { LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 2 UINT32's, 1 BLOB, 1 optional AUTH */ case TPM_ORD_Delegate_LoadOwnerDelegation: case TPM_ORD_GetCapability: case TPM_ORD_UnBind: case TPM_ORD_Sign: { UINT32 keySlot1 = va_arg(ap, UINT32); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (in_len1 && !in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob_UINT32(outOffset, in_len1, out_blob); if (in_len1) LoadBlob(outOffset, in_len1, out_blob, in_blob1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 UINT32, 1 20 byte value, 1 UINT32, 1 optional BLOB, 1 UINT32, 1 BLOB, 1 AUTH */ case TPM_ORD_Seal: case TPM_ORD_Sealx: { UINT32 keySlot1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); blob_size = in_len1 + in_len2 + TPM_DIGEST_SIZE + sizeof(TPM_AUTH); if (blob_size > TSS_TPM_TXBLOB_SIZE) { result = TCSERR(TSS_E_BAD_PARAMETER); LogError("Oversized input when building ordinal 0x%x", ordinal); break; } if (!keySlot1 || !in_blob2 || !auth1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } /* 2 UINT32's, 1 BLOB, 1 optional AUTH, 1 AUTH */ case TPM_ORD_ActivateIdentity: { UINT32 keySlot1 = va_arg(ap, UINT32); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !in_blob1 || !auth2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 UINT32, 1 20-byte blob, 1 BLOB, 1 optional AUTH */ case TPM_ORD_Quote: { UINT32 keySlot1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !digest1 || !in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, in_len1, out_blob, in_blob1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } #ifdef TSS_BUILD_TSS12 /* 1 UINT32, 1 20-byte blob, 1 BLOB, 1 BOOL, 1 optional AUTH */ case TPM_ORD_Quote2: { /* Input vars */ UINT32 keySlot1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TSS_BOOL* addVersion = va_arg(ap,TSS_BOOL *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !digest1 || !in_blob1 || !addVersion) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, in_len1, out_blob, in_blob1); /* Load the addVersion Bool */ LoadBlob_BOOL(outOffset,*addVersion,out_blob); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } #endif /* 1 UINT32, 2 20-byte blobs, 1 BLOB, 1 optional AUTH */ case TPM_ORD_CreateWrapKey: { UINT32 keySlot1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); BYTE *digest2 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !digest1 || !digest2 || !in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest2); LoadBlob(outOffset, in_len1, out_blob, in_blob1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } /* 2 BLOBs, 1 optional AUTH */ case TPM_ORD_NV_DefineSpace: case TPM_ORD_LoadManuMaintPub: { UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!in_blob1 || !in_blob2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob(outOffset, in_len2, out_blob, in_blob2); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } #ifdef TSS_BUILD_TICK /* 1 UINT32, 2 20-byte blobs, 1 optional AUTH */ case TPM_ORD_TickStampBlob: { UINT32 keySlot1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); BYTE *digest2 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!keySlot1 || !digest1 || !digest2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keySlot1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest2); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } #endif /* 1 BLOB */ case TPM_ORD_ReadManuMaintPub: case TPM_ORD_ReadPubek: case TPM_ORD_PCR_Reset: case TPM_ORD_SetOperatorAuth: { UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); va_end(ap); if (!in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } /* 1 UINT32, 1 BLOB, 2 optional AUTHs */ case TPM_ORD_LoadKey: case TPM_ORD_LoadKey2: case TPM_ORD_DirWriteAuth: case TPM_ORD_CertifySelfTest: case TPM_ORD_Unseal: case TPM_ORD_Extend: case TPM_ORD_StirRandom: case TPM_ORD_LoadMaintenanceArchive: /* XXX */ case TPM_ORD_FieldUpgrade: case TPM_ORD_Delegate_UpdateVerification: case TPM_ORD_Delegate_VerifyDelegation: { UINT32 val1 = va_arg(ap, UINT32); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); TPM_AUTH *auth2 = va_arg(ap, TPM_AUTH *); va_end(ap); if (in_len1 && !in_blob1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, val1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); if (auth1 && auth2) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, *outOffset, ordinal, out_blob); } else if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else if (auth2) { LoadBlob_Auth(outOffset, out_blob, auth2); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 UINT16, 1 BLOB, 1 AUTH */ case TPM_ORD_AuthorizeMigrationKey: { UINT16 scheme1 = va_arg(ap, int); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!in_blob1 || !auth1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT16(outOffset, scheme1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } /* 1 UINT16, 1 UINT32, 1 BLOB, 1 UINT32, 2 BLOBs, 1 AUTH */ case TPM_ORD_TakeOwnership: { UINT16 scheme1 = va_arg(ap, int); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); UINT32 in_len3 = va_arg(ap, UINT32); BYTE *in_blob3 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!in_blob1 || !in_blob2 || !in_blob3 || !auth1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT16(outOffset, scheme1, out_blob); LoadBlob_UINT32(outOffset, in_len1, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); LoadBlob(outOffset, in_len3, out_blob, in_blob3); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } #ifdef TSS_BUILD_AUDIT /* 1 UINT32, 1 BOOL, 1 20 byte value, 1 optional AUTH */ case TPM_ORD_GetAuditDigestSigned: { UINT32 keyslot1 = va_arg(ap, UINT32); TSS_BOOL bool1 = va_arg(ap, int); BYTE *digest1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, keyslot1, out_blob); LoadBlob_BOOL(outOffset, bool1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } #endif /* 1 UINT16, 1 UINT32, 1 20 byte value */ case TPM_ORD_OSAP: { UINT16 type1 = va_arg(ap, int); UINT32 value1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); va_end(ap); if (!digest1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT16(outOffset, type1, out_blob); LoadBlob_UINT32(outOffset, value1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } /* 1 UINT16, 1 20 byte value, 1 UINT16, 1 AUTH */ case TPM_ORD_ChangeAuthOwner: { UINT16 type1 = va_arg(ap, int); BYTE *digest1 = va_arg(ap, BYTE *); UINT16 type2 = va_arg(ap, int); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1 || !auth1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT16(outOffset, type1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_UINT16(outOffset, type2, out_blob); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } #ifdef TSS_BUILD_AUDIT /* 1 UINT32, 1 BOOL, 1 AUTH */ case TPM_ORD_SetOrdinalAuditStatus: { UINT32 ord1 = va_arg(ap, UINT32); TSS_BOOL bool1 = va_arg(ap, int); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!auth1) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, ord1, out_blob); LoadBlob_BOOL(outOffset, bool1, out_blob); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } #endif /* 1 BOOL, 1 optional AUTH */ case TPM_ORD_OwnerSetDisable: case TPM_ORD_PhysicalSetDeactivated: case TPM_ORD_CreateMaintenanceArchive: case TPM_ORD_SetOwnerInstall: { TSS_BOOL bool1 = va_arg(ap, int); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_BOOL(outOffset, bool1, out_blob); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 optional AUTH */ case TPM_ORD_OwnerClear: case TPM_ORD_DisablePubekRead: case TPM_ORD_GetCapabilityOwner: case TPM_ORD_ResetLockValue: case TPM_ORD_DisableOwnerClear: case TPM_ORD_SetTempDeactivated: case TPM_ORD_OIAP: case TPM_ORD_OwnerReadPubek: case TPM_ORD_SelfTestFull: case TPM_ORD_GetTicks: case TPM_ORD_GetTestResult: case TPM_ORD_KillMaintenanceFeature: case TPM_ORD_Delegate_ReadTable: case TPM_ORD_PhysicalEnable: case TPM_ORD_DisableForceClear: case TPM_ORD_ForceClear: { TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 UINT32, 1 optional AUTH */ case TPM_ORD_OwnerReadInternalPub: case TPM_ORD_GetPubKey: case TPM_ORD_ReleaseCounterOwner: case TPM_ORD_ReleaseCounter: case TPM_ORD_IncrementCounter: case TPM_ORD_PcrRead: case TPM_ORD_DirRead: case TPM_ORD_ReadCounter: case TPM_ORD_Terminate_Handle: case TPM_ORD_GetAuditDigest: case TPM_ORD_GetRandom: case TPM_ORD_CMK_SetRestrictions: { UINT32 i = va_arg(ap, UINT32); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, i, out_blob); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } #ifdef TSS_BUILD_CMK /* 1 20 byte value, 1 optional AUTH */ case TPM_ORD_CMK_ApproveMA: { BYTE *digest1 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } #endif /* 1 UINT16 only */ case TSC_ORD_PhysicalPresence: { UINT16 i = va_arg(ap, int); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT16(outOffset, i, out_blob); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } #ifdef TSS_BUILD_CMK /* 1 UINT32, 1 20 byte value, 1 BLOB, 2 20 byte values, 1 optional AUTH */ case TPM_ORD_CMK_CreateKey: { UINT32 key1 = va_arg(ap, UINT32); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); BYTE *digest2 = va_arg(ap, BYTE *); BYTE *digest3 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1 || !in_blob1 || !digest2 || !digest3) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, key1, out_blob); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest2); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest3); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 BLOB, 1 20 byte value, 1 UINT32, 1 BLOB, 1 optional AUTH */ case TPM_ORD_CMK_CreateTicket: { UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1 || !in_blob1 || !in_blob2) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 UINT32, 1 UINT16, 1 BLOB, 1 20 byte value, 4 x (1 UINT32, 1 BLOB), 1 optional AUTH */ case TPM_ORD_CMK_CreateBlob: { UINT32 in_key1 = va_arg(ap, UINT32); UINT16 i = va_arg(ap, int); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); UINT32 in_len3 = va_arg(ap, UINT32); BYTE *in_blob3 = va_arg(ap, BYTE *); UINT32 in_len4 = va_arg(ap, UINT32); BYTE *in_blob4 = va_arg(ap, BYTE *); UINT32 in_len5 = va_arg(ap, UINT32); BYTE *in_blob5 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!digest1 || !in_blob1 || !in_blob2 || !in_blob3 || !in_blob4 || !in_blob5) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, in_key1, out_blob); LoadBlob_UINT16(outOffset, i, out_blob); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); LoadBlob_UINT32(outOffset, in_len3, out_blob); LoadBlob(outOffset, in_len3, out_blob, in_blob3); LoadBlob_UINT32(outOffset, in_len4, out_blob); LoadBlob(outOffset, in_len4, out_blob, in_blob4); LoadBlob_UINT32(outOffset, in_len5, out_blob); LoadBlob(outOffset, in_len5, out_blob, in_blob5); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } /* 1 UINT32, 1 60 byte value, 1 20 byte value, 1 BLOB, 2 x (1 UINT32, 1 BLOB), * 1 optional AUTH */ case TPM_ORD_CMK_ConvertMigration: { UINT32 key1 = va_arg(ap, UINT32); BYTE *cmkauth1 = va_arg(ap, BYTE *); BYTE *digest1 = va_arg(ap, BYTE *); UINT32 in_len1 = va_arg(ap, UINT32); BYTE *in_blob1 = va_arg(ap, BYTE *); UINT32 in_len2 = va_arg(ap, UINT32); BYTE *in_blob2 = va_arg(ap, BYTE *); UINT32 in_len3 = va_arg(ap, UINT32); BYTE *in_blob3 = va_arg(ap, BYTE *); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); if (!cmkauth1 || !digest1 || !in_blob1 || !in_blob2 || !in_blob3) { result = TCSERR(TSS_E_INTERNAL_ERROR); LogError("Internal error for ordinal 0x%x", ordinal); break; } *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, key1, out_blob); LoadBlob(outOffset, 3 * TPM_SHA1_160_HASH_LEN, out_blob, cmkauth1); LoadBlob(outOffset, TPM_SHA1_160_HASH_LEN, out_blob, digest1); LoadBlob(outOffset, in_len1, out_blob, in_blob1); LoadBlob_UINT32(outOffset, in_len2, out_blob); LoadBlob(outOffset, in_len2, out_blob, in_blob2); LoadBlob_UINT32(outOffset, in_len3, out_blob); LoadBlob(outOffset, in_len3, out_blob, in_blob3); if (auth1) { LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); } break; } #endif #ifdef TSS_BUILD_TSS12 case TPM_ORD_FlushSpecific: { UINT32 val1 = va_arg(ap, UINT32); UINT32 val2 = va_arg(ap, UINT32); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, val1, out_blob); LoadBlob_UINT32(outOffset, val2, out_blob); LoadBlob_Header(TPM_TAG_RQU_COMMAND, *outOffset, ordinal, out_blob); break; } /* 1 UINT32, 1 BLOB, 1 UINT32, 1 BOOL, 1 AUTH */ case TPM_ORD_KeyControlOwner: { UINT32 i = va_arg(ap, UINT32); UINT32 len1 = va_arg(ap, UINT32); BYTE *blob1 = va_arg(ap, BYTE *); UINT32 j = va_arg(ap, UINT32); TSS_BOOL bool1 = va_arg(ap, int); TPM_AUTH *auth1 = va_arg(ap, TPM_AUTH *); va_end(ap); *outOffset += TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(outOffset, i, out_blob); LoadBlob(outOffset, len1, out_blob, blob1); LoadBlob_UINT32(outOffset, j, out_blob); LoadBlob_BOOL(outOffset, bool1, out_blob); LoadBlob_Auth(outOffset, out_blob, auth1); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, *outOffset, ordinal, out_blob); break; } #endif default: va_end(ap); LogError("Unknown ordinal: 0x%x", ordinal); break; } return result; } trousers-0.3.15/src/tcs/tcsi_bind.c0000664000175000017510000000337513663651711016446 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_UnBind_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { UINT32 paramSize; TSS_RESULT result; UINT64 offset = 0; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering TCSI_UnBind"); if ((result = ctx_verify_context(hContext))) goto done; if (privAuth != NULL) { LogDebug("Auth Used"); if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } LogDebugFn("calling ensureKeyIsLoaded for TCS handle 0x%x", keyHandle); if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_UnBind, &offset, txBlob, keySlot, inDataSize, inData, privAuth, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_UnBind, txBlob, paramSize, outDataSize, outData, privAuth, NULL); } done: auth_mgr_release_auth(privAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_admin.c0000664000175000017510000003002113663651711016606 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_SetOwnerInstall_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL state) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering SetOwnerInstall"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_SetOwnerInstall, &offset, txBlob, state, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("SetOwnerInstall", result); return result; } TSS_RESULT TCSP_OwnerSetDisable_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL disableState, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_OwnerSetDisable, &offset, txBlob, disableState, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_OwnerSetDisable, txBlob, paramSize, ownerAuth); } done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_DisableOwnerClear_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering DisableownerClear"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_DisableOwnerClear, &offset, txBlob, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_DisableOwnerClear, txBlob, paramSize, ownerAuth); } LogResult("DisableOwnerClear", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_ForceClear_Internal(TCS_CONTEXT_HANDLE hContext) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Force Clear"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_ForceClear, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Force Clear", result); return result; } TSS_RESULT TCSP_DisableForceClear_Internal(TCS_CONTEXT_HANDLE hContext) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Disable Force Clear"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_DisableForceClear, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Disable Force Clear", result); return result; } TSS_RESULT TCSP_PhysicalPresence_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PHYSICAL_PRESENCE fPhysicalPresence) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result = TCSERR(TSS_E_NOTIMPL); BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; char runlevel; runlevel = platform_get_runlevel(); if (runlevel != 's' && runlevel != 'S' && runlevel != '1') { LogInfo("Physical Presence command denied: Must be in single" " user mode."); return TCSERR(TSS_E_NOTIMPL); } if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TSC_ORD_PhysicalPresence, &offset, txBlob, fPhysicalPresence))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; return UnloadBlob_Header(txBlob, ¶mSize); } TSS_RESULT TCSP_PhysicalDisable_Internal(TCS_CONTEXT_HANDLE hContext) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Physical Disable"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_PhysicalDisable, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Physical Disable", result); return result; } TSS_RESULT TCSP_PhysicalEnable_Internal(TCS_CONTEXT_HANDLE hContext) /* in */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Physical Enable"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_PhysicalEnable, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Physical Enable", result); return result; } TSS_RESULT TCSP_PhysicalSetDeactivated_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL state) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Physical Set Deactivated"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_PhysicalSetDeactivated, &offset, txBlob, state, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("PhysicalSetDeactivated", result); return result; } TSS_RESULT TCSP_SetTempDeactivated_Internal(TCS_CONTEXT_HANDLE hContext) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Set Temp Deactivated"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_SetTempDeactivated, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("SetTempDeactivated", result); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT TCSP_SetTempDeactivated2_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * operatorAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Set Temp Deactivated2"); if ((result = ctx_verify_context(hContext))) return result; if (operatorAuth) { if ((result = auth_mgr_check(hContext, &operatorAuth->AuthHandle))) return result; } if ((result = tpm_rqu_build(TPM_ORD_SetTempDeactivated, &offset, txBlob, operatorAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_SetTempDeactivated, txBlob, paramSize, operatorAuth); } LogResult("SetTempDeactivated2", result); done: auth_mgr_release_auth(operatorAuth, NULL, hContext); return result; } #endif TSS_RESULT TCSP_FieldUpgrade_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut, /* out */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Field Upgrade"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_FieldUpgrade, &offset, txBlob, dataInSize, dataInSize, dataIn, ownerAuth, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_FieldUpgrade, txBlob, paramSize, dataOutSize, dataOut, ownerAuth); } LogResult("Field Upgrade", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_SetRedirection_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 c1, /* in */ UINT32 c2, /* in */ TPM_AUTH * privAuth) /* in, out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Set Redirection"); if ((result = ctx_verify_context(hContext))) goto done; if (privAuth != NULL) { if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) { result = TCSERR(TSS_E_FAIL); goto done; } if ((result = tpm_rqu_build(TPM_ORD_SetRedirection, &offset, txBlob, keySlot, c1, c2, privAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_SetRedirection, txBlob, paramSize, privAuth); } LogResult("Set Redirection", result); done: auth_mgr_release_auth(privAuth, NULL, hContext); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT TCSP_ResetLockValue_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_ResetLockValue, &offset, txBlob, ownerAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_ResetLockValue, txBlob, paramSize, ownerAuth); } done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_FlushSpecific_Common(UINT32 tpmResHandle, TPM_RESOURCE_TYPE resourceType) { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = tpm_rqu_build(TPM_ORD_FlushSpecific, &offset, txBlob, tpmResHandle, resourceType))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_FlushSpecific, txBlob, paramSize, NULL); } return result; } TSS_RESULT TCSP_FlushSpecific_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_HANDLE hResHandle, /* in */ TPM_RESOURCE_TYPE resourceType) /* in */ { UINT32 tpmResHandle; TSS_RESULT result; if ((result = ctx_verify_context(hContext))) return result; switch (resourceType) { case TPM_RT_KEY: if ((result = get_slot_lite(hContext, hResHandle, &tpmResHandle))) return result; if ((result = ctx_remove_key_loaded(hContext, hResHandle))) return result; if ((result = key_mgr_dec_ref_count(hResHandle))) return result; break; case TPM_RT_AUTH: if ((result = auth_mgr_check(hContext, &hResHandle))) return result; auth_mgr_release_auth_handle(hResHandle, hContext, FALSE); /* fall through */ case TPM_RT_TRANS: case TPM_RT_DAA_TPM: tpmResHandle = hResHandle; break; case TPM_RT_CONTEXT: result = TCSERR(TSS_E_NOTIMPL); goto done; default: LogDebugFn("Unknown resource type: 0x%x", resourceType); goto done; } result = TCSP_FlushSpecific_Common(tpmResHandle, resourceType); done: return result; } #endif trousers-0.3.15/src/tcs/tcsi_aik.c0000664000175000017510000001450313663651711016271 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" #include "tcs_aik.h" TSS_RESULT TCSP_MakeIdentity_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_ENCAUTH identityAuth, /* in */ TCPA_CHOSENID_HASH IDLabel_PrivCAHash, /* in */ UINT32 idKeyInfoSize, /* in */ BYTE * idKeyInfo, /* in */ TPM_AUTH * pSrkAuth, /* in, out */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * idKeySize, /* out */ BYTE ** idKey, /* out */ UINT32 * pcIdentityBindingSize, /* out */ BYTE ** prgbIdentityBinding, /* out */ UINT32 * pcEndorsementCredentialSize, /* out */ BYTE ** prgbEndorsementCredential, /* out */ UINT32 * pcPlatformCredentialSize, /* out */ BYTE ** prgbPlatformCredential, /* out */ UINT32 * pcConformanceCredentialSize, /* out */ BYTE ** prgbConformanceCredential) /* out */ { UINT64 offset; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) goto done; if (pSrkAuth != NULL) { LogDebug("SRK Auth Used"); if ((result = auth_mgr_check(hContext, &pSrkAuth->AuthHandle))) goto done; } else { LogDebug("No SRK Auth"); } if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) goto done; offset = 0; if ((result = tpm_rqu_build(TPM_ORD_MakeIdentity, &offset, txBlob, identityAuth.authdata, IDLabel_PrivCAHash.digest, idKeyInfoSize, idKeyInfo, pSrkAuth, pOwnerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { if ((result = tpm_rsp_parse(TPM_ORD_MakeIdentity, txBlob, paramSize, idKeySize, idKey, pcIdentityBindingSize, prgbIdentityBinding, pSrkAuth, pOwnerAuth))) goto done; /* If an error occurs, these will return NULL */ get_credential(TSS_TCS_CREDENTIAL_PLATFORMCERT, pcPlatformCredentialSize, prgbPlatformCredential); get_credential(TSS_TCS_CREDENTIAL_TPM_CC, pcConformanceCredentialSize, prgbConformanceCredential); get_credential(TSS_TCS_CREDENTIAL_EKCERT, pcEndorsementCredentialSize, prgbEndorsementCredential); } LogResult("Make Identity", result); done: auth_mgr_release_auth(pSrkAuth, pOwnerAuth, hContext); return result; } TSS_RESULT TCSP_ActivateTPMIdentity_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE idKey, /* in */ UINT32 blobSize, /* in */ BYTE * blob, /* in */ TPM_AUTH * idKeyAuth, /* in, out */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * SymmetricKeySize, /* out */ BYTE ** SymmetricKey) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 paramSize; UINT32 keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("TCSP_ActivateTPMIdentity"); if ((result = ctx_verify_context(hContext))) goto done; if (idKeyAuth != NULL) { if ((result = auth_mgr_check(hContext, &idKeyAuth->AuthHandle))) goto done; } if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = ensureKeyIsLoaded(hContext, idKey, &keySlot))) goto done; offset = 0; if ((result = tpm_rqu_build(TPM_ORD_ActivateIdentity, &offset, txBlob, keySlot, blobSize, blob, idKeyAuth, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { if ((result = tpm_rsp_parse(TPM_ORD_ActivateIdentity, txBlob, paramSize, SymmetricKeySize, SymmetricKey, idKeyAuth, ownerAuth))) goto done; } done: auth_mgr_release_auth(idKeyAuth, ownerAuth, hContext); return result; } TSS_RESULT TCS_GetCredential_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 ulCredentialType, /* in */ UINT32 ulCredentialAccessMode, /* in */ UINT32 * pulCredentialSize, /* out */ BYTE ** prgbCredentialData) /* out */ { TSS_RESULT result; if ((result = ctx_verify_context(hContext))) return result; if ((ulCredentialType != TSS_TCS_CREDENTIAL_EKCERT) && (ulCredentialType != TSS_TCS_CREDENTIAL_TPM_CC) && (ulCredentialType != TSS_TCS_CREDENTIAL_PLATFORMCERT)) { LogError("GetCredential - Unsupported Credential Type"); return TCSERR(TSS_E_BAD_PARAMETER); } if (ulCredentialAccessMode == TSS_TCS_CERT_ACCESS_AUTO) { get_credential(ulCredentialType, pulCredentialSize, prgbCredentialData); } else { LogError("GetCredential - Unsupported Credential Access Mode"); return TCSERR(TSS_E_FAIL); } return TSS_SUCCESS; } TSS_RESULT TCSP_MakeIdentity2_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_ENCAUTH identityAuth, /* in */ TCPA_CHOSENID_HASH IDLabel_PrivCAHash, /* in */ UINT32 idKeyInfoSize, /* in */ BYTE * idKeyInfo, /* in */ TPM_AUTH * pSrkAuth, /* in, out */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * idKeySize, /* out */ BYTE ** idKey, /* out */ UINT32 * pcIdentityBindingSize, /* out */ BYTE ** prgbIdentityBinding) /* out */ { UINT64 offset; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) goto done; if (pSrkAuth) { if ((result = auth_mgr_check(hContext, &pSrkAuth->AuthHandle))) goto done; } if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) goto done; offset = 0; if ((result = tpm_rqu_build(TPM_ORD_MakeIdentity, &offset, txBlob, identityAuth.authdata, IDLabel_PrivCAHash.digest, idKeyInfoSize, idKeyInfo, pSrkAuth, pOwnerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { if ((result = tpm_rsp_parse(TPM_ORD_MakeIdentity, txBlob, paramSize, idKeySize, idKey, pcIdentityBindingSize, prgbIdentityBinding, pSrkAuth, pOwnerAuth))) goto done; } LogResult("Make Identity", result); done: auth_mgr_release_auth(pSrkAuth, pOwnerAuth, hContext); return result; } trousers-0.3.15/src/tcs/tcs_ps.c0000664000175000017510000001146013663651711015775 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #include "tddl.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT get_vendor_data(struct key_disk_cache *d, UINT32 *size, BYTE **data) { if (d->vendor_data_size == 0) { *size = 0; *data = NULL; return TSS_SUCCESS; } return ps_get_vendor_data(d, size, data); } TSS_RESULT fill_key_info(struct key_disk_cache *d, struct key_mem_cache *m, TSS_KM_KEYINFO *key_info) { BYTE tmp_blob[2048]; UINT16 tmp_blob_size = 2048; TSS_KEY tmp_key; UINT64 offset; TSS_RESULT result; if (m == NULL) { key_info->fIsLoaded = FALSE; /* read key from disk */ if ((result = ps_get_key_by_cache_entry(d, (BYTE *)&tmp_blob, &tmp_blob_size))) return result; offset = 0; /* XXX add a real context handle here */ if ((result = UnloadBlob_TSS_KEY(&offset, tmp_blob, &tmp_key))) return result; if (tmp_key.hdr.key12.tag == TPM_TAG_KEY12) { key_info->versionInfo.bMajor = TSS_SPEC_MAJOR; key_info->versionInfo.bMinor = TSS_SPEC_MINOR; key_info->versionInfo.bRevMajor = 0; key_info->versionInfo.bRevMajor = 0; } else memcpy(&key_info->versionInfo, &tmp_key.hdr.key11.ver, sizeof(TSS_VERSION)); memcpy(&key_info->bAuthDataUsage, &tmp_key.authDataUsage, sizeof(TCPA_AUTH_DATA_USAGE)); destroy_key_refs(&tmp_key); } else { if (m->tpm_handle == NULL_TPM_HANDLE) key_info->fIsLoaded = FALSE; else key_info->fIsLoaded = TRUE; if (m->blob->hdr.key12.tag == TPM_TAG_KEY12) { key_info->versionInfo.bMajor = TSS_SPEC_MAJOR; key_info->versionInfo.bMinor = TSS_SPEC_MINOR; key_info->versionInfo.bRevMajor = 0; key_info->versionInfo.bRevMajor = 0; } else memcpy(&key_info->versionInfo, &m->blob->hdr.key11.ver, sizeof(TSS_VERSION)); memcpy(&key_info->bAuthDataUsage, &m->blob->authDataUsage, sizeof(TCPA_AUTH_DATA_USAGE)); } memcpy(&key_info->keyUUID, &d->uuid, sizeof(TSS_UUID)); memcpy(&key_info->parentKeyUUID, &d->parent_uuid, sizeof(TSS_UUID)); return get_vendor_data(d, &key_info->ulVendorDataLength, &key_info->rgbVendorData); } TSS_RESULT fill_key_info2(struct key_disk_cache *d, struct key_mem_cache *m, TSS_KM_KEYINFO2 *key_info) { BYTE tmp_blob[2048]; UINT16 tmp_blob_size = 2048; TSS_KEY tmp_key; UINT64 offset; TSS_RESULT result; if (m == NULL) { key_info->fIsLoaded = FALSE; /* read key from disk */ if ((result = ps_get_key_by_cache_entry(d, (BYTE *)&tmp_blob, &tmp_blob_size))) return result; offset = 0; /* XXX add a real context handle here */ if ((result = UnloadBlob_TSS_KEY(&offset, tmp_blob, &tmp_key))) return result; if (tmp_key.hdr.key12.tag == TPM_TAG_KEY12) { key_info->versionInfo.bMajor = TSS_SPEC_MAJOR; key_info->versionInfo.bMinor = TSS_SPEC_MINOR; key_info->versionInfo.bRevMajor = 0; key_info->versionInfo.bRevMajor = 0; } else memcpy(&key_info->versionInfo, &tmp_key.hdr.key11.ver, sizeof(TSS_VERSION)); memcpy(&key_info->bAuthDataUsage, &tmp_key.authDataUsage, sizeof(TCPA_AUTH_DATA_USAGE)); destroy_key_refs(&tmp_key); } else { if (m->tpm_handle == NULL_TPM_HANDLE) key_info->fIsLoaded = FALSE; else key_info->fIsLoaded = TRUE; if (m->blob->hdr.key12.tag == TPM_TAG_KEY12) { key_info->versionInfo.bMajor = TSS_SPEC_MAJOR; key_info->versionInfo.bMinor = TSS_SPEC_MINOR; key_info->versionInfo.bRevMajor = 0; key_info->versionInfo.bRevMajor = 0; } else memcpy(&key_info->versionInfo, &m->blob->hdr.key11.ver, sizeof(TSS_VERSION)); memcpy(&key_info->bAuthDataUsage, &m->blob->authDataUsage, sizeof(TCPA_AUTH_DATA_USAGE)); } memcpy(&key_info->keyUUID, &d->uuid, sizeof(TSS_UUID)); memcpy(&key_info->parentKeyUUID, &d->parent_uuid, sizeof(TSS_UUID)); /* Fill the two new TSS_KM_KEYINFO2 fields here */ key_info->persistentStorageTypeParent = d->flags & CACHE_FLAG_PARENT_PS_SYSTEM ? TSS_PS_TYPE_SYSTEM : TSS_PS_TYPE_USER; key_info->persistentStorageType = TSS_PS_TYPE_SYSTEM; return get_vendor_data(d, &key_info->ulVendorDataLength, &key_info->rgbVendorData); } TSS_RESULT key_mgr_load_by_uuid(TCS_CONTEXT_HANDLE hContext, TSS_UUID *uuid, TCS_LOADKEY_INFO *pInfo, TCS_KEY_HANDLE *phKeyTCSI) { TSS_RESULT result; MUTEX_LOCK(mem_cache_lock); result = TCSP_LoadKeyByUUID_Internal(hContext, uuid, pInfo, phKeyTCSI); LogDebug("Key %s loaded by UUID w/ TCS handle: 0x%x", result ? "NOT" : "successfully", result ? 0 : *phKeyTCSI); MUTEX_UNLOCK(mem_cache_lock); return result; } trousers-0.3.15/src/tcs/tcsi_nv.c0000664000175000017510000001463013663651711016151 0ustar deboradebora /* * The Initial Developer of the Original Code is Intel Corporation. * Portions created by Intel Corporation are Copyright (C) 2007 Intel Corporation. * All Rights Reserved. * trousers - An open source TCG Software Stack * * Author: james.xu@intel.com Rossey.liu@intel.com * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_NV_DefineOrReleaseSpace_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 cPubInfoSize, /* in */ BYTE* pPubInfo, /* in */ TPM_ENCAUTH encAuth, /* in */ TPM_AUTH* pAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (pAuth) { if ((result = auth_mgr_check(hContext, &pAuth->AuthHandle))) goto done; } if ((result = tpm_rqu_build(TPM_ORD_NV_DefineSpace, &offset, txBlob, cPubInfoSize, pPubInfo, TPM_ENCAUTH_SIZE, encAuth.authdata, pAuth))) return result; LogDebug("req_mgr_submit_req (oldOffset=%" PRIu64 ")", offset); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("UnloadBlob (paramSize=%u) result=%u", paramSize, result); if (!result) { result = tpm_rsp_parse(TPM_ORD_NV_DefineSpace, txBlob, paramSize, pAuth); } done: LogDebug("Leaving DefineSpace with result:%u", result); auth_mgr_release_auth(pAuth, NULL, hContext); return result; } TSS_RESULT TCSP_NV_WriteValue_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE * rgbDataToWrite, /* in */ TPM_AUTH * privAuth) /* in, out */ { UINT64 off_set = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ( (result = ctx_verify_context(hContext))) return result; if (privAuth) { if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } if ((result = tpm_rqu_build(TPM_ORD_NV_WriteValue, &off_set, txBlob, hNVStore, offset, ulDataLength, rgbDataToWrite, privAuth))) return result; LogDebug("req_mgr_submit_req (oldOffset=%" PRIu64 ")", off_set); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("UnloadBlob (paramSize=%u) result=%u", paramSize, result); if (!result) { result = tpm_rsp_parse(TPM_ORD_NV_WriteValue, txBlob, paramSize, privAuth); } done: LogDebug("Leaving NVWriteValue with result:%u", result); auth_mgr_release_auth(privAuth, NULL, hContext); return result; } TSS_RESULT TCSP_NV_WriteValueAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE * rgbDataToWrite, /* in */ TPM_AUTH * NVAuth) /* in, out */ { UINT64 off_set = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &NVAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_NV_WriteValueAuth, &off_set, txBlob, hNVStore, offset, ulDataLength, rgbDataToWrite, NVAuth))) return result; LogDebug("req_mgr_submit_req (oldOffset=%" PRIu64 ")", off_set); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("UnloadBlob (paramSize=%u) result=%u", paramSize, result); if (!result) { result = tpm_rsp_parse(TPM_ORD_NV_WriteValueAuth, txBlob, paramSize, NVAuth); } done: LogDebug("Leaving NVWriteValueAuth with result:%u", result); auth_mgr_release_auth(NVAuth, NULL, hContext); return result; } TSS_RESULT TCSP_NV_ReadValue_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 * pulDataLength, /* in, out */ TPM_AUTH * privAuth, /* in, out */ BYTE ** rgbDataRead) /* out */ { UINT64 off_set = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (privAuth) { if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } if ((result = tpm_rqu_build(TPM_ORD_NV_ReadValue, &off_set, txBlob, hNVStore, offset, *pulDataLength, privAuth))) return result; LogDebug("req_mgr_submit_req (oldOffset=%" PRIu64 ")", off_set); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("UnloadBlob (paramSize=%u) result=%u", paramSize, result); if (!result) { result = tpm_rsp_parse(TPM_ORD_NV_ReadValue, txBlob, paramSize, pulDataLength, rgbDataRead, privAuth, NULL); } done: LogDebug("Leaving NVReadValue with result:%u", result); auth_mgr_release_auth(privAuth, NULL, hContext); return result; } TSS_RESULT TCSP_NV_ReadValueAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 * pulDataLength, /* in, out */ TPM_AUTH * NVAuth, /* in, out */ BYTE ** rgbDataRead) /* out */ { UINT64 off_set = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((NVAuth != NULL) && (result = auth_mgr_check(hContext, &NVAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_NV_ReadValueAuth, &off_set, txBlob, hNVStore, offset, *pulDataLength, NVAuth))) return result; LogDebug("req_mgr_submit_req (oldOffset=%" PRIu64 ")", off_set); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("UnloadBlob (paramSize=%u) result=%u", paramSize, result); if (!result) { result = tpm_rsp_parse(TPM_ORD_NV_ReadValueAuth, txBlob, paramSize, pulDataLength, rgbDataRead, NVAuth, NULL); } done: LogDebug("Leaving NVReadValueAuth with result:%u", result); auth_mgr_release_auth(NVAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_selftest.c0000664000175000017510000000575113663651711017363 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_SelfTestFull_Internal(TCS_CONTEXT_HANDLE hContext) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Self Test Full"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_SelfTestFull, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Self Test Full", result); return result; } TSS_RESULT TCSP_CertifySelfTest_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Certify Self Test"); if ((result = ctx_verify_context(hContext))) goto done; if (privAuth != NULL) { LogDebug("Auth Used"); if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_CertifySelfTest, &offset, txBlob, keySlot, TPM_NONCE_SIZE, antiReplay.nonce, privAuth, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CertifySelfTest, txBlob, paramSize, sigSize, sig, privAuth, NULL); } LogResult("Certify Self Test", result); done: auth_mgr_release_auth(privAuth, NULL, hContext); return result; } TSS_RESULT TCSP_GetTestResult_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Get Test Result"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_GetTestResult, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_GetTestResult, txBlob, paramSize, outDataSize, outData, NULL, NULL); } LogResult("Get Test Result", result); return result; } trousers-0.3.15/src/tcs/tcs_context_key.c0000664000175000017510000000666113663651711017716 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_context.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" MUTEX_DECLARE_EXTERN(tcs_ctx_lock); /* runs through the list of all keys loaded by context c and decrements * their ref count by 1, then free's their structures. */ void ctx_ref_count_keys(struct tcs_context *c) { struct keys_loaded *cur, *prev; if (c == NULL) return; cur = prev = c->keys; while (cur != NULL) { key_mgr_dec_ref_count(cur->key_handle); cur = cur->next; free(prev); prev = cur; } } /* Traverse loaded keys list and if matching key handle is found return TRUE else return FALSE */ TSS_BOOL ctx_has_key_loaded(TCS_CONTEXT_HANDLE ctx_handle, TCS_KEY_HANDLE key_handle) { struct tcs_context *c; struct keys_loaded *k = NULL; MUTEX_LOCK(tcs_ctx_lock); c = get_context(ctx_handle); if (c == NULL) { MUTEX_UNLOCK(tcs_ctx_lock); return FALSE; } k = c->keys; while (k != NULL) { if (k->key_handle == key_handle) { MUTEX_UNLOCK(tcs_ctx_lock); return TRUE; } k = k->next; } MUTEX_UNLOCK(tcs_ctx_lock); return FALSE; } /* Traverse loaded keys list and if matching key handle is found remove it */ TSS_RESULT ctx_remove_key_loaded(TCS_CONTEXT_HANDLE ctx_handle, TCS_KEY_HANDLE key_handle) { struct tcs_context *c; struct keys_loaded *cur, *prev; MUTEX_LOCK(tcs_ctx_lock); c = get_context(ctx_handle); if (c == NULL) { MUTEX_UNLOCK(tcs_ctx_lock); return TCSERR(TCS_E_INVALID_CONTEXTHANDLE); } for (prev = cur = c->keys; cur; prev = cur, cur = cur->next) { if (cur->key_handle == key_handle) { if (cur == c->keys) c->keys = cur->next; else prev->next = cur->next; free(cur); MUTEX_UNLOCK(tcs_ctx_lock); return TCS_SUCCESS; } } MUTEX_UNLOCK(tcs_ctx_lock); return TCSERR(TCS_E_INVALID_KEY); } /* make a new entry in the per-context list of loaded keys. If the list already * contains a pointer to the key in memory, just return success. */ TSS_RESULT ctx_mark_key_loaded(TCS_CONTEXT_HANDLE ctx_handle, TCS_KEY_HANDLE key_handle) { struct tcs_context *c; struct keys_loaded *k = NULL, *new; TSS_RESULT result; MUTEX_LOCK(tcs_ctx_lock); c = get_context(ctx_handle); if (c != NULL) { k = c->keys; while (k != NULL) { if (k->key_handle == key_handle) { /* we've previously created a pointer to key_handle in the global * list of loaded keys and incremented that key's reference count, * so there's no need to do anything. */ result = TSS_SUCCESS; break; } k = k->next; } } else { MUTEX_UNLOCK(tcs_ctx_lock); return TCSERR(TSS_E_FAIL); } /* if we have no record of this key being loaded by this context, create a new * entry and increment the key's reference count in the global list. */ if (k == NULL) { new = calloc(1, sizeof(struct keys_loaded)); if (new == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct keys_loaded)); MUTEX_UNLOCK(tcs_ctx_lock); return TCSERR(TSS_E_OUTOFMEMORY); } new->key_handle = key_handle; new->next = c->keys; c->keys = new; result = key_mgr_inc_ref_count(new->key_handle); } MUTEX_UNLOCK(tcs_ctx_lock); return result; } trousers-0.3.15/src/tcs/tcsi_oper.c0000664000175000017510000000171013663651711016466 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_utils.h" #include "tcslog.h" #include "req_mgr.h" TSS_RESULT TCSP_SetOperatorAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_SECRET *operatorAuth) /* in */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_SetOperatorAuth, &offset, txBlob, TPM_AUTHDATA_SIZE, operatorAuth->authdata))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("SetOperatorAuth", result); done: return result; } trousers-0.3.15/src/tcs/tcsi_quote.c0000664000175000017510000000350113663651711016656 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_Quote_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; UINT32 keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering quote"); if ((result = ctx_verify_context(hContext))) goto done; if (privAuth != NULL) { LogDebug("Auth Used"); if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_Quote, &offset, txBlob, keySlot, antiReplay.nonce, pcrDataSizeIn, pcrDataIn, privAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Quote, txBlob, paramSize, pcrDataSizeOut, pcrDataOut, sigSize, sig, privAuth); } LogResult("Quote", result); done: auth_mgr_release_auth(privAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcs_key.c0000664000175000017510000003531713663651711016152 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include "trousers/tss.h" #include "trousers_types.h" #include "req_mgr.h" #include "tcs_tsp.h" #include "tcslog.h" #include "tcs_utils.h" #include "tcs_int_literals.h" struct key_mem_cache *key_mem_cache_head = NULL; TSS_UUID NULL_UUID = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; TSS_RESULT add_cache_entry(TCS_CONTEXT_HANDLE hContext, BYTE* blob, TCS_KEY_HANDLE hParent, TPM_KEY_HANDLE hSlot, TCS_KEY_HANDLE* new) { UINT64 offset; TSS_RESULT result; TCS_KEY_HANDLE tcsHandle; TSS_KEY key, *pKey; if (!blob) { pKey = NULL; } else { offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key))) return result; if ((tcsHandle = mc_get_handle_by_pub(&key.pubKey, hParent)) == NULL_TCS_HANDLE) { pKey = &key; } else { mc_set_slot_by_handle(tcsHandle, hSlot); *new = tcsHandle; goto done; } } LogDebugFn("No existing key handle for this key, creating new one..."); /* Get a new TCS Key Handle */ tcsHandle = getNextTcsKeyHandle(); LogDebugFn("calling mc_add_entry, TCS handle: 0x%x, TPM handle 0x%x", tcsHandle, hSlot); if ((result = mc_add_entry(tcsHandle, hSlot, pKey))) goto done; LogDebugFn("ctx_mark_key_loaded"); if (ctx_mark_key_loaded(hContext, tcsHandle)) { LogError("Error marking key as loaded"); result = TCSERR(TSS_E_INTERNAL_ERROR); goto done; } if ((result = mc_set_parent_by_handle(tcsHandle, hParent))) { LogError("mc_set_parent_by_handle failed."); goto done; } *new = tcsHandle; done: if (blob) destroy_key_refs(&key); return result; } /* Check that the context has this key loaded and return the associated slot. Do not search PS if * the key is not found */ TSS_RESULT get_slot_lite(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out) { if (ctx_has_key_loaded(hContext, hKey)) { if ((*out = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE) return TCSERR(TCS_E_INVALID_KEY); return TSS_SUCCESS; } return TCSERR(TCS_E_INVALID_KEY); } /* XXX Can get_slot be merged with ensureKeyIsLoaded? */ /* Given a handle, get_slot searches the mem cache for a mapping to a TPM handle. If there is no * mapping, it looks up the pub key of the handle and attempts to load it by finding its pub key * in the persistent store. If that's not found, return error. */ TSS_RESULT get_slot(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out) { TSS_RESULT result = TSS_SUCCESS; TPM_STORE_PUBKEY *pub = NULL; TPM_KEY_HANDLE slot; LogDebugFn("calling mc_get_slot_by_handle"); if ((slot = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE) { LogDebugFn("calling mc_get_pub_by_slot"); if ((pub = mc_get_pub_by_slot(hKey)) == NULL) return TCSERR(TCS_E_KM_LOADFAILED); LogDebugFn("calling LoadKeyShim"); /* Otherwise, try to load it using the shim */ result = LoadKeyShim(hContext, pub, NULL, &slot); } if (!result) *out = slot; return result; } /* load_key_init is the common entry point for all load key requests to the TCSD. These can come in * as straight load or load2 requests, or through a transport session. * * We'll always attempt to load the key if * A) It requires auth (load should fail if auth is bad, even when its already been loaded by * another thread) * B) Its in a transport session (the key blob is encrypted) * * Otherwise if the key is already loaded by another thread and it doesn't require auth, then we * will just set *load_key to FALSE, telling the caller that there's no need to send anything to * the TPM. */ TSS_RESULT load_key_init(TPM_COMMAND_CODE ord, TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE parent_handle, UINT32 blob_size, BYTE* blob, TSS_BOOL encrypted, TPM_AUTH* auth, TSS_BOOL* load_key, UINT64* out_len, BYTE* out, TCS_KEY_HANDLE* handle, TPM_KEY_HANDLE* slot) { TSS_RESULT result = TSS_SUCCESS; TSS_KEY key; UINT64 offset; TPM_KEY_HANDLE tpm_slot; TCS_KEY_HANDLE tcs_handle; TSS_BOOL canLoad; if (!encrypted) { offset = 0; memset(&key, 0, sizeof(TSS_KEY)); if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key))) return result; } if (!auth && !encrypted) { LogDebugFn("Checking if LoadKeyByBlob can be avoided by using existing key"); if ((tcs_handle = mc_get_handle_by_pub(&key.pubKey, parent_handle))) { LogDebugFn("tcs key handle exists"); tpm_slot = mc_get_slot_by_handle(tcs_handle); if (tpm_slot && (isKeyLoaded(tpm_slot) == TRUE)) { LogDebugFn("Don't need to reload this key."); *handle = tcs_handle; *slot = tpm_slot; *load_key = FALSE; goto done; } } } *load_key = TRUE; LogDebugFn("calling canILoadThisKey"); if (!encrypted) { if ((result = canILoadThisKey(&(key.algorithmParms), &canLoad))) goto error; if (canLoad == FALSE) { LogDebugFn("calling evictFirstKey"); /* Evict a key that isn't the parent */ if ((result = evictFirstKey(parent_handle))) goto error; } } error: if (!encrypted) destroy_key_refs(&key); done: return result; } TSS_RESULT load_key_final(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE parent_handle, TCS_KEY_HANDLE* tcs_handle, BYTE* blob, TPM_KEY_HANDLE slot) { if (*tcs_handle == NULL_TCS_HANDLE) return add_cache_entry(hContext, blob, parent_handle, slot, tcs_handle); else return mc_set_slot_by_handle(*tcs_handle, slot); } TSS_RESULT canILoadThisKey(TCPA_KEY_PARMS *parms, TSS_BOOL *b) { UINT16 subCapLength; UINT64 offset; BYTE subCap[100]; TCPA_RESULT result; UINT32 respDataLength; BYTE *respData; offset = 0; LoadBlob_KEY_PARMS(&offset, subCap, parms); subCapLength = offset; if ((result = TCSP_GetCapability_Internal(InternalContext, TCPA_CAP_CHECK_LOADED, subCapLength, subCap, &respDataLength, &respData))) { *b = FALSE; LogDebugFn("NO"); return result; } *b = respData[0]; free(respData); LogDebugFn("%s", *b ? "YES" : "NO"); return TSS_SUCCESS; } TCPA_RESULT internal_EvictByKeySlot(TCPA_KEY_HANDLE slot) { TCPA_RESULT result; UINT32 paramSize; UINT64 offset; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Evict Key"); #ifdef TSS_BUILD_TSS12 if (TPM_VERSION_IS(1,2)) { LogDebugFn("Evicting key using FlushSpecific for TPM 1.2"); return TCSP_FlushSpecific_Common(slot, TPM_RT_KEY); } #endif offset = 10; LoadBlob_UINT32(&offset, slot, txBlob); LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_EvictKey, txBlob); if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Evict Key", result); return result; } TSS_RESULT clearUnknownKeys(TCS_CONTEXT_HANDLE hContext, UINT32 *cleared) { TSS_RESULT result = TSS_SUCCESS; TCPA_KEY_HANDLE_LIST keyList = { 0, NULL }; int i; BYTE *respData = NULL; UINT32 respDataSize = 0, count = 0; TCPA_CAPABILITY_AREA capArea = -1; UINT64 offset = 0; TSS_BOOL found = FALSE; struct key_mem_cache *tmp; capArea = TCPA_CAP_KEY_HANDLE; if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL, &respDataSize, &respData))) return result; if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList))) goto done; #ifdef TSS_DEBUG LogDebug("Loaded TPM key handles:"); for (i = 0; i < keyList.loaded; i++) { LogDebugFn("%d: %x", i, keyList.handle[i]); } LogDebug("Loaded TCSD key handles:"); i=0; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("%d: 0x%x -> 0x%x", i++, tmp->tpm_handle, tmp->tcs_handle); } #endif for (i = 0; i < keyList.loaded; i++) { /* as long as we're only called from evictFirstKey(), we don't * need to lock here */ for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { if (tmp->tpm_handle == keyList.handle[i]) { found = TRUE; break; } } if (found) found = FALSE; else { if ((result = internal_EvictByKeySlot(keyList.handle[i]))) goto done; else count++; } } *cleared = count; done: free(keyList.handle); free(respData); return TSS_SUCCESS; } #if 0 TCPA_RESULT clearKeysFromChip(TCS_CONTEXT_HANDLE hContext) { TCPA_RESULT result; TCPA_KEY_HANDLE_LIST keyList; UINT32 i; BYTE *respData = 0; UINT32 respDataSize = 0; TCPA_CAPABILITY_AREA capArea = -1; UINT64 offset = 0; capArea = TCPA_CAP_KEY_HANDLE; if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL, &respDataSize, &respData))) return result; if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList))) return result; for (i = 0; i < keyList.loaded; i++) { if (keyList.handle[i] == SRK_TPM_HANDLE || /*can't evict SRK */ keyList.handle[i] == EK_TPM_HANDLE) /*can't evict EK */ continue; if ((result = internal_EvictByKeySlot(keyList.handle[i]))) return result; } return TSS_SUCCESS; } #endif void LoadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyInfo) { LoadBlob_UINT32(offset, keyInfo->algorithmID, blob); LoadBlob_UINT16(offset, keyInfo->encScheme, blob); LoadBlob_UINT16(offset, keyInfo->sigScheme, blob); LoadBlob_UINT32(offset, keyInfo->parmSize, blob); LoadBlob(offset, keyInfo->parmSize, blob, keyInfo->parms); } TSS_RESULT UnloadBlob_STORE_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_PUBKEY *store) { if (!store) { UINT32 keyLength; UnloadBlob_UINT32(offset, &keyLength, blob); if (keyLength > 0) UnloadBlob(offset, keyLength, blob, NULL); return TSS_SUCCESS; } UnloadBlob_UINT32(offset, &store->keyLength, blob); if (store->keyLength == 0) { store->key = NULL; LogWarn("Unloading a public key of size 0!"); } else { store->key = (BYTE *)malloc(store->keyLength); if (store->key == NULL) { LogError("malloc of %u bytes failed.", store->keyLength); store->keyLength = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, store->keyLength, blob, store->key); } return TSS_SUCCESS; } void LoadBlob_STORE_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_STORE_PUBKEY * store) { LoadBlob_UINT32(offset, store->keyLength, blob); LoadBlob(offset, store->keyLength, blob, store->key); } TSS_RESULT UnloadBlob_TSS_KEY(UINT64 *offset, BYTE *blob, TSS_KEY *key) { TSS_RESULT rc; if (!key) { UINT32 size; /* TPM_KEY's ver and TPM_KEY12's tag/file are the same size, so... */ UnloadBlob_VERSION(offset, blob, NULL); UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob_KEY_FLAGS(offset, blob, NULL); UnloadBlob_BOOL(offset, NULL, blob); if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL))) return rc; UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, NULL))) return rc; UnloadBlob_UINT32(offset, &size, blob); if (size > 0) UnloadBlob(offset, size, blob, NULL); return TSS_SUCCESS; } if (key->hdr.key12.tag == TPM_TAG_KEY12) { UnloadBlob_UINT16(offset, &key->hdr.key12.tag, blob); UnloadBlob_UINT16(offset, &key->hdr.key12.fill, blob); } else UnloadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver); UnloadBlob_UINT16(offset, &key->keyUsage, blob); UnloadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); UnloadBlob_BOOL(offset, (TSS_BOOL *)&key->authDataUsage, blob); if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms))) return rc; UnloadBlob_UINT32(offset, &key->PCRInfoSize, blob); if (key->PCRInfoSize == 0) key->PCRInfo = NULL; else { key->PCRInfo = malloc(key->PCRInfoSize); if (key->PCRInfo == NULL) { LogError("malloc of %u bytes failed.", key->PCRInfoSize); key->PCRInfoSize = 0; free(key->algorithmParms.parms); key->algorithmParms.parms = NULL; key->algorithmParms.parmSize = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); } if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) { free(key->PCRInfo); key->PCRInfo = NULL; key->PCRInfoSize = 0; free(key->algorithmParms.parms); key->algorithmParms.parms = NULL; key->algorithmParms.parmSize = 0; return rc; } UnloadBlob_UINT32(offset, &key->encSize, blob); if (key->encSize == 0) key->encData = NULL; else { key->encData = (BYTE *)malloc(key->encSize); if (key->encData == NULL) { LogError("malloc of %d bytes failed.", key->encSize); key->encSize = 0; free(key->algorithmParms.parms); key->algorithmParms.parms = NULL; key->algorithmParms.parmSize = 0; free(key->PCRInfo); key->PCRInfo = NULL; key->PCRInfoSize = 0; free(key->pubKey.key); key->pubKey.key = NULL; key->pubKey.keyLength = 0; return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, key->encSize, blob, key->encData); } return TSS_SUCCESS; } void LoadBlob_TSS_KEY(UINT64 *offset, BYTE * blob, TSS_KEY * key) { if (key->hdr.key12.tag == TPM_TAG_KEY12) { LoadBlob_UINT16(offset, key->hdr.key12.tag, blob); LoadBlob_UINT16(offset, key->hdr.key12.fill, blob); } else LoadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver); LoadBlob_UINT16(offset, key->keyUsage, blob); LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); LoadBlob_BOOL(offset, key->authDataUsage, blob); LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms); LoadBlob_UINT32(offset, key->PCRInfoSize, blob); LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey); LoadBlob_UINT32(offset, key->encSize, blob); LoadBlob(offset, key->encSize, blob, key->encData); } void LoadBlob_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_PUBKEY * key) { LoadBlob_KEY_PARMS(offset, blob, &(key->algorithmParms)); LoadBlob_STORE_PUBKEY(offset, blob, &(key->pubKey)); } TSS_RESULT UnloadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *key) { TSS_RESULT rc; if (!key) { if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL))) return rc; return UnloadBlob_STORE_PUBKEY(offset, blob, NULL); } if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms))) return rc; if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) { free(key->algorithmParms.parms); key->algorithmParms.parms = NULL; key->algorithmParms.parmSize = 0; } return rc; } void LoadBlob_KEY_FLAGS(UINT64 *offset, BYTE * blob, TCPA_KEY_FLAGS * flags) { LoadBlob_UINT32(offset, *flags, blob); } void destroy_key_refs(TSS_KEY *key) { free(key->algorithmParms.parms); key->algorithmParms.parms = NULL; key->algorithmParms.parmSize = 0; free(key->pubKey.key); key->pubKey.key = NULL; key->pubKey.keyLength = 0; free(key->encData); key->encData = NULL; key->encSize = 0; free(key->PCRInfo); key->PCRInfo = NULL; key->PCRInfoSize = 0; } trousers-0.3.15/src/tcs/tcsi_transport.c0000664000175000017510000003514113663651711017562 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" TSS_RESULT TCSP_EstablishTransport_Internal(TCS_CONTEXT_HANDLE hContext, UINT32 ulTransControlFlags, TCS_KEY_HANDLE hEncKey, UINT32 ulTransSessionInfoSize, BYTE* rgbTransSessionInfo, UINT32 ulSecretSize, BYTE* rgbSecret, TPM_AUTH* pEncKeyAuth, TPM_MODIFIER_INDICATOR* pbLocality, TCS_HANDLE* hTransSession, UINT32* ulCurrentTicks, BYTE** prgbCurrentTicks, TPM_NONCE* pTransNonce) { TSS_RESULT result; UINT32 paramSize; UINT64 offset; TPM_KEY_HANDLE keySlot = TPM_KH_TRANSPORT; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if (ulTransControlFlags == TSS_TCSATTRIB_TRANSPORT_EXCLUSIVE) { if ((result = ctx_req_exclusive_transport(hContext))) return result; } if (pEncKeyAuth) { if ((result = auth_mgr_check(hContext, &pEncKeyAuth->AuthHandle))) return result; } /* if hEncKey is set to TPM_KH_TRANSPORT, that's the signal to the TPM that this will be * an unencrypted transport session, so we don't need to check that its loaded */ if (hEncKey != TPM_KH_TRANSPORT) { if ((result = ensureKeyIsLoaded(hContext, hEncKey, &keySlot))) return result; } offset = TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(&offset, keySlot, txBlob); LoadBlob(&offset, ulTransSessionInfoSize, txBlob, rgbTransSessionInfo); LoadBlob_UINT32(&offset, ulSecretSize, txBlob); LoadBlob(&offset, ulSecretSize, txBlob, rgbSecret); if (pEncKeyAuth) { LoadBlob_Auth(&offset, txBlob, pEncKeyAuth); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_EstablishTransport, txBlob); } else LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_EstablishTransport, txBlob); if ((result = req_mgr_submit_req(txBlob))) goto done; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto done; } offset = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT32(&offset, hTransSession, txBlob); UnloadBlob_UINT32(&offset, pbLocality, txBlob); *ulCurrentTicks = sizeof(TPM_STRUCTURE_TAG) + sizeof(UINT64) + sizeof(UINT16) + sizeof(TPM_NONCE); *prgbCurrentTicks = malloc(*ulCurrentTicks); if (*prgbCurrentTicks == NULL) { result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } UnloadBlob(&offset, *ulCurrentTicks, txBlob, *prgbCurrentTicks); UnloadBlob(&offset, sizeof(TPM_NONCE), txBlob, (BYTE *)pTransNonce); if (pEncKeyAuth) UnloadBlob_Auth(&offset, txBlob, pEncKeyAuth); ctx_set_transport_enabled(hContext, *hTransSession); done: auth_mgr_release_auth(pEncKeyAuth, NULL, hContext); return result; } TSS_RESULT TCSP_ExecuteTransport_Internal(TCS_CONTEXT_HANDLE hContext, TPM_COMMAND_CODE unWrappedCommandOrdinal, UINT32 ulWrappedCmdParamInSize, BYTE* rgbWrappedCmdParamIn, UINT32* pulHandleListSize, /* in, out */ TCS_HANDLE** rghHandles, /* in, out */ TPM_AUTH* pWrappedCmdAuth1, /* in, out */ TPM_AUTH* pWrappedCmdAuth2, /* in, out */ TPM_AUTH* pTransAuth, /* in, out */ UINT64* punCurrentTicks, TPM_MODIFIER_INDICATOR* pbLocality, TPM_RESULT* pulWrappedCmdReturnCode, UINT32* ulWrappedCmdParamOutSize, BYTE** rgbWrappedCmdParamOut) { TSS_RESULT result; UINT32 paramSize, wrappedSize, val1 = 0, val2 = 0, *pVal1 = NULL, *pVal2 = NULL; TCS_HANDLE handle1 = 0, handle2 = 0; UINT64 offset, wrappedOffset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if (*pulHandleListSize > 2) { LogDebugFn("************ EXPAND KEYSLOT SIZE *********"); return TCSERR(TSS_E_INTERNAL_ERROR); } if ((result = ctx_verify_context(hContext))) return result; if (pWrappedCmdAuth1) if ((result = auth_mgr_check(hContext, &pWrappedCmdAuth1->AuthHandle))) goto done; if (pWrappedCmdAuth2) if ((result = auth_mgr_check(hContext, &pWrappedCmdAuth2->AuthHandle))) goto done; switch (unWrappedCommandOrdinal) { /* If the command is FlushSpecific, we get handle that needs to be freed, but we don't know * what type it is. */ case TPM_ORD_FlushSpecific: if (*pulHandleListSize == 0) { /* invalid */ result = TCSERR(TSS_E_BAD_PARAMETER); goto done; } /* If this is a transport handle, remove the context's reference to the session */ ctx_set_transport_disabled(hContext, rghHandles[0]); /* Is it a key? If so, jump to the get_slot_lite and key management calls below */ if (ctx_has_key_loaded(hContext, *rghHandles[0])) goto map_key_handles; /* fall through */ case TPM_ORD_Terminate_Handle: if (!auth_mgr_check(hContext, rghHandles[0])) auth_mgr_release_auth_handle(*rghHandles[0], hContext, FALSE); /* If the handle is an auth handle or any other kind of handle, there's no * mapping done in the TCS, so pass its value straight to the TPM and jump over * the switch statement below where we assume FLushSpecific is being done on a * key */ handle1 = val1 = *rghHandles[0]; pVal1 = &val1; goto build_command; default: break; } map_key_handles: if (*pulHandleListSize == 2) { handle2 = (*rghHandles)[1]; if ((result = get_slot_lite(hContext, handle2, &val2))) { *pulHandleListSize = 0; goto done; } pVal2 = &val2; } if (*pulHandleListSize >= 1) { handle1 = *rghHandles[0]; *pulHandleListSize = 0; if ((result = get_slot_lite(hContext, handle1, &val1))) goto done; pVal1 = &val1; } switch (unWrappedCommandOrdinal) { case TPM_ORD_EvictKey: case TPM_ORD_FlushSpecific: { if ((result = ctx_remove_key_loaded(hContext, handle1))) goto done; if ((result = key_mgr_dec_ref_count(handle1))) goto done; /* we can't call key_mgr_ref_cnt() here since it calls TPM_EvictKey directly */ mc_set_slot_by_handle(handle1, NULL_TPM_HANDLE); break; } case TPM_ORD_OIAP: { /* are the maximum number of auth sessions open? */ if (auth_mgr_req_new(hContext) == FALSE) { if ((result = auth_mgr_swap_out(hContext))) goto done; } break; } case TPM_ORD_OSAP: { UINT16 entityType; UINT32 entityValue, newEntValue; /* are the maximum number of auth sessions open? */ if (auth_mgr_req_new(hContext) == FALSE) { if ((result = auth_mgr_swap_out(hContext))) goto done; } offset = 0; UnloadBlob_UINT16(&offset, &entityType, rgbWrappedCmdParamIn); UnloadBlob_UINT32(&offset, &entityValue, rgbWrappedCmdParamIn); if (entityType == TCPA_ET_KEYHANDLE || entityType == TCPA_ET_KEY) { if (ensureKeyIsLoaded(hContext, entityValue, &newEntValue)) return TCSERR(TSS_E_KEY_NOT_LOADED); /* OSAP is never encrypted in a transport session, so changing * rgbWrappedCmdParamIn is ok here */ offset = sizeof(UINT16); LoadBlob_UINT32(&offset, newEntValue, rgbWrappedCmdParamIn); } break; } case TPM_ORD_DSAP: { UINT16 entityType; UINT32 keyHandle, tpmKeyHandle; /* are the maximum number of auth sessions open? */ if (auth_mgr_req_new(hContext) == FALSE) { if ((result = auth_mgr_swap_out(hContext))) goto done; } offset = 0; UnloadBlob_UINT16(&offset, &entityType, rgbWrappedCmdParamIn); UnloadBlob_UINT32(&offset, &keyHandle, rgbWrappedCmdParamIn); if (ensureKeyIsLoaded(hContext, keyHandle, &tpmKeyHandle)) { result = TCSERR(TSS_E_KEY_NOT_LOADED); goto done; } /* DSAP's only encrypted paramter is entityValue, so replacing keyHandle inside * rgbWrappedCmdParamIn is ok */ offset = sizeof(UINT16); LoadBlob_UINT32(&offset, tpmKeyHandle, rgbWrappedCmdParamIn); } default: break; } build_command: if ((result = tpm_rqu_build(TPM_ORD_ExecuteTransport, &wrappedOffset, &txBlob[TSS_TXBLOB_WRAPPEDCMD_OFFSET], unWrappedCommandOrdinal, pVal1, pVal2, ulWrappedCmdParamInSize, rgbWrappedCmdParamIn, pWrappedCmdAuth1, pWrappedCmdAuth2))) goto done; /* The blob we'll load here looks like this: * * |TAGet|LENet|ORDet|wrappedCmdSize|wrappedCmd|AUTHet| * * wrappedCmd looks like this: * * |TAGw|LENw|ORDw|HANDLESw|DATAw|AUTH1w|AUTH2w| * * w = wrapped command info * et = execute transport command info * * Note that the wrapped command was loaded into the blob by the tpm_rqu_build call * above. * */ offset = TSS_TPM_TXBLOB_HDR_LEN; /* Load wrapped command size: |wrappedCmdSize| */ LoadBlob_UINT32(&offset, wrappedOffset, txBlob); /* offset + wrappedOffset is the position of the execute transport auth struct */ offset += wrappedOffset; if (pTransAuth) { /* Load the auth for the execute transport command: |AUTHet| */ LoadBlob_Auth(&offset, txBlob, pTransAuth); /* Load the outer header: |TAGet|LENet|ORDet| */ LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ExecuteTransport, txBlob); } else { /* Load the outer header: |TAGet|LENet|ORDet| */ LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_ExecuteTransport, txBlob); } if ((result = req_mgr_submit_req(txBlob))) goto done; /* Unload the Execute Transport (outer) header */ if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto done; } /* The response from the TPM looks like this: * * |TAGet|LENet|RCet|currentTicks|locality|wrappedRspSize|wrappedRsp|AUTHet| * * and wrappedRsp looks like: * * |TAGw|LENw|RCw|HANDLESw|DATAw|AUTH1w|AUTH2w| */ offset = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT64(&offset, punCurrentTicks, txBlob); UnloadBlob_UINT32(&offset, pbLocality, txBlob); /* Unload the wrapped response size: |wrappedRspSize| */ UnloadBlob_UINT32(&offset, &wrappedSize, txBlob); /* We've parsed right up to wrappedRsp, so save off this offset for later */ wrappedOffset = offset; /* The current offset + the response size will be the offset of |AUTHet| */ offset += wrappedSize; if (pTransAuth) UnloadBlob_Auth(&offset, txBlob, pTransAuth); /* Now parse through the returned response @ wrappedOffset */ if ((result = UnloadBlob_Header(&txBlob[wrappedOffset], ¶mSize))) { LogDebugFn("Wrapped command (Ordinal 0x%x) failed: rc=0x%x", unWrappedCommandOrdinal, result); /* This is the result of the wrapped command. If its not success, return its value * in the pulWrappedCmdReturnCode variable and return indicating that the execute * transport command was successful */ *pulWrappedCmdReturnCode = result; *ulWrappedCmdParamOutSize = 0; *rgbWrappedCmdParamOut = NULL; auth_mgr_release_auth(pWrappedCmdAuth1, pWrappedCmdAuth2, hContext); return TSS_SUCCESS; } *pulWrappedCmdReturnCode = TSS_SUCCESS; pVal1 = pVal2 = NULL; switch (unWrappedCommandOrdinal) { /* The commands below have 1 outgoing handle */ case TPM_ORD_LoadKey2: pVal1 = &val1; break; default: break; } result = tpm_rsp_parse(TPM_ORD_ExecuteTransport, &txBlob[wrappedOffset], paramSize, pVal1, pVal2, ulWrappedCmdParamOutSize, rgbWrappedCmdParamOut, pWrappedCmdAuth1, pWrappedCmdAuth2); offset = 0; switch (unWrappedCommandOrdinal) { case TPM_ORD_LoadKey2: { TCS_KEY_HANDLE tcs_handle = NULL_TCS_HANDLE; if ((result = load_key_final(hContext, handle1, &tcs_handle, NULL, val1))) goto done; *rghHandles[0] = tcs_handle; *pulHandleListSize = 1; break; } case TPM_ORD_DSAP: case TPM_ORD_OSAP: case TPM_ORD_OIAP: { UINT32 handle; UnloadBlob_UINT32(&offset, &handle, *rgbWrappedCmdParamOut); result = auth_mgr_add(hContext, handle); break; } default: break; } done: auth_mgr_release_auth(pWrappedCmdAuth1, pWrappedCmdAuth2, hContext); return result; } TSS_RESULT TCSP_ReleaseTransportSigned_Internal(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hSignatureKey, TPM_NONCE* AntiReplayNonce, TPM_AUTH* pKeyAuth, /* in, out */ TPM_AUTH* pTransAuth, /* in, out */ TPM_MODIFIER_INDICATOR* pbLocality, UINT32* pulCurrentTicksSize, BYTE** prgbCurrentTicks, UINT32* pulSignatureSize, BYTE** prgbSignature) { TSS_RESULT result; UINT32 paramSize; UINT64 offset; TPM_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) return result; if (pKeyAuth) { if ((result = auth_mgr_check(hContext, &pKeyAuth->AuthHandle))) return result; } if ((result = ensureKeyIsLoaded(hContext, hSignatureKey, &keySlot))) return result; offset = TSS_TPM_TXBLOB_HDR_LEN; LoadBlob_UINT32(&offset, keySlot, txBlob); LoadBlob(&offset, sizeof(TPM_NONCE), txBlob, (BYTE *)AntiReplayNonce); if (pKeyAuth) { LoadBlob_Auth(&offset, txBlob, pKeyAuth); LoadBlob_Auth(&offset, txBlob, pTransAuth); LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, offset, TPM_ORD_ReleaseTransportSigned, txBlob); } else { LoadBlob_Auth(&offset, txBlob, pTransAuth); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ReleaseTransportSigned, txBlob); } if ((result = req_mgr_submit_req(txBlob))) goto done; if ((result = UnloadBlob_Header(txBlob, ¶mSize))) { LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result); goto done; } /* unconditionally disable our accounting of the session */ ctx_set_transport_disabled(hContext, NULL); offset = TSS_TPM_TXBLOB_HDR_LEN; UnloadBlob_UINT32(&offset, pbLocality, txBlob); *pulCurrentTicksSize = sizeof(TPM_STRUCTURE_TAG) + sizeof(UINT64) + sizeof(UINT16) + sizeof(TPM_NONCE); *prgbCurrentTicks = malloc(*pulCurrentTicksSize); if (*prgbCurrentTicks == NULL) { result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } UnloadBlob(&offset, *pulCurrentTicksSize, txBlob, *prgbCurrentTicks); UnloadBlob_UINT32(&offset, pulSignatureSize, txBlob); *prgbSignature = malloc(*pulSignatureSize); if (*prgbSignature == NULL) { free(*prgbCurrentTicks); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } UnloadBlob(&offset, *pulSignatureSize, txBlob, *prgbSignature); if (pKeyAuth) UnloadBlob_Auth(&offset, txBlob, pKeyAuth); UnloadBlob_Auth(&offset, txBlob, pTransAuth); done: auth_mgr_release_auth(pKeyAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_caps_tpm.c0000664000175000017510000000637213663651711017340 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_GetCapability_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Get Cap"); if ((result = tpm_rqu_build(TPM_ORD_GetCapability, &offset, txBlob, capArea, subCapSize, subCap, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_GetCapability, txBlob, paramSize, respSize, resp, NULL, NULL); } LogResult("Get Cap", result); return result; } TSS_RESULT TCSP_GetCapabilityOwner_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * pOwnerAuth, /* in / out */ TCPA_VERSION * pVersion, /* out */ UINT32 * pNonVolatileFlags, /* out */ UINT32 * pVolatileFlags) /* out */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Getcap owner"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_GetCapabilityOwner, &offset, txBlob, pOwnerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_GetCapabilityOwner, txBlob, paramSize, pVersion, pNonVolatileFlags, pVolatileFlags, pOwnerAuth); } LogResult("GetCapowner", result); done: auth_mgr_release_auth(pOwnerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_SetCapability_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 valueSize, /* in */ BYTE * value, /* in */ TPM_AUTH * pOwnerAuth) /* in, out */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) goto done; if ((pOwnerAuth != NULL) && (result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_SetCapability, &offset, txBlob, capArea, subCapSize, subCap, valueSize, value, pOwnerAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_SetCapability, txBlob, paramSize, pOwnerAuth); } done: auth_mgr_release_auth(pOwnerAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_own.c0000664000175000017510000001057413663651711016334 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" TSS_RESULT TCSP_TakeOwnership_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT16 protocolID, /* in */ UINT32 encOwnerAuthSize, /* in */ BYTE * encOwnerAuth, /* in */ UINT32 encSrkAuthSize, /* in */ BYTE * encSrkAuth, /* in */ UINT32 srkInfoSize, /*in */ BYTE * srkInfo, /*in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * srkKeySize, /*out */ BYTE ** srkKey) /*out */ { UINT64 offset; UINT32 paramSize; TSS_RESULT result; TSS_KEY srkKeyContainer; BYTE fake_pubkey[256] = { 0, }, fake_srk[2048] = { 0, }; BYTE oldAuthDataUsage; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; /* Check on the Atmel Bug Patch */ offset = 0; UnloadBlob_TSS_KEY(&offset, srkInfo, &srkKeyContainer); oldAuthDataUsage = srkKeyContainer.authDataUsage; LogDebug("auth data usage is %.2X", oldAuthDataUsage); offset = 0; if ((result = tpm_rqu_build(TPM_ORD_TakeOwnership, &offset, txBlob, protocolID, encOwnerAuthSize, encOwnerAuth, encSrkAuthSize, encSrkAuth, srkInfoSize, srkInfo, ownerAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { if ((result = tpm_rsp_parse(TPM_ORD_TakeOwnership, txBlob, paramSize, srkKeySize, srkKey, ownerAuth))) goto done; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, *srkKey, &srkKeyContainer))) { *srkKeySize = 0; free(*srkKey); goto done; } if (srkKeyContainer.authDataUsage != oldAuthDataUsage) { LogDebug("AuthDataUsage was changed by TPM. Atmel Bug. Fixing it in PS"); srkKeyContainer.authDataUsage = oldAuthDataUsage; } #ifdef TSS_BUILD_PS { BYTE *save; /* Once the key file is created, it stays forever. There could be * migratable keys in the hierarchy that are still useful to someone. */ result = ps_remove_key(&SRK_UUID); if (result != TSS_SUCCESS && result != TCSERR(TSS_E_PS_KEY_NOTFOUND)) { destroy_key_refs(&srkKeyContainer); LogError("Error removing SRK from key file."); *srkKeySize = 0; free(*srkKey); goto done; } /* Set the SRK pubkey to all 0's before writing the SRK to disk, this is for * privacy reasons as outlined in the TSS spec */ save = srkKeyContainer.pubKey.key; srkKeyContainer.pubKey.key = fake_pubkey; offset = 0; LoadBlob_TSS_KEY(&offset, fake_srk, &srkKeyContainer); if ((result = ps_write_key(&SRK_UUID, &NULL_UUID, NULL, 0, fake_srk, offset))) { destroy_key_refs(&srkKeyContainer); LogError("Error writing SRK to disk"); *srkKeySize = 0; free(*srkKey); goto done; } srkKeyContainer.pubKey.key = save; } #endif if ((result = mc_add_entry_init(SRK_TPM_HANDLE, SRK_TPM_HANDLE, &srkKeyContainer, &SRK_UUID))) { destroy_key_refs(&srkKeyContainer); LogError("Error creating SRK mem cache entry"); *srkKeySize = 0; free(*srkKey); } destroy_key_refs(&srkKeyContainer); } LogResult("TakeOwnership", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_OwnerClear_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering OwnerClear"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_OwnerClear, &offset, txBlob, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_OwnerClear, txBlob, paramSize, ownerAuth); } LogResult("Ownerclear", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_seal.c0000664000175000017510000000671013663651711016452 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_Seal_Internal(UINT32 sealOrdinal, /* in */ TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData) /* out */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Seal"); if (!pubAuth) return TCSERR(TSS_E_BAD_PARAMETER); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &pubAuth->AuthHandle))) goto done; if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; /* XXX What's this check for? */ if (keySlot == 0) { result = TCSERR(TSS_E_FAIL); goto done; } if ((result = tpm_rqu_build(sealOrdinal, &offset, txBlob, keySlot, encAuth.authdata, pcrInfoSize, PcrInfo, inDataSize, inData, pubAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; offset = 10; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(sealOrdinal, txBlob, paramSize, SealedDataSize, SealedData, pubAuth); } LogResult("Seal", result); done: auth_mgr_release_auth(pubAuth, NULL, hContext); return result; } TSS_RESULT TCSP_Unseal_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 SealedDataSize, /* in */ BYTE * SealedData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * dataAuth, /* in, out */ UINT32 * DataSize, /* out */ BYTE ** Data) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Unseal"); if (dataAuth == NULL) return TCSERR(TSS_E_BAD_PARAMETER); if ((result = ctx_verify_context(hContext))) goto done; if (parentAuth != NULL) { LogDebug("Auth used"); if ((result = auth_mgr_check(hContext, &parentAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = auth_mgr_check(hContext, &dataAuth->AuthHandle))) goto done; if ((result = ensureKeyIsLoaded(hContext, parentHandle, &keySlot))) goto done; /* XXX What's this check for? */ if (keySlot == 0) { result = TCSERR(TSS_E_FAIL); goto done; } if ((result = tpm_rqu_build(TPM_ORD_Unseal, &offset, txBlob, keySlot, SealedDataSize, SealedData, parentAuth, dataAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; offset = 10; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Unseal, txBlob, paramSize, DataSize, Data, parentAuth, dataAuth); } LogResult("Unseal", result); done: auth_mgr_release_auth(parentAuth, dataAuth, hContext); return result; } trousers-0.3.15/src/tcs/tcs_auth_mgr.c0000664000175000017510000004373613663651711017174 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "auth_mgr.h" #include "req_mgr.h" MUTEX_DECLARE_EXTERN(tcsp_lock); /* Note: The after taking the auth_mgr_lock in any of the functions below, the * mem_cache_lock cannot be taken without risking a deadlock. So, the auth_mgr * functions must be "self-contained" wrt locking */ /* no locking done in init since its called by only a single thread */ TSS_RESULT auth_mgr_init() { memset(&auth_mgr, 0, sizeof(struct _auth_mgr)); auth_mgr.max_auth_sessions = tpm_metrics.num_auths; auth_mgr.overflow = calloc(TSS_DEFAULT_OVERFLOW_AUTHS, sizeof(COND_VAR *)); if (auth_mgr.overflow == NULL) { LogError("malloc of %zd bytes failed", (TSS_DEFAULT_OVERFLOW_AUTHS * sizeof(COND_VAR *))); return TCSERR(TSS_E_OUTOFMEMORY); } auth_mgr.overflow_size = TSS_DEFAULT_OVERFLOW_AUTHS; auth_mgr.auth_mapper = calloc(TSS_DEFAULT_AUTH_TABLE_SIZE, sizeof(struct auth_map)); if (auth_mgr.auth_mapper == NULL) { LogError("malloc of %zd bytes failed", (TSS_DEFAULT_AUTH_TABLE_SIZE * sizeof(struct auth_map))); return TCSERR(TSS_E_OUTOFMEMORY); } auth_mgr.auth_mapper_size = TSS_DEFAULT_AUTH_TABLE_SIZE; return TSS_SUCCESS; } TSS_RESULT auth_mgr_final() { UINT32 i; /* wake up any sleeping threads, so they can be joined */ for (i = 0; i < auth_mgr.overflow_size; i++) { if (auth_mgr.overflow[i] != NULL) COND_SIGNAL(auth_mgr.overflow[i]); } free(auth_mgr.overflow); free(auth_mgr.auth_mapper); return TSS_SUCCESS; } TSS_RESULT auth_mgr_save_ctx(TCS_CONTEXT_HANDLE hContext) { TSS_RESULT result = TSS_SUCCESS; UINT32 i; for (i = 0; i < auth_mgr.auth_mapper_size; i++) { if (auth_mgr.auth_mapper[i].full == TRUE && auth_mgr.auth_mapper[i].swap == NULL && auth_mgr.auth_mapper[i].tcs_ctx != hContext) { LogDebug("Calling TPM_SaveAuthContext for TCS CTX %x. Swapping out: TCS %x " "TPM %x", hContext, auth_mgr.auth_mapper[i].tcs_ctx, auth_mgr.auth_mapper[i].tpm_handle); if ((result = TPM_SaveAuthContext(auth_mgr.auth_mapper[i].tpm_handle, &auth_mgr.auth_mapper[i].swap_size, &auth_mgr.auth_mapper[i].swap))) { LogDebug("TPM_SaveAuthContext failed: 0x%x", result); return result; } break; } } return result; } /* if there's a TCS context waiting to get auth, wake it up or swap it in */ void auth_mgr_swap_in() { if (auth_mgr.overflow[auth_mgr.of_tail] != NULL) { LogDebug("waking up thread %lddd, auth slot has opened", THREAD_ID); /* wake up the next sleeping thread in order and increment tail */ COND_SIGNAL(auth_mgr.overflow[auth_mgr.of_tail]); auth_mgr.overflow[auth_mgr.of_tail] = NULL; auth_mgr.of_tail = (auth_mgr.of_tail + 1) % auth_mgr.overflow_size; } else { /* else nobody needs to be swapped in, so continue */ LogDebug("no threads need to be signaled."); } } /* we need to swap out an auth context or add a waiting context to the overflow queue */ TSS_RESULT auth_mgr_swap_out(TCS_CONTEXT_HANDLE hContext) { COND_VAR *cond; /* If the TPM can do swapping and it succeeds, return, else cond wait below */ if (tpm_metrics.authctx_swap && !auth_mgr_save_ctx(hContext)) return TSS_SUCCESS; if ((cond = ctx_get_cond_var(hContext)) == NULL) { LogError("Auth swap variable not found for TCS context 0x%x", hContext); return TCSERR(TSS_E_INTERNAL_ERROR); } /* Test whether we are the last awake thread. If we are, we can't go to sleep * since then there'd be no worker thread to wake the others up. This situation * can arise when we're on a busy system who's TPM doesn't support auth ctx * swapping. */ if (auth_mgr.sleeping_threads == (tcsd_options.num_threads - 1)) { LogError("auth mgr failing: too many threads already waiting"); LogTPMERR(TCPA_E_RESOURCES, __FILE__, __LINE__); return TCPA_E_RESOURCES; } if (auth_mgr.overflow[auth_mgr.of_head] == NULL) { auth_mgr.overflow[auth_mgr.of_head] = cond; auth_mgr.of_head = (auth_mgr.of_head + 1) % auth_mgr.overflow_size; /* go to sleep */ LogDebug("thread %lddd going to sleep until auth slot opens", THREAD_ID); auth_mgr.sleeping_threads++; COND_WAIT(cond, &tcsp_lock); auth_mgr.sleeping_threads--; } else if (auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS < UINT_MAX) { COND_VAR **tmp = auth_mgr.overflow; LogDebugFn("Table of sleeping threads is full (%hu), growing to %hu entries", auth_mgr.sleeping_threads, auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS); auth_mgr.overflow = calloc(auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS, sizeof(COND_VAR *)); if (auth_mgr.overflow == NULL) { LogDebugFn("malloc of %zd bytes failed", (auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS) * sizeof(COND_VAR *)); auth_mgr.overflow = tmp; return TCSERR(TSS_E_OUTOFMEMORY); } auth_mgr.overflow_size += TSS_DEFAULT_OVERFLOW_AUTHS; LogDebugFn("Success."); memcpy(auth_mgr.overflow, tmp, auth_mgr.sleeping_threads * sizeof(COND_VAR *)); free(tmp); /* XXX This could temporarily wake threads up out of order */ auth_mgr.of_head = auth_mgr.sleeping_threads; auth_mgr.of_tail = 0; auth_mgr.overflow[auth_mgr.of_head] = cond; auth_mgr.of_head = (auth_mgr.of_head + 1) % auth_mgr.overflow_size; LogDebug("thread %lddd going to sleep until auth slot opens", THREAD_ID); auth_mgr.sleeping_threads++; COND_WAIT(cond, &tcsp_lock); auth_mgr.sleeping_threads--; } else { LogError("Auth table overflow is full (%u entries), some will fail.", auth_mgr.overflow_size); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } /* close all auth contexts associated with this TCS_CONTEXT_HANDLE */ TSS_RESULT auth_mgr_close_context(TCS_CONTEXT_HANDLE tcs_handle) { UINT32 i; TSS_RESULT result; for (i = 0; i < auth_mgr.auth_mapper_size; i++) { if (auth_mgr.auth_mapper[i].full == TRUE && auth_mgr.auth_mapper[i].tcs_ctx == tcs_handle) { if (auth_mgr.auth_mapper[i].swap) { /* This context is swapped out of the TPM, so we can just free the * blob */ free(auth_mgr.auth_mapper[i].swap); auth_mgr.auth_mapper[i].swap = NULL; auth_mgr.auth_mapper[i].swap_size = 0; } else { result = TCSP_FlushSpecific_Common(auth_mgr.auth_mapper[i].tpm_handle, TPM_RT_AUTH); /* Ok, probably dealing with a 1.1 TPM */ if (result == TPM_E_BAD_ORDINAL) result = internal_TerminateHandle( auth_mgr.auth_mapper[i].tpm_handle); if (result == TCPA_E_INVALID_AUTHHANDLE) { LogDebug("Tried to close an invalid auth handle: %x", auth_mgr.auth_mapper[i].tpm_handle); } else if (result != TCPA_SUCCESS) { LogDebug("TPM_TerminateHandle returned %d", result); } } /* clear the slot */ auth_mgr.open_auth_sessions--; auth_mgr.auth_mapper[i].full = FALSE; auth_mgr.auth_mapper[i].tpm_handle = 0; auth_mgr.auth_mapper[i].tcs_ctx = 0; LogDebug("released auth for TCS %x TPM %x", tcs_handle, auth_mgr.auth_mapper[i].tpm_handle); auth_mgr_swap_in(); } } return TSS_SUCCESS; } void auth_mgr_release_auth(TPM_AUTH *auth0, TPM_AUTH *auth1, TCS_CONTEXT_HANDLE tcs_handle) { if (auth0) auth_mgr_release_auth_handle(auth0->AuthHandle, tcs_handle, auth0->fContinueAuthSession); if (auth1) auth_mgr_release_auth_handle(auth1->AuthHandle, tcs_handle, auth1->fContinueAuthSession); } /* unload the auth ctx associated with this auth handle */ TSS_RESULT auth_mgr_release_auth_handle(TCS_AUTHHANDLE tpm_auth_handle, TCS_CONTEXT_HANDLE tcs_handle, TSS_BOOL cont) { UINT32 i; TSS_RESULT result = TSS_SUCCESS; for (i = 0; i < auth_mgr.auth_mapper_size; i++) { if (auth_mgr.auth_mapper[i].full == TRUE && auth_mgr.auth_mapper[i].tpm_handle == tpm_auth_handle && auth_mgr.auth_mapper[i].tcs_ctx == tcs_handle) { if (!cont) { /* * This function should not be necessary, but * if the main operation resulted in an error, * the TPM may still hold the auth handle * and it must be freed. Most of the time * this call will result in TPM_E_INVALID_AUTHHANDLE * error which can be ignored. */ result = TCSP_FlushSpecific_Common( auth_mgr.auth_mapper[i].tpm_handle, TPM_RT_AUTH); /* Ok, probably dealing with a 1.1 TPM */ if (result == TPM_E_BAD_ORDINAL) result = internal_TerminateHandle( auth_mgr.auth_mapper[i].tpm_handle); if (result == TCPA_E_INVALID_AUTHHANDLE) { LogDebug("Tried to close an invalid auth handle: %x", auth_mgr.auth_mapper[i].tpm_handle); } else if (result != TCPA_SUCCESS) { LogDebug("TPM_TerminateHandle returned %d", result); } if (result == TPM_SUCCESS) { LogDebug("released auth for TCS %x TPM %x", auth_mgr.auth_mapper[i].tcs_ctx, tpm_auth_handle); } /* * Mark it as released, the "cont" flag indicates * that it is no longer needed. */ auth_mgr.open_auth_sessions--; auth_mgr.auth_mapper[i].full = FALSE; auth_mgr.auth_mapper[i].tpm_handle = 0; auth_mgr.auth_mapper[i].tcs_ctx = 0; auth_mgr_swap_in(); } /* If the cont flag is TRUE, we have to keep the handle */ } } return result; } TSS_RESULT auth_mgr_check(TCS_CONTEXT_HANDLE tcsContext, TPM_AUTHHANDLE *tpm_auth_handle) { UINT32 i; TSS_RESULT result = TSS_SUCCESS; for (i = 0; i < auth_mgr.auth_mapper_size; i++) { if (auth_mgr.auth_mapper[i].full == TRUE && auth_mgr.auth_mapper[i].tpm_handle == *tpm_auth_handle && auth_mgr.auth_mapper[i].tcs_ctx == tcsContext) { /* We have a record of this session, now swap it into the TPM if need be. */ if (auth_mgr.auth_mapper[i].swap) { LogDebugFn("TPM_LoadAuthContext for TCS %x TPM %x", tcsContext, auth_mgr.auth_mapper[i].tpm_handle); result = TPM_LoadAuthContext(auth_mgr.auth_mapper[i].swap_size, auth_mgr.auth_mapper[i].swap, tpm_auth_handle); if (result == TSS_SUCCESS) { free(auth_mgr.auth_mapper[i].swap); auth_mgr.auth_mapper[i].swap = NULL; auth_mgr.auth_mapper[i].swap_size = 0; LogDebugFn("TPM_LoadAuthContext succeeded. Old TPM: %x, New" " TPM: %x", auth_mgr.auth_mapper[i].tpm_handle, *tpm_auth_handle); auth_mgr.auth_mapper[i].tpm_handle = *tpm_auth_handle; } else if (result == TPM_E_RESOURCES) { if ((result = auth_mgr_swap_out(tcsContext))) { LogDebugFn("TPM_LoadAuthContext failed with TPM_E_R" "ESOURCES and swapping out failed, retur" "ning error"); return result; } LogDebugFn("Retrying TPM_LoadAuthContext after swap" " out..."); result = TPM_LoadAuthContext(auth_mgr.auth_mapper[i].swap_size, auth_mgr.auth_mapper[i].swap, tpm_auth_handle); free(auth_mgr.auth_mapper[i].swap); auth_mgr.auth_mapper[i].swap = NULL; auth_mgr.auth_mapper[i].swap_size = 0; } else { LogDebug("TPM_LoadAuthContext failed: 0x%x.", result); } } return result; } } LogDebugFn("Can't find auth for TCS handle %x, should be %x", tcsContext, *tpm_auth_handle); return TCSERR(TSS_E_INTERNAL_ERROR); } TSS_RESULT auth_mgr_add(TCS_CONTEXT_HANDLE tcsContext, TCS_AUTHHANDLE tpm_auth_handle) { struct auth_map *tmp = auth_mgr.auth_mapper; UINT32 i; for (i = 0; i < auth_mgr.auth_mapper_size; i++) { if (auth_mgr.auth_mapper[i].full == FALSE) { auth_mgr.auth_mapper[i].tpm_handle = tpm_auth_handle; auth_mgr.auth_mapper[i].tcs_ctx = tcsContext; auth_mgr.auth_mapper[i].full = TRUE; auth_mgr.open_auth_sessions++; LogDebug("added auth for TCS %x TPM %x", tcsContext, tpm_auth_handle); return TSS_SUCCESS; } } LogDebugFn("Thread %ld growing the auth table to %u entries", THREAD_ID, auth_mgr.auth_mapper_size + TSS_DEFAULT_AUTH_TABLE_SIZE); auth_mgr.auth_mapper = calloc(auth_mgr.auth_mapper_size + TSS_DEFAULT_AUTH_TABLE_SIZE, sizeof(struct auth_map)); if (auth_mgr.auth_mapper == NULL) { auth_mgr.auth_mapper = tmp; return TCSERR(TSS_E_OUTOFMEMORY); } else { memcpy(auth_mgr.auth_mapper, tmp, auth_mgr.auth_mapper_size * sizeof(struct auth_map)); auth_mgr.auth_mapper_size += TSS_DEFAULT_AUTH_TABLE_SIZE; LogDebugFn("Success."); return TSS_SUCCESS; } } /* A thread wants a new OIAP or OSAP session with the TPM. Returning TRUE indicates that we should * allow it to open the session, FALSE to indicate that the request should be queued or have * another thread's session swapped out to make room for it. */ TSS_BOOL auth_mgr_req_new(TCS_CONTEXT_HANDLE hContext) { UINT32 i, opened = 0; for (i = 0; i < auth_mgr.auth_mapper_size; i++) { if (auth_mgr.auth_mapper[i].full == TRUE && auth_mgr.auth_mapper[i].tcs_ctx == hContext) { opened++; } } /* If this TSP has already opened its max open auth handles, deny another open */ if (opened >= MAX(2, (UINT32)auth_mgr.max_auth_sessions/2)) { LogDebug("Max opened auth handles already opened."); return FALSE; } /* if we have one opened already and there's a slot available, ok */ if (opened && ((auth_mgr.max_auth_sessions - auth_mgr.open_auth_sessions) >= 1)) return TRUE; /* we don't already have one open and there are at least 2 slots left */ if ((auth_mgr.max_auth_sessions - auth_mgr.open_auth_sessions) >= 2) return TRUE; LogDebug("Request for new auth handle denied by TCS. (%d opened sessions)", opened); return FALSE; } TSS_RESULT auth_mgr_oiap(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TCPA_NONCE *nonce0) /* out */ { TSS_RESULT result; /* are the maximum number of auth sessions open? */ if (auth_mgr_req_new(hContext) == FALSE) { if ((result = auth_mgr_swap_out(hContext))) goto done; } if ((result = TCSP_OIAP_Internal(hContext, authHandle, nonce0))) goto done; /* success, add an entry to the table */ result = auth_mgr_add(hContext, *authHandle); done: return result; } TSS_RESULT auth_mgr_osap(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 entityValue, /* in */ TCPA_NONCE nonceOddOSAP, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TCPA_NONCE *nonceEven, /* out */ TCPA_NONCE *nonceEvenOSAP) /* out */ { TSS_RESULT result; UINT32 newEntValue = 0; /* if ET is not KEYHANDLE or KEY, newEntValue is a don't care */ if (entityType == TCPA_ET_KEYHANDLE || entityType == TCPA_ET_KEY) { if (ensureKeyIsLoaded(hContext, entityValue, &newEntValue)) return TCSERR(TSS_E_FAIL); } else { newEntValue = entityValue; } /* are the maximum number of auth sessions open? */ if (auth_mgr_req_new(hContext) == FALSE) { if ((result = auth_mgr_swap_out(hContext))) goto done; } if ((result = TCSP_OSAP_Internal(hContext, entityType, newEntValue, nonceOddOSAP, authHandle, nonceEven, nonceEvenOSAP))) goto done; /* success, add an entry to the table */ result = auth_mgr_add(hContext, *authHandle); done: return result; } /* This function is only called directly from the TSP, we use other internal routines to free * our handles. */ TSS_RESULT TCSP_TerminateHandle_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_AUTHHANDLE handle) /* in */ { TSS_RESULT result; LogDebug("Entering TCSI_TerminateHandle"); if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &handle))) return result; result = auth_mgr_release_auth_handle(handle, hContext, TRUE); LogResult("Terminate Handle", result); return result; } TSS_RESULT TPM_SaveAuthContext(TPM_AUTHHANDLE handle, UINT32 *size, BYTE **blob) { UINT64 offset; UINT32 trash, bsize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; offset = 10; LoadBlob_UINT32(&offset, handle, txBlob); LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_SaveAuthContext, txBlob); if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, &trash); LogDebug("total packet size received from TPM: %u", trash); if (!result) { offset = 10; UnloadBlob_UINT32(&offset, &bsize, txBlob); LogDebug("Reported blob size from TPM: %u", bsize); *blob = malloc(bsize); if (*blob == NULL) { LogError("malloc of %u bytes failed.", bsize); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset, bsize, txBlob, *blob); *size = bsize; } return result; } TSS_RESULT TPM_LoadAuthContext(UINT32 size, BYTE *blob, TPM_AUTHHANDLE *handle) { UINT64 offset; UINT32 trash; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Loading %u byte auth blob back into TPM", size); offset = 10; LoadBlob_UINT32(&offset, size, txBlob); LoadBlob(&offset, size, txBlob, blob); LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_LoadAuthContext, txBlob); if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, &trash); if (!result) { offset = 10; UnloadBlob_UINT32(&offset, handle, txBlob); } return result; } trousers-0.3.15/src/tcs/tcsi_changeauth.c0000664000175000017510000002436713663651711017645 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_ChangeAuth_Internal(TCS_CONTEXT_HANDLE contextHandle, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 encDataSize, /* in */ BYTE *encData, /* in */ TPM_AUTH *ownerAuth, /* in, out */ TPM_AUTH *entityAuth, /* in, out */ UINT32 *outDataSize, /* out */ BYTE **outData /* out */ ) { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE keySlot; TCS_KEY_HANDLE tcsKeyHandleToEvict; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Changeauth"); if ((result = ctx_verify_context(contextHandle))) goto done; if ((result = auth_mgr_check(contextHandle, &ownerAuth->AuthHandle))) goto done; if ((result = auth_mgr_check(contextHandle, &entityAuth->AuthHandle))) goto done; if ((result = ensureKeyIsLoaded(contextHandle, parentHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_ChangeAuth, &offset, txBlob, keySlot, protocolID, newAuth.authdata, entityType, encDataSize, encData, ownerAuth, entityAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_ChangeAuth, txBlob, paramSize, outDataSize, outData, ownerAuth, entityAuth); /* if the malloc above failed, terminate the 2 new auth handles and exit */ if (result) goto done; /* * Check if ET is a key. If it is, we need to * 1 - Evict the key if loaded * 2 - update the mem cache entry */ if (entityType == TCPA_ET_KEYHANDLE || entityType == TCPA_ET_KEY) { LogDebug("entity type is a key. Check if mem cache needs updating..."); tcsKeyHandleToEvict = mc_get_handle_by_encdata(encData); LogDebug("tcsKeyHandle being evicted is %.8X", tcsKeyHandleToEvict); /*--- If it was found in knowledge, replace it */ if (tcsKeyHandleToEvict != 0) { internal_EvictByKeySlot(keySlot); mc_update_encdata(encData, *outData); } } } LogResult("ChangeAuth", result); done: auth_mgr_release_auth(ownerAuth, entityAuth, contextHandle); return result; } TSS_RESULT TCSP_ChangeAuthOwner_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TPM_AUTH * ownerAuth /* in, out */ ) { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering ChangeAuthOwner"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_ChangeAuthOwner, &offset, txBlob, protocolID, newAuth.authdata, entityType, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_ChangeAuthOwner, txBlob, paramSize, ownerAuth); } LogResult("ChangeAuthOwner", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_ChangeAuthAsymStart_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE idHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 KeySizeIn, /* in */ BYTE * KeyDataIn, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * KeySizeOut, /* out */ BYTE ** KeyDataOut, /* out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig, /* out */ TCS_KEY_HANDLE * ephHandle /* out */ ) { #if 0 #warning Locking trouble in evictFirstKey UINT64 offset; UINT32 paramSize; TSS_RESULT result; UINT32 keySlot; TCPA_CERTIFY_INFO certifyInfo; TSS_KEY tempKey; UINT32 tempSize; TCPA_KEY_PARMS keyParmsContainer; TSS_BOOL canLoad; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering ChangeAuthAsymStart"); if ((result = ctx_verify_context(hContext))) goto done; if (pAuth != NULL) { LogDebug("Auth Command"); if ((result = auth_mgr_check(hContext, pAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = ensureKeyIsLoaded(hContext, idHandle, &keySlot))) goto done; LogDebug("Checking for room to load the eph key"); offset = 0; if ((result = UnloadBlob_KEY_PARMS(&offset, KeyDataIn, &keyParmsContainer))) goto done; /* if we can't load the key, evict keys until we can */ if ((result = canILoadThisKey(&keyParmsContainer, &canLoad))) goto done; while (canLoad == FALSE) { /* Evict a key that isn't the parent */ if ((result = evictFirstKey(idHandle))) goto done; if ((result = canILoadThisKey(&keyParmsContainer, &canLoad))) goto done; } offset = 10; LoadBlob_UINT32(&offset, keySlot, txBlob); LoadBlob(&offset, TCPA_NONCE_SIZE, txBlob, antiReplay.nonce); /* LoadBlob_KEY_PARMS( &offset, txBlob, &tempKeyParms ); */ /* LoadBlob_UINT32( &offset, KeySizeIn, txBlob ); */ LoadBlob(&offset, KeySizeIn, txBlob, KeyDataIn); if (pAuth != NULL) { LoadBlob_Auth(&offset, txBlob, pAuth); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ChangeAuthAsymStart, txBlob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_ChangeAuthAsymStart, txBlob); } if ((result = req_mgr_submit_req(txBlob))) goto done; offset = 10; result = UnloadBlob_Header(txBlob, ¶mSize); if (result == 0) { UnloadBlob_CERTIFY_INFO(&offset, txBlob, &certifyInfo); *CertifyInfoSize = offset - 10; *CertifyInfo = malloc(*CertifyInfoSize); if (*CertifyInfo == NULL) { LogError("malloc of %u bytes failed.", *CertifyInfoSize); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*CertifyInfo, &txBlob[offset - *CertifyInfoSize], *CertifyInfoSize); UnloadBlob_UINT32(&offset, sigSize, txBlob); *sig = malloc(*sigSize); if (*sig == NULL) { LogError("malloc of %u bytes failed.", *sigSize); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } UnloadBlob(&offset, *sigSize, txBlob, *sig); UnloadBlob_UINT32(&offset, ephHandle, txBlob); tempSize = offset; UnloadBlob_TSS_KEY(&offset, txBlob, &tempKey); *KeySizeOut = offset - tempSize; *KeyDataOut = malloc(*KeySizeOut); if (*KeyDataOut == NULL) { LogError("malloc of %u bytes failed.", *KeySizeOut); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*KeyDataOut, &txBlob[offset - *KeySizeOut], *KeySizeOut); if (pAuth != NULL) UnloadBlob_Auth(&offset, txBlob, pAuth); } LogResult("ChangeAuthAsymStart", result); done: auth_mgr_release_auth(pAuth, NULL, hContext); return result; #else return TCSERR(TSS_E_NOTIMPL); #endif } TSS_RESULT TCSP_ChangeAuthAsymFinish_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCS_KEY_HANDLE ephHandle, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TCPA_HMAC newAuthLink, /* in */ UINT32 newAuthSize, /* in */ BYTE * encNewAuth, /* in */ UINT32 encDataSizeIn, /* in */ BYTE * encDataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * encDataSizeOut, /* out */ BYTE ** encDataOut, /* out */ TCPA_SALT_NONCE * saltNonce, /* out */ TCPA_DIGEST * changeProof /* out */ ) { #if 0 UINT64 offset; UINT32 paramSize; TSS_RESULT result; UINT32 keySlot; #if 0 TCPA_CERTIFY_INFO certifyInfo; TSS_KEY tempKey; UINT32 tempSize; TSS_UUID *uuidKeyToEvict; #endif TCS_KEY_HANDLE tcsKeyHandleToEvict; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering ChangeAuthAsymFinish"); if ((result = ctx_verify_context(hContext))) goto done; if (ownerAuth != NULL) { LogDebug("Auth used"); if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = ensureKeyIsLoaded(hContext, parentHandle, &keySlot))) goto done; offset = 10; LoadBlob_UINT32(&offset, keySlot, txBlob); LoadBlob_UINT32(&offset, ephHandle, txBlob); LoadBlob_UINT16(&offset, entityType, txBlob); LoadBlob(&offset, 20, txBlob, newAuthLink.digest); LoadBlob_UINT32(&offset, newAuthSize, txBlob); LoadBlob(&offset, newAuthSize, txBlob, encNewAuth); LoadBlob_UINT32(&offset, encDataSizeIn, txBlob); LoadBlob(&offset, encDataSizeIn, txBlob, encDataIn); if (ownerAuth != NULL) { LoadBlob_Auth(&offset, txBlob, ownerAuth); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ChangeAuthAsymFinish, txBlob); } else { LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_ChangeAuthAsymFinish, txBlob); } if ((result = req_mgr_submit_req(txBlob))) goto done; offset = 10; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { UnloadBlob_UINT32(&offset, encDataSizeOut, txBlob); *encDataOut = calloc(1, *encDataSizeOut); if (*encDataOut == NULL) { LogError("malloc of %u bytes failed.", *encDataSizeOut); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } UnloadBlob(&offset, *encDataSizeOut, txBlob, *encDataOut); UnloadBlob(&offset, 20, txBlob, saltNonce->nonce); UnloadBlob(&offset, 20, txBlob, changeProof->digest); if (ownerAuth != NULL) UnloadBlob_Auth(&offset, txBlob, ownerAuth); /* Check if ET is a key. If it is, we need to * 1 - Evict the key if loaded * 2 - update the mem cache entry */ if (entityType == TCPA_ET_KEYHANDLE || entityType == TCPA_ET_KEY) { tcsKeyHandleToEvict = mc_get_handle_by_encdata(encDataIn); /* If it was found in mem cache, replace it */ if (tcsKeyHandleToEvict != 0) { key_mgr_evict(hContext, tcsKeyHandleToEvict); mc_update_encdata(encDataIn, *encDataOut); } } } LogResult("ChangeAuthAsymFinish", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; #else return TCSERR(TSS_E_NOTIMPL); #endif } trousers-0.3.15/src/tcs/tcsi_daa.c0000664000175000017510000001420513663651711016251 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_DaaJoin_internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_HANDLE handle, /* in */ BYTE stage, /* in */ UINT32 inputSize0, /* in */ BYTE *inputData0, /* in */ UINT32 inputSize1, /* in */ BYTE *inputData1, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 *outputSize, /* out */ BYTE **outputData) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ( (result = ctx_verify_context(hContext)) != TSS_SUCCESS) return result; if( (result = auth_mgr_check(hContext, &ownerAuth->AuthHandle)) != TSS_SUCCESS) goto done; #if 0 offset = 10; LoadBlob_UINT32( &offset, handle, txBlob); LogDebug("load BYTE: stage: %x", stage); LoadBlob( &offset, sizeof(BYTE), txBlob, &stage); LogDebug("load UNIT32: inputSize0: %x (oldOffset=%" PRIu64 ")", inputSize0, offset); LoadBlob_UINT32(&offset, inputSize0, txBlob); LogDebug("load Data: inputData0: %X (oldOffset=%" PRIu64 ")", (int)inputData0, offset); LoadBlob(&offset, inputSize0, txBlob, inputData0); LogDebug("load UINT32: inputSize1:%x (oldOffset=%" PRIu64 ")", inputSize1, offset); LoadBlob_UINT32(&offset, inputSize1, txBlob); if( inputSize1>0) { LogDebug("load Data: inputData1: %X (oldOffset=%" PRIu64 ")", (int)inputData1, offset); LoadBlob(&offset, inputSize1, txBlob, inputData1); } LogDebug("load Auth: ownerAuth: %X (oldOffset=%" PRIu64 ")", (int)ownerAuth, offset); LoadBlob_Auth(&offset, txBlob, ownerAuth); LogDebug("load Header: ordinal: %X (oldOffset=%" PRIu64 ")", TPM_ORD_DAA_Join, offset); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_DAA_Join, txBlob); #else if ((result = tpm_rqu_build(TPM_ORD_DAA_Join, &offset, txBlob, handle, stage, inputSize0, inputData0, inputSize1, inputData1, ownerAuth))) goto done; #endif LogDebug("req_mgr_submit_req (oldOffset=%" PRIu64 ")", offset); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("UnloadBlob (paramSize=%d) result=%d", paramSize, result); if (!result) { #if 0 offset = 10; UnloadBlob_UINT32( &offset, outputSize, txBlob); LogDebug("Unload outputSize=%d", *outputSize); *outputData = malloc(*outputSize); if( *outputData == NULL) { LogError("malloc of %u bytes failed.", *outputSize); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } LogDebug("Unload outputData"); UnloadBlob( &offset, *outputSize, txBlob, *outputData); LogDebug("Unload Auth"); UnloadBlob_Auth(&offset, txBlob, ownerAuth); #else result = tpm_rsp_parse(TPM_ORD_DAA_Join, txBlob, paramSize, outputSize, outputData, ownerAuth); #endif } done: LogDebug("Leaving DaaJoin with result:%d", result); auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_DaaSign_internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_HANDLE handle, /* in */ BYTE stage, /* in */ UINT32 inputSize0, /* in */ BYTE *inputData0, /* in */ UINT32 inputSize1, /* in */ BYTE *inputData1, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 *outputSize, /* out */ BYTE **outputData) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ( (result = ctx_verify_context(hContext)) != TSS_SUCCESS) return result; if( (result = auth_mgr_check(hContext, &ownerAuth->AuthHandle)) != TSS_SUCCESS) goto done; #if 0 offset = 10; LoadBlob_UINT32( &offset, handle, txBlob); LogDebug("load BYTE: stage: %x", stage); LoadBlob( &offset, sizeof(BYTE), txBlob, &stage); LogDebug("load UNIT32: inputSize0: %x (oldOffset=%" PRIu64 ")", inputSize0, offset); LoadBlob_UINT32(&offset, inputSize0, txBlob); LogDebug("load Data: inputData0: %X (oldOffset=%" PRIu64 ")", (int)inputData0, offset); LoadBlob(&offset, inputSize0, txBlob, inputData0); LogDebug("load UINT32: inputSize1:%x (oldOffset=%" PRIu64 ")", inputSize1, offset); LoadBlob_UINT32(&offset, inputSize1, txBlob); if( inputSize1>0) { LogDebug("load Data: inputData1: %X (oldOffset=%" PRIu64 ")", (int)inputData1, offset); LoadBlob(&offset, inputSize1, txBlob, inputData1); } LogDebug("load Auth: ownerAuth: %X (oldOffset=%" PRIu64 ")", (int)ownerAuth, offset); LoadBlob_Auth(&offset, txBlob, ownerAuth); LogDebug("load Header: ordinal: %X (oldOffset=%" PRIu64 ")", TPM_ORD_DAA_Sign, offset); LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_DAA_Sign, txBlob); #else if ((result = tpm_rqu_build(TPM_ORD_DAA_Sign, &offset, txBlob, handle, stage, inputSize0, inputData0, inputSize1, inputData1, ownerAuth))) goto done; #endif LogDebug("req_mgr_submit_req (oldOffset=%" PRIu64 ")", offset); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); LogDebug("UnloadBlob (paramSize=%d) result=%d", paramSize, result); if (!result) { #if 0 offset = 10; UnloadBlob_UINT32( &offset, outputSize, txBlob); LogDebug("Unload outputSize=%d", *outputSize); *outputData = malloc(*outputSize); if( *outputData == NULL) { LogError("malloc of %u bytes failed.", *outputSize); result = TCSERR(TSS_E_OUTOFMEMORY); goto done; } LogDebug("Unload outputData"); UnloadBlob(&offset, *outputSize, txBlob, *outputData); LogDebug("Unload Auth"); UnloadBlob_Auth(&offset, txBlob, ownerAuth); #else result = tpm_rsp_parse(TPM_ORD_DAA_Sign, txBlob, paramSize, outputSize, outputData, ownerAuth); #endif } done: LogDebug("Leaving DaaSign with result:%d", result); auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/rpc/0000775000175000017510000000000013663651711015120 5ustar deboradeboratrousers-0.3.15/src/tcs/rpc/tcstp/0000775000175000017510000000000013663651711016255 5ustar deboradeboratrousers-0.3.15/src/tcs/rpc/tcstp/rpc_pcr_extend.c0000664000175000017510000000662213663651711021426 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_Extend(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 pcrIndex; TCPA_DIGEST inDigest; TSS_RESULT result; TCPA_DIGEST outDigest; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &pcrIndex, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 2, &inDigest, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_Extend_Internal(hContext, pcrIndex, inDigest, &outDigest); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_DIGEST, 0, &outDigest, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_PcrRead(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 pcrIndex; TCPA_DIGEST digest; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &pcrIndex, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_PcrRead_Internal(hContext, pcrIndex, &digest); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_DIGEST, 0, &digest, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_PcrReset(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 pcrDataSizeIn; BYTE *pcrDataIn; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &pcrDataSizeIn, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); pcrDataIn = (BYTE *)malloc(pcrDataSizeIn); if (pcrDataIn == NULL) { LogError("malloc of %u bytes failed.", pcrDataSizeIn); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, pcrDataIn, pcrDataSizeIn, &data->comm)) { free(pcrDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_PcrReset_Internal(hContext, pcrDataSizeIn, pcrDataIn); MUTEX_UNLOCK(tcsp_lock); free(pcrDataIn); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return result; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_migration.c0000664000175000017510000002137713663651711021270 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_CreateMigrationBlob(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TCS_KEY_HANDLE parentHandle; TSS_MIGRATE_SCHEME migrationType; UINT32 MigrationKeyAuthSize, encDataSize, randomSize, outDataSize; BYTE *MigrationKeyAuth, *encData, *random, *outData; TPM_AUTH auth1, auth2, *pParentAuth, *pEntityAuth; UINT32 i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &parentHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT16, 2, &migrationType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &MigrationKeyAuthSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MigrationKeyAuth = (BYTE *)malloc(MigrationKeyAuthSize); if (MigrationKeyAuth == NULL) { LogError("malloc of %d bytes failed.", MigrationKeyAuthSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, MigrationKeyAuth, MigrationKeyAuthSize, &data->comm)) { free(MigrationKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 5, &encDataSize, 0, &data->comm)) { free(MigrationKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } encData = (BYTE *)malloc(encDataSize); if (encData == NULL) { free(MigrationKeyAuth); LogError("malloc of %d bytes failed.", encDataSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 6, encData, encDataSize, &data->comm)) { free(MigrationKeyAuth); free(encData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 7, &auth1, 0, &data->comm)) { free(MigrationKeyAuth); free(encData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 8, &auth2, 0, &data->comm)) { /* If loading the 2nd auth fails, the first one was entity auth */ pParentAuth = NULL; pEntityAuth = &auth1; } else { /* If loading the 2nd auth succeeds, the first one was parent auth */ pParentAuth = &auth1; pEntityAuth = &auth2; } MUTEX_LOCK(tcsp_lock); result = TCSP_CreateMigrationBlob_Internal(hContext, parentHandle, migrationType, MigrationKeyAuthSize, MigrationKeyAuth, encDataSize, encData, pParentAuth, pEntityAuth, &randomSize, &random, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(MigrationKeyAuth); free(encData); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 6); if (pParentAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pParentAuth, 0, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_AUTH, i++, pEntityAuth, 0, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &randomSize, 0, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (randomSize > 0) { if (setData(TCSD_PACKET_TYPE_PBYTE, i++, random, randomSize, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outDataSize, 0, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outData, outDataSize, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(random); free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ConvertMigrationBlob(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TCS_KEY_HANDLE parentHandle; UINT32 outDataSize, randomSize, inDataSize; BYTE *outData, *random, *inData; TPM_AUTH parentAuth, *pParentAuth; UINT32 i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &parentHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &inDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); inData = (BYTE *)malloc(inDataSize); if (inData == NULL) { LogError("malloc of %d bytes failed.", inDataSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, inData, inDataSize, &data->comm)) { free(inData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 4, &randomSize, 0, &data->comm)) { free(inData); return TCSERR(TSS_E_INTERNAL_ERROR); } random = (BYTE *)malloc(randomSize); if (random == NULL) { free(inData); LogError("malloc of %d bytes failed.", randomSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, random, randomSize, &data->comm)) { free(inData); free(random); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 6, &parentAuth, 0, &data->comm)) pParentAuth = NULL; else pParentAuth = &parentAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_ConvertMigrationBlob_Internal(hContext, parentHandle, inDataSize, inData, randomSize, random, pParentAuth, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(inData); free(random); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pParentAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pParentAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outDataSize, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outData, outDataSize, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_AuthorizeMigrationKey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TSS_MIGRATE_SCHEME migrateScheme; UINT32 MigrationKeySize, MigrationKeyAuthSize; BYTE *MigrationKey, *MigrationKeyAuth; TPM_AUTH ownerAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT16, 1, &migrateScheme, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &MigrationKeySize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MigrationKey = (BYTE *)malloc(MigrationKeySize); if (MigrationKey == NULL) { LogError("malloc of %d bytes failed.", MigrationKeySize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, MigrationKey, MigrationKeySize, &data->comm)) { free(MigrationKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 4, &ownerAuth, 0, &data->comm)) { free(MigrationKey); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_AuthorizeMigrationKey_Internal(hContext, migrateScheme, MigrationKeySize, MigrationKey, &ownerAuth, &MigrationKeyAuthSize, &MigrationKeyAuth); MUTEX_UNLOCK(tcsp_lock); free(MigrationKey); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { free(MigrationKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &MigrationKeyAuthSize, 0, &data->comm)) { free(MigrationKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, MigrationKeyAuth, MigrationKeyAuthSize, &data->comm)) { free(MigrationKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } free(MigrationKeyAuth); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc.c0000664000175000017510000004755213663651711017222 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #if (defined (__OpenBSD__) || defined (__FreeBSD__)) #include #include #endif #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "rpc_tcstp_tcs.h" /* Lock is not static because we need to reference it in the auth manager */ MUTEX_DECLARE_INIT(tcsp_lock); void LoadBlob_Auth_Special(UINT64 *offset, BYTE *blob, TPM_AUTH *auth) { LoadBlob(offset, TCPA_SHA1BASED_NONCE_LEN, blob, auth->NonceEven.nonce); LoadBlob_BOOL(offset, auth->fContinueAuthSession, blob); LoadBlob(offset, TCPA_SHA1BASED_NONCE_LEN, blob, (BYTE *)&auth->HMAC); } void UnloadBlob_Auth_Special(UINT64 *offset, BYTE *blob, TPM_AUTH *auth) { UnloadBlob_UINT32(offset, &auth->AuthHandle, blob); UnloadBlob(offset, TCPA_SHA1BASED_NONCE_LEN, blob, auth->NonceOdd.nonce); UnloadBlob_BOOL(offset, &auth->fContinueAuthSession, blob); UnloadBlob(offset, TCPA_SHA1BASED_NONCE_LEN, blob, (BYTE *)&auth->HMAC); } int recv_from_socket(int sock, void *buffer, int size) { int recv_size = 0, recv_total = 0; while (recv_total < size) { errno = 0; if ((recv_size = recv(sock, buffer+recv_total, size-recv_total, 0)) <= 0) { if (recv_size < 0) { if (errno == EINTR) continue; LogError("Socket receive connection error: %s.", strerror(errno)); } else { LogDebug("Socket connection closed."); } return -1; } recv_total += recv_size; } return recv_total; } int send_to_socket(int sock, void *buffer, int size) { int send_size = 0, send_total = 0; while (send_total < size) { if ((send_size = send(sock, buffer+send_total, size-send_total, 0)) < 0) { LogError("Socket send connection error: %s.", strerror(errno)); return -1; } send_total += send_size; } return send_total; } void initData(struct tcsd_comm_data *comm, int parm_count) { /* min packet size should be the size of the header */ memset(&comm->hdr, 0, sizeof(struct tcsd_packet_hdr)); comm->hdr.packet_size = sizeof(struct tcsd_packet_hdr); if (parm_count > 0) { comm->hdr.type_offset = sizeof(struct tcsd_packet_hdr); comm->hdr.parm_offset = comm->hdr.type_offset + (sizeof(TCSD_PACKET_TYPE) * parm_count); comm->hdr.packet_size = comm->hdr.parm_offset; } memset(comm->buf, 0, comm->buf_size); } int loadData(UINT64 *offset, TCSD_PACKET_TYPE data_type, void *data, int data_size, BYTE *blob) { switch (data_type) { case TCSD_PACKET_TYPE_BYTE: LoadBlob_BYTE(offset, *((BYTE *) (data)), blob); break; case TCSD_PACKET_TYPE_BOOL: LoadBlob_BOOL(offset, *((TSS_BOOL *) (data)), blob); break; case TCSD_PACKET_TYPE_UINT16: LoadBlob_UINT16(offset, *((UINT16 *) (data)), blob); break; case TCSD_PACKET_TYPE_UINT32: LoadBlob_UINT32(offset, *((UINT32 *) (data)), blob); break; case TCSD_PACKET_TYPE_UINT64: LoadBlob_UINT64(offset, *((UINT64 *) (data)), blob); break; case TCSD_PACKET_TYPE_PBYTE: LoadBlob(offset, data_size, blob, data); break; case TCSD_PACKET_TYPE_NONCE: LoadBlob(offset, sizeof(TCPA_NONCE), blob, ((TCPA_NONCE *)data)->nonce); break; case TCSD_PACKET_TYPE_DIGEST: LoadBlob(offset, sizeof(TCPA_DIGEST), blob, ((TCPA_DIGEST *)data)->digest); break; case TCSD_PACKET_TYPE_AUTH: LoadBlob_Auth_Special(offset, blob, ((TPM_AUTH *)data)); break; #ifdef TSS_BUILD_PS case TCSD_PACKET_TYPE_UUID: LoadBlob_UUID(offset, blob, *((TSS_UUID *)data)); break; case TCSD_PACKET_TYPE_KM_KEYINFO: LoadBlob_KM_KEYINFO(offset, blob, ((TSS_KM_KEYINFO *)data)); break; case TCSD_PACKET_TYPE_KM_KEYINFO2: LoadBlob_KM_KEYINFO2(offset, blob, ((TSS_KM_KEYINFO2 *)data)); break; case TCSD_PACKET_TYPE_LOADKEY_INFO: LoadBlob_LOADKEY_INFO(offset, blob, ((TCS_LOADKEY_INFO *)data)); break; #endif case TCSD_PACKET_TYPE_ENCAUTH: LoadBlob(offset, sizeof(TCPA_ENCAUTH), blob, ((TCPA_ENCAUTH *)data)->authdata); break; case TCSD_PACKET_TYPE_VERSION: LoadBlob_VERSION(offset, blob, ((TPM_VERSION *)data)); break; #ifdef TSS_BUILD_PCR_EVENTS case TCSD_PACKET_TYPE_PCR_EVENT: LoadBlob_PCR_EVENT(offset, blob, ((TSS_PCR_EVENT *)data)); break; #endif case TCSD_PACKET_TYPE_SECRET: LoadBlob(offset, sizeof(TCPA_SECRET), blob, ((TCPA_SECRET *)data)->authdata); break; default: LogError("TCSD packet type unknown! (0x%x)", data_type & 0xff); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } int setData(TCSD_PACKET_TYPE dataType, unsigned int index, void *theData, int theDataSize, struct tcsd_comm_data *comm) { UINT64 old_offset, offset; TSS_RESULT result; TCSD_PACKET_TYPE *type; /* Calculate the size of the area needed (use NULL for blob address) */ offset = 0; if ((result = loadData(&offset, dataType, theData, theDataSize, NULL)) != TSS_SUCCESS) return result; if ((comm->hdr.packet_size + offset) > comm->buf_size) { /* reallocate the buffer */ BYTE *buffer; int buffer_size = comm->hdr.packet_size + offset; LogDebug("Increasing communication buffer to %d bytes.", buffer_size); buffer = realloc(comm->buf, buffer_size); if (buffer == NULL) { LogError("realloc of %d bytes failed.", buffer_size); return TCSERR(TSS_E_INTERNAL_ERROR); } comm->buf_size = buffer_size; comm->buf = buffer; } offset = old_offset = comm->hdr.parm_offset + comm->hdr.parm_size; if ((result = loadData(&offset, dataType, theData, theDataSize, comm->buf)) != TSS_SUCCESS) return result; type = (TCSD_PACKET_TYPE *)(comm->buf + comm->hdr.type_offset) + index; *type = dataType; comm->hdr.type_size += sizeof(TCSD_PACKET_TYPE); comm->hdr.parm_size += (offset - old_offset); comm->hdr.packet_size = offset; comm->hdr.num_parms++; return TSS_SUCCESS; } UINT32 getData(TCSD_PACKET_TYPE dataType, unsigned int index, void *theData, int theDataSize, struct tcsd_comm_data *comm) { UINT64 old_offset, offset; TCSD_PACKET_TYPE *type; if ((comm->hdr.type_offset + index) > comm->buf_size) return TSS_TCP_RPC_BAD_PACKET_TYPE; type = (comm->buf + comm->hdr.type_offset) + index; if ((UINT32)index >= comm->hdr.num_parms || dataType != *type) { LogDebug("Data type of TCS packet element %d doesn't match.", index); return TSS_TCP_RPC_BAD_PACKET_TYPE; } old_offset = offset = comm->hdr.parm_offset; switch (dataType) { case TCSD_PACKET_TYPE_BYTE: if (old_offset + sizeof(BYTE) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob_BYTE(&offset, (BYTE *) (theData), comm->buf); break; case TCSD_PACKET_TYPE_BOOL: if (old_offset + sizeof(TSS_BOOL) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob_BOOL(&offset, (TSS_BOOL *) (theData), comm->buf); break; case TCSD_PACKET_TYPE_UINT16: if (old_offset + sizeof(UINT16) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob_UINT16(&offset, (UINT16 *) (theData), comm->buf); break; case TCSD_PACKET_TYPE_UINT32: if (old_offset + sizeof(UINT32) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob_UINT32(&offset, (UINT32 *) (theData), comm->buf); break; case TCSD_PACKET_TYPE_PBYTE: if (old_offset + theDataSize > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob(&offset, theDataSize, comm->buf, theData); break; case TCSD_PACKET_TYPE_NONCE: if (old_offset + sizeof(TPM_NONCE) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob(&offset, sizeof(TCPA_NONCE), comm->buf, ((TCPA_NONCE *) (theData))->nonce); break; case TCSD_PACKET_TYPE_DIGEST: if (old_offset + sizeof(TPM_DIGEST) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob(&offset, sizeof(TCPA_DIGEST), comm->buf, ((TCPA_DIGEST *) (theData))->digest); break; case TCSD_PACKET_TYPE_AUTH: if ((old_offset + sizeof(TCS_AUTHHANDLE) + sizeof(TPM_BOOL) + (2 * sizeof(TPM_NONCE))) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob_Auth_Special(&offset, comm->buf, ((TPM_AUTH *) theData)); break; case TCSD_PACKET_TYPE_ENCAUTH: if (old_offset + sizeof(TPM_ENCAUTH) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob(&offset, sizeof(TCPA_ENCAUTH), comm->buf, ((TCPA_ENCAUTH *) theData)->authdata); break; case TCSD_PACKET_TYPE_VERSION: if (old_offset + sizeof(TPM_VERSION) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob_VERSION(&offset, comm->buf, ((TPM_VERSION *) theData)); break; #ifdef TSS_BUILD_PS case TCSD_PACKET_TYPE_KM_KEYINFO: UnloadBlob_KM_KEYINFO(&old_offset, comm->buf, NULL); if (old_offset > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); old_offset = offset; UnloadBlob_KM_KEYINFO(&offset, comm->buf, ((TSS_KM_KEYINFO *)theData)); break; case TCSD_PACKET_TYPE_LOADKEY_INFO: UnloadBlob_LOADKEY_INFO(&old_offset, comm->buf, NULL); if (old_offset > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); old_offset = offset; UnloadBlob_LOADKEY_INFO(&offset, comm->buf, ((TCS_LOADKEY_INFO *)theData)); break; case TCSD_PACKET_TYPE_UUID: if (old_offset + sizeof(TSS_UUID) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob_UUID(&offset, comm->buf, (TSS_UUID *) theData); break; #endif #ifdef TSS_BUILD_PCR_EVENTS case TCSD_PACKET_TYPE_PCR_EVENT: { TSS_RESULT result; (void)UnloadBlob_PCR_EVENT(&old_offset, comm->buf, NULL); if (old_offset > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); old_offset = offset; if ((result = UnloadBlob_PCR_EVENT(&offset, comm->buf, ((TSS_PCR_EVENT *)theData)))) return result; break; } #endif case TCSD_PACKET_TYPE_SECRET: if (old_offset + sizeof(TPM_SECRET) > comm->hdr.packet_size) return TCSERR(TSS_E_INTERNAL_ERROR); UnloadBlob(&offset, sizeof(TCPA_SECRET), comm->buf, ((TCPA_SECRET *) theData)->authdata); break; default: LogError("TCSD packet type unknown! (0x%x)", dataType & 0xff); return TCSERR(TSS_E_INTERNAL_ERROR); } comm->hdr.parm_offset = offset; comm->hdr.parm_size -= (offset - old_offset); return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Error(struct tcsd_thread_data *data) { LogError("%s reached.", __FUNCTION__); initData(&data->comm, 0); data->comm.hdr.u.result = TCSERR(TSS_E_FAIL); return TSS_SUCCESS; } /* Dispatch */ typedef struct tdDispatchTable { TSS_RESULT (*Func) (struct tcsd_thread_data *); const char *name; } DispatchTable; DispatchTable tcs_func_table[TCSD_MAX_NUM_ORDS] = { {tcs_wrap_Error,"Error"}, /* 0 */ {tcs_wrap_OpenContext,"OpenContext"}, {tcs_wrap_CloseContext,"CloseContext"}, {tcs_wrap_Error,"Error"}, {tcs_wrap_TCSGetCapability,"TCSGetCapability"}, {tcs_wrap_RegisterKey,"RegisterKey"}, /* 5 */ {tcs_wrap_UnregisterKey,"UnregisterKey"}, {tcs_wrap_EnumRegisteredKeys,"EnumRegisteredKeys"}, {tcs_wrap_Error,"Error"}, {tcs_wrap_GetRegisteredKeyBlob,"GetRegisteredKeyBlob"}, {tcs_wrap_GetRegisteredKeyByPublicInfo,"GetRegisteredKeyByPublicInfo"}, /* 10 */ {tcs_wrap_LoadKeyByBlob,"LoadKeyByBlob"}, {tcs_wrap_LoadKeyByUUID,"LoadKeyByUUID"}, {tcs_wrap_EvictKey,"EvictKey"}, {tcs_wrap_CreateWrapKey,"CreateWrapKey"}, {tcs_wrap_GetPubkey,"GetPubkey"}, /* 15 */ {tcs_wrap_MakeIdentity,"MakeIdentity"}, {tcs_wrap_LogPcrEvent,"LogPcrEvent"}, {tcs_wrap_GetPcrEvent,"GetPcrEvent"}, {tcs_wrap_GetPcrEventsByPcr,"GetPcrEventsByPcr"}, {tcs_wrap_GetPcrEventLog,"GetPcrEventLog"}, /* 20 */ {tcs_wrap_SetOwnerInstall,"SetOwnerInstall"}, {tcs_wrap_TakeOwnership,"TakeOwnership"}, {tcs_wrap_OIAP,"OIAP"}, {tcs_wrap_OSAP,"OSAP"}, {tcs_wrap_ChangeAuth,"ChangeAuth"}, /* 25 */ {tcs_wrap_ChangeAuthOwner,"ChangeAuthOwner"}, {tcs_wrap_Error,"Error"}, {tcs_wrap_Error,"Error"}, {tcs_wrap_TerminateHandle,"TerminateHandle"}, {tcs_wrap_ActivateIdentity,"ActivateIdentity"}, /* 30 */ {tcs_wrap_Extend,"Extend"}, {tcs_wrap_PcrRead,"PcrRead"}, {tcs_wrap_Quote,"Quote"}, {tcs_wrap_DirWriteAuth,"DirWriteAuth"}, {tcs_wrap_DirRead,"DirRead"}, /* 35 */ {tcs_wrap_Seal,"Seal"}, {tcs_wrap_UnSeal,"UnSeal"}, {tcs_wrap_UnBind,"UnBind"}, {tcs_wrap_CreateMigrationBlob,"CreateMigrationBlob"}, {tcs_wrap_ConvertMigrationBlob,"ConvertMigrationBlob"}, /* 40 */ {tcs_wrap_AuthorizeMigrationKey,"AuthorizeMigrationKey"}, {tcs_wrap_CertifyKey,"CertifyKey"}, {tcs_wrap_Sign,"Sign"}, {tcs_wrap_GetRandom,"GetRandom"}, {tcs_wrap_StirRandom,"StirRandom"}, /* 45 */ {tcs_wrap_GetCapability,"GetCapability"}, {tcs_wrap_Error,"Error"}, {tcs_wrap_GetCapabilityOwner,"GetCapabilityOwner"}, {tcs_wrap_CreateEndorsementKeyPair,"CreateEndorsementKeyPair"}, {tcs_wrap_ReadPubek,"ReadPubek"}, /* 50 */ {tcs_wrap_DisablePubekRead,"DisablePubekRead"}, {tcs_wrap_OwnerReadPubek,"OwnerReadPubek"}, {tcs_wrap_SelfTestFull,"SelfTestFull"}, {tcs_wrap_CertifySelfTest,"CertifySelfTest"}, {tcs_wrap_Error,"Error"}, /* 55 */ {tcs_wrap_GetTestResult,"GetTestResult"}, {tcs_wrap_OwnerSetDisable,"OwnerSetDisable"}, {tcs_wrap_OwnerClear,"OwnerClear"}, {tcs_wrap_DisableOwnerClear,"DisableOwnerClear"}, {tcs_wrap_ForceClear,"ForceClear"}, /* 60 */ {tcs_wrap_DisableForceClear,"DisableForceClear"}, {tcs_wrap_PhysicalDisable,"PhysicalDisable"}, {tcs_wrap_PhysicalEnable,"PhysicalEnable"}, {tcs_wrap_PhysicalSetDeactivated,"PhysicalSetDeactivated"}, {tcs_wrap_SetTempDeactivated,"SetTempDeactivated"}, /* 65 */ {tcs_wrap_PhysicalPresence,"PhysicalPresence"}, {tcs_wrap_Error,"Error"}, {tcs_wrap_Error,"Error"}, {tcs_wrap_CreateMaintenanceArchive,"CreateMaintenanceArchive"}, {tcs_wrap_LoadMaintenanceArchive,"LoadMaintenanceArchive"}, /* 70 */ {tcs_wrap_KillMaintenanceFeature,"KillMaintenanceFeature"}, {tcs_wrap_LoadManuMaintPub,"LoadManuMaintPub"}, {tcs_wrap_ReadManuMaintPub,"ReadManuMaintPub"}, {tcs_wrap_DaaJoin,"DaaJoin"}, {tcs_wrap_DaaSign,"DaaSign"}, /* 75 */ {tcs_wrap_SetCapability,"SetCapability"}, {tcs_wrap_ResetLockValue,"ResetLockValue"}, {tcs_wrap_PcrReset,"PcrReset"}, {tcs_wrap_ReadCounter,"ReadCounter"}, {tcs_wrap_CreateCounter,"CreateCounter"}, /* 80 */ {tcs_wrap_IncrementCounter,"IncrementCounter"}, {tcs_wrap_ReleaseCounter,"ReleaseCounter"}, {tcs_wrap_ReleaseCounterOwner,"ReleaseCounterOwner"}, {tcs_wrap_ReadCurrentTicks,"ReadCurrentTicks"}, {tcs_wrap_TickStampBlob,"TicksStampBlob"}, /* 85 */ {tcs_wrap_GetCredential,"GetCredential"}, {tcs_wrap_NV_DefineOrReleaseSpace,"NVDefineOrReleaseSpace"}, {tcs_wrap_NV_WriteValue,"NVWriteValue"}, {tcs_wrap_NV_WriteValueAuth,"NVWriteValueAuth"}, {tcs_wrap_NV_ReadValue,"NVReadValue"}, /* 90 */ {tcs_wrap_NV_ReadValueAuth,"NVReadValueAuth"}, {tcs_wrap_EstablishTransport,"EstablishTransport"}, {tcs_wrap_ExecuteTransport,"ExecuteTransport"}, {tcs_wrap_ReleaseTransportSigned,"ReleaseTransportSigned"}, {tcs_wrap_SetOrdinalAuditStatus,"SetOrdinalAuditStatus"}, /* 95 */ {tcs_wrap_GetAuditDigest,"GetAuditDigest"}, {tcs_wrap_GetAuditDigestSigned,"GetAuditDigestSigned"}, {tcs_wrap_Sealx,"Sealx"}, {tcs_wrap_SetOperatorAuth,"SetOperatorAuth"}, {tcs_wrap_OwnerReadInternalPub,"OwnerReadInternalPub"}, /* 100 */ {tcs_wrap_EnumRegisteredKeys2,"EnumRegisteredKeys2"}, {tcs_wrap_SetTempDeactivated2,"SetTempDeactivated2"}, {tcs_wrap_Delegate_Manage,"Delegate_Manage"}, {tcs_wrap_Delegate_CreateKeyDelegation,"Delegate_CreateKeyDelegation"}, {tcs_wrap_Delegate_CreateOwnerDelegation,"Delegate_CreateOwnerDelegation"}, /* 105 */ {tcs_wrap_Delegate_LoadOwnerDelegation,"Delegate_LoadOwnerDelegation"}, {tcs_wrap_Delegate_ReadTable,"Delegate_ReadTable"}, {tcs_wrap_Delegate_UpdateVerificationCount,"Delegate_UpdateVerificationCount"}, {tcs_wrap_Delegate_VerifyDelegation,"Delegate_VerifyDelegation"}, {tcs_wrap_CreateRevocableEndorsementKeyPair,"CreateRevocableEndorsementKeyPair"}, /* 110 */ {tcs_wrap_RevokeEndorsementKeyPair,"RevokeEndorsementKeyPair"}, {tcs_wrap_Error,"Error - was MakeIdentity2"}, {tcs_wrap_Quote2,"Quote2"}, {tcs_wrap_CMK_SetRestrictions,"CMK_SetRestrictions"}, {tcs_wrap_CMK_ApproveMA,"CMK_ApproveMA"}, /* 115 */ {tcs_wrap_CMK_CreateKey,"CMK_CreateKey"}, {tcs_wrap_CMK_CreateTicket,"CMK_CreateTicket"}, {tcs_wrap_CMK_CreateBlob,"CMK_CreateBlob"}, {tcs_wrap_CMK_ConvertMigration,"CMK_ConvertMigration"}, {tcs_wrap_FlushSpecific,"FlushSpecific"}, /* 120 */ {tcs_wrap_KeyControlOwner, "KeyControlOwner"}, {tcs_wrap_DSAP, "DSAP"} }; int access_control(struct tcsd_thread_data *thread_data) { int i = 0; int is_localhost; struct sockaddr_storage sas; struct sockaddr *sa; socklen_t sas_len = sizeof(sas); if (getpeername(thread_data->sock, (struct sockaddr *)&sas, &sas_len) == -1) { LogError("Error retrieving local socket address: %s", strerror(errno)); return 1; } sa = (struct sockaddr *)&sas; is_localhost = 0; // Check if it's localhost for both inet protocols if (sa->sa_family == AF_INET) { struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; in_addr_t nloopaddr = htonl(INADDR_LOOPBACK); if (memcmp(&sa_in->sin_addr.s_addr, &nloopaddr, sizeof(in_addr_t)) == 0) is_localhost = 1; } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; if (memcmp(&sa_in6->sin6_addr.s6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0) is_localhost = 1; } /* if the request comes from localhost, or is in the accepted ops list, * approve it */ if (is_localhost) return 0; else { while (tcsd_options.remote_ops[i]) { if ((UINT32)tcsd_options.remote_ops[i] == thread_data->comm.hdr.u.ordinal) { LogInfo("Accepted %s operation from %s", tcs_func_table[thread_data->comm.hdr.u.ordinal].name, thread_data->hostname); return 0; } i++; } } return 1; } TSS_RESULT dispatchCommand(struct tcsd_thread_data *data) { UINT64 offset; TSS_RESULT result; /* First, check the ordinal bounds */ if (data->comm.hdr.u.ordinal >= TCSD_MAX_NUM_ORDS) { LogError("Illegal TCSD Ordinal"); return TCSERR(TSS_E_FAIL); } LogDebug("Dispatching ordinal %u (%s)", data->comm.hdr.u.ordinal, tcs_func_table[data->comm.hdr.u.ordinal].name); /* We only need to check access_control if there are remote operations that are defined * in the config file, which means we allow remote connections */ if (tcsd_options.remote_ops[0] && access_control(data)) { LogWarn("Denied %s operation from %s", tcs_func_table[data->comm.hdr.u.ordinal].name, data->hostname); /* set platform header */ memset(&data->comm.hdr, 0, sizeof(data->comm.hdr)); data->comm.hdr.packet_size = sizeof(struct tcsd_packet_hdr); data->comm.hdr.u.result = TCSERR(TSS_E_FAIL); /* set the comm buffer */ memset(data->comm.buf, 0, data->comm.buf_size); offset = 0; LoadBlob_UINT32(&offset, data->comm.hdr.packet_size, data->comm.buf); LoadBlob_UINT32(&offset, data->comm.hdr.u.result, data->comm.buf); return TSS_SUCCESS; } /* Now, dispatch */ if ((result = tcs_func_table[data->comm.hdr.u.ordinal].Func(data)) == TSS_SUCCESS) { /* set the comm buffer */ offset = 0; LoadBlob_UINT32(&offset, data->comm.hdr.packet_size, data->comm.buf); LoadBlob_UINT32(&offset, data->comm.hdr.u.result, data->comm.buf); LoadBlob_UINT32(&offset, data->comm.hdr.num_parms, data->comm.buf); LoadBlob_UINT32(&offset, data->comm.hdr.type_size, data->comm.buf); LoadBlob_UINT32(&offset, data->comm.hdr.type_offset, data->comm.buf); LoadBlob_UINT32(&offset, data->comm.hdr.parm_size, data->comm.buf); LoadBlob_UINT32(&offset, data->comm.hdr.parm_offset, data->comm.buf); } return result; } TSS_RESULT getTCSDPacket(struct tcsd_thread_data *data) { if (data->comm.hdr.packet_size != (UINT32)(data->comm.hdr.parm_offset + data->comm.hdr.parm_size)) { LogError("Invalid packet received by TCSD"); return TCSERR(TSS_E_INTERNAL_ERROR); } /* dispatch the command to the TCS */ return dispatchCommand(data); } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_key.c0000664000175000017510000003141713663651711020063 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_EvictKey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = key_mgr_evict(hContext, hKey); MUTEX_UNLOCK(tcsp_lock); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetPubkey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TPM_AUTH auth; TPM_AUTH *pAuth; UINT32 pubKeySize; BYTE *pubKey; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); result = getData(TCSD_PACKET_TYPE_AUTH, 2, &auth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pAuth = NULL; else if (result) return result; else pAuth = &auth; MUTEX_LOCK(tcsp_lock); result = TCSP_GetPubKey_Internal(hContext, hKey, pAuth, &pubKeySize, &pubKey); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth != NULL) if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(pubKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pubKeySize, 0, &data->comm)) { free(pubKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, pubKey, pubKeySize, &data->comm)) { free(pubKey); return TCSERR(TSS_E_INTERNAL_ERROR); } free(pubKey); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_TerminateHandle(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_AUTHHANDLE authHandle; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &authHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_TerminateHandle_Internal(hContext, authHandle); MUTEX_UNLOCK(tcsp_lock); initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_LoadKeyByBlob(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hUnwrappingKey; UINT32 cWrappedKeyBlob; BYTE *rgbWrappedKeyBlob; TPM_AUTH auth; TCS_KEY_HANDLE phKeyTCSI; TCS_KEY_HANDLE phKeyHMAC; TPM_AUTH *pAuth; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hUnwrappingKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &cWrappedKeyBlob, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbWrappedKeyBlob = calloc(1, cWrappedKeyBlob); if (rgbWrappedKeyBlob == NULL) { LogError("malloc of %d bytes failed.", cWrappedKeyBlob); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, rgbWrappedKeyBlob, cWrappedKeyBlob, &data->comm)) { free(rgbWrappedKeyBlob); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 4, &auth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pAuth = NULL; else if (result) { free(rgbWrappedKeyBlob); return result; } else pAuth = &auth; MUTEX_LOCK(tcsp_lock); result = key_mgr_load_by_blob(hContext, hUnwrappingKey, cWrappedKeyBlob, rgbWrappedKeyBlob, pAuth, &phKeyTCSI, &phKeyHMAC); if (!result) result = ctx_mark_key_loaded(hContext, phKeyTCSI); MUTEX_UNLOCK(tcsp_lock); free(rgbWrappedKeyBlob); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &phKeyTCSI, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &phKeyHMAC, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #ifdef TSS_BUILD_TSS12 TSS_RESULT tcs_wrap_LoadKey2ByBlob(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hUnwrappingKey; UINT32 cWrappedKeyBlob; BYTE *rgbWrappedKeyBlob; TPM_AUTH auth; TCS_KEY_HANDLE phKeyTCSI; TPM_AUTH *pAuth; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hUnwrappingKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &cWrappedKeyBlob, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbWrappedKeyBlob = calloc(1, cWrappedKeyBlob); if (rgbWrappedKeyBlob == NULL) { LogError("malloc of %d bytes failed.", cWrappedKeyBlob); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, rgbWrappedKeyBlob, cWrappedKeyBlob, &data->comm)) { free(rgbWrappedKeyBlob); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 4, &auth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pAuth = NULL; else if (result) { free(rgbWrappedKeyBlob); return result; } else pAuth = &auth; MUTEX_LOCK(tcsp_lock); result = key_mgr_load_by_blob(hContext, hUnwrappingKey, cWrappedKeyBlob, rgbWrappedKeyBlob, pAuth, &phKeyTCSI, NULL); if (!result) result = ctx_mark_key_loaded(hContext, phKeyTCSI); MUTEX_UNLOCK(tcsp_lock); free(rgbWrappedKeyBlob); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 2); if (pAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &phKeyTCSI, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #endif TSS_RESULT tcs_wrap_CreateWrapKey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hWrappingKey; TCPA_ENCAUTH KeyUsageAuth; TCPA_ENCAUTH KeyMigrationAuth; UINT32 keyInfoSize; BYTE *keyInfo; TPM_AUTH *pAuth, auth; UINT32 keyDataSize; BYTE *keyData; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hWrappingKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_ENCAUTH, 2, &KeyUsageAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_ENCAUTH, 3, &KeyMigrationAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 4, &keyInfoSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); keyInfo = calloc(1, keyInfoSize); if (keyInfo == NULL) { LogError("malloc of %d bytes failed.", keyInfoSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, keyInfo, keyInfoSize, &data->comm)) { free(keyInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 6, &auth, 0, &data->comm)) pAuth = NULL; else pAuth = &auth; MUTEX_LOCK(tcsp_lock); result = TCSP_CreateWrapKey_Internal(hContext, hWrappingKey, KeyUsageAuth, KeyMigrationAuth, keyInfoSize, keyInfo, &keyDataSize, &keyData, pAuth); MUTEX_UNLOCK(tcsp_lock); free(keyInfo); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &keyDataSize, 0, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, keyData, keyDataSize, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(keyData); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 2, pAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #ifdef TSS_BUILD_TSS12 TSS_RESULT tcs_wrap_OwnerReadInternalPub(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TPM_AUTH ownerAuth; UINT32 pubKeySize; BYTE *pubKeyData; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_OwnerReadInternalPub_Internal(hContext, hKey, &ownerAuth, &pubKeySize, &pubKeyData); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &pubKeySize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, pubKeyData, pubKeySize, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_KeyControlOwner(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; UINT32 ulPublicKeyLength; BYTE* rgbPublicKey = NULL; UINT32 attribName; TSS_BOOL attribValue; TPM_AUTH ownerAuth; TSS_UUID uuidData; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &ulPublicKeyLength, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbPublicKey = (BYTE *) malloc(ulPublicKeyLength); if (rgbPublicKey == NULL) { LogError("malloc of %u bytes failed.", ulPublicKeyLength); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, rgbPublicKey, ulPublicKeyLength, &data->comm)) { free(rgbPublicKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 4, &attribName, 0, &data->comm)) { free(rgbPublicKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_BOOL, 5, &attribValue, 0, &data->comm)) { free(rgbPublicKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 6, &ownerAuth, 0, &data->comm)) { free(rgbPublicKey); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_KeyControlOwner_Internal(hContext, hKey, ulPublicKeyLength, rgbPublicKey, attribName, attribValue, &ownerAuth, &uuidData); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { free(rgbPublicKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UUID, 1, &uuidData, 0, &data->comm)) { free(rgbPublicKey); return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); free(rgbPublicKey); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #endif trousers-0.3.15/src/tcs/rpc/tcstp/rpc_certify.c0000664000175000017510000000640713663651711020741 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_CertifyKey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE certHandle, keyHandle; TPM_AUTH *pCertAuth = NULL, *pKeyAuth = NULL, certAuth, keyAuth, nullAuth; UINT32 CertifyInfoSize, outDataSize; BYTE *CertifyInfo, *outData; TCPA_NONCE antiReplay; TSS_RESULT result; UINT32 i; memset(&nullAuth, 0, sizeof(TPM_AUTH)); memset(&certAuth, 0, sizeof(TPM_AUTH)); memset(&keyAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &certHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &keyHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 3, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 4, &certAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 5, &keyAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (memcmp(&nullAuth, &certAuth, sizeof(TPM_AUTH))) pCertAuth = &certAuth; if (memcmp(&nullAuth, &keyAuth, sizeof(TPM_AUTH))) pKeyAuth = &keyAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_CertifyKey_Internal(hContext, certHandle, keyHandle, antiReplay, pCertAuth, pKeyAuth, &CertifyInfoSize, &CertifyInfo, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 6); if (pCertAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pCertAuth, 0, &data->comm)) { free(CertifyInfo); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (pKeyAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pKeyAuth, 0, &data->comm)) { free(CertifyInfo); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &CertifyInfoSize, 0, &data->comm)) { free(CertifyInfo); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, CertifyInfo, CertifyInfoSize, &data->comm)) { free(CertifyInfo); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(CertifyInfo); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outDataSize, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outData, outDataSize, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_auth.c0000664000175000017510000000556113663651711020235 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_OIAP(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_AUTHHANDLE authHandle; TCPA_NONCE n0; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = auth_mgr_oiap(hContext, &authHandle, &n0); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &authHandle, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_NONCE, 1, &n0, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_OSAP(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_ENTITY_TYPE entityType; UINT32 entityValue; TCPA_NONCE nonceOddOSAP; TCS_AUTHHANDLE authHandle; TCPA_NONCE nonceEven; TCPA_NONCE nonceEvenOSAP; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT16, 1, &entityType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &entityValue, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 3, &nonceOddOSAP, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = auth_mgr_osap(hContext, entityType, entityValue, nonceOddOSAP, &authHandle, &nonceEven, &nonceEvenOSAP); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &authHandle, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_NONCE, 1, &nonceEven, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_NONCE, 2, &nonceEvenOSAP, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_dir.c0000664000175000017510000000476313663651711020055 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_DirWriteAuth(struct tcsd_thread_data *data) { TSS_RESULT result; TSS_HCONTEXT hContext; TCPA_DIRINDEX dirIndex; TCPA_DIGEST dirDigest; TPM_AUTH auth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &dirIndex, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 2, &dirDigest, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 3, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_DirWriteAuth_Internal(hContext, dirIndex, dirDigest, &auth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_DirRead(struct tcsd_thread_data *data) { TSS_RESULT result; TSS_HCONTEXT hContext; TCPA_DIRINDEX dirIndex; TCPA_DIRVALUE dirValue; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &dirIndex, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_DirRead_Internal(hContext, dirIndex, &dirValue); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_DIGEST, 0, &dirValue, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_cmk.c0000664000175000017510000004062313663651711020044 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_CMK_SetRestrictions(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_CMK_DELEGATE restriction; TPM_AUTH ownerAuth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &restriction, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_CMK_SetRestrictions_Internal(hContext, restriction, &ownerAuth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CMK_ApproveMA(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_DIGEST migAuthorityDigest; TPM_AUTH ownerAuth; TPM_HMAC migAuthorityApproval; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_DIGEST, 1, &migAuthorityDigest, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_CMK_ApproveMA_Internal(hContext, migAuthorityDigest, &ownerAuth, &migAuthorityApproval); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 1, &migAuthorityApproval, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CMK_CreateKey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TPM_ENCAUTH keyUsageAuth; TPM_HMAC migAuthorityApproval; TPM_DIGEST migAuthorityDigest; UINT32 keyDataSize; BYTE *keyData; TPM_AUTH parentAuth, nullAuth, *pAuth; TSS_RESULT result; memset(&parentAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_ENCAUTH, 2, &keyUsageAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 3, &migAuthorityApproval, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 4, &migAuthorityDigest, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 5, &keyDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); keyData = malloc(keyDataSize); if (keyData == NULL) { LogError("malloc of %u bytes failed.", keyDataSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 6, keyData, keyDataSize, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 7, &parentAuth, 0, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &parentAuth, sizeof(TPM_AUTH))) pAuth = &parentAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_CMK_CreateKey_Internal(hContext, hKey, keyUsageAuth, migAuthorityApproval, migAuthorityDigest, &keyDataSize, &keyData, pAuth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &keyDataSize, 0, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, keyData, keyDataSize, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(keyData); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 2, pAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CMK_CreateTicket(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 publicVerifyKeySize; BYTE *publicVerifyKey; TPM_DIGEST signedData; UINT32 sigValueSize; BYTE *sigValue; TPM_AUTH ownerAuth; TPM_HMAC sigTicket; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &publicVerifyKeySize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); publicVerifyKey = malloc(publicVerifyKeySize); if (publicVerifyKey == NULL) { LogError("malloc of %u bytes failed.", publicVerifyKeySize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, publicVerifyKey, publicVerifyKeySize, &data->comm)) { free(publicVerifyKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_DIGEST, 3, &signedData, 0, &data->comm)) { free(publicVerifyKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 4, &sigValueSize, 0, &data->comm)) { free(publicVerifyKey); return TCSERR(TSS_E_INTERNAL_ERROR); } sigValue = malloc(sigValueSize); if (sigValue == NULL) { LogError("malloc of %u bytes failed.", sigValueSize); free(publicVerifyKey); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, sigValue, sigValueSize, &data->comm)) { free(publicVerifyKey); free(sigValue); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 6, &ownerAuth, 0, &data->comm)) { free(publicVerifyKey); free(sigValue); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_CMK_CreateTicket_Internal(hContext, publicVerifyKeySize, publicVerifyKey, signedData, sigValueSize, sigValue, &ownerAuth, &sigTicket); MUTEX_UNLOCK(tcsp_lock); free(publicVerifyKey); free(sigValue); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 1, &sigTicket, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CMK_CreateBlob(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; UINT16 migrationType; UINT32 migKeyAuthSize; BYTE *migKeyAuth; TPM_DIGEST pubSourceKeyDigest; UINT32 msaListSize, restrictTicketSize, sigTicketSize, encDataSize; BYTE *msaList, *restrictTicket, *sigTicket, *encData; TPM_AUTH parentAuth, nullAuth, *pAuth; UINT32 randomSize, outDataSize; BYTE *random, *outData; TSS_RESULT result; int i; memset(&parentAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT16, 2, &migrationType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &migKeyAuthSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); migKeyAuth = malloc(migKeyAuthSize); if (migKeyAuth == NULL) { LogError("malloc of %u bytes failed.", migKeyAuthSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, migKeyAuth, migKeyAuthSize, &data->comm)) { free(migKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_DIGEST, 5, &pubSourceKeyDigest, 0, &data->comm)) { free(migKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 6, &msaListSize, 0, &data->comm)) { free(migKeyAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } msaList = malloc(msaListSize); if (msaList == NULL) { LogError("malloc of %u bytes failed.", msaListSize); free(migKeyAuth); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 7, msaList, msaListSize, &data->comm)) { free(migKeyAuth); free(msaList); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 8, &restrictTicketSize, 0, &data->comm)) { free(migKeyAuth); free(msaList); return TCSERR(TSS_E_INTERNAL_ERROR); } restrictTicket = malloc(restrictTicketSize); if (restrictTicket == NULL) { LogError("malloc of %u bytes failed.", restrictTicketSize); free(migKeyAuth); free(msaList); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 9, restrictTicket, restrictTicketSize, &data->comm)) { free(migKeyAuth); free(msaList); free(restrictTicket); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 10, &sigTicketSize, 0, &data->comm)) { free(migKeyAuth); free(msaList); free(restrictTicket); return TCSERR(TSS_E_INTERNAL_ERROR); } sigTicket = malloc(sigTicketSize); if (sigTicket == NULL) { LogError("malloc of %u bytes failed.", sigTicketSize); free(migKeyAuth); free(msaList); free(restrictTicket); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 11, sigTicket, sigTicketSize, &data->comm)) { free(migKeyAuth); free(msaList); free(restrictTicket); free(sigTicket); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 12, &encDataSize, 0, &data->comm)) { free(migKeyAuth); free(msaList); free(restrictTicket); free(sigTicket); return TCSERR(TSS_E_INTERNAL_ERROR); } encData = malloc(encDataSize); if (encData == NULL) { LogError("malloc of %u bytes failed.", encDataSize); free(migKeyAuth); free(msaList); free(restrictTicket); free(sigTicket); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 13, encData, encDataSize, &data->comm)) { free(migKeyAuth); free(msaList); free(restrictTicket); free(sigTicket); free(encData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 14, &parentAuth, 0, &data->comm)) { free(migKeyAuth); free(msaList); free(restrictTicket); free(sigTicket); free(encData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &parentAuth, sizeof(TPM_AUTH))) pAuth = &parentAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_CMK_CreateBlob_Internal(hContext, hKey, migrationType, migKeyAuthSize, migKeyAuth, pubSourceKeyDigest, msaListSize, msaList, restrictTicketSize, restrictTicket, sigTicketSize, sigTicket, encDataSize, encData, pAuth, &randomSize, &random, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(migKeyAuth); free(msaList); free(restrictTicket); free(sigTicket); free(encData); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 5); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &randomSize, 0, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, random, randomSize, &data->comm)) { free(random); free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(random); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outDataSize, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outData, outDataSize, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CMK_ConvertMigration(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TPM_CMK_AUTH restrictTicket; TPM_HMAC sigTicket; UINT32 keyDataSize, msaListSize, randomSize; BYTE *keyData, *msaList, *random; TPM_AUTH parentAuth, nullAuth, *pAuth; UINT32 outDataSize; BYTE *outData; TSS_RESULT result; int i; memset(&parentAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_PBYTE, 2, &restrictTicket, sizeof(restrictTicket), &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 3, &sigTicket, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 4, &keyDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); keyData = malloc(keyDataSize); if (keyData == NULL) { LogError("malloc of %u bytes failed.", keyDataSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, keyData, keyDataSize, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 6, &msaListSize, 0, &data->comm)) { free(keyData); return TCSERR(TSS_E_INTERNAL_ERROR); } msaList = malloc(msaListSize); if (msaList == NULL) { LogError("malloc of %u bytes failed.", msaListSize); free(keyData); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 7, msaList, msaListSize, &data->comm)) { free(keyData); free(msaList); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 8, &randomSize, 0, &data->comm)) { free(keyData); free(msaList); return TCSERR(TSS_E_INTERNAL_ERROR); } random = malloc(randomSize); if (random == NULL) { LogError("malloc of %u bytes failed.", randomSize); free(keyData); free(msaList); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 9, random, randomSize, &data->comm)) { free(keyData); free(msaList); free(random); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 10, &parentAuth, 0, &data->comm)) { free(keyData); free(msaList); free(random); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &parentAuth, sizeof(TPM_AUTH))) pAuth = &parentAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_CMK_ConvertMigration_Internal(hContext, hKey, restrictTicket, sigTicket, keyDataSize, keyData, msaListSize, msaList, randomSize, random, pAuth, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(keyData); free(msaList); free(random); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outDataSize, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outData, outDataSize, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_delegate.c0000664000175000017510000003644613663651711021054 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_Delegate_Manage(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_FAMILY_ID familyId; TPM_FAMILY_OPERATION opFlag; UINT32 opDataSize; BYTE *opData; TPM_AUTH ownerAuth, nullAuth, *pAuth; UINT32 retDataSize; BYTE *retData; TSS_RESULT result; int i; memset(&ownerAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &familyId, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &opFlag, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &opDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); opData = malloc(opDataSize); if (opData == NULL) { LogError("malloc of %u bytes failed.", opDataSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, opData, opDataSize, &data->comm)) { free(opData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 5, &ownerAuth, 0, &data->comm)) { free(opData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &ownerAuth, sizeof(TPM_AUTH))) pAuth = &ownerAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_Delegate_Manage_Internal(hContext, familyId, opFlag, opDataSize, opData, pAuth, &retDataSize, &retData); MUTEX_UNLOCK(tcsp_lock); free(opData); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(retData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &retDataSize, 0, &data->comm)) { free(retData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, retData, retDataSize, &data->comm)) { free(retData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(retData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Delegate_CreateKeyDelegation(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; UINT32 publicInfoSize; BYTE *publicInfo; TPM_ENCAUTH encDelAuth; TPM_AUTH keyAuth, nullAuth, *pAuth; UINT32 blobSize; BYTE *blob; TSS_RESULT result; int i; memset(&keyAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &publicInfoSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); publicInfo = malloc(publicInfoSize); if (publicInfo == NULL) { LogError("malloc of %u bytes failed.", publicInfoSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, publicInfo, publicInfoSize, &data->comm)) { free(publicInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_ENCAUTH, 4, &encDelAuth, 0, &data->comm)) { free(publicInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 5, &keyAuth, 0, &data->comm)) { free(publicInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &keyAuth, sizeof(TPM_AUTH))) pAuth = &keyAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_Delegate_CreateKeyDelegation_Internal(hContext, hKey, publicInfoSize, publicInfo, &encDelAuth, pAuth, &blobSize, &blob); MUTEX_UNLOCK(tcsp_lock); free(publicInfo); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &blobSize, 0, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, blob, blobSize, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } free(blob); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Delegate_CreateOwnerDelegation(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_BOOL increment; UINT32 publicInfoSize; BYTE *publicInfo; TPM_ENCAUTH encDelAuth; TPM_AUTH ownerAuth, nullAuth, *pAuth; UINT32 blobSize; BYTE *blob; TSS_RESULT result; int i; memset(&ownerAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_BOOL, 1, &increment, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &publicInfoSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); publicInfo = malloc(publicInfoSize); if (publicInfo == NULL) { LogError("malloc of %u bytes failed.", publicInfoSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, publicInfo, publicInfoSize, &data->comm)) { free(publicInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_ENCAUTH, 4, &encDelAuth, 0, &data->comm)) { free(publicInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 5, &ownerAuth, 0, &data->comm)) { free(publicInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &ownerAuth, sizeof(TPM_AUTH))) pAuth = &ownerAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_Delegate_CreateOwnerDelegation_Internal(hContext, increment, publicInfoSize, publicInfo, &encDelAuth, pAuth, &blobSize, &blob); MUTEX_UNLOCK(tcsp_lock); free(publicInfo); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &blobSize, 0, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, blob, blobSize, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } free(blob); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Delegate_LoadOwnerDelegation(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_DELEGATE_INDEX index; UINT32 blobSize; BYTE *blob; TPM_AUTH ownerAuth, nullAuth, *pAuth; TSS_RESULT result; memset(&ownerAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &index, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &blobSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); blob = malloc(blobSize); if (blob == NULL) { LogError("malloc of %u bytes failed.", blobSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, blob, blobSize, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 4, &ownerAuth, 0, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &ownerAuth, sizeof(TPM_AUTH))) pAuth = &ownerAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_Delegate_LoadOwnerDelegation_Internal(hContext, index, blobSize, blob, pAuth); MUTEX_UNLOCK(tcsp_lock); free(blob); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Delegate_ReadTable(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 familyTableSize; BYTE *familyTable; UINT32 delegateTableSize; BYTE *delegateTable; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_Delegate_ReadTable_Internal(hContext, &familyTableSize, &familyTable, &delegateTableSize, &delegateTable); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 4); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &familyTableSize, 0, &data->comm)) { free(familyTable); free(delegateTable); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, familyTable, familyTableSize, &data->comm)) { free(familyTable); free(delegateTable); return TCSERR(TSS_E_INTERNAL_ERROR); } free(familyTable); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &delegateTableSize, 0, &data->comm)) { free(delegateTable); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 3, delegateTable, delegateTableSize, &data->comm)) { free(delegateTable); return TCSERR(TSS_E_INTERNAL_ERROR); } free(delegateTable); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Delegate_UpdateVerificationCount(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 inputSize; BYTE *input; TPM_AUTH ownerAuth, nullAuth, *pAuth; UINT32 outputSize; BYTE *output; TSS_RESULT result; int i; memset(&ownerAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &inputSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); input = malloc(inputSize); if (input == NULL) { LogError("malloc of %u bytes failed.", inputSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, input, inputSize, &data->comm)) { free(input); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 3, &ownerAuth, 0, &data->comm)) { free(input); return TCSERR(TSS_E_INTERNAL_ERROR); } if (memcmp(&nullAuth, &ownerAuth, sizeof(TPM_AUTH))) pAuth = &ownerAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_Delegate_UpdateVerificationCount_Internal(hContext, inputSize, input, pAuth, &outputSize, &output); MUTEX_UNLOCK(tcsp_lock); free(input); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(output); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outputSize, 0, &data->comm)) { free(output); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, output, outputSize, &data->comm)) { free(output); return TCSERR(TSS_E_INTERNAL_ERROR); } free(output); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Delegate_VerifyDelegation(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 delegateSize; BYTE *delegate; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &delegateSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); delegate = malloc(delegateSize); if (delegate == NULL) { LogError("malloc of %u bytes failed.", delegateSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, delegate, delegateSize, &data->comm)) { free(delegate); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_Delegate_VerifyDelegation_Internal(hContext, delegateSize, delegate); MUTEX_UNLOCK(tcsp_lock); free(delegate); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_DSAP(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT16 entityType; TCS_KEY_HANDLE keyHandle; TPM_NONCE nonceOddDSAP, nonceEven, nonceEvenDSAP; UINT32 entityValueSize; BYTE *entityValue; TCS_AUTHHANDLE authHandle; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT16, 1, &entityType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &keyHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 3, &nonceOddDSAP, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 4, &entityValueSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); entityValue = malloc(entityValueSize); if (entityValue == NULL) { LogError("malloc of %u bytes failed.", entityValueSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, entityValue, entityValueSize, &data->comm)) { free(entityValue); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_DSAP_Internal(hContext, entityType, keyHandle, &nonceOddDSAP, entityValueSize, entityValue, &authHandle, &nonceEven, &nonceEvenDSAP); MUTEX_UNLOCK(tcsp_lock); free(entityValue); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &authHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 1, &nonceEven, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 2, &nonceEvenDSAP, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_random.c0000664000175000017510000000513213663651711020546 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_GetRandom(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 bytesRequested; BYTE *randomBytes = NULL; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &bytesRequested, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_GetRandom_Internal(hContext, &bytesRequested, &randomBytes); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &bytesRequested, 0, &data->comm)) { free(randomBytes); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, randomBytes, bytesRequested, &data->comm)) { free(randomBytes); return TCSERR(TSS_E_INTERNAL_ERROR); } free(randomBytes); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_StirRandom(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 inDataSize; BYTE *inData; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &inDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); inData = calloc(1, inDataSize); if (inData == NULL) { LogError("malloc of %d bytes failed.", inDataSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, inData, inDataSize, &data->comm)) { free(inData); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_StirRandom_Internal(hContext, inDataSize, inData); MUTEX_UNLOCK(tcsp_lock); free(inData); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_bind.c0000664000175000017510000000472613663651711020212 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_UnBind(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE keyHandle; UINT32 inDataSize; BYTE *inData; TPM_AUTH privAuth; TPM_AUTH *pPrivAuth; UINT32 outDataSize; BYTE *outData; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &inDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); inData = calloc(1, inDataSize); if (inData == NULL) { LogError("malloc of %u bytes failed.", inDataSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, inData, inDataSize, &data->comm)) { free(inData); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 4, &privAuth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pPrivAuth = NULL; else if (result) { free(inData); return result; } else pPrivAuth = &privAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_UnBind_Internal(hContext, keyHandle, inDataSize, inData, pPrivAuth, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(inData); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pPrivAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pPrivAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outDataSize, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outData, outDataSize, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_context.c0000664000175000017510000000372313663651711020756 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_OpenContext(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; UINT32 tpm_version = tpm_metrics.version.minor; LogDebugFn("thread %ld", THREAD_ID); result = TCS_OpenContext_Internal(&hContext); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &tpm_version, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); /* Set the context in the thread's object. Later, if something goes wrong * and the connection can't be closed cleanly, we'll still have a reference * to what resources need to be freed. */ data->context = hContext; LogDebug("New context is 0x%x", hContext); } else initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CloseContext(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); result = TCS_CloseContext_Internal(hContext); /* This will signal the thread that the connection has been closed cleanly */ if (result == TSS_SUCCESS) data->context = NULL_TCS_HANDLE; initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_quote.c0000664000175000017510000000617013663651711020426 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_Quote(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TCPA_NONCE antiReplay; UINT32 pcrDataSizeIn; BYTE *pcrDataIn; TPM_AUTH privAuth; TPM_AUTH *pPrivAuth; UINT32 pcrDataSizeOut; BYTE *pcrDataOut; UINT32 sigSize; BYTE *sig; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 2, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &pcrDataSizeIn, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); pcrDataIn = (BYTE *)calloc(1, pcrDataSizeIn); if (pcrDataIn == NULL) { LogError("malloc of %d bytes failed.", pcrDataSizeIn); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, pcrDataIn, pcrDataSizeIn, &data->comm)) { free(pcrDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 5, &privAuth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pPrivAuth = NULL; else if (result) { free(pcrDataIn); return result; } else pPrivAuth = &privAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_Quote_Internal(hContext, hKey, antiReplay, pcrDataSizeIn, pcrDataIn, pPrivAuth, &pcrDataSizeOut, &pcrDataOut, &sigSize, &sig); MUTEX_UNLOCK(tcsp_lock); free(pcrDataIn); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 5); if (pPrivAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pPrivAuth, 0, &data->comm)) { free(pcrDataOut); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pcrDataSizeOut, 0, &data->comm)) { free(pcrDataOut); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, pcrDataOut, pcrDataSizeOut, &data->comm)) { free(pcrDataOut); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &sigSize, 0, &data->comm)) { free(pcrDataOut); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, sig, sigSize, &data->comm)) { free(pcrDataOut); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } free(pcrDataOut); free(sig); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_seal.c0000664000175000017510000001433513663651711020217 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_common_Seal(UINT32 sealOrdinal, struct tcsd_thread_data *data) { TSS_RESULT result; TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE keyHandle; TCPA_ENCAUTH KeyUsageAuth; UINT32 PCRInfoSize, inDataSize; BYTE *PCRInfo = NULL, *inData = NULL; TPM_AUTH emptyAuth, pubAuth, *pAuth; UINT32 outDataSize; BYTE *outData; int i = 0; memset(&emptyAuth, 0, sizeof(TPM_AUTH)); memset(&pubAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, i++, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, i++, &keyHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_ENCAUTH, i++, &KeyUsageAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, i++, &PCRInfoSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (PCRInfoSize > 0) { PCRInfo = calloc(1, PCRInfoSize); if (PCRInfo == NULL) { LogError("malloc of %u bytes failed.", PCRInfoSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, PCRInfo, PCRInfoSize, &data->comm)) { free(PCRInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, &inDataSize, 0, &data->comm)) { free(PCRInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (inDataSize > 0) { inData = calloc(1, inDataSize); if (inData == NULL) { LogError("malloc of %u bytes failed.", inDataSize); free(PCRInfo); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, inData, inDataSize, &data->comm)) { free(inData); free(PCRInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } } result = getData(TCSD_PACKET_TYPE_AUTH, i++, &pubAuth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pAuth = NULL; else if (result) { free(inData); free(PCRInfo); return result; } else pAuth = &pubAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_Seal_Internal(sealOrdinal, hContext, keyHandle, KeyUsageAuth, PCRInfoSize, PCRInfo, inDataSize, inData, pAuth, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(inData); free(PCRInfo); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (pAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &outDataSize, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, outData, outDataSize, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_Seal(struct tcsd_thread_data *data) { return tcs_common_Seal(TPM_ORD_Seal, data); } #ifdef TSS_BUILD_SEALX TSS_RESULT tcs_wrap_Sealx(struct tcsd_thread_data *data) { return tcs_common_Seal(TPM_ORD_Sealx, data); } #endif TSS_RESULT tcs_wrap_UnSeal(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE parentHandle; UINT32 inDataSize; BYTE *inData; TPM_AUTH parentAuth, dataAuth, emptyAuth; TPM_AUTH *pParentAuth, *pDataAuth; UINT32 outDataSize; BYTE *outData; TSS_RESULT result; memset(&emptyAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &parentHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &inDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); inData = calloc(1, inDataSize); if (inData == NULL) { LogError("malloc of %d bytes failed.", inDataSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, inData, inDataSize, &data->comm)) { free(inData); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 4, &parentAuth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pParentAuth = NULL; else if (result) { free(inData); return result; } else pParentAuth = &parentAuth; result = getData(TCSD_PACKET_TYPE_AUTH, 5, &dataAuth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) { pDataAuth = pParentAuth; pParentAuth = NULL; } else if (result) { free(inData); return result; } else pDataAuth = &dataAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_Unseal_Internal(hContext, parentHandle, inDataSize, inData, pParentAuth, pDataAuth, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(inData); if (result == TSS_SUCCESS) { initData(&data->comm, 4); if (pParentAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pParentAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } else { if (setData(TCSD_PACKET_TYPE_AUTH, 0, &emptyAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_AUTH, 1, &dataAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 2, &outDataSize, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 3, outData, outDataSize, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_ps.c0000664000175000017510000003605713663651711017722 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_RegisterKey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_UUID WrappingKeyUUID; TSS_UUID KeyUUID; UINT32 cKeySize; BYTE *rgbKey; UINT32 cVendorData; BYTE *gbVendorData; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UUID, 1, &WrappingKeyUUID, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UUID, 2, &KeyUUID, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &cKeySize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbKey = calloc(1, cKeySize); if (rgbKey == NULL) { LogError("malloc of %d bytes failed.", cKeySize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, rgbKey, cKeySize, &data->comm)) { free(rgbKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 5, &cVendorData, 0, &data->comm)) { free(rgbKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (cVendorData == 0) gbVendorData = NULL; else { gbVendorData = calloc(1, cVendorData); if (gbVendorData == NULL) { LogError("malloc of %d bytes failed.", cVendorData); free(rgbKey); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 6, gbVendorData, cVendorData, &data->comm)) { free(rgbKey); free(gbVendorData); return TCSERR(TSS_E_INTERNAL_ERROR); } } result = TCS_RegisterKey_Internal(hContext, &WrappingKeyUUID, &KeyUUID, cKeySize, rgbKey, cVendorData, gbVendorData); free(rgbKey); free(gbVendorData); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_UnregisterKey(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_UUID uuid; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UUID, 1, &uuid, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); result = TCS_UnregisterKey_Internal(hContext, uuid); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetRegisteredKeyBlob(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_UUID uuid; UINT32 pcKeySize; BYTE *prgbKey; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UUID, 1, &uuid, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); result = TCS_GetRegisteredKeyBlob_Internal(hContext, &uuid, &pcKeySize, &prgbKey); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &pcKeySize, 0, &data->comm)) { free(prgbKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, prgbKey, pcKeySize, &data->comm)) { free(prgbKey); return TCSERR(TSS_E_INTERNAL_ERROR); } free(prgbKey); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_LoadKeyByUUID(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_UUID uuid; TCS_LOADKEY_INFO info, *pInfo; TCS_KEY_HANDLE phKeyTCSI; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UUID, 1, &uuid, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); result = getData(TCSD_PACKET_TYPE_LOADKEY_INFO, 2, &info, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pInfo = NULL; else if (result) return result; else pInfo = &info; result = key_mgr_load_by_uuid(hContext, &uuid, pInfo, &phKeyTCSI); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &phKeyTCSI, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (pInfo != NULL) { if (setData(TCSD_PACKET_TYPE_LOADKEY_INFO, 1, pInfo, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } } else { if (result == TCSERR(TCS_E_KM_LOADFAILED) && pInfo != NULL) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_LOADKEY_INFO, 0, pInfo, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); } data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_EnumRegisteredKeys(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_UUID uuid, *pUuid; UINT32 cKeyHierarchySize; TSS_KM_KEYINFO *pKeyHierarchy; unsigned int i, j; TSS_RESULT result; /* Receive */ if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); result = getData(TCSD_PACKET_TYPE_UUID , 1, &uuid, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pUuid = NULL; else if (result) return result; else pUuid = &uuid; result = TCS_EnumRegisteredKeys_Internal( hContext, pUuid, &cKeyHierarchySize, &pKeyHierarchy); if (result == TSS_SUCCESS) { i=0; initData(&data->comm, cKeyHierarchySize + 1); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &cKeyHierarchySize, 0, &data->comm)) { free(pKeyHierarchy); return TCSERR(TSS_E_INTERNAL_ERROR); } for (j = 0; j < cKeyHierarchySize; j++) { if (setData(TCSD_PACKET_TYPE_KM_KEYINFO, i++, &pKeyHierarchy[j], 0, &data->comm)) { free(pKeyHierarchy); return TCSERR(TSS_E_INTERNAL_ERROR); } } free(pKeyHierarchy); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_EnumRegisteredKeys2(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_UUID uuid, *pUuid; UINT32 cKeyHierarchySize; TSS_KM_KEYINFO2 *pKeyHierarchy; unsigned int i, j; TSS_RESULT result; /* Receive */ if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); result = getData(TCSD_PACKET_TYPE_UUID , 1, &uuid, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pUuid = NULL; else if (result) return result; else pUuid = &uuid; result = TCS_EnumRegisteredKeys_Internal2( hContext, pUuid, &cKeyHierarchySize, &pKeyHierarchy); if (result == TSS_SUCCESS) { i=0; initData(&data->comm, cKeyHierarchySize + 1); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &cKeyHierarchySize, 0, &data->comm)) { free(pKeyHierarchy); return TCSERR(TSS_E_INTERNAL_ERROR); } for (j = 0; j < cKeyHierarchySize; j++) { if (setData(TCSD_PACKET_TYPE_KM_KEYINFO2, i++, &pKeyHierarchy[j], 0, &data->comm)) { free(pKeyHierarchy); return TCSERR(TSS_E_INTERNAL_ERROR); } } free(pKeyHierarchy); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetRegisteredKeyByPublicInfo(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; UINT32 algId, ulPublicInfoLength, keySize; BYTE *rgbPublicInfo, *keyBlob; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &algId, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &ulPublicInfoLength, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbPublicInfo = (BYTE *)calloc(1, ulPublicInfoLength); if (rgbPublicInfo == NULL) { LogError("malloc of %d bytes failed.", ulPublicInfoLength); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, rgbPublicInfo, ulPublicInfoLength, &data->comm)) { free(rgbPublicInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } result = TCSP_GetRegisteredKeyByPublicInfo_Internal(hContext, algId, ulPublicInfoLength, rgbPublicInfo, &keySize, &keyBlob); free(rgbPublicInfo); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &keySize, 0, &data->comm)) { free(keyBlob); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, keyBlob, keySize, &data->comm)) { free(keyBlob); return TCSERR(TSS_E_INTERNAL_ERROR); } free(keyBlob); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } void LoadBlob_LOADKEY_INFO(UINT64 *offset, BYTE *blob, TCS_LOADKEY_INFO *info) { LoadBlob_UUID(offset, blob, info->keyUUID); LoadBlob_UUID(offset, blob, info->parentKeyUUID); LoadBlob(offset, TCPA_DIGEST_SIZE, blob, info->paramDigest.digest); LoadBlob_UINT32(offset, info->authData.AuthHandle, blob); LoadBlob(offset, TCPA_NONCE_SIZE, blob, info->authData.NonceOdd.nonce); LoadBlob(offset, TCPA_NONCE_SIZE, blob, info->authData.NonceEven.nonce); LoadBlob_BOOL(offset, info->authData.fContinueAuthSession, blob); LoadBlob(offset, TCPA_AUTHDATA_SIZE, blob, (BYTE *)&info->authData.HMAC); } void UnloadBlob_LOADKEY_INFO(UINT64 *offset, BYTE *blob, TCS_LOADKEY_INFO *info) { if (!info) { UnloadBlob_UUID(offset, blob, NULL); UnloadBlob_UUID(offset, blob, NULL); UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, NULL); UnloadBlob_UINT32(offset, NULL, blob); UnloadBlob(offset, TCPA_NONCE_SIZE, blob, NULL); UnloadBlob(offset, TCPA_NONCE_SIZE, blob, NULL); UnloadBlob_BOOL(offset, NULL, blob); UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, NULL); return; } UnloadBlob_UUID(offset, blob, &info->keyUUID); UnloadBlob_UUID(offset, blob, &info->parentKeyUUID); UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, info->paramDigest.digest); UnloadBlob_UINT32(offset, &info->authData.AuthHandle, blob); UnloadBlob(offset, TCPA_NONCE_SIZE, blob, (BYTE *)&info->authData.NonceOdd.nonce); UnloadBlob(offset, TCPA_NONCE_SIZE, blob, (BYTE *)&info->authData.NonceEven.nonce); UnloadBlob_BOOL(offset, &info->authData.fContinueAuthSession, blob); UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, (BYTE *)&info->authData.HMAC); } void LoadBlob_UUID(UINT64 *offset, BYTE * blob, TSS_UUID uuid) { LoadBlob_UINT32(offset, uuid.ulTimeLow, blob); LoadBlob_UINT16(offset, uuid.usTimeMid, blob); LoadBlob_UINT16(offset, uuid.usTimeHigh, blob); LoadBlob_BYTE(offset, uuid.bClockSeqHigh, blob); LoadBlob_BYTE(offset, uuid.bClockSeqLow, blob); LoadBlob(offset, 6, blob, uuid.rgbNode); } void UnloadBlob_UUID(UINT64 *offset, BYTE * blob, TSS_UUID *uuid) { if (!uuid) { UnloadBlob_UINT32(offset, NULL, blob); UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob_UINT16(offset, NULL, blob); UnloadBlob_BYTE(offset, NULL, blob); UnloadBlob_BYTE(offset, NULL, blob); UnloadBlob(offset, 6, blob, NULL); return; } memset(uuid, 0, sizeof(TSS_UUID)); UnloadBlob_UINT32(offset, &uuid->ulTimeLow, blob); UnloadBlob_UINT16(offset, &uuid->usTimeMid, blob); UnloadBlob_UINT16(offset, &uuid->usTimeHigh, blob); UnloadBlob_BYTE(offset, &uuid->bClockSeqHigh, blob); UnloadBlob_BYTE(offset, &uuid->bClockSeqLow, blob); UnloadBlob(offset, 6, blob, uuid->rgbNode); } void LoadBlob_KM_KEYINFO(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO *info) { LoadBlob_VERSION(offset, blob, (TPM_VERSION *)&(info->versionInfo)); LoadBlob_UUID(offset, blob, info->keyUUID); LoadBlob_UUID(offset, blob, info->parentKeyUUID); LoadBlob_BYTE(offset, info->bAuthDataUsage, blob); LoadBlob_BOOL(offset, info->fIsLoaded, blob); LoadBlob_UINT32(offset, info->ulVendorDataLength, blob); LoadBlob(offset, info->ulVendorDataLength, blob, info->rgbVendorData); } void LoadBlob_KM_KEYINFO2(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO2 *info) { LoadBlob_VERSION(offset, blob, (TPM_VERSION *)&(info->versionInfo)); LoadBlob_UUID(offset, blob, info->keyUUID); LoadBlob_UUID(offset, blob, info->parentKeyUUID); LoadBlob_BYTE(offset, info->bAuthDataUsage, blob); /* Load the infos of the blob regarding the new data type TSS_KM_KEYINFO2 */ LoadBlob_UINT32(offset,info->persistentStorageType,blob); LoadBlob_UINT32(offset, info->persistentStorageTypeParent,blob); LoadBlob_BOOL(offset, info->fIsLoaded, blob); LoadBlob_UINT32(offset, info->ulVendorDataLength, blob); LoadBlob(offset, info->ulVendorDataLength, blob, info->rgbVendorData); } void UnloadBlob_KM_KEYINFO(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO *info) { if (!info) { UINT32 ulVendorDataLength; UnloadBlob_VERSION(offset, blob, NULL); UnloadBlob_UUID(offset, blob, NULL); UnloadBlob_UUID(offset, blob, NULL); UnloadBlob_BYTE(offset, blob, NULL); UnloadBlob_BOOL(offset, NULL, blob); UnloadBlob_UINT32(offset, &ulVendorDataLength, blob); (*offset) += ulVendorDataLength; return; } UnloadBlob_VERSION(offset, blob, (TPM_VERSION *)&(info->versionInfo)); UnloadBlob_UUID(offset, blob, &info->keyUUID); UnloadBlob_UUID(offset, blob, &info->parentKeyUUID); UnloadBlob_BYTE(offset, &info->bAuthDataUsage, blob); UnloadBlob_BOOL(offset, &info->fIsLoaded, blob); UnloadBlob_UINT32(offset, &info->ulVendorDataLength, blob); UnloadBlob(offset, info->ulVendorDataLength, info->rgbVendorData, blob); } #if 0 void UnloadBlob_KM_KEYINFO2(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO2 *info) { UnloadBlob_VERSION(offset, blob, (TCPA_VERSION *)&(info->versionInfo)); UnloadBlob_UUID(offset, blob, &info->keyUUID); UnloadBlob_UUID(offset, blob, &info->parentKeyUUID); UnloadBlob_BYTE(offset, blob, &info->bAuthDataUsage); /* Extract the infos of the blob regarding the new data type TSS_KM_KEYINFO2 */ UnloadBlob_UINT32(offset, &info->persistentStorageType, blob); UnloadBlob_UINT32(offset, &info->persistentStorageTypeParent, blob); UnloadBlob_BOOL(offset, &info->fIsLoaded, blob); UnloadBlob_UINT32(offset, &info->ulVendorDataLength, blob); UnloadBlob(offset, info->ulVendorDataLength, info->rgbVendorData, blob); } #endif trousers-0.3.15/src/tcs/rpc/tcstp/rpc_own.c0000664000175000017510000001073113663651711020072 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_TakeOwnership(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT16 protocolID; UINT32 encOwnerAuthSize; BYTE *encOwnerAuth; UINT32 encSrkAuthSize; BYTE *encSrkAuth; UINT32 srkInfoSize; BYTE *srkInfo; TPM_AUTH ownerAuth; UINT32 srkKeySize; BYTE *srkKey; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT16, 1, &protocolID, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &encOwnerAuthSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); encOwnerAuth = calloc(1, encOwnerAuthSize); if (encOwnerAuth == NULL) { LogError("malloc of %d bytes failed.", encOwnerAuthSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, encOwnerAuth, encOwnerAuthSize, &data->comm)) { free(encOwnerAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 4, &encSrkAuthSize, 0, &data->comm)) { free(encOwnerAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } encSrkAuth = calloc(1, encSrkAuthSize); if (encSrkAuth == NULL) { LogError("malloc of %d bytes failed.", encSrkAuthSize); free(encOwnerAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, encSrkAuth, encSrkAuthSize, &data->comm)) { free(encOwnerAuth); free(encSrkAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 6, &srkInfoSize, 0, &data->comm)) { free(encOwnerAuth); free(encSrkAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } srkInfo = calloc(1, srkInfoSize); if (srkInfo == NULL) { LogError("malloc of %d bytes failed.", srkInfoSize); free(encOwnerAuth); free(encSrkAuth); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 7, srkInfo, srkInfoSize, &data->comm)) { free(encOwnerAuth); free(encSrkAuth); free(srkInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 8, &ownerAuth, 0, &data->comm)) { free(encOwnerAuth); free(encSrkAuth); free(srkInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_TakeOwnership_Internal(hContext, protocolID, encOwnerAuthSize, encOwnerAuth, encSrkAuthSize, encSrkAuth, srkInfoSize, srkInfo, &ownerAuth, &srkKeySize, &srkKey); MUTEX_UNLOCK(tcsp_lock); free(encOwnerAuth); free(encSrkAuth); free(srkInfo); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { free(srkKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &srkKeySize, 0, &data->comm)) { free(srkKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, srkKey, srkKeySize, &data->comm)) { free(srkKey); return TCSERR(TSS_E_INTERNAL_ERROR); } free(srkKey); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_OwnerClear(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TPM_AUTH auth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_OwnerClear_Internal(hContext, &auth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_changeauth.c0000664000175000017510000001063213663651711021376 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_ChangeAuth(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE parentHandle; TCPA_PROTOCOL_ID protocolID; TCPA_ENCAUTH newAuth; TCPA_ENTITY_TYPE entityType; UINT32 encDataSize; BYTE *encData; TPM_AUTH ownerAuth; TPM_AUTH entityAuth; UINT32 outDataSize; BYTE *outData; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &parentHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT16, 2, &protocolID, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_ENCAUTH, 3, &newAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT16, 4, &entityType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 5, &encDataSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); encData = calloc(1, encDataSize); if (encData == NULL) { LogError("malloc of %d bytes failed.", encDataSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 6, encData, encDataSize, &data->comm)) { free(encData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 7, &ownerAuth, 0, &data->comm)) { free(encData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 8, &entityAuth, 0, &data->comm)) { free(encData); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_ChangeAuth_Internal(hContext, parentHandle, protocolID, newAuth, entityType, encDataSize, encData, &ownerAuth, &entityAuth, &outDataSize, &outData); MUTEX_UNLOCK(tcsp_lock); free(encData); if (result == TSS_SUCCESS) { initData(&data->comm, 4); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, 1, &entityAuth, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 2, &outDataSize, 0, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 3, outData, outDataSize, &data->comm)) { free(outData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ChangeAuthOwner(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_PROTOCOL_ID protocolID; TCPA_ENCAUTH newAuth; TCPA_ENTITY_TYPE entityType; TPM_AUTH ownerAuth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT16, 1, &protocolID, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_ENCAUTH, 2, &newAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT16, 3, &entityType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 4, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ChangeAuthOwner_Internal(hContext, protocolID, newAuth, entityType, &ownerAuth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_quote2.c0000664000175000017510000001026213663651711020505 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_Quote2(struct tcsd_thread_data *data) { /* Data to be forwarded to the next level */ TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TCPA_NONCE antiReplay; UINT32 pcrDataSizeIn; BYTE *pcrDataIn; TSS_BOOL addVersion; TPM_AUTH privAuth; /* in/out */ TPM_AUTH *pPrivAuth; UINT32 pcrDataSizeOut; BYTE *pcrDataOut; UINT32 versionInfoSize; BYTE * versionInfo; UINT32 sigSize; BYTE *sig; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 2, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &pcrDataSizeIn, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); pcrDataIn = (BYTE *)calloc(1, pcrDataSizeIn); if (pcrDataIn == NULL) { LogError("malloc of %u bytes failed.", pcrDataSizeIn); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, pcrDataIn, pcrDataSizeIn, &data->comm)) { free(pcrDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_BOOL,5,&addVersion, 0, &data->comm)) { free(pcrDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 6, &privAuth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pPrivAuth = NULL; else if (result) { free(pcrDataIn); return result; } else pPrivAuth = &privAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_Quote2_Internal(hContext, hKey, antiReplay, pcrDataSizeIn, pcrDataIn, addVersion,pPrivAuth, &pcrDataSizeOut, &pcrDataOut, &versionInfoSize, &versionInfo,&sigSize, &sig); MUTEX_UNLOCK(tcsp_lock); free(pcrDataIn); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm,7); /* Add versionInfoSize and versionInfo */ if (pPrivAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pPrivAuth, 0, &data->comm)) { free(pcrDataOut); /* It's a null pointer when addVersion == FALSE */ if (addVersion) free(versionInfo); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pcrDataSizeOut, 0, &data->comm)) { free(pcrDataOut); if (addVersion) free(versionInfo); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, pcrDataOut, pcrDataSizeOut, &data->comm)) { free(pcrDataOut); if (addVersion) free(versionInfo); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &versionInfoSize, 0, &data->comm)) { free(pcrDataOut); free(versionInfo); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (versionInfoSize > 0){ if (setData(TCSD_PACKET_TYPE_PBYTE, i++, versionInfo, versionInfoSize, &data->comm)) { free(pcrDataOut); free(versionInfo); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &sigSize, 0, &data->comm)) { free(pcrDataOut); if (addVersion) free(versionInfo); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, sig, sigSize, &data->comm)) { free(pcrDataOut); if (addVersion) free(versionInfo); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } free(pcrDataOut); if (versionInfoSize >0) free(versionInfo); free(sig); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_transport.c0000664000175000017510000003021213663651711021317 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_EstablishTransport(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hEncKey, hTransSession; UINT32 ulTransControlFlags, ulTransSessionInfoSize, ulSecretSize, ulCurrentTicks, i; BYTE *rgbTransSessionInfo, *rgbSecret, *prgbCurrentTicks; TPM_MODIFIER_INDICATOR pbLocality; TPM_AUTH pEncKeyAuth, *pAuth; TPM_NONCE pTransNonce; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &ulTransControlFlags, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &hEncKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &ulTransSessionInfoSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbTransSessionInfo = malloc(ulTransSessionInfoSize); if (rgbTransSessionInfo == NULL) { LogError("malloc of %u bytes failed.", ulTransSessionInfoSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, rgbTransSessionInfo, ulTransSessionInfoSize, &data->comm)) { free(rgbTransSessionInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 5, &ulSecretSize, 0, &data->comm)) { free(rgbTransSessionInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } rgbSecret = malloc(ulSecretSize); if (rgbSecret == NULL) { free(rgbTransSessionInfo); LogError("malloc of %u bytes failed.", ulSecretSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 6, rgbSecret, ulSecretSize, &data->comm)) { free(rgbTransSessionInfo); free(rgbSecret); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 7, &pEncKeyAuth, 0, &data->comm)) pAuth = NULL; else pAuth = &pEncKeyAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_EstablishTransport_Internal(hContext, ulTransControlFlags, hEncKey, ulTransSessionInfoSize, rgbTransSessionInfo, ulSecretSize, rgbSecret, pAuth, &pbLocality, &hTransSession, &ulCurrentTicks, &prgbCurrentTicks, &pTransNonce); MUTEX_UNLOCK(tcsp_lock); free(rgbSecret); free(rgbTransSessionInfo); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 6); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(prgbCurrentTicks); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pbLocality, 0, &data->comm)) { free(prgbCurrentTicks); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &hTransSession, 0, &data->comm)) { free(prgbCurrentTicks); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &ulCurrentTicks, 0, &data->comm)) { free(prgbCurrentTicks); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, prgbCurrentTicks, ulCurrentTicks, &data->comm)) { free(prgbCurrentTicks); return TCSERR(TSS_E_INTERNAL_ERROR); } free(prgbCurrentTicks); if (setData(TCSD_PACKET_TYPE_NONCE, i++, &pTransNonce, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ExecuteTransport(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_COMMAND_CODE unWrappedCommandOrdinal; TCS_HANDLE *rghHandles = NULL, handles[2]; UINT32 ulWrappedCmdDataInSize, pulHandleListSize, ulWrappedCmdDataOutSize, i = 0; BYTE *rgbWrappedCmdDataIn, *rgbWrappedCmdDataOut; TPM_MODIFIER_INDICATOR pbLocality; TPM_AUTH pWrappedCmdAuth1, pWrappedCmdAuth2, pTransAuth, *pAuth1, *pAuth2, null_auth; UINT64 punCurrentTicks; TSS_RESULT result, pulWrappedCmdReturnCode; if (getData(TCSD_PACKET_TYPE_UINT32, i++, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, i++, &unWrappedCommandOrdinal, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, i++, &ulWrappedCmdDataInSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbWrappedCmdDataIn = malloc(ulWrappedCmdDataInSize); if (rgbWrappedCmdDataIn == NULL) { LogError("malloc of %u bytes failed", ulWrappedCmdDataInSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, rgbWrappedCmdDataIn, ulWrappedCmdDataInSize, &data->comm)) { free(rgbWrappedCmdDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, &pulHandleListSize, 0, &data->comm)) { free(rgbWrappedCmdDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } if (pulHandleListSize > 2) { free(rgbWrappedCmdDataIn); return TCSERR(TSS_E_BAD_PARAMETER); } if (pulHandleListSize) { if (getData(TCSD_PACKET_TYPE_PBYTE, i++, handles, pulHandleListSize * sizeof(UINT32), &data->comm)) { free(rgbWrappedCmdDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } } rghHandles = handles; memset(&null_auth, 0, sizeof(TPM_AUTH)); memset(&pWrappedCmdAuth1, 0, sizeof(TPM_AUTH)); memset(&pWrappedCmdAuth2, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_AUTH, i++, &pWrappedCmdAuth1, 0, &data->comm)) { free(rgbWrappedCmdDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, i++, &pWrappedCmdAuth2, 0, &data->comm)) { free(rgbWrappedCmdDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, i++, &pTransAuth, 0, &data->comm)) { free(rgbWrappedCmdDataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } if (!memcmp(&pWrappedCmdAuth1, &null_auth, sizeof(TPM_AUTH))) pAuth1 = NULL; else pAuth1 = &pWrappedCmdAuth1; if (!memcmp(&pWrappedCmdAuth2, &null_auth, sizeof(TPM_AUTH))) pAuth2 = NULL; else pAuth2 = &pWrappedCmdAuth2; MUTEX_LOCK(tcsp_lock); result = TCSP_ExecuteTransport_Internal(hContext, unWrappedCommandOrdinal, ulWrappedCmdDataInSize, rgbWrappedCmdDataIn, &pulHandleListSize, &rghHandles, pAuth1, pAuth2, &pTransAuth, &punCurrentTicks, &pbLocality, &pulWrappedCmdReturnCode, &ulWrappedCmdDataOutSize, &rgbWrappedCmdDataOut); MUTEX_UNLOCK(tcsp_lock); free(rgbWrappedCmdDataIn); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 10); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pulHandleListSize, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (pulHandleListSize) { if (setData(TCSD_PACKET_TYPE_PBYTE, i++, rghHandles, pulHandleListSize * sizeof(UINT32), &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (pAuth1) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth1, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } } else { if (setData(TCSD_PACKET_TYPE_AUTH, i++, &null_auth, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (pAuth2) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth2, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } } else { if (setData(TCSD_PACKET_TYPE_AUTH, i++, &null_auth, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_AUTH, i++, &pTransAuth, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT64, i++, &punCurrentTicks, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pbLocality, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pulWrappedCmdReturnCode, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &ulWrappedCmdDataOutSize, 0, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (ulWrappedCmdDataOutSize) { if (setData(TCSD_PACKET_TYPE_PBYTE, i++, rgbWrappedCmdDataOut, ulWrappedCmdDataOutSize, &data->comm)) { free(rgbWrappedCmdDataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } } free(rgbWrappedCmdDataOut); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ReleaseTransportSigned(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hSignatureKey; TPM_NONCE AntiReplayNonce; UINT32 pulCurrentTicks, pulSignatureSize; BYTE *prgbCurrentTicks, *prgbSignature; TPM_MODIFIER_INDICATOR pbLocality; TPM_AUTH pKeyAuth, pTransAuth, *pAuth, null_auth; TSS_RESULT result; memset(&null_auth, 0, sizeof(TPM_AUTH)); memset(&pKeyAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hSignatureKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 2, &AntiReplayNonce, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 3, &pKeyAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (!memcmp(&null_auth, &pKeyAuth, sizeof(TPM_AUTH))) pAuth = NULL; else pAuth = &pKeyAuth; if (getData(TCSD_PACKET_TYPE_AUTH, 4, &pTransAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ReleaseTransportSigned_Internal(hContext, hSignatureKey, &AntiReplayNonce, pAuth, &pTransAuth, &pbLocality, &pulCurrentTicks, &prgbCurrentTicks, &pulSignatureSize, &prgbSignature); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 7); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &data->comm)) { free(prgbCurrentTicks); free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } } else { if (setData(TCSD_PACKET_TYPE_AUTH, 0, &null_auth, 0, &data->comm)) { free(prgbCurrentTicks); free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_AUTH, 1, &pTransAuth, 0, &data->comm)) { free(prgbCurrentTicks); free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 2, &pbLocality, 0, &data->comm)) { free(prgbCurrentTicks); free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 3, &pulCurrentTicks, 0, &data->comm)) { free(prgbCurrentTicks); free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 4, prgbCurrentTicks, pulCurrentTicks, &data->comm)) { free(prgbCurrentTicks); free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } free(prgbCurrentTicks); if (setData(TCSD_PACKET_TYPE_UINT32, 5, &pulSignatureSize, 0, &data->comm)) { free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 6, prgbSignature, pulSignatureSize, &data->comm)) { free(prgbSignature); return TCSERR(TSS_E_INTERNAL_ERROR); } free(prgbSignature); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_selftest.c0000664000175000017510000000741513663651711021125 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_SelfTestFull(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_SelfTestFull_Internal(hContext); MUTEX_UNLOCK(tcsp_lock); initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CertifySelfTest(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; UINT32 sigSize; BYTE *sigData = NULL; TCS_KEY_HANDLE hKey; TCPA_NONCE antiReplay; TPM_AUTH privAuth; TPM_AUTH *pPrivAuth; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 2, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); result = getData(TCSD_PACKET_TYPE_AUTH, 3, &privAuth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pPrivAuth = NULL; else if (result) return result; else pPrivAuth = &privAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_CertifySelfTest_Internal(hContext, hKey, antiReplay, pPrivAuth, &sigSize, &sigData); MUTEX_UNLOCK(tcsp_lock); i = 0; if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (pPrivAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pPrivAuth, 0, &data->comm)) { free(sigData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &sigSize, 0, &data->comm)) { free(sigData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, sigData, sigSize, &data->comm)) { free(sigData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(sigData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetTestResult(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; UINT32 resultDataSize; BYTE *resultData = NULL; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_GetTestResult_Internal(hContext, &resultDataSize, &resultData); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &resultDataSize, 0, &data->comm)) { free(resultData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, resultData, resultDataSize, &data->comm)) { free(resultData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(resultData); } else initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_tick.c0000664000175000017510000000662513663651711020230 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_ReadCurrentTicks(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 pulCurrentTime; BYTE *prgbCurrentTime; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_ReadCurrentTicks_Internal(hContext, &pulCurrentTime, &prgbCurrentTime); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &pulCurrentTime, 0, &data->comm)) { free(prgbCurrentTime); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, prgbCurrentTime, pulCurrentTime, &data->comm)) { free(prgbCurrentTime); return TCSERR(TSS_E_INTERNAL_ERROR); } free(prgbCurrentTime); } else initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_TickStampBlob(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; TPM_AUTH auth, *pAuth; TPM_NONCE nonce; TPM_DIGEST digest; UINT32 sigSize, tcSize, i; BYTE *sig, *tc; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 2, &nonce, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 3, &digest, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 4, &auth, 0, &data->comm)) pAuth = NULL; else pAuth = &auth; MUTEX_LOCK(tcsp_lock); result = TCSP_TickStampBlob_Internal(hContext, hKey, &nonce, &digest, pAuth, &sigSize, &sig, &tcSize, &tc); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 5); i = 0; if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(sig); free(tc); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &sigSize, 0, &data->comm)) { free(sig); free(tc); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, sig, sigSize, &data->comm)) { free(sig); free(tc); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &tcSize, 0, &data->comm)) { free(sig); free(tc); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, tc, tcSize, &data->comm)) { free(sig); free(tc); return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_sign.c0000664000175000017510000000474313663651711020235 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_Sign(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE hKey; UINT32 areaToSignSize; BYTE *areaToSign; TPM_AUTH auth; TPM_AUTH *pAuth; UINT32 sigSize; BYTE *sig; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &areaToSignSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); areaToSign = calloc(1, areaToSignSize); if (areaToSign == NULL) { LogError("malloc of %d bytes failed.", areaToSignSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, areaToSign, areaToSignSize, &data->comm)) { free(areaToSign); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 4, &auth, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pAuth = NULL; else if (result) { free(areaToSign); return result; } else pAuth = &auth; MUTEX_LOCK(tcsp_lock); result = TCSP_Sign_Internal(hContext, hKey, areaToSignSize, areaToSign, pAuth, &sigSize, &sig); MUTEX_UNLOCK(tcsp_lock); free(areaToSign); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if (pAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, &auth, 0, &data->comm)) { free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &sigSize, 0, &data->comm)) { free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, sig, sigSize, &data->comm)) { free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } free(sig); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_aik.c0000664000175000017510000001742713663651711020044 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_MakeIdentity(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_ENCAUTH identityAuth; TCPA_CHOSENID_HASH privCAHash; UINT32 idKeyInfoSize; BYTE *idKeyInfo = NULL; TPM_AUTH auth1, auth2; TPM_AUTH *pSRKAuth, *pOwnerAuth; UINT32 idKeySize; BYTE *idKey = NULL; UINT32 pcIDBindSize; BYTE *prgbIDBind = NULL; UINT32 pcECSize; BYTE *prgbEC = NULL; UINT32 pcPlatCredSize; BYTE *prgbPlatCred = NULL; UINT32 pcConfCredSize; BYTE *prgbConfCred = NULL; TSS_RESULT result; int i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_ENCAUTH, 1, &identityAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 2, &privCAHash, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &idKeyInfoSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); idKeyInfo = (BYTE *) calloc(1, idKeyInfoSize); if (idKeyInfo == NULL) { LogError("malloc of %d bytes failed.", idKeyInfoSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, idKeyInfo, idKeyInfoSize, &data->comm)) { free(idKeyInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 5, &auth1, 0, &data->comm)) { free(idKeyInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 6, &auth2, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) { pOwnerAuth = &auth1; pSRKAuth = NULL; } else if (result) { free(idKeyInfo); return result; } else { pOwnerAuth = &auth2; pSRKAuth = &auth1; } MUTEX_LOCK(tcsp_lock); result = TCSP_MakeIdentity_Internal(hContext, identityAuth, privCAHash, idKeyInfoSize, idKeyInfo, pSRKAuth, pOwnerAuth, &idKeySize, &idKey, &pcIDBindSize, &prgbIDBind, &pcECSize, &prgbEC, &pcPlatCredSize, &prgbPlatCred, &pcConfCredSize, &prgbConfCred); MUTEX_UNLOCK(tcsp_lock); free(idKeyInfo); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 12); if (pSRKAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pSRKAuth, 0, &data->comm)) goto internal_error; } if (setData(TCSD_PACKET_TYPE_AUTH, i++, pOwnerAuth, 0, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_UINT32, i++, &idKeySize, 0, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_PBYTE, i++, idKey, idKeySize, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pcIDBindSize, 0, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_PBYTE, i++, prgbIDBind, pcIDBindSize, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pcECSize, 0, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_PBYTE, i++, prgbEC, pcECSize, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pcPlatCredSize, 0, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_PBYTE, i++, prgbPlatCred, pcPlatCredSize, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pcConfCredSize, 0, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_PBYTE, i++, prgbConfCred, pcConfCredSize, &data->comm)) goto internal_error; free(idKey); free(prgbIDBind); free(prgbEC); free(prgbPlatCred); free(prgbConfCred); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; internal_error: free(idKey); free(prgbIDBind); free(prgbEC); free(prgbPlatCred); free(prgbConfCred); return TCSERR(TSS_E_INTERNAL_ERROR); } TSS_RESULT tcs_wrap_ActivateIdentity(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE idKeyHandle; TPM_AUTH *pIdKeyAuth = NULL, *pOwnerAuth = NULL, auth1, auth2; UINT32 SymmetricKeySize, blobSize; BYTE *SymmetricKey, *blob; TSS_RESULT result; UINT32 i; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &idKeyHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &blobSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((blob = malloc(blobSize)) == NULL) return TCSERR(TSS_E_OUTOFMEMORY); if (getData(TCSD_PACKET_TYPE_PBYTE, 3, blob, blobSize, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 4, &auth1, 0, &data->comm)) { free(blob); return TCSERR(TSS_E_INTERNAL_ERROR); } result = getData(TCSD_PACKET_TYPE_AUTH, 5, &auth2, 0, &data->comm); if (result == TSS_TCP_RPC_BAD_PACKET_TYPE) pOwnerAuth = &auth1; else if (result) { free(blob); return result; } else { pIdKeyAuth = &auth1; pOwnerAuth = &auth2; } MUTEX_LOCK(tcsp_lock); result = TCSP_ActivateTPMIdentity_Internal(hContext, idKeyHandle, blobSize, blob, pIdKeyAuth, pOwnerAuth, &SymmetricKeySize, &SymmetricKey); MUTEX_UNLOCK(tcsp_lock); free(blob); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 4); if (pIdKeyAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pIdKeyAuth, 0, &data->comm)) { free(SymmetricKey); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_AUTH, i++, pOwnerAuth, 0, &data->comm)) { free(SymmetricKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &SymmetricKeySize, 0, &data->comm)) { free(SymmetricKey); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, SymmetricKey, SymmetricKeySize, &data->comm)) { free(SymmetricKey); return TCSERR(TSS_E_INTERNAL_ERROR); } free(SymmetricKey); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #ifdef TSS_BUILD_TSS12 TSS_RESULT tcs_wrap_GetCredential(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 CredType; UINT32 CredAccessMode; UINT32 CredSize; BYTE *CredData = NULL; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &CredType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &CredAccessMode, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); result = TCS_GetCredential_Internal(hContext, CredType, CredAccessMode, &CredSize, &CredData); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &CredSize, 0, &data->comm)) goto internal_error; if (setData(TCSD_PACKET_TYPE_PBYTE, 1, CredData, CredSize, &data->comm)) goto internal_error; free(CredData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; internal_error: free(CredData); return TCSERR(TSS_E_INTERNAL_ERROR); } #endif trousers-0.3.15/src/tcs/rpc/tcstp/rpc_counter.c0000664000175000017510000001441213663651711020746 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_ReadCounter(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_COUNTER_ID idCounter; TPM_COUNTER_VALUE counterValue; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ReadCounter_Internal(hContext, idCounter, &counterValue); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_COUNTER_VALUE, 0, &counterValue, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CreateCounter(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_COUNTER_ID idCounter; TPM_COUNTER_VALUE counterValue; TPM_AUTH auth; TPM_ENCAUTH encauth; UINT32 LabelSize; BYTE *pLabel = NULL; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &LabelSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((pLabel = calloc(1, LabelSize)) == NULL) { LogError("malloc of %u bytes failed.", LabelSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, &pLabel, LabelSize, &data->comm)) { free(pLabel); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_ENCAUTH, 3, &encauth, 0, &data->comm)) { free(pLabel); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 4, &auth, 0, &data->comm)) { free(pLabel); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_CreateCounter_Internal(hContext, LabelSize, pLabel, encauth, &auth, &idCounter, &counterValue); MUTEX_UNLOCK(tcsp_lock); free(pLabel); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_COUNTER_VALUE, 2, &counterValue, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_IncrementCounter(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_COUNTER_ID idCounter; TPM_COUNTER_VALUE counterValue; TPM_AUTH auth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_IncrementCounter_Internal(hContext, idCounter, &auth, &counterValue); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_COUNTER_VALUE, 1, &counterValue, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ReleaseCounter(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_COUNTER_ID idCounter; TPM_AUTH auth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ReleaseCounter_Internal(hContext, idCounter, &auth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ReleaseCounterOwner(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_COUNTER_ID idCounter; TPM_AUTH auth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ReleaseCounterOwner_Internal(hContext, idCounter, &auth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_nv.c0000664000175000017510000002110313663651711017705 0ustar deboradebora/* * The Initial Developer of the Original Code is Intel Corporation. * Portions created by Intel Corporation are Copyright (C) 2007 Intel Corporation. * All Rights Reserved. * trousers - An open source TCG Software Stack * * Author: james.xu@intel.com Rossey.liu@intel.com * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_NV_DefineOrReleaseSpace(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 cPubInfoSize; BYTE *pubInfo = NULL; TSS_RESULT result; TPM_ENCAUTH encAuth; TPM_AUTH Auth, *pAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &cPubInfoSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); pubInfo = calloc(1, cPubInfoSize); if (pubInfo == NULL) { LogError("malloc of %u bytes failed.", cPubInfoSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, pubInfo, cPubInfoSize, &data->comm)) { free(pubInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_ENCAUTH, 3, &encAuth, 0, &data->comm)) { free(pubInfo); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 4, &Auth, 0, &data->comm)) pAuth = NULL; else pAuth = &Auth; MUTEX_LOCK(tcsp_lock); result = TCSP_NV_DefineOrReleaseSpace_Internal(hContext, cPubInfoSize, pubInfo, encAuth, pAuth); MUTEX_UNLOCK(tcsp_lock); free(pubInfo); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if ( pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_NV_WriteValue(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_NV_INDEX hNVStore; UINT32 offset,ulDataLength; BYTE *rgbDataToWrite = NULL; TSS_RESULT result; TPM_AUTH Auth, *pAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &ulDataLength, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbDataToWrite = calloc(1, ulDataLength); if (rgbDataToWrite == NULL) { LogError("malloc of %u bytes failed.", ulDataLength); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, rgbDataToWrite, ulDataLength, &data->comm)) { free(rgbDataToWrite); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 5, &Auth, 0, &data->comm)) pAuth = NULL; else pAuth = &Auth; MUTEX_LOCK(tcsp_lock); result = TCSP_NV_WriteValue_Internal(hContext, hNVStore, offset, ulDataLength, rgbDataToWrite, pAuth); MUTEX_UNLOCK(tcsp_lock); free(rgbDataToWrite); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_NV_WriteValueAuth(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_NV_INDEX hNVStore; UINT32 offset,ulDataLength; BYTE *rgbDataToWrite = NULL; TSS_RESULT result; TPM_AUTH Auth, *pAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &ulDataLength, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); rgbDataToWrite = calloc(1, ulDataLength); if (rgbDataToWrite == NULL) { LogError("malloc of %u bytes failed.", ulDataLength); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, rgbDataToWrite, ulDataLength, &data->comm)) { free(rgbDataToWrite); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 5, &Auth, 0, &data->comm)) { free(rgbDataToWrite); return TCSERR(TSS_E_INTERNAL_ERROR); } else pAuth = &Auth; MUTEX_LOCK(tcsp_lock); result = TCSP_NV_WriteValueAuth_Internal(hContext, hNVStore, offset, ulDataLength, rgbDataToWrite, pAuth); MUTEX_UNLOCK(tcsp_lock); free(rgbDataToWrite); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if ( pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_NV_ReadValue(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_NV_INDEX hNVStore; UINT32 offset,ulDataLength, i; BYTE *rgbDataRead = NULL; TSS_RESULT result; TPM_AUTH Auth, *pAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &ulDataLength, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 4, &Auth, 0, &data->comm)) pAuth = NULL; else pAuth = &Auth; MUTEX_LOCK(tcsp_lock); result = TCSP_NV_ReadValue_Internal(hContext, hNVStore, offset, &ulDataLength, pAuth, &rgbDataRead); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if ( pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(rgbDataRead); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &ulDataLength, 0, &data->comm)) { free(rgbDataRead); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, rgbDataRead, ulDataLength, &data->comm)) { free(rgbDataRead); return TCSERR(TSS_E_INTERNAL_ERROR); } free(rgbDataRead); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_NV_ReadValueAuth(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_NV_INDEX hNVStore; UINT32 offset,ulDataLength, i; BYTE *rgbDataRead = NULL; TSS_RESULT result; TPM_AUTH NVAuth, *pNVAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &ulDataLength, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 4, &NVAuth, 0, &data->comm)) { pNVAuth = NULL; } else { pNVAuth = &NVAuth; } MUTEX_LOCK(tcsp_lock); result = TCSP_NV_ReadValueAuth_Internal(hContext, hNVStore, offset, &ulDataLength, pNVAuth, &rgbDataRead); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if ( pNVAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pNVAuth, 0, &data->comm)) { free(rgbDataRead); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &ulDataLength, 0, &data->comm)) { free(rgbDataRead); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, rgbDataRead, ulDataLength, &data->comm)) { free(rgbDataRead); return TCSERR(TSS_E_INTERNAL_ERROR); } free(rgbDataRead); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_oper.c0000664000175000017510000000232113663651711020230 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_SetOperatorAuth(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_SECRET operatorAuth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_SECRET, 1, &operatorAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_SetOperatorAuth_Internal(hContext, &operatorAuth); MUTEX_UNLOCK(tcsp_lock); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_caps_tpm.c0000664000175000017510000001275113663651711021101 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_GetCapability(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_CAPABILITY_AREA capArea; UINT32 subCapSize; BYTE *subCap; UINT32 respSize; BYTE *resp; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ldd context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &capArea, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &subCapSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (subCapSize == 0) subCap = NULL; else { subCap = calloc(1, subCapSize); if (subCap == NULL) { LogError("malloc of %u bytes failed.", subCapSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, subCap, subCapSize, &data->comm)) { free(subCap); return TCSERR(TSS_E_INTERNAL_ERROR); } } MUTEX_LOCK(tcsp_lock); result = TCSP_GetCapability_Internal(hContext, capArea, subCapSize, subCap, &respSize, &resp); MUTEX_UNLOCK(tcsp_lock); free(subCap); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &respSize, 0, &data->comm)) { free(resp); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, resp, respSize, &data->comm)) { free(resp); return TCSERR(TSS_E_INTERNAL_ERROR); } free(resp); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetCapabilityOwner(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_AUTH ownerAuth; TCPA_VERSION version; UINT32 nonVol; UINT32 vol; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_GetCapabilityOwner_Internal(hContext, &ownerAuth, &version, &nonVol, &vol); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 4); if (setData(TCSD_PACKET_TYPE_VERSION, 0, &version, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &nonVol, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 2, &vol, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, 3, &ownerAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_SetCapability(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_CAPABILITY_AREA capArea; UINT32 subCapSize; BYTE *subCap; UINT32 valueSize; BYTE *value; TSS_RESULT result; TPM_AUTH ownerAuth, *pOwnerAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &capArea, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &subCapSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (subCapSize == 0) subCap = NULL; else { subCap = calloc(1, subCapSize); if (subCap == NULL) { LogError("malloc of %u bytes failed.", subCapSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, subCap, subCapSize, &data->comm)) { free(subCap); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (getData(TCSD_PACKET_TYPE_UINT32, 4, &valueSize, 0, &data->comm)) { free(subCap); return TCSERR(TSS_E_INTERNAL_ERROR); } if (valueSize == 0) value = NULL; else { value = calloc(1, valueSize); if (value == NULL) { free(subCap); LogError("malloc of %u bytes failed.", valueSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, value, valueSize, &data->comm)) { free(subCap); free(value); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (getData(TCSD_PACKET_TYPE_AUTH, 6, &ownerAuth, 0, &data->comm)) pOwnerAuth = NULL; else pOwnerAuth = &ownerAuth; MUTEX_LOCK(tcsp_lock); result = TCSP_SetCapability_Internal(hContext, capArea, subCapSize, subCap, valueSize, value, pOwnerAuth); MUTEX_UNLOCK(tcsp_lock); free(subCap); free(value); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (pOwnerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pOwnerAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_evlog.c0000664000175000017510000001725113663651711020407 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_GetPcrEvent(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_PCR_EVENT *pEvent = NULL; TSS_RESULT result; UINT32 pcrIndex, number; BYTE lengthOnly; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &pcrIndex, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &number, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_BYTE, 3, &lengthOnly, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (lengthOnly) result = TCS_GetPcrEvent_Internal(hContext, pcrIndex, &number, NULL); else result = TCS_GetPcrEvent_Internal(hContext, pcrIndex, &number, &pEvent); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &number, 0, &data->comm)) { if (lengthOnly == FALSE) free_external_events(1, pEvent); free(pEvent); return TCSERR(TSS_E_INTERNAL_ERROR); } if (lengthOnly == FALSE) { if (setData(TCSD_PACKET_TYPE_PCR_EVENT, 1, pEvent, 0, &data->comm)) { free_external_events(1, pEvent); free(pEvent); return TCSERR(TSS_E_INTERNAL_ERROR); } free_external_events(1, pEvent); free(pEvent); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetPcrEventsByPcr(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_PCR_EVENT *ppEvents = NULL; TSS_RESULT result; UINT32 firstEvent, eventCount, totalSize, pcrIndex, i, j; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &pcrIndex, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &firstEvent, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &eventCount, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); result = TCS_GetPcrEventsByPcr_Internal(hContext, pcrIndex, firstEvent, &eventCount, &ppEvents); if (result == TSS_SUCCESS) { /* XXX totalSize not used */ for (i = 0, totalSize = 0; i < eventCount; i++) totalSize += get_pcr_event_size(&(ppEvents[i])); initData(&data->comm, eventCount + 1); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &eventCount, 0, &data->comm)) { free_external_events(eventCount, ppEvents); free(ppEvents); return TCSERR(TSS_E_INTERNAL_ERROR); } i = 1; for (j = 0; j < eventCount; j++) { if (setData(TCSD_PACKET_TYPE_PCR_EVENT, i++, &(ppEvents[j]), 0, &data->comm)) { free_external_events(eventCount, ppEvents); free(ppEvents); return TCSERR(TSS_E_INTERNAL_ERROR); } } free_external_events(eventCount, ppEvents); free(ppEvents); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetPcrEventLog(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_PCR_EVENT *ppEvents; TSS_RESULT result; UINT32 eventCount, totalSize, i, j; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); result = TCS_GetPcrEventLog_Internal(hContext, &eventCount, &ppEvents); if (result == TSS_SUCCESS) { for (i = 0, totalSize = 0; i < eventCount; i++) totalSize += get_pcr_event_size(&(ppEvents[i])); initData(&data->comm, eventCount + 1); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &eventCount, 0, &data->comm)) { free_external_events(eventCount, ppEvents); free(ppEvents); return TCSERR(TSS_E_INTERNAL_ERROR); } i = 1; for (j = 0; j < eventCount; j++) { if (setData(TCSD_PACKET_TYPE_PCR_EVENT, i++, &(ppEvents[j]), 0, &data->comm)) { free_external_events(eventCount, ppEvents); free(ppEvents); return TCSERR(TSS_E_INTERNAL_ERROR); } } free_external_events(eventCount, ppEvents); free(ppEvents); } else initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_LogPcrEvent(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_PCR_EVENT event; TSS_RESULT result; UINT32 number; /* Receive */ if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_PCR_EVENT , 1, &event, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); result = TCS_LogPcrEvent_Internal(hContext, event, &number); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &number, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } void LoadBlob_PCR_EVENT(UINT64 *offset, BYTE *blob, TSS_PCR_EVENT *event) { LoadBlob_VERSION(offset, blob, (TPM_VERSION *)&(event->versionInfo)); LoadBlob_UINT32(offset, event->ulPcrIndex, blob); LoadBlob_UINT32(offset, event->eventType, blob); LoadBlob_UINT32(offset, event->ulPcrValueLength, blob); if (event->ulPcrValueLength > 0) LoadBlob(offset, event->ulPcrValueLength, blob, event->rgbPcrValue); LoadBlob_UINT32(offset, event->ulEventLength, blob); if (event->ulEventLength > 0) LoadBlob(offset, event->ulEventLength, blob, event->rgbEvent); } TSS_RESULT UnloadBlob_PCR_EVENT(UINT64 *offset, BYTE *blob, TSS_PCR_EVENT *event) { if (!event) { UINT32 ulPcrValueLength, ulEventLength; UnloadBlob_VERSION(offset, blob, NULL); UnloadBlob_UINT32(offset, NULL, blob); UnloadBlob_UINT32(offset, NULL, blob); UnloadBlob_UINT32(offset, &ulPcrValueLength, blob); (*offset) += ulPcrValueLength; UnloadBlob_UINT32(offset, &ulEventLength, blob); (*offset) += ulEventLength; return TSS_SUCCESS; } UnloadBlob_VERSION(offset, blob, (TPM_VERSION *)&(event->versionInfo)); UnloadBlob_UINT32(offset, &event->ulPcrIndex, blob); UnloadBlob_UINT32(offset, &event->eventType, blob); UnloadBlob_UINT32(offset, &event->ulPcrValueLength, blob); if (event->ulPcrValueLength > 0) { event->rgbPcrValue = malloc(event->ulPcrValueLength); if (event->rgbPcrValue == NULL) { LogError("malloc of %u bytes failed.", event->ulPcrValueLength); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, event->ulPcrValueLength, blob, event->rgbPcrValue); } else { event->rgbPcrValue = NULL; } UnloadBlob_UINT32(offset, &event->ulEventLength, blob); if (event->ulEventLength > 0) { event->rgbEvent = malloc(event->ulEventLength); if (event->rgbEvent == NULL) { LogError("malloc of %u bytes failed.", event->ulEventLength); free(event->rgbPcrValue); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(offset, event->ulEventLength, blob, event->rgbEvent); } else { event->rgbEvent = NULL; } return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_caps.c0000664000175000017510000000377313663651711020225 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_TCSGetCapability(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_CAPABILITY_AREA capArea; UINT32 subCapSize; BYTE *subCap; UINT32 respSize; BYTE *resp; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &capArea, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &subCapSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); subCap = calloc(1, subCapSize); if (subCap == NULL) { LogError("malloc of %u bytes failed.", subCapSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, subCap, subCapSize, &data->comm)) { free(subCap); return TCSERR(TSS_E_INTERNAL_ERROR); } result = TCS_GetCapability_Internal(hContext, capArea, subCapSize, subCap, &respSize, &resp); free(subCap); if (result == TSS_SUCCESS) { initData(&data->comm, 2); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &respSize, 0, &data->comm)) { free(resp); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, resp, respSize, &data->comm)) { free(resp); return TCSERR(TSS_E_INTERNAL_ERROR); } free(resp); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_daa.c0000664000175000017510000001460013663651711020013 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_DaaJoin(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_HANDLE hDAA; BYTE stage; UINT32 inputSize0, inputSize1, outputSize, i; BYTE *inputData0 = NULL, *inputData1 = NULL,*outputData; TSS_RESULT result; TPM_AUTH ownerAuth, *pOwnerAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hDAA, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld hDAA %x", THREAD_ID, hDAA); if (getData(TCSD_PACKET_TYPE_BYTE, 2, &stage, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebug("getData 2 (stage=%d)", (int)stage); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &inputSize0, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebug("getData 3 inputSize0=%d", inputSize0); inputData0 = calloc(1, inputSize0); if (inputData0 == NULL) { LogError("malloc of %d bytes failed.", inputSize0); return TCSERR(TSS_E_OUTOFMEMORY); } LogDebug("getData 4 inputData0"); if (getData(TCSD_PACKET_TYPE_PBYTE, 4, inputData0, inputSize0, &data->comm)) { free(inputData0); return TCSERR(TSS_E_INTERNAL_ERROR); } LogDebug("getData 5"); if (getData(TCSD_PACKET_TYPE_UINT32, 5, &inputSize1, 0, &data->comm)) { free( inputData0); return TCSERR(TSS_E_INTERNAL_ERROR); } LogDebug("getData 5 inputSize1=%d", inputSize1); if( inputSize1 > 0) { inputData1 = calloc(1, inputSize1); if (inputData1 == NULL) { LogError("malloc of %d bytes failed.", inputSize1); free( inputData0); return TCSERR(TSS_E_OUTOFMEMORY); } LogDebug("getData 6 inputData1"); if (getData(TCSD_PACKET_TYPE_PBYTE, 6, inputData1, inputSize1, &data->comm)) { free(inputData0); free(inputData1); return TCSERR(TSS_E_INTERNAL_ERROR); } } LogDebug("getData 7"); if (getData(TCSD_PACKET_TYPE_AUTH, 7, &ownerAuth, 0, &data->comm)) { pOwnerAuth = NULL; } else { pOwnerAuth = &ownerAuth; } MUTEX_LOCK(tcsp_lock); result = TCSP_DaaJoin_internal(hContext, hDAA, stage, inputSize0, inputData0, inputSize1, inputData1, pOwnerAuth, &outputSize, &outputData); MUTEX_UNLOCK(tcsp_lock); free(inputData0); if( inputData1 != NULL) free(inputData1); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if ( pOwnerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pOwnerAuth, 0, &data->comm)) { free(outputData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outputSize, 0, &data->comm)) { free(outputData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outputData, outputSize, &data->comm)) { free(outputData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outputData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_DaaSign(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_HANDLE hDAA; BYTE stage; UINT32 inputSize0, inputSize1, outputSize, i; BYTE *inputData0 = NULL, *inputData1 = NULL,*outputData; TSS_RESULT result; TPM_AUTH ownerAuth, *pOwnerAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hDAA, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld hDAA %x", THREAD_ID, hDAA); if (getData(TCSD_PACKET_TYPE_BYTE, 2, &stage, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("getData 2 (stage=%d)", (int)stage); if (getData(TCSD_PACKET_TYPE_UINT32, 3, &inputSize0, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebug("getData 3 inputSize0=%d", inputSize0); inputData0 = calloc(1, inputSize0); if (inputData0 == NULL) { LogError("malloc of %d bytes failed.", inputSize0); return TCSERR(TSS_E_OUTOFMEMORY); } LogDebug("getData 4 inputData0"); if (getData(TCSD_PACKET_TYPE_PBYTE, 4, inputData0, inputSize0, &data->comm)) { free(inputData0); return TCSERR(TSS_E_INTERNAL_ERROR); } LogDebug("getData 5"); if (getData(TCSD_PACKET_TYPE_UINT32, 5, &inputSize1, 0, &data->comm)) { free( inputData0); return TCSERR(TSS_E_INTERNAL_ERROR); } LogDebug("getData 5 inputSize1=%d", inputSize1); if( inputSize1 > 0) { inputData1 = calloc(1, inputSize1); if (inputData1 == NULL) { LogError("malloc of %d bytes failed.", inputSize1); free( inputData0); return TCSERR(TSS_E_OUTOFMEMORY); } LogDebug("getData 6 inputData1"); if (getData(TCSD_PACKET_TYPE_PBYTE, 6, inputData1, inputSize1, &data->comm)) { free(inputData0); free(inputData1); return TCSERR(TSS_E_INTERNAL_ERROR); } } LogDebug("getData 7"); if (getData(TCSD_PACKET_TYPE_AUTH, 7, &ownerAuth, 0, &data->comm)) { pOwnerAuth = NULL; } else { pOwnerAuth = &ownerAuth; } LogDebugFn("-> TCSP_DaaSign_internal"); MUTEX_LOCK(tcsp_lock); result = TCSP_DaaSign_internal(hContext, hDAA, stage, inputSize0, inputData0, inputSize1, inputData1, pOwnerAuth, &outputSize, &outputData); MUTEX_UNLOCK(tcsp_lock); LogDebugFn("<- TCSP_DaaSign_internal"); free(inputData0); if( inputData1 != NULL) free(inputData1); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 3); if ( pOwnerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pOwnerAuth, 0, &data->comm)) { free(outputData); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &outputSize, 0, &data->comm)) { free(outputData); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, outputData, outputSize, &data->comm)) { free(outputData); return TCSERR(TSS_E_INTERNAL_ERROR); } free(outputData); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_maint.c0000664000175000017510000001622613663651711020404 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_KillMaintenanceFeature(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TPM_AUTH ownerAuth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_KillMaintenanceFeature_Internal(hContext, &ownerAuth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_CreateMaintenanceArchive(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TPM_AUTH ownerAuth; TSS_BOOL generateRandom; UINT32 randomSize, archiveSize; BYTE *random, *archive; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_BOOL, 1, &generateRandom, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_CreateMaintenanceArchive_Internal(hContext, generateRandom, &ownerAuth, &randomSize, &random, &archiveSize, &archive); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 5); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { free(random); free(archive); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &randomSize, 0, &data->comm)) { free(random); free(archive); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, random, randomSize, &data->comm)) { free(random); free(archive); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 3, &archiveSize, 0, &data->comm)) { free(random); free(archive); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 4, archive, archiveSize, &data->comm)) { free(random); free(archive); return TCSERR(TSS_E_INTERNAL_ERROR); } free(random); free(archive); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_LoadMaintenanceArchive(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TPM_AUTH ownerAuth; UINT32 dataInSize, dataOutSize; BYTE *dataIn, *dataOut; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &dataInSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); dataIn = (BYTE *)malloc(dataInSize); if (dataIn == NULL) { LogError("malloc of %d bytes failed.", dataInSize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, dataIn, dataInSize, &data->comm)) { free(dataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 3, &ownerAuth, 0, &data->comm)) { free(dataIn); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_LoadMaintenanceArchive_Internal(hContext, dataInSize, dataIn, &ownerAuth, &dataOutSize, &dataOut); MUTEX_UNLOCK(tcsp_lock); free(dataIn); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { free(dataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &dataOutSize, 0, &data->comm)) { free(dataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, dataOut, dataOutSize, &data->comm)) { free(dataOut); return TCSERR(TSS_E_INTERNAL_ERROR); } free(dataOut); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_LoadManuMaintPub(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; UINT32 pubKeySize; BYTE *pubKey; TCPA_NONCE antiReplay; TCPA_DIGEST checksum; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &pubKeySize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); pubKey = (BYTE *)malloc(pubKeySize); if (pubKey == NULL) { LogError("malloc of %d bytes failed.", pubKeySize); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, pubKey, pubKeySize, &data->comm)) { free(pubKey); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_LoadManuMaintPub_Internal(hContext, antiReplay, pubKeySize, pubKey, &checksum); MUTEX_UNLOCK(tcsp_lock); free(pubKey); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_DIGEST, 0, &checksum, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ReadManuMaintPub(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TCPA_NONCE antiReplay; TCPA_DIGEST checksum; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ReadManuMaintPub_Internal(hContext, antiReplay, &checksum); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_DIGEST, 0, &checksum, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_audit.c0000664000175000017510000001426013663651711020376 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_SetOrdinalAuditStatus(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_AUTH ownerAuth; UINT32 ulOrdinal; TSS_BOOL bAuditState; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &ulOrdinal, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_BOOL, 2, &bAuditState, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 3, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_SetOrdinalAuditStatus_Internal(hContext, &ownerAuth, ulOrdinal, bAuditState); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetAuditDigest(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 startOrdinal; TPM_DIGEST auditDigest; UINT32 counterValueSize; BYTE *counterValue; TSS_BOOL more; UINT32 ordSize; UINT32 *ordList; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &startOrdinal, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_GetAuditDigest_Internal(hContext, startOrdinal, &auditDigest, &counterValueSize, &counterValue, &more, &ordSize, &ordList); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 6); if (setData(TCSD_PACKET_TYPE_DIGEST, 0, &auditDigest, 0, &data->comm)) { free(counterValue); free(ordList); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &counterValueSize, 0, &data->comm)) { free(counterValue); free(ordList); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, counterValue, counterValueSize, &data->comm)) { free(counterValue); free(ordList); return TCSERR(TSS_E_INTERNAL_ERROR); } free(counterValue); if (setData(TCSD_PACKET_TYPE_BOOL, 3, &more, 0, &data->comm)) { free(ordList); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 4, &ordSize, 0, &data->comm)) { free(ordList); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 5, ordList, ordSize * sizeof(UINT32), &data->comm)) { free(ordList); return TCSERR(TSS_E_INTERNAL_ERROR); } free(ordList); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_GetAuditDigestSigned(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_KEY_HANDLE keyHandle; TSS_BOOL closeAudit; TPM_NONCE antiReplay; TPM_AUTH privAuth, nullAuth, *pAuth; UINT32 counterValueSize; BYTE *counterValue; TPM_DIGEST auditDigest; TPM_DIGEST ordinalDigest; UINT32 sigSize; BYTE *sig; TSS_RESULT result; int i; memset(&privAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_BOOL, 2, &closeAudit, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 3, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 4, &privAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (memcmp(&nullAuth, &privAuth, sizeof(TPM_AUTH))) pAuth = &privAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_GetAuditDigestSigned_Internal(hContext, keyHandle, closeAudit, antiReplay, pAuth, &counterValueSize, &counterValue, &auditDigest, &ordinalDigest, &sigSize, &sig); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { i = 0; initData(&data->comm, 7); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &data->comm)) { free(counterValue); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &counterValueSize, 0, &data->comm)) { free(counterValue); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, counterValue, counterValueSize, &data->comm)) { free(counterValue); free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } free(counterValue); if (setData(TCSD_PACKET_TYPE_DIGEST, i++, &auditDigest, 0, &data->comm)) { free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_DIGEST, i++, &ordinalDigest, 0, &data->comm)) { free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &sigSize, 0, &data->comm)) { free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, i++, sig, sigSize, &data->comm)) { free(sig); return TCSERR(TSS_E_INTERNAL_ERROR); } free(sig); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } trousers-0.3.15/src/tcs/rpc/tcstp/rpc_admin.c0000664000175000017510000002277413663651711020371 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_PhysicalSetDeactivated(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_BOOL state; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_BOOL, 1, &state, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_PhysicalSetDeactivated_Internal(hContext, state); MUTEX_UNLOCK(tcsp_lock); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_DisableOwnerClear(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TPM_AUTH auth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_DisableOwnerClear_Internal(hContext, &auth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ForceClear(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_ForceClear_Internal(hContext); MUTEX_UNLOCK(tcsp_lock); initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_DisableForceClear(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_DisableForceClear_Internal(hContext); MUTEX_UNLOCK(tcsp_lock); initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_PhysicalEnable(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_PhysicalEnable_Internal(hContext); MUTEX_UNLOCK(tcsp_lock); initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_SetOwnerInstall(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_BOOL state; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_BOOL, 1, &state, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_SetOwnerInstall_Internal(hContext, state); MUTEX_UNLOCK(tcsp_lock); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_OwnerSetDisable(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_BOOL disableState; TPM_AUTH ownerAuth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_BOOL, 1, &disableState, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 2, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_OwnerSetDisable_Internal(hContext, disableState, &ownerAuth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_PhysicalDisable(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_PhysicalDisable_Internal(hContext); MUTEX_UNLOCK(tcsp_lock); initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_PhysicalPresence(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TCPA_PHYSICAL_PRESENCE phyPresFlags; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT16, 1, &phyPresFlags, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_PhysicalPresence_Internal(hContext, phyPresFlags); MUTEX_UNLOCK(tcsp_lock); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_SetTempDeactivated(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); MUTEX_LOCK(tcsp_lock); result = TCSP_SetTempDeactivated_Internal(hContext); MUTEX_UNLOCK(tcsp_lock); initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #ifdef TSS_BUILD_TSS12 TSS_RESULT tcs_wrap_SetTempDeactivated2(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_AUTH operatorAuth, nullAuth, *pAuth; TSS_RESULT result; memset(&operatorAuth, 0, sizeof(TPM_AUTH)); memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &operatorAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (memcmp(&nullAuth, &operatorAuth, sizeof(TPM_AUTH))) pAuth = &operatorAuth; else pAuth = NULL; MUTEX_LOCK(tcsp_lock); result = TCSP_SetTempDeactivated2_Internal(hContext, pAuth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ResetLockValue(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_AUTH ownerAuth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &ownerAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ResetLockValue_Internal(hContext, &ownerAuth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &ownerAuth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_FlushSpecific(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCS_HANDLE hResHandle; TPM_RESOURCE_TYPE resourceType; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, &hResHandle, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &resourceType, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_FlushSpecific_Internal(hContext, hResHandle, resourceType); MUTEX_UNLOCK(tcsp_lock); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #endif trousers-0.3.15/src/tcs/rpc/tcstp/rpc_ek.c0000664000175000017510000002025413663651711017667 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcs_utils.h" #include "rpc_tcstp_tcs.h" TSS_RESULT tcs_wrap_CreateEndorsementKeyPair(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_NONCE antiReplay; UINT32 eKPtrSize; BYTE *eKPtr; UINT32 eKSize; BYTE* eK; TCPA_DIGEST checksum; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &eKPtrSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); eKPtr = calloc(1, eKPtrSize); if (eKPtr == NULL) { LogError("malloc of %u bytes failed.", eKPtrSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, eKPtr, eKPtrSize, &data->comm)) { free(eKPtr); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_CreateEndorsementKeyPair_Internal(hContext, antiReplay, eKPtrSize, eKPtr, &eKSize, &eK, &checksum); MUTEX_UNLOCK(tcsp_lock); free(eKPtr); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &eKSize, 0, &data->comm)) { free(eK); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, eK, eKSize, &data->comm)) { free(eK); return TCSERR(TSS_E_INTERNAL_ERROR); } free(eK); if (setData(TCSD_PACKET_TYPE_DIGEST, 2, &checksum, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_ReadPubek(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TCPA_NONCE antiReplay; UINT32 pubEKSize; BYTE *pubEK; TCPA_DIGEST checksum; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_ReadPubek_Internal(hContext, antiReplay, &pubEKSize, &pubEK, &checksum); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &pubEKSize, 0, &data->comm)) { free(pubEK); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 1, pubEK, pubEKSize, &data->comm)) { free(pubEK); return TCSERR(TSS_E_INTERNAL_ERROR); } free(pubEK); if (setData(TCSD_PACKET_TYPE_DIGEST, 2, &checksum, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_OwnerReadPubek(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; UINT32 pubEKSize; BYTE *pubEK; TSS_RESULT result; TPM_AUTH auth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_OwnerReadPubek_Internal(hContext, &auth, &pubEKSize, &pubEK); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 3); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) { free(pubEK); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &pubEKSize, 0, &data->comm)) { free(pubEK); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, pubEK, pubEKSize, &data->comm)) { free(pubEK); return TCSERR(TSS_E_INTERNAL_ERROR); } free(pubEK); } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_DisablePubekRead(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TSS_RESULT result; TPM_AUTH auth; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_AUTH, 1, &auth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_DisablePubekRead_Internal(hContext, &auth); MUTEX_UNLOCK(tcsp_lock); if (result == TSS_SUCCESS) { initData(&data->comm, 1); if (setData(TCSD_PACKET_TYPE_AUTH, 0, &auth, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #ifdef TSS_BUILD_TSS12 TSS_RESULT tcs_wrap_CreateRevocableEndorsementKeyPair(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_NONCE antiReplay; UINT32 eKPtrSize; BYTE *eKPtr; TSS_BOOL genResetAuth; TPM_DIGEST eKResetAuth; UINT32 eKSize; BYTE* eK; TPM_DIGEST checksum; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, &eKPtrSize, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); eKPtr = calloc(1, eKPtrSize); if (eKPtr == NULL) { LogError("malloc of %d bytes failed.", eKPtrSize); return TCSERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, eKPtr, eKPtrSize, &data->comm)) { free(eKPtr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_BOOL, 4, &genResetAuth, 0, &data->comm)) { free(eKPtr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_DIGEST, 5, &eKResetAuth, 0, &data->comm)) { free(eKPtr); return TCSERR(TSS_E_INTERNAL_ERROR); } MUTEX_LOCK(tcsp_lock); result = TCSP_CreateRevocableEndorsementKeyPair_Internal(hContext, antiReplay, eKPtrSize, eKPtr, genResetAuth, &eKResetAuth, &eKSize, &eK, &checksum); MUTEX_UNLOCK(tcsp_lock); free(eKPtr); if (result == TSS_SUCCESS) { initData(&data->comm, 4); if (setData(TCSD_PACKET_TYPE_DIGEST, 0, &eKResetAuth, 0, &data->comm)) { free(eK); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, 1, &eKSize, 0, &data->comm)) { free(eK); return TCSERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_PBYTE, 2, eK, eKSize, &data->comm)) { free(eK); return TCSERR(TSS_E_INTERNAL_ERROR); } free(eK); if (setData(TCSD_PACKET_TYPE_DIGEST, 3, &checksum, 0, &data->comm)) { return TCSERR(TSS_E_INTERNAL_ERROR); } } else done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } TSS_RESULT tcs_wrap_RevokeEndorsementKeyPair(struct tcsd_thread_data *data) { TCS_CONTEXT_HANDLE hContext; TPM_DIGEST eKResetAuth; TSS_RESULT result; if (getData(TCSD_PACKET_TYPE_UINT32, 0, &hContext, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); if ((result = ctx_verify_context(hContext))) goto done; LogDebugFn("thread %ld context %x", THREAD_ID, hContext); if (getData(TCSD_PACKET_TYPE_DIGEST, 1, &eKResetAuth, 0, &data->comm)) return TCSERR(TSS_E_INTERNAL_ERROR); MUTEX_LOCK(tcsp_lock); result = TCSP_RevokeEndorsementKeyPair_Internal(hContext, eKResetAuth); MUTEX_UNLOCK(tcsp_lock); done: initData(&data->comm, 0); data->comm.hdr.u.result = result; return TSS_SUCCESS; } #endif trousers-0.3.15/src/tcs/tcsi_delegate.c0000664000175000017510000002177213663651711017305 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_utils.h" #include "tcslog.h" #include "req_mgr.h" TSS_RESULT TCSP_Delegate_Manage_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_FAMILY_ID familyID, /* in */ TPM_FAMILY_OPERATION opFlag, /* in */ UINT32 opDataSize, /* in */ BYTE *opData, /* in */ TPM_AUTH *ownerAuth, /* in/out */ UINT32 *retDataSize, /* out */ BYTE **retData) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (ownerAuth) { if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) return result; } if ((result = tpm_rqu_build(TPM_ORD_Delegate_Manage, &offset, txBlob, familyID, opFlag, opDataSize, opData, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Delegate_Manage, txBlob, paramSize, retDataSize, retData, ownerAuth, NULL); } LogResult("Delegate_Manage", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_Delegate_CreateKeyDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *keyAuth, /* in, out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result; TCPA_KEY_HANDLE keySlot; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (keyAuth) { if ((result = auth_mgr_check(hContext, &keyAuth->AuthHandle))) return result; } if ((result = ensureKeyIsLoaded(hContext, hKey, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_Delegate_CreateKeyDelegation, &offset, txBlob, keySlot, publicInfoSize, publicInfo, encDelAuth, keyAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Delegate_CreateKeyDelegation, txBlob, paramSize, blobSize, blob, keyAuth, NULL); } LogResult("Delegate_CreateKeyDelegation", result); done: auth_mgr_release_auth(keyAuth, NULL, hContext); return result; } TSS_RESULT TCSP_Delegate_CreateOwnerDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL increment, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (ownerAuth) { if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) return result; } if ((result = tpm_rqu_build(TPM_ORD_Delegate_CreateOwnerDelegation, &offset, txBlob, increment, publicInfoSize, publicInfo, encDelAuth, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Delegate_CreateOwnerDelegation, txBlob, paramSize, blobSize, blob, ownerAuth, NULL); } LogResult("Delegate_CreateOwnerDelegation", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_Delegate_LoadOwnerDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_DELEGATE_INDEX index, /* in */ UINT32 blobSize, /* in */ BYTE *blob, /* in */ TPM_AUTH *ownerAuth) /* in, out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (ownerAuth) { if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) return result; } if ((result = tpm_rqu_build(TPM_ORD_Delegate_LoadOwnerDelegation, &offset, txBlob, index, blobSize, blob, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Delegate_LoadOwnerDelegation, txBlob, paramSize, ownerAuth); } LogResult("Delegate_LoadOwnerDelegation", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_Delegate_ReadTable_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 *familyTableSize, /* out */ BYTE **familyTable, /* out */ UINT32 *delegateTableSize, /* out */ BYTE **delegateTable) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_Delegate_ReadTable, &offset, txBlob, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Delegate_ReadTable, txBlob, paramSize, familyTableSize, familyTable, delegateTableSize, delegateTable, NULL, NULL); } LogResult("Delegate_ReadTable", result); return result; } TSS_RESULT TCSP_Delegate_UpdateVerificationCount_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 inputSize, /* in */ BYTE *input, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *outputSize, /* out */ BYTE **output) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (ownerAuth) { if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) return result; } if ((result = tpm_rqu_build(TPM_ORD_Delegate_UpdateVerification, &offset, txBlob, inputSize, inputSize, input, ownerAuth, NULL))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Delegate_UpdateVerification, txBlob, paramSize, outputSize, output, ownerAuth, NULL); } LogResult("Delegate_UpdateVerificationCount", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_Delegate_VerifyDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 delegateSize, /* in */ BYTE *delegate) /* in */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_Delegate_VerifyDelegation, &offset, txBlob, delegateSize, delegateSize, delegate, NULL, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Delegate_VerifyDelegation", result); return result; } TSS_RESULT TCSP_DSAP_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_ENTITY_TYPE entityType, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TPM_NONCE *nonceOddDSAP, /* in */ UINT32 entityValueSize, /* in */ BYTE *entityValue, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TPM_NONCE *nonceEven, /* out */ TPM_NONCE *nonceEvenDSAP) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; TPM_KEY_HANDLE tpmKeyHandle; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if (ensureKeyIsLoaded(hContext, keyHandle, &tpmKeyHandle)) return TCSERR(TSS_E_KEY_NOT_LOADED); /* are the maximum number of auth sessions open? */ if (auth_mgr_req_new(hContext) == FALSE) { if ((result = auth_mgr_swap_out(hContext))) goto done; } if ((result = tpm_rqu_build(TPM_ORD_DSAP, &offset, txBlob, entityType, tpmKeyHandle, nonceOddDSAP, entityValueSize, entityValue))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { if ((result = tpm_rsp_parse(TPM_ORD_DSAP, txBlob, paramSize, authHandle, nonceEven->nonce, nonceEvenDSAP->nonce))) goto done; /* success, add an entry to the table */ result = auth_mgr_add(hContext, *authHandle); } done: LogResult("DSAP", result); return result; } trousers-0.3.15/src/tcs/tcsi_context.c0000664000175000017510000000216113663651711017206 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" TSS_RESULT TCS_OpenContext_Internal(TCS_CONTEXT_HANDLE * hContext) /* out */ { *hContext = make_context(); if (*hContext == 0) return TCSERR(TSS_E_OUTOFMEMORY); return TSS_SUCCESS; } TSS_RESULT TCS_CloseContext_Internal(TCS_CONTEXT_HANDLE hContext) /* in */ { TSS_RESULT result; LogDebug("Closing context %.8X", hContext); if ((result = ctx_verify_context(hContext))) return result; destroy_context(hContext); /* close all auth handles associated with hContext */ auth_mgr_close_context(hContext); KEY_MGR_ref_count(); LogDebug("Context %.8X closed", hContext); return TSS_SUCCESS; } TSS_RESULT TCS_FreeMemory_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ BYTE *pMemory) /* in */ { free(pMemory); return TSS_SUCCESS; } trousers-0.3.15/src/tcs/tcsi_cmk.c0000664000175000017510000002024113663651711016273 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_utils.h" #include "tcslog.h" #include "req_mgr.h" TSS_RESULT TCSP_CMK_SetRestrictions_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_CMK_DELEGATE Restriction, /* in */ TPM_AUTH* ownerAuth) /* in */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_CMK_SetRestrictions, &offset, txBlob, Restriction, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CMK_SetRestrictions, txBlob, paramSize, ownerAuth); } LogResult("CMK_SetRestrictions", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_CMK_ApproveMA_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_DIGEST migAuthorityDigest, /* in */ TPM_AUTH* ownerAuth, /* in, out */ TPM_HMAC* HmacMigAuthDigest) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_CMK_ApproveMA, &offset, txBlob, &migAuthorityDigest, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CMK_ApproveMA, txBlob, paramSize, HmacMigAuthDigest, ownerAuth); } LogResult("CMK_SetRestrictions", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_CMK_CreateKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hWrappingKey, /* in */ TPM_ENCAUTH KeyUsageAuth, /* in */ TPM_HMAC MigAuthApproval, /* in */ TPM_DIGEST MigAuthorityDigest, /* in */ UINT32* keyDataSize, /* in, out */ BYTE** prgbKeyData, /* in, out */ TPM_AUTH* pAuth) /* in, out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; UINT32 parentSlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) { free(*prgbKeyData); return result; } if ((result = get_slot(hContext, hWrappingKey, &parentSlot))) { free(*prgbKeyData); return result; } if (pAuth) { if ((result = auth_mgr_check(hContext, &pAuth->AuthHandle))) { free(*prgbKeyData); return result; } } if ((result = tpm_rqu_build(TPM_ORD_CMK_CreateKey, &offset, txBlob, parentSlot, &KeyUsageAuth, *keyDataSize, *prgbKeyData, &MigAuthApproval, &MigAuthorityDigest, pAuth))) { free(*prgbKeyData); goto done; } free(*prgbKeyData); if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CMK_CreateKey, txBlob, paramSize, keyDataSize, prgbKeyData, pAuth); } LogResult("CMK_SetRestrictions", result); done: auth_mgr_release_auth(pAuth, NULL, hContext); return result; } TSS_RESULT TCSP_CMK_CreateTicket_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 PublicVerifyKeySize, /* in */ BYTE* PublicVerifyKey, /* in */ TPM_DIGEST SignedData, /* in */ UINT32 SigValueSize, /* in */ BYTE* SigValue, /* in */ TPM_AUTH* pOwnerAuth, /* in, out */ TPM_HMAC* SigTicket) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = auth_mgr_check(hContext, &pOwnerAuth->AuthHandle))) return result; if ((result = tpm_rqu_build(TPM_ORD_CMK_CreateTicket, &offset, txBlob, PublicVerifyKeySize, PublicVerifyKey, &SignedData, SigValueSize, SigValue, pOwnerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CMK_CreateTicket, txBlob, paramSize, SigTicket, pOwnerAuth); } LogResult("CMK_SetRestrictions", result); done: auth_mgr_release_auth(pOwnerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_CMK_CreateBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TSS_MIGRATE_SCHEME migrationType, /* in */ UINT32 MigrationKeyAuthSize, /* in */ BYTE* MigrationKeyAuth, /* in */ TPM_DIGEST PubSourceKeyDigest, /* in */ UINT32 msaListSize, /* in */ BYTE* msaList, /* in */ UINT32 restrictTicketSize, /* in */ BYTE* restrictTicket, /* in */ UINT32 sigTicketSize, /* in */ BYTE* sigTicket, /* in */ UINT32 encDataSize, /* in */ BYTE* encData, /* in */ TPM_AUTH* parentAuth, /* in, out */ UINT32* randomSize, /* out */ BYTE** random, /* out */ UINT32* outDataSize, /* out */ BYTE** outData) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; UINT32 parentSlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = get_slot(hContext, parentHandle, &parentSlot))) return result; if (parentAuth) { if ((result = auth_mgr_check(hContext, &parentAuth->AuthHandle))) return result; } if ((result = tpm_rqu_build(TPM_ORD_CMK_CreateBlob, &offset, txBlob, parentSlot, migrationType, MigrationKeyAuthSize, MigrationKeyAuth, &PubSourceKeyDigest, msaListSize, msaList, restrictTicketSize, restrictTicket, sigTicketSize, sigTicket, encDataSize, encData, parentAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CMK_CreateBlob, txBlob, paramSize, randomSize, random, outDataSize, outData, parentAuth, NULL); } LogResult("CMK_SetRestrictions", result); done: auth_mgr_release_auth(parentAuth, NULL, hContext); return result; } TSS_RESULT TCSP_CMK_ConvertMigration_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TPM_CMK_AUTH restrictTicket, /* in */ TPM_HMAC sigTicket, /* in */ UINT32 keyDataSize, /* in */ BYTE* prgbKeyData, /* in */ UINT32 msaListSize, /* in */ BYTE* msaList, /* in */ UINT32 randomSize, /* in */ BYTE* random, /* in */ TPM_AUTH* parentAuth, /* in, out */ UINT32* outDataSize, /* out */ BYTE** outData) /* out */ { TSS_RESULT result; UINT64 offset = 0; UINT32 paramSize; UINT32 parentSlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebugFn("Enter"); if ((result = ctx_verify_context(hContext))) return result; if ((result = get_slot(hContext, parentHandle, &parentSlot))) return result; if (parentAuth) { if ((result = auth_mgr_check(hContext, &parentAuth->AuthHandle))) return result; } if ((result = tpm_rqu_build(TPM_ORD_CMK_ConvertMigration, &offset, txBlob, parentSlot, &restrictTicket, &sigTicket, keyDataSize, prgbKeyData, msaListSize, msaList, randomSize, random, parentAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CMK_ConvertMigration, txBlob, paramSize, outDataSize, outData, parentAuth, NULL); } LogResult("CMK_SetRestrictions", result); done: auth_mgr_release_auth(parentAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_random.c0000664000175000017510000000735113663651711017010 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" /* * Get a random number generated by the TPM. Most (all?) TPMs return a maximum number of random * bytes that's less than the max allowed to be returned at the TSP level, which is 4K bytes. * According to the TPM compliance work posted here: http://www.prosec.rub.de/tpmcompliance.html, * some TPMs return as little as 132 bytes per query, which would require about 30 loops to get 4K. * We'll be extremely conservative here and loop 50 times, since it won't affect performance on * TPMs that return more bytes. */ TSS_RESULT TCSP_GetRandom_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 * bytesRequested, /* in, out */ BYTE ** randomBytes) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 paramSize, totalReturned = 0, bytesReturned, retries = 50; BYTE txBlob[TSS_TPM_TXBLOB_SIZE], *rnd_tmp = NULL, *rnd_tmp2 = NULL; LogDebugFn("%u bytes", *bytesRequested); if ((result = ctx_verify_context(hContext))) return result; do { offset = 0; if ((result = tpm_rqu_build(TPM_ORD_GetRandom, &offset, txBlob, *bytesRequested - totalReturned, NULL))) break; if ((result = req_mgr_submit_req(txBlob))) break;; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { #if 0 offset = 10; UnloadBlob_UINT32(&offset, &bytesReturned, txBlob); LogDebugFn("received %u bytes from the TPM", bytesReturned); rnd_tmp = realloc(rnd_tmp, totalReturned + bytesReturned); if (rnd_tmp == NULL) { LogError("malloc of %u bytes failed.", bytesReturned); return TCSERR(TSS_E_OUTOFMEMORY); } UnloadBlob(&offset, bytesReturned, txBlob, &rnd_tmp[totalReturned]); #else /* XXX */ if ((result = tpm_rsp_parse(TPM_ORD_GetRandom, txBlob, paramSize, &bytesReturned, &rnd_tmp, NULL, NULL))) break; rnd_tmp2 = realloc(*randomBytes, totalReturned + bytesReturned); if (rnd_tmp2 == NULL) { free(rnd_tmp); rnd_tmp = NULL; LogError("malloc of %u bytes failed.", bytesReturned); result = TCSERR(TSS_E_OUTOFMEMORY); break; } *randomBytes = rnd_tmp2; memcpy(*randomBytes + totalReturned, rnd_tmp, bytesReturned); free(rnd_tmp); rnd_tmp = NULL; #endif totalReturned += bytesReturned; } else { free(rnd_tmp); return result; } } while (totalReturned < *bytesRequested && retries--); if (totalReturned != *bytesRequested) { LogDebugFn("Only %u random bytes recieved from TPM.", totalReturned); free(rnd_tmp); result = TCSERR(TSS_E_FAIL); #if 0 } else *randomBytes = rnd_tmp; #else } #endif return result; } TSS_RESULT TCSP_StirRandom_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 inDataSize, /* in */ BYTE * inData) /* in */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering stir random"); if (inDataSize > 255) { LogDebugFn("inData is too large! (%u bytes)", inDataSize); return TCSERR(TSS_E_BAD_PARAMETER); } if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_StirRandom, &offset, txBlob, inDataSize, inDataSize, inData, NULL, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("Stir random", result); return result; } trousers-0.3.15/src/tcs/tcs_caps.c0000664000175000017510000001134713663651711016305 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #include "tddl.h" #include "req_mgr.h" TSS_RESULT get_current_version(TPM_VERSION *version) { TCPA_CAPABILITY_AREA capArea = TPM_CAP_VERSION_VAL; UINT32 respSize; BYTE *resp; TSS_RESULT result; UINT64 offset; /* try the 1.2 way first */ result = TCSP_GetCapability_Internal(InternalContext, capArea, 0, NULL, &respSize, &resp); if (result == TSS_SUCCESS) { offset = sizeof(UINT16); // XXX hack UnloadBlob_VERSION(&offset, resp, version); free(resp); } else if (result == TCPA_E_BAD_MODE) { /* if the TPM doesn't understand VERSION_VAL, try the 1.1 way */ capArea = TCPA_CAP_VERSION; result = TCSP_GetCapability_Internal(InternalContext, capArea, 0, NULL, &respSize, &resp); if (result == TSS_SUCCESS) { offset = 0; UnloadBlob_VERSION(&offset, resp, version); free(resp); } } return result; } TSS_RESULT get_cap_uint32(TCPA_CAPABILITY_AREA capArea, BYTE *subCap, UINT32 subCapSize, UINT32 *v) { UINT32 respSize; BYTE *resp; TSS_RESULT result; UINT64 offset; result = TCSP_GetCapability_Internal(InternalContext, capArea, subCapSize, subCap, &respSize, &resp); if (!result) { offset = 0; switch (respSize) { case 1: UnloadBlob_BYTE(&offset, (BYTE *)v, resp); break; case sizeof(UINT16): UnloadBlob_UINT16(&offset, (UINT16 *)v, resp); break; case sizeof(UINT32): UnloadBlob_UINT32(&offset, v, resp); break; default: LogDebug("TCSP_GetCapability_Internal returned" " %u bytes", respSize); result = TCSERR(TSS_E_FAIL); break; } free(resp); } return result; } TSS_RESULT get_max_auths(UINT32 *auths) { TCS_AUTHHANDLE handles[TSS_MAX_AUTHS_CAP]; TCPA_NONCE nonce; UINT32 subCap; TSS_RESULT result; int i; if (TPM_VERSION_IS(1,2)) { UINT32ToArray(TPM_CAP_PROP_MAX_AUTHSESS, (BYTE *)(&subCap)); result = get_cap_uint32(TPM_CAP_PROPERTY, (BYTE *)&subCap, sizeof(subCap), auths); } else if (TPM_VERSION_IS(1,1)) { /* open auth sessions until we get a failure */ for (i = 0; i < TSS_MAX_AUTHS_CAP; i++) { result = TCSP_OIAP_Internal(InternalContext, &(handles[i]), &nonce); if (result != TSS_SUCCESS) { /* this is not off by one since we're 0 indexed */ *auths = i; break; } } if (i == TSS_MAX_AUTHS_CAP) *auths = TSS_MAX_AUTHS_CAP; /* close the auth sessions */ for (i = 0; (UINT32)i < *auths; i++) { internal_TerminateHandle(handles[i]); } } else { result = TCSERR(TSS_E_INTERNAL_ERROR); *auths = 0; } if (*auths < 2) { LogError("%s reported only %u auth available!", __FUNCTION__, *auths); LogError("Your TPM must be reset before the TCSD can be started."); } else { LogDebug("get_max_auths reports %u auth contexts found", *auths); result = TSS_SUCCESS; } return result; } /* This is only called from init paths, so printing an error message is * appropriate if something goes wrong */ TSS_RESULT get_tpm_metrics(struct tpm_properties *p) { TSS_RESULT result; UINT32 subCap, rv = 0; if ((result = get_current_version(&p->version))) goto err; UINT32ToArray(TPM_ORD_SaveKeyContext, (BYTE *)&subCap); if ((result = get_cap_uint32(TCPA_CAP_ORD, (BYTE *)&subCap, sizeof(UINT32), &rv))) goto err; p->keyctx_swap = rv ? TRUE : FALSE; rv = 0; UINT32ToArray(TPM_ORD_SaveAuthContext, (BYTE *)&subCap); if ((result = get_cap_uint32(TCPA_CAP_ORD, (BYTE *)&subCap, sizeof(UINT32), &rv))) goto err; p->authctx_swap = rv ? TRUE : FALSE; UINT32ToArray(TPM_CAP_PROP_PCR, (BYTE *)&subCap); if ((result = get_cap_uint32(TCPA_CAP_PROPERTY, (BYTE *)&subCap, sizeof(UINT32), &p->num_pcrs))) goto err; UINT32ToArray(TPM_CAP_PROP_DIR, (BYTE *)&subCap); if ((result = get_cap_uint32(TCPA_CAP_PROPERTY, (BYTE *)&subCap, sizeof(UINT32), &p->num_dirs))) goto err; UINT32ToArray(TPM_CAP_PROP_SLOTS, (BYTE *)&subCap); if ((result = get_cap_uint32(TCPA_CAP_PROPERTY, (BYTE *)&subCap, sizeof(UINT32), &p->num_keys))) goto err; UINT32ToArray(TPM_CAP_PROP_MANUFACTURER, (BYTE *)&subCap); if ((result = get_cap_uint32(TCPA_CAP_PROPERTY, (BYTE *)&subCap, sizeof(UINT32), (UINT32 *)&p->manufacturer))) goto err; result = get_max_auths(&(p->num_auths)); err: if (result) LogError("TCS GetCapability failed with result = 0x%x", result); return result; } trousers-0.3.15/src/tcs/tcs_key_ps.c0000664000175000017510000001726513663651711016656 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" TSS_RESULT ps_init_disk_cache(void) { int fd; TSS_RESULT rc; MUTEX_INIT(disk_cache_lock); if ((fd = get_file()) < 0) return TCSERR(TSS_E_INTERNAL_ERROR); if ((rc = init_disk_cache(fd))) return rc; /* this is temporary, to clear out a PS file from trousers * versions before 0.2.1 */ if ((rc = clean_disk_cache(fd))) return rc; put_file(fd); return TSS_SUCCESS; } void ps_close_disk_cache(void) { int fd; if ((fd = get_file()) < 0) { LogError("get_file() failed while trying to close disk cache."); return; } close_disk_cache(fd); put_file(fd); } TSS_BOOL ps_is_key_registered(TCPA_STORE_PUBKEY *pub) { TSS_UUID *uuid; int fd; TSS_RESULT rc; TSS_BOOL is_reg = FALSE; if ((fd = get_file()) < 0) return FALSE; if ((rc = psfile_get_uuid_by_pub(fd, pub, &uuid))) { put_file(fd); return FALSE; } put_file(fd); if ((isUUIDRegistered(uuid, &is_reg))) is_reg = FALSE; free(uuid); return is_reg; } TSS_RESULT getParentUUIDByUUID(TSS_UUID *uuid, TSS_UUID *ret_uuid) { struct key_disk_cache *disk_tmp; /* check the registered key disk cache */ MUTEX_LOCK(disk_cache_lock); for (disk_tmp = key_disk_cache_head; disk_tmp; disk_tmp = disk_tmp->next) { if ((disk_tmp->flags & CACHE_FLAG_VALID) && !memcmp(&disk_tmp->uuid, uuid, sizeof(TSS_UUID))) { memcpy(ret_uuid, &disk_tmp->parent_uuid, sizeof(TSS_UUID)); MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } } MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_FAIL); } TSS_RESULT isUUIDRegistered(TSS_UUID *uuid, TSS_BOOL *is_reg) { struct key_disk_cache *disk_tmp; /* check the registered key disk cache */ MUTEX_LOCK(disk_cache_lock); for (disk_tmp = key_disk_cache_head; disk_tmp; disk_tmp = disk_tmp->next) { if ((disk_tmp->flags & CACHE_FLAG_VALID) && !memcmp(&disk_tmp->uuid, uuid, sizeof(TSS_UUID))) { *is_reg = TRUE; MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } } MUTEX_UNLOCK(disk_cache_lock); *is_reg = FALSE; return TSS_SUCCESS; } void disk_cache_shift(struct key_disk_cache *c) { UINT32 key_size, offset; struct key_disk_cache *tmp = key_disk_cache_head; /* offset is the end of the key location in the file */ offset = TSSPS_VENDOR_DATA_OFFSET(c) + c->vendor_data_size; /* key_size is the size of the key entry on disk */ key_size = offset - TSSPS_UUID_OFFSET(c); /* for each disk cache entry, if the data for that entry is at an * offset greater than the key beign removed, then the entry needs to * be decremented by the size of key's disk footprint (the key_size * variable) */ while (tmp) { if (tmp->offset >= offset) { tmp->offset -= key_size; } tmp = tmp->next; } } TSS_RESULT ps_remove_key(TSS_UUID *uuid) { struct key_disk_cache *tmp, *prev = NULL; TSS_RESULT rc; int fd = -1; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; for (; tmp; prev = tmp, tmp = tmp->next) { if ((tmp->flags & CACHE_FLAG_VALID) && !memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID))) { if ((fd = get_file()) < 0) { rc = TCSERR(TSS_E_INTERNAL_ERROR); break; } rc = psfile_remove_key(fd, tmp); put_file(fd); /* if moving the file contents around succeeded, then * change the offsets of the keys in the cache in * mem_cache_shift() and remove the key from the * cache. */ if (!rc) { disk_cache_shift(tmp); if (prev) { prev->next = tmp->next; } else { key_disk_cache_head = tmp->next; } free(tmp); } else { LogError("Error removing registered key."); } MUTEX_UNLOCK(disk_cache_lock); return rc; } } MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TCSERR(TSS_E_PS_KEY_NOTFOUND)); } /* * temporary function to clean out blanked keys from a PS file from * trousers 0.2.0 and before */ TSS_RESULT clean_disk_cache(int fd) { struct key_disk_cache *tmp, *prev = NULL; TSS_RESULT rc; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; for (; tmp; prev = tmp, tmp = tmp->next) { if (!(tmp->flags & CACHE_FLAG_VALID)) { rc = psfile_remove_key(fd, tmp); /* if moving the file contents around succeeded, then * change the offsets of the keys in the cache in * mem_cache_shift() and remove the key from the * cache. */ if (!rc) { disk_cache_shift(tmp); if (prev) { prev->next = tmp->next; } free(tmp); } else { LogError("Error removing blank key."); } MUTEX_UNLOCK(disk_cache_lock); return rc; } } MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } TSS_RESULT ps_get_key_by_uuid(TSS_UUID *uuid, BYTE *blob, UINT16 *blob_size) { int fd = -1; TSS_RESULT rc = TSS_SUCCESS; if ((fd = get_file()) < 0) return TCSERR(TSS_E_INTERNAL_ERROR); rc = psfile_get_key_by_uuid(fd, uuid, blob, blob_size); put_file(fd); return rc; } TSS_RESULT ps_get_key_by_cache_entry(struct key_disk_cache *c, BYTE *blob, UINT16 *blob_size) { int fd = -1; TSS_RESULT rc = TSS_SUCCESS; if ((fd = get_file()) < 0) return TCSERR(TSS_E_INTERNAL_ERROR); rc = psfile_get_key_by_cache_entry(fd, c, blob, blob_size); put_file(fd); return rc; } TSS_RESULT ps_get_vendor_data(struct key_disk_cache *c, UINT32 *size, BYTE **data) { int fd = -1; TSS_RESULT rc; if ((fd = get_file()) < 0) return TCSERR(TSS_E_INTERNAL_ERROR); rc = psfile_get_vendor_data(fd, c, size, data); put_file(fd); return rc; } TSS_RESULT ps_is_pub_registered(TCPA_STORE_PUBKEY *key) { int fd = -1; TSS_BOOL answer; if ((fd = get_file()) < 0) return FALSE; if (psfile_is_pub_registered(fd, key, &answer)) { put_file(fd); return FALSE; } put_file(fd); return answer; } TSS_RESULT ps_get_uuid_by_pub(TCPA_STORE_PUBKEY *pub, TSS_UUID **uuid) { int fd = -1; TSS_RESULT ret; if ((fd = get_file()) < 0) return TCSERR(TSS_E_INTERNAL_ERROR); ret = psfile_get_uuid_by_pub(fd, pub, uuid); put_file(fd); return ret; } TSS_RESULT ps_get_key_by_pub(TCPA_STORE_PUBKEY *pub, UINT32 *size, BYTE **key) { int fd = -1; TSS_RESULT ret; if ((fd = get_file()) < 0) return TCSERR(TSS_E_INTERNAL_ERROR); ret = psfile_get_key_by_pub(fd, pub, size, key); put_file(fd); return ret; } TSS_RESULT ps_write_key(TSS_UUID *uuid, TSS_UUID *parent_uuid, BYTE *vendor_data, UINT32 vendor_size, BYTE *blob, UINT32 blob_size) { int fd = -1; TSS_RESULT rc; UINT32 parent_ps; UINT16 short_blob_size = (UINT16)blob_size; if ((fd = get_file()) < 0) return TCSERR(TSS_E_INTERNAL_ERROR); /* this case needed for PS file init. if the key file doesn't yet exist, the * psfile_get_parent_ps_type_by_uuid() call would fail. */ if (!memcmp(parent_uuid, &NULL_UUID, sizeof(TSS_UUID))) { parent_ps = TSS_PS_TYPE_SYSTEM; } else { if ((rc = psfile_get_ps_type_by_uuid(fd, parent_uuid, &parent_ps))) return rc; } rc = psfile_write_key(fd, uuid, parent_uuid, &parent_ps, vendor_data, vendor_size, blob, short_blob_size); put_file(fd); return TSS_SUCCESS; } trousers-0.3.15/src/tcs/ps/0000775000175000017510000000000013736474160014760 5ustar deboradeboratrousers-0.3.15/src/tcs/ps/ps_utils.c0000664000175000017510000003015613663651711016771 0ustar deboradebora/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include #if defined(HAVE_BYTEORDER_H) #include #elif defined(HTOLE_DEFINED) #ifndef __APPLE__ #include #else #include "portable_endian.h" #endif #define LE_16 htole16 #define LE_32 htole32 #define LE_64 htole64 #else #define LE_16(x) (x) #define LE_32(x) (x) #define LE_64(x) (x) #endif #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_int_literals.h" #include "tcsps.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcslog.h" struct key_disk_cache *key_disk_cache_head = NULL; TSS_RESULT read_data(int fd, void *data, UINT32 size) { int rc; rc = read(fd, data, size); if (rc == -1) { LogError("read of %d bytes: %s", size, strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } else if ((unsigned)rc != size) { LogError("read of %d bytes (only %d read)", size, rc); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT write_data(int fd, void *data, UINT32 size) { int rc; rc = write(fd, data, size); if (rc == -1) { LogError("write of %d bytes: %s", size, strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } else if ((unsigned)rc != size) { LogError("write of %d bytes (only %d written)", size, rc); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } /* * called by write_key_init to find the next available location in the PS file to * write a new key to. */ int find_write_offset(UINT32 pub_data_size, UINT32 blob_size, UINT32 vendor_data_size) { struct key_disk_cache *tmp; unsigned int offset; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; while (tmp) { /* if we find a deleted key of the right size, return its offset */ if (!(tmp->flags & CACHE_FLAG_VALID) && tmp->pub_data_size == pub_data_size && tmp->blob_size == blob_size && tmp->vendor_data_size == vendor_data_size) { offset = tmp->offset; MUTEX_UNLOCK(disk_cache_lock); return offset; } tmp = tmp->next; } MUTEX_UNLOCK(disk_cache_lock); /* no correctly sized holes */ return -1; } /* * move the file pointer to the point where the next key can be written and return * that offset */ int write_key_init(int fd, UINT32 pub_data_size, UINT32 blob_size, UINT32 vendor_data_size) { UINT32 num_keys; BYTE version; int rc, offset; /* seek to the PS version */ rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return -1; } /* go to NUM_KEYS */ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return -1; } /* read the number of keys */ rc = read(fd, &num_keys, sizeof(UINT32)); num_keys = LE_32(num_keys); if (rc == -1) { LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno)); return -1; } else if (rc == 0) { /* This is the first key being written */ num_keys = 1; version = 1; /* seek to the PS version */ rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return -1; } /* write out the version info byte */ if ((rc = write_data(fd, &version, sizeof(BYTE)))) { LogError("%s", __FUNCTION__); return rc; } rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return -1; } num_keys = LE_32(num_keys); if ((rc = write_data(fd, &num_keys, sizeof(UINT32)))) { LogError("%s", __FUNCTION__); return rc; } /* return the offset */ return (TSSPS_NUM_KEYS_OFFSET + sizeof(UINT32)); } /* if there is a hole in the file we can write to, find it */ offset = find_write_offset(pub_data_size, blob_size, vendor_data_size); if (offset != -1) { /* we found a hole, seek to it and don't increment the # of keys on disk */ rc = lseek(fd, offset, SEEK_SET); } else { /* we didn't find a hole, increment the number of keys on disk and seek * to the end of the file */ num_keys++; /* go to the beginning */ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return -1; } num_keys = LE_32(num_keys); if ((rc = write_data(fd, &num_keys, sizeof(UINT32)))) { LogError("%s", __FUNCTION__); return rc; } rc = lseek(fd, 0, SEEK_END); } if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return -1; } /* lseek returns the number of bytes of offset from the beginning of the file */ return rc; } /* * add a new cache entry for a written key */ TSS_RESULT cache_key(UINT32 offset, UINT16 flags, TSS_UUID *uuid, TSS_UUID *parent_uuid, UINT16 pub_data_size, UINT32 blob_size, UINT32 vendor_data_size) { struct key_disk_cache *tmp; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; for (; tmp; tmp = tmp->next) { /* reuse an invalidated key cache entry */ if (!(tmp->flags & CACHE_FLAG_VALID)) goto fill_cache_entry; } tmp = malloc(sizeof(struct key_disk_cache)); if (tmp == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct key_disk_cache)); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_OUTOFMEMORY); } tmp->next = key_disk_cache_head; key_disk_cache_head = tmp; fill_cache_entry: tmp->offset = offset; #ifdef TSS_DEBUG if (offset == 0) LogDebug("Storing key with file offset==0!!!"); #endif tmp->flags = flags; tmp->blob_size = blob_size; tmp->pub_data_size = pub_data_size; tmp->vendor_data_size = vendor_data_size; memcpy(&tmp->uuid, uuid, sizeof(TSS_UUID)); memcpy(&tmp->parent_uuid, parent_uuid, sizeof(TSS_UUID)); MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } /* * read into the PS file and return the number of keys */ int get_num_keys_in_file(int fd) { UINT32 num_keys; int rc; /* go to the number of keys */ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return 0; } rc = read(fd, &num_keys, sizeof(UINT32)); if (rc < 0) { LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno)); return 0; } else if ((unsigned)rc < sizeof(UINT32)) { num_keys = 0; } num_keys = LE_32(num_keys); return num_keys; } /* * count the number of valid keys in the cache */ int get_num_keys() { int num_keys = 0; struct key_disk_cache *tmp; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; for (; tmp; tmp = tmp->next) { if (tmp->flags & CACHE_FLAG_VALID) num_keys++; } MUTEX_UNLOCK(disk_cache_lock); return num_keys; } /* * disk store format: * * TrouSerS 0.2.0 and before: * Version 0: cached? * [UINT32 num_keys_on_disk] * [TSS_UUID uuid0 ] yes * [TSS_UUID uuid_parent0 ] yes * [UINT16 pub_data_size0 ] yes * [UINT16 blob_size0 ] yes * [UINT16 cache_flags0 ] yes * [BYTE[] pub_data0 ] * [BYTE[] blob0 ] * [...] * * TrouSerS 0.2.1+ * Version 1: cached? * [BYTE PS version = '\1'] * [UINT32 num_keys_on_disk ] * [TSS_UUID uuid0 ] yes * [TSS_UUID uuid_parent0 ] yes * [UINT16 pub_data_size0 ] yes * [UINT16 blob_size0 ] yes * [UINT32 vendor_data_size0] yes * [UINT16 cache_flags0 ] yes * [BYTE[] pub_data0 ] * [BYTE[] blob0 ] * [BYTE[] vendor_data0 ] * [...] * */ /* * read the PS file pointed to by fd and create a cache based on it */ int init_disk_cache(int fd) { UINT32 num_keys = get_num_keys_in_file(fd); UINT16 i; UINT64 tmp_offset; int rc = 0, offset; struct key_disk_cache *tmp, *prev = NULL; BYTE srk_blob[2048]; TSS_KEY srk_key; #ifdef TSS_DEBUG int valid_keys = 0; #endif MUTEX_LOCK(disk_cache_lock); if (num_keys == 0) { key_disk_cache_head = NULL; MUTEX_UNLOCK(disk_cache_lock); return 0; } else { key_disk_cache_head = tmp = calloc(1, sizeof(struct key_disk_cache)); if (tmp == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct key_disk_cache)); rc = -1; goto err_exit; } } /* make sure the file pointer is where we expect, just after the number * of keys on disk at the head of the file */ offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET); if (offset == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); rc = -1; goto err_exit; } for (i=0; ioffset = offset; #ifdef TSS_DEBUG if (offset == 0) LogDebug("Storing key with file offset==0!!!"); #endif /* read UUID */ if ((rc = read_data(fd, (void *)&tmp->uuid, sizeof(TSS_UUID)))) { LogError("%s", __FUNCTION__); goto err_exit; } /* read parent UUID */ if ((rc = read_data(fd, (void *)&tmp->parent_uuid, sizeof(TSS_UUID)))) { LogError("%s", __FUNCTION__); goto err_exit; } /* pub data size */ if ((rc = read_data(fd, &tmp->pub_data_size, sizeof(UINT16)))) { LogError("%s", __FUNCTION__); goto err_exit; } tmp->pub_data_size = LE_16(tmp->pub_data_size); DBG_ASSERT(tmp->pub_data_size <= 2048 && tmp->pub_data_size > 0); /* blob size */ if ((rc = read_data(fd, &tmp->blob_size, sizeof(UINT16)))) { LogError("%s", __FUNCTION__); goto err_exit; } tmp->blob_size = LE_16(tmp->blob_size); DBG_ASSERT(tmp->blob_size <= 4096 && tmp->blob_size > 0); /* vendor data size */ if ((rc = read_data(fd, &tmp->vendor_data_size, sizeof(UINT32)))) { LogError("%s", __FUNCTION__); goto err_exit; } tmp->vendor_data_size = LE_32(tmp->vendor_data_size); /* cache flags */ if ((rc = read_data(fd, &tmp->flags, sizeof(UINT16)))) { LogError("%s", __FUNCTION__); goto err_exit; } tmp->flags = LE_16(tmp->flags); #ifdef TSS_DEBUG if (tmp->flags & CACHE_FLAG_VALID) valid_keys++; #endif /* fast forward over the pub key */ offset = lseek(fd, tmp->pub_data_size, SEEK_CUR); if (offset == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); rc = -1; goto err_exit; } /* if this is the SRK, load it into memory, since its already loaded in * the chip */ if (!memcmp(&SRK_UUID, &tmp->uuid, sizeof(TSS_UUID))) { /* read SRK blob from disk */ if ((rc = read_data(fd, srk_blob, tmp->blob_size))) { LogError("%s", __FUNCTION__); goto err_exit; } tmp_offset = 0; if ((rc = UnloadBlob_TSS_KEY(&tmp_offset, srk_blob, &srk_key))) goto err_exit; /* add to the mem cache */ if ((rc = mc_add_entry_init(SRK_TPM_HANDLE, SRK_TPM_HANDLE, &srk_key, &SRK_UUID))) { LogError("Error adding SRK to mem cache."); destroy_key_refs(&srk_key); goto err_exit; } destroy_key_refs(&srk_key); } else { /* fast forward over the blob */ offset = lseek(fd, tmp->blob_size, SEEK_CUR); if (offset == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); rc = -1; goto err_exit; } /* fast forward over the vendor data */ offset = lseek(fd, tmp->vendor_data_size, SEEK_CUR); if (offset == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); rc = -1; goto err_exit; } } tmp->next = calloc(1, sizeof(struct key_disk_cache)); if (tmp->next == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct key_disk_cache)); rc = -1; goto err_exit; } prev = tmp; tmp = tmp->next; } /* delete the dangling, unfilled cache entry */ free(tmp); prev->next = NULL; rc = 0; LogDebug("%s: found %d valid key(s) on disk.\n", __FUNCTION__, valid_keys); err_exit: MUTEX_UNLOCK(disk_cache_lock); return rc; } int close_disk_cache(int fd) { struct key_disk_cache *tmp, *tmp_next; if (key_disk_cache_head == NULL) return 0; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; do { tmp_next = tmp->next; free(tmp); tmp = tmp_next; } while (tmp); MUTEX_UNLOCK(disk_cache_lock); return 0; } trousers-0.3.15/src/tcs/ps/tcsps.c0000664000175000017510000005241313736474160016265 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #if defined (HAVE_BYTEORDER_H) #include #elif defined (HTOLE_DEFINED) #ifndef __APPLE__ #include #else #include "portable_endian.h" #endif #define LE_16 htole16 #define LE_32 htole32 #define LE_64 htole64 #else #define LE_16(x) (x) #define LE_32(x) (x) #define LE_64(x) (x) #endif #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcsps.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" int system_ps_fd = -1; MUTEX_DECLARE(disk_cache_lock); static struct flock fl; int get_file() { int rc; /* check the global file handle first. If it exists, lock it and return */ if (system_ps_fd != -1) { int rc = 0; fl.l_type = F_WRLCK; if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) { LogError("failed to get system PS lock: %s", strerror(errno)); return -1; } return system_ps_fd; } /* open and lock the file */ system_ps_fd = open(tcsd_options.system_ps_file, O_CREAT|O_RDWR|O_NOFOLLOW, 0600); if (system_ps_fd < 0) { LogError("system PS: open() of %s failed: %s", tcsd_options.system_ps_file, strerror(errno)); return -1; } fl.l_type = F_WRLCK; if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) { LogError("failed to get system PS lock of file %s: %s", tcsd_options.system_ps_file, strerror(errno)); return -1; } return system_ps_fd; } int put_file(int fd) { int rc = 0; /* release the file lock */ fl.l_type = F_UNLCK; if ((rc = fcntl(fd, F_SETLKW, &fl))) { LogError("failed to unlock system PS file: %s", strerror(errno)); return -1; } return rc; } void close_file(int fd) { close(fd); system_ps_fd = -1; } TSS_RESULT psfile_get_parent_uuid_by_uuid(int fd, TSS_UUID *uuid, TSS_UUID *ret_uuid) { int rc; UINT32 file_offset = 0; struct key_disk_cache *tmp; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; while (tmp) { if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) { tmp = tmp->next; continue; } /* jump to the location of the parent uuid */ file_offset = TSSPS_PARENT_UUID_OFFSET(tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); MUTEX_UNLOCK(disk_cache_lock); return -1; } if ((rc = read_data(fd, ret_uuid, sizeof(TSS_UUID)))) { LogError("%s", __FUNCTION__); MUTEX_UNLOCK(disk_cache_lock); return rc; } MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } MUTEX_UNLOCK(disk_cache_lock); /* key not found */ return -2; } /* * return a key blob from PS given a uuid */ TSS_RESULT psfile_get_key_by_uuid(int fd, TSS_UUID *uuid, BYTE *ret_buffer, UINT16 *ret_buffer_size) { int rc; UINT32 file_offset = 0; struct key_disk_cache *tmp; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; while (tmp) { if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) { tmp = tmp->next; continue; } /* jump to the location of the key blob */ file_offset = TSSPS_BLOB_DATA_OFFSET(tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } /* we found the key; file ptr is pointing at the blob */ if (*ret_buffer_size < tmp->blob_size) { /* not enough room */ MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_FAIL); } if ((rc = read_data(fd, ret_buffer, tmp->blob_size))) { LogError("%s", __FUNCTION__); MUTEX_UNLOCK(disk_cache_lock); return rc; } *ret_buffer_size = tmp->blob_size; LogDebugUnrollKey(ret_buffer); MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } MUTEX_UNLOCK(disk_cache_lock); /* key not found */ return TCSERR(TSS_E_FAIL); } /* * return a key blob from PS given its cache entry. The disk cache must be * locked by the caller. */ TSS_RESULT psfile_get_key_by_cache_entry(int fd, struct key_disk_cache *c, BYTE *ret_buffer, UINT16 *ret_buffer_size) { int rc; UINT32 file_offset = 0; /* jump to the location of the key blob */ file_offset = TSSPS_BLOB_DATA_OFFSET(c); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* we found the key; file ptr is pointing at the blob */ if (*ret_buffer_size < c->blob_size) { /* not enough room */ LogError("%s: Buf size too small. Needed %d bytes, passed %d", __FUNCTION__, c->blob_size, *ret_buffer_size); return TCSERR(TSS_E_INTERNAL_ERROR); } if ((rc = read_data(fd, ret_buffer, c->blob_size))) { LogError("%s: error reading %d bytes", __FUNCTION__, c->blob_size); return TCSERR(TSS_E_INTERNAL_ERROR); } *ret_buffer_size = c->blob_size; return TSS_SUCCESS; } /* * return the vendor data from PS given its cache entry. The disk cache must be * locked by the caller. */ TSS_RESULT psfile_get_vendor_data(int fd, struct key_disk_cache *c, UINT32 *size, BYTE **data) { int rc; UINT32 file_offset; /* jump to the location of the data */ file_offset = TSSPS_VENDOR_DATA_OFFSET(c); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } if ((*data = malloc(c->vendor_data_size)) == NULL) { LogError("malloc of %u bytes failed", c->vendor_data_size); return TCSERR(TSS_E_OUTOFMEMORY); } if ((rc = read_data(fd, *data, c->vendor_data_size))) { LogError("%s: error reading %u bytes", __FUNCTION__, c->vendor_data_size); free(*data); *data = NULL; return TCSERR(TSS_E_INTERNAL_ERROR); } *size = c->vendor_data_size; return TSS_SUCCESS; } TSS_RESULT psfile_get_ps_type_by_uuid(int fd, TSS_UUID *uuid, UINT32 *ret_ps_type) { struct key_disk_cache *tmp; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; while (tmp) { if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) { tmp = tmp->next; continue; } if (tmp->flags & CACHE_FLAG_PARENT_PS_SYSTEM) { *ret_ps_type = TSS_PS_TYPE_SYSTEM; goto done; } else break; } *ret_ps_type = TSS_PS_TYPE_USER; done: MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } TSS_RESULT psfile_is_pub_registered(int fd, TCPA_STORE_PUBKEY *pub, TSS_BOOL *is_reg) { int rc; UINT32 file_offset = 0; struct key_disk_cache *tmp; char tmp_buffer[2048]; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; while (tmp) { /* if the key is of the wrong size or is invalid, try the next one */ if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) { tmp = tmp->next; continue; } /* we have a valid key with the same key size as the one we're looking for. * grab the pub key data off disk and compare it. */ /* jump to the location of the public key */ file_offset = TSSPS_PUB_DATA_OFFSET(tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } DBG_ASSERT(tmp->pub_data_size < 2048); /* read in the key */ if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) { LogError("%s", __FUNCTION__); MUTEX_UNLOCK(disk_cache_lock); return rc; } /* do the compare */ if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) { tmp = tmp->next; continue; } /* the key matches, copy the uuid out */ *is_reg = TRUE; MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } MUTEX_UNLOCK(disk_cache_lock); /* key not found */ *is_reg = FALSE; return TSS_SUCCESS; } TSS_RESULT psfile_get_uuid_by_pub(int fd, TCPA_STORE_PUBKEY *pub, TSS_UUID **ret_uuid) { int rc; UINT32 file_offset = 0; struct key_disk_cache *tmp; char tmp_buffer[2048]; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; while (tmp) { /* if the key is of the wrong size or is invalid, try the next one */ if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) { tmp = tmp->next; continue; } /* we have a valid key with the same key size as the one we're looking for. * grab the pub key data off disk and compare it. */ /* jump to the location of the public key */ file_offset = TSSPS_PUB_DATA_OFFSET(tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } DBG_ASSERT(tmp->pub_data_size < 2048); if (tmp->pub_data_size > sizeof(tmp_buffer)) { LogError("Source buffer size too big! Size: %d", tmp->pub_data_size); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } /* read in the key */ if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) { LogError("%s", __FUNCTION__); MUTEX_UNLOCK(disk_cache_lock); return rc; } /* do the compare */ if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) { tmp = tmp->next; continue; } *ret_uuid = (TSS_UUID *)malloc(sizeof(TSS_UUID)); if (*ret_uuid == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_UUID)); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_OUTOFMEMORY); } /* the key matches, copy the uuid out */ memcpy(*ret_uuid, &tmp->uuid, sizeof(TSS_UUID)); MUTEX_UNLOCK(disk_cache_lock); return TSS_SUCCESS; } MUTEX_UNLOCK(disk_cache_lock); /* key not found */ return TCSERR(TSS_E_PS_KEY_NOTFOUND); } TSS_RESULT psfile_get_key_by_pub(int fd, TCPA_STORE_PUBKEY *pub, UINT32 *size, BYTE **ret_key) { int rc; UINT32 file_offset = 0; struct key_disk_cache *tmp; BYTE tmp_buffer[4096]; MUTEX_LOCK(disk_cache_lock); tmp = key_disk_cache_head; while (tmp) { /* if the key is of the wrong size or is invalid, try the next one */ if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) { tmp = tmp->next; continue; } /* we have a valid key with the same key size as the one we're looking for. * grab the pub key data off disk and compare it. */ /* jump to the location of the public key */ file_offset = TSSPS_PUB_DATA_OFFSET(tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } DBG_ASSERT(tmp->pub_data_size < 2048); if (tmp->pub_data_size > sizeof(tmp_buffer)) { LogError("Source buffer size too big! Size: %d", tmp->pub_data_size); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } /* read in the key */ if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) { LogError("%s", __FUNCTION__); MUTEX_UNLOCK(disk_cache_lock); return rc; } /* do the compare */ if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) { tmp = tmp->next; continue; } /* jump to the location of the key blob */ file_offset = TSSPS_BLOB_DATA_OFFSET(tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } DBG_ASSERT(tmp->blob_size < 4096); if (tmp->blob_size > sizeof(tmp_buffer)) { LogError("Blob size greater than 4096! Size: %d", tmp->blob_size); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_INTERNAL_ERROR); } /* read in the key blob */ if ((rc = read_data(fd, tmp_buffer, tmp->blob_size))) { LogError("%s", __FUNCTION__); MUTEX_UNLOCK(disk_cache_lock); return rc; } *ret_key = malloc(tmp->blob_size); if (*ret_key == NULL) { LogError("malloc of %d bytes failed.", tmp->blob_size); MUTEX_UNLOCK(disk_cache_lock); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(*ret_key, tmp_buffer, tmp->blob_size); *size = tmp->blob_size; MUTEX_UNLOCK(disk_cache_lock); return rc; } MUTEX_UNLOCK(disk_cache_lock); /* key not found */ return -2; } /* * disk store format: * * TrouSerS 0.2.0 and before: * Version 0: cached? * [UINT32 num_keys_on_disk] * [TSS_UUID uuid0 ] yes * [TSS_UUID uuid_parent0 ] yes * [UINT16 pub_data_size0 ] yes * [UINT16 blob_size0 ] yes * [UINT16 cache_flags0 ] yes * [BYTE[] pub_data0 ] * [BYTE[] blob0 ] * [...] * * TrouSerS 0.2.1+ * Version 1: cached? * [BYTE PS version = '\1'] * [UINT32 num_keys_on_disk ] * [TSS_UUID uuid0 ] yes * [TSS_UUID uuid_parent0 ] yes * [UINT16 pub_data_size0 ] yes * [UINT16 blob_size0 ] yes * [UINT32 vendor_data_size0] yes * [UINT16 cache_flags0 ] yes * [BYTE[] pub_data0 ] * [BYTE[] blob0 ] * [BYTE[] vendor_data0 ] * [...] * */ TSS_RESULT psfile_write_key(int fd, TSS_UUID *uuid, TSS_UUID *parent_uuid, UINT32 *parent_ps, BYTE *vendor_data, UINT32 vendor_size, BYTE *key_blob, UINT16 key_blob_size) { TSS_KEY key; UINT16 pub_key_size, cache_flags = CACHE_FLAG_VALID; UINT64 offset; int rc = 0; /* leaving the cache flag for parent ps type as 0 implies TSS_PS_TYPE_USER */ if (*parent_ps == TSS_PS_TYPE_SYSTEM) cache_flags |= CACHE_FLAG_PARENT_PS_SYSTEM; /* Unload the blob to get the public key */ offset = 0; if ((rc = UnloadBlob_TSS_KEY(&offset, key_blob, &key))) return rc; pub_key_size = key.pubKey.keyLength; if ((rc = write_key_init(fd, pub_key_size, key_blob_size, vendor_size)) < 0) goto done; /* offset now holds the number of bytes from the beginning of the file * the key will be stored at */ offset = rc; #ifdef TSS_DEBUG if (offset == 0) LogDebug("ERROR: key being written with offset 0!!"); #endif /* [TSS_UUID uuid0 ] yes */ if ((rc = write_data(fd, (void *)uuid, sizeof(TSS_UUID)))) { LogError("%s", __FUNCTION__); goto done; } /* [TSS_UUID uuid_parent0 ] yes */ if ((rc = write_data(fd, (void *)parent_uuid, sizeof(TSS_UUID)))) { LogError("%s", __FUNCTION__); goto done; } /* [UINT16 pub_data_size0 ] yes */ pub_key_size = LE_16(pub_key_size); if ((rc = write_data(fd, &pub_key_size, sizeof(UINT16)))) { LogError("%s", __FUNCTION__); goto done; } /* Swap it back for later */ pub_key_size = LE_16(pub_key_size); /* [UINT16 blob_size0 ] yes */ key_blob_size = LE_16(key_blob_size); if ((rc = write_data(fd, &key_blob_size, sizeof(UINT16)))) { LogError("%s", __FUNCTION__); goto done; } /* Swap it back for later */ key_blob_size = LE_16(key_blob_size); /* [UINT32 vendor_data_size0 ] yes */ vendor_size = LE_32(vendor_size); if ((rc = write_data(fd, &vendor_size, sizeof(UINT32)))) { LogError("%s", __FUNCTION__); goto done; } /* Swap it back for later */ vendor_size = LE_32(vendor_size); /* [UINT16 cache_flags0 ] yes */ cache_flags = LE_16(cache_flags); if ((rc = write_data(fd, &cache_flags, sizeof(UINT16)))) { LogError("%s", __FUNCTION__); goto done; } /* Swap it back for later */ cache_flags = LE_16(cache_flags); /* [BYTE[] pub_data0 ] no */ if ((rc = write_data(fd, (void *)key.pubKey.key, pub_key_size))) { LogError("%s", __FUNCTION__); goto done; } /* [BYTE[] blob0 ] no */ if ((rc = write_data(fd, (void *)key_blob, key_blob_size))) { LogError("%s", __FUNCTION__); goto done; } /* [BYTE[] vendor_data0 ] no */ if (vendor_size > 0) { if ((rc = write_data(fd, (void *)vendor_data, vendor_size))) { LogError("%s", __FUNCTION__); goto done; } } if ((rc = cache_key((UINT32)offset, cache_flags, uuid, parent_uuid, pub_key_size, key_blob_size, vendor_size))) goto done; done: destroy_key_refs(&key); return rc; } TSS_RESULT psfile_remove_key(int fd, struct key_disk_cache *c) { TSS_RESULT result; UINT32 head_offset = 0, tail_offset, num_keys; BYTE buf[4096]; struct stat stat_buf; int rc, size = 0; if ((rc = fstat(fd, &stat_buf)) != 0) { LogError("fstat: %s", strerror(errno)); return TSS_E_INTERNAL_ERROR; } /* head_offset is the offset the beginning of the key */ head_offset = TSSPS_UUID_OFFSET(c); /* tail_offset is the offset the beginning of the next key */ tail_offset = TSSPS_VENDOR_DATA_OFFSET(c) + c->vendor_data_size; rc = lseek(fd, tail_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* read in from tail, write out to head to fill the gap */ while ((rc = read(fd, buf, sizeof(buf))) > 0) { size = rc; tail_offset += size; /* set the file pointer to where we want to write */ rc = lseek(fd, head_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* write the data */ if ((result = write_data(fd, (void *)buf, size))) { LogError("%s", __FUNCTION__); return result; } head_offset += size; /* set the file pointer to where we want to read in the next * loop */ rc = lseek(fd, tail_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } } if (rc < 0) { LogError("read: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* set the file pointer to where we want to write */ rc = lseek(fd, head_offset, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* head_offset now contains a pointer to where we want to truncate the * file. Zero out the old tail end of the file and truncate it. */ memset(buf, 0, sizeof(buf)); /* Zero out the old tail end of the file */ if ((result = write_data(fd, (void *)buf, tail_offset - head_offset))) { LogError("%s", __FUNCTION__); return result; } if ((rc = ftruncate(fd, head_offset)) < 0) { LogError("ftruncate: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* we succeeded in removing a key from the disk. Decrement the number * of keys in the file */ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } rc = read(fd, &num_keys, sizeof(UINT32)); num_keys = LE_32(num_keys); if (rc != sizeof(UINT32)) { LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t) - 1)) { LogError("lseek: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* decrement, then write back out to disk */ num_keys--; num_keys = LE_32(num_keys); if ((result = write_data(fd, (void *)&num_keys, sizeof(UINT32)))) { LogError("%s", __FUNCTION__); return result; } return TSS_SUCCESS; } trousers-0.3.15/src/tcs/tcs_evlog.c0000664000175000017510000001205313663651711016466 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcslog.h" #include "tcsem.h" struct event_log *tcs_event_log = NULL; TSS_RESULT event_log_init() { if (tcs_event_log != NULL) return TSS_SUCCESS; tcs_event_log = calloc(1, sizeof(struct event_log)); if (tcs_event_log == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct event_log)); return TCSERR(TSS_E_OUTOFMEMORY); } MUTEX_INIT(tcs_event_log->lock); /* allocate as many event lists as there are PCR's */ tcs_event_log->lists = calloc(tpm_metrics.num_pcrs, sizeof(struct event_wrapper *)); if (tcs_event_log->lists == NULL) { LogError("malloc of %zd bytes failed.", tpm_metrics.num_pcrs * sizeof(struct event_wrapper *)); free(tcs_event_log); return TCSERR(TSS_E_OUTOFMEMORY); } /* assign external event log sources here */ //tcs_event_log->firmware_source = EVLOG_IMA_SOURCE; tcs_event_log->firmware_source = EVLOG_BIOS_SOURCE; tcs_event_log->kernel_source = EVLOG_IMA_SOURCE; return TSS_SUCCESS; } TSS_RESULT event_log_final() { struct event_wrapper *cur, *next; UINT32 i; MUTEX_LOCK(tcs_event_log->lock); for (i = 0; i < tpm_metrics.num_pcrs; i++) { cur = tcs_event_log->lists[i]; while (cur != NULL) { next = cur->next; free(cur->event.rgbPcrValue); free(cur->event.rgbEvent); free(cur); cur = next; } } MUTEX_UNLOCK(tcs_event_log->lock); free(tcs_event_log->lists); free(tcs_event_log); return TSS_SUCCESS; } TSS_RESULT copy_pcr_event(TSS_PCR_EVENT *dest, TSS_PCR_EVENT *source) { memcpy(dest, source, sizeof(TSS_PCR_EVENT)); return TSS_SUCCESS; } TSS_RESULT event_log_add(TSS_PCR_EVENT *event, UINT32 *pNumber) { struct event_wrapper *new, *tmp; TSS_RESULT result; UINT32 i; MUTEX_LOCK(tcs_event_log->lock); new = calloc(1, sizeof(struct event_wrapper)); if (new == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct event_wrapper)); MUTEX_UNLOCK(tcs_event_log->lock); return TCSERR(TSS_E_OUTOFMEMORY); } if ((result = copy_pcr_event(&(new->event), event))) { free(new); MUTEX_UNLOCK(tcs_event_log->lock); return result; } /* go to the end of the list to add the element, so that they're in order */ i = 0; if (tcs_event_log->lists[event->ulPcrIndex] == NULL) { tcs_event_log->lists[event->ulPcrIndex] = new; } else { i++; tmp = tcs_event_log->lists[event->ulPcrIndex]; while (tmp->next != NULL) { i++; tmp = tmp->next; } tmp->next = new; } *pNumber = ++i; MUTEX_UNLOCK(tcs_event_log->lock); return TSS_SUCCESS; } TSS_PCR_EVENT * get_pcr_event(UINT32 pcrIndex, UINT32 eventNumber) { struct event_wrapper *tmp; UINT32 counter = 0; MUTEX_LOCK(tcs_event_log->lock); tmp = tcs_event_log->lists[pcrIndex]; for (; tmp; tmp = tmp->next) { if (counter == eventNumber) { break; } counter++; } MUTEX_UNLOCK(tcs_event_log->lock); return (tmp ? &(tmp->event) : NULL); } /* the lock should be held before calling this function */ UINT32 get_num_events(UINT32 pcrIndex) { struct event_wrapper *tmp; UINT32 counter = 0; tmp = tcs_event_log->lists[pcrIndex]; for (; tmp; tmp = tmp->next) { counter++; } return counter; } TSS_PCR_EVENT * concat_pcr_events(TSS_PCR_EVENT **list_so_far, UINT32 list_size, TSS_PCR_EVENT *addition, UINT32 addition_size) { TSS_PCR_EVENT *ret; ret = realloc(*list_so_far, (list_size + addition_size) * sizeof(TSS_PCR_EVENT)); if (ret == NULL) { LogError("malloc of %zd bytes failed", (list_size + addition_size) * sizeof(TSS_PCR_EVENT)); return ret; } memcpy(&ret[list_size], addition, addition_size * sizeof(TSS_PCR_EVENT)); return ret; } /* XXX make this a macro */ UINT32 get_pcr_event_size(TSS_PCR_EVENT *e) { return (sizeof(TSS_PCR_EVENT) + e->ulEventLength + e->ulPcrValueLength); } void free_external_events(UINT32 eventCount, TSS_PCR_EVENT *ppEvents) { UINT32 j; if (!ppEvents) return; for (j = 0; j < eventCount; j++) { /* This is a fairly heinous hack, but PCR event logs can get really large * and without it, there is a real potential to exhaust memory by leaks. * The PCR event logs that we pull out of securityfs have had their * rgbPcrValue and rgbEvent pointers malloc'd dynamically as the * securityfs log was parsed. The other event log lists that are * maintained by the TCSD don't need to have this data free'd, since that * will happen at shutdown time only. So, for each PCR index that's * read from securityfs, we need to free its pointers after that data has * been set in the packet to send back to the TSP. */ if ((tcsd_options.kernel_pcrs & (1 << ppEvents[j].ulPcrIndex)) || (tcsd_options.firmware_pcrs & (1 << ppEvents[j].ulPcrIndex))) { free(ppEvents[j].rgbPcrValue); free(ppEvents[j].rgbEvent); } } } trousers-0.3.15/src/tcs/tcsi_pcr.c0000664000175000017510000000635713663651711016321 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * (C) Christian Kummer 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_Extend_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_DIGEST inDigest, /* in */ TCPA_PCRVALUE * outDigest) /* out */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Extend"); if ((result = ctx_verify_context(hContext))) return result; /* PCRs are numbered 0 - (NUM_PCRS - 1), thus the >= */ if (pcrNum >= tpm_metrics.num_pcrs) return TCSERR(TSS_E_BAD_PARAMETER); if (tcsd_options.kernel_pcrs & (1 << pcrNum)) { LogInfo("PCR %d is configured to be kernel controlled. Extend request denied.", pcrNum); return TCSERR(TSS_E_FAIL); } if (tcsd_options.firmware_pcrs & (1 << pcrNum)) { LogInfo("PCR %d is configured to be firmware controlled. Extend request denied.", pcrNum); return TCSERR(TSS_E_FAIL); } if ((result = tpm_rqu_build(TPM_ORD_Extend, &offset, txBlob, pcrNum, TPM_DIGEST_SIZE, inDigest.digest, NULL, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Extend, txBlob, paramSize, NULL, outDigest->digest); } LogResult("Extend", result); return result; } TSS_RESULT TCSP_PcrRead_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_PCRVALUE * outDigest) /* out */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering PCRRead"); if ((result = ctx_verify_context(hContext))) return result; /* PCRs are numbered 0 - (NUM_PCRS - 1), thus the >= */ if (pcrNum >= tpm_metrics.num_pcrs) return TCSERR(TSS_E_BAD_PARAMETER); if ((result = tpm_rqu_build(TPM_ORD_PcrRead, &offset, txBlob, pcrNum, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_PcrRead, txBlob, paramSize, NULL, outDigest->digest); } LogResult("PCR Read", result); return result; } TSS_RESULT TCSP_PcrReset_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn) /* in */ { UINT64 offset = 0; TSS_RESULT result; UINT32 paramSize; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering PCRReset"); if ((result = ctx_verify_context(hContext))) return result; if ((result = tpm_rqu_build(TPM_ORD_PCR_Reset, &offset, txBlob, pcrDataSizeIn, pcrDataIn))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); LogResult("PCR Reset", result); return result; } trousers-0.3.15/src/tcs/tcs_key_mem_cache.c0000664000175000017510000007424013663651711020131 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsps.h" #include "req_mgr.h" #include "tcs_key_ps.h" /* * mem_cache_lock will be responsible for protecting the key_mem_cache_head list. This is a * TCSD global linked list of all keys which have been loaded into the TPM at some time. */ MUTEX_DECLARE_INIT(mem_cache_lock); /* * tcs_keyhandle_lock is only used to make TCS keyhandle generation atomic for all TCSD * threads. */ static MUTEX_DECLARE_INIT(tcs_keyhandle_lock); /* * timestamp_lock is only used to make TCS key timestamp generation atomic for all TCSD * threads. */ static MUTEX_DECLARE_INIT(timestamp_lock); TCS_KEY_HANDLE getNextTcsKeyHandle() { static TCS_KEY_HANDLE NextTcsKeyHandle = 0x22330000; TCS_KEY_HANDLE ret; MUTEX_LOCK(tcs_keyhandle_lock); do { ret = NextTcsKeyHandle++; } while (NextTcsKeyHandle == SRK_TPM_HANDLE || NextTcsKeyHandle == NULL_TCS_HANDLE); MUTEX_UNLOCK(tcs_keyhandle_lock); return ret; } UINT32 getNextTimeStamp() { static UINT32 time_stamp = 1; UINT32 ret; MUTEX_LOCK(timestamp_lock); ret = time_stamp++; MUTEX_UNLOCK(timestamp_lock); return ret; } /* only called from load key paths, so no locking */ TCPA_STORE_PUBKEY * mc_get_pub_by_slot(TCPA_KEY_HANDLE tpm_handle) { struct key_mem_cache *tmp; TCPA_STORE_PUBKEY *ret; if (tpm_handle == NULL_TPM_HANDLE) return NULL; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tpm_handle == tpm_handle) { ret = tmp->blob ? &tmp->blob->pubKey : NULL; return ret; } } LogDebugFn("returning NULL TCPA_STORE_PUBKEY"); return NULL; } /* only called from load key paths, so no locking */ TCPA_STORE_PUBKEY * mc_get_pub_by_handle(TCS_KEY_HANDLE tcs_handle) { struct key_mem_cache *tmp; TCPA_STORE_PUBKEY *ret; LogDebugFn("looking for 0x%x", tcs_handle); for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tcs_handle == tcs_handle) { ret = tmp->blob ? &tmp->blob->pubKey : NULL; return ret; } } LogDebugFn("returning NULL TCPA_STORE_PUBKEY"); return NULL; } /* only called from load key paths, so no locking */ TSS_RESULT mc_set_parent_by_handle(TCS_KEY_HANDLE tcs_handle, TCS_KEY_HANDLE p_tcs_handle) { struct key_mem_cache *tmp, *parent; /* find parent */ for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebug("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tcs_handle == p_tcs_handle) { parent = tmp; break; } } /* didn't find parent */ if (tmp == NULL) goto done; /* set parent blob in child */ for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { if (tmp->tcs_handle == tcs_handle) { tmp->parent = parent; return TSS_SUCCESS; } } done: return TCSERR(TSS_E_FAIL); } TCPA_RESULT ensureKeyIsLoaded(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE keyHandle, TCPA_KEY_HANDLE * keySlot) { TCPA_RESULT result = TSS_SUCCESS; TCPA_STORE_PUBKEY *myPub; LogDebugFn("0x%x", keyHandle); if (!ctx_has_key_loaded(hContext, keyHandle)) return TCSERR(TCS_E_INVALID_KEY); MUTEX_LOCK(mem_cache_lock); *keySlot = mc_get_slot_by_handle(keyHandle); LogDebug("keySlot is %08X", *keySlot); if (*keySlot == NULL_TPM_HANDLE || isKeyLoaded(*keySlot) == FALSE) { LogDebug("calling mc_get_pub_by_handle"); if ((myPub = mc_get_pub_by_handle(keyHandle)) == NULL) { LogDebug("Failed to find pub by handle"); result = TCSERR(TCS_E_KM_LOADFAILED); goto done; } LogDebugFn("calling LoadKeyShim"); if ((result = LoadKeyShim(hContext, myPub, NULL, keySlot))) { LogDebug("Failed shim"); goto done; } if (*keySlot == NULL_TPM_HANDLE) { LogDebug("Key slot is still invalid after ensureKeyIsLoaded"); result = TCSERR(TCS_E_KM_LOADFAILED); goto done; } } mc_update_time_stamp(*keySlot); done: MUTEX_UNLOCK(mem_cache_lock); LogDebugFn("Exit"); return result; } /* only called from load key paths, so no locking */ TSS_UUID * mc_get_uuid_by_pub(TCPA_STORE_PUBKEY *pub) { TSS_UUID *ret; struct key_mem_cache *tmp; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->blob && tmp->blob->pubKey.keyLength == pub->keyLength && !memcmp(tmp->blob->pubKey.key, pub->key, pub->keyLength)) { ret = &tmp->uuid; return ret; } } return NULL; } TSS_RESULT mc_get_handles_by_uuid(TSS_UUID *uuid, TCS_KEY_HANDLE *tcsHandle, TCPA_KEY_HANDLE *slot) { struct key_mem_cache *tmp; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { if (!memcmp(&tmp->uuid, uuid, sizeof(TSS_UUID))) { *tcsHandle = tmp->tcs_handle; *slot = tmp->tpm_handle; return TSS_SUCCESS; } } return TCSERR(TSS_E_FAIL); } TCS_KEY_HANDLE mc_get_handle_by_encdata(BYTE *encData) { struct key_mem_cache *tmp; TCS_KEY_HANDLE ret; MUTEX_LOCK(mem_cache_lock); for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (!tmp->blob || tmp->blob->encSize == 0) continue; if (!memcmp(tmp->blob->encData, encData, tmp->blob->encSize)) { ret = tmp->tcs_handle; MUTEX_UNLOCK(mem_cache_lock); return ret; } } MUTEX_UNLOCK(mem_cache_lock); return 0; } TSS_RESULT mc_update_encdata(BYTE *encData, BYTE *newEncData) { struct key_mem_cache *tmp; BYTE *tmp_enc_data; MUTEX_LOCK(mem_cache_lock); for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (!tmp->blob || tmp->blob->encSize == 0) continue; if (!memcmp(tmp->blob->encData, encData, tmp->blob->encSize)) { tmp_enc_data = (BYTE *)malloc(tmp->blob->encSize); if (tmp_enc_data == NULL) { LogError("malloc of %u bytes failed.", tmp->blob->encSize); MUTEX_UNLOCK(mem_cache_lock); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(tmp_enc_data, newEncData, tmp->blob->encSize); free(tmp->blob->encData); tmp->blob->encData = tmp_enc_data; MUTEX_UNLOCK(mem_cache_lock); return TSS_SUCCESS; } } MUTEX_UNLOCK(mem_cache_lock); LogError("Couldn't find requested encdata in mem cache"); return TCSERR(TSS_E_INTERNAL_ERROR); } /* * only called from load key paths and the init (single thread time) path, * so no locking */ TSS_RESULT mc_add_entry(TCS_KEY_HANDLE tcs_handle, TCPA_KEY_HANDLE tpm_handle, TSS_KEY *key_blob) { struct key_mem_cache *entry, *tmp; /* Make sure the cache doesn't already have an entry for this key */ for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tcs_handle == tmp->tcs_handle) { return TSS_SUCCESS; } } /* Not found - we need to create a new entry */ entry = (struct key_mem_cache *)calloc(1, sizeof(struct key_mem_cache)); if (entry == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct key_mem_cache)); return TCSERR(TSS_E_OUTOFMEMORY); } entry->tcs_handle = tcs_handle; if (tpm_handle != NULL_TPM_HANDLE) entry->time_stamp = getNextTimeStamp(); entry->tpm_handle = tpm_handle; if (!key_blob) goto add; /* allocate space for the blob */ entry->blob = calloc(1, sizeof(TSS_KEY)); if (entry->blob == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_KEY)); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(entry->blob, key_blob, sizeof(TSS_KEY)); /* allocate space for the key parameters if necessary */ if (key_blob->algorithmParms.parmSize) { BYTE *tmp_parms = (BYTE *)malloc(key_blob->algorithmParms.parmSize); if (tmp_parms == NULL) { LogError("malloc of %u bytes failed.", key_blob->algorithmParms.parmSize); free(entry->blob); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(tmp_parms, key_blob->algorithmParms.parms, key_blob->algorithmParms.parmSize); entry->blob->algorithmParms.parms = tmp_parms; } entry->blob->algorithmParms.parmSize = key_blob->algorithmParms.parmSize; /* allocate space for the public key */ if (key_blob->pubKey.keyLength > 0) { entry->blob->pubKey.key = (BYTE *)malloc(key_blob->pubKey.keyLength); if (entry->blob->pubKey.key == NULL) { LogError("malloc of %u bytes failed.", key_blob->pubKey.keyLength); free(entry->blob->algorithmParms.parms); free(entry->blob); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(entry->blob->pubKey.key, key_blob->pubKey.key, key_blob->pubKey.keyLength); } entry->blob->pubKey.keyLength = key_blob->pubKey.keyLength; /* allocate space for the PCR info */ if (key_blob->PCRInfoSize > 0) { entry->blob->PCRInfo = (BYTE *)malloc(key_blob->PCRInfoSize); if (entry->blob->PCRInfo == NULL) { LogError("malloc of %u bytes failed.", key_blob->PCRInfoSize); free(entry->blob->pubKey.key); free(entry->blob->algorithmParms.parms); free(entry->blob); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(entry->blob->PCRInfo, key_blob->PCRInfo, key_blob->PCRInfoSize); } entry->blob->PCRInfoSize = key_blob->PCRInfoSize; /* allocate space for the encData if necessary */ if (key_blob->encSize > 0) { entry->blob->encData = (BYTE *)malloc(key_blob->encSize); if (entry->blob->encData == NULL) { LogError("malloc of %u bytes failed.", key_blob->encSize); free(entry->blob->PCRInfo); free(entry->blob->pubKey.key); free(entry->blob->algorithmParms.parms); free(entry->blob); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(entry->blob->encData, key_blob->encData, key_blob->encSize); } entry->blob->encSize = key_blob->encSize; add: /* add to the front of the list */ entry->next = key_mem_cache_head; if (key_mem_cache_head) { /* set the reference count to 0 initially for all keys not being the SRK. Up * the call chain, a reference to this mem cache entry will be set in the * context object of the calling context and this reference count will be * incremented there. */ entry->ref_cnt = 0; key_mem_cache_head->prev = entry; } else { /* if we are the SRK, initially set the reference count to 1, so that it is * always seen as loaded in the TPM. */ entry->ref_cnt = 1; } key_mem_cache_head = entry; return TSS_SUCCESS; } /* caller must lock the mem cache before calling! */ TSS_RESULT mc_remove_entry(TCS_KEY_HANDLE tcs_handle) { struct key_mem_cache *cur; for (cur = key_mem_cache_head; cur; cur = cur->next) { if (cur->tcs_handle == tcs_handle) { if (cur->blob) { destroy_key_refs(cur->blob); free(cur->blob); } if (cur->prev != NULL) cur->prev->next = cur->next; if (cur->next != NULL) cur->next->prev = cur->prev; if (cur == key_mem_cache_head) key_mem_cache_head = cur->next; free(cur); return TSS_SUCCESS; } } return TCSERR(TSS_E_FAIL); } TSS_RESULT mc_add_entry_init(TCS_KEY_HANDLE tcs_handle, TCPA_KEY_HANDLE tpm_handle, TSS_KEY *key_blob, TSS_UUID *uuid) { struct key_mem_cache *entry, *tmp; /* Make sure the cache doesn't already have an entry for this key */ MUTEX_LOCK(mem_cache_lock); for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { if (tcs_handle == tmp->tcs_handle) { mc_remove_entry(tcs_handle); } } MUTEX_UNLOCK(mem_cache_lock); /* Not found - we need to create a new entry */ entry = (struct key_mem_cache *)calloc(1, sizeof(struct key_mem_cache)); if (entry == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct key_mem_cache)); return TCSERR(TSS_E_OUTOFMEMORY); } entry->tcs_handle = tcs_handle; if (tpm_handle != NULL_TPM_HANDLE) entry->time_stamp = getNextTimeStamp(); entry->tpm_handle = tpm_handle; if (key_blob) { /* allocate space for the blob */ entry->blob = malloc(sizeof(TSS_KEY)); if (entry->blob == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_KEY)); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(entry->blob, key_blob, sizeof(TSS_KEY)); /* allocate space for the key parameters if necessary */ if (key_blob->algorithmParms.parmSize) { BYTE *tmp_parms = (BYTE *)malloc(key_blob->algorithmParms.parmSize); if (tmp_parms == NULL) { LogError("malloc of %u bytes failed.", key_blob->algorithmParms.parmSize); free(entry->blob); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(tmp_parms, key_blob->algorithmParms.parms, key_blob->algorithmParms.parmSize); entry->blob->algorithmParms.parms = tmp_parms; } /* allocate space for the public key */ entry->blob->pubKey.key = (BYTE *)malloc(key_blob->pubKey.keyLength); if (entry->blob->pubKey.key == NULL) { LogError("malloc of %u bytes failed.", key_blob->pubKey.keyLength); free(entry->blob); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(entry->blob->pubKey.key, key_blob->pubKey.key, key_blob->pubKey.keyLength); /* allocate space for the encData if necessary */ if (key_blob->encSize != 0) { entry->blob->encData = (BYTE *)malloc(key_blob->encSize); if (entry->blob->encData == NULL) { LogError("malloc of %u bytes failed.", key_blob->encSize); free(entry->blob->pubKey.key); free(entry->blob); free(entry); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(entry->blob->encData, key_blob->encData, key_blob->encSize); } entry->blob->encSize = key_blob->encSize; } memcpy(&entry->uuid, uuid, sizeof(TSS_UUID)); MUTEX_LOCK(mem_cache_lock); entry->next = key_mem_cache_head; if (key_mem_cache_head) key_mem_cache_head->prev = entry; entry->ref_cnt = 1; key_mem_cache_head = entry; MUTEX_UNLOCK(mem_cache_lock); return TSS_SUCCESS; } /* only called from evict key paths, so no locking */ TSS_RESULT mc_set_slot_by_slot(TCPA_KEY_HANDLE old_handle, TCPA_KEY_HANDLE new_handle) { struct key_mem_cache *tmp; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { if (tmp->tpm_handle == old_handle) { LogDebugFn("Set TCS key 0x%x, old TPM handle: 0x%x " "new TPM handle: 0x%x", tmp->tcs_handle, old_handle, new_handle); if (new_handle == NULL_TPM_HANDLE) tmp->time_stamp = 0; else tmp->time_stamp = getNextTimeStamp(); tmp->tpm_handle = new_handle; return TSS_SUCCESS; } } return TCSERR(TSS_E_FAIL); } /* only called from load key paths, so no locking */ TSS_RESULT mc_set_slot_by_handle(TCS_KEY_HANDLE tcs_handle, TCPA_KEY_HANDLE tpm_handle) { struct key_mem_cache *tmp; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebug("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tcs_handle == tcs_handle) { if (tpm_handle == NULL_TPM_HANDLE) tmp->time_stamp = 0; else tmp->time_stamp = getNextTimeStamp(); tmp->tpm_handle = tpm_handle; return TSS_SUCCESS; } } return TCSERR(TSS_E_FAIL); } /* the beginnings of a key manager start here ;-) */ TSS_RESULT key_mgr_evict(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey) { TSS_RESULT result = TCS_SUCCESS; if ((result = ctx_remove_key_loaded(hContext, hKey))) return result; if ((result = key_mgr_dec_ref_count(hKey))) return result; key_mgr_ref_count(); return result; } TSS_RESULT key_mgr_load_by_blob(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hUnwrappingKey, UINT32 cWrappedKeyBlob, BYTE *rgbWrappedKeyBlob, TPM_AUTH *pAuth, TCS_KEY_HANDLE *phKeyTCSI, TCS_KEY_HANDLE *phKeyHMAC) { TSS_RESULT result; /* Check that auth for the parent key is loaded outside the mem_cache_lock. We have to do * this here because if the TPM can't process this request right now, the thread could be * put to sleep while holding the mem_cache_lock, which would result in a deadlock */ if (pAuth) { if ((result = auth_mgr_check(hContext, &pAuth->AuthHandle))) return result; } MUTEX_LOCK(mem_cache_lock); if (TPM_VERSION_IS(1,2)) { result = TCSP_LoadKey2ByBlob_Internal(hContext, hUnwrappingKey, cWrappedKeyBlob, rgbWrappedKeyBlob, pAuth, phKeyTCSI); } else { result = TCSP_LoadKeyByBlob_Internal(hContext, hUnwrappingKey, cWrappedKeyBlob, rgbWrappedKeyBlob, pAuth, phKeyTCSI, phKeyHMAC); } MUTEX_UNLOCK(mem_cache_lock); return result; } /* create a reference to one key. This is called from the key_mgr_load_* * functions only, so no locking is done. */ TSS_RESULT key_mgr_inc_ref_count(TCS_KEY_HANDLE key_handle) { struct key_mem_cache *cur; for (cur = key_mem_cache_head; cur; cur = cur->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", cur->tcs_handle); if (cur->tcs_handle == key_handle) { cur->ref_cnt++; return TSS_SUCCESS; } } return TCSERR(TSS_E_FAIL); } /* de-reference one key. This is called by the context routines, so * locking is necessary. */ TSS_RESULT key_mgr_dec_ref_count(TCS_KEY_HANDLE key_handle) { struct key_mem_cache *cur; MUTEX_LOCK(mem_cache_lock); for (cur = key_mem_cache_head; cur; cur = cur->next) { if (cur->tcs_handle == key_handle) { cur->ref_cnt--; LogDebugFn("decrementing ref cnt for key 0x%x", key_handle); MUTEX_UNLOCK(mem_cache_lock); return TSS_SUCCESS; } } MUTEX_UNLOCK(mem_cache_lock); return TCSERR(TSS_E_FAIL); } /* run through the global list and free any keys with reference counts of 0 */ void key_mgr_ref_count() { struct key_mem_cache *tmp, *cur; MUTEX_LOCK(mem_cache_lock); for (cur = key_mem_cache_head; cur;) { if (cur->ref_cnt == 0) { if (cur->tpm_handle != NULL_TPM_HANDLE) { LogDebugFn("Key 0x%x being freed from TPM", cur->tpm_handle); internal_EvictByKeySlot(cur->tpm_handle); } LogDebugFn("Key 0x%x being freed", cur->tcs_handle); if (cur->blob) { destroy_key_refs(cur->blob); free(cur->blob); } if (cur->prev != NULL) cur->prev->next = cur->next; if (cur->next != NULL) cur->next->prev = cur->prev; tmp = cur; if (cur == key_mem_cache_head) key_mem_cache_head = cur->next; cur = cur->next; free(tmp); } else { cur = cur->next; } } MUTEX_UNLOCK(mem_cache_lock); } /* only called from load key paths, so no locking */ TCPA_KEY_HANDLE mc_get_slot_by_handle(TCS_KEY_HANDLE tcs_handle) { struct key_mem_cache *tmp; TCS_KEY_HANDLE ret; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tcs_handle == tcs_handle) { ret = tmp->tpm_handle; return ret; } } LogDebugFn("returning NULL_TPM_HANDLE"); return NULL_TPM_HANDLE; } /* called from functions outside the load key path */ TCPA_KEY_HANDLE mc_get_slot_by_handle_lock(TCS_KEY_HANDLE tcs_handle) { struct key_mem_cache *tmp; TCS_KEY_HANDLE ret; MUTEX_LOCK(mem_cache_lock); for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tcs_handle == tcs_handle) { ret = tmp->tpm_handle; MUTEX_UNLOCK(mem_cache_lock); return ret; } } MUTEX_UNLOCK(mem_cache_lock); LogDebugFn("returning NULL_TPM_HANDLE"); return NULL_TPM_HANDLE; } /* only called from load key paths, so no locking */ TCPA_KEY_HANDLE mc_get_slot_by_pub(TCPA_STORE_PUBKEY *pub) { struct key_mem_cache *tmp; TCPA_KEY_HANDLE ret; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->blob && !memcmp(tmp->blob->pubKey.key, pub->key, pub->keyLength)) { ret = tmp->tpm_handle; return ret; } } LogDebugFn("returning NULL_TPM_HANDLE"); return NULL_TPM_HANDLE; } /* Check the mem cache for a key with public key pub. If a parent TCS key handle * is passed in, make sure the parent of the key find matches it, else return * key not found */ /* only called from load key paths, so no locking */ TCS_KEY_HANDLE mc_get_handle_by_pub(TCPA_STORE_PUBKEY *pub, TCS_KEY_HANDLE parent) { struct key_mem_cache *tmp; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->blob && pub->keyLength == tmp->blob->pubKey.keyLength && !memcmp(tmp->blob->pubKey.key, pub->key, pub->keyLength)) { if (parent) { if (!tmp->parent) continue; if (parent == tmp->parent->tcs_handle) return tmp->tcs_handle; } else return tmp->tcs_handle; } } LogDebugFn("returning NULL_TCS_HANDLE"); return NULL_TCS_HANDLE; } /* only called from load key paths, so no locking */ TCPA_STORE_PUBKEY * mc_get_parent_pub_by_pub(TCPA_STORE_PUBKEY *pub) { struct key_mem_cache *tmp; TCPA_STORE_PUBKEY *ret = NULL; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tcs_handle == TPM_KEYHND_SRK) { LogDebugFn("skipping the SRK"); continue; } if (tmp->blob && !memcmp(tmp->blob->pubKey.key, pub->key, pub->keyLength)) { if (tmp->parent && tmp->parent->blob) { ret = &tmp->parent->blob->pubKey; LogDebugFn("Success"); } else { LogError("parent pointer not set in key mem cache object w/ TCS " "handle: 0x%x", tmp->tcs_handle); } return ret; } } LogDebugFn("returning NULL TCPA_STORE_PUBKEY"); return NULL; } /* only called from load key paths, so no locking */ TSS_RESULT mc_get_blob_by_pub(TCPA_STORE_PUBKEY *pub, TSS_KEY **ret_key) { struct key_mem_cache *tmp; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->blob && !memcmp(tmp->blob->pubKey.key, pub->key, pub->keyLength)) { *ret_key = tmp->blob; return TSS_SUCCESS; } } LogDebugFn("returning TSS_E_FAIL"); return TCSERR(TSS_E_FAIL); } /* only called from load key paths, so no locking */ TCS_KEY_HANDLE mc_get_handle_by_slot(TCPA_KEY_HANDLE tpm_handle) { struct key_mem_cache *tmp; TCS_KEY_HANDLE ret; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tpm_handle == tpm_handle) { ret = tmp->tcs_handle; return ret; } } return NULL_TCS_HANDLE; } /* only called from load key paths, so no locking */ TSS_RESULT mc_update_time_stamp(TCPA_KEY_HANDLE tpm_handle) { struct key_mem_cache *tmp; for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tpm_handle == tpm_handle) { tmp->time_stamp = getNextTimeStamp(); return TSS_SUCCESS; } } return TCSERR(TSS_E_FAIL); } /* Right now this evicts the LRU key assuming it's not the parent */ TSS_RESULT evictFirstKey(TCS_KEY_HANDLE parent_tcs_handle) { struct key_mem_cache *tmp; TCS_KEY_HANDLE tpm_handle_to_evict = NULL_TPM_HANDLE; UINT32 smallestTimeStamp = ~(0U); /* largest */ TSS_RESULT result; UINT32 count; /* First, see if there are any known keys worth evicting */ if ((result = clearUnknownKeys(InternalContext, &count))) return result; if (count > 0) { LogDebugFn("Evicted %u unknown keys", count); return TSS_SUCCESS; } for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { if (tmp->tpm_handle != NULL_TPM_HANDLE && /* not already evicted */ tmp->tpm_handle != SRK_TPM_HANDLE && /* not the srk */ tmp->tcs_handle != parent_tcs_handle && /* not my parent */ tmp->time_stamp < smallestTimeStamp) { /* is the smallest time stamp so far */ tpm_handle_to_evict = tmp->tpm_handle; smallestTimeStamp = tmp->time_stamp; } } if (tpm_handle_to_evict != NULL_TCS_HANDLE) { if ((result = internal_EvictByKeySlot(tpm_handle_to_evict))) return result; LogDebugFn("Evicted key w/ TPM handle 0x%x", tpm_handle_to_evict); result = mc_set_slot_by_slot(tpm_handle_to_evict, NULL_TPM_HANDLE); } else return TSS_SUCCESS; return result; } TSS_BOOL isKeyLoaded(TCPA_KEY_HANDLE keySlot) { UINT64 offset; UINT32 i; TCPA_KEY_HANDLE_LIST keyList; UINT32 respSize; BYTE *resp; TSS_RESULT result; if (keySlot == SRK_TPM_HANDLE) { return TRUE; } if ((result = TCSP_GetCapability_Internal(InternalContext, TCPA_CAP_KEY_HANDLE, 0, NULL, &respSize, &resp))) goto not_loaded; offset = 0; UnloadBlob_KEY_HANDLE_LIST(&offset, resp, &keyList); free(resp); for (i = 0; i < keyList.loaded; i++) { LogDebugFn("loaded TPM key handle: 0x%x", keyList.handle[i]); if (keyList.handle[i] == keySlot) { free(keyList.handle); return TRUE; } } free(keyList.handle); not_loaded: LogDebugFn("Key is not loaded, changing slot"); mc_set_slot_by_slot(keySlot, NULL_TPM_HANDLE); return FALSE; } /* all calls to LoadKeyShim are inside locks */ TSS_RESULT LoadKeyShim(TCS_CONTEXT_HANDLE hContext, TCPA_STORE_PUBKEY *pubKey, TSS_UUID *parentUuid, TCPA_KEY_HANDLE *slotOut) { TCPA_STORE_PUBKEY *parentPub; UINT32 result; TCPA_KEY_HANDLE keySlot; TCPA_KEY_HANDLE parentSlot; TCS_KEY_HANDLE tcsKeyHandle; TSS_KEY *myKey; UINT64 offset; TCS_KEY_HANDLE parentHandle; BYTE keyBlob[1024]; LogDebugFn("calling mc_get_slot_by_pub"); /* If I'm loaded, then no point being here. Get the slot and return */ keySlot = mc_get_slot_by_pub(pubKey); if (keySlot != NULL_TPM_HANDLE && isKeyLoaded(keySlot)) { *slotOut = keySlot; return TSS_SUCCESS; } /* * Before proceeding, the parent must be loaded. * If the parent is registered, then it can be loaded by UUID. * If not, then the shim will be called to load it's parent and then try * to load it based on the persistent store. */ LogDebugFn("calling mc_get_parent_pub_by_pub"); /* Check if the Key is in the memory cache */ if ((parentPub = mc_get_parent_pub_by_pub(pubKey)) == NULL) { #if 0 LogDebugFn("parentPub is NULL"); /* If parentUUID is not handed in, then this key was never loaded and isn't reg'd */ if (parentUuid == NULL) return TCSERR(TCS_E_KM_LOADFAILED); LogDebugFn("calling TCSP_LoadKeyByUUID_Internal"); /* This will try to load my parent by UUID */ if ((result = TCSP_LoadKeyByUUID_Internal(hContext, parentUuid, NULL, &parentSlot))) return result; #else return TCSERR(TCS_E_KM_LOADFAILED); #endif } else { LogDebugFn("calling LoadKeyShim"); if ((result = LoadKeyShim(hContext, parentPub, NULL, &parentSlot))) return result; } /* * Now that the parent is loaded, I can load myself. * If I'm registered, that's by UUID. If I'm not, * that's by blob. If there is no persistent storage data, then I cannot be * loaded by blob. The user must have some point loaded this key manually. */ /* check the mem cache */ if (mc_get_blob_by_pub(pubKey, &myKey) == TSS_SUCCESS) { parentHandle = mc_get_handle_by_slot(parentSlot); if (parentHandle == 0) return TCSERR(TCS_E_KM_LOADFAILED); offset = 0; LoadBlob_TSS_KEY(&offset, keyBlob, myKey); if (TPM_VERSION_IS(1,2)) result = TCSP_LoadKey2ByBlob_Internal(hContext, parentHandle, offset, keyBlob, NULL, &tcsKeyHandle); else result = TCSP_LoadKeyByBlob_Internal(hContext, parentHandle, offset, keyBlob, NULL, &tcsKeyHandle, slotOut); if (result) return result; return ctx_mark_key_loaded(hContext, tcsKeyHandle); #if TSS_BUILD_PS } else { TSS_UUID *uuid; /* check registered */ if (ps_is_pub_registered(pubKey) == FALSE) return TCSERR(TCS_E_KM_LOADFAILED); //uuid = mc_get_uuid_by_pub(pubKey); // XXX pub is not in MC if ((result = ps_get_uuid_by_pub(pubKey, &uuid))) return result; if ((result = TCSP_LoadKeyByUUID_Internal(hContext, uuid, NULL, &tcsKeyHandle))) { free(uuid); return result; } free(uuid); *slotOut = mc_get_slot_by_handle(tcsKeyHandle); return ctx_mark_key_loaded(hContext, tcsKeyHandle); #endif } return TCSERR(TCS_E_KM_LOADFAILED); } TSS_RESULT owner_evict_init() { TSS_RESULT result = TSS_SUCCESS; TCPA_KEY_HANDLE_LIST keyList = { 0, NULL }; BYTE *respData = NULL, ownerEvictCtr = 0; UINT32 respDataSize = 0, i; UINT64 offset = 0; /* If we're a 1.1 TPM, we can exit immediately since only 1.2+ supports owner evict */ if (TPM_VERSION_IS(1,1)) return TSS_SUCCESS; if ((result = TCSP_GetCapability_Internal(InternalContext, TPM_CAP_KEY_HANDLE, 0, NULL, &respDataSize, &respData))) return result; if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList))) { free(respData); return result; } free(respData); for (i = 0; i < keyList.loaded; i++) { UINT64 offset = 0; UINT32 keyHandle; LoadBlob_UINT32(&offset, keyList.handle[i], (BYTE *)&keyHandle); /* get the ownerEvict flag for this key handle */ result = TCSP_GetCapability_Internal(InternalContext, TPM_CAP_KEY_STATUS, sizeof(UINT32), (BYTE *)&keyHandle, &respDataSize, &respData); /* special case, invalid keys are automatically evicted later */ if (result == TPM_E_INVALID_KEYHANDLE) { result = TSS_SUCCESS; continue; } if (result != TSS_SUCCESS) { free(keyList.handle); return result; } if (*(TPM_BOOL *)respData == TRUE) { TSS_UUID uuid = TSS_UUID_OWNEREVICT(ownerEvictCtr); LogDebugFn("Found an owner evict key, assigned uuid %hhu", ownerEvictCtr); if ((result = mc_add_entry_init(getNextTcsKeyHandle(), keyList.handle[i], NULL, &uuid))) { free(keyList.handle); return result; } ownerEvictCtr++; } } return result; } /* find next lowest OWNEREVICT uuid */ TSS_RESULT mc_find_next_ownerevict_uuid(TSS_UUID *uuid) { TCS_KEY_HANDLE tmpKey; TCPA_KEY_HANDLE tmpSlot; UINT16 seed = 0; TSS_RESULT result = TCSERR(TSS_E_FAIL); MUTEX_LOCK(mem_cache_lock); for (seed = 0; seed <= 255; seed++) { TSS_UUID tmpUuid = TSS_UUID_OWNEREVICT(seed); /* if UUID is found, continue on, trying the next UUID */ if (!mc_get_handles_by_uuid(&tmpUuid, &tmpKey, &tmpSlot)) continue; /* UUID is not found, so its the first one available */ memcpy(uuid, &tmpUuid, sizeof(TSS_UUID)); result = TSS_SUCCESS; break; } MUTEX_UNLOCK(mem_cache_lock); return result; } TSS_RESULT mc_set_uuid(TCS_KEY_HANDLE tcs_handle, TSS_UUID *uuid) { struct key_mem_cache *tmp; TSS_RESULT result = TCSERR(TSS_E_FAIL); MUTEX_LOCK(mem_cache_lock); LogDebugFn("looking for 0x%x", tcs_handle); for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { LogDebugFn("TCSD mem_cached handle: 0x%x", tmp->tcs_handle); if (tmp->tcs_handle == tcs_handle) { LogDebugFn("Handle found, re-setting UUID"); memcpy(&tmp->uuid, uuid, sizeof(TSS_UUID)); result = TSS_SUCCESS; break; } } MUTEX_UNLOCK(mem_cache_lock); return result; } trousers-0.3.15/src/tcs/tcsi_maint.c0000664000175000017510000001171213663651711016634 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_CreateMaintenanceArchive_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL generateRandom, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * archiveSize, /* out */ BYTE ** archive) /* out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Create Main Archive"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_CreateMaintenanceArchive, &offset, txBlob, generateRandom, ownerAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_CreateMaintenanceArchive, txBlob, paramSize, randomSize, random, archiveSize, archive, ownerAuth); } LogResult("Create Main Archive", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_LoadMaintenanceArchive_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut) /* out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Load Maint Archive"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_LoadMaintenanceArchive, &offset, txBlob, dataInSize, dataInSize, dataIn, ownerAuth, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_LoadMaintenanceArchive, txBlob, paramSize, dataOutSize, dataOut, ownerAuth, NULL); } LogResult("Load Maint Archive", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_KillMaintenanceFeature_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; if ((result = tpm_rqu_build(TPM_ORD_KillMaintenanceFeature, &offset, txBlob, ownerAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_KillMaintenanceFeature, txBlob, paramSize, ownerAuth); } done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } TSS_RESULT TCSP_LoadManuMaintPub_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 PubKeySize, /* in */ BYTE * PubKey, /* in */ TCPA_DIGEST * checksum) /* out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Load Manu Maint Pub"); if ((result = tpm_rqu_build(TPM_ORD_LoadManuMaintPub, &offset, txBlob, TPM_NONCE_SIZE, antiReplay.nonce, PubKeySize, PubKey, NULL))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_LoadManuMaintPub, txBlob, paramSize, NULL, checksum->digest); } LogResult("Load Manu Maint Pub", result); return result; } TSS_RESULT TCSP_ReadManuMaintPub_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ TCPA_DIGEST * checksum) /* out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Read Manu Maint Pub"); if ((result = tpm_rqu_build(TPM_ORD_ReadManuMaintPub, &offset, txBlob, TPM_NONCE_SIZE, antiReplay.nonce))) return result; if ((result = req_mgr_submit_req(txBlob))) return result; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_ReadManuMaintPub, txBlob, paramSize, NULL, checksum->digest); } LogResult("Read Manu Maint Pub", result); return result; } trousers-0.3.15/src/tcs/tcsi_migration.c0000664000175000017510000001303613663651711017516 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_CreateMigrationBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TSS_MIGRATE_SCHEME migrationType, /* in */ UINT32 MigrationKeyAuthSize, /* in */ BYTE * MigrationKeyAuth, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE keyHandle; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering TPM_CreateMigrationBlob"); if ((result = ctx_verify_context(hContext))) goto done; if (parentAuth != NULL) { if ((result = auth_mgr_check(hContext, &parentAuth->AuthHandle))) goto done; } if ((result = auth_mgr_check(hContext, &entityAuth->AuthHandle))) goto done; if ((result = ensureKeyIsLoaded(hContext, parentHandle, &keyHandle))) goto done; switch (migrationType) { case TSS_MS_MIGRATE: migrationType = TCPA_MS_MIGRATE; break; case TSS_MS_REWRAP: migrationType = TCPA_MS_REWRAP; break; case TSS_MS_MAINT: migrationType = TCPA_MS_MAINT; break; default: /* Let the TPM return an error */ break; } if ((result = tpm_rqu_build(TPM_ORD_CreateMigrationBlob, &offset, txBlob, keyHandle, migrationType, MigrationKeyAuthSize, MigrationKeyAuth, encDataSize, encData, parentAuth, entityAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (result == TSS_SUCCESS) { result = tpm_rsp_parse(TPM_ORD_CreateMigrationBlob, txBlob, paramSize, randomSize, random, outDataSize, outData, parentAuth, entityAuth); } LogResult("TPM_CreateMigrationBlob", result); done: auth_mgr_release_auth(entityAuth, parentAuth, hContext); return result; } TSS_RESULT TCSP_ConvertMigrationBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ UINT32 randomSize, /* in */ BYTE * random, /* in */ TPM_AUTH * parentAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("ConvertMigBlob"); if ((result = ctx_verify_context(hContext))) goto done; if (parentAuth != NULL) { LogDebug("Auth Used"); if ((result = auth_mgr_check(hContext, &parentAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = ensureKeyIsLoaded(hContext, parentHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_ConvertMigrationBlob, &offset, txBlob, keySlot, inDataSize, inData, randomSize, random, parentAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; offset = 10; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_ConvertMigrationBlob, txBlob, paramSize, outDataSize, outData, parentAuth, NULL); } LogResult("***Leaving ConvertMigrationBlob with result ", result); done: auth_mgr_release_auth(parentAuth, NULL, hContext); return result; } TSS_RESULT TCSP_AuthorizeMigrationKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_MIGRATE_SCHEME migrateScheme, /* in */ UINT32 MigrationKeySize, /* in */ BYTE * MigrationKey, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * MigrationKeyAuthSize, /* out */ BYTE ** MigrationKeyAuth) /* out */ { TSS_RESULT result; UINT32 paramSize; UINT64 offset = 0; //TCPA_MIGRATIONKEYAUTH container; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("TCSP_AuthorizeMigrationKey"); if ((result = ctx_verify_context(hContext))) goto done; if ((result = auth_mgr_check(hContext, &ownerAuth->AuthHandle))) goto done; switch (migrateScheme) { case TSS_MS_MIGRATE: migrateScheme = TCPA_MS_MIGRATE; break; case TSS_MS_REWRAP: migrateScheme = TCPA_MS_REWRAP; break; case TSS_MS_MAINT: migrateScheme = TCPA_MS_MAINT; break; #ifdef TSS_BUILD_CMK case TSS_MS_RESTRICT_MIGRATE: migrateScheme = TPM_MS_RESTRICT_MIGRATE; break; case TSS_MS_RESTRICT_APPROVE_DOUBLE: migrateScheme = TPM_MS_RESTRICT_APPROVE_DOUBLE; break; #endif default: /* Let the TPM return an error */ break; } if ((result = tpm_rqu_build(TPM_ORD_AuthorizeMigrationKey, &offset, txBlob, migrateScheme, MigrationKeySize, MigrationKey, ownerAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_AuthorizeMigrationKey, txBlob, paramSize, MigrationKeyAuthSize, MigrationKeyAuth, ownerAuth); } LogDebugFn("TPM_AuthorizeMigrationKey result: 0x%x", result); done: auth_mgr_release_auth(ownerAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_sign.c0000664000175000017510000000326413663651711016467 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_Sign_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 areaToSignSize, /* in */ BYTE * areaToSign, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig /* out */ ) { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; TCPA_KEY_HANDLE keySlot; BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering Sign"); if ((result = ctx_verify_context(hContext))) return result; if (privAuth != NULL) { LogDebug("Auth Used"); if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_Sign, &offset, txBlob, keySlot, areaToSignSize, areaToSign, privAuth))) return result; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Sign, txBlob, paramSize, sigSize, sig, privAuth, NULL); } LogResult("sign", result); done: auth_mgr_release_auth(privAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcsi_quote2.c0000664000175000017510000000405013663651711016740 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcsps.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT TCSP_Quote2_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TSS_BOOL addVersion, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * versionInfoSize, /* out */ BYTE ** versionInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { UINT64 offset = 0; UINT32 paramSize; TSS_RESULT result; UINT32 keySlot; /* Command packet to be sent to the TPM */ BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; LogDebug("Entering quote2"); if ((result = ctx_verify_context(hContext))) goto done; if (privAuth != NULL) { LogDebug("Auth Used"); if ((result = auth_mgr_check(hContext, &privAuth->AuthHandle))) goto done; } else { LogDebug("No Auth"); } if ((result = ensureKeyIsLoaded(hContext, keyHandle, &keySlot))) goto done; if ((result = tpm_rqu_build(TPM_ORD_Quote2, &offset, txBlob, keySlot, antiReplay.nonce, pcrDataSizeIn, pcrDataIn, &addVersion, privAuth))) goto done; if ((result = req_mgr_submit_req(txBlob))) goto done; result = UnloadBlob_Header(txBlob, ¶mSize); if (!result) { result = tpm_rsp_parse(TPM_ORD_Quote2, txBlob, paramSize, pcrDataSizeOut, pcrDataOut, &addVersion, versionInfoSize, versionInfo, sigSize, sig, privAuth); } LogResult("Quote2", result); done: auth_mgr_release_auth(privAuth, NULL, hContext); return result; } trousers-0.3.15/src/tcs/tcs_req_mgr.c0000664000175000017510000000271713663651711017014 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include "trousers/tss.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tddl.h" #include "req_mgr.h" #include "tcslog.h" static struct tpm_req_mgr *trm; #ifdef TSS_DEBUG #define TSS_TPM_DEBUG #endif TSS_RESULT req_mgr_submit_req(BYTE *blob) { TSS_RESULT result; BYTE loc_buf[TSS_TPM_TXBLOB_SIZE]; UINT32 size = TSS_TPM_TXBLOB_SIZE; UINT32 retry = TSS_REQ_MGR_MAX_RETRIES; MUTEX_LOCK(trm->queue_lock); #ifdef TSS_TPM_DEBUG LogBlobData("To TPM:", Decode_UINT32(&blob[2]), blob); #endif do { result = Tddli_TransmitData(blob, Decode_UINT32(&blob[2]), loc_buf, &size); } while (!result && (Decode_UINT32(&loc_buf[6]) == TCPA_E_RETRY) && --retry); if (!result) memcpy(blob, loc_buf, Decode_UINT32(&loc_buf[2])); #ifdef TSS_TPM_DEBUG LogBlobData("From TPM:", size, loc_buf); #endif MUTEX_UNLOCK(trm->queue_lock); return result; } TSS_RESULT req_mgr_init() { if ((trm = calloc(1, sizeof(struct tpm_req_mgr))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tpm_req_mgr)); return TSS_E_OUTOFMEMORY; } MUTEX_INIT(trm->queue_lock); return Tddli_Open(); } TSS_RESULT req_mgr_final() { free(trm); return Tddli_Close(); } trousers-0.3.15/src/tcs/tcs_quote2.c0000664000175000017510000000334313663651711016573 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #include "tddl.h" #include "req_mgr.h" #include "tcsd_wrap.h" #include "tcsd.h" TSS_RESULT UnloadBlob_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_SHORT *pcrInfoOut) { TSS_RESULT result; BYTE locAtRelease; TPM_DIGEST digest; LogDebugFn("UnloadBlob_PCR_INFO_SHORT."); /* Only adjust the offset until the end of this data type */ if (!pcrInfoOut) { if ((result = UnloadBlob_PCR_SELECTION(offset, blob, NULL))) return result; /* What should go to &pcrInfoOut->localityAtRelease */ UnloadBlob_BYTE(offset, NULL, blob); /* What should go to &pcrInfoOut->digestAtRelease */ UnloadBlob_DIGEST(offset, blob, NULL); return TSS_SUCCESS; } /* Normal retrieve or TPM_PCR_INFO_SHORT (not used yet, kept for * integrity purposes. * TPM_PCR_SELECTION pcrSelection * TPM_LOCALITY_SELECTION localityAtRelease * TPM_COMPOSITE_HASH digestAtRelease * */ if ((result = UnloadBlob_PCR_SELECTION(offset, blob, &pcrInfoOut->pcrSelection))) return result; UnloadBlob_BYTE(offset, &locAtRelease, blob); pcrInfoOut->localityAtRelease = locAtRelease; UnloadBlob_DIGEST(offset, blob, &digest); pcrInfoOut->digestAtRelease = digest; return TSS_SUCCESS; } trousers-0.3.15/src/tspi/0000775000175000017510000000000013746500521014514 5ustar deboradeboratrousers-0.3.15/src/tspi/tsp_seal.c0000664000175000017510000001532213663651711016503 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "obj.h" #include "tsplog.h" #include "authsess.h" #ifdef TSS_BUILD_SEALX TSS_RESULT sealx_mask_cb(PVOID lpAppData, TSS_HKEY hEncKey, TSS_HENCDATA hEncData, TSS_ALGORITHM_ID algId, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulDataLength, BYTE *rgbDataToMask, BYTE *rgbMaskedData) { UINT32 mgf1SeedLen, sharedSecretLen = sizeof(TPM_DIGEST); BYTE *mgf1Seed, *mgf1Buffer; UINT32 i; TSS_RESULT result; struct authsess *sess = (struct authsess *)lpAppData; mgf1SeedLen = (ulSizeNonces * 2) + strlen("XOR") + sharedSecretLen; if ((mgf1Seed = (BYTE *)calloc(1, mgf1SeedLen)) == NULL) { LogError("malloc of %u bytes failed.", mgf1SeedLen); return TSPERR(TSS_E_OUTOFMEMORY); } mgf1Buffer = mgf1Seed; memcpy(mgf1Buffer, rgbNonceEven, ulSizeNonces); mgf1Buffer += ulSizeNonces; memcpy(mgf1Buffer, rgbNonceOdd, ulSizeNonces); mgf1Buffer += ulSizeNonces; memcpy(mgf1Buffer, "XOR", strlen("XOR")); mgf1Buffer += strlen("XOR"); memcpy(mgf1Buffer, sess->sharedSecret.digest, sharedSecretLen); if ((result = Trspi_MGF1(TSS_HASH_SHA1, mgf1SeedLen, mgf1Seed, ulDataLength, rgbMaskedData))) goto done; for (i = 0; i < ulDataLength; i++) rgbMaskedData[i] ^= rgbDataToMask[i]; done: free(mgf1Seed); return result; } #endif #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_Seal(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH *encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen, dataLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; dataLen = (2 * sizeof(UINT32)) + sizeof(TPM_ENCAUTH) + pcrInfoSize + inDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_DIGEST(&offset, data, (TPM_DIGEST *)encAuth); Trspi_LoadBlob_UINT32(&offset, pcrInfoSize, data); Trspi_LoadBlob(&offset, pcrInfoSize, data, PcrInfo); Trspi_LoadBlob_UINT32(&offset, inDataSize, data); Trspi_LoadBlob(&offset, inDataSize, data, inData); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Seal, dataLen, data, &pubKeyHash, &handlesLen, &handles, pubAuth, NULL, &decLen, &dec))) return result; *SealedDataSize = decLen; *SealedData = dec; return result; } TSS_RESULT Transport_Sealx(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH *encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen, dataLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; dataLen = (2 * sizeof(UINT32)) + sizeof(TPM_ENCAUTH) + pcrInfoSize + inDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob(&offset, sizeof(TPM_ENCAUTH), data, encAuth->authdata); Trspi_LoadBlob_UINT32(&offset, pcrInfoSize, data); Trspi_LoadBlob(&offset, pcrInfoSize, data, PcrInfo); Trspi_LoadBlob_UINT32(&offset, inDataSize, data); Trspi_LoadBlob(&offset, inDataSize, data, inData); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Sealx, dataLen, data, &pubKeyHash, &handlesLen, &handles, pubAuth, NULL, &decLen, &dec))) return result; *SealedDataSize = decLen; *SealedData = dec; return result; } TSS_RESULT Transport_Unseal(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 SealedDataSize, /* in */ BYTE * SealedData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * dataAuth, /* in, out */ UINT32 * DataSize, /* out */ BYTE ** Data) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen, decLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(parentHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = parentHandle; handles = &handle; if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Unseal, SealedDataSize, SealedData, &pubKeyHash, &handlesLen, &handles, parentAuth, dataAuth, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, DataSize, dec); if ((*Data = malloc(*DataSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *DataSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *DataSize, dec, *Data); free(dec); return result; } #endif trousers-0.3.15/src/tspi/tspi_bind.c0000664000175000017510000001354513663651711016651 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_Data_Bind(TSS_HENCDATA hEncData, /* in */ TSS_HKEY hEncKey, /* in */ UINT32 ulDataLength, /* in */ BYTE *rgbDataToBind) /* in */ { UINT32 encDataLength; BYTE encData[256]; BYTE *keyData; UINT32 keyDataLength; TCPA_BOUND_DATA boundData; UINT64 offset; BYTE bdblob[256]; TCPA_RESULT result; TSS_KEY keyContainer; TSS_HCONTEXT tspContext; if (rgbDataToBind == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_encdata(hEncData)) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = obj_rsakey_get_tsp_context(hEncKey, &tspContext))) return result; /* XXX Just get the pubkey here */ if ((result = obj_rsakey_get_blob(hEncKey, &keyDataLength, &keyData))) return result; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, keyData, &keyContainer))) { free_tspi(tspContext, keyData); return result; } free_tspi(tspContext, keyData); if (keyContainer.keyUsage != TPM_KEY_BIND && keyContainer.keyUsage != TPM_KEY_LEGACY) { result = TSPERR(TSS_E_INVALID_KEYUSAGE); goto done; } if (keyContainer.pubKey.keyLength < ulDataLength) { result = TSPERR(TSS_E_ENC_INVALID_LENGTH); goto done; } if (keyContainer.algorithmParms.encScheme == TCPA_ES_RSAESPKCSv15 && keyContainer.keyUsage == TPM_KEY_LEGACY) { if ((result = Trspi_RSA_PKCS15_Encrypt(rgbDataToBind, ulDataLength, encData, &encDataLength, keyContainer.pubKey.key, keyContainer.pubKey.keyLength))) goto done; } else if (keyContainer.algorithmParms.encScheme == TCPA_ES_RSAESPKCSv15 && keyContainer.keyUsage == TPM_KEY_BIND) { boundData.payload = TCPA_PT_BIND; memcpy(&boundData.ver, &VERSION_1_1, sizeof(TCPA_VERSION)); boundData.payloadData = malloc(ulDataLength); if (boundData.payloadData == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(boundData.payloadData, rgbDataToBind, ulDataLength); offset = 0; Trspi_LoadBlob_BOUND_DATA(&offset, boundData, ulDataLength, bdblob); if ((result = Trspi_RSA_PKCS15_Encrypt(bdblob, offset, encData, &encDataLength, keyContainer.pubKey.key, keyContainer.pubKey.keyLength))) { free(boundData.payloadData); goto done; } free(boundData.payloadData); } else { boundData.payload = TCPA_PT_BIND; memcpy(&boundData.ver, &VERSION_1_1, sizeof(TCPA_VERSION)); boundData.payloadData = malloc(ulDataLength); if (boundData.payloadData == NULL) { LogError("malloc of %u bytes failed.", ulDataLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(boundData.payloadData, rgbDataToBind, ulDataLength); offset = 0; Trspi_LoadBlob_BOUND_DATA(&offset, boundData, ulDataLength, bdblob); if ((result = Trspi_RSA_Encrypt(bdblob, offset, encData, &encDataLength, keyContainer.pubKey.key, keyContainer.pubKey.keyLength))) { free(boundData.payloadData); goto done; } free(boundData.payloadData); } if ((result = obj_encdata_set_data(hEncData, encDataLength, encData))) { LogError("Error in calling SetAttribData on the encrypted data object."); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } done: free_key_refs(&keyContainer); return result; } TSS_RESULT Tspi_Data_Unbind(TSS_HENCDATA hEncData, /* in */ TSS_HKEY hKey, /* in */ UINT32 * pulUnboundDataLength, /* out */ BYTE ** prgbUnboundData) /* out */ { TCPA_RESULT result; TPM_AUTH privAuth; TCPA_DIGEST digest; TSS_HPOLICY hPolicy; BYTE *encData; UINT32 encDataSize; TCS_KEY_HANDLE tcsKeyHandle; TSS_BOOL usesAuth; TPM_AUTH *pPrivAuth; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; if (pulUnboundDataLength == NULL || prgbUnboundData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_encdata_get_tsp_context(hEncData, &tspContext))) return result; if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; if ((result = obj_encdata_get_data(hEncData, &encDataSize, &encData))) return result == (TSS_E_INVALID_OBJ_ACCESS | TSS_LAYER_TSP) ? TSPERR(TSS_E_ENC_NO_DATA) : result; if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKeyHandle))) return result; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_UnBind); result |= Trspi_Hash_UINT32(&hashCtx, encDataSize); result |= Trspi_HashUpdate(&hashCtx, encDataSize, encData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_UnBind, hPolicy, FALSE, &digest, &privAuth))) return result; pPrivAuth = &privAuth; } else { pPrivAuth = NULL; } if ((result = TCS_API(tspContext)->UnBind(tspContext, tcsKeyHandle, encDataSize, encData, pPrivAuth, pulUnboundDataLength, prgbUnboundData))) return result; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_UnBind); result |= Trspi_Hash_UINT32(&hashCtx, *pulUnboundDataLength); result |= Trspi_HashUpdate(&hashCtx, *pulUnboundDataLength, *prgbUnboundData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &privAuth))) goto error; } if ((result = __tspi_add_mem_entry(tspContext, *prgbUnboundData))) goto error; return TSS_SUCCESS; error: free(*prgbUnboundData); *prgbUnboundData = NULL; *pulUnboundDataLength = 0; return result; } trousers-0.3.15/src/tspi/tspi_caps_tpm.c0000664000175000017510000002221713663651711017537 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_GetCapability(TSS_HTPM hTPM, /* in */ TSS_FLAG capArea, /* in */ UINT32 ulSubCapLength, /* in */ BYTE * rgbSubCap, /* in */ UINT32 * pulRespDataLength, /* out */ BYTE ** prgbRespData) /* out */ { TSS_HCONTEXT tspContext; TPM_CAPABILITY_AREA tcsCapArea; UINT32 tcsSubCap = 0; UINT32 tcsSubCapContainer; TSS_RESULT result; UINT32 nonVolFlags, volFlags, respLen; BYTE *respData; UINT64 offset; TSS_BOOL fOwnerAuth = FALSE, endianFlag = TRUE; if (pulRespDataLength == NULL || prgbRespData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; /* Verify the caps and subcaps */ switch (capArea) { case TSS_TPMCAP_ORD: if ((ulSubCapLength != sizeof(UINT32)) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); tcsCapArea = TCPA_CAP_ORD; tcsSubCap = *(UINT32 *)rgbSubCap; break; case TSS_TPMCAP_FLAG: fOwnerAuth = TRUE; break; case TSS_TPMCAP_AUTH_ENCRYPT: case TSS_TPMCAP_ALG: if ((ulSubCapLength != sizeof(UINT32)) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); /* Test capArea again here in order to keep from having to duplicate the switch * statement below */ tcsCapArea = (capArea == TSS_TPMCAP_ALG ? TPM_CAP_ALG : TPM_CAP_AUTH_ENCRYPT); switch (*(UINT32 *)rgbSubCap) { case TSS_ALG_RSA: tcsSubCap = TPM_ALG_RSA; break; case TSS_ALG_AES128: tcsSubCap = TPM_ALG_AES128; break; case TSS_ALG_AES192: tcsSubCap = TPM_ALG_AES192; break; case TSS_ALG_AES256: tcsSubCap = TPM_ALG_AES256; break; case TSS_ALG_3DES: tcsSubCap = TPM_ALG_3DES; break; case TSS_ALG_DES: tcsSubCap = TPM_ALG_DES; break; case TSS_ALG_SHA: tcsSubCap = TPM_ALG_SHA; break; case TSS_ALG_HMAC: tcsSubCap = TPM_ALG_HMAC; break; case TSS_ALG_MGF1: tcsSubCap = TPM_ALG_MGF1; break; case TSS_ALG_XOR: tcsSubCap = TPM_ALG_XOR; break; default: tcsSubCap = *(UINT32 *)rgbSubCap; break; } break; #ifdef TSS_BUILD_NV case TSS_TPMCAP_NV_LIST: tcsCapArea = TPM_CAP_NV_LIST; endianFlag = FALSE; break; case TSS_TPMCAP_NV_INDEX: if ((ulSubCapLength != sizeof(UINT32)) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); tcsCapArea = TPM_CAP_NV_INDEX; tcsSubCap = *(UINT32 *)rgbSubCap; break; #endif case TSS_TPMCAP_PROPERTY: /* Determines a physical property of the TPM. */ if ((ulSubCapLength != sizeof(UINT32)) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); tcsCapArea = TCPA_CAP_PROPERTY; tcsSubCapContainer = *(UINT32 *)rgbSubCap; switch (tcsSubCapContainer) { case TSS_TPMCAP_PROP_PCR: tcsSubCap = TPM_CAP_PROP_PCR; break; case TSS_TPMCAP_PROP_DIR: tcsSubCap = TPM_CAP_PROP_DIR; break; /* case TSS_TPMCAP_PROP_SLOTS: */ case TSS_TPMCAP_PROP_KEYS: tcsSubCap = TPM_CAP_PROP_SLOTS; break; case TSS_TPMCAP_PROP_MANUFACTURER: tcsSubCap = TPM_CAP_PROP_MANUFACTURER; endianFlag = FALSE; break; case TSS_TPMCAP_PROP_COUNTERS: tcsSubCap = TPM_CAP_PROP_COUNTERS; break; case TSS_TPMCAP_PROP_MAXCOUNTERS: tcsSubCap = TPM_CAP_PROP_MAX_COUNTERS; break; /*case TSS_TPMCAP_PROP_MINCOUNTERINCTIME: */ case TSS_TPMCAP_PROP_MIN_COUNTER: tcsSubCap = TPM_CAP_PROP_MIN_COUNTER; break; case TSS_TPMCAP_PROP_ACTIVECOUNTER: tcsSubCap = TPM_CAP_PROP_ACTIVE_COUNTER; break; case TSS_TPMCAP_PROP_TRANSESSIONS: tcsSubCap = TPM_CAP_PROP_TRANSSESS; break; case TSS_TPMCAP_PROP_MAXTRANSESSIONS: tcsSubCap = TPM_CAP_PROP_MAX_TRANSSESS; break; case TSS_TPMCAP_PROP_SESSIONS: tcsSubCap = TPM_CAP_PROP_SESSIONS; break; case TSS_TPMCAP_PROP_MAXSESSIONS: tcsSubCap = TPM_CAP_PROP_MAX_SESSIONS; break; case TSS_TPMCAP_PROP_FAMILYROWS: tcsSubCap = TPM_CAP_PROP_FAMILYROWS; break; case TSS_TPMCAP_PROP_DELEGATEROWS: tcsSubCap = TPM_CAP_PROP_DELEGATE_ROW; break; case TSS_TPMCAP_PROP_OWNER: tcsSubCap = TPM_CAP_PROP_OWNER; break; case TSS_TPMCAP_PROP_MAXKEYS: tcsSubCap = TPM_CAP_PROP_MAX_KEYS; break; case TSS_TPMCAP_PROP_AUTHSESSIONS: tcsSubCap = TPM_CAP_PROP_AUTHSESS; break; case TSS_TPMCAP_PROP_MAXAUTHSESSIONS: tcsSubCap = TPM_CAP_PROP_MAX_AUTHSESS; break; case TSS_TPMCAP_PROP_CONTEXTS: tcsSubCap = TPM_CAP_PROP_CONTEXT; break; case TSS_TPMCAP_PROP_MAXCONTEXTS: tcsSubCap = TPM_CAP_PROP_MAX_CONTEXT; break; case TSS_TPMCAP_PROP_DAASESSIONS: tcsSubCap = TPM_CAP_PROP_SESSION_DAA; break; case TSS_TPMCAP_PROP_MAXDAASESSIONS: tcsSubCap = TPM_CAP_PROP_DAA_MAX; break; case TSS_TPMCAP_PROP_TISTIMEOUTS: tcsSubCap = TPM_CAP_PROP_TIS_TIMEOUT; break; case TSS_TPMCAP_PROP_STARTUPEFFECTS: tcsSubCap = TPM_CAP_PROP_STARTUP_EFFECT; endianFlag = FALSE; break; case TSS_TPMCAP_PROP_MAXCONTEXTCOUNTDIST: tcsSubCap = TPM_CAP_PROP_CONTEXT_DIST; break; case TSS_TPMCAP_PROP_CMKRESTRICTION: tcsSubCap = TPM_CAP_PROP_CMK_RESTRICTION; break; case TSS_TPMCAP_PROP_DURATION: tcsSubCap = TPM_CAP_PROP_DURATION; break; case TSS_TPMCAP_PROP_MAXNVAVAILABLE: tcsSubCap = TPM_CAP_PROP_NV_AVAILABLE; break; case TSS_TPMCAP_PROP_INPUTBUFFERSIZE: tcsSubCap = TPM_CAP_PROP_INPUT_BUFFER; break; #if 0 /* There isn't a way to query the TPM for these, the TPMWG is considering how to * address some of them in the next version of the TPM - KEY Oct 15, 2007*/ case TSS_TPMCAP_PROP_MAXNVWRITE: break; case TSS_TPMCAP_PROP_REVISION: break; case TSS_TPMCAP_PROP_LOCALITIES_AVAIL: break; case TSS_TPMCAP_PROP_PCRMAP: break; #endif default: return TSPERR(TSS_E_BAD_PARAMETER); } break; case TSS_TPMCAP_VERSION: /* Queries the current TPM version. */ tcsCapArea = TCPA_CAP_VERSION; endianFlag = FALSE; break; case TSS_TPMCAP_VERSION_VAL: /* Queries the current TPM version for 1.2 TPM device. */ tcsCapArea = TPM_CAP_VERSION_VAL; endianFlag = FALSE; break; case TSS_TPMCAP_MFR: tcsCapArea = TPM_CAP_MFR; endianFlag = FALSE; break; case TSS_TPMCAP_SYM_MODE: if ((ulSubCapLength != sizeof(UINT32)) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); tcsCapArea = TPM_CAP_SYM_MODE; tcsSubCap = *(UINT32 *)rgbSubCap; break; case TSS_TPMCAP_HANDLE: if ((ulSubCapLength != sizeof(UINT32)) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); tcsCapArea = TPM_CAP_HANDLE; tcsSubCap = *(UINT32 *)rgbSubCap; break; case TSS_TPMCAP_TRANS_ES: if ((ulSubCapLength != sizeof(UINT32)) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); tcsCapArea = TPM_CAP_TRANS_ES; switch (*(UINT32 *)rgbSubCap) { case TSS_ES_NONE: tcsSubCap = TPM_ES_NONE; break; case TSS_ES_RSAESPKCSV15: tcsSubCap = TPM_ES_RSAESPKCSv15; break; case TSS_ES_RSAESOAEP_SHA1_MGF1: tcsSubCap = TPM_ES_RSAESOAEP_SHA1_MGF1; break; case TSS_ES_SYM_CNT: tcsSubCap = TPM_ES_SYM_CNT; break; case TSS_ES_SYM_OFB: tcsSubCap = TPM_ES_SYM_OFB; break; case TSS_ES_SYM_CBC_PKCS5PAD: tcsSubCap = TPM_ES_SYM_CBC_PKCS5PAD; break; default: tcsSubCap = *(UINT32 *)rgbSubCap; break; } break; default: return TSPERR(TSS_E_BAD_PARAMETER); break; } if (fOwnerAuth) { /* do an owner authorized get capability call */ if ((result = get_tpm_flags(tspContext, hTPM, &volFlags, &nonVolFlags))) return result; respLen = 2 * sizeof(UINT32); respData = calloc_tspi(tspContext, respLen); if (respData == NULL) { LogError("malloc of %u bytes failed.", respLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, nonVolFlags, respData); Trspi_LoadBlob_UINT32(&offset, volFlags, respData); *pulRespDataLength = respLen; *prgbRespData = respData; return TSS_SUCCESS; } tcsSubCap = endian32(tcsSubCap); if ((result = TCS_API(tspContext)->GetTPMCapability(tspContext, tcsCapArea, ulSubCapLength, (BYTE *)&tcsSubCap, pulRespDataLength, prgbRespData))) return result; if (endianFlag) { if (*pulRespDataLength == sizeof(UINT32)) *(UINT32 *)(*prgbRespData) = endian32(*(UINT32 *)(*prgbRespData)); else if (*pulRespDataLength == sizeof(UINT16)) *(UINT32 *)(*prgbRespData) = endian16(*(UINT32 *)(*prgbRespData)); } if ((result = __tspi_add_mem_entry(tspContext, *prgbRespData))) { free(*prgbRespData); *prgbRespData = NULL; *pulRespDataLength = 0; return result; } return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_GetCapabilitySigned(TSS_HTPM hTPM, /* in */ TSS_HTPM hKey, /* in */ TSS_FLAG capArea, /* in */ UINT32 ulSubCapLength, /* in */ BYTE * rgbSubCap, /* in */ TSS_VALIDATION * pValidationData, /* in, out */ UINT32 * pulRespDataLength, /* out */ BYTE ** prgbRespData) /* out */ { /* * Function was found to have a vulnerability, so implementation is not * required by the TSS 1.1b spec. */ return TSPERR(TSS_E_NOTIMPL); } trousers-0.3.15/src/tspi/obj_hash.c0000664000175000017510000001140013663651711016437 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT obj_hash_add(TSS_HCONTEXT tspContext, UINT32 type, TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_hash_obj *hash = calloc(1, sizeof(struct tr_hash_obj)); if (hash == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_hash_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } if ((type == TSS_HASH_SHA1) || (type == TSS_HASH_DEFAULT)) { hash->type = TSS_HASH_SHA1; hash->hashSize = 20; } else if (type == TSS_HASH_OTHER) { hash->type = TSS_HASH_OTHER; hash->hashSize = 0; } if ((result = obj_list_add(&hash_list, tspContext, 0, hash, phObject))) { free(hash); return result; } return TSS_SUCCESS; } TSS_BOOL obj_is_hash(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&hash_list, hObject))) { answer = TRUE; obj_list_put(&hash_list); } return answer; } TSS_RESULT obj_hash_get_tsp_context(TSS_HHASH hHash, TSS_HCONTEXT *tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&hash_list, hHash)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&hash_list); return TSS_SUCCESS; } TSS_RESULT obj_hash_set_value(TSS_HHASH hHash, UINT32 size, BYTE *value) { struct tsp_object *obj; struct tr_hash_obj *hash; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&hash_list, hHash)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); hash = (struct tr_hash_obj *)obj->data; if (hash->type != TSS_HASH_OTHER && size != TCPA_SHA1_160_HASH_LEN) { result = TSPERR(TSS_E_HASH_INVALID_LENGTH); goto done; } free(hash->hashData); if ((hash->hashData = calloc(1, size)) == NULL) { LogError("malloc of %d bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } hash->hashSize = size; memcpy(hash->hashData, value, size); done: obj_list_put(&hash_list); return result; } TSS_RESULT obj_hash_get_value(TSS_HHASH hHash, UINT32 *size, BYTE **value) { struct tsp_object *obj; struct tr_hash_obj *hash; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&hash_list, hHash)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); hash = (struct tr_hash_obj *)obj->data; if (hash->hashData == NULL) { result = TSPERR(TSS_E_HASH_NO_DATA); goto done; } if ((*value = calloc_tspi(obj->tspContext, hash->hashSize)) == NULL) { LogError("malloc of %d bytes failed.", hash->hashSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = hash->hashSize; memcpy(*value, hash->hashData, *size); done: obj_list_put(&hash_list); return result; } TSS_RESULT obj_hash_update_value(TSS_HHASH hHash, UINT32 size, BYTE *data) { struct tsp_object *obj; struct tr_hash_obj *hash; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&hash_list, hHash)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); hash = (struct tr_hash_obj *)obj->data; if (hash->type != TSS_HASH_SHA1 && hash->type != TSS_HASH_DEFAULT) { result = TSPERR(TSS_E_FAIL); goto done; } if (hash->hashUpdateBuffer == NULL) { hash->hashUpdateBuffer = calloc(1, size); if (hash->hashUpdateBuffer == NULL) { LogError("malloc of %u bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } else { hash->hashUpdateBuffer = realloc(hash->hashUpdateBuffer, size + hash->hashUpdateSize); if (hash->hashUpdateBuffer == NULL) { LogError("malloc of %u bytes failed.", size + hash->hashUpdateSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } memcpy(&hash->hashUpdateBuffer[hash->hashUpdateSize], data, size); hash->hashUpdateSize += size; if (hash->hashData == NULL) { hash->hashData = calloc(1, TCPA_SHA1_160_HASH_LEN); if (hash->hashData == NULL) { LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } result = Trspi_Hash(TSS_HASH_SHA1, hash->hashUpdateSize, hash->hashUpdateBuffer, hash->hashData); done: obj_list_put(&hash_list); return result; } void __tspi_hash_free(void *data) { struct tr_hash_obj *hash = (struct tr_hash_obj *)data; free(hash->hashData); free(hash->hashUpdateBuffer); free(hash); } /* * remove hash object hObject from the list */ TSS_RESULT obj_hash_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { TSS_RESULT result; if ((result = obj_list_remove(&hash_list, &__tspi_hash_free, hObject, tspContext))) return result; return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_key.c0000664000175000017510000005063713663651711016530 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "authsess.h" #define TPM_STORE_ASYMKEY_LEN 214 /* Entire TPM_STORE_ASYMKEY length */ #define USAGE_MIG_DIGEST_FLD_LEN 20 /* Usage, Migration and Digest lengths for TPM_STORE_ASYMKEY */ #define TPM_STORE_PRIVKEY_LEN 151 /* Extracted directly from TPM_STORE_ASYMKEY field */ TSS_RESULT Tspi_Key_UnloadKey(TSS_HKEY hKey) /* in */ { TSS_HCONTEXT tspContext; TCS_KEY_HANDLE hTcsKey; TSS_RESULT result; if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext))) return result; if ((result = obj_rsakey_get_tcs_handle(hKey, &hTcsKey))) return result; return __tspi_free_resource(tspContext, hTcsKey, TPM_RT_KEY); } TSS_RESULT Tspi_Key_LoadKey(TSS_HKEY hKey, /* in */ TSS_HKEY hUnwrappingKey) /* in */ { TPM_AUTH auth; TCPA_DIGEST digest; TSS_RESULT result; UINT32 keyslot; TSS_HCONTEXT tspContext; TSS_HPOLICY hPolicy; UINT32 keySize; BYTE *keyBlob; TCS_KEY_HANDLE tcsKey, tcsParentHandle; TSS_BOOL usesAuth; TPM_AUTH *pAuth; Trspi_HashCtx hashCtx; TPM_COMMAND_CODE ordinal; if (!obj_is_rsakey(hUnwrappingKey)) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext))) return result; if ((result = obj_context_get_loadkey_ordinal(tspContext, &ordinal))) return result; if ((result = obj_rsakey_get_blob(hKey, &keySize, &keyBlob))) return result; if ((result = obj_rsakey_get_tcs_handle(hUnwrappingKey, &tcsParentHandle))) return result; if ((result = obj_rsakey_get_policy(hUnwrappingKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) { free_tspi(tspContext, keyBlob); return result; } if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); result |= Trspi_HashUpdate(&hashCtx, keySize, keyBlob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free_tspi(tspContext, keyBlob); return result; } if ((result = secret_PerformAuth_OIAP(hUnwrappingKey, ordinal, hPolicy, FALSE, &digest, &auth))) { free_tspi(tspContext, keyBlob); return result; } pAuth = &auth; } else { pAuth = NULL; } if ((result = TCS_API(tspContext)->LoadKeyByBlob(tspContext, tcsParentHandle, keySize, keyBlob, pAuth, &tcsKey, &keyslot))) { free_tspi(tspContext, keyBlob); return result; } free_tspi(tspContext, keyBlob); if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); if (ordinal == TPM_ORD_LoadKey) result |= Trspi_Hash_UINT32(&hashCtx, keyslot); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) return result; } return obj_rsakey_set_tcs_handle(hKey, tcsKey); } TSS_RESULT Tspi_Key_GetPubKey(TSS_HKEY hKey, /* in */ UINT32 * pulPubKeyLength, /* out */ BYTE ** prgbPubKey) /* out */ { TPM_AUTH auth; TPM_AUTH *pAuth; TCPA_DIGEST digest; TCPA_RESULT result; TSS_HCONTEXT tspContext; TSS_HPOLICY hPolicy; TCS_KEY_HANDLE tcsKeyHandle; TSS_BOOL usesAuth; Trspi_HashCtx hashCtx; if (pulPubKeyLength == NULL || prgbPubKey == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext))) return result; if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKeyHandle))) return result; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetPubKey); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_GetPubKey, hPolicy, FALSE, &digest, &auth))) return result; pAuth = &auth; } else { pAuth = NULL; } if ((result = TCS_API(tspContext)->GetPubKey(tspContext, tcsKeyHandle, pAuth, pulPubKeyLength, prgbPubKey))) return result; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetPubKey); result |= Trspi_HashUpdate(&hashCtx, *pulPubKeyLength, *prgbPubKey); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; /* goto error here since prgbPubKey has been set */ if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) goto error; } if ((result = __tspi_add_mem_entry(tspContext, *prgbPubKey))) goto error; if (tcsKeyHandle == TPM_KEYHND_SRK) obj_rsakey_set_pubkey(hKey, TRUE, *prgbPubKey); return TSS_SUCCESS; error: free(*prgbPubKey); *prgbPubKey = NULL; *pulPubKeyLength = 0; return result; } TSS_RESULT Tspi_Key_CreateKey(TSS_HKEY hKey, /* in */ TSS_HKEY hWrappingKey, /* in */ TSS_HPCRS hPcrComposite) /* in, may be NULL */ { #ifdef TSS_BUILD_CMK UINT32 blobSize; BYTE *blob; TSS_BOOL isCmk = FALSE; TPM_HMAC msaApproval; TPM_DIGEST msaDigest; #endif TCPA_DIGEST digest; TCPA_RESULT result; TCS_KEY_HANDLE parentTCSKeyHandle; BYTE *keyBlob = NULL; UINT32 keySize; UINT32 newKeySize; BYTE *newKey = NULL; UINT32 ordinal = TPM_ORD_CreateWrapKey; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; struct authsess *xsap = NULL; if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext))) return result; if (hPcrComposite) { /* its possible that hPcrComposite could be a bad handle here, * or that no indices of it are yet set, which would throw * internal error. Blanket both those codes with bad * parameter to help the user out */ if ((result = obj_rsakey_set_pcr_data(hKey, hPcrComposite))) return TSPERR(TSS_E_BAD_PARAMETER); } if ((result = obj_rsakey_get_tcs_handle(hWrappingKey, &parentTCSKeyHandle))) return result; if ((result = obj_rsakey_get_blob(hKey, &keySize, &keyBlob))) return result; #ifdef TSS_BUILD_CMK isCmk = obj_rsakey_is_cmk(hKey); if (isCmk) { if ((result = obj_rsakey_get_msa_approval(hKey, &blobSize, &blob))) goto done; memcpy(msaApproval.digest, blob, sizeof(msaApproval.digest)); free_tspi(tspContext, blob); if ((result = obj_rsakey_get_msa_digest(hKey, &blobSize, &blob))) goto done; memcpy(msaDigest.digest, blob, sizeof(msaDigest.digest)); free_tspi(tspContext, blob); ordinal = TPM_ORD_CMK_CreateKey; } #endif if ((result = authsess_xsap_init(tspContext, hWrappingKey, hKey, TSS_AUTH_POLICY_REQUIRED, ordinal, TPM_ET_KEYHANDLE, &xsap))) return result; /* Setup the Hash Data for the HMAC */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); #ifdef TSS_BUILD_CMK if (isCmk) { result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_HashUpdate(&hashCtx, keySize, keyBlob); result |= Trspi_Hash_HMAC(&hashCtx, msaApproval.digest); result |= Trspi_Hash_DIGEST(&hashCtx, msaDigest.digest); } else { #endif result |= Trspi_Hash_DIGEST(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_Hash_DIGEST(&hashCtx, xsap->encAuthMig.authdata); result |= Trspi_HashUpdate(&hashCtx, keySize, keyBlob); #ifdef TSS_BUILD_CMK } #endif if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = authsess_xsap_hmac(xsap, &digest))) goto done; /* Now call the function */ #ifdef TSS_BUILD_CMK if (isCmk) { if ((newKey = malloc(keySize)) == NULL) { LogError("malloc of %u bytes failed.", keySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(newKey, keyBlob, keySize); newKeySize = keySize; if ((result = RPC_CMK_CreateKey(tspContext, parentTCSKeyHandle, (TPM_ENCAUTH *)&xsap->encAuthUse, &msaApproval, &msaDigest, &newKeySize, &newKey, xsap->pAuth))) goto done; } else { #endif if ((result = TCS_API(tspContext)->CreateWrapKey(tspContext, parentTCSKeyHandle, (TPM_ENCAUTH *)&xsap->encAuthUse, (TPM_ENCAUTH *)&xsap->encAuthMig, keySize, keyBlob, &newKeySize, &newKey, xsap->pAuth))) goto done; #ifdef TSS_BUILD_CMK } #endif /* Validate the Authorization before using the new key */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); result |= Trspi_HashUpdate(&hashCtx, newKeySize, newKey); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (authsess_xsap_verify(xsap, &digest)) { result = TSPERR(TSS_E_TSP_AUTHFAIL); goto done; } /* Push the new key into the existing object */ result = obj_rsakey_set_tcpakey(hKey, newKeySize, newKey); done: authsess_free(xsap); free_tspi(tspContext, keyBlob); free(newKey); return result; } TSS_RESULT Tspi_Key_WrapKey(TSS_HKEY hKey, /* in */ TSS_HKEY hWrappingKey, /* in */ TSS_HPCRS hPcrComposite) /* in, may be NULL */ { TSS_HPOLICY hUsePolicy, hMigPolicy; TCPA_SECRET usage, migration; TSS_RESULT result; BYTE *keyPrivBlob = NULL, *wrappingPubKey = NULL, *keyBlob = NULL; UINT32 keyPrivBlobLen, wrappingPubKeyLen, keyBlobLen; BYTE newPrivKey[TPM_STORE_ASYMKEY_LEN]; /* This reflects the size of the TPM_STORE_ASYMKEY structure in both TPM 1.1b and 1.2 */ BYTE encPrivKey[256]; UINT32 newPrivKeyLen = TPM_STORE_ASYMKEY_LEN, encPrivKeyLen = 256; UINT64 offset; TSS_KEY keyContainer; TCPA_DIGEST digest; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext))) return result; if (hPcrComposite) { if ((result = obj_rsakey_set_pcr_data(hKey, hPcrComposite))) return result; } /* get the key to be wrapped's private key */ if ((result = obj_rsakey_get_priv_blob(hKey, &keyPrivBlobLen, &keyPrivBlob))) goto done; /* verify if its under the maximum size, according to the * TPM_STORE_ASYMKEY specification */ if (keyPrivBlobLen > TPM_STORE_PRIVKEY_LEN) return TSPERR(TSS_E_ENC_INVALID_LENGTH); /* get the key to be wrapped's blob */ if ((result = obj_rsakey_get_blob(hKey, &keyBlobLen, &keyBlob))) goto done; /* get the wrapping key's public key */ if ((result = obj_rsakey_get_modulus(hWrappingKey, &wrappingPubKeyLen, &wrappingPubKey))) goto done; /* get the key to be wrapped's usage policy */ if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hUsePolicy, NULL))) goto done; if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_MIGRATION, &hMigPolicy, NULL))) goto done; if ((result = obj_policy_get_secret(hUsePolicy, TR_SECRET_CTX_NEW, &usage))) goto done; if ((result = obj_policy_get_secret(hMigPolicy, TR_SECRET_CTX_NEW, &migration))) goto done; __tspi_memset(&keyContainer, 0, sizeof(TSS_KEY)); /* unload the key to be wrapped's blob */ offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, keyBlob, &keyContainer))) return result; /* load the key's attributes into an object and get its hash value */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Hash_TSS_PRIVKEY_DIGEST(&hashCtx, &keyContainer); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; free_key_refs(&keyContainer); /* create the plaintext private key blob. This is the point where the * TPM structure TPM_STORE_ASYMKEY is crafted in the buffer */ offset = 0; Trspi_LoadBlob_BYTE(&offset, TCPA_PT_ASYM, newPrivKey); Trspi_LoadBlob(&offset, USAGE_MIG_DIGEST_FLD_LEN, newPrivKey, usage.authdata); Trspi_LoadBlob(&offset, USAGE_MIG_DIGEST_FLD_LEN, newPrivKey, migration.authdata); Trspi_LoadBlob(&offset, USAGE_MIG_DIGEST_FLD_LEN, newPrivKey, digest.digest); Trspi_LoadBlob_UINT32(&offset, keyPrivBlobLen, newPrivKey); Trspi_LoadBlob(&offset, keyPrivBlobLen, newPrivKey, keyPrivBlob); newPrivKeyLen = offset; /* encrypt the private key blob */ if ((result = Trspi_RSA_Encrypt(newPrivKey, newPrivKeyLen, encPrivKey, &encPrivKeyLen, wrappingPubKey, wrappingPubKeyLen))) goto done; /* set the new encrypted private key in the wrapped key object */ if ((result = obj_rsakey_set_privkey(hKey, FALSE, encPrivKeyLen, encPrivKey))) goto done; done: free_tspi(tspContext, keyPrivBlob); free_tspi(tspContext, keyBlob); free_tspi(tspContext, wrappingPubKey); return result; } TSS_RESULT Tspi_Context_LoadKeyByBlob(TSS_HCONTEXT tspContext, /* in */ TSS_HKEY hUnwrappingKey, /* in */ UINT32 ulBlobLength, /* in */ BYTE * rgbBlobData, /* in */ TSS_HKEY * phKey) /* out */ { TPM_AUTH auth; UINT64 offset; TCPA_DIGEST digest; TSS_RESULT result; UINT32 keyslot; TSS_HPOLICY hPolicy; TCS_KEY_HANDLE tcsParentHandle, myTCSKeyHandle; TSS_KEY keyContainer; TSS_BOOL useAuth; TPM_AUTH *pAuth; TSS_FLAG initFlags; UINT16 realKeyBlobSize; TCPA_KEY_USAGE keyUsage; UINT32 pubLen; Trspi_HashCtx hashCtx; TPM_COMMAND_CODE ordinal; if (phKey == NULL || rgbBlobData == NULL ) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_rsakey(hUnwrappingKey)) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = obj_context_get_loadkey_ordinal(tspContext, &ordinal))) return result; if ((result = obj_rsakey_get_tcs_handle(hUnwrappingKey, &tcsParentHandle))) return result; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, rgbBlobData, &keyContainer))) return result; realKeyBlobSize = offset; pubLen = keyContainer.pubKey.keyLength; keyUsage = keyContainer.keyUsage; /* free these now, since they're not used below */ free_key_refs(&keyContainer); if ((result = obj_rsakey_get_policy(hUnwrappingKey, TSS_POLICY_USAGE, &hPolicy, &useAuth))) return result; if (useAuth) { /* Create the Authorization */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); result |= Trspi_HashUpdate(&hashCtx, ulBlobLength, rgbBlobData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hUnwrappingKey, ordinal, hPolicy, FALSE, &digest, &auth))) return result; pAuth = &auth; } else { pAuth = NULL; } if ((result = TCS_API(tspContext)->LoadKeyByBlob(tspContext, tcsParentHandle, ulBlobLength, rgbBlobData, pAuth, &myTCSKeyHandle, &keyslot))) return result; if (useAuth) { /* --- Validate return auth */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); if (ordinal == TPM_ORD_LoadKey) result |= Trspi_Hash_UINT32(&hashCtx, keyslot); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) return result; } /* --- Create a new Object */ initFlags = 0; if (pubLen == 0x100) initFlags |= TSS_KEY_SIZE_2048; else if (pubLen == 0x80) initFlags |= TSS_KEY_SIZE_1024; else if (pubLen == 0x40) initFlags |= TSS_KEY_SIZE_512; /* clear the key type field */ initFlags &= ~TSS_KEY_TYPE_MASK; if (keyUsage == TPM_KEY_STORAGE) initFlags |= TSS_KEY_TYPE_STORAGE; else initFlags |= TSS_KEY_TYPE_SIGNING; /* loading the blob will fix this back to what it should be. */ if ((result = obj_rsakey_add(tspContext, initFlags, phKey))) { LogDebug("Failed create object"); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((result = obj_rsakey_set_tcpakey(*phKey,realKeyBlobSize, rgbBlobData))) { LogDebug("Key loaded but failed to setup the key object" "correctly"); return TSPERR(TSS_E_INTERNAL_ERROR); } return obj_rsakey_set_tcs_handle(*phKey, myTCSKeyHandle); } TSS_RESULT Tspi_TPM_OwnerGetSRKPubKey(TSS_HTPM hTPM, /* in */ UINT32 * pulPuKeyLength, /* out */ BYTE ** prgbPubKey) /* out */ { TSS_RESULT result; TSS_HPOLICY hPolicy; TSS_HCONTEXT tspContext; TCS_KEY_HANDLE hKey; TPM_AUTH auth; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; if (pulPuKeyLength == NULL || prgbPubKey == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; hKey = TPM_KEYHND_SRK; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadInternalPub); result |= Trspi_Hash_UINT32(&hashCtx, hKey); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_OwnerReadInternalPub, hPolicy, FALSE, &digest, &auth))) return result; if ((result = TCS_API(tspContext)->OwnerReadInternalPub(tspContext, hKey, &auth, pulPuKeyLength, prgbPubKey))) return result; /* Validate return auth */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadInternalPub); result |= Trspi_HashUpdate(&hashCtx, *pulPuKeyLength, *prgbPubKey); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) goto error; /* Call a special SRK-seeking command to transparently add the public data to the object */ if ((result = obj_rsakey_set_srk_pubkey(*prgbPubKey))) { LogError("Error setting SRK public data, SRK key object may not exist"); } if ((result = __tspi_add_mem_entry(tspContext, *prgbPubKey))) goto error; return result; error: free(*prgbPubKey); pulPuKeyLength = 0; return result; } /* TSS 1.2-only interfaces */ #ifdef TSS_BUILD_TSS12 TSS_RESULT Tspi_TPM_KeyControlOwner(TSS_HTPM hTPM, /* in */ TSS_HKEY hTssKey, /* in */ UINT32 attribName, /* in */ TSS_BOOL attribValue, /* in */ TSS_UUID* pUuidData) /* out */ { TSS_RESULT result; TSS_HPOLICY hPolicy; TSS_HCONTEXT tspContext; TCS_KEY_HANDLE hTcsKey; BYTE *pubKey = NULL; UINT32 pubKeyLen; TPM_KEY_CONTROL tpmAttribName; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; TPM_AUTH ownerAuth; LogDebugFn("Enter"); /* Check valid TPM context, get TSP context */ if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; /* Get Tcs KeyHandle */ if ((result = obj_rsakey_get_tcs_handle(hTssKey, &hTcsKey))) return result; /* Validate/convert attribName */ switch (attribName) { case TSS_TSPATTRIB_KEYCONTROL_OWNEREVICT: tpmAttribName = TPM_KEY_CONTROL_OWNER_EVICT; break; default: return TSPERR(TSS_E_BAD_PARAMETER); } /* Begin Auth - get TPM Policy Handler */ if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy))) return result; /* Get associated pubKey */ if ((result = obj_rsakey_get_pub_blob(hTssKey, &pubKeyLen, &pubKey))) return result; /* Create hash digest */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_KeyControlOwner); LogDebugData(pubKeyLen, pubKey); result |= Trspi_HashUpdate(&hashCtx, pubKeyLen, pubKey); result |= Trspi_Hash_UINT32(&hashCtx, tpmAttribName); result |= Trspi_Hash_BOOL(&hashCtx, attribValue); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free_tspi(tspContext, pubKey); return result; } if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_KeyControlOwner, hPolicy, FALSE, &digest, &ownerAuth))) { free_tspi(tspContext, pubKey); return result; } if ((result = RPC_KeyControlOwner(tspContext, hTcsKey, pubKeyLen, pubKey, tpmAttribName, attribValue, &ownerAuth, pUuidData))) { free_tspi(tspContext, pubKey); return result; } /* Validate return auth */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_KeyControlOwner); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth))) return result; /* change hKey internal flag, according to attrib[Name|Value] */ switch (attribName) { case TSS_TSPATTRIB_KEYCONTROL_OWNEREVICT: result = obj_rsakey_set_ownerevict(hTssKey, attribValue); break; default: /* NOT-REACHED */ result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } #endif trousers-0.3.15/src/tspi/Makefile.am0000664000175000017510000001724213663651711016564 0ustar deboradeboralib_LTLIBRARIES=libtspi.la libtspi_la_LIBADD=${top_builddir}/src/trspi/libtrousers.la # On setting -version-info, from the libtool manual: # # -version-info current:revision:age # # 1. Start with version information of 0:0:0 for each libtool library. # 2. Update the version information only immediately before a public release of your software. # More frequent updates are unnecessary, and only guarantee that the current interface # number gets larger faster. # 3. If the library source code has changed at all since the last update, then increment # revision (c:r:a becomes c:r+1:a). # 4. If any interfaces have been added, removed, or changed since the last update, increment # current, and set revision to 0. # 5. If any interfaces have been added since the last public release, then increment age. # 6. If any interfaces have been removed since the last public release, then set age to 0. libtspi_la_LDFLAGS=-version-info 3:0:2 -lpthread @CRYPTOLIB@ libtspi_la_CFLAGS=-I$(top_srcdir)/src/include -DAPPID=\"TSPI\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" libtspi_la_SOURCES=log.c \ spi_utils.c \ obj.c \ obj_policy.c \ tsp_policy.c \ obj_tpm.c \ obj_context.c \ tsp_context_mem.c \ tspi_context.c \ rpc/@RPC@/rpc_context.c \ rpc/tcs_api.c \ rpc/hosttable.c \ rpc/@RPC@/rpc.c \ tsp_tcsi_param.c if TSS_BUILD_ASYM_CRYPTO libtspi_la_SOURCES+=tsp_asym.c endif if TSS_BUILD_TSS12 # This is for individual APIs that exist outside TSS 1.2, but may have some TSS 1.2 internal # features/options such as Tspi_TPM_SetStatus libtspi_la_SOURCES+=tspi_oper.c tsp_oper.c rpc/@RPC@/rpc_oper.c libtspi_la_CFLAGS+=-DTSS_BUILD_TSS12 endif if TSS_BUILD_TRANSPORT libtspi_la_SOURCES+=tspi_transport.c rpc/@RPC@/rpc_transport.c libtspi_la_CFLAGS+=-DTSS_BUILD_TRANSPORT endif if TSS_BUILD_TICK libtspi_la_SOURCES+=tspi_tick.c tsp_tick.c rpc/@RPC@/rpc_tick.c libtspi_la_CFLAGS+=-DTSS_BUILD_TICK endif if TSS_BUILD_COUNTER libtspi_la_SOURCES+=tspi_counter.c tsp_counter.c rpc/@RPC@/rpc_counter.c libtspi_la_CFLAGS+=-DTSS_BUILD_COUNTER endif if TSS_BUILD_PCR_COMP12 libtspi_la_SOURCES+=tspi_pcr_comp12.c endif if TSS_BUILD_AUTH libtspi_la_SOURCES+=tsp_auth.c rpc/@RPC@/rpc_auth.c libtspi_la_CFLAGS+=-DTSS_BUILD_AUTH endif if TSS_BUILD_GETSET libtspi_la_SOURCES+=tspi_getset.c libtspi_la_CFLAGS+=-DTSS_BUILD_GETSET endif if TSS_BUILD_RANDOM libtspi_la_SOURCES+=tspi_random.c tsp_random.c rpc/@RPC@/rpc_random.c libtspi_la_CFLAGS+=-DTSS_BUILD_RANDOM endif if TSS_BUILD_CAPS libtspi_la_SOURCES+=tspi_caps.c tsp_caps.c rpc/@RPC@/rpc_caps.c libtspi_la_CFLAGS+=-DTSS_BUILD_CAPS endif if TSS_BUILD_CAPS_TPM libtspi_la_SOURCES+=tspi_caps_tpm.c tsp_caps_tpm.c rpc/@RPC@/rpc_caps_tpm.c libtspi_la_CFLAGS+=-DTSS_BUILD_CAPS_TPM endif if TSS_BUILD_POLICY libtspi_la_SOURCES+=tspi_policy.c libtspi_la_CFLAGS+=-DTSS_BUILD_POLICY endif if TSS_BUILD_DIR libtspi_la_SOURCES+=tspi_dir.c tsp_dir.c rpc/@RPC@/rpc_dir.c libtspi_la_CFLAGS+=-DTSS_BUILD_DIR endif if TSS_BUILD_PCR_EVENTS libtspi_la_SOURCES+=tspi_pcr_events.c rpc/@RPC@/rpc_evlog.c libtspi_la_CFLAGS+=-DTSS_BUILD_PCR_EVENTS endif if TSS_BUILD_HASH libtspi_la_SOURCES+=tspi_hash.c libtspi_la_CFLAGS+=-DTSS_BUILD_HASH endif if TSS_BUILD_SIGN libtspi_la_SOURCES+=tspi_sign.c tsp_sign.c rpc/@RPC@/rpc_sign.c libtspi_la_CFLAGS+=-DTSS_BUILD_SIGN endif if TSS_BUILD_QUOTE libtspi_la_SOURCES+=tspi_quote.c tsp_quote.c rpc/@RPC@/rpc_quote.c libtspi_la_CFLAGS+=-DTSS_BUILD_QUOTE endif if TSS_BUILD_PCR_COMP libtspi_la_SOURCES+=tspi_pcr_comp.c libtspi_la_CFLAGS+=-DTSS_BUILD_PCR_COMP endif if TSS_BUILD_SEAL libtspi_la_SOURCES+=tspi_seal.c rpc/@RPC@/rpc_seal.c libtspi_la_CFLAGS+=-DTSS_BUILD_SEAL endif if TSS_BUILD_CHANGEAUTH libtspi_la_SOURCES+=tspi_changeauth.c tsp_changeauth.c rpc/@RPC@/rpc_changeauth.c libtspi_la_CFLAGS+=-DTSS_BUILD_CHANGEAUTH endif if TSS_BUILD_BIND libtspi_la_SOURCES+=tspi_bind.c tsp_bind.c rpc/@RPC@/rpc_bind.c libtspi_la_CFLAGS+=-DTSS_BUILD_BIND endif if TSS_BUILD_OWN libtspi_la_SOURCES+=tsp_own.c tspi_own.c rpc/@RPC@/rpc_own.c libtspi_la_CFLAGS+=-DTSS_BUILD_OWN endif if TSS_BUILD_PS libtspi_la_SOURCES+=ps/ps_utils.c ps/tspps.c tspi_ps.c rpc/@RPC@/rpc_ps.c tsp_ps.c libtspi_la_CFLAGS+=-DTSS_BUILD_PS endif if TSS_BUILD_ADMIN libtspi_la_SOURCES+=tspi_admin.c tsp_admin.c rpc/@RPC@/rpc_admin.c libtspi_la_CFLAGS+=-DTSS_BUILD_ADMIN endif if TSS_BUILD_AIK libtspi_la_SOURCES+=tspi_aik.c tsp_aik.c rpc/@RPC@/rpc_aik.c libtspi_la_CFLAGS+=-DTSS_BUILD_AIK endif if TSS_BUILD_EK libtspi_la_SOURCES+=tspi_ek.c tsp_ek.c rpc/@RPC@/rpc_ek.c libtspi_la_CFLAGS+=-DTSS_BUILD_EK endif if TSS_BUILD_CERTIFY libtspi_la_SOURCES+=tspi_certify.c tsp_certify.c rpc/@RPC@/rpc_certify.c libtspi_la_CFLAGS+=-DTSS_BUILD_CERTIFY endif if TSS_BUILD_KEY libtspi_la_SOURCES+=tspi_key.c rpc/@RPC@/rpc_key.c libtspi_la_CFLAGS+=-DTSS_BUILD_KEY endif if TSS_BUILD_MAINT libtspi_la_SOURCES+=tspi_maint.c tsp_maint.c rpc/@RPC@/rpc_maint.c libtspi_la_CFLAGS+=-DTSS_BUILD_MAINT endif if TSS_BUILD_MIGRATION libtspi_la_SOURCES+=tspi_migration.c tsp_migration.c rpc/@RPC@/rpc_migration.c libtspi_la_CFLAGS+=-DTSS_BUILD_MIGRATION endif if TSS_BUILD_PCR_EXTEND libtspi_la_SOURCES+=tspi_pcr_extend.c tsp_pcr_extend.c rpc/@RPC@/rpc_pcr_extend.c libtspi_la_CFLAGS+=-DTSS_BUILD_PCR_EXTEND endif if TSS_BUILD_SELFTEST libtspi_la_SOURCES+=tspi_selftest.c tsp_selftest.c rpc/@RPC@/rpc_selftest.c libtspi_la_CFLAGS+=-DTSS_BUILD_SELFTEST endif if TSS_BUILD_DAA libtspi_la_SOURCES+=tspi_daa.c tsp_daa.c \ rpc/@RPC@/rpc_daa.c \ daa/daa_issuer/keypair_generator.c daa/daa_issuer/prime_gen.c \ daa/daa_issuer/key_correctness_proof.c daa/daa_platform/platform.c \ daa/daa_issuer/issuer_init.c daa/daa_issuer/issue_credential.c \ daa/daa_verifier/verifier_transaction.c daa/daa_verifier/verifier.c \ daa/daa_structs.c daa/daa_parameter.c daa/big_integer/bi_gmp.c \ daa/big_integer/bi_openssl.c daa/daa_anonymityrevocation/csencryption_result.c \ daa/big_integer/bi.c daa/utils/list.c libtspi_la_CFLAGS+=-DTSS_BUILD_DAA endif if TSS_BUILD_GET_FLAGS libtspi_la_SOURCES+=tsp_get_flags.c endif if TSS_BUILD_PCRS_LIST libtspi_la_SOURCES+=obj_pcrs.c tsp_pcr.c libtspi_la_CFLAGS+=-DTSS_BUILD_PCRS_LIST endif if TSS_BUILD_HASH_LIST libtspi_la_SOURCES+=obj_hash.c libtspi_la_CFLAGS+=-DTSS_BUILD_HASH_LIST endif if TSS_BUILD_ENCDATA_LIST libtspi_la_SOURCES+=obj_encdata.c libtspi_la_CFLAGS+=-DTSS_BUILD_ENCDATA_LIST endif if TSS_BUILD_RSAKEY_LIST libtspi_la_SOURCES+=obj_rsakey.c tsp_key.c libtspi_la_CFLAGS+=-DTSS_BUILD_RSAKEY_LIST endif if TSS_BUILD_ASN1 libtspi_la_SOURCES+=tspi_asn1.c libtspi_la_CFLAGS+=-DTSS_BUILD_ASN1 endif if TSS_BUILD_AUDIT libtspi_la_SOURCES+=tspi_audit.c tsp_audit.c rpc/@RPC@/rpc_audit.c libtspi_la_CFLAGS+=-DTSS_BUILD_AUDIT endif if TSS_BUILD_SEALX libtspi_la_SOURCES+=tsp_seal.c libtspi_la_CFLAGS+=-DTSS_BUILD_SEALX endif if TSS_BUILD_QUOTE2 libtspi_la_SOURCES+=tspi_quote2.c tsp_quote2.c rpc/@RPC@/rpc_quote2.c libtspi_la_CFLAGS+=-DTSS_BUILD_QUOTE2 endif if HAVE_GTK libtspi_la_CFLAGS+=@GTK_CFLAGS@ libtspi_la_LDFLAGS+=@GTK_LIBS@ libtspi_la_SOURCES+=gtk/main.c gtk/support.c gtk/interface.c gtk/callbacks.c endif if OPENSSL_UI libtspi_la_LDFLAGS+=-lssl libtspi_la_SOURCES+=ssl_ui.c endif if TSS_BUILD_NV libtspi_la_SOURCES+=tspi_nv.c obj_nv.c tsp_nv.c rpc/@RPC@/rpc_nv.c libtspi_la_CFLAGS+=-DTSS_BUILD_NV endif if TSS_BUILD_DELEGATION libtspi_la_SOURCES+=tspi_delegate.c tsp_delegate.c obj_delfamily.c rpc/@RPC@/rpc_delegate.c libtspi_la_CFLAGS+=-DTSS_BUILD_DELEGATION endif if TSS_BUILD_CMK libtspi_la_SOURCES+=tspi_cmk.c obj_migdata.c rpc/@RPC@/rpc_cmk.c libtspi_la_CFLAGS+=-DTSS_BUILD_CMK endif trousers-0.3.15/src/tspi/obj_rsakey.c0000664000175000017510000014502213663651711017022 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT obj_rsakey_add(TSS_HCONTEXT tspContext, TSS_FLAG initFlags, TSS_HOBJECT *phObject) { UINT64 offset; TSS_RESULT result; TCPA_RSA_KEY_PARMS rsaKeyParms; TSS_FLAG flags = 0; struct tr_rsakey_obj *rsakey = calloc(1, sizeof(struct tr_rsakey_obj)); TPM_STRUCT_VER ver = { 1, 1, 0, 0 }; // Must be 1.1.0.0 for 1.2 TPMs UINT32 ctx_ver; if (rsakey == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_rsakey_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } if ((result = obj_context_get_policy(tspContext, TSS_POLICY_USAGE, &rsakey->usagePolicy))) { free(rsakey); return result; } if ((initFlags & TSS_KEY_STRUCT_BITMASK) == TSS_KEY_STRUCT_DEFAULT) { /* Its not set, go with the context's default */ if ((result = obj_context_get_connection_version(tspContext, &ctx_ver))) { free(rsakey); return result; } switch (ctx_ver) { case TSS_TSPATTRIB_CONTEXT_VERSION_V1_2: initFlags |= TSS_KEY_STRUCT_KEY12; break; case TSS_TSPATTRIB_CONTEXT_VERSION_V1_1: /* fall through */ default: initFlags |= TSS_KEY_STRUCT_KEY; break; } } offset = 0; switch (initFlags & TSS_KEY_STRUCT_BITMASK) { case TSS_KEY_STRUCT_KEY: rsakey->key.hdr.key11.ver = ver; rsakey->type = TSS_KEY_STRUCT_KEY; rsakey->pcrInfoType = TSS_PCRS_STRUCT_INFO; rsakey->key.keyFlags = 0; break; case TSS_KEY_STRUCT_KEY12: rsakey->key.hdr.key12.tag = TPM_TAG_KEY12; rsakey->key.hdr.key12.fill = 0; rsakey->type = TSS_KEY_STRUCT_KEY12; rsakey->pcrInfoType = TSS_PCRS_STRUCT_INFO_LONG; rsakey->key.keyFlags = TPM_PCRIGNOREDONREAD; break; default: free(rsakey); return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); break; } if (initFlags == TSS_KEY_EMPTY_KEY) goto add_key; __tspi_memset(&rsaKeyParms, 0, sizeof(TCPA_RSA_KEY_PARMS)); rsakey->key.algorithmParms.algorithmID = TCPA_ALG_RSA; rsakey->key.algorithmParms.parmSize = sizeof(TCPA_RSA_KEY_PARMS); rsakey->key.algorithmParms.parms = calloc(1, sizeof(TCPA_RSA_KEY_PARMS)); if (rsakey->key.algorithmParms.parms == NULL) { LogError("calloc of %u bytes failed.", rsakey->key.algorithmParms.parmSize); free(rsakey); return TSPERR(TSS_E_OUTOFMEMORY); } rsaKeyParms.exponentSize = 0; rsaKeyParms.numPrimes = 2; rsakey->key.pubKey.keyLength = 0; rsakey->key.encSize = 0; rsakey->key.PCRInfoSize = 0; /* End of all the default stuff */ if (initFlags & TSS_KEY_VOLATILE) rsakey->key.keyFlags |= TPM_VOLATILE; if (initFlags & TSS_KEY_MIGRATABLE) rsakey->key.keyFlags |= TPM_MIGRATABLE; if (initFlags & TSS_KEY_AUTHORIZATION) { rsakey->key.authDataUsage = TPM_AUTH_ALWAYS; flags |= TSS_OBJ_FLAG_USAGEAUTH; } #ifdef TSS_BUILD_CMK if (initFlags & TSS_KEY_CERTIFIED_MIGRATABLE) { if (rsakey->type == TSS_KEY_STRUCT_KEY) { free(rsakey); return TSPERR(TSS_E_BAD_PARAMETER); } rsakey->key.keyFlags |= TPM_MIGRATEAUTHORITY; } #endif /* set the key length */ if ((initFlags & TSS_KEY_SIZE_MASK) == TSS_KEY_SIZE_512) { rsaKeyParms.keyLength = 512; } else if ((initFlags & TSS_KEY_SIZE_MASK) == TSS_KEY_SIZE_1024) { rsaKeyParms.keyLength = 1024; } else if ((initFlags & TSS_KEY_SIZE_MASK) == TSS_KEY_SIZE_2048) { rsaKeyParms.keyLength = 2048; } else if ((initFlags & TSS_KEY_SIZE_MASK) == TSS_KEY_SIZE_4096) { rsaKeyParms.keyLength = 4096; } else if ((initFlags & TSS_KEY_SIZE_MASK) == TSS_KEY_SIZE_8192) { rsaKeyParms.keyLength = 8192; } else if ((initFlags & TSS_KEY_SIZE_MASK) == TSS_KEY_SIZE_16384) { rsaKeyParms.keyLength = 16384; } /* assign encryption and signature schemes */ if ((initFlags & TSS_KEY_TYPE_MASK) == TSS_KEY_TYPE_SIGNING) { rsakey->key.keyUsage = TPM_KEY_SIGNING; rsakey->key.algorithmParms.encScheme = TCPA_ES_NONE; rsakey->key.algorithmParms.sigScheme = TCPA_SS_RSASSAPKCS1v15_SHA1; } else if ((initFlags & TSS_KEY_TYPE_MASK) == TSS_KEY_TYPE_BIND) { rsakey->key.keyUsage = TPM_KEY_BIND; rsakey->key.algorithmParms.encScheme = TCPA_ES_RSAESOAEP_SHA1_MGF1; rsakey->key.algorithmParms.sigScheme = TCPA_SS_NONE; } else if ((initFlags & TSS_KEY_TYPE_MASK) == TSS_KEY_TYPE_LEGACY) { rsakey->key.keyUsage = TPM_KEY_LEGACY; rsakey->key.algorithmParms.encScheme = TCPA_ES_RSAESOAEP_SHA1_MGF1; rsakey->key.algorithmParms.sigScheme = TCPA_SS_RSASSAPKCS1v15_SHA1; } else if ((initFlags & TSS_KEY_TYPE_MASK) == TSS_KEY_TYPE_STORAGE) { rsakey->key.keyUsage = TPM_KEY_STORAGE; rsakey->key.algorithmParms.encScheme = TCPA_ES_RSAESOAEP_SHA1_MGF1; rsakey->key.algorithmParms.sigScheme = TCPA_SS_NONE; } else if ((initFlags & TSS_KEY_TYPE_MASK) == TSS_KEY_TYPE_IDENTITY) { rsakey->key.keyUsage = TPM_KEY_IDENTITY; rsakey->key.algorithmParms.encScheme = TCPA_ES_NONE; rsakey->key.algorithmParms.sigScheme = TCPA_SS_RSASSAPKCS1v15_SHA1; } else if ((initFlags & TSS_KEY_TYPE_MASK) == TSS_KEY_TYPE_AUTHCHANGE) { rsakey->key.keyUsage = TPM_KEY_AUTHCHANGE; rsakey->key.algorithmParms.encScheme = TCPA_ES_RSAESOAEP_SHA1_MGF1; rsakey->key.algorithmParms.sigScheme = TCPA_SS_NONE; } /* Load the RSA key parms into the blob in the TCPA_KEY_PARMS pointer. * If the exponent is left NULL, the parmSize variable will change * here */ offset = 0; Trspi_LoadBlob_RSA_KEY_PARMS(&offset, rsakey->key.algorithmParms.parms, &rsaKeyParms); rsakey->key.algorithmParms.parmSize = offset; add_key: if ((result = obj_list_add(&rsakey_list, tspContext, flags, rsakey, phObject))) { free(rsakey->key.algorithmParms.parms); free(rsakey); return result; } return TSS_SUCCESS; } /* Add a new rsakey to the list when its pulled from user PS */ TSS_RESULT obj_rsakey_add_by_key(TSS_HCONTEXT tspContext, TSS_UUID *uuid, BYTE *key, TSS_FLAG flags, TSS_HKEY *phKey) { TSS_RESULT result; UINT64 offset; struct tr_rsakey_obj *rsakey = calloc(1, sizeof(struct tr_rsakey_obj)); if (rsakey == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_rsakey_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(&rsakey->uuid, uuid, sizeof(TSS_UUID)); offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, key, &rsakey->key))) { free(rsakey); return result; } if (rsakey->key.hdr.key12.tag == TPM_TAG_KEY12) rsakey->type = TSS_KEY_STRUCT_KEY12; else rsakey->type = TSS_KEY_STRUCT_KEY; flags |= TSS_OBJ_FLAG_KEY_SET; if (rsakey->key.authDataUsage) flags |= TSS_OBJ_FLAG_USAGEAUTH; if ((result = obj_context_get_policy(tspContext, TSS_POLICY_USAGE, &rsakey->usagePolicy))) { free(rsakey); return result; } if ((result = obj_list_add(&rsakey_list, tspContext, flags, rsakey, phKey))) { free_key_refs(&rsakey->key); free(rsakey); return result; } return TSS_SUCCESS; } TSS_BOOL obj_is_rsakey(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&rsakey_list, hObject))) { answer = TRUE; obj_list_put(&rsakey_list); } return answer; } TSS_RESULT obj_rsakey_set_flags(TSS_HKEY hKey, UINT32 flags) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; rsakey->key.keyFlags = flags; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_size(TSS_HKEY hKey, UINT32 len) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; rsakey->key.pubKey.keyLength = len/8; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_key_parms(TSS_HKEY hKey, TCPA_KEY_PARMS *parms) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; free(rsakey->key.algorithmParms.parms); memcpy(&rsakey->key.algorithmParms, parms, sizeof(TCPA_KEY_PARMS)); if (parms->parmSize > 0) { if ((rsakey->key.algorithmParms.parms = malloc(parms->parmSize)) == NULL) { LogError("calloc of %d bytes failed.", parms->parmSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(rsakey->key.algorithmParms.parms, parms->parms, parms->parmSize); } else { rsakey->key.algorithmParms.parms = NULL; } done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_policy(TSS_HKEY hKey, TSS_HPOLICY hPolicy) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; UINT32 policyType; TSS_RESULT result = TSS_SUCCESS; if ((result = obj_policy_get_type(hPolicy, &policyType))) return result; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: rsakey->usagePolicy = hPolicy; break; case TSS_POLICY_MIGRATION: rsakey->migPolicy = hPolicy; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_pstype(TSS_HKEY hKey, UINT32 type) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); switch (type) { case TSS_PS_TYPE_USER: obj->flags |= TSS_OBJ_FLAG_USER_PS; obj->flags &= ~TSS_OBJ_FLAG_SYSTEM_PS; break; case TSS_PS_TYPE_SYSTEM: obj->flags |= TSS_OBJ_FLAG_SYSTEM_PS; obj->flags &= ~TSS_OBJ_FLAG_USER_PS; break; case TSS_PS_TYPE_NO: default: obj->flags &= ~TSS_OBJ_FLAG_USER_PS; obj->flags &= ~TSS_OBJ_FLAG_SYSTEM_PS; break; } obj_list_put(&rsakey_list); return TSS_SUCCESS; } /* WARN: Nobody should call this function directly except for the * Get/Set Attrib functions. The TCPA_KEY structure wants values * for keyUsage to be TPM_KEY_* values, and this function translates * to TSS_KEYUSAGE_* values for passing to an app. */ TSS_RESULT obj_rsakey_get_usage(TSS_HKEY hKey, UINT32 *usage) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; switch (rsakey->key.keyUsage) { case TPM_KEY_SIGNING: *usage = TSS_KEYUSAGE_SIGN; break; case TPM_KEY_BIND: *usage = TSS_KEYUSAGE_BIND; break; case TPM_KEY_LEGACY: *usage = TSS_KEYUSAGE_LEGACY; break; case TPM_KEY_AUTHCHANGE: *usage = TSS_KEYUSAGE_AUTHCHANGE; break; case TPM_KEY_IDENTITY: *usage = TSS_KEYUSAGE_IDENTITY; break; case TPM_KEY_STORAGE: *usage = TSS_KEYUSAGE_STORAGE; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_DATA); break; } obj_list_put(&rsakey_list); return result; } /* WARN: Nobody should call this function directly except for the * Get/Set Attrib functions. The TCPA_KEY structure wants values * for keyUsage to be TPM_KEY_* values, and this function translates * to TSS_KEYUSAGE_* values for passing to an app. */ TSS_RESULT obj_rsakey_set_usage(TSS_HKEY hKey, UINT32 usage) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; switch (usage) { case TSS_KEYUSAGE_SIGN: rsakey->key.keyUsage = TPM_KEY_SIGNING; break; case TSS_KEYUSAGE_BIND: rsakey->key.keyUsage = TPM_KEY_BIND; break; case TSS_KEYUSAGE_LEGACY: rsakey->key.keyUsage = TPM_KEY_LEGACY; break; case TSS_KEYUSAGE_AUTHCHANGE: rsakey->key.keyUsage = TPM_KEY_AUTHCHANGE; break; case TSS_KEYUSAGE_IDENTITY: rsakey->key.keyUsage = TPM_KEY_IDENTITY; break; case TSS_KEYUSAGE_STORAGE: rsakey->key.keyUsage = TPM_KEY_STORAGE; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_DATA); break; } done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_migratable(TSS_HKEY hKey, UINT32 mig) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; if (mig) rsakey->key.keyFlags |= TPM_MIGRATABLE; else rsakey->key.keyFlags &= (~TPM_MIGRATABLE); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_redirected(TSS_HKEY hKey, UINT32 redir) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; if (redir) rsakey->key.keyFlags |= TPM_REDIRECTION; else rsakey->key.keyFlags &= (~TPM_REDIRECTION); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_volatile(TSS_HKEY hKey, UINT32 vol) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; if (vol) rsakey->key.keyFlags |= TPM_VOLATILE; else rsakey->key.keyFlags &= (~TPM_VOLATILE); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_authdata_usage(TSS_HKEY hKey, UINT32 *usage) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; *usage = (UINT32)rsakey->key.authDataUsage ? TRUE : FALSE; obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_set_authdata_usage(TSS_HKEY hKey, UINT32 usage) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; rsakey->key.authDataUsage = (BYTE)usage; if (usage) obj->flags |= TSS_OBJ_FLAG_USAGEAUTH; else obj->flags &= ~TSS_OBJ_FLAG_USAGEAUTH; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_alg(TSS_HKEY hKey, UINT32 *alg) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; switch (rsakey->key.algorithmParms.algorithmID) { case TCPA_ALG_RSA: *alg = TSS_ALG_RSA; break; default: *alg = rsakey->key.algorithmParms.algorithmID; break; } obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_set_alg(TSS_HKEY hKey, UINT32 alg) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; switch (alg) { case TSS_ALG_RSA: rsakey->key.algorithmParms.algorithmID = TCPA_ALG_RSA; break; default: rsakey->key.algorithmParms.algorithmID = alg; break; } done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_es(TSS_HKEY hKey, UINT32 *es) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; /* translate TPM numbers to TSS numbers */ switch (rsakey->key.algorithmParms.encScheme) { case TCPA_ES_NONE: *es = TSS_ES_NONE; break; case TCPA_ES_RSAESPKCSv15: *es = TSS_ES_RSAESPKCSV15; break; case TCPA_ES_RSAESOAEP_SHA1_MGF1: *es = TSS_ES_RSAESOAEP_SHA1_MGF1; break; default: *es = rsakey->key.algorithmParms.encScheme; break; } obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_set_es(TSS_HKEY hKey, UINT32 es) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; /* translate TSS numbers to TPM numbers */ switch (es) { case TSS_ES_NONE: rsakey->key.algorithmParms.encScheme = TCPA_ES_NONE; break; case TSS_ES_RSAESPKCSV15: rsakey->key.algorithmParms.encScheme = TCPA_ES_RSAESPKCSv15; break; case TSS_ES_RSAESOAEP_SHA1_MGF1: rsakey->key.algorithmParms.encScheme = TCPA_ES_RSAESOAEP_SHA1_MGF1; break; default: rsakey->key.algorithmParms.encScheme = es; break; } done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_ss(TSS_HKEY hKey, UINT32 *ss) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; /* translate TPM numbers to TSS numbers */ switch (rsakey->key.algorithmParms.sigScheme) { case TCPA_SS_NONE: *ss = TSS_SS_NONE; break; case TCPA_SS_RSASSAPKCS1v15_SHA1: *ss = TSS_SS_RSASSAPKCS1V15_SHA1; break; case TCPA_SS_RSASSAPKCS1v15_DER: *ss = TSS_SS_RSASSAPKCS1V15_DER; break; case TCPA_SS_RSASSAPKCS1v15_INFO: *ss = TSS_SS_RSASSAPKCS1V15_INFO; break; default: *ss = rsakey->key.algorithmParms.sigScheme; break; } obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_set_ss(TSS_HKEY hKey, UINT32 ss) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; /* translate TSS numbers to TPM numbers */ switch (ss) { case TSS_SS_NONE: rsakey->key.algorithmParms.sigScheme = TCPA_SS_NONE; break; case TSS_SS_RSASSAPKCS1V15_SHA1: rsakey->key.algorithmParms.sigScheme = TCPA_SS_RSASSAPKCS1v15_SHA1; break; case TSS_SS_RSASSAPKCS1V15_DER: rsakey->key.algorithmParms.sigScheme = TCPA_SS_RSASSAPKCS1v15_DER; break; case TSS_SS_RSASSAPKCS1V15_INFO: rsakey->key.algorithmParms.sigScheme = TCPA_SS_RSASSAPKCS1v15_INFO; break; default: rsakey->key.algorithmParms.sigScheme = ss; break; } done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_num_primes(TSS_HKEY hKey, UINT32 num) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; UINT32ToArray(num, &rsakey->key.algorithmParms.parms[4]); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_num_primes(TSS_HKEY hKey, UINT32 *num) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TCPA_RSA_KEY_PARMS *parms; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; parms = (TCPA_RSA_KEY_PARMS *)rsakey->key.algorithmParms.parms; *num = endian32(parms->numPrimes); obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_get_flags(TSS_HKEY hKey, UINT32 *flags) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; *flags = rsakey->key.keyFlags; obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_get_size(TSS_HKEY hKey, UINT32 *len) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; switch (rsakey->key.pubKey.keyLength) { case 512/8: *len = TSS_KEY_SIZEVAL_512BIT; break; case 1024/8: *len = TSS_KEY_SIZEVAL_1024BIT; break; case 2048/8: *len = TSS_KEY_SIZEVAL_2048BIT; break; default: *len = rsakey->key.pubKey.keyLength * 8; break; } obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_get_pstype(TSS_HKEY hKey, UINT32 *type) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_SYSTEM_PS) *type = TSS_PS_TYPE_SYSTEM; else if (obj->flags & TSS_OBJ_FLAG_USER_PS) *type = TSS_PS_TYPE_USER; else *type = TSS_PS_TYPE_NO; obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_BOOL obj_rsakey_is_migratable(TSS_HKEY hKey) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_BOOL answer = FALSE; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return answer; rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->key.keyFlags & TPM_MIGRATABLE) answer = TRUE; obj_list_put(&rsakey_list); return answer; } TSS_BOOL obj_rsakey_is_redirected(TSS_HKEY hKey) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_BOOL answer = FALSE; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return answer; rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->key.keyFlags & TPM_REDIRECTION) answer = TRUE; obj_list_put(&rsakey_list); return answer; } TSS_BOOL obj_rsakey_is_volatile(TSS_HKEY hKey) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_BOOL answer = FALSE; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return answer; rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->key.keyFlags & TPM_VOLATILE) answer = TRUE; obj_list_put(&rsakey_list); return answer; } TSS_RESULT obj_rsakey_get_tsp_context(TSS_HKEY hKey, TSS_HCONTEXT *tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_get_policies(TSS_HKEY hKey, TSS_HPOLICY *usage, TSS_HPOLICY *mig, TSS_BOOL *auth) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; *mig = rsakey->migPolicy; *usage = rsakey->usagePolicy; *auth = rsakey->key.authDataUsage ? TRUE : FALSE; obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_get_policy(TSS_HKEY hKey, UINT32 policyType, TSS_HPOLICY *phPolicy, TSS_BOOL *auth) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: *phPolicy = rsakey->usagePolicy; if (auth != NULL) { if (obj->flags & TSS_OBJ_FLAG_USAGEAUTH) *auth = TRUE; else *auth = FALSE; } break; case TSS_POLICY_MIGRATION: if (!rsakey->migPolicy) { result = TSPERR(TSS_E_KEY_NO_MIGRATION_POLICY); break; } *phPolicy = rsakey->migPolicy; if (auth != NULL) { if (obj->flags & TSS_OBJ_FLAG_MIGAUTH) *auth = TRUE; else *auth = FALSE; } break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_blob(TSS_HKEY hKey, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; UINT64 offset; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; offset = 0; LoadBlob_TSS_KEY(&offset, NULL, &rsakey->key); *data = calloc_tspi(obj->tspContext, offset); if (*data == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", offset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; LoadBlob_TSS_KEY(&offset, *data, &rsakey->key); *size = offset; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_priv_blob(TSS_HKEY hKey, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; *data = calloc_tspi(obj->tspContext, rsakey->key.encSize); if (*data == NULL) { LogError("malloc of %u bytes failed.", rsakey->key.encSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = rsakey->key.encSize; memcpy(*data, rsakey->key.encData, rsakey->key.encSize); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_modulus(TSS_HKEY hKey, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; /* if this key object represents the SRK and the public key * data here is all 0's, then we shouldn't return it, we * should return TSS_E_BAD_PARAMETER. This is part of protecting * the SRK public key. */ if (rsakey->tcsHandle == TPM_KEYHND_SRK) { BYTE zeroBlob[2048] = { 0, }; if (!memcmp(rsakey->key.pubKey.key, zeroBlob, rsakey->key.pubKey.keyLength)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } } *data = calloc_tspi(obj->tspContext, rsakey->key.pubKey.keyLength); if (*data == NULL) { LogError("malloc of %u bytes failed.", rsakey->key.pubKey.keyLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = rsakey->key.pubKey.keyLength; memcpy(*data, rsakey->key.pubKey.key, rsakey->key.pubKey.keyLength); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_modulus(TSS_HKEY hKey, UINT32 size, BYTE *data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; BYTE *free_ptr; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; free_ptr = rsakey->key.pubKey.key; rsakey->key.pubKey.key = malloc(size); if (rsakey->key.pubKey.key == NULL) { rsakey->key.pubKey.key = free_ptr; // restore LogError("malloc of %u bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } rsakey->key.pubKey.keyLength = size; memcpy(rsakey->key.pubKey.key, data, size); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_pub_blob(TSS_HKEY hKey, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; UINT64 offset; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; /* if this key object represents the SRK and the public key * data here is all 0's, then we shouldn't return it, we * should return TSS_E_BAD_PARAMETER. This is part of protecting * the SRK public key. */ if (rsakey->tcsHandle == TPM_KEYHND_SRK) { BYTE zeroBlob[2048] = { 0, }; if (!memcmp(rsakey->key.pubKey.key, zeroBlob, rsakey->key.pubKey.keyLength)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } } offset = 0; Trspi_LoadBlob_KEY_PARMS(&offset, NULL, &rsakey->key.algorithmParms); Trspi_LoadBlob_STORE_PUBKEY(&offset, NULL, &rsakey->key.pubKey); *data = calloc_tspi(obj->tspContext, offset); if (*data == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", offset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_KEY_PARMS(&offset, *data, &rsakey->key.algorithmParms); Trspi_LoadBlob_STORE_PUBKEY(&offset, *data, &rsakey->key.pubKey); *size = offset; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_version(TSS_HKEY hKey, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; UINT64 offset; TPM_STRUCT_VER ver = {1, 2, 0, 0}, *pVer; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->key.hdr.key12.tag == TPM_TAG_KEY12) pVer = &ver; else pVer = &rsakey->key.hdr.key11.ver; offset = 0; Trspi_LoadBlob_TCPA_VERSION(&offset, NULL, *pVer); *data = calloc_tspi(obj->tspContext, offset); if (*data == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", offset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_TCPA_VERSION(&offset, *data, *pVer); *size = offset; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_exponent(TSS_HKEY hKey, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; TCPA_RSA_KEY_PARMS *parms; BYTE default_exp[3] = { 0x1, 0x0, 0x1 }; UINT32 offset; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; parms = (TCPA_RSA_KEY_PARMS *)rsakey->key.algorithmParms.parms; offset = parms->exponentSize; /* see TPM 1.1b spec pg. 51. If exponentSize is 0, we're using the * default exponent of 2^16 + 1. */ if (offset == 0) { offset = 3; *data = calloc_tspi(obj->tspContext, offset); if (*data == NULL) { LogError("malloc of %u bytes failed.", offset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = offset; memcpy(*data, default_exp, offset); } else { *data = calloc_tspi(obj->tspContext, offset); if (*data == NULL) { LogError("malloc of %u bytes failed.", offset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = offset; memcpy(*data, parms->exponent, offset); } done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_exponent(TSS_HKEY hKey, UINT32 size, BYTE *data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; TCPA_RSA_KEY_PARMS *parms; BYTE *free_ptr; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; parms = (TCPA_RSA_KEY_PARMS *)rsakey->key.algorithmParms.parms; free_ptr = parms->exponent; parms->exponent = malloc(size); if (parms->exponent == NULL) { parms->exponent = free_ptr; // restore LogError("malloc of %u bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } parms->exponentSize = size; memcpy(parms->exponent, data, size); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_uuid(TSS_HKEY hKey, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; UINT64 offset; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; offset = 0; Trspi_LoadBlob_UUID(&offset, NULL, rsakey->uuid); *data = calloc_tspi(obj->tspContext, offset); if (*data == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", offset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_UUID(&offset, *data, rsakey->uuid); *size = offset; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_uuid(TSS_HKEY hKey, TSS_FLAG ps_type, TSS_UUID *uuid) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; memcpy(&rsakey->uuid, uuid, sizeof(TSS_UUID)); switch (ps_type) { case TSS_PS_TYPE_SYSTEM: obj->flags |= TSS_OBJ_FLAG_SYSTEM_PS; obj->flags &= ~TSS_OBJ_FLAG_USER_PS; break; case TSS_PS_TYPE_USER: obj->flags |= TSS_OBJ_FLAG_USER_PS; obj->flags &= ~TSS_OBJ_FLAG_SYSTEM_PS; break; case TSS_PS_TYPE_NO: default: obj->flags &= ~TSS_OBJ_FLAG_USER_PS; obj->flags &= ~TSS_OBJ_FLAG_SYSTEM_PS; break; } obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_set_tcs_handle(TSS_HKEY hKey, TCS_KEY_HANDLE tcsHandle) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; rsakey->tcsHandle = tcsHandle; obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_get_tcs_handle(TSS_HKEY hKey, TCS_KEY_HANDLE *tcsHandle) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->tcsHandle) *tcsHandle = rsakey->tcsHandle; else result = TSPERR(TSS_E_KEY_NOT_LOADED); obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_tcpakey(TSS_HKEY hKey, UINT32 size, BYTE *data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; UINT64 offset; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; free_key_refs(&rsakey->key); offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, data, &rsakey->key))) goto done; if (rsakey->key.hdr.key12.tag == TPM_TAG_KEY12) rsakey->type = TSS_KEY_STRUCT_KEY12; else rsakey->type = TSS_KEY_STRUCT_KEY; if (rsakey->key.authDataUsage) obj->flags |= TSS_OBJ_FLAG_USAGEAUTH; else obj->flags &= ~TSS_OBJ_FLAG_USAGEAUTH; if (rsakey->key.PCRInfoSize && rsakey->key.PCRInfo) { offset = 0; if (rsakey->type == TSS_KEY_STRUCT_KEY12) { if ((result = Trspi_UnloadBlob_PCR_INFO_LONG(&offset, rsakey->key.PCRInfo, &rsakey->pcrInfo.infolong))) goto done; } else { if ((result = Trspi_UnloadBlob_PCR_INFO(&offset, rsakey->key.PCRInfo, &rsakey->pcrInfo.info11))) goto done; } } obj->flags |= TSS_OBJ_FLAG_KEY_SET; done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_pcr_digest(TSS_HKEY hKey, TSS_FLAG pcrInfoType, TSS_FLAG dir, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; TPM_DIGEST *digest = NULL; UINT64 offset; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (pcrInfoType != rsakey->pcrInfoType) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } switch (pcrInfoType) { case TSS_PCRS_STRUCT_INFO: if (dir == TSS_TSPATTRIB_KEYPCR_DIGEST_ATCREATION) digest = &rsakey->pcrInfo.info11.digestAtCreation; else if (dir == TSS_TSPATTRIB_KEYPCR_DIGEST_ATRELEASE) digest = &rsakey->pcrInfo.info11.digestAtRelease; else { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } break; case TSS_PCRS_STRUCT_INFO_LONG: if (dir == TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATCREATION) digest = &rsakey->pcrInfo.infolong.digestAtCreation; else if (dir == TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATRELEASE) digest = &rsakey->pcrInfo.infolong.digestAtRelease; else { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *size = sizeof(TPM_DIGEST); if ((*data = calloc_tspi(obj->tspContext, *size)) == NULL) { LogError("malloc of %u bytes failed.", *size); *size = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_DIGEST(&offset, *data, digest); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_pcr_locality(TSS_HKEY hKey, TSS_FLAG dir, UINT32 *locality) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->pcrInfoType == TSS_PCRS_STRUCT_INFO_LONG) { if (dir == TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATCREATION) *locality = rsakey->pcrInfo.infolong.localityAtCreation; else if (dir == TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATRELEASE) *locality = rsakey->pcrInfo.infolong.localityAtRelease; else result = TSPERR(TSS_E_BAD_PARAMETER); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_pcr_selection(TSS_HKEY hKey, UINT32 pcrInfoType, TSS_FLAG dir, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; UINT64 offset; TPM_PCR_SELECTION *selection = NULL; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (pcrInfoType != rsakey->pcrInfoType) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } switch (pcrInfoType) { case TSS_PCRS_STRUCT_INFO: if (dir == TSS_TSPATTRIB_KEYPCR_SELECTION) selection = &rsakey->pcrInfo.info11.pcrSelection; else { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } break; case TSS_PCRS_STRUCT_INFO_LONG: if (dir == TSS_TSPATTRIB_KEYPCRLONG_CREATION_SELECTION) selection = &rsakey->pcrInfo.infolong.creationPCRSelection; else if (dir == TSS_TSPATTRIB_KEYPCRLONG_RELEASE_SELECTION) selection = &rsakey->pcrInfo.infolong.releasePCRSelection; else { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *size = sizeof(UINT16) + selection->sizeOfSelect; if ((*data = calloc_tspi(obj->tspContext, *size)) == NULL) { LogError("malloc of %u bytes failed.", *size); *size = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_PCR_SELECTION(&offset, *data, selection); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT rsakey_set_pubkey(struct tr_rsakey_obj *rsakey, BYTE *pubkey) { TSS_RESULT result; UINT64 offset = 0; TPM_PUBKEY pub; if ((result = Trspi_UnloadBlob_PUBKEY(&offset, pubkey, &pub))) return result; free(rsakey->key.pubKey.key); free(rsakey->key.algorithmParms.parms); memcpy(&rsakey->key.pubKey, &pub.pubKey, sizeof(TPM_STORE_PUBKEY)); memcpy(&rsakey->key.algorithmParms, &pub.algorithmParms, sizeof(TPM_KEY_PARMS)); return TSS_SUCCESS; } /* Expect a TPM_PUBKEY as is explained in the portable data section of the spec */ TSS_RESULT obj_rsakey_set_pubkey(TSS_HKEY hKey, UINT32 force, BYTE *data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (!force && (obj->flags & TSS_OBJ_FLAG_KEY_SET)) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } result = rsakey_set_pubkey(rsakey, data); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_srk_pubkey(BYTE *pubkey) { struct tsp_object *obj; struct obj_list *list = &rsakey_list; struct tr_rsakey_obj *rsakey; TSS_RESULT result; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { rsakey = (struct tr_rsakey_obj *)obj->data; /* we found the SRK, set this data as its public key */ if (rsakey->tcsHandle == TPM_KEYHND_SRK) { result = rsakey_set_pubkey(rsakey, pubkey); MUTEX_UNLOCK(list->lock); return result; } } MUTEX_UNLOCK(list->lock); return TSPERR(TSS_E_INVALID_HANDLE); } TSS_RESULT obj_rsakey_set_privkey(TSS_HKEY hKey, UINT32 force, UINT32 size, BYTE *data) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; void *to_free; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (!force && (obj->flags & TSS_OBJ_FLAG_KEY_SET)) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; to_free = rsakey->key.encData; rsakey->key.encData = calloc(1, size); if (rsakey->key.encData == NULL) { rsakey->key.encData = to_free; // restore LogError("malloc of %u bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } free(to_free); rsakey->key.encSize = size; memcpy(rsakey->key.encData, data, size); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_pcr_data(TSS_HKEY hKey, TSS_HPCRS hPcrComposite) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; UINT32 pcrType, pcrSize; BYTE *pcrInfo; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; /* passing in a pcrType of TSS_PCRS_STRUCT_DEFAULT will tell the pcr routine to create * a structure matching the type of the hPcrComposite object */ pcrType = TSS_PCRS_STRUCT_DEFAULT; if ((result = obj_pcrs_create_info_type(hPcrComposite, &pcrType, &pcrSize, &pcrInfo))) goto done; rsakey->key.PCRInfo = pcrInfo; rsakey->key.PCRInfoSize = pcrSize; done: obj_list_put(&rsakey_list); return result; } void __tspi_rsakey_free(void *data) { struct tr_rsakey_obj *rsakey = (struct tr_rsakey_obj *)data; free(rsakey->key.algorithmParms.parms); free(rsakey->key.encData); free(rsakey->key.PCRInfo); free(rsakey->key.pubKey.key); free(rsakey); } /* Remove an individual rsakey object from the rsakey list with handle * equal to hObject. Clean up the TSP's key handle table. */ TSS_RESULT obj_rsakey_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { TSS_RESULT result; if ((result = obj_list_remove(&rsakey_list, &__tspi_rsakey_free, hObject, tspContext))) return result; return TSS_SUCCESS; } TSS_RESULT obj_rsakey_get_by_pub(UINT32 pub_size, BYTE *pub, TSS_HKEY *hKey) { struct obj_list *list = &rsakey_list; struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->key.pubKey.keyLength == pub_size && !memcmp(&rsakey->key.pubKey.key, pub, pub_size)) { *hKey = obj->handle; goto done; } } *hKey = 0; done: MUTEX_UNLOCK(list->lock); return result; } TSS_RESULT obj_rsakey_get_by_uuid(TSS_UUID *uuid, TSS_HKEY *hKey) { struct obj_list *list = &rsakey_list; struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { rsakey = (struct tr_rsakey_obj *)obj->data; if (!memcmp(&rsakey->uuid, uuid, sizeof(TSS_UUID))) { *hKey = obj->handle; goto done; } } result = TSPERR(TSS_E_PS_KEY_NOTFOUND); done: MUTEX_UNLOCK(list->lock); return result; } void obj_rsakey_remove_policy_refs(TSS_HPOLICY hPolicy, TSS_HCONTEXT tspContext) { struct tsp_object *obj; struct obj_list *list = &rsakey_list; struct tr_rsakey_obj *rsakey; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { if (obj->tspContext != tspContext) continue; rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->usagePolicy == hPolicy) rsakey->usagePolicy = NULL_HPOLICY; if (rsakey->migPolicy == hPolicy) rsakey->migPolicy = NULL_HPOLICY; } MUTEX_UNLOCK(list->lock); } #if 0 TSS_RESULT obj_rsakey_get_transport_attribs(TSS_HKEY hKey, TCS_KEY_HANDLE *hTCSKey, TPM_DIGEST *pubDigest) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result; Trspi_HashCtx hashCtx; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; *hTCSKey = rsakey->tcsHandle; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_STORE_PUBKEY(&hashCtx, &rsakey->key.pubKey); result |= Trspi_HashFinal(&hashCtx, pubDigest->digest); obj_list_put(&rsakey_list); return result; } #endif #ifdef TSS_BUILD_CMK TSS_BOOL obj_rsakey_is_cmk(TSS_HKEY hKey) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_BOOL answer = FALSE; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return answer; rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->type != TSS_KEY_STRUCT_KEY) { if (rsakey->key.keyFlags & TPM_MIGRATEAUTHORITY) answer = TRUE; } obj_list_put(&rsakey_list); return answer; } TSS_RESULT obj_rsakey_set_cmk(TSS_HKEY hKey, UINT32 cmk) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); if (obj->flags & TSS_OBJ_FLAG_KEY_SET) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->type == TSS_KEY_STRUCT_KEY) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } if (cmk) rsakey->key.keyFlags |= TPM_MIGRATEAUTHORITY; else rsakey->key.keyFlags &= (~TPM_MIGRATEAUTHORITY); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_msa_approval(TSS_HKEY hKey, UINT32 blobSize, BYTE *blob) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (blobSize != sizeof(rsakey->msaApproval.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(rsakey->msaApproval.digest, blob, sizeof(rsakey->msaApproval.digest)); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_msa_approval(TSS_HKEY hKey, UINT32 *blobSize, BYTE **blob) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if ((*blob = calloc_tspi(obj->tspContext, sizeof(rsakey->msaApproval.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(rsakey->msaApproval.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*blob, rsakey->msaApproval.digest, sizeof(rsakey->msaApproval.digest)); *blobSize = sizeof(rsakey->msaApproval.digest); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_set_msa_digest(TSS_HKEY hKey, UINT32 blobSize, BYTE *blob) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (blobSize != sizeof(rsakey->msaDigest.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(rsakey->msaDigest.digest, blob, sizeof(rsakey->msaDigest.digest)); done: obj_list_put(&rsakey_list); return result; } TSS_RESULT obj_rsakey_get_msa_digest(TSS_HKEY hKey, UINT32 *blobSize, BYTE **blob) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if ((*blob = calloc_tspi(obj->tspContext, sizeof(rsakey->msaDigest.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(rsakey->msaDigest.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*blob, rsakey->msaDigest.digest, sizeof(rsakey->msaDigest.digest)); *blobSize = sizeof(rsakey->msaDigest.digest); done: obj_list_put(&rsakey_list); return result; } #endif TSS_RESULT obj_rsakey_get_ownerevict(TSS_HKEY hKey, UINT32 *value) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; *value = rsakey->flags & TSS_RSAKEY_FLAG_OWNEREVICT; obj_list_put(&rsakey_list); return TSS_SUCCESS; } TSS_RESULT obj_rsakey_set_ownerevict(TSS_HKEY hKey, TSS_BOOL value) { struct tsp_object *obj; struct tr_rsakey_obj *rsakey; if ((obj = obj_list_get_obj(&rsakey_list, hKey)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); rsakey = (struct tr_rsakey_obj *)obj->data; if (value) rsakey->flags |= TSS_RSAKEY_FLAG_OWNEREVICT; else rsakey->flags &= ~TSS_RSAKEY_FLAG_OWNEREVICT; obj_list_put(&rsakey_list); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_context.c0000664000175000017510000002235613663651711017421 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "tcs_tsp.h" #include "tspps.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "obj.h" TSS_RESULT Tspi_Context_Create(TSS_HCONTEXT * phContext) /* out */ { if (phContext == NULL) return TSPERR(TSS_E_BAD_PARAMETER); return obj_context_add(phContext); } TSS_RESULT Tspi_Context_Close(TSS_HCONTEXT tspContext) /* in */ { if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); obj_context_close(tspContext); /* Have the TCS do its thing */ RPC_CloseContext(tspContext); /* Note: Memory that was returned to the app that was alloc'd by this * context isn't free'd here. Any memory that the app doesn't explicitly * free is left for it to free itself. */ /* Destroy all objects */ obj_close_context(tspContext); /* close the ps file */ PS_close(); /* We're not a connected context, so just exit */ return TSS_SUCCESS; } TSS_RESULT Tspi_Context_Connect(TSS_HCONTEXT tspContext, /* in */ TSS_UNICODE *wszDestination) /* in */ { TSS_RESULT result; BYTE *machine_name = NULL; TSS_HOBJECT hTpm; UINT32 string_len = 0; if (wszDestination == NULL) { if ((result = obj_context_get_machine_name(tspContext, &string_len, &machine_name))) return result; if ((result = RPC_OpenContext(tspContext, machine_name, CONNECTION_TYPE_TCP_PERSISTANT))) { free(machine_name); return result; } } else { if ((machine_name = Trspi_UNICODE_To_Native((BYTE *)wszDestination, NULL)) == NULL) { LogError("Error converting hostname to UTF-8"); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((result = RPC_OpenContext(tspContext, machine_name, CONNECTION_TYPE_TCP_PERSISTANT))) { free(machine_name); return result; } if ((result = obj_context_set_machine_name(tspContext, machine_name, strlen((char *)machine_name)+1))) { free(machine_name); return result; } } free(machine_name); if ((obj_tpm_add(tspContext, &hTpm))) return TSPERR(TSS_E_INTERNAL_ERROR); return TSS_SUCCESS; } TSS_RESULT Tspi_Context_FreeMemory(TSS_HCONTEXT tspContext, /* in */ BYTE * rgbMemory) /* in */ { if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); return free_tspi(tspContext, rgbMemory); } TSS_RESULT Tspi_Context_GetDefaultPolicy(TSS_HCONTEXT tspContext, /* in */ TSS_HPOLICY * phPolicy) /* out */ { if (phPolicy == NULL ) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); return obj_context_get_policy(tspContext, TSS_POLICY_USAGE, phPolicy); } TSS_RESULT Tspi_Context_CreateObject(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG objectType, /* in */ TSS_FLAG initFlags, /* in */ TSS_HOBJECT * phObject) /* out */ { TSS_RESULT result; if (phObject == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); switch (objectType) { case TSS_OBJECT_TYPE_POLICY: switch (initFlags) { #ifdef TSS_BUILD_TSS12 case TSS_POLICY_OPERATOR: /* fall through */ #endif case TSS_POLICY_MIGRATION: /* fall through */ case TSS_POLICY_USAGE: break; default: return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); } result = obj_policy_add(tspContext, initFlags, phObject); break; #ifdef TSS_BUILD_RSAKEY_LIST case TSS_OBJECT_TYPE_RSAKEY: /* If other flags are set that disagree with the SRK, this will * help catch that conflict in the later steps */ if (initFlags & TSS_KEY_TSP_SRK) { initFlags |= (TSS_KEY_TYPE_STORAGE | TSS_KEY_NOT_MIGRATABLE | TSS_KEY_NON_VOLATILE | TSS_KEY_SIZE_2048); } /* Set default key flags */ /* Default key size = 2k */ if ((initFlags & TSS_KEY_SIZE_MASK) == 0) initFlags |= TSS_KEY_SIZE_2048; /* Default key type = storage */ if ((initFlags & TSS_KEY_TYPE_MASK) == 0) initFlags |= TSS_KEY_TYPE_STORAGE; /* Check the key flags */ switch (initFlags & TSS_KEY_SIZE_MASK) { case TSS_KEY_SIZE_512: /* fall through */ case TSS_KEY_SIZE_1024: /* fall through */ case TSS_KEY_SIZE_2048: /* fall through */ case TSS_KEY_SIZE_4096: /* fall through */ case TSS_KEY_SIZE_8192: /* fall through */ case TSS_KEY_SIZE_16384: break; default: return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); } switch (initFlags & TSS_KEY_TYPE_MASK) { case TSS_KEY_TYPE_STORAGE: /* fall through */ case TSS_KEY_TYPE_SIGNING: /* fall through */ case TSS_KEY_TYPE_BIND: /* fall through */ case TSS_KEY_TYPE_AUTHCHANGE: /* fall through */ case TSS_KEY_TYPE_LEGACY: /* fall through */ case TSS_KEY_TYPE_IDENTITY: break; default: return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); } result = obj_rsakey_add(tspContext, initFlags, phObject); break; #endif #ifdef TSS_BUILD_ENCDATA_LIST case TSS_OBJECT_TYPE_ENCDATA: switch (initFlags & TSS_ENCDATA_TYPE_MASK) { case TSS_ENCDATA_LEGACY: /* fall through */ case TSS_ENCDATA_SEAL: /* fall through */ case TSS_ENCDATA_BIND: break; default: return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); } result = obj_encdata_add(tspContext, (initFlags & TSS_ENCDATA_TYPE_MASK), phObject); break; #endif #ifdef TSS_BUILD_PCRS_LIST case TSS_OBJECT_TYPE_PCRS: switch (initFlags) { case TSS_PCRS_STRUCT_DEFAULT: /* fall through */ case TSS_PCRS_STRUCT_INFO: /* fall through */ case TSS_PCRS_STRUCT_INFO_LONG: /* fall through */ case TSS_PCRS_STRUCT_INFO_SHORT: /* fall through */ break; default: return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); } result = obj_pcrs_add(tspContext, initFlags, phObject); break; #endif #ifdef TSS_BUILD_HASH_LIST case TSS_OBJECT_TYPE_HASH: switch (initFlags) { case TSS_HASH_DEFAULT: /* fall through */ case TSS_HASH_SHA1: /* fall through */ case TSS_HASH_OTHER: break; default: return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); } result = obj_hash_add(tspContext, initFlags, phObject); break; #endif #ifdef TSS_BUILD_DAA //case TSS_OBJECT_TYPE_DAA_CREDENTIAL: case TSS_OBJECT_TYPE_DAA_CERTIFICATE: if (initFlags & ~(0UL)) return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); result = obj_daacred_add(tspContext, phObject); break; case TSS_OBJECT_TYPE_DAA_ISSUER_KEY: if (initFlags & ~(0UL)) return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); result = obj_daaissuerkey_add(tspContext, phObject); break; case TSS_OBJECT_TYPE_DAA_ARA_KEY: if (initFlags & ~(0UL)) return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); result = obj_daaarakey_add(tspContext, phObject); break; #endif #ifdef TSS_BUILD_NV case TSS_OBJECT_TYPE_NV: /* There are no valid flags for a NV object */ if (initFlags & ~(0UL)) return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); result = obj_nvstore_add(tspContext, phObject); break; #endif #ifdef TSS_BUILD_DELEGATION case TSS_OBJECT_TYPE_DELFAMILY: /* There are no valid flags for a DELFAMILY object */ if (initFlags & ~(0UL)) return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); result = obj_delfamily_add(tspContext, phObject); break; #endif #ifdef TSS_BUILD_CMK case TSS_OBJECT_TYPE_MIGDATA: /* There are no valid flags for a MIGDATA object */ if (initFlags & ~(0UL)) return TSPERR(TSS_E_INVALID_OBJECT_INITFLAG); result = obj_migdata_add(tspContext, phObject); break; #endif default: LogDebug("Invalid Object type"); return TSPERR(TSS_E_INVALID_OBJECT_TYPE); break; } return result; } TSS_RESULT Tspi_Context_CloseObject(TSS_HCONTEXT tspContext, /* in */ TSS_HOBJECT hObject) /* in */ { TSS_RESULT result; if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); if (obj_is_pcrs(hObject)) { #ifdef TSS_BUILD_PCRS_LIST result = obj_pcrs_remove(hObject, tspContext); #endif } else if (obj_is_encdata(hObject)) { #ifdef TSS_BUILD_ENCDATA_LIST result = obj_encdata_remove(hObject, tspContext); #endif } else if (obj_is_hash(hObject)) { #ifdef TSS_BUILD_HASH_LIST result = obj_hash_remove(hObject, tspContext); #endif } else if (obj_is_rsakey(hObject)) { #ifdef TSS_BUILD_RSAKEY_LIST result = obj_rsakey_remove(hObject, tspContext); #endif } else if (obj_is_policy(hObject)) { result = obj_policy_remove(hObject, tspContext); } else if (obj_is_delfamily(hObject)) { #ifdef TSS_BUILD_DELEGATION result = obj_delfamily_remove(hObject, tspContext); #endif } else if (obj_is_migdata(hObject)) { #ifdef TSS_BUILD_CMK result = obj_migdata_remove(hObject, tspContext); #endif } else if (obj_is_nvstore(hObject)) { #ifdef TSS_BUILD_NV result = obj_nvstore_remove(hObject, tspContext); #endif } else { result = TSPERR(TSS_E_INVALID_HANDLE); } return result; } TSS_RESULT Tspi_Context_GetTpmObject(TSS_HCONTEXT tspContext, /* in */ TSS_HTPM * phTPM) /* out */ { if (phTPM == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); return obj_tpm_get(tspContext, phTPM); } trousers-0.3.15/src/tspi/tsp_ek.c0000664000175000017510000000562313663651711016161 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT owner_get_pubek(TSS_HCONTEXT tspContext, TSS_HTPM hTPM, TSS_HKEY *hPubEk) { TSS_RESULT result; UINT32 tpmVersion, pubEKSize; TSS_HPOLICY hPolicy; Trspi_HashCtx hashCtx; BYTE *pubEK = NULL; TSS_HKEY hRetKey; TPM_AUTH ownerAuth; TPM_DIGEST digest; if ((result = obj_context_get_tpm_version(tspContext, &tpmVersion))) return result; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy))) return result; switch (tpmVersion) { case 2: result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadInternalPub); result |= Trspi_Hash_UINT32(&hashCtx, TPM_KH_EK); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_OwnerReadInternalPub, hPolicy, FALSE, &digest, &ownerAuth))) goto done; if ((result = TCS_API(tspContext)->OwnerReadInternalPub(tspContext, TPM_KH_EK, &ownerAuth, &pubEKSize, &pubEK))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadInternalPub); result |= Trspi_HashUpdate(&hashCtx, pubEKSize, pubEK); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth))) goto done; break; default: result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadPubek); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_OwnerReadPubek, hPolicy, FALSE, &digest, &ownerAuth))) goto done; if ((result = TCS_API(tspContext)->OwnerReadPubek(tspContext, &ownerAuth, &pubEKSize, &pubEK))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadPubek); result |= Trspi_HashUpdate(&hashCtx, pubEKSize, pubEK); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth))) goto done; break; } if ((result = obj_rsakey_add(tspContext, TSS_KEY_SIZE_2048|TSS_KEY_TYPE_LEGACY, &hRetKey))) goto done; if ((result = obj_rsakey_set_pubkey(hRetKey, TRUE, pubEK))) goto done; *hPubEk = hRetKey; done: free(pubEK); return result; } trousers-0.3.15/src/tspi/tspi_policy.c0000664000175000017510000000537213663651711017233 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_GetPolicyObject(TSS_HOBJECT hObject, /* in */ TSS_FLAG policyType, /* in */ TSS_HPOLICY * phPolicy) /* out */ { TSS_RESULT result; if (phPolicy == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (obj_is_tpm(hObject)) { result = obj_tpm_get_policy(hObject, policyType, phPolicy); #ifdef TSS_BUILD_NV } else if (obj_is_nvstore(hObject)) { result = obj_nvstore_get_policy(hObject, policyType, phPolicy); #endif #ifdef TSS_BUILD_RSAKEY_LIST } else if (obj_is_rsakey(hObject)) { result = obj_rsakey_get_policy(hObject, policyType, phPolicy, NULL); #endif #ifdef TSS_BUILD_ENCDATA_LIST } else if (obj_is_encdata(hObject)) { result = obj_encdata_get_policy(hObject, policyType, phPolicy); #endif } else { if (obj_is_policy(hObject) || obj_is_hash(hObject) || obj_is_pcrs(hObject) || obj_is_context(hObject)) result = TSPERR(TSS_E_BAD_PARAMETER); else result = TSPERR(TSS_E_INVALID_HANDLE); } if (result == TSS_SUCCESS && *phPolicy == NULL_HPOLICY) result = TSPERR(TSS_E_INTERNAL_ERROR); return result; } TSS_RESULT Tspi_Policy_SetSecret(TSS_HPOLICY hPolicy, /* in */ TSS_FLAG secretMode, /* in */ UINT32 ulSecretLength, /* in */ BYTE * rgbSecret) /* in */ { TSS_RESULT result; TSS_HCONTEXT tspContext; if ((result = obj_policy_get_tsp_context(hPolicy, &tspContext))) return result; if (obj_context_is_silent(tspContext) && secretMode == TSS_SECRET_MODE_POPUP) return TSPERR(TSS_E_SILENT_CONTEXT); return obj_policy_set_secret(hPolicy, secretMode, ulSecretLength, rgbSecret); } TSS_RESULT Tspi_Policy_FlushSecret(TSS_HPOLICY hPolicy) /* in */ { return obj_policy_flush_secret(hPolicy); } TSS_RESULT Tspi_Policy_AssignToObject(TSS_HPOLICY hPolicy, /* in */ TSS_HOBJECT hObject) /* in */ { TSS_RESULT result; if (obj_is_tpm(hObject)) { result = obj_tpm_set_policy(hObject, hPolicy); #ifdef TSS_BUILD_NV } else if (obj_is_nvstore(hObject)) { result = obj_nvstore_set_policy(hObject, hPolicy); #endif #ifdef TSS_BUILD_RSAKEY_LIST } else if (obj_is_rsakey(hObject)) { result = obj_rsakey_set_policy(hObject, hPolicy); #endif #ifdef TSS_BUILD_ENCDATA_LIST } else if (obj_is_encdata(hObject)) { result = obj_encdata_set_policy(hObject, hPolicy); #endif } else { result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } trousers-0.3.15/src/tspi/tspi_ek.c0000664000175000017510000003163713663651711016336 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_CreateEndorsementKey(TSS_HTPM hTPM, /* in */ TSS_HKEY hKey, /* in */ TSS_VALIDATION * pValidationData) /* in, out */ { TCPA_NONCE antiReplay; TCPA_DIGEST digest; TSS_RESULT result; UINT32 ekSize; BYTE *ek; TSS_KEY dummyKey; UINT64 offset; TCPA_DIGEST hash; UINT32 newEKSize; BYTE *newEK; TSS_HCONTEXT tspContext; TCPA_PUBKEY pubEK; Trspi_HashCtx hashCtx; __tspi_memset(&pubEK, 0, sizeof(TCPA_PUBKEY)); __tspi_memset(&dummyKey, 0, sizeof(TSS_KEY)); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_rsakey_get_blob(hKey, &ekSize, &ek))) return result; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, ek, &dummyKey))) return result; offset = 0; Trspi_LoadBlob_KEY_PARMS(&offset, ek, &dummyKey.algorithmParms); free_key_refs(&dummyKey); ekSize = offset; if (pValidationData == NULL) { if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), (BYTE **)antiReplay.nonce))) { LogError("Failed to create random nonce"); return TSPERR(TSS_E_INTERNAL_ERROR); } } else { if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); } if ((result = TCS_API(tspContext)->CreateEndorsementKeyPair(tspContext, antiReplay, ekSize, ek, &newEKSize, &newEK, &digest))) return result; if (pValidationData == NULL) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_HashUpdate(&hashCtx, newEKSize, newEK); result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, antiReplay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, hash.digest))) goto done; if (memcmp(hash.digest, digest.digest, TCPA_SHA1_160_HASH_LEN)) { LogError("Internal verification failed"); result = TSPERR(TSS_E_EK_CHECKSUM); goto done; } } else { pValidationData->rgbData = calloc_tspi(tspContext, newEKSize); if (pValidationData->rgbData == NULL) { LogError("malloc of %u bytes failed.", newEKSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } pValidationData->ulDataLength = newEKSize; memcpy(pValidationData->rgbData, newEK, newEKSize); memcpy(&pValidationData->rgbData[ekSize], antiReplay.nonce, sizeof(antiReplay.nonce)); pValidationData->rgbValidationData = calloc_tspi(tspContext, TCPA_SHA1_160_HASH_LEN); if (pValidationData->rgbValidationData == NULL) { LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN); free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN; memcpy(pValidationData->rgbValidationData, digest.digest, TCPA_SHA1_160_HASH_LEN); } if ((result = obj_rsakey_set_pubkey(hKey, FALSE, newEK)) && pValidationData) { free_tspi(tspContext, pValidationData->rgbValidationData); free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; pValidationData->rgbValidationData = NULL; pValidationData->ulValidationDataLength = 0; } done: free(newEK); return result; } TSS_RESULT Tspi_TPM_GetPubEndorsementKey(TSS_HTPM hTPM, /* in */ TSS_BOOL fOwnerAuthorized, /* in */ TSS_VALIDATION *pValidationData, /* in, out */ TSS_HKEY *phEndorsementPubKey) /* out */ { TCPA_DIGEST digest; TSS_RESULT result; UINT64 offset; UINT32 pubEKSize; BYTE *pubEK; TCPA_NONCE antiReplay; TCPA_DIGEST checkSum; TSS_HOBJECT retKey; TSS_HCONTEXT tspContext; TCPA_PUBKEY pubKey; Trspi_HashCtx hashCtx; __tspi_memset(&pubKey, 0, sizeof(TCPA_PUBKEY)); if (phEndorsementPubKey == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (fOwnerAuthorized) return owner_get_pubek(tspContext, hTPM, phEndorsementPubKey); if (pValidationData == NULL) { if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), (BYTE **)antiReplay.nonce))) { LogDebug("Failed to generate random nonce"); return TSPERR(TSS_E_INTERNAL_ERROR); } } else { if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); } /* call down to the TPM */ if ((result = TCS_API(tspContext)->ReadPubek(tspContext, antiReplay, &pubEKSize, &pubEK, &checkSum))) return result; /* validate the returned hash, or set up the return so that the user can */ if (pValidationData == NULL) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_HashUpdate(&hashCtx, pubEKSize, pubEK); result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; /* check validation of the entire pubkey structure */ if (memcmp(digest.digest, checkSum.digest, TPM_SHA1_160_HASH_LEN)) { /* validation failed, unload the pubEK in order to hash * just the pubKey portion of the pubEK. This is done on * Atmel chips specifically. */ offset = 0; __tspi_memset(&pubKey, 0, sizeof(TCPA_PUBKEY)); if ((result = Trspi_UnloadBlob_PUBKEY(&offset, pubEK, &pubKey))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_HashUpdate(&hashCtx, pubKey.pubKey.keyLength, pubKey.pubKey.key); result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (memcmp(digest.digest, checkSum.digest, TCPA_SHA1_160_HASH_LEN)) { result = TSPERR(TSS_E_EK_CHECKSUM); goto done; } } } else { /* validate the entire TCPA_PUBKEY structure */ pValidationData->ulDataLength = pubEKSize + TCPA_SHA1_160_HASH_LEN; pValidationData->rgbData = calloc_tspi(tspContext, pValidationData->ulDataLength); if (pValidationData->rgbData == NULL) { LogError("malloc of %u bytes failed.", pValidationData->ulDataLength); pValidationData->ulDataLength = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(pValidationData->rgbData, pubEK, pubEKSize); memcpy(&pValidationData->rgbData[pubEKSize], antiReplay.nonce, TCPA_SHA1_160_HASH_LEN); pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN; pValidationData->rgbValidationData = calloc_tspi(tspContext, TCPA_SHA1_160_HASH_LEN); if (pValidationData->rgbValidationData == NULL) { LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN); pValidationData->ulValidationDataLength = 0; pValidationData->ulDataLength = 0; free_tspi(tspContext,pValidationData->rgbData); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(pValidationData->rgbValidationData, checkSum.digest, TPM_SHA1_160_HASH_LEN); } if ((result = obj_rsakey_add(tspContext, TSS_KEY_SIZE_2048|TSS_KEY_TYPE_LEGACY, &retKey))) goto done; if ((result = obj_rsakey_set_pubkey(retKey, TRUE, pubEK))) goto done; *phEndorsementPubKey = retKey; done: free(pubEK); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT Tspi_TPM_CreateRevocableEndorsementKey(TSS_HTPM hTPM, /* in */ TSS_HKEY hKey, /* in */ TSS_VALIDATION * pValidationData,/* in, out */ UINT32 * pulEkResetDataLength, /* in, out */ BYTE ** prgbEkResetData) /* in, out */ { TPM_NONCE antiReplay; TPM_DIGEST digest; TSS_RESULT result; UINT32 ekSize; BYTE *ek; TSS_KEY dummyKey; UINT64 offset; TSS_BOOL genResetAuth; TPM_DIGEST eKResetAuth; TPM_DIGEST hash; UINT32 newEKSize; BYTE *newEK; TSS_HCONTEXT tspContext; TPM_PUBKEY pubEK; Trspi_HashCtx hashCtx; __tspi_memset(&pubEK, 0, sizeof(TPM_PUBKEY)); __tspi_memset(&dummyKey, 0, sizeof(TSS_KEY)); __tspi_memset(&eKResetAuth, 0xff, sizeof(eKResetAuth)); if (!pulEkResetDataLength || !prgbEkResetData) return TSPERR(TSS_E_BAD_PARAMETER); if (*pulEkResetDataLength != 0) { if (*prgbEkResetData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (*pulEkResetDataLength < sizeof(eKResetAuth.digest)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(eKResetAuth.digest, *prgbEkResetData, sizeof(eKResetAuth.digest)); genResetAuth = FALSE; } else { if (*prgbEkResetData != NULL) return TSPERR(TSS_E_BAD_PARAMETER); genResetAuth = TRUE; } if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_rsakey_get_blob(hKey, &ekSize, &ek))) return result; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, ek, &dummyKey))) return result; offset = 0; Trspi_LoadBlob_KEY_PARMS(&offset, ek, &dummyKey.algorithmParms); free_key_refs(&dummyKey); ekSize = offset; if (pValidationData == NULL) { if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)antiReplay.nonce))) { LogError("Failed to create random nonce"); return TSPERR(TSS_E_INTERNAL_ERROR); } } else { if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); } if ((result = RPC_CreateRevocableEndorsementKeyPair(tspContext, antiReplay, ekSize, ek, genResetAuth, &eKResetAuth, &newEKSize, &newEK, &digest))) return result; if (pValidationData == NULL) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_HashUpdate(&hashCtx, newEKSize, newEK); result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, hash.digest))) goto done; if (memcmp(hash.digest, digest.digest, TPM_SHA1_160_HASH_LEN)) { LogError("Internal verification failed"); result = TSPERR(TSS_E_EK_CHECKSUM); goto done; } } else { pValidationData->rgbData = calloc_tspi(tspContext, newEKSize); if (pValidationData->rgbData == NULL) { LogError("malloc of %u bytes failed.", newEKSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } pValidationData->ulDataLength = newEKSize; memcpy(pValidationData->rgbData, newEK, newEKSize); memcpy(&pValidationData->rgbData[ekSize], antiReplay.nonce, sizeof(antiReplay.nonce)); pValidationData->rgbValidationData = calloc_tspi(tspContext, TPM_SHA1_160_HASH_LEN); if (pValidationData->rgbValidationData == NULL) { LogError("malloc of %d bytes failed.", TPM_SHA1_160_HASH_LEN); free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } pValidationData->ulValidationDataLength = TPM_SHA1_160_HASH_LEN; memcpy(pValidationData->rgbValidationData, digest.digest, TPM_SHA1_160_HASH_LEN); } if ((result = obj_rsakey_set_pubkey(hKey, FALSE, newEK))) { if (pValidationData) { free_tspi(tspContext, pValidationData->rgbValidationData); free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; pValidationData->rgbValidationData = NULL; pValidationData->ulValidationDataLength = 0; } goto done; } if (genResetAuth) { if ((*prgbEkResetData = calloc_tspi(tspContext, sizeof(eKResetAuth.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(eKResetAuth.digest)); if (pValidationData) { free_tspi(tspContext, pValidationData->rgbValidationData); free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; pValidationData->rgbValidationData = NULL; pValidationData->ulValidationDataLength = 0; } goto done; } memcpy(*prgbEkResetData, eKResetAuth.digest, sizeof(eKResetAuth.digest)); *pulEkResetDataLength = sizeof(eKResetAuth.digest); } done: free(newEK); return result; } TSS_RESULT Tspi_TPM_RevokeEndorsementKey(TSS_HTPM hTPM, /* in */ UINT32 ulEkResetDataLength, /* in */ BYTE * rgbEkResetData) /* in */ { TSS_HCONTEXT tspContext; TPM_DIGEST eKResetAuth; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (ulEkResetDataLength < sizeof(eKResetAuth.digest) || !rgbEkResetData) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(eKResetAuth.digest, rgbEkResetData, sizeof(eKResetAuth.digest)); if ((result = RPC_RevokeEndorsementKeyPair(tspContext, &eKResetAuth))) return result; return result; } #endif trousers-0.3.15/src/tspi/obj_encdata.c0000664000175000017510000002631713663651711017130 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT obj_encdata_add(TSS_HCONTEXT tspContext, UINT32 type, TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_encdata_obj *encdata = calloc(1, sizeof(struct tr_encdata_obj)); if (encdata == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_encdata_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } /* add usage policy */ if ((result = obj_context_get_policy(tspContext, TSS_POLICY_USAGE, &encdata->usagePolicy))) { free(encdata); return result; } encdata->type = type; if ((result = obj_list_add(&encdata_list, tspContext, 0, encdata, phObject))) { free(encdata); return result; } return TSS_SUCCESS; } TSS_BOOL obj_is_encdata(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&encdata_list, hObject))) { answer = TRUE; obj_list_put(&encdata_list); } return answer; } TSS_RESULT obj_encdata_get_tsp_context(TSS_HENCDATA hEncdata, TSS_HCONTEXT *tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&encdata_list, hEncdata)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&encdata_list); return TSS_SUCCESS; } TSS_RESULT obj_encdata_get_policy(TSS_HENCDATA hEncData, UINT32 policyType, TSS_HPOLICY *phPolicy) { struct tsp_object *obj; struct tr_encdata_obj *encdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: *phPolicy = encdata->usagePolicy; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&encdata_list); return result; } TSS_RESULT obj_encdata_set_policy(TSS_HENCDATA hEncData, TSS_HPOLICY hPolicy) { struct tsp_object *obj; struct tr_encdata_obj *encdata; UINT32 policyType; TSS_RESULT result = TSS_SUCCESS; if ((result = obj_policy_get_type(hPolicy, &policyType))) return result; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: encdata->usagePolicy = hPolicy; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&encdata_list); return result; } TSS_RESULT obj_encdata_get_data(TSS_HENCDATA hEncData, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_encdata_obj *encdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; if (encdata->encryptedDataLength == 0) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } else { *data = calloc_tspi(obj->tspContext, encdata->encryptedDataLength); if (*data == NULL) { LogError("malloc of %d bytes failed.", encdata->encryptedDataLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = encdata->encryptedDataLength; memcpy(*data, encdata->encryptedData, *size); } done: obj_list_put(&encdata_list); return result; } TSS_RESULT obj_encdata_get_pcr_digest(TSS_HENCDATA hEncData, TSS_FLAG pcrInfoType, TSS_FLAG dir, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_encdata_obj *encdata; TSS_RESULT result = TSS_SUCCESS; TPM_DIGEST *digest; UINT64 offset; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; if (pcrInfoType != encdata->pcrInfoType) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } switch (pcrInfoType) { case TSS_PCRS_STRUCT_INFO: if (dir == TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATCREATION) digest = &encdata->pcrInfo.info11.digestAtCreation; else if (dir == TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATRELEASE) digest = &encdata->pcrInfo.info11.digestAtRelease; else { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } break; case TSS_PCRS_STRUCT_INFO_LONG: if (dir == TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATCREATION) digest = &encdata->pcrInfo.infolong.digestAtCreation; else if (dir == TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATRELEASE) digest = &encdata->pcrInfo.infolong.digestAtRelease; else { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } break; default: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } *size = sizeof(TPM_DIGEST); if ((*data = calloc_tspi(obj->tspContext, *size)) == NULL) { LogError("malloc of %u bytes failed.", *size); *size = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_DIGEST(&offset, *data, digest); done: obj_list_put(&encdata_list); return result; } TSS_RESULT obj_encdata_get_pcr_locality(TSS_HENCDATA hEncData, TSS_FLAG dir, UINT32 *locality) { struct tsp_object *obj; struct tr_encdata_obj *encdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; if (encdata->pcrInfoType == TSS_PCRS_STRUCT_INFO_LONG) { if (dir == TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATCREATION) *locality = encdata->pcrInfo.infolong.localityAtCreation; else if (dir == TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATRELEASE) *locality = encdata->pcrInfo.infolong.localityAtRelease; else result = TSPERR(TSS_E_BAD_PARAMETER); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); obj_list_put(&encdata_list); return result; } TSS_RESULT obj_encdata_get_pcr_selection(TSS_HENCDATA hEncData, TSS_FLAG pcrInfoType, TSS_FLAG dir, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_encdata_obj *encdata; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_SELECTION *selection = NULL; UINT64 offset; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; if (pcrInfoType != encdata->pcrInfoType) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } switch (pcrInfoType) { case TSS_PCRS_STRUCT_INFO: if (dir == TSS_TSPATTRIB_ENCDATAPCR_SELECTION) selection = &encdata->pcrInfo.info11.pcrSelection; break; case TSS_PCRS_STRUCT_INFO_LONG: if (dir == TSS_TSPATTRIB_ENCDATAPCRLONG_CREATION_SELECTION) selection = &encdata->pcrInfo.infolong.creationPCRSelection; else if (dir == TSS_TSPATTRIB_ENCDATAPCRLONG_RELEASE_SELECTION) selection = &encdata->pcrInfo.infolong.releasePCRSelection; else { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } break; default: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } if (selection == NULL) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } *size = sizeof(UINT16) + selection->sizeOfSelect; if ((*data = calloc_tspi(obj->tspContext, *size)) == NULL) { LogError("malloc of %u bytes failed.", *size); *size = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_PCR_SELECTION(&offset, *data, selection); done: obj_list_put(&encdata_list); return result; } TSS_RESULT obj_encdata_set_pcr_info(TSS_HENCDATA hEncData, UINT32 pcrInfoType, BYTE *info_blob) { struct tsp_object *obj; struct tr_encdata_obj *encdata; TSS_RESULT result = TSS_SUCCESS; UINT64 offset = 0; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; switch (pcrInfoType) { case TSS_PCRS_STRUCT_INFO_LONG: result = Trspi_UnloadBlob_PCR_INFO_LONG(&offset, info_blob, &encdata->pcrInfo.infolong); break; case TSS_PCRS_STRUCT_INFO: result = Trspi_UnloadBlob_PCR_INFO(&offset, info_blob, &encdata->pcrInfo.info11); break; default: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } encdata->pcrInfoType = pcrInfoType; /* XXX are we using this anywhere? */ obj->flags |= TSS_OBJ_FLAG_PCRS; done: obj_list_put(&encdata_list); return result; } TSS_RESULT obj_encdata_set_data(TSS_HENCDATA hEncData, UINT32 size, BYTE *data) { struct tsp_object *obj; struct tr_encdata_obj *encdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; free(encdata->encryptedData); encdata->encryptedData = NULL; encdata->encryptedDataLength = 0; if (size > 0) { if ((encdata->encryptedData = malloc(size)) == NULL) { LogError("malloc of %u bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } encdata->encryptedDataLength = size; memcpy(encdata->encryptedData, data, size); } done: obj_list_put(&encdata_list); return result; } void encdata_free(void *data) { struct tr_encdata_obj *encdata = (struct tr_encdata_obj *)data; free(encdata->encryptedData); switch (encdata->pcrInfoType) { case TSS_PCRS_STRUCT_INFO: free(encdata->pcrInfo.info11.pcrSelection.pcrSelect); break; case TSS_PCRS_STRUCT_INFO_LONG: free(encdata->pcrInfo.infolong.creationPCRSelection.pcrSelect); free(encdata->pcrInfo.infolong.releasePCRSelection.pcrSelect); break; default: /* no PCR data was set */ break; } free(encdata); } /* remove an individual encdata object from the encdata list with handle * equal to hObject */ TSS_RESULT obj_encdata_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { TSS_RESULT result; if ((result = obj_list_remove(&encdata_list, &encdata_free, hObject, tspContext))) return result; return TSS_SUCCESS; } void obj_encdata_remove_policy_refs(TSS_HPOLICY hPolicy, TSS_HCONTEXT tspContext) { struct tsp_object *obj; struct obj_list *list = &encdata_list; struct tr_encdata_obj *encdata; pthread_mutex_lock(&list->lock); for (obj = list->head; obj; obj = obj->next) { if (obj->tspContext != tspContext) continue; encdata = (struct tr_encdata_obj *)obj->data; if (encdata->usagePolicy == hPolicy) encdata->usagePolicy = NULL_HPOLICY; } pthread_mutex_unlock(&list->lock); } #ifdef TSS_BUILD_SEALX TSS_RESULT obj_encdata_set_seal_protect_mode(TSS_HENCDATA hEncData, UINT32 protectMode) { struct tsp_object *obj; struct tr_encdata_obj *encdata; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; encdata->protectMode = protectMode; obj_list_put(&encdata_list); return TSS_SUCCESS; } TSS_RESULT obj_encdata_get_seal_protect_mode(TSS_HENCDATA hEncData, UINT32 *protectMode) { struct tsp_object *obj; struct tr_encdata_obj *encdata; if ((obj = obj_list_get_obj(&encdata_list, hEncData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); encdata = (struct tr_encdata_obj *)obj->data; *protectMode = encdata->protectMode; obj_list_put(&encdata_list); return TSS_SUCCESS; } #endif trousers-0.3.15/src/tspi/tspi_audit.c0000664000175000017510000002212513663651711017035 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "obj.h" #include "tsplog.h" /* XXX Split into two functions */ TSS_RESULT Tspi_TPM_GetAuditDigest(TSS_HTPM hTpm, /* in */ TSS_HKEY hKey, /* in */ TSS_BOOL closeAudit, /* in */ UINT32* pulAuditDigestSize, /* out */ BYTE** prgbAuditDigest, /* out */ TPM_COUNTER_VALUE* pCounterValue, /* out */ TSS_VALIDATION* pValidationData, /* out */ UINT32* ordSize, /* out */ UINT32** ordList) /* out */ { TSS_HCONTEXT tspContext; UINT32 counterValueSize; BYTE *counterValue = NULL; TPM_DIGEST auditDigest; TSS_RESULT result = TSS_SUCCESS; UINT64 offset; if ((pulAuditDigestSize == NULL) || (prgbAuditDigest == NULL) || (pCounterValue == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); if (hKey == NULL_HKEY) if ((ordSize == NULL) || (ordList == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTpm, &tspContext))) return result; if (hKey == NULL_HKEY) { UINT32 startOrdinal = 0; TSS_BOOL more; UINT32 tcsOrdSize; UINT32 *tcsOrdList = NULL; UINT32 *pulTemp; *prgbAuditDigest = NULL; *pulAuditDigestSize = 0; *ordList = NULL; *ordSize = 0; do { if ((result = TCS_API(tspContext)->GetAuditDigest(tspContext, startOrdinal, &auditDigest, &counterValueSize, &counterValue, &more, &tcsOrdSize, &tcsOrdList))) goto done1; if ((pulTemp = calloc_tspi(tspContext, (*ordSize + tcsOrdSize) * sizeof(UINT32))) == NULL) { LogError("malloc of %u bytes failed.", *ordSize + tcsOrdSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done1; } if (*ordList) memcpy(pulTemp, *ordList, *ordSize * sizeof(UINT32)); memcpy(pulTemp + *ordSize, tcsOrdList, tcsOrdSize * sizeof(UINT32)); free(tcsOrdList); tcsOrdList = NULL; if (*ordList) free_tspi(tspContext, *ordList); *ordList = pulTemp; *ordSize += tcsOrdSize; if (more == TRUE) { offset = 0; Trspi_UnloadBlob_UINT32(&offset, &startOrdinal, (BYTE *)(*ordList + (*ordSize - 1))); startOrdinal++; free(counterValue); counterValue = NULL; } } while (more == TRUE); *pulAuditDigestSize = sizeof(auditDigest.digest); if ((*prgbAuditDigest = calloc_tspi(tspContext, *pulAuditDigestSize)) == NULL) { LogError("malloc of %u bytes failed.", *pulAuditDigestSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done1; } offset = 0; Trspi_LoadBlob_DIGEST(&offset, *prgbAuditDigest, &auditDigest); offset = 0; Trspi_UnloadBlob_COUNTER_VALUE(&offset, counterValue, pCounterValue); result = TSS_SUCCESS; done1: if (result != TSS_SUCCESS) { if (*prgbAuditDigest) free_tspi(tspContext, *prgbAuditDigest); if (*ordList) free_tspi(tspContext, *ordList); *prgbAuditDigest = NULL; *pulAuditDigestSize = 0; *ordList = NULL; *ordSize = 0; } free(counterValue); free(tcsOrdList); return result; } else { TSS_HPOLICY hPolicy; TSS_BOOL usesAuth; TCS_KEY_HANDLE tcsKeyHandle; TPM_AUTH keyAuth, *pAuth; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; TPM_NONCE antiReplay; TPM_DIGEST auditDigest; TPM_DIGEST ordinalDigest; UINT32 sigSize; BYTE *sig = NULL; TPM_SIGN_INFO signInfo; UINT32 signInfoBlobSize; BYTE *signInfoBlob = NULL; if (pValidationData == NULL) { LogDebug("Internal Verify"); if ((result = get_local_random(tspContext, FALSE, TPM_NONCE_SIZE, (BYTE **)antiReplay.nonce))) return result; } else { LogDebug("External Verify"); if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); if (pValidationData->rgbExternalData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); pValidationData->ulDataLength = 0; pValidationData->rgbData = NULL; pValidationData->ulValidationDataLength = 0; pValidationData->rgbValidationData = NULL; } if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKeyHandle))) return result; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetAuditDigestSigned); result |= Trspi_Hash_BOOL(&hashCtx, closeAudit); result |= Trspi_Hash_NONCE(&hashCtx, antiReplay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; pAuth = &keyAuth; if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_GetAuditDigestSigned, hPolicy, FALSE, &digest, pAuth))) return result; } else pAuth = NULL; if ((result = TCS_API(tspContext)->GetAuditDigestSigned(tspContext, tcsKeyHandle, closeAudit, &antiReplay, pAuth, &counterValueSize, &counterValue, &auditDigest, &ordinalDigest, &sigSize, &sig))) return result; __tspi_memset(&signInfo, 0, sizeof(signInfo)); signInfo.tag = TPM_TAG_SIGNINFO; memcpy(signInfo.fixed, "ADIG", strlen("ADIG")); signInfo.replay = antiReplay; signInfo.dataLen = sizeof(auditDigest.digest) + counterValueSize + sizeof(ordinalDigest.digest); if ((signInfo.data = malloc(signInfo.dataLen)) == NULL) { LogError("malloc of %u bytes failed.", signInfo.dataLen); result = TSPERR(TSS_E_OUTOFMEMORY); goto done2; } offset = 0; Trspi_LoadBlob_DIGEST(&offset, signInfo.data, &auditDigest); Trspi_LoadBlob(&offset, counterValueSize, signInfo.data, counterValue); Trspi_LoadBlob_DIGEST(&offset, signInfo.data, &ordinalDigest); if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetAuditDigestSigned); result |= Trspi_HashUpdate(&hashCtx, counterValueSize, counterValue); result |= Trspi_Hash_DIGEST(&hashCtx, auditDigest.digest); result |= Trspi_Hash_DIGEST(&hashCtx, ordinalDigest.digest); result |= Trspi_Hash_UINT32(&hashCtx, sigSize); result |= Trspi_HashUpdate(&hashCtx, sigSize, sig); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done2; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) goto done2; } offset = 0; Trspi_LoadBlob_SIGN_INFO(&offset, NULL, &signInfo); signInfoBlobSize = offset; signInfoBlob = malloc(signInfoBlobSize); if (signInfoBlob == NULL) { LogError("malloc of %u bytes failed.", signInfoBlobSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done2; } offset = 0; Trspi_LoadBlob_SIGN_INFO(&offset, signInfoBlob, &signInfo); if (pValidationData == NULL) { if ((result = Trspi_Hash(TSS_HASH_SHA1, signInfoBlobSize, signInfoBlob, digest.digest))) goto done2; if ((result = __tspi_rsa_verify(hKey, TSS_HASH_SHA1, sizeof(digest.digest), digest.digest, sigSize, sig))) { result = TSPERR(TSS_E_VERIFICATION_FAILED); goto done2; } } else { pValidationData->ulDataLength = signInfoBlobSize; pValidationData->rgbData = calloc_tspi(tspContext, signInfoBlobSize); if (pValidationData->rgbData == NULL) { LogError("malloc of %u bytes failed.", signInfoBlobSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done2; } memcpy(pValidationData->rgbData, signInfoBlob, signInfoBlobSize); pValidationData->ulValidationDataLength = sigSize; pValidationData->rgbValidationData = calloc_tspi(tspContext, sigSize); if (pValidationData->rgbValidationData == NULL) { LogError("malloc of %u bytes failed.", sigSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done2; } memcpy(pValidationData->rgbValidationData, sig, sigSize); } *pulAuditDigestSize = sizeof(auditDigest.digest); if ((*prgbAuditDigest = calloc_tspi(tspContext, *pulAuditDigestSize)) == NULL) { LogError("malloc of %u bytes failed.", *pulAuditDigestSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done2; } offset = 0; Trspi_LoadBlob_DIGEST(&offset, *prgbAuditDigest, &auditDigest); offset = 0; Trspi_UnloadBlob_COUNTER_VALUE(&offset, counterValue, pCounterValue); result = TSS_SUCCESS; done2: if (result != TSS_SUCCESS) { if (*prgbAuditDigest) free_tspi(tspContext, *prgbAuditDigest); *prgbAuditDigest = NULL; *pulAuditDigestSize = 0; if (pValidationData != NULL) { if (pValidationData->rgbData) free_tspi(tspContext, pValidationData->rgbData); if (pValidationData->rgbValidationData) free_tspi(tspContext, pValidationData->rgbValidationData); pValidationData->ulDataLength = 0; pValidationData->rgbData = NULL; pValidationData->ulValidationDataLength = 0; pValidationData->rgbValidationData = NULL; } } free(counterValue); free(sig); free(signInfo.data); free(signInfoBlob); return result; } } trousers-0.3.15/src/tspi/tspi_counter.c0000664000175000017510000000176013663651711017410 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_ReadCounter(TSS_HTPM hTPM, /* in */ UINT32* counterValue) /* out */ { TSS_HCONTEXT tspContext; TCPA_RESULT result; TSS_COUNTER_ID counterID; TPM_COUNTER_VALUE counter_value; if (counterValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_tpm_get_current_counter(hTPM, &counterID))) return result; if ((result = TCS_API(tspContext)->ReadCounter(tspContext, counterID, &counter_value))) return result; *counterValue = counter_value.counter; return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_own.c0000664000175000017510000001276713663651711016374 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT secret_TakeOwnership(TSS_HKEY hEndorsementPubKey, TSS_HTPM hTPM, TSS_HKEY hKeySRK, TPM_AUTH * auth, UINT32 * encOwnerAuthLength, BYTE * encOwnerAuth, UINT32 * encSRKAuthLength, BYTE * encSRKAuth) { TSS_RESULT result; UINT32 endorsementKeySize; BYTE *endorsementKey; TSS_KEY dummyKey; UINT64 offset; TCPA_SECRET ownerSecret; TCPA_SECRET srkSecret; TCPA_DIGEST digest; TSS_HPOLICY hSrkPolicy; TSS_HPOLICY hOwnerPolicy; UINT32 srkKeyBlobLength; BYTE *srkKeyBlob; TSS_HCONTEXT tspContext; UINT32 ownerMode, srkMode; Trspi_HashCtx hashCtx; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; /************************************************* * First, get the policy objects and check them for how * to handle the secrets. If they cannot be found * or there is an error, then we must fail **************************************************/ /* First get the Owner Policy */ if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hOwnerPolicy))) return result; /* Now get the SRK Policy */ if ((result = obj_rsakey_get_policy(hKeySRK, TSS_POLICY_USAGE, &hSrkPolicy, NULL))) return result; if ((result = obj_policy_get_mode(hOwnerPolicy, &ownerMode))) return result; if ((result = obj_policy_get_mode(hSrkPolicy, &srkMode))) return result; /* If the policy callback's aren't the same, that's an error if one is callback */ if (srkMode == TSS_SECRET_MODE_CALLBACK || ownerMode == TSS_SECRET_MODE_CALLBACK) { if (srkMode != TSS_SECRET_MODE_CALLBACK || ownerMode != TSS_SECRET_MODE_CALLBACK) { LogError("Policy callback modes for SRK policy and Owner policy differ."); return TSPERR(TSS_E_BAD_PARAMETER); } } if (ownerMode != TSS_SECRET_MODE_CALLBACK) { /* First, get the Endorsement Public Key for Encrypting */ if ((result = obj_rsakey_get_blob(hEndorsementPubKey, &endorsementKeySize, &endorsementKey))) return result; /* now stick it in a Key Structure */ offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, endorsementKey, &dummyKey))) { free_tspi(tspContext, endorsementKey); return result; } free_tspi(tspContext, endorsementKey); if ((result = obj_policy_get_secret(hOwnerPolicy, TR_SECRET_CTX_NEW, &ownerSecret))) { free(dummyKey.pubKey.key); free(dummyKey.algorithmParms.parms); return result; } if ((result = obj_policy_get_secret(hSrkPolicy, TR_SECRET_CTX_NEW, &srkSecret))) { free(dummyKey.pubKey.key); free(dummyKey.algorithmParms.parms); return result; } /* Encrypt the Owner, SRK Authorizations */ if ((result = Trspi_RSA_Encrypt(ownerSecret.authdata, 20, encOwnerAuth, encOwnerAuthLength, dummyKey.pubKey.key, dummyKey.pubKey.keyLength))) { free(dummyKey.pubKey.key); free(dummyKey.algorithmParms.parms); return result; } if ((result = Trspi_RSA_Encrypt(srkSecret.authdata, 20, encSRKAuth, encSRKAuthLength, dummyKey.pubKey.key, dummyKey.pubKey.keyLength))) { free(dummyKey.pubKey.key); free(dummyKey.algorithmParms.parms); return result; } free(dummyKey.pubKey.key); free(dummyKey.algorithmParms.parms); } else { *encOwnerAuthLength = 256; *encSRKAuthLength = 256; if ((result = obj_policy_do_takeowner(hOwnerPolicy, hTPM, hEndorsementPubKey, *encOwnerAuthLength, encOwnerAuth))) return result; } if ((result = obj_rsakey_get_blob(hKeySRK, &srkKeyBlobLength, &srkKeyBlob))) return result; /* Authorizatin Digest Calculation */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_TakeOwnership); result |= Trspi_Hash_UINT16(&hashCtx, TCPA_PID_OWNER); result |= Trspi_Hash_UINT32(&hashCtx, *encOwnerAuthLength); result |= Trspi_HashUpdate(&hashCtx, *encOwnerAuthLength, encOwnerAuth); result |= Trspi_Hash_UINT32(&hashCtx, *encSRKAuthLength); result |= Trspi_HashUpdate(&hashCtx, *encSRKAuthLength, encSRKAuth); result |= Trspi_HashUpdate(&hashCtx, srkKeyBlobLength, srkKeyBlob); free_tspi(tspContext, srkKeyBlob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; /* HMAC for the final digest */ if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_TakeOwnership, hOwnerPolicy, FALSE, &digest, auth))) return result; return TSS_SUCCESS; } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_OwnerClear(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); return obj_context_transport_execute(tspContext, TPM_ORD_OwnerClear, 0, NULL, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); } TSS_RESULT Transport_ForceClear(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); return obj_context_transport_execute(tspContext, TPM_ORD_ForceClear, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); } #endif trousers-0.3.15/src/tspi/tspi_changeauth.c0000664000175000017510000003104413663651711020036 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "authsess.h" TSS_RESULT Tspi_ChangeAuth(TSS_HOBJECT hObjectToChange, /* in */ TSS_HOBJECT hParentObject, /* in */ TSS_HPOLICY hNewPolicy) /* in */ { UINT32 keyToChangeHandle; TSS_RESULT result; TSS_HCONTEXT tspContext; if ((result = obj_policy_get_tsp_context(hNewPolicy, &tspContext))) return result; /* if the object to change is the TPM object, then the parent should * be NULL. If the object to change is not the TPM, then the parent * object must be either an rsakey or the TPM */ if (obj_is_tpm(hObjectToChange)) { if (hParentObject != NULL_HOBJECT) return TSPERR(TSS_E_BAD_PARAMETER); } else if (!obj_is_rsakey(hParentObject) && !obj_is_tpm(hParentObject)) { return TSPERR(TSS_E_INVALID_HANDLE); } if (obj_is_tpm(hObjectToChange)) { if ((result = changeauth_owner(tspContext, hObjectToChange, NULL_HTPM, hNewPolicy))) return result; } else if (obj_is_rsakey(hObjectToChange)) { if ((result = obj_rsakey_get_tcs_handle(hObjectToChange, &keyToChangeHandle))) return result; if (keyToChangeHandle == TPM_KEYHND_SRK) { if ((result = changeauth_srk(tspContext, hObjectToChange, hParentObject, hNewPolicy))) return result; } else { if ((result = changeauth_key(tspContext, hObjectToChange, hParentObject, hNewPolicy))) return result; } } else if (obj_is_encdata(hObjectToChange)) { if ((result = changeauth_encdata(tspContext, hObjectToChange, hParentObject, hNewPolicy))) return result; } else if (obj_is_policy(hObjectToChange) || obj_is_hash(hObjectToChange) || obj_is_pcrs(hObjectToChange) || obj_is_context(hObjectToChange)) { return TSPERR(TSS_E_BAD_PARAMETER); } else { return TSPERR(TSS_E_INVALID_HANDLE); } if ((result = obj_policy_set_type(hNewPolicy, TSS_POLICY_USAGE))) return result; return Tspi_Policy_AssignToObject(hNewPolicy, hObjectToChange); } TSS_RESULT Tspi_ChangeAuthAsym(TSS_HOBJECT hObjectToChange, /* in */ TSS_HOBJECT hParentObject, /* in */ TSS_HKEY hIdentKey, /* in */ TSS_HPOLICY hNewPolicy) /* in */ { #if 0 TPM_AUTH auth; UINT64 offset; BYTE hashBlob[0x1000]; TCPA_DIGEST digest; TCPA_RESULT result; UINT32 keyHandle; UINT32 idHandle; TSS_HPOLICY hPolicy; TSS_HPOLICY hParentPolicy; UINT32 keyToChangeHandle; TCPA_NONCE antiReplay; UINT32 bytesRequested; UINT64 tempSize; BYTE tempKey[512]; TCPA_KEY_PARMS keyParms; /* XXX Wow... */ BYTE ephParms[] = { 0, 0, 0x08, 0, 0, 0, 0, 0x02, 0, 0, 0, 0 }; UINT32 KeySizeOut; BYTE *KeyDataOut; UINT32 CertifyInfoSize; BYTE *CertifyInfo; UINT32 sigSize; BYTE *sig; UINT32 ephHandle; TPM_CHANGEAUTH_VALIDATE caValidate; TCPA_SECRET newSecret, oldSecret; BYTE seed[20]; BYTE a1[256]; UINT32 a1Size; TSS_KEY ephemeralKey; TCPA_DIGEST newAuthLink; UINT32 encObjectSize; BYTE *encObject = NULL; UINT32 encDataSizeOut; BYTE *encDataOut; TCPA_NONCE saltNonce; TCPA_DIGEST changeProof; TSS_HPOLICY hOldPolicy; UINT32 caValidSize; UINT32 keyObjectSize; BYTE *keyObject; TSS_KEY keyContainer; TCPA_STORED_DATA dataContainer; BYTE *dataObject; UINT32 dataObjectSize; UINT16 entityType; TSS_BOOL useAuth = TRUE; // XXX TPM_AUTH *pAuth; BYTE dataBlob[1024]; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; if ((result = obj_policy_get_tsp_context(hNewPolicy, &tspContext))) return result; /* grab all of the needed handles */ if ((result = obj_rsakey_get_tcs_handle(hIdentKey, &idHandle))) return result; /* get the secret for the parent */ if ((result = obj_rsakey_get_policy(hIdentKey, TSS_POLICY_USAGE, &hPolicy, &useAuth))) return result; /* get the parent secret */ if ((result = Tspi_GetPolicyObject(hParentObject, TSS_POLICY_USAGE, &hParentPolicy))) return result; if (!obj_is_rsakey(hParentObject) && !obj_is_tpm(hParentObject)) return TSPERR(TSS_E_INVALID_HANDLE); /* get the keyObject */ if ((result = obj_rsakey_get_tcs_handle(hParentObject, &keyHandle))) return result; if (obj_is_rsakey(hObjectToChange) || obj_is_encdata(hObjectToChange)) { if ((result = obj_rsakey_get_tcs_handle(hObjectToChange, &keyToChangeHandle))) return result; if (keyToChangeHandle == TPM_KEYHND_SRK) { return TSPERR(TSS_E_BAD_PARAMETER); } else { /* generate container for ephemeral key */ keyParms.algorithmID = 1; /* rsa */ keyParms.encScheme = 3; keyParms.sigScheme = 1; keyParms.parmSize = 12; keyParms.parms = malloc(12); if (keyParms.parms == NULL) { LogError("malloc of %d bytes failed.", 12); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(keyParms.parms, ephParms, 12); tempSize = 0; Trspi_LoadBlob_KEY_PARMS(&tempSize, tempKey, &keyParms); /* generate antireplay nonce */ bytesRequested = 20; if ((result = get_local_random(tspContext, FALSE, bytesRequested, (BYTE **)antiReplay.nonce))) return result; /* caluculate auth data */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthAsymStart); result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, antiReplay.nonce); result |= Trspi_Hash_KEY_PARMS(&hashCtx, &keyParms); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (useAuth) { if ((result = secret_PerformAuth_OIAP(hIdentKey, TPM_ORD_ChangeAuthAsymStart, hPolicy, FALSE, &digest, &auth))) return result; pAuth = &auth; } else { pAuth = NULL; } if ((result = TCSP_ChangeAuthAsymStart(tspContext, idHandle, antiReplay, tempSize, tempKey, pAuth, &KeySizeOut, &KeyDataOut, &CertifyInfoSize, &CertifyInfo, &sigSize, &sig, &ephHandle))) return result; /* Validate the Auth's */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthAsymStart); result |= Trspi_HashUpdate(&hashCtx, CertifyInfoSize, CertifyInfo); result |= Trspi_Hash_UINT32(&hashCtx, sigSize); result |= Trspi_HashUpdate(&hashCtx, sigSize, sig); result |= Trspi_Hash_UINT32(&hashCtx, ephHandle); result |= Trspi_HashUpdate(&hashCtx, KeySizeOut, KeyDataOut); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (useAuth) { if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) return result; } /* generate random data for asymfinish */ if ((result = get_local_random(tspContext, FALSE, bytesRequested, (BYTE **)&caValidate.n1.nonce))) return result; if ((result = get_local_random(tspContext, FALSE, bytesRequested, (BYTE **)&antiReplay.nonce))) return result; if ((result = get_local_random(tspContext, FALSE, bytesRequested, (BYTE **)&seed))) return result; if ((result = Tspi_GetPolicyObject(hObjectToChange, TSS_POLICY_USAGE, &hOldPolicy))) return result; if ((result = obj_policy_get_secret(hNewPolicy, TR_SECRET_CTX_NEW, &newSecret))) return result; if ((result = obj_policy_get_secret(hOldPolicy, TR_SECRET_CTX_NOT_NEW, &oldSecret))) return result; /* Encrypt the ChangeAuthValidate structure with the * ephemeral key */ memcpy(caValidate.newAuthSecret.authdata, newSecret.authdata, 20); offset = 0; Trspi_LoadBlob_CHANGEAUTH_VALIDATE(&offset, hashBlob, &caValidate); caValidSize = offset; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, KeyDataOut, &ephemeralKey))) return result; Trspi_RSA_Encrypt(hashBlob, caValidSize, a1, &a1Size, ephemeralKey.pubKey.key, ephemeralKey.pubKey.keyLength); free_key_refs(&ephemeralKey); Trspi_HMAC(TSS_HASH_SHA1, 20, oldSecret.authdata, 20, newSecret.authdata, newAuthLink.digest); if (obj_is_rsakey(hObjectToChange)) { if ((result = obj_rsakey_get_blob(hObjectToChange, &keyObjectSize, &keyObject))) return result; __tspi_memset(&keyContainer, 0, sizeof(TSS_KEY)); offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, keyObject, &keyContainer))) return result; encObjectSize = keyContainer.encSize; encObject = malloc(encObjectSize); if (encObject == NULL) { LogError("malloc of %d bytes failed.", encObjectSize); free_key_refs(&keyContainer); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(encObject, keyContainer.encData, encObjectSize); entityType = TCPA_ET_KEY; } else { if ((result = obj_encdata_get_data(hObjectToChange, &dataObjectSize, &dataObject))) return result; offset = 0; if ((result = Trspi_UnloadBlob_STORED_DATA(&offset, dataObject, &dataContainer))) return result; encObjectSize = dataContainer.encDataSize; encObject = malloc(encObjectSize); if (encObject == NULL) { LogError("malloc of %d bytes failed.", encObjectSize); free(dataContainer.sealInfo); free(dataContainer.encData); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(encObject, dataContainer.encData, encObjectSize); entityType = TCPA_ET_DATA; } result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthAsymFinish); result |= Trspi_Hash_UINT16(&hashCtx, entityType); result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, newAuthLink.digest); result |= Trspi_Hash_UINT32(&hashCtx, a1Size); result |= Trspi_HashUpdate(&hashCtx, a1Size, a1); result |= Trspi_Hash_UINT32(&hashCtx, encObjectSize); result |= Trspi_HashUpdate(&hashCtx, encObjectSize, encObject); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (useAuth) { if ((result = secret_PerformAuth_OIAP(hParentObject, TPM_ORD_ChangeAuthAsymFinish, hParentPolicy, FALSE, &digest, &auth))) { free(encObject); free_key_refs(&keyContainer); return result; } pAuth = &auth; } else { pAuth = NULL; } if ((result = TCSP_ChangeAuthAsymFinish(tspContext, keyHandle, ephHandle, entityType, newAuthLink, a1Size, a1, encObjectSize, encObject, pAuth, &encDataSizeOut, &encDataOut, &saltNonce, &changeProof))) { free_key_refs(&keyContainer); free(encObject); return result; } /* --- Validate the Auth's */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthAsymFinish); result |= Trspi_Hash_UINT32(&hashCtx, encDataSizeOut); result |= Trspi_HashUpdate(&hashCtx, encDataSizeOut, encDataOut); result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, saltNonce.nonce); result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, changeProof.digest); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (useAuth) { if ((result = obj_policy_validate_auth_oiap(hParentPolicy, &digest, &auth))) { free_key_refs(&keyContainer); free(encObject); return result; } } if (entityType == TCPA_ET_KEY || entityType == TCPA_ET_KEYHANDLE) { memcpy(keyContainer.encData, encDataOut, encDataSizeOut); keyContainer.encSize = encDataSizeOut; offset = 0; LoadBlob_TSS_KEY(&offset, keyObject, &keyContainer); free_key_refs(&keyContainer); if ((result = obj_rsakey_set_tcpakey(hObjectToChange, offset, keyObject))) { free(encObject); return result; } } if (entityType == TCPA_ET_DATA) { memcpy(dataContainer.encData, encDataOut, encDataSizeOut); dataContainer.encDataSize = encDataSizeOut; offset = 0; Trspi_LoadBlob_STORED_DATA(&offset, dataBlob, &dataContainer); free(dataContainer.sealInfo); free(dataContainer.encData); obj_encdata_set_data(hObjectToChange, offset, dataBlob); } } } else return TSPERR(TSS_E_BAD_PARAMETER); free(encObject); return Tspi_Policy_AssignToObject(hNewPolicy, hObjectToChange); #else return TSPERR(TSS_E_NOTIMPL); #endif } trousers-0.3.15/src/tspi/tspi_cmk.c0000664000175000017510000003445313663651711016510 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "obj.h" #include "tsplog.h" TSS_RESULT Tspi_TPM_CMKSetRestrictions(TSS_HTPM hTpm, /* in */ TSS_CMK_DELEGATE CmkDelegate) /* in */ { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_AUTH ownerAuth; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((result = obj_tpm_get_policy(hTpm, TSS_POLICY_USAGE, &hPolicy))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_SetRestrictions); result |= Trspi_Hash_UINT32(&hashCtx, CmkDelegate); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTpm, TPM_ORD_CMK_SetRestrictions, hPolicy, FALSE, &digest, &ownerAuth))) return result; if ((result = RPC_CMK_SetRestrictions(hContext, CmkDelegate, &ownerAuth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_SetRestrictions); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth))) return result; return result; } TSS_RESULT Tspi_TPM_CMKApproveMA(TSS_HTPM hTpm, /* in */ TSS_HMIGDATA hMaAuthData) /* in */ { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; UINT32 blobSize; BYTE *blob; TPM_DIGEST msaDigest; TPM_HMAC msaHmac; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_AUTH ownerAuth; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((result = obj_tpm_get_policy(hTpm, TSS_POLICY_USAGE, &hPolicy))) return result; if ((result = obj_migdata_get_msa_digest(hMaAuthData, &blobSize, &blob))) return result; memcpy(msaDigest.digest, blob, sizeof(msaDigest.digest)); free_tspi(hContext, blob); result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_ApproveMA); result |= Trspi_Hash_DIGEST(&hashCtx, msaDigest.digest); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTpm, TPM_ORD_CMK_ApproveMA, hPolicy, FALSE, &digest, &ownerAuth))) return result; if ((result = RPC_CMK_ApproveMA(hContext, msaDigest, &ownerAuth, &msaHmac))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_ApproveMA); result |= Trspi_Hash_HMAC(&hashCtx, msaHmac.digest); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth))) return result; if ((result = obj_migdata_set_msa_hmac(hMaAuthData, sizeof(msaHmac.digest), msaHmac.digest))) return result; return result; } TSS_RESULT Tspi_TPM_CMKCreateTicket(TSS_HTPM hTpm, /* in */ TSS_HKEY hVerifyKey, /* in */ TSS_HMIGDATA hSigData) /* in */ { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; UINT32 pubKeySize; BYTE *pubKey = NULL; UINT32 blobSize; BYTE *blob; TPM_DIGEST sigData; UINT32 sigSize; BYTE *sig = NULL; TPM_HMAC sigTicket; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_AUTH ownerAuth; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((result = obj_tpm_get_policy(hTpm, TSS_POLICY_USAGE, &hPolicy))) return result; if ((result = obj_rsakey_get_pub_blob(hVerifyKey, &pubKeySize, &pubKey))) return result; if ((result = obj_migdata_get_sig_data(hSigData, &blobSize, &blob))) goto done; memcpy(sigData.digest, blob, sizeof(sigData.digest)); free_tspi(hContext, blob); if ((result = obj_migdata_get_sig_value(hSigData, &sigSize, &sig))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_CreateTicket); result |= Trspi_HashUpdate(&hashCtx, pubKeySize, pubKey); result |= Trspi_Hash_DIGEST(&hashCtx, sigData.digest); result |= Trspi_Hash_UINT32(&hashCtx, sigSize); result |= Trspi_HashUpdate(&hashCtx, sigSize, sig); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = secret_PerformAuth_OIAP(hTpm, TPM_ORD_CMK_CreateTicket, hPolicy, FALSE, &digest, &ownerAuth))) goto done; if ((result = RPC_CMK_CreateTicket(hContext, pubKeySize, pubKey, sigData, sigSize, sig, &ownerAuth, &sigTicket))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_CreateTicket); result |= Trspi_Hash_HMAC(&hashCtx, sigTicket.digest); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth))) goto done; if ((result = obj_migdata_set_sig_ticket(hSigData, sizeof(sigTicket.digest), sigTicket.digest))) goto done; done: free_tspi(hContext, pubKey); free_tspi(hContext, sig); return result; } TSS_RESULT Tspi_Key_CMKCreateBlob(TSS_HKEY hKeyToMigrate, /* in */ TSS_HKEY hParentKey, /* in */ TSS_HMIGDATA hMigrationData, /* in */ UINT32* pulRandomLength, /* out */ BYTE** prgbRandom) /* out */ { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; TSS_BOOL usageAuth; TCS_KEY_HANDLE tcsKeyHandle; TSS_MIGRATE_SCHEME migScheme; UINT32 migTicketSize; BYTE *migTicket = NULL; TPM_MIGRATIONKEYAUTH tpmMigKeyAuth; UINT32 msaListSize, restrictTicketSize, sigTicketSize, blobSize; BYTE *msaList = NULL, *restrictTicket = NULL, *blob = NULL; BYTE *sigTicket = NULL; UINT32 pubBlobSize; BYTE *pubBlob = NULL; TPM_DIGEST srcPubKeyDigest; TSS_KEY tssKey; UINT32 randomDataSize, outDataSize, newBlobSize; BYTE *randomData = NULL, *outData = NULL, *newBlob = NULL; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_AUTH parentAuth, *pAuth; UINT64 offset; TSS_RESULT result; __tspi_memset(&tssKey, 0, sizeof(tssKey)); if (!pulRandomLength || !prgbRandom) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_rsakey_is_cmk(hKeyToMigrate)) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_rsakey_get_tsp_context(hKeyToMigrate, &hContext))) return result; if ((result = obj_rsakey_get_policy(hParentKey, TSS_POLICY_USAGE, &hPolicy, &usageAuth))) return result; if ((result = obj_rsakey_get_tcs_handle(hParentKey, &tcsKeyHandle))) return result; if ((result = obj_migdata_get_ticket_blob(hMigrationData, &migTicketSize, &migTicket))) return result; /* Just to get the migration scheme... */ offset = 0; if ((result = Trspi_UnloadBlob_MIGRATIONKEYAUTH(&offset, migTicket, &tpmMigKeyAuth))) goto done; /* ... so free everything now */ free(tpmMigKeyAuth.migrationKey.algorithmParms.parms); free(tpmMigKeyAuth.migrationKey.pubKey.key); migScheme = tpmMigKeyAuth.migrationScheme; if ((result = obj_rsakey_get_pub_blob(hKeyToMigrate, &pubBlobSize, &pubBlob))) goto done; if ((result = obj_migdata_calc_pubkey_digest(pubBlobSize, pubBlob, &srcPubKeyDigest))) goto done; if ((result = obj_migdata_get_msa_list_blob(hMigrationData, &msaListSize, &msaList))) goto done; if (tpmMigKeyAuth.migrationScheme == TPM_MS_RESTRICT_APPROVE_DOUBLE) { if ((result = obj_migdata_get_cmk_auth_blob(hMigrationData, &restrictTicketSize, &restrictTicket))) goto done; if ((result = obj_migdata_get_sig_ticket(hMigrationData, &sigTicketSize, &sigTicket))) goto done; } else { restrictTicketSize = 0; sigTicketSize = 0; } if ((result = obj_rsakey_get_blob(hKeyToMigrate, &blobSize, &blob))) goto done; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, blob, &tssKey))) goto done; if (usageAuth) { pAuth = &parentAuth; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_CreateBlob); result |= Trspi_Hash_UINT16(&hashCtx, migScheme); result |= Trspi_HashUpdate(&hashCtx, migTicketSize, migTicket); result |= Trspi_Hash_DIGEST(&hashCtx, srcPubKeyDigest.digest); result |= Trspi_Hash_UINT32(&hashCtx, msaListSize); result |= Trspi_HashUpdate(&hashCtx, msaListSize, msaList); result |= Trspi_Hash_UINT32(&hashCtx, restrictTicketSize); result |= Trspi_HashUpdate(&hashCtx, restrictTicketSize, restrictTicket); result |= Trspi_Hash_UINT32(&hashCtx, sigTicketSize); result |= Trspi_HashUpdate(&hashCtx, sigTicketSize, sigTicket); result |= Trspi_Hash_UINT32(&hashCtx, tssKey.encSize); result |= Trspi_HashUpdate(&hashCtx, tssKey.encSize, tssKey.encData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = secret_PerformAuth_OIAP(hParentKey, TPM_ORD_CMK_CreateBlob, hPolicy, FALSE, &digest, pAuth))) goto done; } else pAuth = NULL; if ((result = RPC_CMK_CreateBlob(hContext, tcsKeyHandle, migScheme, migTicketSize, migTicket, srcPubKeyDigest, msaListSize, msaList, restrictTicketSize, restrictTicket, sigTicketSize, sigTicket, tssKey.encSize, tssKey.encData, pAuth, &randomDataSize, &randomData, &outDataSize, &outData))) goto done; if (pAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_CreateBlob); result |= Trspi_Hash_UINT32(&hashCtx, randomDataSize); result |= Trspi_HashUpdate(&hashCtx, randomDataSize, randomData); result |= Trspi_Hash_UINT32(&hashCtx, outDataSize); result |= Trspi_HashUpdate(&hashCtx, outDataSize, outData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; } if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) goto done; /* Create the migdata key blob */ free(tssKey.encData); tssKey.encSize = outDataSize; tssKey.encData = outData; /* Set outData to null since it will now be freed during key ref freeing */ outData = NULL; offset = 0; LoadBlob_TSS_KEY(&offset, NULL, &tssKey); newBlobSize = offset; if ((newBlob = malloc(newBlobSize)) == NULL) { LogError("malloc of %u bytes failed.", newBlobSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; LoadBlob_TSS_KEY(&offset, newBlob, &tssKey); if ((result = obj_migdata_set_blob(hMigrationData, newBlobSize, newBlob))) goto done; if ((*prgbRandom = calloc_tspi(hContext, randomDataSize)) == NULL) { LogError("malloc of %u bytes failed.", randomDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*prgbRandom, randomData, randomDataSize); *pulRandomLength = randomDataSize; done: free_tspi(hContext, migTicket); free_tspi(hContext, pubBlob); free_tspi(hContext, msaList); free_tspi(hContext, restrictTicket); free_tspi(hContext, sigTicket); free_tspi(hContext, blob); free(randomData); free(outData); free(newBlob); free_key_refs(&tssKey); return result; } TSS_RESULT Tspi_Key_CMKConvertMigration(TSS_HKEY hKeyToMigrate, /* in */ TSS_HKEY hParentKey, /* in */ TSS_HMIGDATA hMigrationData, /* in */ UINT32 ulRandomLength, /* in */ BYTE* rgbRandom) /* in */ { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; TSS_BOOL usageAuth; TCS_KEY_HANDLE tcsKeyHandle; TPM_CMK_AUTH restrictTicket; UINT32 blobSize; BYTE *blob; TPM_HMAC sigTicket; UINT32 migDataSize, msaListSize; BYTE *migData = NULL, *msaList = NULL; UINT32 outDataSize; BYTE *outData = NULL; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_AUTH parentAuth, *pAuth; TSS_RESULT result; if ((result = obj_rsakey_get_tsp_context(hKeyToMigrate, &hContext))) return result; if ((result = obj_rsakey_get_policy(hParentKey, TSS_POLICY_USAGE, &hPolicy, &usageAuth))) return result; if ((result = obj_rsakey_get_tcs_handle(hParentKey, &tcsKeyHandle))) return result; if ((result = obj_migdata_get_cmk_auth(hMigrationData, &restrictTicket))) return result; if ((result = obj_migdata_get_sig_ticket(hMigrationData, &blobSize, &blob))) return result; memcpy(sigTicket.digest, blob, sizeof(sigTicket.digest)); free_tspi(hContext, blob); if ((result = obj_migdata_get_blob(hMigrationData, &migDataSize, &migData))) goto done; if ((result = obj_migdata_get_msa_list_blob(hMigrationData, &msaListSize, &msaList))) goto done; if (usageAuth) { pAuth = &parentAuth; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_ConvertMigration); result |= Trspi_HashUpdate(&hashCtx, sizeof(restrictTicket), (BYTE *)&restrictTicket); result |= Trspi_Hash_HMAC(&hashCtx, sigTicket.digest); result |= Trspi_HashUpdate(&hashCtx, migDataSize, migData); result |= Trspi_Hash_UINT32(&hashCtx, msaListSize); result |= Trspi_HashUpdate(&hashCtx, msaListSize, msaList); result |= Trspi_Hash_UINT32(&hashCtx, ulRandomLength); result |= Trspi_HashUpdate(&hashCtx, ulRandomLength, rgbRandom); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = secret_PerformAuth_OIAP(hParentKey, TPM_ORD_CMK_ConvertMigration, hPolicy, FALSE, &digest, pAuth))) goto done; } else pAuth = NULL; if ((result = RPC_CMK_ConvertMigration(hContext, tcsKeyHandle, restrictTicket, sigTicket, migDataSize, migData, msaListSize, msaList, ulRandomLength, rgbRandom, pAuth, &outDataSize, &outData))) goto done; if (pAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CMK_ConvertMigration); result |= Trspi_Hash_UINT32(&hashCtx, outDataSize); result |= Trspi_HashUpdate(&hashCtx, outDataSize, outData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; } if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) goto done; /* Set the key object to the now migrated key */ if ((result = obj_rsakey_set_tcpakey(hKeyToMigrate, migDataSize, migData))) goto done; if ((result = obj_rsakey_set_privkey(hKeyToMigrate, TRUE, outDataSize, outData))) goto done; result = obj_rsakey_set_tcs_handle(hKeyToMigrate, 0); done: free_tspi(hContext, migData); free_tspi(hContext, msaList); free(outData); return result; } trousers-0.3.15/src/tspi/tspi_aik.c0000664000175000017510000004332513663651711016500 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "authsess.h" TSS_RESULT Tspi_TPM_CollateIdentityRequest(TSS_HTPM hTPM, /* in */ TSS_HKEY hKeySRK, /* in */ TSS_HKEY hCAPubKey, /* in */ UINT32 ulIdentityLabelLength, /* in */ BYTE * rgbIdentityLabelData, /* in */ TSS_HKEY hIdentityKey, /* in */ TSS_ALGORITHM_ID algID, /* in */ UINT32 * pulTcpaIdentityReqLength, /* out */ BYTE ** prgbTcpaIdentityReq) /* out */ { #ifdef TSS_BUILD_TRANSPORT UINT32 transport; #endif TPM_AUTH srkAuth; TCPA_RESULT result; UINT64 offset; BYTE hashblob[USHRT_MAX], idReqBlob[USHRT_MAX], testblob[USHRT_MAX]; TCPA_DIGEST digest; TSS_HPOLICY hSRKPolicy, hIDPolicy, hCAPolicy; UINT32 caKeyBlobSize, idKeySize, idPubSize; BYTE *caKeyBlob, *idKey, *newIdKey, *idPub; TSS_KEY caKey; TCPA_CHOSENID_HASH chosenIDHash = { { 0, } }; UINT32 pcIdentityBindingSize; BYTE *prgbIdentityBinding = NULL; UINT32 pcEndorsementCredentialSize; BYTE *prgbEndorsementCredential = NULL; UINT32 pcPlatformCredentialSize; BYTE *prgbPlatformCredential = NULL; UINT32 pcConformanceCredentialSize; BYTE *prgbConformanceCredential = NULL; #define CHOSENID_BLOB_SIZE 2048 BYTE chosenIDBlob[CHOSENID_BLOB_SIZE]; TSS_HCONTEXT tspContext; UINT32 encSymKeySize = 256, tmp; BYTE encSymKey[256], *cb_var; TSS_BOOL usesAuth; TPM_AUTH *pSrkAuth = &srkAuth; TCPA_IDENTITY_REQ rgbTcpaIdentityReq; TCPA_KEY_PARMS symParms, asymParms; TCPA_SYMMETRIC_KEY symKey; int padding; TSS_CALLBACK *cb; Trspi_HashCtx hashCtx; UINT32 tempCredSize; BYTE *tempCred = NULL; struct authsess *xsap = NULL; if (pulTcpaIdentityReqLength == NULL || prgbTcpaIdentityReq == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_tpm_get_cb12(hTPM, TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY, &tmp, &cb_var))) return result; cb = (TSS_CALLBACK *)cb_var; if (cb->callback == NULL) { free_tspi(tspContext, cb); cb = NULL; } /* Get Policies */ if ((result = obj_rsakey_get_policy(hKeySRK, TSS_POLICY_USAGE, &hSRKPolicy, &usesAuth))) return result; if ((result = obj_rsakey_get_policy(hCAPubKey, TSS_POLICY_USAGE, &hCAPolicy, NULL))) return result; if ((result = obj_rsakey_get_policy(hIdentityKey, TSS_POLICY_USAGE, &hIDPolicy, NULL))) return result; /* setup the symmetric key's parms. */ __tspi_memset(&symParms, 0, sizeof(TCPA_KEY_PARMS)); switch (algID) { case TSS_ALG_AES: symParms.algorithmID = TCPA_ALG_AES; symKey.algId = TCPA_ALG_AES; symKey.size = 128/8; break; case TSS_ALG_DES: symParms.algorithmID = TCPA_ALG_DES; symKey.algId = TCPA_ALG_DES; symKey.size = 64/8; break; case TSS_ALG_3DES: symParms.algorithmID = TCPA_ALG_3DES; symKey.algId = TCPA_ALG_3DES; symKey.size = 192/8; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); goto error; break; } /* No symmetric key encryption schemes existed in the 1.1 time frame */ symParms.encScheme = TCPA_ES_NONE; /* get the CA Pubkey's encryption scheme */ if ((result = obj_rsakey_get_es(hCAPubKey, &tmp))) return TSPERR(TSS_E_BAD_PARAMETER); switch (tmp) { case TSS_ES_RSAESPKCSV15: padding = TR_RSA_PKCS1_PADDING; break; case TSS_ES_RSAESOAEP_SHA1_MGF1: padding = TR_RSA_PKCS1_OAEP_PADDING; break; case TSS_ES_NONE: /* fall through */ default: padding = TR_RSA_NO_PADDING; break; } /* Get Key blobs */ if ((result = obj_rsakey_get_blob(hIdentityKey, &idKeySize, &idKey))) return result; if ((result = obj_rsakey_get_blob(hCAPubKey, &caKeyBlobSize, &caKeyBlob))) return result; offset = 0; __tspi_memset(&caKey, 0, sizeof(TSS_KEY)); if ((result = UnloadBlob_TSS_KEY(&offset, caKeyBlob, &caKey))) return result; /* ChosenID hash = SHA1(label || TCPA_PUBKEY(CApub)) */ offset = 0; Trspi_LoadBlob(&offset, ulIdentityLabelLength, chosenIDBlob, rgbIdentityLabelData); Trspi_LoadBlob_KEY_PARMS(&offset, chosenIDBlob, &caKey.algorithmParms); Trspi_LoadBlob_STORE_PUBKEY(&offset, chosenIDBlob, &caKey.pubKey); if (offset > CHOSENID_BLOB_SIZE) return TSPERR(TSS_E_INTERNAL_ERROR); if ((result = Trspi_Hash(TSS_HASH_SHA1, offset, chosenIDBlob, chosenIDHash.digest))) { free_key_refs(&caKey); return result; } /* use chosenIDBlob temporarily */ offset = 0; Trspi_LoadBlob_KEY_PARMS(&offset, chosenIDBlob, &caKey.algorithmParms); offset = 0; if ((result = Trspi_UnloadBlob_KEY_PARMS(&offset, chosenIDBlob, &asymParms))) return result; if ((result = authsess_xsap_init(tspContext, hTPM, hIdentityKey, TSS_AUTH_POLICY_REQUIRED, TPM_ORD_MakeIdentity, TPM_ET_OWNER, &xsap))){ free(asymParms.parms); return result; } /* Hash the Auth data */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_MakeIdentity); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, chosenIDHash.digest); result |= Trspi_HashUpdate(&hashCtx, idKeySize, idKey); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; /* Do the Auth's */ if (usesAuth) { if ((result = secret_PerformAuth_OIAP(hKeySRK, TPM_ORD_MakeIdentity, hSRKPolicy, FALSE, &digest, &srkAuth))) goto error; pSrkAuth = &srkAuth; } else { pSrkAuth = NULL; } if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; #ifdef TSS_BUILD_TRANSPORT if ((result = obj_context_transport_get_control(tspContext, TSS_TSPATTRIB_ENABLE_TRANSPORT, &transport))) goto error; if (transport) { if ((result = Transport_MakeIdentity2(tspContext, xsap->encAuthUse, chosenIDHash, idKeySize, idKey, pSrkAuth, xsap->pAuth, &idKeySize, &newIdKey, &pcIdentityBindingSize, &prgbIdentityBinding))) goto error; } else { #endif if ((result = RPC_MakeIdentity(tspContext, xsap->encAuthUse, chosenIDHash, idKeySize, idKey, pSrkAuth, xsap->pAuth, &idKeySize, &newIdKey, &pcIdentityBindingSize, &prgbIdentityBinding, &pcEndorsementCredentialSize, &prgbEndorsementCredential, &pcPlatformCredentialSize, &prgbPlatformCredential, &pcConformanceCredentialSize, &prgbConformanceCredential))) goto error; #ifdef TSS_BUILD_TRANSPORT } #endif result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_MakeIdentity); result |= Trspi_HashUpdate(&hashCtx, idKeySize, newIdKey); result |= Trspi_Hash_UINT32(&hashCtx, pcIdentityBindingSize); result |= Trspi_HashUpdate(&hashCtx, pcIdentityBindingSize, prgbIdentityBinding); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free(newIdKey); goto error; } if ((result = authsess_xsap_verify(xsap, &digest))) { free(newIdKey); goto error; } if (usesAuth == TRUE) { if ((result = obj_policy_validate_auth_oiap(hSRKPolicy, &digest, &srkAuth))) { free(newIdKey); goto error; } } if ((result = obj_rsakey_set_tcpakey(hIdentityKey, idKeySize, newIdKey))) { free(newIdKey); goto error; } free(newIdKey); if ((result = obj_rsakey_set_tcs_handle(hIdentityKey, 0))) goto error; if ((result = obj_rsakey_get_pub_blob(hIdentityKey, &idPubSize, &idPub))) goto error; if ((result = obj_tpm_get_cred(hTPM, TSS_TPMATTRIB_EKCERT, &tempCredSize, &tempCred))) goto error; if (tempCred != NULL) { free(prgbEndorsementCredential); prgbEndorsementCredential = tempCred; pcEndorsementCredentialSize = tempCredSize; } if ((result = obj_tpm_get_cred(hTPM, TSS_TPMATTRIB_TPM_CC, &tempCredSize, &tempCred))) goto error; if (tempCred != NULL) { free(prgbConformanceCredential); prgbConformanceCredential = tempCred; pcConformanceCredentialSize = tempCredSize; } if ((result = obj_tpm_get_cred(hTPM, TSS_TPMATTRIB_PLATFORMCERT, &tempCredSize, &tempCred))) goto error; if (tempCred != NULL) { free(prgbPlatformCredential); prgbPlatformCredential = tempCred; pcPlatformCredentialSize = tempCredSize; } /* set up the TCPA_IDENTITY_PROOF structure */ /* XXX This should be DER encoded first. TPM1.1b section 9.4 */ /* XXX hash this incrementally using a Trspi_HashCtx */ offset = 0; Trspi_LoadBlob_TSS_VERSION(&offset, hashblob, VERSION_1_1); Trspi_LoadBlob_UINT32(&offset, ulIdentityLabelLength, hashblob); Trspi_LoadBlob_UINT32(&offset, pcIdentityBindingSize, hashblob); Trspi_LoadBlob_UINT32(&offset, pcEndorsementCredentialSize, hashblob); Trspi_LoadBlob_UINT32(&offset, pcPlatformCredentialSize, hashblob); Trspi_LoadBlob_UINT32(&offset, pcConformanceCredentialSize, hashblob); Trspi_LoadBlob(&offset, idPubSize, hashblob, idPub); free_tspi(tspContext, idPub); Trspi_LoadBlob(&offset, ulIdentityLabelLength, hashblob, rgbIdentityLabelData); Trspi_LoadBlob(&offset, pcIdentityBindingSize, hashblob, prgbIdentityBinding); Trspi_LoadBlob(&offset, pcEndorsementCredentialSize, hashblob, prgbEndorsementCredential); Trspi_LoadBlob(&offset, pcPlatformCredentialSize, hashblob, prgbPlatformCredential); Trspi_LoadBlob(&offset, pcConformanceCredentialSize, hashblob, prgbConformanceCredential); if (cb && cb->callback) { /* Alloc the space for the callback to copy into. The additional 32 bytes will * attempt to account for padding that the symmetric encryption will do. */ rgbTcpaIdentityReq.asymBlob = calloc(1, (int)offset + 32); rgbTcpaIdentityReq.symBlob = calloc(1, (int)offset + 32); if (rgbTcpaIdentityReq.asymBlob == NULL || rgbTcpaIdentityReq.symBlob == NULL) { free(rgbTcpaIdentityReq.asymBlob); free(rgbTcpaIdentityReq.symBlob); LogError("malloc of %" PRIu64 " bytes failed", offset); free_tspi(tspContext, cb); result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } rgbTcpaIdentityReq.asymSize = (UINT32)offset + 32; rgbTcpaIdentityReq.symSize = (UINT32)offset + 32; if ((result = ((TSS_RESULT (*)(PVOID, UINT32, BYTE *, UINT32, UINT32 *, BYTE *, UINT32 *, BYTE *))cb->callback)(cb->appData, (UINT32)offset, hashblob, algID, &rgbTcpaIdentityReq.asymSize, rgbTcpaIdentityReq.asymBlob, &rgbTcpaIdentityReq.symSize, rgbTcpaIdentityReq.symBlob))) { LogDebug("CollateIdentityRequest callback returned error 0x%x", result); free_tspi(tspContext, cb); goto error; } } else { /* generate the symmetric key. */ if ((result = get_local_random(tspContext, TRUE, symKey.size, &symKey.data))) goto error; /* No symmetric key encryption schemes existed in the 1.1 time frame */ symKey.encScheme = TCPA_ES_NONE; /* encrypt the proof */ rgbTcpaIdentityReq.symSize = sizeof(testblob); if ((result = Trspi_SymEncrypt(algID, TR_SYM_MODE_CBC, symKey.data, NULL, hashblob, offset, testblob, &rgbTcpaIdentityReq.symSize))) goto error; rgbTcpaIdentityReq.symBlob = testblob; /* XXX This should be DER encoded first. TPM1.1b section 9.4 */ offset = 0; Trspi_LoadBlob_SYMMETRIC_KEY(&offset, hashblob, &symKey); if ((result = Trspi_RSA_Public_Encrypt(hashblob, offset, encSymKey, &encSymKeySize, caKey.pubKey.key, caKey.pubKey.keyLength, 65537, padding))) goto error; rgbTcpaIdentityReq.asymSize = encSymKeySize; rgbTcpaIdentityReq.asymBlob = encSymKey; } rgbTcpaIdentityReq.asymAlgorithm = asymParms; rgbTcpaIdentityReq.symAlgorithm = symParms; /* XXX This should be DER encoded first. TPM1.1b section 9.4 */ offset = 0; Trspi_LoadBlob_IDENTITY_REQ(&offset, idReqBlob, &rgbTcpaIdentityReq); if (cb && cb->callback) { free(rgbTcpaIdentityReq.symBlob); free(rgbTcpaIdentityReq.asymBlob); free_tspi(tspContext, cb); } if ((*prgbTcpaIdentityReq = calloc_tspi(tspContext, offset)) == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } memcpy(*prgbTcpaIdentityReq, idReqBlob, offset); *pulTcpaIdentityReqLength = offset; error: authsess_free(xsap); free_key_refs(&caKey); free(asymParms.parms); free(prgbIdentityBinding); free(prgbEndorsementCredential); free(prgbPlatformCredential); free(prgbConformanceCredential); return result; } TSS_RESULT Tspi_TPM_ActivateIdentity(TSS_HTPM hTPM, /* in */ TSS_HKEY hIdentKey, /* in */ UINT32 ulAsymCAContentsBlobLength, /* in */ BYTE * rgbAsymCAContentsBlob, /* in */ UINT32 ulSymCAAttestationBlobLength, /* in */ BYTE * rgbSymCAAttestationBlob, /* in */ UINT32 * pulCredentialLength, /* out */ BYTE ** prgbCredential) /* out */ { TPM_AUTH idKeyAuth; TPM_AUTH ownerAuth; TSS_HCONTEXT tspContext; TSS_HPOLICY hIDPolicy, hTPMPolicy; UINT64 offset; BYTE credBlob[0x1000]; TCPA_DIGEST digest; TSS_RESULT result; TCS_KEY_HANDLE tcsKeyHandle; TSS_BOOL usesAuth; TPM_AUTH *pIDKeyAuth; BYTE *symKeyBlob, *credCallback, *cb_var; UINT32 symKeyBlobLen, credLen, tmp; TCPA_SYMMETRIC_KEY symKey; TSS_CALLBACK *cb; Trspi_HashCtx hashCtx; TPM_SYM_CA_ATTESTATION symCAAttestation; if (pulCredentialLength == NULL || prgbCredential == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_tpm_get_cb12(hTPM, TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY, &tmp, &cb_var))) return result; cb = (TSS_CALLBACK *)cb_var; if (cb->callback == NULL) { free_tspi(tspContext, cb); cb = NULL; } if ((result = obj_rsakey_get_tcs_handle(hIdentKey, &tcsKeyHandle))) return result; if ((result = obj_rsakey_get_policy(hIdentKey, TSS_POLICY_USAGE, &hIDPolicy, &usesAuth))) return result; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hTPMPolicy))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ActivateIdentity); result |= Trspi_Hash_UINT32(&hashCtx, ulAsymCAContentsBlobLength); result |= Trspi_HashUpdate(&hashCtx, ulAsymCAContentsBlobLength, rgbAsymCAContentsBlob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (usesAuth) { if ((result = secret_PerformAuth_OIAP(hIDPolicy, TPM_ORD_ActivateIdentity, hIDPolicy, FALSE, &digest, &idKeyAuth))) return result; pIDKeyAuth = &idKeyAuth; } else { pIDKeyAuth = NULL; } if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_ActivateIdentity, hTPMPolicy, FALSE, &digest, &ownerAuth))) return result; if ((result = TCS_API(tspContext)->ActivateTPMIdentity(tspContext, tcsKeyHandle, ulAsymCAContentsBlobLength, rgbAsymCAContentsBlob, pIDKeyAuth, &ownerAuth, &symKeyBlobLen, &symKeyBlob))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ActivateIdentity); result |= Trspi_HashUpdate(&hashCtx, symKeyBlobLen, symKeyBlob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (usesAuth) { if ((result = obj_policy_validate_auth_oiap(hIDPolicy, &digest, &idKeyAuth))) { LogDebugFn("Identity key auth validation of the symmetric key failed."); return result; } } if ((result = obj_policy_validate_auth_oiap(hTPMPolicy, &digest, &ownerAuth))) { LogDebugFn("Owner auth validation of the symmetric key failed."); return result; } offset = 0; if ((result = Trspi_UnloadBlob_SYM_CA_ATTESTATION(&offset, rgbSymCAAttestationBlob, &symCAAttestation))) { LogDebugFn("Error unloading CA's attestation blob."); return result; } if (cb && cb->callback) { /* alloc the space for the callback to copy into */ credCallback = calloc(1, ulSymCAAttestationBlobLength); if (credCallback == NULL) { LogDebug("malloc of %u bytes failed", ulSymCAAttestationBlobLength); free(symKeyBlob); free_tspi(tspContext, cb); return TSPERR(TSS_E_INTERNAL_ERROR); } credLen = ulSymCAAttestationBlobLength; if ((result = ((TSS_RESULT (*)(PVOID, UINT32, BYTE *, UINT32, BYTE *, UINT32 *, BYTE *))cb->callback)(cb->appData, symKeyBlobLen, symKeyBlob, symCAAttestation.credSize, symCAAttestation.credential, &credLen, credCallback))) { LogDebug("ActivateIdentity callback returned error 0x%x", result); free(symCAAttestation.credential); free(symKeyBlob); free_tspi(tspContext, cb); free(credCallback); return TSPERR(TSS_E_INTERNAL_ERROR); } free(symCAAttestation.credential); free_tspi(tspContext, cb); free(symKeyBlob); if ((*prgbCredential = calloc_tspi(tspContext, credLen)) == NULL) { free(credCallback); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(*prgbCredential, credCallback, credLen); *pulCredentialLength = credLen; free(credCallback); return TSS_SUCCESS; } /* decrypt the symmetric blob using the recovered symmetric key */ offset = 0; if ((result = Trspi_UnloadBlob_SYMMETRIC_KEY(&offset, symKeyBlob, &symKey))) { free(symCAAttestation.credential); free(symKeyBlob); return result; } free(symKeyBlob); if ((result = Trspi_SymDecrypt(symKey.algId, symKey.encScheme, symKey.data, NULL, symCAAttestation.credential, symCAAttestation.credSize, credBlob, &credLen))) { free(symCAAttestation.credential); free(symKey.data); return result; } free(symCAAttestation.credential); if ((*prgbCredential = calloc_tspi(tspContext, credLen)) == NULL) { free(symKey.data); return TSPERR(TSS_E_OUTOFMEMORY); } free(symKey.data); memcpy(*prgbCredential, credBlob, credLen); *pulCredentialLength = credLen; return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_own.c0000664000175000017510000001134613663651711016535 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_TakeOwnership(TSS_HTPM hTPM, /* in */ TSS_HKEY hKeySRK, /* in */ TSS_HKEY hEndorsementPubKey) /* in */ { TPM_AUTH privAuth; BYTE encOwnerAuth[256]; UINT32 encOwnerAuthLength; BYTE encSRKAuth[256]; UINT32 encSRKAuthLength; TCPA_DIGEST digest; TSS_RESULT result; TSS_HCONTEXT tspContext; UINT32 srkKeyBlobLength; BYTE *srkKeyBlob; TSS_HPOLICY hOwnerPolicy; UINT32 newSrkBlobSize; BYTE *newSrkBlob = NULL; BYTE oldAuthDataUsage; TSS_HKEY hPubEK; Trspi_HashCtx hashCtx; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (hEndorsementPubKey == NULL_HKEY) { if ((result = Tspi_TPM_GetPubEndorsementKey(hTPM, FALSE, NULL, &hPubEK))) { return result; } } else { hPubEK = hEndorsementPubKey; } /* Get the srkKeyData */ if ((result = obj_rsakey_get_blob(hKeySRK, &srkKeyBlobLength, &srkKeyBlob))) return result; /* Need to check for Atmel bug where authDataUsage is changed */ oldAuthDataUsage = srkKeyBlob[10]; LogDebug("oldAuthDataUsage is %.2X. Wait to see if it changes", oldAuthDataUsage); /* Now call the module that will encrypt the secrets. This * will either get the secrets from the policy objects or * use the callback function to encrypt the secrets */ if ((result = secret_TakeOwnership(hPubEK, hTPM, hKeySRK, &privAuth, &encOwnerAuthLength, encOwnerAuth, &encSRKAuthLength, encSRKAuth))) return result; /* Now, take ownership is ready to call. The auth structure should be complete * and the encrypted data structures should be ready */ if ((result = RPC_TakeOwnership(tspContext, TPM_PID_OWNER, encOwnerAuthLength, encOwnerAuth, encSRKAuthLength, encSRKAuth, srkKeyBlobLength, srkKeyBlob, &privAuth, &newSrkBlobSize, &newSrkBlob))) return result; /* The final step is to validate the return Auth */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_TakeOwnership); result |= Trspi_HashUpdate(&hashCtx, newSrkBlobSize, newSrkBlob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hOwnerPolicy))) { free(newSrkBlob); return result; } if ((result = obj_policy_validate_auth_oiap(hOwnerPolicy, &digest, &privAuth))) { free(newSrkBlob); return result; } /* Now that it's all happy, stuff the keyBlob into the object * If atmel, need to adjust the authDataUsage if it changed */ if (oldAuthDataUsage != newSrkBlob[10]) { /* hardcoded blob stuff */ LogDebug("auth data usage changed. Atmel bug. Fixing in key object"); newSrkBlob[10] = oldAuthDataUsage; /* this will fix it */ } result = obj_rsakey_set_tcpakey(hKeySRK, newSrkBlobSize, newSrkBlob); free(newSrkBlob); if (result) return result; /* The SRK is loaded at this point, so insert it into the key handle list */ return obj_rsakey_set_tcs_handle(hKeySRK, TPM_KEYHND_SRK); } TSS_RESULT Tspi_TPM_ClearOwner(TSS_HTPM hTPM, /* in */ TSS_BOOL fForcedClear) /* in */ { TCPA_RESULT result; TPM_AUTH auth; TSS_HCONTEXT tspContext; TCPA_DIGEST hashDigest; TSS_HPOLICY hPolicy; Trspi_HashCtx hashCtx; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (!fForcedClear) { /* TPM_OwnerClear */ if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy))) return result; /* Now do some Hash'ing */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerClear); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; /* hashDigest now has the hash result */ if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_OwnerClear, hPolicy, FALSE, &hashDigest, &auth))) return result; if ((result = TCS_API(tspContext)->OwnerClear(tspContext, &auth))) return result; /* validate auth */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerClear); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &hashDigest, &auth))) return result; } else { if ((result = TCS_API(tspContext)->ForceClear(tspContext))) return result; } return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_audit.c0000664000175000017510000001610113663651711016661 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #include "obj.h" TSS_RESULT __tspi_audit_set_ordinal_audit_status(TSS_HTPM hTpm, TSS_FLAG flag, TSS_FLAG subFlag, UINT32 ulOrdinal) { TSS_BOOL bAuditState; TSS_HCONTEXT tspContext; TSS_HPOLICY hPolicy; TPM_AUTH ownerAuth; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; TSS_RESULT result = TSS_SUCCESS; if (flag != TSS_TSPATTRIB_TPM_ORDINAL_AUDIT_STATUS) return TSPERR(TSS_E_BAD_PARAMETER); switch (subFlag) { case TPM_CAP_PROP_TPM_SET_ORDINAL_AUDIT: bAuditState = TRUE; break; case TPM_CAP_PROP_TPM_CLEAR_ORDINAL_AUDIT: bAuditState = FALSE; break; default: return TSPERR(TSS_E_BAD_PARAMETER); } if ((result = obj_tpm_get_tsp_context(hTpm, &tspContext))) return result; if ((result = obj_tpm_get_policy(hTpm, TSS_POLICY_USAGE, &hPolicy))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_SetOrdinalAuditStatus); result |= Trspi_Hash_UINT32(&hashCtx, ulOrdinal); result |= Trspi_Hash_BOOL(&hashCtx, bAuditState); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTpm, TPM_ORD_SetOrdinalAuditStatus, hPolicy, FALSE, &digest, &ownerAuth))) return result; if ((result = TCS_API(tspContext)->SetOrdinalAuditStatus(tspContext, &ownerAuth, ulOrdinal, bAuditState))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_SetOrdinalAuditStatus); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; return obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth); } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_SetOrdinalAuditStatus(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH *ownerAuth, /* in/out */ UINT32 ulOrdinal, /* in */ TSS_BOOL bAuditState) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; UINT64 offset; BYTE data[sizeof(UINT32) + sizeof(TSS_BOOL)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, ulOrdinal, data); Trspi_LoadBlob_BOOL(&offset, bAuditState, data); result = obj_context_transport_execute(tspContext, TPM_ORD_SetOrdinalAuditStatus, sizeof(data), data, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); return result; } TSS_RESULT Transport_GetAuditDigest(TSS_HCONTEXT tspContext, /* in */ UINT32 startOrdinal, /* in */ TPM_DIGEST *auditDigest, /* out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TSS_BOOL *more, /* out */ UINT32 *ordSize, /* out */ UINT32 **ordList) /* out */ { TSS_RESULT result; UINT32 handlesLen = 0, decLen; BYTE *dec = NULL; UINT64 offset; BYTE data[sizeof(UINT32)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, startOrdinal, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetAuditDigest, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_COUNTER_VALUE(&offset, dec, NULL); *counterValueSize = (UINT32)offset; if ((*counterValue = malloc(*counterValueSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *counterValueSize); *counterValueSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_UnloadBlob(&offset, *counterValueSize, dec, *counterValue); Trspi_UnloadBlob_DIGEST(&offset, dec, auditDigest); Trspi_UnloadBlob_BOOL(&offset, more, dec); Trspi_UnloadBlob_UINT32(&offset, ordSize, dec); if ((*ordList = malloc(*ordSize)) == NULL) { free(dec); free(*counterValue); *counterValue = NULL; *counterValueSize = 0; LogError("malloc of %u bytes failed", *ordSize); *ordSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *ordSize, dec, *(BYTE **)ordList); *ordSize /= sizeof(UINT32); return TSS_SUCCESS; } TSS_RESULT Transport_GetAuditDigestSigned(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TSS_BOOL closeAudit, /* in */ TPM_NONCE *antiReplay, /* in */ TPM_AUTH *privAuth, /* in/out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TPM_DIGEST *auditDigest, /* out */ TPM_DIGEST *ordinalDigest, /* out */ UINT32 *sigSize, /* out */ BYTE **sig) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen; TCS_HANDLE *handles, handle; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE data[sizeof(TSS_BOOL) + sizeof(TPM_NONCE)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; offset = 0; Trspi_LoadBlob_BOOL(&offset, closeAudit, data); Trspi_LoadBlob_NONCE(&offset, data, antiReplay); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetAuditDigestSigned, sizeof(data), data, &pubKeyHash, &handlesLen, &handles, privAuth, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_COUNTER_VALUE(&offset, dec, NULL); *counterValueSize = (UINT32)offset; if ((*counterValue = malloc(*counterValueSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *counterValueSize); *counterValueSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_UnloadBlob(&offset, *counterValueSize, dec, *counterValue); Trspi_UnloadBlob_DIGEST(&offset, dec, auditDigest); Trspi_UnloadBlob_DIGEST(&offset, dec, ordinalDigest); Trspi_UnloadBlob_UINT32(&offset, sigSize, dec); if ((*sig = malloc(*sigSize)) == NULL) { free(dec); free(*counterValue); *counterValue = NULL; *counterValueSize = 0; LogError("malloc of %u bytes failed", *sigSize); *counterValueSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *sigSize, dec, *sig); return TSS_SUCCESS; } #endif trousers-0.3.15/src/tspi/tsp_sign.c0000664000175000017510000000422013663651711016512 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_Sign(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 areaToSignSize, /* in */ BYTE * areaToSign, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen, decLen, dataLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE *dec, *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; dataLen = sizeof(UINT32) + areaToSignSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, areaToSignSize, data); Trspi_LoadBlob(&offset, areaToSignSize, data, areaToSign); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Sign, dataLen, data, &pubKeyHash, &handlesLen, &handles, privAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, sigSize, dec); if ((*sig = malloc(*sigSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *sigSize); *sigSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *sigSize, dec, *sig); return result; } #endif trousers-0.3.15/src/tspi/tspi_quote.c0000664000175000017510000001462413663651711017071 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_Quote(TSS_HTPM hTPM, /* in */ TSS_HKEY hIdentKey, /* in */ TSS_HPCRS hPcrComposite, /* in */ TSS_VALIDATION * pValidationData) /* in, out */ { TCPA_RESULT result; TPM_AUTH privAuth; TPM_AUTH *pPrivAuth = &privAuth; UINT64 offset; TCPA_DIGEST digest; TCS_KEY_HANDLE tcsKeyHandle; TSS_HPOLICY hPolicy; TCPA_NONCE antiReplay; UINT32 pcrDataSize; BYTE pcrData[128]; UINT32 validationLength = 0; BYTE *validationData = NULL; UINT32 pcrDataOutSize; BYTE *pcrDataOut; UINT32 keyDataSize; BYTE *keyData; TSS_KEY keyContainer; BYTE quoteinfo[1024]; TSS_BOOL usesAuth; TSS_HCONTEXT tspContext; TCPA_VERSION version = {1, 1, 0, 0}; Trspi_HashCtx hashCtx; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (hPcrComposite && !obj_is_pcrs(hPcrComposite)) return TSPERR(TSS_E_INVALID_HANDLE); /* get the identKey Policy */ if ((result = obj_rsakey_get_policy(hIdentKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; /* get the Identity TCS keyHandle */ if ((result = obj_rsakey_get_tcs_handle(hIdentKey, &tcsKeyHandle))) return result; if (pValidationData == NULL) { if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), (BYTE **)antiReplay.nonce))) return result; } else { if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); } pcrDataSize = 0; if (hPcrComposite) { if ((result = obj_pcrs_get_selection(hPcrComposite, &pcrDataSize, pcrData))) return result; } result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Quote); result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce); result |= Trspi_HashUpdate(&hashCtx, pcrDataSize, pcrData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (usesAuth) { if ((result = secret_PerformAuth_OIAP(hIdentKey, TPM_ORD_Quote, hPolicy, FALSE, &digest, &privAuth))) { return result; } pPrivAuth = &privAuth; } else { pPrivAuth = NULL; } if ((result = TCS_API(tspContext)->Quote(tspContext, tcsKeyHandle, &antiReplay, pcrDataSize, pcrData, pPrivAuth, &pcrDataOutSize, &pcrDataOut, &validationLength, &validationData))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Quote); result |= Trspi_HashUpdate(&hashCtx, pcrDataOutSize, pcrDataOut); result |= Trspi_Hash_UINT32(&hashCtx, validationLength); result |= Trspi_HashUpdate(&hashCtx, validationLength, validationData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (usesAuth == TRUE) { if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &privAuth))) { free(pcrDataOut); free(validationData); return result; } } if (hPcrComposite) { TCPA_PCR_COMPOSITE pcrComp; __tspi_memset(&pcrComp, 0, sizeof(pcrComp)); offset = 0; if ((result = Trspi_UnloadBlob_PCR_COMPOSITE(&offset, pcrDataOut, &pcrComp))) { free(pcrDataOut); free(pcrComp.pcrValue); free(pcrComp.select.pcrSelect); free(validationData); return result; } if ((result = obj_pcrs_set_values(hPcrComposite, &pcrComp))) { free(pcrDataOut); free(pcrComp.pcrValue); free(pcrComp.select.pcrSelect); free(validationData); return result; } free(pcrComp.pcrValue); free(pcrComp.select.pcrSelect); } if ((result = Tspi_GetAttribData(hIdentKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &keyDataSize, &keyData))) { free(pcrDataOut); free(validationData); return result; } /* create the validation data */ offset = 0; __tspi_memset(&keyContainer, 0, sizeof(TSS_KEY)); if ((result = UnloadBlob_TSS_KEY(&offset, keyData, &keyContainer))) return result; /* creating pcrCompositeHash */ Trspi_Hash(TSS_HASH_SHA1, pcrDataOutSize, pcrDataOut, digest.digest); free(pcrDataOut); /* generate Quote_info struct */ /* 1. add version */ offset = 0; if (keyContainer.hdr.key12.tag == TPM_TAG_KEY12) Trspi_LoadBlob_TCPA_VERSION(&offset, quoteinfo, version); else Trspi_LoadBlob_TCPA_VERSION(&offset, quoteinfo, keyContainer.hdr.key11.ver); /* 2. add "QUOT" */ quoteinfo[offset++] = 'Q'; quoteinfo[offset++] = 'U'; quoteinfo[offset++] = 'O'; quoteinfo[offset++] = 'T'; /* 3. Composite Hash */ Trspi_LoadBlob(&offset, TCPA_SHA1_160_HASH_LEN, quoteinfo, digest.digest); /* 4. AntiReplay Nonce */ Trspi_LoadBlob(&offset, TCPA_SHA1_160_HASH_LEN, quoteinfo, antiReplay.nonce); if (pValidationData == NULL) { /* validate the data here */ Trspi_Hash(TSS_HASH_SHA1, offset, quoteinfo, digest.digest); if ((result = Trspi_Verify(TSS_HASH_SHA1, digest.digest, 20, keyContainer.pubKey.key, keyContainer.pubKey.keyLength, validationData, validationLength))) { free_key_refs(&keyContainer); free(validationData); return result; } free_key_refs(&keyContainer); } else { free_key_refs(&keyContainer); pValidationData->rgbValidationData = calloc_tspi(tspContext, validationLength); if (pValidationData->rgbValidationData == NULL) { LogError("malloc of %u bytes failed.", validationLength); return TSPERR(TSS_E_OUTOFMEMORY); } pValidationData->ulValidationDataLength = validationLength; memcpy(pValidationData->rgbValidationData, validationData, validationLength); free(validationData); pValidationData->rgbData = calloc_tspi(tspContext, offset); if (pValidationData->rgbData == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", offset); free_tspi(tspContext, pValidationData->rgbValidationData); pValidationData->rgbValidationData = NULL; pValidationData->ulValidationDataLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } pValidationData->ulDataLength = (UINT32)offset; memcpy(pValidationData->rgbData, quoteinfo, offset); } return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_tick.c0000664000175000017510000001145413663651711016664 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_Hash_TickStampBlob(TSS_HHASH hHash, /* in */ TSS_HKEY hIdentKey, /* in */ TSS_VALIDATION* pValidationData) /* in */ { TSS_RESULT result; TSS_HCONTEXT tspContext; TCS_KEY_HANDLE tcsKey; TSS_HPOLICY hPolicy; TPM_DIGEST digest; TSS_BOOL usesAuth; TPM_AUTH auth, *pAuth; UINT32 hashLen, sigLen, tcLen, signInfoLen; BYTE *hash, *sig, *tc, *signInfo = NULL; UINT64 offset; Trspi_HashCtx hashCtx; if (pValidationData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_hash_get_tsp_context(hHash, &tspContext))) return result; if (pValidationData->ulExternalDataLength != sizeof(TPM_NONCE)) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_hash_get_value(hHash, &hashLen, &hash))) return result; if (hashLen != sizeof(TPM_DIGEST)) { free_tspi(tspContext, hash); return TSPERR(TSS_E_HASH_INVALID_LENGTH); } if ((result = obj_rsakey_get_policy(hIdentKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; if ((result = obj_rsakey_get_tcs_handle(hIdentKey, &tcsKey))) return result; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_TickStampBlob); result |= Trspi_HashUpdate(&hashCtx, sizeof(TPM_NONCE), pValidationData->rgbExternalData); result |= Trspi_HashUpdate(&hashCtx, sizeof(TPM_DIGEST), hash); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free_tspi(tspContext, hash); return result; } if ((result = secret_PerformAuth_OIAP(hIdentKey, TPM_ORD_TickStampBlob, hPolicy, FALSE, &digest, &auth))) { free_tspi(tspContext, hash); return result; } pAuth = &auth; } else pAuth = NULL; if ((result = TCS_API(tspContext)->TickStampBlob(tspContext, tcsKey, (TPM_NONCE *)pValidationData->rgbExternalData, (TPM_DIGEST *)hash, pAuth, &sigLen, &sig, &tcLen, &tc))) { free_tspi(tspContext, hash); return result; } if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_TickStampBlob); result |= Trspi_HashUpdate(&hashCtx, tcLen, tc); result |= Trspi_Hash_UINT32(&hashCtx, sigLen); result |= Trspi_HashUpdate(&hashCtx, sigLen, sig); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free_tspi(tspContext, hash); free(sig); free(tc); return result; } if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) { free_tspi(tspContext, hash); free(sig); free(tc); return result; } } /* tag fixed replay length(Data) Data */ signInfoLen = sizeof(UINT16) + 4 + sizeof(TPM_NONCE) + sizeof(UINT32) + sizeof(TPM_DIGEST) + tcLen; if ((signInfo = calloc_tspi(tspContext, signInfoLen)) == NULL) { free_tspi(tspContext, hash); free(sig); free(tc); return TSPERR(TSS_E_INTERNAL_ERROR); } offset = 0; Trspi_LoadBlob_UINT16(&offset, TPM_TAG_SIGNINFO, signInfo); Trspi_LoadBlob_BYTE(&offset, 'T', signInfo); Trspi_LoadBlob_BYTE(&offset, 'S', signInfo); Trspi_LoadBlob_BYTE(&offset, 'T', signInfo); Trspi_LoadBlob_BYTE(&offset, 'P', signInfo); Trspi_LoadBlob(&offset, sizeof(TPM_NONCE), signInfo, pValidationData->rgbExternalData); Trspi_LoadBlob_UINT32(&offset, sizeof(TPM_DIGEST) + tcLen, signInfo); Trspi_LoadBlob(&offset, sizeof(TPM_DIGEST), signInfo, hash); Trspi_LoadBlob(&offset, (size_t)tcLen, signInfo, tc); free(tc); free_tspi(tspContext, hash); pValidationData->rgbData = signInfo; pValidationData->ulDataLength = signInfoLen; /* tag sig so that it can be free'd by the app through Tspi_Context_FreeMemory */ if ((result = __tspi_add_mem_entry(tspContext, sig))) { free_tspi(tspContext, signInfo); free(sig); return result; } pValidationData->rgbValidationData = sig; pValidationData->ulValidationDataLength = sigLen; return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_ReadCurrentTicks(TSS_HTPM hTPM, /* in */ TPM_CURRENT_TICKS* tickCount) /* out */ { TSS_RESULT result; TSS_HCONTEXT tspContext; UINT32 tcLen; BYTE *tc; UINT64 offset; if (tickCount == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = TCS_API(tspContext)->ReadCurrentTicks(tspContext, &tcLen, &tc))) return result; offset = 0; Trspi_UnloadBlob_CURRENT_TICKS(&offset, tc, tickCount); free(tc); return result; } trousers-0.3.15/src/tspi/tspi_maint.c0000664000175000017510000002001113663651711017027 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_CreateMaintenanceArchive(TSS_HTPM hTPM, /* in */ TSS_BOOL fGenerateRndNumber, /* in */ UINT32 * pulRndNumberLength, /* out */ BYTE ** prgbRndNumber, /* out */ UINT32 * pulArchiveDataLength, /* out */ BYTE ** prgbArchiveData) /* out */ { TSS_RESULT result; TSS_HCONTEXT tspContext; TSS_HPOLICY hOwnerPolicy; TPM_AUTH ownerAuth; TCPA_DIGEST digest; Trspi_HashCtx hashCtx; if (pulArchiveDataLength == NULL || prgbArchiveData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (fGenerateRndNumber && (pulRndNumberLength == NULL || prgbRndNumber == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hOwnerPolicy))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CreateMaintenanceArchive); result |= Trspi_Hash_BYTE(&hashCtx, fGenerateRndNumber); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_CreateMaintenanceArchive, hOwnerPolicy, FALSE, &digest, &ownerAuth))) return result; if ((result = TCS_API(tspContext)->CreateMaintenanceArchive(tspContext, fGenerateRndNumber, &ownerAuth, pulRndNumberLength, prgbRndNumber, pulArchiveDataLength, prgbArchiveData))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CreateMaintenanceArchive); result |= Trspi_Hash_UINT32(&hashCtx, *pulRndNumberLength); result |= Trspi_HashUpdate(&hashCtx, *pulRndNumberLength, *prgbRndNumber); result |= Trspi_Hash_UINT32(&hashCtx, *pulArchiveDataLength); result |= Trspi_HashUpdate(&hashCtx, *pulArchiveDataLength, *prgbArchiveData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error1; if ((result = obj_policy_validate_auth_oiap(hOwnerPolicy, &digest, &ownerAuth))) goto error1; if ((result = __tspi_add_mem_entry(tspContext, *prgbRndNumber))) goto error1; if ((result = __tspi_add_mem_entry(tspContext, *prgbArchiveData))) { free_tspi(tspContext, *prgbRndNumber); goto error2; } return TSS_SUCCESS; error1: free(*prgbRndNumber); error2: free(*prgbArchiveData); return result; } TSS_RESULT Tspi_TPM_KillMaintenanceFeature(TSS_HTPM hTPM) /* in */ { TSS_RESULT result; TSS_HCONTEXT tspContext; TSS_HPOLICY hOwnerPolicy; TPM_AUTH ownerAuth; TCPA_DIGEST digest; Trspi_HashCtx hashCtx; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hOwnerPolicy))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_KillMaintenanceFeature); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_KillMaintenanceFeature, hOwnerPolicy, FALSE, &digest, &ownerAuth))) return result; if ((result = TCS_API(tspContext)->KillMaintenanceFeature(tspContext, &ownerAuth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_KillMaintenanceFeature); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hOwnerPolicy, &digest, &ownerAuth))) return result; return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_LoadMaintenancePubKey(TSS_HTPM hTPM, /* in */ TSS_HKEY hMaintenanceKey, /* in */ TSS_VALIDATION * pValidationData) /* in, out */ { TSS_RESULT result; TSS_HCONTEXT tspContext; TCPA_DIGEST checkSum, digest; TCPA_NONCE nonce; UINT64 offset; UINT32 pubBlobSize; BYTE hashBlob[512], *pubBlob; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (pValidationData == NULL) { if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), (BYTE **)nonce.nonce))) return result; } else { if (pValidationData->ulExternalDataLength < sizeof(nonce.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(&nonce.nonce, pValidationData->rgbExternalData, sizeof(nonce.nonce)); } if ((result = obj_rsakey_get_pub_blob(hMaintenanceKey, &pubBlobSize, &pubBlob))) return result; if ((result = TCS_API(tspContext)->LoadManuMaintPub(tspContext, nonce, pubBlobSize, pubBlob, &checkSum))) return result; offset = 0; Trspi_LoadBlob(&offset, pubBlobSize, hashBlob, pubBlob); Trspi_LoadBlob(&offset, TCPA_SHA1_160_HASH_LEN, hashBlob, (BYTE *)&nonce.nonce); if (pValidationData == NULL) { if ((result = Trspi_Hash(TSS_HASH_SHA1, offset, hashBlob, digest.digest))) return result; if (memcmp(&digest.digest, &checkSum.digest, TCPA_SHA1_160_HASH_LEN)) result = TSPERR(TSS_E_FAIL); } else { if ((pValidationData->rgbData = calloc_tspi(tspContext, offset)) == NULL) return TSPERR(TSS_E_OUTOFMEMORY); pValidationData->ulDataLength = offset; memcpy(pValidationData->rgbData, hashBlob, offset); if ((pValidationData->rgbValidationData = calloc_tspi(tspContext, TPM_SHA1_160_HASH_LEN)) == NULL) { free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN; memcpy(pValidationData->rgbValidationData, checkSum.digest, TCPA_SHA1_160_HASH_LEN); } return result; } TSS_RESULT Tspi_TPM_CheckMaintenancePubKey(TSS_HTPM hTPM, /* in */ TSS_HKEY hMaintenanceKey, /* in */ TSS_VALIDATION * pValidationData) /* in, out */ { TSS_RESULT result; TSS_HCONTEXT tspContext; TCPA_DIGEST checkSum, digest; TCPA_NONCE nonce; UINT32 pubBlobSize; BYTE *pubBlob; Trspi_HashCtx hashCtx; if ((pValidationData && hMaintenanceKey) || (!pValidationData && !hMaintenanceKey)) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (pValidationData == NULL) { if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), (BYTE **)nonce.nonce))) return result; } else { if (pValidationData->ulExternalDataLength < sizeof(nonce.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(&nonce.nonce, pValidationData->rgbExternalData, sizeof(nonce.nonce)); } if ((result = TCS_API(tspContext)->ReadManuMaintPub(tspContext, nonce, &checkSum))) return result; if (pValidationData == NULL) { if ((result = obj_rsakey_get_pub_blob(hMaintenanceKey, &pubBlobSize, &pubBlob))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_HashUpdate(&hashCtx, pubBlobSize, pubBlob); result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, (BYTE *)&nonce.nonce); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (memcmp(&digest.digest, &checkSum.digest, TCPA_SHA1_160_HASH_LEN)) result = TSPERR(TSS_E_FAIL); free_tspi(tspContext, pubBlob); } else { /* Ignore Data and DataLength, the application must already have this data. * Do, however, copy out the checksum so that the application can verify */ if ((pValidationData->rgbValidationData = calloc_tspi(tspContext, TCPA_SHA1_160_HASH_LEN)) == NULL) { return TSPERR(TSS_E_OUTOFMEMORY); } pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN; memcpy(pValidationData->rgbValidationData, checkSum.digest, TCPA_SHA1_160_HASH_LEN); } return result; } trousers-0.3.15/src/tspi/tsp_caps.c0000664000175000017510000001115513663651711016505 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT internal_GetCap(TSS_HCONTEXT tspContext, TSS_FLAG capArea, UINT32 subCap, UINT32 * respSize, BYTE ** respData) { UINT64 offset = 0; TSS_VERSION v = INTERNAL_CAP_VERSION; TSS_BOOL bValue = FALSE; UINT32 u32value = 0; switch (capArea) { case TSS_TSPCAP_VERSION: if ((*respData = calloc_tspi(tspContext, sizeof(TSS_VERSION))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(TSS_VERSION)); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_LoadBlob_TSS_VERSION(&offset, *respData, v); *respSize = offset; break; case TSS_TSPCAP_ALG: switch (subCap) { case TSS_ALG_RSA: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TSP_ALG_RSA; break; case TSS_ALG_AES: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TSP_ALG_AES; break; case TSS_ALG_SHA: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TSP_ALG_SHA; break; case TSS_ALG_HMAC: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TSP_ALG_HMAC; break; case TSS_ALG_DES: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TSP_ALG_DES; break; case TSS_ALG_3DES: *respSize = sizeof(TSS_BOOL); bValue = INTERNAL_CAP_TSP_ALG_3DES; break; case TSS_ALG_DEFAULT: *respSize = sizeof(UINT32); u32value = INTERNAL_CAP_TSP_ALG_DEFAULT; break; case TSS_ALG_DEFAULT_SIZE: *respSize = sizeof(UINT32); u32value = INTERNAL_CAP_TSP_ALG_DEFAULT_SIZE; break; default: LogError("Unknown TSP subCap: %u", subCap); return TSPERR(TSS_E_BAD_PARAMETER); } if ((*respData = calloc_tspi(tspContext, *respSize)) == NULL) { LogError("malloc of %u bytes failed", *respSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (*respSize == sizeof(TSS_BOOL)) *(TSS_BOOL *)respData = bValue; else *(UINT32 *)respData = u32value; break; case TSS_TSPCAP_PERSSTORAGE: if ((*respData = calloc_tspi(tspContext, sizeof(TSS_BOOL))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(TSS_BOOL)); return TSPERR(TSS_E_OUTOFMEMORY); } *respSize = sizeof(TSS_BOOL); (*respData)[0] = INTERNAL_CAP_TSP_PERSSTORAGE; break; case TSS_TSPCAP_RETURNVALUE_INFO: if (subCap != TSS_TSPCAP_PROP_RETURNVALUE_INFO) return TSPERR(TSS_E_BAD_PARAMETER); if ((*respData = calloc_tspi(tspContext, sizeof(UINT32))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(UINT32)); return TSPERR(TSS_E_OUTOFMEMORY); } *respSize = sizeof(UINT32); *(UINT32 *)(*respData) = INTERNAL_CAP_TSP_RETURNVALUE_INFO; break; case TSS_TSPCAP_PLATFORM_INFO: switch (subCap) { case TSS_TSPCAP_PLATFORM_TYPE: if ((*respData = calloc_tspi(tspContext, sizeof(UINT32))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(UINT32)); return TSPERR(TSS_E_OUTOFMEMORY); } *respSize = sizeof(UINT32); *(UINT32 *)(*respData) = INTERNAL_CAP_TSP_PLATFORM_TYPE; break; case TSS_TSPCAP_PLATFORM_VERSION: if ((*respData = calloc_tspi(tspContext, sizeof(UINT32))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(UINT32)); return TSPERR(TSS_E_OUTOFMEMORY); } *respSize = sizeof(UINT32); *(UINT32 *)(*respData) = INTERNAL_CAP_TSP_PLATFORM_VERSION; break; default: return TSPERR(TSS_E_BAD_PARAMETER); } break; case TSS_TSPCAP_MANUFACTURER: switch (subCap) { case TSS_TSPCAP_PROP_MANUFACTURER_ID: if ((*respData = calloc_tspi(tspContext, sizeof(UINT32))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(UINT32)); return TSPERR(TSS_E_OUTOFMEMORY); } *respSize = sizeof(UINT32); *(UINT32 *)(*respData) = INTERNAL_CAP_MANUFACTURER_ID; break; case TSS_TSPCAP_PROP_MANUFACTURER_STR: { BYTE str[] = INTERNAL_CAP_MANUFACTURER_STR; if ((*respData = calloc_tspi(tspContext, INTERNAL_CAP_MANUFACTURER_STR_LEN)) == NULL) { LogError("malloc of %d bytes failed", INTERNAL_CAP_MANUFACTURER_STR_LEN); return TSPERR(TSS_E_OUTOFMEMORY); } *respSize = INTERNAL_CAP_MANUFACTURER_STR_LEN; memcpy(*respData, str, INTERNAL_CAP_MANUFACTURER_STR_LEN); break; } default: return TSPERR(TSS_E_BAD_PARAMETER); } break; default: return TSPERR(TSS_E_BAD_PARAMETER); } return TSS_SUCCESS; } trousers-0.3.15/src/tspi/obj_tpm.c0000664000175000017510000002736713663651711016337 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" void tpm_free(void *data) { struct tr_tpm_obj *tpm = (struct tr_tpm_obj *)data; free(tpm); } TSS_RESULT obj_tpm_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_tpm_obj *tpm = calloc(1, sizeof(struct tr_tpm_obj)); if (tpm == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_tpm_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } /* add usage policy */ if ((result = obj_policy_add(tspContext, TSS_POLICY_USAGE, &tpm->policy))) { free(tpm); return result; } /* initialize the default ctr_id to inactive until we query the TPM */ tpm->ctr_id = 0xffffffff; if ((result = obj_list_add(&tpm_list, tspContext, 0, tpm, phObject))) { free(tpm); return result; } return TSS_SUCCESS; } TSS_BOOL obj_is_tpm(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&tpm_list, hObject))) { answer = TRUE; obj_list_put(&tpm_list); } return answer; } TSS_RESULT obj_tpm_set_policy(TSS_HTPM hTpm, TSS_HPOLICY hPolicy) { struct tsp_object *obj; struct tr_tpm_obj *tpm; UINT32 policyType; TSS_RESULT result = TSS_SUCCESS; if ((result = obj_policy_get_type(hPolicy, &policyType))) return result; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: tpm->policy = hPolicy; break; #ifdef TSS_BUILD_TSS12 case TSS_POLICY_OPERATOR: tpm->operatorPolicy = hPolicy; break; #endif default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&tpm_list); return result; } TSS_RESULT obj_tpm_get_policy(TSS_HTPM hTpm, UINT32 policyType, TSS_HPOLICY *phPolicy) { struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: *phPolicy = tpm->policy; break; #ifdef TSS_BUILD_TSS12 case TSS_POLICY_OPERATOR: *phPolicy = tpm->operatorPolicy; break; #endif default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&tpm_list); return result; } TSS_RESULT obj_tpm_get_tsp_context(TSS_HTPM hTpm, TSS_HCONTEXT *tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&tpm_list); return TSS_SUCCESS; } TSS_RESULT obj_tpm_get(TSS_HCONTEXT tspContext, TSS_HTPM *phTpm) { struct tsp_object *obj; if ((obj = obj_list_get_tspcontext(&tpm_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *phTpm = obj->handle; obj_list_put(&tpm_list); return TSS_SUCCESS; } TSS_RESULT obj_tpm_get_cb11(TSS_HTPM hTpm, TSS_FLAG type, UINT32 *cb) { #ifndef __LP64__ struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; switch (type) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: *cb = (UINT32)tpm->Tspicb_CollateIdentity; break; case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: *cb = (UINT32)tpm->Tspicb_ActivateIdentity; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } obj_list_put(&tpm_list); return result; #else return TSPERR(TSS_E_FAIL); #endif } TSS_RESULT obj_tpm_set_cb11(TSS_HTPM hTpm, TSS_FLAG type, TSS_FLAG app_data, UINT32 cb) { #ifndef __LP64__ struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; switch (type) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: tpm->Tspicb_CollateIdentity = (PVOID)cb; tpm->collateAppData = (PVOID)app_data; break; case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: tpm->Tspicb_ActivateIdentity = (PVOID)cb; tpm->activateAppData = (PVOID)app_data; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } obj_list_put(&tpm_list); return result; #else return TSPERR(TSS_E_FAIL); #endif } TSS_RESULT obj_tpm_set_cred(TSS_HTPM hTpm, TSS_FLAG type, UINT32 CredSize, BYTE *CredData) { struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; switch (type) { case TSS_TPMATTRIB_EKCERT: if ((tpm->EndorsementCred = malloc(CredSize)) == NULL) { LogError("malloc of %u bytes failed", CredSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(tpm->EndorsementCred, CredData, CredSize); tpm->EndorsementCredSize = CredSize; break; case TSS_TPMATTRIB_TPM_CC: if ((tpm->ConformanceCred = malloc(CredSize)) == NULL) { LogError("malloc of %u bytes failed", CredSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(tpm->ConformanceCred, CredData, CredSize); tpm->ConformanceCredSize = CredSize; break; case TSS_TPMATTRIB_PLATFORMCERT: if ((tpm->PlatformCred = malloc(CredSize)) == NULL) { LogError("malloc of %u bytes failed", CredSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(tpm->PlatformCred, CredData, CredSize); tpm->PlatformCredSize = CredSize; break; case TSS_TPMATTRIB_PLATFORM_CC: if ((tpm->PlatformConfCred = malloc(CredSize)) == NULL) { LogError("malloc of %u bytes failed", CredSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(tpm->PlatformConfCred, CredData, CredSize); tpm->PlatformConfCredSize = CredSize; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } done: obj_list_put(&tpm_list); return result; } TSS_RESULT obj_tpm_get_cred(TSS_HTPM hTpm, TSS_FLAG type, UINT32 *CredSize, BYTE **CredData) { struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; /* get the size of data we need to allocate */ switch (type) { case TSS_TPMATTRIB_EKCERT: *CredSize = tpm->EndorsementCredSize; break; case TSS_TPMATTRIB_TPM_CC: *CredSize = tpm->ConformanceCredSize; break; case TSS_TPMATTRIB_PLATFORMCERT: *CredSize = tpm->PlatformCredSize; break; case TSS_TPMATTRIB_PLATFORM_CC: *CredSize = tpm->PlatformConfCredSize; break; default: LogError("Credential type is unknown"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (*CredSize == 0) { *CredData = NULL; goto done; } if ((*CredData = calloc_tspi(obj->tspContext, *CredSize)) == NULL) { *CredSize = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } switch (type) { case TSS_TPMATTRIB_EKCERT: memcpy(*CredData, tpm->EndorsementCred, *CredSize); break; case TSS_TPMATTRIB_TPM_CC: memcpy(*CredData, tpm->ConformanceCred, *CredSize); break; case TSS_TPMATTRIB_PLATFORMCERT: memcpy(*CredData, tpm->PlatformCred, *CredSize); break; case TSS_TPMATTRIB_PLATFORM_CC: memcpy(*CredData, tpm->PlatformConfCred, *CredSize); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); *CredSize = 0; free(*CredData); *CredData = NULL; break; } done: obj_list_put(&tpm_list); return result; } TSS_RESULT obj_tpm_set_cb12(TSS_HTPM hTpm, TSS_FLAG flag, BYTE *in) { struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; TSS_CALLBACK *cb = (TSS_CALLBACK *)in; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; switch (flag) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: if (!cb) { tpm->Tspicb_CollateIdentity = NULL; break; } tpm->Tspicb_CollateIdentity = (TSS_RESULT (*)(PVOID, UINT32, BYTE *, TSS_ALGORITHM_ID, UINT32 *, BYTE *, UINT32 *, BYTE *))cb->callback; tpm->collateAppData = cb->appData; tpm->collateAlg = cb->alg; break; case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: if (!cb) { tpm->Tspicb_ActivateIdentity = NULL; break; } tpm->Tspicb_ActivateIdentity = (TSS_RESULT (*)(PVOID, UINT32, BYTE *, UINT32, BYTE *, UINT32 *, BYTE *))cb->callback; tpm->activateAppData = cb->appData; tpm->activateAlg = cb->alg; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } obj_list_put(&tpm_list); return result; } TSS_RESULT obj_tpm_get_cb12(TSS_HTPM hTpm, TSS_FLAG flag, UINT32 *size, BYTE **out) { struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; TSS_CALLBACK *cb; if ((obj = obj_list_get_obj(&tpm_list, hTpm)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; if ((cb = calloc_tspi(obj->tspContext, sizeof(TSS_CALLBACK))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_CALLBACK)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } switch (flag) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: cb->callback = tpm->Tspicb_CollateIdentity; cb->appData = tpm->collateAppData; cb->alg = tpm->collateAlg; *size = sizeof(TSS_CALLBACK); *out = (BYTE *)cb; break; case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: cb->callback = tpm->Tspicb_ActivateIdentity; cb->appData = tpm->activateAppData; cb->alg = tpm->activateAlg; *size = sizeof(TSS_CALLBACK); *out = (BYTE *)cb; break; default: free_tspi(obj->tspContext, cb); result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } done: obj_list_put(&tpm_list); return result; } void obj_tpm_remove_policy_refs(TSS_HPOLICY hPolicy, TSS_HCONTEXT tspContext) { struct tsp_object *obj; struct obj_list *list = &tpm_list; struct tr_tpm_obj *tpm; pthread_mutex_lock(&list->lock); for (obj = list->head; obj; obj = obj->next) { if (obj->tspContext != tspContext) continue; tpm = (struct tr_tpm_obj *)obj->data; if (tpm->policy == hPolicy) tpm->policy = NULL_HPOLICY; #ifdef TSS_BUILD_TSS12 if (tpm->operatorPolicy == hPolicy) tpm->operatorPolicy = NULL_HPOLICY; #endif } pthread_mutex_unlock(&list->lock); } #ifdef TSS_BUILD_COUNTER TSS_RESULT obj_tpm_get_current_counter(TSS_HTPM hTPM, TSS_COUNTER_ID *ctr_id) { struct tsp_object *obj; struct tr_tpm_obj *tpm; TSS_RESULT result = TSS_SUCCESS; UINT32 respLen, subCap = endian32(TPM_CAP_PROP_ACTIVE_COUNTER); BYTE *resp; if ((obj = obj_list_get_obj(&tpm_list, hTPM)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tpm = (struct tr_tpm_obj *)obj->data; if (tpm->ctr_id != 0xffffffff) { *ctr_id = tpm->ctr_id; goto done; } /* No counter has yet been associated with the TPM object, so let the TPM object lock * protect us here and get a counter ID */ if ((result = TCS_API(obj->tspContext)->GetTPMCapability(obj->tspContext, TPM_CAP_PROPERTY, sizeof(UINT32), (BYTE *)&subCap, &respLen, &resp))) goto done; if (respLen != sizeof(UINT32)) { LogDebug("TPM GetCap response size isn't sizeof(UINT32)!"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } memcpy(&tpm->ctr_id, resp, respLen); free(resp); if (tpm->ctr_id == 0xffffffff) { result = TSPERR(TSS_E_NO_ACTIVE_COUNTER); goto done; } *ctr_id = tpm->ctr_id; done: obj_list_put(&tpm_list); return result; } #endif trousers-0.3.15/src/tspi/tspi_random.c0000664000175000017510000000314613663651711017211 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_GetRandom(TSS_HTPM hTPM, /* in */ UINT32 ulRandomDataLength, /* in */ BYTE ** prgbRandomData) /* out */ { TSS_HCONTEXT tspContext; TSS_RESULT result; if (prgbRandomData == NULL || ulRandomDataLength > 4096) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (ulRandomDataLength == 0) return TSS_SUCCESS; if ((result = TCS_API(tspContext)->GetRandom(tspContext, ulRandomDataLength, prgbRandomData))) return result; if ((result = __tspi_add_mem_entry(tspContext, *prgbRandomData))) { free(*prgbRandomData); *prgbRandomData = NULL; return result; } return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_StirRandom(TSS_HTPM hTPM, /* in */ UINT32 ulEntropyDataLength, /* in */ BYTE * rgbEntropyData) /* in */ { TSS_RESULT result; TSS_HCONTEXT tspContext; if (ulEntropyDataLength > 0 && rgbEntropyData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = TCS_API(tspContext)->StirRandom(tspContext, ulEntropyDataLength, rgbEntropyData))) return result; return TSS_SUCCESS; } trousers-0.3.15/src/tspi/obj_delfamily.c0000664000175000017510000001741313663651711017474 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "tsp_delegate.h" void delfamily_free(void *data) { struct tr_delfamily_obj *delfamily = (struct tr_delfamily_obj *)data; free(delfamily); } TSS_BOOL obj_is_delfamily(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&delfamily_list, hObject))) { answer = TRUE; obj_list_put(&delfamily_list); } return answer; } TSS_RESULT obj_delfamily_add(TSS_HCONTEXT hContext, TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_delfamily_obj *delfamily = calloc(1, sizeof(struct tr_delfamily_obj)); if (delfamily == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_delfamily_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } if ((result = obj_list_add(&delfamily_list, hContext, 0, delfamily, phObject))) { free(delfamily); return result; } return TSS_SUCCESS; } TSS_RESULT obj_delfamily_remove(TSS_HDELFAMILY hFamily, TSS_HOBJECT hObject) { TSS_HCONTEXT hContext; TSS_RESULT result; if (obj_is_tpm(hObject)) { if ((result = obj_tpm_get_tsp_context((TSS_HTPM)hObject, &hContext))) return result; } else hContext = (TSS_HCONTEXT)hObject; if ((result = obj_list_remove(&delfamily_list, &delfamily_free, hFamily, hContext))) return result; return TSS_SUCCESS; } void obj_delfamily_find_by_familyid(TSS_HOBJECT hObject, UINT32 familyID, TSS_HDELFAMILY *hFamily) { TSS_HCONTEXT hContext; struct tsp_object *obj; struct obj_list *list = &delfamily_list; struct tr_delfamily_obj *delfamily; pthread_mutex_lock(&list->lock); *hFamily = NULL_HDELFAMILY; if (obj_is_tpm(hObject)) { if (obj_tpm_get_tsp_context((TSS_HTPM)hObject, &hContext)) { pthread_mutex_unlock(&list->lock); return; } } else hContext = (TSS_HCONTEXT)hObject; for (obj = list->head; obj; obj = obj->next) { if (obj->tspContext != hContext) continue; delfamily = (struct tr_delfamily_obj *)obj->data; if (delfamily->familyID == familyID) { *hFamily = obj->handle; break; } } pthread_mutex_unlock(&list->lock); } TSS_RESULT obj_delfamily_get_tsp_context(TSS_HDELFAMILY hFamily, TSS_HCONTEXT *hContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *hContext = obj->tspContext; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_set_locked(TSS_HDELFAMILY hFamily, TSS_BOOL state, TSS_BOOL setInTpm) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; TSS_HTPM hTpm; UINT32 opDataSize; BYTE opData[8]; UINT32 outDataSize; BYTE *outData = NULL; UINT64 offset; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; if (setInTpm) { if ((result = obj_tpm_get(obj->tspContext, &hTpm))) goto done; offset = 0; Trspi_LoadBlob_BOOL(&offset, state, opData); opDataSize = offset; if ((result = do_delegate_manage(hTpm, delfamily->familyID, TPM_FAMILY_ADMIN, opDataSize, opData, &outDataSize, &outData))) goto done; } if (state) delfamily->stateFlags |= TSS_DELFAMILY_FLAGS_STATE_LOCKED; else delfamily->stateFlags &= ~TSS_DELFAMILY_FLAGS_STATE_LOCKED; done: obj_list_put(&delfamily_list); free(outData); return result; } TSS_RESULT obj_delfamily_get_locked(TSS_HDELFAMILY hFamily, TSS_BOOL *state) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; *state = (delfamily->stateFlags & TSS_DELFAMILY_FLAGS_STATE_LOCKED) ? TRUE : FALSE; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_set_enabled(TSS_HDELFAMILY hFamily, TSS_BOOL state, TSS_BOOL setInTpm) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; TSS_HTPM hTpm; UINT32 opDataSize; BYTE opData[8]; UINT32 outDataSize; BYTE *outData = NULL; UINT64 offset; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; if (setInTpm) { if ((result = obj_tpm_get(obj->tspContext, &hTpm))) goto done; offset = 0; Trspi_LoadBlob_BOOL(&offset, state, opData); opDataSize = offset; if ((result = do_delegate_manage(hTpm, delfamily->familyID, TPM_FAMILY_ENABLE, opDataSize, opData, &outDataSize, &outData))) goto done; } if (state) delfamily->stateFlags |= TSS_DELFAMILY_FLAGS_STATE_ENABLED; else delfamily->stateFlags &= ~TSS_DELFAMILY_FLAGS_STATE_ENABLED; done: obj_list_put(&delfamily_list); free(outData); return result; } TSS_RESULT obj_delfamily_get_enabled(TSS_HDELFAMILY hFamily, TSS_BOOL *state) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; *state = (delfamily->stateFlags & TSS_DELFAMILY_FLAGS_STATE_ENABLED) ? TRUE : FALSE; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_set_vercount(TSS_HDELFAMILY hFamily, UINT32 verCount) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; delfamily->verCount = verCount; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_get_vercount(TSS_HDELFAMILY hFamily, UINT32 *verCount) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; *verCount = delfamily->verCount; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_set_familyid(TSS_HDELFAMILY hFamily, UINT32 familyID) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; delfamily->familyID = familyID; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_get_familyid(TSS_HDELFAMILY hFamily, UINT32 *familyID) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; *familyID = delfamily->familyID; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_set_label(TSS_HDELFAMILY hFamily, BYTE label) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; delfamily->label = label; obj_list_put(&delfamily_list); return TSS_SUCCESS; } TSS_RESULT obj_delfamily_get_label(TSS_HDELFAMILY hFamily, BYTE *label) { struct tsp_object *obj; struct tr_delfamily_obj *delfamily; if ((obj = obj_list_get_obj(&delfamily_list, hFamily)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); delfamily = (struct tr_delfamily_obj *)obj->data; *label = delfamily->label; obj_list_put(&delfamily_list); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_daa.c0000664000175000017510000001272413663651711016307 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "tcs_tsp.h" #include "tspps.h" void Trspi_LoadBlob_DAA_PK(UINT64 *offset, BYTE *blob, TSS_DAA_PK *pk) { UINT32 i; Trspi_LoadBlob_TSS_VERSION(offset, blob, pk->versionInfo); Trspi_LoadBlob_UINT32(offset, pk->modulusLength, blob); Trspi_LoadBlob(offset, pk->modulusLength, blob, pk->modulus); Trspi_LoadBlob_UINT32(offset, pk->capitalSLength, blob); Trspi_LoadBlob(offset, pk->capitalSLength, blob, pk->capitalS); Trspi_LoadBlob_UINT32(offset, pk->capitalZLength, blob); Trspi_LoadBlob(offset, pk->capitalZLength, blob, pk->capitalZ); Trspi_LoadBlob_UINT32(offset, pk->capitalR0Length, blob); Trspi_LoadBlob(offset, pk->capitalR0Length, blob, pk->capitalR0); Trspi_LoadBlob_UINT32(offset, pk->capitalR1Length, blob); Trspi_LoadBlob(offset, pk->capitalR1Length, blob, pk->capitalR1); Trspi_LoadBlob_UINT32(offset, pk->gammaLength, blob); Trspi_LoadBlob(offset, pk->gammaLength, blob, pk->gamma); Trspi_LoadBlob_UINT32(offset, pk->capitalGammaLength, blob); Trspi_LoadBlob(offset, pk->capitalGammaLength, blob, pk->capitalGamma); Trspi_LoadBlob_UINT32(offset, pk->rhoLength, blob); Trspi_LoadBlob(offset, pk->rhoLength, blob, pk->rho); for (i = 0; i < pk->capitalYLength; i++) Trspi_LoadBlob(offset, pk->capitalYLength2, blob, pk->capitalY[i]); Trspi_LoadBlob_UINT32(offset, pk->capitalYPlatformLength, blob); Trspi_LoadBlob_UINT32(offset, pk->issuerBaseNameLength, blob); Trspi_LoadBlob(offset, pk->issuerBaseNameLength, blob, pk->issuerBaseName); } TSS_RESULT Trspi_UnloadBlob_DAA_PK(UINT64 *offset, BYTE *blob, TSS_DAA_PK *pk) { UINT32 i = 0, j; __tspi_memset(pk, 0, sizeof(TSS_DAA_PK)); Trspi_UnloadBlob_TSS_VERSION(offset, blob, &pk->versionInfo); Trspi_UnloadBlob_UINT32(offset, &pk->modulusLength, blob); if (pk->modulusLength > 0) { if ((pk->modulus = malloc(pk->modulusLength)) == NULL) return TSPERR(TSS_E_OUTOFMEMORY); Trspi_UnloadBlob(offset, pk->modulusLength, blob, pk->modulus); } else { pk->modulus = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->capitalSLength, blob); if (pk->capitalSLength > 0) { if ((pk->capitalS = malloc(pk->capitalSLength)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->capitalSLength, blob, pk->capitalS); } else { pk->capitalS = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->capitalZLength, blob); if (pk->capitalZLength > 0) { if ((pk->capitalZ = malloc(pk->capitalZLength)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->capitalZLength, blob, pk->capitalZ); } else { pk->capitalZ = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->capitalR0Length, blob); if (pk->capitalR0Length > 0) { if ((pk->capitalR0 = malloc(pk->capitalR0Length)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->capitalR0Length, blob, pk->capitalR0); } else { pk->capitalR0 = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->capitalR1Length, blob); if (pk->capitalR1Length > 0) { if ((pk->capitalR1 = malloc(pk->capitalR1Length)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->capitalR1Length, blob, pk->capitalR1); } else { pk->capitalR1 = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->gammaLength, blob); if (pk->gammaLength > 0) { if ((pk->gamma = malloc(pk->gammaLength)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->gammaLength, blob, pk->gamma); } else { pk->gamma = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->capitalGammaLength, blob); if (pk->capitalGammaLength > 0) { if ((pk->capitalGamma = malloc(pk->capitalGammaLength)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->capitalGammaLength, blob, pk->capitalGamma); } else { pk->capitalGamma = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->rhoLength, blob); if (pk->rhoLength > 0) { if ((pk->rho = malloc(pk->rhoLength)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->rhoLength, blob, pk->rho); } else { pk->rho = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->capitalYLength, blob); Trspi_UnloadBlob_UINT32(offset, &pk->capitalYLength2, blob); if (pk->capitalYLength > 0 && pk->capitalYLength2 > 0) { if ((pk->capitalY = calloc(pk->capitalYLength, sizeof(BYTE *))) == NULL) goto error; for (i = 0; i < pk->capitalYLength; i++) { if ((pk->capitalY[i] = malloc(pk->capitalYLength2)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->capitalYLength2, blob, pk->capitalY[i]); } } else { pk->capitalY = NULL; } Trspi_UnloadBlob_UINT32(offset, &pk->capitalYPlatformLength, blob); Trspi_UnloadBlob_UINT32(offset, &pk->issuerBaseNameLength, blob); if (pk->issuerBaseNameLength > 0) { if ((pk->issuerBaseName = malloc(pk->issuerBaseNameLength)) == NULL) goto error; Trspi_UnloadBlob(offset, pk->issuerBaseNameLength, blob, pk->issuerBaseName); } else { pk->issuerBaseName = NULL; } return TSS_SUCCESS; error: free(pk->modulus); free(pk->capitalS); free(pk->capitalZ); free(pk->capitalR0); free(pk->capitalR1); free(pk->gamma); free(pk->capitalGamma); free(pk->rho); if (pk->capitalY) { for (j = 0; j < i; j++) free(pk->capitalY[j]); free(pk->capitalY); } free(pk->issuerBaseName); __tspi_memset(pk, 0, sizeof(TSS_DAA_PK)); return TSPERR(TSS_E_OUTOFMEMORY); } trousers-0.3.15/src/tspi/tsp_admin.c0000664000175000017510000001670413663651711016654 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_GetCapabilityOwner(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * pOwnerAuth, /* in/out */ TCPA_VERSION * pVersion, /* out */ UINT32 * pNonVolatileFlags, /* out */ UINT32 * pVolatileFlags) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 0, decLen; BYTE *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetCapabilityOwner, 0, NULL, NULL, &handlesLen, NULL, pOwnerAuth, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_TCPA_VERSION(&offset, dec, pVersion); Trspi_UnloadBlob_UINT32(&offset, pNonVolatileFlags, dec); Trspi_UnloadBlob_UINT32(&offset, pVolatileFlags, dec); free(dec); return result; } TSS_RESULT Transport_SetOwnerInstall(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL state) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_SetOwnerInstall, sizeof(TSS_BOOL), (BYTE *)&state, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_DisableOwnerClear(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_DisableOwnerClear, 0, NULL, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); return result; } TSS_RESULT Transport_DisableForceClear(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_DisableForceClear, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_OwnerSetDisable(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL disableState, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_OwnerSetDisable, sizeof(TSS_BOOL), (BYTE *)&disableState, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); return result; } TSS_RESULT Transport_PhysicalDisable(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_PhysicalDisable, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_PhysicalEnable(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_PhysicalEnable, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_PhysicalSetDeactivated(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL state) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_PhysicalSetDeactivated, sizeof(TSS_BOOL), (BYTE *)&state, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_SetTempDeactivated(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_SetTempDeactivated, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_SetTempDeactivated2(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH *operatorAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_SetTempDeactivated, 0, NULL, NULL, &handlesLen, NULL, operatorAuth, NULL, NULL, NULL); return result; } TSS_RESULT Transport_DisablePubekRead(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_DisablePubekRead, 0, NULL, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); return result; } TSS_RESULT Transport_ResetLockValue(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TPM_ORD_ResetLockValue, 0, NULL, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); return result; } TSS_RESULT Transport_PhysicalPresence(TSS_HCONTEXT tspContext, /* in */ TCPA_PHYSICAL_PRESENCE fPhysicalPresence) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); result = obj_context_transport_execute(tspContext, TSC_ORD_PhysicalPresence, sizeof(TCPA_PHYSICAL_PRESENCE), (BYTE *)&fPhysicalPresence, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_FlushSpecific(TSS_HCONTEXT tspContext, /* in */ TCS_HANDLE hResHandle, /* in */ TPM_RESOURCE_TYPE resourceType) /* in */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 1; TCS_HANDLE *handles, handle; BYTE data[sizeof(UINT32)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); handle = hResHandle; handles = &handle; offset = 0; Trspi_LoadBlob_UINT32(&offset, resourceType, data); result = obj_context_transport_execute(tspContext, TPM_ORD_FlushSpecific, sizeof(data), data, NULL, &handlesLen, &handles, NULL, NULL, NULL, NULL); return result; } #endif trousers-0.3.15/src/tspi/log.c0000664000175000017510000000226713663651711015456 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ #include #include #include "trousers/tss.h" #include "spi_utils.h" #include "tsplog.h" #ifdef TSS_DEBUG /* * LogBlobData() * * Log a blob's data to the debugging stream * * szDescriptor - The APPID tag found in the caller's environment at build time * sizeOfBlob - The size of the data to log * blob - the data to log * */ void LogBlobData(char *szDescriptor, unsigned long sizeOfBlob, unsigned char *blob) { char temp[64]; int i; if (getenv("TSS_DEBUG_OFF")) return; __tspi_memset(temp, 0, sizeof(temp)); for (i = 0; (unsigned long)i < sizeOfBlob; i++) { if ((i > 0) && ((i % 16) == 0)) { fprintf(stdout, "%s\n", temp); __tspi_memset(temp, 0, sizeof(temp)); } snprintf(&temp[(i%16)*3], 4, "%.2X ", blob[i]); } fprintf(stdout, "%s\n", temp); } TSS_RESULT LogTSPERR(TSS_RESULT result, char *file, int line) { if (getenv("TSS_DEBUG_OFF") == NULL) fprintf(stderr, "%s %s %s:%d: 0x%x\n", "LOG_RETERR", APPID, file, line, result); return (result | TSS_LAYER_TSP); } #endif trousers-0.3.15/src/tspi/tsp_tcsi_param.c0000664000175000017510000000701513663651711017701 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007, 2013 * */ #include #include #include #ifndef __APPLE__ #include #else #define HOST_NAME_MAX 64 #endif #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "tsplog.h" #include "spi_utils.h" #include "tsp_tcsi_param.h" #define RV_OK 0 #define RV_NO_VALUE -1 #define RV_NO_MEM -2 #define RV_WRONG_VALUE -3 #define RV_UNKNOWN_ERR -4 int get_port_from_env(int *port) { char *env_port; char *raw_port_str; env_port = getenv(PORT_ENV_VAR); if (env_port == NULL) return RV_NO_VALUE; raw_port_str = strdup(env_port); if (raw_port_str == NULL) return RV_NO_MEM; LogDebug("Found data in %s environment var: %s", PORT_ENV_VAR, raw_port_str); *port = atoi(raw_port_str); free(raw_port_str); if (*port < 0 || *port > 65535) { LogError("Environment var %s contains invalid port value!", PORT_ENV_VAR); return RV_WRONG_VALUE; } return RV_OK; } TSS_RESULT convert_port_to_str(int port, char port_str[TCP_PORT_STR_MAX_LEN]) { if (snprintf(port_str, TCP_PORT_STR_MAX_LEN, "%d", port) < 0) return TSPERR(TSS_E_INTERNAL_ERROR); return TSS_SUCCESS; } TSS_RESULT get_tcsd_port(char port_str[TCP_PORT_STR_MAX_LEN]) { int rv, port = 0; // Retrieves port from env var first rv = get_port_from_env(&port); switch(rv) { case RV_OK: return convert_port_to_str(port, port_str); case RV_WRONG_VALUE: return TSPERR(TSS_E_BAD_PARAMETER); case RV_NO_MEM: return TSPERR(TSS_E_OUTOFMEMORY); case RV_NO_VALUE: break; } // TODO: Future work retrieves port from config file. // Last case, retrieve default port used by server. return convert_port_to_str(TCSD_DEFAULT_PORT, port_str); } /** * Allocates a string with up to HOST_NAME_MAX chars which contains * the hostname extracted from the env var */ int get_hostname_from_env(char **host_str, unsigned *len) { char *env_host, *tmp_str = NULL; unsigned env_len; // Tries to retrieve from env var first. env_host = getenv(HOSTNAME_ENV_VAR); if (env_host == NULL) { *host_str = NULL; *len = 0; LogDebug("Got no value inside environment var %s.", HOSTNAME_ENV_VAR); return RV_NO_VALUE; } tmp_str = strdup(env_host); if (tmp_str == NULL) return RV_NO_MEM; LogDebug("Environment var %s got value: %s", HOSTNAME_ENV_VAR, tmp_str); env_len = strlen(tmp_str); if (env_len > HOST_NAME_MAX) { *len = HOST_NAME_MAX + 1; } else { *len = env_len + 1; } *host_str = (char *)malloc(*len); if (*host_str == NULL) { LogError("Not enough memory when allocating string to retrieve host name from environment var"); free(tmp_str); return RV_NO_MEM; } strncpy(*host_str, tmp_str, *len); free(tmp_str); return RV_OK; } TSS_RESULT get_tcsd_hostname(char **host_str, unsigned *len) { int rv; // Retrieve from environment var rv = get_hostname_from_env(host_str, len); switch(rv) { case RV_OK: LogDebug("Hostname %s will be used", *host_str); return TSS_SUCCESS; case RV_NO_MEM: return TSPERR(TSS_E_OUTOFMEMORY); case RV_NO_VALUE: // Tente obter de outra maneira break; default: return TSPERR(TSS_E_INTERNAL_ERROR); } // TODO: Future work - Retrieve from config file // Use localhost in last case. *host_str = strdup(TSS_LOCALHOST_STRING); if (*host_str == NULL) return TSPERR(TSS_E_OUTOFMEMORY); *len = sizeof(TSS_LOCALHOST_STRING); LogDebug("Hostname %s will be used", *host_str); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_pcr_events.c0000664000175000017510000000544413663651711020104 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_GetEvent(TSS_HTPM hTPM, /* in */ UINT32 ulPcrIndex, /* in */ UINT32 ulEventNumber, /* in */ TSS_PCR_EVENT * pPcrEvent) /* out */ { TSS_HCONTEXT tspContext; TSS_RESULT result; TSS_PCR_EVENT *event = NULL; if (pPcrEvent == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = RPC_GetPcrEvent(tspContext, ulPcrIndex, &ulEventNumber, &event))) return result; memcpy(pPcrEvent, event, sizeof(TSS_PCR_EVENT)); free(event); return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_GetEvents(TSS_HTPM hTPM, /* in */ UINT32 ulPcrIndex, /* in */ UINT32 ulStartNumber, /* in */ UINT32 * pulEventNumber, /* in, out */ TSS_PCR_EVENT ** prgbPcrEvents) /* out */ { TSS_HCONTEXT tspContext; TSS_RESULT result; TSS_PCR_EVENT *events = NULL; if (pulEventNumber == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (prgbPcrEvents) { if ((result = RPC_GetPcrEventsByPcr(tspContext, ulPcrIndex, ulStartNumber, pulEventNumber, &events))) return result; *prgbPcrEvents = events; } else { /* if the pointer to receive events is NULL, the app only * wants a total number of events for this PCR. */ if ((result = RPC_GetPcrEvent(tspContext, ulPcrIndex, pulEventNumber, NULL))) return result; } return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_GetEventLog(TSS_HTPM hTPM, /* in */ UINT32 * pulEventNumber, /* out */ TSS_PCR_EVENT ** prgbPcrEvents) /* out */ { TSS_HCONTEXT tspContext; TSS_RESULT result; if (pulEventNumber == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; /* if the pointer to receive events is NULL, the app only wants a * total number of events for all PCRs. */ if (prgbPcrEvents == NULL) { UINT16 numPcrs = get_num_pcrs(tspContext); UINT32 i, numEvents = 0; if (numPcrs == 0) { LogDebugFn("Error querying the TPM for its number of PCRs"); return TSPERR(TSS_E_INTERNAL_ERROR); } *pulEventNumber = 0; for (i = 0; i < numPcrs; i++) { if ((result = RPC_GetPcrEvent(tspContext, i, &numEvents, NULL))) return result; *pulEventNumber += numEvents; } } else return RPC_GetPcrEventLog(tspContext, pulEventNumber, prgbPcrEvents); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/ssl_ui.c0000664000175000017510000000410213663651711016161 0ustar deboradebora #include #include #include #include "trousers/tss.h" #include "spi_utils.h" static TSS_RESULT do_ui(BYTE *string, UINT32 *string_len, BYTE *popup, int verify) { char pin_buf[UI_MAX_SECRET_STRING_LENGTH + 1]; char verify_buf[UI_MAX_SECRET_STRING_LENGTH + 1]; char *popup_nl; UI *ui; BYTE *unicode; TSS_RESULT ret = TSS_E_FAIL; popup_nl = malloc(strlen((char *)popup) + 2); if (!popup_nl) return TSS_E_OUTOFMEMORY; ui = UI_new(); if (!ui) goto no_ui; sprintf(popup_nl, "%s\n", (char *)popup); if (!UI_add_info_string(ui, popup_nl)) { printf("add info fail\n"); goto out; } /* UI_add_input_string() doesn't count for the null terminator in its last */ /* parameter, that's why we statically allocated 1 more byte to pin_buf */ if (!UI_add_input_string(ui, "Enter PIN:", 0, pin_buf, 1, UI_MAX_SECRET_STRING_LENGTH)) { printf("add input fail\n"); goto out; } if (verify && !UI_add_verify_string(ui, "Verify PIN:", 0, verify_buf, 1, UI_MAX_SECRET_STRING_LENGTH, pin_buf)) { printf("Add verify fail\n"); goto out; } if (UI_process(ui)) goto out; ret = TSS_SUCCESS; unicode = Trspi_Native_To_UNICODE((BYTE *)pin_buf, string_len); __tspi_memset(string, 0, UI_MAX_SECRET_STRING_LENGTH); memcpy(string, unicode, *string_len); free(unicode); out: UI_free(ui); no_ui: free(popup_nl); return ret; } /* * DisplayPINWindow() * * Popup the dialog to collect an existing password. * * string - buffer that the password will be passed back to caller in * popup - UTF-8 string to be displayed in the title bar of the dialog box * */ TSS_RESULT DisplayPINWindow(BYTE *string, UINT32 *string_len, BYTE *popup) { return do_ui(string, string_len, popup, 0); } /* * DisplayNewPINWindow() * * Popup the dialog to collect a new password. * * string - buffer that the password will be passed back to caller in * popup - UTF-8 string to be displayed in the title bar of the dialog box * */ TSS_RESULT DisplayNewPINWindow(BYTE *string, UINT32 *string_len, BYTE *popup) { return do_ui(string, string_len, popup, 1); } trousers-0.3.15/src/tspi/gtk/0000775000175000017510000000000013663651711015307 5ustar deboradeboratrousers-0.3.15/src/tspi/gtk/main.c0000664000175000017510000000462313663651711016404 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ /* * Initial main.c file generated by Glade. Edit as required. * Glade will not overwrite this file. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #undef TRUE #undef FALSE #include "trousers/tss.h" #include "tsplog.h" #include "interface.h" #include "support.h" /* * DisplayPINWindow() * * Popup the dialog to collect an existing password. * * string - buffer that the password will be passed back to caller in * popup - UTF-8 string to be displayed in the title bar of the dialog box * */ TSS_RESULT DisplayPINWindow(BYTE *string, UINT32 *string_len, BYTE *popup) { GtkWidget *dialog1; struct userdata ud; ud.string_len = 0; #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif gtk_set_locale(); gtk_init_check((int *)NULL, (char ***)NULL); LogDebug("address of string_len: %p", &ud.string_len); dialog1 = create_password_dialog(&ud, (char *)popup); gtk_widget_show(dialog1); gtk_main(); if (ud.string_len) { memcpy(string, ud.string, ud.string_len); __tspi_memset(ud.string, 0, ud.string_len); free(ud.string); } *string_len = ud.string_len; return TSS_SUCCESS; } /* * DisplayNewPINWindow() * * Popup the dialog to collect a new password. * * string - buffer that the password will be passed back to caller in * popup - UTF-8 string to be displayed in the title bar of the dialog box * */ TSS_RESULT DisplayNewPINWindow(BYTE *string, UINT32 *string_len, BYTE *popup) { GtkWidget *dialog1; struct userdata ud; ud.string_len = 0; #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif gtk_set_locale(); gtk_init_check((int *)NULL, (char ***)NULL); LogDebug("address of string_len: %p", &ud.string_len); dialog1 = create_new_password_dialog(&ud, (char *)popup); gtk_widget_show(dialog1); gtk_main(); if (ud.string_len) { memcpy(string, ud.string, ud.string_len); __tspi_memset(ud.string, 0, ud.string_len); free(ud.string); } *string_len = ud.string_len; return TSS_SUCCESS; } trousers-0.3.15/src/tspi/gtk/support.h0000664000175000017510000000406213663651711017176 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _SUPPORT_H_ #define _SUPPOR_H_ /* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include /* * Standard gettext macros. */ #ifdef ENABLE_NLS # include # undef _ # define _(String) dgettext (PACKAGE, String) # ifdef gettext_noop # define N_(String) gettext_noop (String) # else # define N_(String) (String) # endif #else # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) # define dcgettext(Domain,Message,Type) (Message) # define bindtextdomain(Domain,Directory) (Domain) # define _(String) (String) # define N_(String) (String) #endif /* * Public Functions. */ /* * This function returns a widget in a component created by Glade. * Call it with the toplevel widget in the component (i.e. a window/dialog), * or alternatively any widget in the component, and the name of the widget * you want returned. */ GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name); /* Use this function to set the directory containing installed pixmaps. */ void __tspi_add_pixmap_directory (const gchar *directory); /* * Private Functions. */ /* This is used to create the pixmaps used in the interface. */ GtkWidget* create_pixmap (GtkWidget *widget, const gchar *filename); /* This is used to create the pixbufs used in the interface. */ GdkPixbuf* create_pixbuf (const gchar *filename); /* This is used to set ATK action descriptions. */ void glade_set_atk_action_description (AtkAction *action, const gchar *action_name, const gchar *description); #endif trousers-0.3.15/src/tspi/gtk/callbacks.h0000664000175000017510000000241613663651711017402 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _CALLBACKS_H_ #define _CALLBACKS_H_ #include #include "interface.h" /* Callbacks for the simple text imput dialog */ void on_dialog1_close (GtkDialog *dialog, struct userdata *user_data); void on_cancelbutton1_clicked (GtkButton *button, struct userdata *user_data); void on_okbutton1_clicked (GtkButton *button, struct userdata *user_data); gboolean enter_event (GtkWidget *widget, struct userdata *user_data); void on_inputdialog1_destroy (GtkObject *object, struct userdata *user_data); /* Callbacks for the new password dialog */ void on_entryPassword_activate (GtkEntry *entry, struct userdata *user_data); void on_entryConfirm_activate (GtkEntry *entry, struct userdata *user_data); void on_cancelbutton2_clicked (GtkButton *button, struct userdata *user_data); void on_okbutton2_clicked (GtkButton *button, struct userdata *user_data); #endif trousers-0.3.15/src/tspi/gtk/support.c0000664000175000017510000000745413663651711017201 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ /* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "trousers/tss.h" #include "tsplog.h" #include "support.h" GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name) { GtkWidget *parent, *found_widget; for (;;) { if (GTK_IS_MENU (widget)) parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); else parent = widget->parent; if (!parent) parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); if (parent == NULL) break; widget = parent; } found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), widget_name); if (!found_widget) g_warning ("Widget not found: %s", widget_name); return found_widget; } static GList *pixmaps_directories = NULL; /* Use this function to set the directory containing installed pixmaps. */ void __tspi_add_pixmap_directory (const gchar *directory) { pixmaps_directories = g_list_prepend (pixmaps_directories, g_strdup (directory)); } /* This is an internally used function to find pixmap files. */ static gchar* find_pixmap_file (const gchar *filename) { GList *elem; /* We step through each of the pixmaps directory to find it. */ elem = pixmaps_directories; while (elem) { gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, G_DIR_SEPARATOR_S, filename); if (g_file_test (pathname, G_FILE_TEST_EXISTS)) return pathname; g_free (pathname); elem = elem->next; } return NULL; } /* This is an internally used function to create pixmaps. */ GtkWidget* create_pixmap (GtkWidget *widget, const gchar *filename) { gchar *pathname = NULL; GtkWidget *pixmap; if (!filename || !filename[0]) return gtk_image_new (); pathname = find_pixmap_file (filename); if (!pathname) { g_warning (_("Couldn't find pixmap file: %s"), filename); return gtk_image_new (); } pixmap = gtk_image_new_from_file (pathname); g_free (pathname); return pixmap; } /* This is an internally used function to create pixmaps. */ GdkPixbuf* create_pixbuf (const gchar *filename) { gchar *pathname = NULL; GdkPixbuf *pixbuf; GError *error = NULL; if (!filename || !filename[0]) return NULL; pathname = find_pixmap_file (filename); if (!pathname) { g_warning (_("Couldn't find pixmap file: %s"), filename); return NULL; } pixbuf = gdk_pixbuf_new_from_file (pathname, &error); if (!pixbuf) { LogError ("Failed to load pixbuf file: %s: %s\n", pathname, error->message); g_error_free (error); } g_free (pathname); return pixbuf; } /* This is used to set ATK action descriptions. */ void glade_set_atk_action_description (AtkAction *action, const gchar *action_name, const gchar *description) { gint n_actions, i; n_actions = atk_action_get_n_actions (action); for (i = 0; i < n_actions; i++) { if (!strcmp (atk_action_get_name (action, i), action_name)) atk_action_set_description (action, i, description); } } trousers-0.3.15/src/tspi/gtk/interface.c0000664000175000017510000002616513663651711017425 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ /* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "callbacks.h" #include "interface.h" #include "support.h" #define GLADE_HOOKUP_OBJECT(component,widget,name) \ g_object_set_data_full (G_OBJECT (component), name, \ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) #define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ g_object_set_data (G_OBJECT (component), name, widget) GtkWidget* create_password_dialog (struct userdata *ud, char *message) { GtkWidget *dialog1; GtkWidget *dialog_vbox1; GtkWidget *vbox1; GtkWidget *entry; GtkWidget *alignment1; GtkWidget *table2; GtkWidget *label1; GtkWidget *alignment2; GtkWidget *table1; GtkWidget *dialog_action_area1; GtkWidget *cancelbutton1; GtkWidget *okbutton1; GtkTooltips *tooltips; tooltips = gtk_tooltips_new (); dialog1 = gtk_dialog_new (); gtk_widget_set_size_request (dialog1, 300, 150); //gtk_tooltips_set_tip (tooltips, dialog1, _("This is a box for entering dialogue"), NULL); gtk_window_set_title (GTK_WINDOW (dialog1), _("TSS Password")); //gtk_window_set_title (GTK_WINDOW (dialog1), message); gtk_window_set_position (GTK_WINDOW (dialog1), GTK_WIN_POS_CENTER); gtk_window_set_default_size (GTK_WINDOW (dialog1), 300, 150); dialog_vbox1 = GTK_DIALOG (dialog1)->vbox; gtk_widget_show (dialog_vbox1); vbox1 = gtk_vbox_new (TRUE, 0); gtk_widget_show (vbox1); gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0); alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1); gtk_widget_show (alignment1); gtk_box_pack_start (GTK_BOX (vbox1), alignment1, FALSE, FALSE, 0); table2 = gtk_table_new (3, 3, FALSE); gtk_widget_show (table2); gtk_container_add (GTK_CONTAINER (alignment1), table2); //label1 = gtk_label_new (_("Please enter a password, or not.")); label1 = gtk_label_new (message); gtk_widget_show (label1); gtk_table_attach (GTK_TABLE (table2), label1, 1, 2, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5); alignment2 = gtk_alignment_new (0.5, 0.5, 1, 1); gtk_widget_show (alignment2); gtk_box_pack_start (GTK_BOX (vbox1), alignment2, TRUE, TRUE, 0); table1 = gtk_table_new (2, 3, FALSE); gtk_widget_show (table1); gtk_container_add (GTK_CONTAINER (alignment2), table1); entry = gtk_entry_new (); gtk_widget_show (entry); gtk_table_attach (GTK_TABLE (table1), entry, 1, 2, 0, 1, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); //gtk_tooltips_set_tip (tooltips, entry, _("This is where you enter the characters of your password, using the computer input device of your choice."), NULL); gtk_entry_set_max_length (GTK_ENTRY (entry), 255); gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE); dialog_action_area1 = GTK_DIALOG (dialog1)->action_area; gtk_widget_show (dialog_action_area1); gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel"); gtk_widget_show (cancelbutton1); gtk_dialog_add_action_widget (GTK_DIALOG (dialog1), cancelbutton1, GTK_RESPONSE_CANCEL); GTK_WIDGET_SET_FLAGS (cancelbutton1, GTK_CAN_DEFAULT); //gtk_tooltips_set_tip (tooltips, cancelbutton1, _("Depress this button in order to indicate that you would like to cancel the submitting of authorization data at this time."), NULL); okbutton1 = gtk_button_new_from_stock ("gtk-ok"); gtk_widget_show (okbutton1); gtk_dialog_add_action_widget (GTK_DIALOG (dialog1), okbutton1, GTK_RESPONSE_OK); GTK_WIDGET_SET_FLAGS (okbutton1, GTK_CAN_DEFAULT); //gtk_tooltips_set_tip (tooltips, okbutton1, _("Depress this button in order to indicate that you have completed the entry of your authorization data."), NULL); /* We need to pass the window in to destroy it */ ud->window = dialog1; /* Here we need a pointer to the entry to grab the text out of it */ ud->entry = entry; g_signal_connect ((gpointer) dialog1, "close", G_CALLBACK (on_dialog1_close), ud); g_signal_connect ((gpointer) dialog1, "destroy", G_CALLBACK (on_inputdialog1_destroy), ud); g_signal_connect ((gpointer) entry, "activate", G_CALLBACK (enter_event), ud); g_signal_connect ((gpointer) cancelbutton1, "clicked", G_CALLBACK (on_cancelbutton1_clicked), ud); g_signal_connect ((gpointer) okbutton1, "clicked", G_CALLBACK (on_okbutton1_clicked), ud); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (dialog1, dialog1, "dialog1"); GLADE_HOOKUP_OBJECT_NO_REF (dialog1, dialog_vbox1, "dialog_vbox1"); GLADE_HOOKUP_OBJECT (dialog1, vbox1, "vbox1"); GLADE_HOOKUP_OBJECT (dialog1, alignment1, "alignment1"); GLADE_HOOKUP_OBJECT (dialog1, table2, "table2"); GLADE_HOOKUP_OBJECT (dialog1, label1, "label1"); GLADE_HOOKUP_OBJECT (dialog1, alignment2, "alignment2"); GLADE_HOOKUP_OBJECT (dialog1, table1, "table1"); GLADE_HOOKUP_OBJECT (dialog1, entry, "entry"); GLADE_HOOKUP_OBJECT_NO_REF (dialog1, dialog_action_area1, "dialog_action_area1"); GLADE_HOOKUP_OBJECT (dialog1, cancelbutton1, "cancelbutton1"); GLADE_HOOKUP_OBJECT (dialog1, okbutton1, "okbutton1"); GLADE_HOOKUP_OBJECT_NO_REF (dialog1, tooltips, "tooltips"); return dialog1; } GtkWidget* create_new_password_dialog (struct userdata *ud, char *message) { GtkWidget *dialog1; GtkWidget *dialog_vbox1; GtkWidget *vbox1; GtkWidget *table2; GtkWidget *label7; GtkWidget *table1; GtkWidget *label5; GtkWidget *label6; GtkWidget *entryPassword; GtkWidget *entryConfirm; GtkWidget *dialog_action_area1; GtkWidget *cancelbutton2; GtkWidget *okbutton2; dialog1 = gtk_dialog_new (); gtk_widget_set_size_request (dialog1, 300, 150); gtk_window_set_title (GTK_WINDOW (dialog1), "TSS Password"); //gtk_window_set_title (GTK_WINDOW (dialog1), message); dialog_vbox1 = GTK_DIALOG (dialog1)->vbox; gtk_widget_show (dialog_vbox1); vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0); table2 = gtk_table_new (3, 3, FALSE); gtk_widget_show (table2); gtk_box_pack_start (GTK_BOX (vbox1), table2, TRUE, TRUE, 0); //label7 = gtk_label_new (_("Please enter a new password below.")); label7 = gtk_label_new (message); gtk_widget_show (label7); gtk_table_attach (GTK_TABLE (table2), label7, 1, 2, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_label_set_justify (GTK_LABEL (label7), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label7), 0, 0.5); table1 = gtk_table_new (5, 5, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0); label5 = gtk_label_new (_("Password:")); gtk_widget_show (label5); gtk_table_attach (GTK_TABLE (table1), label5, 1, 2, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_label_set_justify (GTK_LABEL (label5), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label5), 0, 0.5); label6 = gtk_label_new (_("Confirm:")); gtk_widget_show (label6); gtk_table_attach (GTK_TABLE (table1), label6, 1, 2, 3, 4, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_label_set_justify (GTK_LABEL (label6), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (label6), 0, 0.5); entryPassword = gtk_entry_new (); gtk_widget_show (entryPassword); gtk_table_attach (GTK_TABLE (table1), entryPassword, 3, 4, 1, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_entry_set_max_length (GTK_ENTRY (entryPassword), 255); gtk_entry_set_visibility (GTK_ENTRY (entryPassword), FALSE); entryConfirm = gtk_entry_new (); gtk_widget_show (entryConfirm); gtk_table_attach (GTK_TABLE (table1), entryConfirm, 3, 4, 3, 4, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_entry_set_max_length (GTK_ENTRY (entryConfirm), 255); gtk_entry_set_visibility (GTK_ENTRY (entryConfirm), FALSE); dialog_action_area1 = GTK_DIALOG (dialog1)->action_area; gtk_widget_show (dialog_action_area1); gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); cancelbutton2 = gtk_button_new_from_stock ("gtk-cancel"); gtk_widget_show (cancelbutton2); gtk_dialog_add_action_widget (GTK_DIALOG (dialog1), cancelbutton2, GTK_RESPONSE_CANCEL); GTK_WIDGET_SET_FLAGS (cancelbutton2, GTK_CAN_DEFAULT); okbutton2 = gtk_button_new_from_stock ("gtk-ok"); gtk_widget_show (okbutton2); gtk_dialog_add_action_widget (GTK_DIALOG (dialog1), okbutton2, GTK_RESPONSE_OK); GTK_WIDGET_SET_FLAGS (okbutton2, GTK_CAN_DEFAULT); /* We need to pass the window in to destroy it */ ud->window = dialog1; /* Here we need a pointer to the entries to grab text out of them */ ud->entryPass = entryPassword; ud->entryConf = entryConfirm; g_signal_connect ((gpointer) dialog1, "destroy", G_CALLBACK (on_inputdialog1_destroy), ud); g_signal_connect ((gpointer) entryPassword, "activate", G_CALLBACK (on_entryPassword_activate), ud); g_signal_connect ((gpointer) entryConfirm, "activate", G_CALLBACK (on_entryConfirm_activate), ud); g_signal_connect ((gpointer) cancelbutton2, "clicked", G_CALLBACK (on_cancelbutton2_clicked), ud); g_signal_connect ((gpointer) okbutton2, "clicked", G_CALLBACK (on_okbutton2_clicked), ud); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (dialog1, dialog1, "dialog1"); GLADE_HOOKUP_OBJECT_NO_REF (dialog1, dialog_vbox1, "dialog_vbox1"); GLADE_HOOKUP_OBJECT (dialog1, vbox1, "vbox1"); GLADE_HOOKUP_OBJECT (dialog1, table2, "table2"); GLADE_HOOKUP_OBJECT (dialog1, label7, "label7"); GLADE_HOOKUP_OBJECT (dialog1, table1, "table1"); GLADE_HOOKUP_OBJECT (dialog1, label5, "label5"); GLADE_HOOKUP_OBJECT (dialog1, label6, "label6"); GLADE_HOOKUP_OBJECT (dialog1, entryPassword, "entryPassword"); GLADE_HOOKUP_OBJECT (dialog1, entryConfirm, "entryConfirm"); GLADE_HOOKUP_OBJECT_NO_REF (dialog1, dialog_action_area1, "dialog_action_area1"); GLADE_HOOKUP_OBJECT (dialog1, cancelbutton2, "cancelbutton2"); GLADE_HOOKUP_OBJECT (dialog1, okbutton2, "okbutton2"); return dialog1; } trousers-0.3.15/src/tspi/gtk/interface.h0000664000175000017510000000105213663651711017416 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ /* * DO NOT EDIT THIS FILE - it is generated by Glade. */ #ifndef _INTERFACE_H_ #define _INTERFACE_H_ struct userdata { char *string; unsigned string_len; GtkWidget *window; GtkWidget *entry; GtkWidget *entryPass; GtkWidget *entryConf; }; GtkWidget* create_password_dialog (struct userdata *, char *); GtkWidget* create_new_password_dialog (struct userdata *, char *); #endif trousers-0.3.15/src/tspi/gtk/callbacks.c0000664000175000017510000000777713663651711017414 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifdef HAVE_CONFIG_H # include #endif #include #include #undef TRUE #undef FALSE #include "callbacks.h" #include "interface.h" #include "support.h" #include "trousers/tss.h" #include "trousers/trousers.h" #include "tsplog.h" /* Callbacks for the simple password dialog */ void on_inputdialog1_destroy(GtkObject *object, struct userdata *user_data) { gtk_widget_destroy(user_data->window); gtk_main_quit(); } void on_dialog1_close(GtkDialog *dialog, struct userdata *user_data) { gtk_widget_destroy(user_data->window); gtk_main_quit(); } void on_cancelbutton1_clicked(GtkButton *button, struct userdata *user_data) { LogDebugFn(); gtk_widget_destroy(user_data->window); user_data->string_len = 0; gtk_main_quit(); } void on_okbutton1_clicked(GtkButton *button, struct userdata *user_data) { const gchar *entry_text = gtk_entry_get_text (GTK_ENTRY(user_data->entry)); LogDebugFn(); user_data->string = (char *)Trspi_Native_To_UNICODE((BYTE *)entry_text, &user_data->string_len); gtk_widget_destroy(user_data->window); gtk_main_quit(); } gboolean enter_event(GtkWidget *widget, struct userdata *user_data) { const gchar *entry_text = gtk_entry_get_text (GTK_ENTRY(user_data->entry)); LogDebugFn(); user_data->string = (char *)Trspi_Native_To_UNICODE((BYTE *)entry_text, &user_data->string_len); gtk_widget_destroy(user_data->window); gtk_main_quit(); return TRUE; } /* Callbacks for the new password dialog */ void on_entryPassword_activate(GtkEntry *entry, struct userdata *user_data) { const gchar *entryPass_text = gtk_entry_get_text (GTK_ENTRY(user_data->entryPass)); const gchar *entryConf_text = gtk_entry_get_text (GTK_ENTRY(user_data->entryConf)); int len = strlen(entryConf_text); if (strlen(entryConf_text) == strlen(entryPass_text)) { if (!memcmp(entryPass_text, entryConf_text, len)) { user_data->string = (char *)Trspi_Native_To_UNICODE((BYTE *)entryConf_text, &user_data->string_len); gtk_widget_destroy(user_data->window); gtk_main_quit(); LogDebugFn("string len ptr: %p, value = %u", &user_data->string_len, user_data->string_len); return; } } gtk_widget_grab_focus(user_data->entryConf); } void on_entryConfirm_activate(GtkEntry *entry, struct userdata *user_data) { const gchar *entryPass_text = gtk_entry_get_text (GTK_ENTRY(user_data->entryPass)); const gchar *entryConf_text = gtk_entry_get_text (GTK_ENTRY(user_data->entryConf)); unsigned len = strlen(entryConf_text); if (strlen(entryConf_text) == strlen(entryPass_text)) { if (!memcmp(entryPass_text, entryConf_text, len)) { user_data->string = (char *)Trspi_Native_To_UNICODE((BYTE *)entryConf_text, &user_data->string_len); gtk_widget_destroy(user_data->window); gtk_main_quit(); LogDebugFn("string len ptr: %p, value = %u", &user_data->string_len, user_data->string_len); return; } } gtk_widget_grab_focus(user_data->entryPass); } void on_cancelbutton2_clicked(GtkButton *button, struct userdata *user_data) { LogDebugFn(); gtk_widget_destroy(user_data->window); user_data->string_len = 0; gtk_main_quit(); } void on_okbutton2_clicked(GtkButton *button, struct userdata *user_data) { const gchar *entryPass_text = gtk_entry_get_text (GTK_ENTRY(user_data->entryPass)); const gchar *entryConf_text = gtk_entry_get_text (GTK_ENTRY(user_data->entryConf)); unsigned len = strlen(entryConf_text); if (strlen(entryConf_text) == strlen(entryPass_text)) { if (!memcmp(entryPass_text, entryConf_text, len)) { user_data->string = (char *)Trspi_Native_To_UNICODE((BYTE *)entryConf_text, &user_data->string_len); gtk_widget_destroy(user_data->window); gtk_main_quit(); LogDebugFn("string len ptr: %p, value = %u", &user_data->string_len, user_data->string_len); return; } } gtk_widget_grab_focus(user_data->entryPass); } trousers-0.3.15/src/tspi/tsp_policy.c0000664000175000017510000000557213663651711017064 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #define PGSIZE sysconf(_SC_PAGESIZE) #define PGOFFSET (PGSIZE - 1) #define PGMASK (~PGOFFSET) /* * popup_GetSecret() * * newPIN - non-zero to popup the dialog to enter a new PIN, zero to popup a dialog * to enter an existing PIN * hash_mode - flag indicating whether to include null terminating data in the hash * of the secret (1.2 backport only). * popup_str - string to appear in the title bar of the popup dialog * auth_hash - the 20+ byte buffer that receives the SHA1 hash of the auth data * entered into the dialog box * */ TSS_RESULT popup_GetSecret(UINT32 new_pin, UINT32 hash_mode, BYTE *popup_str, void *auth_hash) { BYTE secret[UI_MAX_SECRET_STRING_LENGTH] = { 0 }; BYTE *dflt = (BYTE *)"TSS Authentication Dialog"; UINT32 secret_len = 0; TSS_RESULT result; if (popup_str == NULL) popup_str = dflt; /* pin the area where the secret will be put in memory */ if (pin_mem(&secret, UI_MAX_SECRET_STRING_LENGTH)) { LogError("Failed to pin secret in memory."); return TSPERR(TSS_E_INTERNAL_ERROR); } if (new_pin) DisplayNewPINWindow(secret, &secret_len, popup_str); else DisplayPINWindow(secret, &secret_len, popup_str); if (!secret_len) { unpin_mem(&secret, UI_MAX_SECRET_STRING_LENGTH); return TSPERR(TSS_E_POLICY_NO_SECRET); } if (hash_mode == TSS_TSPATTRIB_HASH_MODE_NOT_NULL) secret_len -= sizeof(TSS_UNICODE); // Take off the NULL terminator LogDebug("Hashing these %u bytes as the secret:", secret_len); LogDebugData(secret_len, secret); result = Trspi_Hash(TSS_HASH_SHA1, secret_len, secret, auth_hash); /* zero, then unpin the memory */ __tspi_memset(secret, 0, secret_len); unpin_mem(&secret, UI_MAX_SECRET_STRING_LENGTH); return result; } int pin_mem(void *addr, size_t len) { /* only root can lock pages into RAM */ if (getuid() != (uid_t)0) { LogWarn("Not pinning secrets in memory due to insufficient perms."); return 0; } len += (uintptr_t)addr & PGOFFSET; addr = (void *)((uintptr_t)addr & PGMASK); if (mlock(addr, len) == -1) { LogError("mlock: %s", strerror(errno)); return 1; } return 0; } int unpin_mem(void *addr, size_t len) { /* only root can lock pages into RAM */ if (getuid() != (uid_t)0) { return 0; } len += (uintptr_t)addr & PGOFFSET; addr = (void *)((uintptr_t)addr & PGMASK); if (munlock(addr, len) == -1) { LogError("mlock: %s", strerror(errno)); return 1; } return 0; } trousers-0.3.15/src/tspi/tspi_oper.c0000664000175000017510000000213413663651711016672 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "obj.h" #include "tsplog.h" TSS_RESULT Tspi_TPM_SetOperatorAuth(TSS_HTPM hTpm, /* in */ TSS_HPOLICY hOperatorPolicy) /* in */ { TSS_HCONTEXT tspContext; UINT32 type; TCPA_SECRET operatorAuth; TSS_RESULT result = TSS_SUCCESS; if ((result = obj_tpm_get_tsp_context(hTpm, &tspContext))) return result; if ((result = obj_policy_get_type(hOperatorPolicy, &type))) return result; if (type != TSS_POLICY_OPERATOR) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_policy_get_secret(hOperatorPolicy, TR_SECRET_CTX_NEW, &operatorAuth))) return result; if ((result = TCS_API(tspContext)->SetOperatorAuth(tspContext, &operatorAuth))) return result; if ((result = obj_tpm_set_policy(hTpm, hOperatorPolicy))) return result; return result; } trousers-0.3.15/src/tspi/tsp_oper.c0000664000175000017510000000204713663651711016524 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_SetOperatorAuth(TSS_HCONTEXT tspContext, /* in */ TCPA_SECRET *operatorAuth) /* in */ { TSS_RESULT result; UINT64 offset; TCS_HANDLE handlesLen = 0; BYTE data[sizeof(TCPA_SECRET)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob(&offset, TPM_SHA1_160_HASH_LEN, data, operatorAuth->authdata); return obj_context_transport_execute(tspContext, TPM_ORD_SetOperatorAuth, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); } #endif trousers-0.3.15/src/tspi/tspi_sign.c0000664000175000017510000000752413663651711016675 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_Hash_Sign(TSS_HHASH hHash, /* in */ TSS_HKEY hKey, /* in */ UINT32 * pulSignatureLength, /* out */ BYTE ** prgbSignature) /* out */ { TPM_AUTH privAuth; TPM_AUTH *pPrivAuth = &privAuth; TCPA_DIGEST digest; TCPA_RESULT result; TSS_HPOLICY hPolicy; TCS_KEY_HANDLE tcsKeyHandle; TSS_BOOL usesAuth; TSS_HCONTEXT tspContext; UINT32 ulDataLen; BYTE *data; Trspi_HashCtx hashCtx; if (pulSignatureLength == NULL || prgbSignature == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_hash_get_tsp_context(hHash, &tspContext))) return result; if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; if ((result = obj_hash_get_value(hHash, &ulDataLen, &data))) return result; if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKeyHandle))) goto done; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Sign); result |= Trspi_Hash_UINT32(&hashCtx, ulDataLen); result |= Trspi_HashUpdate(&hashCtx, ulDataLen, data); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; pPrivAuth = &privAuth; if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_Sign, hPolicy, FALSE, &digest, &privAuth))) goto done; } else { pPrivAuth = NULL; } if ((result = TCS_API(tspContext)->Sign(tspContext, tcsKeyHandle, ulDataLen, data, pPrivAuth, pulSignatureLength, prgbSignature))) goto done; if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Sign); result |= Trspi_Hash_UINT32(&hashCtx, *pulSignatureLength); result |= Trspi_HashUpdate(&hashCtx, *pulSignatureLength, *prgbSignature); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free(*prgbSignature); goto done; } if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &privAuth))) { free(*prgbSignature); goto done; } } if ((result = __tspi_add_mem_entry(tspContext, *prgbSignature))) free(*prgbSignature); done: free_tspi(tspContext, data); return result; } TSS_RESULT Tspi_Hash_VerifySignature(TSS_HHASH hHash, /* in */ TSS_HKEY hKey, /* in */ UINT32 ulSignatureLength, /* in */ BYTE * rgbSignature) /* in */ { TCPA_RESULT result; BYTE *pubKey = NULL; UINT32 pubKeySize; BYTE *hashData = NULL; UINT32 hashDataSize; UINT32 sigScheme; TSS_HCONTEXT tspContext; if (ulSignatureLength > 0 && rgbSignature == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext))) return result; if ((result = obj_rsakey_get_modulus(hKey, &pubKeySize, &pubKey))) return result; if ((result = obj_rsakey_get_ss(hKey, &sigScheme))) { free_tspi(tspContext, pubKey); return result; } if ((result = obj_hash_get_value(hHash, &hashDataSize, &hashData))) { free_tspi(tspContext, pubKey); return result; } if (sigScheme == TSS_SS_RSASSAPKCS1V15_SHA1) { result = Trspi_Verify(TSS_HASH_SHA1, hashData, hashDataSize, pubKey, pubKeySize, rgbSignature, ulSignatureLength); } else if (sigScheme == TSS_SS_RSASSAPKCS1V15_DER) { result = Trspi_Verify(TSS_HASH_OTHER, hashData, hashDataSize, pubKey, pubKeySize, rgbSignature, ulSignatureLength); } else { result = TSPERR(TSS_E_INVALID_SIGSCHEME); } free_tspi(tspContext, pubKey); free_tspi(tspContext, hashData); return result; } trousers-0.3.15/src/tspi/daa/0000775000175000017510000000000013663651711015247 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/Makefile.am0000664000175000017510000000260513663651711017306 0ustar deboradeborabin_PROGRAMS=issuer_setup key_verification test test_tpm test_join test_sign #todel test_SOURCES=big_integer/bi_gmp.c big_integer/bi_openssl.c big_integer/bi.c utils/list.c big_integer/test/test.c big_integer/test/multi_exp.c test_CFLAGS=-I../../include/daa -I../../include -DBI_DEBUG -g -DAPPID=\"BI\" test_LDFLAGS=-lcrypto issuer_setup_SOURCES = daa_issuer/issuer_setup.c issuer_setup_CFLAGS=-I../../include/daa -I../../include -DBI_DEBUG -DAPPID=\"DAA_ISSUER_SETUP\" issuer_setup_LDFLAGS=-lcrypto ../libtspi.la ../libdaa.la key_verification_SOURCES=daa_issuer/key_verification.c key_verification_CFLAGS=-I../../include/daa -I../../include -DBI_DEBUG -DAPPID=\"DAA_KEY_VERIFICATION\" key_verification_LDFLAGS=-lcrypto ../libtspi.la ../libdaa.la test_tpm_SOURCES = daa_platform/test.c test_tpm_CFLAGS=-I../../include/daa -I../../include test_tpm_LDFLAGS=-lcrypto ../libtspi.la ../libdaa.la test_join_SOURCES = daa_platform/test_join.c test_join_CFLAGS=-I../../include/daa -I../../include -DBI_DEBUG -DAPPID=\"DAA_JOIN\" test_join_LDFLAGS=-lcrypto ../libtspi.la ../libdaa.la test_sign_SOURCES = test_sign.c test_sign_CFLAGS=-I../../include/daa -I../../include -DBI_DEBUG -DAPPID=\"DAA_JOIN\" test_sign_LDFLAGS=-lcrypto ../libtspi.la ../libdaa.la #todel_SOURCES = todel.c #todel_CFLAGS=-I../../include/daa -I../../include -DBI_DEBUG -DAPPID=\"DAA_JOIN\" #todel_LDFLAGS=-lcrypto ../libtspi.la ../libdaa.la trousers-0.3.15/src/tspi/daa/test_sign.c0000664000175000017510000001533113663651711017415 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include "daa_structs.h" #include "trousers/tss.h" #include "trousers/trousers.h" #include "spi_internal_types.h" #include "spi_utils.h" #include "obj.h" #include "tsplog.h" #include "daa_parameter.h" #include "verifier.h" #include "platform.h" // for RSA Key #include #define DEFAULT_CREDENTIAL_FILENAME "credential.txt" #define DEFAULT_OWN_PASSWD "OWN_PWD" int print_usage(char *exec) { fprintf(stderr, "usage: %s\n", exec); fprintf(stderr, "\t-m,\t--message\n\t\tif define, the data is signed using this message\n\ \t\totherwise an AIK will be generated and used\n"); fprintf(stderr, "\t-pw,\t--passwd\n\t\ttpm owner password (default: %s)\n", DEFAULT_OWN_PASSWD); fprintf(stderr, "\t-cr,\t--credential\n\t\tcredential filename (default: %s)\n", DEFAULT_CREDENTIAL_FILENAME); return -1; } int main(int argc, char *argv[]) { TSS_HCONTEXT hContext; TSS_RESULT result; TSS_HTPM hTPM; TSS_HPOLICY hPolicy; char *credential_filename = DEFAULT_CREDENTIAL_FILENAME; UINT32 nonceVerifierLength; BYTE *nonceVerifier; TSS_HDAA hDAA; TSS_DAA_CREDENTIAL *hDaaCredential; TSS_DAA_SIGN_DATA signData; TSS_DAA_SIGNATURE daaSignature; TSS_DAA_SELECTED_ATTRIB revealAttributes; char *szTpmPasswd = DEFAULT_OWN_PASSWD; char *message = NULL; BYTE **attributes = NULL; FILE *file; char *param; int i, length, rv; bi_ptr random = NULL; TSS_BOOL isCorrect; EVP_MD_CTX *mdctx; TSS_HKEY hKEY; init_tss_version( &signData); init_tss_version( &daaSignature); init_tss_version( &revealAttributes); i = 1; while( i < argc) { param = argv[ i]; if ( strcmp( param, "-m") == 0 || strcmp( param, "--message") == 0) { i++; if( i == argc) return print_usage( argv[0]); message = argv[i]; } else if( strcmp( param, "-cr") == 0 || strcmp( param, "--credential") == 0){ i++; if( i == argc) return print_usage( argv[0]); credential_filename = argv[i]; } else if( strcmp( param, "-pw") == 0 || strcmp( param, "--passwd") == 0){ i++; if( i == argc) return print_usage( argv[0]); szTpmPasswd = argv[i]; } else { fprintf(stderr, "%s:unrecognized option `%s'\n", argv[0], param); return print_usage( argv[0]); } i++; } bi_init( NULL); printf("Loading credential: %s ", credential_filename); file = fopen( credential_filename, "r"); if( (hDaaCredential = load_TSS_DAA_CREDENTIAL( file)) == 0) { LogError( "[test_join]: Error when loading \'%s\': %s\n", credential_filename, strerror( errno)); result = TSS_E_FAIL; goto out_close; } fclose( file); printf("Done\n"); // Create Context LogDebug("Create Context"); result = Tspi_Context_Create( &hContext ); if ( result != TSS_SUCCESS ) { LogError( "Tspi_Context_Create %d\n", result ); goto out; } // Connect to Context result = Tspi_Context_Connect( hContext, NULL ); if ( result != TSS_SUCCESS) goto out_close; printf("\nConnect to the context: %X\n", hContext); if( (result = Tspi_Context_GetTpmObject( hContext, &hTPM)) != TSS_SUCCESS) goto out_close; // Get the correct policy using the TPM ownership PASSWD if( (result = Tspi_GetPolicyObject( hTPM, TSS_POLICY_USAGE, &hPolicy)) != TSS_SUCCESS) goto out_close; if( (result = Tspi_Policy_SetSecret( hPolicy, TSS_SECRET_MODE_PLAIN, strlen( szTpmPasswd), szTpmPasswd)) != TSS_SUCCESS) goto out_close; LogDebug("Tspi_Policy_SetSecret hPolicy received;%d", hPolicy); //Create Object result = obj_daa_add( hContext, &hDAA); if (result != TSS_SUCCESS) { LogError("Tspi_Context_CreateObject:%d", result); Tspi_Context_Close(hContext); LogError("%s: %s", argv[0], err_string(result)); exit(result); } LogDebug("created DAA object:%X", hDAA); // TODO: verifier base name ?? result = Tspi_DAA_VerifyInit( hDAA, // in &nonceVerifierLength, // out &nonceVerifier, // out 0, //baseNameLength, // out NULL //baseName // out ); if (result != TSS_SUCCESS) goto out_close; LogDebug("Verify Init return nonceVerifier [%s]", dump_byte_array( nonceVerifierLength, nonceVerifier)); create_TSS_DAA_SELECTED_ATTRIB( &revealAttributes, 5, 0, 1, 1, 0, 0); mdctx = EVP_MD_CTX_create(); // create the TSS_DAA_SIGN_DATA struct // .selector: 0 -> payload contains a handle to an AIK // 1 -> payload contains a hashed message if( message != NULL) { signData.selector = TSS_FLAG_DAA_SIGN_MESSAGE_HASH; signData.payloadFlag = TSS_FLAG_DAA_SIGN_MESSAGE_HASH; EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); EVP_DigestUpdate(mdctx, (BYTE *)message, strlen( message)); signData.payloadLength = EVP_MD_CTX_size(mdctx); signData.payload = (BYTE *)EVP_MD_CTX_create(); EVP_DigestFinal(mdctx, signData.payload, NULL); } else { signData.selector = TSS_FLAG_DAA_SIGN_IDENTITY_KEY; result = Tspi_Context_CreateObject( hContext, // in TSS_OBJECT_TYPE_RSAKEY, // in TSS_KEY_SIZE_2048, // in &hKEY // out ); if( result != TSS_SUCCESS) goto out_close; } result = Tspi_TPM_DAA_Sign( hDAA, // in hTPM, // in (TSS_HKEY)hDaaCredential, // in revealAttributes, // in 0, // verifierBaseNameLength, // in NULL, // verifierBaseName, // in nonceVerifierLength, // in nonceVerifier, // in signData, // in &daaSignature // out ); if (result != TSS_SUCCESS) goto out_close; LogDebug("TPM_DAA_Sign return daaSignature [%s]", dump_byte_array( nonceVerifierLength, nonceVerifier)); // generate attributes list but without copying the not revealed ones attributes = malloc( sizeof(BYTE *) * hDaaCredential->attributesLength); for( i=0; i < (int)(hDaaCredential->attributesLength); i++) { if( revealAttributes.indicesList[i]) { attributes[i] = (BYTE *)malloc( DAA_PARAM_SIZE_F_I / 8); memcpy( attributes[i], hDaaCredential->attributes[i], DAA_PARAM_SIZE_F_I / 8); } else { attributes[i] = NULL; } } result = Tspi_DAA_VerifySignature( hDAA, // in daaSignature, // in (TSS_HKEY)&(hDaaCredential->issuerPK), // in signData, // in hDaaCredential->attributesLength, // in attributes, // in nonceVerifierLength, // in nonceVerifier, // in 0, //baseNameLength, //in NULL, // in &isCorrect // out ); printf("Signature correct:%s\n", ( isCorrect ? "yes" : "no")); out_close: EVP_MD_CTX_destroy(mdctx); if( attributes != NULL) { for( i=0; i<(int)hDaaCredential->attributesLength; i++) { if( attributes[i] != NULL) free( attributes[i]); } free( attributes); } if( random != NULL) bi_free_ptr( random); Tspi_Context_FreeMemory( hContext, NULL ); Tspi_Context_Close( hContext ); out: bi_release(); LogDebug("THE END result=%d:%s",result, err_string( result) );; return result; } trousers-0.3.15/src/tspi/daa/daa_structs.c0000664000175000017510000012727113663651711017741 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ /* This file implements Helper functions for converting / creating and freeing internal representation of TSS_DAA structures. An external representation is the one define in tss_structs.h. An internal representation is using bi_t or bi_ptr for representing big numbers. Naming convention: for each structures we can have: init_(, struct *) : initialize the version field create_ : init all fields free_ : free all fields e_2_i_ : convertor from External representation to internal i_2_e_ : convertor from Internal to External. This call use a given memory allocation function, to allow for example to use calloc_tspi, or a "normal" malloc. */ #include #include #include #include #include "daa_parameter.h" #include "daa_structs.h" #include "tcslog.h" #define DUMP_DAA_PK_FIELD( field) \ do { \ printf("%s=", #field); \ dump_field( pk->field##Length, pk->field); \ puts(""); \ } while(0); #if 0 #define STORE_DAA_PK_BI1( field, bi) \ do { \ store_bi( &pk->field##Length, &pk->field, bi); \ } while(0); #define STORE_DAA_PK_BI( field, daa_alloc, param_alloc) \ do { \ store_bi( &pk->field##Length,\ &pk->field,\ pk_internal->field,\ daa_alloc,\ param_alloc); \ } while(0); // used only to read a structure from a file, so only as helping function // for TCG application static char buffer[1000]; #endif BYTE *convert_alloc( TCS_CONTEXT_HANDLE tcsContext, UINT32 length, BYTE *source) { BYTE *result = calloc_tspi( tcsContext, length); if( result == NULL) return NULL; memcpy( result, source, length); free( source); return result; } BYTE *copy_alloc( TCS_CONTEXT_HANDLE tcsContext, UINT32 length, BYTE *source) { BYTE *result = calloc_tspi( tcsContext, length); if( result == NULL) return NULL; memcpy( result, source, length); return result; } static void *normal_malloc( size_t size, TSS_HOBJECT object) { void *ret = malloc( size); return ret; } /* store a bi to a buffer and update the length in big endian format */ void store_bi( UINT32 *length, BYTE **buffer, const bi_ptr i, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT object ) { int size; *buffer = (BYTE *)daa_alloc( bi_length( i), object); bi_2_nbin1( &size, *buffer, i); *length = size; LogDebug( "[store_bi] host_length:%d network_length:%d[address:%d]\n", size, (int)*length, (int)*buffer); } bi_ptr get_bi( const unsigned long n_length, const BYTE *buffer) { unsigned long length; length = n_length; LogDebug( "[get_bi] %d [address:%d -> |%2x|%2x| ]\n", (int)length, (int)buffer, (int)(buffer[0] &0xFF), (int)(buffer[1]&0xFF)); return bi_set_as_nbin( length, buffer); } /* length is in network format: big indian */ void dump_field( int length, BYTE *buffer) { int i; for( i=0; i< length; i++) { BYTE byte = (BYTE)(buffer[i] & 0xFF); printf("%02X", byte); } } #if 0 /* !: do not keep the return buffer */ char *read_str(FILE *file) { int i; char c; fgets( buffer, 1000, file); i=0; while( buffer[i] =='\n' || buffer[i]=='\r' || buffer[i]==' ') i++; do { c = buffer[ i++]; } while( c != 0 && c != ' ' && c!='\n' && c!='\r' && c!='#'); buffer[ i -1] = 0; return buffer; } /** * * @param file * @return */ int read_int( FILE *file) { int i, ret; char c; fgets( buffer, 1000, file); i=0; while( buffer[i] =='\n' || buffer[i]=='\r' || buffer[i]==' ') i++; do { c = buffer[ i++]; } while( c != 0 && c != ' ' && c!='\n' && c!='\r' && c!='#'); buffer[ i -1] = 0; sscanf( buffer, "%d", &ret); return ret; } #endif /******************************************************************************************** * TSS_DAA_SELECTED_ATTRIB * this struct is used internally and externally, only a call to internal_2_DAA_SELECTED_ATTRIB * and DAA_SELECTED_ATTRIB_2_internal will change the struct to be internal or external ********************************************************************************************/ void i_2_e_TSS_DAA_SELECTED_ATTRIB( TSS_DAA_SELECTED_ATTRIB *selected_attrib ) { } void e_2_i_TSS_DAA_SELECTED_ATTRIB( TSS_DAA_SELECTED_ATTRIB *selected_attrib ) { } /* work ONLY with internal format important: TSS_BOOL is of type int_8_t, so a char, if the size is bigger, we will maybe need to transform each part to big indian ? or maybe each part is false if equal to 0, true otherwise. */ BYTE *to_bytes_TSS_DAA_SELECTED_ATTRIB_internal( int *result_length, TSS_DAA_SELECTED_ATTRIB *selected_attrib ) { BYTE *result; int index = 0; unsigned int length = selected_attrib->indicesListLength; *result_length = sizeof(unsigned int) + (selected_attrib->indicesListLength * sizeof(TSS_BOOL)); result = (BYTE *)malloc( *result_length); memcpy( &result[index], &length, sizeof(UINT32)); index+=sizeof(UINT32); memcpy( &result[index], selected_attrib->indicesList, sizeof(TSS_BOOL) * selected_attrib->indicesListLength); return result; } /* create a TSS_DAA_SELECTED_ATTRIB of length with given selected attributes. example of selections of the second and third attributes upon 5: create_TSS_DAA_SELECTED_ATTRIB( &selected_attrib, 5, 0, 1, 1, 0, 0); */ void create_TSS_DAA_SELECTED_ATTRIB( TSS_DAA_SELECTED_ATTRIB *attrib, int length, ...) { va_list ap; int i, select; attrib->indicesListLength = length; attrib->indicesList = (TSS_BOOL *)malloc( length * sizeof( TSS_BOOL)); va_start (ap, length); for( i=0; iindicesList[i] = select; } va_end (ap); } /****************************************************************************************** * TSS_DAA_SIGN_DATA * this struct is used internally and externally, only a call to internal_2_DAA_SIGN_DATA * DAA_SIGN_DATA_2_internal will change the struct to be internal or external *******************************************************************************************/ void i_2_e_TSS_DAA_SIGN_DATA( TSS_DAA_SIGN_DATA *sign_data) { } void e_2_i_TSS_DAA_SIGN( TSS_DAA_SIGN_DATA *sign_data) { } /******************************************************************************************** * TSS_DAA_ATTRIB_COMMIT ********************************************************************************************/ TSS_DAA_ATTRIB_COMMIT_internal *create_TSS_DAA_ATTRIB_COMMIT( bi_ptr beta, bi_ptr sMu) { TSS_DAA_ATTRIB_COMMIT_internal *result = (TSS_DAA_ATTRIB_COMMIT_internal *)malloc( sizeof(TSS_DAA_ATTRIB_COMMIT_internal)); result->beta = beta; result->sMu = sMu; return result; } /******************************************************************************************** * TSS_DAA_PSEUDONYM_PLAIN ********************************************************************************************/ TSS_DAA_PSEUDONYM_PLAIN_internal * create_TSS_DAA_PSEUDONYM_PLAIN(bi_ptr nV) { TSS_DAA_PSEUDONYM_PLAIN_internal *result = (TSS_DAA_PSEUDONYM_PLAIN_internal *) malloc(sizeof(TSS_DAA_PSEUDONYM_PLAIN_internal)); result->nV = nV; return result; } /******************************************************************************************** * DAA PRIVATE KEY ********************************************************************************************/ /* * allocate: ret->p_prime * ret->q_prime * ret->productPQprime */ DAA_PRIVATE_KEY_internal * create_TSS_DAA_PRIVATE_KEY(bi_ptr pPrime, bi_ptr qPrime) { DAA_PRIVATE_KEY_internal *private_key = (DAA_PRIVATE_KEY_internal *)malloc( sizeof( DAA_PRIVATE_KEY_internal)); private_key->p_prime = bi_new_ptr(); bi_set( private_key->p_prime, pPrime); private_key->q_prime = bi_new_ptr(); bi_set( private_key->q_prime, qPrime); private_key->productPQprime = bi_new_ptr(); bi_mul( private_key->productPQprime, pPrime, qPrime); return private_key; } #if 0 int save_DAA_PRIVATE_KEY(FILE *file, const DAA_PRIVATE_KEY_internal *private_key) { BI_SAVE( private_key->p_prime , file); BI_SAVE( private_key->q_prime , file); BI_SAVE( private_key->productPQprime, file); return 0; } DAA_PRIVATE_KEY_internal * load_DAA_PRIVATE_KEY(FILE *file) { DAA_PRIVATE_KEY_internal *private_key = (DAA_PRIVATE_KEY_internal *)malloc( sizeof(DAA_PRIVATE_KEY_internal)); private_key->p_prime = bi_new_ptr(); BI_LOAD( private_key->p_prime, file); private_key->q_prime = bi_new_ptr(); BI_LOAD( private_key->q_prime, file); private_key->productPQprime = bi_new_ptr(); BI_LOAD( private_key->productPQprime, file); return private_key; } #endif DAA_PRIVATE_KEY_internal *e_2_i_TSS_DAA_PRIVATE_KEY(TSS_DAA_PRIVATE_KEY *private_key) { DAA_PRIVATE_KEY_internal *private_key_internal; LogDebug("-> e_2_i_TSS_DAA_PRIVATE_KEY"); private_key_internal = (DAA_PRIVATE_KEY_internal *)malloc( sizeof(DAA_PRIVATE_KEY_internal)); private_key_internal->p_prime = get_bi( private_key->p_primeLength, private_key->p_prime); private_key_internal->q_prime = get_bi( private_key->q_primeLength, private_key->q_prime); private_key_internal->productPQprime = get_bi( private_key->productPQprimeLength, private_key->productPQprime); LogDebug("<- e_2_i_TSS_DAA_PRIVATE_KEY"); return private_key_internal; } TSS_DAA_PRIVATE_KEY * i_2_e_TSS_DAA_PRIVATE_KEY(DAA_PRIVATE_KEY_internal *private_key_internal, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT param_alloc) { TSS_DAA_PRIVATE_KEY *result; LogDebug("-> i_2_e_TSS_DAA_PRIVATE_KEY"); result = (TSS_DAA_PRIVATE_KEY *)daa_alloc( sizeof(TSS_DAA_PRIVATE_KEY), param_alloc); init_tss_version( result); store_bi( &(result->p_primeLength), &(result->p_prime), private_key_internal->p_prime, daa_alloc, param_alloc); store_bi( &(result->q_primeLength), &(result->q_prime), private_key_internal->q_prime, daa_alloc, param_alloc); store_bi( &(result->productPQprimeLength), &(result->productPQprime), private_key_internal->productPQprime, daa_alloc, param_alloc); LogDebug("<- i_2_e_TSS_DAA_PRIVATE_KEY"); return result; } /******************************************************************************************** * KEY PAIR WITH PROOF ********************************************************************************************/ #if 0 /* moved to daa_debug.c */ int save_KEY_PAIR_WITH_PROOF(FILE *file, KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof) { save_DAA_PK_internal( file, key_pair_with_proof->pk); save_DAA_PRIVATE_KEY( file, key_pair_with_proof->private_key); save_DAA_PK_PROOF_internal( file, key_pair_with_proof->proof); return 0; } KEY_PAIR_WITH_PROOF_internal * load_KEY_PAIR_WITH_PROOF(FILE *file) { KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof = (KEY_PAIR_WITH_PROOF_internal *)malloc(sizeof(KEY_PAIR_WITH_PROOF_internal)); key_pair_with_proof->pk = load_DAA_PK_internal(file); key_pair_with_proof->private_key = load_DAA_PRIVATE_KEY(file); key_pair_with_proof->proof = load_DAA_PK_PROOF_internal(file); return key_pair_with_proof; } #endif /* allocated using instrumented daa_alloc */ TSS_DAA_KEY_PAIR *get_TSS_DAA_KEY_PAIR(KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT param_alloc) { TSS_DAA_KEY_PAIR *result; LogDebug("-> i_2_e_KEY_PAIR_WITH_PROOF"); result = (TSS_DAA_KEY_PAIR *)daa_alloc(sizeof(TSS_DAA_KEY_PAIR), param_alloc); init_tss_version(result); result->private_key = i_2_e_TSS_DAA_PRIVATE_KEY(key_pair_with_proof->private_key, daa_alloc, param_alloc); result->public_key = i_2_e_TSS_DAA_PK( key_pair_with_proof->pk, daa_alloc, param_alloc); LogDebug("<- i_2_e_KEY_PAIR_WITH_PROOF"); return result; } /******************************************************************************************** * TSS_DAA_PK ********************************************************************************************/ /* pk_internal->capitalY must be alocated using ALLOC_BI_ARRAY() */ void populate_capitalY(TSS_DAA_PK_internal *pk_internal) { int i; bi_new_array(pk_internal->capitalY, pk_internal->capitalRReceiver->length + pk_internal->capitalRIssuer->length); // CAPITAL Y ( capitalRReceiver ) for (i = 0; i < pk_internal->capitalRReceiver->length; i++) pk_internal->capitalY->array[i] = pk_internal->capitalRReceiver->array[i]; // CAPITAL Y ( capitalRIssuer) for (i = 0; i < pk_internal->capitalRIssuer->length; i++) pk_internal->capitalY->array[pk_internal->capitalRReceiver->length+i] = pk_internal->capitalRIssuer->array[i]; } void compute_capitalSprime(TSS_DAA_PK_internal *pk_internal) { bi_t bi_tmp; bi_new(bi_tmp); pk_internal->capitalSprime = bi_new_ptr(); bi_shift_left( bi_tmp, bi_1, DAA_PARAM_SIZE_SPLIT_EXPONENT); bi_mod_exp(pk_internal->capitalSprime, pk_internal->capitalS, bi_tmp, pk_internal->modulus); bi_free( bi_tmp); } /* * create anf feel a TSS_DAA_PK_internal structures * ! this function keep pointer on all parameters */ TSS_DAA_PK_internal * create_DAA_PK(const bi_ptr modulus, const bi_ptr capitalS, const bi_ptr capitalZ, const bi_ptr capitalR0, const bi_ptr capitalR1, const bi_ptr gamma, const bi_ptr capitalGamma, const bi_ptr rho, const bi_array_ptr capitalRReceiver, const bi_array_ptr capitalRIssuer, const int issuerBaseNameLength, BYTE * const issuerBaseName) { TSS_DAA_PK_internal *pk_internal; LogDebug("-> create_DAA_PK"); pk_internal = (TSS_DAA_PK_internal *)malloc(sizeof(TSS_DAA_PK_internal)); pk_internal->modulus = modulus; pk_internal->capitalS = capitalS; pk_internal->capitalZ = capitalZ; pk_internal->capitalR0 = capitalR0; pk_internal->capitalR1 = capitalR1; pk_internal->gamma = gamma; pk_internal->capitalGamma = capitalGamma; pk_internal->rho = rho; pk_internal->capitalRReceiver = capitalRReceiver; pk_internal->capitalRIssuer = capitalRIssuer; pk_internal->capitalY = ALLOC_BI_ARRAY(); populate_capitalY( pk_internal); pk_internal->issuerBaseNameLength = issuerBaseNameLength; pk_internal->issuerBaseName = issuerBaseName; compute_capitalSprime( pk_internal); LogDebug("<- create_DAA_PK"); return pk_internal; } #if 0 /* moved to daa_debug.c */ int save_DAA_PK_internal(FILE *file, const TSS_DAA_PK_internal *pk_internal) { char *buffer; LogDebug("-> save_DAA_PK_internal"); BI_SAVE( pk_internal->modulus, file); BI_SAVE( pk_internal->capitalS, file); BI_SAVE( pk_internal->capitalZ, file); BI_SAVE( pk_internal->capitalR0, file); BI_SAVE( pk_internal->capitalR1, file); BI_SAVE( pk_internal->gamma, file); BI_SAVE( pk_internal->capitalGamma, file); BI_SAVE( pk_internal->rho, file); BI_SAVE_ARRAY( pk_internal->capitalRReceiver, file); BI_SAVE_ARRAY( pk_internal->capitalRIssuer, file); fprintf( file, "%d\n", pk_internal->issuerBaseNameLength); buffer = (char *)malloc( pk_internal->issuerBaseNameLength + 1); memcpy( buffer, pk_internal->issuerBaseName, pk_internal->issuerBaseNameLength); buffer[ pk_internal->issuerBaseNameLength] = 0; fprintf( file, "%s\n", buffer); free( buffer); LogDebug("<- save_DAA_PK_internal"); return 0; } TSS_DAA_PK_internal * load_DAA_PK_internal(FILE *file) { TSS_DAA_PK_internal *pk_internal = (TSS_DAA_PK_internal *)malloc(sizeof(TSS_DAA_PK_internal)); char *read_buffer; pk_internal->modulus = bi_new_ptr(); BI_LOAD( pk_internal->modulus, file); pk_internal->capitalS = bi_new_ptr(); BI_LOAD( pk_internal->capitalS, file); pk_internal->capitalZ = bi_new_ptr(); BI_LOAD( pk_internal->capitalZ, file); pk_internal->capitalR0 = bi_new_ptr(); BI_LOAD( pk_internal->capitalR0, file); pk_internal->capitalR1 = bi_new_ptr(); BI_LOAD( pk_internal->capitalR1, file); pk_internal->gamma = bi_new_ptr(); BI_LOAD( pk_internal->gamma, file); pk_internal->capitalGamma = bi_new_ptr(); BI_LOAD( pk_internal->capitalGamma, file); pk_internal->rho = bi_new_ptr(); BI_LOAD( pk_internal->rho, file); pk_internal->capitalRReceiver = ALLOC_BI_ARRAY(); BI_LOAD_ARRAY( pk_internal->capitalRReceiver, file); pk_internal->capitalRIssuer = ALLOC_BI_ARRAY(); BI_LOAD_ARRAY( pk_internal->capitalRIssuer, file); pk_internal->capitalY = ALLOC_BI_ARRAY(); populate_capitalY( pk_internal); pk_internal->issuerBaseNameLength = read_int( file); read_buffer = read_str( file); pk_internal->issuerBaseName = malloc( pk_internal->issuerBaseNameLength); memcpy( pk_internal->issuerBaseName, read_buffer, pk_internal->issuerBaseNameLength); compute_capitalSprime( pk_internal); return pk_internal; } #endif void dump_DAA_PK_internal(char *name, TSS_DAA_PK_internal *pk_internal) { LogDebug("Dump TSS_DAA_PK_internal:%s\n", name); DUMP_BI( pk_internal->modulus); DUMP_BI( pk_internal->capitalS); DUMP_BI( pk_internal->capitalZ); DUMP_BI( pk_internal->capitalR0); DUMP_BI( pk_internal->capitalR1); DUMP_BI( pk_internal->gamma); DUMP_BI( pk_internal->capitalGamma); DUMP_BI( pk_internal->rho); DUMP_BI_ARRAY( pk_internal->capitalRReceiver); DUMP_BI_ARRAY( pk_internal->capitalRIssuer); LogDebug("issuerBaseName = %s\n", pk_internal->issuerBaseName); LogDebug("End Dump TSS_DAA_PK_internal:%s\n", name); } /* * Encode the DAA_PK like java.security.Key#getEncoded */ BYTE * encoded_DAA_PK_internal(int *result_length, const TSS_DAA_PK_internal *pk) { int length_issuer_base_name = pk->issuerBaseNameLength; int total_length = DAA_PARAM_TSS_VERSION_LENGTH + 5 * ((DAA_PARAM_SIZE_RSA_MODULUS / 8)+ sizeof(int)) + 2 * ((DAA_PARAM_SIZE_MODULUS_GAMMA / 8)+sizeof(int)) + 1 * ((DAA_PARAM_SIZE_RHO / 8)+sizeof(int)) + pk->capitalY->length*(((DAA_PARAM_SIZE_RSA_MODULUS / 8)+sizeof(int))) + length_issuer_base_name; BYTE *result = (BYTE *)malloc(total_length); int i, index = 0, length, big_indian_length; if (result == NULL) return NULL; LogDebug("total_length=%d", total_length); for (index = 0; index < DAA_PARAM_TSS_VERSION_LENGTH; index++) result[index] = DAA_PARAM_TSS_VERSION[index]; // n, capitalS, capitalZ, capitalR0, capitalR1 length = DAA_PARAM_SIZE_RSA_MODULUS / 8; big_indian_length = length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->modulus); index += length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->capitalS); index += length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->capitalZ); index += length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->capitalR0); index += length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->capitalR1); index += length; // gamma, capitalGamma length = DAA_PARAM_SIZE_MODULUS_GAMMA / 8; big_indian_length = length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->gamma); index += length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->capitalGamma); index += length; // rho length = DAA_PARAM_SIZE_RHO / 8; big_indian_length = length; memcpy(&result[index], &big_indian_length, sizeof(int)); index += sizeof(int); bi_2_byte_array( &result[index], length, pk->rho); index += length; // capitalY length = DAA_PARAM_SIZE_RSA_MODULUS / 8; big_indian_length = length; for( i=0; icapitalY->length; i++) { memcpy( &result[index], &big_indian_length, sizeof(int)); index+=sizeof(int); bi_2_byte_array( &result[index], length, pk->capitalY->array[i]); index+=length; } // basename memcpy( &result[index], pk->issuerBaseName, length_issuer_base_name); index+=length_issuer_base_name; *result_length = index; LogDebug("return length=%d", index); return result; } /* create anf feel a TSS_DAA_PK structures */ TSS_DAA_PK * i_2_e_TSS_DAA_PK(TSS_DAA_PK_internal *pk_internal, void *(*daa_alloc)(size_t size, TSS_HOBJECT param_alloc), TSS_HOBJECT param_alloc) { int i; int capitalYLength; int capitalYLength2; TSS_DAA_PK *pk; LogDebug("-> i_2_e_TSS_DAA_PK"); pk = (TSS_DAA_PK *)daa_alloc( sizeof(TSS_DAA_PK), param_alloc); init_tss_version( pk); if (pk == NULL) { LogError("Can not allocate the TSS_DAA_PK structure"); return NULL; } STORE_DAA_PK_BI( modulus, daa_alloc, param_alloc); STORE_DAA_PK_BI( capitalS, daa_alloc, param_alloc); STORE_DAA_PK_BI( capitalZ, daa_alloc, param_alloc); STORE_DAA_PK_BI( capitalR0, daa_alloc, param_alloc); STORE_DAA_PK_BI( capitalR1, daa_alloc, param_alloc); STORE_DAA_PK_BI( gamma, daa_alloc, param_alloc); STORE_DAA_PK_BI( capitalGamma, daa_alloc, param_alloc); STORE_DAA_PK_BI( rho, daa_alloc, param_alloc); capitalYLength = pk_internal->capitalY->length; capitalYLength2 = bi_nbin_size( pk_internal->capitalY->array[0]); LogDebug("[capitalYLength=%d capitalYLength2=%d total size=%d]\n", capitalYLength, capitalYLength2, sizeof(BYTE) * capitalYLength * capitalYLength2); pk->capitalY = (BYTE **) daa_alloc( sizeof(BYTE *) * capitalYLength, param_alloc ); for (i = 0; i < capitalYLength; i++) { if( bi_nbin_size( pk_internal->capitalY->array[i]) != capitalYLength2) { // LOG ERROR LogError("Error during feel operation of capitalY (index=%d capitalYLength" "2=%d, currentSize=%d)\n", i, capitalYLength2, (int)bi_nbin_size(pk_internal->capitalY->array[i])); } BYTE *buffer = (BYTE*) daa_alloc( sizeof(BYTE) * capitalYLength2, param_alloc); bi_2_byte_array( buffer, capitalYLength2, pk_internal->capitalY->array[i]); // bi_2_nbin1( &checkSize, buffer, pk_internal->capitalY->array[i]); pk->capitalY[i] = buffer; LogDebug( "[i=%d currentsize=%d buffer[%d]=[%2x|%2x]\n", i, (int)bi_nbin_size( pk_internal->capitalY->array[i]), (int)pk->capitalY[i], (int)pk->capitalY[i][0], (int)pk->capitalY[i][1]); } pk->capitalYLength = capitalYLength; pk->capitalYLength2 = capitalYLength2; pk->capitalYPlatformLength = pk_internal->capitalRReceiver->length; LogDebug("issuer= len=%d", pk_internal->issuerBaseNameLength); pk->issuerBaseNameLength = pk_internal->issuerBaseNameLength; pk->issuerBaseName = (BYTE *)daa_alloc(pk_internal->issuerBaseNameLength, param_alloc); memcpy( pk->issuerBaseName, pk_internal->issuerBaseName, pk_internal->issuerBaseNameLength); LogDebug("i_2_e_TSS_DAA_PK extern_issuer=%s intern_issuer=%s\n", pk->issuerBaseName, pk_internal->issuerBaseName); LogDebug("<- i_2_e_TSS_DAA_PK"); return pk; } /**/ TSS_DAA_PK_internal * e_2_i_TSS_DAA_PK( TSS_DAA_PK *pk) { TSS_DAA_PK_internal *pk_internal = (TSS_DAA_PK_internal *)malloc(sizeof(TSS_DAA_PK_internal)); unsigned long capitalYLength, capitalYLength2, capitalYPlatformLength; UINT32 i; int issuer_length; // pk_internal->modulus = GET_DAA_PK_BI( modulus); pk_internal->modulus = get_bi(pk->modulusLength, pk->modulus); pk_internal->capitalS = get_bi(pk->capitalSLength, pk->capitalS); pk_internal->capitalZ = get_bi(pk->capitalZLength, pk->capitalZ); pk_internal->capitalR0 = get_bi(pk->capitalR0Length, pk->capitalR0); pk_internal->capitalR1 = get_bi(pk->capitalR1Length, pk->capitalR1); pk_internal->gamma = get_bi(pk->gammaLength, pk->gamma); pk_internal->capitalGamma = get_bi(pk->capitalGammaLength, pk->capitalGamma); pk_internal->rho = get_bi(pk->rhoLength, pk->rho); capitalYLength = pk->capitalYLength; capitalYLength2= pk->capitalYLength2; capitalYPlatformLength = pk->capitalYPlatformLength; LogDebug( "capitalYLength:%ld capitalYLength2:%ld capitalYPlatformLength:%ld\n", capitalYLength, capitalYLength2, capitalYPlatformLength); pk_internal->capitalRReceiver = ALLOC_BI_ARRAY(); bi_new_array2(pk_internal->capitalRReceiver, capitalYPlatformLength); for (i = 0; i < capitalYPlatformLength; i++) { LogDebug( "i=%d\n", i); pk_internal->capitalRReceiver->array[i] = get_bi(pk->capitalYLength2, pk->capitalY[i]); } pk_internal->capitalRIssuer = ALLOC_BI_ARRAY(); bi_new_array2( pk_internal->capitalRIssuer, capitalYLength - capitalYPlatformLength); for( ; icapitalRIssuer->array[ i - capitalYPlatformLength] = get_bi( pk->capitalYLength2, pk->capitalY[i]); } pk_internal->capitalY = ALLOC_BI_ARRAY(); populate_capitalY( pk_internal); issuer_length = pk->issuerBaseNameLength; pk_internal->issuerBaseNameLength = issuer_length; LogDebug( "issuer_length=%d\n", issuer_length); pk_internal->issuerBaseName = (BYTE *)malloc( issuer_length); memcpy( pk_internal->issuerBaseName, pk->issuerBaseName, issuer_length); LogDebug("e_2_i_TSS_DAA_PK extern_issuer=%s intern_issuer=%s\n", pk->issuerBaseName, pk_internal->issuerBaseName); compute_capitalSprime( pk_internal); // allocation return pk_internal; } void free_TSS_DAA_PK_internal(TSS_DAA_PK_internal *pk_internal) { bi_free_ptr( pk_internal->capitalSprime); free( pk_internal->issuerBaseName); free( pk_internal->capitalY); bi_free_array( pk_internal->capitalRIssuer); bi_free_array( pk_internal->capitalRReceiver); bi_free_ptr( pk_internal->rho); bi_free_ptr( pk_internal->capitalGamma); bi_free_ptr( pk_internal->gamma); bi_free_ptr( pk_internal->capitalR1); bi_free_ptr( pk_internal->capitalR0); bi_free_ptr( pk_internal->capitalZ); bi_free_ptr( pk_internal->capitalS); bi_free_ptr( pk_internal->modulus); free( pk_internal); } /* free a TSS_DAA_PK structures */ void free_TSS_DAA_PK(TSS_DAA_PK *pk) { int i; LogDebug("-> free_TSS_DAA_PK"); free( pk->modulus); free( pk->capitalS); free( pk->capitalZ); free( pk->capitalR0); free( pk->capitalR1); free( pk->gamma); free( pk->capitalGamma); free( pk->rho); for( i=0; i<(int)pk->capitalYLength; i++) { free( pk->capitalY[i]); } free( pk->capitalY); free( pk->issuerBaseName); free( pk); LogDebug("<- free_TSS_DAA_PK"); } TPM_DAA_ISSUER * convert2issuer_settings(TSS_DAA_PK_internal *pk_internal) { TPM_DAA_ISSUER *result = (TPM_DAA_ISSUER *)malloc(sizeof(TPM_DAA_ISSUER)); EVP_MD_CTX *mdctx; UINT32 length; BYTE *array = (BYTE*)malloc((DAA_PARAM_SIZE_RSA_MODULUS+7)/8); LogDebug("convert2issuer_settings"); EVP_MD_CTX_create(mdctx); // TAG result->tag = htons( TPM_TAG_DAA_ISSUER); // capitalR0 EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); bi_2_byte_array( array, length = (bi_length( pk_internal->capitalR0)+7)/8, pk_internal->capitalR0); LogDebug("capitalR0 length=%d", length); EVP_DigestUpdate(mdctx, array, length); EVP_DigestFinal_ex(mdctx, (BYTE *)&(result->DAA_digest_R0), NULL); // capitalR1 EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); bi_2_byte_array( array, length = (bi_length( pk_internal->capitalR1)+7)/8, pk_internal->capitalR1); LogDebug("capitalR1 length=%d", length); EVP_DigestUpdate(mdctx, array, length); EVP_DigestFinal_ex(mdctx, (BYTE *)&(result->DAA_digest_R1), NULL); // capitalS (S0) EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); bi_2_byte_array( array, length = (bi_length( pk_internal->capitalS)+7)/8, pk_internal->capitalS); LogDebug("capitalS length=%d", length); EVP_DigestUpdate(mdctx, array, length); EVP_DigestFinal_ex(mdctx, (BYTE *)&(result->DAA_digest_S0), NULL); // capitalSprime (S1) EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); bi_2_byte_array( array, length = (bi_length( pk_internal->capitalSprime)+7)/8, pk_internal->capitalSprime); LogDebug("capitalSprime length=%d", length); EVP_DigestUpdate(mdctx, array, length); EVP_DigestFinal_ex(mdctx, (BYTE *)&(result->DAA_digest_S1), NULL); // modulus (n) EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); bi_2_byte_array( array, length = (bi_length( pk_internal->modulus)+7)/8, pk_internal->modulus); LogDebug("modulus length=%d", length); EVP_DigestUpdate(mdctx, array, length); EVP_DigestFinal_ex(mdctx, (BYTE *)&(result->DAA_digest_n), NULL); // modulus (n) EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); bi_2_byte_array( array, length = (bi_length( pk_internal->capitalGamma)+7)/8, pk_internal->capitalGamma); LogDebug("capitalGamma length=%d", length); EVP_DigestUpdate(mdctx, array, length); free(array); EVP_DigestFinal_ex(mdctx, (BYTE *)&(result->DAA_digest_gamma), NULL); EVP_MD_CTX_destroy(mdctx); // rho bi_2_byte_array( (BYTE *)&(result->DAA_generic_q), 26, pk_internal->rho); return result; } BYTE * issuer_2_byte_array(TPM_DAA_ISSUER *tpm_daa_issuer, int *length) { UINT32 size = sizeof(UINT16) + ( 6 * TPM_SHA1_160_HASH_LEN) + 26; BYTE * result = (BYTE *)malloc( sizeof(BYTE)*size); UINT32 i = 0; memcpy( &result[i], &(tpm_daa_issuer->tag), sizeof(UINT16)); i+=sizeof(UINT16); memcpy( &result[i], &(tpm_daa_issuer->DAA_digest_R0), TPM_SHA1_160_HASH_LEN); i+=TPM_SHA1_160_HASH_LEN; memcpy( &result[i], &(tpm_daa_issuer->DAA_digest_R1), TPM_SHA1_160_HASH_LEN); i+=TPM_SHA1_160_HASH_LEN; memcpy( &result[i], &(tpm_daa_issuer->DAA_digest_S0), TPM_SHA1_160_HASH_LEN); i+=TPM_SHA1_160_HASH_LEN; memcpy( &result[i], &(tpm_daa_issuer->DAA_digest_S1), TPM_SHA1_160_HASH_LEN); i+=TPM_SHA1_160_HASH_LEN; memcpy( &result[i], &(tpm_daa_issuer->DAA_digest_n), TPM_SHA1_160_HASH_LEN); i+=TPM_SHA1_160_HASH_LEN; memcpy( &result[i], &(tpm_daa_issuer->DAA_digest_gamma), TPM_SHA1_160_HASH_LEN); i+=TPM_SHA1_160_HASH_LEN; memcpy( &result[i], &(tpm_daa_issuer->DAA_generic_q), 26); *length = size; return result; } /******************************************************************************************** * TSS_DAA_PK_PROOF ********************************************************************************************/ /* * this function keep references on: * - challenge (BYTE *) * - response (bi_array_ptr *) */ TSS_DAA_PK_PROOF_internal * create_DAA_PK_PROOF(BYTE* const challenge, const int length_challenge, bi_array_ptr *response, const int length_response) { TSS_DAA_PK_PROOF_internal *pk_proof; #ifdef DAA_DEBUG printf("create_DAA_PK_PROOF_internal\n"); #endif pk_proof = (TSS_DAA_PK_PROOF_internal *)malloc( sizeof(TSS_DAA_PK_PROOF_internal)); pk_proof->challenge = challenge; pk_proof->length_challenge = length_challenge; pk_proof->response = response; pk_proof->length_response = length_response; return pk_proof; } #if 0 int save_DAA_PK_PROOF_internal(FILE *file, TSS_DAA_PK_PROOF_internal *proof) { int i; #ifdef DAA_DEBUG printf("save_DAA_PK_PROOF_internal"); #endif fprintf(file, "%d # %s.length\n", proof->length_challenge, "challenge"); fprintf(file, "%s\n", dump_byte_array( proof->length_challenge, proof->challenge)); fprintf(file, "%d # %s.length\n", proof->length_response, "response"); for (i = 0; i < proof->length_response; i++) { BI_SAVE_ARRAY( proof->response[i], file); } return 0; } /* load using */ /* allocation of: */ /* proof->challenge (BYTE*) */ /* response (bi_array_ptr) */ TSS_DAA_PK_PROOF_internal * load_DAA_PK_PROOF_internal(FILE *file) { TSS_DAA_PK_PROOF_internal *proof = (TSS_DAA_PK_PROOF_internal *)malloc(sizeof(TSS_DAA_PK_PROOF_internal)); char *read_buffer; int i; #ifdef DAA_DEBUG printf("load_DAA_PK_PROOF_internal"); #endif proof->length_challenge = read_int( file); read_buffer = read_str( file); proof->challenge = retrieve_byte_array( &(proof->length_challenge),read_buffer); proof->length_response = read_int( file); proof->response = (bi_array_ptr *)malloc( sizeof(bi_array_ptr) * proof->length_response); for (i = 0; i < proof->length_response; i++) { proof->response[i] = ALLOC_BI_ARRAY(); BI_LOAD_ARRAY( proof->response[i], file); } return proof; } #endif TSS_DAA_PK_PROOF * i_2_e_TSS_DAA_PK_PROOF(TSS_DAA_PK_PROOF_internal*pk_internal_proof, void * (*daa_alloc)(size_t size, TSS_HOBJECT param), TSS_HOBJECT param_alloc) { TSS_DAA_PK_PROOF *pk_proof = (TSS_DAA_PK_PROOF *)daa_alloc( sizeof(TSS_DAA_PK_PROOF), param_alloc); int i, j; int length_response2; int length_response3; init_tss_version( pk_proof); // CHALLENGE pk_proof->challengeLength = pk_internal_proof->length_challenge; pk_proof->challenge = (BYTE *)daa_alloc( pk_internal_proof->length_challenge, param_alloc); memcpy( pk_proof->challenge, pk_internal_proof->challenge, pk_internal_proof->length_challenge); // RESPONSES pk_proof->responseLength = pk_internal_proof->length_response; length_response2 = pk_internal_proof->response[0]->length; pk_proof->responseLength2 = length_response2; length_response3 = bi_nbin_size( pk_internal_proof->response[0]->array[0]); if( length_response3 & 1) length_response3++; // length_response3 should be paire pk_proof->responseLength3 = length_response3; pk_proof->response = (BYTE ***)daa_alloc( sizeof(BYTE **) * pk_internal_proof->length_response, param_alloc); for(i = 0; i < pk_internal_proof->length_response; i++) { pk_proof->response[i] = (BYTE **)daa_alloc( sizeof(BYTE *) * length_response2, param_alloc); for( j = 0; j < length_response2; j++) { (pk_proof->response[i])[j] = (BYTE *)malloc( sizeof(BYTE) * length_response3); bi_2_byte_array( pk_proof->response[i][j], length_response3, pk_internal_proof->response[i]->array[j]); } } return pk_proof; } TSS_DAA_PK_PROOF_internal * e_2_i_TSS_DAA_PK_PROOF(TSS_DAA_PK_PROOF *pk_proof) { int i, j, response_length2; TSS_DAA_PK_PROOF_internal *pk_proof_internal = (TSS_DAA_PK_PROOF_internal *)malloc( sizeof( TSS_DAA_PK_PROOF_internal)); // CHALLENGE pk_proof_internal->length_challenge = pk_proof->challengeLength; #ifdef DAA_DEBUG fprintf(stderr, "issuer_length=%d\n", pk_proof_internal->length_challenge); #endif pk_proof_internal->challenge = (BYTE *)malloc( pk_proof_internal->length_challenge); memcpy( pk_proof_internal->challenge, pk_proof->challenge, pk_proof_internal->length_challenge); // RESPONSES pk_proof_internal->length_response = pk_proof->responseLength; response_length2 = pk_proof->responseLength2; pk_proof_internal->response = (bi_array_ptr *)malloc( sizeof(bi_array_ptr) * pk_proof_internal->length_response); for(i = 0; ilength_response; i++) { pk_proof_internal->response[i] = ALLOC_BI_ARRAY(); bi_new_array2( pk_proof_internal->response[i], response_length2); for( j = 0; j < response_length2; j++) { pk_proof_internal->response[i]->array[j] = get_bi( pk_proof->responseLength3, pk_proof->response[i][j]); } } return pk_proof_internal; } /******************************************************************************************** * TSS_DAA_JOIN_ISSUER_SESSION ********************************************************************************************/ TSS_DAA_JOIN_ISSUER_SESSION_internal * create(TSS_DAA_PK_PROOF_internal *issuerKeyPair, TPM_DAA_ISSUER *issuerAuthKey, TSS_DAA_IDENTITY_PROOF *identityProof, bi_ptr capitalUprime, int daaCounter, int nonceIssuerLength, BYTE *nonceIssuer, int nonceEncryptedLength, BYTE *nonceEncrypted) { TSS_DAA_JOIN_ISSUER_SESSION_internal *result = (TSS_DAA_JOIN_ISSUER_SESSION_internal *)malloc( sizeof(TSS_DAA_JOIN_ISSUER_SESSION_internal)); result->issuerAuthKey = issuerAuthKey; result->issuerKeyPair = issuerKeyPair; result->identityProof = identityProof; result->capitalUprime = capitalUprime; result->daaCounter = daaCounter; result->nonceIssuerLength = nonceIssuerLength; result->nonceIssuer = nonceIssuer; result->nonceEncryptedLength = nonceEncryptedLength; result->nonceEncrypted = nonceEncrypted; return result; } /******************************************************************************************** * TSS_DAA_SIGNATURE ********************************************************************************************/ TSS_DAA_SIGNATURE_internal* e_2_i_TSS_DAA_SIGNATURE(TSS_DAA_SIGNATURE* signature) { TSS_DAA_SIGNATURE_internal *signature_intern = (TSS_DAA_SIGNATURE_internal *)malloc( sizeof( TSS_DAA_SIGNATURE_internal)); int i, length; signature_intern->zeta = bi_set_as_nbin( signature->zetaLength, signature->zeta); signature_intern->capitalT = bi_set_as_nbin( signature->capitalTLength, signature->capitalT); signature_intern->challenge_length = signature->challengeLength; signature_intern->challenge = (BYTE *)malloc( signature->challengeLength); memcpy( signature_intern->challenge, signature->challenge, signature->challengeLength); signature_intern->nonce_tpm_length = signature->nonceTpmLength; signature_intern->nonce_tpm = (BYTE *)malloc( signature->nonceTpmLength); memcpy( signature_intern->nonce_tpm, signature->nonceTpm, signature->nonceTpmLength); signature_intern->sV = bi_set_as_nbin( signature->sVLength, signature->sV); signature_intern->sF0 = bi_set_as_nbin( signature->sF0Length, signature->sF0); signature_intern->sF1 = bi_set_as_nbin( signature->sF1Length, signature->sF1); signature_intern->sE = bi_set_as_nbin( signature->sELength, signature->sE); signature_intern->sA = (bi_array_ptr)malloc( sizeof( bi_array)); bi_new_array2( signature_intern->sA, signature->sALength); length = ( DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES + 7) / 8; for (i = 0; i < (int)signature->sALength; i++) { signature_intern->sA->array[i] = bi_set_as_nbin( length, signature->sA[i]); } return signature_intern; } void free_TSS_DAA_SIGNATURE_internal(TSS_DAA_SIGNATURE_internal *signature) { bi_free_array( signature->sA); bi_free_ptr( signature->sE); bi_free_ptr( signature->sF1); bi_free_ptr( signature->sF0); bi_free_ptr( signature->sV); free( signature->nonce_tpm); free( signature->challenge); bi_free_ptr( signature->capitalT); bi_free_ptr( signature->zeta); free( signature); } #if 0 /******************************************************************************************** TSS_DAA_CRED_ISSUER ********************************************************************************************/ TSS_DAA_CRED_ISSUER * load_TSS_DAA_CRED_ISSUER(FILE *file) { TSS_DAA_CRED_ISSUER *credential = (TSS_DAA_CRED_ISSUER *)malloc(sizeof(TSS_DAA_CRED_ISSUER)); char *read_buffer; int i, len; init_tss_version( credential); credential->capitalALength = read_int( file); read_buffer = read_str( file); credential->capitalA = retrieve_byte_array( &(credential->capitalALength), read_buffer); credential->eLength = read_int( file); read_buffer = read_str( file); credential->e = retrieve_byte_array( &(credential->eLength),read_buffer); credential->vPrimePrimeLength = read_int( file); read_buffer = read_str( file); credential->vPrimePrime = retrieve_byte_array(&(credential->vPrimePrimeLength), read_buffer); // attributes issuer credential->attributesIssuerLength = read_int( file); credential->attributesIssuer = malloc(credential->attributesIssuerLength*sizeof(BYTE*)); for( i=0; i < (int)credential->attributesIssuerLength; i++) { credential->attributesIssuer[i] = retrieve_byte_array( &len, read_buffer); } credential->cPrimeLength = read_int( file); read_buffer = read_str( file); credential->cPrime = retrieve_byte_array( &(credential->cPrimeLength),read_buffer); credential->sELength = read_int( file); read_buffer = read_str( file); credential->sE = retrieve_byte_array( &(credential->sELength),read_buffer); return credential; } int save_TSS_DAA_CRED_ISSUER(FILE *file, TSS_DAA_CRED_ISSUER *credential) { int i; fprintf(file, "%d # %s.length\n", credential->capitalALength, "capitalA"); fprintf(file, "%s\n", dump_byte_array( credential->capitalALength, credential->capitalA)); fprintf(file, "%d # %s.length\n", credential->eLength, "e"); fprintf(file, "%s\n", dump_byte_array( credential->eLength, credential->e)); fprintf(file, "%d # %s.length\n", credential->vPrimePrimeLength, "vPrimePrime"); fprintf(file, "%s\n", dump_byte_array( credential->vPrimePrimeLength, credential->vPrimePrime)); fprintf(file, "%d # %s\n", credential->attributesIssuerLength, "attributesIssuerLength"); for( i=0; i < (int)credential->attributesIssuerLength; i++) { fprintf(file, "%s\n", dump_byte_array( DAA_PARAM_SIZE_F_I / 8, credential->attributesIssuer[i])); } fprintf(file, "%d # %s.length\n", credential->cPrimeLength, "cPrime"); fprintf(file, "%s\n", dump_byte_array( credential->cPrimeLength, credential->cPrime)); fprintf(file, "%d # %s.length\n", credential->sELength, "sE"); fprintf(file, "%s\n", dump_byte_array( credential->sELength, credential->sE)); return 0; } /******************************************************************************************** TSS_DAA_CREDENTIAL ********************************************************************************************/ TSS_DAA_CREDENTIAL * load_TSS_DAA_CREDENTIAL(FILE *file) { TSS_DAA_CREDENTIAL *credential = (TSS_DAA_CREDENTIAL *)malloc(sizeof(TSS_DAA_CREDENTIAL)); char *read_buffer; int i, len; TSS_DAA_PK_internal *pk_internal; TSS_DAA_PK *pk; init_tss_version( credential); credential->capitalALength = read_int( file); read_buffer = read_str( file); credential->capitalA = retrieve_byte_array( &(credential->capitalALength), read_buffer); credential->exponentLength = read_int( file); read_buffer = read_str( file); credential->exponent = retrieve_byte_array( &(credential->exponentLength), read_buffer); credential->vBar0Length = read_int( file); read_buffer = read_str( file); credential->vBar0 = retrieve_byte_array(&(credential->vBar0Length), read_buffer); credential->vBar1Length = read_int( file); read_buffer = read_str( file); credential->vBar1 = retrieve_byte_array(&(credential->vBar1Length), read_buffer); // attributes issuer credential->attributesLength = read_int( file); printf("attributesLength=%d\n", credential->attributesLength); credential->attributes = malloc(credential->attributesLength * sizeof( BYTE *)); for( i=0; i < (int)credential->attributesLength; i++) { read_buffer = read_str( file); credential->attributes[i] = retrieve_byte_array( &len, read_buffer); if( len != DAA_PARAM_SIZE_F_I / 8) { LogError("Error when parsing attributes"); LogError("\tattribute length:%d", len); LogError("\texpected length:%d", DAA_PARAM_SIZE_F_I / 8); return NULL; } } pk_internal = load_DAA_PK_internal( file); pk = i_2_e_TSS_DAA_PK( pk_internal, &normal_malloc, (TSS_HOBJECT)NULL); memcpy( &(credential->issuerPK), pk, sizeof(TSS_DAA_PK)); free( pk); free_TSS_DAA_PK_internal( pk_internal); credential->tpmSpecificEncLength = read_int( file); read_buffer = read_str( file); credential->tpmSpecificEnc = retrieve_byte_array( &(credential->tpmSpecificEncLength), read_buffer); credential->daaCounter = read_int( file); return credential; } int save_TSS_DAA_CREDENTIAL(FILE *file, TSS_DAA_CREDENTIAL *credential) { int i; TSS_DAA_PK_internal *pk_internal; fprintf(file, "%d # %s.length\n", credential->capitalALength, "capitalA"); fprintf(file, "%s\n", dump_byte_array( credential->capitalALength, credential->capitalA)); fprintf(file, "%d # %s.length\n", credential->exponentLength, "exponent"); fprintf(file, "%s\n", dump_byte_array( credential->exponentLength, credential->exponent)); fprintf(file, "%d # %s.length\n", credential->vBar0Length, "vBar0"); fprintf(file, "%s\n", dump_byte_array( credential->vBar0Length, credential->vBar0)); fprintf(file, "%d # %s.length\n", credential->vBar1Length, "vBar1"); fprintf(file, "%s\n", dump_byte_array( credential->vBar1Length, credential->vBar1)); fprintf(file, "%d # %s\n", credential->attributesLength, "attributesLength"); for( i=0; i < (int)credential->attributesLength; i++) { fprintf(file, "%s\n", dump_byte_array( DAA_PARAM_SIZE_F_I / 8, credential->attributes[i])); } pk_internal = e_2_i_TSS_DAA_PK( &(credential->issuerPK) ); save_DAA_PK_internal( file, pk_internal); free_TSS_DAA_PK_internal( pk_internal); fprintf(file, "%d # %s.length\n", credential->tpmSpecificEncLength, "tpmSpecificEnc"); fprintf(file, "%s\n", dump_byte_array( credential->tpmSpecificEncLength, credential->tpmSpecificEnc)); fprintf(file, "%d # daaCounter\n", credential->daaCounter); return 0; } #endif /******************************************************************************************** TPM_DAA_ISSUER ********************************************************************************************/ void free_TPM_DAA_ISSUER(TPM_DAA_ISSUER *tpm_daa_issuer) { free(tpm_daa_issuer); } trousers-0.3.15/src/tspi/daa/daa_debug.c0000664000175000017510000003134613663651711017315 0ustar deboradebora /******************************************************************************************** * KEY PAIR WITH PROOF ********************************************************************************************/ int save_KEY_PAIR_WITH_PROOF(FILE *file, KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof) { save_DAA_PK_internal( file, key_pair_with_proof->pk); save_DAA_PRIVATE_KEY( file, key_pair_with_proof->private_key); save_DAA_PK_PROOF_internal( file, key_pair_with_proof->proof); return 0; } KEY_PAIR_WITH_PROOF_internal * load_KEY_PAIR_WITH_PROOF(FILE *file) { KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof = (KEY_PAIR_WITH_PROOF_internal *)malloc(sizeof(KEY_PAIR_WITH_PROOF_internal)); key_pair_with_proof->pk = load_DAA_PK_internal(file); key_pair_with_proof->private_key = load_DAA_PRIVATE_KEY(file); key_pair_with_proof->proof = load_DAA_PK_PROOF_internal(file); return key_pair_with_proof; } int save_DAA_PK_internal(FILE *file, const TSS_DAA_PK_internal *pk_internal) { char *buffer; LogDebug("-> save_DAA_PK_internal"); BI_SAVE( pk_internal->modulus, file); BI_SAVE( pk_internal->capitalS, file); BI_SAVE( pk_internal->capitalZ, file); BI_SAVE( pk_internal->capitalR0, file); BI_SAVE( pk_internal->capitalR1, file); BI_SAVE( pk_internal->gamma, file); BI_SAVE( pk_internal->capitalGamma, file); BI_SAVE( pk_internal->rho, file); BI_SAVE_ARRAY( pk_internal->capitalRReceiver, file); BI_SAVE_ARRAY( pk_internal->capitalRIssuer, file); fprintf( file, "%d\n", pk_internal->issuerBaseNameLength); buffer = (char *)malloc( pk_internal->issuerBaseNameLength + 1); memcpy( buffer, pk_internal->issuerBaseName, pk_internal->issuerBaseNameLength); buffer[ pk_internal->issuerBaseNameLength] = 0; fprintf( file, "%s\n", buffer); free( buffer); LogDebug("<- save_DAA_PK_internal"); return 0; } TSS_DAA_PK_internal * load_DAA_PK_internal(FILE *file) { TSS_DAA_PK_internal *pk_internal = (TSS_DAA_PK_internal *)malloc(sizeof(TSS_DAA_PK_internal)); char *read_buffer; pk_internal->modulus = bi_new_ptr(); BI_LOAD( pk_internal->modulus, file); pk_internal->capitalS = bi_new_ptr(); BI_LOAD( pk_internal->capitalS, file); pk_internal->capitalZ = bi_new_ptr(); BI_LOAD( pk_internal->capitalZ, file); pk_internal->capitalR0 = bi_new_ptr(); BI_LOAD( pk_internal->capitalR0, file); pk_internal->capitalR1 = bi_new_ptr(); BI_LOAD( pk_internal->capitalR1, file); pk_internal->gamma = bi_new_ptr(); BI_LOAD( pk_internal->gamma, file); pk_internal->capitalGamma = bi_new_ptr(); BI_LOAD( pk_internal->capitalGamma, file); pk_internal->rho = bi_new_ptr(); BI_LOAD( pk_internal->rho, file); pk_internal->capitalRReceiver = ALLOC_BI_ARRAY(); BI_LOAD_ARRAY( pk_internal->capitalRReceiver, file); pk_internal->capitalRIssuer = ALLOC_BI_ARRAY(); BI_LOAD_ARRAY( pk_internal->capitalRIssuer, file); pk_internal->capitalY = ALLOC_BI_ARRAY(); populate_capitalY( pk_internal); pk_internal->issuerBaseNameLength = read_int( file); read_buffer = read_str( file); pk_internal->issuerBaseName = malloc( pk_internal->issuerBaseNameLength); memcpy( pk_internal->issuerBaseName, read_buffer, pk_internal->issuerBaseNameLength); compute_capitalSprime( pk_internal); return pk_internal; } int save_DAA_PK_PROOF_internal(FILE *file, TSS_DAA_PK_PROOF_internal *proof) { int i; #ifdef DAA_DEBUG printf("save_DAA_PK_PROOF_internal"); #endif fprintf(file, "%d # %s.length\n", proof->length_challenge, "challenge"); fprintf(file, "%s\n", dump_byte_array( proof->length_challenge, proof->challenge)); fprintf(file, "%d # %s.length\n", proof->length_response, "response"); for (i = 0; i < proof->length_response; i++) { BI_SAVE_ARRAY( proof->response[i], file); } return 0; } /* load using */ /* allocation of: */ /* proof->challenge (BYTE*) */ /* response (bi_array_ptr) */ TSS_DAA_PK_PROOF_internal * load_DAA_PK_PROOF_internal(FILE *file) { TSS_DAA_PK_PROOF_internal *proof = (TSS_DAA_PK_PROOF_internal *)malloc(sizeof(TSS_DAA_PK_PROOF_internal)); char *read_buffer; int i; #ifdef DAA_DEBUG printf("load_DAA_PK_PROOF_internal"); #endif proof->length_challenge = read_int( file); read_buffer = read_str( file); proof->challenge = retrieve_byte_array( &(proof->length_challenge),read_buffer); proof->length_response = read_int( file); proof->response = (bi_array_ptr *)malloc( sizeof(bi_array_ptr) * proof->length_response); for (i = 0; i < proof->length_response; i++) { proof->response[i] = ALLOC_BI_ARRAY(); BI_LOAD_ARRAY( proof->response[i], file); } return proof; } TSS_DAA_CRED_ISSUER * load_TSS_DAA_CRED_ISSUER(FILE *file) { TSS_DAA_CRED_ISSUER *credential = (TSS_DAA_CRED_ISSUER *)malloc(sizeof(TSS_DAA_CRED_ISSUER)); char *read_buffer; int i, len; init_tss_version( credential); credential->capitalALength = read_int( file); read_buffer = read_str( file); credential->capitalA = retrieve_byte_array( &(credential->capitalALength), read_buffer); credential->eLength = read_int( file); read_buffer = read_str( file); credential->e = retrieve_byte_array( &(credential->eLength),read_buffer); credential->vPrimePrimeLength = read_int( file); read_buffer = read_str( file); credential->vPrimePrime = retrieve_byte_array(&(credential->vPrimePrimeLength), read_buffer); // attributes issuer credential->attributesIssuerLength = read_int( file); credential->attributesIssuer = malloc(credential->attributesIssuerLength*sizeof(BYTE*)); for( i=0; i < (int)credential->attributesIssuerLength; i++) { credential->attributesIssuer[i] = retrieve_byte_array( &len, read_buffer); } credential->cPrimeLength = read_int( file); read_buffer = read_str( file); credential->cPrime = retrieve_byte_array( &(credential->cPrimeLength),read_buffer); credential->sELength = read_int( file); read_buffer = read_str( file); credential->sE = retrieve_byte_array( &(credential->sELength),read_buffer); return credential; } int save_TSS_DAA_CRED_ISSUER(FILE *file, TSS_DAA_CRED_ISSUER *credential) { int i; fprintf(file, "%d # %s.length\n", credential->capitalALength, "capitalA"); fprintf(file, "%s\n", dump_byte_array( credential->capitalALength, credential->capitalA)); fprintf(file, "%d # %s.length\n", credential->eLength, "e"); fprintf(file, "%s\n", dump_byte_array( credential->eLength, credential->e)); fprintf(file, "%d # %s.length\n", credential->vPrimePrimeLength, "vPrimePrime"); fprintf(file, "%s\n", dump_byte_array( credential->vPrimePrimeLength, credential->vPrimePrime)); fprintf(file, "%d # %s\n", credential->attributesIssuerLength, "attributesIssuerLength"); for( i=0; i < (int)credential->attributesIssuerLength; i++) { fprintf(file, "%s\n", dump_byte_array( DAA_PARAM_SIZE_F_I / 8, credential->attributesIssuer[i])); } fprintf(file, "%d # %s.length\n", credential->cPrimeLength, "cPrime"); fprintf(file, "%s\n", dump_byte_array( credential->cPrimeLength, credential->cPrime)); fprintf(file, "%d # %s.length\n", credential->sELength, "sE"); fprintf(file, "%s\n", dump_byte_array( credential->sELength, credential->sE)); return 0; } TSS_DAA_CREDENTIAL * load_TSS_DAA_CREDENTIAL(FILE *file) { TSS_DAA_CREDENTIAL *credential = (TSS_DAA_CREDENTIAL *)malloc(sizeof(TSS_DAA_CREDENTIAL)); char *read_buffer; int i, len; TSS_DAA_PK_internal *pk_internal; TSS_DAA_PK *pk; init_tss_version( credential); credential->capitalALength = read_int( file); read_buffer = read_str( file); credential->capitalA = retrieve_byte_array( &(credential->capitalALength), read_buffer); credential->exponentLength = read_int( file); read_buffer = read_str( file); credential->exponent = retrieve_byte_array( &(credential->exponentLength), read_buffer); credential->vBar0Length = read_int( file); read_buffer = read_str( file); credential->vBar0 = retrieve_byte_array(&(credential->vBar0Length), read_buffer); credential->vBar1Length = read_int( file); read_buffer = read_str( file); credential->vBar1 = retrieve_byte_array(&(credential->vBar1Length), read_buffer); // attributes issuer credential->attributesLength = read_int( file); printf("attributesLength=%d\n", credential->attributesLength); credential->attributes = malloc(credential->attributesLength * sizeof( BYTE *)); for( i=0; i < (int)credential->attributesLength; i++) { read_buffer = read_str( file); credential->attributes[i] = retrieve_byte_array( &len, read_buffer); if( len != DAA_PARAM_SIZE_F_I / 8) { LogError("Error when parsing attributes"); LogError("\tattribute length:%d", len); LogError("\texpected length:%d", DAA_PARAM_SIZE_F_I / 8); return NULL; } } pk_internal = load_DAA_PK_internal( file); pk = i_2_e_TSS_DAA_PK( pk_internal, &normal_malloc, (TSS_HOBJECT)NULL); memcpy( &(credential->issuerPK), pk, sizeof(TSS_DAA_PK)); free( pk); free_TSS_DAA_PK_internal( pk_internal); credential->tpmSpecificEncLength = read_int( file); read_buffer = read_str( file); credential->tpmSpecificEnc = retrieve_byte_array( &(credential->tpmSpecificEncLength), read_buffer); credential->daaCounter = read_int( file); return credential; } int save_TSS_DAA_CREDENTIAL(FILE *file, TSS_DAA_CREDENTIAL *credential) { int i; TSS_DAA_PK_internal *pk_internal; fprintf(file, "%d # %s.length\n", credential->capitalALength, "capitalA"); fprintf(file, "%s\n", dump_byte_array( credential->capitalALength, credential->capitalA)); fprintf(file, "%d # %s.length\n", credential->exponentLength, "exponent"); fprintf(file, "%s\n", dump_byte_array( credential->exponentLength, credential->exponent)); fprintf(file, "%d # %s.length\n", credential->vBar0Length, "vBar0"); fprintf(file, "%s\n", dump_byte_array( credential->vBar0Length, credential->vBar0)); fprintf(file, "%d # %s.length\n", credential->vBar1Length, "vBar1"); fprintf(file, "%s\n", dump_byte_array( credential->vBar1Length, credential->vBar1)); fprintf(file, "%d # %s\n", credential->attributesLength, "attributesLength"); for( i=0; i < (int)credential->attributesLength; i++) { fprintf(file, "%s\n", dump_byte_array( DAA_PARAM_SIZE_F_I / 8, credential->attributes[i])); } pk_internal = e_2_i_TSS_DAA_PK( &(credential->issuerPK) ); save_DAA_PK_internal( file, pk_internal); free_TSS_DAA_PK_internal( pk_internal); fprintf(file, "%d # %s.length\n", credential->tpmSpecificEncLength, "tpmSpecificEnc"); fprintf(file, "%s\n", dump_byte_array( credential->tpmSpecificEncLength, credential->tpmSpecificEnc)); fprintf(file, "%d # daaCounter\n", credential->daaCounter); return 0; } trousers-0.3.15/src/tspi/daa/utils/0000775000175000017510000000000013663651711016407 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/utils/list.c0000664000175000017510000000274613663651711017537 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include "tsplog.h" list_ptr list_new( void) { list_ptr list = (list_ptr)malloc( sizeof( list_struct)); if( list == NULL) return NULL; list->head = NULL; return list; } void list_add(list_ptr list, void *obj) { list->current = (node_t *) malloc (sizeof(struct _list_t)); if (list->current == NULL) { LogError("[list_add] malloc of %d bytes failed", sizeof(struct _list_t)); return; } if( list->head == NULL) { list->head = list->current; } else list->previous->next = list->current; list->current->obj = obj; list->current->next = NULL; list->previous = list->current; } void list_dump(list_ptr list) { node_t *current; if( list->head == NULL) // if head has not been altered puts("no data"); // list is empty else { current = list->head; // go to first node do { printf("%d\n", (int)current->obj); // print value at current node current = current->next; // traverse through the list } while(current != NULL); // until current node is NULL } } void list_freeall(list_ptr list) { node_t *current = list->head; // go to first node node_t *next; if( list->head != NULL) { current = list->head; // go to first node do { next = current->next; free(current); current = next; } while(current != NULL); // until current node is NULL } } trousers-0.3.15/src/tspi/daa/daa_issuer/0000775000175000017510000000000013663651711017366 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/daa_issuer/issuer_init.c0000664000175000017510000001037213663651711022072 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include // for message digest #include #include #include "daa_structs.h" #include "daa_parameter.h" #include "trousers/tss.h" #include "spi_internal_types.h" #include "spi_utils.h" #include #include #include #include "tsplog.h" #include "tss/tcs.h" /* Verifies if the key is a valid endorsement key of a TPM. (TPM is good) return 0 if correct */ int verify_ek_and_daaCounter( UINT32 endorsementLength, BYTE *endorsementCredential, UINT32 daaCounter ) { // TODO return 0; } TSS_RESULT Tspi_DAA_IssueInit_internal( TSS_HDAA hDAA, // in TSS_HKEY issuerAuthPK, // in TSS_HKEY issuerKeyPair, // in (TSS_DAA_KEY_PAIR *) TSS_DAA_IDENTITY_PROOF identityProof, // in UINT32 capitalUprimeLength, // in BYTE* capitalUprime, // in UINT32 daaCounter, // in UINT32* nonceIssuerLength, // out BYTE** nonceIssuer, // out UINT32* authenticationChallengeLength, // out BYTE** authenticationChallenge, // out TSS_DAA_JOIN_ISSUER_SESSION* joinSession // out ) { TCS_CONTEXT_HANDLE tcsContext; TSS_RESULT result; BYTE *ne, *buffer; bi_t random; int length_ne; if( (result = obj_daa_get_tsp_context( hDAA, &tcsContext)) != TSS_SUCCESS) return result; // 1 & 2 : verify EK (and associated credentials) of the platform if( verify_ek_and_daaCounter( identityProof.endorsementLength, identityProof.endorsementCredential, daaCounter) != 0) { LogError("EK verification failed"); return TSS_E_INTERNAL_ERROR; } // 3 : choose a random nonce for the platform (ni) bi_new( random); bi_urandom( random, DAA_PARAM_LENGTH_MESSAGE_DIGEST * 8); buffer = bi_2_nbin( nonceIssuerLength, random); if( buffer == NULL) { LogError("malloc of %d bytes failed", *nonceIssuerLength); return TSPERR(TSS_E_OUTOFMEMORY); } *nonceIssuer = convert_alloc( tcsContext, *nonceIssuerLength, buffer); if (*nonceIssuer == NULL) { LogError("malloc of %d bytes failed", *nonceIssuerLength); free( buffer); return TSPERR(TSS_E_OUTOFMEMORY); } LogDebug("nonce Issuer[%d:%d]:%s", DAA_PARAM_LENGTH_MESSAGE_DIGEST, *nonceIssuerLength, dump_byte_array( *nonceIssuerLength , *nonceIssuer)); // 4 : choose a random nonce ne and encrypt it under EK bi_urandom( random, DAA_PARAM_LENGTH_MESSAGE_DIGEST * 8); ne = convert_alloc( tcsContext, length_ne, bi_2_nbin( &length_ne, random)); if (ne == NULL) { LogError("malloc of %d bytes failed", length_ne); free( buffer); free( nonceIssuer); return TSPERR(TSS_E_OUTOFMEMORY); } bi_free( random); *authenticationChallenge = (BYTE *)calloc_tspi( tcsContext, 256); // 256: RSA size if (*authenticationChallenge == NULL) { LogError("malloc of %d bytes failed", 256); free( buffer); free( nonceIssuer); free( ne); return TSPERR(TSS_E_OUTOFMEMORY); } result = Trspi_RSA_Encrypt( ne, // message to encrypt length_ne, // length message to encrypt *authenticationChallenge, // destination authenticationChallengeLength, // length destination identityProof.endorsementCredential, // public key identityProof.endorsementLength); // public key size if( result != TSS_SUCCESS) { LogError("Can not encrypt the Authentication Challenge"); free( buffer); free( nonceIssuer); free( ne); return TSS_E_INTERNAL_ERROR; } LogDebug("authenticationChallenge[%d:%d]:%s", DAA_PARAM_LENGTH_MESSAGE_DIGEST, *authenticationChallengeLength, dump_byte_array( *authenticationChallengeLength , *authenticationChallenge)); // 5 : save PK, PKDAA, (p', q'), U', daaCounter, ni, ne in joinSession // EK is not a member of joinSession but is already saved in identityProof joinSession->issuerAuthPK = issuerAuthPK; joinSession->issuerKeyPair = issuerKeyPair; memcpy( &(joinSession->identityProof), &identityProof, sizeof(TSS_DAA_IDENTITY_PROOF)); joinSession->capitalUprimeLength = capitalUprimeLength; joinSession->capitalUprime = capitalUprime; joinSession->daaCounter = daaCounter; joinSession->nonceIssuerLength = *nonceIssuerLength; joinSession->nonceIssuer = *nonceIssuer; joinSession->nonceEncryptedLength = length_ne; joinSession->nonceEncrypted = ne; return result; } trousers-0.3.15/src/tspi/daa/daa_issuer/prime_gen.c0000664000175000017510000001736213663651711021510 0ustar deboradebora/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ #include #include #include #include "bi.h" #include "list.h" #include "tsplog.h" static unsigned long *primes; static int primes_length; /* Generates a random number of bit_length bit length. The first two bits and the last bit of this * number are always set, therefore the number is odd and >= (2^(bit_length-1)+2^(bit_length-2)+1) * * bit_length: The length of the number to be generated, in bits * return: a random number of bitLength bit length with first and last bits set */ void random_odd_bi(bi_ptr bi, int bit_length) { if (bit_length > 0) { bi_urandom(bi, bit_length); //bi_generate_prime(bi, bit_length); bi_setbit(bi, 0); bi_setbit(bi, bit_length - 1); bi_setbit(bi, bit_length - 2); } } /* This method generates small prime numbers up to a specified bounds using the Sieve of * Eratosthenes algorithm. * * prime_bound: the upper bound for the primes to be generated * starting_prime: the first prime in the list of primes that is returned * return: list of primes up to the specified bound. Each prime is of type bi_ptr */ void generate_small_primes(int prime_bound, int starting_prime) { list_ptr res; int length; int *is_primes; int i; int k; int prime; node_t *current; primes_length = 0; res = list_new(); if (allocs == NULL) { LogError("malloc of list failed"); return; } if ((prime_bound <= 1) || (starting_prime > prime_bound)) return; if (starting_prime <= 2) { starting_prime = 2; list_add(res, bi_2); } length = (prime_bound - 1) >> 1; // length = (prime_bound -1) / 2; is_primes = (int *)malloc(sizeof(int)*length); if (is_primes == NULL) { LogError("malloc of %zd bytes failed", sizeof(int) * length); return; } for (i = 0; i < length; i++) is_primes[i] = 1; for (i = 0; i < length; i++) { if (is_primes[i] == 1) { prime = 2 * i + 3; for (k = i + prime; k < length; k+= prime) is_primes[k] = 0; if (prime >= starting_prime) { list_add(res, (void *)prime); primes_length++; } } } // converti the list to a table current = res->head; // go to first node primes = (unsigned long *)malloc(sizeof(unsigned long) * primes_length); if (primes == NULL) { LogError("malloc of %d bytes failed", sizeof(unsigned long)*primes_length); return; } i = 0; while (current != NULL) { primes[i++] = (unsigned long)current->obj; current = current->next; // traverse through the list } free(is_primes); list_freeall(res); } void prime_init() { generate_small_primes(16384, 3); } /* Test whether the provided pDash or p = 2*pDash + 1 are divisible by any of the small primes * saved in the listOfSmallPrimes. A limit for the largest prime to be tested against can be * specified, but it will be ignored if it exeeds the number of precalculated primes. * * p_dash: the number to be tested (p_dash) * prime_bound: the limit for the small primes to be tested against. */ static int test_small_prime_factors(const bi_ptr p_dash, const unsigned long prime_bound) { int sievePassed = 1; unsigned long r; unsigned long small_prime; bi_t temp; bi_new(temp); small_prime = 1; int i = 0; while (i < primes_length && small_prime < prime_bound ) { small_prime = primes[i++]; // r = p_dash % small_prime bi_mod_si(temp, p_dash, small_prime); r = bi_get_si(temp); // test if pDash = 0 (mod smallPrime) if (r == 0) { sievePassed = 0; break; } // test if p = 0 (mod smallPrime) (or r == smallPrime - r - 1) if (r == (small_prime - r - 1)) { sievePassed = 0; break; } } bi_free(temp); return sievePassed; } /* Tests if a is a Miller-Rabin witness for n * * a: number which is supposed to be the witness * n: number to be tested against * return: true if a is Miller-Rabin witness for n, false otherwise */ int is_miller_rabin_witness(const bi_ptr a, const bi_ptr n) { bi_t n_1; bi_t temp; bi_t _2_power_t; bi_t u; bi_t x0; bi_t x1; int t = -1; int i; bi_new(n_1); bi_new(temp); bi_new(_2_power_t); bi_new(u); // n1 = n - 1 bi_sub_si(n_1, n, 1); // test if n-1 = 2^t*u with t >= 1 && u even do { t++; // _2_power_t = bi_1 << t ( == 2 ^ t) bi_shift_left(_2_power_t, bi_1, t); // u = n_1 / (2 ^ t) bi_div(u, n_1, _2_power_t); } while (bi_equals_si(bi_mod(temp, u, bi_2), 0)); bi_new(x0); bi_new(x1); // x1 = (a ^ u ) % n bi_mod_exp(x1, a, u, n); // finished to use u, _2_power_t and temp bi_free(u); bi_free(_2_power_t); bi_free(temp); for (i = 0; i < t; i++) { bi_set(x0, x1); // x1 = (x0 ^ 2) % n bi_mod_exp(x1, x0, bi_2, n); if (bi_equals_si(x1, 1) && !bi_equals_si(x0, 1) && !bi_equals(x0, n_1) != 0) { bi_free(x0); bi_free(x1); bi_free(n_1); return 1; } } bi_free(x0); bi_free(x1); bi_free(n_1); if (!bi_equals(x1, bi_1)) return 1; return 0; } bi_ptr compute_trivial_safe_prime(bi_ptr result, int bit_length) { LogDebugFn("Enter"); do { bi_generate_prime(result, bit_length-1); bi_shift_left(result, result, 1); // result := result << 1 bi_add_si(result, result, 1); // result := result -1 if (getenv("TSS_DEBUG_OFF") == NULL) { printf("."); fflush(stdout); } } while (bi_is_probable_prime(result)==0); return result; } /* The main method to compute a random safe prime of the specified bit length. * IMPORTANT: The computer prime will have two first bits and the last bit set to 1 !! * i.e. > (2^(bitLength-1)+2^(bitLength-2)+1). This is done to be sure that if two primes of * bitLength n are multiplied, the result will have the bitLenght of 2*n exactly This * implementation uses the algorithm proposed by Ronald Cramer and Victor Shoup in "Signature * Schemes Based on the strong RSA Assumption" May 9, 2000. * * bitLength: the bit length of the safe prime to be computed. * return: a number which is considered to be safe prime */ bi_ptr compute_safe_prime(bi_ptr p, int bit_length) { bi_ptr p_dash; bi_ptr temp_p; bi_ptr p_minus_1; int stop; unsigned long prime_bound; LogDebug("compute Safe Prime: length: %d bits\n", bit_length); p_dash = bi_new_ptr(); temp_p = bi_new_ptr(); p_minus_1 = bi_new_ptr(); /* some heuristic checks to limit the number of small primes to check against and the * number of Miller-Rabin primality tests at the end */ if (bit_length <= 256) { prime_bound = 768; } else if (bit_length <= 512) { prime_bound = 3072; } else if (bit_length <= 768) { prime_bound = 6144; } else if (bit_length <= 1024) { prime_bound = 1024; } else { prime_bound = 16384; } do { stop = 0; /* p_dash = generated random with basic bit settings (odd) */ random_odd_bi(p_dash, bit_length - 1); if (test_small_prime_factors(p_dash, prime_bound) == 0) { LogDebugFn("1"); continue; } /* test if p_dash or p are divisible by some small primes */ if (is_miller_rabin_witness(bi_2, p_dash)) { LogDebugFn("2"); continue; } /* test if 2^(pDash) = +1/-1 (mod p) * bi can not handle negative operation, we compare to (p-1) instead of -1 * calculate p = 2*pDash+1 -> (pDash << 1) + 1 */ bi_shift_left(p, p_dash, 1); bi_add(p, p, bi_1); // p_minus_1:= p - 1 bi_sub(p_minus_1, p, bi_1); // temp_p := ( 2 ^ p_dash ) mod p bi_mod_exp(temp_p, bi_2, p_dash, p); if (!bi_equals_si(temp_p, 1) && !bi_equals(temp_p, p_minus_1) ) { LogDebugFn("3"); continue; } // test if pDash or p are divisible by some small primes if (is_miller_rabin_witness(bi_2, p_dash)) { LogDebugFn("4"); continue; } // test the library dependent probable_prime if (bi_is_probable_prime(p_dash)) stop = 1; } while (stop == 0); bi_free(p_minus_1); bi_free(temp_p); bi_free(p_dash); LogDebug("found Safe Prime: %s bits", bi_2_hex_char(p)); return p; } trousers-0.3.15/src/tspi/daa/daa_issuer/keypair_generator.c0000664000175000017510000002462213663651711023252 0ustar deboradebora/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include "bi.h" #include "list.h" #include "daa_structs.h" #include "daa_parameter.h" #include "issuer.h" static const int ELEMENT = 0; static const int EXPONENT = 1; extern void prime_init(); extern void compute_safe_prime(bi_ptr result, int bit_length, int prime_certainty); bi_ptr compute_random_number_star( bi_ptr result, const bi_ptr element) { bi_t bi_tmp; bi_new(bi_tmp); do { compute_random_number(result, element); } while (!bi_equals_si(bi_gcd(bi_tmp, result, element), 1)); bi_free(bi_tmp); return result; } /* Compute a generator of the group of quadratic residue modulo n. The * generator will not be part of the subgroup of size 2. * n: modulus */ void compute_generator_quadratic_residue(bi_t qr, bi_t n) { bi_t bi_tmp, bi_tmp1; bi_new(bi_tmp); bi_new(bi_tmp1); do { compute_random_number(qr, n); // qr = (qr ^ bi_2) % n bi_mod_exp(qr, qr, bi_2, n); } while (bi_cmp_si(qr, 1) == 0 || bi_cmp_si(bi_gcd(bi_tmp, n, bi_sub_si(bi_tmp1, qr, 1)), 1) != 0); bi_free(bi_tmp); bi_free(bi_tmp1); } void compute_group_element(bi_ptr result[], bi_ptr generator, bi_ptr product_PQprime, bi_ptr n) { bi_t bi_tmp; bi_new(bi_tmp); compute_random_number(bi_tmp, product_PQprime); // bi_tmp++ bi_inc(bi_tmp); // result[ELEMENT] := (generator ^ bi_tmp) mod n bi_mod_exp(result[ELEMENT], generator, bi_tmp, n); bi_set(result[EXPONENT], bi_tmp); bi_free(bi_tmp); } TSS_RESULT generate_key_pair(UINT32 num_attributes_issuer, UINT32 num_attributes_receiver, UINT32 base_nameLength, BYTE* base_name, KEY_PAIR_WITH_PROOF_internal** key_pair_with_proof) { TSS_RESULT result = TSS_SUCCESS; int length_mod = DAA_PARAM_SIZE_RSA_MODULUS; int length; int i; TSS_DAA_PK_internal *public_key = NULL; BYTE *buffer = NULL; bi_ptr pPrime = NULL; bi_ptr qPrime = NULL; bi_ptr n = NULL; bi_ptr p = NULL; bi_ptr q = NULL; bi_ptr capital_s = NULL; bi_ptr capital_z = NULL; bi_ptr product_PQprime = NULL; bi_ptr pair[2] = {NULL, NULL}; bi_ptr xz = NULL; bi_ptr capital_r0 = NULL; bi_ptr x0 = NULL; bi_ptr capital_r1 = NULL; bi_ptr x1 = NULL; bi_array_ptr x = NULL; bi_array_ptr capital_r = NULL; bi_array_ptr capitalRReceiver = NULL; bi_array_ptr capitalRIssuer = NULL; bi_ptr gamma = NULL; bi_ptr capital_gamma = NULL; bi_ptr rho = NULL; bi_ptr r = NULL; bi_ptr rho_double = NULL; bi_t bi_tmp, bi_tmp1, bi_tmp2; bi_new(bi_tmp); bi_new(bi_tmp1); bi_new(bi_tmp2); *key_pair_with_proof = NULL; // STEP 1 LogDebug("Step 1 of 8 - compute modulus n (please wait: long process)\n"); // FUTURE USAGE if( IS_DEBUG==0) prime_init(); p = bi_new_ptr(); q = bi_new_ptr(); n = bi_new_ptr(); do { // FUTURE USAGE /* compute_safe_prime( p, length_mod / 2); do { compute_safe_prime( q, length_mod - (length_mod >> 1)); } while( bi_cmp( p, q) ==0); } else */ { bi_generate_safe_prime(p, length_mod / 2); bi_generate_safe_prime(q, length_mod - (length_mod / 2)); LogDebug("."); } // n = p*q bi_mul(n, p, q); } while(bi_length(n) != length_mod); pPrime = bi_new_ptr(); bi_sub(pPrime, p, bi_1); // pPrime = (p - 1) >> 1 bi_shift_right(pPrime, pPrime, 1); qPrime = bi_new_ptr(); bi_sub(qPrime, q, bi_1); // qPrime = (q - 1) >> 1 bi_shift_right( qPrime, qPrime, 1); if (bi_is_probable_prime(pPrime) == 0) { LogError("!! pPrime not a prime number: %s", bi_2_hex_char(pPrime)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto close; } if (bi_is_probable_prime(qPrime) == 0) { LogError("!! qPrime not a prime number: %s", bi_2_hex_char(qPrime)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto close; } LogDebug("p=%s", bi_2_hex_char(p)); LogDebug("q=%s", bi_2_hex_char(q)); LogDebug("n=%s", bi_2_hex_char(n)); // STEP 2 LogDebug("Step 2 - choose random generator of QR_n"); capital_s = bi_new_ptr(); compute_generator_quadratic_residue(capital_s, n); LogDebug("capital_s=%s", bi_2_hex_char(capital_s)); // STEP 3 & 4 LogDebug("Step 3 & 4 - compute group elements"); product_PQprime = bi_new_ptr(); bi_mul( product_PQprime, pPrime, qPrime); pair[ELEMENT] = bi_new_ptr(); pair[EXPONENT] = bi_new_ptr(); LogDebug("product_PQprime=%s [%ld]", bi_2_hex_char(product_PQprime), bi_nbin_size(product_PQprime)); compute_group_element(pair, capital_s, product_PQprime, n); capital_z = bi_new_ptr(); bi_set(capital_z, pair[ELEMENT]); xz = bi_new_ptr(); bi_set(xz, pair[EXPONENT]); // attributes bases compute_group_element(pair, capital_s, product_PQprime, n); capital_r0 = bi_new_ptr(); bi_set(capital_r0, pair[ELEMENT]); x0 = bi_new_ptr(); bi_set(x0, pair[EXPONENT]); compute_group_element(pair, capital_s, product_PQprime, n); capital_r1 = bi_new_ptr(); bi_set(capital_r1, pair[ELEMENT]); x1 = bi_new_ptr(); bi_set(x1, pair[EXPONENT]); // additional attribute bases length = num_attributes_issuer + num_attributes_receiver; x = ALLOC_BI_ARRAY(); bi_new_array(x, length); capital_r = ALLOC_BI_ARRAY(); bi_new_array(capital_r, length); for (i = 0; i < length; i++) { compute_group_element(pair, capital_s, product_PQprime, n); bi_set(capital_r->array[i], pair[ELEMENT]); bi_set(x->array[i], pair[EXPONENT]); } // split capitalR into Receiver and Issuer part capitalRReceiver = ALLOC_BI_ARRAY(); bi_new_array2(capitalRReceiver, num_attributes_receiver); for (i = 0; i < num_attributes_receiver; i++) capitalRReceiver->array[i] = capital_r->array[i]; capitalRIssuer = ALLOC_BI_ARRAY(); bi_new_array2(capitalRIssuer, num_attributes_issuer); for (i = 0; i < num_attributes_issuer; i++) capitalRIssuer->array[i] = capital_r->array[i + num_attributes_receiver]; // STEP 6a LogDebug("Step 6"); gamma = bi_new_ptr(); capital_gamma = bi_new_ptr(); rho = bi_new_ptr(); r = bi_new_ptr(); rho_double = bi_new_ptr(); bi_generate_prime(rho, DAA_PARAM_SIZE_RHO); if (bi_length(rho) != DAA_PARAM_SIZE_RHO) { LogError("rho bit length=%ld", bi_length(rho)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto close; } do { length = DAA_PARAM_SIZE_MODULUS_GAMMA - DAA_PARAM_SIZE_RHO; do { bi_urandom(r, length); } while(bi_length(r) != length || bi_equals_si(bi_mod(bi_tmp, r, rho), 0)); // rho is not a dividor of r bi_mul( capital_gamma, rho, r); // capital_gamma ++ bi_inc( capital_gamma); #ifdef DAA_DEBUG if (bi_length(capital_gamma) != DAA_PARAM_SIZE_MODULUS_GAMMA) { printf("|"); fflush(stdout); } else { printf("."); fflush(stdout); } #endif } while (bi_length(capital_gamma) != DAA_PARAM_SIZE_MODULUS_GAMMA || bi_is_probable_prime(capital_gamma) == 0 ); // STEP 6b if (bi_equals(bi_sub_si(bi_tmp, capital_gamma, 1), bi_mod(bi_tmp1, bi_mul(bi_tmp2, rho, r), n)) == 0) { LogWarn("capital_gamma-1 != (rho * r) mod n tmp=%s tmp1=%s", bi_2_hex_char(bi_tmp), bi_2_hex_char(bi_tmp1)); } if (bi_equals(bi_div(bi_tmp, bi_sub_si(bi_tmp1, capital_gamma, 1), rho), r ) == 0) { LogWarn("( capital_gamma - 1)/rho != r"); } LogDebug("capital_gamma=%s\n", bi_2_hex_char(capital_gamma)); do { compute_random_number_star(gamma, capital_gamma); // gamma = (gamma ^ r) mod capital_gamma bi_mod_exp(gamma, gamma, r, capital_gamma); } while (bi_equals(gamma, bi_1)); // STEP 7 buffer = (BYTE *)malloc(base_nameLength); if (buffer == NULL) { LogError("malloc of %u bytes failed", base_nameLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } memcpy(buffer, base_name, base_nameLength); // all fields are linked to the struct with direct reference public_key = create_DAA_PK(n, capital_s, capital_z, capital_r0, capital_r1, gamma, capital_gamma, rho, capitalRReceiver, capitalRIssuer, base_nameLength, buffer); // STEP 8 // TODO dynamically load DAAKeyCorrectnessProof LogDebug("Step 8: generate proof (please wait: long process)"); TSS_DAA_PK_PROOF_internal *correctness_proof = generate_proof(product_PQprime, public_key, xz, x0, x1, x); if (correctness_proof == NULL) { LogError("creation of correctness_proof failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } *key_pair_with_proof = (KEY_PAIR_WITH_PROOF_internal *) malloc(sizeof(KEY_PAIR_WITH_PROOF_internal)); if (*key_pair_with_proof == NULL) { LogError("malloc of %zd bytes failed", sizeof(KEY_PAIR_WITH_PROOF_internal)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } (*key_pair_with_proof)->pk = public_key; (*key_pair_with_proof)->proof = correctness_proof; // all fields are linked to the struct with direct reference (*key_pair_with_proof)->private_key = create_TSS_DAA_PRIVATE_KEY(pPrime, qPrime); close: if (result != TSS_SUCCESS) { // remove everything, even numbers that should be stored in a struct FREE_BI(pPrime); // kept if no error FREE_BI(qPrime); // kept if no error FREE_BI(n); // kept if no error // FREE_BI( p); // FREE_BI( q); FREE_BI(capital_s); // kept if no error FREE_BI(capital_z); // kept if no error // FREE_BI(product_PQprime); // FREE_BI(pair[ELEMENT]); // FREE_BI(pair[EXPONENT]); // FREE_BI(xz); FREE_BI(capital_r0); // kept if no error // FREE_BI(x0); FREE_BI(capital_r1); // kept if no error // FREE_BI( x1); // bi_array_ptr x = NULL; // bi_array_ptr capital_r = NULL; // bi_array_ptr capitalRReceiver = NULL; // bi_array_ptr capitalRIssuer = NULL; FREE_BI( gamma); // kept if no error FREE_BI( capital_gamma); // kept if no error FREE_BI( rho); // kept if no error // FREE_BI( r); // FREE_BI( rho_double); if (buffer!=NULL) free(buffer); if (public_key != NULL) free(public_key); if (*key_pair_with_proof != NULL) free(*key_pair_with_proof); } /* Fields kept by structures TSS_DAA_PK: n capital_s capital_z capital_r0 capital_r1 gamma capital_gamma rho capitalRReceiver capitalRIssuer base_nameLength buffer TSS_DAA_PRIVATE_KEY: pPrime qPrime */ bi_free(bi_tmp); bi_free(bi_tmp1); bi_free(bi_tmp2); FREE_BI(p); FREE_BI(q); FREE_BI(product_PQprime); FREE_BI(pair[ELEMENT]); FREE_BI(pair[EXPONENT]); FREE_BI(xz); FREE_BI(x0); FREE_BI(x0); // bi_array_ptr x = NULL; // bi_array_ptr capital_r = NULL; // bi_array_ptr capitalRReceiver = NULL; // bi_array_ptr capitalRIssuer = NULL; FREE_BI(r); FREE_BI(rho_double); return result; } trousers-0.3.15/src/tspi/daa/daa_issuer/issue_credential.c0000664000175000017510000007015613663651711023065 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include // for message digest #include #include #include "daa_structs.h" #include "daa_parameter.h" #include "trousers/tss.h" #include "spi_internal_types.h" #include "spi_utils.h" #include #include #include #include "tsplog.h" #include "tss/tcs.h" #include "platform.h" // to include compute_zeta #include "verifier.h" // from UBigInteger (computePrime) // remark: the type bi_t (bi_ptr) can not used a certaintity for probable_prime // as used in UbigInteger. (certaintity: DAA_PARAM_SAFETY) void compute_prime( bi_ptr e, int length, int interval) { do { bi_urandom( e, interval - 1); bi_setbit( e, length - 1); } while( bi_is_probable_prime( e) == 0); } /* code derived from verifyAuthenticity (IssuerTransaction.java) */ TSS_RESULT verify_authentificity(TSS_DAA_CREDENTIAL_REQUEST *credentialRequest, TSS_DAA_JOIN_ISSUER_SESSION *joinSession) { EVP_MD_CTX *mdctx; BYTE *modulus_N0_bytes; BYTE *digest_n0; BYTE *contextHash; BYTE *capitalUPrime_bytes; BYTE *hash; UINT32 digest_n0Length, contextHashLength, hashLength, daaCount; bi_ptr capitalUPrime =NULL; bi_ptr modulus_N0 = NULL; TSS_RESULT result = TSS_SUCCESS; char *buffer; modulus_N0 = bi_new_ptr(); buffer = BN_bn2hex( ((RSA *)joinSession->issuerAuthPK)->n); if( buffer == NULL) { LogError("malloc of hexadecimal representation failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set_as_hex( modulus_N0, buffer); // in TPM, N0 is hashed by hashing the scratch (256 bytes) so it must // be formatted according to the scratch size (TPM_DAA_SIZE_issuerModulus) modulus_N0_bytes = (BYTE *)malloc( TPM_DAA_SIZE_issuerModulus); if (modulus_N0_bytes == NULL) { LogError("malloc of %d bytes failed", TPM_DAA_SIZE_issuerModulus); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_byte_array( modulus_N0_bytes, TPM_DAA_SIZE_issuerModulus, modulus_N0); bi_free_ptr( modulus_N0); if( TPM_DAA_SIZE_issuerModulus * 8 != DAA_PARAM_KEY_SIZE) { LogError("TPM_DAA_SIZE_issuerModulus * 8 (%d) != DAA_PARAM_KEY_SIZE(%d)", TPM_DAA_SIZE_issuerModulus*8, DAA_PARAM_KEY_SIZE); return TSS_E_INTERNAL_ERROR; } mdctx = EVP_MD_CTX_create(); EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); // digestN0 = hash( modulus_N0) see Appendix B of spec. and TPM join stage 7 and 8 EVP_DigestUpdate(mdctx, modulus_N0_bytes, TPM_DAA_SIZE_issuerModulus); digest_n0Length = EVP_MD_CTX_size(mdctx); digest_n0 = (BYTE *)malloc( digest_n0Length); if (digest_n0 == NULL) { LogError("malloc of %d bytes failed", digest_n0Length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } EVP_DigestFinal(mdctx, digest_n0, NULL); // test if credentialRequest->authenticationProof = // H( H( U, daaCount, H(n0), joinSession->nonceEncrypted)) EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); // enlarge capitalU to 256 (TPM_DAA_SIZE_issuerModulus) // allocation capitalUPrime = bi_set_as_nbin( joinSession->capitalUprimeLength, joinSession->capitalUprime); capitalUPrime_bytes = (BYTE *)malloc( TPM_DAA_SIZE_issuerModulus); if (capitalUPrime_bytes == NULL) { LogError("malloc of %d bytes failed", TPM_DAA_SIZE_issuerModulus); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_byte_array( capitalUPrime_bytes, TPM_DAA_SIZE_issuerModulus, capitalUPrime); EVP_DigestUpdate(mdctx, capitalUPrime_bytes, TPM_DAA_SIZE_issuerModulus); bi_free_ptr( capitalUPrime); daaCount = htonl( joinSession->daaCounter); EVP_DigestUpdate(mdctx, &daaCount, sizeof(UINT32)); EVP_DigestUpdate(mdctx, digest_n0, digest_n0Length); contextHashLength = EVP_MD_CTX_size(mdctx); contextHash = (BYTE *)malloc( contextHashLength); if (contextHash == NULL) { LogError("malloc of %d bytes failed", contextHashLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } EVP_DigestFinal(mdctx, contextHash, NULL); EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); LogDebug("PK(0).n=%s", dump_byte_array( TPM_DAA_SIZE_issuerModulus, modulus_N0_bytes)); LogDebug("digestN0h=%s", dump_byte_array( digest_n0Length, digest_n0)); LogDebug("UPrime=%s", dump_byte_array( TPM_DAA_SIZE_issuerModulus, capitalUPrime_bytes)); LogDebug("daaCount=%4x", daaCount); LogDebug("contextHash[%d]=%s", contextHashLength, dump_byte_array( contextHashLength, contextHash)); EVP_DigestUpdate(mdctx, contextHash, contextHashLength); EVP_DigestUpdate(mdctx, joinSession->nonceEncrypted, joinSession->nonceEncryptedLength); hashLength = EVP_MD_CTX_size(mdctx); hash = (BYTE *)malloc( hashLength); if (hash == NULL) { LogError("malloc of %d bytes failed", hashLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } EVP_DigestFinal(mdctx, hash, NULL); if( credentialRequest->authenticationProofLength != hashLength || memcmp( credentialRequest->authenticationProof, hash, hashLength) != 0) { LogError("Verification of authenticationProof failed - Step 2.b"); LogError("credentialRequest->authenticationProof[%d]=%s", credentialRequest->authenticationProofLength, dump_byte_array( credentialRequest->authenticationProofLength, credentialRequest->authenticationProof)); LogError("internal cByte[%d]=%s", hashLength, dump_byte_array( hashLength, hash)); result = TSS_E_DAA_AUTHENTICATION_ERROR; goto close; } else LogDebug("verify_authenticity Done:%s", dump_byte_array( hashLength, hash)); close: EVP_MD_CTX_destroy(mdctx); free( contextHash); free( digest_n0); free( capitalUPrime_bytes); free( hash); return result; } TSS_RESULT compute_join_challenge_issuer( TSS_DAA_PK_internal *pk_intern, bi_ptr v_prime_prime, bi_ptr capitalA, bi_ptr capital_Atilde, UINT32 nonceReceiverLength, BYTE *nonceReceiver, UINT32 *c_primeLength, BYTE **c_prime) { // out allocation EVP_MD_CTX *mdctx; BYTE *encoded_pk; BYTE *byte_array; UINT32 encoded_pkLength; byte_array = (BYTE *)malloc( DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE / 8); // allocation if (byte_array == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE / 8); return TSPERR(TSS_E_OUTOFMEMORY); } mdctx = EVP_MD_CTX_create(); EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); encoded_pk = encoded_DAA_PK_internal( &encoded_pkLength, pk_intern); EVP_DigestUpdate(mdctx, encoded_pk, encoded_pkLength); LogDebug( "issuerPk: %s", dump_byte_array( encoded_pkLength, encoded_pk)); bi_2_byte_array( byte_array, DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE / 8, v_prime_prime); EVP_DigestUpdate(mdctx, byte_array, DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE / 8); LogDebug( "vPrimePrime: %s", dump_byte_array( DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE / 8, byte_array)); free( byte_array); // allocation byte_array = (BYTE *)malloc( DAA_PARAM_SIZE_RSA_MODULUS / 8); if (byte_array == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_SIZE_RSA_MODULUS / 8); return TSPERR(TSS_E_OUTOFMEMORY); } bi_2_byte_array( byte_array, DAA_PARAM_SIZE_RSA_MODULUS / 8, capitalA); EVP_DigestUpdate(mdctx, byte_array, DAA_PARAM_SIZE_RSA_MODULUS / 8); LogDebug( "capitalA: %s", dump_byte_array( DAA_PARAM_SIZE_RSA_MODULUS / 8, byte_array)); bi_2_byte_array( byte_array, DAA_PARAM_SIZE_RSA_MODULUS / 8, capital_Atilde); EVP_DigestUpdate(mdctx, byte_array, DAA_PARAM_SIZE_RSA_MODULUS / 8); LogDebug( "capital_Atilde: %s", dump_byte_array( DAA_PARAM_SIZE_RSA_MODULUS / 8, byte_array)); EVP_DigestUpdate(mdctx, nonceReceiver, nonceReceiverLength); LogDebug( "nonceReceiver: %s", dump_byte_array( nonceReceiverLength, nonceReceiver)); *c_primeLength = EVP_MD_CTX_size(mdctx); *c_prime = (BYTE *)malloc( *c_primeLength); if (*c_prime == NULL) { LogError("malloc of %d bytes failed", *c_primeLength); free( byte_array); return TSPERR(TSS_E_OUTOFMEMORY); } LogDebug( "c_prime: %s", dump_byte_array( *c_primeLength, *c_prime)); EVP_DigestFinal(mdctx, *c_prime, NULL); EVP_MD_CTX_destroy(mdctx); free( byte_array); return TSS_SUCCESS; } // inspired by computeCredentialProof (IssuerTransaction.java) TSS_RESULT compute_credential_proof( TSS_DAA_PK_internal *pk_intern, bi_ptr capital_A, bi_ptr fraction_A, bi_ptr eInverse, bi_ptr v_prime_prime, bi_ptr productPQprime, UINT32 noncePlatformLength, BYTE *noncePlatform, bi_ptr *c_prime, // out bi_ptr *s_e // out ) { bi_ptr random_E = bi_new_ptr(); bi_ptr capital_Atilde = bi_new_ptr(); BYTE *c_prime_bytes; UINT32 c_primeLength; bi_urandom( random_E, bi_length( productPQprime) + DAA_PARAM_SAFETY_MARGIN * 8); bi_mod( random_E, random_E, productPQprime); bi_inc( random_E); bi_mod_exp( capital_Atilde, fraction_A, random_E, pk_intern->modulus); compute_join_challenge_issuer( pk_intern, v_prime_prime, capital_A, capital_Atilde, noncePlatformLength, noncePlatform, &c_primeLength, &c_prime_bytes); // allocation *c_prime = bi_set_as_nbin( c_primeLength, c_prime_bytes); // allocation *s_e = bi_new_ptr(); bi_mul( *s_e, *c_prime, eInverse); bi_mod( *s_e, *s_e, productPQprime); bi_sub( *s_e, random_E, *s_e); bi_mod( *s_e, *s_e, productPQprime); bi_free_ptr( capital_Atilde); bi_free_ptr( random_E); free( c_prime_bytes); return TSS_SUCCESS; } // from IssuerTransaction.java (joinStep2) // stacks: TCGApplication.java (retrieveDAACredential) -> Issuer.java(issueCredential) TSPICALL Tspi_DAA_IssueCredential_internal ( TSS_HDAA hDAA, // in UINT32 attributesIssuerLength, // in BYTE** attributesIssuer, // in TSS_DAA_CREDENTIAL_REQUEST credentialRequest, // in TSS_DAA_JOIN_ISSUER_SESSION joinSession, // in TSS_DAA_CRED_ISSUER* credIssuer // out ) { TSS_RESULT result = TSS_SUCCESS; TCS_CONTEXT_HANDLE tcsContext; bi_ptr capitalU_hat_prime = NULL; bi_ptr tmp1; bi_ptr tmp2; bi_ptr sa_i; bi_ptr capitalU_prime = NULL; bi_ptr c = NULL; bi_ptr n = NULL; bi_ptr sf0 = NULL; bi_ptr sf1 = NULL; bi_ptr sv_prime = NULL; bi_ptr capitalR0 = NULL; bi_ptr capitalR1 = NULL; bi_ptr capitalS = NULL; bi_ptr capitalU = NULL; bi_ptr capitalU_hat = NULL; bi_ptr capitalN_hat_i = NULL; bi_ptr exp = NULL; bi_ptr product_attr_receiver = NULL; bi_ptr product_attr_issuer = NULL; bi_ptr sv_tilde_prime = NULL; bi_ptr capital_ni = NULL; bi_ptr v_hat = NULL; bi_ptr fraction_A = NULL; bi_ptr capitalA = NULL; bi_ptr e = NULL; bi_ptr eInverse = NULL; bi_ptr v_prime_prime = NULL; bi_ptr c_prime = NULL; bi_ptr s_e = NULL; bi_ptr zeta = NULL; TSS_DAA_PK *daa_pk_extern; TSS_DAA_PK_internal *pk_intern; TSS_DAA_PRIVATE_KEY *private_key; UINT32 i, chLength, challengeLength, length, interval; EVP_MD_CTX *mdctx; BYTE *ch = NULL, *challenge = NULL; tmp1 = bi_new_ptr(); tmp2 = bi_new_ptr(); if( tmp1 == NULL || tmp2 == NULL) { LogError("malloc of BI <%s> failed", "tmp1, tmp2"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } if( (result = obj_daa_get_tsp_context( hDAA, &tcsContext)) != TSS_SUCCESS) goto close; // 1 TODO Check the TPM rogue list // 2 verify the authentication proof of the TPM result = verify_authentificity(&credentialRequest, &joinSession); if( result != TSS_SUCCESS) goto close; daa_pk_extern = (TSS_DAA_PK *)(((TSS_DAA_KEY_PAIR *)joinSession.issuerKeyPair)->public_key); pk_intern = e_2_i_TSS_DAA_PK( daa_pk_extern); n = bi_set_as_nbin( daa_pk_extern->modulusLength, daa_pk_extern->modulus); // allocation if( n == NULL) { LogError("malloc of BI <%s> failed", "n"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capitalR0 = bi_set_as_nbin( daa_pk_extern->capitalR0Length, daa_pk_extern->capitalR0); // allocation if( capitalR0 == NULL) { LogError("malloc of BI <%s> failed", "capitalR0"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capitalR1 = bi_set_as_nbin( daa_pk_extern->capitalR1Length, daa_pk_extern->capitalR1); // allocation if( capitalR1 == NULL) { LogError("malloc of BI <%s> failed", "capitalR1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capitalS = bi_set_as_nbin( daa_pk_extern->capitalSLength, daa_pk_extern->capitalS); // allocation if( capitalS == NULL) { LogError("malloc of BI <%s> failed", "capitalS"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capitalU = bi_set_as_nbin( credentialRequest.capitalULength, credentialRequest.capitalU); // allocation if( capitalU == NULL) { LogError("malloc of BI <%s> failed", "capitalU"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } sv_tilde_prime = bi_set_as_nbin( credentialRequest.sVtildePrimeLength, credentialRequest.sVtildePrime); // allocation if( sv_tilde_prime == NULL) { LogError("malloc of BI <%s> failed", "sv_tilde_prime"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capital_ni = bi_set_as_nbin( credentialRequest.capitalNiLength, credentialRequest.capitalNi); // allocation if( capital_ni == NULL) { LogError("malloc of BI <%s> failed", "capital_ni"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // 3 Verify the correctness proof of the credential request // 3.a TODO commitments // 3.b capitalU_prime = bi_set_as_nbin( joinSession.capitalUprimeLength, joinSession.capitalUprime); // allocation if( capitalU_prime == NULL) { LogError("malloc of BI <%s> failed", "capitalU_prime"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } sf0 = bi_set_as_nbin( credentialRequest.sF0Length, credentialRequest.sF0); // allocation if( sf0 == NULL) { LogError("malloc of BI <%s> failed", "sf0"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } sf1 = bi_set_as_nbin( credentialRequest.sF1Length, credentialRequest.sF1); // allocation if( sf1 == NULL) { LogError("malloc of BI <%s> failed", "sf1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } sv_prime = bi_set_as_nbin( credentialRequest.sVprimeLength, credentialRequest.sVprime); // allocation if( sv_prime == NULL) { LogError("malloc of BI <%s> failed", "sv_prime"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } c = bi_set_as_nbin( credentialRequest.challengeLength, credentialRequest.challenge); // allocation if( c == NULL) { LogError("malloc of BI <%s> failed", "c"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capitalU_hat_prime = bi_new_ptr();// allocation if( capitalU_hat_prime == NULL) { LogError("malloc of BI <%s> failed", "c"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // capitalU_hat_prime = capitalU_prime ~% n bi_invert_mod( capitalU_hat_prime, capitalU_prime, n); // capitalU_hat_prime = ( capitalU_hat_prime ^ c ) % n bi_mod_exp( capitalU_hat_prime, capitalU_hat_prime, c, n); // capitalU_hat_prime = ( capitalU_hat_prime * ( capitalR0 ^ sf0)) % n bi_mod_exp( tmp1, capitalR0, sf0, n); bi_mul( capitalU_hat_prime, capitalU_hat_prime, tmp1); bi_mod( capitalU_hat_prime, capitalU_hat_prime, n); // capitalU_hat_prime = ( capitalU_hat_prime * ( capitalR1 ^ sf1)) % n bi_mod_exp( tmp1, capitalR1, sf1, n); bi_mul( capitalU_hat_prime, capitalU_hat_prime, tmp1); bi_mod( capitalU_hat_prime, capitalU_hat_prime, n); // capitalU_hat_prime = ( capitalU_hat_prime * ( capitalS ^ sv_prime)) % n bi_mod_exp( tmp1, capitalS, sv_prime, n); bi_mul( capitalU_hat_prime, capitalU_hat_prime, tmp1); bi_mod( capitalU_hat_prime, capitalU_hat_prime, n); // verify blinded encoded attributes of the Receiver product_attr_receiver = bi_new_ptr(); bi_set( product_attr_receiver, bi_1); length = ( DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES + 7) / 8; for( i=0; i failed", "sa_i"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( tmp1, pk_intern->capitalRReceiver->array[i], sa_i, n); bi_mul( product_attr_receiver, product_attr_receiver, tmp1); bi_mod( product_attr_receiver, product_attr_receiver, n); bi_free_ptr( sa_i); } // tmp1 = ( 1 / capitalU ) % n bi_invert_mod( tmp1, capitalU, n); capitalU_hat = bi_new_ptr(); if( capitalU_hat == NULL) { LogError("malloc of BI <%s> failed", "capitalU_hat"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mul( capitalU_hat, capitalU_prime, tmp1); // capitalU_hat = capitalU_prime / capitalU bi_mod( capitalU_hat, capitalU_hat, n); // capital_Uhat = ( (capital_Uhat ^ c ) % n bi_mod_exp( capitalU_hat, capitalU_hat, c, n); // capital_Uhat = ( capital_Uhat * ( capitalS ^ sv_tilde_prime) % n ) % n bi_mod_exp( tmp1, pk_intern->capitalS, sv_tilde_prime, n); bi_mul( capitalU_hat, capitalU_hat, tmp1); bi_mod( capitalU_hat, capitalU_hat, n); bi_mul( capitalU_hat, capitalU_hat, product_attr_receiver); bi_mod( capitalU_hat, capitalU_hat, n); // capital_Nhat_i = (( capital_Ni ~% pk_intern->capitalGamma ) ^ c ) % pk_intern->capitalGamma capitalN_hat_i = bi_new_ptr(); bi_invert_mod( capitalN_hat_i, capital_ni, pk_intern->capitalGamma); bi_mod_exp( capitalN_hat_i, capitalN_hat_i, c, pk_intern->capitalGamma); // exp = sf1 << (DAA_PARAM_SIZE_F_I) + sf0 exp = bi_new_ptr(); if( exp == NULL) { LogError("malloc of BI <%s> failed", "exp"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_shift_left( exp, sf1, DAA_PARAM_SIZE_F_I); bi_add( exp, exp, sf0); zeta = compute_zeta( pk_intern->issuerBaseNameLength, pk_intern->issuerBaseName, pk_intern); // capital_Nhat_i = ( capital_Nhat_i * // ( ( issuer.zeta ^ exp) % pk->capitalGamma) ) % pk->capitalGamma bi_mod_exp( tmp1, zeta, exp, pk_intern->capitalGamma); bi_mul( capitalN_hat_i, capitalN_hat_i, tmp1); bi_mod( capitalN_hat_i, capitalN_hat_i, pk_intern->capitalGamma); LogDebug("calculation Uhat: capitalS:%s\n", bi_2_hex_char( pk_intern->capitalS)); LogDebug("calculation Uhat: sv_tilde_prime:%s\n", bi_2_hex_char( sv_tilde_prime)); LogDebug("calculation Uhat: n:%s\n", bi_2_hex_char( n)); LogDebug("calculation Uhat: product_attributes:%s\n", bi_2_hex_char( product_attr_receiver)); LogDebug("calculation NhatI: zeta:%s\n", bi_2_hex_char( zeta)); LogDebug("calculation NhatI: exp:%s\n", bi_2_hex_char( exp)); LogDebug("calculation NhatI: capitalGamma:%s\n", bi_2_hex_char( pk_intern->capitalGamma)); // calculate challenge result = compute_join_challenge_host(hDAA, pk_intern, capitalU, capitalU_prime, capitalU_hat, capitalU_hat_prime, capital_ni, capitalN_hat_i, 0, // TODO: commitmentsProofLength NULL, // TODO: commits joinSession.nonceIssuerLength, joinSession.nonceIssuer, &chLength, // out &ch); // out allocation if( result != TSS_SUCCESS) goto close; LogDebug("JoinChallengeHost: %s", dump_byte_array( chLength, ch)); mdctx = EVP_MD_CTX_create(); EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); EVP_DigestUpdate(mdctx, ch, chLength); challengeLength = EVP_MD_CTX_size(mdctx); challenge = (BYTE *)malloc( challengeLength); if( challenge == NULL) { LogError("malloc of %d bytes failed", challengeLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } EVP_DigestUpdate(mdctx, credentialRequest.nonceTpm, credentialRequest.nonceTpmLength); EVP_DigestFinal(mdctx, challenge, NULL); // checks if( credentialRequest.challengeLength != challengeLength || memcmp( credentialRequest.challenge, challenge, challengeLength)!=0) { LogError("Verification of c failed - Step 3.f.i"); LogError("credentialRequest.challenge[%d]=%s", credentialRequest.challengeLength, dump_byte_array( credentialRequest.challengeLength, credentialRequest.challenge)); LogError("challenge[%d]=%s", challengeLength, dump_byte_array( challengeLength, challenge)); result = TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR; goto close; } // + 1 because the result of ( rA(43 bits) + c(20 bits) * a(13 bits)) can // shift 1 bit above the normal size (43 bits) length = DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES + 1; if( bi_length( sf0) > (long)length) { LogError( "Verification of sF0 failed - Step 3.f.ii"); LogError("\tsf0 bits length: %d expected maximum length:%d\n", (int)bi_length( sf0), (int)length); result = TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR; goto close; } if( bi_length( sf1) > (long)length) { LogError( "Verification of sF1 failed - Step 3.f.ii"); LogError("\tsf1 length: %d expected maximum length:%d\n", (int)bi_length( sf1), (int)length); result = TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR; goto close; } // blinded attributes length = DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES; for( i=0; i failed", "sa_i"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } if( bi_length( sa_i) > (long)length) { LogError("Verification of sA[%d] failed - Step 3.f.ii", i); LogError("sA.length=%d length=%d", (int)bi_length( sa_i), length); result = TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR; goto close; } bi_free_ptr( sa_i); if( result != TSS_SUCCESS) goto close; } length = DAA_PARAM_SIZE_RSA_MODULUS + 2 * DAA_PARAM_SAFETY_MARGIN + DAA_PARAM_SIZE_MESSAGE_DIGEST; if( bi_length( sv_prime) > (int)length) { LogError("Verification of sVprime failed - Step 3.f.iii\n"); LogError("\tsv_prime bits length: %d expected maximum length:%d\n", (int)bi_length( sv_prime), (int)length); result = TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR; goto close; } if( bi_nbin_size( sv_tilde_prime) > (int)length) { LogError("Verification of sVtildePrime failed - Step 3.f.iii"); LogError("\tsv_tilde_prime bits length: %d expected maximum length:%d\n", (int)bi_length( sv_tilde_prime), (int)length); result = TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR; goto close; } // compute credential v_hat = bi_new_ptr(); if( v_hat == NULL) { LogError("malloc of BI <%s> failed", "v_hat"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_urandom( v_hat, DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE - 1); length = DAA_PARAM_SIZE_EXPONENT_CERTIFICATE; interval = DAA_PARAM_SIZE_INTERVAL_EXPONENT_CERTIFICATE; e = bi_new_ptr(); if( e == NULL) { LogError("malloc of BI <%s> failed", "e"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } compute_prime( e, length, interval); // v'' = ( 1 << DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE) + v_hat v_prime_prime = bi_new_ptr(); bi_shift_left( tmp1, bi_1, DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE - 1); bi_add( v_prime_prime, tmp1, v_hat); // fraction_A = (( pk->capitalS ^ v``) % n) * capitalU fraction_A = bi_new_ptr(); if( fraction_A == NULL) { LogError("malloc of BI <%s> failed", "fraction_A"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( fraction_A, pk_intern->capitalS, v_prime_prime, n); bi_mul( fraction_A, fraction_A, capitalU); bi_mod( fraction_A, fraction_A, n); // encode attributes bi_free_ptr( tmp1); product_attr_issuer = bi_new_ptr(); if( product_attr_issuer == NULL) { LogError("malloc of BI <%s> failed", "product_attr_issuer"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( product_attr_issuer, bi_1); for( i=0; i< attributesIssuerLength; i++) { tmp1 = bi_set_as_nbin( DAA_PARAM_SIZE_F_I / 8, attributesIssuer[i]); // allocation bi_mod_exp( tmp2, pk_intern->capitalRIssuer->array[i], tmp1, n); bi_mul( product_attr_issuer, product_attr_issuer, tmp2); bi_mod( product_attr_issuer, product_attr_issuer, n); bi_free_ptr( tmp1); } tmp1 = bi_new_ptr(); if( tmp1 == NULL) { LogError("malloc of BI <%s> failed", "tmp1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mul( fraction_A, fraction_A, product_attr_issuer); bi_mod( fraction_A, fraction_A, n); bi_invert_mod( fraction_A, fraction_A, n); bi_mul( fraction_A, fraction_A, pk_intern->capitalZ); bi_mod( fraction_A, fraction_A, n); private_key = (TSS_DAA_PRIVATE_KEY *) (((TSS_DAA_KEY_PAIR *)joinSession.issuerKeyPair)->private_key); bi_free_ptr( tmp2); tmp2 = bi_set_as_nbin( private_key->productPQprimeLength, private_key->productPQprime); // allocation if( tmp2 == NULL) { LogError("malloc of BI <%s> failed", "tmp2"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } eInverse = bi_new_ptr(); if( eInverse == NULL) { LogError("malloc of BI <%s> failed", "eInverse"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_invert_mod( eInverse, e, tmp2); capitalA = bi_new_ptr(); if( capitalA == NULL) { LogError("malloc of BI <%s> failed", "capitalA"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug("fraction_A[%ld]=%s", bi_nbin_size( fraction_A), bi_2_hex_char( fraction_A)); LogDebug("eInverse[%ld]=%s", bi_nbin_size( eInverse), bi_2_hex_char( eInverse)); LogDebug("productPQprime[%ld]=%s", bi_nbin_size( tmp2), bi_2_hex_char( tmp2)); LogDebug("eInverse[%ld]=%s", bi_nbin_size( eInverse), bi_2_hex_char( eInverse)); LogDebug("e[%ld]=%s", bi_nbin_size( e), bi_2_hex_char( e)); LogDebug("n[%ld]=%s", bi_nbin_size( n), bi_2_hex_char( n)); bi_mod_exp( capitalA, fraction_A, eInverse, n); compute_credential_proof( pk_intern, capitalA, fraction_A, eInverse, v_prime_prime, tmp2, // productPQprime credentialRequest.noncePlatformLength, credentialRequest.noncePlatform, &c_prime, // out: allocation &s_e); // out: allocation // populate credIssuer (TSS_DAA_CRED_ISSUER *) credIssuer->capitalA = calloc_tspi( tcsContext, bi_nbin_size( capitalA)); if( credIssuer->capitalA == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( capitalA)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credIssuer->capitalALength), credIssuer->capitalA, capitalA); credIssuer->e = calloc_tspi( tcsContext, bi_nbin_size( e)); if( credIssuer->e == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( e)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credIssuer->eLength), credIssuer->e, e); credIssuer->vPrimePrime = calloc_tspi( tcsContext, bi_nbin_size( v_prime_prime)); if( credIssuer->vPrimePrime == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( v_prime_prime)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credIssuer->vPrimePrimeLength), credIssuer->vPrimePrime, v_prime_prime); // attributes issuer credIssuer->attributesIssuerLength = attributesIssuerLength; credIssuer->attributesIssuer = calloc_tspi( tcsContext, attributesIssuerLength * sizeof( BYTE *)); if( credIssuer->attributesIssuer == NULL) { LogError("malloc of %d bytes failed", attributesIssuerLength * sizeof( BYTE *)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; i< attributesIssuerLength; i++) { credIssuer->attributesIssuer[i] = calloc_tspi( tcsContext, DAA_PARAM_SIZE_F_I / 8); if( credIssuer->attributesIssuer[i] == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_SIZE_F_I / 8); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } memcpy( credIssuer->attributesIssuer[i], attributesIssuer[i], DAA_PARAM_SIZE_F_I / 8); } credIssuer->cPrime = calloc_tspi( tcsContext, bi_nbin_size( c_prime)); if( credIssuer->cPrime == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( c_prime)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credIssuer->cPrimeLength), credIssuer->cPrime, c_prime); credIssuer->sE = calloc_tspi( tcsContext, bi_nbin_size( s_e)); if( credIssuer->sE == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( s_e)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credIssuer->sELength), credIssuer->sE, s_e); close: EVP_MD_CTX_destroy(mdctx); //free_TSS_DAA_PK( daa_pk_extern); if( ch != NULL) free( ch); if( challenge != NULL) free( challenge); FREE_BI( tmp1); FREE_BI( tmp2); FREE_BI( s_e); FREE_BI( c_prime); FREE_BI( capitalA); FREE_BI( v_prime_prime); FREE_BI( eInverse); FREE_BI( e); FREE_BI( fraction_A); FREE_BI( v_hat); FREE_BI( capital_ni); FREE_BI( sv_tilde_prime); FREE_BI( product_attr_receiver); FREE_BI( product_attr_issuer); FREE_BI( capitalU_hat_prime); FREE_BI( capitalU_prime); FREE_BI( sv_prime); FREE_BI( exp); FREE_BI( capitalN_hat_i); FREE_BI( capitalU_hat); FREE_BI( capitalU); FREE_BI( capitalS); FREE_BI( capitalR1); FREE_BI( capitalR0); FREE_BI( sf1); FREE_BI( sf0); FREE_BI( n); FREE_BI( c); FREE_BI( zeta); return result; } trousers-0.3.15/src/tspi/daa/daa_issuer/key_verification.c0000664000175000017510000000731013663651711023065 0ustar deboradebora/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include #include "spi_internal_types.h" #include "spi_utils.h" #include "obj.h" #include "issuer.h" static char *DEFAULT_FILENAME = "issuer.txt"; //static TSS_HCONTEXT _hContext; static void *intern_alloc( size_t size, TSS_HOBJECT param_alloc) { // void *ret = calloc_tspi( , size); void *ret = malloc( size); LogDebug("[intern_alloc (%d)] -> %d", (int)size, (int)ret); return ret; } void isCorrect( TSS_HDAA hDAA, TSS_DAA_PK_internal *pk_internal, TSS_DAA_PK_PROOF_internal *proof_internal) { TSS_BOOL isCorrect; TSS_RESULT result; TSS_DAA_PK *pk; TSS_DAA_PK_PROOF *pk_proof; pk = i_2_e_TSS_DAA_PK( pk_internal, &intern_alloc, (TSS_HOBJECT)NULL); pk_proof = i_2_e_TSS_DAA_PK_PROOF( proof_internal, &intern_alloc, (TSS_HOBJECT)NULL); result = Tspi_DAA_IssuerKeyVerification( hDAA, (TSS_HKEY)pk, pk_proof, &isCorrect); if ( result != TSS_SUCCESS ) { fprintf( stderr, "Tspi_DAA_IssuerKeyVerification error: %d\n", result ); } free_TSS_DAA_PK( pk); printf("isCorrect=%d\n", isCorrect); } int print_usage(char *cmd) { fprintf(stderr, "usage: %s\n", cmd); fprintf(stderr, "\t-if,\t--issuer_file\tthe file that will contain\ all key pair and proof to be used by the issuer (default: %s)\n", DEFAULT_FILENAME); return -1; } int main(int argc, char *argv[]) { char *filename = DEFAULT_FILENAME; int i=1; char *param; TSS_RESULT result; TSS_HCONTEXT hContext; TSS_HDAA hDAA; FILE *file; // foreground = 1; // for debug printf("Key Verification (%s:%s,%s)\n", argv[0], __DATE__, __TIME__); while( i < argc) { param = argv[ i]; if( strcmp( param, "-if") == 0 || strcmp( param, "--issuer_file")) { i++; if( i == argc) return print_usage( argv[0]); filename = argv[i]; } else { fprintf(stderr, "%s:unrecognized option `%s'\n", argv[0], param); return print_usage( argv[0]); } i++; } bi_init( NULL); printf("Loading issuer info (keypair & proof) -> \'%s\'", filename); file = fopen( filename, "r"); if( file == NULL) { fprintf( stderr, "%s: Error when opening \'%s\': %s\n", argv[0], filename, strerror( errno)); return -1; } KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof = load_KEY_PAIR_WITH_PROOF( file); if( key_pair_with_proof == NULL) { fprintf( stderr, "%s: Error when reading \'%s\': %s\n", argv[0], filename, strerror( errno)); return -1; } fclose( file); // Create Context printf("\nCreate Context\n"); result = Tspi_Context_Create( &hContext ); if ( result != TSS_SUCCESS ) { fprintf( stderr, "Tspi_Context_Create %d\n", result ); exit( result ); } // Connect to Context printf("\nConnect to the context\n"); result = Tspi_Context_Connect( hContext, NULL ); if ( result != TSS_SUCCESS ) { fprintf( stderr, "Tspi_Context_Connect error:%d\n", result ); Tspi_Context_FreeMemory( hContext, NULL ); Tspi_Context_Close( hContext ); exit( result ); } //TODO save key in the persistent store // result = ps_write_key( fd, ) //Create Object result = obj_daa_add( hContext, &hDAA); if (result != TSS_SUCCESS) { LogError("Tspi_Context_CreateObject:%d", result); Tspi_Context_Close(hContext); LogError("issuer_setup: %s", err_string(result)); exit(result); } // TSS_HDAA, TSS_HKEY, TSS_DAA_PK_PROOF, TSS_BOOL* isCorrect( hDAA, key_pair_with_proof->pk, key_pair_with_proof->proof); obj_daa_remove( hDAA, hContext); printf("\nClosing the context\n"); Tspi_Context_FreeMemory( hContext, NULL ); Tspi_Context_Close( hContext ); exit( 0 ); } trousers-0.3.15/src/tspi/daa/daa_issuer/issuer_setup.c0000664000175000017510000001174013663651711022267 0ustar deboradebora/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include "trousers/tss.h" #include "spi_internal_types.h" #include "spi_utils.h" #include "obj.h" // #include "tcslog.h" #include "bi.h" #include "daa_parameter.h" #include "issuer.h" static char *DEFAULT_FILENAME = "issuer.txt"; static char *DEFAULT_ISSUER = "IBM-Issuer"; static const int DEFAULT_ISSUER_ATTRIBUTES = 2; // A1 A2 static const int DEFAULT_RECEIVER_ATTRIBUTES = 3; // A3 A4 A5 int print_usage(char *cmd) { fprintf(stderr, "usage: %s\n", cmd); fprintf(stderr, " \t-npa,\t--nb_platform_attr\tnumber of attributes that the\ Platform can choose and which will not be visible to the Issuer (default: %d)\n", DEFAULT_ISSUER_ATTRIBUTES); fprintf(stderr, " \t-nia,\t--nb_issuer_attr\tnumber of attributes that the issuer\ can choose and which will be visible to both the Platform and the Issuer(default: %d)\n", DEFAULT_RECEIVER_ATTRIBUTES); fprintf(stderr, " \t-if,\t--issuer_file\tthe file that will contain all key pair\ and proof to be used by the issuer (default: %s)\n", DEFAULT_FILENAME); fprintf(stderr, " \t-i,\t--issuer\tissuer identity (default: %s)\n", DEFAULT_ISSUER); return -1; } int main(int argc, char *argv[]) { int nb_platform_attr = DEFAULT_ISSUER_ATTRIBUTES; int nb_issuer_attr = DEFAULT_RECEIVER_ATTRIBUTES; char *filename = DEFAULT_FILENAME; char *issuer = DEFAULT_ISSUER; int i; char *param; TSS_HCONTEXT hContext; TSS_DAA_KEY_PAIR *key_pair; TSS_DAA_PK_PROOF *public_keyproof; TSS_RESULT result; TSS_HDAA hDAA; TSS_DAA_PK_PROOF_internal *public_keyproof_internal; TSS_DAA_PK_internal *pk; TSS_DAA_PRIVATE_KEY *private_key; DAA_PRIVATE_KEY_internal *private_key_internal; KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof; printf("Issuer Setup (%s:%s,%s)\n", argv[0], __DATE__, __TIME__); i = 1; while( i < argc) { param = argv[ i]; if ( strcmp( param, "-if") == 0 || strcmp( param, "--issuer_file")) { i++; if( i == argc) return print_usage( argv[0]); filename = argv[i]; } else if( strcmp( param, "-npa") == 0 || strcmp( param, "--nb_platform_attr")) { i++; if( i == argc) return print_usage( argv[0]); nb_platform_attr = atoi( argv[i]); } else if( strcmp( param, "-nia") == 0 || strcmp( param, "--nb_issuer_attr")) { i++; if( i == argc) return print_usage( argv[0]); nb_issuer_attr = atoi(argv[i]); } else if( strcmp( param, "-i") == 0 || strcmp( param, "--issuer")) { i++; if( i == argc) return print_usage( argv[0]); issuer = argv[i]; } else { fprintf(stderr, "%s:unrecognized option `%s'\n", argv[0], param); return print_usage( argv[0]); } i++; } bi_init( NULL); // Create Context printf("Create Context\n"); result = Tspi_Context_Create( &hContext ); if ( result != TSS_SUCCESS ) { fprintf( stderr, "Tspi_Context_Create %d\n", result ); exit( result ); } // Connect to Context printf("Connect to the context\n"); result = Tspi_Context_Connect( hContext, NULL ); if ( result != TSS_SUCCESS ) { fprintf( stderr, "Tspi_Context_Connect error:%d\n", result ); Tspi_Context_FreeMemory( hContext, NULL ); Tspi_Context_Close( hContext ); exit( result ); } //Create Object result = obj_daa_add( hContext, &hDAA); if (result != TSS_SUCCESS) { goto close; } result = Tspi_DAA_IssueSetup( hDAA, // in strlen( issuer), // in (BYTE *)issuer, // in nb_platform_attr, // in nb_issuer_attr, // in (TSS_HKEY *)&key_pair, // out &public_keyproof); // out if( result != TSS_SUCCESS) goto close; // TSS_DAA_KEY_PAIR_internal *key_pair_internal = DAA_KEY_PAIR_2_internal( key_pair); public_keyproof_internal = e_2_i_TSS_DAA_PK_PROOF( public_keyproof); pk = e_2_i_TSS_DAA_PK( key_pair->public_key); private_key = key_pair->private_key; private_key_internal = e_2_i_TSS_DAA_PRIVATE_KEY( private_key); key_pair_with_proof = (KEY_PAIR_WITH_PROOF_internal *)malloc( sizeof(KEY_PAIR_WITH_PROOF_internal)); if( key_pair_with_proof == NULL) { fprintf("malloc of %d bytes failed", sizeof(KEY_PAIR_WITH_PROOF_internal)); goto close; } key_pair_with_proof->pk = pk; key_pair_with_proof->private_key = private_key_internal; key_pair_with_proof->proof = public_keyproof_internal; printf("Saving key pair with proof -> \'%s\'", filename); FILE *file = fopen( filename, "w"); if( file == NULL) { fprintf( stderr, "%s: Error when saving \'%s\': %s\n", argv[0], filename, strerror( errno)); return -1; } if( save_KEY_PAIR_WITH_PROOF( file, key_pair_with_proof) != 0) { fprintf( stderr, "%s: Error when saving \'%s\': %s\n", argv[0], filename, strerror( errno)); return -1; } fclose( file); printf("\nDone.\n"); close: obj_daa_remove( hDAA, hContext); printf("Closing the context\n"); Tspi_Context_FreeMemory( hContext, NULL ); Tspi_Context_Close( hContext ); bi_release(); printf("Result: %d", result); return result; } trousers-0.3.15/src/tspi/daa/daa_issuer/key_correctness_proof.c0000664000175000017510000004003013663651711024136 0ustar deboradebora/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include // for little-big endian conversion #include // for message digest #include #include "bi.h" #include "daa_parameter.h" #include "list.h" #include "daa_structs.h" #include "issuer.h" //standard bit length extension to obtain a uniformly distributed number [0,element] static const int SAFETY_PARAM = 80; static bi_array_ptr get_generators( const TSS_DAA_PK_internal *pk) { bi_array_ptr result = ALLOC_BI_ARRAY(); int i; bi_new_array( result, 3 + pk->capitalY->length ); for(i = 0; ilength; i++) { result->array[i] = pk->capitalS; } return result; } static bi_array_ptr get_verifiable_numbers( const TSS_DAA_PK_internal *pk) { bi_array_ptr result = ALLOC_BI_ARRAY(); int i; bi_new_array( result, 3 + pk->capitalY->length); result->array[0] = pk->capitalZ; result->array[1] = pk->capitalR0; result->array[2] = pk->capitalR1; // CAPITAL Y ( capitalRReceiver + capitalRIssuer) for( i=0; icapitalY ->length; i++) result->array[ 3+i] = pk->capitalY->array[i]; return result; } /* computes an array of random numbers in the range of [1,element] */ void compute_random_numbers( bi_array_ptr result, int quantity, const bi_ptr element) { int i=0; for( i=0; iarray[i], element); bi_inc( result->array[i]); // array[i]++ } } int test_bit( int pos, BYTE* array, int length) { return (((int)array[ length - (pos / 8) - 1]) & (1 << (pos % 8))) != 0; } void toByteArray( BYTE *result, int length, bi_ptr bi, char *logMsg) { LogDebug("-> toByteArray <%d> %s",(int)bi, logMsg); LogDebug("lenghts <%d|%d>",length, (int)bi_nbin_size(bi)); bi_2_byte_array( result, length, bi); LogDebug("<- toByteArray result=%s [<%d|%d>] ", dump_byte_array( length, result), length, (int)bi_nbin_size(bi)); } /* Compute the message digest used in the proof. (from DAA_Param, the digest algorithm is RSA, but this is not available in openssl, the successor of RSA is SHA1 */ TSS_RESULT generateMessageDigest(BYTE *md_value, int *md_len, const TSS_DAA_PK_internal *pk, bi_array_ptr *commitments, const int commitments_size ) { EVP_MD_CTX *mdctx; const EVP_MD *md; int i, j; int length = DAA_PARAM_SIZE_RSA_MODULUS / 8; BYTE *array; // 10000 to be sure, and this memory will be released quite quickly array = (BYTE *)malloc( 10000); if (array == NULL) { LogError("malloc of %d bytes failed", 10000); return TSPERR(TSS_E_OUTOFMEMORY); } OpenSSL_add_all_digests(); md = EVP_get_digestbyname( DAA_PARAM_MESSAGE_DIGEST_ALGORITHM); EVP_MD_CTX_create(mdctx); EVP_DigestInit_ex(mdctx, md, NULL); #ifdef DAA_DEBUG fprintf(stderr, "modulus=%s\n", bi_2_hex_char( pk->modulus)); #endif toByteArray( array, length, pk->modulus, "!! [generateMessageDigest modulus] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); toByteArray( array, length, pk->capitalS, "!! [generateMessageDigest capitalS] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); // add capitalZ, capitalR0, capitalR1, capitalY LogDebug("capitalZ capitalR0 capitalY"); toByteArray( array, length, pk->capitalZ, "!! [generateMessageDigest capitalZ] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); toByteArray( array, length, pk->capitalR0, "!! [generateMessageDigest capitalR0] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); toByteArray( array, length, pk->capitalR1, "!! [generateMessageDigest capitalR1] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); // CAPITAL Y ( capitalRReceiver ) LogDebug("capitalRReceiver"); for( i=0; icapitalRReceiver->length; i++) { toByteArray( array, length, pk->capitalRReceiver->array[i], "!![generateMessageDigest capitalRReceiver] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); } LogDebug("capitalRIssuer"); // CAPITAL Y ( capitalRIssuer) for( i=0; icapitalRIssuer->length; i++) { toByteArray( array, length, pk->capitalRIssuer->array[i], "!![generateMessageDigest capitalRReceiver] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); } LogDebug("commitments"); for( i=0; ilength; j++) { toByteArray( array, length, commitments[i]->array[j], "!! [generateMessageDigest commitments] current_size=%d length=%d\n"); EVP_DigestUpdate(mdctx, array , length); } } EVP_DigestFinal_ex(mdctx, md_value, md_len); EVP_MD_CTX_destroy(mdctx); free( array); return TSS_SUCCESS; } int is_range_correct( bi_ptr b, bi_ptr range) { return bi_cmp( b, range) < 0 && bi_cmp( b, bi_0) >= 0; } /* Verifies if the parameters Z,R0,R1,RReceiver and RIssuer of the public key were correctly computed. pk: the public key, which one wants to verfy. */ TSS_RESULT is_pk_correct( TSS_DAA_PK_internal *public_key, TSS_DAA_PK_PROOF_internal *proof, int *isCorrect ) { int bit_size_message_digest = DAA_PARAM_SIZE_MESSAGE_DIGEST; bi_ptr n = public_key->modulus; int num_of_variables; int i,j; TSS_RESULT result = TSS_SUCCESS; BYTE verifiable_challenge[EVP_MAX_MD_SIZE]; int length_challenge; bi_array_ptr verifiable_numbers; bi_array_ptr *verification_commitments = NULL; bi_array_ptr generators = NULL; bi_t tmp; bi_t tmp1; #ifdef DAA_DEBUG FILE *f; bi_array_ptr *commitments; #endif bi_new( tmp); bi_new( tmp1); *isCorrect = 0; #ifdef DAA_DEBUG f=fopen("/tmp/commits", "r"); commitments = (bi_array_ptr *)malloc( sizeof(bi_array_ptr) * num_of_variables); if (commitments == NULL) { LogError("malloc of %d bytes failed", sizeof(bi_array_ptr) * num_of_variables); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; icapitalGamma)) { LogError( "pk->capitalGamma not prime\ncapitalGamma=\n%s", bi_2_hex_char( public_key->capitalGamma)); result = TSS_E_BAD_PARAMETER; goto close; } if( !bi_is_probable_prime( public_key->rho)) { LogError( "pk->rho not prime\nrho=\n%s", bi_2_hex_char( public_key->rho)); result = TSS_E_BAD_PARAMETER; goto close; } // (capitalGamma - 1) % rho should be equal to 0 if( !bi_equals( bi_mod( tmp1, bi_sub( tmp1, public_key->capitalGamma, bi_1), public_key->rho), bi_0)) { LogError( "(capitalGamma - 1) %% rho != 0\nActual value:\n%s", bi_2_hex_char( tmp1)); result = TSS_E_BAD_PARAMETER; } // (gamma ^ rho) % capitalGamma should be equals to 1 if ( !bi_equals( bi_mod_exp( tmp1, public_key->gamma, public_key->rho, public_key->capitalGamma), bi_1) ) { LogError( "(gamma ^ rho) %% capitalGamma != 1\nActual value:\n%s", bi_2_hex_char( tmp1)); result = TSS_E_BAD_PARAMETER; goto close; } // (gamma ^ rho) % capitalGamma should be equal to 1 if ( !bi_equals( bi_mod_exp( tmp1, public_key->gamma, public_key->rho, public_key->capitalGamma), bi_1) ) { LogError( "(gamma ^ rho) %% capitalGamma != 1\nActual value:\n%s", bi_2_hex_char( tmp1)); result = TSS_E_BAD_PARAMETER; goto close; } LogDebug("STEP 2 check whether all public key parameters have the required length"); if( bi_nbin_size( n) != DAA_PARAM_SIZE_RSA_MODULUS / 8) { LogError( "size( n)[%ld] != DAA_PARAM_SIZE_RSA_MODULUS[%d]", bi_nbin_size( n), DAA_PARAM_SIZE_RSA_MODULUS / 8); result = TSS_E_BAD_PARAMETER; goto close; } if( bi_cmp( n, bi_shift_left( tmp1, bi_1, DAA_PARAM_SIZE_RSA_MODULUS)) >= 0) { LogError( "n[%ld] != DAA_PARAM_SIZE_RSA_MODULUS[%d]", bi_nbin_size( n), DAA_PARAM_SIZE_RSA_MODULUS); result = TSS_E_BAD_PARAMETER; goto close; } if( bi_cmp( n, bi_shift_left( tmp1, bi_1, DAA_PARAM_SIZE_RSA_MODULUS - 1 )) <= 0) { LogError( "n[%ld] != DAA_PARAM_SIZE_RSA_MODULUS[%d]", bi_nbin_size( n), DAA_PARAM_SIZE_RSA_MODULUS); result = TSS_E_BAD_PARAMETER; goto close; } // rho if( bi_nbin_size( public_key->rho) * 8 != DAA_PARAM_SIZE_RHO) { LogError( "size( rho)[%ld] != DAA_PARAM_SIZE_RHO[%d]", bi_nbin_size( public_key->rho) * 8, DAA_PARAM_SIZE_RHO); result = TSS_E_BAD_PARAMETER; goto close; } // Gamma if( bi_nbin_size( public_key->capitalGamma) * 8 != DAA_PARAM_SIZE_MODULUS_GAMMA) { LogError( "size( rho)[%ld] != DAA_PARAM_SIZE_MODULUS_GAMMA[%d]", bi_nbin_size( public_key->capitalGamma) * 8, DAA_PARAM_SIZE_MODULUS_GAMMA); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalS, n) == 0) { LogError( "range not correct( pk->capitalS)\ncapitalS=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalS), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalZ, n) == 0) { LogError( "range not correct( pk->capitalZ)\ncapitalZ=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalZ), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalR0, n) == 0) { LogError( "range not correct( pk->capitalR0)\ncapitalR0=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalR0), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalR1, n) == 0) { LogError( "range not correct( pk->capitalR1)\ncapitalR1=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalR1), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } for( i=0; icapitalY->length; i++) { if( is_range_correct( public_key->capitalY->array[i], n) == 0) { LogError( "range not correct(pk->capitalY[%d])\ncapitalY[%d]=\n%s\nn=\n%s", i, i, bi_2_hex_char( public_key->capitalY->array[i]), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } } LogDebug("STEP 3 - compute verification commitments"); // only the array is allocated, but all refs are pointing to public_key numbers generators = get_generators( public_key); verifiable_numbers = get_verifiable_numbers( public_key); num_of_variables = verifiable_numbers->length; verification_commitments = (bi_array_ptr *)malloc( sizeof(bi_array_ptr)*num_of_variables); if (verification_commitments == NULL) { LogError("malloc of %d bytes failed", sizeof(bi_array_ptr)*num_of_variables); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i = 0; ichallenge, proof->length_challenge)); #endif bi_mod_exp( verification_commitments[i]->array[j], generators->array[i], proof->response[i]->array[j], n); if( test_bit( j, proof->challenge, proof->length_challenge)) { bi_mul( verification_commitments[i]->array[j], verification_commitments[i]->array[j], verifiable_numbers->array[i]); #ifdef DAA_DEBUG DUMP_BI( verification_commitments[i]->array[j]); #endif bi_mod( verification_commitments[i]->array[j], verification_commitments[i]->array[j], n); } #ifdef DAA_DEBUG if( commitments != NULL && bi_equals( verification_commitments[i]->array[j], commitments[i]->array[j]) ==0) { LogError( "!! ERROR i=%d j=%d\n", i, j); DUMP_BI( commitments[i]->array[j]); DUMP_BI( verification_commitments[i]->array[j]); DUMP_BI( generators->array[i]); DUMP_BI( proof->response[i]->array[j]); DUMP_BI( verifiable_numbers->array[i]); } printf( "o"); fflush( stdout); #endif } } // STEP 3 - d generateMessageDigest( verifiable_challenge, &length_challenge, public_key, verification_commitments, num_of_variables); LogDebug("verifiable challenge=%s", dump_byte_array( length_challenge, verifiable_challenge)); LogDebug(" challenge=%s", dump_byte_array( proof->length_challenge, proof->challenge)); if( length_challenge != proof->length_challenge) { result = TSS_E_BAD_PARAMETER; goto close; } for( i=0; ichallenge[i]) { result = TSS_E_BAD_PARAMETER; goto close; } } *isCorrect = ( memcmp( verifiable_challenge, proof->challenge, length_challenge) == 0); close: if( verification_commitments != NULL) { for( i = 0; imodulus; int num_of_variables; int bit_size_message_digest = DAA_PARAM_SIZE_MESSAGE_DIGEST; bi_array_ptr *xTildes = NULL; BYTE *challenge_param; bi_array_ptr exponents = ALLOC_BI_ARRAY(); bi_new_array2( exponents, 3 + x->length); exponents->array[0] = xz; exponents->array[1] = x0; exponents->array[2] = x1; bi_copy_array( x, 0, exponents, 3, x->length); num_of_variables = exponents->length; LogDebug("Step a - choose random numbers"); LogDebug("\nchoose random numbers\n"); xTildes = (bi_array_ptr *)malloc( sizeof(bi_array_ptr) * num_of_variables); if (xTildes == NULL) { LogError("malloc of %d bytes failed", sizeof(bi_array_ptr) * num_of_variables); return NULL; } for( i=0; iarray[j], generators->array[i], xTildes[i]->array[j], n); } } #ifdef DAA_DEBUG FILE *f=fopen("/tmp/commits", "w"); for( i=0; iarray[j], xTildes[i]->array[j], exponents->array[i]); } else { bi_set( response[i]->array[j], xTildes[i]->array[j]); } bi_mod( response[i]->array[j], response[i]->array[j], product_PQ_prime); #ifdef DAA_DEBUG printf("#"); fflush(stdout); #endif } } challenge_param = (BYTE *)malloc( length_challenge); if (challenge_param == NULL) { LogError("malloc of %d bytes failed", length_challenge); return NULL; } memcpy( challenge_param, challenge, length_challenge); return create_DAA_PK_PROOF( challenge_param, length_challenge, response, num_of_variables); } trousers-0.3.15/src/tspi/daa/daa_verifier/0000775000175000017510000000000013663651711017667 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/daa_verifier/verifier_transaction.c0000664000175000017510000007452613663651711024271 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include // for message digest #include #include "daa_structs.h" #include "daa_parameter.h" #include "trousers/tss.h" #include "spi_internal_types.h" #include "spi_utils.h" #include #include #include #include "tsplog.h" #include "tss/tcs.h" #include "verifier.h" #include "trousers/tss.h" #include "spi_internal_types.h" #include "spi_utils.h" #include "anonymity_revocation.h" DAA_VERIFIER_TRANSACTION *create_verifier_transaction( int length, char *base_name) { DAA_VERIFIER_TRANSACTION *verifier_transaction = malloc(sizeof(DAA_VERIFIER_TRANSACTION)); if (verifier_transaction == NULL) { LogError("malloc of %d bytes failed", sizeof(DAA_VERIFIER_TRANSACTION)); return NULL; } verifier_transaction->baseName = base_name; verifier_transaction->baseName_length = length; OpenSSL_add_all_digests(); verifier_transaction->digest = DAA_PARAM_get_message_digest(); return verifier_transaction; } static int verifyNonce( BYTE *nonce_verifier, int length) { //TODO check nonce_verifier with the current transaction nonce return 1; } BYTE *compute_bytes( int seedLength, BYTE *seed, int length, const EVP_MD *digest) { EVP_MD_CTX *mdctx; int N; BYTE *hash; BYTE *result; int i, big_indian_i, len_hash; result = (BYTE *)malloc( length); if (result == NULL) { LogError("malloc of %d bytes failed", length); return NULL; } mdctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(mdctx, digest, NULL); len_hash = EVP_MD_size(digest); N = length / len_hash; hash = (BYTE *)malloc( len_hash); if (hash == NULL) { LogError("malloc of %d bytes failed", len_hash); return NULL; } for( i=0; icapitalGamma; bi_ptr rho = issuer_pk->rho; bi_ptr zeta = bi_new_ptr(); if( capital_gamma == NULL || rho == NULL || zeta == NULL) return NULL; // exponent = capital_gamma - 1 bi_sub( exponent, capital_gamma, bi_1); // exponent = exponent / rho bi_div( exponent, exponent, rho); // zeta = ( base ^ exponent) % capital_gamma LogDebug("project_into_group_gamma: rho [%ld]:%s", bi_nbin_size( rho), bi_2_hex_char( rho)); LogDebug("project_into_group_gamma: base[%ld]:%s", bi_nbin_size( base), bi_2_hex_char( base)); LogDebug("project_into_group_gamma: exponent [%ld]:%s", bi_nbin_size( exponent), bi_2_hex_char( exponent)); LogDebug("project_into_group_gamma: capitalGamma[%ld]:%s", bi_nbin_size( capital_gamma), bi_2_hex_char( capital_gamma)); bi_mod_exp( zeta, base, exponent, capital_gamma); LogDebug("project_into_group_gamma: result:%s", bi_2_hex_char( zeta)); bi_free( exponent); return zeta; } bi_ptr compute_zeta( int nameLength, unsigned char *name, TSS_DAA_PK_internal *issuer_pk) { BYTE *bytes; bi_ptr base; bi_ptr result; LogDebug("compute_zeta: %d [%s] pk:%x", nameLength, name, (int)issuer_pk); bytes = compute_bytes( nameLength, name, DAA_PARAM_LENGTH_MFG1_GAMMA, DAA_PARAM_get_message_digest()); if( bytes == NULL) return NULL; base = bi_set_as_nbin( DAA_PARAM_LENGTH_MFG1_GAMMA, bytes); if( base == NULL) return NULL; LogDebug("base: %ld [%s]", bi_nbin_size( base), bi_2_hex_char( base)); result = project_into_group_gamma( base, issuer_pk); if( result == NULL) return NULL; bi_free_ptr( base); free( bytes); LogDebug("return zeta:%s\n", bi_2_hex_char( result)); return result; } bi_ptr compute_parameterized_gamma(int k, TSS_DAA_PK_internal *issuer_pk) { int length; int hashLength = bi_nbin_size( issuer_pk->gamma) + sizeof(int); BYTE *hash; int big_indian_k = htonl( k); BYTE *bytes; bi_ptr value, result; hash = (BYTE *)malloc( hashLength); if (hash == NULL) { LogError("malloc of %d bytes failed", hashLength); return NULL; } // hash[0-3] = big_indian(k) memcpy( hash, &big_indian_k, sizeof(int)); // hash[4-end] = issuer_pk->gamma bi_2_nbin1( &length, &hash[sizeof(int)], issuer_pk->gamma); // allocation bytes = compute_bytes( hashLength, hash, DAA_PARAM_LENGTH_MFG1_GAMMA, DAA_PARAM_get_message_digest()); if( bytes == NULL) return NULL; // allocation value = bi_set_as_nbin( DAA_PARAM_LENGTH_MFG1_GAMMA, bytes); if( value == NULL) return NULL; result = project_into_group_gamma( value, issuer_pk); // allocation if (result == NULL) { LogError("malloc of %d bytes failed", hashLength); return NULL; } bi_free_ptr( value); free( bytes); return result; } inline bi_ptr apply_challenge( bi_ptr value, bi_ptr delta, bi_ptr c, bi_ptr capital_gamma) { bi_ptr delta_tilde = bi_new_ptr(); bi_t c_negate; if( delta_tilde == NULL) return NULL; bi_new( c_negate); bi_set( c_negate, c); bi_negate( c_negate); // delta_tilde = ( delta ^ (-c)) % capital_gamma bi_mod_exp( delta_tilde, delta, c_negate, capital_gamma); bi_free( c_negate); // delta_tilde = (delta_tilde * value) % capital_gamma return bi_mod( delta_tilde, bi_mul( delta_tilde, delta_tilde, value), capital_gamma); } DAA_VERIFIER_TRANSACTION *createTransaction(int baseName_length, BYTE* baseName) { DAA_VERIFIER_TRANSACTION *result = (DAA_VERIFIER_TRANSACTION *)malloc( sizeof(DAA_VERIFIER_TRANSACTION)); if (result == NULL) { LogError("malloc of %d bytes failed", sizeof(DAA_VERIFIER_TRANSACTION)); return NULL; } result->baseName = baseName; result->baseName_length = baseName_length; return result; } void update( EVP_MD_CTX *mdctx, char *name, bi_ptr integer, int bitLength) { int length = bitLength / 8; BYTE buffer[length]; bi_2_byte_array( buffer, length, integer); LogDebug("[update] %s:%s", name, dump_byte_array( length, buffer)); EVP_DigestUpdate(mdctx, buffer, length); } BYTE *compute_sign_challenge_host( int *result_length, EVP_MD *digest, TSS_DAA_PK_internal *issuer_pk, int nonce_verifierLength, BYTE *nonce_verifier, int selected_attributes2commitLength, TSS_DAA_SELECTED_ATTRIB **selected_attributes2commit, int is_anonymity_revocation_enabled, bi_ptr zeta, bi_ptr capital_t, bi_ptr capital_tilde, int attribute_commitmentsLength, TSS_DAA_ATTRIB_COMMIT_internal **attribute_commitments, TSS_DAA_ATTRIB_COMMIT_internal **attribute_commitment_proofs, bi_ptr capital_nv, bi_ptr capital_tilde_v, CS_PUBLIC_KEY *anonymity_revocator_pk, CS_ENCRYPTION_RESULT *encryption_result_rand, CS_ENCRYPTION_RESULT *encryption_result_proof ) { EVP_MD_CTX *mdctx; int i, length; unsigned int big_indian; BYTE *buffer; int length_gamma_modulus; BYTE *buffer1; LogDebug("issuer_pk basename[%d]:%s", issuer_pk->issuerBaseNameLength, dump_byte_array( issuer_pk->issuerBaseNameLength, issuer_pk->issuerBaseName)); LogDebug("nonce_verifier[%d]:%s", nonce_verifierLength, dump_byte_array( nonce_verifierLength, nonce_verifier)); LogDebug("selected_attributes2commitLength:%d", selected_attributes2commitLength); LogDebug("is_anonymity_revocation_enabled:%d", is_anonymity_revocation_enabled); LogDebug("zeta[%ld]:%s", bi_nbin_size( zeta), bi_2_hex_char( zeta)); LogDebug("capital_t[%ld]:%s", bi_nbin_size( capital_t), bi_2_hex_char( capital_t)); LogDebug("capital_tilde[%ld]:%s", bi_nbin_size( capital_tilde), bi_2_hex_char( capital_tilde)); LogDebug("attribute_commitmentsLength:%d", attribute_commitmentsLength); LogDebug("attribute_commitments:%d", (int)attribute_commitments); LogDebug("attribute_commitment_proofs:%d", (int)attribute_commitment_proofs); LogDebug("capital_nv[%ld]:%s", bi_nbin_size( capital_nv), bi_2_hex_char( capital_nv)); LogDebug("capital_tilde_v[%ld]:%s", bi_nbin_size( capital_tilde_v), bi_2_hex_char( capital_tilde_v)); LogDebug("anonymity_revocator_pk:%d", (int)anonymity_revocator_pk); LogDebug("encryption_result_rand:%d", (int)encryption_result_rand); LogDebug("encryption_result_proof:%d", (int)encryption_result_proof); mdctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(mdctx, digest, NULL); // update with encoded PK buffer = encoded_DAA_PK_internal( &length, issuer_pk); if( buffer == NULL) return NULL; LogDebug("encoded issuer_pk[%d]:%s", length, dump_byte_array( length, buffer)); EVP_DigestUpdate(mdctx, buffer , length); free( buffer); // nonce verifier EVP_DigestUpdate(mdctx, nonce_verifier , nonce_verifierLength); // length Commitments big_indian = attribute_commitmentsLength; EVP_DigestUpdate(mdctx, &big_indian, sizeof(int)); // Anonymity enabled big_indian = is_anonymity_revocation_enabled; EVP_DigestUpdate(mdctx, &big_indian, sizeof(int)); update( mdctx, "zeta", zeta, DAA_PARAM_SIZE_MODULUS_GAMMA); update( mdctx, "capitalT", capital_t, DAA_PARAM_SIZE_RSA_MODULUS); update( mdctx, "capitalTTilde", capital_tilde, DAA_PARAM_SIZE_RSA_MODULUS); length_gamma_modulus = DAA_PARAM_SIZE_MODULUS_GAMMA / 8; buffer = (BYTE *)malloc( length_gamma_modulus);// allocation if (buffer == NULL) { LogError("malloc of %d bytes failed", length_gamma_modulus); return NULL; } if( selected_attributes2commitLength > 0) { for( i=0; ibeta); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, attribute_commitment_proofs[i]->beta); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); } } if( !is_anonymity_revocation_enabled) { // Nv, N~v bi_2_byte_array( buffer, length_gamma_modulus, capital_nv); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, capital_tilde_v); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); } else { bi_2_byte_array( buffer, length_gamma_modulus, anonymity_revocator_pk->eta); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, anonymity_revocator_pk->lambda1); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, anonymity_revocator_pk->lambda2); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, anonymity_revocator_pk->lambda3); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_rand->c1); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_rand->c2); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_rand->c3); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_rand->c4); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_proof->c1); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_proof->c2); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_proof->c3); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); bi_2_byte_array( buffer, length_gamma_modulus, encryption_result_proof->c4); EVP_DigestUpdate(mdctx, buffer, length_gamma_modulus); } free(buffer); buffer = (BYTE *)malloc(EVP_MD_size(digest)); // allocation if (buffer == NULL) { LogError("malloc of %d bytes failed", EVP_MD_size(digest)); return NULL; } EVP_DigestFinal_ex(mdctx, buffer, result_length); EVP_MD_CTX_destroy(mdctx); LogDebug("compute_sign_challenge_host[%d]:%s", *result_length, dump_byte_array( *result_length, buffer)); return buffer; } inline int is_element_gamma( bi_ptr capital_nv, TSS_DAA_PK_internal *issuer_pk) { bi_ptr tmp1 = bi_new_ptr(); int result; // ( ( capital_nv ^ issuer_pk->rho ) % issuer_pk->capitalGamma ) == 1 result = bi_equals( bi_mod_exp( tmp1, capital_nv, issuer_pk->rho, issuer_pk->capitalGamma), bi_1); bi_free_ptr( tmp1); return result; } /* implementation derived from isValid (VerifierTransaction.java) */ TSPICALL Tspi_DAA_VerifySignature_internal ( TSS_HDAA hDAA, // in TSS_DAA_SIGNATURE signature_ext, // in TSS_HKEY hPubKeyIssuer, // in TSS_DAA_SIGN_DATA sign_data, // in UINT32 attributesLength, // in BYTE **attributes, // in UINT32 nonce_verifierLength, // out BYTE *nonce_verifier, // out UINT32 base_nameLength, // out BYTE *base_name, // out TSS_BOOL *isCorrect // out ) { int i, j; DAA_VERIFIER_TRANSACTION *verifier_transaction = NULL; TSS_DAA_ATTRIB_COMMIT *commitments; TSS_DAA_PK_internal *issuer_pk; TSS_DAA_SIGNATURE_internal *signature = NULL; bi_ptr tmp1; bi_array_ptr sA; bi_ptr n = NULL; bi_ptr c = NULL; bi_ptr capital_gamma = NULL; bi_ptr zeta_2_verify = NULL; bi_ptr capital_z = NULL; bi_array_ptr capital_R = NULL; bi_ptr product_r = NULL; bi_ptr exp = NULL; bi_ptr capital_THat = NULL; bi_ptr beta_tilde = NULL; bi_ptr gamma_i = NULL; bi_ptr capital_nv = NULL; bi_ptr capital_ntilde_v = NULL; bi_ptr pseudonym_projected = NULL; bi_ptr s_tau = NULL; bi_ptr delta_tilde1 = NULL; bi_ptr delta_tilde2 = NULL; bi_ptr delta_tilde3 = NULL; bi_ptr delta_tilde4 = NULL; bi_ptr attribute_i; TSS_DAA_PSEUDONYM_PLAIN *pseudonym_plain; CS_ENCRYPTION_RESULT *pseudonym_enc = NULL; CS_ENCRYPTION_RESULT *pseudonym_encryption_proof = NULL; TSS_DAA_PSEUDONYM_ENCRYPTED_internal *sig_pseudonym_encrypted = NULL; CS_ENCRYPTION_RESULT_RANDOMNESS *result_random = NULL; CS_ENCRYPTION_RESULT *encryption_result = NULL; TSS_DAA_ATTRIB_COMMIT_internal **commitment_proofs = NULL; TCS_CONTEXT_HANDLE tcsContext; TSS_RESULT result = TSS_SUCCESS; EVP_MD_CTX *mdctx; int length_ch, len_hash, bits; BYTE *ch = NULL, *hash = NULL; TSS_BOOL *indices; tmp1 = bi_new_ptr(); if( tmp1 == NULL) { LogError("malloc of BI <%s> failed", "tmp1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } *isCorrect = FALSE; if( (result = obj_daa_get_tsp_context( hDAA, &tcsContext)) != TSS_SUCCESS) goto close; // allocation of issuer_pk issuer_pk = e_2_i_TSS_DAA_PK( (TSS_DAA_PK *)hPubKeyIssuer); if( issuer_pk == NULL) { LogError("malloc of TSS_DAA_PK_internal failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // allocation of signature signature = e_2_i_TSS_DAA_SIGNATURE( &signature_ext); if( signature == NULL) { LogError("malloc of TSS_DAA_SIGNATURE_internal failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } commitments = signature_ext.attributeCommitments; // TODO verify consistency of sig.getSA() with selectedAttributes,.. sA = signature->sA; if( sA->length != (int)attributesLength) { LogError("Verifier Error: lengths of attributes and sA must be equal"); result = TSS_E_BAD_PARAMETER; goto close; } for ( i = 0; i < (int)attributesLength; i++) { if ( (attributes[i] == NULL && bi_equals( sA->array[i], bi_0)) || (attributes[i] != NULL && !bi_equals( sA->array[i], bi_0))) { LogError( "Verifier Error: illegal argument content in attributes\ and sA[%d]", i); result = TSS_E_BAD_PARAMETER; goto close; } } // TODO: implement verify nonce if ( verifyNonce(nonce_verifier, nonce_verifierLength) == 0) { LogError("Verifier Error: nonce invalid"); result = TSS_E_INTERNAL_ERROR; goto close; } n = issuer_pk->modulus; c = bi_set_as_nbin( signature->challenge_length, signature->challenge); capital_gamma = issuer_pk->capitalGamma; if( base_name != NULL) { // isRandomBaseName zeta_2_verify = compute_zeta( base_nameLength, base_name, issuer_pk); if( bi_equals( signature->zeta, zeta_2_verify) == 0) { LogError("Verifier Error: Verification of zeta failed - Step 1"); result = TSS_E_INTERNAL_ERROR; goto close; } } LogDebug( "step 2"); capital_z = issuer_pk->capitalZ; capital_R = issuer_pk->capitalY; product_r = bi_new_ptr(); if( product_r == NULL) { LogError("malloc of BI <%s> failed", "product_r"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( product_r, bi_1); // product_r = 1 for( i=0; i<(int)attributesLength; i++) { if( attributes[i] != NULL) { // allocation attribute_i = bi_set_as_nbin( DAA_PARAM_SIZE_F_I / 8, attributes[i]); if( attribute_i == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_SIZE_F_I / 8); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // tmp1 = (capital_R[i] ^ attributes[i]) mod n bi_mod_exp( tmp1, capital_R->array[i], attribute_i, n); // product_r = product_r * tmp1 bi_mul( product_r, product_r, tmp1); // product_r = product_r mod n bi_mod( product_r, product_r, n); bi_free_ptr( attribute_i); } } exp = bi_new_ptr(); if( exp == NULL) { LogError("malloc of BI <%s> failed", "product_r"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capital_THat = bi_new_ptr(); // tmp1 = product_r invmod n bi_invert_mod( tmp1, product_r, n); // capital_THat = capital_z * tmp1 bi_mul( capital_THat, capital_z, tmp1); // capital_THat = capital_THat % n bi_mod( capital_THat, capital_THat, n); // capital_THat = (capital_THat ^ (-c)) mod n = ( 1 / (capital_That ^ c) ) % n bi_mod_exp( capital_THat, capital_THat, c, n); bi_invert_mod( capital_THat, capital_THat, n); // tmp1 = c << (SizeExponentCertificate - 1) bi_shift_left( tmp1, c, DAA_PARAM_SIZE_EXPONENT_CERTIFICATE - 1); // exp = signature->sE + tmp1 bi_add( exp, signature->sE, tmp1); // tmp1 = (signature->capitalT ^ exp) mod n bi_mod_exp( tmp1, signature->capitalT, exp, n); // capital_THat = ( capital_THat * tmp1 ) % n bi_mul( capital_THat, capital_THat, tmp1); bi_mod( capital_THat, capital_THat, n); // tmp1=( issuer_pk->capitalR0 ^ signature->sF0) % n bi_mod_exp( tmp1, issuer_pk->capitalR0, signature->sF0, n); // capital_THat = ( capital_THat * tmp1 ) % n bi_mul( capital_THat, capital_THat, tmp1); bi_mod( capital_THat, capital_THat, n); // tmp1=( issuer_pk->capitalR1 ^ signature->sF1) % n bi_mod_exp( tmp1, issuer_pk->capitalR1, signature->sF1, n); // capital_THat = ( capital_THat * tmp1 ) % n bi_mul( capital_THat, capital_THat, tmp1); bi_mod( capital_THat, capital_THat, n); // tmp1=( issuer_pk->capitalS ^ signature->sV) % n bi_mod_exp( tmp1, issuer_pk->capitalS, signature->sV, n); // capital_THat = ( capital_THat * tmp1 ) % n bi_mul( capital_THat, capital_THat, tmp1); bi_mod( capital_THat, capital_THat, n); bi_set( product_r, bi_1); // product_r = 1 for( i=0; i<(int)attributesLength; i++) { if( attributes[i] == NULL) { // tmp1=(capital_R->array[i] ^ sA->array[i]) % n bi_mod_exp( tmp1, capital_R->array[i], sA->array[i], n); // product_r = ( product_r * tmp1 ) % n bi_mul( product_r, product_r, tmp1); bi_mod( product_r, product_r, n); } } // capital_THat = (capital_THat * product_r) % n bi_mod( capital_THat, bi_mul( tmp1, capital_THat, product_r), n); LogDebug("Step 3 - Commitments"); //TODO when enabling the commitment feature, verifier_transaction should be set #ifdef ANONYMITY_REVOCATION if( verifier_transaction != NULL && verifier_transaction->selected_attributes2commitLength > 0) { commitment_proofs = (TSS_DAA_ATTRIB_COMMIT_internal **) malloc(verifier_transaction->selected_attributes2commitLength * sizeof(TSS_DAA_ATTRIB_COMMIT_internal*)); if (commitment_proofs == NULL) { LogError("malloc of %d bytes failed", verifier_transaction->selected_attributes2commitLength * sizeof(TSS_DAA_ATTRIB_COMMIT_internal*)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( j=0; jselected_attributes2commitLength; j++) { if( bi_cmp( commitments[j].sMu, issuer_pk->rho) >= 0 || bi_cmp_si( commitments[j].sMu, 0) < 0) { LogError("sMu >= rho || sMu < 0"); result = TSS_E_INTERNAL_ERROR; goto close; } beta_tilde = bi_new_ptr(); if( beta_tilde == NULL) { LogError("malloc of BI <%s> failed", "beta_tilde"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( tmp1, c); bi_negate( tmp1); // beta_tilde=(commitments[j]->beta ^ (-c)) % capitalGamma bi_mod_exp( beta_tilde, commitments[j]->beta, tmp1, capital_gamma); // tmp1=(issuer_pk->gamma ^ commitments[j]->sMu) % capital_gamma bi_mod_exp( tmp1, issuer_pk->gamma, commitments[j]->sMu, capital_gamma); // beta_tilde=beta_tilde * tmp1 bi_mul( beta_tilde, beta_tilde, tmp1); // beta_tilde=beta_tilde % capital_gamma bi_mod( beta_tilde, beta_tilde, capital_gamma); indices = (verifier_transaction->selected_attributes2commit[j])-> indicesList; if( verifier_transaction->selected_attributes2commit[j]-> indicesListLength != (UINT32)(issuer_pk->capitalY->length) ) { LogError("indicesList of selected_attribs[%d] (%d) \ and issuer_pk are not consistent (%d)\n", j, verifier_transaction->selected_attributes2commit[j]-> indicesListLength, issuer_pk->capitalY->length); result = TSS_E_INTERNAL_ERROR; goto close; } for( i=0; icapitalY->length; i++) { if( indices[i]) { gamma_i = compute_parameterized_gamma( i, issuer_pk); if( gamma_i == NULL) { LogError("malloc of BI <%s> failed", "gamma_i"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // tmp1=(gamma_i ^ sA[j]) % capital_gamma bi_mod_exp( tmp1, gamma_i, sA->array[i], capital_gamma); // beta_tilde=beta_tilde * tmp1 bi_mul( beta_tilde, beta_tilde, tmp1); // beta_tilde=beta_tilde % capital_gamma bi_mod( beta_tilde, beta_tilde, capital_gamma); } } commitment_proofs[j] = create_TSS_DAA_ATTRIB_COMMIT( beta_tilde, NULL); } } #endif LogDebug("Step 4 - Pseudonym"); capital_nv = bi_new_ptr(); if( capital_nv == NULL) { LogError("malloc of BI <%s> failed", "capital_nv"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capital_ntilde_v = bi_new_ptr(); if( capital_ntilde_v == NULL) { LogError("malloc of BI <%s> failed", "capital_ntilde_v"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_shift_left( tmp1, signature->sF1, DAA_PARAM_SIZE_F_I); bi_add( exp, signature->sF0, tmp1); pseudonym_projected = bi_new_ptr(); // pseudonym_projected = (signature->zeta ^ exp) % capital_gamma bi_mod_exp( pseudonym_projected, signature->zeta, exp, capital_gamma); pseudonym_enc = NULL; pseudonym_encryption_proof = NULL; //TODO when enabling the commitment feature, verifier_transaction should be set if( verifier_transaction == NULL || verifier_transaction->is_anonymity_revocation_enabled ==0) { // anonymity revocation not enabled pseudonym_plain = (TSS_DAA_PSEUDONYM_PLAIN *)signature_ext.signedPseudonym; capital_nv = bi_set_as_nbin( pseudonym_plain->capitalNvLength, pseudonym_plain->capitalNv); //TODO // capital_ntilde_v = ( capital_nv ^ ( - c) ) % capital_gamma // = ( 1 / (capital_nv ^ c) % capital_gamma) % capital_gamma bi_mod_exp( tmp1, capital_nv, c, capital_gamma); bi_invert_mod( capital_ntilde_v, tmp1, capital_gamma); // capital_ntilde_v = ( capital_ntilde_v * pseudonym_projected ) % capital_gamma bi_mul(capital_ntilde_v, capital_ntilde_v, pseudonym_projected); bi_mod( capital_ntilde_v, capital_ntilde_v, capital_gamma); } else { #ifdef ANONYMITY_REVOCATION // anonymity revocation enabled sig_pseudonym_encrypted = (TSS_DAA_PSEUDONYM_ENCRYPTED_internal *)pseudonym; s_tau = sig_pseudonym_encrypted->sTau; pseudonym_enc = sig_pseudonym_encrypted->cs_enc_result; // Note: It verifies if s_tau <= rho result_random = compute_ecryption_proof( pseudonym_projected, pseudonym_enc->c1, pseudonym_enc->c2, pseudonym_enc->c3, s_tau, verifier_transaction->anonymity_revocator_pk, issuer_pk, verifier_transaction->anonymity_revocation_condition, verifier_transaction->anonymity_revocation_condition_length, DAA_PARAM_get_message_digest() ); encryption_result = result_random->result; delta_tilde1 = apply_challenge( encryption_result->c1, pseudonym_enc->c1, c, capital_gamma); delta_tilde2 = apply_challenge( encryption_result->c2, pseudonym_enc->c2, c, capital_gamma); delta_tilde3 = apply_challenge( encryption_result->c3, pseudonym_enc->c3, c, capital_gamma); delta_tilde4 = apply_challenge( encryption_result->c4, pseudonym_enc->c4, c, capital_gamma); pseudonym_encryption_proof = create_CS_ENCRYPTION_RESULT( delta_tilde1, delta_tilde2, delta_tilde3, delta_tilde4); #endif } // TODO: Step 5 - Callback LogDebug("Step 5 - Callback"); LogDebug("Step 6 - Hash"); ch = compute_sign_challenge_host( &length_ch, DAA_PARAM_get_message_digest(), issuer_pk, nonce_verifierLength, nonce_verifier, 0, // verifier_transaction->selected_attributes2commitLength, NULL, //verifier_transaction->selected_attributes2commit, 0, // verifier_transaction->is_anonymity_revocation_enabled, signature->zeta, signature->capitalT, capital_THat, 0, //signature_ext.attributeCommitmentsLength, NULL, // signature_ext.attributeCommitments, commitment_proofs, capital_nv, capital_ntilde_v, NULL, // verifier_transaction->anonymity_revocator_pk, pseudonym_enc, pseudonym_encryption_proof); LogDebug("calculation of c: ch[%d]%s", length_ch, dump_byte_array( length_ch, ch)); LogDebug("calculation of c: nonce_tpm[%d]%s", signature->nonce_tpm_length, dump_byte_array( signature->nonce_tpm_length, signature->nonce_tpm)); LogDebug("calculation of c: sign_data.payloadFlag[%d]%x", 1, sign_data.payloadFlag); LogDebug("calculation of c: signdata.payload[%d]%s", sign_data.payloadLength, dump_byte_array( sign_data.payloadLength, sign_data.payload)); mdctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); EVP_DigestUpdate(mdctx, ch, length_ch); EVP_DigestUpdate(mdctx, signature->nonce_tpm, signature->nonce_tpm_length); len_hash = EVP_MD_size( DAA_PARAM_get_message_digest()); hash = (BYTE *)malloc( len_hash);// allocation if (hash == NULL) { LogError("malloc of %d bytes failed", len_hash); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } EVP_DigestFinal_ex(mdctx, hash, NULL); EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); EVP_DigestUpdate(mdctx, hash, EVP_MD_size( DAA_PARAM_get_message_digest())); EVP_DigestUpdate(mdctx, &sign_data.payloadFlag, 1); EVP_DigestUpdate(mdctx, sign_data.payload, sign_data.payloadLength); len_hash = EVP_MD_size( DAA_PARAM_get_message_digest()); free( hash); hash = (BYTE *)malloc( len_hash);// allocation if (hash == NULL) { LogError("malloc of %d bytes failed", len_hash); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } EVP_DigestFinal(mdctx, hash, NULL); if( signature->challenge_length != len_hash || memcmp( signature->challenge, hash, len_hash) != 0) { LogError( "Verification of c failed - Step 6.c.i"); LogError(" - challenge[%d] : %s", signature->challenge_length, dump_byte_array( signature->challenge_length, signature->challenge)); LogError(" - hash[%d] : %s", len_hash, dump_byte_array( len_hash, hash)); result = TSS_E_INTERNAL_ERROR; goto close; } if( verifier_transaction == NULL || !verifier_transaction->is_anonymity_revocation_enabled) { // Nv element ? if( !is_element_gamma( capital_nv, issuer_pk) ) { LogError( "Verification of Nv failed - Step 4.b.i"); result = TSS_E_INTERNAL_ERROR; goto close; } } else { // are delta1-4 element ? if( !( is_element_gamma( pseudonym_enc->c1, issuer_pk) && is_element_gamma( pseudonym_enc->c2, issuer_pk) && is_element_gamma( pseudonym_enc->c3, issuer_pk) && is_element_gamma( pseudonym_enc->c4, issuer_pk))) { LogError( "Verification of delta1-4 failed - Step 4.c.i"); result = TSS_E_INTERNAL_ERROR; goto close; } } // zeta element if( !is_element_gamma( signature->zeta, issuer_pk)) { LogError( "Verification of zeta failed - Step 4.b/c.i"); result = TSS_E_INTERNAL_ERROR; goto close; } bits = DAA_PARAM_SIZE_F_I + DAA_PARAM_SAFETY_MARGIN + DAA_PARAM_SIZE_MESSAGE_DIGEST + 1; if( bi_length( signature->sF0) > bits) { LogError("Verification of sF0 failed - Step 6.c.ii"); result = TSS_E_INTERNAL_ERROR; goto close; } if( bi_length( signature->sF1) > bits) { LogError("Verification of sF1 failed - Step 6.c.ii"); result = TSS_E_INTERNAL_ERROR; goto close; } // attributes extension for( i=0; ilength; i++) { if( sA->array[i] != NULL && bi_length(sA->array[i]) > bits) { LogError( "Verification of sA[%d] failed - Step 6.c.ii", i); result = TSS_E_INTERNAL_ERROR; goto close; } } bits = DAA_PARAM_SIZE_INTERVAL_EXPONENT_CERTIFICATE + DAA_PARAM_SAFETY_MARGIN + DAA_PARAM_SIZE_MESSAGE_DIGEST + 1; if( bi_length( signature->sE) > bits) { LogError("Verification of sE failed - Step 6.c.iii"); result = TSS_E_INTERNAL_ERROR; goto close; } // step 4 // TODO: implement revocation list *isCorrect = TRUE; close: EVP_MD_CTX_destroy(mdctx); bi_free_ptr( tmp1); if( ch != NULL) free( ch); if( hash != NULL) free( hash); free_TSS_DAA_PK_internal( issuer_pk); free_TSS_DAA_SIGNATURE_internal( signature); // n not allocated, refere to issuer_pk->modulus FREE_BI( c); // capital_gamma not allocated, refere to issuer_pk->capitalGamma FREE_BI( zeta_2_verify); // capital_z not allocated, refere to issuer_pk->capitalZ // capital_R not allocated, refere to issuer_pk->capitalY FREE_BI( product_r); FREE_BI( exp); FREE_BI( capital_THat); // beta_tilde kept on TSS_DAA_ATTRIB_COMMIT FREE_BI( gamma_i); FREE_BI( capital_nv); FREE_BI( capital_ntilde_v); FREE_BI( pseudonym_projected); FREE_BI( s_tau); // delta_tilde1 kept on CS_ENCRYPTION_RESULT // delta_tilde2 kept on CS_ENCRYPTION_RESULT // delta_tilde3 kept on CS_ENCRYPTION_RESULT // delta_tilde4 kept on CS_ENCRYPTION_RESULT return result; } trousers-0.3.15/src/tspi/daa/daa_verifier/test/0000775000175000017510000000000013663651711020646 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/daa_verifier/test/Makefile.am0000664000175000017510000000065413663651711022707 0ustar deboradeborabin_PROGRAMS = verifier_transaction verifier_transaction_SOURCES = ../verifier_transaction.c ../../daa_structs.c \ ../../big_integer/bi_gmp.c ../../big_integer/bi_openssl.c ../../big_integer/bi.c \ ../../../include/bi.h ../../../include/bi_openssl.h ../../../include/bi_gmp.h \ ../../../include/list_.h ../../utils/list.c ../../../include/tss/tss.h ../../../include/daa_parameter.h \ ../../../include/daa_structs.h trousers-0.3.15/src/tspi/daa/daa_verifier/verifier.c0000664000175000017510000000257313663651711021655 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include "bi.h" #include "daa_parameter.h" #include "trousers/tss.h" #include "spi_internal_types.h" #include "spi_utils.h" #include #include #include "tsplog.h" #include "tss/tcs.h" #include "platform.h" #include "verifier.h" TSPICALL Tspi_DAA_VerifyInit_internal ( TSS_HDAA hDAA, // in UINT32* nonceVerifierLength, // out BYTE** nonceVerifier, // out UINT32 baseNameLength, // out BYTE ** baseName // out ) { TSS_RESULT result = TSS_SUCCESS; TCS_CONTEXT_HANDLE tcsContext; bi_ptr nounce = NULL; //TODO how to setup the baseName & baseNameLength if( (result = obj_daa_get_tsp_context( hDAA, &tcsContext)) != TSS_SUCCESS) goto close; *nonceVerifierLength = DAA_PARAM_LENGTH_MESSAGE_DIGEST; *nonceVerifier = calloc_tspi( tcsContext, DAA_PARAM_LENGTH_MESSAGE_DIGEST); if (*nonceVerifier == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_LENGTH_MESSAGE_DIGEST); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } nounce = bi_new_ptr(); bi_urandom( nounce, DAA_PARAM_LENGTH_MESSAGE_DIGEST * 8); bi_2_byte_array( *nonceVerifier, DAA_PARAM_LENGTH_MESSAGE_DIGEST, nounce); close: FREE_BI( nounce); return result; } trousers-0.3.15/src/tspi/daa/daa_debug.h0000664000175000017510000000311713663651711017315 0ustar deboradebora /******************************************************************************************** * KEY PAIR WITH PROOF ********************************************************************************************/ typedef struct tdKEY_PAIR_WITH_PROOF_internal { TSS_DAA_PK_internal *pk; DAA_PRIVATE_KEY_internal *private_key; TSS_DAA_PK_PROOF_internal *proof; } KEY_PAIR_WITH_PROOF_internal; int save_KEY_PAIR_WITH_PROOF( FILE *file, KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof ); KEY_PAIR_WITH_PROOF_internal *load_KEY_PAIR_WITH_PROOF( FILE *file ); TSS_DAA_KEY_PAIR *get_TSS_DAA_KEY_PAIR( KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT param_alloc ); int save_DAA_PK_internal( FILE *file, const TSS_DAA_PK_internal *pk_internal ); TSS_DAA_PK_internal *load_DAA_PK_internal( FILE *file ); int save_DAA_PRIVATE_KEY( FILE *file, const DAA_PRIVATE_KEY_internal *private_key ); DAA_PRIVATE_KEY_internal *load_DAA_PRIVATE_KEY( FILE *file ); int save_DAA_PK_PROOF_internal( FILE *file, TSS_DAA_PK_PROOF_internal *pk_internal ); TSS_DAA_PK_PROOF_internal *load_DAA_PK_PROOF_internal( FILE *file ); TSS_DAA_CRED_ISSUER *load_TSS_DAA_CRED_ISSUER( FILE *file); int save_TSS_DAA_CRED_ISSUER( FILE *file, TSS_DAA_CRED_ISSUER *credential); TSS_DAA_CREDENTIAL *load_TSS_DAA_CREDENTIAL( FILE *file); int save_TSS_DAA_CREDENTIAL( FILE *file, TSS_DAA_CREDENTIAL *credential ); trousers-0.3.15/src/tspi/daa/daa_platform/0000775000175000017510000000000013663651711017700 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/daa_platform/test_join.c0000664000175000017510000003752113663651711022052 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include "daa_structs.h" #include "trousers/tss.h" #include "trousers/trousers.h" #include "spi_internal_types.h" #include "spi_utils.h" #include "obj.h" #include "tsplog.h" #include "daa_parameter.h" #include "verifier.h" #include "platform.h" // for RSA Key #include #define DEFAULT_FILENAME "issuer.txt" #define DEFAULT_CREDENTIAL_FILENAME "credential.txt" #define DEFAULT_DAACOUNTER 0x01020304 #define DEFAULT_OWN_PASSWD "OWN_PWD" // from IssuerFactory static const int DEFAULT_KEY_CHAIN_LENGTH = 3; typedef struct tdIssuer { // use on Tspi calls TSS_DAA_PK *pk_extern; TSS_DAA_KEY_PAIR *key_pair_extern; // used internally int length_key_chain; RSA **key_chain; TSS_DAA_PK_internal *pk; DAA_PRIVATE_KEY_internal *private_key; TSS_DAA_PK_PROOF_internal *pk_proof; //RSA **auth_key_pairs; BYTE **pk_signatures; bi_ptr zeta; } Issuer; void *alloc( UINT32 length, TCS_CONTEXT_HANDLE tcsContext) { void *result = calloc_tspi( tcsContext, length); LogDebug("allocate tspi memory:%d", (int)result); return result; } /** Used by RSA_generate_key From RSA_generate_key documentation: -> callback(2, n, cb_arg) is called when n-th randomly generated prime is rejected -> callback(3, 0, cb_arg) is called when p is found with p-1 more or less prime to e -> callback(3, 1, cb_arg) repeatedly called for prime q */ void callback(int step, int number, void *arg) { #ifdef DAA_DEBUG putc( '.', stdout); fflush( stdout); #endif } int sign( BYTE *buffer_2_sign, int len_buffer_2_sign, RSA *rsa, BYTE *signature, int *len_signature ) { EVP_MD_CTX *ctx; int len_message = EVP_MD_size( EVP_sha1()), current_len_message; BYTE *message = (BYTE *)malloc( len_message); int ret; ctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); EVP_DigestUpdate(ctx, buffer_2_sign, len_buffer_2_sign); EVP_DigestFinal_ex(ctx, message, ¤t_len_message); LogDebug("Sign rsa-> with message (length=%d)", current_len_message); // int RSA_sign(int type, unsigned char *m, unsigned int m_len, // unsigned char *sigret, unsigned int *siglen, RSA *rsa); ret = RSA_sign( NID_sha1, message, current_len_message, signature, len_signature, rsa); if( ret == 0) { LogError("Error in RSA_sign: %s", ERR_error_string( ERR_get_error(), NULL)); } LogDebug("Sign rsa-> signature (length=%d)", *len_signature ); EVP_MD_CTX_destroy(ctx); free( message); return ret; } /* Compute key chain. */ static int init_key_chain(int length_key_chain, Issuer *issuer) { BYTE *signature; int i, len_sign, ret; BYTE *modulus; BYTE *message; // generate RSA key of length DAA_PARAM_KEY_SIZE with exponent // 65537 (java.security.spec.RSAKeyGenParameterSpec.F4) unsigned long e = 65537; RSA *rsa; bi_ptr bi; EVP_MD_CTX *ctx; int len_message = EVP_MD_size( EVP_sha1()); int current_len_message; EVP_MD_CTX_create(ctx); message = (BYTE *)malloc(len_message); if( length_key_chain < 1) { free( message); return -1; } issuer->length_key_chain = length_key_chain; issuer->key_chain = (RSA **)malloc(sizeof(RSA *) * length_key_chain); issuer->pk_signatures = (BYTE **)malloc(sizeof(BYTE *) * length_key_chain); for(i = 0; in) + 7) / 8 != (DAA_PARAM_KEY_SIZE + 7) / 8) { LogError("BN_num_bits(rsa->n) + 7) / 8 != (DAA_PARAM_KEY_SIZE + 7) / 8)"); return -1; } issuer->key_chain[i] = rsa; if( i > 0) { signature = (BYTE *)malloc( RSA_size(rsa)); modulus = (BYTE *)malloc( DAA_PARAM_KEY_SIZE / 8); // signature algorithm from Issuer.java - "SHA1withRSA" // sign the modulus (n) of the RSA key with the previous RSA key (chain) // sign rsa(i)->n with auth_key_pairs[i-1] LogDebug("modulus=%s\n", dump_byte_array(256, modulus)); LogDebug("signature=%s\n", dump_byte_array(256, signature)); bi = bi_new_ptr(); bi_set_as_hex( bi, BN_bn2hex( rsa->n)); bi_2_byte_array( modulus, DAA_PARAM_KEY_SIZE / 8, bi); LogDebug("bi=%s", bi_2_hex_char( bi)); bi_free_ptr( bi); EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); EVP_DigestUpdate(ctx, modulus, DAA_PARAM_KEY_SIZE / 8); EVP_DigestFinal_ex(ctx, message, ¤t_len_message); ret = RSA_sign( NID_sha1, message, current_len_message, signature, &len_sign, issuer->key_chain[i-1]); if( ret == 0) { LogError("Error in RSA_sign: %s", ERR_error_string( ERR_get_error(), NULL)); } LogDebug("Sign rsa->n (length=%d) with signature (length=%d,\ truelength=%d message_len=%d) ret = %d ERROR?=%s", RSA_size(rsa), DAA_PARAM_KEY_SIZE / 8, len_sign, current_len_message, ret, ERR_error_string( ERR_get_error(), NULL) ); LogDebug("message=%s\n", dump_byte_array(256, message)); LogDebug("signature=%s\n",dump_byte_array(256, signature)); issuer->pk_signatures[i-1] = signature; } } free( message); EVP_MD_CTX_destroy(ctx); return 0; } Issuer* initIssuer(int length_key_chain, char *filename, char *exec, TSS_HCONTEXT hContext) { FILE *file; EVP_MD_CTX *mdctx; Issuer *issuer = (Issuer *)malloc(sizeof( Issuer)); TPM_DAA_ISSUER *tpm_daa_issuer; bi_ptr modulus_N0; int len_issuer_settings, len_signature; BYTE *modulus_N0_bytes; BYTE *digest_n0; BYTE *issuer_settings_byte_array; BYTE *sign_data; BYTE *signature; RSA *private_nn; KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof; LogDebug("Loading issuer info (keypair & proof) -> \'%s\'", filename); file = fopen( filename, "r"); if( file == NULL) { fprintf( stderr, "%s: Error when opening \'%s\': %s\n", exec, filename, strerror( errno)); free( issuer); return NULL; } key_pair_with_proof = load_KEY_PAIR_WITH_PROOF( file); if( key_pair_with_proof == NULL) { LogError( "Error when reading \'%s\': %s\n", filename, strerror( errno)); free( issuer); return NULL; } fclose( file); issuer->pk = key_pair_with_proof->pk; issuer->pk_extern = i_2_e_TSS_DAA_PK( issuer->pk, &alloc, hContext); issuer->key_pair_extern = (TSS_DAA_KEY_PAIR *)malloc( sizeof(TSS_DAA_KEY_PAIR)); init_tss_version( issuer->key_pair_extern); issuer->key_pair_extern->public_key = issuer->pk_extern; issuer->key_pair_extern->private_key = i_2_e_TSS_DAA_PRIVATE_KEY( key_pair_with_proof->private_key, &alloc, hContext); issuer->pk_proof = key_pair_with_proof->proof; issuer->private_key = key_pair_with_proof->private_key; init_key_chain( length_key_chain, issuer); issuer->zeta = compute_zeta( issuer->pk->issuerBaseNameLength, issuer->pk->issuerBaseName, issuer->pk); // sign "issuer settings" modulus_N0 = bi_new_ptr(); bi_set_as_hex( modulus_N0, BN_bn2hex( issuer->key_chain[0]->n)); // in TPM, N0 is hashed by hashing the scratch (256 bytes) so it must // be formatted according to the scratch size (TPM_DAA_SIZE_issuerModulus) modulus_N0_bytes = (BYTE *)malloc( TPM_DAA_SIZE_issuerModulus); bi_2_byte_array( modulus_N0_bytes, TPM_DAA_SIZE_issuerModulus, modulus_N0); bi_free_ptr( modulus_N0); if( TPM_DAA_SIZE_issuerModulus * 8 != DAA_PARAM_KEY_SIZE) { LogError("TPM_DAA_SIZE_issuerModulus * 8 (%d) != DAA_PARAM_KEY_SIZE(%d)", TPM_DAA_SIZE_issuerModulus*8, DAA_PARAM_KEY_SIZE); free( issuer); return NULL; } EVP_MD_CTX_create(mdctx); EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); // digestN0 = hash( modulus_N0) EVP_DigestUpdate(mdctx, modulus_N0_bytes, TPM_DAA_SIZE_issuerModulus); digest_n0 = (BYTE *)EVP_MD_CTX_create(); EVP_DigestFinal_ex(mdctx, digest_n0, NULL); tpm_daa_issuer = convert2issuer_settings( issuer->pk); issuer_settings_byte_array = issuer_2_byte_array( tpm_daa_issuer, &len_issuer_settings); // data to sign: concatenation of digest_n0 and issuer_settings_byte_array sign_data = (BYTE *)malloc( EVP_MD_CTX_size(mdctx) + len_issuer_settings); memcpy( sign_data, digest_n0, EVP_MD_CTX_size(mdctx)); memcpy( &sign_data[EVP_MD_CTX_size(mdctx)], issuer_settings_byte_array, len_issuer_settings); free( issuer_settings_byte_array); // sign digest of TPM compatible Issuer key (sign_data) private_nn = issuer->key_chain[issuer->length_key_chain - 1]; signature = (BYTE *)malloc( RSA_size(private_nn)); if ( sign( sign_data, EVP_MD_CTX_size(mdctx) + len_issuer_settings, private_nn, signature, &len_signature) ==0) { LogError("Can not sign digest of TPM compatible Issuer key"); goto close; } issuer->pk_signatures[ issuer->length_key_chain - 1] = signature; LogDebug("Set last signature sign[%d] = %s", issuer->length_key_chain - 1, dump_byte_array(EVP_MD_size( EVP_sha1()), signature)); // TODO sign the complete public key of TPM compatible Issuer key /* EVP_DigestInit_ex(mdctx, DAA_PARAM_get_message_digest(), NULL); EVP_DigestUpdate(mdctx, digest_n0, EVP_MD_CTX_size(mdctx)); pk_encoded = encoded_DAA_PK_internal( &pk_encodedLength, issuer->pk); EVP_DigestUpdate(mdctx, pk_encoded, pk_encodedLength); EVP_DigestFinal(mdctx, , NULL); signature = (BYTE *)malloc( EVP_MD_size( EVP_sha1())); if (sign( sign_data, EVP_MD_CTX_size(mdctx) + len_issuer_settings, private_nn, signature, &len_signature) !=0) goto close; */ close: EVP_MD_CTX_destroy(mdctx); free( digest_n0); free( sign_data); return issuer; } int print_usage(char *exec) { fprintf(stderr, "usage: %s\n", exec); fprintf(stderr, "\t-if,\t--issuer_file\n\t\tthe file that will contain all key\ pair and proof to be used by the issuer\n\t\t (default: %s)\n", DEFAULT_FILENAME); fprintf(stderr, "\t-dc,\t--daa_counter\n\t\tdaa counter (default: %d)\n", DEFAULT_DAACOUNTER); fprintf(stderr, "\t-pw,\t--passwd\n\t\ttpm owner password (default: %s)\n", DEFAULT_OWN_PASSWD); return -1; } int main(int argc, char *argv[]) { TSS_HCONTEXT hContext; TSS_RESULT result; TSS_HTPM hTPM; TSS_HPOLICY hPolicy; int i, length; char *param, *filename = DEFAULT_FILENAME; char *credential_filename = DEFAULT_CREDENTIAL_FILENAME; UINT32 daaCounter = DEFAULT_DAACOUNTER; UINT32 capital_UPrimeLength; BYTE *capitalUPrime; TSS_DAA_IDENTITY_PROOF identityProof; TSS_DAA_JOIN_SESSION joinSession; TSS_DAA_JOIN_ISSUER_SESSION join_issuer_session; TSS_DAA_CREDENTIAL_REQUEST credentialRequest; TSS_DAA_CRED_ISSUER credIssuer; TSS_HDAA hDAA; Issuer* issuer; char *szTpmPasswd = DEFAULT_OWN_PASSWD; UINT32 endorsementKeyLength; BYTE *endorsementKey; UINT32 nonceIssuerLength; BYTE *nonceIssuer; UINT32 authenticationChallengeLength; BYTE *authenticationChallenge; bi_array_ptr capital_receiver; BYTE **attributesPlatform; UINT32 attributesPlatformLength; BYTE **attributesIssuer; UINT32 attributesIssuerLength; bi_t random; FILE *file; init_tss_version( &identityProof); init_tss_version( &joinSession); init_tss_version( &join_issuer_session); init_tss_version( &credentialRequest); init_tss_version( &credIssuer); i = 1; while( i < argc) { param = argv[ i]; if ( strcmp( param, "-if") == 0 || strcmp( param, "--issuer_file") == 0) { i++; if( i == argc) return print_usage( argv[0]); filename = argv[i]; } else if( strcmp( param, "-dc") == 0 || strcmp( param, "--daa_counter") == 0){ i++; if( i == argc) return print_usage( argv[0]); daaCounter = atoi(argv[i]); } else if( strcmp( param, "-pw") == 0 || strcmp( param, "--passwd") == 0){ i++; if( i == argc) return print_usage( argv[0]); szTpmPasswd = argv[i]; } else { fprintf(stderr, "\n%s:unrecognized option <%s>\n", argv[0], param); return print_usage( argv[0]); } i++; } bi_init( NULL); // Create Context LogDebug("Create Context"); result = Tspi_Context_Create( &hContext ); if ( result != TSS_SUCCESS ) { LogError( "Tspi_Context_Create %d\n", result ); goto out; } // Connect to Context result = Tspi_Context_Connect( hContext, NULL ); if ( result != TSS_SUCCESS) goto out_close; printf("\nConnect to the context: %X\n", hContext); if( (result = Tspi_Context_GetTpmObject( hContext, &hTPM)) != TSS_SUCCESS) goto out_close; // Get the correct policy using the TPM ownership PASSWD if( (result = Tspi_GetPolicyObject( hTPM, TSS_POLICY_USAGE, &hPolicy)) != TSS_SUCCESS) goto out_close; if( (result = Tspi_Policy_SetSecret( hPolicy, TSS_SECRET_MODE_PLAIN, strlen( szTpmPasswd), szTpmPasswd)) != TSS_SUCCESS) goto out_close; LogDebug("Tspi_Policy_SetSecret hPolicy received;%d\n", hPolicy); //Create Object result = obj_daa_add( hContext, &hDAA); if (result != TSS_SUCCESS) { LogError("Tspi_Context_CreateObject:%d\n", result); Tspi_Context_Close(hContext); LogError("%s: %s\n", argv[0], err_string(result)); exit(result); } LogDebug("created DAA object:%X", hDAA); issuer = initIssuer( DEFAULT_KEY_CHAIN_LENGTH, filename, argv[0], hContext); if( issuer == NULL) goto out_close; // generate receiver attributes and issuer attributes (random) attributesPlatformLength = issuer->pk->capitalRReceiver->length; attributesPlatform = (BYTE **)malloc( attributesPlatformLength * sizeof(BYTE *)); bi_new( random); for( i=0; i<(int)attributesPlatformLength; i++) { bi_urandom( random, DAA_PARAM_SIZE_F_I); attributesPlatform[i] = bi_2_nbin( &length, random); if( attributesPlatform[i] == NULL) { LogError("malloc of %d bytes failed", length); result = TSPERR(TSS_E_OUTOFMEMORY); goto out_close; } } attributesIssuerLength = issuer->pk->capitalRIssuer->length; attributesIssuer = (BYTE **)malloc( attributesIssuerLength * sizeof(BYTE *)); for( i=0; i<(int)attributesIssuerLength; i++) { bi_urandom( random, DAA_PARAM_SIZE_F_I); attributesIssuer[i] = bi_2_nbin( &length, random); if( attributesIssuer[i] == NULL) { LogError("malloc of %d bytes failed", length); result = TSPERR(TSS_E_OUTOFMEMORY); goto out_close; } } bi_free(random); LogDebug("Generated attributes (Platform=%d,Issuer=%d)", attributesPlatformLength, attributesIssuerLength); result = Tspi_TPM_DAA_JoinInit( hDAA, // in hTPM, // in daaCounter, // in (TSS_HKEY)issuer->pk_extern, // in issuer->length_key_chain, // in (TSS_HKEY *)issuer->key_chain, // in issuer->length_key_chain, // in issuer->pk_signatures, // in &capital_UPrimeLength, // out &capitalUPrime, // out &identityProof, // out &joinSession // out ); if( result != TSS_SUCCESS) goto out_close; result = Tspi_DAA_IssueInit( hDAA, // in (TSS_HKEY)issuer->key_chain[0], // in (TSS_HKEY)issuer->key_pair_extern, // in identityProof, // in capital_UPrimeLength, // in capitalUPrime, // in daaCounter, // in &nonceIssuerLength, // out &nonceIssuer, // out &authenticationChallengeLength, // out &authenticationChallenge, // out &join_issuer_session // out ); if( result != TSS_SUCCESS) goto out_close; result = Tspi_TPM_DAA_JoinCreateDaaPubKey( hDAA, // in hTPM, // in authenticationChallengeLength, // in authenticationChallenge, // in nonceIssuerLength, // in nonceIssuer, // in attributesPlatformLength, // in attributesPlatform, // in &joinSession, // in & out &credentialRequest // out ); if( result != TSS_SUCCESS) goto out_close; result = Tspi_DAA_IssueCredential( hDAA, // in attributesIssuerLength, // in attributesIssuer, // in credentialRequest, // in join_issuer_session, // in &credIssuer // out ); result = Tspi_TPM_DAA_JoinStoreCredential( hDAA, // in hTPM, // in credIssuer, // in joinSession, // in (TSS_HKEY*)&credentialRequest // out ); if( result != TSS_SUCCESS) goto out_close; printf("Saving credential: %s ", credential_filename); file = fopen( credential_filename, "w"); if( save_TSS_DAA_CREDENTIAL( file, &credentialRequest) != 0) { LogError( "[test_join]: Error when saving \'%s\': %s", credential_filename, strerror( errno)); result = TSS_E_FAIL; goto out_close; } fclose( file); printf("Done\n"); out_close: Tspi_Context_FreeMemory( hContext, NULL ); Tspi_Context_Close( hContext ); out: bi_release(); LogDebug("THE END result=%d:%s",result, err_string( result) );; return result; } trousers-0.3.15/src/tspi/daa/daa_platform/test.c0000664000175000017510000001255713663651711021035 0ustar deboradebora #include #include #include #include #include "spi_internal_types.h" #include #include #include "tsplog.h" #include "daa_parameter.h" setenv("TCSD_FOREGROUND", "1", 1); // simulating Tspi_TPM_DAA_JoinInit (spi_daa.c) TSS_RESULT Tspi_DAA_Join(TSS_HTPM hTPM, int stage, UINT32 inputSize0, BYTE *inputData0, UINT32 inputSize1, BYTE *inputData1, UINT32 *outputSize, BYTE **outputData) { TSS_RESULT result; TCS_CONTEXT_HANDLE tcsContext; TSS_HCONTEXT tspContext; TSS_HPOLICY hPolicy; TCPA_DIGEST digest; TPM_AUTH ownerAuth; UINT16 offset = 0; BYTE hashblob[1000]; printf("[%s:%d] obj_tpm_is_connected(hTPM)\n", __FILE__, __LINE__); if( (result = obj_tpm_is_connected( hTPM, &tcsContext)) != TSS_SUCCESS) return result; printf("[%s:%d] obj_tpm_get_tsp_context(hTPM)\n", __FILE__, __LINE__); if( (result = obj_tpm_get_tsp_context( hTPM, &tspContext)) != TSS_SUCCESS) return result; printf("[%s:%d] obj_tpm_get_policy(hTPM)\n", __FILE__, __LINE__); if( (result = obj_tpm_get_policy( hTPM, &hPolicy)) != TSS_SUCCESS) return result; printf("[%s:%d] Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Join, hashblob)\n", __FILE__, __LINE__); Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Join, hashblob); // hash TPM_COMMAND_CODE printf("[%s:%d] Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest)\n",__FILE__, __LINE__); Trspi_LoadBlob_BYTE(&offset, stage, hashblob); // hash stage printf("[%s:%d] Trspi_LoadBlob_UINT32(&offset, 0, hashblob)\n",__FILE__, __LINE__); //TODO old 4 Trspi_LoadBlob_UINT32(&offset, inputSize0, hashblob); // hash inputSize0 printf("[%s:%d] Trspi_LoadBlob_UINT32(&offset, 0, hashblob)\n",__FILE__, __LINE__); Trspi_LoadBlob( &offset, inputSize0, hashblob, inputData0); // hash inputData0 //TODO old 1 Trspi_LoadBlob_UINT32(&offset, inputSize1, hashblob); // hash inputSize1 printf("[%s:%d] Trspi_LoadBlob_UINT32(&offset, 0, hashblob)\n",__FILE__, __LINE__); Trspi_LoadBlob( &offset, inputSize1, hashblob, inputData1); // hash inputData1 Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest); if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_DAA_Join, hPolicy, &digest, &ownerAuth)) != TSS_SUCCESS) return result; printf("[%s:%d] secret_PerformAuth_OIAP(hTPM, TPM_ORD_DAA_Join ret=%d\n",__FILE__, __LINE__, result); // out /* step of the following call: TCSP_DAAJoin tcsd_api/calltcsapi.c (define in spi_utils.h) TCSP_DAAJoin_TP tcsd_api/tcstp.c (define in trctp.h) */ printf("[%s:%d] TCSP_DAAJoin(%x,%x,%x,%x,%x,%x,%x)\n",__FILE__, __LINE__, (int)hTPM, 0, inputSize0,(int)inputData0,inputSize1,(int)inputData1,(int)&ownerAuth); if ( (result = TCSP_DaaJoin( tcsContext, hTPM, 0, inputSize0, inputData0, inputSize1, inputData1, &ownerAuth, outputSize, outputData)) != TSS_SUCCESS) return result; offset = 0; Trspi_LoadBlob_UINT32(&offset, result, hashblob); Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Join, hashblob); Trspi_LoadBlob_UINT32(&offset, *outputSize, hashblob); Trspi_LoadBlob(&offset, *outputSize, hashblob, *outputData); Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest); if( (result = obj_policy_validate_auth_oiap( hPolicy, &digest, &ownerAuth))) { printf("[%s:%d] obj_policy_validate_auth=%d\n",__FILE__, __LINE__, result); } return result; } int main(int argc, char *argv[]) { TSS_HCONTEXT hContext; TSS_RESULT result; TSS_HTPM hTPM; TSS_HPOLICY hPolicy; // Create Context printf("Create Context\n"); result = Tspi_Context_Create( &hContext ); if ( result != TSS_SUCCESS ) { fprintf( stderr, "Tspi_Context_Create %d\n", result ); exit( result ); } // Connect to Context printf("\nConnect to the context\n"); result = Tspi_Context_Connect( hContext, NULL ); if ( result != TSS_SUCCESS ) goto out_close; if( (result = Tspi_Context_GetTpmObject( hContext, &hTPM)) != TSS_SUCCESS) goto out_close; // Get the correct policy using the TPM ownership PASSWD char *szTpmPasswd = "OWN_PWD"; if( (result = Tspi_GetPolicyObject( hTPM, TSS_POLICY_USAGE, &hPolicy)) != TSS_SUCCESS) goto out_close; //BUSS if( (result = Tspi_Policy_SetSecret( hPolicy, TSS_SECRET_MODE_PLAIN, strlen( szTpmPasswd), szTpmPasswd)) != TSS_SUCCESS) goto out_close; printf("Tspi_Policy_SetSecret hPolicy received;%d\n", hPolicy); //BUSS // in //int modulus_length = DAA_PARAM_SIZE_MODULUS_GAMMA / 8; UINT32 inputSize0 = sizeof(int); UINT32 inputSize1 = 0; UINT32 outputSize = 0; int ia_length = 7; BYTE *inputData0 = (BYTE *)(&ia_length);//= (BYTE *)malloc( inputSize0) BYTE *inputData1 = NULL; BYTE *outputData = NULL; if( (result = Tspi_DAA_Join(hTPM, 0, inputSize0, inputData0, inputSize1, inputData1, &outputSize, &outputData)) != TSS_SUCCESS) goto out_close; goto out; out_close: printf( "Tspi Error:%d - %s\n", result, err_string( result) ); out: printf("ouputSize=%d\n", outputSize); if( outputData != NULL) { int i; printf("outputData(hex )=[\n"); for( i=0; i<(int)outputSize; i++) printf("%x ", outputData[i]); printf("\n]"); printf("outputData(ascii)=[\n"); for( i=0; i<(int)outputSize; i++) printf("%c ", outputData[i]); printf("\n]"); } Tspi_Context_FreeMemory( hContext, NULL ); Tspi_Context_Close( hContext ); printf("[%s:%d] THE END\n",__FILE__, __LINE__); return result; } trousers-0.3.15/src/tspi/daa/daa_platform/platform.c0000664000175000017510000025427013663651711021702 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include // for message digest #include #include #include #include #include #include #include "daa_structs.h" #include "daa_parameter.h" #include "trousers/tss.h" #include "spi_internal_types.h" #include "spi_utils.h" #include #include #include #include "tsplog.h" #include "tss/tcs.h" #include "platform.h" #include "issuer.h" #include "verifier.h" #define EVP_SUCCESS 1 TSS_RESULT Tcsip_TPM_DAA_Join(TCS_CONTEXT_HANDLE tcsContext, // in TSS_HDAA hDAA, // in BYTE stage, // in UINT32 inputSize0, // in BYTE* inputData0, // in UINT32 inputSize1, // in BYTE* inputData1, // in TPM_AUTH* ownerAuth, // in/out UINT32* outputSize, // out BYTE** outputData // out ) { TSS_RESULT result; TSS_HPOLICY hPolicy; TCPA_DIGEST digest; UINT16 offset = 0; BYTE hashblob[10000]; TPM_HANDLE hTPM; TPM_HANDLE join_session; // TPM_HANDLE hTPM; if( (result = obj_daa_get_handle_tpm( hDAA, &hTPM)) != TSS_SUCCESS) return result; if( (result = obj_daa_get_session_handle( hDAA, &join_session)) != TSS_SUCCESS) return result; LogDebug("Tcsip_TPM_DAA_Join(tcsContext=%x,hDAA=%x,join_session=%x, hTPM=%x stage=%d)", tcsContext, hDAA, join_session, hTPM, stage); LogDebug("obj_tpm_get_policy(hTPM=%X)", hTPM); if( (result = obj_tpm_get_policy( hTPM, &hPolicy)) != TSS_SUCCESS) return result; LogDebug("Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Join, hashblob)"); // hash TPM_COMMAND_CODE Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Join, hashblob); LogDebug("Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest)"); // hash stage Trspi_LoadBlob_BYTE(&offset, stage, hashblob); LogDebug("Trspi_LoadBlob_UINT32(&offset, 0, hashblob)"); // hash inputSize0 Trspi_LoadBlob_UINT32(&offset, inputSize0, hashblob); LogDebug("Trspi_LoadBlob_UINT32(&offset, inputSize0:%d", inputSize0); // hash inputData0 Trspi_LoadBlob( &offset, inputSize0, hashblob, inputData0); // hash inputSize1 Trspi_LoadBlob_UINT32(&offset, inputSize1, hashblob); LogDebug("Trspi_LoadBlob_UINT32(&offset, inputSize1:%d", inputSize1); // hash inputData1 Trspi_LoadBlob( &offset, inputSize1, hashblob, inputData1); Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest); if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_DAA_Join, hPolicy, &digest, ownerAuth)) != TSS_SUCCESS) return result; LogDebug("secret_PerformAuth_OIAP(hTPM, TPM_ORD_DAA_Join ret=%d", result); LogDebug("TCSP_DAAJoin(%x,%x,stage=%x,%x,%x,%x,%x,%x)\n", tcsContext, hTPM, stage, inputSize0, (int)inputData0, inputSize1, (int)inputData1, (int)&ownerAuth); /* step of the following call: TCSP_DAAJoin tcsd_api/calltcsapi.c (define in spi_utils.h) TCSP_DAAJoin_TP tcsd_api/tcstp.c (define in trctp.h) */ result = TCSP_DaaJoin( tcsContext, join_session, stage, inputSize0, inputData0, inputSize1, inputData1, ownerAuth, outputSize, outputData); if( result != TSS_SUCCESS) return result; offset = 0; Trspi_LoadBlob_UINT32(&offset, result, hashblob); Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Join, hashblob); Trspi_LoadBlob_UINT32(&offset, *outputSize, hashblob); Trspi_LoadBlob(&offset, *outputSize, hashblob, *outputData); LogDebug("TCSP_DAAJoin stage=%d outputSize=%d outputData=%x RESULT=%d", (int)stage, (int)*outputSize, (int)outputData, (int)result); Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest); if( (result = obj_policy_validate_auth_oiap( hPolicy, &digest, ownerAuth))) { LogError("obj_policy_validate_auth=%d", result); } return result; } TSS_RESULT Tcsip_TPM_DAA_Sign( TCS_CONTEXT_HANDLE hContext, // in TPM_HANDLE handle, // in BYTE stage, // in UINT32 inputSize0, // in BYTE* inputData0, // in UINT32 inputSize1, // in BYTE* inputData1, // in TPM_AUTH* ownerAuth, // in, out UINT32* outputSize, // out BYTE** outputData // out ) { TSS_RESULT result; TSS_HPOLICY hPolicy; TCPA_DIGEST digest; UINT16 offset = 0; BYTE hashblob[1000]; TPM_HANDLE hTPM; TPM_HANDLE session_handle; TSS_HDAA hDAA = (TSS_HDAA)handle; // TPM_HANDLE hTPM; if( (result = obj_daa_get_handle_tpm( hDAA, &hTPM)) != TSS_SUCCESS) return result; if( (result = obj_daa_get_session_handle( hDAA, &session_handle)) != TSS_SUCCESS) return result; LogDebug("Tcsip_TPM_DAA_Sign(tcsContext=%x,hDAA=%x,sign_session=%x, hTPM=%x stage=%d)", hContext, hDAA, session_handle, hTPM, stage); LogDebug("obj_tpm_get_policy(hTPM=%X)", hTPM); if( (result = obj_tpm_get_policy( hTPM, &hPolicy)) != TSS_SUCCESS) return result; LogDebug("Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Sign, hashblob)"); // hash TPM_COMMAND_CODE Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Sign, hashblob); LogDebug("Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest)"); // hash stage Trspi_LoadBlob_BYTE(&offset, stage, hashblob); LogDebug("Trspi_LoadBlob_UINT32(&offset, 0, hashblob)"); // hash inputSize0 Trspi_LoadBlob_UINT32(&offset, inputSize0, hashblob); LogDebug("Trspi_LoadBlob_UINT32(&offset, inputSize0:%d", inputSize0); // hash inputData0 Trspi_LoadBlob( &offset, inputSize0, hashblob, inputData0); // hash inputSize1 Trspi_LoadBlob_UINT32(&offset, inputSize1, hashblob); LogDebug("Trspi_LoadBlob_UINT32(&offset, inputSize1:%d", inputSize1); // hash inputData1 Trspi_LoadBlob( &offset, inputSize1, hashblob, inputData1); Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest); if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_DAA_Join, hPolicy, &digest, ownerAuth)) != TSS_SUCCESS) return result; LogDebug("secret_PerformAuth_OIAP(hTPM, TPM_ORD_DAA_Join ret=%d", result); LogDebug("TCSP_DAASign(%x,%x,stage=%x,%x,%x,%x,%x,%x)", hContext, hTPM, stage, inputSize0,(int)inputData0, inputSize1,(int)inputData1, (int)&ownerAuth); /* step of the following call: TCSP_DAASign tcsd_api/calltcsapi.c (define in spi_utils.h) TCSP_DAASign_TP tcsd_api/tcstp.c (define in trctp.h) */ result = TCSP_DaaSign( hContext, session_handle, stage, inputSize0, inputData0, inputSize1, inputData1, ownerAuth, outputSize, outputData); if( result != TSS_SUCCESS) return result; offset = 0; Trspi_LoadBlob_UINT32(&offset, result, hashblob); Trspi_LoadBlob_UINT32(&offset, TPM_ORD_DAA_Sign, hashblob); Trspi_LoadBlob_UINT32(&offset, *outputSize, hashblob); Trspi_LoadBlob(&offset, *outputSize, hashblob, *outputData); LogDebug("TCSP_DAASign stage=%d outputSize=%d outputData=%x RESULT=%d", (int)stage, (int)*outputSize, (int)outputData, (int)result); Trspi_Hash(TSS_HASH_SHA1, offset, hashblob, digest.digest); if( (result = obj_policy_validate_auth_oiap( hPolicy, &digest, ownerAuth))) { LogError("obj_policy_validate_auth=%d", result); } return result; } /** Only used for the logging */ static TSS_RESULT Tcsip_TPM_DAA_Join_encapsulate(TCS_CONTEXT_HANDLE tcsContext, // in TSS_HDAA hDAA, // in BYTE stage, // in UINT32 inputSize0, // in BYTE* inputData0, // in UINT32 inputSize1, // in BYTE* inputData1, // in TPM_AUTH* ownerAuth, // in/out UINT32* outputSize, // out BYTE** outputData // out ) { TSS_RESULT result; LogDebug("Tcsip_DAA_Join(TCS_CONTEXT=%X,TSS_HDAA=%X,stage=%d,\ inputSize0=%u,inputData0=%s\ninputSize1=%u,inputData1=%s,ownerAuth=%X)", tcsContext, hDAA, stage, inputSize0, dump_byte_array(inputSize0, inputData0), inputSize1,dump_byte_array(inputSize1, inputData1), (int)ownerAuth); result = Tcsip_TPM_DAA_Join( tcsContext, // in hDAA, // in stage, // in inputSize0, // in inputData0, // in inputSize1, // in inputData1, // in ownerAuth, // in/out outputSize, // out outputData // out ); LogDebug("Tcsip_DAA_Join(stage=%d,outputSize=%u outputData=%s ownerAuth=%X) result=%d", (int)stage, *outputSize, dump_byte_array( *outputSize, *outputData), (int)ownerAuth, result); return result; } #if 0 /* from TSS.java */ /* openssl RSA (struct rsa_st) could manage RSA Key */ TSS_RESULT Tspi_TPM_DAA_JoinInit_internal( TSS_HDAA hDAA, TSS_HTPM hTPM, int daa_counter, TSS_DAA_PK *issuer_pk, int issuer_authentication_PKLengh, RSA **issuer_authentication_PK, int issuer_authentication_PK_signaturesLength, BYTE **issuer_authentication_PK_signatures, int *capital_UprimeLength, BYTE **capital_Uprime, TSS_DAA_IDENTITY_PROOF *identity_proof, TSS_DAA_JOIN_SESSION *join_session) { // Optional: verification of the PKDAA and issuer settings (authen. by the RSA Public Key chain) TSS_RESULT result; TCS_CONTEXT_HANDLE tcsContext; TPM_AUTH ownerAuth; int i, modulus_length, outputSize, length, length1; UINT32 return_join_session; BYTE *outputData, *issuer_settings_bytes; BYTE *buffer_modulus; TPM_DAA_ISSUER *issuer_settings; char buffer[1000], buffer1[1000]; TSS_DAA_PK_internal *pk_internal = e_2_i_TSS_DAA_PK( issuer_pk); bi_ptr issuer_authentication_PK_i = NULL; if( (result = obj_tpm_is_connected( hTPM, &tcsContext)) != TSS_SUCCESS) return result; obj_daa_set_handle_tpm( hDAA, hTPM); // stages 0-2 explained in the diagram "Keys of DAA Issuer" // issuer_authentication_PKLengh should be converted to Network Based integer i = htonl(issuer_authentication_PKLengh); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 0, sizeof(int), (BYTE *)(&i), 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { goto close;} // set the sessionHandle to the returned value return_join_session = ntohl( *((UINT32 *)outputData)); free( outputData); obj_daa_set_session_handle( hDAA, return_join_session); LogDebug("done join 0 settings join_session:%x\n", return_join_session); modulus_length = DAA_PARAM_SIZE_RSA_MODULUS / 8; buffer_modulus = malloc(modulus_length); if (buffer_modulus == NULL) { LogError("malloc of %d bytes failed", modulus_length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } issuer_authentication_PK_i = bi_new_ptr(); for(i =0; i< issuer_authentication_PKLengh; i++) { bi_set_as_BIGNUM( issuer_authentication_PK_i, issuer_authentication_PK[i]->n); bi_2_byte_array( buffer_modulus, modulus_length, issuer_authentication_PK_i); if ( i==0) { result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 1, modulus_length, buffer_modulus, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { free( buffer_modulus); goto close; } } else { result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 1, modulus_length, buffer_modulus, DAA_PARAM_KEY_SIZE / 8, issuer_authentication_PK_signatures[i -1], &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { free( buffer_modulus); goto close; } } } free( buffer_modulus); LogDebug("done join 1-%d\n", issuer_authentication_PKLengh); // define issuer_settings issuer_settings = convert2issuer_settings( pk_internal); issuer_settings_bytes = issuer_2_byte_array( issuer_settings, &length); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 2, length, issuer_settings_bytes, modulus_length, issuer_authentication_PK_signatures[issuer_authentication_PKLengh-1], &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { goto close;} LogDebug("done join 2\n"); i = htonl( daa_counter); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 3, sizeof(UINT32), (BYTE *)(&i), 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { goto close;} LogDebug("done join 3\n"); // reserved another buffer for storing Big Integer bi_2_nbin1( &length, buffer, pk_internal->capitalR0); bi_2_nbin1( &length1, buffer1, pk_internal->modulus); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 4, length, buffer, length1, buffer1, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { goto close;} LogDebug("done join 4\n"); bi_2_nbin1( &length, buffer, pk_internal->capitalR1); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 5, length, buffer, length1, buffer1, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { goto close;} LogDebug("done join 5\n"); bi_2_nbin1( &length, buffer, pk_internal->capitalS); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 6, length, buffer, length1, buffer1, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) { goto close;} LogDebug("done join 6\n"); bi_2_nbin1( &length, buffer, pk_internal->capitalSprime); // define Uprime result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 7, length, buffer, length1, buffer1, &ownerAuth, &outputSize, &outputData); // 5 : save PKDAA, U, daaCount and sessionHandle in joinSession join_session->issuerPk = (TSS_HKEY)issuer_pk; if( result == TSS_SUCCESS) { *capital_UprimeLength = outputSize; *capital_Uprime = convert_alloc( tcsContext, outputSize, outputData); if (*capital_Uprime == NULL) { LogError("malloc of %d bytes failed", outputSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } join_session->capitalUPrime = copy_alloc( tcsContext, *capital_UprimeLength, *capital_Uprime); if (join_session->capitalUPrime == NULL) { LogError("malloc of %d bytes failed", *capital_UprimeLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } join_session->capitalUPrimeLength = *capital_UprimeLength; } join_session->sessionHandle = return_join_session; // get the endorsement Key (public part) result = get_public_EK( hTPM, // in &( identity_proof->endorsementLength), &( identity_proof->endorsementCredential) ); close: FREE_BI( issuer_authentication_PK_i); LogDebug("result = %d", result); LogDebug("outputSize=%d", outputSize); LogDebug("outputData=%s", dump_byte_array( outputSize, outputData)); return result; } #else TSS_RESULT Tspi_TPM_DAA_JoinInit_internal(TSS_HTPM hTPM, TSS_HDAA_ISSUER_KEY hIssuerKey UINT32 daa_counter, UINT32 issuerAuthPKsLength, TSS_HKEY* issuerAuthPKs, UINT32 issuerAuthPKSignaturesLength, UINT32 issuerAuthPKSignaturesLength2, BYTE** issuerAuthPKSignatures, UINT32* capitalUprimeLength, BYTE** capitalUprime, TSS_DAA_IDENTITY_PROOF** identity_proof, UINT32* joinSessionLength, BYTE** joinSession) { // Optional: verification of the PKDAA and issuer settings (authen. by the RSA Public Key chain) TSS_RESULT result; TSS_HCONTEXT tspContext; TPM_AUTH ownerAuth; int length, length1; UINT32 i, modulus_length, outputSize, buf_len; BYTE *outputData, *issuer_settings_bytes; BYTE *modulus, stage, *buf; //TPM_DAA_ISSUER *issuer_settings; //char buffer[1000], buffer1[1000]; //TSS_DAA_PK_internal *pk_internal = e_2_i_TSS_DAA_PK(issuer_pk); bi_ptr issuerAuthPK = NULL; TPM_HANDLE daaHandle; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TSS_DAA_IDENTITY_PROOF daaIdentityProof; if ((result = obj_tpm_is_connected(hTPM, &tspContext))) return result; if ((result = obj_daaissuerkey_get_daa_handle(hIssuerKey, &daaHandle))) return result; stage = 0; inputSize0 = (UINT32)sizeof(UINT32); inputData0 = issuerAuthPKsLength; inputSize1 = 0; inputData1 = NULL; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_DAA_Join); result |= Trspi_Hash_BYTE(&hashCtx, stage); result |= Trspi_Hash_UINT32(&hashCtx, inputSize0); result |= Trspi_HashUpdate(&hashCtx, inputSize0, inputData0); result |= Trspi_Hash_UINT32(&hashCtx, inputSize1); result |= Trspi_HashUpdate(&hashCtx, inputSize1, inputData1); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; // stages 0-2 explained in the diagram "Keys of DAA Issuer" if ((result = TCS_API(tspContext)->DaaJoin(tspContext, daaHandle, stage, inputSize1, inputData0, inputSize1, inputData1, &ownerAuth, &outputSize, &outputData))) goto close; if (outputSize != sizeof(UINT32)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto close; } // set the sessionHandle to the returned value Trspi_UnloadBlob_UINT32(&offset, &daaHandle, outputData); free(outputData); if ((result = obj_daaissuerkey_set_daa_handle(hIssuerKey, daaHandle))) goto close; LogDebug("done join 0 settings join_session:%x", daaHandle); modulus_length = DAA_PARAM_SIZE_RSA_MODULUS / 8; if ((buffer_modulus = malloc(modulus_length)) == NULL) { LogError("malloc of %d bytes failed", modulus_length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } stage = 1; for (i = 0; i < issuerAuthPKsLength; i++) { if ((result = obj_rsakey_get_modulus(issuerAuthPKs[i], &modulus_length, &modulus))) goto close; outputData = NULL; if (i==0) { result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, modulus_length, modulus, 0, NULL, &ownerAuth, &outputSize, &outputData); } else { result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, modulus_length, modulus, issuerAuthPKSignaturesLength2, issuerAuthPKSignatures[i - 1], &ownerAuth, &outputSize, &outputData); } free(outputData); free_tspi(tspContext, modulus); if (result != TSS_SUCCESS) { LogDebugFn("Stage 1 iteration %u failed", i); goto close; } } LogDebug("done join 1-%d\n", issuer_authentication_PKLengh); stage = 2; // define issuer_settings #if 0 issuer_settings = convert2issuer_settings(pk_internal); issuer_settings_bytes = issuer_2_byte_array(issuer_settings, &length); #else if ((result = obj_daaissuerkey_get_daa_issuer(hIssuerKey, &issuer_length, &issuer))) goto close; if ((result = obj_daaissuerkey_get_modulus(hIssuerKey, &modulus_length, &modulus))) { free_tspi(tspContext, issuer); goto close; } #endif if ((result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, issuer_length, issuer, issuerAuthPKSignaturesLength2, issuerAuthPKSignatures[i - 1], &ownerAuth, &outputSize, &outputData))) { free_tspi(tspContext, issuer); free_tspi(tspContext, modulus); goto close; } free_tspi(tspContext, issuer); LogDebug("done join 2\n"); stage = 3; if ((result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, sizeof(UINT32), (BYTE *)(&daa_counter), 0, NULL, &ownerAuth, &outputSize, &outputData))) goto close; LogDebug("done join 3\n"); stage = 4; #if 0 // reserved another buffer for storing Big Integer bi_2_nbin1( &length, buffer, pk_internal->capitalR0); bi_2_nbin1( &length1, buffer1, pk_internal->modulus); #else if ((result = obj_daaissuerkey_get_capitalR0(hIssuerKey, &buf_len, &buf))) return result; #endif if ((result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, buf_len, buf, modulus_length, modulus, &ownerAuth, &outputSize, &outputData))) { free_tspi(tspContext, buf); free_tspi(tspContext, modulus); goto close; } free_tspi(tspContext, buf); LogDebug("done join 4\n"); stage = 5; #if 0 bi_2_nbin1( &length, buffer, pk_internal->capitalR1); #else if ((result = obj_daaissuerkey_get_capitalR1(hIssuerKey, &buf_len, &buf))) return result; #endif if ((result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, buf_len, buf, modulus_length, modulus, &ownerAuth, &outputSize, &outputData))) { free_tspi(tspContext, buf); free_tspi(tspContext, modulus); goto close; } free_tspi(tspContext, buf); LogDebug("done join 5\n"); stage = 6; #if 0 bi_2_nbin1( &length, buffer, pk_internal->capitalS); #else if ((result = obj_daaissuerkey_get_capitalS(hIssuerKey, &buf_len, &buf))) return result; #endif if ((result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, buf_len, buf, modulus_length, modulus, &ownerAuth, &outputSize, &outputData))) { free_tspi(tspContext, buf); free_tspi(tspContext, modulus); goto close; } free_tspi(tspContext, buf); LogDebug("done join 6\n"); stage = 7; #if 0 bi_2_nbin1( &length, buffer, pk_internal->capitalSprime); #else if ((result = obj_daaissuerkey_get_capitalSprime(hIssuerKey, &buf_len, &buf))) return result; #endif // define Uprime if ((result = Tcsip_TPM_DAA_Join_encapsulate(tspContext, daaHandle, stage, buf_len, buf, modulus_length, modulus, &ownerAuth, &outputSize, &outputData))) { free_tspi(tspContext, buf); free_tspi(tspContext, modulus); goto close; } free_tspi(tspContext, buf); #if 0 // 5 : save PKDAA, U, daaCount and sessionHandle in joinSession join_session->issuerPk = (TSS_HKEY)issuer_pk; if( result == TSS_SUCCESS) { *capital_UprimeLength = outputSize; *capital_Uprime = convert_alloc( tspContext, outputSize, outputData); if (*capital_Uprime == NULL) { LogError("malloc of %d bytes failed", outputSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } join_session->capitalUPrime = copy_alloc( tspContext, *capital_UprimeLength, *capital_Uprime); if (join_session->capitalUPrime == NULL) { LogError("malloc of %d bytes failed", *capital_UprimeLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } join_session->capitalUPrimeLength = *capital_UprimeLength; } join_session->sessionHandle = return_join_session; // get the endorsement Key (public part) result = get_public_EK( hTPM, // in &( identity_proof->endorsementLength), &( identity_proof->endorsementCredential) ); #else /* fill out the identity proof struct */ if ((result = TCS_API(obj->tspContext)->GetTPMCapability(obj->tspContext, TPM_CAP_VERSION, 0, NULL, &buf_len, &buf))) goto close; offset = 0; Trspi_UnloadBlob_VERSION(&offset, buf, &daaIdentityProof.versionInfo); free_tspi(tspContext, buf); #error set all 3 credentials in the daaIdentityProof struct here /* set the U data */ if ((result = __tspi_add_mem_entry(tspContext, outputData))) goto close; *capitalUPrime = outputData; *capitalUPrimeLength = outputSize; /* return the TSS specific stuff */ #endif close: FREE_BI( issuer_authentication_PK_i); LogDebug("result = %d", result); LogDebug("outputSize=%d", outputSize); LogDebug("outputData=%s", dump_byte_array( outputSize, outputData)); return result; } #endif /* allocation: endorsementKey as BYTE * */ TSS_RESULT get_public_EK(TSS_HTPM hTPM, UINT32 *endorsementKeyLength, BYTE **endorsementKey ) { TSS_RESULT result; TSS_HKEY hEk; TSS_HPOLICY hTpmPolicy; UINT32 uiAttrSize; BYTE *pAttr; if( (result = obj_tpm_get_policy( hTPM, &hTpmPolicy)) != TSS_SUCCESS) { LogError("can not retrieve policy from the TPM handler"); goto out_close; } if( (result = Tspi_TPM_GetPubEndorsementKey(hTPM, TRUE, NULL, &hEk)) != TSS_SUCCESS) { LogError("can not retrieve the Public endorsed Key"); goto out_close; } result = Tspi_GetAttribData( hEk, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_VERSION, &uiAttrSize, &pAttr); if (result != TSS_SUCCESS) goto out_close; LogDebug("keyinfo:%s", dump_byte_array( uiAttrSize, pAttr)); result = Tspi_GetAttribData( hEk, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, endorsementKeyLength, endorsementKey); LogDebug("Public Endorsement Key:%s", dump_byte_array( *endorsementKeyLength, *endorsementKey)); out_close: return result; } // from TSS.java (479) TSS_RESULT compute_join_challenge_host(TSS_HDAA hDAA, TSS_DAA_PK_internal *pk_internal, bi_ptr capitalU, bi_ptr capital_Uprime, bi_ptr capital_utilde, bi_ptr capital_utilde_prime, bi_ptr capital_ni, bi_ptr capital_ni_tilde, UINT32 commitments_proofLength, TSS_DAA_ATTRIB_COMMIT_internal * commitments_proof, UINT32 nonceIssuerLength, BYTE* nonceIssuer, UINT32 *resultLength, BYTE **result) { EVP_MD_CTX *mdctx; BYTE *encoded_pk = NULL, *buffer; UINT32 encoded_pkLength; int rv, length; buffer = (BYTE *)malloc( 10000); // to be sure, and it will be free quickly if (buffer == NULL) { LogError("malloc of %d bytes failed", 10000); return TSPERR(TSS_E_OUTOFMEMORY); } mdctx = EVP_MD_CTX_create(); rv = EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); if (rv != EVP_SUCCESS) goto err; // allocation encoded_pk = encoded_DAA_PK_internal( &encoded_pkLength, pk_internal); LogDebug("encoded issuerPk[%d]: %s", encoded_pkLength, dump_byte_array( encoded_pkLength, encoded_pk)); rv = EVP_DigestUpdate(mdctx, encoded_pk, encoded_pkLength); if (rv != EVP_SUCCESS) goto err; // capitalU length = DAA_PARAM_SIZE_RSA_MODULUS / 8; bi_2_byte_array( buffer, length, capitalU); LogDebug("capitalU[%ld]: %s", bi_nbin_size(capitalU) , dump_byte_array( length, buffer)); rv = EVP_DigestUpdate(mdctx, buffer, length); if (rv != EVP_SUCCESS) goto err; // capital UPrime bi_2_byte_array( buffer, length, capital_Uprime); LogDebug("capitalUPrime[%d]: %s", length, dump_byte_array( length, buffer)); rv = EVP_DigestUpdate(mdctx, buffer, length); if (rv != EVP_SUCCESS) goto err; // capital Utilde bi_2_byte_array( buffer, length, capital_utilde); LogDebug("capitalUTilde[%d]: %s", length, dump_byte_array( length, buffer)); rv = EVP_DigestUpdate(mdctx, buffer, length); if (rv != EVP_SUCCESS) goto err; // capital UtildePrime bi_2_byte_array( buffer, length, capital_utilde_prime); LogDebug("capital_utilde_prime[%d]: %s", length, dump_byte_array( length, buffer)); rv = EVP_DigestUpdate(mdctx, buffer, length); if (rv != EVP_SUCCESS) goto err; //capital_ni length = DAA_PARAM_SIZE_MODULUS_GAMMA / 8; bi_2_byte_array( buffer, length, capital_ni); LogDebug("capital_ni[%d]: %s", length, dump_byte_array( length, buffer)); rv = EVP_DigestUpdate(mdctx, buffer, length); if (rv != EVP_SUCCESS) goto err; //capital_ni_tilde bi_2_byte_array( buffer, length, capital_ni_tilde); LogDebug("capital_ni_tilde[%d]: %s", length, dump_byte_array( length, buffer)); rv = EVP_DigestUpdate(mdctx, buffer, length); if (rv != EVP_SUCCESS) goto err; // TODO: commitments LogDebug("nonceIssuer[%d]: %s", nonceIssuerLength, dump_byte_array( nonceIssuerLength, nonceIssuer)); rv = EVP_DigestUpdate(mdctx, nonceIssuer, nonceIssuerLength); if (rv != EVP_SUCCESS) goto err; *resultLength = EVP_MD_CTX_size(mdctx); *result = (BYTE *)malloc( *resultLength); if (*result == NULL) { LogError("malloc of %d bytes failed", *resultLength); free( buffer); free( encoded_pk); return TSPERR(TSS_E_OUTOFMEMORY); } rv = EVP_DigestFinal(mdctx, *result, NULL); if (rv != EVP_SUCCESS) goto err; EVP_MD_CTX_destroy(mdctx); free( buffer); free( encoded_pk); return TSS_SUCCESS; err: EVP_MD_CTX_destroy(mdctx); free( buffer); free( encoded_pk); DEBUG_print_openssl_errors(); return TSPERR(TSS_E_INTERNAL_ERROR); } /* This is the second out of 3 functions to execute in order to receive a DAA Credential. It computes the credential request for the DAA Issuer, which also includes the Platforms & DAA public key and the attributes that were chosen by the Platform, and which are not visible to \ the DAA Issuer. The Platform can commit to the attribute values it has chosen. Code influenced by TSS.java (TssDaaCredentialRequest) */ TSPICALL Tspi_TPM_DAA_JoinCreateDaaPubKey_internal( TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in UINT32 authenticationChallengeLength, // in BYTE* authenticationChallenge, // in UINT32 nonceIssuerLength, // in BYTE* nonceIssuer, // in UINT32 attributesPlatformLength, // in BYTE** attributesPlatform, // in TSS_DAA_JOIN_SESSION* joinSession, // in, out TSS_DAA_CREDENTIAL_REQUEST* credentialRequest // out ) { TSS_RESULT result; TCS_CONTEXT_HANDLE tcsContext; TPM_AUTH ownerAuth; bi_ptr tmp1 = bi_new_ptr(); bi_ptr tmp2 = bi_new_ptr(); bi_ptr capital_utilde = bi_new_ptr(); bi_ptr v_tilde_prime = bi_new_ptr(); bi_ptr rv_tilde_prime = bi_new_ptr(); bi_ptr capitalU = bi_new_ptr(); bi_ptr product_attributes = bi_new_ptr(); bi_ptr capital_ni = NULL; bi_ptr capital_utilde_prime = NULL; bi_ptr capital_ni_tilde = NULL; bi_ptr n = NULL; bi_ptr attributePlatform = NULL; bi_ptr c = NULL; bi_ptr zeta = NULL; bi_ptr capital_Uprime = NULL; bi_ptr sv_tilde_prime = NULL; bi_ptr s_f0 = NULL; bi_ptr s_f1 = NULL; bi_ptr sv_prime = NULL; bi_ptr sv_prime1 = NULL; bi_ptr sv_prime2 = NULL; bi_array_ptr ra = NULL; bi_array_ptr sa = NULL; TSS_DAA_PK* pk_extern = (TSS_DAA_PK *)joinSession->issuerPk; TSS_DAA_PK_internal* pk_internal = e_2_i_TSS_DAA_PK( pk_extern); UINT32 i, outputSize, authentication_proofLength, nonce_tpmLength; UINT32 capitalSprime_byte_arrayLength, size_bits, length, chLength, c_byteLength; UINT32 internal_cbyteLength, noncePlatformLength; BYTE *outputData, *authentication_proof, *capitalSprime_byte_array = NULL, *buffer; BYTE *ch = NULL; BYTE *c_byte, *noncePlatform, *nonce_tpm; BYTE *internal_cbyte = NULL; EVP_MD_CTX *mdctx; if( tmp1 == NULL || tmp2 == NULL || capital_utilde == NULL || v_tilde_prime == NULL || rv_tilde_prime == NULL || capitalU == NULL || product_attributes == NULL) { LogError("malloc of bi(s) failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } if( pk_internal == NULL) { LogError("malloc of pk_internal failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } if( (result = obj_tpm_is_connected( hTPM, &tcsContext)) != TSS_SUCCESS) { goto close; } obj_daa_set_handle_tpm( hDAA, hTPM); // allocation n = bi_set_as_nbin( pk_extern->modulusLength, pk_extern->modulus); if( n == NULL) { LogError("malloc of %d bytes failed", pk_extern->modulusLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // allocation capitalSprime_byte_array = bi_2_nbin( &capitalSprime_byte_arrayLength, pk_internal->capitalSprime); if( capitalSprime_byte_array == NULL) { LogError("malloc of %d bytes failed", capitalSprime_byte_arrayLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // compute second part of the credential request // encode plateform attributes (the one visible only by the receiver) bi_set( product_attributes, bi_1); for( i=0; i failed", "attributePlatform"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // bi_tmp1 = ( capitalRReceiver[i] ^ attributesPlatform ) % n bi_mod_exp( tmp1, pk_internal->capitalRReceiver->array[i], attributePlatform, n); // bi_tmp1 = bi_tmp1 * product_attributes bi_mul( tmp1, tmp1, product_attributes); // product_attributes = bi_tmp1 % n bi_mod( product_attributes, tmp1, n); bi_free_ptr( attributePlatform); } bi_urandom( v_tilde_prime, DAA_PARAM_SIZE_RSA_MODULUS + DAA_PARAM_SAFETY_MARGIN); // tmp1 = capitalUPrime * capitalS bi_free_ptr( tmp1); tmp1 = bi_set_as_nbin( joinSession->capitalUPrimeLength, joinSession->capitalUPrime); // allocation if( tmp1 == NULL) { LogError("malloc of %d bytes failed", joinSession->capitalUPrimeLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // U = ( U' * ( ( pk->S ^ v~' ) % n) ) % n // tmp2 = ( pk->S ^ v~') % n bi_mod_exp( tmp2, pk_internal->capitalS, v_tilde_prime, n); // U = tmp1( U') * tmp2 bi_mul( capitalU, tmp1, tmp2); bi_mod( capitalU, capitalU, n); // U = ( U * product_attributes ) % n bi_mul( capitalU, capitalU, product_attributes); bi_mod( capitalU, capitalU, n); // 2 : call the TPM to compute authentication proof with U' result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 8, authenticationChallengeLength, authenticationChallenge, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 8"); authentication_proof = calloc_tspi( tcsContext, outputSize); if( authentication_proof == NULL) { LogError("malloc of %d bytes failed", outputSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } memcpy( authentication_proof, outputData, outputSize); free( outputData); authentication_proofLength = outputSize; // 3 : call the TPM to compute U' (first part of correctness proof of the credential // request result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 9, pk_extern->capitalR0Length, pk_extern->capitalR0, pk_extern->modulusLength, pk_extern->modulus, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 9: capitalR0"); free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 10, pk_extern->capitalR1Length, pk_extern->capitalR1, pk_extern->modulusLength, pk_extern->modulus, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 10: capitalR1"); free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 11, pk_extern->capitalSLength, pk_extern->capitalS, pk_extern->modulusLength, pk_extern->modulus, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 11: capitalS"); free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 12, capitalSprime_byte_arrayLength, capitalSprime_byte_array, pk_extern->modulusLength, pk_extern->modulus, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 12: capitalUTildePrime"); capital_utilde_prime = bi_set_as_nbin( outputSize, outputData); // allocation if( capital_utilde_prime == NULL) { LogError("malloc of %d bytes failed", outputSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); // 4 compute pseudonym with respect to the DAA Issuer // allocation zeta = compute_zeta( pk_internal->issuerBaseNameLength, pk_internal->issuerBaseName, pk_internal); if( zeta == NULL) { LogError("malloc of bi <%s> failed", "zeta"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } buffer = (BYTE *)malloc( TPM_DAA_SIZE_w); if( buffer == NULL) { LogError("malloc of %d bytes failed", TPM_DAA_SIZE_w); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug("zeta[%ld] = %s", bi_nbin_size( zeta), bi_2_hex_char( zeta)); bi_2_byte_array( buffer, TPM_DAA_SIZE_w, zeta); LogDebug("zeta[%d] = %s", TPM_DAA_SIZE_w, dump_byte_array( TPM_DAA_SIZE_w, buffer)); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 13, pk_extern->capitalGammaLength, pk_extern->capitalGamma, TPM_DAA_SIZE_w, buffer, // zeta &ownerAuth, &outputSize, &outputData); free( buffer); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 13: capitalGamma / zeta"); free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 14, pk_extern->capitalGammaLength, pk_extern->capitalGamma, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 14: capitalGamma"); capital_ni = bi_set_as_nbin( outputSize, outputData); // allocation if( capital_ni == NULL) { LogError("malloc of bi <%s> failed", "capital_ni"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 15, pk_extern->capitalGammaLength, pk_extern->capitalGamma, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 15: capitalGamma"); capital_ni_tilde = bi_set_as_nbin( outputSize, outputData); // allocation if( capital_ni_tilde == NULL) { LogError("malloc of bi <%s> failed", "capital_ni_tilde"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); // 5 : compute the second part of the correctness proof of the credential request // (with attributes not visible to issuer) // randomize/blind attributesReceiver size_bits = DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES; bi_set( product_attributes, bi_1); ra = (bi_array_ptr)malloc( sizeof( struct _bi_array)); if( ra == NULL) { LogError("malloc of %d bytes failed", sizeof( struct _bi_array)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_new_array( ra, attributesPlatformLength); if( ra->array == NULL) { LogError("malloc of bi_array <%s> failed", "ra"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; i < attributesPlatformLength; i++) { bi_urandom( ra->array[i], size_bits); LogDebug("ra[i]=%s size=%d", bi_2_hex_char( ra->array[i]), size_bits); // product_attributes=(((capitalYplatform ^ ra[i]) % n)*)%n bi_mod_exp( tmp1, pk_internal->capitalRReceiver->array[i], ra->array[i], n); bi_mul( tmp1, tmp1, product_attributes); bi_mod( product_attributes, tmp1, n); } size_bits = DAA_PARAM_SIZE_F_I+2*DAA_PARAM_SAFETY_MARGIN+DAA_PARAM_SIZE_MESSAGE_DIGEST; bi_urandom( rv_tilde_prime, size_bits); // capital_utilde = ( capitalS ^ rv_tilde_prime) % n bi_mod_exp( capital_utilde, pk_internal->capitalS, rv_tilde_prime, n); // capital_utilde = capital_utilde * product_attributes bi_mul( capital_utilde, capital_utilde, product_attributes); // capital_utilde = capital_utilde % n bi_mod( capital_utilde, capital_utilde, n); // 5e capital_Uprime = bi_set_as_nbin( joinSession->capitalUPrimeLength, joinSession->capitalUPrime); // allocation if( capital_Uprime == NULL) { LogError("malloc of bi <%s> failed", "capital_Uprime"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug("calculation UTilde: capitalS:%s\n", bi_2_hex_char( pk_internal->capitalS)); LogDebug("calculation UTilde: rv_tilde_prime:%s\n", bi_2_hex_char( rv_tilde_prime)); LogDebug("calculation UTilde: n:%s\n", bi_2_hex_char( n)); LogDebug("calculation UTilde: product_attributes:%s\n", bi_2_hex_char( product_attributes)); LogDebug("calculation NItilde: ntilde:%s\n", bi_2_hex_char( capital_ni_tilde)); result = compute_join_challenge_host( hDAA, pk_internal, capitalU, capital_Uprime, capital_utilde, capital_utilde_prime, capital_ni, capital_ni_tilde, 0, // TODO commitmentProofLength NULL, // TODO commitment nonceIssuerLength, nonceIssuer, &chLength, // out &ch // out allocation ); if( result != TSS_SUCCESS) goto close; result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 16, chLength, ch, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; nonce_tpm = outputData; nonce_tpmLength = outputSize; LogDebug("Done Join 16: compute_join_challenge_host return nonce_tpm:%s", dump_byte_array(nonce_tpmLength, nonce_tpm)); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 17, 0, NULL, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; s_f0 = bi_set_as_nbin( outputSize, outputData); // allocation if( s_f0 == NULL) { LogError("malloc of %s failed", "s_f0"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug("Done Join 17: return sF0:%s", dump_byte_array(outputSize, outputData) ); free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 18, 0, NULL, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; s_f1 = bi_set_as_nbin( outputSize, outputData); // allocation if( s_f1 == NULL) { LogError("malloc of %s failed", "s_f1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug("Done Join 18: return sF1:%s", dump_byte_array(outputSize, outputData) ); free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 19, 0, NULL, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 19: return sv_prime1"); sv_prime1 = bi_set_as_nbin( outputSize, outputData); // allocation if( sv_prime1 == NULL) { LogError("malloc of %s failed", "sv_prime1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 20, 0, NULL, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 20: return cByte"); c_byte = (BYTE *)calloc_tspi( tcsContext, outputSize); if( c_byte == NULL) { LogError("malloc of %d bytes failed", outputSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } memcpy( c_byte, outputData, outputSize); free( outputData); c_byteLength = outputSize; c = bi_set_as_nbin( c_byteLength, c_byte); // allocation if( c == NULL) { LogError("malloc of %s failed", "c"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // verify computation of c by TPM mdctx = EVP_MD_CTX_create(); EVP_DigestInit(mdctx, DAA_PARAM_get_message_digest()); EVP_DigestUpdate(mdctx, ch, chLength); EVP_DigestUpdate(mdctx, nonce_tpm, nonce_tpmLength); nonce_tpm = convert_alloc( tcsContext, nonce_tpmLength, nonce_tpm); // allocation if( nonce_tpm == NULL) { LogError("malloc of %d bytes failed", nonce_tpmLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } internal_cbyteLength = EVP_MD_CTX_size(mdctx); internal_cbyte = (BYTE *)malloc( internal_cbyteLength); if( internal_cbyte == NULL) { LogError("malloc of %d bytes failed", internal_cbyteLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } EVP_DigestFinal(mdctx, internal_cbyte, NULL); if( c_byteLength != internal_cbyteLength || memcmp( c_byte, internal_cbyte, c_byteLength) != 0) { LogError( "Computation of c in TPM DAA Join command is incorrect. Affected stages: 16,20\n"); LogError( "\t c_byte[%d] %s", c_byteLength, dump_byte_array( c_byteLength, c_byte)); LogError( "\tc_internal_byte[%d] %s", internal_cbyteLength, dump_byte_array( internal_cbyteLength, internal_cbyte)); result = TSS_E_INTERNAL_ERROR; goto close; } // 5m) blind attributesReceiver sa = (bi_array_ptr)malloc( sizeof( struct _bi_array)); if( sa == NULL) { LogError("malloc of %d bytes failed", sizeof( struct _bi_array)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_new_array( sa, attributesPlatformLength); for( i=0; i < attributesPlatformLength; i++) { attributePlatform = bi_set_as_nbin( DAA_PARAM_SIZE_F_I / 8, attributesPlatform[i]); // allocation if( attributePlatform == NULL) { LogError("malloc of %s failed", "attributePlatform"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug("calculating sa[%d]: raLength=%ld cLength=%ld attributesPlatformLength=%ld\n", i, bi_nbin_size( ra->array[i]), bi_nbin_size( c), bi_nbin_size( attributePlatform)); bi_add( sa->array[i], ra->array[i], bi_mul( tmp1, c, attributePlatform)); bi_free_ptr( attributePlatform); } attributePlatform = NULL; // 5o) Commitments // TODO result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 21, 0, NULL, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 21: return sv_prime2"); sv_prime2 = bi_set_as_nbin( outputSize, outputData); // allocation if( sv_prime2 == NULL) { LogError("malloc of %s failed", "sv_prime2"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); sv_prime = bi_new_ptr(); if( sv_prime == NULL) { LogError("malloc of %s failed", "sv_prime"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // sv_prime = sv_prime2 << DAA_PARAM_SIZE_SPLIT_EXPONENT bi_shift_left( sv_prime, sv_prime2, DAA_PARAM_SIZE_SPLIT_EXPONENT); // sv_prime = sv_prime + sv_prime1 bi_add( sv_prime, sv_prime, sv_prime1); sv_tilde_prime = bi_new_ptr(); // tmp1 = c * v_tilde_prime bi_mul( tmp1, c, v_tilde_prime); // sv_tilde_prime = rv_tilde_prime + tmp1 bi_add( sv_tilde_prime, rv_tilde_prime, tmp1); // step 6) - choose nonce bi_urandom( tmp1, DAA_PARAM_SAFETY_MARGIN * 8); noncePlatform = (BYTE *)calloc_tspi( tcsContext, DAA_PARAM_SAFETY_MARGIN); if( noncePlatform == NULL) { LogError("malloc of %s failed", "noncePlatform"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &noncePlatformLength, noncePlatform, tmp1); LogDebug("challenge:%s", dump_byte_array( c_byteLength, c_byte)); LogDebug("sF0 [%ld]:%s", bi_length( s_f0), bi_2_hex_char( s_f0)); LogDebug("sF1 [%ld]:%s", bi_length( s_f1), bi_2_hex_char( s_f1)); LogDebug("sv_prime [%ld]:%s", bi_length( sv_prime), bi_2_hex_char( sv_prime)); LogDebug("sv_tilde_prime [%ld]:%s", bi_length( sv_tilde_prime), bi_2_hex_char( sv_tilde_prime)); // update joinSession joinSession->capitalU = calloc_tspi( tcsContext, bi_nbin_size( capitalU)); if( joinSession->capitalU == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( capitalU)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(joinSession->capitalULength), joinSession->capitalU, capitalU); joinSession->attributesPlatformLength = attributesPlatformLength; joinSession->attributesPlatform = calloc_tspi( tcsContext, sizeof(BYTE *)); for( i=0; iattributesPlatformLength; i++) { joinSession->attributesPlatform[i] = calloc_tspi( tcsContext,DAA_PARAM_SIZE_F_I / 8); memcpy( joinSession->attributesPlatform[i], attributesPlatform[i], DAA_PARAM_SIZE_F_I / 8); } joinSession->noncePlatform = noncePlatform; joinSession->noncePlatformLength = noncePlatformLength; joinSession->vTildePrime = calloc_tspi( tcsContext, bi_nbin_size( v_tilde_prime)); if( joinSession->vTildePrime == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( v_tilde_prime)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(joinSession->vTildePrimeLength), joinSession->vTildePrime, v_tilde_prime); // update credentialRequest credentialRequest->capitalU = calloc_tspi( tcsContext, bi_nbin_size( capitalU)); if( credentialRequest->capitalU == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( capitalU)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credentialRequest->capitalULength), credentialRequest->capitalU, capitalU); credentialRequest->capitalNi = calloc_tspi( tcsContext, bi_nbin_size( capital_ni)); if( credentialRequest->capitalNi == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( capital_ni)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credentialRequest->capitalNiLength), credentialRequest->capitalNi, capital_ni); credentialRequest->authenticationProofLength = authentication_proofLength; credentialRequest->authenticationProof = authentication_proof; credentialRequest->challenge = c_byte; credentialRequest->challengeLength = c_byteLength; credentialRequest->nonceTpm = nonce_tpm; credentialRequest->nonceTpmLength = nonce_tpmLength; credentialRequest->noncePlatform = noncePlatform; credentialRequest->noncePlatformLength = DAA_PARAM_SAFETY_MARGIN; credentialRequest->sF0 = calloc_tspi( tcsContext, bi_nbin_size( s_f0)); if( credentialRequest->sF0 == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( s_f0)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credentialRequest->sF0Length), credentialRequest->sF0, s_f0); credentialRequest->sF1 = calloc_tspi( tcsContext, bi_nbin_size( s_f1)); if( credentialRequest->sF1 == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( s_f1)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credentialRequest->sF1Length), credentialRequest->sF1, s_f1); credentialRequest->sVprime = calloc_tspi( tcsContext, bi_nbin_size( sv_prime)); if( credentialRequest->sVprime == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( sv_prime)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credentialRequest->sVprimeLength), credentialRequest->sVprime, sv_prime); credentialRequest->sVtildePrime = calloc_tspi( tcsContext, bi_nbin_size( sv_tilde_prime)); if( credentialRequest->sVtildePrime == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( sv_tilde_prime)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(credentialRequest->sVtildePrimeLength), credentialRequest->sVtildePrime, sv_tilde_prime); length = (DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES + 7) / 8; LogDebug("SA length=%d", sa->length); credentialRequest->sA = calloc_tspi( tcsContext, sizeof( BYTE *) * sa->length); if( credentialRequest->sA == NULL) { LogError("malloc of %d bytes failed", sizeof( BYTE *) * sa->length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; i<(UINT32)sa->length; i++) { LogDebug("sa[%d].size=%d", i, (int)bi_nbin_size( sa->array[i])); credentialRequest->sA[i] = calloc_tspi( tcsContext, length); if( credentialRequest->sA[i] == NULL) { LogError("malloc of %d bytes failed", length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // size used only as repository bi_2_byte_array( credentialRequest->sA[i], length, sa->array[i]); } credentialRequest->sALength = sa->length; close: EVP_MD_CTX_destroy(mdctx); if( capitalSprime_byte_array!=NULL) free( capitalSprime_byte_array); if( ch!=NULL) free( ch); if( internal_cbyte != NULL) free( internal_cbyte); bi_free_ptr( rv_tilde_prime); bi_free_ptr( v_tilde_prime); bi_free_ptr( capital_utilde); bi_free_ptr( tmp1); bi_free_ptr( tmp2); bi_free_ptr( capitalU); if( ra != NULL) { bi_free_array( ra); free( ra); } if( sa != NULL) { bi_free_array( sa); free( sa); } FREE_BI( capital_ni); FREE_BI( capital_utilde_prime); FREE_BI( capital_ni_tilde); FREE_BI( n); FREE_BI( attributePlatform); FREE_BI( c); FREE_BI( zeta); FREE_BI( capital_Uprime); FREE_BI( sv_tilde_prime); FREE_BI( s_f0); FREE_BI( s_f1); FREE_BI( sv_prime); FREE_BI( sv_prime1); FREE_BI( sv_prime2); FREE_BI( product_attributes); free_TSS_DAA_PK_internal( pk_internal); return result; } /* Code influenced by TSS.java (joinStoreCredential) */ TSPICALL Tspi_TPM_DAA_JoinStoreCredential_internal ( TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in TSS_DAA_CRED_ISSUER credIssuer, // in TSS_DAA_JOIN_SESSION joinSession, // in TSS_HKEY* hDaaCredential // out ) { TCS_CONTEXT_HANDLE tcsContext; TPM_AUTH ownerAuth; bi_ptr tmp1 = bi_new_ptr(); bi_ptr tmp2 = bi_new_ptr(); bi_ptr n = NULL; bi_ptr e = NULL; bi_ptr fraction_A = NULL; bi_ptr v_prime_prime = NULL; bi_ptr capital_U = NULL; bi_ptr product_attributes = NULL; bi_ptr capital_Atilde = NULL; bi_ptr s_e = NULL; bi_ptr c_prime = NULL; bi_ptr capital_A = NULL; bi_ptr product = NULL; bi_ptr v_tilde_prime = NULL; bi_ptr v_prime_prime0 = NULL; bi_ptr v_prime_prime1 = NULL; TSS_DAA_PK *daa_pk_extern; TSS_DAA_PK_internal *pk_intern = NULL; TSS_DAA_CREDENTIAL *daaCredential; bi_array_ptr attributes_issuer; TSS_RESULT result = TSS_SUCCESS; UINT32 i; UINT32 c_byteLength, v0Length, v1Length, tpm_specificLength; BYTE *c_byte = NULL; BYTE *v0 = NULL; BYTE *v1 = NULL; BYTE *tpm_specific = NULL; if( tmp1 == NULL || tmp2 == NULL) { LogError("malloc of bi(s) failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } if( (result = obj_tpm_is_connected( hTPM, &tcsContext)) != TSS_SUCCESS) return result; obj_daa_set_handle_tpm( hDAA, hTPM); LogDebug("Converting issuer public"); daa_pk_extern = (TSS_DAA_PK *)joinSession.issuerPk; pk_intern = e_2_i_TSS_DAA_PK( daa_pk_extern); if( pk_intern == NULL) { LogError("malloc of pk_intern failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } n = bi_new_ptr(); if( n == NULL) { LogError("malloc of bi <%s> failed", "n"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( n, pk_intern->modulus); attributes_issuer = (bi_array_ptr)malloc( sizeof( struct _bi_array)); if( attributes_issuer == NULL) { LogError("malloc of %d bytes failed", sizeof( struct _bi_array)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_new_array( attributes_issuer, credIssuer.attributesIssuerLength); if( attributes_issuer->array == NULL) { LogError("malloc of bi_array <%s> failed", "attributes_issuer->array"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; i < credIssuer.attributesIssuerLength; i++) { // allocation attributes_issuer->array[i] = bi_set_as_nbin( DAA_PARAM_SIZE_F_I / 8, credIssuer.attributesIssuer[i]); if( attributes_issuer->array[i] == NULL) { LogError("malloc of bi array[%d]> failed", i); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } } LogDebug("verify credential of issuer ( part 1)"); e = bi_set_as_nbin( credIssuer.eLength, credIssuer.e); // allocation if( e == NULL) { LogError("malloc of bi <%s> failed", "e"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( tmp1, bi_0); bi_setbit( tmp1, DAA_PARAM_SIZE_EXPONENT_CERTIFICATE - 1); bi_set( tmp2, bi_0); bi_setbit( tmp1, DAA_PARAM_SIZE_INTERVAL_EXPONENT_CERTIFICATE - 1); bi_add( tmp1, tmp1, tmp2); if( bi_is_probable_prime( e) == 0 || bi_length(e) < DAA_PARAM_SIZE_EXPONENT_CERTIFICATE || bi_cmp( e, tmp1) > 0) { LogError("Verification e failed - Step 1.a"); LogError("\tPrime(e):%d", bi_is_probable_prime( e)); LogError("\tbit_length(e):%ld", bi_length(e)); LogError("\te > (2^(l_e) + 2^(l_prime_e)):%d", bi_cmp( e, tmp1)); result = TSS_E_DAA_CREDENTIAL_PROOF_ERROR; goto close; } LogDebug("verify credential of issuer (part 2) with proof"); fraction_A = bi_new_ptr(); if( fraction_A == NULL) { LogError("malloc of bi <%s> failed", "fraction_A"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } v_prime_prime = bi_set_as_nbin( credIssuer.vPrimePrimeLength, credIssuer.vPrimePrime); // allocation if( v_prime_prime == NULL) { LogError("malloc of bi <%s> failed", "v_prime_prime"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capital_U = bi_set_as_nbin( joinSession.capitalULength, joinSession.capitalU); // allocation if( capital_U == NULL) { LogError("malloc of bi <%s> failed", "capital_U"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( fraction_A, pk_intern->capitalS, v_prime_prime, n); bi_mul( fraction_A, fraction_A, capital_U); bi_mod( fraction_A, fraction_A, n); LogDebug("encode attributes"); product_attributes = bi_new_ptr(); bi_set( product_attributes, bi_1); for( i=0; i<(UINT32)attributes_issuer->length; i++) { bi_mod_exp( tmp1, pk_intern->capitalRIssuer->array[i], attributes_issuer->array[i], n); bi_mul( product_attributes, tmp1, product_attributes); bi_mod( product_attributes, product_attributes, n); } bi_mul( fraction_A, fraction_A, product_attributes); bi_mod( fraction_A, fraction_A, n); capital_Atilde = bi_new_ptr(); if( capital_Atilde == NULL) { LogError("malloc of bi <%s> failed", "capital_Atilde"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_invert_mod( capital_Atilde, fraction_A, n); bi_mul( capital_Atilde, capital_Atilde, pk_intern->capitalZ); bi_mod( capital_Atilde, capital_Atilde, n); s_e = bi_set_as_nbin( credIssuer.sELength, credIssuer.sE); // allocation if( s_e == NULL) { LogError("malloc of bi <%s> failed", "s_e"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( capital_Atilde, capital_Atilde, s_e, n); c_prime = bi_set_as_nbin( credIssuer.cPrimeLength, credIssuer.cPrime); // allocation if( c_prime == NULL) { LogError("malloc of bi <%s> failed", "c_prime"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capital_A = bi_set_as_nbin( credIssuer.capitalALength, credIssuer.capitalA); // allocation if( capital_A == NULL) { LogError("malloc of bi <%s> failed", "capital_A"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( tmp1, capital_A, c_prime, n); bi_mul( capital_Atilde, capital_Atilde, tmp1); bi_mod( capital_Atilde, capital_Atilde, n); result = compute_join_challenge_issuer( pk_intern, v_prime_prime, capital_A, capital_Atilde, joinSession.noncePlatformLength, joinSession.noncePlatform, &c_byteLength, &c_byte); // out allocation if( result != TSS_SUCCESS) goto close; if( credIssuer.cPrimeLength != c_byteLength || memcmp( credIssuer.cPrime, c_byte, c_byteLength)!=0) { LogError("Verification of c failed - Step 1.c.i"); LogError("credentialRequest.cPrime[%d]=%s", credIssuer.cPrimeLength, dump_byte_array( credIssuer.cPrimeLength, credIssuer.cPrime) ); LogError("challenge[%d]=%s", c_byteLength, dump_byte_array( c_byteLength, c_byte) ); result = TSS_E_DAA_CREDENTIAL_PROOF_ERROR; goto close; } product = bi_new_ptr(); if( product == NULL) { LogError("malloc of bi <%s> failed", "product"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( product, capital_A, e, n); bi_mul( product, product, fraction_A); bi_mod( product, product, n); if( bi_equals( pk_intern->capitalZ, product) == 0) { LogError("Verification of A failed - Step 1.c.ii"); LogError("\tcapitalZ=%s", bi_2_hex_char( pk_intern->capitalZ)); LogError("\tproduct=%s", bi_2_hex_char( product)); result = TSS_E_DAA_CREDENTIAL_PROOF_ERROR; goto close; } v_tilde_prime = bi_set_as_nbin( joinSession.vTildePrimeLength, joinSession.vTildePrime); // allocation bi_add( v_prime_prime, v_prime_prime, v_tilde_prime); bi_shift_left( tmp1, bi_1, DAA_PARAM_SIZE_SPLIT_EXPONENT); v_prime_prime0 = bi_new_ptr(); if( v_prime_prime0 == NULL) { LogError("malloc of bi <%s> failed", "v_prime_prime0"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod( v_prime_prime0, v_prime_prime, tmp1); v_prime_prime1 = bi_new_ptr(); if( v_prime_prime1 == NULL) { LogError("malloc of bi <%s> failed", "v_prime_prime1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_shift_right( v_prime_prime1, v_prime_prime, DAA_PARAM_SIZE_SPLIT_EXPONENT); free( c_byte); c_byte = (BYTE *)malloc( TPM_DAA_SIZE_v0); if( c_byte == NULL) { LogError("malloc of %d bytes failed", TPM_DAA_SIZE_v0); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_byte_array( c_byte, TPM_DAA_SIZE_v0, v_prime_prime0); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 22, TPM_DAA_SIZE_v0, c_byte, 0, NULL, &ownerAuth, &v0Length, &v0); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 22: return v0"); free( c_byte); c_byte = (BYTE *)malloc( TPM_DAA_SIZE_v1); if( c_byte == NULL) { LogError("malloc of %d bytes failed", TPM_DAA_SIZE_v1); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_byte_array( c_byte, TPM_DAA_SIZE_v1, v_prime_prime1); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 23, TPM_DAA_SIZE_v1, c_byte, 0, NULL, &ownerAuth, &v1Length, &v1); if( result != TSS_SUCCESS) goto close; LogDebug("Done Join 23: return v1"); result = Tcsip_TPM_DAA_Join_encapsulate( tcsContext, hDAA, 24, 0, NULL, 0, NULL, &ownerAuth, &tpm_specificLength, &tpm_specific); if( result != TSS_SUCCESS) goto close; daaCredential = (TSS_DAA_CREDENTIAL *)hDaaCredential; daaCredential->capitalA = calloc_tspi( tcsContext, bi_nbin_size( capital_A)); if( daaCredential->capitalA == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( capital_A)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaCredential->capitalALength), daaCredential->capitalA, capital_A); daaCredential->exponent = calloc_tspi( tcsContext, bi_nbin_size( e)); if( daaCredential->exponent == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( e)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaCredential->exponentLength), daaCredential->exponent, e); daaCredential->vBar0 = calloc_tspi( tcsContext, v0Length); if( daaCredential->vBar0 == NULL) { LogError("malloc of %d bytes failed", v0Length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } daaCredential->vBar0Length = v0Length; memcpy( daaCredential->vBar0, v0, v0Length); LogDebug("vBar0[%d]=%s", daaCredential->vBar0Length, dump_byte_array( daaCredential->vBar0Length, daaCredential->vBar0)); daaCredential->vBar1 = calloc_tspi( tcsContext, v1Length); if( daaCredential->vBar1 == NULL) { LogError("malloc of %d bytes failed", v1Length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } daaCredential->vBar1Length = v1Length; memcpy( daaCredential->vBar1, v1, v1Length); LogDebug("vBar1[%d]=%s", daaCredential->vBar1Length, dump_byte_array( daaCredential->vBar1Length, daaCredential->vBar1)); //TODO remove LogDebug("[BUSS] joinSession.attributesPlatformLength=%d", joinSession.attributesPlatformLength); LogDebug("[BUSS] credIssuer.attributesIssuerLength=%d", credIssuer.attributesIssuerLength); daaCredential->attributesLength = joinSession.attributesPlatformLength + credIssuer.attributesIssuerLength; daaCredential->attributes = (BYTE **)calloc_tspi( tcsContext, sizeof(BYTE *) * daaCredential->attributesLength); if( daaCredential->attributes == NULL) { LogError("malloc of %d bytes failed", sizeof(BYTE *) * daaCredential->attributesLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; i < joinSession.attributesPlatformLength; i++) { daaCredential->attributes[i] = calloc_tspi( tcsContext, DAA_PARAM_SIZE_F_I / 8); if( daaCredential->attributes[i] == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_SIZE_F_I / 8); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug("allocation attributes[%d]=%lx", i, (long)daaCredential->attributes[i]); memcpy( daaCredential->attributes[i], joinSession.attributesPlatform[i], DAA_PARAM_SIZE_F_I / 8); } for( i=0; i < credIssuer.attributesIssuerLength; i++) { daaCredential->attributes[i+joinSession.attributesPlatformLength] = calloc_tspi( tcsContext, DAA_PARAM_SIZE_F_I / 8); if( daaCredential->attributes[i+joinSession.attributesPlatformLength] == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_SIZE_F_I / 8); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } memcpy( daaCredential->attributes[i+joinSession.attributesPlatformLength], credIssuer.attributesIssuer[i], DAA_PARAM_SIZE_F_I / 8); } memcpy( &(daaCredential->issuerPK), daa_pk_extern, sizeof( TSS_DAA_PK)); daaCredential->tpmSpecificEnc = calloc_tspi( tcsContext, tpm_specificLength); if( daaCredential->tpmSpecificEnc == NULL) { LogError("malloc of %d bytes failed", tpm_specificLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } daaCredential->tpmSpecificEncLength = tpm_specificLength; memcpy( daaCredential->tpmSpecificEnc, tpm_specific, tpm_specificLength); // TODO store in TSS this TSS_DAA_CREDENTIAL_REQUEST *hDaaCredential = (TSS_HKEY)daaCredential; close: if( v0 != NULL) free( v0); if( v1 != NULL) free( v1); if( tpm_specific != NULL) free( tpm_specific); if( c_byte != NULL) free( c_byte); bi_free_ptr( tmp2); bi_free_ptr( tmp1); if( attributes_issuer != NULL) { bi_free_array( attributes_issuer); free( attributes_issuer); } FREE_BI( v_prime_prime1); FREE_BI( v_prime_prime0); FREE_BI( v_tilde_prime); FREE_BI( product); FREE_BI( capital_A); FREE_BI( c_prime); FREE_BI( s_e); FREE_BI( capital_Atilde); FREE_BI( product_attributes); FREE_BI( capital_U); FREE_BI( v_prime_prime); FREE_BI( fraction_A); FREE_BI( e); FREE_BI( n); if( pk_intern!=NULL) free_TSS_DAA_PK_internal( pk_intern); return result; } static void add_splitet( bi_ptr result, bi_ptr a, bi_ptr b) { bi_shift_left( result, bi_1, DAA_PARAM_SIZE_SPLIT_EXPONENT); bi_mul( result, result, b); bi_add( result, result, a); } /* code influenced by TSS.java (signStep) */ TSS_RESULT Tspi_TPM_DAA_Sign_internal ( TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in TSS_HKEY hDaaCredential, // in TSS_DAA_SELECTED_ATTRIB revealAttributes, // in UINT32 verifierBaseNameLength, // in BYTE* verifierBaseName, // in UINT32 verifierNonceLength, // in BYTE* verifierNonce, // in TSS_DAA_SIGN_DATA signData, // in TSS_DAA_SIGNATURE* daaSignature // out ) { TCS_CONTEXT_HANDLE tcsContext; TSS_DAA_CREDENTIAL *daaCredential; TPM_DAA_ISSUER *tpm_daa_issuer; TPM_AUTH ownerAuth; TSS_RESULT result = TSS_SUCCESS; TSS_DAA_PK *pk; TSS_DAA_PK_internal *pk_intern; int i; bi_ptr tmp1 = bi_new_ptr(), tmp2; bi_ptr n = NULL; bi_ptr capital_gamma = NULL; bi_ptr gamma = NULL; bi_ptr zeta = NULL; bi_ptr r = NULL; bi_ptr t_tilde_T = NULL; bi_ptr capital_Nv = NULL; bi_ptr capital_N_tilde_v = NULL; bi_ptr w = NULL; bi_ptr capital_T = NULL; bi_ptr r_E = NULL; bi_ptr r_V = NULL; bi_ptr capital_T_tilde = NULL; bi_ptr capital_A = NULL; bi_array_ptr capital_R; bi_ptr product_R = NULL; bi_array_ptr r_A = NULL; bi_array_ptr s_A = NULL; bi_ptr c = NULL; bi_ptr sF0 = NULL; bi_ptr sF1 = NULL; bi_ptr sV1 = NULL; bi_ptr sV2 = NULL; bi_ptr e = NULL; bi_ptr s_E = NULL; bi_ptr s_V = NULL; CS_ENCRYPTION_RESULT_RANDOMNESS *encryption_result_rand = NULL; BYTE *issuer_settings = NULL, *outputData, byte; BYTE *buffer = NULL, *ch = NULL, *nonce_tpm = NULL, *c_bytes = NULL; UINT32 issuer_settingsLength, outputSize, length, size_bits, chLength; UINT32 nonce_tpmLength; UINT32 c_bytesLength, return_sign_session; // for anonymity revocation CS_ENCRYPTION_RESULT *encryption_result = NULL; CS_ENCRYPTION_RESULT *encryption_result_tilde = NULL; TSS_DAA_PSEUDONYM *signature_pseudonym; TSS_DAA_PSEUDONYM_PLAIN *pseudonym_plain = NULL; TSS_DAA_PSEUDONYM_PLAIN *pseudonym_plain_tilde = NULL; TSS_DAA_ATTRIB_COMMIT *signed_commitments; if( (result = obj_tpm_is_connected( hTPM, &tcsContext)) != TSS_SUCCESS) return result; if( tmp1 == NULL) { LogError("malloc of bi <%s> failed", "tmp1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } obj_daa_set_handle_tpm( hDAA, hTPM); // TODO retrieve the daaCredential from the persistence storage daaCredential = (TSS_DAA_CREDENTIAL *)hDaaCredential; pk = (TSS_DAA_PK *)&(daaCredential->issuerPK); pk_intern = e_2_i_TSS_DAA_PK( pk); if( pk_intern == NULL) { LogError("malloc of <%s> failed", "pk_intern"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } tpm_daa_issuer = convert2issuer_settings( pk_intern); if( daaCredential->attributesLength == 0 || daaCredential->attributesLength != revealAttributes.indicesListLength) { LogDebug("Problem with the reveal attribs: attributes length:%d reveal length:%d", daaCredential->attributesLength, revealAttributes.indicesListLength); result = TSS_E_BAD_PARAMETER; goto close; } if( verifierNonce == NULL || verifierNonceLength != DAA_PARAM_LENGTH_MESSAGE_DIGEST) { LogDebug("Problem with the nonce verifier: nonce verifier length:%d", verifierNonceLength); result = TSS_E_BAD_PARAMETER; goto close; } n = bi_new_ptr(); if( n == NULL) { LogError("malloc of bi <%s> failed", "n"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( n, pk_intern->modulus); capital_gamma = bi_new_ptr(); if( capital_gamma == NULL) { LogError("malloc of bi <%s> failed", "capital_gamma"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( capital_gamma, pk_intern->capitalGamma); gamma = bi_new_ptr(); if( gamma == NULL) { LogError("malloc of bi <%s> failed", "gamma"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( gamma, pk_intern->gamma); if( verifierBaseNameLength == 0 || verifierBaseName == NULL) { r = bi_new_ptr(); compute_random_number( r, capital_gamma); zeta = project_into_group_gamma( r, pk_intern); // allocation if( zeta == NULL) { LogError("malloc of bi <%s> failed", "zeta"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } } else { zeta = compute_zeta( verifierBaseNameLength, verifierBaseName, pk_intern); if( zeta == NULL) { LogError("malloc of bi <%s> failed", "zeta"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } } issuer_settings = issuer_2_byte_array( tpm_daa_issuer, &issuer_settingsLength); // allocation if( issuer_settings == NULL) { LogError("malloc of %d bytes failed", issuer_settingsLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } LogDebug( "Issuer Settings:[%s]", dump_byte_array(issuer_settingsLength, issuer_settings) ); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 0, issuer_settingsLength, issuer_settings, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; // set the sessionHandle to the returned value return_sign_session = ntohl( *((UINT32 *)outputData)); obj_daa_set_session_handle( hDAA, return_sign_session); free( outputData); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 1, daaCredential->tpmSpecificEncLength, daaCredential->tpmSpecificEnc, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; free( outputData); LogDebug( "done Sign 1 - TPM specific"); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 2, pk->capitalR0Length, pk->capitalR0, pk->modulusLength, pk->modulus, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; free( outputData); LogDebug( "done Sign 2 - capitalR0"); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 3, pk->capitalR1Length, pk->capitalR1, pk->modulusLength, pk->modulus, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; free( outputData); LogDebug( "done Sign 3 - capitalR1"); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 4, pk->capitalSLength, pk->capitalS, pk->modulusLength, pk->modulus, &ownerAuth, &outputSize, &outputData); if( outputSize > 0 && outputData != NULL) free( outputData); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 4 - capitalS"); buffer = bi_2_nbin( &length, pk_intern->capitalSprime); // allocation if( buffer == NULL) { LogError("malloc of %d bytes failed", length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 5, length, buffer, pk->modulusLength, pk->modulus, &ownerAuth, &outputSize, &outputData); free( buffer); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 5 - capitalSPrime. Return t_tilde_T"); t_tilde_T = bi_set_as_nbin( outputSize, outputData); // allocation if( t_tilde_T == NULL) { LogError("malloc of bi <%s> failed", "t_tilde_T"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); // first precomputation until here possible (verifier independent) length = TPM_DAA_SIZE_w; buffer = (BYTE *)malloc( length); if( buffer == NULL) { LogError("malloc of %d bytes failed", length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_byte_array( buffer, length, zeta); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 6, pk->capitalGammaLength, pk->capitalGamma, length, buffer, &ownerAuth, &outputSize, &outputData); free( buffer); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 6 - capitalGamma & zeta"); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 7, pk->capitalGammaLength, pk->capitalGamma, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 7 - capitalGamma. Return capital_Nv"); capital_Nv = bi_set_as_nbin( outputSize, outputData); // allocation if( capital_Nv == NULL) { LogError("malloc of bi <%s> failed", "capital_Nv"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); // TODO Step 6 a.b - anonymity revocation result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 8, pk->capitalGammaLength, pk->capitalGamma, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 8 - capitalGamma. Return capital_N_tilde_v"); capital_N_tilde_v = bi_set_as_nbin( outputSize, outputData); // allocation if( capital_N_tilde_v == NULL) { LogError("malloc of bi <%s> failed", "capital_N_tilde_v"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); // TODO Step 6 c,d - anonymity revocation // Second precomputation until here possible (verifier dependent) size_bits = DAA_PARAM_SIZE_RSA_MODULUS + DAA_PARAM_SAFETY_MARGIN; w = bi_new_ptr(); if( w == NULL) { LogError("malloc of bi <%s> failed", "w"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_urandom( w, size_bits); capital_A = bi_set_as_nbin( daaCredential->capitalALength, daaCredential->capitalA); // allocation if( capital_A == NULL) { LogError("malloc of bi <%s> failed", "capital_A"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } capital_T = bi_new_ptr(); if( capital_T == NULL) { LogError("malloc of bi <%s> failed", "capital_T"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( tmp1, pk_intern->capitalS, w, n); bi_mul( capital_T, capital_A, tmp1); bi_mod( capital_T, capital_T, n); size_bits = DAA_PARAM_SIZE_INTERVAL_EXPONENT_CERTIFICATE + DAA_PARAM_SAFETY_MARGIN + DAA_PARAM_SIZE_MESSAGE_DIGEST; r_E = bi_new_ptr(); if( r_E == NULL) { LogError("malloc of bi <%s> failed", "r_E"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_urandom( r_E, size_bits); size_bits = DAA_PARAM_SIZE_EXPONENT_CERTIFICATE + DAA_PARAM_SIZE_RSA_MODULUS + 2 * DAA_PARAM_SAFETY_MARGIN + DAA_PARAM_SIZE_MESSAGE_DIGEST + 1; r_V = bi_new_ptr(); if( r_V == NULL) { LogError("malloc of bi <%s> failed", "r_V"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_urandom( r_V, size_bits); capital_T_tilde = bi_new_ptr(); if( capital_T_tilde == NULL) { LogError("malloc of bi <%s> failed", "capital_T_tilde"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mod_exp( tmp1, capital_T, r_E, n); bi_mul( capital_T_tilde, t_tilde_T, tmp1); bi_mod( capital_T_tilde, capital_T_tilde, n); bi_mod_exp( tmp1, pk_intern->capitalS, r_V, n); bi_mul( capital_T_tilde, capital_T_tilde, tmp1); bi_mod( capital_T_tilde, capital_T_tilde, n); // attributes extension size_bits = DAA_PARAM_SIZE_F_I + DAA_PARAM_SAFETY_MARGIN + DAA_PARAM_SIZE_MESSAGE_DIGEST; capital_R = pk_intern->capitalY; r_A = (bi_array_ptr)malloc( sizeof( struct _bi_array)); if( r_A == NULL) { LogError("malloc of %d bytes failed", sizeof( struct _bi_array)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_new_array2( r_A, revealAttributes.indicesListLength); product_R = bi_new_ptr(); if( product_R == NULL) { LogError("malloc of bi <%s> failed", "product_R"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_set( product_R, bi_1); for( i=0; i<(int)revealAttributes.indicesListLength; i++) { if( revealAttributes.indicesList[i] == 0) { // only non selected r_A->array[i] = bi_new_ptr(); if( r_A->array[i] == NULL) { LogError("malloc of bi <%s> failed", "r_A->array[i]"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_urandom( r_A->array[i] , size_bits); bi_mod_exp( tmp1, capital_R->array[i], r_A->array[i], n); bi_mul( product_R, product_R, tmp1); bi_mod( product_R, product_R, n); } else r_A->array[i] = NULL; } bi_mul( capital_T_tilde, capital_T_tilde, product_R); bi_mod( capital_T_tilde, capital_T_tilde, n); //TODO Step 8 - Commitments // compute commitment to attributes not revealed to the verifier //TODO Step 9 - callback functions // only when revocation not enabled pseudonym_plain = (TSS_DAA_PSEUDONYM_PLAIN *)calloc_tspi( tcsContext, sizeof(TSS_DAA_PSEUDONYM_PLAIN)); if( pseudonym_plain == NULL) { LogError("malloc of %d bytes failed", sizeof(TSS_DAA_PSEUDONYM_PLAIN)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } init_tss_version( pseudonym_plain); pseudonym_plain->capitalNv = calloc_tspi( tcsContext, bi_nbin_size( capital_Nv)); if( pseudonym_plain->capitalNv == NULL) { LogError("malloc of bi <%s> failed", "pseudonym_plain->capitalNv"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(pseudonym_plain->capitalNvLength), pseudonym_plain->capitalNv, capital_Nv); pseudonym_plain_tilde = (TSS_DAA_PSEUDONYM_PLAIN *) calloc_tspi( tcsContext,sizeof(TSS_DAA_PSEUDONYM_PLAIN)); if( pseudonym_plain_tilde == NULL) { LogError("malloc of %d bytes failed", sizeof(TSS_DAA_PSEUDONYM_PLAIN)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } init_tss_version( pseudonym_plain_tilde); pseudonym_plain_tilde->capitalNv = calloc_tspi( tcsContext, bi_nbin_size( capital_N_tilde_v)); if( pseudonym_plain_tilde->capitalNv == NULL) { LogError("malloc of bi <%s> failed", "pseudonym_plain_tilde->capitalNv"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(pseudonym_plain_tilde->capitalNvLength), pseudonym_plain_tilde->capitalNv, capital_N_tilde_v); // Step 10 - compute challenge ch = compute_sign_challenge_host( &chLength, DAA_PARAM_get_message_digest(), pk_intern, verifierNonceLength, verifierNonce, 0, // int selected_attributes2commitLength, NULL, // TSS_DAA_SELECTED_ATTRIB **selected_attributes2commit, 0, // int is_anonymity_revocation_enabled, zeta, capital_T, capital_T_tilde, 0, // int attribute_commitmentsLength, NULL, // TSS_DAA_ATTRIB_COMMIT_internal **attribute_commitments, NULL, // TSS_DAA_ATTRIB_COMMIT_internal **attribute_commitment_proofs, capital_Nv, capital_N_tilde_v, NULL, // CS_PUBLIC_KEY *anonymity_revocator_pk, NULL, // CS_ENCRYPTION_RESULT *encryption_result_rand, NULL //CS_ENCRYPTION_RESULT *encryption_result_proof) ); if( ch == NULL) { LogError("malloc in compute_sign_challenge_host failed"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 9, chLength, ch, 0, NULL, &ownerAuth, &nonce_tpmLength, &nonce_tpm); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 9 - compute sign challenge host. Return nonce_tpm"); byte = (BYTE)signData.payloadFlag; // 0 -> payload contains a handle to an AIK // 1 -> payload contains a hashed message result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 10, sizeof(BYTE), &byte, signData.payloadLength, signData.payload, &ownerAuth, &c_bytesLength, &c_bytes); LogDebug("calculation of c: ch[%d]%s", chLength, dump_byte_array( chLength, ch)); LogDebug("calculation of c: nonce_tpm[%d]%s", nonce_tpmLength, dump_byte_array( nonce_tpmLength, nonce_tpm)); LogDebug("calculation of c: sign_data.payloadFlag[%d]%x", 1, (int)signData.payloadFlag); LogDebug("calculation of c: signdata.payload[%d]%s", signData.payloadLength, dump_byte_array( signData.payloadLength, signData.payload)); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 10 - compute signData.payload."); LogDebug(" Return c_bytes[%d]%s", c_bytesLength, dump_byte_array( c_bytesLength, c_bytes)); c = bi_set_as_nbin( c_bytesLength, c_bytes); // allocation if( c == NULL) { LogError("malloc of bi <%s> failed", "c"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 11, 0, NULL, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS)goto close; LogDebug( "done Sign 11. Return sF0"); sF0 = bi_set_as_nbin( outputSize, outputData); // allocation if( sF0 == NULL) { LogError("malloc of bi <%s> failed", "sF0"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 12, 0, NULL, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 12. Return sF1"); sF1 = bi_set_as_nbin( outputSize, outputData); // allocation if( sF1 == NULL) { LogError("malloc of bi <%s> failed", "sF1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 13, daaCredential->vBar0Length, daaCredential->vBar0, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 13. Return sV1"); sV1 = bi_set_as_nbin( outputSize, outputData); // allocation if( sV1 == NULL) { LogError("malloc of bi <%s> failed", "sV1"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 14, daaCredential->vBar0Length, daaCredential->vBar0, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; free( outputData); LogDebug( "done Sign 14."); result = Tcsip_TPM_DAA_Sign( tcsContext, hDAA, 15, daaCredential->vBar1Length, daaCredential->vBar1, 0, NULL, &ownerAuth, &outputSize, &outputData); if( result != TSS_SUCCESS) goto close; LogDebug( "done Sign 15. Return sV2"); sV2 = bi_set_as_nbin( outputSize, outputData); // allocation if( sV2 == NULL) { LogError("malloc of bi <%s> failed", "sV2"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } free( outputData); // allocation e = bi_set_as_nbin( daaCredential->exponentLength, daaCredential->exponent); if( e == NULL) { LogError("malloc of bi <%s> failed", "e"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } // s_e = r_E + ( c * ( e - ( 1 << (sizeExponentCertificate -1)))) s_E = bi_new_ptr(); if( s_E == NULL) { LogError("malloc of bi <%s> failed", "s_E"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_shift_left( tmp1, bi_1, DAA_PARAM_SIZE_EXPONENT_CERTIFICATE - 1); bi_sub( tmp1, e, tmp1); bi_mul( tmp1, c, tmp1); bi_add( s_E, r_E, tmp1); s_V = bi_new_ptr(); if( s_V == NULL) { LogError("malloc of bi <%s> failed", "s_V"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } add_splitet( s_V, sV1, sV2); bi_add( s_V, s_V, r_V); bi_mul( tmp1, c, w); bi_mul( tmp1, tmp1, e); bi_sub( s_V, s_V, tmp1); // attributes extension // TODO verify the size of each selected attributes s_A = (bi_array_ptr)malloc( sizeof( struct _bi_array)); if( s_A == NULL) { LogError("malloc of bi_array <%s> failed", "s_A"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_new_array2( s_A, revealAttributes.indicesListLength); if( s_A->array == NULL) { LogError("malloc of bi_array <%s> failed", "s_A"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; i<(int)revealAttributes.indicesListLength; i++) { if( revealAttributes.indicesList[i] == 0) { s_A->array[i] = bi_new_ptr(); if( s_A->array[i] == NULL) { LogError("malloc of bi <%s> failed", "s_A->array[i]"); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } tmp2 = bi_set_as_nbin( DAA_PARAM_SIZE_F_I / 8, daaCredential->attributes[i]); // allocation if( tmp2 == NULL) { LogError("malloc of %d bytes failed", DAA_PARAM_SIZE_F_I / 8); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_mul( tmp1, c, tmp2); // TODEL LogDebug("daaCredential->attributes[i]=%ld", bi_nbin_size( tmp2)); LogDebug("r_A:%ld", bi_nbin_size( r_A->array[i])); LogDebug("c:%ld", bi_nbin_size( c)); LogDebug("c*daaCredential->attributes[i]=%ld", bi_nbin_size( tmp1)); // END TODEL bi_add( s_A->array[i], r_A->array[i], tmp1); bi_free_ptr( tmp2); } else s_A->array[i] = NULL; } // Compose result structure // DAASignaturePseudonym TODO: implement anonymity revocation // if ( !revocation_enabled) signature_pseudonym = pseudonym_plain; // populate the signature (TSS_DAA_SIGNATURE) daaSignature->zeta = (BYTE *)calloc_tspi( tcsContext, bi_nbin_size( zeta)); if (daaSignature->zeta == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( zeta)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaSignature->zetaLength), daaSignature->zeta, zeta); daaSignature->capitalT = (BYTE *)calloc_tspi( tcsContext, bi_nbin_size( capital_T)); if (daaSignature->capitalT == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( capital_T)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaSignature->capitalTLength), daaSignature->capitalT, capital_T); daaSignature->challenge = (BYTE *)calloc_tspi( tcsContext, c_bytesLength); if (daaSignature->challenge == NULL) { LogError("malloc of %d bytes failed", c_bytesLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } daaSignature->challengeLength = c_bytesLength; memcpy( daaSignature->challenge, c_bytes, c_bytesLength); daaSignature->nonceTpm = (BYTE *)calloc_tspi( tcsContext, nonce_tpmLength); if (daaSignature->nonceTpm == NULL) { LogError("malloc of %d bytes failed", nonce_tpmLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } daaSignature->nonceTpmLength = nonce_tpmLength; memcpy( daaSignature->nonceTpm, nonce_tpm, nonce_tpmLength); daaSignature->sV = (BYTE *)calloc_tspi( tcsContext, bi_nbin_size( s_V)); if (daaSignature->sV == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( s_V)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaSignature->sVLength), daaSignature->sV, s_V); daaSignature->sF0 = (BYTE *)calloc_tspi( tcsContext, bi_nbin_size( sF0)); if (daaSignature->sF0 == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( sF0)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaSignature->sF0Length), daaSignature->sF0, sF0); daaSignature->sF1 = (BYTE *)calloc_tspi( tcsContext, bi_nbin_size( sF1)); if (daaSignature->sF1 == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( sF1)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaSignature->sF1Length), daaSignature->sF1, sF1); daaSignature->sE = (BYTE *)calloc_tspi( tcsContext, bi_nbin_size( s_E)); if (daaSignature->sE == NULL) { LogError("malloc of %ld bytes failed", bi_nbin_size( s_E)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } bi_2_nbin1( &(daaSignature->sELength), daaSignature->sE, s_E); daaSignature->sALength = revealAttributes.indicesListLength; daaSignature->sA = (BYTE **)calloc_tspi( tcsContext, sizeof(BYTE *)*revealAttributes.indicesListLength); if (daaSignature->sA == NULL) { LogError("malloc of %d bytes failed", sizeof(BYTE *)*revealAttributes.indicesListLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } length = (DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES + 7) / 8; for( i=0; i<(int)revealAttributes.indicesListLength; i++) { daaSignature->sA[i] = calloc_tspi( tcsContext, length); if (daaSignature->sA[i] == NULL) { LogError("malloc of %d bytes failed", length); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } if( s_A->array[i] == NULL) bi_2_byte_array( daaSignature->sA[i], length, bi_0); else { bi_2_byte_array( daaSignature->sA[i], length, s_A->array[i]); LogDebug("size big_integer s_A[i] = %ld size daaSignature->sA[i]=%d", bi_nbin_size( s_A->array[i]), length); } } daaSignature->attributeCommitmentsLength = 0; daaSignature->signedPseudonym = signature_pseudonym; close: bi_free_ptr( tmp1); if( c_bytes != NULL) free( c_bytes); if( ch != NULL) free( ch); if( nonce_tpm != NULL) free( nonce_tpm); if( encryption_result !=NULL) free( encryption_result); if( encryption_result_tilde !=NULL) free( encryption_result_tilde); if( issuer_settings != NULL) free( issuer_settings); if( r_A != NULL) { for( i=0; i<(int)revealAttributes.indicesListLength; i++) if( r_A->array[i] != NULL) bi_free_ptr( r_A->array[i]); free( r_A); } FREE_BI( s_V); FREE_BI( s_E); FREE_BI( e); FREE_BI( sV2); FREE_BI( sV1); FREE_BI( sF1); FREE_BI( sF0); FREE_BI( c); FREE_BI( product_R); FREE_BI( capital_A); FREE_BI( capital_T_tilde); FREE_BI( r_V); FREE_BI( r_E); FREE_BI( capital_T); FREE_BI( w); FREE_BI( capital_N_tilde_v); FREE_BI( capital_Nv); FREE_BI( t_tilde_T); FREE_BI( n); FREE_BI( capital_gamma); FREE_BI( gamma); FREE_BI( zeta); FREE_BI( r); free_TSS_DAA_PK_internal( pk_intern); free_TPM_DAA_ISSUER( tpm_daa_issuer); return result; } trousers-0.3.15/src/tspi/daa/daa_anonymityrevocation/0000775000175000017510000000000013663651711022175 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/daa_anonymityrevocation/csencryption_result.c0000664000175000017510000001300213663651711026453 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include "daa_parameter.h" #include "daa_structs.h" #include "anonymity_revocation.h" #include "verifier.h" #include "tsplog.h" CS_ENCRYPTION_RESULT *create_CS_ENCRYPTION_RESULT( bi_ptr c1, bi_ptr c2, bi_ptr c3, bi_ptr c4 ) { CS_ENCRYPTION_RESULT *result = (CS_ENCRYPTION_RESULT *)malloc( sizeof(CS_ENCRYPTION_RESULT)); if (result == NULL) { LogError("malloc of %d bytes failed", sizeof(CS_ENCRYPTION_RESULT)); return NULL; } result->c1 = c1; result->c2 = c2; result->c3 = c3; result->c4 = c4; return result; } CS_ENCRYPTION_RESULT_RANDOMNESS *create_CS_ENCRYPTION_RESULT_RANDOMNESS( CS_ENCRYPTION_RESULT *cs_encryption_result, bi_ptr randomness ) { CS_ENCRYPTION_RESULT_RANDOMNESS *result = (CS_ENCRYPTION_RESULT_RANDOMNESS *) malloc(sizeof(CS_ENCRYPTION_RESULT_RANDOMNESS)); if (result == NULL) { LogError("malloc of %d bytes failed", sizeof(CS_ENCRYPTION_RESULT_RANDOMNESS)); return NULL; } result->randomness = randomness; result->result = cs_encryption_result; return result; } bi_ptr compute_u( const EVP_MD *digest, const bi_ptr c1, const bi_ptr c2, const bi_ptr c3, const BYTE *condition, const int conditionLength ) { BYTE *buffer, *bytes; int c1_size = bi_nbin_size( c1); int c2_size = bi_nbin_size( c2); int c3_size = bi_nbin_size( c3); int index = 0; int length; bi_ptr value; int bufferLength = c1_size + c2_size + c3_size + conditionLength; buffer = (BYTE *)malloc( bufferLength); if (buffer == NULL) { LogError("malloc of %d bytes failed", bufferLength); return NULL; } bi_2_byte_array( &buffer[index], c1_size, c1); index += c1_size; bi_2_byte_array( &buffer[index], c2_size, c2); index += c2_size; bi_2_byte_array( &buffer[index], c3_size, c3); index += c3_size; memcpy( &buffer[index], condition, conditionLength); index += conditionLength; length = DAA_PARAM_LENGTH_MFG1_ANONYMITY_REVOCATION / 8; // 25 /8 bytes = compute_bytes( bufferLength, buffer, length, digest); if( bytes == NULL) return NULL; value = bi_set_as_nbin( length, bytes); free( bytes); free( buffer); return value; } CS_ENCRYPTION_RESULT_RANDOMNESS* internal_compute_encryption_proof( const bi_ptr msg, const bi_ptr delta1, const bi_ptr delta2, const bi_ptr delta3, const bi_ptr randomness, const CS_PUBLIC_KEY *key, const struct tdTSS_DAA_PK_internal *daa_key, const BYTE *condition, const int conditionLength, const EVP_MD *digest ) { bi_ptr modulus = daa_key->modulus; bi_ptr gamma = daa_key->gamma; bi_ptr c1 = bi_new_ptr( ); bi_ptr c2 = bi_new_ptr( ); bi_ptr c3 = bi_new_ptr( ); bi_ptr c4; bi_ptr exp; bi_t bi_tmp; bi_t bi_tmp1; bi_new( bi_tmp); bi_new( bi_tmp1); if( bi_cmp( msg, modulus) >= 0) { LogError("IllegalArgument: msg to big for key size"); bi_free_ptr( c1); bi_free_ptr( c2); bi_free_ptr( c3); bi_free( bi_tmp); bi_free( bi_tmp1); return NULL; } bi_mod_exp( c1, gamma, randomness, modulus); bi_mod_exp( c2, key->eta, randomness, modulus); // c3=msg * (key->lambda3 ^ randomness) % mopdulus) bi_mul( c3, msg, bi_mod_exp( bi_tmp, key->lambda3, randomness, modulus)); bi_mod( c3, c3, modulus); // c3 = c3 % modulus if( delta1 != NULL) { if( !( delta2!=NULL && delta3!=NULL)) { LogError("Illegal Arguments: delta2==NULL or delta3==NULL"); bi_free_ptr( c1); bi_free_ptr( c2); bi_free_ptr( c3); bi_free( bi_tmp); bi_free( bi_tmp1); return NULL; } exp = compute_u( digest, delta1, delta2, delta3, condition, conditionLength); } else { if( !( delta2==NULL && delta3==NULL)) { LogError("Illegal Arguments: delta2!=NULL or delta3!=NULL"); bi_free_ptr( c1); bi_free_ptr( c2); bi_free_ptr( c3); bi_free( bi_tmp); bi_free( bi_tmp1); return NULL; } exp = compute_u( digest, c1, c2, c3, condition, conditionLength); } // exp = exp * randomness bi_mul( exp, exp, randomness); // exp = exp % daa_key->rho bi_mod( exp, exp, daa_key->rho); // bi_tmp = (key->lambda1 ^ randomness) % modulus bi_mod_exp( bi_tmp, key->lambda1, randomness, modulus); // bi_tmp1 = (key->lambda2 ^ exp) % modulus bi_mod_exp( bi_tmp1, key->lambda2, exp, modulus); c4 = bi_new_ptr(); // c4 = bi_tmp * bi_tmp1 bi_mul( c4, bi_tmp, bi_tmp1); // c4 = c4 % modulus bi_mod( c4, c4, modulus); bi_free_ptr( exp); bi_free( bi_tmp1); bi_free( bi_tmp); return create_CS_ENCRYPTION_RESULT_RANDOMNESS( create_CS_ENCRYPTION_RESULT( c1, c2, c3, c4), randomness); } /* Cramer-Shoup EncryptionProof from com.ibm.zurich.tcg.daa.anonymityrevocation.CSEncryptionProof */ CS_ENCRYPTION_RESULT_RANDOMNESS *compute_ecryption_proof( const bi_ptr msg, const bi_ptr delta1, const bi_ptr delta2, const bi_ptr delta3, const bi_ptr randomness, const CS_PUBLIC_KEY *key, const struct tdTSS_DAA_PK_internal *daa_key, const BYTE *condition, const int conditionLength, const EVP_MD *digest ) { if( delta1 == NULL || delta2 == NULL || delta3 == NULL) { LogError("Illegal Argument: deltas (delta1:%ld delta2:%ld delta3:%ld)", (long)delta1, (long)delta2, (long)delta3); return NULL; } if( bi_cmp( randomness, daa_key->rho) >=0 || bi_cmp_si( randomness, 0) < 0) { LogError("randomness >= rho || randomness < 0 \n\trandomness:%s\n\trho:%s\n", bi_2_dec_char( randomness), bi_2_dec_char( daa_key->rho)); return NULL; } return internal_compute_encryption_proof( msg, delta1, delta2, delta3, randomness, key, daa_key, condition, conditionLength, digest); } trousers-0.3.15/src/tspi/daa/big_integer/0000775000175000017510000000000013663651711017525 5ustar deboradeboratrousers-0.3.15/src/tspi/daa/big_integer/bi.c0000664000175000017510000001447013663651711020271 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include "tcslog.h" #undef INLINE_DECL #define INLINE_DECL /*********************************************************************************** CONSTANT *************************************************************************************/ bi_t bi_0; bi_t bi_1; bi_t bi_2; /*********************************************************************************** WORK VARIABLE *************************************************************************************/ // Buffer to load bi from a file . A static field is used, this should not be // refere in any SPI calls. #define BUFFER_SIZE 10000 static char buffer[BUFFER_SIZE]; // used for loading bi #define SAFETY_PARAM 80 // keep the list of allocated memory, usually used for the format functions list_ptr allocs = NULL; /*********************************************************************************** DUMP LIB *************************************************************************************/ // !! to use only for debugging // do not used it in the same call, as a static buffer is used char *dump_byte_array(int len, unsigned char *array) { int i, j=0; char c, str[3]; for( i=0; i and return it into a byte array of length */ unsigned char *retrieve_byte_array( int *len, const char *strings) { int index_str = 0, index_result = 0; int str_len = strlen( strings); char read_buffer[3]; int c; unsigned char *result; read_buffer[2]=0; *len = ( str_len >> 1); #ifdef BI_DEBUG printf("[%s]\n", strings); printf("[retrieve_byte_array] strlen=%d len=%d\n", str_len, *len); #endif result = (unsigned char *)malloc( *len+1); if( result == NULL) { LogError("malloc of %d bytes failed", *len+1); return NULL; } if( (str_len & 1) ==1) { // impair => 1 12 23 -> 01 12 23 read_buffer[0]='0'; read_buffer[1]=strings[index_str++]; sscanf( read_buffer, "%2X", &c); #ifdef BI_DEBUG printf("[c'=%2X|%s]", (int)(c & 0xFF), read_buffer); #endif result[index_result++] = c&0xFF; (*len)++; } while( index_str < str_len) { read_buffer[0] = strings[ index_str++]; read_buffer[1] = strings[ index_str++]; sscanf( read_buffer, "%02X", &c); #ifdef BI_DEBUG printf("[c'=%2X|%s]", (int)(c & 0xFF), read_buffer); #endif result[index_result++] = c&0xFF; } return result; } /* create a array */ INLINE_DECL void bi_new_array( bi_array array, const int length) { int i=0; bi_new_array2( array, length); if( array->array == NULL) return; for( i = 0; i< length; i++) { array->array[i] = bi_new_ptr(); } } /* create a array */ INLINE_DECL void bi_new_array2( bi_array array, const int length) { array->length = length; array->array = (bi_ptr *)malloc( sizeof(bi_ptr) * length); if( array->array == NULL) { LogError("malloc of %d bytes failed", sizeof(bi_ptr)*length); return; } } /* free resources allocated to the big integer */ INLINE_DECL void bi_free_array(bi_array array) { int length = array->length; int i=0; for( i = 0; i< length; i++) { bi_free_ptr( array->array[i]); } free( array->array); } /* copy length pointers from the array to array */ INLINE_DECL void bi_copy_array(bi_array_ptr src, int offset_src, bi_array_ptr dest, int offset_dest, int length) { int i=0; for( i = 0; i< length; i++) { dest->array[ offset_dest + i] = src->array[ offset_src + i]; } } /* debug function -> dump a field of type bi_array */ void dump_bi_array( char *field, const bi_array_ptr array) { int i; for( i=0; ilength; i++) { printf("%s->array[%d] = %s\n", field, i, bi_2_hex_char(array->array[i])); } } /*********************************************************************************** SAFE RANDOM *************************************************************************************/ /* Returns a random number in the range of [0,element-1] */ bi_ptr compute_random_number( bi_ptr result, const bi_ptr element) { bi_urandom( result, bi_length( element) + SAFETY_PARAM); bi_mod( result, result, element); return result; } /*********************************************************************************** SAVE / LOAD *************************************************************************************/ /* load an big integer from an open file handler */ void bi_load( bi_ptr bi, FILE *file) { int i=0; char c; fgets( buffer, BUFFER_SIZE, file); do { c = buffer[i]; i++; } while( c != 0 && c != ' '); buffer[i-1] = 0; bi_set_as_hex( bi, buffer); } /* load an big integer array from an open file handler */ void bi_load_array( bi_array_ptr array, FILE *file) { int i, j = 0, length; char c; fgets( buffer, BUFFER_SIZE, file); do { c = buffer[ j]; j++; } while( c != 0 && c != ' '); buffer[ j -1] = 0; sscanf( buffer, "%d", &length); bi_new_array( array, length); for( i=0; ilength; i++) { bi_load( array->array[i], file); } } /* save an big integer to an open file handler */ void bi_save( const bi_ptr bi, const char *name, FILE *file) { fprintf( file, "%s # %s [%ld]\n", bi_2_hex_char( bi), name, bi_nbin_size( bi)); } /* save an big integer array to an open file handler */ void bi_save_array( const bi_array_ptr array, const char *name, FILE *file) { int i; char new_name[100]; fprintf(file, "%d # %s.length\n", array->length, name); for( i=0; ilength; i++) { sprintf( new_name, "%s[%d]", name, i); bi_save( array->array[i], new_name, file); } } /* convert to a byte array of length result, the beginning of */ /* this buffer is feel with '0' if needed */ void bi_2_byte_array( unsigned char *result, int length, bi_ptr bi) { int i, result_length; bi_2_nbin1( &result_length, buffer, bi); int delta = length - result_length; #ifdef BI_DEBUG fprintf( stderr, "[bi_2_byte_array] result_length=%d length=%d\n", result_length, length); #endif if( delta < 0) { LogError( "[bi_2_byte_array] asked length:%d found:%d\n", length, result_length); return; } for( i=0; i #include // use standard C definition to avoid .h int test_exp_multi(void) { bi_t result; bi_t g[3]; unsigned long e[3]; bi_new( result); bi_new( g[0]); bi_new( g[1]); bi_new( g[2]); // result = (2^2 * 5^4 * 7^7) mod 56 -> should give 28 bi_set_as_dec( g[0], "2"); bi_set_as_dec( g[1], "5"); bi_set_as_dec( g[2], "7"); e[0] = 2L; e[1] = 4L; e[2] = 7L; bi_multi_mod_exp( result, 3, g, e, 56); printf("multi-exponentiation =%s\n", bi_2_dec_char(result)); bi_free( g[0]); bi_free( g[1]); bi_free( g[2]); bi_free( result); return 0; } trousers-0.3.15/src/tspi/daa/big_integer/test/Makefile.am0000664000175000017510000000035213663651711022540 0ustar deboradeborabin_PROGRAMS = test test_SOURCES=test.c multi_exp.c ../bi_gmp.c ../bi_openssl.c ../bi.c \ ../../../include/bi.h ../../../include/bi_openssl.h ../../../include/bi_gmp.h test_CFLAGS=-G # test_CFLAGS=-I../../../include -DBI_OPENSSL trousers-0.3.15/src/tspi/daa/big_integer/test/test.c0000664000175000017510000003004413663651711021630 0ustar deboradebora#include #include #include #include #include /* for the logging system used by TSS */ setenv("TCSD_FOREGROUND", "1", 1); /* * standard bit length extension to obtain a uniformly distributed number * [0,element] */ int test_exp_multi(void); void foo (bi_t result, const bi_ptr param, unsigned long n) { unsigned long i; bi_set( result, param); bi_mul_si( result, result, n); for (i = 1; i < n; i++) bi_add_si( result, result, i*7); } void *my_malloc(size_t size) { void *ret = malloc( size); printf("my_malloc() -> %ld\n", (long)ret); return ret; } /** * Returns a random number in the range of [0,element-1]. * * @param element * the upper limit * @param random * the secure random source * @return the random number */ void computeRandomNumber(bi_t res, const bi_ptr element) { int length = 80 + bi_length( res); // give the length bi_urandom( res, length); // res = random( of length); int element_length = bi_length( element); bi_mod_si( res, res, element_length); // res = res mod } int main (int argc, char **argv) { bi_t bi_tmp, bi_tmp1, bi_tmp2, bi_tmp3, bi_tmp4, bi_tmp5, bi_tmp6; bi_t r; bi_t n; int i; unsigned char result1[5]; int len; char *byte_array; FILE *file; unsigned char ret[] = { (unsigned char)1, 0, (unsigned char)254 }; int length; unsigned char *buffer; unsigned char byte; bi_ptr nn; bi_init( &my_malloc); printf("test(%s,%s)\n", __DATE__, __TIME__); #ifdef BI_GMP printf("using BMP\n"); #endif #ifdef BI_OPENSSL printf("using OPENSSL\n"); #endif bi_new( bi_tmp); bi_new( bi_tmp1); bi_new( bi_tmp2); bi_new( bi_tmp3); bi_new( bi_tmp4); bi_new( bi_tmp5); bi_new( bi_tmp6); bi_new( n); bi_new( r); bi_set_as_hex( n, "75E8F38669C531EB78C7ACD62CCDEFFB5E5BE15E2AA55B3AD28B1A35F6E937097CE09A49C689AC335FBA669205CEF209275CFF273F8F81C5B864E5029EECDFA0743BC15D6E4D2C2CB0DED2DC7119A7E0D61669D417BB3B12BA1D10FD40326A49CA6C9E77F8585F25D8C897D9C73284152E103582C018C964F02ADDBA56CB1161A949AAE2847ADE8BC1152716C8B4AF37A87011C2569F646FD3EDA83099048B9525A6401C47A372F3EA43C91066AD5851AE11DEF1EAC7108FFB06AD94D0B849C339A5E8793C4C054456D3D22D30ACCCF7EF33EF7A7D65799E7908D95B0538A9EFC91BF104CE5008D79625394DB1E5883B2F202B95320BBD868BF65C996FC0DFC5"); bi_set_as_hex( r, "35A624E6607CFD37162C6052547450B2267ECC749F10CDAEB5C294491321EEB47CA0229F423ADCEF3FA7806F5C4DB3C3445D8E7039EBC457149A1343BECF3B1078385C06EE74351A476BE0D5203633C81F7B8D68548DB763F0C096B20615B6016C180291EF32CC064A173BB22F6B46B3240ACC0B50D8338757FA28D5B0313BC4201CD2B35472842E71994C8FCA557B08004B2495304D13A93D796134BB8078E2EE371707DE5809D72474A7CCE1F865ECD8876105D3DB9AFA9426052D0120C755C60F56A0C0F30FAED2053CEB3129FAB6F57F6E209A8E7B2A559D734B339E19E1F2A147BC94DB2FF491CB5ACCEEEED7F2EA75AFF7CAD33E1E420A09135D9C5C1F"); DUMP_BI( n); DUMP_BI( r); printf("big number n=n*r\n"); bi_mul( n, n, r); DUMP_BI( n); bi_set_as_hex( r, "D7E7028DA181DADAC29C95143C865702453465115AFA7576AADF1E57DD84DA7FF4C8F66530D1E9D1AB69BC12342B89FA0A9755F9F4EE1DA445D50016CEF50622ED905CC9B987FCC7910CAA841641814C1994BC442A15CB05FE5C145626F1454E90435FBC6A529856EF29BDBCBFCB62FB69EDBD11DC33357667867278E1679EABCDBEEA02E9A6911804DF47ACA6B2D63A31E258AD542D71A8178A5E072F5E221EADBB10E16D5533AE427101FF94C5967575FABCD18305C5F15C103CEA1A8ACD01898E88426EDA7C0DF58AA48435808A840F6EEE1D7205D33F356E20FE0D4136B401BF386F11869C3CE4A808B96435694748EF3706F58756548A71E4CF4D2BE157"); bi_mod( n, n, r); printf("mod big number n=n mod r\n"); DUMP_BI( n); if( bi_get_si( bi_set_as_si( n, 13)) != 13) { printf("!!! bi_set_as_si 13(%s) = 13\n", bi_2_dec_char( n )); exit(-1); } if( bi_get_si( bi_set_as_si( n, -13)) != -13) { printf("!!! bi_set_as_si -13(%s) = -13\n", bi_2_dec_char( n )); exit(-1); } if( bi_get_si( bi_inc(bi_set_as_si( n, 13))) != 14) { puts("!!! bi_inc 13++ = 14\n"); exit(-1); } if( bi_get_si( bi_dec(bi_set_as_si( n, 13))) != 12) { puts("!!! bi_dec 13-- = 12\n"); exit(-1); } if( bi_get_si( bi_setbit(bi_set_as_si( n, 0), 10)) != 1024) { puts("!!! bi_setbit set[10] = 1024\n"); exit(-1); } if( bi_get_si( bi_mod_si(bi_tmp, bi_set_as_si( n, 12), 10)) != 2) { puts("!!! bi_mod_si 12 mod 10 = 2\n"); exit(-1); } if( bi_get_si( bi_mul_si(bi_tmp, bi_set_as_si( n, 12), 10)) != 120) { puts("!!! bi_mul_si 12 * 10 = 120\n"); exit(-1); } if( bi_get_si( bi_mul(bi_tmp, bi_set_as_si( n, 12), bi_set_as_si( bi_tmp1, 10))) != 120) { puts("!!! bi_mul_si 12 * 10 = 120\n"); exit(-1); } if( bi_get_si( bi_mod_exp_si(bi_tmp, bi_set_as_si( bi_tmp1, 4), bi_2, 10)) != 6) { puts("!!! bi_mod_exp_si 4 ^ 2 mod 10 = 6\n"); exit(-1); } if( bi_get_si( bi_mod_exp(bi_tmp, bi_set_as_si( bi_tmp1, 4), bi_2, bi_set_as_si( bi_tmp2, 10))) != 6) { puts("!!! bi_mod_exp 4 ^ 2 mod 10 = 6\n"); exit(-1); } if( bi_get_si( bi_mod(bi_tmp, bi_set_as_si( n, 12), bi_set_as_si(bi_tmp1, 10))) != 2) { printf("!!! bi_mod 12 mod 10 = 2 [%s]\n",bi_2_dec_char( bi_tmp)); exit(-1); } if( bi_get_si( bi_mod(bi_tmp, bi_set_as_si( n, -12), bi_set_as_si(bi_tmp1, 10))) != 8) { printf("!!! bi_mod -12 mod 10 = 8 [%s]\n",bi_2_dec_char( bi_tmp)); exit(-1); } if( bi_get_si( bi_mod(bi_tmp, bi_set_as_si( n, -27), bi_set_as_si(bi_tmp1, 10))) != 3) { printf("!!! bi_mod -27 mod 10 = 3 [%s]\n",bi_2_dec_char( bi_tmp)); exit(-1); } bi_set_as_si(n, 0x12345678); bi_2_byte_array( result1, 5, n); if( result1[0] != 0x00 || result1[1] != 0x12 || result1[2] != 0x34 || result1[3] != 0x56 || result1[4] != 0x78 ) { printf("!!! bi_2_byte_array[0x123456578] [0]=%x [1]=%x [2]=%x [3]=%x [4]=%x \n", result1[0], result1[1], result1[2], result1[3], result1[4]); exit( -1); } byte_array = retrieve_byte_array( &len, "12345"); printf("test dump_byte_array len=%d \n", len); printf("test dump_byte_array(\"12345\")=%s\n", dump_byte_array( len, byte_array)); free( byte_array); byte_array = retrieve_byte_array( &len, "12345678"); printf("test dump_byte_array len=%d \n", len); printf("test dump_byte_array(\"12345678\")=%s\n", dump_byte_array( len, byte_array)); // test save end load of bi_t and bi_array ///////////////////////////////////////////////////////////////////////////////////// bi_array result; bi_new_array( result, 2); bi_set_as_si( bi_tmp, 6); bi_set_as_si( result->array[0], 314159); bi_set_as_si( result->array[1], 123456789); file = fopen("/tmp/test.todel", "w"); bi_save_array( result, "result", file); bi_save( bi_tmp, "bi_tmp", file); fclose( file); bi_set_as_si( result->array[0], 0); bi_set_as_si( result->array[1], 0); bi_set_as_si( bi_tmp, 0); file = fopen("/tmp/test.todel", "r"); bi_load_array( result, file); bi_load( bi_tmp, file); fclose( file); if( bi_get_si( result->array[0]) != 314159) { puts("!!! save/load array[0] = 314159\n"); exit(-1); } if( bi_get_si( result->array[1]) != 123456789) { puts("!!! save/load array[1] = 123456789\n"); exit(-1); } if( bi_get_si( bi_tmp) != 6) { puts("!!! save/load bi_tmp = 6\n"); exit(-1); } // conversion from bi_t 2 big endian BYTE* ///////////////////////////////////////////////////////////////////////////////////// bi_set_as_si( n, 254+(1 << 16)); buffer = bi_2_nbin( &length, n); printf("value 2 convert=%s length=%ld\n", bi_2_hex_char( n), bi_nbin_size( n)); for( i=0; i> 5 = %s\n", bi_2_dec_char( bi_shift_right(bi_tmp, bi_shift_left(bi_tmp1, n, 10), 5))); bi_set_as_si(n, 1); printf("[* (1 << 10) >> 5 *] = (2^10) / (2^5) -> %s\n", bi_2_dec_char( bi_shift_right( bi_tmp, ( bi_shift_left( bi_tmp1, n, 10)), 5))); bi_set_as_si( n, 10); printf(" (2^10) = %s\n", bi_2_dec_char( bi_mod_exp_si( bi_tmp, bi_2, n, 2000))); printf(" (1<<5) = %s\n", bi_2_dec_char( bi_shift_left( bi_tmp, bi_set_as_si( bi_tmp1, 1), 5))); printf(" 1024 / 500 = %s\n", bi_2_dec_char( bi_div( bi_tmp, bi_set_as_si( bi_tmp1, 1024), bi_set_as_si( bi_tmp2, 500)))); printf(" 1024 / 500 = %s\n", bi_2_dec_char( bi_div_si( bi_tmp, bi_set_as_si( bi_tmp1, 1024), 500))); printf(" (1 << 10) >> 5 = [* (2^10) / (2^5) *] -> %s\n", bi_2_dec_char( bi_div( bi_tmp1, bi_mod_exp_si( bi_tmp2, bi_2, bi_set_as_si( bi_tmp3, 10), 2000), bi_mod_exp_si( bi_tmp4, bi_2, bi_set_as_si( bi_tmp5, 5), 2000) ))); printf("(1 << 10) >> 5 = (2^10) / (1<<5) -> %d\n", bi_equals( bi_shift_right( bi_tmp, ( bi_shift_left( bi_tmp1, bi_1, 10)), 5), bi_div( bi_tmp2, bi_mod_exp_si( bi_tmp3, bi_2, bi_set_as_si( bi_tmp4, 10), 2000), bi_mod_exp_si( bi_tmp5, bi_2, bi_set_as_si( bi_tmp6, 5), 2000)))); printf("( 45 ^ -5 ) %% 10 == ( 1 / ( (45 ^ 5) %% 10) ) %% 10\n"); bi_set_as_si( bi_tmp, 45); bi_set_as_si( bi_tmp1, 5); // bi_negate( bi_tmp1); bi_set_as_si( bi_tmp2, 10); bi_mod_exp( bi_tmp3, bi_tmp, bi_tmp1, bi_tmp2); bi_set_as_si( bi_tmp1, 5); bi_mod_exp( bi_tmp4, bi_tmp, bi_tmp1, bi_tmp2); printf("\t( 45 ^ -5 ) %% 10 = %s\n", bi_2_dec_char( bi_tmp3)); printf("\t( 1 / ( (45 ^ 5) %% 10) ) %% 10 = %s\n", bi_2_dec_char( bi_tmp4)); if( bi_equals( bi_tmp3, bi_tmp4) == 0) { printf("!!! error !\n"); exit( -1); } for( i=0; i<5; i++) { bi_generate_prime( bi_tmp, 1024); printf("bi=%s\n", bi_2_hex_char( bi_tmp)); printf("bi.length=%ld \n", bi_length( bi_tmp)); if( bi_length( bi_tmp) != 1024) { puts("!!! length(random(1024)) != 1024\n"); exit(-1); } } bi_set_as_si(n, 0); bi_setbit( n, 10); printf("setbit(10) = %s\n", bi_2_dec_char( n)); bi_set_as_dec(n, "123456"); foo( r, n, 20L); printf("TEST:%s\n", bi_2_dec_char( r)); bi_urandom( n, 1024); bi_urandom( r, 1024); computeRandomNumber( r, n); printf("r:%s n:%s\n", bi_2_hex_char( r), bi_2_hex_char( n)); bi_generate_prime( r, 1024); printf("prime:%s\nIs probable prime:%d\n", bi_2_hex_char( r), bi_is_probable_prime( r)); int error = bi_invert_mod( r, r, n); printf("Invert mod return:%d\nInvert(r):%s\n", error, bi_2_hex_char( r)); bi_negate( r); printf("negate(r):%s\n", bi_2_hex_char( r)); bi_generate_safe_prime( r, 128); bi_sub_si( n, r, 1); // n= r - 1 bi_shift_right( n, n, 1); // n = n / 2 printf("safe prime(r):%s probable_prime:%d\n", bi_2_hex_char( r), bi_is_probable_prime( r)); printf("safe prime( (r-1)/2):%s probable_prime:%d\n", bi_2_hex_char( n), bi_is_probable_prime( n)); test_exp_multi(); bi_free( r); bi_free( n); bi_set_as_si( result->array[0], 1); printf("result-> 1<<20:%s\n", bi_2_dec_char( bi_shift_left( result->array[0], result->array[0], 20))); bi_set_as_si( result->array[1], 1); printf("result1-> 1<<10:%s\n", bi_2_dec_char( bi_shift_right( result->array[1], result->array[0], 10))); // copy arrays bi_array new_result; bi_new_array2( new_result, 4); bi_new_array2( new_result, 4); bi_copy_array( result, 0, new_result, 0, 2); bi_copy_array( result, 0, new_result, 2, 2); for( i = 0; i<4; i++) { printf("new_result[%d]-> [even-> 1<<20] [odd-> 1<<10] :%s\n", i, bi_2_dec_char( new_result->array[i])); } bi_free( bi_tmp); bi_free( bi_tmp1); bi_free( bi_tmp2); bi_free( bi_tmp3); bi_free( bi_tmp4); bi_free( bi_tmp5); bi_free( bi_tmp6); bi_release(); printf("THE END [%s,%s]\n", __DATE__, __TIME__); fflush(stdout); return 0; } trousers-0.3.15/src/tspi/daa/big_integer/bi_gmp.c0000664000175000017510000001554113663651711021134 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifdef BI_GMP #include #include #include #include #undef INLINE_DECL #define INLINE_DECL gmp_randstate_t state; /* reps controls how many tests should be done in mpz_probable_prime_p: 5 to 10 are reasonable number */ static int reps = 20; static int initialized = 0; void * (*bi_alloc)(size_t size); /*********************************************************************************** BITS OPERATION *************************************************************************************/ // for conversion from and to byte[] see mpz_export and mpz_import /* return the size of a network byte order representation of */ long bi_nbin_size(const bi_ptr i) { int word_size = 1; // 1 byte per word int numb = 8 * word_size - 0; int count = (mpz_sizeinbase ( i, 2) + numb-1) / numb; return count * word_size; } /* return a BYTE * - in network byte order - and update the length */ unsigned char *bi_2_nbin( int *length, const bi_ptr i) { unsigned char *buffer = (unsigned char *)bi_alloc( bi_nbin_size( i)); if( buffer == NULL) return NULL; mpz_export(buffer, length, 1, 1, 1, 0, i); return buffer; } /* return a BYTE * - in network byte order - and update the length */ /* different from bi_2_nbin: you should reserve enough memory for the storage */ void bi_2_nbin1( int *length, unsigned char *buffer, const bi_ptr i) { mpz_export(buffer, length, 1, 1, 1, 0, i); } /* return a bi_ptr that correspond to the big endian encoded BYTE array of length */ INLINE_DECL bi_ptr bi_set_as_nbin( const unsigned long length, const unsigned char *buffer) { bi_ptr ret = bi_new_ptr(); if( ret == NULL) return NULL; mpz_import( ret, length, 1, 1, 1, 0, buffer); return ret; } /*********************************************************************************** BASIC MATH OPERATION *************************************************************************************/ /* multiple-exponentiation */ /* := mod( Multi( i, i), number of byte ) with 0 <= i <= */ bi_ptr bi_multi_mod_exp( bi_ptr result, const int n, const bi_t g[], const long e[], const int m) { mpz_t temp, bi_m; int i; mpz_init( temp); mpz_init( bi_m); mpz_set_si( bi_m, m); // result := (g[0] ^ e[0]) mod m mpz_powm_ui( result, g[0], e[0], bi_m); for( i=1; i bits */ INLINE_DECL bi_ptr bi_generate_prime( bi_ptr result, const long length) { do { mpz_urandomb( result, state, length); // i := random( length) bi_setbit( result, 0); bi_setbit( result, length - 1); bi_setbit( result, length - 2); mpz_nextprime( result, result); // i := nextPrime( i) } while( mpz_sizeinbase( result, 2) != (unsigned long)length && bi_is_probable_prime( result) ); return result; } /* generate a safe prime number of bits */ /* by safe we mean a prime p so that (p-1)/2 is also prime */ INLINE_DECL bi_ptr bi_generate_safe_prime( bi_ptr result, long length) { mpz_t temp; mpz_init(temp); do { bi_generate_prime( result, length); mpz_sub_ui( temp, result, 1); // temp := result - 1 mpz_div_2exp( temp, temp, 1); // temp := temp / 2 } while( mpz_probab_prime_p( temp, 10) == 0); #ifdef BI_DEBUG printf("GENERATE SAFE PRIME DONE");fflush(stdout); #endif mpz_clear( temp); return result; } /* return true if is a probably prime */ INLINE_DECL int bi_is_probable_prime( bi_ptr i) { /* This function does some trial divisions and after some Miller-Rabin probabilistic primality tests. The second parameter controls how many tests should be done, 5 to 10 are reasonable number */ return mpz_probab_prime_p( i, reps)>=1 ? 1 : 0; } /* return in the greatest common divisor of and */ /* := gcd( , ) */ INLINE_DECL bi_ptr bi_gcd( bi_ptr result, bi_ptr a, bi_ptr b) { // result := gcd( a, b) mpz_gcd( result, a, b); return result; } /*********************************************************************************** INIT/RELEASE LIBRARY *************************************************************************************/ /* bi_alloc_p allocation function used only for exporting a bi struct, so for bi_2_nbin if define as NULL, a stdlib malloc() will be used */ void bi_init( void * (*bi_alloc_p)(size_t size)) { time_t start; unsigned long seed; FILE *f; #ifdef INTERACTIVE int c, i; #endif if( initialized == 1) return; if( bi_alloc_p == NULL) bi_alloc = &malloc; else bi_alloc = bi_alloc_p; mpz_init( bi_0); mpz_set_ui( bi_0, 0); mpz_init( bi_1); mpz_set_ui( bi_1, 1); mpz_init( bi_2); mpz_set_ui( bi_2, 2); allocs = list_new(); if( allocs == NULL) { LogError("malloc of list failed"); return; } #ifdef BI_DEBUG printf("bi_init() -> gmp lib\n"); #endif time( &start); // first try /dev/random, the most secure random generator f = fopen("/dev/random", "r"); // in case of failure, but les secure :( if( f== NULL) f = fopen("/dev/urandom", "r"); if( f != NULL) { fread( &seed, sizeof(unsigned long int), 1, f); fclose(f); } #ifdef INTERACTIVE else { printf("! devices /dev/random and /dev/urandom not found\n"); printf("type some characters to generate a random seed (follow by enter)\n"); fflush(stdout); i=0; while( (c = fgetc(stdin)) != 10) { time_t temps; time( &temps); seed += temps +( c << i); i++; } time_t temps; time( &temps); seed += temps; #ifdef BI_DEBUG printf("temps=%lx\n", temps - start); #endif // BI_DEBUG seed = (long)( temps * start); } #endif // INTERACTIVE #ifdef BI_DEBUG printf("seed=%lx\n", seed); #endif gmp_randinit_default( state); gmp_randseed_ui( state, seed); initialized = 1; } void bi_release(void) { if( initialized) { bi_flush_memory(); bi_free( bi_0); bi_free( bi_1); bi_free( bi_2); initialized = 0; } } void bi_flush_memory(void) { node_t *current; list_ptr list = allocs; if( list->head == NULL) return; // list is empty else { current = list->head; // go to first node do { LogDebug("[flush memory] free %lx\n", current->obj); free( current->obj); current = current->next; // traverse through the list } while(current != NULL); // until current node is NULL } list_freeall( allocs); allocs = list_new(); if( allocs == NULL) { LogError("malloc of list failed"); return; } } int bi_is_initialized(void) { return initialized; } #endif trousers-0.3.15/src/tspi/daa/big_integer/bi_openssl.c0000664000175000017510000001036313663651711022031 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifdef BI_OPENSSL #define INSIDE_LIB #include #include #include #include #include "tcslog.h" #undef INLINE_DECL #define INLINE_DECL #include #include BN_CTX *context; static int initialized = 0; void * (*bi_alloc)(size_t size); /* return true if is a probably prime */ INLINE_DECL int bi_is_probable_prime( const bi_ptr i) { /* * start tests using some small prime numbers. Continue by performing a Miller-Rabin * probabilistic primality test with checks iterations, and with some iterations that * yields a false positive rate of at most 2^-80 for random input. * return: * 0 if the number is composite * 1 if it is prime with an error probability of less than 0.25^checks, and on error. */ return BN_is_prime_fasttest( i, BN_prime_checks, NULL, context, NULL, 1); } /* := ( ^ ) mod */ INLINE_DECL bi_ptr bi_mod_exp_si( bi_ptr result, const bi_ptr g, const bi_ptr e, const long m) { bi_t bi_tmp; bi_new( bi_tmp); BN_set_word( bi_tmp, m); #ifdef BI_DEBUG printf("[bi_mod_exp] (g=%s ^ e=%s) mod=%s\n", BN_bn2dec( g), BN_bn2dec( e), BN_bn2dec( bi_tmp)); #endif BN_mod_exp( result, g, e, bi_tmp, context); // result := (g ^ e) mod bi_tmp9 #ifdef BI_DEBUG printf("[bi_mod_exp] res=%s\n", BN_bn2dec( result)); #endif bi_free( bi_tmp); return result; } /* multiple-exponentiation */ /* := mod( Multi( i, i), number of byte ) with 0 <= i <= */ bi_ptr bi_multi_mod_exp( bi_ptr result, const int n, const bi_t g[], const long e[], const int m ) { BIGNUM *temp = BN_new(); BIGNUM *bi_m = BN_new(); BIGNUM *bi_e = BN_new(); int i; BN_set_word( bi_m, m); BN_set_word( bi_e, e[0]); // result := (g[0] ^ e[0]) mod bi_m BN_mod_exp( result, g[0], bi_e, bi_m, context); for( i=1; i openssl lib\n"); LogDebug("bi_init() -> seed status = %d\n", RAND_status()); context = BN_CTX_new(); if( RAND_status() != 1) { LogError("! PRNG has not been seeded with enough data\n"); #ifdef INTERACTIVE printf("type some characters to regenerate a random seed\n"); fflush(stdout); int c, i=0, seed; char str[2] = "a"; while( RAND_status() !=1 ) { c = fgetc(stdin); time_t temps; time( &temps); seed += temps +( c << i); i++; str[0]=c; RAND_seed( str, 1); } #endif } initialized = 1; } void bi_release(void) { if( initialized) { bi_flush_memory(); bi_free( bi_0); bi_free( bi_1); bi_free( bi_2); BN_CTX_free( context); initialized = 0; } } void bi_flush_memory(void) { node_t *current; list_ptr list = allocs; if( list->head == NULL) return; // list is empty else { current = list->head; // go to first node do { LogDebug("[flush memory] free %lx\n", (long)current->obj); free( current->obj); current = current->next; // traverse through the list } while(current != NULL); // until current node is NULL } list_freeall( allocs); allocs = list_new(); if( allocs == NULL) { LogError("malloc of list failed"); return; } } int bi_is_initialized(void) { return initialized; } #endif trousers-0.3.15/src/tspi/daa/daa_parameter.c0000664000175000017510000002166213663651711020207 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include "daa_parameter.h" setenv("TCSD_FOREGROUND", "1", 1); static EVP_MD *digest = NULL; extern EVP_MD *DAA_PARAM_get_message_digest(void) { if( digest == NULL) { OpenSSL_add_all_digests(); digest = EVP_get_digestbyname( DAA_PARAM_MESSAGE_DIGEST_ALGORITHM); } return digest; } // from common.c (ltp-tss) char *err_string(TSS_RESULT r) { /* Check the return code to see if it is common to all layers. * If so, return it. */ switch (TSS_ERROR_CODE(r)) { case TSS_SUCCESS: return "TSS_SUCCESS"; default: break; } /* The return code is either unknown, or specific to a layer */ if (TSS_ERROR_LAYER(r) == TSS_LAYER_TPM) { switch (TSS_ERROR_CODE(r)) { case TCPA_E_AUTHFAIL: return "TCPA_E_AUTHFAIL"; case TCPA_E_BADINDEX: return "TCPA_E_BADINDEX"; case TCPA_E_AUDITFAILURE: return "TCPA_E_AUDITFAILURE"; case TCPA_E_CLEAR_DISABLED: return "TCPA_E_CLEAR_DISABLED"; case TCPA_E_DEACTIVATED: return "TCPA_E_DEACTIVATED"; case TCPA_E_DISABLED: return "TCPA_E_DISABLED"; case TCPA_E_DISABLED_CMD: return "TCPA_E_DISABLED_CMD"; case TCPA_E_FAIL: return "TCPA_E_FAIL"; case TCPA_E_INACTIVE: return "TCPA_E_INACTIVE"; case TCPA_E_INSTALL_DISABLED: return "TCPA_E_INSTALL_DISABLED"; case TCPA_E_INVALID_KEYHANDLE: return "TCPA_E_INVALID_KEYHANDLE"; case TCPA_E_KEYNOTFOUND: return "TCPA_E_KEYNOTFOUND"; case TCPA_E_NEED_SELFTEST: return "TCPA_E_NEED_SELFTEST"; case TCPA_E_MIGRATEFAIL: return "TCPA_E_MIGRATEFAIL"; case TCPA_E_NO_PCR_INFO: return "TCPA_E_NO_PCR_INFO"; case TCPA_E_NOSPACE: return "TCPA_E_NOSPACE"; case TCPA_E_NOSRK: return "TCPA_E_NOSRK"; case TCPA_E_NOTSEALED_BLOB: return "TCPA_E_NOTSEALED_BLOB"; case TCPA_E_OWNER_SET: return "TCPA_E_OWNER_SET"; case TCPA_E_RESOURCES: return "TCPA_E_RESOURCES"; case TCPA_E_SHORTRANDOM: return "TCPA_E_SHORTRANDOM"; case TCPA_E_SIZE: return "TCPA_E_SIZE"; case TCPA_E_WRONGPCRVAL: return "TCPA_E_WRONGPCRVAL"; case TCPA_E_BAD_PARAM_SIZE: return "TCPA_E_BAD_PARAM_SIZE"; case TCPA_E_SHA_THREAD: return "TCPA_E_SHA_THREAD"; case TCPA_E_SHA_ERROR: return "TCPA_E_SHA_ERROR"; case TCPA_E_FAILEDSELFTEST: return "TCPA_E_FAILEDSELFTEST"; case TCPA_E_AUTH2FAIL: return "TCPA_E_AUTH2FAIL"; case TCPA_E_BADTAG: return "TCPA_E_BADTAG"; case TCPA_E_IOERROR: return "TCPA_E_IOERROR"; case TCPA_E_ENCRYPT_ERROR: return "TCPA_E_ENCRYPT_ERROR"; case TCPA_E_DECRYPT_ERROR: return "TCPA_E_DECRYPT_ERROR"; case TCPA_E_INVALID_AUTHHANDLE: return "TCPA_E_INVALID_AUTHHANDLE"; case TCPA_E_NO_ENDORSEMENT: return "TCPA_E_NO_ENDORSEMENT"; case TCPA_E_INVALID_KEYUSAGE: return "TCPA_E_INVALID_KEYUSAGE"; case TCPA_E_WRONG_ENTITYTYPE: return "TCPA_E_WRONG_ENTITYTYPE"; case TCPA_E_INVALID_POSTINIT: return "TCPA_E_INVALID_POSTINIT"; case TCPA_E_INAPPROPRIATE_SIG: return "TCPA_E_INAPPROPRIATE_SIG"; case TCPA_E_BAD_KEY_PROPERTY: return "TCPA_E_BAD_KEY_PROPERTY"; case TCPA_E_BAD_MIGRATION: return "TCPA_E_BAD_MIGRATION"; case TCPA_E_BAD_SCHEME: return "TCPA_E_BAD_SCHEME"; case TCPA_E_BAD_DATASIZE: return "TCPA_E_BAD_DATASIZE"; case TCPA_E_BAD_MODE: return "TCPA_E_BAD_MODE"; case TCPA_E_BAD_PRESENCE: return "TCPA_E_BAD_PRESENCE"; case TCPA_E_BAD_VERSION: return "TCPA_E_BAD_VERSION"; case TCPA_E_RETRY: return "TCPA_E_RETRY"; default: return "UNKNOWN TPM ERROR"; } } else if (TSS_ERROR_LAYER(r) == TSS_LAYER_TDDL) { switch (TSS_ERROR_CODE(r)) { case TSS_E_FAIL: return "TSS_E_FAIL"; case TSS_E_BAD_PARAMETER: return "TSS_E_BAD_PARAMETER"; case TSS_E_INTERNAL_ERROR: return "TSS_E_INTERNAL_ERROR"; case TSS_E_NOTIMPL: return "TSS_E_NOTIMPL"; case TSS_E_PS_KEY_NOTFOUND: return "TSS_E_PS_KEY_NOTFOUND"; case TSS_E_KEY_ALREADY_REGISTERED: return "TSS_E_KEY_ALREADY_REGISTERED"; case TSS_E_CANCELED: return "TSS_E_CANCELED"; case TSS_E_TIMEOUT: return "TSS_E_TIMEOUT"; case TSS_E_OUTOFMEMORY: return "TSS_E_OUTOFMEMORY"; case TSS_E_TPM_UNEXPECTED: return "TSS_E_TPM_UNEXPECTED"; case TSS_E_COMM_FAILURE: return "TSS_E_COMM_FAILURE"; case TSS_E_TPM_UNSUPPORTED_FEATURE: return "TSS_E_TPM_UNSUPPORTED_FEATURE"; case TDDL_E_COMPONENT_NOT_FOUND: return "TDDL_E_COMPONENT_NOT_FOUND"; case TDDL_E_ALREADY_OPENED: return "TDDL_E_ALREADY_OPENED"; case TDDL_E_BADTAG: return "TDDL_E_BADTAG"; case TDDL_E_INSUFFICIENT_BUFFER: return "TDDL_E_INSUFFICIENT_BUFFER"; case TDDL_E_COMMAND_COMPLETED: return "TDDL_E_COMMAND_COMPLETED"; case TDDL_E_ALREADY_CLOSED: return "TDDL_E_ALREADY_CLOSED"; case TDDL_E_IOERROR: return "TDDL_E_IOERROR"; default: return "UNKNOWN TDDL ERROR"; } } else if (TSS_ERROR_LAYER(r) == TSS_LAYER_TCS) { switch (TSS_ERROR_CODE(r)) { case TSS_E_FAIL: return "TSS_E_FAIL"; case TSS_E_BAD_PARAMETER: return "TSS_E_BAD_PARAMETER"; case TSS_E_INTERNAL_ERROR: return "TSS_E_INTERNAL_ERROR"; case TSS_E_NOTIMPL: return "TSS_E_NOTIMPL"; case TSS_E_PS_KEY_NOTFOUND: return "TSS_E_PS_KEY_NOTFOUND"; case TSS_E_KEY_ALREADY_REGISTERED: return "TSS_E_KEY_ALREADY_REGISTERED"; case TSS_E_CANCELED: return "TSS_E_CANCELED"; case TSS_E_TIMEOUT: return "TSS_E_TIMEOUT"; case TSS_E_OUTOFMEMORY: return "TSS_E_OUTOFMEMORY"; case TSS_E_TPM_UNEXPECTED: return "TSS_E_TPM_UNEXPECTED"; case TSS_E_COMM_FAILURE: return "TSS_E_COMM_FAILURE"; case TSS_E_TPM_UNSUPPORTED_FEATURE: return "TSS_E_TPM_UNSUPPORTED_FEATURE"; case TCS_E_KEY_MISMATCH: return "TCS_E_KEY_MISMATCH"; case TCS_E_KM_LOADFAILED: return "TCS_E_KM_LOADFAILED"; case TCS_E_KEY_CONTEXT_RELOAD: return "TCS_E_KEY_CONTEXT_RELOAD"; case TCS_E_INVALID_CONTEXTHANDLE: return "TCS_E_INVALID_CONTEXTHANDLE"; case TCS_E_INVALID_KEYHANDLE: return "TCS_E_INVALID_KEYHANDLE"; case TCS_E_INVALID_AUTHHANDLE: return "TCS_E_INVALID_AUTHHANDLE"; case TCS_E_INVALID_AUTHSESSION: return "TCS_E_INVALID_AUTHSESSION"; case TCS_E_INVALID_KEY: return "TCS_E_INVALID_KEY"; default: return "UNKNOWN TCS ERROR"; } } else { switch (TSS_ERROR_CODE(r)) { case TSS_E_FAIL: return "TSS_E_FAIL"; case TSS_E_BAD_PARAMETER: return "TSS_E_BAD_PARAMETER"; case TSS_E_INTERNAL_ERROR: return "TSS_E_INTERNAL_ERROR"; case TSS_E_NOTIMPL: return "TSS_E_NOTIMPL"; case TSS_E_PS_KEY_NOTFOUND: return "TSS_E_PS_KEY_NOTFOUND"; case TSS_E_KEY_ALREADY_REGISTERED: return "TSS_E_KEY_ALREADY_REGISTERED"; case TSS_E_CANCELED: return "TSS_E_CANCELED"; case TSS_E_TIMEOUT: return "TSS_E_TIMEOUT"; case TSS_E_OUTOFMEMORY: return "TSS_E_OUTOFMEMORY"; case TSS_E_TPM_UNEXPECTED: return "TSS_E_TPM_UNEXPECTED"; case TSS_E_COMM_FAILURE: return "TSS_E_COMM_FAILURE"; case TSS_E_TPM_UNSUPPORTED_FEATURE: return "TSS_E_TPM_UNSUPPORTED_FEATURE"; case TSS_E_INVALID_OBJECT_TYPE: return "TSS_E_INVALID_OBJECT_TYPE"; case TSS_E_INVALID_OBJECT_INITFLAG: return "TSS_E_INVALID_OBJECT_INITFLAG"; case TSS_E_INVALID_HANDLE: return "TSS_E_INVALID_HANDLE"; case TSS_E_NO_CONNECTION: return "TSS_E_NO_CONNECTION"; case TSS_E_CONNECTION_FAILED: return "TSS_E_CONNECTION_FAILED"; case TSS_E_CONNECTION_BROKEN: return "TSS_E_CONNECTION_BROKEN"; case TSS_E_HASH_INVALID_ALG: return "TSS_E_HASH_INVALID_ALG"; case TSS_E_HASH_INVALID_LENGTH: return "TSS_E_HASH_INVALID_LENGTH"; case TSS_E_HASH_NO_DATA: return "TSS_E_HASH_NO_DATA"; case TSS_E_SILENT_CONTEXT: return "TSS_E_SILENT_CONTEXT"; case TSS_E_INVALID_ATTRIB_FLAG: return "TSS_E_INVALID_ATTRIB_FLAG"; case TSS_E_INVALID_ATTRIB_SUBFLAG: return "TSS_E_INVALID_ATTRIB_SUBFLAG"; case TSS_E_INVALID_ATTRIB_DATA: return "TSS_E_INVALID_ATTRIB_DATA"; case TSS_E_NO_PCRS_SET: return "TSS_E_NO_PCRS_SET"; case TSS_E_KEY_NOT_LOADED: return "TSS_E_KEY_NOT_LOADED"; case TSS_E_KEY_NOT_SET: return "TSS_E_KEY_NOT_SET"; case TSS_E_VALIDATION_FAILED: return "TSS_E_VALIDATION_FAILED"; case TSS_E_TSP_AUTHREQUIRED: return "TSS_E_TSP_AUTHREQUIRED"; case TSS_E_TSP_AUTH2REQUIRED: return "TSS_E_TSP_AUTH2REQUIRED"; case TSS_E_TSP_AUTHFAIL: return "TSS_E_TSP_AUTHFAIL"; case TSS_E_TSP_AUTH2FAIL: return "TSS_E_TSP_AUTH2FAIL"; case TSS_E_KEY_NO_MIGRATION_POLICY: return "TSS_E_KEY_NO_MIGRATION_POLICY"; case TSS_E_POLICY_NO_SECRET: return "TSS_E_POLICY_NO_SECRET"; case TSS_E_INVALID_OBJ_ACCESS: return "TSS_E_INVALID_OBJ_ACCESS"; case TSS_E_INVALID_ENCSCHEME: return "TSS_E_INVALID_ENCSCHEME"; case TSS_E_INVALID_SIGSCHEME: return "TSS_E_INVALID_SIGSCHEME"; case TSS_E_ENC_INVALID_LENGTH: return "TSS_E_ENC_INVALID_LENGTH"; case TSS_E_ENC_NO_DATA: return "TSS_E_ENC_NO_DATA"; case TSS_E_ENC_INVALID_TYPE: return "TSS_E_ENC_INVALID_TYPE"; case TSS_E_INVALID_KEYUSAGE: return "TSS_E_INVALID_KEYUSAGE"; case TSS_E_VERIFICATION_FAILED: return "TSS_E_VERIFICATION_FAILED"; case TSS_E_HASH_NO_IDENTIFIER: return "TSS_E_HASH_NO_IDENTIFIER"; default: return "UNKNOWN TSS ERROR"; } } } trousers-0.3.15/src/tspi/tsp_aik.c0000664000175000017510000000737113663651711016330 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_ActivateTPMIdentity(TSS_HCONTEXT tspContext, TCS_KEY_HANDLE idKey, /* in */ UINT32 blobSize, /* in */ BYTE * blob, /* in */ TPM_AUTH * idKeyAuth, /* in, out */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * SymmetricKeySize, /* out */ BYTE ** SymmetricKey) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(idKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = idKey; handles = &handle; if ((result = obj_context_transport_execute(tspContext, TPM_ORD_ActivateIdentity, blobSize, blob, &pubKeyHash, &handlesLen, &handles, idKeyAuth, ownerAuth, &decLen, &dec))) return result; *SymmetricKeySize = decLen; *SymmetricKey = dec; return result; } TSS_RESULT Transport_MakeIdentity2(TSS_HCONTEXT tspContext, TCPA_ENCAUTH identityAuth, /* in */ TCPA_CHOSENID_HASH IDLabel_PrivCAHash, /* in */ UINT32 idKeyInfoSize, /* in */ BYTE * idKeyInfo, /* in */ TPM_AUTH * pSrkAuth, /* in, out */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * idKeySize, /* out */ BYTE ** idKey, /* out */ UINT32 * pcIdentityBindingSize, /* out */ BYTE ** prgbIdentityBinding) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 0, decLen, dataLen; BYTE *dec, *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TCPA_ENCAUTH) + sizeof(TCPA_CHOSENID_HASH) + idKeyInfoSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob(&offset, sizeof(TCPA_ENCAUTH), data, identityAuth.authdata); Trspi_LoadBlob(&offset, sizeof(TCPA_CHOSENID_HASH), data, IDLabel_PrivCAHash.digest); Trspi_LoadBlob(&offset, idKeyInfoSize, data, idKeyInfo); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_MakeIdentity, dataLen, data, NULL, &handlesLen, NULL, pSrkAuth, pOwnerAuth, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; UnloadBlob_TSS_KEY(&offset, dec, NULL); *idKeySize = offset; if ((*idKey = malloc(*idKeySize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *idKeySize); *idKeySize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_UnloadBlob(&offset, *idKeySize, dec, *idKey); Trspi_UnloadBlob_UINT32(&offset, pcIdentityBindingSize, dec); if ((*prgbIdentityBinding = malloc(*pcIdentityBindingSize)) == NULL) { free(dec); free(*idKey); *idKey = NULL; *idKeySize = 0; LogError("malloc of %u bytes failed", *pcIdentityBindingSize); *pcIdentityBindingSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *pcIdentityBindingSize, dec, *prgbIdentityBinding); free(dec); return result; } #endif trousers-0.3.15/src/tspi/tspi_pcr_comp12.c0000664000175000017510000000325013663651711017672 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_PcrComposite_SetPcrLocality(TSS_HPCRS hPcrComposite, /* in */ UINT32 LocalityValue) /* in */ { /* LocalityValue must be some combination of TPM_LOC_* values logically or'd together */ if (!LocalityValue || (LocalityValue & (~TSS_LOCALITY_ALL))) return TSPERR(TSS_E_BAD_PARAMETER); return obj_pcrs_set_locality(hPcrComposite, LocalityValue); } TSS_RESULT Tspi_PcrComposite_GetPcrLocality(TSS_HPCRS hPcrComposite, /* in */ UINT32* pLocalityValue) /* out */ { if (pLocalityValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); return obj_pcrs_get_locality(hPcrComposite, pLocalityValue); } TSS_RESULT Tspi_PcrComposite_GetCompositeHash(TSS_HPCRS hPcrComposite, /* in */ UINT32* pLen, /* out */ BYTE** ppbHashData) /* out */ { if (pLen == NULL || ppbHashData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); return obj_pcrs_get_digest_at_release(hPcrComposite, pLen, ppbHashData); } TSS_RESULT Tspi_PcrComposite_SelectPcrIndexEx(TSS_HPCRS hPcrComposite, /* in */ UINT32 ulPcrIndex, /* in */ UINT32 Direction) /* in */ { if (Direction != TSS_PCRS_DIRECTION_CREATION && Direction != TSS_PCRS_DIRECTION_RELEASE) return TSPERR(TSS_E_BAD_PARAMETER); return obj_pcrs_select_index_ex(hPcrComposite, Direction, ulPcrIndex); } trousers-0.3.15/src/tspi/tspi_transport.c0000664000175000017510000000671513663651711017772 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_Context_SetTransEncryptionKey(TSS_HCONTEXT hContext, /* in */ TSS_HKEY hIdentKey) /* in */ { if (!obj_is_rsakey(hIdentKey)) return TSPERR(TSS_E_INVALID_HANDLE); return obj_context_set_transport_key(hContext, hIdentKey); } TSS_RESULT Tspi_Context_CloseSignTransport(TSS_HCONTEXT hContext, /* in */ TSS_HKEY hSigningKey, /* in */ TSS_VALIDATION* pValidationData) /* in, out */ { TSS_RESULT result; TSS_HPOLICY hPolicy; TSS_BOOL usesAuth; UINT32 sigLen; BYTE *sig; UINT64 offset; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_SIGN_INFO signInfo; if (!obj_is_context(hContext)) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = obj_rsakey_get_policy(hSigningKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; if (pValidationData) { if (pValidationData->ulExternalDataLength != sizeof(TPM_NONCE)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(signInfo.replay.nonce, pValidationData->rgbExternalData, sizeof(TPM_NONCE)); } else { if ((result = get_local_random(hContext, FALSE, sizeof(TPM_NONCE), (BYTE **)&signInfo.replay.nonce))) return result; } /* the transport sessions properties are kept in the context object itself, so just pass * in what this function provides and let it call ReleaseTransportSigned */ if ((result = obj_context_transport_close(hContext, hSigningKey, hPolicy, usesAuth, &signInfo, &sigLen, &sig))) return result; /* inside obj_context_transport_close we set up all the fields of the sign info structure * other than the tag and 'fixed' */ signInfo.tag = TPM_TAG_SIGNINFO; signInfo.fixed[0] = 'T'; signInfo.fixed[1] = 'R'; signInfo.fixed[2] = 'A'; signInfo.fixed[3] = 'N'; /* hash the sign info struct for use in verifying the TPM's signature */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_SIGN_INFO(&hashCtx, &signInfo); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free(sig); return TSPERR(TSS_E_INTERNAL_ERROR); } offset = 0; if (pValidationData) { /* tag the returned allocated memory as alloc'd by the TSP */ if ((result = __tspi_add_mem_entry(hContext, sig))) { free(sig); return TSPERR(TSS_E_INTERNAL_ERROR); } pValidationData->rgbValidationData = sig; pValidationData->ulValidationDataLength = sigLen; /* passing a NULL blob here puts the exact size of TPM_SIGN_INFO into offset */ Trspi_LoadBlob_SIGN_INFO(&offset, NULL, &signInfo); pValidationData->rgbData = calloc_tspi(hContext, offset); if (pValidationData->rgbData == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", offset); free_tspi(hContext, pValidationData->rgbValidationData); pValidationData->rgbValidationData = NULL; pValidationData->ulValidationDataLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } pValidationData->ulDataLength = (UINT32)offset; offset = 0; Trspi_LoadBlob_SIGN_INFO(&offset, pValidationData->rgbData, &signInfo); } else result = __tspi_rsa_verify(hSigningKey, TSS_HASH_SHA1, sizeof(TPM_DIGEST), digest.digest, sigLen, sig); return result; } trousers-0.3.15/src/tspi/tsp_maint.c0000664000175000017510000001145613663651711016673 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_CreateMaintenanceArchive(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL generateRandom, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * archiveSize, /* out */ BYTE ** archive) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 0, decLen; BYTE *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_CreateMaintenanceArchive, sizeof(TSS_BOOL), (BYTE *)&generateRandom, NULL, &handlesLen, NULL, ownerAuth, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, randomSize, dec); if (*randomSize > 0) { if ((*random = malloc(*randomSize)) == NULL) { *randomSize = 0; free(dec); LogError("malloc of %u bytes failed", *randomSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *randomSize, dec, *random); } Trspi_UnloadBlob_UINT32(&offset, archiveSize, dec); if ((*archive = malloc(*archiveSize)) == NULL) { free(*random); *random = NULL; *randomSize = 0; free(dec); LogError("malloc of %u bytes failed", *archiveSize); *archiveSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *archiveSize, dec, *archive); free(dec); return result; } TSS_RESULT Transport_LoadMaintenanceArchive(TSS_HCONTEXT tspContext, /* in */ UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 0, decLen; BYTE *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_LoadMaintenanceArchive, dataInSize, dataIn, NULL, &handlesLen, NULL, ownerAuth, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, dataOutSize, dec); /* sacrifice 4 bytes */ *dataOut = &dec[offset]; return result; } TSS_RESULT Transport_KillMaintenanceFeature(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); return obj_context_transport_execute(tspContext, TPM_ORD_KillMaintenanceFeature, 0, NULL, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); } TSS_RESULT Transport_LoadManuMaintPub(TSS_HCONTEXT tspContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 PubKeySize, /* in */ BYTE * PubKey, /* in */ TCPA_DIGEST * checksum) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 0, dataLen, decLen; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TCPA_NONCE) + PubKeySize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob(&offset, TPM_SHA1_160_HASH_LEN, data, antiReplay.nonce); Trspi_LoadBlob(&offset, PubKeySize, data, PubKey); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_LoadManuMaintPub, dataLen, data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_DIGEST(&offset, dec, checksum); free(dec); return result; } TSS_RESULT Transport_ReadManuMaintPub(TSS_HCONTEXT tspContext, /* in */ TCPA_NONCE antiReplay, /* in */ TCPA_DIGEST * checksum) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 0, decLen; BYTE *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_ReadManuMaintPub, sizeof(TCPA_NONCE), antiReplay.nonce, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_DIGEST(&offset, dec, checksum); free(dec); return result; } #endif trousers-0.3.15/src/tspi/tspi_migration.c0000664000175000017510000002722613663651711017727 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_AuthorizeMigrationTicket(TSS_HTPM hTPM, /* in */ TSS_HKEY hMigrationKey, /* in */ TSS_MIGRATION_SCHEME migrationScheme, /* in */ UINT32 * pulMigTicketLength, /* out */ BYTE ** prgbMigTicket) /* out */ { UINT64 offset; TCPA_DIGEST digest; TCPA_RESULT result; TSS_HPOLICY hOwnerPolicy; UINT32 migrationKeySize; BYTE *migrationKeyBlob; TSS_KEY tssKey; BYTE pubKeyBlob[0x1000]; TPM_AUTH ownerAuth; UINT32 pubKeySize; TSS_HCONTEXT tspContext; UINT32 tpmMigrationScheme; Trspi_HashCtx hashCtx; if (pulMigTicketLength == NULL || prgbMigTicket == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; /* get the tpm Policy */ if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hOwnerPolicy))) return result; switch (migrationScheme) { case TSS_MS_MIGRATE: tpmMigrationScheme = TCPA_MS_MIGRATE; break; case TSS_MS_REWRAP: tpmMigrationScheme = TCPA_MS_REWRAP; break; case TSS_MS_MAINT: tpmMigrationScheme = TCPA_MS_MAINT; break; #ifdef TSS_BUILD_CMK case TSS_MS_RESTRICT_MIGRATE: tpmMigrationScheme = TPM_MS_RESTRICT_MIGRATE; break; case TSS_MS_RESTRICT_APPROVE_DOUBLE: tpmMigrationScheme = TPM_MS_RESTRICT_APPROVE_DOUBLE; break; #endif default: return TSPERR(TSS_E_BAD_PARAMETER); break; } /* Get the migration key blob */ if ((result = obj_rsakey_get_blob(hMigrationKey, &migrationKeySize, &migrationKeyBlob))) return result; /* First, turn the keyBlob into a TSS_KEY structure */ offset = 0; __tspi_memset(&tssKey, 0, sizeof(TSS_KEY)); if ((result = UnloadBlob_TSS_KEY(&offset, migrationKeyBlob, &tssKey))) { free_tspi(tspContext, migrationKeyBlob); return result; } free_tspi(tspContext, migrationKeyBlob); /* Then pull the _PUBKEY portion out of that struct into a blob */ offset = 0; Trspi_LoadBlob_KEY_PARMS(&offset, pubKeyBlob, &tssKey.algorithmParms); Trspi_LoadBlob_STORE_PUBKEY(&offset, pubKeyBlob, &tssKey.pubKey); pubKeySize = offset; free_key_refs(&tssKey); /* Auth */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_AuthorizeMigrationKey); result |= Trspi_Hash_UINT16(&hashCtx, tpmMigrationScheme); result |= Trspi_HashUpdate(&hashCtx, pubKeySize, pubKeyBlob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_AuthorizeMigrationKey, hOwnerPolicy, FALSE, &digest, &ownerAuth))) return result; /* Send command */ if ((result = TCS_API(tspContext)->AuthorizeMigrationKey(tspContext, migrationScheme, pubKeySize, pubKeyBlob, &ownerAuth, pulMigTicketLength, prgbMigTicket))) return result; /* Validate Auth */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_AuthorizeMigrationKey); result |= Trspi_HashUpdate(&hashCtx, *pulMigTicketLength, *prgbMigTicket); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { *pulMigTicketLength = 0; free(*prgbMigTicket); return result; } if ((result = obj_policy_validate_auth_oiap(hOwnerPolicy, &digest, &ownerAuth))) { *pulMigTicketLength = 0; free(*prgbMigTicket); return result; } if ((result = __tspi_add_mem_entry(tspContext, *prgbMigTicket))) { *pulMigTicketLength = 0; free(*prgbMigTicket); return result; } return TSS_SUCCESS; } TSS_RESULT Tspi_Key_CreateMigrationBlob(TSS_HKEY hKeyToMigrate, /* in */ TSS_HKEY hParentKey, /* in */ UINT32 ulMigTicketLength, /* in */ BYTE * rgbMigTicket, /* in */ UINT32 * pulRandomLength, /* out */ BYTE ** prgbRandom, /* out */ UINT32 * pulMigrationBlobLength, /* out */ BYTE ** prgbMigrationBlob) /* out */ { TPM_AUTH parentAuth, entityAuth; TPM_AUTH *pParentAuth; TCPA_RESULT result; UINT64 offset; TCPA_DIGEST digest; UINT32 keyToMigrateSize; BYTE *keyToMigrateBlob = NULL; TSS_HPOLICY hParentPolicy; TSS_HPOLICY hMigratePolicy; TCPA_MIGRATIONKEYAUTH migAuth; TSS_KEY tssKey; TCS_KEY_HANDLE parentHandle; TSS_BOOL parentUsesAuth; UINT32 randomSize; BYTE *random = NULL; UINT32 blobSize; BYTE *blob = NULL; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; __tspi_memset(&tssKey, 0, sizeof(TSS_KEY)); if (pulRandomLength == NULL || prgbRandom == NULL || rgbMigTicket == NULL || pulMigrationBlobLength == NULL || prgbMigrationBlob == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_rsakey(hKeyToMigrate)) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = obj_rsakey_get_tsp_context(hKeyToMigrate, &tspContext))) return result; if ((result = obj_rsakey_get_blob(hKeyToMigrate, &keyToMigrateSize, &keyToMigrateBlob))) goto done; if ((result = obj_rsakey_get_policy(hParentKey, TSS_POLICY_USAGE, &hParentPolicy, &parentUsesAuth))) goto done; if ((result = obj_rsakey_get_policy(hKeyToMigrate, TSS_POLICY_MIGRATION, &hMigratePolicy, NULL))) goto done; /* Parsing the migration scheme from the blob and key object */ __tspi_memset(&migAuth, 0, sizeof(TCPA_MIGRATIONKEYAUTH)); offset = 0; if ((result = Trspi_UnloadBlob_MIGRATIONKEYAUTH(&offset, rgbMigTicket, &migAuth))) goto done; /* free these now, since none are used below */ free(migAuth.migrationKey.algorithmParms.parms); migAuth.migrationKey.algorithmParms.parmSize = 0; free(migAuth.migrationKey.pubKey.key); migAuth.migrationKey.pubKey.keyLength = 0; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, keyToMigrateBlob, &tssKey))) goto done; /* Generate the Authorization data */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CreateMigrationBlob); result |= Trspi_Hash_UINT16(&hashCtx, migAuth.migrationScheme); result |= Trspi_HashUpdate(&hashCtx, ulMigTicketLength, rgbMigTicket); result |= Trspi_Hash_UINT32(&hashCtx, tssKey.encSize); result |= Trspi_HashUpdate(&hashCtx, tssKey.encSize, tssKey.encData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (parentUsesAuth) { if ((result = secret_PerformAuth_OIAP(hParentPolicy, TPM_ORD_CreateMigrationBlob, hParentPolicy, FALSE, &digest, &parentAuth))) goto done; pParentAuth = &parentAuth; } else { pParentAuth = NULL; } if ((result = secret_PerformAuth_OIAP(hKeyToMigrate, TPM_ORD_CreateMigrationBlob, hMigratePolicy, FALSE, &digest, &entityAuth))) goto done; if ((result = obj_rsakey_get_tcs_handle(hParentKey, &parentHandle))) goto done; if ((result = TCS_API(tspContext)->CreateMigrationBlob(tspContext, parentHandle, migAuth.migrationScheme, ulMigTicketLength, rgbMigTicket, tssKey.encSize, tssKey.encData, pParentAuth, &entityAuth, &randomSize, &random, &blobSize, &blob))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CreateMigrationBlob); result |= Trspi_Hash_UINT32(&hashCtx, randomSize); result |= Trspi_HashUpdate(&hashCtx, randomSize, random); result |= Trspi_Hash_UINT32(&hashCtx, blobSize); result |= Trspi_HashUpdate(&hashCtx, blobSize, blob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (parentUsesAuth) { if ((result = obj_policy_validate_auth_oiap(hParentPolicy, &digest, &parentAuth))) goto done; } if ((result = obj_policy_validate_auth_oiap(hMigratePolicy, &digest, &entityAuth))) goto done; free(tssKey.encData); tssKey.encSize = blobSize; tssKey.encData = blob; /* Set blob to null since it will now be freed during key ref freeing */ blob = NULL; offset = 0; LoadBlob_TSS_KEY(&offset, NULL, &tssKey); *pulMigrationBlobLength = offset; *prgbMigrationBlob = calloc_tspi(tspContext, *pulMigrationBlobLength); if (*prgbMigrationBlob == NULL) { LogError("malloc of %u bytes failed.", *pulMigrationBlobLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; LoadBlob_TSS_KEY(&offset, *prgbMigrationBlob, &tssKey); if (randomSize) { if ((result = __tspi_add_mem_entry(tspContext, random))) goto done; } *pulRandomLength = randomSize; *prgbRandom = random; done: if (result) free(random); free_tspi(tspContext, keyToMigrateBlob); free_key_refs(&tssKey); free(blob); return result; } TSS_RESULT Tspi_Key_ConvertMigrationBlob(TSS_HKEY hKeyToMigrate, /* in */ TSS_HKEY hParentKey, /* in */ UINT32 ulRandomLength, /* in */ BYTE * rgbRandom, /* in */ UINT32 ulMigrationBlobLength, /* in */ BYTE * rgbMigrationBlob) /* in */ { TCPA_RESULT result; TSS_KEY tssKey; UINT32 outDataSize; BYTE *outData = NULL; TCS_KEY_HANDLE parentHandle; TPM_AUTH parentAuth; TSS_HPOLICY hParentPolicy; TCPA_DIGEST digest; TSS_BOOL useAuth; TPM_AUTH *pParentAuth; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; UINT64 offset; __tspi_memset(&tssKey, 0, sizeof(TSS_KEY)); if ((result = obj_rsakey_get_tsp_context(hKeyToMigrate, &tspContext))) return result; if (!obj_is_rsakey(hParentKey)) return TSPERR(TSS_E_INVALID_HANDLE); /* Get the parent key handle */ if ((result = obj_rsakey_get_tcs_handle(hParentKey, &parentHandle))) return result; /* Get the policy */ if ((result = obj_rsakey_get_policy(hParentKey, TSS_POLICY_USAGE, &hParentPolicy, &useAuth))) return result; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, rgbMigrationBlob, &tssKey))) return result; /* Generate the authorization */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ConvertMigrationBlob); result |= Trspi_Hash_UINT32(&hashCtx, tssKey.encSize); result |= Trspi_HashUpdate(&hashCtx, tssKey.encSize, tssKey.encData); result |= Trspi_Hash_UINT32(&hashCtx, ulRandomLength); result |= Trspi_HashUpdate(&hashCtx, ulRandomLength, rgbRandom); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (useAuth) { if ((result = secret_PerformAuth_OIAP(hParentPolicy, TPM_ORD_ConvertMigrationBlob, hParentPolicy, FALSE, &digest, &parentAuth))) goto done; pParentAuth = &parentAuth; } else { pParentAuth = NULL; } if ((result = TCS_API(tspContext)->ConvertMigrationBlob(tspContext, parentHandle, tssKey.encSize, tssKey.encData, ulRandomLength, rgbRandom, pParentAuth, &outDataSize, &outData))) goto done; /* add validation */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ConvertMigrationBlob); result |= Trspi_Hash_UINT32(&hashCtx, outDataSize); result |= Trspi_HashUpdate(&hashCtx, outDataSize, outData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (useAuth) { if ((result = obj_policy_validate_auth_oiap(hParentPolicy, &digest, &parentAuth))) goto done; } /* Set the key object to the now migrated key */ if ((result = obj_rsakey_set_tcpakey(hKeyToMigrate, ulMigrationBlobLength, rgbMigrationBlob))) goto done; if ((result = obj_rsakey_set_privkey(hKeyToMigrate, TRUE, outDataSize, outData))) goto done; result = obj_rsakey_set_tcs_handle(hKeyToMigrate, 0); done: free_key_refs(&tssKey); free(outData); return result; } trousers-0.3.15/src/tspi/tspi_delegate.c0000664000175000017510000003365113663651711017507 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "obj.h" #include "tsp_delegate.h" #include "tsplog.h" TSS_RESULT Tspi_TPM_Delegate_AddFamily(TSS_HTPM hTpm, /* in, must not be NULL */ BYTE bLabel, /* in */ TSS_HDELFAMILY* phFamily) /* out */ { TPM_FAMILY_ID familyID = 0; UINT32 outDataSize; BYTE *outData = NULL; UINT64 offset; TSS_RESULT result; if (phFamily == NULL) return TSPERR(TSS_E_BAD_PARAMETER); *phFamily = NULL_HDELFAMILY; if ((result = do_delegate_manage(hTpm, familyID, TPM_FAMILY_CREATE, sizeof(bLabel), &bLabel, &outDataSize, &outData))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, &familyID, outData); /* Create or update the delfamily object */ if ((result = update_delfamily_object(hTpm, familyID))) goto done; obj_delfamily_find_by_familyid(hTpm, familyID, phFamily); if (*phFamily == NULL_HDELFAMILY) result = TSPERR(TSS_E_INTERNAL_ERROR); done: free(outData); return result; } TSS_RESULT Tspi_TPM_Delegate_GetFamily(TSS_HTPM hTpm, /* in, must not NULL */ UINT32 ulFamilyID, /* in */ TSS_HDELFAMILY* phFamily) /* out */ { TSS_RESULT result; if (phFamily == NULL) return TSPERR(TSS_E_BAD_PARAMETER); *phFamily = NULL_HDELFAMILY; /* Update the delfamily object */ if ((result = update_delfamily_object(hTpm, ulFamilyID))) return result; obj_delfamily_find_by_familyid(hTpm, ulFamilyID, phFamily); if (*phFamily == NULL_HDELFAMILY) result = TSPERR(TSS_E_BAD_PARAMETER); return result; } TSS_RESULT Tspi_TPM_Delegate_InvalidateFamily(TSS_HTPM hTpm, /* in, must not be NULL */ TSS_HDELFAMILY hFamily) /* in */ { TPM_FAMILY_ID familyID; UINT32 outDataSize; BYTE *outData = NULL; TSS_RESULT result; if ((result = obj_delfamily_get_familyid(hFamily, &familyID))) return result; if ((result = do_delegate_manage(hTpm, familyID, TPM_FAMILY_INVALIDATE, 0, NULL, &outDataSize, &outData))) return result; /* Delete the delfamily object */ result = obj_delfamily_remove(hFamily, hTpm); free(outData); return result; } TSS_RESULT Tspi_TPM_Delegate_CreateDelegation(TSS_HOBJECT hObject, /* in */ BYTE bLabel, /* in */ UINT32 ulFlags, /* in */ TSS_HPCRS hPcrs, /* in */ TSS_HDELFAMILY hFamily, /* in */ TSS_HPOLICY hDelegation) /* in, out */ { TSS_RESULT result; if (obj_is_tpm(hObject)) { if ((result = create_owner_delegation(hObject, bLabel, ulFlags, hPcrs, hFamily, hDelegation))) return result; } else if (obj_is_rsakey(hObject)) { if ((result = create_key_delegation(hObject, bLabel, ulFlags, hPcrs, hFamily, hDelegation))) return result; } else return TSPERR(TSS_E_INVALID_HANDLE); return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_Delegate_CacheOwnerDelegation(TSS_HTPM hTpm, /* in */ TSS_HPOLICY hDelegation, /* in */ UINT32 ulIndex, /* in */ UINT32 ulFlags) /* in */ { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; UINT32 blobSize; BYTE *blob = NULL; UINT32 secretMode = TSS_SECRET_MODE_NONE; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; TPM_AUTH ownerAuth, *pAuth; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((result = obj_tpm_get_policy(hTpm, TSS_POLICY_USAGE, &hPolicy))) return result; if ((result = obj_policy_get_delegation_blob(hDelegation, TSS_DELEGATIONTYPE_OWNER, &blobSize, &blob))) return result; if (ulFlags & ~TSS_DELEGATE_CACHEOWNERDELEGATION_OVERWRITEEXISTING) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } if ((ulFlags & TSS_DELEGATE_CACHEOWNERDELEGATION_OVERWRITEEXISTING) == 0) { TPM_DELEGATE_PUBLIC public; /* Verify there is nothing occupying the specified row */ result = get_delegate_index(hContext, ulIndex, &public); if (result == TSS_SUCCESS) { free(public.pcrInfo.pcrSelection.pcrSelect); result = TSPERR(TSS_E_DELFAMILY_ROWEXISTS); goto done; } } if (hPolicy != NULL_HPOLICY) { if ((result = obj_policy_get_mode(hPolicy, &secretMode))) goto done; } if (secretMode != TSS_SECRET_MODE_NONE) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_LoadOwnerDelegation); result |= Trspi_Hash_UINT32(&hashCtx, ulIndex); result |= Trspi_Hash_UINT32(&hashCtx, blobSize); result |= Trspi_HashUpdate(&hashCtx, blobSize, blob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; pAuth = &ownerAuth; if ((result = secret_PerformAuth_OIAP(hTpm, TPM_ORD_Delegate_LoadOwnerDelegation, hPolicy, FALSE, &digest, pAuth))) goto done; } else pAuth = NULL; if ((result = TCS_API(hContext)->Delegate_LoadOwnerDelegation(hContext, ulIndex, blobSize, blob, pAuth))) goto done; if (pAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_LoadOwnerDelegation); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) goto done; } result = obj_policy_set_delegation_index(hDelegation, ulIndex); done: free_tspi(hContext, blob); return result; } TSS_RESULT Tspi_TPM_Delegate_UpdateVerificationCount(TSS_HTPM hTpm, /* in */ TSS_HPOLICY hDelegation) /* in, out */ { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; UINT32 secretMode = TSS_SECRET_MODE_NONE; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; TPM_AUTH ownerAuth, *pAuth; TSS_BOOL indexSet; UINT32 inputSize; BYTE *input = NULL; UINT32 outputSize; BYTE *output = NULL; UINT64 offset; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((result = obj_tpm_get_policy(hTpm, TSS_POLICY_USAGE, &hPolicy))) return result; if (hPolicy != NULL_HPOLICY) { if ((result = obj_policy_get_mode(hPolicy, &secretMode))) goto done; } if ((result = obj_policy_is_delegation_index_set(hDelegation, &indexSet))) return result; if (indexSet) { UINT32 index; if ((result = obj_policy_get_delegation_index(hDelegation, &index))) return result; inputSize = sizeof(UINT32); input = calloc_tspi(hContext, inputSize); if (!input) { LogError("malloc of %zd bytes failed.", sizeof(UINT32)); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, index, input); } else { if ((result = obj_policy_get_delegation_blob(hDelegation, 0, &inputSize, &input))) return result; } if (secretMode != TSS_SECRET_MODE_NONE) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_UpdateVerification); result |= Trspi_Hash_UINT32(&hashCtx, inputSize); result |= Trspi_HashUpdate(&hashCtx, inputSize, input); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; pAuth = &ownerAuth; if ((result = secret_PerformAuth_OIAP(hTpm, TPM_ORD_Delegate_UpdateVerification, hPolicy, FALSE, &digest, pAuth))) goto done; } else pAuth = NULL; if ((result = TCS_API(hContext)->Delegate_UpdateVerificationCount(hContext, inputSize, input, pAuth, &outputSize, &output))) goto done; if (pAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_UpdateVerification); result |= Trspi_Hash_UINT32(&hashCtx, outputSize); result |= Trspi_HashUpdate(&hashCtx, outputSize, output); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) goto done; } result = obj_policy_set_delegation_blob(hDelegation, 0, outputSize, output); done: free_tspi(hContext, input); free(output); return result; } TSS_RESULT Tspi_TPM_Delegate_VerifyDelegation(TSS_HPOLICY hDelegation) /* in, out */ { TSS_HCONTEXT hContext; UINT32 delegateSize; BYTE *delegate = NULL; TSS_RESULT result; if ((result = obj_policy_get_tsp_context(hDelegation, &hContext))) return result; if ((result = obj_policy_get_delegation_blob(hDelegation, 0, &delegateSize, &delegate))) return result; result = TCS_API(hContext)->Delegate_VerifyDelegation(hContext, delegateSize, delegate); free_tspi(hContext, delegate); return result; } TSS_RESULT Tspi_TPM_Delegate_ReadTables(TSS_HCONTEXT hContext, /* in */ UINT32* pulFamilyTableSize, /* out */ TSS_FAMILY_TABLE_ENTRY** ppFamilyTable, /* out */ UINT32* pulDelegateTableSize, /* out */ TSS_DELEGATION_TABLE_ENTRY** ppDelegateTable) /* out */ { UINT32 tpmFamilyTableSize, tpmDelegateTableSize; BYTE *tpmFamilyTable = NULL, *tpmDelegateTable = NULL; TPM_FAMILY_TABLE_ENTRY tpmFamilyEntry; TSS_FAMILY_TABLE_ENTRY tssFamilyEntry, *tssFamilyTable = NULL; UINT32 tssFamilyTableSize = 0; TPM_DELEGATE_PUBLIC tpmDelegatePublic; TSS_DELEGATION_TABLE_ENTRY tssDelegateEntry, *tssDelegateTable = NULL; UINT32 tssDelegateTableSize = 0; UINT32 tableIndex; UINT64 tpmOffset; UINT64 tssOffset; TSS_RESULT result; if (!pulFamilyTableSize || !ppFamilyTable || !pulDelegateTableSize || !ppDelegateTable) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(hContext)) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = TCS_API(hContext)->Delegate_ReadTable(hContext, &tpmFamilyTableSize, &tpmFamilyTable, &tpmDelegateTableSize, &tpmDelegateTable))) return result; if (tpmFamilyTableSize > 0) { /* Create the TSS_FAMILY_TABLE_ENTRY array */ for (tpmOffset = 0, tssOffset = 0; tpmOffset < tpmFamilyTableSize;) { Trspi_UnloadBlob_TPM_FAMILY_TABLE_ENTRY(&tpmOffset, tpmFamilyTable, &tpmFamilyEntry); /* No pointers in the family table entries, so no assignments required before doing LoadBlob */ Trspi_LoadBlob_TSS_FAMILY_TABLE_ENTRY(&tssOffset, NULL, &tssFamilyEntry); } if ((tssFamilyTable = calloc_tspi(hContext, tssOffset)) == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", tssOffset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } for (tpmOffset = 0, tssOffset = 0; tpmOffset < tpmFamilyTableSize; tssFamilyTableSize++) { Trspi_UnloadBlob_TPM_FAMILY_TABLE_ENTRY(&tpmOffset, tpmFamilyTable, &tpmFamilyEntry); tssFamilyEntry.familyID = tpmFamilyEntry.familyID; tssFamilyEntry.label = tpmFamilyEntry.label.label; tssFamilyEntry.verificationCount = tpmFamilyEntry.verificationCount; tssFamilyEntry.enabled = (tpmFamilyEntry.flags & TPM_FAMFLAG_ENABLE) ? TRUE : FALSE; tssFamilyEntry.locked = (tpmFamilyEntry.flags & TPM_FAMFLAG_DELEGATE_ADMIN_LOCK) ? TRUE : FALSE; Trspi_LoadBlob_TSS_FAMILY_TABLE_ENTRY(&tssOffset, (BYTE *)tssFamilyTable, &tssFamilyEntry); } } if (tpmDelegateTableSize > 0) { /* Create the TSS_DELEGATION_TABLE_ENTRY array */ for (tpmOffset = 0, tssOffset = 0; tpmOffset < tpmDelegateTableSize;) { Trspi_UnloadBlob_UINT32(&tpmOffset, &tableIndex, tpmDelegateTable); if ((result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(&tpmOffset, tpmDelegateTable, &tpmDelegatePublic))) { free_tspi(hContext, tssFamilyTable); goto done; } /* Some pointers in the delegate table entries, so do some assignments before doing LoadBlob */ tssDelegateEntry.pcrInfo.sizeOfSelect = tpmDelegatePublic.pcrInfo.pcrSelection.sizeOfSelect; tssDelegateEntry.pcrInfo.selection = tpmDelegatePublic.pcrInfo.pcrSelection.pcrSelect; tssDelegateEntry.pcrInfo.sizeOfDigestAtRelease = sizeof(tpmDelegatePublic.pcrInfo.digestAtRelease.digest); tssDelegateEntry.pcrInfo.digestAtRelease = tpmDelegatePublic.pcrInfo.digestAtRelease.digest; Trspi_LoadBlob_TSS_DELEGATION_TABLE_ENTRY(&tssOffset, NULL, &tssDelegateEntry); free(tpmDelegatePublic.pcrInfo.pcrSelection.pcrSelect); } if ((tssDelegateTable = calloc_tspi(hContext, tssOffset)) == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", tssOffset); free_tspi(hContext, tssFamilyTable); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } for (tpmOffset = 0, tssOffset = 0; tpmOffset < tpmDelegateTableSize; tssDelegateTableSize++) { Trspi_UnloadBlob_UINT32(&tpmOffset, &tableIndex, tpmDelegateTable); if ((result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(&tpmOffset, tpmDelegateTable, &tpmDelegatePublic))) { free_tspi(hContext, tssFamilyTable); free_tspi(hContext, tssDelegateTable); goto done; } tssDelegateEntry.tableIndex = tableIndex; tssDelegateEntry.label = tpmDelegatePublic.label.label; tssDelegateEntry.pcrInfo.sizeOfSelect = tpmDelegatePublic.pcrInfo.pcrSelection.sizeOfSelect; tssDelegateEntry.pcrInfo.selection = tpmDelegatePublic.pcrInfo.pcrSelection.pcrSelect; tssDelegateEntry.pcrInfo.localityAtRelease = tpmDelegatePublic.pcrInfo.localityAtRelease; tssDelegateEntry.pcrInfo.sizeOfDigestAtRelease = sizeof(tpmDelegatePublic.pcrInfo.digestAtRelease.digest); tssDelegateEntry.pcrInfo.digestAtRelease = tpmDelegatePublic.pcrInfo.digestAtRelease.digest; tssDelegateEntry.per1 = tpmDelegatePublic.permissions.per1; tssDelegateEntry.per2 = tpmDelegatePublic.permissions.per2; tssDelegateEntry.familyID = tpmDelegatePublic.familyID; tssDelegateEntry.verificationCount = tpmDelegatePublic.verificationCount; Trspi_LoadBlob_TSS_DELEGATION_TABLE_ENTRY(&tssOffset, (BYTE *)tssDelegateTable, &tssDelegateEntry); free(tpmDelegatePublic.pcrInfo.pcrSelection.pcrSelect); } } *ppFamilyTable = tssFamilyTable; *pulFamilyTableSize = tssFamilyTableSize; *ppDelegateTable = tssDelegateTable; *pulDelegateTableSize = tssDelegateTableSize; done: free(tpmFamilyTable); free(tpmDelegateTable); return result; } trousers-0.3.15/src/tspi/tsp_changeauth.c0000664000175000017510000003266513663651711017677 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "authsess.h" TSS_RESULT Trspi_UnloadBlob_STORED_DATA(UINT64 *offset, BYTE *blob, TCPA_STORED_DATA *data) { Trspi_UnloadBlob_TCPA_VERSION(offset, blob, &data->ver); Trspi_UnloadBlob_UINT32(offset, &data->sealInfoSize, blob); if (data->sealInfoSize > 0) { data->sealInfo = malloc(data->sealInfoSize); if (data->sealInfo == NULL) { LogError("malloc of %d bytes failed.", data->sealInfoSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, data->sealInfoSize, blob, data->sealInfo); } else { data->sealInfo = NULL; } Trspi_UnloadBlob_UINT32(offset, &data->encDataSize, blob); if (data->encDataSize > 0) { data->encData = malloc(data->encDataSize); if (data->encData == NULL) { LogError("malloc of %d bytes failed.", data->encDataSize); free(data->sealInfo); data->sealInfo = NULL; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, data->encDataSize, blob, data->encData); } else { data->encData = NULL; } return TSS_SUCCESS; } void Trspi_LoadBlob_STORED_DATA(UINT64 *offset, BYTE *blob, TCPA_STORED_DATA *data) { Trspi_LoadBlob_TCPA_VERSION(offset, blob, data->ver); Trspi_LoadBlob_UINT32(offset, data->sealInfoSize, blob); Trspi_LoadBlob(offset, data->sealInfoSize, blob, data->sealInfo); Trspi_LoadBlob_UINT32(offset, data->encDataSize, blob); Trspi_LoadBlob(offset, data->encDataSize, blob, data->encData); } TSS_RESULT changeauth_owner(TSS_HCONTEXT tspContext, TSS_HOBJECT hObjectToChange, TSS_HOBJECT hParentObject, TSS_HPOLICY hNewPolicy) { TPM_DIGEST digest; TSS_RESULT result; Trspi_HashCtx hashCtx; struct authsess *xsap = NULL; if ((result = authsess_xsap_init(tspContext, hObjectToChange, hNewPolicy, TSS_AUTH_POLICY_REQUIRED, TPM_ORD_ChangeAuthOwner, TPM_ET_OWNER, &xsap))) return result; /* calculate auth data */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthOwner); result |= Trspi_Hash_UINT16(&hashCtx, TCPA_PID_ADCP); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_Hash_UINT16(&hashCtx, TCPA_ET_OWNER); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; if ((result = TCS_API(tspContext)->ChangeAuthOwner(tspContext, TCPA_PID_ADCP, &xsap->encAuthUse, TPM_ET_OWNER, xsap->pAuth))) goto error; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthOwner); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; result = authsess_xsap_verify(xsap, &digest); error: authsess_free(xsap); return result; } TSS_RESULT changeauth_srk(TSS_HCONTEXT tspContext, TSS_HOBJECT hObjectToChange, TSS_HOBJECT hParentObject, TSS_HPOLICY hNewPolicy) { TPM_DIGEST digest; TSS_RESULT result; Trspi_HashCtx hashCtx; struct authsess *xsap = NULL; if ((result = authsess_xsap_init(tspContext, hParentObject, hNewPolicy, TSS_AUTH_POLICY_REQUIRED, TPM_ORD_ChangeAuthOwner, TPM_ET_OWNER, &xsap))) return result; /* calculate auth data */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthOwner); result |= Trspi_Hash_UINT16(&hashCtx, TCPA_PID_ADCP); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_Hash_UINT16(&hashCtx, TCPA_ET_SRK); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; if ((result = TCS_API(tspContext)->ChangeAuthOwner(tspContext, TCPA_PID_ADCP, &xsap->encAuthUse, TPM_ET_SRK, xsap->pAuth))) goto error; /* Validate the Auths */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuthOwner); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; result = authsess_xsap_verify(xsap, &digest); error: authsess_free(xsap); return result; } TSS_RESULT changeauth_encdata(TSS_HCONTEXT tspContext, TSS_HOBJECT hObjectToChange, TSS_HOBJECT hParentObject, TSS_HPOLICY hNewPolicy) { TPM_DIGEST digest; TSS_RESULT result; Trspi_HashCtx hashCtx; TSS_HPOLICY hPolicy; TCS_KEY_HANDLE keyHandle; UINT64 offset; struct authsess *xsap = NULL; TPM_STORED_DATA storedData; UINT32 dataBlobLength, newEncSize; BYTE *dataBlob, *newEncData; TPM_AUTH auth2; /* get the secret for the parent */ if ((result = obj_encdata_get_policy(hObjectToChange, TSS_POLICY_USAGE, &hPolicy))) return result; /* get the data Object */ if ((result = obj_encdata_get_data(hObjectToChange, &dataBlobLength, &dataBlob))) return result; offset = 0; if ((result = Trspi_UnloadBlob_STORED_DATA(&offset, dataBlob, &storedData))) return result; if ((result = obj_rsakey_get_tcs_handle(hParentObject, &keyHandle))) return result; if ((result = authsess_xsap_init(tspContext, hParentObject, hNewPolicy, TSS_AUTH_POLICY_REQUIRED, TPM_ORD_ChangeAuth, TPM_ET_KEYHANDLE, &xsap))) return result; /* caluculate auth data */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuth); result |= Trspi_Hash_UINT16(&hashCtx, TPM_PID_ADCP); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_Hash_UINT16(&hashCtx, TPM_ET_DATA); result |= Trspi_Hash_UINT32(&hashCtx, storedData.encDataSize); result |= Trspi_HashUpdate(&hashCtx, storedData.encDataSize, storedData.encData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; if ((result = secret_PerformAuth_OIAP(hObjectToChange, TPM_ORD_ChangeAuth, hPolicy, FALSE, &digest, &auth2))) goto error; if ((result = TCS_API(tspContext)->ChangeAuth(tspContext, keyHandle, TPM_PID_ADCP, &xsap->encAuthUse, TPM_ET_DATA, storedData.encDataSize, storedData.encData, xsap->pAuth, &auth2, &newEncSize, &newEncData))) goto error; /* Validate the Auths */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuth); result |= Trspi_Hash_UINT32(&hashCtx, newEncSize); result |= Trspi_HashUpdate(&hashCtx, newEncSize, newEncData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_verify(xsap, &digest))) goto error; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth2))) goto error; memcpy(storedData.encData, newEncData, newEncSize); free(newEncData); storedData.encDataSize = newEncSize; offset = 0; Trspi_LoadBlob_STORED_DATA(&offset, dataBlob, &storedData); result = obj_encdata_set_data(hObjectToChange, offset, dataBlob); error: authsess_free(xsap); free(storedData.sealInfo); free(storedData.encData); return result; } TSS_RESULT changeauth_key(TSS_HCONTEXT tspContext, TSS_HOBJECT hObjectToChange, TSS_HOBJECT hParentObject, TSS_HPOLICY hNewPolicy) { TPM_DIGEST digest; Trspi_HashCtx hashCtx; TSS_RESULT result; TSS_KEY keyToChange; TCS_KEY_HANDLE keyHandle; struct authsess *xsap = NULL; UINT32 objectLength; TSS_HPOLICY hPolicy; BYTE *keyBlob; UINT32 newEncSize; BYTE *newEncData; TPM_AUTH auth2; UINT64 offset; if ((result = obj_rsakey_get_blob(hObjectToChange, &objectLength, &keyBlob))) return result; offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, keyBlob, &keyToChange))) { LogDebug("UnloadBlob_TSS_KEY failed. " "result=0x%x", result); return result; } if ((result = obj_rsakey_get_policy(hObjectToChange, TSS_POLICY_USAGE, &hPolicy, NULL))) return result; if ((result = obj_rsakey_get_tcs_handle(hParentObject, &keyHandle))) return result; if ((result = authsess_xsap_init(tspContext, hParentObject, hNewPolicy, TSS_AUTH_POLICY_REQUIRED, TPM_ORD_ChangeAuth, keyHandle == TPM_KEYHND_SRK ? TPM_ET_SRK : TPM_ET_KEYHANDLE, &xsap))) return result; /* caluculate auth data */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuth); result |= Trspi_Hash_UINT16(&hashCtx, TCPA_PID_ADCP); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_Hash_UINT16(&hashCtx, TCPA_ET_KEY); result |= Trspi_Hash_UINT32(&hashCtx, keyToChange.encSize); result |= Trspi_HashUpdate(&hashCtx, keyToChange.encSize, keyToChange.encData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; if ((result = secret_PerformAuth_OIAP(hObjectToChange, TPM_ORD_ChangeAuth, hPolicy, FALSE, &digest, &auth2))) goto error; if ((result = TCS_API(tspContext)->ChangeAuth(tspContext, keyHandle, TPM_PID_ADCP, &xsap->encAuthUse, TPM_ET_KEY, keyToChange.encSize, keyToChange.encData, xsap->pAuth, &auth2, &newEncSize, &newEncData))) goto error; /* Validate the Auths */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ChangeAuth); result |= Trspi_Hash_UINT32(&hashCtx, newEncSize); result |= Trspi_HashUpdate(&hashCtx, newEncSize, newEncData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_verify(xsap, &digest))) goto error; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth2))) return result; memcpy(keyToChange.encData, newEncData, newEncSize); free(newEncData); offset = 0; LoadBlob_TSS_KEY(&offset, keyBlob, &keyToChange); objectLength = offset; result = obj_rsakey_set_tcpakey(hObjectToChange, objectLength, keyBlob); error: authsess_free(xsap); return result; } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_ChangeAuth(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH *newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * ownerAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; UINT32 handlesLen, dataLen, decLen; TCS_HANDLE *handles, handle; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(parentHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = parentHandle; handles = &handle; dataLen = sizeof(TCPA_PROTOCOL_ID) + sizeof(TCPA_ENCAUTH) + sizeof(TCPA_ENTITY_TYPE) + sizeof(UINT32) + encDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT16(&offset, protocolID, data); Trspi_LoadBlob(&offset, sizeof(TCPA_ENCAUTH), data, newAuth->authdata); Trspi_LoadBlob_UINT16(&offset, entityType, data); Trspi_LoadBlob_UINT32(&offset, encDataSize, data); Trspi_LoadBlob(&offset, encDataSize, data, encData); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_ChangeAuth, dataLen, data, &pubKeyHash, &handlesLen, &handles, ownerAuth, entityAuth, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, outDataSize, dec); if ((*outData = malloc(*outDataSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *outDataSize); *outDataSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *outDataSize, dec, *outData); free(dec); return result; } TSS_RESULT Transport_ChangeAuthOwner(TSS_HCONTEXT tspContext, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH *newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; UINT64 offset; BYTE data[sizeof(TCPA_PROTOCOL_ID) + sizeof(TCPA_ENCAUTH) + sizeof(TCPA_ENTITY_TYPE)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT16(&offset, protocolID, data); Trspi_LoadBlob(&offset, sizeof(TCPA_ENCAUTH), data, newAuth->authdata); Trspi_LoadBlob_UINT16(&offset, entityType, data); return obj_context_transport_execute(tspContext, TPM_ORD_ChangeAuthOwner, sizeof(data), data, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); } #endif trousers-0.3.15/src/tspi/obj_nv.c0000664000175000017510000004560013663651711016150 0ustar deboradebora/* * The Initial Developer of the Original Code is Intel Corporation. * Portions created by Intel Corporation are Copyright (C) 2007 Intel Corporation. * All Rights Reserved. * * trousers - An open source TCG Software Stack * * Author: james.xu@intel.com Rossey.liu@intel.com * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT obj_nvstore_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_nvstore_obj *nvstore = calloc(1, sizeof(struct tr_nvstore_obj)); if (nvstore == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_nvstore_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } if ((result = obj_list_add(&nvstore_list, tspContext, 0, nvstore, phObject))) { free(nvstore); return result; } return TSS_SUCCESS; } TSS_BOOL obj_is_nvstore(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&nvstore_list, hObject))) { answer = TRUE; obj_list_put(&nvstore_list); } return answer; } void nvstore_free(void *data) { struct tr_nvstore_obj *nvstore = (struct tr_nvstore_obj *)data; free(nvstore); } TSS_RESULT obj_nvstore_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { TSS_RESULT result; if ((result = obj_list_remove(&nvstore_list, &nvstore_free, hObject, tspContext))) return result; return TSS_SUCCESS; } TSS_RESULT obj_nvstore_get_tsp_context(TSS_HNVSTORE hNvstore, TSS_HCONTEXT * tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&nvstore_list); return TSS_SUCCESS; } TSS_RESULT obj_nvstore_set_index(TSS_HNVSTORE hNvstore, UINT32 index) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; TSS_RESULT result=TSS_SUCCESS; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; nvstore->nvIndex = index; obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_get_index(TSS_HNVSTORE hNvstore, UINT32 * index) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; TSS_RESULT result=TSS_SUCCESS; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; *index = nvstore->nvIndex; obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_set_datasize(TSS_HNVSTORE hNvstore, UINT32 datasize) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; TSS_RESULT result=TSS_SUCCESS; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; nvstore->dataSize= datasize; obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_get_datasize(TSS_HNVSTORE hNvstore, UINT32 * datasize) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; TSS_RESULT result=TSS_SUCCESS; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; *datasize = nvstore->dataSize; obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_set_permission(TSS_HNVSTORE hNvstore, UINT32 permission) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; TSS_RESULT result=TSS_SUCCESS; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; nvstore->permission.attributes= permission; obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_get_permission_from_tpm(TSS_HNVSTORE hNvstore, UINT32 * permission) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE] = {0}; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; UINT16 pcrwrite_sizeOfSelect; TPM_NV_ATTRIBUTES nv_attributes_value; TSS_HCONTEXT tspContext; TSS_RESULT result; if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; offset = 0; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); nv_attributes_value.attributes = Decode_UINT32(nv_data_public + offset + sizeof(TPM_STRUCTURE_TAG)); *permission = nv_attributes_value.attributes; return result; } TSS_RESULT obj_nvstore_get_permission(TSS_HNVSTORE hNvstore, UINT32 * permission) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; TSS_RESULT result=TSS_SUCCESS; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; *permission = nvstore->permission.attributes; obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_set_policy(TSS_HNVSTORE hNvstore, TSS_HPOLICY hPolicy) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; UINT32 policyType; TSS_RESULT result = TSS_SUCCESS; if ((result = obj_policy_get_type(hPolicy, &policyType))) return result; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: nvstore->policy = hPolicy; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_get_policy(TSS_HNVSTORE hNvstore, UINT32 policyType, TSS_HPOLICY *phPolicy) { struct tsp_object *obj; struct tr_nvstore_obj *nvstore; TSS_RESULT result=TSS_SUCCESS; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); nvstore = (struct tr_nvstore_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: *phPolicy = nvstore->policy; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_get_datapublic(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE *nv_data_public) { struct tsp_object *obj; TSS_HCONTEXT hContext; TSS_HTPM hTpm; TSS_RESULT result; struct tr_nvstore_obj *nvstore; UINT32 uiResultLen; BYTE *pResult; UINT32 i; TPM_BOOL defined_index = FALSE; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); hContext = obj->tspContext; nvstore = (struct tr_nvstore_obj *)obj->data; if ((result = obj_tpm_get(hContext, &hTpm))) goto out; if ((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_LIST, 0, NULL, &uiResultLen, &pResult))) { goto out; } for (i = 0; i < uiResultLen/sizeof(UINT32); i++) { if (nvstore->nvIndex == Decode_UINT32(pResult + i * sizeof(UINT32))) { defined_index = TRUE; break; } } free_tspi(hContext, pResult); if (!defined_index) { result = TSPERR(TPM_E_BADINDEX); goto out; } if ((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_INDEX, sizeof(UINT32), (BYTE *)(&(nvstore->nvIndex)), &uiResultLen, &pResult))) { LogDebug("get the index capability error"); goto out; } if (uiResultLen > *size) { free_tspi(hContext, pResult); result = TSPERR(TSS_E_INTERNAL_ERROR); goto out; } *size = uiResultLen; memcpy(nv_data_public, pResult, uiResultLen); free_tspi(hContext, pResult); out: obj_list_put(&nvstore_list); return result; } TSS_RESULT obj_nvstore_get_readdigestatrelease(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; TSS_HCONTEXT tspContext; TSS_RESULT result; if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; *size = sizeof(TPM_COMPOSITE_HASH); *data = calloc_tspi(tspContext, *size); if (*data == NULL) { LogError("malloc of %u bytes failed.", *size); result = TSPERR(TSS_E_OUTOFMEMORY); return result; } offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION); memcpy(*data, nv_data_public + offset, sizeof(TPM_COMPOSITE_HASH)); return result; } TSS_RESULT obj_nvstore_get_readpcrselection(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; TSS_HCONTEXT tspContext; TSS_RESULT result; if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); *size = sizeof(UINT16) + pcrread_sizeOfSelect; *data = calloc_tspi(tspContext, *size); if (*data == NULL) { LogError("malloc of %u bytes failed.", *size); result = TSPERR(TSS_E_OUTOFMEMORY); return result; } memcpy(*data, nv_data_public + offset, *size); return result; } TSS_RESULT obj_nvstore_get_writedigestatrelease(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; TSS_HCONTEXT tspContext; TSS_RESULT result; if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; *size = sizeof(TPM_COMPOSITE_HASH); *data = calloc_tspi(tspContext, *size); if (*data == NULL) { LogError("malloc of %u bytes failed.", *size); result = TSPERR(TSS_E_OUTOFMEMORY); return result; } offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION); memcpy(*data, nv_data_public + offset, sizeof(TPM_COMPOSITE_HASH)); return result; } TSS_RESULT obj_nvstore_get_writepcrselection(TSS_HNVSTORE hNvstore, UINT32 *size, BYTE **data) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; UINT16 pcrwrite_sizeOfSelect; TSS_HCONTEXT tspContext; TSS_RESULT result; if((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset); *size = sizeof(UINT16) + pcrwrite_sizeOfSelect; *data = calloc_tspi(tspContext, *size); if (*data == NULL) { LogError("malloc of %u bytes failed.", *size); result = TSPERR(TSS_E_OUTOFMEMORY); return result; } memcpy(*data, nv_data_public + offset, *size); return result; } TSS_RESULT obj_nvstore_get_state_readstclear(TSS_HNVSTORE hNvstore, UINT32 * readstclear) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; UINT16 pcrwrite_sizeOfSelect; TPM_BOOL value; TSS_RESULT result; if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH) + sizeof(TPM_NV_ATTRIBUTES); value = *((TPM_BOOL *)(nv_data_public + offset)); *readstclear = value; return result; } TSS_RESULT obj_nvstore_get_state_writedefine(TSS_HNVSTORE hNvstore, UINT32 * writedefine) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; UINT16 pcrwrite_sizeOfSelect; TPM_BOOL value; TSS_RESULT result; if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH) + sizeof(TPM_NV_ATTRIBUTES) + sizeof(TPM_BOOL) + sizeof(TPM_BOOL); value = *((TPM_BOOL *)(nv_data_public + offset)); *writedefine = value; return result; } TSS_RESULT obj_nvstore_get_state_writestclear(TSS_HNVSTORE hNvstore, UINT32 * writestclear) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; UINT16 pcrwrite_sizeOfSelect; TPM_BOOL value; TSS_RESULT result; if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH) + sizeof(TPM_NV_ATTRIBUTES) + sizeof(TPM_BOOL); value = *((TPM_BOOL *)(nv_data_public + offset)); *writestclear = value; return result; } TSS_RESULT obj_nvstore_get_readlocalityatrelease(TSS_HNVSTORE hNvstore, UINT32 * readlocalityatrelease) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; TPM_LOCALITY_SELECTION locality_value; TSS_RESULT result; if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect; locality_value = *((TPM_LOCALITY_SELECTION *)(nv_data_public + offset)); *readlocalityatrelease = locality_value; return result; } TSS_RESULT obj_nvstore_get_writelocalityatrelease(TSS_HNVSTORE hNvstore, UINT32 * writelocalityatrelease) { BYTE nv_data_public[MAX_PUBLIC_DATA_SIZE]; UINT32 data_public_size = MAX_PUBLIC_DATA_SIZE; UINT32 offset; UINT16 pcrread_sizeOfSelect; UINT16 pcrwrite_sizeOfSelect; TPM_LOCALITY_SELECTION locality_value; TSS_RESULT result; if ((result = obj_nvstore_get_datapublic(hNvstore, &data_public_size, nv_data_public))) return result; offset = sizeof(TPM_STRUCTURE_TAG)+ sizeof(TPM_NV_INDEX); pcrread_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrread_sizeOfSelect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); pcrwrite_sizeOfSelect = Decode_UINT16(nv_data_public + offset); offset = offset + sizeof(UINT16) + pcrwrite_sizeOfSelect; locality_value = *((TPM_LOCALITY_SELECTION *)(nv_data_public + offset)); *writelocalityatrelease = locality_value; return result; } TSS_RESULT obj_nvstore_create_pcrshortinfo(TSS_HNVSTORE hNvstore, TSS_HPCRS hPcrComposite, UINT32 *size, BYTE **data) { struct tsp_object *obj; BYTE pdata[MAX_PUBLIC_DATA_SIZE]; UINT32 dataLen; UINT64 offset; TSS_HCONTEXT tspContext; TSS_RESULT result = TSS_SUCCESS; BYTE* ppbHashData; UINT32 i; BYTE digAtRelease[TPM_SHA1_160_HASH_LEN] = { 0, }; UINT32 tmp_locAtRelease; TPM_LOCALITY_SELECTION locAtRelease = TPM_LOC_ZERO | TPM_LOC_ONE | TPM_LOC_TWO | TPM_LOC_THREE| TPM_LOC_FOUR; BYTE tmp_pcr_select[3] = {0, 0, 0}; TCPA_PCR_SELECTION pcrSelect = { 3, tmp_pcr_select}; if ((obj = obj_list_get_obj(&nvstore_list, hNvstore)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); tspContext = obj->tspContext; if (hPcrComposite) { if ((result = obj_pcrs_get_selection(hPcrComposite, &dataLen, pdata))) { LogDebug("get_selection error from hReadPcrComposite"); goto out; } /* the index should not >= 24, so the sizeofselect should not be >3*/ if (dataLen - sizeof(UINT16) > 3) { result = TSPERR(TSS_E_BAD_PARAMETER); goto out; } offset = 0; Trspi_UnloadBlob_PCR_SELECTION(&offset, pdata, &pcrSelect); if (pcrSelect.sizeOfSelect != 0) { if ((result = obj_pcrs_get_digest_at_release(hPcrComposite, &dataLen, &ppbHashData))) { LogDebug("get_composite error from hReadPcrComposite"); goto out; } memcpy(digAtRelease, ppbHashData, dataLen); free_tspi(tspContext, ppbHashData); } else { pcrSelect.sizeOfSelect = 3; pcrSelect.pcrSelect = tmp_pcr_select; } if (pcrSelect.sizeOfSelect < 3) { for (i = 0; i < pcrSelect.sizeOfSelect; i++) { tmp_pcr_select[i] = pcrSelect.pcrSelect[i]; } pcrSelect.sizeOfSelect = 3; pcrSelect.pcrSelect = tmp_pcr_select; } if ((result = obj_pcrs_get_locality(hPcrComposite, &tmp_locAtRelease))) goto out; locAtRelease = (TPM_LOCALITY_SELECTION)(tmp_locAtRelease & TSS_LOCALITY_MASK); } *size = sizeof(UINT16) + 3 + sizeof(TPM_LOCALITY_SELECTION) + TPM_SHA1_160_HASH_LEN; *data = calloc_tspi(tspContext, *size); if (*data == NULL) { LogError("malloc of %u bytes failed.", *size); result = TSPERR(TSS_E_OUTOFMEMORY); goto out; } offset = 0; Trspi_LoadBlob_PCR_SELECTION(&offset, *data, &pcrSelect); Trspi_LoadBlob_BYTE(&offset, locAtRelease, *data); Trspi_LoadBlob(&offset, TPM_SHA1_160_HASH_LEN, *data, digAtRelease); out: obj_list_put(&nvstore_list); return result; } trousers-0.3.15/src/tspi/obj.c0000664000175000017510000001513013663651711015440 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #include "obj.h" UINT32 nextObjectHandle = 0xC0000000; MUTEX_DECLARE_INIT(handle_lock); TPM_LIST_DECLARE; CONTEXT_LIST_DECLARE; HASH_LIST_DECLARE; PCRS_LIST_DECLARE; POLICY_LIST_DECLARE; RSAKEY_LIST_DECLARE; ENCDATA_LIST_DECLARE; DAACRED_LIST_DECLARE; DAAARAKEY_LIST_DECLARE; DAAISSUERKEY_LIST_DECLARE; NVSTORE_LIST_DECLARE; DELFAMILY_LIST_DECLARE; MIGDATA_LIST_DECLARE; static void tspi_list_init(struct obj_list *list) { list->head = NULL; MUTEX_INIT(list->lock); } void __tspi_obj_list_init() { TPM_LIST_INIT(); CONTEXT_LIST_INIT(); HASH_LIST_INIT(); PCRS_LIST_INIT(); POLICY_LIST_INIT(); RSAKEY_LIST_INIT(); ENCDATA_LIST_INIT(); DAACRED_LIST_INIT(); DAAARAKEY_LIST_INIT(); DAAISSUERKEY_LIST_INIT(); NVSTORE_LIST_INIT(); DELFAMILY_LIST_INIT(); MIGDATA_LIST_INIT(); } TSS_HOBJECT obj_get_next_handle() { MUTEX_LOCK(handle_lock); /* return any object handle except NULL_HOBJECT */ do { nextObjectHandle++; } while (nextObjectHandle == NULL_HOBJECT); MUTEX_UNLOCK(handle_lock); return nextObjectHandle; } /* search through the provided list for an object with handle matching * @handle. If found, return a pointer to the object with the list * locked, else return NULL. To release the lock, caller should * call obj_list_put() after manipulating the object. */ struct tsp_object * obj_list_get_obj(struct obj_list *list, UINT32 handle) { struct tsp_object *obj; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { if (obj->handle == handle) break; } if (obj == NULL) MUTEX_UNLOCK(list->lock); return obj; } /* search through the provided list for an object with TSP context * matching @tspContext. If found, return a pointer to the object * with the list locked, else return NULL. To release the lock, * caller should call obj_list_put() after manipulating the object. */ struct tsp_object * obj_list_get_tspcontext(struct obj_list *list, UINT32 tspContext) { struct tsp_object *obj; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { if (obj->tspContext == tspContext) break; } return obj; } /* release a list whose handle was returned by obj_list_get_obj() */ void obj_list_put(struct obj_list *list) { MUTEX_UNLOCK(list->lock); } TSS_RESULT obj_list_add(struct obj_list *list, UINT32 tsp_context, TSS_FLAG flags, void *data, TSS_HOBJECT *phObject) { struct tsp_object *new_obj, *tmp; new_obj = calloc(1, sizeof(struct tsp_object)); if (new_obj == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tsp_object)); return TSPERR(TSS_E_OUTOFMEMORY); } new_obj->handle = obj_get_next_handle(); new_obj->flags = flags; new_obj->data = data; if (list == &context_list) new_obj->tspContext = new_obj->handle; else new_obj->tspContext = tsp_context; MUTEX_LOCK(list->lock); if (list->head == NULL) { list->head = new_obj; } else { tmp = list->head; list->head = new_obj; new_obj->next = tmp; } MUTEX_UNLOCK(list->lock); *phObject = new_obj->handle; return TSS_SUCCESS; } TSS_RESULT obj_list_remove(struct obj_list *list, void (*freeFcn)(void *), TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { struct tsp_object *obj, *prev = NULL; MUTEX_LOCK(list->lock); for (obj = list->head; obj; prev = obj, obj = obj->next) { if (obj->handle == hObject) { /* validate tspContext */ if (obj->tspContext != tspContext) break; (*freeFcn)(obj->data); if (prev) prev->next = obj->next; else list->head = obj->next; free(obj); MUTEX_UNLOCK(list->lock); return TSS_SUCCESS; } } MUTEX_UNLOCK(list->lock); return TSPERR(TSS_E_INVALID_HANDLE); } /* a generic routine for removing all members of a list who's tsp context * matches @tspContext */ void obj_list_close(struct obj_list *list, void (*freeFcn)(void *), TSS_HCONTEXT tspContext) { struct tsp_object *index; struct tsp_object *next = NULL; struct tsp_object *toKill; struct tsp_object *prev = NULL; MUTEX_LOCK(list->lock); for (index = list->head; index; ) { next = index->next; if (index->tspContext == tspContext) { toKill = index; if (prev == NULL) { list->head = toKill->next; } else { prev->next = toKill->next; } (*freeFcn)(toKill->data); free(toKill); index = next; } else { prev = index; index = next; } } MUTEX_UNLOCK(list->lock); } void obj_close_context(TSS_HCONTEXT tspContext) { TPM_LIST_CLOSE(tspContext); CONTEXT_LIST_CLOSE(tspContext); HASH_LIST_CLOSE(tspContext); PCRS_LIST_CLOSE(tspContext); POLICY_LIST_CLOSE(tspContext); RSAKEY_LIST_CLOSE(tspContext); ENCDATA_LIST_CLOSE(tspContext); DAACRED_LIST_CLOSE(tspContext); DAAARAKEY_LIST_CLOSE(tspContext); DAAISSUERKEY_LIST_CLOSE(tspContext); NVSTORE_LIST_CLOSE(tspContext); DELFAMILY_LIST_CLOSE(tspContext); MIGDATA_LIST_CLOSE(tspContext); } /* When a policy object is closed, all references to it must be removed. This function * calls the object specific routines for each working object type to remove all refs to the * policy */ void obj_lists_remove_policy_refs(TSS_HPOLICY hPolicy, TSS_HCONTEXT tspContext) { obj_rsakey_remove_policy_refs(hPolicy, tspContext); obj_encdata_remove_policy_refs(hPolicy, tspContext); obj_tpm_remove_policy_refs(hPolicy, tspContext); } /* search all key lists (right now only RSA keys exist) looking for a TCS key handle, when * found, return the hash of its TPM_STORE_PUBKEY structure */ TSS_RESULT obj_tcskey_get_pubkeyhash(TCS_KEY_HANDLE hKey, BYTE *pubKeyHash) { struct tsp_object *obj; struct obj_list *list = &rsakey_list; struct tr_rsakey_obj *rsakey = NULL; TSS_RESULT result = TSS_SUCCESS; Trspi_HashCtx hashCtx; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { rsakey = (struct tr_rsakey_obj *)obj->data; if (rsakey->tcsHandle == hKey) break; } if (obj == NULL || rsakey == NULL) { MUTEX_UNLOCK(list->lock); return TSPERR(TSS_E_KEY_NOT_LOADED); } result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_STORE_PUBKEY(&hashCtx, &rsakey->key.pubKey); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash))) result = TSPERR(TSS_E_INTERNAL_ERROR); MUTEX_UNLOCK(list->lock); return result; } trousers-0.3.15/src/tspi/tsp_context_mem.c0000664000175000017510000001317113736475370020107 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "memmgr.h" #include "tsplog.h" #include "obj.h" static struct memTable * __tspi_createTable() { struct memTable *table = NULL; /* * No table has yet been created to hold the memory allocations of * this context, so we need to create one */ table = calloc(1, sizeof(struct memTable)); if (table == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct memTable)); return NULL; } return (table); } /* caller needs to lock memtable lock */ struct memTable * getTable(TSS_HCONTEXT tspContext) { struct memTable *tmp; for (tmp = SpiMemoryTable; tmp; tmp = tmp->nextTable) if (tmp->tspContext == tspContext) return tmp; return NULL; } /* caller needs to lock memtable lock */ static void __tspi_addTable(struct memTable *new) { struct memTable *tmp = SpiMemoryTable; /* base case, this is the first table */ if (SpiMemoryTable == NULL) { SpiMemoryTable = new; return; } /* else add @new onto the end */ for (; tmp; tmp = tmp->nextTable) if (tmp->nextTable == NULL) { tmp->nextTable = new; break; } } /* caller needs to lock memtable lock and be sure the context mem slot for * @tspContext exists before calling. */ void __tspi_addEntry(TSS_HCONTEXT tspContext, struct memEntry *new) { struct memTable *tmp = getTable(tspContext); struct memEntry *tmp_entry; if (tmp == NULL) { if ((tmp = __tspi_createTable()) == NULL) return; tmp->tspContext = tspContext; __tspi_addTable(tmp); } tmp_entry = tmp->entries; if (tmp->entries == NULL) { tmp->entries = new; return; } /* else tack @new onto the end */ for (; tmp_entry; tmp_entry = tmp_entry->nextEntry) { if (tmp_entry->nextEntry == NULL) { tmp_entry->nextEntry = new; break; } } } /* caller needs to lock memtable lock */ TSS_RESULT __tspi_freeTable(TSS_HCONTEXT tspContext) { struct memTable *prev = NULL, *index = NULL, *next = NULL; struct memEntry *entry = NULL, *entry_next = NULL; for(index = SpiMemoryTable; index; index = index->nextTable) { next = index->nextTable; if (index->tspContext == tspContext) { for (entry = index->entries; entry; entry = entry_next) { /* this needs to be set before we do free(entry) */ entry_next = entry->nextEntry; free(entry->memPointer); free(entry); } if (prev != NULL) prev->nextTable = next; else SpiMemoryTable = NULL; free(index); break; } prev = index; } return TSS_SUCCESS; } TSS_RESULT __tspi_freeEntry(struct memTable *table, void *pointer) { struct memEntry *index = NULL; struct memEntry *prev = NULL; struct memEntry *toKill = NULL; for (index = table->entries; index; prev = index, index = index->nextEntry) { if (index->memPointer == pointer) { toKill = index; if (prev == NULL) table->entries = toKill->nextEntry; else prev->nextEntry = toKill->nextEntry; free(pointer); free(toKill); return TSS_SUCCESS; } } return TSPERR(TSS_E_INVALID_RESOURCE); } TSS_RESULT __tspi_add_mem_entry(TSS_HCONTEXT tspContext, void *allocd_mem) { struct memEntry *newEntry = calloc(1, sizeof(struct memEntry)); if (newEntry == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct memEntry)); return TSPERR(TSS_E_OUTOFMEMORY); } newEntry->memPointer = allocd_mem; MUTEX_LOCK(memtable_lock); __tspi_addEntry(tspContext, newEntry); MUTEX_UNLOCK(memtable_lock); return TSS_SUCCESS; } /* * calloc_tspi will be called by functions outside of this file. All locking * is done here. */ void * calloc_tspi(TSS_HCONTEXT tspContext, UINT32 howMuch) { struct memTable *table = NULL; struct memEntry *newEntry = NULL; MUTEX_LOCK(memtable_lock); table = getTable(tspContext); if (table == NULL) { if ((table = __tspi_createTable()) == NULL) { MUTEX_UNLOCK(memtable_lock); return NULL; } table->tspContext = tspContext; __tspi_addTable(table); } newEntry = calloc(1, sizeof(struct memEntry)); if (newEntry == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct memEntry)); MUTEX_UNLOCK(memtable_lock); return NULL; } newEntry->memPointer = calloc(1, howMuch); if (newEntry->memPointer == NULL) { LogError("malloc of %d bytes failed.", howMuch); free(newEntry); MUTEX_UNLOCK(memtable_lock); return NULL; } /* this call must happen inside the lock or else another thread could * remove the context mem slot, causing a segfault */ __tspi_addEntry(tspContext, newEntry); MUTEX_UNLOCK(memtable_lock); return newEntry->memPointer; } /* * free_tspi will be called by functions outside of this file. All locking * is done here. */ TSS_RESULT free_tspi(TSS_HCONTEXT tspContext, void *memPointer) { struct memTable *index; TSS_RESULT result; MUTEX_LOCK(memtable_lock); if (memPointer == NULL) { result = __tspi_freeTable(tspContext); MUTEX_UNLOCK(memtable_lock); return result; } if ((index = getTable(tspContext)) == NULL) { MUTEX_UNLOCK(memtable_lock); /* Tspi_Context_FreeMemory checks that the TSP context is good before calling us, * so we can be sure that the problem is with memPointer */ return TSPERR(TSS_E_INVALID_RESOURCE); } /* just free one entry */ result = __tspi_freeEntry(index, memPointer); MUTEX_UNLOCK(memtable_lock); return result; } /* definition for a memset that cannot be optimized away */ void * __tspi_memset(void *s, int c, size_t n) { memset(s, c, n); asm volatile("" ::: "memory"); return s; } trousers-0.3.15/src/tspi/tspi_hash.c0000664000175000017510000000252213663651711016651 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_Hash_SetHashValue(TSS_HHASH hHash, /* in */ UINT32 ulHashValueLength, /* in */ BYTE * rgbHashValue) /* in */ { if (ulHashValueLength == 0 || rgbHashValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); return obj_hash_set_value(hHash, ulHashValueLength, rgbHashValue); } TSS_RESULT Tspi_Hash_GetHashValue(TSS_HHASH hHash, /* in */ UINT32 * pulHashValueLength, /* out */ BYTE ** prgbHashValue) /* out */ { if (pulHashValueLength == NULL || prgbHashValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); return obj_hash_get_value(hHash, pulHashValueLength, prgbHashValue); } TSS_RESULT Tspi_Hash_UpdateHashValue(TSS_HHASH hHash, /* in */ UINT32 ulDataLength, /* in */ BYTE *rgbData) /* in */ { if (rgbData == NULL && ulDataLength != 0) return TSPERR(TSS_E_BAD_PARAMETER); if (ulDataLength == 0) return TSS_SUCCESS; return obj_hash_update_value(hHash, ulDataLength, rgbData); } trousers-0.3.15/src/tspi/tsp_transport.c0000664000175000017510000000423413663651711017613 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Transport_LoadKeyByBlob(TSS_HCONTEXT hContext, TPM_COMMAND_CODE ordinal, TSS_HKEY hParentKey, UINT32 ulBlobLength, BYTE* rgbBlobData, TPM_AUTH* pAuth, TCS_KEY_HANDLE* phKey, TPM_KEY_HANDLE* phSlot) { TSS_RESULT result; UINT32 handleListSize, decLen; TCS_KEY_HANDLE hTCSParentKey; TCS_HANDLE *handleList; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; if ((result = obj_context_transport_init(hContext)) == TSS_TSPATTRIB_DISABLE_TRANSPORT) { if ((result = obj_rsakey_get_tcs_handle(hParentKey, &hTCSParentKey))) return result; return TCSP_LoadKeyByBlob(hContext, hTCSParentKey, ulBlobLength, rgbBlobData, pAuth, phKey, phSlot); } else if (result != TSS_TSPATTRIB_ENABLE_TRANSPORT) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_rsakey_get_transport_attribs(hParentKey, &hTCSParentKey, &pubKeyHash))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; /* Call ExecuteTransport */ handleListSize = 1; if ((handleList = malloc(sizeof(TCS_HANDLE))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(TCS_HANDLE)); return TSPERR(TSS_E_OUTOFMEMORY); } *handleList = hTCSParentKey; if ((result = obj_context_transport_execute(hContext, ordinal, ulBlobLength, rgbBlobData, &pubKeyHash, &handleListSize, &handleList, pAuth, NULL, &decLen, &dec))) { free(handleList); return result; } if (handleListSize == 1) *phKey = *(TCS_KEY_HANDLE *)handleList; else result = TSPERR(TSS_E_INTERNAL_ERROR); free(handleList); free(dec); return result; } trousers-0.3.15/src/tspi/tspi_dir.c0000664000175000017510000000557313663651711016515 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_DirWrite(TSS_HTPM hTPM, /* in */ UINT32 ulDirIndex, /* in */ UINT32 ulDirDataLength, /* in */ BYTE * rgbDirData) /* in */ { TSS_HCONTEXT tspContext; TCPA_RESULT result; TPM_AUTH auth; TCPA_DIGEST hashDigest; TSS_HPOLICY hPolicy; TCPA_DIRVALUE dirValue = { { 0 } }; Trspi_HashCtx hashCtx; if (rgbDirData == NULL || ulDirDataLength == 0) return TSPERR(TSS_E_BAD_PARAMETER); if (ulDirDataLength > (UINT32)sizeof(TCPA_DIRVALUE)) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy))) return result; memcpy((BYTE *)&dirValue, rgbDirData, ulDirDataLength); /* hash to be used for the OIAP calc */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_DirWriteAuth); result |= Trspi_Hash_UINT32(&hashCtx, ulDirIndex); result |= Trspi_HashUpdate(&hashCtx, (UINT32)sizeof(TCPA_DIRVALUE), (BYTE *)&dirValue); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; /* hashDigest now has the hash result */ if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_DirWriteAuth, hPolicy, FALSE, &hashDigest, &auth))) return result; if ((result = TCS_API(tspContext)->DirWriteAuth(tspContext, ulDirIndex, &dirValue, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_DirWriteAuth); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; return obj_policy_validate_auth_oiap(hPolicy, &hashDigest, &auth); } TSS_RESULT Tspi_TPM_DirRead(TSS_HTPM hTPM, /* in */ UINT32 ulDirIndex, /* in */ UINT32 * pulDirDataLength, /* out */ BYTE ** prgbDirData) /* out */ { TCPA_DIRVALUE dirValue; TSS_RESULT result; TSS_HCONTEXT tspContext; if (pulDirDataLength == NULL || prgbDirData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = TCS_API(tspContext)->DirRead(tspContext, ulDirIndex, &dirValue))) return result; *pulDirDataLength = 20; *prgbDirData = calloc_tspi(tspContext, *pulDirDataLength); if (*prgbDirData == NULL) { LogError("malloc of %d bytes failed.", *pulDirDataLength); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(*prgbDirData, dirValue.digest, *pulDirDataLength); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_asym.c0000664000175000017510000000512313663651711016526 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" /* encrypt some data with the RSA public key of 'key', using the padding appropriate for the key */ TSS_RESULT __tspi_rsa_encrypt(TSS_HKEY key, UINT32 inDataLen, BYTE* inData, UINT32* outDataLen, BYTE* outData) { BYTE *blob; UINT32 blobLen; UINT64 offset; TSS_RESULT result; TSS_HCONTEXT tspContext; TPM_PUBKEY pubKey; if (!inData || !outDataLen || !outData) return TSPERR(TSS_E_INTERNAL_ERROR); if ((result = obj_rsakey_get_tsp_context(key, &tspContext))) return result; if ((result = obj_rsakey_get_pub_blob(key, &blobLen, &blob))) return result; offset = 0; if ((result = Trspi_UnloadBlob_PUBKEY(&offset, blob, &pubKey))) { free_tspi(tspContext, blob); return result; } free_tspi(tspContext, blob); if (pubKey.pubKey.keyLength < inDataLen) { result = TSPERR(TSS_E_ENC_INVALID_LENGTH); goto done; } if (pubKey.algorithmParms.encScheme == TPM_ES_RSAESPKCSv15 || pubKey.algorithmParms.encScheme == TSS_ES_RSAESPKCSV15) { if ((result = Trspi_RSA_PKCS15_Encrypt(inData, inDataLen, outData, outDataLen, pubKey.pubKey.key, pubKey.pubKey.keyLength))) goto done; } else { if ((result = Trspi_TPM_RSA_OAEP_Encrypt(inData, inDataLen, outData, outDataLen, pubKey.pubKey.key, pubKey.pubKey.keyLength))) goto done; } done: free(pubKey.pubKey.key); free(pubKey.algorithmParms.parms); return result; } TSS_RESULT __tspi_rsa_verify(TSS_HKEY key, UINT32 type, UINT32 hashLen, BYTE* hash, UINT32 sigLen, BYTE* sig) { BYTE *blob; UINT32 blobLen; UINT64 offset; TSS_RESULT result; TSS_HCONTEXT tspContext; TPM_PUBKEY pubKey; if (!hash || !sig) return TSPERR(TSS_E_INTERNAL_ERROR); if ((result = obj_rsakey_get_tsp_context(key, &tspContext))) return result; if ((result = obj_rsakey_get_pub_blob(key, &blobLen, &blob))) return result; offset = 0; if ((result = Trspi_UnloadBlob_PUBKEY(&offset, blob, &pubKey))) { free_tspi(tspContext, blob); return result; } free_tspi(tspContext, blob); result = Trspi_Verify(type, hash, hashLen, pubKey.pubKey.key, pubKey.pubKey.keyLength, sig, sigLen); free(pubKey.pubKey.key); free(pubKey.algorithmParms.parms); return result; } trousers-0.3.15/src/tspi/tspi_caps.c0000664000175000017510000000420713663651711016656 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "tcs_tsp.h" #include "tspps.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "obj.h" TSS_RESULT Tspi_Context_GetCapability(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG capArea, /* in */ UINT32 ulSubCapLength, /* in */ BYTE * rgbSubCap, /* in */ UINT32 * pulRespDataLength, /* out */ BYTE ** prgbRespData) /* out */ { TSS_RESULT result; if (prgbRespData == NULL || pulRespDataLength == NULL ) return TSPERR(TSS_E_BAD_PARAMETER); if (rgbSubCap == NULL && ulSubCapLength != 0) return TSPERR(TSS_E_BAD_PARAMETER); if (ulSubCapLength > sizeof(UINT32)) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); switch (capArea) { case TSS_TSPCAP_ALG: case TSS_TSPCAP_RETURNVALUE_INFO: case TSS_TSPCAP_PLATFORM_INFO: case TSS_TSPCAP_MANUFACTURER: if (ulSubCapLength != sizeof(UINT32) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); /* fall through */ case TSS_TSPCAP_VERSION: case TSS_TSPCAP_PERSSTORAGE: result = internal_GetCap(tspContext, capArea, rgbSubCap ? *(UINT32 *)rgbSubCap : 0, pulRespDataLength, prgbRespData); break; case TSS_TCSCAP_ALG: if (ulSubCapLength != sizeof(UINT32) || !rgbSubCap) return TSPERR(TSS_E_BAD_PARAMETER); /* fall through */ case TSS_TCSCAP_VERSION: case TSS_TCSCAP_CACHING: case TSS_TCSCAP_PERSSTORAGE: case TSS_TCSCAP_MANUFACTURER: case TSS_TCSCAP_TRANSPORT: case TSS_TCSCAP_PLATFORM_CLASS: result = RPC_GetCapability(tspContext, capArea, ulSubCapLength, rgbSubCap, pulRespDataLength, prgbRespData); break; default: LogDebug("Invalid capArea: 0x%x", capArea); result = TSPERR(TSS_E_BAD_PARAMETER); break; } return result; } trousers-0.3.15/src/tspi/tsp_dir.c0000664000175000017510000000357413663651711016343 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_DirWriteAuth(TSS_HCONTEXT tspContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE *newContents, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0; UINT64 offset; BYTE data[sizeof(TCPA_DIRINDEX) + sizeof(TCPA_DIRVALUE)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, dirIndex, data); Trspi_LoadBlob_DIGEST(&offset, data, (TPM_DIGEST *)newContents); result = obj_context_transport_execute(tspContext, TPM_ORD_DirWriteAuth, sizeof(data), data, NULL, &handlesLen, NULL, ownerAuth, NULL, NULL, NULL); return result; } TSS_RESULT Transport_DirRead(TSS_HCONTEXT tspContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE * dirValue) /* out */ { TSS_RESULT result; UINT32 handlesLen = 0, decLen; UINT64 offset; BYTE data[sizeof(TCPA_DIRINDEX)], *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, dirIndex, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_DirRead, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_DIGEST(&offset, dec, dirValue); return result; } #endif trousers-0.3.15/src/tspi/tsp_certify.c0000664000175000017510000000526113663651711017225 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_CertifyKey(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE certHandle, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TPM_NONCE * antiReplay, /* in */ TPM_AUTH * certAuth, /* in, out */ TPM_AUTH * keyAuth, /* in, out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen; TCS_HANDLE *handles, handle[2]; BYTE *dec = NULL; TPM_DIGEST pubKeyHash1, pubKeyHash2; Trspi_HashCtx hashCtx; UINT64 offset; BYTE data[sizeof(TPM_NONCE)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(certHandle, pubKeyHash1.digest))) return result; if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash2.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash1.digest); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash2.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash1.digest))) return result; handlesLen = 2; handle[0] = certHandle; handle[1] = keyHandle; handles = &handle[0]; offset = 0; Trspi_LoadBlob_NONCE(&offset, data, antiReplay); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_CertifyKey, sizeof(data), data, &pubKeyHash1, &handlesLen, &handles, certAuth, keyAuth, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_CERTIFY_INFO(&offset, dec, NULL); *CertifyInfoSize = offset; if ((*CertifyInfo = malloc(*CertifyInfoSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *CertifyInfoSize); *CertifyInfoSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_UnloadBlob(&offset, *CertifyInfoSize, dec, *CertifyInfo); Trspi_UnloadBlob_UINT32(&offset, outDataSize, dec); if ((*outData = malloc(*outDataSize)) == NULL) { free(*CertifyInfo); *CertifyInfo = NULL; *CertifyInfoSize = 0; free(dec); LogError("malloc of %u bytes failed", *outDataSize); *outDataSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *outDataSize, dec, *outData); free(dec); return result; } #endif trousers-0.3.15/src/tspi/spi_utils.c0000664000175000017510000003070313663651711016704 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_UUID NULL_UUID = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; TSS_VERSION VERSION_1_1 = { 1, 1, 0, 0 }; struct tcs_api_table tcs_normal_api = { #ifdef TSS_BUILD_KEY .LoadKeyByBlob = RPC_LoadKeyByBlob, .EvictKey = RPC_EvictKey, .CreateWrapKey = RPC_CreateWrapKey, .GetPubKey = RPC_GetPubKey, #ifdef TSS_BUILD_TSS12 .OwnerReadInternalPub = RPC_OwnerReadInternalPub, #endif #ifdef TSS_BUILD_CERTIFY .CertifyKey = RPC_CertifyKey, #endif #endif #ifdef TSS_BUILD_OWN .OwnerClear = RPC_OwnerClear, .ForceClear = RPC_ForceClear, #endif #ifdef TSS_BUILD_AUTH .TerminateHandle = RPC_TerminateHandle, .OIAP = RPC_OIAP, .OSAP = RPC_OSAP, #endif #ifdef TSS_BUILD_CHANGEAUTH .ChangeAuth = RPC_ChangeAuth, .ChangeAuthOwner = RPC_ChangeAuthOwner, .ChangeAuthAsymStart = RPC_ChangeAuthAsymStart, .ChangeAuthAsymFinish = RPC_ChangeAuthAsymFinish, #endif #ifdef TSS_BUILD_AIK .ActivateTPMIdentity = RPC_ActivateTPMIdentity, #endif #ifdef TSS_BUILD_PCR_EXTEND .Extend = RPC_Extend, .PcrRead = RPC_PcrRead, .PcrReset = RPC_PcrReset, #endif #ifdef TSS_BUILD_QUOTE .Quote = RPC_Quote, #endif #ifdef TSS_BUILD_QUOTE2 .Quote2 = RPC_Quote2, #endif #ifdef TSS_BUILD_DIR .DirWriteAuth = RPC_DirWriteAuth, .DirRead = RPC_DirRead, #endif #ifdef TSS_BUILD_SEAL .Seal = RPC_Seal, .Unseal = RPC_Unseal, #ifdef TSS_BUILD_SEALX .Sealx = RPC_Sealx, #endif #endif #ifdef TSS_BUILD_BIND .UnBind = RPC_UnBind, #endif #ifdef TSS_BUILD_MIGRATION .CreateMigrationBlob = RPC_CreateMigrationBlob, .ConvertMigrationBlob = RPC_ConvertMigrationBlob, .AuthorizeMigrationKey = RPC_AuthorizeMigrationKey, #endif #ifdef TSS_BUILD_SIGN .Sign = RPC_Sign, #endif #ifdef TSS_BUILD_RANDOM .GetRandom = RPC_GetRandom, .StirRandom = RPC_StirRandom, #endif #ifdef TSS_BUILD_CAPS_TPM .GetTPMCapability = RPC_GetTPMCapability, .SetCapability = RPC_SetCapability, .GetCapabilityOwner = RPC_GetCapabilityOwner, #endif #ifdef TSS_BUILD_EK .CreateEndorsementKeyPair = RPC_CreateEndorsementKeyPair, .ReadPubek = RPC_ReadPubek, .OwnerReadPubek = RPC_OwnerReadPubek, #endif #ifdef TSS_BUILD_SELFTEST .SelfTestFull = RPC_SelfTestFull, .CertifySelfTest = RPC_CertifySelfTest, .GetTestResult = RPC_GetTestResult, #endif #ifdef TSS_BUILD_ADMIN .SetOwnerInstall = RPC_SetOwnerInstall, .DisablePubekRead = RPC_DisablePubekRead, .OwnerSetDisable = RPC_OwnerSetDisable, .DisableOwnerClear = RPC_DisableOwnerClear, .DisableForceClear = RPC_DisableForceClear, .PhysicalDisable = RPC_PhysicalDisable, .PhysicalEnable = RPC_PhysicalEnable, .PhysicalSetDeactivated = RPC_PhysicalSetDeactivated, .PhysicalPresence = RPC_PhysicalPresence, .SetTempDeactivated = RPC_SetTempDeactivated, #ifdef TSS_BUILD_TSS12 .SetTempDeactivated2 = RPC_SetTempDeactivated2, .ResetLockValue = RPC_ResetLockValue, #endif #endif #ifdef TSS_BUILD_MAINT .CreateMaintenanceArchive = RPC_CreateMaintenanceArchive, .LoadMaintenanceArchive = RPC_LoadMaintenanceArchive, .KillMaintenanceFeature = RPC_KillMaintenanceFeature, .LoadManuMaintPub = RPC_LoadManuMaintPub, .ReadManuMaintPub = RPC_ReadManuMaintPub, #endif #ifdef TSS_BUILD_DAA .DaaJoin = RPC_DaaJoin, .DaaSign = RPC_DaaSign, #endif #ifdef TSS_BUILD_COUNTER .ReadCounter = RPC_ReadCounter, .CreateCounter = RPC_CreateCounter, .IncrementCounter = RPC_IncrementCounter, .ReleaseCounter = RPC_ReleaseCounter, .ReleaseCounterOwner = RPC_ReleaseCounterOwner, #endif #ifdef TSS_BUILD_TICK .ReadCurrentTicks = RPC_ReadCurrentTicks, .TickStampBlob = RPC_TickStampBlob, #endif #ifdef TSS_BUILD_NV .NV_DefineOrReleaseSpace = RPC_NV_DefineOrReleaseSpace, .NV_WriteValue = RPC_NV_WriteValue, .NV_WriteValueAuth = RPC_NV_WriteValueAuth, .NV_ReadValue = RPC_NV_ReadValue, .NV_ReadValueAuth = RPC_NV_ReadValueAuth, #endif #ifdef TSS_BUILD_AUDIT .SetOrdinalAuditStatus = RPC_SetOrdinalAuditStatus, .GetAuditDigest = RPC_GetAuditDigest, .GetAuditDigestSigned = RPC_GetAuditDigestSigned, #endif #ifdef TSS_BUILD_TSS12 .SetOperatorAuth = RPC_SetOperatorAuth, .FlushSpecific = RPC_FlushSpecific, #endif #ifdef TSS_BUILD_DELEGATION .Delegate_Manage = RPC_Delegate_Manage, .Delegate_CreateKeyDelegation = RPC_Delegate_CreateKeyDelegation, .Delegate_CreateOwnerDelegation = RPC_Delegate_CreateOwnerDelegation, .Delegate_LoadOwnerDelegation = RPC_Delegate_LoadOwnerDelegation, .Delegate_ReadTable = RPC_Delegate_ReadTable, .Delegate_UpdateVerificationCount = RPC_Delegate_UpdateVerificationCount, .Delegate_VerifyDelegation = RPC_Delegate_VerifyDelegation, .DSAP = RPC_DSAP, #endif .FieldUpgrade = RPC_FieldUpgrade, .SetRedirection = RPC_SetRedirection, }; #ifdef TSS_BUILD_TRANSPORT struct tcs_api_table tcs_transport_api = { #ifdef TSS_BUILD_KEY .LoadKeyByBlob = Transport_LoadKeyByBlob, .EvictKey = Transport_EvictKey, .CreateWrapKey = Transport_CreateWrapKey, .GetPubKey = Transport_GetPubKey, #ifdef TSS_BUILD_TSS12 .OwnerReadInternalPub = Transport_OwnerReadInternalPub, #endif #ifdef TSS_BUILD_CERTIFY .CertifyKey = Transport_CertifyKey, #endif #endif #ifdef TSS_BUILD_OWN .OwnerClear = Transport_OwnerClear, .ForceClear = Transport_ForceClear, #endif #ifdef TSS_BUILD_AUTH .OIAP = Transport_OIAP, .OSAP = Transport_OSAP, .TerminateHandle = Transport_TerminateHandle, #endif #ifdef TSS_BUILD_CHANGEAUTH .ChangeAuth = Transport_ChangeAuth, .ChangeAuthOwner = Transport_ChangeAuthOwner, .ChangeAuthAsymStart = RPC_ChangeAuthAsymStart, .ChangeAuthAsymFinish = RPC_ChangeAuthAsymFinish, #endif #ifdef TSS_BUILD_AIK .ActivateTPMIdentity = Transport_ActivateTPMIdentity, #endif #ifdef TSS_BUILD_PCR_EXTEND .Extend = Transport_Extend, .PcrRead = Transport_PcrRead, .PcrReset = Transport_PcrReset, #endif #ifdef TSS_BUILD_QUOTE .Quote = Transport_Quote, #endif #ifdef TSS_BUILD_QUOTE2 .Quote2 = Transport_Quote2, #endif #ifdef TSS_BUILD_DIR .DirWriteAuth = Transport_DirWriteAuth, .DirRead = Transport_DirRead, #endif #ifdef TSS_BUILD_SEAL .Seal = Transport_Seal, .Sealx = Transport_Sealx, .Unseal = Transport_Unseal, #endif #ifdef TSS_BUILD_BIND .UnBind = Transport_UnBind, #endif #ifdef TSS_BUILD_MIGRATION .CreateMigrationBlob = Transport_CreateMigrationBlob, .ConvertMigrationBlob = Transport_ConvertMigrationBlob, .AuthorizeMigrationKey = Transport_AuthorizeMigrationKey, #endif #ifdef TSS_BUILD_SIGN .Sign = Transport_Sign, #endif #ifdef TSS_BUILD_RANDOM .GetRandom = Transport_GetRandom, .StirRandom = Transport_StirRandom, #endif #ifdef TSS_BUILD_CAPS_TPM .GetTPMCapability = Transport_GetTPMCapability, .SetCapability = Transport_SetCapability, .GetCapabilityOwner = Transport_GetCapabilityOwner, #endif #ifdef TSS_BUILD_EK .ReadPubek = RPC_ReadPubek, .OwnerReadPubek = RPC_OwnerReadPubek, #endif #ifdef TSS_BUILD_SELFTEST .SelfTestFull = Transport_SelfTestFull, .CertifySelfTest = Transport_CertifySelfTest, .GetTestResult = Transport_GetTestResult, #endif #ifdef TSS_BUILD_ADMIN .SetOwnerInstall = Transport_SetOwnerInstall, .DisablePubekRead = Transport_DisablePubekRead, .OwnerSetDisable = Transport_OwnerSetDisable, .ResetLockValue = Transport_ResetLockValue, .DisableOwnerClear = Transport_DisableOwnerClear, .DisableForceClear = Transport_DisableForceClear, .PhysicalDisable = Transport_PhysicalDisable, .PhysicalEnable = Transport_PhysicalEnable, .PhysicalSetDeactivated = Transport_PhysicalSetDeactivated, .PhysicalPresence = Transport_PhysicalPresence, .SetTempDeactivated = Transport_SetTempDeactivated, .SetTempDeactivated2 = Transport_SetTempDeactivated2, #endif #ifdef TSS_BUILD_MAINT .CreateMaintenanceArchive = Transport_CreateMaintenanceArchive, .LoadMaintenanceArchive = Transport_LoadMaintenanceArchive, .KillMaintenanceFeature = Transport_KillMaintenanceFeature, .LoadManuMaintPub = Transport_LoadManuMaintPub, .ReadManuMaintPub = Transport_ReadManuMaintPub, #endif #ifdef TSS_BUILD_DAA .DaaJoin = RPC_DaaJoin, .DaaSign = RPC_DaaSign, #endif #ifdef TSS_BUILD_COUNTER .ReadCounter = Transport_ReadCounter, .CreateCounter = RPC_CreateCounter, .IncrementCounter = RPC_IncrementCounter, .ReleaseCounter = RPC_ReleaseCounter, .ReleaseCounterOwner = RPC_ReleaseCounterOwner, #endif #ifdef TSS_BUILD_TICK .ReadCurrentTicks = Transport_ReadCurrentTicks, .TickStampBlob = Transport_TickStampBlob, #endif #ifdef TSS_BUILD_NV .NV_DefineOrReleaseSpace = Transport_NV_DefineOrReleaseSpace, .NV_WriteValue = Transport_NV_WriteValue, .NV_WriteValueAuth = Transport_NV_WriteValueAuth, .NV_ReadValue = Transport_NV_ReadValue, .NV_ReadValueAuth = Transport_NV_ReadValueAuth, #endif #ifdef TSS_BUILD_AUDIT .SetOrdinalAuditStatus = Transport_SetOrdinalAuditStatus, .GetAuditDigest = Transport_GetAuditDigest, .GetAuditDigestSigned = Transport_GetAuditDigestSigned, #endif #ifdef TSS_BUILD_TSS12 .SetOperatorAuth = Transport_SetOperatorAuth, .FlushSpecific = Transport_FlushSpecific, #endif #ifdef TSS_BUILD_DELEGATION .Delegate_Manage = Transport_Delegate_Manage, .Delegate_CreateKeyDelegation = Transport_Delegate_CreateKeyDelegation, .Delegate_CreateOwnerDelegation = Transport_Delegate_CreateOwnerDelegation, .Delegate_LoadOwnerDelegation = Transport_Delegate_LoadOwnerDelegation, .Delegate_ReadTable = Transport_Delegate_ReadTable, .Delegate_UpdateVerificationCount = Transport_Delegate_UpdateVerificationCount, .Delegate_VerifyDelegation = Transport_Delegate_VerifyDelegation, .DSAP = Transport_DSAP, #endif .FieldUpgrade = RPC_FieldUpgrade, .SetRedirection = RPC_SetRedirection, }; #endif UINT16 Decode_UINT16(BYTE * in) { UINT16 temp = 0; temp = (in[1] & 0xFF); temp |= (in[0] << 8); return temp; } void UINT32ToArray(UINT32 i, BYTE * out) { out[0] = (BYTE) ((i >> 24) & 0xFF); out[1] = (BYTE) ((i >> 16) & 0xFF); out[2] = (BYTE) ((i >> 8) & 0xFF); out[3] = (BYTE) i & 0xFF; } void UINT64ToArray(UINT64 i, BYTE *out) { out[0] = (BYTE) ((i >> 56) & 0xFF); out[1] = (BYTE) ((i >> 48) & 0xFF); out[2] = (BYTE) ((i >> 40) & 0xFF); out[3] = (BYTE) ((i >> 32) & 0xFF); out[4] = (BYTE) ((i >> 24) & 0xFF); out[5] = (BYTE) ((i >> 16) & 0xFF); out[6] = (BYTE) ((i >> 8) & 0xFF); out[7] = (BYTE) i & 0xFF; } void UINT16ToArray(UINT16 i, BYTE * out) { out[0] = ((i >> 8) & 0xFF); out[1] = i & 0xFF; } UINT64 Decode_UINT64(BYTE *y) { UINT64 x = 0; x = y[0]; x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[3] & 0xFF)); x = ((x << 8) | (y[4] & 0xFF)); x = ((x << 8) | (y[5] & 0xFF)); x = ((x << 8) | (y[6] & 0xFF)); x = ((x << 8) | (y[7] & 0xFF)); return x; } UINT32 Decode_UINT32(BYTE * y) { UINT32 x = 0; x = y[0]; x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[3] & 0xFF)); return x; } UINT32 get_pcr_event_size(TSS_PCR_EVENT *e) { return (sizeof(TSS_PCR_EVENT) + e->ulEventLength + e->ulPcrValueLength); } void LoadBlob_AUTH(UINT64 *offset, BYTE *blob, TPM_AUTH *auth) { Trspi_LoadBlob_UINT32(offset, auth->AuthHandle, blob); Trspi_LoadBlob(offset, 20, blob, auth->NonceOdd.nonce); Trspi_LoadBlob_BOOL(offset, auth->fContinueAuthSession, blob); Trspi_LoadBlob(offset, 20, blob, (BYTE *)&auth->HMAC); } void UnloadBlob_AUTH(UINT64 *offset, BYTE *blob, TPM_AUTH *auth) { Trspi_UnloadBlob(offset, 20, blob, auth->NonceEven.nonce); Trspi_UnloadBlob_BOOL(offset, &auth->fContinueAuthSession, blob); Trspi_UnloadBlob(offset, 20, blob, (BYTE *)&auth->HMAC); } /* If alloc is true, we allocate a new buffer for the bytes and set *data to that. * If alloc is false, data is really a BYTE*, so write the bytes directly to that buffer */ TSS_RESULT get_local_random(TSS_HCONTEXT tspContext, TSS_BOOL alloc, UINT32 size, BYTE **data) { FILE *f = NULL; BYTE *buf = NULL; f = fopen(TSS_LOCAL_RANDOM_DEVICE, "r"); if (f == NULL) { LogError("open of %s failed: %s", TSS_LOCAL_RANDOM_DEVICE, strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } if (alloc) { buf = calloc_tspi(tspContext, size); if (buf == NULL) { LogError("malloc of %u bytes failed", size); fclose(f); return TSPERR(TSS_E_OUTOFMEMORY); } } else buf = (BYTE *)data; if (fread(buf, size, 1, f) == 0) { LogError("fread of %s failed: %s", TSS_LOCAL_RANDOM_DEVICE, strerror(errno)); fclose(f); return TSPERR(TSS_E_INTERNAL_ERROR); } if (alloc) *data = buf; fclose(f); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_getset.c0000664000175000017510000011254713663651711017232 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "tsp_audit.h" TSS_RESULT Tspi_SetAttribUint32(TSS_HOBJECT hObject, /* in */ TSS_FLAG attribFlag, /* in */ TSS_FLAG subFlag, /* in */ UINT32 ulAttrib) /* in */ { TSS_RESULT result; if (obj_is_rsakey(hObject)) { #ifdef TSS_BUILD_RSAKEY_LIST if (attribFlag == TSS_TSPATTRIB_KEY_REGISTER) { if (subFlag) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); if (ulAttrib == TSS_TSPATTRIB_KEYREGISTER_USER) result = obj_rsakey_set_pstype(hObject, TSS_PS_TYPE_USER); else if (ulAttrib == TSS_TSPATTRIB_KEYREGISTER_SYSTEM) result = obj_rsakey_set_pstype(hObject, TSS_PS_TYPE_SYSTEM); else if (ulAttrib == TSS_TSPATTRIB_KEYREGISTER_NO) result = obj_rsakey_set_pstype(hObject, TSS_PS_TYPE_NO); else return TSPERR(TSS_E_INVALID_ATTRIB_DATA); } else if (attribFlag == TSS_TSPATTRIB_KEY_INFO) { switch (subFlag) { case TSS_TSPATTRIB_KEYINFO_USAGE: result = obj_rsakey_set_usage(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_MIGRATABLE: if (ulAttrib != TRUE && ulAttrib != FALSE) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_rsakey_set_migratable(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_REDIRECTED: if (ulAttrib != TRUE && ulAttrib != FALSE) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_rsakey_set_redirected(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_VOLATILE: if (ulAttrib != TRUE && ulAttrib != FALSE) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_rsakey_set_volatile(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_AUTHUSAGE: /* fall through */ case TSS_TSPATTRIB_KEYINFO_AUTHDATAUSAGE: if (ulAttrib != TRUE && ulAttrib != FALSE) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_rsakey_set_authdata_usage(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_ALGORITHM: result = obj_rsakey_set_alg(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_ENCSCHEME: if (ulAttrib != TSS_ES_NONE && ulAttrib != TSS_ES_RSAESPKCSV15 && ulAttrib != TSS_ES_RSAESOAEP_SHA1_MGF1) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_rsakey_set_es(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_SIGSCHEME: if (ulAttrib != TSS_SS_NONE && ulAttrib != TSS_SS_RSASSAPKCS1V15_SHA1 && ulAttrib != TSS_SS_RSASSAPKCS1V15_DER && ulAttrib != TSS_SS_RSASSAPKCS1V15_INFO) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_rsakey_set_ss(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_KEYFLAGS: result = obj_rsakey_set_flags(hObject, ulAttrib); break; case TSS_TSPATTRIB_KEYINFO_SIZE: result = obj_rsakey_set_size(hObject, ulAttrib); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else if (attribFlag == TSS_TSPATTRIB_RSAKEY_INFO) { if (subFlag == TSS_TSPATTRIB_KEYINFO_RSA_PRIMES) { result = obj_rsakey_set_num_primes(hObject, ulAttrib); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } else return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); #endif #ifdef TSS_BUILD_NV } else if (obj_is_nvstore(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_NV_INDEX: if ((result = obj_nvstore_set_index(hObject, ulAttrib))) return result; break; case TSS_TSPATTRIB_NV_DATASIZE: if ((result = obj_nvstore_set_datasize(hObject, ulAttrib))) return result; break; case TSS_TSPATTRIB_NV_PERMISSIONS: if ((result = obj_nvstore_set_permission(hObject, ulAttrib))) return result; break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } #endif } else if (obj_is_policy(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: result = obj_policy_set_cb11(hObject, attribFlag, subFlag, ulAttrib); break; case TSS_TSPATTRIB_POLICY_SECRET_LIFETIME: if (subFlag == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS || subFlag == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER || subFlag == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER) { result = obj_policy_set_lifetime(hObject, subFlag, ulAttrib); } else { result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_TSPATTRIB_SECRET_HASH_MODE: result = obj_policy_set_hash_mode(hObject, ulAttrib); break; #ifdef TSS_BUILD_DELEGATION case TSS_TSPATTRIB_POLICY_DELEGATION_INFO: switch (subFlag) { case TSS_TSPATTRIB_POLDEL_TYPE: switch (ulAttrib) { case TSS_DELEGATIONTYPE_NONE: case TSS_DELEGATIONTYPE_OWNER: case TSS_DELEGATIONTYPE_KEY: result = obj_policy_set_delegation_type(hObject, ulAttrib); break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_DATA); } break; case TSS_TSPATTRIB_POLDEL_INDEX: result = obj_policy_set_delegation_index(hObject, ulAttrib); break; case TSS_TSPATTRIB_POLDEL_PER1: result = obj_policy_set_delegation_per1(hObject, ulAttrib); break; case TSS_TSPATTRIB_POLDEL_PER2: result = obj_policy_set_delegation_per2(hObject, ulAttrib); break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; #endif default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_context(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_CONTEXT_SILENT_MODE: if (ulAttrib == TSS_TSPATTRIB_CONTEXT_NOT_SILENT) result = obj_context_set_mode(hObject, ulAttrib); else if (ulAttrib == TSS_TSPATTRIB_CONTEXT_SILENT) { if (obj_context_has_popups(hObject)) return TSPERR(TSS_E_SILENT_CONTEXT); result = obj_context_set_mode(hObject, ulAttrib); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; #ifdef TSS_BUILD_TRANSPORT case TSS_TSPATTRIB_CONTEXT_TRANSPORT: if (subFlag == TSS_TSPATTRIB_CONTEXTTRANS_CONTROL) { if (ulAttrib != TSS_TSPATTRIB_DISABLE_TRANSPORT && ulAttrib != TSS_TSPATTRIB_ENABLE_TRANSPORT) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_context_transport_set_control(hObject, ulAttrib); } else if (subFlag == TSS_TSPATTRIB_CONTEXTTRANS_MODE) { switch (ulAttrib) { case TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION: case TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION: case TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL: case TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE: case TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH: break; default: return TSPERR(TSS_E_INVALID_ATTRIB_DATA); } result = obj_context_transport_set_mode(hObject, ulAttrib); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; #endif case TSS_TSPATTRIB_SECRET_HASH_MODE: result = obj_context_set_hash_mode(hObject, ulAttrib); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_tpm(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: if ((result = obj_tpm_set_cb11(hObject, attribFlag, subFlag, ulAttrib))) return result; break; #ifdef TSS_BUILD_AUDIT case TSS_TSPATTRIB_TPM_ORDINAL_AUDIT_STATUS: result = __tspi_audit_set_ordinal_audit_status(hObject, attribFlag, subFlag, ulAttrib); break; #endif default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } #ifdef TSS_BUILD_SEALX } else if (obj_is_encdata(hObject)) { if (attribFlag != TSS_TSPATTRIB_ENCDATA_SEAL) return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); if (subFlag == TSS_TSPATTRIB_ENCDATASEAL_PROTECT_MODE) { if (ulAttrib != TSS_TSPATTRIB_ENCDATASEAL_NO_PROTECT && ulAttrib != TSS_TSPATTRIB_ENCDATASEAL_PROTECT) return TSPERR(TSS_E_INVALID_ATTRIB_DATA); result = obj_encdata_set_seal_protect_mode(hObject, ulAttrib); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); #endif #ifdef TSS_BUILD_DELEGATION } else if (obj_is_delfamily(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_DELFAMILY_STATE: switch (subFlag) { case TSS_TSPATTRIB_DELFAMILYSTATE_LOCKED: result = obj_delfamily_set_locked(hObject, (TSS_BOOL)ulAttrib, TRUE); break; case TSS_TSPATTRIB_DELFAMILYSTATE_ENABLED: result = obj_delfamily_set_enabled(hObject, (TSS_BOOL)ulAttrib, TRUE); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); } #endif } else { if (obj_is_hash(hObject) || obj_is_pcrs(hObject)) result = TSPERR(TSS_E_BAD_PARAMETER); else result = TSPERR(TSS_E_INVALID_HANDLE); } return result; } TSS_RESULT Tspi_GetAttribUint32(TSS_HOBJECT hObject, /* in */ TSS_FLAG attribFlag, /* in */ TSS_FLAG subFlag, /* in */ UINT32 * pulAttrib) /* out */ { UINT32 attrib; TSS_RESULT result = TSS_SUCCESS; if (pulAttrib == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (obj_is_rsakey(hObject)) { #ifdef TSS_BUILD_RSAKEY_LIST if (attribFlag == TSS_TSPATTRIB_KEY_REGISTER) { if (subFlag != 0) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); if ((result = obj_rsakey_get_pstype(hObject, &attrib))) return result; if (attrib == TSS_PS_TYPE_USER) *pulAttrib = TSS_TSPATTRIB_KEYREGISTER_USER; else if (attrib == TSS_PS_TYPE_SYSTEM) *pulAttrib = TSS_TSPATTRIB_KEYREGISTER_SYSTEM; else *pulAttrib = TSS_TSPATTRIB_KEYREGISTER_NO; } else if (attribFlag == TSS_TSPATTRIB_KEY_INFO) { switch (subFlag) { case TSS_TSPATTRIB_KEYINFO_USAGE: if ((result = obj_rsakey_get_usage(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_KEYINFO_MIGRATABLE: *pulAttrib = obj_rsakey_is_migratable(hObject); break; case TSS_TSPATTRIB_KEYINFO_REDIRECTED: *pulAttrib = obj_rsakey_is_redirected(hObject); break; case TSS_TSPATTRIB_KEYINFO_VOLATILE: *pulAttrib = obj_rsakey_is_volatile(hObject); break; case TSS_TSPATTRIB_KEYINFO_AUTHUSAGE: /* fall through */ case TSS_TSPATTRIB_KEYINFO_AUTHDATAUSAGE: if ((result = obj_rsakey_get_authdata_usage(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_KEYINFO_ALGORITHM: if ((result = obj_rsakey_get_alg(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_KEYINFO_ENCSCHEME: if ((result = obj_rsakey_get_es(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_KEYINFO_SIGSCHEME: if ((result = obj_rsakey_get_ss(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_KEYINFO_KEYFLAGS: if ((result = obj_rsakey_get_flags(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_KEYINFO_SIZE: if ((result = obj_rsakey_get_size(hObject, pulAttrib))) return result; break; #ifdef TSS_BUILD_CMK case TSS_TSPATTRIB_KEYINFO_CMK: *pulAttrib = obj_rsakey_is_cmk(hObject); break; #endif default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else if (attribFlag == TSS_TSPATTRIB_RSAKEY_INFO) { if (subFlag == TSS_TSPATTRIB_KEYINFO_RSA_KEYSIZE) { if ((result = obj_rsakey_get_size(hObject, pulAttrib))) return result; } else if (subFlag == TSS_TSPATTRIB_KEYINFO_RSA_PRIMES) { if ((result = obj_rsakey_get_num_primes(hObject, pulAttrib))) return result; } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else if (attribFlag == TSS_TSPATTRIB_KEY_PCR_LONG) { if (subFlag == TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATCREATION || subFlag == TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATRELEASE) { result = obj_rsakey_get_pcr_locality(hObject, subFlag, pulAttrib); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } else return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); #endif #ifdef TSS_BUILD_NV } else if (obj_is_nvstore(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_NV_INDEX: if ((result = obj_nvstore_get_index(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_NV_DATASIZE: if ((result = obj_nvstore_get_datasize(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_NV_PERMISSIONS: if ((result = obj_nvstore_get_permission(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_NV_STATE: switch (subFlag) { case TSS_TSPATTRIB_NVSTATE_READSTCLEAR: if ((result = obj_nvstore_get_state_readstclear(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_NVSTATE_WRITEDEFINE: if ((result = obj_nvstore_get_state_writedefine(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_NVSTATE_WRITESTCLEAR: if ((result = obj_nvstore_get_state_writestclear(hObject, pulAttrib))) return result; break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_TSPATTRIB_NV_PCR: switch (subFlag) { case TSS_TSPATTRIB_NVPCR_READLOCALITYATRELEASE: if ((result = obj_nvstore_get_readlocalityatrelease(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_NVPCR_WRITELOCALITYATRELEASE: if ((result = obj_nvstore_get_writelocalityatrelease(hObject, pulAttrib))) return result; break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_TSPATTRIB_KEYCONTROL_OWNEREVICT: if ((result = obj_rsakey_get_ownerevict(hObject, pulAttrib))) return result; break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); } #endif } else if (obj_is_policy(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: if ((result = obj_policy_get_cb11(hObject, attribFlag, pulAttrib))) return result; break; case TSS_TSPATTRIB_POLICY_SECRET_LIFETIME: if ((result = obj_policy_get_lifetime(hObject, &attrib))) return result; if (subFlag == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS) { if (attrib == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS) *pulAttrib = TRUE; else *pulAttrib = FALSE; } else if (subFlag == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER) { if (attrib != TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_policy_get_counter(hObject, pulAttrib))) return result; } else if (subFlag == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER) { if ((result = obj_policy_get_secs_until_expired(hObject, pulAttrib))) return result; } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; case TSS_TSPATTRIB_SECRET_HASH_MODE: if (subFlag == TSS_TSPATTRIB_SECRET_HASH_MODE_POPUP) result = obj_policy_get_hash_mode(hObject, pulAttrib); else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; #ifdef TSS_BUILD_DELEGATION case TSS_TSPATTRIB_POLICY_DELEGATION_INFO: switch (subFlag) { case TSS_TSPATTRIB_POLDEL_TYPE: result = obj_policy_get_delegation_type(hObject, pulAttrib); break; case TSS_TSPATTRIB_POLDEL_INDEX: result = obj_policy_get_delegation_index(hObject, pulAttrib); break; case TSS_TSPATTRIB_POLDEL_PER1: result = obj_policy_get_delegation_per1(hObject, pulAttrib); break; case TSS_TSPATTRIB_POLDEL_PER2: result = obj_policy_get_delegation_per2(hObject, pulAttrib); break; case TSS_TSPATTRIB_POLDEL_LABEL: result = obj_policy_get_delegation_label(hObject, (BYTE *)pulAttrib); break; case TSS_TSPATTRIB_POLDEL_FAMILYID: result = obj_policy_get_delegation_familyid(hObject, pulAttrib); break; case TSS_TSPATTRIB_POLDEL_VERCOUNT: result = obj_policy_get_delegation_vercount(hObject, pulAttrib); break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_TSPATTRIB_POLICY_DELEGATION_PCR: switch (subFlag) { case TSS_TSPATTRIB_POLDELPCR_LOCALITY: result = obj_policy_get_delegation_pcr_locality(hObject, pulAttrib); break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; #endif default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_context(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_CONTEXT_SILENT_MODE: if ((result = obj_context_get_mode(hObject, pulAttrib))) return result; break; case TSS_TSPATTRIB_SECRET_HASH_MODE: if (subFlag == TSS_TSPATTRIB_SECRET_HASH_MODE_POPUP) result = obj_context_get_hash_mode(hObject, pulAttrib); else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; #ifdef TSS_BUILD_TRANSPORT case TSS_TSPATTRIB_CONTEXT_TRANSPORT: if (subFlag == TSS_TSPATTRIB_DISABLE_TRANSPORT || subFlag == TSS_TSPATTRIB_ENABLE_TRANSPORT) { result = obj_context_transport_get_control(hObject, subFlag, pulAttrib); } else if ( subFlag == TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION || subFlag == TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION || subFlag == TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL || subFlag == TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE || subFlag == TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH) { result = obj_context_transport_get_mode(hObject, subFlag, pulAttrib); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; #endif default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_tpm(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: if ((result = obj_tpm_get_cb11(hObject, attribFlag, pulAttrib))) return result; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_encdata(hObject)) { #ifdef TSS_BUILD_SEALX if (attribFlag == TSS_TSPATTRIB_ENCDATA_SEAL) { if (subFlag == TSS_TSPATTRIB_ENCDATASEAL_PROTECT_MODE) result = obj_encdata_get_seal_protect_mode(hObject, pulAttrib); else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } else if (attribFlag == TSS_TSPATTRIB_ENCDATA_PCR_LONG) { if (subFlag == TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATCREATION || subFlag == TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATRELEASE) { result = obj_encdata_get_pcr_locality(hObject, subFlag, pulAttrib); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } else return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); #endif #ifdef TSS_BUILD_DELEGATION } else if (obj_is_delfamily(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_DELFAMILY_STATE: switch (subFlag) { case TSS_TSPATTRIB_DELFAMILYSTATE_LOCKED: result = obj_delfamily_get_locked(hObject, (TSS_BOOL *)pulAttrib); break; case TSS_TSPATTRIB_DELFAMILYSTATE_ENABLED: result = obj_delfamily_get_enabled(hObject, (TSS_BOOL *)pulAttrib); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_TSPATTRIB_DELFAMILY_INFO: switch (subFlag) { case TSS_TSPATTRIB_DELFAMILYINFO_LABEL: result = obj_delfamily_get_label(hObject, (BYTE *)pulAttrib); break; case TSS_TSPATTRIB_DELFAMILYINFO_VERCOUNT: result = obj_delfamily_get_vercount(hObject, pulAttrib); break; case TSS_TSPATTRIB_DELFAMILYINFO_FAMILYID: result = obj_delfamily_get_familyid(hObject, pulAttrib); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); } #endif } else { if (obj_is_hash(hObject) || obj_is_pcrs(hObject)) result = TSPERR(TSS_E_BAD_PARAMETER); else result = TSPERR(TSS_E_INVALID_HANDLE); } return result; } TSS_RESULT Tspi_SetAttribData(TSS_HOBJECT hObject, /* in */ TSS_FLAG attribFlag, /* in */ TSS_FLAG subFlag, /* in */ UINT32 ulAttribDataSize, /* in */ BYTE * rgbAttribData) /* in */ { TSS_RESULT result; BYTE *string = NULL; if (obj_is_rsakey(hObject)) { #ifdef TSS_BUILD_RSAKEY_LIST if (attribFlag == TSS_TSPATTRIB_KEY_BLOB) { if (subFlag == TSS_TSPATTRIB_KEYBLOB_BLOB) { /* A TPM_KEY(12) structure, in blob form */ result = obj_rsakey_set_tcpakey(hObject, ulAttribDataSize, rgbAttribData); if (result == TSS_SUCCESS) result = obj_rsakey_set_tcs_handle(hObject, 0); } else if (subFlag == TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY) { /* A TCPA_PUBKEY structure, in blob form */ result = obj_rsakey_set_pubkey(hObject, FALSE, rgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY) { /* A blob, either encrypted or unencrypted */ result = obj_rsakey_set_privkey(hObject, FALSE, ulAttribDataSize, rgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else if (attribFlag == TSS_TSPATTRIB_RSAKEY_INFO) { if (subFlag == TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT) { result = obj_rsakey_set_exponent(hObject, ulAttribDataSize, rgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYINFO_RSA_MODULUS) { result = obj_rsakey_set_modulus(hObject, ulAttribDataSize, rgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } #ifdef TSS_BUILD_CMK } else if (attribFlag == TSS_TSPATTRIB_KEY_CMKINFO) { if (subFlag == TSS_TSPATTRIB_KEYINFO_CMK_MA_APPROVAL) { result = obj_rsakey_set_msa_approval(hObject, ulAttribDataSize, rgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYINFO_CMK_MA_DIGEST) { result = obj_rsakey_set_msa_digest(hObject, ulAttribDataSize, rgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } #endif } else { return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); } #endif } else if (obj_is_encdata(hObject)) { #ifdef TSS_BUILD_ENCDATA_LIST if (attribFlag != TSS_TSPATTRIB_ENCDATA_BLOB) return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); if (subFlag != TSS_TSPATTRIB_ENCDATABLOB_BLOB) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); result = obj_encdata_set_data(hObject, ulAttribDataSize, rgbAttribData); #endif } else if (obj_is_policy(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_POLICY_POPUPSTRING: if ((string = Trspi_UNICODE_To_Native(rgbAttribData, NULL)) == NULL) return TSPERR(TSS_E_INTERNAL_ERROR); result = obj_policy_set_string(hObject, ulAttribDataSize, string); break; case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: #ifdef TSS_BUILD_SEALX case TSS_TSPATTRIB_POLICY_CALLBACK_SEALX_MASK: #endif result = obj_policy_set_cb12(hObject, attribFlag, rgbAttribData); break; #ifdef TSS_BUILD_DELEGATION case TSS_TSPATTRIB_POLICY_DELEGATION_INFO: switch (subFlag) { case TSS_TSPATTRIB_POLDEL_OWNERBLOB: result = obj_policy_set_delegation_blob(hObject, TSS_DELEGATIONTYPE_OWNER, ulAttribDataSize, rgbAttribData); break; case TSS_TSPATTRIB_POLDEL_KEYBLOB: result = obj_policy_set_delegation_blob(hObject, TSS_DELEGATIONTYPE_KEY, ulAttribDataSize, rgbAttribData); break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; #endif default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_hash(hObject)) { #ifdef TSS_BUILD_HASH_LIST if (attribFlag != TSS_TSPATTRIB_HASH_IDENTIFIER) return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); if (subFlag != 0) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); result = obj_hash_set_value(hObject, ulAttribDataSize, rgbAttribData); #endif } else if (obj_is_tpm(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: result = obj_tpm_set_cb12(hObject, attribFlag, rgbAttribData); break; case TSS_TSPATTRIB_TPM_CREDENTIAL: if (subFlag == TSS_TPMATTRIB_EKCERT || subFlag == TSS_TPMATTRIB_TPM_CC || subFlag == TSS_TPMATTRIB_PLATFORMCERT || subFlag == TSS_TPMATTRIB_PLATFORM_CC) { result = obj_tpm_set_cred(hObject, subFlag, ulAttribDataSize, rgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_migdata(hObject)) { #ifdef TSS_BUILD_CMK switch (attribFlag) { case TSS_MIGATTRIB_MIGRATIONBLOB: switch (subFlag) { case TSS_MIGATTRIB_MIG_MSALIST_PUBKEY_BLOB: case TSS_MIGATTRIB_MIG_AUTHORITY_PUBKEY_BLOB: case TSS_MIGATTRIB_MIG_DESTINATION_PUBKEY_BLOB: case TSS_MIGATTRIB_MIG_SOURCE_PUBKEY_BLOB: result = obj_migdata_set_migrationblob(hObject, subFlag, ulAttribDataSize, rgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_MIGATTRIB_MIGRATIONTICKET: if (subFlag != 0) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); result = obj_migdata_set_ticket_blob(hObject, ulAttribDataSize, rgbAttribData); break; case TSS_MIGATTRIB_AUTHORITY_DATA: switch (subFlag) { case TSS_MIGATTRIB_AUTHORITY_DIGEST: case TSS_MIGATTRIB_AUTHORITY_APPROVAL_HMAC: case TSS_MIGATTRIB_AUTHORITY_MSALIST: result = obj_migdata_set_authoritydata(hObject, subFlag, ulAttribDataSize, rgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_MIGATTRIB_MIG_AUTH_DATA: switch (subFlag) { case TSS_MIGATTRIB_MIG_AUTH_AUTHORITY_DIGEST: case TSS_MIGATTRIB_MIG_AUTH_DESTINATION_DIGEST: case TSS_MIGATTRIB_MIG_AUTH_SOURCE_DIGEST: result = obj_migdata_set_migauthdata(hObject, subFlag, ulAttribDataSize, rgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_MIGATTRIB_TICKET_DATA: switch (subFlag) { case TSS_MIGATTRIB_TICKET_SIG_DIGEST: case TSS_MIGATTRIB_TICKET_SIG_VALUE: case TSS_MIGATTRIB_TICKET_SIG_TICKET: case TSS_MIGATTRIB_TICKET_RESTRICT_TICKET: result = obj_migdata_set_ticketdata(hObject, subFlag, ulAttribDataSize, rgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } #endif } else { if (obj_is_pcrs(hObject) || obj_is_context(hObject)) result = TSPERR(TSS_E_BAD_PARAMETER); #ifdef TSS_BUILD_NV else if (obj_is_nvstore(hObject)) result = TSPERR(TSS_E_BAD_PARAMETER); #endif else result = TSPERR(TSS_E_INVALID_HANDLE); } return result; } TSS_RESULT Tspi_GetAttribData(TSS_HOBJECT hObject, /* in */ TSS_FLAG attribFlag, /* in */ TSS_FLAG subFlag, /* in */ UINT32 * pulAttribDataSize, /* out */ BYTE ** prgbAttribData) /* out */ { TSS_RESULT result; if (pulAttribDataSize == NULL || prgbAttribData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (obj_is_rsakey(hObject)) { #ifdef TSS_BUILD_RSAKEY_LIST if (attribFlag == TSS_TSPATTRIB_KEY_BLOB) { if (subFlag == TSS_TSPATTRIB_KEYBLOB_BLOB) { /* A TPM_KEY(12) structure, in blob form */ result = obj_rsakey_get_blob(hObject, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY) { /* A blob, either encrypted or unencrypted */ result = obj_rsakey_get_priv_blob(hObject, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY) { /* A TCPA_PUBKEY structure, in blob form */ result = obj_rsakey_get_pub_blob(hObject, pulAttribDataSize, prgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else if (attribFlag == TSS_TSPATTRIB_KEY_INFO) { if (subFlag != TSS_TSPATTRIB_KEYINFO_VERSION) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); result = obj_rsakey_get_version(hObject, pulAttribDataSize, prgbAttribData); } else if (attribFlag == TSS_TSPATTRIB_RSAKEY_INFO) { if (subFlag == TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT) { result = obj_rsakey_get_exponent(hObject, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYINFO_RSA_MODULUS) { result = obj_rsakey_get_modulus(hObject, pulAttribDataSize, prgbAttribData); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } else if (attribFlag == TSS_TSPATTRIB_KEY_UUID) { if (subFlag) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); result = obj_rsakey_get_uuid(hObject, pulAttribDataSize, prgbAttribData); } else if (attribFlag == TSS_TSPATTRIB_KEY_PCR) { if (subFlag == TSS_TSPATTRIB_KEYPCR_DIGEST_ATCREATION || subFlag == TSS_TSPATTRIB_KEYPCR_DIGEST_ATRELEASE) { result = obj_rsakey_get_pcr_digest(hObject, TSS_PCRS_STRUCT_INFO, subFlag, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYPCR_SELECTION) { result = obj_rsakey_get_pcr_selection(hObject, TSS_PCRS_STRUCT_INFO, subFlag, pulAttribDataSize, prgbAttribData); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } else if (attribFlag == TSS_TSPATTRIB_KEY_PCR_LONG) { if (subFlag == TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATCREATION || subFlag == TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATRELEASE) { result = obj_rsakey_get_pcr_digest(hObject, TSS_PCRS_STRUCT_INFO_LONG, subFlag, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYPCRLONG_CREATION_SELECTION || subFlag == TSS_TSPATTRIB_KEYPCRLONG_RELEASE_SELECTION) { result = obj_rsakey_get_pcr_selection(hObject, TSS_PCRS_STRUCT_INFO_LONG, subFlag, pulAttribDataSize, prgbAttribData); } else return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); #ifdef TSS_BUILD_CMK } else if (attribFlag == TSS_TSPATTRIB_KEY_CMKINFO) { if (subFlag == TSS_TSPATTRIB_KEYINFO_CMK_MA_APPROVAL) { result = obj_rsakey_get_msa_approval(hObject, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_KEYINFO_CMK_MA_DIGEST) { result = obj_rsakey_get_msa_digest(hObject, pulAttribDataSize, prgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } #endif } else return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); #endif #ifdef TSS_BUILD_NV } else if (obj_is_nvstore(hObject)) { if (attribFlag == TSS_TSPATTRIB_NV_PCR) { switch (subFlag) { case TSS_TSPATTRIB_NVPCR_READDIGESTATRELEASE: if ((result = obj_nvstore_get_readdigestatrelease(hObject, pulAttribDataSize, prgbAttribData))) return result; break; case TSS_TSPATTRIB_NVPCR_READPCRSELECTION: if ((result = obj_nvstore_get_readpcrselection( hObject, pulAttribDataSize, prgbAttribData))) return result; break; case TSS_TSPATTRIB_NVPCR_WRITEDIGESTATRELEASE: if ((result = obj_nvstore_get_writedigestatrelease(hObject, pulAttribDataSize, prgbAttribData))) return result; break; case TSS_TSPATTRIB_NVPCR_WRITEPCRSELECTION: if ((result = obj_nvstore_get_writepcrselection(hObject, pulAttribDataSize, prgbAttribData))) return result; break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); #endif } else if (obj_is_encdata(hObject)) { #ifdef TSS_BUILD_ENCDATA_LIST if (attribFlag == TSS_TSPATTRIB_ENCDATA_BLOB) { if (subFlag != TSS_TSPATTRIB_ENCDATABLOB_BLOB) return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); result = obj_encdata_get_data(hObject, pulAttribDataSize, prgbAttribData); } else if (attribFlag == TSS_TSPATTRIB_ENCDATA_PCR) { if (subFlag == TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATCREATION || subFlag == TSS_TSPATTRIB_ENCDATAPCR_DIGEST_RELEASE) { result = obj_encdata_get_pcr_digest(hObject, TSS_PCRS_STRUCT_INFO, subFlag, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_ENCDATAPCR_SELECTION) { result = obj_encdata_get_pcr_selection(hObject, TSS_PCRS_STRUCT_INFO, subFlag, pulAttribDataSize, prgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else if (attribFlag == TSS_TSPATTRIB_ENCDATA_PCR_LONG) { if (subFlag == TSS_TSPATTRIB_ENCDATAPCRLONG_CREATION_SELECTION || subFlag == TSS_TSPATTRIB_ENCDATAPCRLONG_RELEASE_SELECTION) { result = obj_encdata_get_pcr_selection(hObject, TSS_PCRS_STRUCT_INFO_LONG, subFlag, pulAttribDataSize, prgbAttribData); } else if (subFlag == TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATCREATION || subFlag == TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATRELEASE) { result = obj_encdata_get_pcr_digest(hObject, TSS_PCRS_STRUCT_INFO_LONG, subFlag, pulAttribDataSize, prgbAttribData); } else { return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } } else { return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); } #endif } else if (obj_is_context(hObject)) { if (attribFlag != TSS_TSPATTRIB_CONTEXT_MACHINE_NAME) return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); if ((result = obj_context_get_machine_name_attrib(hObject, pulAttribDataSize, prgbAttribData))) return result; } else if (obj_is_policy(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: #ifdef TSS_BUILD_SEALX case TSS_TSPATTRIB_POLICY_CALLBACK_SEALX_MASK: #endif result = obj_policy_get_cb12(hObject, attribFlag, pulAttribDataSize, prgbAttribData); break; case TSS_TSPATTRIB_POLICY_POPUPSTRING: if ((result = obj_policy_get_string(hObject, pulAttribDataSize, prgbAttribData))) return result; break; #ifdef TSS_BUILD_DELEGATION case TSS_TSPATTRIB_POLICY_DELEGATION_INFO: switch (subFlag) { case TSS_TSPATTRIB_POLDEL_OWNERBLOB: result = obj_policy_get_delegation_blob(hObject, TSS_DELEGATIONTYPE_OWNER, pulAttribDataSize, prgbAttribData); break; case TSS_TSPATTRIB_POLDEL_KEYBLOB: result = obj_policy_get_delegation_blob(hObject, TSS_DELEGATIONTYPE_KEY, pulAttribDataSize, prgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_TSPATTRIB_POLICY_DELEGATION_PCR: switch (subFlag) { case TSS_TSPATTRIB_POLDELPCR_DIGESTATRELEASE: result = obj_policy_get_delegation_pcr_digest(hObject, pulAttribDataSize, prgbAttribData); break; case TSS_TSPATTRIB_POLDELPCR_SELECTION: result = obj_policy_get_delegation_pcr_selection(hObject, pulAttribDataSize, prgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; #endif default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_tpm(hObject)) { switch (attribFlag) { case TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY: case TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY: result = obj_tpm_get_cb12(hObject, attribFlag, pulAttribDataSize, prgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } } else if (obj_is_migdata(hObject)) { #ifdef TSS_BUILD_CMK switch (attribFlag) { case TSS_MIGATTRIB_MIGRATIONBLOB: switch (subFlag) { case TSS_MIGATTRIB_MIG_XOR_BLOB: result = obj_migdata_get_migrationblob(hObject, subFlag, pulAttribDataSize, prgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_MIGATTRIB_AUTHORITY_DATA: switch (subFlag) { case TSS_MIGATTRIB_AUTHORITY_DIGEST: case TSS_MIGATTRIB_AUTHORITY_APPROVAL_HMAC: case TSS_MIGATTRIB_AUTHORITY_MSALIST: result = obj_migdata_get_authoritydata(hObject, subFlag, pulAttribDataSize, prgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_MIGATTRIB_MIG_AUTH_DATA: switch (subFlag) { case TSS_MIGATTRIB_MIG_AUTH_AUTHORITY_DIGEST: case TSS_MIGATTRIB_MIG_AUTH_DESTINATION_DIGEST: case TSS_MIGATTRIB_MIG_AUTH_SOURCE_DIGEST: result = obj_migdata_get_migauthdata(hObject, subFlag, pulAttribDataSize, prgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; case TSS_MIGATTRIB_TICKET_DATA: switch (subFlag) { case TSS_MIGATTRIB_TICKET_SIG_TICKET: result = obj_migdata_get_ticketdata(hObject, subFlag, pulAttribDataSize, prgbAttribData); break; default: return TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); } break; default: return TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } #endif } else { if (obj_is_hash(hObject) || obj_is_pcrs(hObject)) result = TSPERR(TSS_E_BAD_PARAMETER); else result = TSPERR(TSS_E_INVALID_HANDLE); } return result; } trousers-0.3.15/src/tspi/tsp_quote2.c0000664000175000017510000000642013663651711016775 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_Quote2(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE *antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TSS_BOOL addVersion, /* in */ TPM_AUTH * privAuth, /* in,out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * versionInfoSize, /* out */ BYTE ** versionInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result; UINT32 handlesLen, dataLen, decLen; TCS_HANDLE *handles, handle; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; dataLen = sizeof(TCPA_NONCE) + pcrDataSizeIn + sizeof(TSS_BOOL); if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_NONCE(&offset, data, antiReplay); Trspi_LoadBlob(&offset, pcrDataSizeIn, data, pcrDataIn); Trspi_LoadBlob_BOOL(&offset, addVersion, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Quote2, dataLen, data, &pubKeyHash, &handlesLen, &handles, privAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_PCR_INFO_SHORT(&offset, dec, NULL); *pcrDataSizeOut = offset; if ((*pcrDataOut = malloc(*pcrDataSizeOut)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *pcrDataSizeOut); *pcrDataSizeOut = 0; return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_UnloadBlob(&offset, *pcrDataSizeOut, dec, *pcrDataOut); Trspi_UnloadBlob_UINT32(&offset, versionInfoSize, dec); if ((*versionInfo = malloc(*versionInfoSize)) == NULL) { free(*pcrDataOut); *pcrDataOut = NULL; *pcrDataSizeOut = 0; free(dec); LogError("malloc of %u bytes failed", *versionInfoSize); *versionInfoSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *versionInfoSize, dec, *versionInfo); Trspi_UnloadBlob_UINT32(&offset, sigSize, dec); if ((*sig = malloc(*sigSize)) == NULL) { free(*versionInfo); *versionInfo = NULL; *versionInfoSize = 0; free(*pcrDataOut); *pcrDataOut = NULL; *pcrDataSizeOut = 0; free(dec); LogError("malloc of %u bytes failed", *sigSize); *sigSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *sigSize, dec, *sig); free(dec); return result; } #endif trousers-0.3.15/src/tspi/tspi_pcr_comp.c0000664000175000017510000000257013663651711017533 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_PcrComposite_SetPcrValue(TSS_HPCRS hPcrComposite, /* in */ UINT32 ulPcrIndex, /* in */ UINT32 ulPcrValueLength, /* in */ BYTE * rgbPcrValue) /* in */ { if (ulPcrValueLength == 0 || rgbPcrValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (ulPcrValueLength != TCPA_SHA1_160_HASH_LEN) return TSPERR(TSS_E_BAD_PARAMETER); return obj_pcrs_set_value(hPcrComposite, ulPcrIndex, ulPcrValueLength, rgbPcrValue); } TSS_RESULT Tspi_PcrComposite_GetPcrValue(TSS_HPCRS hPcrComposite, /* in */ UINT32 ulPcrIndex, /* in */ UINT32 * pulPcrValueLength, /* out */ BYTE ** prgbPcrValue) /* out */ { if (pulPcrValueLength == NULL || prgbPcrValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); return obj_pcrs_get_value(hPcrComposite, ulPcrIndex, pulPcrValueLength, prgbPcrValue); } TSS_RESULT Tspi_PcrComposite_SelectPcrIndex(TSS_HPCRS hPcrComposite, /* in */ UINT32 ulPcrIndex) /* in */ { return obj_pcrs_select_index(hPcrComposite, ulPcrIndex); } trousers-0.3.15/src/tspi/obj_policy.c0000664000175000017510000012175713663651711017034 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "tsp_delegate.h" #include "authsess.h" TSS_RESULT obj_policy_add(TSS_HCONTEXT tsp_context, UINT32 type, TSS_HOBJECT *phObject) { struct tr_policy_obj *policy; TSS_RESULT result; if ((policy = calloc(1, sizeof(struct tr_policy_obj))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(struct tr_policy_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } policy->type = type; #ifndef TSS_SPEC_COMPLIANCE policy->SecretMode = TSS_SECRET_MODE_NONE; #else policy->SecretMode = TSS_SECRET_MODE_POPUP; #endif /* The policy object will inherit this attribute from the context */ if ((result = obj_context_get_hash_mode(tsp_context, &policy->hashMode))) { free(policy); return result; } policy->SecretLifetime = TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS; #ifdef TSS_BUILD_DELEGATION policy->delegationType = TSS_DELEGATIONTYPE_NONE; #endif if ((result = obj_list_add(&policy_list, tsp_context, 0, policy, phObject))) { free(policy); return result; } return TSS_SUCCESS; } void __tspi_policy_free(void *data) { struct tr_policy_obj *policy = (struct tr_policy_obj *)data; free(policy->popupString); #ifdef TSS_BUILD_DELEGATION free(policy->delegationBlob); #endif free(policy); } TSS_RESULT obj_policy_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { TSS_RESULT result; if ((result = obj_list_remove(&policy_list, &__tspi_policy_free, hObject, tspContext))) return result; obj_lists_remove_policy_refs(hObject, tspContext); return TSS_SUCCESS; } TSS_BOOL obj_is_policy(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&policy_list, hObject))) { answer = TRUE; obj_list_put(&policy_list); } return answer; } TSS_RESULT obj_policy_get_type(TSS_HPOLICY hPolicy, UINT32 *type) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *type = policy->type; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_set_type(TSS_HPOLICY hPolicy, UINT32 type) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; policy->type = type; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_get_tsp_context(TSS_HPOLICY hPolicy, TSS_HCONTEXT *tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_do_hmac(TSS_HPOLICY hPolicy, TSS_HOBJECT hAuthorizedObject, TSS_BOOL returnOrVerify, UINT32 ulPendingFunction, TSS_BOOL continueUse, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulSizeDigestHmac, BYTE *rgbParamDigest, BYTE *rgbHmacData) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; result = policy->Tspicb_CallbackHMACAuth( policy->hmacAppData, hAuthorizedObject, returnOrVerify, ulPendingFunction, continueUse, ulSizeNonces, rgbNonceEven, rgbNonceOdd, rgbNonceEvenOSAP, rgbNonceOddOSAP, ulSizeDigestHmac, rgbParamDigest, rgbHmacData); obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_secret(TSS_HPOLICY hPolicy, TSS_BOOL ctx, TCPA_SECRET *secret) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; TCPA_SECRET null_secret; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; __tspi_memset(&null_secret, 0, sizeof(TCPA_SECRET)); switch (policy->SecretMode) { case TSS_SECRET_MODE_POPUP: /* if the secret is still NULL, grab it using the GUI */ if (policy->SecretSet == FALSE) { if ((result = popup_GetSecret(ctx, policy->hashMode, policy->popupString, policy->Secret))) break; } policy->SecretSet = TRUE; /* fall through */ case TSS_SECRET_MODE_PLAIN: case TSS_SECRET_MODE_SHA1: if (policy->SecretSet == FALSE) { result = TSPERR(TSS_E_POLICY_NO_SECRET); break; } memcpy(secret, policy->Secret, sizeof(TCPA_SECRET)); break; case TSS_SECRET_MODE_NONE: memcpy(secret, &null_secret, sizeof(TCPA_SECRET)); break; default: result = TSPERR(TSS_E_POLICY_NO_SECRET); break; } #ifdef TSS_DEBUG if (!result) { LogDebug("Got a secret:"); LogDebugData(20, (BYTE *)secret); } #endif obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_flush_secret(TSS_HPOLICY hPolicy) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; __tspi_memset(&policy->Secret, 0, policy->SecretSize); policy->SecretSet = FALSE; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_set_secret_object(TSS_HPOLICY hPolicy, TSS_FLAG mode, UINT32 size, TCPA_DIGEST *digest, TSS_BOOL set) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; /* if this is going to be a callback policy, the * callbacks need to already be set. (See TSS 1.1b * spec pg. 62). */ if (mode == TSS_SECRET_MODE_CALLBACK) { if (policy->Tspicb_CallbackHMACAuth == NULL) { result = TSPERR(TSS_E_FAIL); goto done; } } if (policy->SecretLifetime == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER) { policy->SecretCounter = policy->SecretTimeStamp; } else if (policy->SecretLifetime == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER) { time_t t = time(NULL); if (t == ((time_t)-1)) { LogError("time failed: %s", strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } policy->SecretTimeStamp = t; } memcpy(policy->Secret, digest, size); policy->SecretMode = mode; policy->SecretSize = size; policy->SecretSet = set; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_is_secret_set(TSS_HPOLICY hPolicy, TSS_BOOL *secretSet) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *secretSet = policy->SecretSet; obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_set_secret(TSS_HPOLICY hPolicy, TSS_FLAG mode, UINT32 size, BYTE *data) { TCPA_DIGEST digest; UINT32 secret_size = 0; TSS_BOOL secret_set = TRUE; TSS_RESULT result; __tspi_memset(&digest.digest, 0, sizeof(TCPA_DIGEST)); switch (mode) { case TSS_SECRET_MODE_PLAIN: if ((result = Trspi_Hash(TSS_HASH_SHA1, size, data, (BYTE *)&digest.digest))) return result; secret_size = TCPA_SHA1_160_HASH_LEN; break; case TSS_SECRET_MODE_SHA1: if (size != TCPA_SHA1_160_HASH_LEN) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(&digest.digest, data, size); secret_size = TCPA_SHA1_160_HASH_LEN; break; case TSS_SECRET_MODE_POPUP: case TSS_SECRET_MODE_NONE: secret_set = FALSE; case TSS_SECRET_MODE_CALLBACK: break; default: return TSPERR(TSS_E_BAD_PARAMETER); } return obj_policy_set_secret_object(hPolicy, mode, secret_size, &digest, secret_set); } TSS_RESULT obj_policy_get_cb11(TSS_HPOLICY hPolicy, TSS_FLAG type, UINT32 *cb) { #ifndef __LP64__ struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; switch (type) { case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: *cb = (UINT32)policy->Tspicb_CallbackHMACAuth; break; case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: *cb = (UINT32)policy->Tspicb_CallbackXorEnc; break; case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: *cb = (UINT32)policy->Tspicb_CallbackTakeOwnership; break; case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: *cb = (UINT32)policy->Tspicb_CallbackChangeAuthAsym; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } obj_list_put(&policy_list); return result; #else return TSPERR(TSS_E_FAIL); #endif } TSS_RESULT obj_policy_set_cb11(TSS_HPOLICY hPolicy, TSS_FLAG type, TSS_FLAG app_data, UINT32 cb) { #ifndef __LP64__ struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; switch (type) { case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: policy->Tspicb_CallbackHMACAuth = (PVOID)cb; policy->hmacAppData = (PVOID)app_data; break; case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: policy->Tspicb_CallbackXorEnc = (PVOID)cb; policy->xorAppData = (PVOID)app_data; break; case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: policy->Tspicb_CallbackTakeOwnership = (PVOID)cb; policy->takeownerAppData = (PVOID)app_data; break; case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: policy->Tspicb_CallbackChangeAuthAsym = (PVOID)cb; policy->changeauthAppData = (PVOID)app_data; break; default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } obj_list_put(&policy_list); return result; #else return TSPERR(TSS_E_FAIL); #endif } TSS_RESULT obj_policy_set_cb12(TSS_HPOLICY hPolicy, TSS_FLAG flag, BYTE *in) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; TSS_CALLBACK *cb = (TSS_CALLBACK *)in; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; switch (flag) { case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: if (!cb) { policy->Tspicb_CallbackHMACAuth = NULL; break; } policy->Tspicb_CallbackHMACAuth = (TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_BOOL, UINT32, TSS_BOOL, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *)) cb->callback; policy->hmacAppData = cb->appData; policy->hmacAlg = cb->alg; break; case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: if (!cb) { policy->Tspicb_CallbackXorEnc = NULL; break; } policy->Tspicb_CallbackXorEnc = (TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_HOBJECT, TSS_FLAG, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *)) cb->callback; policy->xorAppData = cb->appData; policy->xorAlg = cb->alg; break; case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: if (!cb) { policy->Tspicb_CallbackTakeOwnership = NULL; break; } policy->Tspicb_CallbackTakeOwnership = (TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_HKEY, UINT32, BYTE *))cb->callback; policy->takeownerAppData = cb->appData; policy->takeownerAlg = cb->alg; break; case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: if (!cb) { policy->Tspicb_CallbackChangeAuthAsym = NULL; break; } policy->Tspicb_CallbackChangeAuthAsym = (TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_HKEY, UINT32, UINT32, BYTE *, BYTE *))cb->callback; policy->changeauthAppData = cb->appData; policy->changeauthAlg = cb->alg; break; #ifdef TSS_BUILD_SEALX case TSS_TSPATTRIB_POLICY_CALLBACK_SEALX_MASK: if (!cb) { policy->Tspicb_CallbackSealxMask = NULL; policy->sealxAppData = NULL; policy->sealxAlg = 0; break; } policy->Tspicb_CallbackSealxMask = (TSS_RESULT (*)(PVOID, TSS_HKEY, TSS_HENCDATA, TSS_ALGORITHM_ID, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *))cb->callback; policy->sealxAppData = cb->appData; policy->sealxAlg = cb->alg; break; #endif default: result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_cb12(TSS_HPOLICY hPolicy, TSS_FLAG flag, UINT32 *size, BYTE **out) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; TSS_CALLBACK *cb; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if ((cb = calloc_tspi(obj->tspContext, sizeof(TSS_CALLBACK))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_CALLBACK)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } switch (flag) { case TSS_TSPATTRIB_POLICY_CALLBACK_HMAC: cb->callback = policy->Tspicb_CallbackHMACAuth; cb->appData = policy->hmacAppData; cb->alg = policy->hmacAlg; *size = sizeof(TSS_CALLBACK); *out = (BYTE *)cb; break; case TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC: cb->callback = policy->Tspicb_CallbackXorEnc; cb->appData = policy->xorAppData; cb->alg = policy->xorAlg; *size = sizeof(TSS_CALLBACK); *out = (BYTE *)cb; break; case TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP: cb->callback = policy->Tspicb_CallbackTakeOwnership; cb->appData = policy->takeownerAppData; cb->alg = policy->takeownerAlg; *size = sizeof(TSS_CALLBACK); *out = (BYTE *)cb; break; case TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM: cb->callback = policy->Tspicb_CallbackChangeAuthAsym; cb->appData = policy->changeauthAppData; cb->alg = policy->changeauthAlg; *size = sizeof(TSS_CALLBACK); *out = (BYTE *)cb; break; #ifdef TSS_BUILD_SEALX case TSS_TSPATTRIB_POLICY_CALLBACK_SEALX_MASK: cb->callback = policy->Tspicb_CallbackSealxMask; cb->appData = policy->sealxAppData; cb->alg = policy->sealxAlg; *size = sizeof(TSS_CALLBACK); *out = (BYTE *)cb; break; #endif default: free_tspi(obj->tspContext, cb); result = TSPERR(TSS_E_INVALID_ATTRIB_FLAG); break; } done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_lifetime(TSS_HPOLICY hPolicy, UINT32 *lifetime) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *lifetime = policy->SecretLifetime; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_set_lifetime(TSS_HPOLICY hPolicy, UINT32 type, UINT32 value) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; time_t t; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; switch (type) { case TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS: policy->SecretCounter = 0; policy->SecretLifetime = TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS; policy->SecretTimeStamp = 0; break; case TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER: /* Both SecretCounter and SecretTimeStamp will receive value. Every time the * policy is used, SecretCounter will be decremented. Each time SetSecret is * called, SecretCounter will get the value stored in SecretTimeStamp */ policy->SecretCounter = value; policy->SecretLifetime = TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER; policy->SecretTimeStamp = value; break; case TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER: t = time(NULL); if (t == ((time_t)-1)) { LogError("time failed: %s", strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); break; } /* For mode time, we'll use the SecretCounter variable to hold the number * of seconds we're valid and the SecretTimeStamp var to record the current * timestamp. This should protect against overflows. */ policy->SecretCounter = value; policy->SecretLifetime = TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER; policy->SecretTimeStamp = t; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); break; } obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_mode(TSS_HPOLICY hPolicy, UINT32 *mode) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *mode = policy->SecretMode; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_get_counter(TSS_HPOLICY hPolicy, UINT32 *counter) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->SecretLifetime == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER) *counter = policy->SecretCounter; else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_dec_counter(TSS_HPOLICY hPolicy) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; /* Only decrement if SecretCounter > 0, otherwise it could loop and become valid again */ if (policy->SecretLifetime == TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER && policy->SecretCounter > 0) { policy->SecretCounter--; } obj_list_put(&policy_list); return TSS_SUCCESS; } /* return a unicode string to the Tspi_GetAttribData function */ TSS_RESULT obj_policy_get_string(TSS_HPOLICY hPolicy, UINT32 *size, BYTE **data) { TSS_RESULT result = TSS_SUCCESS; BYTE *utf_string; UINT32 utf_size; struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *size = policy->popupStringLength; if (policy->popupStringLength == 0) { *data = NULL; } else { utf_size = policy->popupStringLength; utf_string = Trspi_Native_To_UNICODE(policy->popupString, &utf_size); if (utf_string == NULL) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *data = calloc_tspi(obj->tspContext, utf_size); if (*data == NULL) { free(utf_string); LogError("malloc of %d bytes failed.", utf_size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = utf_size; memcpy(*data, utf_string, utf_size); free(utf_string); } done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_set_string(TSS_HPOLICY hPolicy, UINT32 size, BYTE *data) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; free(policy->popupString); policy->popupString = data; policy->popupStringLength = size; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_get_secs_until_expired(TSS_HPOLICY hPolicy, UINT32 *secs) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_policy_obj *policy; int seconds_elapsed; time_t t; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->SecretLifetime != TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } if ((t = time(NULL)) == ((time_t)-1)) { LogError("time failed: %s", strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } /* curtime - SecretTimeStamp is the number of seconds elapsed since we started the timer. * SecretCounter is the number of seconds the secret is valid. If * seconds_elspased > SecretCounter, we've expired. */ seconds_elapsed = t - policy->SecretTimeStamp; if ((UINT32)seconds_elapsed >= policy->SecretCounter) { *secs = 0; } else { *secs = policy->SecretCounter - seconds_elapsed; } done: obj_list_put(&policy_list); return result; } TSS_RESULT policy_has_expired(struct tr_policy_obj *policy, TSS_BOOL *answer) { switch (policy->SecretLifetime) { case TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS: *answer = FALSE; break; case TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER: *answer = (policy->SecretCounter == 0 ? TRUE : FALSE); break; case TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER: { int seconds_elapsed; time_t t = time(NULL); if (t == ((time_t)-1)) { LogError("time failed: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* curtime - SecretTimer is the number of seconds elapsed since we * started the timer. SecretCounter is the number of seconds the * secret is valid. If seconds_elspased > SecretCounter, we've * expired. */ seconds_elapsed = t - policy->SecretTimeStamp; *answer = ((UINT32)seconds_elapsed >= policy->SecretCounter ? TRUE : FALSE); break; } default: LogError("policy has an undefined secret lifetime!"); return TSPERR(TSS_E_INVALID_OBJ_ACCESS); } return TSS_SUCCESS; } TSS_RESULT obj_policy_has_expired(TSS_HPOLICY hPolicy, TSS_BOOL *answer) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; result = policy_has_expired(policy, answer); obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_xsap_params(TSS_HPOLICY hPolicy, TPM_COMMAND_CODE command, TPM_ENTITY_TYPE *et, UINT32 *entity_value_size, BYTE **entity_value, BYTE *secret, TSS_CALLBACK *cb_xor, TSS_CALLBACK *cb_hmac, TSS_CALLBACK *cb_sealx, UINT32 *mode, TSS_BOOL new_secret) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result; TSS_BOOL answer = FALSE; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if ((result = policy_has_expired(policy, &answer))) goto done; if (answer) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } #ifdef TSS_BUILD_DELEGATION /* if the delegation index or blob is set, check to see if the command is delegated, if so, * return the blob or index as the secret data */ if (command && (policy->delegationType != TSS_DELEGATIONTYPE_NONE)) { if (policy->delegationBlob) { if ((*entity_value = malloc(policy->delegationBlobLength)) == NULL) { LogError("malloc of %u bytes failed.", policy->delegationBlobLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*entity_value, policy->delegationBlob, policy->delegationBlobLength); *entity_value_size = policy->delegationBlobLength; if (policy->delegationType == TSS_DELEGATIONTYPE_OWNER) *et = TPM_ET_DEL_OWNER_BLOB; else *et = TPM_ET_DEL_KEY_BLOB; } else { if ((*entity_value = malloc(sizeof(UINT32))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(UINT32)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *(UINT32 *)entity_value = policy->delegationIndex; *entity_value_size = sizeof(UINT32); *et = TPM_ET_DEL_ROW; } } #endif /* Either this is a policy set to mode callback, in which case both xor and hmac addresses * must be set, or this is an encrypted data object's policy, where its mode is independent * of whether a sealx callback is set */ if (policy->SecretMode == TSS_SECRET_MODE_CALLBACK && cb_xor && cb_hmac) { if ((policy->Tspicb_CallbackXorEnc && !policy->Tspicb_CallbackHMACAuth) || (!policy->Tspicb_CallbackXorEnc && policy->Tspicb_CallbackHMACAuth)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } cb_xor->callback = policy->Tspicb_CallbackXorEnc; cb_xor->appData = policy->xorAppData; cb_xor->alg = policy->xorAlg; cb_hmac->callback = policy->Tspicb_CallbackHMACAuth; cb_hmac->appData = policy->hmacAppData; cb_hmac->alg = policy->hmacAlg; #ifdef TSS_BUILD_SEALX } else if (cb_sealx && policy->Tspicb_CallbackSealxMask) { cb_sealx->callback = policy->Tspicb_CallbackSealxMask; cb_sealx->appData = policy->sealxAppData; cb_sealx->alg = policy->sealxAlg; #endif } if ((policy->SecretMode == TSS_SECRET_MODE_POPUP) && (policy->SecretSet == FALSE)) { if ((result = popup_GetSecret(new_secret, policy->hashMode, policy->popupString, policy->Secret))) goto done; policy->SecretSet = TRUE; } memcpy(secret, policy->Secret, TPM_SHA1_160_HASH_LEN); *mode = policy->SecretMode; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_do_xor(TSS_HPOLICY hPolicy, TSS_HOBJECT hOSAPObject, TSS_HOBJECT hObject, TSS_FLAG PurposeSecret, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulSizeEncAuth, BYTE *rgbEncAuthUsage, BYTE *rgbEncAuthMigration) { TSS_RESULT result; struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; result = policy->Tspicb_CallbackXorEnc(policy->xorAppData, hOSAPObject, hObject, PurposeSecret, ulSizeNonces, rgbNonceEven, rgbNonceOdd, rgbNonceEvenOSAP, rgbNonceOddOSAP, ulSizeEncAuth, rgbEncAuthUsage, rgbEncAuthMigration); obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_do_takeowner(TSS_HPOLICY hPolicy, TSS_HOBJECT hObject, TSS_HKEY hObjectPubKey, UINT32 ulSizeEncAuth, BYTE *rgbEncAuth) { TSS_RESULT result; struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; result = policy->Tspicb_CallbackTakeOwnership( policy->takeownerAppData, hObject, hObjectPubKey, ulSizeEncAuth, rgbEncAuth); obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_hash_mode(TSS_HPOLICY hPolicy, UINT32 *mode) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *mode = policy->hashMode; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_set_hash_mode(TSS_HPOLICY hPolicy, UINT32 mode) { struct tsp_object *obj; struct tr_policy_obj *policy; switch (mode) { case TSS_TSPATTRIB_HASH_MODE_NULL: case TSS_TSPATTRIB_HASH_MODE_NOT_NULL: break; default: return TSPERR(TSS_E_INVALID_ATTRIB_DATA); } if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; policy->hashMode = mode; obj_list_put(&policy_list); return TSS_SUCCESS; } #ifdef TSS_BUILD_DELEGATION TSS_RESULT obj_policy_set_delegation_type(TSS_HPOLICY hPolicy, UINT32 type) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; switch (type) { case TSS_DELEGATIONTYPE_NONE: obj_policy_clear_delegation(policy); break; case TSS_DELEGATIONTYPE_OWNER: case TSS_DELEGATIONTYPE_KEY: if (policy->delegationIndexSet || policy->delegationBlob) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } break; } policy->delegationType = type; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_type(TSS_HPOLICY hPolicy, UINT32 *type) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *type = policy->delegationType; obj_list_put(&policy_list); return TSS_SUCCESS; } TSS_RESULT obj_policy_set_delegation_index(TSS_HPOLICY hPolicy, UINT32 index) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if ((result = get_delegate_index(obj->tspContext, index, &public))) goto done; free(public.pcrInfo.pcrSelection.pcrSelect); obj_policy_clear_delegation(policy); switch (public.permissions.delegateType) { case TPM_DEL_OWNER_BITS: policy->delegationType = TSS_DELEGATIONTYPE_OWNER; break; case TPM_DEL_KEY_BITS: policy->delegationType = TSS_DELEGATIONTYPE_KEY; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } policy->delegationIndex = index; policy->delegationIndexSet = TRUE; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_index(TSS_HPOLICY hPolicy, UINT32 *index) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (!policy->delegationIndexSet) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } *index = policy->delegationIndex; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_set_delegation_per1(TSS_HPOLICY hPolicy, UINT32 per1) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } policy->delegationPer1 = per1; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_per1(TSS_HPOLICY hPolicy, UINT32 *per1) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; *per1 = public.permissions.per1; free(public.pcrInfo.pcrSelection.pcrSelect); } else *per1 = policy->delegationPer1; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_set_delegation_per2(TSS_HPOLICY hPolicy, UINT32 per2) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } policy->delegationPer2 = per2; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_per2(TSS_HPOLICY hPolicy, UINT32 *per2) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; *per2 = public.permissions.per2; free(public.pcrInfo.pcrSelection.pcrSelect); } else *per2 = policy->delegationPer2; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_set_delegation_blob(TSS_HPOLICY hPolicy, UINT32 type, UINT32 blobLength, BYTE *blob) { struct tsp_object *obj; struct tr_policy_obj *policy; UINT16 tag; UINT64 offset; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; obj_policy_clear_delegation(policy); if (blobLength == 0) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } offset = 0; Trspi_UnloadBlob_UINT16(&offset, &tag, blob); switch (tag) { case TPM_TAG_DELEGATE_OWNER_BLOB: if (type && (type != TSS_DELEGATIONTYPE_OWNER)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } policy->delegationType = TSS_DELEGATIONTYPE_OWNER; break; case TPM_TAG_DELG_KEY_BLOB: if (type && (type != TSS_DELEGATIONTYPE_KEY)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } policy->delegationType = TSS_DELEGATIONTYPE_KEY; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } if ((policy->delegationBlob = malloc(blobLength)) == NULL) { LogError("malloc of %u bytes failed.", blobLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } policy->delegationBlobLength = blobLength; memcpy(policy->delegationBlob, blob, blobLength); done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_blob(TSS_HPOLICY hPolicy, UINT32 type, UINT32 *blobLength, BYTE **blob) { struct tsp_object *obj; struct tr_policy_obj *policy; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationBlobLength == 0) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } if (type && (type != policy->delegationType)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } if ((*blob = calloc_tspi(obj->tspContext, policy->delegationBlobLength)) == NULL) { LogError("malloc of %u bytes failed.", policy->delegationBlobLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*blob, policy->delegationBlob, policy->delegationBlobLength); *blobLength = policy->delegationBlobLength; done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_label(TSS_HPOLICY hPolicy, BYTE *label) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; *label = public.label.label; free(public.pcrInfo.pcrSelection.pcrSelect); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_familyid(TSS_HPOLICY hPolicy, UINT32 *familyID) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; *familyID = public.familyID; free(public.pcrInfo.pcrSelection.pcrSelect); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_vercount(TSS_HPOLICY hPolicy, UINT32 *verCount) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; *verCount = public.verificationCount; free(public.pcrInfo.pcrSelection.pcrSelect); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_pcr_locality(TSS_HPOLICY hPolicy, UINT32 *locality) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; *locality = public.pcrInfo.localityAtRelease; free(public.pcrInfo.pcrSelection.pcrSelect); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_pcr_digest(TSS_HPOLICY hPolicy, UINT32 *digestLength, BYTE **digest) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; *digest = calloc_tspi(obj->tspContext, TPM_SHA1_160_HASH_LEN); if (*digest == NULL) { LogError("malloc of %u bytes failed.", TPM_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*digest, &public.pcrInfo.digestAtRelease.digest, TPM_SHA1_160_HASH_LEN); *digestLength = TPM_SHA1_160_HASH_LEN; free(public.pcrInfo.pcrSelection.pcrSelect); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_get_delegation_pcr_selection(TSS_HPOLICY hPolicy, UINT32 *selectionLength, BYTE **selection) { struct tsp_object *obj; struct tr_policy_obj *policy; TPM_DELEGATE_PUBLIC public; UINT64 offset; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet || policy->delegationBlob) { if ((result = obj_policy_get_delegate_public(obj, &public))) goto done; offset = 0; Trspi_LoadBlob_PCR_SELECTION(&offset, NULL, &public.pcrInfo.pcrSelection); *selection = calloc_tspi(obj->tspContext, offset); if (*selection == NULL) { LogError("malloc of %u bytes failed.", (UINT32)offset); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_PCR_SELECTION(&offset, *selection, &public.pcrInfo.pcrSelection); *selectionLength = offset; free(public.pcrInfo.pcrSelection.pcrSelect); } else result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); done: obj_list_put(&policy_list); return result; } TSS_RESULT obj_policy_is_delegation_index_set(TSS_HPOLICY hPolicy, TSS_BOOL *indexSet) { struct tsp_object *obj; struct tr_policy_obj *policy; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; *indexSet = policy->delegationIndexSet; obj_list_put(&policy_list); return TSS_SUCCESS; } void obj_policy_clear_delegation(struct tr_policy_obj *policy) { free(policy->delegationBlob); policy->delegationType = TSS_DELEGATIONTYPE_NONE; policy->delegationPer1 = 0; policy->delegationPer2 = 0; policy->delegationIndexSet = FALSE; policy->delegationIndex = 0; policy->delegationBlobLength = 0; policy->delegationBlob = NULL; } TSS_RESULT obj_policy_get_delegate_public(struct tsp_object *obj, TPM_DELEGATE_PUBLIC *public) { struct tr_policy_obj *policy; UINT16 tag; TPM_DELEGATE_OWNER_BLOB ownerBlob; TPM_DELEGATE_KEY_BLOB keyBlob; UINT64 offset; TSS_RESULT result; policy = (struct tr_policy_obj *)obj->data; if (policy->delegationIndexSet) { if ((result = get_delegate_index(obj->tspContext, policy->delegationIndex, public))) return result; } else if (policy->delegationBlob) { offset = 0; Trspi_UnloadBlob_UINT16(&offset, &tag, policy->delegationBlob); offset = 0; switch (tag) { case TPM_TAG_DELEGATE_OWNER_BLOB: if ((result = Trspi_UnloadBlob_TPM_DELEGATE_OWNER_BLOB(&offset, policy->delegationBlob, &ownerBlob))) return result; *public = ownerBlob.pub; free(ownerBlob.additionalArea); free(ownerBlob.sensitiveArea); break; case TPM_TAG_DELG_KEY_BLOB: if ((result = Trspi_UnloadBlob_TPM_DELEGATE_KEY_BLOB(&offset, policy->delegationBlob, &keyBlob))) return result; *public = keyBlob.pub; free(keyBlob.additionalArea); free(keyBlob.sensitiveArea); break; default: return TSPERR(TSS_E_INTERNAL_ERROR); } } else return TSPERR(TSS_E_INTERNAL_ERROR); return TSS_SUCCESS; } #endif trousers-0.3.15/src/tspi/tspi_daa.c0000664000175000017510000006071313663651711016461 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" //#include "trousers_types.h" #include "spi_utils.h" //#include "capabilities.h" #include "tsplog.h" //#include "tcs_tsp.h" //#include "tspps.h" //#include "hosttable.h" //#include "tcsd_wrap.h" //#include "tcsd.h" #include "obj.h" #include "daa/issuer.h" #include "daa/platform.h" #include "daa/verifier.h" #include "daa/anonymity_revocation.h" #include "daa/key_correct.h" #include "daa/issuer.h" // static TSS_HCONTEXT _hContext; static void *tss_alloc( size_t size, TSS_HOBJECT hContext) { void *ret = calloc_tspi( hContext, size); LogDebug("[intern_alloc (%d)] -> %d", (int)size, (int)ret); return ret; } /* static void *normal_malloc( size_t size, TSS_HOBJECT object) { void *ret = malloc( size); return ret; } */ /** This is the first out of 3 functions to execute in order to receive a DAA Credential. It verifies the keys of the DAA Issuer and computes the TPM DAA public key. Parameters - hDAA: Handle of the DAA object - hTPM: Handle of the TPM object - daaCounter: DAA counter - issuerPk: Handle of the DAA Issuer public key - issuerAuthPKsLength: Length of the array of issuerAuthPKs - issuerAuthPKs:Handle of an array of RSA public keys (key chain) of the DAA Issuer used to authenticate the DAA Issuer public key. The size of the modulus must be TPM_DAA_SIZE_issuerModulus (256) - issuerAuthPKSignaturesLength:Length of the array of issuerAuthPKSignatures. It is equal to issuerAuthPKsLength . The length of an element of the array is TPM_DAA_SIZE_issuerModulus (256) - issuerAuthPKSignatures: An array of byte arrays representing signatures on the modulus of the above key chain (issuerAuthPKs) in more details, the array has the following content (S(K[1],K[0]),S(K[2],N[1]),..S(K[ k ],K[n-1]), S(TPM_DAA_ISSUER,K[ k ])), where S(msg,privateKey) denotes the signature function with msg being signed by the privateKey. - capitalUprimeLength: Length of capitalUprime which is ln/8. ln is defined as the size of the RSA modulus (2048). - capitalUprime: U? - identityProof: This structure contains the endorsement, platform and conformance credential. - joinSession: This structure contains DAA Join session information. */ #if 0 TSPICALL Tspi_TPM_DAA_JoinInit(TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in UINT32 daaCounter, // in TSS_HDAA_DATA issuerPk, // in UINT32 issuerAuthPKsLength, // in TSS_HKEY* issuerAuthPKs, // in UINT32 issuerAuthPKSignaturesLength, // in BYTE** issuerAuthPKSignatures, // in UINT32* capitalUprimeLength, // out BYTE** capitalUprime, // out TSS_DAA_IDENTITY_PROOF** identityProof, // out TSS_DAA_JOIN_SESSION** joinSession) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("-> TSPI_TPM_DAA_joinInit hDAA=%x hTPM=%x daaCounter=%x issuerPk=%x", (int)hDAA, (int)hTPM, daaCounter, (int)issuerPk); result = Tspi_TPM_DAA_JoinInit_internal( hDAA, hTPM, daaCounter, (TSS_DAA_PK *)issuerPk, issuerAuthPKsLength, (RSA **)issuerAuthPKs, issuerAuthPKSignaturesLength, issuerAuthPKSignatures, capitalUprimeLength, capitalUprime, identityProof, joinSession); bi_flush_memory(); LogDebug("TSPI_TPM_DAA_joinInit ALLOC DELTA:%d",mallinfo().uordblks-before); LogDebug("<- TSPI_TPM_DAA_joinInit result=%d", result); return result; } #else TSS_RESULT Tspi_TPM_DAA_JoinInit(TSS_HTPM hTPM, /* in */ TSS_HDAA_ISSUER_KEY hIssuerKey, /* in */ UINT32 daaCounter, /* in */ UINT32 issuerAuthPKsLength, /* in */ TSS_HKEY* issuerAuthPKs, /* in */ UINT32 issuerAuthPKSignaturesLength, /* in */ UINT32 issuerAuthPKSignaturesLength2, /* in */ BYTE** issuerAuthPKSignatures, /* in */ UINT32* capitalUprimeLength, /* out */ BYTE** capitalUprime, /* out */ TSS_DAA_IDENTITY_PROOF** identityProof, /* out */ UINT32* joinSessionLength, /* out */ BYTE** joinSession) /* out */ { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif if (!capitalUprimeLength || !capitalUprime || !identityProof || !joinSessionLength || !joinSession) return TSPERR(TSS_E_BAD_PARAMETER); result = Tspi_TPM_DAA_JoinInit_internal(hTPM, hIssuerKey, daaCounter, issuerAuthPKsLength, issuerAuthPKs, issuerAuthPKSignaturesLength, issuerAuthPKSignaturesLength2, issuerAuthPKSignatures, capitalUprimeLength, capitalUprime, identityProof, joinSessionLength, joinSession); bi_flush_memory(); LogDebug("TSPI_TPM_DAA_joinInit ALLOC DELTA:%d",mallinfo().uordblks-before); LogDebug("<- TSPI_TPM_DAA_joinInit result=%d", result); return result; } #endif /** This function is part of the DAA Issuer component. It defines the generation of a DAA Issuer public and secret key. Further it defines the generation of a non-interactive proof (using the Fiat-Shamir heuristic) that the public keys were chosen correctly. The latter will guarantee the security requirements of the platform (respectively, its user), i.e., that the privacy and anonymity of signatures will hold. The generation of the authentication keys of the DAA Issuer, which are used to authenticate (main) DAA Issuer keys, is not defined by this function. This is an optional function and does not require a TPM or a TCS. Parameters - hDAA: Handle of the DAA object - issuerBaseNameLength: Length of issuerBaseName - issuerBaseName: Unique name of the DAA Issuer - numberPlatformAttributes: Number of attributes that the Platform can choose and which will not be visible to the Issuer. - numberIssuerAttributes:Number of attributes that the Issuer can choose and which will be visible to both the Platform and the Issuer. - keyPair: Handle of the main DAA Issuer key pair (private and public portion) - publicKeyProof:Handle of the proof of the main DAA Issuer public key */ #if 0 TSPICALL Tspi_DAA_IssueSetup(TSS_HDAA hDAA, // in UINT32 issuerBaseNameLength, // in BYTE* issuerBaseName, // in UINT32 numberPlatformAttributes, // in UINT32 numberIssuerAttributes, // in TSS_HDAA_DATA* keyPair, // out (TSS_KEY_PAIR) TSS_HDAA_DATA* publicKeyProof) // out (TSS_DAA_PK_PROOF) { TSS_RESULT result; KEY_PAIR_WITH_PROOF_internal *key_proof; TSS_DAA_KEY_PAIR *tss_daa_key_pair; TSS_HCONTEXT hContext; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug( "TSPI_DAA_IssueSetup hDAA=%d ",hDAA); // TODO: lock access to _hContext if ((result = obj_daa_get_tsp_context(hDAA, &hContext))) return result; result = generate_key_pair(numberIssuerAttributes, numberPlatformAttributes, issuerBaseNameLength, issuerBaseName, &key_proof); if (result != TSS_SUCCESS) return result; LogDebug("TSPI_DAA_IssueSetup convert internal structure to public allocated using tspi_alloc"); LogDebug("key_proof->proof->length_challenge=%d key_proof->proof->length_response=%d", key_proof->proof->length_challenge, key_proof->proof->length_response); // prepare out parameters *publicKeyProof = i_2_e_TSS_DAA_PK_PROOF( key_proof->proof, &tss_alloc, hContext); tss_daa_key_pair = (TSS_DAA_KEY_PAIR *)tss_alloc( sizeof(TSS_DAA_KEY_PAIR), hContext); if (tss_daa_key_pair == NULL) { LogError("malloc of %d bytes failed", sizeof(TSS_DAA_KEY_PAIR)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } tss_daa_key_pair->private_key = i_2_e_TSS_DAA_PRIVATE_KEY( key_proof->private_key, &tss_alloc, hContext); tss_daa_key_pair->public_key = i_2_e_TSS_DAA_PK( key_proof->pk, &tss_alloc, hContext); *keyPair = (TSS_HKEY)tss_daa_key_pair; close: bi_flush_memory(); LogDebug("TSPI_DAA_IssueSetup ALLOC DELTA:%d", mallinfo().uordblks-before); LogDebug( "TSPI_DAA_IssueSetup end return=%d ",result); return result; } #else TSS_RESULT Tspi_DAA_Issuer_GenerateKey(TSS_HDAA_ISSUER_KEY hIssuerKey, // in UINT32 issuerBaseNameLength, // in BYTE* issuerBaseName) // in { TSS_RESULT result; KEY_PAIR_WITH_PROOF_internal *key_proof; TSS_DAA_KEY_PAIR *tss_daa_key_pair; TSS_HCONTEXT tspContext; UINT32 numberPlatformAttributes, numberIssuerAttributes; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif if ((result = obj_daaissuerkey_get_tsp_context(hIssuerKey, &tspContext))) return result; if ((result = obj_daaissuerkey_get_attribs(hIssuerKey, &numberIssuerAttributes, &numberPlatformAttributes))) return result; if ((result = generate_key_pair(numberIssuerAttributes, numberPlatformAttributes, issuerBaseNameLength, issuerBaseName, &key_proof))) return result; LogDebugFn("convert internal structure to public allocated using tspi_alloc"); LogDebug("key_proof->proof->length_challenge=%d key_proof->proof->length_response=%d", key_proof->proof->length_challenge, key_proof->proof->length_response); // prepare out parameters *publicKeyProof = i_2_e_TSS_DAA_PK_PROOF( key_proof->proof, &tss_alloc, tspContext); tss_daa_key_pair = (TSS_DAA_KEY_PAIR *)tss_alloc( sizeof(TSS_DAA_KEY_PAIR), tspContext); if (tss_daa_key_pair == NULL) { LogError("malloc of %d bytes failed", sizeof(TSS_DAA_KEY_PAIR)); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } tss_daa_key_pair->private_key = i_2_e_TSS_DAA_PRIVATE_KEY( key_proof->private_key, &tss_alloc, tspContext); tss_daa_key_pair->public_key = i_2_e_TSS_DAA_PK( key_proof->pk, &tss_alloc, tspContext); *keyPair = (TSS_HKEY)tss_daa_key_pair; close: bi_flush_memory(); LogDebug("TSPI_DAA_IssueSetup ALLOC DELTA:%d", mallinfo().uordblks-before); LogDebug( "TSPI_DAA_IssueSetup end return=%d ",result); return result; } #endif /** This function is part of the DAA Issuer component. It's the first function out of 2 in order to issue a DAA Credential for a TCG Platform. It assumes that the endorsement key and its associated credentials are from a genuine and valid TPM. (Verification of the credentials is a process defined by the TCG Infrastructure WG.) This is an optional function and does not require a TPM or a TCS. */ TSPICALL Tspi_DAA_IssueInit(TSS_HDAA hDAA, // in TSS_HKEY issuerAuthPK, // in TSS_HDAA_DATA issuerKeyPair, // in (TSS_DAA_KEY_PAIR) TSS_DAA_IDENTITY_PROOF* identityProof, // in UINT32 capitalUprimeLength, // in BYTE* capitalUprime, // in UINT32 daaCounter, // in UINT32* nonceIssuerLength, // out BYTE** nonceIssuer, // out UINT32* authenticationChallengeLength, // out BYTE** authenticationChallenge, // out TSS_DAA_JOIN_ISSUER_SESSION** joinSession) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("Tspi_DAA_IssueInit_internal hDAA=%d daaCounter=%d", (int)hDAA, (int)daaCounter); result = Tspi_DAA_IssueInit_internal( hDAA, // in issuerAuthPK, // in issuerKeyPair, // in identityProof, // in capitalUprimeLength, // in capitalUprime, // in daaCounter, // in nonceIssuerLength, // out nonceIssuer, // out authenticationChallengeLength, // out authenticationChallenge, // out joinSession // out ); bi_flush_memory(); LogDebug("Tspi_DAA_IssueInit_internal ALLOC DELTA:%d", mallinfo().uordblks-before); return result; } /** This function verifies the DAA public key of a DAA Issuer with respect to its associated proof. This is a resource consuming task. It can be done by trusted third party (certification). This is an optional function and does not require a TPM or a TCS. Parameters: - hDAA: Handle of the DAA object - issuerPk: DAA Issuer public key - issuerPkProof: Proofs the correctness of the DAA Issuer public key - isCorrect: Proofs the correctness of the DAA Issuer public key */ TSPICALL Tspi_DAA_IssuerKeyVerification(TSS_HDAA hDAA, // in TSS_HDAA_DATA issuerPk, // in (TSS_DAA_PK) TSS_HDAA_DATA issuerPkProof, // in (TSS_DAA_PK_PROOF) TSS_BOOL* isCorrect) // out { TSS_RESULT result; int is_correct; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("TSPI_DAA_IssuerKeyVerification hDAA=%ld issuerPk=%ld issuerPkProof=%ld", (long)hDAA, (long)issuerPk, (long)issuerPkProof); TSS_DAA_PK_internal *pk_internal = e_2_i_TSS_DAA_PK( (TSS_DAA_PK *)issuerPk); TSS_DAA_PK_PROOF_internal *proof_internal = e_2_i_TSS_DAA_PK_PROOF( issuerPkProof); LogDebug( "challenge=[%s]", dump_byte_array( proof_internal->length_challenge, proof_internal->challenge)); result = is_pk_correct( pk_internal, proof_internal, &is_correct ); if( is_correct) *isCorrect = TRUE; else *isCorrect = FALSE; bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("TSPI_DAA_IssuerKeyVerification ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return result; } /** This function is part of the DAA Issuer component. It?s the last function out of 2 in order to issue DAA Credential for a TCG Platform. It detects rogue TPM according to published rogue TPM DAA keys. This is an optional function and does not require a TPM or a TCS. */ TSPICALL Tspi_DAA_IssueCredential(TSS_HDAA hDAA, // in UINT32 attributesIssuerLength, // in BYTE** attributesIssuer, // in TSS_DAA_CREDENTIAL_REQUEST* credentialRequest, // in TSS_DAA_JOIN_ISSUER_SESSION* joinSession, // in TSS_DAA_CRED_ISSUER** credIssuer) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("Tspi_DAA_IssueCredential hDAA=%d attributesIssuerLength=%d", (int)hDAA, (int)attributesIssuerLength); result = Tspi_DAA_IssueCredential_internal( hDAA, attributesIssuerLength, attributesIssuer, credentialRequest, joinSession, credIssuer ); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("Tspi_DAA_IssueCredential ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return result; } /** This function is part of the DAA Verifier component. It is the first function out of 2 in order to verify a DAA credential of a TCG platform. It creates a challenge for the TCG platform.last function out of 2 in order to issue a This is an optional function and does not require a TPM or a TCS. */ TSPICALL Tspi_DAA_VerifyInit(TSS_HDAA hDAA, // in UINT32* nonceVerifierLength, // out BYTE** nonceVerifier, // out UINT32* baseNameLength, // out BYTE** baseName) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif // TODO which interface to use ? with or without baseName ? LogDebug("Tspi_DAA_VerifyInit hDAA=%d", (int)hDAA); result = Tspi_DAA_VerifyInit_internal( hDAA, nonceVerifierLength, nonceVerifier, baseNameLength, baseName); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("Tspi_DAA_VerifyInit ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return result; } /** This function is part of the DAA Verifier component. It is the last function out of 2 in order to verify a DAA Credential of a TCG Platform. It verifies the DAA credential and detects public rogue TPMs. This is an optional function and does not require a TPM or a TCS. */ TSPICALL Tspi_DAA_VerifySignature(TSS_HDAA hDAA, // in TSS_DAA_SIGNATURE* daaSignature, // in TSS_HDAA_DATA hPubKeyIssuer, // in (TSS_DAA_PK) TSS_DAA_SIGN_DATA* signData, // in UINT32 attributesLength, // in BYTE** attributes, // in UINT32 nonceVerifierLength,// in BYTE* nonceVerifier, // in UINT32 baseNameLength, // in BYTE* baseName, // in TSS_BOOL* isCorrect) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("Tspi_DAA_VerifySignature hDAA=%d", (int)hDAA); result = Tspi_DAA_VerifySignature_internal( hDAA, daaSignature, hPubKeyIssuer, signData, attributesLength, attributes, nonceVerifierLength, nonceVerifier, baseNameLength, baseName, isCorrect); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("Tspi_DAA_VerifySignature ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return result; } /** This function is part of the DAA Issuer component. It is the last function out of 2 in order to issue a DAA Credential for a TCG Platform. It detects rogue TPM according to published rogue TPM DAA keys. This is an optional function and does not require a TPM or a TCS. Parameters - hDAA: Handle of the DAA object - daaPublicKey: daaPublickKey - keyPair: Public and private key of the DAA Anonymity Revocation Authority to encrypt the pseudonym of a DAA Signature */ TSPICALL Tspi_DAA_RevokeSetup(TSS_HDAA hDAA, // in TSS_HDAA_DATA daaPublicKey, // in TSS_HDAA_DATA* arPublicKey, // out (TSS_DAA_AR_PK) TSS_HDAA_DATA* arPrivateKey) // out (TSS_DAA_AR_SK) { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif result = Tspi_DAA_RevokeSetup_internal( hDAA, // in //TODO: remove cast when the above interface is changed daaPublicKey, // in keyPair // out ); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("Tspi_DAA_RevokeSetup ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return TSS_SUCCESS; } /** This function is part of the DAA Anonymity Revocation Authority component. It defines the Cramer-Shoup decryption algorithm to revoke the anonymity of a DAA Signature. The pseudonym, with respect to either the DAA Verifier?s base name, the DAA Issuer?s base name or (just for completeness) a random base name, can be revealed. The pseudonym with respect to a DAA Signature and the used base name is V N . An encryption of V N is the tuple (d1,d 2 ,d 3,d 4 ) and is decrypted using the secret key ( 0 5 x ,?, x ), the decryption condition and the DAA public key. This is an optional function and does not require a TPM or a TCS. Parameters: - hDAA: Handle of the DAA object - encryptedPseudonym: encryptedPseudonym - decryptCondition: Condition for the decryption of the pseudonym. - arPrivateKey: arPrivateKey - daaPublicKey: daaPublicKey - pseudonym: pseudonym */ TSPICALL Tspi_DAA_ARDecrypt(TSS_HDAA hDAA, // in TSS_DAA_PSEUDONYM_ENCRYPTED* encryptedPseudonym, // in TSS_HHASH decryptCondition, // in TSS_HDAA_DATA arPrivateKey, // in (TSS_DAA_AR_SK) TSS_HDAA_DATA daaPublicKey, // in (TSS_DAA_PK) TSS_DAA_PSEUDONYM_PLAIN** pseudonym) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif result = Tspi_DAA_ARDecrypt_internal( hDAA, // in encryptedPseudonym, // in decryptCondition, // in //TODO: remove cast when the above interface is changed (void *)arPrivateKey, // in (void *)daaPublicKey, // in pseudonym // out ); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("Tspi_DAA_ARDecrypt ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return result; } /** This is the second out of 3 functions to execute in order to receive a DAA Credential. It computes the credential request for the DAA Issuer, which also includes the Platform DAA public key and the attributes that were chosen by the Platform, and which are not visible to the DAA Issuer. The Platform can commit to the attribute values it has chosen. */ TSPICALL Tspi_TPM_DAA_JoinCreateDaaPubKey(TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in UINT32 authenticationChallengeLength,// in BYTE* authenticationChallenge, // in UINT32 nonceIssuerLength, // in BYTE* nonceIssuer, // in UINT32 attributesPlatformLength, // in BYTE** attributesPlatform, // in TSS_DAA_JOIN_SESSION* joinSession, // in, out TSS_DAA_CREDENTIAL_REQUEST** credentialRequest) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("Tspi_TPM_DAA_JoinCreateDaaPubKey hDAA=%d joinSession=%d", (int)hDAA, (int)joinSession); result = Tspi_TPM_DAA_JoinCreateDaaPubKey_internal( hDAA, // in hTPM, // in authenticationChallengeLength, // in authenticationChallenge, // in nonceIssuerLength, // in nonceIssuer, // in attributesPlatformLength, // in attributesPlatform, // in joinSession, // in, out credentialRequest // out ); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("Tspi_TPM_DAA_JoinCreateDaaPubKey ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return result; } /** This is the last out of 3 functions to execute in order to receive a DAA Credential. It verifies the issued credential from the DAA Issuer and computes the final DAA Credential. */ TSPICALL Tspi_TPM_DAA_JoinStoreCredential(TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in TSS_DAA_CRED_ISSUER* credIssuer, // in TSS_DAA_JOIN_SESSION* joinSession, // in TSS_HDAA_DATA* phDaaCredential) // out (TSS_DAA_CREDENTIAL) { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("Tspi_TPM_DAA_JoinStoreCredential hDAA=%d credIssuer=%d joinSession=%d", (int)hDAA, (int)&credIssuer, (int)&joinSession); result = Tspi_TPM_DAA_JoinStoreCredential_internal(hDAA, hTPM, credIssuer, joinSession, phDaaCredential); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("Tspi_TPM_DAA_JoinStoreCredential ALLOC DELTA:%d", mallinfo().uordblks-before); #endif return result; } /** This function creates a DAA Signature that proofs ownership of the DAA Credential and includes a signature on either a public AIK or a message. If anonymity revocation is enabled, the value Nv is not provided in the clear anymore but encrypted under the public key of anonymity revocation authority, a trusted third party (TTP). Thus the DAA Verifier cannot check for revocation or link a transaction/signature to prior ones. Depending on how z is chosen, the protocol either allows to implementing anonymity revocation (i.e., using the DAA Issuer long-term base name bsn I as the DAA Verifier base name bsnV ), or having the TTP doing the linking of different signatures for the same DAA Verifier (i.e., using the DAA Verifier base name ). */ TSPICALL Tspi_TPM_DAA_Sign(TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in TSS_HDAA_DATA hDaaCredential, // in (TSS_DAA_CREDENTIAL) TSS_DAA_SELECTED_ATTRIB* revealAttributes, // in UINT32 verifierBaseNameLength, // in BYTE* verifierBaseName, // in UINT32 verifierNonceLength, // in BYTE* verifierNonce, // in TSS_DAA_SIGN_DATA* signData, // in TSS_DAA_SIGNATURE** daaSignature) // out { TSS_RESULT result; #ifdef TSS_DEBUG int before = mallinfo().uordblks; #endif LogDebug("-> TSPI_TPM_DAA_Sign hDAA=%ld hTPM=%ld ", (long)hDAA, (long)hTPM); result = Tspi_TPM_DAA_Sign_internal(hDAA, hTPM, hDaaCredential, revealAttributes, verifierBaseNameLength, verifierBaseName, verifierNonceLength, verifierNonce, signData, daaSignature); bi_flush_memory(); #ifdef TSS_DEBUG LogDebug("TSPI_TPM_DAA_joinInit ALLOC DELTA:%d", mallinfo().uordblks-before); #endif LogDebug("<- TSPI_TPM_DAA_joinInit result=%d", result); return result; } trousers-0.3.15/src/tspi/tspi_pcr_extend.c0000664000175000017510000001046013663651711020061 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * (C) Christian Kummer 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_PcrExtend(TSS_HTPM hTPM, /* in */ UINT32 ulPcrIndex, /* in */ UINT32 ulPcrDataLength, /* in */ BYTE *pbPcrData, /* in */ TSS_PCR_EVENT *pPcrEvent, /* in */ UINT32 * pulPcrValueLength, /* out */ BYTE ** prgbPcrValue) /* out */ { TCPA_PCRVALUE outDigest; TSS_RESULT result; BYTE *extendData; TPM_DIGEST digest; UINT32 number; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; if (pulPcrValueLength == NULL || prgbPcrValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (ulPcrDataLength > 0 && pbPcrData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if (pPcrEvent) { /* Create data to extend according to the TSS 1.2 spec section 2.6.2 * 'TSS_PCR_EVENT', in the 'rgbPcrValue' parameter description. */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, ulPcrIndex); result |= Trspi_HashUpdate(&hashCtx, ulPcrDataLength, pbPcrData); result |= Trspi_Hash_UINT32(&hashCtx, pPcrEvent->eventType); result |= Trspi_HashUpdate(&hashCtx, pPcrEvent->ulEventLength, pPcrEvent->rgbEvent); if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest.digest))) return result; extendData = (BYTE *)&digest.digest; } else { if (ulPcrDataLength != TPM_SHA1_160_HASH_LEN) return TSPERR(TSS_E_BAD_PARAMETER); extendData = pbPcrData; } if ((result = TCS_API(tspContext)->Extend(tspContext, ulPcrIndex, *(TPM_DIGEST *)extendData, &outDigest))) return result; /* log the event structure if its passed in */ if (pPcrEvent) { /* Set the PCR index in the event struct */ pPcrEvent->ulPcrIndex = ulPcrIndex; if ((pPcrEvent->rgbPcrValue = calloc_tspi(tspContext, TPM_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", TPM_SHA1_160_HASH_LEN); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(pPcrEvent->rgbPcrValue, (BYTE *)&digest.digest, TPM_SHA1_160_HASH_LEN); pPcrEvent->ulPcrValueLength = TPM_SHA1_160_HASH_LEN; /* Set the version info in the event struct */ memcpy(&pPcrEvent->versionInfo, &VERSION_1_1, sizeof(TCPA_VERSION)); if ((result = RPC_LogPcrEvent(tspContext, *pPcrEvent, &number))) return result; } *prgbPcrValue = calloc_tspi(tspContext, sizeof(TPM_PCRVALUE)); if (*prgbPcrValue == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TPM_PCRVALUE)); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(*prgbPcrValue, &outDigest, sizeof(TPM_PCRVALUE)); *pulPcrValueLength = sizeof(TPM_PCRVALUE); return result; } TSS_RESULT Tspi_TPM_PcrRead(TSS_HTPM hTPM, /* in */ UINT32 ulPcrIndex, /* in */ UINT32 *pulPcrValueLength, /* out */ BYTE **prgbPcrValue) /* out */ { TCPA_PCRVALUE outDigest; TSS_RESULT result; TSS_HCONTEXT tspContext; if (pulPcrValueLength == NULL || prgbPcrValue == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = TCS_API(tspContext)->PcrRead(tspContext, ulPcrIndex, &outDigest))) return result; *prgbPcrValue = calloc_tspi(tspContext, sizeof(TCPA_PCRVALUE)); if (*prgbPcrValue == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TCPA_PCRVALUE)); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(*prgbPcrValue, outDigest.digest, sizeof(TCPA_PCRVALUE)); *pulPcrValueLength = sizeof(TCPA_PCRVALUE); return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_PcrReset(TSS_HTPM hTPM, /* in */ TSS_HPCRS hPcrComposite) /* in */ { TSS_RESULT result; TSS_HCONTEXT tspContext; UINT32 pcrDataSize; BYTE pcrData[16]; if (!hPcrComposite) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_pcrs_get_selection(hPcrComposite, &pcrDataSize, pcrData))) return result; return TCS_API(tspContext)->PcrReset(tspContext, pcrDataSize, pcrData); } trousers-0.3.15/src/tspi/tsp_migration.c0000664000175000017510000001560213663651711017551 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_CreateMigrationBlob(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCPA_MIGRATE_SCHEME migrationType, /* in */ UINT32 MigrationKeyAuthSize, /* in */ BYTE * MigrationKeyAuth, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen, dataLen, decLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(parentHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = parentHandle; handles = &handle; dataLen = sizeof(TCPA_MIGRATE_SCHEME) + MigrationKeyAuthSize + sizeof(UINT32) + encDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT16(&offset, migrationType, data); Trspi_LoadBlob(&offset, MigrationKeyAuthSize, data, MigrationKeyAuth); Trspi_LoadBlob_UINT32(&offset, encDataSize, data); Trspi_LoadBlob(&offset, encDataSize, data, encData); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_CreateMigrationBlob, dataLen, data, &pubKeyHash, &handlesLen, &handles, parentAuth, entityAuth, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, randomSize, dec); if ((*random = malloc(*randomSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *randomSize); *randomSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *randomSize, dec, *random); Trspi_UnloadBlob_UINT32(&offset, outDataSize, dec); if ((*outData = malloc(*outDataSize)) == NULL) { free(*random); *random = NULL; *randomSize = 0; free(dec); LogError("malloc of %u bytes failed", *outDataSize); *outDataSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *outDataSize, dec, *outData); free(dec); return result; } TSS_RESULT Transport_ConvertMigrationBlob(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ UINT32 randomSize, /* in */ BYTE * random, /* in */ TPM_AUTH * parentAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen, dataLen, decLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(parentHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = parentHandle; handles = &handle; dataLen = (2 * sizeof(UINT32)) + randomSize + inDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, inDataSize, data); Trspi_LoadBlob(&offset, inDataSize, data, inData); Trspi_LoadBlob_UINT32(&offset, randomSize, data); Trspi_LoadBlob(&offset, randomSize, data, random); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_ConvertMigrationBlob, dataLen, data, &pubKeyHash, &handlesLen, &handles, parentAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, outDataSize, dec); if ((*outData = malloc(*outDataSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *outDataSize); *outDataSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *outDataSize, dec, *outData); free(dec); return result; } TSS_RESULT Transport_AuthorizeMigrationKey(TSS_HCONTEXT tspContext, /* in */ TCPA_MIGRATE_SCHEME migrateScheme, /* in */ UINT32 MigrationKeySize, /* in */ BYTE * MigrationKey, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * MigrationKeyAuthSize, /* out */ BYTE ** MigrationKeyAuth) /* out */ { UINT64 offset; UINT16 tpmMigrateScheme; TSS_RESULT result; UINT32 handlesLen = 0, dataLen, decLen; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); /* The TSS_MIGRATE_SCHEME must be changed to a TPM_MIGRATE_SCHEME here, since the TCS * expects a TSS migrate scheme, but this could be wrapped by the TSP before it gets to the * TCS. */ switch (migrateScheme) { case TSS_MS_MIGRATE: tpmMigrateScheme = TCPA_MS_MIGRATE; break; case TSS_MS_REWRAP: tpmMigrateScheme = TCPA_MS_REWRAP; break; case TSS_MS_MAINT: tpmMigrateScheme = TCPA_MS_MAINT; break; #ifdef TSS_BUILD_CMK case TSS_MS_RESTRICT_MIGRATE: tpmMigrateScheme = TPM_MS_RESTRICT_MIGRATE; break; case TSS_MS_RESTRICT_APPROVE_DOUBLE: tpmMigrateScheme = TPM_MS_RESTRICT_APPROVE_DOUBLE; break; #endif default: return TSPERR(TSS_E_BAD_PARAMETER); break; } dataLen = sizeof(TCPA_MIGRATE_SCHEME) + MigrationKeySize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT16(&offset, tpmMigrateScheme, data); Trspi_LoadBlob(&offset, MigrationKeySize, data, MigrationKey); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_AuthorizeMigrationKey, dataLen, data, NULL, &handlesLen, NULL, ownerAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); *MigrationKeyAuthSize = decLen; *MigrationKeyAuth = dec; return result; } #endif trousers-0.3.15/src/tspi/tsp_pcr.c0000664000175000017510000000734513663651711016351 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" UINT16 get_num_pcrs(TSS_HCONTEXT tspContext) { TSS_RESULT result; static UINT16 ret = 0; UINT32 subCap; UINT32 respSize; BYTE *resp; if (ret != 0) return ret; subCap = endian32(TPM_CAP_PROP_PCR); if ((result = TCS_API(tspContext)->GetTPMCapability(tspContext, TPM_CAP_PROPERTY, sizeof(UINT32), (BYTE *)&subCap, &respSize, &resp))) { if ((resp = (BYTE *)getenv("TSS_DEFAULT_NUM_PCRS")) == NULL) return TSS_DEFAULT_NUM_PCRS; /* don't set ret here, next time we may be connected */ return atoi((char *)resp); } ret = (UINT16)Decode_UINT32(resp); free(resp); return ret; } TSS_RESULT pcrs_calc_composite(TPM_PCR_SELECTION *select, TPM_PCRVALUE *arrayOfPcrs, TPM_DIGEST *digestOut) { UINT32 size, index; BYTE mask; BYTE hashBlob[1024]; UINT32 numPCRs = 0; UINT64 offset = 0; UINT64 sizeOffset = 0; if (select->sizeOfSelect > 0) { sizeOffset = 0; Trspi_LoadBlob_PCR_SELECTION(&sizeOffset, hashBlob, select); offset = sizeOffset + 4; for (size = 0; size < select->sizeOfSelect; size++) { for (index = 0, mask = 1; index < 8; index++, mask = mask << 1) { if (select->pcrSelect[size] & mask) { memcpy(&hashBlob[(numPCRs * TPM_SHA1_160_HASH_LEN) + offset], arrayOfPcrs[index + (size << 3)].digest, TPM_SHA1_160_HASH_LEN); numPCRs++; } } } if (numPCRs > 0) { offset += (numPCRs * TPM_SHA1_160_HASH_LEN); UINT32ToArray(numPCRs * TPM_SHA1_160_HASH_LEN, &hashBlob[sizeOffset]); return Trspi_Hash(TSS_HASH_SHA1, offset, hashBlob, digestOut->digest); } } return TSPERR(TSS_E_INTERNAL_ERROR); } TSS_RESULT pcrs_sanity_check_selection(TSS_HCONTEXT tspContext, struct tr_pcrs_obj *pcrs, TPM_PCR_SELECTION *select) { UINT16 num_pcrs, bytes_to_hold; if ((num_pcrs = get_num_pcrs(tspContext)) == 0) return TSPERR(TSS_E_INTERNAL_ERROR); bytes_to_hold = num_pcrs / 8; /* Is the current select object going to be interpretable by the TPM? * If the select object is of a size greater than the one the TPM * wants, just calculate the composite hash and let the TPM return an * error code to the user. If its less than the size of the one the * TPM wants, add extra zero bytes until its the right size. */ if (bytes_to_hold > select->sizeOfSelect) { if ((select->pcrSelect = realloc(select->pcrSelect, bytes_to_hold)) == NULL) { LogError("malloc of %hu bytes failed.", bytes_to_hold); return TSPERR(TSS_E_OUTOFMEMORY); } /* set the newly allocated bytes to 0 */ __tspi_memset(&select->pcrSelect[select->sizeOfSelect], 0, bytes_to_hold - select->sizeOfSelect); select->sizeOfSelect = bytes_to_hold; /* realloc the pcr array as well */ if ((pcrs->pcrs = realloc(pcrs->pcrs, (bytes_to_hold * 8) * TPM_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", (bytes_to_hold * 8) * TPM_SHA1_160_HASH_LEN); return TSPERR(TSS_E_OUTOFMEMORY); } } #ifdef TSS_DEBUG { int i; for (i = 0; i < select->sizeOfSelect * 8; i++) { if (select->pcrSelect[i/8] & (1 << (i % 8))) { LogDebug("PCR%d: Selected", i); LogBlobData(APPID, TPM_SHA1_160_HASH_LEN, (unsigned char *)&pcrs->pcrs[i]); } else { LogDebug("PCR%d: Not Selected", i); } } } #endif return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_admin.c0000664000175000017510000002760013663651711017022 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_SetStatus(TSS_HTPM hTPM, /* in */ TSS_FLAG statusFlag, /* in */ TSS_BOOL fTpmState) /* in */ { TPM_AUTH auth, *pAuth; TSS_RESULT result; TCPA_DIGEST hashDigest; TSS_HCONTEXT tspContext; TSS_HPOLICY hPolicy; TSS_HPOLICY hOperatorPolicy; Trspi_HashCtx hashCtx; UINT32 tpmVersion; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy))) return result; switch (statusFlag) { case TSS_TPMSTATUS_DISABLEOWNERCLEAR: result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_DisableOwnerClear); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_DisableOwnerClear, hPolicy, FALSE, &hashDigest, &auth))) return result; if ((result = TCS_API(tspContext)->DisableOwnerClear(tspContext, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_DisableOwnerClear); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &hashDigest, &auth))) return result; break; case TSS_TPMSTATUS_DISABLEFORCECLEAR: result = TCS_API(tspContext)->DisableForceClear(tspContext); break; case TSS_TPMSTATUS_DISABLED: case TSS_TPMSTATUS_OWNERSETDISABLE: result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerSetDisable); result |= Trspi_Hash_BOOL(&hashCtx, fTpmState); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_OwnerSetDisable, hPolicy, FALSE, &hashDigest, &auth))) return result; if ((result = TCS_API(tspContext)->OwnerSetDisable(tspContext, fTpmState, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerSetDisable); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &hashDigest, &auth))) return result; break; case TSS_TPMSTATUS_PHYSICALDISABLE: if (fTpmState) result = TCS_API(tspContext)->PhysicalDisable(tspContext); else result = TCS_API(tspContext)->PhysicalEnable(tspContext); break; case TSS_TPMSTATUS_DEACTIVATED: case TSS_TPMSTATUS_PHYSICALSETDEACTIVATED: result = TCS_API(tspContext)->PhysicalSetDeactivated(tspContext, fTpmState); break; case TSS_TPMSTATUS_SETTEMPDEACTIVATED: if ((result = obj_context_get_tpm_version(tspContext, &tpmVersion))) return result; /* XXX Change 0,1,2 to #defines */ switch (tpmVersion) { case 0: case 1: result = TCS_API(tspContext)->SetTempDeactivated(tspContext); break; case 2: if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_OPERATOR, &hOperatorPolicy))) return result; if (hOperatorPolicy != NULL_HPOLICY) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_SetTempDeactivated); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; pAuth = &auth; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_SetTempDeactivated, hOperatorPolicy, FALSE, &hashDigest, pAuth))) return result; } else pAuth = NULL; if ((result = TCS_API(tspContext)->SetTempDeactivated2(tspContext, pAuth))) return result; if (pAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_SetTempDeactivated); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hOperatorPolicy, &hashDigest, pAuth))) return result; } break; default: return TSPERR(TSS_E_INTERNAL_ERROR); } break; case TSS_TPMSTATUS_SETOWNERINSTALL: result = TCS_API(tspContext)->SetOwnerInstall(tspContext, fTpmState); break; case TSS_TPMSTATUS_DISABLEPUBEKREAD: result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_DisablePubekRead); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_DisablePubekRead, hPolicy, FALSE, &hashDigest, &auth))) return result; if ((result = TCS_API(tspContext)->DisablePubekRead(tspContext, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_DisablePubekRead); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &hashDigest, &auth))) return result; break; case TSS_TPMSTATUS_ALLOWMAINTENANCE: /* Allow maintenance cannot be set to TRUE in the TPM */ if (fTpmState) return TSPERR(TSS_E_BAD_PARAMETER); /* The path to setting allow maintenance to FALSE is through * KillMaintenanceFeature */ return Tspi_TPM_KillMaintenanceFeature(hTPM); break; #ifdef TSS_BUILD_TSS12 case TSS_TPMSTATUS_DISABLEPUBSRKREAD: /* The logic of setting a 'disable' flag is reversed in the TPM, where setting this * flag to TRUE will enable the SRK read, while FALSE disables it. So we need to * flip the bool here. Sigh... */ fTpmState = fTpmState ? FALSE : TRUE; result = TSP_SetCapability(tspContext, hTPM, hPolicy, TPM_SET_PERM_FLAGS, TPM_PF_READSRKPUB, fTpmState); break; case TSS_TPMSTATUS_RESETLOCK: /* ignoring the bool here */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ResetLockValue); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_ResetLockValue, hPolicy, FALSE, &hashDigest, &auth))) return result; if ((result = TCS_API(tspContext)->ResetLockValue(tspContext, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ResetLockValue); if ((result |= Trspi_HashFinal(&hashCtx, hashDigest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &hashDigest, &auth))) return result; break; #endif #ifndef TSS_SPEC_COMPLIANCE case TSS_TPMSTATUS_PHYSPRES_LIFETIMELOCK: /* set the lifetime lock bit */ result = TCS_API(tspContext)->PhysicalPresence(tspContext, TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK); break; case TSS_TPMSTATUS_PHYSPRES_HWENABLE: /* HWENABLE, TRUE -> set the TPM_PHYSICAL_PRESENCE_HW_ENABLE bit * HWENABLE, FALSE -> set the TPM_PHYSICAL_PRESENCE_HW_DISABLE bit */ if (fTpmState) result = TCS_API(tspContext)->PhysicalPresence(tspContext, TPM_PHYSICAL_PRESENCE_HW_ENABLE); else result = TCS_API(tspContext)->PhysicalPresence(tspContext, TPM_PHYSICAL_PRESENCE_HW_DISABLE); break; case TSS_TPMSTATUS_PHYSPRES_CMDENABLE: /* CMDENABLE, TRUE -> set the TPM_PHYSICAL_PRESENCE_CMD_ENABLE bit * CMDENABLE, FALSE -> set the TPM_PHYSICAL_PRESENCE_CMD_DISABLE bit */ if (fTpmState) result = TCS_API(tspContext)->PhysicalPresence(tspContext, TPM_PHYSICAL_PRESENCE_CMD_ENABLE); else result = TCS_API(tspContext)->PhysicalPresence(tspContext, TPM_PHYSICAL_PRESENCE_CMD_DISABLE); break; case TSS_TPMSTATUS_PHYSPRES_LOCK: /* set the physical presence lock bit */ result = TCS_API(tspContext)->PhysicalPresence(tspContext, TPM_PHYSICAL_PRESENCE_LOCK); break; case TSS_TPMSTATUS_PHYSPRESENCE: /* set the physical presence state */ result = TCS_API(tspContext)->PhysicalPresence(tspContext, (fTpmState ? TPM_PHYSICAL_PRESENCE_PRESENT : TPM_PHYSICAL_PRESENCE_NOTPRESENT)); break; #endif default: return TSPERR(TSS_E_BAD_PARAMETER); break; } return result; } TSS_RESULT Tspi_TPM_GetStatus(TSS_HTPM hTPM, /* in */ TSS_FLAG statusFlag, /* in */ TSS_BOOL * pfTpmState) /* out */ { TSS_HCONTEXT tspContext; TSS_RESULT result; UINT32 nonVolFlags; UINT32 volFlags; if (pfTpmState == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = get_tpm_flags(tspContext, hTPM, &volFlags, &nonVolFlags))) return result; switch (statusFlag) { case TSS_TPMSTATUS_DISABLEOWNERCLEAR: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_DISABLEOWNERCLEAR_BIT); break; case TSS_TPMSTATUS_DISABLEFORCECLEAR: *pfTpmState = BOOL(volFlags & TSS_TPM_SF_DISABLEFORCECLEAR_BIT); break; case TSS_TPMSTATUS_DISABLED: case TSS_TPMSTATUS_OWNERSETDISABLE: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_DISABLE_BIT); break; case TSS_TPMSTATUS_DEACTIVATED: case TSS_TPMSTATUS_PHYSICALSETDEACTIVATED: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_DEACTIVATED_BIT); break; case TSS_TPMSTATUS_SETTEMPDEACTIVATED: *pfTpmState = BOOL(volFlags & TSS_TPM_SF_DEACTIVATED_BIT); break; case TSS_TPMSTATUS_SETOWNERINSTALL: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_OWNERSHIP_BIT); break; case TSS_TPMSTATUS_DISABLEPUBEKREAD: *pfTpmState = INVBOOL(nonVolFlags & TSS_TPM_PF_READPUBEK_BIT); break; case TSS_TPMSTATUS_ALLOWMAINTENANCE: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_ALLOWMAINTENANCE_BIT); break; case TSS_TPMSTATUS_MAINTENANCEUSED: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_MAINTENANCEDONE_BIT); break; case TSS_TPMSTATUS_PHYSPRES_LIFETIMELOCK: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_PHYSICALPRESENCELIFETIMELOCK_BIT); break; case TSS_TPMSTATUS_PHYSPRES_HWENABLE: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_PHYSICALPRESENCEHWENABLE_BIT); break; case TSS_TPMSTATUS_PHYSPRES_CMDENABLE: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_PHYSICALPRESENCECMDENABLE_BIT); break; case TSS_TPMSTATUS_CEKP_USED: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_CEKPUSED_BIT); break; case TSS_TPMSTATUS_PHYSPRESENCE: *pfTpmState = BOOL(volFlags & TSS_TPM_SF_PHYSICALPRESENCE_BIT); break; case TSS_TPMSTATUS_PHYSPRES_LOCK: *pfTpmState = BOOL(volFlags & TSS_TPM_SF_PHYSICALPRESENCELOCK_BIT); break; case TSS_TPMSTATUS_TPMPOST: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_TPMPOST_BIT); break; case TSS_TPMSTATUS_TPMPOSTLOCK: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_TPMPOSTLOCK_BIT); break; case TSS_TPMSTATUS_FIPS: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_FIPS_BIT); break; case TSS_TPMSTATUS_ENABLE_REVOKEEK: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_ENABLEREVOKEEK_BIT); break; case TSS_TPMSTATUS_TPM_ESTABLISHED: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_RESETESTABLISHMENTBIT_BIT); break; case TSS_TPMSTATUS_NV_LOCK: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_NV_LOCKED_BIT); break; case TSS_TPMSTATUS_POSTINITIALISE: /* There is no way to query the TPM for this flag. */ result = TSPERR(TSS_E_NOTIMPL); break; #ifdef TSS_BUILD_TSS12 case TSS_TPMSTATUS_DISABLEPUBSRKREAD: *pfTpmState = INVBOOL(nonVolFlags & TSS_TPM_PF_READSRKPUB_BIT); break; case TSS_TPMSTATUS_OPERATORINSTALLED: *pfTpmState = BOOL(nonVolFlags & TSS_TPM_PF_OPERATOR_BIT); break; #endif default: return TSPERR(TSS_E_BAD_PARAMETER); break; } return TSS_SUCCESS; } trousers-0.3.15/src/tspi/rpc/0000775000175000017510000000000013663651711015306 5ustar deboradeboratrousers-0.3.15/src/tspi/rpc/tcstp/0000775000175000017510000000000013663651711016443 5ustar deboradeboratrousers-0.3.15/src/tspi/rpc/tcstp/rpc_pcr_extend.c0000664000175000017510000000553213663651711021613 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_Extend_TP(struct host_table_entry *hte, TCPA_PCRINDEX pcrNum, /* in */ TCPA_DIGEST inDigest, /* in */ TCPA_PCRVALUE * outDigest /* out */ ) { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_EXTEND; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &pcrNum, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 2, &inDigest, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_DIGEST, 0, outDigest, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_PcrRead_TP(struct host_table_entry *hte, TCPA_PCRINDEX pcrNum, /* in */ TCPA_PCRVALUE * outDigest /* out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_PCRREAD; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &pcrNum, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_DIGEST, 0, outDigest, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_PcrReset_TP(struct host_table_entry *hte, UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn) /* in */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_PCRRESET; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &pcrDataSizeIn, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, pcrDataIn, pcrDataSizeIn, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_migration.c0000664000175000017510000001741013663651711021447 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_CreateMigrationBlob_TP(struct host_table_entry *hte, TCS_KEY_HANDLE parentHandle, /* in */ TSS_MIGRATE_SCHEME migrationType, /* in */ UINT32 MigrationKeyAuthSize, /* in */ BYTE * MigrationKeyAuth, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ) { TSS_RESULT result; TPM_AUTH null_auth; UINT32 i; initData(&hte->comm, 9); __tspi_memset(&null_auth, 0, sizeof(TPM_AUTH)); hte->comm.hdr.u.ordinal = TCSD_ORD_CREATEMIGRATIONBLOB; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); i = 0; if (setData(TCSD_PACKET_TYPE_UINT32, i++, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &parentHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, i++, &migrationType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &MigrationKeyAuthSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, i++, MigrationKeyAuth, MigrationKeyAuthSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &encDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, i++, encData, encDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (parentAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, parentAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, i++, entityAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (parentAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, parentAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_AUTH, i++, entityAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, randomSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (*randomSize > 0) { *random = (BYTE *)malloc(*randomSize); if (*random == NULL) { LogError("malloc of %u bytes failed.", *randomSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *random, *randomSize, &hte->comm)) { free(*random); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outDataSize, 0, &hte->comm)) { if (*randomSize > 0) free(*random); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outData = (BYTE *)malloc(*outDataSize); if (*outData == NULL) { if (*randomSize > 0) free(*random); LogError("malloc of %u bytes failed.", *outDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outData, *outDataSize, &hte->comm)) { if (*randomSize > 0) free(*random); free(*outData); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_ConvertMigrationBlob_TP(struct host_table_entry *hte, TCS_KEY_HANDLE parentHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ UINT32 randomSize, /* in */ BYTE * random, /* in */ TPM_AUTH * parentAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ) { TSS_RESULT result; UINT32 i; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_CONVERTMIGRATIONBLOB; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &parentHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &inDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, inData, inDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &randomSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 5, random, randomSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (parentAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 6, parentAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (parentAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, parentAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outDataSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outData = (BYTE *)malloc(*outDataSize); if (*outData == NULL) { LogError("malloc of %u bytes failed.", *outDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outData, *outDataSize, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_AuthorizeMigrationKey_TP(struct host_table_entry *hte, TSS_MIGRATE_SCHEME migrateScheme, /* in */ UINT32 MigrationKeySize, /* in */ BYTE * MigrationKey, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * MigrationKeyAuthSize, /* out */ BYTE ** MigrationKeyAuth /* out */ ) { TSS_RESULT result; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_AUTHORIZEMIGRATIONKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 1, &migrateScheme, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &MigrationKeySize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, MigrationKey, MigrationKeySize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 4, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 1, MigrationKeyAuthSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *MigrationKeyAuth = (BYTE *)malloc(*MigrationKeyAuthSize); if (*MigrationKeyAuth == NULL) { LogError("malloc of %u bytes failed.", *MigrationKeyAuthSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *MigrationKeyAuth, *MigrationKeyAuthSize, &hte->comm)) { free(*MigrationKeyAuth); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc.c0000664000175000017510000003547113663651711017405 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" #include "tsp_tcsi_param.h" void initData(struct tcsd_comm_data *comm, int parm_count) { /* min packet size should be the size of the header */ __tspi_memset(&comm->hdr, 0, sizeof(struct tcsd_packet_hdr)); comm->hdr.packet_size = sizeof(struct tcsd_packet_hdr); comm->hdr.type_offset = sizeof(struct tcsd_packet_hdr); comm->hdr.parm_offset = comm->hdr.type_offset + (sizeof(TCSD_PACKET_TYPE) * parm_count); comm->hdr.packet_size = comm->hdr.parm_offset; __tspi_memset(comm->buf, 0, comm->buf_size); } int loadData(UINT64 *offset, TCSD_PACKET_TYPE data_type, void *data, int data_size, BYTE *blob) { switch (data_type) { case TCSD_PACKET_TYPE_BYTE: Trspi_LoadBlob_BYTE(offset, *((BYTE *) (data)), blob); break; case TCSD_PACKET_TYPE_BOOL: Trspi_LoadBlob_BOOL(offset, *((TSS_BOOL *) (data)), blob); break; case TCSD_PACKET_TYPE_UINT16: Trspi_LoadBlob_UINT16(offset, *((UINT16 *) (data)), blob); break; case TCSD_PACKET_TYPE_UINT32: Trspi_LoadBlob_UINT32(offset, *((UINT32 *) (data)), blob); break; case TCSD_PACKET_TYPE_PBYTE: Trspi_LoadBlob(offset, data_size, blob, (BYTE *)data); break; case TCSD_PACKET_TYPE_NONCE: Trspi_LoadBlob(offset, 20, blob, ((TCPA_NONCE *)data)->nonce); break; case TCSD_PACKET_TYPE_DIGEST: Trspi_LoadBlob(offset, 20, blob, ((TCPA_DIGEST *)data)->digest); break; case TCSD_PACKET_TYPE_AUTH: LoadBlob_AUTH(offset, blob, ((TPM_AUTH *)data)); break; case TCSD_PACKET_TYPE_UUID: Trspi_LoadBlob_UUID(offset, blob, *((TSS_UUID *)data)); break; case TCSD_PACKET_TYPE_ENCAUTH: Trspi_LoadBlob(offset, 20, blob, ((TCPA_ENCAUTH *)data)->authdata); break; case TCSD_PACKET_TYPE_VERSION: Trspi_LoadBlob_TCPA_VERSION(offset, blob, *((TCPA_VERSION *)data)); break; #ifdef TSS_BUILD_PS case TCSD_PACKET_TYPE_LOADKEY_INFO: LoadBlob_LOADKEY_INFO(offset, blob, ((TCS_LOADKEY_INFO *)data)); break; #endif case TCSD_PACKET_TYPE_PCR_EVENT: Trspi_LoadBlob_PCR_EVENT(offset, blob, ((TSS_PCR_EVENT *)data)); break; case TCSD_PACKET_TYPE_COUNTER_VALUE: Trspi_LoadBlob_COUNTER_VALUE(offset, blob, ((TPM_COUNTER_VALUE *)data)); break; case TCSD_PACKET_TYPE_SECRET: Trspi_LoadBlob(offset, 20, blob, ((TCPA_SECRET *)data)->authdata); break; default: LogError("TCSD packet type unknown! (0x%x)", data_type & 0xff); return TSPERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } int setData(TCSD_PACKET_TYPE dataType, int index, void *theData, int theDataSize, struct tcsd_comm_data *comm) { UINT64 old_offset, offset; TSS_RESULT result; TCSD_PACKET_TYPE *type; /* Calculate the size of the area needed (use NULL for blob address) */ offset = 0; if ((result = loadData(&offset, dataType, theData, theDataSize, NULL))) return result; if ((comm->hdr.packet_size + offset) > TSS_TPM_TXBLOB_SIZE) { LogError("Too much data to be transmitted!"); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((comm->hdr.packet_size + offset) > comm->buf_size) { /* reallocate the buffer */ BYTE *buffer; int buffer_size = comm->hdr.packet_size + offset; LogDebug("Increasing communication buffer to %d bytes.", buffer_size); buffer = realloc(comm->buf, buffer_size); if (buffer == NULL) { LogError("realloc of %d bytes failed.", buffer_size); return TSPERR(TSS_E_INTERNAL_ERROR); } comm->buf_size = buffer_size; comm->buf = buffer; } offset = old_offset = comm->hdr.parm_offset + comm->hdr.parm_size; if ((result = loadData(&offset, dataType, theData, theDataSize, comm->buf))) return result; type = (TCSD_PACKET_TYPE *)(comm->buf + comm->hdr.type_offset) + index; *type = dataType; comm->hdr.type_size += sizeof(TCSD_PACKET_TYPE); comm->hdr.parm_size += (offset - old_offset); comm->hdr.packet_size = offset; comm->hdr.num_parms++; return TSS_SUCCESS; } UINT32 getData(TCSD_PACKET_TYPE dataType, int index, void *theData, int theDataSize, struct tcsd_comm_data *comm) { TSS_RESULT result; UINT64 old_offset, offset; TCSD_PACKET_TYPE *type = (TCSD_PACKET_TYPE *)(comm->buf + comm->hdr.type_offset) + index; if ((UINT32)index >= comm->hdr.num_parms || dataType != *type) { LogDebug("Data type of TCS packet element %d doesn't match.", index); return TSS_TCP_RPC_BAD_PACKET_TYPE; } old_offset = offset = comm->hdr.parm_offset; switch (dataType) { case TCSD_PACKET_TYPE_BYTE: Trspi_UnloadBlob_BYTE(&offset, (BYTE *)theData, comm->buf); break; case TCSD_PACKET_TYPE_BOOL: Trspi_UnloadBlob_BOOL(&offset, (TSS_BOOL *)theData, comm->buf); break; case TCSD_PACKET_TYPE_UINT16: Trspi_UnloadBlob_UINT16(&offset, (UINT16 *)theData, comm->buf); break; case TCSD_PACKET_TYPE_UINT32: Trspi_UnloadBlob_UINT32(&offset, (UINT32 *)theData, comm->buf); break; case TCSD_PACKET_TYPE_UINT64: Trspi_UnloadBlob_UINT64(&offset, (UINT64 *)theData, comm->buf); break; case TCSD_PACKET_TYPE_PBYTE: Trspi_UnloadBlob(&offset, theDataSize, comm->buf, (BYTE *)theData); break; case TCSD_PACKET_TYPE_NONCE: Trspi_UnloadBlob_NONCE(&offset, comm->buf, (TPM_NONCE *)theData); break; case TCSD_PACKET_TYPE_DIGEST: Trspi_UnloadBlob(&offset, sizeof(TCPA_DIGEST), comm->buf, ((TCPA_DIGEST *)theData)->digest); break; case TCSD_PACKET_TYPE_AUTH: UnloadBlob_AUTH(&offset, comm->buf, ((TPM_AUTH *)theData)); break; case TCSD_PACKET_TYPE_UUID: Trspi_UnloadBlob_UUID(&offset, comm->buf, ((TSS_UUID *)theData)); break; case TCSD_PACKET_TYPE_ENCAUTH: Trspi_UnloadBlob(&offset, sizeof(TCPA_ENCAUTH), comm->buf, ((TCPA_ENCAUTH *)theData)->authdata); break; case TCSD_PACKET_TYPE_VERSION: Trspi_UnloadBlob_TCPA_VERSION(&offset, comm->buf, ((TCPA_VERSION *)theData)); break; case TCSD_PACKET_TYPE_KM_KEYINFO: if ((result = Trspi_UnloadBlob_KM_KEYINFO(&offset, comm->buf, ((TSS_KM_KEYINFO *)theData)))) return result; break; case TCSD_PACKET_TYPE_KM_KEYINFO2: if ((result = Trspi_UnloadBlob_KM_KEYINFO2(&offset, comm->buf, ((TSS_KM_KEYINFO2 *)theData)))) return result; break; #ifdef TSS_BUILD_PS case TCSD_PACKET_TYPE_LOADKEY_INFO: UnloadBlob_LOADKEY_INFO(&offset, comm->buf, ((TCS_LOADKEY_INFO *)theData)); break; #endif case TCSD_PACKET_TYPE_PCR_EVENT: if ((result = Trspi_UnloadBlob_PCR_EVENT(&offset, comm->buf, ((TSS_PCR_EVENT *)theData)))) return result; break; case TCSD_PACKET_TYPE_COUNTER_VALUE: Trspi_UnloadBlob_COUNTER_VALUE(&offset, comm->buf, ((TPM_COUNTER_VALUE *)theData)); break; case TCSD_PACKET_TYPE_SECRET: Trspi_UnloadBlob(&offset, sizeof(TCPA_SECRET), comm->buf, ((TCPA_SECRET *)theData)->authdata); break; default: LogError("unknown data type (%d) in TCSD packet!", dataType); return -1; } comm->hdr.parm_offset = offset; comm->hdr.parm_size -= (offset - old_offset); return TSS_SUCCESS; } TSS_RESULT sendTCSDPacket(struct host_table_entry *hte) { TSS_RESULT rc; UINT64 offset = 0; Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.packet_size, hte->comm.buf); Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.u.ordinal, hte->comm.buf); Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.num_parms, hte->comm.buf); Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.type_size, hte->comm.buf); Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.type_offset, hte->comm.buf); Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.parm_size, hte->comm.buf); Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.parm_offset, hte->comm.buf); #if 0 /* --- Send it */ printBuffer(hte->comm.buf, hte->comm.hdr.packet_size); LogInfo("Sending Packet with TCSD ordinal 0x%X", hte->comm.hdr.u.ordinal); #endif /* if the ordinal is open context, there are some host table entry * manipulations that must be done, so call _init */ if (hte->comm.hdr.u.ordinal == TCSD_ORD_OPENCONTEXT) { if ((rc = send_init(hte))) { LogError("Failed to send packet"); return rc; } } else { if ((rc = tcs_sendit(hte))) { LogError("Failed to send packet"); return rc; } } /* create a platform version of the tcsd header */ offset = 0; Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.packet_size, hte->comm.buf); Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.u.result, hte->comm.buf); Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.num_parms, hte->comm.buf); Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.type_size, hte->comm.buf); Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.type_offset, hte->comm.buf); Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.parm_size, hte->comm.buf); Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.parm_offset, hte->comm.buf); return TSS_SUCCESS; } int recv_from_socket(int sock, void *buffer, int size) { int recv_size = 0, recv_total = 0; while (recv_total < size) { errno = 0; if ((recv_size = recv(sock, buffer+recv_total, size-recv_total, 0)) <= 0) { if (recv_size < 0) { if (errno == EINTR) continue; LogError("Socket receive connection error: %s.", strerror(errno)); } else { LogDebug("Socket connection closed."); } return -1; } recv_total += recv_size; } return recv_total; } int send_to_socket(int sock, void *buffer, int size) { int send_size = 0, send_total = 0; while (send_total < size) { if ((send_size = send(sock, buffer+send_total, size-send_total, 0)) < 0) { LogError("Socket send connection error: %s.", strerror(errno)); return -1; } send_total += send_size; } return send_total; } TSS_RESULT send_init(struct host_table_entry *hte) { int sd; int recv_size; BYTE *buffer; TSS_RESULT result; result = get_socket(hte, &sd); if (result != TSS_SUCCESS) goto err_exit; if (send_to_socket(sd, hte->comm.buf, hte->comm.hdr.packet_size) < 0) { result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } buffer = hte->comm.buf; recv_size = sizeof(struct tcsd_packet_hdr); if (recv_from_socket(sd, buffer, recv_size) < 0) { result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } buffer += sizeof(struct tcsd_packet_hdr); /* increment the receive buffer pointer */ /* check the packet size */ recv_size = Decode_UINT32(hte->comm.buf); if (recv_size < (int)sizeof(struct tcsd_packet_hdr)) { LogError("Packet to receive from socket %d is too small (%d bytes)", sd, recv_size); result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } if (recv_size > (int) hte->comm.buf_size ) { BYTE *new_buffer; LogDebug("Increasing communication buffer to %d bytes.", recv_size); new_buffer = realloc(hte->comm.buf, recv_size); if (new_buffer == NULL) { LogError("realloc of %d bytes failed.", recv_size); result = TSPERR(TSS_E_OUTOFMEMORY); goto err_exit; } buffer = new_buffer + sizeof(struct tcsd_packet_hdr); hte->comm.buf_size = recv_size; hte->comm.buf = new_buffer; } /* get the rest of the packet */ recv_size -= sizeof(struct tcsd_packet_hdr); /* already received the header */ if (recv_from_socket(sd, buffer, recv_size) < 0) { result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } hte->socket = sd; return TSS_SUCCESS; err_exit: close(sd); return result; } TSS_RESULT tcs_sendit(struct host_table_entry *hte) { int recv_size; BYTE *buffer; TSS_RESULT result; if (send_to_socket(hte->socket, hte->comm.buf, hte->comm.hdr.packet_size) < 0) { result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } buffer = hte->comm.buf; recv_size = sizeof(struct tcsd_packet_hdr); if ((recv_size = recv_from_socket(hte->socket, buffer, recv_size)) < 0) { result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } buffer += recv_size; /* increment the receive buffer pointer */ /* check the packet size */ recv_size = Decode_UINT32(hte->comm.buf); if (recv_size < (int)sizeof(struct tcsd_packet_hdr)) { LogError("Packet to receive from socket %d is too small (%d bytes)", hte->socket, recv_size); result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } if (recv_size > (int) hte->comm.buf_size ) { BYTE *new_buffer; LogDebug("Increasing communication buffer to %d bytes.", recv_size); new_buffer = realloc(hte->comm.buf, recv_size); if (new_buffer == NULL) { LogError("realloc of %d bytes failed.", recv_size); result = TSPERR(TSS_E_OUTOFMEMORY); goto err_exit; } buffer = new_buffer + sizeof(struct tcsd_packet_hdr); hte->comm.buf_size = recv_size; hte->comm.buf = new_buffer; } /* get the rest of the packet */ recv_size -= sizeof(struct tcsd_packet_hdr); /* already received the header */ if ((recv_size = recv_from_socket(hte->socket, buffer, recv_size)) < 0) { result = TSPERR(TSS_E_COMM_FAILURE); goto err_exit; } return TSS_SUCCESS; err_exit: return result; } /* TODO: Future work - remove socket creation/manipulation from RPC-specific file */ TSS_RESULT get_socket(struct host_table_entry *hte, int *sd) { char port_str[TCP_PORT_STR_MAX_LEN]; // To accomodate string 65535 struct addrinfo hints, *p, *res=NULL; int rv; TSS_RESULT result = TSS_SUCCESS; __tspi_memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICSERV; __tspi_memset(&port_str, 0, sizeof(port_str)); if (get_tcsd_port(port_str) != TSS_SUCCESS) { LogError("Could not retrieve TCP port information."); goto exit; } LogDebug("Retrieving address information from host: %s", (char *)hte->hostname); rv = getaddrinfo((char *)hte->hostname, port_str, &hints, &res); if (rv != 0) { LogError("hostname %s does not resolve to a valid address.", hte->hostname); result = TSPERR(TSS_E_CONNECTION_FAILED); res = NULL; goto exit; } LogWarn("Got a list of valid IPs"); for (p = res; p != NULL; p = p->ai_next) { *sd = socket(p->ai_family, SOCK_STREAM, 0); if (*sd == -1) continue; if (connect(*sd, p->ai_addr, p->ai_addrlen) != -1) break; // Got a connection LogWarn("Could not connect to machine: %s", (char*)hte->hostname); close(*sd); } if (p == NULL) { LogError("Could not connect to any machine in the list."); result = TSPERR(TSS_E_COMM_FAILURE); goto exit; } exit: if (res != NULL) freeaddrinfo(res); return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_key.c0000664000175000017510000002401413663651711020244 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_LoadKeyByBlob_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hUnwrappingKey, /* in */ UINT32 cWrappedKeyBlobSize, /* in */ BYTE * rgbWrappedKeyBlob, /* in */ TPM_AUTH * pAuth, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI, /* out */ TCS_KEY_HANDLE * phKeyHMAC) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_LOADKEYBYBLOB; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hUnwrappingKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &cWrappedKeyBlobSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, rgbWrappedKeyBlob, cWrappedKeyBlobSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (pAuth != NULL) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, phKeyTCSI, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, i++, phKeyHMAC, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("OUT: TCS key handle: 0x%x, TPM key slot: 0x%x", *phKeyTCSI, *phKeyHMAC); } return result; } TSS_RESULT RPC_EvictKey_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hKey) /* in */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_EVICTKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_CreateWrapKey_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hWrappingKey, /* in */ TCPA_ENCAUTH *KeyUsageAuth, /* in */ TCPA_ENCAUTH *KeyMigrationAuth, /* in */ UINT32 keyInfoSize, /* in */ BYTE * keyInfo, /* in */ UINT32 * keyDataSize, /* out */ BYTE ** keyData, /* out */ TPM_AUTH * pAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_CREATEWRAPKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hWrappingKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 2, KeyUsageAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 3, KeyMigrationAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &keyInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 5, keyInfo, keyInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 6, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, keyDataSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *keyData = (BYTE *) malloc(*keyDataSize); if (*keyData == NULL) { LogError("malloc of %u bytes failed.", *keyDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *keyData, *keyDataSize, &hte->comm)) { free(*keyData); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (pAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 2, pAuth, 0, &hte->comm)) { free(*keyData); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } done: return result; } TSS_RESULT RPC_GetPubKey_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * pcPubKeySize, /* out */ BYTE ** prgbPubKey) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_GETPUBKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 2, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; i = 0; if (result == TSS_SUCCESS) { if (pAuth != NULL) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcPubKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbPubKey = (BYTE *) malloc(*pcPubKeySize); if (*prgbPubKey == NULL) { LogError("malloc of %u bytes failed.", *pcPubKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbPubKey, *pcPubKeySize, &hte->comm)) { free(*prgbPubKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_TerminateHandle_TP(struct host_table_entry *hte, TCS_AUTHHANDLE handle) /* in */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_TERMINATEHANDLE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &handle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_OwnerReadInternalPub_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * punPubKeySize, /* out */ BYTE ** ppbPubKeyData) /* out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_OWNERREADINTERNALPUB; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pOwnerAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 2, pOwnerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pOwnerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 1, punPubKeySize, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); *ppbPubKeyData = (BYTE *) malloc(*punPubKeySize); if (*ppbPubKeyData == NULL) { LogError("malloc of %u bytes failed.", *punPubKeySize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *ppbPubKeyData, *punPubKeySize, &hte->comm)) { free(*ppbPubKeyData); result = TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } /* TSS 1.2-only interfaces */ #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_KeyControlOwner_TP(struct host_table_entry *hte, // in TCS_KEY_HANDLE hKey, // in UINT32 ulPublicInfoLength, // in BYTE* rgbPublicInfo, // in UINT32 attribName, // in TSS_BOOL attribValue, // in TPM_AUTH* pOwnerAuth, // in, out TSS_UUID* pUuidData) // out { TSS_RESULT result; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_KEYCONTROLOWNER; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &ulPublicInfoLength, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, rgbPublicInfo, ulPublicInfoLength, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &attribName, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 5, &attribValue, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pOwnerAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 6, pOwnerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pOwnerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UUID, 1, pUuidData, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } #endif trousers-0.3.15/src/tspi/rpc/tcstp/rpc_certify.c0000664000175000017510000000706713663651711021132 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_CertifyKey_TP(struct host_table_entry *hte, TCS_KEY_HANDLE certHandle, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TPM_NONCE * antiReplay, /* in */ TPM_AUTH * certAuth, /* in, out */ TPM_AUTH * keyAuth, /* in, out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ) { TSS_RESULT result; TPM_AUTH null_auth; int i; initData(&hte->comm, 6); __tspi_memset(&null_auth, 0, sizeof(TPM_AUTH)); hte->comm.hdr.u.ordinal = TCSD_ORD_CERTIFYKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &certHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 3, antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (certAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, certAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { if (setData(TCSD_PACKET_TYPE_AUTH, 4, &null_auth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (keyAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 5, keyAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { if (setData(TCSD_PACKET_TYPE_AUTH, 5, &null_auth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (certAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, certAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (keyAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, keyAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, CertifyInfoSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *CertifyInfo = (BYTE *) malloc(*CertifyInfoSize); if (*CertifyInfo == NULL) { LogError("malloc of %u bytes failed.", *CertifyInfoSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *CertifyInfo, *CertifyInfoSize, &hte->comm)) { free(*CertifyInfo); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outDataSize, 0, &hte->comm)) { free(*CertifyInfo); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outData = (BYTE *) malloc(*outDataSize); if (*outData == NULL) { LogError("malloc of %u bytes failed.", *outDataSize); free(*CertifyInfo); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outData, *outDataSize, &hte->comm)) { free(*CertifyInfo); free(*outData); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_auth.c0000664000175000017510000000510113663651711020411 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_OIAP_TP(struct host_table_entry *hte, TCS_AUTHHANDLE * authHandle, /* out */ TCPA_NONCE * nonce0 /* out */ ) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_OIAP; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, authHandle, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 1, nonce0, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_OSAP_TP(struct host_table_entry *hte, TCPA_ENTITY_TYPE entityType, /* in */ UINT32 entityValue, /* in */ TCPA_NONCE * nonceOddOSAP, /* in */ TCS_AUTHHANDLE * authHandle, /* out */ TCPA_NONCE * nonceEven, /* out */ TCPA_NONCE * nonceEvenOSAP /* out */ ) { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_OSAP; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 1, &entityType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &entityValue, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 3, nonceOddOSAP, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, authHandle, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 1, nonceEven, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 2, nonceEvenOSAP, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_dir.c0000664000175000017510000000441313663651711020233 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_DirWriteAuth_TP(struct host_table_entry *hte, TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE *newContents, /* in */ TPM_AUTH * ownerAuth /* in, out */ ) { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_DIRWRITEAUTH; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &dirIndex, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 2, newContents, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 3, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_DirRead_TP(struct host_table_entry *hte, TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE * dirValue /* out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_DIRREAD; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &dirIndex, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (hte->comm.hdr.u.result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_DIGEST, 0, dirValue, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_cmk.c0000664000175000017510000003177513663651711020242 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_CMK_SetRestrictions_TP(struct host_table_entry *hte, TSS_CMK_DELEGATE restriction, /* in */ TPM_AUTH *ownerAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_CMK_SETRESTRICTIONS; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &restriction, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 2, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_CMK_ApproveMA_TP(struct host_table_entry *hte, TPM_DIGEST migAuthorityDigest, /* in */ TPM_AUTH *ownerAuth, /* in, out */ TPM_HMAC *migAuthorityApproval) /* out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_CMK_APPROVEMA; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 1, &migAuthorityDigest, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 2, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 1, migAuthorityApproval, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_CMK_CreateKey_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hWrappingKey, /* in */ TPM_ENCAUTH *keyUsageAuth, /* in */ TPM_HMAC *migAuthorityApproval, /* in */ TPM_DIGEST *migAuthorityDigest, /* in */ UINT32 *keyDataSize, /* in, out */ BYTE **keyData, /* in, out */ TPM_AUTH *pAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 8); hte->comm.hdr.u.ordinal = TCSD_ORD_CMK_CREATEKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hWrappingKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 2, keyUsageAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 3, migAuthorityApproval, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 4, migAuthorityDigest, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 5, keyDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 6, *keyData, *keyDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 7, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 7, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } free(*keyData); *keyData = NULL; result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, keyDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *keyData = (BYTE *)malloc(*keyDataSize); if (*keyData == NULL) { LogError("malloc of %u bytes failed.", *keyDataSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *keyData, *keyDataSize, &hte->comm)) { free(*keyData); return TSPERR(TSS_E_INTERNAL_ERROR); } if (pAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 2, pAuth, 0, &hte->comm)) { free(*keyData); return TSPERR(TSS_E_INTERNAL_ERROR); } } } return result; } TSS_RESULT RPC_CMK_CreateTicket_TP(struct host_table_entry *hte, UINT32 publicVerifyKeySize, /* in */ BYTE *publicVerifyKey, /* in */ TPM_DIGEST signedData, /* in */ UINT32 sigValueSize, /* in */ BYTE *sigValue, /* in */ TPM_AUTH *ownerAuth, /* in, out */ TPM_HMAC *sigTicket) /* out */ { TSS_RESULT result; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_CMK_CREATETICKET; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &publicVerifyKeySize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, publicVerifyKey, publicVerifyKeySize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 3, &signedData, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &sigValueSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 5, sigValue, sigValueSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 6, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_DIGEST, 1, sigTicket, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_CMK_CreateBlob_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hParentKey, /* in */ TSS_MIGRATE_SCHEME migrationType, /* in */ UINT32 migKeyAuthSize, /* in */ BYTE *migKeyAuth, /* in */ TPM_DIGEST pubSourceKeyDigest, /* in */ UINT32 msaListSize, /* in */ BYTE *msaList, /* in */ UINT32 restrictTicketSize, /* in */ BYTE *restrictTicket, /* in */ UINT32 sigTicketSize, /* in */ BYTE *sigTicket, /* in */ UINT32 encDataSize, /* in */ BYTE *encData, /* in */ TPM_AUTH *pAuth, /* in, out */ UINT32 *randomSize, /* out */ BYTE **random, /* out */ UINT32 *outDataSize, /* out */ BYTE **outData) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 15); hte->comm.hdr.u.ordinal = TCSD_ORD_CMK_CREATEBLOB; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hParentKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 2, &migrationType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &migKeyAuthSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, migKeyAuth, migKeyAuthSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 5, &pubSourceKeyDigest, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 6, &msaListSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 7, msaList, msaListSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 8, &restrictTicketSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 9, restrictTicket, restrictTicketSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 10, &sigTicketSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 11, sigTicket, sigTicketSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 12, &encDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 13, encData, encDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 14, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 14, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (pAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, randomSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *random = (BYTE *)malloc(*randomSize); if (*random == NULL) { LogError("malloc of %u bytes failed.", *randomSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *random, *randomSize, &hte->comm)) { free(*random); return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *outData = (BYTE *)malloc(*outDataSize); if (*outData == NULL) { LogError("malloc of %u bytes failed.", *outDataSize); free(*random); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outData, *outDataSize, &hte->comm)) { free(*random); free(*outData); return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_CMK_ConvertMigration_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hParentHandle, /* in */ TPM_CMK_AUTH restrictTicket, /* in */ TPM_HMAC sigTicket, /* in */ UINT32 keyDataSize, /* in */ BYTE *keyData, /* in */ UINT32 msaListSize, /* in */ BYTE *msaList, /* in */ UINT32 randomSize, /* in */ BYTE *random, /* in */ TPM_AUTH *pAuth, /* in, out */ UINT32 *outDataSize, /* out */ BYTE **outData) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 11); hte->comm.hdr.u.ordinal = TCSD_ORD_CMK_CONVERTMIGRATION; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hParentHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, &restrictTicket, sizeof(restrictTicket), &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 3, &sigTicket, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &keyDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 5, keyData, keyDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 6, &msaListSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 7, msaList, msaListSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 8, &randomSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 9, random, randomSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 10, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 10, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (pAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *outData = (BYTE *)malloc(*outDataSize); if (*outData == NULL) { LogError("malloc of %u bytes failed.", *outDataSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outData, *outDataSize, &hte->comm)) { free(*outData); return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_delegate.c0000664000175000017510000003333313663651711021232 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_Delegate_Manage_TP(struct host_table_entry *hte, TPM_FAMILY_ID familyID, /* in */ TPM_FAMILY_OPERATION opFlag, /* in */ UINT32 opDataSize, /* in */ BYTE *opData, /* in */ TPM_AUTH *ownerAuth, /* in/out */ UINT32 *retDataSize, /* out */ BYTE **retData) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_DELEGATE_MANAGE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &familyID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &opFlag, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &opDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, opData, opDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (ownerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 5, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 5, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (ownerAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, retDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *retData = (BYTE *)malloc(*retDataSize); if (*retData == NULL) { LogError("malloc of %u bytes failed.", *retDataSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *retData, *retDataSize, &hte->comm)) { free(*retData); return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_Delegate_CreateKeyDelegation_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hKey, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *keyAuth, /* in/out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 8); hte->comm.hdr.u.ordinal = TCSD_ORD_DELEGATE_CREATEKEYDELEGATION; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &publicInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, publicInfo, publicInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 4, encDelAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (keyAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 5, keyAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 5, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (keyAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, keyAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, blobSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *blob = (BYTE *)malloc(*blobSize); if (*blob == NULL) { LogError("malloc of %u bytes failed.", *blobSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *blob, *blobSize, &hte->comm)) { free(*blob); return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_Delegate_CreateOwnerDelegation_TP(struct host_table_entry *hte, TSS_BOOL increment, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *ownerAuth, /* in/out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 8); hte->comm.hdr.u.ordinal = TCSD_ORD_DELEGATE_CREATEOWNERDELEGATION; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 1, &increment, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &publicInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, publicInfo, publicInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 4, encDelAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (ownerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 5, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 5, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (ownerAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, blobSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *blob = (BYTE *)malloc(*blobSize); if (*blob == NULL) { LogError("malloc of %u bytes failed.", *blobSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *blob, *blobSize, &hte->comm)) { free(*blob); return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_Delegate_LoadOwnerDelegation_TP(struct host_table_entry *hte, TPM_DELEGATE_INDEX index, /* in */ UINT32 blobSize, /* in */ BYTE *blob, /* in */ TPM_AUTH *ownerAuth) /* in/out */ { TSS_RESULT result; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_DELEGATE_LOADOWNERDELEGATION; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &index, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &blobSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, blob, blobSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (ownerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 4, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (ownerAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_Delegate_ReadTable_TP(struct host_table_entry *hte, UINT32 *familyTableSize, /* out */ BYTE **familyTable, /* out */ UINT32 *delegateTableSize, /* out */ BYTE **delegateTable) /* out */ { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_DELEGATE_READTABLE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, familyTableSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *familyTable = (BYTE *)malloc(*familyTableSize); if (*familyTable == NULL) { LogError("malloc of %u bytes failed.", *familyTableSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *familyTable, *familyTableSize, &hte->comm)) { free(*familyTable); return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 2, delegateTableSize, 0, &hte->comm)) { free(*familyTable); return TSPERR(TSS_E_INTERNAL_ERROR); } *delegateTable = (BYTE *)malloc(*delegateTableSize); if (*delegateTable == NULL) { free(*familyTable); LogError("malloc of %u bytes failed.", *delegateTableSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, *delegateTable, *delegateTableSize, &hte->comm)) { free(*familyTable); free(*delegateTable); return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_Delegate_UpdateVerificationCount_TP(struct host_table_entry *hte, UINT32 inputSize, /* in */ BYTE *input, /* in */ TPM_AUTH *ownerAuth, /* in/out */ UINT32 *outputSize, /* out */ BYTE **output) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_DELEGATE_UPDATEVERIFICATIONCOUNT; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &inputSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, input, inputSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (ownerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 3, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 3, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (ownerAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outputSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *output = (BYTE *)malloc(*outputSize); if (*output == NULL) { LogError("malloc of %u bytes failed.", *outputSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *output, *outputSize, &hte->comm)) { free(*output); output = NULL; return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_Delegate_VerifyDelegation_TP(struct host_table_entry *hte, UINT32 delegateSize, /* in */ BYTE *delegate) /* in */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_DELEGATE_VERIFYDELEGATION; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &delegateSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, delegate, delegateSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_DSAP_TP(struct host_table_entry *hte, TPM_ENTITY_TYPE entityType, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TPM_NONCE *nonceOddDSAP, /* in */ UINT32 entityValueSize, /* in */ BYTE * entityValue, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TPM_NONCE *nonceEven, /* out */ TPM_NONCE *nonceEvenDSAP) /* out */ { TSS_RESULT result; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_DSAP; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 1, &entityType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 3, nonceOddDSAP, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &entityValueSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 5, entityValue, entityValueSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, authHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 1, nonceEven, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_NONCE, 2, nonceEvenDSAP, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_random.c0000664000175000017510000000447513663651711020745 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_GetRandom_TP(struct host_table_entry *hte, UINT32 bytesRequested, /* in */ BYTE ** randomBytes) /* out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_GETRANDOM; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &bytesRequested, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, &bytesRequested, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *randomBytes = (BYTE *) malloc(bytesRequested); if (*randomBytes == NULL) { LogError("malloc of %u bytes failed.", bytesRequested); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *randomBytes, bytesRequested, &hte->comm)) { free(*randomBytes); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_StirRandom_TP(struct host_table_entry *hte, UINT32 inDataSize, /* in */ BYTE * inData) /* in */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_STIRRANDOM; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &inDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, inData, inDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_bind.c0000664000175000017510000000437413663651711020377 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_UnBind_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ) { TSS_RESULT result; int i; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_UNBIND; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &inDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, inData, inDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (privAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (privAuth != NULL) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outDataSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outData = (BYTE *) malloc(*outDataSize); if (*outData == NULL) { LogError("malloc of %u bytes failed.", *outDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outData, *outDataSize, &hte->comm)) { free(*outData); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_context.c0000664000175000017510000000325413663651711021143 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_OpenContext_TP(struct host_table_entry* hte, UINT32* tpm_version, TCS_CONTEXT_HANDLE* tcsContext) { TSS_RESULT result; initData(&hte->comm, 0); hte->comm.hdr.u.ordinal = TCSD_ORD_OPENCONTEXT; result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("Received TCS Context: 0x%x", *tcsContext); if (getData(TCSD_PACKET_TYPE_UINT32, 1, tpm_version, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_CloseContext_TP(struct host_table_entry *hte) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_CLOSECONTEXT; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_FreeMemory_TP(struct host_table_entry *hte, BYTE * pMemory) /* in */ { free(pMemory); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_quote.c0000664000175000017510000000574613663651711020624 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_Quote_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE *antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_QUOTE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 2, antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &pcrDataSizeIn, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, pcrDataIn, pcrDataSizeIn, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 5, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcrDataSizeOut, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *pcrDataOut = (BYTE *) malloc(*pcrDataSizeOut); if (*pcrDataOut == NULL) { LogError("malloc of %u bytes failed.", *pcrDataSizeOut); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *pcrDataOut, *pcrDataSizeOut, &hte->comm)) { free(*pcrDataOut); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, sigSize, 0, &hte->comm)) { free(*pcrDataOut); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *sig = (BYTE *) malloc(*sigSize); if (*sig == NULL) { LogError("malloc of %u bytes failed.", *sigSize); free(*pcrDataOut); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *sig, *sigSize, &hte->comm)) { free(*pcrDataOut); free(*sig); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_seal.c0000664000175000017510000001343613663651711020406 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT common_Seal_TP(UINT32 sealOrdinal, struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH *encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData /* out */ ) { TSS_RESULT result; int i = 0; initData(&hte->comm, 8); hte->comm.hdr.u.ordinal = sealOrdinal; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, i++, encAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &pcrInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pcrInfoSize > 0) { if (setData(TCSD_PACKET_TYPE_PBYTE, i++, PcrInfo, pcrInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_UINT32, i++, &inDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (inDataSize > 0) { if (setData(TCSD_PACKET_TYPE_PBYTE, i++, inData, inDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, i, pubAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (hte->comm.hdr.u.result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pubAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 1, SealedDataSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *SealedData = (BYTE *) malloc(*SealedDataSize); if (*SealedData == NULL) { LogError("malloc of %u bytes failed.", *SealedDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *SealedData, *SealedDataSize, &hte->comm)) { free(*SealedData); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_Seal_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH *encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData /* out */ ) { return common_Seal_TP(TCSD_ORD_SEAL, hte, keyHandle, encAuth, pcrInfoSize, PcrInfo, inDataSize, inData, pubAuth, SealedDataSize, SealedData); } #ifdef TSS_BUILD_SEALX TSS_RESULT RPC_Sealx_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH *encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData /* out */ ) { return common_Seal_TP(TCSD_ORD_SEALX, hte, keyHandle, encAuth, pcrInfoSize, PcrInfo, inDataSize, inData, pubAuth, SealedDataSize, SealedData); } #endif TSS_RESULT RPC_Unseal_TP(struct host_table_entry *hte, TCS_KEY_HANDLE parentHandle, /* in */ UINT32 SealedDataSize, /* in */ BYTE * SealedData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * dataAuth, /* in, out */ UINT32 * DataSize, /* out */ BYTE ** Data /* out */ ) { TSS_RESULT result; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_UNSEAL; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &parentHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &SealedDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, SealedData, SealedDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (parentAuth != NULL) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, parentAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, 5, dataAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (parentAuth != NULL) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, parentAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_AUTH, 1, dataAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 2, DataSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *Data = (BYTE *) malloc(*DataSize); if (*Data == NULL) { LogError("malloc of %u bytes failed.", *DataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, *Data, *DataSize, &hte->comm)) { free(*Data); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_ps.c0000664000175000017510000002532113663651711020100 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_GetRegisteredKeyByPublicInfo_TP(struct host_table_entry *hte, TCPA_ALGORITHM_ID algID, /* in */ UINT32 ulPublicInfoLength, /* in */ BYTE * rgbPublicInfo, /* in */ UINT32 * keySize, /* out */ BYTE ** keyBlob) /* out */ { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_GETREGISTEREDKEYBYPUBLICINFO; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &algID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &ulPublicInfoLength, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, rgbPublicInfo, ulPublicInfoLength, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, keySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *keyBlob = (BYTE *) malloc(*keySize); if (*keyBlob == NULL) { LogError("malloc of %u bytes failed.", *keySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *keyBlob, *keySize, &hte->comm)) { free(*keyBlob); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_RegisterKey_TP(struct host_table_entry *hte, TSS_UUID WrappingKeyUUID, /* in */ TSS_UUID KeyUUID, /* in */ UINT32 cKeySize, /* in */ BYTE * rgbKey, /* in */ UINT32 cVendorData, /* in */ BYTE * gbVendorData /* in */ ) { TSS_RESULT result; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_REGISTERKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UUID, 1, &WrappingKeyUUID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UUID, 2, &KeyUUID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &cKeySize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, rgbKey, cKeySize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 5, &cVendorData, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 6, gbVendorData, cVendorData, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_UnregisterKey_TP(struct host_table_entry *hte, TSS_UUID KeyUUID /* in */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_UNREGISTERKEY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UUID, 1, &KeyUUID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_EnumRegisteredKeys_TP(struct host_table_entry *hte, TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO ** ppKeyHierarchy /* out */ ) { TSS_RESULT result; int i, j; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_ENUMREGISTEREDKEYS; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pKeyUUID != NULL) { if (setData(TCSD_PACKET_TYPE_UUID, 1, pKeyUUID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcKeyHierarchySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (*pcKeyHierarchySize > 0) { *ppKeyHierarchy = malloc((*pcKeyHierarchySize) * sizeof(TSS_KM_KEYINFO)); if (*ppKeyHierarchy == NULL) { LogError("malloc of %zu bytes failed.", (*pcKeyHierarchySize) * sizeof(TSS_KM_KEYINFO)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } for (j = 0; (UINT32)j < *pcKeyHierarchySize; j++) { if (getData(TCSD_PACKET_TYPE_KM_KEYINFO, i++, &((*ppKeyHierarchy)[j]), 0, &hte->comm)) { free(*ppKeyHierarchy); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } else { *ppKeyHierarchy = NULL; } } done: return result; } TSS_RESULT RPC_EnumRegisteredKeys2_TP(struct host_table_entry *hte, TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO2 ** ppKeyHierarchy /* out */ ) { TSS_RESULT result; int i, j; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_ENUMREGISTEREDKEYS2; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pKeyUUID != NULL) { if (setData(TCSD_PACKET_TYPE_UUID, 1, pKeyUUID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcKeyHierarchySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (*pcKeyHierarchySize > 0) { *ppKeyHierarchy = malloc((*pcKeyHierarchySize) * sizeof(TSS_KM_KEYINFO2)); if (*ppKeyHierarchy == NULL) { LogError("malloc of %zu bytes failed.", (*pcKeyHierarchySize) * sizeof(TSS_KM_KEYINFO2)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } for (j = 0; (UINT32)j < *pcKeyHierarchySize; j++) { if (getData(TCSD_PACKET_TYPE_KM_KEYINFO2, i++, &((*ppKeyHierarchy)[j]), 0, &hte->comm)) { free(*ppKeyHierarchy); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } else { *ppKeyHierarchy = NULL; } } done: return result; } TSS_RESULT RPC_GetRegisteredKey_TP(struct host_table_entry *hte, TSS_UUID KeyUUID, /* in */ TSS_KM_KEYINFO ** ppKeyInfo /* out */ ) { return TSPERR(TSS_E_NOTIMPL); } TSS_RESULT RPC_GetRegisteredKeyBlob_TP(struct host_table_entry *hte, TSS_UUID KeyUUID, /* in */ UINT32 * pcKeySize, /* out */ BYTE ** prgbKey /* out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_GETREGISTEREDKEYBLOB; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UUID, 1, &KeyUUID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pcKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbKey = malloc(*pcKeySize); if (*prgbKey == NULL) { LogError("malloc of %u bytes failed.", *pcKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *prgbKey, *pcKeySize, &hte->comm)) { free(*prgbKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_LoadKeyByUUID_TP(struct host_table_entry *hte, TSS_UUID KeyUUID, /* in */ TCS_LOADKEY_INFO * pLoadKeyInfo, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI /* out */ ) { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_LOADKEYBYUUID; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UUID, 1, &KeyUUID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pLoadKeyInfo != NULL) { if (setData(TCSD_PACKET_TYPE_LOADKEY_INFO, 2, pLoadKeyInfo, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, phKeyTCSI, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("TCS key handle: 0x%x", *phKeyTCSI); } else if (pLoadKeyInfo && (result == (TCS_E_KM_LOADFAILED | TSS_LAYER_TCS))) { if (getData(TCSD_PACKET_TYPE_LOADKEY_INFO, 0, pLoadKeyInfo, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } void LoadBlob_LOADKEY_INFO(UINT64 *offset, BYTE *blob, TCS_LOADKEY_INFO *info) { Trspi_LoadBlob_UUID(offset, blob, info->keyUUID); Trspi_LoadBlob_UUID(offset, blob, info->parentKeyUUID); Trspi_LoadBlob(offset, TCPA_DIGEST_SIZE, blob, info->paramDigest.digest); Trspi_LoadBlob_UINT32(offset, info->authData.AuthHandle, blob); Trspi_LoadBlob(offset, TCPA_NONCE_SIZE, blob, (BYTE *)&info->authData.NonceOdd.nonce); Trspi_LoadBlob(offset, TCPA_NONCE_SIZE, blob, (BYTE *)&info->authData.NonceEven.nonce); Trspi_LoadBlob_BOOL(offset, info->authData.fContinueAuthSession, blob); Trspi_LoadBlob(offset, TCPA_DIGEST_SIZE, blob, (BYTE *)&info->authData.HMAC); } void UnloadBlob_LOADKEY_INFO(UINT64 *offset, BYTE *blob, TCS_LOADKEY_INFO *info) { Trspi_UnloadBlob_UUID(offset, blob, &info->keyUUID); Trspi_UnloadBlob_UUID(offset, blob, &info->parentKeyUUID); Trspi_UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, (BYTE *)&info->paramDigest.digest); Trspi_UnloadBlob_UINT32(offset, &info->authData.AuthHandle, blob); Trspi_UnloadBlob(offset, TCPA_NONCE_SIZE, blob, (BYTE *)&info->authData.NonceOdd.nonce); Trspi_UnloadBlob(offset, TCPA_NONCE_SIZE, blob, (BYTE *)&info->authData.NonceEven.nonce); Trspi_UnloadBlob_BOOL(offset, &info->authData.fContinueAuthSession, blob); Trspi_UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, (BYTE *)&info->authData.HMAC); } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_own.c0000664000175000017510000000716613663651711020270 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_TakeOwnership_TP(struct host_table_entry *hte, UINT16 protocolID, /* in */ UINT32 encOwnerAuthSize, /* in */ BYTE * encOwnerAuth, /* in */ UINT32 encSrkAuthSize, /* in */ BYTE * encSrkAuth, /* in */ UINT32 srkInfoSize, /* in */ BYTE * srkInfo, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * srkKeySize, BYTE ** srkKey) { TSS_RESULT result; initData(&hte->comm, 9); hte->comm.hdr.u.ordinal = TCSD_ORD_TAKEOWNERSHIP; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 1, &protocolID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &encOwnerAuthSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, encOwnerAuth, encOwnerAuthSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &encSrkAuthSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 5, encSrkAuth, encSrkAuthSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 6, &srkInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 7, srkInfo, srkInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 8, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 1, srkKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *srkKey = (BYTE *) malloc(*srkKeySize); if (*srkKey == NULL) { LogError("malloc of %u bytes failed.", *srkKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *srkKey, *srkKeySize, &hte->comm)) { free(*srkKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_OwnerClear_TP(struct host_table_entry *hte, TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_OWNERCLEAR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 1, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS ){ if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_changeauth.c0000664000175000017510000001240013663651711021557 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_ChangeAuth_TP(struct host_table_entry *hte, TCS_KEY_HANDLE parentHandle, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH *newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * ownerAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; initData(&hte->comm, 9); hte->comm.hdr.u.ordinal = TCSD_ORD_CHANGEAUTH; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &parentHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 2, &protocolID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 3, newAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 4, &entityType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 5, &encDataSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 6, encData, encDataSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 7, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 8, entityAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_AUTH, 1, entityAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 2, outDataSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outData = (BYTE *) malloc(*outDataSize); if (*outData == NULL) { LogError("malloc of %u bytes failed.", *outDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 3, *outData, *outDataSize, &hte->comm)) { free(*outData); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_ChangeAuthOwner_TP(struct host_table_entry *hte, TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH *newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TPM_AUTH * ownerAuth /* in, out */ ) { TSS_RESULT result; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_CHANGEAUTHOWNER; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 1, &protocolID, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 2, newAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 3, &entityType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 4, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (hte->comm.hdr.u.result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_ChangeAuthAsymStart_TP(struct host_table_entry *hte, TCS_KEY_HANDLE idHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 KeySizeIn, /* in */ BYTE * KeyDataIn, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * KeySizeOut, /* out */ BYTE ** KeyDataOut, /* out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig, /* out */ TCS_KEY_HANDLE * ephHandle /* out */ ) { return TSPERR(TSS_E_NOTIMPL); } TSS_RESULT RPC_ChangeAuthAsymFinish_TP(struct host_table_entry *hte, TCS_KEY_HANDLE parentHandle, /* in */ TCS_KEY_HANDLE ephHandle, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TCPA_HMAC newAuthLink, /* in */ UINT32 newAuthSize, /* in */ BYTE * encNewAuth, /* in */ UINT32 encDataSizeIn, /* in */ BYTE * encDataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * encDataSizeOut, /* out */ BYTE ** encDataOut, /* out */ TCPA_SALT_NONCE * saltNonce, /* out */ TCPA_DIGEST * changeProof /* out */ ) { return TSPERR(TSS_E_NOTIMPL); } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_quote2.c0000664000175000017510000001003513663651711020671 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_Quote2_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE *antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TSS_BOOL addVersion, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32* versionInfoSize, /* out */ BYTE** versionInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_QUOTE2; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 2, antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &pcrDataSizeIn, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, pcrDataIn, pcrDataSizeIn, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 5, &addVersion, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 6, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; /* Takes and sets the output data */ if (result == TSS_SUCCESS) { i = 0; if (privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcrDataSizeOut, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *pcrDataOut = (BYTE *) malloc(*pcrDataSizeOut); if (*pcrDataOut == NULL) { LogError("malloc of %u bytes failed.", *pcrDataSizeOut); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *pcrDataOut, *pcrDataSizeOut, &hte->comm)) { free(*pcrDataOut); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } /* Retrieves the versionInfo Parameters */ if (getData(TCSD_PACKET_TYPE_UINT32, i++, versionInfoSize, 0, &hte->comm)) { free(*pcrDataOut); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (*versionInfoSize >0){ *versionInfo = (BYTE *) malloc(*versionInfoSize); if (*versionInfo == NULL) { LogError("malloc of %u bytes failed.", *versionInfoSize); free(*pcrDataOut); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *versionInfo, *versionInfoSize, &hte->comm)) { free(*pcrDataOut); free(*versionInfo); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, sigSize, 0, &hte->comm)) { free(*pcrDataOut); if (addVersion) free(*versionInfo); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *sig = (BYTE *) malloc(*sigSize); if (*sig == NULL) { LogError("malloc of %u bytes failed.", *sigSize); free(*pcrDataOut); if (addVersion) free(*versionInfo); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *sig, *sigSize, &hte->comm)) { free(*pcrDataOut); if (addVersion) free(*versionInfo); free(*sig); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_transport.c0000664000175000017510000002727113663651711021520 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_EstablishTransport_TP(struct host_table_entry *hte, UINT32 ulTransControlFlags, TCS_KEY_HANDLE hEncKey, UINT32 ulTransSessionInfoSize, BYTE* rgbTransSessionInfo, UINT32 ulSecretSize, BYTE* rgbSecret, TPM_AUTH* pEncKeyAuth, /* in, out */ TPM_MODIFIER_INDICATOR* pbLocality, TCS_HANDLE* hTransSession, UINT32* ulCurrentTicksSize, BYTE** prgbCurrentTicks, TPM_NONCE* pTransNonce) { TSS_RESULT result; UINT32 i; initData(&hte->comm, 8); hte->comm.hdr.u.ordinal = TCSD_ORD_ESTABLISHTRANSPORT; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &ulTransControlFlags, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &hEncKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &ulTransSessionInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, rgbTransSessionInfo, ulTransSessionInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 5, &ulSecretSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 6, rgbSecret, ulSecretSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pEncKeyAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 7, pEncKeyAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (pEncKeyAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pEncKeyAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pbLocality, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, hTransSession, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, ulCurrentTicksSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbCurrentTicks = malloc(*ulCurrentTicksSize); if (*prgbCurrentTicks == NULL) { *ulCurrentTicksSize = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbCurrentTicks, *ulCurrentTicksSize, &hte->comm)) { free(*prgbCurrentTicks); *prgbCurrentTicks = NULL; *ulCurrentTicksSize = 0; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_NONCE, i++, pTransNonce, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_ExecuteTransport_TP(struct host_table_entry *hte, TPM_COMMAND_CODE unWrappedCommandOrdinal, UINT32 ulWrappedCmdParamInSize, BYTE* rgbWrappedCmdParamIn, UINT32* pulHandleListSize, /* in, out */ TCS_HANDLE** rghHandles, /* in, out */ TPM_AUTH* pWrappedCmdAuth1, /* in, out */ TPM_AUTH* pWrappedCmdAuth2, /* in, out */ TPM_AUTH* pTransAuth, /* in, out */ UINT64* punCurrentTicks, TPM_MODIFIER_INDICATOR* pbLocality, TPM_RESULT* pulWrappedCmdReturnCode, UINT32* ulWrappedCmdParamOutSize, BYTE** rgbWrappedCmdParamOut) { TSS_RESULT result; TPM_AUTH null_auth; UINT32 i = 0; __tspi_memset(&null_auth, 0, sizeof(TPM_AUTH)); initData(&hte->comm, 9); hte->comm.hdr.u.ordinal = TCSD_ORD_EXECUTETRANSPORT; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &unWrappedCommandOrdinal, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &ulWrappedCmdParamInSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, i++, rgbWrappedCmdParamIn, ulWrappedCmdParamInSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, pulHandleListSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (*pulHandleListSize) { if (setData(TCSD_PACKET_TYPE_PBYTE, i++, *rghHandles, *pulHandleListSize * sizeof(UINT32), &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (pWrappedCmdAuth1) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pWrappedCmdAuth1, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { if (setData(TCSD_PACKET_TYPE_AUTH, i++, &null_auth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (pWrappedCmdAuth2) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pWrappedCmdAuth2, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { if (setData(TCSD_PACKET_TYPE_AUTH, i++, &null_auth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, i++, pTransAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (getData(TCSD_PACKET_TYPE_UINT32, i++, pulHandleListSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (*pulHandleListSize) { *rghHandles = malloc(*pulHandleListSize * sizeof(UINT32)); if (*rghHandles == NULL) { *pulHandleListSize = 0; return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *rghHandles, *pulHandleListSize * sizeof(UINT32), &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } } if (pWrappedCmdAuth1) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pWrappedCmdAuth1, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } } else { if (getData(TCSD_PACKET_TYPE_AUTH, i++, &null_auth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } } if (pWrappedCmdAuth2) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pWrappedCmdAuth2, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } } else { if (getData(TCSD_PACKET_TYPE_AUTH, i++, &null_auth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } } if (getData(TCSD_PACKET_TYPE_AUTH, i++, pTransAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } if (getData(TCSD_PACKET_TYPE_UINT64, i++, punCurrentTicks, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pbLocality, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pulWrappedCmdReturnCode, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, ulWrappedCmdParamOutSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } if (*ulWrappedCmdParamOutSize) { *rgbWrappedCmdParamOut = malloc(*ulWrappedCmdParamOutSize); if (*rgbWrappedCmdParamOut == NULL) { *ulWrappedCmdParamOutSize = 0; result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *rgbWrappedCmdParamOut, *ulWrappedCmdParamOutSize, &hte->comm)) { free(*rgbWrappedCmdParamOut); result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } } else *rgbWrappedCmdParamOut = NULL; } return result; error: if (*pulHandleListSize) { free(*rghHandles); *rghHandles = NULL; } return result; } TSS_RESULT RPC_ReleaseTransportSigned_TP(struct host_table_entry *hte, TCS_KEY_HANDLE hSignatureKey, TPM_NONCE* AntiReplayNonce, TPM_AUTH* pKeyAuth, /* in, out */ TPM_AUTH* pTransAuth, /* in, out */ TPM_MODIFIER_INDICATOR* pbLocality, UINT32* pulCurrentTicksSize, BYTE** prgbCurrentTicks, UINT32* pulSignatureSize, BYTE** prgbSignature) { TSS_RESULT result; TPM_AUTH null_auth; __tspi_memset(&null_auth, 0, sizeof(TPM_AUTH)); initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_RELEASETRANSPORTSIGNED; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hSignatureKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 2, AntiReplayNonce, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pKeyAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 3, pKeyAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { if (setData(TCSD_PACKET_TYPE_AUTH, 3, &null_auth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, 4, pTransAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (pKeyAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pKeyAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { if (getData(TCSD_PACKET_TYPE_AUTH, 0, &null_auth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, 1, pTransAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, pbLocality, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 3, pulCurrentTicksSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); *prgbCurrentTicks = malloc(*pulCurrentTicksSize); if (*prgbCurrentTicks == NULL) { *pulCurrentTicksSize = 0; return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, *prgbCurrentTicks, *pulCurrentTicksSize, &hte->comm)) { free(*prgbCurrentTicks); *prgbCurrentTicks = NULL; *pulCurrentTicksSize = 0; return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 5, pulSignatureSize, 0, &hte->comm)) { free(*prgbCurrentTicks); *prgbCurrentTicks = NULL; *pulCurrentTicksSize = 0; return TSPERR(TSS_E_INTERNAL_ERROR); } *prgbSignature = malloc(*pulSignatureSize); if (*prgbSignature == NULL) { free(*prgbCurrentTicks); *prgbCurrentTicks = NULL; *pulCurrentTicksSize = 0; *pulSignatureSize = 0; return TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_PBYTE, 6, *prgbSignature, *pulSignatureSize, &hte->comm)) { free(*prgbCurrentTicks); *prgbCurrentTicks = NULL; *pulCurrentTicksSize = 0; free(*prgbSignature); *prgbSignature = NULL; *pulSignatureSize = 0; return TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_selftest.c0000664000175000017510000000726313663651711021314 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_SelfTestFull_TP(struct host_table_entry *hte) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_SELFTESTFULL; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_CertifySelfTest_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_CERTIFYSELFTEST; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 2, &antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 3, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { LogDebug("privAuth"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, sigSize, 0, &hte->comm)) { LogDebug("sigSize"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *sig = (BYTE *) malloc(*sigSize); if (*sig == NULL) { LogError("malloc of %u bytes failed.", *sigSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *sig, *sigSize, &hte->comm)) { LogDebug("sig"); free(*sig); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_GetTestResult_TP(struct host_table_entry *hte, UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_GETTESTRESULT; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); LogDebug("RPC_GetTestResult_TP"); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { LogDebug("sendTCSDPacket succeeded"); if (getData(TCSD_PACKET_TYPE_UINT32, 0, outDataSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outData = malloc(*outDataSize); if (*outData == NULL) { LogError("malloc of %u bytes failed.", *outDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *outData, *outDataSize, &hte->comm)) { free(*outData); *outData = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); } } LogDebug("RPC_GetTestResult_TP exit"); done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_tick.c0000664000175000017510000001070713663651711020412 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_ReadCurrentTicks_TP(struct host_table_entry* hte, UINT32* pulCurrentTime, /* out */ BYTE** prgbCurrentTime) /* out */ { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_READCURRENTTICKS; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pulCurrentTime, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbCurrentTime = malloc(*pulCurrentTime); if (*prgbCurrentTime == NULL) { *pulCurrentTime = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *prgbCurrentTime, *pulCurrentTime, &hte->comm)) { free(*prgbCurrentTime); *prgbCurrentTime = NULL; *pulCurrentTime = 0; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_TickStampBlob_TP(struct host_table_entry* hte, TCS_KEY_HANDLE hKey, /* in */ TPM_NONCE* antiReplay, /* in */ TPM_DIGEST* digestToStamp, /* in */ TPM_AUTH* privAuth, /* in, out */ UINT32* pulSignatureLength, /* out */ BYTE** prgbSignature, /* out */ UINT32* pulTickCountLength, /* out */ BYTE** prgbTickCount) /* out */ { TSS_RESULT result; UINT32 i; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_TICKSTAMPBLOB; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 2, antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 3, digestToStamp, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pulSignatureLength, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbSignature = malloc(*pulSignatureLength); if (*prgbSignature == NULL) { *pulSignatureLength = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbSignature, *pulSignatureLength, &hte->comm)) { free(*prgbSignature); *prgbSignature = NULL; *pulSignatureLength = 0; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pulTickCountLength, 0, &hte->comm)) { free(*prgbSignature); *prgbSignature = NULL; *pulSignatureLength = 0; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbTickCount = malloc(*pulTickCountLength); if (*prgbTickCount == NULL) { free(*prgbSignature); *prgbSignature = NULL; *pulSignatureLength = 0; *pulTickCountLength = 0; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbTickCount, *pulTickCountLength, &hte->comm)) { free(*prgbSignature); *prgbSignature = NULL; *pulSignatureLength = 0; free(*prgbTickCount); *prgbTickCount = NULL; *pulTickCountLength = 0; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_sign.c0000664000175000017510000000444013663651711020415 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_Sign_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ UINT32 areaToSignSize, /* in */ BYTE * areaToSign, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig /* out */ ) { TSS_RESULT result; int i; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_SIGN; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &areaToSignSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, areaToSign, areaToSignSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, sigSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *sig = (BYTE *) malloc(*sigSize); if (*sig == NULL) { LogError("malloc of %u bytes failed.", *sigSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *sig, *sigSize, &hte->comm)) { result = free_tspi(hte->tspContext, *sig); if (result == TSS_SUCCESS) result = TSPERR(TSS_E_INTERNAL_ERROR); else free(*sig); } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_aik.c0000664000175000017510000002456313663651711020231 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_MakeIdentity_TP(struct host_table_entry *hte, TCPA_ENCAUTH identityAuth, /* in */ TCPA_CHOSENID_HASH IDLabel_PrivCAHash, /* in */ UINT32 idKeyInfoSize, /* in */ BYTE * idKeyInfo, /* in */ TPM_AUTH * pSrkAuth, /* in, out */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * idKeySize, /* out */ BYTE ** idKey, /* out */ UINT32 * pcIdentityBindingSize, /* out */ BYTE ** prgbIdentityBinding, /* out */ UINT32 * pcEndorsementCredentialSize, /* out */ BYTE ** prgbEndorsementCredential, /* out */ UINT32 * pcPlatformCredentialSize, /* out */ BYTE ** prgbPlatformCredential, /* out */ UINT32 * pcConformanceCredentialSize, /* out */ BYTE ** prgbConformanceCredential) /* out */ { TSS_RESULT result; int i; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_MAKEIDENTITY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 1, &identityAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 2, &IDLabel_PrivCAHash, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &idKeyInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, idKeyInfo, idKeyInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); i = 5; if (pSrkAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, pSrkAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, i++, pOwnerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; i = 0; if (result == TSS_SUCCESS) { i = 0; if (pSrkAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, pSrkAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_AUTH, i++, pOwnerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, idKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *idKey = (BYTE *) malloc(*idKeySize); if (*idKey == NULL) { LogError("malloc of %u bytes failed.", *idKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *idKey, *idKeySize, &hte->comm)) { free(*idKey); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcIdentityBindingSize, 0, &hte->comm)) { free(*idKey); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbIdentityBinding = (BYTE *) malloc(*pcIdentityBindingSize); if (*prgbIdentityBinding == NULL) { LogError("malloc of %u bytes failed.", *pcIdentityBindingSize); free(*idKey); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbIdentityBinding, *pcIdentityBindingSize, &hte->comm)) { free(*idKey); free(*prgbIdentityBinding); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcEndorsementCredentialSize, 0, &hte->comm)) { free(*idKey); free(*prgbIdentityBinding); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbEndorsementCredential = (BYTE *) malloc(*pcEndorsementCredentialSize); if (*prgbEndorsementCredential == NULL) { LogError("malloc of %u bytes failed.", *pcEndorsementCredentialSize); free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbEndorsementCredential, *pcEndorsementCredentialSize, &hte->comm)) { free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; free(*prgbEndorsementCredential); *prgbEndorsementCredential = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcPlatformCredentialSize, 0, &hte->comm)) { free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; free(*prgbEndorsementCredential); *prgbEndorsementCredential = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbPlatformCredential = (BYTE *) malloc(*pcPlatformCredentialSize); if (*prgbPlatformCredential == NULL) { LogError("malloc of %u bytes failed.", *pcPlatformCredentialSize); free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; free(*prgbEndorsementCredential); *prgbEndorsementCredential = NULL; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbPlatformCredential, *pcPlatformCredentialSize, &hte->comm)) { free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; free(*prgbEndorsementCredential); *prgbEndorsementCredential = NULL; free(*prgbPlatformCredential); *prgbPlatformCredential = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pcConformanceCredentialSize, 0, &hte->comm)) { free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; free(*prgbEndorsementCredential); *prgbEndorsementCredential = NULL; free(*prgbPlatformCredential); *prgbPlatformCredential = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *prgbConformanceCredential = (BYTE *) malloc(*pcConformanceCredentialSize); if (*prgbConformanceCredential == NULL) { LogError("malloc of %u bytes failed.", *pcConformanceCredentialSize); free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; free(*prgbEndorsementCredential); *prgbEndorsementCredential = NULL; free(*prgbPlatformCredential); *prgbPlatformCredential = NULL; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *prgbConformanceCredential, *pcConformanceCredentialSize, &hte->comm)) { free(*idKey); free(*prgbIdentityBinding); *prgbIdentityBinding = NULL; free(*prgbEndorsementCredential); *prgbEndorsementCredential = NULL; free(*prgbPlatformCredential); *prgbPlatformCredential = NULL; free(*prgbConformanceCredential); *prgbConformanceCredential = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_GetCredential_TP(struct host_table_entry *hte, UINT32 ulCredentialType, /* in */ UINT32 ulCredentialAccessMode, /* in */ UINT32 * pulCredentialSize, /* out */ BYTE ** prgbCredentialData) /* out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_GETCREDENTIAL; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &ulCredentialType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &ulCredentialAccessMode, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pulCredentialSize, 0, &hte->comm)) { return TSPERR(TSS_E_INTERNAL_ERROR); } *prgbCredentialData = (BYTE *) malloc(*pulCredentialSize); if (*prgbCredentialData == NULL) { LogError("malloc of %u bytes failed.", *pulCredentialSize); return TSPERR(TSS_E_OUTOFMEMORY); } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *prgbCredentialData, *pulCredentialSize, &hte->comm)) { free(*prgbCredentialData); result = TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } TSS_RESULT RPC_ActivateTPMIdentity_TP(struct host_table_entry *hte, TCS_KEY_HANDLE idKey, /* in */ UINT32 blobSize, /* in */ BYTE * blob, /* in */ TPM_AUTH * idKeyAuth, /* in, out */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * SymmetricKeySize, /* out */ BYTE ** SymmetricKey) /* out */ { TSS_RESULT result; int i = 0; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_ACTIVATETPMIDENTITY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &idKey, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, i++, &blobSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, i++, blob, blobSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (idKeyAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, i++, idKeyAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } if (setData(TCSD_PACKET_TYPE_AUTH, i++, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (idKeyAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, idKeyAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_AUTH, i++, ownerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, SymmetricKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *SymmetricKey = malloc(*SymmetricKeySize); if (*SymmetricKey == NULL) { LogError("malloc of %u bytes failed.", *SymmetricKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *SymmetricKey, *SymmetricKeySize, &hte->comm)) { free(*SymmetricKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_counter.c0000664000175000017510000001352013663651711021133 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_ReadCounter_TP(struct host_table_entry* hte, TSS_COUNTER_ID idCounter, /* in */ TPM_COUNTER_VALUE* counterValue) /* out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_READCOUNTER; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_COUNTER_VALUE, 0, counterValue, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_CreateCounter_TP(struct host_table_entry* hte, UINT32 LabelSize, /* in (=4) */ BYTE* pLabel, /* in */ TPM_ENCAUTH CounterAuth, /* in */ TPM_AUTH* pOwnerAuth, /* in, out */ TSS_COUNTER_ID* idCounter, /* out */ TPM_COUNTER_VALUE* counterValue) /* out */ { TSS_RESULT result; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_CREATECOUNTER; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &LabelSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, &pLabel, LabelSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 3, &CounterAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 4, pOwnerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pOwnerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 1, idCounter, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_COUNTER_VALUE, 2, counterValue, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_IncrementCounter_TP(struct host_table_entry* hte, TSS_COUNTER_ID idCounter, /* in */ TPM_AUTH* pCounterAuth, /* in, out */ TPM_COUNTER_VALUE* counterValue) /* out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_INCREMENTCOUNTER; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 2, pCounterAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pCounterAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_COUNTER_VALUE, 1, counterValue, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_ReleaseCounter_TP(struct host_table_entry* hte, TSS_COUNTER_ID idCounter, /* in */ TPM_AUTH* pCounterAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_RELEASECOUNTER; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 2, pCounterAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pCounterAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_ReleaseCounterOwner_TP(struct host_table_entry* hte, TSS_COUNTER_ID idCounter, /* in */ TPM_AUTH* pOwnerAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_RELEASECOUNTEROWNER; LogDebugFn("IN: TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &idCounter, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 2, pOwnerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pOwnerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_nv.c0000664000175000017510000002133113663651711020076 0ustar deboradebora/* * The Initial Developer of the Original Code is Intel Corporation. * Portions created by Intel Corporation are Copyright (C) 2007 Intel Corporation. * All Rights Reserved. * * trousers - An open source TCG Software Stack * * Author: james.xu@intel.com Rossey.liu@intel.com * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_NV_DefineOrReleaseSpace_TP(struct host_table_entry *hte, /* in */ UINT32 cPubInfoSize, /* in */ BYTE* pPubInfo, /* in */ TCPA_ENCAUTH encAuth, /* in */ TPM_AUTH* pAuth) /* in,out */ { TSS_RESULT result; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_NVDEFINEORRELEASESPACE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &cPubInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, pPubInfo, cPubInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_ENCAUTH, 3, &encAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if( pAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, pAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { LogDebugFn("getData outputSize"); if( pAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } done: LogDebugFn("result=%u", result); return result; } TSS_RESULT RPC_NV_WriteValue_TP(struct host_table_entry *hte, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* privAuth) /* in,out */ { TSS_RESULT result; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_NVWRITEVALUE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &ulDataLength, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, rgbDataToWrite, ulDataLength, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if( privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 5, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { LogDebugFn("getData outputSize"); if( privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } done: LogDebugFn("result=%u", result); return result; } TSS_RESULT RPC_NV_WriteValueAuth_TP(struct host_table_entry *hte, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* NVAuth) /* in,out */ { TSS_RESULT result; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_NVWRITEVALUEAUTH; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &ulDataLength, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, rgbDataToWrite, ulDataLength, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if( NVAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 5, NVAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { LogDebugFn("getData outputSize"); if( NVAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, NVAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } done: LogDebugFn("result=%u", result); return result; } TSS_RESULT RPC_NV_ReadValue_TP(struct host_table_entry *hte, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in,out */ TPM_AUTH* privAuth, /* in,out */ BYTE** rgbDataRead) /* out */ { TSS_RESULT result; UINT32 i; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_NVREADVALUE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, pulDataLength, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("SetData privAuth\n"); if( privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } LogDebugFn("Send data.\n"); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; LogDebugFn("result=%u", result); if (result == TSS_SUCCESS) { i = 0; LogDebugFn("getData outputSize"); if( privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pulDataLength, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *rgbDataRead = (BYTE *) malloc(*pulDataLength); if (*rgbDataRead == NULL) { LogError("malloc of %u bytes failed.", *pulDataLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } LogDebugFn("getData rgbDataRead (pulDataLength=%u)", *pulDataLength); if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *rgbDataRead, *pulDataLength, &hte->comm)) { free(*rgbDataRead); *rgbDataRead = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: LogDebugFn("result=%u", result); return result; } TSS_RESULT RPC_NV_ReadValueAuth_TP(struct host_table_entry *hte, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in,out */ TPM_AUTH* NVAuth, /* in,out */ BYTE** rgbDataRead) /* out */ { TSS_RESULT result; UINT32 i; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_NVREADVALUEAUTH; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hNVStore, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &offset, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, pulDataLength, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if( NVAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, NVAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; LogDebugFn("getData outputSize"); if( NVAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, NVAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, pulDataLength, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *rgbDataRead = (BYTE *) malloc(*pulDataLength); if (*rgbDataRead == NULL) { LogError("malloc of %u bytes failed.", *pulDataLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } LogDebugFn("getData rgbDataRead (pulDataLength=%u)", *pulDataLength); if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *rgbDataRead, *pulDataLength, &hte->comm)) { free(*rgbDataRead); *rgbDataRead = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: LogDebugFn("result=%u", result); return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_oper.c0000664000175000017510000000177713663651711020434 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_SetOperatorAuth_TP(struct host_table_entry *hte, TCPA_SECRET *operatorAuth) /* in */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_SETOPERATORAUTH; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_SECRET, 1, operatorAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_caps_tpm.c0000664000175000017510000001204113663651711021257 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_GetTPMCapability_TP(struct host_table_entry *hte, TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp) /* out */ { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_GETCAPABILITY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &capArea, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &subCapSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, subCap, subCapSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, respSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *resp = (BYTE *) malloc(*respSize); if (*resp == NULL) { LogError("malloc of %u bytes failed.", *respSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *resp, *respSize, &hte->comm)) { free(*resp); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_GetCapabilitySigned_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ TPM_AUTH * privAuth, /* in, out */ TCPA_VERSION * Version, /* out */ UINT32 * respSize, /* out */ BYTE ** resp, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { return TSPERR(TSS_E_NOTIMPL); } TSS_RESULT RPC_GetCapabilityOwner_TP(struct host_table_entry *hte, TPM_AUTH * pOwnerAuth, /* out */ TCPA_VERSION * pVersion, /* out */ UINT32 * pNonVolatileFlags, /* out */ UINT32 * pVolatileFlags) /* out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_GETCAPABILITYOWNER; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 1, pOwnerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_VERSION, 0, pVersion, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 1, pNonVolatileFlags, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 2, pVolatileFlags, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_AUTH, 3, pOwnerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_SetCapability_TP(struct host_table_entry *hte, TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 valueSize, /* in */ BYTE * value, /* in */ TPM_AUTH * pOwnerAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 7); hte->comm.hdr.u.ordinal = TCSD_ORD_SETCAPABILITY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &capArea, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &subCapSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, subCap, subCapSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 4, &valueSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 5, value, valueSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (pOwnerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 6, pOwnerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, pOwnerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_evlog.c0000664000175000017510000001325613663651711020576 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_LogPcrEvent_TP(struct host_table_entry *hte, TSS_PCR_EVENT Event, /* in */ UINT32 * pNumber /* out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_LOGPCREVENT; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PCR_EVENT, 1, &Event, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pNumber, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_GetPcrEvent_TP(struct host_table_entry *hte, UINT32 PcrIndex, /* in */ UINT32 * pNumber, /* in, out */ TSS_PCR_EVENT ** ppEvent /* out */ ) { TSS_RESULT result; BYTE lengthOnly = (ppEvent == NULL) ? TRUE : FALSE; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_GETPCREVENT; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &PcrIndex, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, pNumber, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BYTE, 3, &lengthOnly, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pNumber, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (ppEvent) { *ppEvent = malloc(sizeof(TSS_PCR_EVENT)); if (*ppEvent == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_PCR_EVENT)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PCR_EVENT, 1, *ppEvent, 0, &hte->comm)) { free(*ppEvent); *ppEvent = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); } } } done: return result; } TSS_RESULT RPC_GetPcrEventsByPcr_TP(struct host_table_entry *hte, UINT32 PcrIndex, /* in */ UINT32 FirstEvent, /* in */ UINT32 * pEventCount, /* in, out */ TSS_PCR_EVENT ** ppEvents /* out */ ) { TSS_RESULT result; UINT32 i, j; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_GETPCREVENTBYPCR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &PcrIndex, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &FirstEvent, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, pEventCount, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pEventCount, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (*pEventCount > 0) { *ppEvents = calloc_tspi(hte->tspContext, sizeof(TSS_PCR_EVENT) * (*pEventCount)); if (*ppEvents == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_PCR_EVENT) * (*pEventCount)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } i = 1; for (j = 0; j < (*pEventCount); j++) { if (getData(TCSD_PACKET_TYPE_PCR_EVENT, i++, &((*ppEvents)[j]), 0, &hte->comm)) { free(*ppEvents); *ppEvents = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } else { *ppEvents = NULL; } } done: return result; } TSS_RESULT RPC_GetPcrEventLog_TP(struct host_table_entry *hte, UINT32 * pEventCount, /* out */ TSS_PCR_EVENT ** ppEvents /* out */ ) { TSS_RESULT result; int i, j; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_GETPCREVENTLOG; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pEventCount, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (*pEventCount > 0) { *ppEvents = calloc_tspi(hte->tspContext, sizeof(TSS_PCR_EVENT) * (*pEventCount)); if (*ppEvents == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TSS_PCR_EVENT) * (*pEventCount)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } i = 1; for (j = 0; (UINT32)j < (*pEventCount); j++) { if (getData(TCSD_PACKET_TYPE_PCR_EVENT, i++, &((*ppEvents)[j]), 0, &hte->comm)) { free(*ppEvents); *ppEvents = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } } else { *ppEvents = NULL; } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_caps.c0000664000175000017510000000365213663651711020407 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_GetCapability_TP(struct host_table_entry *hte, TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp) /* out */ { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_TCSGETCAPABILITY; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &capArea, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &subCapSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, subCap, subCapSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, respSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *resp = (BYTE *) calloc_tspi(hte->tspContext, *respSize); if (*resp == NULL) { LogError("malloc of %u bytes failed.", *respSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *resp, *respSize, &hte->comm)) { free_tspi(hte->tspContext, *resp); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_daa.c0000664000175000017510000001266413663651711020211 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_DaaJoin_TP(struct host_table_entry *hte, TPM_HANDLE handle, // in BYTE stage, // in UINT32 inputSize0, // in BYTE* inputData0, // in UINT32 inputSize1, // in BYTE* inputData1, // in TPM_AUTH* ownerAuth, // in/out UINT32* outputSize, // out BYTE** outputData) // out { TSS_RESULT result; UINT32 i; LogDebugFn("stage=%d", stage); initData(&hte->comm, 8); hte->comm.hdr.u.ordinal = TCSD_ORD_DAAJOIN; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &handle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BYTE, 2, &stage, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &inputSize0, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("inputSize0==%d =%d", inputSize0, inputSize0); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, inputData0, inputSize0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 5, &inputSize1, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("inputSize1==%d =%d", inputSize1, inputSize1); if (setData(TCSD_PACKET_TYPE_PBYTE, 6, inputData1, inputSize1, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if( ownerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 7, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; LogDebugFn("getData outputSize"); if( ownerAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, ownerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outputSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outputData = (BYTE *) malloc(*outputSize); if (*outputData == NULL) { LogError("malloc of %u bytes failed.", *outputSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } LogDebugFn("getData outputData (outputSize=%u)", *outputSize); if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outputData, *outputSize, &hte->comm)) { free(*outputData); *outputData = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: LogDebugFn("result=%u", result); return result; } TSS_RESULT RPC_DaaSign_TP(struct host_table_entry *hte, TPM_HANDLE handle, // in BYTE stage, // in UINT32 inputSize0, // in BYTE* inputData0, // in UINT32 inputSize1, // in BYTE* inputData1, // in TPM_AUTH* ownerAuth, // in/out UINT32* outputSize, // out BYTE** outputData) // out { TSS_RESULT result; UINT32 i; LogDebugFn("stage=%d", stage); initData(&hte->comm, 8); hte->comm.hdr.u.ordinal = TCSD_ORD_DAASIGN; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &handle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BYTE, 2, &stage, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 3, &inputSize0, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("inputSize0==%d =%d", inputSize0, inputSize0); if (setData(TCSD_PACKET_TYPE_PBYTE, 4, inputData0, inputSize0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 5, &inputSize1, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); LogDebugFn("inputSize1==%d =%d", inputSize1, inputSize1); if (setData(TCSD_PACKET_TYPE_PBYTE, 6, inputData1, inputSize1, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if( ownerAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 7, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } LogDebugFn("sendTCSDPacket: 0x%x", (int)hte); result = sendTCSDPacket(hte); // if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; // if (result == TSS_SUCCESS) { i = 0; LogDebugFn("getData outputSize"); if( ownerAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, ownerAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, outputSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *outputData = (BYTE *) malloc(*outputSize); if (*outputData == NULL) { LogError("malloc of %u bytes failed.", *outputSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } LogDebugFn("getData outputData (outputSize=%d)", *outputSize); if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *outputData, *outputSize, &hte->comm)) { free(*outputData); *outputData = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: LogDebugFn("result=%u", result); return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_maint.c0000664000175000017510000001557013663651711020573 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_CreateMaintenanceArchive_TP(struct host_table_entry *hte, TSS_BOOL generateRandom, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * archiveSize, /* out */ BYTE ** archive /* out */ ) { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_CREATEMAINTENANCEARCHIVE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 1, &generateRandom, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 2, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 1, randomSize, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (*randomSize > 0) { *random = malloc(*randomSize); if (*random == NULL) { LogError("malloc of %u bytes failed.", *randomSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *random, *randomSize, &hte->comm)) { free(*random); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } else { *random = NULL; } /* Assume all elements are in the list, even when *randomSize == 0. */ if (getData(TCSD_PACKET_TYPE_UINT32, 3, archiveSize, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (*archiveSize > 0) { *archive = malloc(*archiveSize); if (*archive == NULL) { free(*random); LogError("malloc of %u bytes failed.", *archiveSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 4, *archive, *archiveSize, &hte->comm)) { free(*random); free(*archive); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } else { *archive = NULL; } } done: return result; } TSS_RESULT RPC_LoadMaintenanceArchive_TP(struct host_table_entry *hte, UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut /* out */ ) { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_LOADMAINTENANCEARCHIVE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &dataInSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 2, &dataIn, dataInSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 3, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (getData(TCSD_PACKET_TYPE_UINT32, 1, dataOutSize, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); if (*dataOutSize > 0) { *dataOut = malloc(*dataOutSize); if (*dataOut == NULL) { LogError("malloc of %u bytes failed.", *dataOutSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *dataOut, *dataOutSize, &hte->comm)) { free(*dataOut); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } else { *dataOut = NULL; } } done: return result; } TSS_RESULT RPC_KillMaintenanceFeature_TP(struct host_table_entry *hte, TPM_AUTH * ownerAuth /* in , out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_KILLMAINTENANCEFEATURE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 1, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_LoadManuMaintPub_TP(struct host_table_entry *hte, TCPA_NONCE antiReplay, /* in */ UINT32 PubKeySize, /* in */ BYTE * PubKey, /* in */ TCPA_DIGEST * checksum /* out */ ) { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_LOADMANUFACTURERMAINTENANCEPUB; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &PubKeySize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, PubKey, PubKeySize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_DIGEST, 0, checksum, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_ReadManuMaintPub_TP(struct host_table_entry *hte, TCPA_NONCE antiReplay, /* in */ TCPA_DIGEST * checksum /* out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_READMANUFACTURERMAINTENANCEPUB; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_DIGEST, 0, checksum, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_audit.c0000664000175000017510000001543213663651711020566 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_SetOrdinalAuditStatus_TP(struct host_table_entry *hte, TPM_AUTH *ownerAuth, /* in/out */ UINT32 ulOrdinal, /* in */ TSS_BOOL bAuditState) /* in */ { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_SETORDINALAUDITSTATUS; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &ulOrdinal, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 2, &bAuditState, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 3, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_GetAuditDigest_TP(struct host_table_entry *hte, UINT32 startOrdinal, /* in */ TPM_DIGEST *auditDigest, /* out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TSS_BOOL *more, /* out */ UINT32 *ordSize, /* out */ UINT32 **ordList) /* out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_GETAUDITDIGEST; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &startOrdinal, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_DIGEST, 0, auditDigest, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 1, counterValueSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *counterValue = (BYTE *)malloc(*counterValueSize); if (*counterValue == NULL) { LogError("malloc of %u bytes failed.", *counterValueSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *counterValue, *counterValueSize, &hte->comm)) { free(*counterValue); *counterValue = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_BOOL, 3, more, 0, &hte->comm)) { free(*counterValue); *counterValue = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 4, ordSize, 0, &hte->comm)) { free(*counterValue); *counterValue = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *ordList = (UINT32 *)malloc(*ordSize * sizeof(UINT32)); if (*ordList == NULL) { LogError("malloc of %u bytes failed.", *ordSize); free(*counterValue); *counterValue = NULL; result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 5, *ordList, *ordSize * sizeof(UINT32), &hte->comm)) { free(*counterValue); *counterValue = NULL; free(*ordList); *ordList = NULL; result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } TSS_RESULT RPC_GetAuditDigestSigned_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ TSS_BOOL closeAudit, /* in */ TPM_NONCE *antiReplay, /* in */ TPM_AUTH *privAuth, /* in/out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TPM_DIGEST *auditDigest, /* out */ TPM_DIGEST *ordinalDigest, /* out */ UINT32 *sigSize, /* out */ BYTE **sig) /* out */ { TSS_RESULT result; TPM_AUTH null_auth; int i; initData(&hte->comm, 5); hte->comm.hdr.u.ordinal = TCSD_ORD_GETAUDITDIGESTSIGNED; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); __tspi_memset(&null_auth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &keyHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 2, &closeAudit, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 3, antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (privAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 4, privAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { if (setData(TCSD_PACKET_TYPE_AUTH, 4, &null_auth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { i = 0; if (privAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, i++, privAuth, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } if (getData(TCSD_PACKET_TYPE_UINT32, i++, counterValueSize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *counterValue = (BYTE *)malloc(*counterValueSize); if (*counterValue == NULL) { LogError("malloc of %u bytes failed.", *counterValueSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *counterValue, *counterValueSize, &hte->comm)) { free(*counterValue); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_DIGEST, i++, auditDigest, 0, &hte->comm)) { free(*counterValue); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_DIGEST, i++, ordinalDigest, 0, &hte->comm)) { free(*counterValue); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, i++, sigSize, 0, &hte->comm)) { free(*counterValue); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *sig = (BYTE *)malloc(*sigSize); if (*sig == NULL) { LogError("malloc of %u bytes failed.", *sigSize); free(*counterValue); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, i++, *sig, *sigSize, &hte->comm)) { free(*counterValue); free(*sig); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } trousers-0.3.15/src/tspi/rpc/tcstp/rpc_admin.c0000664000175000017510000002202713663651711020546 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_SetOwnerInstall_TP(struct host_table_entry *hte, TSS_BOOL state) /* in */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_SETOWNERINSTALL; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 1, &state, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_DisableOwnerClear_TP(struct host_table_entry *hte, TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_DISABLEOWNERCLEAR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 1, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS ){ if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_ForceClear_TP(struct host_table_entry *hte) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_FORCECLEAR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_DisableForceClear_TP(struct host_table_entry *hte) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_DISABLEFORCECLEAR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_PhysicalDisable_TP(struct host_table_entry *hte) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_PHYSICALDISABLE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_PhysicalEnable_TP(struct host_table_entry *hte) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_PHYSICALENABLE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_OwnerSetDisable_TP(struct host_table_entry *hte, TSS_BOOL disableState, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_OWNERSETDISABLE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 1, &disableState, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 2, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_PhysicalSetDeactivated_TP(struct host_table_entry *hte, TSS_BOOL state) /* in */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_PHYSICALSETDEACTIVATED; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 1, &state, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_PhysicalPresence_TP(struct host_table_entry *hte, TCPA_PHYSICAL_PRESENCE fPhysicalPresence) /* in */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_PHYSICALPRESENCE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT16, 1, &fPhysicalPresence, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } TSS_RESULT RPC_SetTempDeactivated_TP(struct host_table_entry *hte) { TSS_RESULT result; initData(&hte->comm, 1); hte->comm.hdr.u.ordinal = TCSD_ORD_SETTEMPDEACTIVATED; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_SetTempDeactivated2_TP(struct host_table_entry *hte, TPM_AUTH *operatorAuth) /* in/out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_SETTEMPDEACTIVATED2; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (operatorAuth) { if (setData(TCSD_PACKET_TYPE_AUTH, 1, operatorAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } else { TPM_AUTH nullAuth; __tspi_memset(&nullAuth, 0, sizeof(TPM_AUTH)); if (setData(TCSD_PACKET_TYPE_AUTH, 1, &nullAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); } result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (operatorAuth) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, operatorAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } } return result; } #endif TSS_RESULT RPC_FieldUpgrade_TP(struct host_table_entry *hte, UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut, /* out */ TPM_AUTH * ownerAuth) /* in, out */ { return TSPERR(TSS_E_NOTIMPL); } TSS_RESULT RPC_SetRedirection_TP(struct host_table_entry *hte, TCS_KEY_HANDLE keyHandle, /* in */ UINT32 c1, /* in */ UINT32 c2, /* in */ TPM_AUTH * privAuth) /* in, out */ { return TSPERR(TSS_E_NOTIMPL); } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_ResetLockValue_TP(struct host_table_entry *hte, TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_RESETLOCKVALUE; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 1, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_FlushSpecific_TP(struct host_table_entry *hte, TCS_HANDLE hResHandle, /* in */ TPM_RESOURCE_TYPE resourceType) /* in */ { TSS_RESULT result; initData(&hte->comm, 3); hte->comm.hdr.u.ordinal = TCSD_ORD_FLUSHSPECIFIC; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 1, &hResHandle, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &resourceType, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } #endif trousers-0.3.15/src/tspi/rpc/tcstp/rpc_ek.c0000664000175000017510000002224013663651711020052 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "obj.h" #include "rpc_tcstp_tsp.h" TSS_RESULT RPC_CreateEndorsementKeyPair_TP(struct host_table_entry *hte, TCPA_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize, /* in */ BYTE * endorsementKeyInfo, /* in */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TCPA_DIGEST * checksum /* out */ ) { TSS_RESULT result; initData(&hte->comm, 4); hte->comm.hdr.u.ordinal = TCSD_ORD_CREATEENDORSEMENTKEYPAIR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &endorsementKeyInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, endorsementKeyInfo, endorsementKeyInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, endorsementKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *endorsementKey = (BYTE *) malloc(*endorsementKeySize); if (*endorsementKey == NULL) { LogError("malloc of %u bytes failed.", *endorsementKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *endorsementKey, *endorsementKeySize, &hte->comm)) { free(*endorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_DIGEST, 2, &(checksum->digest), 0, &hte->comm)) { free(*endorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_ReadPubek_TP(struct host_table_entry *hte, TCPA_NONCE antiReplay, /* in */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey, /* out */ TCPA_DIGEST * checksum /* out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_READPUBEK; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); /* &hte->comm.numParms = 2; */ if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_UINT32, 0, pubEndorsementKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *pubEndorsementKey = (BYTE *) malloc(*pubEndorsementKeySize); if (*pubEndorsementKey == NULL) { LogError("malloc of %u bytes failed.", *pubEndorsementKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 1, *pubEndorsementKey, *pubEndorsementKeySize, &hte->comm)) { free(*pubEndorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_DIGEST, 2, &(checksum->digest), 0, &hte->comm)) { free(*pubEndorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_DisablePubekRead_TP(struct host_table_entry *hte, TPM_AUTH * ownerAuth /* in, out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_DISABLEPUBEKREAD; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 1, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)) result = TSPERR(TSS_E_INTERNAL_ERROR); } return result; } TSS_RESULT RPC_OwnerReadPubek_TP(struct host_table_entry *hte, TPM_AUTH * ownerAuth, /* in, out */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey /* out */ ) { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_OWNERREADPUBEK; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_AUTH, 1, ownerAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_AUTH, 0, ownerAuth, 0, &hte->comm)){ free(*pubEndorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } if (getData(TCSD_PACKET_TYPE_UINT32, 1, pubEndorsementKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *pubEndorsementKey = (BYTE *) malloc(*pubEndorsementKeySize); if (*pubEndorsementKey == NULL) { LogError("malloc of %u bytes failed.", *pubEndorsementKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *pubEndorsementKey, *pubEndorsementKeySize, &hte->comm)) { free(*pubEndorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } done: return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_CreateRevocableEndorsementKeyPair_TP(struct host_table_entry *hte, TPM_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize,/* in */ BYTE * endorsementKeyInfo, /* in */ TSS_BOOL genResetAuth, /* in */ TPM_DIGEST * eKResetAuth, /* in, out */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TPM_DIGEST * checksum) /* out */ { TSS_RESULT result; initData(&hte->comm, 6); hte->comm.hdr.u.ordinal = TCSD_ORD_CREATEREVOCABLEENDORSEMENTKEYPAIR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_NONCE, 1, &antiReplay, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_UINT32, 2, &endorsementKeyInfoSize, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_PBYTE, 3, endorsementKeyInfo, endorsementKeyInfoSize, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_BOOL, 4, &genResetAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 5, eKResetAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; if (result == TSS_SUCCESS) { if (getData(TCSD_PACKET_TYPE_DIGEST, 0, &(eKResetAuth->digest), 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_UINT32, 1, endorsementKeySize, 0, &hte->comm)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *endorsementKey = (BYTE *) malloc(*endorsementKeySize); if (*endorsementKey == NULL) { LogError("malloc of %u bytes failed.", *endorsementKeySize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } if (getData(TCSD_PACKET_TYPE_PBYTE, 2, *endorsementKey, *endorsementKeySize, &hte->comm)) { free(*endorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (getData(TCSD_PACKET_TYPE_DIGEST, 3, &(checksum->digest), 0, &hte->comm)) { free(*endorsementKey); result = TSPERR(TSS_E_INTERNAL_ERROR); } } done: return result; } TSS_RESULT RPC_RevokeEndorsementKeyPair_TP(struct host_table_entry *hte, TPM_DIGEST *EKResetAuth) /* in */ { TSS_RESULT result; initData(&hte->comm, 2); hte->comm.hdr.u.ordinal = TCSD_ORD_REVOKEENDORSEMENTKEYPAIR; LogDebugFn("TCS Context: 0x%x", hte->tcsContext); if (setData(TCSD_PACKET_TYPE_UINT32, 0, &hte->tcsContext, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); if (setData(TCSD_PACKET_TYPE_DIGEST, 1, EKResetAuth, 0, &hte->comm)) return TSPERR(TSS_E_INTERNAL_ERROR); result = sendTCSDPacket(hte); if (result == TSS_SUCCESS) result = hte->comm.hdr.u.result; return result; } #endif trousers-0.3.15/src/tspi/rpc/hosttable.c0000664000175000017510000000726313663651711017447 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tsplog.h" #include "hosttable.h" #include "obj.h" static struct host_table *ht = NULL; TSS_RESULT host_table_init() { ht = calloc(1, sizeof(struct host_table)); if (ht == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct host_table)); return TSPERR(TSS_E_OUTOFMEMORY); } MUTEX_INIT(ht->lock); return TSS_SUCCESS; } #ifdef SOLARIS #pragma init(_init) void _init(void) #else static void __attribute__ ((constructor)) my_init(void) #endif { host_table_init(); __tspi_obj_list_init(); } void host_table_final() { struct host_table_entry *hte, *next = NULL; MUTEX_LOCK(ht->lock); for (hte = ht->entries; hte; hte = next) { if (hte) next = hte->next; if (hte->hostname) free(hte->hostname); if (hte->comm.buf) free(hte->comm.buf); free(hte); } MUTEX_UNLOCK(ht->lock); free(ht); ht = NULL; } #ifdef SOLARIS #pragma fini(_fini) void _fini(void) #else static void __attribute__ ((destructor)) my_fini(void) #endif { host_table_final(); } TSS_RESULT __tspi_add_table_entry(TSS_HCONTEXT tspContext, BYTE *host, int type, struct host_table_entry **ret) { struct host_table_entry *entry, *tmp; int hostlen; entry = calloc(1, sizeof(struct host_table_entry)); if (entry == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct host_table_entry)); return TSPERR(TSS_E_OUTOFMEMORY); } entry->tspContext = tspContext; hostlen = strlen((char *)host)+1; entry->hostname = (BYTE *)calloc(1, hostlen); if (entry->hostname == NULL) { LogError("malloc of %u bytes failed.", hostlen); free(entry); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(entry->hostname, host, hostlen); entry->type = type; entry->comm.buf_size = TCSD_INIT_TXBUF_SIZE; entry->comm.buf = calloc(1, entry->comm.buf_size); if (entry->comm.buf == NULL) { LogError("malloc of %u bytes failed.", entry->comm.buf_size); free(entry); return TSPERR(TSS_E_OUTOFMEMORY); } MUTEX_INIT(entry->lock); MUTEX_LOCK(ht->lock); for (tmp = ht->entries; tmp; tmp = tmp->next) { if (tmp->tspContext == tspContext) { LogError("Tspi_Context_Connect attempted on an already connected context!"); MUTEX_UNLOCK(ht->lock); free(entry->hostname); free(entry->comm.buf); free(entry); return TSPERR(TSS_E_CONNECTION_FAILED); } } if( ht->entries == NULL ) { ht->entries = entry; } else { for (tmp = ht->entries; tmp->next; tmp = tmp->next) ; tmp->next = entry; } MUTEX_UNLOCK(ht->lock); *ret = entry; return TSS_SUCCESS; } void remove_table_entry(TSS_HCONTEXT tspContext) { struct host_table_entry *hte, *prev = NULL; MUTEX_LOCK(ht->lock); for (hte = ht->entries; hte; prev = hte, hte = hte->next) { if (hte->tspContext == tspContext) { if (prev != NULL) prev->next = hte->next; else ht->entries = hte->next; if (hte->hostname) free(hte->hostname); free(hte->comm.buf); free(hte); break; } } MUTEX_UNLOCK(ht->lock); } struct host_table_entry * get_table_entry(TSS_HCONTEXT tspContext) { struct host_table_entry *index = NULL; MUTEX_LOCK(ht->lock); for (index = ht->entries; index; index = index->next) { if (index->tspContext == tspContext) break; } if (index) MUTEX_LOCK(index->lock); MUTEX_UNLOCK(ht->lock); return index; } void put_table_entry(struct host_table_entry *entry) { if (entry) MUTEX_UNLOCK(entry->lock); } trousers-0.3.15/src/tspi/rpc/tcs_api.c0000664000175000017510000024674613663651711017117 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "hosttable.h" #include "tsplog.h" #include "rpc_tcstp_tsp.h" #include "obj_context.h" TSS_RESULT RPC_Error(TSS_HCONTEXT tspContext, ...) { LogDebugFn("Context: 0x%x", tspContext); return TSPERR(TSS_E_INTERNAL_ERROR); } TSS_RESULT RPC_OpenContext(TSS_HCONTEXT tspContext, BYTE *hostname, int type) { TSS_RESULT result; TCS_CONTEXT_HANDLE tcsContext; struct host_table_entry *entry; UINT32 tpm_version; /* __tspi_add_table_entry() will make sure an entry doesn't already exist for this tsp context */ if ((result = __tspi_add_table_entry(tspContext, hostname, type, &entry))) return result; switch (type) { case CONNECTION_TYPE_TCP_PERSISTANT: if ((result = RPC_OpenContext_TP(entry, &tpm_version, &tcsContext))) remove_table_entry(tspContext); else { entry->tcsContext = tcsContext; if (obj_context_set_tpm_version(tspContext, tpm_version)) { remove_table_entry(tspContext); result = TSPERR(TSS_E_INTERNAL_ERROR); } } return result; default: break; } return TSPERR(TSS_E_INTERNAL_ERROR); } TSS_RESULT RPC_GetRegisteredKeyByPublicInfo(TSS_HCONTEXT tspContext, TCPA_ALGORITHM_ID algID, /* in */ UINT32 ulPublicInfoLength, /* in */ BYTE * rgbPublicInfo, /* in */ UINT32 * keySize, BYTE ** keyBlob) { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetRegisteredKeyByPublicInfo_TP(entry, algID, ulPublicInfoLength, rgbPublicInfo, keySize, keyBlob); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CloseContext(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: if ((result = RPC_CloseContext_TP(entry)) == TSS_SUCCESS) { close(entry->socket); remove_table_entry(tspContext); } break; default: break; } if (result != TSS_SUCCESS) put_table_entry(entry); return result; } TSS_RESULT RPC_FreeMemory(TSS_HCONTEXT tspContext, /* in */ BYTE * pMemory) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_FreeMemory_TP(entry, pMemory); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_LogPcrEvent(TSS_HCONTEXT tspContext, /* in */ TSS_PCR_EVENT Event, /* in */ UINT32 * pNumber) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_LogPcrEvent_TP(entry, Event, pNumber); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetPcrEvent(TSS_HCONTEXT tspContext, /* in */ UINT32 PcrIndex, /* in */ UINT32 * pNumber, /* in, out */ TSS_PCR_EVENT ** ppEvent) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetPcrEvent_TP(entry, PcrIndex, pNumber, ppEvent); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetPcrEventsByPcr(TSS_HCONTEXT tspContext, /* in */ UINT32 PcrIndex, /* in */ UINT32 FirstEvent, /* in */ UINT32 * pEventCount, /* in,out */ TSS_PCR_EVENT ** ppEvents) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetPcrEventsByPcr_TP(entry, PcrIndex, FirstEvent, pEventCount, ppEvents); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetPcrEventLog(TSS_HCONTEXT tspContext, /* in */ UINT32 * pEventCount, /* out */ TSS_PCR_EVENT ** ppEvents) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetPcrEventLog_TP(entry, pEventCount, ppEvents); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_RegisterKey(TSS_HCONTEXT tspContext, /* in */ TSS_UUID WrappingKeyUUID, /* in */ TSS_UUID KeyUUID, /* in */ UINT32 cKeySize, /* in */ BYTE * rgbKey, /* in */ UINT32 cVendorData, /* in */ BYTE * gbVendorData) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_RegisterKey_TP(entry, WrappingKeyUUID, KeyUUID, cKeySize, rgbKey, cVendorData, gbVendorData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_UnregisterKey(TSS_HCONTEXT tspContext, /* in */ TSS_UUID KeyUUID) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_UnregisterKey_TP(entry, KeyUUID); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_EnumRegisteredKeys(TSS_HCONTEXT tspContext, /* in */ TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO ** ppKeyHierarchy) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_EnumRegisteredKeys_TP(entry, pKeyUUID, pcKeyHierarchySize, ppKeyHierarchy); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_EnumRegisteredKeys2(TSS_HCONTEXT tspContext, /* in */ TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO2 ** ppKeyHierarchy) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_EnumRegisteredKeys2_TP(entry, pKeyUUID, pcKeyHierarchySize, ppKeyHierarchy); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetRegisteredKey(TSS_HCONTEXT tspContext, /* in */ TSS_UUID KeyUUID, /* in */ TSS_KM_KEYINFO ** ppKeyInfo) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetRegisteredKey_TP(entry, KeyUUID, ppKeyInfo); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetRegisteredKeyBlob(TSS_HCONTEXT tspContext, /* in */ TSS_UUID KeyUUID, /* in */ UINT32 * pcKeySize, /* out */ BYTE ** prgbKey) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetRegisteredKeyBlob_TP(entry, KeyUUID, pcKeySize, prgbKey); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_LoadKeyByBlob(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hUnwrappingKey, /* in */ UINT32 cWrappedKeyBlobSize, /* in */ BYTE * rgbWrappedKeyBlob, /* in */ TPM_AUTH * pAuth, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI, /* out */ TCS_KEY_HANDLE * phKeyHMAC) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_LoadKeyByBlob_TP(entry, hUnwrappingKey, cWrappedKeyBlobSize, rgbWrappedKeyBlob, pAuth, phKeyTCSI, phKeyHMAC); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_LoadKeyByUUID(TSS_HCONTEXT tspContext, /* in */ TSS_UUID KeyUUID, /* in */ TCS_LOADKEY_INFO * pLoadKeyInfo, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_LoadKeyByUUID_TP(entry, KeyUUID, pLoadKeyInfo, phKeyTCSI); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_EvictKey(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hKey) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_EvictKey_TP(entry, hKey); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CreateWrapKey(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hWrappingKey, /* in */ TCPA_ENCAUTH *KeyUsageAuth, /* in */ TCPA_ENCAUTH *KeyMigrationAuth, /* in */ UINT32 keyInfoSize, /* in */ BYTE * keyInfo, /* in */ UINT32 * keyDataSize, /* out */ BYTE ** keyData, /* out */ TPM_AUTH * pAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CreateWrapKey_TP(entry, hWrappingKey, KeyUsageAuth, KeyMigrationAuth, keyInfoSize, keyInfo, keyDataSize, keyData, pAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetPubKey(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * pcPubKeySize, /* out */ BYTE ** prgbPubKey) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetPubKey_TP(entry, hKey, pAuth, pcPubKeySize, prgbPubKey); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_MakeIdentity(TSS_HCONTEXT tspContext, /* in */ TCPA_ENCAUTH identityAuth, /* in */ TCPA_CHOSENID_HASH IDLabel_PrivCAHash, /* in */ UINT32 idKeyInfoSize, /* in */ BYTE * idKeyInfo, /* in */ TPM_AUTH * pSrkAuth, /* in, out */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * idKeySize, /* out */ BYTE ** idKey, /* out */ UINT32 * pcIdentityBindingSize, /* out */ BYTE ** prgbIdentityBinding, /* out */ UINT32 * pcEndorsementCredentialSize, /* out */ BYTE ** prgbEndorsementCredential, /* out */ UINT32 * pcPlatformCredentialSize, /* out */ BYTE ** prgbPlatformCredential, /* out */ UINT32 * pcConformanceCredentialSize, /* out */ BYTE ** prgbConformanceCredential) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_MakeIdentity_TP(entry, identityAuth, IDLabel_PrivCAHash, idKeyInfoSize, idKeyInfo, pSrkAuth, pOwnerAuth, idKeySize, idKey, pcIdentityBindingSize, prgbIdentityBinding, pcEndorsementCredentialSize, prgbEndorsementCredential, pcPlatformCredentialSize, prgbPlatformCredential, pcConformanceCredentialSize, prgbConformanceCredential); break; default: break; } put_table_entry(entry); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_GetCredential(TSS_HCONTEXT tspContext, /* in */ UINT32 ulCredentialType, /* in */ UINT32 ulCredentialAccessMode, /* in */ UINT32 * pulCredentialSize, /* out */ BYTE ** prgbCredentialData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetCredential_TP(entry, ulCredentialType, ulCredentialAccessMode, pulCredentialSize, prgbCredentialData); break; default: break; } put_table_entry(entry); return result; } #endif TSS_RESULT RPC_SetOwnerInstall(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL state) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_SetOwnerInstall_TP(entry, state); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_TakeOwnership(TSS_HCONTEXT tspContext, /* in */ UINT16 protocolID, /* in */ UINT32 encOwnerAuthSize, /* in */ BYTE * encOwnerAuth, /* in */ UINT32 encSrkAuthSize, /* in */ BYTE * encSrkAuth, /* in */ UINT32 srkInfoSize, /* in */ BYTE * srkInfo, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * srkKeySize, BYTE ** srkKey) { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_TakeOwnership_TP(entry, protocolID, encOwnerAuthSize, encOwnerAuth, encSrkAuthSize, encSrkAuth, srkInfoSize, srkInfo, ownerAuth, srkKeySize, srkKey); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_OIAP(TSS_HCONTEXT tspContext, /* in */ TCS_AUTHHANDLE * authHandle, /* out */ TCPA_NONCE * nonce0) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_OIAP_TP(entry, authHandle, nonce0); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_OSAP(TSS_HCONTEXT tspContext, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 entityValue, /* in */ TPM_NONCE *nonceOddOSAP, /* in */ TCS_AUTHHANDLE * authHandle, /* out */ TCPA_NONCE * nonceEven, /* out */ TCPA_NONCE * nonceEvenOSAP) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_OSAP_TP(entry, entityType, entityValue, nonceOddOSAP, authHandle, nonceEven, nonceEvenOSAP); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ChangeAuth(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH *newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * ownerAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ChangeAuth_TP(entry, parentHandle, protocolID, newAuth, entityType, encDataSize, encData, ownerAuth, entityAuth, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ChangeAuthOwner(TSS_HCONTEXT tspContext, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH *newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ChangeAuthOwner_TP(entry, protocolID, newAuth, entityType, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ChangeAuthAsymStart(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE idHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 KeySizeIn, /* in */ BYTE * KeyDataIn, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * KeySizeOut, /* out */ BYTE ** KeyDataOut, /* out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig, /* out */ TCS_KEY_HANDLE * ephHandle) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ChangeAuthAsymStart_TP(entry, idHandle, antiReplay, KeySizeIn, KeyDataIn, pAuth, KeySizeOut, KeyDataOut, CertifyInfoSize, CertifyInfo, sigSize, sig, ephHandle); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ChangeAuthAsymFinish(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCS_KEY_HANDLE ephHandle, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TCPA_HMAC newAuthLink, /* in */ UINT32 newAuthSize, /* in */ BYTE * encNewAuth, /* in */ UINT32 encDataSizeIn, /* in */ BYTE * encDataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * encDataSizeOut, /* out */ BYTE ** encDataOut, /* out */ TCPA_SALT_NONCE * saltNonce, /* out */ TCPA_DIGEST * changeProof) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ChangeAuthAsymFinish_TP(entry, parentHandle, ephHandle, entityType, newAuthLink, newAuthSize, encNewAuth, encDataSizeIn, encDataIn, ownerAuth, encDataSizeOut, encDataOut, saltNonce, changeProof); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_TerminateHandle(TSS_HCONTEXT tspContext, /* in */ TCS_AUTHHANDLE handle) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_TerminateHandle_TP(entry, handle); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ActivateTPMIdentity(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE idKey, /* in */ UINT32 blobSize, /* in */ BYTE * blob, /* in */ TPM_AUTH * idKeyAuth, /* in, out */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * SymmetricKeySize, /* out */ BYTE ** SymmetricKey) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ActivateTPMIdentity_TP(entry, idKey, blobSize, blob, idKeyAuth, ownerAuth, SymmetricKeySize, SymmetricKey); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Extend(TSS_HCONTEXT tspContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_DIGEST inDigest, /* in */ TCPA_PCRVALUE * outDigest) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Extend_TP(entry, pcrNum, inDigest, outDigest); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_PcrRead(TSS_HCONTEXT tspContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_PCRVALUE * outDigest) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_PcrRead_TP(entry, pcrNum, outDigest); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_PcrReset(TSS_HCONTEXT tspContext, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_PcrReset_TP(entry, pcrDataSizeIn, pcrDataIn); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Quote(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE *antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Quote_TP(entry, keyHandle, antiReplay, pcrDataSizeIn, pcrDataIn, privAuth, pcrDataSizeOut, pcrDataOut, sigSize, sig); break; default: break; } put_table_entry(entry); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_Quote2(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE *antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TSS_BOOL addVersion, /* in */ TPM_AUTH * privAuth, /* in,out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * versionInfoSize, /* out */ BYTE ** versionInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Quote2_TP(entry, keyHandle, antiReplay, pcrDataSizeIn, pcrDataIn, addVersion,privAuth, pcrDataSizeOut, pcrDataOut, versionInfoSize, versionInfo,sigSize, sig); break; default: break; } put_table_entry(entry); return result; } #endif TSS_RESULT RPC_DirWriteAuth(TSS_HCONTEXT tspContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE *newContents, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DirWriteAuth_TP(entry, dirIndex, newContents, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_DirRead(TSS_HCONTEXT tspContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE * dirValue) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DirRead_TP(entry, dirIndex, dirValue); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Seal(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH *encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Seal_TP(entry, keyHandle, encAuth, pcrInfoSize, PcrInfo, inDataSize, inData, pubAuth, SealedDataSize, SealedData); break; default: break; } put_table_entry(entry); return result; } #ifdef TSS_BUILD_SEALX TSS_RESULT RPC_Sealx(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH *encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Sealx_TP(entry, keyHandle, encAuth, pcrInfoSize, PcrInfo, inDataSize, inData, pubAuth, SealedDataSize, SealedData); break; default: break; } put_table_entry(entry); return result; } #endif TSS_RESULT RPC_Unseal(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 SealedDataSize, /* in */ BYTE * SealedData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * dataAuth, /* in, out */ UINT32 * DataSize, /* out */ BYTE ** Data) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Unseal_TP(entry, parentHandle, SealedDataSize, SealedData, parentAuth, dataAuth, DataSize, Data); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_UnBind(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_UnBind_TP(entry, keyHandle, inDataSize, inData, privAuth, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CreateMigrationBlob(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCPA_MIGRATE_SCHEME migrationType, /* in */ UINT32 MigrationKeyAuthSize, /* in */ BYTE * MigrationKeyAuth, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CreateMigrationBlob_TP(entry, parentHandle, migrationType, MigrationKeyAuthSize, MigrationKeyAuth, encDataSize, encData, parentAuth, entityAuth, randomSize, random, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ConvertMigrationBlob(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ UINT32 randomSize, /* in */ BYTE * random, /* in */ TPM_AUTH * parentAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ConvertMigrationBlob_TP(entry, parentHandle, inDataSize, inData, randomSize, random, parentAuth, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_AuthorizeMigrationKey(TSS_HCONTEXT tspContext, /* in */ TCPA_MIGRATE_SCHEME migrateScheme, /* in */ UINT32 MigrationKeySize, /* in */ BYTE * MigrationKey, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * MigrationKeyAuthSize, /* out */ BYTE ** MigrationKeyAuth) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_AuthorizeMigrationKey_TP(entry, migrateScheme, MigrationKeySize, MigrationKey, ownerAuth, MigrationKeyAuthSize, MigrationKeyAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CertifyKey(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE certHandle, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TPM_NONCE * antiReplay, /* in */ TPM_AUTH * certAuth, /* in, out */ TPM_AUTH * keyAuth, /* in, out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CertifyKey_TP(entry, certHandle, keyHandle, antiReplay, certAuth, keyAuth, CertifyInfoSize, CertifyInfo, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Sign(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 areaToSignSize, /* in */ BYTE * areaToSign, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Sign_TP(entry, keyHandle, areaToSignSize, areaToSign, privAuth, sigSize, sig); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetRandom(TSS_HCONTEXT tspContext, /* in */ UINT32 bytesRequested, /* in */ BYTE ** randomBytes) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetRandom_TP(entry, bytesRequested, randomBytes); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_StirRandom(TSS_HCONTEXT tspContext, /* in */ UINT32 inDataSize, /* in */ BYTE * inData) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_StirRandom_TP(entry, inDataSize, inData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetTPMCapability(TSS_HCONTEXT tspContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetTPMCapability_TP(entry, capArea, subCapSize, subCap, respSize, resp); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_SetCapability(TSS_HCONTEXT tspContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 valueSize, /* in */ BYTE * value, /* in */ TPM_AUTH *ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_SetCapability_TP(entry, capArea, subCapSize, subCap, valueSize, value, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetCapability(TSS_HCONTEXT tspContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetCapability_TP(entry, capArea, subCapSize, subCap, respSize, resp); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetCapabilitySigned(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ TPM_AUTH * privAuth, /* in, out */ TCPA_VERSION * Version, /* out */ UINT32 * respSize, /* out */ BYTE ** resp, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetCapabilitySigned_TP(entry, keyHandle, antiReplay, capArea, subCapSize, subCap, privAuth, Version, respSize, resp, sigSize, sig); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetCapabilityOwner(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * pOwnerAuth, /* out */ TCPA_VERSION * pVersion, /* out */ UINT32 * pNonVolatileFlags, /* out */ UINT32 * pVolatileFlags) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetCapabilityOwner_TP(entry, pOwnerAuth, pVersion, pNonVolatileFlags, pVolatileFlags); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CreateEndorsementKeyPair(TSS_HCONTEXT tspContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize, /* in */ BYTE * endorsementKeyInfo, /* in */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TCPA_DIGEST * checksum) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CreateEndorsementKeyPair_TP(entry, antiReplay, endorsementKeyInfoSize, endorsementKeyInfo, endorsementKeySize, endorsementKey, checksum); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ReadPubek(TSS_HCONTEXT tspContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey, /* out */ TCPA_DIGEST * checksum) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ReadPubek_TP(entry, antiReplay, pubEndorsementKeySize, pubEndorsementKey, checksum); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_DisablePubekRead(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DisablePubekRead_TP(entry, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_OwnerReadPubek(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_OwnerReadPubek_TP(entry, ownerAuth, pubEndorsementKeySize, pubEndorsementKey); break; default: break; } put_table_entry(entry); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_CreateRevocableEndorsementKeyPair(TSS_HCONTEXT tspContext, /* in */ TPM_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize,/* in */ BYTE * endorsementKeyInfo, /* in */ TSS_BOOL genResetAuth, /* in */ TPM_DIGEST * eKResetAuth, /* in, out */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TPM_DIGEST * checksum) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CreateRevocableEndorsementKeyPair_TP(entry, antiReplay, endorsementKeyInfoSize, endorsementKeyInfo, genResetAuth, eKResetAuth, endorsementKeySize, endorsementKey, checksum); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_RevokeEndorsementKeyPair(TSS_HCONTEXT tspContext, /* in */ TPM_DIGEST *EKResetAuth) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_RevokeEndorsementKeyPair_TP(entry, EKResetAuth); break; default: break; } put_table_entry(entry); return result; } #endif TSS_RESULT RPC_SelfTestFull(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_SelfTestFull_TP(entry); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CertifySelfTest(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CertifySelfTest_TP(entry, keyHandle, antiReplay, privAuth, sigSize, sig); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetTestResult(TSS_HCONTEXT tspContext, /* in */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetTestResult_TP(entry, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_OwnerSetDisable(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL disableState, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_OwnerSetDisable_TP(entry, disableState, ownerAuth); break; default: break; } put_table_entry(entry); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_ResetLockValue(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ResetLockValue_TP(entry, ownerAuth); break; default: break; } put_table_entry(entry); return result; } #endif TSS_RESULT RPC_OwnerClear(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_OwnerClear_TP(entry, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_DisableOwnerClear(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DisableOwnerClear_TP(entry, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ForceClear(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ForceClear_TP(entry); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_DisableForceClear(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DisableForceClear_TP(entry); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_PhysicalDisable(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_PhysicalDisable_TP(entry); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_PhysicalEnable(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_PhysicalEnable_TP(entry); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_PhysicalSetDeactivated(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL state) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_PhysicalSetDeactivated_TP(entry, state); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_PhysicalPresence(TSS_HCONTEXT tspContext, /* in */ TCPA_PHYSICAL_PRESENCE fPhysicalPresence) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_PhysicalPresence_TP(entry, fPhysicalPresence); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_SetTempDeactivated(TSS_HCONTEXT tspContext) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_SetTempDeactivated_TP(entry); break; default: break; } put_table_entry(entry); return result; } #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_SetTempDeactivated2(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH *operatorAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_SetTempDeactivated2_TP(entry, operatorAuth); break; default: break; } put_table_entry(entry); return result; } #endif TSS_RESULT RPC_FieldUpgrade(TSS_HCONTEXT tspContext, /* in */ UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut, /* out */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = (UINT32) TSPERR(TSS_E_INTERNAL_ERROR); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_SetRedirection(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 c1, /* in */ UINT32 c2, /* in */ TPM_AUTH * privAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = (UINT32) TSPERR(TSS_E_INTERNAL_ERROR); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CreateMaintenanceArchive(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL generateRandom, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * archiveSize, /* out */ BYTE ** archive) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CreateMaintenanceArchive_TP(entry, generateRandom, ownerAuth, randomSize, random, archiveSize, archive); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_LoadMaintenanceArchive(TSS_HCONTEXT tspContext, /* in */ UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_LoadMaintenanceArchive_TP(entry, dataInSize, dataIn, ownerAuth, dataOutSize, dataOut); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_KillMaintenanceFeature(TSS_HCONTEXT tspContext, /* in */ TPM_AUTH * ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_KillMaintenanceFeature_TP(entry, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_LoadManuMaintPub(TSS_HCONTEXT tspContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 PubKeySize, /* in */ BYTE * PubKey, /* in */ TCPA_DIGEST * checksum) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_LoadManuMaintPub_TP(entry, antiReplay, PubKeySize, PubKey, checksum); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ReadManuMaintPub(TSS_HCONTEXT tspContext, /* in */ TCPA_NONCE antiReplay, /* in */ TCPA_DIGEST * checksum) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ReadManuMaintPub_TP(entry, antiReplay, checksum); break; default: break; } put_table_entry(entry); return result; } #ifdef TSS_BUILD_DAA TSS_RESULT RPC_DaaJoin(TSS_HCONTEXT tspContext, /* in */ TPM_HANDLE daa_session, /* in */ BYTE stage, /* in */ UINT32 inputSize0, /* in */ BYTE* inputData0, /* in */ UINT32 inputSize1, /* in */ BYTE* inputData1, /* in */ TPM_AUTH* ownerAuth, /* in, out */ UINT32* outputSize, /* out */ BYTE** outputData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DaaJoin_TP(entry, daa_session, stage, inputSize0, inputData0, inputSize1, inputData1, ownerAuth, outputSize, outputData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_DaaSign(TSS_HCONTEXT tspContext, /* in */ TPM_HANDLE daa_session, /* in */ BYTE stage, /* in */ UINT32 inputSize0, /* in */ BYTE* inputData0, /* in */ UINT32 inputSize1, /* in */ BYTE* inputData1, /* in */ TPM_AUTH* ownerAuth, /* in, out */ UINT32* outputSize, /* out */ BYTE** outputData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DaaSign_TP(entry, daa_session, stage, inputSize0, inputData0, inputSize1, inputData1, ownerAuth, outputSize, outputData); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_COUNTER TSS_RESULT RPC_ReadCounter(TSS_HCONTEXT tspContext, /* in */ TSS_COUNTER_ID idCounter, /* in */ TPM_COUNTER_VALUE* counterValue) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ReadCounter_TP(entry, idCounter, counterValue); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CreateCounter(TSS_HCONTEXT tspContext, /* in */ UINT32 LabelSize, /* in (=4) */ BYTE* pLabel, /* in */ TPM_ENCAUTH CounterAuth, /* in */ TPM_AUTH* pOwnerAuth, /* in, out */ TSS_COUNTER_ID* idCounter, /* out */ TPM_COUNTER_VALUE* counterValue) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CreateCounter_TP(entry, LabelSize, pLabel, CounterAuth, pOwnerAuth, idCounter, counterValue); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_IncrementCounter(TSS_HCONTEXT tspContext, /* in */ TSS_COUNTER_ID idCounter, /* in */ TPM_AUTH* pCounterAuth, /* in, out */ TPM_COUNTER_VALUE* counterValue) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_IncrementCounter_TP(entry, idCounter, pCounterAuth, counterValue); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ReleaseCounter(TSS_HCONTEXT tspContext, /* in */ TSS_COUNTER_ID idCounter, /* in */ TPM_AUTH* pCounterAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ReleaseCounter_TP(entry, idCounter, pCounterAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ReleaseCounterOwner(TSS_HCONTEXT tspContext, /* in */ TSS_COUNTER_ID idCounter, /* in */ TPM_AUTH* pOwnerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ReleaseCounterOwner_TP(entry, idCounter, pOwnerAuth); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_TICK TSS_RESULT RPC_ReadCurrentTicks(TSS_HCONTEXT tspContext, /* in */ UINT32* pulCurrentTime, /* out */ BYTE** prgbCurrentTime) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ReadCurrentTicks_TP(entry, pulCurrentTime, prgbCurrentTime); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_TickStampBlob(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_NONCE* antiReplay, /* in */ TPM_DIGEST* digestToStamp, /* in */ TPM_AUTH* privAuth, /* in, out */ UINT32* pulSignatureLength, /* out */ BYTE** prgbSignature, /* out */ UINT32* pulTickCountLength, /* out */ BYTE** prgbTickCount) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_TickStampBlob_TP(entry, hKey, antiReplay, digestToStamp, privAuth, pulSignatureLength, prgbSignature, pulTickCountLength, prgbTickCount); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_TRANSPORT TSS_RESULT RPC_EstablishTransport(TSS_HCONTEXT tspContext, UINT32 ulTransControlFlags, TCS_KEY_HANDLE hEncKey, UINT32 ulTransSessionInfoSize, BYTE* rgbTransSessionInfo, UINT32 ulSecretSize, BYTE* rgbSecret, TPM_AUTH* pEncKeyAuth, /* in, out */ TPM_MODIFIER_INDICATOR* pbLocality, TCS_HANDLE* hTransSession, UINT32* ulCurrentTicksSize, BYTE** prgbCurrentTicks, TPM_NONCE* pTransNonce) { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_EstablishTransport_TP(entry, ulTransControlFlags, hEncKey, ulTransSessionInfoSize, rgbTransSessionInfo, ulSecretSize, rgbSecret, pEncKeyAuth, pbLocality, hTransSession, ulCurrentTicksSize, prgbCurrentTicks, pTransNonce); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ExecuteTransport(TSS_HCONTEXT tspContext, TPM_COMMAND_CODE unWrappedCommandOrdinal, UINT32 ulWrappedCmdParamInSize, BYTE* rgbWrappedCmdParamIn, UINT32* pulHandleListSize, /* in, out */ TCS_HANDLE** rghHandles, /* in, out */ TPM_AUTH* pWrappedCmdAuth1, /* in, out */ TPM_AUTH* pWrappedCmdAuth2, /* in, out */ TPM_AUTH* pTransAuth, /* in, out */ UINT64* punCurrentTicks, TPM_MODIFIER_INDICATOR* pbLocality, TPM_RESULT* pulWrappedCmdReturnCode, UINT32* ulWrappedCmdParamOutSize, BYTE** rgbWrappedCmdParamOut) { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ExecuteTransport_TP(entry, unWrappedCommandOrdinal, ulWrappedCmdParamInSize, rgbWrappedCmdParamIn, pulHandleListSize, rghHandles, pWrappedCmdAuth1, pWrappedCmdAuth2, pTransAuth, punCurrentTicks, pbLocality, pulWrappedCmdReturnCode, ulWrappedCmdParamOutSize, rgbWrappedCmdParamOut); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_ReleaseTransportSigned(TSS_HCONTEXT tspContext, TCS_KEY_HANDLE hSignatureKey, TPM_NONCE* AntiReplayNonce, TPM_AUTH* pKeyAuth, /* in, out */ TPM_AUTH* pTransAuth, /* in, out */ TPM_MODIFIER_INDICATOR* pbLocality, UINT32* pulCurrentTicksSize, BYTE** prgbCurrentTicks, UINT32* pulSignatureSize, BYTE** prgbSignature) { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(tspContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_ReleaseTransportSigned_TP(entry, hSignatureKey, AntiReplayNonce, pKeyAuth, pTransAuth, pbLocality, pulCurrentTicksSize, prgbCurrentTicks, pulSignatureSize, prgbSignature); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_NV TSS_RESULT RPC_NV_DefineOrReleaseSpace(TSS_HCONTEXT hContext, /* in */ UINT32 cPubInfoSize, /* in */ BYTE* pPubInfo, /* in */ TCPA_ENCAUTH encAuth, /* in */ TPM_AUTH* pAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_NV_DefineOrReleaseSpace_TP(entry, cPubInfoSize, pPubInfo, encAuth, pAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_NV_WriteValue(TSS_HCONTEXT hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* privAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_NV_WriteValue_TP(entry, hNVStore, offset, ulDataLength, rgbDataToWrite, privAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_NV_WriteValueAuth(TSS_HCONTEXT hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* NVAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_NV_WriteValueAuth_TP(entry, hNVStore, offset, ulDataLength, rgbDataToWrite, NVAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_NV_ReadValue(TSS_HCONTEXT hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in, out */ TPM_AUTH* privAuth, /* in, out */ BYTE** rgbDataRead) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_NV_ReadValue_TP(entry, hNVStore, offset, pulDataLength, privAuth, rgbDataRead); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_NV_ReadValueAuth(TSS_HCONTEXT hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in, out */ TPM_AUTH* NVAuth, /* in, out */ BYTE** rgbDataRead) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_NV_ReadValueAuth_TP(entry, hNVStore, offset, pulDataLength, NVAuth, rgbDataRead); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_AUDIT TSS_RESULT RPC_SetOrdinalAuditStatus(TSS_HCONTEXT hContext, /* in */ TPM_AUTH *ownerAuth, /* in/out */ UINT32 ulOrdinal, /* in */ TSS_BOOL bAuditState) /* in */ { TSS_RESULT result = TSS_SUCCESS; struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_SetOrdinalAuditStatus_TP(entry, ownerAuth, ulOrdinal, bAuditState); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetAuditDigest(TSS_HCONTEXT hContext, /* in */ UINT32 startOrdinal, /* in */ TPM_DIGEST *auditDigest, /* out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TSS_BOOL *more, /* out */ UINT32 *ordSize, /* out */ UINT32 **ordList) /* out */ { TSS_RESULT result = TSS_SUCCESS; struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetAuditDigest_TP(entry, startOrdinal, auditDigest, counterValueSize, counterValue, more, ordSize, ordList); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_GetAuditDigestSigned(TSS_HCONTEXT hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TSS_BOOL closeAudit, /* in */ TPM_NONCE *antiReplay, /* in */ TPM_AUTH *privAuth, /* in/out */ UINT32 *counterValueSize, /* out */ BYTE **counterValue, /* out */ TPM_DIGEST *auditDigest, /* out */ TPM_DIGEST *ordinalDigest, /* out */ UINT32 *sigSize, /* out */ BYTE **sig) /* out */ { TSS_RESULT result = TSS_SUCCESS; struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_GetAuditDigestSigned_TP(entry, keyHandle, closeAudit, antiReplay, privAuth, counterValueSize, counterValue, auditDigest, ordinalDigest, sigSize, sig); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_SetOperatorAuth(TSS_HCONTEXT hContext, /* in */ TCPA_SECRET *operatorAuth) /* in */ { TSS_RESULT result = TSS_SUCCESS; struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_SetOperatorAuth_TP(entry, operatorAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_OwnerReadInternalPub(TSS_HCONTEXT hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH* pOwnerAuth, /* in, out */ UINT32* punPubKeySize, /* out */ BYTE** ppbPubKeyData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_OwnerReadInternalPub_TP(entry, hKey, pOwnerAuth, punPubKeySize, ppbPubKeyData); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_DELEGATION TSS_RESULT RPC_Delegate_Manage(TSS_HCONTEXT hContext, /* in */ TPM_FAMILY_ID familyID, /* in */ TPM_FAMILY_OPERATION opFlag, /* in */ UINT32 opDataSize, /* in */ BYTE *opData, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *retDataSize, /* out */ BYTE **retData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Delegate_Manage_TP(entry, familyID, opFlag, opDataSize, opData, ownerAuth, retDataSize, retData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Delegate_CreateKeyDelegation(TSS_HCONTEXT hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *keyAuth, /* in, out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Delegate_CreateKeyDelegation_TP(entry, hKey, publicInfoSize, publicInfo, encDelAuth, keyAuth, blobSize, blob); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Delegate_CreateOwnerDelegation(TSS_HCONTEXT hContext, /* in */ TSS_BOOL increment, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Delegate_CreateOwnerDelegation_TP(entry, increment, publicInfoSize, publicInfo, encDelAuth, ownerAuth, blobSize, blob); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Delegate_LoadOwnerDelegation(TSS_HCONTEXT hContext, /* in */ TPM_DELEGATE_INDEX index, /* in */ UINT32 blobSize, /* in */ BYTE *blob, /* in */ TPM_AUTH *ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Delegate_LoadOwnerDelegation_TP(entry, index, blobSize, blob, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Delegate_ReadTable(TSS_HCONTEXT hContext, /* in */ UINT32 *familyTableSize, /* out */ BYTE **familyTable, /* out */ UINT32 *delegateTableSize, /* out */ BYTE **delegateTable) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Delegate_ReadTable_TP(entry, familyTableSize, familyTable, delegateTableSize, delegateTable); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Delegate_UpdateVerificationCount(TSS_HCONTEXT hContext, /* in */ UINT32 inputSize, /* in */ BYTE *input, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *outputSize, /* out */ BYTE **output) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Delegate_UpdateVerificationCount_TP(entry, inputSize, input, ownerAuth, outputSize, output); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_Delegate_VerifyDelegation(TSS_HCONTEXT hContext, /* in */ UINT32 delegateSize, /* in */ BYTE *delegate) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_Delegate_VerifyDelegation_TP(entry, delegateSize, delegate); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_DSAP(TSS_HCONTEXT hContext, /* in */ TPM_ENTITY_TYPE entityType, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TPM_NONCE *nonceOddDSAP, /* in */ UINT32 entityValueSize, /* in */ BYTE * entityValue, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TPM_NONCE *nonceEven, /* out */ TPM_NONCE *nonceEvenDSAP) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_DSAP_TP(entry, entityType, keyHandle, nonceOddDSAP, entityValueSize, entityValue, authHandle, nonceEven, nonceEvenDSAP); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_CMK TSS_RESULT RPC_CMK_SetRestrictions(TSS_HCONTEXT hContext, /* in */ TSS_CMK_DELEGATE restriction, /* in */ TPM_AUTH *ownerAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CMK_SetRestrictions_TP(entry, restriction, ownerAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CMK_ApproveMA(TSS_HCONTEXT hContext, /* in */ TPM_DIGEST migAuthorityDigest, /* in */ TPM_AUTH *ownerAuth, /* in, out */ TPM_HMAC *migAuthorityApproval) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CMK_ApproveMA_TP(entry, migAuthorityDigest, ownerAuth, migAuthorityApproval); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CMK_CreateKey(TSS_HCONTEXT hContext, /* in */ TCS_KEY_HANDLE hWrappingKey, /* in */ TPM_ENCAUTH *keyUsageAuth, /* in */ TPM_HMAC *migAuthorityApproval, /* in */ TPM_DIGEST *migAuthorityDigest, /* in */ UINT32 *keyDataSize, /* in, out */ BYTE **keyData, /* in, out */ TPM_AUTH *pAuth) /* in, out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CMK_CreateKey_TP(entry, hWrappingKey, keyUsageAuth, migAuthorityApproval, migAuthorityDigest, keyDataSize, keyData, pAuth); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CMK_CreateTicket(TSS_HCONTEXT hContext, /* in */ UINT32 publicVerifyKeySize, /* in */ BYTE *publicVerifyKey, /* in */ TPM_DIGEST signedData, /* in */ UINT32 sigValueSize, /* in */ BYTE *sigValue, /* in */ TPM_AUTH *ownerAuth, /* in, out */ TPM_HMAC *sigTicket) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CMK_CreateTicket_TP(entry, publicVerifyKeySize, publicVerifyKey, signedData, sigValueSize, sigValue, ownerAuth, sigTicket); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CMK_CreateBlob(TSS_HCONTEXT hContext, /* in */ TCS_KEY_HANDLE hParentKey, /* in */ TSS_MIGRATE_SCHEME migrationType, /* in */ UINT32 migKeyAuthSize, /* in */ BYTE *migKeyAuth, /* in */ TPM_DIGEST pubSourceKeyDigest, /* in */ UINT32 msaListSize, /* in */ BYTE *msaList, /* in */ UINT32 restrictTicketSize, /* in */ BYTE *restrictTicket, /* in */ UINT32 sigTicketSize, /* in */ BYTE *sigTicket, /* in */ UINT32 encDataSize, /* in */ BYTE *encData, /* in */ TPM_AUTH *pAuth, /* in, out */ UINT32 *randomSize, /* out */ BYTE **random, /* out */ UINT32 *outDataSize, /* out */ BYTE **outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CMK_CreateBlob_TP(entry, hParentKey, migrationType, migKeyAuthSize, migKeyAuth, pubSourceKeyDigest, msaListSize, msaList, restrictTicketSize, restrictTicket, sigTicketSize, sigTicket, encDataSize, encData, pAuth, randomSize, random, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_CMK_ConvertMigration(TSS_HCONTEXT hContext, /* in */ TCS_KEY_HANDLE hParentHandle, /* in */ TPM_CMK_AUTH restrictTicket, /* in */ TPM_HMAC sigTicket, /* in */ UINT32 keyDataSize, /* in */ BYTE *keyData, /* in */ UINT32 msaListSize, /* in */ BYTE *msaList, /* in */ UINT32 randomSize, /* in */ BYTE *random, /* in */ TPM_AUTH *pAuth, /* in, out */ UINT32 *outDataSize, /* out */ BYTE **outData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_CMK_ConvertMigration_TP(entry, hParentHandle, restrictTicket, sigTicket, keyDataSize, keyData, msaListSize, msaList, randomSize, random, pAuth, outDataSize, outData); break; default: break; } put_table_entry(entry); return result; } #endif #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_FlushSpecific(TSS_HCONTEXT hContext, /* in */ TCS_HANDLE hResHandle, /* in */ TPM_RESOURCE_TYPE resourceType) /* in */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_FlushSpecific_TP(entry, hResHandle, resourceType); break; default: break; } put_table_entry(entry); return result; } TSS_RESULT RPC_KeyControlOwner(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ UINT32 ulPublicInfoLength, /* in */ BYTE* rgbPublicInfo, /* in */ UINT32 attribName, /* in */ TSS_BOOL attribValue, /* in */ TPM_AUTH* pOwnerAuth, /* in, out */ TSS_UUID* pUuidData) /* out */ { TSS_RESULT result = (TSS_E_INTERNAL_ERROR | TSS_LAYER_TSP); struct host_table_entry *entry = get_table_entry(hContext); if (entry == NULL) return TSPERR(TSS_E_NO_CONNECTION); switch (entry->type) { case CONNECTION_TYPE_TCP_PERSISTANT: result = RPC_KeyControlOwner_TP(entry, hKey, ulPublicInfoLength, rgbPublicInfo, attribName, attribValue, pOwnerAuth, pUuidData); break; default: break; } put_table_entry(entry); return result; } #endif trousers-0.3.15/src/tspi/tsp_get_flags.c0000664000175000017510000000346113663651711017513 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT get_tpm_flags(TSS_HCONTEXT tspContext, TSS_HTPM hTPM, UINT32 *volFlags, UINT32 *nonVolFlags) { TCPA_DIGEST digest; TPM_AUTH auth; TCPA_VERSION version; TSS_RESULT result; TSS_HPOLICY hPolicy; Trspi_HashCtx hashCtx; if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy))) return result; /* do an owner authorized get capability call */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetCapabilityOwner); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_GetCapabilityOwner, hPolicy, FALSE, &digest, &auth))) return result; if ((result = TCS_API(tspContext)->GetCapabilityOwner(tspContext, &auth, &version, nonVolFlags, volFlags))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetCapabilityOwner); result |= Trspi_Hash_VERSION(&hashCtx, (TSS_VERSION *)&version); result |= Trspi_Hash_UINT32(&hashCtx, *nonVolFlags); result |= Trspi_Hash_UINT32(&hashCtx, *volFlags); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; return obj_policy_validate_auth_oiap(hPolicy, &digest, &auth); } trousers-0.3.15/src/tspi/tsp_tick.c0000664000175000017510000000643613663651711016517 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_ReadCurrentTicks(TSS_HCONTEXT tspContext, /* in */ UINT32* pulCurrentTime, /* out */ BYTE** prgbCurrentTime) /* out */ { TSS_RESULT result; UINT32 decLen = 0; BYTE *dec = NULL; TCS_HANDLE handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetTicks, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; *pulCurrentTime = decLen; *prgbCurrentTime = dec; return TSS_SUCCESS; } TSS_RESULT Transport_TickStampBlob(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_NONCE* antiReplay, /* in */ TPM_DIGEST* digestToStamp, /* in */ TPM_AUTH* privAuth, /* in, out */ UINT32* pulSignatureLength, /* out */ BYTE** prgbSignature, /* out */ UINT32* pulTickCountLength, /* out */ BYTE** prgbTickCount) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen = 0; TCS_HANDLE *handles, handle; BYTE *dec = NULL; UINT64 offset; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE data[sizeof(TPM_NONCE) + sizeof(TPM_DIGEST)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(hKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = hKey; handles = &handle; offset = 0; Trspi_LoadBlob_NONCE(&offset, data, antiReplay); Trspi_LoadBlob_DIGEST(&offset, data, digestToStamp); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_TickStampBlob, sizeof(data), data, &pubKeyHash, &handlesLen, &handles, privAuth, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_CURRENT_TICKS(&offset, dec, NULL); *pulTickCountLength = (UINT32)offset; if ((*prgbTickCount = malloc(*pulTickCountLength)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *pulTickCountLength); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_UnloadBlob(&offset, *pulTickCountLength, dec, *prgbTickCount); Trspi_UnloadBlob_UINT32(&offset, pulSignatureLength, dec); if ((*prgbSignature = malloc(*pulSignatureLength)) == NULL) { free(dec); free(*prgbTickCount); *pulTickCountLength = 0; LogError("malloc of %u bytes failed", *pulSignatureLength); *pulSignatureLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *pulSignatureLength, dec, *prgbSignature); free(dec); return result; } #endif trousers-0.3.15/src/tspi/obj_daa.c0000664000175000017510000000633213663651711016251 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" /* * adds a new daa object to the daa list with TSP context tspContext */ TSS_RESULT obj_daa_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_daa_obj *daa = calloc(1, sizeof(struct tr_daa_obj)); if (daa == NULL) { LogError("malloc of %d bytes failed.", sizeof(struct tr_daa_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } if ((result = obj_list_add(&daa_list, tspContext, 0, daa, phObject))) { free(daa); return result; } return TSS_SUCCESS; } void daa_free(void *data) { struct tr_daa_obj *daa = (struct tr_daa_obj *)data; /* free all pointers in the tr_daa_obj object here */ free(daa); } /* * remove DAA object hObject from the DAA list */ TSS_RESULT obj_daa_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { TSS_RESULT result; if ((result = obj_list_remove(&daa_list, &daa_free, hObject, tspContext))) return result; return TSS_SUCCESS; } TSS_BOOL obj_is_daa(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&daa_list, hObject))) { answer = TRUE; obj_list_put(&daa_list); } return answer; } TSS_RESULT obj_daa_get_tsp_context(TSS_HDAA hDaa, TSS_HCONTEXT *tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&daa_list, hDaa)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&daa_list); return TSS_SUCCESS; } static TSS_RESULT obj_daa_get_and_lock_data(TSS_HDAA hDaa, struct tr_daa_obj **daa) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&daa_list, hDaa)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *daa = obj->data; return TSS_SUCCESS; } TSS_RESULT obj_daa_get_handle_tpm(TSS_HDAA hDAA, TPM_HANDLE *hTPM) { struct tr_daa_obj *daa_struct; TSS_RESULT result; if( (result = obj_daa_get_and_lock_data( hDAA, &daa_struct)) != TSS_SUCCESS) return result; *hTPM = daa_struct->tpm_handle; obj_list_put(&daa_list); return TSS_SUCCESS; } TSS_RESULT obj_daa_set_handle_tpm(TSS_HDAA hDAA, TPM_HANDLE hTPM) { struct tr_daa_obj *daa_struct; TSS_RESULT result; if( (result = obj_daa_get_and_lock_data( hDAA, &daa_struct)) != TSS_SUCCESS) return result; daa_struct->tpm_handle = hTPM; obj_list_put(&daa_list); return TSS_SUCCESS; } TSS_RESULT obj_daa_get_session_handle(TSS_HDAA hDAA, UINT32 *session_handle) { struct tr_daa_obj *daa_struct; TSS_RESULT result; if( (result = obj_daa_get_and_lock_data( hDAA, &daa_struct)) != TSS_SUCCESS) return result; *session_handle = daa_struct->session_handle; obj_list_put(&daa_list); return TSS_SUCCESS; } TSS_RESULT obj_daa_set_session_handle(TSS_HDAA hDAA, UINT32 session_handle) { struct tr_daa_obj *daa_struct; TSS_RESULT result; if( (result = obj_daa_get_and_lock_data( hDAA, &daa_struct)) != TSS_SUCCESS) return result; daa_struct->session_handle = session_handle; obj_list_put(&daa_list); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_quote2.c0000664000175000017510000002053413663651711017150 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_Quote2(TSS_HTPM hTPM, // in TSS_HKEY hIdentKey, // in TSS_BOOL fAddVersion, // in TSS_HPCRS hPcrComposite, // in TSS_VALIDATION* pValidationData, // in, out UINT32* versionInfoSize, // out BYTE** versionInfo) // out { TPM_RESULT result; TSS_HCONTEXT tspContext; TPM_AUTH privAuth; TPM_AUTH *pPrivAuth = &privAuth; UINT64 offset; TPM_DIGEST digest; TSS_BOOL usesAuth; TCS_KEY_HANDLE tcsKeyHandle; TSS_HPOLICY hPolicy; TPM_NONCE antiReplay; UINT32 pcrDataSize; BYTE pcrData[128]; UINT32 sigSize = 0; BYTE *sig = NULL; UINT32 pcrDataOutSize; BYTE *pcrDataOut; BYTE quoteinfo[1024]; Trspi_HashCtx hashCtx; LogDebug("Tspi_TPM_Quote2 Start:"); /* Takes the context that this TPM handle is on */ if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; /* Test if the hPcrComposite is valid */ if ((hPcrComposite) && !obj_is_pcrs(hPcrComposite)) return TSPERR(TSS_E_INVALID_HANDLE); /* get the identKey Policy */ if ((result = obj_rsakey_get_policy(hIdentKey, TSS_POLICY_USAGE, &hPolicy, &usesAuth))) return result; /* get the Identity TCS keyHandle */ if ((result = obj_rsakey_get_tcs_handle(hIdentKey, &tcsKeyHandle))) return result; /* Sets the validation data - if NULL, TSS provides it's own random value. If * not NULL, takes the validation external data and sets the antiReplay data * with this */ if (pValidationData == NULL) { LogDebug("Internal Verify:"); if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)antiReplay.nonce))) return result; } else { LogDebug("External Verify:"); if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); } /* Create the TPM_PCR_COMPOSITE object */ pcrDataSize = 0; if (hPcrComposite) { /* Load the PCR Selection Object into the pcrData */ if ((result = obj_pcrs_get_selection(hPcrComposite, &pcrDataSize, pcrData))) return result; } if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Quote2); result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce); result |= Trspi_HashUpdate(&hashCtx, pcrDataSize, pcrData); result |= Trspi_Hash_BOOL(&hashCtx,fAddVersion); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hIdentKey, TPM_ORD_Quote2, hPolicy, FALSE, &digest, &privAuth))) { return result; } pPrivAuth = &privAuth; } else { pPrivAuth = NULL; } /* Send to TCS */ if ((result = TCS_API(tspContext)->Quote2(tspContext, tcsKeyHandle, &antiReplay, pcrDataSize, pcrData, fAddVersion, pPrivAuth, &pcrDataOutSize, &pcrDataOut, versionInfoSize, versionInfo, &sigSize, &sig))) return result; #ifdef TSS_DEBUG LogDebug("Got TCS Response:"); LogDebug(" pcrDataOutSize: %u",pcrDataOutSize); LogDebug(" pcrDataOut:"); LogDebugData(pcrDataOutSize,pcrDataOut); LogDebug(" versionInfoSize: %u",*versionInfoSize); LogDebug(" versionInfo:"); if (*versionInfoSize >0) LogDebugData(*versionInfoSize,*versionInfo); LogDebug(" sigSize: %u",sigSize); LogDebug(" sig:"); LogDebugData(sigSize,sig); #endif if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Quote2); result |= Trspi_HashUpdate(&hashCtx, pcrDataOutSize, pcrDataOut); result |= Trspi_Hash_UINT32(&hashCtx,*versionInfoSize); if (*versionInfoSize > 0) result |= Trspi_HashUpdate(&hashCtx, *versionInfoSize,*versionInfo); result |= Trspi_Hash_UINT32(&hashCtx, sigSize); result |= Trspi_HashUpdate(&hashCtx, sigSize, sig); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free(pcrDataOut); if (*versionInfoSize > 0) free(*versionInfo); free(sig); return result; } if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &privAuth))) { free(pcrDataOut); if (*versionInfoSize > 0) free(*versionInfo); free(sig); return result; } } /* Set the pcrDataOut back to the TSS */ if (hPcrComposite){ TPM_PCR_INFO_SHORT pcrInfo; offset = 0; if ((result = Trspi_UnloadBlob_PCR_INFO_SHORT(&offset, pcrDataOut, &pcrInfo))) { free(pcrDataOut); free(pcrInfo.pcrSelection.pcrSelect); if (*versionInfoSize > 0) free(*versionInfo); free(sig); return result; } free(pcrInfo.pcrSelection.pcrSelect); /* Set both digestAtRelease and localityAtRelease */ if ((result = obj_pcrs_set_locality(hPcrComposite, pcrInfo.localityAtRelease))) { free(pcrDataOut); if (*versionInfoSize > 0) free(*versionInfo); free(sig); return result; } if ((result = obj_pcrs_set_digest_at_release(hPcrComposite, pcrInfo.digestAtRelease))) { free(pcrDataOut); if (*versionInfoSize > 0) free(*versionInfo); free(sig); return result; } } /* generate TPM_QUOTE_INFO2 struct */ __tspi_memset("einfo, 0, sizeof(quoteinfo)); offset = 0; /* 1. Add Structure TAG */ quoteinfo[offset++] = 0x00; quoteinfo[offset++] = (BYTE) TPM_TAG_QUOTE_INFO2; /* 2. add "QUT2" */ quoteinfo[offset++]='Q'; quoteinfo[offset++]='U'; quoteinfo[offset++]='T'; quoteinfo[offset++]='2'; /* 3. AntiReplay Nonce - add the external data*/ Trspi_LoadBlob(&offset, TCPA_SHA1_160_HASH_LEN, quoteinfo, antiReplay.nonce); /* 4. add the infoshort TPM_PCR_INFO_SHORT data */ Trspi_LoadBlob(&offset,pcrDataOutSize,quoteinfo,pcrDataOut); free(pcrDataOut); if (fAddVersion) Trspi_LoadBlob(&offset,*versionInfoSize,quoteinfo,*versionInfo); else { /* versionInfo was not allocated and versionInfoSize has invalid value */ *versionInfoSize = 0; *versionInfo = NULL; } LogDebug("TPM_QUOTE_INFO2 data: "); LogDebugData(offset,quoteinfo); if (pValidationData == NULL) { if ((result = Trspi_Hash(TSS_HASH_SHA1, offset, quoteinfo, digest.digest))) { free(sig); if (*versionInfoSize > 0) free(*versionInfo); return result; } if ((result = __tspi_rsa_verify(hIdentKey,TSS_HASH_SHA1,sizeof(digest.digest), digest.digest, sigSize, sig))) { free(sig); if (*versionInfoSize > 0) free(*versionInfo); return TSPERR(TSS_E_VERIFICATION_FAILED); } free(sig); } else { pValidationData->rgbValidationData = calloc_tspi(tspContext, sigSize); if (pValidationData->rgbValidationData == NULL) { LogError("malloc of %u bytes failed.", sigSize); free(sig); if (*versionInfoSize > 0) free(*versionInfo); return TSPERR(TSS_E_OUTOFMEMORY); } pValidationData->ulValidationDataLength = sigSize; memcpy(pValidationData->rgbValidationData, sig, sigSize); free(sig); pValidationData->rgbData = calloc_tspi(tspContext, offset); if (pValidationData->rgbData == NULL) { LogError("malloc of %" PRIu64 " bytes failed.", offset); free_tspi(tspContext, pValidationData->rgbValidationData); pValidationData->rgbValidationData = NULL; pValidationData->ulValidationDataLength = 0; if (*versionInfoSize > 0) free(*versionInfo); return TSPERR(TSS_E_OUTOFMEMORY); } pValidationData->ulDataLength = (UINT32)offset; memcpy(pValidationData->rgbData, quoteinfo, offset); } if(*versionInfoSize > 0) { if(fAddVersion && pValidationData) { /* tag versionInfo so that it can be free'd by the app through Tspi_Context_FreeMemory */ if ((result = __tspi_add_mem_entry(tspContext, *versionInfo))) { free_tspi(tspContext, pValidationData->rgbValidationData); pValidationData->rgbValidationData = NULL; pValidationData->ulValidationDataLength = 0; free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; free(*versionInfo); return result; } } else { free(*versionInfo); } } LogDebug("Tspi_TPM_Quote2 End"); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_key.c0000664000175000017510000002014513663651711016346 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" void free_key_refs(TSS_KEY *key) { free(key->algorithmParms.parms); key->algorithmParms.parms = NULL; key->algorithmParms.parmSize = 0; free(key->pubKey.key); key->pubKey.key = NULL; key->pubKey.keyLength = 0; free(key->encData); key->encData = NULL; key->encSize = 0; free(key->PCRInfo); key->PCRInfo = NULL; key->PCRInfoSize = 0; } void LoadBlob_TSS_KEY(UINT64 *offset, BYTE *blob, TSS_KEY *key) { if (key->hdr.key12.tag == TPM_TAG_KEY12) Trspi_LoadBlob_KEY12(offset, blob, (TPM_KEY12 *)key); else Trspi_LoadBlob_KEY(offset, blob, (TCPA_KEY *)key); } TSS_RESULT UnloadBlob_TSS_KEY(UINT64 *offset, BYTE *blob, TSS_KEY *key) { UINT16 tag; UINT64 keyOffset = *offset; TSS_RESULT result; Trspi_UnloadBlob_UINT16(&keyOffset, &tag, blob); if (tag == TPM_TAG_KEY12) result = Trspi_UnloadBlob_KEY12(offset, blob, (TPM_KEY12 *)key); else result = Trspi_UnloadBlob_KEY(offset, blob, (TCPA_KEY *)key); return result; } TSS_RESULT Hash_TSS_KEY(Trspi_HashCtx *c, TSS_KEY *key) { TSS_RESULT result; if (key->hdr.key12.tag == TPM_TAG_KEY12) result = Trspi_Hash_KEY12(c, (TPM_KEY12 *)key); else result = Trspi_Hash_KEY(c, (TCPA_KEY *)key); return result; } void LoadBlob_TSS_PRIVKEY_DIGEST(UINT64 *offset, BYTE *blob, TSS_KEY *key) { if (key->hdr.key12.tag == TPM_TAG_KEY12) Trspi_LoadBlob_PRIVKEY_DIGEST12(offset, blob, (TPM_KEY12 *)key); else Trspi_LoadBlob_PRIVKEY_DIGEST(offset, blob, (TCPA_KEY *)key); } TSS_RESULT Hash_TSS_PRIVKEY_DIGEST(Trspi_HashCtx *c, TSS_KEY *key) { TSS_RESULT result; if (key->hdr.key12.tag == TPM_TAG_KEY12) result = Trspi_Hash_PRIVKEY_DIGEST12(c, (TPM_KEY12 *)key); else result = Trspi_Hash_PRIVKEY_DIGEST(c, (TCPA_KEY *)key); return result; } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_EvictKey(TSS_HCONTEXT tspContext, TCS_KEY_HANDLE hKey) { TSS_RESULT result; UINT32 handlesLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(hKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = hKey; handles = &handle; result = obj_context_transport_execute(tspContext, TPM_ORD_EvictKey, 0, NULL, &pubKeyHash, &handlesLen, &handles, NULL, NULL, NULL, NULL); return result; } TSS_RESULT Transport_GetPubKey(TSS_HCONTEXT tspContext, TCS_KEY_HANDLE hKey, TPM_AUTH *pAuth, UINT32 *pcPubKeySize, BYTE **prgbPubKey) { TSS_RESULT result; UINT32 handlesLen, decLen; TCS_HANDLE *handles, handle; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(hKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = hKey; handles = &handle; if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetPubKey, 0, NULL, &pubKeyHash, &handlesLen, &handles, pAuth, NULL, &decLen, &dec))) return result; *prgbPubKey = dec; *pcPubKeySize = decLen; return result; } TSS_RESULT Transport_CreateWrapKey(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hWrappingKey, /* in */ TPM_ENCAUTH *KeyUsageAuth, /* in */ TPM_ENCAUTH *KeyMigrationAuth, /* in */ UINT32 keyInfoSize, /* in */ BYTE * keyInfo, /* in */ UINT32 * keyDataSize, /* out */ BYTE ** keyData, /* out */ TPM_AUTH * pAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen, decLen; TCS_HANDLE *handles, handle; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(hWrappingKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = hWrappingKey; handles = &handle; if ((data = malloc(2 * sizeof(TPM_ENCAUTH) + keyInfoSize)) == NULL) { LogError("malloc of %zd bytes failed", 2 * sizeof(TPM_ENCAUTH) + keyInfoSize); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob(&offset, sizeof(TPM_ENCAUTH), data, KeyUsageAuth->authdata); Trspi_LoadBlob(&offset, sizeof(TPM_ENCAUTH), data, KeyMigrationAuth->authdata); Trspi_LoadBlob(&offset, keyInfoSize, data, keyInfo); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_CreateWrapKey, (2 * sizeof(TPM_ENCAUTH) + keyInfoSize), data, &pubKeyHash, &handlesLen, &handles, pAuth, NULL, &decLen, &dec))) goto done; *keyDataSize = decLen; *keyData = dec; done: free(data); return result; } TSS_RESULT Transport_LoadKeyByBlob(TSS_HCONTEXT tspContext, TCS_KEY_HANDLE hParentKey, UINT32 ulBlobLength, BYTE* rgbBlobData, TPM_AUTH* pAuth, TCS_KEY_HANDLE* phKey, TPM_KEY_HANDLE* phSlot) { TSS_RESULT result; UINT32 handlesLen, decLen; TCS_HANDLE *handles, handle; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(hParentKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = hParentKey; handles = &handle; if ((result = obj_context_transport_execute(tspContext, TPM_ORD_LoadKey2, ulBlobLength, rgbBlobData, &pubKeyHash, &handlesLen, &handles, pAuth, NULL, &decLen, &dec))) return result; if (handlesLen == 1) *phKey = *(TCS_KEY_HANDLE *)handles; else result = TSPERR(TSS_E_INTERNAL_ERROR); free(dec); return result; } /* This function both encrypts the handle of the pubkey being requested and requires the hash * of that pubkey for the transport log when logging is enabled. */ TSS_RESULT Transport_OwnerReadInternalPub(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH* pOwnerAuth, /* in, out */ UINT32* punPubKeySize, /* out */ BYTE** ppbPubKeyData) /* out */ { UINT64 offset; TSS_RESULT result; UINT32 handlesLen = 0, decLen; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE *dec = NULL, data[sizeof(TCS_KEY_HANDLE)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(hKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; offset = 0; Trspi_LoadBlob_UINT32(&offset, hKey, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_OwnerReadInternalPub, sizeof(data), data, &pubKeyHash, &handlesLen, NULL, pOwnerAuth, NULL, &decLen, &dec))) return result; *punPubKeySize = decLen; *ppbPubKeyData = dec; return result; } #endif trousers-0.3.15/src/tspi/tsp_nv.c0000664000175000017510000001460213663651711016202 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_NV_DefineOrReleaseSpace(TSS_HCONTEXT tspContext, /* in */ UINT32 cPubInfoSize, /* in */ BYTE* pPubInfo, /* in */ TCPA_ENCAUTH encAuth, /* in */ TPM_AUTH* pAuth) /* in, out */ { TSS_RESULT result; UINT32 dataLen; UINT64 offset; TCS_HANDLE handlesLen = 0; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TCPA_ENCAUTH) + cPubInfoSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob(&offset, cPubInfoSize, data, pPubInfo); Trspi_LoadBlob(&offset, TPM_SHA1_160_HASH_LEN, data, encAuth.authdata); result = obj_context_transport_execute(tspContext, TPM_ORD_NV_DefineSpace, dataLen, data, NULL, &handlesLen, NULL, pAuth, NULL, NULL, NULL); free(data); return result; } TSS_RESULT Transport_NV_WriteValue(TSS_HCONTEXT tspContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* privAuth) /* in, out */ { TSS_RESULT result; UINT32 dataLen; UINT64 offset64; TCS_HANDLE handlesLen = 0; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TSS_NV_INDEX) + (2 * sizeof(UINT32)) + ulDataLength; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset64 = 0; Trspi_LoadBlob_UINT32(&offset64, hNVStore, data); Trspi_LoadBlob_UINT32(&offset64, offset, data); Trspi_LoadBlob_UINT32(&offset64, ulDataLength, data); Trspi_LoadBlob(&offset64, ulDataLength, data, rgbDataToWrite); result = obj_context_transport_execute(tspContext, TPM_ORD_NV_WriteValue, dataLen, data, NULL, &handlesLen, NULL, privAuth, NULL, NULL, NULL); free(data); return result; } TSS_RESULT Transport_NV_WriteValueAuth(TSS_HCONTEXT tspContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* NVAuth) /* in, out */ { TSS_RESULT result; UINT32 dataLen; UINT64 offset64; TCS_HANDLE handlesLen = 0; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TSS_NV_INDEX) + (2 * sizeof(UINT32)) + ulDataLength; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset64 = 0; Trspi_LoadBlob_UINT32(&offset64, hNVStore, data); Trspi_LoadBlob_UINT32(&offset64, offset, data); Trspi_LoadBlob_UINT32(&offset64, ulDataLength, data); Trspi_LoadBlob(&offset64, ulDataLength, data, rgbDataToWrite); result = obj_context_transport_execute(tspContext, TPM_ORD_NV_WriteValueAuth, dataLen, data, NULL, &handlesLen, NULL, NVAuth, NULL, NULL, NULL); free(data); return result; } TSS_RESULT Transport_NV_ReadValue(TSS_HCONTEXT tspContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in, out */ TPM_AUTH* privAuth, /* in, out */ BYTE** rgbDataRead) /* out */ { TSS_RESULT result; UINT32 dataLen, decLen; UINT64 offset64; TCS_HANDLE handlesLen = 0; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TSS_NV_INDEX) + sizeof(UINT32) + *pulDataLength; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset64 = 0; Trspi_LoadBlob_UINT32(&offset64, hNVStore, data); Trspi_LoadBlob_UINT32(&offset64, offset, data); Trspi_LoadBlob_UINT32(&offset64, *pulDataLength, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_NV_ReadValue, dataLen, data, NULL, &handlesLen, NULL, privAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset64 = 0; Trspi_UnloadBlob_UINT32(&offset64, pulDataLength, dec); if ((*rgbDataRead = malloc(*pulDataLength)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *pulDataLength); *pulDataLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset64, *pulDataLength, dec, *rgbDataRead); free(dec); return result; } TSS_RESULT Transport_NV_ReadValueAuth(TSS_HCONTEXT tspContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in, out */ TPM_AUTH* NVAuth, /* in, out */ BYTE** rgbDataRead) /* out */ { TSS_RESULT result; UINT32 dataLen, decLen; UINT64 offset64; TCS_HANDLE handlesLen = 0; BYTE *data, *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TSS_NV_INDEX) + sizeof(UINT32) + *pulDataLength; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset64 = 0; Trspi_LoadBlob_UINT32(&offset64, hNVStore, data); Trspi_LoadBlob_UINT32(&offset64, offset, data); Trspi_LoadBlob_UINT32(&offset64, *pulDataLength, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_NV_ReadValueAuth, dataLen, data, NULL, &handlesLen, NULL, NVAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset64 = 0; Trspi_UnloadBlob_UINT32(&offset64, pulDataLength, dec); if ((*rgbDataRead = malloc(*pulDataLength)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *pulDataLength); *pulDataLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset64, *pulDataLength, dec, *rgbDataRead); free(dec); return result; } #endif trousers-0.3.15/src/tspi/obj_context.c0000664000175000017510000012414213663651711017210 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "tcs_tsp.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "tsp_tcsi_param.h" TSS_RESULT obj_context_add(TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_context_obj *context = calloc(1, sizeof(struct tr_context_obj)); if (context == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_context_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } #ifndef TSS_NO_GUI context->silentMode = TSS_TSPATTRIB_CONTEXT_NOT_SILENT; #else context->silentMode = TSS_TSPATTRIB_CONTEXT_SILENT; #endif if ((result = get_tcsd_hostname((char **)&context->machineName, &context->machineNameLength)) != TSS_SUCCESS) { free(context); return result; } LogDebug("Hostname to be used by the context is %s.", context->machineName); context->hashMode = TSS_TSPATTRIB_HASH_MODE_NOT_NULL; context->connection_policy = TSS_TSPATTRIB_CONTEXT_VERSION_V1_1; if ((result = obj_list_add(&context_list, NULL_HCONTEXT, 0, context, phObject))) { free(context->machineName); free(context); return result; } /* Add the default policy */ if ((result = obj_policy_add(*phObject, TSS_POLICY_USAGE, &context->policy))) { obj_list_remove(&context_list, &__tspi_obj_context_free, *phObject, *phObject); return result; } context->tcs_api = &tcs_normal_api; return TSS_SUCCESS; } struct tcs_api_table * obj_context_get_tcs_api(TSS_HCONTEXT tspContext) { struct tsp_object *obj; struct tr_context_obj *context; struct tcs_api_table *t; /* If the object cannot be found with the given handle, return a safe value, the normal TCS * API pointer. Since the handle is bad, the RPC_ function will barf in looking up the * corresponding TCS context handle and an invalid handle error will be returned. */ if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return &tcs_normal_api; context = (struct tr_context_obj *)obj->data; /* Return the current API set we're using, either the normal API, or the transport encrypted * API. The context->tcs_api variable is switched back and forth between the two sets by * the obj_context_transport_set_control function through a set attrib. */ t = context->tcs_api; obj_list_put(&context_list); return t; } void __tspi_obj_context_free(void *data) { struct tr_context_obj *context = (struct tr_context_obj *)data; free(context->machineName); free(context); } TSS_BOOL obj_is_context(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&context_list, hObject))) { answer = TRUE; obj_list_put(&context_list); } return answer; } /* Clean up transport session if necessary. */ void obj_context_close(TSS_HCONTEXT tspContext) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return; context = (struct tr_context_obj *)obj->data; #ifdef TSS_BUILD_TRANSPORT if (context->transAuth.AuthHandle) { RPC_FlushSpecific(tspContext, context->transAuth.AuthHandle, TPM_RT_TRANS); __tspi_memset(&context->transPub, 0, sizeof(TPM_TRANSPORT_PUBLIC)); __tspi_memset(&context->transMod, 0, sizeof(TPM_MODIFIER_INDICATOR)); __tspi_memset(&context->transSecret, 0, sizeof(TPM_TRANSPORT_AUTH)); __tspi_memset(&context->transAuth, 0, sizeof(TPM_AUTH)); __tspi_memset(&context->transLogIn, 0, sizeof(TPM_TRANSPORT_LOG_IN)); __tspi_memset(&context->transLogOut, 0, sizeof(TPM_TRANSPORT_LOG_OUT)); __tspi_memset(&context->transLogDigest, 0, sizeof(TPM_DIGEST)); } #endif obj_list_put(&context_list); } TSS_RESULT obj_context_get_policy(TSS_HCONTEXT tspContext, UINT32 policyType, TSS_HPOLICY *phPolicy) { struct tsp_object *obj; struct tr_context_obj *context; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; switch (policyType) { case TSS_POLICY_USAGE: *phPolicy = context->policy; break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } obj_list_put(&context_list); return result; } TSS_RESULT obj_context_get_machine_name(TSS_HCONTEXT tspContext, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_context_obj *context; TSS_RESULT result; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; if (context->machineNameLength == 0) { *data = NULL; *size = 0; LogDebug("context->machineName is NULL."); } else { /* * Don't use calloc_tspi because this memory is * not freed using "free_tspi" */ *data = calloc(1, context->machineNameLength); if (*data == NULL) { LogError("malloc of %u bytes failed.", context->machineNameLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = context->machineNameLength; LogDebug("context->machineName: %s.", context->machineName); memcpy(*data, context->machineName, *size); } result = TSS_SUCCESS; done: obj_list_put(&context_list); return result; } /* This function converts the machine name to a TSS_UNICODE string before * returning it, as Tspi_GetAttribData would like. We could do the conversion * in Tspi_GetAttribData, but we don't have access to the TSP context there */ TSS_RESULT obj_context_get_machine_name_attrib(TSS_HCONTEXT tspContext, UINT32 *size, BYTE **data) { struct tsp_object *obj; struct tr_context_obj *context; BYTE *utf_string; UINT32 utf_size; TSS_RESULT result; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; if (context->machineNameLength == 0) { *data = NULL; *size = 0; } else { utf_size = context->machineNameLength; utf_string = Trspi_Native_To_UNICODE(context->machineName, &utf_size); if (utf_string == NULL) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *data = calloc_tspi(obj->tspContext, utf_size); if (*data == NULL) { free(utf_string); LogError("malloc of %u bytes failed.", utf_size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = utf_size; memcpy(*data, utf_string, utf_size); free(utf_string); } result = TSS_SUCCESS; done: obj_list_put(&context_list); return result; } TSS_RESULT obj_context_set_machine_name(TSS_HCONTEXT tspContext, BYTE *name, UINT32 len) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; free(context->machineName); context->machineName = (BYTE *)calloc(1, len); if (context->machineName == NULL) { LogError("malloc of %u bytes failed.", len); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(context->machineName, name, len); context->machineNameLength = len; obj_list_put(&context_list); return TSS_SUCCESS; } TSS_BOOL obj_context_is_silent(TSS_HCONTEXT tspContext) { struct tsp_object *obj; struct tr_context_obj *context; TSS_BOOL silent = FALSE; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return FALSE; context = (struct tr_context_obj *)obj->data; if (context->silentMode == TSS_TSPATTRIB_CONTEXT_SILENT) silent = TRUE; obj_list_put(&context_list); return silent; } TSS_RESULT obj_context_get_mode(TSS_HCONTEXT tspContext, UINT32 *mode) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; *mode = context->silentMode; obj_list_put(&context_list); return TSS_SUCCESS; } TSS_RESULT obj_context_set_mode(TSS_HCONTEXT tspContext, UINT32 mode) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; context->silentMode = mode; obj_list_put(&context_list); return TSS_SUCCESS; } /* search the list of all policies bound to context @tspContext. If * one is found of type popup, return TRUE, else return FALSE. */ TSS_BOOL obj_context_has_popups(TSS_HCONTEXT tspContext) { struct tsp_object *obj; struct tr_policy_obj *policy; struct obj_list *list = &policy_list; TSS_BOOL ret = FALSE; MUTEX_LOCK(list->lock); for (obj = list->head; obj; obj = obj->next) { if (obj->tspContext == tspContext) { policy = (struct tr_policy_obj *)obj->data; if (policy->SecretMode == TSS_SECRET_MODE_POPUP) ret = TRUE; break; } } MUTEX_UNLOCK(list->lock); return ret; } TSS_RESULT obj_context_get_hash_mode(TSS_HCONTEXT tspContext, UINT32 *mode) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; *mode = context->hashMode; obj_list_put(&context_list); return TSS_SUCCESS; } TSS_RESULT obj_context_set_hash_mode(TSS_HCONTEXT tspContext, UINT32 mode) { struct tsp_object *obj; struct tr_context_obj *context; switch (mode) { case TSS_TSPATTRIB_HASH_MODE_NULL: case TSS_TSPATTRIB_HASH_MODE_NOT_NULL: break; default: return TSPERR(TSS_E_INVALID_ATTRIB_DATA); } if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; context->hashMode = mode; obj_list_put(&context_list); return TSS_SUCCESS; } TSS_RESULT obj_context_get_connection_version(TSS_HCONTEXT tspContext, UINT32 *version) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; *version = context->current_connection; obj_list_put(&context_list); return TSS_SUCCESS; } TSS_RESULT obj_context_set_connection_policy(TSS_HCONTEXT tspContext, UINT32 policy) { struct tsp_object *obj; struct tr_context_obj *context; switch (policy) { case TSS_TSPATTRIB_CONTEXT_VERSION_V1_1: case TSS_TSPATTRIB_CONTEXT_VERSION_V1_2: case TSS_TSPATTRIB_CONTEXT_VERSION_AUTO: break; default: return TSPERR(TSS_E_INVALID_ATTRIB_DATA); } if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; context->connection_policy = policy; obj_list_put(&context_list); return TSS_SUCCESS; } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT obj_context_set_transport_key(TSS_HCONTEXT tspContext, TSS_HKEY hKey) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; context->transKey = hKey; obj_list_put(&context_list); return TSS_SUCCESS; } TSS_RESULT obj_context_transport_get_mode(TSS_HCONTEXT tspContext, UINT32 value, UINT32 *out) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; switch (value) { case TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION: *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT ? FALSE : TRUE; break; case TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION: *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT ? TRUE : FALSE; break; case TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL: *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC ? TRUE : FALSE; break; case TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE: *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE ? TRUE : FALSE; break; case TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH: *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH ? TRUE : FALSE; break; default: LogError("Invalid attribute subflag: 0x%x", value); result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; } obj_list_put(&context_list); return result; } TSS_RESULT obj_context_transport_get_control(TSS_HCONTEXT tspContext, UINT32 value, UINT32 *out) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; switch (value) { case TSS_TSPATTRIB_DISABLE_TRANSPORT: *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED ? FALSE : TRUE; break; case TSS_TSPATTRIB_ENABLE_TRANSPORT: *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED ? TRUE : FALSE; break; default: LogError("Invalid attribute subflag: 0x%x", value); result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); break; } obj_list_put(&context_list); return result; } TSS_RESULT obj_context_transport_set_control(TSS_HCONTEXT tspContext, UINT32 value) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; switch (value) { case TSS_TSPATTRIB_ENABLE_TRANSPORT: context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED; context->tcs_api = &tcs_transport_api; break; case TSS_TSPATTRIB_DISABLE_TRANSPORT: context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED; context->tcs_api = &tcs_normal_api; break; default: LogError("Invalid attribute subflag: 0x%x", value); result = TSPERR(TSS_E_INTERNAL_ERROR); break; } obj_list_put(&context_list); return result; } TSS_RESULT obj_context_transport_set_mode(TSS_HCONTEXT tspContext, UINT32 value) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; switch (value) { case TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION: context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT; break; case TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION: context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT; break; case TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL: context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC; break; case TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE: context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE; break; case TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH: context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH; break; default: LogError("Invalid attribute subflag: 0x%x", value); result = TSPERR(TSS_E_INTERNAL_ERROR); break; } obj_list_put(&context_list); return result; } #if 0 TSS_RESULT get_trans_props(TSS_HCONTEXT tspContext, UINT32 *alg, UINT16 *enc) { TSS_RESULT result; UINT32 algs[] = { TPM_ALG_MGF1, TPM_ALG_AES128, 0 }, a = 0; UINT16 encs[] = { TPM_ES_SYM_OFB, TPM_ES_SYM_CNT, TPM_ES_SYM_CBC_PKCS5PAD, 0 }, e = 0; BYTE *respData; UINT32 respLen, tcsSubCap32; UINT16 tcsSubCap16; if (*alg) goto check_es; for (a = 0; algs[a]; a++) { tcsSubCap32 = endian32(algs[a]); if ((result = RPC_GetTPMCapability(tspContext, TPM_CAP_TRANS_ALG, sizeof(UINT32), (BYTE *)&tcsSubCap32, &respLen, &respData))) return result; if (*(TSS_BOOL *)respData == TRUE) { free(respData); break; } free(respData); } if (!algs[a]) { LogError("TPM reports no usable sym algorithms for transport session"); return TSPERR(TSS_E_INTERNAL_ERROR); } check_es: if (*enc || algs[a] == TPM_ALG_MGF1) goto done; for (e = 0; encs[e]; e++) { tcsSubCap16 = endian16(encs[e]); if ((result = RPC_GetTPMCapability(tspContext, TPM_CAP_TRANS_ES, sizeof(UINT16), (BYTE *)&tcsSubCap16, &respLen, &respData))) return result; if (*(TSS_BOOL *)respData == TRUE) { free(respData); break; } free(respData); } if (!encs[e]) { LogError("TPM reports no usable sym modes for transport session"); return TSPERR(TSS_E_INTERNAL_ERROR); } *alg = algs[a]; *enc = encs[e]; done: return TSS_SUCCESS; } #endif /* called before each TCSP_ExecuteTransport call */ TSS_RESULT obj_context_transport_init(TSS_HCONTEXT tspContext) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; /* return immediately if we're not in a transport session */ if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } /* if the session is not yet established, setup and call EstablishTransport */ if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED)) { if ((result = obj_context_transport_establish(tspContext, context))) goto done; } context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED; result = TSS_SUCCESS; done: obj_list_put(&context_list); return result; } TSS_RESULT obj_context_transport_establish(TSS_HCONTEXT tspContext, struct tr_context_obj *context) { TSS_RESULT result; UINT32 tickLen, secretLen, transPubLen, exclusive = TSS_TCSATTRIB_TRANSPORT_DEFAULT; BYTE *ticks, *secret; UINT64 offset; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TSS_HPOLICY hTransKeyPolicy; TPM_AUTH auth, *pAuth, *pTransAuth; TCS_KEY_HANDLE tcsTransKey; TSS_BOOL usesAuth = FALSE; UINT32 encKeyLen; BYTE encKey[256]; BYTE transPubBlob[sizeof(TPM_TRANSPORT_PUBLIC)]; BYTE transAuthBlob[sizeof(TPM_TRANSPORT_AUTH)]; context->transPub.tag = TPM_TAG_TRANSPORT_PUBLIC; context->transSecret.tag = TPM_TAG_TRANSPORT_AUTH; if ((result = get_local_random(tspContext, FALSE, TPM_SHA1_160_HASH_LEN, (BYTE **)context->transSecret.authData.authdata))) return result; if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH) context->transKey = TPM_KH_TRANSPORT; if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) context->transPub.transAttributes |= TPM_TRANSPORT_LOG; if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE) { context->transPub.transAttributes |= TPM_TRANSPORT_EXCLUSIVE; exclusive = TSS_TCSATTRIB_TRANSPORT_EXCLUSIVE; } /* XXX implement AES128+CTR (Winbond, Infineon), then AES256+CTR (Atmel) */ context->transPub.algId = TPM_ALG_MGF1; context->transPub.encScheme = TPM_ES_NONE; if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) { context->transPub.transAttributes |= TPM_TRANSPORT_ENCRYPT; if (context->transKey == TPM_KH_TRANSPORT) { LogError("No transport key handle has been set yet. Use " "Tspi_Context_SetTransEncryptionKey to set this handle"); return TSPERR(TSS_E_INTERNAL_ERROR); } } if (context->transKey == TPM_KH_TRANSPORT) { secret = context->transSecret.authData.authdata; secretLen = TPM_SHA1_160_HASH_LEN; } else { offset = 0; Trspi_LoadBlob_TRANSPORT_AUTH(&offset, transAuthBlob, &context->transSecret); secretLen = offset; /* encrypt the sym key with the wrapping RSA key */ encKeyLen = sizeof(encKey); if ((result = __tspi_rsa_encrypt(context->transKey, secretLen, transAuthBlob, &encKeyLen, encKey))) return result; secret = encKey; secretLen = encKeyLen; } offset = 0; Trspi_LoadBlob_TRANSPORT_PUBLIC(&offset, transPubBlob, &context->transPub); transPubLen = offset; if (context->transKey != TPM_KH_TRANSPORT) { if ((result = obj_rsakey_get_tcs_handle(context->transKey, &tcsTransKey))) return result; if ((result = obj_rsakey_get_policy(context->transKey, TSS_POLICY_USAGE, &hTransKeyPolicy, &usesAuth))) return result; if (!usesAuth) { LogError("Key used to establish a transport session must use auth"); return TSPERR(TSS_E_TSP_TRANS_AUTHREQUIRED); } } else tcsTransKey = TPM_KH_TRANSPORT; /* If logging is on, do TPM commands spec rev106 step 8.a */ __tspi_memset(context->transLogDigest.digest, 0, sizeof(TPM_DIGEST)); if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { context->transLogIn.tag = TPM_TAG_TRANSPORT_LOG_IN; /* step 8.a, i */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport); result |= Trspi_HashUpdate(&hashCtx, transPubLen, transPubBlob); result |= Trspi_Hash_UINT32(&hashCtx, secretLen); result |= Trspi_HashUpdate(&hashCtx, secretLen, secret); if ((result |= Trspi_HashFinal(&hashCtx, context->transLogIn.parameters.digest))) return result; /* step 8.a, ii */ __tspi_memset(context->transLogIn.pubKeyHash.digest, 0, sizeof(TPM_DIGEST)); /* step 8.a, iii */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); result |= Trspi_Hash_TRANSPORT_LOG_IN(&hashCtx, &context->transLogIn); if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) return result; } if (usesAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport); result |= Trspi_HashUpdate(&hashCtx, (UINT32)offset, (BYTE *)transPubBlob); result |= Trspi_Hash_UINT32(&hashCtx, secretLen); result |= Trspi_HashUpdate(&hashCtx, secretLen, secret); if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest))) return result; /* open OIAP session with continueAuthSession = TRUE */ if ((result = secret_PerformAuth_OIAP(context->transKey, TPM_ORD_EstablishTransport, hTransKeyPolicy, TRUE, &digest, &auth))) return result; pAuth = &auth; } else pAuth = NULL; result = RPC_EstablishTransport(tspContext, exclusive, tcsTransKey, transPubLen, transPubBlob, secretLen, secret, pAuth, &context->transMod, &context->transAuth.AuthHandle, &tickLen, &ticks, &context->transAuth.NonceEven); if (result) { LogError("Establish Transport command failed: %s", Trspi_Error_String(result)); return result; } result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport); result |= Trspi_Hash_UINT32(&hashCtx, context->transMod); result |= Trspi_HashUpdate(&hashCtx, tickLen, ticks); result |= Trspi_Hash_NONCE(&hashCtx, context->transAuth.NonceEven.nonce); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if (usesAuth) { if ((result = obj_policy_validate_auth_oiap(hTransKeyPolicy, &digest, pAuth))) return result; } /* step 8.b iii */ offset = 0; Trspi_UnloadBlob_CURRENT_TICKS(&offset, ticks, &context->transLogOut.currentTicks); free(ticks); /* If logging is on, do TPM commands spec rev106 step 8.b */ if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { context->transLogOut.tag = TPM_TAG_TRANSPORT_LOG_OUT; /* step 8.b i */ memcpy(context->transLogOut.parameters.digest, digest.digest, sizeof(TPM_DIGEST)); /* step 8.b ii */ context->transLogOut.locality = context->transMod; /* step 8.b iii was done above */ /* step 8.b iv */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut); if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) return result; } LogDebug("Transport session established successfully"); pTransAuth = &context->transAuth; pTransAuth->fContinueAuthSession = TRUE; if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)pTransAuth->NonceOdd.nonce))) { LogError("Failed creating random nonce"); return TSPERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT do_transport_decryption(TPM_TRANSPORT_PUBLIC *transPub, TPM_AUTH *pTransAuth, BYTE *secret, UINT32 inLen, BYTE *in, UINT32 *outLen, BYTE **out) { TSS_RESULT result; UINT32 i, decLen; UINT32 seedLen, ivLen; BYTE *dec; BYTE seed[(2 * sizeof(TPM_NONCE)) + strlen("out") + TPM_SHA1_160_HASH_LEN]; /* allocate the most data anyone below might need */ decLen = inLen;//((inLen / TSS_MAX_SYM_BLOCK_SIZE) + 1) * TSS_MAX_SYM_BLOCK_SIZE; if ((dec = malloc(decLen)) == NULL) { LogError("malloc of %u bytes failed", decLen); return TSPERR(TSS_E_OUTOFMEMORY); } /* set the common 3 initial values of 'seed', which is used to generate either the IV or * mask */ memcpy(seed, pTransAuth->NonceEven.nonce, sizeof(TPM_NONCE)); memcpy(&seed[sizeof(TPM_NONCE)], pTransAuth->NonceOdd.nonce, sizeof(TPM_NONCE)); memcpy(&seed[2 * sizeof(TPM_NONCE)], "out", strlen("out")); switch (transPub->algId) { case TPM_ALG_MGF1: { decLen = inLen; seedLen = sizeof(seed); /* add the secret data to the seed for MGF1 */ memcpy(&seed[2 * sizeof(TPM_NONCE) + strlen("out")], secret, TPM_SHA1_160_HASH_LEN); if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, decLen, dec))) { free(dec); return result; } for (i = 0; i < inLen; i++) dec[i] ^= in[i]; break; } case TPM_ALG_AES128: { BYTE iv[TSS_MAX_SYM_BLOCK_SIZE]; ivLen = TSS_MAX_SYM_BLOCK_SIZE; seedLen = (2 * sizeof(TPM_NONCE)) + strlen("out"); if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, ivLen, iv))) { free(dec); return result; } /* use the secret data as the key for AES */ if ((result = Trspi_SymEncrypt(transPub->algId, transPub->encScheme, secret, iv, in, inLen, dec, &decLen))) { free(dec); return result; } break; } default: LogDebug("Unknown algorithm for encrypted transport session: 0x%x", transPub->algId); free(dec); return TSPERR(TSS_E_INTERNAL_ERROR); } *out = dec; *outLen = decLen; return result; } TSS_RESULT do_transport_encryption(TPM_TRANSPORT_PUBLIC *transPub, TPM_AUTH *pTransAuth, BYTE *secret, UINT32 inLen, BYTE *in, UINT32 *outLen, BYTE **out) { TSS_RESULT result; UINT32 i, encLen; UINT32 seedLen, ivLen; BYTE *enc; BYTE seed[(2 * sizeof(TPM_NONCE)) + strlen("in") + TPM_SHA1_160_HASH_LEN]; /* allocate the most data anyone below might need */ encLen = ((inLen / TSS_MAX_SYM_BLOCK_SIZE) + 1) * TSS_MAX_SYM_BLOCK_SIZE; if ((enc = malloc(encLen)) == NULL) { LogError("malloc of %u bytes failed", encLen); return TSPERR(TSS_E_OUTOFMEMORY); } /* set the common 3 initial values of 'seed', which is used to generate either the IV or * mask */ memcpy(seed, pTransAuth->NonceEven.nonce, sizeof(TPM_NONCE)); memcpy(&seed[sizeof(TPM_NONCE)], pTransAuth->NonceOdd.nonce, sizeof(TPM_NONCE)); memcpy(&seed[2 * sizeof(TPM_NONCE)], "in", strlen("in")); switch (transPub->algId) { case TPM_ALG_MGF1: { encLen = inLen; seedLen = sizeof(seed); /* add the secret data to the seed for MGF1 */ memcpy(&seed[2 * sizeof(TPM_NONCE) + strlen("in")], secret, TPM_SHA1_160_HASH_LEN); if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, encLen, enc))) { free(enc); return result; } for (i = 0; i < inLen; i++) enc[i] ^= in[i]; break; } case TPM_ALG_AES128: { BYTE iv[TSS_MAX_SYM_BLOCK_SIZE]; ivLen = TSS_MAX_SYM_BLOCK_SIZE; seedLen = (2 * sizeof(TPM_NONCE)) + strlen("in"); if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, ivLen, iv))) { free(enc); return result; } /* use the secret data as the key for AES */ if ((result = Trspi_SymEncrypt(transPub->algId, transPub->encScheme, secret, iv, in, inLen, enc, &encLen))) { free(enc); return result; } break; } default: LogDebug("Unknown algorithm for encrypted transport session: 0x%x", transPub->algId); free(enc); return TSPERR(TSS_E_INTERNAL_ERROR); } *out = enc; *outLen = encLen; return result; } TSS_RESULT obj_context_transport_execute(TSS_HCONTEXT tspContext, TPM_COMMAND_CODE ordinal, UINT32 ulDataLen, BYTE* rgbData, TPM_DIGEST* pubKeyHash, UINT32* handlesLen, TCS_HANDLE** handles, TPM_AUTH* pAuth1, TPM_AUTH* pAuth2, UINT32* outLen, BYTE** out) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; UINT32 encLen, ulWrappedDataLen = 0; BYTE *pEnc = NULL, *rgbWrappedData = NULL; TPM_RESULT tpmResult; Trspi_HashCtx hashCtx; TPM_DIGEST etDigest, wDigest; TPM_AUTH *pTransAuth; UINT64 currentTicks; TSS_BOOL free_enc = FALSE; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; pTransAuth = &context->transAuth; /* TPM Commands spec rev106 step 6 */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); switch (ordinal) { case TPM_ORD_OSAP: case TPM_ORD_OIAP: break; default: result |= Trspi_HashUpdate(&hashCtx, ulDataLen, rgbData); break; } if ((result |= Trspi_HashFinal(&hashCtx, wDigest.digest))) goto done; if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { /* TPM Commands spec rev106 step 10.b */ memcpy(context->transLogIn.parameters.digest, wDigest.digest, sizeof(TPM_DIGEST)); /* TPM Commands spec rev106 step 10.c, d or e, calculated by the caller */ if (pubKeyHash) memcpy(context->transLogIn.pubKeyHash.digest, pubKeyHash->digest, sizeof(TPM_DIGEST)); else __tspi_memset(context->transLogIn.pubKeyHash.digest, 0, sizeof(TPM_DIGEST)); /* TPM Commands spec rev106 step 10.f */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); result |= Trspi_Hash_TRANSPORT_LOG_IN(&hashCtx, &context->transLogIn); if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) goto done; } /* TPM Commands spec rev106 step 7.a */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ExecuteTransport); result |= Trspi_Hash_UINT32(&hashCtx, ulDataLen + TSS_TPM_TXBLOB_HDR_LEN + (*handlesLen * sizeof(UINT32)) + (pAuth1 ? TPM_AUTH_RQU_SIZE : 0) + (pAuth2 ? TPM_AUTH_RQU_SIZE : 0)); result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, wDigest.digest); if ((result |= Trspi_HashFinal(&hashCtx, etDigest.digest))) goto done; /* encrypt the data if necessary */ if (ulDataLen && context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) { switch (ordinal) { case TPM_ORD_OSAP: case TPM_ORD_OIAP: encLen = ulDataLen; pEnc = rgbData; break; case TPM_ORD_DSAP: { UINT64 offset; UINT32 tmpLen, entityValueLen; BYTE *tmpEnc, *entityValuePtr; /* DSAP is a special case where only entityValue is encrypted. So, we'll * parse through rgbData until we get to entityValue, encrypt it, alloc * new space for rgbData (since it could be up to a block length larger * than it came in) and copy the unencrypted data and the encrypted * entityValue to the new block, setting pEnc and encLen to new values. */ offset = (2 * sizeof(UINT32)) + sizeof(TPM_NONCE); Trspi_UnloadBlob_UINT32(&offset, &entityValueLen, rgbData); entityValuePtr = &rgbData[offset]; if ((result = do_transport_encryption(&context->transPub, pTransAuth, context->transSecret.authData.authdata, entityValueLen, entityValuePtr, &tmpLen, &tmpEnc))) goto done; /* offset is the amount of data before the block we encrypted and tmpLen is * the size of the encrypted data */ encLen = offset + tmpLen; if ((pEnc = malloc(encLen)) == NULL) { LogError("malloc of %u bytes failed.", encLen); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(pEnc, rgbData, offset); memcpy(&pEnc[offset], tmpEnc, tmpLen); free(tmpEnc); free_enc = TRUE; break; } default: if ((result = do_transport_encryption(&context->transPub, pTransAuth, context->transSecret.authData.authdata, ulDataLen, rgbData, &encLen, &pEnc))) goto done; free_enc = TRUE; break; } } else { encLen = ulDataLen; pEnc = rgbData; } /* TPM Commands spec rev106 step 7.b */ HMAC_Auth(context->transSecret.authData.authdata, etDigest.digest, pTransAuth); if ((result = RPC_ExecuteTransport(tspContext, ordinal, encLen, pEnc, handlesLen, handles, pAuth1, pAuth2, pTransAuth, ¤tTicks, &context->transMod, &tpmResult, &ulWrappedDataLen, &rgbWrappedData))) { LogDebugFn("Execute Transport failed: %s", Trspi_Error_String(result)); goto done; } if (tpmResult) { LogDebug("Wrapped command ordinal 0x%x failed with result: 0x%x", ordinal, tpmResult); result = tpmResult; goto done; } /* decrypt the returned wrapped data if necessary */ if (ulWrappedDataLen && context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) { switch (ordinal) { case TPM_ORD_OSAP: case TPM_ORD_OIAP: case TPM_ORD_DSAP: *outLen = ulWrappedDataLen; *out = rgbWrappedData; break; default: if ((result = do_transport_decryption(&context->transPub, pTransAuth, context->transSecret.authData.authdata, ulWrappedDataLen, rgbWrappedData, outLen, out))) goto done; free(rgbWrappedData); } } else { if (outLen) { *outLen = ulWrappedDataLen; *out = rgbWrappedData; } } /* TPM Commands spec rev106 step 14 */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, tpmResult); result |= Trspi_Hash_UINT32(&hashCtx, ordinal); switch (ordinal) { case TPM_ORD_OSAP: case TPM_ORD_OIAP: break; default: if (outLen) result |= Trspi_HashUpdate(&hashCtx, *outLen, *out); break; } if ((result |= Trspi_HashFinal(&hashCtx, wDigest.digest))) goto done; /* TPM Commands spec rev106 step 15 */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ExecuteTransport); result |= Trspi_Hash_UINT64(&hashCtx, currentTicks); result |= Trspi_Hash_UINT32(&hashCtx, context->transMod); result |= Trspi_Hash_UINT32(&hashCtx, (outLen ? *outLen : 0) + TSS_TPM_TXBLOB_HDR_LEN + (*handlesLen * sizeof(UINT32)) + (pAuth1 ? TPM_AUTH_RSP_SIZE : 0) + (pAuth2 ? TPM_AUTH_RSP_SIZE : 0)); result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, wDigest.digest); if ((result |= Trspi_HashFinal(&hashCtx, etDigest.digest))) goto done; if (validateReturnAuth(context->transSecret.authData.authdata, etDigest.digest, pTransAuth)) { result = TSPERR(TSS_E_TSP_TRANS_AUTHFAIL); goto done; } if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { context->transLogOut.currentTicks.currentTicks = currentTicks; /* TPM Commands spec rev106 step 16.b */ memcpy(context->transLogOut.parameters.digest, wDigest.digest, sizeof(TPM_DIGEST)); /* TPM Commands spec rev106 step 16.c done above */ /* TPM Commands spec rev106 step 16.d */ context->transLogOut.locality = context->transMod; /* TPM Commands spec rev106 step 16.d */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut); if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) goto done; } /* Refresh nonceOdd for continued transport auth session */ if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)pTransAuth->NonceOdd.nonce))) { LogError("Failed creating random nonce"); } done: if (free_enc) free(pEnc); obj_list_put(&context_list); return result; } /* called to close a transport session */ TSS_RESULT obj_context_transport_close(TSS_HCONTEXT tspContext, TSS_HKEY hKey, TSS_HPOLICY hPolicy, TSS_BOOL usesAuth, TPM_SIGN_INFO* signInfo, UINT32* sigLen, BYTE** sig) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_AUTH auth, *pAuth; TCS_KEY_HANDLE tcsKey; BYTE *ticks = NULL; UINT32 tickLen; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; /* return immediately if we're not in a transport session */ if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED)) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKey))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned); result |= Trspi_Hash_NONCE(&hashCtx, signInfo->replay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest))) goto done; if (usesAuth) { if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_ReleaseTransportSigned, hPolicy, FALSE, &digest, &auth))) goto done; pAuth = &auth; } else pAuth = NULL; /* continue the auth session established in obj_context_transport_establish */ HMAC_Auth(context->transSecret.authData.authdata, digest.digest, &context->transAuth); if ((result = RPC_ReleaseTransportSigned(tspContext, tcsKey, &signInfo->replay, pAuth, &context->transAuth, &context->transLogOut.locality, &tickLen, &ticks, sigLen, sig))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned); result |= Trspi_Hash_UINT32(&hashCtx, context->transLogOut.locality); result |= Trspi_HashUpdate(&hashCtx, tickLen, ticks); result |= Trspi_Hash_UINT32(&hashCtx, *sigLen); result |= Trspi_HashUpdate(&hashCtx, *sigLen, *sig); if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest))) goto done_disabled; /* validate the return data using the key's auth */ if (pAuth) { if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) goto done_disabled; } /* validate again using the transport session's auth */ if ((result = validateReturnAuth(context->transSecret.authData.authdata, digest.digest, &context->transAuth))) { result = TSPERR(TSS_E_TSP_TRANS_AUTHFAIL); goto done_disabled; } if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { UINT64 offset; /* TPM Commands Spec step 6.b */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned); result |= Trspi_Hash_NONCE(&hashCtx, signInfo->replay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, context->transLogOut.parameters.digest))) goto done_disabled; /* TPM Commands Spec step 6.c */ offset = 0; Trspi_UnloadBlob_CURRENT_TICKS(&offset, ticks, &context->transLogOut.currentTicks); free(ticks); /* TPM Commands Spec step 6.d was set above */ /* TPM Commands Spec step 6.e */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut); if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) goto done_disabled; } if ((signInfo->data = malloc(sizeof(TPM_DIGEST))) == NULL) { LogError("malloc %zd bytes failed.", sizeof(TPM_DIGEST)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done_disabled; } memcpy(signInfo->data, context->transLogDigest.digest, sizeof(TPM_DIGEST)); signInfo->dataLen = sizeof(TPM_DIGEST); /* destroy all transport session info, except the key handle */ __tspi_memset(&context->transPub, 0, sizeof(TPM_TRANSPORT_PUBLIC)); __tspi_memset(&context->transMod, 0, sizeof(TPM_MODIFIER_INDICATOR)); __tspi_memset(&context->transSecret, 0, sizeof(TPM_TRANSPORT_AUTH)); __tspi_memset(&context->transAuth, 0, sizeof(TPM_AUTH)); __tspi_memset(&context->transLogIn, 0, sizeof(TPM_TRANSPORT_LOG_IN)); __tspi_memset(&context->transLogOut, 0, sizeof(TPM_TRANSPORT_LOG_OUT)); __tspi_memset(&context->transLogDigest, 0, sizeof(TPM_DIGEST)); done_disabled: context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED; done: obj_list_put(&context_list); return result; } #endif /* XXX change 0,1,2 to #defines */ TSS_RESULT obj_context_set_tpm_version(TSS_HCONTEXT tspContext, UINT32 ver) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; switch (ver) { case 1: context->flags &= ~TSS_CONTEXT_FLAGS_TPM_VERSION_MASK; context->flags |= TSS_CONTEXT_FLAGS_TPM_VERSION_1; break; case 2: context->flags &= ~TSS_CONTEXT_FLAGS_TPM_VERSION_MASK; context->flags |= TSS_CONTEXT_FLAGS_TPM_VERSION_2; break; default: LogError("Invalid TPM version set: %u", ver); result = TSPERR(TSS_E_INTERNAL_ERROR); break; } obj_list_put(&context_list); return result; } /* XXX change 0,1,2 to #defines */ TSS_RESULT obj_context_get_tpm_version(TSS_HCONTEXT tspContext, UINT32 *ver) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; if (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_1) *ver = 1; else if (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_2) *ver = 2; else *ver = 0; obj_list_put(&context_list); return TSS_SUCCESS; } TSS_RESULT obj_context_get_loadkey_ordinal(TSS_HCONTEXT tspContext, TPM_COMMAND_CODE *ordinal) { struct tsp_object *obj; struct tr_context_obj *context; if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); context = (struct tr_context_obj *)obj->data; switch (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_MASK) { case TSS_CONTEXT_FLAGS_TPM_VERSION_2: *ordinal = TPM_ORD_LoadKey2; break; default: LogDebugFn("No TPM version set!"); /* fall through */ case TSS_CONTEXT_FLAGS_TPM_VERSION_1: *ordinal = TPM_ORD_LoadKey; break; } obj_list_put(&context_list); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_selftest.c0000664000175000017510000000610013663651711017402 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_SelfTestFull(TSS_HCONTEXT tspContext) { TSS_RESULT result; TCS_HANDLE handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); return obj_context_transport_execute(tspContext, TPM_ORD_SelfTestFull, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); } TSS_RESULT Transport_CertifySelfTest(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen = 0; BYTE *dec = NULL; UINT64 offset; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; TCS_HANDLE *handles, handle; if ((result = obj_context_transport_init(tspContext))) return result; if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_CertifySelfTest, sizeof(TCPA_NONCE), antiReplay.nonce, &pubKeyHash, &handlesLen, &handles, privAuth, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, sigSize, dec); if ((*sig = malloc(*sigSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *sigSize); *sigSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *sigSize, dec, *sig); free(dec); return result; } TSS_RESULT Transport_GetTestResult(TSS_HCONTEXT tspContext, /* in */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; UINT32 decLen = 0; BYTE *dec = NULL; UINT64 offset; TCS_HANDLE handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetTestResult, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, outDataSize, dec); if ((*outData = malloc(*outDataSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *outDataSize); *outDataSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *outDataSize, dec, *outData); free(dec); return result; } #endif trousers-0.3.15/src/tspi/tsp_caps_tpm.c0000664000175000017510000001073613663651711017371 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" /* * This function provides a funnel through which all the TCSP_SetCapability requests can be * sent. This will keep the owner auth code from being duplicated around the TSP. */ TSS_RESULT TSP_SetCapability(TSS_HCONTEXT tspContext, TSS_HTPM hTPM, TSS_HPOLICY hTPMPolicy, TPM_CAPABILITY_AREA tcsCapArea, UINT32 subCap, TSS_BOOL value) { TSS_RESULT result; Trspi_HashCtx hashCtx; TPM_DIGEST digest; TPM_AUTH auth; subCap = endian32(subCap); result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_SetCapability); result |= Trspi_Hash_UINT32(&hashCtx, tcsCapArea); result |= Trspi_Hash_UINT32(&hashCtx, (UINT32)sizeof(UINT32)); result |= Trspi_HashUpdate(&hashCtx, (UINT32)sizeof(UINT32), (BYTE *)&subCap); result |= Trspi_Hash_UINT32(&hashCtx, (UINT32)sizeof(TSS_BOOL)); result |= Trspi_Hash_BOOL(&hashCtx, value); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_SetCapability, hTPMPolicy, FALSE, &digest, &auth))) return result; if ((result = TCS_API(tspContext)->SetCapability(tspContext, tcsCapArea, sizeof(UINT32), (BYTE *)&subCap, sizeof(TSS_BOOL), (BYTE *)&value, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_SetCapability); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; return obj_policy_validate_auth_oiap(hTPMPolicy, &digest, &auth); } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_GetTPMCapability(TSS_HCONTEXT tspContext, /* in */ TPM_CAPABILITY_AREA capArea, /* in */ UINT32 subCapLen, /* in */ BYTE* subCap, /* in */ UINT32* respLen, /* out */ BYTE** resp) /* out */ { TSS_RESULT result; UINT32 decLen = 0, dataLen; BYTE *dec = NULL; UINT64 offset; TCS_HANDLE handlesLen = 0; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = (2 * sizeof(UINT32)) + subCapLen; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, capArea, data); Trspi_LoadBlob_UINT32(&offset, subCapLen, data); Trspi_LoadBlob(&offset, subCapLen, data, subCap); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetCapability, dataLen, data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, respLen, dec); if ((*resp = malloc(*respLen)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *respLen); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *respLen, dec, *resp); free(dec); return result; } TSS_RESULT Transport_SetCapability(TSS_HCONTEXT tspContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 valueSize, /* in */ BYTE * value, /* in */ TPM_AUTH *ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 dataLen; UINT64 offset; TCS_HANDLE handlesLen = 0; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = (3 * sizeof(UINT32)) + subCapSize + valueSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, capArea, data); Trspi_LoadBlob_UINT32(&offset, subCapSize, data); Trspi_LoadBlob(&offset, subCapSize, data, subCap); Trspi_LoadBlob_UINT32(&offset, valueSize, data); Trspi_LoadBlob(&offset, valueSize, data, value); result = obj_context_transport_execute(tspContext, TPM_ORD_SetCapability, dataLen, data, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); free(data); return result; } #endif trousers-0.3.15/src/tspi/tsp_quote.c0000664000175000017510000000523113663651711016712 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_Quote(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE *antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig) /* out */ { TSS_RESULT result; UINT32 handlesLen, dataLen, decLen; TCS_HANDLE *handles, handle; BYTE *dec = NULL; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; dataLen = sizeof(TCPA_NONCE) + pcrDataSizeIn; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_NONCE(&offset, data, antiReplay); Trspi_LoadBlob(&offset, pcrDataSizeIn, data, pcrDataIn); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Quote, dataLen, data, &pubKeyHash, &handlesLen, &handles, privAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_PCR_COMPOSITE(&offset, dec, NULL); *pcrDataSizeOut = offset; if ((*pcrDataOut = malloc(*pcrDataSizeOut)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *pcrDataSizeOut); *pcrDataSizeOut = 0; return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_UnloadBlob(&offset, *pcrDataSizeOut, dec, *pcrDataOut); Trspi_UnloadBlob_UINT32(&offset, sigSize, dec); if ((*sig = malloc(*sigSize)) == NULL) { free(*pcrDataOut); *pcrDataOut = NULL; *pcrDataSizeOut = 0; free(dec); LogError("malloc of %u bytes failed", *sigSize); *sigSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *sigSize, dec, *sig); free(dec); return result; } #endif trousers-0.3.15/src/tspi/tsp_bind.c0000664000175000017510000000414413663651711016473 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_UnBind(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData) /* out */ { TSS_RESULT result; UINT32 handlesLen, dataLen, decLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; BYTE *dec, *data; UINT64 offset; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = keyHandle; handles = &handle; dataLen = sizeof(UINT32) + inDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, inDataSize, data); Trspi_LoadBlob(&offset, inDataSize, data, inData); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_UnBind, dataLen, data, &pubKeyHash, &handlesLen, &handles, privAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, outDataSize, dec); if ((*outData = malloc(*outDataSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *outDataSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *outDataSize, dec, *outData); free(dec); return TSS_SUCCESS; } #endif trousers-0.3.15/src/tspi/tspi_asn1.c0000664000175000017510000001443513663651711016576 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include #ifndef TSS_BUILD_ASN1_OPENSSL #include #endif #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "tsplog.h" #define TSS_OPENSSL_ASN1_ERROR (0xffffffff) #if (OPENSSL_VERSION_NUMBER >= 0x0090800FL) #define OPENSSL_COMPAT_CONST const #else #define OPENSSL_COMPAT_CONST #endif #define OPENSSL_COMPAT_ASN1_SEQUENCE(tname) \ static const ASN1_TEMPLATE tname##_seq_tt[] typedef struct tdTSS_BLOB { ASN1_INTEGER * structVersion; ASN1_INTEGER * blobType; ASN1_INTEGER * blobLength; ASN1_OCTET_STRING * blob; } TSS_BLOB; OPENSSL_COMPAT_ASN1_SEQUENCE(TSS_BLOB) = { ASN1_SIMPLE(TSS_BLOB, structVersion, ASN1_INTEGER), ASN1_SIMPLE(TSS_BLOB, blobType, ASN1_INTEGER), ASN1_SIMPLE(TSS_BLOB, blobLength, ASN1_INTEGER), ASN1_SIMPLE(TSS_BLOB, blob, ASN1_OCTET_STRING) } ASN1_SEQUENCE_END(TSS_BLOB) IMPLEMENT_ASN1_FUNCTIONS(TSS_BLOB) TSS_RESULT Tspi_EncodeDER_TssBlob(UINT32 rawBlobSize, /* in */ BYTE *rawBlob, /* in */ UINT32 blobType, /* in */ UINT32 *derBlobSize, /* in/out */ BYTE *derBlob) /* out */ { #ifdef TSS_BUILD_ASN1_OPENSSL TSS_BLOB *tssBlob = NULL; #endif BYTE *encBlob = NULL; UINT32 encBlobLen; if ((rawBlobSize == 0) || (rawBlob == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); if ((blobType < TSS_BLOB_TYPE_KEY) || (blobType > TSS_BLOB_TYPE_CMK_BYTE_STREAM)) return TSPERR(TSS_E_BAD_PARAMETER); if ((*derBlobSize != 0) && (derBlob == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); /* The TSS working group has stated that the ASN1 encoding will be done in a * specific way that generates an ASN1 encoding that is exactly 20 bytes * larger than the blob being encoded. * * OpenSSL uses the smallest number of bytes possible to encode and object * and as a result cannot be used to perform the encoding. The encoding * must be done manually. * * The 20 byte fixed header will result in issues for objects greater than * 2^16 in size since some fields are now limited to 16-bit lengths. */ #ifdef TSS_BUILD_ASN1_OPENSSL tssBlob = TSS_BLOB_new(); if (!tssBlob) return TSPERR(TSS_E_OUTOFMEMORY); if (ASN1_INTEGER_set(tssBlob->structVersion, TSS_BLOB_STRUCT_VERSION) == 0) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_OUTOFMEMORY); } if (ASN1_INTEGER_set(tssBlob->blobType, blobType) == 0) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_OUTOFMEMORY); } if (ASN1_INTEGER_set(tssBlob->blobLength, rawBlobSize) == 0) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_OUTOFMEMORY); } if (ASN1_OCTET_STRING_set(tssBlob->blob, rawBlob, rawBlobSize) == 0) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_OUTOFMEMORY); } encBlobLen = i2d_TSS_BLOB(tssBlob, &encBlob); if (encBlobLen <= 0) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_INTERNAL_ERROR); } if (*derBlobSize != 0) { if (encBlobLen <= *derBlobSize) { memcpy(derBlob, encBlob, encBlobLen); } else { OPENSSL_free(encBlob); TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_BAD_PARAMETER); } } *derBlobSize = encBlobLen; OPENSSL_free(encBlob); TSS_BLOB_free(tssBlob); #else if ((rawBlobSize + 16) > UINT16_MAX) return TSPERR(TSS_E_INTERNAL_ERROR); encBlobLen = rawBlobSize + 20; if (*derBlobSize != 0) { if (encBlobLen <= *derBlobSize) { UINT16 *pShort; UINT32 *pLong; encBlob = derBlob; encBlob[0] = 0x30; /* Sequence tag */ encBlob[1] = 0x82; /* Length in the two octets that follow */ encBlob += 2; pShort = (UINT16 *)encBlob; *pShort = htons(rawBlobSize + 16); encBlob += sizeof(UINT16); encBlob[0] = 0x02; /* Integer tag */ encBlob[1] = 0x01; /* Length is one */ encBlob[2] = (BYTE)TSS_BLOB_STRUCT_VERSION; encBlob += 3; encBlob[0] = 0x02; /* Integer tag */ encBlob[1] = 0x01; /* Length is one */ encBlob[2] = (BYTE)blobType; encBlob += 3; encBlob[0] = 0x02; /* Integer tag */ encBlob[1] = 0x04; /* Length is four */ encBlob += 2; pLong = (UINT32 *)encBlob; *pLong = htonl(rawBlobSize); encBlob += sizeof(UINT32); encBlob[0] = 0x04; /* Octet string tag */ encBlob[1] = 0x82; /* Length in the two octets that follow */ encBlob += 2; pShort = (UINT16 *)encBlob; *pShort = htons(rawBlobSize); encBlob += sizeof(UINT16); memcpy(encBlob, rawBlob, rawBlobSize); } else return TSPERR(TSS_E_BAD_PARAMETER); } *derBlobSize = encBlobLen; #endif return TSS_SUCCESS; } TSS_RESULT Tspi_DecodeBER_TssBlob(UINT32 berBlobSize, /* in */ BYTE *berBlob, /* in */ UINT32 *blobType, /* out */ UINT32 *rawBlobSize, /* in/out */ BYTE *rawBlob) /* out */ { TSS_BLOB *tssBlob = NULL; OPENSSL_COMPAT_CONST BYTE *encBlob = berBlob; UINT32 encBlobLen = berBlobSize; UINT32 decStructVersion, decBlobType, decBlobSize; if ((berBlobSize == 0) || (berBlob == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); if ((*rawBlobSize != 0) && (rawBlob == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); tssBlob = d2i_TSS_BLOB(NULL, &encBlob, encBlobLen); if (!tssBlob) return TSPERR(TSS_E_INTERNAL_ERROR); decStructVersion = ASN1_INTEGER_get(tssBlob->structVersion); if (decStructVersion == TSS_OPENSSL_ASN1_ERROR) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_INTERNAL_ERROR); } if (decStructVersion > TSS_BLOB_STRUCT_VERSION) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_BAD_PARAMETER); } decBlobType = ASN1_INTEGER_get(tssBlob->blobType); if (decBlobType == TSS_OPENSSL_ASN1_ERROR) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((decBlobType < TSS_BLOB_TYPE_KEY) || (decBlobType > TSS_BLOB_TYPE_CMK_BYTE_STREAM)) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_BAD_PARAMETER); } decBlobSize = ASN1_INTEGER_get(tssBlob->blobLength); if (decBlobSize == TSS_OPENSSL_ASN1_ERROR) { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_INTERNAL_ERROR); } if (*rawBlobSize != 0) { if (decBlobSize <= *rawBlobSize) { memcpy(rawBlob, tssBlob->blob->data, decBlobSize); } else { TSS_BLOB_free(tssBlob); return TSPERR(TSS_E_BAD_PARAMETER); } } *rawBlobSize = decBlobSize; *blobType = decBlobType; TSS_BLOB_free(tssBlob); return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_auth.c0000775000175000017510000010437213704255344016525 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "authsess.h" TSS_RESULT secret_PerformAuth_OIAP(TSS_HOBJECT hAuthorizedObject, UINT32 ulPendingFn, TSS_HPOLICY hPolicy, TSS_BOOL cas, /* continue auth session */ TCPA_DIGEST *hashDigest, TPM_AUTH *auth) { TSS_RESULT result; TSS_BOOL bExpired; UINT32 mode; TCPA_SECRET secret; TSS_HCONTEXT tspContext; TSS_RESULT (*OIAP)(TSS_HCONTEXT, TCS_AUTHHANDLE *, TPM_NONCE *); // XXX hack TSS_RESULT (*TerminateHandle)(TSS_HCONTEXT, TCS_HANDLE); // XXX hack /* This validates that the secret can be used */ if ((result = obj_policy_has_expired(hPolicy, &bExpired))) return result; if (bExpired == TRUE) return TSPERR(TSS_E_INVALID_OBJ_ACCESS); if ((result = obj_policy_get_tsp_context(hPolicy, &tspContext))) return result; if ((result = obj_policy_get_mode(hPolicy, &mode))) return result; if ((result = Init_AuthNonce(tspContext, cas, auth))) return result; /* XXX hack for opening a transport session */ if (cas) { OIAP = RPC_OIAP; TerminateHandle = RPC_TerminateHandle; } else { OIAP = TCS_API(tspContext)->OIAP; TerminateHandle = TCS_API(tspContext)->TerminateHandle; } /* added retry logic */ if ((result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven))) { if (result == TCPA_E_RESOURCES) { int retry = 0; do { /* POSIX sleep time, { secs, nanosecs } */ struct timespec t = { 0, AUTH_RETRY_NANOSECS }; nanosleep(&t, NULL); result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven); } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); } if (result) return result; } switch (mode) { case TSS_SECRET_MODE_CALLBACK: result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, TRUE, ulPendingFn, auth->fContinueAuthSession, 20, auth->NonceEven.nonce, auth->NonceOdd.nonce, NULL, NULL, 20, hashDigest->digest, (BYTE *)&auth->HMAC); break; case TSS_SECRET_MODE_SHA1: case TSS_SECRET_MODE_PLAIN: case TSS_SECRET_MODE_POPUP: if ((result = obj_policy_get_secret(hPolicy, TR_SECRET_CTX_NOT_NEW, &secret))) break; HMAC_Auth(secret.authdata, hashDigest->digest, auth); break; case TSS_SECRET_MODE_NONE: /* fall through */ default: result = TSPERR(TSS_E_POLICY_NO_SECRET); break; } if (result) { TerminateHandle(tspContext, auth->AuthHandle); return result; } return obj_policy_dec_counter(hPolicy); } #if 0 TSS_RESULT secret_PerformXOR_OSAP(TSS_HPOLICY hPolicy, TSS_HPOLICY hUsagePolicy, TSS_HPOLICY hMigrationPolicy, TSS_HOBJECT hOSAPObject, UINT16 osapType, UINT32 osapData, TCPA_ENCAUTH * encAuthUsage, TCPA_ENCAUTH * encAuthMig, BYTE *sharedSecret, TPM_AUTH * auth, TCPA_NONCE * nonceEvenOSAP) { TSS_BOOL bExpired; TCPA_SECRET keySecret; TCPA_SECRET usageSecret; TCPA_SECRET migSecret = { { 0, } }; UINT32 keyMode, usageMode, migMode = 0; TSS_RESULT result; TSS_HCONTEXT tspContext; if ((result = obj_policy_has_expired(hPolicy, &bExpired))) return result; if (bExpired == TRUE) return TSPERR(TSS_E_INVALID_OBJ_ACCESS); if ((result = obj_policy_has_expired(hUsagePolicy, &bExpired))) return result; if (bExpired == TRUE) return TSPERR(TSS_E_INVALID_OBJ_ACCESS); if (hMigrationPolicy) { if ((result = obj_policy_has_expired(hMigrationPolicy, &bExpired))) return result; if (bExpired == TRUE) return TSPERR(TSS_E_INVALID_OBJ_ACCESS); if ((result = obj_policy_get_mode(hMigrationPolicy, &migMode))) return result; } if ((result = obj_policy_get_tsp_context(hPolicy, &tspContext))) return result; if ((result = obj_policy_get_mode(hPolicy, &keyMode))) return result; if ((result = obj_policy_get_mode(hUsagePolicy, &usageMode))) return result; if (keyMode == TSS_SECRET_MODE_CALLBACK || usageMode == TSS_SECRET_MODE_CALLBACK || (hMigrationPolicy && migMode == TSS_SECRET_MODE_CALLBACK)) { if (keyMode != TSS_SECRET_MODE_CALLBACK || usageMode != TSS_SECRET_MODE_CALLBACK || (hMigrationPolicy && migMode != TSS_SECRET_MODE_CALLBACK)) return TSPERR(TSS_E_BAD_PARAMETER); } if (keyMode != TSS_SECRET_MODE_CALLBACK) { if ((result = obj_policy_get_secret(hPolicy, TR_SECRET_CTX_NOT_NEW, &keySecret))) return result; if ((result = obj_policy_get_secret(hUsagePolicy, TR_SECRET_CTX_NEW, &usageSecret))) return result; if (hMigrationPolicy) { if ((result = obj_policy_get_secret(hMigrationPolicy, TR_SECRET_CTX_NEW, &migSecret))) return result; } if ((result = OSAP_Calc(tspContext, osapType, osapData, keySecret.authdata, usageSecret.authdata, migSecret.authdata, encAuthUsage, encAuthMig, sharedSecret, auth))) return result; } else { /* If the secret mode is NONE here, we don't return an error. This is * because there are commands such as CreateKey, which require an auth * session even when creating no-auth keys. A secret of all 0's will be * used in this case. */ if ((result = TCS_API(tspContext)->OSAP(tspContext, osapType, osapData, &auth->NonceOdd, &auth->AuthHandle, &auth->NonceEven, nonceEvenOSAP))) return result; if ((result = obj_policy_do_xor(hPolicy, hOSAPObject, hPolicy, TRUE, 20, auth->NonceEven.nonce, NULL, nonceEvenOSAP->nonce, auth->NonceOdd.nonce, 20, encAuthUsage->authdata, encAuthMig->authdata))) { TCS_API(tspContext)->TerminateHandle(tspContext, auth->AuthHandle); return result; } } return TSS_SUCCESS; } TSS_RESULT secret_PerformAuth_OSAP(TSS_HOBJECT hAuthorizedObject, UINT32 ulPendingFn, TSS_HPOLICY hPolicy, TSS_HPOLICY hUsagePolicy, TSS_HPOLICY hMigPolicy, BYTE sharedSecret[20], TPM_AUTH *auth, BYTE *hashDigest, TCPA_NONCE *nonceEvenOSAP) { TSS_RESULT result; UINT32 keyMode, usageMode, migMode = 0; if ((result = obj_policy_get_mode(hPolicy, &keyMode))) return result; if ((result = obj_policy_get_mode(hUsagePolicy, &usageMode))) return result; if (hMigPolicy) { if ((result = obj_policy_get_mode(hMigPolicy, &migMode))) return result; } /* --- If any of them is a callback */ if (keyMode == TSS_SECRET_MODE_CALLBACK || usageMode == TSS_SECRET_MODE_CALLBACK || (hMigPolicy && migMode == TSS_SECRET_MODE_CALLBACK)) { /* --- And they're not all callback */ if (keyMode != TSS_SECRET_MODE_CALLBACK || usageMode != TSS_SECRET_MODE_CALLBACK || (hMigPolicy && migMode != TSS_SECRET_MODE_CALLBACK)) return TSPERR(TSS_E_BAD_PARAMETER); } if (keyMode == TSS_SECRET_MODE_CALLBACK) { if ((result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, TRUE, ulPendingFn, auth->fContinueAuthSession, 20, auth->NonceEven.nonce, NULL, nonceEvenOSAP->nonce, auth->NonceOdd.nonce, 20, hashDigest, (BYTE *)&auth->HMAC))) return result; } else { HMAC_Auth(sharedSecret, hashDigest, auth); } if ((result = obj_policy_dec_counter(hPolicy))) return result; if ((result = obj_policy_dec_counter(hUsagePolicy))) return result; if (hMigPolicy) { if ((result = obj_policy_dec_counter(hMigPolicy))) return result; } return TSS_SUCCESS; } TSS_RESULT secret_ValidateAuth_OSAP(TSS_HOBJECT hAuthorizedObject, UINT32 ulPendingFn, TSS_HPOLICY hPolicy, TSS_HPOLICY hUsagePolicy, TSS_HPOLICY hMigPolicy, BYTE sharedSecret[20], TPM_AUTH *auth, BYTE *hashDigest, TCPA_NONCE *nonceEvenOSAP) { TSS_RESULT result; UINT32 keyMode, usageMode, migMode = 0; if ((result = obj_policy_get_mode(hPolicy, &keyMode))) return result; if ((result = obj_policy_get_mode(hUsagePolicy, &usageMode))) return result; if (hMigPolicy) { if ((result = obj_policy_get_mode(hMigPolicy, &migMode))) return result; } /* --- If any of them is a callback */ if (keyMode == TSS_SECRET_MODE_CALLBACK || usageMode == TSS_SECRET_MODE_CALLBACK || (hMigPolicy && migMode == TSS_SECRET_MODE_CALLBACK)) { /* --- And they're not all callback */ if (keyMode != TSS_SECRET_MODE_CALLBACK || usageMode != TSS_SECRET_MODE_CALLBACK || (hMigPolicy && migMode != TSS_SECRET_MODE_CALLBACK)) return TSPERR(TSS_E_BAD_PARAMETER); } if (keyMode != TSS_SECRET_MODE_CALLBACK) { if (validateReturnAuth(sharedSecret, hashDigest, auth)) return TSPERR(TSS_E_TSP_AUTHFAIL); } else { if ((result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, FALSE, ulPendingFn, auth->fContinueAuthSession, 20, auth->NonceEven.nonce, NULL, nonceEvenOSAP->nonce, auth->NonceOdd.nonce, 20, hashDigest, (BYTE *)&auth->HMAC))) return result; } return TSS_SUCCESS; } #endif TSS_RESULT Init_AuthNonce(TSS_HCONTEXT tspContext, TSS_BOOL cas, TPM_AUTH * auth) { TSS_RESULT result; auth->fContinueAuthSession = cas; if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)auth->NonceOdd.nonce))) { LogError("Failed creating random nonce"); return TSPERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_BOOL validateReturnAuth(BYTE *secret, BYTE *hash, TPM_AUTH *auth) { BYTE digest[20]; /* auth is expected to have both nonces and the digest from the TPM */ memcpy(digest, &auth->HMAC, 20); HMAC_Auth(secret, hash, auth); return ((TSS_BOOL) (memcmp(digest, &auth->HMAC, 20) != 0)); } void HMAC_Auth(BYTE * secret, BYTE * Digest, TPM_AUTH * auth) { UINT64 offset; BYTE Blob[61]; offset = 0; Trspi_LoadBlob(&offset, 20, Blob, Digest); Trspi_LoadBlob(&offset, 20, Blob, auth->NonceEven.nonce); Trspi_LoadBlob(&offset, 20, Blob, auth->NonceOdd.nonce); Blob[offset++] = auth->fContinueAuthSession; Trspi_HMAC(TSS_HASH_SHA1, 20, secret, offset, Blob, (BYTE *)&auth->HMAC); } TSS_RESULT OSAP_Calc(TSS_HCONTEXT tspContext, UINT16 EntityType, UINT32 EntityValue, BYTE * authSecret, BYTE * usageSecret, BYTE * migSecret, TCPA_ENCAUTH * encAuthUsage, TCPA_ENCAUTH * encAuthMig, BYTE * sharedSecret, TPM_AUTH * auth) { TSS_RESULT rc; TCPA_NONCE nonceEvenOSAP; UINT64 offset; BYTE hmacBlob[0x200]; BYTE hashBlob[0x200]; BYTE xorUsageAuth[20]; BYTE xorMigAuth[20]; UINT32 i; if ((rc = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)auth->NonceOdd.nonce))) { LogError("Failed creating random nonce"); return TSPERR(TSS_E_INTERNAL_ERROR); } auth->fContinueAuthSession = 0x00; if ((rc = TCS_API(tspContext)->OSAP(tspContext, EntityType, EntityValue, &auth->NonceOdd, &auth->AuthHandle, &auth->NonceEven, &nonceEvenOSAP))) { if (rc == TCPA_E_RESOURCES) { int retry = 0; do { /* POSIX sleep time, { secs, nanosecs } */ struct timespec t = { 0, AUTH_RETRY_NANOSECS }; nanosleep(&t, NULL); rc = TCS_API(tspContext)->OSAP(tspContext, EntityType, EntityValue, &auth->NonceOdd, &auth->AuthHandle, &auth->NonceEven, &nonceEvenOSAP); } while (rc == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); } if (rc) return rc; } offset = 0; Trspi_LoadBlob(&offset, 20, hmacBlob, nonceEvenOSAP.nonce); Trspi_LoadBlob(&offset, 20, hmacBlob, auth->NonceOdd.nonce); Trspi_HMAC(TSS_HASH_SHA1, 20, authSecret, offset, hmacBlob, sharedSecret); offset = 0; Trspi_LoadBlob(&offset, 20, hashBlob, sharedSecret); Trspi_LoadBlob(&offset, 20, hashBlob, auth->NonceEven.nonce); if ((rc = Trspi_Hash(TSS_HASH_SHA1, offset, hashBlob, xorUsageAuth))) return rc; offset = 0; Trspi_LoadBlob(&offset, 20, hashBlob, sharedSecret); Trspi_LoadBlob(&offset, 20, hashBlob, auth->NonceOdd.nonce); if ((rc = Trspi_Hash(TSS_HASH_SHA1, offset, hashBlob, xorMigAuth))) return rc; for (i = 0; i < sizeof(TCPA_ENCAUTH); i++) encAuthUsage->authdata[i] = usageSecret[i] ^ xorUsageAuth[i]; for (i = 0; i < sizeof(TCPA_ENCAUTH); i++) encAuthMig->authdata[i] = migSecret[i] ^ xorMigAuth[i]; return TSS_SUCCESS; } TSS_RESULT obj_policy_validate_auth_oiap(TSS_HPOLICY hPolicy, TCPA_DIGEST *hashDigest, TPM_AUTH *auth) { TSS_RESULT result = TSS_SUCCESS; struct tsp_object *obj; struct tr_policy_obj *policy; BYTE wellKnown[TCPA_SHA1_160_HASH_LEN] = TSS_WELL_KNOWN_SECRET; if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); policy = (struct tr_policy_obj *)obj->data; switch (policy->SecretMode) { case TSS_SECRET_MODE_CALLBACK: result = policy->Tspicb_CallbackHMACAuth( policy->hmacAppData, hPolicy, 0, auth->fContinueAuthSession, FALSE, 20, auth->NonceEven.nonce, auth->NonceOdd.nonce, NULL, NULL, 20, hashDigest->digest, (BYTE *)&auth->HMAC); break; case TSS_SECRET_MODE_SHA1: case TSS_SECRET_MODE_PLAIN: case TSS_SECRET_MODE_POPUP: if (validateReturnAuth(policy->Secret, hashDigest->digest, auth)) result = TSPERR(TSS_E_TSP_AUTHFAIL); break; case TSS_SECRET_MODE_NONE: if (validateReturnAuth(wellKnown, hashDigest->digest, auth)) result = TSPERR(TSS_E_TSP_AUTHFAIL); break; default: result = TSPERR(TSS_E_POLICY_NO_SECRET); break; } obj_list_put(&policy_list); return result; } #if 0 TSS_RESULT authsess_oiap_get(TSS_HOBJECT obj, TPM_COMMAND_CODE ord, TPM_DIGEST *digest, TPM_AUTH *auth) { TSS_RESULT result = TSS_SUCCESS; TSS_BOOL bExpired; UINT32 mode; TPM_SECRET secret; TSS_HCONTEXT tspContext; TSS_RESULT (*OIAP)(TSS_HCONTEXT, TCS_AUTHHANDLE *, TPM_NONCE *); // XXX hack TSS_RESULT (*TerminateHandle)(TSS_HCONTEXT, TCS_HANDLE); // XXX hack if (obj_is_tpm(obj)) result = obj_tpm_get_tsp_context(obj, hContext); else if (obj_is_rsakey(obj)) result = obj_rsakey_get_tsp_context(obj, hContext); else if (obj_is_encdata(obj)) result = obj_encdata_get_tsp_context(obj, hContext); else if (obj_is_nvstore(obj)) result = obj_nvstore_get_tsp_context(obj, hContext); else result = TSPERR(TSS_E_INVALID_HANDLE); #if 0 /* This validates that the secret can be used */ if ((result = obj_policy_has_expired(hPolicy, &bExpired))) return result; if (bExpired == TRUE) return TSPERR(TSS_E_INVALID_OBJ_ACCESS); if ((result = obj_policy_get_tsp_context(hPolicy, &tspContext))) return result; if ((result = obj_policy_get_mode(hPolicy, &mode))) return result; #else if ((result = obj_policy_get_authsess_params())) return result; #endif if ((result = Init_AuthNonce(tspContext, cas, auth))) return result; /* XXX hack for opening a transport session */ if (cas) { OIAP = RPC_OIAP; TerminateHandle = RPC_TerminateHandle; } else { OIAP = TCS_API(tspContext)->OIAP; TerminateHandle = TCS_API(tspContext)->TerminateHandle; } /* added retry logic */ if ((result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven))) { if (result == TCPA_E_RESOURCES) { int retry = 0; do { /* POSIX sleep time, { secs, nanosecs } */ struct timespec t = { 0, AUTH_RETRY_NANOSECS }; nanosleep(&t, NULL); result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven); } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); } if (result) return result; } switch (mode) { case TSS_SECRET_MODE_CALLBACK: result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, TRUE, ulPendingFn, auth->fContinueAuthSession, 20, auth->NonceEven.nonce, auth->NonceOdd.nonce, NULL, NULL, 20, hashDigest->digest, (BYTE *)&auth->HMAC); break; case TSS_SECRET_MODE_SHA1: case TSS_SECRET_MODE_PLAIN: case TSS_SECRET_MODE_POPUP: if ((result = obj_policy_get_secret(hPolicy, TR_SECRET_CTX_NOT_NEW, &secret))) break; HMAC_Auth(secret.authdata, hashDigest->digest, auth); break; case TSS_SECRET_MODE_NONE: /* fall through */ default: result = TSPERR(TSS_E_POLICY_NO_SECRET); break; } if (result) { TerminateHandle(tspContext, auth->AuthHandle); return result; } return obj_policy_dec_counter(hPolicy); } TSS_RESULT authsess_oiap_put(TPM_AUTH *auth) { } #endif #ifdef TSS_BUILD_DELEGATION TSS_RESULT authsess_do_dsap(struct authsess *sess) { TSS_RESULT result; if ((result = TCS_API(sess->tspContext)->DSAP(sess->tspContext, sess->entity_type, sess->obj_parent, &sess->nonceOddxSAP, sess->entityValueSize, sess->entityValue, &sess->pAuth->AuthHandle, &sess->pAuth->NonceEven, &sess->nonceEvenxSAP))) { if (result == TCPA_E_RESOURCES) { int retry = 0; do { /* POSIX sleep time, { secs, nanosecs } */ struct timespec t = { 0, AUTH_RETRY_NANOSECS }; nanosleep(&t, NULL); result = TCS_API(sess->tspContext)->DSAP(sess->tspContext, sess->entity_type, sess->obj_parent, &sess->nonceOddxSAP, sess->entityValueSize, sess->entityValue, &sess->pAuth->AuthHandle, &sess->pAuth->NonceEven, &sess->nonceEvenxSAP); } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); } } return result; } #endif TSS_RESULT authsess_do_osap(struct authsess *sess) { TSS_RESULT result; if ((result = TCS_API(sess->tspContext)->OSAP(sess->tspContext, sess->entity_type, sess->obj_parent, &sess->nonceOddxSAP, &sess->pAuth->AuthHandle, &sess->pAuth->NonceEven, &sess->nonceEvenxSAP))) { if (result == TCPA_E_RESOURCES) { int retry = 0; do { /* POSIX sleep time, { secs, nanosecs } */ struct timespec t = { 0, AUTH_RETRY_NANOSECS }; nanosleep(&t, NULL); result = TCS_API(sess->tspContext)->OSAP(sess->tspContext, sess->entity_type, sess->obj_parent, &sess->nonceOddxSAP, &sess->pAuth->AuthHandle, &sess->pAuth->NonceEven, &sess->nonceEvenxSAP); } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); } } return result; } TSS_RESULT authsess_callback_xor(PVOID lpAppData, TSS_HOBJECT hOSAPObject, TSS_HOBJECT hObject, TSS_FLAG PurposeSecret, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulSizeEncAuth, BYTE *rgbEncAuthUsage, BYTE *rgbEncAuthMigration) { TSS_RESULT result; BYTE xorUseAuth[sizeof(TPM_DIGEST)]; BYTE xorMigAuth[sizeof(TPM_DIGEST)]; Trspi_HashCtx hashCtx; UINT32 i; struct authsess *sess = (struct authsess *)lpAppData; /* sess->sharedSecret was calculated in authsess_xsap_init */ result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_SECRET(&hashCtx, sess->sharedSecret.digest); result |= Trspi_Hash_NONCE(&hashCtx, rgbNonceEven); if ((result |= Trspi_HashFinal(&hashCtx, xorUseAuth))) return result; for (i = 0; i < ulSizeEncAuth; i++) rgbEncAuthUsage[i] ^= xorUseAuth[i]; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_SECRET(&hashCtx, sess->sharedSecret.digest); result |= Trspi_Hash_NONCE(&hashCtx, rgbNonceOdd); if ((result |= Trspi_HashFinal(&hashCtx, xorMigAuth))) return result; for (i = 0; i < ulSizeEncAuth; i++) rgbEncAuthMigration[i] ^= xorMigAuth[i]; return TSS_SUCCESS; } TSS_RESULT authsess_callback_hmac(PVOID lpAppData, TSS_HOBJECT hAuthorizedObject, TSS_BOOL ReturnOrVerify, UINT32 ulPendingFunction, TSS_BOOL ContinueUse, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulSizeDigestHmac, BYTE *rgbParamDigest, BYTE *rgbHmacData) { struct authsess *sess = (struct authsess *)lpAppData; TSS_RESULT result = TSS_SUCCESS; UINT64 offset; BYTE Blob[61]; offset = 0; Trspi_LoadBlob(&offset, ulSizeDigestHmac, Blob, rgbParamDigest); Trspi_LoadBlob(&offset, ulSizeNonces, Blob, rgbNonceEven); Trspi_LoadBlob(&offset, ulSizeNonces, Blob, rgbNonceOdd); Blob[offset++] = ContinueUse; if (ReturnOrVerify) { Trspi_HMAC(TSS_HASH_SHA1, ulSizeDigestHmac, sess->sharedSecret.digest, offset, Blob, rgbHmacData); } else { TPM_HMAC hmacVerify; Trspi_HMAC(TSS_HASH_SHA1, ulSizeDigestHmac, sess->sharedSecret.digest, offset, Blob, hmacVerify.digest); result = memcmp(rgbHmacData, hmacVerify.digest, ulSizeDigestHmac); if (result) result = TPM_E_AUTHFAIL; } return result; } /* Create an OSAP session. @requirements is used in different ways depending on the command to * indicate whether we should require a policy or auth value */ TSS_RESULT authsess_xsap_init(TSS_HCONTEXT tspContext, TSS_HOBJECT obj_parent, TSS_HOBJECT obj_child, TSS_BOOL requirements, TPM_COMMAND_CODE command, TPM_ENTITY_TYPE entity_type, struct authsess **xsess) { TSS_RESULT result; TSS_BOOL authdatausage = FALSE, req_auth = TRUE, get_child_auth = TRUE, secret_set = FALSE; BYTE hmacBlob[2 * sizeof(TPM_DIGEST)]; UINT64 offset; TSS_BOOL new_secret = TR_SECRET_CTX_NOT_NEW; struct authsess *sess; if ((sess = calloc(1, sizeof(struct authsess))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(struct authsess)); return TSPERR(TSS_E_OUTOFMEMORY); } switch (command) { /* Parent is Key for the cases below */ case TPM_ORD_Delegate_CreateKeyDelegation: case TPM_ORD_CreateWrapKey: case TPM_ORD_CMK_CreateKey: case TPM_ORD_Seal: case TPM_ORD_Sealx: case TPM_ORD_Unseal: case TPM_ORD_ChangeAuth: if ((result = obj_rsakey_get_policy(obj_parent, TSS_POLICY_USAGE, &sess->hUsageParent, NULL))) goto error; break; /* Parent is TPM for the cases below */ case TPM_ORD_Delegate_CreateOwnerDelegation: req_auth = FALSE; /* fall through */ case TPM_ORD_MakeIdentity: case TPM_ORD_NV_DefineSpace: if ((result = obj_tpm_get_policy(obj_parent, TSS_POLICY_USAGE, &sess->hUsageParent))) goto error; break; case TPM_ORD_ChangeAuthOwner: /* Special case, ChangeAuthOwner is used to change Owner and SRK auth */ if (obj_is_rsakey(obj_parent)) { if ((result = obj_rsakey_get_policy(obj_parent, TSS_POLICY_USAGE, &sess->hUsageParent, NULL))) goto error; } else { if ((result = obj_tpm_get_policy(obj_parent, TSS_POLICY_USAGE, &sess->hUsageParent))) goto error; } break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } if (requirements && !sess->hUsageParent) { result = TSPERR(TSS_E_TSP_AUTHREQUIRED); goto error; } if (sess->hUsageParent) { /* These are trousers callback functions which will be used to process the auth * session. If the policy type is callback for hUsageParent, they will be * overwritten by the application defined callback functions in the policy */ sess->cb_xor.callback = authsess_callback_xor; sess->cb_xor.appData = (PVOID)sess; sess->cb_hmac.callback = authsess_callback_hmac; sess->cb_hmac.appData = (PVOID)sess; /* XXX the parent object doesn't always hold the callbacks */ if ((result = obj_policy_get_xsap_params(sess->hUsageParent, command, &sess->entity_type, &sess->entityValueSize, &sess->entityValue, sess->parentSecret.authdata, &sess->cb_xor, &sess->cb_hmac, NULL, &sess->parentMode, new_secret))) goto error; } else sess->parentMode = TSS_SECRET_MODE_NONE; switch (command) { /* Child is a Key object */ case TPM_ORD_CreateWrapKey: case TPM_ORD_CMK_CreateKey: if ((result = obj_rsakey_get_policies(obj_child, &sess->hUsageChild, &sess->hMigChild, &authdatausage))) goto error; if (authdatausage && !sess->hUsageChild) { result = TSPERR(TSS_E_TSP_AUTHREQUIRED); goto error; } if (obj_rsakey_is_migratable(obj_child)) { if (!sess->hMigChild) { result = TSPERR(TSS_E_KEY_NO_MIGRATION_POLICY); goto error; } if ((result = obj_policy_get_xsap_params(sess->hMigChild, 0, NULL, NULL, NULL, sess->encAuthMig.authdata, NULL, NULL, NULL, &sess->mMode, new_secret))) goto error; } if ((result = obj_rsakey_get_tcs_handle(obj_parent, &sess->obj_parent))) goto error; break; /* Child is an Encdata object */ case TPM_ORD_Unseal: #ifdef TSS_BUILD_SEALX case TPM_ORD_Sealx: /* These may be overwritten down below, when obj_policy_get_xsap_params is called * on the child usage policy */ sess->cb_sealx.callback = sealx_mask_cb; sess->cb_sealx.appData = (PVOID)sess; /* fall through */ #endif case TPM_ORD_Seal: if ((result = obj_encdata_get_policy(obj_child, TSS_POLICY_USAGE, &sess->hUsageChild))) goto error; if ((result = obj_rsakey_get_tcs_handle(obj_parent, &sess->obj_parent))) goto error; break; #ifdef TSS_BUILD_NV /* Child is an NV object */ case TPM_ORD_NV_DefineSpace: /* The requirements variable tells us whether nv object auth is required */ req_auth = requirements; if (req_auth) { if (sess->parentMode == TSS_SECRET_MODE_NONE) { result = TSPERR(TSS_E_TSP_AUTHREQUIRED); goto error; } if ((result = obj_nvstore_get_policy(obj_child, TSS_POLICY_USAGE, &sess->hUsageChild))) goto error; /* According to the spec, we must fall back on the TSP context's policy for * auth if none is set in the NV object */ if (!sess->hUsageChild) { if ((result = obj_context_get_policy(tspContext, TSS_POLICY_USAGE, &sess->hUsageChild))) goto error; } if ((result = obj_policy_is_secret_set(sess->hUsageChild, &secret_set))) goto error; if (!secret_set) { result = TSPERR(TSS_E_TSP_AUTHREQUIRED); goto error; } } else { /* In this case, the TPM is owned, but we're creating a no-auth NV area */ get_child_auth = FALSE; } break; #endif /* Child is a Key object */ case TPM_ORD_MakeIdentity: if ((result = obj_rsakey_get_policy(obj_child, TSS_POLICY_USAGE, &sess->hUsageChild, NULL))) goto error; break; /* Child is a Policy object */ case TPM_ORD_Delegate_CreateKeyDelegation: case TPM_ORD_ChangeAuth: if ((result = obj_rsakey_get_tcs_handle(obj_parent, &sess->obj_parent))) goto error; /* fall through */ case TPM_ORD_Delegate_CreateOwnerDelegation: case TPM_ORD_ChangeAuthOwner: sess->hUsageChild = obj_child; new_secret = TR_SECRET_CTX_NEW; break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } /* If req_auth is FALSE here, we don't actually need to set up an auth session, so returning * is OK. At this point, authsess->pAuth is NULL, so the TCS API will not get any * authdata. */ if (req_auth == FALSE && sess->parentMode == TSS_SECRET_MODE_NONE) goto done; if (get_child_auth) { if ((result = obj_policy_get_xsap_params(sess->hUsageChild, 0, 0, NULL, NULL, sess->encAuthUse.authdata, NULL, NULL, &sess->cb_sealx, &sess->uMode, new_secret))) goto error; } if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)sess->nonceOddxSAP.nonce))) goto error; sess->obj_child = obj_child; sess->tspContext = tspContext; sess->pAuth = &sess->auth; sess->command = command; #ifdef TSS_BUILD_DELEGATION /* if entityValue is set, we have a custom entity, i.e. delegation blob or row */ if (sess->entityValue) { /* DSAP's entity type was pulled from the policy in the authsess_xsap_init call * above */ if ((result = authsess_do_dsap(sess))) goto error; } #endif if (!sess->entityValue) { sess->entity_type = entity_type; if ((result = authsess_do_osap(sess))) goto error; } if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), (BYTE **)sess->auth.NonceOdd.nonce))) goto error; /* We have both OSAP nonces, so calculate the shared secret if we're responsible for it */ if (sess->parentMode != TSS_SECRET_MODE_CALLBACK) { offset = 0; Trspi_LoadBlob(&offset, sizeof(TPM_NONCE), hmacBlob, sess->nonceEvenxSAP.nonce); Trspi_LoadBlob(&offset, sizeof(TPM_NONCE), hmacBlob, sess->nonceOddxSAP.nonce); if ((result = Trspi_HMAC(TSS_HASH_SHA1, sizeof(TPM_ENCAUTH), sess->parentSecret.authdata, offset, hmacBlob, sess->sharedSecret.digest))) goto error; } /* XXX What does a PurposeSecret of TRUE mean here? */ if ((result = ((TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_HOBJECT, TSS_FLAG, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *))sess->cb_xor.callback)(sess->cb_xor.appData, sess->hUsageParent, sess->hUsageChild, TRUE, sizeof(TPM_DIGEST), sess->auth.NonceEven.nonce, sess->auth.NonceOdd.nonce, sess->nonceEvenxSAP.nonce, sess->nonceOddxSAP.nonce, sizeof(TPM_ENCAUTH), sess->encAuthUse.authdata, sess->encAuthMig.authdata))) return result; done: *xsess = sess; return TSS_SUCCESS; error: free(sess); return result; } TSS_RESULT authsess_xsap_hmac(struct authsess *sess, TPM_DIGEST *digest) { TSS_RESULT result; /* If no auth session was established using this authsess object, return success */ if (!sess->pAuth) return TSS_SUCCESS; /* XXX Placeholder for future continueAuthSession support: * conditionally bump NonceOdd if continueAuthSession == TRUE here */ if ((result = ((TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_BOOL, UINT32, TSS_BOOL, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *))sess->cb_hmac.callback)(sess->cb_hmac.appData, sess->hUsageParent, TRUE, sess->command, sess->auth.fContinueAuthSession, sizeof(TPM_NONCE), sess->auth.NonceEven.nonce, sess->auth.NonceOdd.nonce, sess->nonceEvenxSAP.nonce, sess->nonceOddxSAP.nonce, sizeof(TPM_DIGEST), digest->digest, sess->auth.HMAC.authdata))) return result; if (sess->hUsageParent) obj_policy_dec_counter(sess->hUsageParent); if (sess->hUsageChild) obj_policy_dec_counter(sess->hUsageChild); if (sess->hMigChild) obj_policy_dec_counter(sess->hMigChild); return TSS_SUCCESS; } TSS_RESULT authsess_xsap_verify(struct authsess *sess, TPM_DIGEST *digest) { /* If no auth session was established using this authsess object, return success */ if (!sess->pAuth) return TSS_SUCCESS; return ((TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_BOOL, UINT32, TSS_BOOL, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *))sess->cb_hmac.callback)(sess->cb_hmac.appData, sess->hUsageParent, FALSE, sess->command, sess->auth.fContinueAuthSession, sizeof(TPM_NONCE), sess->auth.NonceEven.nonce, sess->auth.NonceOdd.nonce, sess->nonceEvenxSAP.nonce, sess->nonceOddxSAP.nonce, sizeof(TPM_DIGEST), digest->digest, sess->auth.HMAC.authdata); } TSS_RESULT __tspi_free_resource(TSS_HCONTEXT tspContext, UINT32 handle, UINT32 resourceType) { TSS_RESULT result = TSS_SUCCESS; #ifdef TSS_BUILD_TSS12 UINT32 version = 0; if ((result = obj_context_get_tpm_version(tspContext, &version))) return result; if (version == 2) { return TCS_API(tspContext)->FlushSpecific(tspContext, handle, resourceType); } #endif switch (resourceType) { case TPM_RT_KEY: result = TCS_API(tspContext)->EvictKey(tspContext, handle); break; case TPM_RT_AUTH: result = TCS_API(tspContext)->TerminateHandle(tspContext, handle); break; default: LogDebugFn("Trying to free TPM 1.2 resource type 0x%x on 1.1 TPM!", resourceType); result = TSPERR(TSS_E_INTERNAL_ERROR); break; } return result; } void authsess_free(struct authsess *xsap) { if (xsap) { if (xsap->auth.AuthHandle && xsap->auth.fContinueAuthSession) (void)__tspi_free_resource(xsap->tspContext, xsap->auth.AuthHandle, TPM_RT_AUTH); free(xsap->entityValue); free(xsap); xsap = NULL; } } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_OIAP(TSS_HCONTEXT tspContext, /* in */ TCS_AUTHHANDLE* authHandle, /* out */ TPM_NONCE* nonce0) /* out */ { TSS_RESULT result; UINT32 decLen = 0; BYTE *dec = NULL; UINT64 offset; TCS_HANDLE handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_OIAP, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; if (decLen != sizeof(TCS_AUTHHANDLE) + sizeof(TPM_NONCE)) return TSPERR(TSS_E_INTERNAL_ERROR); offset = 0; Trspi_UnloadBlob_UINT32(&offset, authHandle, dec); Trspi_UnloadBlob_NONCE(&offset, dec, nonce0); return result; } TSS_RESULT Transport_OSAP(TSS_HCONTEXT tspContext, /* in */ TPM_ENTITY_TYPE entityType, /* in */ UINT32 entityValue, /* in */ TPM_NONCE* nonceOddOSAP, /* in */ TCS_AUTHHANDLE* authHandle, /* out */ TPM_NONCE* nonceEven, /* out */ TPM_NONCE* nonceEvenOSAP) /* out */ { TSS_RESULT result; UINT32 decLen = 0; BYTE *dec = NULL; UINT64 offset; TCS_HANDLE handlesLen = 0; BYTE data[sizeof(UINT16) + sizeof(UINT32) + sizeof(TPM_NONCE)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT16(&offset, entityType, data); Trspi_LoadBlob_UINT32(&offset, entityValue, data); Trspi_LoadBlob_NONCE(&offset, data, nonceOddOSAP); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_OSAP, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, authHandle, dec); Trspi_UnloadBlob_NONCE(&offset, dec, nonceEven); Trspi_UnloadBlob_NONCE(&offset, dec, nonceEvenOSAP); return TSS_SUCCESS; } TSS_RESULT Transport_TerminateHandle(TSS_HCONTEXT tspContext, /* in */ TCS_AUTHHANDLE handle) /* in */ { TSS_RESULT result; TCS_HANDLE handlesLen = 0, *handles, *handles_track; /* Call ExecuteTransport */ handlesLen = 1; if ((handles = malloc(sizeof(TCS_HANDLE))) == NULL) { LogError("malloc of %zd bytes failed", sizeof(TCS_HANDLE)); return TSPERR(TSS_E_OUTOFMEMORY); } *handles = handle; handles_track = handles; // Since the call tree of this function can possibly alloc memory // (check RPC_ExecuteTransport_TP function), its better to keep track of // the handle. result = obj_context_transport_execute(tspContext, TPM_ORD_Terminate_Handle, 0, NULL, NULL, &handlesLen, &handles, NULL, NULL, NULL, NULL); if (handles != handles_track) free(handles); free(handles_track); return result; } #endif trousers-0.3.15/src/tspi/ps/0000775000175000017510000000000013663651711015144 5ustar deboradeboratrousers-0.3.15/src/tspi/ps/ps_utils.c0000664000175000017510000000217413663651711017156 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "spi_utils.h" #include "tspps.h" #include "tsplog.h" TSS_RESULT read_data(int fd, void *data, UINT32 size) { int rc; rc = read(fd, data, size); if (rc == -1) { LogError("read of %d bytes: %s", size, strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } else if ((unsigned)rc != size) { LogError("read of %d bytes (only %d read)", size, rc); return TSPERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT write_data(int fd, void *data, UINT32 size) { int rc; rc = write(fd, data, size); if (rc == -1) { LogError("write of %d bytes: %s", size, strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } else if ((unsigned)rc != size) { LogError("write of %d bytes (only %d written)", size, rc); return TSPERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } trousers-0.3.15/src/tspi/ps/tspps.c0000664000175000017510000007727513663651711016503 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (HAVE_BYTEORDER_H) #include #elif defined(HTOLE_DEFINED) #ifndef __APPLE__ #include #else #include "portable_endian.h" #endif #define LE_16 htole16 #define LE_32 htole32 #define LE_64 htole64 #else #define LE_16(x) (x) #define LE_32(x) (x) #define LE_64(x) (x) #endif #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "spi_utils.h" #include "tspps.h" #include "tsplog.h" static int user_ps_fd = -1; static MUTEX_DECLARE_INIT(user_ps_lock); #if (defined (__FreeBSD__) || defined (__OpenBSD__)) static MUTEX_DECLARE_INIT(user_ps_path); #endif static struct flock fl; /* * Determine the default path to the persistent storage file and create it if it doesn't exist. */ TSS_RESULT get_user_ps_path(char **file) { TSS_RESULT result; char *file_name = NULL, *home_dir = NULL; struct passwd *pwp; #if (defined (__linux) || defined (linux) || defined(__GLIBC__)) struct passwd pw; #endif struct stat stat_buf; char buf[PASSWD_BUFSIZE]; uid_t euid; int rc; if ((file_name = getenv("TSS_USER_PS_FILE"))) { *file = strdup(file_name); return (*file) ? TSS_SUCCESS : TSPERR(TSS_E_OUTOFMEMORY); } #if (defined (__FreeBSD__) || defined (__OpenBSD__)) MUTEX_LOCK(user_ps_path); #endif euid = geteuid(); #if defined (SOLARIS) /* * Solaris keeps user PS in a local directory instead of * in the user's home directory, which may be shared * by multiple systems. * * The directory path on Solaris is /var/tpm/userps/[EUID]/ */ rc = snprintf(buf, sizeof (buf), "%s/%d", TSS_USER_PS_DIR, euid); #else setpwent(); while (1) { #if (defined (__linux) || defined (linux) || defined(__GLIBC__)) rc = getpwent_r(&pw, buf, PASSWD_BUFSIZE, &pwp); if (rc) { LogDebugFn("USER PS: Error getting path to home directory: getpwent_r: %s", strerror(rc)); endpwent(); return TSPERR(TSS_E_INTERNAL_ERROR); } #elif (defined (__FreeBSD__) || defined (__OpenBSD__)) if ((pwp = getpwent()) == NULL) { LogDebugFn("USER PS: Error getting path to home directory: getpwent: %s", strerror(rc)); endpwent(); MUTEX_UNLOCK(user_ps_path); return TSPERR(TSS_E_INTERNAL_ERROR); } #endif if (euid == pwp->pw_uid) { home_dir = strdup(pwp->pw_dir); break; } } endpwent(); if (!home_dir) return TSPERR(TSS_E_OUTOFMEMORY); /* Tack on TSS_USER_PS_DIR and see if it exists */ rc = snprintf(buf, sizeof (buf), "%s/%s", home_dir, TSS_USER_PS_DIR); #endif /* SOLARIS */ if (rc == sizeof (buf)) { LogDebugFn("USER PS: Path to file too long! (> %d bytes)", PASSWD_BUFSIZE); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } errno = 0; if ((rc = stat(buf, &stat_buf)) == -1) { if (errno == ENOENT) { errno = 0; /* Create the user's ps directory if it is not there. */ if ((rc = mkdir(buf, 0700)) == -1) { LogDebugFn("USER PS: Error creating dir: %s: %s", buf, strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } else { LogDebugFn("USER PS: Error stating dir: %s: %s", buf, strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } /* Directory exists or has been created, return the path to the file */ #if defined (SOLARIS) rc = snprintf(buf, sizeof (buf), "%s/%d/%s", TSS_USER_PS_DIR, euid, TSS_USER_PS_FILE); #else rc = snprintf(buf, sizeof (buf), "%s/%s/%s", home_dir, TSS_USER_PS_DIR, TSS_USER_PS_FILE); #endif if (rc == sizeof (buf)) { LogDebugFn("USER PS: Path to file too long! (> %zd bytes)", sizeof (buf)); } else *file = strdup(buf); result = (*file) ? TSS_SUCCESS : TSPERR(TSS_E_OUTOFMEMORY); done: free(home_dir); return result; } TSS_RESULT get_file(int *fd) { TSS_RESULT result; int rc = 0; char *file_name = NULL; MUTEX_LOCK(user_ps_lock); /* check the global file handle first. If it exists, lock it and return */ if (user_ps_fd != -1) { fl.l_type = F_WRLCK; if ((rc = fcntl(user_ps_fd, F_SETLKW, &fl))) { LogDebug("USER PS: failed to lock file: %s", strerror(errno)); MUTEX_UNLOCK(user_ps_lock); return TSPERR(TSS_E_INTERNAL_ERROR); } *fd = user_ps_fd; return TSS_SUCCESS; } /* open and lock the file */ if ((result = get_user_ps_path(&file_name))) { LogDebugFn("USER PS: error getting file path"); MUTEX_UNLOCK(user_ps_lock); return result; } user_ps_fd = open(file_name, O_CREAT|O_RDWR, 0600); if (user_ps_fd < 0) { LogDebug("USER PS: open of %s failed: %s", file_name, strerror(errno)); free(file_name); MUTEX_UNLOCK(user_ps_lock); return TSPERR(TSS_E_INTERNAL_ERROR); } fl.l_type = F_WRLCK; if ((rc = fcntl(user_ps_fd, F_SETLKW, &fl))) { LogDebug("USER PS: failed to get lock of %s: %s", file_name, strerror(errno)); free(file_name); close(user_ps_fd); user_ps_fd = -1; MUTEX_UNLOCK(user_ps_lock); return TSPERR(TSS_E_INTERNAL_ERROR); } *fd = user_ps_fd; free(file_name); return TSS_SUCCESS; } int put_file(int fd) { int rc = 0; fsync(fd); /* release the file lock */ fl.l_type = F_UNLCK; if ((rc = fcntl(fd, F_SETLKW, &fl))) { LogDebug("USER PS: failed to unlock file: %s", strerror(errno)); rc = -1; } MUTEX_UNLOCK(user_ps_lock); return rc; } void psfile_close(int fd) { close(fd); user_ps_fd = -1; MUTEX_UNLOCK(user_ps_lock); } TSS_RESULT psfile_is_key_registered(int fd, TSS_UUID *uuid, TSS_BOOL *answer) { TSS_RESULT result; struct key_disk_cache tmp; if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp)) == TSS_SUCCESS) *answer = TRUE; else if (result == (TSS_E_PS_KEY_NOTFOUND | TSS_LAYER_TSP)) *answer = FALSE; else return result; return TSS_SUCCESS; } TSS_RESULT psfile_get_parent_uuid_by_uuid(int fd, TSS_UUID *uuid, TSS_UUID *ret_uuid) { TSS_RESULT result; struct key_disk_cache tmp; if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp))) return result; memcpy(ret_uuid, &tmp.parent_uuid, sizeof(TSS_UUID)); return TSS_SUCCESS; } TSS_RESULT psfile_get_parent_ps_type(int fd, TSS_UUID *uuid, UINT32 *type) { TSS_RESULT result; struct key_disk_cache tmp; if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp))) return result; if (tmp.flags & CACHE_FLAG_PARENT_PS_SYSTEM) *type = TSS_PS_TYPE_SYSTEM; else *type = TSS_PS_TYPE_USER; return TSS_SUCCESS; } /* * return a key struct from PS given a uuid */ TSS_RESULT psfile_get_key_by_uuid(int fd, TSS_UUID *uuid, BYTE *key) { int rc; TSS_RESULT result; off_t file_offset; struct key_disk_cache tmp; BYTE buf[4096]; if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp))) return result; /* jump to the location of the key blob */ file_offset = TSSPS_BLOB_DATA_OFFSET(&tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t)-1)) { LogDebugFn("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } if (tmp.blob_size > 4096) { LogError("Blob size greater than 4096! Size: %d", tmp.blob_size); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((rc = read_data(fd, buf, tmp.blob_size))) { LogDebugFn("Blob read from disk failed."); return rc; } memcpy(key, buf, tmp.blob_size); return TSS_SUCCESS; } /* * return a key struct from PS given a public key */ TSS_RESULT psfile_get_key_by_pub(int fd, TSS_UUID *uuid, UINT32 pub_size, BYTE *pub, BYTE *key) { int rc; TSS_RESULT result; off_t file_offset; struct key_disk_cache tmp; BYTE buf[4096]; if ((result = psfile_get_cache_entry_by_pub(fd, pub_size, pub, &tmp))) return result; /* jump to the location of the key blob */ file_offset = TSSPS_BLOB_DATA_OFFSET(&tmp); rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t)-1)) { LogDebugFn("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } if (tmp.blob_size > 4096) { LogError("Blob size greater than 4096! Size: %d", tmp.blob_size); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((result = read_data(fd, buf, tmp.blob_size))) { LogDebugFn("Blob read from disk failed."); return result; } memcpy(key, buf, tmp.blob_size); memcpy(uuid, &tmp.uuid, sizeof(TSS_UUID)); return TSS_SUCCESS; } TSS_RESULT psfile_get_uuid_by_pub(int fd, UINT32 pub_size, BYTE *pub, TSS_UUID *uuid) { TSS_RESULT result; struct key_disk_cache tmp; if ((result = psfile_get_cache_entry_by_pub(fd, pub_size, pub, &tmp))) return result; memcpy(uuid, &tmp.uuid, sizeof(TSS_UUID)); return TSS_SUCCESS; } TSS_RESULT psfile_change_num_keys(int fd, BYTE increment) { int rc; TSS_RESULT result; UINT32 num_keys; rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } rc = read(fd, &num_keys, sizeof(UINT32)); if (rc != sizeof(UINT32)) { LogDebug("read of %zd bytes: %s", sizeof(UINT32), strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } num_keys = LE_32(num_keys); if (increment) num_keys++; else num_keys--; rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } num_keys = LE_32(num_keys); if ((result = write_data(fd, (void *)&num_keys, sizeof(UINT32)))) { LogDebug("%s", __FUNCTION__); return result; } return TSS_SUCCESS; } /* Write the initial header (number of keys and PS version) to initialize a new file */ TSS_RESULT psfile_write_key_header(int fd) { int rc; TSS_RESULT result; UINT32 i; rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } i = TSSPS_VERSION; if ((result = write_data(fd, &i, sizeof(BYTE)))) { LogDebug("%s", __FUNCTION__); return result; } rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } i = 0; if ((result = write_data(fd, &i, sizeof(UINT32)))) { LogDebug("%s", __FUNCTION__); return result; } return TSS_SUCCESS; } /* * disk store format: * * TrouSerS 0.2.1+ * Version 1: cached? * [BYTE PS version = '\1'] * [UINT32 num_keys_on_disk ] * [TSS_UUID uuid0 ] yes * [TSS_UUID uuid_parent0 ] yes * [UINT16 pub_data_size0 ] yes * [UINT16 blob_size0 ] yes * [UINT32 vendor_data_size0] yes * [UINT16 cache_flags0 ] yes * [BYTE[] pub_data0 ] * [BYTE[] blob0 ] * [BYTE[] vendor_data0 ] * [...] * */ TSS_RESULT psfile_write_key(int fd, TSS_UUID *uuid, TSS_UUID *parent_uuid, UINT32 parent_ps, BYTE *key_blob, UINT16 key_blob_size) { TSS_RESULT result; TSS_KEY key; UINT32 zero = 0; UINT64 offset; UINT16 pub_key_size, cache_flags = 0; struct stat stat_buf; int rc, file_offset; /* leaving the cache flag for parent ps type as 0 implies TSS_PS_TYPE_USER */ if (parent_ps == TSS_PS_TYPE_SYSTEM) cache_flags |= CACHE_FLAG_PARENT_PS_SYSTEM; if ((rc = fstat(fd, &stat_buf)) == -1) { LogDebugFn("stat failed: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } file_offset = stat_buf.st_size; if (file_offset < (int)TSSPS_KEYS_OFFSET) { if ((result = psfile_write_key_header(fd))) return result; file_offset = TSSPS_KEYS_OFFSET; } rc = lseek(fd, file_offset, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* Unload the blob to get the public key */ offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, key_blob, &key))) return result; pub_key_size = key.pubKey.keyLength; /* [TSS_UUID uuid0 ] yes */ if ((result = write_data(fd, (void *)uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); goto done; } /* [TSS_UUID uuid_parent0 ] yes */ if ((result = write_data(fd, (void *)parent_uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); goto done; } /* [UINT16 pub_data_size0 ] yes */ pub_key_size = LE_16(pub_key_size); if ((result = write_data(fd, &pub_key_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); goto done; } pub_key_size = LE_16(pub_key_size); /* [UINT16 blob_size0 ] yes */ key_blob_size = LE_16(key_blob_size); if ((result = write_data(fd, &key_blob_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); goto done; } key_blob_size = LE_16(key_blob_size); /* [UINT32 vendor_data_size0 ] yes */ if ((result = write_data(fd, &zero, sizeof(UINT32)))) { LogDebug("%s", __FUNCTION__); goto done; } /* [UINT16 cache_flags0 ] yes */ cache_flags = LE_16(cache_flags); if ((result = write_data(fd, &cache_flags, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); goto done; } cache_flags = LE_16(cache_flags); /* [BYTE[] pub_data0 ] no */ if ((result = write_data(fd, (void *)key.pubKey.key, pub_key_size))) { LogDebug("%s", __FUNCTION__); goto done; } /* [BYTE[] blob0 ] no */ if ((result = write_data(fd, (void *)key_blob, key_blob_size))) { LogDebug("%s", __FUNCTION__); goto done; } if ((result = psfile_change_num_keys(fd, TSS_PSFILE_INCREMENT_NUM_KEYS))) { LogDebug("%s", __FUNCTION__); goto done; } done: free_key_refs(&key); return result; } TSS_RESULT psfile_remove_key(int fd, TSS_UUID *uuid) { TSS_RESULT result; UINT32 head_offset = 0, tail_offset; int rc, size = 0; struct key_disk_cache c; BYTE buf[4096]; if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &c))) return result; /* head_offset is the offset the beginning of the key */ head_offset = TSSPS_UUID_OFFSET(&c); /* tail_offset is the offset the beginning of the next key */ tail_offset = TSSPS_VENDOR_DATA_OFFSET(&c) + c.vendor_data_size; rc = lseek(fd, tail_offset, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* read in from tail, write out to head to fill the gap */ while ((rc = read(fd, buf, sizeof(buf))) > 0) { size = rc; tail_offset += size; /* set the file pointer to where we want to write */ rc = lseek(fd, head_offset, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* write the data */ if ((result = write_data(fd, (void *)buf, size))) { LogDebug("%s", __FUNCTION__); return result; } head_offset += size; /* set the file pointer to where we want to read in the next * loop */ rc = lseek(fd, tail_offset, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } } if (rc < 0) { LogDebug("read: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* set the file pointer to where we want to write */ rc = lseek(fd, head_offset, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* head_offset now contains a pointer to where we want to truncate the * file. Zero out the old tail end of the file and truncate it. */ __tspi_memset(buf, 0, sizeof(buf)); /* Zero out the old tail end of the file */ if ((result = write_data(fd, (void *)buf, tail_offset - head_offset))) { LogDebug("%s", __FUNCTION__); return result; } if ((rc = ftruncate(fd, head_offset)) < 0) { LogDebug("ftruncate: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* we succeeded in removing a key from the disk. Decrement the number * of keys in the file */ if ((result = psfile_change_num_keys(fd, TSS_PSFILE_DECREMENT_NUM_KEYS))) return result; return TSS_SUCCESS; } TSS_RESULT psfile_get_all_cache_entries(int fd, UINT32 *size, struct key_disk_cache **c) { UINT32 i, num_keys = psfile_get_num_keys(fd); int offset; TSS_RESULT result; struct key_disk_cache *tmp = NULL; if (num_keys == 0) { *size = 0; *c = NULL; return TSS_SUCCESS; } /* make sure the file pointer is where we expect, just after the number * of keys on disk at the head of the file */ offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((tmp = malloc(num_keys * sizeof(struct key_disk_cache))) == NULL) { LogDebug("malloc of %zu bytes failed.", num_keys * sizeof(struct key_disk_cache)); return TSPERR(TSS_E_OUTOFMEMORY); } for (i = 0; i < num_keys; i++) { offset = lseek(fd, 0, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto err_exit; } tmp[i].offset = offset; /* read UUID */ if ((result = read_data(fd, &tmp[i].uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); goto err_exit; } /* read parent UUID */ if ((result = read_data(fd, &tmp[i].parent_uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); goto err_exit; } /* pub data size */ if ((result = read_data(fd, &tmp[i].pub_data_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); goto err_exit; } tmp[i].pub_data_size = LE_16(tmp[i].pub_data_size); DBG_ASSERT(tmp[i].pub_data_size <= 2048); /* blob size */ if ((result = read_data(fd, &tmp[i].blob_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); goto err_exit; } tmp[i].blob_size = LE_16(tmp[i].blob_size); DBG_ASSERT(tmp[i].blob_size <= 4096); /* vendor data size */ if ((result = read_data(fd, &tmp[i].vendor_data_size, sizeof(UINT32)))) { LogDebug("%s", __FUNCTION__); goto err_exit; } tmp[i].vendor_data_size = LE_32(tmp[i].vendor_data_size); /* cache flags */ if ((result = read_data(fd, &tmp[i].flags, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); goto err_exit; } tmp[i].flags = LE_16(tmp[i].flags); /* fast forward over the pub key */ offset = lseek(fd, tmp[i].pub_data_size, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto err_exit; } /* fast forward over the blob */ offset = lseek(fd, tmp[i].blob_size, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); result = TSPERR(TSS_E_INTERNAL_ERROR); goto err_exit; } /* ignore vendor data for user ps */ } *size = num_keys; *c = tmp; return TSS_SUCCESS; err_exit: free(tmp); return result; } TSS_RESULT copy_key_info(int fd, TSS_KM_KEYINFO *ki, struct key_disk_cache *c) { TSS_KEY key; BYTE blob[4096]; UINT64 offset; TSS_RESULT result; off_t off; /* Set the file pointer to the offset that the key blob is at */ off = lseek(fd, TSSPS_BLOB_DATA_OFFSET(c), SEEK_SET); if (off == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* Read in the key blob */ if ((result = read_data(fd, (void *)blob, c->blob_size))) { LogDebug("%s", __FUNCTION__); return result; } /* Expand the blob into a useable form */ offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key))) return result; if (key.hdr.key12.tag == TPM_TAG_KEY12) { ki->versionInfo.bMajor = TSS_SPEC_MAJOR; ki->versionInfo.bMinor = TSS_SPEC_MINOR; ki->versionInfo.bRevMajor = 0; ki->versionInfo.bRevMinor = 0; } else memcpy(&ki->versionInfo, &key.hdr.key11.ver, sizeof(TSS_VERSION)); memcpy(&ki->keyUUID, &c->uuid, sizeof(TSS_UUID)); memcpy(&ki->parentKeyUUID, &c->parent_uuid, sizeof(TSS_UUID)); ki->bAuthDataUsage = key.authDataUsage; free_key_refs(&key); return TSS_SUCCESS; } TSS_RESULT copy_key_info2(int fd, TSS_KM_KEYINFO2 *ki, struct key_disk_cache *c) { TSS_KEY key; BYTE blob[4096]; UINT64 offset; TSS_RESULT result; off_t off; /* Set the file pointer to the offset that the key blob is at */ off = lseek(fd, TSSPS_BLOB_DATA_OFFSET(c), SEEK_SET); if (off == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* Read in the key blob */ if ((result = read_data(fd, (void *)blob, c->blob_size))) { LogDebug("%s", __FUNCTION__); return result; } /* Expand the blob into a useable form */ offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key))) return result; if (key.hdr.key12.tag == TPM_TAG_KEY12) { ki->versionInfo.bMajor = TSS_SPEC_MAJOR; ki->versionInfo.bMinor = TSS_SPEC_MINOR; ki->versionInfo.bRevMajor = 0; ki->versionInfo.bRevMinor = 0; } else memcpy(&ki->versionInfo, &key.hdr.key11.ver, sizeof(TSS_VERSION)); memcpy(&ki->keyUUID, &c->uuid, sizeof(TSS_UUID)); memcpy(&ki->parentKeyUUID, &c->parent_uuid, sizeof(TSS_UUID)); /* CHECK: fill the two new fields of TSS_KM_KEYINFO2 */ ki->persistentStorageType = TSS_PS_TYPE_USER; ki->persistentStorageTypeParent = c->flags & CACHE_FLAG_PARENT_PS_SYSTEM ? TSS_PS_TYPE_SYSTEM : TSS_PS_TYPE_USER; ki->bAuthDataUsage = key.authDataUsage; free_key_refs(&key); return TSS_SUCCESS; } TSS_RESULT psfile_get_registered_keys(int fd, TSS_UUID *uuid, TSS_UUID *tcs_uuid, UINT32 *size, TSS_KM_KEYINFO **keys) { TSS_RESULT result; struct key_disk_cache *cache_entries; UINT32 cache_size, i, j; TSS_KM_KEYINFO *keyinfos = NULL; TSS_UUID *find_uuid; if ((result = psfile_get_all_cache_entries(fd, &cache_size, &cache_entries))) return result; if (cache_size == 0) { if (uuid) return TSPERR(TSS_E_PS_KEY_NOTFOUND); else { *size = 0; *keys = NULL; return TSS_SUCCESS; } } if (uuid) { find_uuid = uuid; j = 0; restart_search: /* Search for the requested UUID. When found, allocate new space for it, copy * it in, then change the uuid to be searched for it its parent and start over. */ for (i = 0; i < cache_size; i++) { if (!memcmp(&cache_entries[i].uuid, find_uuid, sizeof(TSS_UUID))) { if (!(keyinfos = realloc(keyinfos, (j+1) * sizeof(TSS_KM_KEYINFO)))) { free(cache_entries); free(keyinfos); return TSPERR(TSS_E_OUTOFMEMORY); } __tspi_memset(&keyinfos[j], 0, sizeof(TSS_KM_KEYINFO)); if ((result = copy_key_info(fd, &keyinfos[j], &cache_entries[i]))) { free(cache_entries); free(keyinfos); return result; } find_uuid = &keyinfos[j].parentKeyUUID; j++; goto restart_search; } } /* Searching for keys in the user PS will always lead us up to some key in the * system PS. Return that key's uuid so that the upper layers can call down to TCS * to search for it. */ memcpy(tcs_uuid, find_uuid, sizeof(TSS_UUID)); *size = j; } else { if ((keyinfos = calloc(cache_size, sizeof(TSS_KM_KEYINFO))) == NULL) { LogDebug("malloc of %zu bytes failed.", cache_size * sizeof(TSS_KM_KEYINFO)); free(cache_entries); return TSPERR(TSS_E_OUTOFMEMORY); } for (i = 0; i < cache_size; i++) { if ((result = copy_key_info(fd, &keyinfos[i], &cache_entries[i]))) { free(cache_entries); free(keyinfos); return result; } } *size = cache_size; } free(cache_entries); *keys = keyinfos; return TSS_SUCCESS; } TSS_RESULT psfile_get_registered_keys2(int fd, TSS_UUID *uuid, TSS_UUID *tcs_uuid, UINT32 *size, TSS_KM_KEYINFO2 **keys) { TSS_RESULT result; struct key_disk_cache *cache_entries; UINT32 cache_size, i, j; TSS_KM_KEYINFO2 *keyinfos = NULL; TSS_UUID *find_uuid; if ((result = psfile_get_all_cache_entries(fd, &cache_size, &cache_entries))) return result; if (cache_size == 0) { if (uuid) return TSPERR(TSS_E_PS_KEY_NOTFOUND); else { *size = 0; *keys = NULL; return TSS_SUCCESS; } } if (uuid) { find_uuid = uuid; j = 0; restart_search: /* Search for the requested UUID. When found, allocate new space for it, copy * it in, then change the uuid to be searched for it its parent and start over. */ for (i = 0; i < cache_size; i++) { /*Return 0 if normal finish*/ if (!memcmp(&cache_entries[i].uuid, find_uuid, sizeof(TSS_UUID))) { if (!(keyinfos = realloc(keyinfos, (j+1) * sizeof(TSS_KM_KEYINFO2)))) { free(cache_entries); free(keyinfos); return TSPERR(TSS_E_OUTOFMEMORY); } /* Here the key UUID is found and needs to be copied for the array*/ /* Initializes the keyinfos with 0's*/ __tspi_memset(&keyinfos[j], 0, sizeof(TSS_KM_KEYINFO2)); if ((result = copy_key_info2(fd, &keyinfos[j], &cache_entries[i]))) { free(cache_entries); free(keyinfos); return result; } find_uuid = &keyinfos[j].parentKeyUUID; j++; goto restart_search; } } /* Searching for keys in the user PS will always lead us up to some key in the * system PS. Return that key's uuid so that the upper layers can call down to TCS * to search for it. */ memcpy(tcs_uuid, find_uuid, sizeof(TSS_UUID)); *size = j; } else { if ((keyinfos = calloc(cache_size, sizeof(TSS_KM_KEYINFO2))) == NULL) { LogDebug("malloc of %zu bytes failed.", cache_size * sizeof(TSS_KM_KEYINFO2)); free(cache_entries); return TSPERR(TSS_E_OUTOFMEMORY); } for (i = 0; i < cache_size; i++) { if ((result = copy_key_info2(fd, &keyinfos[i], &cache_entries[i]))) { free(cache_entries); free(keyinfos); return result; } } *size = cache_size; } free(cache_entries); *keys = keyinfos; return TSS_SUCCESS; } /* * read into the PS file and return the number of keys */ UINT32 psfile_get_num_keys(int fd) { UINT32 num_keys; int rc; /* go to the number of keys */ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET); if (rc == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return 0; } rc = read(fd, &num_keys, sizeof(UINT32)); if (rc < 0) { LogDebug("read of %zd bytes: %s", sizeof(UINT32), strerror(errno)); return 0; } else if ((unsigned)rc < sizeof(UINT32)) { num_keys = 0; } /* The system PS file is written in little-endian */ num_keys = LE_32(num_keys); return num_keys; } /* * disk store format: * * TrouSerS 0.2.1+ * Version 1: cached? * [BYTE PS version = '\1'] * [UINT32 num_keys_on_disk ] * [TSS_UUID uuid0 ] yes * [TSS_UUID uuid_parent0 ] yes * [UINT16 pub_data_size0 ] yes * [UINT16 blob_size0 ] yes * [UINT32 vendor_data_size0] yes * [UINT16 cache_flags0 ] yes * [BYTE[] pub_data0 ] * [BYTE[] blob0 ] * [BYTE[] vendor_data0 ] * [...] * */ TSS_RESULT psfile_get_cache_entry_by_uuid(int fd, TSS_UUID *uuid, struct key_disk_cache *c) { UINT32 i, num_keys = psfile_get_num_keys(fd); int offset; TSS_RESULT result; BYTE found = 0; if (num_keys == 0) return TSPERR(TSS_E_PS_KEY_NOTFOUND); /* make sure the file pointer is where we expect, just after the number * of keys on disk at the head of the file */ offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } for (i = 0; i < num_keys && !found; i++) { offset = lseek(fd, 0, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } c->offset = offset; /* read UUID */ if ((result = read_data(fd, (void *)&c->uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); return result; } if (!memcmp(&c->uuid, uuid, sizeof(TSS_UUID))) { found = 1; /* read parent UUID */ if ((result = read_data(fd, (void *)&c->parent_uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); return result; } } else { /* fast forward over the parent UUID */ offset = lseek(fd, sizeof(TSS_UUID), SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } } /* pub data size */ if ((result = read_data(fd, &c->pub_data_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); return result; } c->pub_data_size = LE_16(c->pub_data_size); DBG_ASSERT(c->pub_data_size <= 2048 && c->pub_data_size > 0); /* blob size */ if ((result = read_data(fd, &c->blob_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); return result; } c->blob_size = LE_16(c->blob_size); DBG_ASSERT(c->blob_size <= 4096 && c->blob_size > 0); /* vendor data size */ if ((result = read_data(fd, &c->vendor_data_size, sizeof(UINT32)))) { LogDebug("%s", __FUNCTION__); return result; } c->vendor_data_size = LE_32(c->vendor_data_size); /* cache flags */ if ((result = read_data(fd, &c->flags, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); return result; } c->flags = LE_16(c->flags); /* fast forward over the pub key */ offset = lseek(fd, c->pub_data_size, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* fast forward over the blob */ offset = lseek(fd, c->blob_size, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* ignore vendor data in user ps */ } return found ? TSS_SUCCESS : TSPERR(TSS_E_PS_KEY_NOTFOUND); } TSS_RESULT psfile_get_cache_entry_by_pub(int fd, UINT32 pub_size, BYTE *pub, struct key_disk_cache *c) { BYTE blob[2048]; UINT32 i, num_keys = psfile_get_num_keys(fd); int offset; TSS_RESULT result; if (num_keys == 0) return TSPERR(TSS_E_PS_KEY_NOTFOUND); /* make sure the file pointer is where we expect, just after the number * of keys on disk at the head of the file */ offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } for (i = 0; i < num_keys; i++) { offset = lseek(fd, 0, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } c->offset = offset; /* read UUID */ if ((result = read_data(fd, (void *)&c->uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); return result; } /* read parent UUID */ if ((result = read_data(fd, (void *)&c->parent_uuid, sizeof(TSS_UUID)))) { LogDebug("%s", __FUNCTION__); return result; } /* pub data size */ if ((result = read_data(fd, &c->pub_data_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); return result; } c->pub_data_size = LE_16(c->pub_data_size); DBG_ASSERT(c->pub_data_size <= 2048 && c->pub_data_size > 0); /* blob size */ if ((result = read_data(fd, &c->blob_size, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); return result; } c->blob_size = LE_16(c->blob_size); DBG_ASSERT(c->blob_size <= 4096 && c->blob_size > 0); /* vendor data size */ if ((result = read_data(fd, &c->vendor_data_size, sizeof(UINT32)))) { LogDebug("%s", __FUNCTION__); return result; } c->vendor_data_size = LE_32(c->vendor_data_size); /* cache flags */ if ((result = read_data(fd, &c->flags, sizeof(UINT16)))) { LogDebug("%s", __FUNCTION__); return result; } c->flags = LE_16(c->flags); if (c->pub_data_size == pub_size) { /* read in the pub key */ if ((result = read_data(fd, blob, c->pub_data_size))) { LogDebug("%s", __FUNCTION__); return result; } if (!memcmp(blob, pub, pub_size)) break; } /* fast forward over the blob */ offset = lseek(fd, c->blob_size, SEEK_CUR); if (offset == ((off_t)-1)) { LogDebug("lseek: %s", strerror(errno)); return TSPERR(TSS_E_INTERNAL_ERROR); } /* ignore vendor data */ } return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tsp_random.c0000664000175000017510000000411413663651711017034 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_GetRandom(TSS_HCONTEXT tspContext, /* in */ UINT32 bytesRequested, /* in */ BYTE ** randomBytes) /* out */ { TSS_RESULT result; UINT32 decLen = 0; BYTE *dec = NULL; UINT64 offset; TCS_HANDLE handlesLen = 0; BYTE data[sizeof(UINT32)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, bytesRequested, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_GetRandom, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; *randomBytes = dec; return result; } TSS_RESULT Transport_StirRandom(TSS_HCONTEXT tspContext, /* in */ UINT32 inDataSize, /* in */ BYTE * inData) /* in */ { TSS_RESULT result; UINT64 offset; UINT32 dataLen; TCS_HANDLE handlesLen = 0; BYTE *data; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(UINT32) + inDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, inDataSize, data); Trspi_LoadBlob(&offset, inDataSize, data, inData); result = obj_context_transport_execute(tspContext, TPM_ORD_StirRandom, dataLen, data, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); free(data); return result; } #endif trousers-0.3.15/src/tspi/obj_pcrs.c0000664000175000017510000005571013663651711016477 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT obj_pcrs_add(TSS_HCONTEXT tspContext, UINT32 type, TSS_HOBJECT *phObject) { TSS_RESULT result; UINT32 ver; struct tr_pcrs_obj *pcrs; if ((pcrs = calloc(1, sizeof(struct tr_pcrs_obj))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_pcrs_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } if (type == TSS_PCRS_STRUCT_DEFAULT) { if ((result = obj_context_get_connection_version(tspContext, &ver))) { free(pcrs); return result; } switch (ver) { case TSS_TSPATTRIB_CONTEXT_VERSION_V1_2: pcrs->type = TSS_PCRS_STRUCT_INFO_LONG; pcrs->info.infolong.localityAtRelease = TSS_LOCALITY_ALL; break; case TSS_TSPATTRIB_CONTEXT_VERSION_V1_1: /* fall through */ default: pcrs->type = TSS_PCRS_STRUCT_INFO; break; } } else pcrs->type = type; if ((result = obj_list_add(&pcrs_list, tspContext, 0, pcrs, phObject))) { free(pcrs); return result; } return TSS_SUCCESS; } void pcrs_free(void *data) { struct tr_pcrs_obj *pcrs = (struct tr_pcrs_obj *)data; switch (pcrs->type) { case TSS_PCRS_STRUCT_INFO: free(pcrs->info.info11.pcrSelection.pcrSelect); free(pcrs->pcrs); break; case TSS_PCRS_STRUCT_INFO_SHORT: free(pcrs->info.infoshort.pcrSelection.pcrSelect); free(pcrs->pcrs); break; case TSS_PCRS_STRUCT_INFO_LONG: free(pcrs->info.infolong.creationPCRSelection.pcrSelect); free(pcrs->info.infolong.releasePCRSelection.pcrSelect); break; default: LogDebugFn("Undefined type of PCRs object"); break; } free(pcrs); } TSS_RESULT obj_pcrs_remove(TSS_HOBJECT hObject, TSS_HCONTEXT tspContext) { TSS_RESULT result; if ((result = obj_list_remove(&pcrs_list, &pcrs_free, hObject, tspContext))) return result; return TSS_SUCCESS; } TSS_BOOL obj_is_pcrs(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&pcrs_list, hObject))) { answer = TRUE; obj_list_put(&pcrs_list); } return answer; } TSS_RESULT obj_pcrs_get_tsp_context(TSS_HPCRS hPcrs, TSS_HCONTEXT *tspContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *tspContext = obj->tspContext; obj_list_put(&pcrs_list); return TSS_SUCCESS; } TSS_RESULT obj_pcrs_get_type(TSS_HPCRS hPcrs, UINT32 *type) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; *type = pcrs->type; obj_list_put(&pcrs_list); return TSS_SUCCESS; } TSS_RESULT obj_pcrs_get_selection(TSS_HPCRS hPcrs, UINT32 *size, BYTE *out) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_SELECTION *tmp; UINT64 offset = 0; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch (pcrs->type) { case TSS_PCRS_STRUCT_INFO: tmp = &pcrs->info.info11.pcrSelection; break; case TSS_PCRS_STRUCT_INFO_SHORT: tmp = &pcrs->info.infoshort.pcrSelection; break; case TSS_PCRS_STRUCT_INFO_LONG: tmp = &pcrs->info.infolong.creationPCRSelection; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } Trspi_LoadBlob_PCR_SELECTION(&offset, out, tmp); *size = offset; done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_set_values(TSS_HPCRS hPcrs, TPM_PCR_COMPOSITE *pcrComp) { TSS_RESULT result = TSS_SUCCESS; TPM_PCR_SELECTION *select = &(pcrComp->select); UINT16 i, val_idx = 0; for (i = 0; i < select->sizeOfSelect * 8; i++) { if (select->pcrSelect[i / 8] & (1 << (i % 8))) { if ((result = obj_pcrs_set_value(hPcrs, i, TCPA_SHA1_160_HASH_LEN, (BYTE *)&pcrComp->pcrValue[val_idx]))) return result; val_idx++; } } return result; } TSS_RESULT obj_pcrs_set_value(TSS_HPCRS hPcrs, UINT32 idx, UINT32 size, BYTE *value) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_SELECTION *select; TPM_COMPOSITE_HASH *compHash; UINT16 bytes_to_hold = (idx / 8) + 1; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: bytes_to_hold = (bytes_to_hold < 2) ? 2 : bytes_to_hold; select = &pcrs->info.info11.pcrSelection; compHash = &pcrs->info.info11.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_SHORT: bytes_to_hold = (bytes_to_hold < 3) ? 3 : bytes_to_hold; select = &pcrs->info.infoshort.pcrSelection; compHash = &pcrs->info.infoshort.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_LONG: bytes_to_hold = (bytes_to_hold < 3) ? 3 : bytes_to_hold; select = &pcrs->info.infolong.releasePCRSelection; compHash = &pcrs->info.infolong.digestAtRelease; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; break; } /* allocate the selection structure */ if (select->pcrSelect == NULL) { if ((select->pcrSelect = malloc(bytes_to_hold)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } select->sizeOfSelect = bytes_to_hold; __tspi_memset(select->pcrSelect, 0, bytes_to_hold); /* allocate the pcr array */ if ((pcrs->pcrs = malloc(bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } else if (select->sizeOfSelect < bytes_to_hold) { if ((select->pcrSelect = realloc(select->pcrSelect, bytes_to_hold)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } /* set the newly allocated bytes to 0 */ __tspi_memset(&select->pcrSelect[select->sizeOfSelect], 0, bytes_to_hold - select->sizeOfSelect); select->sizeOfSelect = bytes_to_hold; /* realloc the pcrs array */ if ((pcrs->pcrs = realloc(pcrs->pcrs, bytes_to_hold * 8 * sizeof(TPM_PCRVALUE))) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } /* set the bit in the selection structure */ select->pcrSelect[idx / 8] |= (1 << (idx % 8)); /* set the value in the pcrs array */ memcpy(&(pcrs->pcrs[idx]), value, size); result = pcrs_calc_composite(select, pcrs->pcrs, compHash); done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_get_value(TSS_HPCRS hPcrs, UINT32 idx, UINT32 *size, BYTE **value) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_SELECTION *select; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: select = &pcrs->info.info11.pcrSelection; break; case TSS_PCRS_STRUCT_INFO_SHORT: select = &pcrs->info.infoshort.pcrSelection; break; case TSS_PCRS_STRUCT_INFO_LONG: select = &pcrs->info.infolong.creationPCRSelection; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; break; } if (select->sizeOfSelect < (idx / 8) + 1) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } if ((*value = calloc_tspi(obj->tspContext, TCPA_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } *size = TCPA_SHA1_160_HASH_LEN; memcpy(*value, &pcrs->pcrs[idx], TCPA_SHA1_160_HASH_LEN); done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_get_digest_at_release(TSS_HPCRS hPcrs, UINT32 *size, BYTE **out) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; BYTE *digest; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: #ifdef TSS_SPEC_COMPLIANCE result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; #else digest = (BYTE *)&pcrs->info.info11.digestAtRelease; break; #endif case TSS_PCRS_STRUCT_INFO_SHORT: digest = (BYTE *)&pcrs->info.infoshort.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_LONG: digest = (BYTE *)&pcrs->info.infolong.digestAtRelease; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; break; } if ((*out = calloc_tspi(obj->tspContext, sizeof(TPM_COMPOSITE_HASH))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TPM_COMPOSITE_HASH)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*out, digest, sizeof(TPM_COMPOSITE_HASH)); *size = sizeof(TPM_COMPOSITE_HASH); done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_select_index(TSS_HPCRS hPcrs, UINT32 idx) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_SELECTION *select; UINT16 bytes_to_hold = (idx / 8) + 1; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: bytes_to_hold = (bytes_to_hold < 2) ? 2 : bytes_to_hold; select = &pcrs->info.info11.pcrSelection; break; case TSS_PCRS_STRUCT_INFO_SHORT: case TSS_PCRS_STRUCT_INFO_LONG: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; break; } /* allocate the selection structure */ if (select->pcrSelect == NULL) { if ((select->pcrSelect = malloc(bytes_to_hold)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } select->sizeOfSelect = bytes_to_hold; __tspi_memset(select->pcrSelect, 0, bytes_to_hold); /* alloc the pcrs array */ if ((pcrs->pcrs = malloc(bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } else if (select->sizeOfSelect < bytes_to_hold) { if ((select->pcrSelect = realloc(select->pcrSelect, bytes_to_hold)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } /* set the newly allocated bytes to 0 */ __tspi_memset(&select->pcrSelect[select->sizeOfSelect], 0, bytes_to_hold - select->sizeOfSelect); select->sizeOfSelect = bytes_to_hold; /* realloc the pcrs array */ if ((pcrs->pcrs = realloc(pcrs->pcrs, bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } /* set the bit in the selection structure */ select->pcrSelect[idx / 8] |= (1 << (idx % 8)); done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_select_index_ex(TSS_HPCRS hPcrs, UINT32 dir, UINT32 idx) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_SELECTION *select; UINT16 bytes_to_hold = (idx / 8) + 1; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; case TSS_PCRS_STRUCT_INFO_SHORT: if (dir == TSS_PCRS_DIRECTION_CREATION) { result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; } bytes_to_hold = (bytes_to_hold < 3) ? 3 : bytes_to_hold; select = &pcrs->info.infoshort.pcrSelection; break; case TSS_PCRS_STRUCT_INFO_LONG: bytes_to_hold = (bytes_to_hold < 3) ? 3 : bytes_to_hold; if (dir == TSS_PCRS_DIRECTION_CREATION) select = &pcrs->info.infolong.creationPCRSelection; else select = &pcrs->info.infolong.releasePCRSelection; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; break; } /* allocate the selection structure */ if (select->pcrSelect == NULL) { if ((select->pcrSelect = malloc(bytes_to_hold)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } select->sizeOfSelect = bytes_to_hold; __tspi_memset(select->pcrSelect, 0, bytes_to_hold); /* alloc the pcrs array */ if ((pcrs->pcrs = malloc(bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } else if (select->sizeOfSelect < bytes_to_hold) { if ((select->pcrSelect = realloc(select->pcrSelect, bytes_to_hold)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } /* set the newly allocated bytes to 0 */ __tspi_memset(&select->pcrSelect[select->sizeOfSelect], 0, bytes_to_hold - select->sizeOfSelect); select->sizeOfSelect = bytes_to_hold; /* realloc the pcrs array */ if ((pcrs->pcrs = realloc(pcrs->pcrs, bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN)) == NULL) { LogError("malloc of %d bytes failed.", bytes_to_hold * 8 * TCPA_SHA1_160_HASH_LEN); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } } /* set the bit in the selection structure */ select->pcrSelect[idx / 8] |= (1 << (idx % 8)); done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_create_info_type(TSS_HPCRS hPcrs, UINT32 *type, UINT32 *size, BYTE **info) { TSS_RESULT result; /* If type equals 0, then we create the structure based on how the object was created */ if (*type == 0) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; *type = pcrs->type; obj_list_put(&pcrs_list); } switch (*type) { case TSS_PCRS_STRUCT_INFO: result = obj_pcrs_create_info(hPcrs, size, info); break; case TSS_PCRS_STRUCT_INFO_LONG: result = obj_pcrs_create_info_long(hPcrs, size, info); break; case TSS_PCRS_STRUCT_INFO_SHORT: result = obj_pcrs_create_info_short(hPcrs, size, info); break; default: return TSPERR(TSS_E_INTERNAL_ERROR); } return result; } /* Create a PCR info struct based on the hPcrs object */ TSS_RESULT obj_pcrs_create_info(TSS_HPCRS hPcrs, UINT32 *size, BYTE **info) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_INFO info11; UINT64 offset; UINT32 ret_size; BYTE *ret; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; /* Set everything that is not assigned to be all zeroes */ __tspi_memset(&info11, 0, sizeof(info11)); switch (pcrs->type) { case TSS_PCRS_STRUCT_INFO: info11 = pcrs->info.info11; break; case TSS_PCRS_STRUCT_INFO_LONG: info11.pcrSelection = pcrs->info.infolong.releasePCRSelection; info11.digestAtRelease = pcrs->info.infolong.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_SHORT: info11.pcrSelection = pcrs->info.infoshort.pcrSelection; info11.digestAtRelease = pcrs->info.infoshort.digestAtRelease; break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } offset = 0; Trspi_LoadBlob_PCR_INFO(&offset, NULL, &info11); ret_size = offset; if ((ret = calloc(1, ret_size)) == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); LogDebug("malloc of %u bytes failed.", ret_size); goto done; } offset = 0; Trspi_LoadBlob_PCR_INFO(&offset, ret, &info11); *info = ret; *size = ret_size; done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_create_info_long(TSS_HPCRS hPcrs, UINT32 *size, BYTE **info) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_INFO_LONG infolong; BYTE dummyBits[3] = { 0, 0, 0 }; TPM_PCR_SELECTION dummySelection = { 3, dummyBits }; UINT64 offset; UINT32 ret_size; BYTE *ret; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; /* Set everything that is not assigned to be all zeroes */ __tspi_memset(&infolong, 0, sizeof(infolong)); infolong.tag = TPM_TAG_PCR_INFO_LONG; /* localityAtCreation and creationPCRSelection certainly do not need to be set here, but * some chips such as Winbond do not ignore them on input, so we must give them dummy * "good" values */ infolong.localityAtCreation = TPM_LOC_ZERO; infolong.creationPCRSelection = dummySelection; switch (pcrs->type) { case TSS_PCRS_STRUCT_INFO: infolong.localityAtRelease = TSS_LOCALITY_ALL; infolong.releasePCRSelection = pcrs->info.info11.pcrSelection; infolong.digestAtRelease = pcrs->info.info11.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_LONG: infolong.localityAtRelease = pcrs->info.infolong.localityAtRelease; infolong.releasePCRSelection = pcrs->info.infolong.releasePCRSelection; infolong.digestAtRelease = pcrs->info.infolong.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_SHORT: infolong.localityAtRelease = pcrs->info.infoshort.localityAtRelease; infolong.releasePCRSelection = pcrs->info.infoshort.pcrSelection; infolong.digestAtRelease = pcrs->info.infoshort.digestAtRelease; break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } offset = 0; Trspi_LoadBlob_PCR_INFO_LONG(&offset, NULL, &infolong); ret_size = offset; if ((ret = calloc(1, ret_size)) == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); LogDebug("malloc of %u bytes failed.", ret_size); goto done; } offset = 0; Trspi_LoadBlob_PCR_INFO_LONG(&offset, ret, &infolong); *info = ret; *size = ret_size; done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_create_info_short(TSS_HPCRS hPcrs, UINT32 *size, BYTE **info) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_PCR_INFO_SHORT infoshort; BYTE select[] = { 0, 0, 0 }; UINT64 offset; UINT32 ret_size; BYTE *ret; /* Set everything that is not assigned to be all zeroes */ __tspi_memset(&infoshort, 0, sizeof(infoshort)); if (hPcrs != NULL_HPCRS) { if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch (pcrs->type) { case TSS_PCRS_STRUCT_INFO: infoshort.pcrSelection = pcrs->info.info11.pcrSelection; infoshort.localityAtRelease = TSS_LOCALITY_ALL; infoshort.digestAtRelease = pcrs->info.info11.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_LONG: infoshort.pcrSelection = pcrs->info.infolong.releasePCRSelection; infoshort.localityAtRelease = pcrs->info.infolong.localityAtRelease; infoshort.digestAtRelease = pcrs->info.infolong.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_SHORT: infoshort = pcrs->info.infoshort; break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } } else { infoshort.pcrSelection.sizeOfSelect = sizeof(select); infoshort.pcrSelection.pcrSelect = select; infoshort.localityAtRelease = TSS_LOCALITY_ALL; } offset = 0; Trspi_LoadBlob_PCR_INFO_SHORT(&offset, NULL, &infoshort); ret_size = offset; if ((ret = calloc(1, ret_size)) == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); LogDebug("malloc of %u bytes failed.", ret_size); goto done; } offset = 0; Trspi_LoadBlob_PCR_INFO_SHORT(&offset, ret, &infoshort); *info = ret; *size = ret_size; done: if (hPcrs != NULL_HPCRS) obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_get_locality(TSS_HPCRS hPcrs, UINT32 *out) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; BYTE *locality; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; case TSS_PCRS_STRUCT_INFO_SHORT: locality = &pcrs->info.infoshort.localityAtRelease; break; case TSS_PCRS_STRUCT_INFO_LONG: locality = &pcrs->info.infolong.localityAtRelease; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *out = (UINT32)*locality; done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_set_locality(TSS_HPCRS hPcrs, UINT32 locality) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; BYTE *loc; if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; case TSS_PCRS_STRUCT_INFO_SHORT: loc = &pcrs->info.infoshort.localityAtRelease; break; case TSS_PCRS_STRUCT_INFO_LONG: loc = &pcrs->info.infolong.localityAtRelease; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } *loc = locality; done: obj_list_put(&pcrs_list); return result; } TSS_RESULT obj_pcrs_set_digest_at_release(TSS_HPCRS hPcrs, TPM_COMPOSITE_HASH digest) { struct tsp_object *obj; struct tr_pcrs_obj *pcrs; TSS_RESULT result = TSS_SUCCESS; TPM_COMPOSITE_HASH *dig; LogDebugFn("######## Digest to be set on TSS object:"); LogDebugData(TCPA_SHA1_160_HASH_LEN, digest.digest); if ((obj = obj_list_get_obj(&pcrs_list, hPcrs)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); pcrs = (struct tr_pcrs_obj *)obj->data; switch(pcrs->type) { case TSS_PCRS_STRUCT_INFO: result = TSPERR(TSS_E_INVALID_OBJ_ACCESS); goto done; case TSS_PCRS_STRUCT_INFO_SHORT: dig = &pcrs->info.infoshort.digestAtRelease; break; case TSS_PCRS_STRUCT_INFO_LONG: dig = &pcrs->info.infolong.digestAtRelease; break; default: LogDebugFn("Undefined type of PCRs object"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } /* Copy the digest information */ memcpy(dig->digest,&digest.digest,TPM_SHA1_160_HASH_LEN); LogDebugFn("######## Digest SET on TSS object:"); LogDebugData(TCPA_SHA1_160_HASH_LEN,pcrs->info.infoshort.digestAtRelease.digest); done: obj_list_put(&pcrs_list); return result; } trousers-0.3.15/src/tspi/tspi_seal.c0000664000175000017510000002273313663651711016660 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "authsess.h" TSS_RESULT Tspi_Data_Seal(TSS_HENCDATA hEncData, /* in */ TSS_HKEY hEncKey, /* in */ UINT32 ulDataLength, /* in */ BYTE * rgbDataToSeal, /* in */ TSS_HPCRS hPcrComposite) /* in */ { TPM_DIGEST digest; TSS_RESULT result; TSS_HPOLICY hPolicy, hEncPolicy; BYTE *encData = NULL; BYTE *pcrData = NULL; UINT32 encDataSize; UINT32 pcrDataSize; UINT32 pcrInfoType = TSS_PCRS_STRUCT_DEFAULT; UINT32 sealOrdinal = TPM_ORD_Seal; TCS_KEY_HANDLE tcsKeyHandle; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; BYTE *sealData = NULL; struct authsess *xsap = NULL; #ifdef TSS_BUILD_SEALX UINT32 protectMode; #endif if (rgbDataToSeal == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_encdata_get_tsp_context(hEncData, &tspContext))) return result; if ((result = obj_rsakey_get_policy(hEncKey, TSS_POLICY_USAGE, &hPolicy, NULL))) return result; if ((result = obj_encdata_get_policy(hEncData, TSS_POLICY_USAGE, &hEncPolicy))) return result; if ((result = obj_rsakey_get_tcs_handle(hEncKey, &tcsKeyHandle))) return result; #ifdef TSS_BUILD_SEALX /* Get the TSS_TSPATTRIB_ENCDATASEAL_PROTECT_MODE attribute to determine the seal function to invoke */ if ((result = obj_encdata_get_seal_protect_mode(hEncData, &protectMode))) return result; if (protectMode == TSS_TSPATTRIB_ENCDATASEAL_NO_PROTECT) { sealOrdinal = TPM_ORD_Seal; pcrInfoType = 0; } else if (protectMode == TSS_TSPATTRIB_ENCDATASEAL_PROTECT) { sealOrdinal = TPM_ORD_Sealx; pcrInfoType = TSS_PCRS_STRUCT_INFO_LONG; } else return TSPERR(TSS_E_INTERNAL_ERROR); #endif /* If PCR's are of interest */ pcrDataSize = 0; if (hPcrComposite) { if ((result = obj_pcrs_create_info_type(hPcrComposite, &pcrInfoType, &pcrDataSize, &pcrData))) return result; } if ((result = authsess_xsap_init(tspContext, hEncKey, hEncData, TSS_AUTH_POLICY_REQUIRED, sealOrdinal, TPM_ET_KEYHANDLE, &xsap))) goto error; #ifdef TSS_BUILD_SEALX if (sealOrdinal == TPM_ORD_Seal) sealData = rgbDataToSeal; else { if ((sealData = (BYTE *)calloc(1, ulDataLength)) == NULL) { LogError("malloc of %u bytes failed", ulDataLength); result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } if ((result = ((TSS_RESULT (*)(PVOID, TSS_HKEY, TSS_HENCDATA, TSS_ALGORITHM_ID, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *))xsap->cb_sealx.callback)(xsap->cb_sealx.appData, hEncKey, hEncData, xsap->cb_sealx.alg, sizeof(TPM_NONCE), xsap->auth.NonceEven.nonce, xsap->auth.NonceOdd.nonce, xsap->nonceEvenxSAP.nonce, xsap->nonceOddxSAP.nonce, ulDataLength, rgbDataToSeal, sealData))) goto error; } #else sealData = rgbDataToSeal; #endif result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, sealOrdinal); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); result |= Trspi_Hash_UINT32(&hashCtx, pcrDataSize); result |= Trspi_HashUpdate(&hashCtx, pcrDataSize, pcrData); result |= Trspi_Hash_UINT32(&hashCtx, ulDataLength); result |= Trspi_HashUpdate(&hashCtx, ulDataLength, sealData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { goto error; } if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; #ifdef TSS_BUILD_SEALX if (sealOrdinal == TPM_ORD_Seal) { if ((result = TCS_API(tspContext)->Seal(tspContext, tcsKeyHandle, &xsap->encAuthUse, pcrDataSize, pcrData, ulDataLength, sealData, xsap->pAuth, &encDataSize, &encData))) { goto error; } } else if (sealOrdinal == TPM_ORD_Sealx) { if ((result = TCS_API(tspContext)->Sealx(tspContext, tcsKeyHandle, &xsap->encAuthUse, pcrDataSize, pcrData, ulDataLength, sealData, xsap->pAuth, &encDataSize, &encData))) { goto error; } } else { result = TSPERR(TSS_E_INTERNAL_ERROR); goto error; } #else if ((result = TCS_API(tspContext)->Seal(tspContext, tcsKeyHandle, &xsap->encAuthUse, pcrDataSize, pcrData, ulDataLength, sealData, xsap->pAuth, &encDataSize, &encData))) goto error; #endif result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, sealOrdinal); result |= Trspi_HashUpdate(&hashCtx, encDataSize, encData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_verify(xsap, &digest))) goto error; /* Need to set the object with the blob and the pcr's */ if ((result = obj_encdata_set_data(hEncData, encDataSize, encData))) goto error; if (pcrDataSize) result = obj_encdata_set_pcr_info(hEncData, pcrInfoType, pcrData); error: authsess_free(xsap); free(encData); free(pcrData); if (sealData != rgbDataToSeal) free(sealData); return result; } TSS_RESULT Tspi_Data_Unseal(TSS_HENCDATA hEncData, /* in */ TSS_HKEY hKey, /* in */ UINT32 * pulUnsealedDataLength,/* out */ BYTE ** prgbUnsealedData) /* out */ { UINT64 offset; TPM_AUTH privAuth2; TPM_DIGEST digest; TPM_NONCE authLastNonceEven; TSS_RESULT result; TSS_HPOLICY hPolicy, hEncPolicy; TCS_KEY_HANDLE tcsKeyHandle; TSS_HCONTEXT tspContext; UINT32 ulDataLen, unSealedDataLen; BYTE *data = NULL, *unSealedData = NULL, *maskedData; UINT16 mask; Trspi_HashCtx hashCtx; struct authsess *xsap = NULL; if (pulUnsealedDataLength == NULL || prgbUnsealedData == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_encdata_get_tsp_context(hEncData, &tspContext))) return result; if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hPolicy, NULL))) return result; if ((result = obj_encdata_get_policy(hEncData, TSS_POLICY_USAGE, &hEncPolicy))) return result; if ((result = obj_encdata_get_data(hEncData, &ulDataLen, &data))) return result == (TSS_E_INVALID_OBJ_ACCESS | TSS_LAYER_TSP) ? TSPERR(TSS_E_ENC_NO_DATA) : result; offset = 0; Trspi_UnloadBlob_UINT16(&offset, &mask, data); if (mask == TPM_TAG_STORED_DATA12) { /* The second UINT16 in a TPM_STORED_DATA12 is the entity type. If its non-zero * then we must unmask the unsealed data after it returns from the TCS */ Trspi_UnloadBlob_UINT16(&offset, &mask, data); } else mask = 0; if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKeyHandle))) goto error; if ((result = authsess_xsap_init(tspContext, hKey, hEncData, TSS_AUTH_POLICY_REQUIRED, TPM_ORD_Unseal, TPM_ET_KEYHANDLE, &xsap))) goto error; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Unseal); result |= Trspi_HashUpdate(&hashCtx, ulDataLen, data); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; if ((result = secret_PerformAuth_OIAP(hEncData, TPM_ORD_Unseal, hEncPolicy, FALSE, &digest, &privAuth2))) goto error; if (mask) { /* save off last nonce even to pass to sealx callback */ memcpy(authLastNonceEven.nonce, xsap->auth.NonceEven.nonce, sizeof(TPM_NONCE)); } if ((result = TCS_API(tspContext)->Unseal(tspContext, tcsKeyHandle, ulDataLen, data, xsap->pAuth, &privAuth2, &unSealedDataLen, &unSealedData))) goto error; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Unseal); result |= Trspi_Hash_UINT32(&hashCtx, unSealedDataLen); result |= Trspi_HashUpdate(&hashCtx, unSealedDataLen, unSealedData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free(unSealedData); goto error; } if ((result = authsess_xsap_verify(xsap, &digest))) { free(unSealedData); goto error; } if ((result = obj_policy_validate_auth_oiap(hEncPolicy, &digest, &privAuth2))) { free(unSealedData); goto error; } /* If the data is masked, use the callback set up in authsess_xsap_init */ if (mask) { maskedData = unSealedData; if ((unSealedData = calloc_tspi(tspContext, unSealedDataLen)) == NULL) { free(maskedData); LogError("malloc of %u bytes failed", unSealedDataLen); result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } /* XXX pass in out saved-off authLastNonceEven. This conflicts with the * description of the rgbNonceEven parameter in the spec, but without it, its not * possible to compute the MGF1 key */ if ((result = ((TSS_RESULT (*)(PVOID, TSS_HKEY, TSS_HENCDATA, TSS_ALGORITHM_ID, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *))xsap->cb_sealx.callback)(xsap->cb_sealx.appData, hKey, hEncData, xsap->cb_sealx.alg, sizeof(TPM_NONCE), authLastNonceEven.nonce, xsap->auth.NonceOdd.nonce, xsap->nonceEvenxSAP.nonce, xsap->nonceOddxSAP.nonce, unSealedDataLen, maskedData, unSealedData))) { free(maskedData); goto error; } free(maskedData); } else { if ((result = __tspi_add_mem_entry(tspContext, unSealedData))) goto error; } *pulUnsealedDataLength = unSealedDataLen; *prgbUnsealedData = unSealedData; error: authsess_free(xsap); if (data) free_tspi(tspContext, data); return result; } trousers-0.3.15/src/tspi/tsp_counter.c0000664000175000017510000000235213663651711017235 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_ReadCounter(TSS_HCONTEXT tspContext, /* in */ TSS_COUNTER_ID idCounter, /* in */ TPM_COUNTER_VALUE* counterValue) /* out */ { TSS_RESULT result; UINT32 decLen = 0; BYTE *dec = NULL; UINT64 offset; TCS_HANDLE handlesLen = 0; BYTE data[sizeof(UINT32)]; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, idCounter, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_ReadCounter, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_COUNTER_VALUE(&offset, dec, counterValue); free(dec); return TSS_SUCCESS; } #endif trousers-0.3.15/src/tspi/tspi_nv.c0000664000175000017510000004020413663651711016350 0ustar deboradebora/* * The Initial Developer of the Original Code is Intel Corporation. * Portions created by Intel Corporation are Copyright (C) 2007 Intel Corporation. * All Rights Reserved. * * trousers - An open source TCG Software Stack * * Author: james.xu@intel.com Rossey.liu@intel.com * * Kent Yoder - updates for new authsession mechanism * (C) International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "authsess.h" TSS_RESULT Tspi_NV_DefineSpace(TSS_HNVSTORE hNvstore, /* in */ TSS_HPCRS hReadPcrComposite, /* in, may be NULL */ TSS_HPCRS hWritePcrComposite) /* in, may be NULL*/ { TSS_HCONTEXT tspContext; TSS_HTPM hTpm; TSS_RESULT result; UINT32 uiResultLen; BYTE *pResult; UINT32 i; TPM_BOOL defined_index = FALSE; NV_DATA_PUBLIC nv_data_public; TSS_BOOL need_authdata = FALSE; TCPA_DIGEST digest; BYTE *pReadPCR; UINT32 pReadPCR_len; BYTE *pWritePCR; UINT32 pWritePCR_len; UINT64 NVPublic_DataSize; BYTE NVPublicData[MAX_PUBLIC_DATA_SIZE]; Trspi_HashCtx hashCtx; struct authsess *xsap = NULL; if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; __tspi_memset(&nv_data_public, 0, sizeof(NV_DATA_PUBLIC)); if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex))) return result; if ((result = obj_nvstore_get_datasize(hNvstore, &nv_data_public.dataSize))) return result; if ((result = obj_nvstore_get_permission(hNvstore, &nv_data_public.permission.attributes))) return result; if ((result = obj_tpm_get(tspContext, &hTpm))) return result; if((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_LIST, 0, NULL, &uiResultLen, &pResult))) return result; for (i = 0; i < uiResultLen/sizeof(UINT32); i++) { if (nv_data_public.nvIndex == Decode_UINT32(pResult + i * sizeof(UINT32))) { defined_index = TRUE; break; } } free_tspi(tspContext, pResult); if (defined_index) { result = TSPERR(TSS_E_NV_AREA_EXIST); return result; } need_authdata = (nv_data_public.permission.attributes & (TPM_NV_PER_AUTHREAD |TPM_NV_PER_AUTHWRITE)) ? TRUE : FALSE; nv_data_public.tag = TPM_TAG_NV_DATA_PUBLIC; if ((result = obj_nvstore_create_pcrshortinfo(hNvstore, hReadPcrComposite, &pReadPCR_len, &pReadPCR))) return result; if ((result = obj_nvstore_create_pcrshortinfo(hNvstore, hWritePcrComposite, &pWritePCR_len, &pWritePCR))) { free_tspi(tspContext, pReadPCR); return result; } NVPublic_DataSize = 0; Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_DATA_PUBLIC, NVPublicData); Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.nvIndex, NVPublicData); Trspi_LoadBlob(&NVPublic_DataSize, pReadPCR_len, NVPublicData, pReadPCR); Trspi_LoadBlob(&NVPublic_DataSize, pWritePCR_len, NVPublicData, pWritePCR); Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_ATTRIBUTES, NVPublicData); Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.permission.attributes, NVPublicData); Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bReadSTClear, NVPublicData); Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteSTClear, NVPublicData); Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteDefine, NVPublicData); Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.dataSize, NVPublicData); free_tspi(tspContext, pReadPCR); free_tspi(tspContext, pWritePCR); if ((result = authsess_xsap_init(tspContext, hTpm, hNvstore, need_authdata, TPM_ORD_NV_DefineSpace, TPM_ET_OWNER, &xsap))) { if (result == TSPERR(TSS_E_TSP_AUTHREQUIRED)) result = TSS_ERROR_CODE(TSS_E_BAD_PARAMETER); return result; } result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace); result |= Trspi_HashUpdate(&hashCtx, NVPublic_DataSize, NVPublicData); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; if ((result = TCS_API(tspContext)->NV_DefineOrReleaseSpace(tspContext, NVPublic_DataSize, NVPublicData, xsap->encAuthUse, xsap->pAuth))) goto error; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; result = authsess_xsap_verify(xsap, &digest); error: authsess_free(xsap); return result; } TSS_RESULT Tspi_NV_ReleaseSpace(TSS_HNVSTORE hNvstore) /* in */ { TSS_HCONTEXT tspContext; TSS_HTPM hTpm; TSS_RESULT result; UINT32 uiResultLen; BYTE *pResult; UINT32 i; TPM_BOOL defined_index = FALSE; NV_DATA_PUBLIC nv_data_public; TCPA_DIGEST digest; BYTE *pPCR; UINT32 pPCR_len; UINT64 NVPublic_DataSize; BYTE NVPublicData[MAX_PUBLIC_DATA_SIZE]; Trspi_HashCtx hashCtx; struct authsess *xsap = NULL; __tspi_memset(&nv_data_public, 0, sizeof(NV_DATA_PUBLIC)); if ((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex))) return result; if ((result = obj_nvstore_get_datasize(hNvstore, &nv_data_public.dataSize))) return result; if ((result = obj_nvstore_get_permission(hNvstore, &nv_data_public.permission.attributes))) return result; if ((result = obj_tpm_get(tspContext, &hTpm))) return result; if((result = Tspi_TPM_GetCapability(hTpm, TSS_TPMCAP_NV_LIST, 0, NULL, &uiResultLen, &pResult))) return result; for (i = 0; i < uiResultLen/sizeof(UINT32); i++) { if (nv_data_public.nvIndex == Decode_UINT32(pResult + i * sizeof(UINT32))) { defined_index = TRUE; break; } } free_tspi(tspContext, pResult); if (!defined_index) { result = TSPERR(TSS_E_NV_AREA_NOT_EXIST); return result; } nv_data_public.tag = TPM_TAG_NV_DATA_PUBLIC; if ((result = obj_nvstore_create_pcrshortinfo(hNvstore, NULL_HPCRS, &pPCR_len, &pPCR))) return result; NVPublic_DataSize = 0; Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_DATA_PUBLIC, NVPublicData); Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.nvIndex, NVPublicData); /* load the read pcr short info */ Trspi_LoadBlob(&NVPublic_DataSize, pPCR_len, NVPublicData, pPCR); /* load the write pcr short info */ Trspi_LoadBlob(&NVPublic_DataSize, pPCR_len, NVPublicData, pPCR); Trspi_LoadBlob_UINT16(&NVPublic_DataSize, TPM_TAG_NV_ATTRIBUTES, NVPublicData); Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.permission.attributes, NVPublicData); Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bReadSTClear, NVPublicData); Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteSTClear, NVPublicData); Trspi_LoadBlob_BOOL(&NVPublic_DataSize, nv_data_public.bWriteDefine, NVPublicData); /*Trspi_LoadBlob_UINT32(&NVPublic_DataSize, nv_data_public.dataSize, NVPublicData);*/ Trspi_LoadBlob_UINT32(&NVPublic_DataSize, 0, NVPublicData); free_tspi(tspContext, pPCR); if ((result = authsess_xsap_init(tspContext, hTpm, hNvstore, TSS_AUTH_POLICY_NOT_REQUIRED, TPM_ORD_NV_DefineSpace, TPM_ET_OWNER, &xsap))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace); result |= Trspi_HashUpdate(&hashCtx, NVPublic_DataSize, NVPublicData); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; if ((result = authsess_xsap_hmac(xsap, &digest))) goto error; if ((result = TCS_API(tspContext)->NV_DefineOrReleaseSpace(tspContext, NVPublic_DataSize, NVPublicData, xsap->encAuthUse, xsap->pAuth))) goto error; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_DefineSpace); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto error; result = authsess_xsap_verify(xsap, &digest); error: authsess_free(xsap); return result; } TSS_RESULT Tspi_NV_WriteValue(TSS_HNVSTORE hNvstore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite) /* in */ { TSS_HCONTEXT tspContext; TSS_HTPM hTpm; TSS_RESULT result; NV_DATA_PUBLIC nv_data_public; UINT32 need_authdata = 0; UINT32 authwrite =0; TSS_HPOLICY hPolicy; TPM_AUTH auth; TCPA_DIGEST digest; Trspi_HashCtx hashCtx; if ((ulDataLength != 0) && (rgbDataToWrite == NULL)) return TSPERR(TSS_E_BAD_PARAMETER); if((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; if ((result = obj_tpm_get(tspContext, &hTpm))) return result; if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex))) return result; if ((result = obj_nvstore_get_policy(hNvstore, TSS_POLICY_USAGE, &hPolicy))) return result; if (hPolicy) { if ((result = obj_nvstore_get_permission_from_tpm(hNvstore, &nv_data_public.permission.attributes))) return result; need_authdata = nv_data_public.permission.attributes & (TPM_NV_PER_AUTHWRITE | TPM_NV_PER_OWNERWRITE); authwrite = nv_data_public.permission.attributes & TPM_NV_PER_AUTHWRITE; if (need_authdata) { if (!authwrite) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValue); result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex); result |= Trspi_Hash_UINT32(&hashCtx, offset); result |= Trspi_Hash_UINT32(&hashCtx, ulDataLength); result |= Trspi_HashUpdate(&hashCtx, ulDataLength, rgbDataToWrite); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hNvstore, TPM_ORD_NV_WriteValue, hPolicy, FALSE, &digest, &auth))) return result; if ((result = TCS_API(tspContext)->NV_WriteValue(tspContext, nv_data_public.nvIndex, offset, ulDataLength, rgbDataToWrite, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValue); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) return result; } else { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValueAuth); result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex); result |= Trspi_Hash_UINT32(&hashCtx, offset); result |= Trspi_Hash_UINT32(&hashCtx, ulDataLength); result |= Trspi_HashUpdate(&hashCtx, ulDataLength, rgbDataToWrite); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hNvstore, TPM_ORD_NV_WriteValueAuth, hPolicy, FALSE, &digest, &auth))) return result; if ((result = TCS_API(tspContext)->NV_WriteValueAuth(tspContext, nv_data_public.nvIndex, offset, ulDataLength, rgbDataToWrite, &auth))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_WriteValueAuth); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) return result; } } else { if ((result = TCS_API(tspContext)->NV_WriteValue(tspContext, nv_data_public.nvIndex, offset, ulDataLength, rgbDataToWrite, NULL))) return result; } } else { LogDebug("no policy, so noauthentication"); if ((result = TCS_API(tspContext)->NV_WriteValue(tspContext, nv_data_public.nvIndex, offset, ulDataLength, rgbDataToWrite, NULL))) return result; } return result; } TSS_RESULT Tspi_NV_ReadValue(TSS_HNVSTORE hNvstore, /* in */ UINT32 offset, /* in */ UINT32* ulDataLength, /* in, out */ BYTE** rgbDataRead) /* out */ { TSS_HCONTEXT tspContext; TSS_HTPM hTpm; TSS_RESULT result; NV_DATA_PUBLIC nv_data_public; UINT32 need_authdata = 0; UINT32 authread =0; TSS_HPOLICY hPolicy; TPM_AUTH auth; TCPA_DIGEST digest; Trspi_HashCtx hashCtx; if (ulDataLength == NULL || rgbDataRead == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if((result = obj_nvstore_get_tsp_context(hNvstore, &tspContext))) return result; if ((result = obj_tpm_get(tspContext, &hTpm))) return result; if ((result = obj_nvstore_get_index(hNvstore, &nv_data_public.nvIndex))) return result; if ((result = obj_nvstore_get_policy(hNvstore, TSS_POLICY_USAGE, &hPolicy))) return result; if (hPolicy) {/*if the policy secret is set*/ if ((result = obj_nvstore_get_permission_from_tpm(hNvstore, &nv_data_public.permission.attributes))) return result; need_authdata = nv_data_public.permission.attributes & (TPM_NV_PER_AUTHREAD | TPM_NV_PER_OWNERREAD); authread = nv_data_public.permission.attributes & TPM_NV_PER_AUTHREAD; if (need_authdata) { if (!authread) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValue); result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex); result |= Trspi_Hash_UINT32(&hashCtx, offset); result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hNvstore, TPM_ORD_NV_ReadValue, hPolicy, FALSE, &digest, &auth))) return result; if ((result = TCS_API(tspContext)->NV_ReadValue(tspContext, nv_data_public.nvIndex, offset, ulDataLength, &auth, rgbDataRead))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValue); result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength); result |= Trspi_HashUpdate(&hashCtx, *ulDataLength, *rgbDataRead); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) return result; } else { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValueAuth); result |= Trspi_Hash_UINT32(&hashCtx, nv_data_public.nvIndex); result |= Trspi_Hash_UINT32(&hashCtx, offset); result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hNvstore, TPM_ORD_NV_ReadValueAuth, hPolicy, FALSE, &digest, &auth))) return result; if ((result = TCS_API(tspContext)->NV_ReadValueAuth(tspContext, nv_data_public.nvIndex, offset, ulDataLength, &auth, rgbDataRead))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_NV_ReadValueAuth); result |= Trspi_Hash_UINT32(&hashCtx, *ulDataLength); result |= Trspi_HashUpdate(&hashCtx, *ulDataLength, *rgbDataRead); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth))) return result; } } else { if ((result = TCS_API(tspContext)->NV_ReadValue(tspContext, nv_data_public.nvIndex, offset, ulDataLength, NULL, rgbDataRead))) return result; } } else { if ((result = TCS_API(tspContext)->NV_ReadValue(tspContext, nv_data_public.nvIndex, offset, ulDataLength, NULL, rgbDataRead))) return result; } return result; } trousers-0.3.15/src/tspi/tspi_certify.c0000664000175000017510000001154213663651711017375 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_Key_CertifyKey(TSS_HKEY hKey, /* in */ TSS_HKEY hCertifyingKey, /* in */ TSS_VALIDATION * pValidationData) /* in, out */ { TCPA_RESULT result; TPM_AUTH certAuth; TPM_AUTH keyAuth; TCPA_DIGEST digest; TCPA_NONCE antiReplay; UINT32 CertifyInfoSize; BYTE *CertifyInfo; UINT32 outDataSize; BYTE *outData; TSS_HPOLICY hPolicy; TSS_HPOLICY hCertPolicy; TCS_KEY_HANDLE certifyTCSKeyHandle, keyTCSKeyHandle; TSS_BOOL useAuthCert; TSS_BOOL useAuthKey; TPM_AUTH *pCertAuth = &certAuth; TPM_AUTH *pKeyAuth = &keyAuth; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext))) return result; if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hPolicy, &useAuthKey))) return result; if ((result = obj_rsakey_get_policy(hCertifyingKey, TSS_POLICY_USAGE, &hCertPolicy, &useAuthCert))) return result; if ((result = obj_rsakey_get_tcs_handle(hCertifyingKey, &certifyTCSKeyHandle))) return result; if ((result = obj_rsakey_get_tcs_handle(hKey, &keyTCSKeyHandle))) return result; if (pValidationData == NULL) { LogDebug("Internal Verify"); if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), (BYTE **)antiReplay.nonce))) return result; } else { LogDebug("External Verify"); if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); } if (useAuthCert && !useAuthKey) return TSPERR(TSS_E_BAD_PARAMETER); /* Setup the auths */ if (useAuthCert || useAuthKey) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CertifyKey); result |= Trspi_HashUpdate(&hashCtx, sizeof(antiReplay.nonce), antiReplay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; } if (useAuthKey) { if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_CertifyKey, hPolicy, FALSE, &digest, &keyAuth))) return result; } else pKeyAuth = NULL; if (useAuthCert) { if ((result = secret_PerformAuth_OIAP(hCertifyingKey, TPM_ORD_CertifyKey, hCertPolicy, FALSE, &digest, &certAuth))) return result; } else pCertAuth = NULL; /* XXX free CertifyInfo */ if ((result = TCS_API(tspContext)->CertifyKey(tspContext, certifyTCSKeyHandle, keyTCSKeyHandle, &antiReplay, pCertAuth, pKeyAuth, &CertifyInfoSize, &CertifyInfo, &outDataSize, &outData))) return result; /* Validate auth */ if (useAuthCert || useAuthKey) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CertifyKey); result |= Trspi_HashUpdate(&hashCtx, CertifyInfoSize, CertifyInfo); result |= Trspi_Hash_UINT32(&hashCtx, outDataSize); result |= Trspi_HashUpdate(&hashCtx, outDataSize, outData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto cleanup; if (useAuthKey) if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &keyAuth))) goto cleanup; if (useAuthCert) if ((result = obj_policy_validate_auth_oiap(hCertPolicy, &digest, &certAuth))) goto cleanup; } if (pValidationData == NULL) { if ((result = Trspi_Hash(TSS_HASH_SHA1, CertifyInfoSize, CertifyInfo, digest.digest))) goto cleanup; if ((result = __tspi_rsa_verify(hCertifyingKey, TSS_HASH_SHA1, TPM_SHA1_160_HASH_LEN, digest.digest, outDataSize, outData))){ result = TSPERR(TSS_E_VERIFICATION_FAILED); goto cleanup; } } else { pValidationData->ulDataLength = CertifyInfoSize; pValidationData->rgbData = calloc_tspi(tspContext, CertifyInfoSize); if (pValidationData->rgbData == NULL) { LogError("malloc of %u bytes failed.", CertifyInfoSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto cleanup; } memcpy(pValidationData->rgbData, CertifyInfo, CertifyInfoSize); pValidationData->ulValidationDataLength = outDataSize; pValidationData->rgbValidationData = calloc_tspi(tspContext, outDataSize); if (pValidationData->rgbValidationData == NULL) { LogError("malloc of %u bytes failed.", outDataSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto cleanup; } memcpy(pValidationData->rgbValidationData, outData, outDataSize); } result = TSS_SUCCESS; cleanup: free(CertifyInfo); free(outData); return result; } trousers-0.3.15/src/tspi/obj_migdata.c0000664000175000017510000006777513663651711017154 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" void migdata_free(void *data) { struct tr_migdata_obj *migdata = (struct tr_migdata_obj *)data; free(migdata); } TSS_BOOL obj_is_migdata(TSS_HOBJECT hObject) { TSS_BOOL answer = FALSE; if ((obj_list_get_obj(&migdata_list, hObject))) { answer = TRUE; obj_list_put(&migdata_list); } return answer; } TSS_RESULT obj_migdata_add(TSS_HCONTEXT hContext, TSS_HOBJECT *phObject) { TSS_RESULT result; struct tr_migdata_obj *migdata = calloc(1, sizeof(struct tr_migdata_obj)); if (migdata == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tr_migdata_obj)); return TSPERR(TSS_E_OUTOFMEMORY); } if ((result = obj_list_add(&migdata_list, hContext, 0, migdata, phObject))) { free(migdata); return result; } return TSS_SUCCESS; } TSS_RESULT obj_migdata_remove(TSS_HMIGDATA hMigData, TSS_HCONTEXT hContext) { TSS_RESULT result; if ((result = obj_list_remove(&migdata_list, &migdata_free, hMigData, hContext))) return result; return TSS_SUCCESS; } TSS_RESULT obj_migdata_get_tsp_context(TSS_HMIGDATA hMigData, TSS_HCONTEXT *hContext) { struct tsp_object *obj; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); *hContext = obj->tspContext; obj_list_put(&migdata_list); return TSS_SUCCESS; } TSS_RESULT obj_migdata_set_migrationblob(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 blobSize, BYTE *blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_MIG_MSALIST_PUBKEY_BLOB: result = obj_migdata_set_msa_pubkey(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_MIG_AUTHORITY_PUBKEY_BLOB: result = obj_migdata_set_ma_pubkey(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_MIG_DESTINATION_PUBKEY_BLOB: result = obj_migdata_set_dest_pubkey(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_MIG_SOURCE_PUBKEY_BLOB: result = obj_migdata_set_src_pubkey(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_get_migrationblob(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 *blobSize, BYTE **blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_MIG_XOR_BLOB: result = obj_migdata_get_blob(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_set_authoritydata(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 blobSize, BYTE *blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_AUTHORITY_DIGEST: result = obj_migdata_set_msa_digest(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_AUTHORITY_APPROVAL_HMAC: result = obj_migdata_set_msa_hmac(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_AUTHORITY_MSALIST: result = obj_migdata_set_msa_list(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_get_authoritydata(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 *blobSize, BYTE **blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_AUTHORITY_DIGEST: result = obj_migdata_get_msa_digest(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_AUTHORITY_APPROVAL_HMAC: result = obj_migdata_get_msa_hmac(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_AUTHORITY_MSALIST: result = obj_migdata_get_msa_list(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_set_migauthdata(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 blobSize, BYTE *blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_MIG_AUTH_AUTHORITY_DIGEST: result = obj_migdata_set_ma_digest(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_MIG_AUTH_DESTINATION_DIGEST: result = obj_migdata_set_dest_digest(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_MIG_AUTH_SOURCE_DIGEST: result = obj_migdata_set_src_digest(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_get_migauthdata(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 *blobSize, BYTE **blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_MIG_AUTH_AUTHORITY_DIGEST: result = obj_migdata_get_ma_digest(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_MIG_AUTH_DESTINATION_DIGEST: result = obj_migdata_get_dest_digest(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_MIG_AUTH_SOURCE_DIGEST: result = obj_migdata_get_src_digest(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_set_ticketdata(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 blobSize, BYTE *blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_TICKET_SIG_DIGEST: result = obj_migdata_set_sig_data(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_TICKET_SIG_VALUE: result = obj_migdata_set_sig_value(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_TICKET_SIG_TICKET: result = obj_migdata_set_sig_ticket(hMigData, blobSize, blob); break; case TSS_MIGATTRIB_TICKET_RESTRICT_TICKET: result = obj_migdata_set_cmk_auth(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_get_ticketdata(TSS_HMIGDATA hMigData, UINT32 whichOne, UINT32 *blobSize, BYTE **blob) { TSS_RESULT result; switch (whichOne) { case TSS_MIGATTRIB_TICKET_SIG_TICKET: result = obj_migdata_get_sig_ticket(hMigData, blobSize, blob); break; default: result = TSPERR(TSS_E_BAD_PARAMETER); } return result; } TSS_RESULT obj_migdata_set_ticket_blob(TSS_HMIGDATA hMigData, UINT32 migTicketSize, BYTE *migTicket) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; migdata->migTicketSize = 0; free(migdata->migTicket); if ((migdata->migTicket = malloc(migTicketSize)) == NULL) { LogError("malloc of %u bytes failed.", migTicketSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(migdata->migTicket, migTicket, migTicketSize); migdata->migTicketSize = migTicketSize; done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_ticket_blob(TSS_HMIGDATA hMigData, UINT32 *migTicketSize, BYTE **migTicket) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*migTicket = calloc_tspi(obj->tspContext, migdata->migTicketSize)) == NULL) { LogError("malloc of %u bytes failed.", migdata->migTicketSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*migTicket, migdata->migTicket, migdata->migTicketSize); *migTicketSize = migdata->migTicketSize; done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_msa_list(TSS_HMIGDATA hMigData, UINT32 msaListSize, BYTE *msaList) { struct tsp_object *obj; struct tr_migdata_obj *migdata; UINT32 i, count, size; TPM_DIGEST *digest; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; count = msaListSize / sizeof(digest->digest); size = count * sizeof(*digest); migdata->msaList.MSAlist = 0; free(migdata->msaList.migAuthDigest); if ((migdata->msaList.migAuthDigest = malloc(size)) == NULL) { LogError("malloc of %u bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } digest = migdata->msaList.migAuthDigest; for (i = 0; i < count; i++) { memcpy(digest->digest, msaList, sizeof(digest->digest)); msaList += sizeof(digest->digest); digest++; } migdata->msaList.MSAlist = count; result = obj_migdata_calc_msa_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_msa_list(TSS_HMIGDATA hMigData, UINT32 *size, BYTE **msaList) { struct tsp_object *obj; struct tr_migdata_obj *migdata; UINT32 i; TPM_DIGEST *digest; BYTE *tmpMsaList; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; *size = migdata->msaList.MSAlist * sizeof(migdata->msaList.migAuthDigest->digest); if ((*msaList = calloc_tspi(obj->tspContext, *size)) == NULL) { LogError("malloc of %u bytes failed.", *size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } tmpMsaList = *msaList; digest = migdata->msaList.migAuthDigest; for (i = 0; i < migdata->msaList.MSAlist; i++) { memcpy(tmpMsaList, digest->digest, sizeof(digest->digest)); tmpMsaList += sizeof(digest->digest); digest++; } done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_msa_pubkey(TSS_HMIGDATA hMigData, UINT32 blobSize, BYTE *pubKeyBlob) { struct tsp_object *obj; struct tr_migdata_obj *migdata; UINT32 size; TPM_DIGEST msaDigest; TPM_DIGEST *digest; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((result = obj_migdata_calc_pubkey_digest(blobSize, pubKeyBlob, &msaDigest))) goto done; size = (migdata->msaList.MSAlist + 1) * sizeof(*digest); if ((migdata->msaList.migAuthDigest = realloc(migdata->msaList.migAuthDigest, size)) == NULL) { LogError("malloc of %u bytes failed.", size); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } digest = migdata->msaList.migAuthDigest + migdata->msaList.MSAlist; *digest = msaDigest; migdata->msaList.MSAlist++; result = obj_migdata_calc_msa_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_msa_digest(TSS_HMIGDATA hMigData, UINT32 digestSize, BYTE *digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (digestSize != sizeof(migdata->msaDigest.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->msaDigest.digest, digest, sizeof(migdata->msaDigest.digest)); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_msa_digest(TSS_HMIGDATA hMigData, UINT32 *digestSize, BYTE **digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*digest = calloc_tspi(obj->tspContext, sizeof(migdata->msaDigest.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(migdata->msaDigest.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*digest, migdata->msaDigest.digest, sizeof(migdata->msaDigest.digest)); *digestSize = sizeof(migdata->msaDigest.digest); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_msa_list_blob(TSS_HMIGDATA hMigData, UINT32 *blobSize, BYTE **msaListBlob) { struct tsp_object *obj; struct tr_migdata_obj *migdata; UINT64 offset; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; offset = 0; Trspi_LoadBlob_MSA_COMPOSITE(&offset, NULL, &migdata->msaList); *blobSize = offset; if ((*msaListBlob = calloc_tspi(obj->tspContext, *blobSize)) == NULL) { LogError("malloc of %u bytes failed.", *blobSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_MSA_COMPOSITE(&offset, *msaListBlob, &migdata->msaList); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_msa_hmac(TSS_HMIGDATA hMigData, UINT32 hmacSize, BYTE *hmac) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (hmacSize != sizeof(migdata->msaHmac.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->msaHmac.digest, hmac, sizeof(migdata->msaHmac.digest)); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_msa_hmac(TSS_HMIGDATA hMigData, UINT32 *hmacSize, BYTE **hmac) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*hmac = calloc_tspi(obj->tspContext, sizeof(migdata->msaHmac.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(migdata->msaHmac.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*hmac, migdata->msaHmac.digest, sizeof(migdata->msaHmac.digest)); *hmacSize = sizeof(migdata->msaHmac.digest); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_ma_pubkey(TSS_HMIGDATA hMigData, UINT32 blobSize, BYTE *pubKeyBlob) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TPM_DIGEST pubKeyDigest; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((result = obj_migdata_calc_pubkey_digest(blobSize, pubKeyBlob, &pubKeyDigest))) goto done; migdata->maDigest = pubKeyDigest; obj_migdata_calc_sig_data_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_ma_digest(TSS_HMIGDATA hMigData, UINT32 digestSize, BYTE *digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (digestSize != sizeof(migdata->maDigest.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->maDigest.digest, digest, sizeof(migdata->maDigest.digest)); obj_migdata_calc_sig_data_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_ma_digest(TSS_HMIGDATA hMigData, UINT32 *digestSize, BYTE **digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*digest = calloc_tspi(obj->tspContext, sizeof(migdata->maDigest.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(migdata->maDigest.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*digest, migdata->maDigest.digest, sizeof(migdata->maDigest.digest)); *digestSize = sizeof(migdata->maDigest.digest); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_dest_pubkey(TSS_HMIGDATA hMigData, UINT32 blobSize, BYTE *pubKeyBlob) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TPM_DIGEST pubKeyDigest; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((result = obj_migdata_calc_pubkey_digest(blobSize, pubKeyBlob, &pubKeyDigest))) goto done; migdata->destDigest = pubKeyDigest; obj_migdata_calc_sig_data_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_dest_digest(TSS_HMIGDATA hMigData, UINT32 digestSize, BYTE *digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (digestSize != sizeof(migdata->destDigest.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->destDigest.digest, digest, sizeof(migdata->destDigest.digest)); obj_migdata_calc_sig_data_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_dest_digest(TSS_HMIGDATA hMigData, UINT32 *digestSize, BYTE **digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*digest = calloc_tspi(obj->tspContext, sizeof(migdata->destDigest.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(migdata->destDigest.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*digest, migdata->destDigest.digest, sizeof(migdata->destDigest.digest)); *digestSize = sizeof(migdata->destDigest.digest); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_src_pubkey(TSS_HMIGDATA hMigData, UINT32 blobSize, BYTE *pubKeyBlob) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TPM_DIGEST pubKeyDigest; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((result = obj_migdata_calc_pubkey_digest(blobSize, pubKeyBlob, &pubKeyDigest))) goto done; migdata->srcDigest = pubKeyDigest; obj_migdata_calc_sig_data_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_src_digest(TSS_HMIGDATA hMigData, UINT32 digestSize, BYTE *digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (digestSize != sizeof(migdata->srcDigest.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->srcDigest.digest, digest, sizeof(migdata->srcDigest.digest)); obj_migdata_calc_sig_data_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_src_digest(TSS_HMIGDATA hMigData, UINT32 *digestSize, BYTE **digest) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*digest = calloc_tspi(obj->tspContext, sizeof(migdata->srcDigest.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(migdata->srcDigest.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*digest, migdata->srcDigest.digest, sizeof(migdata->srcDigest.digest)); *digestSize = sizeof(migdata->srcDigest.digest); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_cmk_auth(TSS_HMIGDATA hMigData, UINT32 digestsSize, BYTE *digests) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (digestsSize != (sizeof(migdata->maDigest.digest) + sizeof(migdata->destDigest.digest) + sizeof(migdata->srcDigest.digest))) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->maDigest.digest, digests, sizeof(migdata->maDigest.digest)); digests += sizeof(migdata->maDigest.digest); memcpy(migdata->destDigest.digest, digests, sizeof(migdata->destDigest.digest)); digests += sizeof(migdata->destDigest.digest); memcpy(migdata->srcDigest.digest, digests, sizeof(migdata->srcDigest.digest)); obj_migdata_calc_sig_data_digest(migdata); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_cmk_auth(TSS_HMIGDATA hMigData, TPM_CMK_AUTH *cmkAuth) { struct tsp_object *obj; struct tr_migdata_obj *migdata; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; cmkAuth->migrationAuthorityDigest = migdata->maDigest; cmkAuth->destinationKeyDigest = migdata->destDigest; cmkAuth->sourceKeyDigest = migdata->srcDigest; obj_list_put(&migdata_list); return TSS_SUCCESS; } TSS_RESULT obj_migdata_get_cmk_auth_blob(TSS_HMIGDATA hMigData, UINT32 *blobSize, BYTE **cmkAuthBlob) { struct tsp_object *obj; TPM_CMK_AUTH cmkAuth; UINT64 offset; TSS_RESULT result; if ((result = obj_migdata_get_cmk_auth(hMigData, &cmkAuth))) return result; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); offset = 0; Trspi_LoadBlob_CMK_AUTH(&offset, NULL, &cmkAuth); *blobSize = offset; if ((*cmkAuthBlob = calloc_tspi(obj->tspContext, *blobSize)) == NULL) { LogError("malloc of %u bytes failed.", *blobSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_CMK_AUTH(&offset, *cmkAuthBlob, &cmkAuth); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_sig_data(TSS_HMIGDATA hMigData, UINT32 sigDataSize, BYTE *sigData) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (sigDataSize != sizeof(migdata->sigData.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->sigData.digest, sigData, sizeof(migdata->sigData.digest)); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_sig_data(TSS_HMIGDATA hMigData, UINT32 *sigDataSize, BYTE **sigData) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*sigData = calloc_tspi(obj->tspContext, sizeof(migdata->sigData.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(migdata->sigData.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*sigData, migdata->sigData.digest, sizeof(migdata->sigData.digest)); *sigDataSize = sizeof(migdata->sigData.digest); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_sig_value(TSS_HMIGDATA hMigData, UINT32 sigValueSize, BYTE *sigValue) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; migdata->sigValueSize = 0; free(migdata->sigValue); if ((migdata->sigValue = malloc(sigValueSize)) == NULL) { LogError("malloc of %u bytes failed.", sigValueSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(migdata->sigValue, sigValue, sigValueSize); migdata->sigValueSize = sigValueSize; done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_sig_value(TSS_HMIGDATA hMigData, UINT32 *sigValueSize, BYTE **sigValue) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*sigValue = calloc_tspi(obj->tspContext, migdata->sigValueSize)) == NULL) { LogError("malloc of %u bytes failed.", migdata->sigValueSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*sigValue, migdata->sigValue, migdata->sigValueSize); *sigValueSize = migdata->sigValueSize; done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_sig_ticket(TSS_HMIGDATA hMigData, UINT32 sigTicketSize, BYTE *sigTicket) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if (sigTicketSize != sizeof(migdata->sigTicket.digest)) { result = TSPERR(TSS_E_BAD_PARAMETER); goto done; } memcpy(migdata->sigTicket.digest, sigTicket, sizeof(migdata->sigTicket.digest)); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_sig_ticket(TSS_HMIGDATA hMigData, UINT32 *sigTicketSize, BYTE **sigTicket) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*sigTicket = calloc_tspi(obj->tspContext, sizeof(migdata->sigTicket.digest))) == NULL) { LogError("malloc of %zd bytes failed.", sizeof(migdata->sigTicket.digest)); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*sigTicket, migdata->sigTicket.digest, sizeof(migdata->sigTicket.digest)); *sigTicketSize = sizeof(migdata->sigTicket.digest); done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_set_blob(TSS_HMIGDATA hMigData, UINT32 blobSize, BYTE *blob) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; migdata->blobSize = 0; free(migdata->blob); if ((migdata->blob = malloc(blobSize)) == NULL) { LogError("malloc of %u bytes failed.", blobSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(migdata->blob, blob, blobSize); migdata->blobSize = blobSize; done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_get_blob(TSS_HMIGDATA hMigData, UINT32 *blobSize, BYTE **blob) { struct tsp_object *obj; struct tr_migdata_obj *migdata; TSS_RESULT result = TSS_SUCCESS; if ((obj = obj_list_get_obj(&migdata_list, hMigData)) == NULL) return TSPERR(TSS_E_INVALID_HANDLE); migdata = (struct tr_migdata_obj *)obj->data; if ((*blob = calloc_tspi(obj->tspContext, migdata->blobSize)) == NULL) { LogError("malloc of %u bytes failed.", migdata->blobSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } memcpy(*blob, migdata->blob, migdata->blobSize); *blobSize = migdata->blobSize; done: obj_list_put(&migdata_list); return result; } TSS_RESULT obj_migdata_calc_pubkey_digest(UINT32 blobSize, BYTE *blob, TPM_DIGEST *digest) { Trspi_HashCtx hashCtx; TSS_RESULT result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_HashUpdate(&hashCtx, blobSize, blob); result |= Trspi_HashFinal(&hashCtx, digest->digest); return result; } TSS_RESULT obj_migdata_calc_msa_digest(struct tr_migdata_obj *migdata) { Trspi_HashCtx hashCtx; TSS_RESULT result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_MSA_COMPOSITE(&hashCtx, &migdata->msaList); result |= Trspi_HashFinal(&hashCtx, migdata->msaDigest.digest); return result; } TSS_RESULT obj_migdata_calc_sig_data_digest(struct tr_migdata_obj *migdata) { Trspi_HashCtx hashCtx; TSS_RESULT result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, migdata->maDigest.digest); result |= Trspi_Hash_DIGEST(&hashCtx, migdata->destDigest.digest); result |= Trspi_Hash_DIGEST(&hashCtx, migdata->srcDigest.digest); result |= Trspi_HashFinal(&hashCtx, migdata->sigData.digest); return result; } trousers-0.3.15/src/tspi/tspi_selftest.c0000664000175000017510000001375113663651711017565 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" TSS_RESULT Tspi_TPM_SelfTestFull(TSS_HTPM hTPM) /* in */ { TSS_RESULT result; TSS_HCONTEXT tspContext; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; return TCS_API(tspContext)->SelfTestFull(tspContext); } TSS_RESULT Tspi_TPM_CertifySelfTest(TSS_HTPM hTPM, /* in */ TSS_HKEY hKey, /* in */ TSS_VALIDATION *pValidationData) /* in, out */ { TCPA_RESULT result; TPM_AUTH keyAuth; UINT64 offset = 0; TCPA_DIGEST digest; TCPA_NONCE antiReplay; UINT32 outDataSize; BYTE *outData; TSS_HPOLICY hPolicy; TCS_KEY_HANDLE keyTCSKeyHandle; BYTE *keyData = NULL; UINT32 keyDataSize; TSS_KEY keyContainer; TPM_AUTH *pKeyAuth; TSS_BOOL useAuth; TSS_HCONTEXT tspContext; Trspi_HashCtx hashCtx; if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hPolicy, &useAuth))) return result; if ((result = obj_rsakey_get_tcs_handle(hKey, &keyTCSKeyHandle))) return result; if (pValidationData == NULL) { if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), (BYTE **)antiReplay.nonce))) { LogError("Failed creating random nonce"); return TSPERR(TSS_E_INTERNAL_ERROR); } } else { if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) return TSPERR(TSS_E_BAD_PARAMETER); memcpy(antiReplay.nonce, pValidationData->rgbExternalData, sizeof(antiReplay.nonce)); } if (useAuth) { LogDebug("Uses Auth"); result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CertifySelfTest); result |= Trspi_HashUpdate(&hashCtx, sizeof(TCPA_NONCE), antiReplay.nonce); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_CertifySelfTest, hPolicy, FALSE, &digest, &keyAuth))) return result; pKeyAuth = &keyAuth; } else { LogDebug("No Auth"); pKeyAuth = NULL; } if ((result = TCS_API(tspContext)->CertifySelfTest(tspContext, keyTCSKeyHandle, antiReplay, pKeyAuth, &outDataSize, &outData))) return result; /* validate auth */ if (useAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CertifySelfTest); result |= Trspi_Hash_UINT32(&hashCtx, outDataSize); result |= Trspi_HashUpdate(&hashCtx, outDataSize, outData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &keyAuth))) return result; } if (pValidationData == NULL) { if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &keyDataSize, &keyData))) { LogError("Failed call to GetAttribData to get key blob"); return TSPERR(TSS_E_INTERNAL_ERROR); } offset = 0; __tspi_memset(&keyContainer, 0, sizeof(TSS_KEY)); if ((result = UnloadBlob_TSS_KEY(&offset, keyData, &keyContainer))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_HashUpdate(&hashCtx, strlen("Test Passed"), (BYTE *)"Test Passed"); result |= Trspi_HashUpdate(&hashCtx, sizeof(TCPA_NONCE), antiReplay.nonce); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CertifySelfTest); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; if ((result = Trspi_Verify(TSS_HASH_SHA1, digest.digest, 20, keyContainer.pubKey.key, keyContainer.pubKey.keyLength, outData, outDataSize))) { free(outData); free_key_refs(&keyContainer); return TSPERR(TSS_E_VERIFICATION_FAILED); } } else { pValidationData->ulDataLength = sizeof(TCPA_NONCE) + sizeof(UINT32) + strlen("Test Passed"); pValidationData->rgbData = calloc_tspi(tspContext, pValidationData->ulDataLength); if (pValidationData->rgbData == NULL) { LogError("malloc of %u bytes failed.", pValidationData->ulDataLength); pValidationData->ulDataLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob(&offset, strlen("Test Passed"), pValidationData->rgbData, (BYTE *)"Test Passed"); Trspi_LoadBlob(&offset, sizeof(TCPA_NONCE), pValidationData->rgbData, antiReplay.nonce); Trspi_LoadBlob_UINT32(&offset, TPM_ORD_CertifySelfTest, pValidationData->rgbData); pValidationData->ulValidationDataLength = outDataSize; pValidationData->rgbValidationData = calloc_tspi(tspContext, outDataSize); if (pValidationData->rgbValidationData == NULL) { free_tspi(tspContext, pValidationData->rgbData); pValidationData->rgbData = NULL; pValidationData->ulDataLength = 0; LogError("malloc of %u bytes failed.", pValidationData->ulValidationDataLength); pValidationData->ulValidationDataLength = 0; return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(pValidationData->rgbValidationData, outData, outDataSize); free(outData); } return TSS_SUCCESS; } TSS_RESULT Tspi_TPM_GetTestResult(TSS_HTPM hTPM, /* in */ UINT32 * pulTestResultLength, /* out */ BYTE ** prgbTestResult) /* out */ { TSS_HCONTEXT tspContext; TSS_RESULT result; if (pulTestResultLength == NULL || prgbTestResult == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) return result; if ((result = TCS_API(tspContext)->GetTestResult(tspContext, pulTestResultLength, prgbTestResult))) return result; if ((result = __tspi_add_mem_entry(tspContext, *prgbTestResult))) { free(*prgbTestResult); *prgbTestResult = NULL; *pulTestResultLength = 0; } return TSS_SUCCESS; } trousers-0.3.15/src/tspi/tspi_ps.c0000664000175000017510000004045313663651711016355 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "tcs_tsp.h" #include "tspps.h" #include "hosttable.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "obj.h" TSS_UUID owner_evict_uuid = {0, 0, 0, 0, 0, {0, 0, 0, 0, 1, 0}}; TSS_RESULT Tspi_Context_LoadKeyByUUID(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG persistentStorageType, /* in */ TSS_UUID uuidData, /* in */ TSS_HKEY * phKey) /* out */ { TSS_RESULT result; TSS_UUID parentUUID; UINT32 keyBlobSize, parentPSType; BYTE *keyBlob = NULL; TCS_KEY_HANDLE tcsKeyHandle; TSS_HKEY parentTspHandle; TCS_LOADKEY_INFO info; UINT32 ulPubKeyLength; BYTE *rgbPubKey; TPM_COMMAND_CODE ordinal; if (phKey == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((!obj_is_context(tspContext))) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = obj_context_get_loadkey_ordinal(tspContext, &ordinal))) return result; /* This key is in the System Persistant storage */ if (persistentStorageType == TSS_PS_TYPE_SYSTEM) { #if 1 __tspi_memset(&info, 0, sizeof(TCS_LOADKEY_INFO)); result = RPC_LoadKeyByUUID(tspContext, uuidData, &info, &tcsKeyHandle); if (TSS_ERROR_CODE(result) == TCS_E_KM_LOADFAILED) { TSS_HKEY keyHandle; TSS_HPOLICY hPolicy; /* load failed, due to some key in the chain needing auth * which doesn't yet exist at the TCS level. However, the * auth may already be set in policies at the TSP level. * To find out, get the key handle of the key requiring * auth. First, look at the list of keys in memory. */ if ((obj_rsakey_get_by_uuid(&info.parentKeyUUID, &keyHandle))) { /* If that failed, look on disk, in User PS. */ if (ps_get_key_by_uuid(tspContext, &info.parentKeyUUID, &keyHandle)) return result; } if (obj_rsakey_get_policy(keyHandle, TSS_POLICY_USAGE, &hPolicy, NULL)) return result; if (secret_PerformAuth_OIAP(keyHandle, ordinal, hPolicy, FALSE, &info.paramDigest, &info.authData)) return result; if ((result = RPC_LoadKeyByUUID(tspContext, uuidData, &info, &tcsKeyHandle))) return result; } else if (result) return result; /*check if provided UUID has an owner evict key UUID prefix */ if (!memcmp(&uuidData, &owner_evict_uuid, sizeof(TSS_UUID)-1)) { if ((result = obj_rsakey_add(tspContext, TSS_RSAKEY_FLAG_OWNEREVICT, phKey))) return result; if ((result = obj_rsakey_set_tcs_handle(*phKey, tcsKeyHandle))) return result; //The cached public key portion of the owner evict key is used //further by TPM_KEY_CONTROLOWNER command for sanity check if ((result = Tspi_Key_GetPubKey(*phKey, &ulPubKeyLength, &rgbPubKey))) return result; result = obj_rsakey_set_pubkey(*phKey, FALSE, rgbPubKey); free_tspi(tspContext,rgbPubKey); if (result != TSS_SUCCESS) return result; } else { if ((result = RPC_GetRegisteredKeyBlob(tspContext, uuidData, &keyBlobSize, &keyBlob))) return result; if ((result = obj_rsakey_add_by_key(tspContext, &uuidData, keyBlob, TSS_OBJ_FLAG_SYSTEM_PS, phKey))) { free (keyBlob); return result; } result = obj_rsakey_set_tcs_handle(*phKey, tcsKeyHandle); free (keyBlob); } #else if ((result = load_from_system_ps(tspContext, &uuidData, phKey))) return result; #endif } else if (persistentStorageType == TSS_PS_TYPE_USER) { if ((result = ps_get_parent_uuid_by_uuid(&uuidData, &parentUUID))) return result; /* If the parent is not in memory, recursively call ourselves on it */ if (obj_rsakey_get_by_uuid(&parentUUID, &parentTspHandle) != TSS_SUCCESS) { if ((result = ps_get_parent_ps_type_by_uuid(&uuidData, &parentPSType))) return result; if ((result = Tspi_Context_LoadKeyByUUID(tspContext, parentPSType, parentUUID, &parentTspHandle))) return result; } if ((result = ps_get_key_by_uuid(tspContext, &uuidData, phKey))) return result; /* The parent is loaded and we have the parent key handle, so call the TCS to * actually load the child. */ return Tspi_Key_LoadKey(*phKey, parentTspHandle); } else { return TSPERR(TSS_E_BAD_PARAMETER); } return TSS_SUCCESS; } TSS_RESULT Tspi_Context_RegisterKey(TSS_HCONTEXT tspContext, /* in */ TSS_HKEY hKey, /* in */ TSS_FLAG persistentStorageType, /* in */ TSS_UUID uuidKey, /* in */ TSS_FLAG persistentStorageTypeParent, /* in */ TSS_UUID uuidParentKey) /* in */ { BYTE *keyBlob; UINT32 keyBlobSize; TSS_RESULT result; TSS_BOOL answer; if (!obj_is_context(tspContext) || !obj_is_rsakey(hKey)) return TSPERR(TSS_E_INVALID_HANDLE); if (persistentStorageType == TSS_PS_TYPE_SYSTEM) { if (persistentStorageTypeParent == TSS_PS_TYPE_USER) { return TSPERR(TSS_E_NOTIMPL); } else if (persistentStorageTypeParent == TSS_PS_TYPE_SYSTEM) { if ((result = obj_rsakey_get_blob(hKey, &keyBlobSize, &keyBlob))) return result; if ((result = RPC_RegisterKey(tspContext, uuidParentKey, uuidKey, keyBlobSize, keyBlob, strlen(PACKAGE_STRING) + 1, (BYTE *)PACKAGE_STRING))) return result; } else { return TSPERR(TSS_E_BAD_PARAMETER); } } else if (persistentStorageType == TSS_PS_TYPE_USER) { if ((result = ps_is_key_registered(&uuidKey, &answer))) return result; if (answer == TRUE) return TSPERR(TSS_E_KEY_ALREADY_REGISTERED); if ((result = obj_rsakey_get_blob (hKey, &keyBlobSize, &keyBlob))) return result; if ((result = ps_write_key(&uuidKey, &uuidParentKey, persistentStorageTypeParent, keyBlobSize, keyBlob))) return result; } else { return TSPERR(TSS_E_BAD_PARAMETER); } if ((result = obj_rsakey_set_uuid(hKey, persistentStorageType, &uuidKey))) return result; return TSS_SUCCESS; } TSS_RESULT Tspi_Context_UnregisterKey(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG persistentStorageType, /* in */ TSS_UUID uuidKey, /* in */ TSS_HKEY *phKey) /* out */ { BYTE *keyBlob = NULL; UINT32 keyBlobSize; TSS_RESULT result; if (phKey == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((!obj_is_context(tspContext))) return TSPERR(TSS_E_INVALID_HANDLE); if (persistentStorageType == TSS_PS_TYPE_SYSTEM) { /* get the key first, so it doesn't disappear when we * unregister it */ if ((result = RPC_GetRegisteredKeyBlob(tspContext, uuidKey, &keyBlobSize, &keyBlob))) return result; if ((obj_rsakey_add_by_key(tspContext, &uuidKey, keyBlob, TSS_OBJ_FLAG_SYSTEM_PS, phKey))) { free(keyBlob); return result; } free(keyBlob); /* now unregister it */ if ((result = RPC_UnregisterKey(tspContext, uuidKey))) return result; } else if (persistentStorageType == TSS_PS_TYPE_USER) { /* get the key first, so it doesn't disappear when we * unregister it */ if ((result = ps_get_key_by_uuid(tspContext, &uuidKey, phKey))) return result; /* now unregister it */ if ((result = ps_remove_key(&uuidKey))) return result; } else { return TSPERR(TSS_E_BAD_PARAMETER); } return TSS_SUCCESS; } TSS_RESULT Tspi_Context_GetKeyByUUID(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG persistentStorageType, /* in */ TSS_UUID uuidData, /* in */ TSS_HKEY * phKey) /* out */ { TCPA_RESULT result; UINT32 keyBlobSize = 0; BYTE *keyBlob = NULL; if (phKey == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if ((!obj_is_context(tspContext))) return TSPERR(TSS_E_INVALID_HANDLE); if (persistentStorageType == TSS_PS_TYPE_SYSTEM) { if ((result = RPC_GetRegisteredKeyBlob(tspContext, uuidData, &keyBlobSize, &keyBlob))) return result; if ((obj_rsakey_add_by_key(tspContext, &uuidData, keyBlob, TSS_OBJ_FLAG_SYSTEM_PS, phKey))) { free(keyBlob); return result; } free(keyBlob); } else if (persistentStorageType == TSS_PS_TYPE_USER) { if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); if ((result = ps_get_key_by_uuid(tspContext, &uuidData, phKey))) return result; } else return TSPERR(TSS_E_BAD_PARAMETER); return TSS_SUCCESS; } TSS_RESULT Tspi_Context_GetKeyByPublicInfo(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG persistentStorageType, /* in */ TSS_ALGORITHM_ID algID, /* in */ UINT32 ulPublicInfoLength, /* in */ BYTE * rgbPublicInfo, /* in */ TSS_HKEY * phKey) /* out */ { TCPA_ALGORITHM_ID tcsAlgID; UINT32 keyBlobSize; BYTE *keyBlob; TSS_RESULT result; TSS_HKEY keyOutHandle; UINT32 flag = 0; TSS_KEY keyContainer; UINT64 offset; if (phKey == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); switch (algID) { case TSS_ALG_RSA: tcsAlgID = TCPA_ALG_RSA; break; default: LogError("Algorithm ID was not type RSA."); return TSPERR(TSS_E_BAD_PARAMETER); } if (persistentStorageType == TSS_PS_TYPE_SYSTEM) { if ((result = RPC_GetRegisteredKeyByPublicInfo(tspContext, tcsAlgID, ulPublicInfoLength, rgbPublicInfo, &keyBlobSize, &keyBlob))) return result; } else if (persistentStorageType == TSS_PS_TYPE_USER) { return ps_get_key_by_pub(tspContext, ulPublicInfoLength, rgbPublicInfo, phKey); } else return TSPERR(TSS_E_BAD_PARAMETER); /* need to setup the init flags of the create object based on * the size of the blob's pubkey */ offset = 0; if ((result = UnloadBlob_TSS_KEY(&offset, keyBlob, &keyContainer))) { free(keyBlob); return result; } /* begin setting up the key object */ switch (keyContainer.pubKey.keyLength) { case 16384/8: flag |= TSS_KEY_SIZE_16384; break; case 8192/8: flag |= TSS_KEY_SIZE_8192; break; case 4096/8: flag |= TSS_KEY_SIZE_4096; break; case 2048/8: flag |= TSS_KEY_SIZE_2048; break; case 1024/8: flag |= TSS_KEY_SIZE_1024; break; case 512/8: flag |= TSS_KEY_SIZE_512; break; default: LogError("Key was not a known keylength."); free(keyBlob); free_key_refs(&keyContainer); return TSPERR(TSS_E_INTERNAL_ERROR); } if (keyContainer.keyUsage == TPM_KEY_SIGNING) flag |= TSS_KEY_TYPE_SIGNING; else if (keyContainer.keyUsage == TPM_KEY_STORAGE) flag |= TSS_KEY_TYPE_STORAGE; else if (keyContainer.keyUsage == TPM_KEY_IDENTITY) flag |= TSS_KEY_TYPE_IDENTITY; else if (keyContainer.keyUsage == TPM_KEY_AUTHCHANGE) flag |= TSS_KEY_TYPE_AUTHCHANGE; else if (keyContainer.keyUsage == TPM_KEY_BIND) flag |= TSS_KEY_TYPE_BIND; else if (keyContainer.keyUsage == TPM_KEY_LEGACY) flag |= TSS_KEY_TYPE_LEGACY; if (keyContainer.authDataUsage == TPM_AUTH_NEVER) flag |= TSS_KEY_NO_AUTHORIZATION; else flag |= TSS_KEY_AUTHORIZATION; if (keyContainer.keyFlags & TPM_MIGRATABLE) flag |= TSS_KEY_MIGRATABLE; else flag |= TSS_KEY_NOT_MIGRATABLE; if (keyContainer.keyFlags & TPM_VOLATILE) flag |= TSS_KEY_VOLATILE; else flag |= TSS_KEY_NON_VOLATILE; #ifdef TSS_BUILD_CMK if (keyContainer.keyFlags & TPM_MIGRATEAUTHORITY) flag |= TSS_KEY_CERTIFIED_MIGRATABLE; else flag |= TSS_KEY_NOT_CERTIFIED_MIGRATABLE; #endif /* Create a new Key Object */ if ((result = obj_rsakey_add(tspContext, flag, &keyOutHandle))) { free(keyBlob); free_key_refs(&keyContainer); return result; } /* Stick the info into this net KeyObject */ if ((result = obj_rsakey_set_tcpakey(keyOutHandle, keyBlobSize, keyBlob))) { free(keyBlob); free_key_refs(&keyContainer); return result; } free(keyBlob); free_key_refs(&keyContainer); *phKey = keyOutHandle; return TSS_SUCCESS; } TSS_RESULT Tspi_Context_GetRegisteredKeysByUUID(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG persistentStorageType, /* in */ TSS_UUID * pUuidData, /* in */ UINT32 * pulKeyHierarchySize, /* out */ TSS_KM_KEYINFO ** ppKeyHierarchy) /* out */ { TSS_RESULT result; TSS_KM_KEYINFO *tcsHier, *tspHier; UINT32 tcsHierSize, tspHierSize; TSS_UUID tcs_uuid; if (pulKeyHierarchySize == NULL || ppKeyHierarchy == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); if (pUuidData) { if (persistentStorageType == TSS_PS_TYPE_SYSTEM) { if ((result = RPC_EnumRegisteredKeys(tspContext, pUuidData, pulKeyHierarchySize, ppKeyHierarchy))) return result; } else if (persistentStorageType == TSS_PS_TYPE_USER) { if ((result = ps_get_registered_keys(pUuidData, &tcs_uuid, &tspHierSize, &tspHier))) return result; if ((result = RPC_EnumRegisteredKeys(tspContext, &tcs_uuid, &tcsHierSize, &tcsHier))) { free(tspHier); return result; } result = merge_key_hierarchies(tspContext, tspHierSize, tspHier, tcsHierSize, tcsHier, pulKeyHierarchySize, ppKeyHierarchy); free(tcsHier); free(tspHier); } else return TSPERR(TSS_E_BAD_PARAMETER); } else { if ((result = RPC_EnumRegisteredKeys(tspContext, pUuidData, &tcsHierSize, &tcsHier))) return result; if ((result = ps_get_registered_keys(pUuidData, NULL, &tspHierSize, &tspHier))) { free(tcsHier); return result; } result = merge_key_hierarchies(tspContext, tspHierSize, tspHier, tcsHierSize, tcsHier, pulKeyHierarchySize, ppKeyHierarchy); free(tcsHier); free(tspHier); } if ((result = __tspi_add_mem_entry(tspContext, *ppKeyHierarchy))) { free(*ppKeyHierarchy); *ppKeyHierarchy = NULL; *pulKeyHierarchySize = 0; } return result; } TSS_RESULT Tspi_Context_GetRegisteredKeysByUUID2(TSS_HCONTEXT tspContext, /* in */ TSS_FLAG persistentStorageType, /* in */ TSS_UUID * pUuidData, /* in */ UINT32 * pulKeyHierarchySize, /* out */ TSS_KM_KEYINFO2 ** ppKeyHierarchy) /* out */ { TSS_RESULT result; TSS_KM_KEYINFO2 *tcsHier, *tspHier; UINT32 tcsHierSize, tspHierSize; TSS_UUID tcs_uuid; /* If out parameters are NULL, return error */ if (pulKeyHierarchySize == NULL || ppKeyHierarchy == NULL) return TSPERR(TSS_E_BAD_PARAMETER); if (!obj_is_context(tspContext)) return TSPERR(TSS_E_INVALID_HANDLE); if (pUuidData) { /* TSS 1.2 Spec: If a certain key UUID is provided, the returned array of * TSS_KM_KEYINFO2 structures only contains data reflecting the path of the key * hierarchy regarding that key. The first array entry is the key addressed by the * given UUID followed by its parent key up to and including the root key. */ if (persistentStorageType == TSS_PS_TYPE_SYSTEM) { if ((result = RPC_EnumRegisteredKeys2(tspContext, pUuidData, pulKeyHierarchySize, ppKeyHierarchy))) return result; } else if (persistentStorageType == TSS_PS_TYPE_USER) { if ((result = ps_get_registered_keys2(pUuidData, &tcs_uuid, &tspHierSize, &tspHier))) return result; /* The tcs_uuid returned by ps_get_registered_key2 will always be a parent * of some key into the system ps of a user key into the user ps. This key * needs to be searched for in the system ps to be merged */ if ((result = RPC_EnumRegisteredKeys2(tspContext, &tcs_uuid, &tcsHierSize, &tcsHier))) { free(tspHier); return result; } result = merge_key_hierarchies2(tspContext, tspHierSize, tspHier, tcsHierSize, tcsHier, pulKeyHierarchySize, ppKeyHierarchy); free(tcsHier); free(tspHier); } else return TSPERR(TSS_E_BAD_PARAMETER); } else { /* If this field is set to NULL, the returned array of TSS_KM_KEYINFO2 structures * contains data reflecting the entire key hierarchy starting with root key. The * array will include keys from both the user and the system TSS key store. The * persistentStorageType field will be ignored. */ if ((result = RPC_EnumRegisteredKeys2(tspContext, pUuidData, &tcsHierSize, &tcsHier))) return result; if ((result = ps_get_registered_keys2(pUuidData, NULL, &tspHierSize, &tspHier))) { free(tcsHier); return result; } result = merge_key_hierarchies2(tspContext, tspHierSize, tspHier, tcsHierSize, tcsHier, pulKeyHierarchySize, ppKeyHierarchy); free(tcsHier); free(tspHier); } if ((result = __tspi_add_mem_entry(tspContext, *ppKeyHierarchy))) { free(*ppKeyHierarchy); *ppKeyHierarchy = NULL; *pulKeyHierarchySize = 0; } return result; } trousers-0.3.15/src/tspi/tsp_ps.c0000664000175000017510000001716213663651711016205 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tcs_tsp.h" #include "tspps.h" #include "tsplog.h" #include "obj.h" /* * tsp_ps.c * * Functions used to query the user persistent storage file. * * Since other apps may be altering the file, all operations must be atomic WRT the file and no * cache will be kept, since another app could delete keys from the file out from under us. * * Atomicity is guaranteed for operations inbetween calls to get_file() and put_file(). * * A PS file will have the lifetime of the TSP context. For instance, this code will store hKeyA * and hKeyB in the file "a": * * setenv("TSS_USER_PS_FILE=a"); * Tspi_Context_Create(&hContext); * Tspi_Context_RegisterKey(hKeyA); * setenv("TSS_USER_PS_FILE=b"); * Tspi_Context_RegisterKey(hKeyB); * * but this code will store hKeyA in file "a" and hKeyB in file "b": * * setenv("TSS_USER_PS_FILE=a"); * Tspi_Context_Create(&hContext); * Tspi_Context_RegisterKey(hKeyA); * Tspi_Context_Close(hContext); * * setenv("TSS_USER_PS_FILE=b"); * Tspi_Context_Create(&hContext); * Tspi_Context_RegisterKey(hKeyB); * */ TSS_RESULT ps_get_registered_keys(TSS_UUID *uuid, TSS_UUID *tcs_uuid, UINT32 *size, TSS_KM_KEYINFO **keys) { int fd; UINT32 result; if ((result = get_file(&fd))) return result; result = psfile_get_registered_keys(fd, uuid, tcs_uuid, size, keys); put_file(fd); return result; } TSS_RESULT ps_get_registered_keys2(TSS_UUID *uuid, TSS_UUID *tcs_uuid, UINT32 *size, TSS_KM_KEYINFO2 **keys) { int fd; UINT32 result; if ((result = get_file(&fd))) return result; /* Sets the proper TSS_KM_KEYINFO2 fields according to the UUID type */ result = psfile_get_registered_keys2(fd, uuid, tcs_uuid, size, keys); put_file(fd); return result; } TSS_RESULT ps_is_key_registered(TSS_UUID *uuid, TSS_BOOL *answer) { int fd; TSS_RESULT result; if ((result = get_file(&fd))) return result; result = psfile_is_key_registered(fd, uuid, answer); put_file(fd); return result; } TSS_RESULT ps_write_key(TSS_UUID *uuid, TSS_UUID *parent_uuid, UINT32 parent_ps, UINT32 blob_size, BYTE *blob) { int fd; TSS_RESULT result; UINT16 short_blob_size = (UINT16)blob_size; if (blob_size > USHRT_MAX) { LogError("Blob data being written to disk is too large(%u bytes)!", blob_size); return TSPERR(TSS_E_INTERNAL_ERROR); } if ((result = get_file(&fd))) return result; result = psfile_write_key(fd, uuid, parent_uuid, parent_ps, blob, short_blob_size); put_file(fd); return result; } TSS_RESULT ps_remove_key(TSS_UUID *uuid) { int fd; TSS_RESULT result; if ((result = get_file(&fd))) return result; result = psfile_remove_key(fd, uuid); put_file(fd); return result; } TSS_RESULT ps_get_key_by_pub(TSS_HCONTEXT tspContext, UINT32 pub_size, BYTE *pub, TSS_HKEY *hKey) { int fd; TSS_RESULT result = TSS_SUCCESS; BYTE key[4096]; TSS_UUID uuid; if ((result = get_file(&fd))) return result; if ((result = psfile_get_key_by_pub(fd, &uuid, pub_size, pub, key))) { put_file(fd); return result; } put_file(fd); result = obj_rsakey_add_by_key(tspContext, &uuid, key, TSS_OBJ_FLAG_USER_PS, hKey); return result; } TSS_RESULT ps_get_key_by_uuid(TSS_HCONTEXT tspContext, TSS_UUID *uuid, TSS_HKEY *hKey) { int fd; TSS_RESULT result = TSS_SUCCESS; BYTE key[4096]; if ((result = get_file(&fd))) return result; if ((result = psfile_get_key_by_uuid(fd, uuid, key))) { put_file(fd); return result; } put_file(fd); result = obj_rsakey_add_by_key(tspContext, uuid, key, TSS_OBJ_FLAG_USER_PS, hKey); return result; } TSS_RESULT ps_get_parent_uuid_by_uuid(TSS_UUID *uuid, TSS_UUID *parent_uuid) { int fd; TSS_RESULT result; if ((result = get_file(&fd))) return result; result = psfile_get_parent_uuid_by_uuid(fd, uuid, parent_uuid); put_file(fd); return result; } TSS_RESULT ps_get_parent_ps_type_by_uuid(TSS_UUID *uuid, UINT32 *type) { int fd; TSS_RESULT result; if ((result = get_file(&fd))) return result; result = psfile_get_parent_ps_type(fd, uuid, type); put_file(fd); return result; } TSS_RESULT ps_close() { TSS_RESULT result; int fd; if ((result = get_file(&fd))) return result; psfile_close(fd); /* No need to call put_file() here, the file is closed */ return TSS_SUCCESS; } TSS_RESULT merge_key_hierarchies(TSS_HCONTEXT tspContext, UINT32 tsp_size, TSS_KM_KEYINFO *tsp_hier, UINT32 tcs_size, TSS_KM_KEYINFO *tcs_hier, UINT32 *merged_size, TSS_KM_KEYINFO **merged_hier) { UINT32 i, j; *merged_hier = malloc((tsp_size + tcs_size) * sizeof(TSS_KM_KEYINFO)); if (*merged_hier == NULL) { LogError("malloc of %zu bytes failed.", (tsp_size + tcs_size) * sizeof(TSS_KM_KEYINFO)); return TSPERR(TSS_E_OUTOFMEMORY); } for (i = 0; i < tsp_size; i++) memcpy(&((*merged_hier)[i]), &tsp_hier[i], sizeof(TSS_KM_KEYINFO)); for (j = 0; j < tcs_size; j++) memcpy(&((*merged_hier)[i + j]), &tcs_hier[j], sizeof(TSS_KM_KEYINFO)); *merged_size = i + j; return TSS_SUCCESS; } TSS_RESULT merge_key_hierarchies2(TSS_HCONTEXT tspContext, UINT32 tsp_size, TSS_KM_KEYINFO2 *tsp_hier, UINT32 tcs_size, TSS_KM_KEYINFO2 *tcs_hier, UINT32 *merged_size, TSS_KM_KEYINFO2 **merged_hier) { UINT32 i, j; *merged_hier = malloc((tsp_size + tcs_size) * sizeof(TSS_KM_KEYINFO2)); if (*merged_hier == NULL) { LogError("malloc of %zu bytes failed.", (tsp_size + tcs_size) * sizeof(TSS_KM_KEYINFO2)); return TSPERR(TSS_E_OUTOFMEMORY); } for (i = 0; i < tsp_size; i++) memcpy(&((*merged_hier)[i]), &tsp_hier[i], sizeof(TSS_KM_KEYINFO2)); for (j = 0; j < tcs_size; j++) memcpy(&((*merged_hier)[i + j]), &tcs_hier[j], sizeof(TSS_KM_KEYINFO2)); *merged_size = i + j; return TSS_SUCCESS; } #if 0 TSS_RESULT load_from_system_ps(TSS_HCONTEXT tspContext, TSS_UUID *uuid, TSS_HKEY *phKey) { TCS_KEY_HANDLE tcsKeyHandle; TCS_LOADKEY_INFO info; BYTE *keyBlob = NULL; __tspi_memset(&info, 0, sizeof(TCS_LOADKEY_INFO)); result = TCSP_LoadKeyByUUID(tspContext, uuidData, &info, &tcsKeyHandle); if (TSS_ERROR_CODE(result) == TCS_E_KM_LOADFAILED) { TSS_HKEY keyHandle; TSS_HPOLICY hPolicy; /* load failed, due to some key in the chain needing auth * which doesn't yet exist at the TCS level. However, the * auth may already be set in policies at the TSP level. * To find out, get the key handle of the key requiring * auth. First, look at the list of keys in memory. */ if ((obj_rsakey_get_by_uuid(&info.parentKeyUUID, &keyHandle))) { /* If that failed, look on disk, in User PS. */ if (ps_get_key_by_uuid(tspContext, &info.parentKeyUUID, &keyHandle)) return result; } if (obj_rsakey_get_policy(keyHandle, TSS_POLICY_USAGE, &hPolicy, NULL)) return result; if (secret_PerformAuth_OIAP(keyHandle, TPM_ORD_LoadKey, hPolicy, &info.paramDigest, &info.authData)) return result; if ((result = TCSP_LoadKeyByUUID(tspContext, *uuid, &info, &tcsKeyHandle))) return result; } else if (result) return result; if ((result = TCS_GetRegisteredKeyBlob(tspContext, *uuid, &keyBlobSize, &keyBlob))) return result; if ((result = obj_rsakey_add_by_key(tspContext, uuid, keyBlob, TSS_OBJ_FLAG_SYSTEM_PS, phKey))) { free(keyBlob); return result; } result = obj_rsakey_set_tcs_handle(*phKey, tcsKeyHandle); free(keyBlob); return result; } #endif trousers-0.3.15/src/tspi/tsp_pcr_extend.c0000664000175000017510000000500613663651711017710 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_Extend(TSS_HCONTEXT tspContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_DIGEST inDigest, /* in */ TCPA_PCRVALUE * outDigest) /* out */ { TSS_RESULT result; UINT64 offset; TCS_HANDLE handlesLen = 0; UINT32 decLen; BYTE data[sizeof(TCPA_PCRINDEX) + sizeof(TCPA_DIGEST)], *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, pcrNum, data); Trspi_LoadBlob(&offset, TPM_SHA1_160_HASH_LEN, data, inDigest.digest); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Extend, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob(&offset, decLen, dec, outDigest->digest); free(dec); return TSS_SUCCESS; } TSS_RESULT Transport_PcrRead(TSS_HCONTEXT tspContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_PCRVALUE * outDigest) /* out */ { TSS_RESULT result; UINT64 offset; TCS_HANDLE handlesLen = 0; UINT32 decLen; BYTE data[sizeof(TCPA_PCRINDEX)], *dec; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); offset = 0; Trspi_LoadBlob_UINT32(&offset, pcrNum, data); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_PcrRead, sizeof(data), data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob(&offset, decLen, dec, outDigest->digest); free(dec); return TSS_SUCCESS; } TSS_RESULT Transport_PcrReset(TSS_HCONTEXT tspContext, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn) /* in */ { TSS_RESULT result; TCS_HANDLE handlesLen = 0; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); return obj_context_transport_execute(tspContext, TPM_ORD_PCR_Reset, pcrDataSizeIn, pcrDataIn, NULL, &handlesLen, NULL, NULL, NULL, NULL, NULL); } #endif trousers-0.3.15/src/tspi/tsp_delegate.c0000664000175000017510000006000313663651711017325 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "obj.h" #include "tsplog.h" #include "tsp_delegate.h" #include "authsess.h" TSS_RESULT do_delegate_manage(TSS_HTPM hTpm, UINT32 familyID, UINT32 opFlag, UINT32 opDataSize, BYTE *opData, UINT32 *outDataSize, BYTE **outData) { TSS_HCONTEXT hContext; TSS_HPOLICY hPolicy; UINT32 secretMode = TSS_SECRET_MODE_NONE; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; TPM_AUTH ownerAuth, *pAuth; UINT32 retDataSize; BYTE *retData = NULL; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((result = obj_tpm_get_policy(hTpm, TSS_POLICY_USAGE, &hPolicy))) return result; if (hPolicy != NULL_HPOLICY) { if ((result = obj_policy_get_mode(hPolicy, &secretMode))) return result; } if (secretMode != TSS_SECRET_MODE_NONE) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_Manage); result |= Trspi_Hash_UINT32(&hashCtx, familyID); result |= Trspi_Hash_UINT32(&hashCtx, opFlag); result |= Trspi_Hash_UINT32(&hashCtx, opDataSize); result |= Trspi_HashUpdate(&hashCtx, opDataSize, opData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) return result; pAuth = &ownerAuth; if ((result = secret_PerformAuth_OIAP(hTpm, TPM_ORD_Delegate_Manage, hPolicy, FALSE, &digest, pAuth))) return result; } else pAuth = NULL; /* Perform the delegation operation */ if ((result = TCS_API(hContext)->Delegate_Manage(hContext, familyID, opFlag, opDataSize, opData, pAuth, &retDataSize, &retData))) return result; if (pAuth) { result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_Manage); result |= Trspi_Hash_UINT32(&hashCtx, retDataSize); result |= Trspi_HashUpdate(&hashCtx, retDataSize, retData); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) { free(retData); goto done; } if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) { free(retData); goto done; } } *outDataSize = retDataSize; *outData = retData; done: return result; } TSS_RESULT create_owner_delegation(TSS_HTPM hTpm, BYTE bLabel, UINT32 ulFlags, TSS_HPCRS hPcrs, TSS_HDELFAMILY hFamily, TSS_HPOLICY hDelegation) { TSS_HCONTEXT hContext; TSS_BOOL incrementCount = FALSE; UINT32 type; UINT32 publicInfoSize; BYTE *publicInfo = NULL; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; UINT32 blobSize; BYTE *blob = NULL; TSS_RESULT result; struct authsess *xsap = NULL; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((ulFlags & ~TSS_DELEGATE_INCREMENTVERIFICATIONCOUNT) > 0) return TSPERR(TSS_E_BAD_PARAMETER); if (ulFlags & TSS_DELEGATE_INCREMENTVERIFICATIONCOUNT) incrementCount = TRUE; if ((result = obj_policy_get_delegation_type(hDelegation, &type))) return result; if (type != TSS_DELEGATIONTYPE_OWNER) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = __tspi_build_delegate_public_info(bLabel, hPcrs, hFamily, hDelegation, &publicInfoSize, &publicInfo))) return result; if ((result = authsess_xsap_init(hContext, hTpm, hDelegation, TSS_AUTH_POLICY_NOT_REQUIRED, TPM_ORD_Delegate_CreateOwnerDelegation, TPM_ET_OWNER, &xsap))) { free(publicInfo); return result; } result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_CreateOwnerDelegation); result |= Trspi_Hash_BOOL(&hashCtx, incrementCount); result |= Trspi_HashUpdate(&hashCtx, publicInfoSize, publicInfo); result |= Trspi_Hash_DIGEST(&hashCtx, xsap->encAuthUse.authdata); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = authsess_xsap_hmac(xsap, &digest))) goto done; /* Create the delegation */ if ((result = TCS_API(hContext)->Delegate_CreateOwnerDelegation(hContext, incrementCount, publicInfoSize, publicInfo, &xsap->encAuthUse, xsap->pAuth, &blobSize, &blob))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_CreateOwnerDelegation); result |= Trspi_Hash_UINT32(&hashCtx, blobSize); result |= Trspi_HashUpdate(&hashCtx, blobSize, blob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (authsess_xsap_verify(xsap, &digest)) { result = TSPERR(TSS_E_TSP_AUTHFAIL); goto done; } result = obj_policy_set_delegation_blob(hDelegation, TSS_DELEGATIONTYPE_OWNER, blobSize, blob); done: authsess_free(xsap); free(publicInfo); free(blob); return result; } TSS_RESULT create_key_delegation(TSS_HKEY hKey, BYTE bLabel, UINT32 ulFlags, TSS_HPCRS hPcrs, TSS_HDELFAMILY hFamily, TSS_HPOLICY hDelegation) { TSS_HCONTEXT hContext; UINT32 type; TCS_KEY_HANDLE tcsKeyHandle; UINT32 publicInfoSize; BYTE *publicInfo = NULL; Trspi_HashCtx hashCtx; TCPA_DIGEST digest; UINT32 blobSize; BYTE *blob = NULL; TSS_RESULT result; struct authsess *xsap = NULL; if ((result = obj_rsakey_get_tsp_context(hKey, &hContext))) return result; if (ulFlags != 0) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_policy_get_delegation_type(hDelegation, &type))) return result; if (type != TSS_DELEGATIONTYPE_KEY) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKeyHandle))) return result; if ((result = __tspi_build_delegate_public_info(bLabel, hPcrs, hFamily, hDelegation, &publicInfoSize, &publicInfo))) return result; if ((result = authsess_xsap_init(hContext, hKey, hDelegation, TSS_AUTH_POLICY_REQUIRED, TPM_ORD_Delegate_CreateKeyDelegation, TPM_ET_KEYHANDLE, &xsap))) { free(publicInfo); return result; } result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_CreateKeyDelegation); result |= Trspi_HashUpdate(&hashCtx, publicInfoSize, publicInfo); result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if ((result = authsess_xsap_hmac(xsap, &digest))) goto done; /* Create the delegation */ if ((result = TCS_API(hContext)->Delegate_CreateKeyDelegation(hContext, tcsKeyHandle, publicInfoSize, publicInfo, &xsap->encAuthUse, xsap->pAuth, &blobSize, &blob))) goto done; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_UINT32(&hashCtx, result); result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_Delegate_CreateKeyDelegation); result |= Trspi_Hash_UINT32(&hashCtx, blobSize); result |= Trspi_HashUpdate(&hashCtx, blobSize, blob); if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) goto done; if (authsess_xsap_verify(xsap, &digest)) { result = TSPERR(TSS_E_TSP_AUTHFAIL); goto done; } result = obj_policy_set_delegation_blob(hDelegation, TSS_DELEGATIONTYPE_KEY, blobSize, blob); done: free(blob); authsess_free(xsap); free(publicInfo); return result; } TSS_RESULT update_delfamily_object(TSS_HTPM hTpm, UINT32 familyID) { TSS_HCONTEXT hContext; UINT32 familyTableSize, delegateTableSize; BYTE *familyTable = NULL, *delegateTable = NULL; UINT64 offset; TPM_FAMILY_TABLE_ENTRY familyTableEntry; TSS_BOOL familyState; TSS_HDELFAMILY hFamily; TSS_RESULT result; if ((result = obj_tpm_get_tsp_context(hTpm, &hContext))) return result; if ((result = TCS_API(hContext)->Delegate_ReadTable(hContext, &familyTableSize, &familyTable, &delegateTableSize, &delegateTable))) return result; for (offset = 0; offset < familyTableSize;) { Trspi_UnloadBlob_TPM_FAMILY_TABLE_ENTRY(&offset, familyTable, &familyTableEntry); if (familyTableEntry.familyID == familyID) { obj_delfamily_find_by_familyid(hContext, familyID, &hFamily); if (hFamily == NULL_HDELFAMILY) { if ((result = obj_delfamily_add(hContext, &hFamily))) goto done; if ((result = obj_delfamily_set_familyid(hFamily, familyTableEntry.familyID))) goto done; if ((result = obj_delfamily_set_label(hFamily, familyTableEntry.label.label))) goto done; } /* Set/Update the family attributes */ familyState = (familyTableEntry.flags & TPM_FAMFLAG_DELEGATE_ADMIN_LOCK) ? TRUE : FALSE; if ((result = obj_delfamily_set_locked(hFamily, familyState, FALSE))) goto done; familyState = (familyTableEntry.flags & TPM_FAMFLAG_ENABLE) ? TRUE : FALSE; if ((result = obj_delfamily_set_enabled(hFamily, familyState, FALSE))) goto done; if ((result = obj_delfamily_set_vercount(hFamily, familyTableEntry.verificationCount))) goto done; break; } } done: free(familyTable); free(delegateTable); return result; } TSS_RESULT get_delegate_index(TSS_HCONTEXT hContext, UINT32 index, TPM_DELEGATE_PUBLIC *public) { UINT32 familyTableSize, delegateTableSize; BYTE *familyTable = NULL, *delegateTable = NULL; UINT64 offset; UINT32 tpmIndex; TPM_DELEGATE_PUBLIC tempPublic; TSS_RESULT result; if ((result = TCS_API(hContext)->Delegate_ReadTable(hContext, &familyTableSize, &familyTable, &delegateTableSize, &delegateTable))) goto done; for (offset = 0; offset < delegateTableSize;) { Trspi_UnloadBlob_UINT32(&offset, &tpmIndex, delegateTable); if (tpmIndex == index) { result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(&offset, delegateTable, public); goto done; } else { if ((result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(&offset, delegateTable, &tempPublic))) goto done; } free(tempPublic.pcrInfo.pcrSelection.pcrSelect); } /* Didn't find a matching index */ result = TSPERR(TSS_E_BAD_PARAMETER); done: free(familyTable); free(delegateTable); return result; } TSS_RESULT __tspi_build_delegate_public_info(BYTE bLabel, TSS_HPCRS hPcrs, TSS_HDELFAMILY hFamily, TSS_HPOLICY hDelegation, UINT32 *publicInfoSize, BYTE **publicInfo) { TPM_DELEGATE_PUBLIC public; UINT32 delegateType; UINT32 pcrInfoSize; BYTE *pcrInfo = NULL; UINT64 offset; TSS_RESULT result = TSS_SUCCESS; if (hDelegation == NULL_HPOLICY) return TSPERR(TSS_E_BAD_PARAMETER); if ((result = obj_policy_get_delegation_type(hDelegation, &delegateType))) return result; /* This call will create a "null" PCR_INFO_SHORT if hPcrs is null */ if ((result = obj_pcrs_create_info_short(hPcrs, &pcrInfoSize, &pcrInfo))) return result; __tspi_memset(&public, 0, sizeof(public)); public.tag = TPM_TAG_DELEGATE_PUBLIC; public.label.label = bLabel; offset = 0; if ((result = Trspi_UnloadBlob_PCR_INFO_SHORT(&offset, pcrInfo, &public.pcrInfo))) goto done; public.permissions.tag = TPM_TAG_DELEGATIONS; public.permissions.delegateType = (delegateType == TSS_DELEGATIONTYPE_OWNER) ? TPM_DEL_OWNER_BITS : TPM_DEL_KEY_BITS; if ((result = obj_policy_get_delegation_per1(hDelegation, &public.permissions.per1))) goto done; if ((result = obj_policy_get_delegation_per2(hDelegation, &public.permissions.per2))) goto done; if ((result = obj_delfamily_get_familyid(hFamily, &public.familyID))) goto done; if ((result = obj_delfamily_get_vercount(hFamily, &public.verificationCount))) goto done; offset = 0; Trspi_LoadBlob_TPM_DELEGATE_PUBLIC(&offset, NULL, &public); *publicInfoSize = offset; *publicInfo = malloc(*publicInfoSize); if (*publicInfo == NULL) { LogError("malloc of %u bytes failed.", *publicInfoSize); result = TSPERR(TSS_E_OUTOFMEMORY); goto done; } offset = 0; Trspi_LoadBlob_TPM_DELEGATE_PUBLIC(&offset, *publicInfo, &public); done: free(pcrInfo); free(public.pcrInfo.pcrSelection.pcrSelect); return result; } #ifdef TSS_BUILD_TRANSPORT TSS_RESULT Transport_Delegate_Manage(TSS_HCONTEXT tspContext, /* in */ TPM_FAMILY_ID familyID, /* in */ TPM_FAMILY_OPERATION opFlag, /* in */ UINT32 opDataSize, /* in */ BYTE *opData, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *retDataSize, /* out */ BYTE **retData) /* out */ { TSS_RESULT result; UINT32 handlesLen = 0, decLen, dataLen; UINT64 offset; BYTE *data, *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TPM_FAMILY_ID) + sizeof(TPM_FAMILY_OPERATION) + sizeof(UINT32) + opDataSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, familyID, data); Trspi_LoadBlob_UINT32(&offset, opFlag, data); Trspi_LoadBlob_UINT32(&offset, opDataSize, data); Trspi_LoadBlob(&offset, opDataSize, data, opData); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Delegate_Manage, dataLen, data, NULL, &handlesLen, NULL, ownerAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, retDataSize, dec); if ((*retData = malloc(*retDataSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *retDataSize); *retDataSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *retDataSize, dec, *retData); free(dec); return result; } TSS_RESULT Transport_Delegate_CreateKeyDelegation(TSS_HCONTEXT tspContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *keyAuth, /* in, out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result; UINT32 handlesLen, decLen, dataLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data, *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(hKey, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; handlesLen = 1; handle = hKey; handles = &handle; dataLen = publicInfoSize + sizeof(TPM_ENCAUTH); if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob(&offset, publicInfoSize, data, publicInfo); Trspi_LoadBlob(&offset, sizeof(TPM_ENCAUTH), data, encDelAuth->authdata); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Delegate_CreateKeyDelegation, dataLen, data, &pubKeyHash, &handlesLen, &handles, keyAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, blobSize, dec); if ((*blob = malloc(*blobSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *blobSize); *blobSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *blobSize, dec, *blob); free(dec); return result; } TSS_RESULT Transport_Delegate_CreateOwnerDelegation(TSS_HCONTEXT tspContext, /* in */ TSS_BOOL increment, /* in */ UINT32 publicInfoSize, /* in */ BYTE *publicInfo, /* in */ TPM_ENCAUTH *encDelAuth, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *blobSize, /* out */ BYTE **blob) /* out */ { TSS_RESULT result; UINT32 handlesLen = 0, decLen, dataLen; UINT64 offset; BYTE *data, *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TSS_BOOL) + publicInfoSize + sizeof(TPM_ENCAUTH); if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_BOOL(&offset, increment, data); Trspi_LoadBlob(&offset, publicInfoSize, data, publicInfo); Trspi_LoadBlob(&offset, sizeof(TPM_ENCAUTH), data, encDelAuth->authdata); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Delegate_CreateOwnerDelegation, dataLen, data, NULL, &handlesLen, NULL, ownerAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, blobSize, dec); if ((*blob = malloc(*blobSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *blobSize); *blobSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *blobSize, dec, *blob); free(dec); return result; } TSS_RESULT Transport_Delegate_LoadOwnerDelegation(TSS_HCONTEXT tspContext, /* in */ TPM_DELEGATE_INDEX index, /* in */ UINT32 blobSize, /* in */ BYTE *blob, /* in */ TPM_AUTH *ownerAuth) /* in, out */ { TSS_RESULT result; UINT32 handlesLen = 0, dataLen, decLen; UINT64 offset; BYTE *data, *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(TPM_DELEGATE_INDEX) + sizeof(UINT32) + blobSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, index, data); Trspi_LoadBlob_UINT32(&offset, blobSize, data); Trspi_LoadBlob(&offset, blobSize, data, blob); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Delegate_LoadOwnerDelegation, dataLen, data, NULL, &handlesLen, NULL, ownerAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); free(dec); return result; } TSS_RESULT Transport_Delegate_ReadTable(TSS_HCONTEXT tspContext, /* in */ UINT32 *familyTableSize, /* out */ BYTE **familyTable, /* out */ UINT32 *delegateTableSize, /* out */ BYTE **delegateTable) /* out */ { TSS_RESULT result; UINT32 handlesLen = 0, decLen; UINT64 offset; BYTE *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Delegate_ReadTable, 0, NULL, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec))) return result; offset = 0; Trspi_UnloadBlob_UINT32(&offset, familyTableSize, dec); if ((*familyTable = malloc(*familyTableSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *familyTableSize); *familyTableSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *familyTableSize, dec, *familyTable); Trspi_UnloadBlob_UINT32(&offset, delegateTableSize, dec); if ((*delegateTable = malloc(*delegateTableSize)) == NULL) { free(dec); free(*familyTable); *familyTable = NULL; *familyTableSize = 0; LogError("malloc of %u bytes failed", *delegateTableSize); *delegateTableSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *delegateTableSize, dec, *delegateTable); free(dec); return result; } TSS_RESULT Transport_Delegate_UpdateVerificationCount(TSS_HCONTEXT tspContext, /* in */ UINT32 inputSize, /* in */ BYTE *input, /* in */ TPM_AUTH *ownerAuth, /* in, out */ UINT32 *outputSize, /* out */ BYTE **output) /* out */ { TSS_RESULT result; UINT32 handlesLen = 0, decLen, dataLen; UINT64 offset; BYTE *data, *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = sizeof(UINT32) + inputSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, inputSize, data); Trspi_LoadBlob(&offset, inputSize, data, input); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_Delegate_UpdateVerification, dataLen, data, NULL, &handlesLen, NULL, ownerAuth, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, outputSize, dec); if ((*output = malloc(*outputSize)) == NULL) { free(dec); LogError("malloc of %u bytes failed", *outputSize); *outputSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(&offset, *outputSize, dec, *output); free(dec); return result; } TSS_RESULT Transport_Delegate_VerifyDelegation(TSS_HCONTEXT tspContext, /* in */ UINT32 delegateSize, /* in */ BYTE *delegate) /* in */ { TSS_RESULT result; UINT32 handlesLen = 0, dataLen, decLen; UINT64 offset; BYTE *data, *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); dataLen = + sizeof(UINT32) + delegateSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } offset = 0; Trspi_LoadBlob_UINT32(&offset, delegateSize, data); Trspi_LoadBlob(&offset, delegateSize, data, delegate); result = obj_context_transport_execute(tspContext, TPM_ORD_Delegate_VerifyDelegation, dataLen, data, NULL, &handlesLen, NULL, NULL, NULL, &decLen, &dec); free(data); free(dec); return result; } TSS_RESULT Transport_DSAP(TSS_HCONTEXT tspContext, /* in */ TPM_ENTITY_TYPE entityType, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TPM_NONCE *nonceOddDSAP, /* in */ UINT32 entityValueSize, /* in */ BYTE * entityValue, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TPM_NONCE *nonceEven, /* out */ TPM_NONCE *nonceEvenDSAP) /* out */ { TSS_RESULT result; UINT32 handlesLen, dataLen, decLen; TCS_HANDLE *handles, handle; TPM_DIGEST pubKeyHash; Trspi_HashCtx hashCtx; UINT64 offset; BYTE *data, *dec = NULL; if ((result = obj_context_transport_init(tspContext))) return result; LogDebugFn("Executing in a transport session"); if ((result = obj_tcskey_get_pubkeyhash(keyHandle, pubKeyHash.digest))) return result; result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); result |= Trspi_Hash_DIGEST(&hashCtx, pubKeyHash.digest); if ((result |= Trspi_HashFinal(&hashCtx, pubKeyHash.digest))) return result; dataLen = sizeof(TPM_ENTITY_TYPE) + sizeof(TPM_KEY_HANDLE) + sizeof(TPM_NONCE) + sizeof(UINT32) + entityValueSize; if ((data = malloc(dataLen)) == NULL) { LogError("malloc of %u bytes failed", dataLen); return TSPERR(TSS_E_OUTOFMEMORY); } handlesLen = 1; handle = keyHandle; handles = &handle; offset = 0; Trspi_LoadBlob_UINT32(&offset, entityType, data); Trspi_LoadBlob_UINT32(&offset, keyHandle, data); Trspi_LoadBlob(&offset, sizeof(TPM_NONCE), data, nonceEvenDSAP->nonce); Trspi_LoadBlob_UINT32(&offset, entityValueSize, data); Trspi_LoadBlob(&offset, entityValueSize, data, entityValue); if ((result = obj_context_transport_execute(tspContext, TPM_ORD_DSAP, dataLen, data, &pubKeyHash, &handlesLen, &handles, NULL, NULL, &decLen, &dec))) { free(data); return result; } free(data); offset = 0; Trspi_UnloadBlob_UINT32(&offset, authHandle, dec); Trspi_UnloadBlob(&offset, sizeof(TPM_NONCE), dec, nonceEven->nonce); Trspi_UnloadBlob(&offset, sizeof(TPM_NONCE), dec, nonceEvenDSAP->nonce); free(dec); return result; } #endif trousers-0.3.15/src/tcsd/0000775000175000017510000000000013736474160014502 5ustar deboradeboratrousers-0.3.15/src/tcsd/Makefile.am0000664000175000017510000000071313663651711016535 0ustar deboradeborasbin_PROGRAMS=tcsd tcsd_CFLAGS=-DAPPID=\"TCSD\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -I${top_srcdir}/src/include -fPIE -DPIE tcsd_LDADD=${top_builddir}/src/tcs/libtcs.a ${top_builddir}/src/tddl/libtddl.a -lpthread @CRYPTOLIB@ tcsd_LDFLAGS=@TCSD_LDFLAGS@ tcsd_SOURCES=svrside.c tcsd_conf.c tcsd_threads.c platform.c if TSS_BUILD_PS tcsd_CFLAGS+=-DTSS_BUILD_PS endif if TSS_BUILD_PCR_EVENTS tcsd_CFLAGS+=-DTSS_BUILD_PCR_EVENTS endif trousers-0.3.15/src/tcsd/svrside.c0000664000175000017510000003162313736474160016332 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include #include #include #include #include #include #include #include #if (defined (__OpenBSD__) || defined (__FreeBSD__)) #include #endif #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsps.h" #include "tcsd.h" #include "req_mgr.h" struct tcsd_config tcsd_options; struct tpm_properties tpm_metrics; static volatile int hup = 0, term = 0; extern char *optarg; char *tcsd_config_file = NULL; struct srv_sock_info { int sd; int domain; // AF_INET or AF_INET6 socklen_t addr_len; }; #define MAX_IP_PROTO 2 #define INVALID_ADDR_STR "" static void close_server_socks(struct srv_sock_info *socks_info) { int i, rv; for (i=0; i < MAX_IP_PROTO; i++) { if (socks_info[i].sd != -1) { do { rv = close(socks_info[i].sd); if (rv == -1 && errno != EINTR) { LogError("Error closing server socket descriptor - %s", strerror(errno)); continue; } } while (rv == -1 && errno == EINTR); } } } static void tcsd_shutdown(struct srv_sock_info socks_info[]) { close_server_socks(socks_info); /* order is important here: * allow all threads to complete their current request */ tcsd_threads_final(); PS_close_disk_cache(); auth_mgr_final(); (void)req_mgr_final(); conf_file_final(&tcsd_options); EVENT_LOG_final(); } static void tcsd_signal_term(int signal) { term = 1; } void tcsd_signal_hup(int signal) { hup = 1; } static TSS_RESULT signals_init(void) { int rc; sigset_t sigmask; struct sigaction sa; sigemptyset(&sigmask); if ((rc = sigaddset(&sigmask, SIGTERM))) { LogError("sigaddset: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } if ((rc = sigaddset(&sigmask, SIGHUP))) { LogError("sigaddset: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } if ((rc = THREAD_SET_SIGNAL_MASK(SIG_UNBLOCK, &sigmask, NULL))) { LogError("Setting thread signal mask: %s", strerror(rc)); return TCSERR(TSS_E_INTERNAL_ERROR); } sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = tcsd_signal_term; if ((rc = sigaction(SIGTERM, &sa, NULL))) { LogError("signal SIGTERM not registered: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } sa.sa_handler = tcsd_signal_hup; if ((rc = sigaction(SIGHUP, &sa, NULL))) { LogError("signal SIGHUP not registered: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } static TSS_RESULT tcsd_startup(void) { TSS_RESULT result; #ifdef TSS_DEBUG /* Set stdout to be unbuffered to match stderr and interleave output correctly */ setvbuf(stdout, (char *)NULL, _IONBF, 0); #endif if ((result = signals_init())) return result; if ((result = conf_file_init(&tcsd_options))) return result; if ((result = tcsd_threads_init())) { conf_file_final(&tcsd_options); return result; } if ((result = req_mgr_init())) { conf_file_final(&tcsd_options); return result; } if ((result = ps_dirs_init())) { conf_file_final(&tcsd_options); (void)req_mgr_final(); return result; } result = PS_init_disk_cache(); if (result != TSS_SUCCESS) { conf_file_final(&tcsd_options); (void)req_mgr_final(); return result; } if ((result = get_tpm_metrics(&tpm_metrics))) { conf_file_final(&tcsd_options); PS_close_disk_cache(); (void)req_mgr_final(); return result; } /* must happen after get_tpm_metrics() */ if ((result = auth_mgr_init())) { conf_file_final(&tcsd_options); PS_close_disk_cache(); (void)req_mgr_final(); return result; } result = EVENT_LOG_init(); if (result != TSS_SUCCESS) { auth_mgr_final(); conf_file_final(&tcsd_options); PS_close_disk_cache(); (void)req_mgr_final(); return result; } result = owner_evict_init(); if (result != TSS_SUCCESS) { auth_mgr_final(); conf_file_final(&tcsd_options); PS_close_disk_cache(); (void)req_mgr_final(); return result; } return TSS_SUCCESS; } void usage(void) { fprintf(stderr, "\tusage: tcsd [-f] [-e] [-c [-h]\n\n"); fprintf(stderr, "\t-f|--foreground\trun in the foreground. Logging goes to stderr " "instead of syslog.\n"); fprintf(stderr, "\t-e| attempts to connect to software TPMs over TCP\n"); fprintf(stderr, "\t-c|--config\tpath to configuration file\n"); fprintf(stderr, "\t-h|--help\tdisplay this help message\n"); fprintf(stderr, "\n"); } static TSS_RESULT reload_config(void) { TSS_RESULT result; hup = 0; // FIXME: reload the config - work in progress result = TSS_SUCCESS; return result; } int setup_ipv4_socket(struct srv_sock_info ssi[]) { struct sockaddr_in serv_addr; int sd, opt; ssi->sd = -1; // Initialization of IPv4 socket. sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) { LogWarn("Failed IPv4 socket: %s", strerror(errno)); goto err; } memset(&serv_addr, 0, sizeof (serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(tcsd_options.port); /* If no remote_ops are defined, restrict connections to localhost * only at the socket. */ if (tcsd_options.remote_ops[0] == 0) serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); opt = 1; setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (bind(sd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) { LogWarn("Failed IPv4 bind: %s", strerror(errno)); goto err; } if (listen(sd, TCSD_MAX_SOCKETS_QUEUED) < 0) { LogWarn("Failed IPv4 listen: %s", strerror(errno)); goto err; } ssi->domain = AF_INET; ssi->sd = sd; ssi->addr_len = sizeof(serv_addr); return 0; err: if (sd != -1) close(sd); return -1; } int setup_ipv6_socket(struct srv_sock_info *ssi) { struct sockaddr_in6 serv6_addr; int sd6, opt; ssi->sd = -1; sd6 = socket(AF_INET6, SOCK_STREAM, 0); if (sd6 < 0) { LogWarn("Failed IPv6 socket: %s", strerror(errno)); goto err; } memset(&serv6_addr, 0, sizeof (serv6_addr)); serv6_addr.sin6_family = AF_INET6; serv6_addr.sin6_port = htons(tcsd_options.port); /* If no remote_ops are defined, restrict connections to localhost * only at the socket. */ if (tcsd_options.remote_ops[0] == 0) serv6_addr.sin6_addr = in6addr_loopback; else serv6_addr.sin6_addr = in6addr_any; #ifdef __linux__ /* Linux, by default, allows one socket to be used by both IP stacks * This option disables that behavior, so you must have one socket for * each IP protocol. */ opt = 1; if(setsockopt(sd6, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) { LogWarn("Could not set IPv6 socket option properly.\n"); goto err; } #endif opt = 1; setsockopt(sd6, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (bind(sd6, (struct sockaddr *) &serv6_addr, sizeof (serv6_addr)) < 0) { LogWarn("Failed IPv6 bind: %s", strerror(errno)); goto err; } if (listen(sd6, TCSD_MAX_SOCKETS_QUEUED) < 0) { LogWarn("Failed IPv6 listen: %s", strerror(errno)); goto err; } ssi->domain = AF_INET6; ssi->sd = sd6; ssi->addr_len = sizeof(serv6_addr); return 0; err: if (sd6 != -1) close(sd6); return -1; } int setup_server_sockets(struct srv_sock_info ssi[]) { int i=0; ssi[0].sd = ssi[1].sd = -1; // Only enqueue sockets successfully bound or that weren't disabled. if (tcsd_options.disable_ipv4) { LogWarn("IPv4 support disabled by configuration option"); } else { if (setup_ipv4_socket(&ssi[i]) == 0) i++; } if (tcsd_options.disable_ipv6) { LogWarn("IPv6 support disabled by configuration option"); } else { setup_ipv6_socket(&ssi[i]); } // It's only a failure if both sockets are unavailable. if ((ssi[0].sd == -1) && (ssi[1].sd == -1)) { return -1; } return 0; } char *fetch_hostname(struct sockaddr_storage *client_addr, socklen_t socklen) { char buf[NI_MAXHOST]; if (getnameinfo((struct sockaddr *)client_addr, socklen, buf, sizeof(buf), NULL, 0, 0) != 0) { LogWarn("Could not retrieve client address info"); return NULL; } else { return strdup(buf); } } void prepare_for_select(struct srv_sock_info *socks_info, int *num_fds, fd_set *rdfd_set, int *nfds) { int i; FD_ZERO(rdfd_set); *num_fds = 0; *nfds = 0; // Filter out socket descriptors in the queue that // has the -1 value. for (i=0; i < MAX_IP_PROTO; i++) { if (socks_info[i].sd == -1) break; FD_SET(socks_info[i].sd, rdfd_set); (*num_fds)++; if (*nfds < socks_info[i].sd) // grab highest sd for select call *nfds = socks_info[i].sd; } } int main(int argc, char **argv) { TSS_RESULT result; int newsd, c, rv, option_index = 0; int i; socklen_t client_len; char *hostname = NULL; fd_set rdfd_set; int num_fds = 0; int nfds = 0; int stor_errno; sigset_t sigmask, termmask, oldsigmask; struct sockaddr_storage client_addr; struct srv_sock_info socks_info[MAX_IP_PROTO]; struct passwd *pwd; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"foreground", 0, NULL, 'f'}, {"config", 1, NULL, 'c'}, {0, 0, 0, 0} }; unsetenv("TCSD_USE_TCP_DEVICE"); while ((c = getopt_long(argc, argv, "fhec:", long_options, &option_index)) != -1) { switch (c) { case 'f': setenv("TCSD_FOREGROUND", "1", 1); break; case 'c': tcsd_config_file = optarg; break; case 'e': setenv("TCSD_USE_TCP_DEVICE", "1", 1); break; case 'h': /* fall through */ default: usage(); return -1; break; } } if (!tcsd_config_file) tcsd_config_file = TCSD_DEFAULT_CONFIG_FILE; if ((result = tcsd_startup())) return (int)result; #ifdef NOUSERCHECK LogWarn("will not switch user or check for file permissions. " "(Compiled with --disable-usercheck)"); #else #ifndef SOLARIS pwd = getpwnam(TSS_USER_NAME); if (pwd == NULL) { if (errno == 0) { LogError("User \"%s\" not found, please add this user" " manually.", TSS_USER_NAME); } else { LogError("getpwnam(%s): %s", TSS_USER_NAME, strerror(errno)); } return TCSERR(TSS_E_INTERNAL_ERROR); } setgid(pwd->pw_gid); setuid(pwd->pw_uid); #endif #endif if (setup_server_sockets(socks_info) == -1) { LogError("Could not create sockets to listen to connections. Aborting..."); return -1; } if (getenv("TCSD_FOREGROUND") == NULL) { if (daemon(0, 0) == -1) { perror("daemon"); tcsd_shutdown(socks_info); return -1; } } LogInfo("%s: TCSD up and running.", PACKAGE_STRING); sigemptyset(&sigmask); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGHUP); sigemptyset(&termmask); sigaddset(&termmask, SIGTERM); do { prepare_for_select(socks_info, &num_fds, &rdfd_set, &nfds); // Sanity check if (num_fds == 0) { LogError("No server sockets available to listen connections. Aborting..."); return -1; } // Block TERM and HUP signals to prevent race condition if (sigprocmask(SIG_BLOCK, &sigmask, &oldsigmask) == -1) { LogError("Error setting interrupt mask before accept"); } // TERM and HUP are blocked here, so its safe to test flags. if (hup) { // Config reading can be slow, so unmask SIGTERM. if (sigprocmask(SIG_UNBLOCK, &termmask, NULL) == -1) { LogError("Error unblocking SIGTERM before config reload"); } if (reload_config() != TSS_SUCCESS) LogError("Failed reloading config"); if (sigprocmask(SIG_BLOCK, &termmask, NULL) == -1) { LogError("Error blocking SIGTERM after config reload"); } } if (term) break; // Select IPv4 and IPv6 socket descriptors with appropriate sigmask. LogDebug("Waiting for connections"); rv = pselect(nfds+1, &rdfd_set, NULL, NULL, NULL, &oldsigmask); stor_errno = errno; // original mask must be set ASAP, so store errno. if (sigprocmask(SIG_SETMASK, &oldsigmask, NULL) == -1) { LogError("Error reseting signal mask to the original configuration."); } if (rv == -1) { if (stor_errno != EINTR) { LogError("Error monitoring server socket descriptors."); return -1; } continue; } for (i=0; i < num_fds; i++) { // accept connections from all IP versions (with valid sd) if (!FD_ISSET(socks_info[i].sd, &rdfd_set)) { continue; } client_len = socks_info[i].addr_len; newsd = accept(socks_info[i].sd, (struct sockaddr *) &client_addr, &client_len); if (newsd < 0) { if (errno != EINTR) LogError("Failed accept: %s", strerror(errno)); continue; } LogDebug("accepted socket %i", newsd); hostname = fetch_hostname(&client_addr, client_len); if (hostname == NULL) hostname=INVALID_ADDR_STR; tcsd_thread_create(newsd, hostname); hostname = NULL; } // for (i=0; i < MAX_IP_PROTO; i++) } while (term ==0); /* To close correctly, we must receive a SIGTERM */ tcsd_shutdown(socks_info); return 0; } trousers-0.3.15/src/tcsd/tcsd_threads.c0000664000175000017510000002411613663651711017317 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_int_literals.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcslog.h" #include "rpc_tcstp_tcs.h" struct tcsd_thread_mgr *tm = NULL; TSS_RESULT tcsd_threads_final() { int rc; UINT32 i; MUTEX_LOCK(tm->lock); tm->shutdown = 1; MUTEX_UNLOCK(tm->lock); /* wait for all currently running threads to exit */ for (i = 0; i < tm->max_threads; i++) { if (tm->thread_data[i].thread_id != THREAD_NULL) { if ((rc = THREAD_JOIN(*(tm->thread_data[i].thread_id), NULL))) { LogError("Thread join failed: error: %d", rc); } } } free(tm->thread_data); free(tm); return TSS_SUCCESS; } TSS_RESULT tcsd_threads_init(void) { /* allocate the thread mgmt structure */ tm = calloc(1, sizeof(struct tcsd_thread_mgr)); if (tm == NULL) { LogError("malloc of %zd bytes failed.", sizeof(struct tcsd_thread_mgr)); return TCSERR(TSS_E_OUTOFMEMORY); } /* initialize mutex */ MUTEX_INIT(tm->lock); /* set the max threads variable from config */ tm->max_threads = tcsd_options.num_threads; /* allocate each thread's data structure */ tm->thread_data = calloc(tcsd_options.num_threads, sizeof(struct tcsd_thread_data)); if (tm->thread_data == NULL) { LogError("malloc of %zu bytes failed.", tcsd_options.num_threads * sizeof(struct tcsd_thread_data)); free(tm); return TCSERR(TSS_E_OUTOFMEMORY); } return TSS_SUCCESS; } TSS_RESULT tcsd_thread_create(int socket, char *hostname) { UINT32 thread_num = -1; int rc = TCS_SUCCESS; #ifndef TCSD_SINGLE_THREAD_DEBUG THREAD_ATTR_DECLARE(tcsd_thread_attr); /* init the thread attribute */ if ((rc = THREAD_ATTR_INIT(tcsd_thread_attr))) { LogError("Initializing thread attribute failed: error=%d: %s", rc, strerror(rc)); rc = TCSERR(TSS_E_INTERNAL_ERROR); goto out; } /* make all threads joinable */ if ((rc = THREAD_ATTR_SETJOINABLE(tcsd_thread_attr))) { LogError("Making thread attribute joinable failed: error=%d: %s", rc, strerror(rc)); rc = TCSERR(TSS_E_INTERNAL_ERROR); goto out; } MUTEX_LOCK(tm->lock); #endif if (tm->num_active_threads == tm->max_threads) { if (hostname != NULL) { LogError("max number of connections reached (%d), new connection" " from %s refused.", tm->max_threads, hostname); } else { LogError("max number of connections reached (%d), new connection" " refused.", tm->max_threads); } rc = TCSERR(TSS_E_CONNECTION_FAILED); #ifndef TCSD_SINGLE_THREAD_DEBUG goto out_unlock; #else goto out; #endif } /* search for an open slot to store the thread data in */ for (thread_num = 0; thread_num < tm->max_threads; thread_num++) { if (tm->thread_data[thread_num].thread_id == THREAD_NULL) break; } DBG_ASSERT(thread_num != tm->max_threads); tm->thread_data[thread_num].sock = socket; tm->thread_data[thread_num].context = NULL_TCS_HANDLE; if (hostname != NULL) tm->thread_data[thread_num].hostname = hostname; #ifdef TCSD_SINGLE_THREAD_DEBUG (void)tcsd_thread_run((void *)(&(tm->thread_data[thread_num]))); #else tm->thread_data[thread_num].thread_id = calloc(1, sizeof(THREAD_TYPE)); if (tm->thread_data[thread_num].thread_id == NULL) { rc = TCSERR(TSS_E_OUTOFMEMORY); LogError("malloc of %zd bytes failed.", sizeof(THREAD_TYPE)); goto out_unlock; } if ((rc = THREAD_CREATE(tm->thread_data[thread_num].thread_id, &tcsd_thread_attr, tcsd_thread_run, (void *)(&(tm->thread_data[thread_num]))))) { LogError("Thread create failed: %d", rc); rc = TCSERR(TSS_E_INTERNAL_ERROR); goto out_unlock; } tm->num_active_threads++; out_unlock: MUTEX_UNLOCK(tm->lock); #endif out: /* cleanup in case of error */ if (rc != TCS_SUCCESS) { if (hostname != NULL) { if (thread_num != -1) tm->thread_data[thread_num].hostname = NULL; free(hostname); } close(socket); } return rc; } /* Since we don't want any of the worker threads to catch any signals, we must mask off any * potential signals here after creating the threads. If any of the created threads catch a signal, * they'd eventually call join on themselves, causing a deadlock. */ void thread_signal_init() { sigset_t thread_sigmask; int rc; if ((rc = sigfillset(&thread_sigmask))) { LogError("sigfillset failed: error=%d: %s", rc, strerror(rc)); LogError("worker thread %ld is exiting prematurely", THREAD_ID); THREAD_EXIT(NULL); } if ((rc = THREAD_SET_SIGNAL_MASK(SIG_BLOCK, &thread_sigmask, NULL))) { LogError("Setting thread sigmask failed: error=%d: %s", rc, strerror(rc)); LogError("worker thread %ld is exiting prematurely", THREAD_ID); THREAD_EXIT(NULL); } } void * tcsd_thread_run(void *v) { struct tcsd_thread_data *data = (struct tcsd_thread_data *)v; BYTE *buffer; int recd_so_far, empty_space, total_recv_size, recv_chunk_size, send_size; TSS_RESULT result; UINT64 offset; #ifndef TCSD_SINGLE_THREAD_DEBUG int rc; thread_signal_init(); #endif data->comm.buf_size = TCSD_INIT_TXBUF_SIZE; data->comm.buf = calloc(1, data->comm.buf_size); while (data->comm.buf) { /* get the packet header to get the size of the incoming packet */ if (recv_from_socket(data->sock, data->comm.buf, sizeof(struct tcsd_packet_hdr)) < 0) break; recd_so_far = sizeof(struct tcsd_packet_hdr); /* check the packet size */ total_recv_size = Decode_UINT32(data->comm.buf); if (total_recv_size < (int)sizeof(struct tcsd_packet_hdr)) { LogError("Packet to receive from socket %d is too small (%d bytes)", data->sock, total_recv_size); break; } LogDebug("total_recv_size %d, buf_size %u, recd_so_far %d", total_recv_size, data->comm.buf_size, recd_so_far); empty_space = data->comm.buf_size - recd_so_far; /* instead of blindly allocating recv_size bytes off the bat, stage the realloc * and wait for the data to come in over the socket. This protects against * trivially asking tcsd to alloc 2GB */ while (total_recv_size > (int) data->comm.buf_size) { BYTE *new_buffer; int new_bufsize; if ((int)data->comm.buf_size + TCSD_INCR_TXBUF_SIZE < total_recv_size) { new_bufsize = data->comm.buf_size + TCSD_INCR_TXBUF_SIZE; recv_chunk_size = empty_space + TCSD_INCR_TXBUF_SIZE; } else { new_bufsize = total_recv_size; recv_chunk_size = total_recv_size - recd_so_far; } LogDebug("Increasing communication buffer to %d bytes.", new_bufsize); new_buffer = realloc(data->comm.buf, new_bufsize); if (new_buffer == NULL) { LogError("realloc of %d bytes failed.", new_bufsize); data->comm.buf = NULL; goto no_mem_error; } data->comm.buf_size = new_bufsize; data->comm.buf = new_buffer; buffer = data->comm.buf + recd_so_far; LogDebug("recv_chunk_size %d recd_so_far %d", recv_chunk_size, recd_so_far); if (recv_from_socket(data->sock, buffer, recv_chunk_size) < 0) { result = TCSERR(TSS_E_INTERNAL_ERROR); goto error; } recd_so_far += recv_chunk_size; empty_space = 0; } if (recd_so_far < total_recv_size) { buffer = data->comm.buf + recd_so_far; recv_chunk_size = total_recv_size - recd_so_far; LogDebug("recv_chunk_size %d recd_so_far %d", recv_chunk_size, recd_so_far); if (recv_from_socket(data->sock, buffer, recv_chunk_size) < 0) { result = TCSERR(TSS_E_INTERNAL_ERROR); goto error; } } LogDebug("Rx'd packet"); /* create a platform version of the tcsd header */ offset = 0; UnloadBlob_UINT32(&offset, &data->comm.hdr.packet_size, data->comm.buf); UnloadBlob_UINT32(&offset, &data->comm.hdr.u.result, data->comm.buf); UnloadBlob_UINT32(&offset, &data->comm.hdr.num_parms, data->comm.buf); UnloadBlob_UINT32(&offset, &data->comm.hdr.type_size, data->comm.buf); UnloadBlob_UINT32(&offset, &data->comm.hdr.type_offset, data->comm.buf); UnloadBlob_UINT32(&offset, &data->comm.hdr.parm_size, data->comm.buf); UnloadBlob_UINT32(&offset, &data->comm.hdr.parm_offset, data->comm.buf); result = getTCSDPacket(data); error: if (result) { /* something internal to the TCSD went wrong in preparing the packet * to return to the TSP. Use our already allocated buffer to return a * TSS_E_INTERNAL_ERROR return code to the TSP. In the non-error path, * these LoadBlob's are done in getTCSDPacket(). */ /* set everything to zero, fill in what is non-zero */ memset(data->comm.buf, 0, data->comm.buf_size); offset = 0; /* load packet size */ LoadBlob_UINT32(&offset, sizeof(struct tcsd_packet_hdr), data->comm.buf); /* load result */ LoadBlob_UINT32(&offset, result, data->comm.buf); } send_size = Decode_UINT32(data->comm.buf); LogDebug("Sending 0x%X bytes back", send_size); send_size = send_to_socket(data->sock, data->comm.buf, send_size); if (send_size < 0) break; /* check for shutdown */ if (tm->shutdown) { LogDebug("Thread %ld exiting via shutdown signal!", THREAD_ID); break; } } no_mem_error: LogDebug("Thread exiting."); /* Closing connection to TSP */ close(data->sock); data->sock = -1; free(data->comm.buf); data->comm.buf = NULL; data->comm.buf_size = -1; /* If the connection was not shut down cleanly, free TCS resources here */ if (data->context != NULL_TCS_HANDLE) { TCS_CloseContext_Internal(data->context); data->context = NULL_TCS_HANDLE; } if(data->hostname != NULL) { free(data->hostname); data->hostname = NULL; } #ifndef TCSD_SINGLE_THREAD_DEBUG pthread_mutex_lock(&(tm->lock)); tm->num_active_threads--; /* if we're not in shutdown mode, then nobody is waiting to join this thread, so * detach it so that its resources are free at pthread_exit() time. */ if (!tm->shutdown) { if ((rc = pthread_detach(*(data->thread_id)))) { LogError("pthread_detach failed (errno %d)." " Resources may not be properly released.", rc); } } free(data->thread_id); data->thread_id = THREAD_NULL; pthread_mutex_unlock(&(tm->lock)); pthread_exit(NULL); #endif return NULL; } trousers-0.3.15/src/tcsd/platform.c0000664000175000017510000000502713663651711016474 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ #if (defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__APPLE__)) #include #include #include #elif (defined (__linux) || defined (linux) || defined(__GLIBC__)) #include #elif (defined (SOLARIS)) #include #endif #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_int_literals.h" #include "capabilities.h" #include "tcsps.h" #include "tcslog.h" #if (defined (__linux) || defined (linux) || defined(__GLIBC__)) MUTEX_DECLARE_INIT(utmp_lock); char platform_get_runlevel() { char runlevel; struct utmp ut, save, *next = NULL; struct timeval tv; int flag = 0, counter = 0; MUTEX_LOCK(utmp_lock); memset(&ut, 0, sizeof(struct utmp)); memset(&save, 0, sizeof(struct utmp)); memset(&tv, 0, sizeof(struct timeval)); ut.ut_type = RUN_LVL; setutent(); next = getutid(&ut); while (next != NULL) { if (next->ut_tv.tv_sec > tv.tv_sec) { memcpy(&save, next, sizeof(*next)); flag = 1; } else if (next->ut_tv.tv_sec == tv.tv_sec) { if (next->ut_tv.tv_usec > tv.tv_usec) { memcpy(&save, next, sizeof(*next)); flag = 1; } } counter++; next = getutid(&ut); } if (flag) { //printf("prev_runlevel=%c, runlevel=%c\n", save.ut_pid / 256, save.ut_pid % 256); runlevel = save.ut_pid % 256; } else { //printf("unknown\n"); runlevel = 'u'; } MUTEX_UNLOCK(utmp_lock); return runlevel; } #elif (defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__APPLE__)) char platform_get_runlevel() { int mib[2], rlevel = -1; size_t len; mib[0] = CTL_KERN; mib[1] = KERN_SECURELVL; len = sizeof(rlevel); if (sysctl(mib,2,&rlevel,&len, NULL,0) == -1) { err(1,"Could not get runlevel"); return 'u'; } #if defined (__OpenBSD__) if (rlevel == 0) #else if (rlevel == -1) #endif return 's'; return rlevel + '0'; } #elif (defined (SOLARIS)) MUTEX_DECLARE_INIT(utmp_lock); char platform_get_runlevel() { char runlevel = 'u'; /* unknown run level */ struct utmpx ut, *utp = NULL; MUTEX_LOCK(utmp_lock); memset(&ut, 0, sizeof(ut)); ut.ut_type = RUN_LVL; setutxent(); utp = getutxid(&ut); if (utp->ut_type == RUN_LVL && sscanf(utp->ut_line, "run-level %c", &runlevel) != 1) runlevel = 'u'; endutxent(); MUTEX_UNLOCK(utmp_lock); return runlevel; } #endif trousers-0.3.15/src/tcsd/tcsd_conf.c0000664000175000017510000005777313736474160016633 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #include #include #include #include #include #include #include #include #include #include #include #ifdef SOLARIS #include #endif #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" #include "tcs_utils.h" #include "tcsps.h" #include "tcslog.h" #include "tcsd_wrap.h" #include "tcsd.h" #include "tcsd_ops.h" struct tcsd_config_options options_list[] = { {"port", opt_port}, {"num_threads", opt_max_threads}, {"system_ps_file", opt_system_ps_file}, {"firmware_log_file", opt_firmware_log}, {"firmware_pcrs", opt_firmware_pcrs}, {"kernel_log_file", opt_kernel_log}, {"kernel_pcrs", opt_kernel_pcrs}, {"platform_cred", opt_platform_cred}, {"conformance_cred", opt_conformance_cred}, {"endorsement_cred", opt_endorsement_cred}, {"remote_ops", opt_remote_ops}, {"enforce_exclusive_transport", opt_exclusive_transport}, {"host_platform_class", opt_host_platform_class}, {"all_platform_classes", opt_all_platform_classes}, {"disable_ipv4", opt_disable_ipv4}, {"disable_ipv6", opt_disable_ipv6}, {NULL, 0} }; struct tcg_platform_spec tcg_platform_specs[] = { {"PC_11", TPM_PS_PC_11, TPM_PS_PC_11_URI}, {"PC_12", TPM_PS_PC_12, TPM_PS_PC_12_URI}, {"PDA_12", TPM_PS_PDA_12, TPM_PS_PDA_12_URI}, {"SERVER_12", TPM_PS_Server_12, TPM_PS_Server_12_URI}, {"MOBILE_12", TPM_PS_Mobile_12, TPM_PS_Mobile_12_URI}, {NULL, 0, 0} }; void init_tcsd_config(struct tcsd_config *conf) { conf->port = -1; conf->num_threads = -1; conf->system_ps_file = NULL; conf->system_ps_dir = NULL; conf->firmware_log_file = NULL; conf->firmware_pcrs = 0; conf->kernel_log_file = NULL; conf->kernel_pcrs = 0; conf->platform_cred = NULL; conf->conformance_cred = NULL; conf->endorsement_cred = NULL; memset(conf->remote_ops, 0, sizeof(conf->remote_ops)); conf->unset = 0xffffffff; conf->exclusive_transport = 0; conf->host_platform_class = NULL; conf->all_platform_classes = NULL; conf->disable_ipv4 = 0; conf->disable_ipv6 = 0; } TSS_RESULT platform_class_list_append(struct tcsd_config *conf, char *specName, TSS_BOOL is_main) { int i; struct platform_class *tmp, *new_class; LogDebugFn("platform_class_list_append start:"); for (i = 0; tcg_platform_specs[i].name; i++) { if (!strncasecmp(specName, tcg_platform_specs[i].name, strlen(tcg_platform_specs[i].name))) { /* Allocate the new structure */ new_class = malloc(sizeof(struct platform_class)); if (new_class == NULL) { LogError("malloc of %zd bytes failed", sizeof(struct platform_class)); return TCSERR(TSS_E_OUTOFMEMORY); } new_class->simpleID = tcg_platform_specs[i].specNo; new_class->classURISize = strlen(tcg_platform_specs[i].specURI) + 1; new_class->classURI = malloc(new_class->classURISize); if (new_class->classURI == NULL) { LogError("malloc of %u bytes failed", new_class->classURISize); free(new_class); return TCSERR(TSS_E_OUTOFMEMORY); } memcpy(new_class->classURI, tcg_platform_specs[i].specURI, new_class->classURISize); /* Append to the start of the list */ if (is_main) { tmp = conf->host_platform_class; conf->host_platform_class = new_class; } else { tmp = conf->all_platform_classes; conf->all_platform_classes = new_class; } new_class->next = tmp; LogDebugFn("Platform Class Added."); return TSS_SUCCESS; } } LogError("TCG Specification not supported: \"%s\"", specName); return TCSERR(TSS_E_INTERNAL_ERROR); } void config_set_defaults(struct tcsd_config *conf) { /* give all unset options their default values */ if (conf->unset & TCSD_OPTION_PORT) conf->port = TCSD_DEFAULT_PORT; if (conf->unset & TCSD_OPTION_MAX_THREADS) conf->num_threads = TCSD_DEFAULT_MAX_THREADS; if (conf->unset & TCSD_OPTION_FIRMWARE_PCRS) conf->firmware_pcrs = TCSD_DEFAULT_FIRMWARE_PCRS; if (conf->unset & TCSD_OPTION_KERNEL_PCRS) conf->kernel_pcrs = TCSD_DEFAULT_KERNEL_PCRS; /* these are strdup'd so we know we can free them at shutdown time */ if (conf->unset & TCSD_OPTION_SYSTEM_PSFILE) { conf->system_ps_file = strdup(TCSD_DEFAULT_SYSTEM_PS_FILE); conf->system_ps_dir = strdup(TCSD_DEFAULT_SYSTEM_PS_DIR); } if (conf->unset & TCSD_OPTION_FIRMWARE_LOGFILE) conf->firmware_log_file = strdup(TCSD_DEFAULT_FIRMWARE_LOG_FILE); if (conf->unset & TCSD_OPTION_KERNEL_LOGFILE) conf->kernel_log_file = strdup(TCSD_DEFAULT_KERNEL_LOG_FILE); if (conf->unset & TCSD_OPTION_HOST_PLATFORM_CLASS) platform_class_list_append(conf, "PC_12", TRUE); if (conf->unset & TCSD_OPTION_DISABLE_IPV4) conf->disable_ipv4 = TCSD_DEFAULT_DISABLE_IPV4; if (conf->unset & TCSD_OPTION_DISABLE_IPV6) conf->disable_ipv6 = TCSD_DEFAULT_DISABLE_IPV6; } int get_config_option(char *ptr, char **arg) { int i; for (i = 0; options_list[i].name; i++) { if (!strncasecmp(ptr, options_list[i].name, strlen(options_list[i].name))) { /* move ptr past our recognized token */ ptr += strlen(options_list[i].name); /* try to move ptr to the start of the option's argument */ while (*ptr == '=' || *ptr == ' ' || *ptr == '\t') ptr++; *arg = ptr; return options_list[i].option; } } /* on error we'll print the whole line to the log */ *arg = ptr; return 0; } /* copy a file path from a string into a newly malloc'd string */ int get_file_path(char *ptr, char **dest) { char tmp_buf[1024]; int i = 0; while (isalpha(*ptr) || isdigit(*ptr) || *ptr == '/' || *ptr == '.' || *ptr == '#' || *ptr == '_' || *ptr == '-') { tmp_buf[i] = *ptr; ptr++; i++; } /* move through whitespace after the path */ while (*ptr == ' ' || *ptr == '\t') ptr++; /* if we're not at a comment or EOL, there's junk */ if (*ptr != '#' && *ptr != '\n') { *dest = ptr; return 1; } /* too short a path */ if (i == 0) return -1; tmp_buf[i] = '\0'; *dest = strdup(tmp_buf); if (*dest == NULL) { LogError("malloc of %zd bytes failed", strlen(tmp_buf)); } return 0; } /* add an op ordinal, checking for duplicates along the way */ void tcsd_add_op(int *remote_ops, int *op) { int i = 0, j; while (op[i] != 0) { j = 0; while (remote_ops[j] != 0) { if (remote_ops[j] == op[i]) { break; } j++; } remote_ops[j] = op[i]; i++; } } int tcsd_set_remote_op(struct tcsd_config *conf, char *op_name) { int i = 0; while(tcsd_ops[i]) { if (!strcasecmp(tcsd_ops[i]->name, op_name)) { /* match found */ tcsd_add_op(conf->remote_ops, tcsd_ops[i]->op); return 0; } i++; } /* fail, op not found */ return 1; } TSS_RESULT read_conf_line(char *buf, int line_num, struct tcsd_config *conf) { char *ptr = buf, *tmp_ptr = NULL, *arg, *comma; int option, tmp_int; TSS_RESULT result; if (ptr == NULL || *ptr == '\0' || *ptr == '#' || *ptr == '\n') return TSS_SUCCESS; /* read through whitespace */ while (*ptr == ' ' || *ptr == '\t') ptr++; /* ignore comments */ if (*ptr == '#') return TSS_SUCCESS; option = get_config_option(ptr, &arg); switch (option) { case opt_port: tmp_int = atoi(arg); if (tmp_int < 0 || tmp_int > 65535) { LogError("Config option \"port\" out of range. %s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); return TCSERR(TSS_E_INTERNAL_ERROR); } else { conf->port = tmp_int; conf->unset &= ~TCSD_OPTION_PORT; } break; case opt_max_threads: tmp_int = atoi(arg); if (tmp_int <= 0) { LogError("Config option \"num_threads\" out of range. %s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); return TCSERR(TSS_E_INTERNAL_ERROR); } else { conf->num_threads = tmp_int; conf->unset &= ~TCSD_OPTION_MAX_THREADS; } break; case opt_firmware_pcrs: conf->unset &= ~TCSD_OPTION_FIRMWARE_PCRS; while (1) { comma = rindex(arg, ','); if (comma == NULL) { if (!isdigit(*arg)) break; comma = arg; tmp_int = atoi(comma); if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS) conf->firmware_pcrs |= (1 << tmp_int); else LogError("Config option \"firmware_pcrs\" is out of range." "%s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); break; } *comma++ = '\0'; tmp_int = atoi(comma); if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS) conf->firmware_pcrs |= (1 << tmp_int); else LogError("Config option \"firmware_pcrs\" is out of range. " "%s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); } break; case opt_kernel_pcrs: conf->unset &= ~TCSD_OPTION_KERNEL_PCRS; while (1) { comma = rindex(arg, ','); if (comma == NULL) { if (!isdigit(*arg)) break; comma = arg; tmp_int = atoi(comma); if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS) conf->kernel_pcrs |= (1 << tmp_int); else LogError("Config option \"kernel_pcrs\" is out of range. " "%s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); break; } *comma++ = '\0'; tmp_int = atoi(comma); if (tmp_int >= 0 && tmp_int < TCSD_MAX_PCRS) conf->kernel_pcrs |= (1 << tmp_int); else LogError("Config option \"kernel_pcrs\" is out of range. " "%s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); } break; case opt_system_ps_file: if (*arg != '/') { LogError("Config option \"system_ps_dir\" must be an absolute path name. " "%s:%d: \"%s\"", tcsd_config_file, line_num, arg); } else { char *dir_ptr; int rc; if ((rc = get_file_path(arg, &tmp_ptr)) < 0) { LogError("Config option \"system_ps_file\" is invalid." " %s:%d: \"%s\"", tcsd_config_file, line_num, arg); return TCSERR(TSS_E_INTERNAL_ERROR); } else if (rc > 0) { LogError("Config option \"system_ps_file\" is invalid. %s:%d:" " \"%s\"", tcsd_config_file, line_num, tmp_ptr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (tmp_ptr == NULL) return TCSERR(TSS_E_OUTOFMEMORY); if (conf->system_ps_file) free(conf->system_ps_file); if (conf->system_ps_dir) free(conf->system_ps_dir); /* break out the system ps directory from the file path */ dir_ptr = rindex(tmp_ptr, '/'); *dir_ptr = '\0'; if (strlen(tmp_ptr) == 0) conf->system_ps_dir = strdup("/"); else conf->system_ps_dir = strdup(tmp_ptr); if (conf->system_ps_dir == NULL) { LogError("malloc failed."); free(tmp_ptr); return TCSERR(TSS_E_OUTOFMEMORY); } *dir_ptr = '/'; conf->system_ps_file = tmp_ptr; conf->unset &= ~TCSD_OPTION_SYSTEM_PSFILE; } break; case opt_kernel_log: if (*arg != '/') { LogError("Config option \"kernel_log\" must be an absolute path name." " %s:%d: \"%s\"", tcsd_config_file, line_num, arg); } else { int rc; if ((rc = get_file_path(arg, &tmp_ptr)) < 0) { LogError("Config option \"kernel_log\" is invalid. %s:%d: \"%s\"", tcsd_config_file, line_num, arg); return TCSERR(TSS_E_INTERNAL_ERROR); } else if (rc > 0) { LogError("Config option \"kernel_log\" is invalid. %s:%d: \"%s\"", tcsd_config_file, line_num, tmp_ptr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (tmp_ptr == NULL) return TCSERR(TSS_E_OUTOFMEMORY); if (conf->kernel_log_file) free(conf->kernel_log_file); conf->kernel_log_file = tmp_ptr; conf->unset &= ~TCSD_OPTION_KERNEL_LOGFILE; } break; case opt_firmware_log: if (*arg != '/') { LogError("Config option \"firmware_log\" must be an absolute path name." " %s:%d: \"%s\"", tcsd_config_file, line_num, arg); } else { int rc; if ((rc = get_file_path(arg, &tmp_ptr)) < 0) { LogError("Config option \"firmware_log\" is invalid. %s:%d: \"%s\"", tcsd_config_file, line_num, arg); return TCSERR(TSS_E_INTERNAL_ERROR); } else if (rc > 0) { LogError("Config option \"firmware_log\" is invalid. %s:%d: \"%s\"", tcsd_config_file, line_num, tmp_ptr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (tmp_ptr == NULL) return TCSERR(TSS_E_OUTOFMEMORY); if (conf->firmware_log_file) free(conf->firmware_log_file); conf->firmware_log_file = tmp_ptr; conf->unset &= ~TCSD_OPTION_FIRMWARE_LOGFILE; } break; case opt_platform_cred: if (*arg != '/') { LogError("Config option \"platform_cred\" must be an absolute path name. " "%s:%d: \"%s\"", tcsd_config_file, line_num, arg); } else { int rc; if ((rc = get_file_path(arg, &tmp_ptr)) < 0) { LogError("Config option \"platform_cred\" is invalid. %s:%d: " "\"%s\"", tcsd_config_file, line_num, arg); return TCSERR(TSS_E_INTERNAL_ERROR); } else if (rc > 0) { LogError("Config option \"platform_cred\" is invalid. %s:%d: " "\"%s\"", tcsd_config_file, line_num, tmp_ptr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (tmp_ptr == NULL) return TCSERR(TSS_E_OUTOFMEMORY); if (conf->platform_cred) free(conf->platform_cred); conf->platform_cred = tmp_ptr; conf->unset &= ~TCSD_OPTION_PLATFORM_CRED; } break; case opt_conformance_cred: if (*arg != '/') { LogError("Config option \"conformance_cred\" must be an absolute path name." " %s:%d: \"%s\"", tcsd_config_file, line_num, arg); } else { int rc; if ((rc = get_file_path(arg, &tmp_ptr)) < 0) { LogError("Config option \"conformance_cred\" is invalid. %s:%d: " "\"%s\"", tcsd_config_file, line_num, arg); return TCSERR(TSS_E_INTERNAL_ERROR); } else if (rc > 0) { LogError("Config option \"conformance_cred\" is invalid. %s:%d: " "\"%s\"", tcsd_config_file, line_num, tmp_ptr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (tmp_ptr == NULL) return TCSERR(TSS_E_OUTOFMEMORY); if (conf->conformance_cred) free(conf->conformance_cred); conf->conformance_cred = tmp_ptr; conf->unset &= ~TCSD_OPTION_CONFORMANCE_CRED; } break; case opt_endorsement_cred: if (*arg != '/') { LogError("Config option \"endorsement_cred\" must be an absolute path name." " %s:%d: \"%s\"", tcsd_config_file, line_num, arg); } else { int rc; if ((rc = get_file_path(arg, &tmp_ptr)) < 0) { LogError("Config option \"endorsement_cred\" is invalid. %s:%d: " "\"%s\"", tcsd_config_file, line_num, arg); return TCSERR(TSS_E_INTERNAL_ERROR); } else if (rc > 0) { LogError("Config option \"endorsement_cred\" is invalid. %s:%d: " "\"%s\"", tcsd_config_file, line_num, tmp_ptr); return TCSERR(TSS_E_INTERNAL_ERROR); } if (tmp_ptr == NULL) return TCSERR(TSS_E_OUTOFMEMORY); if (conf->endorsement_cred) free(conf->endorsement_cred); conf->endorsement_cred = tmp_ptr; conf->unset &= ~TCSD_OPTION_ENDORSEMENT_CRED; } break; case opt_remote_ops: conf->unset &= ~TCSD_OPTION_REMOTE_OPS; comma = rindex(arg, '\n'); *comma = '\0'; while (1) { comma = rindex(arg, ','); if (comma == NULL) { comma = arg; if (comma != NULL) { if (tcsd_set_remote_op(conf, comma)) { LogError("Config option \"remote_ops\" is invalid. " "%s:%d: \"%s\"", tcsd_config_file, line_num, comma); } } break; } *comma++ = '\0'; if (tcsd_set_remote_op(conf, comma)) { LogError("Config option \"remote_ops\" is invalid. " "%s:%d: \"%s\"", tcsd_config_file, line_num, comma); } } break; case opt_exclusive_transport: tmp_int = atoi(arg); if (tmp_int < 0 || tmp_int > 1) { LogError("Config option \"enforce_exclusive_transport\" out of range." " %s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); return TCSERR(TSS_E_INTERNAL_ERROR); } else { conf->exclusive_transport = tmp_int; conf->unset &= ~TCSD_OPTION_EXCLUSIVE_TRANSPORT; } break; case opt_host_platform_class: /* append the host class on the list */ conf->unset &= ~TCSD_OPTION_HOST_PLATFORM_CLASS; comma = rindex(arg,'\n'); *comma = '\0'; comma = rindex(arg,','); /* At least one comma: error - more than one host class defined */ if (comma != NULL) { LogError("Config option \"host_platform_class\" error: more than one " "defined. %s:%d: \"%s\"", tcsd_config_file, line_num, comma); return TCSERR(TSS_E_INTERNAL_ERROR); } else { comma = arg; /* Add the platform class on the list */ if ((result = platform_class_list_append(conf, comma, TRUE))){ LogError("Config option \"host_platform_class\" invalid. " "%s:%d: \"%s\"", tcsd_config_file, line_num, comma); return result; } } break; case opt_all_platform_classes: /* append each of the comma separated values on the list */ comma = rindex(arg, '\n'); *comma = '\0'; while (1) { comma = rindex(arg, ','); if (comma == NULL) { comma = arg; if (comma != NULL) { /* Add the platform class on the list */ if ((result = platform_class_list_append(conf, comma, FALSE))) { LogError("Config option \"all_platform_class\" " "invalid. %s:%d: \"%s\"", tcsd_config_file, line_num, comma); return result; } } break; } *comma++ = '\0'; /* Add the platform class on the list */ if ((result = platform_class_list_append(conf, comma, FALSE))) { LogError("Config option \"all_platform_class\" invalid. " "%s:%d: \"%s\"", tcsd_config_file, line_num, comma); return result; } } break; case opt_disable_ipv4: tmp_int = atoi(arg); if (tmp_int < 0 || tmp_int > 1) { LogError("Config option \"disable_ipv4\" out of range." " %s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); return TCSERR(TSS_E_INTERNAL_ERROR); } else { conf->disable_ipv4 = tmp_int; conf->unset &= ~TCSD_OPTION_DISABLE_IPV4; } break; case opt_disable_ipv6: tmp_int = atoi(arg); if (tmp_int < 0 || tmp_int > 1) { LogError("Config option \"disable_ipv6\" out of range." " %s:%d: \"%d\"", tcsd_config_file, line_num, tmp_int); return TCSERR(TSS_E_INTERNAL_ERROR); } else { conf->disable_ipv6 = tmp_int; conf->unset &= ~TCSD_OPTION_DISABLE_IPV6; } break; default: /* bail out on any unknown option */ LogError("Unknown config option %s:%d \"%s\"!", tcsd_config_file, line_num, arg); return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT read_conf_file(FILE *f, struct tcsd_config *conf) { int line_num = 0; char buf[1024]; while (fgets(buf, 1024, f)) { line_num++; if (read_conf_line(buf, line_num, conf)) return TCSERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } void free_platform_lists(struct platform_class *list) { struct platform_class *tmp; while (list != NULL){ if (list->classURISize > 0) free(list->classURI); tmp = list->next; free(list); list = tmp; } } void conf_file_final(struct tcsd_config *conf) { free(conf->system_ps_file); free(conf->system_ps_dir); free(conf->kernel_log_file); free(conf->firmware_log_file); free(conf->platform_cred); free(conf->conformance_cred); free(conf->endorsement_cred); free_platform_lists(conf->host_platform_class); free_platform_lists(conf->all_platform_classes); } #ifdef SOLARIS static int get_smf_prop(const char *var, boolean_t def_val) { scf_simple_prop_t *prop; uint8_t *val; boolean_t res = def_val; prop = scf_simple_prop_get(NULL, "svc:/application/security/tcsd:default", "config", var); if (prop) { if ((val = scf_simple_prop_next_boolean(prop)) != NULL) res = (*val == 0) ? B_FALSE : B_TRUE; scf_simple_prop_free(prop); } if (prop == NULL || val == NULL) { syslog(LOG_ALERT, "no value for config/%s (%s). " "Using default \"%s\"", var, scf_strerror(scf_error()), def_val ? "true" : "false"); } return (res); } #endif TSS_RESULT conf_file_init(struct tcsd_config *conf) { FILE *f = NULL; struct stat stat_buf; #ifndef SOLARIS struct group *grp; struct passwd *pw; mode_t mode = (S_IRUSR|S_IWUSR|S_IRGRP); #endif /* SOLARIS */ TSS_RESULT result; init_tcsd_config(conf); #ifdef SOLARIS /* * Solaris runs as Rajiv Andrade gr_gid != stat_buf.st_gid) { LogError("TCSD config file (%s) must be user/group %s/%s", tcsd_config_file, "root", TSS_GROUP_NAME); return TCSERR(TSS_E_INTERNAL_ERROR); } /* make sure only the tss user can read (but not manipulate) the config file */ if (((stat_buf.st_mode & 0777) ^ mode) != 0) { LogError("TCSD config file (%s) must be mode 0640", tcsd_config_file); return TCSERR(TSS_E_INTERNAL_ERROR); } #endif /* SOLARIS */ #endif /* NOUSERCHECK */ if ((f = fopen(tcsd_config_file, "r")) == NULL) { LogError("fopen(%s): %s", tcsd_config_file, strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } result = read_conf_file(f, conf); fclose(f); /* fill out any uninitialized options */ config_set_defaults(conf); #ifdef SOLARIS /* * The SMF value for "local_only" overrides the config file and * disables all remote operations. */ if (get_smf_prop("local_only", B_TRUE)) { (void) memset(conf->remote_ops, 0, sizeof(conf->remote_ops)); conf->unset |= TCSD_OPTION_REMOTE_OPS; } #endif return result; } TSS_RESULT ps_dirs_init() { struct stat stat_buf; mode_t mode = S_IRWXU; /* 0700 */ /* query the key storage directory to make sure it exists and is of the right mode */ if (stat(tcsd_options.system_ps_dir, &stat_buf) == -1) { if (errno == ENOENT) { /* The dir DNE, create it with mode drwxrwxrwt */ if (mkdir(tcsd_options.system_ps_dir, mode) == -1) { LogError("mkdir(%s) failed: %s. If you'd like to use %s to " "store your system persistent data, please" " create it. Otherwise, change the location" " in your tcsd config file.", tcsd_options.system_ps_dir, strerror(errno), tcsd_options.system_ps_dir); return TCSERR(TSS_E_INTERNAL_ERROR); } } else { LogError("stat failed: %s", strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } } /* stat should not fail now */ if (stat(tcsd_options.system_ps_dir, &stat_buf) == -1) { LogError("stat %s failed: %s", tcsd_options.system_ps_dir, strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } /* tcsd_options.system_ps_dir should be a directory with mode equal to mode */ if (!S_ISDIR(stat_buf.st_mode)) { LogError("PS dir %s is not a directory! Exiting.", tcsd_options.system_ps_dir); return TCSERR(TSS_E_INTERNAL_ERROR); } else if (((stat_buf.st_mode & 0777) ^ mode) != 0) { /* This path is likely to be hit since open &'s mode with ~umask */ LogInfo("resetting mode of %s from %o to: %o", tcsd_options.system_ps_dir, (unsigned int) stat_buf.st_mode, (unsigned int) mode); if (chmod(tcsd_options.system_ps_dir, mode) == -1) { LogError("chmod(%s) failed: %s", tcsd_options.system_ps_dir, strerror(errno)); return TCSERR(TSS_E_INTERNAL_ERROR); } } return TSS_SUCCESS; } trousers-0.3.15/src/tddl/0000775000175000017510000000000013663651711014472 5ustar deboradeboratrousers-0.3.15/src/tddl/Makefile.am0000664000175000017510000000020213663651711016520 0ustar deboradeboralib_LIBRARIES=libtddl.a libtddl_a_SOURCES=tddl.c libtddl_a_CFLAGS=-DAPPID=\"TCSD\ TDDL\" -I${top_srcdir}/src/include -fPIE -DPIE trousers-0.3.15/src/tddl/tddl.c0000664000175000017510000001432513663651711015572 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "linux/tpm.h" #include "tcslog.h" #include "tddl.h" struct tpm_device_node tpm_device_nodes[] = { {"/dev/tpm0", TDDL_UNDEF, TDDL_UNDEF}, {"/udev/tpm0", TDDL_UNDEF, TDDL_UNDEF}, {"/dev/tpm", TDDL_UNDEF, TDDL_UNDEF}, {NULL, 0, 0} }; struct tpm_device_node *opened_device = NULL; BYTE txBuffer[TDDL_TXBUF_SIZE]; TSS_BOOL use_in_socket = FALSE; struct tcsd_config *_tcsd_options = NULL; #include #include #include #include #include #include int open_device() { int i = 0, fd = -1, tcp_device_port; char *tcp_device_hostname = NULL; char *un_socket_device_path = NULL; char *tcp_device_port_string = NULL; if (getenv("TCSD_USE_TCP_DEVICE")) { if ((tcp_device_hostname = getenv("TCSD_TCP_DEVICE_HOSTNAME")) == NULL) tcp_device_hostname = "localhost"; if ((un_socket_device_path = getenv("TCSD_UN_SOCKET_DEVICE_PATH")) == NULL) un_socket_device_path = "/var/run/tpm/tpmd_socket:0"; if ((tcp_device_port_string = getenv("TCSD_TCP_DEVICE_PORT")) != NULL) tcp_device_port = atoi(tcp_device_port_string); else tcp_device_port = 6545; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd > 0) { struct hostent *host = gethostbyname(tcp_device_hostname); if (host != NULL) { struct sockaddr_in addr; memset(&addr, 0x0, sizeof(addr)); addr.sin_family = host->h_addrtype; addr.sin_port = htons(tcp_device_port); memcpy(&addr.sin_addr, host->h_addr, host->h_length); if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { close(fd); fd = -1; } else use_in_socket = TRUE; } else { close (fd); fd = -1; } } if (fd < 0) { struct sockaddr_un addr; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd >= 0) { addr.sun_family = AF_UNIX; strncpy(addr.sun_path, un_socket_device_path, sizeof(addr.sun_path)); if (connect(fd, (void *)&addr, sizeof(addr)) < 0) { close(fd); fd = -1; } } } } if (fd < 0) { /* tpm_device_paths is filled out in tddl.h */ for (i = 0; tpm_device_nodes[i].path != NULL; i++) { errno = 0; if ((fd = open(tpm_device_nodes[i].path, O_RDWR)) >= 0) break; } } if (fd > 0) { opened_device = &(tpm_device_nodes[i]); tpm_device_nodes[i].fd = fd; } return fd; } TSS_RESULT Tddli_Open() { int rc; if (opened_device != NULL) { LogDebug("attempted to re-open the TPM driver!"); return TDDLERR(TDDL_E_ALREADY_OPENED); } rc = open_device(); if (rc < 0) { LogError("Could not find a device to open!"); if (errno == ENOENT) { /* File DNE */ return TDDLERR(TDDL_E_COMPONENT_NOT_FOUND); } return TDDLERR(TDDL_E_FAIL); } return TSS_SUCCESS; } TSS_RESULT Tddli_Close() { if (opened_device == NULL) { LogDebug("attempted to re-close the TPM driver!"); return TDDLERR(TDDL_E_ALREADY_CLOSED); } close(opened_device->fd); opened_device->fd = TDDL_UNDEF; opened_device = NULL; return TSS_SUCCESS; } TSS_RESULT Tddli_TransmitData(BYTE * pTransmitBuf, UINT32 TransmitBufLen, BYTE * pReceiveBuf, UINT32 * pReceiveBufLen) { int sizeResult; if (TransmitBufLen > TDDL_TXBUF_SIZE) { LogError("buffer size handed to TDDL is too large! (%u bytes)", TransmitBufLen); return TDDLERR(TDDL_E_FAIL); } memcpy(txBuffer, pTransmitBuf, TransmitBufLen); LogDebug("Calling write to driver"); if (use_in_socket) { Tddli_Close(); if (Tddli_Open()) return TDDLERR(TDDL_E_IOERROR); } switch (opened_device->transmit) { case TDDL_UNDEF: /* fall through */ case TDDL_TRANSMIT_IOCTL: errno = 0; if ((sizeResult = ioctl(opened_device->fd, TPMIOC_TRANSMIT, txBuffer)) != -1) { opened_device->transmit = TDDL_TRANSMIT_IOCTL; break; } LogWarn("ioctl: (%d) %s", errno, strerror(errno)); LogInfo("Falling back to Read/Write device support."); /* fall through */ case TDDL_TRANSMIT_RW: if ((sizeResult = write(opened_device->fd, txBuffer, TransmitBufLen)) == (int)TransmitBufLen) { opened_device->transmit = TDDL_TRANSMIT_RW; sizeResult = read(opened_device->fd, txBuffer, TDDL_TXBUF_SIZE); break; } else { if (sizeResult == -1) { LogError("write to device %s failed: %s", opened_device->path, strerror(errno)); } else { LogError("wrote %d bytes to %s (tried " "to write %d)", sizeResult, opened_device->path, TransmitBufLen); } } /* fall through */ default: return TDDLERR(TDDL_E_IOERROR); } if (sizeResult < 0) { LogError("read from device %s failed: %s", opened_device->path, strerror(errno)); return TDDLERR(TDDL_E_IOERROR); } else if (sizeResult == 0) { LogError("Zero bytes read from device %s", opened_device->path); return TDDLERR(TDDL_E_IOERROR); } if ((unsigned)sizeResult > *pReceiveBufLen) { LogError("read %d bytes from device %s, (only room for %d)", sizeResult, opened_device->path, *pReceiveBufLen); return TDDLERR(TDDL_E_INSUFFICIENT_BUFFER); } *pReceiveBufLen = sizeResult; memcpy(pReceiveBuf, txBuffer, *pReceiveBufLen); return TSS_SUCCESS; } TSS_RESULT Tddli_GetStatus(UINT32 ReqStatusType, UINT32 *pStatus) { return TDDLERR(TSS_E_NOTIMPL); } TSS_RESULT Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap, BYTE *pSetCapBuf, UINT32 SetCapBufLen) { return TDDLERR(TSS_E_NOTIMPL); } TSS_RESULT Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap, BYTE *pCapBuf, UINT32 *pCapBufLen) { return TDDLERR(TSS_E_NOTIMPL); } TSS_RESULT Tddli_Cancel(void) { int rc; if (opened_device->transmit == TDDL_TRANSMIT_IOCTL) { if ((rc = ioctl(opened_device->fd, TPMIOC_CANCEL, NULL)) == -1) { LogError("ioctl: (%d) %s", errno, strerror(errno)); return TDDLERR(TDDL_E_FAIL); } else if (rc == -EIO) { /* The driver timed out while trying to tell the chip to cancel */ return TDDLERR(TDDL_E_COMMAND_COMPLETED); } return TSS_SUCCESS; } else { return TDDLERR(TSS_E_NOTIMPL); } } trousers-0.3.15/src/trspi/0000775000175000017510000000000013663651711014704 5ustar deboradeboratrousers-0.3.15/src/trspi/Makefile.am0000664000175000017510000000052713663651711016744 0ustar deboradeboranoinst_LTLIBRARIES=libtrousers.la libtrousers_la_SOURCES=trousers.c crypto/@CRYPTO_PACKAGE@/hash.c libtrousers_la_CFLAGS=-DAPPID=\"TSPI\" -I${top_srcdir}/src/include if TSS_BUILD_ASYM_CRYPTO libtrousers_la_SOURCES+=crypto/@CRYPTO_PACKAGE@/rsa.c endif if TSS_BUILD_SYM_CRYPTO libtrousers_la_SOURCES+=crypto/@CRYPTO_PACKAGE@/symmetric.c endif trousers-0.3.15/src/trspi/crypto/0000775000175000017510000000000013663651711016224 5ustar deboradeboratrousers-0.3.15/src/trspi/crypto/Makefile.am0000664000175000017510000000002213663651711020252 0ustar deboradeboraSUBDIRS = openssl trousers-0.3.15/src/trspi/crypto/openssl/0000775000175000017510000000000013663651711017707 5ustar deboradeboratrousers-0.3.15/src/trspi/crypto/openssl/symmetric.c0000664000175000017510000002133213663651711022070 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ /* * symmetric.c - openssl TSS crypto routines * * Kent Yoder * */ #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #ifdef TSS_DEBUG #define DEBUG_print_openssl_errors() \ do { \ ERR_load_crypto_strings(); \ ERR_print_errors_fp(stderr); \ } while (0) #else #define DEBUG_print_openssl_errors() #endif /* * Hopefully this will make the code clearer since * OpenSSL returns 1 on success */ #define EVP_SUCCESS 1 TSS_RESULT Trspi_Encrypt_ECB(UINT16 alg, BYTE *key, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len) { TSS_RESULT result = TSS_SUCCESS; EVP_CIPHER_CTX *ctx = NULL; UINT32 tmp; switch (alg) { case TSS_ALG_AES: break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; break; } ctx = EVP_CIPHER_CTX_new(); if (!EVP_EncryptInit(ctx, EVP_aes_256_ecb(), key, NULL)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if (*out_len < in_len + EVP_CIPHER_CTX_block_size(ctx) - 1) { result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (!EVP_EncryptUpdate(ctx, out, (int *)out_len, in, in_len)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if (!EVP_EncryptFinal(ctx, out + *out_len, (int *)&tmp)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } *out_len += tmp; done: EVP_CIPHER_CTX_free(ctx); return result; } TSS_RESULT Trspi_Decrypt_ECB(UINT16 alg, BYTE *key, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len) { TSS_RESULT result = TSS_SUCCESS; EVP_CIPHER_CTX *ctx = NULL; UINT32 tmp; switch (alg) { case TSS_ALG_AES: break; default: result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; break; } ctx = EVP_CIPHER_CTX_new(); if (!EVP_DecryptInit(ctx, EVP_aes_256_ecb(), key, NULL)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if (!EVP_DecryptUpdate(ctx, out, (int *)out_len, in, in_len)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if (!EVP_DecryptFinal(ctx, out + *out_len, (int *)&tmp)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } *out_len += tmp; done: EVP_CIPHER_CTX_free(ctx); return result; } EVP_CIPHER * get_openssl_cipher(UINT16 alg, UINT16 mode) { EVP_CIPHER *cipher = NULL; switch (alg) { case TSS_ALG_AES: case TCPA_ALG_AES: switch (mode) { case TPM_ES_NONE: case TSS_ES_NONE: case TPM_ES_SYM_CBC_PKCS5PAD: LogDebug("XXX Make sure this is really PKCS5 padded"); case TR_SYM_MODE_CBC: cipher = (EVP_CIPHER *)EVP_aes_128_cbc(); break; case TPM_ES_SYM_OFB: cipher = (EVP_CIPHER *)EVP_aes_128_ofb(); break; case TPM_ES_SYM_CNT: LogDebug("XXX AES128 in CTR mode unsupp by openssl EVP"); default: LogDebug("Invalid mode in doing symmetric encryption"); break; } break; case TSS_ALG_DES: case TCPA_ALG_DES: switch (mode) { case TPM_ES_NONE: case TSS_ES_NONE: case TPM_ES_SYM_CBC_PKCS5PAD: LogDebug("XXX Make sure this is really PKCS5 padded"); case TR_SYM_MODE_CBC: cipher = (EVP_CIPHER *)EVP_des_cbc(); break; case TPM_ES_SYM_OFB: cipher = (EVP_CIPHER *)EVP_des_ofb(); break; case TPM_ES_SYM_CNT: LogDebug("XXX DES in CTR mode unsupp by openssl EVP"); default: LogDebug("Invalid mode in doing symmetric encryption"); break; } break; case TSS_ALG_3DES: case TCPA_ALG_3DES: switch (mode) { case TPM_ES_NONE: case TSS_ES_NONE: case TPM_ES_SYM_CBC_PKCS5PAD: LogDebug("XXX Make sure this is really PKCS5 padded"); case TR_SYM_MODE_CBC: cipher = (EVP_CIPHER *)EVP_des_ede3_cbc(); break; case TPM_ES_SYM_OFB: cipher = (EVP_CIPHER *)EVP_des_ede3_ofb(); break; case TPM_ES_SYM_CNT: LogDebug("XXX 3DES in CTR mode unsupp by openssl EVP"); default: LogDebug("Invalid mode in doing symmetric encryption"); break; } break; case TPM_ALG_AES192: case TSS_ALG_AES192: switch (mode) { case TPM_ES_NONE: case TSS_ES_NONE: case TPM_ES_SYM_CBC_PKCS5PAD: LogDebug("XXX Make sure this is really PKCS5 padded"); case TR_SYM_MODE_CBC: cipher = (EVP_CIPHER *)EVP_aes_192_cbc(); break; case TPM_ES_SYM_OFB: cipher = (EVP_CIPHER *)EVP_aes_192_ofb(); break; case TPM_ES_SYM_CNT: LogDebug("XXX AES192 in CTR mode unsupp by openssl EVP"); default: LogDebug("Invalid mode in doing symmetric encryption"); break; } break; case TPM_ALG_AES256: case TSS_ALG_AES256: switch (mode) { case TPM_ES_NONE: case TSS_ES_NONE: case TPM_ES_SYM_CBC_PKCS5PAD: LogDebug("XXX Make sure this is really PKCS5 padded"); case TR_SYM_MODE_CBC: cipher = (EVP_CIPHER *)EVP_aes_256_cbc(); break; case TPM_ES_SYM_OFB: cipher = (EVP_CIPHER *)EVP_aes_256_ofb(); break; case TPM_ES_SYM_CNT: LogDebug("XXX AES256 in CTR mode unsupp by openssl EVP"); default: LogDebug("Invalid mode in doing symmetric encryption"); break; } break; default: LogDebug("Invalid algorithm in doing symmetric encryption"); break; } return cipher; } TSS_RESULT Trspi_SymEncrypt(UINT16 alg, UINT16 mode, BYTE *key, BYTE *iv, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len) { TSS_RESULT result = TSS_SUCCESS; EVP_CIPHER_CTX *ctx = NULL; EVP_CIPHER *cipher; BYTE *def_iv = NULL, *outiv_ptr; UINT32 tmp; int iv_len, outiv_len; if (*out_len > INT_MAX) outiv_len = INT_MAX; else outiv_len = *(int *)out_len; if ((cipher = get_openssl_cipher(alg, mode)) == NULL) return TSPERR(TSS_E_INTERNAL_ERROR); ctx = EVP_CIPHER_CTX_new(); /* If the iv passed in is NULL, create a new random iv and prepend it to the ciphertext */ iv_len = EVP_CIPHER_iv_length(cipher); if (iv == NULL) { def_iv = malloc(iv_len); if (def_iv == NULL) { LogError("malloc of %d bytes failed.", iv_len); return TSPERR(TSS_E_OUTOFMEMORY); } RAND_bytes(def_iv, iv_len); memcpy(out, def_iv, iv_len); outiv_ptr = &out[iv_len]; outiv_len -= iv_len; } else { def_iv = iv; outiv_ptr = out; } if (!EVP_EncryptInit(ctx, (const EVP_CIPHER *)cipher, key, def_iv)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if ((UINT32)outiv_len < in_len + (EVP_CIPHER_CTX_block_size(ctx) * 2) - 1) { LogDebug("Not enough space to do symmetric encryption"); result = TSPERR(TSS_E_INTERNAL_ERROR); goto done; } if (!EVP_EncryptUpdate(ctx, outiv_ptr, &outiv_len, in, in_len)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if (!EVP_EncryptFinal(ctx, outiv_ptr + outiv_len, (int *)&tmp)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } outiv_len += tmp; *out_len = outiv_len; done: if (def_iv != iv) { *out_len += iv_len; free(def_iv); } EVP_CIPHER_CTX_free(ctx); return result; } TSS_RESULT Trspi_SymDecrypt(UINT16 alg, UINT16 mode, BYTE *key, BYTE *iv, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len) { TSS_RESULT result = TSS_SUCCESS; EVP_CIPHER_CTX *ctx = NULL; EVP_CIPHER *cipher; BYTE *def_iv = NULL, *iniv_ptr; UINT32 tmp; int iv_len, iniv_len; if (in_len > INT_MAX) return TSS_E_BAD_PARAMETER; if ((cipher = get_openssl_cipher(alg, mode)) == NULL) return TSPERR(TSS_E_INTERNAL_ERROR); ctx = EVP_CIPHER_CTX_new(); /* If the iv is NULL, assume that its prepended to the ciphertext */ if (iv == NULL) { iv_len = EVP_CIPHER_iv_length(cipher); def_iv = malloc(iv_len); if (def_iv == NULL) { LogError("malloc of %d bytes failed.", iv_len); return TSPERR(TSS_E_OUTOFMEMORY); } memcpy(def_iv, in, iv_len); iniv_ptr = &in[iv_len]; iniv_len = in_len - iv_len; } else { def_iv = iv; iniv_ptr = in; iniv_len = in_len; } if (!EVP_DecryptInit(ctx, cipher, key, def_iv)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if (!EVP_DecryptUpdate(ctx, out, (int *)out_len, iniv_ptr, iniv_len)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } if (!EVP_DecryptFinal(ctx, out + *out_len, (int *)&tmp)) { result = TSPERR(TSS_E_INTERNAL_ERROR); DEBUG_print_openssl_errors(); goto done; } *out_len += tmp; done: if (def_iv != iv) free(def_iv); EVP_CIPHER_CTX_free(ctx); return result; } trousers-0.3.15/src/trspi/crypto/openssl/rsa.c0000664000175000017510000001520113663651711020637 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ /* * rsa.c - openssl TSS crypto routines * * Kent Yoder * */ #include #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #ifdef TSS_DEBUG #define DEBUG_print_openssl_errors() \ do { \ ERR_load_crypto_strings(); \ ERR_print_errors_fp(stderr); \ } while (0) #else #define DEBUG_print_openssl_errors() #endif #if (OPENSSL_VERSION_NUMBER < 0x10100001L) || defined(LIBRESSL_VERSION_NUMBER) static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { if (n != NULL) { BN_free(r->n); r->n = n; } if (e != NULL) { BN_free(r->e); r->e = e; } if (d != NULL) { BN_free(r->d); r->d = d; } return 1; } #endif /* * Hopefully this will make the code clearer since * OpenSSL returns 1 on success */ #define EVP_SUCCESS 1 /* XXX int set to unsigned int values */ int Trspi_RSA_Encrypt(unsigned char *dataToEncrypt, /* in */ unsigned int dataToEncryptLen, /* in */ unsigned char *encryptedData, /* out */ unsigned int *encryptedDataLen, /* out */ unsigned char *publicKey, unsigned int keysize) { int rv; unsigned char exp[] = { 0x01, 0x00, 0x01 }; /* 65537 hex */ unsigned char oaepPad[] = "TCPA"; int oaepPadLen = 4; RSA *rsa = RSA_new(); BYTE encodedData[256]; int encodedDataLen; BIGNUM *rsa_n = NULL, *rsa_e = NULL; if (rsa == NULL) { rv = TSPERR(TSS_E_OUTOFMEMORY); goto err; } /* set the public key value in the OpenSSL object */ rsa_n = BN_bin2bn(publicKey, keysize, NULL); /* set the public exponent */ rsa_e = BN_bin2bn(exp, sizeof(exp), NULL); if (rsa_n == NULL || rsa_e == NULL) { rv = TSPERR(TSS_E_OUTOFMEMORY); BN_free(rsa_n); BN_free(rsa_e); goto err; } if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) { rv = TSPERR(TSS_E_FAIL); BN_free(rsa_n); BN_free(rsa_e); goto err; } /* padding constraint for PKCS#1 OAEP padding */ if ((int)dataToEncryptLen >= (RSA_size(rsa) - ((2 * SHA_DIGEST_LENGTH) + 1))) { rv = TSPERR(TSS_E_INTERNAL_ERROR); goto err; } encodedDataLen = MIN(RSA_size(rsa), 256); /* perform our OAEP padding here with custom padding parameter */ rv = RSA_padding_add_PKCS1_OAEP(encodedData, encodedDataLen, dataToEncrypt, dataToEncryptLen, oaepPad, oaepPadLen); if (rv != EVP_SUCCESS) { rv = TSPERR(TSS_E_INTERNAL_ERROR); goto err; } /* call OpenSSL with no additional padding */ rv = RSA_public_encrypt(encodedDataLen, encodedData, encryptedData, rsa, RSA_NO_PADDING); if (rv == -1) { rv = TSPERR(TSS_E_INTERNAL_ERROR); goto err; } /* RSA_public_encrypt returns the size of the encrypted data */ *encryptedDataLen = rv; rv = TSS_SUCCESS; goto out; err: DEBUG_print_openssl_errors(); out: if (rsa) RSA_free(rsa); return rv; } TSS_RESULT Trspi_Verify(UINT32 HashType, BYTE *pHash, UINT32 iHashLength, unsigned char *pModulus, int iKeyLength, BYTE *pSignature, UINT32 sig_len) { int rv, nid; unsigned char exp[] = { 0x01, 0x00, 0x01 }; /* The default public exponent for the TPM */ unsigned char buf[256]; RSA *rsa = RSA_new(); BIGNUM *rsa_n = NULL, *rsa_e = NULL; if (rsa == NULL) { rv = TSPERR(TSS_E_OUTOFMEMORY); goto err; } /* We assume we're verifying data from a TPM, so there are only * two options, SHA1 data and PKCSv1.5 encoded signature data. */ switch (HashType) { case TSS_HASH_SHA1: nid = NID_sha1; break; case TSS_HASH_OTHER: nid = NID_undef; break; default: rv = TSPERR(TSS_E_BAD_PARAMETER); goto out; break; } /* set the public key value in the OpenSSL object */ rsa_n = BN_bin2bn(pModulus, iKeyLength, NULL); /* set the public exponent */ rsa_e = BN_bin2bn(exp, sizeof(exp), NULL); if (rsa_n == NULL || rsa_e == NULL) { rv = TSPERR(TSS_E_OUTOFMEMORY); BN_free(rsa_n); BN_free(rsa_e); goto err; } if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) { rv = TSPERR(TSS_E_FAIL); BN_free(rsa_n); BN_free(rsa_e); goto err; } /* if we don't know the structure of the data we're verifying, do a public decrypt * and compare manually. If we know we're looking for a SHA1 hash, allow OpenSSL * to do the work for us. */ if (nid == NID_undef) { rv = RSA_public_decrypt(sig_len, pSignature, buf, rsa, RSA_PKCS1_PADDING); if ((UINT32)rv != iHashLength) { rv = TSPERR(TSS_E_FAIL); goto out; } else if (memcmp(pHash, buf, iHashLength)) { rv = TSPERR(TSS_E_FAIL); goto out; } } else { if ((rv = RSA_verify(nid, pHash, iHashLength, pSignature, sig_len, rsa)) == 0) { rv = TSPERR(TSS_E_FAIL); goto out; } } rv = TSS_SUCCESS; goto out; err: DEBUG_print_openssl_errors(); out: if (rsa) RSA_free(rsa); return rv; } int Trspi_RSA_Public_Encrypt(unsigned char *in, unsigned int inlen, unsigned char *out, unsigned int *outlen, unsigned char *pubkey, unsigned int pubsize, unsigned int e, int padding) { int rv, e_size = 3; unsigned char exp[] = { 0x01, 0x00, 0x01 }; RSA *rsa = RSA_new(); BIGNUM *rsa_n = NULL, *rsa_e = NULL; if (rsa == NULL) { rv = TSPERR(TSS_E_OUTOFMEMORY); goto err; } switch (e) { case 0: /* fall through */ case 65537: break; case 17: exp[0] = 17; e_size = 1; break; case 3: exp[0] = 3; e_size = 1; break; default: rv = TSPERR(TSS_E_INTERNAL_ERROR); goto out; break; } switch (padding) { case TR_RSA_PKCS1_OAEP_PADDING: padding = RSA_PKCS1_OAEP_PADDING; break; case TR_RSA_PKCS1_PADDING: padding = RSA_PKCS1_PADDING; break; case TR_RSA_NO_PADDING: padding = RSA_NO_PADDING; break; default: rv = TSPERR(TSS_E_INTERNAL_ERROR); goto out; break; } /* set the public key value in the OpenSSL object */ rsa_n = BN_bin2bn(pubkey, pubsize, NULL); /* set the public exponent */ rsa_e = BN_bin2bn(exp, e_size, NULL); if (rsa_n == NULL || rsa_e == NULL) { rv = TSPERR(TSS_E_OUTOFMEMORY); BN_free(rsa_n); BN_free(rsa_e); goto err; } if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) { rv = TSPERR(TSS_E_FAIL); BN_free(rsa_n); BN_free(rsa_e); goto err; } rv = RSA_public_encrypt(inlen, in, out, rsa, padding); if (rv == -1) { rv = TSPERR(TSS_E_INTERNAL_ERROR); goto err; } /* RSA_public_encrypt returns the size of the encrypted data */ *outlen = rv; rv = TSS_SUCCESS; goto out; err: DEBUG_print_openssl_errors(); out: if (rsa) RSA_free(rsa); return rv; } trousers-0.3.15/src/trspi/crypto/openssl/hash.c0000664000175000017510000001022013663651711020771 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ /* * hash.c - openssl TSS crypto routines * * Kent Yoder * */ #include #include #include // for some reason the MGF1 prototype is in here #include #include #include #include #include "trousers/tss.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "tsplog.h" #ifdef TSS_DEBUG #define DEBUG_print_openssl_errors() \ do { \ ERR_load_crypto_strings(); \ ERR_print_errors_fp(stderr); \ } while (0) #else #define DEBUG_print_openssl_errors() #endif #if (OPENSSL_VERSION_NUMBER >= 0x0090800FL) #define OpenSSL_MGF1(m,mlen,s,slen,md) PKCS1_MGF1(m,mlen,s,slen,md) #else int MGF1(unsigned char *, long, const unsigned char *, long); #define OpenSSL_MGF1(m,mlen,s,slen,md) MGF1(m,mlen,s,slen) #endif /* * Hopefully this will make the code clearer since * OpenSSL returns 1 on success */ #define EVP_SUCCESS 1 TSS_RESULT Trspi_Hash(UINT32 HashType, UINT32 BufSize, BYTE* Buf, BYTE* Digest) { EVP_MD_CTX *md_ctx; unsigned int result_size; int rv; md_ctx = EVP_MD_CTX_create(); switch (HashType) { case TSS_HASH_SHA1: rv = EVP_DigestInit(md_ctx, EVP_sha1()); break; default: rv = TSPERR(TSS_E_BAD_PARAMETER); goto out; break; } if (rv != EVP_SUCCESS) { rv = TSPERR(TSS_E_INTERNAL_ERROR); goto err; } rv = EVP_DigestUpdate(md_ctx, Buf, BufSize); if (rv != EVP_SUCCESS) { rv = TSPERR(TSS_E_INTERNAL_ERROR); goto err; } result_size = EVP_MD_CTX_size(md_ctx); rv = EVP_DigestFinal(md_ctx, Digest, &result_size); if (rv != EVP_SUCCESS) { rv = TSPERR(TSS_E_INTERNAL_ERROR); goto err; } else rv = TSS_SUCCESS; goto out; err: DEBUG_print_openssl_errors(); out: EVP_MD_CTX_destroy(md_ctx); return rv; } TSS_RESULT Trspi_HashInit(Trspi_HashCtx *ctx, UINT32 HashType) { int rv; EVP_MD *md; switch (HashType) { case TSS_HASH_SHA1: md = (EVP_MD *)EVP_sha1(); break; default: return TSPERR(TSS_E_BAD_PARAMETER); break; } if ((ctx->ctx = EVP_MD_CTX_create()) == NULL) return TSPERR(TSS_E_OUTOFMEMORY); rv = EVP_DigestInit((EVP_MD_CTX *)ctx->ctx, (const EVP_MD *)md); if (rv != EVP_SUCCESS) { DEBUG_print_openssl_errors(); return TSPERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT Trspi_HashUpdate(Trspi_HashCtx *ctx, UINT32 size, BYTE *data) { int rv; if (ctx == NULL || ctx->ctx == NULL) return TSPERR(TSS_E_INTERNAL_ERROR); if (data == NULL && size) return TSPERR(TSS_E_BAD_PARAMETER); if (!size) return TSS_SUCCESS; rv = EVP_DigestUpdate(ctx->ctx, data, size); if (rv != EVP_SUCCESS) { DEBUG_print_openssl_errors(); free(ctx->ctx); ctx->ctx = NULL; return TSPERR(TSS_E_INTERNAL_ERROR); } return TSS_SUCCESS; } TSS_RESULT Trspi_HashFinal(Trspi_HashCtx *ctx, BYTE *digest) { int rv; UINT32 result_size; if (ctx == NULL || ctx->ctx == NULL) return TSPERR(TSS_E_INTERNAL_ERROR); result_size = EVP_MD_CTX_size((EVP_MD_CTX *)ctx->ctx); rv = EVP_DigestFinal(ctx->ctx, digest, &result_size); if (rv != EVP_SUCCESS) return TSPERR(TSS_E_INTERNAL_ERROR); free(ctx->ctx); ctx->ctx = NULL; return TSS_SUCCESS; } UINT32 Trspi_HMAC(UINT32 HashType, UINT32 SecretSize, BYTE* Secret, UINT32 BufSize, BYTE* Buf, BYTE* hmacOut) { /*HMAC_CTX hmac_ctx;*/ const EVP_MD *md; unsigned int len; int rv = TSS_SUCCESS; switch (HashType) { case TSS_HASH_SHA1: md = EVP_sha1(); break; default: rv = TSPERR(TSS_E_BAD_PARAMETER); goto out; break; } len = EVP_MD_size(md); HMAC(md, Secret, SecretSize, Buf, BufSize, hmacOut, &len); out: return rv; } TSS_RESULT Trspi_MGF1(UINT32 alg, UINT32 seedLen, BYTE *seed, UINT32 outLen, BYTE *out) { const EVP_MD *md; long olen = outLen, slen = seedLen; int rv = TSS_SUCCESS; switch (alg) { case TSS_HASH_SHA1: md = EVP_sha1(); break; default: rv = TSPERR(TSS_E_BAD_PARAMETER); goto out; break; } rv = OpenSSL_MGF1(out, olen, seed, slen, md); out: return rv; } trousers-0.3.15/src/trspi/trousers.c0000664000175000017510000025706613663651711016756 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #include #include #include #include #include #include #include "trousers/tss.h" #include "trousers_types.h" #include "trousers/trousers.h" #include "trousers_types.h" #include "spi_utils.h" #include "capabilities.h" #include "tsplog.h" #include "obj.h" #include "tcs_tsp.h" void Trspi_UnloadBlob_NONCE(UINT64 *offset, BYTE *blob, TPM_NONCE *n) { if (!n) { (*offset) += TPM_SHA1_160_HASH_LEN; return; } Trspi_UnloadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, n->nonce); } void Trspi_LoadBlob_NONCE(UINT64 *offset, BYTE *blob, TPM_NONCE *n) { Trspi_LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, n->nonce); } void Trspi_LoadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest) { Trspi_LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, digest->digest); } void Trspi_UnloadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest) { if (!digest) { (*offset) += TPM_SHA1_160_HASH_LEN; return; } Trspi_UnloadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, digest->digest); } void Trspi_LoadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *pubKey) { Trspi_LoadBlob_KEY_PARMS(offset, blob, &pubKey->algorithmParms); Trspi_LoadBlob_STORE_PUBKEY(offset, blob, &pubKey->pubKey); } TSS_RESULT Trspi_UnloadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *pubKey) { TSS_RESULT result; if (!pubKey) { (void)Trspi_UnloadBlob_KEY_PARMS(offset, blob, NULL); (void)Trspi_UnloadBlob_STORE_PUBKEY(offset, blob, NULL); return TSS_SUCCESS; } if ((result = Trspi_UnloadBlob_KEY_PARMS(offset, blob, &pubKey->algorithmParms))) return result; if ((result = Trspi_UnloadBlob_STORE_PUBKEY(offset, blob, &pubKey->pubKey))) { free(pubKey->pubKey.key); free(pubKey->algorithmParms.parms); pubKey->pubKey.key = NULL; pubKey->pubKey.keyLength = 0; pubKey->algorithmParms.parms = NULL; pubKey->algorithmParms.parmSize = 0; return result; } return TSS_SUCCESS; } void Trspi_LoadBlob(UINT64 *offset, size_t size, BYTE *to, BYTE *from) { if (size == 0) return; if (to) memcpy(&to[(*offset)], from, size); (*offset) += size; } void Trspi_UnloadBlob(UINT64 *offset, size_t size, BYTE *from, BYTE *to) { if (size <= 0) return; if (to) memcpy(to, &from[*offset], size); (*offset) += size; } void Trspi_LoadBlob_BYTE(UINT64 *offset, BYTE data, BYTE *blob) { if (blob) blob[*offset] = data; (*offset)++; } void Trspi_UnloadBlob_BYTE(UINT64 *offset, BYTE *dataOut, BYTE *blob) { if (dataOut) *dataOut = blob[*offset]; (*offset)++; } void Trspi_LoadBlob_BOOL(UINT64 *offset, TSS_BOOL data, BYTE *blob) { if (blob) blob[*offset] = (BYTE) data; (*offset)++; } void Trspi_UnloadBlob_BOOL(UINT64 *offset, TSS_BOOL *dataOut, BYTE *blob) { if (dataOut) *dataOut = blob[*offset]; (*offset)++; } void Trspi_LoadBlob_UINT64(UINT64 *offset, UINT64 in, BYTE *blob) { if (blob) UINT64ToArray(in, &blob[*offset]); (*offset) += sizeof(UINT64); } void Trspi_LoadBlob_UINT32(UINT64 *offset, UINT32 in, BYTE *blob) { if (blob) UINT32ToArray(in, &blob[*offset]); (*offset) += sizeof(UINT32); } void Trspi_LoadBlob_UINT16(UINT64 *offset, UINT16 in, BYTE *blob) { if (blob) UINT16ToArray(in, &blob[*offset]); (*offset) += sizeof(UINT16); } void Trspi_UnloadBlob_UINT64(UINT64 *offset, UINT64 *out, BYTE *blob) { if (out) *out = Decode_UINT64(&blob[*offset]); (*offset) += sizeof(UINT64); } void Trspi_UnloadBlob_UINT32(UINT64 *offset, UINT32 *out, BYTE *blob) { if (out) *out = Decode_UINT32(&blob[*offset]); (*offset) += sizeof(UINT32); } void Trspi_UnloadBlob_UINT16(UINT64 *offset, UINT16 *out, BYTE *blob) { if (out) *out = Decode_UINT16(&blob[*offset]); (*offset) += sizeof(UINT16); } void Trspi_LoadBlob_RSA_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_RSA_KEY_PARMS *parms) { Trspi_LoadBlob_UINT32(offset, parms->keyLength, blob); Trspi_LoadBlob_UINT32(offset, parms->numPrimes, blob); Trspi_LoadBlob_UINT32(offset, parms->exponentSize, blob); if (parms->exponentSize > 0) Trspi_LoadBlob(offset, parms->exponentSize, blob, parms->exponent); } void Trspi_UnloadBlob_TSS_VERSION(UINT64 *offset, BYTE *blob, TSS_VERSION *out) { if (!out) { Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); return; } Trspi_UnloadBlob_BYTE(offset, &out->bMajor, blob); Trspi_UnloadBlob_BYTE(offset, &out->bMinor, blob); Trspi_UnloadBlob_BYTE(offset, &out->bRevMajor, blob); Trspi_UnloadBlob_BYTE(offset, &out->bRevMinor, blob); } void Trspi_LoadBlob_TSS_VERSION(UINT64 *offset, BYTE *blob, TSS_VERSION version) { Trspi_LoadBlob_BYTE(offset, version.bMajor, blob); Trspi_LoadBlob_BYTE(offset, version.bMinor, blob); Trspi_LoadBlob_BYTE(offset, version.bRevMajor, blob); Trspi_LoadBlob_BYTE(offset, version.bRevMinor, blob); } void Trspi_UnloadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION *out) { if (!out) { Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); return; } Trspi_UnloadBlob_BYTE(offset, &out->major, blob); Trspi_UnloadBlob_BYTE(offset, &out->minor, blob); Trspi_UnloadBlob_BYTE(offset, &out->revMajor, blob); Trspi_UnloadBlob_BYTE(offset, &out->revMinor, blob); } void Trspi_LoadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION version) { Trspi_LoadBlob_BYTE(offset, version.major, blob); Trspi_LoadBlob_BYTE(offset, version.minor, blob); Trspi_LoadBlob_BYTE(offset, version.revMajor, blob); Trspi_LoadBlob_BYTE(offset, version.revMinor, blob); } TSS_RESULT Trspi_UnloadBlob_PCR_INFO(UINT64 *offset, BYTE *blob, TCPA_PCR_INFO *pcr) { TSS_RESULT result; if (!pcr) { (void)Trspi_UnloadBlob_PCR_SELECTION(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); return TSS_SUCCESS; } if ((result = Trspi_UnloadBlob_PCR_SELECTION(offset, blob, &pcr->pcrSelection))) return result; Trspi_UnloadBlob_DIGEST(offset, blob, &pcr->digestAtRelease); Trspi_UnloadBlob_DIGEST(offset, blob, &pcr->digestAtCreation); return TSS_SUCCESS; } void Trspi_LoadBlob_PCR_INFO(UINT64 *offset, BYTE *blob, TCPA_PCR_INFO *pcr) { Trspi_LoadBlob_PCR_SELECTION(offset, blob, &pcr->pcrSelection); Trspi_LoadBlob_DIGEST(offset, blob, &pcr->digestAtRelease); Trspi_LoadBlob_DIGEST(offset, blob, &pcr->digestAtCreation); } TSS_RESULT Trspi_UnloadBlob_PCR_INFO_LONG(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_LONG *pcr) { TSS_RESULT result; if (!pcr) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_PCR_SELECTION(offset, blob, NULL); Trspi_UnloadBlob_PCR_SELECTION(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &pcr->tag, blob); Trspi_UnloadBlob_BYTE(offset, &pcr->localityAtCreation, blob); Trspi_UnloadBlob_BYTE(offset, &pcr->localityAtRelease, blob); if ((result = Trspi_UnloadBlob_PCR_SELECTION(offset, blob, &pcr->creationPCRSelection))) return result; if ((result = Trspi_UnloadBlob_PCR_SELECTION(offset, blob, &pcr->releasePCRSelection))) return result; Trspi_UnloadBlob_DIGEST(offset, blob, &pcr->digestAtCreation); Trspi_UnloadBlob_DIGEST(offset, blob, &pcr->digestAtRelease); return TSS_SUCCESS; } void Trspi_LoadBlob_PCR_INFO_LONG(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_LONG *pcr) { Trspi_LoadBlob_UINT16(offset, pcr->tag, blob); Trspi_LoadBlob_BYTE(offset, pcr->localityAtCreation, blob); Trspi_LoadBlob_BYTE(offset, pcr->localityAtRelease, blob); Trspi_LoadBlob_PCR_SELECTION(offset, blob, &pcr->creationPCRSelection); Trspi_LoadBlob_PCR_SELECTION(offset, blob, &pcr->releasePCRSelection); Trspi_LoadBlob_DIGEST(offset, blob, &pcr->digestAtCreation); Trspi_LoadBlob_DIGEST(offset, blob, &pcr->digestAtRelease); } TSS_RESULT Trspi_UnloadBlob_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_SHORT *pcr) { TSS_RESULT result; if (!pcr) { Trspi_UnloadBlob_PCR_SELECTION(offset, blob, NULL); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); return TSS_SUCCESS; } if ((result = Trspi_UnloadBlob_PCR_SELECTION(offset, blob, &pcr->pcrSelection))) return result; Trspi_UnloadBlob_BYTE(offset, &pcr->localityAtRelease, blob); Trspi_UnloadBlob_DIGEST(offset, blob, &pcr->digestAtRelease); return TSS_SUCCESS; } void Trspi_LoadBlob_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_SHORT *pcr) { Trspi_LoadBlob_PCR_SELECTION(offset, blob, &pcr->pcrSelection); Trspi_LoadBlob_BYTE(offset, pcr->localityAtRelease, blob); Trspi_LoadBlob_DIGEST(offset, blob, &pcr->digestAtRelease); } TSS_RESULT Trspi_UnloadBlob_PCR_SELECTION(UINT64 *offset, BYTE *blob, TCPA_PCR_SELECTION *pcr) { if (!pcr) { UINT16 sizeOfSelect; Trspi_UnloadBlob_UINT16(offset, &sizeOfSelect, blob); Trspi_UnloadBlob(offset, sizeOfSelect, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &pcr->sizeOfSelect, blob); if (pcr->sizeOfSelect > 0) { pcr->pcrSelect = calloc(1, pcr->sizeOfSelect); if (pcr->pcrSelect == NULL) { LogError("malloc of %u bytes failed.", pcr->sizeOfSelect); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, pcr->sizeOfSelect, blob, pcr->pcrSelect); } else { pcr->pcrSelect = NULL; } return TSS_SUCCESS; } void Trspi_LoadBlob_PCR_SELECTION(UINT64 *offset, BYTE *blob, TCPA_PCR_SELECTION *pcr) { UINT16 i; Trspi_LoadBlob_UINT16(offset, pcr->sizeOfSelect, blob); for (i = 0; i < pcr->sizeOfSelect; i++) Trspi_LoadBlob_BYTE(offset, pcr->pcrSelect[i], blob); } void Trspi_LoadBlob_KEY12(UINT64 *offset, BYTE *blob, TPM_KEY12 *key) { Trspi_LoadBlob_UINT16(offset, key->tag, blob); Trspi_LoadBlob_UINT16(offset, key->fill, blob); Trspi_LoadBlob_UINT16(offset, key->keyUsage, blob); Trspi_LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); Trspi_LoadBlob_BYTE(offset, key->authDataUsage, blob); Trspi_LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms); Trspi_LoadBlob_UINT32(offset, key->PCRInfoSize, blob); Trspi_LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); Trspi_LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey); Trspi_LoadBlob_UINT32(offset, key->encSize, blob); Trspi_LoadBlob(offset, key->encSize, blob, key->encData); } void Trspi_LoadBlob_KEY(UINT64 *offset, BYTE *blob, TCPA_KEY *key) { Trspi_LoadBlob_TCPA_VERSION(offset, blob, key->ver); Trspi_LoadBlob_UINT16(offset, key->keyUsage, blob); Trspi_LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); Trspi_LoadBlob_BYTE(offset, key->authDataUsage, blob); Trspi_LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms); Trspi_LoadBlob_UINT32(offset, key->PCRInfoSize, blob); Trspi_LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); Trspi_LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey); Trspi_LoadBlob_UINT32(offset, key->encSize, blob); Trspi_LoadBlob(offset, key->encSize, blob, key->encData); } void Trspi_LoadBlob_KEY_FLAGS(UINT64 *offset, BYTE *blob, TCPA_KEY_FLAGS *flags) { Trspi_LoadBlob_UINT32(offset, *flags, blob); } void Trspi_UnloadBlob_KEY_FLAGS(UINT64 *offset, BYTE *blob, TCPA_KEY_FLAGS *flags) { Trspi_UnloadBlob_UINT32(offset, flags, blob); } void Trspi_LoadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyInfo) { Trspi_LoadBlob_UINT32(offset, keyInfo->algorithmID, blob); Trspi_LoadBlob_UINT16(offset, keyInfo->encScheme, blob); Trspi_LoadBlob_UINT16(offset, keyInfo->sigScheme, blob); Trspi_LoadBlob_UINT32(offset, keyInfo->parmSize, blob); if (keyInfo->parmSize > 0) Trspi_LoadBlob(offset, keyInfo->parmSize, blob, keyInfo->parms); } void Trspi_LoadBlob_STORE_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_PUBKEY *store) { Trspi_LoadBlob_UINT32(offset, store->keyLength, blob); Trspi_LoadBlob(offset, store->keyLength, blob, store->key); } void Trspi_LoadBlob_UUID(UINT64 *offset, BYTE *blob, TSS_UUID uuid) { Trspi_LoadBlob_UINT32(offset, uuid.ulTimeLow, blob); Trspi_LoadBlob_UINT16(offset, uuid.usTimeMid, blob); Trspi_LoadBlob_UINT16(offset, uuid.usTimeHigh, blob); Trspi_LoadBlob_BYTE(offset, uuid.bClockSeqHigh, blob); Trspi_LoadBlob_BYTE(offset, uuid.bClockSeqLow, blob); Trspi_LoadBlob(offset, 6, blob, uuid.rgbNode); } void Trspi_UnloadBlob_UUID(UINT64 *offset, BYTE *blob, TSS_UUID *uuid) { if (!uuid) { Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob(offset, 6, blob, NULL); return; } memset(uuid, 0, sizeof(TSS_UUID)); Trspi_UnloadBlob_UINT32(offset, &uuid->ulTimeLow, blob); Trspi_UnloadBlob_UINT16(offset, &uuid->usTimeMid, blob); Trspi_UnloadBlob_UINT16(offset, &uuid->usTimeHigh, blob); Trspi_UnloadBlob_BYTE(offset, &uuid->bClockSeqHigh, blob); Trspi_UnloadBlob_BYTE(offset, &uuid->bClockSeqLow, blob); Trspi_UnloadBlob(offset, 6, blob, uuid->rgbNode); } TSS_RESULT Trspi_UnloadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyParms) { if (!keyParms) { UINT32 parmSize; Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, &parmSize, blob); (*offset) += parmSize; return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &keyParms->algorithmID, blob); Trspi_UnloadBlob_UINT16(offset, &keyParms->encScheme, blob); Trspi_UnloadBlob_UINT16(offset, &keyParms->sigScheme, blob); Trspi_UnloadBlob_UINT32(offset, &keyParms->parmSize, blob); if (keyParms->parmSize > 0) { keyParms->parms = malloc(keyParms->parmSize); if (keyParms->parms == NULL) { LogError("malloc of %u bytes failed.", keyParms->parmSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, keyParms->parmSize, blob, keyParms->parms); } else { keyParms->parms = NULL; } return TSS_SUCCESS; } TSS_RESULT Trspi_UnloadBlob_KEY12(UINT64 *offset, BYTE *blob, TPM_KEY12 *key) { TSS_RESULT result; if (!key) { UINT32 PCRInfoSize, encSize; Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_KEY_FLAGS(offset, blob, NULL); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_KEY_PARMS(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &PCRInfoSize, blob); Trspi_UnloadBlob(offset, PCRInfoSize, blob, NULL); Trspi_UnloadBlob_STORE_PUBKEY(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &encSize, blob); Trspi_UnloadBlob(offset, encSize, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &key->tag, blob); Trspi_UnloadBlob_UINT16(offset, &key->fill, blob); Trspi_UnloadBlob_UINT16(offset, &key->keyUsage, blob); Trspi_UnloadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); Trspi_UnloadBlob_BYTE(offset, &key->authDataUsage, blob); if ((result = Trspi_UnloadBlob_KEY_PARMS(offset, (BYTE *) blob, &key->algorithmParms))) return result; Trspi_UnloadBlob_UINT32(offset, &key->PCRInfoSize, blob); if (key->PCRInfoSize > 0) { key->PCRInfo = malloc(key->PCRInfoSize); if (key->PCRInfo == NULL) { LogError("malloc of %d bytes failed.", key->PCRInfoSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); } else { key->PCRInfo = NULL; } if ((result = Trspi_UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) return result; Trspi_UnloadBlob_UINT32(offset, &key->encSize, blob); if (key->encSize > 0) { key->encData = malloc(key->encSize); if (key->encData == NULL) { LogError("malloc of %d bytes failed.", key->encSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, key->encSize, blob, key->encData); } else { key->encData = NULL; } return result; } TSS_RESULT Trspi_UnloadBlob_KEY(UINT64 *offset, BYTE *blob, TCPA_KEY *key) { TSS_RESULT result; if (!key) { UINT32 PCRInfoSize, encSize; Trspi_UnloadBlob_TCPA_VERSION(offset, blob, NULL); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_KEY_FLAGS(offset, blob, NULL); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_KEY_PARMS(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &PCRInfoSize, blob); Trspi_UnloadBlob(offset, PCRInfoSize, blob, NULL); Trspi_UnloadBlob_STORE_PUBKEY(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &encSize, blob); Trspi_UnloadBlob(offset, encSize, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_TCPA_VERSION(offset, blob, &key->ver); Trspi_UnloadBlob_UINT16(offset, &key->keyUsage, blob); Trspi_UnloadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); Trspi_UnloadBlob_BYTE(offset, &key->authDataUsage, blob); if ((result = Trspi_UnloadBlob_KEY_PARMS(offset, (BYTE *) blob, &key->algorithmParms))) return result; Trspi_UnloadBlob_UINT32(offset, &key->PCRInfoSize, blob); if (key->PCRInfoSize > 0) { key->PCRInfo = malloc(key->PCRInfoSize); if (key->PCRInfo == NULL) { LogError("malloc of %d bytes failed.", key->PCRInfoSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); } else { key->PCRInfo = NULL; } if ((result = Trspi_UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) return result; Trspi_UnloadBlob_UINT32(offset, &key->encSize, blob); if (key->encSize > 0) { key->encData = malloc(key->encSize); if (key->encData == NULL) { LogError("malloc of %d bytes failed.", key->encSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, key->encSize, blob, key->encData); } else { key->encData = NULL; } return result; } TSS_RESULT Trspi_UnloadBlob_STORE_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_PUBKEY *store) { if (!store) { UINT32 keyLength; Trspi_UnloadBlob_UINT32(offset, &keyLength, blob); Trspi_UnloadBlob(offset, keyLength, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &store->keyLength, blob); if (store->keyLength > 0) { store->key = malloc(store->keyLength); if (store->key == NULL) { LogError("malloc of %d bytes failed.", store->keyLength); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, store->keyLength, blob, store->key); } else { store->key = NULL; } return TSS_SUCCESS; } void Trspi_UnloadBlob_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION *out) { if (!out) { Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); return; } Trspi_UnloadBlob_BYTE(offset, &out->major, blob); Trspi_UnloadBlob_BYTE(offset, &out->minor, blob); Trspi_UnloadBlob_BYTE(offset, &out->revMajor, blob); Trspi_UnloadBlob_BYTE(offset, &out->revMinor, blob); } TSS_RESULT Trspi_UnloadBlob_KM_KEYINFO(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO *info) { if (!info) { UINT32 ulVendorDataLength; Trspi_UnloadBlob_TSS_VERSION(offset, blob, NULL); Trspi_UnloadBlob_UUID(offset, blob, NULL); Trspi_UnloadBlob_UUID(offset, blob, NULL); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BOOL(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, &ulVendorDataLength, blob); (*offset) += ulVendorDataLength; return TSS_SUCCESS; } Trspi_UnloadBlob_TSS_VERSION(offset, blob, &info->versionInfo); Trspi_UnloadBlob_UUID(offset, blob, &info->keyUUID); Trspi_UnloadBlob_UUID(offset, blob, &info->parentKeyUUID); Trspi_UnloadBlob_BYTE(offset, &info->bAuthDataUsage, blob); Trspi_UnloadBlob_BOOL(offset, &info->fIsLoaded, blob); Trspi_UnloadBlob_UINT32(offset, &info->ulVendorDataLength, blob); if (info->ulVendorDataLength > 0){ /* allocate space for vendor data */ info->rgbVendorData = malloc(info->ulVendorDataLength); if (info->rgbVendorData == NULL) { LogError("malloc of %u bytes failed.", info->ulVendorDataLength); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, info->ulVendorDataLength, blob, info->rgbVendorData); } else info->rgbVendorData = NULL; return TSS_SUCCESS; } TSS_RESULT Trspi_UnloadBlob_KM_KEYINFO2(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO2 *info) { if (!info) { UINT32 ulVendorDataLength; Trspi_UnloadBlob_TSS_VERSION(offset, blob, NULL); Trspi_UnloadBlob_UUID(offset, blob, NULL); Trspi_UnloadBlob_UUID(offset, blob, NULL); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_BOOL(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, &ulVendorDataLength, blob); (*offset) += ulVendorDataLength; return TSS_SUCCESS; } Trspi_UnloadBlob_TSS_VERSION(offset, blob, &info->versionInfo); Trspi_UnloadBlob_UUID(offset, blob, &info->keyUUID); Trspi_UnloadBlob_UUID(offset, blob, &info->parentKeyUUID); Trspi_UnloadBlob_BYTE(offset, &info->bAuthDataUsage, blob); /* Takes data regarding the new 2 fields of TSS_KM_KEYINFO2 */ Trspi_UnloadBlob_UINT32(offset, &info->persistentStorageType, blob); Trspi_UnloadBlob_UINT32(offset, &info->persistentStorageTypeParent, blob); Trspi_UnloadBlob_BOOL(offset, &info->fIsLoaded, blob); Trspi_UnloadBlob_UINT32(offset, &info->ulVendorDataLength, blob); if (info->ulVendorDataLength > 0) { /* allocate space for vendor data */ info->rgbVendorData = malloc(info->ulVendorDataLength); if (info->rgbVendorData == NULL) { LogError("malloc of %u bytes failed.", info->ulVendorDataLength); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, info->ulVendorDataLength, blob, info->rgbVendorData); } else info->rgbVendorData = NULL; return TSS_SUCCESS; } void Trspi_LoadBlob_PCR_EVENT(UINT64 *offset, BYTE *blob, TSS_PCR_EVENT *event) { Trspi_LoadBlob_TCPA_VERSION(offset, blob, *(TCPA_VERSION *)(&event->versionInfo)); Trspi_LoadBlob_UINT32(offset, event->ulPcrIndex, blob); Trspi_LoadBlob_UINT32(offset, event->eventType, blob); Trspi_LoadBlob_UINT32(offset, event->ulPcrValueLength, blob); if (event->ulPcrValueLength > 0) Trspi_LoadBlob(offset, event->ulPcrValueLength, blob, event->rgbPcrValue); Trspi_LoadBlob_UINT32(offset, event->ulEventLength, blob); if (event->ulEventLength > 0) Trspi_LoadBlob(offset, event->ulEventLength, blob, event->rgbEvent); } TSS_RESULT Trspi_UnloadBlob_PCR_EVENT(UINT64 *offset, BYTE *blob, TSS_PCR_EVENT *event) { if (!event) { UINT32 ulPcrValueLength, ulEventLength; Trspi_UnloadBlob_VERSION(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, &ulPcrValueLength, blob); (*offset) += ulPcrValueLength; Trspi_UnloadBlob_UINT32(offset, &ulEventLength, blob); (*offset) += ulEventLength; return TSS_SUCCESS; } Trspi_UnloadBlob_VERSION(offset, blob, (TCPA_VERSION *)&(event->versionInfo)); Trspi_UnloadBlob_UINT32(offset, &event->ulPcrIndex, blob); Trspi_UnloadBlob_UINT32(offset, &event->eventType, blob); Trspi_UnloadBlob_UINT32(offset, &event->ulPcrValueLength, blob); if (event->ulPcrValueLength > 0) { event->rgbPcrValue = malloc(event->ulPcrValueLength); if (event->rgbPcrValue == NULL) { LogError("malloc of %u bytes failed.", event->ulPcrValueLength); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, event->ulPcrValueLength, blob, event->rgbPcrValue); } else { event->rgbPcrValue = NULL; } Trspi_UnloadBlob_UINT32(offset, &event->ulEventLength, blob); if (event->ulEventLength > 0) { event->rgbEvent = malloc(event->ulEventLength); if (event->rgbEvent == NULL) { LogError("malloc of %d bytes failed.", event->ulEventLength); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, event->ulEventLength, blob, event->rgbEvent); } else { event->rgbEvent = NULL; } return TSS_SUCCESS; } /* loads a blob with the info needed to hash when creating the private key area * of a TPM_KEY(12) from an external source */ void Trspi_LoadBlob_PRIVKEY_DIGEST12(UINT64 *offset, BYTE *blob, TPM_KEY12 *key) { Trspi_LoadBlob_UINT16(offset, key->tag, blob); Trspi_LoadBlob_UINT16(offset, key->fill, blob); Trspi_LoadBlob_UINT16(offset, key->keyUsage, blob); Trspi_LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); Trspi_LoadBlob_BYTE(offset, key->authDataUsage, blob); Trspi_LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms); Trspi_LoadBlob_UINT32(offset, key->PCRInfoSize, blob); /* exclude pcrInfo when PCRInfoSize is 0 as spec'd in TPM 1.1b spec p.71 */ if (key->PCRInfoSize != 0) Trspi_LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); Trspi_LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey); /* exclude encSize, encData as spec'd in TPM 1.1b spec p.71 */ } void Trspi_LoadBlob_PRIVKEY_DIGEST(UINT64 *offset, BYTE *blob, TCPA_KEY *key) { Trspi_LoadBlob_TCPA_VERSION(offset, blob, key->ver); Trspi_LoadBlob_UINT16(offset, key->keyUsage, blob); Trspi_LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); Trspi_LoadBlob_BYTE(offset, key->authDataUsage, blob); Trspi_LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms); Trspi_LoadBlob_UINT32(offset, key->PCRInfoSize, blob); /* exclude pcrInfo when PCRInfoSize is 0 as spec'd in TPM 1.1b spec p.71 */ if (key->PCRInfoSize != 0) Trspi_LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); Trspi_LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey); /* exclude encSize, encData as spec'd in TPM 1.1b spec p.71 */ } void Trspi_LoadBlob_SYMMETRIC_KEY(UINT64 *offset, BYTE *blob, TCPA_SYMMETRIC_KEY *key) { Trspi_LoadBlob_UINT32(offset, key->algId, blob); Trspi_LoadBlob_UINT16(offset, key->encScheme, blob); Trspi_LoadBlob_UINT16(offset, key->size, blob); if (key->size > 0) Trspi_LoadBlob(offset, key->size, blob, key->data); } TSS_RESULT Trspi_UnloadBlob_SYMMETRIC_KEY(UINT64 *offset, BYTE *blob, TCPA_SYMMETRIC_KEY *key) { if (!key) { UINT16 size; Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, &size, blob); (*offset) += size; return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &key->algId, blob); Trspi_UnloadBlob_UINT16(offset, &key->encScheme, blob); Trspi_UnloadBlob_UINT16(offset, &key->size, blob); if (key->size > 0) { key->data = malloc(key->size); if (key->data == NULL) { key->size = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, key->size, blob, key->data); } else { key->data = NULL; } return TSS_SUCCESS; } void Trspi_LoadBlob_IDENTITY_REQ(UINT64 *offset, BYTE *blob, TCPA_IDENTITY_REQ *req) { Trspi_LoadBlob_UINT32(offset, req->asymSize, blob); Trspi_LoadBlob_UINT32(offset, req->symSize, blob); Trspi_LoadBlob_KEY_PARMS(offset, blob, &req->asymAlgorithm); Trspi_LoadBlob_KEY_PARMS(offset, blob, &req->symAlgorithm); Trspi_LoadBlob(offset, req->asymSize, blob, req->asymBlob); Trspi_LoadBlob(offset, req->symSize, blob, req->symBlob); } void Trspi_LoadBlob_CHANGEAUTH_VALIDATE(UINT64 *offset, BYTE *blob, TPM_CHANGEAUTH_VALIDATE *caValidate) { Trspi_LoadBlob(offset, TCPA_SHA1_160_HASH_LEN, blob, caValidate->newAuthSecret.authdata); Trspi_LoadBlob(offset, TCPA_SHA1_160_HASH_LEN, blob, caValidate->n1.nonce); } TSS_RESULT Trspi_UnloadBlob_IDENTITY_REQ(UINT64 *offset, BYTE *blob, TCPA_IDENTITY_REQ *req) { TSS_RESULT result; if (!req) { UINT32 asymSize, symSize; Trspi_UnloadBlob_UINT32(offset, &asymSize, blob); Trspi_UnloadBlob_UINT32(offset, &symSize, blob); (void)Trspi_UnloadBlob_KEY_PARMS(offset, blob, NULL); (void)Trspi_UnloadBlob_KEY_PARMS(offset, blob, NULL); (*offset) += asymSize; (*offset) += symSize; return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &req->asymSize, blob); Trspi_UnloadBlob_UINT32(offset, &req->symSize, blob); if ((result = Trspi_UnloadBlob_KEY_PARMS(offset, blob, &req->asymAlgorithm))) return result; if ((Trspi_UnloadBlob_KEY_PARMS(offset, blob, &req->symAlgorithm))) { free(req->asymAlgorithm.parms); req->asymAlgorithm.parmSize = 0; return result; } if (req->asymSize > 0) { req->asymBlob = malloc(req->asymSize); if (req->asymBlob == NULL) { req->asymSize = 0; req->asymAlgorithm.parmSize = 0; free(req->asymAlgorithm.parms); req->symAlgorithm.parmSize = 0; free(req->symAlgorithm.parms); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, req->asymSize, blob, req->asymBlob); } else { req->asymBlob = NULL; } if (req->symSize > 0) { req->symBlob = malloc(req->symSize); if (req->symBlob == NULL) { req->symSize = 0; req->asymSize = 0; free(req->asymBlob); req->asymBlob = NULL; req->asymAlgorithm.parmSize = 0; free(req->asymAlgorithm.parms); req->symAlgorithm.parmSize = 0; free(req->symAlgorithm.parms); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, req->symSize, blob, req->symBlob); } else { req->symBlob = NULL; } return TSS_SUCCESS; } TSS_RESULT Trspi_UnloadBlob_IDENTITY_PROOF(UINT64 *offset, BYTE *blob, TCPA_IDENTITY_PROOF *proof) { TSS_RESULT result; if (!proof) { UINT32 labelSize, identityBindingSize, endorsementSize, platformSize; UINT32 conformanceSize; Trspi_UnloadBlob_VERSION(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &labelSize, blob); Trspi_UnloadBlob_UINT32(offset, &identityBindingSize, blob); Trspi_UnloadBlob_UINT32(offset, &endorsementSize, blob); Trspi_UnloadBlob_UINT32(offset, &platformSize, blob); Trspi_UnloadBlob_UINT32(offset, &conformanceSize, blob); (void)Trspi_UnloadBlob_PUBKEY(offset, blob, NULL); (*offset) += labelSize; (*offset) += identityBindingSize; (*offset) += endorsementSize; (*offset) += platformSize; (*offset) += conformanceSize; return TSS_SUCCESS; } /* helps when an error occurs */ memset(proof, 0, sizeof(TCPA_IDENTITY_PROOF)); Trspi_UnloadBlob_VERSION(offset, blob, (TCPA_VERSION *)&proof->ver); Trspi_UnloadBlob_UINT32(offset, &proof->labelSize, blob); Trspi_UnloadBlob_UINT32(offset, &proof->identityBindingSize, blob); Trspi_UnloadBlob_UINT32(offset, &proof->endorsementSize, blob); Trspi_UnloadBlob_UINT32(offset, &proof->platformSize, blob); Trspi_UnloadBlob_UINT32(offset, &proof->conformanceSize, blob); if ((result = Trspi_UnloadBlob_PUBKEY(offset, blob, &proof->identityKey))) { proof->labelSize = 0; proof->identityBindingSize = 0; proof->endorsementSize = 0; proof->platformSize = 0; proof->conformanceSize = 0; return result; } if (proof->labelSize > 0) { proof->labelArea = malloc(proof->labelSize); if (proof->labelArea == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } Trspi_UnloadBlob(offset, proof->labelSize, blob, proof->labelArea); } else { proof->labelArea = NULL; } if (proof->identityBindingSize > 0) { proof->identityBinding = malloc(proof->identityBindingSize); if (proof->identityBinding == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } Trspi_UnloadBlob(offset, proof->identityBindingSize, blob, proof->identityBinding); } else { proof->identityBinding = NULL; } if (proof->endorsementSize > 0) { proof->endorsementCredential = malloc(proof->endorsementSize); if (proof->endorsementCredential == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } Trspi_UnloadBlob(offset, proof->endorsementSize, blob, proof->endorsementCredential); } else { proof->endorsementCredential = NULL; } if (proof->platformSize > 0) { proof->platformCredential = malloc(proof->platformSize); if (proof->platformCredential == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } Trspi_UnloadBlob(offset, proof->platformSize, blob, proof->platformCredential); } else { proof->platformCredential = NULL; } if (proof->conformanceSize > 0) { proof->conformanceCredential = malloc(proof->conformanceSize); if (proof->conformanceCredential == NULL) { result = TSPERR(TSS_E_OUTOFMEMORY); goto error; } Trspi_UnloadBlob(offset, proof->conformanceSize, blob, proof->conformanceCredential); } else { proof->conformanceCredential = NULL; } return TSS_SUCCESS; error: proof->labelSize = 0; proof->identityBindingSize = 0; proof->endorsementSize = 0; proof->platformSize = 0; proof->conformanceSize = 0; free(proof->labelArea); proof->labelArea = NULL; free(proof->identityBinding); proof->identityBinding = NULL; free(proof->endorsementCredential); proof->endorsementCredential = NULL; free(proof->conformanceCredential); proof->conformanceCredential = NULL; /* free identityKey */ free(proof->identityKey.pubKey.key); free(proof->identityKey.algorithmParms.parms); proof->identityKey.pubKey.key = NULL; proof->identityKey.pubKey.keyLength = 0; proof->identityKey.algorithmParms.parms = NULL; proof->identityKey.algorithmParms.parmSize = 0; return result; } void Trspi_LoadBlob_SYM_CA_ATTESTATION(UINT64 *offset, BYTE *blob, TCPA_SYM_CA_ATTESTATION *sym) { Trspi_LoadBlob_UINT32(offset, sym->credSize, blob); Trspi_LoadBlob_KEY_PARMS(offset, blob, &sym->algorithm); Trspi_LoadBlob(offset, sym->credSize, blob, sym->credential); } TSS_RESULT Trspi_UnloadBlob_SYM_CA_ATTESTATION(UINT64 *offset, BYTE *blob, TCPA_SYM_CA_ATTESTATION *sym) { TSS_RESULT result; if (!sym) { UINT32 credSize; Trspi_UnloadBlob_UINT32(offset, &credSize, blob); (void)Trspi_UnloadBlob_KEY_PARMS(offset, blob, NULL); (*offset) += credSize; return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &sym->credSize, blob); if ((result = Trspi_UnloadBlob_KEY_PARMS(offset, blob, &sym->algorithm))) { sym->credSize = 0; return result; } if (sym->credSize > 0) { if ((sym->credential = malloc(sym->credSize)) == NULL) { free(sym->algorithm.parms); sym->algorithm.parmSize = 0; sym->credSize = 0; return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, sym->credSize, blob, sym->credential); } else { sym->credential = NULL; } return TSS_SUCCESS; } void Trspi_LoadBlob_ASYM_CA_CONTENTS(UINT64 *offset, BYTE *blob, TCPA_ASYM_CA_CONTENTS *asym) { Trspi_LoadBlob_SYMMETRIC_KEY(offset, blob, &asym->sessionKey); Trspi_LoadBlob(offset, TCPA_SHA1_160_HASH_LEN, blob, (BYTE *)&asym->idDigest); } TSS_RESULT Trspi_UnloadBlob_ASYM_CA_CONTENTS(UINT64 *offset, BYTE *blob, TCPA_ASYM_CA_CONTENTS *asym) { TSS_RESULT result; if (!asym) { (void)Trspi_UnloadBlob_SYMMETRIC_KEY(offset, blob, NULL); Trspi_UnloadBlob(offset, TCPA_SHA1_160_HASH_LEN, blob, NULL); return TSS_SUCCESS; } if ((result = Trspi_UnloadBlob_SYMMETRIC_KEY(offset, blob, &asym->sessionKey))) return result; Trspi_UnloadBlob(offset, TCPA_SHA1_160_HASH_LEN, blob, (BYTE *)&asym->idDigest); return TSS_SUCCESS; } void Trspi_LoadBlob_BOUND_DATA(UINT64 *offset, TCPA_BOUND_DATA bd, UINT32 payloadLength, BYTE *blob) { Trspi_LoadBlob_TCPA_VERSION(offset, blob, bd.ver); Trspi_LoadBlob(offset, 1, blob, &bd.payload); Trspi_LoadBlob(offset, payloadLength, blob, bd.payloadData); } /* function to mimic strerror with TSS error codes */ char * Trspi_Error_String(TSS_RESULT r) { /* Check the return code to see if it is common to all layers. * If so, return it. */ switch (TSS_ERROR_CODE(r)) { case TSS_SUCCESS: return "Success"; default: break; } /* The return code is either unknown, or specific to a layer */ if (TSS_ERROR_LAYER(r) == TSS_LAYER_TPM) { switch (TSS_ERROR_CODE(r)) { case TPM_E_AUTHFAIL: return "Authentication failed"; case TPM_E_BAD_PARAMETER: return "Bad Parameter"; case TPM_E_BADINDEX: return "Bad memory index"; case TPM_E_AUDITFAILURE: return "Audit failure"; case TPM_E_CLEAR_DISABLED: return "Clear has been disabled"; case TPM_E_DEACTIVATED: return "TPM is deactivated"; case TPM_E_DISABLED: return "TPM is disabled"; case TPM_E_FAIL: return "Operation failed"; case TPM_E_BAD_ORDINAL: return "Ordinal was unknown or inconsistent"; case TPM_E_INSTALL_DISABLED: return "Owner install disabled"; case TPM_E_INVALID_KEYHANDLE: return "Invalid keyhandle"; case TPM_E_KEYNOTFOUND: return "Key not found"; case TPM_E_INAPPROPRIATE_ENC: return "Bad encryption scheme"; case TPM_E_MIGRATEFAIL: return "Migration authorization failed"; case TPM_E_INVALID_PCR_INFO: return "PCR information uninterpretable"; case TPM_E_NOSPACE: return "No space to load key"; case TPM_E_NOSRK: return "No SRK"; case TPM_E_NOTSEALED_BLOB: return "Encrypted blob invalid"; case TPM_E_OWNER_SET: return "Owner already set"; case TPM_E_RESOURCES: return "Insufficient TPM resources"; case TPM_E_SHORTRANDOM: return "Random string too short"; case TPM_E_SIZE: return "TPM out of space"; case TPM_E_WRONGPCRVAL: return "Wrong PCR value"; case TPM_E_BAD_PARAM_SIZE: return "Bad input size"; case TPM_E_SHA_THREAD: return "No existing SHA-1 thread"; case TPM_E_SHA_ERROR: return "SHA-1 error"; case TPM_E_FAILEDSELFTEST: return "Self-test failed, TPM shutdown"; case TPM_E_AUTH2FAIL: return "Second authorization session failed"; case TPM_E_BADTAG: return "Invalid tag"; case TPM_E_IOERROR: return "I/O error"; case TPM_E_ENCRYPT_ERROR: return "Encryption error"; case TPM_E_DECRYPT_ERROR: return "Decryption error"; case TPM_E_INVALID_AUTHHANDLE: return "Invalid authorization handle"; case TPM_E_NO_ENDORSEMENT: return "No EK"; case TPM_E_INVALID_KEYUSAGE: return "Invalid key usage"; case TPM_E_WRONG_ENTITYTYPE: return "Invalid entity type"; case TPM_E_INVALID_POSTINIT: return "Invalid POST init sequence"; case TPM_E_INAPPROPRIATE_SIG: return "Invalid signature format"; case TPM_E_BAD_KEY_PROPERTY: return "Unsupported key parameters"; case TPM_E_BAD_MIGRATION: return "Invalid migration properties"; case TPM_E_BAD_SCHEME: return "Invalid signature or encryption scheme"; case TPM_E_BAD_DATASIZE: return "Invalid data size"; case TPM_E_BAD_MODE: return "Bad mode parameter"; case TPM_E_BAD_PRESENCE: return "Bad physical presence value"; case TPM_E_BAD_VERSION: return "Invalid version"; case TPM_E_NO_WRAP_TRANSPORT: return "TPM does not allow for wrapped transport sessions"; case TPM_E_AUDITFAIL_UNSUCCESSFUL: return "TPM audit construction failed and the underlying command was returning a failure code also"; case TPM_E_AUDITFAIL_SUCCESSFUL: return "TPM audit construction failed and the underlying command was returning success"; case TPM_E_NOTRESETABLE: return "Attempt to reset a PCR register that does not have the resettable attribute"; case TPM_E_NOTLOCAL: return "Attempt to reset a PCR register that requires locality and locality modifier not part of command transport"; case TPM_E_BAD_TYPE: return "Make identity blob not properly typed"; case TPM_E_INVALID_RESOURCE: return "When saving context identified resource type does not match actual resource"; case TPM_E_NOTFIPS: return "TPM is attempting to execute a command only available when in FIPS mode"; case TPM_E_INVALID_FAMILY: return "Command is attempting to use an invalid family ID"; case TPM_E_NO_NV_PERMISSION: return "Permission to manipulate the NV storage is not available"; case TPM_E_REQUIRES_SIGN: return "Operation requires a signed command"; case TPM_E_KEY_NOTSUPPORTED: return "Wrong operation to load an NV key"; case TPM_E_AUTH_CONFLICT: return "NV_LoadKey blob requires both owner and blob authorization"; case TPM_E_AREA_LOCKED: return "NV area is locked and not writable"; case TPM_E_BAD_LOCALITY: return "Locality is incorrect for attempted operation"; case TPM_E_READ_ONLY: return "NV area is read only and can't be written to"; case TPM_E_PER_NOWRITE: return "There is no protection on write to NV area"; case TPM_E_FAMILYCOUNT: return "Family count value does not match"; case TPM_E_WRITE_LOCKED: return "NV area has already been written to"; case TPM_E_BAD_ATTRIBUTES: return "NV area attributes conflict"; case TPM_E_INVALID_STRUCTURE: return "Structure tag and version are invalid or inconsistent"; case TPM_E_KEY_OWNER_CONTROL: return "Key is under control of TPM Owner and can only be evicted by TPM Owner"; case TPM_E_BAD_COUNTER: return "Counter handle is incorrect"; case TPM_E_NOT_FULLWRITE: return "Write is not a complete write of area"; case TPM_E_CONTEXT_GAP: return "Gap between saved context counts is too large"; case TPM_E_MAXNVWRITES: return "Maximum number of NV writes without an owner has been exceeded"; case TPM_E_NOOPERATOR: return "No operator AuthData value is set"; case TPM_E_RESOURCEMISSING: return "Resource pointed to by context is not loaded"; case TPM_E_DELEGATE_LOCK: return "Delegate administration is locked"; case TPM_E_DELEGATE_FAMILY: return "Attempt to manage a family other then delegated family"; case TPM_E_DELEGATE_ADMIN: return "Delegation table management not enabled"; case TPM_E_TRANSPORT_NOTEXCLUSIVE: return "A command was executed outside of an exclusive transport session"; case TPM_E_OWNER_CONTROL: return "Attempt to context save an owner evict-controlled key"; case TPM_E_DAA_RESOURCES: return "DAA command has no resources available to execute command"; case TPM_E_DAA_INPUT_DATA0: return "Consistency check on DAA parameter inputData0 has failed"; case TPM_E_DAA_INPUT_DATA1: return "Consistency check on DAA parameter inputData1 has failed"; case TPM_E_DAA_ISSUER_SETTINGS: return "Consistency check on DAA_issuerSettings has failed"; case TPM_E_DAA_TPM_SETTINGS: return "Consistency check on DAA_tpmSpecific has failed"; case TPM_E_DAA_STAGE: return "Atomic process indicated by submitted DAA command is not expected process"; case TPM_E_DAA_ISSUER_VALIDITY: return "Issuer's validity check has detected an inconsistency"; case TPM_E_DAA_WRONG_W: return "Consistency check on w has failed"; case TPM_E_BAD_HANDLE: return "Handle is incorrect"; case TPM_E_BAD_DELEGATE: return "Delegation is not correct"; case TPM_E_BADCONTEXT: return "Context blob is invalid"; case TPM_E_TOOMANYCONTEXTS: return "Too many contexts held by TPM"; case TPM_E_MA_TICKET_SIGNATURE: return "Migration authority signature validation failure"; case TPM_E_MA_DESTINATION: return "Migration destination not authenticated"; case TPM_E_MA_SOURCE: return "Migration source incorrect"; case TPM_E_MA_AUTHORITY: return "Incorrect migration authority"; case TPM_E_PERMANENTEK: return "Attempt to revoke EK but EK is not revocable"; case TPM_E_BAD_SIGNATURE: return "Bad signature of CMK ticket"; case TPM_E_NOCONTEXTSPACE: return "No room in context list for additional contexts"; case TPM_E_RETRY: return "TPM busy: Retry command at a later time"; case TPM_E_NEEDS_SELFTEST: return "SelfTestFull has not been run"; case TPM_E_DOING_SELFTEST: return "TPM is currently executing a full selftest"; case TPM_E_DEFEND_LOCK_RUNNING: return "TPM is defending against dictionary attacks and is in some time-out period"; case TPM_E_DISABLED_CMD: return "The TPM target command has been disabled"; default: return "Unknown error"; } } else if (TSS_ERROR_LAYER(r) == TSS_LAYER_TDDL) { switch (TSS_ERROR_CODE(r)) { case TSS_E_FAIL: return "General failure"; case TSS_E_BAD_PARAMETER: return "Bad parameter"; case TSS_E_INTERNAL_ERROR: return "Internal software error"; case TSS_E_NOTIMPL: return "Not implemented"; case TSS_E_PS_KEY_NOTFOUND: return "Key not found in persistent storage"; case TSS_E_KEY_ALREADY_REGISTERED: return "UUID already registered"; case TSS_E_CANCELED: return "The action was cancelled by request"; case TSS_E_TIMEOUT: return "The operation has timed out"; case TSS_E_OUTOFMEMORY: return "Out of memory"; case TSS_E_TPM_UNEXPECTED: return "Unexpected TPM output"; case TSS_E_COMM_FAILURE: return "Communication failure"; case TSS_E_TPM_UNSUPPORTED_FEATURE: return "Unsupported feature"; case TDDL_E_COMPONENT_NOT_FOUND: return "Connection to TPM device failed"; case TDDL_E_ALREADY_OPENED: return "Device already opened"; case TDDL_E_BADTAG: return "Invalid or unsupported capability"; case TDDL_E_INSUFFICIENT_BUFFER: return "Receive buffer too small"; case TDDL_E_COMMAND_COMPLETED: return "Command has already completed"; case TDDL_E_COMMAND_ABORTED: return "TPM aborted processing of command"; case TDDL_E_ALREADY_CLOSED: return "Device driver already closed"; case TDDL_E_IOERROR: return "I/O error"; default: return "Unknown"; } } else if (TSS_ERROR_LAYER(r) == TSS_LAYER_TCS) { switch (TSS_ERROR_CODE(r)) { case TSS_E_FAIL: return "General failure"; case TSS_E_BAD_PARAMETER: return "Bad parameter"; case TSS_E_INTERNAL_ERROR: return "Internal software error"; case TSS_E_NOTIMPL: return "Not implemented"; case TSS_E_PS_KEY_NOTFOUND: return "Key not found in persistent storage"; case TSS_E_KEY_ALREADY_REGISTERED: return "UUID already registered"; case TSS_E_CANCELED: return "The action was cancelled by request"; case TSS_E_TIMEOUT: return "The operation has timed out"; case TSS_E_OUTOFMEMORY: return "Out of memory"; case TSS_E_TPM_UNEXPECTED: return "Unexpected TPM output"; case TSS_E_COMM_FAILURE: return "Communication failure"; case TSS_E_TPM_UNSUPPORTED_FEATURE: return "Unsupported feature"; case TCS_E_KEY_MISMATCH: return "UUID does not match key handle"; case TCS_E_KM_LOADFAILED: return "Key load failed: parent key requires authorization"; case TCS_E_KEY_CONTEXT_RELOAD: return "Reload of key context failed"; case TCS_E_BAD_INDEX: return "Bad memory index"; case TCS_E_INVALID_CONTEXTHANDLE: return "Invalid context handle"; case TCS_E_INVALID_KEYHANDLE: return "Invalid key handle"; case TCS_E_INVALID_AUTHHANDLE: return "Invalid authorization session handle"; case TCS_E_INVALID_AUTHSESSION: return "Authorization session has been closed by TPM"; case TCS_E_INVALID_KEY: return "Invalid key"; default: return "Unknown"; } } else { switch (TSS_ERROR_CODE(r)) { case TSS_E_FAIL: return "General failure"; case TSS_E_BAD_PARAMETER: return "Bad parameter"; case TSS_E_INTERNAL_ERROR: return "Internal software error"; case TSS_E_NOTIMPL: return "Not implemented"; case TSS_E_PS_KEY_NOTFOUND: return "Key not found in persistent storage"; case TSS_E_KEY_ALREADY_REGISTERED: return "UUID already registered"; case TSS_E_CANCELED: return "The action was cancelled by request"; case TSS_E_TIMEOUT: return "The operation has timed out"; case TSS_E_OUTOFMEMORY: return "Out of memory"; case TSS_E_TPM_UNEXPECTED: return "Unexpected TPM output"; case TSS_E_COMM_FAILURE: return "Communication failure"; case TSS_E_TPM_UNSUPPORTED_FEATURE: return "Unsupported feature"; case TSS_E_INVALID_OBJECT_TYPE: return "Object type not valid for this operation"; case TSS_E_INVALID_OBJECT_INITFLAG: return "Wrong flag information for object creation"; case TSS_E_INVALID_HANDLE: return "Invalid handle"; case TSS_E_NO_CONNECTION: return "Core service connection doesn't exist"; case TSS_E_CONNECTION_FAILED: return "Core service connection failed"; case TSS_E_CONNECTION_BROKEN: return "Communication with core services failed"; case TSS_E_HASH_INVALID_ALG: return "Invalid hash algorithm"; case TSS_E_HASH_INVALID_LENGTH: return "Hash length is inconsistent with algorithm"; case TSS_E_HASH_NO_DATA: return "Hash object has no internal hash value"; case TSS_E_SILENT_CONTEXT: return "A silent context requires user input"; case TSS_E_INVALID_ATTRIB_FLAG: return "Flag value for attrib-functions inconsistent"; case TSS_E_INVALID_ATTRIB_SUBFLAG: return "Sub-flag value for attrib-functions inconsistent"; case TSS_E_INVALID_ATTRIB_DATA: return "Data for attrib-functions invalid"; case TSS_E_NO_PCRS_SET: return "No PCR registers are selected or set"; case TSS_E_KEY_NOT_LOADED: return "The addressed key is not currently loaded"; case TSS_E_KEY_NOT_SET: return "No key informatio is currently available"; case TSS_E_VALIDATION_FAILED: return "Internal validation of data failed"; case TSS_E_TSP_AUTHREQUIRED: return "Authorization is required"; case TSS_E_TSP_AUTH2REQUIRED: return "Multiple authorizations are required"; case TSS_E_TSP_AUTHFAIL: return "Authorization failed"; case TSS_E_TSP_AUTH2FAIL: return "Multiple authorization failed"; case TSS_E_KEY_NO_MIGRATION_POLICY: return "Addressed key has no migration policy"; case TSS_E_POLICY_NO_SECRET: return "No secret information available for the address policy"; case TSS_E_INVALID_OBJ_ACCESS: return "Accessed object is in an inconsistent state"; case TSS_E_INVALID_ENCSCHEME: return "Invalid encryption scheme"; case TSS_E_INVALID_SIGSCHEME: return "Invalid signature scheme"; case TSS_E_ENC_INVALID_LENGTH: return "Invalid length for encrypted data object"; case TSS_E_ENC_NO_DATA: return "Encrypted data object contains no data"; case TSS_E_ENC_INVALID_TYPE: return "Invalid type for encrypted data object"; case TSS_E_INVALID_KEYUSAGE: return "Invalid usage of key"; case TSS_E_VERIFICATION_FAILED: return "Internal validation of data failed"; case TSS_E_HASH_NO_IDENTIFIER: return "Hash algorithm identifier not set"; case TSS_E_NV_AREA_EXIST: return "NVRAM area already exists"; case TSS_E_NV_AREA_NOT_EXIST: return "NVRAM area does not exist"; default: return "Unknown"; } } } char * Trspi_Error_Layer(TSS_RESULT r) { switch (TSS_ERROR_LAYER(r)) { case TSS_LAYER_TPM: return "tpm"; case TSS_LAYER_TDDL: return "tddl"; case TSS_LAYER_TCS: return "tcs"; case TSS_LAYER_TSP: return "tsp"; default: return "unknown"; } } TSS_RESULT Trspi_Error_Code(TSS_RESULT r) { return TSS_ERROR_CODE(r); } static int hacky_strlen(char *codeset, BYTE *string) { BYTE *ptr = string; int len = 0; if (strcmp("UTF-16", codeset) == 0) { while (!(ptr[0] == '\0' && ptr[1] == '\0')) { len += 2; ptr += 2; } } else if (strcmp("UTF-32", codeset) == 0) { while (!(ptr[0] == '\0' && ptr[1] == '\0' && ptr[2] == '\0' && ptr[3] == '\0')) { len += 4; ptr += 4; } } else { /* default to 8bit chars */ while (*ptr++ != '\0') { len++; } } return len; } static inline int char_width(char *codeset) { if (strcmp("UTF-16", codeset) == 0) { return 2; } else if (strcmp("UTF-32", codeset) == 0) { return 4; } return 1; } #define MAX_BUF_SIZE 4096 BYTE * Trspi_Native_To_UNICODE(BYTE *string, unsigned *size) { char *ret, *outbuf, tmpbuf[MAX_BUF_SIZE] = { 0, }; BSD_CONST char *ptr; unsigned len = 0, tmplen; iconv_t cd = 0; size_t rc, outbytesleft, inbytesleft; if (string == NULL) goto alloc_string; if ((cd = iconv_open("UTF-16LE", nl_langinfo(CODESET))) == (iconv_t)-1) { LogDebug("iconv_open: %s", strerror(errno)); return NULL; } if ((tmplen = hacky_strlen(nl_langinfo(CODESET), string)) == 0) { LogDebug("hacky_strlen returned 0"); goto alloc_string; } do { len++; outbytesleft = len; inbytesleft = tmplen; outbuf = tmpbuf; ptr = (char *)string; errno = 0; rc = iconv(cd, (BSD_CONST char **)&ptr, &inbytesleft, &outbuf, &outbytesleft); } while (rc == (size_t)-1 && errno == E2BIG); if (len > MAX_BUF_SIZE) { LogDebug("string too long."); iconv_close(cd); return NULL; } alloc_string: /* add terminating bytes of the correct width */ len += char_width("UTF-16"); if ((ret = calloc(1, len)) == NULL) { LogDebug("malloc of %u bytes failed.", len); iconv_close(cd); return NULL; } memcpy(ret, &tmpbuf, len); if (size) *size = len; if (cd) iconv_close(cd); return (BYTE *)ret; } BYTE * Trspi_UNICODE_To_Native(BYTE *string, unsigned *size) { char *ret, *outbuf, tmpbuf[MAX_BUF_SIZE] = { 0, }; BSD_CONST char *ptr; unsigned len = 0, tmplen; iconv_t cd; size_t rc, outbytesleft, inbytesleft; if (string == NULL) { if (size) *size = 0; return NULL; } if ((cd = iconv_open(nl_langinfo(CODESET), "UTF-16LE")) == (iconv_t)-1) { LogDebug("iconv_open: %s", strerror(errno)); return NULL; } if ((tmplen = hacky_strlen("UTF-16", string)) == 0) { LogDebug("hacky_strlen returned 0"); iconv_close(cd); return 0; } do { len++; outbytesleft = len; inbytesleft = tmplen; outbuf = tmpbuf; ptr = (char *)string; errno = 0; rc = iconv(cd, (BSD_CONST char **)&ptr, &inbytesleft, &outbuf, &outbytesleft); } while (rc == (size_t)-1 && errno == E2BIG); /* add terminating bytes of the correct width */ len += char_width(nl_langinfo(CODESET)); if (len > MAX_BUF_SIZE) { LogDebug("string too long."); iconv_close(cd); return NULL; } if ((ret = calloc(1, len)) == NULL) { LogDebug("malloc of %d bytes failed.", len); iconv_close(cd); return NULL; } memcpy(ret, &tmpbuf, len); if (size) *size = len; iconv_close(cd); return (BYTE *)ret; } /* Functions to support incremental hashing */ TSS_RESULT Trspi_Hash_UINT16(Trspi_HashCtx *c, UINT16 i) { BYTE bytes[sizeof(UINT16)]; UINT16ToArray(i, bytes); return Trspi_HashUpdate(c, sizeof(UINT16), bytes); } TSS_RESULT Trspi_Hash_UINT32(Trspi_HashCtx *c, UINT32 i) { BYTE bytes[sizeof(UINT32)]; UINT32ToArray(i, bytes); return Trspi_HashUpdate(c, sizeof(UINT32), bytes); } TSS_RESULT Trspi_Hash_UINT64(Trspi_HashCtx *c, UINT64 i) { BYTE bytes[sizeof(UINT64)]; UINT64ToArray(i, bytes); return Trspi_HashUpdate(c, sizeof(UINT64), bytes); } TSS_RESULT Trspi_Hash_BYTE(Trspi_HashCtx *c, BYTE data) { return Trspi_HashUpdate(c, sizeof(BYTE), &data); } TSS_RESULT Trspi_Hash_BOOL(Trspi_HashCtx *c, TSS_BOOL data) { return Trspi_HashUpdate(c, (UINT32)sizeof(TSS_BOOL), (BYTE *)&data); } TSS_RESULT Trspi_Hash_VERSION(Trspi_HashCtx *c, TSS_VERSION *version) { TSS_RESULT result; result = Trspi_Hash_BYTE(c, version->bMajor); result |= Trspi_Hash_BYTE(c, version->bMinor); result |= Trspi_Hash_BYTE(c, version->bRevMajor); result |= Trspi_Hash_BYTE(c, version->bRevMinor); return result; } TSS_RESULT Trspi_Hash_DAA_PK(Trspi_HashCtx *c, TSS_DAA_PK *pk) { UINT32 i; TSS_RESULT result; result = Trspi_Hash_VERSION(c, &pk->versionInfo); result |= Trspi_Hash_UINT32(c, pk->modulusLength); result |= Trspi_HashUpdate(c, pk->modulusLength, pk->modulus); result |= Trspi_Hash_UINT32(c, pk->capitalSLength); result |= Trspi_HashUpdate(c, pk->capitalSLength, pk->capitalS); result |= Trspi_Hash_UINT32(c, pk->capitalZLength); result |= Trspi_HashUpdate(c, pk->capitalZLength, pk->capitalZ); result |= Trspi_Hash_UINT32(c, pk->capitalR0Length); result |= Trspi_HashUpdate(c, pk->capitalR0Length, pk->capitalR0); result |= Trspi_Hash_UINT32(c, pk->capitalR1Length); result |= Trspi_HashUpdate(c, pk->capitalR1Length, pk->capitalR1); result |= Trspi_Hash_UINT32(c, pk->gammaLength); result |= Trspi_HashUpdate(c, pk->gammaLength, pk->gamma); result |= Trspi_Hash_UINT32(c, pk->capitalGammaLength); result |= Trspi_HashUpdate(c, pk->capitalGammaLength, pk->capitalGamma); result |= Trspi_Hash_UINT32(c, pk->rhoLength); result |= Trspi_HashUpdate(c, pk->rhoLength, pk->rho); for (i = 0; i < pk->capitalYLength; i++) result |= Trspi_HashUpdate(c, pk->capitalYLength2, pk->capitalY[i]); result |= Trspi_Hash_UINT32(c, pk->capitalYPlatformLength); result |= Trspi_Hash_UINT32(c, pk->issuerBaseNameLength); result |= Trspi_HashUpdate(c, pk->issuerBaseNameLength, pk->issuerBaseName); return result; } TSS_RESULT Trspi_Hash_RSA_KEY_PARMS(Trspi_HashCtx *c, TCPA_RSA_KEY_PARMS *parms) { TSS_RESULT result; result = Trspi_Hash_UINT32(c, parms->keyLength); result |= Trspi_Hash_UINT32(c, parms->numPrimes); result |= Trspi_Hash_UINT32(c, parms->exponentSize); if (parms->exponentSize > 0) result |= Trspi_HashUpdate(c, parms->exponentSize, parms->exponent); return result; } TSS_RESULT Trspi_Hash_STORE_PUBKEY(Trspi_HashCtx *c, TCPA_STORE_PUBKEY *store) { TSS_RESULT result; result = Trspi_Hash_UINT32(c, store->keyLength); result |= Trspi_HashUpdate(c, store->keyLength, store->key); return result; } TSS_RESULT Trspi_Hash_KEY_PARMS(Trspi_HashCtx *c, TCPA_KEY_PARMS *keyInfo) { TSS_RESULT result; result = Trspi_Hash_UINT32(c, keyInfo->algorithmID); result |= Trspi_Hash_UINT16(c, keyInfo->encScheme); result |= Trspi_Hash_UINT16(c, keyInfo->sigScheme); result |= Trspi_Hash_UINT32(c, keyInfo->parmSize); if (keyInfo->parmSize > 0) result |= Trspi_HashUpdate(c, keyInfo->parmSize, keyInfo->parms); return result; } TSS_RESULT Trspi_Hash_PUBKEY(Trspi_HashCtx *c, TCPA_PUBKEY *pubKey) { TSS_RESULT result; result = Trspi_Hash_KEY_PARMS(c, &pubKey->algorithmParms); result |= Trspi_Hash_STORE_PUBKEY(c, &pubKey->pubKey); return result; } TSS_RESULT Trspi_Hash_STORED_DATA(Trspi_HashCtx *c, TCPA_STORED_DATA *data) { TSS_RESULT result; result = Trspi_Hash_VERSION(c, (TSS_VERSION *)&data->ver); result |= Trspi_Hash_UINT32(c, data->sealInfoSize); result |= Trspi_HashUpdate(c, data->sealInfoSize, data->sealInfo); result |= Trspi_Hash_UINT32(c, data->encDataSize); result |= Trspi_HashUpdate(c, data->encDataSize, data->encData); return result; } TSS_RESULT Trspi_Hash_PCR_SELECTION(Trspi_HashCtx *c, TCPA_PCR_SELECTION *pcr) { TSS_RESULT result; UINT16 i; result = Trspi_Hash_UINT16(c, pcr->sizeOfSelect); for (i = 0; i < pcr->sizeOfSelect; i++) result |= Trspi_Hash_BYTE(c, pcr->pcrSelect[i]); return result; } TSS_RESULT Trspi_Hash_KEY_FLAGS(Trspi_HashCtx *c, TCPA_KEY_FLAGS *flags) { return Trspi_Hash_UINT32(c, *flags); } TSS_RESULT Trspi_Hash_KEY12(Trspi_HashCtx *c, TPM_KEY12 *key) { TSS_RESULT result; result = Trspi_Hash_UINT16(c, key->tag); result |= Trspi_Hash_UINT16(c, key->fill); result |= Trspi_Hash_UINT16(c, key->keyUsage); result |= Trspi_Hash_KEY_FLAGS(c, &key->keyFlags); result |= Trspi_Hash_BYTE(c, key->authDataUsage); result |= Trspi_Hash_KEY_PARMS(c, &key->algorithmParms); result |= Trspi_Hash_UINT32(c, key->PCRInfoSize); result |= Trspi_HashUpdate(c, key->PCRInfoSize, key->PCRInfo); result |= Trspi_Hash_STORE_PUBKEY(c, &key->pubKey); result |= Trspi_Hash_UINT32(c, key->encSize); result |= Trspi_HashUpdate(c, key->encSize, key->encData); return result; } TSS_RESULT Trspi_Hash_KEY(Trspi_HashCtx *c, TCPA_KEY *key) { TSS_RESULT result; result = Trspi_Hash_VERSION(c, (TSS_VERSION *)&key->ver); result |= Trspi_Hash_UINT16(c, key->keyUsage); result |= Trspi_Hash_KEY_FLAGS(c, &key->keyFlags); result |= Trspi_Hash_BYTE(c, key->authDataUsage); result |= Trspi_Hash_KEY_PARMS(c, &key->algorithmParms); result |= Trspi_Hash_UINT32(c, key->PCRInfoSize); result |= Trspi_HashUpdate(c, key->PCRInfoSize, key->PCRInfo); result |= Trspi_Hash_STORE_PUBKEY(c, &key->pubKey); result |= Trspi_Hash_UINT32(c, key->encSize); result |= Trspi_HashUpdate(c, key->encSize, key->encData); return result; } TSS_RESULT Trspi_Hash_UUID(Trspi_HashCtx *c, TSS_UUID uuid) { TSS_RESULT result; result = Trspi_Hash_UINT32(c, uuid.ulTimeLow); result |= Trspi_Hash_UINT16(c, uuid.usTimeMid); result |= Trspi_Hash_UINT16(c, uuid.usTimeHigh); result |= Trspi_Hash_BYTE(c, uuid.bClockSeqHigh); result |= Trspi_Hash_BYTE(c, uuid.bClockSeqLow); result |= Trspi_HashUpdate(c, sizeof(uuid.rgbNode), uuid.rgbNode); return result; } TSS_RESULT Trspi_Hash_PCR_EVENT(Trspi_HashCtx *c, TSS_PCR_EVENT *event) { TSS_RESULT result; result = Trspi_Hash_VERSION(c, &event->versionInfo); result |= Trspi_Hash_UINT32(c, event->ulPcrIndex); result |= Trspi_Hash_UINT32(c, event->eventType); Trspi_Hash_UINT32(c, event->ulPcrValueLength); if (event->ulPcrValueLength > 0) result |= Trspi_HashUpdate(c, event->ulPcrValueLength, event->rgbPcrValue); result |= Trspi_Hash_UINT32(c, event->ulEventLength); if (event->ulEventLength > 0) result |= Trspi_HashUpdate(c, event->ulEventLength, event->rgbEvent); return result; } TSS_RESULT Trspi_Hash_PRIVKEY_DIGEST12(Trspi_HashCtx *c, TPM_KEY12 *key) { TSS_RESULT result; result = Trspi_Hash_UINT16(c, key->tag); result |= Trspi_Hash_UINT16(c, key->fill); result |= Trspi_Hash_UINT16(c, key->keyUsage); result |= Trspi_Hash_KEY_FLAGS(c, &key->keyFlags); result |= Trspi_Hash_BYTE(c, key->authDataUsage); result |= Trspi_Hash_KEY_PARMS(c, &key->algorithmParms); result |= Trspi_Hash_UINT32(c, key->PCRInfoSize); /* exclude pcrInfo when PCRInfoSize is 0 as spec'd in TPM 1.1b spec p.71 */ if (key->PCRInfoSize != 0) result |= Trspi_HashUpdate(c, key->PCRInfoSize, key->PCRInfo); Trspi_Hash_STORE_PUBKEY(c, &key->pubKey); /* exclude encSize, encData as spec'd in TPM 1.1b spec p.71 */ return result; } TSS_RESULT Trspi_Hash_PRIVKEY_DIGEST(Trspi_HashCtx *c, TCPA_KEY *key) { TSS_RESULT result; result = Trspi_Hash_VERSION(c, (TSS_VERSION *)&key->ver); result |= Trspi_Hash_UINT16(c, key->keyUsage); result |= Trspi_Hash_KEY_FLAGS(c, &key->keyFlags); result |= Trspi_Hash_BYTE(c, key->authDataUsage); result |= Trspi_Hash_KEY_PARMS(c, &key->algorithmParms); result |= Trspi_Hash_UINT32(c, key->PCRInfoSize); /* exclude pcrInfo when PCRInfoSize is 0 as spec'd in TPM 1.1b spec p.71 */ if (key->PCRInfoSize != 0) result |= Trspi_HashUpdate(c, key->PCRInfoSize, key->PCRInfo); Trspi_Hash_STORE_PUBKEY(c, &key->pubKey); /* exclude encSize, encData as spec'd in TPM 1.1b spec p.71 */ return result; } TSS_RESULT Trspi_Hash_SYMMETRIC_KEY(Trspi_HashCtx *c, TCPA_SYMMETRIC_KEY *key) { TSS_RESULT result; result = Trspi_Hash_UINT32(c, key->algId); result |= Trspi_Hash_UINT16(c, key->encScheme); result |= Trspi_Hash_UINT16(c, key->size); if (key->size > 0) result |= Trspi_HashUpdate(c, key->size, key->data); return result; } TSS_RESULT Trspi_Hash_IDENTITY_REQ(Trspi_HashCtx *c, TCPA_IDENTITY_REQ *req) { TSS_RESULT result; result = Trspi_Hash_UINT32(c, req->asymSize); result |= Trspi_Hash_UINT32(c, req->symSize); result |= Trspi_Hash_KEY_PARMS(c, &req->asymAlgorithm); result |= Trspi_Hash_KEY_PARMS(c, &req->symAlgorithm); result |= Trspi_HashUpdate(c, req->asymSize, req->asymBlob); result |= Trspi_HashUpdate(c, req->symSize, req->symBlob); return result; } TSS_RESULT Trspi_Hash_CHANGEAUTH_VALIDATE(Trspi_HashCtx *c, TPM_CHANGEAUTH_VALIDATE *caValidate) { TSS_RESULT result; result = Trspi_HashUpdate(c, TCPA_SHA1_160_HASH_LEN, caValidate->newAuthSecret.authdata); result |= Trspi_HashUpdate(c, TCPA_SHA1_160_HASH_LEN, caValidate->n1.nonce); return result; } TSS_RESULT Trspi_Hash_SYM_CA_ATTESTATION(Trspi_HashCtx *c, TCPA_SYM_CA_ATTESTATION *sym) { TSS_RESULT result; result = Trspi_Hash_UINT32(c, sym->credSize); result |= Trspi_Hash_KEY_PARMS(c, &sym->algorithm); result |= Trspi_HashUpdate(c, sym->credSize, sym->credential); return result; } TSS_RESULT Trspi_Hash_ASYM_CA_CONTENTS(Trspi_HashCtx *c, TCPA_ASYM_CA_CONTENTS *asym) { TSS_RESULT result; result = Trspi_Hash_SYMMETRIC_KEY(c, &asym->sessionKey); result |= Trspi_HashUpdate(c, TCPA_SHA1_160_HASH_LEN, (BYTE *)&asym->idDigest); return result; } TSS_RESULT Trspi_Hash_BOUND_DATA(Trspi_HashCtx *c, TCPA_BOUND_DATA *bd, UINT32 payloadLength) { TSS_RESULT result; result = Trspi_Hash_VERSION(c, (TSS_VERSION *)&bd->ver); result |= Trspi_Hash_BYTE(c, bd->payload); result |= Trspi_HashUpdate(c, payloadLength, bd->payloadData); return result; } TSS_RESULT Trspi_Hash_TRANSPORT_AUTH(Trspi_HashCtx *c, TPM_TRANSPORT_AUTH *a) { TSS_RESULT result; result = Trspi_Hash_UINT16(c, a->tag); result |= Trspi_HashUpdate(c, TPM_SHA1_160_HASH_LEN, a->authData.authdata); return result; } TSS_RESULT Trspi_Hash_TRANSPORT_LOG_IN(Trspi_HashCtx *c, TPM_TRANSPORT_LOG_IN *l) { TSS_RESULT result; result = Trspi_Hash_UINT16(c, l->tag); result |= Trspi_Hash_DIGEST(c, l->parameters.digest); result |= Trspi_Hash_DIGEST(c, l->pubKeyHash.digest); return result; } TSS_RESULT Trspi_Hash_TRANSPORT_LOG_OUT(Trspi_HashCtx *c, TPM_TRANSPORT_LOG_OUT *l) { TSS_RESULT result; result = Trspi_Hash_UINT16(c, l->tag); result |= Trspi_Hash_CURRENT_TICKS(c, &l->currentTicks); result |= Trspi_Hash_DIGEST(c, l->parameters.digest); result |= Trspi_Hash_UINT32(c, l->locality); return result; } TSS_RESULT Trspi_Hash_CURRENT_TICKS(Trspi_HashCtx *c, TPM_CURRENT_TICKS *t) { TSS_RESULT result; result = Trspi_Hash_UINT16(c, t->tag); result |= Trspi_Hash_UINT64(c, t->currentTicks); result |= Trspi_Hash_UINT16(c, t->tickRate); result |= Trspi_Hash_NONCE(c, t->tickNonce.nonce); return result; } TSS_RESULT Trspi_Hash_SIGN_INFO(Trspi_HashCtx *c, TPM_SIGN_INFO *s) { TSS_RESULT result; result = Trspi_Hash_UINT16(c, s->tag); result |= Trspi_HashUpdate(c, 4, s->fixed); result |= Trspi_Hash_NONCE(c, s->replay.nonce); result |= Trspi_Hash_UINT32(c, s->dataLen); result |= Trspi_HashUpdate(c, s->dataLen, s->data); return result; } void Trspi_UnloadBlob_COUNTER_VALUE(UINT64 *offset, BYTE *blob, TPM_COUNTER_VALUE *ctr) { if (!ctr) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); /* '4' is hard-coded in the spec */ Trspi_UnloadBlob(offset, 4, blob, NULL); Trspi_UnloadBlob_UINT32(offset, NULL, blob); return; } Trspi_UnloadBlob_UINT16(offset, &ctr->tag, blob); /* '4' is hard-coded in the spec */ Trspi_UnloadBlob(offset, 4, blob, (BYTE *)&ctr->label); Trspi_UnloadBlob_UINT32(offset, &ctr->counter, blob); } void Trspi_LoadBlob_COUNTER_VALUE(UINT64 *offset, BYTE *blob, TPM_COUNTER_VALUE *ctr) { Trspi_LoadBlob_UINT16(offset, ctr->tag, blob); Trspi_LoadBlob(offset, 4, blob, (BYTE *)&ctr->label); Trspi_LoadBlob_UINT32(offset, ctr->counter, blob); } void Trspi_UnloadBlob_CURRENT_TICKS(UINT64 *offset, BYTE *blob, TPM_CURRENT_TICKS *ticks) { if (!ticks) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT64(offset, NULL, blob); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob(offset, sizeof(TPM_NONCE), blob, NULL); return; } Trspi_UnloadBlob_UINT16(offset, &ticks->tag, blob); Trspi_UnloadBlob_UINT64(offset, &ticks->currentTicks, blob); Trspi_UnloadBlob_UINT16(offset, &ticks->tickRate, blob); Trspi_UnloadBlob(offset, sizeof(TPM_NONCE), blob, (BYTE *)&ticks->tickNonce); } void Trspi_UnloadBlob_TRANSPORT_PUBLIC(UINT64 *offset, BYTE *blob, TPM_TRANSPORT_PUBLIC *t) { Trspi_UnloadBlob_UINT16(offset, &t->tag, blob); Trspi_UnloadBlob_UINT32(offset, &t->transAttributes, blob); Trspi_UnloadBlob_UINT32(offset, &t->algId, blob); Trspi_UnloadBlob_UINT16(offset, &t->encScheme, blob); } void Trspi_LoadBlob_TRANSPORT_PUBLIC(UINT64 *offset, BYTE *blob, TPM_TRANSPORT_PUBLIC *t) { Trspi_LoadBlob_UINT16(offset, t->tag, blob); Trspi_LoadBlob_UINT32(offset, t->transAttributes, blob); Trspi_LoadBlob_UINT32(offset, t->algId, blob); Trspi_LoadBlob_UINT16(offset, t->encScheme, blob); } void Trspi_LoadBlob_TRANSPORT_AUTH(UINT64 *offset, BYTE *blob, TPM_TRANSPORT_AUTH *t) { Trspi_LoadBlob_UINT16(offset, t->tag, blob); Trspi_LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, t->authData.authdata); } void Trspi_LoadBlob_SIGN_INFO(UINT64 *offset, BYTE *blob, TPM_SIGN_INFO *s) { Trspi_LoadBlob_UINT16(offset, s->tag, blob); Trspi_LoadBlob(offset, 4, blob, s->fixed); Trspi_LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, s->replay.nonce); Trspi_LoadBlob_UINT32(offset, s->dataLen, blob); Trspi_LoadBlob(offset, s->dataLen, blob, s->data); } TSS_RESULT Trspi_UnloadBlob_CERTIFY_INFO(UINT64 *offset, BYTE *blob, TPM_CERTIFY_INFO *c) { TSS_RESULT result; if (!c) { UINT32 pcrInfoSize; Trspi_UnloadBlob_VERSION(offset, blob, NULL); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_KEY_PARMS(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); Trspi_UnloadBlob_NONCE(offset, blob, NULL); Trspi_UnloadBlob_BOOL(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, &pcrInfoSize, blob); (*offset) += pcrInfoSize; return TSS_SUCCESS; } Trspi_UnloadBlob_VERSION(offset, blob, &c->version); Trspi_UnloadBlob_UINT16(offset, &c->keyUsage, blob); Trspi_UnloadBlob_UINT32(offset, &c->keyFlags, blob); Trspi_UnloadBlob_BYTE(offset, &c->authDataUsage, blob); if ((result = Trspi_UnloadBlob_KEY_PARMS(offset, blob, &c->algorithmParms))) return result; Trspi_UnloadBlob_DIGEST(offset, blob, &c->pubkeyDigest); Trspi_UnloadBlob_NONCE(offset, blob, &c->data); Trspi_UnloadBlob_BOOL(offset, (TSS_BOOL *)&c->parentPCRStatus, blob); Trspi_UnloadBlob_UINT32(offset, &c->PCRInfoSize, blob); if (c->PCRInfoSize != 0) { c->PCRInfo = malloc(sizeof(TPM_PCR_INFO)); if (c->PCRInfo == NULL) { LogError("malloc of %zd bytes failed.", sizeof(TPM_PCR_INFO)); return TSPERR(TSS_E_OUTOFMEMORY); } } else { c->PCRInfo = NULL; } Trspi_UnloadBlob_PCR_INFO(offset, blob, (TPM_PCR_INFO *)c->PCRInfo); return TSS_SUCCESS; } void Trspi_UnloadBlob_TPM_FAMILY_LABEL(UINT64 *offset, BYTE *blob, TPM_FAMILY_LABEL *label) { if (!label) { Trspi_UnloadBlob_BYTE(offset, NULL, blob); return; } Trspi_UnloadBlob_BYTE(offset, &label->label, blob); } void Trspi_LoadBlob_TPM_FAMILY_LABEL(UINT64 *offset, BYTE *blob, TPM_FAMILY_LABEL *label) { Trspi_LoadBlob_BYTE(offset, label->label, blob); } void Trspi_UnloadBlob_TPM_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TPM_FAMILY_TABLE_ENTRY *entry) { if (!entry) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_TPM_FAMILY_LABEL(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); return; } Trspi_UnloadBlob_UINT16(offset, &entry->tag, blob); Trspi_UnloadBlob_TPM_FAMILY_LABEL(offset, blob, &entry->label); Trspi_UnloadBlob_UINT32(offset, &entry->familyID, blob); Trspi_UnloadBlob_UINT32(offset, &entry->verificationCount, blob); Trspi_UnloadBlob_UINT32(offset, &entry->flags, blob); } void Trspi_LoadBlob_TPM_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TPM_FAMILY_TABLE_ENTRY *entry) { Trspi_LoadBlob_UINT16(offset, entry->tag, blob); Trspi_LoadBlob_TPM_FAMILY_LABEL(offset, blob, &entry->label); Trspi_LoadBlob_UINT32(offset, entry->familyID, blob); Trspi_LoadBlob_UINT32(offset, entry->verificationCount, blob); Trspi_LoadBlob_UINT32(offset, entry->flags, blob); } void Trspi_UnloadBlob_TPM_DELEGATE_LABEL(UINT64 *offset, BYTE *blob, TPM_DELEGATE_LABEL *label) { if (!label) { Trspi_UnloadBlob_BYTE(offset, NULL, blob); return; } Trspi_UnloadBlob_BYTE(offset, &label->label, blob); } void Trspi_LoadBlob_TPM_DELEGATE_LABEL(UINT64 *offset, BYTE *blob, TPM_DELEGATE_LABEL *label) { Trspi_LoadBlob_BYTE(offset, label->label, blob); } void Trspi_UnloadBlob_TPM_DELEGATIONS(UINT64 *offset, BYTE *blob, TPM_DELEGATIONS *delegations) { if (!delegations) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); return; } Trspi_UnloadBlob_UINT16(offset, &delegations->tag, blob); Trspi_UnloadBlob_UINT32(offset, &delegations->delegateType, blob); Trspi_UnloadBlob_UINT32(offset, &delegations->per1, blob); Trspi_UnloadBlob_UINT32(offset, &delegations->per2, blob); } void Trspi_LoadBlob_TPM_DELEGATIONS(UINT64 *offset, BYTE *blob, TPM_DELEGATIONS *delegations) { Trspi_LoadBlob_UINT16(offset, delegations->tag, blob); Trspi_LoadBlob_UINT32(offset, delegations->delegateType, blob); Trspi_LoadBlob_UINT32(offset, delegations->per1, blob); Trspi_LoadBlob_UINT32(offset, delegations->per2, blob); } TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(UINT64 *offset, BYTE *blob, TPM_DELEGATE_PUBLIC *pub) { TSS_RESULT result; if (!pub) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_TPM_DELEGATE_LABEL(offset, blob, NULL); (void)Trspi_UnloadBlob_PCR_INFO_SHORT(offset, blob, NULL); Trspi_UnloadBlob_TPM_DELEGATIONS(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &pub->tag, blob); Trspi_UnloadBlob_TPM_DELEGATE_LABEL(offset, blob, &pub->label); if ((result = Trspi_UnloadBlob_PCR_INFO_SHORT(offset, blob, &pub->pcrInfo))) return result; Trspi_UnloadBlob_TPM_DELEGATIONS(offset, blob, &pub->permissions); Trspi_UnloadBlob_UINT32(offset, &pub->familyID, blob); Trspi_UnloadBlob_UINT32(offset, &pub->verificationCount, blob); return TSS_SUCCESS; } void Trspi_LoadBlob_TPM_DELEGATE_PUBLIC(UINT64 *offset, BYTE *blob, TPM_DELEGATE_PUBLIC *pub) { Trspi_LoadBlob_UINT16(offset, pub->tag, blob); Trspi_LoadBlob_TPM_DELEGATE_LABEL(offset, blob, &pub->label); Trspi_LoadBlob_PCR_INFO_SHORT(offset, blob, &pub->pcrInfo); Trspi_LoadBlob_TPM_DELEGATIONS(offset, blob, &pub->permissions); Trspi_LoadBlob_UINT32(offset, pub->familyID, blob); Trspi_LoadBlob_UINT32(offset, pub->verificationCount, blob); } TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_OWNER_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_OWNER_BLOB *owner) { TSS_RESULT result; if (!owner) { UINT32 additionalSize, sensitiveSize; Trspi_UnloadBlob_UINT16(offset, NULL, blob); (void)Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &additionalSize, blob); (void)Trspi_UnloadBlob(offset, additionalSize, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &sensitiveSize, blob); (void)Trspi_UnloadBlob(offset, sensitiveSize, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &owner->tag, blob); if ((result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(offset, blob, &owner->pub))) return result; Trspi_UnloadBlob_DIGEST(offset, blob, &owner->integrityDigest); Trspi_UnloadBlob_UINT32(offset, &owner->additionalSize, blob); if (owner->additionalSize > 0) { owner->additionalArea = malloc(owner->additionalSize); if (owner->additionalArea == NULL) { LogError("malloc of %u bytes failed.", owner->additionalSize); free(owner->pub.pcrInfo.pcrSelection.pcrSelect); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, owner->additionalSize, blob, owner->additionalArea); } Trspi_UnloadBlob_UINT32(offset, &owner->sensitiveSize, blob); if (owner->sensitiveSize > 0) { owner->sensitiveArea = malloc(owner->sensitiveSize); if (owner->sensitiveArea == NULL) { LogError("malloc of %u bytes failed.", owner->sensitiveSize); free(owner->pub.pcrInfo.pcrSelection.pcrSelect); free(owner->additionalArea); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, owner->sensitiveSize, blob, owner->sensitiveArea); } return TSS_SUCCESS; } void Trspi_LoadBlob_TPM_DELEGATE_OWNER_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_OWNER_BLOB *owner) { Trspi_LoadBlob_UINT16(offset, owner->tag, blob); Trspi_LoadBlob_TPM_DELEGATE_PUBLIC(offset, blob, &owner->pub); Trspi_LoadBlob_DIGEST(offset, blob, &owner->integrityDigest); Trspi_LoadBlob_UINT32(offset, owner->additionalSize, blob); Trspi_LoadBlob(offset, owner->additionalSize, blob, owner->additionalArea); Trspi_LoadBlob_UINT32(offset, owner->sensitiveSize, blob); Trspi_LoadBlob(offset, owner->sensitiveSize, blob, owner->sensitiveArea); } TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_KEY_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_KEY_BLOB *key) { TSS_RESULT result; if (!key) { UINT32 additionalSize, sensitiveSize; Trspi_UnloadBlob_UINT16(offset, NULL, blob); (void)Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &additionalSize, blob); (void)Trspi_UnloadBlob(offset, additionalSize, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &sensitiveSize, blob); (void)Trspi_UnloadBlob(offset, sensitiveSize, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &key->tag, blob); if ((result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(offset, blob, &key->pub))) return result; Trspi_UnloadBlob_DIGEST(offset, blob, &key->integrityDigest); Trspi_UnloadBlob_DIGEST(offset, blob, &key->pubKeyDigest); Trspi_UnloadBlob_UINT32(offset, &key->additionalSize, blob); if (key->additionalSize > 0) { key->additionalArea = malloc(key->additionalSize); if (key->additionalArea == NULL) { LogError("malloc of %u bytes failed.", key->additionalSize); free(key->pub.pcrInfo.pcrSelection.pcrSelect); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, key->additionalSize, blob, key->additionalArea); } Trspi_UnloadBlob_UINT32(offset, &key->sensitiveSize, blob); if (key->sensitiveSize > 0) { key->sensitiveArea = malloc(key->sensitiveSize); if (key->sensitiveArea == NULL) { LogError("malloc of %u bytes failed.", key->sensitiveSize); free(key->pub.pcrInfo.pcrSelection.pcrSelect); free(key->additionalArea); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, key->sensitiveSize, blob, key->sensitiveArea); } return TSS_SUCCESS; } void Trspi_LoadBlob_TPM_DELEGATE_KEY_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_KEY_BLOB *key) { Trspi_LoadBlob_UINT16(offset, key->tag, blob); Trspi_LoadBlob_TPM_DELEGATE_PUBLIC(offset, blob, &key->pub); Trspi_LoadBlob_DIGEST(offset, blob, &key->integrityDigest); Trspi_LoadBlob_DIGEST(offset, blob, &key->pubKeyDigest); Trspi_LoadBlob_UINT32(offset, key->additionalSize, blob); Trspi_LoadBlob(offset, key->additionalSize, blob, key->additionalArea); Trspi_LoadBlob_UINT32(offset, key->sensitiveSize, blob); Trspi_LoadBlob(offset, key->sensitiveSize, blob, key->sensitiveArea); } void Trspi_UnloadBlob_TSS_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_FAMILY_TABLE_ENTRY *entry) { if (!entry) { Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_BOOL(offset, NULL, blob); Trspi_UnloadBlob_BOOL(offset, NULL, blob); return; } Trspi_UnloadBlob_UINT32(offset, &entry->familyID, blob); Trspi_UnloadBlob_BYTE(offset, &entry->label, blob); Trspi_UnloadBlob_UINT32(offset, &entry->verificationCount, blob); Trspi_UnloadBlob_BOOL(offset, &entry->enabled, blob); Trspi_UnloadBlob_BOOL(offset, &entry->locked, blob); } void Trspi_LoadBlob_TSS_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_FAMILY_TABLE_ENTRY *entry) { Trspi_LoadBlob_UINT32(offset, entry->familyID, blob); Trspi_LoadBlob_BYTE(offset, entry->label, blob); Trspi_LoadBlob_UINT32(offset, entry->verificationCount, blob); Trspi_LoadBlob_BOOL(offset, entry->enabled, blob); Trspi_LoadBlob_BOOL(offset, entry->locked, blob); } TSS_RESULT Trspi_UnloadBlob_TSS_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TSS_PCR_INFO_SHORT *pcr) { if (!pcr) { UINT32 sizeOfSelect, sizeOfDigestAtRelease; Trspi_UnloadBlob_UINT32(offset, &sizeOfSelect, blob); (void)Trspi_UnloadBlob(offset, sizeOfSelect, blob, NULL); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, &sizeOfDigestAtRelease, blob); (void)Trspi_UnloadBlob(offset, sizeOfDigestAtRelease, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &pcr->sizeOfSelect, blob); if (pcr->sizeOfSelect > 0) { pcr->selection = malloc(pcr->sizeOfSelect); if (pcr->selection == NULL) { LogError("malloc of %u bytes failed.", pcr->sizeOfSelect); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, pcr->sizeOfSelect, blob, pcr->selection); } else { pcr->selection = NULL; } Trspi_UnloadBlob_BYTE(offset, &pcr->localityAtRelease, blob); Trspi_UnloadBlob_UINT32(offset, &pcr->sizeOfDigestAtRelease, blob); if (pcr->sizeOfDigestAtRelease > 0) { pcr->digestAtRelease = malloc(pcr->sizeOfDigestAtRelease); if (pcr->digestAtRelease == NULL) { LogError("malloc of %u bytes failed.", pcr->sizeOfDigestAtRelease); free(pcr->selection); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, pcr->sizeOfDigestAtRelease, blob, pcr->digestAtRelease); } else { pcr->digestAtRelease = NULL; } return TSS_SUCCESS; } void Trspi_LoadBlob_TSS_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TSS_PCR_INFO_SHORT *pcr) { Trspi_LoadBlob_UINT32(offset, pcr->sizeOfSelect, blob); Trspi_LoadBlob(offset, pcr->sizeOfSelect, blob, pcr->selection); Trspi_LoadBlob_BYTE(offset, pcr->localityAtRelease, blob); Trspi_LoadBlob_UINT32(offset, pcr->sizeOfDigestAtRelease, blob); Trspi_LoadBlob(offset, pcr->sizeOfDigestAtRelease, blob, pcr->digestAtRelease); } TSS_RESULT Trspi_UnloadBlob_TSS_DELEGATION_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_DELEGATION_TABLE_ENTRY *entry) { TSS_RESULT result; if (!entry) { Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); (void)Trspi_UnloadBlob_TSS_PCR_INFO_SHORT(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &entry->tableIndex, blob); Trspi_UnloadBlob_BYTE(offset, &entry->label, blob); if ((result = Trspi_UnloadBlob_TSS_PCR_INFO_SHORT(offset, blob, &entry->pcrInfo))) return result; Trspi_UnloadBlob_UINT32(offset, &entry->per1, blob); Trspi_UnloadBlob_UINT32(offset, &entry->per2, blob); Trspi_UnloadBlob_UINT32(offset, &entry->familyID, blob); Trspi_UnloadBlob_UINT32(offset, &entry->verificationCount, blob); return TSS_SUCCESS; } void Trspi_LoadBlob_TSS_DELEGATION_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_DELEGATION_TABLE_ENTRY *entry) { Trspi_LoadBlob_UINT32(offset, entry->tableIndex, blob); Trspi_LoadBlob_BYTE(offset, entry->label, blob); Trspi_LoadBlob_TSS_PCR_INFO_SHORT(offset, blob, &entry->pcrInfo); Trspi_LoadBlob_UINT32(offset, entry->per1, blob); Trspi_LoadBlob_UINT32(offset, entry->per2, blob); Trspi_LoadBlob_UINT32(offset, entry->familyID, blob); Trspi_LoadBlob_UINT32(offset, entry->verificationCount, blob); } TSS_RESULT Trspi_UnloadBlob_PCR_COMPOSITE(UINT64 *offset, BYTE *blob, TCPA_PCR_COMPOSITE *out) { TSS_RESULT result; if (!out) { UINT32 valueSize; Trspi_UnloadBlob_PCR_SELECTION(offset, blob, NULL); Trspi_UnloadBlob_UINT32(offset, &valueSize, blob); Trspi_UnloadBlob(offset, valueSize, blob, NULL); return TSS_SUCCESS; } if ((result = Trspi_UnloadBlob_PCR_SELECTION(offset, blob, &out->select))) return result; Trspi_UnloadBlob_UINT32(offset, &out->valueSize, blob); out->pcrValue = malloc(out->valueSize); if (out->pcrValue == NULL) { LogError("malloc of %u bytes failed.", out->valueSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, out->valueSize, blob, (BYTE *)out->pcrValue); return TSS_SUCCESS; } TSS_RESULT Trspi_UnloadBlob_MIGRATIONKEYAUTH(UINT64 *offset, BYTE *blob, TPM_MIGRATIONKEYAUTH *migAuth) { TSS_RESULT result; if (!migAuth) { (void)Trspi_UnloadBlob_PUBKEY(offset, blob, NULL); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_DIGEST(offset, blob, NULL); return TSS_SUCCESS; } if ((result = Trspi_UnloadBlob_PUBKEY(offset, blob, &migAuth->migrationKey))) return result; Trspi_UnloadBlob_UINT16(offset, &migAuth->migrationScheme, blob); Trspi_UnloadBlob_DIGEST(offset, blob, &migAuth->digest); return TSS_SUCCESS; } void Trspi_LoadBlob_MIGRATIONKEYAUTH(UINT64 *offset, BYTE *blob, TPM_MIGRATIONKEYAUTH *migAuth) { Trspi_LoadBlob_PUBKEY(offset, blob, &migAuth->migrationKey); Trspi_LoadBlob_UINT16(offset, migAuth->migrationScheme, blob); Trspi_LoadBlob_DIGEST(offset, blob, &migAuth->digest); } void Trspi_LoadBlob_MSA_COMPOSITE(UINT64 *offset, BYTE *blob, TPM_MSA_COMPOSITE *msaComp) { UINT32 i; Trspi_LoadBlob_UINT32(offset, msaComp->MSAlist, blob); for (i = 0; i < msaComp->MSAlist; i++) Trspi_LoadBlob_DIGEST(offset, blob, &msaComp->migAuthDigest[i]); } void Trspi_LoadBlob_CMK_AUTH(UINT64 *offset, BYTE *blob, TPM_CMK_AUTH *cmkAuth) { Trspi_LoadBlob_DIGEST(offset, blob, &cmkAuth->migrationAuthorityDigest); Trspi_LoadBlob_DIGEST(offset, blob, &cmkAuth->destinationKeyDigest); Trspi_LoadBlob_DIGEST(offset, blob, &cmkAuth->sourceKeyDigest); } TSS_RESULT Trspi_Hash_MSA_COMPOSITE(Trspi_HashCtx *c, TPM_MSA_COMPOSITE *m) { UINT32 i; TPM_DIGEST *digest; TSS_RESULT result; result = Trspi_Hash_UINT32(c, m->MSAlist); digest = m->migAuthDigest; for (i = 0; i < m->MSAlist; i++) { result |= Trspi_Hash_DIGEST(c, digest->digest); digest++; } return result; } TSS_RESULT Trspi_UnloadBlob_TSS_PLATFORM_CLASS(UINT64 *offset, BYTE *blob, TSS_PLATFORM_CLASS *platClass) { if (!platClass){ UINT32 classURISize; Trspi_UnloadBlob_UINT32(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, &classURISize, blob); Trspi_UnloadBlob(offset, classURISize, blob, NULL); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, &platClass->platformClassSimpleIdentifier, blob); Trspi_UnloadBlob_UINT32(offset, &platClass->platformClassURISize, blob); platClass->pPlatformClassURI = malloc(platClass->platformClassURISize); if (platClass->pPlatformClassURI == NULL) { LogError("malloc of %u bytes failed.", platClass->platformClassURISize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, platClass->platformClassURISize, blob, (BYTE *)platClass->pPlatformClassURI); return TSS_SUCCESS; } void Trspi_LoadBlob_CAP_VERSION_INFO(UINT64 *offset, BYTE *blob, TPM_CAP_VERSION_INFO *v) { Trspi_LoadBlob_UINT16(offset, v->tag, blob); Trspi_LoadBlob_TCPA_VERSION(offset, blob, *(TCPA_VERSION *)(&v->version)); Trspi_LoadBlob_UINT16(offset, v->specLevel, blob); Trspi_LoadBlob_BYTE(offset, v->errataRev, blob); Trspi_LoadBlob(offset, sizeof(v->tpmVendorID), blob, v->tpmVendorID); Trspi_LoadBlob_UINT16(offset, v->vendorSpecificSize, blob); Trspi_LoadBlob(offset, v->vendorSpecificSize, blob, v->vendorSpecific); } TSS_RESULT Trspi_UnloadBlob_CAP_VERSION_INFO(UINT64 *offset, BYTE *blob, TPM_CAP_VERSION_INFO *v) { if (!v) { UINT16 vendorSpecificSize; Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_VERSION(offset, blob, NULL); Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob(offset, 4, blob, NULL); Trspi_UnloadBlob_UINT16(offset, &vendorSpecificSize, blob); (*offset) += vendorSpecificSize; return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &v->tag, blob); Trspi_UnloadBlob_VERSION(offset, blob, (TCPA_VERSION *)&v->version); Trspi_UnloadBlob_UINT16(offset, &v->specLevel, blob); Trspi_UnloadBlob_BYTE(offset, &v->errataRev, blob); Trspi_UnloadBlob(offset, sizeof(v->tpmVendorID), blob, v->tpmVendorID); Trspi_UnloadBlob_UINT16(offset, &v->vendorSpecificSize, blob); if (v->vendorSpecificSize > 0) { if ((v->vendorSpecific = malloc(v->vendorSpecificSize)) == NULL) { LogError("malloc of %u bytes failed.", v->vendorSpecificSize); return TSPERR(TSS_E_OUTOFMEMORY); } Trspi_UnloadBlob(offset, v->vendorSpecificSize, blob, v->vendorSpecific); } else { v->vendorSpecific = NULL; } return TSS_SUCCESS; } TSS_RESULT Trspi_UnloadBlob_NV_INDEX(UINT64 *offset, BYTE *blob, TPM_NV_INDEX *v) { if (!v) { Trspi_UnloadBlob_UINT32(offset, NULL, blob); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT32(offset, v, blob); return TSS_SUCCESS; } TSS_RESULT Trspi_UnloadBlob_NV_ATTRIBUTES(UINT64 *offset, BYTE *blob, TPM_NV_ATTRIBUTES *v) { if (!v) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &v->tag, blob); Trspi_UnloadBlob_UINT32(offset, &v->attributes, blob); return TSS_SUCCESS; } TSS_RESULT Trspi_UnloadBlob_NV_DATA_PUBLIC(UINT64 *offset, BYTE *blob, TPM_NV_DATA_PUBLIC *v) { if (!v) { Trspi_UnloadBlob_UINT16(offset, NULL, blob); Trspi_UnloadBlob_NV_INDEX(offset, blob, NULL); Trspi_UnloadBlob_PCR_INFO_SHORT(offset, blob, NULL); Trspi_UnloadBlob_PCR_INFO_SHORT(offset, blob, NULL); Trspi_UnloadBlob_NV_ATTRIBUTES(offset, blob, NULL); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_BYTE(offset, NULL, blob); Trspi_UnloadBlob_UINT32(offset, NULL, blob); return TSS_SUCCESS; } Trspi_UnloadBlob_UINT16(offset, &v->tag, blob); Trspi_UnloadBlob_NV_INDEX(offset, blob, &v->nvIndex); Trspi_UnloadBlob_PCR_INFO_SHORT(offset, blob, &v->pcrInfoRead); Trspi_UnloadBlob_PCR_INFO_SHORT(offset, blob, &v->pcrInfoWrite); Trspi_UnloadBlob_NV_ATTRIBUTES(offset, blob, &v->permission); Trspi_UnloadBlob_BYTE(offset, &v->bReadSTClear, blob); Trspi_UnloadBlob_BYTE(offset, &v->bWriteSTClear, blob); Trspi_UnloadBlob_BYTE(offset, &v->bWriteDefine, blob); Trspi_UnloadBlob_UINT32(offset, &v->dataSize, blob); return TSS_SUCCESS; } trousers-0.3.15/src/include/0000775000175000017510000000000013736475370015174 5ustar deboradeboratrousers-0.3.15/src/include/tcsd.h0000664000175000017510000001253413703757207016303 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _TCSD_H_ #define _TCSD_H_ #include #include "rpc_tcstp.h" /* Platform Class structures */ struct platform_class { unsigned int simpleID; /* Platform specific spec identifier */ unsigned int classURISize; /* Size of the classURI */ char *classURI; /* Specific spec. Can be NULL */ struct platform_class *next; }; /* config structures */ struct tcsd_config { int port; /* port the TCSD will listen on */ unsigned int num_threads; /* max number of threads the TCSD allows simultaneously */ char *system_ps_dir; /* the directory the system PS file sits in */ char *system_ps_file; /* the name of the system PS file */ char *firmware_log_file;/* the name of the firmware PCR event file */ char *kernel_log_file; /* the name of the kernel PCR event file */ unsigned int kernel_pcrs; /* bitmask of PCRs the kernel controls */ unsigned int firmware_pcrs; /* bitmask of PCRs the firmware controls */ char *platform_cred; /* location of the platform credential */ char *conformance_cred; /* location of the conformance credential */ char *endorsement_cred; /* location of the endorsement credential */ int remote_ops[TCSD_MAX_NUM_ORDS]; /* array of ordinals executable by remote hosts */ unsigned int unset; /* bitmask of options which are still unset */ int exclusive_transport; /* allow applications to open exclusive transport sessions with the TPM and enforce their exclusivity (possible DOS issue) */ struct platform_class *host_platform_class; /* Host platform class of this TCS System */ struct platform_class *all_platform_classes; /* List of platform classes of this TCS System */ int disable_ipv4; int disable_ipv6; }; #define TCSD_DEFAULT_CONFIG_FILE ETC_PREFIX "/tcsd.conf" extern char *tcsd_config_file; #define TSS_USER_NAME "tss" #define TSS_GROUP_NAME "tss" #define TCSD_DEFAULT_MAX_THREADS 10 #define TCSD_DEFAULT_SYSTEM_PS_FILE VAR_PREFIX "/lib/tpm/system.data" #define TCSD_DEFAULT_SYSTEM_PS_DIR VAR_PREFIX "/lib/tpm" #define TCSD_DEFAULT_FIRMWARE_LOG_FILE "/sys/kernel/security/tpm0/binary_bios_measurements" #define TCSD_DEFAULT_KERNEL_LOG_FILE "/sys/kernel/security/ima/binary_runtime_measurements" #define TCSD_DEFAULT_FIRMWARE_PCRS 0x00000000 #define TCSD_DEFAULT_KERNEL_PCRS 0x00000000 #define TCSD_DEFAULT_DISABLE_IPV4 0 #define TCSD_DEFAULT_DISABLE_IPV6 0 /* This will change when a system with more than 32 PCR's exists */ #define TCSD_MAX_PCRS 32 /* this is the 2nd param passed to the listen() system call */ #define TCSD_MAX_SOCKETS_QUEUED 50 #define TCSD_TXBUF_SIZE 1024 /* The Available Tcs Platform Classes */ struct tcg_platform_spec { char *name; TPM_PLATFORM_SPECIFIC specNo; char *specURI; }; /* The Specific URI's for the platforms specs on TCG website */ #define TPM_PS_PC_11_URI "https://www.trustedcomputinggroup.org/groups/pc_client/TCG_PCSpecificSpecification_v1_1.pdf" #define TPM_PS_PC_12_URI "https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf" #define TPM_PS_PDA_12_URI "https://www.trustedcomputinggroup.org/specs/mobilephone/tcg-mobile-reference-architecture-1.0.pdf" #define TPM_PS_Server_12_URI "https://www.trustedcomputinggroup.org/specs/Server/TCG_Generic_Server_Specification_v1_0_rev0_8.pdf" #define TPM_PS_Mobile_12_URI "https://www.trustedcomputinggroup.org/specs/mobilephone/tcg-mobile-reference-architecture-1.0.pdf" /* for detecting whether an option has been set */ #define TCSD_OPTION_PORT 0x0001 #define TCSD_OPTION_MAX_THREADS 0x0002 #define TCSD_OPTION_FIRMWARE_PCRS 0x0004 #define TCSD_OPTION_KERNEL_PCRS 0x0008 #define TCSD_OPTION_SYSTEM_PSFILE 0x0010 #define TCSD_OPTION_KERNEL_LOGFILE 0x0020 #define TCSD_OPTION_FIRMWARE_LOGFILE 0x0040 #define TCSD_OPTION_PLATFORM_CRED 0x0080 #define TCSD_OPTION_CONFORMANCE_CRED 0x0100 #define TCSD_OPTION_ENDORSEMENT_CRED 0x0200 #define TCSD_OPTION_REMOTE_OPS 0x0400 #define TCSD_OPTION_EXCLUSIVE_TRANSPORT 0x0800 #define TCSD_OPTION_HOST_PLATFORM_CLASS 0x1000 #define TCSD_OPTION_DISABLE_IPV4 0x2000 #define TCSD_OPTION_DISABLE_IPV6 0x4000 #define TSS_TCP_RPC_MAX_DATA_LEN 1048576 #define TSS_TCP_RPC_BAD_PACKET_TYPE 0x10000000 enum tcsd_config_option_code { opt_port = 1, opt_max_threads, opt_system_ps_file, opt_firmware_log, opt_kernel_log, opt_firmware_pcrs, opt_kernel_pcrs, opt_platform_cred, opt_conformance_cred, opt_endorsement_cred, opt_remote_ops, opt_exclusive_transport, opt_host_platform_class, opt_all_platform_classes, opt_disable_ipv4, opt_disable_ipv6 }; struct tcsd_config_options { char *name; enum tcsd_config_option_code option; }; extern struct tcsd_config tcsd_options; TSS_RESULT conf_file_init(struct tcsd_config *); void conf_file_final(struct tcsd_config *); TSS_RESULT ps_dirs_init(); void tcsd_signal_handler(int); /* threading structures */ struct tcsd_thread_data { int sock; UINT32 context; THREAD_TYPE *thread_id; char *hostname; struct tcsd_comm_data comm; }; struct tcsd_thread_mgr { MUTEX_DECLARE(lock); struct tcsd_thread_data *thread_data; int shutdown; UINT32 num_active_threads; UINT32 max_threads; }; TSS_RESULT tcsd_threads_init(); TSS_RESULT tcsd_threads_final(); TSS_RESULT tcsd_thread_create(int, char *); void *tcsd_thread_run(void *); void thread_signal_init(); #endif trousers-0.3.15/src/include/obj_policy.h0000664000175000017510000001567113663651711017502 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_POLICY_H_ #define _OBJ_POLICY_H_ /* structures */ struct tr_policy_obj { BYTE SecretLifetime; TSS_BOOL SecretSet; UINT32 SecretMode; UINT32 SecretCounter; UINT32 SecretTimeStamp; UINT32 SecretSize; BYTE Secret[20]; UINT32 type; BYTE *popupString; UINT32 popupStringLength; UINT32 hashMode; TSS_ALGORITHM_ID hmacAlg; TSS_ALGORITHM_ID xorAlg; TSS_ALGORITHM_ID takeownerAlg; TSS_ALGORITHM_ID changeauthAlg; #ifdef TSS_BUILD_SEALX TSS_ALGORITHM_ID sealxAlg; #endif PVOID hmacAppData; PVOID xorAppData; PVOID takeownerAppData; PVOID changeauthAppData; #ifdef TSS_BUILD_SEALX PVOID sealxAppData; #endif #ifdef TSS_BUILD_DELEGATION /* The per1 and per2 are only used when creating a delegation. After that, the blob or index is used to retrieve the information */ UINT32 delegationPer1; UINT32 delegationPer2; UINT32 delegationType; TSS_BOOL delegationIndexSet; /* Since 0 is a valid index value */ UINT32 delegationIndex; UINT32 delegationBlobLength; BYTE *delegationBlob; #endif TSS_RESULT (*Tspicb_CallbackHMACAuth)( PVOID lpAppData, TSS_HOBJECT hAuthorizedObject, TSS_BOOL ReturnOrVerify, UINT32 ulPendingFunction, TSS_BOOL ContinueUse, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulSizeDigestHmac, BYTE *rgbParamDigest, BYTE *rgbHmacData); TSS_RESULT (*Tspicb_CallbackXorEnc)( PVOID lpAppData, TSS_HOBJECT hOSAPObject, TSS_HOBJECT hObject, TSS_FLAG PurposeSecret, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulSizeEncAuth, BYTE *rgbEncAuthUsage, BYTE *rgbEncAuthMigration); TSS_RESULT (*Tspicb_CallbackTakeOwnership)( PVOID lpAppData, TSS_HOBJECT hObject, TSS_HKEY hObjectPubKey, UINT32 ulSizeEncAuth, BYTE *rgbEncAuth); TSS_RESULT (*Tspicb_CallbackChangeAuthAsym)( PVOID lpAppData, TSS_HOBJECT hObject, TSS_HKEY hObjectPubKey, UINT32 ulSizeEncAuth, UINT32 ulSizeAithLink, BYTE *rgbEncAuth, BYTE *rgbAuthLink); #ifdef TSS_BUILD_SEALX TSS_RESULT (*Tspicb_CallbackSealxMask)( PVOID lpAppData, TSS_HKEY hKey, TSS_HENCDATA hEncData, TSS_ALGORITHM_ID algID, UINT32 ulSizeNonces, BYTE *rgbNonceEven, BYTE *rgbNonceOdd, BYTE *rgbNonceEvenOSAP, BYTE *rgbNonceOddOSAP, UINT32 ulDataLength, BYTE *rgbDataToMask, BYTE *rgbMaskedData); #endif }; /* obj_policy.c */ void __tspi_policy_free(void *data); TSS_BOOL anyPopupPolicies(TSS_HCONTEXT); TSS_BOOL obj_is_policy(TSS_HOBJECT); TSS_RESULT obj_policy_get_tsp_context(TSS_HPOLICY, TSS_HCONTEXT *); /* One of these 2 flags should be passed to obj_policy_get_secret so that if a popup must * be executed to get the secret, we know whether or not the new dialog should be displayed, * which will ask for confirmation */ #define TR_SECRET_CTX_NEW TRUE #define TR_SECRET_CTX_NOT_NEW FALSE TSS_RESULT obj_policy_get_secret(TSS_HPOLICY, TSS_BOOL, TCPA_SECRET *); TSS_RESULT obj_policy_flush_secret(TSS_HPOLICY); TSS_RESULT obj_policy_set_secret_object(TSS_HPOLICY, TSS_FLAG, UINT32, TCPA_DIGEST *, TSS_BOOL); TSS_RESULT obj_policy_set_secret(TSS_HPOLICY, TSS_FLAG, UINT32, BYTE *); TSS_RESULT obj_policy_get_type(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_remove(TSS_HOBJECT, TSS_HCONTEXT); TSS_RESULT obj_policy_add(TSS_HCONTEXT, UINT32, TSS_HOBJECT *); TSS_RESULT obj_policy_set_type(TSS_HPOLICY, UINT32); TSS_RESULT obj_policy_set_cb12(TSS_HPOLICY, TSS_FLAG, BYTE *); TSS_RESULT obj_policy_get_cb12(TSS_HPOLICY, TSS_FLAG, UINT32 *, BYTE **); TSS_RESULT obj_policy_set_cb11(TSS_HPOLICY, TSS_FLAG, TSS_FLAG, UINT32); TSS_RESULT obj_policy_get_cb11(TSS_HPOLICY, TSS_FLAG, UINT32 *); TSS_RESULT obj_policy_get_lifetime(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_set_lifetime(TSS_HPOLICY, UINT32, UINT32); TSS_RESULT obj_policy_get_counter(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_get_string(TSS_HPOLICY, UINT32 *size, BYTE **); TSS_RESULT obj_policy_set_string(TSS_HPOLICY, UINT32 size, BYTE *); TSS_RESULT obj_policy_get_secs_until_expired(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_has_expired(TSS_HPOLICY, TSS_BOOL *); TSS_RESULT obj_policy_get_mode(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_dec_counter(TSS_HPOLICY); TSS_RESULT obj_policy_do_hmac(TSS_HPOLICY, TSS_HOBJECT, TSS_BOOL, UINT32, TSS_BOOL, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *); TSS_RESULT obj_policy_do_xor(TSS_HPOLICY, TSS_HOBJECT, TSS_HOBJECT, TSS_FLAG, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *); TSS_RESULT obj_policy_do_takeowner(TSS_HPOLICY, TSS_HOBJECT, TSS_HKEY, UINT32, BYTE *); TSS_RESULT obj_policy_validate_auth_oiap(TSS_HPOLICY, TCPA_DIGEST *, TPM_AUTH *); TSS_RESULT obj_policy_get_hash_mode(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_set_hash_mode(TSS_HPOLICY, UINT32); TSS_RESULT obj_policy_get_xsap_params(TSS_HPOLICY, TPM_COMMAND_CODE, TPM_ENTITY_TYPE *, UINT32 *, BYTE **, BYTE *, TSS_CALLBACK *, TSS_CALLBACK *, TSS_CALLBACK *, UINT32 *, TSS_BOOL); TSS_RESULT obj_policy_is_secret_set(TSS_HPOLICY, TSS_BOOL *); #ifdef TSS_BUILD_DELEGATION TSS_RESULT obj_policy_set_delegation_type(TSS_HPOLICY, UINT32); TSS_RESULT obj_policy_get_delegation_type(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_set_delegation_index(TSS_HPOLICY, UINT32); TSS_RESULT obj_policy_get_delegation_index(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_set_delegation_per1(TSS_HPOLICY, UINT32); TSS_RESULT obj_policy_get_delegation_per1(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_set_delegation_per2(TSS_HPOLICY, UINT32); TSS_RESULT obj_policy_get_delegation_per2(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_set_delegation_blob(TSS_HPOLICY, UINT32, UINT32, BYTE *); TSS_RESULT obj_policy_get_delegation_blob(TSS_HPOLICY, UINT32, UINT32 *, BYTE **); TSS_RESULT obj_policy_get_delegation_label(TSS_HPOLICY, BYTE *); TSS_RESULT obj_policy_get_delegation_familyid(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_get_delegation_vercount(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_get_delegation_pcr_locality(TSS_HPOLICY, UINT32 *); TSS_RESULT obj_policy_get_delegation_pcr_digest(TSS_HPOLICY, UINT32 *, BYTE **); TSS_RESULT obj_policy_get_delegation_pcr_selection(TSS_HPOLICY, UINT32 *, BYTE **); TSS_RESULT obj_policy_is_delegation_index_set(TSS_HPOLICY, TSS_BOOL *); void obj_policy_clear_delegation(struct tr_policy_obj *); TSS_RESULT obj_policy_get_delegate_public(struct tsp_object *, TPM_DELEGATE_PUBLIC *); #endif #define POLICY_LIST_DECLARE struct obj_list policy_list #define POLICY_LIST_DECLARE_EXTERN extern struct obj_list policy_list #define POLICY_LIST_INIT() tspi_list_init(&policy_list) #define POLICY_LIST_CONNECT(a,b) obj_connectContext_list(&policy_list, a, b) #define POLICY_LIST_CLOSE(a) obj_list_close(&policy_list, &__tspi_policy_free, a) #endif trousers-0.3.15/src/include/tsp_delegate.h0000664000175000017510000000147113663651711020002 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #ifndef _TSP_DELEGATE_H_ #define _TSP_DELEGATE_H_ TSS_RESULT do_delegate_manage(TSS_HTPM hTpm, UINT32 familyID, UINT32 opFlag, UINT32 opDataSize, BYTE *opData, UINT32 *outDataSize, BYTE **outData); TSS_RESULT create_key_delegation(TSS_HKEY, BYTE, UINT32, TSS_HPCRS, TSS_HDELFAMILY, TSS_HPOLICY); TSS_RESULT create_owner_delegation(TSS_HTPM, BYTE, UINT32, TSS_HPCRS, TSS_HDELFAMILY, TSS_HPOLICY); TSS_RESULT update_delfamily_object(TSS_HTPM, UINT32); TSS_RESULT get_delegate_index(TSS_HCONTEXT, UINT32, TPM_DELEGATE_PUBLIC *); TSS_RESULT __tspi_build_delegate_public_info(BYTE, TSS_HPCRS, TSS_HDELFAMILY, TSS_HPOLICY, UINT32 *, BYTE **); #endif trousers-0.3.15/src/include/Makefile.am0000664000175000017510000000254413663651711017227 0ustar deboradeboratssincludedir = $(includedir)/tss trousersincludedir = $(includedir)/trousers tssinclude_HEADERS = tss/tcpa_error.h \ tss/tcs_error.h \ tss/tcs_defines.h \ tss/tcs.h \ tss/tddlapi_error.h \ tss/tspi.h \ tss/tss_error.h \ tss/platform.h \ tss/tcpa_struct.h \ tss/tcs_structs.h \ tss/tddl_error.h \ tss/tss_defines.h \ tss/tss_structs.h \ tss/tcpa_defines.h \ tss/tcpa_typedef.h \ tss/tcs_typedef.h \ tss/tddli.h \ tss/tss_error_basics.h \ tss/tss_typedef.h \ tss/compat11b.h \ tss/tpm.h \ tss/tpm_error.h \ tss/tpm_ordinal.h trousersinclude_HEADERS = trousers/tss.h trousers/trousers.h noinst_HEADERS = auth_mgr.h authsess.h biosem.h capabilities.h \ hosttable.h imaem.h memmgr.h obj_context.h \ obj_daaarakey.h obj_daacred.h obj_daa.h \ obj_daaissuerkey.h obj_delfamily.h obj_encdata.h \ obj.h obj_hash.h obj_migdata.h obj_nv.h \ obj_pcrs.h obj_policy.h obj_rsakey.h \ obj_tpm.h req_mgr.h rpc_tcstp.h rpc_tcstp_tcs.h \ rpc_tcstp_tsp.h spi_utils.h tcs_aik.h \ tcs_context.h tcsd.h tcsd_ops.h tcsd_wrap.h \ tcsem.h tcs_int_literals.h tcs_key_ps.h \ tcslog.h tcsps.h tcs_tsp.h tcs_utils.h \ tddl.h threads.h trousers_types.h tsp_audit.h \ tsp_delegate.h tsplog.h tspps.h tsp_seal.h \ linux/tpm.h tsp_tcsi_param.h trousers-0.3.15/src/include/tcsps.h0000664000175000017510000000554613663651711016505 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _TCSPS_H_ #define _TCSPS_H_ #include "threads.h" extern struct key_disk_cache *key_disk_cache_head; /* file handles for the persistent stores */ extern int system_ps_fd; /* The lock that surrounds all manipulations of the disk cache */ MUTEX_DECLARE_EXTERN(disk_cache_lock); int get_file(); int put_file(int); void close_file(int); void ps_destroy(); TSS_RESULT read_data(int, void *, UINT32); TSS_RESULT write_data(int, void *, UINT32); int write_key_init(int, UINT32, UINT32, UINT32); TSS_RESULT cache_key(UINT32, UINT16, TSS_UUID *, TSS_UUID *, UINT16, UINT32, UINT32); TSS_RESULT UnloadBlob_KEY_PS(UINT16 *, BYTE *, TSS_KEY *); TSS_RESULT psfile_get_parent_uuid_by_uuid(int, TSS_UUID *, TSS_UUID *); TSS_RESULT psfile_remove_key_by_uuid(int, TSS_UUID *); TSS_RESULT psfile_get_key_by_uuid(int, TSS_UUID *, BYTE *, UINT16 *); TSS_RESULT psfile_get_key_by_cache_entry(int, struct key_disk_cache *, BYTE *, UINT16 *); TSS_RESULT psfile_get_ps_type_by_uuid(int, TSS_UUID *, UINT32 *); TSS_RESULT psfile_get_vendor_data(int, struct key_disk_cache *, UINT32 *, BYTE **); TSS_RESULT psfile_is_pub_registered(int, TCPA_STORE_PUBKEY *, TSS_BOOL *); TSS_RESULT psfile_get_uuid_by_pub(int, TCPA_STORE_PUBKEY *, TSS_UUID **); TSS_RESULT psfile_write_key(int, TSS_UUID *, TSS_UUID *, UINT32 *, BYTE *, UINT32, BYTE *, UINT16); TSS_RESULT psfile_remove_key(int, struct key_disk_cache *); TCPA_STORE_PUBKEY *psfile_get_pub_by_tpm_handle(int, TCPA_KEY_HANDLE); TSS_RESULT psfile_get_tpm_handle_by_pub(int, TCPA_STORE_PUBKEY *, TCPA_KEY_HANDLE *); TSS_RESULT psfile_get_tcs_handle_by_pub(int, TCPA_STORE_PUBKEY *, TCS_KEY_HANDLE *); TSS_RESULT psfile_get_parent_tcs_handle_by_pub(int, TCPA_STORE_PUBKEY *, TCS_KEY_HANDLE *); TCPA_STORE_PUBKEY *psfile_get_pub_by_tcs_handle(int, TCS_KEY_HANDLE); TSS_RESULT psfile_get_key_by_pub(int, TCPA_STORE_PUBKEY *, UINT32 *, BYTE **); TSS_RESULT ps_remove_key(TSS_UUID *); int init_disk_cache(int); int close_disk_cache(int); TSS_RESULT clean_disk_cache(int); TSS_RESULT ps_write_key(TSS_UUID *, TSS_UUID *, BYTE *, UINT32, BYTE *, UINT32); TSS_RESULT ps_get_key_by_uuid(TSS_UUID *, BYTE *, UINT16 *); TSS_RESULT ps_get_key_by_cache_entry(struct key_disk_cache *, BYTE *, UINT16 *); TSS_RESULT ps_get_vendor_data(struct key_disk_cache *, UINT32 *, BYTE **); TSS_RESULT ps_init_disk_cache(); void ps_close_disk_cache(); TSS_RESULT ps_get_key_by_pub(TCPA_STORE_PUBKEY *, UINT32 *, BYTE **); #ifdef TSS_BUILD_PS #define PS_init_disk_cache() ps_init_disk_cache() #define PS_close_disk_cache() ps_close_disk_cache() #else #define PS_init_disk_cache() (TSS_SUCCESS) #define PS_close_disk_cache() #endif #endif trousers-0.3.15/src/include/portable_endian.h0000664000175000017510000000515013663651711020466 0ustar deboradebora// "License": Public Domain // I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. #ifndef PORTABLE_ENDIAN_H__ #define PORTABLE_ENDIAN_H__ #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) # define __WINDOWS__ #endif #if defined(__linux__) || defined(__CYGWIN__) # include #elif defined(__APPLE__) # include # define htobe16(x) OSSwapHostToBigInt16(x) # define htole16(x) OSSwapHostToLittleInt16(x) # define be16toh(x) OSSwapBigToHostInt16(x) # define le16toh(x) OSSwapLittleToHostInt16(x) # define htobe32(x) OSSwapHostToBigInt32(x) # define htole32(x) OSSwapHostToLittleInt32(x) # define be32toh(x) OSSwapBigToHostInt32(x) # define le32toh(x) OSSwapLittleToHostInt32(x) # define htobe64(x) OSSwapHostToBigInt64(x) # define htole64(x) OSSwapHostToLittleInt64(x) # define be64toh(x) OSSwapBigToHostInt64(x) # define le64toh(x) OSSwapLittleToHostInt64(x) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # define __PDP_ENDIAN PDP_ENDIAN #elif defined(__OpenBSD__) # include #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) # include # define be16toh(x) betoh16(x) # define le16toh(x) letoh16(x) # define be32toh(x) betoh32(x) # define le32toh(x) letoh32(x) # define be64toh(x) betoh64(x) # define le64toh(x) letoh64(x) #elif defined(__WINDOWS__) # include # include # if BYTE_ORDER == LITTLE_ENDIAN # define htobe16(x) htons(x) # define htole16(x) (x) # define be16toh(x) ntohs(x) # define le16toh(x) (x) # define htobe32(x) htonl(x) # define htole32(x) (x) # define be32toh(x) ntohl(x) # define le32toh(x) (x) # define htobe64(x) htonll(x) # define htole64(x) (x) # define be64toh(x) ntohll(x) # define le64toh(x) (x) # elif BYTE_ORDER == BIG_ENDIAN /* that would be xbox 360 */ # define htobe16(x) (x) # define htole16(x) __builtin_bswap16(x) # define be16toh(x) (x) # define le16toh(x) __builtin_bswap16(x) # define htobe32(x) (x) # define htole32(x) __builtin_bswap32(x) # define be32toh(x) (x) # define le32toh(x) __builtin_bswap32(x) # define htobe64(x) (x) # define htole64(x) __builtin_bswap64(x) # define be64toh(x) (x) # define le64toh(x) __builtin_bswap64(x) # else # error byte order not supported # endif # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # define __PDP_ENDIAN PDP_ENDIAN #else # error platform not supported #endif #endif trousers-0.3.15/src/include/tcs_key_ps.h0000664000175000017510000000174213663651711017506 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #ifndef _TCS_KEY_PS_H_ #define _TCS_KEY_PS_H_ TSS_RESULT ps_init_disk_cache(); void ps_close_disk_cache(); TSS_BOOL ps_is_key_registered(TCPA_STORE_PUBKEY *); TSS_RESULT getParentUUIDByUUID(TSS_UUID *, TSS_UUID *); TSS_RESULT isUUIDRegistered(TSS_UUID *, TSS_BOOL *); void disk_cache_shift(struct key_disk_cache *); TSS_RESULT ps_remove_key(TSS_UUID *); TSS_RESULT clean_disk_cache(int); TSS_RESULT ps_get_key_by_uuid(TSS_UUID *, BYTE *, UINT16 *); TSS_RESULT ps_get_key_by_cache_entry(struct key_disk_cache *, BYTE *, UINT16 *); TSS_RESULT ps_is_pub_registered(TCPA_STORE_PUBKEY *); TSS_RESULT ps_get_uuid_by_pub(TCPA_STORE_PUBKEY *, TSS_UUID **); TSS_RESULT ps_get_key_by_pub(TCPA_STORE_PUBKEY *, UINT32 *, BYTE **); TSS_RESULT ps_write_key(TSS_UUID *, TSS_UUID *, BYTE *, UINT32, BYTE *, UINT32); #endif trousers-0.3.15/src/include/rpc_tcstp_tsp.h0000664000175000017510000005641013663651711020234 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _RPC_TCSTP_TSP_H_ #define _RPC_TCSTP_TSP_H_ #include "hosttable.h" #include "rpc_tcstp.h" #include "tcsd_wrap.h" #include "tcsd.h" int setData(TCSD_PACKET_TYPE,int,void *,int,struct tcsd_comm_data *); UINT32 getData(TCSD_PACKET_TYPE,int,void *,int,struct tcsd_comm_data *); void initData(struct tcsd_comm_data *, int); TSS_RESULT sendTCSDPacket(struct host_table_entry *); TSS_RESULT send_init(struct host_table_entry *); TSS_RESULT tcs_sendit(struct host_table_entry *); /* Underlying socket-related calls */ TSS_RESULT get_socket(struct host_table_entry *hte, int *sd); /* Context commands always included */ TSS_RESULT RPC_OpenContext_TP(struct host_table_entry *, UINT32 *, TCS_CONTEXT_HANDLE *); TSS_RESULT RPC_CloseContext_TP(struct host_table_entry *); TSS_RESULT RPC_FreeMemory_TP(struct host_table_entry *,BYTE *); #ifdef TSS_BUILD_AUTH TSS_RESULT RPC_OIAP_TP(struct host_table_entry *,TCS_AUTHHANDLE *,TCPA_NONCE *); TSS_RESULT RPC_OSAP_TP(struct host_table_entry *,TCPA_ENTITY_TYPE,UINT32,TCPA_NONCE*,TCS_AUTHHANDLE *,TCPA_NONCE *,TCPA_NONCE *); #else #define RPC_OIAP_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_OSAP_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_PCR_EVENTS TSS_RESULT RPC_LogPcrEvent_TP(struct host_table_entry *,TSS_PCR_EVENT,UINT32 *); TSS_RESULT RPC_GetPcrEvent_TP(struct host_table_entry *,UINT32,UINT32 *,TSS_PCR_EVENT **); TSS_RESULT RPC_GetPcrEventLog_TP(struct host_table_entry *,UINT32 *,TSS_PCR_EVENT **); TSS_RESULT RPC_GetPcrEventsByPcr_TP(struct host_table_entry *,UINT32,UINT32,UINT32 *,TSS_PCR_EVENT **); #else #define RPC_LogPcrEvent_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetPcrEvent_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetPcrEventLog_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetPcrEventsByPcr_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_PS TSS_RESULT RPC_GetRegisteredKeyByPublicInfo_TP(struct host_table_entry * tcsContext,TCPA_ALGORITHM_ID algID,UINT32,BYTE *,UINT32 *,BYTE **); TSS_RESULT RPC_RegisterKey_TP(struct host_table_entry *,TSS_UUID,TSS_UUID,UINT32,BYTE *,UINT32,BYTE *); TSS_RESULT RPC_UnregisterKey_TP(struct host_table_entry *,TSS_UUID); TSS_RESULT RPC_EnumRegisteredKeys_TP(struct host_table_entry *,TSS_UUID *,UINT32 *,TSS_KM_KEYINFO **); TSS_RESULT RPC_EnumRegisteredKeys2_TP(struct host_table_entry *,TSS_UUID *,UINT32 *,TSS_KM_KEYINFO2 **); TSS_RESULT RPC_GetRegisteredKey_TP(struct host_table_entry *,TSS_UUID,TSS_KM_KEYINFO **); TSS_RESULT RPC_GetRegisteredKeyBlob_TP(struct host_table_entry *,TSS_UUID,UINT32 *,BYTE **); TSS_RESULT RPC_LoadKeyByUUID_TP(struct host_table_entry *,TSS_UUID,TCS_LOADKEY_INFO *,TCS_KEY_HANDLE *); #else #define RPC_GetRegisteredKeyByPublicInfo_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_RegisterKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_UnregisterKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_EnumRegisteredKeys_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_EnumRegisteredKeys2_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetRegisteredKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetRegisteredKeyBlob_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_LoadKeyByUUID_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_KEY TSS_RESULT RPC_LoadKeyByBlob_TP(struct host_table_entry *,TCS_KEY_HANDLE,UINT32,BYTE *,TPM_AUTH *,TCS_KEY_HANDLE *,TCS_KEY_HANDLE *); TSS_RESULT RPC_EvictKey_TP(struct host_table_entry *,TCS_KEY_HANDLE); TSS_RESULT RPC_CreateWrapKey_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_ENCAUTH *,TCPA_ENCAUTH *,UINT32,BYTE *,UINT32 *,BYTE **,TPM_AUTH *); TSS_RESULT RPC_GetPubKey_TP(struct host_table_entry *,TCS_KEY_HANDLE,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_TerminateHandle_TP(struct host_table_entry *,TCS_AUTHHANDLE); TSS_RESULT RPC_OwnerReadInternalPub_TP(struct host_table_entry *, TCS_KEY_HANDLE, TPM_AUTH *, UINT32 *, BYTE **); #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_KeyControlOwner_TP(struct host_table_entry *, TCS_KEY_HANDLE, UINT32, BYTE *, UINT32, TSS_BOOL, TPM_AUTH *, TSS_UUID *); #else #define RPC_KeyControlOwner_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #else #define RPC_LoadKeyByBlob_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_EvictKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CreateWrapKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetPubKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_TerminateHandle_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_OwnerReadInternalPub_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_KeyControlOwner_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_AIK TSS_RESULT RPC_MakeIdentity_TP(struct host_table_entry *,TCPA_ENCAUTH,TCPA_CHOSENID_HASH,UINT32,BYTE *,TPM_AUTH *,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **,UINT32 *,BYTE **,UINT32 *,BYTE **,UINT32 *,BYTE **); TSS_RESULT RPC_GetCredential_TP(struct host_table_entry *,UINT32 ,UINT32 ,UINT32 *,BYTE **); TSS_RESULT RPC_ActivateTPMIdentity_TP(struct host_table_entry *,TCS_KEY_HANDLE,UINT32,BYTE *,TPM_AUTH *,TPM_AUTH *,UINT32 *,BYTE **); #else #define RPC_MakeIdentity_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetCredential_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ActivateTPMIdentity_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_ADMIN TSS_RESULT RPC_SetOwnerInstall_TP(struct host_table_entry *,TSS_BOOL); TSS_RESULT RPC_DisableOwnerClear_TP(struct host_table_entry *,TPM_AUTH *); TSS_RESULT RPC_ForceClear_TP(struct host_table_entry * hContext); TSS_RESULT RPC_DisableForceClear_TP(struct host_table_entry * hContext); TSS_RESULT RPC_PhysicalDisable_TP(struct host_table_entry * hContext); TSS_RESULT RPC_PhysicalEnable_TP(struct host_table_entry * hContext); TSS_RESULT RPC_PhysicalSetDeactivated_TP(struct host_table_entry *,TSS_BOOL); TSS_RESULT RPC_PhysicalPresence_TP(struct host_table_entry *,TCPA_PHYSICAL_PRESENCE); TSS_RESULT RPC_SetTempDeactivated_TP(struct host_table_entry * hContext); #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_SetTempDeactivated2_TP(struct host_table_entry *, TPM_AUTH *); #else #define RPC_SetTempDeactivated2_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif TSS_RESULT RPC_FieldUpgrade_TP(struct host_table_entry *,UINT32,BYTE *,UINT32 *,BYTE **,TPM_AUTH *); TSS_RESULT RPC_SetRedirection_TP(struct host_table_entry *,TCS_KEY_HANDLE,UINT32,UINT32,TPM_AUTH *); TSS_RESULT RPC_OwnerSetDisable_TP(struct host_table_entry *,TSS_BOOL,TPM_AUTH *); TSS_RESULT RPC_ResetLockValue_TP(struct host_table_entry *, TPM_AUTH *); #else #define RPC_SetOwnerInstall_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_DisableOwnerClear_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ForceClear_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_DisableForceClear_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_PhysicalDisable_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_PhysicalEnable_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_PhysicalSetDeactivated_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_PhysicalPresence_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_SetTempDeactivated_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_SetTempDeactivated2_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_FieldUpgrade_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_SetRedirection_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_OwnerSetDisable_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ResetLockValue_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_OWN TSS_RESULT RPC_TakeOwnership_TP(struct host_table_entry *,UINT16,UINT32,BYTE *,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_OwnerClear_TP(struct host_table_entry *,TPM_AUTH *); #else #define RPC_TakeOwnership_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_OwnerClear_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_CHANGEAUTH TSS_RESULT RPC_ChangeAuth_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_PROTOCOL_ID,TCPA_ENCAUTH *,TCPA_ENTITY_TYPE,UINT32,BYTE *,TPM_AUTH *,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_ChangeAuthOwner_TP(struct host_table_entry *,TCPA_PROTOCOL_ID,TCPA_ENCAUTH *,TCPA_ENTITY_TYPE,TPM_AUTH *); TSS_RESULT RPC_ChangeAuthAsymStart_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_NONCE,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **,UINT32 *,BYTE **,TCS_KEY_HANDLE *); TSS_RESULT RPC_ChangeAuthAsymFinish_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCS_KEY_HANDLE,TCPA_ENTITY_TYPE,TCPA_HMAC,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **,TCPA_SALT_NONCE *,TCPA_DIGEST *); #else #define RPC_ChangeAuth_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ChangeAuthOwner_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ChangeAuthAsymStart_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ChangeAuthAsymFinish_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_PCR_EXTEND TSS_RESULT RPC_Extend_TP(struct host_table_entry *,TCPA_PCRINDEX,TCPA_DIGEST,TCPA_PCRVALUE *); TSS_RESULT RPC_PcrRead_TP(struct host_table_entry *,TCPA_PCRINDEX,TCPA_PCRVALUE *); TSS_RESULT RPC_PcrReset_TP(struct host_table_entry *,UINT32,BYTE *); #else #define RPC_Extend_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_PcrRead_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_PcrReset_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_QUOTE TSS_RESULT RPC_Quote_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_NONCE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **); #else #define RPC_Quote_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_QUOTE2 TSS_RESULT RPC_Quote2_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_NONCE *,UINT32,BYTE *,TSS_BOOL,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **,UINT32 *,BYTE **); #else #define RPC_Quote2_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_DIR TSS_RESULT RPC_DirWriteAuth_TP(struct host_table_entry *,TCPA_DIRINDEX,TCPA_DIRVALUE *,TPM_AUTH *); TSS_RESULT RPC_DirRead_TP(struct host_table_entry *,TCPA_DIRINDEX,TCPA_DIRVALUE *); #else #define RPC_DirWriteAuth_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_DirRead_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_SEAL TSS_RESULT RPC_Seal_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_ENCAUTH *,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_Unseal_TP(struct host_table_entry *,TCS_KEY_HANDLE,UINT32,BYTE *,TPM_AUTH *,TPM_AUTH *,UINT32 *,BYTE **); #else #define RPC_Seal_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_Unseal_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_SEALX TSS_RESULT RPC_Sealx_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_ENCAUTH *,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); #else #define RPC_Sealx_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_BIND TSS_RESULT RPC_UnBind_TP(struct host_table_entry *,TCS_KEY_HANDLE,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); #else #define RPC_UnBind_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_MIGRATION TSS_RESULT RPC_CreateMigrationBlob_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_MIGRATE_SCHEME,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **); TSS_RESULT RPC_ConvertMigrationBlob_TP(struct host_table_entry *,TCS_KEY_HANDLE,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_AuthorizeMigrationKey_TP(struct host_table_entry *,TCPA_MIGRATE_SCHEME,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); #else #define RPC_CreateMigrationBlob_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ConvertMigrationBlob_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_AuthorizeMigrationKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_CERTIFY TSS_RESULT RPC_CertifyKey_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCS_KEY_HANDLE,TPM_NONCE *,TPM_AUTH *,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **); #else #define RPC_CertifyKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_SIGN TSS_RESULT RPC_Sign_TP(struct host_table_entry *,TCS_KEY_HANDLE,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); #else #define RPC_Sign_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_RANDOM TSS_RESULT RPC_GetRandom_TP(struct host_table_entry *,UINT32,BYTE **); TSS_RESULT RPC_StirRandom_TP(struct host_table_entry *,UINT32,BYTE *); #else #define RPC_GetRandom_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_StirRandom_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_CAPS_TPM TSS_RESULT RPC_GetTPMCapability_TP(struct host_table_entry *,TCPA_CAPABILITY_AREA,UINT32,BYTE *,UINT32 *,BYTE **); TSS_RESULT RPC_GetCapabilitySigned_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_NONCE,TCPA_CAPABILITY_AREA,UINT32,BYTE *,TPM_AUTH *,TCPA_VERSION *,UINT32 *,BYTE **,UINT32 *,BYTE **); TSS_RESULT RPC_GetCapabilityOwner_TP(struct host_table_entry *,TPM_AUTH *,TCPA_VERSION *,UINT32 *,UINT32 *); TSS_RESULT RPC_SetCapability_TP(struct host_table_entry *,TCPA_CAPABILITY_AREA,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *); #else #define RPC_GetTPMCapability_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetCapabilitySigned_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetCapabilityOwner_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_SetCapability_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_CAPS TSS_RESULT RPC_GetCapability_TP(struct host_table_entry *,TCPA_CAPABILITY_AREA,UINT32,BYTE *,UINT32 *,BYTE **); #else #define RPC_GetCapability_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_EK TSS_RESULT RPC_CreateEndorsementKeyPair_TP(struct host_table_entry *,TCPA_NONCE,UINT32,BYTE *,UINT32 *,BYTE **,TCPA_DIGEST *); TSS_RESULT RPC_ReadPubek_TP(struct host_table_entry *,TCPA_NONCE,UINT32 *,BYTE **,TCPA_DIGEST *); TSS_RESULT RPC_OwnerReadPubek_TP(struct host_table_entry *,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_DisablePubekRead_TP(struct host_table_entry *,TPM_AUTH *); #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_CreateRevocableEndorsementKeyPair_TP(struct host_table_entry *,TPM_NONCE,UINT32,BYTE *,TSS_BOOL,TPM_DIGEST *,UINT32 *,BYTE **,TPM_DIGEST *); TSS_RESULT RPC_RevokeEndorsementKeyPair_TP(struct host_table_entry *,TPM_DIGEST *); #else #define RPC_CreateRevocableEndorsementKeyPair_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_RevokeEndorsementKeyPair_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #else #define RPC_DisablePubekRead_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CreateEndorsementKeyPair_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ReadPubek_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_OwnerReadPubek_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CreateRevocableEndorsementKeyPair_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_RevokeEndorsementKeyPair_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_SELFTEST TSS_RESULT RPC_SelfTestFull_TP(struct host_table_entry * hContext); TSS_RESULT RPC_CertifySelfTest_TP(struct host_table_entry *,TCS_KEY_HANDLE,TCPA_NONCE,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_GetTestResult_TP(struct host_table_entry *,UINT32 *,BYTE **); #else #define RPC_SelfTestFull_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CertifySelfTest_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetTestResult_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_MAINT TSS_RESULT RPC_CreateMaintenanceArchive_TP(struct host_table_entry *,TSS_BOOL,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **); TSS_RESULT RPC_LoadMaintenanceArchive_TP(struct host_table_entry *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_KillMaintenanceFeature_TP(struct host_table_entry *,TPM_AUTH *); TSS_RESULT RPC_LoadManuMaintPub_TP(struct host_table_entry *,TCPA_NONCE,UINT32,BYTE *,TCPA_DIGEST *); TSS_RESULT RPC_ReadManuMaintPub_TP(struct host_table_entry *,TCPA_NONCE,TCPA_DIGEST *); #else #define RPC_CreateMaintenanceArchive_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_LoadMaintenanceArchive_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_KillMaintenanceFeature_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_LoadManuMaintPub_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ReadManuMaintPub_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_DAA TSS_RESULT RPC_DaaJoin_TP(struct host_table_entry *,TPM_HANDLE,BYTE,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); TSS_RESULT RPC_DaaSign_TP(struct host_table_entry *,TPM_HANDLE,BYTE,UINT32,BYTE *,UINT32,BYTE *,TPM_AUTH *,UINT32 *,BYTE **); #else #define RPC_DaaJoin_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_DaaSign_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_COUNTER TSS_RESULT RPC_ReadCounter_TP(struct host_table_entry *,TSS_COUNTER_ID,TPM_COUNTER_VALUE *); TSS_RESULT RPC_CreateCounter_TP(struct host_table_entry *,UINT32,BYTE *,TPM_ENCAUTH,TPM_AUTH *,TSS_COUNTER_ID *,TPM_COUNTER_VALUE *); TSS_RESULT RPC_IncrementCounter_TP(struct host_table_entry *,TSS_COUNTER_ID,TPM_AUTH *,TPM_COUNTER_VALUE *); TSS_RESULT RPC_ReleaseCounter_TP(struct host_table_entry *,TSS_COUNTER_ID,TPM_AUTH *); TSS_RESULT RPC_ReleaseCounterOwner_TP(struct host_table_entry *,TSS_COUNTER_ID,TPM_AUTH *); #else #define RPC_ReadCounter_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CreateCounter_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_IncrementCounter_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ReleaseCounter_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ReleaseCounterOwner_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_TICK TSS_RESULT RPC_ReadCurrentTicks_TP(struct host_table_entry *,UINT32 *,BYTE **); TSS_RESULT RPC_TickStampBlob_TP(struct host_table_entry *,TCS_KEY_HANDLE,TPM_NONCE *,TPM_DIGEST *,TPM_AUTH *,UINT32 *,BYTE **,UINT32 *,BYTE **); #else #define RPC_ReadCurrentTicks_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_TickStampBlob_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_TRANSPORT TSS_RESULT RPC_EstablishTransport_TP(struct host_table_entry *, UINT32, TCS_KEY_HANDLE, UINT32, BYTE*, UINT32, BYTE*, TPM_AUTH*, TPM_MODIFIER_INDICATOR*, TCS_HANDLE*, UINT32*, BYTE**, TPM_NONCE*); TSS_RESULT RPC_ExecuteTransport_TP(struct host_table_entry *,TPM_COMMAND_CODE, UINT32, BYTE*, UINT32*, TCS_HANDLE**, TPM_AUTH*, TPM_AUTH*, TPM_AUTH*, UINT64*, TPM_MODIFIER_INDICATOR*, TPM_RESULT*, UINT32*, BYTE**); TSS_RESULT RPC_ReleaseTransportSigned_TP(struct host_table_entry *, TCS_KEY_HANDLE, TPM_NONCE *, TPM_AUTH*, TPM_AUTH*, TPM_MODIFIER_INDICATOR*, UINT32*, BYTE**, UINT32*, BYTE**); #else #define RPC_EstablishTransport_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ExecuteTransport_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_ReleaseTransportSigned_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_NV TSS_RESULT RPC_NV_DefineOrReleaseSpace_TP(struct host_table_entry *hte, UINT32, BYTE *, TCPA_ENCAUTH, TPM_AUTH *); TSS_RESULT RPC_NV_WriteValue_TP(struct host_table_entry *hte, TSS_NV_INDEX, UINT32, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT RPC_NV_WriteValueAuth_TP(struct host_table_entry *hte, TSS_NV_INDEX, UINT32, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT RPC_NV_ReadValue_TP(struct host_table_entry *hte, TSS_NV_INDEX, UINT32, UINT32 *, TPM_AUTH *, BYTE **); TSS_RESULT RPC_NV_ReadValueAuth_TP(struct host_table_entry *hte, TSS_NV_INDEX, UINT32, UINT32 *, TPM_AUTH *, BYTE **); #else #define RPC_NV_DefineOrReleaseSpace_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_NV_WriteValue_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_NV_WriteValueAuth_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_NV_ReadValue_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_NV_ReadValueAuth_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_AUDIT TSS_RESULT RPC_SetOrdinalAuditStatus_TP(struct host_table_entry *hte, TPM_AUTH *, UINT32, TSS_BOOL); TSS_RESULT RPC_GetAuditDigest_TP(struct host_table_entry *hte, UINT32, TPM_DIGEST *, UINT32 *, BYTE **, TSS_BOOL *, UINT32 *, UINT32 **); TSS_RESULT RPC_GetAuditDigestSigned_TP(struct host_table_entry *hte, TCS_KEY_HANDLE, TSS_BOOL, TPM_NONCE *, TPM_AUTH *, UINT32 *, BYTE **, TPM_DIGEST *, TPM_DIGEST *, UINT32 *, BYTE **); #else #define RPC_SetOrdinalAuditStatus_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetAuditDigest_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_GetAuditDigestSigned_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_TSS12 TSS_RESULT RPC_SetOperatorAuth_TP(struct host_table_entry *hte, TCPA_SECRET *); TSS_RESULT RPC_FlushSpecific_TP(struct host_table_entry *hte, TCS_HANDLE, TPM_RESOURCE_TYPE); #else #define RPC_SetOperatorAuth_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_FlushSpecific_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_DELEGATION TSS_RESULT RPC_Delegate_Manage_TP(struct host_table_entry *hte, TPM_FAMILY_ID, TPM_FAMILY_OPERATION, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_CreateKeyDelegation_TP(struct host_table_entry *hte, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_CreateOwnerDelegation_TP(struct host_table_entry *hte, TSS_BOOL, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_LoadOwnerDelegation_TP(struct host_table_entry *hte, TPM_DELEGATE_INDEX, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT RPC_Delegate_ReadTable_TP(struct host_table_entry *hte, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_UpdateVerificationCount_TP(struct host_table_entry *hte, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_VerifyDelegation_TP(struct host_table_entry *hte, UINT32, BYTE *); TSS_RESULT RPC_DSAP_TP(struct host_table_entry *hte, TPM_ENTITY_TYPE, TCS_KEY_HANDLE, TPM_NONCE *, UINT32, BYTE *, TCS_AUTHHANDLE *, TPM_NONCE *, TPM_NONCE *); #else #define RPC_Delegate_Manage_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_Delegate_CreateKeyDelegation_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_Delegate_CreateOwnerDelegation_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_Delegate_LoadOwnerDelegation_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_Delegate_ReadTable_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_Delegate_UpdateVerificationCount_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_Delegate_VerifyDelegation_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_DSAP_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #ifdef TSS_BUILD_CMK TSS_RESULT RPC_CMK_SetRestrictions_TP(struct host_table_entry *hte, TSS_CMK_DELEGATE, TPM_AUTH *); TSS_RESULT RPC_CMK_ApproveMA_TP(struct host_table_entry *hte, TPM_DIGEST, TPM_AUTH *, TPM_HMAC *); TSS_RESULT RPC_CMK_CreateKey_TP(struct host_table_entry *hte, TCS_KEY_HANDLE, TPM_ENCAUTH *, TPM_HMAC *, TPM_DIGEST *, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT RPC_CMK_CreateTicket_TP(struct host_table_entry *hte, UINT32, BYTE *, TPM_DIGEST, UINT32, BYTE *, TPM_AUTH *, TPM_HMAC *); TSS_RESULT RPC_CMK_CreateBlob_TP(struct host_table_entry *hte, TCS_KEY_HANDLE, TSS_MIGRATE_SCHEME, UINT32, BYTE *, TPM_DIGEST, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_CMK_ConvertMigration_TP(struct host_table_entry *hte, TCS_KEY_HANDLE, TPM_CMK_AUTH, TPM_HMAC, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); #else #define RPC_CMK_SetRestrictions_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CMK_ApproveMA_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CMK_CreateKey_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CMK_CreateTicket_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CMK_CreateBlob_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #define RPC_CMK_ConvertMigration_TP(...) TSPERR(TSS_E_INTERNAL_ERROR) #endif #endif trousers-0.3.15/src/include/tcs_tsp.h0000664000175000017510000000625413663651711017025 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _TCS_TSP_H_ #define _TCS_TSP_H_ /* Structures and defines needed to be known by the * TSP layer and the TCS layer. */ /* * disk store format: * * [type name ] cached? * -------------------------------------- * [BYTE TrouSerS PS version] no * [UINT32 num_keys_on_disk ] no * [TSS_UUID uuid0 ] yes * [TSS_UUID uuid_parent0 ] yes * [UINT16 pub_data_size0 ] yes * [UINT16 blob_size0 ] yes * [UINT32 vendor_data_size0 ] yes * [UINT16 cache_flags0 ] yes * [BYTE[] pub_data0 ] no * [BYTE[] blob0 ] no * [BYTE[] vendor_data0 ] no * [...] * */ /* * PS disk cache flags */ /* A key may be written to disk, in cache and yet be invalid if it has * since been unregistered. */ #define CACHE_FLAG_VALID 0x0001 /* set if the key's parent is stored in system PS */ #define CACHE_FLAG_PARENT_PS_SYSTEM 0x0002 /* the structure that makes up the in-memory PS disk cache */ struct key_disk_cache { unsigned int offset; UINT16 pub_data_size; UINT16 blob_size; UINT16 flags; UINT32 vendor_data_size; TSS_UUID uuid; TSS_UUID parent_uuid; struct key_disk_cache *next; }; /* The current PS version */ #define TSSPS_VERSION 1 /* offsets into each key on disk. These should be passed a (struct key_disk_cache *) */ #define TSSPS_VERSION_OFFSET (0) #define TSSPS_NUM_KEYS_OFFSET (TSSPS_VERSION_OFFSET + sizeof(BYTE)) #define TSSPS_KEYS_OFFSET (TSSPS_NUM_KEYS_OFFSET + sizeof(UINT32)) #define TSSPS_UUID_OFFSET(c) ((c)->offset) #define TSSPS_PARENT_UUID_OFFSET(c) ((c)->offset + sizeof(TSS_UUID)) #define TSSPS_PUB_DATA_SIZE_OFFSET(c) ((c)->offset + (2 * sizeof(TSS_UUID))) #define TSSPS_BLOB_SIZE_OFFSET(c) ((c)->offset + (2 * sizeof(TSS_UUID)) + sizeof(UINT16)) #define TSSPS_VENDOR_SIZE_OFFSET(c) ((c)->offset + (2 * sizeof(TSS_UUID)) + (2 * sizeof(UINT16))) #define TSSPS_CACHE_FLAGS_OFFSET(c) ((c)->offset + (2 * sizeof(TSS_UUID)) + (2 * sizeof(UINT16)) + sizeof(UINT32)) #define TSSPS_PUB_DATA_OFFSET(c) ((c)->offset + (2 * sizeof(TSS_UUID)) + (3 * sizeof(UINT16)) + sizeof(UINT32)) #define TSSPS_BLOB_DATA_OFFSET(c) ((c)->offset + (2 * sizeof(TSS_UUID)) + (3 * sizeof(UINT16)) + sizeof(UINT32) + (c)->pub_data_size) #define TSSPS_VENDOR_DATA_OFFSET(c) ((c)->offset + (2 * sizeof(TSS_UUID)) + (3 * sizeof(UINT16)) + sizeof(UINT32) + (c)->pub_data_size + (c)->blob_size) /* XXX Get rid of this, there's no reason to set an arbitrary limit */ #define MAX_KEY_CHILDREN 10 #define STRUCTURE_PACKING_ATTRIBUTE __attribute__((packed)) #ifdef TSS_DEBUG #define DBG_ASSERT(x) assert(x) #else #define DBG_ASSERT(x) #endif /* needed by execute transport in the TSP */ #define TSS_TPM_TXBLOB_HDR_LEN (sizeof(UINT16) + (2 * sizeof(UINT32))) #define TSS_TPM_TXBLOB_SIZE (4096) #define TSS_TXBLOB_WRAPPEDCMD_OFFSET (TSS_TPM_TXBLOB_HDR_LEN + sizeof(UINT32)) #define TSS_MAX_AUTHS_CAP (1024) #define TSS_REQ_MGR_MAX_RETRIES (5) #endif trousers-0.3.15/src/include/capabilities.h0000664000175000017510000000365613663651711020002 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _CAPABILITIES_H_ #define _CAPABILITIES_H_ /* This header has all of the software capabilities that are returned either via * Tspi_Context_GetCapability or TCS_GetCapability. */ /* TSP */ /* BOOL */ #define INTERNAL_CAP_TSP_ALG_RSA TRUE #define INTERNAL_CAP_TSP_ALG_SHA TRUE #define INTERNAL_CAP_TSP_ALG_3DES FALSE #define INTERNAL_CAP_TSP_ALG_DES FALSE #define INTERNAL_CAP_TSP_ALG_HMAC TRUE #define INTERNAL_CAP_TSP_ALG_AES TRUE #define INTERNAL_CAP_TSP_PERSSTORAGE TRUE /* UINT32 */ #define INTERNAL_CAP_TSP_ALG_DEFAULT TSS_ALG_RSA #define INTERNAL_CAP_TSP_ALG_DEFAULT_SIZE TSS_KEY_SIZEVAL_2048BIT /* 1 indicates byte-stream return values, 0 indicates ASN.1 encoded return values */ #define INTERNAL_CAP_TSP_RETURNVALUE_INFO 1 /* 0 is unknown platform version/type. Currently the spec is too vague on possible values for this * information to define anything here. */ #define INTERNAL_CAP_TSP_PLATFORM_VERSION 0 #define INTERNAL_CAP_TSP_PLATFORM_TYPE 0 /* TCS */ /* BOOL */ #define INTERNAL_CAP_TCS_ALG_RSA FALSE #define INTERNAL_CAP_TCS_ALG_AES FALSE #define INTERNAL_CAP_TCS_ALG_3DES FALSE #define INTERNAL_CAP_TCS_ALG_DES FALSE #define INTERNAL_CAP_TCS_ALG_SHA TRUE #define INTERNAL_CAP_TCS_ALG_HMAC FALSE #define INTERNAL_CAP_TCS_PERSSTORAGE TRUE #define INTERNAL_CAP_TCS_CACHING_KEYCACHE FALSE #define INTERNAL_CAP_TCS_CACHING_AUTHCACHE TRUE /* UINT32 */ #define INTERNAL_CAP_TCS_ALG_DEFAULT TSS_ALG_RSA #define INTERNAL_CAP_TCS_ALG_DEFAULT_SIZE TSS_KEY_SIZEVAL_2048BIT /* Common between both TSP and TCS */ #define INTERNAL_CAP_VERSION { 1, 2, TSS_VER_MAJOR, TSS_VER_MINOR } #define INTERNAL_CAP_MANUFACTURER_ID 0x49424D00 #define INTERNAL_CAP_MANUFACTURER_STR { 'I', 0, 'B', 0, 'M', 0, 0, 0 } #define INTERNAL_CAP_MANUFACTURER_STR_LEN 8 #endif trousers-0.3.15/src/include/obj_nv.h0000664000175000017510000000605713663651711016624 0ustar deboradebora/* * The Initial Developer of the Original Code is Intel Corporation. * Portions created by Intel Corporation are Copyright (C) 2007 Intel Corporation. * All Rights Reserved. * trousers - An open source TCG Software Stack * * Author: james.xu@intel.com Rossey.liu@intel.com * */ #ifndef _OBJ_NVSTORE_H_ #define _OBJ_NVSTORE_H_ #ifdef TSS_BUILD_NV #define MAX_PUBLIC_DATA_SIZE 1024 #define TSS_LOCALITY_MASK 0x1f typedef struct objNV_DATA_PUBLIC { TPM_STRUCTURE_TAG tag; TPM_NV_INDEX nvIndex; TPM_NV_ATTRIBUTES permission; TPM_BOOL bReadSTClear; TPM_BOOL bWriteSTClear; TPM_BOOL bWriteDefine; UINT32 dataSize; }NV_DATA_PUBLIC; /* structures */ struct tr_nvstore_obj { TPM_STRUCTURE_TAG tag; TPM_NV_INDEX nvIndex; TPM_NV_ATTRIBUTES permission; TPM_BOOL bReadSTClear; TPM_BOOL bWriteSTClear; TPM_BOOL bWriteDefine; UINT32 dataSize; TSS_HPOLICY policy; }; /* obj_nv.c */ void nvstore_free(void *data); TSS_RESULT obj_nvstore_add(TSS_HCONTEXT, TSS_HOBJECT *); TSS_BOOL obj_is_nvstore(TSS_HOBJECT tspContext); TSS_RESULT obj_nvstore_remove(TSS_HOBJECT, TSS_HCONTEXT); TSS_RESULT obj_nvstore_get_tsp_context(TSS_HNVSTORE, TSS_HCONTEXT *); TSS_RESULT obj_nvstore_set_index(TSS_HNVSTORE, UINT32); TSS_RESULT obj_nvstore_get_index(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_set_datasize(TSS_HNVSTORE, UINT32); TSS_RESULT obj_nvstore_get_datasize(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_set_permission(TSS_HNVSTORE, UINT32); TSS_RESULT obj_nvstore_get_permission_from_tpm(TSS_HNVSTORE hNvstore, UINT32 * permission); TSS_RESULT obj_nvstore_get_permission(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_set_policy(TSS_HNVSTORE, TSS_HPOLICY); TSS_RESULT obj_nvstore_get_policy(TSS_HNVSTORE, UINT32, TSS_HPOLICY *); TSS_RESULT obj_nvstore_get_datapublic(TSS_HNVSTORE, UINT32 *, BYTE *); TSS_RESULT obj_nvstore_get_readdigestatrelease(TSS_HNVSTORE, UINT32 *, BYTE **); TSS_RESULT obj_nvstore_get_readpcrselection(TSS_HNVSTORE, UINT32 *, BYTE **); TSS_RESULT obj_nvstore_get_writedigestatrelease(TSS_HNVSTORE, UINT32 *, BYTE **); TSS_RESULT obj_nvstore_get_writepcrselection(TSS_HNVSTORE, UINT32 *, BYTE **); TSS_RESULT obj_nvstore_get_state_readstclear(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_get_state_writedefine(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_get_state_writestclear(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_get_readlocalityatrelease(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_get_writelocalityatrelease(TSS_HNVSTORE, UINT32 *); TSS_RESULT obj_nvstore_create_pcrshortinfo(TSS_HNVSTORE, TSS_HPCRS, UINT32 *, BYTE **); #define NVSTORE_LIST_DECLARE struct obj_list nvstore_list #define NVSTORE_LIST_DECLARE_EXTERN extern struct obj_list nvstore_list #define NVSTORE_LIST_INIT() tspi_list_init(&nvstore_list) #define NVSTORE_LIST_CONNECT(a,b) obj_connectContext_list(&nvstore_list, a, b) #define NVSTORE_LIST_CLOSE(a) obj_list_close(&nvstore_list, &nvstore_free, a) #else #define NVSTORE_LIST_DECLARE #define NVSTORE_LIST_DECLARE_EXTERN #define NVSTORE_LIST_INIT() #define NVSTORE_LIST_CONNECT(a,b) #define NVSTORE_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/tcs_int_literals.h0000664000175000017510000000110413663651711020675 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _TCS_INT_LITERALS_H_ #define _TCS_INT_LITERALS_H_ #define TPM_VENDOR_UNKNOWN 0 #define TPM_VENDOR_ATMEL 1 #define TPM_VENDOR_IFX 2 #define TPM_VENDOR_NATL 3 #define TPM_PARAMSIZE_OFFSET 0x02 #define NULL_TPM_HANDLE ((TCPA_KEY_HANDLE)-1) #define NULL_TCS_HANDLE ((TCS_KEY_HANDLE)-1) #define SRK_TPM_HANDLE (0x40000000) #define EK_TPM_HANDLE (0x40000001) #define FIXED_TCS_MANUFACTURER "IBM " #endif trousers-0.3.15/src/include/obj_hash.h0000664000175000017510000000251613663651711017120 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_HASH_H_ #define _OBJ_HASH_H_ #ifdef TSS_BUILD_HASH_LIST /* structures */ struct tr_hash_obj { UINT32 type; BYTE *hashData; UINT32 hashSize; UINT32 hashUpdateSize; BYTE *hashUpdateBuffer; }; /* obj_hash.c */ void __tspi_hash_free(void *data); TSS_RESULT obj_hash_add(TSS_HCONTEXT, UINT32, TSS_HOBJECT *); TSS_BOOL obj_is_hash(TSS_HOBJECT); TSS_RESULT obj_hash_remove(TSS_HOBJECT, TSS_HCONTEXT); TSS_RESULT obj_hash_get_tsp_context(TSS_HHASH, TSS_HCONTEXT *); TSS_RESULT obj_hash_set_value(TSS_HHASH, UINT32, BYTE *); TSS_RESULT obj_hash_get_value(TSS_HHASH, UINT32 *, BYTE **); TSS_RESULT obj_hash_update_value(TSS_HHASH, UINT32, BYTE *); #define HASH_LIST_DECLARE struct obj_list hash_list #define HASH_LIST_DECLARE_EXTERN extern struct obj_list hash_list #define HASH_LIST_INIT() tspi_list_init(&hash_list) #define HASH_LIST_CONNECT(a,b) obj_connectContext_list(&hash_list, a, b) #define HASH_LIST_CLOSE(a) obj_list_close(&hash_list, &__tspi_hash_free, a) #else #define obj_is_hash(a) FALSE #define HASH_LIST_DECLARE #define HASH_LIST_DECLARE_EXTERN #define HASH_LIST_INIT() #define HASH_LIST_CONNECT(a,b) #define HASH_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/hosttable.h0000664000175000017510000000152413663651711017326 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #ifndef _HOSTTABLE_H_ #define _HOSTTABLE_H_ #include "rpc_tcstp.h" #include "threads.h" #define CONNECTION_TYPE_TCP_PERSISTANT 1 struct host_table_entry { struct host_table_entry *next; TSS_HCONTEXT tspContext; TCS_CONTEXT_HANDLE tcsContext; BYTE *hostname; int type; int socket; struct tcsd_comm_data comm; MUTEX_DECLARE(lock); }; struct host_table { struct host_table_entry *entries; MUTEX_DECLARE(lock); }; struct host_table_entry *get_table_entry(TCS_CONTEXT_HANDLE); void put_table_entry(struct host_table_entry *); TSS_RESULT __tspi_add_table_entry(TSS_HCONTEXT, BYTE *, int, struct host_table_entry **); void remove_table_entry(TCS_CONTEXT_HANDLE); #endif trousers-0.3.15/src/include/imaem.h0000664000175000017510000000154713663651711016436 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _IMAEM_H_ #define _IMAEM_H_ int ima_open(void *, FILE **); TSS_RESULT ima_get_entries_by_pcr(FILE *, UINT32, UINT32, UINT32 *, TSS_PCR_EVENT **); TSS_RESULT ima_get_entry(FILE *, UINT32, UINT32 *, TSS_PCR_EVENT **); int ima_close(FILE *); extern struct ext_log_source ima_source; /* 4 bytes binary [PCR value] * 20 bytes binary [SHA1 value] * 4 bytes binary [event type] * 255 bytes of ascii (MAX) [event name] * 1 byte -> '\0' [separator ] */ #define IMA_MIN_EVENT_SIZE 29 #define IMA_MAX_EVENT_SIZE 284 /* this should be large if we're reading out of /proc */ #define IMA_READ_SIZE (4096 + IMA_MAX_EVENT_SIZE) #define EVLOG_SOURCE_IMA 1 #endif trousers-0.3.15/src/include/tsp_tcsi_param.h0000664000175000017510000000132313663651711020346 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007, 2013 * */ /* Defines which environment var is responsible for setting the port to * which the client will connect */ #define PORT_ENV_VAR "TSS_TCSD_PORT" /* Defines which envionment var is responsible for setting the hostname to * which the client will connect */ #define HOSTNAME_ENV_VAR "TSS_TCSD_HOSTNAME" #define TCP_PORT_STR_MAX_LEN 6 /* Prototypes for functions which retrieve tcsd hostname and port * information */ TSS_RESULT get_tcsd_port(char port_str[TCP_PORT_STR_MAX_LEN]); TSS_RESULT get_tcsd_hostname(char **host_str, unsigned *len); trousers-0.3.15/src/include/tcslog.h0000664000175000017510000000614613663651711016641 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #ifndef _TCSLOG_H_ #define _TCSLOG_H_ #include #include /* log to syslog -- change your syslog destination here */ #define TSS_SYSLOG_LVL LOG_LOCAL5 #ifndef __FUNCTION__ #define __FUNCTION__ __func__ #endif #define LogMessage(dest, priority, layer, fmt, ...) \ do { \ if (getenv("TCSD_FOREGROUND") != NULL) { \ fprintf(dest, "%s " fmt "\n", layer, ## __VA_ARGS__); \ } else { \ openlog(layer, LOG_NDELAY|LOG_PID, TSS_SYSLOG_LVL); \ syslog(priority, "TrouSerS " fmt "\n", ## __VA_ARGS__); \ } \ } while (0) /* Debug logging */ #ifdef TSS_DEBUG #define LogDebug(fmt, ...) LogMessage(stdout, LOG_DEBUG, APPID, "%s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__) #define LogDebugFn(fmt, ...) LogMessage(stdout, LOG_DEBUG, APPID, "%s:%d %s: " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) #define LogBlob(sz,blb) LogBlobData(APPID, sz, blb) #define LogDebugKey(k) \ do { \ if (k.hdr.key12.tag == TPM_TAG_KEY12) \ LogDebugFn("Tag: %hu", k.hdr.key12.tag); \ else \ LogDebugFn("Version: %hhu.%hhu.%hhu.%hhu", \ k.hdr.key11.ver.major, k.hdr.key11.ver.minor, \ k.hdr.key11.ver.revMajor, k.hdr.key11.ver.revMinor); \ LogDebugFn("keyUsage: 0x%hx", k.keyUsage); \ LogDebugFn("keyFlags: 0x%x", k.keyFlags); \ LogDebugFn("authDatausage: %hhu", k.authDataUsage); \ LogDebugFn("pcrInfosize: %u", k.PCRInfoSize); \ LogDebugFn("encDataSize: %u", k.encSize); \ } while (0) #define LogDebugUnrollKey(b) \ do { \ TSS_KEY tmpkey; \ UINT64 offset = 0; \ if (!UnloadBlob_TSS_KEY(&offset, b, &tmpkey)) { \ LogDebugKey(tmpkey); \ destroy_key_refs(&tmpkey); \ } else { \ LogDebugFn("*** ERROR UNLOADING DEBUGGING KEY BLOB ***"); \ } \ } while (0) #define LogError(fmt, ...) LogMessage(stderr, LOG_ERR, APPID, "ERROR: %s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__) #define LogWarn(fmt, ...) LogMessage(stdout, LOG_WARNING, APPID, "%s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__) #define LogInfo(fmt, ...) LogMessage(stdout, LOG_INFO, APPID, "%s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__) /* Return Value logging */ TSS_RESULT LogTCSERR(TSS_RESULT, char *, int); TSS_RESULT LogTDDLERR(TSS_RESULT, char *, int); void LogTPMERR(TSS_RESULT, char *, int); #define LogDebugBacktrace() \ do { \ void *bt_data[10]; \ backtrace_symbols_fd(&bt_data, 10, stdout); \ } while (0) #else #define LogDebug(fmt, ...) #define LogDebugFn(fmt, ...) #define LogBlob(sz,blb) #define LogDebugKey(s) #define LogDebugUnrollKey(b) /* Error logging */ #define LogError(fmt, ...) LogMessage(stderr, LOG_ERR, APPID, "ERROR: " fmt, ##__VA_ARGS__) /* Warn logging */ #define LogWarn(fmt, ...) LogMessage(stdout, LOG_WARNING, APPID, fmt, ##__VA_ARGS__) /* Info Logging */ #define LogInfo(fmt, ...) LogMessage(stdout, LOG_INFO, APPID, fmt, ##__VA_ARGS__) #define LogTPMERR(a,b,c) #define LogDebugBacktrace() #endif void LogBlobData(char *appid, unsigned long sizeOfBlob, unsigned char *blob); #endif trousers-0.3.15/src/include/biosem.h0000664000175000017510000000141013663651711016611 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef _BIOSEM_H_ #define _BIOSEM_H_ int bios_open(void *, FILE **); TSS_RESULT bios_get_entries_by_pcr(FILE *, UINT32, UINT32, UINT32 *, TSS_PCR_EVENT **); TSS_RESULT bios_get_entry(FILE *, UINT32, UINT32 *, TSS_PCR_EVENT **); int bios_close(FILE *); extern struct ext_log_source bios_source; /* this should be large if we're reading out of /proc */ #define BIOS_READ_SIZE 4096 typedef struct { UINT32 pcrIndex; UINT32 eventType; BYTE digest[20]; UINT32 eventDataSize; BYTE event[0];/* (eventSize) bytes of event data follows */ } TCG_PCClientPCREventStruc; #define EVLOG_SOURCE_BIOS 1 #endif trousers-0.3.15/src/include/tddl.h0000664000175000017510000000120313663651711016262 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ #ifndef _TDDL_H_ #define _TDDL_H_ #include #include "tcsd_wrap.h" #include "tcsd.h" struct tpm_device_node { char *path; #define TDDL_TRANSMIT_IOCTL 1 #define TDDL_TRANSMIT_RW 2 int transmit; int fd; }; #define TDDL_TXBUF_SIZE 2048 #define TDDL_UNDEF -1 TSS_RESULT Tddli_Open(void); TSS_RESULT Tddli_TransmitData(BYTE *pTransmitBuf, UINT32 TransmitBufLen, BYTE *pReceiveBuf, UINT32 *pReceiveBufLen); TSS_RESULT Tddli_Close(void); #endif trousers-0.3.15/src/include/daa/0000775000175000017510000000000013663651711015713 5ustar deboradeboratrousers-0.3.15/src/include/daa/daa_parameter.h0000664000175000017510000000410213663651711020646 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef DAA_PARAMETER_H_ #define DAA_PARAMETER_H_ // for message digest //#include #include "trousers/tss.h" //#include "spi_internal_types.h" #include "spi_utils.h" #define DAA_PARAM_TSS_VERSION_LENGTH (4) static const BYTE DAA_PARAM_TSS_VERSION[] = { 1, 2, 0, 0 }; #define DAA_PARAM_DEFAULT_CRYPTO_PROVIDER_NAME "BC" // Name of default hash function #define DAA_PARAM_MESSAGE_DIGEST_ALGORITHM "SHA1" // Name of hash function used independently in TSS #define DAA_PARAM_MESSAGE_DIGEST_ALGORITHM_TSS "SHA1" // l_n (bits) #define DAA_PARAM_SIZE_RSA_MODULUS (2048) // l_f (bits) #define DAA_PARAM_SIZE_F_I (104) // l_q (2 * SIZE_F_I) #define DAA_PARAM_SIZE_RHO (208) // l_e #define DAA_PARAM_SIZE_EXPONENT_CERTIFICATE (368) // lPrime_e #define DAA_PARAM_SIZE_INTERVAL_EXPONENT_CERTIFICATE (120) // l_zero #define DAA_PARAM_SAFETY_MARGIN (80) // Byte length of TPM message digest (sha-1) #define DAA_PARAM_LENGTH_MESSAGE_DIGEST (20) // Byte length of TSS message digest (sha-256) #define DAA_PARAM_LENGTH_MESSAGE_DIGEST_TSS (32) // l_H depends on the message digest algo #define DAA_PARAM_SIZE_MESSAGE_DIGEST (160) // 8 * LENGTH_MESSAGE_DIGEST; // l_GAMMA #define DAA_PARAM_SIZE_MODULUS_GAMMA (1632) #define DAA_PARAM_SIZE_SPLIT_EXPONENT (1024) // TPM asym key size (bits) #define DAA_PARAM_KEY_SIZE (2048) // Default RSA public key exponent (Fermat 4) #define DAA_PARAM_LENGTH_MFG1_ANONYMITY_REVOCATION (25) // (SIZE_RHO-1)/8; #define DAA_PARAM_LENGTH_MFG1_GAMMA (214) // (SIZE_MODULUS_GAMMA + SIZE_SAFETY_MARGIN)/8; #define DAA_PARAM_SIZE_RND_VALUE_CERTIFICATE (2536) // (bits) #define DAA_PARAM_SIZE_RANDOMIZED_ATTRIBUTES (DAA_PARAM_SIZE_F_I+DAA_PARAM_SAFETY_MARGIN+DAA_PARAM_SIZE_MESSAGE_DIGEST) #define TSS_FLAG_DAA_SIGN_IDENTITY_KEY 0 #define TSS_FLAG_DAA_SIGN_MESSAGE_HASH 1 extern EVP_MD *DAA_PARAM_get_message_digest(void); extern char *err_string(TSS_RESULT r); #endif /*DAA_PARAMETER_H_*/ trousers-0.3.15/src/include/daa/list.h0000664000175000017510000000127613663651711017045 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef LIST_H_ #define LIST_H_ /* simple linked list template */ struct _list_t { void *obj; struct _list_t *next; // pointer to next node }; typedef struct _list_t node_t; // each link is a list "node" typedef struct { node_t *head; // pointer to first node node_t *current; node_t *previous; } list_struct; typedef list_struct* list_ptr; typedef list_struct list_t[1]; list_ptr list_new(); void list_add(list_ptr list, void * obj); void list_dump(list_ptr list); void list_freeall(list_ptr list); #endif /*LIST_H_*/ trousers-0.3.15/src/include/daa/key_correct.h0000664000175000017510000000120513663651711020373 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef KEY_CORRECT_H_ #define KEY_CORRECT_H_ #include "daa/daa_structs.h" #include "daa/daa_parameter.h" #include "tsplog.h" /** * Verifies if the parameters Z,R0,R1,RReceiver and RIssuer of the public key * were correctly computed. * * @param pk * the public key, which one wants to verfy. */ TSS_RESULT is_pk_correct( TSS_DAA_PK_internal *public_key, TSS_DAA_PK_PROOF_internal *proof, int *isCorrect ); #endif /*KEY_CORRECTNESS_PROOF_H_*/ trousers-0.3.15/src/include/daa/bi_gmp.h0000664000175000017510000001665213663651711017333 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef BI_GMP_ #define BI_GMP_ #include // needed for OPENSSL_free #include typedef mpz_t bi_t; typedef mpz_ptr bi_ptr; extern gmp_randstate_t state; /* initialized the given big integer */ INLINE_DECL bi_ptr bi_new(bi_t i) { mpz_init( i); return i; } /* create a big integer pointer */ INLINE_DECL bi_ptr bi_new_ptr(void) { mpz_ptr res; res = (mpz_ptr)malloc( sizeof( mpz_t)); if( res == NULL) return NULL; mpz_init( res); return res; } /* free resources allocated to the big integer */ INLINE_DECL void bi_free(const bi_ptr i) { mpz_clear( i); } /* free resources allocated to the big integer pointer */ INLINE_DECL void bi_free_ptr(const bi_ptr i) { mpz_clear( i); free( i); } /* return the current number of bits of the number */ INLINE_DECL long bi_length( const bi_ptr res) { return mpz_sizeinbase( res, 2); } /*********************************************************************************** CONVERSIONS *************************************************************************************/ /* return an hex dump of the given big integer */ INLINE_DECL char *bi_2_hex_char(const bi_ptr i) { char *ret; gmp_asprintf( &ret, "%ZX", i); list_add( allocs, ret); return ret; } /* return an hex dump of the given big integer */ INLINE_DECL char *bi_2_dec_char(const bi_ptr i) { char *ret; gmp_asprintf( &ret, "%Zd", i); list_add( allocs, ret); return ret; } /* set to the same value as the big integer */ INLINE_DECL bi_ptr bi_set( bi_ptr result, const bi_ptr value) { mpz_set( result, value); return result; } /* set the initialized variable to the value represented by the given hex format stirng */ INLINE_DECL bi_ptr bi_set_as_hex( bi_ptr result, const char *value) { mpz_set_str( result, value, 16); return result; } /* set the initialized variable to the value represented by the given hex format stirng */ INLINE_DECL bi_ptr bi_set_as_dec( bi_ptr result, const char *value) { mpz_set_str( result, value, 10); return result; } /* set with the value represented by unsigned int */ /* := */ INLINE_DECL bi_ptr bi_set_as_si( bi_ptr result, const int value) { mpz_set_si( result, value); return result; } /* return (long)bi_t */ INLINE_DECL long bi_get_si(const bi_ptr i) { return mpz_get_si( i); } /* convert a bi type to a openssl BIGNUM struct */ INLINE_DECL BIGNUM *bi_2_BIGNUM( const bi_ptr i) { BIGNUM *result; char *value = bi_2_hex_char( i); BN_hex2bn( &result, value); return result; } /* set with the value represented by the given openssl BIGNUM struct */ INLINE_DECL bi_ptr bi_set_as_BIGNUM( bi_ptr i, BIGNUM *bn) { char *value = BN_bn2hex( bn); if( value == NULL) return NULL; bi_set_as_hex( i, value); OPENSSL_free( value); return i; } /*********************************************************************************** BASIC MATH OPERATION *************************************************************************************/ /* := result + 1 */ INLINE_DECL bi_ptr bi_inc(bi_ptr result) { mpz_add_ui( result, result, 1); return result; } /* := result - 1 */ INLINE_DECL bi_ptr bi_dec(bi_ptr result) { mpz_sub_ui( result, result, 1); return result; } /* set by the division of by the long */ /* := / */ INLINE_DECL bi_ptr bi_div_si( bi_ptr result, const bi_ptr i, const long n) { mpz_div_ui( result, i, n); return result; } /* := / */ INLINE_DECL bi_ptr bi_div( bi_ptr result, const bi_ptr i, const bi_ptr n) { mpz_div( result, i, n); return result; } /* := - */ INLINE_DECL bi_ptr bi_negate( bi_ptr result) { mpz_neg( result, result); return result; } /* multiply the given big integer by the give long and return the result in */ INLINE_DECL bi_ptr bi_mul_si( bi_ptr result, const bi_ptr i, const long n) { mpz_mul_si( result, i, n); return result; } /* := * */ INLINE_DECL bi_ptr bi_mul( bi_ptr result, const bi_ptr i, const bi_ptr n) { mpz_mul( result, i, n); return result; } /* := + */ INLINE_DECL bi_ptr bi_add_si( bi_ptr result, const bi_ptr i, const long n) { mpz_add_ui( result, i, n); return result; } /* := + */ INLINE_DECL bi_ptr bi_add( bi_ptr result, const bi_ptr i, const bi_ptr n) { mpz_add( result, i, n); return result; } /* := - */ INLINE_DECL bi_ptr bi_sub_si( bi_ptr result, const bi_ptr i, const long n) { // n should be unsigned mpz_sub_ui( result, i, n); return result; } /* := - */ INLINE_DECL bi_ptr bi_sub( bi_ptr result, const bi_ptr i, const bi_ptr n) { mpz_sub( result, result, n); return result; } /* := ( ^ ) mod */ INLINE_DECL bi_ptr bi_mod_exp( bi_ptr result, const bi_ptr g, const bi_ptr e, const bi_ptr m) { mpz_powm( result, g, e, m); return result; } /* := ( ^ ) mod */ INLINE_DECL bi_ptr bi_mod_exp_si( bi_ptr result, const bi_ptr g, const bi_ptr e, const long m) { mpz_t bi_m; mpz_init( bi_m); mpz_set_si( bi_m, m); mpz_powm( result, g, e, bi_m); mpz_clear( bi_m); return result; } /*********************************************************************************** BITS OPERATION *************************************************************************************/ /* set the bit to 1 */ INLINE_DECL bi_ptr bi_setbit(bi_ptr result, const int bit) { mpz_setbit( result, bit); return result; } /* := << */ INLINE_DECL bi_ptr bi_shift_left( bi_ptr result, const bi_ptr i, const int n) { mpz_mul_2exp( result, i, n); return result; } /* := >> */ INLINE_DECL bi_ptr bi_shift_right( bi_ptr result, const bi_ptr i, const int n) { mpz_div_2exp( result, i, n); return result; } /*********************************************************************************** COMPARAISON *************************************************************************************/ /* n1n2 return positive value */ INLINE_DECL int bi_cmp( const bi_ptr n1, const bi_ptr n2) { return mpz_cmp( n1, n2); } /* n1n2 return positive value */ INLINE_DECL int bi_cmp_si( const bi_ptr n1, const int n2) { return mpz_cmp_ui( n1, n2); } /* n1 == n2 return 1 (true) * else return 0 */ INLINE_DECL int bi_equals( const bi_ptr n1, const bi_ptr n2) { return mpz_cmp( n1, n2) == 0 ? 1 : 0; } /* n1 == n2 return 1 (true) * else return 0 */ INLINE_DECL int bi_equals_si( const bi_ptr n1, const int n2) { return mpz_cmp_ui( n1, n2) == 0 ? 1 : 0; } /* create a random of length bits */ /* res := random( length) */ INLINE_DECL bi_ptr bi_urandom( bi_ptr result, const long length) { mpz_urandomb( result, state, length); return result; } /* res := mod */ INLINE_DECL bi_ptr bi_mod_si( bi_ptr result, const bi_ptr n, const long m) { mpz_mod_ui( result, n, m); return result; } /* res := mod */ INLINE_DECL bi_ptr bi_mod( bi_ptr result, const bi_ptr n, const bi_ptr m) { mpz_mod( result, n, m); return result; } /* result := (inverse of ) mod */ /* if the inverse exist, return >0, otherwise 0 */ INLINE_DECL int bi_invert_mod( bi_ptr result, const bi_ptr i, const bi_ptr m) { return mpz_invert( result, i, m); } #endif /*BI_GMP_*/ trousers-0.3.15/src/include/daa/platform.h0000664000175000017510000000536213663651711017716 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef PLATFORM_H_ #define PLATFORM_H_ #include "bi.h" #include "daa_structs.h" #if 0 // for RSA key #include TSPICALL Tspi_TPM_DAA_Sign_internal(TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in TSS_HKEY hDaaCredential, // in TSS_DAA_SELECTED_ATTRIB revealAttributes, // in UINT32 verifierBaseNameLength, // in BYTE* verifierBaseName, // in UINT32 verifierNonceLength, // in BYTE* verifierNonce, // in TSS_DAA_SIGN_DATA signData, // in TSS_DAA_SIGNATURE* daaSignature // out ); TSS_RESULT Tspi_TPM_DAA_JoinInit_internal(TSS_HDAA hDAA, TSS_HTPM hTPM, int daa_counter, TSS_DAA_PK *issuer_pk, int issuer_authentication_PKLengh, RSA **issuer_authentication_PK, int issuer_authentication_PK_signaturesLength, BYTE **issuer_authentication_PK_signatures, int *capital_UprimeLength, BYTE **capital_Uprime, TSS_DAA_IDENTITY_PROOF *identity_proof, TSS_DAA_JOIN_SESSION *joinSession ); TSPICALL Tspi_TPM_DAA_JoinCreateDaaPubKey_internal ( TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in UINT32 authenticationChallengeLength, // in BYTE* authenticationChallenge, // in UINT32 nonceIssuerLength, // in BYTE* nonceIssuer, // in UINT32 attributesPlatformLength, // in BYTE** attributesPlatform, // in TSS_DAA_JOIN_SESSION* joinSession, // in, out TSS_DAA_CREDENTIAL_REQUEST* credentialRequest // out ); // allocation: endorsementKey as BYTE * TSS_RESULT get_public_EK( TSS_HDAA hDAA, UINT32 *endorsementKeyLength, BYTE **endorsementKey ); #endif TSS_RESULT compute_join_challenge_host(TSS_HDAA_CREDENTIAL,//TSS_HDAA hDAA, TSS_DAA_PK_internal *pk_internal, bi_ptr capitalU, bi_ptr capital_Uprime, bi_ptr capital_utilde, bi_ptr capital_utilde_prime, bi_ptr capital_ni, bi_ptr capital_ni_tilde, UINT32 commitments_proofLength, TSS_DAA_ATTRIB_COMMIT_internal * commitments_proof, UINT32 nonceIssuerLength, BYTE* nonceIssuer, UINT32 *resultLength, BYTE **result ); #if 0 TSPICALL Tspi_TPM_DAA_JoinStoreCredential_internal(TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in TSS_DAA_CRED_ISSUER credIssuer, // in TSS_DAA_JOIN_SESSION joinSession, // in TSS_HKEY* hDaaCredential // out ); TSPICALL Tspi_TPM_DAA_Sign_internal(TSS_HDAA hDAA, // in TSS_HTPM hTPM, // in TSS_HKEY hDaaCredential, // in TSS_DAA_SELECTED_ATTRIB revealAttributes, // in UINT32 verifierBaseNameLength, // in BYTE* verifierBaseName, // in UINT32 verifierNonceLength, // in BYTE* verifierNonce, // in TSS_DAA_SIGN_DATA signData, // in TSS_DAA_SIGNATURE* daaSignature // out ); #endif #endif trousers-0.3.15/src/include/daa/verifier.h0000664000175000017510000000670413663651711017706 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef VERIFIER_H_ #define VERIFIER_H_ #include "bi.h" #include "daa_structs.h" #include "anonymity_revocation.h" #include "daa_parameter.h" #include "tsplog.h" /* * Transaction of a DAA Verifier to verify a signature (VerifierTransaction.java) */ typedef struct { BYTE *baseName; int baseName_length; EVP_MD *digest; BYTE *nonce; int nonce_length; int is_anonymity_revocation_enabled; // boolean BYTE *anonymity_revocation_condition; int anonymity_revocation_condition_length; CS_PUBLIC_KEY *anonymity_revocator_pk; // private TssDaaSelectedAttrib[] selectedAttributes2Commit; TSS_DAA_SELECTED_ATTRIB **selected_attributes2commit; int selected_attributes2commitLength; } DAA_VERIFIER_TRANSACTION; /* the return (BYTE *) should be free after usage */ BYTE *compute_bytes( int seedLength, BYTE *seed, int length, const EVP_MD *digest); bi_ptr compute_zeta( int nameLength, unsigned char *name, TSS_DAA_PK_internal *issuer_pk); bi_ptr project_into_group_gamma( bi_ptr base, TSS_DAA_PK_internal *issuer_pk); #if 0 TSPICALL Tspi_DAA_VerifyInit_internal ( TSS_HDAA hDAA, // in UINT32* nonceVerifierLength, // out BYTE** nonceVerifier, // out UINT32 baseNameLength, // out BYTE ** baseName // out ); TSPICALL Tspi_DAA_VerifySignature_internal ( TSS_HDAA hDAA, // in TSS_DAA_SIGNATURE signature, // in TSS_HKEY hPubKeyIssuer, // in TSS_DAA_SIGN_DATA sign_data, // in UINT32 attributes_length, // in BYTE **attributes, // in UINT32 nonce_verifierLength, // out BYTE *nonce_verifier, // out UINT32 base_nameLength, // out BYTE *base_name, // out TSS_BOOL *isCorrect // out ); #else TSS_RESULT Tspi_DAA_VerifySignature ( TSS_HDAA_CREDENTIAL hDAACredential, // in TSS_HDAA_ISSUER_KEY hIssuerKey, // in TSS_HDAA_ARA_KEY hARAKey, // in TSS_HHASH hARACondition, // in UINT32 attributesLength, // in UINT32 attributesLength2, // in BYTE** attributes, // in UINT32 verifierNonceLength, // in BYTE* verifierNonce, // in UINT32 verifierBaseNameLength, // in BYTE* verifierBaseName, // in TSS_HOBJECT signData, // in TSS_DAA_SIGNATURE* daaSignature, // in TSS_BOOL* isCorrect // out ); #endif BYTE *compute_sign_challenge_host( int *result_length, EVP_MD *digest, TSS_DAA_PK_internal *issuer_pk, int nonce_verifierLength, BYTE *nonce_verifier, int selected_attributes2commitLength, TSS_DAA_SELECTED_ATTRIB **selected_attributes2commit, int is_anonymity_revocation_enabled, bi_ptr zeta, bi_ptr capital_t, bi_ptr capital_tilde, int attribute_commitmentsLength, TSS_DAA_ATTRIB_COMMIT_internal **attribute_commitments, TSS_DAA_ATTRIB_COMMIT_internal **attribute_commitment_proofs, bi_ptr capital_nv, bi_ptr capital_tilde_v, CS_PUBLIC_KEY *anonymity_revocator_pk, CS_ENCRYPTION_RESULT *encryption_result_rand, CS_ENCRYPTION_RESULT *encryption_result_proof); #endif /*VERIFIER_H_*/ trousers-0.3.15/src/include/daa/bi.h0000664000175000017510000002743713663651711016473 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef BI_H_ #define BI_H_ #include #include #include // for the BIGNUM definition #include #include "list.h" #define INLINE #undef INLINE_DECL #define INLINE_DECL static inline void * (*bi_alloc)(size_t size); // keep the list of allocated memory, usually used for the format functions extern list_ptr allocs; /************************************************************************************ TYPE DEF *************************************************************************************/ #ifdef BI_GMP #include "bi_gmp.h" #endif #ifdef BI_OPENSSL #include "bi_openssl.h" #endif /************************************************************************************ TYPE DEF *************************************************************************************/ struct _bi_array{ bi_ptr *array; int length; }; typedef struct _bi_array bi_array[1]; typedef struct _bi_array *bi_array_ptr; /*********************************************************************************** CONSTANT *************************************************************************************/ extern bi_t bi_0; extern bi_t bi_1; extern bi_t bi_2; /*********************************************************************************** TEMPORARY (WORK) *************************************************************************************/ /* extern bi_t bi_tmp; extern bi_t bi_tmp1; extern bi_t bi_tmp2; extern bi_t bi_tmp3; extern bi_t bi_tmp4; extern bi_t bi_tmp5; extern bi_t bi_tmp6; extern bi_t bi_tmp7; extern bi_t bi_tmp8; extern bi_t bi_tmp9; */ /*********************************************************************************** MACROS *************************************************************************************/ #define ALLOC_BI_ARRAY() (bi_array_ptr)malloc( sizeof( bi_array)) #if 0 #define BI_SAVE( a, b) do { bi_save( a, #a, b); } while(0); #define BI_SAVE_ARRAY( a, b) do { bi_save_array( a, #a, b); } while(0); #define BI_LOAD( a, b) do { bi_load( a, b); } while(0); #define BI_LOAD_ARRAY( a, b) do { bi_load_array( a, b); } while(0); #endif #ifdef BI_DEBUG #define DUMP_BI(field) do { \ fprintf(stderr, "%s=%s [%ld]\n", #field, bi_2_hex_char( field), bi_nbin_size(field));\ } while(0); #define DUMP_BI_ARRAY(field) do { dump_bi_array( #field, field); } while(0); #else #define DUMP_BI(field) #define DUMP_BI_ARRAY(field) #endif /* to free only defines bi_ptr */ #define FREE_BI(a) do { if( (a) != NULL) bi_free_ptr( a); } while(0); /*********************************************************************************** DUMP LIB *************************************************************************************/ char *dump_byte_array(int len, unsigned char *array); /* convert and return it into a byte array of length */ unsigned char *retrieve_byte_array( int *len, const char *strings); /*********************************************************************************** LIBRARY MANAGEMENT *************************************************************************************/ /* initialize the library bi_alloc_p allocation function used only for exporting a bi struct, so for bi_2_nbin if define as NULL, a stdlib malloc() will be used */ void bi_init( void * (*bi_alloc_p)(size_t size)); /* release resources used by the library */ void bi_release(void); /* return >0 if the library was initialized */ int bi_is_initialized(void); /* free the list of internally allocated memory, usually used for the format functions */ void bi_flush_memory(void); /*********************************************************************************** ALLOCATION & BASIC SETTINGS *************************************************************************************/ /* create a big integer */ bi_ptr bi_new( bi_ptr result); /* create a big integer pointer */ bi_ptr bi_new_ptr(void); /* free resources allocated to the big integer */ void bi_free(const bi_ptr i); /* free resources allocated to the big integer pointer */ void bi_free_ptr(const bi_ptr i); /* return the current number of bits of the number */ long bi_length( const bi_ptr res); /* create a array */ void bi_new_array( bi_array_ptr array, const int length); /* create a array */ void bi_new_array2( bi_array_ptr array, const int length); /* free resources allocated to the big integer */ void bi_free_array(bi_array_ptr array); /* copy length pointers from the array to array */ void bi_copy_array(bi_array_ptr src, int offset_src, bi_array_ptr dest, int offset_dest, int length); // for debugging void dump_bi_array( char *field, const bi_array_ptr array); /*********************************************************************************** SAFE RANDOM *************************************************************************************/ bi_ptr compute_random_number( bi_ptr result, const bi_ptr element); #if 0 /*********************************************************************************** SAVE / LOAD *************************************************************************************/ /* load an big integer in the already open ("r") file */ void bi_load( bi_ptr bi, FILE *file); /* load an big integer array in the already open ("r") file */ void bi_load_array( bi_array_ptr array, FILE *file); /* save an big integer array in the already open ("w") file */ void bi_save_array( const bi_array_ptr array, const char *name, FILE *file); /* save an big integer in the already open ("w") file */ void bi_save( const bi_ptr bi,const char *name, FILE *file); #endif /*********************************************************************************** CONVERSION *************************************************************************************/ /* dump the big integer as hexadecimal */ char *bi_2_hex_char(const bi_ptr i); /* dump the big integer as decimal */ char *bi_2_dec_char(const bi_ptr i); /* set to the same value as */ /* := */ bi_ptr bi_set( bi_ptr i, const bi_ptr value); /* set with the value represented by given hexadecimal */ /* := */ bi_ptr bi_set_as_hex( bi_ptr i, const char *value); /* set with the value represented by given decimal */ /* := */ bi_ptr bi_set_as_dec( bi_ptr i, const char *value); /* set with the value represented by unsigned int */ /* := */ bi_ptr bi_set_as_si( bi_ptr result, const int value); /* return (long)bi_t */ long bi_get_si(const bi_ptr i); /* return the size of a network byte order representation of */ long bi_nbin_size(const bi_ptr i); /* return a BYTE * - in network byte order - and update the length */ /* the result is allocated internally */ unsigned char *bi_2_nbin( int *length, const bi_ptr i); /* return a BYTE * - in network byte order - and update the length */ /* different from bi_2_nbin: you should reserve enough memory for the storage */ void bi_2_nbin1( int *length, unsigned char *, const bi_ptr i); /* return a bi_ptr that correspond to the big endian encoded BYTE array of length */ bi_ptr bi_set_as_nbin( const unsigned long length, const unsigned char *buffer); /* convert to a byte array of length result, the beginning of this buffer is feel with '0' if needed */ void bi_2_byte_array( unsigned char *result, int length, bi_ptr bi); /* convert a bi to a openssl BIGNUM struct */ BIGNUM *bi_2_BIGNUM( const bi_ptr); /*********************************************************************************** BITS OPERATION *************************************************************************************/ /* set the bit to 1 */ bi_ptr bi_setbit( bi_ptr result, const int bit); /* := << */ bi_ptr bi_shift_left( bi_ptr result, const bi_ptr i, const int n); /* := >> */ bi_ptr bi_shift_right( bi_ptr result, const bi_ptr i, const int n); /*********************************************************************************** NUMBER THEORIE OPERATION *************************************************************************************/ /* create a random of length bits */ /* res := random( length) */ bi_ptr bi_urandom( bi_ptr res, const long length); /* res := mod */ bi_ptr bi_mod(bi_ptr res, const bi_ptr n, const bi_ptr m); /* res := mod */ bi_ptr bi_mod_si(bi_ptr res, const bi_ptr n, const long m); /* generate prime number of bits */ bi_ptr bi_generate_prime( bi_ptr i, const long length); /* return true (>0, bigger is better, but this is contextual to the plugin) if is a probably prime */ int bi_is_probable_prime( const bi_ptr i); /* result := (inverse of ) mod */ /* if the inverse exist, return >0, otherwise 0 */ int bi_invert_mod( bi_ptr result, const bi_ptr i, const bi_ptr m); /* generate a safe prime number of bits */ /* by safe we mean a prime p so that (p-1)/2 is also prime */ bi_ptr bi_generate_safe_prime( bi_ptr result, const long bit_length); /* return in the greatest common divisor of and */ /* := gcd( , ) */ bi_ptr bi_gcd( bi_ptr result, bi_ptr a, bi_ptr b); /*********************************************************************************** BASIC MATH OPERATION *************************************************************************************/ /* := result++ */ bi_ptr bi_inc(bi_ptr result); /* := result-- */ bi_ptr bi_dec(bi_ptr result); /* := - */ bi_ptr bi_negate( bi_ptr result); /* set by the multiplication of by the long */ /* := * */ bi_ptr bi_mul_si( bi_ptr result, const bi_ptr i, const long n); /* := * */ bi_ptr bi_mul( bi_ptr result, const bi_ptr i, const bi_ptr n); /* set by the division of by the long */ /* := / */ bi_ptr bi_div_si( bi_ptr result, const bi_ptr i, const long n); /* := / */ bi_ptr bi_div( bi_ptr result, const bi_ptr i, const bi_ptr n); /* set by the addition of by the long */ /* := + */ bi_ptr bi_add_si( bi_ptr result, const bi_ptr i, const long n); /* := + */ bi_ptr bi_add( bi_ptr result, const bi_ptr i, const bi_ptr n); /* := - */ bi_ptr bi_sub_si( bi_ptr result, const bi_ptr i, const long n); /* := - */ bi_ptr bi_sub( bi_ptr result, const bi_ptr i, const bi_ptr n); /* := ( ^ ) mod */ bi_ptr bi_mod_exp_si( bi_ptr result, const bi_ptr g, const bi_ptr e, const long m); /* := ( ^ ) mod */ bi_ptr bi_mod_exp( bi_ptr result, const bi_ptr g, const bi_ptr e, const bi_ptr m); /* multiple-exponentiation := mod( Multi( i, i), number of byte ) with 0 <= i <= bi_t[] is used for commodity (bi-ptr[] need allocation for each bi_ptr, something made in the stack with bi_t) */ bi_ptr bi_multi_mod_exp( bi_ptr result, const int n, const bi_t g[], const long e[], const int m); /*********************************************************************************** COMPARAISON *************************************************************************************/ /* n1n2 return positive value */ int bi_cmp( const bi_ptr n1, const bi_ptr n2); /* n1n2 return positive value */ int bi_cmp_si( const bi_ptr n1, const int n2); /* n1 == n2 return 1 (true) else return 0 */ int bi_equals( const bi_ptr n1, const bi_ptr n2); /* n1 == n2 return 1 (true) else return 0 */ int bi_equals_si( const bi_ptr n1, const int n2); #endif /*BI_H_*/ trousers-0.3.15/src/include/daa/daa_structs.h0000664000175000017510000002423013663651711020401 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef DAA_STRUCT_H_ #define DAA_STRUCT_H_ #include #include #include #include "tss/tcs.h" #include "bi.h" #include "arpa/inet.h" // for message digest #include #define init_tss_version(b) \ do {\ (b)->versionInfo.bMajor = DAA_PARAM_TSS_VERSION[0];\ (b)->versionInfo.bMinor = DAA_PARAM_TSS_VERSION[1];\ (b)->versionInfo.bRevMajor = DAA_PARAM_TSS_VERSION[2];\ (b)->versionInfo.bRevMinor = DAA_PARAM_TSS_VERSION[3];\ } while(0); BYTE *convert_alloc( TCS_CONTEXT_HANDLE tcsContext, UINT32 length, BYTE *source); BYTE *copy_alloc( TCS_CONTEXT_HANDLE tcsContext, UINT32 length, BYTE *source); void store_bi( UINT32 *length, BYTE **buffer, const bi_ptr i, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT object); /* length is in network format: big indian */ void dump_field( int length, BYTE *buffer); /******************************************************************************************** TSS_DAA_ATTRIB_COMMIT ********************************************************************************************/ typedef struct tdTSS_DAA_ATTRIB_COMMIT_internal { bi_ptr beta; bi_ptr sMu; } TSS_DAA_ATTRIB_COMMIT_internal; TSS_DAA_ATTRIB_COMMIT_internal *create_TSS_DAA_ATTRIB_COMMIT( bi_ptr beta, bi_ptr sMu); /******************************************************************************************** * TSS_DAA_SELECTED_ATTRIB * this struct is used internally and externally, only a call to internal_2_DAA_SELECTED_ATTRIB * DAA_SELECTED_ATTRIB_2_internal will change the struct to be internal or external ********************************************************************************************/ void i_2_e_TSS_DAA_SELECTED_ATTRIB( TSS_DAA_SELECTED_ATTRIB *selected_attrib); void e_2_i_TSS_DAA_SELECTED_ATTRIB( TSS_DAA_SELECTED_ATTRIB *selected_attrib); /* work ONLY with internal format */ BYTE *to_bytes_TSS_DAA_SELECTED_ATTRIB_internal( int *length, TSS_DAA_SELECTED_ATTRIB *selected_attrib); /* create a TSS_DAA_SELECTED_ATTRIB of length with given selected attributes. example of selections of the second and third attributes upon 5: create_TSS_DAA_SELECTED_ATTRIB( &selected_attrib, 5, 0, 1, 1, 0, 0); */ void create_TSS_DAA_SELECTED_ATTRIB( TSS_DAA_SELECTED_ATTRIB *attrib, int length, ...); /******************************************************************************************** * DAA PRIVATE KEY ********************************************************************************************/ /** * DAA private key. Contains p', q' and the product of it, where n = p*q, p = * 2*p'+1 and q = 2*q'+1. n is part of the public key. * (from com.ibm.zurich.tcg.daa.issuer.DAAPrivateKey.java) */ typedef struct { bi_ptr p_prime; bi_ptr q_prime; bi_ptr productPQprime; } DAA_PRIVATE_KEY_internal; /** * allocate: ret->p_prime * ret->q_prime * ret->productPQprime */ DAA_PRIVATE_KEY_internal *create_TSS_DAA_PRIVATE_KEY( bi_ptr pPrime, bi_ptr qPrime ); #if 0 int save_DAA_PRIVATE_KEY( FILE *file, const DAA_PRIVATE_KEY_internal *private_key ); DAA_PRIVATE_KEY_internal *load_DAA_PRIVATE_KEY( FILE *file ); TSS_DAA_PRIVATE_KEY* i_2_e_TSS_DAA_PRIVATE_KEY( DAA_PRIVATE_KEY_internal *private_key_internal, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT object ); DAA_PRIVATE_KEY_internal *e_2_i_TSS_DAA_PRIVATE_KEY( TSS_DAA_PRIVATE_KEY *private_key ); #endif /******************************************************************************************** * TSS_DAA_PK ********************************************************************************************/ typedef struct tdTSS_DAA_PK_internal { bi_ptr modulus; bi_ptr capitalS; bi_ptr capitalZ; bi_ptr capitalR0; bi_ptr capitalR1; bi_ptr gamma; bi_ptr capitalGamma; bi_ptr rho; bi_array_ptr capitalRReceiver; bi_array_ptr capitalRIssuer; bi_array_ptr capitalY; int issuerBaseNameLength; BYTE *issuerBaseName; // capitalSprime calculated at each init of this structure as : // (capitalS ^ ( 1 << DAA_PARAM_SIZE_SPLIT_EXPONENT)) % modulus bi_ptr capitalSprime; } TSS_DAA_PK_internal; TSS_DAA_PK_internal *create_DAA_PK( const bi_ptr modulus, const bi_ptr capitalS, const bi_ptr capitalZ, const bi_ptr capitalR0, const bi_ptr capitalR1, const bi_ptr gamma, const bi_ptr capitalGamma, const bi_ptr rho, const bi_array_ptr capitalRReceiver, const bi_array_ptr capitalRIssuer, int issuerBaseNameLength, BYTE * const issuerBaseName); /* * create anf feel a TSS_DAA_PK structures */ TSS_DAA_PK_internal *e_2_i_TSS_DAA_PK( TSS_DAA_PK *pk ); TSS_DAA_PK *i_2_e_TSS_DAA_PK( TSS_DAA_PK_internal *pk_internal, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT param_alloc ); #if 0 /* moved to daa_debug.h */ int save_DAA_PK_internal( FILE *file, const TSS_DAA_PK_internal *pk_internal ); TSS_DAA_PK_internal *load_DAA_PK_internal( FILE *file ); #endif void dump_DAA_PK_internal( char *name, TSS_DAA_PK_internal *pk_internal ); TPM_DAA_ISSUER *convert2issuer_settings( TSS_DAA_PK_internal *pk_internal ); void free_TSS_DAA_PK_internal( TSS_DAA_PK_internal *pk_internal ); void free_TSS_DAA_PK( TSS_DAA_PK *pk); BYTE *issuer_2_byte_array( TPM_DAA_ISSUER *tpm_daa_issuer, int *length ); /******************************************************************************************** * TSS_DAA_PK_PROOF ********************************************************************************************/ typedef struct tdTSS_DAA_PK_PROOF_internal { BYTE *challenge; int length_challenge; bi_array_ptr *response; int length_response; } TSS_DAA_PK_PROOF_internal; TSS_DAA_PK_PROOF_internal *create_DAA_PK_PROOF( BYTE* const challenge, const int length_challenge, bi_array_ptr *response, int length_reponse); /* * create anf feel a TSS_DAA_PK structures */ TSS_DAA_PK *TSS_convert_DAA_PK_PROOF( TSS_DAA_PK_PROOF_internal *proof ); #if 0 int save_DAA_PK_PROOF_internal( FILE *file, TSS_DAA_PK_PROOF_internal *pk_internal ); TSS_DAA_PK_PROOF_internal *load_DAA_PK_PROOF_internal( FILE *file ); #endif TSS_DAA_PK_PROOF_internal *e_2_i_TSS_DAA_PK_PROOF( TSS_DAA_PK_PROOF *pk_proof ); TSS_DAA_PK_PROOF *i_2_e_TSS_DAA_PK_PROOF( TSS_DAA_PK_PROOF_internal*pk_internal_proof, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT param_alloc ); /* * Encode the DAA_PK like java.security.Key#getEncoded */ BYTE *encoded_DAA_PK_internal( int *result_length, const TSS_DAA_PK_internal *pk ); /******************************************************************************************** * KEY PAIR WITH PROOF ********************************************************************************************/ typedef struct tdKEY_PAIR_WITH_PROOF_internal { TSS_DAA_PK_internal *pk; DAA_PRIVATE_KEY_internal *private_key; TSS_DAA_PK_PROOF_internal *proof; } KEY_PAIR_WITH_PROOF_internal; #if 0 /* moved to daa_debug.h */ int save_KEY_PAIR_WITH_PROOF( FILE *file, KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof ); KEY_PAIR_WITH_PROOF_internal *load_KEY_PAIR_WITH_PROOF( FILE *file ); #endif TSS_DAA_KEY_PAIR *get_TSS_DAA_KEY_PAIR( KEY_PAIR_WITH_PROOF_internal *key_pair_with_proof, void * (*daa_alloc)(size_t size, TSS_HOBJECT object), TSS_HOBJECT param_alloc ); /******************************************************************************************** * TSS_DAA_PSEUDONYM_PLAIN ********************************************************************************************/ typedef struct { bi_ptr nV; } TSS_DAA_PSEUDONYM_PLAIN_internal; TSS_DAA_PSEUDONYM_PLAIN_internal *create_TSS_DAA_PSEUDONYM_PLAIN( bi_ptr nV ); /******************************************************************************************** * TSS_DAA_PSEUDONYM_ENCRYPTED ********************************************************************************************/ typedef struct { bi_ptr sTau; struct tdCS_ENCRYPTION_RESULT *cs_enc_result; } TSS_DAA_PSEUDONYM_ENCRYPTED_internal; /******************************************************************************************** * TSS_DAA_SIGNATURE ********************************************************************************************/ typedef struct { bi_ptr zeta; bi_ptr capitalT; int challenge_length; BYTE *challenge; int nonce_tpm_length; BYTE *nonce_tpm; bi_ptr sV; bi_ptr sF0; bi_ptr sF1; bi_ptr sE; int sA_length; bi_array_ptr sA; } TSS_DAA_SIGNATURE_internal; TSS_DAA_SIGNATURE_internal *e_2_i_TSS_DAA_SIGNATURE( TSS_DAA_SIGNATURE*signature ); void free_TSS_DAA_SIGNATURE_internal( TSS_DAA_SIGNATURE_internal *signature ); /******************************************************************************************** * TSS_DAA_JOIN_ISSUER_SESSION ********************************************************************************************/ typedef struct td_TSS_DAA_JOIN_ISSUER_SESSION_internal { TPM_DAA_ISSUER *issuerAuthKey; TSS_DAA_PK_PROOF_internal *issuerKeyPair; TSS_DAA_IDENTITY_PROOF *identityProof; bi_ptr capitalUprime; int daaCounter; int nonceIssuerLength; BYTE *nonceIssuer; int nonceEncryptedLength; BYTE *nonceEncrypted; } TSS_DAA_JOIN_ISSUER_SESSION_internal; /******************************************************************************************** TSS_DAA_CRED_ISSUER ********************************************************************************************/ #if 0 TSS_DAA_CRED_ISSUER *load_TSS_DAA_CRED_ISSUER( FILE *file); int save_TSS_DAA_CRED_ISSUER( FILE *file, TSS_DAA_CRED_ISSUER *credential); #endif /******************************************************************************************** TSS_DAA_CREDENTIAL ********************************************************************************************/ #if 0 TSS_DAA_CREDENTIAL *load_TSS_DAA_CREDENTIAL( FILE *file); int save_TSS_DAA_CREDENTIAL( FILE *file, TSS_DAA_CREDENTIAL *credential ); #endif /******************************************************************************************** TPM_DAA_ISSUER ********************************************************************************************/ void free_TPM_DAA_ISSUER( TPM_DAA_ISSUER *tpm_daa_issuer); #endif /*DAA_STRUCT_H_*/ trousers-0.3.15/src/include/daa/anonymity_revocation.h0000664000175000017510000000257513663651711022355 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef ANONYMITY_REVOCATION_H_ #define ANONYMITY_REVOCATION_H_ #include "bi.h" #include "daa_structs.h" /** * Cramer Shoup public key (CSPublicKey.java) */ typedef struct tdCS_PUBLIC_KEY { bi_ptr eta; bi_ptr lambda1; bi_ptr lambda2; bi_ptr lambda3; } CS_PUBLIC_KEY; typedef struct tdCS_ENCRYPTION_RESULT { bi_ptr c1; bi_ptr c2; bi_ptr c3; bi_ptr c4; } CS_ENCRYPTION_RESULT; CS_ENCRYPTION_RESULT *create_CS_ENCRYPTION_RESULT( bi_ptr c1, bi_ptr c2, bi_ptr c3, bi_ptr c4); /* * Cramer-Shoup Encryption Result including randomness. * * from com.ibm.zurich.tcg.daa.anonymityrevocationCSEncryptionResultRandomness */ typedef struct tdCS_ENCRYPTION_RESULT_RANDOMNESS { bi_ptr randomness; CS_ENCRYPTION_RESULT *result; } CS_ENCRYPTION_RESULT_RANDOMNESS; /* * Cramer-Shoup EncryptionProof * from com.ibm.zurich.tcg.daa.anonymityrevocation.CSEncryptionProof */ CS_ENCRYPTION_RESULT_RANDOMNESS *compute_ecryption_proof( const bi_ptr msg, const bi_ptr delta1, const bi_ptr delta2, const bi_ptr delta3, const bi_ptr randomness, const CS_PUBLIC_KEY *key, const struct tdTSS_DAA_PK_internal *daa_key, const BYTE *condition, const int conditionLength, const EVP_MD *messageDigest); #endif /*ANONYMITY_REVOCATION_H_*/ trousers-0.3.15/src/include/daa/bi_openssl.h0000664000175000017510000002173313663651711020227 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef BI_OPENSSL_ #define BI_OPENSSL_ #include #include typedef struct bignum_st bi_t[1]; typedef struct bignum_st *bi_ptr; extern BN_CTX *context; INLINE_DECL bi_ptr bi_new(bi_ptr result) { BN_init( result); return result; } /* create a big integer pointer */ INLINE_DECL bi_ptr bi_new_ptr(void) { return BN_new(); } /* free resources allocated to the big integer */ INLINE_DECL void bi_free(const bi_ptr i) { BN_free( i); } /* free resources allocated to the big integer pointer */ INLINE_DECL void bi_free_ptr(const bi_ptr i) { BN_free( i); } /* := result++ */ INLINE_DECL bi_ptr bi_inc(bi_ptr result) { BN_add_word( result, 1); return result; } /* := result-- */ INLINE_DECL bi_ptr bi_dec(bi_ptr result) { BN_sub_word( result, 1); return result; } /* return the current number of bits of the number */ INLINE_DECL long bi_length( const bi_ptr res) { return BN_num_bits( res); } /*********************************************************************************** BASIC MATH OPERATION *************************************************************************************/ /* := - */ INLINE_DECL bi_ptr bi_negate( bi_ptr result) { BIGNUM *n = result; n->neg = ( n->neg == 0 ? 1 : 0); return result; } INLINE_DECL bi_ptr bi_mul_si( bi_ptr result, const bi_ptr i, const long n) { BN_copy( result, i); BN_mul_word( result, n); return result; } /* := * */ INLINE_DECL bi_ptr bi_mul( bi_ptr result, const bi_ptr i, const bi_ptr n) { BN_mul( result, i, n, context); return result; } INLINE_DECL bi_ptr bi_add_si( bi_ptr result, const bi_ptr i, const long n) { BN_copy( result, i); BN_add_word( result, n); return result; } /* := + */ INLINE_DECL bi_ptr bi_add( bi_ptr result, const bi_ptr i, const bi_ptr n) { BN_add( result, i, n); return result; } /* := - */ INLINE_DECL bi_ptr bi_sub_si( bi_ptr result, const bi_ptr i, const long n) { // n should be unsigned BN_copy( result, i); // result := i BN_sub_word( result, n); // result := result - n return result; } /* := - */ INLINE_DECL bi_ptr bi_sub( bi_ptr result, const bi_ptr i, const bi_ptr n) { BN_sub( result, i, n); return result; } /* := ( ^ ) mod */ INLINE_DECL bi_ptr bi_mod_exp( bi_ptr result, const bi_ptr g, const bi_ptr e, const bi_ptr m) { BN_mod_exp( result, g, e, m, context); // result := (g ^ e) mod bi_m return result; } /* set by the division of by the long */ /* := / */ INLINE_DECL bi_ptr bi_div_si( bi_ptr result, const bi_ptr i, const long n) { BN_copy( result, i); BN_div_word( result, n); return result; } /* := / */ INLINE_DECL bi_ptr bi_div( bi_ptr result, const bi_ptr i, const bi_ptr n) { BN_div( result, NULL, i, n, context); return result; } /*********************************************************************************** COMPARAISON *************************************************************************************/ /* n1n2 return positive value */ INLINE_DECL int bi_cmp( const bi_ptr n1, const bi_ptr n2) { return BN_cmp( n1, n2); } /* n1n2 return positive value */ INLINE_DECL int bi_cmp_si( const bi_ptr n1, const int n2) { BIGNUM *temp = BN_new(); BN_set_word( temp, n2); int res = BN_cmp( n1, temp); BN_free( temp); return res; } /* n1 == n2 return 1 (true) * else return 0 */ INLINE_DECL int bi_equals( const bi_ptr n1, const bi_ptr n2) { return BN_cmp( n1, n2) == 0 ? 1 :0; } /* n1 == n2 return 1 (true) * else return 0 */ INLINE_DECL int bi_equals_si( const bi_ptr n1, const int n2) { return BN_is_word( n1, n2); } /*********************************************************************************** CONVERSIONS *************************************************************************************/ INLINE_DECL char *bi_2_hex_char(const bi_ptr i) { char *result = BN_bn2hex( i); if( result == NULL) { return NULL; } list_add( allocs, result); return result; } INLINE_DECL char *bi_2_dec_char(const bi_ptr i) { char *result = BN_bn2dec( i); if( result == NULL) { return NULL; } list_add( allocs, result); return result; } INLINE_DECL bi_ptr bi_set( bi_ptr result, const bi_ptr value) { BN_copy( result, value); return result; } INLINE_DECL bi_ptr bi_set_as_hex( bi_ptr result, const char *value) { BN_hex2bn( &result, value); return result; } INLINE_DECL bi_ptr bi_set_as_dec( bi_ptr result, const char *value) { BN_dec2bn( &result, value); return result; } /* set with the value represented by unsigned int */ /* := */ INLINE_DECL bi_ptr bi_set_as_si( bi_ptr result, const int value) { if( value < 0) { BN_set_word( result, -value); result->neg=1; } else BN_set_word( result, value); return result; } /* return (long)bi_t */ INLINE_DECL long bi_get_si(const bi_ptr i) { long result = BN_get_word( i); if( i->neg == 1) { return -result; } return result; } /* return the size of a network byte order representation of */ INLINE_DECL long bi_nbin_size(const bi_ptr i) { return BN_num_bytes( i); } /* return a BYTE * in network byte order - big endian - and update the length */ INLINE_DECL unsigned char *bi_2_nbin( int *length, const bi_ptr i) { unsigned char *ret; *length = BN_num_bytes( i); ret = (unsigned char *)bi_alloc( *length * 2); if( ret == NULL) return NULL; BN_bn2bin( i, ret); return ret; } /* return a BYTE * - in network byte order - and update the length */ /* different from bi_2_nbin: you should reserve enough memory for the storage */ INLINE_DECL void bi_2_nbin1( int *length, unsigned char *buffer, const bi_ptr i) { *length = BN_num_bytes( i); BN_bn2bin( i, buffer); } /* return a bi_ptr that correspond to the big endian encoded BYTE array of length */ INLINE_DECL bi_ptr bi_set_as_nbin( const unsigned long length, const unsigned char *buffer) { bi_ptr ret_bi = bi_new_ptr(); if( ret_bi == NULL) return NULL; if( BN_bin2bn( buffer, length, ret_bi) == NULL) { bi_free( ret_bi); return NULL; } return ret_bi; } /* convert a bi to a openssl BIGNUM struct */ INLINE_DECL BIGNUM *bi_2_BIGNUM( const bi_ptr i) { return i; } /* set with the value represented by the given openssl BIGNUM struct */ INLINE_DECL bi_ptr bi_set_as_BIGNUM( bi_ptr i, BIGNUM *bn) { return bi_set( i, bn); } /*********************************************************************************** BITS OPERATION *************************************************************************************/ /* set the bit to 1 */ INLINE_DECL bi_ptr bi_setbit(bi_ptr result, const int bit) { BN_set_bit( result, bit); return result; } /* := << */ INLINE_DECL bi_ptr bi_shift_left( bi_ptr result, const bi_ptr i, const int n) { BN_lshift( result, i, n); return result; } /* := >> */ INLINE_DECL bi_ptr bi_shift_right( bi_ptr result, const bi_ptr i, const int n) { BN_rshift( result, i, n); return result; } /* create a random of length bits */ /* res := random( length) */ INLINE_DECL bi_ptr bi_urandom( bi_ptr result, const long length) { /* * will be a generated cryptographically strong pseudo-random number of length * */ BN_rand( result, length, -1, 0); return result; } /* res := mod */ INLINE_DECL bi_ptr bi_mod_si( bi_ptr result, const bi_ptr n, const long m) { BIGNUM *mod = BN_new(); BN_set_word( mod, m); BN_mod( result, n, mod, context); BN_free( mod); return result; } /* res := mod */ INLINE_DECL bi_ptr bi_mod( bi_ptr result, const bi_ptr n, const bi_ptr m) { BN_mod( result, n, m, context); if( result->neg == 1) { result->neg=0; BN_sub( result, m, result); } return result; } /* result := (inverse of ) mod */ /* if the inverse exist, return >0, otherwise 0 */ INLINE_DECL int bi_invert_mod( bi_ptr result, const bi_ptr i, const bi_ptr m) { while( ERR_get_error() != 0); BN_mod_inverse( result, i, m, context); return ERR_get_error() == 0 ? 1 : 0; } /* generate a prime number of bits */ INLINE_DECL bi_ptr bi_generate_prime( bi_ptr result, const long bit_length) { BN_generate_prime(result, bit_length, 0, NULL, NULL, NULL, NULL); return result; } /* generate a safe prime number of bits */ /* by safe we mean a prime p so that (p-1)/2 is also prime */ INLINE_DECL bi_ptr bi_generate_safe_prime( bi_ptr result, const long bit_length) { BN_generate_prime(result, bit_length, 1, NULL, NULL, NULL, NULL); return result; } /* return in the greatest common divisor of and */ /* := gcd( , ) */ INLINE_DECL bi_ptr bi_gcd( bi_ptr result, bi_ptr a, bi_ptr b) { BN_gcd( result, a, b, context); return result; } #endif /*BI_OPENSSL_*/ trousers-0.3.15/src/include/daa/issuer.h0000664000175000017510000000324513663651711017402 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006-2007 * */ #ifndef __ISSUER_H__ #define __ISSUER_H__ #include "daa/daa_structs.h" #include "daa/daa_parameter.h" #include "tsplog.h" TSS_RESULT generate_key_pair(int num_attributes_issuer, int num_attributes_receiver, int base_nameLength, BYTE *base_name, KEY_PAIR_WITH_PROOF_internal **key_pair_with_proof ); TSS_DAA_PK_PROOF_internal *generate_proof( const bi_ptr product_PQ_prime, const TSS_DAA_PK_internal *public_key, const bi_ptr xz, const bi_ptr x0, const bi_ptr x1, bi_array_ptr x); #if 0 TSPICALL Tspi_DAA_IssueInit_internal( TSS_HDAA hDAA, // in TSS_HKEY issuerAuthPK, // in TSS_HKEY issuerKeyPair, // in TSS_DAA_IDENTITY_PROOF identityProof, // in UINT32 capitalUprimeLength, // in BYTE* capitalUprime, // in UINT32 daaCounter, // in UINT32* nonceIssuerLength, // out BYTE** nonceIssuer, // out UINT32* authenticationChallengeLength, // out BYTE** authenticationChallenge, // out TSS_DAA_JOIN_ISSUER_SESSION* joinSession // out ); TSPICALL Tspi_DAA_IssueCredential_internal( TSS_HDAA hDAA, // in UINT32 attributesIssuerLength, // in BYTE** attributesIssuer, // in TSS_DAA_CREDENTIAL_REQUEST credentialRequest, // in TSS_DAA_JOIN_ISSUER_SESSION joinSession, // in TSS_DAA_CRED_ISSUER* credIssuer // out ); #endif TSS_RESULT compute_join_challenge_issuer( TSS_DAA_PK_internal *pk_intern, bi_ptr v_prime_prime, bi_ptr capitalA, bi_ptr capital_Atilde, UINT32 nonceReceiverLength, BYTE *nonceReceiver, UINT32 *c_primeLength, BYTE **c_prime); // out allocation #endif trousers-0.3.15/src/include/tcsd_wrap.h0000664000175000017510000001210013663651711017317 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _TCSD_WRAP_H_ #define _TCSD_WRAP_H_ #include "tcs_tsp.h" enum TCSP_PACKET_TYPE { TCSD_PACKET_TYPE_BYTE, TCSD_PACKET_TYPE_BOOL, TCSD_PACKET_TYPE_UINT16, TCSD_PACKET_TYPE_UINT32, TCSD_PACKET_TYPE_PBYTE, TCSD_PACKET_TYPE_KEY, TCSD_PACKET_TYPE_NONCE, TCSD_PACKET_TYPE_AUTH, TCSD_PACKET_TYPE_DIGEST, TCSD_PACKET_TYPE_UUID, TCSD_PACKET_TYPE_ENCAUTH, TCSD_PACKET_TYPE_VERSION, /*2004-05-12 Seiji Munetoh added */ TCSD_PACKET_TYPE_KM_KEYINFO, TCSD_PACKET_TYPE_KM_KEYINFO2, TCSD_PACKET_TYPE_LOADKEY_INFO, TCSD_PACKET_TYPE_PCR_EVENT, TCSD_PACKET_TYPE_COUNTER_VALUE, TCSD_PACKET_TYPE_UINT64, TCSD_PACKET_TYPE_SECRET }; enum TCSD_ORD { TCSD_ORD_ERROR = 0, /* 4.5 TCS Contest Manager */ TCSD_ORD_OPENCONTEXT = 1, TCSD_ORD_CLOSECONTEXT = 2, TCSD_ORD_FREEMEMORY = 3, TCSD_ORD_TCSGETCAPABILITY = 4, /* Tcsi_GatCapability */ /* 4.6 TCS Key Credential Manager */ TCSD_ORD_REGISTERKEY = 5, TCSD_ORD_UNREGISTERKEY = 6, TCSD_ORD_ENUMREGISTEREDKEYS = 7, TCSD_ORD_GETREGISTEREDKEY = 8, TCSD_ORD_GETREGISTEREDKEYBLOB = 9, TCSD_ORD_GETREGISTEREDKEYBYPUBLICINFO = 10, TCSD_ORD_LOADKEYBYBLOB = 11, TCSD_ORD_LOADKEYBYUUID = 12, TCSD_ORD_EVICTKEY = 13, TCSD_ORD_CREATEWRAPKEY = 14, TCSD_ORD_GETPUBKEY = 15, TCSD_ORD_MAKEIDENTITY = 16, /* 4.7 TCS Event Manager */ TCSD_ORD_LOGPCREVENT = 17, TCSD_ORD_GETPCREVENT = 18, TCSD_ORD_GETPCREVENTBYPCR = 19, TCSD_ORD_GETPCREVENTLOG = 20, /* 4.8 TCS Audit Manager */ /* 4.9 TCS TPM Parametor Block Generator */ TCSD_ORD_SETOWNERINSTALL = 21, TCSD_ORD_TAKEOWNERSHIP = 22, TCSD_ORD_OIAP = 23, TCSD_ORD_OSAP = 24, TCSD_ORD_CHANGEAUTH = 25, TCSD_ORD_CHANGEAUTHOWNER = 26, TCSD_ORD_CHANGEAUTHASYMSTART = 27, TCSD_ORD_CHANGEAUTHASYMFINISH = 28, TCSD_ORD_TERMINATEHANDLE = 29, TCSD_ORD_ACTIVATETPMIDENTITY = 30, TCSD_ORD_EXTEND = 31, TCSD_ORD_PCRREAD= 32, TCSD_ORD_QUOTE = 33, TCSD_ORD_DIRWRITEAUTH = 34, TCSD_ORD_DIRREAD = 35, TCSD_ORD_SEAL = 36, TCSD_ORD_UNSEAL = 37, TCSD_ORD_UNBIND = 38, TCSD_ORD_CREATEMIGRATIONBLOB = 39, TCSD_ORD_CONVERTMIGRATIONBLOB = 40, TCSD_ORD_AUTHORIZEMIGRATIONKEY = 41, TCSD_ORD_CERTIFYKEY = 42, TCSD_ORD_SIGN = 43, TCSD_ORD_GETRANDOM =44, TCSD_ORD_STIRRANDOM =45, TCSD_ORD_GETCAPABILITY =46, /* Tcsip_GatCapability */ TCSD_ORD_GETCAPABILITYSIGNED = 47, TCSD_ORD_GETCAPABILITYOWNER = 48, TCSD_ORD_CREATEENDORSEMENTKEYPAIR = 49, TCSD_ORD_READPUBEK = 50, TCSD_ORD_DISABLEPUBEKREAD = 51, TCSD_ORD_OWNERREADPUBEK =52, TCSD_ORD_SELFTESTFULL = 53, TCSD_ORD_CERTIFYSELFTEST = 54, TCSD_ORD_CONTINUESELFTEST = 55, TCSD_ORD_GETTESTRESULT = 56, TCSD_ORD_OWNERSETDISABLE = 57, TCSD_ORD_OWNERCLEAR = 58, TCSD_ORD_DISABLEOWNERCLEAR = 59, TCSD_ORD_FORCECLEAR = 60, TCSD_ORD_DISABLEFORCECLEAR = 61, TCSD_ORD_PHYSICALDISABLE = 62, TCSD_ORD_PHYSICALENABLE = 63, TCSD_ORD_PHYSICALSETDEACTIVATED = 64, TCSD_ORD_SETTEMPDEACTIVATED = 65, TCSD_ORD_PHYSICALPRESENCE = 66, TCSD_ORD_FIELDUPGRADE = 67, TCSD_ORD_SETRIDIRECTION = 68, TCSD_ORD_CREATEMAINTENANCEARCHIVE = 69, TCSD_ORD_LOADMAINTENANCEARCHIVE = 70, TCSD_ORD_KILLMAINTENANCEFEATURE = 71, TCSD_ORD_LOADMANUFACTURERMAINTENANCEPUB = 72, TCSD_ORD_READMANUFACTURERMAINTENANCEPUB = 73, /* DAA */ TCSD_ORD_DAAJOIN = 74, TCSD_ORD_DAASIGN = 75, TCSD_ORD_SETCAPABILITY = 76, TCSD_ORD_RESETLOCKVALUE = 77, TCSD_ORD_PCRRESET = 78, TCSD_ORD_READCOUNTER = 79, TCSD_ORD_CREATECOUNTER = 80, TCSD_ORD_INCREMENTCOUNTER = 81, TCSD_ORD_RELEASECOUNTER = 82, TCSD_ORD_RELEASECOUNTEROWNER = 83, TCSD_ORD_READCURRENTTICKS = 84, TCSD_ORD_TICKSTAMPBLOB = 85, TCSD_ORD_GETCREDENTIAL = 86, /* NV */ TCSD_ORD_NVDEFINEORRELEASESPACE = 87, TCSD_ORD_NVWRITEVALUE = 88, TCSD_ORD_NVWRITEVALUEAUTH = 89, TCSD_ORD_NVREADVALUE = 90, TCSD_ORD_NVREADVALUEAUTH = 91, TCSD_ORD_ESTABLISHTRANSPORT = 92, TCSD_ORD_EXECUTETRANSPORT = 93, TCSD_ORD_RELEASETRANSPORTSIGNED = 94, /* Audit */ TCSD_ORD_SETORDINALAUDITSTATUS = 95, TCSD_ORD_GETAUDITDIGEST = 96, TCSD_ORD_GETAUDITDIGESTSIGNED = 97, TCSD_ORD_SEALX = 98, TCSD_ORD_SETOPERATORAUTH = 99, TCSD_ORD_OWNERREADINTERNALPUB = 100, TCSD_ORD_ENUMREGISTEREDKEYS2 = 101, TCSD_ORD_SETTEMPDEACTIVATED2 = 102, /* Delegation */ TCSD_ORD_DELEGATE_MANAGE = 103, TCSD_ORD_DELEGATE_CREATEKEYDELEGATION = 104, TCSD_ORD_DELEGATE_CREATEOWNERDELEGATION = 105, TCSD_ORD_DELEGATE_LOADOWNERDELEGATION = 106, TCSD_ORD_DELEGATE_READTABLE = 107, TCSD_ORD_DELEGATE_UPDATEVERIFICATIONCOUNT = 108, TCSD_ORD_DELEGATE_VERIFYDELEGATION = 109, TCSD_ORD_CREATEREVOCABLEENDORSEMENTKEYPAIR = 110, TCSD_ORD_REVOKEENDORSEMENTKEYPAIR = 111, TCSD_ORD_MAKEIDENTITY2 = 112, TCSD_ORD_QUOTE2 = 113, /* CMK */ TCSD_ORD_CMK_SETRESTRICTIONS = 114, TCSD_ORD_CMK_APPROVEMA = 115, TCSD_ORD_CMK_CREATEKEY = 116, TCSD_ORD_CMK_CREATETICKET = 117, TCSD_ORD_CMK_CREATEBLOB = 118, TCSD_ORD_CMK_CONVERTMIGRATION = 119, TCSD_ORD_FLUSHSPECIFIC = 120, TCSD_ORD_KEYCONTROLOWNER = 121, TCSD_ORD_DSAP = 122, /* Last */ TCSD_LAST_ORD = 123 }; #define TCSD_MAX_NUM_ORDS TCSD_LAST_ORD #include "tcsd.h" #endif trousers-0.3.15/src/include/authsess.h0000664000175000017510000000266113663651711017203 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #ifndef _AUTHSESS_H_ #define _AUTHSESS_H_ struct authsess { TPM_AUTH *pAuth; TPM_AUTH auth; /* XOR masks created before each use of an OSAP session */ TPM_ENCAUTH encAuthUse; TPM_ENCAUTH encAuthMig; TSS_HCONTEXT tspContext; TPM_COMMAND_CODE command; TSS_HOBJECT obj_parent; TSS_HPOLICY hUsageParent; UINT32 parentMode; TPM_SECRET parentSecret; TSS_CALLBACK cb_xor, cb_hmac, cb_sealx; TPM_ENTITY_TYPE entity_type; UINT32 entityValueSize; BYTE *entityValue; TSS_HOBJECT obj_child; TSS_HPOLICY hUsageChild, hMigChild; UINT32 uMode, mMode; /* Created during OSAP or DSAP protocol initiation */ TPM_NONCE nonceOddxSAP; TPM_NONCE nonceEvenxSAP; TPM_HMAC sharedSecret; //MUTEX_DECLARE(lock); //struct authsess *next; }; TSS_RESULT authsess_oiap_get(TSS_HOBJECT, TPM_COMMAND_CODE, TPM_DIGEST *, TPM_AUTH *); TSS_RESULT authsess_oiap_put(TPM_AUTH *, TPM_DIGEST *); TSS_RESULT authsess_xsap_init(TSS_HCONTEXT, TSS_HOBJECT, TSS_HOBJECT, TSS_BOOL, TPM_COMMAND_CODE, TPM_ENTITY_TYPE, struct authsess **); TSS_RESULT authsess_xsap_hmac(struct authsess *, TPM_DIGEST *); TSS_RESULT authsess_xsap_verify(struct authsess *, TPM_DIGEST *); void authsess_free(struct authsess *); #define TSS_AUTH_POLICY_REQUIRED TRUE #define TSS_AUTH_POLICY_NOT_REQUIRED FALSE #endif trousers-0.3.15/src/include/memmgr.h0000664000175000017510000000137213663651711016626 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _MEMMGR_H_ #define _MEMMGR_H_ /* * For each TSP context, there is one memTable, which holds a list of memEntry's, * each of which holds a pointer to some malloc'd memory that's been returned to * the user. The memTable also can point to other memTable's which would be * created if multiple TSP contexts were opened. * */ struct memEntry { void *memPointer; struct memEntry *nextEntry; }; struct memTable { TSS_HCONTEXT tspContext; struct memEntry *entries; struct memTable *nextTable; }; MUTEX_DECLARE_INIT(memtable_lock); struct memTable *SpiMemoryTable = NULL; #endif trousers-0.3.15/src/include/trousers/0000775000175000017510000000000013663651711017054 5ustar deboradeboratrousers-0.3.15/src/include/trousers/trousers.h0000664000175000017510000004041513663651711021117 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _TROUSERS_H_ #define _TROUSERS_H_ #ifdef __cplusplus extern "C" { #endif /* * Utility functions offered by trousers for use in your TSS app. * * All functions listed here are specific to the trousers TSS and should not be * used in applications that are intended to be portable. * */ /* Blob unloading functions */ void Trspi_UnloadBlob(UINT64 *offset, size_t size, BYTE *container, BYTE *object); void Trspi_UnloadBlob_BYTE(UINT64 *offset, BYTE *dataOut, BYTE *blob); void Trspi_UnloadBlob_BOOL(UINT64 *offset, TSS_BOOL *dataOut, BYTE *blob); void Trspi_UnloadBlob_UINT64(UINT64 *offset, UINT64 *out, BYTE *blob); void Trspi_UnloadBlob_UINT32(UINT64 *offset, UINT32 *out, BYTE *blob); void Trspi_UnloadBlob_UINT16(UINT64 *offset, UINT16 *out, BYTE *blob); void Trspi_UnloadBlob_TSS_VERSION(UINT64 *offset, BYTE *blob, TSS_VERSION *out); void Trspi_UnloadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION *out); TSS_RESULT Trspi_UnloadBlob_PCR_INFO(UINT64 *offset, BYTE *blob, TCPA_PCR_INFO *pcr); TSS_RESULT Trspi_UnloadBlob_PCR_INFO_LONG(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_LONG *pcr); TSS_RESULT Trspi_UnloadBlob_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_SHORT *pcr); TSS_RESULT Trspi_UnloadBlob_PCR_SELECTION(UINT64 *offset, BYTE *blob, TCPA_PCR_SELECTION *pcr); TSS_RESULT Trspi_UnloadBlob_PCR_COMPOSITE(UINT64 *offset, BYTE *blob, TCPA_PCR_COMPOSITE *out); TSS_RESULT Trspi_UnloadBlob_STORED_DATA(UINT64 *offset, BYTE *blob, TCPA_STORED_DATA *data); void Trspi_UnloadBlob_KEY_FLAGS(UINT64 *offset, BYTE *blob, TCPA_KEY_FLAGS *flags); TSS_RESULT Trspi_UnloadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyParms); void Trspi_UnloadBlob_UUID(UINT64 *offset, BYTE *blob, TSS_UUID *uuid); TSS_RESULT Trspi_UnloadBlob_STORE_PUBKEY(UINT64 *, BYTE *, TCPA_STORE_PUBKEY *); void Trspi_UnloadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest); TSS_RESULT Trspi_UnloadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *pubKey); TSS_RESULT Trspi_UnloadBlob_KEY(UINT64 *offset, BYTE *blob, TCPA_KEY *key); TSS_RESULT Trspi_UnloadBlob_KEY12(UINT64 *offset, BYTE *blob, TPM_KEY12 *key); TSS_RESULT Trspi_UnloadBlob_MIGRATIONKEYAUTH(UINT64 *offset, BYTE *blob, TPM_MIGRATIONKEYAUTH *migAuth); TSS_RESULT Trspi_UnloadBlob_PCR_EVENT(UINT64 *offset, BYTE *blob, TSS_PCR_EVENT *event); TSS_RESULT Trspi_UnloadBlob_KM_KEYINFO(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO *info); TSS_RESULT Trspi_UnloadBlob_KM_KEYINFO2(UINT64 *offset, BYTE *blob, TSS_KM_KEYINFO2 *info); TSS_RESULT Trspi_UnloadBlob_SYMMETRIC_KEY(UINT64 *offset, BYTE *blob, TCPA_SYMMETRIC_KEY *key); TSS_RESULT Trspi_UnloadBlob_SYM_CA_ATTESTATION(UINT64 *offset, BYTE *blob, TCPA_SYM_CA_ATTESTATION *sym); TSS_RESULT Trspi_UnloadBlob_ASYM_CA_CONTENTS(UINT64 *offset, BYTE *blob, TCPA_ASYM_CA_CONTENTS *asym); TSS_RESULT Trspi_UnloadBlob_IDENTITY_REQ(UINT64 *offset, BYTE *blob, TCPA_IDENTITY_REQ *req); TSS_RESULT Trspi_UnloadBlob_IDENTITY_PROOF(UINT64 *offset, BYTE *blob, TCPA_IDENTITY_PROOF *proof); void Trspi_UnloadBlob_COUNTER_VALUE(UINT64 *offset, BYTE *blob, TPM_COUNTER_VALUE *ctr); void Trspi_UnloadBlob_CURRENT_TICKS(UINT64 *offset, BYTE *blob, TPM_CURRENT_TICKS *ticks); void Trspi_UnloadBlob_TRANSPORT_PUBLIC(UINT64 *offset, BYTE *blob, TPM_TRANSPORT_PUBLIC *t); void Trspi_UnloadBlob_NONCE(UINT64 *offset, BYTE* blob, TPM_NONCE *n); TSS_RESULT Trspi_UnloadBlob_CERTIFY_INFO(UINT64 *offset, BYTE* blob, TPM_CERTIFY_INFO *c); void Trspi_UnloadBlob_TPM_FAMILY_LABEL(UINT64 *offset, BYTE *blob, TPM_FAMILY_LABEL *label); void Trspi_UnloadBlob_TPM_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TPM_FAMILY_TABLE_ENTRY *entry); void Trspi_UnloadBlob_TPM_DELEGATE_LABEL(UINT64 *offset, BYTE *blob, TPM_DELEGATE_LABEL *label); void Trspi_UnloadBlob_TPM_DELEGATIONS(UINT64 *offset, BYTE *blob, TPM_DELEGATIONS *delegations); TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(UINT64 *offset, BYTE *blob, TPM_DELEGATE_PUBLIC *pub); TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_OWNER_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_OWNER_BLOB *owner); TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_KEY_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_KEY_BLOB *key); void Trspi_UnloadBlob_TSS_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_FAMILY_TABLE_ENTRY *entry); TSS_RESULT Trspi_UnloadBlob_TSS_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TSS_PCR_INFO_SHORT *pcr); TSS_RESULT Trspi_UnloadBlob_TSS_DELEGATION_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_DELEGATION_TABLE_ENTRY *entry); TSS_RESULT Trspi_UnloadBlob_TSS_PLATFORM_CLASS(UINT64 *offset, BYTE *blob, TSS_PLATFORM_CLASS *platClass); TSS_RESULT Trspi_UnloadBlob_CAP_VERSION_INFO(UINT64 *offset, BYTE *blob, TPM_CAP_VERSION_INFO *v); TSS_RESULT Trspi_UnloadBlob_NV_INDEX(UINT64 *offset, BYTE *blob, TPM_NV_INDEX *v); TSS_RESULT Trspi_UnloadBlob_NV_ATTRIBUTES(UINT64 *offset, BYTE *blob, TPM_NV_ATTRIBUTES *v); TSS_RESULT Trspi_UnloadBlob_NV_DATA_PUBLIC(UINT64 *offset, BYTE *blob, TPM_NV_DATA_PUBLIC *v); /* Blob loading functions */ void Trspi_LoadBlob_BOUND_DATA(UINT64 *, TCPA_BOUND_DATA, UINT32, BYTE *); void Trspi_LoadBlob_CHANGEAUTH_VALIDATE(UINT64 *, BYTE *, TPM_CHANGEAUTH_VALIDATE *); void Trspi_LoadBlob(UINT64 *offset, size_t size, BYTE *to, BYTE *from); void Trspi_LoadBlob_UINT32(UINT64 *offset, UINT32 in, BYTE *blob); void Trspi_LoadBlob_UINT16(UINT64 *offset, UINT16 in, BYTE *blob); void Trspi_LoadBlob_BYTE(UINT64 *offset, BYTE data, BYTE *blob); void Trspi_LoadBlob_BOOL(UINT64 *offset, TSS_BOOL data, BYTE *blob); void Trspi_LoadBlob_RSA_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_RSA_KEY_PARMS *parms); void Trspi_LoadBlob_TSS_VERSION(UINT64 *offset, BYTE *blob, TSS_VERSION version); void Trspi_LoadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION version); void Trspi_LoadBlob_PCR_INFO(UINT64 *offset, BYTE *blob, TCPA_PCR_INFO *pcr); void Trspi_LoadBlob_PCR_INFO_LONG(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_LONG *pcr); void Trspi_LoadBlob_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TPM_PCR_INFO_SHORT *pcr); void Trspi_LoadBlob_PCR_SELECTION(UINT64 *offset, BYTE *blob, TCPA_PCR_SELECTION *pcr); void Trspi_LoadBlob_STORED_DATA(UINT64 *offset, BYTE *blob, TCPA_STORED_DATA *data); void Trspi_LoadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *pubKey); void Trspi_LoadBlob_KEY(UINT64 *offset, BYTE *blob, TCPA_KEY *key); void Trspi_LoadBlob_KEY12(UINT64 *offset, BYTE *blob, TPM_KEY12 *key); void Trspi_LoadBlob_KEY_FLAGS(UINT64 *offset, BYTE *blob, TCPA_KEY_FLAGS *flags); void Trspi_LoadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyInfo); void Trspi_LoadBlob_STORE_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_PUBKEY *store); void Trspi_LoadBlob_UUID(UINT64 *offset, BYTE *blob, TSS_UUID uuid); void Trspi_LoadBlob_CERTIFY_INFO(UINT64 *offset, BYTE *blob, TCPA_CERTIFY_INFO *certify); void Trspi_LoadBlob_STORE_ASYMKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_ASYMKEY *store); void Trspi_LoadBlob_PCR_EVENT(UINT64 *offset, BYTE *blob, TSS_PCR_EVENT *event); void Trspi_LoadBlob_PRIVKEY_DIGEST(UINT64 *offset, BYTE *blob, TCPA_KEY *key); void Trspi_LoadBlob_PRIVKEY_DIGEST12(UINT64 *offset, BYTE *blob, TPM_KEY12 *key); void Trspi_LoadBlob_SYMMETRIC_KEY(UINT64 *offset, BYTE *blob, TCPA_SYMMETRIC_KEY *key); void Trspi_LoadBlob_SYM_CA_ATTESTATION(UINT64 *offset, BYTE *blob, TCPA_SYM_CA_ATTESTATION *sym); void Trspi_LoadBlob_ASYM_CA_CONTENTS(UINT64 *offset, BYTE *blob, TCPA_ASYM_CA_CONTENTS *asym); void Trspi_LoadBlob_IDENTITY_REQ(UINT64 *offset, BYTE *blob, TCPA_IDENTITY_REQ *req); void Trspi_LoadBlob_COUNTER_VALUE(UINT64 *offset, BYTE *blob, TPM_COUNTER_VALUE *ctr); void Trspi_LoadBlob_TRANSPORT_PUBLIC(UINT64 *offset, BYTE *blob, TPM_TRANSPORT_PUBLIC *t); void Trspi_LoadBlob_TRANSPORT_AUTH(UINT64 *offset, BYTE *blob, TPM_TRANSPORT_AUTH *t); void Trspi_LoadBlob_SIGN_INFO(UINT64 *offset, BYTE *blob, TPM_SIGN_INFO *s); void Trspi_LoadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest); void Trspi_LoadBlob_NONCE(UINT64 *offset, BYTE *blob, TPM_NONCE *n); void Trspi_LoadBlob_TPM_FAMILY_LABEL(UINT64 *offset, BYTE *blob, TPM_FAMILY_LABEL *label); void Trspi_LoadBlob_TPM_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TPM_FAMILY_TABLE_ENTRY *entry); void Trspi_LoadBlob_TPM_DELEGATE_LABEL(UINT64 *offset, BYTE *blob, TPM_DELEGATE_LABEL *label); void Trspi_LoadBlob_TPM_DELEGATIONS(UINT64 *offset, BYTE *blob, TPM_DELEGATIONS *delegations); void Trspi_LoadBlob_TPM_DELEGATE_PUBLIC(UINT64 *offset, BYTE *blob, TPM_DELEGATE_PUBLIC *pub); void Trspi_LoadBlob_TPM_DELEGATE_OWNER_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_OWNER_BLOB *owner); void Trspi_LoadBlob_TPM_DELEGATE_KEY_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_KEY_BLOB *key); void Trspi_LoadBlob_TSS_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_FAMILY_TABLE_ENTRY *entry); void Trspi_LoadBlob_TSS_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TSS_PCR_INFO_SHORT *pcr); void Trspi_LoadBlob_TSS_DELEGATION_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_DELEGATION_TABLE_ENTRY *entry); void Trspi_LoadBlob_MIGRATIONKEYAUTH(UINT64 *offset, BYTE *blob, TPM_MIGRATIONKEYAUTH *migAuth); void Trspi_LoadBlob_MSA_COMPOSITE(UINT64 *offset, BYTE *blob, TPM_MSA_COMPOSITE *msaComp); void Trspi_LoadBlob_CMK_AUTH(UINT64 *offset, BYTE *blob, TPM_CMK_AUTH *cmkAuth); void Trspi_LoadBlob_CAP_VERSION_INFO(UINT64 *offset, BYTE *blob, TPM_CAP_VERSION_INFO *v); /* Cryptographic Functions */ /* Hash @BufSize bytes at location @Buf using the algorithm @HashType. Currently only * TSS_HASH_SHA1 is a suported type, so 20 bytes will be written to @Digest */ TSS_RESULT Trspi_Hash(UINT32 HashType, UINT32 BufSize, BYTE *Buf, BYTE *Digest); typedef struct _Trspi_HashCtx { void *ctx; } Trspi_HashCtx; TSS_RESULT Trspi_HashInit(Trspi_HashCtx *c, UINT32 type); TSS_RESULT Trspi_HashUpdate(Trspi_HashCtx *c, UINT32 size, BYTE *data); TSS_RESULT Trspi_HashFinal(Trspi_HashCtx *c, BYTE *out_digest); /* Functions to support incremental hashing */ TSS_RESULT Trspi_Hash_UINT16(Trspi_HashCtx *c, UINT16 i); TSS_RESULT Trspi_Hash_UINT32(Trspi_HashCtx *c, UINT32 i); TSS_RESULT Trspi_Hash_UINT64(Trspi_HashCtx *c, UINT64 i); TSS_RESULT Trspi_Hash_DAA_PK(Trspi_HashCtx *c, TSS_DAA_PK *pk); TSS_RESULT Trspi_Hash_PUBKEY(Trspi_HashCtx *c, TCPA_PUBKEY *pubKey); TSS_RESULT Trspi_Hash_BYTE(Trspi_HashCtx *c, BYTE data); TSS_RESULT Trspi_Hash_BOOL(Trspi_HashCtx *c, TSS_BOOL data); TSS_RESULT Trspi_Hash_RSA_KEY_PARMS(Trspi_HashCtx *c, TCPA_RSA_KEY_PARMS *parms); TSS_RESULT Trspi_Hash_VERSION(Trspi_HashCtx *c, TSS_VERSION *version); TSS_RESULT Trspi_Hash_STORED_DATA(Trspi_HashCtx *c, TCPA_STORED_DATA *data); TSS_RESULT Trspi_Hash_PCR_SELECTION(Trspi_HashCtx *c, TCPA_PCR_SELECTION *pcr); TSS_RESULT Trspi_Hash_KEY(Trspi_HashCtx *c, TCPA_KEY *key); TSS_RESULT Trspi_Hash_KEY12(Trspi_HashCtx *c, TPM_KEY12 *key); TSS_RESULT Trspi_Hash_KEY_FLAGS(Trspi_HashCtx *c, TCPA_KEY_FLAGS *flags); TSS_RESULT Trspi_Hash_KEY_PARMS(Trspi_HashCtx *c, TCPA_KEY_PARMS *keyInfo); TSS_RESULT Trspi_Hash_STORE_PUBKEY(Trspi_HashCtx *c, TCPA_STORE_PUBKEY *store); TSS_RESULT Trspi_Hash_UUID(Trspi_HashCtx *c, TSS_UUID uuid); TSS_RESULT Trspi_Hash_PCR_EVENT(Trspi_HashCtx *c, TSS_PCR_EVENT *event); TSS_RESULT Trspi_Hash_PRIVKEY_DIGEST(Trspi_HashCtx *c, TCPA_KEY *key); TSS_RESULT Trspi_Hash_PRIVKEY_DIGEST12(Trspi_HashCtx *c, TPM_KEY12 *key); TSS_RESULT Trspi_Hash_SYMMETRIC_KEY(Trspi_HashCtx *c, TCPA_SYMMETRIC_KEY *key); TSS_RESULT Trspi_Hash_IDENTITY_REQ(Trspi_HashCtx *c, TCPA_IDENTITY_REQ *req); TSS_RESULT Trspi_Hash_CHANGEAUTH_VALIDATE(Trspi_HashCtx *c, TPM_CHANGEAUTH_VALIDATE *caValidate); TSS_RESULT Trspi_Hash_SYM_CA_ATTESTATION(Trspi_HashCtx *c, TCPA_SYM_CA_ATTESTATION *sym); TSS_RESULT Trspi_Hash_ASYM_CA_CONTENTS(Trspi_HashCtx *c, TCPA_ASYM_CA_CONTENTS *asym); TSS_RESULT Trspi_Hash_BOUND_DATA(Trspi_HashCtx *c, TCPA_BOUND_DATA *bd, UINT32 payloadLength); TSS_RESULT Trspi_Hash_TRANSPORT_AUTH(Trspi_HashCtx *c, TPM_TRANSPORT_AUTH *a); TSS_RESULT Trspi_Hash_TRANSPORT_LOG_IN(Trspi_HashCtx *c, TPM_TRANSPORT_LOG_IN *l); TSS_RESULT Trspi_Hash_TRANSPORT_LOG_OUT(Trspi_HashCtx *c, TPM_TRANSPORT_LOG_OUT *l); TSS_RESULT Trspi_Hash_CURRENT_TICKS(Trspi_HashCtx *c, TPM_CURRENT_TICKS *t); TSS_RESULT Trspi_Hash_SIGN_INFO(Trspi_HashCtx *c, TPM_SIGN_INFO *s); TSS_RESULT Trspi_Hash_MSA_COMPOSITE(Trspi_HashCtx *c, TPM_MSA_COMPOSITE *m); #define Trspi_Hash_DIGEST(c, d) Trspi_HashUpdate(c, TPM_SHA1_160_HASH_LEN, d) #define Trspi_Hash_NONCE(c, d) Trspi_HashUpdate(c, TPM_SHA1_160_HASH_LEN, d) #define Trspi_Hash_ENCAUTH(c, d) Trspi_HashUpdate(c, TPM_SHA1_160_HASH_LEN, d) #define Trspi_Hash_HMAC(c, d) Trspi_HashUpdate(c, TPM_SHA1_160_HASH_LEN, d) #define Trspi_Hash_SECRET(c, d) Trspi_HashUpdate(c, TPM_SHA1_160_HASH_LEN, d) UINT32 Trspi_HMAC(UINT32 HashType, UINT32 SecretSize, BYTE*Secret, UINT32 BufSize, BYTE*Buf, BYTE*hmacOut); /* RSA encrypt @dataToEncryptLen bytes at location @dataToEncrypt using public key * @publicKey of size @keysize. This data will be encrypted using OAEP padding in * the openssl library using the OAEP padding parameter "TCPA". This will allow * data encrypted with this function to be decrypted by a TPM using non-legacy keys */ int Trspi_RSA_Encrypt(unsigned char *dataToEncrypt, unsigned int dataToEncryptLen, unsigned char *encryptedData, unsigned int *encryptedDataLen, unsigned char *publicKey, unsigned int keysize); TSS_RESULT Trspi_Verify(UINT32 HashType, BYTE *pHash, UINT32 iHashLength, unsigned char *pModulus, int iKeyLength, BYTE *pSignature, UINT32 sig_len); int Trspi_RSA_Public_Encrypt(unsigned char *in, unsigned int inlen, unsigned char *out, unsigned int *outlen, unsigned char *pubkey, unsigned int pubsize, unsigned int e, int padding); #define TR_RSA_PKCS1_PADDING 1 #define TR_RSA_PKCS1_OAEP_PADDING 2 #define TR_RSA_NO_PADDING 3 #define Trspi_RSA_PKCS15_Encrypt(in,inlen,out,outlen,pubKey,pubSize) \ Trspi_RSA_Public_Encrypt(in,inlen,out,outlen,pubKey,pubSize,65537,TR_RSA_PKCS1_PADDING) #define Trspi_RSA_OAEP_Encrypt(in,inlen,out,outlen,pubKey,pubSize) \ Trspi_RSA_Public_Encrypt(in,inlen,out,outlen,pubKey,pubSize,65537, \ TR_RSA_PKCS1_OAEP_PADDING) #define Trspi_TPM_RSA_OAEP_Encrypt(in,inlen,out,outlen,pubKey,pubSize) \ Trspi_RSA_Encrypt(in,inlen,out,outlen,pubKey,pubSize) /* Symmetric Encryption */ TSS_RESULT Trspi_Encrypt_ECB(UINT16 alg, BYTE *key, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len); TSS_RESULT Trspi_Decrypt_ECB(UINT16 alg, BYTE *key, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len); #define TR_SYM_MODE_ECB 1 #define TR_SYM_MODE_CBC 2 #define TR_SYM_MODE_CTR 3 #define TR_SYM_MODE_OFB 4 TSS_RESULT Trspi_SymEncrypt(UINT16 alg, UINT16 mode, BYTE *key, BYTE *iv, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len); TSS_RESULT Trspi_SymDecrypt(UINT16 alg, UINT16 mode, BYTE *key, BYTE *iv, BYTE *in, UINT32 in_len, BYTE *out, UINT32 *out_len); TSS_RESULT Trspi_MGF1(UINT32 alg, UINT32 seedLen, BYTE *seed, UINT32 outLen, BYTE *out); /* String Functions */ /* Below UNICODE is in reference to the TSS type of that name, which is * actually UTF-16. */ /* Convert @string to a UNICODE string. On error, NULL is returned. If len * is non-NULL, *len will be set to the size of the returned buffer. */ BYTE *Trspi_Native_To_UNICODE(BYTE *string, unsigned *len); /* convert UNICODE @string to a string from the current codeset. If len * is non-NULL, *len will be set to the size of the returned buffer. */ BYTE *Trspi_UNICODE_To_Native(BYTE *string, unsigned *len); /* Error Functions */ /* return a human readable string based on the result */ char *Trspi_Error_String(TSS_RESULT); /* return a human readable error layer ( "tpm", "tddl", etc...) */ char *Trspi_Error_Layer(TSS_RESULT); /* return just the error code bits of the result */ TSS_RESULT Trspi_Error_Code(TSS_RESULT); #ifdef __cplusplus } #endif /* masks */ #define TSS_KEY_SIZE_MASK 0x00000F00 #define TSS_KEY_TYPE_MASK 0x000000F0 #define TSS_ENCDATA_TYPE_MASK 0x0000000F /* These should be passed an TSS_FLAG parameter as to * Tspi_Context_CreateObject */ #define TSS_KEY_SIZE(x) (x & TSS_KEY_SIZE_MASK) #define TSS_KEY_TYPE(x) (x & TSS_KEY_TYPE_MASK) #define TSS_ENCDATA_TYPE(x) (x & TSS_ENCDATA_TYPE_MASK) #define TSS_LOCALITY_ALL (TPM_LOC_ZERO|TPM_LOC_ONE|TPM_LOC_TWO|TPM_LOC_THREE|TPM_LOC_FOUR) #endif trousers-0.3.15/src/include/trousers/tss.h0000664000175000017510000000120713663651711020036 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #ifndef _TSS_H_ #define _TSS_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif trousers-0.3.15/src/include/tsp_audit.h0000664000175000017510000000046613663651711017341 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #ifndef _TSP_AUDIT_H_ #define _TSP_AUDIT_H_ TSS_RESULT __tspi_audit_set_ordinal_audit_status(TSS_HTPM, TSS_FLAG, TSS_FLAG, UINT32); #endif trousers-0.3.15/src/include/tcs_context.h0000664000175000017510000000127313663651711017677 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _TCS_CONTEXT_H_ #define _TCS_CONTEXT_H_ #include "threads.h" struct keys_loaded { TCS_KEY_HANDLE key_handle; struct keys_loaded *next; }; #define TSS_CONTEXT_FLAG_TRANSPORT_EXCLUSIVE 0x1 #define TSS_CONTEXT_FLAG_TRANSPORT_ENCRYPTED 0x2 #define TSS_CONTEXT_FLAG_TRANSPORT_ENABLED 0x4 struct tcs_context { TSS_FLAG flags; TPM_TRANSHANDLE transHandle; TCS_CONTEXT_HANDLE handle; COND_VAR cond; /* used in waiting for an auth ctx to become available */ struct keys_loaded *keys; struct tcs_context *next; }; #endif trousers-0.3.15/src/include/obj_daaissuerkey.h0000664000175000017510000000321113663651711020657 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_DAAISSUERKEY_H_ #define _OBJ_DAAISSUERKEY_H_ #ifdef TSS_BUILD_DAA /* structures */ struct tr_daaissuerkey_obj { UINT32 session_handle; TPM_HANDLE tpm_handle; }; /* prototypes */ void daaissuerkey_free(void *data); TSS_RESULT obj_daaissuerkey_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject); TSS_RESULT obj_daaissuerkey_remove(TSS_HDAA_ISSUER_KEY, TSS_HCONTEXT); TSS_BOOL obj_is_daaissuerkey(TSS_HDAA_ISSUER_KEY); TSS_RESULT obj_daaissuerkey_get_tsp_context(TSS_HDAA_ISSUER_KEY, TSS_HCONTEXT *); TSS_RESULT obj_daaissuerkey_get_handle_tpm(TSS_HDAA_ISSUER_KEY, TPM_HANDLE *); TSS_RESULT obj_daaissuerkey_set_handle_tpm(TSS_HDAA_ISSUER_KEY, TPM_HANDLE); TSS_RESULT obj_daaissuerkey_get_session_handle(TSS_HDAA_ISSUER_KEY, UINT32 *); TSS_RESULT obj_daaissuerkey_set_session_handle(TSS_HDAA_ISSUER_KEY, UINT32); #define DAAISSUERKEY_LIST_DECLARE struct obj_list daaissuerkey_list #define DAAISSUERKEY_LIST_DECLARE_EXTERN extern struct obj_list daaissuerkey_list #define DAAISSUERKEY_LIST_INIT() tspi_list_init(&daaissuerkey_list) #define DAAISSUERKEY_LIST_CONNECT(a,b) obj_connectContext_list(&daaissuerkey_list, a, b) #define DAAISSUERKEY_LIST_CLOSE(a) obj_list_close(&daaissuerkey_list, \ &daaissuerkey_free, a) #else #define obj_is_daaissuerkey(a) FALSE #define DAAISSUERKEY_LIST_DECLARE #define DAAISSUERKEY_LIST_DECLARE_EXTERN #define DAAISSUERKEY_LIST_INIT() #define DAAISSUERKEY_LIST_CONNECT(a,b) #define DAAISSUERKEY_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/rpc_tcstp.h0000664000175000017510000000135213663651711017341 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #ifndef _RPC_TCSTP_H_ #define _RPC_TCSTP_H_ #include "tcs_tsp.h" typedef unsigned char TCSD_PACKET_TYPE; /* Packet header used for TCSD communication */ struct tcsd_packet_hdr { UINT32 packet_size; union { UINT32 ordinal; UINT32 result; } u; UINT32 num_parms; UINT32 type_size; UINT32 type_offset; UINT32 parm_size; UINT32 parm_offset; } STRUCTURE_PACKING_ATTRIBUTE; struct tcsd_comm_data { BYTE *buf; UINT32 buf_size; struct tcsd_packet_hdr hdr; } STRUCTURE_PACKING_ATTRIBUTE; #define TCSD_INIT_TXBUF_SIZE 1024 #define TCSD_INCR_TXBUF_SIZE 4096 #endif trousers-0.3.15/src/include/obj_rsakey.h0000664000175000017510000001241113663651711017466 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_RSAKEY_H_ #define _OBJ_RSAKEY_H_ #ifdef TSS_BUILD_RSAKEY_LIST /* rsakey specific flags */ #define TSS_RSAKEY_FLAG_OWNEREVICT (0x00000001) /* structures */ struct tr_rsakey_obj { int type; TSS_KEY key; TSS_FLAG flags; TSS_HPOLICY usagePolicy; TSS_HPOLICY migPolicy; TSS_UUID uuid; TCS_KEY_HANDLE tcsHandle; #ifdef TSS_BUILD_CMK TPM_HMAC msaApproval; TPM_DIGEST msaDigest; #endif union { TPM_PCR_INFO info11; TPM_PCR_INFO_LONG infolong; } pcrInfo; UINT32 pcrInfoType; }; /* obj_rsakey.c */ void __tspi_rsakey_free(void *data); TSS_BOOL obj_is_rsakey(TSS_HOBJECT); TSS_RESULT obj_rsakey_add(TSS_HCONTEXT, TSS_FLAG, TSS_HOBJECT *); TSS_RESULT obj_rsakey_add_by_key(TSS_HCONTEXT, TSS_UUID *, BYTE *, TSS_FLAG, TSS_HKEY *); TSS_RESULT obj_rsakey_set_policy(TSS_HKEY, TSS_HPOLICY); TSS_RESULT obj_rsakey_remove(TSS_HOBJECT, TSS_HCONTEXT); TSS_RESULT obj_rsakey_get_tsp_context(TSS_HKEY, TSS_HCONTEXT *); TSS_RESULT obj_rsakey_set_pstype(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_pstype(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_get_usage(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_usage(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_set_migratable(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_set_redirected(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_set_volatile(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_authdata_usage(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_authdata_usage(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_alg(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_alg(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_es(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_es(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_ss(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_ss(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_set_num_primes(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_num_primes(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_flags(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_flags(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_size(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_get_size(TSS_HKEY, UINT32 *); TSS_BOOL obj_rsakey_is_migratable(TSS_HKEY); TSS_BOOL obj_rsakey_is_redirected(TSS_HKEY); TSS_BOOL obj_rsakey_is_volatile(TSS_HKEY); TSS_RESULT obj_rsakey_get_policy(TSS_HKEY, UINT32, TSS_HPOLICY *, TSS_BOOL *); TSS_RESULT obj_rsakey_get_policies(TSS_HKEY, TSS_HPOLICY *, TSS_HPOLICY *, TSS_BOOL *); TSS_RESULT obj_rsakey_get_blob(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_get_priv_blob(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_get_pub_blob(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_get_version(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_get_exponent(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_set_exponent(TSS_HKEY, UINT32, BYTE *); TSS_RESULT obj_rsakey_get_modulus(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_set_modulus(TSS_HKEY, UINT32, BYTE *); TSS_RESULT obj_rsakey_get_uuid(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_get_parent_uuid(TSS_HKEY, TSS_FLAG *, TSS_UUID *); TSS_RESULT obj_rsakey_set_uuids(TSS_HKEY, TSS_FLAG, TSS_UUID *, TSS_FLAG, TSS_UUID *); TSS_RESULT obj_rsakey_set_uuid(TSS_HKEY, TSS_FLAG, TSS_UUID *); TSS_RESULT obj_rsakey_set_tcpakey(TSS_HKEY, UINT32 , BYTE *); TSS_RESULT obj_rsakey_get_pcr_digest(TSS_HKEY, UINT32, TSS_FLAG, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_get_pcr_selection(TSS_HKEY, UINT32, TSS_FLAG, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_get_pcr_locality(TSS_HKEY, TSS_FLAG, UINT32 *); TSS_RESULT obj_rsakey_set_pubkey(TSS_HKEY, UINT32, BYTE *); TSS_RESULT obj_rsakey_set_privkey(TSS_HKEY, UINT32, UINT32, BYTE *); TSS_RESULT obj_rsakey_set_pcr_data(TSS_HKEY, TSS_HPOLICY); TSS_RESULT obj_rsakey_set_key_parms(TSS_HKEY, TCPA_KEY_PARMS *); TSS_RESULT obj_rsakey_get_by_uuid(TSS_UUID *, TSS_HKEY *); TSS_RESULT obj_rsakey_get_by_pub(UINT32, BYTE *, TSS_HKEY *); TSS_RESULT obj_rsakey_get_tcs_handle(TSS_HKEY, TCS_KEY_HANDLE *); TSS_RESULT obj_rsakey_set_tcs_handle(TSS_HKEY, TCS_KEY_HANDLE); void obj_rsakey_remove_policy_refs(TSS_HPOLICY, TSS_HCONTEXT); TSS_RESULT obj_rsakey_get_transport_attribs(TSS_HKEY, TCS_KEY_HANDLE *, TPM_DIGEST *); #ifdef TSS_BUILD_CMK TSS_BOOL obj_rsakey_is_cmk(TSS_HKEY); TSS_RESULT obj_rsakey_set_cmk(TSS_HKEY, UINT32); TSS_RESULT obj_rsakey_set_msa_approval(TSS_HKEY, UINT32, BYTE *); TSS_RESULT obj_rsakey_get_msa_approval(TSS_HKEY, UINT32 *, BYTE **); TSS_RESULT obj_rsakey_set_msa_digest(TSS_HKEY, UINT32, BYTE *); TSS_RESULT obj_rsakey_get_msa_digest(TSS_HKEY, UINT32 *, BYTE **); #endif TSS_RESULT obj_rsakey_get_ownerevict(TSS_HKEY, UINT32 *); TSS_RESULT obj_rsakey_set_ownerevict(TSS_HKEY, TSS_BOOL); TSS_RESULT obj_rsakey_set_srk_pubkey(BYTE *); #define RSAKEY_LIST_DECLARE struct obj_list rsakey_list #define RSAKEY_LIST_DECLARE_EXTERN extern struct obj_list rsakey_list #define RSAKEY_LIST_INIT() tspi_list_init(&rsakey_list) #define RSAKEY_LIST_CONNECT(a,b) obj_connectContext_list(&rsakey_list, a, b) #define RSAKEY_LIST_CLOSE(a) obj_list_close(&rsakey_list, &__tspi_rsakey_free, a) #else #define obj_is_rsakey(a) FALSE #define RSAKEY_LIST_DECLARE #define RSAKEY_LIST_DECLARE_EXTERN #define RSAKEY_LIST_INIT() #define RSAKEY_LIST_CONNECT(a,b) #define RSAKEY_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/obj.h0000664000175000017510000000527413663651711016121 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_H_ #define _OBJ_H_ #include "threads.h" /* definitions */ /* When TRUE, the object has PCRs associated with it */ #define TSS_OBJ_FLAG_PCRS 0x00000001 /* When TRUE, the object has a usage auth secret associated with it */ #define TSS_OBJ_FLAG_USAGEAUTH 0x00000002 /* When TRUE, the object has a migration auth secret associated with it */ #define TSS_OBJ_FLAG_MIGAUTH 0x00000004 /* When TRUE, the object has previously been registered in USER PS */ #define TSS_OBJ_FLAG_USER_PS 0x00000008 /* When TRUE, the object has previously been registered in SYSTEM PS */ #define TSS_OBJ_FLAG_SYSTEM_PS 0x00000010 /* When TRUE, the key has been created and cannot be altered */ #define TSS_OBJ_FLAG_KEY_SET 0x00000020 /* structures */ struct tsp_object { UINT32 handle; UINT32 tspContext; TSS_FLAG flags; void *data; struct tsp_object *next; }; struct obj_list { struct tsp_object *head; MUTEX_DECLARE(lock); }; /* prototypes */ TSS_RESULT obj_getTpmObject(UINT32, TSS_HOBJECT *); TSS_HOBJECT obj_GetPolicyOfObject(UINT32, UINT32); void __tspi_obj_list_init(); TSS_HOBJECT obj_get_next_handle(); TSS_RESULT obj_list_add(struct obj_list *, UINT32, TSS_FLAG, void *, TSS_HOBJECT *); TSS_RESULT obj_list_remove(struct obj_list *, void (*)(void *), TSS_HOBJECT, TSS_HCONTEXT); void obj_list_put(struct obj_list *); struct tsp_object *obj_list_get_obj(struct obj_list *, UINT32); struct tsp_object *obj_list_get_tspcontext(struct obj_list *, UINT32); void obj_list_close(struct obj_list *, void (*)(void *), TSS_HCONTEXT); void obj_connectContext(TSS_HCONTEXT, TCS_CONTEXT_HANDLE); void obj_close_context(TSS_HCONTEXT); void obj_lists_remove_policy_refs(TSS_HPOLICY, TSS_HCONTEXT); /* prototypes for functions that may traverse more than one list */ TSS_RESULT obj_tcskey_get_pubkeyhash(TCS_KEY_HANDLE, BYTE *); #include "obj_tpm.h" #include "obj_context.h" #include "obj_hash.h" #include "obj_pcrs.h" #include "obj_policy.h" #include "obj_rsakey.h" #include "obj_encdata.h" #include "obj_daacred.h" #include "obj_daaarakey.h" #include "obj_daaissuerkey.h" #include "obj_nv.h" #include "obj_delfamily.h" #include "obj_migdata.h" TPM_LIST_DECLARE_EXTERN; CONTEXT_LIST_DECLARE_EXTERN; HASH_LIST_DECLARE_EXTERN; PCRS_LIST_DECLARE_EXTERN; POLICY_LIST_DECLARE_EXTERN; RSAKEY_LIST_DECLARE_EXTERN; ENCDATA_LIST_DECLARE_EXTERN; DAACRED_LIST_DECLARE_EXTERN; DAAARAKEY_LIST_DECLARE_EXTERN; DAAISSUERKEY_LIST_DECLARE_EXTERN; NVSTORE_LIST_DECLARE_EXTERN; DELFAMILY_LIST_DECLARE_EXTERN; MIGDATA_LIST_DECLARE_EXTERN; #endif trousers-0.3.15/src/include/tsplog.h0000664000175000017510000000271413663651711016653 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #ifndef _TSPLOG_H_ #define _TSPLOG_H_ #include #include #include /* Debug logging */ #ifdef TSS_DEBUG /* log to stdout */ #define LogMessage(dest, priority, layer, fmt, ...) \ do { \ if (getenv("TSS_DEBUG_OFF") == NULL) { \ fprintf(dest, "%s %s %s:%d " fmt "\n", priority, layer, __FILE__, __LINE__, ## __VA_ARGS__); \ } \ } while (0) #define LogDebug(fmt, ...) LogMessage(stdout, "LOG_DEBUG", APPID, fmt, ##__VA_ARGS__) #define LogDebugFn(fmt, ...) LogMessage(stdout, "LOG_DEBUG", APPID, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__) #define LogDebugData(sz,blb) LogBlobData(APPID, sz, blb) /* Error logging */ #define LogError(fmt, ...) LogMessage(stderr, "LOG_ERR", APPID, "ERROR: " fmt, ##__VA_ARGS__) /* Warn logging */ #define LogWarn(fmt, ...) LogMessage(stdout, "LOG_WARNING", APPID, "WARNING: " fmt, ##__VA_ARGS__) /* Info Logging */ #define LogInfo(fmt, ...) LogMessage(stdout, "LOG_INFO", APPID, fmt, ##__VA_ARGS__) /* Return Value logging */ extern TSS_RESULT LogTSPERR(TSS_RESULT, char *, int); #else #define LogDebug(fmt, ...) #define LogDebugFn(fmt, ...) #define LogDebugData(sz,blb) #define LogError(fmt, ...) #define LogWarn(fmt, ...) #define LogInfo(fmt, ...) #endif void LogBlobData(char *appid, unsigned long sizeOfBlob, unsigned char *blob); #endif trousers-0.3.15/src/include/tcsd_ops.h0000664000175000017510000001644213663651711017164 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2005, 2007 * */ #ifndef _TCSD_COMMANDS_H_ #define _TCSD_COMMANDS_H_ #include "tcsd_wrap.h" #define OPENCONTEXT TCSD_ORD_OPENCONTEXT #define CLOSECONTEXT TCSD_ORD_CLOSECONTEXT #define FREEMEMORY TCSD_ORD_FREEMEMORY #define TCSGETCAPABILITY TCSD_ORD_TCSGETCAPABILITY #define REGISTERKEY TCSD_ORD_REGISTERKEY #define UNREGISTERKEY TCSD_ORD_UNREGISTERKEY #define GETREGISTEREDKEYBLOB TCSD_ORD_GETREGISTEREDKEYBLOB #define GETREGISTEREDKEYBYPUBLICINFO TCSD_ORD_GETREGISTEREDKEYBYPUBLICINFO #define GETPUBKEY TCSD_ORD_GETPUBKEY #define LOADKEYBYBLOB TCSD_ORD_LOADKEYBYBLOB #define LOADKEYBYUUID TCSD_ORD_LOADKEYBYUUID #define CREATEWRAPKEY TCSD_ORD_CREATEWRAPKEY #define GETPCREVENTLOG TCSD_ORD_GETPCREVENTLOG #define OIAP TCSD_ORD_OIAP #define OSAP TCSD_ORD_OSAP #define TERMINATEHANDLE TCSD_ORD_TERMINATEHANDLE #define PCRREAD TCSD_ORD_PCRREAD #define PCRRESET TCSD_ORD_PCRRESET #define QUOTE TCSD_ORD_QUOTE #define SEAL TCSD_ORD_SEAL #define UNSEAL TCSD_ORD_UNSEAL #define UNBIND TCSD_ORD_UNBIND #define CERTIFYKEY TCSD_ORD_CERTIFYKEY #define SIGN TCSD_ORD_SIGN #define GETRANDOM TCSD_ORD_GETRANDOM #define STIRRANDOM TCSD_ORD_STIRRANDOM #define GETCAPABILITY TCSD_ORD_GETCAPABILITY #define READPUBEK TCSD_ORD_READPUBEK #define SELFTESTFULL TCSD_ORD_SELFTESTFULL #define CERTIFYSELFTEST TCSD_ORD_CERTIFYSELFTEST #define CONTINUESELFTEST TCSD_ORD_CONTINUESELFTEST #define GETTESTRESULT TCSD_ORD_GETTESTRESULT /* below this line are ordinals that probably shouldn't be allowed for non-localhosts */ #if 0 #define OWNERREADPUBEK TCSD_ORD_OWNERREADPUBEK #define GETPCREVENT TCSD_ORD_GETPCREVENT #define GETPCREVENTBYPCR TCSD_ORD_GETPCREVENTBYPCR #define GETCAPABILITYSIGNED TCSD_ORD_GETCAPABILITYSIGNED #define ENUMREGISTEREDKEYS TCSD_ORD_ENUMREGISTEREDKEYS #define ENUMREGISTEREDKEYS2 TCSD_ORD_ENUMREGISTEREDKEYS2 #define GETREGISTEREDKEY TCSD_ORD_GETREGISTEREDKEY #define EXTEND TCSD_ORD_EXTEND #define LOGPCREVENT TCSD_ORD_LOGPCREVENT #define EVICTKEY TCSD_ORD_EVICTKEY #define DISABLEPUBEKREAD TCSD_ORD_DISABLEPUBEKREAD #define SETOWNERINSTALL TCSD_ORD_SETOWNERINSTALL #define MAKEIDENTITY TCSD_ORD_MAKEIDENTITY #define MAKEIDENTITY2 TCSD_ORD_MAKEIDENTITY2 #define TAKEOWNERSHIP TCSD_ORD_TAKEOWNERSHIP #define CREATEENDORSEMENTKEYPAIR TCSD_ORD_CREATEENDORSEMENTKEYPAIR #define GETCAPABILITYOWNER TCSD_ORD_GETCAPABILITYOWNER #define ACTIVATETPMIDENTITY TCSD_ORD_ACTIVATETPMIDENTITY #define AUTHORIZEMIGRATIONKEY TCSD_ORD_AUTHORIZEMIGRATIONKEY #define CHANGEAUTH TCSD_ORD_CHANGEAUTH #define CHANGEAUTHOWNER TCSD_ORD_CHANGEAUTHOWNER #define CHANGEAUTHASYMSTART TCSD_ORD_CHANGEAUTHASYMSTART #define CHANGEAUTHASYMFINISH TCSD_ORD_CHANGEAUTHASYMFINISH #define DIRREAD TCSD_ORD_DIRREAD #define DIRWRITEAUTH TCSD_ORD_DIRWRITEAUTH #define CREATEMIGRATIONBLOB TCSD_ORD_CREATEMIGRATIONBLOB #define CONVERTMIGRATIONBLOB TCSD_ORD_CONVERTMIGRATIONBLOB #define OWNERSETDISABLE TCSD_ORD_OWNERSETDISABLE #define OWNERCLEAR TCSD_ORD_OWNERCLEAR #define DISABLEOWNERCLEAR TCSD_ORD_DISABLEOWNERCLEAR #define FORCECLEAR TCSD_ORD_FORCECLEAR #define DISABLEFORCECLEAR TCSD_ORD_DISABLEFORCECLEAR #define PHYSICALDISABLE TCSD_ORD_PHYSICALDISABLE #define PHYSICALENABLE TCSD_ORD_PHYSICALENABLE #define PHYSICALSETDEACTIVATED TCSD_ORD_PHYSICALSETDEACTIVATED #define SETTEMPDEACTIVATED TCSD_ORD_SETTEMPDEACTIVATED #define PHYSICALPRESENCE TCSD_ORD_PHYSICALPRESENCE #define FIELDUPGRADE TCSD_ORD_FIELDUPGRADE #define SETRIDIRECTION TCSD_ORD_SETRIDIRECTION #define CREATEMAINTENANCEARCHIVE TCSD_ORD_CREATEMAINTENANCEARCHIVE #define LOADMAINTENANCEARCHIVE TCSD_ORD_LOADMAINTENANCEARCHIVE #define KILLMAINTENANCEFEATURE TCSD_ORD_KILLMAINTENANCEFEATURE #define LOADMANUFECTURERMAINTENANCEPUB TCSD_ORD_LOADMANUFECTURERMAINTENANCEPUB #define READMANUFECTURERMAINTENANCEPUB TCSD_ORD_READMANUFECTURERMAINTENANCEPUB #define SETTEMPDEACTIVATED2 TCSD_ORD_SETTEMPDEACTIVATED2 #endif /* TCSD ordinal sub-command sets */ #define SUBOP_CONTEXT OPENCONTEXT, CLOSECONTEXT #define SUBOP_RANDOM STIRRANDOM, GETRANDOM #define SUBOP_AUTHSESS OIAP, OSAP, TERMINATEHANDLE #define SUBOP_LOADKEYBYUUID LOADKEYBYUUID, GETREGISTEREDKEYBLOB, FREEMEMORY #define SUBOP_SELFTEST SELFTESTFULL, CERTIFYSELFTEST, CONTINUESELFTEST, GETTESTRESULT /* Top level TCSD operations which can be enabled to be used by remote hosts. Each of these * should have a corresponding on/off switch in the tcsd.conf file */ #define TCSD_OP_SEAL SEAL, SUBOP_LOADKEYBYUUID, SUBOP_RANDOM, SUBOP_AUTHSESS, SUBOP_CONTEXT, 0 #define TCSD_OP_UNSEAL UNSEAL, SUBOP_LOADKEYBYUUID, SUBOP_RANDOM, SUBOP_AUTHSESS, SUBOP_CONTEXT, 0 #define TCSD_OP_GETREGISTEREDKEYBYPUBLICINFO GETREGISTEREDKEYBYPUBLICINFO, SUBOP_CONTEXT, 0 #define TCSD_OP_GETPUBKEY GETPUBKEY, SUBOP_RANDOM, SUBOP_AUTHSESS, SUBOP_CONTEXT, 0 #define TCSD_OP_LOADKEY LOADKEYBYBLOB, SUBOP_LOADKEYBYUUID, SUBOP_CONTEXT, SUBOP_AUTHSESS, SUBOP_RANDOM, 0 #define TCSD_OP_REGISTERKEY REGISTERKEY, SUBOP_CONTEXT, SUBOP_LOADKEYBYUUID, LOADKEYBYBLOB, 0 #define TCSD_OP_UNREGISTERKEY UNREGISTERKEY, SUBOP_CONTEXT, 0 #define TCSD_OP_CREATEKEY CREATEWRAPKEY, SUBOP_CONTEXT, SUBOP_AUTHSESS, SUBOP_LOADKEYBYUUID, SUBOP_RANDOM, 0 #define TCSD_OP_SIGN SIGN, SUBOP_CONTEXT, SUBOP_AUTHSESS, SUBOP_RANDOM, FREEMEMORY, 0 #define TCSD_OP_RANDOM SUBOP_RANDOM, SUBOP_CONTEXT, FREEMEMORY, 0 #define TCSD_OP_GETCAPABILITY GETCAPABILITY, TCSGETCAPABILITY, SUBOP_CONTEXT, FREEMEMORY, 0 #define TCSD_OP_UNBIND UNBIND, SUBOP_CONTEXT, SUBOP_AUTHSESS, SUBOP_RANDOM, 0 #define TCSD_OP_QUOTE QUOTE, SUBOP_CONTEXT, SUBOP_AUTHSESS, SUBOP_RANDOM, 0 #define TCSD_OP_READPUBEK READPUBEK, SUBOP_CONTEXT, SUBOP_AUTHSESS, SUBOP_RANDOM, 0 #define TCSD_OP_SELFTEST SUBOP_SELFTEST, SUBOP_CONTEXT, FREEMEMORY, 0 struct tcsd_op { char *name; int op[]; }; struct tcsd_op tcsd_op_seal = {"seal", {TCSD_OP_SEAL}}; struct tcsd_op tcsd_op_unseal = {"unseal", {TCSD_OP_UNSEAL}}; struct tcsd_op tcsd_op_registerkey = {"registerkey", {TCSD_OP_REGISTERKEY}}; struct tcsd_op tcsd_op_unregisterkey = {"unregisterkey", {TCSD_OP_UNREGISTERKEY}}; struct tcsd_op tcsd_op_getregisteredkeybypublicinfo = {"getregisteredkeybypublicinfo", {TCSD_OP_GETREGISTEREDKEYBYPUBLICINFO}}; struct tcsd_op tcsd_op_getpubkey = {"getpubkey", {TCSD_OP_GETPUBKEY}}; struct tcsd_op tcsd_op_loadkey = {"loadkey", {TCSD_OP_LOADKEY}}; struct tcsd_op tcsd_op_createkey = {"createkey", {TCSD_OP_CREATEKEY}}; struct tcsd_op tcsd_op_sign = {"sign", {TCSD_OP_SIGN}}; struct tcsd_op tcsd_op_random = {"random", {TCSD_OP_RANDOM}}; struct tcsd_op tcsd_op_getcapability = {"getcapability", {TCSD_OP_GETCAPABILITY}}; struct tcsd_op tcsd_op_unbind = {"unbind", {TCSD_OP_UNBIND}}; struct tcsd_op tcsd_op_quote = {"quote", {TCSD_OP_QUOTE}}; struct tcsd_op tcsd_op_readpubek = {"readpubek", {TCSD_OP_READPUBEK}}; struct tcsd_op tcsd_op_selftest = {"selftest", {TCSD_OP_SELFTEST}}; struct tcsd_op *tcsd_ops[] = { &tcsd_op_seal, &tcsd_op_unseal, &tcsd_op_registerkey, &tcsd_op_unregisterkey, &tcsd_op_getregisteredkeybypublicinfo, &tcsd_op_getpubkey, &tcsd_op_loadkey, &tcsd_op_createkey, &tcsd_op_sign, &tcsd_op_random, &tcsd_op_getcapability, &tcsd_op_unbind, &tcsd_op_quote, &tcsd_op_readpubek, &tcsd_op_selftest, NULL }; #endif trousers-0.3.15/src/include/obj_daacred.h0000664000175000017510000000300613663651711017553 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_DAACRED_H_ #define _OBJ_DAACRED_H_ #ifdef TSS_BUILD_DAA /* structures */ struct tr_daacred_obj { UINT32 session_handle; // set by [join|sign] stage 0. TPM_HANDLE tpm_handle; }; /* prototypes */ void daacred_free(void *data); TSS_RESULT obj_daacred_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject); TSS_RESULT obj_daacred_remove(TSS_HDAA_CREDENTIAL, TSS_HCONTEXT); TSS_BOOL obj_is_daacred(TSS_HDAA_CREDENTIAL); TSS_RESULT obj_daacred_get_tsp_context(TSS_HDAA_CREDENTIAL, TSS_HCONTEXT *); TSS_RESULT obj_daacred_get_handle_tpm(TSS_HDAA_CREDENTIAL, TPM_HANDLE *); TSS_RESULT obj_daacred_set_handle_tpm(TSS_HDAA_CREDENTIAL, TPM_HANDLE); TSS_RESULT obj_daacred_get_session_handle(TSS_HDAA_CREDENTIAL, UINT32 *); TSS_RESULT obj_daacred_set_session_handle(TSS_HDAA_CREDENTIAL, UINT32); #define DAACRED_LIST_DECLARE struct obj_list daacred_list #define DAACRED_LIST_DECLARE_EXTERN extern struct obj_list daacred_list #define DAACRED_LIST_INIT() tspi_list_init(&daacred_list) #define DAACRED_LIST_CONNECT(a,b) obj_connectContext_list(&daacred_list, a, b) #define DAACRED_LIST_CLOSE(a) obj_list_close(&daacred_list, &daacred_free, a) #else #define obj_is_daacred(a) FALSE #define DAACRED_LIST_DECLARE #define DAACRED_LIST_DECLARE_EXTERN #define DAACRED_LIST_INIT() #define DAACRED_LIST_CONNECT(a,b) #define DAACRED_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/obj_context.h0000664000175000017510000000724413663651711017664 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_CONTEXT_H_ #define _OBJ_CONTEXT_H_ #define TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED 0x01 #define TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT 0x02 #define TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC 0x04 #define TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE 0x08 #define TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH 0x10 #define TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED 0x20 #define TSS_CONTEXT_FLAGS_TRANSPORT_MASK 0x3f #define TSS_CONTEXT_FLAGS_TPM_VERSION_1 0x40 #define TSS_CONTEXT_FLAGS_TPM_VERSION_2 0x80 #define TSS_CONTEXT_FLAGS_TPM_VERSION_MASK 0xc0 /* structures */ struct tr_context_obj { TSS_FLAG silentMode, flags; UINT32 hashMode; TSS_HPOLICY policy; BYTE *machineName; UINT32 machineNameLength; UINT32 connection_policy, current_connection; struct tcs_api_table *tcs_api; #ifdef TSS_BUILD_TRANSPORT /* transport session support */ TSS_HKEY transKey; TPM_TRANSPORT_PUBLIC transPub; TPM_MODIFIER_INDICATOR transMod; TPM_TRANSPORT_AUTH transSecret; TPM_AUTH transAuth; TPM_TRANSPORT_LOG_IN transLogIn; TPM_TRANSPORT_LOG_OUT transLogOut; TPM_DIGEST transLogDigest; #endif }; /* obj_context.c */ void __tspi_obj_context_free(void *data); TSS_BOOL obj_is_context(TSS_HOBJECT); TSS_RESULT obj_context_get_policy(TSS_HCONTEXT, UINT32, TSS_HPOLICY *); TSS_BOOL obj_context_is_silent(TSS_HCONTEXT); TSS_RESULT obj_context_get_machine_name(TSS_HCONTEXT, UINT32 *, BYTE **); TSS_RESULT obj_context_get_machine_name_attrib(TSS_HCONTEXT, UINT32 *, BYTE **); TSS_RESULT obj_context_set_machine_name(TSS_HCONTEXT, BYTE *, UINT32); TSS_RESULT obj_context_add(TSS_HOBJECT *); TSS_RESULT obj_context_set_mode(TSS_HCONTEXT, UINT32); TSS_RESULT obj_context_get_mode(TSS_HCONTEXT, UINT32 *); TSS_BOOL obj_context_has_popups(TSS_HCONTEXT); TSS_RESULT obj_context_get_hash_mode(TSS_HCONTEXT, UINT32 *); TSS_RESULT obj_context_set_hash_mode(TSS_HCONTEXT, UINT32); TSS_RESULT obj_context_get_connection_version(TSS_HCONTEXT, UINT32 *); TSS_RESULT obj_context_set_connection_policy(TSS_HCONTEXT, UINT32); #ifdef TSS_BUILD_TRANSPORT TSS_RESULT obj_context_set_transport_key(TSS_HCONTEXT, TSS_HKEY); TSS_RESULT obj_context_transport_get_control(TSS_HCONTEXT, UINT32, UINT32 *); TSS_RESULT obj_context_transport_set_control(TSS_HCONTEXT, UINT32); TSS_RESULT obj_context_transport_get_mode(TSS_HCONTEXT, UINT32, UINT32 *); TSS_RESULT obj_context_transport_set_mode(TSS_HCONTEXT, UINT32); TSS_RESULT obj_context_transport_init(TSS_HCONTEXT); TSS_RESULT obj_context_transport_establish(TSS_HCONTEXT, struct tr_context_obj *); TSS_RESULT obj_context_transport_execute(TSS_HCONTEXT, TPM_COMMAND_CODE, UINT32, BYTE*, TPM_DIGEST*, UINT32*, TCS_HANDLE**, TPM_AUTH*, TPM_AUTH*, UINT32*, BYTE**); TSS_RESULT obj_context_transport_close(TSS_HCONTEXT, TSS_HKEY, TSS_HPOLICY, TSS_BOOL, TPM_SIGN_INFO*, UINT32*, BYTE**); #endif TSS_RESULT obj_context_set_tpm_version(TSS_HCONTEXT, UINT32); TSS_RESULT obj_context_get_tpm_version(TSS_HCONTEXT, UINT32 *); TSS_RESULT obj_context_get_loadkey_ordinal(TSS_HCONTEXT, TPM_COMMAND_CODE *); void obj_context_close(TSS_HCONTEXT); struct tcs_api_table *obj_context_get_tcs_api(TSS_HCONTEXT); #define TCS_API(c) obj_context_get_tcs_api(c) #define CONTEXT_LIST_DECLARE struct obj_list context_list #define CONTEXT_LIST_DECLARE_EXTERN extern struct obj_list context_list #define CONTEXT_LIST_INIT() tspi_list_init(&context_list) #define CONTEXT_LIST_CONNECT(a,b) obj_connectContext_list(&context_list, a, b) #define CONTEXT_LIST_CLOSE(a) obj_list_close(&context_list, &__tspi_obj_context_free, a) #endif trousers-0.3.15/src/include/tsp_seal.h0000664000175000017510000000046313663651711017154 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #ifndef _TSP_SEAL_H_ #define _TSP_SEAL_H_ TSS_RESULT sealx_mask_cb(UINT32, BYTE *, UINT32, BYTE *, BYTE *, UINT32, BYTE *, BYTE *); #endif trousers-0.3.15/src/include/obj_tpm.h0000664000175000017510000000465713663651711017005 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_TPM_H_ #define _OBJ_TPM_H_ /* structures */ struct tr_tpm_obj { TSS_HPOLICY policy; #ifdef TSS_BUILD_TSS12 TSS_HPOLICY operatorPolicy; #endif TSS_ALGORITHM_ID collateAlg; TSS_ALGORITHM_ID activateAlg; PVOID collateAppData; PVOID activateAppData; TSS_RESULT (*Tspicb_CollateIdentity)( PVOID lpAppData, UINT32 ulTCPAPlainIdentityProofLength, BYTE *rgbTCPAPlainIdentityProof, TSS_ALGORITHM_ID algID, UINT32* ulSessionKeyLength, BYTE *rgbSessionKey, UINT32 *pulTCPAIdentityProofLength, BYTE *rgbTCPAIdentityProof); TSS_RESULT (*Tspicb_ActivateIdentity)( PVOID lpAppData, UINT32 ulSessionKeyLength, BYTE *rgbSessionKey, UINT32 ulSymCAAttestationBlobLength, BYTE *rgbSymCAAttestationBlob, UINT32 *pulCredentialLength, BYTE *rgbCredential); TSS_COUNTER_ID ctr_id; UINT32 EndorsementCredSize; BYTE *EndorsementCred; UINT32 PlatformCredSize; BYTE *PlatformCred; UINT32 PlatformConfCredSize; BYTE *PlatformConfCred; UINT32 ConformanceCredSize; BYTE *ConformanceCred; }; /* prototypes */ TSS_RESULT obj_getTpmObject(UINT32, TSS_HOBJECT *); /* obj_tpm.c */ void tpm_free(void *); TSS_BOOL obj_is_tpm(TSS_HOBJECT); TSS_RESULT obj_tpm_get_tsp_context(TSS_HTPM, TSS_HCONTEXT *); TSS_RESULT obj_tpm_get(TSS_HCONTEXT, TSS_HTPM *); TSS_RESULT obj_tpm_set_policy(TSS_HTPM, TSS_HPOLICY); TSS_RESULT obj_tpm_add(TSS_HCONTEXT, TSS_HOBJECT *); TSS_RESULT obj_tpm_get_policy(TSS_HTPM, UINT32, TSS_HPOLICY *); TSS_RESULT obj_tpm_set_cb12(TSS_HTPM, TSS_FLAG, BYTE *); TSS_RESULT obj_tpm_get_cb12(TSS_HTPM, TSS_FLAG, UINT32 *, BYTE **); TSS_RESULT obj_tpm_set_cb11(TSS_HTPM, TSS_FLAG, TSS_FLAG, UINT32); TSS_RESULT obj_tpm_get_cb11(TSS_HTPM, TSS_FLAG, UINT32 *); void obj_tpm_remove_policy_refs(TSS_HPOLICY, TSS_HCONTEXT); TSS_RESULT obj_tpm_get_current_counter(TSS_HTPM, TSS_COUNTER_ID *); TSS_RESULT obj_tpm_set_cred(TSS_HTPM, TSS_FLAG, UINT32, BYTE *); TSS_RESULT obj_tpm_get_cred(TSS_HTPM, TSS_FLAG, UINT32 *, BYTE **); #define TPM_LIST_DECLARE struct obj_list tpm_list #define TPM_LIST_DECLARE_EXTERN extern struct obj_list tpm_list #define TPM_LIST_INIT() tspi_list_init(&tpm_list) #define TPM_LIST_CONNECT(a,b) obj_connectContext_list(&tpm_list, a, b) #define TPM_LIST_CLOSE(a) obj_list_close(&tpm_list, &tpm_free, a) #endif trousers-0.3.15/src/include/tcs_utils.h0000664000175000017510000013402713663651711017357 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _TCS_UTILS_H_ #define _TCS_UTILS_H_ #include #include "threads.h" #include "tcs_context.h" #include "tcs_tsp.h" #include "trousers_types.h" struct key_mem_cache { TCPA_KEY_HANDLE tpm_handle; TCS_KEY_HANDLE tcs_handle; UINT16 flags; int ref_cnt; UINT32 time_stamp; TSS_UUID uuid; TSS_UUID p_uuid; TSS_KEY *blob; struct key_mem_cache *parent; struct key_mem_cache *next, *prev; }; extern struct key_mem_cache *key_mem_cache_head; MUTEX_DECLARE_EXTERN(mem_cache_lock); struct tpm_properties { UINT32 num_pcrs; UINT32 num_dirs; UINT32 num_keys; UINT32 num_auths; TSS_BOOL authctx_swap; TSS_BOOL keyctx_swap; TPM_VERSION version; BYTE manufacturer[16]; }; extern struct tpm_properties tpm_metrics; #define TPM_VERSION_IS(maj, min) \ ((tpm_metrics.version.major == maj) && (tpm_metrics.version.minor == min)) #define TSS_UUID_IS_OWNEREVICT(uuid) \ ((!uuid->ulTimeLow) && (!uuid->usTimeMid) && (!uuid->usTimeHigh) && \ (!uuid->bClockSeqHigh) && (!uuid->bClockSeqLow) && (!uuid->rgbNode[0]) && \ (!uuid->rgbNode[1]) && (!uuid->rgbNode[2]) && (!uuid->rgbNode[3]) && \ (uuid->rgbNode[4] == 1)) #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif TSS_RESULT get_tpm_metrics(struct tpm_properties *); TSS_RESULT auth_mgr_init(); TSS_RESULT auth_mgr_final(); TSS_RESULT auth_mgr_check(TCS_CONTEXT_HANDLE, TPM_AUTHHANDLE *); TSS_RESULT auth_mgr_release_auth_handle(TCS_AUTHHANDLE, TCS_CONTEXT_HANDLE, TSS_BOOL); void auth_mgr_release_auth(TPM_AUTH *, TPM_AUTH *, TCS_CONTEXT_HANDLE); TSS_RESULT auth_mgr_oiap(TCS_CONTEXT_HANDLE, TCS_AUTHHANDLE *, TCPA_NONCE *); TSS_RESULT auth_mgr_osap(TCS_CONTEXT_HANDLE, TCPA_ENTITY_TYPE, UINT32, TCPA_NONCE, TCS_AUTHHANDLE *, TCPA_NONCE *, TCPA_NONCE *); TSS_RESULT auth_mgr_close_context(TCS_CONTEXT_HANDLE); TSS_RESULT auth_mgr_swap_out(TCS_CONTEXT_HANDLE); TSS_BOOL auth_mgr_req_new(TCS_CONTEXT_HANDLE); TSS_RESULT auth_mgr_add(TCS_CONTEXT_HANDLE, TPM_AUTHHANDLE); TSS_RESULT event_log_init(); TSS_RESULT event_log_final(); TSS_RESULT owner_evict_init(); #ifdef TSS_BUILD_PCR_EVENTS #define EVENT_LOG_init() event_log_init() #define EVENT_LOG_final() event_log_final() #else #define EVENT_LOG_init() (TSS_SUCCESS) #define EVENT_LOG_final() #endif #define next( x ) x = x->next TSS_RESULT key_mgr_dec_ref_count(TCS_KEY_HANDLE); TSS_RESULT key_mgr_inc_ref_count(TCS_KEY_HANDLE); void key_mgr_ref_count(); TSS_RESULT key_mgr_load_by_uuid(TCS_CONTEXT_HANDLE, TSS_UUID *, TCS_LOADKEY_INFO *, TCS_KEY_HANDLE *); TSS_RESULT key_mgr_load_by_blob(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TCS_KEY_HANDLE *, TCS_KEY_HANDLE *); TSS_RESULT key_mgr_evict(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE); extern TCS_CONTEXT_HANDLE InternalContext; TSS_RESULT mc_update_time_stamp(TCPA_KEY_HANDLE); TCS_KEY_HANDLE getNextTcsKeyHandle(); TCPA_STORE_PUBKEY *getParentPubBySlot(TCPA_KEY_HANDLE slot); TCPA_STORE_PUBKEY *mc_get_pub_by_slot(TCPA_KEY_HANDLE); TCPA_STORE_PUBKEY *mc_get_pub_by_handle(TCS_KEY_HANDLE); TSS_UUID *mc_get_uuid_by_pub(TCPA_STORE_PUBKEY *); TSS_RESULT mc_get_handles_by_uuid(TSS_UUID *, TCS_KEY_HANDLE *, TCPA_KEY_HANDLE *); TCS_KEY_HANDLE mc_get_handle_by_encdata(BYTE *); TSS_RESULT mc_update_encdata(BYTE *, BYTE *); TSS_RESULT mc_find_next_ownerevict_uuid(TSS_UUID *); TSS_RESULT mc_set_uuid(TCS_KEY_HANDLE, TSS_UUID *); TSS_RESULT initDiskCache(void); void replaceEncData_PS(TSS_UUID, BYTE *encData, BYTE *newEncData); TSS_RESULT mc_add_entry(TCS_KEY_HANDLE, TCPA_KEY_HANDLE, TSS_KEY *); TSS_RESULT mc_add_entry_init(TCS_KEY_HANDLE, TCPA_KEY_HANDLE, TSS_KEY *, TSS_UUID *); TSS_RESULT mc_remove_entry(TCS_KEY_HANDLE); TSS_RESULT mc_set_slot_by_slot(TCPA_KEY_HANDLE, TCPA_KEY_HANDLE); TSS_RESULT mc_set_slot_by_handle(TCS_KEY_HANDLE, TCPA_KEY_HANDLE); TCPA_KEY_HANDLE mc_get_slot_by_handle(TCS_KEY_HANDLE); TCPA_KEY_HANDLE mc_get_slot_by_handle_lock(TCS_KEY_HANDLE); TCPA_KEY_HANDLE mc_get_slot_by_pub(TCPA_STORE_PUBKEY *); TCS_KEY_HANDLE mc_get_handle_by_pub(TCPA_STORE_PUBKEY *, TCS_KEY_HANDLE); TCPA_STORE_PUBKEY *mc_get_parent_pub_by_pub(TCPA_STORE_PUBKEY *); TSS_BOOL isKeyRegistered(TCPA_STORE_PUBKEY *); TSS_RESULT mc_get_blob_by_pub(TCPA_STORE_PUBKEY *, TSS_KEY **); TSS_RESULT evictFirstKey(TCS_KEY_HANDLE); TSS_RESULT getParentUUIDByUUID(TSS_UUID *, TSS_UUID *); TSS_RESULT getRegisteredKeyByUUID(TSS_UUID *, BYTE *, UINT16 *); TSS_RESULT isPubRegistered(TCPA_STORE_PUBKEY *); TSS_RESULT getRegisteredUuidByPub(TCPA_STORE_PUBKEY *, TSS_UUID **); TSS_RESULT getRegisteredKeyByPub(TCPA_STORE_PUBKEY *, UINT32 *, BYTE **); TSS_BOOL isKeyLoaded(TCPA_KEY_HANDLE); TSS_RESULT LoadKeyShim(TCS_CONTEXT_HANDLE, TCPA_STORE_PUBKEY *, TSS_UUID *,TCPA_KEY_HANDLE *); TSS_RESULT mc_set_parent_by_handle(TCS_KEY_HANDLE, TCS_KEY_HANDLE); TSS_RESULT isUUIDRegistered(TSS_UUID *, TSS_BOOL *); void destroy_key_refs(TSS_KEY *); /* cxt.c */ TSS_RESULT context_close_auth(TCS_CONTEXT_HANDLE); TSS_RESULT checkContextForAuth(TCS_CONTEXT_HANDLE, TCS_AUTHHANDLE); TSS_RESULT addContextForAuth(TCS_CONTEXT_HANDLE, TCS_AUTHHANDLE); TSS_RESULT ctx_verify_context(TCS_CONTEXT_HANDLE); COND_VAR *ctx_get_cond_var(TCS_CONTEXT_HANDLE); TSS_RESULT ctx_mark_key_loaded(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE); TSS_RESULT ctx_remove_key_loaded(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE); TSS_BOOL ctx_has_key_loaded(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE); void ctx_ref_count_keys(struct tcs_context *); struct tcs_context *get_context(TCS_CONTEXT_HANDLE); TSS_RESULT ctx_req_exclusive_transport(TCS_CONTEXT_HANDLE); TSS_RESULT ctx_set_transport_enabled(TCS_CONTEXT_HANDLE, TPM_TRANSHANDLE); TSS_RESULT ctx_set_transport_disabled(TCS_CONTEXT_HANDLE, TCS_HANDLE *); #ifdef TSS_BUILD_KEY #define CTX_ref_count_keys(c) ctx_ref_count_keys(c) #define KEY_MGR_ref_count() key_mgr_ref_count() TSS_RESULT ensureKeyIsLoaded(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE, TCPA_KEY_HANDLE *); #else #define CTX_ref_count_keys(c) #define KEY_MGR_ref_count() #define ensureKeyIsLoaded(...) (1 /* XXX non-zero return will indicate failure */) #endif TCS_CONTEXT_HANDLE make_context(); void destroy_context(TCS_CONTEXT_HANDLE); /* tcs_utils.c */ TSS_RESULT get_current_version(TPM_VERSION *); void LogData(char *string, UINT32 data); void LogResult(char *string, TSS_RESULT result); TSS_RESULT canILoadThisKey(TCPA_KEY_PARMS *parms, TSS_BOOL *); TSS_RESULT internal_EvictByKeySlot(TCPA_KEY_HANDLE slot); TSS_RESULT clearKeysFromChip(TCS_CONTEXT_HANDLE hContext); TSS_RESULT clearUnknownKeys(TCS_CONTEXT_HANDLE, UINT32 *); void UINT64ToArray(UINT64, BYTE *); void UINT32ToArray(UINT32, BYTE *); void UINT16ToArray(UINT16, BYTE *); UINT64 Decode_UINT64(BYTE *); UINT32 Decode_UINT32(BYTE *); UINT16 Decode_UINT16(BYTE *); void LoadBlob_UINT64(UINT64 *, UINT64, BYTE *); void LoadBlob_UINT32(UINT64 *, UINT32, BYTE *); void LoadBlob_UINT16(UINT64 *, UINT16, BYTE *); void UnloadBlob_UINT64(UINT64 *, UINT64 *, BYTE *); void UnloadBlob_UINT32(UINT64 *, UINT32 *, BYTE *); void UnloadBlob_UINT16(UINT64 *, UINT16 *, BYTE *); void LoadBlob_BYTE(UINT64 *, BYTE, BYTE *); void UnloadBlob_BYTE(UINT64 *, BYTE *, BYTE *); void LoadBlob_BOOL(UINT64 *, TSS_BOOL, BYTE *); void UnloadBlob_BOOL(UINT64 *, TSS_BOOL *, BYTE *); void LoadBlob(UINT64 *, UINT32, BYTE *, BYTE *); void UnloadBlob(UINT64 *, UINT32, BYTE *, BYTE *); void LoadBlob_Header(UINT16, UINT32, UINT32, BYTE *); #ifdef TSS_DEBUG #define UnloadBlob_Header(b,u) LogUnloadBlob_Header(b,u, __FILE__, __LINE__) TSS_RESULT LogUnloadBlob_Header(BYTE *, UINT32 *, char *, int); #else TSS_RESULT UnloadBlob_Header(BYTE *, UINT32 *); #endif TSS_RESULT UnloadBlob_MIGRATIONKEYAUTH(UINT64 *, BYTE *, TCPA_MIGRATIONKEYAUTH *); void LoadBlob_Auth(UINT64 *, BYTE *, TPM_AUTH *); void UnloadBlob_Auth(UINT64 *, BYTE *, TPM_AUTH *); void LoadBlob_KEY_PARMS(UINT64 *, BYTE *, TCPA_KEY_PARMS *); TSS_RESULT UnloadBlob_KEY_PARMS(UINT64 *, BYTE *, TCPA_KEY_PARMS *); TSS_RESULT UnloadBlob_STORE_PUBKEY(UINT64 *, BYTE *, TCPA_STORE_PUBKEY *); void LoadBlob_STORE_PUBKEY(UINT64 *, BYTE *, TCPA_STORE_PUBKEY *); void UnloadBlob_VERSION(UINT64 *, BYTE *, TPM_VERSION *); void LoadBlob_VERSION(UINT64 *, BYTE *, TPM_VERSION *); void UnloadBlob_TCPA_VERSION(UINT64 *, BYTE *, TCPA_VERSION *); void LoadBlob_TCPA_VERSION(UINT64 *, BYTE *, TCPA_VERSION *); TSS_RESULT UnloadBlob_TSS_KEY(UINT64 *, BYTE *, TSS_KEY *); void LoadBlob_TSS_KEY(UINT64 *, BYTE *, TSS_KEY *); void LoadBlob_PUBKEY(UINT64 *, BYTE *, TCPA_PUBKEY *); TSS_RESULT UnloadBlob_PUBKEY(UINT64 *, BYTE *, TCPA_PUBKEY *); void LoadBlob_SYMMETRIC_KEY(UINT64 *, BYTE *, TCPA_SYMMETRIC_KEY *); TSS_RESULT UnloadBlob_SYMMETRIC_KEY(UINT64 *, BYTE *, TCPA_SYMMETRIC_KEY *); TSS_RESULT UnloadBlob_PCR_SELECTION(UINT64 *, BYTE *, TCPA_PCR_SELECTION *); void LoadBlob_PCR_SELECTION(UINT64 *, BYTE *, TCPA_PCR_SELECTION); TSS_RESULT UnloadBlob_PCR_COMPOSITE(UINT64 *, BYTE *, TCPA_PCR_COMPOSITE *); void LoadBlob_PCR_INFO(UINT64 *, BYTE *, TCPA_PCR_INFO *); TSS_RESULT UnloadBlob_PCR_INFO(UINT64 *, BYTE *, TCPA_PCR_INFO *); TSS_RESULT UnloadBlob_STORED_DATA(UINT64 *, BYTE *, TCPA_STORED_DATA *); void LoadBlob_STORED_DATA(UINT64 *, BYTE *, TCPA_STORED_DATA *); void LoadBlob_KEY_FLAGS(UINT64 *, BYTE *, TCPA_KEY_FLAGS *); void UnloadBlob_KEY_FLAGS(UINT64 *, BYTE *, TCPA_KEY_FLAGS *); TSS_RESULT UnloadBlob_CERTIFY_INFO(UINT64 *, BYTE *, TCPA_CERTIFY_INFO *); TSS_RESULT UnloadBlob_KEY_HANDLE_LIST(UINT64 *, BYTE *, TCPA_KEY_HANDLE_LIST *); void LoadBlob_UUID(UINT64 *, BYTE *, TSS_UUID); void UnloadBlob_UUID(UINT64 *, BYTE *, TSS_UUID *); void LoadBlob_COUNTER_VALUE(UINT64 *, BYTE *, TPM_COUNTER_VALUE *); void UnloadBlob_COUNTER_VALUE(UINT64 *, BYTE *, TPM_COUNTER_VALUE *); void LoadBlob_DIGEST(UINT64 *, BYTE *, TPM_DIGEST *); void UnloadBlob_DIGEST(UINT64 *, BYTE *, TPM_DIGEST *); void LoadBlob_NONCE(UINT64 *, BYTE *, TPM_NONCE *); void UnloadBlob_NONCE(UINT64 *, BYTE *, TPM_NONCE *); void LoadBlob_AUTHDATA(UINT64 *, BYTE *, TPM_AUTHDATA *); void UnloadBlob_AUTHDATA(UINT64 *, BYTE *, TPM_AUTHDATA *); #define LoadBlob_ENCAUTH(a, b, c) LoadBlob_AUTHDATA(a, b, c) #define UnloadBlob_ENCAUTH(a, b, c) UnloadBlob_AUTHDATA(a, b, c) void UnloadBlob_CURRENT_TICKS(UINT64 *, BYTE *, TPM_CURRENT_TICKS *); TSS_RESULT UnloadBlob_PCR_INFO_SHORT(UINT64 *, BYTE *, TPM_PCR_INFO_SHORT *); TSS_RESULT Hash(UINT32, UINT32, BYTE *, BYTE *); void free_external_events(UINT32, TSS_PCR_EVENT *); TSS_RESULT internal_TerminateHandle(TCS_AUTHHANDLE handle); UINT32 get_pcr_event_size(TSS_PCR_EVENT *); TSS_RESULT fill_key_info(struct key_disk_cache *, struct key_mem_cache *, TSS_KM_KEYINFO *); TSS_RESULT fill_key_info2(struct key_disk_cache *, struct key_mem_cache *, TSS_KM_KEYINFO2 *); char platform_get_runlevel(); TSS_RESULT tpm_rsp_parse(TPM_COMMAND_CODE, BYTE *, UINT32, ...); TSS_RESULT tpm_rqu_build(TPM_COMMAND_CODE, UINT64 *, BYTE *, ...); TSS_RESULT tpm_preload_check(TCS_CONTEXT_HANDLE, TPM_COMMAND_CODE ordinal, ...); TSS_RESULT getKeyByCacheEntry(struct key_disk_cache *, BYTE *, UINT16 *); TSS_RESULT add_cache_entry(TCS_CONTEXT_HANDLE, BYTE *, TCS_KEY_HANDLE, TPM_KEY_HANDLE, TCS_KEY_HANDLE *); TSS_RESULT get_slot(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE, TPM_KEY_HANDLE *); TSS_RESULT get_slot_lite(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE, TPM_KEY_HANDLE *); TSS_RESULT load_key_init(TPM_COMMAND_CODE, TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE, UINT32, BYTE*, TSS_BOOL, TPM_AUTH*, TSS_BOOL*, UINT64*, BYTE*, TCS_KEY_HANDLE*, TPM_KEY_HANDLE*); TSS_RESULT load_key_final(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE, TCS_KEY_HANDLE *, BYTE *, TPM_KEY_HANDLE); TSS_RESULT LoadKeyByBlob_Internal(UINT32,TCS_CONTEXT_HANDLE,TCS_KEY_HANDLE,UINT32,BYTE *,TPM_AUTH *, TCS_KEY_HANDLE *,TCS_KEY_HANDLE *); TSS_RESULT TSC_PhysicalPresence_Internal(UINT16 physPres); TSS_RESULT TCSP_FlushSpecific_Common(UINT32, TPM_RESOURCE_TYPE); TSS_RESULT TCSP_GetRegisteredKeyByPublicInfo_Internal(TCS_CONTEXT_HANDLE tcsContext, TCPA_ALGORITHM_ID algID, /* in */ UINT32 ulPublicInfoLength, /* in */ BYTE * rgbPublicInfo, /* in */ UINT32 * keySize, BYTE ** keyBlob); TSS_RESULT TCS_OpenContext_Internal(TCS_CONTEXT_HANDLE * hContext /* out */ ); TSS_RESULT TCS_CloseContext_Internal(TCS_CONTEXT_HANDLE hContext /* in */ ); TSS_RESULT TCS_FreeMemory_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ BYTE * pMemory /* in */ ); TSS_RESULT TCS_LogPcrEvent_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_PCR_EVENT Event, /* in */ UINT32 * pNumber /* out */ ); TSS_RESULT TCS_GetPcrEvent_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 PcrIndex, /* in */ UINT32 * pNumber, /* in, out */ TSS_PCR_EVENT ** ppEvent /* out */ ); TSS_RESULT TCS_GetPcrEventsByPcr_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 PcrIndex, /* in */ UINT32 FirstEvent, /* in */ UINT32 * pEventCount, /* in,out */ TSS_PCR_EVENT ** ppEvents /* out */ ); TSS_RESULT TCS_GetPcrEventLog_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 * pEventCount, /* out */ TSS_PCR_EVENT ** ppEvents /* out */ ); TSS_RESULT TCS_RegisterKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *WrappingKeyUUID, /* in */ TSS_UUID *KeyUUID, /* in */ UINT32 cKeySize, /* in */ BYTE * rgbKey, /* in */ UINT32 cVendorData, /* in */ BYTE * gbVendorData /* in */ ); TSS_RESULT TCS_UnregisterKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID KeyUUID /* in */ ); TSS_RESULT TCS_EnumRegisteredKeys_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO ** ppKeyHierarchy /* out */ ); TSS_RESULT TCS_EnumRegisteredKeys_Internal2(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID * pKeyUUID, /* in */ UINT32 * pcKeyHierarchySize, /* out */ TSS_KM_KEYINFO2 ** ppKeyHierarchy /* out */ ); TSS_RESULT TCS_GetRegisteredKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *KeyUUID, /* in */ TSS_KM_KEYINFO ** ppKeyInfo /* out */ ); TSS_RESULT TCS_GetRegisteredKeyBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *KeyUUID, /* in */ UINT32 * pcKeySize, /* out */ BYTE ** prgbKey /* out */ ); TSS_RESULT TCSP_LoadKeyByBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hUnwrappingKey, /* in */ UINT32 cWrappedKeyBlobSize, /* in */ BYTE * rgbWrappedKeyBlob, /* in */ TPM_AUTH * pAuth, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI, /* out */ TCS_KEY_HANDLE * phKeyHMAC /* out */ ); TSS_RESULT TCSP_LoadKey2ByBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hUnwrappingKey, /* in */ UINT32 cWrappedKeyBlobSize, /* in */ BYTE * rgbWrappedKeyBlob, /* in */ TPM_AUTH * pAuth, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI /* out */ ); TSS_RESULT TCSP_LoadKeyByUUID_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_UUID *KeyUUID, /* in */ TCS_LOADKEY_INFO * pLoadKeyInfo, /* in, out */ TCS_KEY_HANDLE * phKeyTCSI /* out */ ); TSS_RESULT TCSP_EvictKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey /* in */ ); TSS_RESULT TCSP_CreateWrapKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hWrappingKey, /* in */ TCPA_ENCAUTH KeyUsageAuth, /* in */ TCPA_ENCAUTH KeyMigrationAuth, /* in */ UINT32 keyInfoSize, /* in */ BYTE * keyInfo, /* in */ UINT32 * keyDataSize, /* out */ BYTE ** keyData, /* out */ TPM_AUTH * pAuth /* in, out */ ); TSS_RESULT TCSP_GetPubKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * pcPubKeySize, /* out */ BYTE ** prgbPubKey /* out */ ); TSS_RESULT TCSP_MakeIdentity_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_ENCAUTH identityAuth, /* in */ TCPA_CHOSENID_HASH IDLabel_PrivCAHash, /* in */ UINT32 idKeyInfoSize, /*in */ BYTE * idKeyInfo, /*in */ TPM_AUTH * pSrkAuth, /* in, out */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * idKeySize, /* out */ BYTE ** idKey, /* out */ UINT32 * pcIdentityBindingSize, /* out */ BYTE ** prgbIdentityBinding, /* out */ UINT32 * pcEndorsementCredentialSize, /* out */ BYTE ** prgbEndorsementCredential, /* out */ UINT32 * pcPlatformCredentialSize, /* out */ BYTE ** prgbPlatformCredential, /* out */ UINT32 * pcConformanceCredentialSize, /* out */ BYTE ** prgbConformanceCredential /* out */ ); TSS_RESULT TCSP_MakeIdentity2_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_ENCAUTH identityAuth, /* in */ TCPA_CHOSENID_HASH IDLabel_PrivCAHash, /* in */ UINT32 idKeyInfoSize, /*in */ BYTE * idKeyInfo, /*in */ TPM_AUTH * pSrkAuth, /* in, out */ TPM_AUTH * pOwnerAuth, /* in, out */ UINT32 * idKeySize, /* out */ BYTE ** idKey, /* out */ UINT32 * pcIdentityBindingSize, /* out */ BYTE ** prgbIdentityBinding /* out */ ); TSS_RESULT TCS_GetCredential_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 ulCredentialType, /* in */ UINT32 ulCredentialAccessMode, /* in */ UINT32 * pulCredentialSize, /* out */ BYTE ** prgbCredentialData /* out */ ); TSS_RESULT TCSP_SetOwnerInstall_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL state /* in */ ); TSS_RESULT TCSP_TakeOwnership_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT16 protocolID, /* in */ UINT32 encOwnerAuthSize, /* in */ BYTE * encOwnerAuth, /* in */ UINT32 encSrkAuthSize, /* in */ BYTE * encSrkAuth, /* in */ UINT32 srkInfoSize, /*in */ BYTE * srkInfo, /*in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * srkKeySize, /*out */ BYTE ** srkKey /*out */ ); TSS_RESULT TCSP_OIAP_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_AUTHHANDLE * authHandle, /* out */ TCPA_NONCE * nonce0 /* out */ ); TSS_RESULT TCSP_OSAP_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 entityValue, /* in */ TCPA_NONCE nonceOddOSAP, /* in */ TCS_AUTHHANDLE * authHandle, /* out */ TCPA_NONCE * nonceEven, /* out */ TCPA_NONCE * nonceEvenOSAP /* out */ ); TSS_RESULT TCSP_ChangeAuth_Internal(TCS_CONTEXT_HANDLE contextHandle, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * ownerAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ); TSS_RESULT TCSP_ChangeAuthOwner_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PROTOCOL_ID protocolID, /* in */ TCPA_ENCAUTH newAuth, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_ChangeAuthAsymStart_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE idHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 KeySizeIn, /* in */ BYTE * KeyDataIn, /* in */ TPM_AUTH * pAuth, /* in, out */ UINT32 * KeySizeOut, /* out */ BYTE ** KeyDataOut, /* out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig, /* out */ TCS_KEY_HANDLE * ephHandle /* out */ ); TSS_RESULT TCSP_ChangeAuthAsymFinish_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCS_KEY_HANDLE ephHandle, /* in */ TCPA_ENTITY_TYPE entityType, /* in */ TCPA_HMAC newAuthLink, /* in */ UINT32 newAuthSize, /* in */ BYTE * encNewAuth, /* in */ UINT32 encDataSizeIn, /* in */ BYTE * encDataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * encDataSizeOut, /* out */ BYTE ** encDataOut, /* out */ TCPA_NONCE * saltNonce, /* out */ TCPA_DIGEST * changeProof /* out */ ); TSS_RESULT TCSP_TerminateHandle_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_AUTHHANDLE handle /* in */ ); TSS_RESULT TCSP_ActivateTPMIdentity_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE idKey, /* in */ UINT32 blobSize, /* in */ BYTE * blob, /* in */ TPM_AUTH * idKeyAuth, /* in, out */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * SymmetricKeySize, /* out */ BYTE ** SymmetricKey /* out */ ); TSS_RESULT TCSP_Extend_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_DIGEST inDigest, /* in */ TCPA_PCRVALUE * outDigest /* out */ ); TSS_RESULT TCSP_PcrRead_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PCRINDEX pcrNum, /* in */ TCPA_PCRVALUE * outDigest /* out */ ); TSS_RESULT TCSP_PcrReset_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrData /* in */ ); TSS_RESULT TCSP_Quote_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig /* out */ ); TSS_RESULT TCSP_Quote2_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 pcrDataSizeIn, /* in */ BYTE * pcrDataIn, /* in */ TSS_BOOL addVersion, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * pcrDataSizeOut, /* out */ BYTE ** pcrDataOut, /* out */ UINT32 * versionInfoSize, /* out */ BYTE ** versionInfo, /* out */ UINT32 * sigSize, /* out */ BYTE ** sig /* out */ ); TSS_RESULT TCSP_DirWriteAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE newContents, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_DirRead_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_DIRINDEX dirIndex, /* in */ TCPA_DIRVALUE * dirValue /* out */ ); /* Since only the ordinal differs between Seal and Sealx (from an API point of view), use a common Seal function specifying the ordinal to be sent to the TPM. */ TSS_RESULT TCSP_Seal_Internal(UINT32 sealOrdinal, /* in */ TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_ENCAUTH encAuth, /* in */ UINT32 pcrInfoSize, /* in */ BYTE * PcrInfo, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * pubAuth, /* in, out */ UINT32 * SealedDataSize, /* out */ BYTE ** SealedData /* out */ ); TSS_RESULT TCSP_Unseal_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 SealedDataSize, /* in */ BYTE * SealedData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * dataAuth, /* in, out */ UINT32 * DataSize, /* out */ BYTE ** Data /* out */ ); TSS_RESULT TCSP_UnBind_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ); TSS_RESULT TCSP_CreateMigrationBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TCPA_MIGRATE_SCHEME migrationType, /* in */ UINT32 MigrationKeyAuthSize, /* in */ BYTE * MigrationKeyAuth, /* in */ UINT32 encDataSize, /* in */ BYTE * encData, /* in */ TPM_AUTH * parentAuth, /* in, out */ TPM_AUTH * entityAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ); TSS_RESULT TCSP_ConvertMigrationBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ UINT32 inDataSize, /* in */ BYTE * inData, /* in */ UINT32 randomSize, /* in */ BYTE * random, /* in */ TPM_AUTH * parentAuth, /* in, out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ); TSS_RESULT TCSP_AuthorizeMigrationKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_MIGRATE_SCHEME migrateScheme, /* in */ UINT32 MigrationKeySize, /* in */ BYTE * MigrationKey, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * MigrationKeyAuthSize, /* out */ BYTE ** MigrationKeyAuth /* out */ ); TSS_RESULT TCSP_CertifyKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE certHandle, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TPM_AUTH * certAuth, /* in, out */ TPM_AUTH * keyAuth, /* in, out */ UINT32 * CertifyInfoSize, /* out */ BYTE ** CertifyInfo, /* out */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ); TSS_RESULT TCSP_Sign_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 areaToSignSize, /* in */ BYTE * areaToSign, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig /* out */ ); TSS_RESULT TCSP_GetRandom_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 * bytesRequested, /* in, out */ BYTE ** randomBytes /* out */ ); TSS_RESULT TCSP_StirRandom_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 inDataSize, /* in */ BYTE * inData /* in */ ); TSS_RESULT TCS_GetCapability_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp /* out */ ); TSS_RESULT TCSP_GetCapability_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 * respSize, /* out */ BYTE ** resp /* out */ ); TSS_RESULT TCSP_SetCapability_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_CAPABILITY_AREA capArea, /* in */ UINT32 subCapSize, /* in */ BYTE * subCap, /* in */ UINT32 valueSize, /* in */ BYTE * value, /* in */ TPM_AUTH * pOwnerAuth /* in, out */ ); TSS_RESULT TCSP_GetCapabilityOwner_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * pOwnerAuth, /* out */ TCPA_VERSION * pVersion, /* out */ UINT32 * pNonVolatileFlags, /* out */ UINT32 * pVolatileFlags /* out */ ); TSS_RESULT TCSP_CreateEndorsementKeyPair_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize, /* in */ BYTE * endorsementKeyInfo, /* in */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TCPA_DIGEST * checksum /* out */ ); TSS_RESULT TCSP_ReadPubek_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey, /* out */ TCPA_DIGEST * checksum /* out */ ); TSS_RESULT TCSP_DisablePubekRead_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_OwnerReadPubek_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * pubEndorsementKeySize, /* out */ BYTE ** pubEndorsementKey /* out */ ); TSS_RESULT TCSP_CreateRevocableEndorsementKeyPair_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_NONCE antiReplay, /* in */ UINT32 endorsementKeyInfoSize, /* in */ BYTE * endorsementKeyInfo, /* in */ TSS_BOOL genResetAuth, /* in */ TPM_DIGEST * eKResetAuth, /* in, out */ UINT32 * endorsementKeySize, /* out */ BYTE ** endorsementKey, /* out */ TPM_DIGEST * checksum /* out */ ); TSS_RESULT TCSP_RevokeEndorsementKeyPair_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_DIGEST EKResetAuth /* in */ ); TSS_RESULT TCSP_SelfTestFull_Internal(TCS_CONTEXT_HANDLE hContext /* in */ ); TSS_RESULT TCSP_CertifySelfTest_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TCPA_NONCE antiReplay, /* in */ TPM_AUTH * privAuth, /* in, out */ UINT32 * sigSize, /* out */ BYTE ** sig /* out */ ); TSS_RESULT TCSP_GetTestResult_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 * outDataSize, /* out */ BYTE ** outData /* out */ ); TSS_RESULT TCSP_OwnerSetDisable_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL disableState, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_ResetLockValue_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_OwnerClear_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_DisableOwnerClear_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_ForceClear_Internal(TCS_CONTEXT_HANDLE hContext /* in */ ); TSS_RESULT TCSP_DisableForceClear_Internal(TCS_CONTEXT_HANDLE hContext /* in */ ); TSS_RESULT TCSP_PhysicalPresence_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_PHYSICAL_PRESENCE fPhysicalPresence /* in */ ); TSS_RESULT TCSP_PhysicalDisable_Internal(TCS_CONTEXT_HANDLE hContext /* in */ ); TSS_RESULT TCSP_PhysicalEnable_Internal(TCS_CONTEXT_HANDLE hContext /* in */ ); TSS_RESULT TCSP_PhysicalSetDeactivated_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL state /* in */ ); TSS_RESULT TCSP_SetTempDeactivated_Internal(TCS_CONTEXT_HANDLE hContext /* in */ ); TSS_RESULT TCSP_SetTempDeactivated2_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * operatorAuth /* in, out */ ); TSS_RESULT TCSP_FieldUpgrade_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut, /* out */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_SetRedirection_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ UINT32 c1, /* in */ UINT32 c2, /* in */ TPM_AUTH * privAuth /* in, out */ ); TSS_RESULT TCSP_CreateMaintenanceArchive_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL generateRandom, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * randomSize, /* out */ BYTE ** random, /* out */ UINT32 * archiveSize, /* out */ BYTE ** archive /* out */ ); TSS_RESULT TCSP_LoadMaintenanceArchive_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 dataInSize, /* in */ BYTE * dataIn, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 * dataOutSize, /* out */ BYTE ** dataOut /* out */ ); TSS_RESULT TCSP_KillMaintenanceFeature_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH * ownerAuth /* in, out */ ); TSS_RESULT TCSP_LoadManuMaintPub_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ UINT32 PubKeySize, /* in */ BYTE * PubKey, /* in */ TCPA_DIGEST * checksum /* out */ ); TSS_RESULT TCSP_ReadManuMaintPub_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_NONCE antiReplay, /* in */ TCPA_DIGEST * checksum /* out */ ); TSS_RESULT TCSP_Reset_Internal(TCS_CONTEXT_HANDLE hContext ); TSS_RESULT TCSP_DaaJoin_internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_HANDLE handle, /* in */ BYTE stage, /* in */ UINT32 inputSize0, /* in */ BYTE *inputData0, /* in */ UINT32 inputSize1, /* in */ BYTE *inputData1, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 *outputSize, /* out */ BYTE **outputData /* out */ ); TSS_RESULT TCSP_DaaSign_internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_HANDLE handle, /* in */ BYTE stage, /* in */ UINT32 inputSize0, /* in */ BYTE *inputData0, /* in */ UINT32 inputSize1, /* in */ BYTE *inputData1, /* in */ TPM_AUTH * ownerAuth, /* in, out */ UINT32 *outputSize, /* out */ BYTE **outputData /* out */ ); TSS_RESULT TCSP_ReadCounter_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_COUNTER_VALUE* counterValue ); TSS_RESULT TCSP_CreateCounter_Internal(TCS_CONTEXT_HANDLE hContext, UINT32 LabelSize, BYTE* pLabel, TPM_ENCAUTH CounterAuth, TPM_AUTH* pOwnerAuth, TSS_COUNTER_ID* idCounter, TPM_COUNTER_VALUE* counterValue ); TSS_RESULT TCSP_IncrementCounter_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_AUTH* pCounterAuth, TPM_COUNTER_VALUE* counterValue ); TSS_RESULT TCSP_ReleaseCounter_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_AUTH* pCounterAuth ); TSS_RESULT TCSP_ReleaseCounterOwner_Internal(TCS_CONTEXT_HANDLE hContext, TSS_COUNTER_ID idCounter, TPM_AUTH* pOwnerAuth ); TSS_RESULT TCSP_ReadCurrentTicks_Internal(TCS_CONTEXT_HANDLE hContext, UINT32* pulCurrentTime, BYTE** prgbCurrentTime ); TSS_RESULT TCSP_TickStampBlob_Internal(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_NONCE* antiReplay, TPM_DIGEST* digestToStamp, TPM_AUTH* privAuth, UINT32* pulSignatureLength, BYTE** prgbSignature, UINT32* pulTickCountLength, BYTE** prgbTickCount ); TSS_RESULT TCSP_EstablishTransport_Internal(TCS_CONTEXT_HANDLE hContext, UINT32 ulTransControlFlags, TCS_KEY_HANDLE hEncKey, UINT32 ulTransSessionInfoSize, BYTE* rgbTransSessionInfo, UINT32 ulSecretSize, BYTE* rgbSecret, TPM_AUTH* pEncKeyAuth, TPM_MODIFIER_INDICATOR* pbLocality, TCS_HANDLE* hTransSession, UINT32* ulCurrentTicksSize, BYTE** prgbCurrentTicks, TPM_NONCE* pTransNonce ); TSS_RESULT TCSP_ExecuteTransport_Internal(TCS_CONTEXT_HANDLE hContext, TPM_COMMAND_CODE unWrappedCommandOrdinal, UINT32 ulWrappedCmdParamInSize, BYTE* rgbWrappedCmdParamIn, UINT32* pulHandleListSize, TCS_HANDLE** rghHandles, TPM_AUTH* pWrappedCmdAuth1, TPM_AUTH* pWrappedCmdAuth2, TPM_AUTH* pTransAuth, UINT64* punCurrentTicks, TPM_MODIFIER_INDICATOR* pbLocality, TPM_RESULT* pulWrappedCmdReturnCode, UINT32* ulWrappedCmdParamOutSize, BYTE** rgbWrappedCmdParamOut ); TSS_RESULT TCSP_ReleaseTransportSigned_Internal(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hSignatureKey, TPM_NONCE* AntiReplayNonce, TPM_AUTH* pKeyAuth, TPM_AUTH* pTransAuth, TPM_MODIFIER_INDICATOR* pbLocality, UINT32* pulCurrentTicksSize, BYTE** prgbCurrentTicks, UINT32* pulSignatureSize, BYTE** prgbSignature ); TSS_RESULT TCSP_NV_DefineOrReleaseSpace_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 cPubInfoSize, /* in */ BYTE* pPubInfo, /* in */ TPM_ENCAUTH encAuth, /* in */ TPM_AUTH* pAuth /* in, out */ ); TSS_RESULT TCSP_NV_WriteValue_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* privAuth /* in, out */ ); TSS_RESULT TCSP_NV_WriteValueAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32 ulDataLength, /* in */ BYTE* rgbDataToWrite, /* in */ TPM_AUTH* NVAuth /* in, out */ ); TSS_RESULT TCSP_NV_ReadValue_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in, out */ TPM_AUTH* privAuth, /* in, out */ BYTE** rgbDataRead /* out */ ); TSS_RESULT TCSP_NV_ReadValueAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_NV_INDEX hNVStore, /* in */ UINT32 offset, /* in */ UINT32* pulDataLength, /* in, out */ TPM_AUTH* NVAuth, /* in, out */ BYTE** rgbDataRead /* out */ ); TSS_RESULT TCSP_SetOrdinalAuditStatus_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_AUTH* ownerAuth, /* in, out */ UINT32 ulOrdinal, /* in */ TSS_BOOL bAuditState /* in */ ); TSS_RESULT TCSP_GetAuditDigest_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 startOrdinal, /* in */ TPM_DIGEST* auditDigest, /* out */ UINT32* counterValueSize, /* out */ BYTE** counterValue, /* out */ TSS_BOOL* more, /* out */ UINT32* ordSize, /* out */ UINT32** ordList /* out */ ); TSS_RESULT TCSP_GetAuditDigestSigned_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE keyHandle, /* in */ TSS_BOOL closeAudit, /* in */ TPM_NONCE antiReplay, /* in */ TPM_AUTH* privAuth, /* in, out */ UINT32* counterValueSize, /* out */ BYTE** counterValue, /* out */ TPM_DIGEST* auditDigest, /* out */ TPM_DIGEST* ordinalDigest, /* out */ UINT32* sigSize, /* out */ BYTE** sig /* out */ ); TSS_RESULT TCSP_SetOperatorAuth_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCPA_SECRET* operatorAuth /* in */ ); TSS_RESULT TCSP_OwnerReadInternalPub_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_AUTH* pOwnerAuth, /*in, out*/ UINT32* punPubKeySize, /* out */ BYTE** ppbPubKeyData /* out */ ); TSS_RESULT TCSP_Delegate_Manage_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_FAMILY_ID familyID, /* in */ TPM_FAMILY_OPERATION opFlag, /* in */ UINT32 opDataSize, /* in */ BYTE* opData, /* in */ TPM_AUTH* ownerAuth, /* in, out */ UINT32* retDataSize, /* out */ BYTE** retData /* out */ ); TSS_RESULT TCSP_Delegate_CreateKeyDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ UINT32 publicInfoSize, /* in */ BYTE* publicInfo, /* in */ TPM_ENCAUTH* encDelAuth, /* in */ TPM_AUTH* keyAuth, /* in, out */ UINT32* blobSize, /* out */ BYTE** blob /* out */ ); TSS_RESULT TCSP_Delegate_CreateOwnerDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_BOOL increment, /* in */ UINT32 publicInfoSize, /* in */ BYTE* publicInfo, /* in */ TPM_ENCAUTH* encDelAuth, /* in */ TPM_AUTH* ownerAuth, /* in, out */ UINT32* blobSize, /* out */ BYTE** blob /* out */ ); TSS_RESULT TCSP_Delegate_LoadOwnerDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_DELEGATE_INDEX index, /* in */ UINT32 blobSize, /* in */ BYTE* blob, /* in */ TPM_AUTH* ownerAuth /* in, out */ ); TSS_RESULT TCSP_Delegate_ReadTable_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32* pulFamilyTableSize, /* out */ BYTE** ppFamilyTable, /* out */ UINT32* pulDelegateTableSize, /* out */ BYTE** ppDelegateTable /* out */ ); TSS_RESULT TCSP_Delegate_UpdateVerificationCount_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 inputSize, /* in */ BYTE* input, /* in */ TPM_AUTH* ownerAuth, /* in, out */ UINT32* outputSize, /* out */ BYTE** output /* out */ ); TSS_RESULT TCSP_Delegate_VerifyDelegation_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 delegateSize, /* in */ BYTE* delegate /* in */ ); TSS_RESULT TCSP_CMK_SetRestrictions_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TSS_CMK_DELEGATE Restriction, /* in */ TPM_AUTH* ownerAuth /* in */ ); TSS_RESULT TCSP_CMK_ApproveMA_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_DIGEST migAuthorityDigest, /* in */ TPM_AUTH* ownerAuth, /* in, out */ TPM_HMAC* HmacMigAuthDigest /* out */ ); TSS_RESULT TCSP_CMK_CreateKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hWrappingKey, /* in */ TPM_ENCAUTH KeyUsageAuth, /* in */ TPM_HMAC MigAuthApproval, /* in */ TPM_DIGEST MigAuthorityDigest, /* in */ UINT32* keyDataSize, /* in, out */ BYTE** prgbKeyData, /* in, out */ TPM_AUTH* pAuth /* in, out */ ); TSS_RESULT TCSP_CMK_CreateTicket_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ UINT32 PublicVerifyKeySize, /* in */ BYTE* PublicVerifyKey, /* in */ TPM_DIGEST SignedData, /* in */ UINT32 SigValueSize, /* in */ BYTE* SigValue, /* in */ TPM_AUTH* pOwnerAuth, /* in, out */ TPM_HMAC* SigTicket /* out */ ); TSS_RESULT TCSP_CMK_CreateBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TSS_MIGRATE_SCHEME migrationType, /* in */ UINT32 MigrationKeyAuthSize, /* in */ BYTE* MigrationKeyAuth, /* in */ TPM_DIGEST PubSourceKeyDigest, /* in */ UINT32 msaListSize, /* in */ BYTE* msaList, /* in */ UINT32 restrictTicketSize, /* in */ BYTE* restrictTicket, /* in */ UINT32 sigTicketSize, /* in */ BYTE* sigTicket, /* in */ UINT32 encDataSize, /* in */ BYTE* encData, /* in */ TPM_AUTH* parentAuth, /* in, out */ UINT32* randomSize, /* out */ BYTE** random, /* out */ UINT32* outDataSize, /* out */ BYTE** outData /* out */ ); TSS_RESULT TCSP_CMK_ConvertMigration_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE parentHandle, /* in */ TPM_CMK_AUTH restrictTicket, /* in */ TPM_HMAC sigTicket, /* in */ UINT32 keyDataSize, /* in */ BYTE* prgbKeyData, /* in */ UINT32 msaListSize, /* in */ BYTE* msaList, /* in */ UINT32 randomSize, /* in */ BYTE* random, /* in */ TPM_AUTH* parentAuth, /* in, out */ UINT32* outDataSize, /* out */ BYTE** outData /* out */ ); TSS_RESULT TCSP_FlushSpecific_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_HANDLE hResHandle, /* in */ TPM_RESOURCE_TYPE resourceType /* in */ ); TSS_RESULT TCSP_KeyControlOwner_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TCS_KEY_HANDLE hKey, /* in */ UINT32 ulPubKeyLength, /* in */ BYTE* rgbPubKey, /* in */ UINT32 attribName, /* in */ TSS_BOOL attribValue, /* in */ TPM_AUTH* pOwnerAuth, /* in,out */ TSS_UUID* pUuidData /* out */ ); TSS_RESULT TCSP_DSAP_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ TPM_ENTITY_TYPE entityType, /* in */ TCS_KEY_HANDLE hKey, /* in */ TPM_NONCE *nonceOddDSAP, /* in */ UINT32 entityValueSize, /* in */ BYTE* entityValue, /* in */ TCS_AUTHHANDLE *authHandle, /* out */ TPM_NONCE *nonceEven, /* out */ TPM_NONCE *nonceEvenDSAP /* out */ ); #endif /*_TCS_UTILS_H_ */ trousers-0.3.15/src/include/tcs_aik.h0000664000175000017510000000041413663651711016753 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006-2007 * */ #ifndef _TCS_AIK_H_ #define _TCS_AIK_H_ void get_credential(UINT32, UINT32 *, BYTE **); #endif trousers-0.3.15/src/include/req_mgr.h0000664000175000017510000000060113663651711016770 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _REQ_MGR_H_ #define _REQ_MGR_H_ #include "threads.h" struct tpm_req_mgr { MUTEX_DECLARE(queue_lock); }; TSS_RESULT req_mgr_init(); TSS_RESULT req_mgr_final(); TSS_RESULT req_mgr_submit_req(BYTE *); #endif trousers-0.3.15/src/include/auth_mgr.h0000664000175000017510000000243513663651711017151 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ #ifndef _AUTH_MGR_H_ #define _AUTH_MGR_H_ struct auth_map { TSS_BOOL full; TPM_AUTHHANDLE tpm_handle; TCS_CONTEXT_HANDLE tcs_ctx; BYTE *swap; /* These 'swap' variables manage blobs received from TPM_SaveAuthContext */ UINT32 swap_size; }; /* * it appears that there's no way to query a v1.1 TPM for the * max number of simultaneous auth sessions. We'll make the * default relatively large and let the TPM return * TCPA_RESOURCES to tell us when we cross the line. */ #define TSS_DEFAULT_AUTH_TABLE_SIZE 16 #define TSS_DEFAULT_OVERFLOW_AUTHS 16 struct _auth_mgr { short max_auth_sessions; short open_auth_sessions; UINT32 sleeping_threads; COND_VAR **overflow; /* queue of TCS contexts waiting for an auth session to become * available */ unsigned int of_head, of_tail; /* head and tail of the overflow queue */ struct auth_map *auth_mapper; /* table of currently tracked auth sessions */ UINT32 auth_mapper_size, overflow_size; } auth_mgr; MUTEX_DECLARE_INIT(auth_mgr_lock); TSS_RESULT TPM_SaveAuthContext(TPM_AUTHHANDLE, UINT32 *, BYTE **); TSS_RESULT TPM_LoadAuthContext(UINT32, BYTE *, TPM_AUTHHANDLE *); #endif trousers-0.3.15/src/include/tspps.h0000664000175000017510000000466613663651711016524 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef _TSPPS_H_ #define _TSPPS_H_ #define PASSWD_BUFSIZE 4096 #define TSS_USER_PS_DIR ".trousers" #define TSS_USER_PS_FILE "user.data" TSS_RESULT get_file(int *); int put_file(int); inline TSS_RESULT read_data(int, void *, UINT32); inline TSS_RESULT write_data(int, void *, UINT32); UINT32 psfile_get_num_keys(int); TSS_RESULT psfile_get_parent_uuid_by_uuid(int, TSS_UUID *, TSS_UUID *); TSS_RESULT psfile_remove_key_by_uuid(int, TSS_UUID *); TSS_RESULT psfile_get_key_by_uuid(int, TSS_UUID *, BYTE *); TSS_RESULT psfile_get_ps_type_by_uuid(int, TSS_UUID *, UINT32 *); TSS_RESULT psfile_is_pub_registered(int, TCPA_STORE_PUBKEY *, TSS_BOOL *); TSS_RESULT psfile_is_key_registered(int, TSS_UUID *, TSS_BOOL *); TSS_RESULT psfile_get_uuid_by_pub(int, UINT32, BYTE *, TSS_UUID *); TSS_RESULT psfile_write_key(int, TSS_UUID *, TSS_UUID *, UINT32, BYTE *, UINT16); TSS_RESULT psfile_get_key_by_pub(int, TSS_UUID *, UINT32, BYTE *, BYTE *); TSS_RESULT psfile_get_registered_keys(int, TSS_UUID *, TSS_UUID *, UINT32 *, TSS_KM_KEYINFO **); TSS_RESULT psfile_get_registered_keys2(int, TSS_UUID *, TSS_UUID *, UINT32 *, TSS_KM_KEYINFO2 **); TSS_RESULT psfile_remove_key(int, TSS_UUID *); TSS_RESULT psfile_get_parent_ps_type(int, TSS_UUID *, UINT32 *); TSS_RESULT psfile_get_cache_entry_by_uuid(int, TSS_UUID *, struct key_disk_cache *); TSS_RESULT psfile_get_cache_entry_by_pub(int, UINT32, BYTE *, struct key_disk_cache *); void psfile_close(int); TSS_RESULT ps_remove_key(TSS_UUID *); TSS_RESULT ps_write_key(TSS_UUID *, TSS_UUID *, UINT32, UINT32, BYTE *); TSS_RESULT ps_get_key_by_uuid(TSS_HCONTEXT, TSS_UUID *, TSS_HKEY *); TSS_RESULT ps_init_disk_cache(); TSS_RESULT ps_close(); TSS_RESULT ps_get_key_by_pub(TSS_HCONTEXT, UINT32, BYTE *, TSS_HKEY *); TSS_RESULT ps_get_parent_uuid_by_uuid(TSS_UUID *, TSS_UUID *); TSS_RESULT ps_get_parent_ps_type_by_uuid(TSS_UUID *, UINT32 *); TSS_RESULT ps_is_key_registered(TSS_UUID *, TSS_BOOL *); TSS_RESULT ps_get_registered_keys(TSS_UUID *uuid, TSS_UUID *, UINT32 *size, TSS_KM_KEYINFO **); TSS_RESULT ps_get_registered_keys2(TSS_UUID *uuid, TSS_UUID *, UINT32 *size, TSS_KM_KEYINFO2 **); #ifdef TSS_BUILD_PS #define PS_close() ps_close() #else #define PS_close() #endif #endif trousers-0.3.15/src/include/obj_delfamily.h0000664000175000017510000000410113663651711020133 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #ifndef _OBJ_DELFAMILY_H_ #define _OBJ_DELFAMILY_H_ #ifdef TSS_BUILD_DELEGATION #define TSS_DELFAMILY_FLAGS_STATE_ENABLED (((UINT32)1)<<0) #define TSS_DELFAMILY_FLAGS_STATE_LOCKED (((UINT32)1)<<1) /* structures */ struct tr_delfamily_obj { UINT32 stateFlags; UINT32 verCount; UINT32 familyID; BYTE label; }; /* obj_delfamily.c */ void delfamily_free(void *data); TSS_BOOL obj_is_delfamily(TSS_HOBJECT); TSS_RESULT obj_delfamily_add(TSS_HCONTEXT, TSS_HOBJECT *); TSS_RESULT obj_delfamily_remove(TSS_HDELFAMILY, TSS_HOBJECT); void obj_delfamily_find_by_familyid(TSS_HOBJECT, UINT32, TSS_HDELFAMILY *); TSS_RESULT obj_delfamily_get_tsp_context(TSS_HDELFAMILY, TSS_HCONTEXT *); TSS_RESULT obj_delfamily_set_locked(TSS_HDELFAMILY, TSS_BOOL, TSS_BOOL); TSS_RESULT obj_delfamily_get_locked(TSS_HDELFAMILY, TSS_BOOL *); TSS_RESULT obj_delfamily_set_enabled(TSS_HDELFAMILY, TSS_BOOL, TSS_BOOL); TSS_RESULT obj_delfamily_get_enabled(TSS_HDELFAMILY, TSS_BOOL *); TSS_RESULT obj_delfamily_set_vercount(TSS_HDELFAMILY, UINT32); TSS_RESULT obj_delfamily_get_vercount(TSS_HDELFAMILY, UINT32 *); TSS_RESULT obj_delfamily_set_familyid(TSS_HDELFAMILY, UINT32); TSS_RESULT obj_delfamily_get_familyid(TSS_HDELFAMILY, UINT32 *); TSS_RESULT obj_delfamily_set_label(TSS_HDELFAMILY, BYTE); TSS_RESULT obj_delfamily_get_label(TSS_HDELFAMILY, BYTE *); #define DELFAMILY_LIST_DECLARE struct obj_list delfamily_list #define DELFAMILY_LIST_DECLARE_EXTERN extern struct obj_list delfamily_list #define DELFAMILY_LIST_INIT() tspi_list_init(&delfamily_list) #define DELFAMILY_LIST_CONNECT(a,b) obj_connectContext_list(&delfamily_list, a, b) #define DELFAMILY_LIST_CLOSE(a) obj_list_close(&delfamily_list, &delfamily_free, a) #else #define obj_is_delfamily(a) FALSE #define DELFAMILY_LIST_DECLARE #define DELFAMILY_LIST_DECLARE_EXTERN #define DELFAMILY_LIST_INIT() #define DELFAMILY_LIST_CONNECT(a,b) #define DELFAMILY_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/trousers_types.h0000664000175000017510000001073013663651711020452 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005, 2007 * */ #ifndef _TROUSERS_TYPES_H_ #define _TROUSERS_TYPES_H_ #define TCPA_NONCE_SIZE sizeof(TCPA_NONCE) #define TCPA_DIGEST_SIZE sizeof(TCPA_DIGEST) #define TCPA_ENCAUTH_SIZE sizeof(TCPA_ENCAUTH) #define TCPA_DIRVALUE_SIZE sizeof(TCPA_DIRVALUE) #define TCPA_AUTHDATA_SIZE sizeof(TCPA_AUTHDATA) #define TPM_NONCE_SIZE TCPA_NONCE_SIZE #define TPM_DIGEST_SIZE TCPA_DIGEST_SIZE #define TPM_ENCAUTH_SIZE TCPA_ENCAUTH_SIZE #define TPM_DIRVALUE_SIZE TCPA_DIRVALUE_SIZE #define TPM_AUTHDATA_SIZE TCPA_AUTHDATA_SIZE #define TSS_FLAG_MIGRATABLE (migratable) #define TSS_FLAG_VOLATILE (volatileKey) #define TSS_FLAG_REDIRECTION (redirection) /* return codes */ #define TCPA_E_INAPPROPRIATE_ENC TCPA_E_NEED_SELFTEST #define TSS_ERROR_LAYER(x) (x & 0x3000) #define TSS_ERROR_CODE(x) (x & TSS_MAX_ERROR) #ifdef TSS_DEBUG #define TSPERR(x) LogTSPERR(x, __FILE__, __LINE__) #define TCSERR(x) LogTCSERR(x, __FILE__, __LINE__) #define TDDLERR(x) LogTDDLERR(x, __FILE__, __LINE__) #else #define TSPERR(x) (x | TSS_LAYER_TSP) #define TCSERR(x) (x | TSS_LAYER_TCS) #define TDDLERR(x) (x | TSS_LAYER_TDDL) #endif extern TSS_UUID NULL_UUID; extern TSS_UUID SRK_UUID; #define NULL_HOBJECT 0 #define NULL_HCONTEXT NULL_HOBJECT #define NULL_HPCRS NULL_HOBJECT #define NULL_HENCDATA NULL_HOBJECT #define NULL_HKEY NULL_HOBJECT #define NULL_HTPM NULL_HOBJECT #define NULL_HHASH NULL_HOBJECT #define NULL_HPOLICY NULL_HOBJECT #define NULL_HDELFAMILY NULL_HOBJECT #define NULL_HMIGDATA NULL_HOBJECT #define TSS_OBJECT_TYPE_CONTEXT (0x0e) #define TSS_OBJECT_TYPE_TPM (0x0f) #define TSS_PS_TYPE_NO (0) /* Derived Types */ #define TSS_MIGRATION_SCHEME TSS_MIGRATE_SCHEME // The TPM's non-volatile flags (TPM_PERMANENT_FLAGS) #define TSS_TPM_PF_DISABLE_BIT (1 << (TPM_PF_DISABLE - 1)) #define TSS_TPM_PF_OWNERSHIP_BIT (1 << (TPM_PF_OWNERSHIP - 1)) #define TSS_TPM_PF_DEACTIVATED_BIT (1 << (TPM_PF_DEACTIVATED - 1)) #define TSS_TPM_PF_READPUBEK_BIT (1 << (TPM_PF_READPUBEK - 1)) #define TSS_TPM_PF_DISABLEOWNERCLEAR_BIT (1 << (TPM_PF_DISABLEOWNERCLEAR - 1)) #define TSS_TPM_PF_ALLOWMAINTENANCE_BIT (1 << (TPM_PF_ALLOWMAINTENANCE - 1)) #define TSS_TPM_PF_PHYSICALPRESENCELIFETIMELOCK_BIT (1 << (TPM_PF_PHYSICALPRESENCELIFETIMELOCK - 1)) #define TSS_TPM_PF_PHYSICALPRESENCEHWENABLE_BIT (1 << (TPM_PF_PHYSICALPRESENCEHWENABLE - 1)) #define TSS_TPM_PF_PHYSICALPRESENCECMDENABLE_BIT (1 << (TPM_PF_PHYSICALPRESENCECMDENABLE - 1)) #define TSS_TPM_PF_CEKPUSED_BIT (1 << (TPM_PF_CEKPUSED - 1)) #define TSS_TPM_PF_TPMPOST_BIT (1 << (TPM_PF_TPMPOST - 1)) #define TSS_TPM_PF_TPMPOSTLOCK_BIT (1 << (TPM_PF_TPMPOSTLOCK - 1)) #define TSS_TPM_PF_FIPS_BIT (1 << (TPM_PF_FIPS - 1)) #define TSS_TPM_PF_OPERATOR_BIT (1 << (TPM_PF_OPERATOR - 1)) #define TSS_TPM_PF_ENABLEREVOKEEK_BIT (1 << (TPM_PF_ENABLEREVOKEEK - 1)) #define TSS_TPM_PF_NV_LOCKED_BIT (1 << (TPM_PF_NV_LOCKED - 1)) #define TSS_TPM_PF_READSRKPUB_BIT (1 << (TPM_PF_READSRKPUB - 1)) #define TSS_TPM_PF_RESETESTABLISHMENTBIT_BIT (1 << (TPM_PF_RESETESTABLISHMENTBIT - 1)) #define TSS_TPM_PF_MAINTENANCEDONE_BIT (1 << (TPM_PF_MAINTENANCEDONE - 1)) // The TPM's volatile flags (TPM_STCLEAR_FLAGS) #define TSS_TPM_SF_DEACTIVATED_BIT (1 << (TPM_SF_DEACTIVATED - 1)) #define TSS_TPM_SF_DISABLEFORCECLEAR_BIT (1 << (TPM_SF_DISABLEFORCECLEAR - 1)) #define TSS_TPM_SF_PHYSICALPRESENCE_BIT (1 << (TPM_SF_PHYSICALPRESENCE - 1)) #define TSS_TPM_SF_PHYSICALPRESENCELOCK_BIT (1 << (TPM_SF_PHYSICALPRESENCELOCK - 1)) #define TSS_TPM_SF_GLOBALLOCK_BIT (1 << (TPM_SF_GLOBALLOCK - 1)) // Trousers key formats to ease use of the different TPM_KEY structs typedef struct tdTSS_KEY11_HDR { TPM_STRUCT_VER ver; } TSS_KEY11_HDR; typedef struct tdTSS_KEY12_HDR { TPM_STRUCTURE_TAG tag; UINT16 fill; } __attribute__((packed)) TSS_KEY12_HDR; typedef struct tdTSS_KEY { union { TSS_KEY11_HDR key11; TSS_KEY12_HDR key12; } hdr; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_AUTH_DATA_USAGE authDataUsage; TPM_KEY_PARMS algorithmParms; UINT32 PCRInfoSize; BYTE *PCRInfo; TPM_STORE_PUBKEY pubKey; UINT32 encSize; BYTE *encData; } TSS_KEY; #if (defined (__linux) || defined (linux) || defined (SOLARIS) || defined (__GLIBC__)) #define BSD_CONST #elif (defined (__OpenBSD__) || defined (__FreeBSD__)) || defined (__APPLE__) #define BSD_CONST const #endif #endif trousers-0.3.15/src/include/obj_encdata.h0000664000175000017510000000424513663651711017575 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_ENCDATA_H_ #define _OBJ_ENCDATA_H_ #ifdef TSS_BUILD_ENCDATA_LIST /* structures */ struct tr_encdata_obj { TSS_HPOLICY usagePolicy; UINT32 encryptedDataLength; BYTE *encryptedData; union { TPM_PCR_INFO info11; TPM_PCR_INFO_LONG infolong; } pcrInfo; UINT32 pcrInfoType; UINT32 type; #ifdef TSS_BUILD_SEALX UINT32 protectMode; #endif }; /* obj_encdata.c */ void encdata_free(void *data); TSS_BOOL obj_is_encdata(TSS_HOBJECT); TSS_RESULT obj_encdata_set_policy(TSS_HKEY, TSS_HPOLICY); TSS_RESULT obj_encdata_set_data(TSS_HENCDATA, UINT32, BYTE *); TSS_RESULT obj_encdata_remove(TSS_HOBJECT, TSS_HCONTEXT); TSS_RESULT obj_encdata_get_tsp_context(TSS_HENCDATA, TSS_HCONTEXT *); TSS_RESULT obj_encdata_add(TSS_HCONTEXT, UINT32, TSS_HOBJECT *); TSS_RESULT obj_encdata_get_data(TSS_HENCDATA, UINT32 *, BYTE **); TSS_RESULT obj_encdata_get_pcr_selection(TSS_HENCDATA, TSS_FLAG, TSS_FLAG, UINT32 *, BYTE **); TSS_RESULT obj_encdata_get_pcr_locality(TSS_HENCDATA, TSS_FLAG, UINT32 *); TSS_RESULT obj_encdata_get_pcr_digest(TSS_HENCDATA, TSS_FLAG, TSS_FLAG, UINT32 *, BYTE **); TSS_RESULT obj_encdata_set_pcr_info(TSS_HENCDATA, UINT32, BYTE *); TSS_RESULT obj_encdata_get_policy(TSS_HENCDATA, UINT32, TSS_HPOLICY *); void obj_encdata_remove_policy_refs(TSS_HPOLICY, TSS_HCONTEXT); #ifdef TSS_BUILD_SEALX TSS_RESULT obj_encdata_set_seal_protect_mode(TSS_HENCDATA, UINT32); TSS_RESULT obj_encdata_get_seal_protect_mode(TSS_HENCDATA, UINT32 *); #endif #define ENCDATA_LIST_DECLARE struct obj_list encdata_list #define ENCDATA_LIST_DECLARE_EXTERN extern struct obj_list encdata_list #define ENCDATA_LIST_INIT() tspi_list_init(&encdata_list) #define ENCDATA_LIST_CONNECT(a,b) obj_connectContext_list(&encdata_list, a, b) #define ENCDATA_LIST_CLOSE(a) obj_list_close(&encdata_list, &encdata_free, a) #else #define obj_is_encdata(a) FALSE #define ENCDATA_LIST_DECLARE #define ENCDATA_LIST_DECLARE_EXTERN #define ENCDATA_LIST_INIT() #define ENCDATA_LIST_CONNECT(a,b) #define ENCDATA_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/obj_migdata.h0000664000175000017510000001311713663651711017602 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #ifndef _OBJ_MIGDATA_H_ #define _OBJ_MIGDATA_H_ #ifdef TSS_BUILD_CMK /* structures */ struct tr_migdata_obj { /* TSS_MIGATTRIB_MIGRATIONTICKET (from AuthorizeMigrationTicket) */ UINT32 migTicketSize; BYTE *migTicket; /* TSS_MIGATTRIB_AUTHORITY_DATA/TSS_MIGATTRIB_AUTHORITY_MSALIST - Recalculate the msaDigest or TSS_MIGATTRIB_MIGRATIONBLOB/TSS_MIGATTRIB_MIG_MSALIST_PUBKEY_BLOB - Create a digest from the pubkey blob and append to the list - Recalculate the msaDigest */ TPM_MSA_COMPOSITE msaList; /* TSS_MIGATTRIB_AUTHORITY_DATA/TSS_MIGATTRIB_AUTHORITY_DIGEST */ TPM_DIGEST msaDigest; /* TSS_MIGATTRIB_AUTHORITY_DATA/TSS_MIGATTRIB_AUTHORITY_APPROVAL_HMAC */ TPM_HMAC msaHmac; /* TSS_MIGATTRIB_MIG_AUTH_DATA/TSS_MIGATTRIB_MIG_AUTH_AUTHORITY_DIGEST or TSS_MIGATTRIB_MIGRATIONBLOB/TSS_MIGATTRIB_MIG_AUTHORITY_PUBKEY_BLOB - Create a digest from the pubkey blob */ TPM_DIGEST maDigest; /* TSS_MIGATTRIB_MIG_AUTH_DATA/TSS_MIGATTRIB_MIG_AUTH_DESTINATION_DIGEST or TSS_MIGATTRIB_MIGRATIONBLOB/TSS_MIGATTRIB_MIG_DESTINATION_PUBKEY_BLOB - Create a digest from the pubkey blob */ TPM_DIGEST destDigest; /* TSS_MIGATTRIB_MIG_AUTH_DATA/TSS_MIGATTRIB_MIG_AUTH_SOURCE_DIGEST or TSS_MIGATTRIB_MIGRATIONBLOB/TSS_MIGATTRIB_MIG_SOURCE_PUBKEY_BLOB - Create a digest from the pubkey blob */ TPM_DIGEST srcDigest; /* TSS_MIGATTRIB_TICKET_DATA/TSS_MIGATTRIB_TICKET_SIG_DIGEST */ TPM_DIGEST sigData; /* TSS_MIGATTRIB_TICKET_DATA/TSS_MIGATTRIB_TICKET_SIG_VALUE */ UINT32 sigValueSize; BYTE *sigValue; /* TSS_MIGATTRIB_TICKET_DATA/TSS_MIGATTRIB_TICKET_SIG_TICKET */ TPM_HMAC sigTicket; /* TSS_MIGATTRIB_MIGRATIONBLOB/TSS_MIGATTRIB_MIGRATION_XOR_BLOB */ UINT32 blobSize; BYTE *blob; }; /* obj_migdata.c */ void migdata_free(void *data); TSS_BOOL obj_is_migdata(TSS_HOBJECT); TSS_RESULT obj_migdata_add(TSS_HCONTEXT, TSS_HOBJECT *); TSS_RESULT obj_migdata_remove(TSS_HMIGDATA, TSS_HOBJECT); TSS_RESULT obj_migdata_get_tsp_context(TSS_HMIGDATA, TSS_HCONTEXT *); TSS_RESULT obj_migdata_set_migrationblob(TSS_HMIGDATA, UINT32, UINT32, BYTE *); TSS_RESULT obj_migdata_get_migrationblob(TSS_HMIGDATA, UINT32, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_authoritydata(TSS_HMIGDATA, UINT32, UINT32, BYTE *); TSS_RESULT obj_migdata_get_authoritydata(TSS_HMIGDATA, UINT32, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_migauthdata(TSS_HMIGDATA, UINT32, UINT32, BYTE *); TSS_RESULT obj_migdata_get_migauthdata(TSS_HMIGDATA, UINT32, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_ticketdata(TSS_HMIGDATA, UINT32, UINT32, BYTE *); TSS_RESULT obj_migdata_get_ticketdata(TSS_HMIGDATA, UINT32, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_ticket_blob(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_ticket_blob(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_msa_list(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_msa_list(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_msa_pubkey(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_set_msa_digest(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_msa_digest(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_get_msa_list_blob(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_msa_hmac(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_msa_hmac(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_ma_pubkey(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_set_ma_digest(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_ma_digest(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_dest_pubkey(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_set_dest_digest(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_dest_digest(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_src_pubkey(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_set_src_digest(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_src_digest(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_cmk_auth(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_cmk_auth(TSS_HMIGDATA, TPM_CMK_AUTH *); TSS_RESULT obj_migdata_get_cmk_auth_blob(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_sig_data(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_sig_data(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_sig_value(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_sig_value(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_sig_ticket(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_sig_ticket(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_set_blob(TSS_HMIGDATA, UINT32, BYTE *); TSS_RESULT obj_migdata_get_blob(TSS_HMIGDATA, UINT32 *, BYTE **); TSS_RESULT obj_migdata_calc_pubkey_digest(UINT32, BYTE *, TPM_DIGEST *); TSS_RESULT obj_migdata_calc_msa_digest(struct tr_migdata_obj *); TSS_RESULT obj_migdata_calc_sig_data_digest(struct tr_migdata_obj *); #define MIGDATA_LIST_DECLARE struct obj_list migdata_list #define MIGDATA_LIST_DECLARE_EXTERN extern struct obj_list migdata_list #define MIGDATA_LIST_INIT() tspi_list_init(&migdata_list) #define MIGDATA_LIST_CONNECT(a,b) obj_connectContext_list(&migdata_list, a, b) #define MIGDATA_LIST_CLOSE(a) obj_list_close(&migdata_list, &migdata_free, a) #else #define obj_is_migdata(a) FALSE #define MIGDATA_LIST_DECLARE #define MIGDATA_LIST_DECLARE_EXTERN #define MIGDATA_LIST_INIT() #define MIGDATA_LIST_CONNECT(a,b) #define MIGDATA_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/rpc_tcstp_tcs.h0000664000175000017510000003041313663651711020212 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _RPC_TCSTP_TCS_H_ #define _RPC_TCSTP_TCS_H_ #include "rpc_tcstp.h" #define DECLARE_TCSTP_FUNC(x) \ TSS_RESULT tcs_wrap_##x(struct tcsd_thread_data *) /* Auth session, context and TPM caps support are always compiled in. TPM caps * are necessary so that the TCSD can know what type of TPM its talking to */ DECLARE_TCSTP_FUNC(OpenContext); DECLARE_TCSTP_FUNC(CloseContext); DECLARE_TCSTP_FUNC(OIAP); DECLARE_TCSTP_FUNC(OSAP); DECLARE_TCSTP_FUNC(GetCapability); DECLARE_TCSTP_FUNC(GetCapabilityOwner); DECLARE_TCSTP_FUNC(SetCapability); #ifdef TSS_BUILD_RANDOM DECLARE_TCSTP_FUNC(GetRandom); DECLARE_TCSTP_FUNC(StirRandom); #else #define tcs_wrap_GetRandom tcs_wrap_Error #define tcs_wrap_StirRandom tcs_wrap_Error #endif #ifdef TSS_BUILD_EK DECLARE_TCSTP_FUNC(CreateEndorsementKeyPair); DECLARE_TCSTP_FUNC(ReadPubek); DECLARE_TCSTP_FUNC(OwnerReadPubek); DECLARE_TCSTP_FUNC(DisablePubekRead); #ifdef TSS_BUILD_TSS12 DECLARE_TCSTP_FUNC(CreateRevocableEndorsementKeyPair); DECLARE_TCSTP_FUNC(RevokeEndorsementKeyPair); #else #define tcs_wrap_CreateRevocableEndorsementKeyPair tcs_wrap_Error #define tcs_wrap_RevokeEndorsementKeyPair tcs_wrap_Error #endif #else #define tcs_wrap_CreateEndorsementKeyPair tcs_wrap_Error #define tcs_wrap_ReadPubek tcs_wrap_Error #define tcs_wrap_OwnerReadPubek tcs_wrap_Error #define tcs_wrap_DisablePubekRead tcs_wrap_Error #define tcs_wrap_CreateRevocableEndorsementKeyPair tcs_wrap_Error #define tcs_wrap_RevokeEndorsementKeyPair tcs_wrap_Error #endif #ifdef TSS_BUILD_KEY DECLARE_TCSTP_FUNC(EvictKey); DECLARE_TCSTP_FUNC(GetPubkey); DECLARE_TCSTP_FUNC(TerminateHandle); DECLARE_TCSTP_FUNC(LoadKeyByBlob); DECLARE_TCSTP_FUNC(CreateWrapKey); #ifdef TSS_BUILD_TSS12 DECLARE_TCSTP_FUNC(KeyControlOwner); DECLARE_TCSTP_FUNC(OwnerReadInternalPub); #else #define tcs_wrap_KeyControlOwner tcs_wrap_Error #define tcs_wrap_OwnerReadInternalPub tcs_wrap_Error #endif #else #define tcs_wrap_EvictKey tcs_wrap_Error #define tcs_wrap_GetPubkey tcs_wrap_Error #define tcs_wrap_TerminateHandle tcs_wrap_Error #define tcs_wrap_LoadKeyByBlob tcs_wrap_Error #define tcs_wrap_CreateWrapKey tcs_wrap_Error #define tcs_wrap_KeyControlOwner tcs_wrap_Error #endif #ifdef TSS_BUILD_PCR_EXTEND DECLARE_TCSTP_FUNC(Extend); DECLARE_TCSTP_FUNC(PcrRead); DECLARE_TCSTP_FUNC(PcrReset); #else #define tcs_wrap_Extend tcs_wrap_Error #define tcs_wrap_PcrRead tcs_wrap_Error #define tcs_wrap_PcrReset tcs_wrap_Error #endif #ifdef TSS_BUILD_CAPS DECLARE_TCSTP_FUNC(TCSGetCapability); #else #define tcs_wrap_TCSGetCapability tcs_wrap_Error #endif #ifdef TSS_BUILD_OWN DECLARE_TCSTP_FUNC(TakeOwnership); DECLARE_TCSTP_FUNC(OwnerClear); #else #define tcs_wrap_TakeOwnership tcs_wrap_Error #define tcs_wrap_OwnerClear tcs_wrap_Error #endif #ifdef TSS_BUILD_PS DECLARE_TCSTP_FUNC(RegisterKey); DECLARE_TCSTP_FUNC(UnregisterKey); DECLARE_TCSTP_FUNC(GetRegisteredKeyBlob); DECLARE_TCSTP_FUNC(LoadKeyByUUID); DECLARE_TCSTP_FUNC(GetRegisteredKeyByPublicInfo); DECLARE_TCSTP_FUNC(EnumRegisteredKeys); DECLARE_TCSTP_FUNC(EnumRegisteredKeys2); #else #define tcs_wrap_RegisterKey tcs_wrap_Error #define tcs_wrap_UnregisterKey tcs_wrap_Error #define tcs_wrap_GetRegisteredKeyBlob tcs_wrap_Error #define tcs_wrap_LoadKeyByUUID tcs_wrap_Error #define tcs_wrap_GetRegisteredKeyByPublicInfo tcs_wrap_Error #define tcs_wrap_EnumRegisteredKeys tcs_wrap_Error #define tcs_wrap_EnumRegisteredKeys2 tcs_wrap_Error #endif #ifdef TSS_BUILD_SIGN DECLARE_TCSTP_FUNC(Sign); #else #define tcs_wrap_Sign tcs_wrap_Error #endif #ifdef TSS_BUILD_DIR DECLARE_TCSTP_FUNC(DirWriteAuth); DECLARE_TCSTP_FUNC(DirRead); #else #define tcs_wrap_DirWriteAuth tcs_wrap_Error #define tcs_wrap_DirRead tcs_wrap_Error #endif #ifdef TSS_BUILD_SEAL DECLARE_TCSTP_FUNC(Seal); DECLARE_TCSTP_FUNC(UnSeal); #else #define tcs_wrap_Seal tcs_wrap_Error #define tcs_wrap_UnSeal tcs_wrap_Error #endif #ifdef TSS_BUILD_SEALX DECLARE_TCSTP_FUNC(Sealx); #else #define tcs_wrap_Sealx tcs_wrap_Error #endif #ifdef TSS_BUILD_BIND DECLARE_TCSTP_FUNC(UnBind); #else #define tcs_wrap_UnBind tcs_wrap_Error #endif #ifdef TSS_BUILD_CHANGEAUTH DECLARE_TCSTP_FUNC(ChangeAuth); DECLARE_TCSTP_FUNC(ChangeAuthOwner); #else #define tcs_wrap_ChangeAuth tcs_wrap_Error #define tcs_wrap_ChangeAuthOwner tcs_wrap_Error #endif #ifdef TSS_BUILD_QUOTE DECLARE_TCSTP_FUNC(Quote); #else #define tcs_wrap_Quote tcs_wrap_Error #endif #ifdef TSS_BUILD_QUOTE2 DECLARE_TCSTP_FUNC(Quote2); #else #define tcs_wrap_Quote2 tcs_wrap_Error #endif #ifdef TSS_BUILD_PCR_EVENTS DECLARE_TCSTP_FUNC(LogPcrEvent); DECLARE_TCSTP_FUNC(GetPcrEvent); DECLARE_TCSTP_FUNC(GetPcrEventsByPcr); DECLARE_TCSTP_FUNC(GetPcrEventLog); #else #define tcs_wrap_LogPcrEvent tcs_wrap_Error #define tcs_wrap_GetPcrEvent tcs_wrap_Error #define tcs_wrap_GetPcrEventsByPcr tcs_wrap_Error #define tcs_wrap_GetPcrEventLog tcs_wrap_Error #endif #ifdef TSS_BUILD_SELFTEST DECLARE_TCSTP_FUNC(SelfTestFull); DECLARE_TCSTP_FUNC(CertifySelfTest); DECLARE_TCSTP_FUNC(GetTestResult); #else #define tcs_wrap_SelfTestFull tcs_wrap_Error #define tcs_wrap_CertifySelfTest tcs_wrap_Error #define tcs_wrap_GetTestResult tcs_wrap_Error #endif #ifdef TSS_BUILD_ADMIN DECLARE_TCSTP_FUNC(DisableOwnerClear); DECLARE_TCSTP_FUNC(ForceClear); DECLARE_TCSTP_FUNC(DisableForceClear); DECLARE_TCSTP_FUNC(PhysicalEnable); DECLARE_TCSTP_FUNC(PhysicalSetDeactivated); DECLARE_TCSTP_FUNC(SetOwnerInstall); DECLARE_TCSTP_FUNC(OwnerSetDisable); DECLARE_TCSTP_FUNC(PhysicalDisable); DECLARE_TCSTP_FUNC(PhysicalPresence); DECLARE_TCSTP_FUNC(SetTempDeactivated); #ifdef TSS_BUILD_TSS12 DECLARE_TCSTP_FUNC(SetTempDeactivated2); DECLARE_TCSTP_FUNC(ResetLockValue); #else #define tcs_wrap_SetTempDeactivated2 tcs_wrap_Error #define tcs_wrap_ResetLockValue tcs_wrap_Error #endif #else #define tcs_wrap_DisableOwnerClear tcs_wrap_Error #define tcs_wrap_ForceClear tcs_wrap_Error #define tcs_wrap_DisableForceClear tcs_wrap_Error #define tcs_wrap_PhysicalEnable tcs_wrap_Error #define tcs_wrap_PhysicalSetDeactivated tcs_wrap_Error #define tcs_wrap_SetOwnerInstall tcs_wrap_Error #define tcs_wrap_OwnerSetDisable tcs_wrap_Error #define tcs_wrap_PhysicalDisable tcs_wrap_Error #define tcs_wrap_PhysicalPresence tcs_wrap_Error #define tcs_wrap_SetTempDeactivated tcs_wrap_Error #define tcs_wrap_SetTempDeactivated2 tcs_wrap_Error #define tcs_wrap_ResetLockValue tcs_wrap_Error #endif #ifdef TSS_BUILD_CERTIFY DECLARE_TCSTP_FUNC(CertifyKey); #else #define tcs_wrap_CertifyKey tcs_wrap_Error #endif #ifdef TSS_BUILD_AIK DECLARE_TCSTP_FUNC(MakeIdentity); DECLARE_TCSTP_FUNC(ActivateIdentity); #ifdef TSS_BUILD_TSS12 DECLARE_TCSTP_FUNC(GetCredential); #else #define tcs_wrap_GetCredential tcs_wrap_Error #endif #else #define tcs_wrap_MakeIdentity tcs_wrap_Error #define tcs_wrap_ActivateIdentity tcs_wrap_Error #define tcs_wrap_GetCredential tcs_wrap_Error #endif #ifdef TSS_BUILD_MIGRATION DECLARE_TCSTP_FUNC(CreateMigrationBlob); DECLARE_TCSTP_FUNC(ConvertMigrationBlob); DECLARE_TCSTP_FUNC(AuthorizeMigrationKey); #else #define tcs_wrap_CreateMigrationBlob tcs_wrap_Error #define tcs_wrap_ConvertMigrationBlob tcs_wrap_Error #define tcs_wrap_AuthorizeMigrationKey tcs_wrap_Error #endif #ifdef TSS_BUILD_MAINT DECLARE_TCSTP_FUNC(KillMaintenanceFeature); DECLARE_TCSTP_FUNC(CreateMaintenanceArchive); DECLARE_TCSTP_FUNC(LoadMaintenanceArchive); DECLARE_TCSTP_FUNC(LoadManuMaintPub); DECLARE_TCSTP_FUNC(ReadManuMaintPub); #else #define tcs_wrap_KillMaintenanceFeature tcs_wrap_Error #define tcs_wrap_CreateMaintenanceArchive tcs_wrap_Error #define tcs_wrap_LoadMaintenanceArchive tcs_wrap_Error #define tcs_wrap_LoadManuMaintPub tcs_wrap_Error #define tcs_wrap_ReadManuMaintPub tcs_wrap_Error #endif #ifdef TSS_BUILD_DAA DECLARE_TCSTP_FUNC(DaaJoin); DECLARE_TCSTP_FUNC(DaaSign); #else #define tcs_wrap_DaaJoin tcs_wrap_Error #define tcs_wrap_DaaSign tcs_wrap_Error #endif #ifdef TSS_BUILD_NV DECLARE_TCSTP_FUNC(NV_DefineOrReleaseSpace); DECLARE_TCSTP_FUNC(NV_WriteValue); DECLARE_TCSTP_FUNC(NV_WriteValueAuth); DECLARE_TCSTP_FUNC(NV_ReadValue); DECLARE_TCSTP_FUNC(NV_ReadValueAuth); #else #define tcs_wrap_NV_DefineOrReleaseSpace tcs_wrap_Error #define tcs_wrap_NV_WriteValue tcs_wrap_Error #define tcs_wrap_NV_WriteValueAuth tcs_wrap_Error #define tcs_wrap_NV_ReadValue tcs_wrap_Error #define tcs_wrap_NV_ReadValueAuth tcs_wrap_Error #endif #ifdef TSS_BUILD_COUNTER DECLARE_TCSTP_FUNC(ReadCounter); DECLARE_TCSTP_FUNC(CreateCounter); DECLARE_TCSTP_FUNC(IncrementCounter); DECLARE_TCSTP_FUNC(ReleaseCounter); DECLARE_TCSTP_FUNC(ReleaseCounterOwner); #else #define tcs_wrap_ReadCounter tcs_wrap_Error #define tcs_wrap_CreateCounter tcs_wrap_Error #define tcs_wrap_IncrementCounter tcs_wrap_Error #define tcs_wrap_ReleaseCounter tcs_wrap_Error #define tcs_wrap_ReleaseCounterOwner tcs_wrap_Error #endif #ifdef TSS_BUILD_TICK DECLARE_TCSTP_FUNC(ReadCurrentTicks); DECLARE_TCSTP_FUNC(TickStampBlob); #else #define tcs_wrap_ReadCurrentTicks tcs_wrap_Error #define tcs_wrap_TickStampBlob tcs_wrap_Error #endif #ifdef TSS_BUILD_TRANSPORT DECLARE_TCSTP_FUNC(EstablishTransport); DECLARE_TCSTP_FUNC(ExecuteTransport); DECLARE_TCSTP_FUNC(ReleaseTransportSigned); #else #define tcs_wrap_EstablishTransport tcs_wrap_Error #define tcs_wrap_ExecuteTransport tcs_wrap_Error #define tcs_wrap_ReleaseTransportSigned tcs_wrap_Error #endif #ifdef TSS_BUILD_AUDIT DECLARE_TCSTP_FUNC(SetOrdinalAuditStatus); DECLARE_TCSTP_FUNC(GetAuditDigest); DECLARE_TCSTP_FUNC(GetAuditDigestSigned); #else #define tcs_wrap_SetOrdinalAuditStatus tcs_wrap_Error #define tcs_wrap_GetAuditDigest tcs_wrap_Error #define tcs_wrap_GetAuditDigestSigned tcs_wrap_Error #endif #ifdef TSS_BUILD_TSS12 DECLARE_TCSTP_FUNC(SetOperatorAuth); DECLARE_TCSTP_FUNC(FlushSpecific); #else #define tcs_wrap_SetOperatorAuth tcs_wrap_Error #define tcs_wrap_FlushSpecific tcs_wrap_Error #endif #ifdef TSS_BUILD_DELEGATION DECLARE_TCSTP_FUNC(Delegate_Manage); DECLARE_TCSTP_FUNC(Delegate_CreateKeyDelegation); DECLARE_TCSTP_FUNC(Delegate_CreateOwnerDelegation); DECLARE_TCSTP_FUNC(Delegate_LoadOwnerDelegation); DECLARE_TCSTP_FUNC(Delegate_ReadTable); DECLARE_TCSTP_FUNC(Delegate_UpdateVerificationCount); DECLARE_TCSTP_FUNC(Delegate_VerifyDelegation); DECLARE_TCSTP_FUNC(DSAP); #else #define tcs_wrap_Delegate_Manage tcs_wrap_Error #define tcs_wrap_Delegate_CreateKeyDelegation tcs_wrap_Error #define tcs_wrap_Delegate_CreateOwnerDelegation tcs_wrap_Error #define tcs_wrap_Delegate_LoadOwnerDelegation tcs_wrap_Error #define tcs_wrap_Delegate_ReadTable tcs_wrap_Error #define tcs_wrap_Delegate_UpdateVerificationCount tcs_wrap_Error #define tcs_wrap_Delegate_VerifyDelegation tcs_wrap_Error #define tcs_wrap_DSAP tcs_wrap_Error #endif #ifdef TSS_BUILD_CMK DECLARE_TCSTP_FUNC(CMK_SetRestrictions); DECLARE_TCSTP_FUNC(CMK_ApproveMA); DECLARE_TCSTP_FUNC(CMK_CreateKey); DECLARE_TCSTP_FUNC(CMK_CreateTicket); DECLARE_TCSTP_FUNC(CMK_CreateBlob); DECLARE_TCSTP_FUNC(CMK_ConvertMigration); #else #define tcs_wrap_CMK_SetRestrictions tcs_wrap_Error #define tcs_wrap_CMK_ApproveMA tcs_wrap_Error #define tcs_wrap_CMK_CreateKey tcs_wrap_Error #define tcs_wrap_CMK_CreateTicket tcs_wrap_Error #define tcs_wrap_CMK_CreateBlob tcs_wrap_Error #define tcs_wrap_CMK_ConvertMigration tcs_wrap_Error #endif DECLARE_TCSTP_FUNC(dispatchCommand); void LoadBlob_Auth_Special(UINT64 *, BYTE *, TPM_AUTH *); void UnloadBlob_Auth_Special(UINT64 *, BYTE *, TPM_AUTH *); void LoadBlob_KM_KEYINFO(UINT64 *, BYTE *, TSS_KM_KEYINFO *); void LoadBlob_KM_KEYINFO2(UINT64 *, BYTE *, TSS_KM_KEYINFO2 *); void UnloadBlob_KM_KEYINFO(UINT64 *, BYTE *, TSS_KM_KEYINFO *); void UnloadBlob_KM_KEYINFO2(UINT64 *, BYTE *, TSS_KM_KEYINFO2 *); void LoadBlob_LOADKEY_INFO(UINT64 *, BYTE *, TCS_LOADKEY_INFO *); void UnloadBlob_LOADKEY_INFO(UINT64 *, BYTE *, TCS_LOADKEY_INFO *); void LoadBlob_PCR_EVENT(UINT64 *, BYTE *, TSS_PCR_EVENT *); TSS_RESULT UnloadBlob_PCR_EVENT(UINT64 *, BYTE *, TSS_PCR_EVENT *); int setData(TCSD_PACKET_TYPE, unsigned int, void *, int, struct tcsd_comm_data *); UINT32 getData(TCSD_PACKET_TYPE, unsigned int, void *, int, struct tcsd_comm_data *); void initData(struct tcsd_comm_data *, int); int recv_from_socket(int, void *, int); int send_to_socket(int, void *, int); TSS_RESULT getTCSDPacket(struct tcsd_thread_data *); MUTEX_DECLARE_EXTERN(tcsp_lock); #endif trousers-0.3.15/src/include/obj_pcrs.h0000664000175000017510000000417713663651711017151 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_PCRS_H_ #define _OBJ_PCRS_H_ #ifdef TSS_BUILD_PCRS_LIST /* structures */ struct tr_pcrs_obj { UINT32 type; union { TPM_PCR_INFO info11; TPM_PCR_INFO_SHORT infoshort; TPM_PCR_INFO_LONG infolong; } info; TPM_PCRVALUE *pcrs; }; /* obj_pcrs.c */ void pcrs_free(void *data); TSS_BOOL obj_is_pcrs(TSS_HOBJECT); TSS_RESULT obj_pcrs_get_tsp_context(TSS_HPCRS, TSS_HCONTEXT *); TSS_RESULT obj_pcrs_add(TSS_HCONTEXT, UINT32, TSS_HOBJECT *); TSS_RESULT obj_pcrs_remove(TSS_HOBJECT, TSS_HCONTEXT); TSS_RESULT obj_pcrs_get_type(TSS_HPCRS, UINT32 *); TSS_RESULT obj_pcrs_select_index(TSS_HPCRS, UINT32); TSS_RESULT obj_pcrs_select_index_ex(TSS_HPCRS, UINT32, UINT32); TSS_RESULT obj_pcrs_get_value(TSS_HPCRS, UINT32, UINT32 *, BYTE **); TSS_RESULT obj_pcrs_set_value(TSS_HPCRS, UINT32, UINT32, BYTE *); TSS_RESULT obj_pcrs_set_values(TSS_HPCRS hPcrs, TCPA_PCR_COMPOSITE *); TSS_RESULT obj_pcrs_get_selection(TSS_HPCRS, UINT32 *, BYTE *); TSS_RESULT obj_pcrs_get_digest_at_release(TSS_HPCRS, UINT32 *, BYTE **); TSS_RESULT obj_pcrs_set_digest_at_release(TSS_HPCRS, TPM_COMPOSITE_HASH); TSS_RESULT obj_pcrs_create_info_type(TSS_HPCRS, UINT32 *, UINT32 *, BYTE **); TSS_RESULT obj_pcrs_create_info(TSS_HPCRS, UINT32 *, BYTE **); TSS_RESULT obj_pcrs_create_info_long(TSS_HPCRS, UINT32 *, BYTE **); TSS_RESULT obj_pcrs_create_info_short(TSS_HPCRS, UINT32 *, BYTE **); TSS_RESULT obj_pcrs_get_locality(TSS_HPCRS, UINT32 *); TSS_RESULT obj_pcrs_set_locality(TSS_HPCRS, UINT32); #define PCRS_LIST_DECLARE struct obj_list pcrs_list #define PCRS_LIST_DECLARE_EXTERN extern struct obj_list pcrs_list #define PCRS_LIST_INIT() tspi_list_init(&pcrs_list) #define PCRS_LIST_CONNECT(a,b) obj_connectContext_list(&pcrs_list, a, b) #define PCRS_LIST_CLOSE(a) obj_list_close(&pcrs_list, &pcrs_free, a) #else #define obj_is_pcrs(a) FALSE #define PCRS_LIST_DECLARE #define PCRS_LIST_DECLARE_EXTERN #define PCRS_LIST_INIT() #define PCRS_LIST_CONNECT(a,b) #define PCRS_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/obj_daa.h0000664000175000017510000000251513663651711016721 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_DAA_H_ #define _OBJ_DAA_H_ #ifdef TSS_BUILD_DAA /* structures */ struct tr_daa_obj { UINT32 session_handle; // set by [join|sign] stage 0. TPM_HANDLE tpm_handle; }; /* obj_daa.c */ void daa_free(void *data); TSS_RESULT obj_daa_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject); TSS_RESULT obj_daa_remove(TSS_HOBJECT, TSS_HCONTEXT); TSS_BOOL obj_is_daa(TSS_HOBJECT); TSS_RESULT obj_daa_get_tsp_context(TSS_HDAA, TSS_HCONTEXT *); TSS_RESULT obj_daa_get_handle_tpm(TSS_HDAA, TPM_HANDLE *); TSS_RESULT obj_daa_set_handle_tpm(TSS_HDAA, TPM_HANDLE); TSS_RESULT obj_daa_get_session_handle(TSS_HDAA, UINT32 *); TSS_RESULT obj_daa_set_session_handle(TSS_HDAA, UINT32); #define DAA_LIST_DECLARE struct obj_list daa_list #define DAA_LIST_DECLARE_EXTERN extern struct obj_list daa_list #define DAA_LIST_INIT() tspi_list_init(&daa_list) #define DAA_LIST_CONNECT(a,b) obj_connectContext_list(&daa_list, a, b) #define DAA_LIST_CLOSE(a) obj_list_close(&daa_list, &daa_free, a) #else #define obj_is_daa(a) FALSE #define DAA_LIST_DECLARE #define DAA_LIST_DECLARE_EXTERN #define DAA_LIST_INIT() #define DAA_LIST_CONNECT(a,b) #define DAA_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/linux/0000775000175000017510000000000013663651711016325 5ustar deboradeboratrousers-0.3.15/src/include/linux/tpm.h0000664000175000017510000000203713663651711017300 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004 * */ /* * include/linux/tpm.h * * Device driver for TCPA TPM (trusted platform module). */ #ifndef _TPM_H_ #define _TPM_H_ #if (defined (__linux) || defined (linux)) #include #elif (defined (__OpenBSD__) || defined (__FreeBSD__)) #include #endif /* ioctl commands */ #define TPMIOC_CANCEL _IO('T', 0x00) #define TPMIOC_TRANSMIT _IO('T', 0x01) #if defined(__KERNEL__) extern ssize_t tpm_transmit(const char *buf, size_t bufsiz); extern ssize_t tpm_extend(int index, u8 *digest); extern ssize_t tpm_pcrread(int index, u8 *hash); extern ssize_t tpm_dirread(int index, u8 *hash); extern ssize_t tpm_cap_version(int *maj, int *min, int *ver, int *rev); extern ssize_t tpm_cap_pcr(int *pcrs); extern ssize_t tpm_cap_dir(int *dirs); extern ssize_t tpm_cap_manufacturer(int *manufacturer); extern ssize_t tpm_cap_slot(int *slots); #endif /* __KERNEL__ */ #endif trousers-0.3.15/src/include/spi_utils.h0000664000175000017510000010772713736475370017376 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2007 * */ #ifndef _SPI_UTILS_H_ #define _SPI_UTILS_H_ #include "threads.h" #include // for endian routines #include "trousers_types.h" #include "trousers/trousers.h" struct key_mem_cache { TCS_KEY_HANDLE tcs_handle; TSS_HKEY tsp_handle; UINT16 flags; UINT32 time_stamp; TSS_UUID uuid; TSS_UUID p_uuid; TSS_KEY *blob; struct key_mem_cache *parent; struct key_mem_cache *next; }; extern struct key_mem_cache *key_mem_cache_head; MUTEX_DECLARE_EXTERN(mem_cache_lock); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #define BOOL(x) ((x) == 0) ? FALSE : TRUE #define INVBOOL(x) ((x) == 0) ? TRUE : FALSE #define TSS_PSFILE_INCREMENT_NUM_KEYS 1 #define TSS_PSFILE_DECREMENT_NUM_KEYS 0 #ifdef __GNUC__ #define __no_optimize __attribute__((optimize("O0"))) #else #define __no_optimize #endif void *calloc_tspi(TSS_HCONTEXT, UINT32); TSS_RESULT free_tspi(TSS_HCONTEXT, void *); TSS_RESULT __tspi_add_mem_entry(TSS_HCONTEXT, void *); void * __tspi_memset(void *, int, size_t); /* secrets.c */ TSS_RESULT policy_UsesAuth(TSS_HPOLICY, TSS_BOOL *); TSS_RESULT secret_PerformAuth_OIAP(TSS_HOBJECT, UINT32, TSS_HPOLICY, TSS_BOOL, TCPA_DIGEST *, TPM_AUTH *); #if 0 TSS_RESULT secret_PerformXOR_OSAP(TSS_HPOLICY, TSS_HPOLICY, TSS_HPOLICY, TSS_HOBJECT, UINT16, UINT32, TCPA_ENCAUTH *, TCPA_ENCAUTH *, BYTE *, TPM_AUTH *, TCPA_NONCE *); TSS_RESULT secret_PerformAuth_OSAP(TSS_HOBJECT, UINT32, TSS_HPOLICY, TSS_HPOLICY, TSS_HPOLICY, BYTE *, TPM_AUTH *, BYTE *, TCPA_NONCE *); TSS_RESULT secret_ValidateAuth_OSAP(TSS_HOBJECT, UINT32, TSS_HPOLICY, TSS_HPOLICY, TSS_HPOLICY, BYTE *, TPM_AUTH *, BYTE *, TCPA_NONCE *); #endif TSS_RESULT secret_TakeOwnership(TSS_HKEY, TSS_HTPM, TSS_HKEY, TPM_AUTH *, UINT32 *, BYTE *, UINT32 *, BYTE *); TSS_RESULT changeauth_owner(TSS_HCONTEXT, TSS_HOBJECT, TSS_HOBJECT, TSS_HPOLICY); TSS_RESULT changeauth_srk(TSS_HCONTEXT, TSS_HOBJECT, TSS_HOBJECT, TSS_HPOLICY); TSS_RESULT changeauth_key(TSS_HCONTEXT, TSS_HOBJECT, TSS_HOBJECT, TSS_HPOLICY); TSS_RESULT changeauth_encdata(TSS_HCONTEXT, TSS_HOBJECT, TSS_HOBJECT, TSS_HPOLICY); TSS_RESULT sealx_mask_cb(PVOID, TSS_HKEY, TSS_HENCDATA, TSS_ALGORITHM_ID, UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, BYTE *); TSS_RESULT __tspi_free_resource(TSS_HCONTEXT, UINT32, UINT32); TSS_RESULT owner_get_pubek(TSS_HCONTEXT, TSS_HTPM, TSS_HKEY *); #define next( x ) x = x->next /* spi_utils.c */ UINT16 get_num_pcrs(TSS_HCONTEXT); void free_key_refs(TSS_KEY *); #define UI_MAX_SECRET_STRING_LENGTH 256 #define UI_MAX_POPUP_STRING_LENGTH 256 #ifdef TSS_NO_GUI #define DisplayPINWindow(a,b,c) \ do { \ *(b) = 0; \ } while (0) #define DisplayNewPINWindow(a,b,c) \ do { \ *(b) = 0; \ } while (0) #else TSS_RESULT DisplayPINWindow(BYTE *, UINT32 *, BYTE *); TSS_RESULT DisplayNewPINWindow(BYTE *, UINT32 *, BYTE *); #endif TSS_RESULT merge_key_hierarchies(TSS_HCONTEXT, UINT32, TSS_KM_KEYINFO *, UINT32, TSS_KM_KEYINFO *, UINT32 *, TSS_KM_KEYINFO **); TSS_RESULT merge_key_hierarchies2(TSS_HCONTEXT, UINT32, TSS_KM_KEYINFO2 *, UINT32, TSS_KM_KEYINFO2 *, UINT32 *, TSS_KM_KEYINFO2 **); int pin_mem(void *, size_t); int unpin_mem(void *, size_t); #define TSS_MAX_SYM_BLOCK_SIZE 16 TSS_RESULT internal_GetCap(TSS_HCONTEXT, TSS_FLAG, UINT32, UINT32 *, BYTE **); /* For an unconnected context that wants to do PCR operations, assume that * the TPM has TSS_DEFAULT_NUM_PCRS pcrs */ #define TSS_DEFAULT_NUM_PCRS 16 #define TSS_LOCAL_RANDOM_DEVICE "/dev/urandom" #define TSS_LOCALHOST_STRING "localhost" TSS_RESULT get_local_random(TSS_HCONTEXT, TSS_BOOL, UINT32, BYTE **); #define AUTH_RETRY_NANOSECS 500000000 #define AUTH_RETRY_COUNT 5 #define TPM_AUTH_RQU_SIZE (sizeof(TPM_AUTHHANDLE) + sizeof(TPM_NONCE) \ + sizeof(TPM_BOOL) + sizeof(TPM_AUTHDATA)) #define TPM_AUTH_RSP_SIZE (sizeof(TPM_NONCE) + sizeof(TPM_BOOL) + sizeof(TPM_AUTHDATA)) #define endian32(x) htonl(x) #define endian16(x) htons(x) extern TSS_VERSION VERSION_1_1; TSS_RESULT __tspi_rsa_encrypt(TSS_HKEY, UINT32, BYTE*, UINT32*, BYTE*); TSS_RESULT __tspi_rsa_verify(TSS_HKEY, UINT32, UINT32, BYTE*, UINT32, BYTE*); TSS_RESULT Init_AuthNonce(TCS_CONTEXT_HANDLE, TSS_BOOL, TPM_AUTH *); TSS_BOOL validateReturnAuth(BYTE *, BYTE *, TPM_AUTH *); void HMAC_Auth(BYTE *, BYTE *, TPM_AUTH *); TSS_RESULT OSAP_Calc(TCS_CONTEXT_HANDLE, UINT16, UINT32, BYTE *, BYTE *, BYTE *, TCPA_ENCAUTH *, TCPA_ENCAUTH *, BYTE *, TPM_AUTH *); void UINT64ToArray(UINT64, BYTE *); void UINT32ToArray(UINT32, BYTE *); void UINT16ToArray(UINT16, BYTE *); UINT16 Decode_UINT16(BYTE *); UINT32 Decode_UINT32(BYTE *); UINT64 Decode_UINT64(BYTE *); TSS_RESULT popup_GetSecret(UINT32, UINT32, BYTE *, void *); TSS_RESULT get_tpm_flags(TSS_HCONTEXT, TSS_HTPM, UINT32 *, UINT32 *); TSS_RESULT pcrs_calc_composite(TCPA_PCR_SELECTION *, TCPA_PCRVALUE *, TCPA_DIGEST *); struct tr_pcrs_obj; TSS_RESULT pcrs_sanity_check_selection(TCS_CONTEXT_HANDLE, struct tr_pcrs_obj *, TPM_PCR_SELECTION *); void LoadBlob_AUTH(UINT64 *, BYTE *, TPM_AUTH *); void UnloadBlob_AUTH(UINT64 *, BYTE *, TPM_AUTH *); void LoadBlob_LOADKEY_INFO(UINT64 *, BYTE *, TCS_LOADKEY_INFO *); void UnloadBlob_LOADKEY_INFO(UINT64 *, BYTE *, TCS_LOADKEY_INFO *); void LoadBlob_TSS_KEY(UINT64 *, BYTE *, TSS_KEY *); TSS_RESULT UnloadBlob_TSS_KEY(UINT64 *, BYTE *, TSS_KEY *); TSS_RESULT Hash_TSS_KEY(Trspi_HashCtx *, TSS_KEY *); void LoadBlob_TSS_PRIVKEY_DIGEST(UINT64 *, BYTE *, TSS_KEY *); TSS_RESULT Hash_TSS_PRIVKEY_DIGEST(Trspi_HashCtx *, TSS_KEY *); TSS_RESULT TSP_SetCapability(TSS_HCONTEXT, TSS_HTPM, TSS_HPOLICY, TPM_CAPABILITY_AREA, UINT32, TSS_BOOL); TSS_RESULT RPC_OpenContext(TSS_HCONTEXT, BYTE *, int); TSS_RESULT RPC_FreeMemory(TSS_HCONTEXT, BYTE *); TSS_RESULT RPC_GetRegisteredKeyByPublicInfo(TSS_HCONTEXT, TCPA_ALGORITHM_ID, UINT32, BYTE *, UINT32 *, BYTE **); TSS_RESULT RPC_CloseContext(TSS_HCONTEXT); TSS_RESULT RPC_GetCapability(TSS_HCONTEXT, TCPA_CAPABILITY_AREA, UINT32, BYTE *, UINT32 *, BYTE **); TSS_RESULT RPC_GetTPMCapability(TSS_HCONTEXT, TCPA_CAPABILITY_AREA, UINT32, BYTE *, UINT32 *, BYTE **); TSS_RESULT Transport_GetTPMCapability(TSS_HCONTEXT, TCPA_CAPABILITY_AREA, UINT32, BYTE *, UINT32 *, BYTE **); TSS_RESULT RPC_SetCapability(TSS_HCONTEXT, TCPA_CAPABILITY_AREA, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT Transport_SetCapability(TSS_HCONTEXT, TCPA_CAPABILITY_AREA, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT RPC_LoadKeyByBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TCS_KEY_HANDLE *, TCS_KEY_HANDLE *); TSS_RESULT Transport_LoadKeyByBlob(TSS_HCONTEXT, TSS_HKEY, UINT32, BYTE *, TPM_AUTH *, TCS_KEY_HANDLE *, TPM_KEY_HANDLE *); TSS_RESULT RPC_LoadKeyByUUID(TSS_HCONTEXT, TSS_UUID, TCS_LOADKEY_INFO *, TCS_KEY_HANDLE *); TSS_RESULT RPC_GetRegisteredKey(TSS_HCONTEXT, TSS_UUID, TSS_KM_KEYINFO **); TSS_RESULT RPC_GetRegisteredKeyBlob(TSS_HCONTEXT, TSS_UUID, UINT32 *, BYTE **); TSS_RESULT RPC_RegisterKey(TSS_HCONTEXT, TSS_UUID, TSS_UUID, UINT32, BYTE *, UINT32, BYTE *); TSS_RESULT RPC_UnregisterKey(TSS_HCONTEXT, TSS_UUID); TSS_RESULT RPC_EnumRegisteredKeys(TSS_HCONTEXT, TSS_UUID *, UINT32 *, TSS_KM_KEYINFO **); TSS_RESULT RPC_EnumRegisteredKeys2(TSS_HCONTEXT, TSS_UUID *, UINT32 *, TSS_KM_KEYINFO2 **); TSS_RESULT RPC_ChangeAuth(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_PROTOCOL_ID, TCPA_ENCAUTH *, TCPA_ENTITY_TYPE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_ChangeAuth(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_PROTOCOL_ID, TCPA_ENCAUTH *, TCPA_ENTITY_TYPE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_ChangeAuthOwner(TSS_HCONTEXT, TCPA_PROTOCOL_ID, TCPA_ENCAUTH *, TCPA_ENTITY_TYPE, TPM_AUTH *); TSS_RESULT Transport_ChangeAuthOwner(TSS_HCONTEXT, TCPA_PROTOCOL_ID, TCPA_ENCAUTH *, TCPA_ENTITY_TYPE, TPM_AUTH *); TSS_RESULT RPC_TerminateHandle(TSS_HCONTEXT, TCS_AUTHHANDLE); TSS_RESULT Transport_TerminateHandle(TSS_HCONTEXT, TCS_AUTHHANDLE); TSS_RESULT RPC_GetRandom(TSS_HCONTEXT, UINT32, BYTE **); TSS_RESULT Transport_GetRandom(TSS_HCONTEXT, UINT32, BYTE **); TSS_RESULT RPC_ChangeAuthAsymStart(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **, TCS_KEY_HANDLE *); TSS_RESULT RPC_ChangeAuthAsymFinish(TSS_HCONTEXT, TCS_KEY_HANDLE, TCS_KEY_HANDLE, TCPA_ENTITY_TYPE, TCPA_HMAC, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, TCPA_SALT_NONCE *, TCPA_DIGEST *); TSS_RESULT RPC_GetPubKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_GetPubKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_CreateWrapKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT Transport_CreateWrapKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT RPC_CertifyKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TCS_KEY_HANDLE, TPM_NONCE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_CertifyKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TCS_KEY_HANDLE, TPM_NONCE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_CreateMigrationBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_MIGRATE_SCHEME, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_CreateMigrationBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_MIGRATE_SCHEME, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_ConvertMigrationBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_ConvertMigrationBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_PcrRead(TSS_HCONTEXT, TCPA_PCRINDEX, TCPA_PCRVALUE *); TSS_RESULT Transport_PcrRead(TSS_HCONTEXT, TCPA_PCRINDEX, TCPA_PCRVALUE *); TSS_RESULT RPC_PcrReset(TSS_HCONTEXT, UINT32, BYTE *); TSS_RESULT Transport_PcrReset(TSS_HCONTEXT, UINT32, BYTE *); TSS_RESULT RPC_OSAP(TSS_HCONTEXT, TCPA_ENTITY_TYPE, UINT32, TPM_NONCE *, TCS_AUTHHANDLE *, TCPA_NONCE *, TCPA_NONCE *); TSS_RESULT Transport_OSAP(TSS_HCONTEXT, TCPA_ENTITY_TYPE, UINT32, TPM_NONCE *, TCS_AUTHHANDLE *, TCPA_NONCE *, TCPA_NONCE *); TSS_RESULT RPC_GetCapabilityOwner(TSS_HCONTEXT, TPM_AUTH *, TCPA_VERSION *, UINT32 *, UINT32 *); TSS_RESULT Transport_GetCapabilityOwner(TSS_HCONTEXT, TPM_AUTH *, TCPA_VERSION *, UINT32 *, UINT32 *); TSS_RESULT RPC_OIAP(TSS_HCONTEXT, TCS_AUTHHANDLE *, TCPA_NONCE *); TSS_RESULT Transport_OIAP(TSS_HCONTEXT, TCS_AUTHHANDLE *, TCPA_NONCE *); TSS_RESULT RPC_Seal(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Seal(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Sealx(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Sealx(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Unseal(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Unseal(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_UnBind(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_UnBind(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Sign(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Sign(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_CreateEndorsementKeyPair(TSS_HCONTEXT, TCPA_NONCE, UINT32, BYTE *, UINT32 *, BYTE **, TCPA_DIGEST *); TSS_RESULT RPC_ReadPubek(TSS_HCONTEXT, TCPA_NONCE, UINT32 *, BYTE **, TCPA_DIGEST *); TSS_RESULT RPC_OwnerReadPubek(TSS_HCONTEXT, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_TakeOwnership(TSS_HCONTEXT, UINT16, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_CreateRevocableEndorsementKeyPair(TSS_HCONTEXT, TPM_NONCE, UINT32, BYTE *, TSS_BOOL, TPM_DIGEST *, UINT32 *, BYTE **, TPM_DIGEST *); TSS_RESULT RPC_RevokeEndorsementKeyPair(TSS_HCONTEXT, TPM_DIGEST *); TSS_RESULT RPC_MakeIdentity(TSS_HCONTEXT, TCPA_ENCAUTH, TCPA_CHOSENID_HASH, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_MakeIdentity2(TSS_HCONTEXT, TCPA_ENCAUTH, TCPA_CHOSENID_HASH, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_ActivateTPMIdentity(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_ActivateTPMIdentity(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_OwnerClear(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT Transport_OwnerClear(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT RPC_ForceClear(TSS_HCONTEXT); TSS_RESULT Transport_ForceClear(TSS_HCONTEXT); TSS_RESULT RPC_DisableOwnerClear(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT Transport_DisableOwnerClear(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT RPC_DisableForceClear(TSS_HCONTEXT); TSS_RESULT Transport_DisableForceClear(TSS_HCONTEXT); TSS_RESULT RPC_PhysicalDisable(TSS_HCONTEXT); TSS_RESULT Transport_PhysicalDisable(TSS_HCONTEXT); TSS_RESULT RPC_PhysicalEnable(TSS_HCONTEXT); TSS_RESULT Transport_PhysicalEnable(TSS_HCONTEXT); TSS_RESULT RPC_PhysicalSetDeactivated(TSS_HCONTEXT, TSS_BOOL); TSS_RESULT Transport_PhysicalSetDeactivated(TSS_HCONTEXT, TSS_BOOL); TSS_RESULT RPC_PhysicalPresence(TSS_HCONTEXT, TCPA_PHYSICAL_PRESENCE); TSS_RESULT Transport_PhysicalPresence(TSS_HCONTEXT, TCPA_PHYSICAL_PRESENCE); TSS_RESULT RPC_SetTempDeactivated(TSS_HCONTEXT); TSS_RESULT Transport_SetTempDeactivated(TSS_HCONTEXT); TSS_RESULT RPC_SetTempDeactivated2(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT Transport_SetTempDeactivated2(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT RPC_OwnerSetDisable(TSS_HCONTEXT, TSS_BOOL, TPM_AUTH *); TSS_RESULT Transport_OwnerSetDisable(TSS_HCONTEXT, TSS_BOOL, TPM_AUTH *); TSS_RESULT RPC_ResetLockValue(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT Transport_ResetLockValue(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT RPC_SetOwnerInstall(TSS_HCONTEXT, TSS_BOOL); TSS_RESULT Transport_SetOwnerInstall(TSS_HCONTEXT, TSS_BOOL); TSS_RESULT RPC_DisablePubekRead(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT Transport_DisablePubekRead(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT RPC_SelfTestFull(TSS_HCONTEXT); TSS_RESULT Transport_SelfTestFull(TSS_HCONTEXT); TSS_RESULT RPC_CertifySelfTest(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_CertifySelfTest(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_GetTestResult(TSS_HCONTEXT, UINT32 *, BYTE **); TSS_RESULT Transport_GetTestResult(TSS_HCONTEXT, UINT32 *, BYTE **); TSS_RESULT RPC_StirRandom(TSS_HCONTEXT, UINT32, BYTE *); TSS_RESULT Transport_StirRandom(TSS_HCONTEXT, UINT32, BYTE *); TSS_RESULT RPC_AuthorizeMigrationKey(TSS_HCONTEXT, TCPA_MIGRATE_SCHEME, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_AuthorizeMigrationKey(TSS_HCONTEXT, TCPA_MIGRATE_SCHEME, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_GetPcrEvent(TSS_HCONTEXT, UINT32, UINT32 *, TSS_PCR_EVENT **); TSS_RESULT RPC_GetPcrEventsByPcr(TSS_HCONTEXT, UINT32, UINT32, UINT32 *, TSS_PCR_EVENT **); TSS_RESULT RPC_GetPcrEventLog(TSS_HCONTEXT, UINT32 *, TSS_PCR_EVENT **); TSS_RESULT RPC_Quote(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_Quote(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_Quote2(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE *, UINT32, BYTE *, TSS_BOOL, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_Quote2(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE *, UINT32, BYTE *, TSS_BOOL, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_Extend(TSS_HCONTEXT, TCPA_PCRINDEX, TCPA_DIGEST, TCPA_PCRVALUE *); TSS_RESULT Transport_Extend(TSS_HCONTEXT, TCPA_PCRINDEX, TCPA_DIGEST, TCPA_PCRVALUE *); TSS_RESULT RPC_DirWriteAuth(TSS_HCONTEXT, TCPA_DIRINDEX, TCPA_DIRVALUE *, TPM_AUTH *); TSS_RESULT Transport_DirWriteAuth(TSS_HCONTEXT, TCPA_DIRINDEX, TCPA_DIRVALUE *, TPM_AUTH *); TSS_RESULT RPC_DirRead(TSS_HCONTEXT, TCPA_DIRINDEX, TCPA_DIRVALUE *); TSS_RESULT Transport_DirRead(TSS_HCONTEXT, TCPA_DIRINDEX, TCPA_DIRVALUE *); TSS_RESULT RPC_LogPcrEvent(TSS_HCONTEXT, TSS_PCR_EVENT, UINT32 *); TSS_RESULT RPC_EvictKey(TSS_HCONTEXT, TCS_KEY_HANDLE); TSS_RESULT Transport_EvictKey(TSS_HCONTEXT, TCS_KEY_HANDLE); TSS_RESULT RPC_CreateMaintenanceArchive(TSS_HCONTEXT, TSS_BOOL, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_CreateMaintenanceArchive(TSS_HCONTEXT, TSS_BOOL, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_KillMaintenanceFeature(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT Transport_KillMaintenanceFeature(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT RPC_LoadMaintenanceArchive(TSS_HCONTEXT, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_LoadMaintenanceArchive(TSS_HCONTEXT, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_LoadManuMaintPub(TSS_HCONTEXT, TCPA_NONCE, UINT32, BYTE *, TCPA_DIGEST *); TSS_RESULT Transport_LoadManuMaintPub(TSS_HCONTEXT, TCPA_NONCE, UINT32, BYTE *, TCPA_DIGEST *); TSS_RESULT RPC_ReadManuMaintPub(TSS_HCONTEXT, TCPA_NONCE, TCPA_DIGEST *); TSS_RESULT Transport_ReadManuMaintPub(TSS_HCONTEXT, TCPA_NONCE, TCPA_DIGEST *); TSS_RESULT RPC_DaaJoin(TSS_HCONTEXT, TPM_HANDLE, BYTE, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_DaaSign(TSS_HCONTEXT, TPM_HANDLE, BYTE, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_ReadCounter(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_COUNTER_VALUE *); TSS_RESULT Transport_ReadCounter(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_COUNTER_VALUE *); TSS_RESULT RPC_CreateCounter(TSS_HCONTEXT, UINT32, BYTE *, TPM_ENCAUTH, TPM_AUTH *, TSS_COUNTER_ID *, TPM_COUNTER_VALUE *); TSS_RESULT RPC_IncrementCounter(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_AUTH *, TPM_COUNTER_VALUE *); TSS_RESULT RPC_ReleaseCounter(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_AUTH *); TSS_RESULT RPC_ReleaseCounterOwner(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_AUTH *); TSS_RESULT RPC_ReadCurrentTicks(TSS_HCONTEXT, UINT32 *, BYTE **); TSS_RESULT Transport_ReadCurrentTicks(TSS_HCONTEXT, UINT32 *, BYTE **); TSS_RESULT RPC_TickStampBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_NONCE *, TPM_DIGEST *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_TickStampBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_NONCE *, TPM_DIGEST *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_EstablishTransport(TSS_HCONTEXT, UINT32, TCS_KEY_HANDLE, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, TPM_MODIFIER_INDICATOR *, TCS_HANDLE *, UINT32 *, BYTE **, TPM_NONCE *); TSS_RESULT RPC_ExecuteTransport(TSS_HCONTEXT, TPM_COMMAND_CODE, UINT32, BYTE *, UINT32 *, TCS_HANDLE **, TPM_AUTH *, TPM_AUTH *, TPM_AUTH *, UINT64 *, TPM_MODIFIER_INDICATOR *, TPM_RESULT *, UINT32 *, BYTE **); TSS_RESULT RPC_ReleaseTransportSigned(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_NONCE *, TPM_AUTH *, TPM_AUTH *, TPM_MODIFIER_INDICATOR *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_NV_DefineOrReleaseSpace(TSS_HCONTEXT, UINT32, BYTE *, TCPA_ENCAUTH, TPM_AUTH *); TSS_RESULT Transport_NV_DefineOrReleaseSpace(TSS_HCONTEXT, UINT32, BYTE *, TCPA_ENCAUTH, TPM_AUTH *); TSS_RESULT RPC_NV_WriteValue(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT Transport_NV_WriteValue(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT RPC_NV_WriteValueAuth(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT Transport_NV_WriteValueAuth(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT RPC_NV_ReadValue(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32 *, TPM_AUTH *, BYTE **); TSS_RESULT Transport_NV_ReadValue(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32 *, TPM_AUTH *, BYTE **); TSS_RESULT RPC_NV_ReadValueAuth(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32 *, TPM_AUTH *, BYTE **); TSS_RESULT Transport_NV_ReadValueAuth(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32 *, TPM_AUTH *, BYTE **); TSS_RESULT RPC_SetOrdinalAuditStatus(TSS_HCONTEXT, TPM_AUTH *, UINT32, TSS_BOOL); TSS_RESULT Transport_SetOrdinalAuditStatus(TSS_HCONTEXT, TPM_AUTH *, UINT32, TSS_BOOL); TSS_RESULT RPC_GetAuditDigest(TSS_HCONTEXT, UINT32, TPM_DIGEST *, UINT32 *, BYTE **, TSS_BOOL *, UINT32 *, UINT32 **); TSS_RESULT Transport_GetAuditDigest(TSS_HCONTEXT, UINT32, TPM_DIGEST *, UINT32 *, BYTE **, TSS_BOOL *, UINT32 *, UINT32 **); TSS_RESULT RPC_GetAuditDigestSigned(TSS_HCONTEXT, TCS_KEY_HANDLE, TSS_BOOL, TPM_NONCE *, TPM_AUTH *, UINT32 *, BYTE **, TPM_DIGEST *, TPM_DIGEST *, UINT32 *, BYTE **); TSS_RESULT Transport_GetAuditDigestSigned(TSS_HCONTEXT, TCS_KEY_HANDLE, TSS_BOOL, TPM_NONCE *, TPM_AUTH *, UINT32 *, BYTE **, TPM_DIGEST *, TPM_DIGEST *, UINT32 *, BYTE **); TSS_RESULT RPC_SetOperatorAuth(TSS_HCONTEXT, TCPA_SECRET *); TSS_RESULT Transport_SetOperatorAuth(TSS_HCONTEXT, TCPA_SECRET *); TSS_RESULT RPC_OwnerReadInternalPub(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_OwnerReadInternalPub(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_KeyControlOwner(TCS_CONTEXT_HANDLE, TCS_KEY_HANDLE, UINT32, BYTE *, UINT32, TSS_BOOL, TPM_AUTH *, TSS_UUID *); TSS_RESULT RPC_GetCredential(TSS_HCONTEXT, UINT32, UINT32, UINT32 *, BYTE **); TSS_RESULT RPC_GetCapabilitySigned(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE, TCPA_CAPABILITY_AREA, UINT32, BYTE *, TPM_AUTH *, TCPA_VERSION *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_FieldUpgrade(TSS_HCONTEXT, UINT32, BYTE *, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT RPC_SetRedirection(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, UINT32, TPM_AUTH *); TSS_RESULT RPC_Delegate_Manage(TSS_HCONTEXT, TPM_FAMILY_ID, TPM_FAMILY_OPERATION, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Delegate_Manage(TSS_HCONTEXT, TPM_FAMILY_ID, TPM_FAMILY_OPERATION, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_CreateKeyDelegation(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Delegate_CreateKeyDelegation(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_CreateOwnerDelegation(TSS_HCONTEXT, TSS_BOOL, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Delegate_CreateOwnerDelegation(TSS_HCONTEXT, TSS_BOOL, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_LoadOwnerDelegation(TSS_HCONTEXT, TPM_DELEGATE_INDEX, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT Transport_Delegate_LoadOwnerDelegation(TSS_HCONTEXT, TPM_DELEGATE_INDEX, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT RPC_Delegate_ReadTable(TSS_HCONTEXT, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_Delegate_ReadTable(TSS_HCONTEXT, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_UpdateVerificationCount(TSS_HCONTEXT, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_Delegate_UpdateVerificationCount(TSS_HCONTEXT, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_Delegate_VerifyDelegation(TSS_HCONTEXT, UINT32, BYTE *); TSS_RESULT Transport_Delegate_VerifyDelegation(TSS_HCONTEXT, UINT32, BYTE *); TSS_RESULT RPC_DSAP(TSS_HCONTEXT, TPM_ENTITY_TYPE, TCS_KEY_HANDLE, TPM_NONCE *, UINT32, BYTE *, TCS_AUTHHANDLE *, TPM_NONCE *, TPM_NONCE *); TSS_RESULT Transport_DSAP(TSS_HCONTEXT, TPM_ENTITY_TYPE, TCS_KEY_HANDLE, TPM_NONCE *, UINT32, BYTE *, TCS_AUTHHANDLE *, TPM_NONCE *, TPM_NONCE *); TSS_RESULT RPC_CMK_SetRestrictions(TSS_HCONTEXT, TSS_CMK_DELEGATE, TPM_AUTH *); TSS_RESULT Transport_CMK_SetRestrictions(TSS_HCONTEXT, TSS_CMK_DELEGATE, TPM_AUTH *); TSS_RESULT RPC_CMK_ApproveMA(TSS_HCONTEXT, TPM_DIGEST, TPM_AUTH *, TPM_HMAC *); TSS_RESULT Transport_CMK_ApproveMA(TSS_HCONTEXT, TPM_DIGEST, TPM_AUTH *, TPM_HMAC *); TSS_RESULT RPC_CMK_CreateKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_ENCAUTH *, TPM_HMAC *, TPM_DIGEST *, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT Transport_CMK_CreateKey(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_ENCAUTH, TPM_HMAC, TPM_DIGEST, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT RPC_CMK_CreateTicket(TSS_HCONTEXT, UINT32, BYTE *, TPM_DIGEST, UINT32, BYTE *, TPM_AUTH *, TPM_HMAC *); TSS_RESULT Transport_CMK_CreateTicket(TSS_HCONTEXT, UINT32, BYTE *, TPM_DIGEST, UINT32, BYTE *, TPM_AUTH *, TPM_HMAC *); TSS_RESULT RPC_CMK_CreateBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, TSS_MIGRATE_SCHEME, UINT32, BYTE *, TPM_DIGEST, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT Transport_CMK_CreateBlob(TSS_HCONTEXT, TCS_KEY_HANDLE, TSS_MIGRATE_SCHEME, UINT32, BYTE *, TPM_DIGEST, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT RPC_CMK_ConvertMigration(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_CMK_AUTH, TPM_HMAC, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT Transport_CMK_ConvertMigration(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_CMK_AUTH, TPM_HMAC, UINT32, BYTE *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT RPC_FlushSpecific(TSS_HCONTEXT, TCS_HANDLE, TPM_RESOURCE_TYPE); TSS_RESULT Transport_FlushSpecific(TSS_HCONTEXT, TCS_HANDLE, TPM_RESOURCE_TYPE); TSS_RESULT RPC_Error(TSS_HCONTEXT, ...); struct tcs_api_table { #ifdef TSS_BUILD_KEY TSS_RESULT (*LoadKeyByBlob)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TCS_KEY_HANDLE *, TCS_KEY_HANDLE *); TSS_RESULT (*EvictKey)(TSS_HCONTEXT, TCS_KEY_HANDLE); TSS_RESULT (*CreateWrapKey)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT (*GetPubKey)(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*OwnerReadInternalPub)(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_AUTH*, UINT32*, BYTE**); #ifdef TSS_BUILD_CERTIFY TSS_RESULT (*CertifyKey)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCS_KEY_HANDLE, TPM_NONCE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); #endif #endif #ifdef TSS_BUILD_OWN TSS_RESULT (*OwnerClear)(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT (*ForceClear)(TSS_HCONTEXT); #endif #ifdef TSS_BUILD_AUTH TSS_RESULT (*OIAP)(TSS_HCONTEXT, TCS_AUTHHANDLE *, TCPA_NONCE *); TSS_RESULT (*OSAP)(TSS_HCONTEXT, TCPA_ENTITY_TYPE, UINT32, TPM_NONCE *, TCS_AUTHHANDLE *, TCPA_NONCE *, TCPA_NONCE *); TSS_RESULT (*TerminateHandle)(TSS_HCONTEXT, TCS_AUTHHANDLE); #endif #ifdef TSS_BUILD_CHANGEAUTH TSS_RESULT (*ChangeAuth)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_PROTOCOL_ID, TCPA_ENCAUTH *, TCPA_ENTITY_TYPE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*ChangeAuthOwner)(TSS_HCONTEXT, TCPA_PROTOCOL_ID, TCPA_ENCAUTH *, TCPA_ENTITY_TYPE, TPM_AUTH *); TSS_RESULT (*ChangeAuthAsymStart)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **, TCS_KEY_HANDLE *); TSS_RESULT (*ChangeAuthAsymFinish)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCS_KEY_HANDLE, TCPA_ENTITY_TYPE, TCPA_HMAC, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, TPM_NONCE *, TCPA_DIGEST *); #endif #ifdef TSS_BUILD_AIK TSS_RESULT (*ActivateTPMIdentity)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_PCR_EXTEND TSS_RESULT (*Extend)(TSS_HCONTEXT, TCPA_PCRINDEX, TCPA_DIGEST, TCPA_PCRVALUE *); TSS_RESULT (*PcrRead)(TSS_HCONTEXT, TCPA_PCRINDEX, TCPA_PCRVALUE *); TSS_RESULT (*PcrReset)(TSS_HCONTEXT, UINT32, BYTE *); #endif #ifdef TSS_BUILD_QUOTE TSS_RESULT (*Quote)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_QUOTE2 TSS_RESULT (*Quote2)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE *, UINT32, BYTE *, TSS_BOOL, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_DIR TSS_RESULT (*DirWriteAuth)(TSS_HCONTEXT, TCPA_DIRINDEX, TCPA_DIRVALUE *, TPM_AUTH *); TSS_RESULT (*DirRead)(TSS_HCONTEXT, TCPA_DIRINDEX, TCPA_DIRVALUE *); #endif #ifdef TSS_BUILD_SEAL TSS_RESULT (*Seal)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*Sealx)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_ENCAUTH *, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*Unseal)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_BIND TSS_RESULT (*UnBind)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_MIGRATION TSS_RESULT (*CreateMigrationBlob)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_MIGRATE_SCHEME, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT (*ConvertMigrationBlob)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*AuthorizeMigrationKey)(TSS_HCONTEXT, TCPA_MIGRATE_SCHEME, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_SIGN TSS_RESULT (*Sign)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_RANDOM TSS_RESULT (*GetRandom)(TSS_HCONTEXT, UINT32, BYTE **); TSS_RESULT (*StirRandom)(TSS_HCONTEXT, UINT32, BYTE *); #endif #ifdef TSS_BUILD_CAPS_TPM TSS_RESULT (*GetTPMCapability)(TSS_HCONTEXT, TCPA_CAPABILITY_AREA, UINT32, BYTE *, UINT32 *, BYTE **); TSS_RESULT (*SetCapability)(TSS_HCONTEXT, TCPA_CAPABILITY_AREA, UINT32, BYTE *, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT (*GetCapabilityOwner)(TSS_HCONTEXT, TPM_AUTH *, TCPA_VERSION *, UINT32 *, UINT32 *); #endif #ifdef TSS_BUILD_EK TSS_RESULT (*CreateEndorsementKeyPair)(TSS_HCONTEXT, TCPA_NONCE, UINT32, BYTE *, UINT32 *, BYTE **, TCPA_DIGEST *); TSS_RESULT (*ReadPubek)(TSS_HCONTEXT, TCPA_NONCE, UINT32 *, BYTE **, TCPA_DIGEST *); TSS_RESULT (*OwnerReadPubek)(TSS_HCONTEXT, TPM_AUTH *, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_SELFTEST TSS_RESULT (*SelfTestFull)(TSS_HCONTEXT); TSS_RESULT (*CertifySelfTest)(TSS_HCONTEXT, TCS_KEY_HANDLE, TCPA_NONCE, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*GetTestResult)(TSS_HCONTEXT, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_ADMIN TSS_RESULT (*DisablePubekRead)(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT (*SetOwnerInstall)(TSS_HCONTEXT, TSS_BOOL); TSS_RESULT (*OwnerSetDisable)(TSS_HCONTEXT, TSS_BOOL, TPM_AUTH *); TSS_RESULT (*ResetLockValue)(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT (*DisableOwnerClear)(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT (*DisableForceClear)(TSS_HCONTEXT); TSS_RESULT (*PhysicalDisable)(TSS_HCONTEXT); TSS_RESULT (*PhysicalEnable)(TSS_HCONTEXT); TSS_RESULT (*PhysicalSetDeactivated)(TSS_HCONTEXT, TSS_BOOL); TSS_RESULT (*PhysicalPresence)(TSS_HCONTEXT, TCPA_PHYSICAL_PRESENCE); TSS_RESULT (*SetTempDeactivated)(TSS_HCONTEXT); TSS_RESULT (*SetTempDeactivated2)(TSS_HCONTEXT, TPM_AUTH *); #endif #ifdef TSS_BUILD_MAINT TSS_RESULT (*CreateMaintenanceArchive)(TSS_HCONTEXT, TSS_BOOL, TPM_AUTH *, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT (*LoadMaintenanceArchive)(TSS_HCONTEXT, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*KillMaintenanceFeature)(TSS_HCONTEXT, TPM_AUTH *); TSS_RESULT (*LoadManuMaintPub)(TSS_HCONTEXT, TCPA_NONCE, UINT32, BYTE *, TCPA_DIGEST *); TSS_RESULT (*ReadManuMaintPub)(TSS_HCONTEXT, TCPA_NONCE, TCPA_DIGEST *); #endif #ifdef TSS_BUILD_DAA TSS_RESULT (*DaaJoin)(TSS_HCONTEXT, TPM_HANDLE, BYTE, UINT32, BYTE*, UINT32, BYTE*, TPM_AUTH*, UINT32*, BYTE**); TSS_RESULT (*DaaSign)(TSS_HCONTEXT, TPM_HANDLE, BYTE, UINT32, BYTE*, UINT32, BYTE*, TPM_AUTH*, UINT32*, BYTE**); #endif #ifdef TSS_BUILD_COUNTER TSS_RESULT (*ReadCounter)(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_COUNTER_VALUE*); TSS_RESULT (*CreateCounter)(TSS_HCONTEXT, UINT32, BYTE*, TPM_ENCAUTH, TPM_AUTH*, TSS_COUNTER_ID*, TPM_COUNTER_VALUE*); TSS_RESULT (*IncrementCounter)(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_AUTH*, TPM_COUNTER_VALUE*); TSS_RESULT (*ReleaseCounter)(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_AUTH*); TSS_RESULT (*ReleaseCounterOwner)(TSS_HCONTEXT, TSS_COUNTER_ID, TPM_AUTH*); #endif #ifdef TSS_BUILD_TICK TSS_RESULT (*ReadCurrentTicks)(TSS_HCONTEXT, UINT32*, BYTE**); TSS_RESULT (*TickStampBlob)(TSS_HCONTEXT, TCS_KEY_HANDLE, TPM_NONCE*, TPM_DIGEST*, TPM_AUTH*, UINT32*, BYTE**,UINT32*, BYTE**); #endif #ifdef TSS_BUILD_NV TSS_RESULT (*NV_DefineOrReleaseSpace)(TSS_HCONTEXT, UINT32, BYTE*, TCPA_ENCAUTH, TPM_AUTH*); TSS_RESULT (*NV_WriteValue)(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32, BYTE*, TPM_AUTH*); TSS_RESULT (*NV_WriteValueAuth)(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32, BYTE*, TPM_AUTH*); TSS_RESULT (*NV_ReadValue)(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32*, TPM_AUTH*, BYTE**); TSS_RESULT (*NV_ReadValueAuth)(TSS_HCONTEXT, TSS_NV_INDEX, UINT32, UINT32*, TPM_AUTH*, BYTE**); #endif #ifdef TSS_BUILD_AUDIT TSS_RESULT (*SetOrdinalAuditStatus)(TSS_HCONTEXT, TPM_AUTH *, UINT32, TSS_BOOL); TSS_RESULT (*GetAuditDigest)(TSS_HCONTEXT, UINT32, TPM_DIGEST *, UINT32 *, BYTE **, TSS_BOOL *, UINT32 *, UINT32 **); TSS_RESULT (*GetAuditDigestSigned)(TSS_HCONTEXT, TCS_KEY_HANDLE, TSS_BOOL, TPM_NONCE *, TPM_AUTH *, UINT32 *, BYTE **, TPM_DIGEST *, TPM_DIGEST *, UINT32 *, BYTE **); #endif #ifdef TSS_BUILD_TSS12 TSS_RESULT (*SetOperatorAuth)(TSS_HCONTEXT, TPM_SECRET *); TSS_RESULT (*FlushSpecific)(TSS_HCONTEXT, TCS_HANDLE, TPM_RESOURCE_TYPE); #endif #ifdef TSS_BUILD_DELEGATION TSS_RESULT (*Delegate_Manage)(TSS_HCONTEXT, TPM_FAMILY_ID, TPM_FAMILY_OPERATION, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*Delegate_CreateKeyDelegation)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*Delegate_CreateOwnerDelegation)(TSS_HCONTEXT, TSS_BOOL, UINT32, BYTE *, TPM_ENCAUTH *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*Delegate_LoadOwnerDelegation)(TSS_HCONTEXT, TPM_DELEGATE_INDEX, UINT32, BYTE *, TPM_AUTH *); TSS_RESULT (*Delegate_ReadTable)(TSS_HCONTEXT, UINT32 *, BYTE **, UINT32 *, BYTE **); TSS_RESULT (*Delegate_UpdateVerificationCount)(TSS_HCONTEXT, UINT32, BYTE *, TPM_AUTH *, UINT32 *, BYTE **); TSS_RESULT (*Delegate_VerifyDelegation)(TSS_HCONTEXT, UINT32, BYTE *); TSS_RESULT (*DSAP)(TSS_HCONTEXT, TPM_ENTITY_TYPE, TCS_KEY_HANDLE, TPM_NONCE *, UINT32, BYTE *, TCS_AUTHHANDLE *, TPM_NONCE *, TPM_NONCE *); #endif TSS_RESULT (*FieldUpgrade)(TSS_HCONTEXT, UINT32, BYTE *, UINT32 *, BYTE **, TPM_AUTH *); TSS_RESULT (*SetRedirection)(TSS_HCONTEXT, TCS_KEY_HANDLE, UINT32, UINT32, TPM_AUTH *); }; extern struct tcs_api_table tcs_normal_api; #ifdef TSS_BUILD_TRANSPORT extern struct tcs_api_table tcs_transport_api; #endif #endif trousers-0.3.15/src/include/threads.h0000664000175000017510000000273513663651711017000 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #ifndef __THREADS_H__ #define __THREADS_H__ #ifdef HAVE_PTHREAD_H #include /* mutex abstractions */ #define MUTEX_INIT(m) pthread_mutex_init(&m, NULL) #define MUTEX_LOCK(m) pthread_mutex_lock(&m) #define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m) #define MUTEX_DECLARE(m) pthread_mutex_t m #define MUTEX_DECLARE_INIT(m) pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER #define MUTEX_DECLARE_EXTERN(m) extern pthread_mutex_t m /* condition variable abstractions */ #define COND_DECLARE(c) pthread_cond_t c #define COND_INIT(c) pthread_cond_init(&c, NULL) #define COND_VAR pthread_cond_t #define COND_WAIT(c,m) pthread_cond_wait(c,m) #define COND_SIGNAL(c) pthread_cond_signal(c) /* thread abstractions */ #define THREAD_ID ((THREAD_TYPE)pthread_self()) #define THREAD_TYPE pthread_t #define THREAD_JOIN pthread_join #define THREAD_DETACH pthread_detach #define THREAD_ATTR_DECLARE(a) pthread_attr_t a #define THREAD_ATTR_INIT(a) pthread_attr_init(&a) #define THREAD_ATTR_SETJOINABLE(a) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_JOINABLE) #define THREAD_EXIT pthread_exit #define THREAD_CREATE(a,b,c,d) pthread_create(a,b,c,d) #define THREAD_SET_SIGNAL_MASK pthread_sigmask #define THREAD_NULL (THREAD_TYPE *)0 #else #error No threading library defined! (Cannot find pthread.h) #endif #endif trousers-0.3.15/src/include/tss/0000775000175000017510000000000013663651711015777 5ustar deboradeboratrousers-0.3.15/src/include/tss/tpm_ordinal.h0000664000175000017510000002353013663651711020463 0ustar deboradebora/* * TPM Ordinal definitions extracted from the TPM 1.2 specification, rev 85. */ #ifndef __TPM_ORDINAL_H__ #define __TPM_ORDINAL_H__ #define TPM_PROTECTED_COMMAND ((UINT32)(0x00000000)) #define TPM_UNPROTECTED_COMMAND ((UINT32)(0x80000000)) #define TPM_CONNECTION_COMMAND ((UINT32)(0x40000000)) #define TPM_VENDOR_COMMAND ((UINT32)(0x20000000)) #define TPM_MAIN ((UINT16)(0x0000)) #define TPM_PC ((UINT16)(0x0001)) #define TPM_PDA ((UINT16)(0x0002)) #define TPM_CELL_PHONE ((UINT16)(0x0003)) #define TPM_SERVER ((UINT16)(0x0004)) #define TPM_PROTECTED_ORDINAL (TPM_MAIN | TPM_PROTECTED_COMMAND) #define TPM_UNPROTECTED_ORDINAL (TPM_MAIN | TPM_UNPROTECTED_COMMAND) #define TPM_CONNECTION_ORDINAL (TPM_MAIN | TPM_CONNECTION_COMMAND) #define TPM_ORD_OIAP ((UINT32)0x0000000A) #define TPM_ORD_OSAP ((UINT32)0x0000000B) #define TPM_ORD_ChangeAuth ((UINT32)0x0000000C) #define TPM_ORD_TakeOwnership ((UINT32)0x0000000D) #define TPM_ORD_ChangeAuthAsymStart ((UINT32)0x0000000E) #define TPM_ORD_ChangeAuthAsymFinish ((UINT32)0x0000000F) #define TPM_ORD_ChangeAuthOwner ((UINT32)0x00000010) #define TPM_ORD_DSAP ((UINT32)0x00000011) #define TPM_ORD_CMK_CreateTicket ((UINT32)0x00000012) #define TPM_ORD_CMK_CreateKey ((UINT32)0x00000013) #define TPM_ORD_Extend ((UINT32)0x00000014) #define TPM_ORD_PcrRead ((UINT32)0x00000015) #define TPM_ORD_Quote ((UINT32)0x00000016) #define TPM_ORD_Seal ((UINT32)0x00000017) #define TPM_ORD_Unseal ((UINT32)0x00000018) #define TPM_ORD_DirWriteAuth ((UINT32)0x00000019) #define TPM_ORD_DirRead ((UINT32)0x0000001A) #define TPM_ORD_CMK_CreateBlob ((UINT32)0x0000001B) #define TPM_ORD_CMK_SetRestrictions ((UINT32)0x0000001C) #define TPM_ORD_CMK_ApproveMA ((UINT32)0x0000001D) #define TPM_ORD_UnBind ((UINT32)0x0000001E) #define TPM_ORD_CreateWrapKey ((UINT32)0x0000001F) #define TPM_ORD_LoadKey ((UINT32)0x00000020) #define TPM_ORD_GetPubKey ((UINT32)0x00000021) #define TPM_ORD_EvictKey ((UINT32)0x00000022) #define TPM_ORD_KeyControlOwner ((UINT32)0x00000023) #define TPM_ORD_CMK_ConvertMigration ((UINT32)0x00000024) #define TPM_ORD_MigrateKey ((UINT32)0x00000025) #define TPM_ORD_CreateMigrationBlob ((UINT32)0x00000028) #define TPM_ORD_DAA_Join ((UINT32)0x00000029) #define TPM_ORD_ConvertMigrationBlob ((UINT32)0x0000002A) #define TPM_ORD_AuthorizeMigrationKey ((UINT32)0x0000002B) #define TPM_ORD_CreateMaintenanceArchive ((UINT32)0x0000002C) #define TPM_ORD_LoadMaintenanceArchive ((UINT32)0x0000002D) #define TPM_ORD_KillMaintenanceFeature ((UINT32)0x0000002E) #define TPM_ORD_LoadManuMaintPub ((UINT32)0x0000002F) #define TPM_ORD_ReadManuMaintPub ((UINT32)0x00000030) #define TPM_ORD_DAA_Sign ((UINT32)0x00000031) #define TPM_ORD_CertifyKey ((UINT32)0x00000032) #define TPM_ORD_CertifyKey2 ((UINT32)0x00000033) #define TPM_ORD_Sign ((UINT32)0x0000003C) #define TPM_ORD_Sealx ((UINT32)0x0000003D) #define TPM_ORD_Quote2 ((UINT32)0x0000003E) #define TPM_ORD_SetCapability ((UINT32)0x0000003F) #define TPM_ORD_ResetLockValue ((UINT32)0x00000040) #define TPM_ORD_LoadKey2 ((UINT32)0x00000041) #define TPM_ORD_GetRandom ((UINT32)0x00000046) #define TPM_ORD_StirRandom ((UINT32)0x00000047) #define TPM_ORD_SelfTestFull ((UINT32)0x00000050) #define TPM_ORD_CertifySelfTest ((UINT32)0x00000052) #define TPM_ORD_ContinueSelfTest ((UINT32)0x00000053) #define TPM_ORD_GetTestResult ((UINT32)0x00000054) #define TPM_ORD_Reset ((UINT32)0x0000005A) #define TPM_ORD_OwnerClear ((UINT32)0x0000005B) #define TPM_ORD_DisableOwnerClear ((UINT32)0x0000005C) #define TPM_ORD_ForceClear ((UINT32)0x0000005D) #define TPM_ORD_DisableForceClear ((UINT32)0x0000005E) #define TPM_ORD_GetCapabilitySigned ((UINT32)0x00000064) #define TPM_ORD_GetCapability ((UINT32)0x00000065) #define TPM_ORD_GetCapabilityOwner ((UINT32)0x00000066) #define TPM_ORD_OwnerSetDisable ((UINT32)0x0000006E) #define TPM_ORD_PhysicalEnable ((UINT32)0x0000006F) #define TPM_ORD_PhysicalDisable ((UINT32)0x00000070) #define TPM_ORD_SetOwnerInstall ((UINT32)0x00000071) #define TPM_ORD_PhysicalSetDeactivated ((UINT32)0x00000072) #define TPM_ORD_SetTempDeactivated ((UINT32)0x00000073) #define TPM_ORD_SetOperatorAuth ((UINT32)0x00000074) #define TPM_ORD_SetOwnerPointer ((UINT32)0x00000075) #define TPM_ORD_CreateEndorsementKeyPair ((UINT32)0x00000078) #define TPM_ORD_MakeIdentity ((UINT32)0x00000079) #define TPM_ORD_ActivateIdentity ((UINT32)0x0000007A) #define TPM_ORD_ReadPubek ((UINT32)0x0000007C) #define TPM_ORD_OwnerReadPubek ((UINT32)0x0000007D) #define TPM_ORD_DisablePubekRead ((UINT32)0x0000007E) #define TPM_ORD_CreateRevocableEK ((UINT32)0x0000007F) #define TPM_ORD_RevokeTrust ((UINT32)0x00000080) #define TPM_ORD_OwnerReadInternalPub ((UINT32)0x00000081) #define TPM_ORD_GetAuditEvent ((UINT32)0x00000082) #define TPM_ORD_GetAuditEventSigned ((UINT32)0x00000083) #define TPM_ORD_GetAuditDigest ((UINT32)0x00000085) #define TPM_ORD_GetAuditDigestSigned ((UINT32)0x00000086) #define TPM_ORD_GetOrdinalAuditStatus ((UINT32)0x0000008C) #define TPM_ORD_SetOrdinalAuditStatus ((UINT32)0x0000008D) #define TPM_ORD_Terminate_Handle ((UINT32)0x00000096) #define TPM_ORD_Init ((UINT32)0x00000097) #define TPM_ORD_SaveState ((UINT32)0x00000098) #define TPM_ORD_Startup ((UINT32)0x00000099) #define TPM_ORD_SetRedirection ((UINT32)0x0000009A) #define TPM_ORD_SHA1Start ((UINT32)0x000000A0) #define TPM_ORD_SHA1Update ((UINT32)0x000000A1) #define TPM_ORD_SHA1Complete ((UINT32)0x000000A2) #define TPM_ORD_SHA1CompleteExtend ((UINT32)0x000000A3) #define TPM_ORD_FieldUpgrade ((UINT32)0x000000AA) #define TPM_ORD_SaveKeyContext ((UINT32)0x000000B4) #define TPM_ORD_LoadKeyContext ((UINT32)0x000000B5) #define TPM_ORD_SaveAuthContext ((UINT32)0x000000B6) #define TPM_ORD_LoadAuthContext ((UINT32)0x000000B7) #define TPM_ORD_SaveContext ((UINT32)0x000000B8) #define TPM_ORD_LoadContext ((UINT32)0x000000B9) #define TPM_ORD_FlushSpecific ((UINT32)0x000000BA) #define TPM_ORD_PCR_Reset ((UINT32)0x000000C8) #define TPM_ORD_NV_DefineSpace ((UINT32)0x000000CC) #define TPM_ORD_NV_WriteValue ((UINT32)0x000000CD) #define TPM_ORD_NV_WriteValueAuth ((UINT32)0x000000CE) #define TPM_ORD_NV_ReadValue ((UINT32)0x000000CF) #define TPM_ORD_NV_ReadValueAuth ((UINT32)0x000000D0) #define TPM_ORD_Delegate_UpdateVerification ((UINT32)0x000000D1) #define TPM_ORD_Delegate_Manage ((UINT32)0x000000D2) #define TPM_ORD_Delegate_CreateKeyDelegation ((UINT32)0x000000D4) #define TPM_ORD_Delegate_CreateOwnerDelegation ((UINT32)0x000000D5) #define TPM_ORD_Delegate_VerifyDelegation ((UINT32)0x000000D6) #define TPM_ORD_Delegate_LoadOwnerDelegation ((UINT32)0x000000D8) #define TPM_ORD_Delegate_ReadTable ((UINT32)0x000000DB) #define TPM_ORD_CreateCounter ((UINT32)0x000000DC) #define TPM_ORD_IncrementCounter ((UINT32)0x000000DD) #define TPM_ORD_ReadCounter ((UINT32)0x000000DE) #define TPM_ORD_ReleaseCounter ((UINT32)0x000000DF) #define TPM_ORD_ReleaseCounterOwner ((UINT32)0x000000E0) #define TPM_ORD_EstablishTransport ((UINT32)0x000000E6) #define TPM_ORD_ExecuteTransport ((UINT32)0x000000E7) #define TPM_ORD_ReleaseTransportSigned ((UINT32)0x000000E8) #define TPM_ORD_GetTicks ((UINT32)0x000000F1) #define TPM_ORD_TickStampBlob ((UINT32)0x000000F2) #define TSC_ORD_PhysicalPresence ((UINT32)0x4000000A) #define TSC_ORD_ResetEstablishmentBit ((UINT32)0x4000000B) #endif // __TPM_ORDINAL_H__ trousers-0.3.15/src/include/tss/tddli.h0000664000175000017510000000461013663651711017251 0ustar deboradebora/*++ TPM Device Driver Library interface --*/ #ifndef __TDDLI_H__ #define __TDDLI_H__ #include #include #if !defined(TDDLI) #ifdef WIN32 // --- This should be used on Windows platforms #ifdef TDDLI_EXPORTS #define TDDLI __declspec(dllexport) #else #define TDDLI __declspec(dllimport) #endif #else #define TDDLI #endif #endif /* !defined(TDDLI) */ #define TDDL_CAP_VERSION 0x0100 #define TDDL_CAP_VER_DRV 0x0101 #define TDDL_CAP_VER_FW 0x0102 #define TDDL_CAP_VER_FW_DATE 0x0103 #define TDDL_CAP_PROPERTY 0x0200 #define TDDL_CAP_PROP_MANUFACTURER 0x0201 #define TDDL_CAP_PROP_MODULE_TYPE 0x0202 #define TDDL_CAP_PROP_GLOBAL_STATE 0x0203 //-------------------------------------------------------------------- // TDDL specific helper redefinitions #ifdef __cplusplus extern "C" { #endif //establish a connection to the TPM device driver TDDLI TSS_RESULT Tddli_Open(void); //close a open connection to the TPM device driver TDDLI TSS_RESULT Tddli_Close(void); //cancels the last outstanding TPM command TDDLI TSS_RESULT Tddli_Cancel(void); // read the attributes returned by the TPM HW/FW TDDLI TSS_RESULT Tddli_GetCapability( UINT32 CapArea, UINT32 SubCap, BYTE *pCapBuf, UINT32 *puntCapBufLen); // set parameters to the TPM HW/FW TDDLI TSS_RESULT Tddli_SetCapability( UINT32 CapArea, UINT32 SubCap, BYTE *pCapBuf, UINT32 puntCapBufLen); // get status of the TPM driver and device TDDLI TSS_RESULT Tddli_GetStatus( UINT32 ReqStatusType, UINT32 *puntStatus); // send any data to the TPM module TDDLI TSS_RESULT Tddli_TransmitData( BYTE *pTransmitBuf, UINT32 TransmitBufLen, BYTE *pReceiveBuf, UINT32 *puntReceiveBufLen); TDDLI TSS_RESULT Tddli_SetPowerManagement( TSS_BOOL SendSaveStateCommand, // in UINT32 *QuerySetNewTPMPowerState); // in, out TDDLI TSS_RESULT Tddli_PowerManagementControl( TSS_BOOL SendPowerManager, // in UINT32 *DriverManagesPowerStates); // out #ifdef __cplusplus } #endif #endif // __TDDLI_H__ trousers-0.3.15/src/include/tss/tddl_error.h0000664000175000017510000000247313663651711020316 0ustar deboradebora/*++ TPM Device Driver Library error return codes --*/ #ifndef __TDDL_ERROR_H__ #define __TDDL_ERROR_H__ #include #include #ifndef TSS_E_BASE #define TSS_E_BASE 0x00000000L #endif // TSS_E_BASE // // specific error codes returned by the TPM device driver library // offset TSS_TDDL_OFFSET // #define TDDL_E_FAIL TSS_E_FAIL #define TDDL_E_TIMEOUT TSS_E_TIMEOUT // The connection was already established. #define TDDL_E_ALREADY_OPENED (UINT32)(TSS_E_BASE + 0x081L) // The device was not connected. #define TDDL_E_ALREADY_CLOSED (UINT32)(TSS_E_BASE + 0x082L) // The receive buffer is too small. #define TDDL_E_INSUFFICIENT_BUFFER (UINT32)(TSS_E_BASE + 0x083L) // The command has already completed. #define TDDL_E_COMMAND_COMPLETED (UINT32)(TSS_E_BASE + 0x084L) // TPM aborted processing of command. #define TDDL_E_COMMAND_ABORTED (UINT32)(TSS_E_BASE + 0x085L) // The request could not be performed because of an I/O device error. #define TDDL_E_IOERROR (UINT32)(TSS_E_BASE + 0x087L) // Unsupported TAG is requested #define TDDL_E_BADTAG (UINT32)(TSS_E_BASE + 0x088L) // the requested TPM component was not found #define TDDL_E_COMPONENT_NOT_FOUND (UINT32)(TSS_E_BASE + 0x089L) #endif // __TDDL_ERROR_H__ trousers-0.3.15/src/include/tss/tcs_typedef.h0000664000175000017510000000141013663651711020455 0ustar deboradebora/*++ Global typedefs for TSS Core Service */ #ifndef __TCS_TYPEDEF_H__ #define __TCS_TYPEDEF_H__ #include #include typedef UINT32 TCS_AUTHHANDLE; typedef UINT32 TCS_CONTEXT_HANDLE; typedef UINT32 TCS_KEY_HANDLE; typedef UINT32 TCS_HANDLE; // Substitution definitions for TCS-IDL typedef TPM_ENCAUTH TCG_ENCAUTH; typedef TPM_NONCE TCG_NONCE; typedef TPM_ENTITY_TYPE TCG_ENTITY_TYPE; typedef TPM_PCRINDEX TCG_PCRINDEX; typedef TPM_DIGEST TCG_DIGEST; typedef TPM_PCRVALUE TCG_PCRVALUE; typedef TPM_DIRVALUE TCG_DIRVALUE; typedef TPM_DIRINDEX TCG_DIRINDEX; #endif // __TCS_TYPEDEF_H__ trousers-0.3.15/src/include/tss/tss_defines.h0000664000175000017510000015102413663651711020461 0ustar deboradebora/*++ Global defines for TSS. --*/ #ifndef __TSS_DEFINES_H__ #define __TSS_DEFINES_H__ #include #include ////////////////////////////////////////////////////////////////////////// // Object types: ////////////////////////////////////////////////////////////////////////// // // definition of the object types that can be created via CreateObject // #define TSS_OBJECT_TYPE_POLICY (0x01) // Policy object #define TSS_OBJECT_TYPE_RSAKEY (0x02) // RSA-Key object #define TSS_OBJECT_TYPE_ENCDATA (0x03) // Encrypted data object #define TSS_OBJECT_TYPE_PCRS (0x04) // PCR composite object #define TSS_OBJECT_TYPE_HASH (0x05) // Hash object #define TSS_OBJECT_TYPE_DELFAMILY (0x06) // Delegation Family object #define TSS_OBJECT_TYPE_NV (0x07) // NV object #define TSS_OBJECT_TYPE_MIGDATA (0x08) // CMK Migration data object #define TSS_OBJECT_TYPE_DAA_CERTIFICATE (0x09) // DAA credential #define TSS_OBJECT_TYPE_DAA_ISSUER_KEY (0x0a) // DAA cred. issuer keypair #define TSS_OBJECT_TYPE_DAA_ARA_KEY (0x0b) // DAA anonymity revocation // authority keypair ////////////////////////////////////////////////////////////////////////// // CreateObject: Flags ////////////////////////////////////////////////////////////////////////// //************************************ // Flags for creating RSAKEY object: * //************************************ // // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // |x x|Auth // |x| Volatility // |x| Migration // |x x x x| Type // |x x x x| Size // |x x| CMK // |x x x| Version // |0 0 0 0 0 0 0 0 0| Reserved // |x x x x x x| Fixed Type // // Authorization: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // Never |0 0| // Always |0 1| // Private key always |1 0| // #define TSS_KEY_NO_AUTHORIZATION (0x00000000) // no auth needed // for this key #define TSS_KEY_AUTHORIZATION (0x00000001) // key needs auth // for all ops #define TSS_KEY_AUTHORIZATION_PRIV_USE_ONLY (0x00000002) // key needs auth // for privkey ops, // noauth for pubkey // // Volatility // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // Non Volatile |0| // Volatile |1| // #define TSS_KEY_NON_VOLATILE (0x00000000) // Key is non-volatile #define TSS_KEY_VOLATILE (0x00000004) // Key is volatile // // Migration // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // Non Migratable |0| // Migratable |1| // #define TSS_KEY_NOT_MIGRATABLE (0x00000000) // key is not migratable #define TSS_KEY_MIGRATABLE (0x00000008) // key is migratable // // Usage // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // Default (Legacy) |0 0 0 0| // Signing |0 0 0 1| // Storage |0 0 1 0| // Identity |0 0 1 1| // AuthChange |0 1 0 0| // Bind |0 1 0 1| // Legacy |0 1 1 0| // #define TSS_KEY_TYPE_DEFAULT (0x00000000) // indicate a default key // (Legacy-Key) #define TSS_KEY_TYPE_SIGNING (0x00000010) // indicate a signing key #define TSS_KEY_TYPE_STORAGE (0x00000020) // used as storage key #define TSS_KEY_TYPE_IDENTITY (0x00000030) // indicate an idendity key #define TSS_KEY_TYPE_AUTHCHANGE (0x00000040) // indicate an ephemeral key #define TSS_KEY_TYPE_BIND (0x00000050) // indicate a key for TPM_Bind #define TSS_KEY_TYPE_LEGACY (0x00000060) // indicate a key that can // perform signing and binding #define TSS_KEY_TYPE_MIGRATE (0x00000070) // indicate a key that can // act as a CMK MA #define TSS_KEY_TYPE_BITMASK (0x000000F0) // mask to extract key type // // Key size // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // DEFAULT |0 0 0 0| // 512 |0 0 0 1| // 1024 |0 0 1 0| // 2048 |0 0 1 1| // 4096 |0 1 0 0| // 8192 |0 1 0 1| // 16384 |0 1 1 0| // #define TSS_KEY_SIZE_DEFAULT (UINT32)(0x00000000) // indicate tpm-specific size #define TSS_KEY_SIZE_512 (UINT32)(0x00000100) // indicate a 512-bit key #define TSS_KEY_SIZE_1024 (UINT32)(0x00000200) // indicate a 1024-bit key #define TSS_KEY_SIZE_2048 (UINT32)(0x00000300) // indicate a 2048-bit key #define TSS_KEY_SIZE_4096 (UINT32)(0x00000400) // indicate a 4096-bit key #define TSS_KEY_SIZE_8192 (UINT32)(0x00000500) // indicate a 8192-bit key #define TSS_KEY_SIZE_16384 (UINT32)(0x00000600) // indicate a 16384-bit key #define TSS_KEY_SIZE_BITMASK (UINT32)(0x00000F00) // mask to extract key size // // Certified Migratability // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // DEFAULT |0 0| // Not Certified Migratable |0 0| // Certified Migratable |0 1| // #define TSS_KEY_NOT_CERTIFIED_MIGRATABLE (UINT32)(0x00000000) #define TSS_KEY_CERTIFIED_MIGRATABLE (UINT32)(0x00001000) // // Specification version // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // Context default |0 0 0| // TPM_KEY 1.1b key |0 0 1| // TPM_KEY12 1.2 key |0 1 0| // #define TSS_KEY_STRUCT_DEFAULT (UINT32)(0x00000000) #define TSS_KEY_STRUCT_KEY (UINT32)(0x00004000) #define TSS_KEY_STRUCT_KEY12 (UINT32)(0x00008000) #define TSS_KEY_STRUCT_BITMASK (UINT32)(0x0001C000) // // fixed KeyTypes (templates) // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // |0 0 0 0 0 0| Empty Key // |0 0 0 0 0 1| Storage Root Key // #define TSS_KEY_EMPTY_KEY (0x00000000) // no TPM key template // (empty TSP key object) #define TSS_KEY_TSP_SRK (0x04000000) // use a TPM SRK template // (TSP key object for SRK) #define TSS_KEY_TEMPLATE_BITMASK (0xFC000000) // bitmask to extract key // template //************************************* // Flags for creating ENCDATA object: * //************************************* // // Type // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // Seal |0 0 1| // Bind |0 1 0| // Legacy |0 1 1| // // ENCDATA Reserved: // |x x x x x x x x x x x x x x x x x x x x x x x x x x x x x| // #define TSS_ENCDATA_SEAL (0x00000001) // data for seal operation #define TSS_ENCDATA_BIND (0x00000002) // data for bind operation #define TSS_ENCDATA_LEGACY (0x00000003) // data for legacy bind operation //********************************** // Flags for creating HASH object: * //********************************** // // Algorithm // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // DEFAULT // |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| // SHA1 // |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1| // OTHER // |1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1| // #define TSS_HASH_DEFAULT (0x00000000) // Default hash algorithm #define TSS_HASH_SHA1 (0x00000001) // SHA-1 with 20 bytes #define TSS_HASH_OTHER (0xFFFFFFFF) // Not-specified hash algorithm //************************************ // Flags for creating POLICY object: * //************************************ // // Type // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // // Usage |0 0 1| // Migration |0 1 0| // Operator |0 1 1| // // POLICY Reserved: // |x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x| #define TSS_POLICY_USAGE (0x00000001) // usage policy object #define TSS_POLICY_MIGRATION (0x00000002) // migration policy object #define TSS_POLICY_OPERATOR (0x00000003) // migration policy object //****************************************** // Flags for creating PCRComposite object: * //****************************************** // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // |x x| Struct // |x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x| Reserved // // PCRComposite Version: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // --------------------------------------------------------------- // TPM_PCR_DEFAULT |0 0 0| // TPM_PCR_INFO |0 0 1| // TPM_PCR_INFO_LONG |0 1 0| // TPM_PCR_INFO_SHORT |0 1 1| // #define TSS_PCRS_STRUCT_DEFAULT (0x00000000) // depends on context #define TSS_PCRS_STRUCT_INFO (0x00000001) // TPM_PCR_INFO #define TSS_PCRS_STRUCT_INFO_LONG (0x00000002) // TPM_PCR_INFO_LONG #define TSS_PCRS_STRUCT_INFO_SHORT (0x00000003) // TPM_PCR_INFO_SHORT ////////////////////////////////////////////////////////////////////////// // Attribute Flags, Subflags, and Values ////////////////////////////////////////////////////////////////////////// //****************** // Context object: * //****************** // // Attributes // #define TSS_TSPATTRIB_CONTEXT_SILENT_MODE (0x00000001) // dialog display control #define TSS_TSPATTRIB_CONTEXT_MACHINE_NAME (0x00000002) // remote machine name #define TSS_TSPATTRIB_CONTEXT_VERSION_MODE (0x00000003) // context version #define TSS_TSPATTRIB_CONTEXT_TRANSPORT (0x00000004) // transport control #define TSS_TSPATTRIB_CONTEXT_CONNECTION_VERSION (0x00000005) // connection version #define TSS_TSPATTRIB_SECRET_HASH_MODE (0x00000006) // flag indicating whether // NUL is included in the // hash of the password // // SubFlags for Flag TSS_TSPATTRIB_CONTEXT_TRANSPORT // #define TSS_TSPATTRIB_CONTEXTTRANS_CONTROL (0x00000008) #define TSS_TSPATTRIB_CONTEXTTRANS_MODE (0x00000010) // // Values for the TSS_TSPATTRIB_CONTEXT_SILENT_MODE attribute // #define TSS_TSPATTRIB_CONTEXT_NOT_SILENT (0x00000000) // TSP dialogs enabled #define TSS_TSPATTRIB_CONTEXT_SILENT (0x00000001) // TSP dialogs disabled // // Values for the TSS_TSPATTRIB_CONTEXT_VERSION_MODE attribute // #define TSS_TSPATTRIB_CONTEXT_VERSION_AUTO (0x00000001) #define TSS_TSPATTRIB_CONTEXT_VERSION_V1_1 (0x00000002) #define TSS_TSPATTRIB_CONTEXT_VERSION_V1_2 (0x00000003) // // Values for the subflag TSS_TSPATTRIB_CONTEXT_TRANS_CONTROL // #define TSS_TSPATTRIB_DISABLE_TRANSPORT (0x00000016) #define TSS_TSPATTRIB_ENABLE_TRANSPORT (0x00000032) // // Values for the subflag TSS_TSPATTRIB_CONTEXT_TRANS_MODE // #define TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION (0x00000000) #define TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION (0x00000001) #define TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL (0x00000002) #define TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE (0x00000004) #define TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH (0x00000008) // // Values for the TSS_TSPATTRIB_CONTEXT_CONNECTION_VERSION attribute // #define TSS_CONNECTION_VERSION_1_1 (0x00000001) #define TSS_CONNECTION_VERSION_1_2 (0x00000002) // // Subflags of TSS_TSPATTRIB_SECRET_HASH_MODE // #define TSS_TSPATTRIB_SECRET_HASH_MODE_POPUP (0x00000001) // // Values for TSS_TSPATTRIB_SECRET_HASH_MODE_POPUP subflag // #define TSS_TSPATTRIB_HASH_MODE_NOT_NULL (0x00000000) #define TSS_TSPATTRIB_HASH_MODE_NULL (0x00000001) // ************* // TPM object: * // ************* // // Attributes: // #define TSS_TSPATTRIB_TPM_CALLBACK_COLLATEIDENTITY 0x00000001 #define TSS_TSPATTRIB_TPM_CALLBACK_ACTIVATEIDENTITY 0x00000002 #define TSS_TSPATTRIB_TPM_ORDINAL_AUDIT_STATUS 0x00000003 #define TSS_TSPATTRIB_TPM_CREDENTIAL 0x00001000 // // Subflags for TSS_TSPATTRIB_TPM_ORDINAL_AUDIT_STATUS // #define TPM_CAP_PROP_TPM_CLEAR_ORDINAL_AUDIT 0x00000000 #define TPM_CAP_PROP_TPM_SET_ORDINAL_AUDIT 0x00000001 // // Subflags for TSS_TSPATTRIB_TPM_CREDENTIAL // #define TSS_TPMATTRIB_EKCERT 0x00000001 #define TSS_TPMATTRIB_TPM_CC 0x00000002 #define TSS_TPMATTRIB_PLATFORMCERT 0x00000003 #define TSS_TPMATTRIB_PLATFORM_CC 0x00000004 //***************** // Policy object: * //***************** // // Attributes // #define TSS_TSPATTRIB_POLICY_CALLBACK_HMAC (0x00000080) // enable/disable callback function #define TSS_TSPATTRIB_POLICY_CALLBACK_XOR_ENC (0x00000100) // enable/disable callback function #define TSS_TSPATTRIB_POLICY_CALLBACK_TAKEOWNERSHIP (0x00000180) // enable/disable callback function #define TSS_TSPATTRIB_POLICY_CALLBACK_CHANGEAUTHASYM (0x00000200) // enable/disable callback function #define TSS_TSPATTRIB_POLICY_SECRET_LIFETIME (0x00000280) // set lifetime mode for policy secret #define TSS_TSPATTRIB_POLICY_POPUPSTRING (0x00000300) // set a NULL terminated UNICODE string // which is displayed in the TSP policy // popup dialog #define TSS_TSPATTRIB_POLICY_CALLBACK_SEALX_MASK (0x00000380) // enable/disable callback function #if 0 /* This attribute flag is defined earlier with the context attributes. * It is valid for both context and policy objects. It is copied * here as a reminder to avoid collisions. */ #define TSS_TSPATTRIB_SECRET_HASH_MODE (0x00000006) // flag indicating whether // NUL is included in the // hash of the password #endif #define TSS_TSPATTRIB_POLICY_DELEGATION_INFO (0x00000001) #define TSS_TSPATTRIB_POLICY_DELEGATION_PCR (0x00000002) // // SubFlags for Flag TSS_TSPATTRIB_POLICY_SECRET_LIFETIME // #define TSS_SECRET_LIFETIME_ALWAYS (0x00000001) // secret will not be // invalidated #define TSS_SECRET_LIFETIME_COUNTER (0x00000002) // secret lifetime // controlled by counter #define TSS_SECRET_LIFETIME_TIMER (0x00000003) // secret lifetime // controlled by time #define TSS_TSPATTRIB_POLSECRET_LIFETIME_ALWAYS TSS_SECRET_LIFETIME_ALWAYS #define TSS_TSPATTRIB_POLSECRET_LIFETIME_COUNTER TSS_SECRET_LIFETIME_COUNTER #define TSS_TSPATTRIB_POLSECRET_LIFETIME_TIMER TSS_SECRET_LIFETIME_TIMER // Alternate names misspelled in the 1.1 TSS spec. #define TSS_TSPATTRIB_POLICYSECRET_LIFETIME_ALWAYS TSS_SECRET_LIFETIME_ALWAYS #define TSS_TSPATTRIB_POLICYSECRET_LIFETIME_COUNTER TSS_SECRET_LIFETIME_COUNTER #define TSS_TSPATTRIB_POLICYSECRET_LIFETIME_TIMER TSS_SECRET_LIFETIME_TIMER // // Subflags of TSS_TSPATTRIB_POLICY_DELEGATION_INFO // #define TSS_TSPATTRIB_POLDEL_TYPE (0x00000001) #define TSS_TSPATTRIB_POLDEL_INDEX (0x00000002) #define TSS_TSPATTRIB_POLDEL_PER1 (0x00000003) #define TSS_TSPATTRIB_POLDEL_PER2 (0x00000004) #define TSS_TSPATTRIB_POLDEL_LABEL (0x00000005) #define TSS_TSPATTRIB_POLDEL_FAMILYID (0x00000006) #define TSS_TSPATTRIB_POLDEL_VERCOUNT (0x00000007) #define TSS_TSPATTRIB_POLDEL_OWNERBLOB (0x00000008) #define TSS_TSPATTRIB_POLDEL_KEYBLOB (0x00000009) // // Subflags of TSS_TSPATTRIB_POLICY_DELEGATION_PCR // #define TSS_TSPATTRIB_POLDELPCR_LOCALITY (0x00000001) #define TSS_TSPATTRIB_POLDELPCR_DIGESTATRELEASE (0x00000002) #define TSS_TSPATTRIB_POLDELPCR_SELECTION (0x00000003) // // Values for the Policy TSS_TSPATTRIB_POLDEL_TYPE attribute // #define TSS_DELEGATIONTYPE_NONE (0x00000001) #define TSS_DELEGATIONTYPE_OWNER (0x00000002) #define TSS_DELEGATIONTYPE_KEY (0x00000003) // // Flags used for the 'mode' parameter in Tspi_Policy_SetSecret() // #define TSS_SECRET_MODE_NONE (0x00000800) // No authorization will be // processed #define TSS_SECRET_MODE_SHA1 (0x00001000) // Secret string will not be // touched by TSP #define TSS_SECRET_MODE_PLAIN (0x00001800) // Secret string will be hashed // using SHA1 #define TSS_SECRET_MODE_POPUP (0x00002000) // TSS SP will ask for a secret #define TSS_SECRET_MODE_CALLBACK (0x00002800) // Application has to provide a // call back function //****************** // EncData object: * //****************** // // Attributes // #define TSS_TSPATTRIB_ENCDATA_BLOB (0x00000008) #define TSS_TSPATTRIB_ENCDATA_PCR (0x00000010) #define TSS_TSPATTRIB_ENCDATA_PCR_LONG (0x00000018) #define TSS_TSPATTRIB_ENCDATA_SEAL (0x00000020) // // SubFlags for Flag TSS_TSPATTRIB_ENCDATA_BLOB // #define TSS_TSPATTRIB_ENCDATABLOB_BLOB (0x00000001) // encrypted data blob // // SubFlags for Flag TSS_TSPATTRIB_ENCDATA_PCR // #define TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATCREATION (0x00000002) #define TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATRELEASE (0x00000003) #define TSS_TSPATTRIB_ENCDATAPCR_SELECTION (0x00000004) // support typo from 1.1 headers #define TSS_TSPATTRIB_ENCDATAPCR_DIGEST_RELEASE \ TSS_TSPATTRIB_ENCDATAPCR_DIGEST_ATRELEASE #define TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATCREATION (0x00000005) #define TSS_TSPATTRIB_ENCDATAPCRLONG_LOCALITY_ATRELEASE (0x00000006) #define TSS_TSPATTRIB_ENCDATAPCRLONG_CREATION_SELECTION (0x00000007) #define TSS_TSPATTRIB_ENCDATAPCRLONG_RELEASE_SELECTION (0x00000008) #define TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATCREATION (0x00000009) #define TSS_TSPATTRIB_ENCDATAPCRLONG_DIGEST_ATRELEASE (0x0000000A) // // Attribute subflags TSS_TSPATTRIB_ENCDATA_SEAL // #define TSS_TSPATTRIB_ENCDATASEAL_PROTECT_MODE (0x00000001) // // Attribute values for // TSS_TSPATTRIB_ENCDATA_SEAL/TSS_TSPATTRIB_ENCDATASEAL_PROTECT_MODE // #define TSS_TSPATTRIB_ENCDATASEAL_NOPROTECT (0x00000000) #define TSS_TSPATTRIB_ENCDATASEAL_PROTECT (0x00000001) // Accounting for typos in original header files #define TSS_TSPATTRIB_ENCDATASEAL_NO_PROTECT \ TSS_TSPATTRIB_ENCDATASEAL_NOPROTECT //************* // NV object: * //************* // // Attributes // #define TSS_TSPATTRIB_NV_INDEX (0x00000001) #define TSS_TSPATTRIB_NV_PERMISSIONS (0x00000002) #define TSS_TSPATTRIB_NV_STATE (0x00000003) #define TSS_TSPATTRIB_NV_DATASIZE (0x00000004) #define TSS_TSPATTRIB_NV_PCR (0x00000005) #define TSS_TSPATTRIB_NVSTATE_READSTCLEAR (0x00100000) #define TSS_TSPATTRIB_NVSTATE_WRITESTCLEAR (0x00200000) #define TSS_TSPATTRIB_NVSTATE_WRITEDEFINE (0x00300000) #define TSS_TSPATTRIB_NVPCR_READPCRSELECTION (0x01000000) #define TSS_TSPATTRIB_NVPCR_READDIGESTATRELEASE (0x02000000) #define TSS_TSPATTRIB_NVPCR_READLOCALITYATRELEASE (0x03000000) #define TSS_TSPATTRIB_NVPCR_WRITEPCRSELECTION (0x04000000) #define TSS_TSPATTRIB_NVPCR_WRITEDIGESTATRELEASE (0x05000000) #define TSS_TSPATTRIB_NVPCR_WRITELOCALITYATRELEASE (0x06000000) /* NV index flags * * From the TPM spec, Part 2, Section 19.1. * * 3 2 1 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |T|P|U|D| resvd | Purview | Index | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ #define TSS_NV_TPM (0x80000000) // TPM mfr reserved bit #define TSS_NV_PLATFORM (0x40000000) // Platform mfr reserved bit #define TSS_NV_USER (0x20000000) // User reserved bit #define TSS_NV_DEFINED (0x10000000) // "Defined permanently" flag #define TSS_NV_MASK_TPM (0x80000000) // mask to extract 'T' #define TSS_NV_MASK_PLATFORM (0x40000000) // mask to extract 'P' #define TSS_NV_MASK_USER (0x20000000) // mask to extract 'U' #define TSS_NV_MASK_DEFINED (0x10000000) // mask to extract 'D' #define TSS_NV_MASK_RESERVED (0x0f000000) // mask to extract reserved bits #define TSS_NV_MASK_PURVIEW (0x00ff0000) // mask to extract purview byte #define TSS_NV_MASK_INDEX (0x0000ffff) // mask to extract index byte // This is the index of the NV storage area where the number of sessions // per locality is stored. #define TSS_NV_INDEX_SESSIONS (0x00011101) //****************** // MigData object: * //****************** // // Attributes // #define TSS_MIGATTRIB_MIGRATIONBLOB (0x00000010) #define TSS_MIGATTRIB_MIGRATIONTICKET (0x00000020) #define TSS_MIGATTRIB_AUTHORITY_DATA (0x00000030) #define TSS_MIGATTRIB_MIG_AUTH_DATA (0x00000040) #define TSS_MIGATTRIB_TICKET_DATA (0x00000050) #define TSS_MIGATTRIB_PAYLOAD_TYPE (0x00000060) // // Attribute subflags TSS_MIGATTRIB_MIGRATIONBLOB // #define TSS_MIGATTRIB_MIGRATION_XOR_BLOB (0x00000101) #define TSS_MIGATTRIB_MIGRATION_REWRAPPED_BLOB (0x00000102) #define TSS_MIGATTRIB_MIG_MSALIST_PUBKEY_BLOB (0x00000103) #define TSS_MIGATTRIB_MIG_AUTHORITY_PUBKEY_BLOB (0x00000104) #define TSS_MIGATTRIB_MIG_DESTINATION_PUBKEY_BLOB (0x00000105) #define TSS_MIGATTRIB_MIG_SOURCE_PUBKEY_BLOB (0x00000106) #define TSS_MIGATTRIB_MIG_REWRAPPED_BLOB TSS_MIGATTRIB_MIGRATION_REWRAPPED_BLOB #define TSS_MIGATTRIB_MIG_XOR_BLOB TSS_MIGATTRIB_MIGRATION_XOR_BLOB // // Attribute subflags TSS_MIGATTRIB_MIGRATIONTICKET // // none // // Attribute subflags TSS_MIGATTRIB_AUTHORITY_DATA // #define TSS_MIGATTRIB_AUTHORITY_DIGEST (0x00000301) #define TSS_MIGATTRIB_AUTHORITY_APPROVAL_HMAC (0x00000302) #define TSS_MIGATTRIB_AUTHORITY_MSALIST (0x00000303) // // Attribute subflags TSS_MIGATTRIB_MIG_AUTH_DATA // #define TSS_MIGATTRIB_MIG_AUTH_AUTHORITY_DIGEST (0x00000401) #define TSS_MIGATTRIB_MIG_AUTH_DESTINATION_DIGEST (0x00000402) #define TSS_MIGATTRIB_MIG_AUTH_SOURCE_DIGEST (0x00000403) // // Attribute subflags TSS_MIGATTRIB_TICKET_DATA // #define TSS_MIGATTRIB_TICKET_SIG_DIGEST (0x00000501) #define TSS_MIGATTRIB_TICKET_SIG_VALUE (0x00000502) #define TSS_MIGATTRIB_TICKET_SIG_TICKET (0x00000503) #define TSS_MIGATTRIB_TICKET_RESTRICT_TICKET (0x00000504) // // Attribute subflags TSS_MIGATTRIB_PAYLOAD_TYPE // #define TSS_MIGATTRIB_PT_MIGRATE_RESTRICTED (0x00000601) #define TSS_MIGATTRIB_PT_MIGRATE_EXTERNAL (0x00000602) //*************** // Hash object: * //*************** // // Attributes // #define TSS_TSPATTRIB_HASH_IDENTIFIER (0x00001000) // Hash algorithm identifier #define TSS_TSPATTRIB_ALG_IDENTIFIER (0x00002000) // ASN.1 alg identifier //*************** // PCRs object: * //*************** // // Attributes // #define TSS_TSPATTRIB_PCRS_INFO (0x00000001) // info // // Subflags for TSS_TSPATTRIB_PCRS_INFO flag // #define TSS_TSPATTRIB_PCRSINFO_PCRSTRUCT (0x00000001) // type of pcr struct // TSS_PCRS_STRUCT_TYPE_XX //**************************** // Delegation Family object: * //**************************** // // Attributes // #define TSS_TSPATTRIB_DELFAMILY_STATE (0x00000001) #define TSS_TSPATTRIB_DELFAMILY_INFO (0x00000002) // DELFAMILY_STATE sub-attributes #define TSS_TSPATTRIB_DELFAMILYSTATE_LOCKED (0x00000001) #define TSS_TSPATTRIB_DELFAMILYSTATE_ENABLED (0x00000002) // DELFAMILY_INFO sub-attributes #define TSS_TSPATTRIB_DELFAMILYINFO_LABEL (0x00000003) #define TSS_TSPATTRIB_DELFAMILYINFO_VERCOUNT (0x00000004) #define TSS_TSPATTRIB_DELFAMILYINFO_FAMILYID (0x00000005) // Bitmasks for the 'ulFlags' argument to Tspi_TPM_Delegate_CreateDelegation. // Only one bit used for now. #define TSS_DELEGATE_INCREMENTVERIFICATIONCOUNT ((UINT32)1) // Bitmasks for the 'ulFlags' argument to // Tspi_TPM_Delegate_CacheOwnerDelegation. Only 1 bit is used for now. #define TSS_DELEGATE_CACHEOWNERDELEGATION_OVERWRITEEXISTING ((UINT32)1) //************************* // DAA Credential Object: * //************************* // // Attribute flags // #define TSS_TSPATTRIB_DAACRED_COMMIT (0x00000001) #define TSS_TSPATTRIB_DAACRED_ATTRIB_GAMMAS (0x00000002) #define TSS_TSPATTRIB_DAACRED_CREDENTIAL_BLOB (0x00000003) #define TSS_TSPATTRIB_DAACRED_CALLBACK_SIGN (0x00000004) #define TSS_TSPATTRIB_DAACRED_CALLBACK_VERIFYSIGNATURE (0x00000005) // // Subflags for TSS_TSPATTRIB_DAACRED_COMMIT // #define TSS_TSPATTRIB_DAACOMMIT_NUMBER (0x00000001) #define TSS_TSPATTRIB_DAACOMMIT_SELECTION (0x00000002) #define TSS_TSPATTRIB_DAACOMMIT_COMMITMENTS (0x00000003) // // Subflags for TSS_TSPATTRIB_DAACRED_ATTRIB_GAMMAS // #define TSS_TSPATTRIB_DAAATTRIBGAMMAS_BLOB (0xffffffff) //************************* // DAA Issuer Key Object: * //************************* // // Attribute flags // #define TSS_TSPATTRIB_DAAISSUERKEY_BLOB (0x00000001) #define TSS_TSPATTRIB_DAAISSUERKEY_PUBKEY (0x00000002) // // Subflags for TSS_TSPATTRIB_DAAISSUERKEY_BLOB // #define TSS_TSPATTRIB_DAAISSUERKEYBLOB_PUBLIC_KEY (0x00000001) #define TSS_TSPATTRIB_DAAISSUERKEYBLOB_SECRET_KEY (0x00000002) #define TSS_TSPATTRIB_DAAISSUERKEYBLOB_KEYBLOB (0x00000003) #define TSS_TSPATTRIB_DAAISSUERKEYBLOB_PROOF (0x00000004) // // Subflags for TSS_TSPATTRIB_DAAISSUERKEY_PUBKEY // #define TSS_TSPATTRIB_DAAISSUERKEYPUBKEY_NUM_ATTRIBS (0x00000001) #define TSS_TSPATTRIB_DAAISSUERKEYPUBKEY_NUM_PLATFORM_ATTRIBS (0x00000002) #define TSS_TSPATTRIB_DAAISSUERKEYPUBKEY_NUM_ISSUER_ATTRIBS (0x00000003) //*************************************** // DAA Anonymity Revocation Key Object: * //*************************************** // // Attribute flags // #define TSS_TSPATTRIB_DAAARAKEY_BLOB (0x00000001) // // Subflags for TSS_TSPATTRIB_DAAARAKEY_BLOB // #define TSS_TSPATTRIB_DAAARAKEYBLOB_PUBLIC_KEY (0x00000001) #define TSS_TSPATTRIB_DAAARAKEYBLOB_SECRET_KEY (0x00000002) #define TSS_TSPATTRIB_DAAARAKEYBLOB_KEYBLOB (0x00000003) // // Structure payload flags for TSS_DAA_PSEUDONYM, // (TSS_DAA_PSEUDONYM.payloadFlag) // #define TSS_FLAG_DAA_PSEUDONYM_PLAIN (0x00000000) #define TSS_FLAG_DAA_PSEUDONYM_ENCRYPTED (0x00000001) //************** // Key Object: * //************** // // Attribute flags // #define TSS_TSPATTRIB_KEY_BLOB (0x00000040) // key info as blob data #define TSS_TSPATTRIB_KEY_INFO (0x00000080) // keyparam info as blob data #define TSS_TSPATTRIB_KEY_UUID (0x000000C0) // key UUID info as blob data #define TSS_TSPATTRIB_KEY_PCR (0x00000100) // composite digest value for // the key #define TSS_TSPATTRIB_RSAKEY_INFO (0x00000140) // public key info #define TSS_TSPATTRIB_KEY_REGISTER (0x00000180) // register location #define TSS_TSPATTRIB_KEY_PCR_LONG (0x000001c0) // PCR_INFO_LONG for the key #define TSS_TSPATTRIB_KEY_CONTROLBIT (0x00000200) // key control flags #define TSS_TSPATTRIB_KEY_CMKINFO (0x00000400) // CMK info // // SubFlags for Flag TSS_TSPATTRIB_KEY_BLOB // #define TSS_TSPATTRIB_KEYBLOB_BLOB (0x00000008) // key info using the // key blob #define TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY (0x00000010) // public key info // using the blob #define TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY (0x00000028) // encrypted private key // blob // // SubFlags for Flag TSS_TSPATTRIB_KEY_INFO // #define TSS_TSPATTRIB_KEYINFO_SIZE (0x00000080) // key size in bits #define TSS_TSPATTRIB_KEYINFO_USAGE (0x00000100) // key usage info #define TSS_TSPATTRIB_KEYINFO_KEYFLAGS (0x00000180) // key flags #define TSS_TSPATTRIB_KEYINFO_AUTHUSAGE (0x00000200) // key auth usage info #define TSS_TSPATTRIB_KEYINFO_ALGORITHM (0x00000280) // key algorithm ID #define TSS_TSPATTRIB_KEYINFO_SIGSCHEME (0x00000300) // key sig scheme #define TSS_TSPATTRIB_KEYINFO_ENCSCHEME (0x00000380) // key enc scheme #define TSS_TSPATTRIB_KEYINFO_MIGRATABLE (0x00000400) // if true then key is // migratable #define TSS_TSPATTRIB_KEYINFO_REDIRECTED (0x00000480) // key is redirected #define TSS_TSPATTRIB_KEYINFO_VOLATILE (0x00000500) // if true key is // volatile #define TSS_TSPATTRIB_KEYINFO_AUTHDATAUSAGE (0x00000580) // if true auth is // required #define TSS_TSPATTRIB_KEYINFO_VERSION (0x00000600) // version info as TSS // version struct #define TSS_TSPATTRIB_KEYINFO_CMK (0x00000680) // if true then key // is certified // migratable #define TSS_TSPATTRIB_KEYINFO_KEYSTRUCT (0x00000700) // type of key struct // used for this key // (TPM_KEY or // TPM_KEY12) #define TSS_TSPATTRIB_KEYCONTROL_OWNEREVICT (0x00000780) // Get current status // of owner evict flag // // SubFlags for Flag TSS_TSPATTRIB_RSAKEY_INFO // #define TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT (0x00001000) #define TSS_TSPATTRIB_KEYINFO_RSA_MODULUS (0x00002000) #define TSS_TSPATTRIB_KEYINFO_RSA_KEYSIZE (0x00003000) #define TSS_TSPATTRIB_KEYINFO_RSA_PRIMES (0x00004000) // // SubFlags for Flag TSS_TSPATTRIB_KEY_PCR // #define TSS_TSPATTRIB_KEYPCR_DIGEST_ATCREATION (0x00008000) #define TSS_TSPATTRIB_KEYPCR_DIGEST_ATRELEASE (0x00010000) #define TSS_TSPATTRIB_KEYPCR_SELECTION (0x00018000) // // SubFlags for TSS_TSPATTRIB_KEY_REGISTER // #define TSS_TSPATTRIB_KEYREGISTER_USER (0x02000000) #define TSS_TSPATTRIB_KEYREGISTER_SYSTEM (0x04000000) #define TSS_TSPATTRIB_KEYREGISTER_NO (0x06000000) // // SubFlags for Flag TSS_TSPATTRIB_KEY_PCR_LONG // #define TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATCREATION (0x00040000) /* UINT32 */ #define TSS_TSPATTRIB_KEYPCRLONG_LOCALITY_ATRELEASE (0x00080000) /* UINT32 */ #define TSS_TSPATTRIB_KEYPCRLONG_CREATION_SELECTION (0x000C0000) /* DATA */ #define TSS_TSPATTRIB_KEYPCRLONG_RELEASE_SELECTION (0x00100000) /* DATA */ #define TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATCREATION (0x00140000) /* DATA */ #define TSS_TSPATTRIB_KEYPCRLONG_DIGEST_ATRELEASE (0x00180000) /* DATA */ // // SubFlags for Flag TSS_TSPATTRIB_KEY_CMKINFO // #define TSS_TSPATTRIB_KEYINFO_CMK_MA_APPROVAL (0x00000010) #define TSS_TSPATTRIB_KEYINFO_CMK_MA_DIGEST (0x00000020) // // Attribute Values // // // key size definitions // #define TSS_KEY_SIZEVAL_512BIT (0x0200) #define TSS_KEY_SIZEVAL_1024BIT (0x0400) #define TSS_KEY_SIZEVAL_2048BIT (0x0800) #define TSS_KEY_SIZEVAL_4096BIT (0x1000) #define TSS_KEY_SIZEVAL_8192BIT (0x2000) #define TSS_KEY_SIZEVAL_16384BIT (0x4000) // // key usage definitions // Values intentionally moved away from corresponding TPM values to avoid // possible misuse // #define TSS_KEYUSAGE_BIND (0x00) #define TSS_KEYUSAGE_IDENTITY (0x01) #define TSS_KEYUSAGE_LEGACY (0x02) #define TSS_KEYUSAGE_SIGN (0x03) #define TSS_KEYUSAGE_STORAGE (0x04) #define TSS_KEYUSAGE_AUTHCHANGE (0x05) #define TSS_KEYUSAGE_MIGRATE (0x06) // // key flag definitions // #define TSS_KEYFLAG_REDIRECTION (0x00000001) #define TSS_KEYFLAG_MIGRATABLE (0x00000002) #define TSS_KEYFLAG_VOLATILEKEY (0x00000004) #define TSS_KEYFLAG_CERTIFIED_MIGRATABLE (0x00000008) // // algorithm ID definitions // // This table defines the algo id's // Values intentionally moved away from corresponding TPM values to avoid // possible misuse // #define TSS_ALG_RSA (0x20) #define TSS_ALG_DES (0x21) #define TSS_ALG_3DES (0x22) #define TSS_ALG_SHA (0x23) #define TSS_ALG_HMAC (0x24) #define TSS_ALG_AES128 (0x25) #define TSS_ALG_AES192 (0x26) #define TSS_ALG_AES256 (0x27) #define TSS_ALG_XOR (0x28) #define TSS_ALG_MGF1 (0x29) #define TSS_ALG_AES TSS_ALG_AES128 // Special values for // Tspi_Context_GetCapability(TSS_TSPCAP_ALG) // Tspi_Context_GetCapability(TSS_TCSCAP_ALG) #define TSS_ALG_DEFAULT (0xfe) #define TSS_ALG_DEFAULT_SIZE (0xff) // // key signature scheme definitions // #define TSS_SS_NONE (0x10) #define TSS_SS_RSASSAPKCS1V15_SHA1 (0x11) #define TSS_SS_RSASSAPKCS1V15_DER (0x12) #define TSS_SS_RSASSAPKCS1V15_INFO (0x13) // // key encryption scheme definitions // #define TSS_ES_NONE (0x10) #define TSS_ES_RSAESPKCSV15 (0x11) #define TSS_ES_RSAESOAEP_SHA1_MGF1 (0x12) #define TSS_ES_SYM_CNT (0x13) #define TSS_ES_SYM_OFB (0x14) #define TSS_ES_SYM_CBC_PKCS5PAD (0x15) // // persistent storage registration definitions // #define TSS_PS_TYPE_USER (1) // Key is registered persistantly in the user // storage database. #define TSS_PS_TYPE_SYSTEM (2) // Key is registered persistantly in the system // storage database. // // migration scheme definitions // Values intentionally moved away from corresponding TPM values to avoid // possible misuse // #define TSS_MS_MIGRATE (0x20) #define TSS_MS_REWRAP (0x21) #define TSS_MS_MAINT (0x22) #define TSS_MS_RESTRICT_MIGRATE (0x23) #define TSS_MS_RESTRICT_APPROVE_DOUBLE (0x24) #define TSS_MS_RESTRICT_MIGRATE_EXTERNAL (0x25) // // TPM key authorization // Values intentionally moved away from corresponding TPM values to avoid // possible misuse // #define TSS_KEYAUTH_AUTH_NEVER (0x10) #define TSS_KEYAUTH_AUTH_ALWAYS (0x11) #define TSS_KEYAUTH_AUTH_PRIV_USE_ONLY (0x12) // // Flags for TPM status information (GetStatus and SetStatus) // #define TSS_TPMSTATUS_DISABLEOWNERCLEAR (0x00000001) // persistent flag #define TSS_TPMSTATUS_DISABLEFORCECLEAR (0x00000002) // volatile flag #define TSS_TPMSTATUS_DISABLED (0x00000003) // persistent flag #define TSS_TPMSTATUS_DEACTIVATED (0x00000004) // volatile flag #define TSS_TPMSTATUS_OWNERSETDISABLE (0x00000005) // persistent flag // for SetStatus // (disable flag) #define TSS_TPMSTATUS_SETOWNERINSTALL (0x00000006) // persistent flag // (ownership flag) #define TSS_TPMSTATUS_DISABLEPUBEKREAD (0x00000007) // persistent flag #define TSS_TPMSTATUS_ALLOWMAINTENANCE (0x00000008) // persistent flag #define TSS_TPMSTATUS_PHYSPRES_LIFETIMELOCK (0x00000009) // persistent flag #define TSS_TPMSTATUS_PHYSPRES_HWENABLE (0x0000000A) // persistent flag #define TSS_TPMSTATUS_PHYSPRES_CMDENABLE (0x0000000B) // persistent flag #define TSS_TPMSTATUS_PHYSPRES_LOCK (0x0000000C) // volatile flag #define TSS_TPMSTATUS_PHYSPRESENCE (0x0000000D) // volatile flag #define TSS_TPMSTATUS_PHYSICALDISABLE (0x0000000E) // persistent flag // (SetStatus // disable flag) #define TSS_TPMSTATUS_CEKP_USED (0x0000000F) // persistent flag #define TSS_TPMSTATUS_PHYSICALSETDEACTIVATED (0x00000010) // persistent flag // (deactivated flag) #define TSS_TPMSTATUS_SETTEMPDEACTIVATED (0x00000011) // volatile flag // (deactivated flag) #define TSS_TPMSTATUS_POSTINITIALISE (0x00000012) // volatile flag #define TSS_TPMSTATUS_TPMPOST (0x00000013) // persistent flag #define TSS_TPMSTATUS_TPMPOSTLOCK (0x00000014) // persistent flag #define TSS_TPMSTATUS_DISABLEPUBSRKREAD (0x00000016) // persistent flag #define TSS_TPMSTATUS_MAINTENANCEUSED (0x00000017) // persistent flag #define TSS_TPMSTATUS_OPERATORINSTALLED (0x00000018) // persistent flag #define TSS_TPMSTATUS_OPERATOR_INSTALLED (TSS_TPMSTATUS_OPERATORINSTALLED) #define TSS_TPMSTATUS_FIPS (0x00000019) // persistent flag #define TSS_TPMSTATUS_ENABLEREVOKEEK (0x0000001A) // persistent flag #define TSS_TPMSTATUS_ENABLE_REVOKEEK (TSS_TPMSTATUS_ENABLEREVOKEEK) #define TSS_TPMSTATUS_NV_LOCK (0x0000001B) // persistent flag #define TSS_TPMSTATUS_TPM_ESTABLISHED (0x0000001C) // persistent flag #define TSS_TPMSTATUS_RESETLOCK (0x0000001D) // volatile flag #define TSS_TPMSTATUS_DISABLE_FULL_DA_LOGIC_INFO (0x0000001D) //persistent flag // // Capability flag definitions // // TPM capabilities // #define TSS_TPMCAP_ORD (0x10) #define TSS_TPMCAP_ALG (0x11) #define TSS_TPMCAP_FLAG (0x12) #define TSS_TPMCAP_PROPERTY (0x13) #define TSS_TPMCAP_VERSION (0x14) #define TSS_TPMCAP_VERSION_VAL (0x15) #define TSS_TPMCAP_NV_LIST (0x16) #define TSS_TPMCAP_NV_INDEX (0x17) #define TSS_TPMCAP_MFR (0x18) #define TSS_TPMCAP_SYM_MODE (0x19) #define TSS_TPMCAP_HANDLE (0x1a) #define TSS_TPMCAP_TRANS_ES (0x1b) #define TSS_TPMCAP_AUTH_ENCRYPT (0x1c) #define TSS_TPMCAP_SET_PERM_FLAGS (0x1d) // cf. TPM_SET_PERM_FLAGS #define TSS_TPMCAP_SET_VENDOR (0x1e) // cf. TPM_SET_VENDOR #define TSS_TPMCAP_DA_LOGIC (0x1f) // // Sub-Capability Flags for TSS_TPMCAP_PROPERTY // #define TSS_TPMCAP_PROP_PCR (0x10) #define TSS_TPMCAP_PROP_DIR (0x11) #define TSS_TPMCAP_PROP_MANUFACTURER (0x12) #define TSS_TPMCAP_PROP_SLOTS (0x13) #define TSS_TPMCAP_PROP_KEYS TSS_TPMCAP_PROP_SLOTS #define TSS_TPMCAP_PROP_FAMILYROWS (0x14) #define TSS_TPMCAP_PROP_DELEGATEROWS (0x15) #define TSS_TPMCAP_PROP_OWNER (0x16) #define TSS_TPMCAP_PROP_MAXKEYS (0x18) #define TSS_TPMCAP_PROP_AUTHSESSIONS (0x19) #define TSS_TPMCAP_PROP_MAXAUTHSESSIONS (0x1a) #define TSS_TPMCAP_PROP_TRANSESSIONS (0x1b) #define TSS_TPMCAP_PROP_MAXTRANSESSIONS (0x1c) #define TSS_TPMCAP_PROP_SESSIONS (0x1d) #define TSS_TPMCAP_PROP_MAXSESSIONS (0x1e) #define TSS_TPMCAP_PROP_CONTEXTS (0x1f) #define TSS_TPMCAP_PROP_MAXCONTEXTS (0x20) #define TSS_TPMCAP_PROP_DAASESSIONS (0x21) #define TSS_TPMCAP_PROP_MAXDAASESSIONS (0x22) #define TSS_TPMCAP_PROP_DAA_INTERRUPT (0x23) #define TSS_TPMCAP_PROP_COUNTERS (0x24) #define TSS_TPMCAP_PROP_MAXCOUNTERS (0x25) #define TSS_TPMCAP_PROP_ACTIVECOUNTER (0x26) #define TSS_TPMCAP_PROP_MIN_COUNTER (0x27) #define TSS_TPMCAP_PROP_TISTIMEOUTS (0x28) #define TSS_TPMCAP_PROP_STARTUPEFFECTS (0x29) #define TSS_TPMCAP_PROP_MAXCONTEXTCOUNTDIST (0x2a) #define TSS_TPMCAP_PROP_CMKRESTRICTION (0x2b) #define TSS_TPMCAP_PROP_DURATION (0x2c) #define TSS_TPMCAP_PROP_MAXNVAVAILABLE (0x2d) #define TSS_TPMCAP_PROP_INPUTBUFFERSIZE (0x2e) #define TSS_TPMCAP_PROP_REVISION (0x2f) #define TSS_TPMCAP_PROP_LOCALITIES_AVAIL (0x32) // // Resource type flags // Sub-Capability Flags for TSS_TPMCAP_HANDLE // #define TSS_RT_KEY ((UINT32)0x00000010) #define TSS_RT_AUTH ((UINT32)0x00000020) #define TSS_RT_TRANS ((UINT32)0x00000030) #define TSS_RT_COUNTER ((UINT32)0x00000040) // // TSS Core Service Capabilities // #define TSS_TCSCAP_ALG (0x00000001) #define TSS_TCSCAP_VERSION (0x00000002) #define TSS_TCSCAP_CACHING (0x00000003) #define TSS_TCSCAP_PERSSTORAGE (0x00000004) #define TSS_TCSCAP_MANUFACTURER (0x00000005) #define TSS_TCSCAP_PLATFORM_CLASS (0x00000006) #define TSS_TCSCAP_TRANSPORT (0x00000007) #define TSS_TCSCAP_PLATFORM_INFO (0x00000008) // // Sub-Capability Flags TSS-CoreService-Capabilities // #define TSS_TCSCAP_PROP_KEYCACHE (0x00000100) #define TSS_TCSCAP_PROP_AUTHCACHE (0x00000101) #define TSS_TCSCAP_PROP_MANUFACTURER_STR (0x00000102) #define TSS_TCSCAP_PROP_MANUFACTURER_ID (0x00000103) #define TSS_TCSCAP_PLATFORM_VERSION (0x00001100) #define TSS_TCSCAP_PLATFORM_TYPE (0x00001101) #define TSS_TCSCAP_TRANS_EXCLUSIVE (0x00002100) #define TSS_TCSCAP_PROP_HOST_PLATFORM (0x00003001) #define TSS_TCSCAP_PROP_ALL_PLATFORMS (0x00003002) // // TSS Service Provider Capabilities // #define TSS_TSPCAP_ALG (0x00000010) #define TSS_TSPCAP_VERSION (0x00000011) #define TSS_TSPCAP_PERSSTORAGE (0x00000012) #define TSS_TSPCAP_MANUFACTURER (0x00000013) #define TSS_TSPCAP_RETURNVALUE_INFO (0x00000015) #define TSS_TSPCAP_PLATFORM_INFO (0x00000016) // Sub-Capability Flags for TSS_TSPCAP_MANUFACTURER // #define TSS_TSPCAP_PROP_MANUFACTURER_STR (0x00000102) #define TSS_TSPCAP_PROP_MANUFACTURER_ID (0x00000103) // Sub-Capability Flags for TSS_TSPCAP_PLATFORM_INFO // #define TSS_TSPCAP_PLATFORM_TYPE (0x00000201) #define TSS_TSPCAP_PLATFORM_VERSION (0x00000202) // Sub-Capability Flags for TSS_TSPCAP_RETURNVALUE_INFO // #define TSS_TSPCAP_PROP_RETURNVALUE_INFO (0x00000201) // // Event type definitions // #define TSS_EV_CODE_CERT (0x00000001) #define TSS_EV_CODE_NOCERT (0x00000002) #define TSS_EV_XML_CONFIG (0x00000003) #define TSS_EV_NO_ACTION (0x00000004) #define TSS_EV_SEPARATOR (0x00000005) #define TSS_EV_ACTION (0x00000006) #define TSS_EV_PLATFORM_SPECIFIC (0x00000007) // // TSP random number limits // #define TSS_TSPCAP_RANDOMLIMIT (0x00001000) // Errata: Missing from spec // // UUIDs // // Errata: This are not in the spec #define TSS_UUID_SRK {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 1}} // Storage root key #define TSS_UUID_SK {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 2}} // System key #define TSS_UUID_RK {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 3}} // roaming key #define TSS_UUID_CRK {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 8}} // CMK roaming key #define TSS_UUID_USK1 {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 4}} // user storage key 1 #define TSS_UUID_USK2 {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 5}} // user storage key 2 #define TSS_UUID_USK3 {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 6}} // user storage key 3 #define TSS_UUID_USK4 {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 7}} // user storage key 4 #define TSS_UUID_USK5 {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 9}} // user storage key 5 #define TSS_UUID_USK6 {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 10}}// user storage key 6 // macro to derive UUIDs for keys whose "OwnerEvict" key is set. #define TSS_UUID_OWNEREVICT(i) {0, 0, 0, 0, 0, {0, 0, 0, 0, 1, (i)}} // // TPM well-known secret // #define TSS_WELL_KNOWN_SECRET \ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // Values for the "direction" parameters in the Tspi_PcrComposite_XX functions. #define TSS_PCRS_DIRECTION_CREATION ((UINT32)1) #define TSS_PCRS_DIRECTION_RELEASE ((UINT32)2) // // TSS blob version definition for ASN.1 blobs // #define TSS_BLOB_STRUCT_VERSION 0x01 // // TSS blob type definitions for ASN.1 blobs // #define TSS_BLOB_TYPE_KEY 0x01 #define TSS_BLOB_TYPE_PUBKEY 0x02 #define TSS_BLOB_TYPE_MIGKEY 0x03 #define TSS_BLOB_TYPE_SEALEDDATA 0x04 #define TSS_BLOB_TYPE_BOUNDDATA 0x05 #define TSS_BLOB_TYPE_MIGTICKET 0x06 #define TSS_BLOB_TYPE_PRIVATEKEY 0x07 #define TSS_BLOB_TYPE_PRIVATEKEY_MOD1 0x08 #define TSS_BLOB_TYPE_RANDOM_XOR 0x09 #define TSS_BLOB_TYPE_CERTIFY_INFO 0x0A #define TSS_BLOB_TYPE_KEY_1_2 0x0B #define TSS_BLOB_TYPE_CERTIFY_INFO_2 0x0C #define TSS_BLOB_TYPE_CMK_MIG_KEY 0x0D #define TSS_BLOB_TYPE_CMK_BYTE_STREAM 0x0E // // Values for TPM_CMK_DELEGATE bitmasks // For now these are exactly the same values as the corresponding // TPM_CMK_DELEGATE_* bitmasks. // #define TSS_CMK_DELEGATE_SIGNING (((UINT32)1)<<31) #define TSS_CMK_DELEGATE_STORAGE (((UINT32)1)<<30) #define TSS_CMK_DELEGATE_BIND (((UINT32)1)<<29) #define TSS_CMK_DELEGATE_LEGACY (((UINT32)1)<<28) #define TSS_CMK_DELEGATE_MIGRATE (((UINT32)1)<<27) // // Constants for DAA // #define TSS_DAA_LENGTH_N 256 // Length of the RSA Modulus (2048 bits) #define TSS_DAA_LENGTH_F 13 // Length of the f_i's (information encoded into the certificate, 104 bits) #define TSS_DAA_LENGTH_E 46 // Length of the e's (exponents, part of certificate, 386 bits) #define TSS_DAA_LENGTH_E_PRIME 15 // Length of the interval the e's are chosen from (120 bits) #define TSS_DAA_LENGTH_V 317 // Length of the v's (random value, part of certificate, 2536 bits) #define TSS_DAA_LENGTH_SAFETY 10 // Length of the security parameter controlling the statistical zero-knowledge property (80 bits) #define TSS_DAA_LENGTH_HASH TPM_SHA1_160_HASH_LEN // Length of the output of the hash function SHA-1 used for the Fiat-Shamir heuristic(160 bits) #define TSS_DAA_LENGTH_S 128 // Length of the split large exponent for easier computations on the TPM (1024 bits) #define TSS_DAA_LENGTH_GAMMA 204 // Length of the modulus 'Gamma' (1632 bits) #define TSS_DAA_LENGTH_RHO 26 // Length of the order 'rho' of the sub group of Z*_Gamma that is used for roggue tagging (208 bits) #define TSS_DAA_LENGTH_MFG1_GAMMA 214 // Length of the output of MGF1 in conjunction with the modulus Gamma (1712 bits) #define TSS_DAA_LENGTH_MGF1_AR 25 // Length of the output of MGF1 used for anonymity revocation (200 bits) #endif // __TSS_DEFINES_H__ trousers-0.3.15/src/include/tss/tcs_error.h0000664000175000017510000000372213663651711020156 0ustar deboradebora/*++ TSS Core Service error return codes --*/ #ifndef __TCS_ERROR_H__ #define __TCS_ERROR_H__ #ifndef TSS_E_BASE #define TSS_E_BASE 0x00000000L #endif // TSS_E_BASE // The context handle supplied is invalid. #define TCS_E_INVALID_CONTEXTHANDLE (UINT32)(TSS_E_BASE + 0x0C1L) // The key handle supplied is invalid. #define TCS_E_INVALID_KEYHANDLE (UINT32)(TSS_E_BASE + 0x0C2L) // The authorization session handle supplied is invalid. #define TCS_E_INVALID_AUTHHANDLE (UINT32)(TSS_E_BASE + 0x0C3L) // the auth session has been closed by the TPM #define TCS_E_INVALID_AUTHSESSION (UINT32)(TSS_E_BASE + 0x0C4L) // the key has been unloaded #define TCS_E_INVALID_KEY (UINT32)(TSS_E_BASE + 0x0C5L) // Key addressed by the application key handle does not match the key addressed // by the given UUID. #define TCS_E_KEY_MISMATCH (UINT32)(TSS_E_BASE + 0x0C8L) // Key adressed by Key's UUID cannot be loaded because one of the required // parent keys needs authorization. #define TCS_E_KM_LOADFAILED (UINT32)(TSS_E_BASE + 0x0CAL) // The Key Cache Manager could not reload the key into the TPM. #define TCS_E_KEY_CONTEXT_RELOAD (UINT32)(TSS_E_BASE + 0x0CCL) // Bad memory index #define TCS_E_BAD_INDEX (UINT32)(TSS_E_BASE + 0x0CDL) // These TCS_E_ macros are defined by name in the TSS spec, however // they are defined to have the same values as the TSS_E_ equivalents. #define TCS_SUCCESS TSS_SUCCESS #define TCS_E_KEY_ALREADY_REGISTERED TSS_E_KEY_ALREADY_REGISTERED #define TCS_E_KEY_NOT_REGISTERED TSS_E_KEY_NOT_REGISTERED #define TCS_E_BAD_PARAMETER TSS_E_BAD_PARAMETER #define TCS_E_OUTOFMEMORY TSS_E_OUTOFMEMORY #define TCS_E_SIZE TSS_E_SIZE #define TCS_E_NOTIMPL TSS_E_NOTIMPL #define TCS_E_INTERNAL_ERROR TSS_E_INTERNAL_ERROR #endif // __TCS_ERROR_H__ trousers-0.3.15/src/include/tss/tcpa_defines.h0000664000175000017510000000020013663651711020564 0ustar deboradebora #ifndef __TCPA_DEFINES_H__ #define __TCPA_DEFINES_H__ #warning including deprecated header file tcpa_defines.h #endif trousers-0.3.15/src/include/tss/tpm_error.h0000664000175000017510000004716313663651711020174 0ustar deboradebora/* * The TPM error codes extracted from the TPM main specification * version 1.2 revision 85. */ #ifndef __TPM_ERROR_H__ #define __TPM_ERROR_H__ #ifndef TPM_E_BASE #define TPM_E_BASE ((UINT32)0) #endif #ifndef TPM_E_NON_FATAL #define TPM_E_NON_FATAL ((UINT32)0x00000800) #endif // Successful completion of the TPM operation. #define TPM_SUCCESS TPM_E_BASE // // MessageId: TPM_E_AUTHFAIL // // MessageText: // // Authentication failed // #define TPM_E_AUTHFAIL ((UINT32)(TPM_E_BASE + 0x00000001)) // // MessageId: TPM_E_BADINDEX // // MessageText: // // The index to a PCR, DIR or other register is incorrect // #define TPM_E_BADINDEX ((UINT32)(TPM_E_BASE + 0x00000002)) // // MessageId: TPM_E_BAD_PARAMETER // // MessageText: // // One or more parameter is bad // #define TPM_E_BAD_PARAMETER ((UINT32)(TPM_E_BASE + 0x00000003)) // // MessageId: TPM_E_AUDITFAILURE // // MessageText: // // An operation completed successfully but the auditing of that // operation failed. // #define TPM_E_AUDITFAILURE ((UINT32)(TPM_E_BASE + 0x00000004)) // // MessageId: TPM_E_CLEAR_DISABLED // // MessageText: // // The clear disable flag is set and all clear operations now require // physical access // #define TPM_E_CLEAR_DISABLED ((UINT32)(TPM_E_BASE + 0x00000005)) // // MessageId: TPM_E_DEACTIVATED // // MessageText: // // The TPM is deactivated // #define TPM_E_DEACTIVATED ((UINT32)(TPM_E_BASE + 0x00000006)) // // MessageId: TPM_E_DISABLED // // MessageText: // // The TPM is disabled // #define TPM_E_DISABLED ((UINT32)(TPM_E_BASE + 0x00000007)) // // MessageId: TPM_E_DISABLED_CMD // // MessageText: // // The target command has been disabled // #define TPM_E_DISABLED_CMD ((UINT32)(TPM_E_BASE + 0x00000008)) // // MessageId: TPM_E_FAIL // // MessageText: // // The operation failed // #define TPM_E_FAIL ((UINT32)(TPM_E_BASE + 0x00000009)) // // MessageId: TPM_E_BAD_ORDINAL // // MessageText: // // The ordinal was unknown or inconsistent // #define TPM_E_BAD_ORDINAL ((UINT32)(TPM_E_BASE + 0x0000000a)) // // MessageId: TPM_E_INSTALL_DISABLED // // MessageText: // // The ability to install an owner is disabled // #define TPM_E_INSTALL_DISABLED ((UINT32)(TPM_E_BASE + 0x0000000b)) // // MessageId: TPM_E_INVALID_KEYHANDLE // // MessageText: // // The key handle can not be interpreted // #define TPM_E_INVALID_KEYHANDLE ((UINT32)(TPM_E_BASE + 0x0000000c)) // // MessageId: TPM_E_KEYNOTFOUND // // MessageText: // // The key handle points to an invalid key // #define TPM_E_KEYNOTFOUND ((UINT32)(TPM_E_BASE + 0x0000000d)) // // MessageId: TPM_E_INAPPROPRIATE_ENC // // MessageText: // // Unacceptable encryption scheme // #define TPM_E_INAPPROPRIATE_ENC ((UINT32)(TPM_E_BASE + 0x0000000e)) // // MessageId: TPM_E_MIGRATEFAIL // // MessageText: // // Migration authorization failed // #define TPM_E_MIGRATEFAIL ((UINT32)(TPM_E_BASE + 0x0000000f)) // // MessageId: TPM_E_INVALID_PCR_INFO // // MessageText: // // PCR information could not be interpreted // #define TPM_E_INVALID_PCR_INFO ((UINT32)(TPM_E_BASE + 0x00000010)) // // MessageId: TPM_E_NOSPACE // // MessageText: // // No room to load key. // #define TPM_E_NOSPACE ((UINT32)(TPM_E_BASE + 0x00000011)) // // MessageId: TPM_E_NOSRK // // MessageText: // // There is no SRK set // #define TPM_E_NOSRK ((UINT32)(TPM_E_BASE + 0x00000012)) // // MessageId: TPM_E_NOTSEALED_BLOB // // MessageText: // // An encrypted blob is invalid or was not created by this TPM // #define TPM_E_NOTSEALED_BLOB ((UINT32)(TPM_E_BASE + 0x00000013)) // // MessageId: TPM_E_OWNER_SET // // MessageText: // // There is already an Owner // #define TPM_E_OWNER_SET ((UINT32)(TPM_E_BASE + 0x00000014)) // // MessageId: TPM_E_RESOURCES // // MessageText: // // The TPM has insufficient internal resources to perform the // requested action. // #define TPM_E_RESOURCES ((UINT32)(TPM_E_BASE + 0x00000015)) // // MessageId: TPM_E_SHORTRANDOM // // MessageText: // // A random string was too short // #define TPM_E_SHORTRANDOM ((UINT32)(TPM_E_BASE + 0x00000016)) // // MessageId: TPM_E_SIZE // // MessageText: // // The TPM does not have the space to perform the operation. // #define TPM_E_SIZE ((UINT32)(TPM_E_BASE + 0x00000017)) // // MessageId: TPM_E_WRONGPCRVAL // // MessageText: // // The named PCR value does not match the current PCR value. // #define TPM_E_WRONGPCRVAL ((UINT32)(TPM_E_BASE + 0x00000018)) // // MessageId: TPM_E_BAD_PARAM_SIZE // // MessageText: // // The paramSize argument to the command has the incorrect value // #define TPM_E_BAD_PARAM_SIZE ((UINT32)(TPM_E_BASE + 0x00000019)) // // MessageId: TPM_E_SHA_THREAD // // MessageText: // // There is no existing SHA-1 thread. // #define TPM_E_SHA_THREAD ((UINT32)(TPM_E_BASE + 0x0000001a)) // // MessageId: TPM_E_SHA_ERROR // // MessageText: // // The calculation is unable to proceed because the existing SHA-1 // thread has already encountered an error. // #define TPM_E_SHA_ERROR ((UINT32)(TPM_E_BASE + 0x0000001b)) // // MessageId: TPM_E_FAILEDSELFTEST // // MessageText: // // Self-test has failed and the TPM has shutdown. // #define TPM_E_FAILEDSELFTEST ((UINT32)(TPM_E_BASE + 0x0000001c)) // // MessageId: TPM_E_AUTH2FAIL // // MessageText: // // The authorization for the second key in a 2 key function failed // authorization // #define TPM_E_AUTH2FAIL ((UINT32)(TPM_E_BASE + 0x0000001d)) // // MessageId: TPM_E_BADTAG // // MessageText: // // The tag value sent to for a command is invalid // #define TPM_E_BADTAG ((UINT32)(TPM_E_BASE + 0x0000001e)) // // MessageId: TPM_E_IOERROR // // MessageText: // // An IO error occurred transmitting information to the TPM // #define TPM_E_IOERROR ((UINT32)(TPM_E_BASE + 0x0000001f)) // // MessageId: TPM_E_ENCRYPT_ERROR // // MessageText: // // The encryption process had a problem. // #define TPM_E_ENCRYPT_ERROR ((UINT32)(TPM_E_BASE + 0x00000020)) // // MessageId: TPM_E_DECRYPT_ERROR // // MessageText: // // The decryption process did not complete. // #define TPM_E_DECRYPT_ERROR ((UINT32)(TPM_E_BASE + 0x00000021)) // // MessageId: TPM_E_INVALID_AUTHHANDLE // // MessageText: // // An invalid handle was used. // #define TPM_E_INVALID_AUTHHANDLE ((UINT32)(TPM_E_BASE + 0x00000022)) // // MessageId: TPM_E_NO_ENDORSEMENT // // MessageText: // // The TPM does not a EK installed // #define TPM_E_NO_ENDORSEMENT ((UINT32)(TPM_E_BASE + 0x00000023)) // // MessageId: TPM_E_INVALID_KEYUSAGE // // MessageText: // // The usage of a key is not allowed // #define TPM_E_INVALID_KEYUSAGE ((UINT32)(TPM_E_BASE + 0x00000024)) // // MessageId: TPM_E_WRONG_ENTITYTYPE // // MessageText: // // The submitted entity type is not allowed // #define TPM_E_WRONG_ENTITYTYPE ((UINT32)(TPM_E_BASE + 0x00000025)) // // MessageId: TPM_E_INVALID_POSTINIT // // MessageText: // // The command was received in the wrong sequence relative to TPM_Init // and a subsequent TPM_Startup // #define TPM_E_INVALID_POSTINIT ((UINT32)(TPM_E_BASE + 0x00000026)) // // MessageId: TPM_E_INAPPROPRIATE_SIG // // MessageText: // // Signed data cannot include additional DER information // #define TPM_E_INAPPROPRIATE_SIG ((UINT32)(TPM_E_BASE + 0x00000027)) // // MessageId: TPM_E_BAD_KEY_PROPERTY // // MessageText: // // The key properties in TPM_KEY_PARMs are not supported by this TPM // #define TPM_E_BAD_KEY_PROPERTY ((UINT32)(TPM_E_BASE + 0x00000028)) // // MessageId: TPM_E_BAD_MIGRATION // // MessageText: // // The migration properties of this key are incorrect. // #define TPM_E_BAD_MIGRATION ((UINT32)(TPM_E_BASE + 0x00000029)) // // MessageId: TPM_E_BAD_SCHEME // // MessageText: // // The signature or encryption scheme for this key is incorrect or not // permitted in this situation. // #define TPM_E_BAD_SCHEME ((UINT32)(TPM_E_BASE + 0x0000002a)) // // MessageId: TPM_E_BAD_DATASIZE // // MessageText: // // The size of the data (or blob) parameter is bad or inconsistent // with the referenced key // #define TPM_E_BAD_DATASIZE ((UINT32)(TPM_E_BASE + 0x0000002b)) // // MessageId: TPM_E_BAD_MODE // // MessageText: // // A mode parameter is bad, such as capArea or subCapArea for // TPM_GetCapability, physicalPresence parameter for // TPM_PhysicalPresence, or migrationType for TPM_CreateMigrationBlob. // #define TPM_E_BAD_MODE ((UINT32)(TPM_E_BASE + 0x0000002c)) // // MessageId: TPM_E_BAD_PRESENCE // // MessageText: // // Either the physicalPresence or physicalPresenceLock bits have the // wrong value // #define TPM_E_BAD_PRESENCE ((UINT32)(TPM_E_BASE + 0x0000002d)) // // MessageId: TPM_E_BAD_VERSION // // MessageText: // // The TPM cannot perform this version of the capability // #define TPM_E_BAD_VERSION ((UINT32)(TPM_E_BASE + 0x0000002e)) // // MessageId: TPM_E_NO_WRAP_TRANSPORT // // MessageText: // // The TPM does not allow for wrapped transport sessions // #define TPM_E_NO_WRAP_TRANSPORT ((UINT32)(TPM_E_BASE + 0x0000002f)) // // MessageId: TPM_E_AUDITFAIL_UNSUCCESSFUL // // MessageText: // // TPM audit construction failed and the underlying command was // returning a failure code also // #define TPM_E_AUDITFAIL_UNSUCCESSFUL ((UINT32)(TPM_E_BASE + 0x00000030)) // // MessageId: TPM_E_AUDITFAIL_SUCCESSFUL // // MessageText: // // TPM audit construction failed and the underlying command was // returning success // #define TPM_E_AUDITFAIL_SUCCESSFUL ((UINT32)(TPM_E_BASE + 0x00000031)) // // MessageId: TPM_E_NOTRESETABLE // // MessageText: // // Attempt to reset a PCR register that does not have the resettable // attribute // #define TPM_E_NOTRESETABLE ((UINT32)(TPM_E_BASE + 0x00000032)) // // MessageId: TPM_E_NOTLOCAL // // MessageText: // // Attempt to reset a PCR register that requires locality and locality // modifier not part of command transport // #define TPM_E_NOTLOCAL ((UINT32)(TPM_E_BASE + 0x00000033)) // // MessageId: TPM_E_BAD_TYPE // // MessageText: // // Make identity blob not properly typed // #define TPM_E_BAD_TYPE ((UINT32)(TPM_E_BASE + 0x00000034)) // // MessageId: TPM_E_INVALID_RESOURCE // // MessageText: // // When saving context identified resource type does not match actual // resource // #define TPM_E_INVALID_RESOURCE ((UINT32)(TPM_E_BASE + 0x00000035)) // // MessageId: TPM_E_NOTFIPS // // MessageText: // // The TPM is attempting to execute a command only available when in // FIPS mode // #define TPM_E_NOTFIPS ((UINT32)(TPM_E_BASE + 0x00000036)) // // MessageId: TPM_E_INVALID_FAMILY // // MessageText: // // The command is attempting to use an invalid family ID // #define TPM_E_INVALID_FAMILY ((UINT32)(TPM_E_BASE + 0x00000037)) // // MessageId: TPM_E_NO_NV_PERMISSION // // MessageText: // // The permission to manipulate the NV storage is not available // #define TPM_E_NO_NV_PERMISSION ((UINT32)(TPM_E_BASE + 0x00000038)) // // MessageId: TPM_E_REQUIRES_SIGN // // MessageText: // // The operation requires a signed command // #define TPM_E_REQUIRES_SIGN ((UINT32)(TPM_E_BASE + 0x00000039)) // // MessageId: TPM_E_KEY_NOTSUPPORTED // // MessageText: // // Wrong operation to load an NV key // #define TPM_E_KEY_NOTSUPPORTED ((UINT32)(TPM_E_BASE + 0x0000003a)) // // MessageId: TPM_E_AUTH_CONFLICT // // MessageText: // // NV_LoadKey blob requires both owner and blob authorization // #define TPM_E_AUTH_CONFLICT ((UINT32)(TPM_E_BASE + 0x0000003b)) // // MessageId: TPM_E_AREA_LOCKED // // MessageText: // // The NV area is locked and not writable // #define TPM_E_AREA_LOCKED ((UINT32)(TPM_E_BASE + 0x0000003c)) // // MessageId: TPM_E_BAD_LOCALITY // // MessageText: // // The locality is incorrect for the attempted operation // #define TPM_E_BAD_LOCALITY ((UINT32)(TPM_E_BASE + 0x0000003d)) // // MessageId: TPM_E_READ_ONLY // // MessageText: // // The NV area is read only and can't be written to // #define TPM_E_READ_ONLY ((UINT32)(TPM_E_BASE + 0x0000003e)) // // MessageId: TPM_E_PER_NOWRITE // // MessageText: // // There is no protection on the write to the NV area // #define TPM_E_PER_NOWRITE ((UINT32)(TPM_E_BASE + 0x0000003f)) // // MessageId: TPM_E_FAMILYCOUNT // // MessageText: // // The family count value does not match // #define TPM_E_FAMILYCOUNT ((UINT32)(TPM_E_BASE + 0x00000040)) // // MessageId: TPM_E_WRITE_LOCKED // // MessageText: // // The NV area has already been written to // #define TPM_E_WRITE_LOCKED ((UINT32)(TPM_E_BASE + 0x00000041)) // // MessageId: TPM_E_BAD_ATTRIBUTES // // MessageText: // // The NV area attributes conflict // #define TPM_E_BAD_ATTRIBUTES ((UINT32)(TPM_E_BASE + 0x00000042)) // // MessageId: TPM_E_INVALID_STRUCTURE // // MessageText: // // The structure tag and version are invalid or inconsistent // #define TPM_E_INVALID_STRUCTURE ((UINT32)(TPM_E_BASE + 0x00000043)) // // MessageId: TPM_E_KEY_OWNER_CONTROL // // MessageText: // // The key is under control of the TPM Owner and can only be evicted // by the TPM Owner. // #define TPM_E_KEY_OWNER_CONTROL ((UINT32)(TPM_E_BASE + 0x00000044)) // // MessageId: TPM_E_BAD_COUNTER // // MessageText: // // The counter handle is incorrect // #define TPM_E_BAD_COUNTER ((UINT32)(TPM_E_BASE + 0x00000045)) // // MessageId: TPM_E_NOT_FULLWRITE // // MessageText: // // The write is not a complete write of the area // #define TPM_E_NOT_FULLWRITE ((UINT32)(TPM_E_BASE + 0x00000046)) // // MessageId: TPM_E_CONTEXT_GAP // // MessageText: // // The gap between saved context counts is too large // #define TPM_E_CONTEXT_GAP ((UINT32)(TPM_E_BASE + 0x00000047)) // // MessageId: TPM_E_MAXNVWRITES // // MessageText: // // The maximum number of NV writes without an owner has been exceeded // #define TPM_E_MAXNVWRITES ((UINT32)(TPM_E_BASE + 0x00000048)) // // MessageId: TPM_E_NOOPERATOR // // MessageText: // // No operator AuthData value is set // #define TPM_E_NOOPERATOR ((UINT32)(TPM_E_BASE + 0x00000049)) // // MessageId: TPM_E_RESOURCEMISSING // // MessageText: // // The resource pointed to by context is not loaded // #define TPM_E_RESOURCEMISSING ((UINT32)(TPM_E_BASE + 0x0000004a)) // // MessageId: TPM_E_DELEGATE_LOCK // // MessageText: // // The delegate administration is locked // #define TPM_E_DELEGATE_LOCK ((UINT32)(TPM_E_BASE + 0x0000004b)) // // MessageId: TPM_E_DELEGATE_FAMILY // // MessageText: // // Attempt to manage a family other then the delegated family // #define TPM_E_DELEGATE_FAMILY ((UINT32)(TPM_E_BASE + 0x0000004c)) // // MessageId: TPM_E_DELEGATE_ADMIN // // MessageText: // // Delegation table management not enabled // #define TPM_E_DELEGATE_ADMIN ((UINT32)(TPM_E_BASE + 0x0000004d)) // // MessageId: TPM_E_TRANSPORT_NOTEXCLUSIVE // // MessageText: // // There was a command executed outside of an exclusive transport session // #define TPM_E_TRANSPORT_NOTEXCLUSIVE ((UINT32)(TPM_E_BASE + 0x0000004e)) // // MessageId: TPM_E_OWNER_CONTROL // // MessageText: // // Attempt to context save a owner evict controlled key // #define TPM_E_OWNER_CONTROL ((UINT32)(TPM_E_BASE + 0x0000004f)) // // MessageId: TPM_E_DAA_RESOURCES // // MessageText: // // The DAA command has no resources available to execute the command // #define TPM_E_DAA_RESOURCES ((UINT32)(TPM_E_BASE + 0x00000050)) // // MessageId: TPM_E_DAA_INPUT_DATA0 // // MessageText: // // The consistency check on DAA parameter inputData0 has failed. // #define TPM_E_DAA_INPUT_DATA0 ((UINT32)(TPM_E_BASE + 0x00000051)) // // MessageId: TPM_E_DAA_INPUT_DATA1 // // MessageText: // // The consistency check on DAA parameter inputData1 has failed. // #define TPM_E_DAA_INPUT_DATA1 ((UINT32)(TPM_E_BASE + 0x00000052)) // // MessageId: TPM_E_DAA_ISSUER_SETTINGS // // MessageText: // // The consistency check on DAA_issuerSettings has failed. // #define TPM_E_DAA_ISSUER_SETTINGS ((UINT32)(TPM_E_BASE + 0x00000053)) // // MessageId: TPM_E_DAA_TPM_SETTINGS // // MessageText: // // The consistency check on DAA_tpmSpecific has failed. // #define TPM_E_DAA_TPM_SETTINGS ((UINT32)(TPM_E_BASE + 0x00000054)) // // MessageId: TPM_E_DAA_STAGE // // MessageText: // // The atomic process indicated by the submitted DAA command is not // the expected process. // #define TPM_E_DAA_STAGE ((UINT32)(TPM_E_BASE + 0x00000055)) // // MessageId: TPM_E_DAA_ISSUER_VALIDITY // // MessageText: // // The issuer's validity check has detected an inconsistency // #define TPM_E_DAA_ISSUER_VALIDITY ((UINT32)(TPM_E_BASE + 0x00000056)) // // MessageId: TPM_E_DAA_WRONG_W // // MessageText: // // The consistency check on w has failed. // #define TPM_E_DAA_WRONG_W ((UINT32)(TPM_E_BASE + 0x00000057)) // // MessageId: TPM_E_BAD_HANDLE // // MessageText: // // The handle is incorrect // #define TPM_E_BAD_HANDLE ((UINT32)(TPM_E_BASE + 0x00000058)) // // MessageId: TPM_E_BAD_DELEGATE // // MessageText: // // Delegation is not correct // #define TPM_E_BAD_DELEGATE ((UINT32)(TPM_E_BASE + 0x00000059)) // // MessageId: TPM_E_BADCONTEXT // // MessageText: // // The context blob is invalid // #define TPM_E_BADCONTEXT ((UINT32)(TPM_E_BASE + 0x0000005a)) // // MessageId: TPM_E_TOOMANYCONTEXTS // // MessageText: // // Too many contexts held by the TPM // #define TPM_E_TOOMANYCONTEXTS ((UINT32)(TPM_E_BASE + 0x0000005b)) // // MessageId: TPM_E_MA_TICKET_SIGNATURE // // MessageText: // // Migration authority signature validation failure // #define TPM_E_MA_TICKET_SIGNATURE ((UINT32)(TPM_E_BASE + 0x0000005c)) // // MessageId: TPM_E_MA_DESTINATION // // MessageText: // // Migration destination not authenticated // #define TPM_E_MA_DESTINATION ((UINT32)(TPM_E_BASE + 0x0000005d)) // // MessageId: TPM_E_MA_SOURCE // // MessageText: // // Migration source incorrect // #define TPM_E_MA_SOURCE ((UINT32)(TPM_E_BASE + 0x0000005e)) // // MessageId: TPM_E_MA_AUTHORITY // // MessageText: // // Incorrect migration authority // #define TPM_E_MA_AUTHORITY ((UINT32)(TPM_E_BASE + 0x0000005f)) // // MessageId: TPM_E_PERMANENTEK // // MessageText: // // Attempt to revoke the EK and the EK is not revocable // #define TPM_E_PERMANENTEK ((UINT32)(TPM_E_BASE + 0x00000061)) // // MessageId: TPM_E_BAD_SIGNATURE // // MessageText: // // Bad signature of CMK ticket // #define TPM_E_BAD_SIGNATURE ((UINT32)(TPM_E_BASE + 0x00000062)) // // MessageId: TPM_E_NOCONTEXTSPACE // // MessageText: // // There is no room in the context list for additional contexts // #define TPM_E_NOCONTEXTSPACE ((UINT32)(TPM_E_BASE + 0x00000063)) // // MessageId: TPM_E_RETRY // // MessageText: // // The TPM is too busy to respond to the command immediately, but the // command could be resubmitted at a later time. The TPM MAY return // TPM_Retry for any command at any time. // #define TPM_E_RETRY ((UINT32)(TPM_E_BASE + TPM_E_NON_FATAL)) // // MessageId: TPM_E_NEEDS_SELFTEST // // MessageText: // // SelfTestFull has not been run // #define TPM_E_NEEDS_SELFTEST ((UINT32)(TPM_E_BASE + TPM_E_NON_FATAL + 1)) // // MessageId: TPM_E_DOING_SELFTEST // // MessageText: // // The TPM is currently executing a full selftest // #define TPM_E_DOING_SELFTEST ((UINT32)(TPM_E_BASE + TPM_E_NON_FATAL + 2)) // // MessageId: TPM_E_DEFEND_LOCK_RUNNING // // MessageText: // // The TPM is defending against dictionary attacks and is in some // time-out period. // #define TPM_E_DEFEND_LOCK_RUNNING ((UINT32)(TPM_E_BASE + TPM_E_NON_FATAL + 3)) #endif /* __TPM_ERROR_H__ */ trousers-0.3.15/src/include/tss/tss_typedef.h0000664000175000017510000000347513663651711020512 0ustar deboradebora/*++ Global typedefs for TSS */ #ifndef __TSS_TYPEDEF_H__ #define __TSS_TYPEDEF_H__ #include //-------------------------------------------------------------------- // definitions for TSS Service Provider (TSP) // typedef UINT32 TSS_HANDLE; typedef UINT32 TSS_FLAG; // object attributes typedef UINT32 TSS_RESULT; // the return code from a TSS function typedef UINT32 TSS_HOBJECT; // basic object handle typedef TSS_HOBJECT TSS_HCONTEXT; // context object handle typedef TSS_HOBJECT TSS_HPOLICY; // policy object handle typedef TSS_HOBJECT TSS_HTPM; // TPM object handle typedef TSS_HOBJECT TSS_HKEY; // key object handle typedef TSS_HOBJECT TSS_HENCDATA; // encrypted data object handle typedef TSS_HOBJECT TSS_HPCRS; // PCR composite object handle typedef TSS_HOBJECT TSS_HHASH; // hash object handle typedef TSS_HOBJECT TSS_HNVSTORE; // NV storage object handle typedef TSS_HOBJECT TSS_HMIGDATA; // migration data utility obj handle typedef TSS_HOBJECT TSS_HDELFAMILY; // delegation family object handle typedef TSS_HOBJECT TSS_HDAA_CREDENTIAL; // daa credential typedef TSS_HOBJECT TSS_HDAA_ISSUER_KEY; // daa credential issuer keypair typedef TSS_HOBJECT TSS_HDAA_ARA_KEY; // daa anonymity revocation // authority keypair typedef UINT32 TSS_EVENTTYPE; typedef UINT16 TSS_MIGRATE_SCHEME; typedef UINT32 TSS_ALGORITHM_ID; typedef UINT32 TSS_KEY_USAGE_ID; typedef UINT16 TSS_KEY_ENC_SCHEME; typedef UINT16 TSS_KEY_SIG_SCHEME; typedef BYTE TSS_KEY_AUTH_DATA_USAGE; typedef UINT32 TSS_CMK_DELEGATE; typedef UINT32 TSS_NV_INDEX; typedef UINT32 TSS_COUNTER_ID; #endif // __TSS_TYPEDEF_H__ trousers-0.3.15/src/include/tss/platform.h0000664000175000017510000000226413663651711020000 0ustar deboradebora/*++ There are platform dependent and general defines. --*/ #ifndef TSS_PLATFORM_H #define TSS_PLATFORM_H /* The default implementation is to use stdint.h, a part of the C99 standard. * Systems that don't support this are handled on a case-by-case basis. */ #if !defined(WIN32) #include typedef uint8_t BYTE; typedef int8_t TSS_BOOL; typedef uint16_t UINT16; typedef uint32_t UINT32; typedef uint64_t UINT64; typedef uint16_t TSS_UNICODE; typedef void* PVOID; #elif defined(WIN32) #include typedef unsigned char BYTE; typedef signed char TSS_BOOL; #ifndef _BASETSD_H_ // basetsd.h provides definitions of UINT16, UINT32 and UINT64. typedef unsigned short UINT16; typedef unsigned long UINT32; typedef unsigned __int64 UINT64; #endif typedef unsigned short TSS_UNICODE; typedef void* PVOID; #endif /* Include this so that applications that use names as defined in the * 1.1 TSS specification can still compile */ #include #endif // TSS_PLATFORM_H trousers-0.3.15/src/include/tss/tcs_defines.h0000664000175000017510000000166413663651711020445 0ustar deboradebora/*++ TSS Core Service structures */ #ifndef __TCS_DEFINES_H__ #define __TCS_DEFINES_H__ #define TSS_TCSATTRIB_TRANSPORT_DEFAULT ((UINT32)(0x00000000)) #define TSS_TCSATTRIB_TRANSPORT_EXCLUSIVE ((UINT32)(0x00000001)) // Values for the ulCredentialType parameter to Tcsi_GetCredential #define TSS_TCS_CREDENTIAL_EKCERT ((UINT32)0x00000001) #define TSS_TCS_CREDENTIAL_TPM_CC ((UINT32)0x00000002) #define TSS_TCS_CREDENTIAL_PLATFORMCERT ((UINT32)0x00000003) // Values for the ulCredentialAccessMode parameter to Tcsi_GetCredential // TSS_TCS_CERT_ACCESS_AUTO triggers the default behavior. // Values with TSS_TCS_CERT_VENDOR_SPECIFIC_BIT set trigger // vendor specific behavior. #define TSS_TCS_CERT_ACCESS_AUTO ((UINT32)0x00000001) #define TSS_TCS_CERT_VENDOR_SPECIFIC_BIT ((UINT32)0x80000000) #endif // __TCS_DEFINES_H__ trousers-0.3.15/src/include/tss/tddlapi_error.h0000664000175000017510000000301213663651711020776 0ustar deboradebora/*++ TDDL error return codes for the TPM Device Driver Library Interface (TDDLI) --*/ #ifndef __TDDLAPI_ERROR_H__ #define __TDDLAPI_ERROR_H__ // // error coding scheme for a Microsoft Windows platform - // refer to the TSS Specification Parts // // Values are 32 bit values layed out as follows: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +---+-+-+-----------------------+-------+-----------------------+ // |Lev|C|R| Facility | Layer | Code | // +---+-+-+-----------------------+-------+-----------------------+ // | Platform specific coding | TSS error coding system | // +---+-+-+-----------------------+-------+-----------------------+ // // Lev - is the Level code // // 00 - Success // 01 - Informational // 10 - Warning // 11 - Error // // C - is the Customer code flag (must actually be set) // // R - is a reserved bit (unused) // // Facility - is the facility code: TCPA: proposal 0x028 // // Code - is the facility's status code // // no macros are used below intentionally // for a better error code recognition by the reader // note that the values of TPM_E_BASE and TSS_E_BASE, TSS_W_BASE and TSS_I_BASE // have to be adjusted for a platform other than Windows // // TPM specific error codes (layer nibble set to TPM layer TSS_LAYER_TPM) // #endif // __TDDLAPI_ERROR_H__ trousers-0.3.15/src/include/tss/tcpa_error.h0000664000175000017510000000017213663651711020310 0ustar deboradebora #ifndef __TCPA_ERROR_H__ #define __TCPA_ERROR_H__ #warning including deprecated header file tcpa_error.h #endif trousers-0.3.15/src/include/tss/tss_structs.h0000664000175000017510000003650613663651711020562 0ustar deboradebora/*++ TSS structures for TSS */ #ifndef __TSS_STRUCTS_H__ #define __TSS_STRUCTS_H__ #include #include #include typedef struct tdTSS_VERSION { BYTE bMajor; BYTE bMinor; BYTE bRevMajor; BYTE bRevMinor; } TSS_VERSION; typedef struct tdTSS_PCR_EVENT { TSS_VERSION versionInfo; UINT32 ulPcrIndex; TSS_EVENTTYPE eventType; UINT32 ulPcrValueLength; #ifdef __midl [size_is(ulPcrValueLength)] #endif BYTE* rgbPcrValue; UINT32 ulEventLength; #ifdef __midl [size_is(ulEventLength)] #endif BYTE* rgbEvent; } TSS_PCR_EVENT; typedef struct tdTSS_EVENT_CERT { TSS_VERSION versionInfo; UINT32 ulCertificateHashLength; #ifdef __midl [size_is(ulCertificateHashLength)] #endif BYTE* rgbCertificateHash; UINT32 ulEntityDigestLength; #ifdef __midl [size_is(ulEntityDigestLength)] #endif BYTE* rgbentityDigest; TSS_BOOL fDigestChecked; TSS_BOOL fDigestVerified; UINT32 ulIssuerLength; #ifdef __midl [size_is(ulIssuerLength)] #endif BYTE* rgbIssuer; } TSS_EVENT_CERT; typedef struct tdTSS_UUID { UINT32 ulTimeLow; UINT16 usTimeMid; UINT16 usTimeHigh; BYTE bClockSeqHigh; BYTE bClockSeqLow; BYTE rgbNode[6]; } TSS_UUID; typedef struct tdTSS_KM_KEYINFO { TSS_VERSION versionInfo; TSS_UUID keyUUID; TSS_UUID parentKeyUUID; BYTE bAuthDataUsage; // whether auth is needed to load child keys TSS_BOOL fIsLoaded; // TRUE: actually loaded in TPM UINT32 ulVendorDataLength; // may be 0 #ifdef __midl [size_is(ulVendorDataLength)] #endif BYTE *rgbVendorData; // may be NULL } TSS_KM_KEYINFO; typedef struct tdTSS_KM_KEYINFO2 { TSS_VERSION versionInfo; TSS_UUID keyUUID; TSS_UUID parentKeyUUID; BYTE bAuthDataUsage; // whether auth is needed to load child keys TSS_FLAG persistentStorageType; TSS_FLAG persistentStorageTypeParent; TSS_BOOL fIsLoaded; // TRUE: actually loaded in TPM UINT32 ulVendorDataLength; // may be 0 #ifdef __midl [size_is(ulVendorDataLength)] #endif BYTE *rgbVendorData; // may be NULL } TSS_KM_KEYINFO2; typedef struct tdTSS_NONCE { BYTE nonce[TPM_SHA1BASED_NONCE_LEN]; } TSS_NONCE; typedef struct tdTSS_VALIDATION { TSS_VERSION versionInfo; UINT32 ulExternalDataLength; #ifdef __midl [size_is(ulExternalDataLength)] #endif BYTE* rgbExternalData; UINT32 ulDataLength; #ifdef __midl [size_is(ulDataLength)] #endif BYTE* rgbData; UINT32 ulValidationDataLength; #ifdef __midl [size_is(ulValidationDataLength)] #endif BYTE* rgbValidationData; } TSS_VALIDATION; typedef struct tdTSS_CALLBACK { PVOID callback; PVOID appData; TSS_ALGORITHM_ID alg; } TSS_CALLBACK; typedef struct tdTSS_DAA_PK { TSS_VERSION versionInfo; UINT32 modulusLength; #ifdef __midl [size_is(modulusLength)] #endif BYTE* modulus; UINT32 capitalSLength; #ifdef __midl [size_is(capitalSLength)] #endif BYTE* capitalS; UINT32 capitalZLength; #ifdef __midl [size_is(capitalZLength)] #endif BYTE* capitalZ; UINT32 capitalR0Length; #ifdef __midl [size_is(capitalR0Length)] #endif BYTE* capitalR0; UINT32 capitalR1Length; #ifdef __midl [size_is(capitalR1Length)] #endif BYTE* capitalR1; UINT32 gammaLength; #ifdef __midl [size_is(gammaLength)] #endif BYTE* gamma; UINT32 capitalGammaLength; #ifdef __midl [size_is(capitalGammaLength)] #endif BYTE* capitalGamma; UINT32 rhoLength; #ifdef __midl [size_is(rhoLength)] #endif BYTE* rho; UINT32 capitalYLength; // Length of first dimenstion UINT32 capitalYLength2; // Length of second dimension #ifdef __midl [size_is(capitalYLength,capitalYLength2)] #endif BYTE** capitalY; UINT32 capitalYPlatformLength; UINT32 issuerBaseNameLength; #ifdef __midl [size_is(issuerBaseName)] #endif BYTE* issuerBaseName; UINT32 numPlatformAttributes; UINT32 numIssuerAttributes; } TSS_DAA_PK; typedef struct tdTSS_DAA_PK_PROOF { TSS_VERSION versionInfo; UINT32 challengeLength; #ifdef __midl [size_is(challengeLength)] #endif BYTE* challenge; UINT32 responseLength; // Length of first dimension UINT32 responseLength2; // Length of second dimension #ifdef __midl [size_is(responseLength,responseLength2)] #endif BYTE** response; } TSS_DAA_PK_PROOF; typedef struct tdTSS_DAA_SK { TSS_VERSION versionInfo; UINT32 productPQprimeLength; #ifdef __midl [size_is(productPQprimeLength)] #endif BYTE* productPQprime; } TSS_DAA_SK; typedef struct tdTSS_DAA_KEY_PAIR { TSS_VERSION versionInfo; TSS_DAA_SK secretKey; TSS_DAA_PK publicKey; } TSS_DAA_KEY_PAIR; typedef struct tdTSS_DAA_AR_PK { TSS_VERSION versionInfo; UINT32 etaLength; #ifdef __midl [size_is(etaLength)] #endif BYTE* eta; UINT32 lambda1Length; #ifdef __midl [size_is(lambda1Length)] #endif BYTE* lambda1; UINT32 lambda2Length; #ifdef __midl [size_is(lambda2Length)] #endif BYTE* lambda2; UINT32 lambda3Length; #ifdef __midl [size_is(lambda3Length)] #endif BYTE* lambda3; } TSS_DAA_AR_PK; typedef struct tdTSS_DAA_AR_SK { TSS_VERSION versionInfo; UINT32 x0Length; #ifdef __midl [size_is(x0Length)] #endif BYTE* x0; UINT32 x1Length; #ifdef __midl [size_is(x1Length)] #endif BYTE* x1; UINT32 x2Length; #ifdef __midl [size_is(x2Length)] #endif BYTE* x2; UINT32 x3Length; #ifdef __midl [size_is(x3Length)] #endif BYTE* x3; UINT32 x4Length; #ifdef __midl [size_is(x4Length)] #endif BYTE* x4; UINT32 x5Length; #ifdef __midl [size_is(x5Length)] #endif BYTE* x5; } TSS_DAA_AR_SK; typedef struct tdTSS_DAA_AR_KEY_PAIR { TSS_VERSION versionInfo; TSS_DAA_AR_SK secretKey; TSS_DAA_AR_PK publicKey; } TSS_DAA_AR_KEY_PAIR; typedef struct tdTSS_DAA_CRED_ISSUER { TSS_VERSION versionInfo; UINT32 capitalALength; #ifdef __midl [size_is(capitalALength)] #endif BYTE* capitalA; UINT32 eLength; #ifdef __midl [size_is(eLength)] #endif BYTE* e; UINT32 vPrimePrimeLength; #ifdef __midl [size_is(vPrimePrimeLength)] #endif BYTE* vPrimePrime; UINT32 attributesIssuerLength; // Length of first dimension UINT32 attributesIssuerLength2; // Length of second dimension #ifdef __midl [size_is(attributesIssuerLength,attributesIssuerLength2)] #endif BYTE** attributesIssuer; UINT32 cPrimeLength; #ifdef __midl [size_is(cPrimeLength)] #endif BYTE* cPrime; UINT32 sELength; #ifdef __midl [size_is(sELength)] #endif BYTE* sE; } TSS_DAA_CRED_ISSUER; typedef struct tdTSS_DAA_CREDENTIAL { TSS_VERSION versionInfo; UINT32 capitalALength; #ifdef __midl [size_is(capitalALength)] #endif BYTE* capitalA; UINT32 exponentLength; #ifdef __midl [size_is(exponentLength)] #endif BYTE* exponent; UINT32 vBar0Length; #ifdef __midl [size_is(vBar0Length)] #endif BYTE* vBar0; UINT32 vBar1Length; #ifdef __midl [size_is(vBar1Length)] #endif BYTE* vBar1; UINT32 attributesLength; // Length of first dimension UINT32 attributesLength2; // Length of second dimension #ifdef __midl [size_is(attributesLength,attributesLength2)] #endif BYTE** attributes; TSS_DAA_PK issuerPK; UINT32 tpmSpecificEncLength; #ifdef __midl [size_is(tpmSpecificEncLength)] #endif BYTE* tpmSpecificEnc; UINT32 daaCounter; } TSS_DAA_CREDENTIAL; typedef struct tdTSS_DAA_ATTRIB_COMMIT { TSS_VERSION versionInfo; UINT32 betaLength; #ifdef __midl [size_is(betaLength)] #endif BYTE* beta; UINT32 sMuLength; #ifdef __midl [size_is(sMuLength)] #endif BYTE* sMu; } TSS_DAA_ATTRIB_COMMIT; typedef struct tdTSS_DAA_CREDENTIAL_REQUEST { TSS_VERSION versionInfo; UINT32 capitalULength; #ifdef __midl [size_is(capitalULength)] #endif BYTE* capitalU; UINT32 capitalNiLength; #ifdef __midl [size_is(capitalNiLength)] #endif BYTE* capitalNi; UINT32 authenticationProofLength; #ifdef __midl [size_is(authenticationProofLength)] #endif BYTE* authenticationProof; UINT32 challengeLength; #ifdef __midl [size_is(challengeLength)] #endif BYTE* challenge; UINT32 nonceTpmLength; #ifdef __midl [size_is(nonceTpmLength)] #endif BYTE* nonceTpm; UINT32 noncePlatformLength; #ifdef __midl [size_is(noncePlatformLength)] #endif BYTE* noncePlatform; UINT32 sF0Length; #ifdef __midl [size_is(sF0Length)] #endif BYTE* sF0; UINT32 sF1Length; #ifdef __midl [size_is(sF1Length)] #endif BYTE* sF1; UINT32 sVprimeLength; #ifdef __midl [size_is(sVprimeLength)] #endif BYTE* sVprime; UINT32 sVtildePrimeLength; #ifdef __midl [size_is(sVtildePrimeLength)] #endif BYTE* sVtildePrime; UINT32 sALength; // Length of first dimension UINT32 sALength2; // Length of second dimension #ifdef __midl [size_is(sALength,sALength2)] #endif BYTE** sA; UINT32 attributeCommitmentsLength; TSS_DAA_ATTRIB_COMMIT* attributeCommitments; } TSS_DAA_CREDENTIAL_REQUEST; typedef struct tdTSS_DAA_SELECTED_ATTRIB { TSS_VERSION versionInfo; UINT32 indicesListLength; #ifdef __midl [size_is(indicesListLength)] #endif TSS_BOOL* indicesList; } TSS_DAA_SELECTED_ATTRIB; typedef struct tdTSS_DAA_PSEUDONYM { TSS_VERSION versionInfo; TSS_FLAG payloadFlag; UINT32 payloadLength; #ifdef __midl [size_is(payloadLength)] #endif BYTE* payload; } TSS_DAA_PSEUDONYM; typedef struct tdTSS_DAA_PSEUDONYM_PLAIN { TSS_VERSION versionInfo; UINT32 capitalNvLength; #ifdef __midl [size_is(capitalNvLength)] #endif BYTE* capitalNv; } TSS_DAA_PSEUDONYM_PLAIN; typedef struct tdTSS_DAA_PSEUDONYM_ENCRYPTED { TSS_VERSION versionInfo; UINT32 delta1Length; #ifdef __midl [size_is(delta1Length)] #endif BYTE* delta1; UINT32 delta2Length; #ifdef __midl [size_is(delta2Length)] #endif BYTE* delta2; UINT32 delta3Length; #ifdef __midl [size_is(delta3Length)] #endif BYTE* delta3; UINT32 delta4Length; #ifdef __midl [size_is(delta4Length)] #endif BYTE* delta4; UINT32 sTauLength; #ifdef __midl [size_is(sTauLength)] #endif BYTE* sTau; } TSS_DAA_PSEUDONYM_ENCRYPTED; typedef struct tdTSS_DAA_SIGN_CALLBACK { TSS_VERSION versionInfo; TSS_HHASH challenge; TSS_FLAG payloadFlag; UINT32 payloadLength; #ifdef __midl [size_is(payloadLength)] #endif BYTE* payload; } TSS_DAA_SIGN_CALLBACK; typedef struct tdTSS_DAA_SIGNATURE { TSS_VERSION versionInfo; UINT32 zetaLength; #ifdef __midl [size_is(zetaLength)] #endif BYTE* zeta; UINT32 capitalTLength; #ifdef __midl [size_is(capitalTLength)] #endif BYTE* capitalT; UINT32 challengeLength; #ifdef __midl [size_is(challengeLength)] #endif BYTE* challenge; UINT32 nonceTpmLength; #ifdef __midl [size_is(nonceTpmLength)] #endif BYTE* nonceTpm; UINT32 sVLength; #ifdef __midl [size_is(sVLength)] #endif BYTE* sV; UINT32 sF0Length; #ifdef __midl [size_is(sF0Length)] #endif BYTE* sF0; UINT32 sF1Length; #ifdef __midl [size_is(sF1Length)] #endif BYTE* sF1; UINT32 sELength; #ifdef __midl [size_is(sELength)] #endif BYTE* sE; UINT32 sALength; // Length of first dimension UINT32 sALength2; // Length of second dimension #ifdef __midl [size_is(sALength,sALength2)] #endif BYTE** sA; UINT32 attributeCommitmentsLength; #ifdef __midl [size_is(attributeCommitmentsLength)] #endif TSS_DAA_ATTRIB_COMMIT* attributeCommitments; TSS_DAA_PSEUDONYM signedPseudonym; TSS_DAA_SIGN_CALLBACK callbackResult; } TSS_DAA_SIGNATURE; typedef struct tdTSS_DAA_IDENTITY_PROOF { TSS_VERSION versionInfo; UINT32 endorsementLength; #ifdef __midl [size_is(endorsementLength)] #endif BYTE* endorsementCredential; UINT32 platformLength; #ifdef __midl [size_is(platformLength)] #endif BYTE* platform; UINT32 conformanceLength; #ifdef __midl [size_is(conformanceLength)] #endif BYTE* conformance; } TSS_DAA_IDENTITY_PROOF; //////////////////////////////////////////////////////////////////// typedef UINT32 TSS_FAMILY_ID; typedef BYTE TSS_DELEGATION_LABEL; // Values are TSS_DELEGATIONTYPE_KEY or TSS_DELEGATIONTYPE_OWNER typedef UINT32 TSS_DELEGATION_TYPE; typedef struct tdTSS_PCR_INFO_SHORT { UINT32 sizeOfSelect; #ifdef __midl [size_is(sizeOfSelect)] #endif BYTE *selection; BYTE localityAtRelease; UINT32 sizeOfDigestAtRelease; #ifdef __midl [size_is(sizeOfDigestAtRelease)] #endif BYTE *digestAtRelease; } TSS_PCR_INFO_SHORT; typedef struct tdTSS_FAMILY_TABLE_ENTRY { TSS_FAMILY_ID familyID; TSS_DELEGATION_LABEL label; UINT32 verificationCount; TSS_BOOL enabled; TSS_BOOL locked; } TSS_FAMILY_TABLE_ENTRY; typedef struct tdTSS_DELEGATION_TABLE_ENTRY { UINT32 tableIndex; TSS_DELEGATION_LABEL label; TSS_PCR_INFO_SHORT pcrInfo; UINT32 per1; UINT32 per2; TSS_FAMILY_ID familyID; UINT32 verificationCount; } TSS_DELEGATION_TABLE_ENTRY; typedef struct tdTSS_PLATFORM_CLASS { UINT32 platformClassSimpleIdentifier; UINT32 platformClassURISize; BYTE* pPlatformClassURI; } TSS_PLATFORM_CLASS; #endif // __TSS_STRUCTS_H__ trousers-0.3.15/src/include/tss/tpm.h0000664000175000017510000016717613663651711016772 0ustar deboradebora/*++ * * TPM structures extracted from the TPM specification 1.2, * Part 2 (Structures), rev 85. * * Errata: * * *) The individual bits of TPM_STARTUP_EFFECTS were not given names in * the TPM spec so they are not defined in tpm.h. * * *) A few typedefs not present in the TPM 1.2 specification have been * added. This was generally done when the TPM 1.2 spec defined a set of * related values (either bitmasks or enumeration values) but did not * define an associated type to hold these values. The typedefs have been * added and structure fields that were to hold those values have been * switched from generic UINT* types to the more specific types. This was * done to highlight exactly where those #defined values were to be used. * The types that have been added are: * TPM_NV_PER_ATTRIBUTES * TPM_DELEGATE_TYPE * * *) The layout of bitfields within a structure are compiler-dependent * and the use of structure bitfields has been avoided where possible. In * cases where a value is a collection of independent bits the type is * given a name (typedeffed to UINT16 or UINT32 as appropriate) and masks * are #defined to access the individual bits. This is not possible for * TPM_VERSION_BYTE because the fields are 4-bit values. A best attempt * has been made to make this compiler independent but it has only been * checked on GCC and Visual C++ on little-endian machines. * * *) The TPM_DELEGATIONS per1 and per2 fields field are a bitmask but * are defined as a UINT32 because the bitfields have different meaning * based on the type of delegation blob. * * *) The definitions of TPM_PERMANENT_DATA, TPM_STCLEAR_DATA, * TPM_STANY_DATA, and TPM_DELEGATE_TABLE_ROW are commented out. These * structures are internal to the TPM and are not directly accessible by * external software so this should not be a problem. * * *) The definitions of TPM_FAMILY_TABLE and TPM_DELEGATE_TABLE are * commented out because they are variable length arrays internal to the * TPM. As above they are not directly accessible by external software * so this should not be a problem. */ #ifndef __TPM_H__ #define __TPM_H__ #ifdef __midl #define SIZEIS(x) [size_is(x)] #else #define SIZEIS(x) #endif #include //------------------------------------------------------------------- // Part 2, section 2.1: Basic data types typedef BYTE TPM_BOOL; #ifndef FALSE #define FALSE 0x00 #define TRUE 0x01 #endif /* ifndef FALSE */ //------------------------------------------------------------------- // Part 2, section 2.3: Helper Redefinitions // Many of the helper redefinitions appear later in this file // so that they are declared next to the list of valid values // they may hold. typedef BYTE TPM_LOCALITY_MODIFIER; typedef UINT32 TPM_COMMAND_CODE; /* 1.1b */ typedef UINT32 TPM_COUNT_ID; typedef UINT32 TPM_REDIT_COMMAND; typedef UINT32 TPM_HANDLE; typedef UINT32 TPM_AUTHHANDLE; typedef UINT32 TPM_TRANSHANDLE; typedef UINT32 TPM_KEYHANDLE; typedef UINT32 TPM_DIRINDEX; typedef UINT32 TPM_PCRINDEX; typedef UINT32 TPM_RESULT; typedef UINT32 TPM_MODIFIER_INDICATOR; //------------------------------------------------------------------- // Part 2, section 2.2.4: Vendor Specific #define TPM_Vendor_Specific32 0x00000400 #define TPM_Vendor_Specific8 0x80 //------------------------------------------------------------------- // Part 2, section 3: Structure Tags typedef UINT16 TPM_STRUCTURE_TAG; #define TPM_TAG_CONTEXTBLOB ((UINT16)0x0001) #define TPM_TAG_CONTEXT_SENSITIVE ((UINT16)0x0002) #define TPM_TAG_CONTEXTPOINTER ((UINT16)0x0003) #define TPM_TAG_CONTEXTLIST ((UINT16)0x0004) #define TPM_TAG_SIGNINFO ((UINT16)0x0005) #define TPM_TAG_PCR_INFO_LONG ((UINT16)0x0006) #define TPM_TAG_PERSISTENT_FLAGS ((UINT16)0x0007) #define TPM_TAG_VOLATILE_FLAGS ((UINT16)0x0008) #define TPM_TAG_PERSISTENT_DATA ((UINT16)0x0009) #define TPM_TAG_VOLATILE_DATA ((UINT16)0x000a) #define TPM_TAG_SV_DATA ((UINT16)0x000b) #define TPM_TAG_EK_BLOB ((UINT16)0x000c) #define TPM_TAG_EK_BLOB_AUTH ((UINT16)0x000d) #define TPM_TAG_COUNTER_VALUE ((UINT16)0x000e) #define TPM_TAG_TRANSPORT_INTERNAL ((UINT16)0x000f) #define TPM_TAG_TRANSPORT_LOG_IN ((UINT16)0x0010) #define TPM_TAG_TRANSPORT_LOG_OUT ((UINT16)0x0011) #define TPM_TAG_AUDIT_EVENT_IN ((UINT16)0x0012) #define TPM_TAG_AUDIT_EVENT_OUT ((UINT16)0x0013) #define TPM_TAG_CURRENT_TICKS ((UINT16)0x0014) #define TPM_TAG_KEY ((UINT16)0x0015) #define TPM_TAG_STORED_DATA12 ((UINT16)0x0016) #define TPM_TAG_NV_ATTRIBUTES ((UINT16)0x0017) #define TPM_TAG_NV_DATA_PUBLIC ((UINT16)0x0018) #define TPM_TAG_NV_DATA_SENSITIVE ((UINT16)0x0019) #define TPM_TAG_DELEGATIONS ((UINT16)0x001a) #define TPM_TAG_DELEGATE_PUBLIC ((UINT16)0x001b) #define TPM_TAG_DELEGATE_TABLE_ROW ((UINT16)0x001c) #define TPM_TAG_TRANSPORT_AUTH ((UINT16)0x001d) #define TPM_TAG_TRANSPORT_PUBLIC ((UINT16)0x001e) #define TPM_TAG_PERMANENT_FLAGS ((UINT16)0x001f) #define TPM_TAG_STCLEAR_FLAGS ((UINT16)0x0020) #define TPM_TAG_STANY_FLAGS ((UINT16)0x0021) #define TPM_TAG_PERMANENT_DATA ((UINT16)0x0022) #define TPM_TAG_STCLEAR_DATA ((UINT16)0x0023) #define TPM_TAG_STANY_DATA ((UINT16)0x0024) #define TPM_TAG_FAMILY_TABLE_ENTRY ((UINT16)0x0025) #define TPM_TAG_DELEGATE_SENSITIVE ((UINT16)0x0026) #define TPM_TAG_DELG_KEY_BLOB ((UINT16)0x0027) #define TPM_TAG_KEY12 ((UINT16)0x0028) #define TPM_TAG_CERTIFY_INFO2 ((UINT16)0x0029) #define TPM_TAG_DELEGATE_OWNER_BLOB ((UINT16)0x002a) #define TPM_TAG_EK_BLOB_ACTIVATE ((UINT16)0x002b) #define TPM_TAG_DAA_BLOB ((UINT16)0x002c) #define TPM_TAG_DAA_CONTEXT ((UINT16)0x002d) #define TPM_TAG_DAA_ENFORCE ((UINT16)0x002e) #define TPM_TAG_DAA_ISSUER ((UINT16)0x002f) #define TPM_TAG_CAP_VERSION_INFO ((UINT16)0x0030) #define TPM_TAG_DAA_SENSITIVE ((UINT16)0x0031) #define TPM_TAG_DAA_TPM ((UINT16)0x0032) #define TPM_TAG_CMK_MIGAUTH ((UINT16)0x0033) #define TPM_TAG_CMK_SIGTICKET ((UINT16)0x0034) #define TPM_TAG_CMK_MA_APPROVAL ((UINT16)0x0035) #define TPM_TAG_QUOTE_INFO2 ((UINT16)0x0036) #define TPM_TAG_DA_INFO ((UINT16)0x0037) #define TPM_TAG_DA_INFO_LIMITED ((UINT16)0x0038) #define TPM_TAG_DA_ACTION_TYPE ((UINT16)0x0039) //------------------------------------------------------------------- // Part 2, section 4: Types typedef UINT32 TPM_RESOURCE_TYPE; #define TPM_RT_KEY ((UINT32)0x00000001) #define TPM_RT_AUTH ((UINT32)0x00000002) #define TPM_RT_HASH ((UINT32)0x00000003) #define TPM_RT_TRANS ((UINT32)0x00000004) #define TPM_RT_CONTEXT ((UINT32)0x00000005) #define TPM_RT_COUNTER ((UINT32)0x00000006) #define TPM_RT_DELEGATE ((UINT32)0x00000007) #define TPM_RT_DAA_TPM ((UINT32)0x00000008) #define TPM_RT_DAA_V0 ((UINT32)0x00000009) #define TPM_RT_DAA_V1 ((UINT32)0x0000000a) typedef BYTE TPM_PAYLOAD_TYPE; /* 1.1b */ #define TPM_PT_ASYM ((BYTE)0x01) /* 1.1b */ #define TPM_PT_BIND ((BYTE)0x02) /* 1.1b */ #define TPM_PT_MIGRATE ((BYTE)0x03) /* 1.1b */ #define TPM_PT_MAINT ((BYTE)0x04) /* 1.1b */ #define TPM_PT_SEAL ((BYTE)0x05) /* 1.1b */ #define TPM_PT_MIGRATE_RESTRICTED ((BYTE)0x06) #define TPM_PT_MIGRATE_EXTERNAL ((BYTE)0x07) #define TPM_PT_CMK_MIGRATE ((BYTE)0x08) typedef UINT16 TPM_ENTITY_TYPE; /* 1.1b */ #define TPM_ET_KEYHANDLE ((UINT16)0x0001) /* 1.1b */ #define TPM_ET_OWNER ((UINT16)0x0002) /* 1.1b */ #define TPM_ET_DATA ((UINT16)0x0003) /* 1.1b */ #define TPM_ET_SRK ((UINT16)0x0004) /* 1.1b */ #define TPM_ET_KEY ((UINT16)0x0005) /* 1.1b */ #define TPM_ET_REVOKE ((UINT16)0x0006) #define TPM_ET_DEL_OWNER_BLOB ((UINT16)0x0007) #define TPM_ET_DEL_ROW ((UINT16)0x0008) #define TPM_ET_DEL_KEY_BLOB ((UINT16)0x0009) #define TPM_ET_COUNTER ((UINT16)0x000a) #define TPM_ET_NV ((UINT16)0x000b) #define TPM_ET_OPERATOR ((UINT16)0x000c) #define TPM_ET_RESERVED_HANDLE ((UINT16)0x0040) /* The following values may be ORed into the MSB of the TPM_ENTITY_TYPE * to indicate particular encryption scheme */ #define TPM_ET_XOR ((BYTE)0x00) #define TPM_ET_AES ((BYTE)0x06) typedef UINT32 TPM_KEY_HANDLE; /* 1.1b */ #define TPM_KH_SRK ((UINT32)0x40000000) #define TPM_KH_OWNER ((UINT32)0x40000001) #define TPM_KH_REVOKE ((UINT32)0x40000002) #define TPM_KH_TRANSPORT ((UINT32)0x40000003) #define TPM_KH_OPERATOR ((UINT32)0x40000004) #define TPM_KH_ADMIN ((UINT32)0x40000005) #define TPM_KH_EK ((UINT32)0x40000006) /* 1.1b used different names, but the same values */ #define TPM_KEYHND_SRK (TPM_KH_SRK) /* 1.1b */ #define TPM_KEYHND_OWNER (TPM_KH_OWNER) /* 1.1b */ typedef UINT16 TPM_STARTUP_TYPE; /* 1.1b */ #define TPM_ST_CLEAR ((UINT16)0x0001) /* 1.1b */ #define TPM_ST_STATE ((UINT16)0x0002) /* 1.1b */ #define TPM_ST_DEACTIVATED ((UINT16)0x0003) /* 1.1b */ //typedef UINT32 TPM_STARTUP_EFFECTS; // 32-bit mask, see spec for meaning. Names not currently defined. // bits 0-8 have meaning typedef UINT16 TPM_PROTOCOL_ID; /* 1.1b */ #define TPM_PID_OIAP ((UINT16)0x0001) /* 1.1b */ #define TPM_PID_OSAP ((UINT16)0x0002) /* 1.1b */ #define TPM_PID_ADIP ((UINT16)0x0003) /* 1.1b */ #define TPM_PID_ADCP ((UINT16)0x0004) /* 1.1b */ #define TPM_PID_OWNER ((UINT16)0x0005) /* 1.1b */ #define TPM_PID_DSAP ((UINT16)0x0006) #define TPM_PID_TRANSPORT ((UINT16)0x0007) // Note in 1.2 rev 104, DES and 3DES are eliminated typedef UINT32 TPM_ALGORITHM_ID; /* 1.1b */ #define TPM_ALG_RSA ((UINT32)0x00000001) /* 1.1b */ #define TPM_ALG_DES ((UINT32)0x00000002) /* 1.1b */ #define TPM_ALG_3DES ((UINT32)0x00000003) /* 1.1b */ #define TPM_ALG_SHA ((UINT32)0x00000004) /* 1.1b */ #define TPM_ALG_HMAC ((UINT32)0x00000005) /* 1.1b */ #define TPM_ALG_AES ((UINT32)0x00000006) /* 1.1b */ #define TPM_ALG_AES128 (TPM_ALG_AES) #define TPM_ALG_MGF1 ((UINT32)0x00000007) #define TPM_ALG_AES192 ((UINT32)0x00000008) #define TPM_ALG_AES256 ((UINT32)0x00000009) #define TPM_ALG_XOR ((UINT32)0x0000000a) typedef UINT16 TPM_PHYSICAL_PRESENCE; /* 1.1b */ #define TPM_PHYSICAL_PRESENCE_LOCK ((UINT16)0x0004) /* 1.1b */ #define TPM_PHYSICAL_PRESENCE_PRESENT ((UINT16)0x0008) /* 1.1b */ #define TPM_PHYSICAL_PRESENCE_NOTPRESENT ((UINT16)0x0010) /* 1.1b */ #define TPM_PHYSICAL_PRESENCE_CMD_ENABLE ((UINT16)0x0020) /* 1.1b */ #define TPM_PHYSICAL_PRESENCE_HW_ENABLE ((UINT16)0x0040) /* 1.1b */ #define TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK ((UINT16)0x0080) /* 1.1b */ #define TPM_PHYSICAL_PRESENCE_CMD_DISABLE ((UINT16)0x0100) #define TPM_PHYSICAL_PRESENCE_HW_DISABLE ((UINT16)0x0200) typedef UINT16 TPM_MIGRATE_SCHEME; /* 1.1b */ #define TPM_MS_MIGRATE ((UINT16)0x0001) /* 1.1b */ #define TPM_MS_REWRAP ((UINT16)0x0002) /* 1.1b */ #define TPM_MS_MAINT ((UINT16)0x0003) /* 1.1b */ #define TPM_MS_RESTRICT_MIGRATE ((UINT16)0x0004) #define TPM_MS_RESTRICT_APPROVE_DOUBLE ((UINT16)0x0005) typedef UINT16 TPM_EK_TYPE; #define TPM_EK_TYPE_ACTIVATE ((UINT16)0x0001) #define TPM_EK_TYPE_AUTH ((UINT16)0x0002) typedef UINT16 TPM_PLATFORM_SPECIFIC; #define TPM_PS_PC_11 ((UINT16)0x0001) #define TPM_PS_PC_12 ((UINT16)0x0002) #define TPM_PS_PDA_12 ((UINT16)0x0003) #define TPM_PS_Server_12 ((UINT16)0x0004) #define TPM_PS_Mobile_12 ((UINT16)0x0005) //------------------------------------------------------------------- // Part 2, section 5: Basic Structures typedef struct tdTPM_STRUCT_VER { BYTE major; BYTE minor; BYTE revMajor; BYTE revMinor; } TPM_STRUCT_VER; typedef struct tdTPM_VERSION_BYTE { // This needs to be made compiler-independent. int leastSigVer : 4; // least significant 4 bits int mostSigVer : 4; // most significant 4 bits } TPM_VERSION_BYTE; typedef struct tdTPM_VERSION { BYTE major; // Should really be a TPM_VERSION_BYTE BYTE minor; // Should really be a TPM_VERSION_BYTE BYTE revMajor; BYTE revMinor; } TPM_VERSION; // Put this in the right place: // byte size definition for 160 bit SHA1 hash value #define TPM_SHA1_160_HASH_LEN 0x14 #define TPM_SHA1BASED_NONCE_LEN TPM_SHA1_160_HASH_LEN typedef struct tdTPM_DIGEST { BYTE digest[TPM_SHA1_160_HASH_LEN]; } TPM_DIGEST; typedef TPM_DIGEST TPM_CHOSENID_HASH; typedef TPM_DIGEST TPM_COMPOSITE_HASH; typedef TPM_DIGEST TPM_DIRVALUE; typedef TPM_DIGEST TPM_HMAC; typedef TPM_DIGEST TPM_PCRVALUE; typedef TPM_DIGEST TPM_AUDITDIGEST; typedef struct tdTPM_NONCE /* 1.1b */ { BYTE nonce[TPM_SHA1BASED_NONCE_LEN]; } TPM_NONCE; typedef TPM_NONCE TPM_DAA_TPM_SEED; typedef TPM_NONCE TPM_DAA_CONTEXT_SEED; typedef struct tdTPM_AUTHDATA /* 1.1b */ { BYTE authdata[TPM_SHA1_160_HASH_LEN]; } TPM_AUTHDATA; typedef TPM_AUTHDATA TPM_SECRET; typedef TPM_AUTHDATA TPM_ENCAUTH; typedef struct tdTPM_KEY_HANDLE_LIST /* 1.1b */ { UINT16 loaded; SIZEIS(loaded) TPM_KEY_HANDLE *handle; } TPM_KEY_HANDLE_LIST; //------------------------------------------------------------------- // Part 2, section 5.8: Key usage values typedef UINT16 TPM_KEY_USAGE; /* 1.1b */ #define TPM_KEY_SIGNING ((UINT16)0x0010) /* 1.1b */ #define TPM_KEY_STORAGE ((UINT16)0x0011) /* 1.1b */ #define TPM_KEY_IDENTITY ((UINT16)0x0012) /* 1.1b */ #define TPM_KEY_AUTHCHANGE ((UINT16)0x0013) /* 1.1b */ #define TPM_KEY_BIND ((UINT16)0x0014) /* 1.1b */ #define TPM_KEY_LEGACY ((UINT16)0x0015) /* 1.1b */ #define TPM_KEY_MIGRATE ((UINT16)0x0016) typedef UINT16 TPM_SIG_SCHEME; /* 1.1b */ #define TPM_SS_NONE ((UINT16)0x0001) /* 1.1b */ #define TPM_SS_RSASSAPKCS1v15_SHA1 ((UINT16)0x0002) /* 1.1b */ #define TPM_SS_RSASSAPKCS1v15_DER ((UINT16)0x0003) /* 1.1b */ #define TPM_SS_RSASSAPKCS1v15_INFO ((UINT16)0x0004) typedef UINT16 TPM_ENC_SCHEME; /* 1.1b */ #define TPM_ES_NONE ((UINT16)0x0001) /* 1.1b */ #define TPM_ES_RSAESPKCSv15 ((UINT16)0x0002) /* 1.1b */ #define TPM_ES_RSAESOAEP_SHA1_MGF1 ((UINT16)0x0003) /* 1.1b */ #define TPM_ES_SYM_CNT ((UINT16)0x0004) #define TPM_ES_SYM_CTR TPM_ES_SYM_CNT #define TPM_ES_SYM_OFB ((UINT16)0x0005) #define TPM_ES_SYM_CBC_PKCS5PAD ((UINT16)0x00ff) //------------------------------------------------------------------- // Part 2, section 5.9: TPM_AUTH_DATA_USAGE values typedef BYTE TPM_AUTH_DATA_USAGE; /* 1.1b */ #define TPM_AUTH_NEVER ((BYTE)0x00) /* 1.1b */ #define TPM_AUTH_ALWAYS ((BYTE)0x01) /* 1.1b */ #define TPM_AUTH_PRIV_USE_ONLY ((BYTE)0x11) //------------------------------------------------------------------- // Part 2, section 5.10: TPM_KEY_FLAGS flags typedef UINT32 TPM_KEY_FLAGS; /* 1.1b */ #define TPM_REDIRECTION ((UINT32)0x00000001) /* 1.1b */ #define TPM_MIGRATABLE ((UINT32)0x00000002) /* 1.1b */ #define TPM_VOLATILE ((UINT32)0x00000004) /* 1.1b */ #define TPM_PCRIGNOREDONREAD ((UINT32)0x00000008) #define TPM_MIGRATEAUTHORITY ((UINT32)0x00000010) //------------------------------------------------------------------- // Part 2, section 5.11: TPM_CHANGEAUTH_VALIDATE typedef struct tdTPM_CHANGEAUTH_VALIDATE { TPM_SECRET newAuthSecret; TPM_NONCE n1; } TPM_CHANGEAUTH_VALIDATE; //------------------------------------------------------------------- // Part 2, section 5.12: TPM_MIGRATIONKEYAUTH // declared after section 10 to catch declaration of TPM_PUBKEY //------------------------------------------------------------------- // Part 2, section 5.13: TPM_COUNTER_VALUE; typedef UINT32 TPM_ACTUAL_COUNT; typedef struct tdTPM_COUNTER_VALUE { TPM_STRUCTURE_TAG tag; BYTE label[4]; TPM_ACTUAL_COUNT counter; } TPM_COUNTER_VALUE; //------------------------------------------------------------------- // Part 2, section 5.14: TPM_SIGN_INFO structure typedef struct tdTPM_SIGN_INFO { TPM_STRUCTURE_TAG tag; BYTE fixed[4]; TPM_NONCE replay; UINT32 dataLen; SIZEIS(dataLen) BYTE *data; } TPM_SIGN_INFO; //------------------------------------------------------------------- // Part 2, section 5.15: TPM_MSA_COMPOSITE typedef struct tdTPM_MSA_COMPOSITE { UINT32 MSAlist; SIZEIS(MSAlist) TPM_DIGEST *migAuthDigest; } TPM_MSA_COMPOSITE; //------------------------------------------------------------------- // Part 2, section 5.16: TPM_CMK_AUTH typedef struct tdTPM_CMK_AUTH { TPM_DIGEST migrationAuthorityDigest; TPM_DIGEST destinationKeyDigest; TPM_DIGEST sourceKeyDigest; } TPM_CMK_AUTH; //------------------------------------------------------------------- // Part 2, section 5.17: TPM_CMK_DELEGATE typedef UINT32 TPM_CMK_DELEGATE; #define TPM_CMK_DELEGATE_SIGNING (((UINT32)1)<<31) #define TPM_CMK_DELEGATE_STORAGE (((UINT32)1)<<30) #define TPM_CMK_DELEGATE_BIND (((UINT32)1)<<29) #define TPM_CMK_DELEGATE_LEGACY (((UINT32)1)<<28) #define TPM_CMK_DELEGATE_MIGRATE (((UINT32)1)<<27) //------------------------------------------------------------------- // Part 2, section 5.18: TPM_SELECT_SIZE typedef struct tdTPM_SELECT_SIZE { BYTE major; BYTE minor; UINT16 reqSize; } TPM_SELECT_SIZE; //------------------------------------------------------------------- // Part 2, section 5.19: TPM_CMK_MIGAUTH typedef struct tdTPM_CMK_MIGAUTH { TPM_STRUCTURE_TAG tag; TPM_DIGEST msaDigest; TPM_DIGEST pubKeyDigest; } TPM_CMK_MIGAUTH; //------------------------------------------------------------------- // Part 2, section 5.20: TPM_CMK_SIGTICKET typedef struct tdTPM_CMK_SIGTICKET { TPM_STRUCTURE_TAG tag; TPM_DIGEST verKeyDigest; TPM_DIGEST signedData; } TPM_CMK_SIGTICKET; //------------------------------------------------------------------- // Part 2, section 5.21: TPM_CMK_MA_APPROVAL typedef struct tdTPM_CMK_MA_APPROVAL { TPM_STRUCTURE_TAG tag; TPM_DIGEST migrationAuthorityDigest; } TPM_CMK_MA_APPROVAL; //------------------------------------------------------------------- // Part 2, section 6: Command Tags typedef UINT16 TPM_TAG; /* 1.1b */ #define TPM_TAG_RQU_COMMAND ((UINT16)0x00c1) #define TPM_TAG_RQU_AUTH1_COMMAND ((UINT16)0x00c2) #define TPM_TAG_RQU_AUTH2_COMMAND ((UINT16)0x00c3) #define TPM_TAG_RSP_COMMAND ((UINT16)0x00c4) #define TPM_TAG_RSP_AUTH1_COMMAND ((UINT16)0x00c5) #define TPM_TAG_RSP_AUTH2_COMMAND ((UINT16)0x00c6) //------------------------------------------------------------------- // Part 2, section 7.1: TPM_PERMANENT_FLAGS typedef struct tdTPM_PERMANENT_FLAGS { TPM_STRUCTURE_TAG tag; TSS_BOOL disable; TSS_BOOL ownership; TSS_BOOL deactivated; TSS_BOOL readPubek; TSS_BOOL disableOwnerClear; TSS_BOOL allowMaintenance; TSS_BOOL physicalPresenceLifetimeLock; TSS_BOOL physicalPresenceHWEnable; TSS_BOOL physicalPresenceCMDEnable; TSS_BOOL CEKPUsed; TSS_BOOL TPMpost; TSS_BOOL TPMpostLock; TSS_BOOL FIPS; TSS_BOOL Operator; TSS_BOOL enableRevokeEK; TSS_BOOL nvLocked; TSS_BOOL readSRKPub; TSS_BOOL tpmEstablished; TSS_BOOL maintenanceDone; TSS_BOOL disableFullDALogicInfo; } TPM_PERMANENT_FLAGS; #define TPM_PF_DISABLE ((UINT32)0x00000001) #define TPM_PF_OWNERSHIP ((UINT32)0x00000002) #define TPM_PF_DEACTIVATED ((UINT32)0x00000003) #define TPM_PF_READPUBEK ((UINT32)0x00000004) #define TPM_PF_DISABLEOWNERCLEAR ((UINT32)0x00000005) #define TPM_PF_ALLOWMAINTENANCE ((UINT32)0x00000006) #define TPM_PF_PHYSICALPRESENCELIFETIMELOCK ((UINT32)0x00000007) #define TPM_PF_PHYSICALPRESENCEHWENABLE ((UINT32)0x00000008) #define TPM_PF_PHYSICALPRESENCECMDENABLE ((UINT32)0x00000009) #define TPM_PF_CEKPUSED ((UINT32)0x0000000A) #define TPM_PF_TPMPOST ((UINT32)0x0000000B) #define TPM_PF_TPMPOSTLOCK ((UINT32)0x0000000C) #define TPM_PF_FIPS ((UINT32)0x0000000D) #define TPM_PF_OPERATOR ((UINT32)0x0000000E) #define TPM_PF_ENABLEREVOKEEK ((UINT32)0x0000000F) #define TPM_PF_NV_LOCKED ((UINT32)0x00000010) #define TPM_PF_READSRKPUB ((UINT32)0x00000011) #define TPM_PF_RESETESTABLISHMENTBIT ((UINT32)0x00000012) #define TPM_PF_MAINTENANCEDONE ((UINT32)0x00000013) #define TPM_PF_DISABLEFULLDALOGICINFO ((UINT32)0x00000014) //------------------------------------------------------------------- // Part 2, section 7.2: TPM_STCLEAR_FLAGS typedef struct tdTPM_STCLEAR_FLAGS { TPM_STRUCTURE_TAG tag; TSS_BOOL deactivated; TSS_BOOL disableForceClear; TSS_BOOL physicalPresence; TSS_BOOL physicalPresenceLock; TSS_BOOL bGlobalLock; } TPM_STCLEAR_FLAGS; #define TPM_SF_DEACTIVATED ((UINT32)0x00000001) #define TPM_SF_DISABLEFORCECLEAR ((UINT32)0x00000002) #define TPM_SF_PHYSICALPRESENCE ((UINT32)0x00000003) #define TPM_SF_PHYSICALPRESENCELOCK ((UINT32)0x00000004) #define TPM_SF_GLOBALLOCK ((UINT32)0x00000005) //------------------------------------------------------------------- // Part 2, section 7.3: TPM_STANY_FLAGS typedef struct tdTPM_STANY_FLAGS { TPM_STRUCTURE_TAG tag; TSS_BOOL postInitialise; TPM_MODIFIER_INDICATOR localityModifier; TSS_BOOL transportExclusive; TSS_BOOL TOSPresent; } TPM_STANY_FLAGS; #define TPM_AF_POSTINITIALIZE ((UINT32)0x00000001) #define TPM_AF_LOCALITYMODIFIER ((UINT32)0x00000002) #define TPM_AF_TRANSPORTEXCLUSIVE ((UINT32)0x00000003) #define TPM_AF_TOSPRESENT ((UINT32)0x00000004) //------------------------------------------------------------------- // Part 2, section 7.4: TPM_PERMANENT_DATA // available inside TPM only // //#define TPM_MIN_COUNTERS 4 //#define TPM_NUM_PCR 16 //#define TPM_MAX_NV_WRITE_NOOWNER 64 // //typedef struct tdTPM_PERMANENT_DATA //{ // TPM_STRUCTURE_TAG tag; // BYTE revMajor; // BYTE revMinor; // TPM_NONCE tpmProof; // TPM_NONCE ekReset; // TPM_SECRET ownerAuth; // TPM_SECRET operatorAuth; // TPM_DIRVALUE authDIR[1]; // TPM_PUBKEY manuMaintPub; // TPM_KEY endorsementKey; // TPM_KEY srk; // TPM_KEY contextKey; // TPM_KEY delegateKey; // TPM_COUNTER_VALUE auditMonotonicCounter; // TPM_COUNTER_VALUE monitonicCounter[TPM_MIN_COUNTERS]; // TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; // BYTE ordinalAuditStatus[]; // BYTE *rngState; // TPM_FAMILY_TABLE familyTable; // TPM_DELEGATE_TABLE delegateTable; // UINT32 maxNVBufSize; // UINT32 lastFamilyID; // UINT32 noOwnerNVWrite; // TPM_CMK_DELEGATE restrictDelegate; // TPM_DAA_TPM_SEED tpmDAASeed; // TPM_NONCE daaProof; // TPM_NONCE daaBlobKey; //} TPM_PERMANENT_DATA; //------------------------------------------------------------------- // Part 2, section 7.5: TPM_STCLEAR_DATA // available inside TPM only // //typedef struct tdTPM_STCLEAR_DATA //{ // TPM_STRUCTURE_TAG tag; // TPM_NONCE contextNonceKey; // TPM_COUNT_ID countID; // UINT32 ownerReference; // TPM_BOOL disableResetLock; // TPM_PCRVALUE PCR[TPM_NUM_PCR]; // UINT32 deferredPhysicalPresence; //} TPM_STCLEAR_DATA; //------------------------------------------------------------------- // Part 2, section 7.5: TPM_STANY_DATA // available inside TPM only // //typedef struct tdTPM_STANY_DATA //{ // TPM_STRUCTURE_TAG tag; // TPM_NONCE contextNonceSession; // TPM_DIGEST auditDigest; // TPM_CURRENT_TICKS currentTicks; // UINT32 contextCount; // UINT32 contextList[TPM_MIN_SESSION_LIST]; // TPM_SESSION_DATA sessions[TPM_MIN_SESSIONS]; // // The following appear in section 22.6 but not in 7.5 // TPM_DAA_ISSUER DAA_issuerSettings; // TPM_DAA_TPM DAA_tpmSpecific; // TPM_DAA_CONTEXT DAA_session; // TPM_DAA_JOINDATA DAA_joinSession; //} TPM_STANY_DATA; //------------------------------------------------------------------- // Part 2, section 8: PCR Structures typedef BYTE TPM_LOCALITY_SELECTION; #define TPM_LOC_FOUR (((UINT32)1)<<4) #define TPM_LOC_THREE (((UINT32)1)<<3) #define TPM_LOC_TWO (((UINT32)1)<<2) #define TPM_LOC_ONE (((UINT32)1)<<1) #define TPM_LOC_ZERO (((UINT32)1)<<0) typedef struct tdTPM_PCR_SELECTION /* 1.1b */ { UINT16 sizeOfSelect; SIZEIS(sizeOfSelect) BYTE *pcrSelect; } TPM_PCR_SELECTION; typedef struct tdTPM_PCR_COMPOSITE /* 1.1b */ { TPM_PCR_SELECTION select; UINT32 valueSize; SIZEIS(valueSize) TPM_PCRVALUE *pcrValue; } TPM_PCR_COMPOSITE; typedef struct tdTPM_PCR_INFO /* 1.1b */ { TPM_PCR_SELECTION pcrSelection; TPM_COMPOSITE_HASH digestAtRelease; TPM_COMPOSITE_HASH digestAtCreation; } TPM_PCR_INFO; typedef struct tdTPM_PCR_INFO_LONG { TPM_STRUCTURE_TAG tag; TPM_LOCALITY_SELECTION localityAtCreation; TPM_LOCALITY_SELECTION localityAtRelease; TPM_PCR_SELECTION creationPCRSelection; TPM_PCR_SELECTION releasePCRSelection; TPM_COMPOSITE_HASH digestAtCreation; TPM_COMPOSITE_HASH digestAtRelease; } TPM_PCR_INFO_LONG; typedef struct tdTPM_PCR_INFO_SHORT { TPM_PCR_SELECTION pcrSelection; TPM_LOCALITY_SELECTION localityAtRelease; TPM_COMPOSITE_HASH digestAtRelease; } TPM_PCR_INFO_SHORT; typedef struct tdTPM_PCR_ATTRIBUTES { BYTE pcrReset; TPM_LOCALITY_SELECTION pcrExtendLocal; TPM_LOCALITY_SELECTION pcrResetLocal; } TPM_PCR_ATTRIBUTES; //------------------------------------------------------------------- // Part 2, section 9: typedef struct tdTPM_STORED_DATA /* 1.1b */ { TPM_STRUCT_VER ver; UINT32 sealInfoSize; SIZEIS(sealInfoSize) BYTE *sealInfo; UINT32 encDataSize; SIZEIS(encDataSize) BYTE *encData; } TPM_STORED_DATA; typedef struct tdTPM_STORED_DATA12 { TPM_STRUCTURE_TAG tag; TPM_ENTITY_TYPE et; UINT32 sealInfoSize; SIZEIS(sealInfoSize) BYTE *sealInfo; UINT32 encDataSize; SIZEIS(encDataSize) BYTE *encData; } TPM_STORED_DATA12; typedef struct tdTPM_SEALED_DATA /* 1.1b */ { TPM_PAYLOAD_TYPE payload; TPM_SECRET authData; TPM_NONCE tpmProof; TPM_DIGEST storedDigest; UINT32 dataSize; SIZEIS(dataSize) BYTE *data; } TPM_SEALED_DATA; typedef struct tdTPM_SYMMETRIC_KEY /* 1.1b */ { TPM_ALGORITHM_ID algId; TPM_ENC_SCHEME encScheme; UINT16 size; SIZEIS(size) BYTE *data; } TPM_SYMMETRIC_KEY; typedef struct tdTPM_BOUND_DATA { TPM_STRUCT_VER ver; TPM_PAYLOAD_TYPE payload; BYTE *payloadData; // length is implied } TPM_BOUND_DATA; //------------------------------------------------------------------- // Part 2, section 10: TPM_KEY complex typedef struct tdTPM_KEY_PARMS /* 1.1b */ { TPM_ALGORITHM_ID algorithmID; TPM_ENC_SCHEME encScheme; TPM_SIG_SCHEME sigScheme; UINT32 parmSize; SIZEIS(parmSize) BYTE *parms; } TPM_KEY_PARMS; typedef struct tdTPM_RSA_KEY_PARMS /* 1.1b */ { UINT32 keyLength; UINT32 numPrimes; UINT32 exponentSize; SIZEIS(exponentSize) BYTE *exponent; } TPM_RSA_KEY_PARMS; typedef struct tdTPM_SYMMETRIC_KEY_PARMS { UINT32 keyLength; UINT32 blockSize; UINT32 ivSize; SIZEIS(ivSize) BYTE *IV; } TPM_SYMMETRIC_KEY_PARMS; typedef struct tdTPM_STORE_PUBKEY /* 1.1b */ { UINT32 keyLength; SIZEIS(keyLength) BYTE *key; } TPM_STORE_PUBKEY; typedef struct tdTPM_PUBKEY /* 1.1b */ { TPM_KEY_PARMS algorithmParms; TPM_STORE_PUBKEY pubKey; } TPM_PUBKEY; typedef struct tdTPM_STORE_PRIVKEY /* 1.1b */ { UINT32 keyLength; SIZEIS(keyLength) BYTE *key; } TPM_STORE_PRIVKEY; typedef struct tdTPM_STORE_ASYMKEY /* 1.1b */ { TPM_PAYLOAD_TYPE payload; TPM_SECRET usageAuth; TPM_SECRET migrationAuth; TPM_DIGEST pubDataDigest; TPM_STORE_PRIVKEY privKey; } TPM_STORE_ASYMKEY; typedef struct tdTPM_KEY /* 1.1b */ { TPM_STRUCT_VER ver; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_AUTH_DATA_USAGE authDataUsage; TPM_KEY_PARMS algorithmParms; UINT32 PCRInfoSize; SIZEIS(PCRInfoSize) BYTE *PCRInfo; TPM_STORE_PUBKEY pubKey; UINT32 encSize; SIZEIS(encSize) BYTE *encData; } TPM_KEY; typedef struct tdTPM_KEY12 { TPM_STRUCTURE_TAG tag; UINT16 fill; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_AUTH_DATA_USAGE authDataUsage; TPM_KEY_PARMS algorithmParms; UINT32 PCRInfoSize; SIZEIS(PCRInfoSize) BYTE *PCRInfo; TPM_STORE_PUBKEY pubKey; UINT32 encSize; SIZEIS(encSize) BYTE *encData; } TPM_KEY12; typedef struct tdTPM_MIGRATE_ASYMKEY { TPM_PAYLOAD_TYPE payload; TPM_SECRET usageAuth; TPM_DIGEST pubDataDigest; UINT32 partPrivKeyLen; SIZEIS(partPrivKeyLen) BYTE *partPrivKey; } TPM_MIGRATE_ASYMKEY; typedef UINT32 TPM_KEY_CONTROL; #define TPM_KEY_CONTROL_OWNER_EVICT ((UINT32)0x00000001) //------------------------------------------------------------------- // Part 2, section 5.12: TPM_MIGRATIONKEYAUTH typedef struct tdTPM_MIGRATIONKEYAUTH /* 1.1b */ { TPM_PUBKEY migrationKey; TPM_MIGRATE_SCHEME migrationScheme; TPM_DIGEST digest; } TPM_MIGRATIONKEYAUTH; //------------------------------------------------------------------- // Part 2, section 11: Signed Structures typedef struct tdTPM_CERTIFY_INFO /* 1.1b */ { TPM_STRUCT_VER version; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_AUTH_DATA_USAGE authDataUsage; TPM_KEY_PARMS algorithmParms; TPM_DIGEST pubkeyDigest; TPM_NONCE data; TPM_BOOL parentPCRStatus; UINT32 PCRInfoSize; SIZEIS(PCRInfoSize) BYTE *PCRInfo; } TPM_CERTIFY_INFO; typedef struct tdTPM_CERTIFY_INFO2 { TPM_STRUCTURE_TAG tag; BYTE fill; TPM_PAYLOAD_TYPE payloadType; TPM_KEY_USAGE keyUsage; TPM_KEY_FLAGS keyFlags; TPM_AUTH_DATA_USAGE authDataUsage; TPM_KEY_PARMS algorithmParms; TPM_DIGEST pubkeyDigest; TPM_NONCE data; TPM_BOOL parentPCRStatus; UINT32 PCRInfoSize; SIZEIS(PCRInfoSize) BYTE *PCRInfo; UINT32 migrationAuthoritySize; SIZEIS(migrationAuthoritySize) BYTE *migrationAuthority; } TPM_CERTIFY_INFO2; typedef struct tdTPM_QUOTE_INFO /* 1.1b */ { TPM_STRUCT_VER version; BYTE fixed[4]; TPM_COMPOSITE_HASH compositeHash; /* in 1.2 TPM spec, named digestValue */ TPM_NONCE externalData; } TPM_QUOTE_INFO; typedef struct tdTPM_QUOTE_INFO2 { TPM_STRUCTURE_TAG tag; BYTE fixed[4]; TPM_NONCE externalData; TPM_PCR_INFO_SHORT infoShort; } TPM_QUOTE_INFO2; //------------------------------------------------------------------- // Part 2, section 12: Identity Structures typedef struct tdTPM_EK_BLOB { TPM_STRUCTURE_TAG tag; TPM_EK_TYPE ekType; UINT32 blobSize; SIZEIS(blobSize) BYTE *blob; } TPM_EK_BLOB; typedef struct tdTPM_EK_BLOB_ACTIVATE { TPM_STRUCTURE_TAG tag; TPM_SYMMETRIC_KEY sessionKey; TPM_DIGEST idDigest; TPM_PCR_INFO_SHORT pcrInfo; } TPM_EK_BLOB_ACTIVATE; typedef struct tdTPM_EK_BLOB_AUTH { TPM_STRUCTURE_TAG tag; TPM_SECRET authValue; } TPM_EK_BLOB_AUTH; typedef struct tdTPM_IDENTITY_CONTENTS { TPM_STRUCT_VER ver; UINT32 ordinal; TPM_CHOSENID_HASH labelPrivCADigest; TPM_PUBKEY identityPubKey; } TPM_IDENTITY_CONTENTS; typedef struct tdTPM_IDENTITY_REQ /* 1.1b */ { UINT32 asymSize; UINT32 symSize; TPM_KEY_PARMS asymAlgorithm; TPM_KEY_PARMS symAlgorithm; SIZEIS(asymSize) BYTE *asymBlob; SIZEIS(symSize) BYTE *symBlob; } TPM_IDENTITY_REQ; typedef struct tdTPM_IDENTITY_PROOF /* 1.1b */ { TPM_STRUCT_VER ver; UINT32 labelSize; UINT32 identityBindingSize; UINT32 endorsementSize; UINT32 platformSize; UINT32 conformanceSize; TPM_PUBKEY identityKey; SIZEIS(labelSize) BYTE *labelArea; SIZEIS(identityBindingSize) BYTE *identityBinding; SIZEIS(endorsementSize) BYTE *endorsementCredential; SIZEIS(platformSize) BYTE *platformCredential; SIZEIS(conformanceSize) BYTE *conformanceCredential; } TPM_IDENTITY_PROOF; typedef struct tdTPM_ASYM_CA_CONTENTS /* 1.1b */ { TPM_SYMMETRIC_KEY sessionKey; TPM_DIGEST idDigest; } TPM_ASYM_CA_CONTENTS; typedef struct tdTPM_SYM_CA_ATTESTATION { UINT32 credSize; TPM_KEY_PARMS algorithm; SIZEIS(credSize) BYTE *credential; } TPM_SYM_CA_ATTESTATION; //------------------------------------------------------------------- // Part 2, section 15: Tick Structures // Placed here out of order because definitions are used in section 13. typedef struct tdTPM_CURRENT_TICKS { TPM_STRUCTURE_TAG tag; UINT64 currentTicks; UINT16 tickRate; TPM_NONCE tickNonce; } TPM_CURRENT_TICKS; //------------------------------------------------------------------- // Part 2, section 13: Transport structures typedef UINT32 TPM_TRANSPORT_ATTRIBUTES; #define TPM_TRANSPORT_ENCRYPT ((UINT32)0x00000001) #define TPM_TRANSPORT_LOG ((UINT32)0x00000002) #define TPM_TRANSPORT_EXCLUSIVE ((UINT32)0x00000004) typedef struct tdTPM_TRANSPORT_PUBLIC { TPM_STRUCTURE_TAG tag; TPM_TRANSPORT_ATTRIBUTES transAttributes; TPM_ALGORITHM_ID algId; TPM_ENC_SCHEME encScheme; } TPM_TRANSPORT_PUBLIC; typedef struct tdTPM_TRANSPORT_INTERNAL { TPM_STRUCTURE_TAG tag; TPM_AUTHDATA authData; TPM_TRANSPORT_PUBLIC transPublic; TPM_TRANSHANDLE transHandle; TPM_NONCE transNonceEven; TPM_DIGEST transDigest; } TPM_TRANSPORT_INTERNAL; typedef struct tdTPM_TRANSPORT_LOG_IN { TPM_STRUCTURE_TAG tag; TPM_DIGEST parameters; TPM_DIGEST pubKeyHash; } TPM_TRANSPORT_LOG_IN; typedef struct tdTPM_TRANSPORT_LOG_OUT { TPM_STRUCTURE_TAG tag; TPM_CURRENT_TICKS currentTicks; TPM_DIGEST parameters; TPM_MODIFIER_INDICATOR locality; } TPM_TRANSPORT_LOG_OUT; typedef struct tdTPM_TRANSPORT_AUTH { TPM_STRUCTURE_TAG tag; TPM_AUTHDATA authData; } TPM_TRANSPORT_AUTH; //------------------------------------------------------------------- // Part 2, section 14: Audit Structures typedef struct tdTPM_AUDIT_EVENT_IN { TPM_STRUCTURE_TAG tag; TPM_DIGEST inputParms; TPM_COUNTER_VALUE auditCount; } TPM_AUDIT_EVENT_IN; typedef struct tdTPM_AUDIT_EVENT_OUT { TPM_STRUCTURE_TAG tag; TPM_COMMAND_CODE ordinal; TPM_DIGEST outputParms; TPM_COUNTER_VALUE auditCount; TPM_RESULT returnCode; } TPM_AUDIT_EVENT_OUT; //------------------------------------------------------------------- // Part 2, section 16: Return codes #include //------------------------------------------------------------------- // Part 2, section 17: Ordinals #include //------------------------------------------------------------------- // Part 2, section 18: Context structures typedef struct tdTPM_CONTEXT_BLOB { TPM_STRUCTURE_TAG tag; TPM_RESOURCE_TYPE resourceType; TPM_HANDLE handle; BYTE label[16]; UINT32 contextCount; TPM_DIGEST integrityDigest; UINT32 additionalSize; SIZEIS(additionalSize) BYTE *additionalData; UINT32 sensitiveSize; SIZEIS(sensitiveSize) BYTE *sensitiveData; } TPM_CONTEXT_BLOB; typedef struct tdTPM_CONTEXT_SENSITIVE { TPM_STRUCTURE_TAG tag; TPM_NONCE contextNonce; UINT32 internalSize; SIZEIS(internalSize) BYTE *internalData; } TPM_CONTEXT_SENSITIVE; //------------------------------------------------------------------- // Part 2, section 19: NV Structures typedef UINT32 TPM_NV_INDEX; #define TPM_NV_INDEX_LOCK ((UINT32)0xffffffff) #define TPM_NV_INDEX0 ((UINT32)0x00000000) #define TPM_NV_INDEX_DIR ((UINT32)0x10000001) // The reserved index values MAY have their D bit set by the // TPM vendor to permanently reserve the index in the TPM. // e.g. the typical EK certificate would have the D bit set // so the actual address would be 1000f000 #define TPM_NV_INDEX_EKCert ((UINT32)0x0000f000) #define TPM_NV_INDEX_TPM_CC ((UINT32)0x0000f001) #define TPM_NV_INDEX_PlatformCert ((UINT32)0x0000f002) #define TPM_NV_INDEX_Platform_CC ((UINT32)0x0000f003) // The following define ranges of reserved indices. #define TPM_NV_INDEX_TSS_BASE ((UINT32)0x00011100) #define TPM_NV_INDEX_PC_BASE ((UINT32)0x00011200) #define TPM_NV_INDEX_SERVER_BASE ((UINT32)0x00011300) #define TPM_NV_INDEX_MOBILE_BASE ((UINT32)0x00011400) #define TPM_NV_INDEX_PERIPHERAL_BASE ((UINT32)0x00011500) #define TPM_NV_INDEX_GROUP_RESV_BASE ((UINT32)0x00010000) typedef UINT32 TPM_NV_PER_ATTRIBUTES; #define TPM_NV_PER_READ_STCLEAR (((UINT32)1)<<31) #define TPM_NV_PER_AUTHREAD (((UINT32)1)<<18) #define TPM_NV_PER_OWNERREAD (((UINT32)1)<<17) #define TPM_NV_PER_PPREAD (((UINT32)1)<<16) #define TPM_NV_PER_GLOBALLOCK (((UINT32)1)<<15) #define TPM_NV_PER_WRITE_STCLEAR (((UINT32)1)<<14) #define TPM_NV_PER_WRITEDEFINE (((UINT32)1)<<13) #define TPM_NV_PER_WRITEALL (((UINT32)1)<<12) #define TPM_NV_PER_AUTHWRITE (((UINT32)1)<<2) #define TPM_NV_PER_OWNERWRITE (((UINT32)1)<<1) #define TPM_NV_PER_PPWRITE (((UINT32)1)<<0) typedef struct tdTPM_NV_ATTRIBUTES { TPM_STRUCTURE_TAG tag; TPM_NV_PER_ATTRIBUTES attributes; } TPM_NV_ATTRIBUTES; typedef struct tdTPM_NV_DATA_PUBLIC { TPM_STRUCTURE_TAG tag; TPM_NV_INDEX nvIndex; TPM_PCR_INFO_SHORT pcrInfoRead; TPM_PCR_INFO_SHORT pcrInfoWrite; TPM_NV_ATTRIBUTES permission; TPM_BOOL bReadSTClear; TPM_BOOL bWriteSTClear; TPM_BOOL bWriteDefine; UINT32 dataSize; } TPM_NV_DATA_PUBLIC; #if 0 // Internal to TPM: typedef struct tdTPM_NV_DATA_SENSITIVE { TPM_STRUCTURE_TAG tag; TPM_NV_DATA_PUBLIC pubInfo; TPM_AUTHDATA authValue; SIZEIS(pubInfo.dataSize) BYTE *data; } TPM_NV_DATA_SENSITIVE; #endif //------------------------------------------------------------------- // Part 2, section 20: Delegation //------------------------------------------------------------------- // Part 2, section 20.3: Owner Permissions Settings for per1 bits #define TPM_DELEGATE_SetOrdinalAuditStatus (((UINT32)1)<<30) #define TPM_DELEGATE_DirWriteAuth (((UINT32)1)<<29) #define TPM_DELEGATE_CMK_ApproveMA (((UINT32)1)<<28) #define TPM_DELEGATE_NV_WriteValue (((UINT32)1)<<27) #define TPM_DELEGATE_CMK_CreateTicket (((UINT32)1)<<26) #define TPM_DELEGATE_NV_ReadValue (((UINT32)1)<<25) #define TPM_DELEGATE_Delegate_LoadOwnerDelegation (((UINT32)1)<<24) #define TPM_DELEGATE_DAA_Join (((UINT32)1)<<23) #define TPM_DELEGATE_AuthorizeMigrationKey (((UINT32)1)<<22) #define TPM_DELEGATE_CreateMaintenanceArchive (((UINT32)1)<<21) #define TPM_DELEGATE_LoadMaintenanceArchive (((UINT32)1)<<20) #define TPM_DELEGATE_KillMaintenanceFeature (((UINT32)1)<<19) #define TPM_DELEGATE_OwnerReadInternalPub (((UINT32)1)<<18) #define TPM_DELEGATE_ResetLockValue (((UINT32)1)<<17) #define TPM_DELEGATE_OwnerClear (((UINT32)1)<<16) #define TPM_DELEGATE_DisableOwnerClear (((UINT32)1)<<15) #define TPM_DELEGATE_NV_DefineSpace (((UINT32)1)<<14) #define TPM_DELEGATE_OwnerSetDisable (((UINT32)1)<<13) #define TPM_DELEGATE_SetCapability (((UINT32)1)<<12) #define TPM_DELEGATE_MakeIdentity (((UINT32)1)<<11) #define TPM_DELEGATE_ActivateIdentity (((UINT32)1)<<10) #define TPM_DELEGATE_OwnerReadPubek (((UINT32)1)<<9) #define TPM_DELEGATE_DisablePubekRead (((UINT32)1)<<8) #define TPM_DELEGATE_SetRedirection (((UINT32)1)<<7) #define TPM_DELEGATE_FieldUpgrade (((UINT32)1)<<6) #define TPM_DELEGATE_Delegate_UpdateVerification (((UINT32)1)<<5) #define TPM_DELEGATE_CreateCounter (((UINT32)1)<<4) #define TPM_DELEGATE_ReleaseCounterOwner (((UINT32)1)<<3) #define TPM_DELEGATE_DelegateManage (((UINT32)1)<<2) #define TPM_DELEGATE_Delegate_CreateOwnerDelegation (((UINT32)1)<<1) #define TPM_DELEGATE_DAA_Sign (((UINT32)1)<<0) //------------------------------------------------------------------- // Part 2, section 20.3: Key Permissions Settings for per1 bits #define TPM_KEY_DELEGATE_CMK_ConvertMigration (((UINT32)1)<<28) #define TPM_KEY_DELEGATE_TickStampBlob (((UINT32)1)<<27) #define TPM_KEY_DELEGATE_ChangeAuthAsymStart (((UINT32)1)<<26) #define TPM_KEY_DELEGATE_ChangeAuthAsymFinish (((UINT32)1)<<25) #define TPM_KEY_DELEGATE_CMK_CreateKey (((UINT32)1)<<24) #define TPM_KEY_DELEGATE_MigrateKey (((UINT32)1)<<23) #define TPM_KEY_DELEGATE_LoadKey2 (((UINT32)1)<<22) #define TPM_KEY_DELEGATE_EstablishTransport (((UINT32)1)<<21) #define TPM_KEY_DELEGATE_ReleaseTransportSigned (((UINT32)1)<<20) #define TPM_KEY_DELEGATE_Quote2 (((UINT32)1)<<19) #define TPM_KEY_DELEGATE_Sealx (((UINT32)1)<<18) #define TPM_KEY_DELEGATE_MakeIdentity (((UINT32)1)<<17) #define TPM_KEY_DELEGATE_ActivateIdentity (((UINT32)1)<<16) #define TPM_KEY_DELEGATE_GetAuditDigestSigned (((UINT32)1)<<15) #define TPM_KEY_DELEGATE_Sign (((UINT32)1)<<14) #define TPM_KEY_DELEGATE_CertifyKey2 (((UINT32)1)<<13) #define TPM_KEY_DELEGATE_CertifyKey (((UINT32)1)<<12) #define TPM_KEY_DELEGATE_CreateWrapKey (((UINT32)1)<<11) #define TPM_KEY_DELEGATE_CMK_CreateBlob (((UINT32)1)<<10) #define TPM_KEY_DELEGATE_CreateMigrationBlob (((UINT32)1)<<9) #define TPM_KEY_DELEGATE_ConvertMigrationBlob (((UINT32)1)<<8) #define TPM_KEY_DELEGATE_CreateKeyDelegation (((UINT32)1)<<7) #define TPM_KEY_DELEGATE_ChangeAuth (((UINT32)1)<<6) #define TPM_KEY_DELEGATE_GetPubKey (((UINT32)1)<<5) #define TPM_KEY_DELEGATE_UnBind (((UINT32)1)<<4) #define TPM_KEY_DELEGATE_Quote (((UINT32)1)<<3) #define TPM_KEY_DELEGATE_Unseal (((UINT32)1)<<2) #define TPM_KEY_DELEGATE_Seal (((UINT32)1)<<1) #define TPM_KEY_DELEGATE_LoadKey (((UINT32)1)<<0) typedef UINT32 TPM_FAMILY_VERIFICATION; typedef UINT32 TPM_FAMILY_ID; typedef UINT32 TPM_DELEGATE_INDEX; typedef UINT32 TPM_FAMILY_OPERATION; #define TPM_FAMILY_CREATE ((UINT32)0x00000001) #define TPM_FAMILY_ENABLE ((UINT32)0x00000002) #define TPM_FAMILY_ADMIN ((UINT32)0x00000003) #define TPM_FAMILY_INVALIDATE ((UINT32)0x00000004) typedef UINT32 TPM_FAMILY_FLAGS; #define TPM_FAMFLAG_DELEGATE_ADMIN_LOCK (((UINT32)1)<<1) #define TPM_FAMFLAG_ENABLE (((UINT32)1)<<0) typedef struct tdTPM_FAMILY_LABEL { BYTE label; } TPM_FAMILY_LABEL; typedef struct tdTPM_FAMILY_TABLE_ENTRY { TPM_STRUCTURE_TAG tag; TPM_FAMILY_LABEL label; TPM_FAMILY_ID familyID; TPM_FAMILY_VERIFICATION verificationCount; TPM_FAMILY_FLAGS flags; } TPM_FAMILY_TABLE_ENTRY; #define TPM_FAMILY_TABLE_ENTRY_MIN 8 //typedef struct tdTPM_FAMILY_TABLE //{ // TPM_FAMILY_TABLE_ENTRY FamTableRow[TPM_NUM_FAMILY_TABLE_ENTRY_MIN]; //} TPM_FAMILY_TABLE; typedef struct tdTPM_DELEGATE_LABEL { BYTE label; } TPM_DELEGATE_LABEL; typedef UINT32 TPM_DELEGATE_TYPE; #define TPM_DEL_OWNER_BITS ((UINT32)0x00000001) #define TPM_DEL_KEY_BITS ((UINT32)0x00000002) typedef struct tdTPM_DELEGATIONS { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_TYPE delegateType; UINT32 per1; UINT32 per2; } TPM_DELEGATIONS; typedef struct tdTPM_DELEGATE_PUBLIC { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_LABEL label; TPM_PCR_INFO_SHORT pcrInfo; TPM_DELEGATIONS permissions; TPM_FAMILY_ID familyID; TPM_FAMILY_VERIFICATION verificationCount; } TPM_DELEGATE_PUBLIC; typedef struct tdTPM_DELEGATE_TABLE_ROW { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_PUBLIC pub; TPM_SECRET authValue; } TPM_DELEGATE_TABLE_ROW; #define TPM_NUM_DELEGATE_TABLE_ENTRY_MIN 2 //typedef struct tdTPM_DELEGATE_TABLE //{ // TPM_DELEGATE_TABLE_ROW delRow[TPM_NUM_DELEGATE_TABLE_ENTRY_MIN]; //} TPM_DELEGATE_TABLE; typedef struct tdTPM_DELEGATE_SENSITIVE { TPM_STRUCTURE_TAG tag; TPM_SECRET authValue; } TPM_DELEGATE_SENSITIVE; typedef struct tdTPM_DELEGATE_OWNER_BLOB { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_PUBLIC pub; TPM_DIGEST integrityDigest; UINT32 additionalSize; SIZEIS(additionalSize) BYTE *additionalArea; UINT32 sensitiveSize; SIZEIS(sensitiveSize) BYTE *sensitiveArea; } TPM_DELEGATE_OWNER_BLOB; typedef struct tdTPM_DELEGATE_KEY_BLOB { TPM_STRUCTURE_TAG tag; TPM_DELEGATE_PUBLIC pub; TPM_DIGEST integrityDigest; TPM_DIGEST pubKeyDigest; UINT32 additionalSize; SIZEIS(additionalSize) BYTE *additionalArea; UINT32 sensitiveSize; SIZEIS(sensitiveSize) BYTE *sensitiveArea; } TPM_DELEGATE_KEY_BLOB; //------------------------------------------------------------------- // Part 2, section 21.1: TPM_CAPABILITY_AREA typedef UINT32 TPM_CAPABILITY_AREA; /* 1.1b */ #define TPM_CAP_ORD ((UINT32)0x00000001) /* 1.1b */ #define TPM_CAP_ALG ((UINT32)0x00000002) /* 1.1b */ #define TPM_CAP_PID ((UINT32)0x00000003) /* 1.1b */ #define TPM_CAP_FLAG ((UINT32)0x00000004) /* 1.1b */ #define TPM_CAP_PROPERTY ((UINT32)0x00000005) /* 1.1b */ #define TPM_CAP_VERSION ((UINT32)0x00000006) /* 1.1b */ #define TPM_CAP_KEY_HANDLE ((UINT32)0x00000007) /* 1.1b */ #define TPM_CAP_CHECK_LOADED ((UINT32)0x00000008) /* 1.1b */ #define TPM_CAP_SYM_MODE ((UINT32)0x00000009) #define TPM_CAP_KEY_STATUS ((UINT32)0x0000000C) #define TPM_CAP_NV_LIST ((UINT32)0x0000000D) #define TPM_CAP_MFR ((UINT32)0x00000010) #define TPM_CAP_NV_INDEX ((UINT32)0x00000011) #define TPM_CAP_TRANS_ALG ((UINT32)0x00000012) #define TPM_CAP_HANDLE ((UINT32)0x00000014) #define TPM_CAP_TRANS_ES ((UINT32)0x00000015) #define TPM_CAP_AUTH_ENCRYPT ((UINT32)0x00000017) #define TPM_CAP_SELECT_SIZE ((UINT32)0x00000018) #define TPM_CAP_DA_LOGIC ((UINT32)0x00000019) #define TPM_CAP_VERSION_VAL ((UINT32)0x0000001A) // Part 2, section 21.1: Subcap values for CAP_FLAG #define TPM_CAP_FLAG_PERMANENT ((UINT32)0x00000108) #define TPM_CAP_FLAG_VOLATILE ((UINT32)0x00000109) //------------------------------------------------------------------- // Part 2, section 21.2: Subcap values for CAP_PROPERTY #define TPM_CAP_PROP_PCR ((UINT32)0x00000101) /* 1.1b */ #define TPM_CAP_PROP_DIR ((UINT32)0x00000102) /* 1.1b */ #define TPM_CAP_PROP_MANUFACTURER ((UINT32)0x00000103) /* 1.1b */ #define TPM_CAP_PROP_KEYS ((UINT32)0x00000104) #define TPM_CAP_PROP_SLOTS (TPM_CAP_PROP_KEYS) #define TPM_CAP_PROP_MIN_COUNTER ((UINT32)0x00000107) #define TPM_CAP_PROP_AUTHSESS ((UINT32)0x0000010A) #define TPM_CAP_PROP_TRANSSESS ((UINT32)0x0000010B) #define TPM_CAP_PROP_COUNTERS ((UINT32)0x0000010C) #define TPM_CAP_PROP_MAX_AUTHSESS ((UINT32)0x0000010D) #define TPM_CAP_PROP_MAX_TRANSSESS ((UINT32)0x0000010E) #define TPM_CAP_PROP_MAX_COUNTERS ((UINT32)0x0000010F) #define TPM_CAP_PROP_MAX_KEYS ((UINT32)0x00000110) #define TPM_CAP_PROP_OWNER ((UINT32)0x00000111) #define TPM_CAP_PROP_CONTEXT ((UINT32)0x00000112) #define TPM_CAP_PROP_MAX_CONTEXT ((UINT32)0x00000113) #define TPM_CAP_PROP_FAMILYROWS ((UINT32)0x00000114) #define TPM_CAP_PROP_TIS_TIMEOUT ((UINT32)0x00000115) #define TPM_CAP_PROP_STARTUP_EFFECT ((UINT32)0x00000116) #define TPM_CAP_PROP_DELEGATE_ROW ((UINT32)0x00000117) #define TPM_CAP_PROP_MAX_DAASESS ((UINT32)0x00000119) #define TPM_CAP_PROP_DAA_MAX TPM_CAP_PROP_MAX_DAASESS #define TPM_CAP_PROP_DAASESS ((UINT32)0x0000011A) #define TPM_CAP_PROP_SESSION_DAA TPM_CAP_PROP_DAASESS #define TPM_CAP_PROP_CONTEXT_DIST ((UINT32)0x0000011B) #define TPM_CAP_PROP_DAA_INTERRUPT ((UINT32)0x0000011C) #define TPM_CAP_PROP_SESSIONS ((UINT32)0x0000011D) #define TPM_CAP_PROP_MAX_SESSIONS ((UINT32)0x0000011E) #define TPM_CAP_PROP_CMK_RESTRICTION ((UINT32)0x0000011F) #define TPM_CAP_PROP_DURATION ((UINT32)0x00000120) #define TPM_CAP_PROP_ACTIVE_COUNTER ((UINT32)0x00000122) #define TPM_CAP_PROP_NV_AVAILABLE ((UINT32)0x00000123) #define TPM_CAP_PROP_INPUT_BUFFER ((UINT32)0x00000124) // Part 2, section 21.4: SetCapability Values #define TPM_SET_PERM_FLAGS ((UINT32)0x00000001) #define TPM_SET_PERM_DATA ((UINT32)0x00000002) #define TPM_SET_STCLEAR_FLAGS ((UINT32)0x00000003) #define TPM_SET_STCLEAR_DATA ((UINT32)0x00000004) #define TPM_SET_STANY_FLAGS ((UINT32)0x00000005) #define TPM_SET_STANY_DATA ((UINT32)0x00000006) #define TPM_SET_VENDOR ((UINT32)0x00000007) // Part 2, section 21.6: TPM_CAP_VERSION_INFO typedef struct tdTPM_CAP_VERSION_INFO { TPM_STRUCTURE_TAG tag; TPM_VERSION version; UINT16 specLevel; BYTE errataRev; BYTE tpmVendorID[4]; UINT16 vendorSpecificSize; SIZEIS(vendorSpecificSize) BYTE *vendorSpecific; } TPM_CAP_VERSION_INFO; // Part 2, section 21.9: TPM_DA_STATE // out of order to make it available for structure definitions typedef BYTE TPM_DA_STATE; #define TPM_DA_STATE_INACTIVE (0x00) #define TPM_DA_STATE_ACTIVE (0x01) // Part 2, section 21.10: TPM_DA_ACTION_TYPE typedef struct tdTPM_DA_ACTION_TYPE { TPM_STRUCTURE_TAG tag; UINT32 actions; } TPM_DA_ACTION_TYPE; #define TPM_DA_ACTION_TIMEOUT ((UINT32)0x00000001) #define TPM_DA_ACTION_DISABLE ((UINT32)0x00000002) #define TPM_DA_ACTION_DEACTIVATE ((UINT32)0x00000004) #define TPM_DA_ACTION_FAILURE_MODE ((UINT32)0x00000008) // Part 2, section 21.7: TPM_DA_INFO typedef struct tdTPM_DA_INFO { TPM_STRUCTURE_TAG tag; TPM_DA_STATE state; UINT16 currentCount; UINT16 threshholdCount; TPM_DA_ACTION_TYPE actionAtThreshold; UINT32 actionDependValue; UINT32 vendorDataSize; SIZEIS(vendorDataSize) BYTE *vendorData; } TPM_DA_INFO; // Part 2, section 21.8: TPM_DA_INFO_LIMITED typedef struct tdTPM_DA_INFO_LIMITED { TPM_STRUCTURE_TAG tag; TPM_DA_STATE state; TPM_DA_ACTION_TYPE actionAtThreshold; UINT32 vendorDataSize; SIZEIS(vendorDataSize) BYTE *vendorData; } TPM_DA_INFO_LIMITED; //------------------------------------------------------------------- // Part 2, section 22: DAA Structures #define TPM_DAA_SIZE_r0 (43) #define TPM_DAA_SIZE_r1 (43) #define TPM_DAA_SIZE_r2 (128) #define TPM_DAA_SIZE_r3 (168) #define TPM_DAA_SIZE_r4 (219) #define TPM_DAA_SIZE_NT (20) #define TPM_DAA_SIZE_v0 (128) #define TPM_DAA_SIZE_v1 (192) #define TPM_DAA_SIZE_NE (256) #define TPM_DAA_SIZE_w (256) #define TPM_DAA_SIZE_issuerModulus (256) #define TPM_DAA_power0 (104) #define TPM_DAA_power1 (1024) typedef struct tdTPM_DAA_ISSUER { TPM_STRUCTURE_TAG tag; TPM_DIGEST DAA_digest_R0; TPM_DIGEST DAA_digest_R1; TPM_DIGEST DAA_digest_S0; TPM_DIGEST DAA_digest_S1; TPM_DIGEST DAA_digest_n; TPM_DIGEST DAA_digest_gamma; BYTE DAA_generic_q[26]; } TPM_DAA_ISSUER; typedef struct tdTPM_DAA_TPM { TPM_STRUCTURE_TAG tag; TPM_DIGEST DAA_digestIssuer; TPM_DIGEST DAA_digest_v0; TPM_DIGEST DAA_digest_v1; TPM_DIGEST DAA_rekey; UINT32 DAA_count; } TPM_DAA_TPM; typedef struct tdTPM_DAA_CONTEXT { TPM_STRUCTURE_TAG tag; TPM_DIGEST DAA_digestContext; TPM_DIGEST DAA_digest; TPM_DAA_CONTEXT_SEED DAA_contextSeed; BYTE DAA_scratch[256]; BYTE DAA_stage; } TPM_DAA_CONTEXT; typedef struct tdTPM_DAA_JOINDATA { BYTE DAA_join_u0[128]; BYTE DAA_join_u1[138]; TPM_DIGEST DAA_digest_n0; } TPM_DAA_JOINDATA; typedef struct tdTPM_DAA_BLOB { TPM_STRUCTURE_TAG tag; TPM_RESOURCE_TYPE resourceType; BYTE label[16]; TPM_DIGEST blobIntegrity; UINT32 additionalSize; SIZEIS(additionalSize) BYTE *additionalData; UINT32 sensitiveSize; SIZEIS(sensitiveSize) BYTE *sensitiveData; } TPM_DAA_BLOB; typedef struct tdTPM_DAA_SENSITIVE { TPM_STRUCTURE_TAG tag; UINT32 internalSize; SIZEIS(internalSize) BYTE *internalData; } TPM_DAA_SENSITIVE; //------------------------------------------------------------------- // Part 2, section 23: Redirection // This section of the TPM spec defines exactly one value but does not // give it a name. The definition of TPM_SetRedirection in Part3 // refers to exactly one name but does not give its value. We join // them here. #define TPM_REDIR_GPIO (0x00000001) //------------------------------------------------------------------- // Part 2, section 24.6: TPM_SYM_MODE // Deprecated by TPM 1.2 spec typedef UINT32 TPM_SYM_MODE; #define TPM_SYM_MODE_ECB (0x00000001) #define TPM_SYM_MODE_CBC (0x00000002) #define TPM_SYM_MODE_CFB (0x00000003) #endif // __TPM_H__ trousers-0.3.15/src/include/tss/tcs_structs.h0000664000175000017510000000174513663651711020537 0ustar deboradebora/*++ TSS Core Service structures */ #ifndef __TCS_STRUCT_H__ #define __TCS_STRUCT_H__ #include #include #include typedef struct tdTCS_AUTH { TCS_AUTHHANDLE AuthHandle; TPM_NONCE NonceOdd; // system TPM_NONCE NonceEven; // TPM TSS_BOOL fContinueAuthSession; TPM_AUTHDATA HMAC; } TCS_AUTH; // This is kept for legacy compatibility typedef TCS_AUTH TPM_AUTH; typedef struct tdTCS_LOADKEY_INFO { TSS_UUID keyUUID; TSS_UUID parentKeyUUID; TPM_DIGEST paramDigest; // SHA1 digest of the TPM_LoadKey // Command input parameters // As defined in TPM Main Specification TPM_AUTH authData; // Data regarding a valid auth // Session including the // HMAC digest } TCS_LOADKEY_INFO; #endif // __TCS_STRUCT_H__ trousers-0.3.15/src/include/tss/tss_error.h0000664000175000017510000003621113663651711020175 0ustar deboradebora/*++ TSS error return codes --*/ #ifndef __TSS_ERROR_H__ #define __TSS_ERROR_H__ #include // // error coding scheme for a Microsoft Windows platform - // refer to the TSS Specification Parts // // Values are 32 bit values layed out as follows: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +---+-+-+-----------------------+-------+-----------------------+ // |Lev|C|R| Facility | Layer | Code | // +---+-+-+-----------------------+-------+-----------------------+ // | Platform specific coding | TSS error coding system | // +---+-+-+-----------------------+-------+-----------------------+ // // Lev - is the Level code // // 00 - Success // 01 - Informational // 10 - Warning // 11 - Error // // C - is the Customer code flag (must actually be set) // // R - is a reserved bit (unused) // // Facility - is the facility code: TCPA: proposal 0x028 // // Code - is the facility's status code // // // definitions for the code level information // #define TSS_LEVEL_SUCCESS 0x00 // code level success #define TSS_LEVEL_INFO 0x40000000L // code level information #define TSS_LEVEL_WARNING 0x80000000L // code level warning #define TSS_LEVEL_ERROR 0xC0000000L // code level error // // some defines for the platform specific information // #define FACILITY_TSS 0x28L // facility number for TCPA return codes #define FACILITY_TSS_CODEPOS (FACILITY_TSS << 16) // shift the facility info to the code // position #define TSS_CUSTOM_CODEFLAG 0x20000000L // bit position for the custom flag in // return code // // // TSS error return codes // // #ifndef TSS_E_BASE #define TSS_E_BASE 0x00000000L #endif // TSS_E_BASE #ifndef TSS_W_BASE #define TSS_W_BASE 0x00000000L #endif // TSS_W_BASE #ifndef TSS_I_BASE #define TSS_I_BASE 0x00000000L #endif // TSS_I_BASE // // basic error return codes common to all TSS Service Provider Interface methods // and returned by all TSS SW stack components // // // MessageId: TSS_SUCCESS // // MessageText: // // Successful completion of the operation. // #define TSS_SUCCESS (UINT32)(0x00000000L) // // MessageId: TSS_E_FAIL // // MessageText: // // An internal error has been detected, but the source is unknown. // #define TSS_E_FAIL (UINT32)(TSS_E_BASE + 0x002L) // // MessageId: TSS_E_BAD_PARAMETER // // MessageText: // // One or more parameter is bad. // #define TSS_E_BAD_PARAMETER (UINT32)(TSS_E_BASE + 0x003L) // // MessageId: TSS_E_INTERNAL_ERROR // // MessageText: // // An internal SW error has been detected. // #define TSS_E_INTERNAL_ERROR (UINT32)(TSS_E_BASE + 0x004L) // // MessageId: TSS_E_OUTOFMEMORY // // MessageText: // // Ran out of memory. // #define TSS_E_OUTOFMEMORY (UINT32)(TSS_E_BASE + 0x005L) // // MessageId: TSS_E_NOTIMPL // // MessageText: // // Not implemented. // #define TSS_E_NOTIMPL (UINT32)(TSS_E_BASE + 0x006L) // // MessageId: TSS_E_KEY_ALREADY_REGISTERED // // MessageText: // // Key is already registered // #define TSS_E_KEY_ALREADY_REGISTERED (UINT32)(TSS_E_BASE + 0x008L) // // MessageId: TSS_E_TPM_UNEXPECTED // // MessageText: // // An unexpected TPM error has occurred. // #define TSS_E_TPM_UNEXPECTED (UINT32)(TSS_E_BASE + 0x010L) // // MessageId: TSS_E_COMM_FAILURE // // MessageText: // // A communications error with the TPM has been detected. // #define TSS_E_COMM_FAILURE (UINT32)(TSS_E_BASE + 0x011L) // // MessageId: TSS_E_TIMEOUT // // MessageText: // // The operation has timed out. // #define TSS_E_TIMEOUT (UINT32)(TSS_E_BASE + 0x012L) // // MessageId: TSS_E_TPM_UNSUPPORTED_FEATURE // // MessageText: // // The TPM does not support the requested feature. // #define TSS_E_TPM_UNSUPPORTED_FEATURE (UINT32)(TSS_E_BASE + 0x014L) // // MessageId: TSS_E_CANCELED // // MessageText: // // The action was canceled by request. // #define TSS_E_CANCELED (UINT32)(TSS_E_BASE + 0x016L) // // MessageId: TSS_E_PS_KEY_NOTFOUND // // MessageText: // // The key cannot be found in the persistent storage database. // #define TSS_E_PS_KEY_NOTFOUND (UINT32)(TSS_E_BASE + 0x020L) // // MessageId: TSS_E_PS_KEY_EXISTS // // MessageText: // // The key already exists in the persistent storage database. // #define TSS_E_PS_KEY_EXISTS (UINT32)(TSS_E_BASE + 0x021L) // // MessageId: TSS_E_PS_BAD_KEY_STATE // // MessageText: // // The key data set not valid in the persistent storage database. // #define TSS_E_PS_BAD_KEY_STATE (UINT32)(TSS_E_BASE + 0x022L) // // error codes returned by specific TSS Service Provider Interface methods // offset TSS_TSPI_OFFSET // // // MessageId: TSS_E_INVALID_OBJECT_TYPE // // MessageText: // // Object type not valid for this operation. // #define TSS_E_INVALID_OBJECT_TYPE (UINT32)(TSS_E_BASE + 0x101L) // // MessageId: TSS_E_NO_CONNECTION // // MessageText: // // Core Service connection doesn't exist. // #define TSS_E_NO_CONNECTION (UINT32)(TSS_E_BASE + 0x102L) // // MessageId: TSS_E_CONNECTION_FAILED // // MessageText: // // Core Service connection failed. // #define TSS_E_CONNECTION_FAILED (UINT32)(TSS_E_BASE + 0x103L) // // MessageId: TSS_E_CONNECTION_BROKEN // // MessageText: // // Communication with Core Service failed. // #define TSS_E_CONNECTION_BROKEN (UINT32)(TSS_E_BASE + 0x104L) // // MessageId: TSS_E_HASH_INVALID_ALG // // MessageText: // // Invalid hash algorithm. // #define TSS_E_HASH_INVALID_ALG (UINT32)(TSS_E_BASE + 0x105L) // // MessageId: TSS_E_HASH_INVALID_LENGTH // // MessageText: // // Hash length is inconsistent with hash algorithm. // #define TSS_E_HASH_INVALID_LENGTH (UINT32)(TSS_E_BASE + 0x106L) // // MessageId: TSS_E_HASH_NO_DATA // // MessageText: // // Hash object has no internal hash value. // #define TSS_E_HASH_NO_DATA (UINT32)(TSS_E_BASE + 0x107L) // // MessageId: TSS_E_INVALID_ATTRIB_FLAG // // MessageText: // // Flag value for attrib-functions inconsistent. // #define TSS_E_INVALID_ATTRIB_FLAG (UINT32)(TSS_E_BASE + 0x109L) // // MessageId: TSS_E_INVALID_ATTRIB_SUBFLAG // // MessageText: // // Subflag value for attrib-functions inconsistent. // #define TSS_E_INVALID_ATTRIB_SUBFLAG (UINT32)(TSS_E_BASE + 0x10AL) // // MessageId: TSS_E_INVALID_ATTRIB_DATA // // MessageText: // // Data for attrib-functions invalid. // #define TSS_E_INVALID_ATTRIB_DATA (UINT32)(TSS_E_BASE + 0x10BL) // // MessageId: TSS_E_INVALID_OBJECT_INITFLAG // // MessageText: // // Wrong flag information for object creation. // // The alternate spelling is supported to be compatible with a typo // in the 1.1b header files. // #define TSS_E_INVALID_OBJECT_INIT_FLAG (UINT32)(TSS_E_BASE + 0x10CL) #define TSS_E_INVALID_OBJECT_INITFLAG TSS_E_INVALID_OBJECT_INIT_FLAG // // MessageId: TSS_E_NO_PCRS_SET // // MessageText: // // No PCR register are selected or set. // #define TSS_E_NO_PCRS_SET (UINT32)(TSS_E_BASE + 0x10DL) // // MessageId: TSS_E_KEY_NOT_LOADED // // MessageText: // // The addressed key is currently not loaded. // #define TSS_E_KEY_NOT_LOADED (UINT32)(TSS_E_BASE + 0x10EL) // // MessageId: TSS_E_KEY_NOT_SET // // MessageText: // // No key information is currently available. // #define TSS_E_KEY_NOT_SET (UINT32)(TSS_E_BASE + 0x10FL) // // MessageId: TSS_E_VALIDATION_FAILED // // MessageText: // // Internal validation of data failed. // #define TSS_E_VALIDATION_FAILED (UINT32)(TSS_E_BASE + 0x110L) // // MessageId: TSS_E_TSP_AUTHREQUIRED // // MessageText: // // Authorization is required. // #define TSS_E_TSP_AUTHREQUIRED (UINT32)(TSS_E_BASE + 0x111L) // // MessageId: TSS_E_TSP_AUTH2REQUIRED // // MessageText: // // Multiple authorization is required. // #define TSS_E_TSP_AUTH2REQUIRED (UINT32)(TSS_E_BASE + 0x112L) // // MessageId: TSS_E_TSP_AUTHFAIL // // MessageText: // // Authorization failed. // #define TSS_E_TSP_AUTHFAIL (UINT32)(TSS_E_BASE + 0x113L) // // MessageId: TSS_E_TSP_AUTH2FAIL // // MessageText: // // Multiple authorization failed. // #define TSS_E_TSP_AUTH2FAIL (UINT32)(TSS_E_BASE + 0x114L) // // MessageId: TSS_E_KEY_NO_MIGRATION_POLICY // // MessageText: // // There's no migration policy object set for the addressed key. // #define TSS_E_KEY_NO_MIGRATION_POLICY (UINT32)(TSS_E_BASE + 0x115L) // // MessageId: TSS_E_POLICY_NO_SECRET // // MessageText: // // No secret information is currently available for the addressed policy object. // #define TSS_E_POLICY_NO_SECRET (UINT32)(TSS_E_BASE + 0x116L) // // MessageId: TSS_E_INVALID_OBJ_ACCESS // // MessageText: // // The operation failed due to an invalid object status. // #define TSS_E_INVALID_OBJ_ACCESS (UINT32)(TSS_E_BASE + 0x117L) // // MessageId: TSS_E_INVALID_ENCSCHEME // // MessageText: // // // #define TSS_E_INVALID_ENCSCHEME (UINT32)(TSS_E_BASE + 0x118L) // // MessageId: TSS_E_INVALID_SIGSCHEME // // MessageText: // // // #define TSS_E_INVALID_SIGSCHEME (UINT32)(TSS_E_BASE + 0x119L) // // MessageId: TSS_E_ENC_INVALID_LENGTH // // MessageText: // // // #define TSS_E_ENC_INVALID_LENGTH (UINT32)(TSS_E_BASE + 0x120L) // // MessageId: TSS_E_ENC_NO_DATA // // MessageText: // // // #define TSS_E_ENC_NO_DATA (UINT32)(TSS_E_BASE + 0x121L) // // MessageId: TSS_E_ENC_INVALID_TYPE // // MessageText: // // // #define TSS_E_ENC_INVALID_TYPE (UINT32)(TSS_E_BASE + 0x122L) // // MessageId: TSS_E_INVALID_KEYUSAGE // // MessageText: // // // #define TSS_E_INVALID_KEYUSAGE (UINT32)(TSS_E_BASE + 0x123L) // // MessageId: TSS_E_VERIFICATION_FAILED // // MessageText: // // // #define TSS_E_VERIFICATION_FAILED (UINT32)(TSS_E_BASE + 0x124L) // // MessageId: TSS_E_HASH_NO_IDENTIFIER // // MessageText: // // Hash algorithm identifier not set. // #define TSS_E_HASH_NO_IDENTIFIER (UINT32)(TSS_E_BASE + 0x125L) // // MessageId: TSS_E_INVALID_HANDLE // // MessageText: // // An invalid handle // #define TSS_E_INVALID_HANDLE (UINT32)(TSS_E_BASE + 0x126L) // // MessageId: TSS_E_SILENT_CONTEXT // // MessageText: // // A silent context requires user input // #define TSS_E_SILENT_CONTEXT (UINT32)(TSS_E_BASE + 0x127L) // // MessageId: TSS_E_EK_CHECKSUM // // MessageText: // // TSP is instructed to verify the EK checksum and it does not verify. // #define TSS_E_EK_CHECKSUM (UINT32)(TSS_E_BASE + 0x128L) // // MessageId: TSS_E_DELGATION_NOTSET // // MessageText: // // The Policy object does not have a delegation blob set. // #define TSS_E_DELEGATION_NOTSET (UINT32)(TSS_E_BASE + 0x129L) // // MessageId: TSS_E_DELFAMILY_NOTFOUND // // MessageText: // // The specified delegation family was not found // #define TSS_E_DELFAMILY_NOTFOUND (UINT32)(TSS_E_BASE + 0x130L) // // MessageId: TSS_E_DELFAMILY_ROWEXISTS // // MessageText: // // The specified delegation family table row is already in use and // the command flags does not allow the TSS to overwrite the existing // entry. // #define TSS_E_DELFAMILY_ROWEXISTS (UINT32)(TSS_E_BASE + 0x131L) // // MessageId: TSS_E_VERSION_MISMATCH // // MessageText: // // The specified delegation family table row is already in use and // the command flags does not allow the TSS to overwrite the existing // entry. // #define TSS_E_VERSION_MISMATCH (UINT32)(TSS_E_BASE + 0x132L) // // MessageId: TSS_E_DAA_AR_DECRYPTION_ERROR // // Decryption of the encrypted pseudonym has failed, due to // either a wrong secret key or a wrong decryption condition. // #define TSS_E_DAA_AR_DECRYPTION_ERROR (UINT32)(TSS_E_BASE + 0x133L) // // MessageId: TSS_E_DAA_AUTHENTICATION_ERROR // // The TPM could not be authenticated by the DAA Issuer. // #define TSS_E_DAA_AUTHENTICATION_ERROR (UINT32)(TSS_E_BASE + 0x134L) // // MessageId: TSS_E_DAA_CHALLENGE_RESPONSE_ERROR // // DAA Challenge response error. // #define TSS_E_DAA_CHALLENGE_RESPONSE_ERROR (UINT32)(TSS_E_BASE + 0x135L) // // MessageId: TSS_E_DAA_CREDENTIAL_PROOF_ERROR // // Verification of the credential TSS_DAA_CRED_ISSUER issued by // the DAA Issuer has failed. // #define TSS_E_DAA_CREDENTIAL_PROOF_ERROR (UINT32)(TSS_E_BASE + 0x136L) // // MessageId: TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR // // Verification of the platform's credential request // TSS_DAA_CREDENTIAL_REQUEST has failed. // #define TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR (UINT32)(TSS_E_BASE + 0x137L) // // MessageId: TSS_E_DAA_ISSUER_KEY_ERROR // // DAA Issuer's authentication key chain could not be verified or // is not correct. // #define TSS_E_DAA_ISSUER_KEY_ERROR (UINT32)(TSS_E_BASE + 0x138L) // // MessageId: TSS_E_DAA_PSEUDONYM_ERROR // // While verifying the pseudonym of the TPM, the private key of the // TPM was found on the rogue list. // #define TSS_E_DAA_PSEUDONYM_ERROR (UINT32)(TSS_E_BASE + 0x139L) // // MessageId: TSS_E_INVALID_RESOURCE // // Pointer to memory wrong. // #define TSS_E_INVALID_RESOURCE (UINT32)(TSS_E_BASE + 0x13AL) // // MessageId: TSS_E_NV_AREA_EXIST // // The NV area referenced already exists // #define TSS_E_NV_AREA_EXIST (UINT32)(TSS_E_BASE + 0x13BL) // // MessageId: TSS_E_NV_AREA_NOT_EXIST // // The NV area referenced doesn't exist // #define TSS_E_NV_AREA_NOT_EXIST (UINT32)(TSS_E_BASE + 0x13CL) // // MessageId: TSS_E_TSP_TRANS_AUTHFAIL // // The transport session authorization failed // #define TSS_E_TSP_TRANS_AUTHFAIL (UINT32)(TSS_E_BASE + 0x13DL) // // MessageId: TSS_E_TSP_TRANS_AUTHREQUIRED // // Authorization for transport is required // #define TSS_E_TSP_TRANS_AUTHREQUIRED (UINT32)(TSS_E_BASE + 0x13EL) // // MessageId: TSS_E_TSP_TRANS_NOT_EXCLUSIVE // // A command was executed outside of an exclusive transport session. // #define TSS_E_TSP_TRANS_NOTEXCLUSIVE (UINT32)(TSS_E_BASE + 0x13FL) // // MessageId: TSS_E_TSP_TRANS_FAIL // // Generic transport protection error. // #define TSS_E_TSP_TRANS_FAIL (UINT32)(TSS_E_BASE + 0x140L) // // MessageId: TSS_E_TSP_TRANS_NO_PUBKEY // // A command could not be executed through a logged transport session // because the command used a key and the key's public key is not // known to the TSP. // #define TSS_E_TSP_TRANS_NO_PUBKEY (UINT32)(TSS_E_BASE + 0x141L) // // MessageId: TSS_E_NO_ACTIVE_COUNTER // // The TPM active counter has not been set yet. // #define TSS_E_NO_ACTIVE_COUNTER (UINT32)(TSS_E_BASE + 0x142L) #endif // __TSS_ERROR_H__ trousers-0.3.15/src/include/tss/compat11b.h0000664000175000017510000002254413663651711017746 0ustar deboradebora #ifndef __COMPAT11B_H__ #define __COMPAT11B_H__ #include #define TCPA_Vendor_Specific32 TPM_Vendor_Specific32 #define TCPA_Vendor_Specific8 TPM_Vendor_Specific8 typedef TSS_UNICODE UNICODE; typedef TPM_DIGEST TCPA_DIGEST; typedef TPM_NONCE TCPA_NONCE; typedef TPM_NONCE TCPA_SALT_NONCE; typedef TPM_PUBKEY TCPA_PUBKEY; typedef TPM_SECRET TCPA_SECRET; typedef TPM_KEY TCPA_KEY; typedef TPM_DIRVALUE TCPA_DIRVALUE; typedef TPM_COMMAND_CODE TCPA_COMMAND_CODE; typedef TPM_BOUND_DATA TCPA_BOUND_DATA; typedef TPM_STRUCT_VER TCPA_VERSION; typedef TPM_RESULT TCPA_RESULT; typedef TPM_PAYLOAD_TYPE TCPA_PAYLOAD_TYPE; typedef TPM_STORE_PRIVKEY TCPA_STORE_PRIVKEY; typedef TPM_CHOSENID_HASH TCPA_CHOSENID_HASH; typedef TPM_SYMMETRIC_KEY TCPA_SYMMETRIC_KEY; typedef TPM_PCR_INFO TCPA_PCR_INFO; typedef TPM_PCR_SELECTION TCPA_PCR_SELECTION; typedef TPM_STORED_DATA TCPA_STORED_DATA; typedef TPM_SEALED_DATA TCPA_SEALED_DATA; typedef TPM_KEY_FLAGS TCPA_KEY_FLAGS; typedef TPM_KEY_PARMS TCPA_KEY_PARMS; typedef TPM_STORE_PUBKEY TCPA_STORE_PUBKEY; typedef TPM_MIGRATIONKEYAUTH TCPA_MIGRATIONKEYAUTH; typedef TPM_RSA_KEY_PARMS TCPA_RSA_KEY_PARMS; typedef TPM_CERTIFY_INFO TCPA_CERTIFY_INFO; typedef TPM_STORE_ASYMKEY TCPA_STORE_ASYMKEY; typedef TPM_ENCAUTH TCPA_ENCAUTH; typedef TPM_PCRINDEX TCPA_PCRINDEX; typedef TPM_PCRVALUE TCPA_PCRVALUE; typedef TPM_DIRINDEX TCPA_DIRINDEX; typedef TPM_PROTOCOL_ID TCPA_PROTOCOL_ID; typedef TPM_ALGORITHM_ID TCPA_ALGORITHM_ID; typedef TPM_ENTITY_TYPE TCPA_ENTITY_TYPE; typedef TPM_CAPABILITY_AREA TCPA_CAPABILITY_AREA; typedef TPM_HMAC TCPA_HMAC; typedef TPM_MIGRATE_SCHEME TCPA_MIGRATE_SCHEME; typedef TPM_PHYSICAL_PRESENCE TCPA_PHYSICAL_PRESENCE; typedef TPM_KEY_HANDLE TCPA_KEY_HANDLE; typedef TPM_KEY_HANDLE_LIST TCPA_KEY_HANDLE_LIST; typedef TPM_PCR_COMPOSITE TCPA_PCR_COMPOSITE; typedef TPM_AUTH_DATA_USAGE TCPA_AUTH_DATA_USAGE; typedef TPM_AUTHDATA TCPA_AUTHDATA; typedef TPM_KEY_USAGE TCPA_KEY_USAGE; typedef TPM_COMPOSITE_HASH TCPA_COMPOSITE_HASH; typedef TPM_QUOTE_INFO TCPA_QUOTE_INFO; typedef TPM_TAG TCPA_TAG; typedef TPM_ENC_SCHEME TCPA_ENC_SCHEME; typedef TPM_SIG_SCHEME TCPA_SIG_SCHEME; typedef TPM_STARTUP_TYPE TCPA_STARTUP_TYPE; typedef TPM_AUTHHANDLE TCPA_AUTHHANDLE; typedef TPM_SYM_CA_ATTESTATION TCPA_SYM_CA_ATTESTATION; typedef TPM_ASYM_CA_CONTENTS TCPA_ASYM_CA_CONTENTS; typedef TPM_IDENTITY_REQ TCPA_IDENTITY_REQ; typedef TPM_IDENTITY_PROOF TCPA_IDENTITY_PROOF; // These were removed from the 1.2 TPM spec typedef UINT32 TCPA_ENCHANDLE; typedef UINT32 TCPA_EVENTTYPE; typedef struct tdTCPA_AUDIT_EVENT { TCPA_COMMAND_CODE ordinal; TCPA_RESULT returncode; } TCPA_AUDIT_EVENT; #define TCPA_SHA1_160_HASH_LEN TPM_SHA1_160_HASH_LEN #define TCPA_SHA1BASED_NONCE_LEN TPM_SHA1BASED_NONCE_LEN #define redirection TSS_KEYFLAG_REDIRECTION #define migratable TSS_KEYFLAG_MIGRATABLE #define volatileKey TSS_KEYFLAG_VOLATILEKEY #define TCPA_ET_KEYHANDLE TPM_ET_KEYHANDLE #define TCPA_ET_KEY TPM_ET_KEY #define TCPA_ET_OWNER TPM_ET_OWNER #define TCPA_ET_SRK TPM_ET_SRK #define TCPA_ET_DATA TPM_ET_DATA #define TCPA_PID_OIAP TPM_PID_OIAP #define TCPA_PID_OSAP TPM_PID_OSAP #define TCPA_PID_ADIP TPM_PID_ADIP #define TCPA_PID_ADCP TPM_PID_ADCP #define TCPA_PID_OWNER TPM_PID_OWNER #define TCPA_PT_ASYM TPM_PT_ASYM #define TCPA_PT_BIND TPM_PT_BIND #define TCPA_PT_MIGRATE TPM_PT_MIGRATE #define TCPA_PT_MAINT TPM_PT_MAINT #define TCPA_PT_SEAL TPM_PT_SEAL #define TCPA_CAP_ALG TPM_CAP_ALG #define TCPA_CAP_ORD TPM_CAP_ORD #define TCPA_CAP_PID TPM_CAP_PID #define TCPA_CAP_FLAG TPM_CAP_FLAG #define TCPA_CAP_VERSION TPM_CAP_VERSION #define TCPA_CAP_PROPERTY TPM_CAP_PROPERTY #define TCPA_CAP_KEY_HANDLE TPM_CAP_KEY_HANDLE #define TCPA_CAP_CHECK_LOADED TPM_CAP_CHECK_LOADED #define TCPA_ALG_RSA TPM_ALG_RSA #define TCPA_ALG_DES TPM_ALG_DES #define TCPA_ALG_3DES TPM_ALG_3DES #define TCPA_ALG_SHA TPM_ALG_SHA #define TCPA_ALG_HMAC TPM_ALG_HMAC #define TCPA_ALG_AES TPM_ALG_AES #define TCPA_PROTECTED_ORDINAL TPM_PROTECTED_ORDINAL #define TCPA_UNPROTECTED_ORDINAL TPM_UNPROTECTED_ORDINAL #define TCPA_CONNECTION_ORDINAL TPM_CONNECTION_ORDINAL #define TCPA_PROTECTED_COMMAND TPM_PROTECTED_COMMAND #define TCPA_UNPROTECTED_COMMAND TPM_UNPROTECTED_COMMAND #define TCPA_CONNECTION_COMMAND TPM_CONNECTION_COMMAND #define TCPA_VENDOR_COMMAND TPM_VENDOR_COMMAND #define TCPA_MAIN TPM_MAIN #define TCPA_PC TPM_PC #define TCPA_PDA TPM_PDA #define TCPA_CELL_PHONE TPM_CELL_PHONE #define TCPA_MS_MIGRATE TPM_MS_MIGRATE #define TCPA_MS_REWRAP TPM_MS_REWRAP #define TCPA_MS_MAINT TPM_MS_MAINT #define TCPA_ES_NONE TPM_ES_NONE #define TCPA_ES_RSAESPKCSv15 TPM_ES_RSAESPKCSv15 #define TCPA_ES_RSAESOAEP_SHA1_MGF1 TPM_ES_RSAESOAEP_SHA1_MGF1 #define TCPA_SS_NONE TPM_SS_NONE #define TCPA_SS_RSASSAPKCS1v15_SHA1 TPM_SS_RSASSAPKCS1v15_SHA1 #define TCPA_SS_RSASSAPKCS1v15_DER TPM_SS_RSASSAPKCS1v15_DER #define TCPA_SS_RSASSAPKCS1v15_INFO TPM_SS_RSASSAPKCS1v15_INFO #define TCPA_PHYSICAL_PRESENCE_LIFETIME_LOCK TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK #define TCPA_PHYSICAL_PRESENCE_HW_ENABLE TPM_PHYSICAL_PRESENCE_HW_ENABLE #define TCPA_PHYSICAL_PRESENCE_CMD_ENABLE TPM_PHYSICAL_PRESENCE_CMD_ENABLE #define TCPA_PHYSICAL_PRESENCE_LOCK TPM_PHYSICAL_PRESENCE_LOCK #define TCPA_PHYSICAL_PRESENCE_PRESENT TPM_PHYSICAL_PRESENCE_PRESENT #define TCPA_PHYSICAL_PRESENCE_NOTPRESENT TPM_PHYSICAL_PRESENCE_NOTPRESENT #define TCPA_SUCCESS TPM_SUCCESS #define TCPA_E_BASE TPM_E_BASE #define TCPA_E_NON_FATAL TPM_E_NON_FATAL #define TCPA_E_AUTHFAIL TPM_E_AUTHFAIL #define TCPA_E_BAD_PARAMETER TPM_E_BAD_PARAMETER #define TCPA_E_BADINDEX TPM_E_BADINDEX #define TCPA_E_AUDITFAILURE TPM_E_AUDITFAILURE #define TCPA_E_CLEAR_DISABLED TPM_E_CLEAR_DISABLED #define TCPA_E_DEACTIVATED TPM_E_DEACTIVATED #define TCPA_E_DISABLED TPM_E_DISABLED #define TCPA_E_DISABLED_CMD TPM_E_DISABLED_CMD #define TCPA_E_FAIL TPM_E_FAIL #define TCPA_E_INACTIVE TPM_E_BAD_ORDINAL #define TCPA_E_INSTALL_DISABLED TPM_E_INSTALL_DISABLED #define TCPA_E_INVALID_KEYHANDLE TPM_E_INVALID_KEYHANDLE #define TCPA_E_KEYNOTFOUND TPM_E_KEYNOTFOUND #define TCPA_E_NEED_SELFTEST TPM_E_INAPPROPRIATE_ENC #define TCPA_E_MIGRATEFAIL TPM_E_MIGRATEFAIL #define TCPA_E_NO_PCR_INFO TPM_E_INVALID_PCR_INFO #define TCPA_E_NOSPACE TPM_E_NOSPACE #define TCPA_E_NOSRK TPM_E_NOSRK #define TCPA_E_NOTSEALED_BLOB TPM_E_NOTSEALED_BLOB #define TCPA_E_OWNER_SET TPM_E_OWNER_SET #define TCPA_E_RESOURCES TPM_E_RESOURCES #define TCPA_E_SHORTRANDOM TPM_E_SHORTRANDOM #define TCPA_E_SIZE TPM_E_SIZE #define TCPA_E_WRONGPCRVAL TPM_E_WRONGPCRVAL #define TCPA_E_BAD_PARAM_SIZE TPM_E_BAD_PARAM_SIZE #define TCPA_E_SHA_THREAD TPM_E_SHA_THREAD #define TCPA_E_SHA_ERROR TPM_E_SHA_ERROR #define TCPA_E_FAILEDSELFTEST TPM_E_FAILEDSELFTEST #define TCPA_E_AUTH2FAIL TPM_E_AUTH2FAIL #define TCPA_E_BADTAG TPM_E_BADTAG #define TCPA_E_IOERROR TPM_E_IOERROR #define TCPA_E_ENCRYPT_ERROR TPM_E_ENCRYPT_ERROR #define TCPA_E_DECRYPT_ERROR TPM_E_DECRYPT_ERROR #define TCPA_E_INVALID_AUTHHANDLE TPM_E_INVALID_AUTHHANDLE #define TCPA_E_NO_ENDORSEMENT TPM_E_NO_ENDORSEMENT #define TCPA_E_INVALID_KEYUSAGE TPM_E_INVALID_KEYUSAGE #define TCPA_E_WRONG_ENTITYTYPE TPM_E_WRONG_ENTITYTYPE #define TCPA_E_INVALID_POSTINIT TPM_E_INVALID_POSTINIT #define TCPA_E_INAPPROPRIATE_SIG TPM_E_INAPPROPRIATE_SIG #define TCPA_E_BAD_KEY_PROPERTY TPM_E_BAD_KEY_PROPERTY #define TCPA_E_BAD_MIGRATION TPM_E_BAD_MIGRATION #define TCPA_E_BAD_SCHEME TPM_E_BAD_SCHEME #define TCPA_E_BAD_DATASIZE TPM_E_BAD_DATASIZE #define TCPA_E_BAD_MODE TPM_E_BAD_MODE #define TCPA_E_BAD_PRESENCE TPM_E_BAD_PRESENCE #define TCPA_E_BAD_VERSION TPM_E_BAD_VERSION #define TCPA_E_RETRY TPM_E_RETRY #endif trousers-0.3.15/src/include/tss/tspi.h0000664000175000017510000012762413663651711017143 0ustar deboradebora#if !defined(_TSPI_H_) #define _TSPI_H_ #include #include #include #include #include #if !defined( TSPICALL ) #if !defined(WIN32) || defined (TSP_STATIC) // Linux, or a Win32 static library #define TSPICALL extern TSS_RESULT #elif defined (TSPDLL_EXPORTS) // Win32 DLL build #define TSPICALL extern __declspec(dllexport) TSS_RESULT #else // Win32 DLL import #define TSPICALL extern __declspec(dllimport) TSS_RESULT #endif #endif /* TSPICALL */ #if defined ( __cplusplus ) extern "C" { #endif /* __cplusplus */ // Class-independent ASN.1 conversion functions TSPICALL Tspi_EncodeDER_TssBlob ( UINT32 rawBlobSize, // in BYTE* rawBlob, // in UINT32 blobType, // in UINT32* derBlobSize, // in, out BYTE* derBlob // out ); TSPICALL Tspi_DecodeBER_TssBlob ( UINT32 berBlobSize, // in BYTE* berBlob, // in UINT32* blobType, // out UINT32* rawBlobSize, // in, out BYTE* rawBlob // out ); // Common Methods TSPICALL Tspi_SetAttribUint32 ( TSS_HOBJECT hObject, // in TSS_FLAG attribFlag, // in TSS_FLAG subFlag, // in UINT32 ulAttrib // in ); TSPICALL Tspi_GetAttribUint32 ( TSS_HOBJECT hObject, // in TSS_FLAG attribFlag, // in TSS_FLAG subFlag, // in UINT32* pulAttrib // out ); TSPICALL Tspi_SetAttribData ( TSS_HOBJECT hObject, // in TSS_FLAG attribFlag, // in TSS_FLAG subFlag, // in UINT32 ulAttribDataSize, // in BYTE* rgbAttribData // in ); TSPICALL Tspi_GetAttribData ( TSS_HOBJECT hObject, // in TSS_FLAG attribFlag, // in TSS_FLAG subFlag, // in UINT32* pulAttribDataSize, // out BYTE** prgbAttribData // out ); TSPICALL Tspi_ChangeAuth ( TSS_HOBJECT hObjectToChange, // in TSS_HOBJECT hParentObject, // in TSS_HPOLICY hNewPolicy // in ); TSPICALL Tspi_ChangeAuthAsym ( TSS_HOBJECT hObjectToChange, // in TSS_HOBJECT hParentObject, // in TSS_HKEY hIdentKey, // in TSS_HPOLICY hNewPolicy // in ); TSPICALL Tspi_GetPolicyObject ( TSS_HOBJECT hObject, // in TSS_FLAG policyType, // in TSS_HPOLICY* phPolicy // out ); // Tspi_Context Class Definitions TSPICALL Tspi_Context_Create ( TSS_HCONTEXT* phContext // out ); TSPICALL Tspi_Context_Close ( TSS_HCONTEXT hContext // in ); TSPICALL Tspi_Context_Connect ( TSS_HCONTEXT hContext, // in TSS_UNICODE* wszDestination // in ); TSPICALL Tspi_Context_FreeMemory ( TSS_HCONTEXT hContext, // in BYTE* rgbMemory // in ); TSPICALL Tspi_Context_GetDefaultPolicy ( TSS_HCONTEXT hContext, // in TSS_HPOLICY* phPolicy // out ); TSPICALL Tspi_Context_CreateObject ( TSS_HCONTEXT hContext, // in TSS_FLAG objectType, // in TSS_FLAG initFlags, // in TSS_HOBJECT* phObject // out ); TSPICALL Tspi_Context_CloseObject ( TSS_HCONTEXT hContext, // in TSS_HOBJECT hObject // in ); TSPICALL Tspi_Context_GetCapability ( TSS_HCONTEXT hContext, // in TSS_FLAG capArea, // in UINT32 ulSubCapLength, // in BYTE* rgbSubCap, // in UINT32* pulRespDataLength, // out BYTE** prgbRespData // out ); TSPICALL Tspi_Context_GetTpmObject ( TSS_HCONTEXT hContext, // in TSS_HTPM* phTPM // out ); TSPICALL Tspi_Context_SetTransEncryptionKey ( TSS_HCONTEXT hContext, // in TSS_HKEY hKey // in ); TSPICALL Tspi_Context_CloseSignTransport ( TSS_HCONTEXT hContext, // in TSS_HKEY hSigningKey, // in TSS_VALIDATION* pValidationData // in, out ); TSPICALL Tspi_Context_LoadKeyByBlob ( TSS_HCONTEXT hContext, // in TSS_HKEY hUnwrappingKey, // in UINT32 ulBlobLength, // in BYTE* rgbBlobData, // in TSS_HKEY* phKey // out ); TSPICALL Tspi_Context_LoadKeyByUUID ( TSS_HCONTEXT hContext, // in TSS_FLAG persistentStorageType, // in TSS_UUID uuidData, // in TSS_HKEY* phKey // out ); TSPICALL Tspi_Context_RegisterKey ( TSS_HCONTEXT hContext, // in TSS_HKEY hKey, // in TSS_FLAG persistentStorageType, // in TSS_UUID uuidKey, // in TSS_FLAG persistentStorageTypeParent, // in TSS_UUID uuidParentKey // in ); TSPICALL Tspi_Context_UnregisterKey ( TSS_HCONTEXT hContext, // in TSS_FLAG persistentStorageType, // in TSS_UUID uuidKey, // in TSS_HKEY* phkey // out ); TSPICALL Tspi_Context_GetKeyByUUID ( TSS_HCONTEXT hContext, // in TSS_FLAG persistentStorageType, // in TSS_UUID uuidData, // in TSS_HKEY* phKey // out ); TSPICALL Tspi_Context_GetKeyByPublicInfo ( TSS_HCONTEXT hContext, // in TSS_FLAG persistentStorageType, // in TSS_ALGORITHM_ID algID, // in UINT32 ulPublicInfoLength, // in BYTE* rgbPublicInfo, // in TSS_HKEY* phKey // out ); TSPICALL Tspi_Context_GetRegisteredKeysByUUID ( TSS_HCONTEXT hContext, // in TSS_FLAG persistentStorageType, // in TSS_UUID* pUuidData, // in UINT32* pulKeyHierarchySize, // out TSS_KM_KEYINFO** ppKeyHierarchy // out ); TSPICALL Tspi_Context_GetRegisteredKeysByUUID2 ( TSS_HCONTEXT hContext, // in TSS_FLAG persistentStorageType, // in TSS_UUID* pUuidData, // in UINT32* pulKeyHierarchySize, // out TSS_KM_KEYINFO2** ppKeyHierarchy // out ); // Policy class definitions TSPICALL Tspi_Policy_SetSecret ( TSS_HPOLICY hPolicy, // in TSS_FLAG secretMode, // in UINT32 ulSecretLength, // in BYTE* rgbSecret // in ); TSPICALL Tspi_Policy_FlushSecret ( TSS_HPOLICY hPolicy // in ); TSPICALL Tspi_Policy_AssignToObject ( TSS_HPOLICY hPolicy, // in TSS_HOBJECT hObject // in ); // TPM Class Definitions TSPICALL Tspi_TPM_KeyControlOwner ( TSS_HTPM hTPM, // in TSS_HKEY hKey, // in UINT32 attribName, // in TSS_BOOL attribValue, // in TSS_UUID* pUuidData // out ); TSPICALL Tspi_TPM_CreateEndorsementKey ( TSS_HTPM hTPM, // in TSS_HKEY hKey, // in TSS_VALIDATION* pValidationData // in, out ); TSPICALL Tspi_TPM_CreateRevocableEndorsementKey ( TSS_HTPM hTPM, // in TSS_HKEY hKey, // in TSS_VALIDATION* pValidationData, // in, out UINT32* pulEkResetDataLength, // in, out BYTE** rgbEkResetData // in, out ); TSPICALL Tspi_TPM_RevokeEndorsementKey ( TSS_HTPM hTPM, // in UINT32 ulEkResetDataLength, // in BYTE* rgbEkResetData // in ); TSPICALL Tspi_TPM_GetPubEndorsementKey ( TSS_HTPM hTPM, // in TSS_BOOL fOwnerAuthorized, // in TSS_VALIDATION* pValidationData, // in, out TSS_HKEY* phEndorsementPubKey // out ); TSPICALL Tspi_TPM_OwnerGetSRKPubKey ( TSS_HTPM hTPM, // in UINT32* pulPubKeyLength, // out BYTE** prgbPubKey // out ); TSPICALL Tspi_TPM_TakeOwnership ( TSS_HTPM hTPM, // in TSS_HKEY hKeySRK, // in TSS_HKEY hEndorsementPubKey // in ); TSPICALL Tspi_TPM_ClearOwner ( TSS_HTPM hTPM, // in TSS_BOOL fForcedClear // in ); TSPICALL Tspi_TPM_CollateIdentityRequest ( TSS_HTPM hTPM, // in TSS_HKEY hKeySRK, // in TSS_HKEY hCAPubKey, // in UINT32 ulIdentityLabelLength, // in BYTE* rgbIdentityLabelData, // in TSS_HKEY hIdentityKey, // in TSS_ALGORITHM_ID algID, // in UINT32* pulTCPAIdentityReqLength, // out BYTE** prgbTCPAIdentityReq // out ); TSPICALL Tspi_TPM_ActivateIdentity ( TSS_HTPM hTPM, // in TSS_HKEY hIdentKey, // in UINT32 ulAsymCAContentsBlobLength, // in BYTE* rgbAsymCAContentsBlob, // in UINT32 ulSymCAAttestationBlobLength, // in BYTE* rgbSymCAAttestationBlob, // in UINT32* pulCredentialLength, // out BYTE** prgbCredential // out ); TSPICALL Tspi_TPM_CreateMaintenanceArchive ( TSS_HTPM hTPM, // in TSS_BOOL fGenerateRndNumber, // in UINT32* pulRndNumberLength, // out BYTE** prgbRndNumber, // out UINT32* pulArchiveDataLength, // out BYTE** prgbArchiveData // out ); TSPICALL Tspi_TPM_KillMaintenanceFeature ( TSS_HTPM hTPM // in ); TSPICALL Tspi_TPM_LoadMaintenancePubKey ( TSS_HTPM hTPM, // in TSS_HKEY hMaintenanceKey, // in TSS_VALIDATION* pValidationData // in, out ); TSPICALL Tspi_TPM_CheckMaintenancePubKey ( TSS_HTPM hTPM, // in TSS_HKEY hMaintenanceKey, // in TSS_VALIDATION* pValidationData // in, out ); TSPICALL Tspi_TPM_SetOperatorAuth ( TSS_HTPM hTPM, // in TSS_HPOLICY hOperatorPolicy // in ); TSPICALL Tspi_TPM_SetStatus ( TSS_HTPM hTPM, // in TSS_FLAG statusFlag, // in TSS_BOOL fTpmState // in ); TSPICALL Tspi_TPM_GetStatus ( TSS_HTPM hTPM, // in TSS_FLAG statusFlag, // in TSS_BOOL* pfTpmState // out ); TSPICALL Tspi_TPM_GetCapability ( TSS_HTPM hTPM, // in TSS_FLAG capArea, // in UINT32 ulSubCapLength, // in BYTE* rgbSubCap, // in UINT32* pulRespDataLength, // out BYTE** prgbRespData // out ); TSPICALL Tspi_TPM_GetCapabilitySigned ( TSS_HTPM hTPM, // in TSS_HKEY hKey, // in TSS_FLAG capArea, // in UINT32 ulSubCapLength, // in BYTE* rgbSubCap, // in TSS_VALIDATION* pValidationData, // in, out UINT32* pulRespDataLength, // out BYTE** prgbRespData // out ); TSPICALL Tspi_TPM_SelfTestFull ( TSS_HTPM hTPM // in ); TSPICALL Tspi_TPM_CertifySelfTest ( TSS_HTPM hTPM, // in TSS_HKEY hKey, // in TSS_VALIDATION* pValidationData // in, out ); TSPICALL Tspi_TPM_GetTestResult ( TSS_HTPM hTPM, // in UINT32* pulTestResultLength, // out BYTE** prgbTestResult // out ); TSPICALL Tspi_TPM_GetRandom ( TSS_HTPM hTPM, // in UINT32 ulRandomDataLength, // in BYTE** prgbRandomData // out ); TSPICALL Tspi_TPM_StirRandom ( TSS_HTPM hTPM, // in UINT32 ulEntropyDataLength, // in BYTE* rgbEntropyData // in ); TSPICALL Tspi_TPM_GetEvent ( TSS_HTPM hTPM, // in UINT32 ulPcrIndex, // in UINT32 ulEventNumber, // in TSS_PCR_EVENT* pPcrEvent // out ); TSPICALL Tspi_TPM_GetEvents ( TSS_HTPM hTPM, // in UINT32 ulPcrIndex, // in UINT32 ulStartNumber, // in UINT32* pulEventNumber, // in, out TSS_PCR_EVENT** prgPcrEvents // out ); TSPICALL Tspi_TPM_GetEventLog ( TSS_HTPM hTPM, // in UINT32* pulEventNumber, // out TSS_PCR_EVENT** prgPcrEvents // out ); TSPICALL Tspi_TPM_Quote ( TSS_HTPM hTPM, // in TSS_HKEY hIdentKey, // in TSS_HPCRS hPcrComposite, // in TSS_VALIDATION* pValidationData // in, out ); TSPICALL Tspi_TPM_Quote2 ( TSS_HTPM hTPM, // in TSS_HKEY hIdentKey, // in TSS_BOOL fAddVersion, // in TSS_HPCRS hPcrComposite, // in TSS_VALIDATION* pValidationData, // in, out UINT32* versionInfoSize, // out BYTE** versionInfo // out ); TSPICALL Tspi_TPM_PcrExtend ( TSS_HTPM hTPM, // in UINT32 ulPcrIndex, // in UINT32 ulPcrDataLength, // in BYTE* pbPcrData, // in TSS_PCR_EVENT* pPcrEvent, // in UINT32* pulPcrValueLength, // out BYTE** prgbPcrValue // out ); TSPICALL Tspi_TPM_PcrRead ( TSS_HTPM hTPM, // in UINT32 ulPcrIndex, // in UINT32* pulPcrValueLength, // out BYTE** prgbPcrValue // out ); TSPICALL Tspi_TPM_PcrReset ( TSS_HTPM hTPM, // in TSS_HPCRS hPcrComposite // in ); TSPICALL Tspi_TPM_AuthorizeMigrationTicket ( TSS_HTPM hTPM, // in TSS_HKEY hMigrationKey, // in TSS_MIGRATE_SCHEME migrationScheme, // in UINT32* pulMigTicketLength, // out BYTE** prgbMigTicket // out ); TSPICALL Tspi_TPM_CMKSetRestrictions ( TSS_HTPM hTPM, // in TSS_CMK_DELEGATE CmkDelegate // in ); TSPICALL Tspi_TPM_CMKApproveMA ( TSS_HTPM hTPM, // in TSS_HMIGDATA hMaAuthData // in ); TSPICALL Tspi_TPM_CMKCreateTicket ( TSS_HTPM hTPM, // in TSS_HKEY hVerifyKey, // in TSS_HMIGDATA hSigData // in ); TSPICALL Tspi_TPM_ReadCounter ( TSS_HTPM hTPM, // in UINT32* counterValue // out ); TSPICALL Tspi_TPM_ReadCurrentTicks ( TSS_HTPM hTPM, // in TPM_CURRENT_TICKS* tickCount // out ); TSPICALL Tspi_TPM_DirWrite ( TSS_HTPM hTPM, // in UINT32 ulDirIndex, // in UINT32 ulDirDataLength, // in BYTE* rgbDirData // in ); TSPICALL Tspi_TPM_DirRead ( TSS_HTPM hTPM, // in UINT32 ulDirIndex, // in UINT32* pulDirDataLength, // out BYTE** prgbDirData // out ); TSPICALL Tspi_TPM_Delegate_AddFamily ( TSS_HTPM hTPM, // in, must not be NULL BYTE bLabel, // in TSS_HDELFAMILY* phFamily // out ); TSPICALL Tspi_TPM_Delegate_GetFamily ( TSS_HTPM hTPM, // in, must not NULL UINT32 ulFamilyID, // in TSS_HDELFAMILY* phFamily // out ); TSPICALL Tspi_TPM_Delegate_InvalidateFamily ( TSS_HTPM hTPM, // in, must not be NULL TSS_HDELFAMILY hFamily // in ); TSPICALL Tspi_TPM_Delegate_CreateDelegation ( TSS_HOBJECT hObject, // in BYTE bLabel, // in UINT32 ulFlags, // in TSS_HPCRS hPcr, // in, may be NULL TSS_HDELFAMILY hFamily, // in TSS_HPOLICY hDelegation // in, out ); TSPICALL Tspi_TPM_Delegate_CacheOwnerDelegation ( TSS_HTPM hTPM, // in, must not be NULL TSS_HPOLICY hDelegation, // in, out UINT32 ulIndex, // in UINT32 ulFlags // in ); TSPICALL Tspi_TPM_Delegate_UpdateVerificationCount ( TSS_HTPM hTPM, // in TSS_HPOLICY hDelegation // in, out ); TSPICALL Tspi_TPM_Delegate_VerifyDelegation ( TSS_HPOLICY hDelegation // in, out ); TSPICALL Tspi_TPM_Delegate_ReadTables ( TSS_HCONTEXT hContext, // in UINT32* pulFamilyTableSize, // out TSS_FAMILY_TABLE_ENTRY** ppFamilyTable, // out UINT32* pulDelegateTableSize, // out TSS_DELEGATION_TABLE_ENTRY** ppDelegateTable // out ); TSPICALL Tspi_TPM_DAA_JoinInit ( TSS_HTPM hTPM, // in TSS_HDAA_ISSUER_KEY hIssuerKey, // in UINT32 daaCounter, // in UINT32 issuerAuthPKsLength, // in TSS_HKEY* issuerAuthPKs, // in UINT32 issuerAuthPKSignaturesLength, // in UINT32 issuerAuthPKSignaturesLength2, // in BYTE** issuerAuthPKSignatures, // in UINT32* capitalUprimeLength, // out BYTE** capitalUprime, // out TSS_DAA_IDENTITY_PROOF** identityProof, // out UINT32* joinSessionLength, // out BYTE** joinSession // out ); TSPICALL Tspi_TPM_DAA_JoinCreateDaaPubKey ( TSS_HTPM hTPM, // in TSS_HDAA_CREDENTIAL hDAACredential, // in UINT32 authenticationChallengeLength, // in BYTE* authenticationChallenge, // in UINT32 nonceIssuerLength, // in BYTE* nonceIssuer, // in UINT32 attributesPlatformLength, // in UINT32 attributesPlatformLength2, // in BYTE** attributesPlatform, // in UINT32 joinSessionLength, // in BYTE* joinSession, // in TSS_DAA_CREDENTIAL_REQUEST** credentialRequest // out ); TSPICALL Tspi_TPM_DAA_JoinStoreCredential ( TSS_HTPM hTPM, // in TSS_HDAA_CREDENTIAL hDAACredential, // in TSS_DAA_CRED_ISSUER* credIssuer, // in UINT32 joinSessionLength, // in BYTE* joinSession // in ); TSPICALL Tspi_TPM_DAA_Sign ( TSS_HTPM hTPM, // in TSS_HDAA_CREDENTIAL hDAACredential, // in TSS_HDAA_ARA_KEY hARAKey, // in TSS_DAA_SELECTED_ATTRIB* revealAttributes, // in UINT32 verifierNonceLength, // in BYTE* verifierNonce, // in UINT32 verifierBaseNameLength, // in BYTE* verifierBaseName, // in TSS_HOBJECT signData, // in TSS_DAA_SIGNATURE** daaSignature // out ); TSPICALL Tspi_TPM_GetAuditDigest ( TSS_HTPM hTPM, // in TSS_HKEY hKey, // in TSS_BOOL closeAudit, // in UINT32* pulAuditDigestSize, // out BYTE** prgbAuditDigest, // out TPM_COUNTER_VALUE* pCounterValue, // out TSS_VALIDATION* pValidationData, // out UINT32* ordSize, // out UINT32** ordList // out ); // PcrComposite Class Definitions TSPICALL Tspi_PcrComposite_SelectPcrIndex ( TSS_HPCRS hPcrComposite, // in UINT32 ulPcrIndex // in ); TSPICALL Tspi_PcrComposite_SelectPcrIndexEx ( TSS_HPCRS hPcrComposite, // in UINT32 ulPcrIndex, // in UINT32 direction // in ); TSPICALL Tspi_PcrComposite_SetPcrValue ( TSS_HPCRS hPcrComposite, // in UINT32 ulPcrIndex, // in UINT32 ulPcrValueLength, // in BYTE* rgbPcrValue // in ); TSPICALL Tspi_PcrComposite_GetPcrValue ( TSS_HPCRS hPcrComposite, // in UINT32 ulPcrIndex, // in UINT32* pulPcrValueLength, // out BYTE** prgbPcrValue // out ); TSPICALL Tspi_PcrComposite_SetPcrLocality ( TSS_HPCRS hPcrComposite, // in UINT32 LocalityValue // in ); TSPICALL Tspi_PcrComposite_GetPcrLocality ( TSS_HPCRS hPcrComposite, // in UINT32* pLocalityValue // out ); TSPICALL Tspi_PcrComposite_GetCompositeHash ( TSS_HPCRS hPcrComposite, // in UINT32* pLen, // in BYTE** ppbHashData // out ); // Key Class Definition TSPICALL Tspi_Key_LoadKey ( TSS_HKEY hKey, // in TSS_HKEY hUnwrappingKey // in ); TSPICALL Tspi_Key_UnloadKey ( TSS_HKEY hKey // in ); TSPICALL Tspi_Key_GetPubKey ( TSS_HKEY hKey, // in UINT32* pulPubKeyLength, // out BYTE** prgbPubKey // out ); TSPICALL Tspi_Key_CertifyKey ( TSS_HKEY hKey, // in TSS_HKEY hCertifyingKey, // in TSS_VALIDATION* pValidationData // in, out ); TSPICALL Tspi_Key_CreateKey ( TSS_HKEY hKey, // in TSS_HKEY hWrappingKey, // in TSS_HPCRS hPcrComposite // in, may be NULL ); TSPICALL Tspi_Key_WrapKey ( TSS_HKEY hKey, // in TSS_HKEY hWrappingKey, // in TSS_HPCRS hPcrComposite // in, may be NULL ); TSPICALL Tspi_Key_CreateMigrationBlob ( TSS_HKEY hKeyToMigrate, // in TSS_HKEY hParentKey, // in UINT32 ulMigTicketLength, // in BYTE* rgbMigTicket, // in UINT32* pulRandomLength, // out BYTE** prgbRandom, // out UINT32* pulMigrationBlobLength, // out BYTE** prgbMigrationBlob // out ); TSPICALL Tspi_Key_ConvertMigrationBlob ( TSS_HKEY hKeyToMigrate, // in TSS_HKEY hParentKey, // in UINT32 ulRandomLength, // in BYTE* rgbRandom, // in UINT32 ulMigrationBlobLength, // in BYTE* rgbMigrationBlob // in ); TSPICALL Tspi_Key_MigrateKey ( TSS_HKEY hMaKey, // in TSS_HKEY hPublicKey, // in TSS_HKEY hMigData // in ); TSPICALL Tspi_Key_CMKCreateBlob ( TSS_HKEY hKeyToMigrate, // in TSS_HKEY hParentKey, // in TSS_HMIGDATA hMigrationData, // in UINT32* pulRandomLength, // out BYTE** prgbRandom // out ); TSPICALL Tspi_Key_CMKConvertMigration ( TSS_HKEY hKeyToMigrate, // in TSS_HKEY hParentKey, // in TSS_HMIGDATA hMigrationData, // in UINT32 ulRandomLength, // in BYTE* rgbRandom // in ); // Hash Class Definition TSPICALL Tspi_Hash_Sign ( TSS_HHASH hHash, // in TSS_HKEY hKey, // in UINT32* pulSignatureLength, // out BYTE** prgbSignature // out ); TSPICALL Tspi_Hash_VerifySignature ( TSS_HHASH hHash, // in TSS_HKEY hKey, // in UINT32 ulSignatureLength, // in BYTE* rgbSignature // in ); TSPICALL Tspi_Hash_SetHashValue ( TSS_HHASH hHash, // in UINT32 ulHashValueLength, // in BYTE* rgbHashValue // in ); TSPICALL Tspi_Hash_GetHashValue ( TSS_HHASH hHash, // in UINT32* pulHashValueLength, // out BYTE** prgbHashValue // out ); TSPICALL Tspi_Hash_UpdateHashValue ( TSS_HHASH hHash, // in UINT32 ulDataLength, // in BYTE* rgbData // in ); TSPICALL Tspi_Hash_TickStampBlob ( TSS_HHASH hHash, // in TSS_HKEY hIdentKey, // in TSS_VALIDATION* pValidationData // in ); // EncData Class Definition TSPICALL Tspi_Data_Bind ( TSS_HENCDATA hEncData, // in TSS_HKEY hEncKey, // in UINT32 ulDataLength, // in BYTE* rgbDataToBind // in ); TSPICALL Tspi_Data_Unbind ( TSS_HENCDATA hEncData, // in TSS_HKEY hKey, // in UINT32* pulUnboundDataLength, // out BYTE** prgbUnboundData // out ); TSPICALL Tspi_Data_Seal ( TSS_HENCDATA hEncData, // in TSS_HKEY hEncKey, // in UINT32 ulDataLength, // in BYTE* rgbDataToSeal, // in TSS_HPCRS hPcrComposite // in ); TSPICALL Tspi_Data_Unseal ( TSS_HENCDATA hEncData, // in TSS_HKEY hKey, // in UINT32* pulUnsealedDataLength, // out BYTE** prgbUnsealedData // out ); // NV Class Definition TSPICALL Tspi_NV_DefineSpace ( TSS_HNVSTORE hNVStore, // in TSS_HPCRS hReadPcrComposite, // in, may be NULL TSS_HPCRS hWritePcrComposite // in, may be NULL ); TSPICALL Tspi_NV_ReleaseSpace ( TSS_HNVSTORE hNVStore // in ); TSPICALL Tspi_NV_WriteValue ( TSS_HNVSTORE hNVStore, // in UINT32 offset, // in UINT32 ulDataLength, // in BYTE* rgbDataToWrite // in ); TSPICALL Tspi_NV_ReadValue ( TSS_HNVSTORE hNVStore, // in UINT32 offset, // in UINT32* ulDataLength, // in, out BYTE** rgbDataRead // out ); // DAA Utility functions (optional, do not require a TPM or TCS) TSPICALL Tspi_DAA_IssuerKeyVerify ( TSS_HDAA_CREDENTIAL hDAACredential, // in TSS_HDAA_ISSUER_KEY hIssuerKey, // in TSS_BOOL* isCorrect // out ); TSPICALL Tspi_DAA_Issuer_GenerateKey ( TSS_HDAA_ISSUER_KEY hIssuerKey, // in UINT32 issuerBaseNameLength, // in BYTE* issuerBaseName // in ); TSPICALL Tspi_DAA_Issuer_InitCredential ( TSS_HDAA_ISSUER_KEY hIssuerKey, // in TSS_HKEY issuerAuthPK, // in TSS_DAA_IDENTITY_PROOF* identityProof, // in UINT32 capitalUprimeLength, // in BYTE* capitalUprime, // in UINT32 daaCounter, // in UINT32* nonceIssuerLength, // out BYTE** nonceIssuer, // out UINT32* authenticationChallengeLength, // out BYTE** authenticationChallenge, // out UINT32* joinSessionLength, // out BYTE** joinSession // out ); TSPICALL Tspi_DAA_Issuer_IssueCredential ( TSS_HDAA_ISSUER_KEY hIssuerKey, // in TSS_DAA_CREDENTIAL_REQUEST* credentialRequest, // in UINT32 issuerJoinSessionLength, // in BYTE* issuerJoinSession, // in TSS_DAA_CRED_ISSUER** credIssuer // out ); TSPICALL Tspi_DAA_Verifier_Init ( TSS_HDAA_CREDENTIAL hDAACredential, // in UINT32* nonceVerifierLength, // out BYTE** nonceVerifier, // out UINT32* baseNameLength, // out BYTE** baseName // out ); TSPICALL Tspi_DAA_VerifySignature ( TSS_HDAA_CREDENTIAL hDAACredential, // in TSS_HDAA_ISSUER_KEY hIssuerKey, // in TSS_HDAA_ARA_KEY hARAKey, // in TSS_HHASH hARACondition, // in UINT32 attributesLength, // in UINT32 attributesLength2, // in BYTE** attributes, // in UINT32 verifierNonceLength, // in BYTE* verifierNonce, // in UINT32 verifierBaseNameLength, // in BYTE* verifierBaseName, // in TSS_HOBJECT signData, // in TSS_DAA_SIGNATURE* daaSignature, // in TSS_BOOL* isCorrect // out ); TSPICALL Tspi_DAA_ARA_GenerateKey ( TSS_HDAA_ISSUER_KEY hIssuerKey, // in TSS_HDAA_ARA_KEY hARAKey // in ); TSPICALL Tspi_DAA_ARA_RevokeAnonymity ( TSS_HDAA_ARA_KEY hARAKey, // in TSS_HHASH hARACondition, // in TSS_HDAA_ISSUER_KEY hIssuerKey, // in TSS_DAA_PSEUDONYM_ENCRYPTED* encryptedPseudonym, // in TSS_DAA_PSEUDONYM_PLAIN** pseudonym // out ); // Callback typedefs typedef TSS_RESULT (*Tspicb_CallbackHMACAuth) ( PVOID lpAppData, // in TSS_HOBJECT hAuthorizedObject, // in TSS_BOOL ReturnOrVerify, // in UINT32 ulPendingFunction, // in TSS_BOOL ContinueUse, // in UINT32 ulSizeNonces, // in BYTE* rgbNonceEven, // in BYTE* rgbNonceOdd, // in BYTE* rgbNonceEvenOSAP, // in BYTE* rgbNonceOddOSAP, // in UINT32 ulSizeDigestHmac, // in BYTE* rgbParamDigest, // in BYTE* rgbHmacData // in, out ); typedef TSS_RESULT (*Tspicb_CallbackXorEnc) ( PVOID lpAppData, // in TSS_HOBJECT hOSAPObject, // in TSS_HOBJECT hObject, // in TSS_FLAG PurposeSecret, // in UINT32 ulSizeNonces, // in BYTE* rgbNonceEven, // in BYTE* rgbNonceOdd, // in BYTE* rgbNonceEvenOSAP, // in BYTE* rgbNonceOddOSAP, // in UINT32 ulSizeEncAuth, // in BYTE* rgbEncAuthUsage, // out BYTE* rgbEncAuthMigration // out ); typedef TSS_RESULT (*Tspicb_CallbackTakeOwnership) ( PVOID lpAppData, // in TSS_HOBJECT hObject, // in TSS_HKEY hObjectPubKey, // in UINT32 ulSizeEncAuth, // in BYTE* rgbEncAuth // out ); typedef TSS_RESULT (*Tspicb_CallbackSealxMask) ( PVOID lpAppData, // in TSS_HKEY hKey, // in TSS_HENCDATA hEncData, // in TSS_ALGORITHM_ID algID, // in UINT32 ulSizeNonces, // in BYTE* rgbNonceEven, // in BYTE* rgbNonceOdd, // in BYTE* rgbNonceEvenOSAP, // in BYTE* rgbNonceOddOSAP, // in UINT32 ulDataLength, // in BYTE* rgbDataToMask, // in BYTE* rgbMaskedData // out ); typedef TSS_RESULT (*Tspicb_CallbackChangeAuthAsym) ( PVOID lpAppData, // in TSS_HOBJECT hObject, // in TSS_HKEY hObjectPubKey, // in UINT32 ulSizeEncAuth, // in UINT32 ulSizeAuthLink, // in BYTE* rgbEncAuth, // out BYTE* rgbAuthLink // out ); typedef TSS_RESULT (*Tspicb_CollateIdentity) ( PVOID lpAppData, // in UINT32 ulTCPAPlainIdentityProofLength, // in BYTE* rgbTCPAPlainIdentityProof, // in TSS_ALGORITHM_ID algID, // in UINT32 ulSessionKeyLength, // out BYTE* rgbSessionKey, // out UINT32* pulTCPAIdentityProofLength, // out BYTE* rgbTCPAIdentityProof // out ); typedef TSS_RESULT (*Tspicb_ActivateIdentity) ( PVOID lpAppData, // in UINT32 ulSessionKeyLength, // in BYTE* rgbSessionKey, // in UINT32 ulSymCAAttestationBlobLength, // in BYTE* rgbSymCAAttestationBlob, // in UINT32* pulCredentialLength, // out BYTE* rgbCredential // out ); typedef TSS_RESULT (*Tspicb_DAA_Sign) ( PVOID lpAppData, // in TSS_HDAA_ISSUER_KEY daaPublicKey, // in UINT32 gammasLength, // in BYTE** gammas, // in UINT32 attributesLength, // in BYTE** attributes, // in UINT32 randomAttributesLength, // in BYTE** randomAttributes, // in UINT32 attributeCommitmentsLength,// in TSS_DAA_ATTRIB_COMMIT* attributeCommitments, // in TSS_DAA_ATTRIB_COMMIT* attributeCommitmentsProof, // in TSS_DAA_PSEUDONYM_PLAIN* pseudonym, // in TSS_DAA_PSEUDONYM_PLAIN* pseudonymTilde, // in TSS_DAA_PSEUDONYM_ENCRYPTED* pseudonymEncrypted, // in TSS_DAA_PSEUDONYM_ENCRYPTED* pseudonymEncProof, // in TSS_DAA_SIGN_CALLBACK** additionalProof // out ); typedef TSS_RESULT (*Tspicb_DAA_VerifySignature) ( PVOID lpAppData, // in UINT32 challengeLength, // in BYTE* challenge, // in TSS_DAA_SIGN_CALLBACK* additionalProof, // in TSS_HDAA_ISSUER_KEY daaPublicKey, // in UINT32 gammasLength, // in BYTE** gammas, // in UINT32 sAttributesLength, // in BYTE** sAttributes, // in UINT32 attributeCommitmentsLength,// in TSS_DAA_ATTRIB_COMMIT* attributeCommitments, // in TSS_DAA_ATTRIB_COMMIT* attributeCommitmentsProof, // in UINT32 zetaLength, // in BYTE* zeta, // in UINT32 sFLength, // in BYTE* sF, // in TSS_DAA_PSEUDONYM* pseudonym, // in TSS_DAA_PSEUDONYM* pseudonymProof, // in TSS_BOOL* isCorrect // out ); #if defined ( __cplusplus ) } #endif /* __cplusplus */ #endif /* _TSPI_H_ */ trousers-0.3.15/src/include/tss/tcpa_struct.h0000664000175000017510000000017513663651711020506 0ustar deboradebora #ifndef __TCPA_STRUCT_H__ #define __TCPA_STRUCT_H__ #warning including deprecated header file tcpa_struct.h #endif trousers-0.3.15/src/include/tss/tcs.h0000664000175000017510000014746413663651711016761 0ustar deboradebora#ifndef TCS_H #define TCS_H #include #include #include #include #include #include #include #if defined __cplusplus extern "C" { #endif extern TSS_RESULT Tcsi_OpenContext ( TCS_CONTEXT_HANDLE* hContext // out ); extern TSS_RESULT Tcsi_CloseContext ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsi_FreeMemory ( TCS_CONTEXT_HANDLE hContext, // in BYTE* pMemory // in ); extern TSS_RESULT Tcsi_GetCapability ( TCS_CONTEXT_HANDLE hContext, // in TPM_CAPABILITY_AREA capArea, // in UINT32 subCapSize, // in BYTE* subCap, // in UINT32* respSize, // out BYTE** resp // out ); extern TSS_RESULT Tcsi_RegisterKey ( TCS_CONTEXT_HANDLE hContext, // in TSS_UUID WrappingKeyUUID, // in TSS_UUID KeyUUID, // in UINT32 cKeySize, // in BYTE* rgbKey, // in UINT32 cVendorDataSize, // in BYTE* gbVendorData // in ); extern TSS_RESULT Tcsip_UnregisterKey ( TCS_CONTEXT_HANDLE hContext, // in TSS_UUID KeyUUID // in ); extern TSS_RESULT Tcsip_KeyControlOwner ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hKey, // in UINT32 ulPubKeyLength, // in BYTE* prgbPubKey, // in UINT32 attribName, // in TSS_BOOL attribValue, // in TPM_AUTH* pOwnerAuth, // in, out TSS_UUID* pUuidData // out ); extern TSS_RESULT Tcsi_EnumRegisteredKeys ( TCS_CONTEXT_HANDLE hContext, // in TSS_UUID* pKeyUUID, // in UINT32* pcKeyHierarchySize, // out TSS_KM_KEYINFO** ppKeyHierarchy // out ); extern TSS_RESULT Tcsi_GetRegisteredKey ( TCS_CONTEXT_HANDLE hContext, // in TSS_UUID KeyUUID, // in TSS_KM_KEYINFO** ppKeyInfo // out ); extern TSS_RESULT Tcsi_GetRegisteredKeyBlob ( TCS_CONTEXT_HANDLE hContext, // in TSS_UUID KeyUUID, // in UINT32* pcKeySize, // out BYTE** prgbKey // out ); extern TSS_RESULT Tcsip_GetRegisteredKeyByPublicInfo ( TCS_CONTEXT_HANDLE hContext, // in TSS_ALGORITHM_ID algID, // in UINT32 ulPublicInfoLength, // in BYTE* rgbPublicInfo, // in UINT32* keySize, // out BYTE** keyBlob // out ); extern TSS_RESULT Tcsip_LoadKeyByBlob ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hUnwrappingKey, // in UINT32 cWrappedKeyBlobSize, // in BYTE* rgbWrappedKeyBlob, // in TPM_AUTH* pAuth, // in, out TCS_KEY_HANDLE* phKeyTCSI, // out TCS_KEY_HANDLE* phKeyHMAC // out ); extern TSS_RESULT Tcsip_LoadKeyByUUID ( TCS_CONTEXT_HANDLE hContext, // in TSS_UUID KeyUUID, // in TCS_LOADKEY_INFO* pLoadKeyInfo, // in, out TCS_KEY_HANDLE* phKeyTCSI // out ); extern TSS_RESULT Tcsip_EvictKey ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hKey // in ); extern TSS_RESULT Tcsip_CreateWrapKey ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hWrappingKey, // in TPM_ENCAUTH KeyUsageAuth, // in TPM_ENCAUTH KeyMigrationAuth, // in UINT32 keyInfoSize, // in BYTE* keyInfo, // in TPM_AUTH* pAuth, // in, out UINT32* keyDataSize, // out BYTE** keyData // out ); extern TSS_RESULT Tcsip_GetPubKey ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hKey, // in TPM_AUTH* pAuth, // in, out UINT32* pcPubKeySize, // out BYTE** prgbPubKey // out ); extern TSS_RESULT Tcsip_MakeIdentity ( TCS_CONTEXT_HANDLE hContext, // in TPM_ENCAUTH identityAuth, // in TPM_CHOSENID_HASH IDLabel_PrivCAHash, // in UINT32 idIdentityKeyInfoSize, // in BYTE* idIdentityKeyInfo, // in TPM_AUTH* pSrkAuth, // in, out TPM_AUTH* pOwnerAuth, // in, out UINT32* idIdentityKeySize, // out BYTE** idIdentityKey, // out UINT32* pcIdentityBindingSize, // out BYTE** prgbIdentityBinding, // out UINT32* pcEndorsementCredentialSize, // out BYTE** prgbEndorsementCredential, // out UINT32* pcPlatformCredentialSize, // out BYTE** prgbPlatformCredential, // out UINT32* pcConformanceCredentialSize, // out BYTE** prgbConformanceCredential // out ); extern TSS_RESULT Tcsip_MakeIdentity2 ( TCS_CONTEXT_HANDLE hContext, // in TPM_ENCAUTH identityAuth, // in TPM_CHOSENID_HASH IDLabel_PrivCAHash, // in UINT32 idIdentityKeyInfoSize, // in BYTE* idIdentityKeyInfo, // in TPM_AUTH* pSrkAuth, // in, out TPM_AUTH* pOwnerAuth, // in, out UINT32* idIdentityKeySize, // out BYTE** idIdentityKey, // out UINT32* pcIdentityBindingSize, // out BYTE** prgbIdentityBinding // out ); extern TSS_RESULT Tcsi_LogPcrEvent ( TCS_CONTEXT_HANDLE hContext, // in TSS_PCR_EVENT Event, // in UINT32* pNumber // out ); extern TSS_RESULT Tcsi_GetPcrEvent ( TCS_CONTEXT_HANDLE hContext, // in UINT32 PcrIndex, // in UINT32* pNumber, // in, out TSS_PCR_EVENT** ppEvent // out ); extern TSS_RESULT Tcsi_GetPcrEventsByPcr ( TCS_CONTEXT_HANDLE hContext, // in UINT32 PcrIndex, // in UINT32 FirstEvent, // in UINT32* pEventCount, // in, out TSS_PCR_EVENT** ppEvents // out ); extern TSS_RESULT Tcsi_GetPcrEventLog ( TCS_CONTEXT_HANDLE hContext, // in UINT32* pEventCount, // out TSS_PCR_EVENT** ppEvents // out ); extern TSS_RESULT Tcsip_SetOwnerInstall ( TCS_CONTEXT_HANDLE hContext, // in TSS_BOOL state // in ); extern TSS_RESULT Tcsip_TakeOwnership ( TCS_CONTEXT_HANDLE hContext, // in UINT16 protocolID, // in UINT32 encOwnerAuthSize, // in BYTE* encOwnerAuth, // in UINT32 encSrkAuthSize, // in BYTE* encSrkAuth, // in UINT32 srkKeyInfoSize, // in BYTE* srkKeyInfo, // in TPM_AUTH* ownerAuth, // in, out UINT32* srkKeyDataSize, // out BYTE** srkKeyData // out ); extern TSS_RESULT Tcsip_SetOperatorAuth ( TCS_CONTEXT_HANDLE hContext, // in TPM_SECRET operatorAuth // in ); extern TSS_RESULT Tcsip_OIAP ( TCS_CONTEXT_HANDLE hContext, // in TCS_AUTHHANDLE* authHandle, // out TPM_NONCE* nonce0 // out ); extern TSS_RESULT Tcsip_OSAP ( TCS_CONTEXT_HANDLE hContext, // in TPM_ENTITY_TYPE entityType, // in UINT32 entityValue, // in TPM_NONCE nonceOddOSAP, // in TCS_AUTHHANDLE* authHandle, // out TPM_NONCE* nonceEven, // out TPM_NONCE* nonceEvenOSAP // out ); extern TSS_RESULT Tcsip_ChangeAuth ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE parentHandle, // in TPM_PROTOCOL_ID protocolID, // in TPM_ENCAUTH newAuth, // in TPM_ENTITY_TYPE entityType, // in UINT32 encDataSize, // in BYTE* encData, // in TPM_AUTH* ownerAuth, // in, out TPM_AUTH* entityAuth, // in, out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_ChangeAuthOwner ( TCS_CONTEXT_HANDLE hContext, // in TPM_PROTOCOL_ID protocolID, // in TPM_ENCAUTH newAuth, // in TPM_ENTITY_TYPE entityType, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_ChangeAuthAsymStart ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE idHandle, // in TPM_NONCE antiReplay, // in UINT32 TempKeyInfoSize, // in BYTE* TempKeyInfoData, // in TPM_AUTH* pAuth, // in, out UINT32* TempKeySize, // out BYTE** TempKeyData, // out UINT32* CertifyInfoSize, // out BYTE** CertifyInfo, // out UINT32* sigSize, // out BYTE** sig, // out TCS_KEY_HANDLE* ephHandle // out ); extern TSS_RESULT Tcsip_ChangeAuthAsymFinish ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE parentHandle, // in TCS_KEY_HANDLE ephHandle, // in TPM_ENTITY_TYPE entityType, // in TPM_HMAC newAuthLink, // in UINT32 newAuthSize, // in BYTE* encNewAuth, // in UINT32 encDataSizeIn, // in BYTE* encDataIn, // in TPM_AUTH* ownerAuth, // in, out UINT32* encDataSizeOut, // out BYTE** encDataOut, // out TPM_NONCE* saltNonce, // out TPM_DIGEST* changeProof // out ); extern TSS_RESULT Tcsip_TerminateHandle ( TCS_CONTEXT_HANDLE hContext, // in TCS_AUTHHANDLE handle // in ); extern TSS_RESULT Tcsip_ActivateTPMIdentity ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE idKey, // in UINT32 blobSize, // in BYTE* blob, // in TPM_AUTH* idKeyAuth, // in, out TPM_AUTH* ownerAuth, // in, out UINT32* SymmetricKeySize, // out BYTE** SymmetricKey // out ); extern TSS_RESULT Tcsip_EstablishTransport ( TCS_CONTEXT_HANDLE hContext, // in UINT32 ulTransControlFlags, // in TCS_KEY_HANDLE hEncKey, // in UINT32 ulTransSessionInfoSize, // in BYTE* rgbTransSessionInfo, // in UINT32 ulSecretSize, // in BYTE* rgbSecret, // in TPM_AUTH* pEncKeyAuth, // in, out TPM_MODIFIER_INDICATOR* pbLocality, // out TCS_HANDLE* hTransSession, // out UINT32* ulCurrentTicksSize, // out BYTE** prgbCurrentTicks, // out TPM_NONCE* pTransNonce // out ); extern TSS_RESULT Tcsip_ExecuteTransport ( TCS_CONTEXT_HANDLE hContext, // in TPM_COMMAND_CODE unWrappedCommandOrdinal, // in UINT32 ulWrappedCmdParamInSize, // in BYTE* rgbWrappedCmdParamIn, // in UINT32* pulHandleListSize, // in, out TCS_HANDLE** rghHandles, // in, out TPM_AUTH* pWrappedCmdAuth1, // in, out TPM_AUTH* pWrappedCmdAuth2, // in, out TPM_AUTH* pTransAuth, // in, out UINT64* punCurrentTicks, // out TPM_MODIFIER_INDICATOR* pbLocality, // out TPM_RESULT* pulWrappedCmdReturnCode, // out UINT32* ulWrappedCmdParamOutSize, // out BYTE** rgbWrappedCmdParamOut // out ); extern TSS_RESULT Tcsip_ReleaseTransportSigned ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hSignatureKey, // in TPM_NONCE AntiReplayNonce, // in TPM_AUTH* pKeyAuth, // in, out TPM_AUTH* pTransAuth, // in, out TPM_MODIFIER_INDICATOR* pbLocality, // out UINT32* pulCurrentTicksSize, // out BYTE** prgbCurrentTicks, // out UINT32* pulSignatureSize, // out BYTE** prgbSignature // out ); extern TSS_RESULT Tcsip_Extend ( TCS_CONTEXT_HANDLE hContext, // in TPM_PCRINDEX pcrNum, // in TPM_DIGEST inDigest, // in TPM_PCRVALUE* outDigest // out ); extern TSS_RESULT Tcsip_PcrRead ( TCS_CONTEXT_HANDLE hContext, // in TPM_PCRINDEX pcrNum, // in TPM_PCRVALUE* outDigest // out ); extern TSS_RESULT Tcsip_Quote ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in TPM_NONCE antiReplay, // in UINT32 pcrTargetSize, // in BYTE* pcrTarget, // in TPM_AUTH* privAuth, // in, out UINT32* pcrDataSize, // out BYTE** pcrData, // out UINT32* sigSize, // out BYTE** sig // out ); extern TSS_RESULT Tcsip_Quote2 ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in TPM_NONCE antiReplay, // in UINT32 pcrTargetSize, // in BYTE* pcrTarget, // in TSS_BOOL addVersion, // in TPM_AUTH* privAuth, // in, out UINT32* pcrDataSize, // out BYTE** pcrData, // out UINT32* versionInfoSize, // out BYTE** versionInfo, // out UINT32* sigSize, // out BYTE** sig // out ); extern TSS_RESULT Tcsip_DirWriteAuth ( TCS_CONTEXT_HANDLE hContext, // in TPM_DIRINDEX dirIndex, // in TPM_DIRVALUE newContents, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_DirRead ( TCS_CONTEXT_HANDLE hContext, // in TPM_DIRINDEX dirIndex, // in TPM_DIRVALUE* dirValue // out ); extern TSS_RESULT Tcsip_Seal ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in TPM_ENCAUTH encAuth, // in UINT32 pcrInfoSize, // in BYTE* PcrInfo, // in UINT32 inDataSize, // in BYTE* inData, // in TPM_AUTH* pubAuth, // in, out UINT32* SealedDataSize, // out BYTE** SealedData // out ); extern TSS_RESULT Tcsip_Unseal ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in UINT32 SealedDataSize, // in BYTE* SealedData, // in TPM_AUTH* keyAuth, // in, out TPM_AUTH* dataAuth, // in, out UINT32* DataSize, // out BYTE** Data // out ); extern TSS_RESULT Tcsip_UnBind ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in UINT32 inDataSize, // in BYTE* inData, // in TPM_AUTH* privAuth, // in, out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_Sealx ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in TPM_ENCAUTH encAuth, // in UINT32 pcrInfoSize, // in BYTE* PcrInfo, // in UINT32 inDataSize, // in BYTE* inData, // in TPM_AUTH* pubAuth, // in, out UINT32* SealedDataSize, // out BYTE** SealedData // out ); extern TSS_RESULT Tcsip_LoadKey2ByBlob ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hUnwrappingKey, // in UINT32 cWrappedKeyBlobSize, // in BYTE* rgbWrappedKeyBlob, // in TPM_AUTH* pAuth, // in, out TCS_KEY_HANDLE* phKeyTCSI // out ); extern TSS_RESULT Tcsip_CreateMigrationBlob ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE parentHandle, // in TSS_MIGRATE_SCHEME migrationType, // in UINT32 MigrationKeyAuthSize, // in BYTE* MigrationKeyAuth, // in UINT32 encDataSize, // in BYTE* encData, // in TPM_AUTH* parentAuth, // in, out TPM_AUTH* entityAuth, // in, out UINT32* randomSize, // out BYTE** random, // out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_ConvertMigrationBlob ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE parentHandle, // in UINT32 inDataSize, // in BYTE* inData, // in UINT32 randomSize, // in BYTE* random, // in TPM_AUTH* parentAuth, // in, out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_AuthorizeMigrationKey ( TCS_CONTEXT_HANDLE hContext, // in TSS_MIGRATE_SCHEME migrateScheme, // in UINT32 MigrationKeySize, // in BYTE* MigrationKey, // in TPM_AUTH* ownerAuth, // in, out UINT32* MigrationKeyAuthSize, // out BYTE** MigrationKeyAuth // out ); extern TSS_RESULT Tcsip_CertifyKey ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE certHandle, // in TCS_KEY_HANDLE keyHandle, // in TPM_NONCE antiReplay, // in TPM_AUTH* certAuth, // in, out TPM_AUTH* keyAuth, // in, out UINT32* CertifyInfoSize, // out BYTE** CertifyInfo, // out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_CertifyKey2 ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE certHandle, // in TCS_KEY_HANDLE keyHandle, // in TPM_DIGEST MSAdigest, // in TPM_NONCE antiReplay, // in TPM_AUTH* certAuth, // in, out TPM_AUTH* keyAuth, // in, out UINT32* CertifyInfoSize, // out BYTE** CertifyInfo, // out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_Sign ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in UINT32 areaToSignSize, // in BYTE* areaToSign, // in TPM_AUTH* privAuth, // in, out UINT32* sigSize, // out BYTE** sig // out ); extern TSS_RESULT Tcsip_GetRandom ( TCS_CONTEXT_HANDLE hContext, // in UINT32* bytesRequested, // in, out BYTE** randomBytes // out ); extern TSS_RESULT Tcsip_StirRandom ( TCS_CONTEXT_HANDLE hContext, // in UINT32 inDataSize, // in BYTE* inData // in ); extern TSS_RESULT Tcsip_GetCapability ( TCS_CONTEXT_HANDLE hContext, // in TPM_CAPABILITY_AREA capArea, // in UINT32 subCapSize, // in BYTE* subCap, // in UINT32* respSize, // out BYTE** resp // out ); extern TSS_RESULT Tcsip_GetCapabilitySigned ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in TPM_NONCE antiReplay, // in TPM_CAPABILITY_AREA capArea, // in UINT32 subCapSize, // in BYTE* subCap, // in TPM_AUTH* privAuth, // in, out TPM_VERSION* Version, // out UINT32* respSize, // out BYTE** resp, // out UINT32* sigSize, // out BYTE** sig // out ); extern TSS_RESULT Tcsip_GetCapabilityOwner ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* pOwnerAuth, // in, out TPM_VERSION* pVersion, // out UINT32* pNonVolatileFlags, // out UINT32* pVolatileFlags // out ); extern TSS_RESULT Tcsip_CreateEndorsementKeyPair ( TCS_CONTEXT_HANDLE hContext, // in TPM_NONCE antiReplay, // in UINT32 endorsementKeyInfoSize, // in BYTE* endorsementKeyInfo, // in UINT32* endorsementKeySize, // out BYTE** endorsementKey, // out TPM_DIGEST* checksum // out ); extern TSS_RESULT Tcsip_ReadPubek ( TCS_CONTEXT_HANDLE hContext, // in TPM_NONCE antiReplay, // in UINT32* pubEndorsementKeySize, // out BYTE** pubEndorsementKey, // out TPM_DIGEST* checksum // out ); extern TSS_RESULT Tcsip_DisablePubekRead ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_OwnerReadPubek ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* ownerAuth, // in, out UINT32* pubEndorsementKeySize, // out BYTE** pubEndorsementKey // out ); extern TSS_RESULT Tcsip_SelfTestFull ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsip_CertifySelfTest ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in TPM_NONCE antiReplay, // in TPM_AUTH* privAuth, // in, out UINT32* sigSize, // out BYTE** sig // out ); extern TSS_RESULT Tcsip_ContinueSelfTest ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsip_GetTestResult ( TCS_CONTEXT_HANDLE hContext, // in UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_OwnerSetDisable ( TCS_CONTEXT_HANDLE hContext, // in TSS_BOOL disableState, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_OwnerClear ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_DisableOwnerClear ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_ForceClear ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsip_DisableForceClear ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsip_PhysicalDisable ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsip_PhysicalEnable ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsip_PhysicalSetDeactivated ( TCS_CONTEXT_HANDLE hContext, // in TSS_BOOL state // in ); extern TSS_RESULT Tcsip_SetTempDeactivated ( TCS_CONTEXT_HANDLE hContext // in ); extern TSS_RESULT Tcsip_SetTempDeactivated2 ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* pOperatorAuth // in, out ); extern TSS_RESULT Tcsip_OwnerReadInternalPub ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hKey, // in TPM_AUTH* pOwnerAuth, // in, out UINT32* punPubKeySize, // out BYTE** ppbPubKeyData // out ); extern TSS_RESULT Tcsip_PhysicalPresence ( TCS_CONTEXT_HANDLE hContext, // in TPM_PHYSICAL_PRESENCE fPhysicalPresence // in ); extern TSS_RESULT Tcsip_FieldUpgrade ( TCS_CONTEXT_HANDLE hContext, // in UINT32 dataInSize, // in BYTE* dataIn, // in TPM_AUTH* ownerAuth, // in, out UINT32* dataOutSize, // out BYTE** dataOut // out ); extern TSS_RESULT Tcsip_ResetLockValue ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_FlushSpecific ( TCS_CONTEXT_HANDLE hContext, // in TCS_HANDLE hResHandle, // in TPM_RESOURCE_TYPE resourceType // in ); extern TSS_RESULT Tcsip_SetRedirection ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in UINT32 c1, // in UINT32 c2, // in TPM_AUTH* privAuth // in, out ); extern TSS_RESULT Tcsip_DSAP ( TCS_CONTEXT_HANDLE hContext, // in TPM_ENTITY_TYPE entityType, // in TCS_KEY_HANDLE keyHandle, // in TPM_NONCE nonceOddDSAP, // in UINT32 entityValueSize, // in BYTE* entityValue, // in TCS_AUTHHANDLE* authHandle, // out TPM_NONCE* nonceEven, // out TPM_NONCE* nonceEvenDSAP // out ); extern TSS_RESULT Tcsip_Delegate_Manage ( TCS_CONTEXT_HANDLE hContext, // in TPM_FAMILY_ID familyID, // in TPM_FAMILY_OPERATION opFlag, // in UINT32 opDataSize, // in BYTE* opData, // in TPM_AUTH* ownerAuth, // in, out UINT32* retDataSize, // out BYTE** retData // out ); extern TSS_RESULT Tcsip_Delegate_CreateKeyDelegation ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hKey, // in UINT32 publicInfoSize, // in BYTE* publicInfo, // in TPM_ENCAUTH encDelAuth, // in TPM_AUTH* keyAuth, // in, out UINT32* blobSize, // out BYTE** blob // out ); extern TSS_RESULT Tcsip_Delegate_CreateOwnerDelegation ( TCS_CONTEXT_HANDLE hContext, // in TSS_BOOL increment, // in UINT32 publicInfoSize, // in BYTE* publicInfo, // in TPM_ENCAUTH encDelAuth, // in TPM_AUTH* ownerAuth, // in, out UINT32* blobSize, // out BYTE** blob // out ); extern TSS_RESULT Tcsip_Delegate_LoadOwnerDelegation ( TCS_CONTEXT_HANDLE hContext, // in TPM_DELEGATE_INDEX index, // in UINT32 blobSize, // in BYTE* blob, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_Delegate_UpdateVerificationCount ( TCS_CONTEXT_HANDLE hContext, // in UINT32 inputSize, // in BYTE* input, // in TPM_AUTH* ownerAuth, // in, out UINT32* outputSize, // out BYTE** output // out ); extern TSS_RESULT Tcsip_Delegate_VerifyDelegation ( TCS_CONTEXT_HANDLE hContext, // in UINT32 delegateSize, // in BYTE* delegate // in ); extern TSS_RESULT Tcsip_Delegate_ReadTable ( TCS_CONTEXT_HANDLE hContext, // in UINT32* pulFamilyTableSize, // out BYTE** ppFamilyTable, // out UINT32* pulDelegateTableSize, // out BYTE** ppDelegateTable // out ); extern TSS_RESULT Tcsip_NV_DefineOrReleaseSpace ( TCS_CONTEXT_HANDLE hContext, // in UINT32 cPubInfoSize, // in BYTE* pPubInfo, // in TPM_ENCAUTH encAuth, // in TPM_AUTH* pAuth // in, out ); extern TSS_RESULT Tcsip_NV_WriteValue ( TCS_CONTEXT_HANDLE hContext, // in TSS_NV_INDEX hNVStore, // in UINT32 offset, // in UINT32 ulDataLength, // in BYTE* rgbDataToWrite, // in TPM_AUTH* privAuth // in, out ); extern TSS_RESULT Tcsip_NV_WriteValueAuth ( TCS_CONTEXT_HANDLE hContext, // in TSS_NV_INDEX hNVStore, // in UINT32 offset, // in UINT32 ulDataLength, // in BYTE* rgbDataToWrite, // in TPM_AUTH* NVAuth // in, out ); extern TSS_RESULT Tcsip_NV_ReadValue ( TCS_CONTEXT_HANDLE hContext, // in TSS_NV_INDEX hNVStore, // in UINT32 offset, // in UINT32* pulDataLength, // in, out TPM_AUTH* privAuth, // in, out BYTE** rgbDataRead // out ); extern TSS_RESULT Tcsip_NV_ReadValueAuth ( TCS_CONTEXT_HANDLE hContext, // in TSS_NV_INDEX hNVStore, // in UINT32 offset, // in UINT32* pulDataLength, // in, out TPM_AUTH* NVAuth, // in, out BYTE** rgbDataRead // out ); extern TSS_RESULT Tcsip_CreateMaintenanceArchive ( TCS_CONTEXT_HANDLE hContext, // in TSS_BOOL generateRandom, // in TPM_AUTH* ownerAuth, // in, out UINT32* randomSize, // out BYTE** random, // out UINT32* archiveSize, // out BYTE** archive // out ); extern TSS_RESULT Tcsip_LoadMaintenanceArchive ( TCS_CONTEXT_HANDLE hContext, // in UINT32 dataInSize, // in BYTE* dataIn, // in TPM_AUTH* ownerAuth, // in, out UINT32* dataOutSize, // out BYTE** dataOut // out ); extern TSS_RESULT Tcsip_KillMaintenanceFeature ( TCS_CONTEXT_HANDLE hContext, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_LoadManuMaintPub ( TCS_CONTEXT_HANDLE hContext, // in TPM_NONCE antiReplay, // in UINT32 PubKeySize, // in BYTE* PubKey, // in TPM_DIGEST* checksum // out ); extern TSS_RESULT Tcsip_ReadManuMaintPub ( TCS_CONTEXT_HANDLE hContext, // in TPM_NONCE antiReplay, // in TPM_DIGEST* checksum // out ); extern TSS_RESULT Tcsip_CreateRevocableEndorsementKeyPair ( TCS_CONTEXT_HANDLE hContext, // in TPM_NONCE antiReplay, // in UINT32 endorsementKeyInfoSize, // in BYTE* endorsementKeyInfo, // in TSS_BOOL GenResetAuth, // in TPM_DIGEST* EKResetAuth, // in, out UINT32* endorsementKeySize, // out BYTE** endorsementKey, // out TPM_DIGEST* checksum // out ); extern TSS_RESULT Tcsip_RevokeEndorsementKeyPair ( TCS_CONTEXT_HANDLE hContext, // in TPM_DIGEST EKResetAuth // in ); extern TSS_RESULT Tcsip_PcrReset ( TCS_CONTEXT_HANDLE hContext, // in UINT32 pcrTargetSize, // in BYTE* pcrTarget // in ); extern TSS_RESULT Tcsip_ReadCounter ( TCS_CONTEXT_HANDLE hContext, // in TSS_COUNTER_ID idCounter, // in TPM_COUNTER_VALUE* counterValue // out ); extern TSS_RESULT Tcsip_CreateCounter ( TCS_CONTEXT_HANDLE hContext, // in UINT32 LabelSize, // in (=4) BYTE* pLabel, // in TPM_ENCAUTH CounterAuth, // in TPM_AUTH* pOwnerAuth, // in, out TSS_COUNTER_ID* idCounter, // out TPM_COUNTER_VALUE* counterValue // out ); extern TSS_RESULT Tcsip_IncrementCounter ( TCS_CONTEXT_HANDLE hContext, // in TSS_COUNTER_ID idCounter, // in TPM_AUTH* pCounterAuth, // in, out TPM_COUNTER_VALUE* counterValue // out ); extern TSS_RESULT Tcsip_ReleaseCounter ( TCS_CONTEXT_HANDLE hContext, // in TSS_COUNTER_ID idCounter, // in TPM_AUTH* pCounterAuth // in, out ); extern TSS_RESULT Tcsip_ReleaseCounterOwner ( TCS_CONTEXT_HANDLE hContext, // in TSS_COUNTER_ID idCounter, // in TPM_AUTH* pOwnerAuth // in, out ); extern TSS_RESULT Tcsip_ReadCurrentTicks ( TCS_CONTEXT_HANDLE hContext, // in UINT32* pulCurrentTimeSize, // out BYTE** prgbCurrentTime // out ); extern TSS_RESULT Tcsip_TickStampBlob ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hKey, // in TPM_NONCE antiReplay, // in TPM_DIGEST digestToStamp, // in TPM_AUTH* privAuth, // in, out UINT32* pulSignatureLength, // out BYTE** prgbSignature, // out UINT32* pulTickCountSize, // out BYTE** prgbTickCount // out ); extern TSS_RESULT Tcsip_TPM_DAA_Join ( TCS_CONTEXT_HANDLE hContext, // in TPM_HANDLE handle, // in BYTE stage, // in UINT32 inputSize0, // in BYTE* inputData0, // in UINT32 inputSize1, // in BYTE* inputData1, // in TPM_AUTH* ownerAuth, // in, out UINT32* outputSize, // out BYTE** outputData // out ); extern TSS_RESULT Tcsip_TPM_DAA_Sign ( TCS_CONTEXT_HANDLE hContext, // in TPM_HANDLE handle, // in BYTE stage, // in UINT32 inputSize0, // in BYTE* inputData0, // in UINT32 inputSize1, // in BYTE* inputData1, // in TPM_AUTH* ownerAuth, // in, out UINT32* outputSize, // out BYTE** outputData // out ); extern TSS_RESULT Tcsip_MigrateKey ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hMaKey, // in UINT32 PublicKeySize, // in BYTE* PublicKey, // in UINT32 inDataSize, // in BYTE* inData, // in TPM_AUTH* ownerAuth, // in, out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_CMK_SetRestrictions ( TCS_CONTEXT_HANDLE hContext, // in TSS_CMK_DELEGATE Restriction, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_CMK_ApproveMA ( TCS_CONTEXT_HANDLE hContext, // in TPM_DIGEST migAuthorityDigest, // in TPM_AUTH* ownerAuth, // in, out TPM_HMAC* HmacMigAuthDigest // out ); extern TSS_RESULT Tcsip_CMK_CreateKey ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE hWrappingKey, // in TPM_ENCAUTH KeyUsageAuth, // in TPM_HMAC MigAuthApproval, // in TPM_DIGEST MigAuthorityDigest, // in UINT32* keyDataSize, // in, out BYTE** prgbKeyData, // in, out TPM_AUTH* pAuth // in, out ); extern TSS_RESULT Tcsip_CMK_CreateTicket ( TCS_CONTEXT_HANDLE hContext, // in UINT32 PublicVerifyKeySize, // in BYTE* PublicVerifyKey, // in TPM_DIGEST SignedData, // in UINT32 SigValueSize, // in BYTE* SigValue, // in TPM_AUTH* pOwnerAuth, // in, out TPM_HMAC* SigTicket // out ); extern TSS_RESULT Tcsip_CMK_CreateBlob ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE parentHandle, // in TSS_MIGRATE_SCHEME migrationType, // in UINT32 MigrationKeyAuthSize, // in BYTE* MigrationKeyAuth, // in TPM_DIGEST PubSourceKeyDigest, // in UINT32 msaListSize, // in BYTE* msaList, // in UINT32 restrictTicketSize, // in BYTE* restrictTicket, // in UINT32 sigTicketSize, // in BYTE* sigTicket, // in UINT32 encDataSize, // in BYTE* encData, // in TPM_AUTH* parentAuth, // in, out UINT32* randomSize, // out BYTE** random, // out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_CMK_ConvertMigration ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE parentHandle, // in TPM_CMK_AUTH restrictTicket, // in TPM_HMAC sigTicket, // in UINT32 keyDataSize, // in BYTE* prgbKeyData, // in UINT32 msaListSize, // in BYTE* msaList, // in UINT32 randomSize, // in BYTE* random, // in TPM_AUTH* parentAuth, // in, out UINT32* outDataSize, // out BYTE** outData // out ); extern TSS_RESULT Tcsip_SetCapability ( TCS_CONTEXT_HANDLE hContext, // in TPM_CAPABILITY_AREA capArea, // in UINT32 subCapSize, // in BYTE* subCap, // in UINT32 valueSize, // in BYTE* value, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsip_GetAuditDigest ( TCS_CONTEXT_HANDLE hContext, // in UINT32 startOrdinal, // in TPM_DIGEST* auditDigest, // out UINT32* counterValueSize, // out BYTE** counterValue, // out TSS_BOOL* more, // out UINT32* ordSize, // out UINT32** ordList // out ); extern TSS_RESULT Tcsip_GetAuditDigestSigned ( TCS_CONTEXT_HANDLE hContext, // in TCS_KEY_HANDLE keyHandle, // in TSS_BOOL closeAudit, // in TPM_NONCE antiReplay, // in TPM_AUTH* privAuth, // in, out UINT32* counterValueSize, // out BYTE** counterValue, // out TPM_DIGEST* auditDigest, // out TPM_DIGEST* ordinalDigest, // out UINT32* sigSize, // out BYTE** sig // out ); extern TSS_RESULT Tcsip_SetOrdinalAuditStatus ( TCS_CONTEXT_HANDLE hContext, // in UINT32 ordinalToAudit, // in TSS_BOOL auditState, // in TPM_AUTH* ownerAuth // in, out ); extern TSS_RESULT Tcsi_Admin_TSS_SessionsPerLocality ( TCS_CONTEXT_HANDLE hContext, // in UINT32 ulLocality, // in UINT32 ulSessions, // in TPM_AUTH* pOwnerAuth // in, out ); extern TSS_RESULT Tcsi_GetCredential ( TCS_CONTEXT_HANDLE hContext, // in UINT32 ulCredentialType, // in UINT32 ulCredentialAccessMode, // in UINT32* pulCredentialSize, // out BYTE** prgbCredentialData // out ); #if defined __cplusplus } // extern "C" #endif #endif /* TCS_H */ trousers-0.3.15/src/include/tss/TSP.idl0000664000175000017510000006734213663651711017153 0ustar deboradebora/*++ +++TSP.idl Interface declarations for the TSS Service Provider - COM interface for Windows based platforms --*/ import "oaidl.idl"; // include ODL base types import "ocidl.idl"; //import the header files from TSS v1.2 import "tss_typedef.h"; import "tss_structs.h"; // forward declaration interface ITCPAPolicy; interface ITCPAKey; /* Missing: TSS_RESULT Tspi_Context_Create TSS_RESULT Tspi_Context_Close TSS_RESULT Tspi_Context_FreeMemory */ //ITCPAAttrib Interface [ local, object, uuid(FBCD9C2E-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAAttrib Interface"), pointer_default(unique) ] interface ITCPAAttrib : IUnknown { [helpstring("method SetAttribUint32")] HRESULT SetAttribUint32([in] TSS_FLAG attribFlag, [in] TSS_FLAG subFlags, [in] UINT32 ulAttrib); [helpstring("method GetAttribUint32")] HRESULT GetAttribUint32([in] TSS_FLAG attribFlag, [in] TSS_FLAG subFlags, [out] UINT32* pulAttrib); [helpstring("method SetAttribData")] HRESULT SetAttribData([in] TSS_FLAG attribFlag, [in] TSS_FLAG subFlags, [in] UINT32 ulAttribDataSize, [in, ptr, size_is(ulAttribDataSize)] BYTE* pbAttribData); [helpstring("method GetAttribData")] HRESULT GetAttribData([in] TSS_FLAG attribFlag, [in] TSS_FLAG subFlags, [out] UINT32* pulAttribDataSize, [out, size_is(, *pulAttribDataSize)] BYTE** ppbAttribData); } //ITCPAAuth Interface [ local, object, uuid(FBCD9C2F-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAAuth Interface"), pointer_default(unique) ] interface ITCPAAuth : IUnknown { [helpstring("method GetPolicyObject")] HRESULT GetPolicyObject([in] TSS_FLAG PolicyType, [out] ITCPAPolicy** ppPolicyObject); [helpstring("method ChangeAuth")] HRESULT ChangeAuth([in] IUnknown* PpParentObject, [in] ITCPAPolicy* PpNewPolicy); // HRESULT ChangeAuthAsym }; [ object, uuid(FBCD9C2D-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAPcrs Interface"), pointer_default(unique) ] interface ITCPAPcrs : IUnknown { [helpstring("method SetPcrValue")] HRESULT SetPcrValue([in] UINT32 ulPCRIndex, [in] UINT32 ulPcrValueLength, [in, size_is(ulPcrValueLength)] BYTE* pbPcrValue); [helpstring("method GetPcrValue")] HRESULT GetPcrValue([in] UINT32 ulPCRIndex, [out] UINT32* pulPcrValueLength, [out, size_is(, *pulPcrValueLength)] BYTE** ppbPcrValue); [helpstring("method SelectPcrIndex")] HRESULT SelectPcrIndex([in] UINT32 ulPCRIndex); }; //ITCPAKey Interface [ object, uuid(FBCD9C27-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAKey Interface"), pointer_default(unique) ] interface ITCPAKey : IUnknown { [helpstring("method LoadKey")] HRESULT LoadKey([in] ITCPAKey* pUnwrappingKey); [helpstring("method CreateKey")] HRESULT CreateKey([in] ITCPAKey* pUnwrappingKey, [in] ITCPAPcrs* pPcrComosite); [helpstring("method WrapKey")] HRESULT WrapKey([in] ITCPAKey* pWrappinKey, [in] ITCPAPcrs* pPcrComposite); [helpstring("method CertifyKey")] HRESULT CertifyKey([in] ITCPAKey* pCertifyingKey, [in, out, ptr] TSS_VALIDATION* pValidation); [helpstring("method GetPubKey")] HRESULT GetPubKey([out] UINT32* pulPubKeyLength, [out, size_is(, *pulPubKeyLength)] BYTE** ppbPubKey); [helpstring("method UnLoadKey")] HRESULT UnLoadKey(); }; // ITCPAMigration [ local, object, uuid(FBCD9C30-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAMigration Interface"), pointer_default(unique) ] interface ITCPAMigration : IUnknown { [helpstring("method CreateMigrationBlob")] HRESULT CreateMigrationBlob([in] ITCPAKey *pParentKey, [in] UINT32 ulMigTicketLength, [in, size_is(ulMigTicketLength)] BYTE* rgbMigTicket, [out] UINT32 *pulRandomLength, [out, size_is(, *pulRandomLength)] BYTE **prgbRandom, [out] UINT32 *pulMigrationBlobLength, [out, size_is(, *pulMigrationBlobLength)] BYTE **prgbMigBlob); [helpstring("method ConvertMigrationBlob")] HRESULT ConvertMigrationBlob([in] ITCPAKey *pParentKey, [in] UINT32 ulRandomLength, [in, size_is(ulRandomLength)] BYTE *rgbRandom, [in] UINT32 ulMigrationBlobLength, [in, size_is(ulMigrationBlobLength)] BYTE *rgbMigBlob); }; //ITCPAEncData Interface [ uuid(FBCD9C29-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAEncData Interface"), pointer_default(unique) ] interface ITCPAEncData : IUnknown { [helpstring("method Seal")] HRESULT Seal([in] ITCPAKey* pEncKey, [in] UINT32 ulDataLength, [in, size_is(ulDataLength)] BYTE* pbData, [in] ITCPAPcrs* pPcrComposite); [helpstring("method Unseal")] HRESULT Unseal([in] ITCPAKey* pKey, [out] UINT32* pulUnsealedDataLength, [out, size_is(, *pulUnsealedDataLength)] BYTE** ppbData); [helpstring("method Bind")] HRESULT Bind([in] ITCPAKey* pEncKey, [in] UINT32 ulDataLength, [in, size_is(ulDataLength)] BYTE* pbData); [helpstring("method Unbind")] HRESULT Unbind([in] ITCPAKey* pKey, [out] UINT32* pulUnboundDataLength, [out, size_is(, *pulUnboundDataLength)] BYTE** ppbData); }; //ITCPAHash Interface [ local, object, uuid(FBCD9C2B-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAHash Interface"), pointer_default(unique) ] interface ITCPAHash : IUnknown { [helpstring("method SetHashValue")] HRESULT SetHashValue([in] UINT32 ulHashValueLength, [in, size_is(ulHashValueLength)] BYTE* pbHash); [helpstring("method GetHashValue")] HRESULT GetHashValue([out] UINT32* pulHashValueLength, [out, size_is(, *pulHashValueLength)] BYTE** ppbHash); [helpstring("method UpdateHashValue")] HRESULT UpdateHashValue([in] UINT32 ulDataLength, [in, size_is(ulDataLength)] BYTE* pbData); [helpstring("method Sign")] HRESULT Sign([in] ITCPAKey* pKey, [out] UINT32* pulSignatureLength, [out, size_is(, *pulSignatureLength)] BYTE** ppbSignature); [helpstring("method VerifySignature")] HRESULT VerifySignature([in] ITCPAKey* pKey, [in] UINT32 ulSignatureLength, [in, size_is(ulSignatureLength)] BYTE* pbSignature); }; //ITCPAPolicy Interface [ uuid(FBCD9C1E-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAPolicy Interface"), pointer_default(unique) ] interface ITCPAPolicy : IUnknown { [helpstring("method SetSecret")] HRESULT SetSecret([in] TSS_FLAG SecretMode, [in] UINT32 ulSecretLength, [in, ptr, size_is(ulSecretLength)] BYTE* pbSecret); [helpstring("method FlushSecret")] HRESULT FlushSecret(); [helpstring("method AssignToObject")] HRESULT AssignToObject([in] IUnknown* pUnkObject); }; //ITCPAAdministration Interface [ local, object, uuid(FBCD9C24-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAAdministration Interface"), pointer_default(unique) ] interface ITCPAAdministration : IUnknown { [helpstring("method SelfTestFull")] HRESULT SelfTestFull(); [helpstring("method GetTestResult")] HRESULT GetTestResult([out] UINT32* pulTestResultLength, [out, size_is(, *pulTestResultLength)] BYTE** ppbTestResult); [helpstring("method CertifySelfTest")] HRESULT CertifySelfTest([in] ITCPAKey* phKey, [in, out, ptr] TSS_VALIDATION* pValidationData); [helpstring("method CreateEndorsementKey")] HRESULT CreateEndorsementKey([in] ITCPAKey* pEndorsementKey, [in, out, ptr] TSS_VALIDATION* pValidation); [helpstring("method GetPubEndorsementKey")] HRESULT GetPubEndorsementKey([in] BOOL fOwnerAuthorized, [in, out, ptr] TSS_VALIDATION* pValidation, [out] ITCPAKey** ppEndorsementKey); [helpstring("method TakeOwnerShip")] HRESULT TakeOwnerShip([in] ITCPAKey* pKeySRK, [in] ITCPAKey* pEndorsementKeyPubKey); [helpstring("method ClearOwner")] HRESULT ClearOwner([in] BOOL fForcedClear); [helpstring("method SetStatus")] HRESULT SetStatus([in] TSS_FLAG statusFlag, [in] BOOL fTpmState); [helpstring("method GetStatus")] HRESULT GetStatus([in] TSS_FLAG statusFlag, [out] BOOL* pfTpmState); [helpstring("method AuthorizeMigrationTicket")] HRESULT AuthorizeMigrationTicket([in] ITCPAKey* pMigrationKey, [in] UINT32 MigrationScheme, [out] UINT32* pulMigTicketLength, [out, size_is(, *pulMigTicketLength)] BYTE** ppbMigTicket); } //ITCPAIntegrity Interface [ local, object, uuid(FBCD9C22-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAIntegrity Interface"), pointer_default(unique) ] interface ITCPAIntegrity : IUnknown { [helpstring("method PcrExtend")] HRESULT PcrExtend([in] UINT32 ulPcrIndex, [in] UINT32 ulPcrDataLength, [in, size_is(ulPcrDataLength)] BYTE* pbPcrData, [in, ptr] TSS_PCR_EVENT* pEventInfo, [out] UINT32* pulPcrValueLength, [out, size_is(, *pulPcrValueLength)] BYTE** ppbPcrValue); [helpstring("method PcrRead")] HRESULT PcrRead([in] UINT32 ulPcrIndex, [out] UINT32* pulPcrValueLength, [out, size_is(, *pulPcrValueLength)] BYTE** ppbPcrValue); [helpstring("method DirWrite")] HRESULT DirWrite([in] UINT32 ulDirIndex, [in] UINT32 ulDirDataLength, [in, size_is(ulDirDataLength)] BYTE* pbDirData); [helpstring("method DirRead")] HRESULT DirRead([in] UINT32 ulDirIndex, [out] UINT32* pulDirDataLength, [out, size_is(, *pulDirDataLength)] BYTE** pbDirData); [helpstring("method Quote")] HRESULT Quote([in] ITCPAKey* pIdentKey, [in] ITCPAPcrs* pPcrComposite, [in, out, ptr] TSS_VALIDATION* pValidation); }; //ITCPAIdentityCreation Interface [ object, uuid(FBCD9C23-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAIdentityCreation Interface"), pointer_default(unique) ] interface ITCPAIdentityCreation: IUnknown { [helpstring("method CollateIdentityRequest")] HRESULT CollateIdentityRequest([in] ITCPAKey* pKeySRK, [in] ITCPAKey* pCAPubKey, [in] UINT32 ulIdentityLabelLength, [in, size_is(ulIdentityLabelLength)] BYTE* rgbIdentityLabelData, [in] ITCPAKey* pIdentityKey, [in] TSS_ALGORITHM_ID algID, [out] UINT32* pulTCPAIdentityReqLength, [out, size_is(, *pulTCPAIdentityReqLength)] BYTE** prgbTCPAIdentityReq); [helpstring("method ActivateIdentity")] HRESULT ActivateIdentity([in] ITCPAKey* pIdentityKey, [in] UINT32 ulAsymCAContentsBlobLength, [in, size_is(ulAsymCAContentsBlobLength)] BYTE* rgbAsymCAContentsBlob, [in] UINT32 ulSymCAAttestationBlobLength, [in, size_is(ulSymCAAttestationBlobLength)] BYTE* rgbSymCAAttestationBlob, [out] UINT32* pulCredentialLength, [out, size_is(, *pulCredentialLength)] BYTE** prgbCredential); }; // end of ITCPAIdentityCreation //ITCPAMaintenance Interface [ local, object, uuid(FBCD9C25-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAMaintenance Interface"), pointer_default(unique) ] interface ITCPAMaintenance: IUnknown { // HRESULT CreateMaintenanceArchive // HRESULT KillMaintenanceFeature // HRESULT LoadMaintenancePubKey // HRESULT CheckMaintenancePubKey }; //ITCPATpm Interface [ uuid(FBCD9C21-72CB-47BB-99DD-2317551491DE), helpstring("ITCPATpm Interface"), pointer_default(unique) ] interface ITCPATpm : IUnknown { [helpstring("method GetRandom")] HRESULT GetRandom([in] UINT32 ulRandomDataLength, [out, size_is(, ulRandomDataLength)] BYTE** ppbData); [helpstring("method StirRandom")] HRESULT StirRandom([in] UINT32 ulEntropyDataLength, [in, size_is(ulEntropyDataLength)] BYTE* pbData); [helpstring("method GetCapability")] HRESULT GetCapability([in] TSS_FLAG CapArea, [in] UINT32 ulSubCapLength, [in, ptr, size_is(ulSubCapLength)] BYTE* pbSubCap, [out] UINT32* pulRespDataLength, [out, size_is(, *pulRespDataLength)] BYTE** ppbRespData); [helpstring("method GetCapabilitySigned")] HRESULT GetCapabilitySigned([in] ITCPAKey* pKey, [in] TSS_FLAG CapArea, [in] UINT32 ulSubCapLength, [in, ptr, size_is(ulSubCapLength)] BYTE* pbSubCap, [in, out, ptr] TSS_VALIDATION *pValidation, [out] UINT32* pulRespDataLength, [out, size_is(, *pulRespDataLength)] BYTE** ppbRespData); // HRESULT GetEvent // HRESULT GetEvents // HRESULT GetEventLog }; //ITCPAPersistentStorage Interface [ local, object, uuid(FBCD9C1C-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAPersistentStorage Interface"), pointer_default(unique) ] interface ITCPAPersistentStorage: IUnknown { [helpstring("method LoadKeyByUUID")] HRESULT LoadKeyByUUID([in] TSS_FLAG persistentStorageType, [in] TSS_UUID uuidData, [out] ITCPAKey** ppKey); [helpstring("method RegisterKey")] HRESULT RegisterKey([in] ITCPAKey* pKey, [in] TSS_FLAG persistentStorageType, [in] TSS_UUID uuidKey, [in] TSS_FLAG persistentStorageTypeParent, [in] TSS_UUID uuidParentKey); [helpstring("method UnregisterKey")] HRESULT UnregisterKey([in] TSS_FLAG persistentStorageType, [in] TSS_UUID uuidKey, [out] ITCPAKey** ppKey); [helpstring("method DeleteKeyByUUID")] HRESULT DeleteKeyByUUID([in] TSS_FLAG persistentStorageType, [in] TSS_UUID uuidData); [helpstring("method GetKeyByUUID")] HRESULT GetKeyByUUID([in] TSS_FLAG persistentStorageType, [in] TSS_UUID uuidData, [out] ITCPAKey** ppKey); [helpstring("method GetKeyByPublicInfo")] HRESULT GetKeyByPublicInfo([in] TSS_FLAG persistentStorageType, [in] TSS_ALGORITHM_ID ulAlgId, [in] UINT32 ulPublicInfoLength, [in, size_is(ulPublicInfoLength)] BYTE* pbPublicInfo, [out] ITCPAKey** ppKey); [helpstring("method GetRegisteredKeysByUUID")] HRESULT GetRegisteredKeysByUUID([in] TSS_FLAG ulPersistentStorageType, [in] LPOLESTR wszKeyGuid, [out] UINT32* pulKeyHierarchySize, [out, size_is(, *pulKeyHierarchySize)] TSS_KM_KEYINFO** ppKeyHierarchy); } //ITCPAContext Interface [ local, object, uuid(FBCD9C1B-72CB-47BB-99DD-2317551491DE), helpstring("ITCPAContext Interface"), pointer_default(unique) ] interface ITCPAContext : IUnknown { [helpstring("method Connect")] HRESULT Connect([in, ptr] LPOLESTR wszRemoteMachine); [helpstring("method CreateObject")] HRESULT CreateObject([in] UINT32 ulObjectType, [in] UINT32 ulInitFlags, [out] IUnknown** ppUnkObject); // HRESULT CloseObject [helpstring("method LoadKeyByBlob")] HRESULT LoadKeyByBlob([in] ITCPAKey* pUnwrappingKey, [in] UINT32 ulBlobLength, [in, size_is(ulBlobLength)] BYTE* pbBlobData, [out] ITCPAKey** ppKey); [helpstring("method GetTPMObject")] HRESULT GetTPMObject([out] ITCPATpm** ppTPMObject); [helpstring("method GetDefaultPolicy")] HRESULT GetDefaultPolicy([out] ITCPAPolicy** ppPolicyObject); [helpstring("method GetCapability")] HRESULT GetCapability([in] TSS_FLAG ulCapArea, [in] UINT32 ulSubCapLength, [in, ptr, size_is(ulSubCapLength)] BYTE* pbSubCap, [out] UINT32* pulRespDataLength, [out, size_is(, *pulRespDataLength)] BYTE** ppbRespData); }; //ITCPANonVolatileStorage Interface [ object, uuid(4730c51b-8998-43f6-993b-80befea1d404), helpstring("ITCPANonVolatileStorage Interface"), pointer_default(unique) ] interface ITCPANonVolatileStorage : IUnknown { [helpstring("method DefineSpace")] HRESULT DefineSpace([in] ITCPAPcrs* pPCRsRead, [in] ITCPAPcrs* pPCRsWrite); [helpstring("method ReleaseSpace")] HRESULT ReleaseSpace(); [helpstring("method WriteValue")] HRESULT WriteValue([in] UINT32 ulOffset, [in] UINT32 ulDataLength, [in, size_is(ulDataLength)] BYTE* rgbData); [helpstring("method ReadValue")] HRESULT ReadValue([in] UINT32 ulOffset, [in, out] UINT32* pulDataLength, [out, size_is(, *pulDataLength)] BYTE** prgbData); }; //ITCPATransport Interface [ object, uuid(4730c51d-8998-43f6-993b-80befea1d404), helpstring("ITCPATransport Interface"), pointer_default(unique) ] interface ITCPATransport : IUnknown { [helpstring("method SetTransEncryptionKey")] HRESULT SetTransEncryptionKey([in] ITCPAKey* pKey); [helpstring("method CloseSignTransport")] HRESULT CloseSignTransport([in] ITCPAKey* pSigningKey, [in, out, ptr] TSS_VALIDATION* pValidationData); }; [ uuid(FBCD9C19-72CB-47BB-99DD-2317551491DE), version(1.0), helpstring("TSS Service Provider 1.0 Type Library") ] library TSPLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); interface ITCPAContext; //TCPAContext Class [ uuid(FBCD9C1A-72CB-47BB-99DD-2317551491DE), helpstring("TCPAContext Class") ] coclass TCPAContext { [default] interface ITCPAContext; interface ITCPAAttrib; interface ITCPAPersistentStorage; }; //TCPAContext2 Class extensions for TSS v1.2 [ uuid(4730C51E-8998-43F6-993B-80BEFEA1D404), helpstring("TCPAContext2 Class") ] coclass TCPAContext2 { [default] interface ITCPAContext; interface ITCPAAttrib; interface ITCPAPersistentStorage; interface ITCPATransport; }; // _ITCPACallback Interface for TCPAPolicy Class [ uuid(FBCD9C1F-72CB-47BB-99DD-2317551491DE), helpstring("_ITCPACallback Interface"), pointer_default(unique) ] interface _ITCPACallback : IUnknown { [helpstring("method Tspicb_CallbackHMACAuth"), callback] HRESULT Tspicb_CallbackHMACAuth([in] UINT32 PulAppData, [in] IUnknown *PpAuthorizedObject, [in] BOOL PfReturnOrVerify, [in] UINT32 PulPendingFunction, [in] BOOL PfContinueUse, [in] UINT32 PulSizeNonces, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceEven, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceOdd, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceEvenOSAP, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceOddOSAP, [in] UINT32 PulSizeDigestHmac, [in, size_is(PulSizeDigestHmac)] BYTE* PrgbParamDigest, [in, out, size_is(PulSizeDigestHmac)] BYTE* PrgbHmacData); [helpstring("method Tspicb_CallbackXorEnc"), callback] HRESULT Tspicb_CallbackXorEnc([in] UINT32 PulAppData, [in] IUnknown *PpOSAPObject, [in] IUnknown *PpObject, [in] BOOL PfPurposeSecret, [in] UINT32 PulSizeNonces, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceEven, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceOdd, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceEvenOSAP, [in, size_is(PulSizeNonces)] BYTE* PrgbNonceOddOSAP, [in] UINT32 PulSizeEncAuth, [out, size_is(PulSizeEncAuth)] BYTE* PrgbEncAuthUsage, [out, size_is(PulSizeEncAuth)] BYTE* PrgbEncAuthMigration); [helpstring("method Tspicb_CallbackTakeOwnership"), callback] HRESULT Tspicb_CallbackTakeOwnership([in] UINT32 PulAppData, [in] IUnknown *PpObject, [in] IUnknown *PpObjectPubKey, [in] UINT32 PulSizeEncAuth, [out, size_is(PulSizeEncAuth)] BYTE* PrgbEncAuth ); [helpstring("method Tspicb_CallbackChangeAuthAsym"), callback] HRESULT Tspicb_CallbackChangeAuthAsym([in] UINT32 PulAppData, [in] IUnknown *PpObject, [in] IUnknown *PpObjectPubKey, [in] UINT32 PulSizeEncAuth, [in] UINT32 PulSizeAuthLink, [out, size_is(PulSizeEncAuth)] BYTE* PrgbEncAuth, [out, size_is(PulSizeAuthLink)] BYTE* PrgbAuthLink); }; // end of _ITCPACallback //TCPAPolicy Class [ uuid(FBCD9C1D-72CB-47BB-99DD-2317551491DE), helpstring("TCPAPolicy Class"), noncreatable ] coclass TCPAPolicy { [default] interface ITCPAPolicy; interface ITCPAAttrib; [default, source] interface _ITCPACallback; }; //TCPATpm Class [ uuid(FBCD9C20-72CB-47BB-99DD-2317551491DE), helpstring("TCPATpm Class"), noncreatable ] coclass TCPATpm { [default] interface ITCPATpm; interface ITCPAAttrib; interface ITCPAAuth; interface ITCPAIntegrity; interface ITCPAAdministration; interface ITCPAIdentityCreation; interface ITCPAMaintenance; }; //TCPAKey Class [ uuid(FBCD9C26-72CB-47BB-99DD-2317551491DE), helpstring("TCPAKey Class"), noncreatable ] coclass TCPAKey { [default] interface ITCPAKey; interface ITCPAAttrib; interface ITCPAAuth; interface ITCPAMigration; }; //TCPAEncData Class [ uuid(FBCD9C28-72CB-47BB-99DD-2317551491DE), helpstring("TCPAEncData Class"), noncreatable ] coclass TCPAEncData { [default] interface ITCPAEncData; interface ITCPAAttrib; interface ITCPAAuth; }; //TCPAHash Class [ uuid(FBCD9C2A-72CB-47BB-99DD-2317551491DE), helpstring("TCPAHash Class"), noncreatable ] coclass TCPAHash { [default] interface ITCPAHash; interface ITCPAAttrib; }; //TCPAPcrs Class [ uuid(FBCD9C2C-72CB-47BB-99DD-2317551491DE), helpstring("TCPAPcrs Class"), noncreatable ] coclass TCPAPcrs { [default] interface ITCPAPcrs; }; //TCPANonVolatileStorage Class [ uuid(4730c51c-8998-43f6-993b-80befea1d404), helpstring("TCPANonVolatileStorage Class"), noncreatable ] coclass TCPANonVolatileStorage { [default] interface ITCPANonVolatileStorage; interface ITCPAAttrib; interface ITCPAAuth; }; }; // end of library TSPLib trousers-0.3.15/src/include/tss/tss_error_basics.h0000664000175000017510000000317513663651711021524 0ustar deboradebora/*++ Basic defines for TSS error return codes --*/ #ifndef __TSS_ERROR_BASICS_H__ #define __TSS_ERROR_BASICS_H__ // // definitions for the various TSS-SW layers // #ifndef TSS_LAYER_TPM #define TSS_LAYER_TPM 0x0000L // definition for TPM layer #endif // TSS_LAYER_TPM #define TSS_LAYER_TDDL 0x1000L // definition for TDDL layer #define TSS_LAYER_TCS 0x2000L // definition for TCS layer #ifndef TSS_LAYER_TSP #define TSS_LAYER_TSP 0x3000L // definition for TSP layer #endif // TSS_LAYER_TSP // // definitions for the start points of layer specific error codes // #ifndef TSS_COMMON_OFFSET #define TSS_COMMON_OFFSET 0x000L #endif // TSS_COMMON_OFFSET #define TSS_TDDL_OFFSET 0x080L #define TSS_TCSI_OFFSET 0x0C0L #ifndef TSS_TSPI_OFFSET #define TSS_TSPI_OFFSET 0x100L #endif // TSS_TSPI_OFFSET #ifndef TSS_VENDOR_OFFSET #define TSS_VENDOR_OFFSET 0x800L #endif // TSS_VENDOR_OFFSET // do not exceed TSS_MAX_ERROR for vendor specific code values: #ifndef TSS_MAX_ERROR #define TSS_MAX_ERROR 0xFFFL #endif // TSS_MAX_ERROR /* Macros for the construction and interpretation of error codes */ #define TPM_ERROR(code) (code) #define TDDL_ERROR(code) ((code) ? (TSS_LAYER_TDDL | (code)) : (code)) #define TCS_ERROR(code) ((code) ? (TSS_LAYER_TCS | (code)) : (code)) #define TSP_ERROR(code) ((code) ? (TSS_LAYER_TSP | (code)) : (code)) #define ERROR_LAYER(error) ((error) & 0xf000) #define ERROR_CODE(error) ((error) & 0x0fff) #endif // __TSS_ERROR_BASICS_H__ trousers-0.3.15/src/include/tss/tcpa_typedef.h0000664000175000017510000000020013663651711020607 0ustar deboradebora #ifndef __TCPA_TYPEDEF_H__ #define __TCPA_TYPEDEF_H__ #warning including deprecated header file tcpa_typedef.h #endif trousers-0.3.15/src/include/obj_daaarakey.h0000664000175000017510000000304113663651711020111 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #ifndef _OBJ_DAAARAKEY_H_ #define _OBJ_DAAARAKEY_H_ #ifdef TSS_BUILD_DAA /* structures */ struct tr_daaarakey_obj { UINT32 session_handle; TPM_HANDLE tpm_handle; }; /* prototypes */ void daaarakey_free(void *data); TSS_RESULT obj_daaarakey_add(TSS_HCONTEXT tspContext, TSS_HOBJECT *phObject); TSS_RESULT obj_daaarakey_remove(TSS_HDAA_ISSUER_KEY, TSS_HCONTEXT); TSS_BOOL obj_is_daaarakey(TSS_HDAA_ISSUER_KEY); TSS_RESULT obj_daaarakey_get_tsp_context(TSS_HDAA_ISSUER_KEY, TSS_HCONTEXT *); TSS_RESULT obj_daaarakey_get_handle_tpm(TSS_HDAA_ISSUER_KEY, TPM_HANDLE *); TSS_RESULT obj_daaarakey_set_handle_tpm(TSS_HDAA_ISSUER_KEY, TPM_HANDLE); TSS_RESULT obj_daaarakey_get_session_handle(TSS_HDAA_ISSUER_KEY, UINT32 *); TSS_RESULT obj_daaarakey_set_session_handle(TSS_HDAA_ISSUER_KEY, UINT32); #define DAAARAKEY_LIST_DECLARE struct obj_list daaarakey_list #define DAAARAKEY_LIST_DECLARE_EXTERN extern struct obj_list daaarakey_list #define DAAARAKEY_LIST_INIT() tspi_list_init(&daaarakey_list) #define DAAARAKEY_LIST_CONNECT(a,b) obj_connectContext_list(&daaarakey_list, a, b) #define DAAARAKEY_LIST_CLOSE(a) obj_list_close(&daaarakey_list, &daaarakey_free, a) #else #define obj_is_daaarakey(a) FALSE #define DAAARAKEY_LIST_DECLARE #define DAAARAKEY_LIST_DECLARE_EXTERN #define DAAARAKEY_LIST_INIT() #define DAAARAKEY_LIST_CONNECT(a,b) #define DAAARAKEY_LIST_CLOSE(a) #endif #endif trousers-0.3.15/src/include/tcsem.h0000664000175000017510000000275113663651711016457 0ustar deboradebora /* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2006 * */ #ifndef _TCSEM_H_ #define _TCSEM_H_ struct ext_log_source { int (*open)(void *, FILE **); TSS_RESULT (*get_entries_by_pcr)(FILE *, UINT32, UINT32, UINT32 *, TSS_PCR_EVENT **); TSS_RESULT (*get_entry)(FILE *, UINT32, UINT32 *, TSS_PCR_EVENT **); int (*close)(FILE *); }; struct event_wrapper { TSS_PCR_EVENT event; struct event_wrapper *next; }; struct event_log { MUTEX_DECLARE(lock); struct ext_log_source *firmware_source; struct ext_log_source *kernel_source; struct event_wrapper **lists; }; /* include the compiled-in log sources and struct references here */ #include "imaem.h" #include "biosem.h" #ifdef EVLOG_SOURCE_IMA #define EVLOG_IMA_SOURCE &ima_source #else #define EVLOG_IMA_SOURCE NULL #endif #ifdef EVLOG_SOURCE_BIOS #define EVLOG_BIOS_SOURCE &bios_source #else #define EVLOG_BIOS_SOURCE NULL #endif TSS_RESULT event_log_init(); TSS_RESULT event_log_final(); TSS_RESULT copy_pcr_event(TSS_PCR_EVENT *, TSS_PCR_EVENT *); TSS_RESULT event_log_add(TSS_PCR_EVENT *, UINT32 *); TSS_PCR_EVENT *get_pcr_event(UINT32, UINT32); UINT32 get_num_events(UINT32); TSS_PCR_EVENT *concat_pcr_events(TSS_PCR_EVENT **, UINT32, TSS_PCR_EVENT *, UINT32); UINT32 get_pcr_event_size(TSS_PCR_EVENT *); void free_external_events(UINT32, TSS_PCR_EVENT *); extern struct event_log *tcs_event_log; #endif trousers-0.3.15/man/0000775000175000017510000000000013663651711013527 5ustar deboradeboratrousers-0.3.15/man/Makefile.am0000664000175000017510000000003113663651711015555 0ustar deboradeboraSUBDIRS = man3 man5 man8 trousers-0.3.15/man/man3/0000775000175000017510000000000013663651711014365 5ustar deboradeboratrousers-0.3.15/man/man3/Makefile.am0000664000175000017510000000564013663651711016426 0ustar deboradeboraman3_MANS = Tspi_ChangeAuth.3 \ Tspi_ChangeAuthAsym.3 \ Tspi_Context_Close.3 \ Tspi_Context_CloseObject.3 \ Tspi_Context_Connect.3 \ Tspi_Context_Create.3 \ Tspi_Context_CreateObject.3 \ Tspi_Context_FreeMemory.3 \ Tspi_Context_GetCapability.3 \ Tspi_Context_GetDefaultPolicy.3 \ Tspi_Context_GetKeyByPublicInfo.3 \ Tspi_Context_GetKeyByUUID.3 \ Tspi_Context_GetRegisteredKeysByUUID.3 \ Tspi_Context_GetRegisteredKeysByUUID2.3 \ Tspi_Context_GetTpmObject.3 \ Tspi_Context_LoadKeyByBlob.3 \ Tspi_Context_LoadKeyByUUID.3 \ Tspi_Context_RegisterKey.3 \ Tspi_Context_UnregisterKey.3 \ Tspi_Data_Bind.3 \ Tspi_Data_Seal.3 \ Tspi_Data_Unbind.3 \ Tspi_Data_Unseal.3 \ Tspi_DecodeBER_TssBlob.3 \ Tspi_EncodeDER_TssBlob.3 \ Tspi_GetAttribData.3 \ Tspi_GetAttribUint32.3 \ Tspi_GetPolicyObject.3 \ Tspi_Hash_GetHashValue.3 \ Tspi_Hash_SetHashValue.3 \ Tspi_Hash_Sign.3 \ Tspi_Hash_UpdateHashValue.3 \ Tspi_Hash_VerifySignature.3 \ Tspi_Key_CertifyKey.3 \ Tspi_Key_ConvertMigrationBlob.3 \ Tspi_Key_CreateKey.3 \ Tspi_Key_CreateMigrationBlob.3 \ Tspi_Key_GetPubKey.3 \ Tspi_Key_LoadKey.3 \ Tspi_Key_UnloadKey.3 \ Tspi_Key_WrapKey.3 \ Tspi_PcrComposite_GetPcrValue.3 \ Tspi_PcrComposite_SelectPcrIndex.3 \ Tspi_PcrComposite_SetPcrValue.3 \ Tspi_Policy_AssignToObject.3 \ Tspi_Policy_FlushSecret.3 \ Tspi_Policy_SetSecret.3 \ Tspi_SetAttribData.3 \ Tspi_SetAttribUint32.3 \ Tspi_TPM_AuthorizeMigrationTicket.3 \ Tspi_TPM_CertifySelfTest.3 \ Tspi_TPM_CheckMaintenancePubKey.3 \ Tspi_TPM_ClearOwner.3 \ Tspi_TPM_CollateIdentityRequest.3 \ Tspi_TPM_CreateEndorsementKey.3 \ Tspi_TPM_CreateMaintenanceArchive.3 \ Tspi_TPM_DirRead.3 \ Tspi_TPM_DirWrite.3 \ Tspi_TPM_GetCapability.3 \ Tspi_TPM_GetEvent.3 \ Tspi_TPM_GetEventLog.3 \ Tspi_TPM_GetEvents.3 \ Tspi_TPM_GetPubEndorsementKey.3 \ Tspi_TPM_GetRandom.3 \ Tspi_TPM_GetStatus.3 \ Tspi_TPM_GetTestResult.3 \ Tspi_TPM_KillMaintenanceFeature.3 \ Tspi_TPM_LoadMaintenancePubKey.3 \ Tspi_TPM_PcrRead.3 \ Tspi_TPM_PcrExtend.3 \ Tspi_TPM_Quote.3 \ Tspi_TPM_SelfTestFull.3 \ Tspi_TPM_SetStatus.3 \ Tspi_TPM_StirRandom.3 \ Tspi_TPM_TakeOwnership.3 \ Tspi_TPM_GetAuditDigest.3 \ Tspi_TPM_OwnerGetSRKPubKey.3 \ Tspi_TPM_Quote2.3 \ Tspi_TPM_CMKSetRestrictions.3 if TSS_BUILD_DAA man3_MANS += Tspi_DAA_IssueCredential.3 \ Tspi_DAA_VerifySignature.3 \ Tspi_DAA_IssueInit.3 \ Tspi_TPM_DAA_JoinCreateDaaPubKey.3 \ Tspi_DAA_IssuerKeyVerification.3 \ Tspi_TPM_DAA_JoinInit.3 \ Tspi_DAA_IssueSetup.3 \ Tspi_TPM_DAA_JoinStoreCredential.3 \ Tspi_DAA_VerifyInit.3 \ Tspi_TPM_DAA_Sign.3 endif EXTRA_DIST = $(man3_MANS) trousers-0.3.15/man/man3/Tspi_Context_LoadKeyByUUID.30000664000175000017510000000446613663651711021500 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_LoadKeyByUUID" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_LoadKeyByUUID \- load a key that's been registered in persistent storage. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_LoadKeyByUUID(TSS_HCONTEXT " hContext ", TSS_FLAG " persistentStorageType ", " .BI " TSS_UUID " uuidData ", TSS_HKEY* " phKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_LoadKeyByUUID\fR creates a key object based on the information got from the manager using the UUID and loads the key into the TPM. The persistent storage provides all information to load the parent keys required to load the key associated with the given UUID. .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS persistentStorageType Flag indicating the persistent storage the key is registered in. Should be either TSS_PS_TYPE_USER ot TSS_PS_TYPE_SYSTEM. .PP .SS uuidData The UUID of the key by which the key was registered in the persistent storage (TSP or connected TCS). .PP .SS phKey Receives the handle of the key object representing the loaded key. .SH "RETURN CODES" .PP \fBTspi_Context_LoadKeyByUUID\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhContext\fR is an invalid handle. .TP .SM TSS_E_BAD_PARAMETER - \fIpersistentStorageType\fR is not valid. .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_LoadKeyByUUID\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_LoadKeyByBlob(3)\fR, \fBTspi_Key_LoadKey(3)\fR. trousers-0.3.15/man/man3/Tspi_TPM_GetEventLog.30000664000175000017510000000371013663651711020354 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetEventLog" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_GetEventLog\- get the entire PCR event log. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetEventLog(TSS_HTPM " hTPM ", UINT32* " pulEventNumber "," .BI " TSS_PCR_EVENT** " prgPcrEvents ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetEventLog\fR provides the whole event log that was used to create all of the PCRs. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object. .PP .SS pulEventNumber Receives number of returned event data structures in prgPcrEvents parameter. .PP .SS prgPcrEvents Receives a pointer to an array of PCR event data. If NULL, only the numberof elements is returned in pulEventNumber parameter. .SH "RETURN CODES" .PP \fBTspi_TPM_GetEventLog\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE \fBhTPM\fR is not a valid handle to the TPM object. .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetEventLog\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetEvent\fR(3) \fBTspi_TPM_GetEvents\fR(3). trousers-0.3.15/man/man3/Tspi_Context_GetKeyByUUID.30000664000175000017510000000466513663651711021341 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_GetKeyByUUID" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_Context_GetKeyByUUID \- get a handle to a key registered in persistent storage. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_GetKeyByUUID(TSS_HCONTEXT " hContext ", TSS_FLAG " persistentStorageType "," .BI " TSS_UUID " uuidData ", TSS_HKEY* " phKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_GetKeyByUUID\fR searches the Persistent Storage database for a registered key using the given UUID. It then creates a key object initialized to the found data and returns a handle to the key object. .SH "PARAMETERS" .PP .SS hContext The \fIhContext\fR parameter is the handle of the context object. .SS persistentStorageType The \fIpersistentStorageType\fR parameter indicates the persistent storage the key is registered in. .SS uuidData The \fIuuidData\fR parameter is the UUID by which the key is registered in persistent storage. .SS phKey The \fIphKey\fR parameter receives the handle of the key object representing the key. .SH "RETURN CODES" .PP \fBTspi_Context_GetKeyByUUID\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhContext\fR is an invalid handle. .TP .SM TSS_E_PS_KEY_NOTFOUND The key cannot be found in the persistent storage database. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_Context_GetKeyByUUID\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_GetTpmObject\fR(3), \fBTspi_Context_LoadKeyByUUID\fR(3), \fBTspi_Context_GetRegisteredKeysByUUID\fR(3), \fBTspi_Context_GetKeyByPublicInfo\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_GetTestResult.30000664000175000017510000000363013663651711020750 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetTestResult" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_GetTestResult\- get manufacturer specific information regarding the results of a self test. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetTestResult(TSS_HTPM " hTPM ", UINT32* " pulTestResultLength ", BYTE** " prgbTestResult ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetTestResult\fR is provided by a manufacturer of a TPM to provide manufacturer specific self test results. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object .PP .SS pulTestREsultLength Receives the length (in bytes) of the prgbTestResult parameter .PP .SS prgbTestResult Pointer to the memory block containing the TPM manufacturer specific information. .SH "RETURN CODES" .PP \fBTspi_TPM_GetTestResult\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE \fBhTPM\fR is not a valid handle to the TPM object. .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetTestResult\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_SelfTestFull\fR(3). trousers-0.3.15/man/man3/Tspi_PcrComposite_SetPcrValue.30000664000175000017510000000431113663651711022333 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_PcrComposite_SetPcrValue" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_PcrComposite_SetPcrValue\- set the digest for a given PCR index inside a PCR composite object. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_PcrComposite_SetPcrValue(TSS_HPCRS " hPcrComposite ", UINT32 " ulPcrIndex "," .BI " UINT32 " ulPcrValueLength ", BYTE* " rgbPcrValue ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_PcrComposite_SetPcrValue\fR sets the digest for a given PCR index inside the PCR composite object. .SH "PARAMETERS" .PP .SS hPcrComposite Handle of the PCR composite object instance where a PCR value should be set. .PP .SS ulPcrIndex This parameter indicates the index of the PCR to set. .PP .SS ulPcrValueLength The length (in bytes) of the rgbPcrValue parameter. .PP .SS rgbPcrValue Pointer to memory containing the actual value which should be set for the PCR indicated by ulPcrIndex. .SH "RETURN CODES" .PP \fBTspi_PcrComposite_SetPcrValue\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhPcrComposite\fR or \fIulPcrIndex\fR is an invalid parameter. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_PcrComposite_SetPcrValue\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_PcrComposite_SelectPcrIndex\fR(3), \fBTspi_PcrComposite_GetPcrValue\fR(3). trousers-0.3.15/man/man3/Tspi_Context_Close.30000664000175000017510000000315013663651711020220 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_Close" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_Close \- destroy a TSP context handle. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_Close(TSS_HCONTEXT " hLocalContext ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_Close\fR destroys a context by passing in the handle to that context. .SH "PARAMETERS" .PP .SS hLocalContext The handle to the context to be closed. .SH "RETURN CODES" .PP \fBTspi_Context_Close\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhLocalContext\fR is an invalid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_Close\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_Create\fR(3), \fBTspi_Context_Connect\fR(3). trousers-0.3.15/man/man3/Tspi_Hash_VerifySignature.30000664000175000017510000000477513663651711021556 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Hash_VerifySignature" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Hash_VerifySignature \- verify the hash value with a given signature .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Hash_VerifySignature(TSS_HHASH " hHash ", TSS_HKEY " hKey "," .BI " UINT32 " ulSignatureLength ", BYTE* " rgbSignature ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Hash_VerifySignature\fR verifies the hash value of a given hash object with a given signature. In order to use this command, one must have a hash and a signature of the hash that one is trying to verify. The public key which corresponds to the private key used to sign the hash is also needed. .SH "PARAMETERS" .PP .SS hHash The handle to the hash object instance whose hash value should be signed. .SS hKey Handle to the key object which should be used for the signature verification. .SS ulSignatureLength The length of the signature data provided at the parameter \fIrgbSignature\fR. .SS rgbSignature A pointer to the signature data. .SH "RETURN CODES" .PP \fBTspi_Hash_VerifySignature\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_HASH_INVALID_LENGTH Hash length is inconsistent with hash algorithm. .TP .SM TSS_E_HASH_NO_DATA Hash object has no internal hash value. .TP .SM TSS_E_INVALID_SIGSCHEME Invalid signature scheme. .SH "CONFORMING TO" .PP \fBTspi_Hash_VerifySignature\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Hash_UpdateHashValue\fR(3), \fBTspi_Hash_SetHashValue\fR(3), \fBTspi_Hash_Sign\fR(3), \fRTspi_Hash_GetHashValue\fR(3). trousers-0.3.15/man/man3/Tspi_Key_LoadKey.30000664000175000017510000000340713663651711017614 0ustar deboradebora.\" Copyright (C) 2005 International Business Machines Corporation .\" Written by Kent Yoder based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_LoadKey" 3 "2005-02-01" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Key_LoadKey \- load a key into the TPM .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_LoadKey(TSS_HKEY " hKey ", TSS_HKEY " hUnwrappingKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Key_LoadKey\fR loads the key referenced by \fIhKey\fR into the TPM. .SH "PARAMETERS" .PP .SS hKey The \fIhKey\fR parameter is the handle of the key object to load. .SS hUnwrappingKey The \fIhUnwrappingKey\fR parameter is the handle of the key which should be used to unwrap the key addressed by \fIhKey\fR. .SH "RETURN CODES" .PP \fBTspi_Key_LoadKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either \fIhKey\fR or \fIhUnwrappingKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_Key_LoadKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_UnloadKey\fR(3), \fBTspi_Key_GetPubKey\fR(3). trousers-0.3.15/man/man3/Tspi_Context_GetRegisteredKeysByUUID.30000664000175000017510000000603513663651711023533 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_GetRegisteredKeysByUUID" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_GetRegisteredKeysByUUID \- get an array of TSS_KM_KEYINFO structures based on the state of persistent storage. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_GetRegisteredKeysByUUID(TSS_HCONTEXT " hContext ", TSS_FLAG " persistentStorageType "," .BI " TSS_UUID* " pUuidData ", UINT32* " pulKeyHierarchySize "," .BI " TSS_KM_KEYINFO** " ppKeyHierarchy ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_GetRegisteredKeysByUUID\fR gets an array of TSS_KM_KEYINFO structures. This information reflects the state of the registered key hierarchy. The keys stored in the persistent storage are totallly independent from either the context provided in the function call or the context, which was provided while processing the key registration. .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS persistentStorageType Flag indicating the persistent storage the key is registered in. .PP .SS pUuidData The UUID the key was registered in the persistent storage (TSP or connected TCS). If no key UUID is provided, thus KeyUUID is NULL, the returned array of the TSS_KM_KEYINFO structure contins data reflecting the whole key hierarchy starting with root key. If a certain key is UUID is provided, the returned array of TSS_KM_KEYINFO structures only contains data reflecting the path of the key hierarchy regarding that key. The first array entry is the key addressed by the given UUID followed by its parent key up to the root key. .PP .SS pulKeyHierarchySize Recieves the length (number of array entries) of the ppKeyHierarchy parameter. .PP .SS ppKeyHierarchy On successful completion of the command, this parameter points to a buffer containing the actual key hierarchy data. .SH "RETURN CODES" .PP \fBTspi_Context_GetRegisteredKeysByUUID\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhContext\fR is an invalid handle. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_GetRegisteredKeysByUUID\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_LoadKeyByUUID\fR(3). trousers-0.3.15/man/man3/Tspi_Policy_SetSecret.30000664000175000017510000000503113663651711020667 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Policy_SetSecret" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Policy_SetSecret \- set the authorization data of a policy object and define the handling of its retrieval .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Policy_SetSecret(TSS_HPOLICY " hPolicy ", TSS_FLAG " secretMode "," .BI " UINT32 " ulSecretLength ", BYTE* " rgbSecret ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Policy_SetSecret\fR sets the authorization data for an object. This mthod also defines the handling of its retrieving. There are mand different paths as specified by the secretMode Flag. .SH "PARAMETERS" .PP .SS hPolicy The handle of the policy object. .PP .SS secretMode Flag indicating the policy secret mode to set. Possible values are: \fBTSS_SECRET_MODE_SHA1\fR - Secret in the form of 20 bytes of SHA-1 data. The secret will not be touched by the TSP. \fBTSS_SECRET_MODE_PLAIN\fR - The data passed in will be hashed by the TSP using SHA-1. \fBTSS_SECRET_MODE_POPUP\fR - The TSP will ask for a secret by displaying a GUI pop-up window. \fBTSS_SECRET_MODE_CALLBACK\fR - The application will provide a callback function for authorization data. \fBTSS_SECRET_MODE_NONE\fR - \fIulSecretLen\fR and \fIrgbSecret\fR are ignored and any object requiring auth assigned this policy will return an error. .PP .SS ulSecretLength The length (in bytes) of the rgbSecret parameter. .PP .SS rgbSecret The secret data blob. .SH "RETURN CODES" .PP \fBTspi_Policy_SetSecret\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - hPolicy is an invalid parameter. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Policy_SetSecret\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Policy_FlushSecret\fR(3). trousers-0.3.15/man/man3/Tspi_Hash_GetHashValue.30000664000175000017510000000430413663651711020734 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Hash_GetHashValue" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Hash_GetHashValue \- get the current hash value of a hash object .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Hash_GetHashValue(TSS_HHASH " hHash ", UINT32* " pulHashValueLength ", BYTE** " prgbHashValue ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Hash_GetHashValue\fR gets the hash value of a hash object. \fBTspi_Context_FreeMemory\fR must be used to clean up after this function, as memory is allocated for the \fIprgbHashValue\fR data. .SH "PARAMETERS" .PP .SS hHash The handle to the hash object instance whose hash value should be signed. .SS pulHashValueLength Receives the length of the hash value data returned at the parameter \fIprgbHashValue\fR. .SS prgbHashValue Receives a pointer to the hash value data. .SH "RETURN CODES" .PP \fBTspi_Hash_GetHashValue\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhHash\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_HASH_INVALID_LENGTH Hash length is inconsistent with hash algorithm. .TP .SM TSS_E_HASH_NO_DATA Hash object has no internal hash value. .SH "CONFORMING TO" .PP \fBTspi_Hash_GetHashValue\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Hash_UpdateHashValue\fR(3), \fBTspi_Hash_Sign\fR(3), \fBTspi_Hash_VerifySignature\fR(3), \fBTspi_Hash_SetHashValue\fR(3). trousers-0.3.15/man/man3/Tspi_Key_ConvertMigrationBlob.30000664000175000017510000000540713663651711022357 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_ConvertMigrationBlob" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Key_ConvertMigrationBlob \- create a wrapped key from a migration blob .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_ConvertMigrationBlob(TSS_HKEY " hKeyToMigrate ", TSS_HKEY " hParentKey "," .BI " UINT32 " ulRandomLength ", BYTE* " rgbRandom "," .BI " UINT32 " ulMigrationBlobLength ", BYTE* " rgbMigrationBlob ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Key_ConvertMigrationBlob\fR takes the migration blob built by \fBTspi_Key_CreateMigrationBlob\fR using the migration scheme TSS_MS_MIGRATE and creates a normal wrapped key. The resulting normal wrapped key blob is stored in the instance associated with hKeyToMigrate and may be retrieved from that instance by \fBTspi_GetAttribData\fR. .SH "PARAMETERS" .PP .SS hKeyToMigrate The handle of the key object to convert. .SS hParentKey Handle to the parent key related to the key addressed by \fIhKeyToMigrate\fR. .SS ulRandomLength Length of random data provided at the parameter \fIrgbRandom\fR. .SS rgbRandom Random data as returned together with the migration blob by the method \fBTspi_Key_CreateMigrationBlob\fR. .SS ulMigrationBlobLength Length of the migration blob data provided at the parameter \fIrgbMigrationBlob\fR. .SS rgbMigrationBlob Migration blob data as returned by a previously called method \fBTspi_Key_CreateMigrationBlob\fR. .SH "RETURN CODES" .PP \fBTspi_Key_ConvertMigrationBlob\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhKeyToMigrate\fR or \fIhParentKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_Key_ConvertMigrationBlob\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_LoadKey\fR(3), \fBTspi_Key_UnloadKey\fR(3), \fBTspi_Key_CertifyKey\fR(3), \fBTspi_Key_CreateMigrationBlob\fR(3). trousers-0.3.15/man/man3/Tspi_EncodeDER_TssBlob.30000664000175000017510000000445113663651711020634 0ustar deboradebora.\" Copyright (C) 2007 International Business Machines Corporation .\" Written by Tom Lendacky based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_EncodeDER_TssBlob" 3 "2007-06-12" "TSS 1.2" "TCG Software Stack Developer's Reference" .SH NAME Tspi_EncodeDER_TssBlob \- generate a DER encoded TSS blob. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .sp .BI "TSS_RESULT Tspi_EncodeDER_TssBlob(UINT32 " rawBlobSize ", BYTE* " rawBlob "," .BI " UINT32 " blobType ", UINT32* " derBlobSize "," .BI " BYTE* " derBlob ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_EncodeDER_TssBlob\fR is used to generate a DER-encoded blob in accordance with the ASN.1 data definitions in the Portable Data section of the Trusted Computing Group Software Stack Specification Version 1.2. .SH "PARAMETERS" .PP .SS rawBlobSize Size of the unwrapped blob. .PP .SS rawBlob Pointer to the unwrapped blob. .PP .SS blobType Type of blob being wrapped (refer to the TSS_BLOB_TYPE_* constants). .PP .SS derBlobSize Pointer to the size of the derBlob buffer. On input this parameter contains a pointer to the maximum size of the supplied derBlob buffer. On output this parameter contains a pointer to the actual size of the DER-encoded blob. On input, if this parameter points to a value of 0, then this function will return the size of the buffer required to hold the DER-encoded blob without writing to the derBlob buffer. .sp \fBNote:\fR If the raw data blob length is less than 2^16 bytes then the DER-encoding may add no more than 20 bytes. .PP .SS derBlob Pointer to a buffer to hold the DER-encoded blob. .SH "RETURN CODES" .PP \fBTspi_EncodeDER_TssBlob\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_EncodeDER_TssBlob\fR conforms to the Trusted Computing Group Software Specification Version 1.2 .SH "SEE ALSO" .PP \fBTspi_DecodeBER_TssBlob\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_DAA_JoinInit.30000664000175000017510000000764013663651711020367 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_DAA_JoinInit" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_DAA_JoinInit \- start the DAA Join process .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSPICALL Tspi_TPM_DAA_JoinInit(" .BI " TSS_HDAA " hDAA "," .BI " TSS_HTPM " hTPM "," .BI " TSS_HKEY " issuer_pk "," .BI " UINT32 " issuer_authentication_PKLength "," .BI " TSS_HKEY* " issuer_authentication_PK "," .BI " UINT32 " issuer_authentication_PK_signaturesLength "," .BI " BYTE** " issuer_authentication_PK_signatures "," .BI " UINT32* " capital_UprimeLength "," .BI " BYTE** " capital_Uprime "," .BI " TSS_DAA_IDENTITY_PROOF* " identity_proof "," .BI " TSS_DAA_JOIN_SESSION* " join_session .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_TPM_DAA_JoinInit\fR is the first out of 3 functions to execute in order to receive a DAA Credential. It verifies the keys of the DAA Issuer and computes the TPM DAA public key. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS hTPM The \fIhTPM\fR parameter is the handle to the TPM object. .SS issuer_pk The \fIissuer_pk\fR parameter is the of the DAA Issuer public key. .SS issuer_authentication_PKLength The \fIissuer_authentication_PKLength\fR parameter is the length of the array of \fIissuerAuthPKs\fR. .SS issuer_authentication_PK The \fIissuer_authentication_PK\fR parameter is an array of RSA public keys (key chain) of the DAA Issuer used to authenticate the DAA Issuer public key. The size of the modulus must be TPM_DAA_SIZE_issuerModulus (256). .SS issuer_authentication_PK_signaturesLength The \fIissuer_authentication_PK_signaturesLength\fR parameter is the length of the array of issuerAuthPKSignatures. It is equal to issuerAuthPKsLength. The length of an element of the array is TPM_DAA_SIZE_issuerModulus (256). .SS issuer_authentication_PK_signatures The \fIissuer_authentication_PK_signatures\fR parameter is the array of byte arrays representing signatures on the modulus of the above key chain (issuerAuthPKs) in more details, the array has the following content (S(K[1],K[0]),S(K[2],N[1]),..S(K[ k ],K[n-1]), S(TPM_DAA_ISSUER,K[ k ])), where S(msg,privateKey) denotes the signature function with msg being signed by the privateKey. .SS capital_UprimeLength The \fIcapital_UprimeLength\fR parameter is the length of capitalUprime which is ln/8. ln is defined as the size of the RSA modulus (2048). .SS capital_Uprime The \fIcapital_Uprime\fR parameter is U'. .SS identityProof The \fIidentityProof\fR parameter is a structure containing the endorsement, platform and conformance credential. .SS joinSession The \fIjoinSession\fR parameter is a structure containing DAA Join session information. .SH "RETURN CODES" .PP \fBTspi_TPM_DAA_JoinInit\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the DAA or the TPM handler is not valid. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_DAA_ISSUER_KEY_ERROR .SH "CONFORMING TO" .PP \fBTspi_TPM_DAA_JoinInit\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_TPM_DAA_JoinCreateDaaPubKey\fR(3) \fBTspi_TPM_DAA_JoinStoreCredential\fR(3) trousers-0.3.15/man/man3/Tspi_DAA_IssuerKeyVerification.30000664000175000017510000000414713663651711022411 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_DAA_IssuerKeyVerification" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_DAA_IssuerKeyVerification \- verifies the DAA public key .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSPICALL Tspi_DAA_IssuerKeyVerification(" .BI " TSS_HDAA " hDAA "," .BI " TSS_HKEY " issuerPk "," .BI " TSS_DAA_PK_PROOF* " issuerPkProof "," .BI " TSS_BOOL* " isCorrect .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_DAA_IssuerKeyVerification\fR verifies the DAA public key of a DAA Issuer with respect to its associated proof. This is a resource consuming task. It can be done by trusted third party (certification). This is an optional function and does not require a TPM or a TCS. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS issuerPk The \fIissuerPk\fR parameter is a DAA Issuer public key. .SS issuerPkProof The \fIissuerPkProof\fR parameter is a structure representing the proofs of the correctness of the DAA Issuer public key. .SS isCorrect The \fIisCorrect\fR parameter is the return corectness of the proof. .SH "RETURN CODES" .PP \fBTspi_DAA_IssuerKeyVerification\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the DAA is not valid. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_DAA_IssuerKeyVerification\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_DAA_IssueSetup\fR(3) trousers-0.3.15/man/man3/Tspi_Data_Unbind.30000664000175000017510000000465513663651711017632 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Data_Unbind" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Data_Unbind \- Decrypts data that has been bound to a key .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Data_Unbind(TSS_HENCDATA " hEncData ", TSS_HKEY " hEncKey "," .BI " UINT32* " pulUnboundDataLength ", BYTE** " prgbUnboundData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Data_Unbind\fR decrypts the encrypted data blob exportedfrom the data object used in \fBTspi_Data_Bind\fR. The encrypted data blob must be imported to the object addressed by \fBTspi_SetAttribData\fR before calling this method. .SH "PARAMETERS" .PP .SS hEncData The handle of the data object which contains the encrypted data. .SS hEncKey Handle to the key object addressing the private key which is used to decrypt the data. .SS pulDataLength Receives the length of the data at the parameter \fIprgbUnboundData\fR. .SS prgbUnboundData Receives a pointer to a buffer containing the plaintext data. .SH "RETURN CODES" .PP \fBTspi_Data_Unbind\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhEncData\fR or \fIhEncKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_INVALID_ENCSCHEME Invalid encryption scheme. .TP .SM TSS_E_ENC_INVALID_LENGTH Invalid length of data to be encypted. .TP .SM TSS_E_ENC_NO_DATA No data to encrypt. .TP .SM TSS_E_ENC_INVALID_TYPE Invalid encryption type. .SH "CONFORMING TO" .PP \fBTspi_Data_Unbind\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Data_Bind\fR(3), \fBTspi_Data_Unseal\fR(3), \fBTspi_Data_Seal\fR(3). trousers-0.3.15/man/man3/Tspi_Context_UnregisterKey.30000664000175000017510000000745613663651711021770 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_UnregisterKey" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_UnregisterKey \- unregister a key from the persistent storage device. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_UnregisterKey(TSS_HCONTEXT " hContext ", TSS_FLAG " persistentStorageType "," .BI " TSS_UUID " uuidKey ", TSS_HKEY* " phKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_UnregisterKey\fR provides the capabilities of the TSS Core Service or TSS Service Provider .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS persistentStorageType Flag indicating the persistent storage. .PP .SS uuidKey The UUID of the key to be removed from the persistent storage. .PP .SS phKey Recieves the handle of a key object containing the information from the archive. .PP .SS pulRespDataLength Recieves the length (in bytes) of the prgbRespData parameter. .PP .SS prgbRespData On successful completion of the command, this parameter points to the buffer containing the actual data of the specified capability. The handle of the object to be destroyed .SH "RETURN CODES" .PP \fBTspi_Context_UnregisterKey\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - the parameter \fIhContext\fR is an invalid parameter. .TP .SM TSS_E_PS_KEY_NOTFOUND - the parameter \fIuuidKey\fR is an invalid UUID. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "EXAMPLE" .nf #include int main(void) { TSS_FLAGS initFlags = ...; TSS_HKEY hKey, hSRK; TSS_UUID keyUUID = {...}; // Create a TSP handle result = Tspi_Context_Create(&hContext); if (result != TSS_SUCCESS) Error_Path(); // Connect to the TCSD result = Tspi_Context_Connect(hContext, GLOBALSERVER); if (result != TSS_SUCCESS) Error_Path(); // Create the Key Object result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, initFlags, &hKey); if (result != TSS_SUCCESS) Error_Path(); // Load parent Key by UUID result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK); if (result != TSS_SUCCESS) Error_Path(); // Do policy/secret handling here result = Tspi_Key_CreateKey(hKey, hSRK, 0); if (result != TSS_SUCCESS) Error_Path(); // Register the Key in System PS (on the TCSD's platform) result = Tspi_Context_RegisterKey(hContext, hKey, TSS_PS_TYPE_SYSTEM, keyUUID, TSS_PS_TYPE_SYSTEM, SRK_UUID); if (result != TSS_SUCCESS) Error_Path(); /* ... * * Use the key as needed, exiting the program if necessary, reloading * the key using Tspi_Context_LoadKeyByUUID() after each restart. Once * the key is no longer useful, unregister it from system PS as part * of clean up. */ // Unregister the Key result = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_SYSTEM, migratableSignUUID, &hKey); if (result != TSS_SUCCESS) Error_Path(); // exit, discarding hKey } .fi .SH "CONFORMING TO" .PP \fBTspi_Context_UnregisterKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_CreateKey\fR(3), \fBTspi_Context_RegisterKey\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_CMKSetRestrictions.30000664000175000017510000000436213663651711021674 0ustar deboradebora.\" Copyright (C) 2007 International Business Machines Corporation .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_CMKSetRestrictions" 3 "2007-12-13" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_CMKSetRestrictions \- set restrictions on use of delegated Certified Migratable Keys .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .sp .BI "TSS_RESULT Tspi_TPM_CMKSetRestrictions(TSS_HTPM " hTPM ", TSS_CMK_DELEGATE " CmkDelegate ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_CMKSetRestrictions\fR is used to set restrictions on the delegated use of Certified Migratable Keys (CMKs). Use of this command cannot itself be delegated. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS CmkDelegate The \fICmkDelegate\fR parameter is a bitmask describing the kinds of CMKs that can be used in a delegated auth session. Each bit represents a type of key. If the bit of a key type is set, then the CMK can be used in a delegated authorization session, otherwise use of that key will result in a TPM_E_INVALID_KEYUSAGE return code from the TPM. The possible values of \fICmkDelegate\fR are any combination of the following flags logically OR'd together: .TP .SM "TSS_CMK_DELEGATE_SIGNING" Allow use of signing keys. .TP .SM "TSS_CMK_DELEGATE_STORAGE" Allow use of storage keys. .TP .SM "TSS_CMK_DELEGATE_BIND" Allow use of binding keys. .TP .SM "TSS_CMK_DELEGATE_LEGACY" Allow use of legacy keys. .TP .SM "TSS_CMK_DELEGATE_MIGRATE" Allow use of migratable keys. .SH "RETURN CODES" .PP \fBTspi_TPM_CMKSetRestrictions\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_TPM_CMKSetRestrictions\fR conforms to the Trusted Computing Group Software Specification version 1.2 Errata A .SH "SEE ALSO" .PP \fBTspi_TPM_CMKApproveMA\fR(3), \fBTspi_TPM_CMKCreateTicket\fR(3), \fBTspi_Key_CMKCreateBlob\fR(3) trousers-0.3.15/man/man3/Tspi_Context_GetRegisteredKeysByUUID2.30000664000175000017510000000621713663651711023617 0ustar deboradebora.\" Copyright (C) 2004,2007 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" Revised by Ramon Brandão based on Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_GetRegisteredKeysByUUID2" 3 "2007-07-06" "TSS 1.2" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_GetRegisteredKeysByUUID2 \- get an array of TSS_KM_KEYINFO2 structures based on the state of persistent storage. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_GetRegisteredKeysByUUID2(TSS_HCONTEXT " hContext ", TSS_FLAG " persistentStorageType "," .BI " TSS_UUID* " pUuidData ", UINT32* " pulKeyHierarchySize "," .BI " TSS_KM_KEYINFO2** " ppKeyHierarchy ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_GetRegisteredKeysByUUID2\fR gets an array of TSS_KM_KEYINFO2 structures. This information reflects the state of the registered key hierarchy. The keys stored in the persistent storage are totallly independent from either the context provided in the function call or the context, which was provided while processing the key registration. .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS persistentStorageType Flag indicating the persistent storage the key is registered in. .PP .SS pUuidData The UUID the key was registered in the persistent storage (TSP or connected TCS). If no key UUID is provided, thus KeyUUID is NULL, the returned array of the TSS_KM_KEYINFO2 structure contains data reflecting the whole key hierarchy starting with root key. If a certain key is UUID is provided, the returned array of TSS_KM_KEYINFO2 structures only contains data reflecting the path of the key hierarchy regarding that key. The first array entry is the key addressed by the given UUID followed by its parent key up to the root key. .PP .SS pulKeyHierarchySize Recieves the length (number of array entries) of the ppKeyHierarchy parameter. .PP .SS ppKeyHierarchy On successful completion of the command, this parameter points to a buffer containing the actual key hierarchy data. .SH "RETURN CODES" .PP \fBTspi_Context_GetRegisteredKeysByUUID2\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhContext\fR is an invalid handle. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_GetRegisteredKeysByUUID2\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_Context_LoadKeyByUUID\fR(3). trousers-0.3.15/man/man3/Tspi_Key_CreateKey.30000664000175000017510000000424513663651711020141 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_CreateKey" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Key_CreateKey \- create a key pair within the TPM, wrapping it with the key addressed by hWrappingKey. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_CreateKey(TSS_HKEY " hKey ", TSS_HKEY " hWrappingKey ", TSS_HPCRS " hPcrComposite ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Key_CreateKey\fR calls the TPM command TPM_CreateWrapKey. If hPcrComposite is not set to NULL, the created key blob is bound to this PCR values. The key object addressed by hKey must contain the key information needed for the creation. .SH "PARAMETERS" .PP .SS hKey The handle of the key object to create. .PP .SS hWrappingKey The handle to the key used to wrap the newly created key. .PP .SS hPcrComposite The handle to an object, if the value of the handle doesn't equal NULL, the newly create key will be bound ot the PCR values described with this object. .SH "RETURN CODES" .PP \fBTspi_Key_CreateKey\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhKey\fR, \fIhWrappingKey\fR or \fIhPcrComposite\fR are invalid parameters. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Key_CreateKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_WrapKey\fR(3), \fBTspi_Key_CertifyKey\fR(3), \fBTspi_Key_RegisterKey\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_ClearOwner.30000664000175000017510000000415613663651711020237 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_ClearOwner" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_ClearOwner \- clear TPM ownership .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_ClearOwner(TSS_HTPM " hTPM ", TSS_BOOL " fForcedClear ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_ClearOwner\fR wipes the TPM of everything but its endorsement key. It will wipe the SRK, so anything locked to the SRK will also disappear when this command is executed. This is the only way to be certain that keys are gone, as it is the only way to guarantee that nothing can keep a copy of the key. You must assert either physical presence or owner authorization in order to use this command. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS fForcedClear The \fIfForcedClear\fR parameter is used to tell whether this command is being executed with owner authorization or with physical presence. If FALSE, then TPM owner authorization is used. If TRUE, then physical presence is required to clear the TPM. .SH "RETURN CODES" .PP \fBTspi_TPM_ClearOwner\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_TPM_ClearOwner\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_TakeOwnership\fR(3) trousers-0.3.15/man/man3/Tspi_TPM_CertifySelfTest.30000664000175000017510000000415213663651711021251 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_CertifySelfTest" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_CertifySelfTest\- have the TPM sign its self test data .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_CertifySelfTest(TSS_HTPM " hTPM ", TSS_HKEY " hKey "," .BI " TSS_VALIDATION* " pValidationData " );" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_CertifySelfTest\fR performs a self-test of each internal TPM function and returns an authenticated value (signature) if the test has passed. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object .PP .SS hKey Handle of the signature key object .PP .SS pValidationData Validation data structure. [IN] Provide externalData information required to compute the signature. [OUT] On successful completion of the ocmmand, the structure provides a buffer containing the validation data and a buffer containing the data the validation data was computed from. .SH "RETURN CODES" .PP \fBTspi_TPM_CertifySelfTest\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE \fBhTPM\fR is not a valid handle to a TPM object. .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_CertifySelfTest\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_SelfTestFull\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_PcrRead.30000664000175000017510000000405413663651711017513 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_PcrRead" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_PcrRead \- read the value in a PCR register .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_PcrRead(TSS_HTPM " hTPM ", UINT32 " ulPcrIndex "," .BI " UINT32* " pulPcrValueLength ", BYTE** " prgbPcrValue ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_PcrRead\fR reads a PCR register to find the current values. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. The command to get the TPM to test itself will be sent here. .SS ulPcrIndex The \fIulPcrIndex\fR parameter is the index of the PCR to read. .SS pulPcrValueLength The \fIpulPcrValueLength\fR parameter receives the length in bytes of the \fIprgbPcrValue\fR parameter. .SS prgbPcrValue The \fIprgbPcrValue\fR parameter receives a pointer to the memory block containing the PCR data. .SH "RETURN CODES" .PP \fBTspi_TPM_PcrRead\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_PcrRead\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_PcrExtend\fR(3). trousers-0.3.15/man/man3/Tspi_Key_CreateMigrationBlob.30000664000175000017510000000624513663651711022143 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_CreateMigrationBlob" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Key_CreateMigrationBlob \- create a key blob suitable for migrating to another TPM. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_CreateMigrationBlob(TSS_HKEY " hKeyToMigrate ", TSS_HKEY " hParentKey "," .BI " UINT32 " ulMigTicketLength ", BYTE* " rgbMigTicket "," .BI " UINT32* " pulRandomLength ", BYTE** " prgbRandom "," .BI " UINT32* " pulMigrationBlobLength ", BYTE** " prgbMigrationBlob ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Key_CreateMigrationBlob\fR returns a key blob containing an encrypted section, which will be different depending on the migration scheme indicated within the migration ticket previously created by the method Tspi_TPM_AuthorizeMigrationTicket(). .SH "PARAMETERS" .PP .SS hKeyToMigrate Handle of the key object to migrate. .PP .SS hParentKey Handle to the parent key related to the key addressed by hKeyToMigrate. .PP .SS ulMigTicketLength The length (in bytes) of the rgbMigTickey parameter. .PP .SS rgbMigTicket Pointer to memory containing the migration ticket (migration public key and its authorization digest). .PP .SS pulRandomLength On successful completion this parameter returns the random data length returned at the parameter prgbRandom. .PP .SS prgbRandom On successful completion this parameter returns the random data. .PP .SS pulMigrationBlobLength On successful completion this parameter returns the length of the migration blob data returned at the parameter prgbMigrationBlob. .PP .SS prgbMigrationBlob On successful completion this parameter returns the migration data blob. .PP .SH "RETURN CODES" .PP \fBTspi_Key_CreateMigrationBlob\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhKeyToMigrate\fR, \fIhParentKey\fR or \fIrgbMigTicket\fR are invalid parameters. .TP .SM TSS_E_BAD_PARAMETER - One of the passed parameters is wrong. .TP .SM TSS_E_KEY_NO_MIGRATION_POLICY - No migration policy picked. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Key_CreateMigrationBlob\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_CreateKey\fR(3), \fBTspi_Key_CertifyKey\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_PcrExtend.30000664000175000017510000000541013663651711020064 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_PcrExtend" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_PcrExtend \- extend a PCR register and optionally write the PCR event log. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_PcrExtend(TSS_HTPM " hTPM ", UINT32 " ulPcrIndex "," .BI " UINT32 " ulPcrDataLength ", BYTE* " pbPcrData "," .BI " TSS_PCR_EVENT* " pPcrEvent "," .BI " UINT32* " pulPcrValueLength ", BYTE** " prgbPcrValue ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_PcrExtend\fR extends a PCR register and writes the PCR event log if one is supplied by the user. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. The command to get the TPM to test itself will be sent here. .SS ulPcrIndex The \fIulPcrIndex\fR parameter is the index of the PCR to extend. .SS ulPcrDataLength The \fIulPcrDataLength\fR parameter is the length in bytes of the \fIpbPcrData\fR parameter. .SS pbPcrData The \fIpbPcrData\fR parameter is a pointer to data which will be used in the extend operation. .SS pPcrEvent The \fIpPcrEvent\fR parameter is the TSS_PCR_EVENT structure to be passed to the TCS to record the extend event. If \fIpPcrEvent\fR is not NULL, the application should fill out the members of the structure that it cares about. .SS pulPcrValueLength The \fIpulPcrValueLength\fR parameter receives the length in bytes of the \fIprgbPcrValue\fR parameter. .SS prgbPcrValue The \fIprgbPcrValue\fR receives a pointer to the memory block containing the PCR data after the extend operation. .SH "RETURN CODES" .PP \fBTspi_TPM_PcrExtend\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_PcrExtend\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_PcrRead\fR(3). trousers-0.3.15/man/man3/Tspi_DecodeBER_TssBlob.30000664000175000017510000000450513663651711020620 0ustar deboradebora.\" Copyright (C) 2007 International Business Machines Corporation .\" Written by Tom Lendacky based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_DecodeBER_TssBlob" 3 "2007-06-12" "TSS 1.2" "TCG Software Stack Developer's Reference" .SH NAME Tspi_DecodeBER_TssBlob \- unwraps a BER-encoded TSS blob. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .sp .BI "TSS_RESULT Tspi_DecodeBER_TssBlob(UINT32 " berBlobSize ", BYTE* " berBlob "," .BI " UINT32* " blobType ", UINT32* " rawBlobSize "," .BI " BYTE* " rawBlob ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_DecodeBER_TssBlob\fR is used to unwrap a BER-encoded blob in accordance with the ASN.1 data definitions in the Portable Data section of the Trusted Computing Group Software Stack Specification Version 1.2. .SH "PARAMETERS" .PP .SS berBlobSize Size of the BER-encoded blob. .PP .SS berBlob Pointer to the BER-encoded blob. .PP .SS blobType Pointer to the type of blob being unwrapped (refer to the TSS_BLOB_TYPE_* constants). .PP .SS rawBlobSize Pointer to the size of the rawBlob buffer. On input this parameter contains a pointer to the maximum size of the supplied rawBlob buffer. On output this parameter contains a pointer to the actual size of the unwrapped blob. On input, if this parameter points to a value of 0, then this function will return the size of the buffer required to hold the unwrapped blob without writing to the rawBlob buffer. .sp \fBNote:\fR The output data must be shorter than the BER-encoding, so berBlobSize is a useful upper limit on rawBlob buffer size. .PP .SS rawBlob Pointer to a buffer to hold the unwrapped blob. .SH "RETURN CODES" .PP \fBTspi_EncodeDER_TssBlob\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_DecodeBER_TssBlob\fR conforms to the Trusted Computing Group Software Specification Version 1.2 .SH "SEE ALSO" .PP \fBTspi_DecodeBER_TssBlob\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_GetStatus.30000664000175000017510000000360713663651711020121 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetStatus" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_GetStatus \- query the TPM's status .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetStatus(TSS_HTPM " hTPM ", TSS_FLAG " statusFlag ", BOOL* " pfTpmState ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetStatus\fR queries the status of the TPM, returning a specific status based on the flags specified. \fBThis command is not currently implemented\fR. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS statusFlag The \fIstatusFlag\fR parameter is the status to be retrieved. .SS fTpmState The \fIpfTpmState\fR parameter is a pointer to the value of the status queried. .SH "RETURN CODES" .PP \fBTspi_TPM_GetStatus\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetStatus\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_SetStatus\fR(3), \fBTspi_TPM_GetCapability\fR(3). trousers-0.3.15/man/man3/Tspi_Context_Create.30000664000175000017510000000313713663651711020363 0ustar deboradebora.\" Copyright (C) 2005 International Business Machines Corporation .\" Written by Kent Yoder based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_Create" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_Create \- create a TSP context handle. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_Create(TSS_HCONTEXT* " phContext ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_Create\fR creates a handle to a new context object. The context is then used by other API functions to track resources related to it. .SH "PARAMETERS" .PP .SS phContext Receives the handle to the created context object. .SH "RETURN CODES" .PP \fBTspi_Context_Create\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INTERNAL_ERROR - An internal error occurred in the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_Create\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_Close\fR(3), \fBTspi_Context_Connect\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_TakeOwnership.30000664000175000017510000000426513663651711020762 0ustar deboradebora.\" Copyright (C) 2005 International Business Machines Corporation .\" Written by Kent Yoder based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_TakeOwnership" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_TakeOwnership \- take ownership of a TPM .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_TakeOwnership(TSS_HTPM " hTPM ", TSS_HKEY " hKeySRK "," .BI " TSS_HKEY " hEndorsementPubKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_TakeOwnership\fR takes ownership of a TPM. Taking ownership is the process of inserting a shared secret into the TPM. The owner of the TPM (anyone who knows the shared secret) has the right to perform special operations. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS hKeySRK The \fIhKeySRK\fR parameter is the handle to the object representing the TPM's Storage Root Key. .SS hEndorsementPubKey The \fIhEndorsementPubKey\fR parameter is the handle to the object representing the TPM's endorsement public key. This key is required for encrypting the secret of the SRK and the TPM owner secret. If NULL, the TSP internally queries the TPM for that endorsement public key. .SH "RETURN CODES" .PP \fBTspi_TPM_TakeOwnership\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the TPM or one of the key handles is not valid. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_TPM_TakeOwnership\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_ClearOwner\fR(3) .PP trousers-0.3.15/man/man3/Tspi_Context_RegisterKey.30000664000175000017510000001047513663651711021420 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_RegisterKey" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_Context_RegisterKey \- register a key in the TSS Persistent Storage database .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_RegisterKey(TSS_HCONTEXT " hContext ", TSS_HKEY " hKey "," .BI " TSS_FLAG " persistentStorageType ", TSS_UUID " uuidKey "," .BI " TSS_FLAG " persistentStorageTypeParent ", TSS_UUID " uuidParentKey "); " .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_RegisterKey\fR is the API that registers a key with the TSS Persistent Storage database so that it can be loaded as necessary. It also includes all information required for loading the key, as well as information about its parent key. .SH "PARAMETERS" .PP .SS hContext The \fIhContext\fR parameter is the handle of the context object. .SS hKey The \fIhKey\fR parameter is the handle of the key object addressing the key to be registered. .SS persistentStorageType The \fIpersistentStorageType\fR parameter indicates the persistent storage the key is registered in. .SS uuidKey The \fIuuidKey\fR parameter is the UUID by which the key is registered in persistent storage. .SS persistentStorageTypeParent The \fIpersistentStorageTypeParent\fR parameter indicates the persistent storage that the parent key is registered in. .SS uuidParentKey The \fIuuidParentKey\fR parameter is the UUID by which the parent key is registered in persistent storage. .SH "RETURN CODES" .PP \fBTspi_Context_RegisterKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhContext\fR is not a valid handle. .TP .SM TSS_E_PS_KEY_NOTFOUND The key cannot be found in the persistent storage database. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "EXAMPLE" .nf #include int main(void) { TSS_FLAGS initFlags = ...; TSS_HKEY hKey, hSRK; TSS_UUID keyUUID = {...}; // Create a TSP handle result = Tspi_Context_Create(&hContext); if (result != TSS_SUCCESS) Error_Path(); // Connect to the TCSD result = Tspi_Context_Connect(hContext, GLOBALSERVER); if (result != TSS_SUCCESS) Error_Path(); // Create the Key Object result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, initFlags, &hKey); if (result != TSS_SUCCESS) Error_Path(); // Load parent Key by UUID result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK); if (result != TSS_SUCCESS) Error_Path(); // Do policy/secret handling here result = Tspi_Key_CreateKey(hKey, hSRK, 0); if (result != TSS_SUCCESS) Error_Path(); // Register the Key in System PS (on the TCSD's platform) result = Tspi_Context_RegisterKey(hContext, hKey, TSS_PS_TYPE_SYSTEM, keyUUID, TSS_PS_TYPE_SYSTEM, SRK_UUID); if (result != TSS_SUCCESS) Error_Path(); /* ... * * Use the key as needed, exiting the program if necessary, reloading * the key using Tspi_Context_LoadKeyByUUID() after each restart. Once * the key is no longer useful, unregister it from system PS as part * of clean up. */ // Unregister the Key result = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_SYSTEM, migratableSignUUID, &hKey); if (result != TSS_SUCCESS) Error_Path(); // exit, discarding hKey } .fi .SH "CONFORMING TO" .PP \fBTspi_Context_RegisterKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_UnregisterKey\fR(3), \fBTspi_Context_LoadKeyByUUID\fR(3), \fBTspi_Context_GetRegisteredKeyByUUID\fR(3). trousers-0.3.15/man/man3/Tspi_Context_LoadKeyByBlob.30000664000175000017510000000511013663651711021573 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_LoadKeyByBlob" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_Context_LoadKeyByBlob \- load a key into the TPM using the key's blob. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_LoadKeyByBlob(TSS_HCONTEXT " hContext ", TSS_HKEY " hUnwrappingKey "," .BI " UINT32 " ulBlobLength ", BYTE* " rgbBlobData "," .BI " TSS_HKEY* " phKey "); " .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_LoadKeyByBlob\fR creates a key based on the information gotten by the key blob. It then loads the key into the TPM, which unwraps the key blob by using the key associated with \fIhUnwrappingKey\fR. The key blob addressed by \fihUnwrappingKey\fR must have been already loaded into the TPM. This function returns a handle to the created key object. .SH "PARAMETERS" .PP .SS hContext The \fIhContext\fR parameter is the handle of the context object. .SS hUnwrappingKey The \fIhUnwrappingKey\fR parameter is the handle of the key object which should be used to unwrap the key information associated with \fIrgbBlobData\fR. .SS rgbBlobData The \fIrgbBlobData\fR parameter is the wrapped key to load. .SS phKey The \fIphKey\fR parameter receives the handle of the key object representing the loaded key. .SH "RETURN CODES" .PP \fBTspi_Context_LoadKeyByBlob\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhContext\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_Context_LoadKeyByBlob\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_LoadKeyByUUID\fR(3), \fBTspi_Policy_SetSecret\fR(3), \fBTspi_GetPolicyObject\fR(3), \fBTspi_Key_CreateKey\fR(3), \fBTspi_GetAttribUint32\fR(3). trousers-0.3.15/man/man3/Tspi_Context_CloseObject.30000664000175000017510000000343713663651711021357 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_CloseObject" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_CloseObject \- destroy resources associated with an object handle. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI " TSS_RESULT Tspi_Context_CloseObject(TSS_HCONTEXT " hContext ", TSS_HOBJECT " hObject ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_CloseObject\fR destroys the object associated with the object handle. All allocated resources associated within the object are also released. .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS hObject The handle of the object to be destroyed. .SH "RETURN CODES" .PP \fBTspi_Context_CloseObject\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhContext\fR or \fIhObject\fR are invalid handles. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_CloseObject\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_CreateObject\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_StirRandom.30000664000175000017510000000410313663651711020250 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_StirRandom" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_StirRandom \- add entropy to the TPM random number generator .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_StirRandom(TSS_HTPM " hTPM ", UINT32 " ulEntropyDataLength ", BYTE* " rgbEntropyData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_StirRandom\fR adds entropy to the TPM random number generator for the purpose of generating better random numbers. The \fIentropy\fR variable should assigned an appropriately seeded random number before this function is called. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. The command to get the TPM to test itself will be sent here. .SS ulEntropyDataLength The \fIulEntropyDataLength\fR parameter is the length in bytes of the \fIrgbEntropyData\fR parameter. .SS rgbEntropyData The \fIrgbEntropyData\fR parameter is a pointer to the entropy data. .SH "RETURN CODES" .PP \fBTspi_TPM_StirRandom\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_StirRandom\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetRandom\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_GetPubEndorsementKey.30000664000175000017510000000566413663651711022246 0ustar deboradebora.\" Copyright (C) 2004, 2005 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetPubEndorsementKey" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_GetPubEndorsementKey \- create a TSS key object from the TPM's public endorsement key .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetPubEndorsementKey(TSS_HTPM " hTPM ", TSS_BOOL " fOwnerAuthorized "," .BI " TSS_VALIDATION* " pValidationData ", TSS_HKEY* " phEndorsementPubKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetPubEndorsementKey\fR This function retrieves the public endorsement key (PubEK) from the TPM and creates a TSS key object for it, whose handle is returned in \fIphEndorsementPubKey\fR. Due to the fact that different TPM chips validate the PubEK in different ways, application verification of the PubEK (using a non-NULL \fIpValidationData\fR is \fBbroken\fR. Tspi_TPM_GetPubEndorsementKey should be called with a NULL \fIpValidationData\fR parameter to allow the TSS to verify the PubEK itself. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS fOwnerAuthorized If TRUE, the TPM owner secret must be provided to get the public endorsement key. If FALSE, no TPM owner secret must be provided to get the public endorsement key. .SS pValidationData If non-NULL, the application should set the pValidationData->rgbExternalData parameter to 20 bytes of random data before calling Tspi_TPM_GetPubEndorsementKey. On successful completion of the command, the structure will provide buffers containing the validation data and the buffer the validation data was computed from. .SS phEndorsementPubKey Receives a handle to a key object representing the TPM's public endorsement key. .SH "RETURN CODES" .PP \fBTspi_TPM_GetPubEndorsementKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TPM_E_DISABLED_CMD Reading of PubEK from TPM has been disabled. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetPubEndorsementKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_GetPubKey\fR(3). trousers-0.3.15/man/man3/Tspi_Data_Bind.30000664000175000017510000000540213663651711017256 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Data_Bind" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Data_Bind \- Encrypts a data blob .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Data_Bind(TSS_HENCDATA " hEncData ", TSS_HKEY " hEncKey "," .BI " UINT32 " ulDataLength ", BYTE* " rgbDataToBind ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Data_Bind\fR encrypts a data blob in a manner that is decryptable by \fBTspi_Data_Unbind\fR. The data blob is encrypted using a public key operation with the key addressed by the given encryption key object. To bind data that is larger than the RSA public key modulus is the responsibility of the caller to perform the blocking and subsequent combination of data. The bound data blob is stored in the data object addressed by \fIhEncData\fR and can be exported from the object by \fBTspi_GetAttribData\fR. The caller of this function should perform validations that the public key presented to it is from a valid TPM. .SH "PARAMETERS" .PP .SS hEncData The handle of the data object which contains the encrypted data on successful completion of the command. .SS hEncKey Handle to the key object addressing the public key which is used to encrypt the data. .SS ulDataLength Indicates the length of the data provided at the parameter \fIrgbDataToBind\fR. .SS rgbDataToBind A pointer to the data to be encrypted. .SH "RETURN CODES" .PP \fBTspi_Data_Bind\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhHash\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_INVALID_ENCSCHEME Invalid encryption scheme. .TP .SM TSS_E_ENC_INVALID_LENGTH Invalid length of data to be encypted. .TP .SM TSS_E_ENC_NO_DATA No data to encrypt. .TP .SM TSS_E_ENC_INVALID_TYPE Invalid encryption type. .SH "CONFORMING TO" .PP \fBTspi_Data_Bind\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Data_Unbind\fR(3), \fBTspi_Data_Unseal\fR(3), \fBTspi_Data_Seal\fR(3). trousers-0.3.15/man/man3/Tspi_DAA_VerifySignature.30000664000175000017510000000654613663651711021256 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_DAA_VerifySignature" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_DAA_VerifySignature \- creates a challenge for the TCG platform .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSPICALL Tspi_DAA_VerifySignature(" .BI " TSS_HDAA " hDAA "," .BI " TSS_DAA_SIGNATURE " daaSignature "," .BI " TSS_HKEY " hPubKeyIssuer "," .BI " TSS_DAA_SIGN_DATA " signData "," .BI " UINT32 " attributesLength "," .BI " BYTE** " attributes "," .BI " UINT32 " nonceVerifierLength "," .BI " BYTE* " nonceVerifier "," .BI " UINT32 " baseNameLength "," .BI " BYTE* " baseName "," .BI " TSS_BOOL* " isCorrect .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_DAA_VerifySignature\fR is part of the DAA Verifier component. It's the last function out of 2 in order to verify a DAA Credential of a TCG platform. It verifies the DAA Credential and detects public rogue TPMs. This is an optional function and does not require a TPM or a TCS. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS daaSignature The \fIdaaSignature\fR parameter is the DAA signature contains proof of ownership of the DAA Credential, as well as a signature on either an AIK or a message. .SS hPubKeyIssuer The \fIhPubKeyIssuer\fR parameter is the handle of the DAA public key of the DAA Issuer of the credential. .SS signData The \fIsignData\fR parameter defines what data is signed (AIK or message). .SS attributesLength The \fIattributesLength\fR parameter is the Length of attributes array that is determined by the DAA Issuer public key (lh+li). The length of a single attribute is lf/8. .SS attributes The \fIattributes\fR parameter is the array of attributes which the DAA Credential owner reveals. .SS nonceVerifierLength The \fInonceVerifierLength\fR parameter is the length of nonceVerifier (20 bytes). .SS nonceVerifier The \fInonceVerifier\fR parameter is the nonce that was computed in the previous function (Tspi_VerifyInit). .SS baseNameLength The \fIbaseNameLength\fR parameter the length of the baseName. .SS baseName The \fIbaseName\fR parameter is the base name that was chosen for the DAA Signature. .SS isCorrect The \fIisCorrect\fR parameter denotes if the verification of the DAA Signature was successful. .SH "RETURN CODES" .PP \fBTspi_DAA_VerifySignature\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SH "CONFORMING TO" .PP \fBTspi_DAA_VerifySignature\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_DAA_IssuerKeyVerification\fR(3) trousers-0.3.15/man/man3/Tspi_Policy_AssignToObject.30000664000175000017510000000415313663651711021650 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Policy_AssignToObject" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_Policy_AssignToObject \- assign a policy to an object .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Policy_AssignToObject(TSS_HPOLICY " hPolicy ", TSS_HOBJECT " hObject ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Policy_AssignToObject\fR assigns a given object to a certain policy. The object then uses its assigned policy to process an authorized TPM command. When each new object is initialized, it is assigned to the default policy, which is created when a context object is created. When an object is assigned to a policy, a reference is added to the list of assigned objects stored in the policy, and a reference to the policy is stored in the object by internal object functions. .SH "PARAMETERS" .PP .SS hPolicy The \fIhPolicy\fR parameter is the handle of the policy object to be assigned to. .SS hObject The \fIhObject\fR parameter is the object that will be assigned to \fIhPolicy\fR. .SH "RETURN CODES" .PP \fBTspi_Policy_AssignToObject\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhPolicy\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_Policy_AssignToObject\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Policy_SetSecret\fR(3), \fBTspi_Policy_FlushSecret\fR(3). trousers-0.3.15/man/man3/Tspi_Data_Seal.30000664000175000017510000000504013663651711017264 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Data_Seal" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Data_Seal \- encrypt a data blob in a mannar that is only decryptable by Tspi_Data_Unseal on the same system. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Data_Seal(TSS_HENCDATA " hEncData ", TSS_HKEY " hEncKey "," .BI " UINT32 " ulDataLength ", BYTE* " rgbDataToSeal "," .BI " TSS_HPCRS " hPcrComposite ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Data_Seal\fR encrypts a data blob in a mannar that is only decryptable by Tspi_Data_Unseal on the same system. The data blob is encrypted using a public key operation with the nonmigratable key addressed by the given encryption key object. .SH "PARAMETERS" .PP .SS hEncData Handle of the data object which contains the sealed data on successful completion of the command. .PP .SS hEncKey Handle to the key object addressing the nonmigratable key which is used to encrypt the data. .PP .SS ulDataLength The Length (in bytes) of the rgbDataToSeal parameter. .PP .SS rgbDataToSeal Pointer to memory containing the data to be encrypted. .PP .SS hPcrComposite Handle of the PCR Composite object specifying the PCRs which are part of the sealed data blob. Set to NULL, if the encrypted data should only be bound to the system and PCRs are not of interest. .SH "RETURN CODES" .PP \fBTspi_Data_Seal\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - One of the following parameters \fIhEncData\fR, \fIhEncKey\fR, \fIrgbDataToSeal\fR is invalid. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Data_Seal\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Data_Unseal\fR(3). trousers-0.3.15/man/man3/Tspi_Key_UnloadKey.30000664000175000017510000000324513663651711020157 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_UnloadKey" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Key_UnloadKey \- unload a key from the TPM .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_UnloadKey(TSS_HKEY " hKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Key_UnloadKey\fR unloads the key referenced by the given key object from the TPM. This call will result in a TPM_EvictKey operation for the specified key. .SH "PARAMETERS" .PP .SS hKey The \fIhKey\fR parameter is the handle of the key object to unload. .SH "RETURN CODES" .PP \fBTspi_Key_UnloadKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_Key_UnloadKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_LoadKey\fR(3), \fBTspi_Key_GetPubKey\fR(3). trousers-0.3.15/man/man3/Tspi_Policy_FlushSecret.30000664000175000017510000000313213663651711021215 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Policy_FlushSecret" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_Policy_FlushSecret \- flush a cached secret .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Policy_FlushSecret(TSS_HPOLICY " hPolicy ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Policy_FlushSecret\fR tells the TSS to flush a secret that it had cached for a user. .SH "PARAMETERS" .PP .SS hPolicy The \fIhPolicy\fR parameter is the handle of the policy object to be flushed. .SH "RETURN CODES" .PP \fBTspi_Policy_FlushSecret\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhPolicy\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_Policy_FlushSecret\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Policy_SetSecret\fR(3), \fBTspi_Policy_AssignToObject\fR(3). trousers-0.3.15/man/man3/Tspi_Hash_UpdateHashValue.30000664000175000017510000000444013663651711021440 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Hash_UpdateHashValue" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Hash_UpdateHashValue \- update the hash value of a hash object .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Hash_UpdateHashValue(TSS_HHASH " hHash ", UINT32 " ulDataLength ", BYTE* " rgbData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Hash_UpdateHashValue\fR updates the hash value of a hash object with new information. If the object was created with the flag TSS_HASH_OTHER, then this method will return an error. \fBThe object can't be modified after Tspi_Hash_SetHashValue, Tspi_Hash_GetHashValue, Tspi_Hash_Sign, or Tspi_Hash_VerifySignature have been called on it.\fR .SH "PARAMETERS" .PP .SS hHash The handle to the hash object instance whose hash value should be signed. .SS ulDataLength Indicates the length of the data provided at the parameter \fIrgbData\fR. .SS rgbData A pointer to the data. .SH "RETURN CODES" .PP \fBTspi_Hash_UpdateHashValue\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhHash\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_HASH_INVALID_LENGTH Hash length is inconsistent with hash algorithm. .TP .SM TSS_E_HASH_NO_DATA Hash object has no internal hash value. .SH "CONFORMING TO" .PP \fBTspi_Hash_UpdateHashValue\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Hash_GetHashValue\fR(3), \fBTspi_Hash_Sign\fR(3), \fBTspi_Hash_SetHashValue\fR(3), \fBTspi_Hash_VerifySignature\fR(3). trousers-0.3.15/man/man3/Tspi_GetAttribUint32.30000664000175000017510000000465413663651711020353 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_GetAttribUint32" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_GetAttribUint32 \- get the value of particular attribute associated with a given class or object .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_GetAttribUint32(TSS_HOBJECT " hObject ", TSS_FLAG " attribFlag "," .BI " TSS_FLAG " subFlag ", UINT32* " pulAttrib "); " .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_GetAttribUint32\fR returns a specified uint32 attribute associated with a given class or object. In order to use this command, you must first create an object and then find the attributes you wish to set. .SH "PARAMETERS" .PP .SS hObject The \fIhObject\fR parameter is the handle of the object to retrieve the attribute from. .SS attribFlag The \fIattribFlag\fR parameter indicates the specific attribute to query. .SS subFlag The \fIsubFlag\fR parameter also indicates the specific attribute to query. .SS pulAttrib The \fIpulAttrib\fR parameter is a pointer to the location where the attribute value is returned. .SH "RETURN CODES" .PP \fBTspi_GetAttribUint32\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhObject\fR is not a valid handle. .TP .SM TSS_E_INVALID_ATTRIB_FLAG \fIattribFlag\fR is incorrect. .TP .SM TSS_E_INVALID_ATTRIB_SUBFLAG \fIsubFlag\fR is incorrect. .TP .SM TSS_E_INVALID_ATTRIB_DATA \fIpulAttrib\fR is incorrect. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_GetAttribUint32\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_GetAttribData\fR(3), \fBTspi_SetAttribUint32\fR(3), \fBTspi_SetAttribData\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_GetRandom.30000664000175000017510000000401313663651711020046 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetRandom" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_GetRandom \- generate a random number on the TPM .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetRandom(TSS_HTPM " hTPM ", UINT32 " size ", BYTE** " random ");" .fi .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetRandom\fR gets a good random number for the purpose of generating symmetric keys, nonces, or seeding a random number generator. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. The command to get the TPM to test itself will be sent here. .SS size The \fIsize\fR parameter is the number of random bytes requested. .SS random The \fIrandom\fR parameter is a pointer to memory containing the random data. This is where the generated number goes. Because this internally allocates memory, Tspi_Context_FreeMemory should also be used. .SH "RETURN CODES" .PP \fBTspi_TPM_GetRandom\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetRandom\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_FreeMemory\fR(3). trousers-0.3.15/man/man3/Tspi_DAA_IssueInit.30000664000175000017510000000720513663651711020035 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_DAA_IssueInit" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_DAA_IssueInit \- initialize the Issuer for a join operation .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSPICALL Tspi_DAA_IssueInit(" .BI " TSS_HDAA " hDAA "," .BI " TSS_HKEY " issuerAuthPK "," .BI " TSS_HKEY " issuerKeyPair "," .BI " TSS_DAA_IDENTITY_PROOF " identityProof "," .BI " UINT32 " capitalUprimeLength "," .BI " BYTE* " capitalUprime "," .BI " UINT32 " daaCounter "," .BI " UINT32* " nonceIssuerLength "," .BI " BYTE** " nonceIssuer "," .BI " UINT32* " authenticationChallengeLength "," .BI " BYTE** " authenticationChallenge "," .BI " TSS_DAA_JOIN_ISSUER_SESSION* " joinSession .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_DAA_IssueInit\fR is a function that is part of the DAA Issuer component. It's the first function out of 2 in order to issue a DAA Credential for a TCG Platform. It assumes that the endorsement key and its associated credentials are from a genuine and valid TPM. (Verification of the credentials is a process defined by the TCG Infrastructure WG.) .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS issuerAuthPK The \fIissuerAuthPKh\fR parameter is the root authentication (public) key of DAA Issuer. .SS issuerKeyPair The \fIissuerKeyPair\fR parameter is the handle of the main DAA Issuer key pair (private and public portion). .SS identityProof The \fIidentityProof\fR parameter is the structure containing endorsement, platform and conformance credential of the TPM requesting the DAA Credential. .SS capitalUprimeLength The \fIcapitalUprimeLength\fR parameter is the length of capitalUprime which is . .SS capitalUprime The \fIcapitalUprime\fR parameter is U'. .SS daaCounter The \fIdaaCounter\fR parameter is the DAA counter. .SS nonceIssuerLength The \fInonceIssuerLength\fR parameter is the length of nonceIssuer (20 bytes). .SS nonceIssuer The \fInonceIssuer\fR parameter is the nonce of the DAA Issuer. .SS authenticationChallengeLength The \fIauthenticationChallengeLength\fR parameter is the length of authenticationChallenge (256 bytes - DAA_SIZE_NE1). .SS authenticationChallenge The \fIauthenticationChallenge\fR parameter is the second nonce of the DAA Issuer that is encrypted by the endorsement public key. It is used as a challenge to authenticate the TPM. .SS joinSession The \fIjoinSession\fR parameter is the structure containing the DAA Join session information. .SH "RETURN CODES" .PP \fBTspi_DAA_IssueInit\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the DAA is not valid. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_DAA_IssueInit\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_DAA_IssuerKeyVerification\fR(3) trousers-0.3.15/man/man3/Tspi_TPM_GetAuditDigest.30000664000175000017510000000665513663651711021052 0ustar deboradebora.\" Copyright (C) 2007 International Business Machines Corporation .\" Written by Tom Lendacky based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetAuditDigest" 3 "2007-06-27" "TSS 1.2" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_GetAuditDigest \- retrieve the audit digest. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetAuditDigest(TSS_HTPM " hTpm ", TSS_HKEY " hKey "," .BI " TSS_BOOL " closeAudit ", UINT32* " pulAuditDigestSize "," .BI " BYTE** " prgbAuditDigest ", TPM_COUNTER_VALUE* " pCounterValue "," .BI " TSS_VALIDATION* " pValidationData ", UINT32* " ordSize "," .BI " UINT32** " ordList ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetAuditDigest\fR is used to retrieve the audit digest. The audit digest may be signed or unsigned. If the audit digest is signed (hKey is non-NULL) then the current audit digest, the current audit counter and, optionally, the hash of the audited ordinal list and a signature are returned. If the audit digest is not signed (hKey is NULL) then the current audit digest, the current audit counter and the full list of audited ordinals is returned. .SH "PARAMETERS" .PP .SS hTpm Handle of the TPM object. .PP .SS hKey Handle of the signature key object (the handle can be NULL). .PP .SS closeAudit A flag indicating whether or not to close the current audit digest after it is signed. This parameter is ignored if \fIhKey\fR is NULL. .PP .SS pulAuditDigestSize Pointer to the size of the returned audit digest. .PP .SS prgbAuditDigest Pointer to a buffer that holds the returned audit digest. .PP .SS pCounterValue Pointer to a TPM_COUNTER_VALUE structure that holds the returned audit counter. .PP .SS pValidationData Pointer to a validation data structure. The validation data structure provides external information required to compute the signature. On input, the fields representing the ExternalData must contain an anti-replay nonce that will be used in the signing operation. On output, this structure provides a buffer containing the data used to compute the validation data and a buffer containing the validation data (a signature generated by signing the data using the key referenced by \fIhKey\fR). If this parameter is NULL then the TSS will perform the validation. This parameter is ignored if \fIhKey\fR is NULL. .PP .SS ordSize Pointer to the number of ordinals in the returned audited ordinal list. This parameter is ignored if \fIhKey\fR is non-NULL. .PP .SS ordList Pointer to a buffer that holds the returned audited ordinal list. This parameter is ignored if \fIhKey\fR is non-NULL. .SH "RETURN CODES" .PP \fBTspi_TPM_GetAuditDigest\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetAuditDigest\fR conforms to the Trusted Computing Group Software Specification Version 1.2 trousers-0.3.15/man/man3/Tspi_TPM_Quote2.30000664000175000017510000000554213663651711017355 0ustar deboradebora.\" Copyright (C) 2007 International Business Machines Corporation .\" Written by Ramon Brandão based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_Quote2" 3 "2007-04-03" "TSS 1.2" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_Quote2 \- retreive a signed set of PCR values with a more complete view than Tspi_TPM_Quote. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_Quote2(TSS_HTPM " hTPM ", TSS_HKEY " hIdentKey "," .BI " TSS_BOOL " fAddVersion ", TSS_HPCRS " hPcrComposite "," .BI " TSS_VALIDATION* " pValidationData ", UINT32* " versionInfoSize "," .BI " BYTE** " versionInfo ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_Quote2\fR quotes a TCG system, providing the requestor with a more complete view of the current platform configuration, than \fBTspi_TPM_Quote\fR. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object. .PP .SS hIdentKey Handle of the signature key object. .PP .SS fAddVersion If TRUE, the TPM version is added to the output. If FALSE, the TPM version isn't added to the output. .PP .SS hPcrComposite Handle of the PCR composite object, which contains the PCRs to be quoted. .PP .SS pValidationData Validation data structure [IN] Provide externalData information required to compute the signature. [OUT] On successful completion of the command, the structure provides a buffer containing the validation data and a buffer containing the data the validation data was computed form. .PP .SS versionInfoSize The size of the bytestream returned by versionInfo. If the \fIfAddVersion\fR is False this is zero. .PP .SS versionInfo The version information returned as a byte stream reflecting the data in TSS_CAP_VERSION_INFO if the fAddVersion is TRUE. Else it's NULL. .PP .SH "RETURN CODES" .PP \fBTspi_TPM_Quote\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhTPM\fR, \fIhIdentKey\fR or \fIhPcrComposite\fR is not a valid handle. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_Quote2\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_TPM_Quote\fR(3). trousers-0.3.15/man/man3/Tspi_DAA_IssueSetup.30000664000175000017510000000615113663651711020231 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_DAA_IssueSetup" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_DAA_IssueSetup \- generate a DAA Issuer public and private key .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSPICALL Tspi_DAA_IssueSetup(" .BI " TSS_HDAA " hDAA "," .BI " UINT32 " issuerBaseNameLength "," .BI " BYTE* " issuerBaseName "," .BI " UINT32 " numberPlatformAttributes "," .BI " UINT32 " numberIssuerAttributes "," .BI " TSS_HKEY* " keyPair "," .BI " TSS_DAA_PK_PROOF** " identity_proof .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_DAA_IssueSetup\fR is part of the DAA Issuer component. It defines the generation of a DAA Issuer public and secret key. Further it defines the generation of a non-interactive proof (using the Fiat-Shamir heuristic) that the public keys were chosen correctly. The latter will guarantee the security requirements of the platform (respectively, its user), i.e., that the privacy and anonymity of signatures will hold. The generation of the authentication keys of the DAA Issuer, which are used to authenticate (main) DAA Issuer keys, is not defined by this function. This is an optional function and does not require a TPM or a TCS. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS issuerBaseNameLength The \fIissuerBaseNameLength\fR parameter is the length of the issuerBaseName. .SS issuerBaseName The \fIissuerBaseName\fR parameter is the unique name of the DAA Issuer. .SS numberPlatformAttributes The \fInumberPlatformAttributes\fR parameter is the number of attributes that the Platform can choose and which will not be visible to the Issuer. .SS numberIssuerAttributes The \fInumberIssuerAttributes\fR parameter is number of attributes that the Issuer can choose and which will be visible to both the Platform and the Issuer. .SS keyPair The \fIkeyPair\fR parameter is the handle of the main DAA Issuer key pair (private and public portion). .SS publicKeyProof The \fIpublicKeyProof\fR parameter is the Handle of the proof of the main DAA Issuer public key. .SH "RETURN CODES" .PP \fBTspi_DAA_IssueSetup\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the DAA is not valid. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_DAA_IssueSetup\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_DAA_IssuerKeyVerification\fR(3) trousers-0.3.15/man/man3/Tspi_Context_FreeMemory.30000664000175000017510000000355513663651711021236 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_FreeMemory" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_Context_FreeMemory \- Free allocated memory for a given context. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .br .HP .BI "TSS_RESULT Tspi_Context_FreeMemory(TSS_HCONTEXT " hContext ", BYTE* " rgbMemory ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_FreeMemory\fR frees memory allocated by the TSS Service Provider on a per-context basis. This should be used before Tspi_Context_Close is called, to avoid memory leaks. .SH "PARAMETERS" .PP .SS hContext The \fIhContext\fR parameter is the handle to the local context. .SS rgbMemory The \fIrgbMemory\fR parameter is a pointer to the memory block to be freed. If this is NULL, all memory blocks bound to the context are freed. .SH "RETURN CODES" .PP \fBTspi_Context_FreeMemory\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhContext\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_Context_FreeMemory\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_Create\fR(3), \fBTspi_Context_Close\fR(3). trousers-0.3.15/man/man3/Tspi_Hash_SetHashValue.30000664000175000017510000000430213663651711020746 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Hash_SetHashValue" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Hash_SetHashValue \- Sets the hash value of a hash object for non-SHA1 hash objects. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Hash_SetHashValue(TSS_HHASH " hHash ", UINT32 " ulHashValueLength ", BYTE* " rgbHashValue ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Hash_SetHashValue\fR sets the hash value of a hash object. If the object was created with the flag TSS_HASH_OTHER, then the hash identifier has to be set by calling \fBTspi_SetAttribData\fR to perform the sign operation. .SH "PARAMETERS" .PP .SS hHash The handle to the hash object instance whose hash value should be signed. .SS ulHashValueLength Indicates the length of the hash value data provided at the parameter \fIrgbHashValue\fR. .SS rgbHashValue A pointer to the hash value data. .SH "RETURN CODES" .PP \fBTspi_Hash_SetHashValue\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhHash\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_HASH_INVALID_LENGTH Hash length is inconsistent with hash algorithm. .TP .SM TSS_E_HASH_NO_DATA Hash object has no internal hash value. .SH "CONFORMING TO" .PP \fBTspi_Hash_SetHashValue\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Hash_UpdateHashValue\fR(3), \fBTspi_Hash_Sign\fR(3), \fBTspi_Hash_GetHashValue\fR(3). trousers-0.3.15/man/man3/Tspi_Context_Connect.30000664000175000017510000000357213663651711020554 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_Connect" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME. Tspi_Context_Connect\- connect a TSP to a Core Services daemon .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_Connect(TSS_HCONTEXT " hLocalContext ", UNICODE* " wszDestination ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_Connect\fR creates a connetion between the application and the local or remote TSS System. .SH "PARAMETERS" .PP .SS hLocalContext The handle to the context to be connected. .PP .SS wszDestination A null terminated unicode string which specifies the local or remote system to which one will be connected. If \fIwszDestination\fR is NULL, the connection will be to a local TCS. .SH "RETURN CODES" .PP \fBTspi_Context_Connect\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhLocalContext\fR is an invalid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_Connect\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_Create\fR(3), \fBTspi_Context_Close\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_SelfTestFull.30000664000175000017510000000360213663651711020545 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_SelfTestFull" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_SelfTestFull \- perform a self-test of each internal TPM function .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_SelfTestFull(TSS_HTPM " hTPM ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_SelfTestFull\fR assures that the TPM is functioning as designed. For FIPS certification, crypto modules are required to test themselves before they are used, and this command is used to fulfill that requirement. This command can also be used to check the TPM whenever such a check is desired. \fBThis command is not currently implemented\fR. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object on which the self-tests will be run. .SH "RETURN CODES" .PP \fBTspi_TPM_GetStatus\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_TPM_SelfTestFull\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_CertifySelfTest\fR(3), \fBTspi_TPM_GetTestResults\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_GetEvents.30000664000175000017510000000432513663651711020100 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetEvents" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_GetEvents\- get a specific number of PCR events for a given index. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetEvents(TSS_HTPM " hTPM ", UINT32 " ulPcrIndex ", " .BI " UINT32 " ulStartNumber ", UINT32* " pulEventNumber ", " .BI " TSS_PCR_EVENT* " prgbPcrEvents ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetEvents\fR provides a specific number of PCR events for a given index. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object. .PP .SS ulPcrIndex Index of the PCR to request. .PP .SS ulStartNumber Indext of the first event to request .PP .SS pulEventNumber [IN] Number of elements to request. [OUT] Receives number of returned event data structures in prgbPcrEvents parameter. .PP .SS prgbPcrEvents Receives a pointer to an array of PCR event data. If NULL, only the number of elements is returned in pulEventNumber parameter. .SH "RETURN CODES" .PP \fBTspi_TPM_GetEvents\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE \fBhTPM\fR is not a valid handle to the TPM object. .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetEvents\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetEvent\fR(3) \fBTspi_TPM_GetEventLog\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_AuthorizeMigrationTicket.30000664000175000017510000000511513663651711023162 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_AuthorizeMigrationTicket" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_AuthorizeMigrationTicket\- create the migration ticket required for the migration process. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_AuthorizeMigrationTicket(TSS_HTPM " hTPM ", TSS_HKEY " hMigrationKey "," .BI " TSS_MIGRATE_SCHEME " migrationScheme ", UINT32* " pulMigTicketLength "," .BI " BYTE** " prgbMigTicket ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_AuthorizeMigrationTicket\fR is used by the owner to authorize a target public key for migration. This mean sthat when a system is set up, the owner can decide that all archives should be done on a particular server. Then as keys are created, the user can pick one of these servers for the target of the migration of their keys, if they wish. This provides one of the two authorizations necessary to migrate a key. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object .PP .SS hMigrationKey Handle of the object representing the migration key. .PP .SS migrationScheme Flag indiating the migration scheme to be used. .PP .SS pulMigTicketLength Recieves the length (in bytes) of the prgbMigTicket parameter. .PP .SS prgbMigTicket Recieves a pointer to thememory block containing the migration ticket blob. .SH "RETURN CODES" .PP \fBTspi_TPM_AuthorizeMigrationTicket\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE Either \fBhTPM\fR or \fBhMigrationKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_AuthorizeMigrationTicket\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fB(none)\fR. trousers-0.3.15/man/man3/Tspi_TPM_DirRead.30000664000175000017510000000423613663651711017507 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Kent Yoder based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_DirRead" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_DirRead \- Read a Data Integrity Register .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_DirRead(TSS_HTPM " hTPM ", UINT32 " ulDirIndex "," .BI " UINT32* " pulDirDataLength ", BYTE** " prgbDirData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_DirRead\fR reads a data integrity register. DIRs are non-volatile (persistent across reboots) memory areas maintained by the TPM. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS ulDirIndex The \fIulDirIndex\fR parameter is the index of the DIR to read. To query the TPM for the number of DIR registers it supports, use \fBTspi_TPM_GetCapability\fR(3). .SS pulDirDataLength The \fIpulDirDataLength\fR parameter receives the length in bytes of the \fIprgbDirData\fR parameter. .SS prgbDirData The \fIprgbDirData\fR parameter receives a pointer to memory containing the DIR data. .SH "RETURN CODES" .PP \fBTspi_TPM_DirRead\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_DirRead\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetCapability\fR(3), \fBTspi_TPM_DirWrite\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_DAA_JoinCreateDaaPubKey.30000664000175000017510000000753113663651711022414 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_DAA_JoinCreateDaaPubKey" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_DAA_JoinCreateDaaPubKey \- computes the credential request for the DAA Issuer .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_DAA_JoinCreateDaaPubKey(" .BI " TSS_HDAA " hDAA "," .BI " TSS_HTPM " hTPM "," .BI " UINT32 " authenticationChallengeLength "," .BI " BYTE* " authenticationChallenge "," .BI " UINT32 " nonceIssuerLength "," .BI " BYTE* " nonceIssuer "," .BI " UINT32 " attributesPlatformLength "," .BI " BYTE** " attributesPlatform "," .BI " TSS_DAA_JOIN_SESSION* " joinSession "," .BI " TSS_DAA_CREDENTIAL_REQUEST* " credentialRequest .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_TPM_DAA_JoinCreateDaaPubKey\fR is the second (between \fBTspi_TPM_DAA_JoinInit()\fR and \fBTspi_TPM_DAA_JoinStoreCredential()\fR) out of 3 functions to execute in order to receive a DAA Credential. It computes the credential request for the DAA Issuer, which also includes the Platforms's DAA public key and the attributes that were chosen by the Platform, and which are not visible to the DAA Issuer. The Platform can commit to the attribute values it has chosen. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS hTPM The \fIhTPM\fR parameter is the handle to the TPM object. .SS authenticationChallengeLength The \fIauthenticationChallengeLength\fR parameter is length of authenticationChallenge (256 bytes - DAA_SIZE_NE1). .SS authenticationChallenge The \fIauthenticationChallenge\fR parameter is the second nonce of the DAA Issuer that is encrypted by the endorsement public key. It is used as a challenge to authenticate the underlying TPM. .SS nonceIssuerLength The \fInonceIssuerLength\fR parameter is the length of nonceIssuer (20 bytes). .SS nonceIssuer The \fInonceIssuer\fR parameter is the nonce of the DAA Issuer. .SS attributesPlatformLength The \fIattributesPlatformLength\fR parameter is length of attributesPlatform array, which is determined by the DAA Issuer public key (). The length of a single attribute is ln/8. ln is defined as the size of the RSA modulus (2048). .SS attributesPlatform The \fIattributesPlatform\fR parameter is an array of attributes to be encoded into the DAA Credential not visible to the DAA Issuer. .SS joinSession The \fIjoinSession\fR parameter is a structure containing the DAA Join session information. .SS credentialRequest The \fIcredentialRequest\fR parameter is the credential request of the Platform, it contains the blinded DAA public key of the platform on which the DAA Issuer will issue the credential the blinded attributes chosen by the Platform. .SH "RETURN CODES" .PP \fBTspi_TPM_DAA_JoinCreateDaaPubKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the DAA is not valid. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_TPM_DAA_JoinCreateDaaPubKey\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_TPM_DAA_JoinInit\fR(3) \fBTspi_TPM_DAA_JoinStoreCredential\fR(3) trousers-0.3.15/man/man3/Tspi_TPM_CreateEndorsementKey.30000664000175000017510000000473513663651711022261 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_CreateEndorsementKey" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_CreateEndorsementKey \- create the endorsement key .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_CreateEndorsementKey(TSS_HTPM " hTPM ", TSS_HKEY " hKey "," .BI " TSS_VALIDATION* " pValidationData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_CreateEndorsementKey\fR creates an endorsement key. \fBThis function is currently not implemented\fR. Before this method is called, the key information for creating the key must be set in the key object by \fITspi_SetAttribData\fR. On return, the public endorsement key can be retrieved by \fITspi_GetAttribData\fR from the key object. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS hKey The \fIhKey\fR parameter is the handle of the key specifying the attributes of the endorsement key to create. .SS pValidationData The \fIpValidationData\fR parameter is a validation data structure. It provides external information required to compute the signature. Once the command is completed, the structure provides a buffer containing the validation data and a buffer containing the data the validation data was computed from. .SH "RETURN CODES" .PP \fBTspi_TPM_CreateEndorsementKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR or \fIhKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_CreateEndorsementKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetPubEndorsementKey\fR(3), \fBTspi_Key_GetPubKey\fR(3). trousers-0.3.15/man/man3/Tspi_ChangeAuth.30000664000175000017510000000402613663651711017461 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Change_Auth" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_ChangeAuth \- change the authorization data of an entity. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_ChangeAuth(TSS_HOBJECT " hObjectToChange ", TSS_HOBJECT " hParentObject "," .BI " TSS_HPOLICY " hNewPolicy " );" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_ChangeAuth \fR changes the authorization data (secret) of an entity (object) and assigns the object to the policy object. All classes using secrets provide this method for changing their authorization data. .SH "PARAMETERS" .PP .SS hObjectToChange Handle of the object to change authorization for. .PP .SS hParentObject Handle of the parent object wrapping the object addressed by hObjectToChange. .PP .SS hNewPolicy Handle of the policy object providing the new authorization data. .SH "RETURN CODES" .PP \fBTspi_ChangeAuth\fR returns TSS_SUCCESS on success,otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhObjectToChange\fR, or \fIhParentObject\fR are not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_ChangeAuth\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_ChangeAuthAsym\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_DirWrite.30000664000175000017510000000427413663651711017730 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_DirWrite" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_DirWrite \- write to a Data Integrity Register .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_DirWrite(TSS_HTPM " hTPM ", UINT32 " ulDirIndex "," .BI " UINT32 " ulDirDataLength ", BYTE* " rgbDirData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_DirWrite\fR writes a data integrity register. You need to know the DIR index and data you wish to write to the DIR prior to using this command. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS ulDirIndex The \fIulDirIndex\fR parameter is the index of the DIR to write. To query the TPM for the number of DIR registers it supports, use \fBTspi_TPM_GetCapability\fR(3). .SS ulDirDataLength The \fIulDirDataLength\fR parameter is the length in bytes of the \fIrgbDirData\fR parameter. .SS rgbDirData The \fIrgbDirData\fR parameter is a pointer to memory containing the data to be written to the DIR. .SH "RETURN CODES" .PP \fBTspi_TPM_DirWrite\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_DirWrite\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetCapability\fR(3), \fBTspi_TPM_DirRead\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_SetStatus.30000664000175000017510000000406113663651711020130 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_SetStatus" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_SetStatus \- modify the TPM's status .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_SetStatus(TSS_HTPM " hTPM ", TSS_FLAG " statusFlag "," .BI " TSS_BOOL " fTpmState ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_SetStatus\fR alters the status of the TPM. Depending on the chosen \fIstatusFlag\fR, \fIfTpmState\fR may or may not be ignored. This command requires that the TPM be on and the handle to the TPM available. \fBThis command is not currently implemented\fR. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS statusFlag The \fIstatusFlag\fR parameter is what the TPM status should be set to. .SS fTpmState The \fIfTpmState\fR parameter is the status value to set. For some states, this flag is ignored. .SH "RETURN CODES" .PP \fBTspi_TPM_SetStatus\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_SetStatus\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetStatus\fR(3), \fBTspi_TPM_GetCapability\fR(3). trousers-0.3.15/man/man3/Tspi_Key_CertifyKey.30000664000175000017510000000420513663651711020337 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_CertifyKey" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Key_CertifyKey \- sign a public key. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_CertifyKey(TSS_HKEY " hKey ", TSS_HKEY " hCertifyingKey "," .BI " TSS_VALIDATION* " pValidationData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Key_CertifyKey\fR signs a public key. .SH "PARAMETERS" .PP .SS hKey Handle of the key object to be loaded. .PP .SS hCertifyingKey Handle to the certifying key used to sign the addressed by hKey. .PP .SS pValidationData Pointer to a structure of the type TSS_VALIDATION. After successful completion of the call the member rgbValidationData of this structure contains the signature data of the command. The member prgbData of the structure points to a buffer containing a TCPA_CERTIFY_INFO data stream as specified within the TCPA 1.1b Main Specification. .SH "RETURN CODES" .PP \fBTspi_Key_CertifyKey\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhKey\fR or \fIhCertifyingKey\fR are invalid handles. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Key_CertifyKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_CreateKey\fR(3), \fBTspi_Key_WrapKey\fR(3). trousers-0.3.15/man/man3/Tspi_Context_GetCapability.30000664000175000017510000000445213663651711021702 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_GetCapability" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_GetCapability \- provide the capabilites of a TSS Core Service, TSS Service Provider, or TPM. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_GetCapability(TSS_HCONTEXT " hContext ", TSS_FLAG " capArea "," .BI " UINT32 " ulSubCapLength ", BYTE* " rgbSubCap "," .BI " UINT32* " pulRespDataLength ", BYTE** " prgbRespData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_GetCapability\fR provides the capabilities of the TSS Core Service or TSS Service Provider .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS capArea Flag indicating the attribute to query. .PP .SS ulSubCapLength The length (in bytes) of the rgbSubCap parameter. .PP .SS rgbSubCap Data indicating the attribute to query. .PP .SS pulRespDataLength Recieves the length (in bytes) of the prgbRespData parameter. .PP .SS prgbRespData On successful completion of the command, this parameter points to a buffer containing the actual data of the specified capability. .SH "RETURN CODES" .PP \fBTspi_Context_GetCapability\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhContext\fR is an invalid handle. .TP .SM TSS_E_BAD_PARAMETER - One of the parameters did not match. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_GetCapability\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fB(none)\fR. trousers-0.3.15/man/man3/Tspi_TPM_GetEvent.30000664000175000017510000000360113663651711017711 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetEvent" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_GetEvent\- get a PCR event for a given PCR index and event number. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetEvent(TSS_HTPM " hTPM ", UINT32 " ulPcrIndex "," .BI " UINT32 " ulEventNumber ", TSS_PCR_EVENT* " pPcrEvent ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetEvent\fR provides a PCR event for a given PCR index and event number. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object. .PP .SS ulPcrIndex Index of the PCR to request. .PP .SS ulEventNumber Index of the event to request. .PP .SS pPcrEvent Receives the PCR event data. .SH "RETURN CODES" .PP \fBTspi_TPM_GetEvent\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE \fBhTPM\fR is not a valid handle to the TPM object. .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetEvent\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetEvents\fR(3) \fBTspi_TPM_GetEventLog\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_Quote.30000664000175000017510000000417713663651711017276 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_Quote" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_Quote \- retreive a signed set of PCR values. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_Quote(TSS_HTPM " hTPM ", TSS_HKEY " hIdentKey "," .BI " TSS_HPCRS " hPcrComposite ", TSS_VALIDATION* " pValidationData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_Quote\fR destroys a context by passing in the handle to that context. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object. .PP .SS hIdentKey Handle of the signature key object. .PP .SS hPcrComposite Handle of the PCR composite object .PP .SS pValidationData Validation data structure [IN] Provide externalData information required to compute the signature. [OUT] On successful completion of the command, the structure provides a buffer containing the validation data and a buffer containing the data the validation data was computed form. .PP .SH "RETURN CODES" .PP \fBTspi_TPM_Quote\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhTPM\fR, \fIhIdentKey\fR or \fIhPcrComposite\fR is not a valid handle. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_Quote\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fB(none)\fR. trousers-0.3.15/man/man3/Tspi_DAA_IssueCredential.30000664000175000017510000000606113663651711021203 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_DAA_IssueCredential" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_DAA_IssueCredential \- issue a DAA credential for a TCG platform .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSPICALL Tspi_DAA_IssueCredential(" .BI " TSS_HDAA " hDAA "," .BI " UINT32 " attributesIssuerLength "," .BI " BYTE** " attributesIssuer "," .BI " TSS_DAA_CREDENTIAL_REQUEST " credentialRequest "," .BI " TSS_DAA_JOIN_ISSUER_SESSION " joinSession "," .BI " TSS_DAA_CRED_ISSUER* " credIssuer .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_DAA_IssueCredential\fR is part of the DAA Issuer component. It's the last function out of 2 in order to issue a DAA Credential for a TCG Platform. It detects rogue TPM according to published rogue TPM DAA keys. This is an optional function and does not require a TPM or a TCS. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS attributesIssuerLength The \fIattributesIssuerLength\fR parameter is the length of the attributesIssuer array, which is determined by the DAA Issuer public key (li). The length of a single attribute is if/8. .SS attributesIssuer The \fIattributesIssuer\fR parameter is the array of attributes to be encoded into the DAA Credential visible to the DAA Issuer . .SS credentialRequest The \fIcredentialRequest\fR parameter is the credential request of the Platform, it contains the blinded DAA public key of the platform on which the DAA Issuer will issue the credential the blinded attributes chosen by the Platform. .SS joinSession The \fIjoinSession\fR parameter is the structure containing the DAA Join session information. .SS credIssuer The \fIcredIssuer\fR parameter is the structure containing the DAA Credential issued by the DAA Issuer, the proof of correctness of the credential and the attributes chosen by the DAA Issuer. .SH "RETURN CODES" .PP \fBTspi_DAA_IssueCredential\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_DAA_AUTHENTICATION_ERROR The authentication proof of the TPM is incorrect. .TP .SM TSS_E_DAA_PSEUDONYM_ERROR The TPM is rogue. .TP .SM TSS_E_DAA_CREDENTIAL_REQUEST_PROOF_ERROR The proof of the credential request is incorrect. .SH "CONFORMING TO" .PP \fBTspi_DAA_IssueCredential\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_DAA_IssuerKeyVerification\fR(3) trousers-0.3.15/man/man3/Tspi_Context_GetTpmObject.30000664000175000017510000000420213663651711021501 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_GetTpmObject" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Context_GetTpmObject \- get the handle of the TPM object associated with a context. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .br .HP .BI "TSS_RESULT Tspi_Context_GetTpmObject(TSS_HCONTEXT " hContext ", TSS_HTPM* " phTPM "); " .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_GetTpmObject\fR retrieves the TPM object of a context. Only one instance of this object exists for a given context and implicitly represents a TPM owner. This function is normally called at the beginning of a program, right after the context is established. You must have a context established prior to calling this function. .SH "PARAMETERS" .PP .SS hContext The \fIhContext\fR parameter is the handle of the context object (already existing). .SS phTPM The \fIphTPM\fR parameter is a pointer to where the handle of the TPM will be placed. .SH "RETURN CODES" .PP \fBTspi_Context_GetTpmObject\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhContext\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more of the parameters is incorrect. .SH "CONFORMING TO" .PP \fBTspi_Context_GetTpmObject\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_Create\fR(3), \fBTspi_Context_Connect\fR(3), \fBTspi_Context_FreeMemory\fR(3), \fBTspi_Context_Close\fR(3). trousers-0.3.15/man/man3/Tspi_GetAttribData.30000664000175000017510000000465413663651711020140 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_GetAttribData" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_GetAttribData \- get a non 32bit attribute of the object. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_GetAttribData(TSS_HOBJECT " hObject ", TSS_FLAG " attribFlag "," .BI " TSS_FLAG " subFlag ", UINT32* " pulAttribDataSize "," .BI " BYTE** " prgbAttribData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_GetAttribData\fR is used to get the value of a particular attribute associated iwth a particular object where that attribute does not happen to be a UINT32. The structure and size of the attribute data depends on the attribute. .SH "PARAMETERS" .PP .SS hObject Handle of the object where to retrieve the attribute. .PP .SS attribFlag Flag indicating the attribute to query. .PP .SS subFlag Sub flag indicating the attribute to query. .PP .SS pulAttribDataSize Recieves the length (in bytes) of the prgbAttribData parameter. .PP .SS prgbAttribData On successful completion of the command, this parameter points to a buffer containing the actual data of the specified attribute. .SH "RETURN CODES" .PP \fBTspi_GetAttribData\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhObject\fR, \fIattribFlag\fR, or \fIsubFlag\fR are invalid. .TP .SM TSS_E_ATTRIB_FLAG .TP .SM TSS_E_ATTRIB_SUBFLAG .TP .SM TSS_E_ATTRIB_DATA .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_GetAttribData\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_SetAttribData\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_KillMaintenanceFeature.30000664000175000017510000000346613663651711022553 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_KillMaintenanceFeature" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_KillMaintenanceFeature \- Disables the ability to create a maintenance archive .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_KillMaintenanceFeature(TSS_HTPM " hTPM ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_KillMaintenanceFeature\fR disables the functionality of creating a maintenance archive. \fBThis feature is not yet implemented\fR. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SH "RETURN CODES" .PP \fBTspi_TPM_KillMaintenanceFeature\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_NOTIMPL The function is not implemented. .SH "CONFORMING TO" .PP \fBTspi_TPM_KillMaintenanceFeature\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_CreateMaintenanceArchive\fR(3), \fBTspi_TPM_LoadMaintenancePubKey\fR(3), \fBTspi_TPM_CheckMaintenancePubKey\fR(3). trousers-0.3.15/man/man3/Tspi_Key_WrapKey.30000664000175000017510000000501213663651711017640 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Kent Yoder based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_WrapKey" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Key_WrapKey \- wrap a key with the key addressed by hWrappingKey. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_WrapKey(TSS_HKEY " hKey ", TSS_HKEY " hWrappingKey "," .BI " TSS_HPCRS " hPcrComposite ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Key_WrapKey\fR wraps the private key \fIhKey\fR using the public key addressed by \fIhWrappingKey\fR. If hPcrComposite is not set to NULL (0), the created key blob is bound to its PCR values. The key object addressed by \fIhKey\fR must contain the key information needed for the creation. On successful return from this call, \fIhKey\fR can be loaded into a TPM. \fIhKey\fR must have been created as a migratable key and should have its usage and migrations secrets set using \fBTspi_Policy_SetSecret(3)\fR. Also, \fIhKey\fR should have had its private key set to either RSA private component, p or q. .SH "PARAMETERS" .PP .SS hKey The handle of the key object that is wrapped. .PP .SS hWrappingKey The handle to the key used to wrap the newly created key. .PP .SS hPcrComposite The handle to an object, if the value of the handle doesn't equal NULL, the newly create key will be bound ot the PCR values described with this object. .SH "RETURN CODES" .PP \fBTspi_Key_WrapKey\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhKey\fR, \fIhWrappingKey\fR or \fIhPcrComposite\fR are invalid handles. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Key_WrapKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_CreateKey\fR(3), \fBTspi_Key_CertifyKey\fR(3), \fBTspi_Key_RegisterKey\fR(3). trousers-0.3.15/man/man3/Tspi_Hash_Sign.30000664000175000017510000000511213663651711017312 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Hash_Sign" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Hash_Sign \- sign the hash data of an object with a signing key .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Hash_Sign(TSS_HHASH " hHash ", TSS_HKEY " hKey "," .BI " UINT32 " pulSignatureLength ", BYTE** " prgbSignature ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Hash_Sign\fR signs the hash data of an object with a given signing key. The data must be set at the hash instance associated with \fIhHash\fR by calling \fBTspi_Hash_SetHashValue\fR or \fBTspi_Hash_UpdateHashValue\fR. The \fBTspi_Hash_Sign\fR method allocates a memory block for the \fIprgbSignature\fR data. This memory must be released using \fBTspi_Context_FreeMemory\fR. .SH "PARAMETERS" .PP .SS hHash The handle to the hash object instance whose hash value should be signed. .SS hKey Handle to the key object which should be used for the signature. .SS pulSignatureLength Receives the length of the signature data returned at the parameter \fIprgbSignature\fR on successful completion. .SS prgbSignature Receives a pointer to the signature data on successful completion. .SH "RETURN CODES" .PP \fBTspi_Hash_Sign\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_HASH_INVALID_LENGTH Hash length is inconsistent with hash algorithm. .TP .SM TSS_E_HASH_NO_DATA Hash object has no internal hash value. .TP .SM TSS_E_HASH_NO_IDENTIFIER The hash algorithm identifier is not set. .SH "CONFORMING TO" .PP \fBTspi_Hash_Sign\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Hash_UpdateHashValue\fR(3), \fBTspi_Hash_SetHashValue\fR(3), \fBTspi_Hash_VerifySignature\fR(3). trousers-0.3.15/man/man3/Tspi_Key_GetPubKey.30000664000175000017510000000370413663651711020123 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Key_GetPubKey" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_Key_GetPubKey \- get the public key of an object .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Key_GetPubKey(TSS_HKEY " hKey ", UINT32* " pulPubKeyLength ", BYTE** " prgbPubKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Key_GetPubKey\fR gets the public portion of a given key object. .SH "PARAMETERS" .PP .SS hKey The \fIhKey\fR parameter is the handle of the key object to unload. .SS pulPubKeyLength The \fIpulPubKeyLength\fR parameter receives the length in bytes of the \fIprgbPubKey\fR parameter. .SS prgbPubKey The \fIprgbPubKey\fR parameter receives a pointer to the memory block containing the public key blob retrieved for the key object referenced by \fIhKey\fR. .SH "RETURN CODES" .PP \fBTspi_Key_GetPubKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_Key_GetPubKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Key_LoadKey\fR(3), \fBTspi_Key_UnloadKey\fR(3), \fBTspi_Key_CertifyKey\fR(3). trousers-0.3.15/man/man3/Tspi_Context_GetDefaultPolicy.30000664000175000017510000000355013663651711022363 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_GetDefaultPolicy" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_Context_GetDefaultPolicy \- Get a handle to the default policy object of a given context. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .HP .BI "TSS_RESULT Tspi_Context_GetDefaultPolicy(TSS_HCONTEXT " hContext ", TSS_HPOLICY " *phPolicy "); " .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Context_GetDefaultPolicy\fR determines what policy is used by all of the keys in a given context. .SH "PARAMETERS" .PP .SS hContext The \fIhContext\fR parameter is the handle of the context object. .SS phPolicy The \fIphPolicy\fR parameter receives the handle of the default policy object bound to the context. .SH "RETURN CODES" .PP \fBTspi_Context_GetDefaultPolicy\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhContext\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_Context_GetDefaultPolicy\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_Create\fR(3), \fBTspi_Context_Connect\fR(3), \fBTspi_Context_FreeMemory\fR(3), \fBTspi_Context_Close\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_CheckMaintenancePubKey.30000664000175000017510000000542313663651711022474 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_CheckMaintenancePubKey" 3 "2004-05-26" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_CheckMaintenancePubKey\- check the public maintenance key .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_CheckMaintenancePubKey(TSS_HTPM " hTPM ", TSS_HKEY " hMaintenanceKey "," .BI " TSS_VALIDATION* " pValidationData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_CheckMaintenancePubKey\fR checks the public maintenance key. If \fIhMaintenanceKey\fR is NULL, then \fIpValidationData\fR must not be NULL; the caller has to proof the digest on its own. If \fIhMaintenanceKey\fR is not NULL, then \fIpValidationData\fR must be NULL; the TSS service provider proofs the digest got internally from the TPM. The key information required for proofing the public maintenance key must be set in the key object by Tspi_SetAttribData before this method is called. \fBThis function is not yet implemented\fR. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object .PP .SS hMaintenanceKey Handle of the maintenance key object .PP .SS pValidationData Validation data structure. [IN] Provide externalData information required to compute the signature. [OUT] On successful completion of the ocmmand, the structure provides a buffer containing the validation data and a buffer containing the data the validation data was computed from. .SH "RETURN CODES" .PP \fBTspi_TPM_CheckMaintenancePubKey\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more of the parameters is incorrect. .TP .SM TSS_E_NOTIMPL The command is not implemented. .SH "CONFORMING TO" .PP \fBTspi_TPM_CheckMaintenancePubKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_LoadMaintenancePubKey\fR(3), \fBTspi_TPM_CreateMaintenanceArchive\fR(3), \fBTspi_TPM_KillMaintenanceFeature\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_OwnerGetSRKPubKey.30000664000175000017510000000405313663651711021424 0ustar deboradebora.\" Copyright (C) 2007 International Business Machines Corporation .\" Written by Loulwa Salem based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_OwnerGetSRKPubKey" 3 "2007-07-19" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_OwnerGetSRKPubKey \- get public key of the SRK .SH "SYNOPSIS" .ad l .hy 0 .nf .sp .B "#include " .B "" .BI "TSS_RESULT Tspi_TPM_OwnerGetSRKPubKey(TSS_HTPM " hTPM "," .BI " UINT32* " pulPubKeyLength "," .BI " BYTE** " prgbPubKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_OwnerGetSRKPubKey\fR returns the public key of the key object using owner authorization. This can only be used on 1.2 TPMs, and only to return the public key of the SRK. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS pulPubKeyLength The \fIpulPubKeyLength\fR parameter is the length (in bytes) of the prgbPubKey parameter. .SS prgbPubKey The \fIprgbPubKey\fR parameter is the pointer to the memory block containing the public key blob retrieved for the key object referenced by hKey. .SH "RETURN CODES" .PP \fBTspi_TPM_OwnerGetSRKPubKey\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_TPM_UNSUPPORTED The TPM is not version 1.2 or later - (Note: still unimplemented) .SH "CONFORMING TO" .PP \fBTspi_TPM_OwnerGetSRKPubKey\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_Context_FreeMemory\fR(3), \fBTspi_Key_GetPubKey\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_GetCapability.30000664000175000017510000000702613663651711020716 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_GetCapability" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_GetCapability \- get information on the capabilities of the TPM .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_GetCapability(TSS_HTPM " hTPM ", TSS_FLAG " capArea "," .BI " UINT32 " ulSubCapLength ", BYTE* " rgbSubCap ", " .BI " UINT32* " pulRespDataLength ", BYTE** " prgbRespData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_GetCapability\fR gets information on various capabilities of the TPM. This command can be used to learn how many PCRs the TPM supports, etc. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS capArea The \fIcapArea\fR parameter is the flag indicating the attribute to query. Possible values are: .SS ulSubCapLength The \fIulSubCapLength\fR parameter is the length in bytes of the \fIrgbSubCap\fR parameter. .SS rgbSubCap The \fIrgbSubCap\fR parameter is the data indicating the attribute to query. Possible values are: .SS pulRespDataLength The \fIpulRespDataLength\fR parameter is the length in bytes of the \fIprgbRespData\fR parameter. .SS prgbRespData The \fIprgbRespData\fR parameter receives a pointer to the actual data of the specified attribute. .SH "NOTES" .PP The following Capability Areas and Sub-Capability Areas are supported by 1.1 TSS's: .sp 2 .BR TSS_TPMCAP_ORD " - query whether an ordinal is supported by the TPM. " subCaps: TPM_ORD_* (see tcpa_literals.h) .sp .BR TSS_TPMCAP_FLAG " - query for the volatile and non-volatile flags inside the TPM. (Must be owner authorized). In this case, the 2 UINT32 values will be returned concatenated together in prgbRespData. " subCaps: ignored. .sp .BR TSS_TPMCAP_ALG " - query whether an algorithm is supported by the TPM. " subCaps: TSS_ALG_RSA TSS_ALG_DES TSS_ALG_3DES TSS_ALG_SHA TSS_ALG_HMAC TSS_ALG_AES .sp .BR TSS_TPMCAP_PROPERTY " - query a property of the TPM. " subCaps: TSS_TPMCAP_PROP_PCR TSS_TPMCAP_PROP_DIR TSS_TPMCAP_PROP_MANUFACTURER TSS_TPMCAP_PROP_SLOTS .sp .BR TSS_TPMCAP_VERSION " - get the TSS_VERSION structure tha identifies the TPM. " subCaps: ignored. .SH "RETURN CODES" .PP \fBTspi_TPM_GetCapability\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_TPM_GetCapability\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_GetCapabilitySigned\fR(3), \fBTspi_TPM_GetEvent\fR(3). trousers-0.3.15/man/man3/Tspi_SetAttribData.30000664000175000017510000000460613663651711020151 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_SetAttribData" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_SetAttribData \- set a non 32bit attribute of an object. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_SetAttribData(TSS_HOBJECT " hObject ", TSS_FLAG " attribFlag "," .BI " TSS_FLAG " subFlag ", UINT32 " ulAttribDataSize "," .BI " BYTE* " rgbAttribData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_SetAttribData\fR sets the attributes associated with a given class of object that aren't UINT32. The structure and size of hte attribute data depends on the attribute. .SH "PARAMETERS" .PP .SS hObject Handle of the object where the attribute is to be set. .PP .SS attribFlag Flag indicating the attribute to set. .PP .SS subFlag Sub flag indicating the attribute to set .PP .SS ulAttribDataSize Supplies the length (in bytes) of the rgbAttribData. .PP .SS rgbAttribData Pointer to the actual data which is to be set for the specified attribute. .SH "RETURN CODES" .PP \fBTspi_SetAttribData\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhObject\fR is an invalid parameter. .TP .SM TSS_E_ATTRIB_FLAG - \fIattribFlag\fR is an invalid parameter. .TP .SM TSS_E_ATTRIB_SUBFLAG - \fIsubFlag\fR is an invalid parameter. .TP .SM TSS_E_ATTRIB_DATA - \fIrgbAttribData\fR is an invalid parameter. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_SetAttribData\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_GetAttribData\fR(3). trousers-0.3.15/man/man3/Tspi_SetAttribUint32.30000664000175000017510000000473013663651711020362 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_SetAttribUint32" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_SetAttribUint32 \- set a 32bit attribute associated with a given class or object .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_SetAttribUint32(TSS_HOBJECT " hObject ", TSS_FLAG " attribFlag "," .BI " TSS_FLAG " subFlag ", UINT32 " ulAttrib "); " .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_SetAttribUint32\fR sets a uint32 attribute associated with a given class or object. In order to use this command, you must first create an object and then find the attributes you wish to set. .SH "PARAMETERS" .PP .SS hObject The \fIhObject\fR parameter is the handle of the object or class whose attributes are being set. Note that this is any object handler - context, policy, TPM, key, hash, etc. .SS attribFlag The \fIattribFlag\fR parameter indicates the specific attribute to be set. .SS subFlag The \fIsubFlag\fR parameter also indicates the specific attribute to be set. .SS ulAttrib The \fIulAttrib\fR parameter is the value that the specified attribute will be set to. .SH "RETURN CODES" .PP \fBTspi_SetAttribUint32\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhObject\fR is not a valid handle. .TP .SM TSS_E_INVALID_ATTRIB_FLAG \fIattribFlag\fR is incorrect. .TP .SM TSS_E_INVALID_ATTRIB_SUBFLAG \fIsubFlag\fR is incorrect. .TP .SM TSS_E_INVALID_ATTRIB_DATA \fIulAttrib\fR is incorrect. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_SetAttribUint32\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_GetAttribUint32\fR(3), \fBTspi_SetAttribData\fR(3), \fBTspi_GetAttribData\fR(3). trousers-0.3.15/man/man3/Tspi_PcrComposite_GetPcrValue.30000664000175000017510000000440413663651711022322 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_PcrComposite_GetPcrValue" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_PcrComposite_GetPcrValue \- get the digest value of a given PCR index inside a PCR composite object. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_PcrComposite_GetPcrValue(TSS_HPCRS " hPcrComposite ", UINT32 " ulPcrIndex "," .BI " UINT32* " ulPcrValueLength ", BYTE** " rgbPcrValue ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_PcrComposite_GetPcrValue\fR returns the digest value of a given PCR index inside a PCR composite object. .SH "PARAMETERS" .PP .SS hPcrComposite Handle of the PCR composite object instance where a PCR value should be returned. .PP .SS ulPcrIndex This parameter indicates the index of the PCR to read. .PP .SS ulPcrValueLength The length (in bytes) of the rgbPcrValue parameter. .PP .SS rgbPcrValue After successful completion this parameter recieves a pointer to the memory block containing the PCR value of the PCR indicated by ulPcrIndex. .SH "RETURN CODES" .PP \fBTspi_PcrComposite_GetPcrValue\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhPcrComposite\fR or \fIulPcrIndex\fR is an invalid parameter. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_PcrComposite_GetPcrValue\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_PcrComposite_SelectPcrIndex\fR(3), \fBTspi_PcrComposite_SetPcrValue\fR(3). trousers-0.3.15/man/man3/Tspi_Context_GetKeyByPublicInfo.30000664000175000017510000000526513663651711022622 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_GetKeyByPublicInfo" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_GetKeyByPublicInfo \- search the persistent storage for a registered key using the provided public key information .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_GetKeyByPublicInfo(TSS_HCONTEXT " hContext ", TSS_FLAG " persistentStorageType "," .BI " TSS_ALGORITHM_ID " algID ", UINT32 " ulPublicInfoLength "," .BI " BYTE* " rgbPublicInfo ", TSS_HKEY* " phKey ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_GetKeyByPublicInfo\fR searches the persistent storage for a registered key using the provided public key information and creates a key object initalized according to the found data. On successful completion of the method a handle to the created new key object is returned. .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS persistentStorageType Flag indicating the persistent storage the key is registered in. .PP .SS algId This parameter indicates the algorithm of the requested key. .PP .SS ulPublicInfoLength The length of the public key info provided at the parameter rgbPublicInfo. .PP .SS rgbPublicInfo The public key info is provided to identify the key to be look for at the persistent storage. In case algID equals to TSS_ALG_RSA this prameter contains the modulus of the public RSA key. .PP .SS hKey Recieves the handle of the key object representing the key. In case the key hasn't been found, this value will be NULL. .SH "RETURN CODES" .PP \fBTspi_Context_GetKeyByPublicInfo\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - \fIhContext\fR is an invalid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_GetKeyByPublicInfo\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_LoadKeyByUUID\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_DAA_Sign.30000664000175000017510000000716313663651711017544 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_DAA_Sign" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_DAA_Sign \- creates a DAA Signature that proofs ownership of the DAA Credential .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_DAA_Sign(" .BI " TSS_HDAA " hDAA "," .BI " TSS_HTPM " hTPM "," .BI " TSS_HKEY " hDaaCredential "," .BI " TSS_DAA_SELECTED_ATTRIB " revealAttributes "," .BI " UINT32 " verifierBaseNameLength "," .BI " BYTE* " verifierBaseName "," .BI " UINT32 " verifierNonceLength "," .BI " BYTE* " verifierNonce "," .BI " TSS_DAA_SIGN_DATA " signData "," .BI " TSS_DAA_SIGNATURE* " daaSignature .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_TPM_DAA_Sign\fR creates a DAA Signature that proofs ownership of the DAA Credential and includes a signature on either a public AIK or a message. If anonymity revocation is enabled, the value Nv is not provided in the clear anymore but encrypted under the public key of anonymity revocation authority, a trusted third party (TTP). Thus the DAA Verifier cannot check for revocation or link a transaction/signature to prior ones. Depending on how is chosen, the protocol either allows implementing anonymity revocation (i.e., using the DAA Issuer's long-term base name as the DAA Verifier's base name ), or having the TTP doing the linking of different signatures for the same DAA Verifier (i.e., using the DAA Verifier's base name ). .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS hTPM The \fIhTPM\fR parameter is the handle to the TPM object. .SS hDaaCredential The \fIhDaaCredential\fR parameter is the Handle of the DAA Credential. .SS revealAttributes The \fIrevealAttributes\fR parameter is the attributes which the credential owner wants to reveal to the DAA Verifier. .SS verifierBaseNameLength The \fIverifierBaseNameLength\fR parameter is the Length of verifierBaseName. .SS verifierBaseName The \fIverifierBaseName\fR parameter is the base name chosen by the DAA Verifier. If it equals to null, the platform chooses a random base name. .SS verifierNonceLength The \fIverifierNonceLength\fR parameter is the length of verifierNonceName (20 bytes). .SS verifierNonce The \fIverifierNonce\fR parameter is the nonce created by the DAA Verifier. .SS signData The \fIsignData\fR parameter is the handle of the received DAA Credential. .SS daaSignature The \fIdaaSignature\fR parameter is the DAA signature containing the proof of ownership of the DAA Credential, as well as a signature on either an AIK or a message. .SH "RETURN CODES" .PP \fBTspi_TPM_DAA_Sign\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the DAA or the TPM handler is not valid. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SH "CONFORMING TO" .PP \fBTspi_TPM_DAA_Sign\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP trousers-0.3.15/man/man3/Tspi_TPM_CollateIdentityRequest.30000664000175000017510000000646013663651711022644 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_CollateIdentityRequest" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_TPM_CollateIdentityRequest \- Gets all the informatin necessary to send to a trusted third party (TTP), repartory to asking the TTP to create a certificate for identity. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_CollateIdentityRequest(TSS_HTPM " hTPM ", TSS_HKEY " hKeySRK "," .BI " TSS_HKEY " hCAPPubKey "," .BI " UINT32 " ulIdentityLabelData ", BYTE* " rgbIdentityLabelData "," .BI " TSS_HKEY " hIdentityKey ", TSS_ALGORITHM_ID " algid "," .BI " UINT32* " pulTCPAIdentityReqLength ", BYTE** " prgbTCPAIdentityReq ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_TPM_CollateIdentityRequest\fR creates an identity key, binds it to the label and returns a certificate request package. The privacty CA requires this certificate request to attest the identity key. Only the Owner of the TPM has the privledge of creating a TPM identity key. The symmetric session key is required to provide confidentiality of the "TCPA_IDENTITY_REQ" data structure, which should be sent to the Privacy CA chosen by the owner. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object. .PP .SS hKeySRK Handle to the key object representing the Storage Root Key .PP .SS hCAPubKey Handle to the key object representing the public key of the CA which signs the certificate of the created identity key. .PP .SS ulIdentityLabelLength Supplies the length (in bytes) of the rgbIdentityLabelData parameter .PP .SS rgbLabelData Pointer to a memory block containing the identity label, which should be a UNICODE string .PP .SS hIdentityKey Handle to the identity key object .PP .SS algid The type of symmetric algorithm touse as requred by the Enhanced CA. .PP .SS pulTCPAIdentityReqLength Recieves the length (in bytes) of the prgbTCPAIdentityReq parameter .PP .SS prgbTCPAIdentyReq Pointer to the memory block containing the certicficate request structure. .SH "RETURN CODES" .PP \fBTspi_TPM_CollateIdentityRequest\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE Either \fBhTPM\fR or \fBhKeySRK\fR or \fBhCAPubKey\fR is not a valid handle. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_TPM_CollateIdentityRequest\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_LoadKeyByUUID\fR(3). trousers-0.3.15/man/man3/Tspi_GetPolicyObject.30000664000175000017510000000426213663651711020502 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_GetPolicyObject" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developers Reference .SH NAME Tspi_GetPolicyObject \- get a policy object assigned to a working object .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_GetPolicyObject(TSS_HOBJECT " hObject ", TSS_FLAG " policyType "," .BI " TSS_HPOLICY* " phPolicy "); " .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_GetPolicyObject\fR returns a policy object currently assigned to a working object. If you determine that the policy is different from what you require, you can change the policy by creating a new one and using Tspi_Policy_AssignToObject. .SH "PARAMETERS" .PP .SS hObject The \fIhObject\fR parameter is the handle of the object. .SS policyType The \fIpolicyType\fR parameter indicates the policy type of interest. Types are TSS_POLICY_USAGE and TSS_POLICY_MIGRATION. .SS phPolicy The \fIphPolicy\fR parameter receives the handle to the assigned policy object. .SH "RETURN CODES" .PP \fBTspi_GetPolicyObject\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhContext\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .SH "CONFORMING TO" .PP \fBTspi_GetPolicyObject\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_GetTpmObject\fR(3), \fBTspi_Context_LoadKeyByUUID\fR(3), \fBTspi_SetAttribUint32\fR(3), \fBTspi_Policy_AssignToObject\fR(3). trousers-0.3.15/man/man3/Tspi_PcrComposite_SelectPcrIndex.30000664000175000017510000000411013663651711023007 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_PcrComposite_SelectPcrIndex" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_PcrComposite_SelectPcrIndex\- select a PCR index inside a PCR composite object. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_PcrComposite_SelectPcrIndex(TSS_HPCRS " hPcrComposite ", UINT32 " ulPcrIndex ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_PcrComposite_SelectPcrIndex\fR selects a PCR index inside a PCR composite object. The PCR composite object must be created withthe function Tspi_Context_CreateObject(). An exampled for the usage is the selection of PCR registeres before calling Tspi_TPM_Quote(). .SH "PARAMETERS" .PP .SS hPcrComposite Handle of the PCR composite object instance where the index should be selected. .PP .SS ulPcrIndex This parameter indicates the index of the PCR to select. .SH "RETURN CODES" .PP \fBTspi_PcrComposite_SelectPcrIndex\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhPcrComposite\fR or \fIulPcrIndex\fR is an invalid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_PcrComposite_SelectPcrIndex\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_Quote\fR(3), \fBTspi_PcrComposite_SetPcrValue\fR(3), \fBTspi_PcrComposite_GetPcrValue\fR(3). trousers-0.3.15/man/man3/Tspi_Data_Unseal.30000664000175000017510000000473013663651711017634 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Data_Unseal" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Data_Unseal \- dencrypt data encrypted by Tspi_Data_Seal() only if it was encrypted on the same platform and under the current configuration. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Data_Unseal(TSS_HENCDATA " hEncData ", TSS_HKEY " hKey "," .BI " UINT32 " pulUnsealedDataLength ", BYTE** " prgbUnsealedData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_Data_Unseal\fR reveals data encrypted by the Tspi_Data_Seal only if it was encrypted on the same platform and the current configuration. This is internally proofed and guaranteed by the TPM. .SH "PARAMETERS" .PP .SS hEncData Handle of the data object which contains the sealed data. .PP .SS hKey Handle to the key object addressing the nonmigratable key which is used to decrypt the data. .PP .SS pulUnsealedDataLength The length (in bytes) of the prgbUnsealedData parameter. .PP .SS prgbUnsealedData On successful completion of the command, this parameter points to a buffer containing the plaintext data. .PP .SS hPcrComposite Handle of the PCR Composite object specifying the PCRs which are part of the sealed data blob. Set to NULL, if the encrypted data should only be bound to the system and PCRs are not of interest. .SH "RETURN CODES" .PP \fBTspi_Data_Unseal\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fBhEncData\fR or \fBhKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Data_Unseal\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Data_Seal\fR(3). trousers-0.3.15/man/man3/Tspi_Context_CreateObject.30000664000175000017510000001067213663651711021514 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_Context_CreateObject" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_Context_CreateObject \- create an empty object and return a handle to that object. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_Context_CreateObject(TSS_HCONTEXT " hContext ", TSS_FLAG " objectType "," .BI " TSS_FLAG " initFlags ", TSS_HOBJECT* " phObject ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTSS_Context_CreateObject\fR creates and initializes an empty object of the specified type and returns a handle addressing that object. The object is bound to an already opened context \fIhContext\fR. .SH "PARAMETERS" .PP .SS hContext The handle of the context object. .PP .SS objectType Flag indicating the object type to create. Possible types are: .TP .SM TSS_OBJECT_TYPE_POLICY - a policy object. .TP .SM TSS_OBJECT_TYPE_ENCDATA - an encrypted data object (either sealed or bound data). .TP .SM TSS_OBJECT_TYPE_RSAKEY - an RSA key. .TP .SM TSS_OBJECT_TYPE_PCRS - a PCR composite object. .TP .SM TSS_OBJECT_TYPE_HASH - a hash object. .PP .SS initFlags Flag indicating the default attributes of the object. Attributes for each type of object are: .TP .SM Policy: \fBTSS_POLICY_USAGE\fR - a usage policy (for authorization to use an object). \fBTSS_POLICY_MIGRATION\fR - a migration policy. .TP .SM Encrypted data objects: \fBTSS_ENCDATA_SEAL\fR - A data object used for a Seal operation. \fBTSS_ENCDATA_BIND\fR - A data object used for a Bind operation. \fBTSS_ENCDATA_LEGACY\fR - A data object for a bind operation using a legacy key. .TP .SM RSA Keys: \fBTSS_KEY_SIZE_DEFAULT\fR - Use the default key size of the TCS you're connected to. \fBTSS_KEY_SIZE_512\fR - Create a 512 bit key. \fBTSS_KEY_SIZE_1024\fR - Create a 1024 bit key. \fBTSS_KEY_SIZE_2048\fR - Create a 2048 bit key. \fBTSS_KEY_SIZE_4096\fR - Create a 4096 bit key. \fBTSS_KEY_SIZE_8192\fR - Create a 8192 bit key. \fBTSS_KEY_SIZE_16384\fR - Create a 16384 bit key. \fBTSS_KEY_TYPE_STORAGE\fR - Create a storage key. (Used to wrap other keys). \fBTSS_KEY_TYPE_SIGNING\fR - Create a signing key. \fBTSS_KEY_TYPE_BIND\fR - Create a binding key. (Used to encrypt data). \fBTSS_KEY_TYPE_IDENTITY\fR - Create an identity key. (Used for an identity). \fBTSS_KEY_TYPE_LEGACY\fR - Create a legacy key. (Can be used for signing and binding, created from data external to a TSS). \fBTSS_KEY_TYPE_AUTHCHANGE\fR - Create an ephemeral key used to change authorization values. \fBTSS_KEY_VOLATILE\fR - Create a volatile key. (Must be unloaded at startup). \fBTSS_KEY_NON_VOLATILE\fR - Create a non-volatile key. (May be unloaded at startup). \fBTSS_KEY_MIGRATABLE\fR - Create a migratable key. \fBTSS_KEY_NOT_MIGRATABLE\fR - Create a non-migratable key. [DEFAULT] \fBTSS_KEY_AUTHORIZATION\fR - Key will require authorization. \fBTSS_KEY_NO_AUTHORIZATION\fR - Key will not require authorization. [DEFAULT] \fBTSS_KEY_EMPTY_KEY\fR - Key template which will be returned as an object with very few attributes. .TP .SM PCR composite objects: None. .TP .SM Hash objects: \fBTSS_HASH_SHA1\fR - a hash object of type SHA-1. \fBTSS_HASH_OTHER\fR - a hash object of type other than SHA-1. .PP .PP .SS phObject The handle of the object to be created. .SH "RETURN CODES" .PP \fBTspi_Context_CreateObject\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhContext\fR or \fIphObject\fR is an invalid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_Context_CreateObject\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_Context_CloseObject\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_DAA_JoinStoreCredential.30000664000175000017510000000471713663651711022555 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_DAA_JoinStoreCredential" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_DAA_JoinStoreCredential \- compute the final DAA Credential .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_DAA_JoinStoreCredential(" .BI " TSS_HDAA " hDAA "," .BI " TSS_HTPM " hTPM "," .BI " TSS_DAA_CRED_ISSUER " credIssuer "," .BI " TSS_DAA_JOIN_SESSION " joinSession "," .BI " TSS_HKEY* " hDaaCredential .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_TPM_DAA_JoinStoreCredential\fR is the last out of 3 functions (after \fBTspi_TPM_DAA_JoinInit()\fR and \fBTspi_TPM_DAA_JoinCreateDaaPubKey()\fR) to execute in order to receive a DAA Credential. It verifies the issued credential from the DAA Issuer and computes the final DAA Credential. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS hTPM The \fIhTPM\fR parameter is the handle to the TPM object. .SS credIssuer The \fIcredIssuer\fR parameter is the DAA Credential issued by the DAA Issuer including proof of correctness. .SS joinSession The \fIjoinSession\fR parameter is the structure containing the DAA Join session information. .SS hDaaCredential The \fIhDaaCredential\fR parameter is the handle of the received DAA Credential. .SH "RETURN CODES" .PP \fBTspi_TPM_DAA_JoinStoreCredential\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE Either the DAA or the TPM handler is not valid. .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .SM TSS_E_DAA_CREDENTIAL_PROOF_ERROR One of the verification of the issued credential failed .SH "CONFORMING TO" .PP \fBTspi_TPM_DAA_JoinStoreCredential\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_TPM_DAA_JoinInit\fR(3) \fBTspi_TPM_DAA_JoinCreateDaaPubKey\fR(3) trousers-0.3.15/man/man3/Tspi_ChangeAuthAsym.30000664000175000017510000000465513663651711020323 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Kathy Robertson based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_ChangeAuthAsym" 3 "2004-05-26" "TSS 1.1" "TCG Software Stack Developer's Reference" .SH NAME Tspi_ChangeAuthAsym \- change the authorization data of an entity using asymmetric change protocol. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_ChangeAuthAsym(TSS_HOBJECT " hObjectToChange ", TSS_HOBJECT " hParentObject "," .BI " TSS_HKEY " hIdentKey ", TSS_HPOLICY " hNewPolicy ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_ChangeAuthAsym\fR changes the authorization data (secret) of an entity (object) utilizing the asymmetric change protocol and assigns the object to the policy object. All classes using secrets provide this method for changing their authorization data. This method changes the authorization data of an object ensuring that the parent of the object does not get knowledge of the new secret. .SH "PARAMETERS" .PP .SS hObjectToChange Handle of the object the authorization data should be changed. .PP .SS hParentObject Handle of the parent object wrapping the object addressed by \fIhObjectToChange\fR. .PP .SS hIdentKey Handle of the identity key object required to proof the internally created temporary key. .PP .SS hNewPolicy Handle of the policy object providing the new authorization data. .SH "RETURN CODES" .PP \fBTspi_ChangeAuthAsym\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE - Either \fIhObjectToChange\fR, \fIhParentObject\fR, or \fIhIdentKey\fR is an invalid handle. .TP .SM TSS_E_INTERNAL_ERROR - An error occurred internal to the TSS. .SH "CONFORMING TO" .PP \fBTspi_ChangeAuthAsym\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_ChangeAuth\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_CreateMaintenanceArchive.30000664000175000017510000000574013663651711023046 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_CreateMaintenanceArchive" 3 "2004-05-25" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_CreateMaintenanceArchive \- create the TPM manufacturer specific maintenance archive data. .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_CreateMaintenanceArchive(TSS_HTPM " hTPM ", TSS_BOOL " fGenerateRndNumber "," .BI " UINT32* " pulRndNumberLength ", BYTE** " prgbRndNumber "," .BI " UINT32* " pulArchiveDataLength ", BYTE** " prgbArchiveData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_CreateMaintenanceArchive\fR creates the TPM Manufacturer specific maintenance archive data. \fBThis command is not currently implemented by any manufacturer\fR. .SH "PARAMETERS" .PP .SS hTPM The \fIhTPM\fR parameter is used to specify the handle of the TPM object. .SS fGenerateRndNumber The \fIfGenerateRndNumber\fR parameter determines how the random number is generated. If TRUE, a random number is generated by the TPM and returned. If FALSE, a random number is calculated based on the owner secret. .SS pulRndNumberLength The \fIpulRndNumberLength\fR parameter receives the length in bytes of the \fIprgbRndNumber\fR parameter. This is 0 if \fIfGenerateRndNumber\fR is FALSE. .SS prgbRndNumber The \fIprgbRndNumber\fR parameter receives a pointer to the random number data attributes. This is NULL if \fIfGenerateRndNumber\fR is FALSE. .SS pulArchiveDataLength The \fIpulArchiveDataLength\fR parameter receives the length in bytes of the \fIprgbArchiveData\fR parameter. .SS prgbArchiveData The \fIprgbArchiveData\fR parameter receives a pointer to the archive data. .SH "RETURN CODES" .PP \fBTspi_TPM_CreateMaintenanceArchive\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more parameters is bad. .TP .SM TSS_E_NOTIMPL The function is not implemented. .SH "CONFORMING TO" .PP \fBTspi_TPM_CreateMaintenanceArchive\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_KillMaintenanceFeature\fR(3), \fBTspi_TPM_LoadMaintenancePubKey\fR(3), \fBTspi_TPM_CheckMaintenancePubKey\fR(3). trousers-0.3.15/man/man3/Tspi_TPM_LoadMaintenancePubKey.30000664000175000017510000000537113663651711022340 0ustar deboradebora.\" Copyright (C) 2004 International Business Machines Corporation .\" Written by Megan Schneider based on the Trusted Computing Group Software Stack Specification Version 1.1 Golden .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_TPM_LoadMaintenancePubKey" 3 "2004-05-26" "TSS 1.1" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_TPM_LoadMaintenancePubKey\- load the public maintenance key into the TPM .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .B #include .B #include .B #include .B #include .sp .BI "TSS_RESULT Tspi_TPM_LoadMaintenancePubKey(TSS_HTPM " hTPM ", TSS_HKEY " hMaintenanceKey "," .BI " TSS_VALIDATION* " pValidationData ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \fBTspi_TPM_LoadMaintenancePubKey\fR loads the public maintenance key into the TPM. The maintenance key can only be loaded once; any subsequent calls to this function will fail. The key information for loading the maintenance public key must be set in the key object by Tspi_SetAttribData before this method is called. If \fIpValidationData\fR is NULL, the TSS service provider proofs the digest got internally from the TPM. Otherwise, the caller has to proof the digest by its own. .SH "PARAMETERS" .PP .SS hTPM Handle of the TPM object .PP .SS hMaintenanceKey Handle of the maintenance key object .PP .SS pValidationData Validation data structure. [IN] Provide externalData information required to compute the signature. [OUT] On successful completion of the ocmmand, the structure provides a buffer containing the validation data and a buffer containing the data the validation data was computed from. .SH "RETURN CODES" .PP \fBTspi_TPM_LoadMaintenancePubKey\fR returns TSS_SUCCESS on success, otherwise one of the following values are returned: .TP .SM TSS_E_INVALID_HANDLE \fIhTPM\fR or \fIhMaintenanceKey\fR is not a valid handle. .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SM TSS_E_BAD_PARAMETER One or more of the parameters is incorrect. .TP .SM TSS_E_NOTIMPL The command is not implemented. .SH "CONFORMING TO" .PP \fBTspi_TPM_LoadMaintenancePubKey\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBTspi_TPM_CheckMaintenancePubKey\fR(3), \fBTspi_TPM_KillMaintenanceFeature\fR(3), \fBTspi_TPM_CreateMaintenanceArchive\fR(3). trousers-0.3.15/man/man3/Tspi_DAA_VerifyInit.30000664000175000017510000000423613663651711020212 0ustar deboradebora.\" Copyright (C) 2006 International Business Machines Corporation .\" Written by Anthony Bussani based on the Trusted Computing Group Software Stack Specification Version 1.2 .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "Tspi_DAA_VerifyInit" 3 "2006-09-04" "TSS 1.2" .ce 1 TCG Software Stack Developer's Reference .SH NAME Tspi_DAA_VerifyInit \- creates a challenge for the TCG platform .SH "SYNOPSIS" .ad l .hy 0 .nf .B #include .B #include .B #include .sp .BI "TSPICALL Tspi_DAA_VerifyInit(" .BI " TSS_HDAA " hDAA "," .BI " UINT32* " nonceVerifierLength "," .BI " BYTE** " nonceVerifier "," .BI " UINT32* " baseNameLength "," .BI " BYTE** " baseName .BI ");" .fi .sp .ad .hy .SH "DESCRIPTION" .PP \Tspi_DAA_VerifyInit\fR is part of the DAA Verifier component. It's the first function out of 2 in order to verify a DAA Credential of a TCG platform. It creates a challenge for the TCG platform. This is an optional function and does not require a TPM or a TCS. .SH "PARAMETERS" .PP .SS hDAA The \fIhDAA\fR parameter is used to specify the handle of the DAA object. .SS nonceVerifierLength The \fInonceVerifierLength\fR parameter is the length of the nonceVerifier. .SS nonceVerifier The \fInonceVerifier\fR parameter is the challenge for the platform. .SS baseNameLength The \fIbaseNameLength\fR parameter is the length of the baseName. .SS baseName The \fIbaseName\fR parameter is the base name that was chosen for the DAA Signature. .SH "RETURN CODES" .PP \fBTspi_DAA_VerifyInit\fR returns TSS_SUCCESS on success, otherwise one of the following values is returned: .TP .SM TSS_E_BAD_PARAMETER .TP .SM TSS_E_INTERNAL_ERROR An internal SW error has been detected. .TP .SH "CONFORMING TO" .PP \fBTspi_DAA_VerifyInit\fR conforms to the Trusted Computing Group Software Specification version 1.2 .SH "SEE ALSO" .PP \fBTspi_DAA_IssuerKeyVerification\fR(3) trousers-0.3.15/man/man5/0000775000175000017510000000000013663651711014367 5ustar deboradeboratrousers-0.3.15/man/man5/Makefile.am0000664000175000017510000000006213663651711016421 0ustar deboradeboraman5_MANS = tcsd.conf.5 EXTRA_DIST = $(man5_MANS) trousers-0.3.15/man/man5/tcsd.conf.5.in0000664000175000017510000001051313663651711016743 0ustar deboradebora.\" Copyright (C) 2005 International Business Machines Corporation .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "tcsd.conf" 5 "2006-07-14" "TSS 1.1" .ce 1 TCG Software Stack .SH NAME tcsd.conf \- configuration file for the trousers TCS daemon. .SH "DESCRIPTION" .PP This file, by default .IR /etc/tcsd.conf is read by the trousers TCSD daemon, tcsd (see tcsd(8)). The tcsd.conf file that is installed by trousers contains all the default options, commented out. .SH "OPTIONS" .PP .BI port The port that TCSD will listen on for connections, local and remote, from applications. .BI num_threads The maximum number of threads that the TCSD will spawn simultaneously to service applications. After .BI num_threads threads have been spawned, any application that attempts to connect to the TCSD will receive an error. .BI system_ps_file The location of the system persistent storage file. The system persistent storage file holds keys and data across restarts of the TCSD and system reboots. .BI firmware_log_file Path to the file containing the current firmware PCR event log data. The interface to this log is usually provided by the TPM device driver. .BI kernel_log_file Path to the file containing the current kernel PCR event log data. By default, this data will be parsed in the format provided by the Integrity Measurement Architecture LSM. .BI firmware_pcrs A list of PCR indices that are manipulated only by the system firmware and therefore are not extended or logged by the TCSD. Applications that call Tcsi_PcrExtend on PCRs listed here will receive an error. .BI kernel_pcrs A list of PCR indices that are manipulated only by the kernel and therefore are not extended or logged by the TCSD. Applications that call Tcsi_PcrExtend on PCRs listed here will receive an error. .BI platform_cred Path to the platform credential for your TPM. Your TPM manufacturer may have provided you with a set of credentials (certificates) that should be used when creating identities using your TPM. When a user of your TPM makes an identity, this credential will be encrypted as part of that process. See the 1.1b TPM Main specification section 9.3 for information on this process. .BI conformance_cred Path to the conformance credential for your TPM. Your TPM manufacturer may have provided you with a set of credentials (certificates) that should be used when creating identities using your TPM. When a user of your TPM makes an identity, this credential will be encrypted as part of that process. See the 1.1b TPM Main specification section 9.3 for information on this process. .BI endorsement_cred Path to the endorsement credential for your TPM. Your TPM manufacturer may have provided you with a set of credentials (certificates) that should be used when creating identities using your TPM. When a user of your TPM makes an identity, this credential will be encrypted as part of that process. See the 1.1b TPM Main specification section 9.3 for information on this process. .BI remote_ops A list of TCS commands which will be allowed to be executed on this machine's TCSD by TSP's on non-local hosts (over the internet). By default, access to all operations is denied. .BI host_platform_class Determines the TCG specification of the host's platform class. This refers to one of the specifications contained in the TCG web site. The default is PC specification version 1.2 . .BI all_platform_classes Specifies all the TCG defined platforms associated with the host platform. The host_platform_class must not be defined here. By default, all platforms but the host platform are associated. .SH "EXAMPLE" .PP .IP .nf port = 30003 num_threads = 10 system_ps_file = /usr/local/var/tpm/system.data firmware_log_file = /proc/tpm/firmware_events kernel_log_file = /proc/tcg/measurement_events firmware_pcrs = 0,1,2,3,4,5,6,7 kernel_pcrs = 10,11 platform_cred = /usr/local/var/lib/tpm/platform.cert conformance_cred = /usr/local/var/lib/tpm/conformance.cert endorsement_cred = /usr/local/var/lib/tpm/endorsement.cert remote_ops = create_key,random host_platform_class = server_12 all_platform_classes = pc_11,pc_12,mobile_12 .fi .SH "SEE ALSO" .PP \fBtcsd\fR(8) .SH "AUTHOR" Kent Yoder .SH "REPORTING BUGS" Report bugs to <@PACKAGE_BUGREPORT@> trousers-0.3.15/man/man8/0000775000175000017510000000000013663651711014372 5ustar deboradeboratrousers-0.3.15/man/man8/Makefile.am0000664000175000017510000000005513663651711016426 0ustar deboradeboraman8_MANS = tcsd.8 EXTRA_DIST = $(man8_MANS) trousers-0.3.15/man/man8/tcsd.8.in0000664000175000017510000000761613663651711016037 0ustar deboradebora.\" Copyright (C) 2005 International Business Machines Corporation .\" .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "tcsd" 8 "2005-03-15" "TSS 1.1" .ce 1 TCG Software Stack .SH NAME tcsd \- daemon that manages Trusted Computing resources .SH "SYNOPSIS" .ad l .hy 0 .B tcsd .RB [ \-f ] .RB [ \-e ] .RB [ \-c\ \ ] .RB [ \-h ] .SH "DESCRIPTION" .PP Trousers is an open-source TCG Software Stack (TSS), released under the BSD License. Trousers aims to be compliant with the current (1.1b) and upcoming (1.2) TSS specifications available from the Trusted Computing Group website: http://www.trustedcomputinggroup.org. \fBtcsd\fR is a user space daemon that should be (according to the TSS spec) the only portal to the TPM device driver. At boot time, \fBtcsd\fR should be started, it should open the TPM device driver and from that point on, all requests to the TPM should go through the TSS stack. The \fBtcsd\fR manages TPM resources and handles requests from TSP's both local and remote. .TP \fB\-f,\ \-\-foreground\fR run the daemon in the foreground .TP \fB\-e\fR attempt to connect to software TPMs over TCP .TP \fB\-c,\ \-\-config \fR use the provided configuration file rather than the default configuration file .TP \fB\-h,\ \-\-help\fR display help message .SH "ACCESS CONTROL" .PP There are two types of access control for the \fBtcsd\fR, access to the daemon's socket itself and access to specific commands internal to the \fBtcsd\fR. Access to the \fBtcsd\fR's port should be controlled by the system administrator using firewall rules. If using iptables, the following rule will allow a specific host access to the tcsd: # iptables -A INPUT -s $IP_ADDRESS -p tcp --destination-port @TCSD_DEFAULT_PORT@ -j ACCEPT Access to individual commands internal to the tcsd is configured by the \fBtcsd\fR configuration file's "remote_ops" directive. Each function call in the TCS API is reachable by a unique ordinal. Each labeled "remote op" actually defines a set of ordinals (usually more than one) necessary to accomplish the operation. So, for example, the "random" operation enables the ordinals for opening and closing a context, calling TCS_StirRandom and TCS_GetRandom, as well as TCS_FreeMemory. By default, connections from localhost will allow any ordinals. .SH "DATA FILES" .PP TSS applications have access to 2 different kinds of 'persistant' storage. 'User' persistant storage has the lifetime of that of the application using it and therefore is destroyed when an application exits. User PS is controlled by the TSP of the application. 'System' persistent storage is controlled by the TCS and stays valid across application lifetimes, \fBtcsd\fR restarts and system resets. Data registered in system PS stays valid until an application requests that it be removed. User PS files are by default stored as /var/tpm/user.{pid} and the system PS file by default is /var/tpm/system.data. The system PS file is initially created when ownership of the TPM is first taken. .SH "CONFIGURATION" \fBtcsd\fR configuration is stored by default in /etc/tcsd.conf .SH "DEBUG OUTPUT" If TrouSerS has been compiled with debugging enabled, the debugging output can be supressed by setting the TSS_DEBUG_OFF environment variable. .SH "DEVICE DRIVERS" .PP \fBtcsd\fR is compatible with the IBM Research TPM device driver available from http://ibmswtpm.sourceforge.net/ and the TPM device driver available from http://sf.net/projects/tpmdd, which is also available in the upstream Linux kernel and many Linux distros. .SH "CONFORMING TO" .PP \fBtcsd\fR conforms to the Trusted Computing Group Software Specification version 1.1 Golden .SH "SEE ALSO" .PP \fBtcsd.conf\fR(5) .SH "AUTHOR" Kent Yoder .SH "REPORTING BUGS" Report bugs to <@PACKAGE_BUGREPORT@> trousers-0.3.15/bootstrap.sh0000775000175000017510000000017213663651711015330 0ustar deboradeboraset -x aclocal || exit 1 libtoolize --force -c || exit 1 automake --add-missing -c --foreign || exit 1 autoconf || exit 1 trousers-0.3.15/.gitignore0000664000175000017510000000051313663651711014743 0ustar deboradebora*.deps *.o *.la *.libs *.lo *.a *.spec *~ *Makefile *Makefile.in /.pc /ltmain.sh /aclocal.m4 /autom4te.cache /config.guess /config.log /config.status /config.sub /configure /depcomp /install-sh /libtool /missing /dist/tcsd.conf /man/man5/*.5 /man/man8/*.8 /src/tcsd/tcsd /tools/ps_convert /tools/ps_inspect cscope.out tags compile trousers-0.3.15/doc/0000775000175000017510000000000013663651711013521 5ustar deboradeboratrousers-0.3.15/doc/LTC-TSS_LLD_08_r2.sxw0000664000175000017510000032760013663651711016772 0ustar deboradeboraPK}.219mimetypeapplication/vnd.sun.xml.writerPK}.2TF-Pictures/1000000000000249000001E26ECA3CC2.jpgJFIFZ`Created with The GIMPC  #!!!$'$ & ! C  I" i !"1v7UVW#AQTg268EFHSXt$Baq3R4DGw%&(Cb'5def ?Gtɴtl$ISb"ߤ~AQrJɨP9 SCI1<ܙWsZ!{ݯ7J{ݯ7J&[*k__T7&U־$n&k ҆&k ҉ʻė ɕw5/ItIte2%Cre]kKꀆiv (oiv (nL|I}PܙWsZ!{ݯ7J{ݯ7J&[*k__T7&U־$n&k ҆&k ҉ʻė ɕw5/F]7J?{7J%+k__T7.Y$fkM҆fkM҉~;ė ˖w9/*7J7J%,s__T7.Y$fkM҆fkM҉~;ė ˖w9/!tt_r5%CrkKꀈog$(og$(\|I}Pܹgs"7J7J%,s__T7.Y$fkM҆fkM҉~;ė ˖w9/!tt_r5%CrkKꀈog$(og$(\|I}Pܹgs"7J7J%,s__T7.Y$fkM҆fkM҉~;ė ˖w9/!tt_r5%CrkKꀈog$(og$(\|I}Pܹgs"7J7J%,s__T7.Y$fkM҆fkM҉~;ė ˖w9/!tt_r5%CrkKꀈog$(og$(\|I}Pܹgs"7J7J%,s__T7.Y$fkM҆fkM҉~;ė ˖w9/!tt_r5%CrkKꀈog$(og$(\|I}Pܹgs"7J7J%,s__T7.Y$fkM҆fkM҉~;ė ˖w9/!tt_r5%CrkKꀈog$(og$(\|I}Pܹgs"7J7J%,s__T7.Y$fkM҆fkM҉~;ė ˖w9/!tt_r5%CrkKꀈop(`lFCrP??VT5! !_eWG?ȱFZ"g5 Ao(0I@(.K!4$o([d@SDn1DDs sf1Q&yN`JT=95t579 cY^5 )tzU*: b""0FkGm_n4rVEtN"0\)PA *+.SON[1eB&@PL`v >q96UPLehNztbj""e(]1P1@-Gţط|N9L"'R.S@@@@CPBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB~7[WG3cQf?w+nQF̴Gl"yͨ3GgF>q(cSPr'2e*&:]tc"%ps Υg,v9є=;kRҲjj`9H _1PuHK.Ο v0jY",C;" `D"6🴅0Di¥yc)Ĺ\W6o/hjKixCLOr!J!m wW֋0ڜw$4 l't\Т)@l}cpwT[۾fQ w`$q *y{yἕQ,a>TH1/ ɐ.Lf6$]%I9NrPPE SP UQ82[~*j햆Pm@A\%Pr=5N}jPAU2a?(2"\6Kn` sTT#ısH}jq qKÖلM,6VUw\ʕ#$gPL܅ϘuAƳ"\l{U5J NdpPS e 7a1m@S<"cgьhxw;c.+>5eϗ^M%7 *؃gXcڨ8("p a`eܠ" %ʋaoU2b+J30J!|7(L@ƷGUQ{KL6\Fe9@ Q2ָl6b s8E =Z2Zb 6` Qw8Gcګ*UZdKLb`(XDWX͝1fNSS7/4GrR[ZP _0Tk+kܹxĴvST@PE &6> ~ 8 R96=.C TR!""pR tUgmg GIo6U Kc2|2cm7;M$EEAʡP@Me5`=À_ix[dsTC:ÓHCq)8fe%\\AƱbϱPv H*BC@'QDK *b5MjPCU2`?(2l6k:E- TAH[[(0QS2vs%^`6YpQ[h}2wؖL0<qXs{T 6s @@@@@5 Y7#jU!/1H9@qu\9bYt7IoVm)mm=ErHBur ܾLFb?8APTڣ|43YDNb&A9"#b +6؃gXcڨ8("p a`eܠ" 2X!^s})8 gLv]?1s8E =Z2Zb 6` Qo0懀{2s[>6\uZ{q6 X1H $5S !H\򈈉C(J & [~؃eE1ʥTȀpn& Xc5b=j&VdĀ'-5 osG([ 8,U9=BiTHb9 @ crw呵videHLSS>[8PˢF,Ź1&eT3 ;U8Bs XQtH6Sk8j3ZL.T"lU &&6"+ܡc`tLv\2jV#`ϣ!xdrs6@GqȹMRS>r6Dp kL]:ՈZ+9.1 J Blb Lc wly'T̐"bg Jd*B( fJ"@XC8,U9=BiTHb9 @ crqǵPhe *TSa :oWxLps+u*heJ̒v3&nB:c Yr.6=LU28(|)m2B0 )1tW3nw4<ܝlCY˯&՛ۋf5ud sNS6$H,T@,&bيg1BBBBBBBBBBBB~7[WG3cT,?Ŏ72F;HWES HP|a HP|a HP|a HP|aB[۾fQ wbg-Ts~Q3(~{߻04T"r=v6AVM$l4j.&Qbيmd2dҸ'o`W+8sqR-`Ұ=\w+`3V4sAC $q G7vb,QDb#%s⟖?BiZf0\.n0])8gxY;~}(𱅞O,Å,JyeN;~}(1ej'Ro(AEUӪI$LQT(&CVŝxK<ۧz`iRXji-!mvR"JW1%"G0[Xm !3lgT›$Pi8aa[+Hd7*7Q*t eT87>G]\0Mepd\Lf`u:0qf 蚍\q&'EG0~3LT0EGux1*;(SM:H3I4`)B ^$6eH z]e Oda{z>h&4t̋C3̚AiDҘ*M0 !en!q6q22͕Js-j#"ic3 $r"6`R5Ì-bmvS"H{Hnd+6[ eO _l,.lWS aM) `& 5'6FKVˣm_'  Qe54րi÷>I(X"E@ܧI"n LLse(M0:?)٠+;`XJOt2)XrWm@tSL: " SYLr 屮.|nF ߦs8͛]ǰQ\%&4ha%!YR4H`Bd̨m0{H xY;~}(𱅞O,Å,JyeN;~}(pw߬_EJ&|,agS-pc <%ҞYmӀL*62J7e'z4 ,Рkq5 {z&~  afe+Tc}?U;OSq]6C[5a#sFb?8+oe# JQV'IID]Bi HyG:fX M+C1 qgvb,PX>LX t[txK<ۧ X>k1:2} jM=4!6k_2˯"c <%ҞYmӈ]CVQoku]Nc] -v\?]'EUIA0dt@Q(rXFRi&(3el 4/{ѯr)sVnEaR&S[kh,DT wL@%f1.+<wCrNc aO(8]샣Q)Z(؉6$F$̦J& e :[SJ=YBSwbkC]C( ݌qI7n)ZG,*Hܼl&8i.Pq#'ؑ7o0ARlغ9Nem%ƍ~xV%=4g\]b%̚"4E9HfDBkL:w+/f;)tu"ɝ tS:Iqa WL\G6K1!gN\lGªS3bo#",0,gҊOxHڭ fW$%hdgIb*$( bLbe/]N$: ].Zͅ'@NP3B"""& @%|gҀa:ȻR,Qx<\ZhT-&%hvL53 ũ~*xjڕEIrc]&cF kp1 /̢dt͔ U7o$p@.;">A`=DΨ2mP6E<5Gt+((P#ڋI!K\rYBυ$gIZGdQDl\SQ"b%l7NU" %$CPuc;~}({{ 192IY*s9Jp1&SpFPeHRWy Qv> 6F-{@LrKx;o/"ϥHD U8p庎:W*ʙ ]@@NrC0x;o/"ϥl1RE*IX['TE&y3&ti D`G"kzҚX*ܙ4X0*܆8na) #b/`r(DO [Ut̍.TnA1a""""#DbY!!!\L?_+t?bi HY#i+oe"(>od(>od(>od(>od!-Ts~Q3(~{߻139(C?= * >l6GS2Z%TRD9p `)oAȦ]eNn|Y\"%cf F5(-BBBBB';LIdQ* %+qIAL貦sc]&$(Ȧ=    ~  a8nT^9R$4HAk#P85R(|1cyL+oe"g!2IY- $mzi'bvુ K27 8 eLŶ7r 1Mi=أ?ܥGGaFeW|OYP9mJ͜Sy:I`apLŰ P,rnjW\*ziuNHRT1*aa%bFb?8gBF3%r3' eP@G)Jk^kɄGR\V d* !D9ˬ69)fZaqU2r9HX"r&kB5it%>)K+(e.csPGȕe*a:TtrBLKL_7 Dۀ#VԻX77U%ATfT(_A)qs[TnXLڃk[*PE~c43;HWD!BFRe(vl%-TUVb5 UsDa "9*ɯYwK5lj$Q V@ P @ "Q&:~TDM _4%mrat;&fg)UWU59D@!j1f \c Dj=3ax 4Ҋ ` l.a0 "e3)j͢F]uի"I1l8wKLTFkUsD*ɯS itzJ!*\lPrj2x4;U508D3JsU_^i6җEJlfy?|%Re2k,r2(@Yn?vG( ڻ~?i =83 HP|aBBB~7[WG3cT,?Ŏ72F;HWES HP|a HP|a HP|a HP|aB[۾fQ wbg-Ts~Q3(~{߻04T|V?EbHR!H 済2l⦠7Wtorvģk͠mrw>]kkBBBBBwbg1BBB73e݈KS,v9єC1cyLl5ù2JƤ+n̐]40ZP jwOTue/ Er#3.$f\ _l"&CHke(¤KH9.DJR(j\ QM&bN]1oh^1NN"HC\ *)lٖTv]˵:(\IP171fimmlm->}L\{f){.hf,v9є%Xbi Hͯ)uI+pi+\ј@ _!&) ՑL%z]n}&\3K{j7xY;~}(4j隝4)>;THRV: c u_*`fZ81<*iSg ɪ*&' [gҊ1O𦽗gg2/1U6Ȇ7LÝL'aL,)k`KT+u#,(I@1E"Dn"CM'R%U+珙ٚ"R&fg@3[H}F7 Z5 (lk~Ż;%teYѥr@@@@CPۃvb,P\N_Tը2Mel (az L&m'8pfCN`3-1uMGEXZL\_850;o/"ϥH@~%xVY,q,#2:ڢ'rM7 c715<"VR^rQ5K*\Nc9?p[vb,PX>9 X>fSwNGIݞuLTDp,alǙ( ڻ~zef'j(>odg'!A}'8!!! aly]?_+=QF;HWFYLX!^s})L'!A}' '!A}' '!A}' '!A}'ꊢZ:x|d$2P 0% mb~@@D#e08;0ncXu:3q)FT5 )J(*T!bP1D1oq6 9QJPpci q na.ր踨0OhRJJ NVW(q0D,GSphU"S e` -D,P P@!@!@!@!@S?\L{߻1dV*BeR it$T!T!say9FD!I-_!3xk 1:H @V˗100.V/˶VΤoc o"Lbbumap@,BBQ}؏0C(߾G_˜@1cyL+oe"g!LbsE3b'E\~0 b_1v20 L {}Ҟr wb怄8e*I$s byz}+iɨʞ4JfEc˧ - 8$[8|gTy%+ tn ( T%ncT!^)JyCtOSW=B"2,iۉLg(HnM L&8q8hVU@eAVA7g6A"`\(@6Sz3,SѴPM1ereko0i4y{^(Ǫ$MdR!pXƫfudtN&0(P9W\%&"9L)I%hmvlcF !na\DF3bk0ƉSI{*Qj+fM` T* 6܏ \s5DAS3 $I(~BSH#c[cB)) 5Z4'{E8p+l({!%PΦ#NKQ3JNXdti&;R Lڀ`#`1K+"( ha"2%TPE |y%<tmBEѐ,#!p9W2pL#qOXmhKs[]w-D3|,iJyB3f{@ͶP܍mb*h%$L &GE&c0c($$/Pk/I":%T)Jp5tc a1idWFR܇H0 BY0MNz~f{i]<"XPsDl@ohb: 6\]\sZ&Fex{@$=?,~NETQ(9J FYҔ3nQ\匽ސLZKSвAԽ%HԖ(eL((X =f e\d e$GD*)@1ƸXs~ŧPԴڜ|YD@R(A! c 9.?ޞۻwl4y4Zi;tXʩbC1Q\yQЭ*Yn捛p"t' *̙a2FLJ K)"ZfG]"&UU'v\T-U#\fDQm4zBHҀ 2`\!5__p#+G4Fi$c/tX*rG)PyBM,6~{M:vC,J[s\DDDDGXdʈ,efbZ*FC*e1D)BŰX){C6ssDΑ3l(GŦa1idWFR܇H0 BY73e݈KS,v9єC1cyL )]?LB.hvQ Uw1){.hꕟD_7#:#0Wl⦌t Duv )U~vMzί:ț1fI\EQ ޢP*F!qs.M&}7tH2ғ:(iÐCR醠O4;U50ҜWd׬AТq`iuoh݊"*W)lEėS)Dr70:XH_S؈ 4ȫ`t5ͧ6piNwJka9*ɯY6qY; U^5@,Eg.NUKne>ck.8/QBRH1vhwDJkc r8 .7℆UTff@uqw&kș"b۫84;U508D3JsU_^ )U~vMz HP|a029 $ ^6ch!@-"#` l3~c43;HWFmu9@y$3B?^`GxI=s 5k,X!^s}) Kc 'V >O6nn)Jy"IXƑfL^"QD(P8 Mp&M\6~TNzW5"j:܉L"T< \TL4+;akVr }`DR68 e Tk)ZSO[>P]myyv菐ѵ96Sf(LX V~TNz77O6nn)JyQjbTiRIi"P1Ι!.RGWYT\ȉUT|U|b:dHVVS&S)p %ۛ}Rm9Sʔi_؀spV^Rfʐ JMf.EBCF\37ԚZpe]s@1J%  ~TNza+0u],w;l'3Fre*p)P@@Ka`D2Îp+)Y3lƦ"E$3P A6[(X79"@&oߙsR6x:EYqX%Ι3@/hoʣOUUaz/;*&pT~ 꿜ʺ7Q's*33~Uz2 T~ 꿜ʺ+&Qe)&Mک@u |6jq k.g2]!$$mL]$UU sK`L?ߕG̫~Uz2:Z|E52LZݻu[Ft ) `pbDم5"fJLRgN3͵EL&1t Ð*=WW]?_e]v"O2k*ZJJlu20/8@ДT(r K٣NfL$:,Rɼ;%iqJE I2R&e# =_-oͲq'79 T}.:LbdO0]f7 \ ^ߕG̫vg?e ^KN(I[aѦ`!q@ 1wuu1 VPra`ٺˢЪ-ʨ9HP E)o*=WW]?_e]v oq~|3N\U2EMa)P؅@T4~`va,tޣ1A4W 9U,i!ʖseTl` c~Uz2 T~ 꿜ʺI$w1*tEUBB _HπoʣOUUa*=WW] "rwRΏfEH" Q~  a n_I~p%);HWD!BFR&pB?!4S;(*~\E=ʪMU4Rڇ3Q+XT8(E>x4<ۡ3C8't"=>b˥ ,IsN"f8 D@(aQ RI 8[.UeHqH*RQ7wPqo ulWgM&Fĉ60SX9ƦRA.vey{`Ȕe*)U~NobM,a|rmlZP &PHE =/`CFG'IZqLg "A3 b01D@@B„C8't!>x4<ۡ3C0L){.h=!BFR>f!%fnM%A*&CDQP%&a  ^>BFR&pT~ 꿜ʺ7Q's*33~Uz2 T~ 꿜ʺL ߕG̫f} * >8vé_Ulr.k0rn\15}9wWhL 馒0N'p"*.)Gq ~Uz2 T~ 꿜ʺnI\IHJӹ?bܭ՘FLr@01:`C7Q's*ߕG̫T~ 꿜ʺk*Z9ܙh.`$)@rD>ָƄo"HKLu 6P`ZG72gcsEM@ q=\J "\b^16KDR혨0Cd~5*.I((Bq q8e)Dل 4} WQ3jMwȪBT"$snRJ`(\DvHWR ?wRYԢAâ1+Vie2"2Ā"DńTSY9QaLi (8jAjU:d" qPLb$ B&&]ÙdxϜ5#vbAIPIcɈA>P0@-xEQN%{7i2zA06扠PGsdT)rPeULSr 噷m!*Lh\55 .E\c`t[*=SѨiw,KF )LLQ, [T ˋZJA:JFTeȮ""H lqX@D,XEg4iMln&_*r=5mkjK0ҳmMH6ٝG:j G12BbT!ۀrp}s'K@paPXCHd.4@!͔@Dpe4˒a%,ݻw5$x}g@LAJ~vE;צJti*"X *Eɭ[69@3]Y+&xFe,Q:Ű$ A(䚉~2-Eh RdžV|^ZC;2)1!ę (F=C40ބ!3ysbUL0-C.[nK*rES<_KӔcn\""dLrr[Hma%Im4™7)Wl%prNc\ckojs2K~o2Q}؏0˷}/cItڨpTRuBFR&q Ŏ723BvQ Uw1G1U"怦=?;(Ttr4.^" P1"smqv5gJSͺ8$ n],3ʝ:f6.q `(P't#1Bk 60 &`$   y@ulpfL<mCc&aM4HA0~.aèA9NI5e>ȗ3r4t"M c31N6KkZab8eM%**Q8!u)P }'t 5igO9w>Aӄ\&H=&R EoTN~)xܷd\f܀( &D @и'MFe=h{0vP MZ#a%MY%+Cmn1Q$0J ZP?M-C(rBVLuJ.MwP&ll"C>x4<ۡ~7z2q3FX1nŋdlQEH"D(X)CP3~c43;HWFꩪdT]0m K"UJZ 9Xʹ\Rܛ.|&)>R(cQNJuIeI)9961iFDv@:K8txpHٝ51df#320SjT?lti U-$4L%+ʝ`s@Na sGۍecϱ1qRRҡ^GQK]IҀH`QuQLщH@aJDhՔp`Mu@ʨ0qEq0^UB!G=aG=b3G=cuKc֕;Jf}}<ctbì}"Y}a8gf'jy𝫾'h@wѓC0L   +tz0oy~zlᘃk_XX KJͩ*I5,tD"J"60!hbmm>YmGϚֶlAfG2Kל/?pݰKDE&cL!$d F\`ږ;5>YLTqTT{aN&uBIBw&͐kG*"a \R{ 鸖%C\NTfWu¡XlS&ɔfJ:0"`j/ ',QL  L<>'L寎eʚN")J q(ׂIo[ZJd=59%ʩ4GLck9`dVIa/2N_86E'1Kn$H*SFerCH&DbUESh|ܳLXDT  aXD" <RFmЍʈ,efbZ*FC*e1D)BŰX[[s3ҊI1i-OLv#RXÙC sX,Q0bn?|݋B;rQEfuNaJR"" Dc2[DQrf32BI.i2OB#XB c\,aF0a0|=lVEte-tQLS. ! >LBdsEs⟖?BV&hw(3 Ð@c6EKꥱ^WSU5o2Pe" 1&CLc9U/L=gE^WO%(3ǐ#E[S) "V Kfsrx~1рÐW8xfT=]I&= Ҝ& B\FsADL""6pO,lhо9b(%)@B"a,6~{M:vC,J[s\DDDDGXj&{JɴgOʷ'tXc1Mi8 :;b=Y.%Vg1k=C H|S18MaL.r^oHI&-%Y ^jK2S@b,[B[DQrf32BI.i2OB#XB c\,aF`bQ9:PU:jBF|,iJyBhʎI1rmUL(a54S .oO99XUQ DE6*$&S\08't!>x4<ۡ6j,+%Qhu޸USkb e8(s8ר-K (tW+l3CD3q1~x't!>x4<ۡ3C8't!>x4<ۡ3ee݇WSpO )O#6Flhо9b(%)@B"a 4y𝫾'hGQn?vOBFN&q ~7z2q3BBB&o/Ǖ?dm1cyj,?Ŏ72UXa$1rZe";ң3w N+e[܋? HP|aBZ1F KA Q0 %'݀~7z2q9(C?={wߔzL!"vGSv:Rep8-@,a k~* >+PG"ʋRJ $)\C\DDN@ Q6aA"F Քڛ0팙ZYgpl׵Nr4Stp޳@ФR '5NeX>bLl2ÕZi\*DԓiUP(b!s0@0ҜWd׬i4f,9$r~4m =>LMpM-n^/^ ,hM/Iln-x<c EXiNwJka9*ɯY–Rԝq_t)8]B7 YR0D9H9sd1 1b]eg'&ɒc )U~vMz84;U50Lg,E1HG4 E*y3Xa]3f4f,9$r~4m =>LMpM-n^/^ )U~vMz84;U50KGKFX20i*P6[kVYVO1M@#z/',B:OXF."_ߋˬB$SҪpiNwJk`0t%:4rWhP ndҧsqk\ra1ychnԔI(HQ1fPN(JsU_^ )U~vMz]Fbjby/cFߛ:}|\0Q[נ4_k[=G )U~vMz84;U50 n_I~p%)fɨZ~G<,홦Hr#9J p-$DFb?8j|ePhiYTRNBms1H&(@. b,K"+oe"g\ՔQG#Z'#,D#\`)@0_>l't!2K~o2ؙB¼(I#*iPi;`tG$c0mDtt Q9emDG/'+AuE5P25 )BKLͨ+4h`xtUv0 S)**1"0j&ㅘL 4*`܆ل=dMZl{6[n!2Nm[ɦi2vbH؉,)CNRDQ }*J^e9i fG{QfhHt25@&gJSͺ.I.Rf 'mm{@0ۉlƩ,t\M5% 1J8wSlf.4bYH @kaFca(R\Dd̀>D|LTk&NR\ 1e8i[]؊-R2$T dLW* ܁c O2\p֔fmЏa^JÊHDP ;n0jNMaR|Wu-pyjآb$ccM5@L!CF5Bon)9Sev+5;|<`r X6+qLB\P0 <RFmЇYҔ3n`ᴲjU&ѦRXM5U0qJ"*oq0'!A}'8a?i =8S?\P٠2Z%h3R`Q(q0D6H&m5rcH%9nQ \9eXwSrj-!Ec lRok8陴фFw4_kQӕr4Q1bF1X{R#Z&,D3')S小 .˞8X? u_\"O:AjŠ O$̽v+: ܁eR(@qd\%9Ȥ&)"#`c%~Ysӎ@R!1y4 a< Q_)l;PSLq6S \K|˧N8X? u_\)K'yᴰ'y8SUeN,b.zqK|˧NK|˧N8X? u_\)K'yᴰ'y8SUeN,b.zqK|˧NK|˧N8X? u_\34MgEtc,(3"6 GK|˧N7TCwJ0ޟjI0Vje2k"CB0@npLѣV [b&&TQA )JP#!!!\L?_+t?bi HY#i+oe"9gxYGy0v57"ؠQP00@y@$xOBFNOBFNOBFN"G72gc9onID31Oc.,+%+0:9[pgc$#0)d~5<%UI*E(,A8 Y\DH @oBBBBBBD2~p%)LFb?8gB73e݈KS,v9єC1cyL*lGi<;:FwXͷ1yT*eEiyLBokj(~y1sB~y0~y1sB~y0~y1sEg빶M$y&9VЊ:٬S\i3`4xя>xя> [Nj*CgPɮM Q?LQO?F<vQO?F<LQO?F<vQO?F<LQO?F<vQO?F< ~7z2q3 ){.h=!BFR&q$[ڛ/pldϢҦbgpl׵n)JyL>O6nn)JyL)W/=4Ԑe'G3g$H*sȨ*P6f~TNz77O6 / Rvȹ~i=MsECmpIC $ALO#/.(%Fn2ܤDuUMɢMc& \(fͪWߕ)Ӟ >O6fbE\MRˊPu(Ȁ"Ī<`a,\ͭ{0:M9T4JBDLU:YaR_0(Q%4[}Rm98D3sqO*Sͧ=~}Rm98Q}؏0~TNzfTFyݤ`;6Fhvlp!HeUDDDܦA&!!!!\L?_+t?bi HY#i+oe"(>odⳣ 7隚ftNhS&vib&%Cř(>odG wkSS3-:}3b]Ý\ 9sQ!$q^xutn$+U lJ<(q kOa#;fۘzSW@ٕ0ɔC m_VhsjFFIɐ帉KD̙CX\WϚRT51Q D@rZhuj(k(|(f\D-$M~s:Q-Q5Lr} KEV1 uD >$M`D*b[&(8k 9d=֎be+9f@~PjM24!uDGqPĔťOSf$̡Q)x{erܰp-B1UcF(hP> `Yq@@ Q)m |y][ʩhI+4byvs"Hb ?L({ۊzks7|RɝtсCHHMlA 5sd Q% l58]ħۮF!t<0>rru0j_8k꙳jrt_X%&*"Gjc,R j@)872D(9 7&<^9AH( VYDȉLa]! CYV*N3xs6%mrnZ [C2䶫[TmfU%H%.>3AfM@}+,0Q5@1qĉi56:`~VC&&PPD`/.x_ X8pՊqӍMmi(Hº4[ I.0 ) !bL!1c'l䏨鲏70 +bf d@_Qsb4bLTȐS$!6*@6(\ܦDDDDzű S !5)@Pn'1ԓyjr'jTnMVPL'/`K*vzJhe..j%NbJQ'1.pՊqӌ׸%[MqoB.gTt|c !jƙ/M=KK"c.c;*!6M!5G(j=[iiK bCM2hDURQ\Ɂ/U}ˁj1CDT%RPaKk"NI/{/͟ tL8bk\,6x ؤq4I(uJ`"`( , X"0׉S8%*:տ hoB//huGG8i2E60v:rSF &9PF)1l51*IjM8R䶛iNXԧ5̘l- @G.Pn`g2o%8ys!N:<:8{q.F* h Sg qK1C7( "%-@S<|5buAЭh)K-ӹ >4Rm` d 5 KJͩ*I5,tD"J"60!hb |4 )W?q)-ɞ0pOmW" 0"цb !}`"l |W?qsBsj;XS2$@ 7);plhTF|DHaHD zPGʝ5KYJP(68ڊ&a(3\Jsna0&M'{]Y\N"y-zD}^g-o%7-ž C)QL: {Q؛YS<Q^*L_" V7*dUhb j LՊqӇ_ X8P;4b%LL8% D@&W?qsBGA)1@J0H9Or ܡ-b014JELaNP0,8ܠ (LՊqӏl QU,hɝ!gT,r ldlaJ60 ΊU\-X«&,OwPX 1u6qfBBBBBB)ZVS wjNN]MEzG[(}f 0掿`itݚ #;T/M!V` s遈: D:~BBBBBB~7[WG3cT,?Ŏ72F;HWES HP|a HP|a HP|aI{)*ISkMQ DAe3F. P!.""X,S[in6˗\.6h 9| otݹ|] ^x;Z9|桚&%Y A4T/*u9|ҭ%&Il(Q]#@W3X䰀syêm)ل@ ENn% dBݍê\5XEf*ɪRo%r`,!pLMRN]aaե0]RI;$ؤGeٷp'1 \@ P0q9o\`FNUteP̄H{@LIgI֣?,v#ľbuޘuŒbp)nX9;}Rm9Sʔi_ҚGTvx|&M](|3uDSsPuL/J6TAaFa/Yеl2dhpTs(#-6Sʔi_~TNzɜ9;?A)r hJPx.Y`)( a)#k跭sqO*Sͧ=~}Rm9OzeFf܀-+EBFhFhrJfz-]fʟ̙Y꽃 sqO*Sͧ=~}Rm94]ֆ\A$NtUhSP[ˋP1YF E `mCPTN40gE3UY[a9Д P^Nc@ @m>O6nn)Jy}ݿĒ>pF44B`EU  20D,"c,}=+bJfUmg&67F30p7!2[}Rm9Sʔi_͗{Lr9miV d!3&B3k,S6P~TNz77I7#NA(,5 NB_bY 1@GUÖI8#N]T0" r_c "1Uǖ>}Rm9Y&HVq\R(RpPFap,)}Wm,HM¥X܄:7,}EI.h Vu]OpDj[00BH_QMCbˈ8$tʓoMI&Y3 jG 4X%rF`3\P ޒJqݶrGsqO*Sͧ=~ -&ҽȧNmh^\>Α&Πc'|܏:iP.9 ~1AdP0\@WXU'ZLsۀ1~]b!Y҂i_$|i:ivPT.9~)@d`(XDWXYhZuE'FPAvM#tƱ5uPPm|Pͫ3 Q q^ps>O6 h㒣I%1*n(R f[]YXm)+ >O6nn)JyfM˦iYvd4K Y9U9DuKmfkJ(~MA)$(,)5|èr~TNz77I7#NA(,5 NB_bY 1@GUÖ>G3ES4m'6TPd@-8U[}Rm9Sʔi_٬-:v "( E&ꑺdX\:R(k6(fMNwL ,RqFS34`vnn)JysqO*Sͧ=~Xm)+{Sr}f3O6 [i)}vsŜN(*ff`,#->iO9\nn)JysqO*Sͧ=~g2wZ$^yDHډN"xN*R -wZ*`yHiݒMf"籸H)SFڀYߕ)Ӟ >O6 gR܍SCr?[.m/?b=,ް hyɀJ9U'm33L q k~TNz77I8#N]T0" r_c "1Uǖ3&ND(IQ;IV@/3P`AXk77S=xя>xя>S=xя>xя>S=xя>xя>S=xя>7T==iSio͞g7.Sϐ9L )L:ڀ!OjZ{P3Ҷ)Wp rX5D "S=xя>xя>S=xя>xя>S=xя>xя>S=xя>xя>S=xя>xя>lZڟ}/]/TLIb19uW-ƖĊ#ػyEҚ@IA5:B!rBƵJ`F FT2IGgl%"l#*yt1=2e:.Ol-9E3>eQMgkfQ#&tkSq9P)T xl5ù2JƤ+n̐]40ZQ~y0)ZAT(:u 8XL(&F" |a]B\tDd&̈8*C DT@@2fQO?F<vQO?F< ٝ=VL@za:}fA?bYE[%Q)@' XI͓]3Y%+p*ݓWMcH(()I;('};('}LCI8LѠi[S("tMe\-ă2^F gб3D˦PGZ0MWjQ=N 1`˟txF1GG]2 B&8e0}RζL $r3Z EU+Q@m/l,0XpW CQ!o05f8T&Yi9n*MƌHpX‡"I=iw8$8֘b^&myL`QѩC久$A¨Y}a8)ǩġJk]eT#umpUAr@%S lES6uq*UϜOc:f%X3XIU+K1P{TPm/p\q.&g]gd1aut @9șq);;pghUVLa)ps{Vi[ KNڱP3U:JT̡JSAG DIT l:ʿ{Nb%=(*ѕ(@rob>GtZ:Uc,ć2K`2 "MgD s'qͬFO9ѳW6f!vtLm)mY kX }ylq}粆aDV`fx:-ޕ @.C q)$jYI.sh/DȨc'"ɔTGDblZvzժOKUHe**U`-&TPyNP0 : ɭN%%)ju'?\t"25mAS~ph*4+s(ʎBUܕA b1bI4IxJQ!ϦLÔ\ŸZ&[:-ҔOG'rHKDS) \* r`#cY**~Q8)3PHbcU)AC@LŽ,6u2)dfVH3ruODr"!F@"*I JLFԽ#D^0M Y5aS0d "jck)CrڴùJ m-fl6 UH0CaQdָP`L2K~o2ؙ@!}aaCf]~o&[3g0%?[4S8_) L$ cMf D3d0:s P `Q@Efy%mQ&^ZvXށRTT6„Mq.bdf)D pΞ⪉UJjE*2C ]xb/sJ&(a^a|ގ`Yz)xܹ.2g%e c73-R1ܷq$FK8#kk0hCаl¸}]_L]1#dP;@n`7R,okڸb &p\qo!y'`u#CD@ɦE r3Xh"U'Kgy;`\ U nphyG1U"geW|O+oe!(>od+oe!(>od#uEMX ڞq&cacgRRk cɏ(s W1%32˞ү)P>m.W($SA|p5.A5$"#3NŢ Jgf]TU8@"|%՚NV dA{7UeIr Z+/("tĂ &\ G889ELyUjɛUWrTnsɐ9)l6-L_nA?'c7z&PMcEBfP@\,fet ORHs,LЊ逓@M`1P5%VӮKg4V3UTj*&}db6Sڽ=Ѐ)UUSyښEMhWaXSj؆0 {yԥZU8T !Nrb& sXa.J\t2R_ڦ")e!bLLmBs}1Zo3^hޜ2Έ2l3LVștTJG F |b+Fb?8%l0B_-f&m ݺ`i9 R=݈KSf?!4S;(*~\BBB=Q~7[W@zg,v9є_6BFR*OBFNOBFNOBFNOBFN"+JvB7ݸS"*mfDPr@z9TLN@9, b[ĥ8l0t8wc9lA!/bh̯rIPN3(R(R9|12*`:HLbp[܁I@kY%U/3D?e݈KS|f\;ĬAV5&?^pn̐ t0rkW@XBFR&qI1 _V :h3" J]cl "@b%^nҞiՠ:f%6m)暝Z%6m)暝Za^nҞiա^nҞiՠ:f%6m)暝Z%6m)暝ZbY}a8)w6MNaؗ##4 ?,~N+"w(rB"af%XvQO?F<šl<+&l3Rb\9@s7 { JyV { JyV阁:ŠeBU߃p*}1MlT D*>w6MNw6MNcSJS3)& WkNANaMn5L"7eYTiV4u3u:.fL]s@!tT CDw6MNw6MN:/. KnT^fɋ6ʮV**ݺHPdHC!Tɬx㙸KmS5:8KmS5:L9ͥn{('}[۾fQ3yfZTn䓗iwR@n"smqv5%6m)暝Z_Gݾdtc&qn@ E\ˣ!B х*zRTp9]ח=8>F EE=@q xKmS5:8KmS5:NWoĦLk8xv霩Sb Bk(zBO0.Lɲ4hArPGN e ʘ` K^۹juhp۹juhd˷}/b/asiO4ѳcfZiSgj&(vbDn!rmpr* Oò{1Ʋw cUJČj9r5b D p0 G݀b>é GSPz;#*Lv)ڥ8e.4 { JyV { JyVK6?RSyǖhMLTL\͉@ `(on/".S3(Zb'w'&@@ #s`%6m)暝Z%6m)暝Zg+̂T Pf솲h&Tж7Α7CN5YM8ETi*f$NLBF /s { JyV { JyVbsG3p۹juhQO?F< ,v9єѓ3߱p`S2+ ȩ 1LQF :"\%6m)暝Za^nҞiա^nҞiՠ:AsIcdűx]Q3Jb{!ٜ)PNfs΀6Ag39& &֊_]E5Nw6MNw6MNcaJNITltb,A"" r&Q?( nH7*ag'm0zs4[ 6dLTYb7 +)[#Z۹juhp۹juh *_I4$USc,+6ڹ2@!Jb&X ї.[4֗>IUdpSXŸj( ݀.":ƀ/asiO4/asiO43nw6MNw6MN1 ~  a { JyVdƪiӓ| Ara)JG1U"MǼ{zj*f7.SϑG7B)XQPBBB=Q~7[W@zg,v9є_6BFR*OBFNOBFNOBFNOBFN" XTL\'$,31M Al)c/Xñ ǰ֙Q_(/ &S*Aɤb&i 'ר,&AyQ+ |=7Lhc9EHS b{q}ˠ!YE0:1lZڟ}/]/TLIb19uW-}g-0&%6Trʗ>k u{e;TpD2a.-w^sCO5SXL 1to4#6NN5qj Qr8ᛌAb)q@ `avAr%3c=GNM^tvjڂlt`L2p1D  ",/WV;MHU0fTbr&%*yh )!` 7KJtN̡O dRl$YY2v!%~Pۄs$ H~oVT3p((.THR*4gS [Tp^Ԗ\+D1L `)P @cF59F<(Zi¨#h"&RtʆYe֛=991+\DDDDGX5r %CM}-Kn8Okr(mI.a#{78kHJzL*VdpK)˖PD8\QvB͞r !"߄gT&֕;6M;<REb=oP)s(K`E ;wOz2wr}n-myd&]Qp9lr{0'o}\VJ(.1GHI'.Ӟ"/I@(6丏pg qxM 5vr1MB)7`e53p2ێH b*g i' oYҔ3n8't # xEKTLzV]4b M\!aV %0BCPfҮY˜y, pO )O#6C|,iJyB qxwPRzFs'vG%fTX. ϔJ\9 "RТg px1Evㅳ$&)QC) 7kԥ*}Yy5'&!ēluVTzY*&N\(6L.ל~CQav.`OxIhV3hnLTG CbS{Bڋcu{!vsʱ$aK )JQ)6.]YKp7V[qhPDLU5 8pe3,>Z@.IJ'!(|JK56`YT- C0 p밀ag px1Evㅳ$&)QC) 7F{0'o}L't# c9ytJQ9D@q툀U`~fسM+2uBA0 `TsDƹGX$4;=t%i1I)&lϥP 6Ü,̲a NQ9Q;l >x4<ۡpWFw l6R CXʈ l !Na=iSjSo͞dӸSϐ!xP )JڍYҔ3n8't 00[)-5,p.ێF& gjL!Ɛ1"T:bT̈7)LC*%8j@ <> )fpO )O#6@DgG>}Gە ˭6zss cVCcU)^# z2tB6D*6)@L71> )f.09HI$Ԟ,a/IA(J6g iIOS{IBj̒ێ e9rR @u[M)9 ܮt]vm0@B-@VuNa=iSjSo͞dӸSϐ!xP )Jڌw=ksd|ͮ,@W4QieSdETN!JbQ)P  Q;ς8|Uӷ*eZlT0qb# +p֮$ 7XS-=R-Ƞ $@GW ##)oi0[Y[q›a,.[ATr XlgFcGe +6zCrb_c^G*uYɕUI^BT @#byDDlh@W n;퍳۪&{ɛ3\a ]NҦiM6g@o9S&rA(ܦ0kn,@Tm1v+*U`*PDH(kplaBBB&o/Ǖ?diݴuNd͕unT2Z9t؁ZDJLDT eP~Y"v.>rV2.H 0UiVܝ \]%{[\s5V޸E+&;ÆYNݐڄ `6D8eJ6S/nk8X66]lⳄbU:Es)bْ67'k](hyx2kZ"+"v3蹼*N+i>RdH)UlP( PHsԙJJb涚*3bhSr´g%P /5H:dEB*a 9Ovsk,YC5PMNJ,Ri8^) ."" vsk,YC5PMNJ,Ri8^) .""2BBBBBBBBBB731zхKPLʦHդoNW'HlqP o XNa>O6nn)JyL>O6nn)Jy}MZdHk3}$s):Ad̨:{4ozʢlydlᑓVNXEQ99(&<n>n)JysqO*Sͧ=~1:G&A0TnY++KM,p;3uRnT! _ l*ZU v2'BLDv'8"TL J8t@D/pn)JysqO*Sͧ=~s9cWu誈\ R[:@"(%OXJ T"jѝJuݝO6=t '2'oSw5t'Mw4 i-S56\cF4+:e;=q,#0AG먓wJ&.*h'XDH  &~TNz77Q5 x* V 1(/{sqO*Sͧ=~}Rm99Pg4*dJzrEۄ ]UN "c,uN:D xߕ)Ӟ >O6 "ߕ)Ӟ >O6 C+/8ŸsqO*Sͧ=~>%G-?3#W=#vE[SCP1% a9!!!!!!!!!!!\L?_+tnݵaS8|MZ6ve]c {0ڻ%V K"PflS~W3/$飗fEd DZbBM,6aգ8{M5vFdWFR܇Hnq)`%@@5U[-5`Ż-jѲeE b @*gm`3e]a VNa6 k"&Qs%OBFN"xeXlϰt̍.Ω܂cKZ;jw\飔ʲ+p9!1L5 } W)Hhƒ_D՚%E$a0!@.""6Qr :xJvu ~:7R\C)kSB>~ ?BQ3Qv |( Dvd 8ϰcGO!1'ِ>?`ПGfB>~ ?BQ3Qv |( Dvd 8ϰcGO!1'ِ>?`ПGfB>~ ?BQ3Qv |( Dvd 8ϰcGO!1'ِ>?`ПGfB>~ ?BQ3Qv |( Dvd 8ϰcGO!1'ِ>?`ПGfB1Kba7wɹz&b%zcZ< |( DZ{*liz3IY rHW $"b#> qM \JAR;ry/MADrG)Db Q-=FQv |( Dvd 8ϰcGO!1'ِ>?`ПGfB>~ ?BQ3Qv |( Dvd 8ϰcGO!1'ِ>?`ПGfB>~ ?BQ3Qv |( Dvd 8ϰcGO!1'ِ>?`ПGfB>~:S/ܙ ^viMzu C3mqk@!@!@!@WcFaly]6BFR5bi Ha?i =8a?i =8a?i =8a?i =8BBBBBBBBBBDM!l'/NvܽBH_"G2dT *"|ֽ dC(߾G_˜@8K;U5.mW׫D~iz8K;U533s_s^~izL .mW׫Cs_s^J}Q 3)kNe)(V븽Qr! sӲ#9YXȹPD[,DQqe))jIB1.mW׫Cs_s^#WՆK`YRL粄\MC b[P5sX-xIe9$WlJ)'-he(s;F%q6@-%|%ӝͪӚhpNw6NkգV3Q/&rɞS$%>D:eܷ LrPe,^:2F`0LPP-B-%uΚjWBs'2LtD @^CmJ,.R*S;E=3Ҥ > jLTs237drg $P@SO%m@L"qlRMeejgMp"BDLS\.mW׫Cs_s^^>^F͐ΩJDD2@򀀉D0 .mW׫Cs_s^8@C8K;U5.mW׫D~iz8K;U53hy#a;L鲹L]"G(.a͈fѓq0oy~%piNwJka9*ɯYS ԟmAP+.YQ"N cc1 q pau#g0H5I7x KCdŎT[b9ORʔ&t`uAʘ9n FڀG4E<5[l$rk\0Ksu&v]ffA(1SY*jꩨ0@nh;=EZ;]:p !N D1x4;U50ҜWd׬e@Rͦ j Wjg)󑾓DC "RpiNwJka9*ɯY!SҪpiNwJk`&pgt;&fSҪ "9*ɯYt;&f(>odgR[ Va/nVf1iRDc6BBBBBBBBBB~7[WG3cT,?Ŏ72F;HWEUCjK7jV { zY޽cѓM'sL2!U]-K EDMǷJ)&[OBFN"&p P]]j!t6Kr]G3ofOzS)ofOzS)s6d'>r]d'>r]G3ofOzS)ofOzS)s6d'>r]d'>r]G3ofOzS)ofOzS)s6d'>r]d'>r]G3ofOzS)ofOzS)s6d'>r]d'>r]G3ofOzS)ofOzS)s6d'>r]d'>r]G3ofOzS)ofOzS)s6d'>r]d'>r]G3ofOzS)K$l%ۘv喘meD'O9u(`6l!!! aly]?_+=QF;HWFYLX!^s})T*'tA/n#"lA30 Q9s,s0s2ń(>od?]6\42]`;cl+}hml}ymoѓ!!!!!!!!!!!!AH`֬3&h"C,S >%n¬,Wa¬,Wa0f*:m*:m3n¬,Wa¬,Wa0f*:m*:m3n¬,Wa¬,Wa?]bLiZq^Vє@tZQgN6t0͔k4uħuw MͥAMn6L׵׎s*:m*:m3n¬,Wa¬,Wa0f*:m*:m3n¬,Wa¬,Wa0f*:m*:m3n¬,Wab&SXuRlgu*ROQ"[ t1DB @m\* =GʮU*nq8Rh)J"߀BBBBBBBBBB&o/Ǖ?dm1cyj,?Ŏ72T~7z2p~7z2p~7z2p~7z2q3!!!!!!!!!!!fۿy:f9cn}zK" +GRObu)lAi1pg*rf` -G=JNIM2|JU&EruGHs"&V+y[9kU&E0E.r_F'=9-5ŬA_:GҤ Ъ"[*"e-P+3PϱjTh4ΩnJEP\?+k 6@:ر-jic[enjL\ æW~13BQ1.Z;b؎]PJQKgY2ka1!ͨacQxT%tu0*a@JLRC(!q0#2>6r&MH˦ggRLV 1HAw* ED qTL:!8HԚ6Q%&;%.L"k\@,]b2WUMPxŵfJoL=H^C6h Q*\sm$>&&M3+(HI.Us&.% sח6W %f*3~`Ikv* h:"PJ "2>Q a3cYLa"œi{ǩ&x' NkbDljkT郹D"] ?xSmЊNf2*M34618B\B.kRs qe&OM`.ruF"sq汄/mPZĊ5&o5{.nIt@Fr!]R (kSTFoR)8~5685> :PPuC1cyL+oe !?*G㞘\L\zbs@!@!@!@!@!@!@!@!@!@!@WcFaly][=LVIfv`EUHCL61DCUÖ"mbN pʭn35<`¢5ɕUTل$=r4YkXh/T2Ģtؠ+0XBèu(ÊF✺!U[ס4{/nldɥ&Rgq|f)ZWTSٶNS"[mLN`PoHB*  \}vGR*U%41 yns7-0XsCDr&wRgڵSj&eE 9ͩM4:5{"M , V:٥6qו09a{Cg@!@!@!@!@!@!@!@!@!@!@#8vpMڲwRʤfM+0fbܗv0])8pO,L0])8pO,L0])8pO,L0])8pO,L0])8pO,L0])8pO,L0])8pO,L0])8pO,HI\5tx(G%Bl"xK<ۧ0])8 kRI\yr&@`{7(s,JyeN,agS-p8bi HpO,Oq7 hŎ!SNE799 Rq b#ع1R?gbHsBBBBBBBBBB~7[WG3cT,?cqg*&h|v)8NP7(AhB"           wXlϰtʆYe֔991$d !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ !gJSͺ <RFmЉ 0rTVI,i,`MYTRNR"#`̈́           +tz0oy~n؞za.ȷ-_d=9? V.{M,-8tN֤&lXcn6Je]Nf%T#3uK6%Jlx[{fv9 *2uUIe8KPܿXΣc£OvvK4%ɌBXLCPihz<Zdm+`=2zoO4+ӱALަj\s )`:] }`)@o9cT@v!\cl9 2ƹ9.Kj >|C ǚYgZ9Do?Zϰ}?B`*өndeԳ1hdҕ7Q&ӛ_1ỬE4m}F }eI`/ c慜w.?,Nw rP 㢽 RVAơ>#y[ ]ήMN]&G[1;uYm讳:|5Y-C__ju_ZőE}8V ݺTBz0TeZ.[uuB^2cU^2 uՅA&%FG50(_S_Nv%tl+M^"57$RGS:>aviF}LKHL2X\2tuC+&]c_yt+Jο#'T[Q]+ NN]Xsnoc~2`7NL\b&y&W`aa  / 3Mwñ7;wüFZ"=]=8z}25 @ZX7?u{DV"־9 3Q{mqOemȺJǕW%AU^A2m>Z, UP1Ph ʹ{ mMjRНwC 0ma@bO}~??sn5@}wHPYQƠ]WY 3C%" k.%N//fc:b8gܖ(ӭ'&56z*HfլdVO:HP(Gͼ\IQHZ^#jf"ʗ$QCf?s:K9jmoކj(Aag% U-UPU;+dP߀T(OrW+ٷv wxR=3*W+M#؆§ rfC=NJ ֍y\0+e-WD?*E:2|wArjC7z[,qy6vM?;`^ C鴖NH$ācf+Eٺw׏gDa#i 73Kl%GO7iGITCY]gliQ#7AST!6cV|¡|sbV0ߠ} E@υ_|\GɲY csus'Y#k,*b%qs62mjʪK[*Vj߳ x)Ly^~6lMKZ3O, ֆj<AaXj7QVaZ1oe["+bwxoOSPR~z)Dw; EXXH1D#=\YƠ{2_o9Z?{rrA4֌U:;&Ũ}?fJ(U?m0~yE/S}*p{O9zw+kZfR6.=PWvVdNj>ua/o#]a"qCTs㐃Œ8 *j%1 7qx4s"$Em?oÿ2O0%prR'.Iy-3u=a)IrD+'ٮ-de0A([{߲\ߛ Čaf)!LdE fM,9Cӄ #|?,_`h/"ɓ'oHV&fy 5!7-D|->,_wOk{,f#ωotjîi?Np L?l`.>ʼnGVFck'v0w(sl5Fnw;4vi&삗;`jH\pGJDJW[yҚ.ث@jve %+l7[C}pPyLz {tXyLs ;M0vIFZ%Ek[Ee-O]veWxsgk-%>osl%cpR'6v{tҠ_,U4Gci, ?:Ƥ1cLcLͬcLjfVgfֳOFǾ^IUn{S9Ѝsvgܞ7γQ*=Io0g>*VMhvvh>uQGUChguv;w;uSZ>u Sg:3Oj=)X3OjSNNcPjWv6Vyve)o[;(+_`vmY?(+.(5P ceRePstw OV܊)|H8܅Ub]INIJ,H>6|FU1j  &ԍ@'fp"_^|uBߜڮ-ge:N4a{kR~yP)&p5:f{?p`OMF#.nZ[uqKCfM@HN? MIs0 aĉ}oHZ2Ifz3G'0#h.ЛDgڢ '˄߼[A/ț,!O`#1c d?C(t\k~׀"D&iu^q[s< `+ٔ2˱6g2\?}vڍ7 nBsM=ip!;+A=_1r2_is6hQ`M.}7O'o~ SYPD!|.ZՠOQ"" SowImӷEf~`! Y%38+ ERbnaC̍:Yɛw8!zO.γӫ$@]s^/ h{?݇^ yK.>WR2P+#W> ##2ulsugcN\>:=I#yr TQnXֲAe,Ț,ť7C( *0N޴""ZNmuuyc"O޼w6ͷ̿+b7Uqn)Y !{ʋĚrs~{s}t{); L` zEL@мvb 9" w۹g3;k%S-4WJ^$2II~" !^/uuAj65md-:1eÁ@̖"829.A`71e(|`ϕK:K?:JÏGgS~P aee/>:U>>jٹ*_D6`RS,j 2w|;&ӇDZĻNۖίDY1r$AwXd,KF0/Lđ|&Ao=w]Ffhy$)ߚLQ2-oBނ }#Ѻ|pB[? Bt/GHA_,goh$Qbñx^;flj2g?vAP=~~oH?xO7X>#] aՙ+Pn{?E[kn1~S:{b۟0t Sn|˜[ћXN}Cώ72q}2At#Kh>9 I;M/Xv@)7pX+fA*8nWCK[fL>܉A7΀}T C zzk8h]-2 2P('nn8S!Xv+ u#!>(ginB?"V[M3Hcp_$B|}I > U0`_vi `ƍm`SASy2$|l]Ȏ3tx~j֥2a:j/6lx{(;+=W6Au"dX6/X4KFY.B_ h;3JPKnH_f$YVvzK*բcW/m ,m6QslSB]NT{5ۛj8t'WHF$cS3w7h >R˚4G~'Ć]'+RwOHz\2I}/AQ9ҕל7qsXmKԗ`eԾ%3k|Wo4UyBN@-le kҊǴ+w_)L3^<-ywuT~0 H SrS#gt\ra :<9a7I~ȵ_,oTxۅy6DړŧEFkuEܷg7y= pe![9.A 'kx'rW~|fp ZXL[K-d`~:a574w{\V,.-+8߼_HYyIsYyO{V ށ:y9 ZnH` ? b6|v%6|H |vj@,=ut R3(z5vR.}U#O y89έFeR_UB2I%Cz<\'7>7|l W\ΠzKU2f agTOc3)DzpƱGa0W/hrwCG} m-'%MSy6aq.K(c\썏U*+j|AaP3mq0٘QSDJՆSD=Qdah;io4)f^t`_ta_`k * N4$vDy+^(|k ۻCUYա\Uա}%XHGė Zh\gd4͚пgLv ͽG]!X y/.zo+dwWJS3^%s$A\!T'5yIxi8I v҂ؿ|x׸ &2qqޜxq#-=~0{^ɋ ^3:oX;6 ,Zf`v(0L <k Maf퀔 DXhcjS/q.pL>M,FyRh8I .B:)$*SEUR+cqbh羇x}t-* K*v{j,kP툢Y K89+0YX~W?߼6o=asďW5xx`JtybR놕| _]yYO-6pvOcN Mw2U4-S'ajNVX 9C U%@v'6R` b4 E7} !"p,V jii.Dj8>Tv(>/ Hz~0)\DFCYle2_a+HX],A^[ofw{47@@W #`&kŔ8=vFB@; k JTqH7/4n&ōyr%Vp)#D7+ؗsFH YY!U(TNȾaCY6'j D>ut>& A9X.2$k@7X6ltlX%Uʽm*7gii@ 9MV ?\lI689UqG~le6oNK+lm1wdUA1(;LUeƦO}p6 ͉f]_ LUkAdV:(EhƆ$K@&TQj3خD[ly3fFE/!ȁDq;s֪\h9!mc<"/hȷMdbp X)(!=1!KuևKHFN`B@ҷ&."e#4!!s Snfygޜ 0gb]eA%ūij@~4sZ5aea @s¤x>e_eaX:AGa6r d؃T®8:'`'`Oۅ7Fl}Cm)CPj$`r4fGy 7~g|nԲbPuQr%i992KNQi#I{L]O9LQ hR)(&(2lM9#A}pK2GqQ}Ny@D]x8t)(a 5 ;1aU6wvJp:QH mv F4l7$BEՙCE))+[n6nИ&SA0}Η?|tF[M _4]8HjA8rL_{F,q[ ^,0 z`P(wpcǁCAXCLM' t Lq'b@EckH;R`~p=xOD8OdhQ#-[']^,aIH>ܒ9bt7Eo,t e!]}}v3 E^y G[+sf6bC6#e 6.GۅZE/ {ێwM 5W 2Jw/Hofx ;H, 9N|7nn>y񡿘6gexjt:q$5Œͥ7im0  8 e Ͻ?P:-4k:[ 8uwWb}Y{uYu=sP-ʉ C#,VK#XeTbb:&h"{br]x/&0ہYg:?9d.}~1R rhrP)|; Mkw"mw%ئh^"t Z,tYU0Y6WOF0Z|Dhw c"lw3{qVЋJ/'K虓-z]ix3?r3Â!φrs*;H|y >_\]IfPXPD' Ý޿_w>&1w,GT=B+.>s @=ےC'4#,ʗsw,-0S h ԁG',F\[𞶚i/]> T?G1!Ƹ;'W ,M)ٯgD|юH؈][mB_q'Ktw03>hg~Ar^ $1,H|\PƔEzA8m0n"WP mE:Fq+r`fczv@af36Rǡ:0Xu,aΩ1'd:#ifhbNINxbPư!=A,6mRٟI B"R m(>(o\$y(!nO:ٸr?OYr6==|}ۃ]s@/'rP;66P<rxށgP\y75#'DN{<h2*y>0 f7M[yz_&jMY49 3rlEI}{N4sݼ̵\~N Kfht#GxYn5W]kOH&2n <޿HHJ~DLU 4+!ID8Km o\F'SUC7btilaWQwG0.o|'\9m> M!O ⥰L 0mF˽5'{hn8{^@W|,`шd{ M0bBi0 h <LGrҜaZDވI,umXg&VZ3Aőt L(^'Nehir^*d-(-ap Ah-!>9$ݣOs/"g4g8%sn# C`-:qZ$5R[sjص{'o ,%rNeq$!|SR LB[mt-,w)HsIRXӨh7J,ES 6dV-3ޓElt7]%YIWd4Ll0ӛIYnvZ7ΤLNYa3~=] ]3 `*dy]L1&^}٥_ QEiA&{"aI(™u s &6UR=y}2 XOcfقO2_ɢЪo@y3J3#/  *1$]똀6!E#1Ok}&j?%!=Fj Ta?D&9">"y$WΞZk+$)OHG T",J VgGFuL7Y9 J{D`J|9 HldiweWGtL.*iICҠ-skboF$ׄ0ރ&N4KH%L $ֆ0fh& dWH+  }~_]~}uwSБ2N<=KI.b.*NX\rabI#OGWcE=LxT!=%diId m$x6cWHndϐyJc7,l,RC~7N%dwfz ol},80ˡ>.'}"cC&)`eh*gI^VSSAHncs*4;oqUȉ_j UgߡQvWl q9/\fj~1k#pJh'oJ)LFfB'ۆ>M/_+Q3L[q4ɕ65SD"3sFz\^e7cf B0MEaLB\t+yEXXm-'*ߓ7[^omIuLfnqTEFu_~W{u7DV S>ANU]Վ 70aSv(vDBrB%6yB4/nَ\?vo]=)P˒E~ܷSY2yw&(څ-og(g;>h$“%nPmPnT>yGt' 0y'~l۠c1;^Yנ0 ;Px6~Pנ *B{%vڃL{t[N5ؤOQʼGa7y6dc6ΙfZcaVF Mypy}6,!cڶ<@(]k+Y p0` ;FD ^iX@ ۞0 Mi\Ovd"1W~ê7ms@hshgw$%&n7"Р/3x_m4y9د na(6]\/[,FChynkJ]$nM EK!xM=-҄k - <2{jLO2eךhEOTNCQ0:yk'K\6)RՔ:vE^NXQ+‹BUpr(BfpP-Xp2˛ϟnviDBK\${tI+1Iq ]A0ăk΄KPE^9a֦Z4͝дk- Qea wfS rG,t^͢g^M'5H>X(w(j>j8twa,q"yeg0(}k[0ZԐz ;X0D.МT 4,a~؅"`^/JIa ɾ;۷2,y 9iK|gWu cM}oF`Q"QsdNɏ(u<wz 篷/gdgl7)oWW:5{d88XJ@'Gp^jSGj&?<9T*ДeL2ڥD5]ff=&8%˖}Ap'i.[o"'K͊y2z}+R3ӵC6\=~ڥ ΈZ_XCS9H ?i [eͱ8P6Xm[o9R~d#ʹ)FOH6\ ܀$q7xə6|˜,Xr!&@(D)- 9 ׀dWMWb4'9[5rB{Fe6D!J-R|+';?|qFaRA&4$8Kw"{$ qkHDV/-Y>o!NIu`'ke|{»##ik#MI|Xat]u ]i o֓XgZYMMi(·!=;$F bAJoC]=,_NƑB'bDB&ӫ7mdOB$2H,NxX6Hݫw^HaiOs=Z{/tNv#uLs4 2p'oyȟ{<`1B 4tSGC&޴3o&S}{`ymOG>锊8,R}u2IE#|".kYؐmhfp29<ӸH/F>!n.4ӝL7 r`38eJSpAҏM>BLøH ohʸQ?:j'JTrre\\cƩT(M ,]擊& kJch@"`vƋD'oD=/x@a˃y0ֻ՟( v%#ZnPi'-ؿޓĆ?$pՋ3mf3c~gs3e(=G&(?NY2(j!\$f&}9sYTFήӵCF: F8 ao/(L۽Ӛaf@,q4O8?QN} fķH8˜9)@ F y%Q (*e)~C.C>U*gڃdy)C`foFݿO'qo3e[ ORH"t1·&teĪ,M!c7L8wጞfv:zCN:֋|U# Nq6v#z_ 'Wdԗ Ҡ>:=@03v)Gȃłx"9ﶻi=z2KGbFovȶj5c? / E rOk :=+~ U?ԻۭxlH+n"lBi :erIY%Y#;6IA~.)(~o+=n4sr UIR,zR'zyZ3)UN 9$˲|Jg+Q"O(,p[im*J3*[s86KԪ[ﵻREUүMϥ_5Z^"YrG9-$~.mڌ\跆%$mTv6c%O vLan7JJҡr.nu^1l9VzDYe8{|E=U'6u77dJ K . /Bkd$]o(*BQ<[U҆}4y}2K܀5Wo/?6=|a8C@X{&U= \ 4rC^؇[@acO*[ c ▸ͮ$1PUc}ڨN6&.u 9R;MwuFg7Ϸ֚$%NPz6HIh-=n#Y<0v4:σLLH4/##h8-4`5#LPΪ&E?Ĵɣe$7CL{bIکΤI*#Zli0醧'*T (g\ҵK54N41LpJRPh X35!SMGY#߃p)I,Wõ\V]ƴ*Eԩq4sR<Iw sHn1]' (0%6qp2 8PB[ߋ"mBuk>rRffHF/Lc ^~!/P/M-sau)[h:ӧ7JΝzN)帞mSǖ j?XL6&$؎T+2e3SV8+WyFIT:ceHKݙzueė.*wBim(T@RYt“yk=zm2bm_;/ZFrYTJ*·=6E% 6lZ.>foNCkoôl鍾5:O@؂p$8a?gW˩"T%V̨ ӻnVOPzMoi6R~K,Wwq1 PsiYyٳ~uظͬL.czi*=Ҕx%7o){Q*hb3jt=i0N(bCaD&koͶv/GcCrGiX m{c|C2x;qDF=ag29 o.1td~UH\۾=2rxrbn9]FrF[iV^\$lq㳂/냖bNE=?iZ(PMɭFAf o%`p5D'o/ Cg^n.T6σ!I;%ӛ:qNM(=lo0A&X#t=D?׷/._c!ě|quM*\/\29^_qrL8u$3%Į0&0V6PucZg V;QUXs=X+r<~} \w eH4hzcJ{ j{PftyE*,w\`)5bsV_0cԗA'g6./ib6r۝cUh:BԦcyk?z)!XPRA!OOkE'ΡDҕ5%UHi3W14@P!B/;@^^}Ih'5|BZO2sxw{fW;GxŇ/_>Y)ևKiuDc }Njð|zi8 =7`[abdȭZlfsT*Ãؘ;DS[v|2프f¼T>*e$FPӄVcN|DFrpKTξL%KYpc]3UJV}v=%̀t4|8,2@[-/n~BWc4uɻBEGK]"IH6_k/J+T-MG2B4Dwf}_`zac¿ښ/?,khŋQ41.&R1a_ٹƱ.[]cƖ 8? 8o{4wgߎ3vc:/KKISsliQ*nbK{Q#%soEsɝxOI_JR3WܐB#/JdRu R.Ğ(< ǷAĻ`Yic ~lDXo~BwBmsLv"$[t~2pbDږ!91/S2掹d=]a߷>ٌӉISs\#mN'd7o'OH(G ZpT@3x>FiOnF.:)+~71#=I>@ξh='{>g#;ec=j-9^ޣ+E}Vt.4>7ncG[Pb7"EowszBRƛ踅V^CCke?.[n|4zޮ9CUڠOz!5uֶb43v:HƗhZݖn/tgɏ!hs ]kr7d[Ș5yqF9oI>B`")Z1`gq3LE8042-9vp9uňj$vlW2yopxm:)E&xtǖIiwAiWH.|4]@BMḛܿ@-?b@b$05REA(ŗ}NitB88d5r/ag pA%vZmbp@+sqLQۙ+ҫݹn0I䘕DKH,^l*`tA%P$B| ^9fL E.*EDݣGONoB?ct=^;0эmwD7JxVO;ysEeīQ"AAs .4ƏQȇeSm9GVM#E;U\U (o '(M%/?Y[I)sbkB'W>;2+sJ l*JTE(|g5roc@\jm i e\*7^YcAGW}|>r z7h5e#WI7z;`a'f{&TFcj3k6 D.ֹ TŰz) nŰ>wVq |(R"[m)"fN "X|l6+؂ASOR҅MVK܄:݅}dz^~~/<3:s%ޠ}`Vb./ }<@1(~}Jdfj"e$IoJO$ Qzn''{veQPUvía转n ;l1%W^nk-roOqkaN.#[Սjr]Q.u9u=/үQ-%Qxec,ma/,f V+AQ؝h`JmQh쵺= P0;$iFW(If$QhzSet0C[$`,\0;|ZX{pZ9$vLn1dB7<D#69ÄPAؓJԫ\7{r{ppxuk*tvWrgtaR5ixQ2ʫ~<~v5meS3-!~qҋU+^֗'*Yl~ƦkY6*<G ) v9C2K Hɖs2 9ExiSbn]B򜐐rN}oǒ.L鸓*sw] {XW=;T>?xi8`* =}n,8)ϙ,dڏR[-),ϓI$}%^ Yij` EHi9Tg&2u vPWTfꓪMVsl\~Ӳ o@c[#?&"G(+XůIa+Xb;bkn,D%$+Wz&WiJ؍" <4nV&I>{Ѧ;>R^QW <,R$jKz pBŇ$Pujp7K;]&>:u#kLLxqtfȒJ8 "[׫e3rABHK"ridҙJrWyq=e؛f3ICc w*5A@S]<lWcvmCں =?)T>CpmkHHNo^.OZ `,h 3it A㘴@TDf!%3LYeR98n>G ŚDgA-xB <_'tB4:A&;_c7d߬y( ux ')|E ….Bl3-Q&bp}s9L+#S*Kc9ȷvXRX;)B"񦲛>ԍ#Qp5IDs):'0Pm~×w}՗wjW/,<ؘrdt02R\V 6(wgAKpބ]_/s{@;VQ ҧ&|, x`x Q6i$N  g8;~H7Y@_'KkJ+XM/LSL>"vcԛ:oF*c_'3LnIv7["XaB v/)3nw3jg2 y9L^}~M`fR<fbUyÆZY"WxĊ9lJ֔oIv6eۍӝ0@lQ"ʹW $;gҗƯO ЍfwH;ϽCcXQ<ZRξSK4G7k,`:}Pt4,f5 T'^E/NF _XዎV5 ,:4,6֊r)ig͘ҵ,}Q¢aU<7kD+b,s1F!`%|,%9&`$mj o}7ypH"^xL7O /rTZhà GL Q1ڇiY- 1D;\/l̅ę4q :1HbzPǚ ~Ui7b+ř D8.WK?[[<n$kdawVxxٓтoᓬy#`NILUK]wv +hZ/RiÅ9h &qh̊k0j&DZ+s2Qf(CGN[g_fɖO/YN3=@SYr*#Ziq%o26lghoѱfIm%x7I.\>rnxd:p+CǛ__y*ac>-hlpq KilI(۫YNf/\{XbKpRW&+U/d#d|vAf1뭂ٜ7HVr={vƺNTTEF!LT Q XmvE~5<6Md5 F^ :@ػ߅W^_ԯAQO&9zo.!.i/OhҶX~Iwk.8>W|: [~ɔd2 }z*sQ63''H@T/yQ3߀Ge\3nPt.@ -X Z; U*^fZoe8ׅJ'I'(TPN+H['̀ОBt5qblA+g2.t\c" l,qvaUom_Q7gAjCB¿HԤ&='ȬD5>63F|=y_m-L69CpI(ET?_;MX%wPvGK>hԘƒBYW2rk@PwbR'@lQoUlIoU/?ڡyXߜ|K_Z","s`F A%nΡ+eq-jz9v^rsr`}7<ՎItsۣjA)_T.PA|xJT܍xa=Jީ9Ymb4ފʬ؇. "- 2 m7+g8J&kpn}Χ-l̷)(}tX7!9 smm#I!{%GQvVw;|ÒwcbEcdռr$u@ x)bz,2Q@G}Ž WJD)__S:[^eͯ3qr UN5@b0; C|\}J-ﲇ- y*ix"-Z$/ I`IXAw!W+DlSkid-Q)lmCmVܻL;ܨ6_Lk.!2eZ龎SB]fpnj:੷yIv] +c]4̑MκobJEaCwgXP;|f]ː]ֵn/oK;8XWa¤wq.ĎuxGooz*IQ<ЏﰉTl*~BXh~7&FaH5\_'MTg@g$S{ [OGCfEFmR$᫠>8HI"z"GJu};1<7;(sqB áeeDP C'oA1ZG?]d߇v0>?q]Wwއ0ZO0|P:ݎo̹xq~LKN7/5钜ǻؙh$5~?l?7qA /:tZ;cP2)ܕ٠cd`nC~Fq`MH4f?XzgF̄W9Rjv5~>8}mkl@w:w6nZNB ,9Ywr&ȟF9+\v%hjVJ45kN3#ꭦ&PܿQYu>g: v [Yj4ZxEe2z!R #G (ޖM1oxQs]7mJMhv#Z̓wNlTːj& Y4u'O4.^լJFJ@Hc1Ms(c(TWۘ'Oe'V 3MVIFG$4Aa}}X&܍h s+RJ=x)-]q* Vc|xaJXhȃ};gnc4rQ'էA ,d,vMrو䖎VAr;>`l@B[ژ;gw3CD{߼SB`9,L#= :1c9ɹ/^rqDA %}ϒoi."OՓ-6)Q5++;R6EMP6 c,xu[5IOccg%g 8h^0d k:x@!#o2$ e8C֡cΟ0|q)Z-qyn Degy+Ν5D9`QdۑE$/`g$yrfHx]|O˯`xlAj>@Xi ;L87] OGϺ\% |dN*NnslsIYж-2'IxgKɨ~O?os9ϳ#LH&t[֖H>X" b$GsMy㴓 Zǣqp~^l5PKVGp Ko>d5%.zcJtwc!Q7 +7 ^~|&q rcɺ(+k9o(G|4骩F)r+P ɒ7ߋ. `)^ Yps=+|'Q54 M%çCR@vRag/eN܃ \ޗ2BXѬLd zb9I#o8E['fGٯd݅o(G6~KLXxl{tl,O\.$؄팬u\5a2M;<&E xЁŌc" ֚8pJt7qY̆$)u#(71S+v!cn"g⩺{N<[A+xJq(#mبF0>V!ĉE^Cq#`2gO+$ѰJ*Z6 )ZGĜ!#\_(gĆL[XRb}au5 {)7k9!ZL&#c7Z)#>grw=׎)-OTr,r47{hXΤ; #y*IBtsdJ/lF7oZ)-y1gR $-vuv#쬻lN̬a5ffn~֝|/:*m^ͬW(L=p|)kZYNS׉xgҔժFyRӪAtnM_HjǪhqVۼw:veN=kiۨ>N, ϗoۥP(uش:j$ Zo;ZDz]O/\v{E{N@U}H1!}.lZ~81Vnjw4nꮩpƻy LiqH)sYA/HK>YԶ҂KU64_Bb#R;h F#-m4U \A/)-匴q@[ S,Qg˷OGK+Չ(vL =n'f7q*y|n pr;{ғ-?xNytDEW#{o~|Bb 9*3.)s K;4~|[Cj>snS0o?؎KS/vȝem0-(py' CHg{C9S3 AȏDcWV/:ۮ@uQfDBP̷EA#X^a?赧c(w2nAɃϴ5鲪ܯ=I#{ۢJ+7*hmuIGA=` D%6Uϧ>6L Y\ |x^GX#6ޑ?Ĩo,0aNN5_,b圉-}4 Ų<ԫ> q;/>(:>SiN%''[E kGe߆e8M Xr>_~WF+xeVjW2fV:{]8-)|qH1L6TI=%)>[OpF$f񢩲%<('8iaM)Z|cᝨJyOzT)|~bMϡ(-Ndl?'JhhNk:GHctMCt<>ORY1/OTF覵gQ)eg,R*B$ǏmWs)ehEXApJG# ,)F)X1񓊎ߏAe<Ex 0g r|+ $%I/v^بlW[etO(ٵٿ/4BUzPR e=:y؈OҜө3,{ZH" `_UGTjɗNN銕aΔ2pȗXC>A f?xGZ$A558IC cf#4sH|+ƺ m!a@ܗ[˿}ur7R̪  zfîP"0'wutjjhA/EEl> KGW%E)okO° g)17fBqMS3Y\JJn-M+ `UmFR9.JãdjOhljϫ7.HQzoZv΍`)԰f*gйAUv-^ T;"y.rׂ8_nR8{Y)mUJk}2{Ml(mX"\oq VJbkڭ%B@9=2TcCe+hs@FCL5m _.)G[ש/xm^D6uCz@Fzo~uf%I5r~0'Ew^ 7u /{믰"ÊXo#nzsΪo [HlQëuo~veQA_o9]!^/+*֧kT$aYѿh,k<f2PYX|BEz&%x{XSgI2̉NfUS.NvYLOǒȘJs3y"fjf84D^v8O7*aV@i R)*Q`ApbpfJ)7^}6ޑ!g$ܢ#UsFڼsҹ9k+RQP'oޘ\Zܨ)BӢ}EOemڲw1u8cXX8D\4r6*ݼ%bbd~|*ĢhliK $!n)!icMq"'8[Cݎu@zŒbF,8 `0+'3 BB'1̭5FsJ{0T^$0ds%4c\29fIBkԇɛ/A$VVv6m=7 = `*J%,b >@:.0F#F6։}%[>nA-/Vل bwZLX?)c7,/V/% fXi7 :笣LZ!`Q0̑ef ~d-F K KhYr9;tK>Am"9WwmM. (WJjJ*eqIߕ>aLTYLtuynI^*@X'F t2}Lg{` u2(Mc^yƶHʾ1_3ڼw?<ʌKf) qlQ"qcاy&7Q,@Feuu6zW`IUNVyzb9Čjܯ 5wK/y+kb@?)mІ dyYk؞L] 2jN

f_V[XLlo r?1x|$/f4_ C3+8}F3GFgKdQ7`VxF+{0 E -,,c?a[ΖBgG~4BkծVћQXgdp(E\_HܑBKfd\Y5D.sLv|28(5A4RlCْMUd5rf'El?N3ah?\ b{A`=0;gs  ެuͳ<7Z)7jz,KfG[.T8V:=oZf4`Wg-c~LDf.e PuΚ<tf84g🳳zֹ6Zyw?ʝ%0nKBRhġk5snm%зFo县Y;,+4[§{~>p(=Et,?DuC]pYX j9huZjϒIvvY7BP6*1j!-ai WK.ꊮ?UR-Dl4J(P^cpʴ6. ZOd@SDgމl8FAv GsL%KI\I'a.dݕRs6͟R~Ph{)k˗:R$a]BI{gUCꆔXXR5r<+ CBV,{FXӲ;Gd]R+϶gSJ–sx X]eR#Zt=;<?W"F9];DoR&EN+bG;h)#{ITIY LJFA (?D)9E9 p(c4<PA&IN/:'֪y8Nav上0$[Rݱk<Ɔ| ˺.,2SFL4Oj`/nSsb2xq~LIJ#JمNTnTxhsKlY<%C~r`V̆jY&<͆afy;Q'du(>}Tˀ! ;ZL,8cI=ƙ#Fk[IEӉۊ2#γ}6o5y6LIC&]KK'z>}x_]vI;`}$o(K# (%PT(Z7, <'b*R,"=~~LRph评_=!QMj#b,B7p(P8|j<(F&FjHڄ#hhG!WbK\s9C榬4/=:S(m iuT/:7kVj>-F5,L~2Pbڄ4rÿ<+AS=Z4x":9#"eZ;IO!Iʴ%ն)RJַ KY@#?`z~G4mТO3siN̸Z0ԏ6u+o36A]4HŪ%gq "gDy:Iʔѭ]hQ!L6ohyHͶhD7fD{bB7Trs0N;t}tyެB%?s=B)wƆʜRmm9 U PȮ̷c~NR۱mڎf{34#v#e>҆csqNz/'s[H-َc5e>fܳ&Q9Ii ؎ڭz^z[stٳڮn<rn8~*ި 7>o-sQf{Qxtk]ެv3RޡxhR9rTT=oRJ:Sd\% g[)lߚLԾO^*q5nv~I83q؏]əFRĝ5m/lX?a>F-ݸw;nүwaA2_|&%:.c᧬!}4gANiUz.9YO*1:clH۷`sO\g@=zyBɑt>&G$m3|⚢rDM?ݸ~/XXOǃ`F6`fz.7_o?^Aa֙]LkbUe9g% p*e8t*5NZ.^ՂFdhOKqOdQ WhY+CYy 8ip3?+Tgc0fKK*@K0N5r͋rV`.%p'%`XeOїkDMc:QUbNJVm]CuE #A0 >yxNFaQ R VqI3Nu.1͘󨲇mP2=;Y; )-.5ܙ[PKj~ "B`pE}҇ނ ?KbbUo?VbSx %jf=xs%"|Yt518#Ol6h5!1G 7tA;KͼįF Kw1ư^s;G44j+`BX.=`B:{ˆ/$w[3X}d=x{.WK7uBHvc*-EXh|FHL}xE\e-ڣ Ol v6+ H$ $7ͫb)i;V?p(I`Ղr&8l^Msw a'a(G~aNdE6Ղpk.a?, Ac<OJ@]5:afwz58sۓ@լ/p/n[IC^1-7NJUZܞ·8,vѓ-UM$ At"vt.h-{!^dK̙]ڡuAYM82MD:C}]Zs?M}=j4kA}Ni>:s4ެ(iJeO.+@EIͨ -ue+0l,]=̾P|i#us[P H]W ]tsp,pRORcNޕT("6H6 4~(WCE\fy_TLKu~nx=@neകe4g6,kƠ^`dehZY49A52s}Dl%)jb>"PW_x{((-Z<` |) 'gyoˁGX)|2bBo0B˻S'5r5fkFPĜT(˃_,>S*r{g7% unt)TLK񙨕."8.&N6X[+1۞ 56pzUtbӵv8ɛF _"\58}f{4z4VE:^v?lW2F!Ʒ΄`]o9  b=˨iNp22V!/ssxpB6<5ө$ ~lܜ[m*i l]LA|=O/%`nm|58;D"vpԃlUx^˥E`bd6H[cRɑL?\ 7olFH2dt'Fxs!'#="=M~_X1Msb;^ c,]#x(NSGa 7M `N DLn '}Vh;}us AL"|`:=ްȟE?|t;i UFaeewtw]uӷM8@^h{~9-fO՟܇m!;Mjcv ْ&^Гomҫ'1S|[qMi#{CEH (9! OcИ!J2}C>D$jʐ(m+A|Fgm!(t[K|LT#Q *RVݱݛM1e CFgԄ`6)=-\6wk4"d3z~7xQaK|?@~>`eP%N= R==Nk;)7uߎ|Vw|L%:]£SnA昚AS*EΏv/nWxMҢ?"0YTEfr7SX=%| f"pI2oVˣM+rsoȽIb-)3@?p\2r{xj[ ܭy@Wt;+ѣBe ,QD^wO׺Ax'ɎF2^v;Nx飐B'= 7f.{G Cd٠J-Nzwr!yG%lh2T'^ vKRsqrct#=%FOly@#Q (7Ǵ%K}%b;N}jH;©%'uI.JF&z>?A} !#,|pn`3i;9(||&z`_ ,#a"(ɂ-2RdN{6R,Qs)mqzLa Azkt +NB%q&K8Q~Կ\n%v"c?F|a2ҧTËfml]AnFX05qP_w5 ΉCANleSkŭr @wȵ-trgX+])e&=,_A$LZ1 bQt@du,KYx'?*(}i\X}ރL=)[Z|KJ(yXk1ꝖbE2^T8_JC,):K5@<̜& Ģ(zC1"x@2fQ/H(F&Gg]vF#d )*,UFg4oɊ1LFWn: w jR0f 9l7;?41~{|r =zn1D7SĶC I>\F 8 ^f3)5#I22Os.pVCk6-C nnق|#,/> a- hd7/nѻB?>l~o=09\Tow΅ #VF~)bm\1^󵨢j-tVα֯X"FQr)kFLref핵^eǻVk}vs]c4*X' ,tHGzCDTaz&">0ČZ{՗qg1C7x/G?F1Uz4BVN%Y|š3Tb1F1{̻e͝4UvrJXsflz+kʈeW91xlcv)tuL];b &aԠ+*<..Տ,؎S_,EmbQ)p0TB >r!Y:*(f }'x0ӆ6D,!.6F x: ͇~2r8q!BX$v5U=uT8sSS+A*@6l;YbR+vT!q<\uj&<^ߤ=m&Q Yʈ $gVwSN;N<1UA{"Gj1b JO|PSGZ>摡ꡆ 0?9Q61.$F Q6<o;+?x XbBC0v̎g?84 Z$6r j{⤷hdk 8&Q%G!` #cTջ7k "+zP12G#3VQ]ovTGy}>_F ,,/v0З2[\FcY9 Th `KlӍ7%7Vׇ ş׊(QqL8LU5Xݔ~D: >?+-dQO8O=YkeyYq缱.hn_j9\ y\:w!ږM1T-`^j&}'ca#5ԬZ.bMgB b/ѻ..?^v?i: $I>{P7Qo6슞eJ$ $%<* fxcx8e7>ӑ9we}/' 2 c/zpAl\7'CF r`J ӠwC) ?o>9~JȖ^'=>9Aw,=IeV)A=>| ͖P7 A!qyF,:;gv&yq4@O p-+ C~j,g㧀dXjh2}k{D$``oSgyVXmf}!/* ʪ1h2iP9!}SFvQ)ʪFE~LDԞHρ"q5_r'oL, gsȓnoڨ5+ 9ŸEƬ4;+qBO`d/J ;&d+ ᱣ5DxoP08%?ZdZy5"0Jka9jؗO7ZWp=6_sgVS>N`d7=<ىGSEr,J2ReR;Z67WBi3޽$tU xk\d=8I>a5aJbxDF͞}I#!.>b=~'`,xoa`82g%`hf`B=Fĺp]F-ToyZ}Yj%2H[4!ɼC `~''Ig@ ?PK0vPK.2Basic/Standard/Module1.xmlUOk@~ qLOEPI z\.Zޛ&߆~4KbP\7Ru1^/eV $GYzkz2,r]7ʴG|jXkSIJg[6M[s"XTÅԗmPQq AԿ !sD2:2=ePKlRPK.2 styles.xmlrܸ=_0yx$kI[Y{*X.'3$X 8#1?_H 9݇˃nF1 f9yӐF$]ڟ:WwG.$ Ss~mَ~pAbQr7o,dmيY#f6H xk9Ϯ]Zs ~!#ٸ .cqZ]Rq~w# XXw/gqrZRD  BFxo#* iAG'J4qVunU gSHxk3$/B"`f.3P¨ 0K']C\NsmT޽{sgPIT^\w# zzTYo)ƍl0'0=l^UA դznP Fsrf@dܝ{/{e1h2ܕM2Ha0[ᴀ`)牬>KM إME[49Vriea`{ۆ T(DY}V9Y>AOW@}KYe"_wJu]KXrPZex+Hg҉gH)ueni;^C{\b}. \Oh"c=[\ںKNj}WnF7A3>v.iOO)42$t+{^q֣{98z#EĽsqrnhu ./WB0pꋅ=Yl|0[M 2e2G-cJ2}q}8 ǔ@* D<L=ƴ'kO'PD L4D8p)/_:,{W/]t_I# dkgW4rX%llvK}.ɪ`s>~1?4Qp9.h Ņrb-a=6 7T#èq)ٕKVUņft_;BSk,FX{NVRs&IB ]?vSqg(p7𷓠\04%ϒ}Nw:CIfR"ٍ?dvƑ~+})V6u>>fjnRQr\BW)^5P~"ν -)CX(V"X:U\_<Lj[h0f80 W&:;wi'Lqgݸn v> uԜ+{t:eݢ/Y sKn`"aw.<zYM*5ZJPK6 :PK.2WC88meta.xml OpenOffice.org 1.1.1 (Linux)2004-04-23T15:18:432005-01-14T16:43:55en-US425P13DT13H29M2SPK.2 settings.xmlY]w8}_uObCiR$ )!x %,a d[sh\|yX d ~UO Kmi_\پkfx|=LIJlTn].;rQooUP_/Rg]Gf6Ͽ'Ir|diV_]"?ye%7._AS<$@K|H^Y~2QG|FͬՍ 5{a;Z]s4a_X]tT5;K b@kI JP\5 r4H"({yÛ|/}u}KPN(IF WUcFv =o!%jnӰ-S (Ds&Vܘ,^-zCy%T)HDU&,|c;8}sYKnw%PB6Gg,]ps۱f,D dx]VH2U䀊w1 e/2ّ RJsg \xʊXoyYi L0ȽC"87}N3/ݠ &+2]oBAk:_N- 7v'۲c[c3zn&ј?tamn٪y,ɪ8>k S3LOfSfa@ FWwj5;oVtJt1W$ywݏs52gcyu_35ճ߇)e;0M< l,΅z#;l5@"ǏzFKM[{lxGi:M/{|fݍW kS`7XԚ|ۄz%wR=qsm7 ;aPK^;ϢgϽZu*tp3BC?uv[g0~PKePK}.219mimetypePK}.2TF-DPictures/1000000000000249000001E26ECA3CC2.jpgPK}.2ڣ nlayout-cachePK}.20v Gcontent.xmlPK.2ʯ Basic/Standard/Module1.xmlPK.2\+Basic/Standard/script-lb.xmlPK.2lRKBasic/script-lc.xmlPK.26 : _styles.xmlPK.2WC88tmeta.xmlPK.2xE< ҥsettings.xmlPK.2eMETA-INF/manifest.xmlPK trousers-0.3.15/doc/LTC-TSS_LLD_08_r2.pdf0000664000175000017510000145364213663651711016731 0ustar deboradebora%PDF-1.4 % 1 0 obj << /Length 2 0 R /Filter /FlateDecode >> stream xSj1 >zPzHٽ>BsWAÂ43ZݼKI*ةtUz[nOeZ[[͒f !-ߥë1ZF+[2)/06grV,tA3Qfo'TC1 @?k k*y',hL+uam#^Մ8"aE޶6*ӿʁ5q!ۈ+%]a DA=.LPM"GZ(FO 3 4.<0!Ij t0ղ(fa<ށլdlFi20Dq9{Qg.f{-)-~[>}0Hendstream endobj 2 0 obj 376 endobj 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream x\K$7a{SL0껡a ;T*'evͬ,s2PF5OΚL ztʛv [>/G>br۞$iO.g%5Dn㵣%WxY_u*֢/M4bhq4h3kL;'.5S4Bb6DiDJr]r6ڈ5AGKrĔUɋTr܊vx~ʢ%+4jPݏ'u)#kYƈ#F22 &tHj8g~nɥD:7IHF7_/ca\`1OIvK|݌7u9X2eVY@Dz:sBx#w N Fs4xaߕ$ cM]4-6Mx=Um=s8"8Aa^yL_;D9гDth5ӶZ!5^ϨU7+]t68kt ~PmY J7GGmg)OSS+ `pفmzJ+P9 ~:Q~lQR:u7~01׶2px'x3Isl1E|-sl~OғMJ-P1VFO3Oֿ&B"N9uqe N_41N_I\F9aF[ZU^ Yzt/s=؂f>:s}|z[t ID=`%=݅0P/}#I)58汳kHb8ޗ4ШS=zf\/-*yQ%j9a<ퟹjn2|\\iP zVA$UBLes803Ssĵ)}xm,Qu3 R j | c%R\d ;@vgY}KC\q}9Yj_c+πT{׶n&lFr2>03@{輒ޭ~`6ީ>-rU{ď"`{tn=&\sE]GvަJz0VbsEU}!G˳%\l=:+ƶ!Q$(f=& T0T{]%0.7-3ߙ4{>Gxir\VA߳m剎Qΐ,lv3B;TdM Bb}H :N2Z)C?xW ANG/.?l2WIN¨%]˵7ILRkIYU*{- |>VI3*:j"W|9J*e&K_{Fҕ\ɜP^Hf\ף2})O M!|k%3rKTk)lKS gd3nˏ˻q{"+٘oLYkXs0}ywSeؖu7+4> stream xYj$7}d*I,3s_0,^)UU<8jR_LJyq> ߔM0Z}κ駳NO_yza9DN}5:yqy]tĺxm1"ѯː<5. rkA]WNW, …xhHOQ9?"`q²6/t5$Ϧ+xq&::c>Ms ,F uRٚ/RAJ$|!6A6}^ݗWjTW gN:p*dȢ^XXE%Iur 4}*0fXcۇ'.,K8"źŷDk"tȢ:SI]`ʒO ?*9(( -E8O e![  ppUsB2/[vl*U$lS: !$'<:*E! F|]^(U[ӓl*6+2AZc: 6*HcyHj3Rc1]>D /J6 KW̎Z1;PAZTT|mV2V$1H_kMCYfyzKGԪK:]n}˂Ꮡe^lQ .C<i0f0V(" Xs]% ۀޖ t|:nJWTFI %CGDiᖈUR9NM jhҳ{: +Ȉj»$h+\&nGǫ:ȱB uX `Qh$㊆MԘ)Wt,X&I,XVhM,i[OK,["_/#XMTkZrmFޫ]o&KK_m$ԃ>q\P/Y<ѱeCڠH >Eo[-Zw9@$F4ά [Lsvmxy4 $1GV:tN[(}SɩR?pK[>zrm0@^ư;~$7wۚ&kp_^xZ`=ܩd0$#bd/K3W2kNIڃ> stream xVKk1 /Щ-aC!{`\+gCے$ٚ?ocG;8+1}_/̯i78/ǃc7x#6|:;\?uǦ ݴe-tiMK2@Y&7[!r{C851E<] nko;GtQd8b [P´Q|E䓦8A@ߏhzChD^XkĐEe'*\ OM*rdу&؁ ŘBTbo]d$e[EasGHQPL!$쎙ɖ!!u NHu”$s@ Rr5lbjI $^b֚.iQ`ղ2/7e7p֗H%MkҮ$37\IzP;h_ [95g|*|RY6E"v=$&C(ﺆOԆ>6  OuB EmL`mZ˶wqZޖ :6Y;+l\mkY.Ke78KZKKcZ&8Tb%'f$7II7Ҟ8M/밠%4n tZOGճ fߴpendstream endobj 8 0 obj 703 endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode >> stream x[ۊ$}gG*n€?70Fz;#NtFdvͮe$(v"-{]e]~%;_[_w?omO/_?˲my-./[~ ?>l~^?6V46ׅnc\̱nþ4=6Iȅm\U@)^^bbVK3EGbFm~M!_roBtL#0aYZJN#_hnM[)$wR}7%W M1nUBNi^lKd@Kn^ %*%? ]G8e.Lʃ5ֱeW"n4φ &O]vO797~4BŵooAP Ů`xFH6^4HJKe`/%s|!bcU9}޵X4ORMe#5lNc"n4yXv(c2' 0t+{ "PS]k^NQw3[ RlĿnV6[EV B&}HUgIoLM<"BZ|#꼖Nnd'3(F=A+ VGG&Vj&hfl7 Qb$+wQV}ŃIx1Œ^@15+ ,_찵C S'1riEk]TS]h0_M)WIͅ5rU4ZbĤfQ^P IJcO(c' C)K cCo|^yֱٓm/껇p,;k%QkȪ7EBA*3PEɠ$ 5?\̈nHR%޷ Ase6?0 .R#tBll΢'JZޱχ#YjS|٘RӸ0LQyU 8V. ('AQX7{K2lmpX1$Fc"'Qas=^y1qohlWx76VZsM7MtQL ~e}vc%  0E},5|[6Ca}y5%}I͙~D`&腕w\x^9Qg֯zwi+I<ӟ"t6`oբ 1лGX){pCLtPQ]#O#_nwny!!e7i'hH 7xB*lM߄knS3~D#_jŭYUP?<)| w}ki:? R3C/v]w~*kUp=Ko3,m@V28 i jN^(R}L"w 𤫅Zbዳf TB,M$]#"[I#ڳ75ڴ{ů`/!CI :655K1X _}]\lobhZ T_O/G~M}PJ&|F|dLu:&fO%*U?Qendstream endobj 10 0 obj 2708 endobj 11 0 obj << /Type /XObject /Subtype /Image /Width 585 /Height 482 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 47555 >> stream JFIFC    ' .)10.)-,3:J>36F7,-@WAFLNRSR2>ZaZP`JQROC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOI" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?&ԧg@Xƛ?#dJ3t?V٠3?g?g4?Qh? YƏYƴ}(3VGVG?A<#fxG| ՟Gh՟GkOG٠3?g?g4?Qh? YƏYƴ}(3VGԟGkKG1"3?<?Qx?Ƞ 9Ə9ƴ}(7NN/կXs&U}1?mVbOgXգR&b֨~i(X@TW!w'WyGLsgImwKmu =!O)3r ݾ弽aw;}ԱHD$n0=5ces^ūk0lY?秠j9c 6ϡ;&ȞL>QEtTqHD$n0=5%QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEbO/?}?aWϴO,WIo2;4qn ϭciCR&)!_b/8L9-1?mT'[W)@.Yce@@`Ͽ5k[;=WMo!T6OߑI@Z<1"^P @|;M5 rp/ <zyjoi `YhC3n8u5_ו=fS'נ zwp}rư1.S=1޴#Nin׭b# \1~㥮sC?Xxoqlrayo׉' nWF,I?n9tzψϕJUMqs[%BOPclRUps55}`~@5'#{ g׷GKEs~+7*qI?J_Ǚw]qw]ǭxe]b'8v^zR` Xqzwk'viySo 9`J}?.gɭxXy^f]b8w^:R˭xJ3FfbRGbG8KyifP{ 9Wcw}MG%I#:Ь|ch?M)o3qܿ1`0Avsæʧy֫ M+͉č|ɟutjshRJxL*4(UQ.0$Ppm%)7ЯòRc ^+,KXn@UtY HK*coJI%΀s/4'&@cE]2*2ۺghGR^Zod(R٢#mf 'w?uxZUM{Hgiͼi^&IO,mɆ{ 7zNM^fy(|vUG#M lԾF', R} ?8~nyG^>-B;)wKN>}/@K746%Pƨ?W'rd_G'rd_Z?*?=zoG4Am ;W~/€=M.YKHK$Ҡ((( I}?j>٪ȭה?'mj+j7hGyC-[H(+ixcEm# C?k֝WmYT kCh((((KoZ?ơ4pŷ[w[nI,7tluS'׮ ( ( ( #<5Yc5u!~KPBǑ䎧vȭהVeEm_((5&B?Uݸ|ʄ <[ U彦m[~~umm?/V"&ljWO@,.^5bc 1h<34i"}46tb+In^YzOu_'5((hidqflt%AL ._`I63t}NZY9r=Irmmyڸ|ǎ?:hlwLnȕq=}HnK\#I2 AϽYh# %CHkO\?z/+j7թY~'[W)EVIc.fFFӠ 2GEe`mKW?]5Kѝ5U: j+ I m/ g՟? J+%t[fUK/S~zg^iqhfǛGiuKp2IɢXϩ?%q j+t91֠\g jw~u' Կesg=/\uV{M%F-ҫ/+`1T€7¾$/_?{ԿJ ȭה?֥ecEm#((((yfk)}'mj+j7jo?ڿyM<1"^P G?V?hGyC-[H(Fo#Uy[sg?zмM~T[w@72Ã}"u6{a42]` ,`ro_J_ ^]iX9ٴ*H7DFy8ϵAix>TYwFWHQ *1)׎O57 ]4ΘA¨RF:ޒAbz$E*G v)1Yׅt,u fdi"8FDgx?}bT𭅹aԥ6gwL@b񍛾@Zc=ݾnBa=wsҬ587%56-H屳cϵGm%%OG>Y$kY?CCkb3$UOȿƏOȿƀ:zտ#<ՙԖZ֧/Cl IX&wѠ+GzI^^#GK褠aGyC-jV_?V?kR ( ( (1'?j^٫ bfO"^S٪ȭה+ixcEm# ȭה?@Zzv$^iK+Qv޲N: ҨW}8^|@Qo5c"ZL;SE9LaqAzq@sZlmؓ@5dXoP@S\8fS@ $a@7Mf?^n ?hcPs2}M>*iUfsrV/+i@?z$?"c]<f8t@jԬȭהVV6 /ڗ'ydx1h&:uɼI[wG!:Ҁ6k[oO&o5X$ pxҭZi~}^v5xⅵK[o&{v6̛*rw DZH (#rNsSV sxÖS.hE szvc秾@{RGڢy/boG"ޫ鎧^Ů \Ķ[9V1=Vr:#wm||sZcWRb+f 0 ;I Yn[kYx^v^oE"8hSH{kThavI3U&+bH&IM@ʪr%H-icScaȵVOd^ #ޥlRWׅ|HR_)(|1"^P Z@ZԠ((( I}?j>٪ȭה?'mj+j7hGyC-[H(+ixcEm#2ؚkR(]*c̀3=9=Gs:x9Y l'Zقm,پdb@ =MVц_gtٻݷ8hQY.i:i2}"Ea#4(RqQCΝi4p.ؒHcAҋ}'MhHcvʑ$z5O^ccr@`Aǿ5% ?闕+t{.yI-3 rH\  (NGRTJP-Z x`vu e sʥM'LK7M:mdm ¡\`[hM=cdF8 zP.+6$Y퐖''-ƓE W:ubI V8PGOJEgi6g(rlUާG6-ETOH2:[ *GB(JO jV^!oWI+j7թY~'[W)J(>$ȉ/1#DMKԮ9may~/IEٝ~F6R@j^Z$Q Jwz$SX0XmY$UY7`c&;skl`mKW?]6R@)x>hq&B{>9OGkGj" ;U 򤣶w֟ Կesg=/\t^tm,h]HC [{ct<6HcmO{&?7$l^z?u ~ר *6,ŵ_5O@5SEm_ [H(+ixcEm# ȭה?>xwH~s$XcR_< I$*VJY0 ~[Es'؂'$lm\օi‪M֥vAW:c PI~r1`kRd669Mr= P,'#.pO9ԽRv\^^<+4muH̟Ssuڅ{iK!0۫1zP j^пo;Yxf B \7Upb;gEWp й;CuRj^пo;G v)'$u : T{B-ڗ/_֥m4ڂYivMsr;P}<07`ab(ʒ@ڪx֮]\EwsjryGʒ1p~cPGhĒ.u Y*PW #4(&VynGW1α;w`(O׆(!54UpzYG,`*jtϧDybXhd(g'A: +X4v ԰QwoxcEm#*8HbHE4P0 915O^z?ڿyM5YԵ ].K|xHR*VoO(3?`S//G, W%k9X>K Ÿy/Za.&rTWK;Pg, W%k ^x[moB/:LEs.~Nq=NWȁYSO0H2=7qZQxZ[)H,D20A993^{]Ol0 EF':կX>Kx-$HFp~69+ÿV9VgD#ufE<Ϧ@|)A_?+5@, W%jΝX_by2.p <@kzoO5jW|HR_)+k¾$/>[H(JGyC-jPEPEPEP$]_>Sv5|@AO?Vo5O@4/n ~]hۏ^xcEm#]y Kd6RH7;0A*y5xcEm# C?k֝WmYT sC/4Lt6!:/Nsdc/l7˟ ; qf~?S߿*GҜ0zڿfe&,hCWg~6\m9ϥttZs ]_M" r암Q) H?4dNRVYq~wwis fdB37xvS?բW JQm9ЯQjm&C<(X`WF7n(-Kqq);PXDzՏj¹Ưa١Y3p3*wuW^wbHNG>f|{`@TxCN2LI,zl)gu@0cSNSOmi̬)\QS<Uq%,Xd*4]ڿkb0|,m'{vy~}+}A~w<Z<D쿲?yi}v4&|pKfc(ݶ}MXђy?m Ii-eF3w{8ֲn][T"[u%ys+1#C G^M  x Vh^e~Rpzxo#dDHq_#3QIwbpHHwqy$֮Ww2IϺ/nʸ?4wLӗMO,H,q(Q?3k?75~= ۦ~PjVYiZwY|F['dt@TPu&vTdp#<}+y xW?mpհppGqzE΋v3zImјcG=1F$- S!qf"y+;-VMQdvH Ԗ.i:i2}"Eat i^Y}>I$bl=I8 AMNȖO:> 0鞵NyaLԴ\MS@piƓE W:ubI V8PGOJ-6)ӭ!u*Gs9z5Ca=EbO]fŠhʒãGKdHAiPEP15O^z?kO@~'[W)?m?:FvO qZ/tOx\ Fl~\v_6RG ԿesVvn#.jG=QYi~ k/ڼ"@<GVl綥+.? xZx33,эeqs9ޥK|6~_8]:կ?{j_2MLFѭtM62q$޳5jzf0>ʳew#ݪ Կesg=/\tƝI5&HlƍܻlP"[qHi#e;vp Կesg=/\tV / cu %n%O\9Q6SkkLgFw) xjg=/\t`mKW?]PӵRhCr &C^1gxsz'#߳L݌,yYvuz1L+FЦ+m$G楿l,~Z;<7Q"F? _G4i R4]7,Y#hd{,j HQ?ɴ6|!/H _' AK/+Ÿ/ _5Y' CBNѧUã̄zs{P[kZ })cFNN>'$z/ k6itxIw)teg+Ÿ/ _5@; AK?#׿7T^xSKƨ)BPTԿ*O={zI5^W?^j+Ÿ/ _5@; AK?#׿7T^xSKƨ)BPTԿ*O={zI5^W?^j+Ÿ/ _5@; AKss=Ou<$Y+Ÿ/ _5Vlt #[h?-M^cAǠ64D]֪":ϡ(((((((O jV^!oWI J( #<5YzOu_'ȭהVeEm_(?D״ۭRȅncV͖ CQ^_&z(O 伿M|)A_?`S//G, W%kǪrE.t:wڀ+^_&X>KG†Dxc-&ާu쁑{W}@, W%hO 伿MtP1 Ÿy?`S//]=^_&X>KOEecEm#(915O^z?ڿyM5jUMNCJFA-7<{Zo ,>sbKv`b91UU@ˑw/-Kj*"PO}|{Zo yǨ66L߾I^RhZCf[@'c 1,7U##^?FA-7мIy\E.eo+ccNWu)|h|9plTHFzz<{Zo EeǨ5 i/Pe?<{Zo &e=)溟cF5DLYހ4((((ğ^٫ yfh/o?ڿyMbfO"^S ȭה?z&c\Eedlf5#EncEm#Wھl&ie _ުydi޽]iw|)km6\60z?DZǑ 5mc18A5ZKul%1I'=T~4cVX6.Q1c^Ycf[k]2ϙ:rr@H.+ Ƨ{Crު,e@v>\=bjǥ#[ZJe\ۙd%x|rO͎u>RV[I$U2W=7¶Ur8AoO"FHu2d~Qp*?Cf'5cZ$XfDkc0^2[? -Jʍ ̡Bez{ ğԟھ '7ߏ.?sf{cbUKxJdݝr~\I̐YD,W--㞴Oh7ocR'k0 pتg n%!Bz t ׎&WKň[}Y泽m ,0\*?^?ɪ*2J6s#<ι6uT5b@7ocRKO68}<)/p_f|@*Y,1)/#< >:XŐ˦ ەH>nS7??a G /'9vuߏA[}ؾE4;Bj@V?I|EX?lS'N) MҦocvWZZup! 6 ڠd+4[oP& _)X#8Ҁ-EO*9} rSVBiL!h%`g#=܎;+9Cf'5 ]ݴ-ԛܝp;(*(ws3,w4NW 8 ğOEsOjK_ }!_˖r>pcIOk9<$d`ľ"(_/Az׿ZY|$7|Bر x}\jfo5 (g=3}}p 쮿u]gFv.8 Jܗ/3e^O͏TŶ V2m#co ϯҀ9Cf'4S7??O±K-Ł`N:=:vS7??%xXuK^qx%xD0}_*u2Yc;yI /2MIR傽Of~W{@Q@Q@Q@Q@Q@Q@v5|_AO/?}1?mT'[W)PO?Vo@Z<1"^P G?V?k&Vz&ķ:ń&( ǁVFe?zwݍq;781޴4m&=.)kˆut晿?:Xd=CMmKu+>Y@:=5:MWtdf㜨i4mZ=R)kkv uj慿Â?*zՔα(f>I/;PYYD.t]&iqI9dEP.{m{RܮnѴ$%3%Aޤ5 i/Qk_' Itt J^_6\cK8,](ǶxO.1hgpn}9<{Zo yǨY.%揦,(ɶI|Ș1g^dr7.mFdnإ%+ߺ/tFA-7<{Zo 'Ya4ADuUjĺHGi.6zTS6nih.#LP9/w׈<{Zo yǨMPMa؁܁ bfք!1zHH?3M5 i/S^=r5?M$cb׎y ߐǽ:MM"Ct`ƾ(eմ ">^os>u/7MfZ6sei=E1-}{qN4Ü}|{Zo gFRHpIyPO=3[qMPMa؁܁ bkSI=Kk_'K6%qakRGbGqŚ2ZZ~xCy=w湇]u=0ۃ_#^?Mi&}ii x᡺i}0c_~7Mf#^?FA-7yueed@dx鵻GADrS%1"9V眷6G>KM|z#^?:)* =c,7޻;Iv㺈Gk_'׿%O=@FKKCtO`s/']YQwec'4wo#;)s~FA-7<{Zo ytIjI՗=}"9}Gk_'׿%O=@ɩ4SKHQ1&1 )* =c,7޻;O wsK,-,d}֒cu6?:׿%O=GKM|z%uo 7cێ=4:+?yyqLKΣ5 i/Qk_'K6%qakRGbGqMIbZZI#ެLO) TFA-7<{Zo 5E1ㆆ9}IksMH0^i ( ( (1'?j^٫ bfO"^S٪ȭה+iCAtSv3Pn[tf?P2H[H(+i_L& 6ѵ0߁YVDWְ\ƺ6Fu\OkjJcYmlgZO U=) BHdoB 3Y:m[:B6BG\daPi?Ԭ'B:~@T7WZZup! 6 ڠd+O 伿MtW1 Ÿy?`S//@=^_&X>KOEs|)A_?+4\, W%jΝX_by2.p <@hz*嶟g- +ݏSހ,\, W%hO 伿MtW1 Ÿy?`S//@=^_&X>KOEs|)A_?+4\, W%hO 伿Mt^$ܧ OnWG4v)$uWӂ}iP)h-Ziŵ".wG(wqS]?vvJI0EZ4]mu;"gA"u^_&/{dRv@1ԱQp_aQ5; {X6p]ᶶ r;M Ÿy?`S//@\Yj~.9 "Wʌ+4x0کmm# m[vߺ|)A_?+4=y^hed5bYҭ8A$"7Eo.eu~/鿩p|)A_G4]nt>dC#/u" R& C!\<+69kEgƟZ-֩qB#V͖8ƒhB?`S//G, W%hX>K Ÿyc?+4^_&:z+O 伿MtQP\Eik52H'jx{?+4\, W%hO 伿MtW1 Ÿy?`S//@=^_&X>KOEs|)A_?+4\, W%hO 伿MtW1 Ÿy5?[k.υͱ qPGď5/eRz>$ȉ/EPEPEP$]_>Sv5|@AO?Vo5O@4xcEm# ȭה?@Z<1"^P @!vK_hVeh4a,ӿNWEݰB >Z*>$Q-Q?{?܏u*sssg$~{b;Z#<5YzOu_'ȭהV: rk7+j7h]4_ 2+6ߛB 3g6RO4Q. h|IH~M#P*$ykX߽5} քp vt"IJ{EeyloahRq =2w]OH3f*ypcéϯvW'0;d@Bpwv nEO)BȰNm0gjwz/V_W1eͳk-׊of8قNzI^hIm|rO<Y~!t_i֥eAG@jPkNU!t\E@Am'E; ! ndPޣ8r3@x ,ln&O3r  ;qej̶:͕d[r3r27d'#$Fnm򭢅|( 88?f_j<5Žд̉YO7h$W6ZBHgRw-r6?Nj┊mNDhci0! 9aRj>H{)'0̝.GL zg>iW7P4L^[W>jtrA`7GznY"H.j6F?g3l|JC,U珙Hzj=SGFX sfIH3Q#^&gkWJ #vrm-d>_4+[i2M6v},*X41xH# *{Ts.Wk0dhp3x>k\F̖67sqhx0w[fh6yjN ^G4QƙV$42}3P R -V+yABx_AZ 7R"W1f0cʞ#P%o[;O2UBwMq_'>_iZ7lp+/g;zKh>myfۀIcfϭJ}NӥK"PGLj <#7l?>CI_ք0o Cih6"=G[xh3Gѩ]=s?DԿJ(((yfk)}'mj+j7jo?ڿyM<1"^P G?V?hGyC-[H( oH{{6kk07#6l\}GQQibJ|~oJ[o_^][2*K/˖!y*HiyxRT; #<5\xE5bS&{Wv ljVoRY|y)xUJ50=AzVwoൿwtW xi-o7GoൿwtW xi-o7GoൿwtW xi-o7GoൿwuGDym<4mMu2#XdcҀ;jO(?`S//PvS29? 7m<4팗t7`,5s 熛to|6o [Շ,'Xg# v|xZ$Wi2f(cCuO c;{ZnMkִugGf(bFq3"*n TG]-p 熛to|6o [wEp 熛to|6o [#׊E뎲`"v:g SV`S//@v5_ו=jWy_%@Cb@OsPo|6o [Z_6,-E9k1 ?\汿 7m<4 |$mWrĥC< 3%buj3ގq`WWeX>m<4{Zn;˸8+m<4W+ L2Z[HWixl]  (c/nf?+5^~ E}uaG^Mu{Z__-0LDlݗ t1+m<4{Zn5o*]1DwFQٸ898%Y|B \v aۿ5xi-o7GoൿixMfkƗs)Q@F?Bk~; {8Y;x$-ԅ \ooൿ 熛t#DMKԮOMkO 伿MiEm_ ȭה?L<lc,c&9HPB;0Bly?Mk? 7r [Zۘ/o-'P!)U#:u:mwqq 熛to|6o [wEp 熛to|6o [wYzOu_'Mkg?XDb2ۊCg"}p,|HR_5+;4 Ww6mľ^d\ԞJ5QEQEQE?aWϵ]_>_5O@5SEm_ [H(+ixcEm# ȭה?Fu L.I9u?AU/ď};T"!2% Ceqwީ2$;`6&ﳌ0@5w;8U{X^4r+A= &|Úvw.3JÆl`,Lr\qAc@(qsߞGv~d~gww<뜿R 43^f=mO-#SXZyHB k`p$\# R;kTzrev5Ϟ~ExlY{>a6VR}5rs#)跩PۆCN0%-4r%ȘL\gfǯ8.-Vde Ld"#nв0.6 \8&,WpX5M-{Z9.PHm;KZ5&-vQ,>Ǔ`o\NnJa+ l`Gn9Ik iSv5|@AO?Vo;.&}$v9'|qỽQԷ5ƾD,T2V:/ ȭה?@Z<1"^P \ huƥhmbE$8`n ɉHw$9M*i &ŋSji޽]iw|)km6\60z?DZǑ 5mc18A4V^y{.p@*M#.vֺe2!u :[TcҞ͚9|!##&/zz.6pw,AAl(~gm9F,2$_Eԭm-ollˁ|c ŽEcXx_EmnloS˝|;c$J/fXtH2: Ѓ騠 G/n%\8 Thf?i3:gE`}텇qv?#c lt&?w37 xj k 躕헛 yp/b dxQ֙c=N++6;3!طɭ(~d96 2t jwY ``nQ@x_EFHmI3|9ڢӼ.; *,:FAMoQ@ׁ5wu5ƛiXU huum,kp8  ڢ1t hGm-˓e̼G#'K?U=k-is U4*q=O_ESDy\Rib>̒/5fys+ߵK@M7c ? ,@>++&܎~_ o/lk[s\K=vh??o ߆4{:N[K_Q5̸_{zG]/"gC78$um?kz,ME_fMʣ[_5Nz+D]`߷G Ÿ ɉ_ESDy\Rj8 J!h!2Exv\:ʒNN"v`܃@zeΙ ;V>B<N=Eye`Dۑ^?ӽ]sA&55xGዋw 3J4's-gnyx_E.L&t1y\GP*+ +&%OotBP@ɵ=V)u6*<3}%q.7"lt9MXG4i PR_EFHuG+|9&ޙOCEޛfNB=->co9MX€3efNi$;̤=I;WbicCy={z @M7c u-im!e/ *q=X𾋦YyPާ:wI=*5iu ;h]dWGE`>}%q.7"ltcG4`߿Lvqq<(K𞇣ދ6͠)]<{[}}A'$j.kik{ed\ ظu(#FޑK$]@ҍ<6:d3sZQ@Q@Q@Q@v5|_AO/?}1?mUIc 6ϡ;&ȞL>QE[٫^YY]c&΋<7xٳݻ1kTzdb"ȆIP@{{H>mŴW";‡t\n9 _M>l_+͸n8(w6sj N2;`Zƭ%l+s\)hcƽ ǁimSlw wVĽx>kFc⑞V`WN>i(8Fc⑞V`WN>i(8*((((((((((O jVG~ 7u*RkFNEeǨ5 i/Pk_'׿%O=@Zis&ȦܲKwVm?REKii*YFDz<Տ#^?FA-7yeMmy$mnCoBTTq#63޵Vo [9V<2v;$V|{Zo yǨ!GAڦp.dKU_-n37 3QxwTeq'Y%32]lyǨ5 i/Puyks[ V߸#pǹb;q]-eǨ5 i/Pk_'׿%O=@GDy5 i/S?9l澿;YZP4eFOdn>rzv z( ( ( ( ( ( ( ( ( ( (1'?j^٫dHo^Y]c$,@QEhcEm#=xsK]I$ bPdb&%HC#`zjJ Ku38*s5_mbPڑ>IWvTOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:TOΏTOν:|;Юu?o? qOTOη%^G+'nX!2_5O@5SEm_ [H(+ixcEm# ȭה?Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@fͭYCs5 $(R@lnU#8`Ҭ'B:~@Կ[sQg(YZEo ݠdʼsPԿ[sQgfSI.MG%eH%p߻})6RG ԿesGrgHVݼ !3օe`mKW?]6R@V_ Կesg=/\tEe`mKW?]6R@V_ Կesg=/\txcEm#*-aM‚8$P055QEQEQEQEQEQEQEQEQEQEbO/?}?aWϴSEm_ A1?mT'[W)@߆ X!85%7* t[H(kEU}ub|OlmK@ZԢ(=Kk&54fQя^v4W '7/SO o_;@j|IMhBwEpڟ_?>$п\'ğvO?/wtW '7/SO o_;@j|IMhBwEpڟ_?>$п\'ğvO?/wtW '7/SO o_;@j|IMhBwEpڟ_?>$п\'ğvO?/wtW '7/SO o_;@j|IMhBwEpڟ_?>$п7mWO^Y+KóP8;ڧϧֶ?>$п\'ğvO?/wtW '7/SO o_;@j|IMhBwEpڟ_?>$п\'ğvO?/wtW '7/SO o_;@j|IMhBwEpڟ_?>$п\'ğvO?/wtW '7/SO o_;@j|IMhBwEpڟ_?>$п\'ğv[WKXdșLn r:ր&(((yfk)}'mj+j7jo?ڿyM&I@h e Sv5|@AO?Vo5O@4xcEm# ȭה?@Z<1"^P @QEQEQEQEQEQEQEQEQEQEQExFOEs^1Tӥ/:;_AysyFpaHKEqkw}[ǦDfeFٹB݁=}zY_$v 'l{uYv.OwWW/~A0>i#S|G]jzuİwb~Ρ ̭+{Q\'5 rI\,O|xU Qa|(HVn'<h(05}Cݪ >A+$8mp@ y=EiPg8n[̴Ty^;+ω<@ Ej>sm۝׾;U5{x]V[Q, ǻ`ld㯭vTWYZkA 9>{7>^٭/K/hx<Ń Åx}PwEyKMMqfY˴d6oS&j[r޸&${aF :ݓ]4tW9\o(ks}sRN#>>_Z:'gI-n"7R6&"G-yz]RF7YͰE]2w2Wn/Zfwmf6MtIȭהVeEm_3>ȉ_1DM7׮ ( ( ( ( ( ( ( ( ( (1'?j^٫D,!f]H+:)uf+R12K ٻnH/8<1?mUcIT6IZ݋] oꧡSOYgV>gh-qۥs2Ҭmאַ6-o2r77A xKxɿUigKs8$ -ePԦ[RB*5"?6<` "Y5ޘgrIJEQEQEQEQEQEQEQEQEQEQEW a_CV|Yk_2T݇8稠E#7TG$z hRAޛQ?*? J+/=zoG4GoMƀ5(H  A7Ԣ#7TG$z hRAޛQ?*? J+/=zoG4GoMƀ5(H  A7ukڢGG"ʜSx/=zoG4GoMƀ5*ŤMOX<6ϿST#7TG$z hRO"^S G$z k;:75H,$KIUQnP%7M5맮coѯ]=QEQEQEQEQEQEQEQEQEQEbO/?}?aWϴ[u1?mVFѡe1T9#>( ( ( ( ( ( ( ( ( ( ( ( ͗@fGF,KԓҢ2 ,G#4+RsA&h??J(/o9MXµ( G4i Q@M7c Ԣ2 ,G#4+RsA&h??J(/o9MXµ( G4i Q@M7c Ԣ2 ,G#4+RsA&h??J(/o9MXµ(mX-`S;c<SQEQEQEQEQEQEQEQEQEQEQEbO/?}?aWϴ[u>R7>o[oJ|z>'^4߷=m[oJ|z>'^4߷=m[oJ|z>'^4߷=m[oJ|z>'^4߷=m[oJ|z>'^4߷=m[oJ|zO=m :+3BOm|[oNГz/GzӢ?$'^4 ?筷hI=m :+3BOm|[oNГz/GzӢ?$'^4 ?筷hI=m :+3BOm|[oNГz/GzӢ?$'^4 ?筷hI=m :+3BOm|[oNГz/GzӢ?$'^4 ?筷hI=m :+3BOm|[oNГz/GzӢ?$'^4 ?筷hI=m :+3BOm|[oNГz/GzӢ?$'^4 ?筷hI=m v5|^+C#3l(> stream x\۪=r7@vZRI!0v'c L&`27y-ac[::J>%=Z~ǿ?O)7zԗ?~M= mǷ`2Ͽm_Ui%k/7_eK7k{e{@w:ϐ:޽؛_tOi{۩zq#wĶSUp8GSBAu#Hw[i1v>tت,MK.֎VY{V Yq  gubcˇWIz%m+#tV ts߼ ^g},9Hhٮ4uq=O_ƀ:'*)I긕Tf+R-Sd3xo7aZ*D@"#ǼSHߊ-RʯWUjZ-V/J>T%D3^!)a~/(fH>o:sr@%@NAғ-T]6b[ذ?FɀWSљ-)50ˆ^g7:v5 —0~+|[z;jV1ƴ{-o3ne嬅l}`WuφxjXۙUg-}qWd 3>&-:LDp˼W׮CN H :4W%9 z`BO}0mh8UxmTNx MLP=ɱfh5wtv.,9oË;/͌ڥGSpxp z7q+vѹ A ejTH!k)5|(Menahwa{#4H #ó? hYϚ fM1Ǚ B!nho-_jƕ~1bAd dCGm\I1)=M 3uX-(R(Qx(hi\vvypk3pU[埕noþ)ʌlE1qc6v` 7.cP*i6۽+?emEkܯ\|3An!nɭEyڧ |ŕE7j4bsZ?+"(Քd>c. K[y_ sIw Դx oD{.lա7{/Ӣs N9<qxƣ}<8Zu\$'PSQR,qܯ=gA&Zܦ2TC3蛀P%Z_<20>L"m==mP̸ʷX ~К/T/7XszP۷I"Ѷ7 s6S=-ƀ|ғd:\L+T".jb<*sYWA"wܑ*ݻ?'ȕU9:MVNZBR~1WzQ@>n](l16&JKkW~ZԳXȦֲDCIEc'%JoLM0(40#/1\3/ld .ɩLOej,@=?&hjJ>_8~!`_aAve"$ʄ5ɕ vr:md*|j@>cPacnP r$]Yܨvuw f\ a3T l ~uV7'yߪ6Nvbjy4K=u:é!@lVg^V}6m}#ӚTxJEb[u&>6q{9SRS;%GQ D;\N4;1 ~-Gۙ “𥄳*G>&4o -~QN/⅃I+'VXIB+UǓEܢ@T %Wv=e=ym DpK {_=Y<3鶮ݔ wR Џ`-w=j[]MڗtRGUNN>&6L|6b!׳"sJ]mo i%gʗL$' I leZBM|[fXU tm:M:dv!?vseJ ItD2ޒT!^6Ib $*I$"TShfk?/=)QXJ~-lV!Y).yč7,Qb@c THTŨ7 Tŀ-I%PƱeH-39d; F{<7򝛦;rWvX qpVv i[`IrP962[Xкj;b#/E2":fݝbUx7sf4A<0H:7V(n-P8cۄ"Jh*!D;!8HouSZVUY"h B9ªh1BE9{*,# >,G}daYG=>/ y)"A pJ.'_;>_:t{(ށNS0 7N%4H47zIa*S Nt:=o2z]y"z^QPɆdȀzKɎ86;GJ:lCa_{/σ ǡ9EZ17:@ZU`+kmQ%6jIVvu=s$/r|N+7wԜҐۥc?^pendstream endobj 13 0 obj 5026 endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode >> stream x]K$9n7! zKb*36]}"AETxV Ѓ#Eem㟶!oxMO뗟e@K{~ =~㏹_~)/}o?cM| }K/[XFߵߥ0OM|&'hyזyi_rNCZ+eȚ`js]H@_4\G}M{Hs>+bUαp5if-UL/Eޮ}5p7U4(2D":O2[YWU޼V {7Y=yuEsJ>p+R&$z)cN\͠6RsVwƭʮ[6US1ۜYk?Zq#Oj/~-o^wgoJv~۟p%IC*t㓬lSs[ A\{Nūu깾5*k!VU,YgK.1h$:Z o#BQASSi\A[R$>4+I̥wNbjot/lo6K\]lg݅f^~[,0hvگSHB[K -;؞' 7'g;\ J5js]Ӵ?7M} `dU8k/,1bl#s~>RΨ,Br5f輟5Cʋ'0PIF4 EUo/q~.tNsNJeZsQmJo~A&/cV9? kNR(NΥ(6Rn/,)B7K?txEM YF)Aw4fap0eI ;Z4 SeDaE&>| *ʛ:nv79ɺ`p`~gijR Ftf@[n:b $ Dl,in&w6aiN˩Hꁱ`~pz2ּ&zI>L$N9^an͙|uJ`r7bs2 N099U"lG+x{ө,]֝TE"&Wy\l|RI0!鼅ʯ,onaDV=?E5cpܛn5#?#y*j,и7EΤu/n+GpśW Ԙ ci[ۂ9ݓmfLN +ܼmGc{ZV=ZAD\+bA0%EO\Tg"rU(Es|fN&cZ"(g͉uʑy%J9 x]fݛP f X'ݭ+G_>P*LEQL p@R0F|aepZ39{5EgoD*'f͖hQc2f,$Ns5~)ݜ;? =퇏A~i޾>mnq׋'jj )de1>F'ziٺNuV{iUVhK-ϥhFT_RL@E8FD [ 4ؔ*%kN蜈1sr.'&9`cgNBN\uX r=1Zovs٭w?ڠ]=r;)&ҾZY |=?  -M*&se-&wEBZP;p}J2WE*118O7w}i\&&^MnI&/0W~2Y:/>@8u…-[5`JX~WǭKQ Kz0tsW~BW+)b;TkL Sѝ8)xM=x ”@ $̟i,Vjf|¶~Ns)a'meF/Ee0_Jg e²Y lsAG<+Zg*۠=)5YK갲kgBΑf(M kLA74h )rT|$\8vUDe\8 \I$ ?~t,n T jc(|vE)!IF+5Fav?,C^V:/(, ÌRLQYxܭ}en9CD3;4ViNؘG"i沱F\U6LHd1@E6I`#:T-"nKdüpyXSR k6ȱa,0Y;ݵv$c'!42M<(!ORʐP xcoLҘ")"R)7O@IeCTe|h rwa`6)T5".)WC*!kCRT-Fdc׈௫j(b8 fcu$ Ý5dh 67do4Q_G6vcρ)vRH'z dᨣi+d"Ab`햱j2$g p h!z̉"#TfLLƶ*,Z73n(}{[@o/}P8y%(˜NP ( 2ιTA8A9QgT}FeQgT}FeQgT^Q![@ ů-G-K|U>dI5lhcIV(|[ĩp`1iDwƔie{͎[VΨ gU+zat>6 )$dEDjRI("HsF$P@2XV;ڎ43#s0y#09 nW5dQr\`~F$7v-1E"^/0N*`HJjCJ8J?!VȩT H=Tuȍc:gCX#,hӟ^,D"C]$1 EYl3$j%S6;I;a'AsbB%Bf HiӅQ,͌o<қp ?#\kDriۊJ뒱z; 6n e#&.2Ÿ(;&(yaFQ`* Po?X병%~F'd̎4 $G7PhlH4HAЃAp6}076ҤhcR *ᨀUZ*L@!greVr l^Wi6z@18F妇Qn͑UڛI bgƇU,J"w!UXQ(ˆE1cw[n^~\ x$Ӗ $Q]swfCgU9|c?A'.nһ ~)ӫ'jal«W7C^..gՇͬQN1KR0qL6]*E?1; Mwx#MKugk1Nd6PS-P j߻K:q]l/'Jr8;P=|"_"|?JDnh]ꍾ8r7^NSo*2ME$yv2Tpk> stream x]ˊH?a  fS23Maq"fUpUʣP?]ӿ~Oi^O3yzߞ~?5oǝWbzy6okxOe.o{ە^K'RrQa,mWn\&?]YVm^w:H׷+p1ݲmk ~宸e{vewVsqUl?#ŏ=/ vk6$>;|VK۹93kw]?K9#^6vX7 CcW Ʀ+BMK&zEvZ;XkK1śz<MXVy~)1[Z^~3X7x/M}1Tܖ[WLܵE%9Y^dɆʛUYe2wp=+KmGv, p uha.³mv:(Dt78RQӞ^Unx+&P~Jv9_d "="C%|VEhf|[C=voH&{uō&AkHONco,Ez.{bSy[6j>Mgv;}ɲcRzϰD0d]~j xV`[4&϶ vKmr8~]إݟGD[&wWv9:C`3e3{sÚHKmߜ[zG 2(S˙.uѐ5\#('6\]Q\ݱT~b<p-c~OSR`OFuw0lHl^50F!46\eX3FlCIU;᠘OymUy=Du޼xZ/aK̊jt߼uV|ŢKu%2ʟ>/r\dFjf8D M+rI4xҡcz1Hz"ax܃U~ө=dAe،St㋁C he_@sy"#r0  |ۀ7(翩`Xl :Ez`si OWHPN 68^$FK0D e:!ċނk =:)ru3$ḿV9#drogpr]ڂ{TX)G&:9PI*vܦ!E p]S=CJ @VE|*z/: 쳫Wc]b7L?Vr hK@!: eBcTÜet[<>?<0$7hrKd(Gc>G53ƺavC]hY"m~ZH %oe1Њ@Vn(AD!?mj?ᬔP{Is8Z.r!b|ѴTS(<;EU\+pC$Uu>¼TF]uL*=K=]p}aJu"h8y~8Et~G ѣS %vM VD$]?_n@gsž0sQXD{NBj:2E!KF`[TN,.`\'NVH։8.|QvUxfAtKYXuUۺFBrx"8~sH?A!%NGz׎SТAA J XػD$,iF)$ П a׈L;H$57.sGpO_DRsX1_'精0V' SޏD( Ƣ.j;wvg0B}1=^߃fZmj#gׄr(~=Rj?Ná}px ܫ6CwIοu 'XRZť*Jpk°?685Հ|0 蠅O 81dܻ`br.|eKe^=P{H m>pļzvLB?P\@'w xҩޡkC{LP2T:H@$ACfF"804 Jv^~'+oGijPϱ(V9n+, եc}jij1KJNA?(,ꤼĕ?[Zn(Џ]RrQJ1Kݠ8Z۶"9n_L *\eL|8#_V pRWX5~ak0c+T+0AqrC>)+YA&CPs4Fi<Ǔm2M~g[Ic{kDnn5(OSCAP{OPZx y*ʞ9#ook*3SM4m^e.?x%lʥ} IA_q1^u{pX~[‡z:*n_Xi ֳ#Z|P@<pgFǶֿrZDy#3`r,,jJAR2{1C"9l | Lj vu(&J9FeԂDQOM !LX[b >tR'jڑzԵi&,m]gyv 92FlAtmf6^T^~`jGpއ_כwñ??жvŸ$/`l )B!(.3oFRX 6p u:ueZŊl S <[H}pLL#&ќ"e "mTO<=," Ž,#oY/;&0vX/SX pNަRX豋cƥGAQޔN4N;$:2OJ=1«Urt=TrrO'q5FId \Rʅ>sv=IaqMLXGIހ]'D{7(XN/CKG L0 1ܱN#ACKIypأuDf!u|՟(ٞ6)aO/"=}r@j(  Pi5ƚym+܀$ T}rگw6EG~}@PQqV onE{)hJzz ;|wA*׾:l#D/t?? #${*Q#a/ńx 3pɹv3Bv- ‹>\8% c)1e 29p]P&lNԤ\)Ι$Xs|KJ`?a"|B^`Loy9?:tB̽cK_~hpqnEn#=՚T"6\YUs܌ U"H`譅U: [oۡ^BonI_. b; I %_'7c4jtqDsX?7S@4RK=x]GӠ`i\@#̅ہ ^6`\F/_ '8tԀN趣F^2ަG^5cwPS()Q6 ޻n[+UKT͡7W:Ў1u30ES~ج M.͍b|8`5@L,!~eM٪vRc䎹 ET*<5?_kBHi_yf1e)/4Ԥ@hmJH}94X8˃^D/Jqz{@{#q/W:sgyC>7 O(vĝ&4+w\)?'i"Șp뇼m!GR&/&(ryN: oD L "2֓-8'KD`q\ao̾n)s%fNIA%tw4i5ͰJ%-j"UeH@%D~帹fwu@r̖ɏpS5 UO@2rUendstream endobj 17 0 obj 5653 endobj 18 0 obj << /Length 19 0 R /Filter /FlateDecode >> stream x]ˊ_㒔RJp1tW ? ƿo3(ɨ3`f#32'uy_ry ގ__/_}e;ðo/ /?^~]?|ק_~_\ʕe/nis*/-[y_.wL9az4Gi|h,rM[l47z}yռ/(lr>-qys2Ne-"fjK܏l#|Ӳl e ܘ*Vq*DZv=ZoDw@&Id;D*yM̟ZNvٷy*=W߿R.۶T?׮N|!yvFk6؎vevNXSIHX΅?sեj7]jg\`ڥ&?9ۤzhFc% y3.1؁*2j`Z(a2 Vn2l N/ѹJ?[;=Jʇ-< ߵ+sa̍w3WS.pI{/8^psPìf7Dnku57 r)KL] pmy]zX4K:&.>5?.Wʋ͸AlrwOň1#ٕ>XG2)EpȰyDξ%W5Ȇ`L춋nyԍ@Mm:3Uws,ېa^HjN`UoAM[uFJfEЛ:ao,ÚYFWLtz7p>Z `!B &G! mlL݇hQ^ZS(` H. 4PY lq(j>%N+iJu.nxpidHqJtpa -ub(L,H:Yy*jx%Vz#u7vyl gR:B!pnVgQk{S2},Ͼ, @JNv0_@p4/o<$x >w[E=n2gs)*즡ܝu05n Ӽo^a|w?υ e=o BD+pf!"_h=# O,򗙍IdίrC|d~*hg=YWa`4mN~GL}1`( &߷܏Mvdju \>f>/yǀ%ejroFU k!TYRd'b #R䐺άcG2#2òb,bA@" O)$*]< q MpJzͬ]L Hdc6Se6UA0QV1o\vP*Ow4nzM" D5Цd+|T]mD~ @qY7fV0WE3]@Ѯ5T$aKT^J$}Y̲""RnksoET)\W4k\?JՃ62s&}$%ej{i<^fT!Jv˩L)ׂ%1X^5`>L,C[ (v)QYSq |!Fv=\ҥ )U(jF8VՑQE}q^z$VF|R i6"bl.P*5͗\-a^RҽHۓ`Nfbvi"uaقSd$ruqY@[|.܇SE/AbueAޤXs;DOj XYIXl r{H"ڷ|Ry,I** B嘗x^/ݠ]cm ݌0c$`t@]bJߣ؄  7p;`BߴU]F(v8qhw[ĹST@h "J缂3mȄ7xlJj7h#}_6"P`h:Czpi5# @`ey>5s/;R̲$$՘ȋIS:u66ҰUr^"HyR.Ӛn̚wv.3:?Mד kt4}a%j6L zr3!F. 6ܰ]y%ʁ s9{ 䙰!k3 TVVsQ,-: ~c&@Ac2N/0aV`𺋱])6daX49`W` -79D -HP 6L Xhғ!~ޑcEW #V )}:@C?zl+e򗤺5G)gJN.%2A8F 9wrZ*fb!Ԟ Q̽A#f| FD2yQPA,YoB~%PL)zpZ#涰+HT,L7*~v+tx@TV7ꢢ75kɆf߫>HI^N}3͋qcB+a(*O?xCW5t$6Ef݉DT|HΘ+ l^<}r`4fluP~:pUuI0"Tm_Dh6Lk \,{XTSeq6H-Գ-UiߌC}8Оl4]b֓-A8231q5f'jK=!Ӎ?qiҵSEAjSzgO 8?"gߑj%a^Ud,BTwzde"5ʼԅ럼h?8nZi&e??V^6 +X>Cs"GykFeo ȋx}9Z"^uRSVʼnƘJiA3JxeR#8U= **6y0G]B;M@0~sK&I$TxV.YԃH֋D ܃ybhZ4Cj`N!>c3˸(u6c 9_a6Bd#| Wgd2I(`aNvm5:+z?>ST<͓/t-p`ٓ<(˭vB-2q_,j#Zf|1|dSXg*"GSҴVoO;.˙ =f22Bwl{3 NOgTcM1j[yJY9}a s`^ -`>{K>HQ!+ށ1d,%Wz.t#H7II3S6̉Nj=u`]CS o$a Gx2']acߵJP-%>V uCVӴe]R Vx` ˗/ʓʺ^ԷJ TTt\HB8ޕ1c}o('T)>A'x:FP݅F#V2x~jD_On ۩(;==vQ=&EOgiIp Ps:B9 W3 YUSTVyu%Ck.(N5֓º["䇳> stream x]ۊ캵}߰ؒ, ' !ߏ*91Rꝓ@X]u1^Ox^~;/qvi?__O߾bi<|?|[?>.KnMpZҧr߶6_޿v%}jA.tnWW]X+v%~ܟtag2FY}t2E!Gr]);{C|s)eRy̭7G P1{ڬWVtxg!}PtB0To_ܒO7/<`3R*s+3,)̺;/AΤܽnyȦ۶ҥ0GZV+kM!-2쏲s;_dmBYKބnQ"?xP6hNLEeeܣfbzQ3o' C$"# {t"m s>z[PfIJزʾ}1<,7 o'{[@WMDY+Ouރc}C Q2!.OKRVNmNܜ""sͲ,2ZXol^'UDk鲝^e0#Hkլ\*D4sp^8+;De෭HU} .f#x}+!߭LsƮ]^c0(O, Qvƫ@1c2r 3/ )&!e>쥈zsPv_U=mMvwf1|Th0*) ]@%$דP&vn e&eh 'Q4pcQMfMR!'!9[k֚F&1`$J ûh2 ,$ Ίt%Q\R]Э!U$df(:&`ɂxn#63aQWlh)}pYvFc=@T>\Ö] Hi[e(3E[leyAEw}OεL!< ".z8 @鼡"s0'Ocx? hA]Q+xtDSP%'1>׺TF]@ FXQ7W\xސOVZzj .'B&`~^O"H&Շq(YT<9*Lhf\LBC"} GZ^W T"EON6U1[+b"LJM Qё׊fIwIBO ߦr4g'Rib ]xeJ< bxHGs'<-׶EW+O++W I:bO)Ĉ3ž>v#.29%XO9Q(Ч ~1 eU =5ooU߂qJLWr'_ɴ>8ܴ^yQm'c F]zITbd/$}_|{ C@b|Hdl7㍂V=+UHT6UhPhp2kbT";$ #JܤIdN3ZJYU =cxmrOHa@ i6IeI0!odu)*Aہehg^33p@Az(Ɉw%fmm4|0y1#MꐈEpQ/<#hAfCѴSm\0\NVԸk(<[c>4P597Q 8=>^\H") h$tg;#>?M83 "() -tB$ff~Z8lj{8rf+NcL%Z+{6y)ŒgtzƜ(XP #PRW=%/c,9 ^ڌ;A=uDd*z)~S a ~;(1Yۂ`efC eFOu7o#FE*cd9Ryg;{.ꍇF}=2j;AIseJs.3yY$g,C M=8h'6e|t9>: usҬDȱYی5icASn-n#Q&D~}. ! \FKk@ 8yn5P[&8LL'eG-;g8!W2U\/YD} Ua+}ʵEd]ݱ7yv6g-l롷ҤYTaLW,O_ NcOÜ̫X; ~Q.z,aDÇHd &,ۊ  dvُB!q}%2|R?mVgync.X:[WOVgxAC$|@H6k V-D# >3Sl5)6`hp]K XHbD főJ%\*4n\'xC|  /W:ʗdL5Lzpʟh1j#49n!?NHN4>Ou]fzo@=43F ?Ǖ/v6j3%]H]D]V v!r/Y^Z]Y>ǾW ,|;`w-nb hӰ4ED;$A5,<{}^6\f.tNM2xiРx:h::kPw QM ~r5^}ՠ7y@GU^LM!/$d hh f}}rI =H- Sv0P[vg60mx#$j>ۅ(̠.Ӈ ms43lɢDSIDoor{~XxHչeLf iPu'Pt| )%%jr9֦Ռ}=ɀvl~aЁc =;DB$E+RޑfO:[8yAWKﲑMO*9I,~Fi9#mmJҧa6 Z&WIq.VNu 0(4qB5'G5z/r }[ G^0yUP [靆n~܇>$:33DA'ѓU*i cD/Q31&0 C(ky&)X_8vk.N1H )ӭZҦdZfȰSmlң8~J`c- &망!wjYq /fY5_xsb.at!Z$%ν*(kwSG Fv] ׷drH4TUqE>%8ݝ{JpSv}%GvpP h/} C9U`+V҅ˁٞ]qLv!OԌ~M?{"$CAz-i' 勦$%(#K8GƉ$'I)wjBLZ$n15B|t76"zf j *fppƷ] *grg:wN&0nZ]`ĘB= aJ'+bn:bH/$@:r% Cq+T ?rag >`k6;}voy˭"|U[9_n_Nnq-BmWi ݔvud? Idendstream endobj 21 0 obj 5737 endobj 22 0 obj << /Length 23 0 R /Filter /FlateDecode >> stream x]ٮ}` F`Kw CJbUHҥk9tL?MO2~~/>~Xr8?\/~謽N|6Snc/'~DS_!8Ó/UHcoolܓ+WS_Eӝ\4簿\h[ڙpF/vkZw+fi2@ 'K{[YN/im:f'VX{V;)G,i}5t(ک4]+ݹFmtC}=VNwUe|C2+l"Yz@^bλ }ML¦ҝ_^[<2Wq@@Lg^&q&jt+|+ة}yr45ة8e =w]yv?PKǷbyaYE>V-]:_vxie •"♷=ӉEqq@[F_h$Ψ9J9$7#ؽPq ez Z #]=Xxb0oV$A3 ''zqYi2oezAo`}ӵ;yGeb^]16EkAҸ2I(>TX!5:gD|MBo}e+^*ra*L9D\Ea,̠A|@ C;Rk+ݤ& A kі/@7L|I: p6][3Dur ֝XyAjXT`~J] bVlr#WtAb:Qk˵&dFG. 5aׁ"*\YKDdO 1'ܚ)LP4$rwY]oSx6M!kѲ hTEے#x=`d&\B;@k(6KJPje֐Qlߑ^ot$AP1ۧ/][BR䞁ogkfcζqŠL)H1x@C9Y†S-s[Woe:t\tbm>#eb#B*r2dU ~i?-t7HSuJG&`8= Ǯ LR¯Ynm 5d;+5F(d YUvrLtL3H2k7[}%1V$p5Rz鿖h{ŬsK|:1ayB7^ƌn]P.6\v׬ 8>i,X1s6讳DA\4L7IeMlLBVz| FI oGLL:IHEW6nW(ZұZ}G݅Uf)i6ߦe kyk|Wb Q@)Vl<WluP[۪C-PGA);G sn\ҵzx ܙy4&MXARqVZ"H [EV]ah cL[eĠ8)p˚%zVH9\ΊY &$]8I5M `ةlNSad2bL!hL J9*J~<.L8qLzf;`}6Wp4ʹk3 uI%_Sox[fex l "萭E৳cj*m犪TObR+&XM"tLڭu]{Q|ߜ H,PST816>` D}qBjcUoT\8%\A&NhXpZ"&́tZX2 PrlOH(c5⃀0%DWHGkA\{Hm_5-Q(^ຍp}l5"đ<'#fd}Ɓ2'5گb':2 Tݶv9('BZ[SWZn%s=8"A#EMf e+Q):(zpI0d` [-v&3ӜϮœveyaRтcK@"j3V@ۑڽgw_m_N <\b( _+\W9܏[qФ`i13jQ9`Z=Fm0F{E=iUۥ{6fC#$7@jzF :!?`1(-ԊpYب\V_if87ݩZ~ emq8HgԎg2~Ax0B85"pΰF8lgn ҚbZPQjʫ4]jG纲.bq2u"t%  i(0UбC1#H:@5DWK  @dR RV!u%TײQai,{":5=`wi=ӓ\^8h6J#0bb3jVY=7yWA1f׸;QXh^Aɔ,bST~Vpg;Cja!p!\" `D:t\<,B̅GpRMsḚ@"PV)WP`\u 8ʱ@ľ0ianQ?!Q7*1:X` ͑r^GfY$ 1v$Xb2.2JXtRMr1_;Fׁ''p?+Va; T+Fpe6;6bOp-2e \A4pmAٻ|龊|/=Ϲ~ASϛ -jvO4huk1zju 2mg7v2'0:x yNQCDPwj* t;ACZTo.ayIBZ*(`@f>@iZUz,SaI𰈪wn@FT 2W stSAPb4T8 x;S˶c@G"=C%^G@eo#l%8Ȁ 0Pgz͐y:e7,{`x"6wm(rp5Æ#Bsvq) vг mlcѕUEsa]pԑԢK>L8uQ[Ͱ3Gmʛ\Z<@S>Q-UQVHUM"TDv NVR`I,Д|$%QDbM\A*Ej"X\[Ÿ{BT QoҠ Y(01zRPѫ6);-Нt KdJleCPLQ N]WhX9N*Ja,z:E&U3㒋4XnrfA9k 0潚H5aiUIkq7wbܰ$fިa)$>+3-Pűj&.B,:Y-YͰ솬k'Z)md^)CiYoiN1q`no`s˝M޷CˀY-$V ;k 'j,TQo{tcJS{Za>h^H,!ZA4' #lW9qMy쮈0¼$T> A|R+{eg:݁e^\eVƂEj5e`eq|jӲ;ts %ʢn^p=;cRկ$?V bZ!( *wh (7uaۮrkX/&* +RyUΐ7g,۫u:g*Y֨qfFWQW+}z ::pE0 7F֒~ =I@ _, rJЋJ̃f2=uR{m݉Bd׾S2bu60>l>TkJh ~C (7E%K$uIR*B,_Pӫn7kp 6*yY %E!CN9>PX ~U~"nNa6$2d:]dF_ФTS~ Z[\ *V}5w>WJcDf|A=!Z= )#=BG|g~0eM3Z2]JDϔ%_.vUD{K{>r|ٛv?6 }|i x% 񳢢Dds5Pxn&@:jޙhs/6-j'cGaaEi'I $_+%ݬ?t\-!#]<]廷d3|{La}2KVӥY˵0_8ǗΠ~Zw\K:jXUYûޚEoȴ-sZ^6?y=ikCR/43豟=8j,x5p:|}Dؖ\Z^l63Cfϴv5YZ)c_h^ኴf;e>Hc4.2Z,\LD損9!KiޟDdo|a ?1vn6N7ݞxki*ԏ10^ք*&Ur3'mO6e58g,Z"3\`ݴJ,2fr{\7şk.'Ts[߹ I*aUڞ$set?tcendstream endobj 23 0 obj 5258 endobj 24 0 obj << /Length 25 0 R /Filter /FlateDecode >> stream x\ۊF}79wA؛wB~ C yGO_NU4Y;1F+u=wq'D$MVNkVBt(] 9WojӚ O}ٛ>Y΍If䲤,ƣZ0}Q%If'P5 4̻씋's:ܼ+c=ٽ2nomswm'{tEnE ݌nE!(k9\ff3񳞥P[Csy):UGj;`)hRL@$>SITO/Ŭ |2PE]h]CݬٔiJLcXRͫl{Qzpǜ1˾ΈP,m+%S.d4n2%w4S<$S~y~yzN7bgi\vGe9e]3_'Jki ~ bxKZ6_gx>"=8P/<4ˋoBue Hh"׭ҐRi+u*?Q!( ?钶V"^jܴ2P^lo^[$Idr2,#qih#lvuj,q Y))GgVPv*ir.U|cr>P̭eoO7ܑnne1 :{#_C~}W^]U䩿^jBzǻ̫\Z8eT~#rK&Zf.]t06=)Nǡ8QXj C٣;cm*ϚiXR5t[Y8ܰ?RX&+La BhkЛͭz)_tTM&`~+]>2eML/pLCӯ.k~I@uEjr.M7ӠV]O;bwc;Z̦NM:ԠTk#R&Yˍg?X%rnjpy% +4Z16ؑ$#N!a#Ro7o yC(Ԡ!̒,k/)G]w6_5o_=w&06`Aodc0t57$nk_I "Mcb? _ UhP$V:+t\@/&笙b*%H-TTҀݍ/ra:+OU_Q%Uch@LHFT[Õkt!7nh-Y'L=d11O]Ѡ\"SX."4N'wHFEJX 7CW 4f8-"[* uܖM~ocGܜuΑS8ޝۈ*`X춠.)BS(PڙW-"2ǘ0G{ ;]QcqRud7Gפ\ T F*iE`sPkռz?\ OI&ri܀3aZ:6) Rˮ&\ P*tUB'* E#mOn;>|i?qbrnZ/^=Ap"g_M` ~WTT06 O@P5_<{L ~9Ǡ95GWj\W)`)xMS~"i0tHz ZИ$2r>sl([=UhXiWT6iV[_Y>^jf֋uYӌ>|K6#Ѹf1P÷_~ȉmS7ᯘuN5ڂP}m 픽zou>'9peKiN|!)~X > 4H<+H0endstream endobj 25 0 obj 2685 endobj 26 0 obj << /Length 27 0 R /Filter /FlateDecode >> stream x\j$7}_?s NKK7,30r</tۣ֩*iz,,RKSS%n>{?]?pۿ|ps;1?- ?7:x~1, zIKu_ٰ-mn#i'ɘ''aI tz2 :]Eΰ@A<!MNy'N$|\X;xaivϴ<:iT$KE< {O8A;&Ԧ{OOȑ3L?KO^\Hg8zѧqSwL3X$ręU3!<<}5q8O"< 0F&i'ڰ3~X<}htldvpІ=VDcS!o/)K,rv!YubgO5&h>e\M ';?<]&MHk6ȏ05gX9o7oLdtd<=|[+#6*nf4S6E>}(mjq e|0{"O k6c#sU!^;td>}pO$;I~cѱ zU_k Lɂ4ov)|-E!hi5cJ v-.gK>Pz&sYͣ#=vi\B8ÊAָiоU(_x6J?nJA ݁n$ࣅ"T1ÙÔ?C:RVk*pߑJZ(δ{P*PaA9+$3Po J`gBƤcb<ܷW{(j*+9!I30lY@UKFۄ.CM[e=*ʳ+D$f_ v./:yuDr 6mYVe_S!~pt\V:2늂ߵ&鼪cw Y%˜8#nڶa5&/!`X,Y@1ipAdJ{8F0D7W)M OH +b+zЖngHJwi.֘`ya-څWkMJ !˫wildYCDݕo E;Z]=NR7DD1blGvӋkWYfg,:ݑOozT5" 5i|r9/HI10ń>@2eVmIө!xUdnk y#oA2i#B~kkنj@832JX32=`Y +;xI+.d˧|6s#fPܿR;J up9V`"hhmWJ:sk Y#c喜~ J hy1]k=v0Q7+ ڲifmW:siR~\lڽ)̫AzJjJxvN%1d ֏Lꬔ X[THzZd]t 1}mV&vT1I#\_H V+gXDh1)0"'݊9fJQۛ rzޫbYrGug52D$}hdS0Lj<}u")<[ߠ8Q9l= .fڴl+R;obue!Ƙ6T 1l_rGe: :jyknJ[LκSoE!9 `}E]uM'yU3~_/endstream endobj 27 0 obj 2500 endobj 28 0 obj << /Length 29 0 R /Filter /FlateDecode >> stream x\ۊ6}_@:,K6,M{` ? !}Ǟ.]$efv[Jҩ]ۛ7v?v_?|~X4{}ӱߙn{ao~kܾ_o1cwNkS[nbCC|m&3w߯}YL̛Y?s| p'ic;]m)"NN3qm@Z%cj1Ƭ ʇHAWw+M(l/q vH'vsw-!';5 ]umqL&s<QYc? )cp@N^nfC9bDw&$SH U m%~`5 Ν x/\XbE%DM#ObFPZ@9?y'&zFy:Rk`Ky16B'EՖ;EIiiZN<4Ew5m;1'w/)eMzr)&ԀB (Ũfu%V<e* !n2w->M\:>y(C2 ;CCyC1x+JC4XX T/3hpLsiG( oke19Q.9gMftٛ\B6Uۇyh>/d1oVh+TI]3c@70&yMXy XiCq>9C =lסg;8gۦkzfDk=*V\:xge-?T;|H֧| |X܏j}r̈́=k&L $+}g81-D0݀ 1tB> stream x\٪8}y`X,0?0 e~Nk:U%ٽ$ @ZNmGv=7v?L]}]0fߙn?{;?Ͽywp}GGᅶp,08b>+{~ޫ}ۇ!o_/@Cm|'s('ciF2mދ RtzMLm:$a%q(b.>c`1lZq]z[x8fNOv|{JҤOKIYioK~? pzp-{Ü=1=)khOxZ[sxƨtPa6y$@YS3Ziz9mHƈ3qBZ *0A@+Nv|PkNNPjhFous`TP0B#LURBqe(u$Qz{FUn=I]2șZҞ!% Ӽh>zQPr!a?7eUJE 4 QQ b]8?p%N Rv0Z A]R&;" ٣f"E"],5z\i+Fa<(Msa|bhXLj s̨h ^l+$7ܴXpml[V`MKF;LƑan:KAKCs}UO<oyDO!hNӕ4)eoee*jRhTaX$5&wm&OæghAfivRY9X5cΐv&,%d34dPi4qóMd\|w1iTД(ZF3ۋ}mT^W!;l揚ðI-u^aֵŎ2bn"b)9 {o] C&"!$ukH)g'%$xiqĤ|iRPyqo-7e編Q*3*NX)}w`gyGk.S8,5@Ң%t@g ~#\ҩlNeXt6 02SO t-co:kgMk=z," 7bWyW<+a}q=1E` :˱2A^`zxM- s)2q9J ~x4rJf64:u[,\Z-Jk -x$j z*yp!DF+u[C4/e\U׼C aZtd3LVR@|;)9:ax͗*`A~v{3e.]Q;$N #(XPQ"Hd1AFBskk$5Sfdyj|&u]7aF nO*wNy&=r2_*  YC:êfkY7 UnCk۶$m+).S{^ Oj ={/տ:PUbmJQzw#-Uc`ZEAu.Gᦕ @]B:- ŕ1 >Q|Dn [\ꢒnhǘM r- xKr[w%O9Ť0} Znhk2$l UG_ ITK$_l)VU+:|qR^um\ѐo|.4Tʉ #LK{/siMp} 4(-Pb+ZKGgc{Ûˉ\2f䅵FX3(đ6& ! eȵaN3$,~u$cMX5':^t7 GxfENruF]ڷUeEK{qy2wgendstream endobj 31 0 obj 2664 endobj 32 0 obj << /Length 33 0 R /Filter /FlateDecode >> stream x\ɊF7?r`0Ruhx RwR"2S*u=CCC$eDd/"k8sa88+=o_~8Ǘ;rR_?A ;Oa'C|1\q7_n2yxrtpoHIoF:9R6?Mw3p&opy%OxC ސ5)WgG;8+\X…} *rwPQ."Oykjt>&fg/ -\ΆAmk",xmti5ْؼک˖_$,X^!>7贻b& -k3N`?.sQ{ D $ 8h=m瓮 J\[+Hq4=} Ќ, :*JBsuHdf bd^2 K6"kc)/xaA Y-HR$43)"+| +Ixng!01N]s '9xD=1.K`-ˈE8Jɱ e(يvb<21a \3ѲGMI#C›EWN}Nd>JNv.tNen7*snwd]b6(')]krW )-Dlǣ[=+57=E;Cdb-1QCHz dƏt?k~:.Sd6$FWO' S&Kt 3Fe;E=+B]x)oEԦqE\)qrTuOX8[s(TD%ʨrb}T}ZPlъ*BWbw O4&N>՜JԹ1KiPpeEIqy0,e7".QԄŃ!>w%N4Eم^>$ g ;r[°/߹qb`I=!^±Tz=bpiZs^A7~ƘM=ư^\{ wCCְvvi8r% OZ d0 RM„?fu rEHuN6@/%Z,ɌK*+aM>O‚8{0Nb5aLo;7/=5f4츧;x L$q\+ 7\YjfPzԘ)jW]B3w28# .r-.*/Dri 4iw9OdROIit디F'c6֑uGeDu)6:wX*-GL[\0Gd.znKC?X2۫=(/SZghT(FK+IA%%{uF˖"(&R3D5 `hMD-jHd e[-:(2x@K0K` Oy dޡ}Cؿ6wbgP#~ںk~Te\{=ChUʗ<{wHi%ysD}ȎÞM@ILB=1!'a)M0gz> AVV6kv00CM8VLޗL|P{g t\077 gЦAQ0/_~!HI=S-aZ3:^KV =emVչF%l( puUX+^ZeGkpJQ_=/Qaendstream endobj 33 0 obj 2572 endobj 34 0 obj << /Length 35 0 R /Filter /FlateDecode >> stream x]ۮFr}78Daߛ $Ky@2 9@%vժ M-y&0`7ɾTZu??o?l[ wǿo㟿?}B>o-_?Oo?xrtǿԝ^)Vb2!`zz}#|=';sqյiQi_w`ޒ ($gƟ"/E|DQ~<.'ip:^16A8__4yy ȝv( \p~^lp֊! ,eVM1жi{TI (2:_;u9^X\~mL9&/NK%ג?\/_`>w^g#Ən:똮3ss7] ߭*wEh.9]W6U.Ӭ>?1)=ݯ0| Ag:;r2asgښvpk/'{9ʼnp_40G9_&H\b[>E 4;P/3!u)[r_Muöt,(?#t7gZʊ&&5/_q䞚8e[$*rt?k3ZgUnoa1;)>&gp1˂ A_:L ]J3KUK0(oh>۽P-+g4Ro"]½.a2Tgϼ<.< fjjIz-ox5x.j\tlRrAL V/r~=rׄDKtIXC.ThZ 1S^Ájh0|_CYt+o_G@}0xL%)y;yY/+{OKv\+֟=^Pi,|WIXz7 [!ĶS1vY_j VaɣsN"0UMY63e}^c!8Y˦iOz KC6MQKj:g`14BZIfVشMmB! 8Mp~ѲAeƽ:G'<;;K͟>*sYb+0H!W_p٥Ic{'~RvB`1輟"[iP=aIn.=v[tѸen}m/x2-q% UI9ҫ"_Z1E͓]Lphn~1hOD6E3,\bg84ʹ{g۳{Z9):'/"ټϾaeri` cwG/dG{PpN//̶Gcl]B*ZRoa_ w.Q,S̝,3u L4l~kD>8x"79dwmQr7G gmUːmvE0Y"\2эO8=%B\}ؽ}lzU:}=RҩQ5"nJ7jbH^~iΰE.G+As !8券M+ǫ-3)\)@/J\K@Yυ\V .kE>e.|%.ɮݑ&svϱؕ-͉SZ껪/Og!i$!?]@GOD\\z61Bń\ ,V۞pxqa_u[x䓖z?.-u{ߋiwjrjCʑhȦB}6&uo)=J*WjWS\?Y}q޽V+im+\3=?kWx/xU8x`/qYgsy7lV;I|5N i3QkuQFQ{0Ƿ d=p^9z )N@ѭԐ>Z-^K*Ӿ:gzbqQݚ3v"U1U,KpH[^_%l{dSKP! yhx{p3coac#_s,҅0> # Rw} {:Fzn๾kܹsOrW݇S61U3Y 5N_ܮ++R~x9*޽\klMyG9*8^d39ja:K-ɟkKH1,y[79ԯއ0?O|7M@GKaO*l$Xi!xvlo;H5~ g}CwZ#OMi"`N:wB'-O~W.FY(uڈ9g5ټM\Oi̧sEJ+?)j>Wk5N520e)OWU!g^SrÎ|^"[z,*|~6o^ϛ<՜+0\lR]niR'e\P݈v-W^>JDwaN?s%(o~`ags*(fev&>=9~}{_4sh;oj8w0qO{Em;Got:% 悒8~ޕd^CI{3U,M֧7˛_E4M쵠Oܹvt"|f@;;Uыʆre_\UyQtĹ)([Za14몾}*}sBl[q'hVHʐHJc:iihдɑtbs$8؇:!ce,6"ǚg64 ʍxm"& @r`x 1r𴝭w|ڏز7U0s6΃͉xjL Gdb@Z* A`A$rAP< b@ՀHP'G'`W 7y82A6?9tKڈ{B[@O'RLĶ.3Da/ߨgt|n0Mlu+ȟzv^#t]wjQS6uV"@ J@9p+T=TJ)uiaxHc40"-hѼI(Nd%(ޖ$EhQ)&q,T;&IoIH /*Cbc5 b؊Y`w\')IcpX>ZxQBQ?Z-{ͪ%Nn*ϊG(:;"JLŘ/֒" X)B^A#F1Ehw ,. RlP6w=qI|"g3.bv$y658%0f 4f/}L}NbTwdF,yIl 6!v/J5X}Tv3Z HK2m0w0e ҽ]4de3#? JAꌮ)8 A"!ea?WH&45LYE-ʻU MFB?*Z" R&w\Q sp>c=x gԡo,]3J,9 (q'<@e3/`\H`XN!(sk |"$pX֎VDH"lZ `W$nĺHy$lm]6L&[B8'o7Y8,D ®TeS!r&Ŋdcpѡ0 C!l p\@` B 3h $O1.,ݪKb'N̾ K2j\ݖ7 (;^Aot˅kZd]M!lzE TmߋKQ'jIр; 8O S>!^AIOR&hu&栖fiGw-'7z9<`@m|TSaǿޜYKC†,jaJVCde Rm)Uy~q$OG0`'^1f܁B Ʒx 0 nl2~NcVeF;`1:CqG^ѯGG>@M>4Z\"cwrHFk0MҋMVz(bk P莂+k|k`FC\p݁ܥfJ <|S5 pqFZŐȆ6x7>ԝ7-U6Dr r0ڊZƎU,U }8IP.ozM*!;9b'Z)dž:؟7(sSMT0\t7@j+@m {TSS˙C"L ̈!v5X޻oC9uh^I%ӑ^ԺhDڃ&M(˲XG}ƾFSVTŏ@MA1Zvjb* wH! xFh4^ZUc e8(!+ho[45[ME7f6+"1bR%H_̐IQR5, rvhɴ w(ZP-bbIi0HsC0A7;;+\ K[JJŃ Ҡzl0J\Irjy!8Zz㕉>Rnđ.]&N[.왋.c-)(SPT8Ȇ}: AV^]%{i+ntαH_N?Wfj"WD9l6Č"Z'K-C 6uw3+ C{3fO 8#{Rh.]1}?\ KŮWliISi" ΓDFFo| `7te;2uؼc!wYzZ%=8!hF8\xO %uw+69J yB7&5m8p+J|h=b$A*rUol2趝l2$/7 2&Nhdq 90vʉrS)*-rpw*E3@whA}P[MA7>c ъ*g& "|5[ lpcHO]Gb:rxs̷BevhC&l:q[EM!z3UjiUlnt.UJ+Gce .oooV HArh PYv {l>X]+ԍcl߰aKyy";R)1Gwޝݴ$[e)ƝM 1t Ā&8 P8._Qz6H>[Uml=(+8oOVb>CwEvzpJI|`ZZҽ z`2!,BcTT To٪+ G&dc?c?k %tE(EO/Pz핳sļM`tǮJT5Ng;~F3#T"Hw4 a8[Q5sFflz;,U4F u'HXEtS6]jQe= 97.6ZUD6C( ={Ms*WksTI]G#_.&RŨ']sSrendstream endobj 35 0 obj 8802 endobj 36 0 obj << /Length 37 0 R /Filter /FlateDecode >> stream x]m7wXN (`^6hӢ 47}Jx;Nfit)j=yl>|3?_kOݧߝfvn{|yzn/loٞ>{Z?ɱ= dOI[}a=9ОD'O|k(>dSzH~KQɲO|nO2j){9++izKn* +qBf.&p+*~Fk|RaPbsRO-E)XrSg=e8FmbJh~ޢZj=N&ﰥFuj[~F)SIۏ\zc9as,n\ 4P zö˺"6&6㢽lP̠Nۯ3dg-M`S(5AFgF9ao [@O轌S GͨkC8Wl!^[0,C5ͬJq+-7SvKIA=J`Pv?ْkYPwoҟ}RZI+<8IayDT4cix6ʠp[-κ|,r^>\9aq5@Lqx #H4@& hg-'\M~\0Etim3k|*x vYK)15pb?<*ew YYT 53xrL'Ɗr qE3;NTo Բ7[ᢸ$.&B c:Ăj՘~|4~)ͣ&0nn,\Ĕ\v_fxosҶ'}m}fB(O?h"%jAW0 ?bTdȐtMO-A3TiqwoP!D1șPg À&kb &Y\GhjgZ2޹ ͼfH:{f` (pO]"YfQ_D:Kp\ӰTY8aaqǍ={ߤo~@س> 6a]D3N nN=(晆8^9^U3s|&:_$o ‡b~< ҳ i5 ACéD<k牊D a0zӢCqlEDTLƠp/(:V*ܶNǨ9t[I~ƃNMgZby9~s4qXOr͛2[Od)\3`lvz!,;kҒ4U 2i<[tQz Cew= J_ez+9 'f۶]-Jh{*9v0I+r4Lw/'b,hښ-CTlxv+ W\Xq*\N\LAd\rKDneۉ@12rdy::)O reբC٭o3%\$ m{lJe1xHL`An-j,2h"ËqG/?(H?3vjX;v\ Sp7Xˍq[纸Y3 B,#} Eu8ߊªQDay~5@ebJ.ZՇa7% Q.y'zWBJ꒑%g4ڮN.y`~[22auczj_ f֏@ eB <2b۷qI-V'\I#gmPuJm ,_ր˓z`@I ੝mݾRn+3u&LD׽}|ctyB.3og,./">3ge Sp1-ŻwP>sdN=q,>s]<}̣gOf "bI0 k׏Dޛ짱Ă o:8ĹR@K qQIJN0>Y'NŮbuН7םB[Y.ґxCBJ/bόfq h TA-M,R~yBW^b-qUՓ>QQͷI,従 nd&Dﬞ?!Kx=ĘőAdJ}ƃ_ǹ7^${3qGuKFq$IENdk@Yܧ|Ň"?ՇLJKԱ 3I>lϊ9\IMP@M~='Ǩ23^xj9#Q2 o<LjSi~1DM4ş;fGTC᝻:NڸN=Zoѩ&.Wbu Uw\y/'yʝsowTis|H*0fD_2IBn5ȪH&̗zKNmy:n|B_p6sČd*NuU@#;F_a $|}5>13~ʬ,tI:yyUFӡd>Sv/>a N ˋ bOpda+c_ufIݚi^詫Y18눏w^<^Qy=4GGG2Evpa[pc}upaȫ8K2q 2]Vߘ=mUI$(MK(MS '1%;*TP e/N_"q N`l[d/2*̋U5b(! UW ^R+~{-Rz-wwm4ڵߩǢk;/F-݋A}(i<q}b  SCOk%N&$RG[\f}ț;TE_Y,wPa {k4(wz/6 $+-R%Q磵TYJ+~{|Y ѝu Tq{VPշGz-=\kS?ˏEvfgD~t~v8o2'v/ a-ɽ ܠ{i)oRڢKo58b|[cL+dEˀ|lд"hR(ηC{Xv\Se[cpv!oUx&89x#^c >&2agyk:wl2Yɐ;R_^Gfm*:* l+\Jwۥ$~.JL]??51>H@cEu;\V웂e}g{F;$$ڭkNO@,^~,:b>FO8;|N\hG+"UVsyZm<ˏEvf''2 FyiUGt@'qS|> }gvjJ<% zkwfgYwzΊW~7w~JxF=rlFD{nr/aH#PK 5e+D è:AIPiQl'NyV$+6L,C%c5Кsտ{sS@,7nUVsn6#Ǣk;Ssylk~+'Vun%0G;[їb*t ` @XJ@abxnmҰujԒ ϶"8qm&VKtF1No;kbq{W |m^;z#h 7V7eض&PVK{?)V⵵Ԃ/Y/@e#n껖7A7Y/5ŏ;4čB֛C7u>a]^@q@.z.ylUB0.G]P\\-~ "bPh#"t?PJ*om$^C)І%*&RaР(ҏDjvE= :|o|89c듁[+7!GGk^>X(~X SxrjQ9ͱ//,}7PH@;jVK5@s[A-[Y&}T;mI 6'|o5#{q&>}:XT,@$Q& cMp]r2WCj[bۼK ҹ+wקM"vДZ]-ڍ&tԌP)v+FجQ.r#Lk,[Sq5!QSFU)x[me[?ߙ'kw;,W%~h DN ܜzm7mG/5o,mbm-T'!8GD+)O`03)F |H~ Їy0<5j@&gđ>{).X3;}?Kc$ fIwfۑJRN\Km#M@j@q 94pkLUD: qS s |Nkͼڸ@&pPZɱb1@AG7ؘmm*5i5+E\zԠ^D ?V-u "d6VH\KGk Ca:j< C8;A{OArG..1]3 9jeAHkhn o(#hS}u}4 jGh!Scyhͼ| ư$pp_? x?v?buTZOqKM"T<.$Y@E!ɪo|4zh t͗":Q{?Np'h㠐qSru~|:> stream x\ۊ6}@:dI6,IBC~ Bٗ~.I]G%}1 غTnVm?NsO^:aw||PM)96|ߏ.<ɚkNwD;vڏ|~`o(۳'تsylÞ8k63(v 5>B$*omR!z;͙x۸!KO )Zb`isQg³2|8-۾y~Uqa+L426A6͏:JyM50v6Pg:aIqCsaL*,EF"j(w ЋZ EktGCpEK-"Ĺ-q}Juaiلb<11Oƣx$JZiUy<5L >*/:{ѻ0&G!DqzZz0vR9Y|LƤ+Ɍn 큔1$W;.1Iy';4ڹI+Et+Si ֘:-KF&ֵ\,~.=\jL\)&;mJ_Kub[) )kS @^\! .G[h@I\`KH ,Hi!mx"yhRMiAqՕXjIei *?RU:=umjPt $Z 2){` QEK hwqM- ()X!'E=_B/OZ **ȍ:VLV Ƚ^Ϣ3t,>UFp(b0GI~rM\C' iht>e./o4mTlI"/zQ_b@HsԞ;F鮧lHvOR0yc-<8NvIdaP#`=HbJk ϊRNJ9Ҟ{7(X{OI*JoWe _U25+_4chG 0\wI)tQGy (YQ4I~ձ1ϝ3>?NEh,"ZS}%njY;;?@& is'^?'%'8xne'{;wvzR\&uS>`MAߓT~H5:g}Ko.jV~A|k{ ~k ! ʔlC}[ : rrqR܃Xw=*]˪hxW@灌H VX%v.ɏvE*-)ʅTzFKs@tڞ0e'¯5-f˜0Z]j=yfNf 4JfKfF"² p,u`|}ƹ ^PISjsP{Á *h6Vzъ<ln4Tu e+O5U:Ӳ_Or6͸o|.Ջ|[SE9 ׬\zۙUHM-x+֓ WeVP6}T6i]@(>d hCd1(c9SEˇ RE hƲTwVgS XP=[.X>󹚘BJ@H>)yG0+OIj=P D؝ԙPcX] =kX:z._K[ɸ4w16A1H1fj^F1f/~qcktgJ1obrtRwqHƉL⟯=VqQ%3%/#[F$cq+xs|<5rk/}r}7Ћhq\ŕX\EJ, OEYV\iŕViEmhEҊZ=~s~=hlK\iŲN?X]h6 S⩃UO6Ӟ,a'މhT7}wo2b/8Egꅵ}ѩGor'n(EЭѭًݪHއnU5s%:G#'|WoNF_lF⬬ԨV72 sKoq 9sM}>cCe P7P8,<X9,G3l7g~q91endstream endobj 39 0 obj 2248 endobj 40 0 obj << /Length 41 0 R /Filter /FlateDecode >> stream x[[k6~?ЭP&Py߯.;${I=&`G͌f$OǺَw׺o?uwax|̃8w;}Q݉i/FQ;u|cs~1~{{#vlXGVۻak9æƹiWgj:_gςY4;@&k8E %p0} E ɨum"@F d^C"+)z;AG*d)?S2QiL@]*m u-ڢO̳30SFK:E3dr q@QMt&0f%LWUPGd 04=14]!ӈHM `f EгVۙ,fs`ָ.saaK@9\MC݃&DzPF&7dWFP*mɦz8I6Ip H$%)%i]fL%]d FHzT.K_[ŢT4k1<)ņ \FF3\'uD{ Vf֙mYi^qWɅQWҷ+鎎GtO1X%l4R*$Z6i3'aI6K3_%*VKT%*_kDN.'Ѕ`C?sjfY ŀEĸUx8BrYXG#hgA&ԯԠ9hhi XHx~) B\,A$<3:C+Dʨ ʁ"e.D+tcjʵrt $Y&k1VOCy N(O%hegܲԂGk2-TJқDz&?!#TjbR*i?ڨL[bn0/`;CͮsmY2{ZxfG3ZZrʔЋHOLH)͌+@b#5Z}zΝq ClcjIkȏkMJ!.d}Cɮ(oyuV%=YmuVluSj>Ϊf *uJ'N+ dSiMV8<^&Ϻ$j_(BF02OtnPG}Jv-˸qMWާW҂Ud.v|a'@uqMcTN%..w[kB!n0a" W*_\XG7Ѫbp zt Dw*\_oPGf4R"%mj-])=wDϡjڳЕ̭>gkwjsIxW4gvH˯7!pi,L̊P")dyemTj?yTb: zcEЋ^ ޜH/&AlbGAS -l^ڒE-]*o6]-wn?fs9yE~Eendstream endobj 41 0 obj 1825 endobj 42 0 obj << /Length 43 0 R /Filter /FlateDecode >> stream x\ێ }`c],"to r vwKr]Lz jYx9H鷯_{N)9_q۟Ny}K|=ON<䧿KZF/i2|~y$g0 8H`B3!]У1F53SE0Bi4=W"Žq{ 0Ɨ1y#?Le̐jY.e9|ӷ)ٔy5NSiT?::MuYaURG63:颯:`AD, `[\F|^qg\A`f&,ÃbJBk=4,5O$Ġ"CG 1zcstpyN MX&wta@+ 90tro Lp1b$!N4k6NewNEB1Ңq^mYfg1:>tkCg ;7u1 `!)h2~| 55\1դZ.=zAʭh@n3=^"&[_~cF3u&LQ%e; [Pa4 L~*# 0}k/(M~G6&MruMJ-XZfPhjcIvCwajqNP@ 6^65;,Np:UXLГl?"8ôx,n(oYa+jK6>{Uz1 CaI޽\+ W11qFKcNip8įXf.*CjC{,R&9ܓ-`:"Mn!aj!5 7I]9ɔ 1*KMܙ 93KɄ:΢Om,){͒R7;dHS=s?ste &Kd0@LD2f4DM @?b$)3hA\Ӛ-}mk Y1}Fsi<:+)NX>.n`F)Ki +XG͎1L_6lO|/cm`FxžF-ZZ\.ZkEequn_T̘Pjg0#3%\ًi peUϊw2-PsJR?L#AxJ " w߷tVTHhŌ첓n.-_Ej8IyY7#J̺A7}jɭw2'9$Fd,h]( EQ6V~gZMtI>WK3Z2xoC+3mp Aߩ >:qk:3Ѹ dtq + Q>a<0,CUT]Pk$ RTҌ3I`G;#pqPQ:(S¦qqyD`ba,bҍR,1:"J ԛAjv {;7Żr A_ ۠V[d_s{7BIN ~4@|?zbh MYCj%;L>LDnoy?a!8~B@g|zV{Vwwk9@b:nw,7͕蓹iz`LӉH 򴺅%sOpׅĥz\(y],wOUr2}kaŔ~#Rrܽ6zlή'L ZZQJVɩchKkrDBpIlx,'Џ1ItCRPd"3+a ?,S3uL2Ц<| h:pk_8&ss`w{QV}7Ssh9 ra+*RUr ?Rۊެ<Q4ظl+p~yl+l+xg[t~snt/0mfqj.hm4iVciZʿXq]wBnendstream endobj 43 0 obj 2729 endobj 44 0 obj << /Length 45 0 R /Filter /FlateDecode >> stream x]Ɋ$7?YR*+>Р:4"*,{xTI tT,<[r:wί/_rNu}vso>Nn:}駘x_N~*v%|]/ P+vAbeYPD^nHߗ|_BKsJyɷ\,﾿9b{ooX;gS7dEU>lmGY^ ?xߜ?U^cUpT^K*ZeW.`KV2J}?$獜&fڢUeIU%7PGV޿ VqQwh} n(&ǠZT"Ԓ0Wƥ{Ppo4wqnQMo"T-7"'=8.,7_w?̽iܹm葖Em=Z>"Y0d!' 2#fA/QfVdzoFzl:Rl6ϫ%##\~0: n7thi90o.uYw,b(|i^aN9r4s3K,&/ 47Xx3"! ռbVҝvrGaٮUMݸ1D#QTwsJ)lifҘB "} Ҝkñ򥵳{uA2 $!?Q'<0= _jxş<7"&S6ґ SBS$oWhq=?Ǻm19zKTM:ܻi4̛psu!RHZ Dun&jarNsT‚@^P >:1\y&~d."0+M߄!hH,m4ŻEc8o4C3lp;dܢQZ1&M1 ܏-S.BH%8v P:^?P@2:!i9Z03aIy+Cn[Y|ЅPhUHu"a~ȡp;*^?[iw[crWZ0,=RGZwrc"oEJw!ncZ|+kdGScκRW {G5)iSEXW2m$Q󼖑*g)S&(GvT^HPLL18VFfɁ<+ ~IxKЇ>hK͖x9kXDܠk!ti%)=u14@8H̜Rq[-t͕=a\3P^s@Pw+g3П+g&  m /eJFOH|fzJ'CY#L oֈbf |<=s7G pY4tLEbE]xbC79!Nt~ }<)N=oh&mӚ};FV e%ാ@m_n~g%l HXz9.k\ohm&÷z8X%WPh9¹Crԟd H8RkDjq +h9m=b;ay %Rp-9bp 5DjκX,@w,: mng(.2$n"h5DGB YYe$Y~Ssb`eїDhUE!ҙ%y4TA ~FALvl-7P=bHckYzX E{.F$!k)td  ,1>^Cv#<snVQ`a ܣ2RN$ 7\J7/QR<)(^e70a]뤽Iװ`ђHsaD$KOΠOrCϊ d+x>x9N*h>?x}AW3SMSx7:4R NySh.bg\Afʿs,J (lN#Ʉ3KvDG]iyeY!qtݓ j#ӳUs52bFF\鷰SA%WK4h%Y|(ɤ=tvfӕ0$.% =Y Yt>|3lb ΈqdǾ2D,?JX7hKݮw kcGJXtM1 ޺]Pd A'E[ KPpl%$twQ[: Ƚ` 1ķzXp*˱T rO2zGW[.#v:M8 4,J+YLQI"sck%D@8ߜ)M 6i[-d.gM;ohx! IJb p0ܯN/47te  OMϑ__<OD< No!Dc=fUX]2;3*.igAydV;9Dr V Ng~nBP-f2I) Ű@ Fjg&=7﷞, _J^4EDؗ9B28~'+{k9K&mx2m= >ea@:2eS~'(LQaD{5rxzFWXUcht$5؏Q)ia{vd[QRNEc#ZIF5ĕhsٻy ~0q(gc=#isI :XԱ%2Hjw0Cgg%B(RȻ3v" #8eUdz%35l 9RZA#1|{nz%LSut*\ߚXW wC#GzQĔMV1e=S;>dpܪ+Z6=:79t^/ V=&CoА%-2u Xnz%wQq1A'N#B?MCH$$X6Fqb\o21͒ψr{pakmphkAߡߕxauϧѹϺל> stream x]ۊ$}g۩{&, =U  ~0x_]T)fh TJq9qQz:_'sƮO?y_y?~Om1o8f:|`=|O)%'ɟ$>yLȿϳ'g9YzʣBOle ~+h)'/oO^cuh\uK,x[6R?Y|9xdR-$ eqdߋޑA8#l}#Xe$'(ಧ_5.'CA⬽ PNT Ə$&[#u aghF7 <|a@r+q bPG0b#]@kԶhcg{E<#N c4b3} Vd^8@PNKyIQ#'F1H-1gm ŘEd4" _;ʧU/c,%y Ⱦ03t\7_1@rH]4nKq[@~kQ! f V`gOеJЇJ2`0Y෌ P2KUѢ4i@ /ѥVg(P%g/(jGt 6}hF(qAN2ГKf@}]yZ:4k"kx\e+tkO*tՑ{>,aRmQeU*m4B&4c U&*60W) @/ zn#> #(,MEalj%D z;%JjQ?>%X.^{^H-a v2 e"4c+M=#RYMZ M "4q2Ziy8)b0G1Ǜ 1b-R3` WΕ)jc95+0[Sq.({" x1|q$zV7\oEo=z4ѼnM3OfO2]. o&}A-p5W@Bm.%oYdZ( %ԴU@YƋJ2Afd7TZ|ʒRzDS]VsQW'6D"TC}Ш3 :5,Hh$kAP)AJ 07BxCw ) 4'ržSw6G%woHW{{"V/B(مV($ Q z~P!J^],b|A`y3BtJD$,dsY ¸aЮMx|Tfizf%@k:>VEw&8d+Ͳ >b{g/RV|,b7,2EyyK'Dqܖv]rE#1$,e_Iq~z{V )yU-TT]=8J)>k7stqn9W\^OȌ{g|z"87}9Ix<}l{;X*\W_b{ǽ5=X~7­i3թCeC2xX~` c@S21lުV i&|&,d_t 35(d:z7NX5X)]> stream x]ي#}г\ja[~a?`};KR.URwOψUrDd,_{Л8t?_z3/Yy͛io6.OFw~b򎏟/'G9l|o!>15\qEs}q~;?9l«K7dH;8ΰt-8;5bcdmuDF2:0-[%68]v_Ps^陉BwI"*aHҙ 2J NcL$*TNQ+CQv > u%~a/>/o9q J^Q?*&~o*|,n-͔ҟ/܆Y^T,D YM 1/Lp"VȌQ(3:@Xfx2$e7LCxPBƸ0ԓa©ٲ038`k‚ tSDCp& '=at 77^k/F Τ'dU(3A$lsCPǨmY66eS "܋+B=]8P5@N GXyʊ#+| nDaȉv7wiZ#8檩sa`;`V0djSHGAr:vީ'#iX1R8E1vJĭn; _q_|'`"6Nf*kхp8\YFAr6v1}yMl'M)+-=E(t1,)FeDO؜crs(|s[´]3 b̞ǣ&uzCLzBς:DVA viiĉ~2R]3[1/5Uh\tLbk.]I.8,YCv]̚++涋F2&6xu #j}iJ7T8rTiF#]n/7(%[aʛ%>7~ H$тuGbK'Aa ٷ CEP@VP*fp4ɩs=~N𥘃!*BT"'2IvZwj7Q~cCmzzH[kǜo!U˂x%ᡤ#)J{PT (J>HM |4R["fc׭|o#ZE 20|ؒSOr%_as)k}İD%_ioۙ|f 3N޶F%+bW[=DGu$!@(LkxШm5 paMO+;u)hLbN8'[|;  3#jwTaVٗbZq?S@߬=y^c1uڡqJ&$8—k^9u&oڃ&t.zvJk0o$26\uH*;1|,cRwӀH!s9;CH; h9!n*$ԅ\RBn /z&1rrCyuz~DBК6Z^执u^,OƁm`"e6AO̸KTlNN> Y䓔Eh#lQVcB:lj؞[5+.Bo-FR܍l}J@P2d{-7{=Z^m'Pl9iE..d&Rts1uz/QTBt o,\JUVq D-* zJu/;NOC+]^`{>oФ#qK쭮tJw`ͩվc;&`IAI* kGmCӏQq|nj#jF9ݞ >WU9+Di ŒR Eze#*ZTJe$|5(4qnvksu[ߩv֑hkfz^nvɣ]Z^(Gws)H}G/^DG'{~.wcL{t?:NBQbէd7=Y$YFZ*)K>.F9,i&kN|&8ptK I4u/װJDR6$Ih@y(¢jn_NAmYjkh7>.oIjbUՀT$wvoۻLЖIb{t۹/7܁J꣆w_^iKhAL@`VYf,oblZw_r+$w&|kpL)Kk)]hap)$q:*>ln6krlZ]G%9 o(ou:o1K/x*=Pk˨<9rVWH}fg8ҞDe/R$zϖ9Rc41iL(>,+;9k@zƫ=h&HSGwre~Sby݌( *bà3>,}-'8t_52r9I2sFwTJMVЪn@GSl}][9 u,.P}LE7TK a:+ ll^чYf i"|z2³xy3\<=vtmjZc_bDޱBu\|%wQFwiwfͧqa;'L睋<|@ﯿ` Mߟ1R8>1$_ +jJcޢSD˕*ȖдC5Ly*^e.GrXJBL$=LDNJ}gGS a"s{qΠendstream endobj 49 0 obj 3410 endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream x][8~op6v|I`X>,߸X'9>U5 '8,}ZY.志!\Juot_ۿ~ ey/5Oe?/?KzH~J>^oWևսR<+{*][Q_9]bF}2 IR|GNeTJ}^vB/>JDž yHKK!IRt`:T^; ~dzRGw;:o5μ! =#GNf KCY°l4Iydm1y|_wb^1,MxavXH ۉ{A}3<,'F|qx"J`CMX@(l[6X.: ug(|ڌ5Mz"7LMcSs,{1e=w b\99E\7v/v:߃\'͔ NaUI6rS)A"CU7 P(Z 2X ETr*M'[ пU=63TWK!&U Ą3@CGO T0Oida€12r91.g"fl4WoA12-ZMr"2BNz`;d0mF ;3cGaȈՈ6b1Iq猔3v;.{6Pj9|_J\)1#0%lMwZ=3EN6 N~T{(#v7?jVrIÿV\5BX|k, [i92XnY ";.{% JT vE$GF6Ҷ{iE1DN"&rW؉ )l$FOK,Y}nN{{9~zHtᕶԳ o+]9\qA{y% ,&cTʀƦm#Y եÒYDx@Jb }rV&гhVzuX dinCR-7u IӮj\E pHH iCS$~:${qXTkY*wbttEdHD %![]=RR,DchmqD9ƽ)P.p 4wb]{⮧FnY4VCە4~pGUx# ХuH˵,K?ͬBWY;p VΜr1H'7)T=ŨS_`J^,:O}xP/  @a퐣}HboĪ 3gIXx  J5QO0'.c/^, >3aɝg`ǭN]Z(b8)Y8GT$ťSJ \$ $I+47[W'UVopiFrM˛{$~fq0)>Nu*{ŕj "6<lm =dİl.R  d%YUu*|f[8hyȧEYRWMN`@Pe/`&w<u)H="7,DFgg=GP׈J 'wmV!hsCUY{C^黄V$>2=oHAs\NTB|eX#Eb/#N|:du^zUiޘv=bo4֨'fL8vbzZNiߚV6o6`-ЌBɆD5M١M15̸A02ȃ3hT(K=`=HZѠF(nUHgDz8g%ft)N6*Se&K W4M …:ePfUC@,Qކ+NlWi![øM 7"ePgK&89U@MN d(h*hlSj! #G; e+!;2K)R&t$=&c ьcmta *j^,Ҟt0IQnñ'"V>KDF>5Rsp:ҭF5 Ui ڄQZ'R*+!q'W^.΋L1n,$ܺ\`- W5F m/lz>bVMVJ (U &|7]Z<>SܲnM٠jj,Yn^IňZ bÇ"BMa"ǺGa=1XauVʉxt^c_^5,&ݷ1Rn9`֭^"jҌi s@2.NI -Emu.;{(b3'GG(@`NZԔM|1->;w[of#a޷eyy5[-1[K"V;K-&,m6,t!(5QlBː^0ʍW)bK N"ꥋۓT &nb]2j*!rJ^ { "D˃wɺr#FiIu2NU"}Q U8po1h:uvח$}Tp83j}9hO=Gs#Q'& 9ibi"ޢC;6aoX76=NU"^=_, r%8"."/6W|" _V!TG؊N]^|aPv[G͠t? &>E_) ރ/ٸ TWhuz@0sQ}DŏW~VfbNFoj5O؋xN0qU3Z卞gӽ9>ڳU:{:@se M)>sUG0 6`)ȺuB>'+VݢlZL"t/F`fe'ݖj.v< ؠaԕô_9> u"Vts#vǑS;lHû;&Uxt3 'M"g[f|ZT!_}F4ou|x NV=Kvu}a|%*:aBd׵rEg L|aS}:3EWSX7.u$  S_"jZ&bӇ3ᮦs=bc\x& 0zGBɳEii`~Ig+^I~ʻR}+nPBq:tnFLʭAN}G=A+yħf8yf|:;Q4 --C||``;1W^ ͂~9{{!d܏NmmZ5ͼY yC;wl|/] xyts;iX9qm5ѷ6T#fo 7pG{s_+̀gTLO|o ;(Qİ8,A)zD# 3DX̧^'09O,fbje#,a܁UB(-՛X0⳩ȄtkK.(OE6[~g`V ê3_̣ FTx 2 Z.%EH>Oz+tlY~"`1&7ލ chƠ0Ɓ#}Ϊ.8˸l/%ޥu 79"3><1&LaP 2i  '0WEbڱ6Z`0g-?+֜f[;s#|swBωQFmq0L8:|8¾ɣׅu?' #Imu2%Ű7l* Qg< )/:5wYendstream endobj 51 0 obj 5044 endobj 52 0 obj << /Length 53 0 R /Filter /FlateDecode >> stream x]ٮ$q}`> ur'??`ˆmz;q"E22`2rbގ;[voi׷ï?ފso oxo/GvS{O篿/ u7)MZ<W߃|OQ2U2{{iI4+<˭G'D˂hDɓ&D97>Mc7=WD*]4 yb|' x u"r)131FD Ru'(9SJÊn|jk\rr6pVhoE KofZWg:nݙD~;::_[YG nn$O$Y] ⒖j n Qmgq)q{Vn'ˉNy …|qs>݀] ACsO:+ndozVgVӠ˽Ɯ%/l"$wom&[׶( %`]l6]<-RaQXv^1fo[~oXgD'hyFbWW,_>q^I}s-8i ytَVt3`n'@eb<Yƹj~!4͏4:xqC9gcNLU4`/'}=X&w։pg[7:PJ.HM{r:a٫3V1WҐȚKJ.kup=L踚bjka9jsĚ%T͟'Vj~E4CZ9뵫ĹA4L Ǔ59KAUۋyU ~m諻h)r,[xp0 Cş"P)U"fe e+7moc̺ZQdRW] f=J՞Џ>(%,{W xsѿٍ_ &ٟ+ҷ(Ut"\gZrSztKg~M.H0w;n^;xgpLfYSᚻ痀bv7̖S9n{F^6Po su0x_0l9nYڧY saKhSZ>[t#> mZ@^tOtc}EK_'hO"cўBט;?7Nπ0 rKNc']njKTWo ̈́l1* цId婡ʼnҮ]]CY!Y{u~2|=|3[5ycj!v7*TK0­LCZ(ćbtzaM|4l#+iQx/5כ#)mF)aV[rlM1ǝ,sfbmt/\@duZcZ;R><\Y ?SX=h2DJK?)PAfRI1O[Nr8?X1_UzYcȹ,o h1AON6^_ U:״֓oB?1񥻧AxQ88W>6Ը|ÿ́fm`]=X]{jGn06}M(lٴ}o 0zn[k&K|cn@\טXf}rvkEnUݘI&?#Ro}TY-`\-;[~sG4yk61`߹kʽ6tg|. Pd[ 菚g5=Own7Q{=g]6٪Ak텛W&,X{/aEZoFolIw|\ .BHKD.@ڲQ.^o:o?*ϗ7_]?X@\[rx\W.ݷWqڟg7f>rG+W?v%ߣAЕg+n)f6)U5Jw[ܑ侦5ΨQȢ>Jroky&wii5~D:gj5-ŗm/ܐxf-E[4)$5wַRuC}tt.i#<9t;Ǘ}ַoo}TQ[QzT$G2&9ԇ~ZxG ~sdI]kg:jo&4hS_a\4a]\Hf^v>\G4MЎ ;s$?OЫ2'ze2o{KsK#:A$9VlNy D0@朋i/or PCL8U8@#I<ىr44pJQP#'ӧ9XLrLؘ> LJ];J,|\}&J&]nDFrS0+ؔ Ledpx3~#8hϐLreT/9$]MqU aMRe'єV ,Ȧ2@L 3LFYq&@l@d&)F2 @^+XOVh$PNb!0 ?`&#®FNQYooO?Q|>` GbD䧋C2=$Y:Jh*RyDM'F23ST<ԭ҈90k).:0:);P}g3b2˝`- .XhT7w踖I * I*0Ad"hRyɟjP8E%C".f]آFh eX`4&УcUT+嵘({d1A&f᫕ؿq&x44/E>+x8R[u,cXM)]WypPL̘11-S' t]s|l)ZzxQ/*uʖxvj"gW 3gI\U5:U>R'_&h%?6LԠxAC0<|%6s |+_!`)rG[l*b6"8?3CbiH`) jlFD İae嗄[=auQ&)bfE Z'SPu*FGKv?k)$sfi[#\YE?/IGo}Z !8;#)?.ajEZsD}ޱ<ĺ GRhBe )J, ld5&*kb֠1E:{V bє!cD{f!iU6=ӋP czT#9fxN4MF/h0| Y$G4mܰ6M+x `D ry0T%=rNC2FmYkMєEN3dtq0g@:_irdEE"H00K)gץd84|Zc -'3UlG;*{^K! RY`Ew+Hr3bN:ߐPS,HbX4HhZ%)&pDƌD j"$0Ep& &?}oѷ->Ww&Ca{d`  @(@Cc+I\2v3U`2I2C@i C 0x^H6y1BP1Pìm}cw(F=9Fӿ2j(j<-+G}$ wY~ҏuHT9,yC ˓JHI+y(KԺ>;sduvQ޲ z* \FN7o5A߂-So}](3q6^±Nja)sT7lWQ @sb 3&`+k*ZVEc.Q~ zA\L|5mhjT@]ĉ4+T mM_T.xSn|n7 #ʉ+6.Mt=$?Gm8ta1:GM2N !y9P<00s# LQJdBT0>ajΐ؆ (&c3+^jJ k023IҭAÁa l :`=uFGBDNmɲ.~|H1@96Ao*2nQauXƻNg Dß%F< ެ{<Xg%@/=v5GF M>LnBXylK"rmG Dwa} $Jd( ["M0c}3eɎ+T͑ ח!' ¡ŧx_eٖ6B{Rx+%Sȣ^k}EoD7b1+}D~'u6ˍc#re,=;uY]uauY׼rBwFYCeSPs#%rRxf s 4"Q~KYnX`mpi9RB60" }r d^9'`lN1l R[f?#`ay=M1KmH/n`X(Z}4s06R\87G"%pHI>N'=Pc ȨّPpXt y%;"{@iEe|< c%N:<@M\3V]١BAO`Fh12 (/ 2Dx{1~Et)0/e* ro {LNnިIZDDr|v:^B*|j]E焠\b#LK@6d?a:}&R)<`ZOSdimx1߼IQ "l\^1QԮ1D!ucaΌ40s6,7,0bCHԼ 翷lۥ;U?Nv|}wjzjC˅@ąp!HgBT1q9 X$W/$W&U /:;">ͩ=j &ҮȂsQSd42oܺ >F% D^#礏-t*IQPqy8Mų!vaqA3 $QCID%?T xa/6B8E-WYL^e DTfv_}p6U ZBD%Q%_%"'s2PjBViwtV01BZlC#x*+OlWHJ`8͙|TI3%id f"> cK WB;"$.(bd2 wp (.m8-2 .XW1d Ƣْdw##2ƧH#&0gE0¬`Dy(QQH f֡=_vz7iCR\|uP@ĐzSdGĄCсg 1oE 4]MZ3=MLSl/$Q ¥$ͫZIfM,rį#[wv1)΅MNxvd?%iBb5TgD^]+oSuFKrȍ+F rBx}ƍea!*mzj*]-J(?BNSL="SA8Y1Y*kX^L,},?#LpMwwҀJyR}\imj5K!!&bjlc&Ojt r5?dNPE0yNs"]]#nȖ%t @(w>xa.szDߛ(;N}v|JG1!U?0:iK/ qEMsa+pHw)Q A/1z @ր OƵ3 vqJC_h[nHklʋ@C*LC4b%7:MBM!" Bx@ "7μD3bWDbƉܡI^.(0 rM$ )|k&HIA\z Xds(TUSǸq@$V*9CQGi:}H (0Ȧ4@>Ad @J'&A ܁B/O+:e-lzib "*ؐ"9zD& ~@aZXA:`hB?wGӪ\o:+BpW`i9\:'@CJtj#HC3RGx|,v"ZjtwRghg;>ƚ)qSkp"!32Iy<[ }mvJUQJ,*E=(45>B^i_m}_ƽyi Jtś^gN1ՙmz~ &xohT֕R߱W 퇌HG+z5my?\ЛqrQGã\t/.(w<5-KL 'endstream endobj 53 0 obj 8907 endobj 54 0 obj << /Length 55 0 R /Filter /FlateDecode >> stream x\ۊ$7 }_@:{,ݝ@.@%Ww2:d dIv}{7~j畎òv]q:uq{{uQ=hϻ?>w]1mqFײF&+3;Z_R>}f-чmX33~+N6rf$1js((reN̤+D-?X!N)~ԛm^eDҌXjިY#n 9lu_Y?!2hUmyAY;$xs]@%Svɉs33m_ULXxexRD|G*RXHv8Rb7?bCݱW*ݸ)P+sI?]q&lA-ro/KnCEPyL:ఇj(./\{&;; uD9&Jy@;HtO}oe&%Rӄ5ْ[2\`i2pdJW #O.%JV000>^36Yu'+jҁKQ;!]M:7ryNǣeGZ2$}0 Qn`O0ͭ,ha6bdWxM je^!VGY\{hZ s+Jft&ˍR$Fu3:1K>lXQNd쎝(&Ho|W?B& pN̾x9ZIQ{Bt֑_; Ymނ83g'\hߪ|Ÿ[KRy%?CGL_Ce pŚ_szT--Wno)ͦ|(5;ʪOT Fp>5*)@9=]OWR*ohd@‡pRmfozg%Ftؐm[>k8h^k@k.4=B}MzH[Qڥ\ iϵ̽dS1? nZRE{&> stream x\ۊ#G}j+U` nа?^>,x^R+/n@K5s:ohl믟?q9$cO9f:<_~<<'wtb:i? D<nNVݘ583g@bש]L`u񜷸 @$5B:&^ $Y:ɯ'BFGq˶/J2؋|,d(cYF"iX@A*u}3wxkIVx"GyQ6:et>Q6kA{ /XHؠm,"(F)sRۓb.R\wu@Fп)'e !$kI{N^>U@sFs(#̥"zEւؑ,7@A9rNS>u2"aZb#/- +1 /YeUqE:ySdÈ^Gx2+7QQu%$pYfu}O)_GNtgћy4MdsAg ]v3KO:Z~cӌA;8 xN mSsX>A_7m`$ <*հtxYFK0"ֲ2Ju1ԐI2q9*D18{.<H/eƗsP$nh6R8M!Ub$yT2,ʠ` `ez0=2*tM G)P3ebd _ȱÐ!&d;u+¦y.ZA1[lQid]k]Q@t8QSr27t-|5jjIk6@Hj? Ceai*9_ us^R0opl]Ԇ li|n%jVLɖT95{ҟ!N'ߧD!Hdw+A1u^ESW:j3Nhf(vQ4+}> iO>^_tWvuQnM# RoDέ C~ C wuZYyY'y+al_l^(`?t@VvFzzѬCǎ'^qgB%I7gaKwіO[Unᢠ/p% 2%!ƚ\B/=4А+ XtC/ŐSը M;du5oa||A=<3z z͢R> stream x]ۊ$}g). SU8!{LI'.L}tNy-/?ߖ~//߾~qizZOٹӷ?pM'7S <}/i{v9nOO?_l @~ۇZY/4Rj FsUu?h(DWU%]O`IK1>w-Un/d.ߎPԅ;??chM4vTE j<3|ƿuƗH6ZieWC^ >sǕl;GKD:/u-kSG{Pi]n7?FP_HDԳ<ƒ+AvI]=6ؒB`Z{J;-J,JаRRAkSg_ָޓg^GPvNҵ۠#r\m }HD(ꥏP>H+;'wrW!<ԙ䧚q'"!M񒟩ਿX6'7P׉Ӻf\zs>[꺊JX#G/g_X,m+ ˩V*mxnB r,qhOi:m*aL'x"EXg|,jVbqCͬu̇d<2"2Petd^80M;CAhHum"tuhKX ś1*N^r]2" Ȍx1r4δV/?mH?p!m',4N0e3Z%sg] ScM%9D;QwZ) `fY.Ee_w.Cd6(WLaWgF|QOlhp_HW٨7 nRF05q1,ZP` aL}Ƃ*kZbqs4d(&{MuIlt :m2sIBtXeਗs D\@_w8sĒV44/cIkD66XIB5{QE׎b$gPZZL^=vw\Ν{!'0H3d;,= ![;e֤u7#'QzoyN^\D"fJ2C\ɯBqn;EuPֳ.ٹ֋5uP^̋QEMrB?Kɸf-X &Vv|/@x7#`X1"CMl!ل.eIh?bkSÉL\-ᏽg{D]K)6~0Wb9`6ADH處̆[$ݰsz5&-"" 0CK]vye6q \tA(I0`r5c҉.8 Ig՟2'bIs1[6H+0_"(\JMҁyATF,Yz)82 GcE 0SlƽDWXvEHxurDL|q6S?G|yv+.Tt+NTu 1z0F&/u7fp) o$*XDÏcFV -ޘܮcMca]H'7GZak) _j1wwv ˤIѾ)4u1ۋm93N zJGv*Q|xvXY=|ڲKf@v6/)~~cp܍DPUʡX{7`)j,`,w;aqIUeh0kƴ˭9^ԹUq}"xh^MRjP8;,5 1~ȣy&~Xq؞բ5 fPXjы6tTkg9lHetjlCdΊw g.0fj<YYVhsGG^]d"#]~GU6ymX Q]w[_ ^)^E1/Zk xhLA`jj͎u|Ps?Cs碯~҄:iX9(0~ٔtcd[˔<"Q9F1ϩEH 6ZK! *ZTZj ZTs_ڼ!SuB::@թ]uW(V Ig8f9%q\ǭ-y>tZt#8`8#Z\b/J/pZϧjendstream endobj 59 0 obj 4417 endobj 60 0 obj << /Length 61 0 R /Filter /FlateDecode >> stream x\ۊ8}煭%YaXK}``/ ;/+g""d2ghhHuˉ"<?~BG?GT1c=L<^&~\Ƭ~O׿U=/¨Hs`$^ S.]ɽ?[˳%t L7Hq |]zYӋ(ڄ+Mh` eVxẓgZ^-A8>B,\N$_ҠEΠ?By+o #l-S<t3yhILhǗӫ/FKYC-EǢ%sTR^%p Y,TT5%nL+,zBXbŤɞ]mF"S<&~E L-YЏ&4IOYSp'L{+Qʨԉ#899"m&IdJL&Eb9;)QW&SCLCA:o@ʀ\ZMH8 Xf՗,3PⷞYh1աƦ3bObA{}{/ٷWQ3B "VdGaC7tZ>m*.0e;uA4@հjA9آ5w'sNj=5QqBGYGlGӫ ) xFeAPwVfhŰ#5LaGRl,İT{ *5ayBC_A 9ѽ&i_"WYĪ pM@J(<E0 1ed9PH?n1Lw:bCRy`HTZ-mPU^9cB :ZŹD0f6hx"p(R$œmc3`wpхo9k,) (S4[~7]z0\V^]Z!~N?V}Z4B/"TQw_&b8-X{{0՟zʅ2ber~p.5K }:~N Y9`eA 輵<,8\wȌnvȘg >]?wP@5c&FAmpN7W5(u DYJCmiwMT=Ce g4λro\A~.Fc Qg[W-xs.'-kca'G'kdتS-=QV=IQuepmq[R^kiɵhU(S֖1D SÙDYmIoY]t 1ϟ2ecv0c^EeiGɖEf䳻*\Z걚pKP5+zD.,(ʜ#lV)EX+L:T!,eU#K\rMЛ/  +lJa 7ZԃiHGڄMkŧ.naOGlZzs͂JRZu'!^~wGy n}<~wWo"+ 0Ne0EjO!Bf}sX#^*N 7#yܑ,j°;JwlfQM0,>l :ZkQȬ5 ͆=1{iFVYtvYHֹtyYϰsVXcIa$΅^td 9kύICRÐFt}|`!\s擡k$ <@|)Pm4Đ;~Z[f X%Lk3 ^_B普҄ئ}ׁ;y;d$7rX3f% CK|għEݪnI-u.8:dof:ɠ+IԹOCuS3 ͘KW3֟1ȣvO|(N)N8w EQ!N, ]F3 ڣhK oʨ=w x6'R:nfyv}{am Xw52Q]7O&>o9B1}: c~}"6R v!'(-.ֱ!KJ8hKXSmg[KDC{;R+ߤ--m ;Xդg{ަ/ufMSͻSOyJ`]HX%!a7;h{aקp]J?{hlDYG'QL4T ^ǮծmA?[()(i[dVt:R驽KWX_lGNڭ.n゠ݭ.)V]4z Ϭju*zVՁuOq![ғu*1[U̠ڜkjwki\Լм<ԧFN1tx߸`P`D@7P(IVک[trx7~PU*>|*8okiʇ3elz o,v(|_>fc\[ q]lقEԥ=Ap 58, ˂־iGdkmendstream endobj 61 0 obj 3822 endobj 62 0 obj << /Length 63 0 R /Filter /FlateDecode >> stream x]ˎ:?zeYҝ0nn=htփ")HݝOݹ?-y^]ϟ?CwOO?i8?o!o\eiwؕCj8/KͤoBh&<3Hs4SzHsɜ٧.i}_iL ?1\w13#_ rL&M~߇Cz-\g]u9:@uƤ:IMQޛ.+szs.cmo 82_U^2NGMH`ԷTV$%&<)88y>SaVyΨ(䐇9ohgV%&Sqt?hpΏ_t"Jo7fp7zQ6]ǍvgŻ:z/h SvzCQ n=]/qW nlՍFAQP*}@b>#=` q([=׍џeDQ羦B>Ӑcql~ 6dpOIs-Uإw~Ixmi#qBˌMD~yOKoxbC2|liڨw~|"h}PbdLWR0_Ko60xSiràƛ%;S?pLFhՂi׆rV-ogb4-31!\«;~$5`EJ Ȩ%hh Qkջ3xƒa@NI<@Vܛa .--rjvTiƵs썜ZE#š+XO)iY^I^Aԟy!bRP9Xx0؀ jĎ 1HLBGTRbM r FaR)eŖ ,[ HM=Ⱥ*S-ndmѵ^Wq2xqyDpo 0jݰȢ|vR '5ԏ iwT 440J\d9^8CX<+w1:)j4jӨaqK ZUϛv' 䩨@{ EJzB\| ʨwYGM^7pH3\3&]{L)NnX qO?5`f =WiDg:X/`FU8X9`4%?ؑ4zjnOg9J48]n0 =mٍB܊YXu&7րR!o@ ~Jg'(@yR C@&&*xZs,EnS}o~U~5u2f6C6dg,YfVXiSR(ƨ3qXJT9OZ%I(!X&B\ȃ`ƿ R0%yE0aU7ż)sl;)Rmn{(݆Z~vy+iq0 ;jSȔ rJwNd銱> OLl+֊[Yi@6Ka[wJ4z2?gy3l2 n(琉j(^I2ZJL0/0nz)!Ub"; <2?N@Q GZG|fѻ =Lu;s\Th%VXa};- +wч<}Z`? -h瑫 آ!v>h_b  оҾD4Z11Z}ڗwkanE$>MxA =6]T3g#~ ٰY4_xr]ա+v,raZJvX$KrS6AG {\F(a[f_ctz Y,y94!r4 vA;)d&Va) jr23EGt1%룻nW;効v-=9+?47,|ہFjQpjK2c1+y.3ڱX'+P]KX!%9E y0ַ0I2}{@J A gn17#\Xb"nQ}$?Ӕl5/X& ֘ʉ~$J{V Yp.v8a8 c(2 UR#JؕMRl%r4KZR)Ytǝ IXnGNoPpIT[i>oZF).E$Sx%|VJ>9 E{$_8溠mO ךfLӫž(&X.p1<y c8~qϞhgj4~2ʬSqêsh8 W2eZG/w7?zLbӅ@y?l7'jˌԶi|;q |h3U-HT%cjPnwWakf|yP)ЏެFTAFL"GYe˚бX.fؖT4%+Dw^ΫI}xP;pBtŭ zWn\-w-f0\R~+XgQu(9w%IJhKx2#RQۛc,w>i͸R14V۷%tE P-rIN3ZI}LâUZ`VS.B4'?ӳd9pvp$a1m 1~˜ܫݪ]L5"}Wǣ!50Ww1gorjhJYCY A*Sf\ fP~h??s0ʍ9qL =rj{%aXM:TwomCdqmiXȒ PenJvÁaҩ y&(7Cz(Yt#}ʟ2OiA Dejy+0h`OS5sচso"=z CxôK C$ݨ6OQؚᵧPN11pړ&)U\G >9_Ӹg^:N3wcEx/;a_IZT9-zxrۦuoSn9`8=r#2U+)5ZsqX/j Nxeoi(T1ot<?FKdB[Vd/5QaZyn-'edl RZ,U>ʙMok*wY8P:<Xc:R86"a7? z~endstream endobj 63 0 obj 3322 endobj 64 0 obj << /Length 65 0 R /Filter /FlateDecode >> stream x\jF}_?s ]%^ϼ \ K~?}:եެA=R_N*i{ݰq؛]4vw˟w>8]2fۙacy݇i_?&%_[?fS)-垦|b%܏{z=cw=H[SYh EPE#sāk'O}f!*Prq-Q''7 (骃#Gxb=Q'r autL'M@0eqT /e+_4|Pg`O3RVQi¤Y(3Vq<,rݢ4Uq/}*d80'Z>jo*fm#_\3K@ ?cQKYmp (G qMj#Gw|y۸x^)CmZfo=D1CE>]Oa^&u8][,fZ8fP|PD2ӵ33bmq&*yF=:+pGٞ/׵JTN1a-Yj/{xͦK=n;u-x9egp[Pw\?v9PeY 4j8,/,@3 52l3sdaՎ(IF@N.*O!Z}ޏ\TLÚ̜qcc.gg}D6Y^#Mv˂dMY$l^BO#N2Zp`1=hCsJ?e)pv8ՕΙѢHY*gMCڂ۴i&E#࠘?J0vCq"B 0-#Nmb(! ZlBr`p k$4DMt=6<^ijN#9@|;XrM"yuVO2Oq-}ɇ-T.eZceD v-UFw=C豒K +&TMI=䶆N}VOZ1iH 3?c$"Ґ5mT251>I>Sȧ(a☌t EG@Eh'] ]By\,=7BfnX#oVEmU r5S.Op6f,JPc^(51[ ;k1 MD|[x_s-M>jcqQK!Y;jg'iF|TMN1E9ҹh^|Y=ЗM3g>6Pbj‰:2 -b&B]I2ks¬BMVeU4=etrОq8vPB!5$8."rzWiu]jy?AڭVKso90Qt~Pn:+C.rQ K9׭МTc)O᪓jK3=TCLk%GǢE7Y=E^-:*smE/3ԨsY;M,>n9 )ksN1UR#[C 7 ]olǍV]k4FlDž"\_Ϣyfly.{" ryNoY=#95A8,~ `(骅AoA (sLC򎐨VʮJl,jS  5K΋GjJ.=04KTHGsكdg&Vh$4!KW@wTUMyٱ@X ti>5zδNW3'|։EǃPذ%ˬ WJ&Nqy:Jn/d$oYi V2{*"ŴL!)wn+t3B>Ln>/fxpendstream endobj 65 0 obj 2505 endobj 66 0 obj << /Length 67 0 R /Filter /FlateDecode >> stream x]Yk~pqԻx Y>r_ӲO/T31R/յ|Lt`.3-v.||'c1.f||O~'=?qKy;;0wTgK÷⭌]g/Ϯy'2S~9.Ki{l/#Yfh/ nm#?ĞN; Gǽ'}XMI> 2ez4qX%H8c.L`Hm:Ҭ.}_ Ф\)2<E\j&Pqx+{sau~'*^FFnX. !thbV^v6 6_v(G7yG s?JSf;YM1We*~h\#'ybp#1#=2#-x~+]1/b \cj}ګuO,ە\WxԤ%5!"AeJKʏ[,s,*AɘpcVQ滸zu>40O:LCVz.~ nݪdF,92/fͪ7Xagr(]~bȐ4߯ j5ԅ.tYNrzÓ Cd'?]*%pnn(V-( Nm׌Ɯƕ <ƒcsU9 䩤3]5n=cv#&0Y.!@0'C6x.3DZx["Y$ɒ2ssr5[9m-U VDA#p:'Eb7C"!VҘ /6EEq2/2 bIbb>ҩF׎CO ޖMڌȒW19 6D8&_+ O[nN1c` c&K3 J0tFo+ˎ!1[$߲R[=bt90;:#xӫ"ab\ad]/qj:gffVv˯$H%X @噔"ojœ TEnZ'2HD(|) hA!h iTVL ޮd~4 T @$̊nkjaIZ dU9|m aT1OՎZƷ"5'c䡖5˱KIG\`|&w;J#8S]HuSU"{T<i<%,7 3ͰS~dIG@(?jA+Nɗ pS`6:u}tcŎ`If10u>Pw4L DZE<}ة"3tt)Efo^ѓ0Grúq,}xظBM`  U:L[ÚX7{(GK#Bv}}1wY)fxA|Fe%/26I 3}8/Ĉ uZ@CU˫Je_8%U9{.C:N, Ubmvde]zCcjX苩~!ݢLPD׼~M%!B}xF!A&f #Ƥ*I.eP`FR;Jy?Qe[9ǸZ'Z[R02 0Wn TG^L+fZیXsT:X{Wl ɋjQJ r3FL~WFLS}*TqŒFB~(6s4vSs0L 9WGj9`<#JLq@okBJLnP M>" 0Q MKGBpQ'=Cʶi:T.7|'ԔT5:^F(Ё/9ķ&-o_;乌 H%4"fE횪  e%"z#T RŴT{ܹ^g'apM=*?  E/x%=ZskE؄ISAׯ myE:ntnX+}f}}:^ >\{%[Z>?y~; ù-l$Hz11SgCB0>zP/aD\xdzM6Lu V1p1,:K/vW<&$Go(aGakZ;P؞ޚ;,Vwѐ.jdAdq baZ[X 5ӡXʪrLX4ӼAd|f¹ghr˗OŽa7l]/;o\}nm&QWMw\]f R;[vcv[ KQ>h Y:R*cԧ-{|1 "ԣ`ciЖb:j}X1zd\~W!c/tUT3Div11]asYkk:2⨫Ces'k3\%1m!ť}˵R`GhޗvCZw_kyZ1iϗ fq7 Di6c.n)Hg)UռBYl+:)9[E |cEڥ:6Bt*`uiFtJ Ҏ+Y$|α~dYavIn"DNF0! 5I㹞U1!ʪD:>Ӈ. L;Нi3%%SM7P/j\Ealл}3L%o,̲!K@Ki4FdCYGf}▀iqfzKk@ȺS\ə<Uq$x9l#nҊ\4xc9d"cDQ moyY6 jlesHFI}v#8[c8Mɒتm_x+n0Ƃ(*>Zq`uG8#p1mS] V#^W* :Μ "> stream x]ي$}gۙf0LT ^EHuRܸq3-K`3cr"4~忧i>٤?N?o__<~2i=y>K8_O%w_~Oo=_v+` :]^`ѪNћ37(%ɾs^G8'B`{2Ul3}f|4%OgVaL6i-oܔw٘%D;\AfDš"!T:_wY0SY%Dז}j.BV J܉ wpB d}s\+:fϸ¬xa]z*eV,˂BUg@HG)įSFfTW9!QB~婷hxlΔW(У}/S" MrA[oM=-[%fOtj <#512GyR?G@1β1a ג zBM' -Mds7;!?1]UiUb\-~Ә`Aat]U`h{&wp00LXhGAVaBw32/flW%^1/čblML.=JѥhFw4Y8ɽPig g.PsLsG@6O_Uvˮa]Cud%z!7`!'&dƸ% ?GsZM0 R5|Z"0ɥ̂P0iZi`,M-,*t 1MfcXt " ^"c(L3/1`fj,NIR9%M%-{KRw;&:(pxZaXz^:;58Cޒ*I4v͜A*T UWJ# ֈ2yhd&)v@?ڍ !8wm\eIvWbȷY)b i_R# OI4(װ?Uԗ-ߺ-|,u# ٩7G@G=蚰1('iQ}䲈BBeKfJBwH5&q}q{X !32T=.QX.Utmx06t:ZIbR44傀u+ &Y3 X b)ZLZGyc ]hCQܠ_[ 4q_Jv/H7VkAC}MaKh§06S`!*3V[ME֌kaM綈+{q? ͬLe@tE\ ib]C~uH!P&Dx~J .9sHD -J" vk`VA5/ö4 sYiN#FL"U")<;+Q,NĿPQҲQ.i@6UYm?UwE%. Y<'Bp'S~]LNƵ0XNJ&MqA_UŨti@Lv b_}>AL  &~&CgP(@7c"&Duj۩U\+7}!~teIFp/ur}\ۭ2Qi&VϩGv">|Аא,`YSH~5X #SNDHmS6vY2QhVT{W8T)#lǯ8EU 4G:/EV{ѐPNxp*kGK0{#:B^z-Z>l>TQ8 ~H5{uR%ܚsQh֢\Ii*@L}aspgCjA[qSYK2*yktl71gzxoyGiA㱻sȒ^g8}XJ7xU]xAjCLCB+L/{Fy {\o5Z rxztT~֢r{Zxg1ЋAg{xR< ^:C @`I`BuBԜRJ,]govw"i@ q+$WE/["MyXK;~MGV႙ĉC 2*p_DL\ Ժ/3 `yb@ ar5=h<2yӤJwd1g&g cc1z\xNUaîSLf Ӎ߁U沏2+|mxy򎪤8Fy*;0O{6+"Ү.8袅:SxtpҾ_-o5c> stream x]ێ8}o! lƖd tu'?;;/뤢KxHvRS h.)v忻nnbo߾~yz~ލ}{q_~ZF/y/w|4&1.;qx! !=7]zCaY/H|&{"Yհ~Y|=">Gx="ĉUJaЯLgA܊cbqGmI$'1]ZD$|E1mUDkAL {u!Īr*zw")a?|""DZK;!i*J'*QFjAOި)''rYJLc7d|aYӚt ~ZD`HF#!/ (DK,bB͂PE}:BQ&sD: &w't#.*IG2~Ӎc%;L*u۽Xn8ݼ׎@ >/tk<[$R&b'.^ϣnm,7AEWb=!ϕ=ӎ驄Mٿ)ޝei,y|7Sŭޓl;)gVx,Qίp<7<:D\@j$#(O1[:2ae<4gN$i8V - jS2G'LUAa !ݺBp6*DrP"e7z&\]>VBWb*;胺 m'ް:|7xFdn`uabDrSlyۨihS1I={rjxrc Gn6̉ Z#Q! cE:XNڸZ!Z"w{;`q'D=S͌2}+ÜgcxVXEC"$Dni9:T&(jF Hm%6lYX7jQX6(1腈f9[Pn8!{O n'tsn`n_IX2rN=LeP Մ9)R* fў ~]mN' L2x C{:)990141ͷP,&ϘΔexHոrÁ g簣 eKi!0*\穊@M  -bhgE/ӴQI^ԤEjzLcnEELUyJ FOii |,L$[gbOu.ǴF5N;-I"̄ >fKDvRT-E0;j̦3 8_)hew*+A˺$rv"#ri1|3 +O(L~v8=Z}1[|MLL*W0͖bn=}n(?x8 Q&3'?gsXPPmٞ*o-kdvL S_!mP)= MĊ!A6Pml`MF_­2 u=FӆVhKDj 6g.r}ur^ :7E^dx.:7󳵴Mb~SPD7[MȳI2ڦ HXKTcg/|}&,lrS*j]jf]>K'WZM8aZ|1Z$ojVKھxV[V1;"1`IҮA'mm0!̶zTk=ʦJ~+tI]!T*㌥Ǧ!sRTEu+>'"m2;8V7#n/ qc؃Ȇʵ\;YIIb>~[-e#pnKRҊaZ^om3k35`4eM sYo-RbJQV$G-" bTEyQ\0t+9/C+)#?i*RNJлu "% LI1pc4@8`ni4jSǵ1R`[J lh|70_|S4@_;"{wh|wN|??v|4>V[UP,5U&l,(&~?m3rE~추]B@W  j`Ɂ@ֳgJ[ EN^3|/#s45ψxDžKɷ,+^#~2@tD0]%WnIp:m7K!5WVfP|.->>}I(֡(Zz=[PA[%ُ8V]o}1I6ؒD*o[@lA=>½0mƳHo6T"TШ]&ˠHCdq?ē2 Px;nl?UY+~BHS:&, ܆D~8ӘQQwg_C4W7endstream endobj 71 0 obj 2900 endobj 72 0 obj << /Length 73 0 R /Filter /FlateDecode >> stream xێ%7}~о%3s`$~B$cwwUT> Eڌv7uZ7Yߔ?uw?&yI,Y~.?,K?>~enyPfOb1~.~l6r]C?xx=341{p01O7< |w38ىpO$Lp ' ?hQ'+` sgաrV"q8xc$Bd_t֌ Q8 EF|UTva8)>plxHDKgd ɨ@)܌ 7GGsIZLIDg߬ejsx!{؞K~FovOlZ 4JtŌSg#HPfm3zՖ}1<HW[EL\H ]"/Da)bYkJR,&Y8p'wQ܌XG_u+Q̹A!G*P'P /d8 `uv*l[Mթ nup{E,ң b9b=WnoIo4ϘoYXHBСrE(6%y)SO\Y >Tuk;8A$SJ]T' v|TV 5ŖN Al:E( ,qæ`@\[Ȼ\MlcRY(X>S0Vs+N[#Tr* 9=\Q!9EU(Mj^uk;p&uN\T^ {L6%5)Bz':jy}$<KskxGXᙍ{!ќ{|1y e:i6.3 6UwRsMG&" $Skg66b73id ¿ aO3{Ճ2%-ID{dWe"(}1`ceӾ0h%p2 tcxKz;f^D@&&+im -){- }!z`Ug v vc00L )m`OxV=Lc0=T&ENU| >+(R HsQԋ84wlHDk[=պph*|"Uf]M%fR5-*++-r0ܽi+j|-eg֊ll0TMҲ+&*ilC!%JMvpbsKLȇc&<mۣcd"[JlrU5J~m oo@'NR)EkOxEFѐwECYmZ6p##fM)-R#$kD L4Ù[vAlafA~,z&Jx:f$@oly3 : ʐE3:BƗZu_efީYF ,l*"R5}r̤%k~7iɻQv7Ϥi.jqJt !qKiRgnXtm٩ϯ3'yǚ~ ߳")^ux_KbxQOWNn _kA3ucvYW(Ӛ+ph ήuzT3@زp^@ט˲ϤtoBdAMc@ I&Ac@o88Ȧp9YE~:~sRc%:ԩSjh6 )7Gx's"֖@mn V{ |B#RB1P0 Z >ځ"daZOgZo$/p^4p e2E- 9eP4bԕy qٌWd̀:@CΌrɃwD Okq m(Y$ڪ&v4O-'9p@@?jЃk[kxQ͆C(%"T^ LEE[ډRU)Դ~-rOK̵VBbH^j1Eiu FeFn}8 O%`MCtR+AĶT0K3N[ji6Y c-e^HnoE3XK[8i~ⲥȝ_]av+\^}2&f_A,it'vzw; ~laY& $$\>$?^AC*]/Go0I62!icPLq; p7'^k]4lrKr9#m@5\,= O'?OEzH/,&W? +\~[?zI|`o o2)lgMEovsu`ka&k&"bvy?]`gc*_ԤJ/K;*dJC`Blu /e5+E~Y%1Jdv(|ޖNW`T=} LUV9OXS؛A\p̲%lX> stream x\ݮܸ w:m`Q ;3 hE+j'pYȏG?\\%;_ _~_ʥ,^>Ƿ_/?}~Ly']Ywuaxw^{ݠsm.urqo-J~q_n?oܿS\_"{?u=ngJ՞U75n(jɞܰz`rv RνPYpAۧBJ(-2Dw=RI2 *07>7ǒ`ƛbK|tQŦڹ賷EW*FFxM 13vU-Tb7w8)<?ڌTt$ҩXNlQ"-Q[[ˡ6E2 @T_钅&TX<*GVO ODql*_5xE~jMȣpSD ňdלUK<gIP49# XZ>m/NYzQ`Wn8LZx6 BMth*fG5@5 PqXQ KHXLs,&0̪01,c"ϜVE|8"M!hz/ԱGpPxrrl3VNZYp`R;dV,IhA)e Xo{$s$BU,"{]U)+fӺ4Ir,J |%崔peժ0^pqP-8b7hD!eW#é6A ؃׈wcW>;M` V&3PY-NU5b"O2zik5 n,ꛤX8Q#_[&=M8{˅:>BN 8ei&AFM-8JI/NbPJ'NǾg'+o64PҜBE^Sy5C9Ш{KP9I>XHcBB *p4 V&"qPc%HLJ=9I2Z-X/!NTh9 kMpXȻqwTSs8)V8 ^o+ {%Qx)~o5[hQA3 8Q1OTV4xj/>:S$"},TՋH獳As~cXa@y1*m$2hjN 5[iY JO!Lrߋ!/e\uXD4{7I T58vJ ي-h^W)鸤)yLM!`H)ȟ!yzH{,~U!$ ։Hq@IɊAsWBg/LCW i@Mo]4ЁJnBLb" &eEd6}炙ܧʙ^JVXBq}js?^3njܴD+9@R̻{+>{=z1W)u} -g! Phʺchٛ-&N'GVVYC>G^)6aέfb!l1z輖ٚD6JSk㓿]xw96ᶷX?f xܜ2 Gފ02;(330]:YeocPWxtD9/C%BA&&ˉ$&p[hҝ^ ʼ4Ga-i ȯBqiZ)R3 ‘ ?TgXരFRjzbǤ\GdrmLhNki OdGVW#Wb4xr.ˢ>0!>Ы 'y.]=U>]@3sKtd{بD܈@ؤ "ڟGI~,Z~su<{UP#j\|20wpXщJJo$=)E&%< 9-s  #3Rt d0h Lv̼C|b%@sЙC p Ρ| _A nݗA} q7IOqOȏcOkygw^/~YsKcjԯ<׈7A-=BPZJ2j~ɿAϥ,!{_־Kݪ&߅n0?F'k= O |ObsFx˿?_;ս0ݮ1m3ы=v{bZs܊n +\֋%-H"~/wAy-Z?@:L_AfIkM v ax^B@ݤ, \mU^ o: M}NmRpUs \ڗÒ.86v!nm.lXWB \A@&` @5ahW_duwg5xa|+-nϧ +^nldJЁڦr+qq:\endstream endobj 75 0 obj 3910 endobj 76 0 obj << /Length 77 0 R /Filter /FlateDecode >> stream x]Y9r~P XNI`a`$uy=khdI5#dT1yAt?%??I_}rO^Z?Yg<? uSi3u^|tͻOJ(iz}ϟyyNy|ou>P蚗70LKM#ӋWb\Rh% w$!5_rhZ܊G1jI=z$y)q=嘾[T &_TO*j?J7j}n^>*L ]2MJe3jlu8,CFo9j `Yp\s5f'sb^ay^ vÆOx~!E.Vfq3)LvZC&xGw6,qTȊ6R2 :`TlS;2[/B~_L5|-SXYR'X],&~g2*|$ͪ!ZiSWR2.+Ms`V n 3~ n +[ѩ12ۥbTIsmrm9:YrQ|xR4x[Iܦ*-&XY O(RPES] j#[ŝ( F&+G+\,sc5A'C _eD{ ɥ@ܥ,dEدn&YR1P„:1g%;1"YnS/%x^P &aq~C_f;tzkiLkx6zŢeSpX}j&>W]5+Tq4K-$wQ CQ8kgRu/J2q`eT9KE&(5?1ʰsk%UDze^|ln[`QY*HIZ?fݻΦeS $(nuTܵM rCKrIH<\T#_H "ud.TD#AқhrctE\|?@̻s%|S4uM .DpE~g9X9BgtdF̣vǓ_6} 6w[\4oTiԱhZXUmF`"433"Y/3QZ/J Js ʒ~ S7~ყk |} Υ̧*躔;%ELP1=}Ȏdק,#SzrT Brb ϱ:?c&}e<`Jhe >5wC=?ˆTJI~-ՈJz\L{:| 7r|=G٫RW^O;̊5{LhM7iv<[.;÷ic?12ߪN:ZW3g/=XEzm }dắ 5~#Y)9`L?m/*H1 h:<ۣ7ROtOz4c3൏GWCC*(AXS;!W̼1, $ӡ!PK5@i3N=:+T--&ǭ8ˏAӉmphr{3Ae:l'۴Ճ`Cnze_~o9ξ3TM0{IR3K?I&ǵ庡 [&o_/B=GNqhvz;K^][1}l!TVg9no.:REʝoNzWj4=I8ˏAx*d1џDp c( Rb̤mHZ;Mhi1:Aj[q̗7^16PES6&Nn }FY*{k; EpSG1>#N:\Ɍ픯DIScIk/"7ƛN M|l!͠~9gO zB =fAy8{כ^ QcϖX̐])mvaÉ(c8Ujf҅ܝ1UswpDݛtӳ"uީE qZqD .p$b^l`/跐}>>ifY-~9D>҈#馃}DuGT1]A-i_]"!>nfi~Iڇо )|Nҵ,$ܩ#3KH>N7=F!|PB"_퐻vp"522EI#/?l%%/=2:lNP8cIQ/>cCWa5 sty|יa! `JB³@A7tlzQ?2!rGOqVB 8إ\ jJ  #*mjCc׻n.Q:"l $`r{RxbL$ |B 1(S;갟 a_b7Ü"*j>aZ ؈u=0-,@дpGBsڽ1 S,3G:U4#nh8[O>B!RV9HUp~v\Jay+J¦]s$oj,`R vRy hhBMS[o܀¡7 ip!!kVђ@:$f C}N? -DD뀟fR0BFM>X Hu o#+?"ade@QrLaE915#63,}T!ld wkgtn19ԓ~v> 1!G@N Au@O* x Q10X{A\.CQ0 _K 廃,HQU2C[_R͠~e Yg|R.zr.:@ +8mUoy_KMendstream endobj 77 0 obj 5183 endobj 78 0 obj << /Length 79 0 R /Filter /FlateDecode >> stream x]n$ }_`aDwF4z7@~ <_T$Y]3Үv`؀fzFRϟsZN^);l?m_>>Oy 'S =}O.OT|Oe)pW^Gwk{@//IV֑T.$hlktw6Fh3n>D֐5G_\j{~~.]tkQ^"?u#ЮnfG+O@'hmFKٵ\H 3=l] f[r;ȳl9Ζ}ni 2ܾb$ݶXqn6_L hKwG0%D9ٺ:gP#s{jc")+Rk?u<42:D`ls'sN<S9j$ULQ4~ό8/헅?8;?~"oKx)ϘO!\l (X νpQh`x yeS7"<F{QRgU\WŽ}BR6Fi;F >ZT Fn@\D D0 UC ?@ > TPHn+>>!\-M`m̠h:]ŗeuZ*}EހqLݶJdz#+Z@`sN$'D9R]@|Eu*bHmU*.2Ǝ@8cA.`21gxg[jh1AC}.c\ڢn#;E{k{ rG{N][GY>,9@'YQLLPP!`Ha,9j @*N uԔWH[;Զ0- yjy^5F fÉ#R 25hߛAKE0MpSD(c n|ո\|<%9tUbCGp΀Oe;ʸ 8G15rDo,$A63n3tpq-Æ} 刹$N]4x\(kkjSyxEk nfx{Q\ĢFHт#kVX!"k\^38;l*5AYo ˴Uv:2/xcުE%4jZB=>1Yg8Unס8ɚ.y }H*P)E&9Y&&`o5seplG2=[<ñc=~qίv&dA3ªf"ƈ$kC^;ZLӘ&0|V dJEc|AuwsS 8 * Ǚ(J38ɼ͹0נSh&`(*n);+Y'%FYD)kr3Q%d_g?k '23meT[+jSkvl{/޼LiЃ3(~dwCm2=8`^W{ Bս8ϫE Z #D˯|STM?V0G yuWEUUw槵i-TFlTfbHafS 97#f`V A 837v@"} \27Ѻ5SA}} -cs9n;"4pvKۨN-S#ĎF}%&VFCp١ṵVU*MAD Gmǖmzy^1#}{}ovk=zRSdSNVDpGmNu=uv۝]:;>fdk?0HһCe-m{a[[.ctZjAV# ނ +9ɉ*Ǩr'ޡQ;g*KK~sמ*pFf?>H ?mY]>]]ϥ ,Џ;7j&oIAZ]nMUrg57G#*A}zN?*PsyqtIޱЖy}?œ~բ쏟) E$)q9iw}k&CHh0C*A57yu#8M"N;G2Xb\Nn:`PDRbg>(G[?l╊զ9V n%-BԂ׽i/ $~Uive./? C҆jC҅6%"Uҫ&] cEzqj̇[ыd~>U{/r>mtX%^(S~&Fm[Z1{TNY)jc&a\1/Qa7Sv?mf_r7"_I(tڋx_B2~0MkF./-F6:)tu ɽ^tX;d,)$TJ?A#@>C9 "4?<Ŝܶ @l%>+;=% ] 4\plœe1K⼔lKWlbg P0:s}se#1xz8z ha+.>NGqŰT4>=M4^8AStI}g~MM̷DjDX_ v &,; -Pf|E0 GMrlrٛ(4)PWJ.jLDR\$4T5X q tx(=璍sk(c<ķ#՛1rfҋ1&E(>Ri6 3 a8B nlj2Ιa`mdxB$EKK+ⲗb=i ļ,x9&%Ca؅?h܊ڒ4iQvD# 5z]Y6s7N|>[ˑ۽{S ojYZQ6Ns$Ucd @m}O)l-;dS 08קAV9$n&WAr<$|A2$bJnK1Ghz؁u#T5Tfqf]d&,MdNA1+`;7IE?T';B"%F),0|C  =Z^ Lʭ|"e^ 5'0s| Dqendstream endobj 79 0 obj 4173 endobj 80 0 obj << /Length 81 0 R /Filter /FlateDecode >> stream x\Ɋ$7?rjc%nx ſoeWR!tc30JIXߟ?yNGw˲/9q>zӲ,|n:|}?Sosr*5t~X Z5_6NJ  e9?[ Dv5 իSBBpy\^H3b-ODfǩr<ĥ^F]xzg=?[J&<ϕk-HDU)4T # 'Ozyk73 [>lbr!U nD[@1z 7qiQG=! [U\%ߵȹ%-W3L?_*C((>#wA~-cF#RLkdGW"bt:;~R|äA-*}G!OEeoC#.Y瑂*~WH'IgO1ww>7bxS{LYlwx : FNXZAwrb\'D@+]ǺcukyC&¥^Kg)iD |1G3stP`t Y:n7g oO\*D3P:0^!_z:0:eSڞ~N K]VF {|RnF^8lUtWZ wgTq쎮nİ+;AN(X2ZphW!.-=Pu,K ni@&vXĜJ'x9"JYMG6 4 1IqQG[Vu4{}օ0S:zeV+*B Jdx7`BJȠ'/fUCV=a.Zq Q-bWۉ2H( OT.j JUa*,6Q>t:G#HM74Mjf81y˲"qf58x5_pW?EcŐ(o c4yu zG5P>WVl[vUŰA!3GTɢ*PF|qwEβY:׎xf^]`Et.`}|BNp TVô]?PSk=a93o@5X,V&Td|%uӘ/$ +vRZaf ʡ=&,DA Q*\[a*e딓dQGk![bnB#=V, q.bZJδR~ Ƅ)VХ< !fNjdkB(AfH_̭Al0v7or?ze$qM >{^sv*s.M80ra :kֺN0@lettY--R6dUUb % d. X&5AG/e0³Ww44Uu/2_ x&~S`';O.muFQU%2P Xמ%P4"fѪ ~n!i''JWe)RITݣc6 e,.m 4Xaқ@D'GZaˎl >(Yfz1s||.(V-6 n3xP%#UTڈO;-RkJсdIF_9_4“b&N]9$Cg=@> stream x]YF~@` 9 K~YZ%3i>vuNq~z~Ec/~g!{C?ޏ_>i?;G>϶;GCOh~xbXz[ڡ7ˊH8a Da'F= {E. џ{KB56qMv?Cļ[W}hEG8\GPT%ݪ/T+ "k1=ї D ߇aNKO1FCӛܒ$խ # Me}Cs= (=olT]**?7i# G+U ΢wN\d9C1P-: x=nYk L"hp 9FU7"y½;Qmt;Y@h-v=rTC7Af4Zz'-mC/lP8`td|}C@شjAQ > /c֜'3HbFLX>Zϟҹ+Mw咥$b6<}k*seC8-=TGDw&'TfT쩸^+X1QeFV]f|e@\4vycyg[gٖm pUZ"'ȵ}]o2%FoO985C}I& #S(#<2ԧ.KI/dHsϝJ,9Ba`& qF~ؕ@pllυn%Gƹ|OyA@MB7T}(GM>aٳU i3G㞒P 1iSWw\S%-hnZmgˎKᑶ\ P6o#LW;ς4+r!xawY?^^q4:W9F>ʊ#t 8 Gn4fnp Z:}f >J7:=2Ĉ}r`MtvO )M{&@@KeCA I\6╞v!u&7b_,ygΞS4endstream endobj 83 0 obj 2528 endobj 84 0 obj << /Length 85 0 R /Filter /FlateDecode >> stream x\ۊ}gT*S0=S`WꮼTȐjv1 U%%'2>i8yxr?-q۟Nyu_?=|𴜒sO_.?O/=>R>Oo$Dn?py!.d@'^~eFy~ ouuA7c]H̐lI|*^eE+b6q˽x4ܣpxk;9~4@`6N7^ɛcoYS$e(ΙK;$6R}jWlQ|yi}vK @Wj\;S*v@VP(m/2{py{ yDu519U ٹe}1S=R'OǰѐyAju(s͂L'J ]z2Z)B^+U.Ѣ-zJ[ ,|9*Pd a0~ 3{  03Lg&apJ(o\U ,/DXd,<Ɇ.fA؎`G]w:C1 +fr`2P4~?@!%-nl,cх2̄+\/ á"1Cq-%˂[\03 %G0PEQ(+Ƹ5 \ϳ 97׆k$M r XE\V;,J$&WYBر)\ h)e \S$VjV-~74v[]l`p4JPpXRNKUca73h_W]3b^ӀeUSX5WHUX_KImۨ>R-Xƺfps> u 9A06 J)5c;05HRjP &rZL7.sa0Gºvu268n\7#4[SAkf?ؙ4˝Y,xNc53 c.rU$L;{䨚Iv0ɲLˏ9u@? ]L>#$45]C @@@)!`N .Vtr(=E9pQ}/S}TQŝG/לfj4D{-׸ijSPuK"LH's~,k##<71ҏ5!φ4Vzo5E|q״Է;D;4B- n;0N[g=DPREhީ|;e̯ Db#2WuJW.BpC͟'F9F~"v[Uv @0 Q=5u8cS$vvX-hoXTT08Zaac ϖvޙca9I2(i#`i#z|-#yJ5dѻd[aw5eKR2t=݅^KlYB1ؒIx$ uh>S <*/Fn#5'7JhRb1- Ho!%g_KC߈Y{CBWs"rWw*kk%"Ӝ ~fDZ څKV?-jŶ6> )6R5,1tS,߈k3ܷu``J؁rT*w> stream x]j$7?`9c΄owfb8޸* ʌÉϟ{N)M^~ϟ?2q[NɘOyr'3y-oE S/ߛt.?+[_/߄u-oB[1?mޖJK~ukLԧ|~oS>BǕ6#7M3b&Wyyp!`>?o@??=#4k05 9U>#!UX+BrWAK6?Ű f,!7YBʚ}u;qHȜ̘4u#戝il`1-]u#VC0cC7B#&,22 j&ghQ&Y{yQ,dmld9mu5Pn9{)ˇuո+}Wri1nf7ʂfUoY3&u MvZiCmfV~Dŷ.Uo[xl uv-u)c-n,X0۞8Fy_Ϣ3H29/"lư#藑Wr2j rus|~W(&>Q9*KKA=@A%zSN3o*K Sen6/~ ŧ3f"FgЏM3Bu#Vb! k!k"dX S~qlTAx-пο'1$Qd=k|x)i$% hˉv́PiKm+\,`ߜ .3cm-pUU/QQ vSe~㩺ft#:l |<mN'BebB$JJ>=fQrJ2e"}PdԄySXr`xڼ8aaF6.٪5(MFiTwWUpa\%ZtH`8M#B hT͞UvVJG)1J4ܠtJuџT6wϗ 43}Ck&J[" xo^57Pi}B(b~jFc&uB[(R%,<r4F'FC%Jd] 4EJr\ u=N{U49E#X}U( yδ @'|vN4 X5m,@)h|TOлts0.XK>(pgs~ {}ɡw@\Qqze`ve~ ً%GB1,1>y1`Pp#uH*D,<(շ Fw.> (|%t?kVI;h Nkx-$=<+ 0'/v4Z# ܎"Ni+u2ұKpZ;U'RiB) aC!k1(J8s34e ҷj(fTU#i\JCT=xlkUl\8({[5:d[[3c_~BǺ4 T2QR [աeT:(v=NiŠZ30r)7-tlZ9PqKImJ:e#P{^|L# $8FBnP \6Yh(u2E1a xkZU:N90d 'ġ3-$"g\g:m-k.tba[P,$scY}Q &82 $Y5#6"'p8vJ7J\7.thdo{MV=JEv!批;1=+orcBkgu <bKa&Dfx׫LʞRû]KmL8ik;i7MouRq0;!͌ҪZŷUVKԚrcr޿}9D8 >RXFuA s%cۧ~= myvO oMX|?nq^ITN+>Ke.W.(_.oƅ2:.eQl$WbPQenANj6\Ku_dO0&xaj۔Gw:eiBiV"\<oÆLRL9DۙHLI1nվli-?Jݾvژs=Sju_;y X> o~ֿ2)"3sH[iNji2]c lܮ  .%?kZSk:D_kt*'EG]7vcyF KtJbIb⾯;[OdiiK7Re-w]endstream endobj 87 0 obj 3092 endobj 88 0 obj << /Length 89 0 R /Filter /FlateDecode >> stream x]ۊ$}g).{ U%:NDf<^zL]r*tO>M?NO/?o_~O/_?r>mrӟ.M??o?5 OqZ=\٥_O|{B}'9ܞ;+<)e? K&-Km>oֶ?Ic}+ݞ̴˶>yOȡC#uDFξf_5 f֌s]pDFcաw95,0z -["$>eӝ*$pm7T~y_~57{W!I e'.-:CP@#ۛ@ (CN@|v\>iJIܺ*bBШVF*Pynt*U  PewT9A˹n>C]EI6dS+!vP cUiLZT&;h75>j`f[27DnYIpHdp)lӰEcU]џf $"LJׄg ;V`Kʹ2~%ƃ }haYRQh [/G<j dVrܟ AXrV< fl * `0Av"͕=io0_8G|oΚ0_w`1wg& :X!Nw}zkr~CbX\`_#,D`ЖfL`nyQdlYHJ;#+ÓIЮ3VP!"Wg(K=:`u7~nw /^];:mJaUVP4xw,XGQC~,xEVD|h=RTؽ-=[,cr?{Z_5Կ;&301֙Xa:ʆ׭kw]Kl~A#d& E'_/nF609 BUܱ%R"h0 Uà4oO|\3eNHH3}8^AتŁ~_hJ}1$\J44/OmM FJWҡCsxgW Rb01zVU ľ WWO9{̾?{DRݶy( YуjsrQښ`j9սb)`՚Lڙ֘ k['JP>"P]Lޘ +N:!=g@r v^Xg (!ȫ-xHI`|qj$3ӝBo #ݔmVGA\c(hgeK6b~FR*+?xi5!Q{felZ7@ˣ`Pw8m_)ӍT@̞)uY 9&JUרW]UU+:Ot_ >aZNA2>VO nB@+L&iS=ui\-+ZX5}7VkN[Q`s2uGz6F!)b8RFֶt3 [^EOBZ]V{ԅs PE:&)d̊"cp?1@cD#0H9Se`Y@s4!jןeh;/zLiQHiRaN[6nQsnþC- m ǫwnYQkO+9!=)7I@_ou񷬹:Āi Bp.V7a~h=@JOugwW`!:0rrFNX ,76o Ň♻ۛ*:!n$xԝ{֏๭\H2Gb@6R1i"ϟӂwx>K*,n@CE #H$aZX7q!NSXF$Ěue}MdݶFthn0Zbs,/^w;jl$@^s`Ksq"K{Ygptn}3 #<;8RZe:T)*m-@$Cun펤A6\vƹTP?sB}E2G0t)7r V.ֆ&rqYC@;) M$VU,K%V]qQ)ƨ&KfeJ+N "K!d`L\M\79n׏Y)ff\jmt1ǩmԣ2ݔWm6) "wo4)z\0+-Kw˻l,]۟VA )!Am0u(]7@V &9&*ڐy ' Uf>.%oc V)'Z=}\Ay0lh:U )B']cX" &iT 풢i Ŏ;(w 8.KU>^ X^{xԼt,qoL; I[@7Ք .:;# Rpd(CGн-uqkӊI0ޤHSfGM`ZXjaRjy\YR*mp;6ѥ2eLD%Uμo>K$Sk{cfOQ.f ;%dCT%Qc<.9tK֙y<|Js:B"RL7;$Ӭ(>ؒjXNx(DxnSNLmXey辺c&]ߌIȳ.n诏VF"厙ʈcqﺎgkQ;O`Bq;Z9@A >ev&_6缫U]Ň4<biq_NMKK|Ew Ρ/jĠ!e;Yi紌ND+?8u}ן]O} )'MnxJ>0OrEup_pʽϖ9"pgr-;> stream x\ۊ6}s ˒,^ $ yd_GS%s.R]N]}?]ܟL7a?~|}r{ vNl;wwv&w\q'p%{==63_ )Ӈ[qb_-+/~y6&#{Б!O8=ߟ=k$w5#~+ O aN JZzYe+AҕI"iW8*rq{xB8:k +ð R&x> =SvA eüʝVfYMwPV iOS\vQ=.cO<8FPŃM%Jy)~#A\}X$e]<\1*5!QȻ3nJauS0a .B<0U!rYu0l>;QMDN-벅+ c%q `ցЬYgϕj F; JeR5t#dm?BGx of@/C_ Wҋ)WR'pq-9shC땁Y ULж9=ìٯ ȱg8'W \23x;qGRҰkց޳<2$"H~@ժ~_,m7jAΏ9807CXE34#LRl_`/q&;#"98aiC4r}ԯVzG}^Bgx6kzF|l~\#\xJIn.LGi!a=!O8ҳ 8+\ l/fwcLC m]Kͫ7:Z4 앾SMDg 2ŌJvAp2؂f!p0*L$ǎۭ%D )zH@rah F3݊*b7m~F1,jƢj8?c{VST>2:8;`{ؕB9( q[; M}(M*}v͈Ǯ}-S{WkdmLU Yen--:6v^68]h;(O4eayH bcI*3V f Vp'5 ;œQ2"6U6(2-PalJ+{h]HJ;/Ԃ`jƄ`R) r`;~ SW&((8 j5+('YM /R,Sp'x31w+(WJx6Ty83E n텐5TW[1qLao \ZDŲ̄X3*`u̼ӌVKj~bUyWX!2M2Fb!/tĹwxcrx!tw?a kF:Ny!W.?_3M;P 1!m!qs  GNۋffdd:C#4hғ MhJ0a^#0)S_hO_(ΊytBC"y;}Ӳvi"lNJ})0˫ 0 8L7%'Dk ˮs**RU~$^1?Aq%;-ߞ9ʿm+E[5%1ž`s!1PځD1-,ˎ%\w ; pMfXi -ܺݏBZʵF@FS3:Ԋ{~r^ĭ3hsձqp2Q=V5DȌ*c*pCFO~jb<l?.d{!ի{' W{B?eendstream endobj 91 0 obj 2202 endobj 92 0 obj << /Length 93 0 R /Filter /FlateDecode >> stream x][%Q~?!efr$&H䅿OWˮ岽z9 4Ҩۗ|uqy?<|dO ?|l-=yob/Oz/??~Gqz9s(S۪1Yy_4'gV,J("p#`ċ{y^ ݠ[Ь97c8Q^=BVnb@̍8,_@SZ IDXoȋf)ڻ17L߾KY3WEUA "SImD9 *#0m\銆p J,"4ɲȮUrn^젘YB:E4j}(_!;7tIp-eVoJŽ+h=m{Szn%ʥ5)w1ïؐ'7C6?KH_a6̉W{Օ_2bnXT=oDG0gb,; Us504foeSN7k׊^v7[/3!o:@(S]1+lu,"Wl4KTSI;S=F1kUEo FAd)}z]6;V}7Tet[ߦWO]_`Dgar"9,"UlwRɔyP ÔUR,T+Mvʹ:"U@A!}iiAK&MdY` :ˆD B3eb)vg3r^XhǷ6Ql ՠu MX5^Ǜ.3&]`[ `=.\> hHit19.ܘƯ:cSx dt/ <9PCsS),-y/{ϜM T~ymQc Y bH6vy -2R$IBmB0=;X})SIWXW_V1̞%kոu_3vݪL/w/K3 /O|0GwbJޙ&]k1oSQv@{\q&ƛaMJO4˔rX2Pό؞YAB-I;A g;e1 Ө=W~˪梷Uc3Ѻl[NJNy$r墙5P<,jfL]${ 96%')Vs}}B _X+/VWO"^+Z]7b>4oM ~ =AgZ$_W*_1V\Ou!X &(؍vu~iY="( =ʢ0 tI ~)w-:eo'?:' @9sJꪘ(7LUYec7i8sC&`op⥎m:2GP7<2RDJR~&n|<d |Y |{;1 Wju.g; }bMW)W?Kuyֱ /E$->g\lD{1GN^G?s ص_Kʝ͡%DakhyU, t_A\<mTP= s[@C$N\y}sѿHL)*/r=%LeDy)g *dUU?AvR~ͣ^D[ &l~gYQe3b2 jDn$٩qwh`sWl!{κReR Js- ;vl"qgYvmJh.Pt»ʳ0sc.l_*ֲ3L*Xu)2(ϖ" $Ÿ3l^|8E/^~'nVt8#bԝN^? [{d}]$Tۋ- zw*-=vKS՗!]u<%΍|/w=[d\>/Y 0ۓVa_ԗEEc3  ̊>|{W̭P7}*`돂nm|&;ۣ,~da/Y%1EfbEh-6l( 5-lC sk0Wa֑/q*{vJ(U,wECe)5X؁ "ʼns71:_"=| po0p _8PzX0mvL oTqNoW'^|W v8,itX |;*:HƬ}No)Ç}x8}!μ]zpxުn|)XZdŗҳ3\1}[XAA^FlU^;1zc>"E#×ܫS̰?nK̘xxV&>ojn])Z坸auJւO7HqT {]9=WFydJ_; Q2z핗dS '>wjsqPv(}"8|}ex*}׺kj(wī\x&m9U9?x'ݖ{!U.8u9M>eVG0F.e29>^iQ;c9{rs*Edޜ [GukhH";M;i;:-ě^;9ZT,ﴶ!ٷpD+[eߕ>)('0:GNJՈ0|iX/] ėe{",Wm+6xBB?^-'^ L=A4SOJ@G #Gh&5~k[ԸZb dZRA?'a[Y3M@R q< }þnP@Z\3Qʐf\&J,3ņʂ=WVJq(uk(,dbr8XQ.4SL\pPLhA7`zaSzq);RgFP|%;XU)KuLuK>vh5͉A1C~GhPSE q1o'Fy.9VtͱyĀ`,5 gXZ"u'7(|ɉ> E?r/W9KǴkfhd?s< .k<^v0r,مn +؅5Aסtjكv5b zL?Fd2ۉaA8f) &Ij F3c^8y ϊV@a S)L )_y~ȕnʑ阎,fG@ 1s]Ȧ4Ick"vœ--Y.H.`gF([Nԫr:Ց,4-t(v$z;~:%|׌w^xyPH-|fRls@DYZ{h$"S-2'h$h%q]pG'uZ 36PY'(2nr7- kDm[foiiFຆ(!|-0QB֗0B Gt WHIMtח2 whB[e/WZ ^s_'9E8>7A>;J$%.37ؕ`n*4pe46B[2>4^h9Sx#Q(wrkTheJqendstream endobj 93 0 obj 6976 endobj 94 0 obj << /Length 95 0 R /Filter /FlateDecode >> stream x]] }7z;@b6ڴ(K~G!4s'MjGCI!Eͬ߾mv{2h7?7?oߘ-<[>s3÷ۇ}X7)Θ'/\1؍KO9'">J`Aǵ7e2ՉM.\wAw)FYXU%񜼌WVҫf7yM8ԖT])H?&YuQ/Yg UDE4n0W9\}g7gUP렪Nރcg- ;[B {e+U^9Fw+ Z%6 {Yw'>G:rul=0}7:订gq?`@IѤ]W(8B OQanG*zM뼬3IT/ ss!$C+F&6e̓;+Լp?3;WGH_j|+L-,f2+wbcgHQPGB÷B_)펵=c+b;_~'n>/Ztj-  vkB٩|G,`zOiVGS?JJ;L i-C(9tzVvv Ia9N}yv +~7Otc|/軝 a-"VR%sX4:1:Iv4WjWF7GzQ k~8';ڑWzwEP >4'p<Yn %\9s>a 6 E]| {~4| ỳWp;sF<18i9#9GA Lsx-a >Ϛ*6T;gI-m/ԡn>%6CnڌD7un;Ii0-Y3;0:҉Of>䯦.P|IO<OZ G#γ^<s8zzhuf+SR}P:FPU!qmd]x!hz?bє9BΔ.UT9ݣ [c}-j%sqw(gƿQLX}.\GIӀ*5)xj\D]OA&C.ok_%OV?&> g'@]qIɍRq{rӸW9e!ƯhU`Fqĕ؛B#c8fveƮ ޾9e-݈ 'E~~΄N='CaY$){EDaխVİ:QWǕxX9g?x_EWEߥcQhglMY?v +364W?c=)˃*gnݓlWNݜ;>|n$)NX>f&?I$MA[uqJބmQ#RA_Rrq'^[Nwҥ\1 gVV"rT9a x,Oꃲȣ:pR[ܕ]-2 6g>JǏĦz#wmZQN~NX7hR 7볣W=am3 q! Wcsh_ǭ=+c>aWy?iѻ~*yS;&빎&plVsXbДS7)Pߋ^Soh2.}kU=x)MTb S/(|LߝnqJ7Zsb5էZuE,=aU6߹K<Bt9KG ǜў+p^*1?Ig}T@-"⯿c7-y9u|zdypD©鯽`3gE2<?'qȉ]ܸPXhvjՄfXuWc0寏OǠAt"aIAtݝ|ߟX|c0[͋C57ҳ`rR[{ Xo_hu]?ͷ$jT1S}JPnjhu]lJwEb*Ol_۳~8ZDV{AӜ18ҕߋKa$YC j~S|'ZgHLioG9VVeH}9F]1..ѵBrD2RaڪR#D\MV?'Wq)'-՟H!3 Q\_6fg!$H]]OE"C}mB@LbQG_6B|<;R˚eEɎyhp,ʀPJǷ>65`A0E$İ&%z*Yu*U/ cB)EeJSLl[20zRt)DI Ű!+.-%kjSBo{U k+lJ:C=!,b䐻 YDm(;D4%"Jpӆ/B;ɓ@$E$Vv6P"aE@?/q/ ǸY8;('eP KCʞh)M)dzua[xC@[, s st^(\©0e"誟PaQyP3-)x>4'Aɜ^ɒZ:;BA @XYa)Q,C`±hM iC\CC>M"Oߨi r榚|,y \9Ke%2sVV"HeN@-918o}}piܪCjy$5 ieը1s 0-L8kx xQxq*$ov!V3%0%H` {NLyUk]D M% 23 81Ȓk$2 &*?ˌGzE'Z̡dT.:fe U5Flo#U1^}E%XЊ7{zNoj35H"<赥.w5JYMb\1 D%?.q& cKTr\6^PHϰg5 (aC! pF?=&6`mP <CK'qcԝ`Ќ .1|×g/iƀ=@f=fpq&YbOM!j>gƔqd5N()̴ta|ƇX~XhJ9#KM8!JBV*DlB*Rӱ aFCBZ`lr@4A@,C.Hנ_[EBΗ _ͨ&T섒}IToIrWF4i+HO6VieSY]$ZV@WHGp ]Xu MlK-Rl5H5IbSޭAGĠ`6 LjL+NV3"=)`;Tn;!weFp ^܋vMN]#M\]kT7=aՉS-J@^Np6dUN9n܆8.G%V&fTsnr,4d̠8{uK¦+e`BM"ҤLG@8 e0!lhRn+v+v=y .T/ȶ$얒T]Kl>ٔ$azhAtǫcA騵DW[-?~RaG/Ӗ.yFnwR0Z8.H[.y\VM12DᖸYu1H&z/3F,w [b^%C?ryIendstream endobj 95 0 obj 5313 endobj 96 0 obj << /Length 97 0 R /Filter /FlateDecode >> stream x\jF}79.zf \ K~?-eTZxz MUvv?{JacOο_tvA_N~ӟO;_>wvqko NdVdcܜ~Lڜ.Mt!֔/Sr甖W) a2i6O.ۋǔVi`~tJOeLQcִ7{tfnO%Z48l.D8"!˶`<*ᘚ1N )'<ƊRS\ӘG! y5‘((?Rry:ć*vHxJEc%n~PZY(23ЖBuwT9i\#S~x2Tf@#D 02d(Nmldx2;DEdQil\-gh2"yBO X9#6BVl)zC6s #{`k [S8,-rM2OƧmK.0]U'kazVxm|AЀj13^QP~C!;y{(4`X ;:HF%dolM=A$ X rc'&˶+Ǒ OO8f+ |qQRU/:Ի` <)宪xd(eN喆 q4No*Rլdcu-G7őG` 37筇4Nq+b85 T˰A< Nc!–F4 Tu|T'³K PU<`&or3e+<`\UꩳiM^sT׆Cӵ!MH쳕I~H)Ϯ6kt%`RB6Q@8!'ZC89=-Ѡжuw'zLx3j@apj[BU>9MI۟f=+Y_#LP`q" ˏ;@dtB÷?Pn=ii.9;tF1M Ce&yp`VeN'b ̩NJ!!z=XޤsҎ'nH% 1JSO\v C"Mbb;R}U}mܧreCve4銦~uB?_ 5<#ٵ~\~r/𥭀с@v%GL"]W+{8># $m5Y-.]Ҋ09`CKi NmА>`W'~yid (C5Í*B޴x_đ(O=y5*RJQq2N"_nHZLl`a3|0lj_$ c>N-1ۈmIN[h5N8geړR B3nc?\/]XYRZ(Y=m140Э†~Ʊ\[\M;SSIxgo}׻o6leըTaM>b# ali%ibJ%Hsd1Eof@g(Xj; *]oǸҷixiNDꉍ)f-p39?Ezi{"(\s`PnI4o4kO<%Fb6's 5K[%7.#-9Jm#h{-Z/}gxFONHDY1=4gh}z%fȡCą-d!gnv~@Gact&NrxU#xCr?zEB @): U#Tgs$lme/WNlPOӨ!뎄3$ nُݱU[S$mfo/V]r~ &Ur30TZA}V9ߪ1xBVnԔ -H58.mo(/<]J2vw8zk 6 wDu 5 j X(rtQ:aKʃo ̤AI(;)QPCxߓ@hL&oO8LU:6E qp5'ӈ]n\ά  endstream endobj 97 0 obj 2362 endobj 98 0 obj << /Length 99 0 R /Filter /FlateDecode >> stream x]ۮ:r}odGUzFDOàfc[*Xi 9wH$]hE7aoBTĄk:_ubА.:ڀ,F N:.Q\8њB<{R`Od1sOeCZ)YYK32?t"Aa "aXdh%^Ȥl\@c5ɹ5WQ@pxNU$3jHp*pdxϛd0Dl%AnOp⑌ӆ-4J ,jOc];/|`#=8'6)2EAu&U4ZvkmFA<;Zѥ *$FSʮzknr9#@`hO79B"0)=%w^e*^w}ߘbwWӶhîyĈf@(n&~oу)(qe0[ :!R#QR8LAbb*AC3<*(J#gC S].PbASֹbPX, qT҄26:৸vEꭢF >օb V^ ي>K o[fsHGS,xj3?j¨[z@x\/s2[O)ebLSP,>=)\5РO*K! m;#fG׷m%(H;0H"hB=]7(J^2~ XnkEQsᚑjJMJ,7'@7EW,Cj+?QQUA| sL6>$+zGDRȮCG\(:j+oFsxȚwJչF`aApވ _]3$?OKJ\E<{qVaY[mi 8)q-#AzP@o6cvf}ZR^ [(|^~yZ*Sh3ZRro\#T\O4A3 CݔܐV'hq6j2 SI^LyTz\q3[%Eߊ[[.d*}ɚ/`^ci$+n]5Vqwg#Fte\!XV)Φ9ujO#(adB dXH' eJ@g:B^hd+V`$>Qw ;NGR&aČ^:=e> >]*l=uE]hQY,ȡHj22p,lvB}Z3䷝Fx&N#YWn} SU]ß $lfWL⸖TRxQ#]O!oO_뗿cA+xI_:e_/-Rc/Ԙ˛O{|sztl,?Fy/IcU@) nAjG'αeTe'5t_Eq}l=]>OelmS@(֥~3d&2|1:a;N򓫉s\\WJvj|Gu9F i :HJR0oEWZ 7lPxiZEUPӍUtDfߐBea \j & >Eri+LӤ~3 K0|c / ]_ 'i2ox/OEu*uQu2{GEn|MP5ɟwX$q\'B*痾r~+ qj jY\it$}v;fWHO2{Bydu`ChU=p2l3J)˜ Ą!Ĵ1ZNo,m:p]Jz݆apM2/1N{A#c먟V?mbq?dYY !Ky0nKW`}]嵗̇w0wy/9hdRi1KMnGUkîA/.RÏ6\NUrl䎯ֵ-#%ߦ/XiEź D6iIx7U]2՗쉮bt)պIN ",,XS\ 5@]9}YJVV> :ʾ:ȘJC60lS 4<ܦo7݇#u?ޤ ei]u^M_EwefE[x"la7|*ͪZBKS ^oaU;ʀ.ˆ _)7]fiW2O=טH9%gk_Ϊ*lMcZz3*ekv0JYB] vcXKC-tkmA6P$֜c02&t$P.UU+4|,T[WjF QB䒚3hR5kzCԄ[:DP$#'f D{>M+xJ`uf6ɑ6ghiw%i/jĦ48?AJ<Ilr xl!̃mX8jN̚v&;gFGJu61s싡r!Pb׵fWach[7׿a1(V6R>ik'WVAU,R0k껤0kmf(" V->:v8@LzeP@{'lDκ~#~r~PY榣iG+(!fi?ѐWn~q(wG17.wv=A&;?+zո!UH `$btmOP!ON򻘒h; 6Czp + N֭Xjs .hđ)룿DcÙfĕ& NQm٩ g]pgqHiDT谯?O9rhLJyqDh"GC!+IuJsFYP ڗ9+"z ,F㧧w}!⃗ &g-ԏ:(1Vc/~_oqi>.V'j+S;hCͱ%y\1gqǝx$Csfc19c83s'ڞ3{!L~g]7;n.KRXyl_X@j Ns~#dHO_n=v8>ucy(cOzҙɢMR+i>;˭L[4 %+# bǧo}1ҤO×Τi3w4-j8gtnt+JA^|1ٸv:?Fy/It{d7ZTm$SԌ\ԍ͂?.C.~endstream endobj 99 0 obj 5701 endobj 100 0 obj << /Length 101 0 R /Filter /FlateDecode >> stream x\j8}?ya{ $> ڝuJdr1[*J.ӿ]Dga:|'a9!߻_N}g_ǿ>/]tmƧد'i~m=H5@0OQo)KKQa)2<@w4 tgw EaFƶC2utGţDֆgH9i䇲>fR| "vq@VQ [.Q)$§P☣+*8ZjXcm2hk9s, *-5 EuPtT?Fi.XzNpW< h8ա'LLWb5(2D,ы>D&&/bZZ$ YFBY&f^xKJ+CCT ,qtV3)amZ* a.́Ljy J*HZ9nyKԌ6&W|s`x;a4zQF,u3賃ۢh@ DNLJ\KJBy= 2Ҋ%R J&$],D@ަbC:֎A۶Ҟ-MJX&& aaO.M5wc 7ÛC!0,7Dh2k&2#hI!>z㱛"pb#`MuPvJAL!{ⳓþe~]5 q ̸ǞƜ*Fx7gmрԌ4)_r753`0hqa~- 1蠌z *nR4)Bt5-E~eb Ÿ~Woqkd}c%=Qwx{[/u!d[!h&6!Tp%#c65S]B<'sj?-0dUlZ*{cE#N̛a*oRTG#-~:.&?@e~"{endstream endobj 101 0 obj 2279 endobj 102 0 obj << /Length 103 0 R /Filter /FlateDecode >> stream x]j$G }6]W` `\u./233HaKUbݴqګW:~a_>ux_vAﻟ~㟻{w_>Xŷ8s;/oG_ v&#(x@ޠ_舁.`~#zE8tNjZ!WdQB}Hn=1O{Kz2B} 3y80?Q'Z;K~^_ ,W D6wRE2$Pei;M63" l&cqY t+OeOQ&L# >zJ$mh#E~PFM^" eFf0@@3ZK >嶇Oql'Em0I}RQ}uL면hF*;(#c;CWbV̪0q1ɵB XBnLvcRꉥ_1|c!xgͽ&\sDDCQ )24ܪU'/@Iy$=q:ND5EOKoIbU# :&:8vN%ƖqlBх,vd$CyhotDnwe+cu ۺС0z{-aI({B"E[Χ'O ~ (WMGXD*츄Hj 20*ư|36'"}]hbvuEu'D.C(H麞gfZ┧9mŽjqP>c|>8PU\Wn ,;l!wIGƃ:Q8 #2Eb#;Gr{[8TcX% aMnA#I2;$.%I q r*iW dP&d~[*}8e1>:@rwfA)\ QsBl% -M+6aKByI #:7&6>Q#GgqQ]D2wO~cD\4؜q3Q2k ȅ9 *#:(ǩ꿟]=h 1@V41 CnsO{6nȞ2MgN˲S<7P<1rUY'cfgc~ Snm T@f R!!2#֍G͆S JPnC[ɷ$?wfDZR/axNg]Z~1  /CI`"QTEeIT+pBs:=1y&jFCQiؤY!^݀jj~zx܇ύ:e3"[.h[_!3_nժQW,+WBb+4=AgyM7[iHn*`t=7n(K +M?nO 2F/ݵOl]ը}dJutpݕijT@ Tݢ,[`&-oA/6%>i؈| hU)WL@럱EWMpylutϬn-_/&%;*T.o` LV4I(-'r +ٽ$}<5VR] #IqAwKӘVmlŴ\ x,/)s6:FG^ITnJLf$Q64z&O|fZ9 zZ9nVʡhXuv[+ǭcKVﶕC- U_[+'[#[#ǭ!~^SNuOX{=;Ա $(ẘFKksXO|c'Dzѿƺy3^kR1Mڡ W/tt>X6…0ǻ]&_Ɓцoq546ˆƙsPu?5Lendstream endobj 103 0 obj 2436 endobj 104 0 obj << /Length 105 0 R /Filter /FlateDecode >> stream x]n8}o[,,I?0`~_;]hWt *Y("?ػo׿~?\~]}ϟz7p_ϟ-~pSڸfHm786]obo; _.ߝ|e&7vKqxyp$ 4"~ <1cO8dL=;gChqot }KhC]-pE\QcUwm `&i"˧oLSy9ɶOυ1SꯏLihsnUT#UwXU/@/^wSS{=|d5OU>^q@LtRTKWϲbgL!wv?)u-&Hc\Lm wLX=3[ MLd'1X5tim=p ގeɻ23[@h[&ĴǙ)S+(i̛0zcJ|,L@H J I䦠,,^fa 2n A6|oL7+apΠd?h*NGh LEgqSv/;޵ָ25滾HUi,!ǼRjX~=QItp 1Y8=,!N'ZޢqwAXHnJ@/tK}H_+@$>ؑ5?*6UCIMGZo#L`5fBYRaX,ZDLt\I yّ%i`7΄]9vܠy_ ǖZ莘dp \ :-s \2C08i#[,YȂaHV}ORm;º6sG$a] ϔWģ(5ȿ%A5OLj%*%Z֎$n79`-`kGmhSYRբ)LB۠)KНSyEh)l;̿`%jdϽ=mf&S!(mt'gȋO1{#CRbr '$ODd(S 0,e(=[@#"aGO=5)OBRP,Y" շ1פC7ݍ)g m(d  cpc3E xWc=ԲTD$M~)ItmaZTU95{f20.t!t:O><:<^:/v_ 8ƼЧ% 睐~Q+)gJo@U&@^gh'fݠzYz@2NlAwϽ]g'2#2֣p-͡r+h|ƭ߃th ztV8R@;zNU W/9VdWUNJ.ڙQq-1@p>dV1!/CA&6(#M> Ôx@)<{΃Ų0 glh=%rьΈ, 1mâv>Tf̢}EUI#7e`eD˳|'P!Odc1Bj+BM)syobh]v wQZrA6VEIߦU.bH+p2rE\a!P;@1ž1C0ܽ.[$\Mf]t粩d8Q=k7*>JfC;ia0&"`=PY[*XKS+|g*kXP/zA7wdܴ|g(1"Ho)gȧkATNUFbZw֜0:ݴF('W 먌Eeg岩865-k(-js);~Jp?%n~E@~eV*ʡN#4ucwLÝlA ,e]CZs\-[n]kȠ"o@eXq" ] yB#$v۱1QٛbtWC{4fK M&*)e2ዩ+-aF~bsnuS3cC+VJKx;Ā״G%FuK#} #> stream x\jH}oQ%,JvDd6 VeJqGN鿧9EcӲ_󧻇ϟL4_)szӽ;qzOq߻2]-mI/'fDהm!@0QGLށ:G՗ rϰ3/x?%Ț%+;0 %Ks?uZM~" H 6ͫGo1w0@eI#l?q?E0o:y%7L\IJOyWã@3 yk}(̤ް^ʅyR+>">%\]0\^-!S$+Y\ڙ+8S=2 by<3Rb! 7 Δ-ό+/< pTbX;t}&8<T=yR ۡPTȜABeqQ@\kG6iՊj^β^XCY [ț7SU#=]A"zS 'P=ɂ&|G* |UtIxfs])O)Ťrϵ*?1bNd5T[_llePV !0f6\e1@ !e9la*hS95zt*4UuiX|҅\=)\#nq(4j[-a7m{ͭ~Ct\z+ugSȣf^x,0Dѭ&HY5V]zZf5M}ny0g2ua\VC`gHn\K-ʰ2RDypG1"ւ{T{`lg.UG.4 H\Č:읉"R[_lB"g77k5d0y8ۗf^:2f\&KVe֢ fQcBVph3 93u :FPfZ6e3XhR@1A^ڌBsL2ms4ƻ}2bD;:x4E.k:i)tmׇeMq^ ҽ !I A+`^y3C<ׇ 6~c{ 49@lb?Kp@NrjqJb~6Ǽ,=JtqeM8 ]#o,62kd=M9*{Ճ0r痀 >8]wy~(rT"<0'(+J/U8n"eBYꪡekr iZ{h՜(ʚ5{mY oNEQo5Rccwf1L@b*+wGq+U ؀?^ih`;X^5Gut 4{]w̙ 2sH ",yB(Rm9 crcto0fHo0fy!q>Xu CB~j -dfEyi\ fʪ!*vt6eG%+|֤q8]n*N22Ic^hid|Qu25|0[3OH78?/!*f&Z$ IƹGwo~@7EhHZ'K"2)֚t0lw%V $6C=l$wQM i3ny/E|OJ0*0=Gj=̌}&B'p`uGA 9GV Vf]h1{QFOGx>_w5k@jnb-*S{z='vU@ghe[A(J ! X]wûm:g7V7R MUfY.rٵendstream endobj 107 0 obj 2675 endobj 108 0 obj << /Length 109 0 R /Filter /FlateDecode >> stream x]jF}79GK0ƞC~ !yGުZ8 tYQe8s{a88ܩWz7L˿~;.}Fn:~:>9?<,dM wqw<FW98 }&[WcӝcǸ~ܣCi/#!5 f6?VC<=qWdaldL[dC.MDoE~oKWQ#I7{2H:Q9 .] qN$ y(emq2hz" D()87*Jsx0 >18]ΒE9b4y$ ~]Yҋc9E&eF>|pg|D r>h`grԬu<0<%6E7`W-;ۤ!ӼI8FΏPz-VO02OߤwV40c`D~/?GuE%֌Mœ [;2?2^f%Љ(O q\=;sLVC[ԖaҸu[&KP8Is1yiQ."[0E>SUf> e%R1,(؉"Jf#yW IYxccC-{w .Nr6@Fi*3̏rtqdR;H풪J䷢+D=JO<3 a鲓?ŷsI`NKFnxrQq+@X&Oֺ_XC7bh d~?!퐭&(fj55N4AЅm:B.2i^AĎ=EIS>x^l=]1*F'A5'蚄rzӁDj>Rn]c-S7$h!LxM~!IEo(](]״=*햘R9V /q*Fc7b#XHO'كiilʶ1DPrWv2|udRwqxhe۱lN%!e+fyq|db_c)9fg(blSmU"8l=-FkDJ+]I bD21qb2BoJAل.1ք+5Tv1w,LR8bc:Qwد(LV *ݲf0/X#{kE=IR(e_̅I;z 9v4g3lZTk=d":gQRL.+ob,e5PoNdC\NDG>DloNd3)ub^PDT+/گG\ Ï+zdIL W2òWNĩ˩ @)@*؈{ _g,]3Rn~Oؠ̎.9 b(t + ½/zݹ}( 2xv}ob`9OI]PPw-]ڂ@`gցU*B¸RL{h)mKGիQ{#@p}6').udRXPw@AX~솟aRJeQ* ~J#ɚ#\{â1Ñd>^(> Ԍw #Y '*bZ"0B(#dUb^֝Uɐle5b=P==ܷ`]m Gp!{p_fVTb{p >Ogp>:ҖϕƞM@7wFaw#pzw0WwPӈ0S6.v< BsƮwe nћ:]WWnϘ`YTվh.^XF_͹곴FCOY4hD}0넉\ U_<.O*l-h}}Ԃޔs$HM&xw(Gr&+Ԃt@'(µ3t%q 4lJX}; 6vFeN K^na{ TWJr4`d\Cu4RT? *g.>EenfDJ v~D^`mL;mi\9[ËAc}1Gp1HU/@)ңsKNۼA󂺪s}ʪzU}\4nX=,A3X|= Nendstream endobj 109 0 obj 2604 endobj 110 0 obj << /Length 111 0 R /Filter /FlateDecode >> stream x]ۊ7}7?s ֽLy7,r<~wGS%{f`0֥T:w yôo?y׿>?}P/]i?r4;5}twsSK-zr(fo(=<}|lѱs+hJN-sa~qB{E77F@̧QLܚ'6-:Ȓ jrǓc\ 8vD.6D sf؞Omġin8mI{ۑ'~?šqx ؅I2g;Ŗ "Jz͟ޞuU Q&Dt!ʱ*D{+sqz* D #7Z-! ՈZO5eDL OҦ'Yeb$S#dZ Ć߷6y)/Bo30?mόuwC3FĠFmy+fht!h:8]*J[F1|fF@F)/RnT0Tv!RN >GU5‰Tl_`DI>2@$K.b `&H( l"oK\$Eg0YWn+@GꀢS Ngf6́z8}$vdLAKOKTqOY!#;8ic sL<3/+xfɐRm+7G"H6T}7z (7d2.,6鑍)jr" /c6`b] i:GLttqJd:c9IG3FIAjkt)#j2DBp*zԏS|M9vD!d 8!g$eNGI!YŖN^+Hw-ȶOza|vAppIDx%v*璌vj `ahM d)&C YUH_̃Ć`BP6 J\ @tЌndNуz!Qy;M)ʍh}{]p{~A9֗3D-m!Yze]}!ΰ]9rn/T`]786]Ku0yvpiV*C%\bȀo'&TN h{u#zU/ е"=4&@Rz!IAv:ԙ%c"Nנ3"f8`:#e-˄jc: 0zCg"]\2Iƍ> stream x\ۊF}_s ]%3@ٗ~$:U-۳YXFRw׽N{{ݰqW;]}'i=`vj=ϻ>ag?z|mkzx]tMO+f^t7xSz>^OyCWç=+.1I|PaZk]![a!Wv2pguyGsUW XGaELlq -8ܘۣ'qRjI > x^tUټ0z*-~Dכ/y5ƇņY9 Evmt%F|dOxo1]XӃM!3O1?()f%xE=1. }W", #AM{4އx9.fl̹NouzM)+[{O+#kD%7d2 65Zԯ'sP9;&O<7kL;ܰYC7X7f}PTzGYM3}T )W$6ekԸp5eC}j}#ntR!BJȕtǁ|F7`&SPgHҴF3PÕ)YN+-n .6!hs;W}h1OIo#BqN]x ܢL=.<.څ8gi.y9/aqyBE X`M#T-VQW| [ ^!p,笖4Z|b[i! C;,|cz_2.26t=E^=0epQ++=pQFTӏzT&6Hd˘0ޯx@1FO " U)6 ^Ry)XWҫ8kP#tExN<cyD:Ee8;@Qfhqiw942`4S8)Vϩڬ.%|tj-SnkYT۫_t_ J՜2j^&qrLtO5h>0<=((={_!=>ڷ-ۦSGGxvbχ;U:N n\,ӵ[*@ZЄjBFrAx[[474w^By)x+}C;8ڠq6|Fbv6:3!YTIyQqRotK%`/T:'> ږPhƥ@w'O B"~I=Bi&z0>$`zNtj`H(kߩ,פ!_TT&q8,qo>%ERSR8=#J wBIkRRۢ,εn%()lo p=^!E4K.(2Ncr-cD̈qD_tBf<L @P?7c6 f\P-?99mk JIY{3;sĀg ;R pX1q.&)La@T\mizS?2P9,$wK550XB6.МCx6 g&4dC/ox҂!dԣw>XL n?2 QʙScdgZfS4.>2[M[{-jnk7q6Y8BP J$.8r"v,tDH(F+4-\햓躇Si$ym ?)Gu ‚ɬ2W*qph{Ouo]%_nFny>/a2:S}O%.Lbe*GY!|oԨ8=[ߏW0}Xf ̼e %XG35Փ_w1aendstream endobj 113 0 obj 2426 endobj 114 0 obj << /Length 115 0 R /Filter /FlateDecode >> stream x\٪H}7y`\$h|mջ0?00ҿߒoRq""Sr]. %kɌrBN}pp6`o۟?ӧoL)sx2_߾z|ĝHtGyJG|n*-9_]->2˲a4#Y> î=7noxNgt YeqLϛGw>%m1pXr7RY|˘6/6GlW*  s].=/"Ͳ\:2âdL*r̳&q+d,^;Ǎ.i_~Lꗍ&<dq}Q_|%zʍ rQ8Ț.~qYq!d;obz)F߁1 n߄5&8w'l qT ړZ{1,, 6[ -HXDUWh jdx2gͺ}xLe]ڰ"K̰zY Kj`21Ƥk+ &#>#J]딡FЄ nbwFKB,\aApzfFI3SoAN.nv=Bd'$RY'gjGIWڙIpa{I-Cy+SM" j ,'g^̙gX~*0+WфRNd Z"Q8ڜř*K/uLp%x6GW&.qHoǒ{t5]A7@د#@p^JT"iGV~M@^/-OD7h؋]@Фt6w.+tC1۪[NjV&x1]ѭ:C odjR7MW.`֐va}?J"%:'v=MkP7h;EߝlÃ:Sr״!K塔 .lJқN S4Zkz x茙:>f ]ɶZbB%R VAzvkx)F~j%H0[JD"q1)Q#Ca@sf_.csrWg1nf(Aw#wğ`p|Gϝ?m}-MƟ;ϥyf},ӴSnnۖ-6M+q2;.QE/mӸa'kCzO&uԄI \ٗe!4p3Р(;#u`QĨcݭY !aƓr2ȊYޘ+c]傂OWc ~N|sbENI8qz}\隐n[+"d?VUOYGs'.g-xNE+f&TE+Pg*ʫC LAPv(ECȔhrF/[ ErJ%{ = -,D㒹0yaꥪdBLɻЊb'(6l,2 8fWU=efr[wU"bpYP-Y,]|U;$K.ҷHݮ=`Ä$0mMmH`noc{4Bah2BI=f8y "1:־w;d,C֝1<d6f];$eqx\~}zxoL0 Xu>FIrQ}63l.wrץ)3>̺/Wgi¡Fh=;+ӡU\o[]))J!ؔV1þtݴ+q/|=ht_1O3#v@'[^{ji}nۊ WܪNC nsLmr ,I(܊1d0F6]"%[:Ϩ. û[1Vp$mV`j1Sk@xf:,I[L}<g<0, ]ۙX JCtǣe@"&9K9.(,"F#Wu(Rʏ1 :ƪ^ _A̰5ε dSOż[eLW?cz6[$hO񆃲dm+E|k&JitG;΅ؗ4) s-' ,AgdF[ *hу =o׶n2T U6!2SbnT;s̒64j'wiЗpZL]Ơ>5DW dGy;Ai=%[*UUw2)Lw)a[V)/oNO|Cendstream endobj 115 0 obj 2836 endobj 116 0 obj << /Length 117 0 R /Filter /FlateDecode >> stream x\jF}79G}` m{Ⱦ#͸}Kqⵃ0]Sg8}{a8|?ܙC4v_?wۛۛi3sxpx)OػqySc8_5;]t%w]{3=I,]ve0L**&1Y%|DC닞 PSx|H|EZk$v6e~Ȣ9sFPSCoKZjƑp%y IqBWϋxZGmY/69le"By?a0&.)~gi8S .{zpU&E,HnhlܶƫHs9bk i 1GWNcl;^~bcAeD><>#<4-W (P.7Ŵs~L,9 w^h+ .{j!ͽ<[igG=TYNOf $T 0L^$0!($w)kCkU:CX@ L^xdR\'G.OX 2"W(-.MP:v90Zl'TrԾ%1œVh Ƽ+M=BGFGCCZ{Ƴ1*` McbRl!WSLe_}q*5KduP)T*`Pe׶y֘3+t֟tH{a /U몒sBFt$'[1 2SV(ϨJN$JtةRW>wt&f3Ho*R=3 ,F)d,, x{ٜFIQKOPl{*o,g ]M\ /2  %,MveҶ&O1T(eX"/M @ц)Je%Y^&h߮F0jԍ>0/EFYd)`i{?y _'mR'лg¸IE[HYSi5YpWnˬٴbbaddd&F!_Z}Ŗ+f քD|cKe?3a0CاTW"Kݯљt]̬b,/ &c{B`Ǔ*-rN).uX7 5x&E, ޔ)<}! o/`v6>m21rnޠj1Kvc5u\m۩<,{+V @-*P:lI"aS $g (2_hsD CY KK|}fNjA7$! CcpjԎT>l|FquzϱaYIa^>E PټC2bK= /o⬲YW~o|+}dkSBZʈ+5M:po3/rnS-q5ŢZzlĨbp b+J@ ExD_~C]f [7e| lX2u2"|ln):4**UoN *l,{x f>iRčŨP0{zd dxniCrir,/JBE8Mobޏq)~8#lg$@)A\n4kfW;DbA}s+=aDc 9?¤"h;`'\BGٛ[Cٌb>Otb.o8ɸ^Ju9Mpn´9w 72; %6G-Ȝș`I U]{6U[#(C*"oj,vCu*`fUªW 6xQ76 fT ]nPWf}lxߎ< "6Bx`&xڽv =@vS),/%1`*4c麄 ?:H.Y)4Ǽ/ߋ9SFuBi@ߪ$FڎnU^<AGZ0~O/qDn($8j2c/%boCqMemjo-!]" XIX]-ZFK?k"T1?N3{̟aYżF烴X'&xi:;`œȾKuBE@u̎>)Sȃ[`Rc];5c0fCuOIh֫Ny pɺr.b-}ˉ7G?T1@{T=mF`xacVq+<+zf6T2?6/4 @ -{y?Cendstream endobj 117 0 obj 2475 endobj 118 0 obj << /Length 119 0 R /Filter /FlateDecode >> stream x]ۊ#I}ofDfFd°0Uc4aae~.:BvUv7 veE[HGp_'wo:/|'!_yi<߇/}4?o?5)?>ziI_7ϯIex zYIH+!dMӝ^ dy>g FcBFU@#Bg~Hf 1<̈́]+O]I:=MyC#<3[C̳d*m<[LN1 8cB'Tk"#01+e~H"7NMX|idN*Y`< +'rL-=b a=3G緌gF:fv fH}S,l|E*g7%u"@u%=Otvt84"'02)l3uKc[7 1u}?[8ոf莦-0'q,eR]h'9& ʫpTpTz(I@O1<@Ji^ba#&5iq[!jSr ѿefQҲβ[hI޷'^P(/4>=+ '4mGq$FAM zHƠYY5>'橝MWQmel"쌲a\!7 '>1.#H_v7}K։p*1 [y4hdhCuh<޵R4D8z[\(xN9Gm/ @E[A\bbL]CL`Ӊ)`h@K2_JfڪC.}6+aHV 刘O[&^)$)!\ nſ LnF -*R4ノTgTĸ6SXAŤ\ qfs>0 ݚƶecv<'YY.xi=v˘טN%ENN/0> @j[31l 9¢gDD0m~,r~*:FY6 |`hh2x0;M e @pG: $[ݦ+FL' h~򧴱 %4>g٘c-+IjG3ųney" AfI ӏ"/: (j2vr2t 9 6䍉Pa&FWpPRfGlq4pWpWxVռqWC!EKUp7ViTXʕ(^8Na(Œif pi@cQ؎2?%fFVROJƔTPN#ʄ tI $#@J"T=zbnMm۪veIe)ӝ%,4P̙DzNCݟ6s}UL(n?&A81*p{;jrsrDv3͇|ؕ3M?Z&^|敚i]s; 6hc0Pǒ+w\μ ˦8|+XhفkLƱh.ru܋Z2k#KSm6{GCuTTpR bTt1 %\8X6ۘ࿁gcu4f%M9ԓAѕ L?yPDLQ,C3dkmQMg+ɤKHWLY^`,R{,s g j ov@6γ)/%DEu6j0T~8I-4WKjOOI07n3@)tNq" Il3[቎@cI3HXϚcVb r%2mkPĒ[_ǒIHd@f[:~٢V\gP(rjw-QÐ0/w^9ߤRE#lh')?0 8ѡn&p&Lb*֓}(/"]֗wg\he0sR_K(䒋dlpni*ϡ~]&DG|=2L Dc2y?EXcuQ=)ҪaRmU5şP c<ɒ5Cg1LfLsսQ}QP;նt YXK -AD#/;^FQ]ל#r|H7$[؀㼩jkr$#Aϭ/h֪i7Ư@]>:L2x@1@Pz JڭdW@UO}ݤ޲]]zy+BJmM݋0W}q+{22.AtRwom/tU70}c' -|=Ma@,lGcѦ{nK RB% ,ա0 h =Ezz[0*4.y,״hq:o߯RQ& @.\pz&R3^vڎI:1#Dګ `#[88F.8_endstream endobj 119 0 obj 3541 endobj 120 0 obj << /Length 121 0 R /Filter /FlateDecode >> stream x\n6}s$ŋ, l6}(}WJD33g750M+r,ߝlvao?yvκ8M};ٝ}1>Fj?3 f~u8'.B*]& ȋ'la,BV4rգcL2Y891e.؎9l d=x<7#HI&l=)/P9q|]ToO֗8u敭Գ5.4KO[ p&-G]$rgXKLh`Dr̂++g GG_Sqm\1^`_[p`PzWC"JDŽ;toԦjR1*BM4Ogmr/A`hm9ƣCh1' ) 0Sl"ZS,3bѫ4Y7cR;Rʃg9mWBQHO:|\;sE7g0hV˅ D)ゝx w!M,Sɼ]qQ@Z qH H^e"G~Mi:h H+PbH9^挔OىSY*3eRIIn-ʴdyJVz8UbMˡH B0Ӭc2YSr$󐚯'D\LI*tY Z$^-P]X0W=GZTG&9<9."r)#/$LO U{ w9O]Nۀ%JaB^钖ۖ753qw{[לwz3*mxI fwٝ) fwN ۄNߓA'tϟby˞?Cފ?(DopUӖ G3lArYւ;ׯa; :cs] &?VPRJ8OxaeGDgTJJ*416.` zHDU#vK/ AV3.vhV¹GX^> nq4 *!tЅ7Cg)CdScqOHYhA駼0asAI7!J49+ˬ5(hhla>iuSg_n)6aM'=-zO\t&ލ=sƎ)t O hx Η<2|= c\LXM@eax5]PӬ_{8ҸZK0UҎSQLK9  ̀oDxȵ5h9;˓҄J_y9rqX}ræc8(n8D c7+m8R(iC> stream x\ۊ6}_@: !;y$/س-]TL&ݲ,U<~pv8Cr~_~_׿~{wΧusǟߝǃ߿Ǵ^~>yȗ_x̗|uˠ?|sZ^#!2JR]I(+/S% O!vf {}crN&sf2GzHYS& (IF#/6c#N:wnUp]yD&tcNr5N1tE TSPbfs+S7, #DRRĤ#:POn $?@y))ţ'V]BQ Dw=m~Jύ eڞkz|f%7QbYV(0C:&40Y@+JMk'kM]15<A;!Q/!NePi WP>39eJ8M`e~j()(Sslx>ZCGV S/Dgr !=)nX-x,#@J 5 F&iZ͗E76*/i/0pMI=0S 2a :U@{ݧ_}"x# VQ?l@ ^Rq7.@+ˊ֕{qUV*pkV!L੽:0݌73U1ҌhZ<x->n5ϕЋICAGKti5k 8KC$ @ے)MƒVlA}(0] R,nfKe`MbS+B_Y|߯D*Nзfj\5kBJ= @:-XWp.ѓfξ4J"5~fʓN .-ޕ xQ$Pi5FwkaDGk*Քnƨ <}ȹ8NTN~4Ӄ9L]:s0xLRsu,Q! \ZvsX  uIPkQ5QU/])&i0~uNS8Zp< p {iV]rn5E,-U08x53wqE"nRtjw/掗"r: k߷igEtk 3!"jb?K Рͼ90ݖ9Z!t-av.KOYb]g}Fs,'Vn2)y6x\7Y@=z oMTgn[{leD`yРŤs$+ؼ09qw:ƛZLY<p[WeWWNyav(1V&pٴ0JpHSZC;udSךt=WpdfXFH60JZڒ"Q$%WjEڵ?XvP37a6f̋1:vdn"U1Tt>3+J1*4ƆJ̛w %BL1{j![Xe_m4^NnV֚s~xKOia2^ ·}h0P}OP=_nB-&d 5 ȱ5itWOxenSendstream endobj 123 0 obj 2629 endobj 124 0 obj << /Length 125 0 R /Filter /FlateDecode >> stream x\ۊ$}g).,tW/ l/}oVwRe6xi*K))B'nGQ=Oٝy?O?/|t^OٹӏvOn:p_FoO"}d=ߺl3/JἯh^K>h.#<%"p +gh8Y3C`Rvz| 'Utl >? `;sd3mĽ3gPx΢4#ɖj`.E@ĤY1>CwOCf2O[4q3\BI3% }Q dƝXΑA-OHCRP!eRu*O%O)k'\ '~d#9}B xĺ߃^iF(+6.y&`DL n#Ft?b($?}M'aD/Q$ ϒ>Gw4ыb@E ) ]NHr,3H=m\#bA3w#Iinۅ59}t,ep+]K扔*JJY q&zc]zW#*SqbtP9N dFk.q{KմnAn^C"ùŽR dUn=La2M3'( I5V/+ X 6z8a<4FO%zFvRW#e𽅏2ߙTTX q'kSCi9tܼO`<Ϋr^;N=~v=zaҜ,VaqԬTcmUJf1Tk iѳQҁؐ'ș;TxPẢVyʓГ7C[19sl (y6LAgLT1ᤁIG<%p dJ3 wޝ %|o-WTD7AT,_d53SM="i <gv&E4R%d#IT˶+ع:SpLEcaeci\DTOzpW Z򖃷=[KF~;C>R(/饟!^|~+ lU 4 fZ\ Z-]oqnd4jMF7>SS M/&F鄹@2ћs4hUC_A/g$M+/MJ?;NVz+Y4(]Ć, (!FLugp<N_M 2{3.ƐE-$n.˅]&B ]Zrm~;-.܎tUI`CQ`YRe,N]h|$KU"`ыf%u 7#uaՈjZ@L?z UhǁnBJJ +J-;Q&zQœ==0;VqM=G'Ħ*{{\l7TPBTowLg!wot/'\hc#6Α GC [C_6jKDM-zFY#&xRuC quh m+zZ m:RX흢1x^mV3 x71T}AiT7LJ&4ljN3/j-7nI0>X3J> /'b8Zެ$Q*C1v1>PqPOCF#]).!XMoWMբE.[R+?f~SjP[qDF%vK4lވm)7k`/#endstream endobj 125 0 obj 2880 endobj 126 0 obj << /Length 127 0 R /Filter /FlateDecode >> stream x]Ɋ$7?YR02 I:4<*ӖgUݠ94 m6_iz}/年~)$=ǓOBOd%>GLoBO5۹S{UmK}P,(iF6|<QV3F40cM8)a-{:Cj,Qh ' 7[<q#:wMVj/3r%n$.n5ZiP%h 涚Ru%5k!3+mQ͌D^eÑp=ꎡIY ((S'zkut}GL6[SpV?N]Œ_8?[Ϣ Yx&@y[ u.v#s弓:U UT#-d~$a{E1w v$E9jw'8o8ÍF2cʍv2{r`BsH$kxp+)tG]-M .bmċdmE_ۿ-~zG! @,< ;,CtG8= szvG'uVXs;9ГboDOނ_tK_-}L4'N: _畽i"G#E%%L9cjHQ`{Cu1$> ub1H5$ߡFI:ң+eGCA%ꗞlGCyIR.w/j$8*-GF8h%3*gA)C;]ȉ`Krz ҤcxakEQwɮ%L#kyc[6Jpmefxv1G݂M%J2R ѯN̪E0Yz ˊl'X^sF{9!V+m#nNk"-[UphBTVL>&, sP)3.}Dbq[*d.JUW0JX5,"*%t}'OzT@6F#e!jk.+F,`'o۸Yؙ9RyiPżѦP@y ;$Ed(6oVG`a7Zo" {fR)b@2:Mo&켆s ِ=BP(/T1su3Et謦n̖A=F T` 8_LKԊߔ׫{՛`^%_W pMK2 @2QpNE}L8>+DN9Ъ4cER,`E& D0))9D \mͪzp/ =3Lt ml,ؽI{f.U;n搥:LbOZ%]ړUz.8'Lv|Q`AaMI}1~֜#[#A|~2{;'PyoUIzwYV%#qqr3P]b;w|H+[>uvZ (cF4w+IQnET:҄? ܹɲ9wap{dw7/\i ,G:+u|l3sV{.QڣQgXQd"LOAl0qg $89`$i/kH OP3|,0&-y Z}_Q=߻*sGyI-FPVWJP1s'v]=&1"~mu싉pb:QqtZ*қ;̬l$-_pA*gMP|)/ʡ/;c 4\$z Ef z"BM4XGlĦ3 1tv"м*t788=攜rbZ㨫=US€RM&eѻ}W]|,oxdp` 8]jfQY@ Ô(9u۩駿,,,Lv"1EQ9bH.1K s ^QVVВVZ^Zd~ DZqdUw3=$+`,_(@ y2*L<":a 'BE5ߙK@=T|]JlJ[JĴU)6V N>;~VިtX4Y*R;h\Ra]h'Jyx=>un,ttCURӳu[nF>{jAFotv0l1'0VͰ+"nӁ)G^7^w JW|i@\ᆤ,N kwLnlg lS:)e]g'uĖd`?ƊnPYڗМD׌r\uL1Y*9G2|>9-sjlzurBW8_ ^b"k qZŋ=:@QvS]]5pW1B6Y"sxMZaLJt (QmEx3h&M=>"5dX”̜ rff>*zu)=GUG*aլ;@R`С~s؈yOdL3/ۭe r!ODB~ۈj.o:7h(!3\⑖(fM(T鐨^ꔱʷlaNd ar8܎0k\9/xE':}f 1m8yX`>Eu\'SSeU,*u3te:8`NDN xř'-0-Ot*t;@rV*Q(E*N$9{wXjkv7,tuWhLjשKVwK)1*C`,*U(rF_3KX"E+E;Jkx"݈J$p CJXL^(39 #p{?f%.t LjA3<wNI$3$$,U$(hB +HhJ㼾oT%CTͼIJnS!pWbH) +(BX_x7~ zsSI.60C; l Ąug·FC'i(R? ŠFC2Pq1 @Hb?^e. H8Smޟ<Ү촟%pKG.uaSc  o+{Z^U3Aa1WF/]g @u5qV1s煾.@"Ƽ1={$Hz@)bWm29`Ҽ M@)PȒ{J:WL+)Rѽj^G['9oUkdH~v ܯqNZLO2WSZ#5}K~Fʖe[c3Fؼ‰8ªKO~Dl䥄oҗ ;m] ^MyYpZS]=*'^YkAֆK8 '\ 24Lv]>8Jݯ" {c4U3Ȣ\=39C\ڿUoĴF%_GvSdi qQ<16pbʹXHMHG8<1B;g{3tARlgϙ>A[늻jx,xt_s/Ng Rlݒ퍵`GKdu:Uڔ- ^%MuiO;sۡ@ao;V{#~ s"ŠΊd6Dnq1r@us?̂plIpt֔bmy@ca(1D~tA_X4;KX?cjĤڡx^́&Jupcs6%n7 k=g٪lK2F ~dyR\j2e++q~}3endstream endobj 127 0 obj 5014 endobj 128 0 obj << /Length 129 0 R /Filter /FlateDecode >> stream x\Ɋ$7?YR:>Р:4L[žgT !ܖgcy,/\^K m__~/߾b_ __t /ayR۟_u).9гxVI5.$Fz'ĥӾLZo4bfge^KDO*{jvVZ?dc51Rقk~44Aha3iސJhy)0.tTvQ[5gmZ4m?~ԏ?l@Z}s-ø>DDD]K\Z)՜xA#nV!7zwhQ!hkC>N`m|@%@SaͮT%Rhs|LwjǮ.ODv7doEd0~U G띔d!;\Abqw^ 276SLrlA[ȗfIy߀A7Ί묦FR* ɷJ~ABtllw5\";=dۭb r^AvH"!ctJ4yAw)y+*0XbP\m`v[GEQZ'*"'Ua]qy*qCS `=Z)Y:(adheje "1'Vip"9 %.)(DžT?*ijVh,0,hViF }J].'  N(6oīIZ/~V ؛?!Ue3b1#f( bva\璋o sTcuaMb.0_B8VzQ79%G\8nw-d ģ=b?{.`f0JKvOk܊n}0ޖT${/zT"/?ƒure̾rS,jJ&0X@X$&!gzlC%+j&ZSVEL5dˈqnVpI=)J£2D[q NM+9(s`dm'\KZ{6F؇m %2 !pyr>rt_H$=,vFwl~l\b'8CS+9x8UQ;& H H4zt!^-k7yĮ9vEgD 6J1qӇ7,{ewH܋rʛ1_8߰-)഑X>6zcmlVB7 8M>h.JMU9(U-S\*Ә6ΗX%t8-ܑ*8JT!D "Cfc.k86Cg/ OYPcߚ:Ar,cS|9=Ĵ\<rer# XXcs;e1B8yV| Ϭ~>T$P|U1Ɇ }UkSHtR:F^F%#YEwFb:o =J{_e[!|Չk,qS&_= /y%O4%y- @%V6⹑@[ߵЋԙJ{Rc9dUgT%MJ!;iK Ytg)b;5]ւ#kqs8ޡ'`%}#Jb5vAi).vrYQOaN漺ֆܬFyEacq\l}fn # M&Y tG#Ntj@0z0mƽ6fJ` y~{P7Eeq4A*ZP@rU`;ݞϪ'8\R3i@xy:H[V:tM۰ݮr.qtZ@WfUnjv 㨪8^4ehP/5Ud/"Y PFN@X2@0>^"hJ^iNG(a1T%x+tld_ nT$qEY4<ߑNkcɡ$Wk%Hc,k{Cks~L;.lFo=20z%l#vv|$! 6|C+ A2gaH$ ƶ̚fC,y T:3W_\cOE-) ^" >EsPe=Fb̰ E*/<ߵv*OKv>l[ͤu I˅~l `0s$ۅi.{=Z|+g֜g'ݲYJRUMI:~aG v[\@ :h31bֽM(H"e(^PC5a>)Tw[?Q2KFQqrwVDskJ =nʍw Jœ\ߑ٬2k/g _w)U1 JwZ3csU3Mr(C}BVNtIT +ޛ(NSȂq*| 's;ztݭeE$R&5D 'nz|Yk஡=>ѳ빟*ݺ2#;p!وì#S+#j 2fUg})jc`{P5K'*$*3FXH}e>'g.e.jvPD궉吰%ڹcdܩ0t$PNfgo`$@*.NXI3mdVʭ®=OWvZY6NGWHmwB`=sMx`$'^/tHߩ沧q#T?uBY);KNrS1Np~V0!|X Ja=ڡu__`=8Q9E'X= b|wl?v%6&?:Ij,xs@ߤntrpԳd.Uġ]BC F> endobj 132 0 obj << /Length 133 0 R /Filter /FlateDecode /Length1 865 /Length2 36182 /Length3 0 >> stream xctfA-v6:m'_lض1;8۶m>s檪])HTL ,̼uWG+ciWc[+S3?Bhj`/f h+n.bYXY,,% rV.@*f@;cg9?Tqv.i{SgGXXfVJ˵cs: _i46s\LjQG/g+ KW)?<@Y. iPV%_ 3Mp5v [ ,lZHXy͔\M-ƶ.̀ζV@% Rfiejctqp7zf?jloflI+[ٻy9[?,{,ol e7E (-``""> ,2sylS7ggml@SL9iqIBKdd &_K*Ӓ!m񤯔k˘w{:UZj1=y`Zyǚ76w=&r=RBܧw2Wك{~{+9-H7ڐB=~5- 0its?YGnz/lǑ;T:KȏBf< _.,W>[/,M?4~WWYg"\vcJdvR1Ŕ4B< 1w5qnI["A0՞6,4tJٝpmJd2`lFE`$hcn2>X!ڶ}[PCIu$` ~W3U4fNy%M USDNvv$m-?4MPp8pki{bl+ܨgwcg!ur39OA ;2l;H;"JZY k}¥vԀ)x~G~&!RgݡiPX΅j|Dhڅ5~mN#xnuyDbf7RpIs"/dܱzR{ D'Z\5/MқR=dWM Fت[ Xmy}ˊ[ϼ' :ۍ? v n^q5Xu*ǿߴ986=[S+Fj$aj"79 ubxsI/N]2FD5 LA.Pd MY5pց]?@{IBtnXfrn rԕ<0LHWۥiOuk88V-Ӄ=L}EocP6Faqyɋ,s@IZ9k&ԶA)_KaHqiMQ0ȃEySyPY)QO3WIv=8 &p;%?&2S@}ٞDȞ\佭o6#b=ycd)y@r\cβ!@ t ͻF`^1)rz8\4}#*?t=ccRqـ*.a=$:qKC"U[=`eja`''wO䇮m LxUU ]+q-?꽝<+渍 ci|6t)6/$T(^"M]!J".5eW/8M̫_+U( ԬMdC$u.*$+0L4}irUtX5o"$6ոK;8ua_'{"Q9ڪUoI@(ӷk-ML`d(r5χp:~lu%/Wg*j5c\ֻveAUk,Bӽ{Ml2`:J.m5#KD6/s6rd{[ aྱN/>U@˨'.ȤyVhrqù[)M8RP)J͜!j%f9ψ3 -ۉja*H!zۃ6JW>E TMTwd_T3aTwFP$e]~T,!NRJء=Ax3k?J*ryKbZ >+S=ΖB'򠑍[ɌSVUP-w~yL>;ya;Kå j :ZvjwЉP];V(޲BoZq{; Gn+$E7/ 'EBRj^~O3V)F:Sx@q,VZnjI )+>E!@ : n}8\"4"}{H0* :'Ajϱ| Jv!Z=BNWNҀ^Xki3JNޓff\Oc)$ 4On2yʢ0dܯü蔢`=ٮ D-Mo-dg88c&?Ι1CY-[G]긤" Q@sR@R698&(y/S,JeJGˑ,^[93#&:R/^&<G"B4ĤknxHGz.Ncin!US #Ж5'Anw]s,^tcLV"aErgFo$!+#~K{Z"sym#j,20:DN[_\Ɛمc(%6X^O 9* Qַ7,㳱tVd\f5Lqgk+GPj! 3Ak$̋KQ I ^&ax8=xٮ b P+RKxBb-O^s|~Hl1>HpwLqp-UŁ+%+_][?Glj!nf-7׶{ȖZ%3ۈ~v El=7Cfqnҟ)BjLKێO#>z۫m.CIu. q)%־Nm.*6ۥJ0 YBYr]@ l;]lD~9IU0{ʥ]e ^;">ۭT\\3,lʲy(F:NPP8qa#BIiEF^b{jʑלRijy]U]5"ɕ6 U!QE ʖ,bʌ|Q=h#FA\K]?;rY-$4>`ַ,Fuٲ<Ѵ1oś" H6cLpӵ=8O6EaYVx9ih Z /=!>Dk,eWw-D䙖_@`=$E'FoJ ;^"LɈC10U׀ *_­-FD燷.ݘHlj\&6;r<`f4 zt)6ڑFBu+eHtlأE#s-Okd1Ύi ~ތiL (JL 2 ]^@2\9(4{"U`r3qUzw1M5= !k\A@^w;HV뱰迟*&I_@|~ {y{~aNxpI9T^Ccaew xA`Glٿۧ~jDE$#m1^Ɠ`o:3s2+,T2x9ɪcROvROf%hS%́P E$5CTI֗|ϼ- v%ŗf,, Z$`w!\D&ȕ{ #>>ʱL"5_@om].sBRJgu|{Id誼bPnR1 _ GDUzdve\qMxb7D j̮H1L~T2xhqxa.)g"8ɒ6.LpN7G\ (c3t:TMG;Q }bV.6g5Ī{gw-mQInzs=pa3%oؠf^h} X ;6Xj_?0߀ҭ)("l.\~l90eβ*Ea fNJʒq0w>o80c(  f\b:z hu ͓*~MbW`‡|kÓ ՘u6oɃon3F}QzI:iݱӪ7> `07N.U Chŵɔ8Zۃ$ z_B$U~:Gօxlva(7>tі/7!inXTPb{ wS|_|Қ%MSe pCr Z(;av;t`oo8H*Wl ,YMk^i=-UtLO;Q7:\D\gFsYu#8M JPXw83h߷:6l'MBszi rߠv w 849C"&\OQ6!YYN_nqa *t_&,0]}~`0o|"t0F`Gd 1Y?7 EDV&ZʭdW;y>Au[0$N:wf; Q̒Nr^ (ېO%J0KO-k}tQ9ߺ22 PDd.9Gi\]S2@ r8,I=v/ 3}5 ZɃ9 d"#@ܖIWh%k[wbl7 *\'WR~;dY=T6jqC %Y $NV\@va_Θ`$@< >t- tY,[@`>e$!E%vE1%w(i64t[$NP2Lh.=~p'T+ձHG- Xie! cys>grƅ3)8}(m'+]J5diЊs[Dx+ d\H6s>$qQc,P7.֎"D„  72$pmϥ~f^_ZVjW]G̓':E,c]+ky%[h?tڟC+W|>Gֻsol$8ŽmE0n[لo,/]J G9jjUXf $M0_$ʗ ޵N1~rwۓMX "]gh2Ϸg2ufHe>nb9oۃD=ޭyg&}oL4K!; L)+s{ K+!8!yqb)g$h(z\Ƚy6}x_tcO+'RQ}خ$.dP$dud e9E*ݎ &!Eh{bKNQox/UxkX:7ș<{rd0tk@S7C1'labB{_ 7}v›:!;T0?D 1*5D6LJ=AH߿>t "w\R'b$Q{Dbn1m{=܊y/i7Oy6[hCE7@q vt[+Nh҉GmIG2z4ޝqwCz)N3 =Ԩ/W)9wZdhF圃,'b('H:{T)|zq:mOHy秔ܕŊL;g{LlũniO$32/g#4G&<@CkEti`C|VYV(Y8 nE(v۾gP홰HrEX:.f?S*b[Ю~0P3ȩRuu#O/\wmwL(\P c(BR ׀Tn\~"Kj>cVGIgG& y✍ڎR)+#q/4>87=[`^qP]N&s ?n9zCёK#x3xe?AYBP?Z`҆m;m)K8`dR9Hw.wl& 8E< #O2ֈ2{B8>4wҔ]-zcsL{$(yupG !/lnjQTY4B!*W!|9"0jgt5JUdG057T&ţ2w}FFjMW>X20/aVsG.{lƋ(ʝSGJ'^}ԼacHfG9v4]146<Fr-gAyÒl(壳ձ "U-^Bg٨T/!Eu_2a a2{ÑW؜=UKbZ'R!XCU.b  Վ#R6ZeU_]"PQT'(3Xj֋S0ͱQ)Ko ףe?xV ~!l7sUz4 'e8!ErTybWv˂aeMm`, '+'0{R<\ l9^bBm"8vK;vnHkP  !Tp:0ˤ,۶^}@IA7ph+;#Zʙp, f1Iܙ  `z>1'@T>saNo$|N52S\{6vn^4@<[b|$C^['IP܂J\K`_?& 3#qe$\dssJL٩bljl)g >݋oNx 8 #;yFa>ǸuX.Νm?9iwٝ"Y)0DC0E9;vMWY@' N{xu6 #T.ph{ Q2v^':](<~*%҈E21sq I(CRkV n7ςzb|n%MN(wQ}.{h \%\ Y}LnK 峴06@ʓ^@U~ }~/a6]ȃhۋMdxSF=b<ôk4{27ym0z4cNoHݤ+2 miqVu?ߜfLۼox!<= mQySKM>9Iƪ%6k:Xt k>Dt[3b!ކġO[r]xvbvB>~Gά?[^nDjt핣WFg?u܊-Z!wϕ;}a֨XzpA ,bEOoo_mxaGj7(gɫVW%h/+5mj>5֯Y;]D_J.F|%1!5fN֬OC{֫{loH=/Ö3\/]jY(Df}[N-S92<&fOPLV<Scdt_mk{:DP6:3}bޙ*w QBxE3 v,D]mjLFB9~U,8 L}&.XjEUs”[`@Kdye1Xd::]oѳ޸<(,F4\(=?8Ow,&IP.l=ۈfCݳR0-<㙑9؝25 z`SBfzS@Ԫh> )Bklmȷ6FA E2Ɂ#A,Cr5Ύw'lck*eSHqk v%@Bqj! >eOVϭ3`p$#3MEzt-Uw D9:c__\6Z#SܙoE}zdžE(eM̷C8_4k&j6xi6ǩYclB7E[l97N,0ؼ 0Ͱs~tTBsl#lޛweFB<'&}lj!0Ё>{Jtӟ N6̓]ܡO1 C +  zf"+ĝAYԣ(pcsRs-4ԑGH;yٕ\Rpf2U_ٛOb !i^I;۝ZEʗDK;:uum,E]"ϊ0$q '*&cY){NO֔b8 &YAa!LT?XĿDgqfqɏG,zަU(1\Yila(72\ACyd_<ȇ;9A0Ԅ_:u)*9q:$= qWX3EؠٯWYFe_pv~=wsmѨt1B:40_@Iducku;x.Ui@ 4H׀-܌`A5ǴT(s !)SvYqEPO<*5&,6m?aE)ZPRۛ2-ǻ$DHpm:M>s쟱.ˡ`#kRl cefV,y 9 B$kA8`,r PgCOO!H6[˟n9 OcSastJ&g;;WaNҭ*%(o^l MV/@esH(3Vx\e} >o/&tK"eh/}T77rװ1%WdE͔O;cs{=R̓.Fބ%ßMI׼I6$؇]!q _scTƴ:K̩޳`^5;q,'EWMV)5#hmG`n 9?=A'䀍HpƂ7SLNhx 5XEzeuX{ec-jZb}W/z ͬʊ#k')¦`ԝM$>e)Fdh0W [[ey/Ѐ]47] e:jjxJm,g-TNLuj _PNC]Ű72z3{rW|t63eB[/~`^'bGp|E- Mcb y;HdU0%'[l E0RhEmSbޡ5>-kYC8c= {jJ{,ևK-R4n&?brцz9MDlEbM ~c2Wɖs|_`ᷠ`D$E/wuQ.?mT W,:BڔuLtpJ9i'fDb1Vg2LQ =d~[U3눎2+vԶ_*8v Vm \}\c@m<ǔ#ePNrtP2ۑ1GN[Zw<󐯜_reVݛ;Bcj\CI4m5Uj#Ac8#zv{@HA3M֬<={;bD(92#dKeYx}XC.q6Jgdӛ Wx4U8ҹ|R)GgBQESZJ50to]$y_}yfN1kZdF=MOWzٝX" ]txs`H΋qm U,(->[Cb5lOUy\4 nm@n6aWcZEԞ]Lu˿l[f5*\H(g,jfN"3>RqJT҉M]{C:bI,k=ހgjLaaq.䮏 t8$ױ&v9!~OlVSS&{P'e(BmE8E=RO}7Ów݀dyW/+uԴO({%!uRADkV$]ttWVV`z=V#,m1`BDžU2c~[ Eŀ)*޵k]1t_1p+TwwmLR|T=;&_yh#>)UO*%Jty:/1L&8aOW&*-հ ?6 hs$5x~FyYP0fF^za\57Umo 5J2%lp꡺B02DyIs3R4l/[] |ځI{Kٖf6p bhN^MO{g[ygJno,lkMp²s b®U+LjFZ F2V=v+&S-e+yI *IuY KOGFLB.'Ҟe3VIÂoF^BVP'ßF/_i;ю8xNJPL*,}ZܹBees!/"_iIA7If9vڞ9uBzdx2].„0|0.UcZ+򖝭PhĜR,-K x %N>W w>| F ]ŽYv9ĠVRMمgڗQ5 lMX4,7k_W΅CZ!j=幬88ŲooTώ3kt 먌AP0Ji{}yI"^se`jǜ(|8DФe>QmnԒe._2;^Dwisu%g(yk@Ծk]^8pS]KbSJwE2/FNkl$PT6UպFE8ܯI$HL 8s qhjM@82ZS@i"FӮOdE;ZUuP~ԧV~Zi~>T 󽫱!‰JVkձ{HLъ)7+)Pe:sXU|U7;[lj|7 twS')!vɔꍱ{ɂeAAKj v9H4Px愙B-V39'H@SK5fp< Fk|p^YQG-AZ1Cdu1lv5"kI9cݥ拾2v{?=:>2;_I%"m_&[-˷|n2Q*`652:ZF@񨛊1Ne֞;GW6<`/-VboYPbi~uKz#QK h.%ٸFc;tw[`'<;/lqzb0wA~zSƬ#q~e[V>|y6"2Cb<6<_6]'tjY+IiN{q )f]Mc:Sޕ=6烛?KQq8W pB}QHOoyw}ADx-~ c( nШ~WXcvt2 y|Azm|yo;)vVZ4]|Ad!Rא"&Qz†NKq@tI7j-LDfk8)ڼZQ S@g ,-% =^ؓ;g Q ?6J+xqc5峟zܗ?1dIC+bF2>yb%kljmЂIV5-zHQul>,} ^qR*Qw¥"BDdԻ{{Hx뜦vl/_ <{loCs{^(̨{]lQPͪM|4IL0с,͓I2Dc#Ry (BTe=E@A;S/?kC_s,{NPTisELɫ,*FծEkO6uGT^VH_!9Ƴm+K ccta#]T4$\ gC6jn@FEA)+ѫOh*LտOU^UY/8(Rr_-7L|4 Dqcf6@)ų|[rSqSNu6WE+4ޏҮRޞJ[8~ ǙU<=5e;N[^c=2@tw}2ʮ :(w@%!}  ,%mY+&^;[Sڊ?|~By_m#2̴3Idunǡֽ*_M1lhV]?܉-"7HHoTA5L4)c ?sX,?^1G>Y^]Pc>i]8,Sm:3`=IwL?~ HOF ،N\elL4=Z5s 9gŰWM~&3;7 Ի]կ :R1_rb[zSӤZ"=UNR-h1da>sD*+P9|I8P4}k^?w(C߅m#Vee "T`tgWb@u""MBE ԡ1]f TN"Ԗgd R3c7_l?^\: 6ubVC&iP/܅b'o]ꡙWuT}wFxfr62!%(]r8MԸFs˿, d0ףR dM'/Mx w[bl8=osD7PJ*IUMq8V˴iE[{>J572afljSS".hphַ2KN1۝%UX > {a&7 &- M2êg)$S#V+&IRܘ33|?`%TMߜݒqLa9iLs2Vњf)o59KL#ѵ@ssجFdN]rQhŞSm?>s5QS!|U!R. fOE}x@y4K?Ԡ)39ۦ3ߠhM"_iUg{L'/ 0]SF vN7xSfF&rn;<KgK8FME:h=Y4Wc^L-ߣKAsl@dgeV- VWQ]sN eh38vڅ!wIh~hX!&+н2Pa|UOyTdз =-\hOOw!ש5Wg]]oxhAO~ay /|ܘ!*6;G?_pOorF> SG%qawrsаiIĚ??;KjM稢jjio]A+pBKYeO'u 4h˨2).p#| p}5tGLU|WkIVz23ۦ" UW^,*0 ~504#5T?6-+Xiп|ӠK!dfBΩвyby$xWfq9Ck='UucM_XN11[xЁϚU?m9̀^<@Yj>m=_@a.P0z6av{FH a# >zD"ZatLfЮs_SZD g@rs;`=E iٻH6Y[-o|Yk=<+݂]bC"1F-?߰y\g\ݸ !@f&KVNjVJvC|k1vSƶI' Ѓw1czU- eVԜ (IVU^Ww6Z*e :*uj啤Xx):|ۤHǫûn!s Xr.,刕m^/?AH[ zT@ЧJ 2E ű̗7.ۨUNx&~?, f)K? $ t~""{ XMaw#s~>joWAaoM~`5K}ퟶyk9Dbq+cnVKsX֗`WfӋͥ5C __*4P07#0»{PцCJ`!_r'^R^@3} g~q{^xwVԒq2Y͑HY $ﴬ=7WE.Ɇf1+JypJTϟksxt谇I }-qgؖMŐ"/36"|5Bٔ MhMQj1W a}"*o?)1R&*jWΎ'.ܦqySFPgMR;X [ O n%z"j?^V!m騺x>,Us@YILoۆ9uXB/i(ةO(5ǸyM| H/#iG r=*7e*([XgRیEGtb *k}+%=+/~a-ѰI0uPqÓ2MfG2 lb-hlq_P*TA=tH$fYGt wp6k;wqTp[{o7V) {jO\GJz2e#(Q*Wn||xq )ufxtjs(s_eoAƷnox+4%_r> C5U&*\ѼIx7z3 ( LFdzwQH~-skX%/%&s[7M~VnNޝw{%n.=hsEzCi;[a/LTIo{374+5;V~ _'` TVăGJL{o&]#7Gfr"im$Mxkg!K.?"cwbuL6YfU^>}9o$ [K藦ǁ +.\\VC Ke*ezp>tˣr?זX3o?2T&(anC\z vrNF|B~ wXR._6.Kц/$⋒㧙<$W6Ks>;-琯!':\gҫFtisbW4I!zV !CKgvӼ6|vS^ދӋ_8ORoU.B>.o51Rj0/Ω]|aFcoDxSP ? Uf1iO |XJӅ'< mvF-H MKӏXvZPDy,6Jsp d:) &I\q:q59iݨD12ar ?KL%΁լ&0FelVf?Y{-C8PqX(J Igfn"7L|۰J]}\A{fQH; 'hxRnp^͖Qq&$7D%4L޹:\j sjP^8j\]6Ȼ?ǹޏtPO% Imz#`\@ //MډmvKT?pKV>A$+F?Ha|VuLXѹDNC)g+."==m/Fv(uԆN  B:]S ƦnӋH+ [?/]XIU4Cr/f֞llb碓Xs Wc-瘿6[rQ^=/8Oʎ] *MKLpu2*UǡSX|Um9vh)12p1֏Cڦ1@S؁ X*X>>Z٥1Dd6p}v4i"$kax/o'2FOSd4=]148,-p>$鼳oJE>X6M6Ȇ}zwof`ံi@;|rT_'_4;_|6O˔/a.I!C*oA.wm ;a9B:üec WN u8Ii1 `ëGs0g 1+\":ٰȄHe*i@m@D&q͕=|$bC&ЗoX!X:i/= U)< >ʠ Q`h޸JH 9U׊[.Tdhr)?dT7Q+lP<9|!\{4XI<ܒߜ(8.~cEf Fꅐ 5Sivynq%Znc׀QUNgs#kL꽮0)q \Mue3'Əj;t7,_ 5s,}SwɄ'w|)q5.qyJ:̪0`YD9ȭ%;'&+:>brBpF_uچon/u3!юdU)cLjH~9~U)a Gmș @9>>O$Z璝*vh\E2d$= U7vjB,=!E Gn0qSq%Ӗ/{$v]f@*<&v"Pb3e`/ІSPUA❦F7gN MbGլjZGsߋ *VҔLo2WGuA4:jpm AƽKd:/H5칕`E*-ITrk_eB4N^l Eڮ([B#ngǠUɵd /ÖI=CZ;*l"&8CoBӬ:&,q8;Pܣ uF4H: 8+&΀L?%ue㯟Ipw^quHh)Ɇ/~XP'`A_k)./%ļ079c2 z)g2SN 5GjZ]NZ}a\" vE_L$*e~\?fqlH06$8ɯX2aPn8FDaP,h])պ˱e6}Ž=O?KԶR' j)v0U2FV&|q;Y"{@S=3.` &j|kA.y J\7 W|f&;+h+,d $eqXܜ%b\0zFB)f=Q|xnr!&LlKM ?f9|#1C9\ͣ\s[Z(`[bٙ(c3%s?@ED͞C(ы2ZrdYGjPeNoIjJpT玸,+‘LW VO 02^x#NTnv@!p)"pJGUI?3DPaAAzRwׁ+edZ/XwnͩH>uEj-9rnqro! Ē}?ه#+}ͦP}~ڧ`yzs/WJs~4RH$`@o%VckiBvLg-3[~U#s N{ITU p V+4ԕlEtzGRi(xX{rM'I̍~$_"㶣{Ξk421 ;^Κeg>?t?2zZ0Ы٪ųrse O= \T]Z0 Z^؂qVH:ŌtگEu(,oqyMlW"^ }΁&C.|w% B6?9ҰЄݣ%1Tw0wP)%W22a8菡jCwgH"M 3y ٙij0&NrpNyD#ݤɐ7h2_o}TiTa7D9VއX}TuYyeBYd:O8C6nLola!ӹcPyRBG=)Ƅ} A*bVL[/#jݭJ@;B ^I.Jscq}}B6тx?]o[ePG56|l@ޥe237yoCǣq>j/2Z"ꪒM ʲss~wS)NB:'0p_'p/9MޙP{Jiވbh[L<&eւm9C6sW&!{ijIg?JZk :e`D2Bڒ=-AG]k߭i~>,)b8-C jaHK3" :Eup|'4?,d$,&15֔_dәm$V# ;+ D3]pӥLX5j_ߏ_()oj[ ^0EۂiSY-kDL=CK뇔8=k'i$5.O:`H \k Ha1׳M$Q[Ǹ~4T5TժAV0h!<{}<#/ Un&EZcb]]i<d350Ա9_EJ6YJq(TG5|Ѯ[$t&A[Mh,)d} 2nq l8(gp=ݤȭڎ!}5s/轸@eR=gb#_B[MyymLcŨETmvv8mW Й43"q:I#W6 ZJ +Xd' wF0?'. }H7 Y[k~}6g~xqV95vh- 絎 ]k#lZ4!g읛nѷ GOw@"ޚXΈjotSUe%{X?~(kFl~PSe+4b|[ڪC(!џ +qۂ+𫝐 9GA)D^1vUe:$ »-M`MUV1xjϒw9>:Laϋ~Uƽ4ǐH|_UUu`*C*~e=0> |RE}[m̝HnVmSz =Epqߠ:Gkf;0FzW*_|ib)yFfc\-qgܺH~~xXN Ic- iHxLvi#7teZKEdwy>ýA_>{1U@g:y+!ds%+]w'mAPDYd-3|LՌ=e-ܟ߇d}bpFK8wuL@(g`>y<F^ص{u/vG}ȔU"xHqJ Q-YxHe:Dں.4DyCP߂G\Ԟr?bYݞ6EV78aJRz ah㇠וgfq5!q2aB/܈{>8ߧ7w}:Ս.KemcZ߰'rlKw `h* }"!5%'&X3PbjFM~6f܊z?0x_ދ𠍢G8;quLONHc%HQԿf/_Hb?aǿ}^sf(jȱ߲Dp4 U5) ߖg\Mj&dZa]vϮ\NЋ*> K~W+WNE>ɟb@&ZZ>]Vt\'k}6N ~WiyH٤`3$x 2NT*QVdsNvi1__$Y/o<@ti6z ?]Ha;QZ~1{LT Ua`%vfENSW`Pza* \`Fy V镵E";{:/rK0KpYl3}ҸIzaUҥ|R*bss/H B9ICZo1?TK}&Vnb٩;>W@h kbkg򎶳WVCpۣ6h3Py f"GO|^K5ÚMr\s{"*Pu b1Aj~%b~DɌ/is]O6f)}S tRl nʝ>K[[CW9fvψ΍w0(c\(wg,cQE]~`*Lى&uK&K=:DjU Va D&>)DGWvy%J"Pi;?@PpB1E5p=0Xh$9NڭyAkGGsV{mUq:ZB3ru'w k54:c="Ȇ$L=?BP[UOpN6F BSiw-ѓ@\9=+2z: lFڤ&n.Jxj9!d2DFH 4c3^WhT);֛m- ۠<\ܭe&7=;5Nkaދ`Q"(kgLU Ēh xDߡGmWyvBLnIa6k%Uh%([+;b*}^&>nE,- /2EC΄+\cI2bEg!rjbDH@Y1r2/ Pˢ-^;)}5J=onM;c_ Bj4z#CTs%7˧wL PozgJ~Bǟ{ĈUVU:Tl:|Rn_c8LJzx nPEGlE,vpfy-PEbJN ?+6K!L&hOޡߊ0r 5෦ stPǃ|cbv O\RkDl0joA*9>C1lfv_z Erm"H`K&ǢZ!C xE<MP (5?{N꽚 4j :95[V['h5bw-u]&.,9`9m}B=!zhT$ẵ88C-apj A+{ м_e(=vd\1(?4PF ױP,JmPIj5g˔ /FQ22տxeOFr" ~'1@H3զP+X'%BN;i\[mT'\ܻݤOY^khj{ɎR?D\+ʛ&@ ΞdAaDQ>åo wT8׸qBkb:j(.io=Y,pMѐ#nSO wN&djN vp= endstream endobj 133 0 obj 36793 endobj 134 0 obj << /Type /FontDescriptor /FontName /Utopia-Italic /Flags 70 /FontBBox [ -166 -250 1204 890 ] /ItalicAngle -30 /Ascent 890 /Descent -250 /CapHeight 890 /StemV 80 /FontFile 132 0 R >> endobj 135 0 obj << /Length 881 /Filter /FlateDecode >> stream x]n8߃"$1` e b~0i/@#ݏJ1M#2Va8]_px苧4,U]OguY.Voax>rQn]ǏK:؏ygע\.?O5_ܿJ+N׏\5_Tv8Џ_.6e-6]].hUL{z>؏Lv c 5Vp ^A!B]Vk{FF!)dBVhŽFw -#BG8y'qx<qH x<q8> endobj 137 0 obj << /Length 138 0 R /Filter /FlateDecode /Length1 854 /Length2 35174 /Length3 0 >> stream xct߲5v~Ivl۶m۶mNvl۶?o_z<_5kVլU5*R"eZA{#S1{;ZF:.! TNŔ nj7v\L,\lFNd] 033s99WX3djnbO'CS[C'kJʞlvNNd4adX_;镴3027quo?R%򟄆&v6S3z9{KcS ˜4K hcP3@gqS?+ ZxP7Oqoޒ.6Ƃv6@b& .3Cgv&N6v Ζ-#XX[ۙ:;Xc23iٿ#o?abigPv131t2_ v.*KBϲ.Nm?%v"f6VBHÛ@OL,NF6˿"lfMzü̈́}I9*Yʱ;wM51Pp\dC: @F\ONG+]O& NQ~Qg{1L+˔jӑJ:ZqU4mǖўpE2:&7-ҬI\2e0IcD{Vw7Tv9kն XwPvvb+#ٜKy7Ev inY r>7kMkdL#N?mdh^ zk: °ږs3eA*ią~KaY'iT y%ʺ&l;V#al%M2dByip݉v0~lM0(f-+xͽ|Lb]dMM| !m/F¬;%m) e&Ǐ@t'hC9UALAz0gQR|9%"^iMOØY>] v3G*KGș}2j5Qx9xᆷoofb=-?|6" IweJˁce2<-:q:g(V"[HzyQCv]SWLUTӹ&B3HoB",bmPY*N2Ђ9]VAG1)JJl]CmѤ$. 5εt~VDw!@<.a ī8ZIG>X |֟F#jqTImWFM[ibM.D ђbD6zC vi=.ON_96 tst *v]=kIPeP+]йescguư?:YvtScRvwDfB ?&ARl? Llt~xzjlJ9ahfJ' 37U =IJ:^!Cʌ$"ȅ{[/ŖIUhׇvJ_ EJ~-P6\nvZ!%+:1+UL6FǗ3>SMv 툜7T|>uƌj*x[G]пwY8Λ^`4d"}#Σj<$ŻH݁%5W(R`s.5K0hS CvhLtZuv`fG3&+uG?iWҔ GT,0G"\(,Q˦r<}eo6N}>uj% cteSȓJYڥ p܇M8̖O{TxMG`oB+ 0ۃXrjhp O=lit@Y$uih|8֯? pN勇Q%Gvh"ۣaB=EIz{A;4jxh8W9UT@S{ofsL]=}bO&_m^ H$ LgJ;"dh4 BJ+LzJ@Y".Ї|:t Z J~o+t+.*ZF#uCiqwnseʘ 9 e;L/ ]ꨞZUMۋ$?Co %!9?Wnz'|=+I.wHvSK떧5!D^j"Tx~e8=>,L?wtO6_8HzTO`O2x{jZB?Tn?YD8ߟ*E`LKO8J8[ +%65?WҜoyXr] jnWrJwgnB5uA!WZRrlrێCsj3\ߛ1w{.gRJPE${VOՏÐ{}*j[ 0U@S6iQ*ږ2qF 뱲R{6J Iк }J/,_K/OKX-a\=n, U&Gt6Re)wRPӢO5Ң{@ B4Sv5_N^e4 Ԥ?Lt [Af`@J$c̝˵ -#<:2'#yIyx8JSuk.L~xas8}-;d!:`+nؓl[b ^02-I:vXXhQb\c.Jfs 8=u%`V4Ga?cɩRmD]'fKɰ WW̫w JA-4}@ʰbz#6*{2+_=7ꭎ^e Ygv Пy%z> "́0]WQ#؅ Rp }|L@Qsn~P95d='P gpdTrΰKJ!+y Yt^]3y^m۴|.ŝ4劢2G=~>l޶LJz\pP~1 UC@eoVM[DiE颽p53Dw C@8.ل]Ggyvb:u*x> t!vgDšeQs\(:}]2Z9>)v6e؀ kkGgD 5Y;B)RF=L,wYGnx{NiVJF;+G䖓lIiVp(Nt(ƈ'0IBc&R E>&0h?T D6Sd/; d 5=90Ub".wȞk ĽL4)@l+,{Ob9WeI殇ANhWzmY- \.#0򤔃;<(YWGzP Zץ09$)9adQ8qʼo5fzڛ_L:Lջ;ݜenwjYmCݷ:6{fLS-4cgV=_4c=l!b`/ij4[*)/Ғו J:J _C&&md]9!^#W,_=_''=(hg2؉-t+J+F^(E&q,9؞# td=I}U^ @uhFhʛfohCE.꫈G;ƛi^\!,x&Oj lg$3߻ k`}.eҩ}Jf^uꤚ/{݉#OP]<_pFOʒPQcb`/-K~J鬶x7Č(j<-7!O\PNyu6Mywegg1S/=S贻'["RJhB9mEfӠ!łXi{hpzٟr9BnBhOJsLnrjV?'qah\nMa EVB΀]ƚFٛ| ;9? + DBxPQzgw˼^&#>bS ZvZd{jTKlT7r>]k(=~:[Dt#(UIjjpȬfU"@51#, R r> iT;&jϬycw 7gj^;Bk Қ:#-!L/^6>ݸDSQ.guC4G\rx8ŵivx8F+€ևn^}A/w`68fO$Y`. k W,xVI9_cKJ/ŢPnCO9r:))hx?z)\=RKﻗ{b"F$ ~`X$nyVb$Kdn{CvX3v.…e}|D_4aZI8u:E퀃(ŗ[n8|Ntq4dX%V}@71* O1"UUA)";U%I[xe PIn04YiԑNV:GXK3߈M4t.-1k xzSc3=S-((R$*=K\K}m aquC "&xDv.*ff`"aaCldin?Md-?2=Vzu.7ˌ%:AAmaABHaoH#Cu%Eo;A*A?f9h̟mJ3s_ Jƚ"l),79 4?fͿd><1R{ `8ѿJwP*uO[nK6 MġȒTn9<8laݛ},$~*vXƊeU&əGL!QQhOzbE{]9TnbuE@?>.\ָJ5.Lgd~5qGoѝrڵc$8) )"a[m+)4kNEH_#];I=e@j+=nRdfZq;A*1j-rM#EgRƎ' f_{[\ \;@=eJ,}"{u ZgjMeҌ3CלC^V FG'eډwGZ.ٞ~pq6^X{|1Xxh79J `&~}{r35Dbe;%:Ŋ_=@j#Dn W9ƣnym Q4.%>p\liu)A1.5:837o iҎZ%6[[cF[?֘ xD/x;J%KUE7ק 51՜v? Ù{lo HFXMa [RS$vAf觀<$xrmқ. {DץRhů8hA/G|>'Z/2Ы~Xu$Ժl-[ N^dۧN,~!av\OF|vآYld^ /4& Յz M PciOr}źFbO27>7c$'tѿ -0eolwCϳx 3kNWLY Aaz߮6axW@bgL [YߍLqo;#)qvA,_T}fB @02:dT` L->whP}, ezj^J7Ez3w3l1}wЭ[%ҝ>d>Y4EuP nZmvXQ'fbNqʐ?]=*ڭV;mcn˰`^& HY i],+mi[Nb(Uuxj5 K~C88,H dިH m55Clv|ATŠuˠbq_ Y"eE]於'YZ&|6{l?^:eI[bZ /p}8}P3#`LsĦnj%AsAÛdO9EDfZcGړt#H/y,XfXA U+~`8"N- WML3u*aqTg-9o`#b)rU۫!O;jw2nfyv'C2R}H|LkP bsp۶"*Nu6<AڔYB@R.W4b#o~\nJapGِx6Vtje2+O@UA*0B#~v^Slȕh+ܔc!Mk?ฐpv5{e+("IO#}GPj9t1 ;)tgO;,: .I#p"V캡 )()Ao kW׸.BWiޮ{nǭ3_6 8&ibm a IO`@O>OAzHeK ֏a!;Q FKLFcB}-2^"J%bpDaK+^~< xJj1;ʽ9z0XOH GUnJm3 [⬅_)0^݆<եSN1|w+T0hgnըpy7Jʕ l uE`HX_"E&(嬓#9!2".p9/w¦k)$_r:Wpƥաřt^Ri9n:^~vcqڴM2D1SMf}~W'3,.<,w㒑x6>-!62~ǏW$H16AL1PQ=WFk Fdi?G7 C\2󓳃X~>ն?*p]Gu!0ywO{'\P?؅Ea~pȂeYc@yERmfhp~7 p_1xvPn ߃Fh7M XG\3^cD 4ARNhHuCjw7s߰*=7yچM>?>T. @%ξ @P0[YbVZ\6\吃f"w&'PX6Q'*`~rK6/z3of&bYf&1(LVn~=!NYoI8O 2H4[js}QR_OR"5/Q@f0hRKkQ <#}4\v%c9>yvb+S%͆.smM7Ƒƽ ݒNng*M540e؉>VJUPp'Tsae lĮRQG `+R`Nwl0DGԋ6 ˴b i=| >T(CG>%$.>`A]!H 7ri:cZ9jJlLs:2?zL2)QߦHtMuGE{I۸!q=G簽C(RF)# e{Gsľ~B'& q9UE;wEx&l#U~9G/wCxIkx:Bbfڰ9x֙"`aXUU;>u4)<(|}6^F݋(b@\ Z bqWϢj&#LH_][<Ӟ"{|28V$6HP2&C(Cg}0˻IԱ&bʥe (qrsM?d/((=MoU3Cv/f^#vwY02/ p\H"#S LJf w ]C -3Y5:pr& ^Iȯ \Mm Oo-F^Qb޹ [0okU߶u 4*Pw! menÔ=)ZQ 0N\x'!ИCH+nsJ4a԰WHὭ{wYT~/n)jtSR݂2SZqK9;K 4h:5ъdߞteruvg cЊN0A,IjZ>8 1z$V@Fs5JNOl]+D,eED(H^ 0:1;D ehrHv&jx҅- WK Ѧf> ħe a!@;f ϭBb_ڊC]N P99[Dhe)EV0<)0h~gΞ9Ð< <9x8xH`D9)W:ڊѩqdfFwu=4Ty)h ;-MIbŚk!0^ӆ/8Gle\;S[Nz^_*qL79O*웷.FOgcHtv~?Mk/Ӣ{l0}:(\2˷IӁ gZ@~d9$.-CIߕM,IԼ/Rww2XÌz__!=X&yYqHtkj$ ,sA7'aZޕR8'ʝ Л'.sIWkwt~D= FxUuJ<}DX9]:sz ۦ0^]JR٪ݦsOj^1 LeLМ/e6?KS|K/#P\WYIPHo=h|E(Z&c)`iv֩tg )f?n) Ok@-Ns@ ǢVm3,Db}GV?{/7ea0ͪL]湵Ӹm;fvDM g#J,fq=KştE<=s^(P"Ljh GZ?P4| X妮3.5P]m!9키iigM\RR=MxW/Šר95JƱ%U^R0UGR7ew[#yYE٩D[.@{lZVa?1C}[o7>5E7?A^e&;fGa)Ij1u@LgS2fRxd]@8cl(m&[5 6 RDU^ u+9xdrd+OupV(Jmi|ZV"нKڪƻl?q ?O1g|Ӎ|I $ = 7 T5*rp"/8`?[t(V^iFH(۔B6x+V8-8Hldg:2$[wڅ]eSL*RH\I8rj& C6,Jro9pñB!9[.m {mU޴Ħ)VCvg%}&xs dY+ S7 F xOdѠVhGVIhΩˡ@LEbe>)ԞYV{6`0 vדh$&`c'Yg]d%d (ZЕ3085P?lҾ'5:u$@j䣳@[eUUkN; x.%Jfy5/9R7~iOޙ4iB#(gÍ9~j08QMO-! \sN~}srS-q' eZH i_fɴX,nSRNEzE*&,> ! NӭMw(\希M ը*(KuStZgD= Pjv4HPSL ^cmB:&V !*oh]1r\w7+CsKEg?ίAK45xk+MYѥ2Z؍ǗWu=*ӥJX A{xY UX #SVHC.ط.kXCO l֫U^4@.{Lz~c!B21\$Wu=GO96V%9$-+ˍUde?A.a$h /gti=&Q,ep+kɌyW/c{\Q=(`SleXbՅR^*s0Skuw׽nûT/Ch*1)V۹9US`xMgg,ɵ)B}GiNtY,8R0幮G). v~-/fzςW*$6*z=2 ʒ*8GS1w4 Z̲E9gOѥ 2MfD= ҍJIyX!}oNWvC̫V@F|p3$ٷ}gN~5m`eUpOJy;O :-ȹjF_:4f+2yة{Θ>mhٌ k g(pp4Ǽ:pFbsF4NQ!BKN4 `NL3p`iE3q!H hn|a9BA&rQ&83g$ νysu.ߒŦ]Q}Q"Mv,%T 3 ֔.QUD2{{@{6#[9 1Cs<:/n?FZ۴4^8ϖTxЬ 'bFɰ ]S(^C&>6j ΀?_:ŀ._C խb, {̷_?66lҷMo4k,s# DI1{6߸$M8DBX F _l:%h~IUu=:;־}LlgGVή PΤjREMH6FxNen]dPT> s8x 5GC+=z`g@ǃ+8}E{gOe诲&Ww^kzt8z L$m kVbWʁ#.,wy Lؐdg^S JC 47qtWxGT@^u+u8% 7yλqxliHC-`f$Rӫ:q@GՆסm%*p!5PMNxE]樊. |ŽBα eT)dcJMJpl |BC4C$~ll9RQ!BэOj pR281M&QR!% 54'3G\oDk9asVY.{2ց^fZ4Iy+RMmZ.E}d\԰e;88g]X 3+#:9dƄ?OA=NupꖁZ0̛-`p0v0+}Inj`P #˰,pv!w)^XfF0l>%q{*5A 5+:ZsF>k^ۦ5/%hYJ.1+LcYЇ+87Q&BXrـ +ZCXt"]HVityl22XͿ1K֓l"'AEmEo4j]ݞ"KX"D#PoHjE",*;~+{t2o i8!)]jY ̐x $6JdZ<(kyqhؤ@g"=OaaPSW89tjrk5V,(g7uHE&H6_EXE*b iز1E.hJ=5v0 RΙ+t*GD_K; ]ܗɐsGx)B00 ynk[9st% P wɽVیՓJA P; ^ɯR?94eσ ߩȟß|- v A6l?y3},E?v%}a_`TD{DM=1.IZCȰuLڱ!vzfW=zi;8[6T RRQbhӡ!/3lh}e&A]9U13z}X\Ǚ4Nr yJd,_L* L7% `/6}\P~M<7%TI0y DJXВF|Rc"ݫ'5n9oc]*?LЩ֖19BG;e548 j7BFxXCw# ^hKW}B| LJEr} i` ʯ&2wcsxRv×Ը6c/=S_4M#^~5 9e#ۇM:5JKy^ !{ WclkGyiXU¿#"+k?o;EWGc4]?]R>7zZ>|tU',dA 3EwJb7灅"nj4`*-EX^.l-6οB)2u=+ y(V>..I ̑JFIZ a.H ^xw)v-gGu`Zu%<-g}ĖA2)[ry 4f[ &d%(x,nOW@%^XJ M(3fSVI eZAӐ[M8W^! =b(/fܤ M4)[Vckh8R¾@k%J#GM}X/ ħtw˩CD@O2-+([ 1hRWٸv0sK0xCsu'w#WF>&?= ʾVC ZNͦeh7Bz:v|47uGF+5@~vv|x@~Ltf[YKO`Dts / [;>A.,"}s. xZEzI @}ŋTzr)@Zzŀgy2}\V^YlkN 7渁?Jv'{iRS٨UNIj;cB_]"'Й#WGNR_| { INf}~yLf:]H'w!b@QM]xi۸dN,ft4}4cEPձ5_5 {\yIJhu&ؓ|VށetD w SA{FCD݊i׋\MM 5O \|:e9Ld!Y6ݺHHrR#V;$}If&L^͸T~eT@8 Y;ez4ZLy ܟ_ihēs\"?c?B|T_> 3eo{avbo&ƛ^SG|A&+H(tKwޣ{pF XөgJWP#A"uKR6w[)P!Ґ&wVJ]>zV @A1 i43C}J;.P:3}y|H!xs2U&! oրǰrTXk s=".Y[H,?tK[ KDŻmlEphs:+yCzYBq 8hg0bgD\~Vū"m6m7ڶ @!cCJb1Git@h3 fOVJ:-&qzo~YW=3ĩhP^|{eut }TR;xyFm/Gfzn:jGh滶F$L!CE):` և?((?\Yt r+i\bxΊV9xS~(`mK"-0WO. )<50 KVhǵǝqjUEan/ʣHJ RhB*tt0š,iN2)" 1 $Mrb]WZ$>u5szoݶY kÞN.̰Μ>zc@Md2gFSm㕵~gHrRZ@HY^ K/fK":,zeEֵ:nT\%wTCwճDe"#A ``16s/A64y 5Tg;䧄L'[3L蟶X(HX+N(3a N M1Anf^JJqv S^!hp{? JrVi$HORuLJ C ہ]ixOX)]J _D%W]2gr ݓ`@ɩ!C0bx;ƠLT.{1X 5ۨK eċOCoRMO14heEFM^zX#pH )@- 1!d*R9TgHR֌ݴs cB,,V8aO]WkoOk B^|! #k^Tb=.xZ~s5Bw7Px9k ʍ۽=qYxN5h?]V[vZr&.M^+ՂuoE )z8ͭk(<|IT$'sY>44Ã,fچ; "|%^b>KI>hm7u%fxї%}S fO֬F tHcg,5rv|h`[<@=+A i*=[ilQ#;֖<6;( 3* CM_P*w|?V V>tP2`Z'naYl`uzVt&5RnLDoHJQd<^6L*-3Ve~y>}1+D',&41gdIg)vlMgLJ$ KI;yH_ ЀDI3{P!K  T>c@4*pij2X،C c{ Ԙ9Ev8I,5O3*ap@tc[#0&PJ2/Mm$WSظ{6 kG9o6c$Ӈ{p~}x(jPePܿ\6skB,rS'Td~5.utjk;T}gɏ;ȢDbՄ'c:lyH(4IT(<>4 g9FbxQ;!͕J̿_^gIec[w }gL@FxU^O˄=2(ӆ &#AUm&92i='KZk o(Otuw1bNK0 qi#l敥V\Ci¨.tzѻXJBbh^L唌BL? KK,>&Fʄx*N*)+bNkcC\ҿۑ](uGiPB<~U 2sˠ.8%ȩp7M}Zڄ[tC@ y/>$Zc8޲1^&0ePHў/!ds 9H[fkN"m:KZH/TV };2uux*V~O 0vܠRH A($~$ BEO|<j9NLM ҇@vwXQk&km(]w޷󼸥r{XLO"o Q &È+n ~Z٫ kj_ h@gv7pG2ĚUfNu*ACha5(Y *ZoqI877tj6zo{bEhzN!2Q?fk~=m]RiQd h!=OLqKB4/7^a JѬX[#[A@lT67`;1cB4d}囵L"]q2SfX}[߅G$r#Ē9q7JX#o kF=YkQf>>|n}V:0ۼ";:8#0Lws;xJ촄jƿyG1te4;L?VAHmeNwK۹w؎UWd0De_ ESB'xl5fgcU)CT/l|gaXTĪR-;18`.`\%k  ĞJ̑(FГ9puxfP1ؿ#A(iIҴ|ovv씡豤dɴ7!Zry\{F2^Z-)a3VCW4>?6/ |\ sxFUkk?M5|Hc( 6wc֦oP԰EصܵUG+!-1TV~8-.[R81"h x^/aݴhϥZ'>a`Py˟R!Egy{Aѣ_ęGJwW@d:7Q.:3ho(h@~Z$<:wNFɃȐsfsO5DLLxZT|d̀ c3aa;[˃J< ^E}gΖ\l{:dK3ٱKjY57Οe VY+qwrBSY:uas1!B?Hꍫޞ4CXu47NSl4=f{!*Z= 4 vG!٠x=XZIwoe< DjCryGY6&ꔻ5u@VW8L%R~.M5<s=k`(պƣGGĄ"{ .@F识bDC(RI|"..HN)uY6csƒ Ke*$W]`w5N BNniDra-N?1}1={Z/~-vP,ڮkN^|S5#Tǽ;ĵbuon/A{} !T;$ɄׁVN(qFxScv/h+`FyVP\\exE?S5JN}Jmu s>$IjWQLJ @*SS׿9]89hr l[474[prL&pq)˟Q6=0ZOo:vPt[ Зk^D p!&F3Q \PZ,悭;dS5҇*l:bVMI,FB%y/bi*h|2n6U2FHPj9r츑ȓO~ DۊjSPP_'ig c21]( ҔS>o;FK}X_ |/S}#wѿrՎ/12m8f15 Y.ĀǗUqBxlnХd$75*ʍ&VC ? \vHQ&I9/K,;FPھfp:j.am]^eO .0ȃM1yrB0DJBl^yK4VM;#i ". Qb1`o-s}(/OhV䆘VdФ=Վ'/I#$j^!+O?R ؽ~ ;#[?TJ-A8X4˼3 z;'7Cy_6pW9fеAxIiߋo}}LodsJVy\d!bj$'.Du.r,2qah8fdIrAb\W!p(q.U3’D Vo dPa(c+!5M/SQ>1!=sc^?`IҒ. 5]s}@+sb~{lZE8Ŏ|e)&T}Oɖ`~HȜųsFIjT4,6۾fD`h`b* PE =Ngi:\=%.10!@W}́+V.Wr$z~jYٕGGDczD]l"V8`jq-c! "$ @M*,\444q5bbd?NTc_Ym:*F6"Xř{;f=#R@N2@[I?$) U]}+ږ!+;`oJq#Y;=ry>@X+$c[rkܟ(ƺ'p^ACf [F;lG x<܄/BՀ8 'yE [i:@WАTL4=EqVKZhVy~`èuOЭ=uf1G.dFjX5@7Glc luܗfzX~<mCih.w wp\/n 5(?6yfƏ5wlPt*\$#3䖓0ʋP\ <|&fݞ0#4Bߔ9n2xdL # ͏v^bp+5M>,3s8th䑋m䨰)\QDzspe;dlG/U9MtMZl$0A؛e :йpZ7Ō~ V0ڍ6oɺ,a Ě\H5/E`2k02.\XzG!;7F81/aA1!D+HdۂS .|\mz>v??G֢@|SJ)d&n|p?;sRWپ:3@wza*~-!z.Yն Y5='4%5r `\;ee,/MkLLPUAّ) KD IwRtNll{ dGM.^C٬LDO9 +F$EVrϺD]xu|h%)5d/Eg Z*SPף~l3}m[V=[E|KыqKjJ=; 2;Q68{8YvM٢wuɋ}{rO-@!P6AQ]f ϖ&wI)J o~ޏSS?[BHC:4$NVFTzDMw}QI Di#$:|­-Pc彡|N&MJ!6iWSifǤM\Ms^F 7#KSnN-*(/[Kq-}m8(0f 7\`OO&۩ w幋W2x-)&Gp#ԬQ.KO-~#X!EMysun)r1RDcEʆr3ez4Mz65o[p ;]ՎΘ uKhn!hK4h +P^Nak+Q]/ZlOy襤C_Je%úq&y]T4;^mz]pQ3~ޖs{Ux_y²g5o;Y6J96)rཡW}AWI%d<HN: bWn]F§#6)$Z%xeb do l^&X&'9%.A@MNEl k_ (.,4)/>WE-.-Zfß +ܜ[.MLH5f|L}u~XdvO ,}vnőEq,31w7ǛlƓӪl9%>Oَq#470KAH}-m|UfgU<R1,@c[6dqG{DD>0"J20t@R4u_*ICi;\܄q'xXnbӌ"ڐG:?;U-ڈ_K{3L2=J^mg8Xϑ3Đu|i`;k7;l>k:xk6gz[8w'Jov Z:ʇҽz\5`dHO(.DЬ 461j[t >ğګ2MpDȈ #{ck~c^4R7? wKrbKF!x!/髷p7tra5!GNb#)0`XJƩtzi[o kZdD1`pu:1Hd%?h}"#>v}Z:^m*`fan2isՎ0bOlVCmκ2Bʼno}T尫9s,|鱾xLI[U *_#'d׃8F7_'NЇf4MT"m^^+*8R(ˤfx{:UK 2=hUQfuF%RKfY8*7AkN\_Y}g,A._WIb0m9u%Ly͟dȄc@lN`0 C=- t+̞avcv_QFCU= *V|-2{ ZIr6FcT|heuXqSr1l 2V,chh$8My{.a${'4G I=w*HY%Bʑi=}s~4T{hħ3|a`|\@G-]Q{" n XT-Y X

D6ycShVoD ~Q~RF` fl .f3.!GT#*^@xa2Y3)t)K03A:vvޚpߜUdnp9NӂD[VPV,ȯ'`<+^Tʌ̲Kힼ-WUK)u9;CՏ ;Vf4(0]ТbW0X#8@$ C9,91?δh #=[ S YjwlCdIn 9`&< }!.׍O;:ޛKw Ʌ -R.` :)vp iYFk~0P:>iIˉ+бPh*sIHu:ϕ=D+O̎~]C(/?ClY?wROFTgd.J} XCK!]FHq0;QyҒf%6T<'{U 4 |5Ƶv# yദ$tR- hm`wac#WSF"9؎H'6ez3w&MQ&jd\GTTg?^8Ù|OrIcBsv4nVQxs9 1 MHz]K1 M] 5EIH9Џ EN$V(~jiFwܾ"3W:f:ѩ `cmeJԐx  \D;L6U155? #\?ќ 'ʇ]\i]G"u}$tڅ<Zi6n3e HӅub= )Qsf֡BQWHͦa A"Wa 8ju{+nn3*b{ CzECi FXwLˏsey-;Tm`+,&Jkх.@òԮ _[:fG1Q(+H>笫>wO:fm` /ZLՆzR[rx|om:ǃt0f^ŖXiSck&1Adiv8ޢb=;e乜2l5wҩ"D .#UU6ͥʥ񂿼T]uM8=09iߔhL.`U qH7xJ!J|ax>a&s}Xܺr#}aLYn7^ɊbaEuwÇJKz+Өҕ3N_jڰ{hSVθr2˄8Nafio+m.4XpdSm@QU6ވRiwCBY5X (H^ؼ20mq 5е.GD]_,[Agp]x'{E-D>l< s0M&]I?iSGT~j ҆-+耿qvCZ si<IfO/-0$W(SAU֙!4B w+ZOw䅀@5F"̝|~񆇤 f|_帘NAu(i lnX.[ŒDDH߈ZcN漍RGTUQcA١"iA )MwNwzc:6?Bke͈ QmPc%bPؙX|{.C{dS*pvL`^-N?_#9i+H8`]l$ DŘ s{|[kxٛ#ULV&Whw=0LKߝƪnPQ}{Z@{jp"J1֭3U*T ݞC㌪@Jw&٪iT2$51Ude;)1l 4.JvlduQA6i+EMQ(5 Un8osiQ-C61ZbdWl V Ll$娚1KeᰂӺdlNADЎaSi_ bI4`12ϳRDRѿL.s, N=Po!J4l;AaEL5¶zNƠS-o5%J?b\ VlRa^©?Ӣ6,a+!#0Xc,Zmʬi EF!!p)IJXå3>(lyfVWhU6~[lcgp-)2Ea5E.YZ+Y3Aޙ4tQe);Is5Mz 6WB湅9I^Cܵ~G;b\żp"~oKO1 ĤY0>p!%h0$\gB,wY(XBN:H螵[M8ӴvpIkm1 'R^'),nbQ\Eg/?cA%CNrvH`i| wbhs|u@6n1z=U#|E;ďOrɄa͑ԑõYUJ}LU~n׾__I˻qbġϪ9l P|q_ֲw}*;t!ܣi4O@L$ Eg^ڬLgъw[SSDI'ZeqCsF5$]De(V aӜDyWH#ކH eJM\6W*dee|`Rb9jbG,=; A ^KN 2Ax0N*6DyVb &Ll]mfV#unm.)btOl\02y/|//H9t`4^y)vc8TP’}8DV&na;(NI(^f `Q8Q)v(vɅh G d|c((+OĚ ofkrP d$om$?S)g>_I:d&Rx D Kζfy;"%`m? .Mo S ΁)cMqmyvJTf1^a/s@(xZܧ#_L[+PKz܋n7oTn{qLo5CR>_y:2`3g~垆/TѨK8Z%BR5_xp98I[>BVO{Z~,K) {2sKȰ`o‰%%Tjɵ*V@r@ 1+O.ӥגQ|+8VzTU`Pݑ Ky1R:?J{;bk+I6O9f3HNY. Yc3`,axA7H& ZUpb(S G%;''NKק8h<> ׏_hRi!*ZLyiT2cF\d A{),U鵂eX%M<8SRMWL;!hdEaeiӲ/z5<WB]qKǤ].Gvzc;5a% >DMSorU30|D0(GMmc@:O''7~yh#u͂/A=p4 rQp s!It/ [&G Lg[Q҇"-ϴsLmg0"2rݢDG &tևlUߔ.QR+b!R;*C؜:J7ۡfo{p/\%ڙzʞ#K.F og$b/:P{s4N9x0c6\#u%>YJ`1ߚ:Ǟ@Z8Rc GT?) Yh6i#?6v6")0P hxKT\*r p%p`Y{!SBlό,?wmYVs/T49% ^s ò\0 N2Va8% =è1.YUlz= @%`ϲ|FxH(Z9:xN$6x%⚚?zf m_7Y$1! e-Zl>NJU&~Q]5bt"M G/e= 1 DmtPYuؘ,;`A}(G sd^akPj-*za}ʺa 67! UrT,C â^7 {ktjX%EZ_$K1Dk 800ʽ^;8 |#*Im8W[ rPk! !6x**p{AsqJ\=}I"{7` )ct'! @T&ciOb$޾eئDcV [5#'lWsXff !jV.%lf0Rs~jQV#ygn{)k4R'Q%GEurq ) .^,0-iHXpc:]etV<"³@q{iMςF~qR7Oa۱֯ ?ځ`!)S #m>_QBغ^> s5b&K$PS'ZP߱?|,+jtIi/*j۽ L/ Ňx̊PHkn}rBrtM݉L'Az{v\ع@>>OM:^1@Od صⲵxom ۈsJ54a+AhNȵLmygbȒ R1CE} "rYryrbOY=WJ~%roV̢Aĉg+Oڵ7 b"aāp怭JxXo!NjuIʽmN7QW茧UuwB GJq_piFb''q64u2'#G+$DZ]{f ݙx_jL<2gq.>̻jE%T?d5va r⭁>W+޴Д\F0YN&]nKL64?"kTCh5-^1.ŌSgdB~ I8'>fE-?S^5=z4cJ] +Ǎ ]Yia]b3"iSyYH7 c]زE+7")撉HeCyxR?zƙ,t55 T (x ,^3?1[8:85oPӹwn5d7߷0Hf.0QnȐP߃Z43iAZ/ C"Xmp5[kg/ ҅BrRKx@urY^'BD?Ÿ<:c>\EO]Xh}*YB+ok|);1ݑBx9tNׇ扵l$,^bx%7de$wAweW&}5m ;X}"nZdJ_cYnm*1LTjeFqo!fP1ACbCly|OTZjiTW@ͦ˯Rΰc5Cї{)=ھE{z[+Buͼ ?|MnMZh~_"nA4a8bQpfbWsa︪[k'Ip^4[IfJu+.wwgCP[ endstream endobj 138 0 obj 35779 endobj 139 0 obj << /Type /FontDescriptor /FontName /Utopia-Bold /Flags 6 /FontBBox [ -155 -250 1248 916 ] /ItalicAngle 0 /Ascent 916 /Descent -250 /CapHeight 916 /StemV 80 /FontFile 137 0 R >> endobj 140 0 obj << /Length 881 /Filter /FlateDecode >> stream x]n8߃"$1` e b~0i/@#ݏJ1M#2Va8]_px苧4,U]OguY.Voax>rQn]ǏK:؏ygע\.?O5_ܿJ+N׏\5_Tv8Џ_.6e-6]].hUL{z>؏Lv c 5Vp ^A!B]Vk{FF!)dBVhŽFw -#BG8y'qx<qH x<q8> endobj 142 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Courier /Encoding /WinAnsiEncoding >> endobj 143 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Courier-Oblique /Encoding /WinAnsiEncoding >> endobj 144 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Courier-Bold /Encoding /WinAnsiEncoding >> endobj 145 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Times-Italic /Encoding /WinAnsiEncoding >> endobj 146 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Times-Roman /Encoding /WinAnsiEncoding >> endobj 147 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Symbol >> endobj 148 0 obj << /Length 149 0 R /Filter /FlateDecode /Length1 866 /Length2 34932 /Length3 0 >> stream xspgQ6ۙXضmNl۶m۶mgbvvgV~Oӧ=UPAVD֙ lgoa@hbbm``20 ;8[ي8pLF.Nf|89^ pM,MEqv4061pؙ @ ikdho/1 ##_Jkmapces5qtG@)%409[(=-̝Fspg_<Akkr(88C? X[߁? kP3_H:X[ ښY pp71Vp62X;bklhmak`ded`6es #+[''Ll'Oc*o[-lJOfSg?uYgG wI: !$dEeW H >F.&9}_ſ41q71y'G_SCc%:s*:.UV c62s"gPC|i}ݢ/")A?uk3~2VB<١s9y h&aK I8ls" BId>[B01FuGih /C=t[ݮQZ6[r@utxyB+u!D!};!rXS(q0XY{F[Q$V[:mLU)eوlLT0-J@0PJP 赨 wڹg&>7ϛV>+{۩=KCS<;u)$ٛ/Aaaths8"V5v-ҡp'uկ7`Pe2%- )U0 D1[`S,45\ '̪QP0l輒{YT/wPjLȡ!YPXU|r#ϓz'`꿅=hXQeR c'8¤~"[ 'OhWjV˝a/+dBhQmȑ3/&aaVoda}=k*TFl"MWndfU{op)n Y,0/ ǐϹ''gN7(E zˮ*txGɧ . D9ۗ}EYśK*Eߋ'MBL-L!;"ܫl,OyT]α/ȵ ^q80pĎ}c;0uaݎ %ƀJgV]8$"VJKkF BbxӰ`wi WVUҶp$H .%n$Pz~I??YZ2ђ[؏y n|@Bjcك.4G9c8Y raG/bc y^deԬu6l2gmJBY_'.u/&5&Rny^oHvϪsjg]qz-4҅i]8Z+of^ W ! 9liQ7PH@5~6$[tv7~K ?l"-;Vj ([}/~Z hmodL!j6L R8@LBZ_gyPwu RZ;[bnt&ZkN8sĨͨ';{m u-T& w:I3F̀:r^9UzHX0so1F2نF x3KPt9U"zT*p$֓ɇxٲ?.I5oGW,ts$wݔ 2\&kF{YIDk+O$)a{Rf@*d7Deg翌1Ԙc!aflD^ )3 7冖۞eܻ5iv̚@827Tv{ƒeGK8M:|57 Ķh6)B`w۴^ݞMn.<0iXi84jfOJEiAaHUgNL#. db^&ѻ{4!fv+`RLK\iL`⸮C)I2E5P ,~ၗ -$OM##{CKlWCƍ jtnVG_RWM͎{ Ϛ{m4[iw %!8rQbLJ׎CSl,I4 1IЃ[I:|YtiXvMnt\u5g1\Ndotj51gjjJAX?jz[OF&db ]sS)=ZT΀h谥L % |ghBvMlU4T #C/*TO qF(l az4ZmNBHF>Typ/ v9?S]OGmr˭@0WUy*c _1wO}6%-=g:7I">lL\?;lzV7a"A xmL 39ۆɗt[*&ښЇ&dcQ# }./^hDP#23@*M :-s}ّV{;MC{8F^ˇ‡g w'h<]%Zlc氝'ɤyInWj G#y UTntsIEscjI"*v ڪs/Tr8=#+Z͋ Y=֝ :Gu>?J|%vf=)4@eH! xQ;F9!^<O(^i@ FW@C1'r?@qqݏ ɑMb-~-ԚnDhG- HU}/,c#%Zwnי5,lJy/D!*s V3 m&k^4#5ŇNYl+N2紑9I.$oQS|~}]oN9FgWxL1mV&_ ضxyz8i答D% >6^y6 \hjo0oYhbLXtQ1qE% ]2U:9o$l8!_cهHKeR5@P9۴uq=&bEX3]em&2)(klԗ* Gͷp`6Di\" /[3*<<`|Jdh~:k5z-E#tϢր[p-ͥDEI@_vyOWi+NW|;i&q(__0͑`'|kޗ)t㕫K L'LڽZe?2-'_5|qݒ{K?ç6;/1\οBdxŊD*AqOo{H0޽{2mVԎL;I(7`mSH_"pt?aƻc`0Y!Fq@)Be8 if+ވ$S7_L^P p}7<×O 3"hZOϠ #o8V,6ʜ]^nf{eYd<~?N'Sq-JWm+[b*@V6` tuTf٧Lf(_)ד0pjOW*sYRVz0+?a@[61|jRo*(M7IX$m"r\H"fܪ D'1YcJD1=9 {ܜL#Cha&f8ӇXJSt|2(GK3X?BЉGy vE!d!$7'X sfoKӀA4XزKM3y أ꣍3~⨻wp׈]>Il#״"M||ذ!KIu.(J.6R5R||$\dQ.\?.h0cōQwn@P_C m V^xKOr(oΧwN sl"lҭFM}rP! ߌ̮Ξ6\[,rΝ|cZc4hTwq9Ps#>}~.C#Ѕg Ri23XNx.ۇk˛Z,Z %0 ,d$c9C>{߁לuiW殦V7N:_Z[K qIP\"Nk@\ Δtv3!45R)}ŇL^78 vRɷ~c%|A!HO-CZhNDq $ NBbW۽Y3G:|Q m`};X8gLGTvd<0->@ H/8[>]7M: e}SiXkQ͘c'9/.*k+`t,&{pfT\TW,c72Q~.@r%%9mˤ ,#dTǶ`eui[D2-& MfSda1O3ryWno]δ39ZYߩS|{17O ؃q,~[φx]U_Y\~x*ޮ=9] N?]i^AMo{eFsk1\ڼ[K7pyo /Z k:%xYF+[ Wy*Olg6LJ]e-_(HަWcBlqkfX*ǿe)Z, cb ;M t2 GӲM$mm1|F"$fH=zR2b^$У/k" NW\BK[fa=1Dy:Cv] J3]'fj67 PJs :Wc !rF>PK OѢqk֟tu^bs gՒ/X&-lU']ÍL߽=d= 5B݋Lao;NElAMДs};WI^/c6RJ55N=yvJ>BEtc=޸9o3KJ/T9Z EAy29.@DV estXtNT 񼇿ŕǵQHzk3*|‰Y`FUiMV;POY}akF\.v3'w.y*/o~8GlUcD3;(G0^SݕKׇB[,<>zH]MđcviGkeDi&PKOͭ x")b ^4ŏ;ԨܽOjEhgtpG \dDB_3QK\9Isԙ^^p|Prz8bwEpMTW@ae.uĝ==LU =nm|}ʞ*%_,ZZE\2aCBYv*.Ƅ!x6<k9WW hJ m~DN)H,T E|2r 3`Ƕ?7bNUy rUfH5j|pt>.1_ ^ zJ^39n#g)Gj k-*P dR6Q2p L f:"iTI.8"=U4JtAk |/" TjI`Y${| *Y,`E>t4хJ(\yi(#G\yIW)o%{gEZxjTt.3aԌEG 3jL:a>r8 Ş~ HgAbGŸ"-eJ8OԩKOM-E7tokR)a5Uk( k|oͻ}(mV)mkHR2(QTHi~ zplmC=N3FK% bK N [7"e@.N ^!M%QE JȉayL+& DQ{dOJ[뤁p2]mxܴ=}ֳIZbNwYݡ=ڡ&Zt4ZLv}2Ɲ֟iݯ݉xi[[;M} ˾ypvZmViR .y4 Y̮ۭn*bupn;\R V$-< \r7`tpWtHK~: 8$lDJ蘤q oz *#ܧi1oyTW[R>ƭǿ&X2Q7Y]+ߩXh!4W\&2,wV"10%Ш|zvryʂ0"h$UJ_?wܜKrc#OqrO?S4e7dBlUfUY}^5u;}cs Ja:bW܃ؠl .]KP جLJo!CHXݙKk|Ug ,dX0Vwdc|zwde جak 1m83 ~؂kC4ruCCO0A~5ks-Vrt}5c]*j'csbYǐbQ] ̐T}\5P_DL{yT`ӣc"a^zA)"톦ئDaM`9yFMkNك@ I3`N^YaE@WRPD`p$HYXxk 2ㄹι ?#95#̢_C< h[>xr=܏5gx4\<THF2-|?l*4\#h4q[)_d2TN-$7+ez_òԷaf !AmAZʼSkF`v& p+K^h22('P4F%Ze9|2)fX`;I=bjgb?ssANJ+u1YG6ۓ 6XX ߈ <.q|a2_! c1|܅Bڅh$\UqʂSp?nQEߘ N]J8"=?\yxoIdf6t%Jf5̊Jg_~-V;r"hLUuSFJ :_݂d9rUI4C&[3=~˶p0~1TvBN,A-.d1H%ER)bǡl֕-¢&T|t/h%̽cyrQ'-TQ j XnC|^^͝ dh`e6 hI%4BadaCinc̈AЛe%KbG?9M]2_^˫יִP25dE^BHhՐF±%=uЍ?@d*n*59] {[w3/״Q)-/5c/dPBvsD^ڥB*UX'OlbN1!!bCꐢCt&rN,Dff'\ OD=P.Vlhe~++#>Qm4R7c%VvE8N󈟒+Y 3XFp7PM;^'+.,Q⇟J7n_[[zm1"Ot8~Q"y]l%3CxvgpHOw0]= ~ϑ][:(L?j;̮R^rS:Mp4/x>Ď#Cˇv֨X?U?C*JcAw?! Qc*'/xu?TINv|*sPd֗.pWVIz!9ǼXMJl_G*0#Aҋ6!XrvhYZoMw~rG=A$nל=Tqt!v>|S]縜hL;ydn8ՙ!D3@!2p&o'LS䈂TKu` )vc\y[zװc|r^9HX,;k$?ӅvR"ĿRV3L:cMXj;%W/%T5|ڔDXP'"{ 9sqU)IV.[P8K\ k҈IQp-8:[{M62 e: : tPƏn)U$hhNϼ7MVn%#YQKc[%f0mx ʜҬmQ`T W}~0xVZ!r!R1َ{;1%zYy@NUZT 3NU6W#[u5悷$tz.RyEsQl Rm3,;Js'eo"B?FjЋJWc}z-qiAZΓIJ_# 4)[WGEXpGyi ^*]@VhnfaA>~r{t8CKhLQhF>6cc.DWdqǐxClBmCY+_46UKJ4t;QNa߽D + mvc- ٻ7pH@3] dʋzhbЍ2>$`|,־_^u{H咜pG7ܡx5]i'9qe Kl͖s^n yt@ݹ29ˉHe#1ZG.[cXCL@nPkUJ# spZ;G}#߇[a~Q/Ol?ŅttT 3B92ޭוͯ4؞¬/8OdbCi;7%@þsX5Z˙Eu g)*|*:ʞ lEYV8 OKU-;'`k3-c>X,Nqۅ$qI65ShgI;@^} y;0ƕzAۄ-֏$[FI$/RS e1W RI {[D\3L3%J]_w`ŸΠ®W:}+}WGRAho=+5{g1Bź0r% eB`y(wKz^L0B=Q#wDLua=}imC A+ u0PPzA @,sXRL =Bޠ.:PҘ" :GYǣ eSm]@2)8>9Bbqw;2ᯰ6.7_Dž`J; Ke KD*Qyڻ6pWzo1!rsџ}D#xпRO:l[}cjr`E1˞a{]^ ^PO?$tv ])PW'~{ 뗽Ict`ʕa1hX lXu:ezJ&?H >ҧo-01V#a:F eLTRmhw]Ev.h@V@oPTl]4D#p+z-Lb`i"vrO6F9ZZd.v ]o?c!Fۺ\_绕LeM[/ 5;c6׈%%/]=M =l&lXfkYvUڥrYNp{?FCwv4ץ[((p.󂫞C7-!&yZ[̢9kd) yTfTX%$W09z.Z0ڍY׽Jѧ{;̌C̵1Q3_='!),+B{}ڧӦSp%-T(ۼ@0-erM? 0sj"q a >v=\! (5;iqq{ÝvK/`ÕBrqyHr݀b{H$j+֪mqXc-[z`E NCZoS`ARc" SMQ:\);mpf;E<4h2=,|.r631{E-0ޱ(TځH;CnVy[j|?aWVF_uRZ(^'*Z_F[Ab֓n^@4`&;V҂ {#,Tl~jĩ6zM2`=F0m5ҭzuKK,?l[G}aW3 E,eID}}a8ҩ:PDoAX8ܛB$%8%{u9HgH |jIյ(?_XW?&)]" ftvg^~x?R;ɛjF#(eRkv`CƣnBfL/L~|gB>0ʀhv;c(?@Ǜ;b% _jC8t+;)D@g wJ1k.;9evSy?)˺X!xlskM+@ /v's;oPq%T^dxKQ?f@i^L9oCz]\!|3Z*SV4c.}m?M?7Cvg*ye?Nd Eq -U@n-} y3vXW覱$9IZ@u* "B# CE눣o_i{q2-WMYSuHO1C1!f-/}W ~tC ^%:۫좀(ʧKqK[dQ}9/4$ jԟN6ZD#R?h\+OĶ(jN.鋧$k !r0&\x#f0m;Q鈖CefT!}oVg1!%VGF}L\@ݗ%P~}Ⰳ,kXp#;95lYNM%=6XJ*yG v@_}\N>fC(𴛖z8?K>f]vÀ}@ThN n:2-?85NIȻ"NsऑaN[`; "_9v -)y'ĥa;agLD&hF{T39|V-^Acȟ0ٕR7(cktCDTu2chQa rΊ}m[}[)pN 5״!\ 'q,ûgF0o)S7`V/ZYm( $n.ΎkkGȃ|e _O _#_/)8^p* mǪHC VNq.`} Nk*RVnpssr;~ BtT꩘-z\ U}.`IO/>>}hGA'p,|)GT&KXPX`9Rwj :L fjb)Q&/nt5or o*2,?7{ lִ"Nխϗ*f=G3_7QuKxB!4}tkY ȩúzkKx9zUXLZc[`Xvq!7ʉnm|&0_c2~`nHFHM`J3R]±q}ixvxܱT%g6"slY$]fx(oJT# ( Gͥ[qxݢ s֞}.)/Swǎåj;:xx,ᢁ2<L0-ށ9徝 Trmiaa{بᄖtPӃO ZsQ:Zծ 9@h[lM/,cQP.O굥h.>zD(d!]$ŽZU핐B[',MB$4 䳼Cu 6ufh}\/!6SU?t>*cLucR?_+3[G#&1c`ޠuIA 38~6O-w*> YA*)9Se:!CDe_ISIJضл ~3ǥFtZ\#T)pxDx:.VzmE?D5Aۍ%^2x{Kp5\ԃwv9K}:4>sƾ{9|Fl59÷~i)k1U5l/h ^sT(Tr>Lk$(=5U"Y7wrao6yfɃDqPnm~9:[M#0FY+I^vZc G x6kfCrq_ڏ.:|V־^໗Yx5Itםz O*|?KGY=L*c^-R[7%`LqUI H ɴRU72c 'PI'(O3\P x,_NR +5 1aB똸n UۀkXHK`ٺA4qi- ͣCCq@ '5S]w=>K{+)*8f b#gĭٓg5ո(JgC$ uv!\vLPBҧg#JKX@d&]n\S&c/Zu ?#ypM΃gYӻP6ʅMUk^kd`e%>+ <.Zܬũ9u}>Twi藺JIW5G{ڦ7e@57IbDxsY0u y=,kϚ29+^ @ '5g$c$:JL2Ԋ Z[K cϱLLE,'ѓBϤ{搎M)@p^x@ MXʉb"3x G!]Ps-ꐉY>ۦ>ƒ^!;Lxe'j/*؈]ȶ[)shxl0p;(?'"_b$g[LQ޳2os'—nȃNP@U`\y?WBSJ[r"ad2u"a5j.Qrt6PiXQJ"# 3 Nٹcn(klY2\'qA 9G$osknFKvK|p}HaǠ5QY!k cĺ K|"/ϞFz\/Jپ7zzn[}鼼 75 < ڃ(C'$Oc#,qC LM6(~_<:#v * JjJ `{<QHc{A?Ο#xGKL>e4BA l zEGz*eO4p\oJ4\2_{5M& [81㧹nC2ٻAa(d`:kg[U&l/rDV/OV&-I=~z<ބP~;@9 pz|cJcTvHď=>\Wzc}"Aܕ<:6pƪK^!m6貘V .UH/WbS-C.xc}j`3U󹏲tFRߕ΀il,!wC.-D٨oKNm[/>6"0lmz!r.$|a #?AMZ#Zt;:l9TXI l'Ş&<1Ca7 RPj%1 f{g6 U!` f?$#&A LDuV;]_[iG{?nI%#[!uU=<\B-A 1jS25gs޹ۊ~JhZEn<+JhB wy$ƃS`6z)b/Gm^լAbC\zaCY=#2Ǻ}(Zž?maF·+t'lyk|,ʅ&ַ*΃@B'?&p!#X! ץPt iG*]OkeX K;IܽKETwkNc}N%V.b\5e\ԑ5ד?iWR]y<Aѽ-$O (Jɚ_+ їq3}GRAO'R\3NԽ9<iՀ3!ɋ61E;ܱD&̑qҙ~@e ^V}v ֑J&i e\N7Ty"u) %4+et"9x`tz@OۉQ{Dl1Gjt혰рv 2mT9Pa3ݢ9D̶6ҹQܒu\k@t>UfAaeA(M^?K7\1۟혜tX(bʭ;t_Edk#+`!9M֡['}􍲕]ͩCy$cpD!݀ue0>KlJY5⅘*NeΖh6eԽchpڹXi緹(#F2+O Pz8]PQV(^ƣZsx&'KUtQ wi&\SwW{is3\1/w~Eyf=1Lz}9p Is]l8bb -+`.;<>/CE*y8>V! DzGZz> j.Rs6yʃȜsUY{)9L $]֨m@zڇun [9h { u(=<']`22disBQ֗Lp ;}5c@qE:E^!Bs@NiA3*j`h;6VBc߆N4oS0O/S0#:5z Oe =^<_'g~ņ(ayt4\'4LuRi^dk;́/Ա$\A6FrʄqX(*lJ|՚m]~/Ӓy _QxI1 Mp&e҃-lu*ŷLw&_G␗~"QHtN沝AgrK{:YF6@Rݘ,̀0hl{$QBhz)ĉ(ajU=P= 7)N97CJ9lnQޯ#쵘BOxGL&8B x<8;äYApUHN BkףAČKܱNp=8VYnO628S- [fh 11M욇RL`)z_Q0c\jM&[Nqұ)-xPdF&B22NF /y=-]rMb N~Ӳ<vєyT“oqwnȧX8KTj! ٍRtAfkSP|ؒ[A/ŅG!/ 0B524-mɭVϑ;>skQ&jAxTILHxȂ#W#x8CQW?ED:Oрc㟇mwOQu3H!K%A0cZXq﬷/9rJŦH:Z/I@ ~+?Ajޓsa T\ ݜ|}z2W{GTW8}?j8 q,n4"MZ#~~_jO5Kkܫ yȯt}3R6Th,s6# U8wn}cO_MK5} T#RŐh]*xH7+):Aiy\m%c|rRzboTf$Q j?}Ӄ*86_!fi]MVuZHHq;fqUY>T ڠ.8t`B4ʪ*zi!osK5?iax2}rVjY t܊;]JbzC>ѴPr 1Sj Csd9GtBjszj2Bḁ] ߔCJНp*̥ ŁH$jn U"54 Ecn. 6X@4gl=:\z`[L4-f{jtqx#Cš;rKs'A X#RCSW9ENzlZ\@KdL7ĚG2xK 8wœpvBB8tR\*T_t\hCTrU"a((ɱņ32Zp ͘R?EA@2>ǂd dlF ( +ve0Tw u[gd3:"3o|Fq[Y3pi΅u Fh u'emim?VBz'x#(0K(Ah\Cn֮~ b+1dPt]ܖ*P:XH$p%xo%_H ̪s4 BS/3!(с;:\O#cqW5Sfh !AqzSZ6rۋi)| L13΄4MY-RrEɕ9cB6Zs=.HM=9s"F&je'28 5;!z&;&(ݷlgAP ̲D=9W6~urQwQۮD|`$ #+<9"F'L`g^&i(6oI29J}qO?tDvvQܸ&t̉kg~j$])n;Ͼֵ*+0v>P0L9d;{)XZ+l &Ixe^0/nΕ\eyp#̹iτSAO;K9bN hfr & 2(}KPMD=Z"g;y^v.؞nvO&,>!,`>)E B/_"?ic0bu_6z~3eLg[.^%"x[eZOFUGE'(+^bP}i"S,GӶIRzbʉhȶ aPQ]ns!D[Mh*1'9@9cC l+[Tٷ^fJCՑ$XэgINrB1Kq"\4*qxI:`jK 7G7JoRZ,'^Td.Jӳ'Ɛt(O%Mxh 'B4ґh.̓뷴j@N}ӯ|9U0%Ǒcxr%4z\;)*zLqRxQiD=XIO>Nff)yelO?X٦/< Ijq[GôOI4ch8/$2sYNxR`=}到)h@fdspӔ!'Nm{%o,_j1f-q3¤9hmFj=c\O'OȐ|DUAׯg$ܦI )_~{EN8Aqe5#WMݲ`Axqǰa H,K0.ḽCz&-'p"E:s_ {NJ~M:D̦`pAk%Jk;( -pt\asV9Pܚ 1kohӅ/cʎa{^䊖%i܁"ؿˍBFfv$BӔ=$Fw8q|C?0Av+'oOu=e_yTi-5gX%k-VH7<Lw+Ʃ6cݴξX~;L*M.*=Ge ڛLD {7BARqw΃[B֔P8QI@PV!7!6W-e\ыjM1p6_Q'|&Xh[+菑FJ55A@&D vXh;yR Z5mk ƝQB2M%lT)qvfsF<7%-q +zK]N( l}`&a Hڬi^lc+uQ|q˫6mr=qEܧ d^Cf2@2?$ّF'P|;C 3jN})#I(\|'X5t.-HKt+m:RHA5l |7ddl2ʰvGmi$0[ߟ^l_6Ř5VI+w ֬D?TuMٵ1i 2>)` {2ӫžá[**Ů"}Vq>#R7l Axkj^&jND#jXRQKdfM7&5%TG \55;`0̏JFSuq2K3a LKBw)~0) _=sn(-uGe6k)BtN|gk\Y*}|;+"QqФIPuM,Hm+p/Au '=!ⱅ+Fk5ʯ-x Gc0Ѽ0D+L?=ǩLoDs-g,=LӇ#_'[}%4(Dg NAUF?kĀOh8>틃+䠵b6),\Y@7*9Xp*S_M9U'[eʞF}׆Mݗ_<ٝf:Zʪ~+iϡS֮p%!EpV%7W{͚"\!Gh^`cdF]G ('z8 < f2.ٸ:#5Pe"Jeh(f(3o7e*iN|akz{ߚ9u\G`e$ sKX5g#I't͡2D}:VmH}v)k!n2N&־dHO9Jt7ZOuUi63sQ0\I!qKm܃v4 B:Z"7^ ?!'2&5ԐaA+cvjUmNz\RZNuPfsnCUyxӟ>'uKhڇi#W\ʙz_pf4Mq qX"5HEihd&Vf:q)X*%Wba(N2h7|iش(gЛ l `wfN*8":f̷\Yk(UʸH894DgCDq)^}cR,G}-7|9k^ O=;5ojm[b+laU@~e>5{mZ(ƴgfDʻ\~dt-EGyᩲD/9JW88 @>ݪJn<}\eJu8,p OE,oۦZ;5.<9ˇfed\EN VnնzF58|9z a5 n >b;v @ t^ozzV ˴?u,MӇE34 joJVgr^LBY2a}^9Ǭj~B2P1vT0[d*y5qd.C+4s^:.4JƦ$a*e[NO[d`_p*ܶΗM~jIy e:6ˀ-IֈV; ahsQ6c1U^qHF2!n5 'ٻB5s#h 7zd; YP|7X:VW`h%RoN = qN퀅 ?'eM 2*uľyצ3Gtj)UxCgҪ4ii}[Vѧ׻&D܅x|4,^P0qJߐ]mpaZM&K.q c,wIq/?[v^\3xbXKK^>d1Ki_X}lZRb搿n J*M8G5R>AE tHeh9ҞeB p ߸IYY29 ኵ^3hQ $݀dzpi!4y7Tu2TwG(l(Fzú CfGg88U{RY]|`ٰ:D;AzJsؓ*V ֜ AiPMhR줊NJK']JliQ6x&$LՖe OD`KVL1 } jhOږrMC>Bh%f%~S=m#DZFZ<kʼY 3^2g&n+G+y-3:5qT`ϱ}]aڑ#*k"ܞE~slNjC6rew AYjijXlϺ~{4k6b/rmЃURcP| ̤wO^5 #foB&GZ;}b/Vr5 lbc[*־QJh H-₌vﴡ+ãuTRVSvFu^vxRwzʐ w 5P^G*_*7΢6z]{Br79ʞ-sIx"Q'S. 44zR CRz=ZU/V4L QŞ nEL3ͩ +f'Bg5bDčR`] ~Ā_>gXji 4$]}]V;:rbN_w` _c4O"݇C z؀<(u;GZ/r1 Y7d`PqRNAZ3(<\j!Pћ|Yc'Z7-õƽqVaǣp>h+90MnZT "q3J7 K)t^m>Z/#"lN+?o3ϯhl0WS.v͖dUC-Zb Z;DYabr>rrV-_JE娥iNSeL֨=8TN9&q|@+"YQ&,x !^*~MEpʠ41w 'bA}O-XqN*d!l{2 _'D;w ҙKGw#sA٥3<"DhUĔ mUq:A3pXJ!crNg%VP&ܑS\k1iaQ}KsuV|٧lj,k~5^x7[o!6øC乒$1m ̙4FjMhPY$/;,Ǐ]w ծ(9gywfQ ?;9T~V@?3gq1-m#x6yP7^B$m!haJ҃btՏ˺vhi LpD:^U;F]U=πRUϫ&rmȪDn^zM d|ny~`>Y!uOF`}8z] 8o1N<a_ts´w k8>6{M ?W9;hl.$?͗ܙ5 BdSE d񞑚'&a>_5.?4?OێCDZp6RjJTDtr? PYQ;,x!B= J#kR7h2J r::yrgpEXd2۶܃9=Goۤv3^%4Fw̾YQh'M#]t ȤOʰXb-GA>nͬHNqQa >;1E=.f9;jeb1nY1u;,nꁷہ7RPeXӟtP9h EobbRfNj=U!փ Ҵ7O}?_Un?Sthrgs}]18/CęP2'JQ0/|dNiܫFhbO;򖺜%cXl33;VvL 7M|_48E"!Z|R[Fg 6E ?ԔeS,9cX^E m0ҍ zXq3FU9K)lR/[V֬%;qoRu3gB(@|;2 |8;MO̰+LJ$ 2؞KBA/0^}rcN`Z":{J0DmC߉Uыa/m;an>\ǟ`}t9Z(ζQ¨fܼKUY4;%^J}@y;1 ҫI^R03o׷Bqc9@ǖM//c.+}[Q9lN5!՗wJ-d,a #=I7%"'}\ک^c"&zZAZ76.Hq# l hPE0apQ<//4BbaBHK5) k5շWx5#C3Hjړb;=˷\{-$VuD$iJA9-9nhh$oj"ה V.I |~YӳH^97dVq| 3 7C!3w{P^_SuZ1vYaPuJR-Y`Δ9//:Wm0xv'h"L"6!xQpu81mPb jY5Z.sD7Ϋ~7@ hf}N,X#qw `J&3yN/iIujZdj'x| O_"37,oBZ CRm'u7*?w骛yҿ9^&mEM(fUe{r7Q;*E鏄 R# |fauD( ! h3 |WyBڭ(IK$d' ss+AN1p,}2rʯ 9\9Y(p\a9B;;)$HЯ{bZI(a&1x$O:7vڻ!O!u=ơĨb endstream endobj 149 0 obj 35538 endobj 150 0 obj << /Type /FontDescriptor /FontName /Utopia-Regular /Flags 6 /FontBBox [ -158 -250 1157 890 ] /ItalicAngle 0 /Ascent 890 /Descent -250 /CapHeight 890 /StemV 80 /FontFile 148 0 R >> endobj 151 0 obj << /Length 881 /Filter /FlateDecode >> stream x]n8߃"$1` e b~0i/@#ݏJ1M#2Va8]_px苧4,U]OguY.Voax>rQn]ǏK:؏ygע\.?O5_ܿJ+N׏\5_Tv8Џ_.6e-6]].hUL{z>؏Lv c 5Vp ^A!B]Vk{FF!)dBVhŽFw -#BG8y'qx<qH x<q8> endobj 153 0 obj << /F1 152 0 R /F2 141 0 R /F3 146 0 R /F4 147 0 R /F5 144 0 R /F6 142 0 R /F7 136 0 R /F8 131 0 R /F9 143 0 R /F10 145 0 R >> endobj 154 0 obj << /Im11 11 0 R >> endobj 155 0 obj << /Font 153 0 R /XObject 154 0 R /ProcSet [ /PDF /ImageC /ImageI ] >> endobj 156 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 1 0 R >> endobj 157 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 3 0 R >> endobj 158 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 5 0 R >> endobj 159 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 7 0 R >> endobj 160 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 9 0 R >> endobj 161 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 12 0 R >> endobj 162 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 14 0 R >> endobj 163 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 16 0 R >> endobj 164 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 18 0 R >> endobj 165 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 20 0 R >> endobj 166 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 22 0 R >> endobj 167 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 24 0 R >> endobj 168 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 26 0 R >> endobj 169 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 28 0 R >> endobj 170 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 30 0 R >> endobj 171 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 32 0 R >> endobj 172 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 34 0 R >> endobj 173 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 36 0 R >> endobj 174 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 38 0 R >> endobj 175 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 40 0 R >> endobj 176 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 42 0 R >> endobj 177 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 44 0 R >> endobj 178 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 46 0 R >> endobj 179 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 48 0 R >> endobj 180 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 50 0 R >> endobj 181 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 52 0 R >> endobj 182 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 54 0 R >> endobj 183 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 56 0 R >> endobj 184 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 58 0 R >> endobj 185 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 60 0 R >> endobj 186 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 62 0 R >> endobj 187 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 64 0 R >> endobj 188 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 66 0 R >> endobj 189 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 68 0 R >> endobj 190 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 70 0 R >> endobj 191 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 72 0 R >> endobj 192 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 74 0 R >> endobj 193 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 76 0 R >> endobj 194 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 78 0 R >> endobj 195 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 80 0 R >> endobj 196 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 82 0 R >> endobj 197 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 84 0 R >> endobj 198 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 86 0 R >> endobj 199 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 88 0 R >> endobj 200 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 90 0 R >> endobj 201 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 92 0 R >> endobj 202 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 94 0 R >> endobj 203 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 96 0 R >> endobj 204 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 98 0 R >> endobj 205 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 100 0 R >> endobj 206 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 102 0 R >> endobj 207 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 104 0 R >> endobj 208 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 106 0 R >> endobj 209 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 108 0 R >> endobj 210 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 110 0 R >> endobj 211 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 112 0 R >> endobj 212 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 114 0 R >> endobj 213 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 116 0 R >> endobj 214 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 118 0 R >> endobj 215 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 120 0 R >> endobj 216 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 122 0 R >> endobj 217 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 124 0 R >> endobj 218 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 126 0 R >> endobj 219 0 obj << /Type /Page /Parent 130 0 R /Resources 155 0 R /MediaBox [ 0 0 612 792 ] /Contents 128 0 R >> endobj 130 0 obj << /Type /Pages /Resources 155 0 R /MediaBox [ 0 0 595 842 ] /Kids [ 156 0 R 157 0 R 158 0 R 159 0 R 160 0 R 161 0 R 162 0 R 163 0 R 164 0 R 165 0 R 166 0 R 167 0 R 168 0 R 169 0 R 170 0 R 171 0 R 172 0 R 173 0 R 174 0 R 175 0 R 176 0 R 177 0 R 178 0 R 179 0 R 180 0 R 181 0 R 182 0 R 183 0 R 184 0 R 185 0 R 186 0 R 187 0 R 188 0 R 189 0 R 190 0 R 191 0 R 192 0 R 193 0 R 194 0 R 195 0 R 196 0 R 197 0 R 198 0 R 199 0 R 200 0 R 201 0 R 202 0 R 203 0 R 204 0 R 205 0 R 206 0 R 207 0 R 208 0 R 209 0 R 210 0 R 211 0 R 212 0 R 213 0 R 214 0 R 215 0 R 216 0 R 217 0 R 218 0 R 219 0 R ] /Count 64 >> endobj 220 0 obj << /Type /Catalog /Pages 130 0 R >> endobj 221 0 obj << /Creator /Producer /CreationDate (D:20050114164413-06'00') >> endobj xref 0 222 0000000000 65535 f 0000000017 00000 n 0000000478 00000 n 0000000504 00000 n 0000003785 00000 n 0000003812 00000 n 0000005480 00000 n 0000005507 00000 n 0000006295 00000 n 0000006321 00000 n 0000009115 00000 n 0000009143 00000 n 0000056905 00000 n 0000062018 00000 n 0000062046 00000 n 0000068552 00000 n 0000068580 00000 n 0000074320 00000 n 0000074348 00000 n 0000079779 00000 n 0000079807 00000 n 0000085631 00000 n 0000085659 00000 n 0000091004 00000 n 0000091032 00000 n 0000093804 00000 n 0000093832 00000 n 0000096419 00000 n 0000096447 00000 n 0000098953 00000 n 0000098981 00000 n 0000101732 00000 n 0000101760 00000 n 0000104419 00000 n 0000104447 00000 n 0000113336 00000 n 0000113364 00000 n 0000119579 00000 n 0000119607 00000 n 0000121942 00000 n 0000121970 00000 n 0000123882 00000 n 0000123910 00000 n 0000126726 00000 n 0000126754 00000 n 0000131433 00000 n 0000131461 00000 n 0000134823 00000 n 0000134851 00000 n 0000138348 00000 n 0000138376 00000 n 0000143507 00000 n 0000143535 00000 n 0000152529 00000 n 0000152557 00000 n 0000155037 00000 n 0000155065 00000 n 0000157763 00000 n 0000157791 00000 n 0000162295 00000 n 0000162323 00000 n 0000166232 00000 n 0000166260 00000 n 0000169669 00000 n 0000169697 00000 n 0000172289 00000 n 0000172317 00000 n 0000175892 00000 n 0000175920 00000 n 0000179042 00000 n 0000179070 00000 n 0000182057 00000 n 0000182085 00000 n 0000185900 00000 n 0000185928 00000 n 0000189925 00000 n 0000189953 00000 n 0000195223 00000 n 0000195251 00000 n 0000199511 00000 n 0000199539 00000 n 0000202514 00000 n 0000202542 00000 n 0000205157 00000 n 0000205185 00000 n 0000208168 00000 n 0000208196 00000 n 0000211375 00000 n 0000211403 00000 n 0000215217 00000 n 0000215245 00000 n 0000217534 00000 n 0000217562 00000 n 0000224625 00000 n 0000224653 00000 n 0000230053 00000 n 0000230081 00000 n 0000232530 00000 n 0000232558 00000 n 0000238346 00000 n 0000238374 00000 n 0000240742 00000 n 0000240771 00000 n 0000243296 00000 n 0000243325 00000 n 0000246420 00000 n 0000246449 00000 n 0000249213 00000 n 0000249242 00000 n 0000251935 00000 n 0000251964 00000 n 0000254604 00000 n 0000254633 00000 n 0000257148 00000 n 0000257177 00000 n 0000260102 00000 n 0000260131 00000 n 0000262695 00000 n 0000262724 00000 n 0000266354 00000 n 0000266383 00000 n 0000268833 00000 n 0000268862 00000 n 0000271580 00000 n 0000271609 00000 n 0000274578 00000 n 0000274607 00000 n 0000279710 00000 n 0000279739 00000 n 0000283790 00000 n 0000409434 00000 n 0000283819 00000 n 0000283937 00000 n 0000320872 00000 n 0000320900 00000 n 0000321141 00000 n 0000322106 00000 n 0000323305 00000 n 0000359226 00000 n 0000359254 00000 n 0000359490 00000 n 0000360455 00000 n 0000361652 00000 n 0000361767 00000 n 0000361890 00000 n 0000362010 00000 n 0000362130 00000 n 0000362249 00000 n 0000362332 00000 n 0000398012 00000 n 0000398040 00000 n 0000398279 00000 n 0000399244 00000 n 0000400444 00000 n 0000400633 00000 n 0000400678 00000 n 0000400784 00000 n 0000400918 00000 n 0000401052 00000 n 0000401186 00000 n 0000401320 00000 n 0000401454 00000 n 0000401589 00000 n 0000401724 00000 n 0000401859 00000 n 0000401994 00000 n 0000402129 00000 n 0000402264 00000 n 0000402399 00000 n 0000402534 00000 n 0000402669 00000 n 0000402804 00000 n 0000402939 00000 n 0000403074 00000 n 0000403209 00000 n 0000403344 00000 n 0000403479 00000 n 0000403614 00000 n 0000403749 00000 n 0000403884 00000 n 0000404019 00000 n 0000404154 00000 n 0000404289 00000 n 0000404424 00000 n 0000404559 00000 n 0000404694 00000 n 0000404829 00000 n 0000404964 00000 n 0000405099 00000 n 0000405234 00000 n 0000405369 00000 n 0000405504 00000 n 0000405639 00000 n 0000405774 00000 n 0000405909 00000 n 0000406044 00000 n 0000406179 00000 n 0000406314 00000 n 0000406449 00000 n 0000406584 00000 n 0000406719 00000 n 0000406854 00000 n 0000406989 00000 n 0000407124 00000 n 0000407259 00000 n 0000407394 00000 n 0000407530 00000 n 0000407666 00000 n 0000407802 00000 n 0000407938 00000 n 0000408074 00000 n 0000408210 00000 n 0000408346 00000 n 0000408482 00000 n 0000408618 00000 n 0000408754 00000 n 0000408890 00000 n 0000409026 00000 n 0000409162 00000 n 0000409298 00000 n 0000410837 00000 n 0000410900 00000 n trailer << /Size 222 /Root 220 0 R /Info 221 0 R >> startxref 411108 %%EOF trousers-0.3.15/doc/TSS_programming_SNAFUs.txt0000664000175000017510000000071513663651711020457 0ustar deboradebora Tspi_TPM_GetEvents Events in the TCS event log are 0 indexed. So, a call such as: UINT32 five = 5; Tspi_TPM_GetEvents(hTPM, ulPcrIndex, 1, &five, &prgbPcrEvents); will get you 5 events (assuming at least 6 events have happened on the PCR) which will be the 2nd through 6th events on the PCR. (Since the 1st event is at index 0). This is probably what you want: UINT32 five = 5; Tspi_TPM_GetEvents(hTPM, ulPcrIndex, 0, &five, &prgbPcrEvents); trousers-0.3.15/dist/0000775000175000017510000000000013750250317013711 5ustar deboradeboratrousers-0.3.15/dist/tcsd.conf.in0000664000175000017510000001562113663651711016135 0ustar deboradebora # # This is the configuration file for the trousers tcsd. (The Trusted Computing # Software Stack Core Services Daemon). # # Defaults are listed below, commented out # # Send questions to: trousers-users@lists.sourceforge.net # # Option: port # Values: 1 - 65535 # Description: The port that the tcsd will listen on. # # port = 30003 # # Option: num_threads # Values: 1 - 65535 # Description: The number of threads that the tcsd will spawn internally. # # num_threads = 10 # # Option: system_ps_file # Values: Any absolute directory path # Description: Path where the tcsd creates its persistent storage file. # # system_ps_file = @localstatedir@/lib/tpm/system.data # # Option: firmware_log_file # Values: Any absolute directory path # Description: Path to the file containing the current firmware PCR event # log data. The interface to this log is usually provided by the TPM # device driver. # # firmware_log_file = /sys/kernel/security/tpm0/binary_bios_measurements # # Option: kernel_log_file # Values: Any absolute directory path # Description: Path to the file containing the current kernel PCR event # log data. By default, this data will be parsed in the format provided # by the Integrity Measurement Architecture LSM. See # http://sf.net/projects/linux-ima for more info on getting IMA. # # # kernel_log_file = /sys/kernel/security/ima/binary_runtime_measurements # # Option: firmware_pcrs # Values: PCR indices, separated by commas (no whitespace) # Description: A list of PCR indices that are manipulated only by the system # firmware and therefore are not extended or logged by the TCSD. # # firmware_pcrs = # # Option: kernel_pcrs # Values: PCR indices, separated by commas (no whitespace) # Description: A list of PCR indices that are manipulated only by the kernel # and therefore are not extended or logged by the TCSD. # # kernel_pcrs = # # Option: platform_cred # Values: Any absolute directory path (example: /path/to/platform.cert) # Description: Path to the file containing your TPM's platform credential. # The platform credential may have been provided to you by your TPM # manufacturer. If so, set platform_cred to the path to the file on disk. # Whenever a new TPM identity is created, the credential will be used. See # Tspi_TPM_CollateIdentityRequest(3) for more information. # # platform_cred = # # Option: conformance_cred # Values: Any absolute directory path (example: /path/to/conformance.cert) # Description: Path to the file containing your TPM's conformance credential. # The conformance credential may have been provided to you by your TPM # manufacturer. If so, set conformance_cred to the path to the file on disk. # Whenever a new TPM identity is created, the credential will be used. See # Tspi_TPM_CollateIdentityRequest(3) for more information. # # conformance_cred = # # Option: endorsement_cred # Values: Any absolute directory path (example: /path/to/endorsement.cert) # Description: Path to the file containing your TPM's endorsement credential. # The endorsement credential may have been provided to you by your TPM # manufacturer. If so, set endorsement_cred to the path to the file on disk. # Whenever a new TPM identity is created, the credential will be used. See # Tspi_TPM_CollateIdentityRequest(3) for more information. # # endorsement_cred = # # Option: remote_ops # Values: TCS operation names, separated by commas (no whitespace) # Description: A list of TCS commands which will be allowed to be executed # on this machine's TCSD by TSP's on non-local hosts (over the internet). # By default, access to all operations is denied. # # possible values: seal - encrypt data bound to PCR values # unseal - decrypt data bound to PCR values # registerkey - store keys in system persistent storage [Disk write access!] # unregisterkey - remove keys from system persistent storage [Disk write access!] # loadkey - load a key into the TPM # createkey - create a key using the TPM # sign - encrypt data using a private key # random - generate random numbers # getcapability - query the TCS/TPM for its capabilities # unbind - decrypt data # quote - request a signed blob containing all PCR values # readpubek - access the TPM's Public EndorsementKey # getregisteredkeybypublicinfo - Search system persistent storage for a public key # getpubkey - Retrieve a loaded key's public data from inside the TPM # selftest - execute selftest and test results ordinals # # remote_ops = # # Option: enforce_exclusive_transport # Values: 0 or 1 # Description: When an application opens a transport session with the TPM, one # of the options available is an "exclusive" session, meaning that the TPM # will not execute any commands other than those coming through the transport # session for the lifetime of the session. The TCSD can choose to enforce this # option or not. By default, exclusive sessions are not enforced, since this # could allow for a denial of service to the TPM. # # enforce_exclusive_transport = 0 # # Option: host_platform_class # Values: One of the TCG platform class specifications # PC_11 - PC Client System, version 1.1 # PC_12 - PC Client System, version 1.2 # PDA_12 - PDA System, version 1.2 # SERVER_12 - Server System, version 1.2 # MOBILE_12 - Mobile Phone System, version 1.2 # # Description: This option determines the host platform (host the TCS system # is running on) class, among those specified by the Trusted Computing group # on https://www.trustedcomputinggroup.org/specs/. This class will be reported # by the TCS daemon when an application queries it using the # TSS_TCSCAP_PROP_HOST_PLATFORM sub-capability. The default is PC_12. # # host_platform_class = PC_12 # # Option: all_platform_classes # Values: TCG Platform class names, separated by commas (no whitespaces) # PC_11 - PC Client System, version 1.1 # PC_12 - PC Client System, version 1.2 # PDA_12 - PDA System, version 1.2 # SERVER_12 - Server System, version 1.2 # MOBILE_12 - Mobile Phone System, version 1.2 # # Description: This option determines all the platform classes supported by the # TCS daemon. This list must not include the value set as "host_platform_class" # specified above. Since by default TrouSerS supports all TPM 1.2 functionality, # the default is all 1.2 and 1.1 platform classes. # # all_platform_classes = PC_11,PDA_12,SERVER_12,MOBILE_12 # # # Option: disable_ipv4 # Values: 0 or 1 # Description: This options determines if the TCSD will bind itself to the # machine's local IPv4 addresses in order to receive requisitions through # its TCP port. Value of 1 disables IPv4 support, so clients cannot reach # TCSD using that protocol. # # disable_ipv4 = 0 # # # Option: disable_ipv6 # Values: 0 or 1 # Description: This options determines if the TCSD will bind itself to the # machine's local IPv6 addresses in order to receive requisitions through # its TCP port. Value of 1 disables IPv6 support, so clients cannot reach # TCSD using that protocol. # # disable_ipv6 = 0 # trousers-0.3.15/dist/Makefile.am0000664000175000017510000000161113750230143015737 0ustar deboradeboraEXTRA_DIST = system.data.auth system.data.noauth \ fedora/fedora.initrd.tcsd install: install-exec-hook if test ! -e ${DESTDIR}/@sysconfdir@/tcsd.conf; then mkdir -p ${DESTDIR}/@sysconfdir@ && cp tcsd.conf ${DESTDIR}/@sysconfdir@; fi if !NOUSERCHECK /bin/chown root:tss ${DESTDIR}/@sysconfdir@/tcsd.conf || true /bin/chmod 0640 ${DESTDIR}/@sysconfdir@/tcsd.conf endif install-exec-hook: /bin/sh -c 'if [ ! -e ${DESTDIR}/@localstatedir@/lib/tpm ];then mkdir -p ${DESTDIR}/@localstatedir@/lib/tpm; fi' if !NOUSERCHECK /usr/sbin/groupadd tss || true /usr/sbin/useradd -r tss -g tss || true /bin/chown tss:tss ${DESTDIR}/@localstatedir@/lib/tpm || true /bin/chmod 0700 ${DESTDIR}/@localstatedir@/lib/tpm endif uninstall-hook: rm ${DESTDIR}/@sysconfdir@/tcsd.conf rmdir ${DESTDIR}/@localstatedir@/lib/tpm if !NOUSERCHECK /usr/sbin/userdel tss || true /usr/sbin/groupdel tss || true endif trousers-0.3.15/dist/fedora/0000775000175000017510000000000013663651711015157 5ustar deboradeboratrousers-0.3.15/dist/fedora/trousers.te0000664000175000017510000000301213663651711017373 0ustar deboradeboratype tcsd_device_t, device_type, dev_fs; type tcsd_readwrite_t, file_type; type tcsd_config_t, file_type, sysadmfile; daemon_domain(tcsd, `') general_domain_access(tcsd_t) allow unconfined_t tcsd_t:process transition; type_transition unconfined_t tcsd_exec_t:process tcsd_t; allow tcsd_t tcsd_exec_t:dir r_dir_perms; allow tcsd_t etc_t:file { read getattr lock ioctl }; allow tcsd_t etc_t:lnk_file { read getattr }; allow tcsd_t devtty_t:chr_file { ioctl read getattr lock write append }; allow tcsd_t devpts_t:chr_file { ioctl read getattr lock write append }; can_network(tcsd_t) read_sysctl(tcsd_t, full) r_dir_file(tcsd_t, usr_t) r_dir_file(tcsd_t, tcsd_config_t) rw_dir_file(tcsd_t, tcsd_readwrite_t) allow tcsd_t tcsd_readwrite_t:file { setattr }; allow tcsd_t tcsd_readwrite_t:dir { setattr }; allow tcsd_t tcsd_device_t:chr_file { ioctl read getattr lock write append }; allow tcsd_t { random_device_t }:chr_file { read getattr }; allow tcsd_t lib_t:dir r_dir_perms; allow tcsd_t lib_t:file { rx_file_perms execmod }; allow tcsd_t lib_t:lnk_file r_file_perms; allow tcsd_t lib_t:file { rx_file_perms execmod }; allow tcsd_t lib_t:lnk_file r_file_perms; allow tcsd_t lib_t:file { rx_file_perms execmod }; allow tcsd_t lib_t:lnk_file r_file_perms; allow tcsd_t var_lib_t:dir r_dir_perms; allow tcsd_t var_lib_t:file { rx_file_perms execmod }; allow tcsd_t var_lib_t:lnk_file r_file_perms; allow tcsd_t port_type:tcp_socket { send_msg recv_msg name_bind }; allow tcsd_t self:capability { chown net_bind_service dac_override fowner fsetid }; trousers-0.3.15/dist/fedora/trousers.fc0000664000175000017510000000030013663651711017350 0ustar deboradebora/usr/sbin/tcsd system_u:object_r:tcsd_exec_t /etc/tcsd.conf system_u:object_r:tcsd_config_t /var/lib/tpm(/.*)? system_u:object_r:tcsd_readwrite_t /dev/tpm(.*) system_u:object_r:tcsd_device_t trousers-0.3.15/dist/fedora/fedora.initrd.tcsd0000775000175000017510000000365013663651711020575 0ustar deboradebora#!/bin/bash # # Init file for the TrouSerS TCG Core Services daemon # # chkconfig: - 90 10 # description: TrouSerS server daemon # # processname: tcsd # config: /etc/tcsd.conf # pidfile: /var/run/tcsd.pid # # Return values according to LSB for all commands but status: # 0 - success # 1 - generic or unspecified error # 2 - invalid or excess argument(s) # 3 - unimplemented feature (e.g. "reload") # 4 - insufficient privilege # 5 - program is not installed # 6 - program is not configured # 7 - program is not running # prog="tcsd" # source function library . /etc/rc.d/init.d/functions # Allow anyone to run status if [ "$1" = "status" ] ; then status $prog RETVAL=$? exit $RETVAL fi # Check that we are root ... so non-root users stop here test $EUID = 0 || exit 4 # pull in sysconfig settings test -f /etc/sysconfig/tcsd && . /etc/sysconfig/tcsd RETVAL=0 # Some variables to make the below more readable TCSD=/usr/sbin/tcsd PID_FILE=/var/run/tcsd.pid INSMOD=/sbin/insmod LSMOD=/sbin/lsmod GREP=/bin/grep load_drivers() { for d in `echo /lib/modules/$(uname -r)/kernel/drivers/char/tpm/tpm_*`; do $INSMOD $d if test $? -eq 0; then break; fi done } check_drivers() { $LSMOD | $GREP tpm_ } start() { test -x $TCSD || exit 5 test -f /etc/tcsd.conf || exit 6 check_drivers || load_drivers || failure echo -n $"Starting $prog: " $TCSD $OPTIONS && success || failure RETVAL=$? [ "$RETVAL" = 0 ] && touch /var/lock/subsys/tcsd echo } stop() { echo -n $"Stopping $prog: " killproc $prog RETVAL=$? [ "$RETVAL" = 0 ] && rm -f /var/lock/subsys/tcsd echo } case "$1" in start) start ;; stop) stop ;; restart) test -f /etc/tcsd.conf || exit 6 stop start ;; reload|force-reload) restart ;; condrestart|try-restart) if [ -f /var/lock/subsys/tcsd ] ; then restart fi ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" RETVAL=3 esac exit $RETVAL trousers-0.3.15/dist/fedora/trousers.spec.in0000664000175000017510000000661513663651711020336 0ustar deboradebora # RPM specfile for the trousers project on Fedora %define name @PACKAGE@ %define version @VERSION@ %define release 1 Name: %{name} Summary: Implementation of the TCG's Software Stack v1.1 Specification Version: %{version} Release: %{release} License: BSD Group: Development/Libraries Source: %{name}-%{version}.tar.gz Url: http://www.sf.net/projects/trousers BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: libtool, gtk2-devel, openssl-devel Requires: gtk+ >= 2.0, openssl Requires(post): /sbin/ldconfig Requires(post): /sbin/chkconfig Requires(postun): /sbin/ldconfig Requires(postun): /sbin/service Requires(preun): /sbin/chkconfig Requires(preun): /sbin/service %description TrouSerS is an implementation of the Trusted Computing Group's Software Stack (TSS) specification. You can use TrouSerS to write applications that make use of your TPM hardware. TPM hardware can create, store and use RSA keys securely (without ever being exposed in memory), verify a platform's software state using cryptographic hashes and more. %package devel Summary: TrouSerS header files and documentation Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description devel Header files and man pages for use in creating Trusted Computing enabled applications. %prep %setup -q %build autoreconf %configure --disable-static --prefix=/usr --libdir=%{_libdir} make %{?_smp_mflags} %clean [ "${RPM_BUILD_ROOT}" != "/" ] && [ -d ${RPM_BUILD_ROOT} ] && rm -rf ${RPM_BUILD_ROOT}; # # $1 is the number of entries in the RPM database for the package after the step is # executed. So in the post step, if $1 is 1, then this is the first time we've been # installed. If its 2, we're upgrading. # %post /sbin/ldconfig if [ $1 = 1 ]; then /sbin/chkconfig --add tcsd if [ $? == 0 ]; then /sbin/chkconfig --level 35 tcsd on fi fi %post devel -p /sbin/ldconfig %install # This line keeps build machines from being affected [ "${RPM_BUILD_ROOT}" != "/" ] && [ -d ${RPM_BUILD_ROOT} ] && rm -rf ${RPM_BUILD_ROOT}; mkdir -p ${RPM_BUILD_ROOT} mkdir -p ${RPM_BUILD_ROOT}/%{_initrddir} cp dist/fedora/fedora.initrd.tcsd ${RPM_BUILD_ROOT}/%{_initrddir}/tcsd make install DESTDIR=${RPM_BUILD_ROOT} rm -f ${RPM_BUILD_ROOT}/%{_libdir}/libtspi.la %preun if [ $1 = 0 ]; then /sbin/service tcsd stop &> /dev/null /sbin/chkconfig --del tcsd fi %postun /sbin/ldconfig if [ $1 -gt 1 ]; then /sbin/service tcsd condrestart &>/dev/null fi %postun devel -p /sbin/ldconfig %files %doc README AUTHORS LICENSE %defattr(755, root, root) %attr(755, tss, tss) %{_sbindir}/tcsd %{_libdir}/libtspi.so.? %{_libdir}/libtspi.so.?.?.? %config(noreplace) %attr(600, tss, tss) %{_sysconfdir}/tcsd.conf %attr(644, root, root) %{_mandir}/man5/* %attr(644, root, root) %{_mandir}/man8/* %{_initrddir}/tcsd # The files to be used by developers, 'trousers-devel' %files devel %attr(755, root, root) %{_libdir}/libtspi.so %defattr(644, root, root) %{_libdir}/libtddl.a %{_includedir}/tss/*.h %{_includedir}/trousers/*.h %{_mandir}/man3/Tspi_* %changelog * Mon Nov 12 2007 Kent Yoder - 0.3.1 - Updated specfile for comments in RHBZ#323441 * Wed Jun 07 2006 Kent Yoder - 0.2.6-1 - Updated build section to use smp_mflags - Removed .la file from installed dest and files section * Tue Jun 06 2006 Kent Yoder - 0.2.6-1 - Initial add of changelog tag for trousers CVS trousers-0.3.15/dist/system.data.auth0000664000175000017510000000113613663651711017037 0ustar deboradebora/ trousers-0.3.15/dist/system.data.noauth0000664000175000017510000000113613663651711017374 0ustar deboradebora/ trousers-0.3.15/dist/trousers.spec.in0000664000175000017510000000575713663651711017104 0ustar deboradebora %define name @PACKAGE@ %define version @VERSION@ %define release 1 %ifarch ppc64 x86_64 ia64 s390x %define arch64 1 %define packages64 cairo-devel-64bit, glitz-devel-64bit, fontconfig-devel-64bit, freetype2-devel-64bit, xorg-x11-devel-64bit, libpng-devel-64bit %define pkgconfig_path /opt/gnome/lib64/pkgconfig:/usr/lib64/pkgconfig %endif # RPM specfile for the trousers project Name: %{name} Summary: Implementation of the TCG's Software Stack v1.1 Specification Version: %{version} Release: %{release} License: BSD Group: Productivity/Security Source: %{name}-%{version}.tar.gz Url: http://www.sf.net/projects/trousers BuildRoot: %{_tmppath}/%{name}-%{version}-root PreReq: /usr/sbin/groupadd /usr/sbin/useradd /bin/chown Requires: gtk+ >= 2.0, openssl BuildRequires: gtk+ >= 2.0, openssl %{?arch64:,%{packages64}} %description TrouSerS is an implementation of the Trusted Computing Group's Software Stack (TSS) specification. You can use TrouSerS to write applications that make use of your TPM hardware. TPM hardware can create, store and use RSA keys securely (without ever being exposed in memory), verify a platform's software state using cryptographic hashes and more. %package devel Summary: TrouSerS header files and documentation Group: Productivity/Security Requires: trousers %description devel Header files and man pages for use in creating Trusted Computing enabled applications. %prep %setup %build %{?arch64:export PKG_CONFIG_PATH=%{pkgconfig_path}:$PKG_CONFIG_PATH} ./configure --prefix=/usr --libdir=%{_libdir} make %clean [ "${RPM_BUILD_ROOT}" != "/" ] && [ -d ${RPM_BUILD_ROOT} ] && rm -rf ${RPM_BUILD_ROOT}; %pre # add group tss /usr/sbin/groupadd tss || { RC=$? case $RC in 9) # group 'tss' already exists ;; *) # some other error; fail echo "Couldn't create group 'tss'. Exiting." exit $RC;; esac } # add user tss /usr/sbin/useradd -r tss || { RC=$? case $RC in 9) # user 'tss' already exists ;; *) # some other error; fail echo "Couldn't create user 'tss'. Exiting." exit $RC;; esac } %post # create the default location for the persistent store files if test -e %{_localstatedir}/tpm; then mkdir -p %{_localstatedir}/tpm /bin/chown tss:tss %{_localstatedir}/tpm /bin/chmod 1777 %{_localstatedir}/tpm fi # chown the daemon /bin/chown tss:tss %{_sbindir}/tcsd /sbin/ldconfig %install # This line keeps build machines from being affected [ "${RPM_BUILD_ROOT}" != "/" ] && [ -d ${RPM_BUILD_ROOT} ] && rm -rf ${RPM_BUILD_ROOT}; mkdir -p ${RPM_BUILD_ROOT} make install DESTDIR=${RPM_BUILD_ROOT} %postun /sbin/ldconfig /usr/sbin/userdel tss /usr/sbin/groupdel tss # The files for the base package, 'trousers' %files %doc README AUTHORS %attr(755, tss, tss) %{_sbindir}/tcsd %{_libdir}/libtspi.la %{_libdir}/libtspi.so* %{_libdir}/libtddl.a %config %attr(600, tss, tss) %{_sysconfdir}/tcsd.conf %{_mandir}/man5/* %{_mandir}/man8/* # The files to be used by developers, 'trousers-devel' %files devel %{_includedir}/tss/*.h %{_includedir}/trousers/*.h %{_mandir}/man3/Tspi_*